pax_global_header00006660000000000000000000000064141254343400014512gustar00rootroot0000000000000052 comment=00d6469eafdd4aac346a0b598184c15f2560dbe5 sympy-sympy-1.9/000077500000000000000000000000001412543434000137235ustar00rootroot00000000000000sympy-sympy-1.9/.ci/000077500000000000000000000000001412543434000143745ustar00rootroot00000000000000sympy-sympy-1.9/.ci/README.rst000066400000000000000000000011741412543434000160660ustar00rootroot00000000000000This folder currently holds ``durations.json`` and ``blacklisted.json`` which are used in our pytest configuration. ``durations.json`` allows the two options ``--quickcheck`` and ``--veryquickcheck`` to be passed to ``pytest``. Currently, the list of slow tests is updated intermittently by running:: $ ./.ci/generate_durations_log.sh $ ./.ci/parse_durations_log.py $ git commit -am "pytest: Updated .ci/durations.json" make sure you have a C compiler, a Fortran compiler, numpy, scipy, cython, matplotlib & sage installed (the latter can be tricky, in which case just make sure that no sage tests are removed in the git diff). sympy-sympy-1.9/.ci/blacklisted.json000066400000000000000000000002361412543434000175510ustar00rootroot00000000000000{ "sympy/physics/mechanics/tests/test_kane3.py": [ "test_bicycle" ], "sympy/utilities/tests/test_wester.py": [ "test_W25" ] } sympy-sympy-1.9/.ci/durations.json000066400000000000000000002673731412543434000173210ustar00rootroot00000000000000[ { "sympy/assumptions/tests/test_query.py": [ "test_algebraic", "test_bounded1", "test_bounded2a", "test_bounded2b", "test_bounded3", "test_even_query", "test_evenness_in_ternary_integer_product_with_odd", "test_hermitian", "test_imaginary", "test_known_facts_consistent", "test_negative", "test_odd_query", "test_oddness_in_ternary_integer_product_with_odd", "test_positive", "test_real_functions", "test_real_pow", "test_zero" ], "sympy/assumptions/tests/test_refine.py": [ "test_pow2", "test_pow3", "test_pow4" ], "sympy/assumptions/tests/test_satask.py": [ "test_integer", "test_pow_pos_neg" ], "sympy/combinatorics/tests/test_coset_table.py": [ "test_coset_enumeration", "test_look_ahead" ], "sympy/combinatorics/tests/test_fp_groups.py": [ "test_order" ], "sympy/combinatorics/tests/test_perm_groups.py": [ "test_presentation" ], "sympy/concrete/tests/test_sums_products.py": [ "test_evalf_euler_maclaurin", "test_is_convergent" ], "sympy/functions/combinatorial/tests/test_comb_numbers.py": [ "test_bell" ], "sympy/functions/elementary/tests/test_piecewise.py": [ "test_issue_11045", "test_piecewise_integrate1ca", "test_piecewise_integrate1cb", "test_piecewise_integrate4_symbolic_conditions" ], "sympy/functions/elementary/tests/test_trigonometric.py": [ "test_sincos_rewrite_sqrt", "test_tancot_rewrite_sqrt" ], "sympy/functions/special/tests/test_bsplines.py": [ "test_10_points_degree_1", "test_5_points_degree_2", "test_6_points_degree_3" ], "sympy/functions/special/tests/test_error_functions.py": [ "test_fresnel" ], "sympy/functions/special/tests/test_hyper.py": [ "test_hyperrep", "test_meijerg_eval" ], "sympy/geometry/tests/test_curve.py": [ "test_free_symbols" ], "sympy/geometry/tests/test_ellipse.py": [ "test_ellipse_geom", "test_second_moment_of_area" ], "sympy/geometry/tests/test_entity.py": [ "test_reflect_entity_overrides" ], "sympy/geometry/tests/test_line.py": [ "test_line_intersection" ], "sympy/geometry/tests/test_polygon.py": [ "test_parameter_value", "test_polygon" ], "sympy/holonomic/tests/test_holonomic.py": [ "test_to_meijerg" ], "sympy/integrals/tests/test_failing_integrals.py": [ "test_issue_1796a", "test_issue_4540", "test_issue_4941" ], "sympy/integrals/tests/test_heurisch.py": [ "test_pmint_WrightOmega", "test_pmint_bessel_products", "test_pmint_logexp" ], "sympy/integrals/tests/test_integrals.py": [ "test_evalf_integrals", "test_issue_4311", "test_issue_7130", "test_issue_8945", "test_principal_value" ], "sympy/integrals/tests/test_intpoly.py": [ "test_polytope_integrate" ], "sympy/integrals/tests/test_manual.py": [ "test_issue_10847", "test_issue_13297", "test_issue_2850", "test_issue_6799", "test_issue_9858" ], "sympy/integrals/tests/test_meijerint.py": [ "test_expint", "test_lookup_table", "test_meijerint", "test_messy", "test_probability" ], "sympy/integrals/tests/test_transforms.py": [ "test_expint", "test_fourier_transform", "test_inverse_laplace_transform", "test_inverse_mellin_transform", "test_issue_8368_7173", "test_laplace_transform", "test_mellin_transform2", "test_mellin_transform_bessel" ], "sympy/logic/tests/test_boolalg.py": [ "test_relational_simplification", "test_relational_simplification_numerically" ], "sympy/matrices/tests/test_matrices.py": [ "test_issue_11238" ], "sympy/physics/continuum_mechanics/tests/test_beam.py": [ "test_Beam3D", "test_max_shear_force", "test_variable_moment" ], "sympy/physics/mechanics/tests/test_kane.py": [ "test_aux" ], "sympy/physics/mechanics/tests/test_kane2.py": [ "test_aux_dep" ], "sympy/physics/mechanics/tests/test_linearize.py": [ "test_linearize_rolling_disc_kane" ], "sympy/physics/quantum/tests/test_circuitutils.py": [ "test_random_reduce" ], "sympy/physics/quantum/tests/test_qubit.py": [ "test_apply_represent_equality" ], "sympy/physics/quantum/tests/test_spin.py": [ "test_couple_4_states", "test_uncouple_4_coupled_states" ], "sympy/physics/tests/test_clebsch_gordan.py": [ "test_gaunt" ], "sympy/physics/tests/test_secondquant.py": [ "test_dummy_order_ambiguous", "test_sho" ], "sympy/plotting/tests/test_plot.py": [ "test_matplotlib_4", "test_matplotlib_5" ], "sympy/plotting/tests/test_plot_implicit.py": [ "test_matplotlib" ], "sympy/polys/tests/test_ring_series.py": [ "test_rs_series" ], "sympy/polys/tests/test_rootoftools.py": [ "test_CRootOf_evalf" ], "sympy/printing/tests/test_str.py": [ "test_issue_15716" ], "sympy/series/tests/test_formal.py": [ "test_fps__hyper", "test_fps__rational" ], "sympy/series/tests/test_gruntz.py": [ "test_gruntz_eval_special", "test_gruntz_evaluation" ], "sympy/series/tests/test_limitseq.py": [ "test_limit_seq" ], "sympy/series/tests/test_sequences.py": [ "test_find_linear_recurrence" ], "sympy/simplify/tests/test_hyperexpand.py": [ "test_formulae", "test_meijerg_confluence", "test_meijerg_expand", "test_prudnikov_10", "test_prudnikov_2", "test_prudnikov_3", "test_prudnikov_4", "test_prudnikov_5", "test_prudnikov_6", "test_prudnikov_7", "test_prudnikov_8", "test_prudnikov_misc" ], "sympy/simplify/tests/test_trigsimp.py": [ "test_trigsimp_groebner" ], "sympy/solvers/tests/test_diophantine.py": [ "test_quadratic_non_perfect_slow" ], "sympy/solvers/tests/test_ode.py": [ "test_1st_exact1", "test_1st_exact2", "test_1st_homogeneous_coeff_ode", "test_2nd_power_series_ordinary", "test_checkodesol", "test_dsolve_options", "test_heuristic3", "test_lie_group", "test_linear_2eq_order2", "test_nonlinear_3eq_order1", "test_nth_algebraic", "test_nth_linear_constant_coeff_homogeneous", "test_nth_linear_constant_coeff_homogeneous_rootof", "test_nth_linear_constant_coeff_homogeneous_rootof_sol", "test_nth_linear_constant_coeff_undetermined_coefficients", "test_nth_linear_constant_coeff_variation_of_parameters", "test_nth_linear_constant_coeff_variation_of_parameters_simplify_False", "test_nth_order_linear_euler_eq_nonhomogeneous_variation_of_parameters", "test_nth_order_reducible", "test_separable2", "test_separable3", "test_separable5", "test_separable_reduced", "test_solve_ics" ], "sympy/solvers/tests/test_recurr.py": [ "test_issue_15751", "test_rsolve" ], "sympy/solvers/tests/test_solvers.py": [ "test_high_order_multivariate", "test_issue_12114", "test_issue_15731", "test_issue_2840_8155", "test_issue_4793", "test_issue_5114_solvers", "test_issue_8828", "test_lambert_multivariate", "test_solve_transcendental", "test_unrad1", "test_unrad_slow" ], "sympy/solvers/tests/test_solveset.py": [ "test_solve_sqrt_3" ], "sympy/stats/tests/test_continuous_rv.py": [ "test_multiple_normal", "test_precomputed_cdf", "test_trapezoidal" ], "sympy/stats/tests/test_discrete_rv.py": [ "test_sample_discrete" ], "sympy/stats/tests/test_joint_rv.py": [ "test_JointPSpace_margial_distribution" ], "sympy/utilities/tests/test_wester.py": [ "test_J12", "test_R19", "test_V14", "test_W19", "test_W23", "test_W24", "test_W6" ], "sympy/vector/tests/test_coordsysrect.py": [ "test_coordinate_vars" ] }, { "sympy/algebras/tests/test_quaternion.py": [ "test_quaternion_construction", "test_quaternion_conversions", "test_quaternion_functions", "test_quaternion_rotation_iss1593" ], "sympy/assumptions/tests/test_context.py": [ "test_assuming", "test_assuming_nested" ], "sympy/assumptions/tests/test_matrices.py": [ "test_MatrixSlice", "test_diagonal", "test_field_assumptions", "test_fullrank", "test_invertible", "test_invertible_fullrank", "test_non_atoms", "test_non_trivial_implies", "test_orthogonal", "test_positive_definite", "test_singular", "test_symmetric", "test_unitary" ], "sympy/assumptions/tests/test_query.py": [ "test_bounded_xfail", "test_check_old_assumption", "test_complex", "test_composite_ask", "test_composite_assumptions", "test_composite_proposition", "test_evenness_in_ternary_integer_product_with_even", "test_float_1", "test_global", "test_incompatible_resolutors", "test_integer", "test_issue_5833", "test_issue_7246", "test_issue_7246_failing", "test_key_extensibility", "test_nonzero", "test_oddness_in_ternary_integer_product_with_even", "test_pi", "test_positive_assuming", "test_prime", "test_rational", "test_real_basic", "test_tautology" ], "sympy/assumptions/tests/test_refine.py": [ "test_Abs", "test_Piecewise", "test_Relational", "test_atan2", "test_exp", "test_pow1", "test_refine_issue_12724" ], "sympy/assumptions/tests/test_satask.py": [ "test_abs", "test_even_satask", "test_imaginary", "test_invertible", "test_odd_satask", "test_old_assump", "test_pos_neg", "test_prime", "test_rational_irrational", "test_real", "test_satask", "test_zero", "test_zero_positive", "test_zero_pow" ], "sympy/calculus/tests/test_euler.py": [ "test_euler_high_order" ], "sympy/calculus/tests/test_singularities.py": [ "test_is_decreasing", "test_is_increasing", "test_is_monotonic", "test_is_strictly_decreasing", "test_is_strictly_increasing", "test_singularities" ], "sympy/calculus/tests/test_util.py": [ "test_continuous_domain", "test_function_range", "test_is_convex", "test_maximum", "test_minimum", "test_not_empty_in", "test_periodicity", "test_periodicity_check", "test_stationary_points" ], "sympy/categories/tests/test_drawing.py": [ "test_DiagramGrid", "test_XypicDiagramDrawer_cube", "test_XypicDiagramDrawer_curved_and_loops" ], "sympy/codegen/tests/test_algorithms.py": [ "test_newtons_method_function__ccode", "test_newtons_method_function__ccode_parameters", "test_newtons_method_function__fcode" ], "sympy/codegen/tests/test_applications.py": [ "test_copying_function" ], "sympy/codegen/tests/test_approximations.py": [ "test_SeriesApprox_trivial", "test_SumApprox_monotone_terms" ], "sympy/codegen/tests/test_array_utils.py": [ "test_recognize_diagonalized_vectors" ], "sympy/codegen/tests/test_ast.py": [ "test_Type__cast_check__complex_floating_point" ], "sympy/codegen/tests/test_fnodes.py": [ "test_ImpliedDoLoop", "test_Module", "test_Program", "test_Subroutine", "test_bind_C", "test_size_assumed_shape" ], "sympy/codegen/tests/test_rewriting.py": [ "test_log2_opt", "test_optims_c99" ], "sympy/combinatorics/tests/test_coset_table.py": [ "test_modified_methods", "test_scan_1" ], "sympy/combinatorics/tests/test_fp_groups.py": [ "test_cyclic", "test_fp_subgroup", "test_low_index_subgroups", "test_permutation_methods", "test_subgroup_presentations" ], "sympy/combinatorics/tests/test_homomorphisms.py": [ "test_homomorphism", "test_isomorphisms" ], "sympy/combinatorics/tests/test_partitions.py": [ "test_rgs" ], "sympy/combinatorics/tests/test_perm_groups.py": [ "test_center", "test_centralizer", "test_normal_closure", "test_rubik1", "test_subgroup_search", "test_sylow_subgroup" ], "sympy/combinatorics/tests/test_polyhedron.py": [ "test_polyhedron" ], "sympy/combinatorics/tests/test_rewriting.py": [ "test_rewriting" ], "sympy/combinatorics/tests/test_tensor_can.py": [ "test_graph_certificate" ], "sympy/concrete/tests/test_delta.py": [ "test_deltaproduct_add_kd_kd", "test_deltaproduct_add_mul_x_y_mul_x_kd", "test_deltaproduct_mul_add_x_kd_add_y_kd", "test_deltaproduct_mul_add_x_y_add_kd_kd", "test_deltaproduct_mul_add_x_y_add_y_kd", "test_deltaproduct_mul_x_add_kd_kd", "test_deltaproduct_mul_x_add_y_kd", "test_deltaproduct_mul_x_add_y_twokd", "test_deltasummation_add_kd_kd", "test_deltasummation_add_mul_x_kd_kd", "test_deltasummation_add_mul_x_y_mul_x_kd", "test_deltasummation_basic_numerical", "test_deltasummation_basic_symbolic", "test_deltasummation_mul_add_x_kd_add_y_kd", "test_deltasummation_mul_add_x_y_add_kd_kd", "test_deltasummation_mul_add_x_y_add_y_kd", "test_deltasummation_mul_add_x_y_kd", "test_deltasummation_mul_x_add_kd_kd", "test_deltasummation_mul_x_add_y_kd", "test_deltasummation_mul_x_add_y_twokd", "test_deltasummation_mul_x_kd" ], "sympy/concrete/tests/test_gosper.py": [ "test_gosper_nan", "test_gosper_sum", "test_gosper_sum_AeqB_part1", "test_gosper_sum_AeqB_part2", "test_gosper_sum_AeqB_part3", "test_gosper_sum_algebraic", "test_gosper_sum_indefinite", "test_gosper_sum_iterated", "test_gosper_sum_parametric", "test_gosper_term" ], "sympy/concrete/tests/test_guess.py": [ "test_find_simple_recurrence", "test_guess", "test_guess_generating_function" ], "sympy/concrete/tests/test_products.py": [ "test_Product_is_convergent", "test_issue_9983", "test_karr_proposition_2a", "test_karr_proposition_2b", "test_simplify" ], "sympy/concrete/tests/test_sums_products.py": [ "test_Sum_doit", "test_arithmetic_sums", "test_convergent_failing", "test_euler_maclaurin", "test_evalf_fast_series", "test_evalf_fast_series_issue_4021", "test_evalf_slow_series", "test_geometric_sums", "test_harmonic_sums", "test_hypergeometric_sums", "test_hypersum", "test_issue_14111", "test_issue_14112", "test_issue_14129", "test_issue_14484", "test_issue_14640", "test_issue_15852", "test_issue_15943", "test_issue_2787", "test_issue_4171", "test_issue_7097", "test_karr_proposition_2a", "test_karr_proposition_2b", "test_other_sums", "test_rational_products", "test_simplify", "test_sin_times_absolutely_convergent", "test_telescopic_sums", "test_wallis_product" ], "sympy/core/tests/test_args.py": [ "test_all_classes_are_tested", "test_sympy__functions__elementary__hyperbolic__acosh", "test_sympy__physics__quantum__state__Wavefunction", "test_sympy__series__formal__FormalPowerSeries", "test_sympy__series__fourier__FourierSeries" ], "sympy/core/tests/test_arit.py": [ "test_Add_is_negative_positive", "test_Mod", "test_float_int", "test_issue_8247_8354", "test_pow_E", "test_pow_im" ], "sympy/core/tests/test_assumptions.py": [ "test_issue_10302", "test_special_assumptions" ], "sympy/core/tests/test_diff.py": [ "test_diff_nth_derivative" ], "sympy/core/tests/test_evalf.py": [ "test_AssocOp_Function", "test_evalf_divergent_series", "test_evalf_integer_parts", "test_evalf_mul", "test_evalf_product", "test_evalf_sum", "test_issue_4806", "test_issue_4956_5204" ], "sympy/core/tests/test_expand.py": [ "test_expand_arit", "test_issue_6121", "test_issues_5919_6830" ], "sympy/core/tests/test_expr.py": [ "test_action_verbs", "test_as_leading_term4", "test_as_numer_denom", "test_equals", "test_eval_interval", "test_is_constant", "test_issue_11877", "test_issue_6325", "test_leadterm", "test_random", "test_series_expansion_for_uniform_order" ], "sympy/core/tests/test_exprtools.py": [ "test_factor_nc", "test_factor_terms", "test_gcd_terms", "test_issue_7903" ], "sympy/core/tests/test_function.py": [ "test_Derivative_as_finite_difference", "test_Subs", "test_Subs_Derivative", "test_function__eval_nseries", "test_issue_15084_13166", "test_issue_15241", "test_issue_7231", "test_nfloat", "test_subs_in_derivative" ], "sympy/core/tests/test_match.py": [ "test_issue_3883" ], "sympy/core/tests/test_numbers.py": [ "test_Rational_gcd_lcm_cofactors", "test_powers_Integer", "test_simplify_AlgebraicNumber" ], "sympy/core/tests/test_power.py": [ "test_issue_6068", "test_issue_6429", "test_issue_6653", "test_issue_6782", "test_issue_6990", "test_issue_7638", "test_power_rewrite_exp" ], "sympy/core/tests/test_relational.py": [ "test_equals", "test_issues_13081_12583_12534", "test_simplify_relational", "test_univariate_relational_as_set" ], "sympy/core/tests/test_subs.py": [ "test_mul" ], "sympy/core/tests/test_sympify.py": [ "test_kernS" ], "sympy/crypto/tests/test_crypto.py": [ "test_dh_private_key", "test_dh_public_key", "test_dh_shared_key", "test_elgamal_private_key", "test_encipher_decipher_gm" ], "sympy/diffgeom/tests/test_diffgeom.py": [ "test_R2", "test_R3", "test_covar_deriv", "test_helpers_and_coordinate_dependent", "test_intcurve_diffequ", "test_products" ], "sympy/diffgeom/tests/test_function_diffgeom_book.py": [ "test_functional_diffgeom_ch2", "test_functional_diffgeom_ch3", "test_functional_diffgeom_ch4", "test_functional_diffgeom_ch6" ], "sympy/diffgeom/tests/test_hyperbolic_space.py": [ "test_H2" ], "sympy/discrete/tests/test_convolutions.py": [ "test_convolution", "test_convolution_fft", "test_convolution_fwht", "test_cyclic_convolution" ], "sympy/discrete/tests/test_recurrences.py": [ "test_linrec" ], "sympy/external/tests/test_autowrap.py": [ "test_autowrap_custom_printer", "test_autowrap_matrix_matrix_C_cython", "test_autowrap_matrix_vector_C_cython", "test_autowrap_trace_C_Cython", "test_issue_10274_C_cython", "test_issue_15337_C_cython", "test_ufuncify_C_Cython", "test_ufuncify_numpy", "test_wrap_twice_c_cython" ], "sympy/external/tests/test_codegen.py": [ "test_basic_codegen", "test_complicated_codegen", "test_instrinsic_math2_codegen", "test_intrinsic_math1_codegen" ], "sympy/external/tests/test_numpy.py": [ "test_systematic_basic" ], "sympy/functions/combinatorial/tests/test_comb_factorials.py": [ "test_binomial", "test_binomial_Mod", "test_factorial_series", "test_ff_eval_apply", "test_rf_eval_apply" ], "sympy/functions/combinatorial/tests/test_comb_numbers.py": [ "test_catalan", "test_fibonacci", "test_harmonic_rational", "test_nC_nP_nT", "test_tribonacci" ], "sympy/functions/elementary/tests/test_complexes.py": [ "test_Abs", "test_derivatives_issue_4757", "test_re", "test_sign" ], "sympy/functions/elementary/tests/test_exponential.py": [ "test_exp_rewrite", "test_exp_values", "test_issue_8866" ], "sympy/functions/elementary/tests/test_hyperbolic.py": [ "test_acosh_series", "test_acsch", "test_asech", "test_sinh" ], "sympy/functions/elementary/tests/test_integers.py": [ "test_floor", "test_series" ], "sympy/functions/elementary/tests/test_interface.py": [ "test_function_series1", "test_function_series2", "test_function_series3" ], "sympy/functions/elementary/tests/test_miscellaneous.py": [ "test_Max", "test_Min", "test_instantiation_evaluation", "test_issue_11099", "test_minmax_assumptions", "test_real_root", "test_rewrite_MaxMin_as_Piecewise", "test_rewrite_as_Abs" ], "sympy/functions/elementary/tests/test_piecewise.py": [ "test_Piecewise_rewrite_as_ITE", "test__intervals", "test_containment", "test_holes", "test_issue_10087", "test_issue_10137", "test_issue_11922", "test_issue_12557", "test_issue_12587", "test_issue_14052", "test_issue_4313", "test_issue_5227", "test_issue_6900", "test_issue_8458", "test_issue_8919", "test_piecewise", "test_piecewise_collapse", "test_piecewise_fold", "test_piecewise_fold_expand", "test_piecewise_fold_piecewise_in_cond", "test_piecewise_fold_piecewise_in_cond_2", "test_piecewise_integrate1", "test_piecewise_integrate1b", "test_piecewise_integrate2", "test_piecewise_integrate3_inequality_conditions", "test_piecewise_interval", "test_piecewise_lambdify", "test_piecewise_simplify", "test_piecewise_solve", "test_stackoverflow_43852159", "test_unevaluated_integrals" ], "sympy/functions/elementary/tests/test_trigonometric.py": [ "test_acos_series", "test_aseries", "test_atan2", "test_atan2_expansion", "test_cos", "test_cos_AccumBounds", "test_cos_rewrite", "test_cot", "test_cot_expansion", "test_cot_rewrite", "test_cot_series", "test_csc", "test_issue_14320", "test_issue_4420", "test_real_assumptions", "test_sec", "test_sin", "test_sin_AccumBounds", "test_sin_cos", "test_sin_rewrite", "test_sinc", "test_tan", "test_tan_expansion", "test_tan_rewrite" ], "sympy/functions/special/tests/test_bessel.py": [ "test_airyai", "test_airyaiprime", "test_bessel_rand", "test_branching", "test_conjugate", "test_expand", "test_rewrite" ], "sympy/functions/special/tests/test_beta_functions.py": [ "test_beta" ], "sympy/functions/special/tests/test_bsplines.py": [ "test_3_points_degree_2", "test_basic_degree_0", "test_basic_degree_1", "test_basic_degree_2", "test_basic_degree_3", "test_repeated_degree_1", "test_repeated_degree_2" ], "sympy/functions/special/tests/test_delta_functions.py": [ "test_DiracDelta" ], "sympy/functions/special/tests/test_elliptic_integrals.py": [ "test_E", "test_F", "test_K", "test_P" ], "sympy/functions/special/tests/test_error_functions.py": [ "test_Li", "test__eis", "test__erfs", "test_ci", "test_ei", "test_erf", "test_erfc_series", "test_expint", "test_li", "test_si" ], "sympy/functions/special/tests/test_gamma_functions.py": [ "test_gamma", "test_gamma_series", "test_loggamma", "test_lowergamma", "test_polygamma", "test_polygamma_expansion", "test_uppergamma" ], "sympy/functions/special/tests/test_hyper.py": [ "test_expand_func", "test_hyper", "test_limits", "test_meijer", "test_meijerg_derivative" ], "sympy/functions/special/tests/test_spec_polynomials.py": [ "test_jacobi", "test_legendre" ], "sympy/functions/special/tests/test_spherical_harmonics.py": [ "test_Ynm" ], "sympy/functions/special/tests/test_zeta_functions.py": [ "test_derivatives", "test_issue_8404", "test_lerchphi_expansion", "test_polylog_expansion", "test_polylog_values", "test_rewriting" ], "sympy/geometry/tests/test_curve.py": [ "test_length" ], "sympy/geometry/tests/test_ellipse.py": [ "test_circumference", "test_is_tangent", "test_issue_15797", "test_parameter_value", "test_reflect" ], "sympy/geometry/tests/test_entity.py": [ "test_subs" ], "sympy/geometry/tests/test_geometrysets.py": [ "test_booleans" ], "sympy/geometry/tests/test_line.py": [ "test_arbitrary_point", "test_are_concurrent_2d", "test_are_concurrent_3d", "test_arguments", "test_basic_properties_2d", "test_contains", "test_contains_nonreal_symbols", "test_distance_3d", "test_equals", "test_equation", "test_intersection_2d", "test_intersection_3d", "test_is_parallel", "test_is_perpendicular", "test_issue_2941", "test_parameter_value", "test_projection", "test_raises", "test_ray_generation" ], "sympy/geometry/tests/test_parabola.py": [ "test_parabola_geom", "test_parabola_intersection" ], "sympy/geometry/tests/test_plane.py": [ "test_parameter_value", "test_plane" ], "sympy/geometry/tests/test_point.py": [ "test_point", "test_point3D" ], "sympy/geometry/tests/test_polygon.py": [ "test_bisectors", "test_eulerline", "test_exradii", "test_incircle", "test_intersection", "test_issue_12966", "test_reflect", "test_second_moment_of_area", "test_triangle_kwargs" ], "sympy/geometry/tests/test_util.py": [ "test_centroid", "test_farthest_points_closest_points", "test_idiff" ], "sympy/holonomic/tests/test_holonomic.py": [ "test_HolonomicFunction_addition", "test_HolonomicFunction_composition", "test_HolonomicFunction_multiplication", "test_addition_initial_condition", "test_beta", "test_diff", "test_evalf_euler", "test_evalf_rk4", "test_expr_to_holonomic", "test_extended_domain_in_expr_to_holonomic", "test_from_hyper", "test_from_meijerg", "test_gamma", "test_gaussian", "test_integrate", "test_multiplication_initial_condition", "test_series", "test_to_Sequence", "test_to_Sequence_Initial_Coniditons", "test_to_expr", "test_to_hyper" ], "sympy/integrals/tests/test_deltafunctions.py": [ "test_deltaintegrate" ], "sympy/integrals/tests/test_failing_integrals.py": [ "test_issue_4212", "test_issue_4326", "test_issue_4491", "test_issue_4511", "test_issue_4551", "test_issue_4737a", "test_issue_4891", "test_issue_4895b", "test_issue_4895c", "test_issue_4895d", "test_issue_4992" ], "sympy/integrals/tests/test_heurisch.py": [ "test_RR", "test_heurisch_exp", "test_heurisch_fractions", "test_heurisch_function_derivative", "test_heurisch_hacking", "test_heurisch_hyperbolic", "test_heurisch_log", "test_heurisch_mixed", "test_heurisch_polynomials", "test_heurisch_radicals", "test_heurisch_special", "test_heurisch_symbolic_coeffs", "test_heurisch_symbolic_coeffs_1130", "test_heurisch_trigonometric", "test_heurisch_wrapper", "test_issue_10680", "test_issue_3609", "test_pmint_LambertW", "test_pmint_besselj", "test_pmint_erf", "test_pmint_rat", "test_pmint_trig" ], "sympy/integrals/tests/test_integrals.py": [ "test_as_sum_left", "test_as_sum_midpoint2", "test_as_sum_right", "test_as_sum_trapezoid", "test_atom_bug", "test_basics", "test_basics_multiple", "test_constructor", "test_evalf_issue_939", "test_heurisch_option", "test_improper_integral", "test_integrate_Abs_sign", "test_integrate_DiracDelta", "test_integrate_DiracDelta_fails", "test_integrate_Piecewise_rational_over_reals", "test_integrate_SingularityFunction", "test_integrate_derivatives", "test_integrate_functions", "test_integrate_max_min", "test_integrate_returns_piecewise", "test_integrate_series", "test_issue_11856", "test_issue_12081", "test_issue_12645", "test_issue_12677", "test_issue_13749", "test_issue_14027", "test_issue_14064", "test_issue_14096", "test_issue_14144", "test_issue_14375", "test_issue_14437", "test_issue_14470", "test_issue_14782", "test_issue_14877", "test_issue_15124", "test_issue_15285", "test_issue_15292", "test_issue_15431", "test_issue_15432", "test_issue_15457", "test_issue_15509", "test_issue_15640_log_substitutions", "test_issue_1888", "test_issue_2708", "test_issue_2884", "test_issue_3558", "test_issue_3664", "test_issue_3686", "test_issue_3940", "test_issue_4052", "test_issue_4100", "test_issue_4153", "test_issue_4199", "test_issue_4234", "test_issue_4326", "test_issue_4376", "test_issue_4400", "test_issue_4403", "test_issue_4403_2", "test_issue_4422", "test_issue_4487", "test_issue_4492", "test_issue_4493", "test_issue_4514", "test_issue_4517", "test_issue_4527", "test_issue_4703", "test_issue_4803", "test_issue_4884", "test_issue_4890", "test_issue_4892a", "test_issue_4892b", "test_issue_4950", "test_issue_4968", "test_issue_4992", "test_issue_5167", "test_issue_5178", "test_issue_5413", "test_issue_6253", "test_issue_6828", "test_issue_7450", "test_issue_8170", "test_issue_8368", "test_issue_8440_14040", "test_issue_8623", "test_issue_8901", "test_issue_9569", "test_limit_bug", "test_log_polylog", "test_manual_option", "test_multiple_integration", "test_powers", "test_risch_option", "test_series", "test_singularities", "test_transcendental_functions", "test_transform", "test_trig_nonelementary_integrals" ], "sympy/integrals/tests/test_intpoly.py": [ "test_main_integrate3d", "test_polytopes_intersecting_sides" ], "sympy/integrals/tests/test_lineintegrals.py": [ "test_lineintegral" ], "sympy/integrals/tests/test_manual.py": [ "test_cyclic_parts", "test_find_substitutions", "test_issue_12641", "test_issue_14470", "test_issue_15471", "test_issue_3796", "test_issue_6746", "test_issue_8520", "test_issue_9462", "test_manual_true", "test_manualintegrate_Heaviside", "test_manualintegrate_exponentials", "test_manualintegrate_inversetrig", "test_manualintegrate_orthogonal_poly", "test_manualintegrate_parts", "test_manualintegrate_polynomials", "test_manualintegrate_special", "test_manualintegrate_trig_substitution", "test_manualintegrate_trigonometry", "test_manualintegrate_trigpowers", "test_manualintegrate_trivial_substitution" ], "sympy/integrals/tests/test_meijerint.py": [ "test_bessel", "test_branch_bug", "test_fresnel", "test_inflate", "test_inversion", "test_inversion_conditional_output", "test_issue_10211", "test_issue_10681", "test_issue_11806", "test_issue_6122", "test_issue_6252", "test_issue_6348", "test_issue_6860", "test_issue_7337", "test_issue_8368", "test_linear_subs", "test_meijerint_indefinite_numerically", "test_recursive", "test_rewrite_single" ], "sympy/integrals/tests/test_prde.py": [ "test_constant_system", "test_is_deriv_k", "test_is_log_deriv_k_t_radical", "test_is_log_deriv_k_t_radical_in_field", "test_param_rischDE", "test_prde_cancel_liouvillian", "test_prde_no_cancel", "test_prde_special_denom" ], "sympy/integrals/tests/test_quadrature.py": [ "test_gen_laguerre", "test_hermite", "test_jacobi", "test_laguerre" ], "sympy/integrals/tests/test_rationaltools.py": [ "test_issue_10488", "test_issue_5249", "test_issue_5817", "test_issue_5907", "test_issue_6308", "test_issues_8246_12050_13501_14080", "test_ratint" ], "sympy/integrals/tests/test_rde.py": [ "test_bound_degree_fail", "test_order_at", "test_spde", "test_weak_normalizer" ], "sympy/integrals/tests/test_risch.py": [ "test_DifferentialExtension_Rothstein", "test_DifferentialExtension_exp", "test_DifferentialExtension_handle_first", "test_DifferentialExtension_log", "test_DifferentialExtension_symlog", "test_NonElementaryIntegral", "test_derivation", "test_hermite_reduce", "test_integrate_hyperexponential", "test_integrate_hyperexponential_polynomial", "test_integrate_hyperexponential_returns_piecewise", "test_integrate_nonlinear_no_specials", "test_integrate_primitive", "test_issue_13947", "test_laurent_series", "test_recognize_log_derivative", "test_residue_reduce", "test_risch_integrate", "test_risch_integrate_float", "test_splitfactor" ], "sympy/integrals/tests/test_singularityfunctions.py": [ "test_singularityintegrate" ], "sympy/integrals/tests/test_transforms.py": [ "test_cosine_transform", "test_hankel_transform", "test_inverse_laplace_transform_delta", "test_inverse_laplace_transform_delta_cond", "test_issue_12591", "test_issue_14692", "test_issue_7173", "test_issue_7181", "test_issue_8514", "test_mellin_transform", "test_sine_transform", "test_undefined_function" ], "sympy/integrals/tests/test_trigonometry.py": [ "test_trigintegrate_mixed", "test_trigintegrate_odd" ], "sympy/interactive/tests/test_ipythonprinting.py": [ "test_matplotlib_bad_latex" ], "sympy/liealgebras/tests/test_weyl_group.py": [ "test_weyl_group" ], "sympy/logic/tests/test_boolalg.py": [ "test_bool_as_set", "test_issue_14700", "test_issue_8777", "test_issue_8975", "test_relational_simplification_patterns_numerically", "test_simplification" ], "sympy/logic/tests/test_dimacs.py": [ "test_f4" ], "sympy/logic/tests/test_inference.py": [ "test_pl_true" ], "sympy/matrices/expressions/tests/test_blockmatrix.py": [ "test_BlockMatrix", "test_BlockMatrix_Determinant" ], "sympy/matrices/expressions/tests/test_derivatives.py": [ "test_derivatives_elementwise_applyfunc", "test_derivatives_of_complicated_matrix_expr", "test_matrix_derivative_vectors_and_scalars", "test_matrix_derivatives_of_traces" ], "sympy/matrices/expressions/tests/test_determinant.py": [ "test_refine" ], "sympy/matrices/expressions/tests/test_inverse.py": [ "test_refine" ], "sympy/matrices/expressions/tests/test_matexpr.py": [ "test_Identity", "test_MatMul_postprocessor", "test_MatrixSymbol_determinant" ], "sympy/matrices/expressions/tests/test_matmul.py": [ "test_refine" ], "sympy/matrices/expressions/tests/test_transpose.py": [ "test_refine" ], "sympy/matrices/tests/test_commonmatrix.py": [ "test_det", "test_is_diagonalizable", "test_jordan_form", "test_refine", "test_rref", "test_simplify", "test_singular_values" ], "sympy/matrices/tests/test_matrices.py": [ "test_LDLsolve", "test_Matrix_berkowitz_charpoly", "test_QRsolve", "test_bidiagonalize", "test_cholesky_solve", "test_columnspace", "test_determinant", "test_diagonalization", "test_diff_by_matrix", "test_dual", "test_eigen", "test_find_reasonable_pivot_naive_finds_guaranteed_nonzero2", "test_find_reasonable_pivot_naive_simplifies", "test_inv_block", "test_inverse", "test_invertible_check", "test_issue_11434", "test_issue_14517", "test_issue_15872", "test_issue_3749", "test_issue_8240", "test_jacobian_metrics", "test_jordan_form", "test_jordan_form_complex_issue_9274", "test_jordan_form_issue_15858", "test_limit", "test_matrix_norm", "test_opportunistic_simplification", "test_pinv", "test_power", "test_rank", "test_rank_regression_from_so", "test_refine", "test_simplify" ], "sympy/matrices/tests/test_sparse.py": [ "test_add", "test_sparse_matrix", "test_sparse_solve" ], "sympy/ntheory/tests/test_continued_fraction.py": [ "test_continued_fraction" ], "sympy/ntheory/tests/test_factor_.py": [ "test_factorint", "test_multiplicity", "test_perfect_power", "test_primenu", "test_primeomega" ], "sympy/ntheory/tests/test_generate.py": [ "test_composite", "test_compositepi", "test_generate", "test_prime", "test_primepi" ], "sympy/ntheory/tests/test_primetest.py": [ "test_isprime", "test_prps" ], "sympy/ntheory/tests/test_residue.py": [ "test_residue" ], "sympy/parsing/tests/test_mathematica.py": [ "test_mathematica" ], "sympy/parsing/tests/test_maxima.py": [ "test_maxima_functions" ], "sympy/physics/continuum_mechanics/tests/test_beam.py": [ "test_Beam", "test_apply_support", "test_beam_units", "test_composite_beam", "test_insufficient_bconditions", "test_max_bmoment", "test_max_deflection", "test_parabolic_loads", "test_point_cflexure", "test_statically_indeterminate" ], "sympy/physics/hep/tests/test_gamma_matrices.py": [ "test_gamma_matrix_class", "test_gamma_matrix_trace", "test_kahane_algorithm", "test_kahane_simplify1" ], "sympy/physics/mechanics/tests/test_kane.py": [ "test_input_format", "test_parallel_axis", "test_pend", "test_rolling_disc", "test_two_dof" ], "sympy/physics/mechanics/tests/test_kane2.py": [ "test_non_central_inertia", "test_sub_qdot", "test_sub_qdot2" ], "sympy/physics/mechanics/tests/test_lagrange.py": [ "test_disc_on_an_incline_plane", "test_dub_pen", "test_nonminimal_pendulum", "test_rolling_disc" ], "sympy/physics/mechanics/tests/test_lagrange2.py": [ "test_lagrange_2forces" ], "sympy/physics/mechanics/tests/test_linearize.py": [ "test_linearize_pendulum_kane_minimal", "test_linearize_pendulum_kane_nonminimal", "test_linearize_pendulum_lagrange_minimal", "test_linearize_pendulum_lagrange_nonminimal", "test_linearize_rolling_disc_lagrange" ], "sympy/physics/mechanics/tests/test_models.py": [ "test_multi_mass_spring_damper_higher_order", "test_multi_mass_spring_damper_inputs", "test_n_link_pendulum_on_cart_higher_order", "test_n_link_pendulum_on_cart_inputs" ], "sympy/physics/mechanics/tests/test_rigidbody.py": [ "test_rigidbody3" ], "sympy/physics/optics/tests/test_gaussopt.py": [ "test_gauss_opt" ], "sympy/physics/optics/tests/test_utils.py": [ "test_deviation", "test_lens_formula", "test_mirror_formula", "test_refraction_angle" ], "sympy/physics/optics/tests/test_waves.py": [ "test_twave" ], "sympy/physics/quantum/tests/test_cartesian.py": [ "test_p", "test_x" ], "sympy/physics/quantum/tests/test_cg.py": [ "test_cg_simp_add" ], "sympy/physics/quantum/tests/test_circuitutils.py": [ "test_random_insert" ], "sympy/physics/quantum/tests/test_density.py": [ "test_entropy", "test_fidelity", "test_represent" ], "sympy/physics/quantum/tests/test_gate.py": [ "test_cgate", "test_one_qubit_anticommutators", "test_one_qubit_commutators", "test_random_circuit", "test_swap_gate" ], "sympy/physics/quantum/tests/test_grover.py": [ "test_grover", "test_grover_iteration_2" ], "sympy/physics/quantum/tests/test_identitysearch.py": [ "test_bfs_identity_search" ], "sympy/physics/quantum/tests/test_matrixutils.py": [ "test_matrix_tensor_product" ], "sympy/physics/quantum/tests/test_qapply.py": [ "test_anticommutator", "test_basic", "test_commutator", "test_extra", "test_issue3044", "test_outerproduct" ], "sympy/physics/quantum/tests/test_qft.py": [ "test_qft_represent", "test_quantum_fourier" ], "sympy/physics/quantum/tests/test_qubit.py": [ "test_eval_trace", "test_measure_partial" ], "sympy/physics/quantum/tests/test_spin.py": [ "test_couple_2_states", "test_couple_2_states_numerical", "test_couple_3_states", "test_couple_3_states_numerical", "test_couple_4_states_numerical", "test_innerproducts_of_rewritten_states", "test_j2", "test_jminus", "test_jplus", "test_jx", "test_jy", "test_jz", "test_represent_coupled_states", "test_represent_spin_states", "test_represent_uncoupled_states", "test_rewrite_Bra", "test_rewrite_Ket", "test_rewrite_coupled_state", "test_rewrite_uncoupled_state", "test_rotation", "test_rotation_d", "test_rotation_small_d", "test_uncouple_2_coupled_states", "test_uncouple_2_coupled_states_numerical", "test_uncouple_3_coupled_states", "test_uncouple_3_coupled_states_numerical", "test_uncouple_4_coupled_states_numerical" ], "sympy/physics/quantum/tests/test_state.py": [ "test_wavefunction" ], "sympy/physics/tests/test_clebsch_gordan.py": [ "test_dot_rota_grad_SH", "test_wigner" ], "sympy/physics/tests/test_hydrogen.py": [ "test_hydrogen_energies_relat", "test_norm", "test_wavefunction" ], "sympy/physics/tests/test_pring.py": [ "test_orthogonality" ], "sympy/physics/tests/test_qho_1d.py": [ "test_coherent_state", "test_norm", "test_wavefunction" ], "sympy/physics/tests/test_secondquant.py": [ "test_dummy_order_inner_outer_lines_VT1T1T1T1", "test_dummy_order_inner_outer_lines_VT1T1T1_AT", "test_equivalent_internal_lines_VT1T1", "test_equivalent_internal_lines_VT1T1_AT", "test_equivalent_internal_lines_VT2", "test_equivalent_internal_lines_VT2_AT", "test_equivalent_internal_lines_VT2conjT2", "test_equivalent_internal_lines_VT2conjT2_AT", "test_equivalent_internal_lines_VT2conjT2_ambiguous_order", "test_equivalent_internal_lines_VT2conjT2_ambiguous_order_AT", "test_fully_contracted", "test_internal_external_VT2T2", "test_internal_external_VT2T2_AT", "test_internal_external_pqrs_AT", "test_substitute_dummies_substitution_order", "test_wicks" ], "sympy/physics/tests/test_sho.py": [ "test_sho_R_nl" ], "sympy/physics/units/tests/test_util.py": [ "test_convert_to_quantities", "test_convert_to_tuples_of_quantities", "test_eval_simplify" ], "sympy/physics/vector/tests/test_dyadic.py": [ "test_dyadic", "test_dyadic_simplify" ], "sympy/physics/vector/tests/test_fieldfunctions.py": [ "test_conservative", "test_curl", "test_divergence", "test_gradient", "test_scalar_potential", "test_scalar_potential_difference", "test_solenoidal" ], "sympy/physics/vector/tests/test_frame.py": [ "test_ang_vel", "test_coordinate_vars", "test_dcm", "test_issue_10348" ], "sympy/physics/vector/tests/test_functions.py": [ "test_cross_different_frames", "test_dot_different_frames", "test_express", "test_get_motion_methods", "test_operator_match", "test_partial_velocity", "test_time_derivative" ], "sympy/physics/vector/tests/test_output.py": [ "test_output_type" ], "sympy/physics/vector/tests/test_point.py": [ "test_point_a1pt_theorys" ], "sympy/physics/vector/tests/test_vector.py": [ "test_Vector", "test_Vector_diffs", "test_vector_simplify" ], "sympy/plotting/tests/test_plot.py": [ "test_issue_15265", "test_matplotlib_1", "test_matplotlib_2", "test_matplotlib_3", "test_matplotlib_6", "test_matplotlib_7" ], "sympy/polys/agca/tests/test_homomorphisms.py": [ "test_creation" ], "sympy/polys/agca/tests/test_modules.py": [ "test_ModulesQuotientRing" ], "sympy/polys/domains/tests/test_domains.py": [ "test_Domain__contains__", "test_Domain_unify_algebraic" ], "sympy/polys/tests/test_constructor.py": [ "test_construct_domain" ], "sympy/polys/tests/test_dispersion.py": [ "test_dispersion" ], "sympy/polys/tests/test_euclidtools.py": [ "test_dmp_gcd", "test_dmp_subresultants" ], "sympy/polys/tests/test_factortools.py": [ "test_dmp_factor_list", "test_dmp_zz_factor" ], "sympy/polys/tests/test_galoistools.py": [ "test_gf_factor" ], "sympy/polys/tests/test_groebnertools.py": [ "test_benchmark_coloring", "test_benchmark_czichowski_buchberger", "test_benchmark_czichowski_f5b" ], "sympy/polys/tests/test_heuristicgcd.py": [ "test_heugcd_multivariate_integers" ], "sympy/polys/tests/test_modulargcd.py": [ "test_modgcd_algebraic_field", "test_modgcd_multivariate_integers" ], "sympy/polys/tests/test_multivariate_resultants.py": [ "test_get_dixon_matrix", "test_get_dixon_matrix_example_two", "test_get_dixon_polynomial_numerical", "test_macaulay_example_one", "test_macaulay_example_two" ], "sympy/polys/tests/test_numberfields.py": [ "test_AlgebraicNumber", "test_field_isomorphism", "test_field_isomorphism_pslq", "test_issue_14831", "test_minimal_polynomial", "test_minimal_polynomial_sq", "test_minpoly_compose", "test_minpoly_fraction_field", "test_minpoly_fraction_field_slow", "test_primitive_element", "test_to_number_field" ], "sympy/polys/tests/test_partfrac.py": [ "test_apart", "test_apart_extension", "test_apart_full", "test_apart_list", "test_apart_symbolic", "test_apart_undetermined_coeffs" ], "sympy/polys/tests/test_polyroots.py": [ "test_issue_14291", "test_issue_14522", "test_issue_8285", "test_issue_8289", "test_issue_8438", "test_nroots1", "test_roots0", "test_roots_binomial", "test_roots_cubic", "test_roots_cyclotomic", "test_roots_mixed", "test_roots_preprocessed", "test_roots_preprocessing", "test_roots_quadratic", "test_roots_quartic", "test_roots_slow" ], "sympy/polys/tests/test_polytools.py": [ "test_cancel", "test_factor", "test_factor_large", "test_fglm", "test_intervals", "test_issue_5786", "test_sqf_norm", "test_torational_factor_list", "test_transform" ], "sympy/polys/tests/test_polyutils.py": [ "test__nsort" ], "sympy/polys/tests/test_rationaltools.py": [ "test_together" ], "sympy/polys/tests/test_ring_series.py": [ "test_RR", "test_atan", "test_atanh", "test_log", "test_nth_root", "test_tan", "test_tanh" ], "sympy/polys/tests/test_rings.py": [ "test_sring" ], "sympy/polys/tests/test_rootisolation.py": [ "test_dup_count_complex_roots_4", "test_dup_count_complex_roots_5", "test_dup_count_complex_roots_6", "test_dup_count_complex_roots_7", "test_dup_count_complex_roots_8", "test_dup_count_complex_roots_exclude", "test_dup_isolate_real_roots_sqf" ], "sympy/polys/tests/test_rootoftools.py": [ "test_CRootOf___eval_Eq__", "test_CRootOf___new__", "test_RootSum___new__", "test_RootSum_rational", "test_eval_approx_relative", "test_issue_8316" ], "sympy/polys/tests/test_solvers.py": [ "test_solve_lin_sys_6x6_1", "test_solve_lin_sys_6x6_2" ], "sympy/polys/tests/test_specialpolys.py": [ "test_swinnerton_dyer_poly" ], "sympy/polys/tests/test_subresultants_qq_zz.py": [ "test_bezout", "test_euclid_amv", "test_euclid_pg", "test_modified_subresultants_amv", "test_modified_subresultants_bezout", "test_modified_subresultants_pg", "test_modified_subresultants_sylv", "test_sturm_amv", "test_sturm_pg", "test_subresultants_amv", "test_subresultants_amv_q", "test_subresultants_bezout", "test_subresultants_pg", "test_subresultants_rem", "test_subresultants_sylv", "test_subresultants_vv", "test_subresultants_vv_2" ], "sympy/printing/pretty/tests/test_pretty.py": [ "test_pretty_FormalPowerSeries", "test_pretty_FourierSeries", "test_pretty_functions", "test_pretty_geometry", "test_pretty_ndim_arrays", "test_pretty_order", "test_pretty_sequences" ], "sympy/printing/tests/test_ccode.py": [ "test_C99CodePrinter__precision", "test_ccode_Min_performance" ], "sympy/printing/tests/test_fcode.py": [ "test_fcode_Piecewise" ], "sympy/printing/tests/test_glsl.py": [ "test_MxN_mats", "test_misc_mats" ], "sympy/printing/tests/test_lambdarepr.py": [ "test_piecewise" ], "sympy/printing/tests/test_latex.py": [ "test_latex_FormalPowerSeries", "test_latex_FourierSeries", "test_latex_functions" ], "sympy/printing/tests/test_repr.py": [ "test_more_than_255_args_issue_10259" ], "sympy/printing/tests/test_str.py": [ "test_Add" ], "sympy/series/tests/test_approximants.py": [ "test_approximants" ], "sympy/series/tests/test_demidovich.py": [ "test_Limits_simple_0", "test_Limits_simple_1", "test_Limits_simple_2", "test_Limits_simple_3a", "test_Limits_simple_3b", "test_Limits_simple_4a", "test_Limits_simple_4b", "test_Limits_simple_4c", "test_bounded", "test_f1a", "test_f1a2", "test_f1b", "test_f2", "test_f2a", "test_f3", "test_leadterm", "test_limits_simple_4aa" ], "sympy/series/tests/test_formal.py": [ "test_fps", "test_fps__Add_expr", "test_fps__asymptotic", "test_fps__fractional", "test_fps__logarithmic_singularity", "test_fps__logarithmic_singularity_fail", "test_fps__operations", "test_fps__slow", "test_fps__symbolic", "test_fps_shift", "test_hyper_re", "test_rational_algorithm", "test_simpleDE" ], "sympy/series/tests/test_fourier.py": [ "test_FourierSeries", "test_FourierSeries_2", "test_FourierSeries__add__sub", "test_FourierSeries__operations", "test_FourierSeries_finite", "test_fourier_series_square_wave" ], "sympy/series/tests/test_gruntz.py": [ "test_I", "test_MrvTestCase_page47_ex3_21", "test_aseries_trig", "test_compare1", "test_compare2", "test_compare3", "test_exp_log_series", "test_gruntz_eval_special_fail", "test_gruntz_hyperbolic", "test_intractable", "test_issue_3644", "test_issue_4109", "test_issue_4190", "test_issue_5172", "test_issue_6682", "test_issue_6843", "test_limit1", "test_limit2", "test_limit3", "test_limit4", "test_mrv1", "test_mrv2a", "test_mrv2b", "test_mrv2c", "test_mrv3", "test_mrv_leadterm1", "test_mrv_leadterm2", "test_mrv_leadterm3", "test_rewrite1", "test_rewrite3", "test_sign1" ], "sympy/series/tests/test_limits.py": [ "test_AccumBounds", "test_abs", "test_atan", "test_basic1", "test_basic2", "test_basic4", "test_calculate_series", "test_ceiling", "test_ceiling_requires_robust_assumptions", "test_exponential", "test_exponential2", "test_extended_real_line", "test_factorial", "test_floor", "test_floor_requires_robust_assumptions", "test_heuristic", "test_issue_10102", "test_issue_10801", "test_issue_11879", "test_issue_12555", "test_issue_12564", "test_issue_14377", "test_issue_14411", "test_issue_14574", "test_issue_15984", "test_issue_3792", "test_issue_3871", "test_issue_3934", "test_issue_4090", "test_issue_4503", "test_issue_4546", "test_issue_4547", "test_issue_5164", "test_issue_5172", "test_issue_5183", "test_issue_5184", "test_issue_5229", "test_issue_5436", "test_issue_5740", "test_issue_5955", "test_issue_6364", "test_issue_6366", "test_issue_6560", "test_issue_6599", "test_issue_7088", "test_newissue", "test_polynomial", "test_rational" ], "sympy/series/tests/test_limitseq.py": [ "test_accum_bounds", "test_alternating_sign", "test_issue_10382", "test_limit_seq_fail", "test_limitseq_sum" ], "sympy/series/tests/test_lseries.py": [ "test_cos", "test_exp", "test_exp2", "test_issue_5183", "test_issue_6999", "test_sin" ], "sympy/series/tests/test_nseries.py": [ "test_abs", "test_bug2", "test_bug5", "test_ceiling", "test_dir", "test_exp", "test_exp_1", "test_exp_sqrt_1", "test_expbug4", "test_expsinbug", "test_floor", "test_geometric_1", "test_issue_3204", "test_issue_3224", "test_issue_3258", "test_issue_3463", "test_issue_3501", "test_issue_3502", "test_issue_3504", "test_issue_3505", "test_issue_3506", "test_issue_3507", "test_issue_3508", "test_issue_4115", "test_issue_4329", "test_issue_4441", "test_issue_5183", "test_issue_5654", "test_issue_5925", "test_log_series", "test_log_singular1", "test_mul_1", "test_pole", "test_power_x_x1", "test_series1", "test_series2", "test_seriesbug2c", "test_seriesbug2d", "test_sin", "test_sinsinbug", "test_sqrt_1" ], "sympy/series/tests/test_order.py": [ "test_add_1", "test_contains_1", "test_contains_3", "test_contains_4", "test_issue_14622", "test_issue_15539", "test_issue_4279", "test_issue_9351", "test_ln_args", "test_multivar_1", "test_order_at_infinity", "test_order_subs_limits", "test_performance_of_adding_order", "test_simple_3", "test_simple_6" ], "sympy/series/tests/test_residues.py": [ "test_NotImplemented", "test_basic1", "test_basic2", "test_bug", "test_expressions", "test_expressions_failing", "test_f", "test_functions", "test_issue_5654", "test_issue_6499" ], "sympy/series/tests/test_series.py": [ "test_acceleration", "test_cos", "test_exp", "test_exp2", "test_exp_product_positive_factors", "test_issue_11313", "test_issue_14885", "test_issue_15539", "test_issue_3978", "test_issue_4583", "test_issue_5223", "test_issue_5852", "test_issue_7203", "test_series_of_Subs", "test_sin", "test_sin_power" ], "sympy/sets/tests/test_fancysets.py": [ "test_ComplexRegion_intersect", "test_ComplexRegion_union", "test_ImageSet", "test_Range_set", "test_imageset_intersect_interval", "test_infinitely_indexed_set_1", "test_issue_11914", "test_issue_11938", "test_normalize_theta_set", "test_range_range_intersection" ], "sympy/sets/tests/test_setexpr.py": [ "test_Add_Mul", "test_Interval_FiniteSet", "test_Many_Sets", "test_SetExpr_Interval_div", "test_SetExpr_Interval_pow", "test_compound" ], "sympy/sets/tests/test_sets.py": [ "test_Complement", "test_complement", "test_contains", "test_image_interval", "test_image_piecewise", "test_issue_10113", "test_issue_Symbol_inter", "test_real" ], "sympy/simplify/tests/test_combsimp.py": [ "test_combsimp", "test_issue_14528" ], "sympy/simplify/tests/test_cse.py": [ "test_ignore_order_terms", "test_issue_11230", "test_issue_7840" ], "sympy/simplify/tests/test_fu.py": [ "test_TR10i", "test_TR12i", "test_TR8", "test_TR9", "test_TRmorrie", "test_TRpower", "test_fu", "test_hyper_as_trig" ], "sympy/simplify/tests/test_gammasimp.py": [ "test_gammasimp" ], "sympy/simplify/tests/test_hyperexpand.py": [ "test_Mod1_behavior", "test_branch_bug", "test_hyperexpand", "test_hyperexpand_bases", "test_hyperexpand_parametric", "test_hyperexpand_special", "test_lerchphi", "test_meijerg", "test_meijerg_expand_fail", "test_meijerg_formulae", "test_meijerg_lookup", "test_meijerg_shift_operators", "test_meijerg_with_Floats", "test_omgissue_203", "test_partial_simp", "test_plan", "test_plan_derivatives", "test_polynomial", "test_prudnikov_1", "test_prudnikov_11", "test_prudnikov_12", "test_prudnikov_2F1", "test_prudnikov_9", "test_prudnikov_fail_3F2", "test_reduction_operators", "test_roach", "test_roach_fail", "test_shift_operators", "test_shifted_sum", "test_ushift_operators" ], "sympy/simplify/tests/test_powsimp.py": [ "test_issue_5728", "test_issue_6367", "test_powdenest", "test_powsimp" ], "sympy/simplify/tests/test_radsimp.py": [ "test_collect_order", "test_issue_5933", "test_radsimp" ], "sympy/simplify/tests/test_ratsimp.py": [ "test_ratsimp", "test_ratsimpmodprime" ], "sympy/simplify/tests/test_simplify.py": [ "test_Piecewise", "test_besselsimp", "test_hypersimp", "test_issue_3557", "test_issue_6920", "test_issue_7001", "test_issue_7263", "test_logcombine_1", "test_nc_simplify", "test_nsimplify", "test_nthroot", "test_nthroot1", "test_separatevars", "test_simplify_complex", "test_simplify_expr", "test_simplify_measure", "test_simplify_other", "test_simplify_ratio" ], "sympy/simplify/tests/test_sqrtdenest.py": [ "test_sqrt_symbolic_denest", "test_sqrtdenest2", "test_sqrtdenest3", "test_sqrtdenest4", "test_sqrtdenest_rec" ], "sympy/simplify/tests/test_traversaltools.py": [ "test_use" ], "sympy/simplify/tests/test_trigsimp.py": [ "test_Piecewise", "test_exptrigsimp", "test_hyperbolic_simp", "test_issue_15129_trigsimp_methods", "test_issue_3210", "test_issue_4280", "test_issue_4494", "test_issue_4661", "test_issue_4775", "test_issue_6811_fail", "test_trigsimp1", "test_trigsimp1a", "test_trigsimp2", "test_trigsimp3", "test_trigsimp_issue_3826", "test_trigsimp_issues", "test_trigsimp_noncommutative", "test_trigsimp_old" ], "sympy/solvers/tests/test_constantsimp.py": [ "test_constant_mul", "test_ode_solutions" ], "sympy/solvers/tests/test_diophantine.py": [ "test_DN", "test_bf_pell", "test_diop_general_sum_of_squares_quick", "test_diop_ternary_quadratic", "test_diop_ternary_quadratic_normal", "test_diopcoverage", "test_diophantine", "test_diophantine_permute_sign", "test_general_pythagorean", "test_issue_9106", "test_length", "test_no_square_ternary_quadratic", "test_parametrize_ternary_quadratic", "test_power_representation", "test_quadratic_non_perfect_square", "test_quadratic_parabolic_case", "test_quadratic_perfect_square", "test_transformation_to_normal", "test_transformation_to_pell" ], "sympy/solvers/tests/test_inequalities.py": [ "test__solve_inequality", "test_issue_10047", "test_issue_10198", "test_issue_10268", "test_issue_10671_12466", "test_issue_8235", "test_issue_8974", "test_reduce_abs_inequalities", "test_reduce_inequalities_errors", "test_reduce_inequalities_general", "test_reduce_poly_inequalities_complex_relational", "test_reduce_poly_inequalities_real_interval", "test_reduce_rational_inequalities_real_relational", "test_slow_general_univariate", "test_solve_univariate_inequality", "test_trig_inequalities" ], "sympy/solvers/tests/test_numeric.py": [ "test_nsolve" ], "sympy/solvers/tests/test_ode.py": [ "test_1st_homogeneous_coeff_corner_case", "test_1st_homogeneous_coeff_ode2", "test_1st_homogeneous_coeff_ode3", "test_1st_homogeneous_coeff_ode_check2", "test_1st_homogeneous_coeff_ode_check7", "test_1st_homogeneous_coeff_ode_check9", "test_1st_linear", "test_2nd_power_series_regular", "test_Bernoulli", "test_Liouville_ODE", "test_Riccati_special_minus2", "test_almost_linear", "test_checksysodesol", "test_classify_ode", "test_classify_ode_ics", "test_classify_sysode", "test_dsolve_linsystem_symbol", "test_dsolve_linsystem_symbol_piecewise", "test_exact_enhancement", "test_factoring_ode", "test_heuristic1", "test_heuristic2", "test_heuristic_4", "test_heuristic_abaco2_similar", "test_heuristic_abaco2_unique_unknown", "test_heuristic_function_sum", "test_heuristic_linear", "test_homogeneous_function", "test_homogeneous_order", "test_issue_10379", "test_issue_10867", "test_issue_11290", "test_issue_11542", "test_issue_14395", "test_issue_15913", "test_issue_4785", "test_issue_4838", "test_issue_5095", "test_issue_5770", "test_issue_5787", "test_issue_6247", "test_issue_6879", "test_issue_6989", "test_issue_7081", "test_issue_7093", "test_kamke", "test_lie_group_issue15219", "test_linear_2eq_order1", "test_linear_3eq_order1", "test_linear_coefficients", "test_nonlinear_2eq_order1", "test_nth_algebraic_find_multiple1", "test_nth_algebraic_find_multiple2", "test_nth_algebraic_issue15999", "test_nth_algebraic_noprep1", "test_nth_algebraic_noprep2", "test_nth_algebraic_prep1", "test_nth_algebraic_prep2", "test_nth_algebraic_redundant_solutions", "test_nth_linear_constant_coeff_homogeneous_irrational", "test_nth_linear_constant_coeff_undetermined_coefficients_imaginary_exp", "test_nth_order_linear_euler_eq_homogeneous", "test_nth_order_linear_euler_eq_nonhomogeneous_undetermined_coefficients", "test_ode_order", "test_old_ode_tests", "test_separable1", "test_separable4", "test_separable_1_5_checkodesol", "test_series", "test_sysode_linear_2eq_order1_many_zeros", "test_sysode_linear_2eq_order1_type1_D_lt_0", "test_sysode_linear_neq_order1", "test_undetermined_coefficients_match", "test_unexpanded_Liouville_ODE", "test_user_infinitesimals" ], "sympy/solvers/tests/test_pde.py": [ "test_checkpdesol", "test_pde_1st_linear_constant_coeff", "test_pde_1st_linear_constant_coeff_homogeneous", "test_pde_classify", "test_pde_separate_add", "test_pde_separate_mul", "test_pdsolve_all", "test_pdsolve_variable_coeff" ], "sympy/solvers/tests/test_polysys.py": [ "test_solve_biquadratic", "test_solve_poly_system", "test_solve_triangulated" ], "sympy/solvers/tests/test_recurr.py": [ "test_issue_6844", "test_rsolve_bulk", "test_rsolve_hyper", "test_rsolve_poly", "test_rsolve_ratio" ], "sympy/solvers/tests/test_solvers.py": [ "test_PR1964", "test_atan2", "test_checking", "test_errorinverses", "test_exclude", "test_float_handling", "test_guess_poly", "test_guess_poly_cv", "test_guess_rational_cv", "test_guess_transcendental", "test_high_order_roots", "test_highorder_poly", "test_issue_11538", "test_issue_12448", "test_issue_12476", "test_issue_13849", "test_issue_14607", "test_issue_14721", "test_issue_14779", "test_issue_2725", "test_issue_2777", "test_issue_3870", "test_issue_4463", "test_issue_4671_4463_4467", "test_issue_5114_6611", "test_issue_5132", "test_issue_5197", "test_issue_5335", "test_issue_5849", "test_issue_5849_matrix", "test_issue_5901", "test_issue_5912", "test_issue_6056", "test_issue_6528", "test_issue_6605", "test_issue_6644", "test_issue_6792", "test_issue_7190", "test_issue_7228", "test_issues_6819_6820_6821_6248_8692", "test_linear_system", "test_minsolve_linear_system", "test_other_lambert", "test_overdetermined", "test_polysys", "test_quintics_1", "test_quintics_2", "test_real_imag_splitting", "test_rewrite_trig", "test_rewrite_trigh", "test_solve_args", "test_solve_for_functions_derivatives", "test_solve_inequalities", "test_solve_nonlinear", "test_solve_polynomial1", "test_solve_polynomial_cv_1a", "test_solve_polynomial_cv_1b", "test_swap_back", "test_uselogcombine" ], "sympy/solvers/tests/test_solveset.py": [ "test_conditionset", "test_conditionset_equality", "test_expo_conditionset", "test_exponential_complex", "test_exponential_real", "test_exponential_symbols", "test_invert_real", "test_issue_10069", "test_issue_10158", "test_issue_10477", "test_issue_10671", "test_issue_11064", "test_issue_11534", "test_issue_12429", "test_issue_12478", "test_issue_13849", "test_issue_14223", "test_issue_14454", "test_issue_2777", "test_issue_5132_1", "test_issue_5132_2", "test_issue_5132_substitution", "test_issue_8715", "test_issue_8828", "test_issue_9565", "test_issue_9913", "test_linsolve", "test_logarithmic", "test_no_sol", "test_nonlinsolve_basic", "test_nonlinsolve_complex", "test_nonlinsolve_conditionset", "test_nonlinsolve_polysys", "test_nonlinsolve_positive_dimensional", "test_nonlinsolve_using_substitution", "test_other_lambert", "test_piecewise_solveset", "test_real_imag_splitting", "test_return_root_of", "test_rewrite_trigh", "test_solve_abs", "test_solve_complex_sqrt", "test_solve_decomposition", "test_solve_exponential", "test_solve_invalid_sol", "test_solve_nonlinear_trans", "test_solve_only_exp_1", "test_solve_polynomial", "test_solve_polynomial_cv_1a", "test_solve_polynomial_symbolic_param", "test_solve_rational", "test_solve_trig", "test_solve_trig_simplified", "test_solveset", "test_solveset_arg", "test_solveset_complex_exp", "test_solveset_complex_polynomial", "test_solveset_complex_rational", "test_solveset_complex_tan", "test_solveset_real_exp", "test_solveset_sqrt_1", "test_solveset_sqrt_2", "test_solvify", "test_substitution_basic", "test_trig_system", "test_trig_system_fail" ], "sympy/stats/tests/test_continuous_rv.py": [ "test_ContinuousRV", "test_NormalDistribution", "test_Or", "test_beta", "test_cdf", "test_chi_squared", "test_conditional_1d", "test_conjugate_priors", "test_difficult_univariate", "test_exponential", "test_gamma", "test_issue_13324", "test_long_precomputed_cdf", "test_maxwell", "test_nakagami", "test_pareto", "test_pareto_numeric", "test_precomputed_characteristic_functions", "test_prefab_sampling", "test_rayleigh", "test_sample_continuous", "test_sampling_gamma_inverse", "test_single_normal", "test_symbolic", "test_triangular", "test_uniform", "test_uniform_P", "test_union", "test_weibull", "test_weibull_numeric", "test_wignersemicircle" ], "sympy/stats/tests/test_discrete_rv.py": [ "test_GeometricDistribution", "test_Logarithmic", "test_Or", "test_Poisson", "test_PoissonDistribution", "test_conditional", "test_discrete_probability", "test_moment_generating_functions", "test_negative_binomial", "test_precomputed_characteristic_functions", "test_product_spaces", "test_yule_simon", "test_zeta" ], "sympy/stats/tests/test_error_prop.py": [ "test_variance_prop", "test_variance_prop_with_covar" ], "sympy/stats/tests/test_finite_rv.py": [ "test_bernoulli", "test_binomial_numeric", "test_binomial_symbolic", "test_dice", "test_dice_bayes", "test_discreteuniform", "test_domains", "test_hypergeometric_numeric" ], "sympy/stats/tests/test_joint_rv.py": [ "test_JointRV", "test_MultivariateTDist", "test_Normal", "test_expectation" ], "sympy/stats/tests/test_mix.py": [ "test_compound_distribution", "test_density", "test_mix_expression" ], "sympy/stats/tests/test_rv.py": [ "test_H", "test_Sample", "test_dependence", "test_normality" ], "sympy/stats/tests/test_symbolic_probability.py": [ "test_literal_probability" ], "sympy/tensor/array/tests/test_arrayop.py": [ "test_array_permutedims" ], "sympy/tensor/tests/test_indexed.py": [ "test_indexed_is_constant" ], "sympy/tensor/tests/test_tensor.py": [ "test_TensMul_data", "test_TensorManager", "test_add1", "test_add2", "test_canonicalize1", "test_contract_delta1", "test_contract_metric2", "test_epsilon", "test_fun", "test_issue_11020_TensAdd_data", "test_metric_contract3", "test_riemann_cyclic", "test_tensor_expand", "test_tensor_replacement", "test_valued_assign_numpy_ndarray", "test_valued_canon_bp_swapaxes", "test_valued_metric_inverse", "test_valued_tensor_add_scalar", "test_valued_tensor_contraction", "test_valued_tensor_expressions", "test_valued_tensor_get_matrix" ], "sympy/unify/tests/test_rewrite.py": [ "test_assumptions" ], "sympy/utilities/_compilation/tests/test_compilation.py": [ "test_compile_link_import_strings" ], "sympy/utilities/tests/test_codegen.py": [ "test_complicated_codegen", "test_complicated_codegen_f95" ], "sympy/utilities/tests/test_codegen_julia.py": [ "test_complicated_jl_codegen" ], "sympy/utilities/tests/test_codegen_octave.py": [ "test_complicated_m_codegen" ], "sympy/utilities/tests/test_enumerative.py": [ "test_subrange", "test_subrange_large" ], "sympy/utilities/tests/test_iterables.py": [ "test_necklaces", "test_partitions" ], "sympy/utilities/tests/test_lambdify.py": [ "test_scipy_fns", "test_scipy_polys", "test_sym_integral" ], "sympy/utilities/tests/test_module_imports.py": [ "test_module_imports_are_direct" ], "sympy/utilities/tests/test_pickling.py": [ "test_concrete", "test_core_interval", "test_core_relational", "test_core_symbol", "test_functions", "test_pickling_polys_monomials", "test_pickling_polys_polytools", "test_pickling_polys_rootoftools", "test_series" ], "sympy/utilities/tests/test_wester.py": [ "test_C18", "test_C20", "test_C21", "test_C22", "test_G19", "test_G20", "test_H14", "test_H15", "test_H17", "test_H25", "test_H26", "test_H27", "test_H30", "test_H6", "test_I10", "test_I4", "test_J11", "test_J8", "test_K3", "test_K8", "test_L4", "test_L8", "test_L9", "test_M10", "test_M12", "test_M13", "test_M14", "test_M16", "test_M2", "test_M22", "test_M23", "test_M24", "test_M25", "test_M26", "test_M27", "test_M28", "test_M30", "test_M31", "test_M32", "test_M33", "test_M38", "test_M39", "test_M5", "test_M6", "test_M7", "test_N10", "test_N11", "test_N12", "test_N13", "test_N14", "test_N15", "test_N16", "test_N2", "test_N4", "test_N5", "test_N6", "test_N7", "test_N9", "test_P11", "test_P11_workaround", "test_P13", "test_P17", "test_P19", "test_P22", "test_P25", "test_P26", "test_P27", "test_P32", "test_P33", "test_R1", "test_R10", "test_R15", "test_R16", "test_R17", "test_R18", "test_R20", "test_R23", "test_R24", "test_R3", "test_R5", "test_R8", "test_R9", "test_T1", "test_T10", "test_T11", "test_T12", "test_T14", "test_T2", "test_T3", "test_T4", "test_T5", "test_T6", "test_T8", "test_U10", "test_U13", "test_U6", "test_U8", "test_V10", "test_V11", "test_V12", "test_V13", "test_V15", "test_V16", "test_V17", "test_V3", "test_V4", "test_V5", "test_V6", "test_V7", "test_W10", "test_W11", "test_W12", "test_W13", "test_W14", "test_W15", "test_W17", "test_W18", "test_W20", "test_W21", "test_W22", "test_W23b", "test_W26", "test_W3", "test_W4", "test_W5", "test_W7", "test_W9", "test_X1", "test_X10", "test_X11", "test_X12", "test_X13", "test_X16", "test_X17", "test_X18", "test_X2", "test_X21", "test_X3", "test_X4", "test_X5", "test_X6", "test_X7", "test_X8", "test_X9", "test_Y1", "test_Y10", "test_Y12", "test_Y2", "test_Y3", "test_Y4", "test_Y5_Y6", "test_Y7", "test_Y8", "test_Y9", "test_Z1", "test_Z2", "test_Z3", "test_Z4", "test_Z5", "test_Z6" ], "sympy/vector/tests/test_coordsysrect.py": [ "test_check_orthogonality", "test_orient_new_methods", "test_rotation_matrix", "test_rotation_trans_equations", "test_transformation_equations", "test_vector_with_orientation" ], "sympy/vector/tests/test_dyadic.py": [ "test_dyadic", "test_dyadic_simplify" ], "sympy/vector/tests/test_field_functions.py": [ "test_conservative", "test_del_operator", "test_differential_operators_curvilinear_system", "test_mixed_coordinates", "test_product_rules", "test_scalar_potential", "test_scalar_potential_difference" ], "sympy/vector/tests/test_functions.py": [ "test_express", "test_orthogonalize" ], "sympy/vector/tests/test_vector.py": [ "test_vector_simplify" ] } ] sympy-sympy-1.9/.ci/generate_durations_log.sh000077500000000000000000000006071412543434000214610ustar00rootroot00000000000000#!/bin/bash -e ABS_REPO_PATH=$(unset CDPATH && cd "$(dirname "$0")/.." && echo $PWD) cat <${ABS_REPO_PATH}/.ci/blacklisted.json { "sympy/physics/mechanics/tests/test_kane3.py": [ "test_bicycle" ], "sympy/utilities/tests/test_wester.py": [ "test_W25" ] } EOF ${PYTHON:-python} -m pytest -ra --durations 0 --verbose | tee $ABS_REPO_PATH/.ci/durations.log sympy-sympy-1.9/.ci/parse_durations_log.py000077500000000000000000000040741412543434000210210ustar00rootroot00000000000000#!/usr/bin/env python3 from collections import defaultdict import os import json import time ci_folder = os.path.dirname(__file__) def read_log(): start_token = '= slowest test durations =' start_token_seen = False for line in open(os.path.join(ci_folder, 'durations.log')): if start_token_seen: try: dur, kind, test_id = line.split() except: return else: if dur[0] not in '0123456789': return if kind != 'call': continue if dur[-1] != 's': raise NotImplementedError("expected seconds") yield test_id, float(dur[:-1]) elif start_token in line: start_token_seen = True def main(ref_timing, limits=(10, .1)): """ parses durations.log (made by generate_durations_log.sh) """ groupings = [defaultdict(list) for _ in range(len(limits))] accumul_n = [0 for _ in range(len(limits))] accumul_t = [0.0 for _ in range(len(limits))] for test_id, dur in read_log(): if test_id.startswith('sympy/utilities/tests/test_code_quality.py'): continue # white-listed (worth running since it catches many errors) for idx, lim in enumerate(limits): if dur/ref_timing >= lim: fname, tname = test_id.split('::') groupings[idx][fname].append(tname) accumul_t[idx] += dur accumul_n[idx] += 1 break json_data = json.dumps([{k: sorted(v) for k, v in gr.items()} for gr in groupings], indent=4, sort_keys=True) open(os.path.join(ci_folder, 'durations.json'), 'wt').write(json_data) print('number in group, accumulated_time: %s' % str(list(zip(accumul_n, accumul_t)))) def slow_function(): t = time.time() a = 0 for i in range(5): a += sum([x**.3 - x**i for x in range(1000000) if x % 3 == 0]) return time.time() - t if __name__ == '__main__': ref_time = slow_function() main(ref_time) sympy-sympy-1.9/.editorconfig000066400000000000000000000007611412543434000164040ustar00rootroot00000000000000root = true [*] end_of_line = lf insert_final_newline = true trim_trailing_whitespace = true charset = utf-8 # Python files [*.py] indent_style = space indent_size = 4 # isort plugin configuration known_first_party = sympy multi_line_output = 4 default_section = THIRDPARTY skip = .eggs # RST files (used by sphinx) [*.rst] indent_style = space indent_size = 3 # JSON, YML [*.{json,yml}] indent_style = space indent_size = 2 # Tab indentation (no size specified) [Makefile] indent_type = tab sympy-sympy-1.9/.gitattributes000066400000000000000000000002131412543434000166120ustar00rootroot00000000000000*.py diff=python *.sh eol=lf # auto-collapse generated files in github diffs sympy/parsing/*/_antlr/*.py linguist-generated=true sympy-sympy-1.9/.github/000077500000000000000000000000001412543434000152635ustar00rootroot00000000000000sympy-sympy-1.9/.github/workflows/000077500000000000000000000000001412543434000173205ustar00rootroot00000000000000sympy-sympy-1.9/.github/workflows/ci-sage.yml000066400000000000000000000175501412543434000213630ustar00rootroot00000000000000name: Run Sage CI ## This GitHub Actions workflow provides: ## ## - portability testing, by building and testing this project on many platforms ## ## - continuous integration, by building and testing other software ## that depends on this project. ## ## The testing can be monitored in the "Actions" tab of the GitHub repository. ## ## After all jobs have finished (or are canceled) and a short delay, ## tar files of all logs are made available as "build artifacts". ## ## This GitHub Actions workflow uses the portability testing framework ## of SageMath (https://www.sagemath.org/). For more information, see ## https://doc.sagemath.org/html/en/developer/portability_testing.html ## The workflow consists of two jobs: ## ## - First, it builds a source distribution of the project ## and generates a script "update-pkgs.sh". It uploads them ## as a build artifact named upstream. ## ## - Second, it checks out a copy of the SageMath source tree. ## It downloads the upstream artifact and replaces the project's ## package in the SageMath distribution by the newly packaged one ## from the upstream artifact, by running the script "update-pkgs.sh". ## Then it builds a small portion of the Sage distribution. ## ## Many copies of the second step are run in parallel for each of the tested ## systems/configurations. on: push: branches: - master # run on release branches # https://docs.github.com/en/actions/reference/workflow-syntax-for-github-actions#patterns-to-match-branches-and-tags - "[1-9].[0-9]+*" workflow_dispatch: # Allow to run manually env: # Ubuntu packages to install so that the project's "make dist" can succeed DIST_PREREQ: python3-setuptools # Name of this project in the Sage distribution SPKG: sympy # Sage distribution packages to build TARGETS_PRE: build/make/Makefile TARGETS: SAGE_CHECK=no SAGE_CHECK_PACKAGES=sympy build ptest TARGETS_OPTIONAL: build/make/Makefile # Standard setting: Test the current beta release of Sage: SAGE_REPO: sagemath/sage SAGE_REF: develop # Uncomment to temporarily test with the branch from a sage ticket # (this is a no-op after that ticket is merged) SAGE_TRAC_GIT: https://github.com/sagemath/sagetrac-mirror.git SAGE_TICKET: 32420 REMOVE_PATCHES: "*" jobs: dist: runs-on: ubuntu-latest steps: - name: Check out ${{ env.SPKG }} uses: actions/checkout@v2 with: path: build/pkgs/${{ env.SPKG }}/src - name: Install prerequisites run: | sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install $DIST_PREREQ - name: Run make dist, prepare upstream artifact run: | (cd build/pkgs/${{ env.SPKG }}/src && python3 setup.py sdist ) \ && mkdir -p upstream && cp build/pkgs/${{ env.SPKG }}/src/dist/*.tar.gz upstream/${{ env.SPKG }}-git.tar.gz \ && echo "sage-package create ${{ env.SPKG }} --version git --tarball ${{ env.SPKG }}-git.tar.gz --type=standard" > upstream/update-pkgs.sh \ && if [ -n "${{ env.REMOVE_PATCHES }}" ]; then echo "(cd ../build/pkgs/${{ env.SPKG }}/patches && rm -f ${{ env.REMOVE_PATCHES }}; :)" >> upstream/update-pkgs.sh; fi \ && ls -l upstream/ - uses: actions/upload-artifact@v2 with: path: upstream name: upstream docker: runs-on: ubuntu-latest needs: [dist] strategy: fail-fast: false max-parallel: 32 matrix: # debian-buster uses system python 3.7 # archlinux-latest is at the cutting edge tox_system_factor: [debian-buster, archlinux-latest] # "standard" installs lots of system packages, reducing the full build and test of the # Sage distribution to 3-4 hours tox_packages_factor: [standard] env: TOX_ENV: docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} LOGS_ARTIFACT_NAME: logs-commit-${{ github.sha }}-tox-docker-${{ matrix.tox_system_factor }}-${{ matrix.tox_packages_factor }} DOCKER_TARGETS: configured with-targets with-targets-optional steps: - name: Check out SageMath uses: actions/checkout@v2 with: repository: ${{ env.SAGE_REPO }} ref: ${{ env.SAGE_REF }} fetch-depth: 2000 if: env.SAGE_REPO != '' - name: Check out git-trac-command uses: actions/checkout@v2 with: repository: sagemath/git-trac-command path: git-trac-command if: env.SAGE_TRAC_GIT != '' - name: Check out SageMath from trac.sagemath.org shell: bash {0} run: | git config --global user.email "ci-sage@example.com" git config --global user.name "ci-sage workflow" if [ ! -d .git ]; then git init; fi; git remote add trac ${{ env.SAGE_TRAC_GIT }} && x=1 && while [ $x -le 5 ]; do x=$(( $x + 1 )); sleep $(( $RANDOM % 60 + 1 )); if git-trac-command/git-trac fetch $SAGE_TICKET; then git merge FETCH_HEAD || echo "(ignored)"; exit 0; fi; sleep 40; done; exit 1 if: env.SAGE_TRAC_GIT != '' - uses: actions/download-artifact@v2 with: path: upstream name: upstream - name: Install test prerequisites run: | sudo DEBIAN_FRONTEND=noninteractive apt-get update sudo DEBIAN_FRONTEND=noninteractive apt-get install tox python3-setuptools - name: Update Sage packages from upstream artifact run: | (export PATH=$(pwd)/build/bin:$PATH; (cd upstream && bash -x update-pkgs.sh) && sed -i.bak '/upstream/d' .dockerignore && echo "/:toolchain:/i ADD upstream upstream" | sed -i.bak -f - build/bin/write-dockerfile.sh && git diff) - name: Configure and build Sage distribution within a Docker container run: | set -o pipefail; EXTRA_DOCKER_BUILD_ARGS="--build-arg USE_MAKEFLAGS=\"-k V=0 SAGE_NUM_THREADS=3\"" tox -e $TOX_ENV -- $TARGETS 2>&1 | sed "/^configure: notice:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: warning:/s|^|::warning file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;/^configure: error:/s|^|::error file=artifacts/$LOGS_ARTIFACT_NAME/config.log::|;" - name: Copy logs from the Docker image or build container run: | mkdir -p "artifacts/$LOGS_ARTIFACT_NAME" cp -r .tox/$TOX_ENV/Dockerfile .tox/$TOX_ENV/log "artifacts/$LOGS_ARTIFACT_NAME" if [ -f .tox/$TOX_ENV/Dockertags ]; then CONTAINERS=$(docker create $(tail -1 .tox/$TOX_ENV/Dockertags) /bin/bash || true); fi if [ -n "$CONTAINERS" ]; then for CONTAINER in $CONTAINERS; do for ARTIFACT in /sage/logs; do docker cp $CONTAINER:$ARTIFACT artifacts/$LOGS_ARTIFACT_NAME && HAVE_LOG=1; done; if [ -n "$HAVE_LOG" ]; then break; fi; done; fi if: always() - uses: actions/upload-artifact@v2 with: path: artifacts name: ${{ env.LOGS_ARTIFACT_NAME }} if: always() - name: Print out logs for immediate inspection # and markup the output with GitHub Actions logging commands run: | .github/workflows/scan-logs.sh "artifacts/$LOGS_ARTIFACT_NAME" if: always() - name: Push Docker images run: | if [ -f .tox/$TOX_ENV/Dockertags ]; then TOKEN="${{ secrets.DOCKER_PKG_GITHUB_TOKEN }}" if [ -z "$TOKEN" ]; then TOKEN="${{ secrets.GITHUB_TOKEN }}" fi echo "$TOKEN" | docker login docker.pkg.github.com -u ${{ github.actor }} --password-stdin for a in $(cat .tox/$TOX_ENV/Dockertags); do FULL_TAG=docker.pkg.github.com/$(echo ${{ github.repository }}|tr 'A-Z' 'a-z')/$a docker tag $a $FULL_TAG echo Pushing $FULL_TAG docker push $FULL_TAG done || echo "(Ignoring errors)" fi if: always() sympy-sympy-1.9/.github/workflows/comment-on-pr.yml000066400000000000000000000100461412543434000225370ustar00rootroot00000000000000# ------------------------------------------------------------------ # # # # SymPy CI script to comment on a PR # # # # Runs after the main tests are complete and reports results. # # # # ------------------------------------------------------------------ # name: Report CI results to PR on: workflow_run: # test is the name given for the workflow in runtests.yml workflows: ["test"] types: [completed] jobs: comment-on-pr: runs-on: ubuntu-latest # Only run if the tests passed: if: ${{ github.event.workflow_run.conclusion == 'success' }} steps: # The previous workflow stored the issue number for the PR. We need it # here to be able to comment on the PR - name: Download benchmarks uses: dawidd6/action-download-artifact@v2 with: workflow: runtests.yml workflow_conclusion: success name: pr_number - name: Read the PR number id: pr_number_reader uses: juliangruber/read-file-action@v1.0.0 with: path: pr_number.txt # This may be running after a push with no associated PR in which case # the PR number variable is empty. All further steps will be skipped in # that case. # Retrieve benchmark results - name: Download benchmarks if: ${{ steps.pr_number_reader.outputs.content != '' }} uses: dawidd6/action-download-artifact@v2 with: workflow: runtests.yml workflow_conclusion: success name: benchmarks - name: Read benchmark output 1 if: ${{ steps.pr_number_reader.outputs.content != '' }} id: pr_vs_master_changed uses: juliangruber/read-file-action@v1.0.0 with: path: pr_vs_master_changed.txt - name: Read benchmark output 2 if: ${{ steps.pr_number_reader.outputs.content != '' }} id: master_vs_release_changed uses: juliangruber/read-file-action@v1.0.0 with: path: master_vs_release_changed.txt # The two steps below should create a new comment or update the # existing comment (edit-mode: replace). Note that the opening line of # the comment body is matched by body-includes so if that does not # match then a new comment will always be created. - name: Find Comment if: ${{ steps.pr_number_reader.outputs.content != '' }} uses: peter-evans/find-comment@v1 id: fc with: issue-number: ${{ steps.pr_number_reader.outputs.content }} comment-author: 'github-actions[bot]' body-includes: Benchmark results from GitHub Actions - name: Create or update comment if: ${{ steps.pr_number_reader.outputs.content != '' }} uses: peter-evans/create-or-update-comment@v1 with: comment-id: ${{ steps.fc.outputs.comment-id }} issue-number: ${{ steps.pr_number_reader.outputs.content }} body: | Benchmark results from GitHub Actions Lower numbers are good, higher numbers are bad. A ratio less than 1 means a speed up and greater than 1 means a slowdown. Green lines beginning with `+` are slowdowns (the PR is slower then master or master is slower than the previous release). Red lines beginning with `-` are speedups. Significantly changed benchmark results (PR vs master) ```diff ${{ steps.pr_vs_master_changed.outputs.content }} ``` Significantly changed benchmark results (master vs previous release) ```diff ${{ steps.master_vs_release_changed.outputs.content }} ``` Full benchmark results can be found as artifacts in GitHub Actions (click on checks at the top of the PR). edit-mode: replace sympy-sympy-1.9/.github/workflows/release.yml000066400000000000000000000042031412543434000214620ustar00rootroot00000000000000# ------------------------------------------------------------------ # # # # SymPy CI script for Github Actions # # # # Run on the release branch and builds the release artifacts. # # # # ------------------------------------------------------------------ # name: release on: push: branches: - 1.9 pull_request: branches: - 1.9 env: release_branch: 1.9 release_version: 1.9 previous_version: 1.8 jobs: # -------------------- Build artifacts --------------------------- # build: runs-on: ubuntu-20.04 steps: # Check out with full git history for authors check: - uses: actions/checkout@v2 with: fetch-depth: 0 - name: Setup Python uses: actions/setup-python@v2 with: python-version: 3.9 - name: Build release files run: release/ci_release_script.sh ${{ env.release_version }} ${{ env.previous_version }} - name: Store release files uses: actions/upload-artifact@v2 with: name: release_files path: release-${{ env.release_version }} # -------------------- Test installation ------------------------- # test-install: needs: [build] runs-on: ubuntu-20.04 strategy: matrix: python-version: ['3.6', '3.7', '3.8', '3.9', '3.10.0-rc.1', 'pypy-3.7'] name: Python ${{ matrix.python-version }} test install steps: - name: Setup python uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} architecture: x64 - name: Retrieve release files uses: actions/download-artifact@v2 with: name: release_files - name: List files run: ls -R - name: Install wheel run: pip install sympy-${{ env.release_version }}-py3-none-any.whl - name: Run tests after install run: python -c 'import sympy; sympy.test()' sympy-sympy-1.9/.github/workflows/runtests.yml000066400000000000000000000260461412543434000217420ustar00rootroot00000000000000# ------------------------------------------------------------------ # # # # SymPy CI script for Github Actions # # # # Runs each time a pull request is opened, pushed or merged # # # # ------------------------------------------------------------------ # name: test on: [push, pull_request] jobs: # -------------------- Code quality ------------------------------ # code-quality: runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 with: # Clone full git history (needed for AUTHORS/mailmap) fetch-depth: '0' - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath flake8 - name: Basic code quality tests run: bin/test quality - name: Run flake8 on the sympy package run: flake8 sympy - name: Detect invalid escapes like '\e' run: python -We:invalid -We::SyntaxWarning -m compileall -f -q sympy/ - name: Test all modules are listed in setup.py run: bin/test_setup.py # -- temporarily disabled -- # # These checks were too difficult for new contributors. They will # need to be made easier to work with before they are reenabled. #- name: Test for ambiguous author information in commits # run: bin/mailmap_update.py #- name: Make sure all commits have an associated author # run: bin/authors_update.py # -------------------- Doctests latest Python -------------------- # doctests-latest: needs: code-quality runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath - run: bin/doctest --force-colors - run: examples/all.py -q # -------------------- Test split 1/2 latest Python -------------- # tests1-latest: needs: code-quality runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath - run: bin/test --force-colors --split=1/2 # -------------------- Test split 2/2 latest Python -------------- # tests2-latest: needs: code-quality runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath - run: bin/test --force-colors --split=2/2 # -------------------- Optional dependency tests ----------------- # optional-dependencies: needs: code-quality runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: sudo apt install antlr4 libgfortran5 gfortran libmpfr-dev libmpc-dev - run: python -m pip install --upgrade pip - run: pip install mpmath gmpy2 matplotlib numpy scipy pymc3 aesara ipython \ symengine cython llvmlite wurlitzer \ autowrap numexpr 'antlr4-python3-runtime==4.7.*' # Test external imports - run: bin/test_external_imports.py - run: bin/test_submodule_imports.py - run: bin/test_executable.py # Test modules with specific dependencies - run: bin/test_optional_dependencies.py # -------------------- Tensorflow tests -------------------------- # tensorflow: needs: code-quality runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath numpy scipy tensorflow # Test modules that can use tensorflow - run: bin/test_tensorflow.py # -------------------- SymEngine tests --------------------------- # symengine: needs: code-quality runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath numpy symengine # Test modules that can use tensorflow - run: bin/test_symengine.py env: USE_SYMENGINE: '1' # -------------------- Slow test split 1/2 ----------------------- # slow1: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath - run: TRAVIS_BUILD_NUMBER=true bin/test --force-colors --slow --timeout=595 --split=1/2 # -------------------- Slow test split 2/2 ----------------------- # slow2: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: python -m pip install --upgrade pip - run: pip install mpmath - run: TRAVIS_BUILD_NUMBER=true bin/test --force-colors --slow --timeout=595 --split=2/2 # -------------------- Test split 1/2 older Python --------------- # tests1: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 strategy: matrix: python-version: ['3.6', '3.7', '3.8', '3.10.0-rc.1', 'pypy-3.7'] steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade pip - run: pip install mpmath - run: bin/test --force-colors --split=1/2 # -------------------- Test split 2/2 older Python --------------- # tests2: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 strategy: matrix: python-version: ['3.6', '3.7', '3.8', '3.10.0-rc.1', 'pypy-3.7'] steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade pip - run: pip install mpmath - run: bin/test --force-colors --split=2/2 # -------------------- Doctests older Python --------------------- # doctests: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 strategy: matrix: python-version: ['3.6', '3.7', '3.8', '3.10.0-rc.1', 'pypy-3.7'] steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - run: python -m pip install --upgrade pip - run: pip install mpmath - run: bin/doctest --force-colors - run: examples/all.py -q # -------------------- Build the html/latex docs ----------------- # sphinx: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: release/aptinstall.sh - run: pip install -r release/requirements.txt - run: bin/test_sphinx.sh # -------------------- Check the error message under py2 --------- # py2-import: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '2.7' - run: bin/test_py2_import.py # -------------------- Run benchmarks against master and 1.8 ----- # benchmarks: needs: [doctests-latest, tests1-latest, tests2-latest] runs-on: ubuntu-20.04 steps: - uses: actions/checkout@v2 with: # Checkout repo with full history fetch-depth: 0 - uses: actions/setup-python@v2 with: python-version: '3.9' - run: pip install asv virtualenv - run: git submodule add https://github.com/sympy/sympy_benchmarks.git # Need to make sure we can access the branches from the main repo. We # will run benchmarks for the PR, for master and for the previous # release. The version branch names below should be updated once there # has been a newer release of sympy. The list of branches to check is # also specified in asv.conf.actions.json which should be updated as # well. - run: git remote add upstream https://github.com/sympy/sympy.git - run: git fetch upstream master - run: git fetch upstream 1.8 - name: Configure benchmarks run: asv machine --yes --config asv.conf.actions.json # This is the slow part: - name: Run benchmarks run: asv run --config asv.conf.actions.json # Output benchmark results - run: asv compare upstream/master HEAD --config asv.conf.actions.json --factor 1.5 | tee pr_vs_master.txt - run: asv compare upstream/master HEAD --config asv.conf.actions.json --factor 1.5 --only-changed | tee pr_vs_master_changed.txt - run: asv compare upstream/1.8 upstream/master --config asv.conf.actions.json --factor 1.5 | tee master_vs_release.txt - run: asv compare upstream/1.8 upstream/master --config asv.conf.actions.json --factor 1.5 --only-changed | tee master_vs_release_changed.txt # This workflow does not have write permissions for the repository so # we save all outputs as artifacts that can be accessed by the # comment-on-pr workflow which is triggered by workflow_run to run when # this one completes. - name: Upload results as artifacts uses: actions/upload-artifact@v2 with: name: benchmarks path: | pr_vs_master.txt pr_vs_master_changed.txt master_vs_release.txt master_vs_release_changed.txt # -------------------- Save PR number ---------------------------- # save-pr-number: needs: [doctests-latest, tests1-latest, tests2-latest] # The comment-on-pr workflow needs the issue number of the PR to be able to # comment so we output that to a file and pass it over as an artifact. runs-on: ubuntu-20.04 steps: - name: Write PR number to file if: ${{ github.event_name == 'pull_request' }} run: echo -n ${{ github.event.number }} > pr_number.txt - name: Write empty file for PR number if: ${{ github.event_name != 'pull_request' }} run: echo -n > pr_number.txt - name: Upload results as artifacts uses: actions/upload-artifact@v2 with: name: pr_number path: pr_number.txt sympy-sympy-1.9/.gitignore000066400000000000000000000032401412543434000157120ustar00rootroot00000000000000# This file tells git what files to ignore (e.g., you won't see them as # untracked with "git status"). Add anything to it that can be cleared # without any worry (e.g., by "git clean -Xdf"), because it can be # regenerated. Lines beginning with # are comments. You can also ignore # files on a per-repository basis by modifying the core.excludesfile # configuration option (see "git help config"). If you need to make git # track a file that is ignored for some reason, you have to use # "git add -f". See "git help gitignore" for more information. # Virtualenv /.venv/ # Regular Python bytecode file *.pyc __pycache__/ # Optimized Python bytecode file *.pyo # Vim's swap files *.sw[op] # VSCode settings file .vscode/ # PyCharm settings file /.idea/ # Generated files from Jython *$py.class # Generated C files in the polys directory /sympy/polys/*.c # Generated dynamic libraries in the polys directory /sympy/polys/*.so # File generated by setup.py using MANIFEST.in MANIFEST # Generated by ctags (used to improve autocompletion in vim) tags my/ # Files generated by setup.py dist/ build/ # Files generated by setupegg.py sympy.egg-info/ # Tox files tox.ini .tox/ # Coverage files (./bin/coverage_report.py) .coverage covhtml/ # Built doc files (cd doc; make html) doc/_build/ doc/sphinx/ # pdf files generated from svg files (cd doc; make latex) doc/src/modules/physics/mechanics/*.pdf doc/src/modules/physics/vector/*.pdf # Mac OS X Junk .DS_Store # Backup files *~ # Temp output of sympy/printing/preview.py: sample.tex # IPython Notebook Checkpoints .ipynb_checkpoints/ # pytest cache folder .*cache # pytest related data file for slow tests .ci/durations.log sympy-sympy-1.9/.mailmap000066400000000000000000001052011412543434000153430ustar00rootroot00000000000000# Before editing this file, run bin/mailmap_update.py. It will # inform you about the types of entries needed here. See HELP # below for guidance if needed. # # After making entries to .mailmap, # # 1) re-run bin/mailmap_update.py; if no further edits are needed, # 2) run bin/authors_update.py to update AUTHORS and see which # authors are being added. If no error is raised, and no changes # are desired, # 3) commit the results, e.g. # # $ git commit -am 'Update .mailmap/AUTHORS. Welcome to SymPy!' # or # $ git commit -am 'Add Foo to AUTHORS. Welcome to SymPy!' # # HELP # # Entries in this file are made for two reasons: to merge git # authors that are one in the same or to simply change how the # name and/or address of an author appears. Either can be done # with an entry to this file like # # Proper Name commit name # \-----------+------------/ \----------+-------------/ # | | # replace find # # The email (or name and email) in the "find" part of the entry will # be used in a case-insensitive way to identify a git author and # replace it with whatever is included in the "replace" part: # # author author # before .mailmap entry after # --------- ---------------------- ----------- # Foo # A ---------------------> Foo # B ---------------------> Foo # # # A ---------------------> A # B ---------------------> B # # Foo # A ---------------------> Foo # B ---------------------> Foo # # Foo b # A ---------------------> same # B ---------------------> Foo # b ---------------------> Foo # # Foo b # Foo # A ---------------------> Foo # B ---------------------> Foo # b ---------------------> Foo # c ---------------------> same # # See also: 'git shortlog --help' and 'git check-mailmap --help'. # Ondřej Čertík ondrej.certik Ondřej Čertík Ondřej Čertík Ondřej Čertík Fredrik Johansson fredrik.johansson Fredrik Johansson Kirill Smelkov convert-repo Kirill Smelkov kirill.smelkov Mateusz Paprocki mattpap Jason Gedge inferno1386 Robert Schwarz lethargo Sebastian Krämer basti.kr David Roberts David Roberts (dvdr18 [at] gmail [dot] com) Pearu Peterson pearu.peterson Brian Jorgensen brian.jorgensen Chris Wu Chris.Wu Jurjen N.E. Bos Goutham Lakshminarayan Goutham Fabian Pedregosa Fabian Pedregosa Saroj Adhikari Rizgar Mella Jezreel Ng James Pearson Cristóvão Sousa Addison Cugini Addison Cugini Addison Cugini Alexey U. Gudchenko Vinzent Steinberg Vinzent Steinberg Chris Smith Chris Smith Brian E. Granger Benjamin McDonald Prafullkumar P. Tale Øyvind Jensen Jeremias Yehdegho Oleksandr Gituliar Renato Coutinho Thomas Wiecki Thomas Wiecki Nicolas Pourcelot Min Ragan-Kelley Bradley Froehle Matthew Rocklin Bilal Akhtar David Li unknown David Li David Ju David Ju David Marek Gilbert Gede Gilbert Gede Ronan Lamy Toon Verstraelen Toon Verstraelen Andrej Tokarčík Tomáš Bambas Roberto Colistete, Jr. Robert Cimrman Raymond Wong Raymond Wong Raymond Wong Luke Peterson Davy Mao Nathan Alison Raoul Bourquin Raoul Bourquin Sachin Irukula Siddhanathan Shanmugam Siddhanathan Shanmugam Jim Zhang Angus Griffith <16sn6uv@gmail.com> Timothy Reluga me Timothy Reluga Saurabh Jha Arpit Goyal Tom Bachmann Rom le Clair Manoj Babu K. Ljubiša Moćić <3rdslasher@gmail.com> Oscar Benjamin Oscar Benjamin Jens H. Nielsen Niklas Thörne Marek Šuppa Prasoon Shukla Sachin Joglekar Sachin Joglekar Stefen Yin Manoj Kumar Benjamin Fishbein Chetna Gupta Rishabh Dixit Mary Clark Mary Clark Akshit Agarwal Colleen Lee Amit Jamadagni Seshagiri Prabhu Shravas K Rao Ananya H Nichita Utiu Matthew Hoff Tarang Patel Thilina Rathnayake Pradyumna Francesco Bonazzi Francesco Bonazzi Dmitry Batkovich Yuriy Demidov Amit Saha Heiner Kirchhoffer David Joyner David Joyner Jason Moore Alkiviadis G. Akritas Pablo Puente Paul Strickland Shipra Banga rathmann Akshay Akshay Rajath Shashidhara Buck Shlegeris Buck Shlegeris Jonathan Miller Sambuddha Basu Aditya Shah Rajat Aggarwal Patrick Poitras Thomas Hisch Thomas Hisch Sushant Hiray Anurag Sharma Jim Crist Zeel Shah Dammina Sahabandu Sahil Shekhawat Kundan Kumar Maciej Baranski Zamrath Nizam Dhruvesh Vijay Parikh Fawaz Alazemi Venkatesh Halli Kaushik Varanasi Leonid Blouvshtein Duane Nykamp Mihai A. Ionescu Sarwar Chahal Hamish Dickson Peter Brady Peter Brady Peter Brady Peter Brady Peter Brady peter Craig A. Stoudt Raj John V. Siratt Ted Dokos Akshat Jain Cody Herbst Nishith Shah Tuan Manh Lai Darshan Chaudhary Jayesh Lahori Lokesh Sharma Aaditya Nair Shivam Vats Shivam Vats Ramana Venkata Ramana Venkata Peleg Michaeli Kyle McDaniel Kalevi Suominen Dustin Gadal Colin B. Macdonald Colin B. Macdonald Chai Wah Wu Adam Bloomston Alex Lindsay Devyani Kota Alec Kalinin Konstantin Togoi Longqi Wang Jennifer White Jack Kemp Jack Kemp Guillaume Gay Gregory Ashton Prashant Tyagi Philippe Bouafia Juha Remes Matthew Davis Vinay Singh Sampad Kumar Saha Jiaxing Liang Jiaxing Liang Jens Jørgen Mortensen Björn Dahlgren Shekhar Prasad Rajak shekharrajak Shekhar Prasad Rajak Arafat Dad Khan Arafat Dad Khan Aqnouch Mohammed Meghana Madhyastha Tanu Hari Dixit Guo Xingjian Shubham Tibra Bhautik Mavani Pablo Zubieta Asish Panda Edward Schembor Harshil Goel Harshil Goel Lukas Zorich Shashank Agarwal Chaitanya Sai Alaparthi Abhinav Agarwal Rishabh Daal Aravind Reddy Akshay Siramdas Nitin Chaudhary Alex Argunov Abhishek Garg Gaurav Dhingra Gaurav Dhingra Gaurav Dhingra Krit Karan Arihant Parsoya Harsh Gupta Kshitij Saraogi Langston Barrett Devang Kulshreshtha Mohammad Sadeq Dousti Rohit Rango Sergey Pestov Varun Garg Rajat Thakur Rajat Thakur Rajat Thakur Tanay Agrawal Mohit Chandra Amit Kumar Amit Kumar Amit Kumar Ruslan Pisarev Isuru Fernando Arif Ahmed Valeriia Gladkova Szymon Mieszczak Ranjith Kumar Rishabh Madan Nicolás Guarín-Zapata Markus Müller Marcel Stimberg Jainul Vaghasia Pranjal Tale Jason Tokayer Jason Tokayer Theodore Han Theodore Han Mauro Garavello Shikhar Jaiswal Thomas Hunt tborisova Dhia Kennouche Dhia Kennouche Elliot Marshall Manish Shukla Manish Shukla Ray Cathcart Sumith Kulal Richard Otis Richard Otis João Moura Shivam Agarwal Christina Zografou Fiach Antaw Nick Curtis Steph Papanik Zulfikar Blair Azzopardi Anjul Kumar Tyagi Karthik Chintapalli Shikhar Makhija Yathartha Joshi Harsh Jain James Taylor Micah Fitch ylemkimon Peter Enenkel Jithin D. George Lev Chelyadinov Sourav Ghosh Ethan Ward etkewa@gmail.com Ethan Ward Ethan Ward <14932247+ethankward@users.noreply.github.com> Ethan Ward eward Ethan Ward Ethan Ward Nilabja Bhattacharya Akash Kundu Shubham Maheshwari Pavel Tkachenko Ashish Kumar Gaurav Himanshu Rob Drynkin Unknown Sayan Goswami Subhash Saurabh Vishal Jeremey Gluck Akshat Maheshwari Poom Chiarawongse Poom Chiarawongse <15707729+Eight1911@users.noreply.github.com> Leonid Kovalev Leonid Kovalev Jashanpreet Singh Cristian Di Pietrantonio P. Sai Prasanth Cédric Travelletti Cedric Ravi charan Nityananda Gohain Nicholas Bollweg Johan Blåbäck Adwait Baokar abaokar-07 Rahil Hastu rahil hastu Sidhant Nagpal sidhantnagpal Sidhant Nagpal “sidhantnagpal” Sidhant Nagpal Sidhant Nagpal <36465988+sidhantnagpal@users.noreply.github.com> Nikoleta Glynatsi Nikoleta Glynatsi Samyak Jain Samyak Jain Avi Shrivastava avi Gagandeep Singh czgdp1807 Gagandeep Singh czgdp1807 <36567889+czgdp1807@users.noreply.github.com> Gagandeep Singh czgdp1807 Gagandeep Singh MathLover <36567889+czgdp1807@users.noreply.github.com> Gagandeep Singh czgdp1807 Gagandeep Singh Gagandeep Singh <36567889+czgdp1807@users.noreply.github.com> Gagandeep Singh Gagandeep Singh Gagandeep Singh Gagandeep Singh Gagandeep Singh Gagandeep Singh S.Y. Lee sylee957 Yatna Verma yatna Jared Lumpe Michael Jared Lumpe Austin Palmer austin Marduk Bolaños mardukbp amsuhane amsuhane <“ayushsuhane99@iitkgp.ac.in”> Ritu Raj Singh Ritu Raj Singh <37741324+RituRajSingh878@users.noreply.github.com> Ritu Raj Singh RituRajSingh878 Ritu Raj Singh Ritu Raj Singh Ritu Raj Singh rationa-kunal kunal rationa-kunal kunal shiksha11 shiksha11 <33157995+shiksha11@users.noreply.github.com> Jogi Miglani jmig5776 Supreet Agrawal stm Bavish Kulur bavish2201 Divyanshu Thakur Divyanshu Shubham Kumar Jha ShubhamKJha Frédéric Chapoton fchapoton Salmista-94 alejandrogroso@hotmail.com Denis Ivanenko Jack Denis Ivanenko LilJohny Nabanita Dash Nabanita Dash <31562743+Naba7@users.noreply.github.com> Nabanita Dash Naba7 Rajiv Ranjan Singh Rajiv Ranjan Singh <42106787+iamrajiv@users.noreply.github.com> kangzhiq <709563092@qq.com> kangzhia <709563092@qq.com> kangzhiq <709563092@qq.com> kangzhiq <709563092@qq.com> kangzhiq <709563092@qq.com> kkkkx <709563092@qq.com> kangzhiq <709563092@qq.com> <32410422+kangzhiq@users.noreply.github.com> Yeshwanth N Steven Lee <41497963+stevenleeS0ht@users.noreply.github.com> Sachin Agarwal sachin-4099 Sachin Agarwal Nikhil Maan Nikhil Maan Parker Berry Parker Berry Hou-Rui Hou-Rui <13244639785@163.com> Arun Singh Arun Singh Ankit Raj Pandey Ankit Pandey Oscar Gerardo Lazo Arjona oscarlazoarjona Zhi-Qiang Zhou zhouzq-thu Srinivasa Arun Yeragudipati Arun Yeragudipati Srinivasa Arun Yeragudipati Srinivasa Arun Yeragudipati <38272686+arun-y99@users.noreply.github.com> Srinivasa Arun Yeragudipati arun-y99 Srinivasa Arun Yeragudipati arun Ivan Tkachenko ratijas Ivan Tkachenko ivan tkachenko luzpaz luz.paz Charalampos Tsiagkalis ctsiagkalis <49073139+ctsiagkalis@users.noreply.github.com> Soniya Nayak Soniyanayak51 <39791511+Soniyanayak51@users.noreply.github.com> Ritesh Kumar riteshkumar Petr Kungurtsev Corwinpro Akash Nagaraj grassknoted Jun Lin wate123 Louis Abraham louisabraham Louis Abraham Bharat Raghunathan Bharat123rox Samesh Lakhotia Samesh Lakhotia Samesh Samesh Lakhotia <43701530+sameshl@users.noreply.github.com> Yogesh Mishra yogesh1997 Erik R. Gomez erik Qingsha Shi sqs Kirtan Mali KIRTAN MALI <43683545+kmm555@users.noreply.github.com> Kirtan Mali kmm555 Vasileios Kalos Basileios Kalos Vasileios Kalos Vasilis Jean-Luc Herren jlherren Moses Paul R Moses PaulR Vikrant Malik Vikrant Vikrant Malik Vikrant Saanidhya vats Saanidhya <50399005+Saanidhyavats@users.noreply.github.com> Saanidhya vats Saanidhya Smit Lunagariya Smit Lunagariya <55887635+Smit-create@users.noreply.github.com> Smit Lunagariya Smit-create <55887635+Smit-create@users.noreply.github.com> Smit Lunagariya Smit-create Vatsal Srivastava sava-1729 Omar Wagih OmarWagih1 Arpan Chattopadhyay Arpan612 Dhruv Mendiratta dhruvmendiratta6 Dhruv Mendiratta Dhruv Mendiratta <42745880+dhruvmendiratta6@users.noreply.github.com> Hugo van Kemenade Hugo Michal Grňo Michal Grno Mohit Balwani Mohit Balwani <44258119+Mohitbalwani26@users.noreply.github.com> Mohit Balwani Mohitbalwani26 <44258119+Mohitbalwani26@users.noreply.github.com> Mohit Balwani Mohitbalwani26 Mathias Louboutin Psycho-Pirate Psycho-Pirate Psycho-Pirate Psycho-Pirate <50932406+Psycho-Pirate@users.noreply.github.com> Psycho-Pirate Prakhar Saxena Aaryan Dewan Aaryan Dewan <49852384+aaryandewan@users.noreply.github.com> Akhil Rajput Akhil Rajput <43316490+akhil-dh1@users.noreply.github.com> Naman Gera Naman Gera <43007653+namannimmo10@users.noreply.github.com> Naman Gera Namannimmo mohit <39158356+mohitacecode@users.noreply.github.com> mohit <42018918+mohitshah3111999@users.noreply.github.com> Marijan Smetko InCogNiTo124 Lagaras Stelios lagamura Milan Jolly mijo2 Hannah Kari hannah-kari <42753364+hannah-kari@users.noreply.github.com> Akash Nagaraj (akasnaga) Akash Nagaraj Riyan Dhiman Riyan <43529842+Ryand1234@users.noreply.github.com> Ayush Malik Ayush-Malik Ben Payne Ben Garrett Folbe gfolbe318 Ilya Pchelintsev ILLIA PCHALINTSAU Chris du Plessis Maelstrom6 Chris du Plessis Chris du Plessis <45897212+Maelstrom6@users.noreply.github.com> Wolfgang Stöcher coproc Sudeep Sidhu sidhu1012 Devesh Sawant dsaw Devesh Sawant dsaw Coder-RG Rishabh Goel Lorenzo Contento lcontento Lorenzo Contento Lorenzo Contento Naveen Sai naveensaigit Naveen Sai Naveen Sai <56525288+naveensaigit@users.noreply.github.com> Kartik Sethi Kartik Sethi <37146279+ks147@users.noreply.github.com> Sidharth Mundhra Sidharth Mundhra <56464077+0sidharth@users.noreply.github.com> Michael Greminger mgreminger Sayandip Halder Sayandip Kaustubh Chaudhari Kaustubh Kaustubh Chaudhari kc611 Kunal Singh kunal singh Ayush Bisht Ayush Ayush Bisht ayushbisht2001 <61404154+ayushbisht2001@users.noreply.github.com> Nikhil Gopalam gopalamn Mayank Raj mayank raj Mayank Raj mayank <54908605+mayankray2020@users.noreply.github.com> Jisoo Song JSS95 <52185322+JSS95@users.noreply.github.com> Jisoo Song mcpl-sympy <59268464+mcpl-sympy@users.noreply.github.com> Aditya Kumar Sinha aditya113141 Kristian Brünn Kristianmitk Mario Maio nopria Eva Tiwari Eva Qijia Liu eagleoflqj Fabian Froehlich FFroehlich Praveen Sahu povinsahu1909 Jose M. Gomez jmgc Akshansh Bhatt akshanshbhatt <53227127+akshanshbhatt@users.noreply.github.com> Akshansh Bhatt Akshansh <53227127+akshanshbhatt@users.noreply.github.com> Suryam Arnav Kalra suryam35 Yukai Chou muzimuzhi Priyansh Rathi techiepriyansh Prince Gupta LAPTOP-AS1M2R8B\codem Muhammed Abdul Quadir Owais MaqOwais Vaibhav Bhat VBhat97 Bhaskar Joshi BhaskarJoshi-01 Miguel Torres Costa Elisha Hollander donno2048 Mamidi Ratna Praneeth praneeth Zach Carmichael <20629897+craymichael@users.noreply.github.com> Zach <20629897+craymichael@users.noreply.github.com> Anup Parikh Anup Parikh <84572003+parikhanupk@users.noreply.github.com> Harshit Yadav Harshit Yadav <45384915+hyadav2k@users.noreply.github.com> Megan Ly Megan Ly Robert Pollak Robert Pollak Gautam Menghani gum3ng Gautam Menghani gum3ng <78410304+gum3ng@users.noreply.github.com> Gautam Menghani gautammenghani Aman Sharma mostlyaman Aman Sharma mostlyaman <85072876+mostlyaman@users.noreply.github.com> Robin Richard robinechuca Robin Richard robinechuca <61911191+robinechuca@users.noreply.github.com> Robin Richard Nornort Ayush Kumar Ayush Kumar <65803868+ayushk7102@users.noreply.github.com> Huangduirong Huangxiaodui Jonathan Gutow gutow Ben Oostendorp oostben Evani Balasubramanyam evani balasubramanyam Sebastian East sebastian-east Shashank KS Shashank KS Davide Sandonà Davide_sd Vijairam Ganesh Moorthy vijair Vijairam Ganesh Moorthy vijairam20 Lucy Mountain LucyMountain Aditya Ravuri InfProbSciX Rahil Parikh rprkh Yaser AlOsh Yaser Joannah Nanjekye nanjekyejoannah Matthias Köppe Matthias Koeppe Kshitij Kshitij Parwani <44468674+P-Kshitij@users.noreply.github.com> Daniel Hyams dhyams sympy-sympy-1.9/.travis.yml000066400000000000000000000141041412543434000160340ustar00rootroot00000000000000language: python os: - linux jobs: fast_finish: true include: - python: 3.8 dist: xenial script: bin/test quality env: - TEST_QUALITY="true" - python: 3.8 dist: xenial env: - TEST_FLAKE8="true" - python: 3.8 dist: xenial env: - TEST_DOCTESTS="true" TEST_SETUP="true" TEST_EXAMPLES="true" - python: 3.8 dist: xenial env: - TEST_SYMPY="true" SPLIT="1/2" - python: 3.8 dist: xenial env: - TEST_SYMPY="true" SPLIT="2/2" - python: 3.7 dist: xenial # At the time of writing this is Python 3.7 but it will become 3.8 when # all of the dependencies are supported on 3.8. env: - TEST_ASCII="true" - TEST_OPT_DEPENDENCY="matchpy numpy scipy gmpy2 matplotlib aesara llvmlite autowrap cython wurlitzer python-symengine tensorflow numexpr ipython antlr-python-runtime>=4.7,<4.8 antlr>=4.7,<4.8 cloudpickle pyglet pycosat lfortran python-clang lxml" - TEST_SAGE="true" - SYMPY_STRICT_COMPILER_CHECKS=1 addons: apt: packages: # for aesara - libatlas-dev - libatlas-base-dev - liblapack-dev - gfortran - python-scipy # Tensorflow 1 support - python: 3.6 env: - TEST_OPT_DEPENDENCY="tensorflow<2 python=3" - TEST_TENSORFLOW_1=true - python: 3.8 dist: xenial env: - TEST_SPHINX="true" - secure: "YIEZal9EBTL+fg2YmoZoS8Bvt3eAVUOZjb38CtqpzR2CCSXWoUk35KG23m2NknlY1iKfYJyt7XWBszT/VKOQEbWQq7PIakV4vIByrWacgBxy1x3WC+rZoW7TX+JJiL+y942qIYbMoNMMB8xFpE5RDLSjSecMpFhJJXoafVTvju8=" addons: apt: packages: - graphviz - inkscape - texlive - texlive-xetex - texlive-fonts-recommended - texlive-latex-extra - latexmk - lmodern - librsvg2-bin - imagemagick - docbook2x - python: 3.8 dist: xenial env: - TEST_SLOW="true" - SPLIT="1/2" - python: 3.8 dist: xenial env: - TEST_SLOW="true" - SPLIT="2/2" - python: 2.7 dist: xenial env: - TEST_PY2_IMPORT="true" before_install: - set -e - python -c "import fcntl; fcntl.fcntl(1, fcntl.F_SETFL, 0)" - if [[ "${TEST_COVERAGE}" == "true" ]]; then pip install coverage; coverage debug sys; fi - if [[ "${TEST_FLAKE8}" == "true" ]]; then pip install flake8; fi - if [ "$TRAVIS_PYTHON_VERSION" == "3.8" ]; then pip uninstall -y Cython; fi - | if [[ -n "${TEST_OPT_DEPENDENCY}" ]]; then # We do this conditionally because it saves us some downloading if the # version is the same. deactivate; # Deactivate the Travis virtualenv wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -q -O miniconda.sh; bash miniconda.sh -b -p $HOME/miniconda; export PATH="$HOME/miniconda/bin:$PATH"; hash -r; conda config --set always_yes yes --set changeps1 no; conda update -q conda; conda config --prepend channels conda-forge --prepend channels symengine/label/dev; conda info -a; # This became very slow: https://github.com/sympy/sympy/issues/20289 # We give it a 30 minute wait for now but hopefully this command will # stop being so slow. conda install mamba travis_wait 30 mamba create -q -n test-environment ${TEST_OPT_DEPENDENCY}; source activate test-environment; export CPATH=$CONDA_PREFIX/include; export LIBRARY_PATH=$CONDA_PREFIX/lib; export LD_LIBRARY_PATH=$CONDA_PREFIX/lib; conda clean --all; if [[ "$TEST_SAGE" == "true" ]]; then # Use a separate environment because sage downgrades matplotlib conda create -c conda-forge/label/cf201901 -n sage sagelib mpmath "ipython>=5.5.0,<6"; conda clean --all; fi elif [ "$TRAVIS_PYTHON_VERSION" != "pypy" ]; then if pip list | grep "numpy"; then pip uninstall -y numpy; fi fi - if [[ "${TEST_SPHINX}" == "true" ]]; then pip install sphinx "docutils" doctr matplotlib sphinx-math-dollar sphinx-reredirects; fi install: # If a command fails, fail the build. - set -e - if [ "$TRAVIS_PYTHON_VERSION" = "pypy" ]; then virtualenv -p /usr/bin/pypy3 ~/.venv; . ~/.venv/bin/activate; fi # -We:invalid makes invalid escape sequences error in Python 3.6. See # -#12028. # SyntaxWarning flag for catching errors in Python3.8 # Issue - #16973. -We:invalid can be dropped from 3.8 onwards, but # it needs to be there for earlier versions. # # This would fail due to invalid Python 2.7 syntax so we disable it while # testing import under Python 2. - | if [[ -z "${TEST_PY2_IMPORT}" ]]; then if [[ "${TEST_SETUP}" == "true" ]]; then # The install cycle below is to test installation on systems without # setuptools. pip install virtualenv virtualenv ~/.venv-no-setuptools; ~/.venv-no-setuptools/bin/pip install mpmath; ~/.venv-no-setuptools/bin/pip uninstall -y setuptools; ~/.venv-no-setuptools/bin/python -We:invalid setup.py -q install; fi python -We:invalid -We::SyntaxWarning -m compileall -f -q sympy/; python -We:invalid setup.py -q install; pip list --format=columns; fi script: # Don't run doctr if the build fails - set -e - bin/test_travis.sh - if [[ "${TEST_SPHINX}" == "true" ]]; then doctr deploy dev --deploy-repo sympy/sympy_doc --command './generate_indexes.py'; fi - if [[ "${TEST_COVERAGE}" == "true" ]]; then bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports"; fi - if [[ "${BENCHMARK}" == "true" ]]; then asv machine --yes --config asv.conf.travis.json; asv run --config asv.conf.travis.json; asv compare master HEAD --config asv.conf.travis.json --factor 1.5; fi notifications: email: false sympy-sympy-1.9/AUTHORS000066400000000000000000001260001412543434000147720ustar00rootroot00000000000000All people who contributed to SymPy by sending at least a patch or more (in the order of the date of their first contribution), except those who explicitly didn't want to be mentioned. People with a * next to their names are not found in the metadata of the git history. This file is generated automatically by running `./bin/authors_update.py`. There are a total of 1094 authors. Ondřej Čertík Fabian Pedregosa Jurjen N.E. Bos Mateusz Paprocki *Marc-Etienne M.Leveille Brian Jorgensen Jason Gedge Robert Schwarz Pearu Peterson Fredrik Johansson Chris Wu *Ulrich Hecht Goutham Lakshminarayan David Lawrence Jaroslaw Tworek David Marek Bernhard R. Link Andrej Tokarčík Or Dvory Saroj Adhikari Pauli Virtanen Robert Kern James Aspnes Nimish Telang Abderrahim Kitouni Pan Peng Friedrich Hagedorn Elrond der Elbenfuerst Rizgar Mella Felix Kaiser Roberto Nobrega David Roberts Sebastian Krämer Vinzent Steinberg Riccardo Gori Case Van Horsen Stepan Roucka Ali Raza Syed Stefano Maggiolo Robert Cimrman Bastian Weber Sebastian Krause Sebastian Kreft *Dan Alan Bromborsky Boris Timokhin Robert Andy R. Terrel Hubert Tsang Konrad Meyer Henrik Johansson Priit Laes Freddie Witherden Brian E. Granger Andrew Straw Kaifeng Zhu Ted Horst Andrew Docherty Akshay Srinivasan Aaron Meurer Barry Wardell Tomasz Buchert Vinay Kumar Johann Cohen-Tanugi Jochen Voss Luke Peterson Chris Smith Thomas Sidoti Florian Mickler Nicolas Pourcelot Ben Goodrich Toon Verstraelen Ronan Lamy James Abbatiello Ryan Krauss Bill Flynn Kevin Goodsell Jorn Baayen Eh Tan Renato Coutinho Oscar Benjamin Øyvind Jensen Julio Idichekop Filho Łukasz Pankowski *Chu-Ching Huang Fernando Perez Raffaele De Feo Christian Muise Matt Curry Kazuo Thow Christian Schubert Jezreel Ng James Pearson Matthew Brett Addison Cugini Nicholas J.S. Kinar Harold Erbin Thomas Dixon Cristóvão Sousa Andre de Fortier Smit Mark Dewing Alexey U. Gudchenko Gary Kerr Sherjil Ozair Oleksandr Gituliar Sean Vig Prafullkumar P. Tale Vladimir Perić Tom Bachmann Yuri Karadzhov Vladimir Lagunov Matthew Rocklin Saptarshi Mandal Gilbert Gede Anatolii Koval Tomo Lazovich Pavel Fedotov Jack McCaffery Jeremias Yehdegho Kibeom Kim Gregory Ksionda Tomáš Bambas Raymond Wong Luca Weihs Shai 'Deshe' Wyborski Thomas Wiecki Óscar Nájera Mario Pernici Benjamin McDonald Sam Magura Stefan Krastanov Bradley Froehle Min Ragan-Kelley Emma Hogan Nikhil Sarda Julien Rioux Roberto Colistete, Jr. Raoul Bourquin Gert-Ludwig Ingold Srinivas Vasudevan Jason Moore Miha Marolt Tim Lahey Luis Garcia Matt Rajca David Li Alexandr Gudulin Bilal Akhtar Grzegorz Świrski Matt Habel David Ju Nichita Utiu Nikolay Lazarov Steve Anton Imran Ahmed Manzoor Ljubiša Moćić <3rdslasher@gmail.com> Piotr Korgul Jim Zhang Sam Sleight tborisova Chancellor Arkantos Stepan Simsa Tobias Lenz Siddhanathan Shanmugam Tiffany Zhu Tristan Hume Alexey Subach Joan Creus Geoffry Song Puneeth Chaganti Marcin Kostrzewa <> Natalia Nawara vishal Shruti Mangipudi Davy Mao Swapnil Agarwal Dhia Kennouche jerryma1121 Joachim Durchholz Martin Povišer Siddhant Jain Kevin Hunter Michael Mayorov Nathan Alison Christian Bühler Carsten Knoll Bharath M R Matthias Toews Sergiu Ivanov Jorge E. Cardona Sanket Agarwal Manoj Babu K. Sai Nikhil Aleksandar Makelov Sachin Irukula Raphael Michel Ashwini Oruganti Andreas Kloeckner Prateek Papriwal Arpit Goyal Angadh Nanjangud Comer Duncan Jens H. Nielsen Joseph Dougherty Elliot Marshall Guru Devanla George Waksman Alexandr Popov Tarun Gaba Takafumi Arakaki Saurabh Jha Rom le Clair Angus Griffith <16sn6uv@gmail.com> Timothy Reluga Brian Stephanik Alexander Eberspächer Sachin Joglekar Tyler Pirtle Vasily Povalyaev Colleen Lee Matthew Hoff Niklas Thörne Huijun Mai Marek Šuppa Ramana Venkata Prasoon Shukla Stefen Yin Thomas Hisch Madeleine Ball Mary Clark Rishabh Dixit Manoj Kumar Akshit Agarwal CJ Carey Patrick Lacasse Ananya H Tarang Patel Christopher Dembia Benjamin Fishbein Sean Ge Amit Jamadagni Ankit Agrawal Björn Dahlgren Christophe Saint-Jean Demian Wassermann Khagesh Patel Stephen Loo hm Patrick Poitras Katja Sophie Hotz Varun Joshi Chetna Gupta Thilina Rathnayake Max Hutchinson Shravas K Rao Matthew Tadd Alexander Hirzel Randy Heydon Oliver Lee Seshagiri Prabhu Pradyumna Erik Welch Eric Nelson Roland Puntaier Chris Conley Tim Swast Dmitry Batkovich Francesco Bonazzi Yuriy Demidov Rick Muller Manish Gill Markus Müller Amit Saha Jeremy QuaBoo Stefan van der Walt David Joyner Lars Buitinck Alkiviadis G. Akritas Vinit Ravishankar Mike Boyle Heiner Kirchhoffer Pablo Puente James Fiedler Harsh Gupta Tuomas Airaksinen Paul Strickland James Goppert rathmann Avichal Dayal Paul Scott Shipra Banga Pramod Ch Akshay Buck Shlegeris Jonathan Miller Edward Schembor Rajath Shashidhara Zamrath Nizam Aditya Shah Rajat Aggarwal Sambuddha Basu Zeel Shah Abhinav Chanda Jim Crist Sudhanshu Mishra Anurag Sharma Soumya Dipta Biswas Sushant Hiray Ben Lucato Kunal Arora Henry Gebhardt Dammina Sahabandu Manish Shukla Ralph Bean richierichrawr John Connor Juan Luis Cano Rodríguez Sahil Shekhawat Kundan Kumar Stas Kelvich sevaader Dhruvesh Vijay Parikh Venkatesh Halli Lennart Fricke Vlad Seghete Shashank Agarwal carstimon Pierre Haessig Maciej Baranski Benjamin Gudehus Faisal Anees Mark Shoulson Robert Johansson Kalevi Suominen Kaushik Varanasi Fawaz Alazemi Ambar Mehrotra David P. Sanders Peter Brady John V. Siratt Sarwar Chahal Nathan Woods Colin B. Macdonald Marcus Näslund Clemens Novak Mridul Seth Craig A. Stoudt Raj Mihai A. Ionescu immerrr Chai Wah Wu Leonid Blouvshtein Peleg Michaeli ck Lux zsc347 Hamish Dickson Michael Gallaspy Roman Inflianskas Duane Nykamp Ted Dokos Sunny Aggarwal Victor Brebenar Akshat Jain Shivam Vats Longqi Wang Juan Felipe Osorio Ray Cathcart Lukas Zorich Eric Miller Cody Herbst Nishith Shah Amit Kumar Yury G. Kudryashov Guillaume Gay Mihir Wadwekar Tuan Manh Lai Asish Panda Darshan Chaudhary Alec Kalinin Ralf Stephan Aaditya Nair Jayesh Lahori Harshil Goel Luv Agarwal Jason Ly Lokesh Sharma Sartaj Singh Chris Swierczewski Konstantin Togoi Param Singh Sumith Kulal Juha Remes Philippe Bouafia Peter Schmidt Jiaxing Liang Lucas Jones Gregory Ashton Jennifer White Renato Orsino Michael Boyle Alistair Lynn Govind Sahai Adam Bloomston Kyle McDaniel Nguyen Truong Duy Alex Lindsay Mathew Chong Jason Siefken Gaurav Dhingra Gao, Xiang Kevin Ventullo mao8 Isuru Fernando Shivam Tyagi Richard Otis Rich LaSota dustyrockpyle Anton Akhmerov Michael Zingale Chak-Pong Chung David T Phil Ruffwind Sebastian Koslowski Kumar Krishna Agrawal Dustin Gadal João Moura Yu Kobayashi Shashank Kumar Timothy Cyrus Devyani Kota Keval Shah Dzhelil Rufat Pastafarianist Sourav Singh Jacob Garber Vinay Singh GolimarOurHero Prashant Tyagi Matthew Davis Tschijnmo TSCHAU Alexander Bentkamp Jack Kemp Kshitij Saraogi Thomas Baruchel Nicolás Guarín-Zapata Jens Jørgen Mortensen Sampad Kumar Saha Eva Charlotte Mayer Laura Domine Justin Blythe Meghana Madhyastha Tanu Hari Dixit Shekhar Prasad Rajak Aqnouch Mohammed Arafat Dad Khan Boris Atamanovskiy Sam Tygier Jai Luthra Guo Xingjian Sandeep Veethu Archit Verma Shubham Tibra Ashutosh Saboo Michael S. Hansen Anish Shah Guillaume Jacquenot Bhautik Mavani Michał Radwański Jerry Li Pablo Zubieta Shivam Agarwal Chaitanya Sai Alaparthi Arihant Parsoya Ruslan Pisarev Akash Trehan Nishant Nikhil Vladimir Poluhsin Akshay Nagar James Brandon Milam Abhinav Agarwal Rishabh Daal Sanya Khurana Aman Deep Aravind Reddy Abhishek Verma Matthew Parnell Thomas Hickman Akshay Siramdas YiDing Jiang Jatin Yadav Matthew Thomas Rehas Sachdeva Michael Mueller Srajan Garg Prabhjot Singh Haruki Moriguchi Tom Gijselinck Nitin Chaudhary Alex Argunov Nathan Musoke Abhishek Garg Dana Jacobsen Vasiliy Dommes Phillip Berndt Haimo Zhang Anthony Scopatz bluebrook Leonid Kovalev Josh Burkart Dimitra Konomi Christina Zografou Fiach Antaw Langston Barrett Krit Karan G. D. McBain Prempal Singh Gabriel Orisaka Matthias Bussonnier rahuldan Colin Marquardt Andrew Taber Yash Reddy Peter Stangl elvis-sik Nikos Karagiannakis Jainul Vaghasia Dennis Meckel Harshil Meena Micky Nick Curtis Michele Zaffalon Martha Giannoudovardi Devang Kulshreshtha Steph Papanik Mohammad Sadeq Dousti Arif Ahmed Abdullah Javed Nesar Lakshya Agrawal shruti Rohit Rango Hong Xu Ivan Petuhov Alsheh Marcel Stimberg Alexey Pakhocmhik Tommy Olofsson Zulfikar Blair Azzopardi Danny Hermes Sergey Pestov Mohit Chandra Karthik Chintapalli Marcin Briański andreo Flamy Owl Yicong Guo Varun Garg Rishabh Madan Aditya Kapoor Karan Sharma Vedant Rathore Johan Blåbäck Pranjal Tale Jason Tokayer Raghav Jajodia Rajat Thakur Dhruv Bhanushali Anjul Kumar Tyagi Barun Parruck Bao Chau Tanay Agrawal Ranjith Kumar Shikhar Makhija Yathartha Joshi Valeriia Gladkova Sagar Bharadwaj Daniel Mahler Ka Yi Rishat Iskhakov Szymon Mieszczak Sachin Agarwal Priyank Patel Satya Prakash Dwibedi tools4origins Nico Schlömer Fermi Paradox Ekansh Purohit Vedarth Sharma Peeyush Kushwaha Jayjayyy Christopher J. Wright Jakub Wilk Mauro Garavello Chris Tefer Shikhar Jaiswal Chiu-Hsiang Hsu Carlos Cordoba Fabian Ball Yerniyaz Christiano Anderson Robin Neatherway Thomas Hunt Theodore Han Duc-Minh Phan Lejla Metohajrova Samyak Jain Aditya Rohan Vincent Delecroix Michael Sparapany Harsh Jain Nathan Goldbaum latot Kenneth Lyons Stan Schymanski David Daly Ayush Shridhar Javed Nissar Jiri Kuncar vedantc98 Rupesh Harode Rob Zinkov James Harrop James Taylor Ishan Joshi Marco Mancini Boris Ettinger Micah Fitch Daniel Wennberg ylemkimon Akash Vaish Peter Enenkel Waldir Pimenta Jithin D. George Lev Chelyadinov Lucas Wiman Rhea Parekh James Cotton Robert Pollak anca-mc Sourav Ghosh Jonathan Allan Nikhil Pappu Ethan Ward Cezary Marczak dps7ud Nilabja Bhattacharya Itay4 <31018228+Itay4@users.noreply.github.com> Poom Chiarawongse Yang Yang Cavendish McKay Bradley Gannon B McG Rob Drynkin Seth Ebner Akash Kundu Mark Jeromin Roberto Díaz Pérez Gleb Siroki Segev Finer Alex Lubbock Ayodeji Ige Matthew Wardrop Hugo van Kemenade Austin Palmer der-blaue-elefant Filip Gokstorp Yuki Matsuda Aaron Miller Salil Vishnu Kapur Atharva Khare Shubham Maheshwari Pavel Tkachenko Ashish Kumar Gaurav Rajeev Singh Keno Goertz Lucas Gallindo Himanshu David Menéndez Hurtado Amit Manchanda Rohit Jain Jonathan A. Gross Unknown Sayan Goswami Subhash Saurabh Rastislav Rabatin Vishal Jeremey Gluck Akshat Maheshwari symbolique Saloni Jain Arighna Chakrabarty Abhigyan Khaund Jashanpreet Singh Saurabh Agarwal luzpaz P. Sai Prasanth Nirmal Sarswat Cristian Di Pietrantonio Ravi charan Nityananda Gohain Cédric Travelletti Nicholas Bollweg Himanshu Ladia Adwait Baokar Mihail Tarigradschi Saketh rushyam sfoo Rahil Hastu Zach Raines Sidhant Nagpal Gagandeep Singh Rishav Chakraborty Malkhan Singh Joaquim Monserrat Mayank Singh Rémy Léone Maxence Mayrand <35958639+maxencemayrand@users.noreply.github.com> Nikoleta Glynatsi helo9 Ken Wakita Carl Sandrock Fredrik Eriksson Ian Swire Bulat Ehren Metcalfe Dmitry Savransky Kiyohito Yamazaki Caley Finn Zhi-Qiang Zhou Alexander Pozdneev Wes Turner <50891+westurner@users.noreply.github.com> JMSS-Unknown <31131631+JMSS-Unknown@users.noreply.github.com> Arshdeep Singh cym1 <16437732+cym1@users.noreply.github.com> Stewart Wadsworth Jared Lumpe Avi Shrivastava ramvenkat98 Bilal Ahmed Dimas Abreu Archanjo Dutra Yatna Verma S.Y. Lee Miro Hrončok Sudarshan Kamath Ayushman Koul Robert Dougherty-Bliss Andrey Grozin Bavish Kulur Arun Singh sirnicolaf <43586954+sirnicolaf@users.noreply.github.com> Zachariah Etienne Prayush Dawda <35144226+iamprayush@users.noreply.github.com> 2torus Faisal Riyaz Martin Roelfs SirJohnFranklin Anthony Sottile ViacheslavP Safiya03 Alexander Dunlap Rohit Sharma <31184621+rohitx007@users.noreply.github.com> Jonathan Warner Mohit Balwani Marduk Bolaños amsuhane Matthias Geier klaasvanaarsen <44929042+klaasvanaarsen@users.noreply.github.com> Shubham Kumar Jha rationa-kunal Animesh Sinha Gaurang Tandon <1gaurangtandon@gmail.com> Matthew Craven Daniel Ingram Jogi Miglani Takumasa Nakamura Ritu Raj Singh Rajiv Ranjan Singh Vera Lozhkina adhoc-king <46354827+adhoc-king@users.noreply.github.com> Mikel Rouco Oscar Gustafsson damianos Supreet Agrawal shiksha11 Martin Ueding sharma-kunal Divyanshu Thakur Susumu Ishizuka Samnan Rahee Fredrik Andersson Bhavya Srivastava Alpesh Jamgade Shubham Abhang Vishesh Mangla Nicko van Someren dandiez <47832466+dandiez@users.noreply.github.com> Frédéric Chapoton jhanwar Noumbissi valere Gille Geovan Salmista-94 Shivani Kohli Parker Berry Pragyan Mehrotra Nabanita Dash Gaetano Guerriero Ankit Raj Pandey Ritesh Kumar kangzhiq <709563092@qq.com> Jun Lin Petr Kungurtsev Anway De znxftw Denis Ivanenko OrestisVaggelis Nikhil Maan Abhinav Anand Qingsha Shi Juan Barbosa Prionti Nasir Bradley Dowling <34559056+btdow@users.noreply.github.com> Bharat Raghunathan arooshiverma Christoph Gohle Charalampos Tsiagkalis Daniel Sears Megan Ly Sean P. Cornelius Erik R. Gomez Riccardo Magliocchetti Henry Metlov pekochun Bendik Samseth Vighnesh Shenoy Versus Void Denys Rybalka Mark Dickinson Rimi rimibis <33387803+rimibis@users.noreply.github.com> Steven Lee Gilles Schintgen Abhi58 Tomasz Pytel Aadit Kamat Samesh Velibor Zeli Gabriel Bernardino Joseph Redfern Cameron King Miguel Marco David Hagen Hannah Kari Soniya Nayak Harsh Agarwal Enric Florit Yogesh Mishra Denis Rykov Ivan Tkachenko Kenneth Emeka Odoh Stephan Seitz Yeshwanth N Oscar Gerardo Lazo Arjona Srinivasa Arun Yeragudipati TitanSnow Pengning Chao <8857165+PengningChao@users.noreply.github.com> Louis Abraham Morten Olsen Lysgaard Kirtan Mali Akash Nagaraj (akasnaga) Akash Nagaraj Lauren Glattly Hou-Rui George Korepanov dranknight09 aditisingh2362 Gina gregmedlock Georgios Giapitzakis Tzintanos Maria Marginean <33810762+mmargin@users.noreply.github.com> Akash Agrawall jgulian Sourav Goyal Zlatan Vasović Alex Meiburg Smit Lunagariya Naman Gera Julien Palard Dhruv Mendiratta erdOne <36414270+erdOne@users.noreply.github.com> risubaba abhinav28071999 <41710346+abhinav28071999@users.noreply.github.com> Jisoo Song Jaime R <38530589+Jaime02@users.noreply.github.com> Vikrant Malik Hardik Saini <43683678+Guardianofgotham@users.noreply.github.com> Abhishek Johannes Hartung Milan Jolly faizan2700 mohit <39158356+mohitacecode@users.noreply.github.com> Mohit Gupta Psycho-Pirate Chanakya-Ekbote Rashmi Shehana Jonty16117 Anubhav Gupta Michal Grňo vezeli <37907135+vezeli@users.noreply.github.com> Tim Gates Sandeep Murthy Neil V1krant <46847915+V1krant@users.noreply.github.com> alejandro Riyan Dhiman sbt4104 Seth Troisi Bhaskar Gupta Smit Gajjar rbl Ilya Pchelintsev Omar Wagih prshnt19 Johan Guzman Vasileios Kalos BasileiosKal <61801875+BasileiosKal@users.noreply.github.com> Shubham Thorat <37049710+sbt4104@users.noreply.github.com> Arpan Chattopadhyay Ashutosh Hathidara Moses Paul R Saanidhya vats tnzl Vatsal Srivastava Jean-Luc Herren Dhruv Kothari seadavis <45022599+seadavis@users.noreply.github.com> kamimura slacker404 Jaime Resano Ebrahim Byagowi wuyudi Akira Kyle Calvin Jay Ross Martin Thoma Thomas A Caswell Eric Wieser Lagaras Stelios Jerry James Jan Kruse Nathan Taylor Vaishnav Damani Mohit Shah Mathias Louboutin Marijan Smetko Dave Witte Morris soumi7 Zhongshi Wes Galbraith KaustubhDamania w495 Akhil Rajput Markus Mohrhard Benjamin Wolba 彭于斌 <1931127624@qq.com> Rudr Tiwari Aaryan Dewan Benedikt Placke Sneha Goddu goddus <39923708+goddus@users.noreply.github.com> Shivang Dubey Michael Greminger Peter Cock Willem Melching Elias Basler Brandon David Abhay_Dhiman Tasha Kim Ayush Malik Devesh Sawant Wolfgang Stöcher Sudeep Sidhu foice Ben Payne Muskan Kumar <31043527+muskanvk@users.noreply.github.com> noam simcha finkelstein Garrett Folbe Islam Mansour Sayandip Halder Shubham Agrawal numbermaniac <5206120+numbermaniac@users.noreply.github.com> Sakirul Alam Mohammed Bilal Naveen Sai Chris du Plessis Coder-RG Ansh Mishra Alex Malins Lorenzo Contento Shital Mule Amanda Dsouza Nijso Beishuizen Harry Zheng Felix Yan Constantin Mateescu Eva Tiwari Aditya Kumar Sinha Soumi Bardhan <51290447+Soumi7@users.noreply.github.com> Kaustubh Chaudhari Kristian Brünn Neel Gorasiya Akshat Sood <68052998+akshatsood2249@users.noreply.github.com> Jose M. Gomez Stefan Petrea Praveen Sahu Mark Bell AlexCQY Fabian Froehlich Nikhil Gopalam Kartik Sethi Muhammed Abdul Quadir Owais Harshit Yadav Sidharth Mundhra Suryam Arnav Kalra Prince Gupta Kunal Singh Mayank Raj Achal Jain <2achaljain@gmail.com> Mario Maio Aaron Stiff <69512633+AaronStiff@users.noreply.github.com> Wyatt Peak Bhaskar Joshi Aditya Jindal Vaibhav Bhat Priyansh Rathi Saket Kumar Singh Yukai Chou Qijia Liu Paul Mandel Nisarg Chaudhari <54911392+Nisarg-Chaudhari@users.noreply.github.com> Dominik Stańczak Rodrigo Luger Marco Antônio Habitzreuter Ayush Bisht Akshansh Bhatt Brandon T. Willard Thomas Aarholt Hiren Chalodiya Roland Dixon dimasvq Sagar231 Michael Chu Abby Ng Angad Sandhu <55819847+angadsinghsandhu@users.noreply.github.com> Alexander Cockburn Yaser AlOsh Davide Sandonà Jonathan Gutow Nihir Agarwal Lee Johnston Zach Carmichael <20629897+craymichael@users.noreply.github.com> Vijairam Ganesh Moorthy Hanspeter Schmid Ben Oostendorp Nikita Aman Shashank KS Aman Sharma Anup Parikh Lucy Mountain Miguel Torres Costa Rikard Nordgren Arun sanganal <74652697+ArunSanganal@users.noreply.github.com> Kamlesh Joshi <72374645+kamleshjoshi8102@users.noreply.github.com> Joseph Rance <56409230+Joseph-Rance@users.noreply.github.com> Huangduirong Nils Schulte <47043622+Schnilz@users.noreply.github.com> Matt Bogosian Elisha Hollander Aditya Ravuri Mamidi Ratna Praneeth Jeffrey Ryan Jonathan Daniel <36337649+jond01@users.noreply.github.com> Robin Richard Gautam Menghani Remco de Boer Sebastian East Evani Balasubramanyam Rahil Parikh Jason Ross Joannah Nanjekye Ayush Kumar Kshitij Daniel Hyams Matthias Köppe sympy-sympy-1.9/CODEOWNERS000066400000000000000000000011161412543434000153150ustar00rootroot00000000000000# This file allows SymPy developers with write access to the Github repository # to specify if they'd like to be automatically requested for review in new # pull requests that touch specific files and directories in the repository. # The format is essentially: # # @user1 @user2 ... @usern # # See the following link for more information on editing this file: # # https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/about-code-owners # /sympy/physics/mechanics/ @moorepants /sympy/physics/vector/ @moorepants /sympy/solvers/ode/ @oscarbenjamin sympy-sympy-1.9/CODE_OF_CONDUCT.md000066400000000000000000000063031412543434000165240ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to make participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing or otherwise unacceptable behavior may be reported by contacting one of the project maintainers at asmeurer@gmail.com or ondrej.certik@gmail.com. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [https://contributor-covenant.org/version/1/4][version] [homepage]: https://contributor-covenant.org [version]: https://contributor-covenant.org/version/1/4/ sympy-sympy-1.9/CONTRIBUTING.md000066400000000000000000000011611412543434000161530ustar00rootroot00000000000000## Contributing We welcome contributions from anyone, even if you are new to open source. Please read our [introduction to contributing]( https://github.com/sympy/sympy/wiki/Introduction-to-contributing). If you are new and looking for some way to contribute a good place to start is to look at the issues tagged [Easy to Fix]( https://github.com/sympy/sympy/issues?q=is%3Aopen+is%3Aissue+label%3A%22Easy+to+Fix%22). Please note that all participants of this project are expected to follow our Code of Conduct. By participating in this project you agree to abide by its terms. See [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md). sympy-sympy-1.9/LICENSE000066400000000000000000000173151412543434000147370ustar00rootroot00000000000000Copyright (c) 2006-2021 SymPy Development Team All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. c. Neither the name of SymPy nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Patches that were taken from the Diofant project (https://github.com/diofant/diofant) are licensed as: Copyright (c) 2006-2018 SymPy Development Team, 2013-2021 Sergey B Kirpichev All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. c. Neither the name of Diofant or SymPy nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- Submodules taken from the multipledispatch project (https://github.com/mrocklin/multipledispatch) are licensed as: Copyright (c) 2014 Matthew Rocklin All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: a. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. b. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. c. Neither the name of multipledispatch nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- The files under the directory sympy/parsing/autolev/tests/pydy-example-repo are directly copied from PyDy project and are licensed as: Copyright (c) 2009-2021, PyDy Authors All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of this project nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PYDY AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- The files under the directory sympy/parsing/latex are directly copied from latex2sympy project and are licensed as: Copyright 2016, latex2sympy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sympy-sympy-1.9/MANIFEST.in000066400000000000000000000007601412543434000154640ustar00rootroot00000000000000recursive-include data * recursive-include doc * prune doc/_build prune doc/ext/__pycache__ exclude doc/src/modules/physics/mechanics/examples/*.pdf exclude doc/src/modules/physics/vector/*.pdf exclude doc/src/modules/vector/*.pdf recursive-include examples *.py README include sympy/utilities/mathml/data/*.xsl recursive-include sympy/parsing/latex *.g4 *.txt recursive-include sympy/parsing/autolev *.g4 *.al include LICENSE include TODO include AUTHORS include README.md include bin/isympy sympy-sympy-1.9/PULL_REQUEST_TEMPLATE.md000066400000000000000000000022201412543434000175200ustar00rootroot00000000000000 #### References to other Issues or PRs #### Brief description of what is fixed or changed #### Other comments #### Release Notes sympy-sympy-1.9/README.md000066400000000000000000000253531412543434000152120ustar00rootroot00000000000000# SymPy [![pypi version](https://img.shields.io/pypi/v/sympy.svg)](https://pypi.python.org/pypi/sympy) [![Build status](https://secure.travis-ci.org/sympy/sympy.svg?branch=master)](https://travis-ci.org/sympy/sympy) [![Join the chat at https://gitter.im/sympy/sympy](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/sympy/sympy?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Zenodo Badge](https://zenodo.org/badge/18918/sympy/sympy.svg)](https://zenodo.org/badge/latestdoi/18918/sympy/sympy) [![codecov Badge](https://codecov.io/gh/sympy/sympy/branch/master/graph/badge.svg)](https://codecov.io/gh/sympy/sympy) [![SymPy Banner](https://github.com/sympy/sympy/raw/master/banner.svg)](https://sympy.org/) See the AUTHORS file for the list of authors. And many more people helped on the SymPy mailing list, reported bugs, helped organize SymPy's participation in the Google Summer of Code, the Google Highly Open Participation Contest, Google Code-In, wrote and blogged about SymPy... License: New BSD License (see the LICENSE file for details) covers all files in the sympy repository unless stated otherwise. Our mailing list is at . We have a community chat at [Gitter](https://gitter.im/sympy/sympy). Feel free to ask us anything there. We have a very welcoming and helpful community. ## Download The recommended installation method is through Anaconda, You can also get the latest version of SymPy from To get the git version do $ git clone git://github.com/sympy/sympy.git For other options (tarballs, debs, etc.), see . ## Documentation and Usage For in-depth instructions on installation and building the documentation, see the [SymPy Documentation Style Guide](https://docs.sympy.org/dev/documentation-style-guide.html). Everything is at: You can generate everything at the above site in your local copy of SymPy by: $ cd doc $ make html Then the docs will be in \_build/html. If you don't want to read that, here is a short usage: From this directory, start Python and: ``` python >>> from sympy import Symbol, cos >>> x = Symbol('x') >>> e = 1/cos(x) >>> print(e.series(x, 0, 10)) 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + 277*x**8/8064 + O(x**10) ``` SymPy also comes with a console that is a simple wrapper around the classic python console (or IPython when available) that loads the SymPy namespace and executes some common commands for you. To start it, issue: $ bin/isympy from this directory, if SymPy is not installed or simply: $ isympy if SymPy is installed. ## Installation SymPy has a hard dependency on the [mpmath](http://mpmath.org/) library (version \>= 0.19). You should install it first, please refer to the mpmath installation guide: To install SymPy using PyPI, run the following command: $ pip install sympy To install SymPy using Anaconda, run the following command: $ conda install -c anaconda sympy To install SymPy from GitHub source, first clone SymPy using `git`: $ git clone https://github.com/sympy/sympy.git Then, in the `sympy` repository that you cloned, simply run: $ python setup.py install See for more information. ## Contributing We welcome contributions from anyone, even if you are new to open source. Please read our [Introduction to Contributing](https://github.com/sympy/sympy/wiki/Introduction-to-contributing) page and the [SymPy Documentation Style Guide](https://docs.sympy.org/dev/documentation-style-guide.html). If you are new and looking for some way to contribute, a good place to start is to look at the issues tagged [Easy to Fix](https://github.com/sympy/sympy/issues?q=is%3Aopen+is%3Aissue+label%3A%22Easy+to+Fix%22). Please note that all participants in this project are expected to follow our Code of Conduct. By participating in this project you agree to abide by its terms. See [CODE\_OF\_CONDUCT.md](CODE_OF_CONDUCT.md). ## Tests To execute all tests, run: $./setup.py test in the current directory. For the more fine-grained running of tests or doctests, use `bin/test` or respectively `bin/doctest`. The master branch is automatically tested by Travis CI. To test pull requests, use [sympy-bot](https://github.com/sympy/sympy-bot). ## Regenerate Experimental LaTeX Parser/Lexer The parser and lexer generated with the [ANTLR4](http://antlr4.org) toolchain in `sympy/parsing/latex/_antlr` and checked into the repo. Presently, most users should not need to regenerate these files, but if you plan to work on this feature, you will need the `antlr4` command-line tool (and you must ensure that it is in your `PATH`). One way to get it is: $ conda install -c conda-forge antlr=4.7.2 Alternatively, follow the instructions on the ANTLR website and download the `antlr-4.7.2-complete.jar`. Then export the `CLASSPATH` as instructed and instead of creating `antlr4` as an alias, make it an executable file with the following contents: ``` bash #!/bin/bash java -jar /usr/local/lib/antlr-4.7.2-complete.jar "$@" ``` After making changes to `sympy/parsing/latex/LaTeX.g4`, run: $ ./setup.py antlr ## Clean To clean everything (thus getting the same tree as in the repository): $ ./setup.py clean You can also clean things with git using: $ git clean -Xdf which will clear everything ignored by `.gitignore`, and: $ git clean -df to clear all untracked files. You can revert the most recent changes in git with: $ git reset --hard WARNING: The above commands will all clear changes you may have made, and you will lose them forever. Be sure to check things with `git status`, `git diff`, `git clean -Xn`, and `git clean -n` before doing any of those. ## Bugs Our issue tracker is at . Please report any bugs that you find. Or, even better, fork the repository on GitHub and create a pull request. We welcome all changes, big or small, and we will help you make the pull request if you are new to git (just ask on our mailing list or Gitter Channel). If you further have any queries, you can find answers on Stack Overflow using the [sympy](https://stackoverflow.com/questions/tagged/sympy) tag. ## Brief History SymPy was started by Ondřej Čertík in 2005, he wrote some code during the summer, then he wrote some more code during summer 2006. In February 2007, Fabian Pedregosa joined the project and helped fixed many things, contributed documentation, and made it alive again. 5 students (Mateusz Paprocki, Brian Jorgensen, Jason Gedge, Robert Schwarz, and Chris Wu) improved SymPy incredibly during summer 2007 as part of the Google Summer of Code. Pearu Peterson joined the development during the summer 2007 and he has made SymPy much more competitive by rewriting the core from scratch, which has made it from 10x to 100x faster. Jurjen N.E. Bos has contributed pretty-printing and other patches. Fredrik Johansson has written mpmath and contributed a lot of patches. SymPy has participated in every Google Summer of Code since 2007. You can see for full details. Each year has improved SymPy by bounds. Most of SymPy's development has come from Google Summer of Code students. In 2011, Ondřej Čertík stepped down as lead developer, with Aaron Meurer, who also started as a Google Summer of Code student, taking his place. Ondřej Čertík is still active in the community but is too busy with work and family to play a lead development role. Since then, a lot more people have joined the development and some people have also left. You can see the full list in doc/src/aboutus.rst, or online at: The git history goes back to 2007 when development moved from svn to hg. To see the history before that point, look at . You can use git to see the biggest developers. The command: $ git shortlog -ns will show each developer, sorted by commits to the project. The command: $ git shortlog -ns --since="1 year" will show the top developers from the last year. ## Citation To cite SymPy in publications use > Meurer A, Smith CP, Paprocki M, Čertík O, Kirpichev SB, Rocklin M, > Kumar A, Ivanov S, Moore JK, Singh S, Rathnayake T, Vig S, Granger BE, > Muller RP, Bonazzi F, Gupta H, Vats S, Johansson F, Pedregosa F, Curry > MJ, Terrel AR, Roučka Š, Saboo A, Fernando I, Kulal S, Cimrman R, > Scopatz A. (2017) SymPy: symbolic computing in Python. *PeerJ Computer > Science* 3:e103 A BibTeX entry for LaTeX users is ``` bibtex @article{10.7717/peerj-cs.103, title = {SymPy: symbolic computing in Python}, author = {Meurer, Aaron and Smith, Christopher P. and Paprocki, Mateusz and \v{C}ert\'{i}k, Ond\v{r}ej and Kirpichev, Sergey B. and Rocklin, Matthew and Kumar, Amit and Ivanov, Sergiu and Moore, Jason K. and Singh, Sartaj and Rathnayake, Thilina and Vig, Sean and Granger, Brian E. and Muller, Richard P. and Bonazzi, Francesco and Gupta, Harsh and Vats, Shivam and Johansson, Fredrik and Pedregosa, Fabian and Curry, Matthew J. and Terrel, Andy R. and Rou\v{c}ka, \v{S}t\v{e}p\'{a}n and Saboo, Ashutosh and Fernando, Isuru and Kulal, Sumith and Cimrman, Robert and Scopatz, Anthony}, year = 2017, month = Jan, keywords = {Python, Computer algebra system, Symbolics}, abstract = { SymPy is an open-source computer algebra system written in pure Python. It is built with a focus on extensibility and ease of use, through both interactive and programmatic applications. These characteristics have led SymPy to become a popular symbolic library for the scientific Python ecosystem. This paper presents the architecture of SymPy, a description of its features, and a discussion of select submodules. The supplementary material provides additional examples and further outlines details of the architecture and features of SymPy. }, volume = 3, pages = {e103}, journal = {PeerJ Computer Science}, issn = {2376-5992}, url = {https://doi.org/10.7717/peerj-cs.103}, doi = {10.7717/peerj-cs.103} } ``` SymPy is BSD licensed, so you are free to use it whatever you like, be it academic, commercial, creating forks or derivatives, as long as you copy the BSD statement if you redistribute it (see the LICENSE file for details). That said, although not required by the SymPy license, if it is convenient for you, please cite SymPy when using it in your work and also consider contributing all your changes back, so that we can incorporate it and all of us will benefit in the end. sympy-sympy-1.9/asv.conf.actions.json000066400000000000000000000061041412543434000177730ustar00rootroot00000000000000{ // This is the configuration file used for running the benchmarks from // sympy_benchmarks in GitHub Actions. The commands that are run can be // seen in the benchmarks job in runtests.yml. // The version of the config file format. Do not change, unless // you know what you are doing. "version": 1, // The name of the project being benchmarked "project": "sympy", // The project's homepage "project_url": "http://sympy.org/", // The URL or local path of the source code repository for the // project being benchmarked "repo": ".", // List of branches to benchmark. If not provided, defaults to "master" // (for git) or "tip" (for mercurial). // This list needs to be updated after each release of sympy. The branch to // be checked should always be the previous release. "branches": ["upstream/1.8", "upstream/master", "HEAD"], // for git // "branches": ["tip"], // for mercurial // The DVCS being used. If not set, it will be automatically // determined from "repo" by looking at the protocol in the URL // (if remote), or by looking for special directories, such as // ".git" (if local). // "dvcs": "git", // The tool to use to create environments. May be "conda", // "virtualenv" or other value depending on the plugins in use. // If missing or the empty string, the tool will be automatically // determined by looking for tools on the PATH environment // variable. "environment_type": "virtualenv", // the base URL to show a commit for the project. "show_commit_url": "http://github.com/sympy/sympy/commit/", // The Pythons you'd like to test against. If not provided, defaults // to the current version of Python used to run `asv`. "pythons": ["3.8"], // The matrix of dependencies to test. Each key is the name of a // package (in PyPI) and the values are version numbers. An empty // list indicates to just test against the default (latest) // version. "matrix": { "mpmath": [], "numpy": [] }, // The directory (relative to the current directory) that benchmarks are // stored in. If not provided, defaults to "benchmarks" "benchmark_dir": "sympy_benchmarks/benchmarks", // The directory (relative to the current directory) to cache the Python // environments in. If not provided, defaults to "env" "env_dir": "sympy_benchmarks/env", // The directory (relative to the current directory) that raw benchmark // results are stored in. If not provided, defaults to "results". "results_dir": "sympy_benchmarks/results" // The directory (relative to the current directory) that the html tree // should be written to. If not provided, defaults to "html". // "html_dir": "html", // The number of characters to retain in the commit hashes. // "hash_length": 8, // `asv` will cache wheels of the recent builds in each // environment, making them faster to install next time. This is // number of builds to keep, per environment. // "wheel_cache_size": 0 } sympy-sympy-1.9/asv.conf.travis.json000066400000000000000000000053261412543434000176500ustar00rootroot00000000000000{ // The version of the config file format. Do not change, unless // you know what you are doing. "version": 1, // The name of the project being benchmarked "project": "sympy", // The project's homepage "project_url": "http://sympy.org/", // The URL or local path of the source code repository for the // project being benchmarked "repo": ".", // List of branches to benchmark. If not provided, defaults to "master" // (for git) or "tip" (for mercurial). "branches": ["master", "HEAD"], // for git // "branches": ["tip"], // for mercurial // The DVCS being used. If not set, it will be automatically // determined from "repo" by looking at the protocol in the URL // (if remote), or by looking for special directories, such as // ".git" (if local). // "dvcs": "git", // The tool to use to create environments. May be "conda", // "virtualenv" or other value depending on the plugins in use. // If missing or the empty string, the tool will be automatically // determined by looking for tools on the PATH environment // variable. "environment_type": "virtualenv", // the base URL to show a commit for the project. "show_commit_url": "http://github.com/sympy/sympy/commit/", // The Pythons you'd like to test against. If not provided, defaults // to the current version of Python used to run `asv`. "pythons": ["3.6"], // The matrix of dependencies to test. Each key is the name of a // package (in PyPI) and the values are version numbers. An empty // list indicates to just test against the default (latest) // version. "matrix": { "mpmath": [], "numpy": [] }, // The directory (relative to the current directory) that benchmarks are // stored in. If not provided, defaults to "benchmarks" "benchmark_dir": "sympy_benchmarks/benchmarks", // The directory (relative to the current directory) to cache the Python // environments in. If not provided, defaults to "env" "env_dir": "sympy_benchmarks/env", // The directory (relative to the current directory) that raw benchmark // results are stored in. If not provided, defaults to "results". "results_dir": "sympy_benchmarks/results" // The directory (relative to the current directory) that the html tree // should be written to. If not provided, defaults to "html". // "html_dir": "html", // The number of characters to retain in the commit hashes. // "hash_length": 8, // `asv` will cache wheels of the recent builds in each // environment, making them faster to install next time. This is // number of builds to keep, per environment. // "wheel_cache_size": 0 } sympy-sympy-1.9/banner.svg000066400000000000000000002534741412543434000157300ustar00rootroot00000000000000 image/svg+xml Python Library for Symbolic Mathematics https://sympy.org/ sympy-sympy-1.9/bin/000077500000000000000000000000001412543434000144735ustar00rootroot00000000000000sympy-sympy-1.9/bin/ask_update.py000077500000000000000000000052741412543434000172000ustar00rootroot00000000000000#!/usr/bin/env python """ Update the ``ask_generated.py`` file. This must be run each time ``known_facts()`` in ``assumptions.facts`` module is changed. Should be run from sympy root directory. $ python bin/ask_update.py """ # hook in-tree SymPy into Python path, if possible import os import sys isympy_path = os.path.abspath(__file__) isympy_dir = os.path.dirname(isympy_path) sympy_top = os.path.split(isympy_dir)[0] sympy_dir = os.path.join(sympy_top, 'sympy') if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) from sympy.assumptions.cnf import CNF, Literal from sympy.assumptions.facts import (get_known_facts, generate_known_facts_dict, get_known_facts_keys) from sympy.core import Symbol def generate_code(): from textwrap import dedent, wrap LINE = ",\n " HANG = ' '*8 code_string = dedent('''\ """ Do NOT manually edit this file. Instead, run ./bin/ask_update.py. """ from sympy.assumptions.ask import Q from sympy.assumptions.cnf import Literal from sympy.core.cache import cacheit @cacheit def get_all_known_facts(): """ Known facts between unary predicates as CNF clauses. """ return { %s } @cacheit def get_known_facts_dict(): """ Logical relations between unary predicates as dictionary. Each key is a predicate, and item is two groups of predicates. First group contains the predicates which are implied by the key, and second group contains the predicates which are rejected by the key. """ return { %s } ''') x = Symbol('x') fact = get_known_facts(x) # Generate CNF of facts between known unary predicates cnf = CNF.to_CNF(fact) p = LINE.join(sorted([ 'frozenset((' + ', '.join(str(Literal(lit.arg.function, lit.is_Not)) for lit in sorted(clause, key=str)) + '))' for clause in cnf.clauses])) # Generate dictionary of facts between known unary predicates keys = [pred(x) for pred in get_known_facts_keys()] mapping = generate_known_facts_dict(keys, fact) items = sorted(mapping.items(), key=str) keys = [str(i[0]) for i in items] values = ['(set(%s), set(%s))' % (sorted(i[1][0], key=str), sorted(i[1][1], key=str)) for i in items] m = LINE.join(['\n'.join( wrap("{}: {}".format(k, v), subsequent_indent=HANG, break_long_words=False)) for k, v in zip(keys, values)]) + ',' return code_string % (p, m) with open('sympy/assumptions/ask_generated.py', 'w') as f: code = generate_code() f.write(code) sympy-sympy-1.9/bin/authors_update.py000077500000000000000000000130251412543434000201000ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ A tool to generate AUTHORS. We started tracking authors before moving to git, so we have to do some manual rearrangement of the git history authors in order to get the order in AUTHORS. bin/mailmap_update.py should be run before committing the results. """ from __future__ import unicode_literals from __future__ import print_function import codecs import sys import os if sys.version_info < (3, 6): sys.exit("This script requires Python 3.6 or newer") from sympy.external.importtools import version_tuple from subprocess import check_output, PIPE from collections import OrderedDict def run(cmd): return check_output(cmd, encoding='utf-8') def red(text): return "\033[31m%s\033[0m" % text def yellow(text): return "\033[33m%s\033[0m" % text def green(text): return "\033[32m%s\033[0m" % text # put sympy on the path mailmap_update_path = os.path.abspath(__file__) mailmap_update_dir = os.path.dirname(mailmap_update_path) sympy_top = os.path.split(mailmap_update_dir)[0] sympy_dir = os.path.join(sympy_top, 'sympy') if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) from sympy.utilities.misc import filldedent # check git version minimal = '1.8.4.2' git_ver = run(['git', '--version'])[12:] if version_tuple(git_ver) < version_tuple(minimal): print(yellow("Please use a git version >= %s" % minimal)) def author_name(line): assert line.count("<") == line.count(">") == 1 assert line.endswith(">") return line.split("<", 1)[0].strip() def move(l, i1, i2, who): x = l.pop(i1) # this will fail if the .mailmap is not right assert who == author_name(x), \ '%s was not found at line %i' % (who, i1) l.insert(i2, x) # find who git knows ahout git_command = ["git", "log", "--topo-order", "--reverse", "--format=%aN <%aE>"] git_people = run(git_command).strip().split("\n") # remove duplicates, keeping the original order git_people = list(OrderedDict.fromkeys(git_people)) # Do the few changes necessary in order to reproduce AUTHORS: try: move(git_people, 2, 0, 'Ondřej Čertík') move(git_people, 42, 1, 'Fabian Pedregosa') move(git_people, 22, 2, 'Jurjen N.E. Bos') git_people.insert(4, "*Marc-Etienne M.Leveille ") move(git_people, 10, 5, 'Brian Jorgensen') git_people.insert(11, "*Ulrich Hecht ") # this will fail if the .mailmap is not right assert 'Kirill Smelkov' == author_name(git_people.pop(12) ), 'Kirill Smelkov was not found at line 12' move(git_people, 12, 32, 'Sebastian Krämer') move(git_people, 227, 35, 'Case Van Horsen') git_people.insert(43, "*Dan ") move(git_people, 57, 59, 'Aaron Meurer') move(git_people, 58, 57, 'Andrew Docherty') move(git_people, 67, 66, 'Chris Smith') move(git_people, 79, 76, 'Kevin Goodsell') git_people.insert(84, "*Chu-Ching Huang ") move(git_people, 93, 92, 'James Pearson') # this will fail if the .mailmap is not right assert 'Sergey B Kirpichev' == author_name(git_people.pop(226) ), 'Sergey B Kirpichev was not found at line 226.' index = git_people.index( "azure-pipelines[bot] " + "") git_people.pop(index) index = git_people.index( "whitesource-bolt-for-github[bot] " + "") git_people.pop(index) except AssertionError as msg: print(red(msg)) sys.exit(1) # define new lines for the file header = filldedent(""" All people who contributed to SymPy by sending at least a patch or more (in the order of the date of their first contribution), except those who explicitly didn't want to be mentioned. People with a * next to their names are not found in the metadata of the git history. This file is generated automatically by running `./bin/authors_update.py`. """).lstrip() fmt = """There are a total of {authors_count} authors.""" header_extra = fmt.format(authors_count=len(git_people)) lines = header.splitlines() lines.append('') lines.append(header_extra) lines.append('') lines.extend(git_people) # compare to old lines and stop if no changes were made old_lines = codecs.open(os.path.realpath(os.path.join( __file__, os.path.pardir, os.path.pardir, "AUTHORS")), "r", "utf-8").read().splitlines() if old_lines == lines: print(green('No changes made to AUTHORS.')) sys.exit(0) # check for new additions new_authors = [] for i in sorted(set(lines) - set(old_lines)): try: author_name(i) new_authors.append(i) except AssertionError: continue # write the new file with codecs.open(os.path.realpath(os.path.join( __file__, os.path.pardir, os.path.pardir, "AUTHORS")), "w", "utf-8") as fd: fd.write('\n'.join(lines)) fd.write('\n') # warn about additions if new_authors: print(yellow(filldedent(""" The following authors were added to AUTHORS. If mailmap_update.py has already been run and each author appears as desired and is not a duplicate of some other author, then the changes can be committed. Otherwise, see .mailmap for instructions on how to change an author's entry."""))) print() for i in sorted(new_authors, key=lambda x: x.lower()): print('\t%s' % i) else: print(yellow("The AUTHORS file was updated.")) print(red("Changes were made in the authors file")) run(['git', 'diff']) # Show the changes sys.exit(1) sympy-sympy-1.9/bin/coverage_doctest.py000077500000000000000000000531021412543434000203710ustar00rootroot00000000000000#!/usr/bin/env python """ Program to test that all methods/functions have at least one example doctest. Also checks if docstrings are imported into Sphinx. For this to work, the Sphinx docs need to be built first. Use "cd doc; make html" to build the Sphinx docs. Usage: ./bin/coverage_doctest.py sympy/core or ./bin/coverage_doctest.py sympy/core/basic.py If no arguments are given, all files in sympy/ are checked. """ from __future__ import print_function import os import sys import inspect from argparse import ArgumentParser, RawDescriptionHelpFormatter try: from HTMLParser import HTMLParser except ImportError: # It's html.parser in Python 3 from html.parser import HTMLParser from sympy.utilities.misc import filldedent # Load color templates, duplicated from sympy/testing/runtests.py color_templates = ( ("Black", "0;30"), ("Red", "0;31"), ("Green", "0;32"), ("Brown", "0;33"), ("Blue", "0;34"), ("Purple", "0;35"), ("Cyan", "0;36"), ("LightGray", "0;37"), ("DarkGray", "1;30"), ("LightRed", "1;31"), ("LightGreen", "1;32"), ("Yellow", "1;33"), ("LightBlue", "1;34"), ("LightPurple", "1;35"), ("LightCyan", "1;36"), ("White", "1;37"), ) colors = {} for name, value in color_templates: colors[name] = value c_normal = '\033[0m' c_color = '\033[%sm' def print_header(name, underline=None, color=None): print() if color: print("%s%s%s" % (c_color % colors[color], name, c_normal)) else: print(name) if underline and not color: print(underline*len(name)) def print_coverage(module_path, c, c_md, c_mdt, c_idt, c_sph, f, f_md, f_mdt, f_idt, f_sph, score, total_doctests, total_members, sphinx_score, total_sphinx, verbose=False, no_color=False, sphinx=True): """ Prints details (depending on verbose) of a module """ doctest_color = "Brown" sphinx_color = "DarkGray" less_100_color = "Red" less_50_color = "LightRed" equal_100_color = "Green" big_header_color = "LightPurple" small_header_color = "Purple" if no_color: score_string = "Doctests: %s%% (%s of %s)" % (score, total_doctests, total_members) elif score < 100: if score < 50: score_string = "%sDoctests:%s %s%s%% (%s of %s)%s" % \ (c_color % colors[doctest_color], c_normal, c_color % colors[less_50_color], score, total_doctests, total_members, c_normal) else: score_string = "%sDoctests:%s %s%s%% (%s of %s)%s" % \ (c_color % colors[doctest_color], c_normal, c_color % colors[less_100_color], score, total_doctests, total_members, c_normal) else: score_string = "%sDoctests:%s %s%s%% (%s of %s)%s" % \ (c_color % colors[doctest_color], c_normal, c_color % colors[equal_100_color], score, total_doctests, total_members, c_normal) if sphinx: if no_color: sphinx_score_string = "Sphinx: %s%% (%s of %s)" % (sphinx_score, total_members - total_sphinx, total_members) elif sphinx_score < 100: if sphinx_score < 50: sphinx_score_string = "%sSphinx:%s %s%s%% (%s of %s)%s" % \ (c_color % colors[sphinx_color], c_normal, c_color % colors[less_50_color], sphinx_score, total_members - total_sphinx, total_members, c_normal) else: sphinx_score_string = "%sSphinx:%s %s%s%% (%s of %s)%s" % \ (c_color % colors[sphinx_color], c_normal, c_color % colors[less_100_color], sphinx_score, total_members - total_sphinx, total_members, c_normal) else: sphinx_score_string = "%sSphinx:%s %s%s%% (%s of %s)%s" % \ (c_color % colors[sphinx_color], c_normal, c_color % colors[equal_100_color], sphinx_score, total_members - total_sphinx, total_members, c_normal) if verbose: print('\n' + '-'*70) print(module_path) print('-'*70) else: if sphinx: print("%s: %s %s" % (module_path, score_string, sphinx_score_string)) else: print("%s: %s" % (module_path, score_string)) if verbose: print_header('CLASSES', '*', not no_color and big_header_color) if not c: print_header('No classes found!') else: if c_md: print_header('Missing docstrings', '-', not no_color and small_header_color) for md in c_md: print(' * ' + md) if c_mdt: print_header('Missing doctests', '-', not no_color and small_header_color) for md in c_mdt: print(' * ' + md) if c_idt: # Use "# indirect doctest" in the docstring to # suppress this warning. print_header('Indirect doctests', '-', not no_color and small_header_color) for md in c_idt: print(' * ' + md) print('\n Use \"# indirect doctest\" in the docstring to suppress this warning') if c_sph: print_header('Not imported into Sphinx', '-', not no_color and small_header_color) for md in c_sph: print(' * ' + md) print_header('FUNCTIONS', '*', not no_color and big_header_color) if not f: print_header('No functions found!') else: if f_md: print_header('Missing docstrings', '-', not no_color and small_header_color) for md in f_md: print(' * ' + md) if f_mdt: print_header('Missing doctests', '-', not no_color and small_header_color) for md in f_mdt: print(' * ' + md) if f_idt: print_header('Indirect doctests', '-', not no_color and small_header_color) for md in f_idt: print(' * ' + md) print('\n Use \"# indirect doctest\" in the docstring to suppress this warning') if f_sph: print_header('Not imported into Sphinx', '-', not no_color and small_header_color) for md in f_sph: print(' * ' + md) if verbose: print('\n' + '-'*70) print(score_string) if sphinx: print(sphinx_score_string) print('-'*70) def _is_indirect(member, doc): """ Given string repr of doc and member checks if the member contains indirect documentation """ d = member in doc e = 'indirect doctest' in doc if not d and not e: return True else: return False def _get_arg_list(name, fobj): """ Given a function object, constructs a list of arguments and their defaults. Takes care of varargs and kwargs """ trunc = 20 # Sometimes argument length can be huge argspec = inspect.getfullargspec(fobj) arg_list = [] if argspec.args: for arg in argspec.args: arg_list.append(str(arg)) arg_list.reverse() # Now add the defaults if argspec.defaults: for i in range(len(argspec.defaults)): arg_list[i] = str(arg_list[i]) + '=' + str(argspec.defaults[-i]) # Get the list in right order arg_list.reverse() # Add var args if argspec.varargs: arg_list.append(argspec.varargs) if argspec.keywords: arg_list.append(argspec.keywords) # Truncate long arguments arg_list = [x[:trunc] for x in arg_list] # Construct the parameter string (enclosed in brackets) str_param = "%s(%s)" % (name, ', '.join(arg_list)) return str_param def get_mod_name(path, base): """ Gets a module name, given the path of file/dir and base dir of sympy """ rel_path = os.path.relpath(path, base) # Remove the file extension rel_path, ign = os.path.splitext(rel_path) # Replace separators by . for module path file_module = "" h, t = os.path.split(rel_path) while h or t: if t: file_module = t + '.' + file_module h, t = os.path.split(h) return file_module[:-1] class FindInSphinx(HTMLParser): is_imported = [] def handle_starttag(self, tag, attr): a = dict(attr) if tag == "div" and a.get('class', None) == "viewcode-block": self.is_imported.append(a['id']) def find_sphinx(name, mod_path, found={}): if mod_path in found: # Cache results return name in found[mod_path] doc_path = mod_path.split('.') doc_path[-1] += '.html' sphinx_path = os.path.join(sympy_top, 'doc', '_build', 'html', '_modules', *doc_path) if not os.path.exists(sphinx_path): return False with open(sphinx_path) as f: html_txt = f.read() p = FindInSphinx() p.feed(html_txt) found[mod_path] = p.is_imported return name in p.is_imported def process_function(name, c_name, b_obj, mod_path, f_sk, f_md, f_mdt, f_idt, f_has_doctest, sk_list, sph, sphinx=True): """ Processes a function to get information regarding documentation. It is assume that the function calling this subrouting has already verified that it is a valid module function. """ if name in sk_list: return False, False # We add in the end, as inspect.getsourcelines is slow add_md = False add_mdt = False add_idt = False in_sphinx = True f_doctest = False function = False if inspect.isclass(b_obj): obj = getattr(b_obj, name) obj_name = c_name + '.' + name else: obj = b_obj obj_name = name full_name = _get_arg_list(name, obj) if name.startswith('_'): f_sk.append(full_name) else: doc = obj.__doc__ if type(doc) is str: if not doc: add_md = True elif not '>>>' in doc: add_mdt = True elif _is_indirect(name, doc): add_idt = True else: f_doctest = True elif doc is None: # this was a function defined in the docstring f_doctest = True else: assert None, type(doc) function = True if sphinx: in_sphinx = find_sphinx(obj_name, mod_path) if add_md or add_mdt or add_idt or not in_sphinx: try: line_no = inspect.getsourcelines(obj)[1] except IOError: # Raised when source does not exist # which means the function is not there. return False, False full_name = "LINE %d: %s" % (line_no, full_name) if add_md: f_md.append(full_name) elif add_mdt: f_mdt.append(full_name) elif add_idt: f_idt.append(full_name) if not in_sphinx: sph.append(full_name) return f_doctest, function def process_class(c_name, obj, c_sk, c_md, c_mdt, c_idt, c_has_doctest, mod_path, sph, sphinx=True): """ Extracts information about the class regarding documentation. It is assumed that the function calling this subroutine has already checked that the class is valid. """ # Skip class case if c_name.startswith('_'): c_sk.append(c_name) return False, False, None c = False c_dt = False # Get the line number of class try: source, line_no = inspect.getsourcelines(obj) except IOError: # Raised when source does not exist # which means the class is not there. return False, False, None c = True full_name = "LINE %d: %s" % (line_no, c_name) doc = obj.__doc__ if type(doc) is str: if not doc: c_md.append(full_name) elif not '>>>' in doc: c_mdt.append(full_name) elif _is_indirect(c_name, doc): c_idt.append(full_name) else: c_dt = True c_has_doctest.append(full_name) elif doc is None: # this was a class defined in the docstring c_dt = True c_has_doctest.append(full_name) else: assert None, type(doc) in_sphinx = False if sphinx: in_sphinx = find_sphinx(c_name, mod_path) if not in_sphinx: sph.append(full_name) return c_dt, c, source def coverage(module_path, verbose=False, no_color=False, sphinx=True): """ Given a module path, builds an index of all classes and functions contained. It then goes through each of the classes/functions to get the docstring and doctest coverage of the module. """ # Import the package and find members m = None try: __import__(module_path) m = sys.modules[module_path] except Exception as a: # Most likely cause, absence of __init__ print("%s could not be loaded due to %s." % (module_path, repr(a))) return 0, 0, 0 c_skipped = [] c_md = [] c_mdt = [] c_has_doctest = [] c_idt = [] classes = 0 c_doctests = 0 c_sph = [] f_skipped = [] f_md = [] f_mdt = [] f_has_doctest = [] f_idt = [] functions = 0 f_doctests = 0 f_sph = [] skip_members = ['__abstractmethods__'] # Get the list of members m_members = dir(m) for member in m_members: # Check for skipped functions first, they throw nasty errors # when combined with getattr if member in skip_members: continue # Identify if the member (class/def) is a part of this module obj = getattr(m, member) obj_mod = inspect.getmodule(obj) # Function not a part of this module if not obj_mod or not obj_mod.__name__ == module_path: continue # If it's a function if inspect.isfunction(obj) or inspect.ismethod(obj): f_dt, f = process_function(member, '', obj, module_path, f_skipped, f_md, f_mdt, f_idt, f_has_doctest, skip_members, f_sph, sphinx=sphinx) if f: functions += 1 if f_dt: f_doctests += 1 # If it's a class, look at it's methods too elif inspect.isclass(obj): # Process the class first c_dt, c, source = process_class(member, obj, c_skipped, c_md, c_mdt, c_idt, c_has_doctest, module_path, c_sph, sphinx=sphinx) if not c: continue else: classes += 1 if c_dt: c_doctests += 1 # Iterate through it's members for f_name in obj.__dict__: if f_name in skip_members or f_name.startswith('_'): continue # Check if def funcname appears in source if not ("def " + f_name) in ' '.join(source): continue # Identify the module of the current class member f_obj = getattr(obj, f_name) obj_mod = inspect.getmodule(f_obj) # Function not a part of this module if not obj_mod or not obj_mod.__name__ == module_path: continue # If it's a function if inspect.isfunction(f_obj) or inspect.ismethod(f_obj): f_dt, f = process_function(f_name, member, obj, module_path, f_skipped, f_md, f_mdt, f_idt, f_has_doctest, skip_members, f_sph, sphinx=sphinx) if f: functions += 1 if f_dt: f_doctests += 1 # Evaluate the percent coverage total_doctests = c_doctests + f_doctests total_members = classes + functions if total_members: score = 100 * float(total_doctests) / (total_members) else: score = 100 score = int(score) if sphinx: total_sphinx = len(c_sph) + len(f_sph) if total_members: sphinx_score = 100 - 100 * float(total_sphinx) / total_members else: sphinx_score = 100 sphinx_score = int(sphinx_score) else: total_sphinx = 0 sphinx_score = 0 # Sort functions/classes by line number c_md = sorted(c_md, key=lambda x: int(x.split()[1][:-1])) c_mdt = sorted(c_mdt, key=lambda x: int(x.split()[1][:-1])) c_idt = sorted(c_idt, key=lambda x: int(x.split()[1][:-1])) f_md = sorted(f_md, key=lambda x: int(x.split()[1][:-1])) f_mdt = sorted(f_mdt, key=lambda x: int(x.split()[1][:-1])) f_idt = sorted(f_idt, key=lambda x: int(x.split()[1][:-1])) print_coverage(module_path, classes, c_md, c_mdt, c_idt, c_sph, functions, f_md, f_mdt, f_idt, f_sph, score, total_doctests, total_members, sphinx_score, total_sphinx, verbose=verbose, no_color=no_color, sphinx=sphinx) return total_doctests, total_sphinx, total_members def go(sympy_top, file, verbose=False, no_color=False, exact=True, sphinx=True): # file names containing any string in skip_paths will be skipped, skip_paths = [] if os.path.isdir(file): doctests, total_sphinx, num_functions = 0, 0, 0 for F in os.listdir(file): _doctests, _total_sphinx, _num_functions = go(sympy_top, '%s/%s' % (file, F), verbose=verbose, no_color=no_color, exact=False, sphinx=sphinx) doctests += _doctests total_sphinx += _total_sphinx num_functions += _num_functions return doctests, total_sphinx, num_functions if (not (file.endswith('.py') or file.endswith('.pyx')) or file.endswith('__init__.py') or not exact and ('test_' in file or 'bench_' in file or any(name in file for name in skip_paths))): return 0, 0, 0 if not os.path.exists(file): print("File(%s does not exist." % file) sys.exit(1) # Relpath for constructing the module name return coverage(get_mod_name(file, sympy_top), verbose=verbose, no_color=no_color, sphinx=sphinx) if __name__ == "__main__": bintest_dir = os.path.abspath(os.path.dirname(__file__)) # bin/cover... sympy_top = os.path.split(bintest_dir)[0] # ../ sympy_dir = os.path.join(sympy_top, 'sympy') # ../sympy/ if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) usage = "usage: ./bin/doctest_coverage.py PATHS" parser = ArgumentParser( description=__doc__, usage=usage, formatter_class=RawDescriptionHelpFormatter, ) parser.add_argument("path", nargs='*', default=[os.path.join(sympy_top, 'sympy')]) parser.add_argument("-v", "--verbose", action="store_true", dest="verbose", default=False) parser.add_argument("--no-colors", action="store_true", dest="no_color", help="use no colors", default=False) parser.add_argument("--no-sphinx", action="store_false", dest="sphinx", help="don't report Sphinx coverage", default=True) args = parser.parse_args() if args.sphinx and not os.path.exists(os.path.join(sympy_top, 'doc', '_build', 'html')): print(filldedent(""" Cannot check Sphinx coverage without a documentation build. To build the docs, run "cd doc; make html". To skip checking Sphinx coverage, pass --no-sphinx. """)) sys.exit(1) full_coverage = True for file in args.path: file = os.path.normpath(file) print('DOCTEST COVERAGE for %s' % (file)) print('='*70) print() doctests, total_sphinx, num_functions = go(sympy_top, file, verbose=args.verbose, no_color=args.no_color, sphinx=args.sphinx) if num_functions == 0: score = 100 sphinx_score = 100 else: score = 100 * float(doctests) / num_functions score = int(score) if doctests < num_functions: full_coverage = False if args.sphinx: sphinx_score = 100 - 100 * float(total_sphinx) / num_functions sphinx_score = int(sphinx_score) if total_sphinx > 0: full_coverage = False print() print('='*70) if args.no_color: print("TOTAL DOCTEST SCORE for %s: %s%% (%s of %s)" % \ (get_mod_name(file, sympy_top), score, doctests, num_functions)) elif score < 100: print("TOTAL DOCTEST SCORE for %s: %s%s%% (%s of %s)%s" % \ (get_mod_name(file, sympy_top), c_color % (colors["Red"]), score, doctests, num_functions, c_normal)) else: print("TOTAL DOCTEST SCORE for %s: %s%s%% (%s of %s)%s" % \ (get_mod_name(file, sympy_top), c_color % (colors["Green"]), score, doctests, num_functions, c_normal)) if args.sphinx: if args.no_color: print("TOTAL SPHINX SCORE for %s: %s%% (%s of %s)" % \ (get_mod_name(file, sympy_top), sphinx_score, num_functions - total_sphinx, num_functions)) elif sphinx_score < 100: print("TOTAL SPHINX SCORE for %s: %s%s%% (%s of %s)%s" % \ (get_mod_name(file, sympy_top), c_color % (colors["Red"]), sphinx_score, num_functions - total_sphinx, num_functions, c_normal)) else: print("TOTAL SPHINX SCORE for %s: %s%s%% (%s of %s)%s" % \ (get_mod_name(file, sympy_top), c_color % (colors["Green"]), sphinx_score, num_functions - total_sphinx, num_functions, c_normal)) print() sys.exit(not full_coverage) sympy-sympy-1.9/bin/coverage_report.py000077500000000000000000000066521412543434000202470ustar00rootroot00000000000000#!/usr/bin/env python """ Script to generate test coverage reports. Usage: $ bin/coverage_report.py This will create a directory covhtml with the coverage reports. To restrict the analysis to a directory, you just need to pass its name as argument. For example: $ bin/coverage_report.py sympy/logic runs only the tests in sympy/logic/ and reports only on the modules in sympy/logic/. To also run slow tests use --slow option. You can also get a report on the parts of the whole sympy code covered by the tests in sympy/logic/ by following up the previous command with $ bin/coverage_report.py -c """ from __future__ import print_function import os import re import sys from argparse import ArgumentParser minver = '3.4' try: import coverage if coverage.__version__ < minver: raise ImportError except ImportError: print( "You need to install module coverage (version %s or newer required).\n" "See https://coverage.readthedocs.io/en/latest/ or \n" "https://launchpad.net/ubuntu/+source/python-coverage/" % minver) sys.exit(-1) omit_dir_patterns = ['.*tests', 'benchmark', 'examples', 'pyglet', 'test_external'] omit_dir_re = re.compile(r'|'.join(omit_dir_patterns)) source_re = re.compile(r'.*\.py$') def generate_covered_files(top_dir): for dirpath, dirnames, filenames in os.walk(top_dir): omit_dirs = [dirn for dirn in dirnames if omit_dir_re.match(dirn)] for x in omit_dirs: dirnames.remove(x) for filename in filenames: if source_re.match(filename): yield os.path.join(dirpath, filename) def make_report( test_args, source_dir='sympy/', report_dir='covhtml', use_cache=False, slow=False ): # code adapted from /bin/test from get_sympy import path_hack sympy_top = path_hack() os.chdir(sympy_top) cov = coverage.coverage() cov.exclude("raise NotImplementedError") cov.exclude("def canonize") # this should be "@decorated" if use_cache: cov.load() else: cov.erase() cov.start() import sympy sympy.test(*test_args, subprocess=False, slow=slow) #sympy.doctest() # coverage doesn't play well with doctests cov.stop() try: cov.save() except PermissionError: import warnings warnings.warn( "PermissionError has been raised while saving the " \ "coverage result.", RuntimeWarning ) covered_files = list(generate_covered_files(source_dir)) cov.html_report(morfs=covered_files, directory=report_dir) parser = ArgumentParser() parser.add_argument( '-c', '--use-cache', action='store_true', default=False, help='Use cached data.') parser.add_argument( '-d', '--report-dir', default='covhtml', help='Directory to put the generated report in.') parser.add_argument( "--slow", action="store_true", dest="slow", default=False, help="Run slow functions also.") options, args = parser.parse_known_args() if __name__ == '__main__': report_dir = options.report_dir use_cache = options.use_cache slow = options.slow make_report( args, report_dir=report_dir, use_cache=use_cache, slow=slow) print("The generated coverage report is in covhtml directory.") print( "Open %s in your web browser to view the report" % os.sep.join([report_dir, 'index.html']) ) sympy-sympy-1.9/bin/diagnose_imports000077500000000000000000000010621412543434000177660ustar00rootroot00000000000000#!/usr/bin/env python """ Diagnostics for import statements. Run bin/diagnose_imports.py --help for details. """ from os.path import abspath, dirname, join, normpath import subprocess import sys this_file = abspath(__file__) diagnose_imports_filename = join( dirname(this_file), '..', 'sympy', 'utilities', 'tests', 'diagnose_imports.py') diagnose_imports_filename = normpath(diagnose_imports_filename) process = subprocess.Popen( [ sys.executable, diagnose_imports_filename, ] + sys.argv[1:], bufsize = -1) process.wait() sympy-sympy-1.9/bin/doctest000077500000000000000000000056711412543434000160770ustar00rootroot00000000000000#!/usr/bin/env python """ Program to execute doctests using the py.test like interface. The advantage over py.test is that it only depends on sympy and should just work in any circumstances. See "sympy.doctest?" for documentation. """ from __future__ import print_function # files listed here can be in unix forward slash format with paths # listed relative to sympy (which contains bin, etc...) blacklist = [] import sys import os from argparse import ArgumentParser import re from get_sympy import path_hack path_hack() epilog = """ "options" are any of the options above. "files" are 0 or more glob strings of files to run doctests on. If no file arguments are given, all doctests will be run. This program runs both doctests in the source and doctests in the Sphinx documentation (doc/src/ directory). """ parser = ArgumentParser(epilog=epilog) parser.add_argument( "-v", "--verbose", action="store_true", dest="verbose", default=False) parser.add_argument( "-n", "--normal", action="store_true", dest="normal", default=False, help="run normal doctests; do not require explicit imports") parser.add_argument( '-t', '--types', dest='types', action='store', default=None, choices=['gmpy', 'gmpy1', 'python'], help='Setup ground types') parser.add_argument( "--no-colors", action="store_false", dest="colors", default=True, help="Do not report colored [OK] and [FAIL]") parser.add_argument( "--force-colors", action="store_true", dest="force_colors", default=False, help="Always use colors, even if the output is not to a terminal.") parser.add_argument( '-C', '--no-cache', dest='cache', action='store_false', default=True, help='Disable caching mechanism.') parser.add_argument( "--no-subprocess", action="store_false", dest="subprocess", default=True, help="Don't run the tests in a separate subprocess. " "This may prevent hash randomization from being enabled.") parser.add_argument( '--split', action="store", type=str, default=None, help="Only run part of the doctests. Should be of the form a/b, e.g., 1/2") parser.add_argument( '--rerun', action="store", dest="rerun", default=0, help="Number of times to rerun the specified tests", type=int) options, args = parser.parse_known_args() # Check this again here to give a better error message if options.split: sp = re.compile(r'([0-9]+)/([1-9][0-9]*)') if not sp.match(options.split): parser.error("option --split: must be of the form a/b where a and b " "are integers, not %r" % options.split) if not options.cache: os.environ['SYMPY_USE_CACHE'] = 'no' if options.types: os.environ['SYMPY_GROUND_TYPES'] = options.types import sympy ok = sympy.doctest(*args, verbose=options.verbose, blacklist=blacklist, normal=options.normal, subprocess=options.subprocess, split=options.split, rerun=options.rerun, colors=options.colors, force_colors=options.force_colors) if ok: sys.exit(0) else: sys.exit(1) sympy-sympy-1.9/bin/generate_module_list.py000066400000000000000000000031421412543434000212370ustar00rootroot00000000000000""" Execute like this: $ python bin/generate_module_list.py modules = [ 'sympy.assumptions', 'sympy.assumptions.handlers', 'sympy.benchmarks', 'sympy.calculus', 'sympy.categories', 'sympy.codegen', 'sympy.combinatorics', 'sympy.concrete', 'sympy.core', 'sympy.core.benchmarks', 'sympy.crypto', 'sympy.deprecated', 'sympy.diffgeom', 'sympy.external', 'sympy.functions', 'sympy.functions.combinatorial', 'sympy.functions.elementary', 'sympy.functions.elementary.benchmarks', ... ] """ from __future__ import print_function from glob import glob def get_paths(level=15): """ Generates a set of paths for modules searching. Examples ======== >>> get_paths(2) ['sympy/__init__.py', 'sympy/*/__init__.py', 'sympy/*/*/__init__.py'] >>> get_paths(6) ['sympy/__init__.py', 'sympy/*/__init__.py', 'sympy/*/*/__init__.py', 'sympy/*/*/*/__init__.py', 'sympy/*/*/*/*/__init__.py', 'sympy/*/*/*/*/*/__init__.py', 'sympy/*/*/*/*/*/*/__init__.py'] """ wildcards = ["/"] for i in range(level): wildcards.append(wildcards[-1] + "*/") p = ["sympy" + x + "__init__.py" for x in wildcards] return p def generate_module_list(): g = [] for x in get_paths(): g.extend(glob(x)) g = [".".join(x.split("/")[:-1]) for x in g] g = [i for i in g if not i.endswith('.tests')] g.remove('sympy') g = list(set(g)) g.sort() return g if __name__ == '__main__': g = generate_module_list() print("modules = [") for x in g: print(" '%s'," % x) print("]") sympy-sympy-1.9/bin/generate_test_list.py000066400000000000000000000032131412543434000207300ustar00rootroot00000000000000""" Execute like this: $ python bin/generate_test_list.py tests = [ 'sympy.concrete.tests', 'sympy.core.tests', 'sympy.functions.combinatorial.tests', 'sympy.functions.elementary.tests', 'sympy.functions.special.tests', 'sympy.geometry.tests', 'sympy.integrals.tests', 'sympy.matrices.tests', 'sympy.ntheory.tests', 'sympy.numerics.tests', 'sympy.parsing.tests', 'sympy.physics.tests', 'sympy.plotting.tests', 'sympy.polynomials.tests', 'sympy.printing.tests', 'sympy.series.tests', 'sympy.simplify.tests', 'sympy.solvers.tests', 'sympy.specfun.tests', 'sympy.test_external', 'sympy.utilities.tests', ] """ from __future__ import print_function from glob import glob def get_paths(level=15): """ Generates a set of paths for testfiles searching. Examples ======== >>> get_paths(2) ['sympy/test_*.py', 'sympy/*/test_*.py', 'sympy/*/*/test_*.py'] >>> get_paths(6) ['sympy/test_*.py', 'sympy/*/test_*.py', 'sympy/*/*/test_*.py', 'sympy/*/*/*/test_*.py', 'sympy/*/*/*/*/test_*.py', 'sympy/*/*/*/*/*/test_*.py', 'sympy/*/*/*/*/*/*/test_*.py'] """ wildcards = ["/"] for i in range(level): wildcards.append(wildcards[-1] + "*/") p = ["sympy" + x + "test_*.py" for x in wildcards] return p def generate_test_list(): g = [] for x in get_paths(): g.extend(glob(x)) g = [".".join(x.split("/")[:-1]) for x in g] g = list(set(g)) g.sort() return g if __name__ == '__main__': g = generate_test_list() print("tests = [") for x in g: print(" '%s'," % x) print("]") sympy-sympy-1.9/bin/get_sympy.py000066400000000000000000000006361412543434000170720ustar00rootroot00000000000000"""Functions to get the correct sympy version to run tests.""" from __future__ import print_function import os import sys def path_hack(): """ Hack sys.path to import correct (local) sympy. """ this_file = os.path.abspath(__file__) sympy_dir = os.path.join(os.path.dirname(this_file), "..") sympy_dir = os.path.normpath(sympy_dir) sys.path.insert(0, sympy_dir) return sympy_dir sympy-sympy-1.9/bin/isympy000077500000000000000000000007751412543434000157640ustar00rootroot00000000000000#!/usr/bin/env python import os import sys # DO NOT IMPORT SYMPY HERE! Or the setting of the sympy environment variables # by the command line will break. # hook in-tree SymPy into Python path, if possible isympy_path = os.path.abspath(__file__) isympy_dir = os.path.dirname(isympy_path) sympy_top = os.path.split(isympy_dir)[0] sympy_dir = os.path.join(sympy_top, 'sympy') if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) if __name__ == "__main__": from isympy import main main() sympy-sympy-1.9/bin/mailmap_update.py000077500000000000000000000151071412543434000200360ustar00rootroot00000000000000#!/usr/bin/env python """ A tool to help keep .mailmap up-to-date with the current git authors. See also bin/authors_update.py """ import codecs import sys import os if sys.version_info < (3, 6): sys.exit("This script requires Python 3.6 or newer") from subprocess import run, PIPE from sympy.external.importtools import version_tuple from collections import defaultdict, OrderedDict def red(text): return "\033[31m%s\033[0m" % text def yellow(text): return "\033[33m%s\033[0m" % text def blue(text): return "\033[34m%s\033[0m" % text # put sympy on the path mailmap_update_path = os.path.abspath(__file__) mailmap_update_dir = os.path.dirname(mailmap_update_path) sympy_top = os.path.split(mailmap_update_dir)[0] sympy_dir = os.path.join(sympy_top, 'sympy') if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) from sympy.utilities.misc import filldedent from sympy.utilities.iterables import sift # check git version minimal = '1.8.4.2' git_ver = run(['git', '--version'], stdout=PIPE, encoding='utf-8').stdout[12:] if version_tuple(git_ver) < version_tuple(minimal): print(yellow("Please use a git version >= %s" % minimal)) def author_name(line): assert line.count("<") == line.count(">") == 1 assert line.endswith(">") return line.split("<", 1)[0].strip() def author_email(line): assert line.count("<") == line.count(">") == 1 assert line.endswith(">") return line.split("<", 1)[1][:-1].strip() sysexit = 0 print(blue("checking git authors...")) # read git authors git_command = ['git', 'log', '--format=%aN <%aE>'] git_people = sorted(set(run(git_command, stdout=PIPE, encoding='utf-8').stdout.strip().split("\n"))) # check for ambiguous emails dups = defaultdict(list) near_dups = defaultdict(list) for i in git_people: k = i.split('<')[1] dups[k].append(i) near_dups[k.lower()].append((k, i)) multi = [k for k in dups if len(dups[k]) > 1] if multi: print() print(red(filldedent(""" Ambiguous email address error: each address should refer to a single author. Disambiguate the following in .mailmap. Then re-run this script."""))) for k in multi: print() for e in sorted(dups[k]): print('\t%s' % e) sysexit = 1 # warn for nearly ambiguous email addresses dups = near_dups # some may have been real dups, so disregard those # for which all email addresses were the same multi = [k for k in dups if len(dups[k]) > 1 and len(set([i for i, _ in dups[k]])) > 1] if multi: # not fatal but make it red print() print(red(filldedent(""" Ambiguous email address warning: git treats the following as distinct but .mailmap will treat them the same. If these are not all the same person then, when making an entry in .mailmap, be sure to include both commit name and address (not just the address)."""))) for k in multi: print() for _, e in sorted(dups[k]): print('\t%s' % e) sysexit = 1 # warn for ambiguous names dups = defaultdict(list) for i in git_people: dups[author_name(i)].append(i) multi = [k for k in dups if len(dups[k]) > 1] if multi: print() print(yellow(filldedent(""" Ambiguous name warning: if a person uses more than one email address, entries should be added to .mailmap to merge them into a single canonical address. Then re-run this script. """))) for k in multi: print() for e in sorted(dups[k]): print('\t%s' % e) sysexit = 1 bad_names = [] bad_emails = [] for i in git_people: name = author_name(i) email = author_email(i) if '@' in name: bad_names.append(i) elif '@' not in email: bad_emails.append(i) if bad_names: print() print(yellow(filldedent(""" The following people appear to have an email address listed for their name. Entries should be added to .mailmap so that names are formatted like "Name ". """))) for i in bad_names: print("\t%s" % i) sysexit = 1 # TODO: Should we check for bad emails as well? Some people have empty email # addresses. The above check seems to catch people who get the name and email # backwards, so let's leave this alone for now. # if bad_emails: # print() # print(yellow(filldedent(""" # The following names do not appear to have valid # emails. Entries should be added to .mailmap that # use a proper email address. If there is no email # address for a person, use "none@example.com". # """))) # for i in bad_emails: # print("\t%s" % i) print() print(blue("checking .mailmap...")) # put entries in order -- this will help the user # to see if there are already existing entries for an author file = codecs.open(os.path.realpath(os.path.join( __file__, os.path.pardir, os.path.pardir, ".mailmap")), "r", "utf-8").read() blankline = not file or file.endswith('\n') lines = file.splitlines() def key(line): # return lower case first address on line or # raise an error if not an entry if '#' in line: line = line.split('#')[0] L, R = line.count("<"), line.count(">") assert L == R and L in (1, 2) return line.split(">", 1)[0].split("<")[1].lower() who = OrderedDict() for i, line in enumerate(lines): try: who.setdefault(key(line), []).append(line) except AssertionError: who[i] = [line] out = [] for k in who: # put long entries before short since if they match, the # short entries will be ignored. The ORDER MATTERS # so don't re-order the lines for a given address. # Other tidying up could be done but we won't do that here. def short_entry(line): if line.count('<') == 2: if line.split('>', 1)[1].split('<')[0].strip(): return False return True if len(who[k]) == 1: line = who[k][0] if not line.strip(): continue # ignore blank lines out.append(line) else: uniq = list(OrderedDict.fromkeys(who[k])) short, long = sift(uniq, short_entry, binary=True) out.extend(long) out.extend(short) if out != lines or not blankline: # write lines with codecs.open(os.path.realpath(os.path.join( __file__, os.path.pardir, os.path.pardir, ".mailmap")), "w", "utf-8") as fd: fd.write('\n'.join(out)) fd.write('\n') print() if out != lines: print(yellow('.mailmap lines were re-ordered.')) else: print(yellow('blank line added to end of .mailmap')) sysexit = 1 sys.exit(sysexit) sympy-sympy-1.9/bin/py.bench000077500000000000000000000007701412543434000161330ustar00rootroot00000000000000#!/usr/bin/env python # hook in-tree SymPy into Python path, if possible # TODO this should be shared with isympy from __future__ import print_function import os import sys isympy_dir = os.path.dirname(__file__) # bin/isympy sympy_top = os.path.split(isympy_dir)[0] # ../ sympy_dir = os.path.join(sympy_top, 'sympy') # ../sympy/ if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) from sympy.utilities import benchmarking if __name__ == '__main__': benchmarking.main() sympy-sympy-1.9/bin/strip_whitespace000077500000000000000000000057721412543434000200110ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function import os def strip_file(filename, write, report): # .readlines() retains \n chars, while .read().splitlines() does not. # Assuming that whitespace errors will be few, we will thus only need # to re-add \n to a few right-stripped lines. The hit flag will keep us # from unecessarily re-writing files with no changes. # newline="" keeps current line endings with open(filename, newline="") as f: lines = f.readlines() hit = False cr = False extra = 0 for index, line in enumerate(lines): if line.endswith(" \n"): if report: print("%s, line %s" % (filename, index + 1)) if write: lines[index] = line.rstrip() + "\n" hit = True if line.endswith("\r\n"): if report and not cr: print("%s, line %s (crlf now silent)" % (filename, index + 1)) cr = True if write: lines[index] = line.rstrip() + "\n" hit = True # correct no newline at eof if lines and not lines[-1].endswith("\n"): lines[-1] += "\n" if report: print("%s, no newline at eof" % filename) if write: hit = True # correct multiple newlines at eof while len(lines) > 1 and lines[-1] == "\n" and lines[-2].endswith("\n"): if write: hit = True lines.pop() extra += 1 if extra > 0 and report: print("%s, %d extra newlines at eof" % (filename, extra)) if write and hit: # newline="" leaves line endings unchanged with open(filename, "w", newline="") as f: f.writelines(lines) def go(path, write, report): allowed_ext = [ ".cpp", ".cc", ".h", ".py", ".rst", ] for root, dirs, files in os.walk(path): for b in [".git"]: if b in dirs: dirs.remove(b) for file in files: if os.path.splitext(file)[1] not in allowed_ext: continue filename = os.path.join(root, file) strip_file(filename, write, report) def main(): from optparse import OptionParser p = OptionParser("usage: %prog [options] filename") p.add_option("-d", "--dry", action="store_true", dest="dry", help="Do not modify files.") p.add_option("-v", "--verbose", action="store_true", dest="verbose", help="Report all changes.") p.add_option("-r", "--recursive", action="store_true", dest="recursive", help="Recursively correct all files in a directory.") options, args = p.parse_args() if options.dry: options.verbose = True if len(args) == 1: if options.recursive: go(args[0], not options.dry, options.verbose) else: strip_file(args[0], not options.dry, options.verbose) else: p.print_help() if __name__ == "__main__": main() sympy-sympy-1.9/bin/sympy_time.py000066400000000000000000000023761412543434000172540ustar00rootroot00000000000000from __future__ import print_function import time from get_sympy import path_hack path_hack() seen = set() import_order = [] elapsed_times = {} level = 0 parent = None children = {} def new_import(name, globals={}, locals={}, fromlist=[]): global level, parent if name in seen: return old_import(name, globals, locals, fromlist) seen.add(name) import_order.append((name, level, parent)) t1 = time.time() old_parent = parent parent = name level += 1 module = old_import(name, globals, locals, fromlist) level -= 1 parent = old_parent t2 = time.time() elapsed_times[name] = t2 - t1 return module old_import = __builtins__.__import__ __builtins__.__import__ = new_import from sympy import * parents = {} is_parent = {} for name, level, parent in import_order: parents[name] = parent is_parent[parent] = True print("== Tree ==") for name, level, parent in import_order: print("%s%s: %.3f (%s)" % (" "*level, name, elapsed_times.get(name, 0), parent)) print("\n") print("== Slowest (including children) ==") slowest = sorted((t, name) for (name, t) in elapsed_times.items())[-50:] for elapsed_time, name in slowest[::-1]: print("%.3f %s (%s)" % (elapsed_time, name, parents[name])) sympy-sympy-1.9/bin/sympy_time_cache.py000066400000000000000000000061731412543434000203760ustar00rootroot00000000000000from __future__ import print_function import time import timeit class TreeNode(object): def __init__(self, name): self._name = name self._children = [] self._time = 0 def __str__(self): return "%s: %s" % (self._name, self._time) __repr__ = __str__ def add_child(self, node): self._children.append(node) def children(self): return self._children def child(self, i): return self.children()[i] def set_time(self, time): self._time = time def time(self): return self._time total_time = time def exclusive_time(self): return self.total_time() - sum(child.time() for child in self.children()) def name(self): return self._name def linearize(self): res = [self] for child in self.children(): res.extend(child.linearize()) return res def print_tree(self, level=0, max_depth=None): print(" "*level + str(self)) if max_depth is not None and max_depth <= level: return for child in self.children(): child.print_tree(level + 1, max_depth=max_depth) def print_generic(self, n=50, method="time"): slowest = sorted((getattr(node, method)(), node.name()) for node in self.linearize())[-n:] for time, name in slowest[::-1]: print("%s %s" % (time, name)) def print_slowest(self, n=50): self.print_generic(n=50, method="time") def print_slowest_exclusive(self, n=50): self.print_generic(n, method="exclusive_time") def write_cachegrind(self, f): if isinstance(f, str): f = open(f, "w") f.write("events: Microseconds\n") f.write("fl=sympyallimport\n") must_close = True else: must_close = False f.write("fn=%s\n" % self.name()) f.write("1 %s\n" % self.exclusive_time()) counter = 2 for child in self.children(): f.write("cfn=%s\n" % child.name()) f.write("calls=1 1\n") f.write("%s %s\n" % (counter, child.time())) counter += 1 f.write("\n\n") for child in self.children(): child.write_cachegrind(f) if must_close: f.close() pp = TreeNode(None) # We have to use pp since there is a sage function #called parent that gets imported seen = set() def new_import(name, globals={}, locals={}, fromlist=[]): global pp if name in seen: return old_import(name, globals, locals, fromlist) seen.add(name) node = TreeNode(name) pp.add_child(node) old_pp = pp pp = node #Do the actual import t1 = timeit.default_timer() module = old_import(name, globals, locals, fromlist) t2 = timeit.default_timer() node.set_time(int(1000000*(t2 - t1))) pp = old_pp return module old_import = __builtins__.__import__ __builtins__.__import__ = new_import old_sum = sum from sympy import * sum = old_sum sageall = pp.child(0) sageall.write_cachegrind("sympy.cachegrind") print("Timings saved. Do:\n$ kcachegrind sympy.cachegrind") sympy-sympy-1.9/bin/test000077500000000000000000000076271412543434000154140ustar00rootroot00000000000000#!/usr/bin/env python """ Program to execute tests using the py.test like interface. The advantage over py.test is that it only depends on sympy and should just work in any circumstances. See "sympy.test?" for documentation. """ from __future__ import print_function import sys import os from argparse import ArgumentParser, ArgumentDefaultsHelpFormatter import re from get_sympy import path_hack path_hack() epilog = """ "options" are any of the options above. "tests" are 0 or more glob strings of tests to run. If no test arguments are given, all tests will be run. """ parser = ArgumentParser( epilog=epilog, formatter_class=ArgumentDefaultsHelpFormatter) parser.add_argument( "-v", "--verbose", action="store_true", dest="verbose", default=False) parser.add_argument( "--pdb", action="store_true", dest="pdb", default=False, help="Run post mortem pdb on each failure") parser.add_argument( "--no-colors", action="store_false", dest="colors", default=True, help="Do not report colored [OK] and [FAIL]") parser.add_argument( "--force-colors", action="store_true", dest="force_colors", default=False, help="Always use colors, even if the output is not to a terminal.") parser.add_argument( "-k", dest="kw", metavar="KEYWORDS", action="store", nargs='*', help="Only run tests matching the given keyword expressions") parser.add_argument( "--tb", dest="tb", metavar="TBSTYLE", default="short", help="Traceback verboseness (short/no)") parser.add_argument( "--random", action="store_false", dest="sort", default=True, help="Run tests in random order instead of sorting them.") parser.add_argument( "--seed", dest="seed", type=int, metavar="SEED", help="Use this seed for randomized tests.") parser.add_argument( '-t', '--types', dest='types', action='store', default=None, choices=['gmpy', 'gmpy1', 'python'], help='Setup ground types.') parser.add_argument( '-C', '--no-cache', dest='cache', action='store_false', default=True, help='Disable caching mechanism.') parser.add_argument( "--timeout", action="store", dest="timeout", default=False, type=int, help="Set a timeout for the all functions, in seconds. " "By default there is no timeout.") parser.add_argument( "--slow", action="store_true", dest="slow", default=False, help="Run only the slow functions.") parser.add_argument( "--no-subprocess", action="store_false", dest="subprocess", default=True, help="Don't run the tests in a separate subprocess. " "This may prevent hash randomization from being enabled.") parser.add_argument( "-E", "--enhance-asserts", action="store_true", dest="enhance_asserts", default=False, help="Rewrite assert statements to give more useful error messages.") parser.add_argument( '--split', action="store", type=str, default=None, help="Only run part of the tests. Should be of the form a/b, (e.g., 1/2)") parser.add_argument( '--rerun', action="store", dest="rerun", default=0, type=int, help="Number of times to rerun the specified tests.") options, args = parser.parse_known_args() # Check this again here to give a better error message if options.split: sp = re.compile(r'([0-9]+)/([1-9][0-9]*)') if not sp.match(options.split): parser.error("option --split: must be of the form a/b where a and b " "are integers, not %r" % options.split) if not options.cache: os.environ['SYMPY_USE_CACHE'] = 'no' if options.types: os.environ['SYMPY_GROUND_TYPES'] = options.types import sympy ok = sympy.test(*args, verbose=options.verbose, kw=options.kw, tb=options.tb, pdb=options.pdb, colors=options.colors, force_colors=options.force_colors, sort=options.sort, seed=options.seed, slow=options.slow, timeout=options.timeout, subprocess=options.subprocess, enhance_asserts=options.enhance_asserts, split=options.split, rerun=options.rerun) if ok: sys.exit(0) else: sys.exit(1) sympy-sympy-1.9/bin/test_executable.py000077500000000000000000000013501412543434000202270ustar00rootroot00000000000000#!/usr/bin/env python """ Test that only executable files have an executable bit set """ from __future__ import print_function import os import sys from get_sympy import path_hack base_dir = path_hack() def test_executable(path): if not os.path.isdir(path): if os.access(path, os.X_OK): with open(path, 'r') as f: if f.readline()[:2] != "#!": exn_msg = "File at " + path + " either should not be executable or should have a shebang line" raise OSError(exn_msg) else: for file in os.listdir(path): if file in ('.git', 'venv_main'): continue test_executable(os.path.join(path, file)) test_executable(base_dir) sympy-sympy-1.9/bin/test_external_imports.py000077500000000000000000000053331412543434000215120ustar00rootroot00000000000000#!/usr/bin/env python """ Test that from sympy import * doesn't import anything other than SymPy, it's hard dependencies (mpmath), and hard optional dependencies (gmpy2). Importing unnecessary libraries can accidentally add hard dependencies to SymPy in the worst case, or at best slow down the SymPy import time when they are installed. Note, for this test to be effective, every external library that could potentially be imported by SymPy must be installed. TODO: Monkeypatch the importer to detect non-standard library imports even when they aren't installed. Based on code from https://stackoverflow.com/questions/22195382/how-to-check-if-a-module-library-package-is-part-of-the-python-standard-library. """ # These libraries will always be imported with SymPy hard_dependencies = ['mpmath'] # These libraries are optional, but are always imported at SymPy import time # when they are installed. External libraries should only be added to this # list if they are required for core SymPy functionality. hard_optional_dependencies = ['gmpy', 'gmpy2', 'pycosat', 'python-sat'] import sys import os def is_stdlib(p): return ((p.startswith(sys.prefix) or p.startswith(sys.base_prefix)) and 'site-packages' not in p) stdlib = {p for p in sys.path if is_stdlib(p)} existing_modules = list(sys.modules.keys()) # hook in-tree SymPy into Python path, if possible this_path = os.path.abspath(__file__) this_dir = os.path.dirname(this_path) sympy_top = os.path.split(this_dir)[0] sympy_dir = os.path.join(sympy_top, 'sympy') if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) def test_external_imports(): exec("from sympy import *", {}) bad = [] for mod in sys.modules: if '.' in mod and mod.split('.')[0] in sys.modules: # Only worry about the top-level modules continue if mod in existing_modules: continue if any(mod == i or mod.startswith(i + '.') for i in ['sympy'] + hard_dependencies + hard_optional_dependencies): continue if mod in sys.builtin_module_names: continue fname = getattr(sys.modules[mod], "__file__", None) if fname is None: bad.append(mod) continue if fname.endswith(('__init__.py', '__init__.pyc', '__init__.pyo')): fname = os.path.dirname(fname) if os.path.dirname(fname) in stdlib: continue bad.append(mod) if bad: raise RuntimeError("""Unexpected external modules found when running 'from sympy import *': """ + '\n '.join(bad)) print("No unexpected external modules were imported with 'from sympy import *'!") if __name__ == '__main__': test_external_imports() sympy-sympy-1.9/bin/test_import000077500000000000000000000013461412543434000167760ustar00rootroot00000000000000#!/usr/bin/env python """ Tests the speed of "import sympy" by measuring it many times in a row and averaging the values. Usage: $ bin/test_import """ from __future__ import print_function n_tests = 50 from pexpect import run from numpy import mean, std from get_sympy import path_hack def test(): t = run("python bin/test_import.py", cwd=path_hack()) t = float(t) return t tests = [test() for x in range(n_tests + 1)] print("Note: the first run (warm up) was not included in the average + std dev") print("All runs (including warm up):") print(tests) # skip the first run (warm up): tests = tests[1:] print("Number of tests: %d" % (n_tests)) print('The speed of "import sympy" is: %f +- %f' % (mean(tests), std(tests))) sympy-sympy-1.9/bin/test_import.py000066400000000000000000000002571412543434000174220ustar00rootroot00000000000000from __future__ import print_function from timeit import default_timer as clock from get_sympy import path_hack path_hack() t = clock() import sympy t = clock() - t print(t) sympy-sympy-1.9/bin/test_isolated000077500000000000000000000073651412543434000172770ustar00rootroot00000000000000#!/usr/bin/env python """ Generates a bash script, that executes py.test or nosetest on each file individually. Usage and help: $ bin/test_isolated -h and read the instructions. """ from __future__ import print_function from os import chmod, getcwd from glob import glob from optparse import OptionParser from stat import S_IREAD, S_IWRITE, S_IXUSR, S_IRGRP, S_IROTH, S_IXGRP, S_IXOTH filemode = S_IREAD | S_IWRITE | S_IXUSR | S_IRGRP | S_IROTH | S_IXGRP | S_IXOTH def get_paths(level=6): """ Generates a set of paths for testfiles searching. Example: >>> get_paths(2) ['sympy/test_*.py', 'sympy/*/test_*.py', 'sympy/*/*/test_*.py'] >>> get_paths(6) ['sympy/test_*.py', 'sympy/*/test_*.py', 'sympy/*/*/test_*.py', 'sympy/*/*/*/test_*.py', 'sympy/*/*/*/*/test_*.py', 'sympy/*/*/*/*/*/test_*.py', 'sympy/*/*/*/*/*/*/test_*.py'] """ wildcards = ["/"] for i in range(level): wildcards.append(wildcards[-1] + "*/") my_dir = getcwd() p = [my_dir + "/sympy" + x + "test_*.py" for x in wildcards] return p def generate_test_script1(testlib="py.test"): """Generates a bash script for doing the test. "testlib" is the name of the executable, that is going to execute the test, for example "py.test" or "nosetests". """ g = [] for x in get_paths(10): g.extend(glob(x)) with open("/tmp/test_sympy.sh", "w") as f: f.write("#! /bin/sh\n") f.write("# Autogenerated script for a reliable test of SymPy.\n") f.write("# Execute with 'sh test_sympy.sh' (in any directory).\n\n") for x in g: f.write(testlib + " " + x + "\n") chmod(f.name, filemode) def generate_test_script2(testlib="nosetests"): """Generates a bash script for doing the test. "testlib" is the name of the executable, that is going to execute the test, for example "py.test" or "nosetests". """ g = [] for x in get_paths(10): g.extend(glob(x)) with open("/tmp/test_sympy.sh", "w") as f: f.write("#! /bin/sh\n") f.write("# Autogenerated script for a reliable test of SymPy.\n") f.write("# Execute with 'sh test_sympy.sh' (in any directory).\n\n") for x in g: f.write(testlib + " " + x + " && \\\n") f.write("echo 'all tests passed, ok to commit'") chmod(f.name, filemode) usage = """%prog [options] Generates a bash script, that executes py.test or nosetest on each file individually. Usage: $ bin/test_isolated Generating py.test isolated testsuite... Done. Run (search for 'COMMIT' in the less environment): /tmp/test_sympy.sh | less $ /tmp/test_sympy.sh | less Let the tests run and then search if any test failed (it will write DO NOT COMMIT), so search for COMMIT.""" def main(): parser = OptionParser(usage=usage) parser.add_option("-p", "--py.test", action="store_false", dest="nosetests", help="Use py.test (default)") parser.add_option("-n", "--nosetests", action="store_true", dest="nosetests", help="Use nosetests") parser.add_option("-q", "--quiet", action="store_false", dest="verbose") parser.set_defaults(nosetests=False, verbose=True) options, args = parser.parse_args() if len(args) != 0: parser.error("too many arguments") if options.nosetests: if options.verbose: print("Generating nosetests isolated testsuite...") generate_test_script2("nosetests") else: if options.verbose: print("Generating py.test isolated testsuite...") generate_test_script1("py.test") if options.verbose: print("Done. Run (search for 'COMMIT' in the less environment):") print("/tmp/test_sympy.sh | less") if __name__ == "__main__": main() sympy-sympy-1.9/bin/test_optional_dependencies.py000077500000000000000000000044051412543434000224450ustar00rootroot00000000000000#!/usr/bin/env python """ Run tests for specific packages that use optional dependencies. The optional dependencies need to be installed before running this. """ # Add the local sympy to sys.path (needed for CI) from get_sympy import path_hack path_hack() class TestsFailedError(Exception): pass print('Testing optional dependencies') import sympy test_list = [ # numpy '*numpy*', 'sympy/core/', 'sympy/matrices/', 'sympy/physics/quantum/', 'sympy/utilities/tests/test_lambdify.py', # scipy '*scipy*', # llvmlite '*llvm*', # aesara '*aesara*', # gmpy 'polys', # autowrap '*autowrap*', # ipython '*ipython*', # antlr, lfortran, clang 'sympy/parsing/', # matchpy '*rubi*', # codegen 'sympy/codegen/', 'sympy/utilities/tests/test_codegen', 'sympy/utilities/_compilation/tests/test_compilation', # cloudpickle 'pickling', # pycosat 'sympy/logic', 'sympy/assumptions', #stats 'sympy/stats', ] blacklist = [ 'sympy/physics/quantum/tests/test_circuitplot.py', ] doctest_list = [ # numpy 'sympy/matrices/', 'sympy/utilities/lambdify.py', # scipy '*scipy*', # llvmlite '*llvm*', # aesara '*aesara*', # gmpy 'polys', # autowrap '*autowrap*', # ipython '*ipython*', # antlr, lfortran, clang 'sympy/parsing/', # matchpy '*rubi*', # codegen 'sympy/codegen/', # pycosat 'sympy/logic', 'sympy/assumptions', #stats 'sympy/stats', ] if not (sympy.test(*test_list, verbose=True, blacklist=blacklist) and sympy.doctest(*doctest_list)): raise TestsFailedError('Tests failed') print('Testing MATPLOTLIB') # Set matplotlib so that it works correctly in headless Travis. We have to do # this here because it doesn't work after the sympy plotting module is # imported. import matplotlib matplotlib.use("Agg") import sympy # Unfortunately, we have to use subprocess=False so that the above will be # applied, so no hash randomization here. if not (sympy.test('sympy/plotting', 'sympy/physics/quantum/tests/test_circuitplot.py', subprocess=False) and sympy.doctest('sympy/plotting', subprocess=False)): raise TestsFailedError('Tests failed') sympy-sympy-1.9/bin/test_py2_import.py000077500000000000000000000014611412543434000202150ustar00rootroot00000000000000#!/usr/bin/env python # # Tests that a useful message is give in the ImportError when trying to import # sympy from Python 2. This is tested on Travis to ensure that we don't get a # Py2 SyntaxError from sympy/__init__.py import sys assert sys.version_info[:2] == (2, 7), "This test is for Python 2.7 only" import os thisdir = os.path.dirname(__file__) parentdir = os.path.normpath(os.path.join(thisdir, '..')) # Append the SymPy root directory to path sys.path.append(parentdir) try: import sympy except ImportError as exc: message = str(exc) # e.g. "Python version 3.5 or above is required for SymPy." assert message.startswith("Python version") assert message.endswith(" or above is required for SymPy.") else: raise AssertionError("import sympy should give ImportError on Python 2.7") sympy-sympy-1.9/bin/test_setup.py000077500000000000000000000013071412543434000172500ustar00rootroot00000000000000#!/usr/bin/env python """ Test that the installed modules in setup.py are up-to-date. If this test fails, run python bin/generate_test_list.py and python bin/generate_module_list.py to generate the up-to-date test and modules list to put in setup.py. """ import generate_test_list import generate_module_list from get_sympy import path_hack path_hack() import setup module_list = generate_module_list.generate_module_list() test_list = generate_test_list.generate_test_list() assert setup.modules == module_list, set(setup.modules).symmetric_difference(set(module_list)) assert setup.tests == test_list, set(setup.tests).symmetric_difference(set(test_list)) print("setup.py modules and tests are OK") sympy-sympy-1.9/bin/test_sphinx.sh000077500000000000000000000005241412543434000174030ustar00rootroot00000000000000#! /usr/bin/env bash set -o errexit echo "Testing SPHINX" cd doc make html make man make latex cd _build/latex export LATEXMKOPTS="-halt-on-error -xelatex -silent" make all || { echo "An error had occured during the LaTeX build"; tail -n 1000 *.log; sleep 1; # A guard against travis running tail concurrently. exit -1; } sympy-sympy-1.9/bin/test_submodule_imports.py000077500000000000000000000041721412543434000216670ustar00rootroot00000000000000#!/usr/bin/env python """ Test that from sympy import * only imports those sympy submodules that have names that are part of the top-level namespace. """ import sys import os # hook in-tree SymPy into Python path, if possible this_path = os.path.abspath(__file__) this_dir = os.path.dirname(this_path) sympy_top = os.path.split(this_dir)[0] sympy_dir = os.path.join(sympy_top, 'sympy') if os.path.isdir(sympy_dir): sys.path.insert(0, sympy_top) submodule_whitelist = [ 'algebras', 'assumptions', 'calculus', 'concrete', 'core', 'deprecated', 'discrete', 'external', 'functions', 'geometry', 'integrals', 'interactive', 'logic', 'matrices', 'multipledispatch', 'ntheory', 'parsing', 'plotting', 'polys', 'printing', 'release', 'series', 'sets', 'simplify', 'solvers', 'strategies', 'tensor', 'testing', 'utilities', ] def test_submodule_imports(): if 'sympy' in sys.modules: raise RuntimeError("SymPy has already been imported, the test_submodule_imports test cannot run") exec("from sympy import *", {}) for mod in sys.modules: if not mod.startswith('sympy'): continue if not mod.count('.') == 1: continue _, submodule = mod.split('.') if submodule not in submodule_whitelist: sys.exit(f"""\ Error: The submodule {mod} was imported with 'from sympy import *', but it was not expected to be. If {mod} is a new module that has functions that are imported at the top-level, then the whitelist in bin/test_submodule_imports should be updated. If it is not, the place that imports it should be modified so that it does not get imported at the top-level, e.g., by moving the 'import {mod}' import inside the function that uses it. If you are unsure which code is importing {mod}, it may help to add 'raise Exception' to sympy/{submodule}/__init__.py and observe the traceback from running 'from sympy import *'.""") print("No unexpected submodules were imported with 'from sympy import *'") if __name__ == '__main__': test_submodule_imports() sympy-sympy-1.9/bin/test_symengine.py000077500000000000000000000015201412543434000201030ustar00rootroot00000000000000#!/usr/bin/env python """ Run tests involving symengine These are separate from the other optional dependency tests because they need to be run with the USE_SYMENGINE=1 environment variable set. This script does not set the environment variable by default so that the same tests can be run with and without symengine. Run this as: $ USE_SYMENGINE=1 bin/test_symengine.py """ # Add the local sympy to sys.path (needed for CI) from get_sympy import path_hack path_hack() class TestsFailedError(Exception): pass test_list = [ 'sympy/physics/mechanics', 'sympy/liealgebras', ] print('Testing optional dependencies') # # XXX: The doctests are not tested here but there are many failures when # running them with symengine. # import sympy if not sympy.test(*test_list, verbose=True): raise TestsFailedError('Tests failed') sympy-sympy-1.9/bin/test_tensorflow.py000077500000000000000000000013061412543434000203110ustar00rootroot00000000000000#!/usr/bin/env python """ Run tests involving tensorflow These are separate from the other optional dependency tests because tensorflow pins the numpy version. """ # Add the local sympy to sys.path (needed for CI) from get_sympy import path_hack path_hack() class TestsFailedError(Exception): pass test_list = doctest_list = [ 'sympy/printing/tensorflow.py', 'sympy/printing/tests/test_tensorflow.py', 'sympy/stats/sampling', 'sympy/utilities/lambdify.py', 'sympy/utilities/tests/test_lambdify.py', ] print('Testing optional dependencies') import sympy if not (sympy.test(*test_list, verbose=True) and sympy.doctest(*doctest_list)): raise TestsFailedError('Tests failed') sympy-sympy-1.9/bin/test_travis.sh000077500000000000000000000137561412543434000174150ustar00rootroot00000000000000#! /usr/bin/env bash # Exit on error set -e # Echo each command set -x if [[ "${TEST_FLAKE8}" == "true" ]]; then flake8 sympy; fi if [[ "${TEST_SETUP}" == "true" ]]; then python bin/test_setup.py fi if [[ "${TEST_PY2_IMPORT}" == "true" ]]; then python bin/test_py2_import.py fi if [[ "${TEST_SPHINX}" == "true" ]]; then echo "Testing SPHINX" cd doc make html make man make latex cd _build/latex export LATEXMKOPTS="-halt-on-error -xelatex -silent" make all || { echo "An error had occured during the LaTeX build"; tail -n 1000 *.log; sleep 1; # A guard against travis running tail concurrently. exit -1; } fi if [[ -n "${TEST_OPT_DEPENDENCY}" ]]; then python bin/test_external_imports.py python bin/test_submodule_imports.py python bin/test_executable.py fi # We change directories to make sure that we test the installed version of # sympy. mkdir empty cd empty if [[ "${TEST_COVERAGE}" == "true" ]]; then rm -f $TRAVIS_BUILD_DIR/.coverage.* $TRAVIS_BUILD_DIR/.coverage cat << EOF | python import distutils.sysconfig import os with open(os.path.join(distutils.sysconfig.get_python_lib(), 'coverage.pth'), 'w') as pth: pth.write('import sys; exec(%r)\n' % '''\ try: import coverage except ImportError: pass else: coverage.process_startup() ''') EOF export COVERAGE_PROCESS_START=$TRAVIS_BUILD_DIR/coveragerc_travis fi if [[ "${TEST_ASCII}" == "true" ]]; then # Force Python to act like pre-3.7 where LC_ALL=C causes # UnicodeEncodeErrors. Once the lowest Python version we support is 3.7, # we can consider dropping this test entirely. See PEP 538. export PYTHONIOENCODING=ascii:strict cat <' where is one of" @echo " changes to make an overview over all changed/added/deprecated items" @echo " cheatsheet to make the Cheatsheet" @echo " clean to remove generated files" @echo " html to make standalone HTML files" @echo " htmlapi to make HTML API docs" @echo " htmlhelp to make HTML files and a HTML help project" @echo " info to make Texinfo files and run them through makeinfo" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " linkcheck to check all external links for integrity" @echo " livehtml to use livereload to view the built html" @echo " texinfo to make Texinfo files" @echo " web to make files usable by Sphinx.web" @echo " logo generate logos from src/logo/sympy.svg" @echo " man build manpage" clean: -rm -rf _build -rm -rf sphinx -rm -f $(PDFFILES) html: SPHINXOPTS += -W --keep-going html: _build/logo/sympy-notailtext-favicon.ico mkdir -p src/.static mkdir -p _build/html mkdir -p _build/doctrees mkdir -p src/modules $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) _build/html cp -r src/pics _build/html/ @echo @echo "Build finished. The HTML pages are in _build/html." htmlapi: mkdir -p api/.static mkdir -p api/modules mkdir -p _build/api _build/doctreesapi rm -f api/modules/sympy*.rst $(SPHINXBUILD) -b html $(ALLSPHINXOPTSapi) _build/api @echo @echo "Build finished. The API docs pages are in _build/api." web: mkdir -p _build/web _build/doctrees $(SPHINXBUILD) -b web $(ALLSPHINXOPTS) _build/web @echo @echo "Build finished; now you can run" @echo " python -m sphinx.web _build/web" @echo "to start the server." htmlhelp: mkdir -p _build/htmlhelp _build/doctrees $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) _build/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in _build/htmlhelp." latex: $(PDFFILES) mkdir -p _build/latex _build/doctrees $(SPHINXBUILD) -b latex $(ALLSPHINXOPTSlatex) _build/latex @echo @echo "Build finished; the LaTeX files are in _build/latex." @echo "Set the environment variable LATEXMKOPTS='-xelatex -silent'" @echo "And run \`make all' in that directory to run these through xelatex." .svg.pdf: inkscape --file=$< --export-area-drawing --without-gui --export-pdf=$@ changes: mkdir -p _build/changes _build/doctrees $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) _build/changes @echo @echo "The overview file is in _build/changes." linkcheck: mkdir -p _build/linkcheck _build/doctrees $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) _build/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in _build/linkcheck/output.txt." livehtml: livereload _build/html cheatsheet: _build/cheatsheet/cheatsheet.pdf _build/cheatsheet/combinatoric_cheatsheet.pdf _build/cheatsheet/cheatsheet.pdf: cheatsheet/cheatsheet.tex mkdir -p _build/cheatsheet pdflatex -output-directory=_build/cheatsheet cheatsheet/cheatsheet.tex pdflatex -output-directory=_build/cheatsheet cheatsheet/cheatsheet.tex _build/cheatsheet/combinatoric_cheatsheet.pdf: cheatsheet/combinatoric_cheatsheet.tex mkdir -p _build/cheatsheet pdflatex -output-directory=_build/cheatsheet cheatsheet/combinatoric_cheatsheet.tex pdflatex -output-directory=_build/cheatsheet cheatsheet/combinatoric_cheatsheet.tex texinfo: mkdir -p _build/texinfo $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) _build/texinfo @echo @echo "Build finished. The Texinfo files are in _build/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: mkdir -p _build/texinfo $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) _build/texinfo @echo "Running Texinfo files through makeinfo..." make -C _build/texinfo info @echo "makeinfo finished; the Info files are in _build/texinfo." man: man/isympy.xml docbook2x-man --to-stdout $< > man/isympy.1 _build/logo/sympy-notailtext-favicon.ico: logo logo: src/logo/sympy.svg rm -rf _build/logo mkdir -p _build/logo $(PYTHON) ./generate_logos.py -d @echo @echo "Logo generated." sympy-sympy-1.9/doc/README.rst000066400000000000000000000005041412543434000161560ustar00rootroot00000000000000For instructions on installation, building the documentation, and guidelines for contributing to SymPy's documentation, please read the `SymPy Documentation Style Guide `_. The SymPy Documentation Style Guide can also be read at src/documentation-style-guide.rst. sympy-sympy-1.9/doc/api/000077500000000000000000000000001412543434000152415ustar00rootroot00000000000000sympy-sympy-1.9/doc/api/conf.py000066400000000000000000000100561412543434000165420ustar00rootroot00000000000000# # SymPy documentation build configuration file, created by # sphinx-quickstart.py on Sat Mar 22 19:34:32 2008. # # This file is execfile()d with the current directory set to its containing dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. import sys import sympy # If your extensions are in another directory, add it here. #sys.path.append('some/directory') # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.addons.*') or your custom ones. extensions = ['sphinx.ext.autodoc'] # Add any paths that contain templates here, relative to this directory. templates_path = ['.templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' # General substitutions. project = 'SymPy' copyright = '2015, SymPy Development Team' # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. version = sympy.__version__ # The full version, including alpha/beta/rc tags. release = version # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = 'default.css' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['.static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Content template for the index page. #html_index = '' # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True # If true, the reST sources are included in the HTML build as _sources/. #html_copy_source = True # Output file base name for HTML help builder. htmlhelp_basename = 'SymPydoc' # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual]). latex_documents = [('index', 'sympy.tex', 'SymPy Documentation', 'SymPy Development Team', 'manual')] # Additional stuff for the LaTeX preamble. #latex_preamble = '' # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_use_modindex = True sympy-sympy-1.9/doc/api/index.rst000066400000000000000000000004671412543434000171110ustar00rootroot00000000000000Welcome to SymPy API reference ============================== This is an automatically generated API documentation from SymPy sources. Click the "modules" (:ref:`modindex`) link in the top right corner to browse the modules. Or click the "index" to see an index of all SymPy functions, methods and classes. sympy-sympy-1.9/doc/apidoc.conf000066400000000000000000000003521412543434000165760ustar00rootroot00000000000000[epydoc] name : SymPy url: https://code.google.com/p/sympy modules : sympy, sympy.core, sympy.modules output : html target : ../api/ dotpath : /usr/bin/dot parse: yes introspect: yes private : no frames: no docformat : epytext sympy-sympy-1.9/doc/cheatsheet/000077500000000000000000000000001412543434000166055ustar00rootroot00000000000000sympy-sympy-1.9/doc/cheatsheet/cheatsheet.tex000066400000000000000000000211301412543434000214410ustar00rootroot00000000000000\documentclass{article} \usepackage[landscape]{geometry} \usepackage{url} \usepackage{multicol} \usepackage{amsmath} \usepackage{amsfonts} \advance\topmargin-.8in \advance\textheight2in \advance\textwidth3in \advance\oddsidemargin-1.5in \advance\evensidemargin-1.5in \parindent0pt \parskip2pt \newcommand{\hr}{\centerline{\rule{3.5in}{1pt}}} \usepackage{tikz} \usetikzlibrary{shapes,snakes} \usepackage{amsmath,amssymb} \begin{document} \begin{center}\huge{\textbf{SymPy Cheatsheet (https://sympy.org)}}\end{center} \begin{multicols*}{3} \tikzstyle{mybox} = [draw=black, fill=white, very thick, rectangle, rounded corners, inner sep=10pt, inner ysep=10pt] \tikzstyle{fancytitle} =[fill=black, text=white, font=\bfseries] \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} %Sympy packages:& \verb|from sympy import some_package |\\ Sympy help: & \verb|help(function)|\\ Declare symbol:& \verb|x = Symbol('x')|\\ Substitution:& \verb|expr.subs(old, new)|\\ Numerical evaluation:& \verb|expr.evalf()|\\ Expanding:& \verb|expr.expand()|\\ Common denominator:& \verb|ratsimp(expr)|\\ Simplify expression:&\verb|simplify(expr)|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Basics}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.075\textwidth} \begin{center}\small{\begin{tabular}{l r} $\pi$: &\verb|pi|\\ $e$: &\verb|E|\\ $\infty$:&\verb|oo|\\ $i$:&\verb|I| \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Constants}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.195\textwidth} \begin{center}\small{\begin{tabular}{l r} Integers ($\mathbb{Z}$): &\verb|Integer(x)|\\ Rationals ($\mathbb{Q}$): &\verb|Rational(p, q)|\\ Reals ($\mathbb{R}$): &\verb|Float(x)|\\ \\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Numbers types}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} Trigonometric: &\verb|sin cos tan cot|\\ Cyclometric: &\verb|asin acos atan acot|\\ Hyperbolic: &\verb|sinh cosh tanh coth|\\ Area hyperbolic: &\verb|asinh acosh atanh acoth|\\ Exponential: &\verb|exp(x)|\\ Square root: &\verb|sqrt(x)|\\ Logarithm ($\log_ba$): &\verb|log(a, b)|\\ Natural logarithm: &\verb|log(a)|\\ Gamma ($\Gamma(x)$): &\verb|gamma(x)|\\ Absolute value: &\verb|abs(x)|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Basic functions}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} $\displaystyle\lim_{x\to a} f(x)$: &\verb|limit(f, x, a)|\\ $\displaystyle\lim_{x\to a_-} f(x)$: &\verb|limit(f, x, a, dir='-')|\\ $\displaystyle\lim_{x\to a_+} f(x)$: &\verb|limit(f, x, a, dir='+')|\\ $\frac{d}{dx}f(x)$: &\verb|diff(f, x)|\\ $\frac{\partial}{\partial x} f(x,y)$: &\verb|diff(f, x)|\\ $\int f(x) \, dx:$& \verb|integrate(f, x)|\\ $\int_a^b f(x) \, dx:$& \verb|integrate(f, (x, a, b))|\\ Taylor series (at $a$, deg $n$)& \verb|f.series(x, a, n)|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Calculus}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} Equation $f(x)=0$: &\verb|solve(f, x)|\\ System of equations: &\verb|solve([f, g], [x, y])|\\ Differential equation: &\verb|dsolve(equation, f(x))|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Equations}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} Points: & \verb|a = Point(xcoord, ycoord)|\\ Lines: &\verb|l = Line(pointA, pointB)|\\ Circles: &\verb|c = Circle(center, radius)|\\ Triangles: &\verb|t = Triangle(a, b, c)|\\ Area: &\verb|object.area|\\ Intersection: &\verb|intersection(a, b)|\\ Checking tangency: &\verb|c.is_tangent(l)|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Geometry}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} Plot: &\verb|Plot(f, [a, b])|\\ Zoom: $+/-$: &\verb|R/F or PgUp/PgDn or Numpad +/-|\\ Rotate X,Y axis: &\verb|Arrow Keys or WASD|\\ Rotate Z axis: &\verb| Q and E or Numpad 7 and 9|\\ View XY: &\verb|F1|\\ View XZ: &\verb|F2|\\ View YZ: &\verb|F3|\\ View Perspective: &\verb|F4|\\ Axes Visibility: &\verb|F5|\\ Axes Colors: &\verb|F6|\\ Screenshot: &\verb|F8|\\ Exit plot: &\verb|ESC|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Plotting}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} Factorial ($n!$): &\verb|factorial(n)|\\ Binomial coefficient $n\choose k$: &\verb|binomial(n, k)|\\ Sum ($\sum_{n=a}^b expr$): &\verb|summation(expr, (n, a, b))|\\ Product ($\prod_{n=a}^b expr$): &\verb|product(expr, (n, a, b))|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Discrete math}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} Matrix definition: &\verb|m = Matrix([[a, b], [c, d]])|\\ Determinant: &\verb|m.det()|\\ Inverse: &\verb|m.inv()|\\ Identity matrix $n\times n$: &\verb|eye(n)|\\ Zero matrix $n\times n$: &\verb|zeros(n)|\\ Ones matrix $n\times n$: &\verb|ones(n)|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Linear algebra}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \begin{center}\small{\begin{tabular}{l r} \LaTeX{} print: &\verb|print latex()|\\ Python print: &\verb|print python()|\\ Pretty print: &\verb|pprint()|\\ \end{tabular}}\end{center} \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Printing}; \end{tikzpicture} \begin{tikzpicture} \node [mybox] (box){% \begin{minipage}{0.3\textwidth} \small{ Find 100 digits of $\pi^e$:\\ \verb|(pi**E).n(100)|\\ \\ Expand $(x+y)^2(x-y)(x^2+y)$:\\ \verb|((x + y)**2 * (x - y) * (x**2 + y)).expand()|\\ \\ Simplify $\displaystyle\frac{1}{x} + \frac{x\sin x -1}{x^2-1}$:\\ \verb|simplify((1/x) + (x * sin(x) - 1)/(x**2 - 1))|\\ \\ Check if line passing through points $(0,1)$ and $(1,1)$\\ is tangent to circle with center at $(5,5)$ and radius $3$:\\ \verb|Circle(Point(5,5), 3).is_tangent(|\\\verb|Line(Point(0,1), Point(1,1)))|\\ \\ Find roots of $x^4-4x^3+2x^2-x=0$:\\ \verb|solve(x**4 - 4*x**3 + 2*x**2 - x, x)|\\ \\ Solve the equations system: $x+y=4$, $xy=3$:\\ \verb|solve([x + y - 4, x*y - 3], [x, y])|\\ \\ Calculate limit of the sequence $\sqrt[n]{n}$:\\ \verb|limit(n**(1/n), n, oo)|\\ \\ Calculate left-sided limit of the function $\frac{|x|}{x}$ in 0:\\ \verb|limit(abs(x)/x, x, 0, dir='-')|\\ \\ Calculate the sum $\sum_{n=0}^{100} n^2$:\\ \verb|summation(n**2, (n, 0, 100))|\\ \\ Calculate the sum $\sum_{n=0}^{\infty} \frac{1}{n^2}$:\\ \verb|summation(1/n**2, (n, 0, oo))|\\ \\ Calculate the integral $\int \cos^3 x \, dx$:\\ \verb|integrate(cos(x)**3, x)|\\ \\ Calculate the integral $\int_1^{\infty} \frac{dx}{x^2}$:\\ \verb|integrate(1/x**2, (x, 1, oo))|\\ \\ Find 10 terms of series expansion of $\frac{1}{1-2x}$ at $0$:\\ \verb|(1/(1 - 2*x)).series(x, 0, 10)|\\ \\ Solve the differential equation $f^{''}(x)+9f(x)=1$:\\ \verb|dsolve(f(x).diff(x, x) + 9*f(x) - 1, f(x))|\\ } \end{minipage} }; \node[fancytitle, right=10pt] at (box.north west) {Examples}; \end{tikzpicture} %\begin{tikzpicture} %\node [mybox] (box){% % \begin{minipage}{0.3\textwidth} % \begin{center}\small{\begin{tabular}{l r} % % \end{tabular}}\end{center} % \end{minipage} %}; %\node[fancytitle, right=10pt] at (box.north west) {Numbers types}; %\end{tikzpicture} %\begin{tikzpicture} %\node [mybox] (box){% % \begin{minipage}{0.3\textwidth} % \begin{center}\small{\begin{tabular}{l r} % % \end{tabular}}\end{center} % \end{minipage} %}; %\node[fancytitle, right=10pt] at (box.north west) {Numbers types}; %\end{tikzpicture} \end{multicols*} \end{document} sympy-sympy-1.9/doc/cheatsheet/combinatoric_cheatsheet.tex000066400000000000000000000560221412543434000242020ustar00rootroot00000000000000\documentclass[10pt,landscape]{article} \usepackage{multicol} \usepackage{calc} \usepackage{ifthen} \usepackage[landscape]{geometry} % To make this come out properly in landscape mode, do one of the following % 1. % pdflatex latexsheet.tex % % 2. % latex latexsheet.tex % dvips -P pdf -t landscape latexsheet.dvi % ps2pdf latexsheet.ps % If you're reading this, be prepared for confusion. Making this was % a learning experience for me, and it shows. Much of the placement % was hacked in; if you make it better, let me know... % 2008-04 % Changed page margin code to use the geometry package. Also added code for % conditional page margins, depending on paper size. Thanks to Uwe Ziegenhagen % for the suggestions. % 2006-08 % Made changes based on suggestions from Gene Cooperman. % To Do: % \listoffigures \listoftables % \setcounter{secnumdepth}{0} % This sets page margins to .5 inch if using letter paper, and to 1cm % if using A4 paper. (This probably isn't strictly necessary.) % If using another size paper, use default 1cm margins. \ifthenelse{\lengthtest { \paperwidth = 11in}} { \geometry{top=.5in,left=.5in,right=.5in,bottom=.5in} } {\ifthenelse{ \lengthtest{ \paperwidth = 297mm}} {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} } {\geometry{top=1cm,left=1cm,right=1cm,bottom=1cm} } } % Turn off header and footer \pagestyle{empty} % Redefine section commands to use less space \makeatletter \renewcommand{\section}{\@startsection{section}{1}{0mm}% {-1ex plus -.5ex minus -.2ex}% {0.5ex plus .2ex}%x {\normalfont\large\bfseries}} \renewcommand{\subsection}{\@startsection{subsection}{2}{0mm}% {-1explus -.5ex minus -.2ex}% {0.5ex plus .2ex}% {\normalfont\normalsize\bfseries}} \renewcommand{\subsubsection}{\@startsection{subsubsection}{3}{0mm}% {-1ex plus -.5ex minus -.2ex}% {1ex plus .2ex}% {\normalfont\small\bfseries}} \makeatother % Define BibTeX command \def\BibTeX{{\rm B\kern-.05em{\sc i\kern-.025em b}\kern-.08em T\kern-.1667em\lower.7ex\hbox{E}\kern-.125emX}} % Don't print section numbers \setcounter{secnumdepth}{0} \setlength{\parindent}{0pt} \setlength{\parskip}{0pt plus 0.5ex} % ----------------------------------------------------------------------- \newcommand{\tab}{\hspace*{2em}} \begin{document} \raggedright \footnotesize \begin{multicols}{3} % multicol parameters % These lengths are set only within the two main columns %\setlength{\columnseprule}{0.25pt} \setlength{\premulticols}{1pt} \setlength{\postmulticols}{1pt} \setlength{\multicolsep}{1pt} \setlength{\columnsep}{2pt} \begin{center} \Large{\textbf{Combinatoric CheatSheet \\ Sympy.org}} \\ \end{center} \section{Partition} \verb!Path: from sympy.combinatorics.partitions!\\ \subsection{Methods} \verb!random_integer_partition(n, seed=None)! \\ Generates a random integer partition summing to n as a list of reverse-sorted integers \verb!RGS_generalized(m)! \\ Computes the \verb!m + 1! generalized unrestricted growth strings and returns them as rows in matrix \verb!RGS_enum(m)! \\ computes the total number of restricted growth strings possible for a superset of size \verb!m! \verb!RGS_unrank(rank, m)! \\ Gives the unranked restricted growth string for a given superset size \verb!RGS_rank(rgs)! \\ Computes the rank of a restricted growth string. \subsection{Subclass \texttt{Partition}} A partition is a set of disjoint sets whose union equals a given set. This Class represent abstract partition. \begin{tabular}{@{}lp{4.5cm}l@{}} \verb!rgs! & Restricted Growth String\\ \verb!from_rgs(rgs,elements)! & Creates a set partition from a RSG\\ \verb!rank! & Gets the rank of a partition \\ \verb!partition! & Return partition as a sorted list of lists\\ \verb!sort_key(order=None)! & Return a canonical key that can be used for sorting. \end{tabular} %dump : \\ %Used at the very beginning of a document: %\verb!\documentclass{!\textit{class}\verb!}!. Use %\verb!\begin{document}! to start contents and \verb!\end{document}! to %end the document. %\\end dump. \subsection{Subclass \texttt{IntegerPartition}} This class represents an integer partition. \newlength{\MyLen} \settowidth{\MyLen}{\texttt{letterpaper}/\texttt{a4paper} \ } \begin{tabular}{@{}p{\the\MyLen}% @{}p{\linewidth-\the\MyLen}@{}} \verb!as_dict()! & Return the partition as a dictionary whose keys are the partition integers and the values are the multiplicity of that integer \\ \verb!as_ferrers(char='#')! & Prints the ferrer diagram of a partition\\ \verb!conjugate! &Computes the conjugate partition of itself\\ \verb!next_lex()! & Return the next partition of the integer, n, in lexical order\\ \verb!prev_lex()! & Return the previous partition of the integer, n, in lexical order\\ \end{tabular} \section{Permutation} Path \verb!sympy.combinatorics.permutations.Permutation!\\ \subsection{Methods} \verb!array_form! \\ This is used to convert from cyclic notation to the canonical notation \verb!ascents()!\\ Returns the positions of ascents in a permutation, i.e., the location where $p[i] < p[i+1]$ \verb!descents()! Returns the positions of descents in a permutation, i.e., the location where $p[i] > p[i+1]$ \verb!atoms()!\\ Returns all the elements of a permutation \verb!cardinality!\\ Returns the number of all possible permutations. \verb!commutator(x)!\\ Return the commutator of self and x: \verb!~x*~self*x*self! \verb!commutes_with(other)!\\ Checks if the elements are commuting. \verb!cycle_structure!\\ Return the cycle structure of the permutation as a dictionary indicating the multiplicity of each cycle length. \verb!cycles! \\ Returns the number of cycles contained in the permutation (including singletons). \verb!cyclic_form!\\ This is used to convert to the cyclic notation from the canonical notation. Singletons are omitted. \verb!from_inversion_vector(inversion)!\\ Calculates the permutation from the inversion vector. \verb!from_sequence(i, key=None)!\\ Return the permutation needed to obtain \verb!i! from the sorted elements of \verb!i!. If custom sorting is desired, a key can be given. \verb!full_cyclic_form!\\ Return permutation in cyclic form including singletons. \verb!get_adjacency_distance(other)!\\ Computes the adjacency distance between two permutations. \verb!get_adjacency_matrix()!\\ Computes the adjacency matrix of a permutation. \verb!get_positional_distance(other)!\\ Computes the positional distance between two permutations. \verb!get_precedence_distance(other)!\\ Computes the precedence distance between two permutations. \verb!get_precedence_matrix()!\\ Gets the precedence matrix. This is used for computing the distance between two permutations. \verb!index()!\\ Returns the index of a permutation. \verb!inversion_vector()!\\ Return the inversion vector of the permutation. \verb!inversions()!\\ Computes the number of inversions of a permutation. \verb!is_Empty!\\ Checks to see if the permutation is a set with zero elements \verb!is_Identity!\\ Returns True if the Permutation is an identity permutation. \verb!is_Singleton!\\ Checks to see if the permutation contains only one number and is thus the only possible permutation of this set of numbers. \verb!is_even!\\ Checks if a permutation is even. \verb!is_odd!\\ Checks if a permutation is odd. \verb!josephus(m, n, s=1)!\\ Return as a permutation the shuffling of range(\verb!n!) using the Josephus scheme in which every \verb!m!-th item is selected until all have been chosen. \verb!length()!\\ Returns the number of integers moved by a permutation. \verb!list(size=None)!\\ Return the permutation as an explicit list \verb!max()!\\ The maximum element moved by the permutation. \verb!min()!\\ The minimum element moved by the permutation \verb!next_lex()!\\ Returns the next permutation in lexicographical order. \verb!next_nonlex()!\\ Returns the next permutation in nonlex order. \verb!next_trotterjohnson()!\\ Returns the next permutation in Trotter-Johnson order. \verb!order()!\\ Computes the order of a permutation. \verb!parity()!\\ Computes the parity of a permutation. \verb!random(n)!\\ Generates a random permutation of length \verb!n!. \verb!rank(i=None)!\\ Returns the lexicographic rank of the permutation (default) or the \verb!i!th ranked permutation of self. \verb!rank_nonlex(inv_perm=None)!\\ This is a linear time ranking algorithm that does not enforce lexicographic order. \verb!rank_trotterjohnson()!\\ Returns the Trotter Johnson rank, which we get from the minimal change algorithm. \verb!static rmul(*args)!\\ Return product of Permutations $[a, b, c, \ldots]$ as the Permutation whose $i$th value is $a(b(c(i)))$. \verb!runs()!\\ Returns the runs of a permutation. \verb!signature()!\\ Gives the signature of the permutation needed to place the elements of the permutation in canonical order. \verb!size!\\ Returns the number of elements in the permutation. \verb!support()!\\ Return the elements in permutation, $P$, for which $P[i] \neq i$. \verb!transpositions()!\\ Return the permutation decomposed into a list of transpositions. \verb!unrank_lex(size, rank)!\\ Lexicographic permutation unranking. \verb!unrank_nonlex(n, r)!\\ This is a linear time unranking algorithm that does not respect lexicographic order. \verb!unrank_trotterjohnson(size, rank)!\\ Trotter Johnson permutation unranking. \subsection{Subclass \texttt{Cycle(*args)}} Wrapper around dict which provides the functionality of a disjoint cycle. \subsection{Subclass \texttt{Generators}} \verb!symmetric(n)!\\ Generates the symmetric group of order \verb!n!, \verb!Sn!. \verb!cyclic(n)!\\ Generates the cyclic group of order \verb!n, Cn!. \verb!alternating(n)!\\ Generates the alternating group of order \verb!n, An! \verb!dihedral(n)!\\ Generates the dihedral group of order \verb!2n, Dn!. \section{PermutationGroup} Path : \verb!sympy.combinatorics.perm_groups.PermutationGroup! \subsection{Methods} \verb!base!\\ Return a base from the Schreier-Sims algorithm. \verb!baseswap(base, strong_gens, pos, randomized=False,!\\ \verb!transversals=None, basic_orbits=None,! \\ \verb!strong_gens_distr=None)!\\ Swap two consecutive base points in base and strong generating set. \verb!basic_orbits!\\ Return the basic orbits relative to a base and strong generating set. \verb!basic_stabilizers!\\ Return a chain of stabilizers relative to a base and strong generating set. \verb!basic_transversals!\\ Return basic transversals relative to a base and strong generating set. \verb!center()!\\ Return the center of a permutation group. \verb!centralizer(other)!\\ Return the centralizer of a group/set/element. \verb!commutator(G, H)!\\ Return the commutator of two subgroups. \verb!contains(g, strict=True)!\\ Test if permutation \verb!g! belong to self. \verb!coset_factor(g, af=False)!\\ Return G's (self's) coset factorization, \verb!f,! of \verb!g!. \verb!coset_rank(g)!\\ rank using Schreier-Sims representation \verb!coset_unrank(rank, af=False)!\\ unrank using Schreier-Sims representation \verb!degree!\\ Returns the size of the permutations in the group. \verb!derived_series()!\\ Return the derived series for the group. \verb!derived_subgroup()!\\ Compute the derived subgroup. \verb!generate(method='coset', af=False)!\\ Return iterator to generate the elements of the group \verb!generate_dimino(af=False)!\\ Yield group elements using Dimino's algorithm \verb!generate_schreier_sims(af=False)!\\ Yield group elements using the Schreier-Sims representation. \verb!generators!\\ Returns the generators of the group. \verb!is_abelian!\\ Test if the group is Abelian. \verb!is_alt_sym(eps=0.05, _random_prec=None)!\\ Monte Carlo test for the symmetric/alternating group for degrees $>= 8$. \verb!is_group()!\\ Return True if the group if identity is present, the inverse of every element is also an element, and the product of any two elements is also an element. \verb!is_nilpotent!\\ Test if the group is nilpotent. \verb!is_normal(gr)!\\ Test if G=self is a normal subgroup of \verb!gr!. \verb!is_primitive(randomized=True)!\\ Test if a group is primitive. \verb!is_solvable!\\ Test if the group is solvable. \verb!is_subgroup(G, strict=True)!\\ Return True if all elements of self belong to G. \verb!is_transitive(strict=True)!\\ Test if the group is transitive. \verb!is_trivial!\\ Test if the group is the trivial group. \verb!lower_central_series()! \\ Return the lower central series for the group. \verb!make_perm(n, seed=None)!\\ Multiply n randomly selected permutations from pgroup together, starting with the identity permutation. \verb!max_div!\\ Maximum proper divisor of the degree of a permutation group. \verb!minimal_block(points)!\\ For a transitive group, finds the block system generated by \verb!points!. \verb!normal_closure(other, k=10)!\\ Return the normal closure of a subgroup/set of permutations. \verb!orbit(alpha, action='tuples')!\\ Compute the orbit of alpha \verb!\{g(\alpha) | g \in G\}! as a set. \verb!orbit_rep(alpha, beta, schreier_vector=None)!\\ Return a group element which sends \verb!alpha! to \verb!beta!. \verb!orbit_transversal(alpha, pairs=False)!\\ Computes a transversal for the orbit of \verb!alpha! as a set. \verb!orbits(rep=False)!\\ Return the orbits of self, ordered according to lowest element in each orbit. \verb!order()!\\ Return the number of permutations that can be generated from elements of the group. \verb!pointwise_stabilizer(points, incremental=False)!\\ Return the pointwise stabilizer for a set of points. \verb!random(af=False)!\\ Return a random group element. \verb!random_pr(gen_count=11, iterations=50, _random_prec=None)!\\ Return a random group element using product replacement. \verb!random_stab(alpha, schreier_vector=None, _random_prec=None)!\\ Random element from the stabilizer of \verb!alpha!. \verb!schreier_sims()!\\ Schreier-Sims algorithm. \verb!schreier_sims_incremental(base=None, gens=None)!\\ Extend a sequence of points and generating set to a base and strong generating set. \verb!schreier_sims_random(base=None, gens=None,!\\ \verb! consec_succ=10, _random_prec=None)!\\ Randomized Schreier-Sims algorithm. \verb!schreier_vector(alpha)! \\ Computes the schreier vector for \verb!alpha!. \verb!stabilizer(alpha)!\\ Return the stabilizer subgroup of \verb!alpha!. \verb!stabilizer_cosets(af=False)!\\ Return a list of cosets of the stabilizer chain of the group as computed by the Schreir-Sims algorithm. \verb!stabilizer_gens(af=False)!\\ Return the generators of the chain of stabilizers of the Schreier-Sims representation. \verb!strong_gens!\\ Return a strong generating set from the Schreier-Sims algorithm. \verb!subgroup_search(prop, base=None, strong_gens=None,!\\ \verb!tests=None, init_subgroup=None)!\\ Find the subgroup of all elements satisfying the property prop. \verb!transitivity_degree!\\ Compute the degree of transitivity of the group. \section{Polyhedron} Path : \verb!sympy.combinatorics.polyhedron.Polyhedron!\\ Represents the polyhedral symmetry group (PSG). \subsection{Methods} \verb!array_form!\\ Return the indices of the corners. \verb!corners!\\ Get the corners of the Polyhedron. \verb!cyclic_form!\\ Return the indices of the corners in cyclic notation. \verb!edges!\\ Given the faces of the polyhedra we can get the edges. \verb!faces!\\ Get the faces of the Polyhedron. \verb!pgroup!\\ Get the permutations of the Polyhedron. \verb!reset()!\\ Return corners to their original positions. \verb!rotate(perm)!\\ Apply a permutation to the polyhedron in place. \verb!size!\\ Get the number of corners of the Polyhedron. \verb!vertices!\\ Get the corners of the Polyhedron. \section{Prufer} Path: \verb!sympy.combinatorics.prufer.Prufer!\\ The Prufer correspondence is an algorithm that describes the bijection between labeled trees and the Prufer code. A Prufer code of a labeled tree is unique up to isomorphism and has a length of $n - 2$. \subsection{Methods} \verb!static edges(*runs)!\\ Return a list of edges and the number of nodes from the given runs that connect nodes in an integer-labelled tree. \verb!next(delta=1)!\\ Generates the Prufer sequence that is delta beyond the current one. \verb!nodes!\\ Returns the number of nodes in the tree. \verb!prev(delta=1)!\\ Generates the Prufer sequence that is -delta before the current one. \verb!prufer_rank()!\\ Computes the rank of a Prufer sequence. \verb!prufer_repr!\\ Returns Prufer sequence for the Prufer object. \verb!rank!\\ Returns the rank of the Prufer sequence. \verb!size!\\ Return the number of possible trees of this Prufer object. \verb!static to_prufer(tree, n)!\\ Return the Prufer sequence for a tree given as a list of edges where n is the number of nodes in the tree. \verb!static to_tree(prufer)!\\ Return the tree (as a list of edges) of the given Prufer sequence. \verb!tree_repr!\\ Returns the tree representation of the Prufer object. \verb!unrank(rank, n)!\\ Finds the unranked Prufer sequence. \section{Subset} Path: \verb!sympy.combinatorics.subsets.Subset!\\ Represents a basic subset object. \subsection{Methods} \verb!bitlist_from_subset(subset, superset)!\\ Gets the bitlist corresponding to a subset. \verb!cardinality!\\ Returns the number of all possible subsets. \verb!iterate_binary(k)!\\ This is a helper function. It iterates over the binary subsets by k steps. This variable can be both positive or negative. \verb!iterate_graycode(k)!\\ It performs k step overs to get the respective Gray codes. \verb!next_binary()!\\ Generates the next binary ordered subset. \verb!next_gray()!\\ Generates the next Gray code ordered subset. \verb!next_lexicographic()!\\ Generates the next lexicographically ordered subset. NOT IMPLEMENTED \verb!prev_binary()!\\ Generates the previous binary ordered subset. \verb!prev_gray()!\\ Generates the previous Gray code ordered subset. \verb!prev_lexicographic()!\\ Generates the previous lexicographically ordered subset. NOT IMPLEMENTED \verb!rank_binary!\\ Computes the binary ordered rank. \verb!rank_gray!\\ Computes the Gray code ranking of the subset. \verb!rank_lexicographic!\\ Computes the lexicographic ranking of the subset. \verb!size!\\ Gets the size of the subset. \verb!subset!\\ Gets the subset represented by the current instance. \verb!subset_from_bitlist(super_set, bitlist)!\\ Gets the subset defined by the \verb!bitlist!. \verb!subset_indices(subset, superset)!\\ Return indices of subset in superset in a list; the list is empty if all elements of \verb!subset! are not in \verb!superset!. \verb!superset!\\ Gets the superset of the subset. \verb!superset_size!\\ Returns the size of the superset. \verb!unrank_binary(rank, superset)!\\ Gets the binary ordered subset of the specified rank. \verb!unrank_gray(rank, superset)!\\ Gets the Gray code ordered subset of the specified rank. \verb!subsets.ksubsets(superset, k)!\\ Finds the subsets of size \verb!k! in lexicographic order. \section{Gray Code} Path: \verb!sympy.combinatorics.graycode.GrayCode! A Gray code is essentially a Hamiltonian walk on an n-dimensional cube with edge length of one. The vertices of the cube are represented by vectors whose values are binary. The Hamilton walk visits each vertex exactly once. \subsection{Methods} \verb!current!\\ Returns the currently referenced Gray code as a bit string. \verb!generate_gray(**hints)!\\ Generates the sequence of bit vectors of a Gray Code. \verb!n!\\ Returns the dimension of the Gray code. \verb!next(delta=1)!\\ Returns the Gray code a distance delta (default = 1) from the current value in canonical order. \verb!rank!\\ Ranks the Gray code. \verb!selections!\\ Returns the number of bit vectors in the Gray code. \verb!skip()!\\ Skips the bit generation. \verb!unrank(n, rank)!\\ Unranks an n-bit sized Gray code of rank k. This method exists so that a derivative GrayCode class can define its own code of a given rank. \verb!graycode.random_bitstring(n)!\\ Generates a random bitlist of length n. \verb!graycode.gray_to_bin(bin_list)!\\ Convert from Gray coding to binary coding. \verb!graycode.bin_to_gray(bin_list)!\\ Convert from binary coding to gray coding. \verb!graycode.get_subset_from_bitstring(super_set, bitstring)!\\ Gets the subset defined by the bitstring. \verb!graycode.graycode_subsets(gray_code_set)!\\ Generates the subsets as enumerated by a Gray code. \section{Named Groups} Path: \verb!sympy.combinatorics.named_groups!\\ \subsection{Methods} \verb!SymmetricGroup(n)!\\ Generates the symmetric group on \verb!n! elements as a permutation group. \verb!CyclicGroup(n)!\\ Generates the cyclic group of order n as a permutation group. \verb!DihedralGroup(n)!\\ Generates the dihedral group Dn as a permutation group. \verb!AlternatingGroup(n)!\\ Generates the alternating group on \verb!n! elements as a permutation group. \verb!AbelianGroup(*cyclic_orders)!\\ Returns the direct product of cyclic groups with the given orders. \section{Utilities} Path: \verb!sympy.combinatorics.util! \subsection{Methods} \verb!_base_ordering(base, degree)!\\ Order $\{0,1,\ldots,n\}$ so that base points come first and in order \verb!_check_cycles_alt_sym(perm)!\\ Checks for cycles of prime length $p$ with $n/2 < p < n-2$. \verb!_distribute_gens_by_base(base, gens)!\\ Distribute the group elements \verb!gens! by membership in basic stabilizers. \verb!_handle_precomputed_bsgs(base, strong_gens,!\\ \verb!transversals=None, basic_orbits=None,!\\ \verb!strong_gens_distr=None)!\\ Calculate BSGS-related structures from those present. \verb!_orbits_transversals_from_bsgs(base, strong_gens_distr,!\\ \verb!transversals_only=False)!\\ Compute basic orbits and transversals from a base and strong generating set. \verb!_remove_gens(base, strong_gens,! \verb!basic_orbits=None, strong_gens_distr=None)!\\ Remove redundant generators from a strong generating set. \verb!_strip(g, base, orbits, transversals)!\\ Attempt to decompose a permutation using a (possibly partial) BSGS structure. \verb!_strong_gens_from_distr(strong_gens_distr)!\\ Retrieve strong generating set from generators of basic stabilizers. \section{Group Constructors} Path: \verb!sympy.combinatorics.group_constructs! \subsection{Method} \verb!DirectProduct(*groups)!\\ Returns the direct product of several groups as a permutation group. \section{Test Utilities} Path: \verb!sympy.combinatorics.testutil! \subsection{Methods} \verb!_cmp_perm_lists(first, second)!\\ Compare two lists of permutations as sets. \verb!_naive_list_centralizer(self, other)!\\ \verb!_verify_bsgs(group, base, gens)!\\ Verify the correctness of a base and strong generating set. \verb!_verify_centralizer(group, arg, centr=None)!\\ Verify the centralizer of a group/set/element inside another group. \verb!_verify_normal_closure(group, arg, closure=None)!\\ \rule{0.3\linewidth}{0.25pt} \scriptsize\\ https://www.sympy.org/cheatsheets \end{multicols} \end{document} sympy-sympy-1.9/doc/ext/000077500000000000000000000000001412543434000152705ustar00rootroot00000000000000sympy-sympy-1.9/doc/ext/docscrape.py000066400000000000000000000410021412543434000176020ustar00rootroot00000000000000""" Extract reference documentation from the NumPy source tree. """ import inspect import textwrap import re import pydoc from collections.abc import Mapping import sys class Reader: """ A line-based string reader. """ def __init__(self, data): """ Parameters ---------- data : str String with lines separated by '\n'. """ if isinstance(data, list): self._str = data else: self._str = data.split('\n') # store string as list of lines self.reset() def __getitem__(self, n): return self._str[n] def reset(self): self._l = 0 # current line nr def read(self): if not self.eof(): out = self[self._l] self._l += 1 return out else: return '' def seek_next_non_empty_line(self): for l in self[self._l:]: if l.strip(): break else: self._l += 1 def eof(self): return self._l >= len(self._str) def read_to_condition(self, condition_func): start = self._l for line in self[start:]: if condition_func(line): return self[start:self._l] self._l += 1 if self.eof(): return self[start:self._l + 1] return [] def read_to_next_empty_line(self): self.seek_next_non_empty_line() def is_empty(line): return not line.strip() return self.read_to_condition(is_empty) def read_to_next_unindented_line(self): def is_unindented(line): return (line.strip() and (len(line.lstrip()) == len(line))) return self.read_to_condition(is_unindented) def peek(self, n=0): if self._l + n < len(self._str): return self[self._l + n] else: return '' def is_empty(self): return not ''.join(self._str).strip() class NumpyDocString(Mapping): def __init__(self, docstring, config={}): docstring = textwrap.dedent(docstring).split('\n') self._doc = Reader(docstring) self._parsed_data = { 'Signature': '', 'Summary': [''], 'Extended Summary': [], 'Parameters': [], 'Returns': [], 'Yields': [], 'Raises': [], 'Warns': [], 'Other Parameters': [], 'Attributes': [], 'Methods': [], 'See Also': [], # 'Notes': [], 'Warnings': [], 'References': '', # 'Examples': '', 'index': {} } self._other_keys = [] self._parse() def __getitem__(self, key): return self._parsed_data[key] def __setitem__(self, key, val): if key not in self._parsed_data: self._other_keys.append(key) self._parsed_data[key] = val def __iter__(self): return iter(self._parsed_data) def __len__(self): return len(self._parsed_data) def _is_at_section(self): self._doc.seek_next_non_empty_line() if self._doc.eof(): return False l1 = self._doc.peek().strip() # e.g. Parameters if l1.startswith('.. index::'): return True l2 = self._doc.peek(1).strip() # ---------- or ========== return l2.startswith('-'*len(l1)) or l2.startswith('='*len(l1)) def _strip(self, doc): i = 0 j = 0 for i, line in enumerate(doc): if line.strip(): break for j, line in enumerate(doc[::-1]): if line.strip(): break return doc[i:len(doc) - j] def _read_to_next_section(self): section = self._doc.read_to_next_empty_line() while not self._is_at_section() and not self._doc.eof(): if not self._doc.peek(-1).strip(): # previous line was empty section += [''] section += self._doc.read_to_next_empty_line() return section def _read_sections(self): while not self._doc.eof(): data = self._read_to_next_section() name = data[0].strip() if name.startswith('..'): # index section yield name, data[1:] elif len(data) < 2: yield StopIteration else: yield name, self._strip(data[2:]) def _parse_param_list(self, content): r = Reader(content) params = [] while not r.eof(): header = r.read().strip() if ' : ' in header: arg_name, arg_type = header.split(' : ')[:2] else: arg_name, arg_type = header, '' desc = r.read_to_next_unindented_line() desc = dedent_lines(desc) params.append((arg_name, arg_type, desc)) return params _name_rgx = re.compile(r"^\s*(:(?P\w+):`(?P[a-zA-Z0-9_.-]+)`|" r" (?P[a-zA-Z0-9_.-]+))\s*", re.X) def _parse_see_also(self, content): """ func_name : Descriptive text continued text another_func_name : Descriptive text func_name1, func_name2, :meth:`func_name`, func_name3 """ items = [] def parse_item_name(text): """Match ':role:`name`' or 'name'""" m = self._name_rgx.match(text) if m: g = m.groups() if g[1] is None: return g[3], None else: return g[2], g[1] raise ValueError("%s is not an item name" % text) def push_item(name, rest): if not name: return name, role = parse_item_name(name) if '.' not in name: name = '~.' + name items.append((name, list(rest), role)) del rest[:] current_func = None rest = [] for line in content: if not line.strip(): continue m = self._name_rgx.match(line) if m and line[m.end():].strip().startswith(':'): push_item(current_func, rest) current_func, line = line[:m.end()], line[m.end():] rest = [line.split(':', 1)[1].strip()] if not rest[0]: rest = [] elif not line.startswith(' '): push_item(current_func, rest) current_func = None if ',' in line: for func in line.split(','): if func.strip(): push_item(func, []) elif line.strip(): current_func = line elif current_func is not None: rest.append(line.strip()) push_item(current_func, rest) return items def _parse_index(self, section, content): """ .. index: default :refguide: something, else, and more """ def strip_each_in(lst): return [s.strip() for s in lst] out = {} section = section.split('::') if len(section) > 1: out['default'] = strip_each_in(section[1].split(','))[0] for line in content: line = line.split(':') if len(line) > 2: out[line[1]] = strip_each_in(line[2].split(',')) return out def _parse_summary(self): """Grab signature (if given) and summary""" if self._is_at_section(): return # If several signatures present, take the last one while True: summary = self._doc.read_to_next_empty_line() summary_str = " ".join([s.strip() for s in summary]).strip() if re.compile(r'^([\w., ]+=)?\s*[\w\.]+\(.*\)$').match(summary_str): self['Signature'] = summary_str if not self._is_at_section(): continue break if summary is not None: self['Summary'] = summary if not self._is_at_section(): self['Extended Summary'] = self._read_to_next_section() def _parse(self): self._doc.reset() self._parse_summary() sections = list(self._read_sections()) section_names = {section for section, content in sections} has_returns = 'Returns' in section_names has_yields = 'Yields' in section_names # We could do more tests, but we are not. Arbitrarily. if has_returns and has_yields: msg = 'Docstring contains both a Returns and Yields section.' raise ValueError(msg) for (section, content) in sections: if not section.startswith('..'): section = (s.capitalize() for s in section.split(' ')) section = ' '.join(section) if section in ('Parameters', 'Returns', 'Yields', 'Raises', 'Warns', 'Other Parameters', 'Attributes', 'Methods'): self[section] = self._parse_param_list(content) elif section.startswith('.. index::'): self['index'] = self._parse_index(section, content) elif section == 'See Also': self['See Also'] = self._parse_see_also(content) else: self[section] = content # string conversion routines def _str_header(self, name, symbol='-'): return [name, len(name)*symbol] def _str_indent(self, doc, indent=4): out = [] for line in doc: out += [' '*indent + line] return out def _str_signature(self): if self['Signature']: return [self['Signature'].replace('*', r'\*')] + [''] else: return [''] def _str_summary(self): if self['Summary']: return self['Summary'] + [''] else: return [] def _str_extended_summary(self): if self['Extended Summary']: return self['Extended Summary'] + [''] else: return [] def _str_param_list(self, name): out = [] if self[name]: out += self._str_header(name) for param, param_type, desc in self[name]: if param_type: out += ['{} : {}'.format(param, param_type)] else: out += [param] out += self._str_indent(desc) out += [''] return out def _str_section(self, name): out = [] if self[name]: out += self._str_header(name) out += self[name] out += [''] return out def _str_see_also(self, func_role): if not self['See Also']: return [] out = [] out += self._str_header("See Also") last_had_desc = True for func, desc, role in self['See Also']: if role: link = ':{}:`{}`'.format(role, func) elif func_role: link = ':{}:`{}`'.format(func_role, func) else: link = "`%s`_" % func if desc or last_had_desc: out += [''] out += [link] else: out[-1] += ", %s" % link if desc: out += self._str_indent([' '.join(desc)]) last_had_desc = True else: last_had_desc = False out += [''] return out def _str_index(self): idx = self['index'] out = [] out += ['.. index:: %s' % idx.get('default', '')] for section, references in idx.items(): if section == 'default': continue out += [' :{}: {}'.format(section, ', '.join(references))] return out def __str__(self, func_role=''): out = [] out += self._str_signature() out += self._str_summary() out += self._str_extended_summary() for param_list in ('Parameters', 'Returns', 'Yields', 'Other Parameters', 'Raises', 'Warns'): out += self._str_param_list(param_list) out += self._str_section('Warnings') out += self._str_see_also(func_role) for s in ('Notes', 'References', 'Examples'): out += self._str_section(s) for param_list in ('Attributes', 'Methods'): out += self._str_param_list(param_list) out += self._str_index() return '\n'.join(out) def indent(str, indent=4): indent_str = ' '*indent if str is None: return indent_str lines = str.split('\n') return '\n'.join(indent_str + l for l in lines) def dedent_lines(lines): """Deindent a list of lines maximally""" return textwrap.dedent("\n".join(lines)).split("\n") def header(text, style='-'): return text + '\n' + style*len(text) + '\n' class FunctionDoc(NumpyDocString): def __init__(self, func, role='func', doc=None, config={}): self._f = func self._role = role # e.g. "func" or "meth" if doc is None: if func is None: raise ValueError("No function or docstring given") doc = inspect.getdoc(func) or '' NumpyDocString.__init__(self, doc) if not self['Signature'] and func is not None: func, func_name = self.get_func() try: # try to read signature argspec = inspect.getfullargspec(func) argspec = inspect.formatargspec(*argspec) argspec = argspec.replace('*', r'\*') signature = '{}{}'.format(func_name, argspec) except TypeError as e: signature = '%s()' % func_name self['Signature'] = signature def get_func(self): func_name = getattr(self._f, '__name__', self.__class__.__name__) if inspect.isclass(self._f): func = getattr(self._f, '__call__', self._f.__init__) else: func = self._f return func, func_name def __str__(self): out = '' func, func_name = self.get_func() signature = self['Signature'].replace('*', r'\*') roles = {'func': 'function', 'meth': 'method'} if self._role: if self._role not in roles: print("Warning: invalid role %s" % self._role) out += '.. {}:: {}\n \n\n'.format(roles.get(self._role, ''), func_name) out += super().__str__(func_role=self._role) return out class ClassDoc(NumpyDocString): extra_public_methods = ['__call__'] def __init__(self, cls, doc=None, modulename='', func_doc=FunctionDoc, config={}): if not inspect.isclass(cls) and cls is not None: raise ValueError("Expected a class or None, but got %r" % cls) self._cls = cls self.show_inherited_members = config.get( 'show_inherited_class_members', True) if modulename and not modulename.endswith('.'): modulename += '.' self._mod = modulename if doc is None: if cls is None: raise ValueError("No class or documentation string given") doc = pydoc.getdoc(cls) NumpyDocString.__init__(self, doc) if config.get('show_class_members', True): def splitlines_x(s): if not s: return [] else: return s.splitlines() for field, items in [('Methods', self.methods), ('Attributes', self.properties)]: if not self[field]: doc_list = [] for name in sorted(items): clsname = getattr(self._cls, name, None) if clsname is not None: doc_item = pydoc.getdoc(clsname) doc_list.append((name, '', splitlines_x(doc_item))) self[field] = doc_list @property def methods(self): if self._cls is None: return [] return [name for name, func in inspect.getmembers(self._cls) if ((not name.startswith('_') or name in self.extra_public_methods) and callable(func))] @property def properties(self): if self._cls is None: return [] return [name for name, func in inspect.getmembers(self._cls) if not name.startswith('_') and func is None] sympy-sympy-1.9/doc/ext/docscrape_sphinx.py000066400000000000000000000223151412543434000212010ustar00rootroot00000000000000import sys import re import inspect import textwrap import pydoc import sphinx import collections from docscrape import NumpyDocString, FunctionDoc, ClassDoc class SphinxDocString(NumpyDocString): def __init__(self, docstring, config={}): NumpyDocString.__init__(self, docstring, config=config) self.load_config(config) def load_config(self, config): self.use_plots = config.get('use_plots', False) self.class_members_toctree = config.get('class_members_toctree', True) # string conversion routines def _str_header(self, name, symbol='`'): return ['.. rubric:: ' + name, ''] def _str_field_list(self, name): return [':' + name + ':'] def _str_indent(self, doc, indent=4): out = [] for line in doc: out += [' '*indent + line] return out def _str_signature(self): return [''] if self['Signature']: return ['``%s``' % self['Signature']] + [''] else: return [''] def _str_summary(self): return self['Summary'] + [''] def _str_extended_summary(self): return self['Extended Summary'] + [''] def _str_returns(self, name='Returns'): out = [] if self[name]: out += self._str_field_list(name) out += [''] for param, param_type, desc in self[name]: if param_type: out += self._str_indent(['**{}** : {}'.format(param.strip(), param_type)]) else: out += self._str_indent([param.strip()]) if desc: out += [''] out += self._str_indent(desc, 8) out += [''] return out def _str_param_list(self, name): out = [] if self[name]: out += self._str_field_list(name) out += [''] for param, param_type, desc in self[name]: if param_type: out += self._str_indent(['**{}** : {}'.format(param.strip(), param_type)]) else: out += self._str_indent(['**%s**' % param.strip()]) if desc: out += [''] out += self._str_indent(desc, 8) out += [''] return out @property def _obj(self): if hasattr(self, '_cls'): return self._cls elif hasattr(self, '_f'): return self._f return None def _str_member_list(self, name): """ Generate a member listing, autosummary:: table where possible, and a table where not. """ out = [] if self[name]: out += ['.. rubric:: %s' % name, ''] prefix = getattr(self, '_name', '') if prefix: prefix = '~%s.' % prefix # Lines that are commented out are used to make the # autosummary:: table. Since SymPy does not use the # autosummary:: functionality, it is easiest to just comment it # out. # autosum = [] others = [] for param, param_type, desc in self[name]: param = param.strip() # Check if the referenced member can have a docstring or not param_obj = getattr(self._obj, param, None) if not (callable(param_obj) or isinstance(param_obj, property) or inspect.isgetsetdescriptor(param_obj)): param_obj = None # if param_obj and (pydoc.getdoc(param_obj) or not desc): # # Referenced object has a docstring # autosum += [" %s%s" % (prefix, param)] # else: others.append((param, param_type, desc)) # if autosum: # out += ['.. autosummary::'] # if self.class_members_toctree: # out += [' :toctree:'] # out += [''] + autosum if others: maxlen_0 = max(3, max([len(x[0]) for x in others])) hdr = "="*maxlen_0 + " " + "="*10 fmt = '%%%ds %%s ' % (maxlen_0,) out += ['', '', hdr] for param, param_type, desc in others: desc = " ".join(x.strip() for x in desc).strip() if param_type: desc = "({}) {}".format(param_type, desc) out += [fmt % (param.strip(), desc)] out += [hdr] out += [''] return out def _str_section(self, name): out = [] if self[name]: out += self._str_header(name) out += [''] content = textwrap.dedent("\n".join(self[name])).split("\n") out += content out += [''] return out def _str_see_also(self, func_role): out = [] if self['See Also']: see_also = super()._str_see_also(func_role) out = ['.. seealso::', ''] out += self._str_indent(see_also[2:]) return out def _str_warnings(self): out = [] if self['Warnings']: out = ['.. warning::', ''] out += self._str_indent(self['Warnings']) return out def _str_index(self): idx = self['index'] out = [] if len(idx) == 0: return out out += ['.. index:: %s' % idx.get('default', '')] for section, references in idx.items(): if section == 'default': continue elif section == 'refguide': out += [' single: %s' % (', '.join(references))] else: out += [' {}: {}'.format(section, ','.join(references))] return out def _str_references(self): out = [] if self['References']: out += self._str_header('References') if isinstance(self['References'], str): self['References'] = [self['References']] out.extend(self['References']) out += [''] # Latex collects all references to a separate bibliography, # so we need to insert links to it if sphinx.__version__ >= "0.6": out += ['.. only:: latex', ''] else: out += ['.. latexonly::', ''] items = [] for line in self['References']: m = re.match(r'.. \[([a-z0-9._-]+)\]', line, re.I) if m: items.append(m.group(1)) out += [' ' + ", ".join(["[%s]_" % item for item in items]), ''] return out def _str_examples(self): examples_str = "\n".join(self['Examples']) if (self.use_plots and 'import matplotlib' in examples_str and 'plot::' not in examples_str): out = [] out += self._str_header('Examples') out += ['.. plot::', ''] out += self._str_indent(self['Examples']) out += [''] return out else: return self._str_section('Examples') def __str__(self, indent=0, func_role="obj"): out = [] out += self._str_signature() out += self._str_index() + [''] out += self._str_summary() out += self._str_extended_summary() out += self._str_param_list('Parameters') out += self._str_returns('Returns') out += self._str_returns('Yields') for param_list in ('Other Parameters', 'Raises', 'Warns'): out += self._str_param_list(param_list) out += self._str_warnings() for s in self._other_keys: out += self._str_section(s) out += self._str_see_also(func_role) out += self._str_references() out += self._str_member_list('Attributes') out = self._str_indent(out, indent) return '\n'.join(out) class SphinxFunctionDoc(SphinxDocString, FunctionDoc): def __init__(self, obj, doc=None, config={}): self.load_config(config) FunctionDoc.__init__(self, obj, doc=doc, config=config) class SphinxClassDoc(SphinxDocString, ClassDoc): def __init__(self, obj, doc=None, func_doc=None, config={}): self.load_config(config) ClassDoc.__init__(self, obj, doc=doc, func_doc=None, config=config) class SphinxObjDoc(SphinxDocString): def __init__(self, obj, doc=None, config={}): self._f = obj self.load_config(config) SphinxDocString.__init__(self, doc, config=config) def get_doc_object(obj, what=None, doc=None, config={}): if inspect.isclass(obj): what = 'class' elif inspect.ismodule(obj): what = 'module' elif callable(obj): what = 'function' else: what = 'object' if what == 'class': return SphinxClassDoc(obj, func_doc=SphinxFunctionDoc, doc=doc, config=config) elif what in ('function', 'method'): return SphinxFunctionDoc(obj, doc=doc, config=config) else: if doc is None: doc = pydoc.getdoc(obj) return SphinxObjDoc(obj, doc, config=config) sympy-sympy-1.9/doc/ext/numpydoc.py000066400000000000000000000142001412543434000174750ustar00rootroot00000000000000""" ======== numpydoc ======== Sphinx extension that handles docstrings in the Numpy standard format. [1] It will: - Convert Parameters etc. sections to field lists. - Convert See Also section to a See also entry. - Renumber references. - Extract the signature from the docstring, if it can't be determined otherwise. .. [1] https://github.com/numpy/numpy/blob/master/doc/HOWTO_DOCUMENT.rst.txt """ import sys import re import pydoc import sphinx import inspect from collections.abc import Callable if sphinx.__version__ < '1.0.1': raise RuntimeError("Sphinx 1.0.1 or newer is required") from docscrape_sphinx import get_doc_object, SphinxDocString def mangle_docstrings(app, what, name, obj, options, lines, reference_offset=[0]): cfg = {'use_plots': app.config.numpydoc_use_plots, 'show_class_members': app.config.numpydoc_show_class_members, 'show_inherited_class_members': app.config.numpydoc_show_inherited_class_members, 'class_members_toctree': app.config.numpydoc_class_members_toctree} u_NL = '\n' if what == 'module': # Strip top title pattern = '^\\s*[#*=]{4,}\\n[a-z0-9 -]+\\n[#*=]{4,}\\s*' title_re = re.compile(pattern, re.I | re.S) lines[:] = title_re.sub('', u_NL.join(lines)).split(u_NL) else: doc = get_doc_object(obj, what, u_NL.join(lines), config=cfg) if sys.version_info[0] >= 3: doc = str(doc) else: doc = unicode(doc) lines[:] = doc.split(u_NL) if (app.config.numpydoc_edit_link and hasattr(obj, '__name__') and obj.__name__): if hasattr(obj, '__module__'): v = dict(full_name="{}.{}".format(obj.__module__, obj.__name__)) else: v = dict(full_name=obj.__name__) lines += ['', '.. htmlonly::', ''] lines += [' %s' % x for x in (app.config.numpydoc_edit_link % v).split("\n")] # replace reference numbers so that there are no duplicates references = [] for line in lines: line = line.strip() m = re.match('^.. \\[([a-z0-9_.-])\\]', line, re.I) if m: references.append(m.group(1)) # start renaming from the longest string, to avoid overwriting parts references.sort(key=lambda x: -len(x)) if references: for i, line in enumerate(lines): for r in references: if re.match('^\\d+$', r): new_r = "R%d" % (reference_offset[0] + int(r)) else: new_r = "%s%d" % (r, reference_offset[0]) lines[i] = lines[i].replace('[%s]_' % r, '[%s]_' % new_r) lines[i] = lines[i].replace('.. [%s]' % r, '.. [%s]' % new_r) reference_offset[0] += len(references) def mangle_signature(app, what, name, obj, options, sig, retann): # Do not try to inspect classes that don't define `__init__` if (inspect.isclass(obj) and (not hasattr(obj, '__init__') or 'initializes x; see ' in pydoc.getdoc(obj.__init__))): return '', '' if not (isinstance(obj, Callable) or hasattr(obj, '__argspec_is_invalid_')): return if not hasattr(obj, '__doc__'): return doc = SphinxDocString(pydoc.getdoc(obj)) if doc['Signature']: sig = re.sub("^[^(]*", "", doc['Signature']) return sig, '' def setup(app, get_doc_object_=get_doc_object): if not hasattr(app, 'add_config_value'): return # probably called by nose, better bail out global get_doc_object get_doc_object = get_doc_object_ app.connect('autodoc-process-docstring', mangle_docstrings) app.connect('autodoc-process-signature', mangle_signature) app.add_config_value('numpydoc_edit_link', None, False) app.add_config_value('numpydoc_use_plots', None, False) app.add_config_value('numpydoc_show_class_members', True, True) app.add_config_value('numpydoc_show_inherited_class_members', True, True) app.add_config_value('numpydoc_class_members_toctree', True, True) # Extra mangling domains app.add_domain(NumpyPythonDomain) app.add_domain(NumpyCDomain) # ------------------------------------------------------------------------------ # Docstring-mangling domains # ------------------------------------------------------------------------------ from docutils.statemachine import ViewList from sphinx.domains.c import CDomain from sphinx.domains.python import PythonDomain class ManglingDomainBase: directive_mangling_map = {} def __init__(self, *a, **kw): super().__init__(*a, **kw) self.wrap_mangling_directives() def wrap_mangling_directives(self): for name, objtype in list(self.directive_mangling_map.items()): self.directives[name] = wrap_mangling_directive( self.directives[name], objtype) class NumpyPythonDomain(ManglingDomainBase, PythonDomain): name = 'np' directive_mangling_map = { 'function': 'function', 'class': 'class', 'exception': 'class', 'method': 'function', 'classmethod': 'function', 'staticmethod': 'function', 'attribute': 'attribute', } indices = [] class NumpyCDomain(ManglingDomainBase, CDomain): name = 'np-c' directive_mangling_map = { 'function': 'function', 'member': 'attribute', 'macro': 'function', 'type': 'class', 'var': 'object', } def wrap_mangling_directive(base_directive, objtype): class directive(base_directive): def run(self): env = self.state.document.settings.env name = None if self.arguments: m = re.match(r'^(.*\s+)?(.*?)(\(.*)?', self.arguments[0]) name = m.group(2).strip() if not name: name = self.arguments[0] lines = list(self.content) mangle_docstrings(env.app, objtype, name, None, None, lines) self.content = ViewList(lines, self.content.parent) return base_directive.run(self) return directive sympy-sympy-1.9/doc/ext/sympylive.py000066400000000000000000000023351412543434000177060ustar00rootroot00000000000000""" sympylive ~~~~~~~~~ Allow `SymPy Live `_ to be used for interactive evaluation of SymPy's code examples. :copyright: Copyright 2014 by the SymPy Development Team, see AUTHORS. :license: BSD, see LICENSE for details. """ def builder_inited(app): if not app.config.sympylive_url: raise ExtensionError('sympylive_url config value must be set' ' for the sympylive extension to work') app.add_js_file(app.config.sympylive_url + '/static/utilities.js') app.add_js_file(app.config.sympylive_url + '/static/external/classy.js') app.add_css_file(app.config.sympylive_url + '/static/live-core.css') app.add_css_file(app.config.sympylive_url + '/static/live-autocomplete.css') app.add_css_file(app.config.sympylive_url + '/static/live-sphinx.css') app.add_js_file(app.config.sympylive_url + '/static/live-core.js') app.add_js_file(app.config.sympylive_url + '/static/live-autocomplete.js') app.add_js_file(app.config.sympylive_url + '/static/live-sphinx.js') def setup(app): app.add_config_value('sympylive_url', 'https://live.sympy.org', False) app.connect('builder-inited', builder_inited) sympy-sympy-1.9/doc/generate_logos.py000077500000000000000000000224001412543434000200400ustar00rootroot00000000000000#!/usr/bin/env python """ This script creates logos of different formats from the source "sympy.svg" Requirements: rsvg-convert - for converting to *.png format (librsvg2-bin deb package) imagemagick - for converting to *.ico favicon format """ from argparse import ArgumentParser import xml.dom.minidom import os.path import logging import subprocess import sys default_source_dir = os.path.join(os.path.dirname(__file__), "src/logo") default_source_svg = "sympy.svg" default_output_dir = os.path.join(os.path.dirname(__file__), "_build/logo") # those are the options for resizing versions without tail or text svg_sizes = {} svg_sizes['notail'] = { "prefix":"notail", "dx":-70, "dy":-20, "size":690, "title":"SymPy Logo, with no tail"} svg_sizes['notail-notext'] = { "prefix":"notailtext", "dx":-70, "dy":60, "size":690, "title":"SymPy Logo, with no tail, no text"} svg_sizes['notext'] = { "prefix":"notext", "dx":-7, "dy":90, "size":750, "title":"SymPy Logo, with no text"} # The list of identifiers of various versions versions = ['notail', 'notail-notext', 'notext'] parser = ArgumentParser(usage="%(prog)s [options ...]") parser.add_argument("--source-dir", type=str, dest="source_dir", help="Directory of the source *.svg file [default: %(default)s]", default=default_source_dir) parser.add_argument("--source-svg", type=str, dest="source_svg", help="File name of the source *.svg file [default: %(default)s]", default=default_source_svg) parser.add_argument("--svg", action="store_true", dest="generate_svg", help="Generate *.svg versions without tails " \ "and without text 'SymPy' [default: %(default)s]", default=False) parser.add_argument("--png", action="store_true", dest="generate_png", help="Generate *.png versions [default: %(default)s]", default=False) parser.add_argument("--ico", action="store_true", dest="generate_ico", help="Generate *.ico versions [default: %(default)s]", default=False) parser.add_argument("--clear", action="store_true", dest="clear", help="Remove temporary files [default: %(default)s]", default=False) parser.add_argument("-a", "--all", action="store_true", dest="generate_all", help="Shorthand for '--svg --png --ico --clear' options " \ "[default: %(default)s]", default=True) parser.add_argument("-s", "--sizes", type=str, dest="sizes", help="Sizes of png pictures [default: %(default)s]", default="160,500") parser.add_argument("--icon-sizes", type=str, dest="icon_sizes", help="Sizes of icons embedded in favicon file [default: %(default)s]", default="16,32,48,64") parser.add_argument("--output-dir", type=str, dest="output_dir", help="Output dir [default: %(default)s]", default=default_output_dir) parser.add_argument("-d", "--debug", action="store_true", dest="debug", help="Print debug log [default: %(default)s]", default=False) def main(): options, args = parser.parse_known_args() if options.debug: logging.basicConfig(level=logging.DEBUG) fn_source = os.path.join(options.source_dir, options.source_svg) if options.generate_svg or options.generate_all: generate_notail_notext_versions(fn_source, options.output_dir) if options.generate_png or options.generate_all: sizes = options.sizes.split(",") sizes = [int(s) for s in sizes] convert_to_png(fn_source, options.output_dir, sizes) if options.generate_ico or options.generate_all: sizes = options.icon_sizes.split(",") sizes = [int(s) for s in sizes] convert_to_ico(fn_source, options.output_dir, sizes) def generate_notail_notext_versions(fn_source, output_dir): for ver in versions: properties = svg_sizes[ver] doc = load_svg(fn_source) (notail, notext) = versionkey_to_boolean_tuple(ver) g_tail = searchElementById(doc, "SnakeTail", "g") if notail: g_tail.setAttribute("display", "none") g_text = searchElementById(doc, "SymPy_text", "g") if notext: g_text.setAttribute("display", "none") g_logo = searchElementById(doc, "SympyLogo", "g") dx = properties["dx"] dy = properties["dy"] transform = "translate(%d,%d)" % (dx, dy) g_logo.setAttribute("transform", transform) svg = searchElementById(doc, "svg_SympyLogo", "svg") newsize = properties["size"] svg.setAttribute("width", "%d" % newsize) svg.setAttribute("height", "%d" % newsize) title = svg.getElementsByTagName("title")[0] title.firstChild.data = properties["title"] desc = svg.getElementsByTagName("desc")[0] desc.appendChild( doc.createTextNode( "\n\nThis file is generated from %s !" % fn_source)) fn_out = get_svg_filename_from_versionkey(fn_source, ver) fn_out = os.path.join(output_dir, fn_out) save_svg(fn_out, doc) def convert_to_png(fn_source, output_dir, sizes): svgs = list(versions) svgs.insert(0, '') cmd = "rsvg-convert" p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.communicate() if p.returncode == 127: logging.error( "%s: command not found. Install librsvg" % cmd) sys.exit(p.returncode) for ver in svgs: if ver == '': fn_svg = fn_source else: fn_svg = get_svg_filename_from_versionkey(fn_source, ver) fn_svg = os.path.join(output_dir, fn_svg) basename = os.path.basename(fn_svg) name, ext = os.path.splitext(basename) for size in sizes: fn_out = "%s-%dpx.png" % (name, size) fn_out = os.path.join(output_dir, fn_out) cmd = "rsvg-convert %s -f png -o %s -h %d -w %d" % (fn_svg, fn_out, size, size) p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.communicate() if p.returncode != 0: logging.error("Return code is not 0: Command: %s" % cmd) logging.error("return code: %s" % p.returncode) sys.exit(p.returncode) else: logging.debug("command: %s" % cmd) logging.debug("return code: %s" % p.returncode) def convert_to_ico(fn_source, output_dir, sizes): # firstly prepare *.png files, which will be embedded # into the *.ico files. convert_to_png(fn_source, output_dir, sizes) svgs = list(versions) svgs.insert(0, '') cmd = "convert" p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.communicate() if p.returncode == 127: logging.error("%s: command not found. Install imagemagick" % cmd) sys.exit(p.returncode) for ver in svgs: if ver == '': fn_svg = fn_source else: fn_svg = get_svg_filename_from_versionkey(fn_source, ver) fn_svg = os.path.join(output_dir, fn_svg) basename = os.path.basename(fn_svg) name, ext = os.path.splitext(basename) # calculate the list of *.png files pngs = [] for size in sizes: fn_png= "%s-%dpx.png" % (name, size) fn_png = os.path.join(output_dir, fn_png) pngs.append(fn_png) # convert them to *.ico fn_out = "%s-favicon.ico" % name fn_out = os.path.join(output_dir, fn_out) cmd = "convert {} {}".format(" ".join(pngs), fn_out) p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) p.communicate() if p.returncode != 0: logging.error("Return code is not 0: Command: %s" % cmd) logging.error("return code: %s" % p.returncode) sys.exit(p.returncode) else: logging.debug("command: %s" % cmd) logging.debug("return code: %s" % p.returncode) def versionkey_to_boolean_tuple(ver): notail = False notext = False vers = ver.split("-") notail = 'notail' in vers notext = 'notext' in vers return (notail, notext) def get_svg_filename_from_versionkey(fn_source, ver): basename = os.path.basename(fn_source) if ver == '': return basename name, ext = os.path.splitext(basename) prefix = svg_sizes[ver]["prefix"] fn_out = "{}-{}.svg".format(name, prefix) return fn_out def searchElementById(node, Id, tagname): """ Search element by id in all the children and descendants of node. id is lower case, not ID which is usually used for getElementById """ nodes = node.getElementsByTagName(tagname) for node in nodes: an = node.getAttributeNode('id') if an and an.nodeValue == Id: return node def load_svg(fn): doc = xml.dom.minidom.parse(fn) return doc def save_svg(fn, doc): with open(fn, "wb") as f: xmlstr = doc.toxml("utf-8") f.write(xmlstr) logging.info(" File saved: %s" % fn) main() sympy-sympy-1.9/doc/man/000077500000000000000000000000001412543434000152435ustar00rootroot00000000000000sympy-sympy-1.9/doc/man/isympy.1000066400000000000000000000150031412543434000166560ustar00rootroot00000000000000'\" -*- coding: us-ascii -*- .if \n(.g .ds T< \\FC .if \n(.g .ds T> \\F[\n[.fam]] .de URL \\$2 \(la\\$1\(ra\\$3 .. .if \n(.g .mso www.tmac .TH isympy 1 2007-10-8 "" "" .SH NAME isympy \- interactive shell for SymPy .SH SYNOPSIS 'nh .fi .ad l \fBisympy\fR \kx .if (\nx>(\n(.l/2)) .nr x (\n(.l/5) 'in \n(.iu+\nxu [\fB-c\fR | \fB--console\fR] [\fB-p\fR ENCODING | \fB--pretty\fR ENCODING] [\fB-t\fR TYPE | \fB--types\fR TYPE] [\fB-o\fR ORDER | \fB--order\fR ORDER] [\fB-q\fR | \fB--quiet\fR] [\fB-d\fR | \fB--doctest\fR] [\fB-C\fR | \fB--no-cache\fR] [\fB-a\fR | \fB--auto\fR] [\fB-D\fR | \fB--debug\fR] [ -- | PYTHONOPTIONS] 'in \n(.iu-\nxu .ad b 'hy 'nh .fi .ad l \fBisympy\fR \kx .if (\nx>(\n(.l/2)) .nr x (\n(.l/5) 'in \n(.iu+\nxu [ {\fB-h\fR | \fB--help\fR} | {\fB-v\fR | \fB--version\fR} ] 'in \n(.iu-\nxu .ad b 'hy .SH DESCRIPTION isympy is a Python shell for SymPy. It is just a normal python shell (ipython shell if you have the ipython package installed) that executes the following commands so that you don't have to: .PP .nf \*(T< >>> from __future__ import division >>> from sympy import * >>> x, y, z = symbols("x,y,z") >>> k, m, n = symbols("k,m,n", integer=True) \*(T> .fi .PP So starting isympy is equivalent to starting python (or ipython) and executing the above commands by hand. It is intended for easy and quick experimentation with SymPy. For more complicated programs, it is recommended to write a script and import things explicitly (using the "from sympy import sin, log, Symbol, ..." idiom). .SH OPTIONS .TP \*(T<\fB\-c \fR\*(T>\fISHELL\fR, \*(T<\fB\-\-console=\fR\*(T>\fISHELL\fR Use the specified shell (python or ipython) as console backend instead of the default one (ipython if present or python otherwise). Example: isympy -c python \fISHELL\fR could be either \&'ipython' or 'python' .TP \*(T<\fB\-p \fR\*(T>\fIENCODING\fR, \*(T<\fB\-\-pretty=\fR\*(T>\fIENCODING\fR Setup pretty printing in SymPy. By default, the most pretty, unicode printing is enabled (if the terminal supports it). You can use less pretty ASCII printing instead or no pretty printing at all. Example: isympy -p no \fIENCODING\fR must be one of 'unicode', \&'ascii' or 'no'. .TP \*(T<\fB\-t \fR\*(T>\fITYPE\fR, \*(T<\fB\-\-types=\fR\*(T>\fITYPE\fR Setup the ground types for the polys. By default, gmpy ground types are used if gmpy2 or gmpy is installed, otherwise it falls back to python ground types, which are a little bit slower. You can manually choose python ground types even if gmpy is installed (e.g., for testing purposes). Note that sympy ground types are not supported, and should be used only for experimental purposes. Note that the gmpy1 ground type is primarily intended for testing; it the use of gmpy even if gmpy2 is available. This is the same as setting the environment variable SYMPY_GROUND_TYPES to the given ground type (e.g., SYMPY_GROUND_TYPES='gmpy') The ground types can be determined interactively from the variable sympy.polys.domains.GROUND_TYPES inside the isympy shell itself. Example: isympy -t python \fITYPE\fR must be one of 'gmpy', \&'gmpy1' or 'python'. .TP \*(T<\fB\-o \fR\*(T>\fIORDER\fR, \*(T<\fB\-\-order=\fR\*(T>\fIORDER\fR Setup the ordering of terms for printing. The default is lex, which orders terms lexicographically (e.g., x**2 + x + 1). You can choose other orderings, such as rev-lex, which will use reverse lexicographic ordering (e.g., 1 + x + x**2). Note that for very large expressions, ORDER='none' may speed up printing considerably, with the tradeoff that the order of the terms in the printed expression will have no canonical order Example: isympy -o rev-lax \fIORDER\fR must be one of 'lex', 'rev-lex', 'grlex', \&'rev-grlex', 'grevlex', 'rev-grevlex', 'old', or 'none'. .TP \*(T<\fB\-q\fR\*(T>, \*(T<\fB\-\-quiet\fR\*(T> Print only Python's and SymPy's versions to stdout at startup, and nothing else. .TP \*(T<\fB\-d\fR\*(T>, \*(T<\fB\-\-doctest\fR\*(T> Use the same format that should be used for doctests. This is equivalent to '\fIisympy -c python -p no\fR'. .TP \*(T<\fB\-C\fR\*(T>, \*(T<\fB\-\-no\-cache\fR\*(T> Disable the caching mechanism. Disabling the cache may slow certain operations down considerably. This is useful for testing the cache, or for benchmarking, as the cache can result in deceptive benchmark timings. This is the same as setting the environment variable SYMPY_USE_CACHE to 'no'. .TP \*(T<\fB\-a\fR\*(T>, \*(T<\fB\-\-auto\fR\*(T> Automatically create missing symbols. Normally, typing a name of a Symbol that has not been instantiated first would raise NameError, but with this option enabled, any undefined name will be automatically created as a Symbol. This only works in IPython 0.11. Note that this is intended only for interactive, calculator style usage. In a script that uses SymPy, Symbols should be instantiated at the top, so that it's clear what they are. This will not override any names that are already defined, which includes the single character letters represented by the mnemonic QCOSINE (see the "Gotchas and Pitfalls" document in the documentation). You can delete existing names by executing "del name" in the shell itself. You can see if a name is defined by typing "'name' in globals()". The Symbols that are created using this have default assumptions. If you want to place assumptions on symbols, you should create them using symbols() or var(). Finally, this only works in the top level namespace. So, for example, if you define a function in isympy with an undefined Symbol, it will not work. .TP \*(T<\fB\-D\fR\*(T>, \*(T<\fB\-\-debug\fR\*(T> Enable debugging output. This is the same as setting the environment variable SYMPY_DEBUG to 'True'. The debug status is set in the variable SYMPY_DEBUG within isympy. .TP -- \fIPYTHONOPTIONS\fR These options will be passed on to \fIipython (1)\fR shell. Only supported when ipython is being used (standard python shell not supported). Two dashes (--) are required to separate \fIPYTHONOPTIONS\fR from the other isympy options. For example, to run iSymPy without startup banner and colors: isympy -q -c ipython -- --colors=NoColor .TP \*(T<\fB\-h\fR\*(T>, \*(T<\fB\-\-help\fR\*(T> Print help output and exit. .TP \*(T<\fB\-v\fR\*(T>, \*(T<\fB\-\-version\fR\*(T> Print isympy version information and exit. .SH FILES .TP \*(T<\fI${HOME}/.sympy\-history\fR\*(T> Saves the history of commands when using the python shell as backend. .SH BUGS The upstreams BTS can be found at \(lahttps://github.com/sympy/sympy/issues\(ra Please report all bugs that you find in there, this will help improve the overall quality of SymPy. .SH "SEE ALSO" \fBipython\fR(1), \fBpython\fR(1) sympy-sympy-1.9/doc/man/isympy.xml000066400000000000000000000426641412543434000173330ustar00rootroot00000000000000 ]> &dhtitle; &dhpackage; &dhrelease; &dhdate; Ondrej Certik Design, programming.
ondrej@certik.cz
&dhfirstname; &dhsurname; Programming.
&dhemail;
2013 SymPy Development Team Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
&dhucpackage; &dhsection; &dhpackage; interactive shell for SymPy &dhpackage; ENCODING ENCODING TYPE TYPE ORDER ORDER -- PYTHONOPTIONS &dhpackage; DESCRIPTION isympy is a Python shell for SymPy. It is just a normal python shell (ipython shell if you have the ipython package installed) that executes the following commands so that you don't have to: >>> from __future__ import division >>> from sympy import * >>> x, y, z = symbols("x,y,z") >>> k, m, n = symbols("k,m,n", integer=True) So starting isympy is equivalent to starting python (or ipython) and executing the above commands by hand. It is intended for easy and quick experimentation with SymPy. For more complicated programs, it is recommended to write a script and import things explicitly (using the "from sympy import sin, log, Symbol, ..." idiom). OPTIONS Use the specified shell (python or ipython) as console backend instead of the default one (ipython if present or python otherwise). Example: isympy -c python SHELL could be either 'ipython' or 'python' Setup pretty printing in SymPy. By default, the most pretty, unicode printing is enabled (if the terminal supports it). You can use less pretty ASCII printing instead or no pretty printing at all. Example: isympy -p no ENCODING must be one of 'unicode', 'ascii' or 'no'. Setup the ground types for the polys. By default, gmpy ground types are used if gmpy2 or gmpy is installed, otherwise it falls back to python ground types, which are a little bit slower. You can manually choose python ground types even if gmpy is installed (e.g., for testing purposes). Note that sympy ground types are not supported, and should be used only for experimental purposes. Note that the gmpy1 ground type is primarily intended for testing; it the use of gmpy even if gmpy2 is available. This is the same as setting the environment variable SYMPY_GROUND_TYPES to the given ground type (e.g., SYMPY_GROUND_TYPES='gmpy') The ground types can be determined interactively from the variable sympy.polys.domains.GROUND_TYPES inside the isympy shell itself. Example: isympy -t python TYPE must be one of 'gmpy', 'gmpy1' or 'python'. Setup the ordering of terms for printing. The default is lex, which orders terms lexicographically (e.g., x**2 + x + 1). You can choose other orderings, such as rev-lex, which will use reverse lexicographic ordering (e.g., 1 + x + x**2). Note that for very large expressions, ORDER='none' may speed up printing considerably, with the tradeoff that the order of the terms in the printed expression will have no canonical order Example: isympy -o rev-lax ORDER must be one of 'lex', 'rev-lex', 'grlex', 'rev-grlex', 'grevlex', 'rev-grevlex', 'old', or 'none'. Print only Python's and SymPy's versions to stdout at startup, and nothing else. Use the same format that should be used for doctests. This is equivalent to 'isympy -c python -p no'. Disable the caching mechanism. Disabling the cache may slow certain operations down considerably. This is useful for testing the cache, or for benchmarking, as the cache can result in deceptive benchmark timings. This is the same as setting the environment variable SYMPY_USE_CACHE to 'no'. Automatically create missing symbols. Normally, typing a name of a Symbol that has not been instantiated first would raise NameError, but with this option enabled, any undefined name will be automatically created as a Symbol. This only works in IPython 0.11. Note that this is intended only for interactive, calculator style usage. In a script that uses SymPy, Symbols should be instantiated at the top, so that it's clear what they are. This will not override any names that are already defined, which includes the single character letters represented by the mnemonic QCOSINE (see the "Gotchas and Pitfalls" document in the documentation). You can delete existing names by executing "del name" in the shell itself. You can see if a name is defined by typing "'name' in globals()". The Symbols that are created using this have default assumptions. If you want to place assumptions on symbols, you should create them using symbols() or var(). Finally, this only works in the top level namespace. So, for example, if you define a function in isympy with an undefined Symbol, it will not work. Enable debugging output. This is the same as setting the environment variable SYMPY_DEBUG to 'True'. The debug status is set in the variable SYMPY_DEBUG within isympy. -- PYTHONOPTIONS These options will be passed on to ipython (1) shell. Only supported when ipython is being used (standard python shell not supported). Two dashes (--) are required to separate PYTHONOPTIONS from the other isympy options. For example, to run iSymPy without startup banner and colors: isympy -q -c ipython -- --colors=NoColor Print help output and exit. Print isympy version information and exit. FILES ${HOME}/.sympy-history Saves the history of commands when using the python shell as backend. BUGS The upstreams BTS can be found at https://github.com/sympy/sympy/issues Please report all bugs that you find in there, this will help improve the overall quality of SymPy. SEE ALSO ipython 1 , python 1
sympy-sympy-1.9/doc/src/000077500000000000000000000000001412543434000152575ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/_static/000077500000000000000000000000001412543434000167055ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/_static/default.css_t000066400000000000000000000152011412543434000213650ustar00rootroot00000000000000/* * default.css_t * ~~~~~~~~~~~~~ * * Sphinx stylesheet -- default theme. * * :copyright: Copyright 2007-2013 by the Sphinx team, see AUTHORS. * :license: BSD, see LICENSE for details. * */ @import url("classic.css"); @import url(https://fonts.googleapis.com/css?family=Open+Sans); /* -- page layout ----------------------------------------------------------- */ {% set theme_collapsiblesidebar = True %} {% set theme_relbarbgcolor = '#2f441e' %} {% set theme_sidebarbgcolor = '#3b5526' %} {% set theme_sidebarbtncolor = '#4F663C' %} {% set theme_sidebarlinkcolor = '#81B953' %} {% set theme_linkcolor = '#29A329' %} {% set theme_visitedlinkcolor = '#307748' %} {% set theme_headtextcolor = '#2f441e' %} {% set theme_footerbgcolor = '#293b1b' %} {% set theme_headlinkcolor = '#AAAAAA' %} {% set theme_sidebartextcolor = '#DDDDDD' %} {% set theme_footertextcolor = '#DDDDDD' %} {% set theme_relbartextcolor = '#DDDDDD' %} {% set theme_relbarlinkcolor = '#81B953' %} {% set theme_bgcolor = '#FFFFFF' %} body { font-family: Open Sans, sans-serif; font-size: 100%; background-color: {{ theme_footerbgcolor }}; color: #000; margin: 0; padding: 0; } div.document { background-color: {{ theme_sidebarbgcolor }}; } div.documentwrapper { float: left; width: 100%; } div.bodywrapper { margin: 0 200px 0 {{ theme_sidebarwidth|toint }}px; } div.body { background-color: {{ theme_bgcolor }}; color: {{ theme_textcolor }}; padding: 0 20px 30px 20px; } {%- if theme_rightsidebar|tobool %} div.bodywrapper { margin: 0 {{ theme_sidebarwidth|toint }}px 0 0; } {%- endif %} div.footer { color: {{ theme_footertextcolor }}; width: 100%; padding: 9px 0 9px 0; text-align: center; font-size: 75%; } div.footer a { color: {{ theme_footertextcolor }}; text-decoration: underline; } div.related { background-color: {{ theme_relbarbgcolor }}; line-height: 30px; color: {{ theme_relbartextcolor }}; } div.related a { color: {{ theme_relbarlinkcolor }}; } div.sphinxsidebar { {%- if theme_stickysidebar|tobool %} top: 30px; bottom: 0; margin: 0; position: fixed; overflow: auto; height: auto; {%- endif %} {%- if theme_rightsidebar|tobool %} float: right; {%- if theme_stickysidebar|tobool %} right: 0; {%- endif %} {%- endif %} } {%- if theme_stickysidebar|tobool %} /* this is nice, but it it leads to hidden headings when jumping to an anchor */ /* div.related { position: fixed; } div.documentwrapper { margin-top: 30px; } */ {%- endif %} div.sphinxsidebar h3 { font-family: {{ theme_headfont }}; color: {{ theme_sidebartextcolor }}; font-size: 1.4em; font-weight: normal; margin: 0; padding: 0; } div.sphinxsidebar h3 a { color: {{ theme_sidebartextcolor }}; } div.sphinxsidebar h4 { font-family: {{ theme_headfont }}; color: {{ theme_sidebartextcolor }}; font-size: 1.3em; font-weight: normal; margin: 5px 0 0 0; padding: 0; } div.sphinxsidebar p { color: {{ theme_sidebartextcolor }}; } div.sphinxsidebar p.topless { margin: 5px 10px 10px 10px; } div.sphinxsidebar ul { margin: 10px; padding: 0; color: {{ theme_sidebartextcolor }}; } div.sphinxsidebar a { color: {{ theme_sidebarlinkcolor }}; } div.sphinxsidebar input { border: 1px solid {{ theme_sidebarlinkcolor }}; font-family: sans-serif; font-size: 1em; } {% if theme_collapsiblesidebar|tobool %} /* for collapsible sidebar */ div#sidebarbutton { background-color: {{ theme_sidebarbtncolor }}; } {% endif %} /* -- hyperlink styles ------------------------------------------------------ */ a { color: {{ theme_linkcolor }}; text-decoration: none; } a:visited { color: {{ theme_visitedlinkcolor }}; text-decoration: none; } a:hover { text-decoration: underline; } {% if theme_externalrefs|tobool %} a.external { text-decoration: none; border-bottom: 1px dashed {{ theme_linkcolor }}; } a.external:hover { text-decoration: none; border-bottom: none; } a.external:visited { text-decoration: none; border-bottom: 1px dashed {{ theme_visitedlinkcolor }}; } {% endif %} /* -- body styles ----------------------------------------------------------- */ div.body h1, div.body h2, div.body h3, div.body h4, div.body h5, div.body h6 { font-family: {{ theme_headfont }}; background-color: {{ theme_headbgcolor }}; font-weight: normal; color: {{ theme_headtextcolor }}; border-bottom: 1px solid #ccc; margin: 20px -20px 10px -20px; padding: 3px 0 3px 10px; } div.body h1 { margin-top: 0; font-size: 200%; } div.body h2 { font-size: 160%; } div.body h3 { font-size: 140%; } div.body h4 { font-size: 120%; } div.body h5 { font-size: 110%; } div.body h6 { font-size: 100%; } a.headerlink { color: {{ theme_headlinkcolor }}; font-size: 0.8em; padding: 0 4px 0 4px; text-decoration: none; } a.headerlink:hover { background-color: {{ theme_headlinkcolor }}; color: white; } div.body p, div.body dd, div.body li { text-align: left; line-height: 130%; } div.admonition p.admonition-title + p { display: inline; } div.admonition p { margin-bottom: 5px; } div.admonition pre { margin-bottom: 5px; } div.admonition ul, div.admonition ol { margin-bottom: 5px; } div.note { background-color: #eee; border: 1px solid #ccc; } div.seealso { background-color: #ffc; border: 1px solid #ff6; } div.topic { background-color: #eee; } div.warning { background-color: #ffe4e4; border: 1px solid #f66; } p.admonition-title { display: inline; } p.admonition-title:after { content: ":"; } pre { font-family: DejaVu Sans Mono, monospace; font-size: 100%; padding: 5px; background-color: {{ theme_codebgcolor }}; color: {{ theme_codetextcolor }}; line-height: 120%; border: 1px solid #ac9; border-left: none; border-right: none; } tt { background-color: #ecf0f3; padding: 0 1px 0 1px; font-size: 0.95em; } th { background-color: #ede; } .warning tt { background: #efc2c2; } .note tt { background: #d6d6d6; } .viewcode-back { font-family: {{ theme_bodyfont }}; } div.viewcode-block:target { background-color: #f4debf; border-top: 1px solid #ac9; border-bottom: 1px solid #ac9; } /* To highlight inline code blocks */ code{ background-color: #ECF0F3; border-radius: 3px; padding: 2px; } p.rubric { font-size: 18px; color: #2f441e; font-family: "Trebuchet MS", sans-serif; } /* To fit long MathJax equations inside the document body */ .MathJax_Display { overflow: auto hidden; } sympy-sympy-1.9/doc/src/_static/sympylogo.png000066400000000000000000000463771412543434000214760ustar00rootroot00000000000000PNG  IHDRofo sRGBbKGDRhj" pHYs XtIME [Zۇ IDATxg]Yz>n.B7: lNaMMeqʢ*?,rlIU,%"KT`g ':ZϽ@dUup{w/,xw;wǻe<3ϝ;;F|sΕw6ĻSsO}js"IԈScXj o !Y@?w']`*QJױƎ.Li~?6wފa/Yo<ֻ]`PX%MՌm\ ^yz:?6Z屇t4UlyUnb֬mlnwzDE_i': !:೺s"}u_ѿ;٧Oq+/S>#eLMVh'Ņ A۷v{k+o1IC(FIS5~h@"ZGBXk]!:px^k͋痖x3>KD?I ){}ywɉ#3#ӎc26^$!/6RHXi l@i,GbӖCS 4VThIbE)T$J'iѩFDv !.-K4R,NNTO^=sۻ|Y٥nŒ`|gha60Lc{ QZ#H!!@?K `Rķ,(!NJiD vZZۢ @JR B4{߹x~[#$lxt|78PZy9ǵNWc c łoy~Vԛml/Y&9X`~LβJ`K# 6 ީcJ$*aq|j9Cbzz QBD%eX)4!N;.ke0Q-&)kv{mZ1A;!4RXx;*lx(<39G$}R)q={ı),=MK_fKA#g<0c>KXù\|d*M/pk~G(hZwpmɃG_7Rť-xjTHEC3㌗RYi՛تHLh8:CRiJ;h!^LRC:)ZZ-!o³Wҷ+w*3|cI`_}ł7<350>V/̍sd _?r903"&4KE$Z*H)p^Ӊ"iҊt!ʓjEH03R;:z!`sIH$cqbj H)qM/ZgHϠ=>pr4B &BUA1)q4RHC  |RRNc@?CeNL-uc9_}%Ro f(r2c%ʾ˔5M:juDXDͤp%hYh֬6xJ5I1 i S"d(NG a`[bp[NRFg<0=J5H)eQ.lыb,#8v~^;݉q_ܶ; J>/.<{4oʌBC0;w'!s9<{l||XOc)Q񻿏X /z0cC9Uף8ӄnx*~;OBlM GrBEM6^;%bTC*љ`tw4 )0 ob3p}3p=1Xt IL!L 4Y6wQd0߶x9FH*^K_N3R Bך^WkkBXZI!)Q!ė/_ZQ۬~$p\;wRzdZx c/X'O.ih!֚_\t5xLM)(uilv4V^Ð;ZLIH !;)BH5JyHCU",`yEhZGm윑_iZABƖPt !E1_L'IS( _7_ 9`kArVZ\x8{h%BrsPa|vfd~t,N,Nqt~\"MA~U4_[TxG/]t~@;v2!4cnj&R CI& 4FOF Rb&a`4- c蠆(QZ"c0IBH B(!)ؾAa&?jSVNbx?g7mrmH\fneH$ǎMU1n}zԶ=ucbULܢ֫]n:'BHB|+?,@`7;wT W \ת\{x^J9ד=or+hw_Y~~Cerڝ>;۽.0*(\D~ք@4FK!ЩBig;+ .B PXA>351L\,J<ա"`YRi*_{ݭ ibZ6Չ)ȗnv{nd40 L["-[0?ct˖-˜zGq,'͒L|Ӣlt:t^Ne] C *aҵ}^vbCԵ? 8ۑ>яZt]?=}Ţ_92=Vg8u|Z-$DCZ)΢#in6>e6O'b\B G4:( 5qJo`v<^=XE u)x9F %Me6Ng8%nˢ *T)T866g-*X9xϵ1-4qAϗ>)i`;.1p')WGIuڽפ$7sW8z4'N^-OW^FaYq~q bRdv!%Ef.c@)%vcWօNx~~)?wzk5<<,,"P[X ,Nw=8MFG823ƃ%MSTL##֗o3{$wnji7GX+'v_ )36][s_34F&&9L2 \oџrqUZnǫǜ%h)-9Ugۡh1dT"՚翱ɕ?Gܾ;zS+.YvW)ismGĩbfjr9Gki"MR6WY}mbxM0F K(7z\P'M48L,\Te'A*G$0- >r1Ro ΃40L;\v!R>{b kF._,1˗; OY``&9"Hb W#0T*83[x}%6^ӿwSgܼo; !%'xDEljA?1^R«_兗oա~񵫦01Ƿ,|ӢvIk]LK)e :_B4Saܼr;7rsecZ6C#c-~C$I­+/013= #o5;mhvg?X%Ű5 sx΍RM#  [`;I*pG?X{4m{@{3k`{-.ڢ2WLrv}X#S-cZ݀ݍ݉(LdR6m&fAEOÅ|駙]`f(QJ!,ɼAxQw56hw8Qfʇ=oR=/P~l*JD+4!<*Ei138Uoz][ϵrg>g*H-WC`~SKD!]ddH'?0qҔfK/s_DJm;LLpA&g1 8h)W-Zr`/&IʥV|uN'`{>^XGefefZM?:bG(J=E$PZ뒳,V vP]X4RDA tPK>|Sx+Ϙ;H)ȍX I8UBKL 4 ̊i770`qqQrpPI'ɟye6oWce|fr䑹C&3 [춸qkkiw:R(L0L>o&Y[ ?O ^'ZЧJюD{8~yEJ|_5yfyUK+6u%-R.]pMS] `c;[זᡒs191$==Ǒ&0>5JL[0DY]^|:Vz18}rƱM . FQc[C C} s&Qʄ&q-ֶElB*^pxݑ3>痾x^,||JkV^94ϲ*Rܦ\! H>(Ya LX8OM\V7כ,/[7S*ΌPJAkEf.WVثi/ fr@fu?J{٧ORO?dӃsDZmn*nAD!QTb.RY*k_\baq6[ӏlr%*J8VGZ @)1Ṯ^#h%Tl$.CYmwN-wk׸ugC U TJum 5$I±!>#Tʙ\uE?o_]/.ֶ~ܰw 4!5޴V*)3Xʿ'sA1K[\z#EFJ9ʕkuT㔌Ck\:-ZCeĦJDTTdZu,>AH` +hے?ᆴ y[| n+~ӧ~Ǵ՗6VBG-  `A6.M l7oي|`aVvRDq&w҄HxcIYƻx'\l^\ZĔzӷb;a-2 3dZiV/g>| ^>ZT4Q \F)<_1unIܨEyɊBi>z4B3V~A >CyCMU4D0!LSZaİg0˱2R03йpa8ct$+7`jvɱ9x~^³W>}SZ[)=5OiC.B mR,zAk#%bCj5G>NTxY˯cə*S3U6vÔR2D(du)X6~3)}[ [;]8aT`kܑoKQRJ{;nu<ӧ ^ aX)8~; B,_M}vsBB$:d)+w~]fdmztz z\V8AB|rgYV?}_؉)%aꭕ7\}y٠obu+_+~UqxMk}ɘvZK֚&m҉R7C#Xm.9Dq Ҕ;A;b2K!+jWYigPJEx\ɺc(˲& +MzQ2O:`ՋoYY3E IDAT~Νo]7B:36Yq-~ϔD_V"Niz-%S#nA :zaDo'8{&Yͭ6…|[H)*Y  ;*qmw9"4ט82aoYzqÈm x[Ǽk|ryߘWX~ry SOq;o\+xyջdGZ`Bӯ(timL b/2PY{!ż&ٻ֧ڈmϾoEGthv9?O]<8( QJ34R%M A-}#-0cJ=翡'30Wގ˹Pdz%V>n隂Ш-,j60Pꔊv t"FhN&qEw}vpe!s,sCA^0LyX/B<~?~_^Jg,!9,=z|btyRhY4u [(H#K&Xi6 IU@C(C˸r-f,'iu a<NDs5ٍmwӯ̟|J#Mrd|*kwQ?GLoht>mDiw7rҾ2PBO̖bYk,?sZoR*Ҳfd洋@$ aآƸ3eH%l,'9 9!(E+hF!(db1>V_s\]2$Ӯːkg]޴K H<'5Rh:l%WKTPU~#QVBJD?{M&z@H>!$c!n7˧ \faEN$Kdgm)z7?Y+KFm|amA\%U'˸$}8=>Jޱ)4!JS4 U]IB~OȢi[ZFK˼,5Ea%I9qdSXA2@_j4UT4(MuR%q:+@A#ܿd^k}A5duɹoK/fLLqa?fv¥kiz"֫,;Oi4}ZCS0jH#B2<,uZa(FM;xP^SZ5~$7l1X^-a-v+K|ի8ɇx=|T 4I\`|jR ɦJ+4ZJD)+$QA~%ɼO)uQS htBގ~3B3yɹ 4#)͈@B0>Ym3L͗);Z6 >_{HPp,VJgf0S,25TbnBZiex>~T+Z;uA(MRp/(7`^UMNJԭw#v̀ooO^U$IƠҐ>a*A,Br: L0:=n Jb^R2`Dҽ4:R蓚vV?c0Hӵ-yuԓBr֔Qݝ?A9;?-)=~9^k}i_t(<ʅіH"C0[_v֚v+;ElZ~43#eJ.I+8!c=ƚ;_mB/\_9{eQ};۫XRJ6W74)?o/0wJsckZ-ChK8Z vu|bDz.]Үe-T)"k0daSlujvt!ߖ<ݗ)w827!90s/0sGw톤FHr]E~ȼvZkVZ-vz=\m&)[a/"!%NֶAܤ DˬХ߉xpf^٣a (Ec0TWϿʫ7ydfA~27޳6W7Is% #{u8s)%Rk74c8_X^M;~Q "'5or=vǔ, 0 0oYh;bŘ9æR±2ͯvV8p55jYN)G4Z C1Q#AQiƈĠLK&RAYHzIL3 too IH,$&vq ʈ&Li0Q,l*KuY`ی>4 tBafI_eVgGX8@ThtّAA#OOGԏ[cza۱1̬ΩrmÐ_XZZ}m+MM۝([Q6}'n wOxZv^iԊReZ 0孝Sk}El?P4^x( 绌3M׈$BjF& T3s ՚Vю#IB4zI$A RE:h  UR!f,pa7-R)-:Tz7Lsln uh7 B l'k fQJQ,y-F)h:%tx5V8>qzSy@476 maap|brq7^Yefvj&钌(Gӣۍ>FfwUM֠B j58ѧlT(4 )K˒miT5e7-ryBC3 Ymv֗֟|m<ʍokYs+MZf2Owb[G~”V-=58an0{40I0ec=cL k#`v,ŭ&iQ%nrʐCPۈo%% /.9s MM&8Rba uL?H{)˭&e,r1z |~L㐫Z\l/pf{禨lZkŴL^Hy7oF2%TibX`24IBe]{&KYQH1ǛbܞPZ!`R~ }:' RuB)0lSM˖t!4!4q|Zz؏$Wkm ߭+?5ŗ~=s'fƸ`-AZIr;'o+c[[p|_=P bVyЙWuRR{H[r=ˎ>ץ:(d{TaYNl'ǹ{{Ԗrk/|^3 B̂fɳ4XˢB˃9B[:E҃  B>AKp} <`JCg,SF?EhPڥ+x6}.L&Ő?>jFֶx\ 57!v >BnOIڦIvE'ӴoUa(-dKDFKH QrrsZ#0 R!zq8kڎ!DcTOVszaPP1;7B!r#֌} Jv Ҽ/k,&\D0 b#v%a1w?ee&!l_{0|yMF¶llg[rݎutS'nnLJN;:u$vO(Rv(S(ah0bb#j"eGP(+,mn$to$c{8oq-9 2x I^?,pLR߶HRMX0zlR3pTkY2r*lEj z7o Z|;s՚=v;]j#HƳLL>ݴK5{SJ}ְb}Ɠ.$[) S߫1<>rn)01!,+F-!D6lB׋ql,9|3y0鉟"am 8NE"Yq*/H}$RV3DK`!ġfo53uQVr#Ї!QefZG%1/pYyzdڭ>76y2iיtDaFRn"eɴKՈj'B$RVZ2"~}Uy"nIj&aK@?]~qڨQϴG|MK\"=ɉcJ=oY1ˌ|L+LI޹ZT>1t;6&'W87Y\-]p5X-Hְ7ML`%Ľ E d8,\ >"r)V4Y_)z [C3b1ep"C&0SFhX ;7囵 7?n6tV/haEd$(!ܕ_1g+L_C84xYuϾ&&ͣ{PJ26Ttn~/O>塐JfaL\'z.Y/+:d3);8( nj 2ÊjC#XhF|n`/E~^~ڿ~ׄX&zY on,aH)(rc>3pO?_9F6Z&slp<293̠SXR f-}dRbr(7@|ޣG4h[)i(gCi,9x,m?BuPȉ'2 Sa 6e\*x&_} Rm} GģT,ԉxF6rqGu@vLަRkDœ!.G:a>olA9QCz8T Y^7_s{50+S]_?s;lԪ {w%IJ łG60<|b!c_9B-c~;g+R\hLIoG(bݦ7YgNk-ǡxd DhXY]TJ`G[7ט_ʦ3jryHz- ַ V(`?܀*a3PS1đ9 h8rm%s;AssMb/TحKu `qn8601­ı«;u1$³^gt/ !fo\;YN^rm8jܕ­Bo$jr}=c[^PYmܱİͧ[B dK OjHgFA'\_reizs1Rf$qge])`a#QJϯ0}:O*li1u*˝㘍{pb7(7ojlHƲ1>+ drI"WX# ]KU+#s+[)%Q?y\k\!5Iflbel_FӪ!bޙIz||?^kSYi0_^k%yR2Tڅ;5ݾBJnIpY3ݶ(LN4 ~ዸodvjRd:[CJ 1ڭ+K\%5ZOeҝ<~Ǒwl&e[nL'm *M$uf m ~`tGvmK ۅ5Kq}|FZBŅqQJ:L\q-%BmzY uJXŒeEBc)2,_Pw'_/0TBrY[.n Gal?X0V"zevKI7.)8Wmyr;04FP4YN]&\Tz;`DXHmq:Qr c1ƲRiu%S0o^^9? d{r#9z=k,Vu2axLD4>: sU&R ,!:.^["WeQLg 6mX)g!%z(CMPʐRIzjIb٬Rz|V[lb8kmO?dg#ґvz9ʽy%bf>\` QB\%ߣYo$dRI qזϯT1RJ}"ȇz R)qzUOLΓQ gIDAT8V`WgKnr+%7ݳg^>}4gϞN̙3]p7Zȓ+kp@VY ;w:U(͆Onk~Yزhn6(8tBF7Ko._h(>;ڛWk>R I = "N7۶^k BJagoXk/9sn"=4pv~pƜ>}Ƌ/S{O>ƻ#٣lKkGG8Gr4l#>oeۭdrYҖ.iVnӿ/Oc-+_oƄ-TI=bb?={Gw{g^.>}:f‹Wvjx,G9qx7P!oaIR\;d:J'/O*#>"">8b,DIEZ |V2n׻>U=\n~g8/,_Z.*՛ScxiP,7؇}[WM {([OfX>'j j1:pѴ웋N|wp~1> Z5Muΰxӗ) 8:ϣ(\"z߂)`&Cg_(߻B}8[&Z )$i]JC *X0_"Mr#ZVo¹)'~7Y5PǓGﶵQaEޙᥟE.GL>uڥ;[Z?yuҎolLi>JHFTsz߰Gkڟ^#|_8qۗOIG\6,"%8&߫]td|CдVT^[~6%CJmI߿>&ķ f #n.PƣJzCJXX{%D> 5gH 1`{/1h[pnO>=q,WV_ DjKtF A@'кEpX_Xe ?yyqٯM# fɤY~0a,QLE/U޼|Ȇ8Rx}KR hH]'QVb!d5ٛ ªU-a>'=ayYR_U!U҇(GNpS.Xb RD'ф(rDea8y^PbNXzvR0pҾ4^QaͧW4[ňʻT)KD,6ĺKFX<7um_Bִ2y~OOsnIP^'4(QC tF\UZ$`%%mF\L4 :2f'(eh?^ޡ8p<+1Ү>sҤTrZB !uOǟ`r{w%cvhodN3X%KuBoTʐJNoFR/С%j ]r'8f5QhO mNTSKXr' 7! kƪi&ONSw+0G:z+x)xViJJT8B.ʸ-l'|#Pm?c-)O;sJ# тtb֚>k̀S( ,|1: !h"Z ipLdsSwݵef1+q!Ǧ bR(HAO*#$יKq:N<7i,vڟA0bqNҏ7-C샴HCE//T+HPMcժ_p~' 9.Dl_4J<؟A vPQʑVefP5ײPZ o|} ifQ~!m dAdž6Fdٷ βVߛ<7_6P;iN>3?+^eݲ#2)iEf4VugGDZEYS 1""p*<xQnZւM>#|(:ʪO&uBԌukߺp~ݭs`ξWg?XW4̃ &r/ERi0hg玴NvaOְ<$5GwPGldC*Oy`vlf#ؠXj&B0y~ǟ`r|C`1.V(i%H9feFE r૟=Xb) mG& |MNO%Vm'A΅SssOs3A,906Q"ߓF됵&j\(a{dL)̓@l4u kѱ% Qېz@]`&O{eni`̢<|J5 % 6()2^q$J 6kvy!4ABbk$i*'E٤Zl|w+{}`nǟx?S[RBJ'N:#P]&zXT"|`"HsSѽ=`>@3bk&p ѷ(XGX:ҕƎ btW@|`7&OߓgI7&SGB#rP`H&PhPfI+xM ˊw{qsd,63pn"߳7{co|ު7WIENDB`sympy-sympy-1.9/doc/src/_static/sympylogo_big.png000066400000000000000000005067011412543434000223070ustar00rootroot00000000000000PNG  IHDRߊsBIT|d pHYs ` `% tEXtSoftwareMacromedia Fireworks 8hx prVWx[M$e^kzZo>i6(?BbDO^ !!] c$xPzpЃ'1L QIC,tDoOWwUP3lwٜ?')_l0fʏ))lͧ<93tMS9΂)_ 44|Ͽxۿ8'?ps~~GG'??|,Hn}?^NՏh}o*{sOpwC_q_sp2޺! 3S $?wj{OkW>S}d *!<}{]ëd%+YJVd%8U g0CH_޴ SLØ1Zn0)0QD&#y]UWZ[TeSwJ) xM=xHS(R*TH.$WVZ#La|#%4̣^DĠNyN:o" $Y! D6a7GLp] $_93L+o@}U ]HH&Qڼs><RpZM-*l\q3ݕ:0WTfx?U On vBo IH-0`iӎo0s Ad*GпX cmRӰr"fJ(h˼Ẽ&}epAݒW tWЦߩMJ/Q,0 Zd/)ֲxŀ.YZ ᔸy:=~m֋T}!j  ڙ)R /2ӧ#ϻcmHcN΃`0;H`ǡ3M5Dlc~ݯ<z`bp)7ky`) FbȠ7{\DS` a9볧hN|~bD*+Npu>>mP[K#]:'ABA/q+q(-[Gy9WywCrĺoeJ?ۅ y liSv8x P),1EDh+XbƇw pd-ˎPHBcdeYmqpف(d D#NbYHPf ǶҘ?m+ߡ %{Mrw4*35_BV0nd{6tX5h@.pQ? P6Tpv7ً&` *tl5`Ƙ,+  s4\WLzU#٧aB0 b̶CޔVٍOu^߿|a7QHaALVzcX-HY\WA2gZBqC AӸC wdhЮ xi@Zw̳y@n` m##m6K_?ZƸۏZs!R**r2t_4z*I Hp~ -N/Qmɰ٤*&-@]a,%:ކ"y~rf%DZx-Wۯ(Yٱ$}bO}<8ɇ=؂Y"^w^Tl.+GL?-qdak7|_22ape#H0L< &]®\z32;c=yLI{6X'4[,oF8ӀvN;qFcޏx #;G ܹٽ;d4&&|9wE/1/ "Q&eq|o$sO*X :CjbYn_d\[!q{/鷣}찰ۡ$ʻmg<~#~B^wb [mknzەd%+YJVd%+YJV>JwMǽg~O}%+_Mm\*$HmkBF)3>mkTSx][sFdƱ%dka_TONQEI]8$yqjkcKVsNwE D Nsst͸7ؽ?N`h7Wl򰛎]؇05 }LJ&N~n#-"ڕvEÓc_Q-Z/d2螆 xg:JNblOv/ l`w0Acx@vG `Dv[o@s؇cΈ5GC&]m'+}=5;S/=hӃ&lLp3Q 6 ZŷE3\R6ccng-Q gphX=XM1Cǵ>>."B-md !!d3ɰ3>D!8e1Ҏ&>@ eHPacP;|{?+~j99|?hj42-7[l!I|HBj KˈcWoНAE dI^.N EUv@FXҭC3:CE[D9M'R;jV2C]@^֪/WϖTFϾ_p-ESRRQ|{ga?ܙ!^o)@c6DD/Ì5W)e3+}F M'`@id|VO(qb E4eq0h br^s R&<2`]6LYicH,'Eө #gc2j25fg62Ѓ|&_HnVL(EXbȦǣJJѲLZ.Ceh̔0-2AfJ2F1}"h9ۢh3IatY2>G+5ϵd{r`BL)G`頒/MXI+բgZ1`ȆagzvɘUeV֠\e,XF)J]*כd'_*Nqp u6n89 b=<*)VjfjrP#T_y99&.z cF+a > 5eD?9` Jrl(Dn%[]~kEqͰE[B(E8L>` f5Tp1ʕJ#&b #HUc5juf 4|N^C1 *)^KזѯU S3@E(/ӬzϝK*Γ/\}EE-"2d@ a5|>aIbܸi 7 N/L7,2 .F (SY߂' V Rfp7ZmV>9 Ȁ<̯6+)%E4 $,MhUoJZS 1y(dմl|:F aps:&%%UXmdz @KDXYbQXSZ9#*ocN3goz<7Hi|*ز'*hdlj ^?];|!%A\A;T }8ٕJ|7S,,q\<ױ vf4˜?P*HiOArMf`7$pr8[Th!>&لl.,Qf"ZzEX#ޚLs:aR*M]6%"P׈,^Z-q )3irSe^q I{3ʤ|9>k by79lcC=ޠK  56zzeS1W,UF_f_tńAo'ד]{N&&C4W`+locK&lܰ臤`\APմ-6r69&#ܐ-f#sB(ZeوmH?rVٲXL%U&JnD2spb# ]dD1_SQUQ1g EF;M)=&_iMS?%;l orx?idvVӶȥlBǞ8BKCJ.f/(i_1p5rfUfR2 23)-*/v75EB>EQlVVEFGbT*/6Z-&e_e3ܩv{&ݻ8ElvFaƞO/զ-ڴe1٘-„/il2ÄgVҎњS{68NCz9 ŸS|\Y|BLO&[mGNhF.+6vSXx:˗%hí[dj`Kqخo<)6zYJo$I0g~p_M>QzbKcIzXRLY)%tWB %sЊ}U0DAPuq F|f-Kt_P?QK%:Z 3 uQZM?T5([>׭;SsQY7ѢFZ@+iY75O)L݊Jn~P5; T t ))Zw9W 2UG&ǐWv[fw%ŅDh!v_Lf~Jdzμ#U[\@# ʽo5K3ҝ{I R5O׺g9Zڟ@dJ6vqVP/~38eAMXJul8 j&}oOOo%eΘ핚\gǽ^f˭HCZԌ7ʈ${>'Ю'{͸~H{TLȏS8YczV#Rz ?aNM?eN{$'y avpNJI i5 عҌY쑚NSg=.tS3z^7,#ptٟ^j2*垼OkpLi_DetrCˏmu 5S>c =@ CGv-mRC%='v2B9璿 .;9saKeqOBoh$_3O͗W`1UǗ%Lߚ)?z YYs[3w~@[i ,"wv!=4.άM::k? kW% 1N0Ϳ~9r'vWb:);opvg7-C 2t-C+3u 9Кrt-Gr2GwѢ1mݲs-;q [疡[ne薡UڽC3AċO)hO8rv-g g 2t-C ƭZ:nڣ[vnٹeb2ʻjvϕw-C 2t_>C~]5Cʻ[n9/on~c+Zvnٹe疝|vʻ5Xy2t-C 3WU3zk9얳[9+Ge薡[ngۯ6sHeoe =}Qbkíe| }͆-q5̯Aoή_S3G818bJ&2ݤ1o%)(4IA V_*XJ \~l8~qmhZr$Vt9i;k?ϊ4p^/h<:JMہޤWƃW#0N _gwzHwC]5)% ]*jrJ|ǴFD .?Ђ|8c9q>#?[9+ii|h;ʸjeM"sp7ZX}Lr,fC{JA,hLq -'cs9Ϡw(x}W)sxx֟A3UUҒYց}-Qϐ"KyF!vm|;O5wE5!ye&XޕGa$ Z]RU}L4$V.>KzށlekWyJ,1=5|k72˘Y[̾%e_`?h92a#-+UQA85_-Xz2Qu#/}O-!_bgc'1*n"]Ђ]@j2/sF*\ϭeuU6%z|[F6gg[ HeF]' 1E|r !e~A-Ϋׅof#̞ mc\u$@UzNxT+IYdQm%4bQ6׉hⱏlmW+J=ILn3&K!Ƚr-w4'{!`{?֣JgV3"U:T.yF" ٢x ay\s+~?XmU^Q^]3X?m3, , 7 ~hyw^x|:p,Gbazx4O^)GCv0:FW hK'=1h@3qsݦؾï;M6 l{x

钴+hƏxg_mwot65!ǻ2wvj?#x?q~ڣن4\ | 54Z!BIdr߆Iw 6'DDFaEU^3. TEDNjrv( "\GUHDUEBD("m/"XUU!B~a\DHp*iv~r*m$" Raq*H"F"Ұ MU~#Qa)ɰ2T,#0=AjDFp*lt 7UF2ϰrUò+dTy CPщTe8dxA*8UʬW+Ti$#APՋ[^ptᜌHՍ[~#alBFm}Ff}F3/d'F2>4TvOA/}v 9'v@عi:si"# 2UF2C6h4ɈHso&EhvQ|Mϰ U1H]?KX՟;f#efc5*>RUpFv Yϳ7eȹ$]eٹraN,Ut?nYY4P;ZQ_/B6 uS\d(U_gMݛ9+ )b[6%?8;3$l#-N4q:ܦY#f﷬,mkBSx]N0Æ WM- 2*5X|DZ=fLc(F? hҶ BLrGpodgd/e>f 9]WA\\Lf[xilϣTs1H QlHاEt(SAZ_Y XmmkBT~rxݡJa]q cb X ,C U󄧿+|u8;U=ߛ[=| Io@B_Oo@GGGzLo c@iz,џ/ ?NПP$ _>Yz??ǷG @њ[M}VA:Y@mkBT~xݱ `Qhhj $Z  W!1M~K7mQZiצmviz?2 ? ޛGGG7?^& ϏGGGGGAz????74k >QuimkBT~~xݡJQa/EAt-baip? 6AP֌+bv* N:vk5jjmצmm71Jo@'" _.7?Jo ,`G^_N?7?????Omצmצmצm֎n vПPvz? k[fz^z???ท@Jӿ6?hmkBT~x-JQab:&ʸ'jE,ÀlP q#p^pJUSߚߛp@zހ?|757x-fAk__[[' '\7 GGG?_}ހs7??????? OO(M&<#YXrmkBT~x!J`Q"*X(V4-0QA ܀b ds wz= _}tscA5Mncr@iz? Ouz?O _]7^7??>Oo@GGGGܸ*7MnwӿQzG'˭//6& C_M/c`l<4wmkBT~ܚx-NCQ% !iB,yiRQנ00$! 1(\#`&QnqX~';vڍG5jjmצm>`G џޥ7W]z?sׯG//џۓ' k~@b3Ko _7????3`mצ?.G \mkBT~bxݡmBaaF!) 5 !L +t&t::Lqyuǜ0jQSӿ4kӿ6kӿӧ7?ۤ7yY7Ko@GGJӿ6kkez????3P<`kz?????w wiz???? Qbp7mkBTx-JQa?h"lNqcm\Ab\;9{{?pi55Kӿ6kӿv:Io yހO8џ@GGGz;Io *`G/_?_7?7O lS_Az?zJo@GAz+ kn5`Zzvz???=;Ho ?_TqwZY)>mkBTx흇WTY9ٙA2%$79HPD%*ID 9a<;{6ͻ{55 9sfsoݪUu@m[ֶmOӆ Çɓl.^OrFm~Zmbb̥:QvlmX~,֒8Ǐ@iqoϻW‚Z}}=2y!02gkmMԮ_˼X+Φ8gsңpyo%av'x1+!2G5l |r~ 7mKX_p .1PU6sJMk333ZkTvm+:,#kbvI\m y3PqӃTGn.im:.&kbof낤9B aǡ0<_7 l70^[ZZRknn`^D1Z LKp szJ3GSjq}pdN 0Gn t9=(X2~?ALvkw&ч9 VJ37t nkp;40G~Itv*.)Gg?,|k===Db⵺B1p2,<*YjBcHNp74+/c`iT^.3No0^{@V"U00syU"=Y( +q0204NL;fl m7J?^|6:: Z>V#jxM^ϟ,smuvй&H.B\} ^2g4OSyLC d [A9$ 6˻k_4TWW-^;Nk=`OtjFY}wѾ\%==7qoDi0*ÝѹQkȼh pFB?={VNU8^i? 5>Pq/o}4sT;m~ΎՈ&V~Ѹ)VwJduBnR$dw^W7^c2pV?LkMMMk 񚐦&]k.KZCu7~G~Y;F~j[AOuhZ9Q&Pj NҢpnuk-%plHxT=xS)c3B^ޯ_D)dB_s9>ӋOhmIݻPR$7^o^A|=o";d_ű#Du NI3GavZoVVrz;xxMYǜ真z֞G=$LЧ_G!]OsyEK+SClm~Iڵkk׎azn.ïDk|Yx~zF)1߾dY{8 xs|?x!6w87SOÞga߫-//=^k(KkBzrOCC'4ps2\,,Az2=c3^yQ3}P~') z?sZI>9uww;^'`0]^AG=a bu76DZg:QvT]q+w/tdO@eGŔ`|:J3F` %;%Quɧc#J'_'woǏ5VϢ@6=Z=^åh+$Oqjp?3ràⲋL^s)r: {iC#H=fKuA#j w%2L622xmT9s/`=u*wbcz:N&{t2g6Or`6Gu`OĚ?ko޼Ygv{+ 5-seW w.W]=~x=߿KS!k,2=eN:Aj|d1x(6-H+#z^Uq_^˛2^#^:R~ e_b9xv޾v}ꠅ̞#ԕy\mU2J〺RZccl"s:ZUf9seq=ISNc~v'^Zk6pq?x6꽠=;A[x֭[.*T-9"4(9\oQsX MFV/Ne܃Aˍ㵻wuuu9^k-+SM*ޅ.πs'$\`!{&q2;B@B`(ܛivHt*F_~rgyB}w<0@c|zoQY4sq6SǚkE쯼Jr^;YO9:>^;;+բ!..233+w㵱Zxv_WO.Sp9K)b}ɭ뭼q>}W?G`{E{vX5*f_y:(^{a?**J8EGe;~ rtV=mm}e[kCBdc|u  4ʟm'af"q L {W"!-535ŹQbpR%K|y2l 5%sZ󉟍3ޜ﮾j>\[Wk0Qhځz?ko"\f.4sp6pdC?. Pƻ0/9:0־ԟBDgt<vRk.z}}vn~ \`>~aK!'hp|g(^#Ȓ? g xOa= "ڍÝ"#%#`HO޵̘;_O|O qY/v-,H_ Gv1p4{Ww {T~޼w%dvdIz~6˝?++#8kQ$R"!'+ k13B1YȤ^ +5%Ѿ#yv'|䈷>jrc/nҔ%}.qoCZa'Ԟc|g (W+NA dAQN8dPAx(y-?'.uX='~;n燊J9Us9FeKRXcWvW=s_OX"}bC^?j-^V  )^Q_^۠9<φi*X <ۙ ԥ5l>m\v}=~C"};DP bGa e➗%$^l}{38cTvN.5Lo 1$Doi8ZtzAcL=Q5}8/ggAia,6ҟZȆqΉxssbO%t~l}E+se1{c}nk8H Ȝs5Yj=ǻҺu0WDBgK̝Z9N,[T9@B3t[cO<#t_G?AlVP m/(yu\ ka;+U|$|FNω_}1J}~XD5[1AM87s CPY߼aU9dW8G^Pyz|Hx3?{2+X)v{} lzk)s9'r 1xN;'W[Q8F̔/;`!X>2J]D|| CI{_?K 1D1L[8Ixa~-ȳZNL]Mκ[{KjĪ(/>!>ns"X5@ =_!hTְfo,tF5@k5)_OۑsZR@?X}>nl=ωzD/iJIk)^=LO1uтdr:Ggl6s" ;'ek{pi1a2!QYZ%')WH=[ۓ=]Yq>)t^B9N8pgiCOg~s)=k|z\gB|!>MT}_{oelɟN?s5?IW8CqgO ]pX.p7HK?D s;멅z+=˙_rU˺!6&3a5e+fP'}KU$y;@x~Hw+nWwƇ;k '_y >b =F6-֣-w4|v;i/tMG7_}?5LVw 8'`VZˉzB~]{(#EFS6ޏfD~>Δb WkpnEK ,V7/r'`siE4TϹ=8}~™JX+Z+t(z2&[lH W1[Msn:TGbğ{~G?U{ ^m7L%>Ss0{~~r7HX> 3]=X{j=}?gY=/|dv8SS,{MnzZs=sb /TWWZj쟻1Yow ȶ]Ocf]нΜā>^zֻC@36Z5$Չ{l=-˟ٿh/ COMRC+vwVp>=1u^8%Nt[Hm iNmr7HMT?^o){FZS gs9Ľo'b }ϔoIOi CoT`Ϧٯg ,-rv'H`g\!~46å7S9m-EOV4܎hh)oB g٪hiʮFz`l fDq< zWmo?+ya Q3s{PvvZe b&E\ M ԘzBrSY!O(lay6KߌN}p$ 1V_B< Eg~s ,~{_w@T{ nLBCU<#TxoMdӥ#r~"tQ%ptݯ7P}+F4?@CQ<='5wzroܟQ~3"N5f9;/9I{糳q^;g}H:>>'Seg3}f}a G~k-v/O-A"w9/Sã\s?'^YgĖ8zNlZJ}`)FMsN^3IE$wT7zz~ f̌o!Ftg؋`K=N *ezxۢO $x{Q_Ž9|l_z̝>{Z>es@XuzT"z5,?w1QYlu>3]qpaO{{Ǘ{Il1=XV]_PD50e#_/Fċ"ovTe f)Dϯk{~D+4˟-7P q!&q?{7I\gR ~؀n9 Dǖ#t_NrOݠK}~$g}-fαz?,7Sȿ(y|6KP~:p;_Š};Y7Q\+f(7 WU6#T_ q-J 2{aHuj/bzչ/8#h=6ԥl@\aV<2z4}l=HX3|@vl?Iyڼ5rAYIp{R`4 n!>fVb޸oe ?}J8DYs$i c{$.&gnzHz`jc*V1~R{lade޻ߘ*J\J evxg7D),Fg@#<gTw/y߻ 2!*ܬw>Ӡ=4}ЧoVH~,AgֆpyΕ{K^#Ms?;7Mg ʌ5 V|3֓b3MpS< >bV珺җ3b>\ͽ ~&4!?0u`/(Yjm0_o''^8Vh :KstL9li»ߵhOw?7n/ܑ"?vyN|k£P ַJBM`;»n&;i#`z@wW}ΪY*zuE >W]Fv@MJ }q{}k@OΌ.1gDD гO )5q^|}[A{!!"?FY\ˌk@dσ `4̚9DR^gF^4k|;udH}_ 3k Z]"mRŒ! )Y7?H}Z9)V4WW%fF?<-&{bׁ+t IJSn4C2"j'iJ+ |_y^qP1eÀ]َ-.ls_j0_Ns_VbCXo>0fl gznCőD8{tD<ecRl,Lk6P}Rr\v7손 cοD5`W"|gbs.~oGH!ᛁ?[xsl]̨s"*y?TTE?x*kp&c"v5P,gQ/!tأpgȘ-$dzǂ;ݛɌ_Sp43,1Mw\ցYKLͅ\{aM(\ Ԉ]S}%2sCS ="xf`/g)cbzmf:xJgZEQ֪ 8FـQro[XǬ/_'(?3Q-ʡ9b8[ҵ7u/ |]0 7l6J!MuXoK\E؀rL·'GՌECPuJ*Mk p#k@jT"4cE?l nW;Rҕy`)o/v^i_nfa8V=}2kgJ,fe eR>5/)WIgT= ]Nك ?$µkQT0BlQJԇ򷱔uvgJu' grƬ9OMq3'uYx.0s&L91_jlmFl+?Yo#7M_9t(Ǹ пG_gE3+CyτSɴ=C!+%tA@.wO_QsIgIπ6kmez0)_/(0G|4YA8/׎*NRNF.Da+&R?s+]tb  3嘸{ ) 22H^$jҒ1kZS~R`X33/Z9%UK[lstM8kB7;lw(IAdckY-bf#{JV-]0v77mײuP|џ({d?=/?I&j53n1o*ZT>ew#,WK 8Il_cs+E׼NN@фmO5?n+X^ᚐ?;63d{(:@3.93"vM)#~F|8z sP>]`ώ$Q~,ң;t ^:` c.^tV!g |Pw&F./4Xw. 2? ѽƐo Qt\W-("GZ5 ؏5HU&r_GV'mkBT!x}Uw鵶e13%uleY`ٲZ3@&&$9׹;\dfKVVUNY[z7 ObL I{ocj?+y0>MNaMFx+nI[|B詏`uG>$IDy -<"jPZQLg پp;vV?:|<*9Řf0CXh{ u_Zl8 oip&ɂ[e,"8\IS.,.$9z^ WaVp5Y’\L8hS|rQ_v ˌ<̘)JM44|nqYȟ஽l]D\jSx*?3yH)daRlSZȆ@1k4ՎF nW:<|_ŰLzaP5[Pˢ͝@h: 0M"݆̆h}7- A6 !1^L-_|zH:áy/j | 7qlu>_E2`MY|'}>etf/3x<i:@^( M4c|c}&3cC%zx2Xu{"}? vVT2rp6`=ړw^GAfD:sz;AӵQ{)7w18;Miq(2B2c TǑ=*$?ꀹ2oH\s#E}-Ǽ-A&*rǣtb4YcR\1c #3KǣFǓ*D>WGA;\Y#m+UGAvT܌}=/lʠaN{+-Y11 wNx1U=<72dq_ aFّ~*T7)\,ФSe~"|9/wq;WXtvCv!<6s ?fNce/ =d<&5p+ʀ{Uɶ*Y?{}xmЇ`J.X*{+po֘,hC΀̿a+ L$9 %9R+Wh`eۄ-z"}9.V?y|b="R:Q&Va` 6kaL /c^PNr25 n#;g|RZ-":/g`D>1'\CO{Ko7gD߱/xhq\& lEb,cH:= tug ,d`E #ߒ 3:9KP Uk&/F"2g:1n$֪sx?(ڌEy0$t}[{ϛ5-Yۑw'-@̴ P8Spc& ,"дږ wïbυnSb]eF_L"3һ r9Lj&uuBcG3`q?ڏb3<$#2%2 FX*32Q9ui^rg5|z[~Η+N tn଑eeX-11 #7&b1D'#Ax:Oe$_HFh ^@@I't&*Ő s }+!+d=I6ZHgDd&T?́P('?!A/"b<%#sx}'?삊@+wdWWkQǫoKsM^ڀ2qb[0u7أ1|<ߟmP(k#>6A6eZ(3,NT[-cm| =v}#Rƣ>m,b/ecwO!^ڶBcL9k\"66b= Xsc?OVV)gB?؃I&p̜! &9A5;`m[\emm0OCM2*y31`;K`{ǝ\ uO>ag>)o)x ՎWQ0M?fk+裮R1y$xzQü oI+eyv"Ф3$Ϙ2 >T̹pS VQC֌X3S.|Ȗ7c끈q`B/lLAoȚr<x. hUw܋yçz0ƻ<֢leh2=r&Yo<#FOG=g 4v9U%/~ZW0X50CxrB1Eb ,?kÞߐ!欢a/\R0G#"ﺃouh }W͖/ưb;l ?uT9k+'_ Zk h1ل+6/Ę5Yp>|FGy?gF}+_ ?_nFx#Up~Z)aMoh-.#o(X `g4|l9r:7_tߒ #{e0{W~8gh~!`|ZV1 {X*Z#Y\{Aάo/csNek>Bs5OydX} _@/&ՙ=1>DKͫWac۴&|"|]ivetuC'OB/`]82LjV#eP<}CVT0JbX[d-ěfl tB0Y>\*{jt.B ;Xtx1CB>{\IaPO=r57(z&N?5 /~ |_ae!br1 kr!XֶX 6kde~ol;BX?Bc={ s?RALFGtMelGCZ>/8KcRӮlZ\j l2^D9h8׌ij'YnΓ,9=b\#` Zf 8F? 3?m))I}H KHVu.~| _ox+uW\˗/AAvCqJ#(nTh4CW.;ۙ =ݞ]\e)>^+?+2SG0{]dw 9(3|j{ax >XZef!h`rO Oth4aaa:V2GmT.r!d)< \Cgc r NV;R:'5 >G!0ESX-= 𰧀a' ?Q'Y)@qi'8Cl>Z 9 "HKTXmpw @?h[埫_j A֓/4]f\D@(Յ) Wݲi9ĆA%T|gde ׺v@K%%7[I&2-Gtߌ}#^_^R1D0N\}|>:`D@p̭//CNkr#I'Xod@ut0e1;_GnV wVZߤB6~XwBb#G"dfJ#L#0?#92?l=k } Y@- m9cG UJ_~ Cmy/γ 3P#qe -a>("1A}!z@({ eQ6l*}v{l<7s%#Og 3sFTĀH_as_;5R\Й?L?ng p?Oy5sZx~(ΈP(žz7 |Ú?μ2RٿV[VdX&`ߥbbOEq뿕RS]nc }3&'3@iƞs P|fs\h{7T͐<3/f=Q,m;~O\-񏻫h?39T' ^ :-g9YQx9hpGqYgh^xQ?m=Y=ڒg?㾸o=91B8ڦ_!OyKC@N竛?KgHfUy9S?)k9#l}cbu`?-&?AT4Zj;.3<%3{V+m@F}4|sNl˜M;w;?A?)įi{,e村{,ɳyq|W%6kV(Lw9)V5 C?}\/(R^/-5S;9䔅I@)WͲIsB&BaN8;4?^ Zg'ǒv O 8YRk@l>c܏8#U|op9?inn"P2;on4 ]<,0hg?YNOjlӝoI ]6nP{Ahflǒ| pd}]B/<ؘ†b ^ [hg4cCk*?nn>2!q8wMc##>e瀑? ;N]cd.5Ϥs~-_8n=VE륚i;#zE8PQ'~H cq `! uPϿ-F c}DaUxL 0s]ƽgc~Ol.IM}uJ* ܫe p?B#-B"u? |[#9_'c~/@Q$zZV ¸@B>Ԭ>О}X#p/xoklD\tnH#5׀.J ?`>t>x[p:ƁʿÙ]?5eTX,25`n^ ~Yǯ^ lݭ`k=wJA.@4'r6-{I_Tnv!+hܺ=s[B.Ac' -ş_z#?q@iAϷLc?r@n>~'H;9?aId|#Ooku?惍ƽ"y,?#g'Jo ֽP)s.-f>6Un)]|~68 ”!~?s^o̳d1XǽyRSD=9b8Z]l=-7kP^L<t>l@kC 02jan~s/Hr3}h轭#G$ݟjUqx`+^`?9F\mj+(?{\b4Yo=xP@?뉷UǾmj;ٽ\?Rߎ5`Q ԔD?}26Ca R;Lo!yJ3]=6rs?+\åK .ϛ2lO10#ݑb|=1C-5Y#>6$#b]0??>W>&*>:ノ6|$$ I<$O /ΕJ/ 8Ӝ=Cz?DS :Prxg>\׿o~3Z:$(p/7P%kcO8Buk1ƿ,w>0b= y1 =1WWcc=cJH(Qs5߆؏'r @[oAٻ=C䬹%|!}%u~wDݳ[$]G`?!b9֙F|qOc]Ze7jN_ UܳL><.Osu^ 9%}~<ӱـ'>磄;_WG&roΜT ` ~an; u0sahz?!:>|3t_S·$a_X>WKo}?7}GΦ'i?e< 2!RǢ!i"ӡGD=cuP;_??j+m&{mkBTACx=JAQ*6cF!ڙJ7l,l,\;w=/<006+5jjmצmmw@sހOgހOmz??Q߫N7?{;Jo@'<`Iz txq@oaצmצmpq@a+]/` ӿֻHo oހOG6kJի--mkBTRx1 !A`_ h8k~-Qncl%zk[vG~?3Dݠ mkBTWx흍8 FSHI!)$FRHnw HYx3ꇤsaaaaxIǏ'U{o_ھgW9 o'GW {>~Jlo߾)*/N\ϱov[iZ_ձaJΝ/:6O- 92b?Tlk%?_21B sY5>:>c=1Ow y^- ڶ,XzusM#גU]>H_yYv!ۉ_mi Rus]Xm_g)YY)m]y,m z1aaaxEߓGקo/Y\k6xjgH|yu.\aæM&wk#ϐ$?]Mo\Ⱦ,/ڥQ@~6s?)}, l gX #vQg Bٙ^uのuhm?}{].~}v_J;xogJY]޳@.)oqC?}>@Xߘ'-(W? źvƔOʙRv[K?[A}?-wmՑ}g\=c}M ggg DŽ-B^k_g?F? v0||؎=ǧHPgs/hؑI t~{n^}ZyD5XWvO)"c0vY Z|~_%/,p\ɹyΰZ/;/xs_9?Pܯ5ݻ\[y|č8gʱL{? 0 0 _k3>z_\S |<)b|7aaaxn.ta?l^Cvkؽ#~e)3<3^kdlc&jK+o"e<.ʞ`^(3zu l+6v<ï k7]/lc[`On}򚄫 G뎱zt^v2)?;Wmr5ocIz?Ozx{&!ez."ѯ 1Gg{+ҏlw<=}GݽFƨ^)zIpG K֜{{e G12ۭqiumf>.}~a? 0 0 [u+7Svq֭y΅ ?ނ}XwŶv?ߩDZۓ-q/?߳=<~#>Fk"qzrQo 9r,nY[;o:)@-`ק-7({߯S@µK9֠ɸ>:n3 _[_*mtcmC>qSL=<6;ǫsaaa{xˌ\ފpx?0׋#5zяc]x^l򼠕(f:~٣^lin59W~\;?vn6erUbS~v^U O7O(|;+SG4|?f*?rW~2oNٟS9~daևmH6mX[J~s.ym4ٶO|Bd/b5ɿyU? 0 0 0 0 0 0 0.P~*1@G\⟿KrKXs2(ߥ纎J8'>X@▼QQbqwx b)_K|v 1M6kee-2Ǜ59?K^E~9ϱQﱮYF8N?~;:=J<-tĒyNAgC \NXKs)'^Kg\~2}6}Գ)n]Or^j~"{p29w6/.z-v:+M{WJYZ굢`% Ҥl9ힶկ#OUz+U?;sd~vND7*.Y+v:ye;8}~|+ÑޅN9}{Bƞ#txխsXɿkSV/uJ=o G<ջL'L:D]6jfgLz/+ؽ[{rCMYq~[{yy czA;w9zszWHVax3 % mkBT]px}[TYS}/YL$Ifr9(A@ 9 "I2sFTLl}gw<ӳ~7`P@a={ww>U{a||5558{-<\?XpRQTT$  o߾~7Ǭ믿 7nhK;''!Kϟ޽{'<wsyvV28deXȖ\~'Ē!q8ODιtD#3-ٙ Buu099)/bS%@fF2T~",nN'={'E?+=Z>|?( NuiX !\=&_~?~Q/? / [?._{>'`R8 :S:0w>c]i^ҀvAX[YHp=M[{6`_0<"X K(Ÿ Aq^Bx,ĦG BJ~Q,T 5xpeɋG?YueOѽ D%9+zg 7z.8x 3#3iBeS>,_<%שbb_?246 A160sӅfX`s`/xD8Åasb=s'{2S} ?g4j~碢wSx{Mr^{̒Q}U~m8o>m8w l'v4n7*UpӄK^ւzJ gC.s͐4M'k6A0 0ى#;znBn 47cњ,u,v nBr^PV%\yQ~SXh݈^ۡ{ 2]D4D|>Rƌy9͑7i(iS7PrmP-*ء=2TsXеt rv3_q\DS0Bl>¿Tn,ly,cFt1a7G.Mshwos>u!N7A857w 'Ǎ:nK&(bk]Fe3@d>ڇvN.Bh<yWkhOΑ\0FdaxсUD{jDŽ.! C(/nݛwObz9#x5/dCH8G:CH6@:C0Ӂ# f+׿ BZ 4&_-{勑>|Tt,C;˼jM!pNxkR㥹Ҽi h~&ߴi%?n nc!>t/qBDzCkE{b`(BeSdOHQLyiF/Au,.5?&np!8.q,zӺ-g Oy)K)&Yx|G]' #堨2ɓ,=o1u`"rcd/au//Ƌ3o| ۠`9Ö f칏BxA3('& Fr9iE K_5#p/׆E.wP@<32 ӧyd!͝ܦ.7O۫?!l:4]f]gqb8+Nԩu%]{^[5r.y,|ז 92GO5HZLLe%kN1*{ XDРުq?i>`?CGV/C+:[ϓ]:D֜Bɇ_ $O1oZ[[6m? `S FkùF U{aW <5rHV%-ӄ}^8UkN_óqڮ?{Ym1a>Y\-ʍ-j\kv¡Y]{>:5FLkS~v߲ZLu.oDcTR=_^khPzV#'6FyFשǹ.ՀQ*' w6`O- {T/a'd]chR̀bbF'li!I~za)GxY߷Wޭa{pnhD5m ;Yov Y*N:VSHFmߋ79tpGXݯ IWrpیΛe3ܶ@w=νJzQ| d^ڼf׶Wj9TOU]O6 vGMPeވV  f SI0$6` %@~]|GUx;Liq˦1M汢pArR\ :O5h˘Uc}0se@ ?mqaۡM֛`>Nӱ6g<ƦclĕDLMt,yL ɸoUvM9i<ϽR ys5TQMJT3WPuCtN+ɔnM/3<=m0 jp- V)ܜ38o汾>OxX쁱`6.avp41<}Lg?KZ#8a!sDT3bGBl Xt ]C~F8h :7@h2ހ=@]/v܊#`L A݋L3H1Hk|pἭ q5az` m0d߿l}7BŊX5M~6Vj3#V),&Y}гIDh0 5o|}臓IH?@d#;-9 C~V8 #PXT%l Z՜Xz !Q^@l!!S!~bS8q/Lf1cS>_uLU`bu4s}S9p.FmE[rpi \{myy|O:pc$]!I Qp:ks-\Y}(IӒx^nIuЊ'/ml~Ͻ5Y词ĭ؎dG9A|:qgmK c0{ ϿnWx~~z nKY} Fpr)UG>@j(mcޥËGF^v,ϋrb|4רּ=gErk8ߖBt<1ޞbk<;k\gVʚy8G*6_ !w/c!:rI+Q/|y5TY>;l—T\eQe9@>=)yDP]Ή>w{xmUl *endj?wmR c1f4&"ʃk% _&s]1]rK?ƍz4!s?{c( Bc4-(LEPol6⟱ZO\-5wqi8-G/OX[YrNozW}\:*UrcͭՅSDz='ٛkjucK")!puq9>b./CǦ{^21H#xأ՝k|f`Fd,qǂ{Y|Kby+X*Oa~&w+e6zO{Yp% q2u}!mm䊒p 3Φ/]d^?'|ko_mOz.qJ׋3077-⢽Py =a kndE̍4&K|Et~V u/t7'\35PO輍!O /&\BWELށ^C>\lWH+uj]cQ\3 d-5\$򞝒wڂjjMꯊruV+tazt]_.4esSl_O@Sߛˏd3E!=O+6w,ggH=_T瑾ә=W)tz?y{:_5%W2>#JIy] IO.SWYB@{0H:#^i37cSXry %ǰz/ ]V zIUOBrU|NNߜoKP iSmf5yܾÛu%uݑ?wݢ]/u+V׃WOו^t]@~u=fm뺒ᴮQ.`-+_ot=~麒xJv]s_R}׸ˊϘ \B#uySf0s]$\(s|`1uzuuy L% =:4*u]:˘:ӛ5H VϰӟW+nHQYg?uO}T?h?/|g{d: { kkt=]q<=BYw939r}߈,x`J+JS." k:ã7Q]uWǔH kH׳Xt݊tJ]_xЅ~麝C(R4bu0tlx:|eu=+=Fs9"Fu6KWAK # t6'OH甐 Ŀ$<cAHI:{,J]_H9 ?oyq07WϚt=DM0t_9f-]דD?7GPq*"]ag+ƿ$:KլEȰ+\ˆ/Jl| 6\y({.#YJWdyV<:bc+l ʳE'}ω\ }PpOh}JypOh}JWrE'U#ؕursO+?[}BAcy^ A]lw~>f!79qL}bc_{_`)}E^+XwMWT.J}_];S>w&Rq& _xO\ue@kycZ_tLw@Pdx&Xy 4F Y"N˲g>qB^%j $آ,CWk):.)uXcд޼ [`祇DUYΥ<謏үe[uhc;v=8j(j(,ԍ6S1l|PA֖Yp"EϨ.{åd/Lbv+4 7]Q(- \[Ư]Vxi #sصNELRh `ᦅc?TcD1f5L9_Oυ4= 3B~ע' 6k{kVHjxGW9[0V{YgWH{VMD?3&g]\mkBTaPxݡm`ю,I!ӦTUT0.@w&lA0uLw73 g55Kӿ6kӿ7Lo@BUzgzoGGGsMހtHo 0Oo@GGGGC8`)џ'Ϗ RTqHALmkBTiKxݡQQJ  AfŶ@ GBH_AK'&b8&3m֨__a@uހoOUz2`6џ/??7 m~/GGGG8pzހtM*xHk͝\mkBTnxݱiaRE0bg!","hR V6"d7)FMMM>7=MПP,`2`"`GzGGG4kӿ97?????_7?ߍ`Oo@GGGG:?<7KiP Vr :FmkBTx?xݡJQa/*IYp0V\""Z &k ˪Q슈½{_s8pJoyFMMMyMo@Bfg ?79No c~ހ,8`?_[f _ џxտv27y]X;xLo@'a#`G { & k{M 7?????_TZ6 FmkBT3xݡqaSl P@TQu6a3]#k*>o8Ox)fAk__[;>V _]z&`g@Oo@GGJӿ6kk"џGGGGGz<n' ٿ7Giצ?!5mkBTxݡJ`]L*",-UD1Ȋ+4L0N7`VۂŴ+N~by?xG;5Vz??sހOrހO> ^]7{@,џ@篻g'~@*YS0`MM?7?xKo@G6ܿ77}af?Ys?Jӿ6kJ =7YdmkBT}xݱiQQGUbPFH@ZV"CBv MS-)N^RSѿjM_[7?}~Mo@Bez???w@, oGGGGGny7Ho ؿYПPfހOO ?ۯqz??wހܨ_7 F<mkBTx-Jaa"*Ij A0QA&܀ Ap }¹}kuPUToo@~z?ПPϟG?x;Ho@'"`4 | ?7w1{ӿ7{ӿ7{ӿ7{wk loF& Ok? '_U RmkBTx!nBaQA P  -tM ׁN~Vb8&3mZk/MMޥ7?ܤ7?ߏ o@OiNGGGG*`2џgiz????=t(MY/ծRmkBTxݡm`юmB0a0 , C|Eulp;|>55Kӿ6kӿ6^ Ow@o@m@@}ހmHo s7?????/?џ'- ϋQ@xjlgEmkBTx흍) q ĉ8D^>׻gI@XjjgiЃ`0 `0 ?ϟ|:seQ3|ӧO|:2|.};7eGFO6_Qv]T]^ˮg{>pjzkuo{yye?{-x/ D:3D&򈼹e^Hyi#/OGzϪ߯_~ :sMe#M3Y#=2 QЙ[\s=E8}E>GȩT ڲTg-}VfoSVwzV}./>~!?U1<#}=F[ ~QڋBN..+푹^edLo+[\-k dW(}6q$#?z6Bөi?L7!3O_Q}Пuo[=tkȋM!'}/Ƈdr2_Cﲨ: `0 :8o=+8-4}۞cĥXdq{bUq©ήm!ƶg*ΪU\z[GA=^+ru{LV U?)V>ғ)x|Yҁgi\yi^cUo*= !TY?rfgWsʽVn*VX#=Fϫ+[F~yH\L~[O҇h5ݵTow|Sfӟ+);F;:x )/OS yUo2e)Ve3'wgGg=J^`0  ľu kU,Ksؑ5nY,bXw{ w&3QהNQev ]ƷgcH˞i{A3I8hwduwUIWq8I>+@pQşGcZ\ƪUߝ]/:3d;ɫ:gB9R|GW~w2;fzt|+i5nΟgZY|<1NyŬ|E7k?z/k><=Α}N΅>uWydʬdz `0 *\?W8GY:Dgcg< 2+'W6qn؟{ru"wU쏘~c#T?+y{Q,,^qF/Xv8.֩g3}ȸOP ~n%hUG4(_sn|W}Tg&x^c,Fѭ+ <#+}/Uw8BRh_|33!mr\7U9m({ѝpvew[xG]߱?g;,nҽow8]וb?OV=Z_#ve?vN_WrYLo;1g9pV^G~>[_vNOS3 `0Q[ veO\k^8֔v<Zbz\Opbn$~}oz3ј mK vU]^iNWA#x딫jt q :E= z%օq)CcYEqyRG-+u (K\hP'*^ء^q=m=y|Kvūe\rȊ4={W1;=ݷxp;o@>ȘT\Ԏ+C=*ɫ|GJOCW]x1.ﵠ9_Eб Vq)v(ʑ}[GwǺ{-oSdו_˞׃2;iT&w*w:g׭SOsj%Z[~_˯d֮+w]7 `0]kIu+eL]ւoA^;=GR?v쯱;<y o$N1紈=:ߥPVu< <&3KyC/4r)i=*/|Ύ^]QNН1qGw>ù{ ?Kv:A}E:_n+{u=rq͓̳]>>d}+|L01`0 leg:׺񶊝`W,3O?]\9P~[kOWiGc~)-<w.3q}'vuw$Vnv(r52S;Wk_Kϔ8B/hEՠ'9w?K;x:x<|@cϽVyc@ۖSw8Bq]=2lBe6V}eR( VeZT4ade2ޒ+nYBTqSߔ<[&=f[|szP)G}{Zׅ3n7jpWwftEw[ǽ;`l? `0 `0 `{~i`oLy>uoi\qK|}7Svu9G쯿c¾#>,jow{ՆݲL=mW2u_8دjo?kD߱mw>#}E:OۡO;y`$jwmkBTxݯJPa/E f*&(Z&LYIE,lVAl 5½{_i ٙ55Kӿ6kӿvހOd7`'g@wހLqz{ ߽7?g _l72>Ho ؿxހ?7y____[[^Ko ؿ{ހOy'` ӿ9Oo eހL)`mUbJݶymkBTxݱ*pa"td1IVIl,eHLnբ\dsww oŅ17/v :Jo@B߿O9Oo@B>Ko@',`yz?Ǐ A _7MnwӿؾJo zހOd@d@l=џK5Qy]mkBTxݡmQaFATTt]-z\B7?ɛ\sb=147m>ަ7?o? N TӿSz????3Qe@Yb7Mnwӿq@Lo@GGGg7IRPmkBTx!aabTŠ)b(-!ݦys''@\ڠ[Ho i@Zހ/_Fzu(RDmkBTsxݱJP.%"$Z5¦@Ƃ hn ! x 3<8Ziצmn _M7??W ?_79Lo@Gvc@<`Oamr@t5No@GGGgG ^{U__[ua daz'GGGgQ_@#ԟ{ mkBTxoǿr8ر8s:;})MPh(`P H@0 b&&q FFg87N|Cry~?yn9'OZJ PR3*U" TCn KAM'Tj*5 nNp5{WǯgO}?Uds&ξY Y kK4`joH6W2=UdԃR F썆Z@]06;vÝG7^ >|1j n1Jca,V|TIptk3j ]`K ߋAp4փ?lH5\9 Vã6?O?~:PV4'_a $h 7̧\zZ`҂٘z\0<{rW ugk/4`KM a]Niry57z`Ce.DЦ"7t>8?.½ `i szMRcs{ͦ^7k{C;"O\ϸU3g APYQq/ Rys,ټ!dz0xc!bZt]Ր+Oj;t`ijjC鋡$ohVޓbf݃Ok<0vm <0| cD4u|6[*GW"o0oH󆹽f_lYͼyöݬ g08r\[T_sSBR=N3yCbwvBpupyBK.q;n(|/Sk` 5%BȘ_ܽaF(cWaзO r7 c/_8ϭ/hk/]k!?M"oy΅ U ސ Z|-|W\DXcV1 oK 쌕uP:M\΢EԞ#:w0of`Dsncof8\0B{&?uS-k`gg_QL]s֕ 1ݽ783Ϭ {ۦ֋4dn`g8eUu (1By ̍,!+߳H|?T`RdcX\x7$ij "U{А&6\Z5L &A :p1G?@ZE}g A8-&83;4jhHʛJ?ʺBbAf9\D:oǼAi*=FK:z`M6h?X[&MCQNHFV3ޡ3s]CUzcTs⾠DŽ}}{6^TzH9Z.ǠJǐ=.KLȱN!Y-fq50/:@4L ư<Ë)fN:7ڠic%,+@`_0-]Bmk]UwvIJ?rI{y,T@%! _4 5jKbfoE4qWM'8W"pneUlJc!3|juw{ BS/pĵ#KRrr@-`_yڀom -LW6pw9?}˂/9,zc^:0 <)y,L ڤ=;@O͏~CI!`]`:t|]zI;v58{*2ܗ^b!'DYNX 6њX}0_X )I\P"9%=T=414{%#d?wz7_lAPLX3x:C/+}LMf՞r.%Y/gμ'}^pl5A-x}pdX=TM{m@+̥Ra塢S#E3^|owܘxwq-Tp Fqt2M6Zcr} d?ߟ i.4Ztx<[д]ӹAYVS-QϤ)x#ǹ.g1/ A>}'Ĵ,HIK~./2}[8SL: 7!]?`ĒvL1_`-q "Gj>^eд G=6MCgRypGkIւ' wLDbu>:"8CFBsX?p/~۲w<}R{ +wڰk*ٟ?1 !=99|er߿or:q77'7-H׃ϓƗ_Sܾ|AE˗w{gT7 s!ιo{n`U.:{=M޺5 e|)'6ݸPW08rϞzZBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAem-ƆymkBT6x횉m0]HI!)$FR?6c>>~sm+vuՑνYu8uN?WP>1JsWiV_uKEϸ/rˆ_gKW]ױEYcl,[TYHT}xL#}A GV7^}>iҞ-i;}LJX&TP3T#ߨgJl e'=?͘ona|7>?ǐU%;/mN/IfQփz{G}?v✽3X~j{zTAO^ʰ>?sy|G)P7yހtNo Jo@'xހlџ3~7?]7??Z xҿ6ZZN頿MUf`jmkBTxݯJaa/e"|1V\,fQ 2X]ZZL˒MfN^ O?SvV):u+vzwg  >/No &џ~_7L}7??Y7?~>Lo@'ހO G^znz??RAzOgMzIz߻Oo@GGG?OR5?P?{ymkBTxݡJaa/ ƆI&+ (. V/`1-N>b{y_G5jjmצm{77?. 7Oo@G6`GG盛'Կ{Ko@GGGgV ӿ6kkqz~z??sAz/ ,`_Jӿ6*]SmkBTxi`Qqqqq ! COMlS$I$I$I$I$I$IqO9˵wOo]ss,Խu˲<^0 tc}av=7_{V9z}ٿ^s_y~?}ez۶@wE՟k$I$I$I@? R*f}mkBTx+JPQbIr 6-[lzA &'"8ds 8 a3' c : MnwG ? |7?sހOqz ?]7zހ=7?????ӿ7Mnw7{ O6ПPf,6Vg Ol+ӕSMnxD.MmkBTxwSםQvwyd˒%kwٖ[lc`pBRB503s=i̴MLN4i5~}nce!s~{~1vp8@U e^XÁo} 8^T@Eo]@::¤l/K5u_1AͼN2SjqfQ 7׸)twT4kKA'\W3]~Eݯq? v-YrOW U ?7?2t-KPw\T^{ ?N]d%>#,}t+dL-OkwMLgM %?yP:W l7s_ g!xAY'gOCP 9$K Jޥuߓ"LNg??G过7rͯ>8 mZwM' CrOhz~eh{vٽ */o@?V<'@S]4y\/ZtFcZP_{c4CQuORk W@Tt$wot ~9\; uF޽L`Uu_D!fyfa#_O=wwaّ }Kz,337,[ {B!g|~KwoO`$9'TfBQ5^+vI竤O5Bh g1WSto=j~G0c)8qlZ;hWݿa׼ʃ0p3^8rE?aJGjAw(_}N}5¹o=J}q.HJPBB}\#ʠp2^gWׁj >C8{ۂuQ/]CP^ z{~@sܫ[Q󾒾W}5E?ʡ|%@7'c{~B;PgN9Lեi8hGv?48& v2_8{_v* =iܟX(x1%ΞFmoOޜsCEuVYj7:5ˮJAB Ż3Z¾{{_.JN@w} +iG:+Mع{OCM`O.q3r:.> ZM¹>Ol~86@:T-16N<I9|E&X{}^>MkaUn>Wb>G5xo|˹dq!h{6A|!8/WUlߴA (+;RiX2!<$XCo t}}5wO;Vt_ZZ{/R1LE1)oYtdz|_gG w놘;|!b vW:g9"s )A{4>&}}+fg5nhe tR=Y` +wBB3|ߊsdV%Bz1L{nZ>ˡ\b}u&`+*(SG)X9ǭTU vo'澤Iǽ{?*bLH1[`wFk/_jE#+OkI9XlnR cP0z_^뽇{r/h θk mkakzh:. ^4n\wkv{rwp_fZE=CeqS]kZ 5^稸 ܇X_=!޸QOqٱ'!m${y\#Vm$%f:{0 v`ggÄ6,-|Mz93Z7}͔Q{_bs5jn:Hz%!}5yIZQ>X{3OyY<z$]px.z=a&GZm^};ڷddާX6SxO E+{>^ڟ*:Junuol~ڵd |=!24@1٠sB $⽨9݅!%!p(#ig+&տU4dz~fOo5o9w<JƢ &B54MԾ-7 =_)ȵ8L܇0n%(M`z+)v]k-57ycs ]IJ;SN1rzY׾u+NOs-u ߖ yʄ蜑J9?HhhdKGsVgd8ӂY\Nw 5rz\SҕQzݰr2;V$Ƨ9S@|=*YK81ߛ y}9uV*^1|]6đKA%hlSYL5؜O#S'}x-֪/r:=|5({3gJ IO<+xrF%L%dz$R whn_?[N1$C?۵+{ڿ ٿYx׾Nqc*,t/O'SE5 n(w žA9FC'=r/ 3Wɢkw/ܱ;~jVþ/ca i!YX$wq8~ɼwc!f+Oc+d_M:f˱ scc˿'{7.r?p}Y?<~{ܿw%nw-ȎY4`+w3W-o- 9ֿ+5+gqsC\ρV{|-3NOF^}?/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAVB. mkBTxݱ*aqbD -GNI$-daTJ,&b QV;y]۟_SƛёR u*WM_7V'?~[Io@B ?~7٦7s@0nz7 _7Ύh:qn.3<T*NOO}}ҿ^<L&8:: Κ}M=#HL&\.7p\OAprrߍ$ ߘژS4JzCmkBT"xݡ QEQJ `6b5 i.~@'&<1GL55Kӿ6kӿ] _'6| oހ4kӿvznџwuz?????<_TMx% rmkBTx!JQabĤLPP)) P%Mdl7wr] O?nco3Ơпz;Io " ^7]7s@]z???3q?q7q@8Qzg ϟf _>6/ӿ7mџ?~mkBT xݡJaa/E9 YdA,a .xc lfz'W1Ox 8mwZiצm& 7?ݥ7?{ހ,`Ez'Կ{=Lo %.;,[pO"%dƾ(]mk``Yq ?Ҳ{oNQ<;?I9 Se0=d[ [_MN/_ }͢4OT0h~`Yzl!BJwsbJ.!N?SΛiN?ȅ#w3y}Ƌ1P'BKm+̑,(KzN!~}&[5uat} Fj?;+L$y2k7 =3ȟym/|azYy#N$)/,.kt&I䋯k=dck=)* ɪ!8HvN\h.6\B7c o¶kPs&v@aL(3 \e&^NNR"C2{n4I̋ 9a$6KN2LӂW .R.=}(4GnȯN} Lh-ePth&RSᰨM Qn[YI. NqcCU< TU2X}Gl-Wo:;!l L (;H"t_߭ ciG}#w3z¶cw#uG G rgo<E; DVHgGB0d,A`8볇Jqk!΋ ZŨ愜v! ;!~;LfggˋAl;Zg{Z뗓$4QוjG@#Z0Rvp~.)k#s<:%) ݾ 1 ? $s@r<'vB%_0E\ 2r̈́Uk.Fg6GY{tGh㯫bV t%ūHG?_r؟ݟ*8{ '\h  ^03mvi2 7l0l Eyusܟ`Ew0֛O|-ZBzѿz0)g&k'_0B'@'H\ st|aV+d| y}xmO Ϣ9@=y?ƇO07A>H-joUX(;*Etw3D ^ x7e2Dpܽ3 ޻bv:7PalIb8I7OφS9Mͷ 8mTGi^an%پgk6M+^zcDN 8bjE0ms~4lZS8I:LjvpF>fMbTV_}L>;X}>Ơ_Л)lЌG_-}]h}!Et3(O׉XX[9 khgXZ}b=e-%P{|6iwBfͣpNhiUa2ĤGk^1ilMXsٓZjA0^qMhWkի1UR~BS V%@pv}9k.aҖGp37|㋰g>h^zt NE)w#|AbK)sc `LbS7,|ӳƞ4g-D=+4wk敽PW$g*0v>st2ySՃa߱VK i:Z`j,bEs!4W 8&0YjYo G`g2u,}vAKμIygҾ* 4n_+4{}yn]]a޺ZUJN7)ZcdNZ藱QK ;ӹK\<{vU,ť*ɀxQh>&~aoS\ΙhRZ](8MʲP&GpWb rەX?7Hd5K VU!dX+ܝʹ ʟ˯$Add$'HJR }+`IX7%< ڌw`&fOs:!Z͝5R(b琸? APoz3JETA)sM!y$:dD]=yf\?x9أo W07I3oj_0/w-bB~OxFqJĹ^sSaM!;\? cD2?`nQk[T 8뙫{]JX Am׍g]}J>vowW1il's@۾mM6!m@RbfL \=rk%3#MO/> ?gAhW/629!:ˁ<@d lĿ@"bYVNzpuS]  (yS@=3 4Wh=vi?˂Wʛxgs> a!`(ePdWº;d"w t}z3It,YnX>Mcr>`9>Kg mQXzs炪Jkۉ}z(g0k40<Q8WG]y.֚Ί{٨^\RKi:as} bj04TϏ%E,?H~.u.|0i{:8Ƣp,9<ԂB6g:sNUN|uloKGg9G{p\e잷s[ҸY!m1 |-j3!Жq/f rvQ<Orq[sv [;VԶrŞ@+An>ڀ)g4vv3aIE|uעF]x(M!(T*m!}]O șLgxuw F91Z?Sr x c{1uqܳwgf8'5c7]v{ 8}SD޳FMQAa <gObV#={? ^Q︉9OLZs/k~%g(Ƈ:3f"(Fw=jik߾ϛ}?ACu>. .nw?7gymggl3.(de`{Z%'Y=F\Gqz/Õ(@9;͋ xCVل_ l0> hwQ2!L^|Gp/}v1{֨q g?8xѲ>Y.ɪ˿p߹6:`P7>#ۑ(փe5s9-ϻ;-4n5}s_ Q.9Wj-9~_ {w`k'ߞ#uLtϧ{½8i3[@a;q\;wm{R0j׿s!{x y:;DZאsi-![a1au:}'!*w}~jܧ j}ii+>>;0~\\;ګ>J; =1kpR]-~y3\%+U$.;<Es~tvm3^gsZ[ Io3~/]] \>D6o$$b)x]:_8 x=r"cIBfP?u١thh4T*ɵ::E~xDVУi,֡|÷bwM?ߒ3yy"qgO'ǏPP+/5iD.WUid A}a"q--ZOǑn65iWDH.\(GT^{"#y`^r -_Nɓ>((((((|K?%WRmkBTxݭJp]l2?Ғ,6eAa&T &o@EVLk^w* OW3֨__W' _7?Ko@'<`Yz?ϟ />f Oez?????t~@MMM=7?nzd3` vzmP/c>xmkBTxݱ*pa"tIdQG) &7jQbm*x7֧Kc : Mnw{g[ _7?uހ~Ho@B>;Lo@'<`Ez? AK_7MnwӿؽIo zހOd@\bc2[Ko {ހ?Z>amkBTx!JQa3("1(`hQ D\ǀEfd *'<-7[{͍ҿ5{ӿ7{>/ _ Oo@GGG&`k@yzQzoGG Oe? ?{>Io oMMMj8No t@j47?Mo p8Ho@GGG/ߛ@'XߞmkBTIxݭJaab!* /[+Vg<b,`1 <(;W Sۋ Tuӿn׭\o7Ko@B? L ?O џ9=Mo 0`'쭛ހOu;`&`~zIz???3?*Jj'`Jz??3zzݻ[õGGGGf@/Uӿn'|H`{CmkBTx][T89j#JҔޫ{W@iQ @"OԨ9ܜ]2ϓ'-3޳03{fMg}Y]@{SS'mK'shk4+l h?K6.h5Xf,e] k*mdEU﵁c.P5(4*#cp{/B`:B|bB:_fT8C" rt JߏÞ+G >IfMD^fip$>S0D#G39o*򅈍k4O׀UF w#^MX PߟMy.phMdCrNG8pw!NȀg)4 6LzF1 T@0t( :AUvK&} זQ(0'{A8 ~8W`'] =Sor7X ?}!R%Xb]9c-s4ÅSc̿ Aޠl@q Bd;ayNW: R6k>V4 F2Vkw#(̞ 'k8ˋ"ΌZ@sQفPA08Hj!1qJj/D{,/ dF;(偔hG9'sMmsT"&%Zh ւ~s̛<ql/bq-d{+i !Ʌ؅քPV n~S뵁j\~']DsMpl{ / '✔G$'E!7Lg׀}-P:EtpJ:@TORC(! V=Gd:R Z(i 5Ս k:|.H .ԾXLZy>CbǭgJ 2R'Hp%R#Q`n;HA)?ՆY2|!_iLsw%h`- l0}~DJGсvL8PqBFoi4 T=cNF<*;`|3e~M#Mi`NRA` 3EJ[!o$?`F <( "Y,©Fpȫfp4=S X%p gķGP|5 iS2BIL1R L'׶prrG|Qs kGw'j@y`Rx{Gޥ*rvl"jwLf 4 Z3i^?h3s G2a>"p0ԈL0 hd?=)f[,{D!l:x?i!h! `s탠?6?V8+AcPE$/Di]6H wt UDg93WH=UI Mf kp:#Xs )ni]+2 D k$?S>Oh~PK"}ICeT&(X7D*ރ+9o p]]}{SH,~]%?#.{Ɠy s$'j;4%ǎx&P[~ ݓ օ<´I|7{[>0W P`wGd=ysQ?y:ݥ_W? Z+-p%\E(3=\@S\ G= ']mBg F?י;ŬGv'Q;'<ΧOgբs`#zX+bPf9e#wӛ p; *uu1b3ҩH9 ?2>Wlo2x=^4nWD4oI ~QiKqTr??=Δ;-]ה1nOSwMmC&zN\t1qW$}0sXM*0z%δDxN@w>}+QROa=5|ݭ+(KL=r9pIg4ç*ϹՄs?9%/U)Ӭ߿?twuB{S}E̍WRsy=niſg*wLP&?7'9]6;Vٰ-ϦROp=?'^1'h{U7|da X]o)q4y&3SA8/PwEs?wu <'_?ި{5Ž*Pw=Z~q]EDЦ>X-cYnSjIrMЁ4yT'8<âƳR<.!w?Bo>׍9IQ@o!5 s N,oDb݀x IMywŔg755RDwH~TqS_Alt@k'q a,%DzKȗ_<&%ם!y.[N-X_P-5;%n .'z˫[N*S_[>#U;Z%03^̛Zb 8] ۡ%r:۩۽e15@]{aͰ@wPOM6fńzK<"υ{ K ٌZl1<$b677gǨ޽]fl͹jc&'Ho9aog_va3Q8x z=9"OoߚMOOñcyBOL`[|)_of6??#O, 5x5L V-+C_KybP-1_:剟L+O+y.ʿ6Dὼ"2 +?ʣykB(+'y =aj%8C&g`Z'>y"&#=6FCJ?lMXFȿ<AWG ħ@Ee,5fBbx'nskqXz;?n-[BTD@sCz9P[-&'D\Yzy+s/<`VE2X |nO%-Cc P+N"ZHl0` +`称C0w'ߪz N@];`PyBt{V9,=>ka/> V:?l>_ևYCLF2z'2EymkBTKxݯJqa/e*",-Uے  jjx Қ| o8Ox z^kѨހOW O?~nПP}z7uހts@fހO:W ?+LMMMd=No xހO`@@$џR@% 0JSmkBTx!aabj0"&Am YĀmcUpokQSӿ4kӿ6kkQzyz-o?{= Oiצmހtu77?????AvހtM*xSE͵mkBTHx-JQa`b h1| m `vN`L2Y|Oxpxm`sFMmkހO NLo@Bџ ~7? OyzWӋGGGG,`___[Ko ހp@Jڠ[Ko f=`nހ8q0_jӿ6dBףhi]mkBTѴx!na.M&#&:L YIX$Agog^{Zk/MM ~W 6 _?CMLo w7????3b0Mo kހ_?_]z????#O QTq~Cz}I*mkBTx}+(H,"H$"#X$,QԈZs>U{ ..T}6ڳ-F`p]k߅~b  О$wݓٱ|sCoA+q3lOx@(0a+? T,_7s\Ϙ^Bl1)C+k(FyN"8dPC_9>O0&l4Im+nwGrŰ)/tihf ѸX>E)<,6s45zb?J\<OM%O#(76:= ӋYAƒH Ls6MXBcX&ǘJte. 3.je(??Lj=%wZizFTx$kP8Em jAOހ>~؆B9 ֤8UKCvjbL Cy ;mj P. DkwUE€3ܨ8xUJs\ɟ+;}sFQ(KIXݛƨ 1 +KdX];Jģcx$D׷X`i @l̏rnm$^9΄zBGϞQ=nfkDe; <a>,⢞jk0B[p($Ǡp4 nq`XƓ vϵ.xHnorJ5Hu뇗 f a[Z:>36[g RL؍?( &w.7C#~B{] UW 71jk~ecGrD.=K@WDZM0倐0\xvqNZ ># BE )&yA}t?B Ym(WIpɱ |2+\2 )l8tl@Z.Be񅋍RSƃm>dIl'N adĢG3%#)?$s _5=YBR#-k"qGP-e"f%֩-ϓ378M9ϊ,_*n;HEBƱcl~ ˝[/sagIE2,z1t:kLș壋G){7ond{@rP>kwk׽ #kXfyEAB9uM4P=_lgW؇N#_nGpp ,ZUu6ȓVӰ0EK7*|]{75F\ԶzQz! uH>upT٣o3P)[^6` -d&*=%fY<^ط`_6|h3ء>2 Pq7ώ ,NsjF=B` 큳CiU)R鐏@LҮǧmb<2FHRqùFXi䎲OmGA}:*u f:@ʫRH.66jcGOpO- 6HKJU:Jǃv,3DZEƮqq7p?ȌK%ȧ$;?Qr6pP7`a^=R_)m>D3#£ _' Iɭu͋C-Rne㯄ssL<ȭ/R)|Lt_1Lk=rr 4/gEr~PnB[\g[{gYvRW' {Fem1{ wL;7&$xc0 n&u@5sCCձm8Heft x{q(aтa?Q%l4ςxmWI׆GC1kQ3iJh,KRO`ʲ4)%b6B8\pe;u)ko)#WSncRx{[sXv195_0Kՙ7>Tp5ٴl3S"؝LX睫[5m Q="u}pϘ*xbՉ#iM+@Z! Ϯ~jYݬ$?5mtu] %@݅:4h8ۃtu3; ΑO1A/r R*5i&j#Y2:$Z(ad@>'z L뇶6Z8|`6"X1_z' F-я?X^ A:?1;h/KVB' vOnFS ƤQ{=kh7MwXQp\v͓O/. N3HKRlK"q^Wh1wt h@3e6N|I;y?8t[[! $,ήLe"z%IކAkRl!3u8ځy?_W)AbCO!rza5Sn֗#<43y6"R߃CQ&>[# BHǽ{vekOTlq(UH͵h ݔ8,@tՂL{p/*L"d_y k,4 G̖bD>,.ok"D;|7[.DCA#ilϟI֬Dq]+eE _-- ڰc^Lq1~CCC9gNH8BkhJ#Z-`VoMa 9r$պZ-hkh ?C$ ^tď9d(8P݅]ڶw[wl;dn׆oKd Hބ(DInI M_(5)6H/Y1 QRk,nXHʉ?>df&6^EJmt{CCc`0ʅv5x<\9Yc}106"״!֏9dl:' 1H"z'7QqɌ#KR./CVgQȬ\ `?d1yuM6Ƶ8ZX]8^pwQE &1frRKi$GݜЕh3'{;;~FK37ku<pdʎ+C RMzƏ7)nҀ lEGyl:̑IoBS%|ЕsTulebA}Aʹ10A{KʘӺtjdLI=r PRg_LbR Şl?␔)![Fo wi&k^CV(t@pW2{hxHGRn͉eCbxԉ6GQd27\ثdS=\Ff*0ۣOP5(rZߙxQZ>~GAeN-jY7Ҿn;n?ӹ"Px}/NW:݊&׾:x" ꭥу;R펔 c䛅љElmG§a= h¨BG_uYnZ쫭FYs U"zM&:Gnu.DX5Xn;}ԫ%XO?~2&Frjj8 yA*W I9/ub)Zl: s 85J>~iI3Yԕ;:#hELם[ROd^GA˩f~Y!En0~/A Km>^WYq"<цF*c:xw|͞w%ehRgd9̕v3v Dgh>>?3hYDkgC(ʹƒԕSԜ| 2Q94(?OGQ34 fccPopTYaW(>@tX4`LGٞpɄaŰl\[9c26U M6f,'C4i?W~psϠ?kAKrŵk@I|>^xs?\`,D̒5W^w DMXf_8<%|8_왉pP1Wlm߃f?4:́_Ԕv M;k:p_sj؎qw]$F}y ,b'N=o0, ~M YR46+!}@~ujctCP.Y(x׎z?70WXFܣo3z0c8RGg0 TU򄽻w"/4֏CQ`[{Ocn]+{{ N!33+5]qpj' r9FDȬ)~: 9Gmx2-?sraG"yvUpa;Ră A\& ?#n 0eed~oq嶭!!DzP^H)>oȑ.ļԶ=Hy7S-M ?8ycߧq|#5"2Б lm#UeΤVbM͘jAc7Z ]> 4gb s 2WRsKg6 's8qzTT[R[w)I95xWj #!nN+zPڔ KgTE,?{^RDݥ=Ru^zîc&D'i74SJߔ&HUG[crͦ<׿~4}څh;lpAZ%XZ;tQ?yk1+Ƴu6[ Dc4Ɯ*dB#!}e>samhG3c^8u9󼵕⸈߂UyB;f "Yi=D =4&|C3g]~WgjhSIXU"1A5Fr4{AljwTt6</N \Rta| i>T.Wo>>xϯY{緷m,J{gg}v~)]s!?wXGFl!7U|Cnfﳅ:.@mq%臔Ru?.:aBֺE#Gg'yXDuSWNJD)21ѵVagWPqȒ s?¶@g")s\T{f3go^w:^"{d#!φt},nyWFKv„X4|VB~,˘_&fjp/WԍwaO H 3I`u1ͤ+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_W|+_Wݚw)UmkBTxݡmQюmB  @`$uMIA#H@PMKw7(PuӿneOo s7?4 y.?.џxПPu@8Ho@GGGG?џ7 OCTM@ ^4̔en]mkBTxݡmBa4h( I4XNрjgOGLv#%CZ5y- M_Ic=*G iL2gYh}=9q: 0Gykf(Ǐ);J%J~WJp t|=33Qw9(U6/*Vӑ2wт/r$a3jԀ̽ޠq\Fd% ?]nƥnaM!C''#-p>'OX&?`0{-悓Lq^1#Ygs"}rȿ_o,am* EIi#?*u~_z\f'y[]O,$ r2w4ga]16i3_#ҳd /q2;dt&>]*L)8_?/ęqm9ՀG91 ,?eu;:s>wXow%ng w~a˹j2kw/diP?ya[t:&4sm6/gWu3;h&t,ȿ챝k|v^C4tol5KLGTt~5;ţk|K[1x} ocv$ $/`B"4NnFZ;sԡmwLFɿ|Ay±XT~US%6#eh3ռ9h{­^Oh܉HT|Ud~!U#:V=s =RqΕ_v/:˩{A*vZŵ$ȝ#ο+_^ _Hh.*.hgCOru/%T,^3s \?ȿ#]i#9u:UH`gݏ9b[bKzYVXg]UXSՎ@ BdkS\gNZEi] #ʆ>ma޹Y5/$YT`Yh]|&8 Ćjݫy;}: _%V îptFϵW( B( #%~`/5>#C<J?_gھNe,s`VS}c8ԉ_jBZV>iKyNJDjy󠌣;4-$c Y6{<տԘr ?CjX_O/'>Fn117pY(_ܜP/kZzv+aerH~G;φ 6#TIPsR䖥΂Ώ)LP$@zBf2%QXil9AWO>5iT9kX̽;k~Ɣ֘?!Mfs@}vW C_/!ɯ $%NB2_#!ɯ%&                        )w"klmkBT^x1Jqa⪄jh"z OM~B ot^k__)џ@Kz=<7?7???wxMo w@gހOo9C(`sހ\uz?^ܦ7 ]7?????g4kzmkBT1xݡJ`a/e(C.FM&„i6ՠ4,,&W^y?xz55Kӿ6kӿvހO0`W? Ho@'s@azo _v72Jo ؿ?>Ho |ހ߽rS_ۭ{w ?_9]No @h#Yp?Jӿ6keP3YmkBT^x!nBaQ A Z[W%;Y9|n̴pZiצmֺ<`, ]ПPe@'џ'?~w)MJo ؿ;|7?????=_{@{ހOǟ(MS^ImkBTxݡaab F)$))|؜L^G+\~)O55Kӿ6kӿ6Y {n  އ_sz???qMIo@GGGG:꿿./4No@GGGG:?[4 .X|~mkBTpxݡJaa/E &ú$V&'Z F` V`_3xUl'Ox6mo֨___[7?:Io " _ݦ7?W /џ ܤ7>Mo@Bgo]z/ Ϛ.?7????kp@q/џ@t'`޵~@~7Lo@GGgmP?ƺ IDATxytdu'*VM6IqId-,k,3^fbg&>3q$s2'edĉeq2ؑWMırc٦$4EJn6 Q(Wz{xRU@ant~xBPu BÍ{@!N! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN! BHN!A!7kkkʊ8b|2&''!>(y<-B@{qniiəÝ;w\0:V3ހyE05d7®T4Y ߙfZ^p030<<.]Gy%<  G0;;[n^wEQX3 eq]Bqgaj]ǵq v%LMMQ!! 脜\.j3T**ԝ}Al{w !:!PZ#l6۱Wu 86p8@"TS)Tm;[;Xnbu3|rrRrZږDj$-DBяE#f"NvwE8!3 hۭWl3uH3SiLO =̗JX氺.gau'{coF±#(ILLabt#$~EÀ:!G0M@63ntTLM13@,60p󋸻F<'pC&5S$GyP@'qYܹs5^̦'RfX`vaw1[w={>d_n$(Ҵ9ܼymt̬\[Y3Si 63q0w1 $(D'0"/0p"^dDﺽ8Ab^˜uK2/6?c;L²ؖ,ہcmuvڀx75uqߏ[#ϏN5$G0|=y(\.תPVn3Jcl$PWÛW7Pm CqPaP $s71c`=kIs]K.lDži9tFnYh,hGBlB05m9Gd\~=cOK@,:Q@';BU~6LO19$ XZ{ o^wϽœ1@ DS bI`D/@8w>a a H">[|aaZmCU^q]؎qizBjV1Q-Ъ ͆Ys-WH8aO\S kr(j ⛛]̚AKYf(z޼zߺz;rO &D " B!$Bc-_g8$##Aw`t~ } .\7w\b-_BX8=iOxdˆճ ñar@i¦rN(Yo>Տ+dO^~O_y,$QߔP@'}h֭[j6[浙e03$ 7߹ߛ=B6%$ #5G,@Ȃp3cVjtV(p~㺸E~ԃL`;.lٻt]XDž:~kn ¶bV7Q/XlN_Y8Jun#{cK8w]mpX v`:6Lǁi;]iuEN;؎mC,J: [:v65T wLhy f|I/?2tsTEDSiTͷ^ǝSc@(#c`J#ē>D>Q˕[:1} M걝Tu];c% S80 s; ;wqR mahX5ۛ9zr1=rW}'=NJͬco7mfRlz*cxm|oy(!: 1b0b!3@w7߾z9sC]OVg+ե:by Wt`-_n`9ވ>G7G0uӄf(W l.QZonaK>OOi|ONN*mnZm6 FyR_}M_GjT)AD{8EEB^7,]g!:A0b h&,v߱xcѶO6KO ac7_Eԅv?Vٵ\OG1:iͯݲѰ- KuYꖉaak :*I__4zi'P@'^Ph . ޡ,34&ƓDoڭ;?KU=vd N{AA 8=\0l+ a n[Ntێbn50K. 8./{d{#rеch&e[r59FcxEP\Z-mҶ2SpK,޴><3vqq}mŚh:N+ao7uQ7MT 5,W-Ts #/~Ч/Px0+ qA ޥ tU^ߍ sqy(evRq]UF WՠO9Ʊ=2~3??Q缈y({*ͶjQ%~dH3i6̺)+o9 b 2OKUA@hu!"+)ʑX.^qJY\b BpdNΕ 0yrvj0|d8.BZoA]8B{Ͳmq+=wZec3_aX[zo]dTYtrA V @l<9Bħzr@0Q3MtZ &-`Zi?^~{^Ͼ E>ȃC|>ߪP/j3 `PQ֏N 2~dC {_g IQY90z91EEDM:Jo-a[%;5q;6tˆب ߾]4"Mkh{#9v=@@Q8}myin. <ϼKvEP5 fs9A*߽q*}Pޖ] hyf:0t߾#As- U@;]E0T_ {dIaz%|W ߋP|"EJ7o,bz*6㸮/7G~7ڨ xy!c, EnPӰyp5u!5F`"4V̂>XQEf^,hUZ͆VP0-͵sJw< HdpڼT׫`͔U^ee1W@Zd,8 sDX=0_$?$Nm e{p/ ,(b<'vٳO> ^Gtuu!$# 4M;Y\`z > bz2Ƀmfi_ qڑ %L"@b/D~uQ_sv*5,wX+ ^W^y-`p7`t8Qt]-bhӭ5**Ɍalx1q}?4ͭc-7W]ŚrCُͤA3 Dvfggt6P z_KJ> #Jc!#"FQYF?ةnY(6(z۩8(4xga j]va  @NccRUVxE+~L~4 AP"x P:,K,5=ouQL b3_FqrPXQ7_U(xfwoį(<|AjDx(!;ߔnZXϕ;%ȵUY#x79M?|UZ[K$q _3p;y,ϝxAyO?B=]P@']̬}AsX Si 7 0RW"H07'.0Ϗܽa[تQ=C|\VP*Mh@Wqg똷л| 88cnce>i\nNY\0ӻ%/(aj򂾨.x膅byu# `d0u$/qsݣ2HhՕur-Z~]R8\N@xhu wJN뷫Gmwa G؏}'0?:9 bvv7o<ͬ; <8'>줾/V`<E#P+T}]ӛmcKlik+R6vmoR4Q[( XFW!@ڇ~2c0 6E C}"\3s: h}f w)0x=,@iz_L/&B?&jôaD$Ȣ\# 7(mS7rxݶ[$"+٫u˸N:sJ+>>'06<BN+~631 `f232;r!P8 n_q<6gb*UI8PEalfq0r:J4[ ,A9o3P)8&A- XՅ:Q^'9l/2b"|^D(a 3ֺ>n| ޔnW:nW{ df:=iV//ZA=oA+Z ֙=p ͓5,@ (,6uKc>O ϶+ Srfu6d3iL(eͿVyēi3ø;58Fx]<a:pfӽlfk3v>yC״ۊ5񍥮oyTQ0 'خ0ہn|C;0*LCG( P{ bZ\ \33l__DD|e؂C<Ʊnl D(@Z&vrY4?'#ʀC0PTPV`j< LI=/#p(/JXP:?d^I"^~dk:nY(44TnY7B{QW"a<\p +5}{x~ÿ_Fn,Nf6dx5 |5-.tΣauN @&DTW;Cz\Jsu]CwV8[EvI;rn8Wst)ea___tox$6!xy,W  )|Pl,ace ;=%YFjx1ةT66v>7y^x!2 6 6@ r Gl"3a2*T(68o%/sZa[)hXw3+ϱǿzp]˘;C$f&ȜSY'wno~>C8601\X|$BHڛ/5su] mP.vځtƎuɌFR0qwƹrf\Wk/:þ #Oc ,y#lQ$ H&cHUT ]26V]]ț1D 1Guz+M,odFmzO*P|5zq\,o[ى;  !|s`H5n屲Sj=q]liZk=uuQ2tT~,"CٸN 矒.F/w@H,y<$Iߧ""@,h$Ф3]N.WP.{~?D,o4}3/#_*uiecpF횖7 dwm't'vn$*PE^ybCCQ۶Տ{' Hj׵Z9;_+}]%g#>?]`B;;;JR6 G1ALO11(^7? o~.ɏxF!H(_3=^=`^o _sa<Xt=.c=\WoF.h\e$1$CQgx"CD~LN ad8h4Y:"7v67'[FZi6`۽AD"3R#cP}S,2n]Ƶ_YACI c>d>i7tۥtc/'b!t7OQYvt 4?bciI Yz %:S뜆y}?3>h(?$rWLmfSiLCy1ŎsOHkGC!gs*{#u]r]pHPems6goRbm▁'2_zJ2BٷTU!TEF2(2qwko%!$̌ X¶e! Ffj~xv;n "t*ǐ~ҏ:hg,DZ q5UceP5M;O(2" 25DVEhƗwPW#84 i^S BJcz"}nmfBMw?v}*9㙟LBq=s֝%uUv]0pPcةYe.*]LGjaV F߉{c6p_s "D2<;GiECK#>=9kjG/l|Hf #;;o66^\X'+jk=14 Qٲl]ksXgUA%# ` 8|vwGR)M1À"v. r Z5 x~~jܶ|6pho7n3L5Hd@$6x/egx7`݂fxk~`[amDQaհ^cz|xB&@<=[ K"E@,'p>ޜ@/$2È " ٕe,bsmV=a0i@N]71{6XހiƖ<&'{w$p\(1Rԣ3pɅnX( ^\p' _w; ?ywnn<#CU^h1f6=Tm3J:c QN?hϣNn/-??q$.(j͑5`Zw7[}mC+~3M˷+Xծ&Br¥Y h|(?S[O38j{]e^LT+tbW4@"ua֗z{ap5>Lj,d1{kWo vʽcsw˜7~.0 w.h [KXyg~[?s󾢀~|wggg[OB,Wl*LlKXYFҾbrh/g?g?[m ΨxxshSQH0@l mc^jACε  Ev'YkkKqŇ4ةF ߯BDeĕi$vwuL\z 3$4trʮcg3 CF( J#A"3Hl]˞V7pzq|'%(jo{onv 1`Rci (I da;X* &Bmf]v1q0GyllO _fN]>Q@@~~ɽq= Rsx^ZˋȮ.#_<'A"3|寽W;ms;9c Hk4gyX E\]Zo{[u gvns׫Ъtоc .,b \D<9>U(~>U tڡcq$Num[ȭy%OPܢ> OL!3:T瓌|c F0jڷ G:4r .nliخkBFh bF(Kwvȑ?x1,A'#PЏģﻸ6ֱ*jSػpni~m,euqGC48s&+_bi%-l抭 ^Ѫ8fS a9$" t7  PtצZ3-h"k," W_u] 8Ʀ( ~?|>y4$F16H|¢R~ƳV-֥g?˿V2 ƀ,c$@ H0ꖉrN3|nfvOcP84WC9o@ \9p;af0&CN*K"TU0qӲvQeW5zoi]с Si)'>@(|ѾVݷmR#H BQV87 X\ai%JsߺnX(Xbtv;AsO΋qHvCHc dΘwۛYl,Zz[gG'W,1Ddi/Zi%]j }^?~np|_i<Fb'22"'_@7y9\l.}¯@"=lKa{-_biJ*v̄9RBR0Y􋸵1C S\ok1D-{{_5mU漀B9PRNۀGxWp:_7^T/+-\YeoavY~ĩ3W6{Z 0i{URd"a&Us`F;R)lwj(vHW7uuӶ)1iU]$"㕏dϏ{?U*X_lgl ˆg c096~?8㸸P"jrFF;;SianwRc# Ģ'O!<$fibsmKȮ,ev7gd@>+-7*yQoiXV~<|~,٥w.{H RfD _l}\(0t]i0t @QTHYQ#bDz^ fS3% E#14D b<^E]<bQ#\~d>Vg՚fCMxeۚkn.ϼY2g8Kka8,r/\CCq@~ j03殺_}+앏|T}+}.OqyKmlqf +lK[RRLV˭Լn,oB0b|$2[Q$ƽTε.loꆅ[t sH?;*uE  Cn3.r{bt ȉӓ#'_<Ý:PFCBQ|zCC^CR~ >TpppP8?ߋ4tdWW۶3/ Pk ,-oaq%V{*\Gt|*=cz"Sftaf9]0 a]/vR uϖ^ u,'66 t҇tvKͻZU[yU, T*XµKE#C=}j>:@t0Ǟ :6Vk𕎅jyoAszenuܣy?㐈n!8o+~sM^C ,~1=5r7WQV!"^اU^Ca{ 7ekVBUz@(DD $с ]WT|g+U51Kס*5v{4pQq8qm'g}{{B JAUNR@@?ֿSEmo7OOs(=5oXXl>5|w x-C>ADq(ۚMò|९ `Evf–ݶiH㉑i(b}ϒ(`p0o#_ǝ{ZsP|juUqce [=4T%T˥Z(b0Ffl yJdlTrk;0;Uc*W "a{R{<5rS-kNz0ulo{Emcmm ӭ1nߘ1`a\ۋ+a ߟU>Ֆi~Ssds|@h'L_} Fl"qm&a{+jsʝ*כӑ8.gObW'Թvk}eջwzN;`QәU#B"=X lbkc,DvueǑ 2ۃ/T'>38}5*?Bѓ4ܯiUP=j+Y8FkY\=t.蘂ظ6j_7 O 鄊tKCU޻Ye4͞éyYQ5X}8FGPHo]8` WvG¾V~h؛l4,\}%n<ĉJ~>ԇ15}O?kܭKU~*DID"30# JH !5<7֐[_ o碰Ca+2cyI =hF[[oJu(|^x:q[ %萚 vWX7z05ǍmS,Z,Ay6nvkދW˰vX` =2 IDATԉyⳟyG)!k(l4L-cmq 'AdYƧxsћ+\[En}qtOX[\q<":xڠ'a#>U0>噳OB 9 p"8QE|X°51}*́aBP(b||r<#>Xݎ po@D ?6=,¿_?/~O> [b~ kj`@Hcq|oWs3͓|7az oY4;x˛Ks6ءZ"WJ?{o&}~~g}}]3˒wx!`B$@H!$B qBcK%K#4W׾?NwuUWUo==9=󨧺=}}./qEv!؈GIu]Y]#$I-45K:U4>`aF I.''<{ma121yS?㭤^7#<rRܭBPHn_K*Rã$PrBuI\NXmzKh&4q.<_5쇸'$ 9䞍:/uHw_.Wpdj4@>pNum*z&a2ސm H8{Mv(/ 6UWɮxힱ0t)fZ`(Ltf޾ = jUAfd"}1&^8ԟYϕ&ulۡtJL`dHe'zul{7oDpht̰I*Xe$h$%ꢦ6ݐU'-}?ŭt1 3,^ZΩ׫!IObm鼺emTVMsϕ+s{KwFFTTeHl{l;U==;,76W9J:BJC7Lo<"E„B0P2Jh*X3$8vXXZoTJ?KHbܭ@ mw9 Y)rᱝtۦfDJdÄG%Ļ*핡7XFzKo{MQ M(<`?؞_-0sFUn &Qh/#:XC].R}JtX_[a}mI%)b$ʶ@__w}c:"FۜLCZ)SutM5LĵmiȲ$+ȲL $Dē}[*ju+}TzXc*=̉%RA HF ro\9Dw wBHpI^mYЛH^@xslOgkGhYwZW+,Iyz+M)\i@nzqlJ<D'=qE$1>NJt5$vuSJ(PRO9<[^J㌖tbG+IDbJبvPB=H }gćZk+O۽t#u`\&1BV^tnu 5m, Bx$D4ܺi<ܢ-: .EgZzh~QGQnA*n9>=J.O˯7~!r JJ[k/;ԁ^?|;!qUmxP5'ߞg/7K%q|A92ͭ^l?hQ 7t\dnLi\lۥZ7 "!T ub8.&E9@O<@9;W0$346mz3zTzUPR%K9.(Y_}F`Ou=73*u[$G n63yއݟĭt#K?bռg^7L^^X;Li&s+yR1.s.D8OqUʔK*"FZ(r遭mVXYㅧL"mȮ"=T=9ۘ|whrQ6fFne.WMݣt P̝ݏHѶCJO󓟺dzW|A9\4x(!J7ąvxqn.1.k 턤m'mD4$H¨W^)KQ7_}y # M08:Now0?Tp{T~(]|F\zuKMP6Vr9/:(itu]qq\.5ˢn.Y{_{Գ~~K|[>zˏk7|A9vIm0lx)WVb4f;K1]_* ѽhNMdS[Ca0'Ϝo|.ϳ47,un\c5f`hlbVә[*=_J 3yK@ ?tck$t vjzMK0nyYMiP1 ޗq 2Hgۇ:oc#pdHx\ЈsUX.ɖ[6lNFv8\Ħfl4t"DltfUOO8fNu]Wl|]%Dve}H,d談o%RmmTzTkD{Ky9'O?o+.D\/ZvtZIԊ:z k?ۈɷ$Mi[e4]oau}e,,n)~LJY>ĥW_lK.P/.:ni1l;-?J$YpNTg^!\ ^tY$f6ƶr$W!fSq,M p6.>k*K'εΓc¨69iF8DaRKq\'f>(dltU$5jMga)G@UH&#QX?lGVưz糫;fl]tEQw`x"0y۶)gY_]fea0=q;@vyϮ$Ν:_yϴ| '%7V/ BtNjyXUMg"n 3:ŅpޭtC]{M.SM,EunՄ+P( WL: oWbbZU*݆ZZ$ F2,,QdH`>R}t,Ks3,nY0ean8Cc z{%~*_:q@A,lEw^]YCLZkNCFp'ͺV'ձ%{>XZ)BF|ۿx _}/=QPBgum;f-B-qU6ܯ\m3\C`9eA$I"PQU3xJ?K%01O_|0g1q]Ybivi*Qo˱.;0('S:NTkV6:VZ/%ҏ1w/~ bAplҺAOfjŀfA 욄k261vuVLQ?!^R/7?]^ ϡR*)R]i* ) ޺7\oof+m/+[eJ4wd$B!Zj8hx®ĢzײEֲE5cLgN *$xTJEo" ٕ9p 8eK̭2=Jv}T녏}_yA% 4%7A!%ސ1|XeV%£6KݯVkAY!pN}Vzm}/_c:Z_}]O u{"Tvml7B3E޼cK˨t4ىLa5)WMlSw01 ǶY]FDBJ4^yuW^CQdFz01|,̽p0M9*"#e,,3=RbDJ猟Jy!+ϷckҨB~++d-> $`񴼹xS6ZŠJO(6AW_}^W|r0|?I\ja{⺒MAX}FH Fຐkte^u]Yρ,+bQ"0P:?˲7VM21xyU 0:y@D5&-,溦U.tEM{^;jyL803qli}R_v&j3 jD:LvADvL  RoDpYٳQ ϡaY6J,|Ȓh8ÁBE+b Ŕ啖ǂa!@q;'o!77ͅ,VubZgbbH$B4!4֋y%5PֲE7DS!~*Mgrq8L>k;p8F|7Ml6eYD"W`d{PQ7H!=^k7^NՇtCcnqd'p%4t)[3J QNmш™{yztթ+5 Ӌ]ץZRz`0{j^eb aYWgZwo*>{#N~Op6Hej" zϣoX&WUdY&*괪z& fmrݘy _}^/t'w?D_\FEkO:T奶1{U;[h(a"!7>qT˯YRn{Jͩ }KW'sWݩ'Oloz=ůmuX֨kNݜd}'O㠵ϻWDz;_u}oV ϡ1x1F{poL/`;.خ|=jͶ ^SŲ,JGH;ܩ$+Y^scL6Nj~Sbc?RgN91|G෉Ju!@ϮG2"59J!b&X%:P+FY|Q49|AX[)HFQ0] @H$P02+ B`h$I4\w# ` E{-l/@ef~j~~KoF*;f[j.6U.|ko箕='0<4. 5mJePp[jkf+[Ǧu K՚J#/q?|뽉œ Jz2$F;C\F2u3lz0^ E9Ϳ"&OfX[S[s W//HҟIHE.ؕr(;7>YFިtąrX;@]iQw ô xNz-kY7Rs=}p(/_/MpܴFnZC IO=g2<>紛%2[5鼠|VVW|AGdR,vQhT+W6}qdYR1;\ ziƣi2\N$Y_uw[_э] YTL_wo\LN(w{/~|;FzBpXHZ!V(]vn{lC@4~ouɓf bq~u$I"e}auߥeͰmBU#J4_Yq6Ao5Ll=\sNi{ů04ku8`(!{VU= cpKUE%G w+ ~OO]l>_af:R]r0 b9N+yJ' z7@p  \y}Vg܊ܥ\zDxy;~}Wi%dn}\ J O+Sޟ[#dz UM[\ϟWvS&F]!; IDATy<5"NjE"Z)R8ƞA5k\ƈTRavBmȲ̇|]w ˻Ga%ҶLNj7#`L2JΕ?̡۷# ]H*#?qTq\Dv,5k+⭛f$A:$Aas%x/muZM ge ?ƍė_yϸ ӡMQL뷢}*ɑ MȚӶ1lׅ٧J~|362q;d|AK<5 ^?m;IPg[V0YܛI''Nsr4;R$z33\!wdMլI5kb2#Lj3rv=7zS\'RG;>V ]J_&A,ޱ/}tKvLR֢whEDUl!d,6QU%(o3)kͭ{rH"%J | >-+ٖWDbN{Isۛ|ZI{-E1=wif\BKU/U 1pXpZbj:fS ,:/#nS\zagjTriSu[w(ۤGWdWMꭤETm_UCa^@$tx $|[I' rv]^\r>f;. N<^;J)CJצ<{.[>GG" qZw[,,3 _r.֛F~ZCRɑ J`MnZ7}ց@hK_rR<M ]PWk{;ٜfNcJ'5r-bΧ[sf= 0X @TU_'*JrZegzH[QV|:S.r & LDݧϝ$ɌL062gV,4,L30Ҝkvq,F~upD'?rxSrϋS:^s_bLʥ}u]y,aܕ%tFtWjֽyimA7ГaPL$TsO^>arrVClqc"`4k^텽&ZtD}}qu/]ȋ_k8}d'~/~ؘF8ęBir:j i,vwھ2HBbdp1MZʥ+//=gր]-X4.C?li>%nۺ?|xG~5G/w9$1>WڕqU0K(*Q+;ǭkDdD̕hiv%(GlNIәH%"XCP_w0}uj_b s p7>&Лw3SOa#O|3~xӣo%vg=<#?"_hcۼO/ӌ=YRO 9|Aat+]hwu]fn4ZdK ,ر8b-R,jIYCLUI Yo@35wgJ9P8^TTdܖؖK_^̮ 5O F;8uôl.و kzпW/W:~>pI@Pax,Lv'o r1t!kCܽ8Ԗmz;QUmDB Em;u41 ݴq6$IPeB0 ȒDb(ߝ ][×/NSN'' w-ir~$K:"|ӯ ̈+^{W["@<~d O,̮ii'BARF*#*ԛ D6U+&';Ǖt#be*IAIu)$D"XM0`"dX@m\eXTպ0;[hhhd@L_ex^ TvZ{97ޏ$=};Cݹy 11{ߋ^,z{>1#l? 00zaJ붥7\Ud]`i`ZŰ 6ZId2 V+żgPḫ&G<ywjx˥Z7W_?͟,;Os {34#8'uͬ@nO Y^5xTJuVz'^3qs\yXsTV6 :}0.2'Nt3"ub)W^IAve*尸V$ ћ! \J,^â\ss 3hHTз "uz{K`O0}|n)J$˾R{#}w;X䩁} z$RI(з%`gRY yM#Hخld"$ז1-WL CI E]lFUcrKkm+ v0= 'ߑ; ֯ɾQ[??L-ZO @4FX!RAw4G||F綠?A<\ڛ[*fe[f pk_Kv.KQ:BL@ + 0[.1H" AYɖ;WID(JNc:P״6D2}\nP7L{  0$:%:TU0Wlh1 CV)m-4 Ft^|A^z~zOM(e;Ț8M=ci=Jw\RYFm%I+ 8)v$oKI)^dR1E1T'FA+kucOL80HG⸎KyŤS).Xi?"$1>ɑAN 0m"8*jM *qIvyDOX9&~&[yt%3" R>4 6]1!QrkxKcn9ӥ"')TIfY,˔c(DC2$(4 u"BDU[%@=C5(l1r\ 1 1`Q.5). c;SL-'_0>ljN gL lR*F1_%t!8v"!Mh fHn{ fXD2,IMBҺP0m,3R *A+ aEA,JfY(NC*^7oN;S ?]+Z7Ľ8S3 e^_@Ud81p>Cpgnqkkhsqӂ~*ޭ{O  37>h/7-w řBp7R.5;uݦT4H${4bfcݲm&[Hc\EY &eq]$15@<q!Qv\lv]lŰ,GWJ* P)g iXXƂWE>N g81a|@{ʶXu Jnm>>3Grgt O8M7lg.$?ڕ];>JɆ,)[iDc*,(-J&s)k>w2ƅ'Nk_yz籽gfjY ƇS,iZS}\uq6iv>uSGًg$"Z !(;eVkUz"ITً]%!*"ooE5o|8V=@ $Mr -mNTex4Fa"H Y/V쎳ZtAQVXm Z!H;וUl>9MAbk|k@ 2N;q,!e5z,@D Dq6LP>ܣQ|CׅҢNnJ#7Q]_Yr\__'gNIRco}|n'uv ~S'Έ0>YQU"; oo }{W蕴E& s TK::i~Sԟg~3g݁v/N<\<|xeiFd7^UV\6Vg"Dc*S/7B YLRb1Z"{\d #J$13֗BQǘԿ8\rZJ0lQ T piڹ`6U:-ddtYх ˶yu|üESa cJ3;ƣ8v݄~kD9{`Lf8~MȗgG_8+OO9'N K IDAT7v|PA7'\[L*N]WWjaj IvY!(p\F]3ᗫR1U%PM Y&Dt<_Rc/*4Sռ,GE6mcwTth떗7ۇ臯&n Y yjK][\E^]d7?Y+3צ)Z*n|n?n*,K$$b>_,S1-ö eU>&}» .TVIW8ѐ[?"LEڋmD@H4H xrkT NzR,vc=K$3 }#;=N.eaalITPe7}V). шfVUҺeqc5ZmΠ\ò1O-0mWr% uI $+dPx#oQ1 ʦA}jDb#h?W!?5?s/7=}|bob/>;r䂾)J}q`"N)Xlq5RMT ez6WmLi"?>'oV#Z}ҧ>L0>:ɉc0yrW^{/NPmk8z2|dwH.#v8; yv+H<7建{zκYww p8gDIPȐB!=H/C HHB % {۽5;3ޖzU]f'bbcAs-nG!k m7}Jnr$Le2fΣ8 C+IT;~,Zm ,Ȃ unlޛ_RrbO1e L8yt|~)om,{]pTm?WMK|#>Xm}ih``NMw gi*z?-D'3?xJ "t|+zfb.|Ƽ]6nwi.9 ΄QȽ%>~~1| N>suwE1Ш[\,!k֮Z|F:nyDQLeij#ޱ; {nx5iwlk29E%i'(AJа]2M.MmP# ž&;' xMץ .WK\T7:,:v /Zt"K=gu $#uyU& w9 O_2}#mi-_/zn拟|k%c֗X]X! w2Qwfy}\!ϹOrG<J҂sqaR{km۽oP$EJ{*$k!~@7ܵz. dd0aqҨt] 6J O|)Zr~;t$I w?X8Ux)޼zo7ƲȕrEUS12EsC;L +"Qk *y2ћ,vڬv-NA0xmSmdQĐLYPk]W[#zXF>%PHUlyPq5XIĘd0z4Ib40M0kn"OlosMfFGSOͰ7k gc4k }jKDa(L_4QӃ UU`@'[.nP 84=1i_'] n*{85ppvz"rZ$lt)bE[۱1rabD7cE,; ? A}+H^KVrQDsi{M_ YƐʈ@ESU9c=,Fy,e@=,o4Еۂ% L( fu]MI3C76M?e0vEg'~"?eng?v>mE:ǭ- דeG\>bD?NUm;+ o\`]ku~SuQHDz3#͚xl %A4x"E9{a3gմ(2b"grdQ䃍+Gtb͚zʯ, c,%bI^omt!)BE>~퉾YE}k54Lmt\4iBο?$bVf{Fq\SS>,5<:w`s)+9L9v( HgMu([o~SL aյk-|Gg#Bǔ*c#1ql-ݶ{ܮOaU,xVU(20c*<#A;pL߯32TuVӐq{u XfBdFx5I".^`6"SS% 1Ai;3e$ڨo (!Dܧ׬Qw퀉 YI0 cj>ՀLad8gӉM#%jq€{.yQ$ E(GgH?KS~u\oY\(#q:Gsx~ZKکL Ӥ:lvtjJ<g_r4՚/ʧ_kO sڦ-1 8h֛-&!յjjpԮsñ/->fPh_ң Ԧ$(r+LmQ{M7xbɁju8.nXkL)c5F#YU!*'ifV B@8 gΎ.xZg嘩s}bwj;)}΅С\1fw1D 2ɓvHҷUh!k{΢04i H*J(EC/p G u~T{me8[WEA'awd-v( 6w/_*򙏠B ՋK={Ճ ֛ỽvskDQ乩}Ĉp" xEd6P8ZSN#_6x 6 5lIc&~0P%∘05Jo;.uV_p:"3]sv,;e9IaҕIW[x,l'Bm\~-iQxv͵f CAYE>2Q*Ǎ=gԗ}kqN#cZKkn."ԢMEik飍jS ;w\eQDm8E հ# 94 W5FǴ=ut`;ev]Y|}͜^*:qCb7E.2o\=(T?1"=fs(RFGTq^ow޴x4.}r'f]1a`v>885gDjs>dt(ȍy"Ьwz U=+ɖdNӁ7=g*Ʉc@@ lEQ{ExIB(^UDT"o!aˌg`ΐe򔍀N;u]νcɭ?QKFU^~~~ Fm<=Qn±l*S>#JvWxDtmcWv};Hw |,m}xڶˏgyr|.]J*c\(s{v vloFUx~jW;udmB~bҘN^vq:Ncc';&OlmցZ PD5IB'|˪vK%ADwD^EH! ~Ŕ̬Eԝ۽_#)\);]+FH< s?l1VB?*$- cEUg*z#/fp~0#1lDKUI #rܡ#cCuY"gmaP6 ZKvpS$A`:,Yčq/$Fnz?F??3>I~DMS%h_{ײWDaHy:8}NLO::Bc ZMռ$lw뒂$A-," ]@dx:WmPe0Nֱr|vAݸw4CaXI>1ƽz]Fc"Q-(anym3~j 24) O8%(l qXug'hk,QU䗾DpֻtCyP:XixEyWYqﶈS6a_MU>Y Sj D."r_#ʉK7G=v:׻6mn}D{A8*NkFK9Sy|:ţĥ+z,|0;`{R"®HRA^=/dybmK fd}wj>ur)jUI (qkk.KEqgͩ/ZrO6nԹjR0'~5+>)i(i:O>+9^ zu~̔,aҵ*c{^#FǎЛ ۋ`>FFy24~,P8[v+ Ah̡Jb-+@rXmu|&d:Vg-sʳgyoј̚{=%cD7i;XtbIPԆryo%#D(gc?L]!cC0.vmrR d6 ?. 0if(j:]+5. 9tIfsS*/i잯`||Ӫذ66?5bQ9Kn΋J (ZgKq Șh<QdM?n9ʠ8lMCe2ݵG.>17g5INDU^8SZ{W(k!Aqp<$5vۣ\13+^Ls- B"f^:$Bw_"ÑaӍ|V$me5S;`{\4*c$q!yt7 tYbI˚3_*F; NI[xaą'/uf&nTG8 '+ѩt+w]VyW|:">ʖ fG1]giSul{=M Vz&gΖ8 d񜎮 weS3nQ/ףV ~Je ?) bՀ;.3?rǥ] ^l:4|a?KW^N5'i.KV,n CV,vT;ʕbabz[w i1Gb>8AWÃWyo[Rn(sF8xVz=Csva˭6 Gǿ AGsš(\Т.K\-{F E+i|m݀6C4DqV#d̛6+>_L]SnlyX8p8r2걮*nwӨsVMDoۺETm;:KNZ& ɪݞAR,Wcu^jYKͭUcͷE=n8bq9VN&80wm6<a)/de {;xq!0h8^5K) uOޅA23W-3%E~rsʭڞyu!e-"̋Y8få E982.͂[w/fXXm8ROjbSC:|}7_ETco/)h~^ 1l;4q9$R["Ȣ* }(t}XPT!Ye 07lCF8,[㑂WsƙY;[ ^x,$Z!٭>hڷRtbՐ0+šM)@tt7VYzc t"=Qp 5mGW׮NN r^`-a2⦬Eq ܽ6v7zAHHQP38GՏ${b[-A |4= 'xNDPIՔM1>ނnf4&./}n\Ds^,|?'oOQ6 ƽzko'&!aF ʊG0=NǧM}B&#cf#^T4LE#c( BnD׊ȕde]14>-WVLe2{s{y (i[6?Y Sd6fs̷[=eNod9 G4nb~Z9$i41+ ׎ilz7B^4 6K u;98N-d=:Czaȝfbqhl{.u79=/Q&=A{49zf;zQ5yKd_K?vm8s1Ik#ű]4Qv~9L[>ܘU$x=_F1V+YYxϥwVe^4tSW&_~|6}&z3/OOp\bj"#!|r=CzemƊ?i0lZj=D?# AwȅZή6IHj$q.g\FNyz]));G,'RX"m[UQFNocamCЈ>9%=HU,e!OlRgR+EO=f߲.DJiFc\|Jn|WNp6 a:.Hpζ}feilD;/鐿Gb` .J̺mlMۍQ{pkecoK>i}!}*g;KRJ+eЗfiT̍џ }(s7N("(Gէ)L&{_YU޻' ;C6MX4CBc9-A>f\ґ_dWgxb*aEK70h<-Q0ͤ0cZf^0!cNqvS~ju& ln͵ _$4;OXG2kY^}pIψ:SeXyܿtf#VAT)Nkq 5^>Ʃna" 5:!B ?UJ}cGB@GGeXGb""%H7ߍ!k}+ڝQί类gz͌Ƶgw#W.U?{Njz,dȅBJ\#y1RbE 2 6Exdy㘇n+ L9#wzDA̤_P@w; ˘nqc3+|O&n-TQԜ-Puza]{?"\uS쵔=cܮ/P_O#ON5>mτaWw,R( M 0# Ui31_Z?(Ͽty0TsW?Ɵ}]jrۏ&K\*9_ȲԲ Z! !@V$<@8wY9XnD2CeHBjiȺ3i1UK0p{睔5$"k]a}'4 0dl"c zuJTHяg8`K엗,6i4% !w\AΘN#>N縮r띔xYr]!"gg&юLEE泼zv'E!F ä!'?\Ev;>o2wfc;rd7Vsl}5c9^j߁)+dͼ+Ș?kUDQ8]t;YVcیO1"oAPq @EQ UUq`R Z8nb=DQ[ ܶ6>¥ʩ]ÕKLoEfr?~A`"k25i..59ML;tH !*Sq rtokjHBr[%Kص< 6w]Ntٯ.EZOxF1c &bD鰙zvJת{o6VRe i,ȲL}u+ ~Ĉ- tt tX#]Fecͦanz8 @LYl|}kvW)9;1d|Ӌc Gyԑ Y^ƙ ĝ8.7eeGĝn}l:z=Rm] S"]ߧ"nϞ] Y&ͤȢHYzg]ßAjt-6>3yn]V~.%cZGqiݔ6SVn{B,1uJg+Yh; Oncjwdt{aHP g }0:@Q zFF}ncm:0f.CJ\T0v#qlAڌ~>}}qjk*lH҃qm'EWLy0]JE+|ozGv;, P44{_[ݦc2̲|]\^Tx}֖||7f3]Sh*JEs񣈆0 YҎpV$I2.笪"~ԿrFG~?jdsTA%su#FT#ow/};IuBV,rY}k{@:չ̃QS3sSMcwzHqk'qZlE@8Vӣ)4ynjjq"<0>,}s4o|= MDJIJquJI'O~0>_(oD.zSfbZ( MYV .m.z8emapYdrvu<" <p#$A tߛ.I?(M=t[p4PX^Ơ݈؍(^H^Y!#EQo8U(p]==͓OL߻bCICeʚLYmߡX;anqڔt fdt ,% {+&Ɩֱu8PpIv+)+{{T2.WwDA:@Iױ;1e* 6j:EI4{7_)|m&sk33'1NDsov؄u笄G+w[ ϼp>^顩2g/ޠRb'oJs\$Aϔx*?ɹLj [Q"W#>Vq ,/Jam%"r逑͘@ ;MҖaʁُ"˖Tw䳽1MaF8![AϷ|mFڌ gϜ4K q7$ZD=46B`b<7Q0):f \̖2(bZch;NB'u=q]w*pntiAU?MɢH}`%j_6t_f$)?.=k3¯Wb.ڋ<-;6Q͇Tb_bAwo |̥+Sʽ֏ K_Xa”U&.C ~X<lZēS>< ƯʗӓS?i4If\r%_|f$8+>vT)grR$cIGdV Lro0h!=Y3&<7 l~3ba !o_מ~!jN"^ߨ=~HY^0$+Ͽ`XO&+yW^ᙧΐh(}@$WƴLֱ-aQA5bV-R3P\4UftƋrHD/f8;QtrVJ71 澵$`MBA <{/?GG|mFG%LOMW0&Z߳WMta{nq~S*|o]'짯Q)g1 Ȩ̤$SF!.cpnv8uZu'JnA@W Y'K,115UehAOgE4ضߝy-5f.돢~ bډ>hǿ%Zarlz|3ZH6=Gڗ_gf. %J„؅4zᲺݞo0p(}c5d(Jq? )G*RV)F1ᆇK=tSo5sSA1oO_?ï~E^qIL,QDAgz$ &]wѵd-#hW?♆t7 ql5":@l{Q@ǸϏFQS<"{#QL%s sE_zx]?L&sǮ_8\1rY*V]DL ~@jD񼐥v7tz&<voDv75IQO^^rE#NGk0__—_'?֮.|̓ק>k]SvukW'hwuյ˫MmUUp!,a*  I*i 1qX1Q8펃aDqD)1 EQe-$(0iv='k{emK?,,u Hm$[Iǐ(ʑiĈ }wC(Q37-*_|]rY\VA(HD&MAui4:̮Ro {Lb wKpF (kz?qks8yvxiwM:|#f9@Ͳ zpt٨/}M#FH?$6a"v}UUQ՝Ԯ$I':(I!or4t-,n0;j9;A ^kujD ;׷:0 IDAT}٥<5}(4=wCv?JI :ddS:(`X{ή-xy>g}M#FĨ!ڌP)O|ؗҗ s}?/܋P!5~P?X^0֮c2ƋϜ/y3.vc]ruVmaJ CvpQRvv1ASF?bQ DeW^ȇ}qooun {Tp![F޷MbH}Di2#v+)r Q|'\iĈA}D_fnШ*sLCc7.SH X.Q_[pWߛvo1@hR;51H^0s{uc?x[HEDMKjȺp>3s߭ O~98B$JwܓG<ތ}D0֮ƙz'A֡kݐqkx蛖r}Nl~ow`aIKrW3Rq|}M#F b$#z,\~>^cqk}{wVhWW$IKOjIxN9cz^ M=cDP(}1fgF8,#A WS&֮QkF""nZ8y/!m|qC&sUg| nDĶxAOj?f{]yđm?gΒ/cww `PkSx1y)vq)E^tàYnG!1.z'E.qF>Hn.o~h@TsU_:F0ha+BP#Z>;J9C֌AyT ׊ƹ+Zt9(j8?rX\BIϖɠ:^ *A(])SBE#α=><8\+V`CtZs+*2e[P{~;rqh4\\:'v)E-G`GH/ kX[zsW.ʥuhL3YLf`{nEq~^Gݭ xuA x\.HXLP6_Qk6twBAENwNHb [X].au$fݙ_]@J"]YmsPLLaǛ6zzG%Ur#/i]\h3vxJ]Zn3%QT ~s15$@J=Ң8( p A UZF~rRkݴ[H5Biеq]/N @Jx"b2z`ImW?t g(I08 (P,԰λۍ?L[ݏ*^)@I5Mл]pkD]-[Vd#]k~JaQcJcr*_y.[)\ڽW MЍg!`N 3SDOuFRmw͏y[/dLJQW  %!s\s=FQ?cm\4z{q"RBHpe]55ks -!%}q@"2(L#S8td RH`K͟oke]S_+7bý(yH6`F*-bX\Ñ!rfyc_:e7CdW-q+eQ8[h86r@<1*с8G:aZo?k]BV 7/SunGRBA˂~\kmAlXFOv:[߾mλ-q}{%xr@w?`2DviJ0un !P7l6̝cm]rD'xŒVAFs"FKkd1sڎ `k{ѐ ː, q_JT69n{hGss(u%n4QsXb9tY&2 TDs:2w`44ŒXcu VVZ1h@'{lZݶO*$RP )QT.7⻳]3\ +6:xsQӮB&RX2'V5McʵV^Qrgvw!Pcg/UQK`q.5Ö8o/h)C'ө?P<69{T‚VFn#۸:HJaݶTna*թI^H|s^z!ĕ*.\.;ux(1!.7pu9kK\,W󯻅FI)۶%#,Cg7αVH4|v⼂L>^s`"sQ99 2,U7~s bgnAU ܚ˗\K.N."ӱ8fcƸ98ffݖ8z>r(,WKͷ9HeC_J>"S1,ny!ՈOQ}dS1LzW=ϥT[%ىDb{.\.9p(t# HC*a l N.V tcn&v`J{%y^]zcvq3.͏Oe#G9;93(7l Tij$S:px.׵] >[!q^o]e }c.\@P|Vдx f|R~WPj|fVY>-q@~5>–ZnB gQ.[| riKѨm no9_,NBIqqH>@@ SנW5Aߩ^]no+}w:g-gfڷmKTQ)=Ͳykpĉ8(~?0* pΟ?W*\ùnM°&jBE48t|Kanqs#n;#/o Vg_캜qp\T$=ީua DkJ9jzoWz0`e`a~k.^.•o&vlj'}d2qwvplS4x8>QYfDYJ˼9hmj婙G[:(ŰkovkkQ>i͋*Uk﨔n.vɓȍ}3MǏǡbVRo]5 |=%܅Xۙ;% tW\EW' G^Μ/Ru!b<Ͳ'Oɓ{ ؇' c XXXC=Mi~5Ac;%RÝ}˯CRfKđe<)^xĔ+"碥RT=R@og=xB]ב >eq1vI*(o`{Zcq>-ͷn;h݋1whn;wm%2F6K`c~ ]2]155]R:,ͯ}KJzW\5ph`~"@njb{˧O}wK3_Z_[#OO"mS)ba~~}K0z^)h ¥8&Rid…us3]gAD1pёʽ 籌ޯ]h tW\uwǮ 8߯/\Nv0li^%V+mL6),LL"Li~܈gfOT*\^YGaw]>uBes]*C̛o(.m_ow_cɞ@?`)/u9>JX)g1Jaab Tpt6#3g/E^~=ρrv ][f {^@?z?4XXŰ81+SJ8QCӨ@eXp :ٴQϤ2_) k}/`XFPwY3K`&&0m,b{ީ4?$3Vz}ͷMggCqw@Jz>S`tjvlzyѹ+V3=_}}C6!â@']^{s_L3R k VDrSMM^C7tXݛRⱧ|ߑGBbX 6px>f'҈o그; B(V@mw1ӠJ{$ҿwɧz TS3Kxb\$Q8g - mzJ^inl6毓d:ԙ (׺O:Gbj~ puv@zsi/`OVs{~ϝ2$ tI4ƿ 2Ksaji-_. ?Gp>9nj-X i{. 8cJg€\.8Qi3;BeGaI*,SwN+mK;^Ђ8rPfG>~ >1lG@ \gBe==lAx N9] H%?S€8 KGþgUqAI]!D$-fXi VZCh8zKR@ %/]uX* x KX-py$_mLbJ/!%>܆[biRjv]őoSLqð8Zuek;v5r=Qһߏβ𢪬Ѩ8R)4np3<4!5kr(0܋|; "W8<,ч[=u%[Y"t&{?49G&4}gZ,w]['8)mJ)40 `oYZ %Bp~'ڛqoxC]'!;AN[G:'ѨHfW-;5+$sa߅X9zwѻ] 7V+)!dw}K z 7H>kλOđY]HQi~,x[E󘘆&W UbR*\9@ =& Wy<{އNBvhF IDAT { elLGq Q,j]BrBf 6,ԜԜȎѻ5R̀bsmsgpvy _{4ޏඛ&8 l|!/=cxۛ~pGȨ(~G߁7SxyYLQiv= ihz#`"RuL4xF/^ifs823{o;ێM`~ff n kZwhz!DnjTn':au9jA<[·%G,5Z+ ٮX/c 5G:ܻo7ދ@3v=pNl2 ylޱs $7ƯH\R73׮tb5q̮M2ugjWajUbv@)aF?jUzw9f2'nqm!{x![~Q@x&3nJ~-H!05vBt2 ơk C887Y0D8Q^A9fhhUp k:9ܲ07ۏ;M=+u<}2^bN`< 4q,ceF>uT1Ҹ'^AՊe)B]G`t7$tXpSFZ1wC|E> t4M#!_${P/I.60{J+6 oPxdb0b|i5\VWo`ԑlܻ] >&v5V™'Oa"Ʊiw!|&F;|\]+ty1;X;Yx9c2*=HQBy=ې}7k#e{߶Kѫ:}wqBtIvu_ \zq&'5ܚn#b9yҖn%ca1j3SƑI2Ppbk>emkMS&ҩ&p xUGpHN/BBT ,.Q6P`aĩ!O>g3pO'j_)|}̩]y+&c鞫ۥPr󅧱*Xf}_ !B߉< g.DOD-0)/ee$H/N'be6ܑcbIӓY((Tv))$쪋FE paؐԬ[>n(U(TP5Gۈi&2V"rU@6D/mϲwĻdO5׾Z0>C:x7Ga440Ơd>|^  rXwb;pηM6m|®ͅy nh>1}Њq̂[c>q(F`H[ sU;,6OOΰOsz ^(ɞ ۿ}3m515ҩu8/ ~~:2)L``n2k?ULB‡d>$z. @uClaP]JetLdF;YcߔӇ kpZ×)gh:LMGL7^X]i|^m}g? _ !;GN >SmO[H@\/=Ģ.:tK 4jyL*'Q@m(c`g\\roY5q>w5`߬J +: :ӆrV={pWA_zu-`Fg}\W?G>ALp'1uUm!5vso"f2_ G+wV$;r9XNGz\?N%5=!,_o 揅s ]:>>Vl錉*[u^4= wh wLqk,~s^ \WknmC3̸ԱU_5n}wVm|>|xO!;AN^6/?}[[mHqLLƐɘX?WFZ AK@ )!:=4h!o6{ӸfXIa~7 U %µ5}v^zMofC"{[(˪aO~H1,G,cf& ,?_W( R&R9ya3λVʏJI/UI%! J)0Ys9c5CXo\@z|O!@'F[ b&9`0LNƐɚpVN5F0܇]N9i =fp>gUuv8~?c\*Dlk/x+zY^,;#!Ϟ?BFENP1!c LK]vrNlZ> ǃ;o,< <3ڶ_%'LmGvv;pM3 ) tGg_̉ HTĄM稭X;S a ֻNqΐ[%¹.KH #{ 9rA; I)UZ0o99&sgP}'痱_*qH1lDv"m.TA۪롵Mc:\*h`JCXȗPL4٦0=o9 +yBZ ~ċv%|7|[ \i,<g1]@beLMߺd#'D^@'Z^o#EU&•J G Ox R}0yuS; ܞលteF#°BെKN@1hW6}ӊX'@8RNdvj#fw;'s죿q]/\_zam˷@,6n5i/T5Q^<ޕRsLBWM_8¿  Q%x kws iߕJAZ\)`|;oy- BLe=?m<#Cvt?( R7/ɭ}㉄LB<p/QREei?pEwx AZ A[k&}s p;c p[e * j)6m}^n=p]őm4m+pBI S⡐wF)yٶ5Q{| #B^._"_E S"6s092Y m\.UV#[w^ SO,^ڣHdϢF,dc57kr 9>|_b}͆c(7ZN͏cjbz&d@'7]?b$LsflSiVKکx(]Qr!}ՉnF)STl2k3Arb/j`qGS (] [ViWv2ѫ( myu GV]e jY=zh`Ie-K we{Y T4x᜻*wo w ۲4G_5އPk%rH ;~O+/u]%̈ V+>%'_>Ke}ŃFN~ݏ|90e}D@"CoB䢲܀Svy{ `%`{8=^t~ƀS%`ݮ !!#_d>H>U&s]kTVP8n701݄9Ff~g[Ul Ia-ksQ3.u9V &b[/P]Tʃv=ϋ=|~-$/q<>GkeAƺWsOH$ z[i|;@uFuFÅ} 1 [,wif~+yҳߛLLvgG+܃9+ h}j>{·ιr]7[8rᮔ:9x~_}}J ]}ij4XqֵMIz  d !tai[1꾃g \YФ\4 %3%ϡ& mhy9?.*EN3Nq|*!٢c{m XLG,!7W;R:ܒp6r 559ÑfjwOHϗpeF'*Tvnf_UQiۿgp@jckA]+M oy>* Wm ca9 И6gA75{=im #~P} } Qա#\Z]AH77WI|!:9N=m;gQoP*ֻ40M J* 6*K 5RȰkXai$&^0 UώX-e[wNg柡ӛV^!O_nBn`4/~ 4xe2H+\9]34M&un̓SA858#i3 uꐧ= oo nKh sDw~7/ Qau}?(om;WFu\6 )\Gn.\χPW Ӯ(h5Lͱд=:!O?-<̹Cn>7?1:n7Lx|nB$|w|$|Y5Q0y],e.M?}hR'FDNȐ_Wx _֫-h:<[38g<|A֩JE|[*Bȡ*ry_y/{ۛ~o|JޱqBNH)O'W2N}~ 7%u(p7zنy~?@a@N.*x'}+TnSZ}77C_9bV}ބW?@%uB@'dH)SS_dzƳO!_\mw `Q/aa<ѱ hem9 OӧgаGk{Lfp` Ivկ>$䀠@'e$ąKSxŧ܋峰mVD mϱ5%6V\7k^>cu(!^Q(8,]: ΢RPtr8n>z+n9zzzūa5!lHtVֱ^Xza훮rܯ$譸q~S/!@@'B~ZK!QB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!sRIDAT2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBB@'B:!2( !1@N! tB!d PB!cBBT+}{IENDB`sympy-sympy-1.9/doc/src/_templates/000077500000000000000000000000001412543434000174145ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/_templates/layout.html000066400000000000000000000002541412543434000216200ustar00rootroot00000000000000{% extends '!layout.html' %} {%- block linktags %} {{ super() }} {%- endblock %} sympy-sympy-1.9/doc/src/aboutus.rst000066400000000000000000000067651412543434000175110ustar00rootroot00000000000000About ===== SymPy Development Team ---------------------- .. literalinclude:: ../../AUTHORS You can find a brief history of SymPy in the `README `_. Financial and Infrastructure Support ------------------------------------ * `Google `_: SymPy has received generous financial support from Google in various years through the `Google Summer of Code `_ program by providing stipends: * in 2007 for 5 students (`GSoC 2007 `_) * in 2008 for 1 student (`GSoC 2008 `_) * in 2009 for 5 students (`GSoC 2009 `_) * in 2010 for 5 students (`GSoC 2010 `_) * in 2011 for 9 students (`GSoC 2011 `_) * in 2012 for 6 students (`GSoC 2012 `_) * in 2013 for 7 students (`GSoC 2013 `_) * in 2014 for 10 students (`GSoC 2014 `_) * in 2015 for 7 students (`GSoC 2015 `_) * in 2016 for 9 students (`GSoC 2016 `_) * in 2017 for 9 students (`GSoC 2017 `_) * in 2018 for 7 students (`GSoC 2018 `_) * in 2019 for 9 students (`GSoC 2019 `_) * in 2020 for 6 students (`GSoC 2020 `_) Of these, we would like to thank these organizations for hosting GSoC students under their umbrella organizations: * `Python Software Foundation (PSF) `_ has hosted various GSoC students over the years: * 3 GSoC 2007 students (Brian, Robert and Jason) * 1 GSoC 2008 student (Fredrik) * 2 GSoC 2009 students (Freddie and Priit) * 4 GSoC 2010 students (Aaron, Christian, Matthew and Øyvind) * 6 GSoC 2015 students * 1 GSoC 2016 student (James) * `Portland State University (PSU) `_ has hosted following GSoC students: * 1 student (Chris) in 2007 * 3 students (Aaron, Dale and Fabian) in 2009 * 1 student (Addison) in 2010 * `The Space Telescope Science Institute `_: STScI hosted 1 GSoC 2007 student (Mateusz) * `The Ruby Science Foundation `_ has hosted following GSoC students: * 1 student (Abinash) in 2015 * 1 student (Rajith) in 2016 * Several 13-17 year old pre-university students contributed as part of Google's `Code-In `_ 2011. (`GCI 2011 `_) * `Simula Research Laboratory `_: supports Pearu Peterson work in SymPy/SymPy Core projects * `GitHub `_ is providing us with development and collaboration tools License ------- Unless stated otherwise, all files in the SymPy project, SymPy's webpage (and wiki), all images and all documentation including this User's Guide are licensed using the new BSD license: .. literalinclude:: ../../LICENSE sympy-sympy-1.9/doc/src/citing.rst000066400000000000000000000050321412543434000172660ustar00rootroot00000000000000Citing SymPy ============ To cite SymPy in publications use Meurer A, Smith CP, Paprocki M, Čertík O, Kirpichev SB, Rocklin M, Kumar A, Ivanov S, Moore JK, Singh S, Rathnayake T, Vig S, Granger BE, Muller RP, Bonazzi F, Gupta H, Vats S, Johansson F, Pedregosa F, Curry MJ, Terrel AR, Roučka Š, Saboo A, Fernando I, Kulal S, Cimrman R, Scopatz A. (2017) SymPy: symbolic computing in Python. *PeerJ Computer Science* 3:e103 https://doi.org/10.7717/peerj-cs.103 A BibTeX entry for LaTeX users is .. code-block:: none @article{10.7717/peerj-cs.103, title = {SymPy: symbolic computing in Python}, author = {Meurer, Aaron and Smith, Christopher P. and Paprocki, Mateusz and \v{C}ert\'{i}k, Ond\v{r}ej and Kirpichev, Sergey B. and Rocklin, Matthew and Kumar, AMiT and Ivanov, Sergiu and Moore, Jason K. and Singh, Sartaj and Rathnayake, Thilina and Vig, Sean and Granger, Brian E. and Muller, Richard P. and Bonazzi, Francesco and Gupta, Harsh and Vats, Shivam and Johansson, Fredrik and Pedregosa, Fabian and Curry, Matthew J. and Terrel, Andy R. and Rou\v{c}ka, \v{S}t\v{e}p\'{a}n and Saboo, Ashutosh and Fernando, Isuru and Kulal, Sumith and Cimrman, Robert and Scopatz, Anthony}, year = 2017, month = jan, keywords = {Python, Computer algebra system, Symbolics}, abstract = { SymPy is an open source computer algebra system written in pure Python. It is built with a focus on extensibility and ease of use, through both interactive and programmatic applications. These characteristics have led SymPy to become a popular symbolic library for the scientific Python ecosystem. This paper presents the architecture of SymPy, a description of its features, and a discussion of select submodules. The supplementary material provide additional examples and further outline details of the architecture and features of SymPy. }, volume = 3, pages = {e103}, journal = {PeerJ Computer Science}, issn = {2376-5992}, url = {https://doi.org/10.7717/peerj-cs.103}, doi = {10.7717/peerj-cs.103} } SymPy is BSD licensed, so you are free to use it whatever you like, be it academic, commercial, creating forks or derivatives, as long as you copy the BSD statement if you redistribute it (see the LICENSE file for details). That said, although not required by the SymPy license, if it is convenient for you, please cite SymPy when using it in your work and also consider contributing all your changes back, so that we can incorporate it and all of us will benefit in the end. sympy-sympy-1.9/doc/src/conf.py000066400000000000000000000224211412543434000165570ustar00rootroot00000000000000# # SymPy documentation build configuration file, created by # sphinx-quickstart.py on Sat Mar 22 19:34:32 2008. # # This file is execfile()d with the current directory set to its containing dir. # # The contents of this file are pickled, so don't put values in the namespace # that aren't pickleable (module imports are okay, they're removed automatically). # # All configuration values have a default value; values that are commented out # serve to show the default value. import sys import inspect import os import subprocess from datetime import datetime import sympy # If your extensions are in another directory, add it here. sys.path = ['ext'] + sys.path # General configuration # --------------------- # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.addons.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.linkcode', 'sphinx_math_dollar', 'sphinx.ext.mathjax', 'numpydoc', 'sympylive', 'sphinx.ext.graphviz', 'matplotlib.sphinxext.plot_directive'] # Use this to use pngmath instead #extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.pngmath', ] # Enable warnings for all bad cross references. These are turned into errors # with the -W flag in the Makefile. nitpicky = True nitpick_ignore = [ ('py:class', 'sympy.logic.boolalg.Boolean') ] # To stop docstrings inheritance. autodoc_inherit_docstrings = False # MathJax file, which is free to use. See https://www.mathjax.org/#gettingstarted # As explained in the link using latest.js will get the latest version even # though it says 2.7.5. mathjax_path = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS_HTML-full' # See https://www.sympy.org/sphinx-math-dollar/ mathjax_config = { 'tex2jax': { 'inlineMath': [ ["\\(","\\)"] ], 'displayMath': [["\\[","\\]"] ], }, } # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The master toctree document. master_doc = 'index' suppress_warnings = ['ref.citation', 'ref.footnote'] # General substitutions. project = 'SymPy' copyright = '{} SymPy Development Team'.format(datetime.utcnow().year) # The default replacements for |version| and |release|, also used in various # other places throughout the built documents. # # The short X.Y version. version = sympy.__version__ # The full version, including alpha/beta/rc tags. release = version # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. today_fmt = '%B %d, %Y' # List of documents that shouldn't be included in the build. #unused_docs = [] # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # Don't show the source code hyperlinks when using matplotlib plot directive. plot_html_show_source_link = False # Options for HTML output # ----------------------- # The style sheet to use for HTML and HTML Help pages. A file of that name # must exist either in Sphinx' static/ path, or in one of the custom paths # given in html_static_path. html_style = 'default.css' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%b %d, %Y' html_theme = 'classic' html_logo = '_static/sympylogo.png' html_favicon = '../_build/logo/sympy-notailtext-favicon.ico' # See http://www.sphinx-doc.org/en/master/theming.html#builtin-themes # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Content template for the index page. #html_index = '' # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. #html_use_modindex = True html_domain_indices = ['py-modindex'] # If true, the reST sources are included in the HTML build as _sources/. #html_copy_source = True # Output file base name for HTML help builder. htmlhelp_basename = 'SymPydoc' # Options for LaTeX output # ------------------------ # The paper size ('letter' or 'a4'). #latex_paper_size = 'letter' # The font size ('10pt', '11pt' or '12pt'). #latex_font_size = '10pt' # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, document class [howto/manual], toctree_only). # toctree_only is set to True so that the start file document itself is not included in the # output, only the documents referenced by it via TOC trees. The extra stuff in the master # document is intended to show up in the HTML, but doesn't really belong in the LaTeX output. latex_documents = [('index', 'sympy-%s.tex' % release, 'SymPy Documentation', 'SymPy Development Team', 'manual', True)] # Additional stuff for the LaTeX preamble. # Tweaked to work with XeTeX. latex_elements = { 'babel': '', 'fontenc': r''' % Define version of \LaTeX that is usable in math mode \let\OldLaTeX\LaTeX \renewcommand{\LaTeX}{\text{\OldLaTeX}} \usepackage{bm} \usepackage{amssymb} \usepackage{fontspec} \usepackage[english]{babel} \defaultfontfeatures{Mapping=tex-text} \setmainfont{DejaVu Serif} \setsansfont{DejaVu Sans} \setmonofont{DejaVu Sans Mono} ''', 'fontpkg': '', 'inputenc': '', 'utf8extra': '', 'preamble': r''' ''' } # SymPy logo on title page html_logo = '_static/sympylogo.png' latex_logo = '_static/sympylogo_big.png' # Documents to append as an appendix to all manuals. #latex_appendices = [] # Show page numbers next to internal references latex_show_pagerefs = True # We use False otherwise the module index gets generated twice. latex_use_modindex = False default_role = 'math' pngmath_divpng_args = ['-gamma 1.5', '-D 110'] # Note, this is ignored by the mathjax extension # Any \newcommand should be defined in the file pngmath_latex_preamble = '\\usepackage{amsmath}\n' \ '\\usepackage{bm}\n' \ '\\usepackage{amsfonts}\n' \ '\\usepackage{amssymb}\n' \ '\\setlength{\\parindent}{0pt}\n' texinfo_documents = [ (master_doc, 'sympy', 'SymPy Documentation', 'SymPy Development Team', 'SymPy', 'Computer algebra system (CAS) in Python', 'Programming', 1), ] # Use svg for graphviz graphviz_output_format = 'svg' # Requried for linkcode extension. # Get commit hash from the external file. commit_hash_filepath = '../commit_hash.txt' commit_hash = None if os.path.isfile(commit_hash_filepath): with open(commit_hash_filepath) as f: commit_hash = f.readline() # Get commit hash from the external file. if not commit_hash: try: commit_hash = subprocess.check_output(['git', 'rev-parse', 'HEAD']) commit_hash = commit_hash.decode('ascii') commit_hash = commit_hash.rstrip() except: import warnings warnings.warn( "Failed to get the git commit hash as the command " \ "'git rev-parse HEAD' is not working. The commit hash will be " \ "assumed as the SymPy master, but the lines may be misleading " \ "or nonexistent as it is not the correct branch the doc is " \ "built with. Check your installation of 'git' if you want to " \ "resolve this warning.") commit_hash = 'master' fork = 'sympy' blobpath = \ "https://github.com/{}/sympy/blob/{}/sympy/".format(fork, commit_hash) def linkcode_resolve(domain, info): """Determine the URL corresponding to Python object.""" if domain != 'py': return modname = info['module'] fullname = info['fullname'] submod = sys.modules.get(modname) if submod is None: return obj = submod for part in fullname.split('.'): try: obj = getattr(obj, part) except Exception: return # strip decorators, which would resolve to the source of the decorator # possibly an upstream bug in getsourcefile, bpo-1764286 try: unwrap = inspect.unwrap except AttributeError: pass else: obj = unwrap(obj) try: fn = inspect.getsourcefile(obj) except Exception: fn = None if not fn: return try: source, lineno = inspect.getsourcelines(obj) except Exception: lineno = None if lineno: linespec = "#L%d-L%d" % (lineno, lineno + len(source) - 1) else: linespec = "" fn = os.path.relpath(fn, start=os.path.dirname(sympy.__file__)) return blobpath + fn + linespec sympy-sympy-1.9/doc/src/documentation-style-guide.rst000066400000000000000000001430431412543434000231200ustar00rootroot00000000000000=============================== SymPy Documentation Style Guide =============================== **A Writing Resource for Documentation and Docstrings** General Guidelines ================== Documentation is one of the most highly valued aspects of an open source project. Documentation teaches users and contributors how to use a project, how to contribute, and the standards of conduct within an open source community. But according to GitHub’s `Open Source Survey `_, incomplete or confusing documentation is the most commonly encountered problem in open source. This style guide aims to change that. The purpose of this style guide is to provide the SymPy community with a set of style and formatting guidelines that can be utilized and followed when writing SymPy documentation. Adhering to the guidelines offered in this style guide will bring greater consistency and clarity to SymPy’s documentation, supporting its mission to become a full-featured, open source computer algebra system (CAS). The SymPy documentation found at `docs.sympy.org `_ is generated from docstrings in the source code and dedicated narrative documentation files in the `doc/src directory `_. Both are written in `reStructuredText `_ format extended by `Sphinx `_. The documentation contained in the `doc/src directory `_ and the docstrings embedded in the Python source code are processed by Sphinx and various Sphinx extensions. This means that the documentation source format is specified by the documentation processing tools. The SymPy Documentation Style Guide provides both the essential elements for writing SymPy documentation as well as any deviations in style we specify relative to these documentation processing tools. The following lists the processing tools: * reStructuredText: Narrative documentation files and documentation strings embedded in Python code follow the reStructuredText format. Advanced features not described in this document can be found at http://docutils.sourceforge.net/rst.html. * Sphinx: Sphinx includes additional default features for the reStructuredText specification that are described at: http://www.sphinx-doc.org/. * Sphinx extensions included with Sphinx that we enable: * ``sphinx.ext.autodoc``: Processes Python source code files for the associated documentation strings to automatically generate pages containing the Application Programming Interface (API). See section on calling autodoc directives in this document to get started. More information is at: https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html. * ``sphinx.ext.graphviz``: Provides a directive for adding Graphviz graphics. See https://www.sphinx-doc.org/en/master/usage/extensions/graphviz.html for more info. * ``sphinx.ext.mathjax``: Causes math written in LaTeX to display using MathJax in the HTML version of the documentation. More information is at: https://www.sphinx-doc.org/en/master/usage/extensions/math.html#module-sphinx.ext.mathjax. *No bearing on documentation source format.* * ``sphinx.ext.linkcode``: Causes links to source code to direct to the related files on Github. More information is at: https://www.sphinx-doc.org/en/master/usage/extensions/linkcode.html. *No bearing on documentation source format.* * Sphinx extensions that are not included with Sphinx that we enable: * ``numpydoc``: Processes docstrings written in the "numpydoc" format, see https://numpydoc.readthedocs.io. We recommend the subset of numpydoc formatting features in this document. (Note that we currently use an older modified fork of numpydoc, which is included in the SymPy source code.) * ``sphinx_math_dollar``: Allows math to be delimited with dollar signs instead of reStructuredText directives (e.g., ``$a^2$`` instead of ``:math:`a^2```). See https://www.sympy.org/sphinx-math-dollar/ for more info. * ``matplotlib.sphinxext.plot_directive``: Provides directives for included matplotlib generated figures in reStructuredText. See https://matplotlib.org/devel/plot_directive.html for more info. * ``sympylive``: Adds a button on each example in the HTML documentation that opens the example in SymPy Live. *No bearing on documentation source format.* Everything supported by the above processing tools is available for use in the SymPy documentation, but this style guide supersedes any recommendations made in the above documents. Note that we do not follow PEP 257 or the www.python.org documentation recommendations. If you are contributing to SymPy for the first time, please read our `Introduction to Contributing `_ page as well as this guide. Types of Documentation ====================== There are four main locations where SymPy’s documentation can be found: **SymPy Website** https://sympy.org The SymPy website’s primary function is to advertise the software to users and developers. It also serves as an initial location to point viewers to other relevant resources on the web. The SymPy website has basic information on SymPy and how to obtain it, as well as examples to advertise it to users, but it does not have technical documentation. The source files are located in the SymPy `webpage directory `_. Appropriate items for the website are: * General descriptions of what SymPy and the SymPy community are * Explanations/demonstrations of major software features * Listings of other major software that uses SymPy * Getting started info for users (download and install instructions) * Getting started info for developers * Where users can get help and support on using SymPy * News about SymPy **SymPy Documentation** https://docs.sympy.org This is the main place where users go to learn how to use SymPy. It contains a tutorial for SymPy as well as technical documentation for all of the modules. The source files are hosted in the main SymPy repository in the `doc directory `_ at and are built using the `Sphinx site generator `_ and uploaded to the docs.sympy.org site automatically. The docs website also contains a built- in shell (SymPy Live) that allows users to interactively execute examples. There are two primary types of pages that are generated from different source files in the docs directory: * Narrative Pages: reStructuredText files that correspond to manually written documentation pages not present in the Python source code. Examples are the `tutorial RST files `_. In general, if your documentation is not API documentation it belongs in a narrative page. * API Documentation Pages: reStructuredText files that contain directives that generate the Application Programming Interface documentation. These are automatically generated from the SymPy Python source code. **SymPy Source Code** https://github.com/sympy/sympy Most functions and classes have documentation written inside it in the form of a docstring, which explains the function and includes examples called doctests. The purpose of these docstrings are to explain the API of that class or function. The doctests examples are tested as part of the test suite, so that we know that they always produce the output that they say that they do. Here is an `example docstring `_. Most docstrings are also automatically included in the Sphinx documentation above, so that they appear on the SymPy Documentation website. Here is that :obj:`same docstring <.im>` on the SymPy website. The docstrings are formatted in a specific way so that Sphinx can render them correctly for the docs website. The SymPy sources all contain sparse technical documentation in the form of source code comments, although this does not generally constitute anything substantial and is not displayed on the documentation website. **SymPy Wiki** https://github.com/sympy/sympy/wiki The SymPy Wiki can be edited by anyone without review. It contains various types of documentation, including: * High-level developer documentation (for example: https://github.com/sympy/sympy/wiki/Args-Invariant) * Guides for new contributors (for example: https://github.com/sympy/sympy/wiki/Introduction-to-contributing) * Development policies (for example: https://github.com/sympy/sympy/wiki/Python-version-support-policy) * Release notes (for example: https://github.com/sympy/sympy/wiki/Release-Notes-for-1.5) * Various pages that different contributors have added Getting Started =============== The first step to contributing to the code base is creating your development environment. Please find instructions on how to create your development environment in our `Development Workflow – Create Your Environment `_ guide. Once you have created your development environment, follow these steps: 1. Installation --------------- **Debian/Ubuntu** For Debian/Ubuntu, install the prerequisites:: apt-get install python3-sphinx texlive-latex-recommended dvipng librsvg2-bin imagemagick docbook2x graphviz python -m pip install sphinx-math-dollar And do:: make html If you get mpmath error, install python-mpmath package:: apt-get install python-mpmath If you get matplotlib error, install python-matplotlib package:: apt-get install python-matplotlib And to view it, do:: firefox _build/html/index.html **Fedora** For Fedora (and maybe other RPM-based distributions), install the prerequisites:: dnf install python3-sphinx librsvg2 ImageMagick docbook2X texlive-dvipng-bin texlive-scheme-medium librsvg2-tools python -m pip install sphinx-math-dollar After that, run:: make html If you get mpmath error, install python3-mpmath package:: dnf install python3-mpmath If you get matplotlib error, install python3-matplotlib package:: dnf install python3-matplotlib And view it at:: _build/html/index.html **Mac** For Mac, first install homebrew: https://brew.sh/ Then install these packages with homebrew:: brew install imagemagick graphviz docbook librsvg Install these packages with either pip or conda:: python -m pip install mpmath matplotlib sphinx sphinx-math-dollar Or:: conda install -c conda-forge mpmath matplotlib sphinx sphinx-math-dollar **Windows 10** Making your Sphinx build successful on the Windows system is tricky because some dependencies like ``dvipng`` or ``docbook2x`` are not available. For Windows 10, however, the Windows Subsystem for Linux can be a possible workaround solution, and you can install Ubuntu shell on your Windows system after following the tutorial below: https://github.com/MicrosoftDocs/WSL/blob/live/WSL/install-win10.md In your command prompt, run ``ubuntu`` to transfer to Linux terminal, and follow the Debian/Ubuntu tutorial above to install the dependencies, and then you can run ``make html`` to build. (Note that you also have to install ``make`` via ``apt-get install make``.) If you want to change the directory in your prompt to your working folder of SymPy in the Windows file system, you can prepend ``cd /mnt/`` to your file path in Windows, and run in your shell to navigate to the folder. (Also note that Linux uses ``/`` instead of ``\`` for file paths.) This method provides better compatibility than Cygwin or MSYS2 and more convenience than a virtual machine if you partially need a Linux environment for your workflow, however this method is only viable for Windows 10 64-bit users. 2. Build the Documentation -------------------------- The documentation can be built by running the ``makefile`` in the ``doc`` subdirectory. To start, in your preferred web browser, use the drop down menu and select “open file” to navigate into the sympy/doc folder saved on your computer. In the doc folder, select the _build folder, then the html folder, and in the html folder, open the index.html file. To build the HTML documentation, run:: cd doc make html This builds a local version of the documentation in ``doc/_build/html`` in your web browser. Open ``_build/html/index.html``. 3. Make a Contribution ---------------------- For in-depth instructions on how to contribute to SymPy’s code base including coding conventions, creating your environment, picking an issue to fix, and opening a pull request, please read our full `Development Workflow `_ guide. Narrative Documentation Guidelines ================================== Extensive documentation, or documentation that is not centered around an API reference, should be written as a narrative document in the Sphinx docs (located in the `doc/src directory `_). The narrative documents do not reside in the Python source files, but as standalone restructured files in the doc/src directory. SymPy’s narrative documentation is defined as the collective documents, tutorials, and guides that teach users how to use SymPy. Reference documentation should go in the docstrings and be pulled into the RST with autodoc. The RST itself should only have narrative style documentation that is not a reference for a single specific function. .. _style_guide_best_practices_for_writing_documentation: Best Practices for Writing Documentation ---------------------------------------- Please follow these formatting, style, and tone preferences when writing documentation. Formatting Preferences ^^^^^^^^^^^^^^^^^^^^^^ In order for math and code to render correctly on the SymPy website, please follow these formatting guidelines. .. _style_guide_math_formatting: Math ~~~~ Text that is surrounded by dollar signs $ _ $ will be rendered as LaTeX math. Any text that is meant to appear as LaTeX math should be written as ``$math$``. In the HTML version of the docs, MathJax will render the math. **Example** :: The Bessel $J$ function of order $\nu$ is defined to be the function satisfying Bessel’s differential equation. LaTeX Recommendations ~~~~~~~~~~~~~~~~~~~~~ * If a docstring has any LaTeX, be sure to make it "raw." See the :ref:`Docstring Formatting ` section for details. * If you are not sure how to render something, you can use the SymPy :func:`~.latex` function. But be sure to strip out the unimportant parts (the bullet points below). * Avoid unnecessary ``\left`` and ``\right`` (but be sure to use them when they are required). * Avoid unnecessary ``{}``. (For example, write ``x^2`` instead of ``x^{2}``.) * Use whitespace in a way that makes the equation easiest to read. * Always check the final rendering to make sure it looks the way you expect it to. **Examples** Correct:: \int \sin(x)\,dx Incorrect:: \int \sin{\left( x\right)}\, dx For more in-depth resources on how to write math in LaTeX, see: * https://math.meta.stackexchange.com/questions/5020/mathjax-basic-tutorial-and-quick-reference * https://en.wikibooks.org/wiki/LaTeX/Mathematics * https://www.overleaf.com/learn/latex/Mathematical_expressions Code ~~~~ Text that should be printed verbatim, such as code, should be surrounded by a set of double backticks ``like this``. **Example** :: To use this class, define the ``_rewrite()`` and ``_expand()`` methods. Sometimes a variable will be the same in both math and code, and can even appear in the same paragraph, making it difficult to know if it should be formatted as math or code. If the sentence in question is discussing mathematics, then LaTeX should be used, but if the sentence is discussing the SymPy implementation specifically, then code should be used. In general, the rule of thumb is to consider if the variable in question were something that rendered differently in code and in math. For example, the Greek letter α would be written as ``alpha`` in code and ``$\alpha$`` in LaTeX. The reason being that ``$\alpha$`` cannot be used in contexts referring to Python code because it is not valid Python, and conversely ``alpha`` would be incorrect in a math context because it does not render as the Greek letter (α). **Example** :: class loggamma(Function): r""" The ``loggamma`` function implements the logarithm of the gamma function (i.e, $\log\Gamma(x)$). """ Variables listed in the parameters after the function name should, in written text, be italicized using Sphinx emphasis with asterisks like ``*this*``. **Example** :: def stirling(n, k, d=None, kind=2, signed=False): """ ... The first kind of Stirling number counts the number of permutations of *n* distinct items that have *k* cycles; the second kind counts the ways in which *n* distinct items can be partitioned into *k* parts. If *d* is given, the "reduced Stirling number of the second kind" is returned: $S^{d}(n, k) = S(n - d + 1, k - d + 1)$ with $n \ge k \ge d$. This counts the ways to partition $n$ consecutive integers into $k$ groups with no pairwise difference less than $d$. """ Note that in the above example, the first instances of *n* and *k* are referring to the input parameters of the function ``stirling``. Because they are Python variables but also parameters listed by themselves, they are formatted as parameters in italics. The last instances of $n$ and $k$ are talking about mathematical expressions, so they are formatted as math. If a variable is code, but is also a parameter written by itself, the parameter formatting takes precedence and it should be rendered in italics. However, if a parameter appears in a larger code expression it should be within double backticks to be rendered as code. If a variable is only code and not a parameter as well, it should be in double backticks to be rendered as code. Please note that references to other functions in SymPy are handled differently from parameters or code. If something is referencing another function in SymPy, the cross-reference reStructuredText syntax should be used. See the section on :ref:`Cross-Referencing ` for more information. Headings ~~~~~~~~ Section headings in reStructuredText files are created by underlining (and optionally overlining) the section title with a punctuation character at least as long as the text. Normally, there are no heading levels assigned to certain characters as the structure is determined from the succession of headings. However, for SymPy's documentation, here is a suggested convention: ``===`` with overline: title (top level heading) ``===`` heading 1 ``---`` heading 2 ``^^^`` heading 3 ``~~~`` heading 4 ``"""`` heading 5 Style Preferences ^^^^^^^^^^^^^^^^^ Spelling and Punctuation ~~~~~~~~~~~~~~~~~~~~~~~~ All narrative writing in SymPy follows American spelling and punctuation standards. For example, “color” is preferred over “colour” and commas should be placed inside of quotation marks. **Examples** :: If the ``line_color`` aesthetic is a function of arity 1, then the coloring is a function of the x value of a point. The term "unrestricted necklace," or "bracelet," is used to imply an object that can be turned over or a sequence that can be reversed. If there is any ambiguity about the spelling of a word, such as in the case of a function named after a person, refer to the spelling of the actual SymPy function. For example, Chebyshev polynomials are named after Pafnuty Lvovich Tchebychev, whose name is sometimes transliterated from Russian to be spelled with a “T,” but in SymPy it should always be spelled “Chebyshev” to refer to the SymPy function. **Example** :: class chebyshevt(OrthogonalPolynomial): r""" Chebyshev polynomial of the first kind, $T_n(x)$ ... """ Capitalization ~~~~~~~~~~~~~~ Title case capitalization is preferred in all SymPy headings. **Example** :: What is Symbolic Computation? ----------------------------- Tone Preferences ^^^^^^^^^^^^^^^^ Across SymPy documentation, please write in: * The present tense (e.g., In the following section, we are going to learn...) * The first-person inclusive plural (e.g., We did this the long way, but now we can try it the short way...) * Use the generic pronoun “you” instead of “one.” Or use “the reader” or “the user.” (e.g., You can access this function by... The user can then access this function by...) * Use the gender-neutral pronoun “they” instead of “he” or “she.” (e.g., A good docstring tells the user exactly what they need to know.) Avoid extraneous or belittling words such as “obviously,” “easily,” “simply,” “just,” or “straightforward.” Avoid unwelcoming or judgement-based phrases like “That is wrong.” Instead use friendly and inclusive language like “A common mistake is...” Avoid extraneous phrases like, “we just have to do one more thing.” .. _style_guide_docstring_guidelines: Docstring Guidelines ==================== To contribute to SymPy’s docstrings, please read these guidelines in full. A documentation string (docstring) is a string literal that occurs as the first statement in a module, function, class, or method definition. Such a docstring becomes the ``__doc__`` special attribute of that object. **Example** Here is a basic docstring:: def fdiff(self, argindex=1): """ Returns the first derivative of a Heaviside Function. Examples ======== >>> from sympy import Heaviside, diff >>> from sympy.abc import x >>> Heaviside(x).fdiff() DiracDelta(x) >>> Heaviside(x**2 - 1).fdiff() DiracDelta(x**2 - 1) >>> diff(Heaviside(x)).fdiff() DiracDelta(x, 1) """ Every public function, class, method, and module should have a docstring that describes what it does. Documentation that is specific to a function or class in the module should be in the docstring of that function or class. The module level docstring should discuss the purpose and scope of the module, and give a high-level example of how to use the functions or classes in the module. A module docstring is the docstring at the very top of the file, for example, the docstring for `solvers.ode `_. A public function is one that is intended to be used by the end- user, or the public. Documentation is important for public functions because they will be seen and used by many people. A private function, on the other hand, is one that is only intended to be used in the code in SymPy itself. Although it is less important to document private functions, it also helps to have docstrings on private functions to help other SymPy developers understand how to use the function. It may not always be clear what is a public function and what is a private function. If a function begins with an underscore, it is private, and if a function is included in ``__init__.py`` it is public, but the converse is not always true, so sometimes you have to decide based on context. In general, if you are unsure, having documentation on a function is better than not having documentation, regardless if it is public or private. Docstrings should contain information aimed at users of the function. Comments specific to the code or other notes that would only distract users should go in comments in the code, not in docstrings. Every docstring should have examples that show how the function works. Examples are the most important part of a docstring. A single example showing input and output to a function can be more helpful than a paragraph of descriptive text. Remember that the primary consumers of docstrings are other human beings, not machines, so it is important to describe what the function does in plain English. Likewise, examples of how to use the function should be designed for human readers, not just for the doctest machinery. Keep in mind that while Sphinx is the primary way users consume docstrings, and therefore the first platform to keep in mind while writing docstrings (especially for public functions), it is not the only way users consume docstrings. You can also view docstrings using ``help()`` or ``?`` in IPython. When using ``help()``, for instance, it will show you all of the docstrings on private methods. Additionally, anyone reading the source code directly will see every docstring. All public functions, classes, and methods and their corresponding docstrings should be imported into the Sphinx docs, instructions on which can be found at the end of this guide. .. _style_guide_docstring_formatting: Docstring Formatting -------------------- Docstrings are are written in `reStructuredText `_ format extended by `Sphinx `_. Here is a concise guide to `Quick reStructuredText `_. More in-depth information about using reStructuredText can be found in the `Sphinx Documentation `_. In order for Sphinx to render docstrings nicely in the HTML documentation, some formatting guidelines should be followed when writing docstrings: * Always use """triple double quotes""" around docstrings. Use r"""raw triple double quotes""" if you use any backslashes in your docstrings. * Include a blank line before the docstring’s closing quotes. * Lines should not be longer than 80 characters. * Always write class-level docstrings under the class definition line, as that is better to read in the source code. * The various methods on the class can be mentioned in the docstring or examples if they are important, but details on them should go in the docstring for the method itself. * Be aware that :: creates code blocks, which are rarely used in the docstrings. Any code example with example Python should be put in a doctest. Always check that the final version as rendered by Sphinx looks correct in the HTML. * In order to make section underlining work nicely in docstrings, `numpydoc Sphinx extension `_ is used. * Always double check that you have formatted your docstring correctly: 1. Make sure that your docstring is imported into Sphinx. 2. Build the Sphinx docs (``cd doc; make html``). 3. Make sure that Sphinx doesn't output any errors. 4. Open the page in ``_build/html`` and make sure that it is formatted correctly. Docstring Sections ------------------ In SymPy’s docstrings, it is preferred that function, class, and method docstrings consist of the following sections in this order: 1. Single-Sentence Summary 2. Explanation 3. Examples 4. Parameters 5. See Also 6. References The Single-Sentence Summary and Examples sections are **required** for every docstring. Docstrings will not pass review if these sections are not included. Do not change the names of these supported sections, for example, the heading “Examples” as a plural should be used even if there is only one example. SymPy will continue to support all of the section headings listed in the `NumPy Docstring Guide `_. Headings should be underlined with the same length in equals signs. If a section is not required and that information for the function in question is unnecessary, do not use it. Unnecessary sections and cluttered docstrings can make a function harder to understand. Aim for the minimal amount of information required to understand the function. 1. Single-Sentence Summary -------------------------- This section is **required** for every docstring. A docstring will not pass review if it is not included. No heading is necessary for this section. This section consists of a one-line sentence ending in a period that describes the function, class, or method's effect. Deprecation warnings should go directly after the Single-Sentence Summary, so as to notify users right away. Deprecation warnings should be written as a note in the Sphinx directive:: .. note:: Deprecated in Sympy 0.7.1. 2. Explanation Section ---------------------- This section is encouraged. If you choose to include an Explanation section in your docstring, it should be labeled with the heading “Explanation” underlined with the same length in equals signs. :: Explanation =========== This section consists of a more elaborate description of what the function, class, or method does when the concise Single-Sentence Summary will not suffice. This section should be used to clarify functionality in several sentences or paragraphs. 3. Examples Section ------------------- This section is **required** for every docstring. A docstring will not pass review if it is not included. It should be labeled with the heading “Examples” (even if there is only one example) underlined with the same length in equals signs. :: Examples ======== This section consists of examples that show how the function works, called doctests. Doctests should be complicated enough that they fully demonstrate the API and functionality of the function, but simple enough that a user can understand them without too much thought. The perfect doctest tells the user exactly what they need to know about the function without reading any other part of the docstring. There should always be a blank line before the doctest. When multiple examples are provided, they should be separated by blank lines. Comments explaining the examples should have blank lines both above and below them. Do not think of doctests as tests. Think of them as examples that happen to be tested. They should demonstrate the API of the function to the user (i.e., what the input parameters look like, what the output looks like, and what it does). If you only want to test something, add a test to the relevant ``test_*.py file``. You can use the ``./bin/coverage_doctest.py`` script to test the doctest coverage of a file or module. Run the doctests with ``./bin/doctest``. You should only skip the testing of an example if it is impossible to test it. If necessary, testing of an example can be skipped by adding a special comment. **Example** .. code:: >>> import random >>> random.random() # doctest: +SKIP 0.6868680200532414 If an example is longer than 80 characters, it should be line wrapped. Examples should be line wrapped so that they are still valid Python code, using ``...`` continuation as in a Python prompt. For example, from the ODE module documentation: **Example** .. code:: >>> from sympy import Function, dsolve, cos, sin >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), ... f(x), hint='1st_exact') Eq(x*cos(f(x)) + f(x)**3/3, C1) Here ``dsolve(cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), f(x), hint='1st_exact')`` is too long, so we line break it after a comma so that it is readable, and put ``...`` on the continuation lines. If this is not done correctly, the doctests will fail. The output of a command can also be line wrapped. No ``...`` should be used in this case. The doctester automatically accepts output that is line wrapped. **Example** .. code:: >>> list(range(30)) [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] In a doctest, write imports like ``sympy import ...`` instead of ``import sympy`` or ``from sympy import *``. To define symbols, use ``from sympy.abc import x``, unless the name is not in ``sympy.abc`` (for instance, if it has assumptions), in which case use ``symbols`` like ``x, y = symbols('x y')``. In general, you should run ``./bin/doctest`` to make sure your examples run correctly, and fix them if they do not. 4. Parameters Section --------------------- This section is encouraged. If you choose to include a Parameters section in your docstring, it should be labeled with the heading “Parameters” underlined with the same length in equals signs. :: Parameters ========== If you have parameters listed in parentheses after a function, class, or method name, you must include a parameters section. This section consists of descriptions of the function arguments, keywords, and their respective types. Enclose variables in double backticks. The colon must be preceded by a space, or omitted if the type is absent. For the parameter types, be as precise as possible. If it is not necessary to specify a keyword argument, use ``optional``. Optional keyword parameters have default values, which are displayed as part of the function signature. They can also be detailed in the description. When a parameter can only assume one of a fixed set of values, those values can be listed in braces, with the default appearing first. When two or more input parameters have exactly the same type, shape, and description, they can be combined. If the Parameters section is not formatted correctly, the documentation build will render incorrectly. If you wish to include a Returns section, write it as its own section with its own heading. **Example** Here is an example of a correctly formatted Parameters section:: def opt_cse(exprs, order='canonical'): """ Find optimization opportunities in Adds, Muls, Pows and negative coefficient Muls. Parameters ========== exprs : list of sympy expressions The expressions to optimize. order : string, 'none' or 'canonical' The order by which Mul and Add arguments are processed. For large expressions where speed is a concern, use the setting order='none'. """ .. _style_guide_see_also: 5. See Also Section ------------------- This section is encouraged. If you choose to include a See Also section in your docstring, it should be labeled with the heading “See Also” underlined with the same length in equals signs. :: See Also ======== This section consists of a listing of related functions, classes, and methods. The related items can be described with a concise fragment (not a full sentence) if desired, but this is not required. If the description spans more than one line, subsequent lines must be indented. The See Also section should only be used to reference other SymPy objects. Anything that is a link should be embedded as a hyperlink in the text of the docstring instead; see the References section for details. Do not reference classes with ``class:Classname``, ``class:`Classname```, or ``:class:`Classname```, but rather only by their class name. **Examples** Here is a correctly formatted See Also section with concise descriptions:: class erf(Function): r""" The Gauss error function. See Also ======== erfc: Complementary error function. erfi: Imaginary error function. erf2: Two-argument error function. erfinv: Inverse error function. erfcinv: Inverse Complementary error function. erf2inv: Inverse two-argument error function. """ Here is a correctly formatted See Also section with just a list of names:: class besselj(BesselBase): r""" Bessel function of the first kind. See Also ======== bessely, besseli, besselk """ 6. References Section --------------------- This section is encouraged. If you choose to include a References section in your docstring, it should be labeled with the heading “References” underlined with the same length in equals signs. :: References ========== This section consists of a list of references cited anywhere in the previous sections. Any reference to other SymPy objects should go in the See Also section instead. The References section should include online resources, paper citations, and/or any other printed resource giving general information about the function. References are meant to augment the docstring, but should not be required to understand it. References are numbered, starting from one, in the order in which they are cited. For online resources, only link to freely accessible and stable online resources such as Wikipedia, Wolfram MathWorld, and the NIST Digital Library of Mathematical Functions (DLMF), which are unlikely to suffer from hyperlink rot. References for papers should include, in this order: reference citation, author name, title of work, journal or publication, year published, page number. If there is a DOI (Digital Object Identifier), include it in the citation and make sure it is a clickable hyperlink. **Examples** Here is a References section that cites a printed resource:: References ========== .. [1] [Kozen89] D. Kozen, S. Landau, Polynomial Decomposition Algorithms, Journal of Symbolic Computation 7 (1989), pp. 445-456 Here is a References section that cites printed and online resources:: References ========== .. [1] Abramowitz, Milton; Stegun, Irene A., "Chapter 9," Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables, eds. (1965) .. [2] Luke, Y. L., The Special Functions and Their Approximations, Volume 1, (1969) .. [3] https://en.wikipedia.org/wiki/Bessel_function .. [4] http://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/ Sample Docstring ================ Here is an example of a correctly formatted docstring:: class gamma(Function): r""" The gamma function .. math:: \Gamma(x) := \int^{\infty}_{0} t^{x-1} e^{-t} \mathrm{d}t. Explanation =========== The ``gamma`` function implements the function which passes through the values of the factorial function (i.e., $\Gamma(n) = (n - 1)!$), when n is an integer. More generally, $\Gamma(z)$ is defined in the whole complex plane except at the negative integers where there are simple poles. Examples ======== >>> from sympy import S, I, pi, oo, gamma >>> from sympy.abc import x Several special values are known: >>> gamma(1) 1 >>> gamma(4) 6 >>> gamma(S(3)/2) sqrt(pi)/2 The ``gamma`` function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(gamma(x)) gamma(conjugate(x)) Differentiation with respect to $x$ is supported: >>> from sympy import diff >>> diff(gamma(x), x) gamma(x)*polygamma(0, x) Series expansion is also supported: >>> from sympy import series >>> series(gamma(x), x, 0, 3) 1/x - EulerGamma + x*(EulerGamma**2/2 + pi**2/12) + x**2*(-EulerGamma*pi**2/12 + polygamma(2, 1)/6 - EulerGamma**3/6) + O(x**3) We can numerically evaluate the ``gamma`` function to arbitrary precision on the whole complex plane: >>> gamma(pi).evalf(40) 2.288037795340032417959588909060233922890 >>> gamma(1+I).evalf(20) 0.49801566811835604271 - 0.15494982830181068512*I See Also ======== lowergamma: Lower incomplete gamma function. uppergamma: Upper incomplete gamma function. polygamma: Polygamma function. loggamma: Log Gamma function. digamma: Digamma function. trigamma: Trigamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Gamma_function .. [2] http://dlmf.nist.gov/5 .. [3] http://mathworld.wolfram.com/GammaFunction.html .. [4] http://functions.wolfram.com/GammaBetaErf/Gamma/ """ Docstrings for Classes that are Mathematical Functions ====================================================== SymPy is unusual in that it also has classes that are mathematical functions. The docstrings for classes that are mathematical functions should include details specific to this kind of class, as noted below: * The Explanation section should include a mathematical definition of the function. This should use LaTeX math. Use $$ for :ref:`inline math ` and .. math:: for display math, which should be used for the main definition. The variable names in the formulas should match the names of the parameters, and the LaTeX formatting should match the LaTeX pretty printing used by SymPy. As relevant, the mathematical definitions should mention their domain of definition, especially if the domain is different from the complex numbers. * If there are multiple conventions in the literature for a function, make sure to clearly specify which convention SymPy uses. * The Explanation section may also include some important mathematical facts about the function. These can alternately be demonstrated in the Examples section. Mathematical discussions should not be too long, as users can check the references for more details. * The docstring does not need to discuss every implementation detail such as at which operations are defined on the function or at which points it evaluates in the "eval" method. Important or illuminating instances of these can be shown in the Examples section. * The docstring should go on the class level (right under the line that has "class"). The "eval" method should not have a docstring. * Private methods on the class, that is, any method that starts with an underscore, do not need to be documented. They can still be documented if you like, but note that these docstrings are not pulled into the Sphinx documentation, so they will only be seen by developers who are reading the code, so if there is anything very important that you want to mention here, it should go in the class-level docstring as well. Best Practices for Writing Docstrings ===================================== When writing docstrings, please follow all of the same formatting, style, and tone preferences as when writing narrative documentation. For guidelines, see :ref:`Best Practices for Writing Documentation `, Formatting, Style, and Tone. Importing Docstrings into the Sphinx Documentation ================================================== Here are excerpts from the ``doc/src/modules/geometry`` directory that imports the relevant docstrings from geometry module into documentation:: Utils ===== .. module:: sympy.geometry.util .. autofunction:: intersection .. autofunction:: convex_hull .. autofunction:: are_similar Points ====== .. module:: sympy.geometry.point .. autoclass:: Point :members: Lines ===== .. module:: sympy.geometry.line .. autoclass:: LinearEntity :members: .. autoclass:: Line :members: .. autoclass:: Ray :members: .. autoclass:: Segment :members: Curves ====== .. module:: sympy.geometry.curve .. autoclass:: Curve :members: Ellipses ======== .. module:: sympy.geometry.ellipse .. autoclass:: Ellipse :members: .. autoclass:: Circle :members: Polygons ======== .. module:: sympy.geometry.polygon .. autoclass:: Polygon :members: .. autoclass:: RegularPolygon :members: .. autoclass:: Triangle :members: First namespace is set to particular submodule (file) with ``.. module::`` directive, then docstrings are imported with ``.. autoclass::`` or ``.. autofunction::`` relative to that submodule (file). Other methods are either cumbersome to use (using full paths for all objects) or break something (importing relative to main module using ``.. module:: sympy.geometry`` breaks viewcode Sphinx extension). All files in ``doc/src/modules/`` should use this format. .. _style_guide_cross-referencing: Cross-Referencing ================= Any text that references another SymPy function should be formatted so that a cross-reference link to that function's documentation is created automatically. This is done using the RST cross-reference syntax. There are two different kinds of objects that have conventions here: 1. Objects that are included in ``from sympy import *``, for example, ``sympy.acos``. For these, use ``:obj:`~.acos()```. The ``~`` makes it so that the text in the rendered HTML only shows ``acos``. Without it, it would use the fully qualified name ``sympy.functions.elementary.trigonometric.acos``. However, for names that are part of the global ``sympy`` namespace, we do not want to encourage accessing them from their specific submodule, as this is an implementation detail that could change. The ``.`` makes it so that the function name is found automatically. Sometimes, Sphinx will give a warning that there are multiple names found. If that happens, replace the ``.`` with the full name. For example, ``:obj:`~sympy.solvers.solvers.solve()```. For functions, methods, and classes, it is a convention to add () after the name to indicate such. You may also use a more specific type indicator instead of ``obj`` (see https://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#cross-referencing-python-objects). However, ``obj`` will always work, and sometimes SymPy names are not the type you might expect them to be. For example, mathematical function objects such as ``sin`` are not actually a Python function, rather they are a Python class, therefore ``:func:`~.sin``` will not work. 2. Objects that are not included in ``from sympy import *``, for example, ``sympy.physics.vector.dynamicsymbols``. This can be public API objects from submodules that are not included in the main ``sympy/__init__.py``, such as the physics submodule, or private API objects that are not necessarily intended to be used by end-users (but should still be documented). In this case, you must show the fully qualified name, so do not use the ``~.`` syntax. For example, ``:obj:`sympy.physics.vector.dynamicsymbols()```. You may also write custom text that links to the documentation for something using the following syntax ``:obj:`custom text```. For example, ``:obj:`the sine function <.sin>``` produces the text "the sine function" that links to the documentation for ``sin``. Note that the ``~`` character should not be used here. Note that references in the :ref:`See Also ` section of the docstrings do not require the ``:obj:`` syntax. If the resulting cross reference is written incorrectly, Sphinx will error when building the docs with an error like: :: WARNING: py:obj reference target not found: expand Here are some troubleshooting tips to fix the errors: * Make sure you have used the correct syntax, as described above. * Make sure you spelled the function name correctly. * Check if the function you are trying to cross-reference is actually included in the Sphinx documentation. If it is not, Sphinx will not be able to create a reference for it. In that case, you should add it to the appropriate RST file as described in the :ref:`Docstring Guidelines `. * If the function or object is not included in ``from sympy import *``, you will need to use the fully qualified name, like ``sympy.submodule.submodule.function`` instead of just ``function``. * A fully qualified name must include the full submodule for a function all the way down to the file. For example, ``sympy.physics.vector.ReferenceFrame`` will not work (even though you can access it that way in code). It has to be ``sympy.physics.vector.frame.ReferenceFrame``. * If the thing you are referring to does not actually have somewhere to link to, do not use the ``:obj:`` syntax. Instead, mark it as code using double backticks. Examples of things that cannot be linked to are Python built in functions like ``int`` or ``NotImplementedError``, functions from other modules outside of SymPy like ``matplotlib.plot``, and variable or parameter names that are specific to the text at hand. In general, if the object cannot be accessed as ``sympy.something.something.object``, it cannot be cross- referenced and you should not use the ``:obj:`` syntax. * If you are using are using one of the `type specific `_ identifiers like ``:func:``, be sure that the type for it is correct. ``:func:`` only refers to Python functions. For classes, you need to use ``:class:``, and for methods on a class you need to use ``:method:``. In general, it is recommended to use ``:obj:``, as this will work for any type of object. * If you cannot get the cross-referencing syntax to work, go ahead and submit the pull request as is and ask the reviewers for help. You may also see errors like: :: WARNING: more than one target found for cross-reference 'subs()': sympy.core.basic.Basic.subs, sympy.matrices.common.MatrixCommon.subs, sympy.physics.vector.vector.Vector.subs, sympy.physics.vector.dyadic.Dyadic.subs for instance, from using ``:obj:`~.subs```. This means that the ``.`` is not sufficient to find the function, because there are multiple names in SymPy named ``subs``. In this case, you need to use the fully qualified name. You can still use ``~`` to make it shortened in the final text, like ``:obj:`~sympy.core.basic.Basic.subs```. The line numbers for warnings in Python files are relative to the top of the docstring, not the file itself. The line numbers are often not completely correct, so you will generally have to search the docstring for the part that the warning is referring to. This is due to a bug in Sphinx. sympy-sympy-1.9/doc/src/gotchas.rst000066400000000000000000000665001412543434000174500ustar00rootroot00000000000000.. _gotchas: ==================== Gotchas and Pitfalls ==================== .. role:: input(strong) Introduction ============ SymPy runs under the `Python Programming Language `_, so there are some things that may behave differently than they do in other, independent computer algebra systems like Maple or Mathematica. These are some of the gotchas and pitfalls that you may encounter when using SymPy. See also the `FAQ `_, the :ref:`Tutorial`, the remainder of the SymPy Docs, and the `official Python Tutorial `_. If you are already familiar with C or Java, you might also want to look at this `4 minute Python tutorial `_. Ignore ``#doctest: +SKIP`` in the examples. That has to do with internal testing of the examples. .. _equals-signs: Equals Signs (=) ================ Single Equals Sign ------------------ The equals sign (``=``) is the assignment operator, not equality. If you want to do :math:`x = y`, use ``Eq(x, y)`` for equality. Alternatively, all expressions are assumed to equal zero, so you can just subtract one side and use ``x - y``. The proper use of the equals sign is to assign expressions to variables. For example: >>> from sympy.abc import x, y >>> a = x - y >>> print(a) x - y Double Equals Signs ------------------- Double equals signs (``==``) are used to test equality. However, this tests expressions exactly, not symbolically. For example: >>> (x + 1)**2 == x**2 + 2*x + 1 False >>> (x + 1)**2 == (x + 1)**2 True If you want to test for symbolic equality, one way is to subtract one expression from the other and run it through functions like :func:`~.expand`, :func:`~.simplify`, and :func:`~.trigsimp` and see if the equation reduces to 0. >>> from sympy import simplify, cos, sin, expand >>> simplify((x + 1)**2 - (x**2 + 2*x + 1)) 0 >>> eq = sin(2*x) - 2*sin(x)*cos(x) >>> simplify(eq) 0 >>> expand(eq, trig=True) 0 .. note:: See also `Why does SymPy say that two equal expressions are unequal? `_ in the FAQ. Variables ========= Variables Assignment does not Create a Relation Between Expressions ------------------------------------------------------------------- When you use ``=`` to do assignment, remember that in Python, as in most programming languages, the variable does not change if you change the value you assigned to it. The equations you are typing use the values present at the time of creation to "fill in" values, just like regular Python definitions. They are not altered by changes made afterwards. Consider the following: >>> from sympy import Symbol >>> a = Symbol('a') # Symbol, `a`, stored as variable "a" >>> b = a + 1 # an expression involving `a` stored as variable "b" >>> print(b) a + 1 >>> a = 4 # "a" now points to literal integer 4, not Symbol('a') >>> print(a) 4 >>> print(b) # "b" is still pointing at the expression involving `a` a + 1 Changing quantity ``a`` does not change ``b``; you are not working with a set of simultaneous equations. It might be helpful to remember that the string that gets printed when you print a variable referring to a SymPy object is the string that was given to it when it was created; that string does not have to be the same as the variable that you assign it to. >>> from sympy import var >>> r, t, d = var('rate time short_life') >>> d = r*t >>> print(d) rate*time >>> r = 80 >>> t = 2 >>> print(d) # We haven't changed d, only r and t rate*time >>> d = r*t >>> print(d) # Now d is using the current values of r and t 160 If you need variables that have dependence on each other, you can define functions. Use the ``def`` operator. Indent the body of the function. See the Python docs for more information on defining functions. >>> c, d = var('c d') >>> print(c) c >>> print(d) d >>> def ctimesd(): ... """ ... This function returns whatever c is times whatever d is. ... """ ... return c*d ... >>> ctimesd() c*d >>> c = 2 >>> print(c) 2 >>> ctimesd() 2*d If you define a circular relationship, you will get a ``RuntimeError``. >>> def a(): ... return b() ... >>> def b(): ... return a() ... >>> a() #doctest: +SKIP Traceback (most recent call last): File "...", line ..., in ... compileflags, 1) in test.globs File "<...>", line 1, in a() File "<...>", line 2, in a return b() File "<...>", line 2, in b return a() File "<...>", line 2, in a return b() ... RuntimeError: maximum recursion depth exceeded .. note:: See also `Why doesn't changing one variable change another that depends on it? `_ in the FAQ. .. _symbols: Symbols ------- Symbols are variables, and like all other variables, they need to be assigned before you can use them. For example: >>> import sympy >>> z**2 # z is not defined yet #doctest: +SKIP Traceback (most recent call last): File "", line 1, in NameError: name 'z' is not defined >>> sympy.var('z') # This is the easiest way to define z as a standard symbol z >>> z**2 z**2 If you use :command:`isympy`, it runs the following commands for you, giving you some default Symbols and Functions. >>> from __future__ import division >>> from sympy import * >>> x, y, z, t = symbols('x y z t') >>> k, m, n = symbols('k m n', integer=True) >>> f, g, h = symbols('f g h', cls=Function) You can also import common symbol names from :mod:`sympy.abc`. >>> from sympy.abc import w >>> w w >>> import sympy >>> dir(sympy.abc) #doctest: +SKIP ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'Symbol', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '_greek', '_latin', 'a', 'alpha', 'b', 'beta', 'c', 'chi', 'd', 'delta', 'e', 'epsilon', 'eta', 'f', 'g', 'gamma', 'h', 'i', 'iota', 'j', 'k', 'kappa', 'l', 'm', 'mu', 'n', 'nu', 'o', 'omega', 'omicron', 'p', 'phi', 'pi', 'psi', 'q', 'r', 'rho', 's', 'sigma', 't', 'tau', 'theta', 'u', 'upsilon', 'v', 'w', 'x', 'xi', 'y', 'z', 'zeta'] If you want control over the assumptions of the variables, use :class:`~.Symbol` and :func:`~.symbols`. See :ref:`Keyword Arguments` below. Lastly, it is recommended that you not use :obj:`I `, :obj:`~.E`, :obj:`~.S`, :obj:`N `, ``C``, :obj:`O `, or :obj:`Q ` for variable or symbol names, as those are used for the imaginary unit (:math:`i`), the base of the natural logarithm (:math:`e`), the :func:`~.sympify` function (see :ref:`Symbolic Expressions` below), numeric evaluation (:func:`~.N` is equivalent to :ref:`evalf()` ), the `big O `_ order symbol (as in :math:`O(n\log{n})`), and the assumptions object that holds a list of supported ask keys (such as ``Q.real``), respectively. You can use the mnemonic ``OSINEQ`` to remember what Symbols are defined by default in SymPy. Or better yet, always use lowercase letters for Symbol names. Python will not prevent you from overriding default SymPy names or functions, so be careful. >>> cos(pi) # cos and pi are a built-in sympy names. -1 >>> pi = 3 # Notice that there is no warning for overriding pi. >>> cos(pi) cos(3) >>> def cos(x): # No warning for overriding built-in functions either. ... return 5*x ... >>> cos(pi) 15 >>> from sympy import cos # reimport to restore normal behavior To get a full list of all default names in SymPy do: >>> import sympy >>> dir(sympy) #doctest: +SKIP # A big list of all default sympy names and functions follows. # Ignore everything that starts and ends with __. If you have `IPython `_ installed and use :command:`isympy`, you can also press the TAB key to get a list of all built-in names and to autocomplete. Also, see `this page `_ for a trick for getting tab completion in the regular Python console. .. note:: See also `What is the best way to create symbols? `_ in the FAQ. .. _calling-functions: Functions --------- A function like ``f(x)`` can be created by defining the Function and the variable: >>> from sympy import Function >>> f = Function('f') >>> x = Symbol('x') >>> f(x) f(x) If you assign ``f(x)`` to a Python variable `f` you will lose your ability to copy and paste that function or to create a function with a different argument: ``Function('f')`` is callable, but ``Function('f')(x)`` is not: >>> f1 = Function('f1') >>> f2 = Function('f2')('x') >>> f1 f1 >>> f2 f2(x) >>> f1(1) f1(1) >>> f2(1) Traceback (most recent call last): ... TypeError: 'f2' object is not callable >>> f2.subs(x, 1) f2(1) .. _symbolic-expressions: Symbolic Expressions ==================== .. _python-vs-sympy-numbers: Python numbers vs. SymPy Numbers -------------------------------- SymPy uses its own classes for integers, rational numbers, and floating point numbers instead of the default Python ``int`` and ``float`` types because it allows for more control. But you have to be careful. If you type an expression that just has numbers in it, it will default to a Python expression. Use the :func:`~.sympify` function, or just :obj:`~.S`, to ensure that something is a SymPy expression. >>> 6.2 # Python float. Notice the floating point accuracy problems. 6.2000000000000002 >>> type(6.2) # in Python 2.x, in Py3k <... 'float'> >>> S(6.2) # SymPy Float has no such problems because of arbitrary precision. 6.20000000000000 >>> type(S(6.2)) If you include numbers in a SymPy expression, they will be sympified automatically, but there is one gotcha you should be aware of. If you do ``/`` inside of a SymPy expression, Python will evaluate the two numbers before SymPy has a chance to get to them. The solution is to :func:`~.sympify` one of the numbers, or use :obj:`~.Rational`. >>> x**(1/2) # evaluates to x**0 or x**0.5 x**0.5 >>> x**(S(1)/2) # sympyify one of the ints sqrt(x) >>> x**Rational(1, 2) # use the Rational class sqrt(x) With a power of ``1/2`` you can also use ``sqrt`` shorthand: >>> sqrt(x) == x**Rational(1, 2) True If the two integers are not directly separated by a division sign then you don't have to worry about this problem: >>> x**(2*x/3) x**(2*x/3) .. note:: A common mistake is copying an expression that is printed and reusing it. If the expression has a :obj:`~.Rational` (i.e., ``/``) in it, you will not get the same result, obtaining the Python result for the division rather than a SymPy Rational. >>> x = Symbol('x') >>> print(solve(7*x -22, x)) [22/7] >>> 22/7 # If we just copy and paste we get int 3 or a float 3.142857142857143 >>> # One solution is to just assign the expression to a variable >>> # if we need to use it again. >>> a = solve(7*x - 22, x)[0] >>> a 22/7 The other solution is to put quotes around the expression and run it through S() (i.e., sympify it): >>> S("22/7") 22/7 Also, if you do not use :command:`isympy`, you could use ``from __future__ import division`` to prevent the ``/`` sign from performing `integer division `_. >>> from __future__ import division >>> 1/2 # With division imported it evaluates to a python float 0.5 >>> 1//2 # You can still achieve integer division with // 0 But be careful: you will now receive floats where you might have desired a Rational: >>> x**(1/2) x**0.5 :obj:`~.Rational` only works for number/number and is only meant for rational numbers. If you want a fraction with symbols or expressions in it, just use ``/``. If you do number/expression or expression/number, then the number will automatically be converted into a SymPy Number. You only need to be careful with number/number. >>> Rational(2, x) Traceback (most recent call last): ... TypeError: invalid input: x >>> 2/x 2/x Evaluating Expressions with Floats and Rationals ------------------------------------------------ SymPy keeps track of the precision of ``Float`` objects. The default precision is 15 digits. When an expression involving a ``Float`` is evaluated, the result will be expressed to 15 digits of precision but those digits (depending on the numbers involved with the calculation) may not all be significant. The first issue to keep in mind is how the ``Float`` is created: it is created with a value and a precision. The precision indicates how precise of a value to use when that ``Float`` (or an expression it appears in) is evaluated. The values can be given as strings, integers, floats, or rationals. - strings and integers are interpreted as exact >>> Float(100) 100.000000000000 >>> Float('100', 5) 100.00 - to have the precision match the number of digits, the null string can be used for the precision >>> Float(100, '') 100. >>> Float('12.34') 12.3400000000000 >>> Float('12.34', '') 12.34 >>> s, r = [Float(j, 3) for j in ('0.25', Rational(1, 7))] >>> for f in [s, r]: ... print(f) 0.250 0.143 Next, notice that each of those values looks correct to 3 digits. But if we try to evaluate them to 20 digits, a difference will become apparent: The 0.25 (with precision of 3) represents a number that has a non-repeating binary decimal; 1/7 is repeating in binary and decimal -- it cannot be represented accurately too far past those first 3 digits (the correct decimal is a repeating 142857): >>> s.n(20) 0.25000000000000000000 >>> r.n(20) 0.14285278320312500000 It is important to realize that although a Float is being displayed in decimal at arbitrary precision, it is actually stored in binary. Once the Float is created, its binary information is set at the given precision. The accuracy of that value cannot be subsequently changed; so 1/7, at a precision of 3 digits, can be padded with binary zeros, but these will not make it a more accurate value of 1/7. If inexact, low-precision numbers are involved in a calculation with higher precision values, the evalf engine will increase the precision of the low precision values and inexact results will be obtained. This is feature of calculations with limited precision: >>> Float('0.1', 10) + Float('0.1', 3) 0.2000061035 Although the ``evalf`` engine tried to maintain 10 digits of precision (since that was the highest precision represented) the 3-digit precision used limits the accuracy to about 4 digits -- not all the digits you see are significant. evalf doesn't try to keep track of the number of significant digits. That very simple expression involving the addition of two numbers with different precisions will hopefully be instructive in helping you understand why more complicated expressions (like trig expressions that may not be simplified) will not evaluate to an exact zero even though, with the right simplification, they should be zero. Consider this unsimplified trig identity, multiplied by a big number: >>> big = 12345678901234567890 >>> big_trig_identity = big*cos(x)**2 + big*sin(x)**2 - big*1 >>> abs(big_trig_identity.subs(x, .1).n(2)) > 1000 True When the `\cos` and `\sin` terms were evaluated to 15 digits of precision and multiplied by the big number, they gave a large number that was only precise to 15 digits (approximately) and when the 20 digit big number was subtracted the result was not zero. There are three things that will help you obtain more precise numerical values for expressions: 1) Pass the desired substitutions with the call to evaluate. By doing the subs first, the ``Float`` values cannot be updated as necessary. By passing the desired substitutions with the call to evalf the ability to re-evaluate as necessary is gained and the results are impressively better: >>> big_trig_identity.n(2, {x: 0.1}) -0.e-91 2) Use Rationals, not Floats. During the evaluation process, the Rational can be computed to an arbitrary precision while the Float, once created -- at a default of 15 digits -- cannot. Compare the value of ``-1.4e+3`` above with the nearly zero value obtained when replacing x with a Rational representing 1/10 -- before the call to evaluate: >>> big_trig_identity.subs(x, S('1/10')).n(2) 0.e-91 3) Try to simplify the expression. In this case, SymPy will recognize the trig identity and simplify it to zero so you don't even have to evaluate it numerically: >>> big_trig_identity.simplify() 0 .. _Immutability-of-Expressions: Immutability of Expressions --------------------------- Expressions in SymPy are immutable, and cannot be modified by an in-place operation. This means that a function will always return an object, and the original expression will not be modified. The following example snippet demonstrates how this works:: def main(): var('x y a b') expr = 3*x + 4*y print('original =', expr) expr_modified = expr.subs({x: a, y: b}) print('modified =', expr_modified) if __name__ == "__main__": main() The output shows that the :obj:`~sympy.core.basic.Basic.subs()` function has replaced variable ``x`` with variable ``a``, and variable ``y`` with variable ``b``:: original = 3*x + 4*y modified = 3*a + 4*b The :obj:`~sympy.core.basic.Basic.subs()` function does not modify the original expression ``expr``. Rather, a modified copy of the expression is returned. This returned object is stored in the variable ``expr_modified``. Note that unlike C/C++ and other high-level languages, Python does not require you to declare a variable before it is used. Mathematical Operators ---------------------- SymPy uses the same default operators as Python. Most of these, like ``*/+-``, are standard. Aside from integer division discussed in :ref:`Python numbers vs. SymPy Numbers ` above, you should also be aware that implied multiplication is not allowed. You need to use ``*`` whenever you wish to multiply something. Also, to raise something to a power, use ``**``, not ``^`` as many computer algebra systems use. Parentheses ``()`` change operator precedence as you would normally expect. In :command:`isympy`, with the :command:`ipython` shell:: >>> 2x Traceback (most recent call last): ... SyntaxError: invalid syntax >>> 2*x 2*x >>> (x + 1)^2 # This is not power. Use ** instead. Traceback (most recent call last): ... TypeError: unsupported operand type(s) for ^: 'Add' and 'int' >>> (x + 1)**2 (x + 1)**2 >>> pprint(3 - x**(2*x)/(x + 1)) 2*x x - ----- + 3 x + 1 Inverse Trig Functions ---------------------- SymPy uses different names for some functions than most computer algebra systems. In particular, the inverse trig functions use the python names of :obj:`~.asin`, :obj:`~.acos` and so on instead of the usual ``arcsin`` and ``arccos``. Use the methods described in :ref:`Symbols ` above to see the names of all SymPy functions. Sqrt is not a Function ---------------------- There is no ``sqrt`` function in the same way that there is an exponential function (``exp``). ``sqrt(x)`` is used to represent ``Pow(x, S(1)/2)`` so if you want to know if an expression has any square roots in it, ``expr.has(sqrt)`` will not work. You must look for ``Pow`` with an exponent of one half (or negative one half if it is in a denominator, e.g. >>> (y + sqrt(x)).find(Wild('w')**S.Half) {sqrt(x)} >>> (y + 1/sqrt(x)).find(Wild('w')**-S.Half) {1/sqrt(x)} If you are interested in any power of the ``sqrt`` then the following pattern would be appropriate >>> sq = lambda s: s.is_Pow and s.exp.is_Rational and s.exp.q == 2 >>> (y + sqrt(x)**3).find(sq) {x**(3/2)} Special Symbols =============== The symbols ``[]``, ``{}``, ``=``, and ``()`` have special meanings in Python, and thus in SymPy. See the Python docs linked to above for additional information. .. _lists: Lists ----- Square brackets ``[]`` denote a list. A list is a container that holds any number of different objects. A list can contain anything, including items of different types. Lists are mutable, which means that you can change the elements of a list after it has been created. You access the items of a list also using square brackets, placing them after the list or list variable. Items are numbered using the space before the item. .. note:: List indexes begin at 0. Example: >>> a = [x, 1] # A simple list of two items >>> a [x, 1] >>> a[0] # This is the first item x >>> a[0] = 2 # You can change values of lists after they have been created >>> print(a) [2, 1] >>> print(solve(x**2 + 2*x - 1, x)) # Some functions return lists [-1 + sqrt(2), -sqrt(2) - 1] .. note:: See the Python docs for more information on lists and the square bracket notation for accessing elements of a list. Dictionaries ------------ Curly brackets ``{}`` denote a dictionary, or a dict for short. A dictionary is an unordered list of non-duplicate keys and values. The syntax is ``{key: value}``. You can access values of keys using square bracket notation. >>> d = {'a': 1, 'b': 2} # A dictionary. >>> d {'a': 1, 'b': 2} >>> d['a'] # How to access items in a dict 1 >>> roots((x - 1)**2*(x - 2), x) # Some functions return dicts {1: 2, 2: 1} >>> # Some SymPy functions return dictionaries. For example, >>> # roots returns a dictionary of root:multiplicity items. >>> roots((x - 5)**2*(x + 3), x) {-3: 1, 5: 2} >>> # This means that the root -3 occurs once and the root 5 occurs twice. .. note:: See the Python docs for more information on dictionaries. Tuples ------ Parentheses ``()``, aside from changing operator precedence and their use in function calls, (like ``cos(x)``), are also used for tuples. A ``tuple`` is identical to a :ref:`list `, except that it is not mutable. That means that you cannot change their values after they have been created. In general, you will not need tuples in SymPy, but sometimes it can be more convenient to type parentheses instead of square brackets. >>> t = (1, 2, x) # Tuples are like lists >>> t (1, 2, x) >>> t[0] 1 >>> t[0] = 4 # Except you cannot change them after they have been created Traceback (most recent call last): File "", line 1, in TypeError: 'tuple' object does not support item assignment Single element tuples, unlike lists, must have a comma in them: >>> (x,) (x,) Without the comma, a single expression without a comma is not a tuple: >>> (x) x integrate takes a sequence as the second argument if you want to integrate with limits (and a tuple or list will work): >>> integrate(x**2, (x, 0, 1)) 1/3 >>> integrate(x**2, [x, 0, 1]) 1/3 .. note:: See the Python docs for more information on tuples. .. _keyword-arguments: Keyword Arguments ----------------- Aside from the usage described :ref:`above `, equals signs (``=``) are also used to give named arguments to functions. Any function that has ``key=value`` in its parameters list (see below on how to find this out), then ``key`` is set to ``value`` by default. You can change the value of the key by supplying your own value using the equals sign in the function call. Also, functions that have ``**`` followed by a name in the parameters list (usually ``**kwargs`` or ``**assumptions``) allow you to add any number of ``key=value`` pairs that you want, and they will all be evaluated according to the function. ``sqrt(x**2)`` doesn't auto simplify to x because x is assumed to be complex by default, and, for example, ``sqrt((-1)**2) == sqrt(1) == 1 != -1``: >>> sqrt(x**2) sqrt(x**2) Giving assumptions to Symbols is an example of using the keyword argument: >>> x = Symbol('x', positive=True) The square root will now simplify since it knows that ``x >= 0``: >>> sqrt(x**2) x powsimp has a default argument of ``combine='all'``: >>> pprint(powsimp(x**n*x**m*y**n*y**m)) m + n (x*y) Setting combine to the default value is the same as not setting it. >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='all')) m + n (x*y) The non-default options are ``'exp'``, which combines exponents... >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='exp')) m + n m + n x *y ...and 'base', which combines bases. >>> pprint(powsimp(x**n*x**m*y**n*y**m, combine='base')) m n (x*y) *(x*y) .. note:: See the Python docs for more information on function parameters. Getting help from within SymPy ============================== help() ------ Although all docs are available at `docs.sympy.org `_ or on the `SymPy Wiki `_, you can also get info on functions from within the Python interpreter that runs SymPy. The easiest way to do this is to do ``help(function)``, or ``function?`` if you are using :command:`ipython`:: In [1]: help(powsimp) # help() works everywhere In [2]: # But in ipython, you can also use ?, which is better because it In [3]: # it gives you more information In [4]: powsimp? These will give you the function parameters and docstring for :func:`~.powsimp`. The output will look something like this: .. module:: sympy.simplify.simplify .. autofunction:: powsimp :noindex: source() -------- Another useful option is the :func:`~.source` function. This will print the source code of a function, including any docstring that it may have. You can also do ``function??`` in :command:`ipython`. For example, from SymPy 0.6.5: >>> source(simplify) # simplify() is actually only 2 lines of code. #doctest: +SKIP In file: ./sympy/simplify/simplify.py def simplify(expr): """Naively simplifies the given expression. ... Simplification is not a well defined term and the exact strategies this function tries can change in the future versions of SymPy. If your algorithm relies on "simplification" (whatever it is), try to determine what you need exactly - is it powsimp()? radsimp()? together()?, logcombine()?, or something else? And use this particular function directly, because those are well defined and thus your algorithm will be robust. ... """ expr = Poly.cancel(powsimp(expr)) return powsimp(together(expr.expand()), combine='exp', deep=True) sympy-sympy-1.9/doc/src/guides/000077500000000000000000000000001412543434000165375ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/guides/assumptions.rst000066400000000000000000001541131412543434000216630ustar00rootroot00000000000000.. _assumptions: ============= Assumptions ============= This page outlines the core assumptions system in SymPy. It explains what the core assumptions system is, how the assumptions system is used and what the different assumptions predicates mean. .. note:: This page describes the core assumptions system also often referred to as the "old assumptions" system. There is also a "new assumptions" system which is described elsewhere. Note that the system described here is actually the system that is widely used in SymPy. The "new assumptions" system is not really used anywhere in SymPy yet and the "old assumptions" system will not be removed. At the time of writing (SymPy 1.7) it is still recommended for users to use the old assumption system. Firstly we consider what happens when taking the square root of the square of a concrete integer such as $2$ or $-2$: >>> from sympy import sqrt >>> sqrt(2**2) 2 >>> sqrt((-2)**2) 2 >>> x = 2 >>> sqrt(x**2) 2 >>> sqrt(x**2) == x True >>> y = -2 >>> sqrt(y**2) == y False >>> sqrt(y**2) == -y True What these examples demonstrate is that for a positive number $x$ we have $\sqrt{x^2} = x$ whereas for a negative number we would instead have $\sqrt{x^2} = -x$. That may seem obvious but the situation can be more surprising when working with a symbol rather then an explicit number. For example >>> from sympy import Symbol, simplify >>> x = Symbol('x') >>> sqrt(x**2) sqrt(x**2) It might look as if that should simplify to ``x`` but it does not even if :func:`~.simplify` is used: >>> simplify(sqrt(x**2)) sqrt(x**2) This is because SymPy will refuse to simplify this expression if the simplification is not valid for *every* possible value of ``x``. By default the symbol ``x`` is considered only to represent something roughly like an arbitrary complex number and the obvious simplification here is only valid for positive real numbers. Since ``x`` is not known to be positive or even real no simplification of this expression is possible. We can tell SymPy that a symbol represents a positive real number when creating the symbol and then the simplification will happen automatically: >>> y = Symbol('y', positive=True) >>> sqrt(y**2) y This is what is meant by "assumptions" in SymPy. If the symbol ``y`` is created with ``positive=True`` then SymPy will *assume* that it represents a positive real number rather than an arbitrary complex or possibly infinite number. That *assumption* can make it possible to simplify expressions or might allow other manipulations to work. It is usually a good idea to be as precise as possible about the assumptions on a symbol when creating it. The (old) assumptions system ============================ There are two sides to the assumptions system. The first side is that we can declare assumptions on a symbol when creating the symbol. The other side is that we can query the assumptions on any expression using the corresponding ``is_*`` attribute. For example: >>> x = Symbol('x', positive=True) >>> x.is_positive True We can query assumptions on any expression not just a symbol: >>> x = Symbol('x', positive=True) >>> expr = 1 + x**2 >>> expr x**2 + 1 >>> expr.is_positive True >>> expr.is_negative False The values given in an assumptions query use three-valued "fuzzy" logic. Any query can return ``True``, ``False``, or ``None`` where ``None`` should be interpreted as meaning that the result is *unknown*. >>> x = Symbol('x') >>> y = Symbol('y', positive=True) >>> z = Symbol('z', negative=True) >>> print(x.is_positive) None >>> print(y.is_positive) True >>> print(z.is_positive) False .. note:: We need to use ``print`` in the above examples because the special value ``None`` does not display by default in the Python interpretter. There are several reasons why an assumptions query might give ``None``. It is possible that the query is *unknowable* as in the case of ``x`` above. Since ``x`` does not have any assumptions declared it roughly represents an arbitrary complex number. An arbitrary complex number *might* be a positive real number but it also might *not* be. Without further information there is no way to resolve the query ``x.is_positive``. Another reason why an assumptions query might give ``None`` is that there does in many cases the problem of determining whether an expression is e.g. positive is *undecidable*. That means that there does not exist an algorithm for answering the query in general. For some cases an algorithm or at least a simple check would be possible but has not yet been implemented although it could be added to SymPy. The final reason that an assumptions query might give ``None`` is just that the assumptions system does not try very hard to answer complicated queries. The system is intended to be fast and uses simple heuristic methods to conclude a ``True`` or ``False`` answer in common cases. For example any sum of positive terms is positive so: >>> from sympy import symbols >>> x, y = symbols('x, y', positive=True) >>> expr = x + y >>> expr x + y >>> expr.is_positive True The last example is particularly simple so the assumptions system is able to give a definite answer. If the sum involved a mix of positive or negative terms it would be a harder query: >>> x = Symbol('x', real=True) >>> expr = 1 + (x - 2)**2 >>> expr (x - 2)**2 + 1 >>> expr.is_positive True >>> expr2 = expr.expand() >>> expr2 x**2 - 4*x + 5 >>> print(expr2.is_positive) None Ideally that last example would give ``True`` rather than ``None`` because the expression is always positive for any real value of ``x`` (and ``x`` has been assumed real). The assumptions system is intended to be efficient though: it is expected many more complex queries will not be fully resolved. This is because assumptions queries are primarily used internally by SymPy as part of low-level calculations. Making the system more comprehensive would slow SymPy down. Note that in fuzzy logic giving an indeterminate result ``None`` is never a contradiction. If it is possible to infer a definite ``True`` or ``False`` result when resolving a query then that is better than returning ``None``. However a result of ``None`` is not a *bug*. Any code that uses the assumptions system needs to be prepared to handle all three cases for any query and should not presume that a definite answer will always be given. The assumptions system is not just for symbols or for complex expressions. It can also be used for plain SymPy integers and other objects. The assumptions predicates are available on any instance of :class:`~.Basic` which is the superclass for most classes of SymPy objects. A plain Python :class:`int` is not a :class:`~.Basic` instance and can not be used to query assumptions predicates. We can "sympify" regular Python objects to become SymPy objects with :func:`~.sympify` or ``S`` (:class:`~.SingletonRegistry`) and then the assumptions system can be used: >>> from sympy import S >>> x = 2 >>> x.is_positive Traceback (most recent call last): ... AttributeError: 'int' object has no attribute 'is_positive' >>> x = S(2) >>> type(x) >>> x.is_positive True Gotcha: symbols with different assumptions ========================================== In SymPy it is possible to declare two symbols with different names and they will implicitly be considered equal under *structural equality*: >>> x1 = Symbol('x') >>> x2 = Symbol('x') >>> x1 x >>> x2 x >>> x1 == x2 True However if the symbols have different assumptions then they will be considered to represent distinct symbols: >>> x1 = Symbol('x', positive=True) >>> x2 = Symbol('x') >>> x1 x >>> x2 x >>> x1 == x2 False One way to simplify an expression is to use the :func:`~.posify` function which will replace all symbols in an expression with symbols that have the assumption ``positive=True`` (unless that contradicts any existing assumptions for the symbol): >>> from sympy import posify, exp >>> x = Symbol('x') >>> expr = exp(sqrt(x**2)) >>> expr exp(sqrt(x**2)) >>> posify(expr) (exp(_x), {_x: x}) >>> expr2, rep = posify(expr) >>> expr2 exp(_x) The :func:`~.posify` function returns the expression with all symbols replaced (which might lead to simplifications) and also a dict which maps the new symbols to the old that can be used with :py:meth:`~.Basic.subs`. This is useful because otherwise the new expression with the new symbols having the ``positive=True`` assumption will not compare equal to the old: >>> expr2 exp(_x) >>> expr2 == exp(x) False >>> expr2.subs(rep) exp(x) >>> expr2.subs(rep) == exp(x) True Applying assumptions to string inputs ===================================== We have seen how to set assumptions when :class:`~.Symbol` or :func:`~.symbols` explicitly. A natural question to ask is in what other situations can we assign assumptions to an object? It is common for users to use strings as input to SymPy functions (although the general feeling among SymPy developers is that this should be discouraged) e.g.: >>> from sympy import solve >>> solve('x**2 - 1') [-1, 1] When creating symbols explicitly it would be possible to assign assumptions that would affect the behaviour of :func:`~.solve`: >>> x = Symbol('x', positive=True) >>> solve(x**2 - 1) [1] When using string input SymPy will create the expression and create all of the symbolc implicitly so the question arises how can the assumptions be specified? The answer is that rather than depending on implicit string conversion it is better to use the :func:`~.parse_expr` function explicitly and then it is possible to provide assumptions for the symbols e.g.: >>> from sympy import parse_expr >>> parse_expr('x**2 - 1') x**2 - 1 >>> eq = parse_expr('x**2 - 1', {'x':Symbol('x', positive=True)}) >>> solve(eq) [1] .. note:: The :func:`~.solve` function is unusual as a high level API in that it actually checks the assumptions on any input symbols (the unknowns) and uses that to tailor its output. The assumptions system otherwise affects low-level evaluation but is not necessarily handled explicitly by high-level APIs. Predicates ========== There are many different predicates that can be assumed for a symbol or can be queried for an expression. It is possible to combine multiple predicates when creating a symbol. Predicates are logically combined using *and* so if a symbol is declared with ``positive=True`` and also with ``integer=True`` then it is both positive *and* integer: >>> x = Symbol('x', positive=True, integer=True) >>> x.is_positive True >>> x.is_integer True The full set of known predicates for a symbol can be accessed using the :attr:`~.Basic.assumptions0` attribute: >>> x.assumptions0 {'algebraic': True, 'commutative': True, 'complex': True, 'extended_negative': False, 'extended_nonnegative': True, 'extended_nonpositive': False, 'extended_nonzero': True, 'extended_positive': True, 'extended_real': True, 'finite': True, 'hermitian': True, 'imaginary': False, 'infinite': False, 'integer': True, 'irrational': False, 'negative': False, 'noninteger': False, 'nonnegative': True, 'nonpositive': False, 'nonzero': True, 'positive': True, 'rational': True, 'real': True, 'transcendental': False, 'zero': False} We can see that there are many more predicates listed than the two that were used to create ``x``. This is because the assumptions system can infer some predicates from combinations of other predicates. For example if a symbol is declared with ``positive=True`` then it is possible to infer that it should have ``negative=False`` because a positive number can never be negative. Similarly if a symbol is created with ``integer=True`` then it is possible to infer that is should have ``rational=True`` because every integer is a rational number. A full table of the possible predicates and their definitions is given below. .. list-table:: Assumptions predicates for the (old) assumptions :widths: 20, 45, 35 :header-rows: 1 * - Predicate - Definition - Implications * - ``commutative`` - A commutative expression. A ``commutative`` expression commutes with all other expressions under multiplication. If an expression ``a`` has ``commutative=True`` then ``a * b == b * a`` for any other expression ``b`` (even if ``b`` is not ``commutative``). Unlike all other assumptions predicates ``commutative`` must always be ``True`` or ``False`` and can never be ``None``. Also unlike all other predicates ``commutative`` defaults to ``True`` in e.g. ``Symbol('x')``. [commutative]_ - * - ``infinite`` - An infinite expression such as ``oo``, ``-oo`` or ``zoo``. [infinite]_ - | ``== !finite`` * - ``finite`` - A finite expression. Any expression that is not ``infinite`` is considered ``finite``. [infinite]_ - | ``== !infinite`` * - ``hermitian`` - An element of the field of Hermitian operators. [antihermitian]_ - * - ``antihermitian`` - An element of the field of antihermitian operators. [antihermitian]_ - * - ``complex`` - A complex number, $z\in\mathbb{C}$. Any number of the form $x + iy$ where $x$ and $y$ are ``real`` and $i = \sqrt{-1}$. All ``complex`` numbers are ``finite``. Includes all ``real`` numbers. [complex]_ - | ``-> commutative`` | ``-> finite`` * - ``algebraic`` - An algebraic number, $z\in\overline{\mathbb{Q}}$. Any number that is a root of a non-zero polynomial $p(z)\in\mathbb{Q}[z]$ having rational coefficients. All ``algebraic`` numbers are ``complex``. An ``algebraic`` number may or may not be ``real``. Includes all ``rational`` numbers. [algebraic]_ - | ``-> complex`` * - ``transcendental`` - A complex number that is not algebraic, $z\in\mathbb{C}-\overline{\mathbb{Q}}$. All ``transcendental`` numbers are ``complex``. A ``transcendental`` number may or may not be ``real`` but can never be ``rational``. [transcendental]_ - | ``== (complex & !algebraic)`` * - ``extended_real`` - An element of the extended real number line, $x\in\overline{\mathbb{R}}$ where $\overline{\mathbb{R}}=\mathbb{R}\cup\{-\infty,+\infty\}$. An ``extended_real`` number is either ``real`` or $\pm\infty$. The relational operators ``<``, ``<=``, ``>=`` and ``>`` are defined only for expressions that are ``extended_real``. [extended_real]_ - | ``-> commutative`` * - ``real`` - A real number, $x\in\mathbb{R}$. All ``real`` numbers are ``finite`` and ``complex`` (the set of reals is a subset of the set of complex numbers). Includes all ``rational`` numbers. A ``real`` number is either ``negative``, ``zero`` or ``positive``. [real]_ - | ``-> complex`` | ``== (extended_real & finite)`` | ``== (negative | zero | positive)`` | ``-> hermitian`` * - ``imaginary`` - An imaginary number, $z\in\mathbb{I}-\{0\}$. A number of the form $z=yi$ where $y$ is real, $y\ne 0$ and $i=\sqrt{-1}$. All ``imaginary`` numbers are ``complex`` and not ``real``. Note in particular that ``zero`` is `not` considered ``imaginary`` in SymPy. [imaginary]_ - | ``-> complex`` | ``-> antihermitian`` | ``-> !extended_real`` * - ``rational`` - A rational number, $q\in\mathbb{Q}$. Any number of the form $\frac{a}{b}$ where $a$ and $b$ are integers and $b \ne 0$. All ``rational`` numbers are ``real`` and ``algebraic``. Includes all ``integer`` numbers. [rational]_ - | ``-> real`` | ``-> algebraic`` * - ``irrational`` - A real number that is not rational, $x\in\mathbb{R}-\mathbb{Q}$. [irrational]_ - | ``== (real & !rational)`` * - ``integer`` - An integer, $a\in\mathbb{Z}$. All integers are ``rational``. Includes ``zero`` and all ``prime``, ``composite``, ``even`` and ``odd`` numbers. [integer]_ - | ``-> rational`` * - ``noninteger`` - An extended real number that is not an integer, $x\in\overline{\mathbb{R}}-\mathbb{Z}$. - | ``== (extended_real & !integer)`` * - ``even`` - An even number, $e\in\{2k: k\in\mathbb{Z}\}$. All ``even`` numbers are ``integer`` numbers. Includes ``zero``. [parity]_ - | ``-> integer`` | ``-> !odd`` * - ``odd`` - An odd number, $o\in\{2k + 1: k\in\mathbb{Z}\}$. All ``odd`` numbers are ``integer`` numbers. [parity]_ - | ``-> integer`` | ``-> !even`` * - ``prime`` - A prime number, $p\in\mathbb{P}$. All ``prime`` numbers are ``positive`` and ``integer``. [prime]_ - | ``-> integer`` | ``-> positive`` * - ``composite`` - A composite number, $c\in\mathbb{N}-(\mathbb{P}\cup\{1\})$. A positive integer that is the product of two or more primes. A ``composite`` number is always a ``positive`` ``integer`` and is not ``prime``. [composite]_ - | ``-> (integer & positive & !prime)`` | ``!composite -> (!positive | !even | prime)`` * - ``zero`` - The number $0$. An expression with ``zero=True`` represents the number ``0`` which is an ``integer``. [zero]_ - | ``-> even & finite`` | ``== (extended_nonnegative & extended_nonpositive)`` | ``== (nonnegative & nonpositive)`` * - ``nonzero`` - A nonzero real number, $x\in\mathbb{R}-\{0\}$. A ``nonzero`` number is always ``real`` and can not be ``zero``. - | ``-> real`` | ``== (extended_nonzero & finite)`` * - ``extended_nonzero`` - A member of the extended reals that is not zero, $x\in\overline{\mathbb{R}}-\{0\}$. - | ``== (extended_real & !zero)`` * - ``positive`` - A positive real number, $x\in\mathbb{R}, x>0$. All ``positive`` numbers are ``finite`` so ``oo`` is not ``positive``. [positive]_ - | ``== (nonnegative & nonzero)`` | ``== (extended_positive & finite)`` * - ``nonnegative`` - A nonnegative real number, $x\in\mathbb{R}, x\ge 0$. All ``nonnegative`` numbers are ``finite`` so ``oo`` is not ``nonnegative``. [positive]_ - | ``== (real & !negative)`` | ``== (extended_nonnegative & finite)`` * - ``negative`` - A negative real number, $x\in\mathbb{R}, x<0$. All ``negative`` numbers are ``finite`` so ``-oo`` is not ``negative``. [negative]_ - | ``== (nonpositive & nonzero)`` | ``== (extended_negative & finite)`` * - ``nonpositive`` - A nonpositive real number, $x\in\mathbb{R}, x\le 0$. All ``nonpositive`` numbers are ``finite`` so ``-oo`` is not ``nonpositive``. [negative]_ - | ``== (real & !positive)`` | ``== (extended_nonpositive & finite)`` * - ``extended_positive`` - A positive extended real number, $x\in\overline{\mathbb{R}}, x>0$. An ``extended_positive`` number is either ``positive`` or ``oo``. [extended_real]_ - | ``== (extended_nonnegative & extended_nonzero)`` * - ``extended_nonnegative`` - A nonnegative extended real number, $x\in\overline{\mathbb{R}}, x\ge 0$. An ``extended_nonnegative`` number is either ``nonnegative`` or ``oo``. [extended_real]_ - | ``== (extended_real & !extended_negative)`` * - ``extended_negative`` - A negative extended real number, $x\in\overline{\mathbb{R}}, x<0$. An ``extended_negative`` number is either ``negative`` or ``-oo``. [extended_real]_ - | ``== (extended_nonpositive & extended_nonzero)`` * - ``extended_nonpositive`` - A nonpositive extended real number, $x\in\overline{\mathbb{R}}, x\le 0$. An ``extended_nonpositive`` number is either ``nonpositive`` or ``-oo``. [extended_real]_ - | ``== (extended_real & !extended_positive)`` References for the above definitions ------------------------------------ .. [commutative] https://en.wikipedia.org/wiki/Commutative_property .. [infinite] https://en.wikipedia.org/wiki/Infinity .. [antihermitian] https://en.wikipedia.org/wiki/Skew-Hermitian_matrix .. [complex] https://en.wikipedia.org/wiki/Complex_number .. [algebraic] https://en.wikipedia.org/wiki/Algebraic_number .. [transcendental] https://en.wikipedia.org/wiki/Transcendental_number .. [extended_real] https://en.wikipedia.org/wiki/Extended_real_number_line .. [real] https://en.wikipedia.org/wiki/Real_number .. [imaginary] https://en.wikipedia.org/wiki/Imaginary_number .. [rational] https://en.wikipedia.org/wiki/Rational_number .. [irrational] https://en.wikipedia.org/wiki/Irrational_number .. [integer] https://en.wikipedia.org/wiki/Integer .. [parity] https://en.wikipedia.org/wiki/Parity_(mathematics) .. [prime] https://en.wikipedia.org/wiki/Prime_number .. [composite] https://en.wikipedia.org/wiki/Composite_number .. [zero] https://en.wikipedia.org/wiki/0 .. [positive] https://en.wikipedia.org/wiki/Positive_real_numbers .. [negative] https://en.wikipedia.org/wiki/Negative_number Implications ============ The assumptions system uses the inference rules to infer new predicates beyond those immediately specified when creating a symbol: >>> x = Symbol('x', real=True, negative=False, zero=False) >>> x.is_positive True Although ``x`` was not explicitly declared ``positive`` it can be inferred from the predicates that were given explicitly. Specifically one of the inference rules is ``real == negative | zero | positive`` so if ``real`` is ``True`` and both ``negative`` and ``zero`` are ``False`` then ``positive`` must be ``True``. In practice the assumption inference rules mean that it is not necessary to include redundant predicates for example a positive real number can be simply be declared as positive: >>> x1 = Symbol('x1', positive=True, real=True) >>> x2 = Symbol('x2', positive=True) >>> x1.is_real True >>> x2.is_real True >>> x1.assumptions0 == x2.assumptions0 True Combining predicates that are inconsistent will give an error: >>> x = Symbol('x', commutative=False, real=True) Traceback (most recent call last): ... InconsistentAssumptions: { algebraic: False, commutative: False, complex: False, composite: False, even: False, extended_negative: False, extended_nonnegative: False, extended_nonpositive: False, extended_nonzero: False, extended_positive: False, extended_real: False, imaginary: False, integer: False, irrational: False, negative: False, noninteger: False, nonnegative: False, nonpositive: False, nonzero: False, odd: False, positive: False, prime: False, rational: False, real: False, transcendental: False, zero: False}, real=True Interpretation of the predicates ================================ Although the predicates are defined in the table above it is worth taking some time to think about how to interpret them. Firstly many of the concepts referred to by the predicate names like "zero", "prime", "rational" etc have a basic meaning in mathematics but can also have more general meanings. For example when dealing with matrices a matrix of all zeros might be referred to as "zero". The predicates in the assumptions system do not allow any generalizations such as this. The predicate ``zero`` is strictly reserved for the plain number $0$. Instead matrices have an :py:meth:`~.MatrixCommon.is_zero_matrix` property for this purpose (although that property is not strictly part of the assumptions system): >>> from sympy import Matrix >>> M = Matrix([[0, 0], [0, 0]]) >>> M.is_zero False >>> M.is_zero_matrix True Similarly there are generalisations of the integers such as the Gaussian integers which have a different notion of prime number. The ``prime`` predicate in the assumptions system does not include those and strictly refers only to the standard prime numbers $\mathbb{P} = \{2, 3, 5, 7, 11, \cdots\}$. Likewise ``integer`` only means the standard concept of the integers $\mathbb{Z} = \{0, \pm 1, \pm 2, \cdots\}$, ``rational`` only means the standard concept of the rational numbers $\mathbb{Q}$ and so on. The predicates set up schemes of subsets such as the chain beginning with the complex numbers which are considered as a superset of the reals which are in turn a superset of the rationals and so on. The chain of subsets .. math:: \mathbb{Z} \subset \mathbb{Q} \subset \mathbb{R} \subset \mathbb{C} corresponds to the chain of implications in the assumptions system .. code-block:: C integer -> rational -> real -> complex A "vanilla" symbol with no assumptions explicitly attached is not known to belong to any of these sets and is not even known to be finite: >>> x = Symbol('x') >>> x.assumptions0 {'commutative': True} >>> print(x.is_commutative) True >>> print(x.is_rational) None >>> print(x.is_complex) None >>> print(x.is_real) None >>> print(x.is_integer) None >>> print(x.is_finite) None It is hard for SymPy to know what it can do with such a symbol that is not even known to be finite or complex so it is generally better to give some assumptions to the symbol explicitly. Many parts of SymPy will implicitly treat such a symbol as complex and in some cases SymPy will permit manipulations that would not strictly be valid given that ``x`` is not known to be finite. In a formal sense though very little is known about a vanilla symbol which makes manipulations involving it difficult. Defining *something* about a symbol can make a big difference. For example if we declare the symbol to be an integer then this implies a suite of other predicates that will help in further manipulations: >>> n = Symbol('n', integer=True) >>> n.assumptions0 {'algebraic': True, 'commutative': True, 'complex': True, 'extended_real': True, 'finite': True, 'hermitian': True, 'imaginary': False, 'infinite': False, 'integer': True, 'irrational': False, 'noninteger': False, 'rational': True, 'real': True, 'transcendental': False} These assumptions can lead to very significant simplifications e.g. ``integer=True`` gives: >>> from sympy import sin, pi >>> n1 = Symbol('n1') >>> n2 = Symbol('n2', integer=True) >>> sin(n1 * pi) sin(pi*n1) >>> sin(n2 * pi) 0 Replacing a whole expression with $0$ is about as good as simplification can get! It is normally advisable to set as many assumptions as possible on any symbols so that expressions can be simplified as much as possible. A common misunderstanding leads to defining a symbol with a ``False`` predicate e.g.: >>> x = Symbol('x', negative=False) >>> print(x.is_negative) False >>> print(x.is_nonnegative) None >>> print(x.is_real) None >>> print(x.is_complex) None >>> print(x.is_finite) None If the intention is to say that ``x`` is a real number that is not positive then that needs to be explicitly stated. In the context that the symbol is known to be real, the predicate ``positive=False`` becomes much more meaningful: >>> x = Symbol('x', real=True, negative=False) >>> print(x.is_negative) False >>> print(x.is_nonnegative) True >>> print(x.is_real) True >>> print(x.is_complex) True >>> print(x.is_finite) True A symbol declared as ``Symbol('x', real=True, negative=False)`` is equivalent to a symbol declared as ``Symbol('x', nonnegative=True)``. Simply declaring a symbol as ``Symbol('x', positive=False)`` does not allow the assumptions system to conclude much about it because a vanilla symbol is not known to be finite or even complex. A related confusion arises with ``Symbol('x', complex=True)`` and ``Symbol('x', real=False)``. Often when either of these is used neither is what is actually wanted. The first thing to understand is that all real numbers are complex so a symbol created with ``real=True`` will also have ``complex=True`` and a symbol created with ``complex=True`` will not have ``real=False``. If the intention was to create a complex number that is not a real number then it should be ``Symbol('x', complex=True, real=False)``. On the other hand declaring ``real=False`` alone is not sufficient to conclude that ``complex=True`` because knowing that it is not a real number does not tell us whether it is finite or whether or not it is some completely different kind of object from a complex number. A vanilla symbol is defined by not knowing whether it is ``finite`` etc but there is no clear definition of what it *should* actually represent. It is tempting to think of it as an "arbitrary complex number or possibly one of the infinities" but there is no way to query an arbitrary (non-symbol) expression in order to determine if it meets those criteria. It is important to bear in mind that within the SymPy codebase and potentially in downstream libraries many other kinds of mathematical objects can be found that might also have ``commutative=True`` while being something very different from an ordinary number (in this context even SymPy's standard infinities are considered "ordinary"). The only predicate that is applied by default for a symbol is ``commutative``. We can also declare a symbol to be *noncommutative* e.g.: >>> x, y = symbols('x, y', commutative=False) >>> z = Symbol('z') # defaults to commutative=True >>> x*y + y*x x*y + y*x >>> x*z + z*x 2*z*x Note here that since ``x`` and ``y`` are both noncommutative ``x`` and ``y`` do not commute so ``x*y != y*x``. On the other hand since ``z`` is commutative ``x`` and ``z`` commute and ``x*z == z*x`` even though ``x`` is noncommutative. The interpretation of what a vanilla symbol represents is unclear but the interpretation of an expression with ``commutative=False`` is entirely obscure. Such an expression is necessarily not a complex number or an extended real or any of the standard infinities (even ``zoo`` is commutative). We are left with very little that we can say about what such an expression *does* represent. Other is_* properties ===================== There are many properties and attributes in SymPy that that have names beginning with ``is_`` that look similar to the properties used in the (old) assumptions system but are not in fact part of the assumptions system. Some of these have a similar meaning and usage as those of the assumptions system such as the :py:meth:`~.MatrixCommon.is_zero_matrix` property shown above. Another example is the ``is_empty`` property of sets: >>> from sympy import FiniteSet, Intersection >>> S1 = FiniteSet(1, 2) >>> S1 {1, 2} >>> print(S1.is_empty) False >>> S2 = Intersection(FiniteSet(1), FiniteSet(Symbol('x'))) >>> S2 Intersection({1}, {x}) >>> print(S2.is_empty) None The ``is_empty`` property gives a fuzzy-bool indicating whether or not a :class:`~.Set` is the empty set. In the example of ``S2`` it is not possible to know whether or not the set is empty without knowing whether or not ``x`` is equal to ``1`` so ``S2.is_empty`` gives ``None``. The ``is_empty`` property for sets plays a similar role to the ``is_zero`` property for numbers in the assumptions system: ``is_empty`` is normally only ``True`` for the :class:`~.EmptySet` object but it is still useful to be able to distinguish between the cases where ``is_empty=False`` and ``is_empty=None``. Although ``is_zero_matrix`` and ``is_empty`` are used for similar purposes to the assumptions properties such as ``is_zero`` they are not part of the (old) assumptions system. There are no associated inference rules connecting e.g. ``Set.is_empty`` and ``Set.is_finite_set`` because the inference rules are part of the (old) assumptions system which only deals with the predicates listed in the table above. It is not possible to declare a :class:`~.MatrixSymbol` with e.g. ``zero_matrix=False`` and there is no ``SetSymbol`` class but if there was it would not have a system for understanding predicates like ``empty=False``. The properties :py:meth:`~.MatrixCommon.is_zero_matrix` and ``is_empty`` are similar to those of the assumptions system because they concern *semantic* aspects of an expression. There are a large number of other properties that focus on *structural* aspects such as ``is_Number``, :py:meth:`~.Expr.is_number`, :py:meth:`~.Basic.is_comparable`. Since these properties refer to structural aspects of an expression they will always give ``True`` or ``False`` rather than a fuzzy bool that also has the possibility of being ``None``. Capitalised properties such as ``is_Number`` are usually shorthand for ``isinstance`` checks e.g.: >>> from sympy import Number, Rational >>> x = Rational(1, 2) >>> isinstance(x, Number) True >>> x.is_Number True >>> y = Symbol('y', rational=True) >>> isinstance(y, Number) False >>> y.is_Number False The :class:`~.Number` class is the superclass for :class:`~.Integer`, :class:`~.Rational` and :class:`~.Float` so any instance of :class:`~.Number` represents a concrete number with a known value. A symbol such as ``y`` that is declared with ``rational=True`` might represent the same value as ``x`` but it is not a concrete number with a known value so this is a structural rather than a semantic distinction. Properties like ``is_Number`` are sometimes used in SymPy in place of e.g. ``isinstance(obj, Number)`` because they do not have problems with circular imports and checking ``x.is_Number`` can be faster than a call to ``isinstance``. The :attr:`~.Expr.is_number` (lower-case) property is very different from ``is_Number``. The :attr:`~.Expr.is_number` property is ``True`` for any expression that can be numerically evaluated to a floating point complex number with :py:meth:`~.EvalfMixin.evalf`: >>> from sympy import I >>> expr1 = I + sqrt(2) >>> expr1 sqrt(2) + I >>> expr1.is_number True >>> expr1.evalf() 1.4142135623731 + 1.0*I >>> x = Symbol('x') >>> expr2 = 1 + x >>> expr2 x + 1 >>> expr2.is_number False >>> expr2.evalf() x + 1.0 The primary reason for checking ``expr.is_number`` is to predict whether a call to :py:meth:`~.EvalfMixin.evalf` will fully evaluate. The :py:meth:`~.Basic.is_comparable` property is similar to :py:meth:`~.Expr.is_number` except that if ``is_comparable`` gives ``True`` then the expression is guaranteed to numerically evaluate to a *real* :class:`~.Float`. When ``a.is_comparable`` and ``b.is_comparable`` the inequality ``a < b`` should be resolvable as something like ``a.evalf() < b.evalf()``. The full set of ``is_*`` properties, attributes and methods in SymPy is large. It is important to be clear though that only those that are listed in the table of predicates above are actually part of the assumptions system. It is only those properties that are involved in the *mechanism* that implements the assumptions system which is explained below. Implementing assumptions handlers ================================= We will now work through an example of how to implement a SymPy symbolic function so that we can see how the old assumptions are used internally. SymPy already has an ``exp`` function which is defined for all complex numbers but we will define an ``expreal`` function which is restricted to real arguments. >>> from sympy import Function >>> from sympy.core.logic import fuzzy_and, fuzzy_or >>> >>> class expreal(Function): ... """exponential function E**x restricted to the extended reals""" ... ... is_extended_nonnegative = True ... ... @classmethod ... def eval(cls, x): ... # Validate the argument ... if x.is_extended_real is False: ... raise ValueError("non-real argument to expreal") ... # Evaluate for special values ... if x.is_zero: ... return S.One ... elif x.is_infinite: ... if x.is_extended_negative: ... return S.Zero ... elif x.is_extended_positive: ... return S.Infinity ... ... @property ... def x(self): ... return self.args[0] ... ... def _eval_is_finite(self): ... return fuzzy_or([self.x.is_real, self.x.is_extended_nonpositive]) ... ... def _eval_is_algebraic(self): ... if fuzzy_and([self.x.is_rational, self.x.is_nonzero]): ... return False ... ... def _eval_is_integer(self): ... if self.x.is_zero: ... return True ... ... def _eval_is_zero(self): ... return fuzzy_and([self.x.is_infinite, self.x.is_extended_negative]) The ``Function.eval`` method is used to pick up on special values of the function so that we can return a different object if it would be a simplification. When ``expreal(x)`` is called the ``expreal.__new__`` class method (defined in the superclass ``Function``) will call ``expreal.eval(x)``. If ``expreal.eval`` returns something other than ``None`` then that will be returned instead of an unevaluated ``expreal(x)``: >>> from sympy import oo >>> expreal(1) expreal(1) >>> expreal(0) 1 >>> expreal(-oo) 0 >>> expreal(oo) oo Note that the ``expreal.eval`` method does not compare the argument using ``==``. The special values are verified using the assumptions system to query the properties of the argument. That means that the ``expreal`` method can also evaluate for different forms of expression that have matching properties e.g. >>> x = Symbol('x', extended_negative=True, infinite=True) >>> x x >>> expreal(x) 0 Of course the assumptions system can only resolve a limited number of special values so most ``eval`` methods will also check against some special values with ``==`` but it is preferable to check e.g. ``x.is_zero`` rather than ``x==0``. Note also that the ``expreal.eval`` method validates that the argument is real. We want to allow $\pm\infty$ as arguments to ``expreal`` so we check for ``extended_real`` rather than ``real``. If the argument is not extended real then we raise an error: >>> expreal(I) Traceback (most recent call last): ... ValueError: non-real argument to expreal Importantly we check ``x.is_extended_real is False`` rather than ``not x.is_extended_real`` which means that we only reject the argument if it is *definitely* not extended real: if ``x.is_extended_real`` gives ``None`` then the argument will not be rejected. The first reason for allowing ``x.is_extended_real=None`` is so that a vanilla symbol can be used with ``expreal``. The second reason is that an assumptions query can always give ``None`` even in cases where an argument is definitely real e.g.: >>> x = Symbol('x') >>> print(x.is_extended_real) None >>> expreal(x) expreal(x) >>> expr = (1 + I)/sqrt(2) + (1 - I)/sqrt(2) >>> print(expr.is_extended_real) None >>> expr.expand() sqrt(2) >>> expr.expand().is_extended_real True >>> expreal(expr) expreal(sqrt(2)*(1 - I)/2 + sqrt(2)*(1 + I)/2) Validating the argument in ``expreal.eval`` does mean that it will not be validated when ``evaluate=False`` is passed but there is not really a better place to perform the validation: >>> expreal(I, evaluate=False) expreal(I) The ``extended_nonnegative`` class attribute and the ``_eval_is_*`` methods on the ``expreal`` class implement queries in the assumptions system for instances of ``expreal``: >>> expreal(2) expreal(2) >>> expreal(2).is_finite True >>> expreal(2).is_integer False >>> expreal(2).is_rational False >>> expreal(2).is_algebraic False >>> z = expreal(-oo, evaluate=False) >>> z expreal(-oo) >>> z.is_integer True >>> x = Symbol('x', real=True) >>> expreal(x) expreal(x) >>> expreal(x).is_nonnegative True The assumptions system resolves queries like ``expreal(2).is_finite`` using the corresponding handler ``expreal._eval_is_finite`` and *also* the implication rules. For example it is known that ``expreal(2).is_rational`` is ``False`` because ``expreal(2)._eval_is_algebraic`` returns ``False`` and there is an implication rule ``rational -> algebraic``. This means that an ``is_rational`` query can be resolved in this case by the ``_eval_is_algebraic`` handler. It is actually better not to implement assumptions handlers for every possible predicate but rather to try and identify a minimal set of handlers that can resolve as many queries as possible with as few checks as possible. Another point to note is that the ``_eval_is_*`` methods only make assumptions queries on the argument ``x`` and do not make any assumptions queries on ``self``. Recursive assumptions queries on the same object will interfere with the assumptions implications resolver potentially leading to non-deterministic behaviour so they should not be used (there are examples of this in the SymPy codebase but they should be removed). Many of the ``expreal`` methods implicitly return ``None``. This is a common pattern in the assumptions system. The ``eval`` method and the ``_eval_is_*`` methods can all return ``None`` and often will. A Python function that ends without reaching a ``return`` statement will implicitly return ``None``. We take advantage of this by leaving out many of the ``else`` clauses from the ``if`` statements and allowing ``None`` to be returned implicitly. When following the control flow of these methods it is important to bear in mind firstly that any queried property can give ``True``, ``False`` or ``None`` and also that any function will implicitly return ``None`` if all of the conditionals fail. Mechanism of the assumptions system =================================== .. note:: This section describes internal details that could change in a future SymPy version. This section will explain the inner workings of the assumptions system. It is important to understand that these inner workings are implementation details and could change from one SymPy version to another. This explanation is written as of SymPy 1.7. Although the (old) assumptions system has many limitations (discussed in the next section) it is a mature system that is used extensively in SymPy and has been well optimised for its current usage. The assumptions system is used implicitly in most SymPy operations to control evaluation of elementary expressions. There are several stages in the implementation of the assumptions system within a SymPy process that lead up to the evaluation of a single query in the assumptions system. Briefly these are: 1. At import time the assumptions rules defined in ``sympy/core/assumptions.py`` are processed into a canonical form ready for efficiently applying the implication rules. This happens once when SymPy is imported before even the :class:`~.Basic` class is defined. 2. The ``ManagedProperties`` metaclass is defined which is the metaclass for all :class:`~.Basic` subclasses. This class will post-process every :class:`~.Basic` subclass to add the relevant properties needed for assumptions queries. This also adds the ``default_assumptions`` attribute to the class. This happens each time a :class:`~.Basic` subclass is defined. 3. Every :class:`~.Basic` instance initially uses the ``default_assumptions`` class attribute. When an assumptions query is made on a :class:`~.Basic` instance in the first instance the query will be answered from the ``default_assumptions`` for the class. 4. If there is no cached value for the assumptions query in the ``default_assumptions`` for the class then the default assumptions will be copied to make an assumptions cache for the instance. Then the ``_ask()`` function is called to resolve the query which will firstly call the relevant instance handler ``_eval_is`` method. If the handler returns non-None then the result will be cached and returned. 5. If the handler does not exist or gives None then the implications resolver is tried. This will enumerate (in a randomised order) all possible combinations of predicates that could potentially be used to resolve the query under the implication rules. In each case the handler ``_eval_is`` method will be called to see if it gives non-None. If any combination of handlers and implication rules leads to a definitive result for the query then that result is cached in the instance cache and returned. 6. Finally if the implications resolver failed to resolve the query then the query is considered unresolvable. The value of ``None`` for the query is cached in the instance cache and returned. The assumptions rules defined in ``sympy/core/assumptions.py`` are given in forms like ``real == negative | zero | positive``. When this module is imported these are converted into a ``FactRules`` instance called ``_assume_rules``. This preprocesses the implication rules into the form of "A" and "B" rules that can be used for the implications resolver. This is explained in the code in ``sympy/core/facts.py``. We can access this internal object directly like (full output omitted): >>> from sympy.core.assumptions import _assume_rules >>> _assume_rules.defined_facts # doctest: +SKIP {'algebraic', 'antihermitian', 'commutative', 'complex', 'composite', 'even', ... >>> _assume_rules.full_implications # doctest: +SKIP defaultdict(set, {('extended_positive', False): {('composite', False), ('positive', False), ('prime', False)}, ('finite', False): {('algebraic', False), ('complex', False), ('composite', False), ... The ``ManagedProperties`` metaclass will inspect the attributes of each ``Basic`` class to see if any assumptions related attributes are defined. An example of these is the ``is_extended_nonnegative = True`` attribute defined in the ``expreal`` class. The implications of any such attributes will be used to precompute any statically knowable assumptions. For example ``is_extended_nonnegative=True`` implies ``real=True`` etc. A ``StdFactKB`` instance is created for the class which stores those assumptions whose values are known at this stage. The ``StdFactKB`` instance is assigned as the class attribute ``default_assumptions``. We can see this with >>> from sympy import Expr ... >>> class A(Expr): ... is_positive = True ... ... def _eval_is_rational(self): ... # Let's print something to see when this method is called... ... print('!!! calling _eval_is_rational') ... return True ... >>> A.is_positive True >>> A.is_real # inferred from is_positive True Although only ``is_positive`` was defined in the class ``A`` it also has attributes such as ``is_real`` which are inferred from ``is_positive``. The set of all such assumptions for class ``A`` can be seen in ``default_assumptions`` which looks like a ``dict`` but is in fact a ``StdFactKB`` instance: >>> type(A.default_assumptions) >>> A.default_assumptions {'commutative': True, 'complex': True, 'extended_negative': False, 'extended_nonnegative': True, 'extended_nonpositive': False, 'extended_nonzero': True, 'extended_positive': True, 'extended_real': True, 'finite': True, 'hermitian': True, 'imaginary': False, 'infinite': False, 'negative': False, 'nonnegative': True, 'nonpositive': False, 'nonzero': True, 'positive': True, 'real': True, 'zero': False} When an instance of any :class:`~.Basic` subclass is created ``Basic.__new__`` will assign its ``_assumptions`` attribute which will initially be a reference to ``cls.default_assumptions`` shared amongst all instances of the same class. The instance will use this to resolve any assumptions queries until that fails to give a definitive result at which point a copy of ``cls.default_assumptions`` will be created and assigned to the instance's ``_assumptions`` attribute. The copy will be used as a cache to store any results computed for the instance by its ``_eval_is`` handlers. When the ``_assumptions`` attribute fails to give the relevant result it is time to call the ``_eval_is`` handlers. At this point the ``_ask()`` function is called. The ``_ask()`` function will initially try to resolve a query such as ``is_rational`` by calling the corresponding method i.e. ``_eval_is_rational``. If that gives non-None then the result is stored in ``_assumptions`` and any implications of that result are computed and stored as well. At that point the query is resolved and the value returned. >>> a = A() >>> a._assumptions is A.default_assumptions True >>> a.is_rational !!! calling _eval_is_rational True >>> a._assumptions is A.default_assumptions False >>> a._assumptions # rational now shows as True {'algebraic': True, 'commutative': True, 'complex': True, 'extended_negative': False, 'extended_nonnegative': True, 'extended_nonpositive': False, 'extended_nonzero': True, 'extended_positive': True, 'extended_real': True, 'finite': True, 'hermitian': True, 'imaginary': False, 'infinite': False, 'irrational': False, 'negative': False, 'nonnegative': True, 'nonpositive': False, 'nonzero': True, 'positive': True, 'rational': True, 'real': True, 'transcendental': False, 'zero': False} If e.g. ``_eval_is_rational`` does not exist or gives ``None`` then ``_ask()`` will try all possibilities to use the implication rules and any other handler methods such as ``_eval_is_integer``, ``_eval_is_algebraic`` etc that might possibly be able to give an answer to the original query. If any method leads to a definite result being known for the original query then that is returned. Otherwise once all possibilities for using a handler and the implication rules to resolve the query are exhausted ``None`` will be cached and returned. >>> b = A() >>> b.is_algebraic # called _eval_is_rational indirectly !!! calling _eval_is_rational True >>> c = A() >>> print(c.is_prime) # called _eval_is_rational indirectly !!! calling _eval_is_rational None >>> c._assumptions # prime now shows as None {'algebraic': True, 'commutative': True, 'complex': True, 'extended_negative': False, 'extended_nonnegative': True, 'extended_nonpositive': False, 'extended_nonzero': True, 'extended_positive': True, 'extended_real': True, 'finite': True, 'hermitian': True, 'imaginary': False, 'infinite': False, 'irrational': False, 'negative': False, 'nonnegative': True, 'nonpositive': False, 'nonzero': True, 'positive': True, 'prime': None, 'rational': True, 'real': True, 'transcendental': False, 'zero': False} .. note:: In the ``_ask()`` function the handlers are called in a randomised order which can mean that execution at this point is non-deterministic. Provided all of the different handler methods are consistent (i.e. there are no bugs) then the end result will still be deterministic. However a bug where two handlers are inconsistent can manifest in non-deterministic behaviour because this randomisation might lead to the handlers being called in different orders when the same program is run multiple times. Limitations =========== Combining predicates with or ---------------------------- In the old assumptions we can easily combine predicates with *and* when creating a Symbol e.g.: >>> x = Symbol('x', integer=True, positive=True) >>> x.is_positive True >>> x.is_integer True We can also easily query whether two conditions are jointly satisfied with >>> fuzzy_and([x.is_positive, x.is_integer]) True >>> x.is_positive and x.is_integer True However there is no way in the old assumptions to create a :class:`~.Symbol` with assumptions predicates combined with *or*. For example if we wanted to say that "x is positive or x is an integer" then it is not possible to create a :class:`~.Symbol` with those assumptions. It is also not possible to ask an assumptions query based on *or* e.g. "is expr an expression that is positive or an integer". We can use e.g. >>> fuzzy_or([x.is_positive, x.is_integer]) True However if all that is known about ``x`` is that it is possibly positive or otherwise a negative integer then both queries ``x.is_positive`` and ``x.is_integer`` will resolve to ``None``. That means that the query becomes >>> fuzzy_or([None, None]) which then also gives ``None``. Relations between different symbols ----------------------------------- A fundamental limitation of the old assumptions system is that all explicit assumptions are properties of an individual symbol. There is no way in this system to make an assumption about the *relationship* between two symbols. One of the most common requests is the ability to assume something like ``x < y`` but there is no way to even specify that in the old assumptions. The new assumptions have the theoretical capability that relational assumptions can be specified. However the algorithms to make use of that information are not yet implemented and the exact API for specifying relational assumptions has not been decided upon. Dynamic changing assumptions ---------------------------- Selectively controlling evaluation ---------------------------------- Extensibility ------------- New assumptions =============== ZZZ: Talk about the new assumptions here... sympy-sympy-1.9/doc/src/guides/booleans.rst000066400000000000000000000370431412543434000211020ustar00rootroot00000000000000.. _booleans: ============================= Symbolic and fuzzy booleans ============================= This page described what a symbolic :class:`~.Boolean` in SymPy is and also how that relates to three-valued fuzzy-bools that are used in many parts of SymPy. It also discusses some common problems that arise when writing code that uses three-valued logic and how to handle them correctly. Symbolic Boolean vs three valued bool ===================================== Assumptions queries like ``x.ispositive`` give fuzzy-bool ``True``, ``False`` or ``None`` results [#fuzzy]_. These are low-level Python objects rather than SymPy's symbolic :class:`~.Boolean` expressions. >>> from sympy import Symbol, symbols >>> xpos = Symbol('xpos', positive=True) >>> xneg = Symbol('xneg', negative=True) >>> x = Symbol('x') >>> print(xpos.is_positive) True >>> print(xneg.is_positive) False >>> print(x.is_positive) None A ``None`` result as a fuzzy-bool should be interpreted as meaning "maybe" or "unknown". An example of a symbolic :class:`~.Boolean` class in SymPy can be found when using inequalities. When an inequality is not known to be true or false a :class:`~.Boolean` can represent indeterminate results symbolically: >>> xpos > 0 True >>> xneg > 0 False >>> x > 0 x > 0 >>> type(x > 0) The last example shows what happens when an inequality is indeterminate: we get an instance of :class:`~.StrictGreaterThan` which represents the inequality as a symbolic expression. Internally when attempting to evaluate an inequality like ``a > b`` SymPy will compute ``(a - b).is_extended_positive``. If the result is ``True`` or ``False`` then SymPy's symbolic ``S.true`` or ``S.false`` will be returned. If the result is ``None`` then an unevaluated :class:`~.StrictGreaterThan` is returned as shown for ``x > 0`` above. It is not obvious that queries like ``xpos > 0`` return ``S.true`` rather than ``True`` because both objects display in the same way but we can check this using the Python ``is`` operator: >>> from sympy import S >>> xpos.is_positive is True True >>> xpos.is_positive is S.true False >>> (xpos > 0) is True False >>> (xpos > 0) is S.true True There is no general symbolic analogue of ``None`` in SymPy. In the cases where a low-level assumptions query gives ``None`` the symbolic query will result in an unevaluated symbolic :class:`~.Boolean` (e.g, ``x > 0``). We can use a symbolic :class:`~.Boolean` as part of a symbolic expression such as a :class:`~.Piecewise`: >>> from sympy import Piecewise >>> p = Piecewise((1, x > 0), (2, True)) >>> p Piecewise((1, x > 0), (2, True)) >>> p.subs(x, 3) 1 Here ``p`` represents an expression that will be equal to ``1`` if ``x > 0`` or otherwise it will be equal to ``2``. The unevaluated :class:`~.Boolean` inequality ``x > 0`` represents the condition for deciding the value of the expression symbolically. When we substitute a value for ``x`` the inequality will resolve to ``S.true`` and then the :class:`~.Piecewise` can evaluate to ``1`` or ``2``. The same will not work when using a fuzzy-bool instead of a symbolic :class:`~.Boolean`: >>> p2 = Piecewise((1, x.is_positive), (2, True)) Traceback (most recent call last): ... TypeError: Second argument must be a Boolean, not `NoneType` The :class:`~.Piecewise` can not use ``None`` as the condition because unlike the inequality ``x > 0`` it gives no information. With the inequality it is possible to decide in future if the condition might ``True`` or ``False`` once a value for ``x`` is known. A value of ``None`` can not be used in that way so it is rejected. .. note:: We can use ``True`` in the :class:`~.Piecewise` because ``True`` sympifies to ``S.true``. Sympifying ``None`` just gives ``None`` again which is not a valid symbolic SymPy object. There are many other symbolic :class:`~.Boolean` types in SymPy. The same considerations about the differences between fuzzy bool and symbolic :class:`~.Boolean` apply to all other SymPy :class:`~.Boolean` types. To give a different example there is :class:`~.Contains` which represents the statement that an object is contained in a set: >>> from sympy import Reals, Contains >>> x = Symbol('x', real=True) >>> y = Symbol('y') >>> Contains(x, Reals) True >>> Contains(y, Reals) Contains(y, Reals) >>> Contains(y, Reals).subs(y, 1) True The Python operator corresponding to :class:`~.Contains` is ``in``. A quirk of ``in`` is that it can only evaluate to a ``bool`` (``True`` or ``False``) so if the result is indeterminate then an exception will be raised: >>> from sympy import I >>> 2 in Reals True >>> I in Reals False >>> x in Reals True >>> y in Reals Traceback (most recent call last): ... TypeError: did not evaluate to a bool: (-oo < y) & (y < oo) The exception can be avoided by using ``Contains(x, Reals)`` or ``Reals.contains(x)`` rather than ``x in Reals``. Three-valued logic with fuzzy bools =================================== Whether we use the fuzzy-bool or symbolic :class:`~.Boolean` we always need to be aware of the possibility that a query might be indeterminate. How to write code that handles this is different in the two cases though. We will look at fuzzy-bools first. Consider the following function: >>> def both_positive(a, b): ... """ask whether a and b are both positive""" ... if a.is_positive and b.is_positive: ... return True ... else: ... return False The ``both_positive`` function is supposed to tell us whether or not ``a`` and ``b`` are both positive. However the ``both_positive`` function will fail if either of the ``is_positive`` queries gives ``None``: >>> print(both_positive(S(1), S(1))) True >>> print(both_positive(S(1), S(-1))) False >>> print(both_positive(S(-1), S(-1))) False >>> x = Symbol('x') # may or may not be positive >>> print(both_positive(S(1), x)) False .. note:: We need to sympify the arguments to this function using ``S`` because the assumptions are only defined on SymPy objects and not regular Python :class:`int` objects. Here ``False`` is incorrect because it is *possible* that ``x`` is positive in which case both arguments would be positive. We get ``False`` here because ``x.is_positive`` gives ``None`` and Python will treat ``None`` as "falsey". In order to handle all possible cases correctly we need to separate the logic for identifying the ``True`` and ``False`` cases. An improved function might be: >>> def both_positive_better(a, b): ... """ask whether a and b are both positive""" ... if a.is_positive is False or b.is_positive is False: ... return False ... elif a.is_positive is True and b.is_positive is True: ... return True ... else: ... return None This function now can handle all cases of ``True``, ``False`` or ``None`` for both ``a`` and ``b`` and will always return a fuzzy bool representing whether the statement "``a`` and ``b`` are both positive" is true, false or unknown: >>> print(both_positive_better(S(1), S(1))) True >>> print(both_positive_better(S(1), S(-1))) False >>> x = Symbol('x') >>> y = Symbol('y', positive=True) >>> print(both_positive_better(S(1), x)) None >>> print(both_positive_better(S(-1), x)) False >>> print(both_positive_better(S(1), y)) True Another case that we need to careful of when using fuzzy-bools is negation with Python's ``not`` operator e.g.: >>> x = Symbol('x') >>> print(x.is_positive) None >>> not x.is_positive True The correct negation of a fuzzy bool ``None`` is ``None`` again. If we do not know whether the statement "``x`` is positive" is ``True`` or ``False`` then we also do not know whether its negation "``x`` is not positive" is ``True`` or ``False``. The reason we get ``True`` instead is again because ``None`` is considered "falsey". When ``None`` is used with a logical operator such as ``not`` it will first be converted to a :class:`bool` and then negated: >>> bool(None) False >>> not bool(None) True >>> not None True The fact that ``None`` is treated as falsey can be useful if used correctly. For example we may want to do something only if ``x`` is known to positive in which case we can do >>> x = Symbol('x', positive=True) >>> if x.is_positive: ... print("x is definitely positive") ... else: ... print("x may or may not be positive") x is definitely positive Provided we understand that an alternate condition branch refers to two cases (``False`` and ``None``) then this can be a useful way of writing conditionals. When we really do need to distinguish all cases then we need to use things like ``x.is_positive is False``. What we need to be careful of though is using Python's binary logic operators like ``not`` or ``and`` with fuzzy bools as they will not handle the indeterminate case correctly. In fact SymPy has internal functions that are designed to handle fuzzy-bools correctly: >>> from sympy.core.logic import fuzzy_not, fuzzy_and >>> print(fuzzy_not(True)) False >>> print(fuzzy_not(False)) True >>> print(fuzzy_not(None)) None >>> print(fuzzy_and([True, True])) True >>> print(fuzzy_and([True, None])) None >>> print(fuzzy_and([False, None])) False Using the ``fuzzy_and`` function we can write the ``both_positive`` function more simply: >>> def both_positive_best(a, b): ... """ask whether a and b are both positive""" ... return fuzzy_and([a.is_positive, b.is_positive]) Making use of ``fuzzy_and``, ``fuzzy_or`` and ``fuzzy_not`` leads to simpler code and can also reduce the chance of introducing a logic error because the code can look more like it would in the case of ordinary binary logic. Three-valued logic with symbolic Booleans ========================================= When working with symbolic :class:`~.Boolean` rather than fuzzy-bool the issue of ``None`` silently being treated as falsey does not arise so it is easier not to end up with a logic error. However instead the indeterminate case will often lead to an exception being raised if not handled carefully. We will try to implement the ``both_positive`` function this time using symbolic :class:`~.Boolean`: >>> def both_positive(a, b): ... """ask whether a and b are both positive""" ... if a > 0 and b > 0: ... return S.true ... else: ... return S.false The first difference is that we return the symbolic :class:`~.Boolean` objects ``S.true`` and ``S.false`` rather than ``True`` and ``False``. The second difference is that we test e.g. ``a > 0`` rather than ``a.is_positive``. Trying this out we get >>> both_positive(1, 2) True >>> both_positive(-1, 1) False >>> x = Symbol('x') # may or may not be positive >>> both_positive(x, 1) Traceback (most recent call last): ... TypeError: cannot determine truth value of Relational What happens now is that testing ``x > 0`` gives an exception when ``x`` is not known to be positive or not positive. More precisely ``x > 0`` does not give an exception but ``if x > 0`` does and that is because the ``if`` statement implicitly calls ``bool(x > 0)`` which raises. >>> x > 0 x > 0 >>> bool(x > 0) Traceback (most recent call last): ... TypeError: cannot determine truth value of Relational >>> if x > 0: ... print("x is positive") Traceback (most recent call last): ... TypeError: cannot determine truth value of Relational The Python expression ``x > 0`` creates a SymPy :class:`~.Boolean`. Since in this case the :class:`~.Boolean` can not evaluate to ``True`` or ``False`` we get an unevaluated :class:`~.StrictGreaterThan`. Attempting to force that into a ``bool`` with ``bool(x > 0)`` raises an exception. That is because a regular Python ``bool`` must be either ``True`` or ``False`` and neither of those are known to be correct in this case. The same kind of issue arises when using ``and``, ``or`` or ``not`` with symbolic :class:`~.Boolean`. The solution is to use SymPy's symbolic :class:`~.And`, :class:`~.Or` and :class:`~.Not` or equivalently Python's bitwise logical operators ``&``, ``|`` and ``~``: >>> from sympy import And, Or, Not >>> x > 0 x > 0 >>> x > 0 and x < 1 Traceback (most recent call last): ... TypeError: cannot determine truth value of Relational >>> And(x > 0, x < 1) (x > 0) & (x < 1) >>> (x > 0) & (x < 1) (x > 0) & (x < 1) >>> Or(x < 0, x > 1) (x > 1) | (x < 0) >>> Not(x < 0) x >= 0 >>> ~(x < 0) x >= 0 As before we can make a better version of ``both_positive`` if we avoid directly using a SymPy :class:`~.Boolean` in an ``if``, ``and``, ``or``, or ``not``. Instead we can test whether or not the :class:`~.Boolean` has evaluated to ``S.true`` or ``S.false``: >>> def both_positive_better(a, b): ... """ask whether a and b are both positive""" ... if (a > 0) is S.false or (b > 0) is S.false: ... return S.false ... elif (a > 0) is S.true and (b > 0) is S.true: ... return S.true ... else: ... return And(a > 0, b > 0) Now with this version we don't get any exceptions and if the result is indeterminate we will get a symbolic :class:`~.Boolean` representing the conditions under which the statement "``a`` and ``b`` are both positive" would be true: >>> both_positive_better(S(1), S(2)) True >>> both_positive_better(S(1), S(-1)) False >>> x, y = symbols("x, y") >>> both_positive_better(x, y + 1) (x > 0) & (y + 1 > 0) >>> both_positive_better(x, S(3)) x > 0 The last case shows that actually using the :class:`~.And` with a condition that is known to be true simplifies the :class:`~.And`. In fact we have >>> And(x > 0, 3 > 0) x > 0 >>> And(4 > 0, 3 > 0) True >>> And(-1 > 0, 3 > 0) False What this means is that we can improve ``both_positive_better``. The different cases are not needed at all. Instead we can simply return the :class:`~.And` and let it simplify if possible: >>> def both_positive_best(a, b): ... """ask whether a and b are both positive""" ... return And(a > 0, b > 0) Now this will work with any symbolic real objects and produce a symbolic result. We can also substitute into the result to see how it would work for particular values: >>> both_positive_best(2, 1) True >>> both_positive_best(-1, 2) False >>> both_positive_best(x, 3) x > 0 >>> condition = both_positive_best(x/y, x + y) >>> condition (x + y > 0) & (x/y > 0) >>> condition.subs(x, 1) (1/y > 0) & (y + 1 > 0) >>> condition.subs(x, 1).subs(y, 2) True The idea when working with symbolic :class:`~.Boolean` objects is as much as possible to avoid trying to branch on them with ``if/else`` and other logical operators like ``and`` etc. Instead think of computing a condition and passing it around as a variable. The elementary symbolic operations like :class:`~.And`, :class:`~.Or` and :class:`~.Not` can then take care of the logic for you. .. rubric:: Footnotes .. [#fuzzy] Note that what is referred to in SymPy as a "fuzzy bool" is really about using three-valued logic. In normal usage "fuzzy logic" refers to a system where logical values are continuous in between zero and one which is something different from three-valued logic. sympy-sympy-1.9/doc/src/guides/index.rst000066400000000000000000000001731412543434000204010ustar00rootroot00000000000000.. _guides: ============== SymPy Guides ============== .. toctree:: :maxdepth: 2 assumptions.rst booleans.rst sympy-sympy-1.9/doc/src/index.rst000066400000000000000000000015271412543434000171250ustar00rootroot00000000000000.. _documentation: .. SymPy documentation master file, created by sphinx-quickstart.py on Sat Mar 22 19:34:32 2008. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Welcome to SymPy's documentation! ================================= A PDF version of these docs can be found `here `_. `SymPy `_ is a Python library for symbolic mathematics. If you are new to SymPy, start with the :ref:`Tutorial `. This is the central page for all of SymPy's documentation. Contents: .. toctree:: :maxdepth: 2 install.rst tutorial/index.rst guides/index.rst gotchas.rst modules/index.rst special_topics/index.rst wiki.rst outreach.rst aboutus.rst citing.rst documentation-style-guide.rst sympy-sympy-1.9/doc/src/install.rst000066400000000000000000000074761412543434000174750ustar00rootroot00000000000000.. _installation: Installation ------------ The SymPy CAS can be installed on virtually any computer with Python. SymPy does require `mpmath`_ Python library to be installed first. The recommended method of installation is through Anaconda, which includes mpmath, as well as several other useful libraries. Alternatively, some Linux distributions have SymPy packages available. SymPy officially supports Python 3.5, 3.6, 3.7, and PyPy. Anaconda ======== `Anaconda `_ is a free Python distribution from Continuum Analytics that includes SymPy, Matplotlib, IPython, NumPy, and many more useful packages for scientific computing. This is recommended because many nice features of SymPy are only enabled when certain libraries are installed. For example, without Matplotlib, only simple text-based plotting is enabled. With the IPython notebook or qtconsole, you can get nicer `\mathrm{\LaTeX}` printing by running ``init_printing()``. If you already have Anaconda and want to update SymPy to the latest version, use:: conda update sympy Git === If you wish to contribute to SymPy or like to get the latest updates as they come, install SymPy from git. To download the repository, execute the following from the command line:: git clone https://github.com/sympy/sympy.git To update to the latest version, go into your repository and execute:: git pull origin master If you want to install SymPy, but still want to use the git version, you can run from your repository:: python setupegg.py develop This will cause the installed version to always point to the version in the git directory. Other Methods ============= You may also install SymPy using pip or from source. In addition, most Linux and Python distributions have some SymPy version available to install using their package manager. Here is a list of several such Python distributions: * `Anaconda `_ * `Enthought Canopy `_ * `ActivePython `_ * `Spack `_ Run SymPy ========= After installation, it is best to verify that your freshly-installed SymPy works. To do this, start up Python and import the SymPy libraries:: $ python >>> from sympy import * From here, execute some simple SymPy statements like the ones below:: >>> x = Symbol('x') >>> limit(sin(x)/x, x, 0) 1 >>> integrate(1/x, x) log(x) For a starter guide on using SymPy effectively, refer to the :ref:`tutorial`. Mpmath ====== Versions of SymPy prior to 1.0 included `mpmath`_, but it now depends on it as an external dependency. If you installed SymPy with Anaconda, it will already include mpmath. Use:: conda install mpmath to ensure that it is installed. If you do not wish to use Anaconda, you can use ``pip install mpmath``. If you use mpmath via ``sympy.mpmath`` in your code, you will need to change this to use just ``mpmath``. If you depend on code that does this that you cannot easily change, you can work around it by doing:: import sys import mpmath sys.modules['sympy.mpmath'] = mpmath before the code that imports ``sympy.mpmath``. It is recommended to change code that uses ``sympy.mpmath`` to use ``mpmath`` directly wherever possible. Questions ========= If you have a question about installation or SymPy in general, feel free to visit our chat on `Gitter`_. In addition, our `mailing list`_ is an excellent source of community support. If you think there's a bug or you would like to request a feature, please open an `issue ticket`_. .. _downloads site: https://github.com/sympy/sympy/releases .. _Gitter: https://gitter.im/sympy/sympy .. _issue ticket: https://github.com/sympy/sympy/issues .. _mailing list: https://groups.google.com/forum/#!forum/sympy .. _mpmath: http://mpmath.org/ sympy-sympy-1.9/doc/src/logo/000077500000000000000000000000001412543434000162175ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/logo/info.txt000066400000000000000000000004671412543434000177220ustar00rootroot00000000000000The real source is `sympy-use-text.svg`. The `sympy.svg` is "text to path" version of `sympy-use-text.svg`. To create it from `sympy-use-text.svg` do (you have to install the Computer Modern fonts first): Inkscape 1. Run Inkscape. 2. Open `sympy-use-text.svg` 3. Ctrl-A 4. Shift-Ctrl-C 5. Save As `sympy.svg` sympy-sympy-1.9/doc/src/logo/sympy-use-text.svg000066400000000000000000001024631412543434000217030ustar00rootroot00000000000000 sympy-sympy-1.9/doc/src/logo/sympy.svg000066400000000000000000001172071412543434000201310ustar00rootroot00000000000000 sympy-sympy-1.9/doc/src/modules/000077500000000000000000000000001412543434000167275ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/abc.rst000066400000000000000000000000541412543434000202050ustar00rootroot00000000000000===== abc ===== .. automodule:: sympy.abc sympy-sympy-1.9/doc/src/modules/algebras.rst000066400000000000000000000005141412543434000212410ustar00rootroot00000000000000======== Algebras ======== Introduction ------------ The Algebras module for SymPy provides support for basic algebraic operations on Quaternions. Quaternion Reference -------------------- .. automodule:: sympy.algebras This section lists the classes implemented by the Algebras module. .. autoclass:: Quaternion :members: sympy-sympy-1.9/doc/src/modules/assumptions/000077500000000000000000000000001412543434000213145ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/assumptions/ask.rst000066400000000000000000000001001412543434000226130ustar00rootroot00000000000000=== Ask === .. automodule:: sympy.assumptions.ask :members: sympy-sympy-1.9/doc/src/modules/assumptions/assume.rst000066400000000000000000000001141412543434000233370ustar00rootroot00000000000000====== Assume ====== .. automodule:: sympy.assumptions.assume :members: sympy-sympy-1.9/doc/src/modules/assumptions/index.rst000066400000000000000000000036211412543434000231570ustar00rootroot00000000000000.. _assumptions_module: =========== Assumptions =========== .. automodule:: sympy.assumptions Predicate ========= .. autoclass:: sympy.assumptions.assume::Predicate :members: :noindex: .. autoclass:: sympy.assumptions.assume::AppliedPredicate :members: :noindex: Querying ======== Queries are used to ask information about expressions. Main method for this is ``ask()``: .. autofunction:: sympy.assumptions.ask::ask :noindex: ``ask``'s optional second argument should be a boolean expression involving assumptions about objects in *expr*. Valid values include: * ``Q.integer(x)`` * ``Q.positive(x)`` * ``Q.integer(x) & Q.positive(x)`` * etc. ``Q`` is an object holding known predicates. See documentation for the logic module for a complete list of valid boolean expressions. You can also define a context so you don't have to pass that argument each time to function ``ask()``. This is done by using the assuming context manager from module sympy.assumptions. :: >>> from sympy import * >>> x = Symbol('x') >>> y = Symbol('y') >>> facts = Q.positive(x), Q.positive(y) >>> with assuming(*facts): ... print(ask(Q.positive(2*x + y))) True Contents ======== .. toctree:: :maxdepth: 3 ask.rst assume.rst refine.rst predicates.rst Performance improvements ======================== On queries that involve symbolic coefficients, logical inference is used. Work on improving satisfiable function (sympy.logic.inference.satisfiable) should result in notable speed improvements. Logic inference used in one ask could be used to speed up further queries, and current system does not take advantage of this. For example, a truth maintenance system (https://en.wikipedia.org/wiki/Truth_maintenance_system) could be implemented. Misc ==== You can find more examples in the in the form of test under directory sympy/assumptions/tests/ sympy-sympy-1.9/doc/src/modules/assumptions/predicates.rst000066400000000000000000000111041412543434000241660ustar00rootroot00000000000000.. _predicates: .. module:: sympy.assumptions.predicates ========== Predicates ========== Common ====== Tautological ------------ .. autoclass:: sympy.assumptions.predicates.common.IsTruePredicate :members: Commutative ----------- .. autoclass:: sympy.assumptions.predicates.common.CommutativePredicate :members: Calculus ======== Finite ------ .. autoclass:: sympy.assumptions.predicates.calculus.FinitePredicate :members: Infinite -------- .. autoclass:: sympy.assumptions.predicates.calculus.InfinitePredicate :members: Matrix ====== Symmetric --------- .. autoclass:: sympy.assumptions.predicates.matrices.SymmetricPredicate :members: Invertible ---------- .. autoclass:: sympy.assumptions.predicates.matrices.InvertiblePredicate :members: Orthogonal ---------- .. autoclass:: sympy.assumptions.predicates.matrices.OrthogonalPredicate :members: Unitary ------- .. autoclass:: sympy.assumptions.predicates.matrices.UnitaryPredicate :members: Positive Definite ----------------- .. autoclass:: sympy.assumptions.predicates.matrices.PositiveDefinitePredicate :members: Upper triangular ---------------- .. autoclass:: sympy.assumptions.predicates.matrices.UpperTriangularPredicate :members: Lower triangular ---------------- .. autoclass:: sympy.assumptions.predicates.matrices.LowerTriangularPredicate :members: Diagonal -------- .. autoclass:: sympy.assumptions.predicates.matrices.DiagonalPredicate :members: Full rank --------- .. autoclass:: sympy.assumptions.predicates.matrices.FullRankPredicate :members: Square ------ .. autoclass:: sympy.assumptions.predicates.matrices.SquarePredicate :members: Integer elements ---------------- .. autoclass:: sympy.assumptions.predicates.matrices.IntegerElementsPredicate :members: Real elements ------------- .. autoclass:: sympy.assumptions.predicates.matrices.RealElementsPredicate :members: Complex elements ---------------- .. autoclass:: sympy.assumptions.predicates.matrices.ComplexElementsPredicate :members: Singular -------- .. autoclass:: sympy.assumptions.predicates.matrices.SingularPredicate :members: Normal ------ .. autoclass:: sympy.assumptions.predicates.matrices.NormalPredicate :members: Triangular ---------- .. autoclass:: sympy.assumptions.predicates.matrices.TriangularPredicate :members: Unit triangular --------------- .. autoclass:: sympy.assumptions.predicates.matrices.UnitTriangularPredicate :members: Number Theory ============= Even ---- .. autoclass:: sympy.assumptions.predicates.ntheory.EvenPredicate :members: Odd --- .. autoclass:: sympy.assumptions.predicates.ntheory.OddPredicate :members: Prime ----- .. autoclass:: sympy.assumptions.predicates.ntheory.PrimePredicate :members: Composite --------- .. autoclass:: sympy.assumptions.predicates.ntheory.CompositePredicate :members: Order ===== Positive -------- ... autoclass:: sympy.assumptions.predicates.order.PositivePredicate :members: Negative -------- .. autoclass:: sympy.assumptions.predicates.order.NegativePredicate :members: Zero ---- .. autoclass:: sympy.assumptions.predicates.order.ZeroPredicate :members: Nonzero ------- .. autoclass:: sympy.assumptions.predicates.order.NonZeroPredicate :members: Nonpositive ----------- .. autoclass:: sympy.assumptions.predicates.order.NonPositivePredicate :members: Nonnegative ----------- .. autoclass:: sympy.assumptions.predicates.order.NonNegativePredicate :members: Sets ==== Integer ------- .. autoclass:: sympy.assumptions.predicates.sets.IntegerPredicate :members: Rational -------- .. autoclass:: sympy.assumptions.predicates.sets.RationalPredicate :members: Irrational ---------- .. autoclass:: sympy.assumptions.predicates.sets.IrrationalPredicate :members: Real ---- .. autoclass:: sympy.assumptions.predicates.sets.RealPredicate :members: Extended real ------------- .. autoclass:: sympy.assumptions.predicates.sets.ExtendedRealPredicate :members: Hermitian --------- .. autoclass:: sympy.assumptions.predicates.sets.HermitianPredicate :members: Complex ------- .. autoclass:: sympy.assumptions.predicates.sets.ComplexPredicate :members: Imaginary --------- .. autoclass:: sympy.assumptions.predicates.sets.ImaginaryPredicate :members: Antihermitian ------------- .. autoclass:: sympy.assumptions.predicates.sets.AntihermitianPredicate :members: Algebraic --------- .. autoclass:: sympy.assumptions.predicates.sets.AlgebraicPredicate :members: Transcendental -------------- .. autoclass:: sympy.assumptions.predicates.sets.TranscendentalPredicate :members: sympy-sympy-1.9/doc/src/modules/assumptions/refine.rst000066400000000000000000000001141412543434000233120ustar00rootroot00000000000000====== Refine ====== .. automodule:: sympy.assumptions.refine :members: sympy-sympy-1.9/doc/src/modules/calculus/000077500000000000000000000000001412543434000205425ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/calculus/index.rst000066400000000000000000000004521412543434000224040ustar00rootroot00000000000000======== Calculus ======== .. automodule:: sympy.calculus .. automodule:: sympy.calculus.euler :members: .. automodule:: sympy.calculus.singularities :members: .. _finite_diff: .. automodule:: sympy.calculus.finite_diff :members: .. automodule:: sympy.calculus.util :members: sympy-sympy-1.9/doc/src/modules/categories.rst000066400000000000000000000027331412543434000216130ustar00rootroot00000000000000=============== Category Theory =============== Introduction ------------ The category theory module for SymPy will allow manipulating diagrams within a single category, including drawing them in TikZ and deciding whether they are commutative or not. The general reference work this module tries to follow is .. [JoyOfCats] J. Adamek, H. Herrlich. G. E. Strecker: Abstract and Concrete Categories. The Joy of Cats. The latest version of this book should be available for free download from `katmat.math.uni-bremen.de/acc/acc.pdf `_ The module is still in its pre-embryonic stage. Base Class Reference -------------------- .. module:: sympy.categories This section lists the classes which implement some of the basic notions in category theory: objects, morphisms, categories, and diagrams. .. autoclass:: Object :members: .. autoclass:: Morphism :members: .. autoclass:: NamedMorphism :members: .. autoclass:: CompositeMorphism :members: .. autoclass:: IdentityMorphism :members: .. autoclass:: Category :members: .. autoclass:: Diagram :members: Diagram Drawing --------------- .. module:: sympy.categories.diagram_drawing This section lists the classes which allow automatic drawing of diagrams. .. autoclass:: DiagramGrid :members: .. autoclass:: ArrowStringDescription :members: .. autoclass:: XypicDiagramDrawer :members: .. autofunction:: xypic_draw_diagram .. autofunction:: preview_diagram sympy-sympy-1.9/doc/src/modules/codegen.rst000066400000000000000000000562751412543434000211040ustar00rootroot00000000000000.. _codegen_prose: =============== Code Generation =============== Several submodules in SymPy allow one to generate directly compilable and executable code in a variety of different programming languages from SymPy expressions. In addition, there are functions that generate Python importable objects that can evaluate SymPy expressions very efficiently. We will start with a brief introduction to the components that make up the code generation capabilities of SymPy. Introduction ------------ There are four main levels of abstractions:: expression | code printers | code generators | autowrap :mod:`sympy.utilities.autowrap` uses codegen, and codegen uses the code printers. :mod:`sympy.utilities.autowrap` does everything: it lets you go from SymPy expression to numerical function in the same Python process in one step. Codegen is actual code generation, i.e., to compile and use later, or to include in some larger project. The code printers translate the SymPy objects into actual code, like ``abs(x) -> fabs(x)`` (for C). The code printers don't print optimal code in many cases. An example of this is powers in C. ``x**2`` prints as ``pow(x, 2)`` instead of ``x*x``. Other optimizations (like mathematical simplifications) should happen before the code printers. Currently, :py:func:`sympy.simplify.cse_main.cse` is not applied automatically anywhere in this chain. It ideally happens at the codegen level, or somewhere above it. We will iterate through the levels below. The following three lines will be used to setup each example:: >>> from sympy import * >>> init_printing(use_unicode=True) >>> from sympy.abc import a, e, k, n, r, t, x, y, z, T, Z >>> from sympy.abc import beta, omega, tau >>> f, g = symbols('f, g', cls=Function) Code printers (sympy.printing) ------------------------------ This is where the meat of code generation is; the translation of SymPy actually more like a lightweight version of codegen for Python, and Python (:py:func:`sympy.printing.pycode.pycode`), and :py:func:`sympy.printing.lambdarepr.lambdarepr`, which supports many libraries (like NumPy), and Aesara (:py:func:`sympy.printing.aesaracode.aesara_function`). The code printers are special cases of the other prints in SymPy (str printer, pretty printer, etc.). An important distinction is that the code printer has to deal with assignments (using the :class:`sympy.codegen.ast.Assignment` object). This serves as building blocks for the code printers and hence the ``codegen`` module. An example that shows the use of ``Assignment`` in C code:: >>> from sympy.codegen.ast import Assignment >>> print(ccode(Assignment(x, y + 1))) x = y + 1; Here is another simple example of printing a C version of a SymPy expression:: >>> expr = (Rational(-1, 2) * Z * k * (e**2) / r) >>> expr 2 -Z⋅e ⋅k ──────── 2⋅r >>> ccode(expr) -1.0/2.0*Z*pow(e, 2)*k/r >>> from sympy.codegen.ast import real, float80 >>> ccode(expr, assign_to="E", type_aliases={real: float80}) E = -1.0L/2.0L*Z*powl(e, 2)*k/r; To generate code with some math functions provided by e.g. the C99 standard we need to import functions from :mod:`sympy.codegen.cfunctions`:: >>> from sympy.codegen.cfunctions import expm1 >>> ccode(expm1(x), standard='C99') expm1(x) ``Piecewise`` expressions are converted into conditionals. If an ``assign_to`` variable is provided an if statement is created, otherwise the ternary operator is used. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. A use case for ``Piecewise``:: >>> expr = Piecewise((x + 1, x > 0), (x, True)) >>> print(fcode(expr, tau)) if (x > 0) then tau = x + 1 else tau = x end if The various printers also tend to support ``Indexed`` objects well. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over:: >>> len_y = 5 >>> mat_1 = IndexedBase('mat_1', shape=(len_y,)) >>> mat_2 = IndexedBase('mat_2', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> eq = Eq(Dy[i], (mat_1[i+1] - mat_1[i]) / (mat_2[i+1] - mat_2[i])) >>> print(jscode(eq.rhs, assign_to=eq.lhs, contract=False)) Dy[i] = (mat_1[i + 1] - mat_1[i])/(mat_2[i + 1] - mat_2[i]); >>> Res = IndexedBase('Res', shape=(len_y,)) >>> j = Idx('j', len_y) >>> eq = Eq(Res[j], mat_1[j]*mat_2[j]) >>> print(jscode(eq.rhs, assign_to=eq.lhs, contract=True)) for (var j=0; j<5; j++){ Res[j] = 0; } for (var j=0; j<5; j++){ for (var j=0; j<5; j++){ Res[j] = Res[j] + mat_1[j]*mat_2[j]; } } >>> print(jscode(eq.rhs, assign_to=eq.lhs, contract=False)) Res[j] = mat_1[j]*mat_2[j]; Custom printing can be defined for certain types by passing a dictionary of "type" : "function" to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e., ``[(argument_test, cfunction_string)]``. This can be used to call a custom Octave function:: >>> custom_functions = { ... "f": "existing_octave_fcn", ... "g": [(lambda x: x.is_Matrix, "my_mat_fcn"), ... (lambda x: not x.is_Matrix, "my_fcn")] ... } >>> mat = Matrix([[1, x]]) >>> octave_code(f(x) + g(x) + g(mat), user_functions=custom_functions) existing_octave_fcn(x) + my_fcn(x) + my_mat_fcn([1 x]) An example of Mathematica code printer:: >>> x_ = Function('x') >>> expr = x_(n*T) * sin((t - n*T) / T) >>> expr = expr / ((-T*n + t) / T) >>> expr ⎛-T⋅n + t⎞ T⋅x(T⋅n)⋅sin⎜────────⎟ ⎝ T ⎠ ────────────────────── -T⋅n + t >>> expr = summation(expr, (n, -1, 1)) >>> mathematica_code(expr) T*(x[-T]*Sin[(T + t)/T]/(T + t) + x[T]*Sin[(-T + t)/T]/(-T + t) + x[0]*Sin[t/T ]/t) We can go through a common expression in different languages we support and see how it works:: >>> k, g1, g2, r, I, S = symbols("k, gamma_1, gamma_2, r, I, S") >>> expr = k * g1 * g2 / (r**3) >>> expr = expr * 2 * I * S * (3 * (cos(beta))**2 - 1) / 2 >>> expr ⎛ 2 ⎞ I⋅S⋅γ₁⋅γ₂⋅k⋅⎝3⋅cos (β) - 1⎠ ─────────────────────────── 3 r >>> print(jscode(expr, assign_to="H_is")) H_is = I*S*gamma_1*gamma_2*k*(3*Math.pow(Math.cos(beta), 2) - 1)/Math.pow(r, 3); >>> print(ccode(expr, assign_to="H_is", standard='C89')) H_is = I*S*gamma_1*gamma_2*k*(3*pow(cos(beta), 2) - 1)/pow(r, 3); >>> print(fcode(expr, assign_to="H_is")) H_is = I*S*gamma_1*gamma_2*k*(3*cos(beta)**2 - 1)/r**3 >>> print(julia_code(expr, assign_to="H_is")) H_is = I.*S.*gamma_1.*gamma_2.*k.*(3*cos(beta).^2 - 1)./r.^3 >>> print(octave_code(expr, assign_to="H_is")) H_is = I.*S.*gamma_1.*gamma_2.*k.*(3*cos(beta).^2 - 1)./r.^3; >>> print(rust_code(expr, assign_to="H_is")) H_is = I*S*gamma_1*gamma_2*k*(3*beta.cos().powi(2) - 1)/r.powi(3); >>> print(mathematica_code(expr)) I*S*gamma_1*gamma_2*k*(3*Cos[beta]^2 - 1)/r^3 Codegen (sympy.utilities.codegen) --------------------------------- This module deals with creating compilable code from SymPy expressions. This is lower level than autowrap, as it doesn't actually attempt to compile the code, but higher level than the printers, as it generates compilable files (including header files), rather than just code snippets. The user friendly functions, here, are ``codegen`` and ``make_routine``. ``codegen`` takes a list of ``(variable, expression)`` pairs and a language (C, F95, and Octave/Matlab are supported). It returns, as strings, a code file and a header file (for relevant languages). The variables are created as functions that return the value of the expression as output. .. note:: The ``codegen`` callable is not in the sympy namespace automatically, to use it you must first import ``codegen`` from ``sympy.utilities.codegen`` For instance:: >>> from sympy.utilities.codegen import codegen >>> length, breadth, height = symbols('length, breadth, height') >>> [(c_name, c_code), (h_name, c_header)] = \ ... codegen(('volume', length*breadth*height), "C99", "test", ... header=False, empty=False) >>> print(c_name) test.c >>> print(c_code) #include "test.h" #include double volume(double breadth, double height, double length) { double volume_result; volume_result = breadth*height*length; return volume_result; } >>> print(h_name) test.h >>> print(c_header) #ifndef PROJECT__TEST__H #define PROJECT__TEST__H double volume(double breadth, double height, double length); #endif Various flags to ``codegen`` let you modify things. The project name for preprocessor instructions can be varied using ``project``. Variables listed as global variables in arg ``global_vars`` will not show up as function arguments. ``language`` is a case-insensitive string that indicates the source code language. Currently, ``C``, ``F95`` and ``Octave`` are supported. ``Octave`` generates code compatible with both Octave and Matlab. ``header`` when True, a header is written on top of each source file. ``empty`` when True, empty lines are used to structure the code. With ``argument_sequence`` a sequence of arguments for the routine can be defined in a preferred order. ``prefix`` defines a prefix for the names of the files that contain the source code. If omitted, the name of the first name_expr tuple is used. ``to_files`` when True, the code will be written to one or more files with the given prefix. Here is an example:: >>> [(f_name, f_code), header] = codegen(("volume", length*breadth*height), ... "F95", header=False, empty=False, argument_sequence=(breadth, length), ... global_vars=(height,)) >>> print(f_code) REAL*8 function volume(breadth, length) implicit none REAL*8, intent(in) :: breadth REAL*8, intent(in) :: length volume = breadth*height*length end function The method ``make_routine`` creates a ``Routine`` object, which represents an evaluation routine for a set of expressions. This is only good for internal use by the CodeGen objects, as an intermediate representation from SymPy expression to generated code. It is not recommended to make a ``Routine`` object yourself. You should instead use ``make_routine`` method. ``make_routine`` in turn calls the ``routine`` method of the CodeGen object depending upon the language of choice. This creates the internal objects representing assignments and so on, and creates the ``Routine`` class with them. The various codegen objects such as ``Routine`` and ``Variable`` aren't SymPy objects (they don't subclass from Basic). For example:: >>> from sympy.utilities.codegen import make_routine >>> from sympy.physics.hydrogen import R_nl >>> expr = R_nl(3, y, x, 6) >>> routine = make_routine('my_routine', expr) >>> [arg.result_var for arg in routine.results] # doctest: +SKIP [result₅₁₄₂₃₄₁₆₈₁₃₉₇₇₁₉₄₂₈] >>> [arg.expr for arg in routine.results] ⎡ __________ ⎤ ⎢ y ╱ (2 - y)! -2⋅x ⎥ ⎢4⋅√6⋅(4⋅x) ⋅ ╱ ──────── ⋅ℯ ⋅assoc_laguerre(2 - y, 2⋅y + 1, 4⋅x)⎥ ⎢ ╲╱ (y + 3)! ⎥ ⎢────────────────────────────────────────────────────────────────────⎥ ⎣ 3 ⎦ >>> [arg.name for arg in routine.arguments] [x, y] Another more complicated example with a mixture of specified and automatically-assigned names. Also has Matrix output:: >>> routine = make_routine('fcn', [x*y, Eq(a, 1), Eq(r, x + r), Matrix([[x, 2]])]) >>> [arg.result_var for arg in routine.results] # doctest: +SKIP [result_5397460570204848505] >>> [arg.expr for arg in routine.results] [x⋅y] >>> [arg.name for arg in routine.arguments] # doctest: +SKIP [x, y, a, r, out_8598435338387848786] We can examine the various arguments more closely:: >>> from sympy.utilities.codegen import (InputArgument, OutputArgument, ... InOutArgument) >>> [a.name for a in routine.arguments if isinstance(a, InputArgument)] [x, y] >>> [a.name for a in routine.arguments if isinstance(a, OutputArgument)] # doctest: +SKIP [a, out_8598435338387848786] >>> [a.expr for a in routine.arguments if isinstance(a, OutputArgument)] [1, [x 2]] >>> [a.name for a in routine.arguments if isinstance(a, InOutArgument)] [r] >>> [a.expr for a in routine.arguments if isinstance(a, InOutArgument)] [r + x] The full API reference can be viewed :ref:`here`. Autowrap -------- Autowrap automatically generates code, writes it to disk, compiles it, and imports it into the current session. Main functions of this module are ``autowrap``, ``binary_function``, and ``ufuncify``. It also automatically converts expressions containing ``Indexed`` objects into summations. The classes IndexedBase, Indexed and Idx represent a matrix element M[i, j]. See :ref:`tensor_module` for more on this. .. _autowrap: ``autowrap`` creates a wrapper using f2py or Cython and creates a numerical function. .. note:: The ``autowrap`` callable is not in the sympy namespace automatically, to use it you must first import ``autowrap`` from ``sympy.utilities.autowrap`` The callable returned from autowrap() is a binary Python function, not a SymPy object. For example:: >>> from sympy.utilities.autowrap import autowrap >>> expr = ((x - y + z)**(13)).expand() >>> binary_func = autowrap(expr) # doctest: +SKIP >>> binary_func(1, 4, 2) # doctest: +SKIP -1.0 The various flags available with autowrap() help to modify the services provided by the method. The argument ``tempdir`` tells autowrap to compile the code in a specific directory, and leave the files intact when finished. For instance:: >>> from sympy.utilities.autowrap import autowrap >>> from sympy.physics.qho_1d import psi_n >>> x_ = IndexedBase('x') >>> y_ = IndexedBase('y') >>> m = symbols('m', integer=True) >>> i = Idx('i', m) >>> qho = autowrap(Eq(y_[i], psi_n(0, x_[i], m, omega)), tempdir='/tmp') # doctest: +SKIP Checking the Fortran source code in the directory specified reveals this:: subroutine autofunc(m, omega, x, y) implicit none INTEGER*4, intent(in) :: m REAL*8, intent(in) :: omega REAL*8, intent(in), dimension(1:m) :: x REAL*8, intent(out), dimension(1:m) :: y INTEGER*4 :: i REAL*8, parameter :: hbar = 1.05457162d-34 REAL*8, parameter :: pi = 3.14159265358979d0 do i = 1, m y(i) = (m*omega)**(1.0d0/4.0d0)*exp(-4.74126166983329d+33*m*omega*x(i & )**2)/(hbar**(1.0d0/4.0d0)*pi**(1.0d0/4.0d0)) end do end subroutine Using the argument ``args`` along with it changes argument sequence:: >>> eq = Eq(y_[i], psi_n(0, x_[i], m, omega)) >>> qho = autowrap(eq, tempdir='/tmp', args=[y, x, m, omega]) # doctest: +SKIP yields:: subroutine autofunc(y, x, m, omega) implicit none INTEGER*4, intent(in) :: m REAL*8, intent(in) :: omega REAL*8, intent(out), dimension(1:m) :: y REAL*8, intent(in), dimension(1:m) :: x INTEGER*4 :: i REAL*8, parameter :: hbar = 1.05457162d-34 REAL*8, parameter :: pi = 3.14159265358979d0 do i = 1, m y(i) = (m*omega)**(1.0d0/4.0d0)*exp(-4.74126166983329d+33*m*omega*x(i & )**2)/(hbar**(1.0d0/4.0d0)*pi**(1.0d0/4.0d0)) end do end subroutine The argument ``verbose`` is boolean, optional and if True, autowrap will not mute the command line backends. This can be helpful for debugging. The argument ``language`` and ``backend`` are used to change defaults: ``Fortran`` and ``f2py`` to ``C`` and ``Cython``. The argument helpers is used to define auxiliary expressions needed for the main expression. If the main expression needs to call a specialized function it should be put in the ``helpers`` iterable. Autowrap will then make sure that the compiled main expression can link to the helper routine. Items should be tuples with ``(, , )``. It is mandatory to supply an argument sequence to helper routines. .. _binary_function: Another method available at the ``autowrap`` level is ``binary_function``. It returns a sympy function. The advantage is that we can have very fast functions as compared to SymPy speeds. This is because we will be using compiled functions with Sympy attributes and methods. An illustration:: >>> from sympy.utilities.autowrap import binary_function >>> from sympy.physics.hydrogen import R_nl >>> psi_nl = R_nl(1, 0, a, r) >>> f = binary_function('f', psi_nl) # doctest: +SKIP >>> f(a, r).evalf(3, subs={a: 1, r: 2}) # doctest: +SKIP 0.766 .. _ufuncify_method: While NumPy operations are very efficient for vectorized data but they sometimes incur unnecessary costs when chained together. Consider the following operation >>> x = get_numpy_array(...) # doctest: +SKIP >>> y = sin(x) / x The operators ``sin`` and ``/`` call routines that execute tight for loops in ``C``. The resulting computation looks something like this .. code:: c for(int i = 0; i < n; i++) { temp[i] = sin(x[i]); } for(int i = i; i < n; i++) { y[i] = temp[i] / x[i]; } This is slightly sub-optimal because 1. We allocate an extra ``temp`` array 2. We walk over ``x`` memory twice when once would have been sufficient A better solution would fuse both element-wise operations into a single for loop .. code:: c for(int i = i; i < n; i++) { y[i] = sin(x[i]) / x[i]; } Statically compiled projects like NumPy are unable to take advantage of such optimizations. Fortunately, SymPy is able to generate efficient low-level C or Fortran code. It can then depend on projects like ``Cython`` or ``f2py`` to compile and reconnect that code back up to Python. Fortunately this process is well automated and a SymPy user wishing to make use of this code generation should call the ``ufuncify`` function. ``ufuncify`` is the third method available with Autowrap module. It basically implies 'Universal functions' and follows an ideology set by NumPy. The main point of ufuncify as compared to autowrap is that it allows arrays as arguments and can operate in an element-by-element fashion. The core operation done element-wise is in accordance to Numpy's array broadcasting rules. See `this `_ for more. >>> from sympy import * >>> from sympy.abc import x >>> expr = sin(x)/x >>> from sympy.utilities.autowrap import ufuncify >>> f = ufuncify([x], expr) # doctest: +SKIP This function ``f`` consumes and returns a NumPy array. Generally ``ufuncify`` performs at least as well as ``lambdify``. If the expression is complicated then ``ufuncify`` often significantly outperforms the NumPy backed solution. Jensen has a good `blog post `_ on this topic. Let us see an example for some quantitative analysis:: >>> from sympy.physics.hydrogen import R_nl >>> expr = R_nl(3, 1, x, 6) >>> expr -2⋅x 8⋅x⋅(4 - 4⋅x)⋅ℯ ─────────────────── 3 The lambdify function translates SymPy expressions into Python functions, leveraging a variety of numerical libraries. By default lambdify relies on implementations in the ``math`` standard library. Naturally, Raw Python is faster than SymPy. However it also supports ``mpmath`` and most notably, ``numpy``. Using the NumPy library gives the generated function access to powerful vectorized ufuncs that are backed by compiled C code. Let us compare the speeds:: >>> from sympy.utilities.autowrap import ufuncify >>> from sympy.utilities.lambdify import lambdify >>> fn_numpy = lambdify(x, expr, 'numpy') # doctest: +SKIP >>> fn_fortran = ufuncify([x], expr, backend='f2py') # doctest: +SKIP >>> from numpy import linspace # doctest: +SKIP >>> xx = linspace(0, 1, 5) # doctest: +SKIP >>> fn_numpy(xx) # doctest: +SKIP [ 0. 1.21306132 0.98101184 0.44626032 0. ] >>> fn_fortran(xx) # doctest: +SKIP [ 0. 1.21306132 0.98101184 0.44626032 0. ] >>> import timeit >>> timeit.timeit('fn_numpy(xx)', 'from __main__ import fn_numpy, xx', number=10000) # doctest: +SKIP 0.18891601900395472 >>> timeit.timeit('fn_fortran(xx)', 'from __main__ import fn_fortran, xx', number=10000) # doctest: +SKIP 0.004707066000264604 The options available with ufuncify are more or less the same as those available with ``autowrap``. There are other facilities available with SymPy to do efficient numeric computation. See :ref:`this` page for a comparison among them. Classes and functions for rewriting expressions (sympy.codegen.rewriting) ------------------------------------------------------------------------- .. automodule:: sympy.codegen.rewriting :members: .. automodule:: sympy.codegen.matrix_nodes :members: Tools for simplifying expressions using approximations (sympy.codegen.approximations) ------------------------------------------------------------------------------------- .. automodule:: sympy.codegen.approximations :members: Classes for abstract syntax trees (sympy.codegen.ast) ----------------------------------------------------- .. automodule:: sympy.codegen.ast :members: Special C math functions (sympy.codegen.cfunctions) --------------------------------------------------- .. automodule:: sympy.codegen.cfunctions :members: C specific AST nodes (sympy.codegen.cnodes) ------------------------------------------- .. automodule:: sympy.codegen.cnodes :members: C++ specific AST nodes (sympy.codegen.cxxnodes) ----------------------------------------------- .. automodule:: sympy.codegen.cxxnodes :members: Fortran specific AST nodes (sympy.codegen.fnodes) ------------------------------------------------- .. automodule:: sympy.codegen.fnodes :members: Algorithms (sympy.codegen.algorithms) ------------------------------------- .. automodule:: sympy.codegen.algorithms :members: Python utilities (sympy.codegen.pyutils) ---------------------------------------- .. automodule:: sympy.codegen.pyutils :members: C utilities (sympy.codegen.cutils) ---------------------------------- .. automodule:: sympy.codegen.cutils :members: Fortran utilities (sympy.codegen.futils) ---------------------------------------- .. automodule:: sympy.codegen.futils :members: sympy-sympy-1.9/doc/src/modules/combinatorics/000077500000000000000000000000001412543434000215635ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/combinatorics/fp_groups.rst000066400000000000000000000261201412543434000243220ustar00rootroot00000000000000Finitely Presented Groups ========================= Introduction ------------ This module presents the functionality designed for computing with finitely- presented groups (fp-groups for short). The name of the corresponding SymPy object is ``FpGroup``. The functions or classes described here are studied under **computational group theory**. All code examples assume: >>> from sympy.combinatorics.free_groups import free_group, vfree_group, xfree_group >>> from sympy.combinatorics.fp_groups import FpGroup, CosetTable, coset_enumeration_r Overview of Facilities `````````````````````` The facilities provided for fp-groups fall into a number of natural groupings * The construction of fp-groups using a free group and a list of words in generators of that free group. * Index determination using the famous Todd-Coxeter procedure. * The construction of all subgroups having index less than some (small) specified positive integer, using the *Low-Index Subgroups* algorithm. * Algorithms for computing presentations of a subgroup of finite index in a group defined by finite presentation. For a description of fundamental algorithms of finitely presented groups we often make use of *Handbook of Computational Group Theory*. The Construction of Finitely Presented Groups --------------------------------------------- Finitely presented groups are constructed by factoring a free group by a set of relators. The set of relators is taken in as a list of words in generators of free group in SymPy, using a list provides ordering to the relators. If the list of relators is empty, the associated free group is returned. Example of construction of a finitely-presented group. The symmetric group of degree 4 may be represented as a two generator group with presentation `\left\langle a, b \mid a^2, b^3, (ab)^4 \right\rangle`. Giving the relations as a list of relators, group in SymPy would be specified as: >>> F, a, b = free_group("a, b") >>> G = FpGroup(F, [a**2, b**3, (a*b)**4]) >>> G Currently groups with relators having presentation like `\left\langle r, s, t \mid r^2, s^2, t^2, rst = str = trs \right\rangle` will have to be specified as: >>> F, r, s, t = free_group("r, s, t") >>> G = FpGroup(F, [r**2, s**2, t**2, r*s*t*r**-1*t**-1*s**-1, s*t*r*s**-1*r**-1*t**-1]) Obviously this is not a unique way to make that particular group, but the point is that in case of equality with non-identity the user has to manually do that. Free Groups and Words --------------------- Construction of a Free Group ```````````````````````````` ``free_group("gen0, gen1, ..., gen_(n-1)")`` constructs a free group ``F`` on ``n`` generators, where ``n`` is a positive integer. The `i`-th generator of `F` may be obtained using the method ``.generators[i]``, `i = 0, \ldots n-1`. >>> F, x, y = free_group("x, y") creates a free group ``F`` of rank 2 and assigns the variables ``x`` and ``y`` to the two generators. >>> F = vfree_group("x, y") >>> F creates a free group ``F`` of rank 2, with tuple of generators ``F.generators``, and inserts ``x`` and ``y`` as generators into the global namespace. >>> F = xfree_group("x, y") >>> F (, (x, y)) >>> x**2 x**2 creates a free groups ``F[0]`` of rank 2, with tuple of generators ``F[1]``. Construction of words ````````````````````` This section is applicable to words of ``FreeGroup`` as well as ``FpGroup``. When we say *word* in SymPy, it actually means a `reduced word `_ , since the words are automatically reduced. Given a group ``G`` defined on `n` generators `x_1, x_2, x_3, \ldots, x_n`, a word is constructed as `s_1^{r_1}s_2^{r_2} \cdots s_k^{r_k}` where `s_i \in \{x_1, x_2, \ldots, x_n\}` , `r_i \in \mathbb{Z}` for all `k`. Each word can be constructed in a variety of ways, since after reduction they may be equivalent. Coset Enumeration: The Todd-Coxeter Algorithm --------------------------------------------- This section describes the use of coset enumeration techniques in SymPy. The algorithm used for coset enumeration procedure is Todd-Coxeter algorithm and is developed in Sympy using [Ho05] and [CDHW73]. The reader should consult [CDHW73] and [Hav91] for a general description of the algorithm. We have two strategies of coset enumeration *relator-based* and *coset-table based* and the two have been implemented as ``coset_enumeration_r``, ``coset_enumeration_c`` respectively. The two strategies differ in the way they make new definitions for the cosets. Though from the user point of view it is suggested to rather use the ``.coset_enumeration`` method of ``FpGroup`` and specify the ``strategy`` argument. ``strategy``: (default="relator_based") specifies the strategy of coset enumeration to be used, possible values are *"relator_based"* or *"coset_table_based"*. CosetTable `````````` Class used to manipulate the information regarding the coset enumeration of the finitely presented group ``G`` on the cosets of the subgroup ``H``. Basically a *coset table* ``CosetTable(G,H)``, is the permutation representation of the finitely presented group on the cosets of a subgroup. Most of the set theoretic and group functions use the regular representation of ``G``, i.e., the coset table of ``G`` over the trivial subgroup. The actual mathematical coset table is obtained using ``.table`` attribute and is a list of lists. For each generator ``g`` of ``G`` it contains a column and the next column corresponds to ``g**-1`` and so on for other generators, so in total it has ``2*G.rank()`` columns. Each column is simply a list of integers. If ``l`` is the generator list for the generator `g` and if ``l[i] = j`` then generator ``g`` takes the coset `i` to the coset `j` by multiplication from the right. For finitely presented groups, a coset table is computed by a Todd-Coxeter coset enumeration. Note that you may influence the performance of that enumeration by changing the values of the variable ``CosetTable.coset_table_max_limit``. Attributes of CosetTable ```````````````````````` For ``CosetTable(G, H)`` where ``G`` is the group and ``H`` is the subgroup. * ``n``: A non-negative integer, non-mutable attribute, dependently calculated as the maximum among the live-cosets (i.e. `\Omega`). * ``table``: A list of lists, mutable attribute, mathematically represents the coset table. * ``omega``: A list, dependent on the internal attribute ``p``. `\Omega` represents the list of live-cosets. A *standard* coset-table has its `\Omega = \{0, 1, \ldots, index-1 \}` where `index` is the index of subgroup `H` in `G`. For experienced users we have a number of parameters that can be used to manipulate the algorithm, like * ``coset_table_max_limit`` (default value = `4096000`): manipulate the maximum number of cosets allowed in coset enumeration, i.e. the number of rows allowed in coset table. A coset enumeration will not finish if the subgroup does not have finite index, and even if it has it may take many more intermediate cosets than the actual index of the subgroup is. To avoid a coset enumeration "running away" therefore SymPy has a "safety stop" built-in. This is controlled by this variable. To change it, use `max_cosets` keyword. For example: >>> F, a, b = free_group("a, b") >>> Cox = FpGroup(F, [a**6, b**6, (a*b)**2, (a**2*b**2)**2, (a**3*b**3)**5]) >>> C_r = coset_enumeration_r(Cox, [a], max_cosets=50) Traceback (most recent call last): ... ValueError: the coset enumeration has defined more than 50 cosets * ``max_stack_size`` (default value = `500`): manipulate the maximum size of ``deduction_stack`` above or equal to which the stack is emptied. Compression and Standardization ``````````````````````````````` For any two entries `i, j` with `i < j` in coset table, the first occurrence of `i` in a coset table precedes the first occurrence of `j` with respect to the usual row-wise ordering of the table entries. We call such a table a standard coset table. To standardize a ``CosetTable`` we use the ``.standardize`` method. **Note** the method alters the given table, it does not create a copy. Subgroups of Finite Index ------------------------- The functionality in this section are concerned with the construction of subgroups of finite index. We describe a method for computing all subgroups whose index does not exceed some (modest) integer bound. Low Index Subgroups ``````````````````` ``low_index_subgroups(G, N)``: Given a finitely presented group `G = \left\langle X \mid R \right\rangle` (can be a free group), and ``N`` a positive integer, determine the conjugacy classes of subgroups of ``G`` whose indices is less than or equal to ``N``. For example to find all subgroups of `G = \left\langle a, b \mid a^2 = b^3 = (ab)^4 = 1 \right\rangle` having index `\le` 4, can be found as follows: >>> from sympy.combinatorics.fp_groups import low_index_subgroups >>> F, a, b = free_group("a, b") >>> G = FpGroup(F, [a**2, b**3, (a*b)**4]) >>> l = low_index_subgroups(G, 4) >>> for coset_table in l: ... print(coset_table.table) ... [[0, 0, 0, 0]] [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 3, 3]] [[0, 0, 1, 2], [2, 2, 2, 0], [1, 1, 0, 1]] [[1, 1, 0, 0], [0, 0, 1, 1]] This returns the coset tables of subgroups of satisfying the property that index, `index`, of subgroup in group is `\le n`. Constructing a presentation for a subgroup ------------------------------------------ In this section we discuss finding the presentation of a subgroup in a finitely presentation group. While the *subgroup* is currently allowed as input only in the form of a list of generators for the subgroup, you can expect the functionality of a *coset table* as input for subgroup in the group in near future. There are two ways to construct a set of defining relations for subgroup from those of ``G``. First is on a set of Schreier generators, known generally as Reidemeister-Schreier algorithm or on the given list of generators of ``H``. Reidemeister Schreier algorithm ``````````````````````````````` called using ``reidemeister_presentation(G, Y)`` where ``G`` is the group and ``Y`` is a list of generators for subgroup ``H`` whose presentation we want to find. >>> from sympy.combinatorics.fp_groups import reidemeister_presentation >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**3, y**5, (x*y)**2]) >>> H = [x*y, x**-1*y**-1*x*y*x] >>> p1 = reidemeister_presentation(f, H) >>> p1 ((y_1, y_2), (y_1**2, y_2**3, y_2*y_1*y_2*y_1*y_2*y_1)) Bibliography ------------ .. [CDHW73] John J. Cannon, Lucien A. Dimino, George Havas, and Jane M. Watson. Implementation and analysis of the Todd-Coxeter algorithm. Math. Comp., 27:463– 490, 1973. .. [Ho05] Derek F. Holt, Handbook of Computational Group Theory. In the series 'Discrete Mathematics and its Applications', `Chapman & Hall/CRC 2005, xvi + 514 p `_. .. [Hav91] George Havas, Coset enumeration strategies. In Proceedings of the International Symposium on Symbolic and Algebraic Computation (ISSAC'91), Bonn 1991, pages 191--199. ACM Press, 1991. sympy-sympy-1.9/doc/src/modules/combinatorics/graycode.rst000066400000000000000000000006731412543434000241200ustar00rootroot00000000000000.. _combinatorics-graycode: Gray Code ========= .. module:: sympy.combinatorics.graycode .. autoclass:: GrayCode :members: .. automethod:: sympy.combinatorics.graycode.random_bitstring .. automethod:: sympy.combinatorics.graycode.gray_to_bin .. automethod:: sympy.combinatorics.graycode.bin_to_gray .. automethod:: sympy.combinatorics.graycode.get_subset_from_bitstring .. automethod:: sympy.combinatorics.graycode.graycode_subsets sympy-sympy-1.9/doc/src/modules/combinatorics/group_constructs.rst000066400000000000000000000002361412543434000257410ustar00rootroot00000000000000.. _combinatorics-group_constructs: Group constructors ================== .. module:: sympy.combinatorics.group_constructs .. autofunction:: DirectProduct sympy-sympy-1.9/doc/src/modules/combinatorics/index.rst000066400000000000000000000005521412543434000234260ustar00rootroot00000000000000.. _combinatiorics-docs: ============= Combinatorics ============= Contents ======== .. toctree:: :maxdepth: 2 partitions.rst permutations.rst perm_groups.rst polyhedron.rst prufer.rst subsets.rst graycode.rst named_groups.rst util.rst group_constructs.rst testutil.rst tensor_can.rst fp_groups.rst pc_groups.rst sympy-sympy-1.9/doc/src/modules/combinatorics/named_groups.rst000066400000000000000000000004171412543434000250020ustar00rootroot00000000000000.. _combinatorics-named_groups: Named Groups ============ .. module:: sympy.combinatorics.named_groups .. autofunction:: SymmetricGroup .. autofunction:: CyclicGroup .. autofunction:: DihedralGroup .. autofunction:: AlternatingGroup .. autofunction:: AbelianGroup sympy-sympy-1.9/doc/src/modules/combinatorics/partitions.rst000066400000000000000000000005331412543434000245120ustar00rootroot00000000000000.. _combinatorics-partitions: Partitions ========== .. module:: sympy.combinatorics.partitions .. autoclass:: Partition :members: .. autoclass:: IntegerPartition :members: .. autofunction:: random_integer_partition .. autofunction:: RGS_generalized .. autofunction:: RGS_enum .. autofunction:: RGS_unrank .. autofunction:: RGS_rank sympy-sympy-1.9/doc/src/modules/combinatorics/pc_groups.rst000066400000000000000000000226421412543434000243240ustar00rootroot00000000000000Polycyclic Groups ================= Introduction ------------ This module presents the functionality designed for computing with polycyclic groups(PcGroup for short). The name of the corresponding SymPy object is ``PolycyclicGroup``. The functions or classes described here are studied under **Computational Group Theory**. Overview of functionalities ``````````````````````````` * The construction of PolycyclicGroup from a given PermutationGroup. * Computation of polycyclic generating sequence(pcgs for short) and polycyclic series(pc_series). * Computation of relative order for polycyclic series. * Implementation of class Collector which can be treated as a base for polycylic groups. * Implementation of polycyclic group presentation(pc_presentation for short). * Computation of exponent vector, depth and leading exponent for a given element of a polycyclic group. For a description of fundamental algorithms of polycyclic groups, we often make use of *Handbook of Computational Group Theory*. The Construction of Polycyclic Groups ------------------------------------- Given a Permutation Group, A Polycyclic Group is constructed by computing the corresponding polycylic generating sequence, polycyclic series and it's relative order. Attributes of PolycyclicGroup ````````````````````````````` * ``pc_sequence`` : Polycyclic sequence is formed by collecting all the missing generators between the adjacent groups in the derived series of given permutation group. * ``pc_series`` : Polycyclic series is formed by adding all the missing generators of ``der[i+1]`` in ``der[i]``, where ``der`` represents derived series. * ``relative_order`` : A list, computed by the ratio of adjacent groups in pc_series. * ``collector`` : By default, it is None. Collector class provides the polycyclic presentation. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> len(PcGroup.pcgs) 4 >>> pc_series = PcGroup.pc_series >>> pc_series[0]==G True >>> gen = pc_series[len(pc_series)-1].generators[0] >>> gen.is_identity True >>> PcGroup.relative_order [2, 3, 2, 2] The Construction of Collector ----------------------------- Collector is one of the attributes of class PolycyclicGroup. Attributes of Collector ``````````````````````` Collector posses all the attributes of PolycyclicGroup, In addition there are few more attributes which are defined below: * ``free_group`` : free_group provides the mapping of polycyclic generating sequence with the free group elements. * ``pc_presentation`` : Provides the presentation of polycyclic groups with the help of power and conjugate relators. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(3) >>> PcGroup = G.polycyclic_group() >>> Collector = PcGroup.collector >>> Collector.free_group >>> Collector.pc_presentation {x0**2: (), x1**3: (), x0**-1*x1*x0: x1**2} Computation of Minimal Uncollected Subword `````````````````````````````````````````` A word ``V`` defined on generators in the free_group of pc_group is a minimal uncollected subword of the word ``W`` if ``V`` is a subword of ``W`` and it has one of the following form: * `v = {x_{i+1}}^{a_j}x_i` * `v = {x_{i+1}}^{a_j}{x_i}^{-1}` * `v = {x_i}^{a_j}` `a_j \notin \{0, \ldots \mathrm{relative\_order}[j]-1\}`. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.free_groups import free_group >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> F, x1, x2 = free_group("x1, x2") >>> word = x2**2*x1**7 >>> collector.minimal_uncollected_subword(word) ((x2, 2),) Computation of Subword Index ```````````````````````````` For a given word and it's subword, subword_index computes the starting and ending index of the subword in the word. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.free_groups import free_group >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> F, x1, x2 = free_group("x1, x2") >>> word = x2**2*x1**7 >>> w = x2**2*x1 >>> collector.subword_index(word, w) (0, 3) >>> w = x1**7 >>> collector.subword_index(word, w) (2, 9) Computation of Collected Word ````````````````````````````` A word ``W`` is called collected, if ``W`` `= {x_{i_1}}^{a_1} \ldots {x_{i_r}}^{a_r}` with `i_1 < i_2< \ldots < i_r` and `a_j` is in `\{1 \ldots s_{j-1}\}`, where `s_j` represents the respective relative order. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics.free_groups import free_group >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> F, x0, x1, x2, x3 = free_group("x0, x1, x2, x3") >>> word = x3*x2*x1*x0 >>> collected_word = collector.collected_word(word) >>> free_to_perm = {} >>> free_group = collector.free_group >>> for sym, gen in zip(free_group.symbols, collector.pcgs): ... free_to_perm[sym] = gen >>> G1 = PermutationGroup() >>> for w in word: ... sym = w[0] ... perm = free_to_perm[sym] ... G1 = PermutationGroup([perm] + G1.generators) >>> G2 = PermutationGroup() >>> for w in collected_word: ... sym = w[0] ... perm = free_to_perm[sym] ... G2 = PermutationGroup([perm] + G2.generators) >>> G1 == G2 True Computation of Polycyclic Presentation -------------------------------------- The computation of presentation starts from the bottom of the pcgs and polycyclic series. Storing all the previous generators from pcgs and then taking the last generator as the generator which acts as a conjugator and conjugates all the previous generators in the list. To get a clear picture, start with an example of SymmetricGroup(4). For S(4) there are 4 generators in pcgs say `[x_0, x_1, x_2, x_3]` and the relative_order vector is [2, 3, 2, 2]. Starting from bottom of this sequence the presentation is computed in order as below. using only `[x_3]` from ``pcgs`` and ``pc_series[4]`` compute: * `x_3^2` using only `[x_3]` from ``pcgs`` and ``pc_series[3]`` compute: * `x_2^2` * `x_2^{-1}x_3x_2` using `[x_3, x_2]` from ``pcgs`` and ``pc_series[2]`` compute: * `x_1^3` * `x_1^{-1}x_3x_1` * `x_1^{-1}x_2x_1` using `[x_3, x_2, x_1]` from ``pcgs`` and ``pc_series[1]`` compute: * `x_0^2` * `x_0^{-1}x_3x_0` * `x_0^{-1}x_2x_0` * `x_0^{-1}x_1x_0` One thing to note is same group can have different pcgs due to variying derived_series which, results in different polycyclic presentations. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.permutations import Permutation >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> pcgs = PcGroup.pcgs >>> len(pcgs) 4 >>> free_group = collector.free_group >>> pc_resentation = collector.pc_presentation >>> free_to_perm = {} >>> for s, g in zip(free_group.symbols, pcgs): ... free_to_perm[s] = g >>> for k, v in pc_resentation.items(): ... k_array = k.array_form ... if v != (): ... v_array = v.array_form ... lhs = Permutation() ... for gen in k_array: ... s = gen[0] ... e = gen[1] ... lhs = lhs*free_to_perm[s]**e ... if v == (): ... assert lhs.is_identity ... continue ... rhs = Permutation() ... for gen in v_array: ... s = gen[0] ... e = gen[1] ... rhs = rhs*free_to_perm[s]**e ... assert lhs == rhs Computation of Exponent Vector ------------------------------ Any generator of the polycyclic group can be represented with the help of it's polycyclic generating sequence. Hence, the length of exponent vector is equal to the length of the pcgs. A given generator ``g`` of the polycyclic group, can be represented as `g = x_1^{e_1} \ldots x_n^{e_n}`, where `x_i` represents polycyclic generators and ``n`` is the number of generators in the free_group equal to the length of pcgs. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.permutations import Permutation >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> pcgs = PcGroup.pcgs >>> collector.exponent_vector(G[0]) [1, 0, 0, 0] >>> exp = collector.exponent_vector(G[1]) >>> g = Permutation() >>> for i in range(len(exp)): ... g = g*pcgs[i]**exp[i] if exp[i] else g >>> assert g == G[1] Depth of Polycyclic generator ````````````````````````````` Depth of a given polycyclic generator is defined as the index of the first non-zero entry in the exponent vector. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(3) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> collector.depth(G[0]) 2 >>> collector.depth(G[1]) 1 Computation of Leading Exponent ``````````````````````````````` Leading exponent represents the exponent of polycyclic generator at the above depth. >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(3) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> collector.leading_exponent(G[1]) 1 Bibliography ------------ .. [Ho05] Derek F. Holt, Handbook of Computational Group Theory. In the series 'Discrete Mathematics and its Applications', `Chapman & Hall/CRC 2005, xvi + 514 p `_. sympy-sympy-1.9/doc/src/modules/combinatorics/perm_groups.rst000066400000000000000000000003131412543434000246540ustar00rootroot00000000000000.. _combinatorics-perm_groups: Permutation Groups ================== .. module:: sympy.combinatorics.perm_groups .. autoclass:: PermutationGroup :members: :private-members: :special-members: sympy-sympy-1.9/doc/src/modules/combinatorics/permutations.rst000066400000000000000000000010331412543434000250440ustar00rootroot00000000000000.. _combinatorics-permutations: Permutations ============ .. module:: sympy.combinatorics.permutations .. autoclass:: Permutation :members: .. autoclass:: Cycle :members: .. autofunction:: _af_parity .. _combinatorics-generators: Generators ---------- .. module:: sympy.combinatorics.generators .. automethod:: sympy.combinatorics.generators.symmetric .. automethod:: sympy.combinatorics.generators.cyclic .. automethod:: sympy.combinatorics.generators.alternating .. automethod:: sympy.combinatorics.generators.dihedral sympy-sympy-1.9/doc/src/modules/combinatorics/polyhedron.rst000066400000000000000000000002111412543434000244720ustar00rootroot00000000000000.. _combinatorics-polyhedron: Polyhedron ========== .. module:: sympy.combinatorics.polyhedron .. autoclass:: Polyhedron :members: sympy-sympy-1.9/doc/src/modules/combinatorics/prufer.rst000066400000000000000000000002111412543434000236120ustar00rootroot00000000000000.. _combinatorics-prufer: Prufer Sequences ================ .. module:: sympy.combinatorics.prufer .. autoclass:: Prufer :members: sympy-sympy-1.9/doc/src/modules/combinatorics/subsets.rst000066400000000000000000000002571412543434000240110ustar00rootroot00000000000000.. _combinatorics-subsets: Subsets ======= .. module:: sympy.combinatorics.subsets .. autoclass:: Subset :members: .. automethod:: sympy.combinatorics.subsets.ksubsets sympy-sympy-1.9/doc/src/modules/combinatorics/tensor_can.rst000066400000000000000000000004251412543434000244510ustar00rootroot00000000000000.. _combinatorics-tensor_can: Tensor Canonicalization ======================= .. module:: sympy.combinatorics.tensor_can .. autofunction:: canonicalize .. autofunction:: double_coset_can_rep .. autofunction:: get_symmetric_group_sgs .. autofunction:: bsgs_direct_product sympy-sympy-1.9/doc/src/modules/combinatorics/testutil.rst000066400000000000000000000004441412543434000241740ustar00rootroot00000000000000.. _combinatorics-testutil: Test Utilities ============== .. module:: sympy.combinatorics.testutil .. autofunction:: _cmp_perm_lists .. autofunction:: _naive_list_centralizer .. autofunction:: _verify_bsgs .. autofunction:: _verify_centralizer .. autofunction:: _verify_normal_closure sympy-sympy-1.9/doc/src/modules/combinatorics/util.rst000066400000000000000000000006201412543434000232700ustar00rootroot00000000000000.. _combinatorics-util: Utilities ============ .. module:: sympy.combinatorics.util .. autofunction:: _base_ordering .. autofunction:: _check_cycles_alt_sym .. autofunction:: _distribute_gens_by_base .. autofunction:: _handle_precomputed_bsgs .. autofunction:: _orbits_transversals_from_bsgs .. autofunction:: _remove_gens .. autofunction:: _strip .. autofunction:: _strong_gens_from_distr sympy-sympy-1.9/doc/src/modules/concrete.rst000066400000000000000000000057321412543434000212720ustar00rootroot00000000000000======== Concrete ======== Hypergeometric terms -------------------- The center stage, in recurrence solving and summations, play hypergeometric terms. Formally these are sequences annihilated by first order linear recurrence operators. In simple words if we are given term `a(n)` then it is hypergeometric if its consecutive term ratio is a rational function in `n`. To check if a sequence is of this type you can use the ``is_hypergeometric`` method which is available in Basic class. Here is simple example involving a polynomial: >>> from sympy import * >>> n, k = symbols('n,k') >>> (n**2 + 1).is_hypergeometric(n) True Of course polynomials are hypergeometric but are there any more complicated sequences of this type? Here are some trivial examples: >>> factorial(n).is_hypergeometric(n) True >>> binomial(n, k).is_hypergeometric(n) True >>> rf(n, k).is_hypergeometric(n) True >>> ff(n, k).is_hypergeometric(n) True >>> gamma(n).is_hypergeometric(n) True >>> (2**n).is_hypergeometric(n) True We see that all species used in summations and other parts of concrete mathematics are hypergeometric. Note also that binomial coefficients and both rising and falling factorials are hypergeometric in both their arguments: >>> binomial(n, k).is_hypergeometric(k) True >>> rf(n, k).is_hypergeometric(k) True >>> ff(n, k).is_hypergeometric(k) True To say more, all previously shown examples are valid for integer linear arguments: >>> factorial(2*n).is_hypergeometric(n) True >>> binomial(3*n+1, k).is_hypergeometric(n) True >>> rf(n+1, k-1).is_hypergeometric(n) True >>> ff(n-1, k+1).is_hypergeometric(n) True >>> gamma(5*n).is_hypergeometric(n) True >>> (2**(n-7)).is_hypergeometric(n) True However nonlinear arguments make those sequences fail to be hypergeometric: >>> factorial(n**2).is_hypergeometric(n) False >>> (2**(n**3 + 1)).is_hypergeometric(n) False If not only the knowledge of being hypergeometric or not is needed, you can use ``hypersimp()`` function. It will try to simplify combinatorial expression and if the term given is hypergeometric it will return a quotient of polynomials of minimal degree. Otherwise is will return `None` to say that sequence is not hypergeometric: >>> hypersimp(factorial(2*n), n) 2*(n + 1)*(2*n + 1) >>> hypersimp(factorial(n**2), n) Concrete Class Reference ------------------------ .. autoclass:: sympy.concrete.summations.Sum :members: .. autoclass:: sympy.concrete.products.Product :members: .. autoclass:: sympy.concrete.expr_with_intlimits.ExprWithIntLimits :members: Concrete Functions Reference ---------------------------- .. autofunction:: sympy.concrete.summations.summation .. autofunction:: sympy.concrete.products.product .. autofunction:: sympy.concrete.gosper.gosper_normal .. autofunction:: sympy.concrete.gosper.gosper_term .. autofunction:: sympy.concrete.gosper.gosper_sum sympy-sympy-1.9/doc/src/modules/core.rst000066400000000000000000000151701412543434000204150ustar00rootroot00000000000000==== Core ==== sympify ------- .. module:: sympy.core.sympify sympify ^^^^^^^ .. autofunction:: sympify assumptions ----------- .. automodule:: sympy.core.assumptions cache ----- .. module:: sympy.core.cache cacheit ^^^^^^^ .. autofunction:: __cacheit basic ----- .. module:: sympy.core.basic Basic ^^^^^ .. autoclass:: Basic :members: Atom ^^^^ .. autoclass:: Atom :members: core ---- .. module:: sympy.core.core singleton --------- .. module:: sympy.core.singleton S ^ .. autoclass:: sympy.core.singleton.SingletonRegistry :members: .. autoclass:: Singleton :members: expr ---- .. module:: sympy.core.expr Expr ^^^^ .. autoclass:: Expr :members: UnevaluatedExpr ^^^^^^^^^^^^^^^ .. autoclass:: UnevaluatedExpr :members: AtomicExpr ^^^^^^^^^^ .. autoclass:: AtomicExpr :members: symbol ------ .. module:: sympy.core.symbol Symbol ^^^^^^ .. autoclass:: Symbol :members: Wild ^^^^ .. autoclass:: Wild :members: Dummy ^^^^^ .. autoclass:: Dummy :members: symbols ^^^^^^^ .. autofunction:: symbols var ^^^ .. autofunction:: var numbers ------- .. module:: sympy.core.numbers Number ^^^^^^ .. autoclass:: Number :members: Float ^^^^^ .. autoclass:: Float :members: Rational ^^^^^^^^ .. autoclass:: Rational :members: Integer ^^^^^^^ .. autoclass:: Integer :members: NumberSymbol ^^^^^^^^^^^^ .. autoclass:: NumberSymbol :members: RealNumber ^^^^^^^^^^ .. autoclass:: RealNumber :members: igcd ^^^^ .. autofunction:: igcd ilcm ^^^^ .. autofunction:: ilcm seterr ^^^^^^ .. autofunction:: seterr Zero ^^^^ .. autoclass:: Zero :members: One ^^^ .. autoclass:: One :members: NegativeOne ^^^^^^^^^^^ .. autoclass:: NegativeOne :members: Half ^^^^ .. autoclass:: Half :members: NaN ^^^ .. autoclass:: NaN :members: Infinity ^^^^^^^^ .. autoclass:: Infinity :members: NegativeInfinity ^^^^^^^^^^^^^^^^ .. autoclass:: NegativeInfinity :members: ComplexInfinity ^^^^^^^^^^^^^^^ .. autoclass:: ComplexInfinity :members: Exp1 ^^^^ .. autoclass:: Exp1 :members: ImaginaryUnit ^^^^^^^^^^^^^ .. autoclass:: ImaginaryUnit :members: Pi ^^ .. autoclass:: Pi :members: EulerGamma ^^^^^^^^^^ .. autoclass:: EulerGamma :members: Catalan ^^^^^^^ .. autoclass:: Catalan :members: GoldenRatio ^^^^^^^^^^^ .. autoclass:: GoldenRatio :members: TribonacciConstant ^^^^^^^^^^^^^^^^^^ .. autoclass:: TribonacciConstant :members: mod_inverse ^^^^^^^^^^^ .. autofunction:: mod_inverse power ----- .. module:: sympy.core.power Pow ^^^ .. autoclass:: Pow :members: integer_nthroot ^^^^^^^^^^^^^^^ .. autofunction:: integer_nthroot integer_log ^^^^^^^^^^^ .. autofunction:: integer_log mul --- .. module:: sympy.core.mul Mul ^^^ .. autoclass:: Mul :members: prod ^^^^ .. autofunction:: prod add --- .. module:: sympy.core.add Add ^^^ .. autoclass:: Add :members: mod --- .. module:: sympy.core.mod Mod ^^^ .. autoclass:: Mod :members: relational ---------- .. module:: sympy.core.relational Rel ^^^ .. autoclass:: Relational :members: .. autoclass:: Rel :members: Eq ^^ .. autoclass:: Eq :members: Ne ^^ .. autoclass:: Ne :members: Lt ^^ .. autoclass:: Lt :members: Le ^^ .. autoclass:: Le :members: Gt ^^ .. autoclass:: Gt :members: Ge ^^ .. autoclass:: Ge :members: Equality ^^^^^^^^ .. autoclass:: Equality :members: GreaterThan ^^^^^^^^^^^ .. autoclass:: GreaterThan :members: LessThan ^^^^^^^^ .. autoclass:: LessThan :members: Unequality ^^^^^^^^^^ .. autoclass:: Unequality :members: StrictGreaterThan ^^^^^^^^^^^^^^^^^ .. autoclass:: StrictGreaterThan :members: StrictLessThan ^^^^^^^^^^^^^^ .. autoclass:: StrictLessThan :members: multidimensional ---------------- .. module:: sympy.core.multidimensional vectorize ^^^^^^^^^ .. autoclass:: vectorize :members: function -------- .. module:: sympy.core.function Lambda ^^^^^^ .. autoclass:: Lambda :members: WildFunction ^^^^^^^^^^^^ .. autoclass:: WildFunction :members: Derivative ^^^^^^^^^^ .. autoclass:: Derivative :members: :private-members: diff ^^^^ .. autofunction:: diff FunctionClass ^^^^^^^^^^^^^ .. autoclass:: FunctionClass :members: Function ^^^^^^^^ .. autoclass:: Function :members: .. note:: Not all functions are the same SymPy defines many functions (like ``cos`` and ``factorial``). It also allows the user to create generic functions which act as argument holders. Such functions are created just like symbols: >>> from sympy import Function, cos >>> from sympy.abc import x >>> f = Function('f') >>> f(2) + f(x) f(2) + f(x) If you want to see which functions appear in an expression you can use the atoms method: >>> e = (f(x) + cos(x) + 2) >>> e.atoms(Function) {f(x), cos(x)} If you just want the function you defined, not SymPy functions, the thing to search for is AppliedUndef: >>> from sympy.core.function import AppliedUndef >>> e.atoms(AppliedUndef) {f(x)} Subs ^^^^ .. autoclass:: Subs :members: expand ^^^^^^ .. autofunction:: expand PoleError ^^^^^^^^^ .. autoclass:: PoleError :members: count_ops ^^^^^^^^^ .. autofunction:: count_ops expand_mul ^^^^^^^^^^ .. autofunction:: expand_mul expand_log ^^^^^^^^^^ .. autofunction:: expand_log expand_func ^^^^^^^^^^^ .. autofunction:: expand_func expand_trig ^^^^^^^^^^^ .. autofunction:: expand_trig expand_complex ^^^^^^^^^^^^^^ .. autofunction:: expand_complex expand_multinomial ^^^^^^^^^^^^^^^^^^ .. autofunction:: expand_multinomial expand_power_exp ^^^^^^^^^^^^^^^^ .. autofunction:: expand_power_exp expand_power_base ^^^^^^^^^^^^^^^^^ .. autofunction:: expand_power_base nfloat ^^^^^^ .. autofunction:: nfloat evalf ----- .. module:: sympy.core.evalf EvalfMixin ^^^^^^^^^^ .. autoclass:: EvalfMixin :members: PrecisionExhausted ^^^^^^^^^^^^^^^^^^ .. autoclass:: PrecisionExhausted :members: N ^ .. autofunction:: N containers ---------- .. module:: sympy.core.containers Tuple ^^^^^ .. autoclass:: Tuple :members: Dict ^^^^ .. autoclass:: Dict :members: compatibility ------------- .. module:: sympy.core.compatibility iterable ^^^^^^^^ .. autofunction:: iterable is_sequence ^^^^^^^^^^^ .. autofunction:: is_sequence as_int ^^^^^^ .. autofunction:: as_int exprtools --------- .. module:: sympy.core.exprtools gcd_terms ^^^^^^^^^ .. autofunction:: gcd_terms factor_terms ^^^^^^^^^^^^ .. autofunction:: factor_terms ordered ^^^^^^^ .. autofunction:: sympy.core.compatibility.ordered kind ---- .. module:: sympy.core.kind Kind ^^^^ .. autoclass:: Kind :members: NumberKind ^^^^^^^^^^ .. autoclass:: NumberKind :members: BooleanKind ^^^^^^^^^^^ .. autoclass:: BooleanKind :members: sympy-sympy-1.9/doc/src/modules/crypto.rst000066400000000000000000000060161412543434000210040ustar00rootroot00000000000000============ Cryptography ============ .. warning:: This module is intended for educational purposes only. Do not use the functions in this module for real cryptographic applications. If you wish to encrypt real data, we recommend using something like the `cryptography `_ module. Encryption is the process of hiding a message and a cipher is a means of doing so. Included in this module are both block and stream ciphers: * Shift cipher * Affine cipher * substitution ciphers * Vigenere's cipher * Hill's cipher * Bifid ciphers * RSA * Kid RSA * linear-feedback shift registers (for stream ciphers) * ElGamal encryption In a *substitution cipher* "units" (not necessarily single characters) of plaintext are replaced with ciphertext according to a regular system. A *transposition cipher* is a method of encryption by which the positions held by "units" of plaintext are replaced by a permutation of the plaintext. That is, the order of the units is changed using a bijective function on the position of the characters to perform the encryption. A *monoalphabetic cipher* uses fixed substitution over the entire message, whereas a *polyalphabetic cipher* uses a number of substitutions at different times in the message. .. module:: sympy.crypto.crypto .. autofunction:: AZ .. autofunction:: padded_key .. autofunction:: check_and_join .. autofunction:: cycle_list .. autofunction:: encipher_shift .. autofunction:: decipher_shift .. autofunction:: encipher_rot13 .. autofunction:: decipher_rot13 .. autofunction:: encipher_affine .. autofunction:: decipher_affine .. autofunction:: encipher_atbash .. autofunction:: decipher_atbash .. autofunction:: encipher_substitution .. autofunction:: encipher_vigenere .. autofunction:: decipher_vigenere .. autofunction:: encipher_hill .. autofunction:: decipher_hill .. autofunction:: encipher_bifid .. autofunction:: decipher_bifid .. autofunction:: bifid5_square .. autofunction:: encipher_bifid5 .. autofunction:: decipher_bifid5 .. autofunction:: encipher_bifid6 .. autofunction:: decipher_bifid6 .. autofunction:: bifid6_square .. autofunction:: rsa_public_key .. autofunction:: rsa_private_key .. autofunction:: encipher_rsa .. autofunction:: decipher_rsa .. autofunction:: kid_rsa_public_key .. autofunction:: kid_rsa_private_key .. autofunction:: encipher_kid_rsa .. autofunction:: decipher_kid_rsa .. autofunction:: encode_morse .. autofunction:: decode_morse .. autofunction:: lfsr_sequence .. autofunction:: lfsr_autocorrelation .. autofunction:: lfsr_connection_polynomial .. autofunction:: elgamal_public_key .. autofunction:: elgamal_private_key .. autofunction:: encipher_elgamal .. autofunction:: decipher_elgamal .. autofunction:: dh_public_key .. autofunction:: dh_private_key .. autofunction:: dh_shared_key .. autofunction:: gm_public_key .. autofunction:: gm_private_key .. autofunction:: encipher_gm .. autofunction:: decipher_gm .. autofunction:: encipher_railfence .. autofunction:: decipher_railfence sympy-sympy-1.9/doc/src/modules/diffgeom.rst000066400000000000000000000020741412543434000212440ustar00rootroot00000000000000===================== Differential Geometry ===================== .. module:: sympy.diffgeom Introduction ------------ Base Class Reference -------------------- .. autoclass:: Manifold :members: .. autoclass:: Patch :members: .. autoclass:: CoordSystem :members: .. autoclass:: CoordinateSymbol :members: .. autoclass:: Point :members: .. autoclass:: BaseScalarField :members: .. autoclass:: BaseVectorField :members: .. autoclass:: Commutator :members: .. autoclass:: Differential :members: .. autoclass:: TensorProduct :members: .. autoclass:: WedgeProduct :members: .. autoclass:: LieDerivative :members: .. autoclass:: BaseCovarDerivativeOp :members: .. autoclass:: CovarDerivativeOp :members: .. autofunction:: intcurve_series .. autofunction:: intcurve_diffequ .. autofunction:: vectors_in_basis .. autofunction:: twoform_to_matrix .. autofunction:: metric_to_Christoffel_1st .. autofunction:: metric_to_Christoffel_2nd .. autofunction:: metric_to_Riemann_components .. autofunction:: metric_to_Ricci_components sympy-sympy-1.9/doc/src/modules/discrete.rst000066400000000000000000000037711412543434000212730ustar00rootroot00000000000000======== Discrete ======== The ``discrete`` module in SymPy implements methods to compute discrete transforms and convolutions of finite sequences. .. automodule:: sympy.discrete Since the discrete transforms can be used to reduce the computational complexity of the discrete convolutions, the ``convolutions`` module makes use of the ``transforms`` module for efficient computation (notable for long input sequences). Transforms ---------- .. module:: sympy.discrete.transforms This section lists the methods which implement the basic transforms for discrete sequences. Fast Fourier Transform ^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: fft .. autofunction:: ifft Number Theoretic Transform ^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: ntt .. autofunction:: intt Fast Walsh Hadamard Transform ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: fwht .. autofunction:: ifwht Möbius Transform ^^^^^^^^^^^^^^^^ .. autofunction:: mobius_transform .. autofunction:: inverse_mobius_transform Convolutions ------------ .. module:: sympy.discrete.convolutions This section lists the methods which implement the basic convolutions for discrete sequences. Convolution ^^^^^^^^^^^ This is a general method for calculating the convolution of discrete sequences, which internally calls one of the methods ``convolution_fft``, ``convolution_ntt``, ``convolution_fwht``, or ``convolution_subset``. .. autofunction:: convolution Convolution using Fast Fourier Transform ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: convolution_fft Convolution using Number Theoretic Transform ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: convolution_ntt Convolution using Fast Walsh Hadamard Transform ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: convolution_fwht Subset Convolution ^^^^^^^^^^^^^^^^^^ .. autofunction:: convolution_subset Covering Product ^^^^^^^^^^^^^^^^ .. autofunction:: covering_product Intersecting Product ^^^^^^^^^^^^^^^^^^^^ .. autofunction:: intersecting_product sympy-sympy-1.9/doc/src/modules/evalf.rst000066400000000000000000000325711412543434000205660ustar00rootroot00000000000000.. _evalf-label: ==================== Numerical Evaluation ==================== Basics ------ Exact SymPy expressions can be converted to floating-point approximations (decimal numbers) using either the ``.evalf()`` method or the ``N()`` function. ``N(expr, )`` is equivalent to ``sympify(expr).evalf()``. >>> from sympy import * >>> N(sqrt(2)*pi) 4.44288293815837 >>> (sqrt(2)*pi).evalf() 4.44288293815837 By default, numerical evaluation is performed to an accuracy of 15 decimal digits. You can optionally pass a desired accuracy (which should be a positive integer) as an argument to ``evalf`` or ``N``: >>> N(sqrt(2)*pi, 5) 4.4429 >>> N(sqrt(2)*pi, 50) 4.4428829381583662470158809900606936986146216893757 Complex numbers are supported: >>> N(1/(pi + I), 20) 0.28902548222223624241 - 0.091999668350375232456*I If the expression contains symbols or for some other reason cannot be evaluated numerically, calling ``.evalf()`` or ``N()`` returns the original expression, or in some cases a partially evaluated expression. For example, when the expression is a polynomial in expanded form, the coefficients are evaluated: >>> x = Symbol('x') >>> (pi*x**2 + x/3).evalf() 3.14159265358979*x**2 + 0.333333333333333*x You can also use the standard Python functions ``float()``, ``complex()`` to convert SymPy expressions to regular Python numbers: >>> float(pi) 3.1415926535... >>> complex(pi+E*I) (3.1415926535...+2.7182818284...j) If these functions are used, failure to evaluate the expression to an explicit number (for example if the expression contains symbols) will raise an exception. There is essentially no upper precision limit. The following command, for example, computes the first 100,000 digits of π/e: >>> N(pi/E, 100000) #doctest: +SKIP ... This shows digits 999,951 through 1,000,000 of pi: >>> str(N(pi, 10**6))[-50:] #doctest: +SKIP '95678796130331164628399634646042209010610577945815' High-precision calculations can be slow. It is recommended (but entirely optional) to install gmpy (https://code.google.com/p/gmpy/), which will significantly speed up computations such as the one above. Floating-point numbers ---------------------- Floating-point numbers in SymPy are instances of the class ``Float``. A ``Float`` can be created with a custom precision as second argument: >>> Float(0.1) 0.100000000000000 >>> Float(0.1, 10) 0.1000000000 >>> Float(0.125, 30) 0.125000000000000000000000000000 >>> Float(0.1, 30) 0.100000000000000005551115123126 As the last example shows, some Python floats are only accurate to about 15 digits as inputs, while others (those that have a denominator that is a power of 2, like 0.125 = 1/8) are exact. To create a ``Float`` from a high-precision decimal number, it is better to pass a string, ``Rational``, or ``evalf`` a ``Rational``: >>> Float('0.1', 30) 0.100000000000000000000000000000 >>> Float(Rational(1, 10), 30) 0.100000000000000000000000000000 >>> Rational(1, 10).evalf(30) 0.100000000000000000000000000000 The precision of a number determines 1) the precision to use when performing arithmetic with the number, and 2) the number of digits to display when printing the number. When two numbers with different precision are used together in an arithmetic operation, the higher of the precisions is used for the result. The product of 0.1 +/- 0.001 and 3.1415 +/- 0.0001 has an uncertainty of about 0.003 and yet 5 digits of precision are shown. >>> Float(0.1, 3)*Float(3.1415, 5) 0.31417 So the displayed precision should not be used as a model of error propagation or significance arithmetic; rather, this scheme is employed to ensure stability of numerical algorithms. ``N`` and ``evalf`` can be used to change the precision of existing floating-point numbers: >>> N(3.5) 3.50000000000000 >>> N(3.5, 5) 3.5000 >>> N(3.5, 30) 3.50000000000000000000000000000 Accuracy and error handling --------------------------- When the input to ``N`` or ``evalf`` is a complicated expression, numerical error propagation becomes a concern. As an example, consider the 100'th Fibonacci number and the excellent (but not exact) approximation `\varphi^{100} / \sqrt{5}` where `\varphi` is the golden ratio. With ordinary floating-point arithmetic, subtracting these numbers from each other erroneously results in a complete cancellation: >>> a, b = GoldenRatio**1000/sqrt(5), fibonacci(1000) >>> float(a) 4.34665576869e+208 >>> float(b) 4.34665576869e+208 >>> float(a) - float(b) 0.0 ``N`` and ``evalf`` keep track of errors and automatically increase the precision used internally in order to obtain a correct result: >>> N(fibonacci(100) - GoldenRatio**100/sqrt(5)) -5.64613129282185e-22 Unfortunately, numerical evaluation cannot tell an expression that is exactly zero apart from one that is merely very small. The working precision is therefore capped, by default to around 100 digits. If we try with the 1000'th Fibonacci number, the following happens: >>> N(fibonacci(1000) - (GoldenRatio)**1000/sqrt(5)) 0.e+85 The lack of digits in the returned number indicates that ``N`` failed to achieve full accuracy. The result indicates that the magnitude of the expression is something less than 10^84, but that is not a particularly good answer. To force a higher working precision, the ``maxn`` keyword argument can be used: >>> N(fibonacci(1000) - (GoldenRatio)**1000/sqrt(5), maxn=500) -4.60123853010113e-210 Normally, ``maxn`` can be set very high (thousands of digits), but be aware that this may cause significant slowdown in extreme cases. Alternatively, the ``strict=True`` option can be set to force an exception instead of silently returning a value with less than the requested accuracy: >>> N(fibonacci(1000) - (GoldenRatio)**1000/sqrt(5), strict=True) Traceback (most recent call last): ... PrecisionExhausted: Failed to distinguish the expression: -sqrt(5)*GoldenRatio**1000/5 + 43466557686937456435688527675040625802564660517371780402481729089536555417949051890403879840079255169295922593080322634775209689623239873322471161642996440906533187938298969649928516003704476137795166849228875 from zero. Try simplifying the input, using chop=True, or providing a higher maxn for evalf If we add a term so that the Fibonacci approximation becomes exact (the full form of Binet's formula), we get an expression that is exactly zero, but ``N`` does not know this: >>> f = fibonacci(100) - (GoldenRatio**100 - (GoldenRatio-1)**100)/sqrt(5) >>> N(f) 0.e-104 >>> N(f, maxn=1000) 0.e-1336 In situations where such cancellations are known to occur, the ``chop`` options is useful. This basically replaces very small numbers in the real or imaginary portions of a number with exact zeros: >>> N(f, chop=True) 0 >>> N(3 + I*f, chop=True) 3.00000000000000 In situations where you wish to remove meaningless digits, re-evaluation or the use of the ``round`` method are useful: >>> Float('.1', '')*Float('.12345', '') 0.012297 >>> ans = _ >>> N(ans, 1) 0.01 >>> ans.round(2) 0.01 If you are dealing with a numeric expression that contains no floats, it can be evaluated to arbitrary precision. To round the result relative to a given decimal, the round method is useful: >>> v = 10*pi + cos(1) >>> N(v) 31.9562288417661 >>> v.round(3) 31.956 Sums and integrals ------------------ Sums (in particular, infinite series) and integrals can be used like regular closed-form expressions, and support arbitrary-precision evaluation: >>> var('n x') (n, x) >>> Sum(1/n**n, (n, 1, oo)).evalf() 1.29128599706266 >>> Integral(x**(-x), (x, 0, 1)).evalf() 1.29128599706266 >>> Sum(1/n**n, (n, 1, oo)).evalf(50) 1.2912859970626635404072825905956005414986193682745 >>> Integral(x**(-x), (x, 0, 1)).evalf(50) 1.2912859970626635404072825905956005414986193682745 >>> (Integral(exp(-x**2), (x, -oo, oo)) ** 2).evalf(30) 3.14159265358979323846264338328 By default, the tanh-sinh quadrature algorithm is used to evaluate integrals. This algorithm is very efficient and robust for smooth integrands (and even integrals with endpoint singularities), but may struggle with integrals that are highly oscillatory or have mid-interval discontinuities. In many cases, ``evalf``/``N`` will correctly estimate the error. With the following integral, the result is accurate but only good to four digits: >>> f = abs(sin(x)) >>> Integral(abs(sin(x)), (x, 0, 4)).evalf() 2.346 It is better to split this integral into two pieces: >>> (Integral(f, (x, 0, pi)) + Integral(f, (x, pi, 4))).evalf() 2.34635637913639 A similar example is the following oscillatory integral: >>> Integral(sin(x)/x**2, (x, 1, oo)).evalf(maxn=20) 0.5 It can be dealt with much more efficiently by telling ``evalf`` or ``N`` to use an oscillatory quadrature algorithm: >>> Integral(sin(x)/x**2, (x, 1, oo)).evalf(quad='osc') 0.504067061906928 >>> Integral(sin(x)/x**2, (x, 1, oo)).evalf(20, quad='osc') 0.50406706190692837199 Oscillatory quadrature requires an integrand containing a factor cos(ax+b) or sin(ax+b). Note that many other oscillatory integrals can be transformed to this form with a change of variables: >>> init_printing(use_unicode=False, wrap_line=False) >>> intgrl = Integral(sin(1/x), (x, 0, 1)).transform(x, 1/x) >>> intgrl oo / | | sin(x) | ------ dx | 2 | x | / 1 >>> N(intgrl, quad='osc') 0.504067061906928 Infinite series use direct summation if the series converges quickly enough. Otherwise, extrapolation methods (generally the Euler-Maclaurin formula but also Richardson extrapolation) are used to speed up convergence. This allows high-precision evaluation of slowly convergent series: >>> var('k') k >>> Sum(1/k**2, (k, 1, oo)).evalf() 1.64493406684823 >>> zeta(2).evalf() 1.64493406684823 >>> Sum(1/k-log(1+1/k), (k, 1, oo)).evalf() 0.577215664901533 >>> Sum(1/k-log(1+1/k), (k, 1, oo)).evalf(50) 0.57721566490153286060651209008240243104215933593992 >>> EulerGamma.evalf(50) 0.57721566490153286060651209008240243104215933593992 The Euler-Maclaurin formula is also used for finite series, allowing them to be approximated quickly without evaluating all terms: >>> Sum(1/k, (k, 10000000, 20000000)).evalf() 0.693147255559946 Note that ``evalf`` makes some assumptions that are not always optimal. For fine-tuned control over numerical summation, it might be worthwhile to manually use the method ``Sum.euler_maclaurin``. Special optimizations are used for rational hypergeometric series (where the term is a product of polynomials, powers, factorials, binomial coefficients and the like). ``N``/``evalf`` sum series of this type very rapidly to high precision. For example, this Ramanujan formula for pi can be summed to 10,000 digits in a fraction of a second with a simple command: >>> f = factorial >>> n = Symbol('n', integer=True) >>> R = 9801/sqrt(8)/Sum(f(4*n)*(1103+26390*n)/f(n)**4/396**(4*n), ... (n, 0, oo)) #doctest: +SKIP >>> N(R, 10000) #doctest: +SKIP 3.141592653589793238462643383279502884197169399375105820974944592307816406286208 99862803482534211706798214808651328230664709384460955058223172535940812848111745 02841027019385211055596446229489549303819644288109756659334461284756482337867831 ... Numerical simplification ------------------------ The function ``nsimplify`` attempts to find a formula that is numerically equal to the given input. This feature can be used to guess an exact formula for an approximate floating-point input, or to guess a simpler formula for a complicated symbolic input. The algorithm used by ``nsimplify`` is capable of identifying simple fractions, simple algebraic expressions, linear combinations of given constants, and certain elementary functional transformations of any of the preceding. Optionally, ``nsimplify`` can be passed a list of constants to include (e.g. pi) and a minimum numerical tolerance. Here are some elementary examples: >>> nsimplify(0.1) 1/10 >>> nsimplify(6.28, [pi], tolerance=0.01) 2*pi >>> nsimplify(pi, tolerance=0.01) 22/7 >>> nsimplify(pi, tolerance=0.001) 355 --- 113 >>> nsimplify(0.33333, tolerance=1e-4) 1/3 >>> nsimplify(2.0**(1/3.), tolerance=0.001) 635 --- 504 >>> nsimplify(2.0**(1/3.), tolerance=0.001, full=True) 3 ___ \/ 2 Here are several more advanced examples: >>> nsimplify(Float('0.130198866629986772369127970337',30), [pi, E]) 1 ---------- 5*pi ---- + 2*e 7 >>> nsimplify(cos(atan('1/3'))) ____ 3*\/ 10 -------- 10 >>> nsimplify(4/(1+sqrt(5)), [GoldenRatio]) -2 + 2*GoldenRatio >>> nsimplify(2 + exp(2*atan('1/4')*I)) 49 8*I -- + --- 17 17 >>> nsimplify((1/(exp(3*pi*I/5)+1))) ___________ / ___ 1 / \/ 5 1 - - I* / ----- + - 2 \/ 10 4 >>> nsimplify(I**I, [pi]) -pi ---- 2 e >>> n = Symbol('n') >>> nsimplify(Sum(1/n**2, (n, 1, oo)), [pi]) 2 pi --- 6 >>> nsimplify(gamma('1/4')*gamma('3/4'), [pi]) ___ \/ 2 *pi sympy-sympy-1.9/doc/src/modules/functions/000077500000000000000000000000001412543434000207375ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/functions/combinatorial.rst000066400000000000000000000055271412543434000243250ustar00rootroot00000000000000Combinatorial ============= This module implements various combinatorial functions. bell ---- .. autoclass:: sympy.functions.combinatorial.numbers.bell :members: bernoulli --------- .. autoclass:: sympy.functions.combinatorial.numbers.bernoulli :members: binomial -------- .. autoclass:: sympy.functions.combinatorial.factorials.binomial :members: catalan ------- .. autoclass:: sympy.functions.combinatorial.numbers.catalan :members: euler ----- .. autoclass:: sympy.functions.combinatorial.numbers.euler :members: factorial --------- .. autoclass:: sympy.functions.combinatorial.factorials.factorial :members: subfactorial ------------ .. autoclass:: sympy.functions.combinatorial.factorials.subfactorial :members: factorial2 / double factorial ----------------------------- .. autoclass:: sympy.functions.combinatorial.factorials.factorial2 :members: FallingFactorial ---------------- .. autoclass:: sympy.functions.combinatorial.factorials.FallingFactorial :members: fibonacci --------- .. autoclass:: sympy.functions.combinatorial.numbers.fibonacci :members: tribonacci ---------- .. autoclass:: sympy.functions.combinatorial.numbers.tribonacci :members: harmonic -------- .. autoclass:: sympy.functions.combinatorial.numbers.harmonic :members: lucas ----- .. autoclass:: sympy.functions.combinatorial.numbers.lucas :members: genocchi -------- .. autoclass:: sympy.functions.combinatorial.numbers.genocchi :members: partition --------- .. autoclass:: sympy.functions.combinatorial.numbers.partition :members: MultiFactorial -------------- .. autoclass:: sympy.functions.combinatorial.factorials.MultiFactorial :members: RisingFactorial --------------- .. autoclass:: sympy.functions.combinatorial.factorials.RisingFactorial :members: stirling -------- .. autofunction:: sympy.functions.combinatorial.numbers.stirling Enumeration =========== Three functions are available. Each of them attempts to efficiently compute a given combinatorial quantity for a given set or multiset which can be entered as an integer, sequence or multiset (dictionary with elements as keys and multiplicities as values). The ``k`` parameter indicates the number of elements to pick (or the number of partitions to make). When ``k`` is None, the sum of the enumeration for all ``k`` (from 0 through the number of items represented by ``n``) is returned. A ``replacement`` parameter is recognized for combinations and permutations; this indicates that any item may appear with multiplicity as high as the number of items in the original set. >>> from sympy.functions.combinatorial.numbers import nC, nP, nT >>> items = 'baby' nC -- .. autofunction:: sympy.functions.combinatorial.numbers.nC nP -- .. autofunction:: sympy.functions.combinatorial.numbers.nP nT -- .. autofunction:: sympy.functions.combinatorial.numbers.nT sympy-sympy-1.9/doc/src/modules/functions/elementary.rst000066400000000000000000000132271412543434000236430ustar00rootroot00000000000000Elementary ========== This module implements elementary functions such as trigonometric, hyperbolic, and sqrt, as well as functions like ``Abs``, ``Max``, ``Min`` etc. sympy.functions.elementary.complexes ==================================== re -- .. autoclass:: sympy.functions.elementary.complexes.re :members: im -- .. autoclass:: sympy.functions.elementary.complexes.im :members: sign ---- .. autoclass:: sympy.functions.elementary.complexes.sign :members: Abs --- .. autoclass:: sympy.functions.elementary.complexes.Abs :members: arg --- .. autoclass:: sympy.functions.elementary.complexes.arg :members: conjugate --------- .. autoclass:: sympy.functions.elementary.complexes.conjugate :members: polar_lift ---------- .. autoclass:: sympy.functions.elementary.complexes.polar_lift :members: periodic_argument ----------------- .. autoclass:: sympy.functions.elementary.complexes.periodic_argument :members: principal_branch ----------------- .. autoclass:: sympy.functions.elementary.complexes.principal_branch :members: sympy.functions.elementary.trigonometric ======================================== .. _trionometric functions: Trigonometric Functions ======================== sin --- .. autoclass:: sympy.functions.elementary.trigonometric.sin :members: cos --- .. autoclass:: sympy.functions.elementary.trigonometric.cos :members: tan --- .. autoclass:: sympy.functions.elementary.trigonometric.tan :members: cot --- .. autoclass:: sympy.functions.elementary.trigonometric.cot :members: sec --- .. autoclass:: sympy.functions.elementary.trigonometric.sec :members: csc --- .. autoclass:: sympy.functions.elementary.trigonometric.csc :members: sinc ---- .. autoclass:: sympy.functions.elementary.trigonometric.sinc :members: Trigonometric Inverses ====================== asin ---- .. autoclass:: sympy.functions.elementary.trigonometric.asin :members: acos ---- .. autoclass:: sympy.functions.elementary.trigonometric.acos :members: atan ---- .. autoclass:: sympy.functions.elementary.trigonometric.atan :members: acot ---- .. autoclass:: sympy.functions.elementary.trigonometric.acot :members: asec ---- .. autoclass:: sympy.functions.elementary.trigonometric.asec :members: acsc ---- .. autoclass:: sympy.functions.elementary.trigonometric.acsc :members: atan2 ----- .. autoclass:: sympy.functions.elementary.trigonometric.atan2 :members: sympy.functions.elementary.hyperbolic ====================================== Hyperbolic Functions ==================== HyperbolicFunction ------------------ .. autoclass:: sympy.functions.elementary.hyperbolic.HyperbolicFunction :members: sinh ---- .. autoclass:: sympy.functions.elementary.hyperbolic.sinh :members: cosh ---- .. autoclass:: sympy.functions.elementary.hyperbolic.cosh :members: tanh ---- .. autoclass:: sympy.functions.elementary.hyperbolic.tanh :members: coth ---- .. autoclass:: sympy.functions.elementary.hyperbolic.coth :members: sech ---- .. autoclass:: sympy.functions.elementary.hyperbolic.sech :members: csch ---- .. autoclass:: sympy.functions.elementary.hyperbolic.csch :members: Hyperbolic Inverses =================== asinh ----- .. autoclass:: sympy.functions.elementary.hyperbolic.asinh :members: acosh ----- .. autoclass:: sympy.functions.elementary.hyperbolic.acosh :members: atanh ----- .. autoclass:: sympy.functions.elementary.hyperbolic.atanh :members: acoth ----- .. autoclass:: sympy.functions.elementary.hyperbolic.acoth :members: asech ----- .. autoclass:: sympy.functions.elementary.hyperbolic.asech :members: acsch ----- .. autoclass:: sympy.functions.elementary.hyperbolic.acsch :members: sympy.functions.elementary.integers =================================== ceiling ------- .. autoclass:: sympy.functions.elementary.integers.ceiling :members: floor ----- .. autoclass:: sympy.functions.elementary.integers.floor :members: RoundFunction ------------- .. autoclass:: sympy.functions.elementary.integers.RoundFunction :members: frac ---- .. autoclass:: sympy.functions.elementary.integers.frac :members: sympy.functions.elementary.exponential ====================================== exp --- .. autoclass:: sympy.functions.elementary.exponential.exp :members: LambertW -------- .. autoclass:: sympy.functions.elementary.exponential.LambertW :members: log --- .. autoclass:: sympy.functions.elementary.exponential.log :members: exp_polar --------- .. autoclass:: sympy.functions.elementary.exponential.exp_polar :members: sympy.functions.elementary.piecewise ==================================== ExprCondPair ------------ .. autoclass:: sympy.functions.elementary.piecewise.ExprCondPair :members: Piecewise --------- .. autoclass:: sympy.functions.elementary.piecewise.Piecewise :members: .. automethod:: sympy.functions.elementary.piecewise.Piecewise._eval_integral .. autofunction:: sympy.functions.elementary.piecewise.piecewise_fold sympy.functions.elementary.miscellaneous ======================================== IdentityFunction ---------------- .. autoclass:: sympy.functions.elementary.miscellaneous.IdentityFunction :members: Min --- .. autoclass:: sympy.functions.elementary.miscellaneous.Min :members: Max --- .. autoclass:: sympy.functions.elementary.miscellaneous.Max :members: root ---- .. autofunction:: sympy.functions.elementary.miscellaneous.root sqrt ---- .. autofunction:: sympy.functions.elementary.miscellaneous.sqrt cbrt ---- .. autofunction:: sympy.functions.elementary.miscellaneous.cbrt real_root --------- .. autofunction:: sympy.functions.elementary.miscellaneous.real_root sympy-sympy-1.9/doc/src/modules/functions/index.rst000066400000000000000000000006011412543434000225750ustar00rootroot00000000000000.. _functions: ========= Functions ========= .. module:: sympy.functions All functions support the methods documented below, inherited from :py:class:`sympy.core.function.Function`. .. autoclass:: sympy.core.function.Function :noindex: :members: .. _functions-contents: Contents ======== .. toctree:: :maxdepth: 2 elementary.rst combinatorial.rst special.rst sympy-sympy-1.9/doc/src/modules/functions/special.rst000066400000000000000000000156611412543434000231220ustar00rootroot00000000000000Special ======= DiracDelta ---------- .. autoclass:: sympy.functions.special.delta_functions.DiracDelta :members: Heaviside --------- .. autoclass:: sympy.functions.special.delta_functions.Heaviside :members: Singularity Function -------------------- .. module:: sympy.functions.special.singularity_functions .. autoclass:: sympy.functions.special.singularity_functions.SingularityFunction :members: Gamma, Beta and related Functions --------------------------------- .. module:: sympy.functions.special.gamma_functions .. autoclass:: sympy.functions.special.gamma_functions.gamma :members: .. autoclass:: sympy.functions.special.gamma_functions.loggamma :members: .. autoclass:: sympy.functions.special.gamma_functions.polygamma :members: .. autoclass:: sympy.functions.special.gamma_functions.digamma :members: .. autoclass:: sympy.functions.special.gamma_functions.trigamma :members: .. autoclass:: sympy.functions.special.gamma_functions.uppergamma :members: .. autoclass:: sympy.functions.special.gamma_functions.lowergamma :members: .. autoclass:: sympy.functions.special.gamma_functions.multigamma :members: .. module:: sympy.functions.special.beta_functions .. autoclass:: sympy.functions.special.beta_functions.beta :members: Error Functions and Fresnel Integrals ------------------------------------- .. module:: sympy.functions.special.error_functions .. autoclass:: sympy.functions.special.error_functions.erf :members: .. autoclass:: sympy.functions.special.error_functions.erfc :members: .. autoclass:: sympy.functions.special.error_functions.erfi :members: .. autoclass:: sympy.functions.special.error_functions.erf2 :members: .. autoclass:: sympy.functions.special.error_functions.erfinv :members: .. autoclass:: sympy.functions.special.error_functions.erfcinv :members: .. autoclass:: sympy.functions.special.error_functions.erf2inv :members: .. autoclass:: sympy.functions.special.error_functions.FresnelIntegral :members: .. autoclass:: fresnels :members: .. autoclass:: fresnelc :members: Exponential, Logarithmic and Trigonometric Integrals ---------------------------------------------------- .. autoclass:: Ei :members: .. autoclass:: expint :members: .. autofunction:: E1 .. autoclass:: li :members: .. autoclass:: Li :members: .. autoclass:: Si :members: .. autoclass:: Ci :members: .. autoclass:: Shi :members: .. autoclass:: Chi :members: Bessel Type Functions --------------------- .. module:: sympy.functions.special.bessel .. autoclass:: sympy.functions.special.bessel.BesselBase :members: .. autoclass:: sympy.functions.special.bessel.besselj :members: .. autoclass:: sympy.functions.special.bessel.bessely :members: .. _besseli: .. autoclass:: sympy.functions.special.bessel.besseli :members: .. autoclass:: sympy.functions.special.bessel.besselk :members: .. autoclass:: sympy.functions.special.bessel.hankel1 :members: .. autoclass:: sympy.functions.special.bessel.hankel2 :members: .. autoclass:: sympy.functions.special.bessel.jn :members: .. autoclass:: sympy.functions.special.bessel.yn :members: .. autofunction:: sympy.functions.special.bessel.jn_zeros .. autoclass:: sympy.functions.special.bessel.marcumq :members: Airy Functions -------------- .. autoclass:: sympy.functions.special.bessel.AiryBase :members: .. autoclass:: sympy.functions.special.bessel.airyai :members: .. autoclass:: sympy.functions.special.bessel.airybi :members: .. autoclass:: sympy.functions.special.bessel.airyaiprime :members: .. autoclass:: sympy.functions.special.bessel.airybiprime :members: B-Splines --------- .. autofunction:: sympy.functions.special.bsplines.bspline_basis .. autofunction:: sympy.functions.special.bsplines.bspline_basis_set .. autofunction:: sympy.functions.special.bsplines.interpolating_spline Riemann Zeta and Related Functions ---------------------------------- .. module:: sympy.functions.special.zeta_functions .. autoclass:: zeta :members: .. autoclass:: dirichlet_eta :members: .. autoclass:: polylog :members: .. autoclass:: lerchphi :members: .. autoclass:: stieltjes :members: Hypergeometric Functions ------------------------ .. autoclass:: sympy.functions.special.hyper.hyper :members: .. autoclass:: sympy.functions.special.hyper.meijerg :members: .. autoclass:: sympy.functions.special.hyper.appellf1 :members: Elliptic integrals ------------------ .. module:: sympy.functions.special.elliptic_integrals .. autoclass:: elliptic_k :members: .. autoclass:: elliptic_f :members: .. autoclass:: elliptic_e :members: .. autoclass:: elliptic_pi :members: Mathieu Functions ----------------- .. module:: sympy.functions.special.mathieu_functions .. autoclass:: sympy.functions.special.mathieu_functions.MathieuBase :members: .. autoclass:: sympy.functions.special.mathieu_functions.mathieus :members: .. autoclass:: sympy.functions.special.mathieu_functions.mathieuc :members: .. autoclass:: sympy.functions.special.mathieu_functions.mathieusprime :members: .. autoclass:: sympy.functions.special.mathieu_functions.mathieucprime :members: Orthogonal Polynomials ---------------------- .. automodule:: sympy.functions.special.polynomials Jacobi Polynomials ++++++++++++++++++ .. autoclass:: sympy.functions.special.polynomials.jacobi :members: .. autofunction:: sympy.functions.special.polynomials.jacobi_normalized Gegenbauer Polynomials ++++++++++++++++++++++ .. autoclass:: sympy.functions.special.polynomials.gegenbauer :members: Chebyshev Polynomials +++++++++++++++++++++ .. autoclass:: sympy.functions.special.polynomials.chebyshevt :members: .. autoclass:: sympy.functions.special.polynomials.chebyshevu :members: .. autoclass:: sympy.functions.special.polynomials.chebyshevt_root :members: .. autoclass:: sympy.functions.special.polynomials.chebyshevu_root :members: Legendre Polynomials ++++++++++++++++++++ .. autoclass:: sympy.functions.special.polynomials.legendre :members: .. autoclass:: sympy.functions.special.polynomials.assoc_legendre :members: Hermite Polynomials +++++++++++++++++++ .. autoclass:: sympy.functions.special.polynomials.hermite :members: Laguerre Polynomials ++++++++++++++++++++ .. autoclass:: sympy.functions.special.polynomials.laguerre :members: .. autoclass:: sympy.functions.special.polynomials.assoc_laguerre :members: Spherical Harmonics ------------------- .. autoclass:: sympy.functions.special.spherical_harmonics.Ynm :members: .. autofunction:: sympy.functions.special.spherical_harmonics.Ynm_c .. autoclass:: sympy.functions.special.spherical_harmonics.Znm :members: Tensor Functions ---------------- .. autofunction:: sympy.functions.special.tensor_functions.Eijk .. autofunction:: sympy.functions.special.tensor_functions.eval_levicivita .. autoclass:: sympy.functions.special.tensor_functions.LeviCivita :members: .. autoclass:: sympy.functions.special.tensor_functions.KroneckerDelta :members: sympy-sympy-1.9/doc/src/modules/geometry/000077500000000000000000000000001412543434000205625ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/geometry/curves.rst000066400000000000000000000001231412543434000226170ustar00rootroot00000000000000Curves ------ .. module:: sympy.geometry.curve .. autoclass:: Curve :members: sympy-sympy-1.9/doc/src/modules/geometry/ellipses.rst000066400000000000000000000001771412543434000231410ustar00rootroot00000000000000Ellipses -------- .. module:: sympy.geometry.ellipse .. autoclass:: Ellipse :members: .. autoclass:: Circle :members: sympy-sympy-1.9/doc/src/modules/geometry/entities.rst000066400000000000000000000001671412543434000231440ustar00rootroot00000000000000Entities -------- .. module:: sympy.geometry.entity .. autoclass:: sympy.geometry.entity.GeometryEntity :members: sympy-sympy-1.9/doc/src/modules/geometry/index.rst000066400000000000000000000150111412543434000224210ustar00rootroot00000000000000======== Geometry ======== Introduction ------------ The geometry module for SymPy allows one to create two-dimensional geometrical entities, such as lines and circles, and query for information about these entities. This could include asking the area of an ellipse, checking for collinearity of a set of points, or finding the intersection between two lines. The primary use case of the module involves entities with numerical values, but it is possible to also use symbolic representations. Available Entities ------------------ The following entities are currently available in the geometry module: * :class:`~sympy.geometry.point.Point` * :class:`~sympy.geometry.line.Line`, :class:`~sympy.geometry.line.Segment`, :class:`~sympy.geometry.line.Ray` * :class:`~sympy.geometry.ellipse.Ellipse`, :class:`~sympy.geometry.ellipse.Circle` * :class:`~sympy.geometry.polygon.Polygon`, :class:`~sympy.geometry.polygon.RegularPolygon`, :class:`~sympy.geometry.polygon.Triangle` Most of the work one will do will be through the properties and methods of these entities, but several global methods exist: * ``intersection(entity1, entity2)`` * ``are_similar(entity1, entity2)`` * ``convex_hull(points)`` For a full API listing and an explanation of the methods and their return values please see the list of classes at the end of this document. Example Usage ------------- The following Python session gives one an idea of how to work with some of the geometry module. >>> from sympy import * >>> from sympy.geometry import * >>> x = Point(0, 0) >>> y = Point(1, 1) >>> z = Point(2, 2) >>> zp = Point(1, 0) >>> Point.is_collinear(x, y, z) True >>> Point.is_collinear(x, y, zp) False >>> t = Triangle(zp, y, x) >>> t.area 1/2 >>> t.medians[x] Segment2D(Point2D(0, 0), Point2D(1, 1/2)) >>> m = t.medians >>> intersection(m[x], m[y], m[zp]) [Point2D(2/3, 1/3)] >>> c = Circle(x, 5) >>> l = Line(Point(5, -5), Point(5, 5)) >>> c.is_tangent(l) # is l tangent to c? True >>> l = Line(x, y) >>> c.is_tangent(l) # is l tangent to c? False >>> intersection(c, l) [Point2D(-5*sqrt(2)/2, -5*sqrt(2)/2), Point2D(5*sqrt(2)/2, 5*sqrt(2)/2)] Intersection of medians ----------------------- :: >>> from sympy import symbols >>> from sympy.geometry import Point, Triangle, intersection >>> a, b = symbols("a,b", positive=True) >>> x = Point(0, 0) >>> y = Point(a, 0) >>> z = Point(2*a, b) >>> t = Triangle(x, y, z) >>> t.area a*b/2 >>> t.medians[x] Segment2D(Point2D(0, 0), Point2D(3*a/2, b/2)) >>> intersection(t.medians[x], t.medians[y], t.medians[z]) [Point2D(a, b/3)] An in-depth example: Pappus' Hexagon Theorem -------------------------------------------- From Wikipedia ([WikiPappus]_): Given one set of collinear points `A`, `B`, `C`, and another set of collinear points `a`, `b`, `c`, then the intersection points `X`, `Y`, `Z` of line pairs `Ab` and `aB`, `Ac` and `aC`, `Bc` and `bC` are collinear. :: >>> from sympy import * >>> from sympy.geometry import * >>> >>> l1 = Line(Point(0, 0), Point(5, 6)) >>> l2 = Line(Point(0, 0), Point(2, -2)) >>> >>> def subs_point(l, val): ... """Take an arbitrary point and make it a fixed point.""" ... t = Symbol('t', real=True) ... ap = l.arbitrary_point() ... return Point(ap.x.subs(t, val), ap.y.subs(t, val)) ... >>> p11 = subs_point(l1, 5) >>> p12 = subs_point(l1, 6) >>> p13 = subs_point(l1, 11) >>> >>> p21 = subs_point(l2, -1) >>> p22 = subs_point(l2, 2) >>> p23 = subs_point(l2, 13) >>> >>> ll1 = Line(p11, p22) >>> ll2 = Line(p11, p23) >>> ll3 = Line(p12, p21) >>> ll4 = Line(p12, p23) >>> ll5 = Line(p13, p21) >>> ll6 = Line(p13, p22) >>> >>> pp1 = intersection(ll1, ll3)[0] >>> pp2 = intersection(ll2, ll5)[0] >>> pp3 = intersection(ll4, ll6)[0] >>> >>> Point.is_collinear(pp1, pp2, pp3) True References ~~~~~~~~~~ .. [WikiPappus] "Pappus's Hexagon Theorem" Wikipedia, the Free Encyclopedia. Web. 26 Apr. 2013. Miscellaneous Notes ------------------- * The area property of ``Polygon`` and ``Triangle`` may return a positive or negative value, depending on whether or not the points are oriented counter-clockwise or clockwise, respectively. If you always want a positive value be sure to use the ``abs`` function. * Although ``Polygon`` can refer to any type of polygon, the code has been written for simple polygons. Hence, expect potential problems if dealing with complex polygons (overlapping sides). * Since SymPy is still in its infancy some things may not simplify properly and hence some things that should return ``True`` (e.g., ``Point.is_collinear``) may not actually do so. Similarly, attempting to find the intersection of entities that do intersect may result in an empty result. Future Work ----------- Truth Setting Expressions ~~~~~~~~~~~~~~~~~~~~~~~~~ When one deals with symbolic entities, it often happens that an assertion cannot be guaranteed. For example, consider the following code: >>> from sympy import * >>> from sympy.geometry import * >>> x,y,z = map(Symbol, 'xyz') >>> p1,p2,p3 = Point(x, y), Point(y, z), Point(2*x*y, y) >>> Point.is_collinear(p1, p2, p3) False Even though the result is currently ``False``, this is not *always* true. If the quantity `z - y - 2*y*z + 2*y**2 == 0` then the points will be collinear. It would be really nice to inform the user of this because such a quantity may be useful to a user for further calculation and, at the very least, being nice to know. This could be potentially done by returning an object (e.g., GeometryResult) that the user could use. This actually would not involve an extensive amount of work. Three Dimensions and Beyond ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Currently a limited subset of the geometry module has been extended to three dimensions, but it certainly would be a good addition to extend more. This would probably involve a fair amount of work since many of the algorithms used are specific to two dimensions. Geometry Visualization ~~~~~~~~~~~~~~~~~~~~~~ The plotting module is capable of plotting geometric entities. See :ref:`Plotting Geometric Entities ` in the plotting module entry. Submodules ~~~~~~~~~~ .. toctree:: :maxdepth: 3 entities.rst utils.rst points.rst lines.rst curves.rst ellipses.rst polygons.rst plane.rst sympy-sympy-1.9/doc/src/modules/geometry/lines.rst000066400000000000000000000007631412543434000224340ustar00rootroot00000000000000Lines ----- .. module:: sympy.geometry.line .. autoclass:: LinearEntity :members: .. autoclass:: Line :members: .. autoclass:: Ray :members: .. autoclass:: Segment :members: .. autoclass:: LinearEntity2D :members: .. autoclass:: Line2D :members: .. autoclass:: Ray2D :members: .. autoclass:: Segment2D :members: .. autoclass:: LinearEntity3D :members: .. autoclass:: Line3D :members: .. autoclass:: Ray3D :members: .. autoclass:: Segment3D :members: sympy-sympy-1.9/doc/src/modules/geometry/plane.rst000066400000000000000000000001211412543434000224050ustar00rootroot00000000000000Plane ----- .. module:: sympy.geometry.plane .. autoclass:: Plane :members: sympy-sympy-1.9/doc/src/modules/geometry/points.rst000066400000000000000000000002351412543434000226300ustar00rootroot00000000000000Points ------ .. module:: sympy.geometry.point .. autoclass:: Point :members: .. autoclass:: Point2D :members: .. autoclass:: Point3D :members: sympy-sympy-1.9/doc/src/modules/geometry/polygons.rst000066400000000000000000000002551412543434000231700ustar00rootroot00000000000000Polygons -------- .. module:: sympy.geometry.polygon .. autoclass:: Polygon :members: .. autoclass:: RegularPolygon :members: .. autoclass:: Triangle :members: sympy-sympy-1.9/doc/src/modules/geometry/utils.rst000066400000000000000000000003001412543434000224450ustar00rootroot00000000000000Utils ----- .. module:: sympy.geometry.util .. autofunction:: intersection .. autofunction:: convex_hull .. autofunction:: are_similar .. autofunction:: centroid .. autofunction:: idiff sympy-sympy-1.9/doc/src/modules/holonomic/000077500000000000000000000000001412543434000207165ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/holonomic/about.rst000066400000000000000000000037201412543434000225640ustar00rootroot00000000000000About Holonomic Functions ========================= This text aims to explain holonomic functions. We assume you have a basic idea of Differential equations and Abstract algebra. Definition ---------- Holonomic function is a very general type of special function that includes lots of simple known functions as its special cases. In fact the more known hypergeometric function and Meijer G-function are also a special case of it. A function is called holonomic if it's a solution to an ordinary differential equation having polynomial coefficients only. Since the general solution of a differential equation consists of a family of functions rather than a single function, holonomic functions are usually defined by a set of initial conditions along with the differential equation. Let :math:`K` be a field of characteristic ``0``. For example, :math:`K` can be ``QQ`` or ``RR``. A function :math:`f(x)` will be holonomic if there exists polynomials :math:`p_0, p_1, p_2, ... p_r \in K[x]` such that .. math:: p_0 \cdot f(x) + p_1 \cdot f^{(1)}(x) + p_2 \cdot f^{(2)}(x) + ... + p_r \cdot f^{(r)}(x) = 0 This differential equation can also be written as :math:`L \cdot f(x) = 0` where .. math:: L = p_0 + p_1 \cdot D + p_2 \cdot D^2 + ... p_r \cdot D^r Here `D` is the Differential Operator and `L` is called the annihilator of the function. A unique holonomic function can be defined from the annihilator and a set of initial conditions. For instance: .. math:: f(x) = \exp(x): L = D - 1,\: f(0) = 1 f(x) = \sin(x): L = D^2 + 1,\: f(0) = 0, f'(0) = 1 Other fundamental functions such as `\cos(x)`, `\log(x)`, bessel functions etc. are also holonomic. The family of holonomic functions is closed under addition, multiplication, integration, composition. This means if two functions are given are holonomic, then the function resulting on applying these operation on them will also be holonomic. References ---------- https://en.wikipedia.org/wiki/Holonomic_function sympy-sympy-1.9/doc/src/modules/holonomic/convert.rst000066400000000000000000000006631412543434000231350ustar00rootroot00000000000000Converting other representations to holonomic ============================================= .. currentmodule:: sympy.holonomic.holonomic Converting hypergeometric functions ----------------------------------- .. autofunction:: from_hyper Converting Meijer G-functions ----------------------------- .. autofunction:: from_meijerg Converting symbolic expressions ------------------------------- .. autofunction:: expr_to_holonomicsympy-sympy-1.9/doc/src/modules/holonomic/index.rst000066400000000000000000000003411412543434000225550ustar00rootroot00000000000000.. _holonomic-docs: ========= Holonomic ========= .. automodule:: sympy.holonomic Contents ======== .. toctree:: :maxdepth: 2 about.rst represent.rst operations.rst convert.rst uses.rst internal.rst sympy-sympy-1.9/doc/src/modules/holonomic/internal.rst000066400000000000000000000002301412543434000232570ustar00rootroot00000000000000Internal API ============ .. autofunction:: sympy.holonomic.holonomic._create_table .. autofunction:: sympy.holonomic.holonomic._convert_poly_rat_alg sympy-sympy-1.9/doc/src/modules/holonomic/operations.rst000066400000000000000000000036111412543434000236340ustar00rootroot00000000000000Operations on holonomic functions ================================= Addition and Multiplication --------------------------- Two holonomic functions can be added or multiplied with the result also a holonomic functions. >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import QQ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') ``p`` and ``q`` here are holonomic representation of `e^x` and `\sin(x)` respectively. >>> p = HolonomicFunction(Dx - 1, x, 0, [1]) >>> q = HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]) Holonomic representation of `e^x+\sin(x)` >>> p + q HolonomicFunction((-1) + (1)*Dx + (-1)*Dx**2 + (1)*Dx**3, x, 0, [1, 2, 1]) Holonomic representation of `e^x \cdot \sin(x)` >>> p * q HolonomicFunction((2) + (-2)*Dx + (1)*Dx**2, x, 0, [0, 1]) .. currentmodule:: sympy.holonomic.holonomic Integration and Differentiation ------------------------------- .. automethod:: HolonomicFunction.integrate .. automethod:: HolonomicFunction.diff Composition with polynomials ---------------------------- .. automethod:: HolonomicFunction.composition Convert to holonomic sequence ----------------------------- .. automethod:: HolonomicFunction.to_sequence Series expansion ---------------- .. automethod:: HolonomicFunction.series Numerical evaluation -------------------- .. automethod:: HolonomicFunction.evalf Convert to a linear combination of hypergeometric functions ----------------------------------------------------------- .. automethod:: HolonomicFunction.to_hyper Convert to a linear combination of Meijer G-functions ----------------------------------------------------- .. automethod:: HolonomicFunction.to_meijerg Convert to expressions ---------------------- .. automethod:: HolonomicFunction.to_expr sympy-sympy-1.9/doc/src/modules/holonomic/represent.rst000066400000000000000000000044121412543434000234600ustar00rootroot00000000000000Representation of holonomic functions in SymPy ============================================== .. currentmodule:: sympy.holonomic.holonomic Class :class:`DifferentialOperator` is used to represent the annihilator but we create differential operators easily using the function :func:`DifferentialOperators`. Class :class:`HolonomicFunction` represents a holonomic function. Let's explain this with an example: Take `\sin(x)` for instance, the differential equation satisfied by it is `y^{(2)}(x) + y(x) = 0`. By definition we conclude it is a holonomic function. The general solution of this ODE is `C_{1} \cdot \sin(x) + C_{2} \cdot \cos(x)` but to get `\sin(x)` we need to provide initial conditions i.e. `y(0) = 0, y^{(1)}(0) = 1`. To represent the same in this module one needs to provide the differential equation in the form of annihilator. Basically a differential operator is an operator on functions that differentiates them. So `D^{n} \cdot y(x) = y^{(n)}(x)` where :math:`y^{(n)}(x)` denotes ``n`` times differentiation of :math:`y(x)` with respect to ``x``. So the differential equation can also be written as :math:`D^{2} \cdot y(x) + y(x) = 0` or `(D^{2} + 1) \cdot y(x) = 0`. The part left of :math:`y(x)` is the annihilator i.e. :math:`D^{2}+1`. So this is how one will represent `\sin(x)` as a Holonomic Function: >>> from sympy.holonomic import DifferentialOperators, HolonomicFunction >>> from sympy.abc import x >>> from sympy import ZZ >>> R, D = DifferentialOperators(ZZ.old_poly_ring(x), 'D') >>> HolonomicFunction(D**2 + 1, x, 0, [0, 1]) HolonomicFunction((1) + (1)*D**2, x, 0, [0, 1]) The polynomial coefficients will be members of the ring ``ZZ[x]`` in the example. The ``D`` operator returned by the function :py:func:`DifferentialOperators` can be used to create annihilators just like SymPy expressions. We currently use the older implementations of rings in SymPy for priority mechanism. HolonomicFunction ----------------- .. autoclass:: HolonomicFunction DifferentialOperator -------------------- .. autoclass:: DifferentialOperator :members: DifferentialOperators --------------------- .. autofunction:: DifferentialOperators DifferentialOperatorAlgebra --------------------------- .. autoclass:: DifferentialOperatorAlgebra :members: sympy-sympy-1.9/doc/src/modules/holonomic/uses.rst000066400000000000000000000036601412543434000224340ustar00rootroot00000000000000.. currentmodule:: sympy.holonomic.holonomic Uses and Current limitations ============================ Integration ----------- One can perform integrations using holonomic functions by following these steps: 1. Convert the integrand to a holonomic function. 2. Now integrate the holonomic representation of the function. 3. Convert the integral back to expressions. Examples ^^^^^^^^ >>> from sympy.abc import x, a >>> from sympy import sin >>> from sympy.holonomic import expr_to_holonomic >>> expr_to_holonomic(1/(x**2+a), x).integrate(x).to_expr() atan(x/sqrt(a))/sqrt(a) >>> expr_to_holonomic(sin(x)/x).integrate(x).to_expr() Si(x) As you can see in the first example we converted the function to holonomic, integrated the result and then converted back to symbolic expression. Limitations ----------- 1. Converting to expressions is not always possible. The holonomic function should have a hypergeometric series at ``x0``. 2. Implementation of converting to holonomic sequence currently doesn't support ``Frobenius method`` when the solutions need to have `\log` terms. This happens when at least one pair of the roots of the indicial equation differ by an integer and frobenius method yields linearly dependent series solutions. Since we use this while converting to expressions, sometimes :func:`~HolonomicFunction.to_expr()` fails. 3. There doesn't seem to be a way for computing indefinite integrals, so :func:`~HolonomicFunction.integrate()` basically computes `\int_{x_0}^{x} f(x)dx` if no limits are given, where `x_0` is the point at which initial conditions for the integrand are stored. Sometimes this gives an additional constant in the result. For instance: >>> expr_to_holonomic(sin(x)).integrate(x).to_expr() 1 - cos(x) >>> sin(x).integrate(x) -cos(x) The indefinite integral of `\sin(x)` is `-\cos(x)`. But the output is `-\cos(x) + 1` which is `\int_{0}^{x} sin(x)dx`. Although both are considered correct but `-\cos(x)` is simpler. sympy-sympy-1.9/doc/src/modules/index.rst000066400000000000000000000033421412543434000205720ustar00rootroot00000000000000.. _module-docs: SymPy Modules Reference ======================= .. module:: sympy Because every feature of SymPy must have a test case, when you are not sure how to use something, just look into the ``tests/`` directories, find that feature and read the tests for it, that will tell you everything you need to know. Most of the things are already documented though in this document, that is automatically generated using SymPy's docstrings. Click the "modules" (:ref:`modindex`) link in the top right corner to easily access any SymPy module, or use the list below: .. toctree:: :maxdepth: 2 abc.rst algebras.rst assumptions/index.rst calculus/index.rst categories.rst codegen.rst combinatorics/index.rst concrete.rst core.rst crypto.rst diffgeom.rst solvers/diophantine.rst discrete.rst evalf.rst functions/index.rst geometry/index.rst holonomic/index.rst solvers/inequalities.rst integrals/integrals.rst integrals/g-functions.rst interactive.rst liealgebras/index.rst logic.rst matrices/index.rst ntheory.rst numeric-computation.rst solvers/ode.rst parsing.rst solvers/pde.rst physics/index.rst plotting.rst polys/index.rst printing.rst rewriting.rst series/index.rst sets.rst simplify/index.rst solvers/solvers.rst solvers/solveset.rst stats.rst tensor/index.rst testing/index.rst utilities/index.rst vector/index.rst Contributions to Docs --------------------- All contributions are welcome. If you'd like to improve something, look into the sources if they contain the information you need (if not, please fix them), otherwise the documentation generation needs to be improved (look in the ``doc/`` directory). sympy-sympy-1.9/doc/src/modules/integrals/000077500000000000000000000000001412543434000207175ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/integrals/g-functions.rst000066400000000000000000000747341412543434000237240ustar00rootroot00000000000000.. _g-functions: Computing Integrals using Meijer G-Functions ******************************************** This text aims do describe in some detail the steps (and subtleties) involved in using Meijer G-functions for computing definite and indefinite integrals. We shall ignore proofs completely. Overview ======== The algorithm to compute `\int f(x) \mathrm{d}x` or `\int_0^\infty f(x) \mathrm{d}x` generally consists of three steps: 1. Rewrite the integrand using Meijer G-functions (one or sometimes two). 2. Apply an integration theorem, to get the answer (usually expressed as another G-function). 3. Expand the result in named special functions. Step (3) is implemented in the function hyperexpand (q.v.). Steps (1) and (2) are described below. Moreover, G-functions are usually branched. Thus our treatment of branched functions is described first. Some other integrals (e.g. `\int_{-\infty}^\infty`) can also be computed by first recasting them into one of the above forms. There is a lot of choice involved here, and the algorithm is heuristic at best. Polar Numbers and Branched Functions ==================================== Both Meijer G-Functions and Hypergeometric functions are typically branched (possible branchpoints being `0`, `\pm 1`, `\infty`). This is not very important when e.g. expanding a single hypergeometric function into named special functions, since sorting out the branches can be left to the human user. However this algorithm manipulates and transforms G-functions, and to do this correctly it needs at least some crude understanding of the branchings involved. To begin, we consider the set `\mathcal{S} = \{(r, \theta) : r > 0, \theta \in \mathbb{R}\}`. We have a map `p: \mathcal{S}: \rightarrow \mathbb{C}-\{0\}, (r, \theta) \mapsto r e^{i \theta}`. Decreeing this to be a local biholomorphism gives `\mathcal{S}` both a topology and a complex structure. This Riemann Surface is usually referred to as the Riemann Surface of the logarithm, for the following reason: We can define maps `\operatorname{Exp}: \mathbb{C} \rightarrow \mathcal{S}, (x + i y) \mapsto (\exp(x), y)` and `\operatorname{Log}: \mathcal{S} \rightarrow \mathbb{C}, (e^x, y) \mapsto x + iy`. These can both be shown to be holomorphic, and are indeed mutual inverses. We also sometimes formally attach a point "zero" (`0`) to `\mathcal{S}` and denote the resulting object `\mathcal{S}_0`. Notably there is no complex structure defined near `0`. A fundamental system of neighbourhoods is given by `\{\operatorname{Exp}(z) : \Re(z) < k\}`, which at least defines a topology. Elements of `\mathcal{S}_0` shall be called polar numbers. We further define functions `\operatorname{Arg}: \mathcal{S} \rightarrow \mathbb{R}, (r, \theta) \mapsto \theta` and `|.|: \mathcal{S}_0 \rightarrow \mathbb{R}_{>0}, (r, \theta) \mapsto r`. These have evident meaning and are both continuous everywhere. Using these maps many operations can be extended from `\mathbb{C}` to `\mathcal{S}`. We define `\operatorname{Exp}(a) \operatorname{Exp}(b) = \operatorname{Exp}(a + b)` for `a, b \in \mathbb{C}`, also for `a \in \mathcal{S}` and `b \in \mathbb{C}` we define `a^b = \operatorname{Exp}(b \operatorname{Log}(a))`. It can be checked easily that using these definitions, many algebraic properties holding for positive reals (e.g. `(ab)^c = a^c b^c`) which hold in `\mathbb{C}` only for some numbers (because of branch cuts) hold indeed for all polar numbers. As one peculiarity it should be mentioned that addition of polar numbers is not usually defined. However, formal sums of polar numbers can be used to express branching behaviour. For example, consider the functions `F(z) = \sqrt{1 + z}` and `G(a, b) = \sqrt{a + b}`, where `a, b, z` are polar numbers. The general rule is that functions of a single polar variable are defined in such a way that they are continuous on circles, and agree with the usual definition for positive reals. Thus if `S(z)` denotes the standard branch of the square root function on `\mathbb{C}`, we are forced to define .. math:: F(z) = \begin{cases} S(p(z)) &: |z| < 1 \\ S(p(z)) &: -\pi < \operatorname{Arg}(z) + 4\pi n \le \pi \text{ for some } n \in \mathbb{Z} \\ -S(p(z)) &: \text{else} \end{cases}. (We are omitting `|z| = 1` here, this does not matter for integration.) Finally we define `G(a, b) = \sqrt{a}F(b/a)`. Representing Branched Functions on the Argand Plane =================================================== Suppose `f: \mathcal{S} \to \mathbb{C}` is a holomorphic function. We wish to define a function `F` on (part of) the complex numbers `\mathbb{C}` that represents `f` as closely as possible. This process is knows as "introducing branch cuts". In our situation, there is actually a canonical way of doing this (which is adhered to in all of SymPy), as follows: Introduce the "cut complex plane" `C = \mathbb{C} \setminus \mathbb{R}_{\le 0}`. Define a function `l: C \to \mathcal{S}` via `re^{i\theta} \mapsto r \operatorname{Exp}(i\theta)`. Here `r > 0` and `-\pi < \theta \le \pi`. Then `l` is holomorphic, and we define `G = f \circ l`. This called "lifting to the principal branch" throughout the SymPy documentation. Table Lookups and Inverse Mellin Transforms =========================================== Suppose we are given an integrand `f(x)` and are trying to rewrite it as a single G-function. To do this, we first split `f(x)` into the form `x^s g(x)` (where `g(x)` is supposed to be simpler than `f(x)`). This is because multiplicative powers can be absorbed into the G-function later. This splitting is done by ``_split_mul(f, x)``. Then we assemble a tuple of functions that occur in `f` (e.g. if `f(x) = e^x \cos{x}`, we would assemble the tuple `(\cos, \exp)`). This is done by the function ``_mytype(f, x)``. Next we index a lookup table (created using ``_create_lookup_table()``) with this tuple. This (hopefully) yields a list of Meijer G-function formulae involving these functions, we then pattern-match all of them. If one fits, we were successful, otherwise not and we have to try something else. Suppose now we want to rewrite as a product of two G-functions. To do this, we (try to) find all inequivalent ways of splitting `f(x)` into a product `f_1(x) f_2(x)`. We could try these splittings in any order, but it is often a good idea to minimize (a) the number of powers occurring in `f_i(x)` and (b) the number of different functions occurring in `f_i(x)`. Thus given e.g. `f(x) = \sin{x}\, e^{x} \sin{2x}` we should try `f_1(x) = \sin{x}\, \sin{2x}`, `f_2(x) = e^{x}` first. All of this is done by the function ``_mul_as_two_parts(f)``. Finally, we can try a recursive Mellin transform technique. Since the Meijer G-function is defined essentially as a certain inverse mellin transform, if we want to write a function `f(x)` as a G-function, we can compute its mellin transform `F(s)`. If `F(s)` is in the right form, the G-function expression can be read off. This technique generalises many standard rewritings, e.g. `e^{ax} e^{bx} = e^{(a + b) x}`. One twist is that some functions don't have mellin transforms, even though they can be written as G-functions. This is true for example for `f(x) = e^x \sin{x}` (the function grows too rapidly to have a mellin transform). However if the function is recognised to be analytic, then we can try to compute the mellin-transform of `f(ax)` for a parameter `a`, and deduce the G-function expression by analytic continuation. (Checking for analyticity is easy. Since we can only deal with a certain subset of functions anyway, we only have to filter out those which are not analyitc.) The function ``_rewrite_single`` does the table lookup and recursive mellin transform. The functions ``_rewrite1`` and ``_rewrite2`` respectively use above-mentioned helpers and ``_rewrite_single`` to rewrite their argument as respectively one or two G-functions. Applying the Integral Theorems ============================== If the integrand has been recast into G-functions, evaluating the integral is relatively easy. We first do some substitutions to reduce e.g. the exponent of the argument of the G-function to unity (see ``_rewrite_saxena_1`` and ``_rewrite_saxena``, respectively, for one or two G-functions). Next we go through a list of conditions under which the integral theorem applies. It can fail for basically two reasons: either the integral does not exist, or the manipulations in deriving the theorem may not be allowed (for more details, see this [BlogPost]_). Sometimes this can be remedied by reducing the argument of the G-functions involved. For example it is clear that the G-function representing `e^z` is satisfies `G(\operatorname{Exp}(2 \pi i)z) = G(z)` for all `z \in \mathcal{S}`. The function ``meijerg.get_period()`` can be used to discover this, and the function ``principal_branch(z, period)`` in ``functions/elementary/complexes.py`` can be used to exploit the information. This is done transparently by the integration code. .. [BlogPost] https://nessgrh.wordpress.com/2011/07/07/tricky-branch-cuts/ The G-Function Integration Theorems *********************************** This section intends to display in detail the definite integration theorems used in the code. The following two formulae go back to Meijer (In fact he proved more general formulae; indeed in the literature formulae are usually staded in more general form. However it is very easy to deduce the general formulae from the ones we give here. It seemed best to keep the theorems as simple as possible, since they are very complicated anyway.): 1. .. math:: \int_0^\infty G_{p, q}^{m, n} \left.\left(\begin{matrix} a_1, \cdots, a_p \\ b_1, \cdots, b_q \end{matrix} \right| \eta x \right) \mathrm{d}x = \frac{\prod_{j=1}^m \Gamma(b_j + 1) \prod_{j=1}^n \Gamma(-a_j)}{\eta \prod_{j=m+1}^q \Gamma(-b_j) \prod_{j=n+1}^p \Gamma(a_j + 1)} 2. .. math:: \int_0^\infty G_{u, v}^{s, t} \left.\left(\begin{matrix} c_1, \cdots, c_u \\ d_1, \cdots, d_v \end{matrix} \right| \sigma x \right) G_{p, q}^{m, n} \left.\left(\begin{matrix} a_1, \cdots, a_p \\ b_1, \cdots, b_q \end{matrix} \right| \omega x \right) \mathrm{d}x = G_{v+p, u+q}^{m+t, n+s} \left.\left( \begin{matrix} a_1, \cdots, a_n, -d_1, \cdots, -d_v, a_{n+1}, \cdots, a_p \\ b_1, \cdots, b_m, -c_1, \cdots, -c_u, b_{m+1}, \cdots, b_q \end{matrix} \right| \frac{\omega}{\sigma} \right) The more interesting question is under what conditions these formulae are valid. Below we detail the conditions implemented in SymPy. They are an amalgamation of conditions found in [Prudnikov1990]_ and [Luke1969]_; please let us know if you find any errors. Conditions of Convergence for Integral (1) ========================================== .. TODO: Formatting could be improved. We can without loss of generality assume `p \le q`, since the G-functions of indices `m, n, p, q` and of indices `n, m, q, p` can be related easily (see e.g. [Luke1969]_, section 5.3). We introduce the following notation: .. math:: \xi = m + n - p \\ \delta = m + n - \frac{p + q}{2} .. math:: C_3: -\Re(b_j) < 1 \text{ for } j=1, \ldots, m \\ 0 < -\Re(a_j) \text{ for } j=1, \ldots, n .. math:: C_3^*: -\Re(b_j) < 1 \text{ for } j=1, \ldots, q \\ 0 < -\Re(a_j) \text{ for } j=1, \ldots, p .. math:: C_4: -\Re(\delta) + \frac{q + 1 - p}{2} > q - p The convergence conditions will be detailed in several "cases", numbered one to five. For later use it will be helpful to separate conditions "at infinity" from conditions "at zero". By conditions "at infinity" we mean conditions that only depend on the behaviour of the integrand for large, positive values of `x`, whereas by conditions "at zero" we mean conditions that only depend on the behaviour of the integrand on `(0, \epsilon)` for any `\epsilon > 0`. Since all our conditions are specified in terms of parameters of the G-functions, this distinction is not immediately visible. They are, however, of very distinct character mathematically; the conditions at infinity being in particular much harder to control. In order for the integral theorem to be valid, conditions `n` "at zero" and "at infinity" both have to be fulfilled, for some `n`. These are the conditions "at infinity": 1. .. math:: \delta > 0 \wedge |\arg(\eta)| < \delta \pi \wedge (A \vee B \vee C), where .. math:: A = 1 \le n \wedge p < q \wedge 1 \le m .. math:: B = 1 \le p \wedge 1 \le m \wedge q = p+1 \wedge \neg (n = 0 \wedge m = p + 1 ) .. math:: C = 1 \le n \wedge q = p \wedge |\arg(\eta)| \ne (\delta - 2k)\pi \text{ for } k = 0, 1, \ldots \left\lceil \frac{\delta}{2} \right\rceil. 2. .. math:: n = 0 \wedge p + 1 \le m \wedge |\arg(\eta)| < \delta \pi 3. .. math:: (p < q \wedge 1 \le m \wedge \delta > 0 \wedge |\arg(\eta)| = \delta \pi) \vee (p \le q - 2 \wedge \delta = 0 \wedge \arg(\eta) = 0) 4. .. math:: p = q \wedge \delta = 0 \wedge \arg(\eta) = 0 \wedge \eta \ne 0 \wedge \Re\left(\sum_{j=1}^p b_j - a_j \right) < 0 5. .. math:: \delta > 0 \wedge |\arg(\eta)| < \delta \pi And these are the conditions "at zero": 1. .. math:: \eta \ne 0 \wedge C_3 2. .. math:: C_3 3. .. math:: C_3 \wedge C_4 4. .. math:: C_3 5. .. math:: C_3 Conditions of Convergence for Integral (2) ========================================== We introduce the following notation: .. many of the latex expressions below were generated semi-automatically .. math:: b^* = s + t - \frac{u + v}{2} .. math:: c^* = m + n - \frac{p + q}{2} .. math:: \rho = \sum_{j=1}^v d_j - \sum_{j=1}^u c_j + \frac{u - v}{2} + 1 .. math:: \mu = \sum_{j=1}^q b_j - \sum_{j=1}^p a_j + \frac{p - q}{2} + 1 .. math:: \phi = q - p - \frac{u - v}{2} + 1 .. math:: \eta = 1 - (v - u) - \mu - \rho .. math:: \psi = \frac{\pi(q - m - n) + |\arg(\omega)|}{q - p} .. math:: \theta = \frac{\pi(v - s - t) + |\arg(\sigma)|)}{v - u} .. math:: \lambda_c = (q - p)|\omega|^{1/(q - p)} \cos{\psi} + (v - u)|\sigma|^{1/(v - u)} \cos{\theta} .. math:: \lambda_{s0}(c_1, c_2) = c_1 (q - p)|\omega|^{1/(q - p)} \sin{\psi} + c_2 (v - u)|\sigma|^{1/(v - u)} \sin{\theta} .. math:: \lambda_s = \begin{cases} \operatorname{\lambda_{s0}}\left(-1,-1\right) \operatorname{\lambda_{s0}}\left(1,1\right) & \text{for}\: \arg(\omega) = 0 \wedge \arg(\sigma) = 0 \\\operatorname{\lambda_{s0}}\left(\operatorname{sign}\left(\operatorname{\arg}\left(\omega\right)\right),-1\right) \operatorname{\lambda_{s0}}\left(\operatorname{sign}\left(\operatorname{\arg}\left(\omega\right)\right),1\right) & \text{for}\: \arg(\omega) \ne 0 \wedge \arg(\sigma) = 0 \\\operatorname{\lambda_{s0}}\left(-1,\operatorname{sign}\left(\operatorname{\arg}\left(\sigma\right)\right)\right) \operatorname{\lambda_{s0}}\left(1,\operatorname{sign}\left(\operatorname{\arg}\left(\sigma\right)\right)\right) & \text{for}\: \arg(\omega) = 0 \wedge \arg(\sigma) \ne 0) \\\operatorname{\lambda_{s0}}\left(\operatorname{sign}\left(\operatorname{\arg}\left(\omega\right)\right),\operatorname{sign}\left(\operatorname{\arg}\left(\sigma\right)\right)\right) & \text{otherwise} \end{cases} .. math:: z_0 = \frac{\omega}{\sigma} e^{-i\pi (b^* + c^*)} .. math:: z_1 = \frac{\sigma}{\omega} e^{-i\pi (b^* + c^*)} The following conditions will be helpful: .. math:: C_1: (a_i - b_j \notin \mathbb{Z}_{>0} \text{ for } i = 1, \ldots, n, j = 1, \ldots, m) \\ \wedge (c_i - d_j \notin \mathbb{Z}_{>0} \text{ for } i = 1, \ldots, t, j = 1, \ldots, s) .. math:: C_2: \Re(1 + b_i + d_j) > 0 \text{ for } i = 1, \ldots, m, j = 1, \ldots, s .. math:: C_3: \Re(a_i + c_j) < 1 \text{ for } i = 1, \ldots, n, j = 1, \ldots, t .. math:: C_4: (p - q)\Re(c_i) - \Re(\mu) > -\frac{3}{2} \text{ for } i=1, \ldots, t .. math:: C_5: (p - q)\Re(1 + d_i) - \Re(\mu) > -\frac{3}{2} \text{ for } i=1, \ldots, s .. math:: C_6: (u - v)\Re(a_i) - \Re(\rho) > -\frac{3}{2} \text{ for } i=1, \ldots, n .. math:: C_7: (u - v)\Re(1 + b_i) - \Re(\rho) > -\frac{3}{2} \text{ for } i=1, \ldots, m .. math:: C_8: 0 < \lvert{\phi}\rvert + 2 \Re\left(\left(\mu -1\right) \left(- u + v\right) + \left(- p + q\right) \left(\rho -1\right) + \left(- p + q\right) \left(- u + v\right)\right) .. math:: C_9: 0 < \lvert{\phi}\rvert - 2 \Re\left(\left(\mu -1\right) \left(- u + v\right) + \left(- p + q\right) \left(\rho -1\right) + \left(- p + q\right) \left(- u + v\right)\right) .. math:: C_{10}: \lvert{\operatorname{arg}\left(\sigma\right)}\rvert < \pi b^{*} .. math:: C_{11}: \lvert{\operatorname{arg}\left(\sigma\right)}\rvert = \pi b^{*} .. math:: C_{12}: |\arg(\omega)| < c^*\pi .. math:: C_{13}: |\arg(\omega)| = c^*\pi .. math:: C_{14}^1: \left(z_0 \ne 1 \wedge |\arg(1 - z_0)| < \pi \right) \vee \left(z_0 = 1 \wedge \Re(\mu + \rho - u + v) < 1 \right) .. math:: C_{14}^2: \left(z_1 \ne 1 \wedge |\arg(1 - z_1)| < \pi \right) \vee \left(z_1 = 1 \wedge \Re(\mu + \rho - p + q) < 1 \right) .. math:: C_{14}: \phi = 0 \wedge b^* + c^* \le 1 \wedge (C_{14}^1 \vee C_{14}^2) .. math:: C_{15}: \lambda_c > 0 \vee (\lambda_c = 0 \wedge \lambda_s \ne 0 \wedge \Re(\eta) > -1) \vee (\lambda_c = 0 \wedge \lambda_s = 0 \wedge \Re(\eta) > 0) .. math:: C_{16}: \int_0^\infty G_{u, v}^{s, t}(\sigma x) \mathrm{d} x \text{ converges at infinity } .. math:: C_{17}: \int_0^\infty G_{p, q}^{m, n}(\omega x) \mathrm{d} x \text{ converges at infinity } Note that `C_{16}` and `C_{17}` are the reason we split the convergence conditions for integral (1). With this notation established, the implemented convergence conditions can be enumerated as follows: 1. .. math:: m n s t \neq 0 \wedge 0 < b^{*} \wedge 0 < c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{10} \wedge C_{12} 2. .. math:: u = v \wedge b^{*} = 0 \wedge 0 < c^{*} \wedge 0 < \sigma \wedge \Re{\rho} < 1 \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{12} 3. .. math:: p = q \wedge u = v \wedge b^{*} = 0 \wedge c^{*} = 0 \wedge 0 < \sigma \wedge 0 < \omega \wedge \Re{\mu} < 1 \wedge \Re{\rho} < 1 \wedge \sigma \neq \omega \wedge C_{1} \wedge C_{2} \wedge C_{3} 4. .. math:: p = q \wedge u = v \wedge b^{*} = 0 \wedge c^{*} = 0 \wedge 0 < \sigma \wedge 0 < \omega \wedge \Re\left(\mu + \rho\right) < 1 \wedge \omega \neq \sigma \wedge C_{1} \wedge C_{2} \wedge C_{3} 5. .. math:: p = q \wedge u = v \wedge b^{*} = 0 \wedge c^{*} = 0 \wedge 0 < \sigma \wedge 0 < \omega \wedge \Re\left(\mu + \rho\right) < 1 \wedge \omega \neq \sigma \wedge C_{1} \wedge C_{2} \wedge C_{3} 6. .. math:: q < p \wedge 0 < s \wedge 0 < b^{*} \wedge 0 \leq c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{5} \wedge C_{10} \wedge C_{13} 7. .. math:: p < q \wedge 0 < t \wedge 0 < b^{*} \wedge 0 \leq c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{4} \wedge C_{10} \wedge C_{13} 8. .. math:: v < u \wedge 0 < m \wedge 0 < c^{*} \wedge 0 \leq b^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{7} \wedge C_{11} \wedge C_{12} 9. .. math:: u < v \wedge 0 < n \wedge 0 < c^{*} \wedge 0 \leq b^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{6} \wedge C_{11} \wedge C_{12} 10. .. math:: q < p \wedge u = v \wedge b^{*} = 0 \wedge 0 \leq c^{*} \wedge 0 < \sigma \wedge \Re{\rho} < 1 \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{5} \wedge C_{13} 11. .. math:: p < q \wedge u = v \wedge b^{*} = 0 \wedge 0 \leq c^{*} \wedge 0 < \sigma \wedge \Re{\rho} < 1 \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{4} \wedge C_{13} 12. .. math:: p = q \wedge v < u \wedge 0 \leq b^{*} \wedge c^{*} = 0 \wedge 0 < \omega \wedge \Re{\mu} < 1 \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{7} \wedge C_{11} 13. .. math:: p = q \wedge u < v \wedge 0 \leq b^{*} \wedge c^{*} = 0 \wedge 0 < \omega \wedge \Re{\mu} < 1 \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{6} \wedge C_{11} 14. .. math:: p < q \wedge v < u \wedge 0 \leq b^{*} \wedge 0 \leq c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{4} \wedge C_{7} \wedge C_{11} \wedge C_{13} 15. .. math:: q < p \wedge u < v \wedge 0 \leq b^{*} \wedge 0 \leq c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{5} \wedge C_{6} \wedge C_{11} \wedge C_{13} 16. .. math:: q < p \wedge v < u \wedge 0 \leq b^{*} \wedge 0 \leq c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{5} \wedge C_{7} \wedge C_{8} \wedge C_{11} \wedge C_{13} \wedge C_{14} 17. .. math:: p < q \wedge u < v \wedge 0 \leq b^{*} \wedge 0 \leq c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{4} \wedge C_{6} \wedge C_{9} \wedge C_{11} \wedge C_{13} \wedge C_{14} 18. .. math:: t = 0 \wedge 0 < s \wedge 0 < b^{*} \wedge 0 < \phi \wedge C_{1} \wedge C_{2} \wedge C_{10} 19. .. math:: s = 0 \wedge 0 < t \wedge 0 < b^{*} \wedge \phi < 0 \wedge C_{1} \wedge C_{3} \wedge C_{10} 20. .. math:: n = 0 \wedge 0 < m \wedge 0 < c^{*} \wedge \phi < 0 \wedge C_{1} \wedge C_{2} \wedge C_{12} 21. .. math:: m = 0 \wedge 0 < n \wedge 0 < c^{*} \wedge 0 < \phi \wedge C_{1} \wedge C_{3} \wedge C_{12} 22. .. math:: s t = 0 \wedge 0 < b^{*} \wedge 0 < c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{10} \wedge C_{12} 23. .. math:: m n = 0 \wedge 0 < b^{*} \wedge 0 < c^{*} \wedge C_{1} \wedge C_{2} \wedge C_{3} \wedge C_{10} \wedge C_{12} 24. .. math:: p < m + n \wedge t = 0 \wedge \phi = 0 \wedge 0 < s \wedge 0 < b^{*} \wedge c^{*} < 0 \wedge \lvert{\operatorname{arg}\left(\omega\right)}\rvert < \pi \left(m + n - p + 1\right) \wedge C_{1} \wedge C_{2} \wedge C_{10} \wedge C_{14} \wedge C_{15} 25. .. math:: q < m + n \wedge s = 0 \wedge \phi = 0 \wedge 0 < t \wedge 0 < b^{*} \wedge c^{*} < 0 \wedge \lvert{\operatorname{arg}\left(\omega\right)}\rvert < \pi \left(m + n - q + 1\right) \wedge C_{1} \wedge C_{3} \wedge C_{10} \wedge C_{14} \wedge C_{15} 26. .. math:: p = q -1 \wedge t = 0 \wedge \phi = 0 \wedge 0 < s \wedge 0 < b^{*} \wedge 0 \leq c^{*} \wedge \pi c^{*} < \lvert{\operatorname{arg}\left(\omega\right)}\rvert \wedge C_{1} \wedge C_{2} \wedge C_{10} \wedge C_{14} \wedge C_{15} 27. .. math:: p = q + 1 \wedge s = 0 \wedge \phi = 0 \wedge 0 < t \wedge 0 < b^{*} \wedge 0 \leq c^{*} \wedge \pi c^{*} < \lvert{\operatorname{arg}\left(\omega\right)}\rvert \wedge C_{1} \wedge C_{3} \wedge C_{10} \wedge C_{14} \wedge C_{15} 28. .. math:: p < q -1 \wedge t = 0 \wedge \phi = 0 \wedge 0 < s \wedge 0 < b^{*} \wedge 0 \leq c^{*} \wedge \pi c^{*} < \lvert{\operatorname{arg}\left(\omega\right)}\rvert \wedge \lvert{\operatorname{arg}\left(\omega\right)}\rvert < \pi \left(m + n - p + 1\right) \wedge C_{1} \wedge C_{2} \wedge C_{10} \wedge C_{14} \wedge C_{15} 29. .. math:: q + 1 < p \wedge s = 0 \wedge \phi = 0 \wedge 0 < t \wedge 0 < b^{*} \wedge 0 \leq c^{*} \wedge \pi c^{*} < \lvert{\operatorname{arg}\left(\omega\right)}\rvert \wedge \lvert{\operatorname{arg}\left(\omega\right)}\rvert < \pi \left(m + n - q + 1 \right) \wedge C_{1} \wedge C_{3} \wedge C_{10} \wedge C_{14} \wedge C_{15} 30. .. math:: n = 0 \wedge \phi = 0 \wedge 0 < s + t \wedge 0 < m \wedge 0 < c^{*} \wedge b^{*} < 0 \wedge \lvert{\operatorname{arg}\left(\sigma\right)}\rvert < \pi \left(s + t - u + 1\right) \wedge C_{1} \wedge C_{2} \wedge C_{12} \wedge C_{14} \wedge C_{15} 31. .. math:: m = 0 \wedge \phi = 0 \wedge v < s + t \wedge 0 < n \wedge 0 < c^{*} \wedge b^{*} < 0 \wedge \lvert{\operatorname{arg}\left(\sigma\right)}\rvert < \pi \left(s + t - v + 1\right) \wedge C_{1} \wedge C_{3} \wedge C_{12} \wedge C_{14} \wedge C_{15} 32. .. math:: n = 0 \wedge \phi = 0 \wedge u = v -1 \wedge 0 < m \wedge 0 < c^{*} \wedge 0 \leq b^{*} \wedge \pi b^{*} < \lvert{\operatorname{arg}\left(\sigma\right)}\rvert \wedge \lvert{\operatorname{arg}\left(\sigma\right)}\rvert < \pi \left(b^{*} + 1\right) \wedge C_{1} \wedge C_{2} \wedge C_{12} \wedge C_{14} \wedge C_{15} 33. .. math:: m = 0 \wedge \phi = 0 \wedge u = v + 1 \wedge 0 < n \wedge 0 < c^{*} \wedge 0 \leq b^{*} \wedge \pi b^{*} < \lvert{\operatorname{arg}\left(\sigma\right)}\rvert \wedge \lvert{\operatorname{arg}\left(\sigma\right)}\rvert < \pi \left(b^{*} + 1\right) \wedge C_{1} \wedge C_{3} \wedge C_{12} \wedge C_{14} \wedge C_{15} 34. .. math:: n = 0 \wedge \phi = 0 \wedge u < v -1 \wedge 0 < m \wedge 0 < c^{*} \wedge 0 \leq b^{*} \wedge \pi b^{*} < \lvert{\operatorname{arg}\left(\sigma\right)}\rvert \wedge \lvert{\operatorname{arg}\left(\sigma\right)}\rvert < \pi \left(s + t - u + 1\right) \wedge C_{1} \wedge C_{2} \wedge C_{12} \wedge C_{14} \wedge C_{15} 35. .. math:: m = 0 \wedge \phi = 0 \wedge v + 1 < u \wedge 0 < n \wedge 0 < c^{*} \wedge 0 \leq b^{*} \wedge \pi b^{*} < \lvert{\operatorname{arg}\left(\sigma\right)}\rvert \wedge \lvert{\operatorname{arg}\left(\sigma\right)}\rvert < \pi \left(s + t - v + 1 \right) \wedge C_{1} \wedge C_{3} \wedge C_{12} \wedge C_{14} \wedge C_{15} 36. .. math:: C_{17} \wedge t = 0 \wedge u < s \wedge 0 < b^{*} \wedge C_{10} \wedge C_{1} \wedge C_{2} \wedge C_{3} 37. .. math:: C_{17} \wedge s = 0 \wedge v < t \wedge 0 < b^{*} \wedge C_{10} \wedge C_{1} \wedge C_{2} \wedge C_{3} 38. .. math:: C_{16} \wedge n = 0 \wedge p < m \wedge 0 < c^{*} \wedge C_{12} \wedge C_{1} \wedge C_{2} \wedge C_{3} 39. .. math:: C_{16} \wedge m = 0 \wedge q < n \wedge 0 < c^{*} \wedge C_{12} \wedge C_{1} \wedge C_{2} \wedge C_{3} The Inverse Laplace Transform of a G-function ********************************************* The inverse laplace transform of a Meijer G-function can be expressed as another G-function. This is a fairly versatile method for computing this transform. However, I could not find the details in the literature, so I work them out here. In [Luke1969]_, section 5.6.3, there is a formula for the inverse Laplace transform of a G-function of argument `bz`, and convergence conditions are also given. However, we need a formula for argument `bz^a` for rational `a`. We are asked to compute .. math :: f(t) = \frac{1}{2\pi i} \int_{c-i\infty}^{c+i\infty} e^{zt} G(bz^a) \mathrm{d}z, for positive real `t`. Three questions arise: 1. When does this integral converge? 2. How can we compute the integral? 3. When is our computation valid? How to compute the integral =========================== We shall work formally for now. Denote by `\Delta(s)` the product of gamma functions appearing in the definition of `G`, so that .. math :: G(z) = \frac{1}{2\pi i} \int_L \Delta(s) z^s \mathrm{d}s. Thus .. math :: f(t) = \frac{1}{(2\pi i)^2} \int_{c - i\infty}^{c + i\infty} \int_L e^{zt} \Delta(s) b^s z^{as} \mathrm{d}s \mathrm{d}z. We interchange the order of integration to get .. math :: f(t) = \frac{1}{2\pi i} \int_L b^s \Delta(s) \int_{c-i\infty}^{c+i\infty} e^{zt} z^{as} \frac{\mathrm{d}z}{2\pi i} \mathrm{d}s. The inner integral is easily seen to be `\frac{1}{\Gamma(-as)} \frac{1}{t^{1+as}}`. (Using Cauchy's theorem and Jordan's lemma deform the contour to run from `-\infty` to `-\infty`, encircling `0` once in the negative sense. For `as` real and greater than one, this contour can be pushed onto the negative real axis and the integral is recognised as a product of a sine and a gamma function. The formula is then proved using the functional equation of the gamma function, and extended to the entire domain of convergence of the original integral by appealing to analytic continuation.) Hence we find .. math :: f(t) = \frac{1}{t} \frac{1}{2\pi i} \int_L \Delta(s) \frac{1}{\Gamma(-as)} \left(\frac{b}{t^a}\right)^s \mathrm{d}s, which is a so-called Fox H function (of argument `\frac{b}{t^a}`). For rational `a`, this can be expressed as a Meijer G-function using the gamma function multiplication theorem. When this computation is valid ============================== There are a number of obstacles in this computation. Interchange of integrals is only valid if all integrals involved are absolutely convergent. In particular the inner integral has to converge. Also, for our identification of the final integral as a Fox H / Meijer G-function to be correct, the poles of the newly obtained gamma function must be separated properly. It is easy to check that the inner integral converges absolutely for `\Re(as) < -1`. Thus the contour `L` has to run left of the line `\Re(as) = -1`. Under this condition, the poles of the newly-introduced gamma function are separated properly. It remains to observe that the Meijer G-function is an analytic, unbranched function of its parameters, and of the coefficient `b`. Hence so is `f(t)`. Thus the final computation remains valid as long as the initial integral converges, and if there exists a changed set of parameters where the computation is valid. If we assume w.l.o.g. that `a > 0`, then the latter condition is fulfilled if `G` converges along contours (2) or (3) of [Luke1969]_, section 5.2, i.e. either `\delta >= \frac{a}{2}` or `p \ge 1, p \ge q`. When the integral exists ======================== Using [Luke1969]_, section 5.10, for any given meijer G-function we can find a dominant term of the form `z^a e^{bz^c}` (although this expression might not be the best possible, because of cancellation). We must thus investigate .. math :: \lim_{T \to \infty} \int_{c-iT}^{c+iT} e^{zt} z^a e^{bz^c} \mathrm{d}z. (This principal value integral is the exact statement used in the Laplace inversion theorem.) We write `z = c + i \tau`. Then `arg(z) \to \pm \frac{\pi}{2}`, and so `e^{zt} \sim e^{it \tau}` (where `\sim` shall always mean "asymptotically equivalent up to a positive real multiplicative constant"). Also `z^{x + iy} \sim |\tau|^x e^{i y \log{|\tau|}} e^{\pm x i \frac{\pi}{2}}.` Set `\omega_{\pm} = b e^{\pm i \Re(c) \frac{\pi}{2}}`. We have three cases: 1. `b=0` or `\Re(c) \le 0`. In this case the integral converges if `\Re(a) \le -1`. 2. `b \ne 0`, `\Im(c) = 0`, `\Re(c) > 0`. In this case the integral converges if `\Re(\omega_{\pm}) < 0`. 3. `b \ne 0`, `\Im(c) = 0`, `\Re(c) > 0`, `\Re(\omega_{\pm}) \le 0`, and at least one of `\Re(\omega_{\pm}) = 0`. Here the same condition as in (1) applies. Implemented G-Function Formulae ******************************* An important part of the algorithm is a table expressing various functions as Meijer G-functions. This is essentially a table of Mellin Transforms in disguise. The following automatically generated table shows the formulae currently implemented in SymPy. An entry "generated" means that the corresponding G-function has a variable number of parameters. This table is intended to shrink in future, when the algorithm's capabilities of deriving new formulae improve. Of course it has to grow whenever a new class of special functions is to be dealt with. .. automodule:: sympy.integrals.meijerint_doc Internal API Reference ********************** .. automodule:: sympy.integrals.meijerint :members: :private-members: sympy-sympy-1.9/doc/src/modules/integrals/integrals.rst000066400000000000000000000311701412543434000234430ustar00rootroot00000000000000========= Integrals ========= .. module:: sympy.integrals The ``integrals`` module in SymPy implements methods to calculate definite and indefinite integrals of expressions. Principal method in this module is :func:`~.integrate` - ``integrate(f, x)`` returns the indefinite integral :math:`\int f\,dx` - ``integrate(f, (x, a, b))`` returns the definite integral :math:`\int_{a}^{b} f\,dx` Examples -------- SymPy can integrate a vast array of functions. It can integrate polynomial functions:: >>> from sympy import * >>> init_printing(use_unicode=False, wrap_line=False) >>> x = Symbol('x') >>> integrate(x**2 + x + 1, x) 3 2 x x -- + -- + x 3 2 Rational functions:: >>> integrate(x/(x**2+2*x+1), x) 1 log(x + 1) + ----- x + 1 Exponential-polynomial functions. These multiplicative combinations of polynomials and the functions ``exp``, ``cos`` and ``sin`` can be integrated by hand using repeated integration by parts, which is an extremely tedious process. Happily, SymPy will deal with these integrals. :: >>> integrate(x**2 * exp(x) * cos(x), x) 2 x 2 x x x x *e *sin(x) x *e *cos(x) x e *sin(x) e *cos(x) ------------ + ------------ - x*e *sin(x) + --------- - --------- 2 2 2 2 even a few nonelementary integrals (in particular, some integrals involving the error function) can be evaluated:: >>> integrate(exp(-x**2)*erf(x), x) ____ 2 \/ pi *erf (x) -------------- 4 Integral Transforms ------------------- .. module:: sympy.integrals.transforms SymPy has special support for definite integrals, and integral transforms. .. autofunction:: mellin_transform .. autoclass:: MellinTransform :members: .. autofunction:: inverse_mellin_transform .. autoclass:: InverseMellinTransform :members: .. autofunction:: laplace_transform .. autoclass:: LaplaceTransform :members: .. autofunction:: inverse_laplace_transform .. autoclass:: InverseLaplaceTransform :members: .. autofunction:: _fast_inverse_laplace .. autofunction:: fourier_transform .. autofunction:: _fourier_transform .. autoclass:: FourierTransform :members: .. autofunction:: inverse_fourier_transform .. autoclass:: InverseFourierTransform :members: .. autofunction:: sine_transform .. autoclass:: SineTransform :members: .. autofunction:: inverse_sine_transform .. autoclass:: InverseSineTransform :members: .. autofunction:: cosine_transform .. autoclass:: CosineTransform :members: .. autofunction:: inverse_cosine_transform .. autoclass:: InverseCosineTransform :members: .. autofunction:: hankel_transform .. autoclass:: HankelTransform :members: .. autofunction:: inverse_hankel_transform .. autoclass:: InverseHankelTransform :members: .. autoclass:: IntegralTransform :members: .. autoexception:: IntegralTransformError Internals --------- SymPy uses a number of algorithms to compute integrals. Algorithms are tried in order until one produces an answer. Most of these algorithms can be enabled or disabled manually using various flags to :func:`~.integrate` or :meth:`~.Integral.doit`. SymPy first applies several heuristic algorithms, as these are the fastest: 1. If the function is a rational function, there is a complete algorithm for integrating rational functions called the Lazard-Rioboo-Trager and the Horowitz-Ostrogradsky algorithms. They are implemented in :func:`.ratint`. .. autofunction:: sympy.integrals.rationaltools::ratint .. autofunction:: sympy.integrals.rationaltools::ratint_ratpart .. autofunction:: sympy.integrals.rationaltools::ratint_logpart 2. :func:`.trigintegrate` solves integrals of trigonometric functions using pattern matching .. autofunction:: sympy.integrals.trigonometry::trigintegrate 3. :func:`.deltaintegrate` solves integrals with :class:`~.DiracDelta` objects. .. autofunction:: sympy.integrals.deltafunctions::deltaintegrate 4. :func:`.singularityintegrate` is applied if the function contains a :class:`~.SingularityFunction` .. autofunction:: sympy.integrals.singularityfunctions::singularityintegrate 5. If the heuristic algorithms cannot be applied, :func:`.risch_integrate` is tried next. The *Risch algorithm* is a general method for calculating antiderivatives of elementary functions. The Risch algorithm is a decision procedure that can determine whether an elementary solution exists, and in that case calculate it. It can be extended to handle many nonelementary functions in addition to the elementary ones. However, the version implemented in SymPy only supports a small subset of the full algorithm, particularly, on part of the transcendental algorithm for exponentials and logarithms is implemented. An advantage of :func:`.risch_integrate` over other methods is that if it returns an instance of :class:`.NonElementaryIntegral`, the integral is proven to be nonelementary by the algorithm, meaning the integral cannot be represented using a combination of exponentials, logarithms, trig functions, powers, rational functions, algebraic functions, and function composition. .. autofunction:: sympy.integrals.risch::risch_integrate .. autoclass:: sympy.integrals.risch::NonElementaryIntegral :members: 6. For non-elementary definite integrals, SymPy uses so-called Meijer G-functions. Details are described in :ref:`g-functions`. 7. All the algorithms mentioned thus far are either pattern-matching based heuristic, or solve integrals using algorithms that are much different from the way most people are taught in their calculus courses. SymPy also implements a method that can solve integrals in much the same way you would in calculus. The advantage of this method is that it is possible to extract the integration steps from, so that one can see how to compute the integral "by hand". This is used by `SymPy Gamma `_. This is implemented in the :func:`.manualintegrate` function. The steps for an integral can be seen with the :func:`.integral_steps` function. .. autofunction:: sympy.integrals.manualintegrate::manualintegrate .. autofunction:: sympy.integrals.manualintegrate::integral_steps 8. Finally, if all the above fail, SymPy also uses a simplified version of the Risch algorithm, called the *Risch-Norman algorithm*. This algorithm is tried last because it is often the slowest to compute. This is implemented in :func:`.heurisch`: .. autofunction:: sympy.integrals.heurisch::heurisch .. autofunction:: sympy.integrals.heurisch::components API reference ------------- .. autofunction:: sympy.integrals.integrals::integrate .. autofunction:: sympy.integrals.integrals::line_integrate The class :class:`~.Integral` represents an unevaluated integral and has some methods that help in the integration of an expression. .. autoclass:: sympy.integrals.integrals::Integral :members: .. data:: is_commutative Returns whether all the free symbols in the integral are commutative. :class:`~.Integral` subclasses from :class:`~.ExprWithLimits`, which is a common superclass of :class:`~.Integral` and :class:`~.Sum`. .. autoclass:: sympy.concrete.expr_with_limits::ExprWithLimits :members: TODO and Bugs ------------- There are still lots of functions that SymPy does not know how to integrate. For bugs related to this module, see https://github.com/sympy/sympy/issues?q=is%3Aissue+is%3Aopen+label%3Aintegrals Numeric Integrals ================= SymPy has functions to calculate points and weights for Gaussian quadrature of any order and any precision: .. autofunction:: sympy.integrals.quadrature::gauss_legendre .. autofunction:: sympy.integrals.quadrature::gauss_laguerre .. autofunction:: sympy.integrals.quadrature::gauss_hermite .. autofunction:: sympy.integrals.quadrature::gauss_gen_laguerre .. autofunction:: sympy.integrals.quadrature::gauss_chebyshev_t .. autofunction:: sympy.integrals.quadrature::gauss_chebyshev_u .. autofunction:: sympy.integrals.quadrature::gauss_jacobi .. autofunction:: sympy.integrals.quadrature::gauss_lobatto Integration over Polytopes ========================== .. module:: sympy.integrals.intpoly The ``intpoly`` module in SymPy implements methods to calculate the integral of a polynomial over 2/3-Polytopes. Uses evaluation techniques as described in Chin et al. (2015) [1]. The input for 2-Polytope or Polygon uses the already existing ``Polygon`` data structure in SymPy. See :mod:`sympy.geometry.polygon` for how to create a polygon. For the 3-Polytope or Polyhedron, the most economical representation is to specify a list of vertices and then to provide each constituting face(Polygon) as a list of vertex indices. For example, consider the unit cube. Here is how it would be represented. ``unit_cube = [[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0),(1, 0, 1), (1, 1, 0), (1, 1, 1)],`` ``[3, 7, 6, 2], [1, 5, 7, 3], [5, 4, 6, 7], [0, 4, 5, 1], [2, 0, 1, 3], [2, 6, 4, 0]]`` Here, the first sublist is the list of vertices. The other smaller lists such as ``[3, 7, 6, 2]`` represent a 2D face of the polyhedra with vertices having index ``3, 7, 6 and 2`` in the first sublist(in that order). Principal method in this module is :func:`polytope_integrate` - ``polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), x)`` returns the integral of :math:`x` over the triangle with vertices (0, 0), (0, 1) and (1, 0) - ``polytope_integrate(unit_cube, x + y + z)`` returns the integral of :math:`x + y + z` over the unit cube. References ---------- [1] : Chin, Eric B., Jean B. Lasserre, and N. Sukumar. "Numerical integration of homogeneous functions on convex and nonconvex polygons and polyhedra." Computational Mechanics 56.6 (2015): 967-981 PDF link : http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf Examples -------- For 2D Polygons --------------- Single Polynomial:: >>> from sympy.integrals.intpoly import * >>> init_printing(use_unicode=False, wrap_line=False) >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), x) 1/6 >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), x + x*y + y**2) 7/24 List of specified polynomials:: >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), [3, x*y + y**2, x**4], max_degree=4) 4 2 {3: 3/2, x : 1/30, x*y + y : 1/8} >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), [1.125, x, x**2, 6.89*x**3, x*y + y**2, x**4], max_degree=4) 2 3 689 4 2 {1.125: 9/16, x: 1/6, x : 1/12, 6.89*x : ----, x : 1/30, x*y + y : 1/8} 2000 Computing all monomials up to a maximum degree:: >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)),max_degree=3) 2 3 2 3 2 2 {0: 0, 1: 1/2, x: 1/6, x : 1/12, x : 1/20, y: 1/6, y : 1/12, y : 1/20, x*y: 1/24, x*y : 1/60, x *y: 1/60} For 3-Polytopes/Polyhedra ------------------------- Single Polynomial:: >>> from sympy.integrals.intpoly import * >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0), (5, 0, 5), (5, 5, 0), (5, 5, 5)], [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0], [3, 1, 0, 2], [0, 4, 6, 2]] >>> polytope_integrate(cube, x**2 + y**2 + z**2 + x*y + y*z + x*z) -21875/4 >>> octahedron = [[(S(-1) / sqrt(2), 0, 0), (0, S(1) / sqrt(2), 0), (0, 0, S(-1) / sqrt(2)), (0, 0, S(1) / sqrt(2)), (0, S(-1) / sqrt(2), 0), (S(1) / sqrt(2), 0, 0)], [3, 4, 5], [3, 5, 1], [3, 1, 0], [3, 0, 4], [4, 0, 2], [4, 2, 5], [2, 0, 1], [5, 2, 1]] >>> polytope_integrate(octahedron, x**2 + y**2 + z**2 + x*y + y*z + x*z) ___ \/ 2 ----- 20 List of specified polynomials:: >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), [3, x*y + y**2, x**4], max_degree=4) 4 2 {3: 3/2, x : 1/30, x*y + y : 1/8} >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)), [1.125, x, x**2, 6.89*x**3, x*y + y**2, x**4], max_degree=4) 2 3 689 4 2 {1.125: 9/16, x: 1/6, x : 1/12, 6.89*x : ----, x : 1/30, x*y + y : 1/8} 2000 Computing all monomials up to a maximum degree:: >>> polytope_integrate(Polygon((0, 0), (0, 1), (1, 0)),max_degree=3) 2 3 2 3 2 2 {0: 0, 1: 1/2, x: 1/6, x : 1/12, x : 1/20, y: 1/6, y : 1/12, y : 1/20, x*y: 1/24, x*y : 1/60, x *y: 1/60} API reference ------------- .. autofunction:: sympy.integrals.intpoly::polytope_integrate sympy-sympy-1.9/doc/src/modules/interactive.rst000066400000000000000000000003411412543434000217740ustar00rootroot00000000000000============= Interactive ============= .. automodule:: sympy.interactive Session ======= .. automodule:: sympy.interactive.session :members: Printing ======== .. automodule:: sympy.interactive.printing :members: sympy-sympy-1.9/doc/src/modules/liealgebras/000077500000000000000000000000001412543434000212015ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/liealgebras/index.rst000066400000000000000000000016221412543434000230430ustar00rootroot00000000000000=========== Lie Algebra =========== .. automodule:: sympy.liealgebras .. autoclass:: sympy.liealgebras.root_system.RootSystem :members: .. autoclass:: sympy.liealgebras.type_a.TypeA :members: .. autoclass:: sympy.liealgebras.type_b.TypeB :members: .. autoclass:: sympy.liealgebras.type_c.TypeC :members: .. autoclass:: sympy.liealgebras.type_d.TypeD :members: .. autoclass:: sympy.liealgebras.type_e.TypeE :members: .. autoclass:: sympy.liealgebras.type_f.TypeF :members: .. autoclass:: sympy.liealgebras.type_g.TypeG :members: .. autoclass:: sympy.liealgebras.weyl_group.WeylGroup :members: .. autoclass:: sympy.liealgebras.cartan_type.CartanType_generator :members: .. autoclass:: sympy.liealgebras.cartan_type.Standard_Cartan :members: .. autofunction:: sympy.liealgebras.dynkin_diagram.DynkinDiagram .. autofunction:: sympy.liealgebras.cartan_matrix.CartanMatrix sympy-sympy-1.9/doc/src/modules/logic.rst000066400000000000000000000063561412543434000205700ustar00rootroot00000000000000===== Logic ===== .. module:: sympy.logic Introduction ------------ The logic module for SymPy allows to form and manipulate logic expressions using symbolic and Boolean values. Forming logical expressions --------------------------- You can build Boolean expressions with the standard python operators ``&`` (:class:`~.And`), ``|`` (:class:`~.Or`), ``~`` (:class:`~.Not`):: >>> from sympy import * >>> x, y = symbols('x,y') >>> y | (x & y) y | (x & y) >>> x | y x | y >>> ~x ~x You can also form implications with ``>>`` and ``<<``:: >>> x >> y Implies(x, y) >>> x << y Implies(y, x) Like most types in SymPy, Boolean expressions inherit from :class:`~.Basic`:: >>> (y & x).subs({x: True, y: True}) True >>> (x | y).atoms() {x, y} The logic module also includes the following functions to derive boolean expressions from their truth tables- .. autofunction:: sympy.logic.boolalg::SOPform .. autofunction:: sympy.logic.boolalg::POSform Boolean functions ----------------- .. autoclass:: sympy.logic.boolalg::Boolean :members: .. autoclass:: sympy.logic.boolalg::BooleanTrue :members: .. autoclass:: sympy.logic.boolalg::BooleanFalse :members: .. autoclass:: sympy.logic.boolalg::And :members: .. autoclass:: sympy.logic.boolalg::Or :members: .. autoclass:: sympy.logic.boolalg::Not :members: .. autoclass:: sympy.logic.boolalg::Xor :members: .. autoclass:: sympy.logic.boolalg::Nand :members: .. autoclass:: sympy.logic.boolalg::Nor :members: .. autoclass:: sympy.logic.boolalg::Implies :members: .. autoclass:: sympy.logic.boolalg::Equivalent :members: .. autoclass:: sympy.logic.boolalg::ITE :members: The following functions can be used to handle Conjunctive and Disjunctive Normal forms- .. autofunction:: sympy.logic.boolalg::to_cnf .. autofunction:: sympy.logic.boolalg::to_dnf .. autofunction:: sympy.logic.boolalg::is_cnf .. autofunction:: sympy.logic.boolalg::is_dnf Simplification and equivalence-testing -------------------------------------- .. autofunction:: sympy.logic.boolalg::simplify_logic SymPy's simplify() function can also be used to simplify logic expressions to their simplest forms. .. autofunction:: sympy.logic.boolalg::bool_map Inference --------- .. module:: sympy.logic.inference This module implements some inference routines in propositional logic. The function satisfiable will test that a given Boolean expression is satisfiable, that is, you can assign values to the variables to make the sentence `True`. For example, the expression ``x & ~x`` is not satisfiable, since there are no values for ``x`` that make this sentence ``True``. On the other hand, ``(x | y) & (x | ~y) & (~x | y)`` is satisfiable with both ``x`` and ``y`` being ``True``. >>> from sympy.logic.inference import satisfiable >>> from sympy import Symbol >>> x = Symbol('x') >>> y = Symbol('y') >>> satisfiable(x & ~x) False >>> satisfiable((x | y) & (x | ~y) & (~x | y)) {x: True, y: True} As you see, when a sentence is satisfiable, it returns a model that makes that sentence ``True``. If it is not satisfiable it will return ``False``. .. autofunction:: sympy.logic.inference::satisfiable .. TODO: write about CNF file format sympy-sympy-1.9/doc/src/modules/matrices/000077500000000000000000000000001412543434000205365ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/matrices/common.rst000066400000000000000000000003231412543434000225560ustar00rootroot00000000000000Common Matrices =============== .. module:: sympy.matrices.common MatrixCommon Class Reference ---------------------------- .. autoclass:: MatrixCommon :members: :special-members: :inherited-members: sympy-sympy-1.9/doc/src/modules/matrices/dense.rst000066400000000000000000000006451412543434000223730ustar00rootroot00000000000000Dense Matrices ============== Matrix Class Reference ---------------------- .. autoclass:: sympy.matrices.dense::Matrix :members: .. autoclass:: sympy.matrices.dense::DenseMatrix :members: .. autoclass:: sympy.matrices.dense::MutableDenseMatrix :members: ImmutableMatrix Class Reference ------------------------------- .. autoclass:: sympy.matrices.immutable::ImmutableDenseMatrix :members: :noindex: sympy-sympy-1.9/doc/src/modules/matrices/expressions.rst000066400000000000000000000032431412543434000236540ustar00rootroot00000000000000Matrix Expressions ================== .. module:: sympy.matrices.expressions The Matrix expression module allows users to write down statements like >>> from sympy import MatrixSymbol, Matrix >>> X = MatrixSymbol('X', 3, 3) >>> Y = MatrixSymbol('Y', 3, 3) >>> (X.T*X).I*Y X**(-1)*X.T**(-1)*Y >>> Matrix(X) Matrix([ [X[0, 0], X[0, 1], X[0, 2]], [X[1, 0], X[1, 1], X[1, 2]], [X[2, 0], X[2, 1], X[2, 2]]]) >>> (X*Y)[1, 2] X[1, 0]*Y[0, 2] + X[1, 1]*Y[1, 2] + X[1, 2]*Y[2, 2] where ``X`` and ``Y`` are :class:`MatrixSymbol`'s rather than scalar symbols. Matrix Expressions Core Reference --------------------------------- .. autoclass:: MatrixExpr :members: .. autoclass:: MatrixSymbol :members: .. autoclass:: MatAdd :members: .. autoclass:: MatMul :members: .. autoclass:: MatPow :members: .. autoclass:: HadamardProduct :members: .. autoclass:: HadamardPower :members: .. autoclass:: Inverse :members: .. autoclass:: Transpose :members: .. autoclass:: Trace :members: .. autoclass:: FunctionMatrix :members: .. autoclass:: PermutationMatrix :members: .. autoclass:: MatrixPermute :members: .. autoclass:: Identity :members: .. autoclass:: ZeroMatrix :members: .. autoclass:: CompanionMatrix :members: .. autoclass:: MatrixSet :members: Block Matrices -------------- Block matrices allow you to construct larger matrices out of smaller sub-blocks. They can work with :class:`MatrixExpr` or :obj:`~.ImmutableMatrix` objects. .. module:: sympy.matrices.expressions.blockmatrix .. autoclass:: BlockMatrix :members: .. autoclass:: BlockDiagMatrix :members: .. autofunction:: block_collapse sympy-sympy-1.9/doc/src/modules/matrices/immutablematrices.rst000066400000000000000000000027461412543434000250100ustar00rootroot00000000000000Immutable Matrices ================== .. currentmodule:: sympy The standard :obj:`~.Matrix` class in SymPy is mutable. This is important for performance reasons but means that standard matrices cannot interact well with the rest of SymPy. This is because the :class:`~.Basic` object, from which most SymPy classes inherit, is immutable. The mission of the :class:`~.ImmutableDenseMatrix` class, which is aliased as :obj:`~.ImmutableMatrix` for short, is to bridge the tension between performance/mutability and safety/immutability. Immutable matrices can do almost everything that normal matrices can do but they inherit from :class:`~.Basic` and can thus interact more naturally with the rest of SymPy. :obj:`~.ImmutableMatrix` also inherits from :class:`~.MatrixExpr`, allowing it to interact freely with SymPy's Matrix Expression module. You can turn any Matrix-like object into an :obj:`~.ImmutableMatrix` by calling the constructor >>> from sympy import Matrix, ImmutableMatrix >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> M[1, 1] = 0 >>> IM = ImmutableMatrix(M) >>> IM Matrix([ [1, 2, 3], [4, 0, 6], [7, 8, 9]]) >>> IM[1, 1] = 5 Traceback (most recent call last): ... TypeError: Can not set values in Immutable Matrix. Use Matrix instead. ImmutableMatrix Class Reference ------------------------------- .. module:: sympy.matrices.immutable .. autoclass:: ImmutableMatrix :members: .. autoclass:: ImmutableDenseMatrix :members: sympy-sympy-1.9/doc/src/modules/matrices/index.rst000066400000000000000000000003611412543434000223770ustar00rootroot00000000000000.. _matrices-docs: ======== Matrices ======== .. automodule:: sympy.matrices Contents: .. toctree:: :maxdepth: 2 matrices.rst common.rst dense.rst sparse.rst sparsetools.rst immutablematrices.rst expressions.rst sympy-sympy-1.9/doc/src/modules/matrices/matrices.rst000066400000000000000000000335171412543434000231100ustar00rootroot00000000000000Matrices (linear algebra) ========================= .. module:: sympy.matrices.matrices Creating Matrices ----------------- The linear algebra module is designed to be as simple as possible. First, we import and declare our first ``Matrix`` object: >>> from sympy.interactive.printing import init_printing >>> init_printing(use_unicode=False, wrap_line=False) >>> from sympy.matrices import Matrix, eye, zeros, ones, diag, GramSchmidt >>> M = Matrix([[1,0,0], [0,0,0]]); M [1 0 0] [ ] [0 0 0] >>> Matrix([M, (0, 0, -1)]) [1 0 0 ] [ ] [0 0 0 ] [ ] [0 0 -1] >>> Matrix([[1, 2, 3]]) [1 2 3] >>> Matrix([1, 2, 3]) [1] [ ] [2] [ ] [3] In addition to creating a matrix from a list of appropriately-sized lists and/or matrices, SymPy also supports more advanced methods of matrix creation including a single list of values and dimension inputs: >>> Matrix(2, 3, [1, 2, 3, 4, 5, 6]) [1 2 3] [ ] [4 5 6] More interesting (and useful), is the ability to use a 2-variable function (or ``lambda``) to create a matrix. Here we create an indicator function which is 1 on the diagonal and then use it to make the identity matrix: >>> def f(i,j): ... if i == j: ... return 1 ... else: ... return 0 ... >>> Matrix(4, 4, f) [1 0 0 0] [ ] [0 1 0 0] [ ] [0 0 1 0] [ ] [0 0 0 1] Finally let's use ``lambda`` to create a 1-line matrix with 1's in the even permutation entries: >>> Matrix(3, 4, lambda i,j: 1 - (i+j) % 2) [1 0 1 0] [ ] [0 1 0 1] [ ] [1 0 1 0] There are also a couple of special constructors for quick matrix construction: ``eye`` is the identity matrix, ``zeros`` and ``ones`` for matrices of all zeros and ones, respectively, and ``diag`` to put matrices or elements along the diagonal: >>> eye(4) [1 0 0 0] [ ] [0 1 0 0] [ ] [0 0 1 0] [ ] [0 0 0 1] >>> zeros(2) [0 0] [ ] [0 0] >>> zeros(2, 5) [0 0 0 0 0] [ ] [0 0 0 0 0] >>> ones(3) [1 1 1] [ ] [1 1 1] [ ] [1 1 1] >>> ones(1, 3) [1 1 1] >>> diag(1, Matrix([[1, 2], [3, 4]])) [1 0 0] [ ] [0 1 2] [ ] [0 3 4] Basic Manipulation ------------------ While learning to work with matrices, let's choose one where the entries are readily identifiable. One useful thing to know is that while matrices are 2-dimensional, the storage is not and so it is allowable - though one should be careful - to access the entries as if they were a 1-d list. >>> M = Matrix(2, 3, [1, 2, 3, 4, 5, 6]) >>> M[4] 5 Now, the more standard entry access is a pair of indices which will always return the value at the corresponding row and column of the matrix: >>> M[1, 2] 6 >>> M[0, 0] 1 >>> M[1, 1] 5 Since this is Python we're also able to slice submatrices; slices always give a matrix in return, even if the dimension is 1 x 1:: >>> M[0:2, 0:2] [1 2] [ ] [4 5] >>> M[2:2, 2] [] >>> M[:, 2] [3] [ ] [6] >>> M[:1, 2] [3] In the second example above notice that the slice 2:2 gives an empty range. Note also (in keeping with 0-based indexing of Python) the first row/column is 0. You cannot access rows or columns that are not present unless they are in a slice: >>> M[:, 10] # the 10-th column (not there) Traceback (most recent call last): ... IndexError: Index out of range: a[[0, 10]] >>> M[:, 10:11] # the 10-th column (if there) [] >>> M[:, :10] # all columns up to the 10-th [1 2 3] [ ] [4 5 6] Slicing an empty matrix works as long as you use a slice for the coordinate that has no size: >>> Matrix(0, 3, [])[:, 1] [] Slicing gives a copy of what is sliced, so modifications of one object do not affect the other: >>> M2 = M[:, :] >>> M2[0, 0] = 100 >>> M[0, 0] == 100 False Notice that changing ``M2`` didn't change ``M``. Since we can slice, we can also assign entries: >>> M = Matrix(([1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16])) >>> M [1 2 3 4 ] [ ] [5 6 7 8 ] [ ] [9 10 11 12] [ ] [13 14 15 16] >>> M[2,2] = M[0,3] = 0 >>> M [1 2 3 0 ] [ ] [5 6 7 8 ] [ ] [9 10 0 12] [ ] [13 14 15 16] as well as assign slices: >>> M = Matrix(([1,2,3,4],[5,6,7,8],[9,10,11,12],[13,14,15,16])) >>> M[2:,2:] = Matrix(2,2,lambda i,j: 0) >>> M [1 2 3 4] [ ] [5 6 7 8] [ ] [9 10 0 0] [ ] [13 14 0 0] All the standard arithmetic operations are supported: >>> M = Matrix(([1,2,3],[4,5,6],[7,8,9])) >>> M - M [0 0 0] [ ] [0 0 0] [ ] [0 0 0] >>> M + M [2 4 6 ] [ ] [8 10 12] [ ] [14 16 18] >>> M * M [30 36 42 ] [ ] [66 81 96 ] [ ] [102 126 150] >>> M2 = Matrix(3,1,[1,5,0]) >>> M*M2 [11] [ ] [29] [ ] [47] >>> M**2 [30 36 42 ] [ ] [66 81 96 ] [ ] [102 126 150] As well as some useful vector operations: >>> M.row_del(0) >>> M [4 5 6] [ ] [7 8 9] >>> M.col_del(1) >>> M [4 6] [ ] [7 9] >>> v1 = Matrix([1,2,3]) >>> v2 = Matrix([4,5,6]) >>> v3 = v1.cross(v2) >>> v1.dot(v2) 32 >>> v2.dot(v3) 0 >>> v1.dot(v3) 0 Recall that the ``row_del()`` and ``col_del()`` operations don't return a value - they simply change the matrix object. We can also ''glue'' together matrices of the appropriate size: >>> M1 = eye(3) >>> M2 = zeros(3, 4) >>> M1.row_join(M2) [1 0 0 0 0 0 0] [ ] [0 1 0 0 0 0 0] [ ] [0 0 1 0 0 0 0] >>> M3 = zeros(4, 3) >>> M1.col_join(M3) [1 0 0] [ ] [0 1 0] [ ] [0 0 1] [ ] [0 0 0] [ ] [0 0 0] [ ] [0 0 0] [ ] [0 0 0] Operations on entries --------------------- We are not restricted to having multiplication between two matrices: >>> M = eye(3) >>> 2*M [2 0 0] [ ] [0 2 0] [ ] [0 0 2] >>> 3*M [3 0 0] [ ] [0 3 0] [ ] [0 0 3] but we can also apply functions to our matrix entries using ``applyfunc()``. Here we'll declare a function that double any input number. Then we apply it to the 3x3 identity matrix: >>> f = lambda x: 2*x >>> eye(3).applyfunc(f) [2 0 0] [ ] [0 2 0] [ ] [0 0 2] If you want to extract a common factor from a matrix you can do so by applying ``gcd`` to the data of the matrix: >>> from sympy.abc import x, y >>> from sympy import gcd >>> m = Matrix([[x, y], [1, x*y]]).inv('ADJ'); m [ x*y -y ] [-------- --------] [ 2 2 ] [x *y - y x *y - y] [ ] [ -1 x ] [-------- --------] [ 2 2 ] [x *y - y x *y - y] >>> gcd(tuple(_)) 1 -------- 2 x *y - y >>> m/_ [x*y -y] [ ] [-1 x ] One more useful matrix-wide entry application function is the substitution function. Let's declare a matrix with symbolic entries then substitute a value. Remember we can substitute anything - even another symbol!: >>> from sympy import Symbol >>> x = Symbol('x') >>> M = eye(3) * x >>> M [x 0 0] [ ] [0 x 0] [ ] [0 0 x] >>> M.subs(x, 4) [4 0 0] [ ] [0 4 0] [ ] [0 0 4] >>> y = Symbol('y') >>> M.subs(x, y) [y 0 0] [ ] [0 y 0] [ ] [0 0 y] Linear algebra -------------- Now that we have the basics out of the way, let's see what we can do with the actual matrices. Of course, one of the first things that comes to mind is the determinant: >>> M = Matrix(( [1, 2, 3], [3, 6, 2], [2, 0, 1] )) >>> M.det() -28 >>> M2 = eye(3) >>> M2.det() 1 >>> M3 = Matrix(( [1, 0, 0], [1, 0, 0], [1, 0, 0] )) >>> M3.det() 0 Another common operation is the inverse: In SymPy, this is computed by Gaussian elimination by default (for dense matrices) but we can specify it be done by `LU` decomposition as well: >>> M2.inv() [1 0 0] [ ] [0 1 0] [ ] [0 0 1] >>> M2.inv(method="LU") [1 0 0] [ ] [0 1 0] [ ] [0 0 1] >>> M.inv(method="LU") [-3/14 1/14 1/2 ] [ ] [-1/28 5/28 -1/4] [ ] [ 3/7 -1/7 0 ] >>> M * M.inv(method="LU") [1 0 0] [ ] [0 1 0] [ ] [0 0 1] We can perform a `QR` factorization which is handy for solving systems: >>> A = Matrix([[1,1,1],[1,1,3],[2,3,4]]) >>> Q, R = A.QRdecomposition() >>> Q [ ___ ___ ___ ] [\/ 6 -\/ 3 -\/ 2 ] [----- ------- -------] [ 6 3 2 ] [ ] [ ___ ___ ___ ] [\/ 6 -\/ 3 \/ 2 ] [----- ------- ----- ] [ 6 3 2 ] [ ] [ ___ ___ ] [\/ 6 \/ 3 ] [----- ----- 0 ] [ 3 3 ] >>> R [ ___ ] [ ___ 4*\/ 6 ___] [\/ 6 ------- 2*\/ 6 ] [ 3 ] [ ] [ ___ ] [ \/ 3 ] [ 0 ----- 0 ] [ 3 ] [ ] [ ___ ] [ 0 0 \/ 2 ] >>> Q*R [1 1 1] [ ] [1 1 3] [ ] [2 3 4] In addition to the solvers in the ``solver.py`` file, we can solve the system Ax=b by passing the b vector to the matrix A's LUsolve function. Here we'll cheat a little choose A and x then multiply to get b. Then we can solve for x and check that it's correct: >>> A = Matrix([ [2, 3, 5], [3, 6, 2], [8, 3, 6] ]) >>> x = Matrix(3,1,[3,7,5]) >>> b = A*x >>> soln = A.LUsolve(b) >>> soln [3] [ ] [7] [ ] [5] There's also a nice Gram-Schmidt orthogonalizer which will take a set of vectors and orthogonalize them with respect to another. There is an optional argument which specifies whether or not the output should also be normalized, it defaults to ``False``. Let's take some vectors and orthogonalize them - one normalized and one not: >>> L = [Matrix([2,3,5]), Matrix([3,6,2]), Matrix([8,3,6])] >>> out1 = GramSchmidt(L) >>> out2 = GramSchmidt(L, True) Let's take a look at the vectors: >>> for i in out1: ... print(i) ... Matrix([[2], [3], [5]]) Matrix([[23/19], [63/19], [-47/19]]) Matrix([[1692/353], [-1551/706], [-423/706]]) >>> for i in out2: ... print(i) ... Matrix([[sqrt(38)/19], [3*sqrt(38)/38], [5*sqrt(38)/38]]) Matrix([[23*sqrt(6707)/6707], [63*sqrt(6707)/6707], [-47*sqrt(6707)/6707]]) Matrix([[12*sqrt(706)/353], [-11*sqrt(706)/706], [-3*sqrt(706)/706]]) We can spot-check their orthogonality with dot() and their normality with norm(): >>> out1[0].dot(out1[1]) 0 >>> out1[0].dot(out1[2]) 0 >>> out1[1].dot(out1[2]) 0 >>> out2[0].norm() 1 >>> out2[1].norm() 1 >>> out2[2].norm() 1 So there is quite a bit that can be done with the module including eigenvalues, eigenvectors, nullspace calculation, cofactor expansion tools, and so on. From here one might want to look over the ``matrices.py`` file for all functionality. MatrixDeterminant Class Reference --------------------------------- .. autoclass:: MatrixDeterminant :members: MatrixReductions Class Reference -------------------------------- .. autoclass:: MatrixReductions :members: MatrixSubspaces Class Reference ------------------------------- .. autoclass:: MatrixSubspaces :members: MatrixEigen Class Reference --------------------------- .. autoclass:: MatrixEigen :members: MatrixCalculus Class Reference ------------------------------ .. autoclass:: MatrixCalculus :members: MatrixBase Class Reference -------------------------- .. autoclass:: MatrixBase :members: Matrix Exceptions Reference --------------------------- .. autoclass:: MatrixError :members: .. autoclass:: ShapeError :members: .. autoclass:: NonSquareMatrixError :members: Matrix Functions Reference -------------------------- .. autofunction:: sympy.matrices.dense::matrix_multiply_elementwise .. autofunction:: sympy.matrices.dense::zeros .. autofunction:: sympy.matrices.dense::ones .. autofunction:: sympy.matrices.dense::eye .. autofunction:: sympy.matrices.dense::diag .. autofunction:: sympy.matrices.dense::jordan_cell .. autofunction:: sympy.matrices.dense::hessian .. autofunction:: sympy.matrices.dense::GramSchmidt .. autofunction:: sympy.matrices.dense::wronskian .. autofunction:: sympy.matrices.dense::casoratian .. autofunction:: sympy.matrices.dense::randMatrix Numpy Utility Functions Reference --------------------------------- .. autofunction:: sympy.matrices.dense::list2numpy .. autofunction:: sympy.matrices.dense::matrix2numpy .. autofunction:: sympy.matrices.dense::symarray .. autofunction:: sympy.matrices.dense::rot_axis1 .. autofunction:: sympy.matrices.dense::rot_axis2 .. autofunction:: sympy.matrices.dense::rot_axis3 .. autofunction:: a2idx sympy-sympy-1.9/doc/src/modules/matrices/sparse.rst000066400000000000000000000005601412543434000225660ustar00rootroot00000000000000Sparse Matrices =============== .. module:: sympy.matrices.sparse SparseMatrix Class Reference ---------------------------- .. autoclass:: SparseMatrix :members: .. autoclass:: MutableSparseMatrix :members: ImmutableSparseMatrix Class Reference ------------------------------------- .. autoclass:: sympy.matrices.immutable::ImmutableSparseMatrix :members: sympy-sympy-1.9/doc/src/modules/matrices/sparsetools.rst000066400000000000000000000003771412543434000236550ustar00rootroot00000000000000.. _matrices-sparsetools: Sparse Tools ============ .. module:: sympy.matrices.sparsetools .. automethod:: sympy.matrices.sparsetools::_doktocsr .. automethod:: sympy.matrices.sparsetools::_csrtodok .. automethod:: sympy.matrices.sparsetools::banded sympy-sympy-1.9/doc/src/modules/ntheory.rst000066400000000000000000000115741412543434000211610ustar00rootroot00000000000000============= Number Theory ============= .. module:: sympy.ntheory.generate Ntheory Class Reference ----------------------- .. autoclass:: Sieve :members: Ntheory Functions Reference --------------------------- .. autofunction:: prime .. autofunction:: primepi .. autofunction:: nextprime .. autofunction:: prevprime .. autofunction:: primerange .. autofunction:: randprime .. autofunction:: primorial .. autofunction:: cycle_length .. autofunction:: composite .. autofunction:: compositepi .. module:: sympy.ntheory.factor_ .. autofunction:: smoothness .. autofunction:: smoothness_p .. autofunction:: trailing .. autofunction:: multiplicity .. autofunction:: perfect_power .. autofunction:: pollard_rho .. autofunction:: pollard_pm1 .. autofunction:: factorint .. autofunction:: factorrat .. autofunction:: primefactors .. autofunction:: divisors .. autofunction:: proper_divisors .. autofunction:: divisor_count .. autofunction:: proper_divisor_count .. autofunction:: udivisors .. autofunction:: udivisor_count .. autofunction:: antidivisors .. autofunction:: antidivisor_count .. autoclass:: totient :members: .. autoclass:: reduced_totient :members: .. autoclass:: divisor_sigma :members: .. autoclass:: udivisor_sigma :members: .. autofunction:: core .. autofunction:: digits .. autoclass:: primenu :members: .. autoclass:: primeomega :members: .. autofunction:: mersenne_prime_exponent .. autofunction:: is_perfect .. autofunction:: is_mersenne_prime .. autofunction:: abundance .. autofunction:: is_abundant .. autofunction:: is_deficient .. autofunction:: is_amicable .. module:: sympy.ntheory.modular .. autofunction:: symmetric_residue .. autofunction:: crt .. autofunction:: crt1 .. autofunction:: crt2 .. autofunction:: solve_congruence .. module:: sympy.ntheory.multinomial .. autofunction:: binomial_coefficients .. autofunction:: binomial_coefficients_list .. autofunction:: multinomial_coefficients .. autofunction:: multinomial_coefficients_iterator .. module:: sympy.ntheory.partitions_ .. autofunction:: npartitions .. module:: sympy.ntheory.primetest .. autofunction:: is_euler_pseudoprime .. autofunction:: is_square .. autofunction:: mr .. autofunction:: is_lucas_prp .. autofunction:: is_strong_lucas_prp .. autofunction:: is_extra_strong_lucas_prp .. autofunction:: isprime .. autofunction:: is_gaussian_prime .. module:: sympy.ntheory.residue_ntheory .. autofunction:: n_order .. autofunction:: is_primitive_root .. autofunction:: primitive_root .. autofunction:: sqrt_mod .. autofunction:: sqrt_mod_iter .. autofunction:: quadratic_residues .. autofunction:: nthroot_mod .. autofunction:: is_nthpow_residue .. autofunction:: is_quad_residue .. autofunction:: legendre_symbol .. autofunction:: jacobi_symbol .. autofunction:: discrete_log .. automodule:: sympy.ntheory.continued_fraction :members: .. automodule:: sympy.ntheory.digits :members: .. autoclass:: sympy.ntheory.mobius :members: .. module:: sympy.ntheory.egyptian_fraction .. autofunction:: egyptian_fraction .. module:: sympy.ntheory.bbp_pi .. autofunction:: pi_hex_digits .. module:: sympy.ntheory.ecm ECM function ============ The `ecm` function is a subexponential factoring algorithm capable of factoring numbers of around ~35 digits comfortably within few seconds. The time complexity of `ecm` is dependent on the smallest proper factor of the number. So even if the number is really large but its factors are comparatively smaller then `ecm` can easily factor them. For example we take `N` with 15 digit factors `15154262241479`, `15423094826093`, `799333555511111`, `809709509409109`, `888888877777777`, `914148152112161`. Now N is a 87 digit number. `ECM` takes under around 47s to factorise this. .. autofunction:: ecm Examples ======== >>> from sympy.ntheory import ecm >>> ecm(7060005655815754299976961394452809, B1=100000, B2=1000000) {6988699669998001, 1010203040506070809} >>> ecm(122921448543883967430908091422761898618349713604256384403202282756086473494959648313841, B1=100000, B2=1000000) {15154262241479, 15423094826093, 799333555511111, 809709509409109, 888888877777777, 914148152112161} .. module:: sympy.ntheory.qs QS function =========== The `qs` function is a subexponential factoring algorithm, the fastest factoring algorithm for numbers within 100 digits. The time complexity of `qs` is dependent on the size of the number so it is used if the number contains large factors. Due to this while factoring numbers first `ecm` is used to get smaller factors of around ~15 digits then `qs` is used to get larger factors. For factoring `2709077133180915240135586837960864768806330782747` which is a semi-prime number with two 25 digit factors. `qs` is able to factorize this in around 248s. .. autofunction:: qs Examples ======== >>> from sympy.ntheory import qs >>> qs(5915587277*3267000013, 1000, 10000) {3267000013, 5915587277} sympy-sympy-1.9/doc/src/modules/numeric-computation.rst000066400000000000000000000144741412543434000234750ustar00rootroot00000000000000.. _numeric_computation: =================== Numeric Computation =================== Symbolic computer algebra systems like SymPy facilitate the construction and manipulation of mathematical expressions. Unfortunately when it comes time to evaluate these expressions on numerical data, symbolic systems often have poor performance. Fortunately SymPy offers a number of easy-to-use hooks into other numeric systems, allowing you to create mathematical expressions in SymPy and then ship them off to the numeric system of your choice. This page documents many of the options available including the ``math`` library, the popular array computing package ``numpy``, code generation in ``Fortran`` or ``C``, and the use of the array compiler ``Aesara``. Subs/evalf ---------- Subs is the slowest but simplest option. It runs at SymPy speeds. The ``.subs(...).evalf()`` method can substitute a numeric value for a symbolic one and then evaluate the result within SymPy. >>> from sympy import * >>> from sympy.abc import x >>> expr = sin(x)/x >>> expr.evalf(subs={x: 3.14}) 0.000507214304613640 This method is slow. You should use this method production only if performance is not an issue. You can expect ``.subs`` to take tens of microseconds. It can be useful while prototyping or if you just want to see a value once. Lambdify -------- The ``lambdify`` function translates SymPy expressions into Python functions, leveraging a variety of numerical libraries. It is used as follows: >>> from sympy import * >>> from sympy.abc import x >>> expr = sin(x)/x >>> f = lambdify(x, expr) >>> f(3.14) 0.000507214304614 Here lambdify makes a function that computes ``f(x) = sin(x)/x``. By default lambdify relies on implementations in the ``math`` standard library. This numerical evaluation takes on the order of hundreds of nanoseconds, roughly two orders of magnitude faster than the ``.subs`` method. This is the speed difference between SymPy and raw Python. Lambdify can leverage a variety of numerical backends. By default it uses the ``math`` library. However it also supports ``mpmath`` and most notably, ``numpy``. Using the ``numpy`` library gives the generated function access to powerful vectorized ufuncs that are backed by compiled C code. >>> from sympy import * >>> from sympy.abc import x >>> expr = sin(x)/x >>> f = lambdify(x, expr, "numpy") >>> import numpy >>> data = numpy.linspace(1, 10, 10000) >>> f(data) [ 0.84147098 0.84119981 0.84092844 ... -0.05426074 -0.05433146 -0.05440211] If you have array-based data this can confer a considerable speedup, on the order of 10 nano-seconds per element. Unfortunately numpy incurs some start-up time and introduces an overhead of a few microseconds. CuPy is a NumPy-compatible array library that mainly runs on CUDA, but has increasing support for other GPU manufacturers. It can in many cases be used as a drop-in replacement for numpy. >>> f = lambdify(x, expr, "cupy") >>> import cupy as cp >>> data = cp.linspace(1, 10, 10000) >>> y = f(data) # perform the computation >>> cp.asnumpy(y) # explicitly copy from GPU to CPU / numpy array [ 0.84147098 0.84119981 0.84092844 ... -0.05426074 -0.05433146 -0.05440211] uFuncify -------- The ``autowrap`` module contains methods that help in efficient computation. * :ref:`autowrap` method for compiling code generated by the :ref:`codegen` module, and wrap the binary for use in python. * :ref:`binary_function` method automates the steps needed to autowrap the SymPy expression and attaching it to a ``Function`` object with ``implemented_function()``. * :ref:`ufuncify` generates a binary function that supports broadcasting on numpy arrays using different backends that are faster as compared to ``subs/evalf`` and ``lambdify``. The API reference of all the above is listed here: :py:func:`sympy.utilities.autowrap`. Aesara ------ SymPy has a strong connection with `Aesara `_, a mathematical array compiler. SymPy expressions can be easily translated to Aesara graphs and then compiled using the Aesara compiler chain. >>> from sympy import * >>> from sympy.abc import x >>> expr = sin(x)/x >>> from sympy.printing.aesaracode import aesara_function >>> f = aesara_function([x], [expr]) If array broadcasting or types are desired then Aesara requires this extra information >>> f = aesara_function([x], [expr], dims={x: 1}, dtypes={x: 'float64'}) Aesara has a more sophisticated code generation system than SymPy's C/Fortran code printers. Among other things it handles common sub-expressions and compilation onto the GPU. Aesara also supports SymPy Matrix and Matrix Expression objects. So Which Should I Use? ---------------------- The options here were listed in order from slowest and least dependencies to fastest and most dependencies. For example, if you have Aesara installed then that will often be the best choice. If you don't have Aesara but do have ``f2py`` then you should use ``ufuncify``. If you have been comfortable using lambdify with the numpy module, but have a GPU, CuPy can provide substantial speedups with little effort. +-----------------+-------+-----------------------------+---------------+ | Tool | Speed | Qualities | Dependencies | +=================+=======+=============================+===============+ | subs/evalf | 50us | Simple | None | +-----------------+-------+-----------------------------+---------------+ | lambdify | 1us | Scalar functions | math | +-----------------+-------+-----------------------------+---------------+ | lambdify-numpy | 10ns | Vector functions | numpy | +-----------------+-------+-----------------------------+---------------+ | ufuncify | 10ns | Complex vector expressions | f2py, Cython | +-----------------+-------+-----------------------------+---------------+ | lambdify-cupy | 10ns | Vector functions on GPUs | cupy | +-----------------+-------+-----------------------------+---------------+ | Aesara | 10ns | Many outputs, CSE, GPUs | Aesara | +-----------------+-------+-----------------------------+---------------+ sympy-sympy-1.9/doc/src/modules/parsing.rst000066400000000000000000000075201412543434000211300ustar00rootroot00000000000000======= Parsing ======= .. module:: sympy.parsing Parsing Functions Reference --------------------------- .. autofunction:: sympy.parsing.sympy_parser.parse_expr .. autofunction:: sympy.parsing.sympy_parser.stringify_expr .. autofunction:: sympy.parsing.sympy_parser.eval_expr .. autofunction:: sympy.parsing.maxima.parse_maxima .. autofunction:: sympy.parsing.mathematica.mathematica Parsing Transformations Reference --------------------------------- A transformation is a function that accepts the arguments ``tokens, local_dict, global_dict`` and returns a list of transformed tokens. They can be used by passing a list of functions to :py:func:`~.parse_expr` and are applied in the order given. .. autodata:: sympy.parsing.sympy_parser.standard_transformations .. autofunction:: sympy.parsing.sympy_parser.split_symbols .. autofunction:: sympy.parsing.sympy_parser.split_symbols_custom .. autofunction:: sympy.parsing.sympy_parser.implicit_multiplication .. autofunction:: sympy.parsing.sympy_parser.implicit_application .. autofunction:: sympy.parsing.sympy_parser.function_exponentiation .. autofunction:: sympy.parsing.sympy_parser.implicit_multiplication_application .. autofunction:: sympy.parsing.sympy_parser.rationalize .. autofunction:: sympy.parsing.sympy_parser.convert_xor These are included in :data:``sympy.parsing.sympy_parser.standard_transformations`` and generally don't need to be manually added by the user. .. autofunction:: sympy.parsing.sympy_parser.lambda_notation .. autofunction:: sympy.parsing.sympy_parser.auto_symbol .. autofunction:: sympy.parsing.sympy_parser.repeated_decimals .. autofunction:: sympy.parsing.sympy_parser.auto_number .. autofunction:: sympy.parsing.sympy_parser.factorial_notation Experimental `\mathrm{\LaTeX}` Parsing -------------------------------------- `\mathrm{\LaTeX}` parsing was ported from `latex2sympy `_. While functional and its API should remain stable, the parsing behavior or backend may change in future releases. `\mathrm{\LaTeX}` Parsing Caveats --------------------------------- The current implementation is experimental. The behavior, parser backend and API might change in the future. Unlike some of the other parsers, `\mathrm{\LaTeX}` is designed as a *type-setting* language, not a *computer algebra system* and so can contain typographical conventions that might be interpreted multiple ways. In its current definition, the parser will at times will fail to fully parse the expression, but not throw a warning:: parse_latex(r'x -') Will simply find ``x``. What is covered by this behavior will almost certainly change between releases, and become stricter, more relaxed, or some mix. `\mathrm{\LaTeX}` Parsing Functions Reference --------------------------------------------- .. autofunction:: sympy.parsing.latex.parse_latex `\mathrm{\LaTeX}` Parsing Exceptions Reference ---------------------------------------------- .. autoclass:: sympy.parsing.latex.LaTeXParsingError :members: SymPy Expression Reference -------------------------- .. module:: sympy.parsing.sym_expr .. autoclass:: SymPyExpression :members: Runtime Installation -------------------- The currently-packaged LaTeX parser backend is partially generated with `ANTLR4 `_, but to use the parser, you only need the ``antlr4`` Python package available. Depending on your package manager, you can install the right package with, for example, ``pip3`` (Python 3 only):: $ pip3 install antlr4-python3-runtime or ``pip`` (Python 2 only):: $ pip install antlr4-python2-runtime or ``conda`` (Python 2 or Python 3):: $ conda install --channel=conda-forge antlr-python-runtime The C parser depends on ``clang`` and the Fortran parser depends on ``LFortran``. You can install these packages using:: $ conda install -c conda-forge lfortran clang sympy-sympy-1.9/doc/src/modules/physics/000077500000000000000000000000001412543434000204115ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/continuum_mechanics/000077500000000000000000000000001412543434000244445ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/continuum_mechanics/allowed-sign-conventions.png000066400000000000000000000214631412543434000321100ustar00rootroot00000000000000PNG  IHDR,ʩ7PLTEnnm110TSS烃M"IDATx[ǵ~ 4ˊ$6Ɛ;qcٹebk'Nv$p 忽]KL+b$pϏé* (AwIF F| $C~kZe$i ȷ3 NfMC GI$C:? 2N]0yXIf|6L^@|lYyFdV^ >y e164Irŵ$&Ifm2w ;ɋ$sehF9j@p:Ifa'J&G2I$̖Z\[\mz4kDQ\}7,럹 (A( d$$$ IH2H2@ dd$$ IFu%*`CvíVf.'QWGQdg۞GY$? wuEY$GeywI{K IN[r~DBkrTU8 IKs}WDO'QneNr\7d3IgbdOyk6eNr嚍/hWzQ$GUy%3CIo;(Cx(Ey(Cx(_iԢ${2'32'YyZ?(Cz=lI6?i I]_P!?sZ/q ?f2$Y٢L IC/P$s(Em̍>.l I̕$~C!>^-k!1$'Z;NJ{M;/6$N&Yy?2GILI$*ky],f5_T>;yk I%:kSV^@FmIia2deSa5"Hr\SN}]l"$'%9wBǢ΄rdBW4IIo=xեM9h7:M(Y|ǷrIr$GQ]{!mE Q >J8:)I{:zHExa]][$9#J|{%6jSQdu$g|76$JrxgPkIT='/!k$vINqa<|r|#{wON}Ŝ'}K^cwM} GBN)lu= >Z8$zFve윝%9~~dC-T32Nxt$ZZ 2<$QN.?dϽ'9GE%y1n苕L,3ɃKm0Kҡޣ̿'$SP{SngK9ڻ.0aJrH'69sUIff\I$' 2fتHwѧP2<\IOexh,38aaI^v*k4]~ aK-ԜVMS]?3"նkH%ܪx:5;p$RIr9ޭ5 G)I$WOVqߘ6zI^Uj=+sXg?T\gއ0HKrJ?j"p\.6QcSPɫ:{ĩO?Hr&.íA%{nvz|?UhNiGk򻽽n\a}?+* gQi\i҃+g%j%6[Or><$WLdWb^MrnO >5N9=仛ʭh$y$ǣވIrJ_-R&l}bݝ$W$L|>7DMvĺI"8\zJ}e)Id5G^D&sn%HryiHr{PvdI NedE/<*$K%LM4yn)/YpYn)z$SɃ4\'ɔidq4kI$S&YQfI<|wY8 Is?X?+zd5kuf)1Lu7-OH&= /]p} ֓1wў0Sq~-܅ ?wbn]|]+si+Meyll{jOr"c>y'>*C(ȜO7C]T&%?#xųָ.[]Dg_5٪I]w:ZW$?;(ͽ>Od<득^9$>8=6|MKIVgF?\rI~+癑M,əᒼU&%{|]Iv 'qɞVͭ,oNw ,Y]ϕTн:W+yьZzvr?ʢZf{1I.UђN$y_h56L_ҬYT$ut-BI>ɋcAJVs$& At`AE۟zd3!$hs"rk2IM],1&Or.eH.S2$9̀aū.HŀɝOʪ j7>L~k0QIN&>krD9]m0l6GUNr [ wll{C8g$YqmrM^k);ky*䅤:AvzGt~|v&.HeuZN*6L|6fZ^쵪\/&m-Njl\rz[n Jr"_^CE-=q I{|d5#_VFm.KVM[KCII9>{al3(dᅤ{|^(Iθ,d'+WVtJIs3hȷU<ɛϛ4r&0{" KZ\HZ@W+ɚ"bdt/Wl'f"sw{''*7gInny%Y=>u.`,Mo8|$G~mvܖQ{kϋJr>_{/y񁼸z$[ÝrdIVǓRCXfIu?m>aaVgcy9< 6qq($gM+E%yi?:?$A^~9&j h%y>I~uj3݉gkeA}]ojQU:nV9^lLy[J }[]$&.5*Paܱʌ.jr)|Ȑ\${ eHH5Y~M^.||L; ,7ʅw"l6\$S&/\ꇥ~FT:!C'Y-2 窕I>5\u^F.|YȥMW$dI6L(;*$#%ypn*hQEyʝB-;qoCJz2$?)B}_AlIr[gDFRw&=&+wlvW[;EO' d.>Y(~7'lI~ɹ-./~]+AsU-> |r\.d~c=r3& .lUǧ: 74θ52d[nqKɯWqUp [mkrjI%y[tق,E^vޭ~H $?- G2] /&g,2Ζ'u+1g'f]fM~l?$'nms|}9֕𙑬Ë{ɧl&̗<#Y>IO%ٛtVrIJr0<$2n s!n2&Yb$s-N.ɓMr13~pL9oİϪKtP~`Lɷ_⮳<$ˢ仡qo'NIt膨wj-O@#duNI&anI&䡓]JK&ịUndLM&wc%djI6]I25y$7neVLaQSYSIlIwJrՓII^N 'oTI6N[.2nM](nIzw HEé s$W=yT =(UO\xCIV|.mv$W=~1w>&P=,O f3s-j=8ov\=,ɕOndI~u}oueOtѧ\{|+3ٽŵ$nԢK;ΦZFY;1}B;əe7jI+$W&V$;X ڇ6d]jc%D;Id $MN-$*6y69${^T&Iμ%ݙgK2I^X4ܙMN/$y;\(98W($G3fގ6%$S{Cy`ߙ Jr$FNM~羈m.\)xY%LM |Qv,ɹ~(A^*_ 4%9o DOVbYuq}~Wd?3?Jr$;d\~3srAm.>3Y\dItxQNi>|E&vWm6i?`YS[GESs&9|p#$9GE%y.#o_IΗov;ᖙzZ֮oW%v-'=kѴ˻.rﻲ=@ߒ'levWH_UFqWs$90*~slÝ'9L reׯ$dFJ?#Oϟnbɕ{_j_IΑsZ|}.EKv|\U&wN!F]DLrd}Us6M~k?' <0Bgx0G]:l.CmF'eR$C=<~7 m2lo~$6a?7 $/hK[6 l.1~Xtbkr~sl6YeB5BMm.$@?R*N*fciEsG|f I$c&١SlOJ!6Oud$En(A:?ve2=O-ɬ$ے|dL A|"%%HQ!>'&.P$Z O65tB~͏Z׹I6%“yg=8dSG=.d'YyQLoIV ?~{#$+o%-D'9 ޠ$IDoIV;A CrOG IWI$(}#9ݏ CdUD݄x9ݏ5os\@!5ɗϓVWG 3{{G C!3l$/ts|(^V< HkeC!:vD1d'=$$ IIH2@ dd$$ IH2@A IFij2]ZWŮ٠ŀ$\'K͑!7~/_r9 &e Hn/:I~B!Or5&CvOMF)叙MF)\K$Cx#]C>C>|(ǐm2'yJa;|(Őo3Jr$CS.P ܫF 'I1urD_'C>$JM&P$2 RX]be3R$yp(Kre.(\$0mlIENDB`sympy-sympy-1.9/doc/src/modules/physics/continuum_mechanics/beam.rst000066400000000000000000000002061412543434000261000ustar00rootroot00000000000000================= Beam (Docstrings) ================= Beam ==== .. automodule:: sympy.physics.continuum_mechanics.beam :members: sympy-sympy-1.9/doc/src/modules/physics/continuum_mechanics/beam_problems.rst000066400000000000000000001367271412543434000300250ustar00rootroot00000000000000=========================================================== Solving Beam Bending Problems using Singularity Functions =========================================================== To make this document easier to read, enable pretty printing: .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import * >>> x, y, z = symbols('x y z') >>> init_printing(use_unicode=True, wrap_line=False) Beam ==== A planar beam is a structural element that is capable of withstanding load through resistance to internal shear and bending. Beams are characterized by their length, constraints, cross-sectional second moment of area, and elastic modulus. In SymPy, 2D beam objects are constructed by specifying the following properties: - Length - Elastic Modulus - Second Moment of Area - Variable : A symbol representing the location along the beam's length. By default, this is set to ``Symbol(x)``. - Boundary Conditions - bc_slope : Boundary conditions for slope. - bc_deflection : Boundary conditions for deflection. - Load Distribution Once the above are specified, the following methods are used to compute useful information about the loaded beam: - ``solve_for_reaction_loads()`` - ``shear_force()`` - ``bending_moment()`` - ``slope()`` Examples ======== Below are examples of a variety two dimensional beam bending problems. Example 1 --------- A cantilever beam 9 meters in length has a distributed constant load of 8 kN/m applied downward from the fixed end over a 5 meter distance. A counterclockwise moment of 50 kN-m is applied 5 meters from the fixed end. Lastly, a downward point load of 12 kN is applied at the free end of the beam. :: y ^ | \\\\| \\\\| 8 kN/m \\\\|_________________ \\\\|| | | | | | | | | 12 kN \\\\|V V V V V V V V V | \\\\|________________|_______________V \\\\| | | \\\\o - - - - - - - -⭯ 50 kN-m - - - | - - -> x \\\\|________________|_______________| \\\\| : \\\\|----------------|---------------| 5.0 m 4.0 m .. note:: The user is free to choose their own sign convention. In this case the downward forces and counterclockwise bending moment being positive. The beam must be initialized with the length, modulus of elasticity, and the second moment of area. These quantities can be symbols or numbers. .. plot:: :context: :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> E, I = symbols('E, I') >>> b = Beam(9, E, I) The three loads are applied to the beam using the ``apply_load()`` method. This method supports point forces, point moments, and polynomial distributed loads of any order, i.e. :math:`c, cx, cx^2, cx^3, \ldots``. The 12 kN point load is in the negative direction, at the location of 9 meters, and the polynomial order is specified as -1: .. plot:: :context: :format: doctest :include-source: True >>> b.apply_load(12, 9, -1) The ``load`` attribute can then be used to access the loading function in singularity function form: .. plot:: :context: :format: doctest :include-source: True >>> b.load -1 12⋅ Similarly, the positive moment can be applied with a polynomial order -2: .. plot:: :context: :format: doctest :include-source: True >>> b.apply_load(50, 5, -2) The distributed load is of order 0 and spans x=0 to x=5: .. plot:: :context: :format: doctest :include-source: True >>> b.apply_load(8, 0, 0, end=5) The fixed end imposes two boundary conditions: 1) no vertical deflection and 2) no rotation. These are specified by appending tuples of x values and the corresponding deflection or slope values: .. plot:: :context: :format: doctest :include-source: True >>> b.bc_deflection.append((0, 0)) >>> b.bc_slope.append((0, 0)) These boundary conditions introduce an unknown reaction force and moment which need to be applied to the beam to maintain static equilibrium: .. plot:: :context: :format: doctest :include-source: True >>> R, M = symbols('R, M') >>> b.apply_load(R, 0, -1) >>> b.apply_load(M, 0, -2) >>> b.load -2 -1 0 -2 0 -1 M⋅ + R⋅ + 8⋅ + 50⋅ - 8⋅ + 12⋅ These two variables can be solved for in terms of the applied loads and the final loading can be displayed: .. plot:: :context: :format: doctest :include-source: True >>> b.solve_for_reaction_loads(R, M) >>> b.reaction_loads {M: 158, R: -52} >>> b.load -2 -1 0 -2 0 -1 158⋅ - 52⋅ + 8⋅ + 50⋅ - 8⋅ + 12⋅ At this point, the beam is fully defined and the internal shear and bending moments are calculated: .. plot:: :context: :format: doctest :include-source: True >>> b.shear_force() -1 0 1 -1 1 0 - 158⋅ + 52⋅ - 8⋅ - 50⋅ + 8⋅ - 12⋅ >>> b.bending_moment() 0 1 2 0 2 1 - 158⋅ + 52⋅ - 4⋅ - 50⋅ + 4⋅ - 12⋅ These can be visualized by calling the respective plot methods: .. plot:: :context: :format: doctest :include-source: True >>> b.plot_shear_force() # doctest: +SKIP >>> b.plot_bending_moment() # doctest: +SKIP The beam will deform under load and the slope and deflection can be determined with: .. plot:: :context: close-figs :format: doctest :include-source: True >>> b.slope() ⎛ 3 3 ⎞ ⎜ 1 2 4⋅ 1 4⋅ 2⎟ -⎜- 158⋅ + 26⋅ - ────── - 50⋅ + ────────── - 6⋅ ⎟ ⎝ 3 3 ⎠ ───────────────────────────────────────────────────────────────────────── E⋅I >>> b.deflection() ⎛ 3 4 4 ⎞ ⎜ 2 26⋅ 2 3⎟ -⎜- 79⋅ + ─────── - ──── - 25⋅ + ──────── - 2⋅ ⎟ ⎝ 3 3 3 ⎠ ──────────────────────────────────────────────────────────────────── E⋅I The slope and deflection of the beam can be plotted so long as numbers are provided for the modulus and second moment: .. plot:: :context: close-figs :format: doctest :include-source: True >>> b.plot_slope(subs={E: 20E9, I: 3.25E-6}) # doctest: +SKIP >>> b.plot_deflection(subs={E: 20E9, I: 3.25E-6}) # doctest: +SKIP All of the plots can be shown in one figure with: .. plot:: :context: close-figs :format: doctest :include-source: True >>> b.plot_loading_results(subs={E: 20E9, I: 3.25E-6}) # doctest: +SKIP Example 2 --------- There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the counter-clockwise direction at the end of the beam. A point load of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. :: || 8 N ⭯ 120 Nm \/______________________________________________| |_______________________________________________| /\ /\ |------------|---------------------------------| 10 m 20 m .. note:: Using the sign convention of downward forces and counterclockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection.append((10, 0)) >>> b.bc_deflection.append((30, 0)) >>> b.solve_for_reaction_loads(R1, R2) >>> b.reaction_loads {R₁: -18, R₂: 10} >>> b.load -1 -1 -2 -1 8⋅ - 18⋅ + 120⋅ + 10⋅ >>> b.shear_force() 0 0 -1 0 - 8⋅ + 18⋅ - 120⋅ - 10⋅ >>> b.bending_moment() 1 1 0 1 - 8⋅ + 18⋅ - 120⋅ - 10⋅ >>> b.slope() 2 2 1 2 1600 4⋅ - 9⋅ + 120⋅ + 5⋅ - ──── 3 ───────────────────────────────────────────────────────── E⋅I >>> b.deflection() 3 3 1600⋅x 4⋅ 3 2 5⋅ - ────── + ────── - 3⋅ + 60⋅ + ─────────── + 4000 3 3 3 ─────────────────────────────────────────────────────────────────── E⋅I Example 3 --------- A beam of length 6 meters is having a roller support at the start and a hinged support at the end. A counterclockwise moment of 1.5 kN-m is applied at the mid of the beam. A constant distributed load of 3 kN/m and a ramp load of 1 kN/m/m is applied from the mid till the end of the beam. :: ramp load = 1 KN/m/m constant load = 3 KN/m |------------------------| ⭯ 1.5 KN-m ______________________|________________________ |_______________________________________________| o | /\ |----------------------|-----------------------| 3.0 m 3.0 m .. note:: Using the sign convention of downward forces and counterclockwise moment being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols, plot, S >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(6, E, I) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(-S(3)/2, 3, -2) >>> b.apply_load(3, 3, 0) >>> b.apply_load(1, 3, 1) >>> b.apply_load(R2, 6, -1) >>> b.bc_deflection.append((0, 0)) >>> b.bc_deflection.append((6, 0)) >>> b.solve_for_reaction_loads(R1, R2) >>> b.reaction_loads {R₁: -11/4, R₂: -43/4} >>> b.load -1 -2 -1 11⋅ 3⋅ 0 1 43⋅ - ──────── - ─────────── + 3⋅ + - ──────────── 4 2 4 .. plot:: :context: :format: doctest :include-source: True >>> plot(b.load) # doctest: +SKIP .. plot:: :context: close-figs :format: doctest :include-source: True >>> b.shear_force() 0 -1 2 0 11⋅ 3⋅ 1 43⋅ ─────── + ─────────── - 3⋅ - ──────── + ─────────── 4 2 2 4 >>> b.bending_moment() 1 0 2 3 1 11⋅ 3⋅ 3⋅ 43⋅ ─────── + ────────── - ────────── - ──────── + ─────────── 4 2 2 6 4 >>> b.slope() 2 1 3 4 2 11⋅ 3⋅ 43⋅ 78 - ─────── - ────────── + ──────── + ──────── - ─────────── + ── 8 2 2 24 8 5 ─────────────────────────────────────────────────────────────── E⋅I >>> b.deflection() 3 2 4 5 3 78⋅x 11⋅ 3⋅ 43⋅ ──── - ─────── - ────────── + ──────── + ──────── - ─────────── 5 24 4 8 120 24 ─────────────────────────────────────────────────────────────── E⋅I Example 4 --------- An overhanging beam of length 8 meters is pinned at 1 meter from starting point and supported by a roller 1 meter before the other end. It is subjected to a distributed constant load of 10 KN/m from the starting point till 2 meters away from it. Two point loads of 20KN and 8KN are applied at 5 meters and 7.5 meters away from the starting point respectively. :: ---> x | v y 10 KN/m _____________ 20 KN 8 KN | | | | | | | | | V V V V V V V V V _______________________________________________ |_______________________________________________| /\ O |-----|------|-----------------|----------|--|--| 1m 1m 3m 2m .5m .5m .. code:: pycon >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E,I,M,V = symbols('E I M V') >>> b = Beam(8, E, I) >>> E,I,R1,R2 = symbols('E I R1 R2') >>> b.apply_load(R1, 1, -1) >>> b.apply_load(R2, 7, -1) >>> b.apply_load(10, 0, 0, end=2) >>> b.apply_load(20, 5, -1) >>> b.apply_load(8, 7.5, -1) >>> b.solve_for_reaction_loads(R1, R2) >>> b.reaction_loads {R₁: -26.0, R₂: -22.0} >>> b.load 0 -1 0 -1 -1 -1 10⋅ - 26.0⋅ - 10⋅ + 20⋅ - 22.0⋅ + 8⋅ >>> b.shear_force() 1 0 1 0 0 0 - 10⋅ + 26.0⋅ + 10⋅ - 20⋅ + 22.0⋅ - 8⋅ >>> b.bending_moment() 2 1 2 1 1 1 - 5⋅ + 26.0⋅ + 5⋅ - 20⋅ + 22.0⋅ - 8⋅ >>> b.bc_deflection = [(1, 0), (7, 0)] >>> b.slope() 3 3 5⋅ 2 5⋅ 2 2 2 ────── - 13.0⋅ - ────────── + 10⋅ - 11.0⋅ + 4⋅ + 28.2916666666667 3 3 ─────────────────────────────────────────────────────────────────────────────────────────────────── E⋅I >>> b.deflection() 4 4 3 3 5⋅ 3 5⋅ 10⋅ 3 4⋅ 28.2916666666667⋅x + ────── - 4.33333333333333⋅ - ────────── + ─────────── - 3.66666666666667⋅ + ──────────── - 28.7083333333333 12 12 3 3 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────── E⋅I Example 5 --------- A cantilever beam of length 6 meters is under downward distributed constant load with magnitude of 4.0 KN/m from starting point till 2 meters away from it. A ramp load of 1 kN/m/m applied from the mid till the end of the beam. A point load of 12KN is also applied in same direction 4 meters away from start. :: ---> x . | . | v y 12 KN . | | | . | | | V . | | | | \\\\| 4 KN/m . | | | | | \\\\|___________ . 1 KN/m/m| | \\\\|| | | | | | . V V V V V V V \\\\|V V V V V V |---------------| \\\\|________________________________ \\\\|________________________________| \\\\| : : : \\\\|----------|-----|----|----------| 2.0 m 1m 1m 2.0 m .. code:: pycon >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E,I,M,V = symbols('E I M V') >>> b = Beam(6, E, I) >>> b.apply_load(V, 0, -1) >>> b.apply_load(M, 0, -2) >>> b.apply_load(4, 0, 0, end=2) >>> b.apply_load(12, 4, -1) >>> b.apply_load(1, 3, 1, end=6) >>> b.solve_for_reaction_loads(V, M) >>> b.reaction_loads {M: 157/2, V: -49/2} >>> b.load -2 -1 157⋅ 49⋅ 0 0 1 -1 0 1 ───────── - ──────── + 4⋅ - 4⋅ + + 12⋅ - 3⋅ - 2 2 >>> b.shear_force() -1 0 2 2 157⋅ 49⋅ 1 1 0 1 - ───────── + ─────── - 4⋅ + 4⋅ - ──────── - 12⋅ + 3⋅ + ──────── 2 2 2 2 >>> b.bending_moment() 0 1 3 2 3 157⋅ 49⋅ 2 2 1 3⋅ - ──────── + ─────── - 2⋅ + 2⋅ - ──────── - 12⋅ + ────────── + ──────── 2 2 6 2 6 >>> b.bc_deflection = [(0, 0)] >>> b.bc_slope = [(0, 0)] >>> b.slope() ⎛ 1 2 3 3 4 3 4⎞ ⎜ 157⋅ 49⋅ 2⋅ 2⋅ 2 ⎟ -⎜- ──────── + ─────── - ────── + ────────── - ──────── - 6⋅ + ──────── + ────────⎟ ⎝ 2 4 3 3 24 2 24 ⎠ ──────────────────────────────────────────────────────────────────────────────────────────── E⋅I >>> b.deflection() ⎛ 2 3 4 4 5 4 5⎞ ⎜ 157⋅ 49⋅ 3 ⎟ -⎜- ──────── + ─────── - ──── + ──────── - ──────── - 2⋅ + ──────── + ────────⎟ ⎝ 4 12 6 6 120 8 120 ⎠ ──────────────────────────────────────────────────────────────────────────────────────── E⋅I Example 6 --------- An overhanging beam of length 11 meters is subjected to a distributed constant load of 2 KN/m from 2 meters away from the starting point till 6 meters away from it. It is pinned at the starting point and is resting over a roller 8 meters away from that end. Also a counterclockwise moment of 5 KN-m is applied at the overhanging end. :: 2 KN/m ---> x _________________ | | | | | | | | | | v y V V V V V V V V V ⭯ 5 KN-m ____________________________________________________| O____________________________________________________| / \ /\ |--------|----------------|----------|---------------| 2m 4m 2m 3m .. code:: pycon >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> E, I = symbols('E, I') >>> b = Beam(11, E, I) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(2, 2, 0, end=6) >>> b.apply_load(R2, 8, -1) >>> b.apply_load(5, 11, -2) >>> b.solve_for_reaction_loads(R1, R2) >>> b.reaction_loads {R₁: -37/8, R₂: -27/8} >>> b.load -1 -1 37⋅ 0 0 27⋅ -2 - ──────── + 2⋅ - 2⋅ - ──────────── + 5⋅ 8 8 >>> b.shear_force() 0 0 37⋅ 1 1 27⋅ -1 ─────── - 2⋅ + 2⋅ + ─────────── - 5⋅ 8 8 >>> b.bending_moment() 1 1 37⋅ 2 2 27⋅ 0 ─────── - + + ─────────── - 5⋅ 8 8 >>> b.bc_deflection = [(0, 0), (8, 0)] >>> b.slope() 2 3 3 2 37⋅ 27⋅ 1 - ─────── + ──────── - ──────── - ─────────── + 5⋅ + 36 16 3 3 16 ──────────────────────────────────────────────────────────────── E⋅I >>> b.deflection() 3 4 4 3 2 37⋅ 9⋅ 5⋅ 36⋅x - ─────── + ──────── - ──────── - ────────── + ─────────── 48 12 12 16 2 ─────────────────────────────────────────────────────────────── E⋅I Example 7 --------- There is a beam of length ``l``, fixed at both ends. A concentrated point load of magnitude ``F`` is applied in downward direction at mid-point of the beam. :: ^ y | ---> x \\\\| F |\\\\ \\\\| | |\\\\ \\\\| V |\\\\ \\\\|_____________________________________|\\\\ \\\\|_____________________________________|\\\\ \\\\| : |\\\\ \\\\| : |\\\\ \\\\|------------------|------------------|\\\\ l/2 l/2 .. code:: pycon >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I, F = symbols('E I F') >>> l = symbols('l', positive=True) >>> b = Beam(l, E, I) >>> R1,R2 = symbols('R1 R2') >>> M1, M2 = symbols('M1, M2') >>> b.apply_load(R1, 0, -1) >>> b.apply_load(M1, 0, -2) >>> b.apply_load(R2, l, -1) >>> b.apply_load(M2, l, -2) >>> b.apply_load(-F, l/2, -1) >>> b.bc_deflection = [(0, 0),(l, 0)] >>> b.bc_slope = [(0, 0),(l, 0)] >>> b.solve_for_reaction_loads(R1, R2, M1, M2) >>> b.reaction_loads ⎧ -F⋅l F⋅l F F⎫ ⎨M₁: ─────, M₂: ───, R₁: ─, R₂: ─⎬ ⎩ 8 8 2 2⎭ >>> b.load -2 -2 -1 -1 -1 F⋅l⋅ F⋅l⋅<-l + x> F⋅ l F⋅<-l + x> - ───────── + ────────────── + ─────── - F⋅<- ─ + x> + ──────────── 8 8 2 2 2 >>> b.shear_force() -1 -1 0 0 0 F⋅l⋅ F⋅l⋅<-l + x> F⋅ l F⋅<-l + x> ───────── - ────────────── - ────── + F⋅<- ─ + x> - ─────────── 8 8 2 2 2 >>> b.bending_moment() 0 0 1 1 1 F⋅l⋅ F⋅l⋅<-l + x> F⋅ l F⋅<-l + x> ──────── - ───────────── - ────── + F⋅<- ─ + x> - ─────────── 8 8 2 2 2 >>> b.slope() ⎛ 2 ⎞ ⎜ l ⎟ ⎜ 1 1 2 F⋅<- ─ + x> 2⎟ ⎜F⋅l⋅ F⋅l⋅<-l + x> F⋅ 2 F⋅<-l + x> ⎟ -⎜──────── - ───────────── - ────── + ──────────── - ───────────⎟ ⎝ 8 8 4 2 4 ⎠ ────────────────────────────────────────────────────────────────── E⋅I >>> b.deflection() ⎛ 3 ⎞ ⎜ l ⎟ ⎜ 2 2 3 F⋅<- ─ + x> 3⎟ ⎜F⋅l⋅ F⋅l⋅<-l + x> F⋅ 2 F⋅<-l + x> ⎟ -⎜──────── - ───────────── - ────── + ──────────── - ───────────⎟ ⎝ 16 16 12 6 12 ⎠ ────────────────────────────────────────────────────────────────── E⋅I Example 8 --------- There is a beam of length ``4*l``, having a hinge connector at the middle. It is having a fixed support at the start and also has two rollers at a distance of ``l`` and ``4*l`` from the starting point. A concentrated point load ``P`` is also applied at a distance of ``3*l`` from the starting point. :: ---> x \\\\| P | \\\\| | v y \\\\| V \\\\|_____________________ _______________________ \\\\|_____________________O_______________________| \\\\| /\ : /\ \\\\| oooo : oooo \\\\|----------|-----------|----------|-----------| l l l l .. code:: pycon >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E I') >>> l = symbols('l', positive=True) >>> R1, M1, R2, R3, P = symbols('R1 M1 R2 R3 P') >>> b1 = Beam(2*l, E, I) >>> b2 = Beam(2*l, E, I) >>> b = b1.join(b2, "hinge") >>> b.apply_load(M1, 0, -2) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, l, -1) >>> b.apply_load(R3, 4*l, -1) >>> b.apply_load(P, 3*l, -1) >>> b.bc_slope = [(0, 0)] >>> b.bc_deflection = [(0, 0), (l, 0), (4*l, 0)] >>> b.solve_for_reaction_loads(M1, R1, R2, R3) >>> b.reaction_loads ⎧ -P⋅l 3⋅P -5⋅P -P ⎫ ⎨M₁: ─────, R₁: ───, R₂: ─────, R₃: ───⎬ ⎩ 4 4 4 2 ⎭ >>> b.load -2 -1 -1 -1 P⋅l⋅ 3⋅P⋅ 5⋅P⋅<-l + x> -1 P⋅<-4⋅l + x> - ───────── + ───────── - ────────────── + P⋅<-3⋅l + x> - ────────────── 4 4 4 2 >>> b.shear_force() -1 0 0 0 P⋅l⋅ 3⋅P⋅ 5⋅P⋅<-l + x> 0 P⋅<-4⋅l + x> ───────── - ──────── + ───────────── - P⋅<-3⋅l + x> + ───────────── 4 4 4 2 >>> b.bending_moment() 0 1 1 1 P⋅l⋅ 3⋅P⋅ 5⋅P⋅<-l + x> 1 P⋅<-4⋅l + x> ──────── - ──────── + ───────────── - P⋅<-3⋅l + x> + ───────────── 4 4 4 2 >>> b.slope() ⎛ 2 2 2 2⎞ ⎛ 1 2 2 2⎞ ⎛ 1 2 2 2⎞ ⎜5⋅P⋅l P⋅<-2⋅l + x> P⋅<-3⋅l + x> P⋅<-4⋅l + x> ⎟ 0 ⎜ P⋅l⋅ 3⋅P⋅ 5⋅P⋅<-l + x> P⋅<-2⋅l + x> ⎟ 0 ⎜ P⋅l⋅ 3⋅P⋅ 5⋅P⋅<-l + x> P⋅<-2⋅l + x> ⎟ 0 ⎜────── - ───────────── + ───────────── - ─────────────⎟⋅<-2⋅l + x> ⎜- ──────── + ──────── - ───────────── + ─────────────⎟⋅ ⎜- ──────── + ──────── - ───────────── + ─────────────⎟⋅<-2⋅l + x> ⎝ 48 4 2 4 ⎠ ⎝ 4 8 8 4 ⎠ ⎝ 4 8 8 4 ⎠ ──────────────────────────────────────────────────────────────────── + ──────────────────────────────────────────────────────────── - ─────────────────────────────────────────────────────────────────── E⋅I E⋅I E⋅I >>> b.deflection() ⎛ 2 3 3 3⎞ ⎛ 2 3 3 3⎞ ⎛ 3 2 3 3 3⎞ ⎜ P⋅l⋅ P⋅ 5⋅P⋅<-l + x> P⋅<-2⋅l + x> ⎟ 0 ⎜ P⋅l⋅ P⋅ 5⋅P⋅<-l + x> P⋅<-2⋅l + x> ⎟ 0 ⎜7⋅P⋅l 5⋅P⋅l ⋅(-2⋅l + x) P⋅<-2⋅l + x> P⋅<-3⋅l + x> P⋅<-4⋅l + x> ⎟ 0 ⎜- ──────── + ────── - ───────────── + ─────────────⎟⋅ ⎜- ──────── + ────── - ───────────── + ─────────────⎟⋅<-2⋅l + x> ⎜────── + ───────────────── - ───────────── + ───────────── - ─────────────⎟⋅<-2⋅l + x> ⎝ 8 8 24 12 ⎠ ⎝ 8 8 24 12 ⎠ ⎝ 24 48 12 6 12 ⎠ ────────────────────────────────────────────────────────── - ───────────────────────────────────────────────────────────────── + ──────────────────────────────────────────────────────────────────────────────────────── E⋅I E⋅I E⋅I Example 9 --------- There is a cantilever beam of length 4 meters. For first 2 meters its moment of inertia is ``1.5*I`` and ``I`` for the rest. A pointload of magnitude 20 N is applied from the top at its free end. :: ---> x \\\\| | \\\\| 20 N v y \\\\|________________ | \\\\| |_______________V \\\\| 1.5*I _______I_______| \\\\|________________| \\\\| : \\\\|----------------|---------------| 2.0 m 2.0 m .. code:: pycon >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b1 = Beam(2, E, 1.5*I) >>> b2 = Beam(2, E, I) >>> b = b1.join(b2, "fixed") >>> b.apply_load(20, 4, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 0, -2) >>> b.bc_slope = [(0, 0)] >>> b.bc_deflection = [(0, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.load -2 -1 -1 80⋅ - 20⋅ + 20⋅ >>> b.shear_force() -1 0 0 - 80⋅ + 20⋅ - 20⋅ >>> b.bending_moment() 0 1 1 - 80⋅ + 20⋅ - 20⋅ >>> b.slope() ⎛ 1 2 2 ⎞ ⎜ - 80⋅ + 10⋅ - 10⋅ 120 ⎟ ⎜ ───────────────────────────────── + ─── ⎟ ⎛ 1 2 2⎞ 0 ⎛ 1 2 2⎞ 0 ⎜ I I 80.0⎟ 0 0.666666666666667⋅⎝- 80⋅ + 10⋅ - 10⋅ ⎠⋅ 0.666666666666667⋅⎝- 80⋅ + 10⋅ - 10⋅ ⎠⋅ ⎜- ─────────────────────────────────────── + ────⎟⋅ - ────────────────────────────────────────────────────────── + ────────────────────────────────────────────────────────────── ⎝ E E⋅I ⎠ E⋅I E⋅I Example 10 ---------- A combined beam, with constant flexural rigidity ``E*I``, is formed by joining a Beam of length ``2*l`` to the right of another Beam of length ``l``. The whole beam is fixed at both of its ends. A point load of magnitude ``P`` is also applied from the top at a distance of ``2*l`` from starting point. :: ---> x | \\\\| P v y |\\\\ \\\\| | |\\\\ \\\\| V |\\\\ \\\\|____________ ________________________|\\\\ \\\\|____________O________________________|\\\\ \\\\| : : |\\\\ \\\\| : : |\\\\ \\\\|------------|------------|-----------|\\\\ l l l .. code:: pycon >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> l = symbols('l', positive=True) >>> b1 = Beam(l ,E,I) >>> b2 = Beam(2*l ,E,I) >>> b = b1.join(b2,"hinge") >>> M1, A1, M2, A2, P = symbols('M1 A1 M2 A2 P') >>> b.apply_load(A1, 0, -1) >>> b.apply_load(M1, 0 ,-2) >>> b.apply_load(P, 2*l, -1) >>> b.apply_load(A2, 3*l, -1) >>> b.apply_load(M2, 3*l, -2) >>> b.bc_slope=[(0, 0), (3*l, 0)] >>> b.bc_deflection=[(0, 0), (3*l, 0)] >>> b.solve_for_reaction_loads(M1, A1, M2, A2) >>> b.reaction_loads ⎧ -5⋅P -13⋅P 5⋅P⋅l -4⋅P⋅l ⎫ ⎨A₁: ─────, A₂: ──────, M₁: ─────, M₂: ───────⎬ ⎩ 18 18 18 9 ⎭ >>> b.load -2 -2 -1 -1 5⋅P⋅l⋅ 4⋅P⋅l⋅<-3⋅l + x> 5⋅P⋅ -1 13⋅P⋅<-3⋅l + x> ─────────── - ────────────────── - ───────── + P⋅<-2⋅l + x> - ───────────────── 18 9 18 18 >>> b.shear_force() -1 -1 0 0 5⋅P⋅l⋅ 4⋅P⋅l⋅<-3⋅l + x> 5⋅P⋅ 0 13⋅P⋅<-3⋅l + x> - ─────────── + ────────────────── + ──────── - P⋅<-2⋅l + x> + ──────────────── 18 9 18 18 >>> b.bending_moment() 0 0 1 1 5⋅P⋅l⋅ 4⋅P⋅l⋅<-3⋅l + x> 5⋅P⋅ 1 13⋅P⋅<-3⋅l + x> - ────────── + ───────────────── + ──────── - P⋅<-2⋅l + x> + ──────────────── 18 9 18 18 >>> b.slope() ⎛ 1 2 2⎞ ⎛ 1 2 2⎞ ⎛ 2 1 2 2 2⎞ ⎜5⋅P⋅l⋅ 5⋅P⋅ 5⋅P⋅<-l + x> ⎟ 0 ⎜5⋅P⋅l⋅ 5⋅P⋅ 5⋅P⋅<-l + x> ⎟ 0 ⎜P⋅l 4⋅P⋅l⋅<-3⋅l + x> 5⋅P⋅<-l + x> P⋅<-2⋅l + x> 13⋅P⋅<-3⋅l + x> ⎟ 0 ⎜────────── - ──────── + ─────────────⎟⋅ ⎜────────── - ──────── + ─────────────⎟⋅<-l + x> ⎜──── - ───────────────── - ───────────── + ───────────── - ────────────────⎟⋅<-l + x> ⎝ 18 36 36 ⎠ ⎝ 18 36 36 ⎠ ⎝ 18 9 36 2 36 ⎠ ──────────────────────────────────────────── - ───────────────────────────────────────────────── + ─────────────────────────────────────────────────────────────────────────────────────── E⋅I E⋅I E⋅I >>> b.deflection() ⎛ 2 3 3⎞ ⎛ 2 3 3⎞ ⎛ 3 2 2 3 3 3⎞ ⎜5⋅P⋅l⋅ 5⋅P⋅ 5⋅P⋅<-l + x> ⎟ 0 ⎜5⋅P⋅l⋅ 5⋅P⋅ 5⋅P⋅<-l + x> ⎟ 0 ⎜5⋅P⋅l P⋅l ⋅(-l + x) 2⋅P⋅l⋅<-3⋅l + x> 5⋅P⋅<-l + x> P⋅<-2⋅l + x> 13⋅P⋅<-3⋅l + x> ⎟ 0 ⎜────────── - ──────── + ─────────────⎟⋅ ⎜────────── - ──────── + ─────────────⎟⋅<-l + x> ⎜────── + ───────────── - ───────────────── - ───────────── + ───────────── - ────────────────⎟⋅<-l + x> ⎝ 36 108 108 ⎠ ⎝ 36 108 108 ⎠ ⎝ 54 18 9 108 6 108 ⎠ ──────────────────────────────────────────── - ───────────────────────────────────────────────── + ───────────────────────────────────────────────────────────────────────────────────────────────────────── E⋅I E⋅I E⋅I Example 11 ---------- Any type of load defined by a polynomial can be applied to the beam. This allows approximation of arbitrary load distributions. The following example shows six truncated polynomial loads across the surface of a beam. .. plot:: :context: close-figs :format: doctest :include-source: True >>> n = 6 >>> b = Beam(10*n, E, I) >>> for i in range(n): ... b.apply_load(1 / (5**i), 10*i + 5, i, end=10*i + 10) >>> plot(b.load, (x, 0, 10*n)) # doctest: +SKIP sympy-sympy-1.9/doc/src/modules/physics/continuum_mechanics/ildreaction.png000066400000000000000000000754141412543434000274620ustar00rootroot00000000000000PNG  IHDRo&sBITOtEXtSoftwaregnome-screenshot> IDATx[nuUK3CI8H /5lA1$bL`Y, `bf#偎bSR ${HΜs]VV_z̜azMO_v|[VUVnVnVlr+r+r܂ʭ@nVnVn} `}+r+>[[[y-XʭʭoVnVr ַr+r+[[܂ʭ@nVnVn} `}+r+>x>NtL{߹KW.+].#UE},U~=ɢ&cMOP](nktV}]dLwFyܢ -CMnK~K K7W#r\wLkg\_'+_Ip[__.YpAOVnVnaZ(1:?>#ꇴ!ٹ\UR|j>'L7خ_[7}9czd{Zkn(^{ckUkܼ.w2/7t*/%~fwLt#XĄh=&/Gwr'PHgL]j+v\dm4=n~-yFoVOGrýٽ-dUߵ5ǀ.{68Wu(=An s hy|B}3=y7_7ㆬnJ;=Ad]ru-s\rgY2Q|7y}:ronG.*tq΍'lQ~RJ9 wYo͋ڝy_Y/õyGg{7 mz0J?rrex>vδcy a7JK7Ny3`}Ʀ M~ YڨG<>ʒ5Xp5}.+Rgg U tA/nC~;yMu<-]ͅ_g<,%%?oێVϪ~#^& wcE=듕|*['OV5¶nXk. Y =z2vMϿ@\hy}+7nl)u?}u@%KeLk\"T}q[[!c7I6) ]yH%+Jq  dv)G=Fu..ew{Q.k人}G6Iru3.9i.9v= _[N{^?y)ñ2:!s\sPj櫙ЏCV]WC q6+҈Yvv-xw1޹A_[\*-5`(z O ]籖?E2= Us+&4eR{ŬW}h]-F9/Ǜ V1r=ᑽ-kJ<1 O¬˗M^j” }h?ZSt4ZtO 2+N~{fGoijL鳿{Xz#PKR(-5ؒ5ObgYe#haߊ}xqac_l$_r.1˶E@F{ɬ!\*ꌬV'ۍoB :7`ܡKc2zDY^Av+_xuww/9>Q o }TfצeFݚϟs?3п>fôj2NMM^$ΛP@d4շU9={ XgûQKR/8z::TO/ )آY匯ڵgH\Eh^־\d] b&Rx~K_^k`֥4RPfu.5W=Z6+Rv>ހupmUDK&kJ[+ʳoYLo]Z 9g<%Fj="5El)F*v]wg_W?)?rx ]˭z1* M+s\+-MvY\[6:^{dx6#U[77 mBoe]ڑ^:XMZ,{뻿~_.|jԕ b矴vxg%x% ^WgMZ'g dj:[u)@W^tBG"+\~ҳ766a-s(^>.ߝyY`ɘ[i7 cw?Vq r.G:.p|qFjn|.Ϲ\/,~w/|/ `fVUEPgrrT;M@DگƿpӵLbUɅ,|Ѵ=jRDJEݰ˟a@Ŧ(lvC&+5/4إEkOX*ʇNW>QZfpB@@1(46zQz\PyFfSPU2%3J}Ezpxh$2&]7I@Hdv&&bP "#'%V% 1A3@\e`? CS԰@^cNhCyC{quRo-7؉@:=Q<*s i9-nֿx|\۽gfx>_QJY"cWDʔKu]e@K"dN~FW˥x*_c^\:g?K(S`ѿ{AJɉs8x7oAvݬκl':H9r$"u@G'!Lcu<<490C6& b0!`E Uj@ * %*jj!QdS'(DI21^6 HV"f<*}lYcoen<-u6kV]jx!3MwA_i׋y.\q# -?50Z~JJ 謢m4{t= >|= պ `٭v} 7&M͸d̯}/'}mBM`b02Nw;?x(k5L㜺NE" D<(2eV@$(!1S P["4c1>sYƋ9 J^!b:1PL`23!P{$Pn@Eΐr1:@%'(18P JomZ}k!msU },rNv]lYum~{y&٣" 8$:[\6{LXgqkck{ū/^_}A pR>?I'a8VQA*I5%.C!ױNF`!&"JI@$NWX|;DT* 8sdfff/LDd;;=YZ0LD́(oAʠm"dH \G{h뻠˱kiMN6NjX[nA}Gű⠠u,X&,֭{2Q]ʾ*_*aԬ7Mбbw}PSۨLbR ahu&o[[wMR܆`Z"r-RQfZ7+ZooNĽu{?Mǯ hq9Ow&lOqà *L91F8Pv{'$ќG(E%;9.tP`,PEr&IP 4YE""D U\ -{<3 AL:C!Ex҅.r츋#w1t6jH"B4ĀRD '[]BMXF#uAG]TL'\B8#W=+B &5rV?wĠnEKt`y9c~ʴzM|;/eitz륦^{JI6ؐ`siSEW|Vd~^h=eW/O|S/|o~&~K/n?O}}c<ãӓOU{E/{{G |6OI.E@!5"H!C6D# 9V"2E?eēۚMlm&] AUsYR,"gLlf)RIYrVFt%0^x!lƯ3UQ1pU}mB6DWAߵ.$gYsQJ*Y S}He킉9A>9i\9̩qO"i#!p!F:9xj$Ĥ fL (lUj,lTH>5w㚬v`>[R~_Q4 c"P[\[:K *RwXfco!#6ȣB:>g+(6MYO< 3g( rM7Ȫ00ݹjl]XBfQQ,dA"N*}ʋ$CÄTH5n 'ب#"EJ2RVg)k[ 9ĬD9N:ֽ?N1Ƃ"Zwje)f6 bL=,HfHҜ G5-P)*f7 2"$$DB8HYvˊ(t7ʔA@& AA#;(˲2#31.FM JVcox%5Wjٸ"iՉMJkq )fJI2f 38,*t%['$<6"f=ۄl̲#.;?K-Aw\]5UnEM1tƓV\g9)ו!!x#?|sUu)ST(@bh4d2Br|϶jQs<DDThUJ$KP)Z#7ZEHYM$dRJʤ&]c0ԶmMK&b Tc8R{eY$KeCSR\86d|(H,&UEaO07*4 (j)*Pf`(9]Qr7S2˱ I" f!LBY*s&G:D0Me8dU@ CF/P[ 3&PgL= <v4=EؽfMH#kzQƿvWKG fUQ!c(,"8ņ,(Yrq&儤`xІ:/RAhw/C}i_;^*NיC{ ehI\eT,dO՜Tr HChayrR踨Ĉ傆pB݁:[SJ@-JW#;7,XԻ> (T5)} ucAnίd>Qu\(뢂3 j>P`ݛM)0Y'Ey>"`f%R3Y_W~ʐrpwPm #wTo{oOa ƅ,fR Rc;is\OM㬌r2 )ӌ0ׂd^yexxQAKy1ח~+??X/{ؿO'?z؛uV |ΑJתqV̅6?Zn5JgT:f9rGǻ?x3 Mfwz{$v.2( -՜r %rZRA (3]+gel4u1:+e6P#b8ȷaiel)ee[>TLVQNTA:W /o۪iI]gh)❑*%wPf5)z5jV*I$KN(D CќD2  7}Oi\)X0A 3s bB 1b+v^[/lhjs~}vJֻ|$YTT.-1Q3 5NI) ee)o 4^n4T{f*/oժ!EYDutgդCJ-=rKUsE6d290֢SCH5fʼn5u+Z}"sgy0(pcPxl l?dlI HJ`;zd8u,s! 4w o}lfګsw˨GFHϕ;[`qT@L84 5VQ)[i9M"BDsVf&NN,fwݝnV3bNCzr€EKrUeI٧M"j_bPեQDy@C ep?3ؽ#iҴ;D~E-84U"܎!t^4O[]}XýkvfaHc*F5UonU=갱7ֲ+L@hD]کC'wJmÁ,)R\XI-VAZOnm*ցg$.qS[*Y-$ߐN-k@WRBkh&Ґ2r}uB^DZ,.7#ަKB@L$'Y7vI!]&]ĮbbPgœu;u>s,-1BNm͒s/`'~ _=~T߄J *mp+f++bq<*U.㺚Ojg l%)UrN|x|$ٙoͺޞo??yl6 o,@Ph`iހ9#CM!qޤQsQpmfpڧ]W=+9C 52R>-.,4! f2{o%_=lb 8qJݖJXzw5' 5YM+&@"yajusLU3CwZ-@u!_KhxSqi ~/C&Nħm+^Vo&aQZmz҅9tsNSA u+[%Z{}l6aURdQDP!7',|s0sاx Juj/(4 sOm==^  |'^c_~`so>ҽHu"đI{@ܸ ֥pluK H(:DD)CӓS8fwf l|;w泎y/}z*!uqBB2$KY6lQ[F)*@Ǚb H\,N3͂jOj'ۄ!Z(/8H41VcTZpgm4>U-յd :/sc%?th :CH- RKvк2-۾#T<٧+ZS$puKGܮh_%\B%h.:Y3_AуULAhU֋ )녚Vf.`ˆȀfDK+5hG/)ӹcIʜ:Dj.k~C]fU$ŀ2]q2@}e<g>07BW~_S,ww_?XL>gsFȸD<2{+v~̖(Cdbh 4˗`Cw)INC<"S7lvg{>"Rā22wXm&D*QMq͖粤5?g@HX-tbw"c >;mP:P¼CթU!TcJxTC10˻9*=+\we[} ѓBE ?V]Brpv7FwQ}=ԟS63[cy6y)+QGZ pՊZ^<cGU>us#:;n꞉!HSyOٿT6~" u l TC9Ϩx MeFuJ ,8Sl+t=xT뫄HJNh<$=a3upw͒?]s T3YW_'>WB{/?~~ϼu8_O|m"cVG \K=:zz);v\f~AE9+ge͔4-OCEY*6aօO'.֜SdR/|4G?B3<5[$R e{^dkIi`̑@"Uu#$su[RwYr!)TTJ"1+/1T U(5ꔯp"Fq8eBXܹB~o*vhJ^#/\EiM$x'&B|mtln%宎l7۵;o3#;J|4KC67c\-\RɐOls1\S`&(*X-ɘ1nQ $UP<c-~َ::dS UjNPA !p7sGL.,B!+wmQsKi޸%ɗK_do4I~{X|7[>s!OT\zb5;[z{_?r߿{_/~h%n:}#QQ(5QF@P;Sur/m$:&83Dð}N~1C]Iv\ˢW.Ǐ*9Ie#f^V&˨st,@}8"ۅeh 1:P|]3j|hSZb5\FϹZ2ns3|-oB'nD݌m")P䔆!>Y]&tMQ(gKY!@"rnTU#!e>"aNH?kzo^x2-EFg_KooB?4V:y%cW!;+{Qu]WNb=0{nŏ[L,͢}b1,_$8E=1Q9дI7Y&ڧԟ INj|w''G!=T?܏}G1P>ȋC7tys0IE M Iia*if0-?99P[Lc(J7CZD~L &u]%IPI]A)$€ l\1Dڱ?y}P0C:넾ƿ(NL+2@F'<jԆPw&6PbcdZ:M!2lj>-&Q&GkRyP zcQ^Zbc[y(L%B3Ҿ,PuV(%bPw* o*w%w=!b]W,, 0iFqnW!tqBGGG3 EYaIӡc[{{Gw/ntV&L9+_~яc+,}^kܰA|[m~]"F3zijPʐD1>=<:~xrd4 $NΝ; Jtf>i.rJYTt$@J 4R D@Nr:dGgv{OH%Oxlĩ^%nw;qf)'IYɃAI%iڷj0bkwȠrHe2f.h JTb``Ć3FepQ^IWR0 2j[eL\EQ:B16mDCN@8楢(qYRIxEP셒RZI>< To_&㏬. nV5Ħ8MXf{"uJ{[a:4kL2>yXHhB}G)K{S7QrKqUP-Y,Qɱ=k{kjH"{GG}?{ w B?~yuqk2ALqf] +XUmQG'?{wI"hC̝;?{q:Mc7g E!XԓHN'vY#Rd}8L%Rp8ӻL il!Ǽߥ#P0IbéPvÜgmV,RIs_}? )KE"B3$$**&! @e;+wD '' $4±-ê~o4Ul玺Jc mcnlĮgG6炠1 -[AMG{tQbu'h}֭2G%5ڢnmb ^`<~sͽ^n{kkrg6{f>S[[O?l7jn'n: ]TrR^)IJ:HEm|!ޝMq:i]ڈ5GL#&A;;ii8?oNA>0l5ᘅ9VLc@ ;QYy'~ڊWhnGֵy"}٦ƍd]- k# V h$5%2#Ȫ N,GU| mBD Fhm3ԬB]ZT1RjԾ\im5f, `n^UgeяB>gh.>/*`Tձ$<e 7sD#6NOL$eʚ2'!"(+K ..MJ>|a޶e9曝7O$k5ej}g>լ'G1zIfө0IvU;_ν/xs?T}o? S7GV)ڥj/o[?fPB'||iVm;pl˧R$ڞ'Y#9JyȃM!YTLAhV LygnMlkk>Mi ȓȓ@S "Uo=0G3U뭹-Խ9|"Ea¨ٽJnK(lSNU_(XI5ӸJQ*X_)14vlkAiNNjEGbl!o3~3¨fYgْ{e_kc4Ks] QDD!NO̷$}J3hs-j>PsNIr֜D%`!f;ڛC` H!:!n͉!Ll6g٬`Q4Ő>/ϿVǓ)J'r`Ⱦ<,!\1 cC ͡yEb eԭ ԝ$BX#K ~CPD{4͞H|8y0AY){^i}Ds!!%s䬃B$auqg_L"s e 4/=޲)bH˦^K=;!rQxe Фu seŪҺ(f)GuRPA7 AKp2 T3rbj xyJVzZe%JЛYA bH Cj,\tSj^~)Ì".$Q L1Ѱpۅ3;wlN.b!>6PU- l]]EO Uƴ2s D\N*J~臡~b*֙uAeb3aSPV[)g^EЧRiaD̡#]m+r>m= Z ^!F1>@Q`R@$( L2׿v<ݝL1N'@@f&QV=:Z"*1 $ni~ !b"eVʡ";Dƻ;#HvO1=M14_K}MVouJvs%;z^귩DSGG ‚ї@ HIs]yiHyȩ`RӐBBsdFjI% 4eI 9!LvEĊb@~:@I(bSȪT&S*8!  F!#P{GAImr7GԮ(g 8=БࢴϙD2yyq'h |3[E[;ӆqrGbڢ r:o=x{- g[àc%3rғ}7ߺ3$!,f1V|X V΁8i/:d 2lȍd|I3U]uf4 ~8] bCʁ׶7{<>ءK+TVf5G`5)nCe@J@0hdg,l'<3{;8C2LYI#j$gی$lf`p(м '-?T}Tncgز o- 1vh ȁ|NTǡ,I.NK/]9N5ڽ1 RadF-[,k>-Gq,0'` ;152g Jf'b|3FEX1v3T Val-iÐdg$|: C2A\5:Jg(TjB"PvATm74Q54]`6vD0jY$bPPDE"lHHȊ,E !嫞ElRs5PAVEh={ٹ=*].ۋg#q")v:}|'~ yH9P~AzisJ{;rKcMeDy(R)G է>!ʪMh蝩Pxa%;G}S;Wc^(1]PӐRZ d EDd|Kj۲K ],&gyZSCZ8hpY Yk<KgKu޳mݹ{gN7RaH)gdnE"AIoIt1j}r͏ VZ6m+hhAm?KbhF)hkב^%TΪ%oPl8nP2.l+X˪nkk'H9CJ9J\9T[q'tmsq7Ej,"]T-Rb@jl.";yCy;x*Z/⸡6CUc˞ ̞E⠄p1L4 t zq7$7nQ33Kl赪ѐB "9RH.._Ű889)R/mt㰨fgږgl{B5 b1UNT!Qci!n !`ˎesɞca{ll[V0X \»L`,P{.v˾FúWp"jl:z5{7uZ, *bvr(ಋח!Oj['M/:WVp \%fyb*]VU*L"Z ^^A:! 3TVJi@ .HQ J)8JSI&L(DBD2N\^x_XI&KLeRsZqL#J@Z!(bB  I2њ4ɮYd]ةәwD Z@djg86ikؿS PLvӽxOT`H |pWsA-^{Bڅ6z *ŠI]YHm:B]ɠ/1u4/ICFa#`k+#P9?3{8o1XDol@WT$.A qA},7? 5UʂZ[lLClf{3hhѓs{L&! 2 IPk++>/'t+: =Cb]9Y܈Tʲ*+.ZJ[.,$H+^A^QW5`1]RsE\.%`#.$k-(J4%L,|j̴ܺw|j[&:l# `̙;%>!VucfB솈 ^v`^5C~f9;sS"d#/˦4 e5v\\Ϝ t+`FqVh h%5|yB99;ȧ;g0[1IoL][m?W=}Xsi̷DZhvdr@ ɄOaUڕAkPU *hrU6 *ja %!#31@0 AhOFIoJVQkQU\j$0WZ\@H+[ZQ +.5@BU~ܽҪBelR7) G DB2JUH@vG'خbMt$ _3@3 hzZRZ#j\sp!ͭ׬9;͖SړMv\`[_ .v n026k-^ 8c"{sAOog ڧkZ= N2 ceCiL1ր5 8l03y"5nnnJ4SS )mG 29\Aj0/HbQgq!POjmjTƾ&ֶZ@]3 ̠4*]TUYA1V@%*Q$PqA"$@%WFPUիJ]0BJ ܹVeqAID{BAEioG)خvw䞗xh4r~I.A\`48lO=(k \d2!#i5TC?l{EZ0_f ޵~$8 4.AmhS;qݝeX5%DոϺې1>ā<'V8W0~A} ˨2puzw S9 v"Ր)0 fLLF P1+u5/z^VTE+"`$ Bhq$9,f#s,E*#g}K,J,4y } e/͗e'ҸPey7޷~G51*  53Y%鳖;2Nj23ɴe:@~O -fȊ~Bw"0Ђu}za`NHmGX˗> Xr:>y)5O1 Чbm-ӍߝrA,^[7*0$J\804~xh Rb'{yU(]_YuD\(d((8R(*yϲ~(BrtJkY $1HE1΋?ӑ1RAAi`? Q#kd &-%uD:9M, ;\O`4:xvB8zވ;f^ɹpiBI u }wpazA8k h 5Hߨ1;8yƃb=.&Su3?mWim ±L\\Dz-km{-Bd|W6c \29s_ݪ-ˢ" \;8&d$eSdE罤V*ݕJ._׶u %1XI+%!DhBhŝ(d -"m񯶮+ZkNv 6H"f=TrPЬClnhf'qV%z*5pkϸ1ٹ:fjm?~FS?0l\|C+pA66ȂfvH6|ɭAf4"̠Kꕕ2KXܡBX;7Ѫn^PI`bϜkΘssJxELHJHx%I$#KybqMVz(ҫׄbׯ8sAQH21$ЍQU:@ӫDo6m&& 5kẖ]D a>;}@ǃ5Lædyj 5JBx7;7@?}fJc<5i.k4KW'˚bcte&ʸ6fcږV%f2+bp $ 9cӜ3' (8q7HF\EUE(JUKŌܻ^YP(4.b% UksGk]&]t޴[T$IW5;7g5"F NɃ0Y#{ܢFrCs<-Iu'ynvW^ 3 sjvrU]6d7{ l0[}x>9FG.?LklbmQ[ATjA$?ׯ P@!א1dz }0]A!H2tJ*UE֯HT?w^/TR]HV:pjNɸ4dJ8J*UV%"}NMo|޸M4@Kچ>s_7Z٧X .;!Zyȃ:kh5FDPC߆s][{"9nԍɾ- 8Kf6h}5 6tú٤4"Vp]zO#05Ϙw nSl3+0f.K@MH3TιPHQHM)@/vsuA$)q7Mk8튤K2' _ꬼ~-oxǛn{M7KXukAg(u;l9z^Gֳalg`e j0Uz«*W05j\;gXZd_{=f K1̽W68!LLHGdFJkNyd3ݰsVlm& kLA2"22B JgeRBq2XT, R@~Uk/^΋[߹rr$)$WO7ԍ;(4tzkDn_WTUQ Dh{26LkLllJu ׂ6jSH‡"1QˆtԱ0p !,Տ) 4?p<`dGHLfdP)RZ(!TJ ?ɨ>?7go{I3U@fvIkTQC BFRR ,UQTy^yYT8IUeW{._}_SqL"4]Y[_敛nD${;{+;;+o믎Q*uBiBa ?me+/?h oȇ2-5z`A\yU"DF7|PQjwaydpB.e)~,5a56t;Oɧ`D !hذyδRJ9VK~@1Qj5#iH )^@PPU^/+d_{Uw޵vʌ"v:Itx%NVtmem}z]Eʷwno6o廾mgOoXJQ:l2@m{jx!bK}GHwʖYkI lY A.4&UMR `"hM#Žk$ Q 'Q k 4t$75oxͭz5d$+]` Cp1ǭGn C)Ҭ 3B~q 멠nGa{ k6|NV54< VGv3L~)]fv^5n mwGɬJh2ՒR&%.<3(PB*JM)ݯP@'>Z j`<-+7ۈAj6fdm#k6z\Gkn #h!MpCo9}`b@ ;#΀,!شYk]vbFݰ*7K>M<դSN> g2LjS.=eqfꢛ/a!MƵF/ 853vbmv̚-rG@&FFb lZV08 `sd#0K$DIW[mrA$&@3F4-ⵟQCc̠fSd;9e,,X/miK[T3ӟ3 &3瓵:f Bj7.0T= N063;yJ3@1IOo32&+X3#[?;w*@!DրXѽeKkm$" 2u`)e-Y}ba; rn /- `%f o^(Ruj$.Ů gq0+qػ%uʩEͩN/whW466=qQPY#[nVl5?,vkkFr2,8Xf2| U71wc=gE)/1J3~%Oqd6>̀棷&_%F XNF8 F$ 3'I`a؝Ȭ ЛLjVP7VyɭƫQ@&"lu#GZvHmDaeNX/miK[  NhfHIb7CX7Xgfry)a1yHvd03﷭2 " BHT/faD0;X'Og 56G_?|Ǡr,xqMsyOkr@.j #`mzf?95G2R|u0DD!ԧu2` Hl"kŌ @Xh̓p ݬO>$`༧SiW^ (k=GpT60a^[r[{CَVQ6w3#jr k|&54߶r~Od'# t#szԲGHYlEQ\z[n9,m^7??O5KO>G'vr}g)λcO^zg6O}s-3GYh3B7>@׭BJD2$;lH;;p6/];Ǟ?ٟy{/|O>woէwu@3w{ωb♢Q![)`Q>C -B? $"IUx~8n\WJ!^j߼x=`j 0e00Mq'gמ~쳾}ްNiӱßic1,Na az߽ ;5|G~g>X*؏~|_czO|=xomeN>t':s4{JbZ=&[xHkC^Ev>w}\Faw DR.q#c~55nٹ*U]r[s%}g,,DNߩtvvNI$Y.=}/uK}#=oWϼ;??sɎz>d]ßߺ&Hފ>h=F]MHPccG8CIjcB^aTvzuugx>Wo,gYeY?gyfϲ,z 7u?S؝vnb]{ÿ12>z̻O~q?~;51yܹW~͇~#a{k V{蠧69 Uq`ː?0P[Qn4*2a2Ӏiɦ[C>$X=U{?+]!0q$Ϧ۽R=[dϲlmm{k>_C~nw v#EV󧞼g_ 7/PB.=إE(z~;n.<1@Qzn5=vG,8#ڡn*Ӭ :Z?:? ƬT@^z :8FϽ,ճ[7`Uڴ孷[Ug{/ԚPviwݖ˦@Oo?gu~at[ym4w1[@?ip>'SiKo݈vO/n^whyy7O=7luu\J^E~yo~eW\yv ~5ܲ[o-W(%'ނ;q+{PO{:9X6\yw>"ޙN{{%t;5 !ƗxMnɧ6~w>y߸KPl^܄{CP8{4|#SϞ?4kԃ}^qJGk9ޙ-nH5e@1o54t,7 YE4`kkks}}v,5yr^w뭷wADgȥ'w.]҅z.8}Ny/^w  l_>S}n?g.|9﮳o;6֗>߸pq{hu$n7Mg3O~++++G~/vZcCA.ڍzcPظ9ŚɚuM{n֭YY/~ oy[i'BԬz~'o=dIQeSYbD;귯%ll>?1~i7}Խ# %L/mi'11F~1"scJ>wkoLJzQ@(ؘ2ǫ#=ja!>n yN qg˖мO;7]qpQNKcK^N Տ9v)́ ħ+ny֥--6)*x}=DAG1,ǩK[1<>;^+іҎpqI-O0I|tf7|ٰCQZ!{07ҖC$ v:o1Xtج!R'{ <|ӄ/!n͘X p%Fܸ#DK۟M&52o'ǬG$>/Lc Bt`Fe T1tl!ɭn0;8\؍4[z,miK[ Ý`OkB^QxԣqYi5K[[^](".|ˣIENDB`sympy-sympy-1.9/doc/src/modules/physics/continuum_mechanics/ildshear.png000066400000000000000000001327251412543434000267570ustar00rootroot00000000000000PNG  IHDR2%sBITOtEXtSoftwaregnome-screenshot> IDATx}eWU/8\{sﭺ7KBPL(4Q!دEPc;GF^5>QF8FG=xmBA_(X*uJ*㜳לǚsSު_Nn^{}ߜs57L(((((Qإ`(RPPPP0}v)((((> L] .Ga飰KAAAAQإ`(RPPPP0}v)((((> L] . ݮ@AA%.pO|nףA(u~w_: \*(c>stnWB=wq>ء~?w6~Ņ@WSPPpI. \Z(RPPPP0}v)((((> L] .Ga飰KAAAAQإ`(RPPPP0}v)((((> @w頰Kb #LJL("]]#xcK=N oËoo]\(RPPPP0}XAAAAQإ`(RPPPP0}v)((((> L] .Ga飰KAAAAQv =w.$mjvvvSPPpѣd)'/e5>)((Q L] .Ga飰KAAAAQإ`(RPPPP0}v)((((> L] K]~}{|kQPPP\ǥ._?Էvu\jRPPPPPإ`(RPPPP0}v)((((> L] .Ga}3?[yhɾ_z7/wxAAA%.AozqkwlC|a `{rgznװ`'Qv.t>{ӑ~ぅ_릅ݮ\AAA.SEۏt}鑇?qgnxj)((xnR]K_OW\y\;;7ol;;;7:77;o_Md 20<ı߻tTeƴVPڱ`pmvKK_ 7ܰrܹ'OՕՕՕGsfg37;7Soz|~s[~-F~ރC`X?SW$?.5vzqq^ oٲj-M++++˧NZ_7;s~3_/%[jZSj[uݭcn^ESϳW:xm5C?Ýng;xA1V9ی x1iu[{/@ $VOaN.l:E]x«nyny5n4yee%rGrdg9o~3J򅷫MD 'G^yk^}ŹS\mPL*id ٟ{?;'=q8rw/uoil>5G{~O$^k=x˻3s]Z6e0+e[:z^=zNo[S_G[qι~__nz+^o:pդ.w{#5M6s]rliCѷx_sz'w|C/wɓ'?/}J .flH0"0ۼZPvSo9rFu0ux;o;xw}}wn'v!pnB-;bbH)X_g9şO>rس\py?/Pb\4".bSXrXf`bɼ捞2?Fv&H5 v2pMȆo!Qv7~sX-RNqMc\m rٽ 7rON]d\}/ѳ7Oֻv#=N.z|2N6u#z|+տBNA5/pR ņ XP:V8]8]/xݧ ^K[Ĵyett? yž*߬sM `r v(ce2B6m(p(.Oolh ~~!\Lzc>6]a;>'\zB1I96{&Vtdncj2FXAAAA˺N0l_q׵W16ԍS_^ac4 i3 'L{h"Mv]Ħ0lMǕxɽ9364|q q]8Vɂ$XÌӡ܋|HٞZJ]{ *a&bOM 1(˔Vú7uRfG*<^9qٺ~7`R>Չ<11'bJ 뻉d"xkeV Km ;RO8AY~2Ł_PPPP0}zƫ+0*d[Nɭ͓." vc=ßgر'׃tr~pXKZcY׾İ-0Y'؂ѱ3\TqÑ?e'>-lvVNe']xĂ lTuΏCUul{V@DeL6L:KiSݶ.ryra}_|coy=Ë]-=?r } 2aDF-6YIeb >pqVhcWCc;ɗ46b"cŸo:Ғ {އOt=.^ǻ~݅\ "6 ^e>T$ϙxo#{?uOY̎dl#k|m9$niO`;2ez^\F~ݩ/}v)2:Ώȏ?⦛~魿tk_;Tc'S:s#ۿGs}8#o;)3_xd)((kn]Nm=Lq?pņcd|]O}>iP[?7=>>ʛ*7)?xp~o_\uw;]V6-AlXmRsYͷs .ro-٬.6jyv]<ַ=_gφ_wjo7g;osйcA}B_0Gn^hl/gcsm*mgݶ{LEm$2^o-o^۽O}soOk4:h]FDž["uŞa ~M~T!%"" $$헌ZI/W|dekRI;ڰz}Mhvl ޵޷)&wSN.Ʋ+O|mŶ}GpSI-ߓ&{~R61Mtz(_Av{dU~O>v%k w} D8yjPWmlG 0/ʎyatH7ä_o~+sX7lPɗZzs7tN`"*ȰP=#̴1<KoU=Ɓ8{KǖLyW_-, [o%< hSd7S᜻k]򘛛o=~<9|᲋9=.> 8ُ0ή2bOc=`y.80뭩c?6ݚё#ZE m¾:_LAv0郧2hGSĮϥ]g㟸S70?t "!C"$"?9!{9@z%/xw-xp` ` Cxf3 {BԬ7!-L%" r]l[6wx$쟸+UƟ37k_U$P ~_suݿ~G,\> ΃h1'7d?CoGDN:4r g#3 l W (YYIUxx-9ɧ,t"T `҉w]/Nx؝.K+YO}DU-vtYia򑒦*_,{σA3h~xf@0s6БsUs) P :DGǦ;T'ǭO(@'UJ $,F #|b7O0$7+;wW_?'-?o~OC pĉc_g싽W? UQ I*;,U Bmbnr%nط2c~P |v/@@< !0| V:9`{Z87B)ǖa` x}`o7J3A ' _xװ4~]bQ5kH>e2UaU: ^B@lDWb88o43-:S{뻿ɯ=_~>9 5-:2WO=?z}#нjСS_qk>MqFlK:i!b\!$ǑZg1Qٸnq62vwN/ KQ%oOs~GMvWZ8t /o7 4g`09,M-yd,"!du lq` "ʑsm EՍs(=!!O&>;<EjJ(y E3AY"f~1nҲBV1gWWT<Ϙ-!~:Kw4jI8$K?zX{e >Tӏ֓<[_!p֣77cUlir{~^w_`^|wgޫdYexPbA,,$"($ ^`7H1:HX&[oP @X$Jn%z&2 !o Kg񲵪`&c˦wWruh mCsrˣ?5&;-ѥd8wb|8Ex'*4ȴ85z1G힏WU—z?~|,&/Y`e~M MӰL(Ȅa(V,4]2Ir*u`T ] i@}* pv`ړoC& 7lÜYCI ;vZZ{T^w}>3;ZD @tKDZ;`5!4ܲ mB hT EЬ`~dBڞpnK Ջ p8H2t.1y%+ыfFVpv݆ VD\a&\h?0ԒLc){iOeǿ]ml˞9ɰ?~gܒ]X\8Cs{o`AiMXhF{"8t.# HQmKijV5A%11]-H*oP2_%AC怳D{| o}w_}׿!cQ#0̍N\oeHI'.H3mϺ*= IDAT,SU6"SM`d4r5#:-v=sgf16 Cb8$\%xTdI<.:L/mhMphm f0Z8v[MDV) uzOjyHU+ᙉJ}gOuoOla]GFB  ~oo E&bB!"l(#x!7f\@3ϙ d3zuuһ35*dbZ[yp: {߳~>D徵O1C+ 6"1]h)(FShP&YMA-`tDyHȞ=33Vv89B\(sXE9".̬'* v Nx/DR mbo&hY2N= CU*"<ŷr m\2# NP$.ЋCz#m>>r9x]q[5ڋcz×C;^[^ Cð[Y뭬ًxȖd`uk/}Y@WbB^H{)I kœƜ!-P 9Fl|D?)鈰Vrб'xDl}a |Ҵ89Fh L+g'yt . fK[6Fq7S깜 3Ŗl Kٕ 9TɼyQF%D°gKwBF-V0L2$Sm&a؈i( ʵˏf`on8wl*d4&Wgw[8fSlc&/ibeu108znyܳϮ ^,K6Frr" FϮ"BfkBpBH#͎L6%=D!T-f: e񈰃; щ&_lb"찞Ru6]|Ffu H# UA5N ɸrrUUU 7^ X@!x6`*@[Xr+\#PW6#(_gU H9Zl6wy: mtZEJ5Cf@D $0v8"",1A~;Qa.<|汰 sDFdܢd2̄ /QAYB,03.pSuf(O\u5վeWUփ57@Xelom&" x9F4GAXbH#/d Mθ"0tiS1zrtt"V`'몮ꪪ\ DxĜDdU@ښ%(>NX@PAP`6ڈr2)oU&݉}a#`njd.atnVӝ#^@8Ȟdi%̆34H EѦ BF\J+Jjdd#R'1YL앛Eb(XD!w[Dܒ\Y]MtFN̘ (QƿQDf:IgF5QHL7c 8g|yGn4m+ P9#Q?Hr>JlVek+Ma7H?1@lnE/y={/u9JHUqU# c2X<{e3;p\gGe˷p{/գ`}.`֦ =EX3s@}`0ʁݞ\-Y^1`WOkrPHd1EpMOO'QZ*]=FQ{dl#"֬EQܶ% HNu(a` 5r9̌pLĺ fqa^PiCLb J`DH>pHf]a-r7 dSMBN6$F-*=U4%lЦm-&#[s1Bn-2;XLu\I8l?@JVV&jm0d HxT3SP(E3f m?Ba905ILj.VjxE6>bRFZhFax!1hurH5 xAȂ++a<}{gN>OZ\<=/ܷovӭ;m.q MQeAtC,^WX L8rϫ컎zM .n :/P4̌AZ@C1Z#i428tHT2T~N4N|t ՖiJz2!4 (.0Fc|& !E&!]EQ.=eG!l ;ya\U+UskrsWUպ@F/ "fN a}щ ̬Ɛˣ uB 6<F@]hV!*{FBa(L2cflK J=-CP0,)o !,Ϣ"XlѼ K{M =PIU(mo, l5(Z_C*.e&f4<i42{`v8G+@5 ps KЭSUp??>c8v+_'/:x͕lԟ٫Cjvk$0pGK% QE4M=8GZ~w;kf?g:NUyfT!S G{*N5c!-jgM#Er:;t)#9OYAV@ֈ-qQ5C%eP# 5rj_e.5 %- =CtvyJT4TL4ԊrH [bD)J B, ˶H 04 ? ۓvlJ΢GȄ5pΨ1I40m\Hb4# ӰLD;SN~@HƮUL;a`2 =& ")t-$3mj85Dm(YGSjT۬ l@&P._`x; _9lBB @]E@3СggVN:v_~jw:wc:[o?vIHJt0$j9cm}/S<}|jye\tjeu٣ !TN:hHT;IHRPGh_~SMRF`= $1DzK$'=Cfkʿa&"=3O]ݖ]|cJvPSyb۸DayÍG>=C7\34\UWuite'$""Ww.KiE܅hqp3`Ycs1̌ &Bb7&D Yn@*PgtM!ۚ?m˱z AkJ:D%.ܬjd!b\aJt"K?ܒ  ˯=M@1ٌĺV,61c[05m,xfIvj-V}AJ&L7 8rH !wM\sbמ:_;vG}~ueœwu D ]l4y[%dYBB[mkO ,={s˧9έu׿qbkyss;3 NW:bRZ(°tn!zdZ0 EFpWaQ9*a KTK0Gڙ< .+3>=noQbT1Hz.Iq!P%5QH e4="@kW^?Xk3Rﭮ z@3Ln|wN-Uu*TT; f$  "  Zq$ϪSPAސ( 9,AK`fZnDSWE[/%zE0p]҅[0zTtzZG#yW߼_?OY^P P- s p'F^BĴ__'wmd`[\치1x aNO`~9R U+ rH.n7' ?o(`xUNctYl@Լ.WuZ<.Ct-"#?G^ hAQq0oĘ\8 OV4`/] Soͯz _5t+X:(]ff =[%S5"0g>zA{D`kN<`6#v\T3`MU]W3nSwZ ;NUUթ*Qq݋ d@;Y9&$ڏƫ"Mo.#JP̆lI%wS@'|18cb &Lًmj^]2u- *d@F'E6U1J]SSB{Wkk_}wӽW]>xwk}>кX(bӞ1DM UGb8mQ O"d#&ȋDV?{vmm7 y//쟙t\U=+:p`fjb]1#G@[xn#^,x2v4=7\oDK$WY!BTj31;*wrU!S^IoF I@lwAk` | `27rlO2\(-}C)w{5({'jyEȂ˝v30Є;ZICs`oe#mW4y:yD*AsԔ0lO V>zi%N( i<6[ z(B%HM񠲘@u2Z"}gN駟 _r݋^^=v!@1!rfǖ%D+‰&P&BP[ۢlPX4/4 3D&qCݙtffYf\s3kAt]f\=י:,]M3iMc7L r)#!DAlZQh@-ç\a*@9B䙪^Ֆ PK/5=k0Bܩ*|-u'u,ulv`w;˫O5Щ:_q__=hZũU-~F>d"I3m=dr a誹SP%$DZE A7 Kъ LȄȡtt+vn\2۹efizŹzfv 5<sff3ݺS x7g콵M2ED^b}V{#A,m{L̔DoxffdHa˛6 mtQ @#FtLăe=6)" 8 GV9#o7`G>>ryViJfJGJ1'Ut;cD %8f[ψT4YPȔ +b]+ mL! G! YZytcdĚN0V Qc 6 EGX$[2ƜfNNo iqClEEOPUj8lOM;#[ qPtǙ]`X tU5 E#KqU1Q"od  />`5NN5rо  4G=cQB93æB.(6Eld9+ 1y> x|#! %7M#C !WĎ"fjVqP8ٙ-.~;9,UU~C+|nٹٙ[#  ·݇^Ӓxa3}hHkFRCcIf H>d2/H!6N`K}!}FV=W@e !!էK2 (Cj !ƦN=?ŗ>q?#GyKOcWQEywP4(Tl0=c6[TV2s4}%a*΄8; *} :A 9xohڈG" LVW|Tk fՂTUngܾ+??4ө:4G!ˀF>pk@ZR@XgY e鰄zRM+Uiyasþl*^ Ago,V'kfǾυeV"v Al ":4*`JOx uXgDV)9[Dtc<[`61^˫H!b(t/SײiϜ&U cO>Wqs$j`8LLtZ%[#Y u_&4D J@)10#si dHF:' 6* c#ȅ'BUu(ZQXWU]WuUtŐ/u)Ķ[jAaA7k LtAE >8ZC& 4(  xQ.ODlѓ#=l4S8)(DR:WkD$A 0  y>C# ZUȅEnt3sx zMV͠7VUZg׿ݿ˯xV#T" TU^4C=ۿG@\ c$ə$ w}&Ņ HxiEDŘD?jI scfQh} aXQvIu7`7'm=+ /2AbX;A=gP([0%ET#y2*Q1pc13UDI(Xl/%9@S&U a"v.)leqR"-DrNܕяH6jmmVb5zz4dWj [2#?׊5b'><'c 1W9Oh`/m 1-h&)o, "A,hSĞrÀbJ!ژGbnN~~ڸ.p&ז cC[}:3g^, jh2p2:FJIh7+jfɺ~uKK X,hQp8zu'&Z@|Q7 Q2qN0[}VR4afoiDzXQb'TH;T {l5OI$6#5q{r`Fv@G>}_Ϟ)9ŔDp5VN7]di3aY5[GM!M3&^qE@Ua y?z[uT]d/}3r_0ݿ3;T?{YvՇ9<5 (?rĩ\\6!b*REJA%68C8* IvL@N6P0B<;g?Z{=n{o|kzgoW*&JGُ2fhZ6rdAյյU渳B@᰹x60JӌI.82ZUF*-ei,=s}$ VSMv%TMt?iQdH32" vt !ȱz@Z` \qb `!K[_ 2!3D !Ө j[B4W#`lx%\+~,HX7ZC{PVLftI{&WLݤL(phO~KiTX΅IydUeH3BTRHJ O[i˂AiMA%M! s_$pRxd#KTԁut񂝷ĞI3A`kȈNPiY`\=̋YBw\,$^JB3B U qnw^}7^{wcUCͨ`~;[{`8J;N:Gl:heue}c}0hA{/|M`M9TXQx@BMX13EFf$kI .yG|.|S4g_9Z8 Q0 ZFH9@ @zN Y"vƂLT Sqp˕%V-ZyW bl}"Vcc@Qm0q$d@ D(jMIBnhK:pjڴN|T$DJ'b %*O/s а ^U`޺@[IgM"p,_&)ye@t?K8.z[$Q2_㔂HueSL0N(B?ˬѨCWa9VZZ,])%I( KT8H8G^A,$S9[8sSC A%tH0`Lĩr74d-Ob!/A}id]d;ȷwwm~֭kw6oGz N&T պCEb˱m6vtYB!a3o_rix[qm_yPPQgH( PH1"jXj "I2В ݤTzG&;Xta@3Nmk^u#nV8H)/'FbBl-D#>O>W(QZR |y @ެ@q+)5߄@܁E|bҷt&Mә=L<խ%%{22/&o1g!ŐD6˸(m}]&>"m&x"')?`I!{^)dU$HYTV6`Eu!ѓYPmwݸgה`E{$ 澊I%_:ܩ*VwVYkn/tpFf\wo@@qcuҴQ(E#ߥYJƢ'cOǞXZiWʛ5uM I+uiHp2!U)jٖVs JBh%ca.0r7hePcU!t|_I/}Xqׅxqz*hJ X}Ven;qoo~ƹuދݘ9U5UMU7TסnB!lw[_PVqOPWeI! j}mo^}gsue+.X hfNƮ(Bysխ ҹG7VXFDMB0ꀊxSߢ5QGhpD+ DBz;Zs$&(tA${+yczAPVҐBVT!ZRkNN֨CI݁@_2t-@5[EnfU, ?OFa 1v LgMG$DrW*4hԛCpj E q* IsƴM !})$6)ēk:ᙕ)%61砭@Ls_ Bd BCnO14@1XnbwW:ϭ]xqpJ1(KQ-$[./wH]~?#"VU"menY" yx2(w]P:w먨R w<Z'X_X?yR%DLB4fޏqg[n{;w;[-5+A6jՊjZjA` &ck@cEkB׻r3kgav }3?2}RKؼ0M|'8/Q- ;irt Zf[Y'ыŘ1J IDATzO8G$nXUHĈTI@»nZn_ڻv&*6Zb{,LD6ZlVV=i0uBth2bhV,ZHATh0 M]kS ߮Dc"1JcFDQi B2+xo.M] (Hd5̾ ` aZ2;$GZOtEuq䂉wL,4D IWZ'IRO>,YfɺHzn#!~ j|BOr/3\5# @Uu]Wu ʜtap)0aTƉ$Km^&-<REdbmYʮ wRt]Ů芚Oس;:QX+DF=Wc,Pg/QxRZkyd>!#hfkp C$­!54ImWn~i/+//<]>VUU :Q*-cI?Y (HD"bxLV6%K2 c55)!vٞ`LJC廒)D9j=uqZ})T "..n]7 V€ZMUj6Wlnm֭k/?xvoz4P%4]_4@%b8;BPUQK /;ݬ23kyX7\^o8튒:˪OL;L2[ Y׽l)k KI $!&lCӃ [Rؖ%g7yա0`ew1j!͓*˺@IE8H&I,^pnM<>)=Vam ̭8v؍9ftɒKL17H9@:N ΙWVq^7x#)m@rU5XI׎ݶ/Kɝk_zŭ[ð2Z?~aT+ ;u/.+HB $\E3.'kJKͥ߀?e(Y*Py[ /($#A~},}:E5uPjE3 'ʪ%ᰪPX% >qFPc' |1%%L,Ћ!0s۵]b#.r.6)NH=PXˏJ$@,TaXZ Јh8zz٣:b "fc%r|hjcyi$@XoݶmrZU^>[}"R،R$a*1AD`D 'B@5R$c1N؍ny]"C0 ^`DiRO` aS IȷHm"<&߀Mjy D:ΊTƀTH b#W A [ͭ;a}ww|g?ׯ_uAV҅zz;~\LO2&Q&-Gt&F&R\aBf}.ޕzhmI<\!vV#* ^~memmuey5jƹ.s[4U D@Ĺx @Q:tYwFF s }Ģkk ,Ź,pšgZ (k/a&+_'L_˗Qw1VN?vz !NHB;]*&?ihWV xG b+V51B≥cU_7-J#TD}* v,[w6_ݼ}}gkcnp،V]7nEQԅ) 2E!JPa:@]!TUC& 6uBr"2PR#B5*-H݊9-S!6i r?CU\tuD+& S;0:/eA" A|%/Jq(!l~W_~㽽U|au屫~˓=q#]Y[ nİSA4w:SB`tFĺ=f4E YKJZdgkR~$j pS& IO?{}I߈ P㇂[rG*Du}J;c>ѧ ؐ0ÇOXUkIE؄ yM A{75Z)5I3.gD iE|.D^l9j(;NbP3$Ǵq T@0*(5$H 阷xww^ʋ7ou=sVܰwv{oov;NnS!D B  ieX ͠Ո0RCDI,;$ FB j Dq/ʟ9ALBcH5_?~S. XPT0"ag5JL(MD1Ff93Le&@QECB]P v/U?|^ZiV(\\m=y!t@٬tiĩP_0xo*XODL5PX UQ@(ҾNhc}iǜѭA_g^mvk O R.hv!U h!A3gn3ج&)EGYQTS&BG]v@>S 'aoe#S/40) (1X&8k'Zi#cd#kXص*ZD1SV>TѺo#@XUDI񭽝[۝@] z0\޸xܥ.oVV}}s+7^xkw a-4WM=€h؈5Y=1wݹ7.֑ضm׶8nZ!Oe"=/qͳ(U[C$:[vRۡڎg7SQMq2 fV%4=$?&5B 5գA=h<޽/v{6p+;ȕ'6ί1T’Q0ɺėw D4EܕhfKonOYO|"ـpcL^hBƴ<0 jAe*ckQ6 Ul~Z~6 ^ϮgR M6q_ 54M -uo{U>zo~zJ'㶦Z3)bpk8ήݩe5KY hnR-y* X5fF\yCWS_>+"^l9sP{ di] Z'=k!0ϥ5LAFD)㒐m,q P 8{Nޣb :jDjlH,|t>TJ.î Q& D+oX0[|y60#GZG҈0[$0%s*d[m3;b/+Y9Wg{ $OU$@dOb~2].^^EZM@JhozGWL2CdF^ˣqÒ'?l.MķnE(EDM D fw[( b`ɵm9CD-~lwc߻+ꨦizF{{oǮGuusk_xڗ6o;VWVV7V֛fM]M3hnjz$ noOUxl}㩇>ȣGQUZ\:P5 ^ǵ}pKE{sAu]ke}dU&$ ^e%Up#;l"`6G@-ǽ: 9ZƨkNk ^%b$AUꦮ*kY.d/m7UzՏ=|qc5O>g4d4+ͱ01AHLp""II/(YDchP\L\wYoi0ʰ> OzԄ>&R_e="Q0 ԸAH*>w%&e D Xqo\|u=<:Nhڼ/ IDATr{ g|G@ DrDe\EYY #r ,L,\Yክ>Szȁ,HRW:#n[mhcu\ *J#1Gjvwwi_pswn߸-W+ T`~quՍQ3M*E" Hwo]_E|7_tupV~ ‘9H "Ӛ.vìX[mZSEM(pPT,!Qh""~I7٤IXialr4BHЉV By9(DDt,mٵ{1^.?#]ZY2tN1(biltg V\Ո%`f턆* Ʉ no-}8.R.KKMWMuǔ.؞IQz ]pd2Dg}(9g}?Cg(/̾C4^ekB1j6d"&dB&9D*y2,e2b@KdpF 4 5jahF`u4\ 䋱ָ{Nnloolnm{ShV! kVϭ Up!!v{gkWp9/]z_<53ID3S0kV,]"q0#"#BǾ9L_&;)N9{!`>ۣ[Zl0tFzSb *.-J/HGFD5Y;vK=h))f[ hao[ X0$%E n_ab]B.ep'""VJ;KZ݊zCFd+ jb2^7,nEsr=1lp Bׇ5q9<P8FDV1S䠺DFYEp 2x ;, D0zί]Gp{In0KjqoABXu54+kέmVֆ@ע*T!aqygsڵݗ_\m˗G?QC*Fx5 .Wu s@AB Os "+b Ѿz1hfԮ9hM* ZgH+a8 /On؞Nv(M2_&`" ғ &#,E'IsuD+jaL3&mb?>0IIg%iNF9"b EEr!LkL]KX,J]mZ饣4@[Ɋɴ̵fQ9S2?hD ^y6aF&#3aІB XPEX"D A5 + ӡ G,e`Yr#w^ۮuĎ6 f4 nꪮF]w1bugxݭo8K>tyu8X=u5tef'"-e;CV0*{ڋ0 @R=]:#JՊc`""0`Fva"lH"b_ b)lQb'ӮoUU5i cݸkui~j~KT(UjBD-ެ%S jmcMreãmy٤H˟02Z';V{0-d"ND;InO )R^R~iy@[S2}W` hd:U +"Bh0pH.gxt\䤗Y&tB{|0Av `Kt.2MC"IPPS`5;cwwڮmq[/DJň5 XmD*Җ5x8Kdmclcx+_rnKO>Ȁ hXsűRU0a7*HwU,;i 뇭Mʧ-_ /*:,nz !;ibS$_|׻"4 -4YȦws Nkl>͙ -v2qIեtjKJkO'i0 idvKDq0IH\D^[FT03/?,Jg`;x-hц_$60%A^-xCqWZx *0sfzAfjnB쪼0j$P VZ&igKyjSw I$XA`HA ! h5Nb' v݃Z@U|"D{moc'c:Vfu8\6Mj"Uj%]"NJۛBN˚2/(x~ڊ3{ڵ$[f??3,VH,Y@fPJh3 -߹@rN(N| MUO.^[PCyȯ#\s 8co 3?+62WTރ d?mħ%ښ(22D*ـʹJJDA Ȃ (HUª *Ii QXb+}Yag`d[.v]P+AX=qy1z4Ǯ:i}}1=ie%L i j,dJ&5 In`Qfl˘+@/i fJt]~`*HIK%ф?bzُG/4 h YyʕNbt~sVA(NΒgR&5u|}IF)/Req%s r]?X%)oEB( Ȭ6 8M # T: $!@ UB4e=ZOBhk1TQQ4xy6'bo{$T$hIL(\/յu8V15wA*p` n9tP4Lѩѥπ'~q3~+f xә`&Jb |9 n _ &t٤%(f!xN3%cZ)fftDCNxcٗAn1C Έޣ9iyNRnO֗zZ Ўa7ohƳZ %GǪ8HmQDjo?U A!LkIXҳcү(XKL]/6 WWE  l}f1=\cƓQxH+$!p%G2 f.ӣ]Ξ:pd#3*SR &s;,zs$W*LSyteZ*9&vs$35#~Rk S'l,If<+o&sJ_c}t61b爋??-o_"ww_?~zdl&~sٿ]߃[]-SDJ:kU4 0sRP! *ɲjTuT`L)c迓?9s쒎H8$ ][VwyCb 6fQcX)50)V.)ڈvw[ Z'!5?W}rs7y.هySgk jbnذ) Y A9y!I? hP]vUJMFCJ/ ?j%ȑSwJK |'?dXHXi`"cq +~XzKowrRNBPYp%'nם_UrO JAͪ6FIVuȟ_{ ( 00j,x>WVo{?'mv+TC$Áa W?B9dF`|v'Er;|Nq?Hrx=0[@;3h!2 3SRfdsuXĒ)c bOA [ChtkQB) mZ,W@h*sجQ xI_;YK*lƂ(W_I_a~@#<%&L7Fw&ZVA{tsF22~ ?O:3UtNITgw=;n^(+YZe˜BDI`XF fΌ7_mwېT_{7^w!/Xĕ@4it@Dmh`'HBAOЊh' ~b&4{3.:fR:}q#? |ym>Vzj1E sbiG.0dg> w 3N0OKO9=< Xgwםr~7,Av"$("[Y p*튦>(&"V-P#"( }å`KG3-?t`W.Ҽ< ]?.v*k s{?..,"Vb>VZ\sD aZ2i5%[T,S+5jBPk\'~GB#<< -%WTd S1y6XgydHw /}3_x^_O/7]w[@İsEq#VEʊi`"@k#Xdtj,T< &0=ɭo ) P\zZv:[˄z1S"wa$_.7Ox0Ŋ g6zKizlGɄb9 ABI@]~?ol`Go}dpb%BB"`^* Z g&E֤ЀRk_P42b S4/i@ \^ b%C g,Zl<'2.&s- ~wA_nq9L?Tp[S@"3=*?6`x. W -- D7~m3?9ؿ͗?k_>/|Ǔ3+f"f C]zw89F=LpDD{$tAD *#]7*ģ*hiy3-s 0tݬ;xG ޜg| \ۻp'[xie{][ȩr=8ٗJH}8ȧ-hZ%P]v'o|_xg>w &}Ip]z$u@)< jQizHѳMf q2Գi1U4荆.w}qQY}}j/g{;nܷg9%rw(hm~rcL& LqD&%/vT~xŪ.~~_Ku&ߛrt[5ibҟ I)@*,hw+T^P@2V,+$U^xݳϱ ͲΠ{}rk4?@88&uBKӁ7,iIMãi2d>% O[G7Wu䳏7w[ + 2^d$ò␎H A_RP.>Zg';]]o&cONy3s~#;e\&W F)[B:&h{\ = ]ttSJ Ayzb_+h= 1<ַ^^UUqd=Wv ΐ`~E>?O,nN >h&rӟ-S%,iIgz2 'sMe7~ywmS0yk)TʈG,t@xq/2PM?hr-F9]NɯOb›}\0]G~_|ױr~/Z}jP19<\k:́s3)]ge-42H]щsbDL:?y g~:;)ۼ Z&()BF .nhX*F9{wlb؟aĿg貤%=htS?w?xƟ/ncc0[/=O ,s:̌JiXiaLs]iO0Y̜{?x]#ŬDK2+9Ӵ's~Pu:خ|nJ .,eIKz0#љΎc ]7A3O2a#_}Dl:jT|@_rĿ<`U֢Tu~ZӪہ㙻|dr%.W59N9\q9"zFC{Ci1=FgGs9ŗGX=Y<2}33/dLؽfZ:a\arv~Ȓ%- OpN"LBg@: qaaGr s]/oIV瞮zz.><VQ鈽ytG{*?SRx>:q$M? g0-Cs̞/HvK,rŮp)34qys~?vC^貤%-4;xIKZrte4s܃u5#>?lYaC18@K%-i,H[q%ɳ <<:D#*`Eh630G"ͬ W>K$|y^rgI ^҂t^Eff^^`e FQ'Ĺab΃? elIKZҒt]{zt`+1GP\f̢{‘OXuO)fkGg`82A l!dg׃8nKˆrc"mq:h:Kyhڄjw7Tei[Ғ%?Au Zx:j(В=$EP Lds],IDAT |̓E}5Rk-yKeIKZ١+i۽|i9y_fs]~89$~pЧshn=̻׽rS+$N2w#Dѡ`f?r)9uݧ'yw'<1-=hXȖ%-iIKZRw9`|'=W9Z.A/',G"G}%Dc,B3a޽ݎbqD@ u+sDii[Ғtv !oZ.숤K:tKd_s~3N>g/g+Sns '&IRwYҒ%?-u%-(tB*BR3tQ\p3GB=x̣~҃2Ks=&{]HGuG .5 Nzn&~ΝO?O|_{~ۢ?C~9LV#S_>tآAϒ׽ru9z]/~'R~mϼKѨ~?|xc廯O'>gЏ??s_^cIJy%=t`/XIwnݾv'?׮_/^]]׻ۻ0VVVVVVheuu?/Vt@aǞ8g?~߿6|'~o|ӏ=~K~?c]?3W|GOޖ4Mt{W&rbN+~qO`Zo:C͓_B2gwVYa2Nik[k7|6i5_~˲ 0 _]eYf0,f[p!6RD*H%R}UuU)φRnn{,gk}) e7/2*ݞmr/&tmmE͉Ozt Mw$0#gL8tHS_Z[Z[>xߙ.2_e;dcaXeX{܉*-TWSO|ETp*G9~iUe7Yr?䤅7ͽf7^~[$Џ*ssI%ݷ{w>?uAhv_2"ͼ< }ѱ ѝ%E]U3[|}%˗v1Tќ/_sMwIR|:$>˯Ųlf͖-[O(y/~C Yf+bG q| 84`7QP tbҥLRiQsF;y\p;Vsel62,0wޕ )?.% ?9dr޽_\h4͛.jd%޽==zzz>iIZTzb&M5RT$кӕum:&⃅ ͵5n)3J Ǜ P-RV|WfllzRfE˝9`NF@Tީh^1'0ða 12H$n,_|K/tt\488|UWEQ|M51Vw&(m]F@ХYȕ Y{؞pJ/*# Bf6{?ݕ+?ל74Wq#F;OwEиtKK6L2gcF.?3n#'mv9D*jeDc-Y־u0-yoڊrsi<99=* ѓ8:Dqyɇ/L賰\S\]R~u .]VRawթNNWi769/ o 4L~ȣk~d]xB:}%KT*UJV;g z1=u.\p;w.vv 1 /rmE9XGal\& %ɉ?޽ʜv Ł5g!Jh@*)dċ튜=ji UVFJ#PebH8UA4)yGAAA1kƬ]_YG|H:)B}A6(SF{ם1~xܛI\.xr#p=CM!>MWa:zβG%` Lq{U*"--[%xe,X(,,,lB9Ȋ 2`y? /}D" f]l\\Rrr+Vw&Ng/^<KEwRY aͫt84M$ QΡPF9 c;}ʬW) ݥҪ P쬭,ŋ[ցL= a=cYvhhuO#9uI,*J}n}ۧ]/%rĤ k׭]z ^|_''s{Q)!%5qԥ#uڪ404T;EA$MIpdH]S 460]f2~(3+#ʣ Ͻ72͛wi#'=|C=3?'#f vh0j5Fs='Ǥ=qE-O8ccvݺu֭[-Zʟ|WR|7_YI1.Wܼ!{OwV֙46-6,R)ӰUNA*P7B.,TBQ,ʁlƦTr SWU>K)JJF\xhs3gzh\hb~aߊG 7>_G7uL_EގF.b#...^ξ%!!? |grK˟~.=Rc]* puF8𣍱 \1/$$uQqdQ5ze]\%n$?O/8NK(T]@)"L&t\ڛnтD/nǹF52*22*r߯[~ۮm& c<SXal6&4T: - {==r x2< j8˖-  BDMM^2P(oUi 8 % ^|7'x_{H$iGj g$FD?BC%m}/]/.tt{uRrrRrR/);{͵tyT6پiƋj;VQg2fd΍Vlh,My\ڶWdږƚ];z5{ 5ȶHs=ʙI]Mfj#K3xNbxm6f`em}w ޿@9.\I%ΈrD}qqq6{&oؐ)?}_4eExtWjQ;ﳔBJg| ENEBșiGӊ S>O[~\ڸm.D_8߾c__sʹ,òbf{^rʕ Ŗ[ٽ\Kk6c}K9{$/X lucY8U T1ظk}CjNL9I|^&88x+%L OosE!33 Tfn~WL`z8@Rc6P 53uW.(0g?dks]5: $кEyE-}i@u־TS~fAyav"mBʇM^Xfs^~eƍ]I¶ B!a  B!a wAh^|ƔM] 4a 4ޮI1BtA!$> KM.coords([q1, q2, q3]) >> KM.speeds([q1d, q2d, q3d]) Your code would not work. Currently, kinematic differential equations are required to be provided. It is at this point that we hope the user will discover they should not attempt the behavior shown in the code above. This behavior might not be true for other methods of forming the equations of motion though. Printing -------- The default printing options are to use sorting for ``Vector`` and ``Dyad`` measure numbers, and have unsorted output from the ``mprint``, ``mpprint``, and ``mlatex`` functions. If you are printing something large, please use one of those functions, as the sorting can increase printing time from seconds to minutes. Substitution ------------ There are two common issues with substitution in mechanics: - When subbing in expressions for ``dynamicsymbols``, sympy's normal ``subs`` will substitute in for derivatives of the dynamic symbol as well: :: >>> from sympy.physics.mechanics import dynamicsymbols >>> x = dynamicsymbols('x') >>> expr = x.diff() + x >>> sub_dict = {x: 1} >>> expr.subs(sub_dict) Derivative(1, t) + 1 In this case, ``x`` was replaced with 1 inside the ``Derivative`` as well, which is undesired. - Substitution into large expressions can be slow. If your substitution is simple (direct replacement of expressions with other expressions, such as when evaluating at an operating point) it is recommended to use the provided ``msubs`` function, as it is significantly faster, and handles the derivative issue appropriately: :: >>> from sympy.physics.mechanics import msubs >>> msubs(expr, sub_dict) Derivative(x(t), t) + 1 Linearization ------------- Currently, the linearization methods don't support cases where there are non-coordinate, non-speed dynamic symbols outside of the "dynamic equations". It also does not support cases where time derivatives of these types of dynamic symbols show up. This means if you have kinematic differential equations which have a non-coordinate, non-speed dynamic symbol, it will not work. It also means if you have defined a system parameter (say a length or distance or mass) as a dynamic symbol, its time derivative is likely to show up in the dynamic equations, and this will prevent linearization. Acceleration of Points ---------------------- At a minimum, points need to have their velocities defined, as the acceleration can be calculated by taking the time derivative of the velocity in the same frame. If the 1 point or 2 point theorems were used to compute the velocity, the time derivative of the velocity expression will most likely be more complex than if you were to use the acceleration level 1 point and 2 point theorems. Using the acceleration level methods can result in shorted expressions at this point, which will result in shorter expressions later (such as when forming Kane's equations). Advanced Interfaces =================== Advanced Functionality ---------------------- Remember that the ``Kane`` object supports bodies which have time-varying masses and inertias, although this functionality isn't completely compatible with the linearization method. Operators were discussed earlier as a potential way to do mathematical operations on ``Vector`` and ``Dyad`` objects. The majority of the code in this module is actually coded with them, as it can (subjectively) result in cleaner, shorter, more readable code. If using this interface in your code, remember to take care and use parentheses; the default order of operations in Python results in addition occurring before some of the vector products, so use parentheses liberally. Future Features =============== This will cover the planned features to be added to this submodule. Code Output ----------- A function for generating code output for numerical integration is the highest priority feature to implement next. There are a number of considerations here. Code output for C (using the GSL libraries), Fortran 90 (using LSODA), MATLAB, and SciPy is the goal. Things to be considered include: use of ``cse`` on large expressions for MATLAB and SciPy, which are interpretive. It is currently unclear whether compiled languages will benefit from common subexpression elimination, especially considering that it is a common part of compiler optimization, and there can be a significant time penalty when calling ``cse``. Care needs to be taken when constructing the strings for these expressions, as well as handling of input parameters, and other dynamic symbols. How to deal with output quantities when integrating also needs to be decided, with the potential for multiple options being considered. sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/000077500000000000000000000000001412543434000231145ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/body.rst000066400000000000000000000001741412543434000246050ustar00rootroot00000000000000================= Body (Docstrings) ================= Body ==== .. automodule:: sympy.physics.mechanics.body :members: sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/expr_manip.rst000066400000000000000000000004251412543434000260110ustar00rootroot00000000000000==================================== Expression Manipulation (Docstrings) ==================================== msubs ===== .. autofunction:: sympy.physics.mechanics.msubs find_dynamicsymbols =================== .. autofunction:: sympy.physics.mechanics.find_dynamicsymbols sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/joint.rst000066400000000000000000000004301412543434000247660ustar00rootroot00000000000000================== Joint (Docstrings) ================== .. module:: sympy.physics.mechanics.joint Joint ===== .. autoclass:: Joint :members: PinJoint ======== .. autoclass:: PinJoint :members: PrismaticJoint ============== .. autoclass:: PrismaticJoint :members: sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/kane_lagrange.rst000066400000000000000000000005241412543434000264250ustar00rootroot00000000000000.. _kane_lagrange: ============================================== Kane's Method & Lagrange's Method (Docstrings) ============================================== KaneMethod ========== .. automodule:: sympy.physics.mechanics.kane :members: LagrangesMethod =============== .. automodule:: sympy.physics.mechanics.lagrange :members: sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/linearize.rst000066400000000000000000000002501412543434000256250ustar00rootroot00000000000000========================== Linearization (Docstrings) ========================== Linearizer ========== .. automodule:: sympy.physics.mechanics.linearize :members: sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/part_bod.rst000066400000000000000000000020251412543434000254370ustar00rootroot00000000000000.. _part_bod: ===================================================== Masses, Inertias & Particles, RigidBodys (Docstrings) ===================================================== Particle ======== .. automodule:: sympy.physics.mechanics.particle :members: RigidBody ========= .. automodule:: sympy.physics.mechanics.rigidbody :members: inertia ======= .. autofunction:: sympy.physics.mechanics.functions.inertia inertia_of_point_mass ===================== .. autofunction:: sympy.physics.mechanics.functions.inertia_of_point_mass linear_momentum =============== .. autofunction:: sympy.physics.mechanics.functions.linear_momentum angular_momentum ================ .. autofunction:: sympy.physics.mechanics.functions.angular_momentum kinetic_energy ============== .. autofunction:: sympy.physics.mechanics.functions.kinetic_energy potential_energy ================ .. autofunction:: sympy.physics.mechanics.functions.potential_energy Lagrangian ========== .. autofunction:: sympy.physics.mechanics.functions.Lagrangian sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/printing.rst000066400000000000000000000007211412543434000255000ustar00rootroot00000000000000===================== Printing (Docstrings) ===================== mechanics_printing ================== This function is the same as :obj:`sympy.physics.vector.printing.init_vprinting`. mprint ====== This function is the same as :obj:`sympy.physics.vector.printing.vprint`. mpprint ======= This function is the same as :obj:`sympy.physics.vector.printing.vpprint`. mlatex ====== This function is the same as :obj:`sympy.physics.vector.printing.vlatex`. sympy-sympy-1.9/doc/src/modules/physics/mechanics/api/system.rst000066400000000000000000000002601412543434000251700ustar00rootroot00000000000000=========================== SymbolicSystem (Docstrings) =========================== SymbolicSystem ============== .. automodule:: sympy.physics.mechanics.system :members: sympy-sympy-1.9/doc/src/modules/physics/mechanics/autolev_parser.rst000066400000000000000000000521641412543434000261400ustar00rootroot00000000000000.. _autolev_parser: ============== Autolev Parser ============== .. role:: input(strong) Introduction ============ Autolev (now superseded by MotionGenesis) is a domain specific language used for symbolic multibody dynamics. The SymPy mechanics module now has enough power and functionality to be a fully featured symbolic dynamics module. This parser parses Autolev (version 4.1) code to SymPy code by making use of SymPy's math libraries and the mechanics module. The parser has been built using the `ANTLR `_ framework and its main purpose is to help former users of Autolev to get familiarized with multibody dynamics in SymPy. The sections below shall discuss details of the parser like usage, gotchas, issues and future improvements. For a detailed comparison of Autolev and SymPy Mechanics you might want to look at the :ref:`SymPy Mechanics for Autolev Users guide `. .. _usage: Usage ===== We first start with an Autolev code file. Let us take this example (Comments ``%`` have been included to show the Autolev responses): .. code-block:: none % double_pendulum.al %------------------- MOTIONVARIABLES' Q{2}', U{2}' CONSTANTS L,M,G NEWTONIAN N FRAMES A,B SIMPROT(N, A, 3, Q1) % -> N_A = [COS(Q1), -SIN(Q1), 0; SIN(Q1), COS(Q1), 0; 0, 0, 1] SIMPROT(N, B, 3, Q2) % -> N_B = [COS(Q2), -SIN(Q2), 0; SIN(Q2), COS(Q2), 0; 0, 0, 1] W_A_N>=U1*N3> % -> W_A_N> = U1*N3> W_B_N>=U2*N3> % -> W_B_N> = U2*N3> POINT O PARTICLES P,R P_O_P> = L*A1> % -> P_O_P> = L*A1> P_P_R> = L*B1> % -> P_P_R> = L*B1> V_O_N> = 0> % -> V_O_N> = 0> V2PTS(N, A, O, P) % -> V_P_N> = L*U1*A2> V2PTS(N, B, P, R) % -> V_R_N> = L*U1*A2> + L*U2*B2> MASS P=M, R=M Q1' = U1 Q2' = U2 GRAVITY(G*N1>) % -> FORCE_P> = G*M*N1> % -> FORCE_R> = G*M*N1> ZERO = FR() + FRSTAR() % -> ZERO[1] = -L*M*(2*G*SIN(Q1)+L*(U2^2*SIN(Q1-Q2)+2*U1'+COS(Q1-Q2)*U2')) % -> ZERO[2] = -L*M*(G*SIN(Q2)-L*(U1^2*SIN(Q1-Q2)-U2'-COS(Q1-Q2)*U1')) KANE() INPUT M=1,G=9.81,L=1 INPUT Q1=.1,Q2=.2,U1=0,U2=0 INPUT TFINAL=10, INTEGSTP=.01 CODE DYNAMICS() some_filename.c The parser can be used as follows:: >>> from sympy.parsing.autolev import parse_autolev >>> sympy_code = parse_autolev(open('double_pendulum.al'), include_numeric=True) # The include_pydy flag is False by default. Setting it to True will # enable PyDy simulation code to be outputted if applicable. >>> print(sympy_code) import sympy.physics.mechanics as me import sympy as sm import math as m import numpy as np q1, q2, u1, u2 = me.dynamicsymbols('q1 q2 u1 u2') q1d, q2d, u1d, u2d = me.dynamicsymbols('q1 q2 u1 u2', 1) l, m, g=sm.symbols('l m g', real=True) frame_n=me.ReferenceFrame('n') frame_a=me.ReferenceFrame('a') frame_b=me.ReferenceFrame('b') frame_a.orient(frame_n, 'Axis', [q1, frame_n.z]) # print(frame_n.dcm(frame_a)) frame_b.orient(frame_n, 'Axis', [q2, frame_n.z]) # print(frame_n.dcm(frame_b)) frame_a.set_ang_vel(frame_n, u1*frame_n.z) # print(frame_a.ang_vel_in(frame_n)) frame_b.set_ang_vel(frame_n, u2*frame_n.z) # print(frame_b.ang_vel_in(frame_n)) point_o=me.Point('o') particle_p=me.Particle('p', me.Point('p_pt'), sm.Symbol('m')) particle_r=me.Particle('r', me.Point('r_pt'), sm.Symbol('m')) particle_p.point.set_pos(point_o, l*frame_a.x) # print(particle_p.point.pos_from(point_o)) particle_r.point.set_pos(particle_p.point, l*frame_b.x) # print(particle_p.point.pos_from(particle_r.point)) point_o.set_vel(frame_n, 0) # print(point_o.vel(frame_n)) particle_p.point.v2pt_theory(point_o,frame_n,frame_a) # print(particle_p.point.vel(frame_n)) particle_r.point.v2pt_theory(particle_p.point,frame_n,frame_b) # print(particle_r.point.vel(frame_n)) particle_p.mass = m particle_r.mass = m force_p = particle_p.mass*(g*frame_n.x) # print(force_p) force_r = particle_r.mass*(g*frame_n.x) # print(force_r) kd_eqs = [q1d - u1, q2d - u2] forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x)), (particle_r.point,particle_r.mass*(g*frame_n.x))] kane = me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs) fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList) zero = fr+frstar # print(zero) #---------PyDy code for integration---------- from pydy.system import System sys = System(kane, constants = {l:1, m:1, g:9.81}, specifieds={}, initial_conditions={q1:.1, q2:.2, u1:0, u2:0}, times = np.linspace(0.0, 10, 10/.01)) y=sys.integrate() The commented code is not part of the output code. The print statements demonstrate how to get responses similar to the ones in the Autolev file. Note that we need to use SymPy functions like ``.ang_vel_in()``, ``.dcm()`` etc in many cases unlike directly printing out the variables like ``zero``. If you are completely new to SymPy mechanics, the :ref:`SymPy Mechanics for Autolev Users guide ` guide should help. You might also have to use basic SymPy simplifications and manipulations like ``trigsimp()``, ``expand()``, ``evalf()`` etc for getting outputs similar to Autolev. Refer to the `SymPy Tutorial `_ to know more about these. .. _gotchas_autolev: Gotchas ======= - Don't use variable names that conflict with Python's reserved words. This is one example where this is violated: .. code-block:: none %Autolev Code %------------ LAMBDA = EIG(M) .. code-block:: python #SymPy Code #---------- lambda = sm.Matrix([i.evalf() for i in (m).eigenvals().keys()]) ------------------------------------------------------------------------ - Make sure that the names of vectors and scalars are different. Autolev treats these differently but these will get overwritten in Python. The parser currently allows the names of bodies and scalars/vectors to coincide but doesn't do this between scalars and vectors. This should probably be changed in the future. .. code-block:: none %Autolev Code %------------ VARIABLES X,Y FRAMES A A> = X*A1> + Y*A2> A = X+Y .. code-block:: python #SymPy Code #---------- x, y = me.dynamicsymbols('x y') frame_a = me.ReferenceFrame('a') a = x*frame_a.x + y*frame_a.y a = x + y # Note how frame_a is named differently so it doesn't cause a problem. # On the other hand, 'a' gets rewritten from a scalar to a vector. # This should be changed in the future. ------------------------------------------------------------------------ - When dealing with Matrices returned by functions, one must check the order of the values as they may not be the same as in Autolev. This is especially the case for eigenvalues and eigenvectors. .. code-block:: none %Autolev Code %------------ EIG(M, E1, E2) % -> [5; 14; 13] E2ROW = ROWS(E2, 1) EIGVEC> = VECTOR(A, E2ROW) .. code-block:: python #SymPy Code #---------- e1 = sm.Matrix([i.evalf() for i in m.eigenvals().keys()]) # sm.Matrix([5;13;14]) different order e2 = sm.Matrix([i[2][0].evalf() for i in m.eigenvects()]).reshape(m.shape[0], m.shape[1]) e2row = e2.row(0) # This result depends on the order of the vectors in the eigenvecs. eigenvec = e2row[0]*a.x + e2row[1]*a.y + e2row[2]*a.y ------------------------------------------------------------------------ - When using ``EVALUATE``, use something like ``90*UNITS(deg,rad)`` for angle substitutions as radians are the default in SymPy. You could also add ``np.deg2rad()`` directly in the SymPy code. This need not be done for the output code (generated on parsing the ``CODE`` commands) as the parser takes care of this when ``deg`` units are given in the ``INPUT`` declarations. The ``DEGREES`` setting, on the other hand, works only in some cases like in ``SIMPROT`` where an angle is expected. .. code-block:: none %Autolev Code %------------ A> = Q1*A1> + Q2*A2> B> = EVALUATE(A>, Q1:30*UNITS(DEG,RAD)) .. code-block:: python #SymPy Code #---------- a = q1*a.frame_a.x + q2*frame_a.y b = a.subs({q1:30*0.0174533}) # b = a.subs({q1:np.deg2rad(30)} ------------------------------------------------------------------------ - Most of the Autolev settings have not been parsed and have no effect on the parser. The only ones that work somewhat are ``COMPLEX`` and ``DEGREES``. It is advised to look into alternatives to these in SymPy and Python. ------------------------------------------------------------------------ - The ``REPRESENT`` command is not supported. Use the ``MATRIX``, ``VECTOR`` or ``DYADIC`` commands instead. Autolev 4.1 suggests these over ``REPRESENT`` as well while still allowing it but the parser doesn't parse it. ------------------------------------------------------------------------ - Do not use variables declarations of the type ``WO{3}RD{2,4}``. The parser can only handle one variable name followed by one pair of curly braces and any number of ``'`` s. You would have to declare all the cases manually if you want to achieve something like ``WO{3}RD{2,4}``. ------------------------------------------------------------------------ - The parser can handle normal versions of most commands but it may not parse functions with Matrix arguments properly in most cases. Eg: ``M=COEF([E1;E2],[U1,U2,U3])`` This would compute the coefficients of ``U1``, ``U2`` and ``U3`` in ``E1`` and ``E2``. It is preferable to manually construct a Matrix using the regular versions of these commands. .. code-block:: none %Autolev Code %------------ % COEF([E1;E2],[U1,U2,U3]) M = [COEF(E1,U1),COEF(E1,U2),COEF(E1,U3) & ;COEF(E2,U1),COEF(E2,U2),COEF(E2,U3)] ------------------------------------------------------------------------ - ``MOTIONVARIABLE`` declarations must be used for the generalized coordinates and speeds and all other variables must be declared in regular ``VARIABLE`` declarations. The parser requires this to distinguish between them to pass the correct parameters to the Kane's method object. It is also preferred to always declare the speeds corresponding to the coordinates and to pass in the kinematic differential equations. The parser is able to handle some cases where this isn't the case by introducing some dummy variables of its own but SymPy on its own does require them. Also note that older Autolev declarations like ``VARIABLES U{3}'`` are not supported either. .. code-block:: none %Autolev Code %------------ MOTIONVARIABLES' Q{2}', U{2}' % ----- OTHER LINES ---- Q1' = U1 Q2' = U2 ----- OTHER LINES ---- ZERO = FR() + FRSTAR() .. code-block:: python #SymPy Code #---------- q1, q2, u1, u2 = me.dynamicsymbols('q1 q2 u1 u2') q1d, q2d, u1d, u2d = me.dynamicsymbols('q1 q2 u1 u2', 1) # ------- other lines ------- kd_eqs = [q1d - u1, q2d - u2] kane = me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs) fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList) zero = fr+frstar ------------------------------------------------------------------------ - Need to change ``me.dynamicsymbols._t`` to ``me.dynamicsymbols('t')`` for all occurrences of it in the Kane's equations. For example have a look at line 10 of this `spring damper example `_. This equation is used in forming the Kane's equations so we need to change ``me.dynamicsymbols._t`` to ``me.dynamicsymbols('t')`` in this case. The main reason that this needs to be done is because PyDy requires time dependent specifieds to be explicitly laid out while Autolev simply takes care of the stray time variables in the equations by itself. The problem is that PyDy's System class does not accept ``dynamicsymbols._t`` as a specified. Refer to issue `#396 `_. This change is not actually ideal so a better solution should be figured out in the future. ------------------------------------------------------------------------ - The parser creates SymPy ``symbols`` and ``dynamicsymbols`` by parsing variable declarations in the Autolev Code. For intermediate expressions which are directly initialized the parser does not create SymPy symbols. It just assigns them to the expression. On the other hand, when a declared variable is assigned to an expression, the parser stores the expression against the variable in a dictionary so as to not reassign it to a completely different entity. This constraint is due to the inherent nature of Python and how it differs from a language like Autolev. Also, Autolev seems to be able to assume whether to use a variable or the rhs expression that variable has been assigned to in equations even without an explicit ``RHS()`` call in some cases. For the parser to work correctly however, it is better to use ``RHS()`` wherever a variable's rhs expression is meant to be used. .. code-block:: none %Autolev Code %------------ VARIABLES X, Y E = X + Y X = 2*Y RHS_X = RHS(X) I1 = X I2 = Y I3 = X + Y INERTIA B,I1,I2,I3 % -> I_B_BO>> = I1*B1>*B1> + I2*B2>*B2> + I3*B3>*B3> .. code-block:: python #SymPy Code #---------- x,y = me.dynamicsymbols('x y') e = x + y # No symbol is made out of 'e' # an entry like {x:2*y} is stored in an rhs dictionary rhs_x = 2*y i1 = x # again these are not made into SymPy symbols i2 = y i3 = x + y body_b.inertia = (me.inertia(body_b_f, i1, i2, i3), b_cm) # This prints as: # x*b_f.x*b_f.x + y*b_f.y*b_f.y + (x+y)*b_f.z*b_f.z # while Autolev's output has I1,I2 and I3 in it. # Autolev however seems to know when to use the RHS of I1,I2 and I3 # based on the context. ------------------------------------------------------------------------ - This is how the ``SOLVE`` command is parsed: .. code-block:: none %Autolev Code %------------ SOLVE(ZERO,X,Y) A = RHS(X)*2 + RHS(Y) .. code-block:: python #SymPy Code #---------- print(sm.solve(zero,x,y)) # Behind the scenes the rhs of x # is set to sm.solve(zero,x,y)[x]. a = sm.solve(zero,x,y)[x]*2 + sm.solve(zero,x,y)[y] The indexing like ``[x]`` and ``[y]`` doesn't always work so you might want to look at the underlying dictionary that solve returns and index it correctly. ------------------------------------------------------------------------ - Inertia declarations and Inertia functions work somewhat differently in the context of the parser. This might be hard to understand at first but this had to be done to bridge the gap due to the differences in SymPy and Autolev. Here are some points about them: 1. Inertia declarations (``INERTIA B,I1,I2,I3``) set the inertias of rigid bodies. 2. Inertia setters of the form ``I_C_D>> = expr`` however, set the inertias only when C is a body. If C is a particle then ``I_C_D>> = expr`` simply parses to ``i_c_d = expr`` and ``i_c_d`` acts like a regular variable. 3. When it comes to inertia getters (``I_C_D>>`` used in an expression or ``INERTIA`` commands), these MUST be used with the ``EXPRESS`` command to specify the frame as SymPy needs this information to compute the inertia dyadic. .. code-block:: none %Autolev Code %------------ INERTIA B,I1,I2,I3 I_B_BO>> = X*A1>*A1> + Y*A2>*A2> % Parser will set the inertia of B I_P_Q>> = X*A1>*A1> + Y^2*A2>*A2> % Parser just parses it as i_p_q = expr E1 = 2*EXPRESS(I_B_O>>,A) E2 = I_P_Q>> E3 = EXPRESS(I_P_O>>,A) E4 = EXPRESS(INERTIA(O),A) % In E1 we are using the EXPRESS command with I_B_O>> which makes % the parser and SymPy compute the inertia of Body B about point O. % In E2 we are just using the dyadic object I_P_Q>> (as I_P_Q>> = expr % doesn't act as a setter) defined above and not asking the parser % or SymPy to compute anything. % E3 asks the parser to compute the inertia of P about point O. % E4 asks the parser to compute the inertias of all bodies wrt about O. ------------------------------------------------------------------------ - In an inertia declaration of a body, if the inertia is being set about a point other than the center of mass, one needs to make sure that the position vector setter for that point and the center of mass appears before the inertia declaration as SymPy will throw an error otherwise. .. code-block:: none %Autolev Code %------------ P_SO_O> = X*A1> INERTIA S_(O) I1,I2,I3 ------------------------------------------------------------------------ - Note that all Autolev commands have not been implemented. The parser now covers the important ones in their basic forms. If you are doubtful whether a command is included or not, please have a look at `this file `_ in the source code. Search for "" to verify this. Looking at the code for the specific command will also give an idea about what form it is expected to work in. .. _issues: Limitations and Issues ====================== - A lot of the issues have already been discussed in the Gotchas section. Some of these are: - Vector names coinciding with scalar names are overwritten in Python. - Some convenient variable declarations aren't parsed. - Some convenient forms of functions to return matrices aren't parsed. - Settings aren't parsed. - symbols and rhs expressions work very differently in Python which might cause undesirable results. - Dictionary indexing for the parsed code of the ``SOLVE`` command is not proper in many cases. - Need to change ``dynamicsymbols._t`` to ``dynamicsymbols('t')`` for the PyDy simulation code to work properly. Here are some other ones: - Eigenvectors do not seem to work as expected. The values in Autolev and SymPy are not the same in many cases. - Block matrices aren't parsed by the parser. It would actually be easier to make a change in SymPy to allow matrices to accept other matrices for arguments. - The SymPy equivalent of the ``TAYLOR`` command ``.series()`` does not work with ``dynamicsymbols()``. - Only ``DEPENDENT`` constraints are currently parsed. Need to parse ``AUXILIARY`` constraints as well. This should be done soon as it isn't very difficult. - None of the energy and momentum functions are parsed right now. It would be nice to get these working as well. Some changes should probably be made to SymPy. For instance, SymPy doesn't have a function equivalent to ``NICHECK()``. - The numerical integration parts work properly only in the case of the ``KANE`` command with no arguments. Things like ``KANE(F1,F2)`` do not currently work. - Also, the PyDy numerical simulation code works only for cases where the matrix say ``ZERO = FR() + FRSTAR()`` is solved for. It doesn't work well when the matrix has some other equations plugged in as well. One hurdle faced in achieving this was that PyDy's System class automatically takes in the ``forcing_full`` and ``mass_matrix_full`` and solves them without giving the user the flexibility to specify the equations. It would be nice to add this functionality to the System class. .. _future_improvements: Future Improvements =================== 1. Completing Dynamics Online ----------------------------- The parser has been built by referring to and parsing codes from the `Autolev Tutorial `_ and the book *Dynamics Online: Theory and Implementation Using Autolev*. Basically, the process involved going through each of these codes, validating the parser results and improving the rules if required to make sure the codes parsed well. The parsed codes of these are available on GitLab `here `_. The repo is private so access needs to be requested. As of now, most codes till Chapter 4 of *Dynamics Online* have been parsed. Completing all the remaining codes of the book (namely, *2-10*, *2-11*, *rest of Ch4*, *Ch5* and *Ch6* (less important) ) would make the parser more complete. 2. Fixing Issues ---------------- The second thing to do would be to go about fixing the problems described above in the :ref:`Gotchas ` and :ref:`Limitations and Issues ` sections in order of priority and ease. Many of these require changes in the parser code while some of these are better fixed by adding some functionality to SymPy. 3. Switching to an AST ---------------------- The parser is currently built using a kind of Concrete Syntax Tree (CST) using the `ANTLR `_ framework. It would be ideal to switch from a CST to an Abstract Syntax Tree (AST). This way, the parser code will be independent of the ANTLR grammar which makes it a lot more flexible. It would also be easier to make changes to the grammar and the rules of the parser. sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples.rst000066400000000000000000000010501412543434000247070ustar00rootroot00000000000000============================== Examples for Physics/Mechanics ============================== Here are some examples that illustrate how one typically uses this module. We have ordered the examples roughly according to increasing difficulty. If you have used this module to do something others might find useful or interesting, consider adding it here! .. toctree:: :maxdepth: 1 examples/rollingdisc_example.rst examples/bicycle_example.rst examples/lin_pend_nonmin_example.rst examples/multi_degree_freedom_holonomic_system.rst sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/000077500000000000000000000000001412543434000241615ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/bicycle_example.rst000066400000000000000000000434421412543434000300470ustar00rootroot00000000000000========= A bicycle ========= The bicycle is an interesting system in that it has multiple rigid bodies, non-holonomic constraints, and a holonomic constraint. The linearized equations of motion are presented in [Meijaard2007]_. This example will go through construction of the equations of motion in :mod:`sympy.physics.mechanics`. :: >>> from sympy import * >>> from sympy.physics.mechanics import * >>> print('Calculation of Linearized Bicycle \"A\" Matrix, ' ... 'with States: Roll, Steer, Roll Rate, Steer Rate') Calculation of Linearized Bicycle "A" Matrix, with States: Roll, Steer, Roll Rate, Steer Rate Note that this code has been crudely ported from Autolev, which is the reason for some of the unusual naming conventions. It was purposefully as similar as possible in order to aid initial porting & debugging. We set Vector.simp to False (in case it has been set True elsewhere), since it slows down the computations:: >>> Vector.simp = False >>> mechanics_printing(pretty_print=False) Declaration of Coordinates & Speeds: A simple definition for qdots, qd = u,is used in this code. Speeds are: yaw frame ang. rate, roll frame ang. rate, rear wheel frame ang. rate (spinning motion), frame ang. rate (pitching motion), steering frame ang. rate, and front wheel ang. rate (spinning motion). Wheel positions are ignorable coordinates, so they are not introduced. :: >>> q1, q2, q3, q4, q5 = dynamicsymbols('q1 q2 q3 q4 q5') >>> q1d, q2d, q4d, q5d = dynamicsymbols('q1 q2 q4 q5', 1) >>> u1, u2, u3, u4, u5, u6 = dynamicsymbols('u1 u2 u3 u4 u5 u6') >>> u1d, u2d, u3d, u4d, u5d, u6d = dynamicsymbols('u1 u2 u3 u4 u5 u6', 1) Declaration of System's Parameters: The below symbols should be fairly self-explanatory. :: >>> WFrad, WRrad, htangle, forkoffset = symbols('WFrad WRrad htangle forkoffset') >>> forklength, framelength, forkcg1 = symbols('forklength framelength forkcg1') >>> forkcg3, framecg1, framecg3, Iwr11 = symbols('forkcg3 framecg1 framecg3 Iwr11') >>> Iwr22, Iwf11, Iwf22, Iframe11 = symbols('Iwr22 Iwf11 Iwf22 Iframe11') >>> Iframe22, Iframe33, Iframe31, Ifork11 = \ ... symbols('Iframe22 Iframe33 Iframe31 Ifork11') >>> Ifork22, Ifork33, Ifork31, g = symbols('Ifork22 Ifork33 Ifork31 g') >>> mframe, mfork, mwf, mwr = symbols('mframe mfork mwf mwr') Set up reference frames for the system: N - inertial Y - yaw R - roll WR - rear wheel, rotation angle is ignorable coordinate so not oriented Frame - bicycle frame TempFrame - statically rotated frame for easier reference inertia definition Fork - bicycle fork TempFork - statically rotated frame for easier reference inertia definition WF - front wheel, again posses an ignorable coordinate :: >>> N = ReferenceFrame('N') >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) >>> R = Y.orientnew('R', 'Axis', [q2, Y.x]) >>> Frame = R.orientnew('Frame', 'Axis', [q4 + htangle, R.y]) >>> WR = ReferenceFrame('WR') >>> TempFrame = Frame.orientnew('TempFrame', 'Axis', [-htangle, Frame.y]) >>> Fork = Frame.orientnew('Fork', 'Axis', [q5, Frame.x]) >>> TempFork = Fork.orientnew('TempFork', 'Axis', [-htangle, Fork.y]) >>> WF = ReferenceFrame('WF') Kinematics of the Bicycle: First block of code is forming the positions of the relevant points rear wheel contact -> rear wheel's center of mass -> frame's center of mass + frame/fork connection -> fork's center of mass + front wheel's center of mass -> front wheel contact point. :: >>> WR_cont = Point('WR_cont') >>> WR_mc = WR_cont.locatenew('WR_mc', WRrad * R.z) >>> Steer = WR_mc.locatenew('Steer', framelength * Frame.z) >>> Frame_mc = WR_mc.locatenew('Frame_mc', -framecg1 * Frame.x + framecg3 * Frame.z) >>> Fork_mc = Steer.locatenew('Fork_mc', -forkcg1 * Fork.x + forkcg3 * Fork.z) >>> WF_mc = Steer.locatenew('WF_mc', forklength * Fork.x + forkoffset * Fork.z) >>> WF_cont = WF_mc.locatenew('WF_cont', WFrad*(dot(Fork.y, Y.z)*Fork.y - \ ... Y.z).normalize()) Set the angular velocity of each frame: Angular accelerations end up being calculated automatically by differentiating the angular velocities when first needed. :: u1 is yaw rate u2 is roll rate u3 is rear wheel rate u4 is frame pitch rate u5 is fork steer rate u6 is front wheel rate :: >>> Y.set_ang_vel(N, u1 * Y.z) >>> R.set_ang_vel(Y, u2 * R.x) >>> WR.set_ang_vel(Frame, u3 * Frame.y) >>> Frame.set_ang_vel(R, u4 * Frame.y) >>> Fork.set_ang_vel(Frame, u5 * Fork.x) >>> WF.set_ang_vel(Fork, u6 * Fork.y) Form the velocities of the points, using the 2-point theorem. Accelerations again are calculated automatically when first needed. :: >>> WR_cont.set_vel(N, 0) >>> WR_mc.v2pt_theory(WR_cont, N, WR) WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y >>> Steer.v2pt_theory(WR_mc, N, Frame) WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y >>> Frame_mc.v2pt_theory(WR_mc, N, Frame) WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framecg3*(u1*sin(q2) + u4)*Frame.x + (-framecg1*(u1*cos(htangle + q4)*cos(q2) + u2*sin(htangle + q4)) - framecg3*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4)))*Frame.y + framecg1*(u1*sin(q2) + u4)*Frame.z >>> Fork_mc.v2pt_theory(Steer, N, Fork) WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + forkcg3*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.x + (-forkcg1*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkcg3*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y + forkcg1*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.z >>> WF_mc.v2pt_theory(Steer, N, Fork) WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + forkoffset*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.x + (forklength*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkoffset*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y - forklength*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5))*Fork.z >>> WF_cont.v2pt_theory(WF_mc, N, WF) - WFrad*((-sin(q2)*sin(q5)*cos(htangle + q4) + cos(q2)*cos(q5))*u6 + u4*cos(q2) + u5*sin(htangle + q4)*sin(q2))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1)*Y.x + WFrad*(u2 + u5*cos(htangle + q4) + u6*sin(htangle + q4)*sin(q5))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1)*Y.y + WRrad*(u1*sin(q2) + u3 + u4)*R.x - WRrad*u2*R.y + framelength*(u1*sin(q2) + u4)*Frame.x - framelength*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4))*Frame.y + (-WFrad*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5))/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1) + forkoffset*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5)))*Fork.x + (forklength*((-sin(q2)*sin(q5) + cos(htangle + q4)*cos(q2)*cos(q5))*u1 + u2*sin(htangle + q4)*cos(q5) - u4*sin(q5)) - forkoffset*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5))*Fork.y + (WFrad*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*(-u1*sin(htangle + q4)*cos(q2) + u2*cos(htangle + q4) + u5)/sqrt((-sin(q2)*cos(q5) - sin(q5)*cos(htangle + q4)*cos(q2))*(sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2)) + 1) - forklength*((sin(q2)*cos(q5) + sin(q5)*cos(htangle + q4)*cos(q2))*u1 + u2*sin(htangle + q4)*sin(q5) + u4*cos(q5)))*Fork.z Sets the inertias of each body. Uses the inertia frame to construct the inertia dyadics. Wheel inertias are only defined by principal moments of inertia, and are in fact constant in the frame and fork reference frames; it is for this reason that the orientations of the wheels does not need to be defined. The frame and fork inertias are defined in the 'Temp' frames which are fixed to the appropriate body frames; this is to allow easier input of the reference values of the benchmark paper. Note that due to slightly different orientations, the products of inertia need to have their signs flipped; this is done later when entering the numerical value. :: >>> Frame_I = (inertia(TempFrame, Iframe11, Iframe22, Iframe33, 0, 0, ... Iframe31), Frame_mc) >>> Fork_I = (inertia(TempFork, Ifork11, Ifork22, Ifork33, 0, 0, Ifork31), Fork_mc) >>> WR_I = (inertia(Frame, Iwr11, Iwr22, Iwr11), WR_mc) >>> WF_I = (inertia(Fork, Iwf11, Iwf22, Iwf11), WF_mc) Declaration of the RigidBody containers. :: >>> BodyFrame = RigidBody('BodyFrame', Frame_mc, Frame, mframe, Frame_I) >>> BodyFork = RigidBody('BodyFork', Fork_mc, Fork, mfork, Fork_I) >>> BodyWR = RigidBody('BodyWR', WR_mc, WR, mwr, WR_I) >>> BodyWF = RigidBody('BodyWF', WF_mc, WF, mwf, WF_I) >>> print('Before Forming the List of Nonholonomic Constraints.') Before Forming the List of Nonholonomic Constraints. The kinematic differential equations; they are defined quite simply. Each entry in this list is equal to zero. :: >>> kd = [q1d - u1, q2d - u2, q4d - u4, q5d - u5] The nonholonomic constraints are the velocity of the front wheel contact point dotted into the X, Y, and Z directions; the yaw frame is used as it is "closer" to the front wheel (1 less DCM connecting them). These constraints force the velocity of the front wheel contact point to be 0 in the inertial frame; the X and Y direction constraints enforce a "no-slip" condition, and the Z direction constraint forces the front wheel contact point to not move away from the ground frame, essentially replicating the holonomic constraint which does not allow the frame pitch to change in an invalid fashion. :: >>> conlist_speed = [WF_cont.vel(N) & Y.x, ... WF_cont.vel(N) & Y.y, ... WF_cont.vel(N) & Y.z] The holonomic constraint is that the position from the rear wheel contact point to the front wheel contact point when dotted into the normal-to-ground plane direction must be zero; effectively that the front and rear wheel contact points are always touching the ground plane. This is actually not part of the dynamic equations, but instead is necessary for the linearization process. :: >>> conlist_coord = [WF_cont.pos_from(WR_cont) & Y.z] The force list; each body has the appropriate gravitational force applied at its center of mass. :: >>> FL = [(Frame_mc, -mframe * g * Y.z), (Fork_mc, -mfork * g * Y.z), ... (WF_mc, -mwf * g * Y.z), (WR_mc, -mwr * g * Y.z)] >>> BL = [BodyFrame, BodyFork, BodyWR, BodyWF] The N frame is the inertial frame, coordinates are supplied in the order of independent, dependent coordinates. The kinematic differential equations are also entered here. Here the independent speeds are specified, followed by the dependent speeds, along with the non-holonomic constraints. The dependent coordinate is also provided, with the holonomic constraint. Again, this is only comes into play in the linearization process, but is necessary for the linearization to correctly work. :: >>> KM = KanesMethod(N, q_ind=[q1, q2, q5], ... q_dependent=[q4], configuration_constraints=conlist_coord, ... u_ind=[u2, u3, u5], ... u_dependent=[u1, u4, u6], velocity_constraints=conlist_speed, ... kd_eqs=kd) >>> print('Before Forming Generalized Active and Inertia Forces, Fr and Fr*') Before Forming Generalized Active and Inertia Forces, Fr and Fr* >>> (fr, frstar) = KM.kanes_equations(BL, FL) >>> print('Base Equations of Motion Computed') Base Equations of Motion Computed This is the start of entering in the numerical values from the benchmark paper to validate the eigenvalues of the linearized equations from this model to the reference eigenvalues. Look at the aforementioned paper for more information. Some of these are intermediate values, used to transform values from the paper into the coordinate systems used in this model. :: >>> PaperRadRear = 0.3 >>> PaperRadFront = 0.35 >>> HTA = evalf.N(pi/2-pi/10) >>> TrailPaper = 0.08 >>> rake = evalf.N(-(TrailPaper*sin(HTA)-(PaperRadFront*cos(HTA)))) >>> PaperWb = 1.02 >>> PaperFrameCgX = 0.3 >>> PaperFrameCgZ = 0.9 >>> PaperForkCgX = 0.9 >>> PaperForkCgZ = 0.7 >>> FrameLength = evalf.N(PaperWb*sin(HTA) - (rake - \ ... (PaperRadFront - PaperRadRear)*cos(HTA))) >>> FrameCGNorm = evalf.N((PaperFrameCgZ - PaperRadRear - \ ... (PaperFrameCgX/sin(HTA))*cos(HTA))*sin(HTA)) >>> FrameCGPar = evalf.N((PaperFrameCgX / sin(HTA) + \ ... (PaperFrameCgZ - PaperRadRear - \ ... PaperFrameCgX / sin(HTA) * cos(HTA)) * cos(HTA))) >>> tempa = evalf.N((PaperForkCgZ - PaperRadFront)) >>> tempb = evalf.N((PaperWb-PaperForkCgX)) >>> tempc = evalf.N(sqrt(tempa**2 + tempb**2)) >>> PaperForkL = evalf.N((PaperWb*cos(HTA) - \ ... (PaperRadFront - PaperRadRear)*sin(HTA))) >>> ForkCGNorm = evalf.N(rake + (tempc * sin(pi/2 - \ ... HTA - acos(tempa/tempc)))) >>> ForkCGPar = evalf.N(tempc * cos((pi/2 - HTA) - \ ... acos(tempa/tempc)) - PaperForkL) Here is the final assembly of the numerical values. The symbol 'v' is the forward speed of the bicycle (a concept which only makes sense in the upright, static equilibrium case?). These are in a dictionary which will later be substituted in. Again the sign on the *product* of inertia values is flipped here, due to different orientations of coordinate systems. :: >>> v = Symbol('v') >>> val_dict = { ... WFrad: PaperRadFront, ... WRrad: PaperRadRear, ... htangle: HTA, ... forkoffset: rake, ... forklength: PaperForkL, ... framelength: FrameLength, ... forkcg1: ForkCGPar, ... forkcg3: ForkCGNorm, ... framecg1: FrameCGNorm, ... framecg3: FrameCGPar, ... Iwr11: 0.0603, ... Iwr22: 0.12, ... Iwf11: 0.1405, ... Iwf22: 0.28, ... Ifork11: 0.05892, ... Ifork22: 0.06, ... Ifork33: 0.00708, ... Ifork31: 0.00756, ... Iframe11: 9.2, ... Iframe22: 11, ... Iframe33: 2.8, ... Iframe31: -2.4, ... mfork: 4, ... mframe: 85, ... mwf: 3, ... mwr: 2, ... g: 9.81, ... q1: 0, ... q2: 0, ... q4: 0, ... q5: 0, ... u1: 0, ... u2: 0, ... u3: v/PaperRadRear, ... u4: 0, ... u5: 0, ... u6: v/PaperRadFront} >>> kdd = KM.kindiffdict() >>> print('Before Linearization of the \"Forcing\" Term') Before Linearization of the "Forcing" Term Linearizes the forcing vector; the equations are set up as MM udot = forcing, where MM is the mass matrix, udot is the vector representing the time derivatives of the generalized speeds, and forcing is a vector which contains both external forcing terms and internal forcing terms, such as centripetal or Coriolis forces. This actually returns a matrix with as many rows as *total* coordinates and speeds, but only as many columns as independent coordinates and speeds. (Note that below this is commented out, as it takes a few minutes to run, which is not good when performing the doctests) :: >>> # forcing_lin = KM.linearize()[0].subs(sub_dict) As mentioned above, the size of the linearized forcing terms is expanded to include both q's and u's, so the mass matrix must have this done as well. This will likely be changed to be part of the linearized process, for future reference. :: >>> MM_full = (KM._k_kqdot).row_join(zeros(4, 6)).col_join( ... (zeros(6, 4)).row_join(KM.mass_matrix)) >>> print('Before Substitution of Numerical Values') Before Substitution of Numerical Values I think this is pretty self explanatory. It takes a really long time though. I've experimented with using evalf with substitution, this failed due to maximum recursion depth being exceeded; I also tried lambdifying this, and it is also not successful. (again commented out due to speed) :: >>> # MM_full = MM_full.subs(val_dict) >>> # forcing_lin = forcing_lin.subs(val_dict) >>> # print('Before .evalf() call') >>> # MM_full = MM_full.evalf() >>> # forcing_lin = forcing_lin.evalf() Finally, we construct an "A" matrix for the form xdot = A x (x being the state vector, although in this case, the sizes are a little off). The following line extracts only the minimum entries required for eigenvalue analysis, which correspond to rows and columns for lean, steer, lean rate, and steer rate. (this is all commented out due to being dependent on the above code, which is also commented out):: >>> # Amat = MM_full.inv() * forcing_lin >>> # A = Amat.extract([1,2,4,6],[1,2,3,5]) >>> # print(A) >>> # print('v = 1') >>> # print(A.subs(v, 1).eigenvals()) >>> # print('v = 2') >>> # print(A.subs(v, 2).eigenvals()) >>> # print('v = 3') >>> # print(A.subs(v, 3).eigenvals()) >>> # print('v = 4') >>> # print(A.subs(v, 4).eigenvals()) >>> # print('v = 5') >>> # print(A.subs(v, 5).eigenvals()) Upon running the above code yourself, enabling the commented out lines, compare the computed eigenvalues to those is the referenced paper. This concludes the bicycle example. sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/lin_pend_nonmin_example.rst000066400000000000000000000246301412543434000316010ustar00rootroot00000000000000=============================== Nonminimal Coordinates Pendulum =============================== In this example we demonstrate the use of the functionality provided in :mod:`sympy.physics.mechanics` for deriving the equations of motion (EOM) for a pendulum with a nonminimal set of coordinates. As the pendulum is a one degree of freedom system, it can be described using one coordinate and one speed (the pendulum angle, and the angular velocity respectively). Choosing instead to describe the system using the `x` and `y` coordinates of the mass results in a need for constraints. The system is shown below: .. image:: pendulum_nonmin.* :align: center The system will be modeled using both Kane's and Lagrange's methods, and the resulting EOM linearized. While this is a simple problem, it should illustrate the use of the linearization methods in the presence of constraints. Kane's Method ============= First we need to create the ``dynamicsymbols`` needed to describe the system as shown in the above diagram. In this case, the generalized coordinates `q_1` and `q_2` represent the mass `x` and `y` coordinates in the inertial `N` frame. Likewise, the generalized speeds `u_1` and `u_2` represent the velocities in these directions. We also create some ``symbols`` to represent the length and mass of the pendulum, as well as gravity and time. :: >>> from sympy.physics.mechanics import * >>> from sympy import symbols, atan, Matrix, solve >>> # Create generalized coordinates and speeds for this non-minimal realization >>> # q1, q2 = N.x and N.y coordinates of pendulum >>> # u1, u2 = N.x and N.y velocities of pendulum >>> q1, q2 = dynamicsymbols('q1:3') >>> q1d, q2d = dynamicsymbols('q1:3', level=1) >>> u1, u2 = dynamicsymbols('u1:3') >>> u1d, u2d = dynamicsymbols('u1:3', level=1) >>> L, m, g, t = symbols('L, m, g, t') Next, we create a world coordinate frame `N`, and its origin point `N^*`. The velocity of the origin is set to 0. A second coordinate frame `A` is oriented such that its x-axis is along the pendulum (as shown in the diagram above). :: >>> # Compose world frame >>> N = ReferenceFrame('N') >>> pN = Point('N*') >>> pN.set_vel(N, 0) >>> # A.x is along the pendulum >>> theta1 = atan(q2/q1) >>> A = N.orientnew('A', 'axis', [theta1, N.z]) Locating the pendulum mass is then as easy as specifying its location with in terms of its x and y coordinates in the world frame. A ``Particle`` object is then created to represent the mass at this location. :: >>> # Locate the pendulum mass >>> P = pN.locatenew('P1', q1*N.x + q2*N.y) >>> pP = Particle('pP', P, m) The kinematic differential equations (KDEs) relate the derivatives of the generalized coordinates to the generalized speeds. In this case the speeds are the derivatives, so these are simple. A dictionary is also created to map `\dot{q}` to `u`: :: >>> # Calculate the kinematic differential equations >>> kde = Matrix([q1d - u1, ... q2d - u2]) >>> dq_dict = solve(kde, [q1d, q2d]) The velocity of the mass is then the time derivative of the position from the origin `N^*`: :: >>> # Set velocity of point P >>> P.set_vel(N, P.pos_from(pN).dt(N).subs(dq_dict)) As this system has more coordinates than degrees of freedom, constraints are needed. The configuration constraints relate the coordinates to each other. In this case the constraint is that the distance from the origin to the mass is always the length `L` (the pendulum doesn't get longer). Likewise, the velocity constraint is that the mass velocity in the ``A.x`` direction is always 0 (no radial velocity). :: >>> f_c = Matrix([P.pos_from(pN).magnitude() - L]) >>> f_v = Matrix([P.vel(N).express(A).dot(A.x)]) >>> f_v.simplify() The force on the system is just gravity, at point ``P``. :: >>> # Input the force resultant at P >>> R = m*g*N.x With the problem setup, the equations of motion can be generated using the ``KanesMethod`` class. As there are constraints, dependent and independent coordinates need to be provided to the class. In this case we'll use `q_2` and `u_2` as the independent coordinates and speeds: :: >>> # Derive the equations of motion using the KanesMethod class. >>> KM = KanesMethod(N, q_ind=[q2], u_ind=[u2], q_dependent=[q1], ... u_dependent=[u1], configuration_constraints=f_c, ... velocity_constraints=f_v, kd_eqs=kde) >>> (fr, frstar) = KM.kanes_equations([pP],[(P, R)]) For linearization, operating points can be specified on the call, or be substituted in afterwards. In this case we'll provide them in the call, supplied in a list. The ``A_and_B=True`` kwarg indicates to solve invert the `M` matrix and solve for just the explicit linearized `A` and `B` matrices. The ``simplify=True`` kwarg indicates to simplify inside the linearize call, and return the presimplified matrices. The cost of doing this is small for simple systems, but for larger systems this can be a costly operation, and should be avoided. :: >>> # Set the operating point to be straight down, and non-moving >>> q_op = {q1: L, q2: 0} >>> u_op = {u1: 0, u2: 0} >>> ud_op = {u1d: 0, u2d: 0} >>> # Perform the linearization >>> A, B, inp_vec = KM.linearize(op_point=[q_op, u_op, ud_op], A_and_B=True, ... new_method=True, simplify=True) >>> A Matrix([ [ 0, 1], [-g/L, 0]]) >>> B Matrix(0, 0, []) The resulting `A` matrix has dimensions 2 x 2, while the number of total states is ``len(q) + len(u) = 2 + 2 = 4``. This is because for constrained systems the resulting ``A_and_B`` form has a partitioned state vector only containing the independent coordinates and speeds. Written out mathematically, the system linearized about this point would be written as: .. math:: \begin{bmatrix} \dot{q_2} \\ \dot{u_2} \end{bmatrix} = \begin{bmatrix} 0 & 1 \\ \frac{-g}{L} & 0 \end{bmatrix} \begin{bmatrix} q_2 \\ u_2 \end{bmatrix} Lagrange's Method ================= The derivation using Lagrange's method is very similar to the approach using Kane's method described above. As before, we first create the ``dynamicsymbols`` needed to describe the system. In this case, the generalized coordinates `q_1` and `q_2` represent the mass `x` and `y` coordinates in the inertial `N` frame. This results in the time derivatives `\dot{q_1}` and `\dot{q_2}` representing the velocities in these directions. We also create some ``symbols`` to represent the length and mass of the pendulum, as well as gravity and time. :: >>> from sympy.physics.mechanics import * >>> from sympy import symbols, atan, Matrix >>> q1, q2 = dynamicsymbols('q1:3') >>> q1d, q2d = dynamicsymbols('q1:3', level=1) >>> L, m, g, t = symbols('L, m, g, t') Next, we create a world coordinate frame `N`, and its origin point `N^*`. The velocity of the origin is set to 0. A second coordinate frame `A` is oriented such that its x-axis is along the pendulum (as shown in the diagram above). :: >>> # Compose World Frame >>> N = ReferenceFrame('N') >>> pN = Point('N*') >>> pN.set_vel(N, 0) >>> # A.x is along the pendulum >>> theta1 = atan(q2/q1) >>> A = N.orientnew('A', 'axis', [theta1, N.z]) Locating the pendulum mass is then as easy as specifying its location with in terms of its x and y coordinates in the world frame. A ``Particle`` object is then created to represent the mass at this location. :: >>> # Create point P, the pendulum mass >>> P = pN.locatenew('P1', q1*N.x + q2*N.y) >>> P.set_vel(N, P.pos_from(pN).dt(N)) >>> pP = Particle('pP', P, m) As this system has more coordinates than degrees of freedom, constraints are needed. In this case only a single holonomic constraints is needed: the distance from the origin to the mass is always the length `L` (the pendulum doesn't get longer). :: >>> # Holonomic Constraint Equations >>> f_c = Matrix([q1**2 + q2**2 - L**2]) The force on the system is just gravity, at point ``P``. :: >>> # Input the force resultant at P >>> R = m*g*N.x With the problem setup, the Lagrangian can be calculated, and the equations of motion formed. Note that the call to ``LagrangesMethod`` includes the Lagrangian, the generalized coordinates, the constraints (specified by ``hol_coneqs`` or ``nonhol_coneqs``), the list of (body, force) pairs, and the inertial frame. In contrast to the ``KanesMethod`` initializer, independent and dependent coordinates are not partitioned inside the ``LagrangesMethod`` object. Such a partition is supplied later. :: >>> # Calculate the lagrangian, and form the equations of motion >>> Lag = Lagrangian(N, pP) >>> LM = LagrangesMethod(Lag, [q1, q2], hol_coneqs=f_c, forcelist=[(P, R)], frame=N) >>> lag_eqs = LM.form_lagranges_equations() Next, we compose the operating point dictionary, set in the hanging at rest position: :: >>> # Compose operating point >>> op_point = {q1: L, q2: 0, q1d: 0, q2d: 0, q1d.diff(t): 0, q2d.diff(t): 0} As there are constraints in the formulation, there will be corresponding Lagrange Multipliers. These may appear inside the linearized form as well, and thus should also be included inside the operating point dictionary. Fortunately, the ``LagrangesMethod`` class provides an easy way of solving for the multipliers at a given operating point using the ``solve_multipliers`` method. :: >>> # Solve for multiplier operating point >>> lam_op = LM.solve_multipliers(op_point=op_point) With this solution, linearization can be completed. Note that in contrast to the ``KanesMethod`` approach, the ``LagrangesMethod.linearize`` method also requires the partitioning of the generalized coordinates and their time derivatives into independent and dependent vectors. This is the same as what was passed into the ``KanesMethod`` constructor above: >>> op_point.update(lam_op) >>> # Perform the Linearization >>> A, B, inp_vec = LM.linearize([q2], [q2d], [q1], [q1d], ... op_point=op_point, A_and_B=True) >>> A Matrix([ [ 0, 1], [-g/L, 0]]) >>> B Matrix(0, 0, []) The resulting `A` matrix has dimensions 2 x 2, while the number of total states is ``2*len(q) = 4``. This is because for constrained systems the resulting ``A_and_B`` form has a partitioned state vector only containing the independent coordinates and their derivatives. Written out mathematically, the system linearized about this point would be written as: .. math:: \begin{bmatrix} \dot{q_2} \\ \ddot{q_2} \end{bmatrix} = \begin{bmatrix} 0 & 1 \\ \frac{-g}{L} & 0 \end{bmatrix} \begin{bmatrix} q_2 \\ \dot{q_2} \end{bmatrix} sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/multi_degree_freedom_holonomic_system.rst000066400000000000000000000161551412543434000345440ustar00rootroot00000000000000========================================= Multi Degree of Freedom Holonomic System ========================================= In this example we demonstrate the use of the functionality provided in :mod:`sympy.physics.mechanics` for deriving the equations of motion (EOM) of a holonomic system that includes both particles and rigid bodies with contributing forces and torques, some of which are specified forces and torques. The system is shown below: .. image:: multidof-holonomic.* :align: center The system will be modeled using ``JointsMethod``. First we need to create the ``dynamicsymbols`` needed to describe the system as shown in the above diagram. In this case, the generalized coordinates :math:`q_1` represent lateral distance of block from wall, :math:`q_2` represents ngle of the compound pendulum from vertical, :math:`q_3` represents angle of the simple pendulum from the compound pendulum. The generalized speeds :math:`u_1` represents lateral speed of block, :math:`u_2` represents lateral speed of compound pendulum and :math:`u_3` represents angular speed of C relative to B. We also create some ``symbols`` to represent the length and mass of the pendulum, as well as gravity and others. :: >>> from sympy import zeros, symbols >>> from sympy.physics.mechanics import Body, PinJoint, PrismaticJoint, JointsMethod, inertia >>> from sympy.physics.mechanics import dynamicsymbols >>> q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1, q2, q3, u1, u2, u3') >>> l, k, c, g, kT = symbols('l, k, c, g, kT') >>> ma, mb, mc, IBzz= symbols('ma, mb, mc, IBzz') Next, we create the bodies and connect them using joints to establish the kinematics. :: >>> wall = Body('N') >>> block = Body('A', mass=ma) >>> IB = inertia(block.frame, 0, 0, IBzz) >>> compound_pend = Body('B', mass=mb, central_inertia=IB) >>> simple_pend = Body('C', mass=mc) >>> bodies = (wall, block, compound_pend, simple_pend) >>> slider = PrismaticJoint('J1', wall, block, coordinates=q1, speeds=u1) >>> rev1 = PinJoint('J2', block, compound_pend, coordinates=q2, speeds=u2, ... child_axis=compound_pend.z, child_joint_pos=l*2/3*compound_pend.y, ... parent_axis=block.z) >>> rev2 = PinJoint('J3', compound_pend, simple_pend, coordinates=q3, speeds=u3, ... child_axis=simple_pend.z, parent_joint_pos=-l/3*compound_pend.y, ... parent_axis=compound_pend.z, child_joint_pos=l*simple_pend.y) >>> joints = (slider, rev1, rev2) Now we can apply loads (forces and torques) to the bodies, gravity acts on all bodies, a linear spring and damper act on block and wall, a rotational linear spring acts on C relative to B specified torque T acts on compound_pend and block, specified force F acts on block. :: >>> F, T = dynamicsymbols('F, T') >>> block.apply_force(F*block.x) >>> block.apply_force(-k*q1*block.x, reaction_body=wall) >>> block.apply_force(-c*u1*block.x, reaction_body=wall) >>> compound_pend.apply_torque(T*compound_pend.z, reaction_body=block) >>> simple_pend.apply_torque(kT*q3*simple_pend.z, reaction_body=compound_pend) >>> block.apply_force(-wall.y*block.mass*g) >>> compound_pend.apply_force(-wall.y*compound_pend.mass*g) >>> simple_pend.apply_force(-wall.y*simple_pend.mass*g) With the problem setup, the equations of motion can be generated using the ``JointsMethod`` class with KanesMethod in backend. :: >>> method = JointsMethod(wall, slider, rev1, rev2) >>> method.form_eoms() Matrix([ [ -c*u1(t) - k*q1(t) + 2*l*mb*u2(t)**2*sin(q2(t))/3 - l*mc*(-sin(q2(t))*cos(q3(t)) - sin(q3(t))*cos(q2(t)))*(u2(t) + u3(t))*u3(t) - mc*(l*(-sin(q2(t))*sin(q3(t)) + cos(q2(t))*cos(q3(t))) + l*cos(q2(t))/3)*Derivative(u3(t), t) + mc*(2*l*u2(t)/3 + l*u3(t)/3)*u2(t)*sin(q2(t)) - (2*l*mb*cos(q2(t))/3 + 2*l*mc*cos(q2(t))/3)*Derivative(u2(t), t) - (ma + mb + mc)*Derivative(u1(t), t) + F(t)], [ -2*g*l*mb*sin(q2(t))/3 - 2*g*l*mc*sin(q2(t))/3 + 2*l**2*mc*(u2(t) + u3(t))*u3(t)*sin(q3(t))/3 - mc*(2*l**2*cos(q3(t))/3 + 2*l**2/9)*Derivative(u3(t), t) - (2*l*mb*cos(q2(t))/3 + 2*l*mc*cos(q2(t))/3)*Derivative(u1(t), t) - (IBzz + 4*l**2*mb/9 + 4*l**2*mc/9)*Derivative(u2(t), t) + T(t)], [-g*l*mc*(sin(q2(t))*cos(q3(t)) + sin(q3(t))*cos(q2(t))) - g*l*mc*sin(q2(t))/3 + kT*q3(t) + l**2*mc*(u2(t) + u3(t))*u3(t)*sin(q3(t))/3 - l*mc*(2*l*u2(t)/3 + l*u3(t)/3)*u2(t)*sin(q3(t)) - mc*(l*(-sin(q2(t))*sin(q3(t)) + cos(q2(t))*cos(q3(t))) + l*cos(q2(t))/3)*Derivative(u1(t), t) - mc*(2*l**2*cos(q3(t))/3 + 2*l**2/9)*Derivative(u2(t), t) - mc*(2*l**2*cos(q3(t))/3 + 10*l**2/9)*Derivative(u3(t), t)]]) >>> method.mass_matrix_full Matrix([ [1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0], [0, 0, 0, ma + mb + mc, 2*l*mb*cos(q2(t))/3 + 2*l*mc*cos(q2(t))/3, mc*(l*(-sin(q2(t))*sin(q3(t)) + cos(q2(t))*cos(q3(t))) + l*cos(q2(t))/3)], [0, 0, 0, 2*l*mb*cos(q2(t))/3 + 2*l*mc*cos(q2(t))/3, IBzz + 4*l**2*mb/9 + 4*l**2*mc/9, mc*(2*l**2*cos(q3(t))/3 + 2*l**2/9)], [0, 0, 0, mc*(l*(-sin(q2(t))*sin(q3(t)) + cos(q2(t))*cos(q3(t))) + l*cos(q2(t))/3), mc*(2*l**2*cos(q3(t))/3 + 2*l**2/9), mc*(2*l**2*cos(q3(t))/3 + 10*l**2/9)]]) >>> method.forcing_full Matrix([ [ u1(t)], [ u2(t)], [ u3(t)], [ -c*u1(t) - k*q1(t) + 2*l*mb*u2(t)**2*sin(q2(t))/3 - l*mc*(-sin(q2(t))*cos(q3(t)) - sin(q3(t))*cos(q2(t)))*(u2(t) + u3(t))*u3(t) + mc*(2*l*u2(t)/3 + l*u3(t)/3)*u2(t)*sin(q2(t)) + F(t)], [ -2*g*l*mb*sin(q2(t))/3 - 2*g*l*mc*sin(q2(t))/3 + 2*l**2*mc*(u2(t) + u3(t))*u3(t)*sin(q3(t))/3 + T(t)], [-g*l*mc*(sin(q2(t))*cos(q3(t)) + sin(q3(t))*cos(q2(t))) - g*l*mc*sin(q2(t))/3 + kT*q3(t) + l**2*mc*(u2(t) + u3(t))*u3(t)*sin(q3(t))/3 - l*mc*(2*l*u2(t)/3 + l*u3(t)/3)*u2(t)*sin(q3(t))]]) sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/multidof-holonomic.png000066400000000000000000002062631412543434000305100ustar00rootroot00000000000000PNG  IHDRUL\ĶbKGD pHYs  tIME å IDATxg@Yo:!. b[{Xb]{SWm]`/AA:!6ߏ!A@y~ݙ3;sH!ha5Zⲿ{'Lظ| LI9$ Ba>-.' TWa?Y|X,P@gbq9I$ ,v=לyB0+}s4yz L2T"O=6B(-0X5"OXSֺ#B(0; !h- ھ/.~Nv!d3(?-}H7iQkP$%AfiX P^DŽD"V_wЈf s`A?m;z}S0_%(Bu*wJz{le !VHB~ J5O <@*7/_ Bׇ[V C#Eֺcqc"!Nb{syg'kh)WIέ:{|+O vHIy`7п uq'#dTU5URM 5mT^`PxA=f$DZw:Dv6vpO\5FO IL&S>:R3#2t_G,tk:7c(ˁ`?Lr!5=A1醗$1j `/BwJFCG @*W 4!T ͹zص\YbIt@rL&w#&qS#csH@MoDvCYߟ/*\uk݈gW*-;)2`6/|<}Ó6밴 .ŠLH*CNO]_Bbq B&{,vtns/rZ#rSy֕9_sz{olkBcH$h>:q9INV;YNH* 6쒄:yC5:y;3nZпja؝Ot2jdݵ&1LJIQⅰ/s.pܫJgmL:D" jW(k 7Ϳ35?c񍿈P$i~#P8cq&/c?=ߍ9]X!»E"FC_v6zeauM.74ܗq4UBZA4Dп:+4ϥ9|.BFnuٳ%zRn/8T"g_qz=b1K@~M ӵT5|\oTmet{]F*rي^ԏH/J2huCdF@Ǭֺcc<ͣ^}X)w)! _\4F(ACνDUֿ#{O 5~(.'~:Ch9.! 2/)]Fݞd=/"=)_26Z~]NzoR.&4Dп:J=\s{Ow'afT EEQM]:! ^8tc}4 6^5U ^n)/6#Z4baXȷʇ!Wڔ.қ[S>KFJY B{P|-|xZ=kJUTm5!TjqhSN=3Jk7A/Nw'i jj nj*jHi BH8-_'uIlpNI<^N' {ה`PvVD& HSnϤͥv*oөͮ#T]EBD"-mRQkA' ;fXo=q(^&vq !R{]K 4JBz/Y b[NL5oھB]iz}ʓ<[K0֬&dS:ۛdы|^E9_4&_%35خ'^ʥ/>!4ȼ7QRl0yR|Ɍ)^ U)ZH>rTgszRo7o_3ƼjjC3Ӻ)W^f۬_&,F7^Cy#CLK-\9?alS_^?3oZ虎`+p BHE_ O{aP^W!~:YBi臗w>%3nӃx*5v͘DrcX5 uB^M?!hQS1$SDdĚhf3T+aiAPu\9dbD,,G^y]G:,~mp5:l ;O}fYxb̸W&$榔='ޚ{bNIYW|_'b &{,SCBR>WTD"uP޺vEfo >>~ B9Qco3bIj ŻǮ{ƭ7~DӅU?4 /^NoB|sgx-"(5rH{^ϴD/iIY3&_bcrЫWVgV̨HջmEfKm{7ҩ',\F(01YZnV!4&`ɹ"2˰9Bio3p$O_,q+_ t!} 6oEyiL*Z0ܙSSa8:>BʜÆzӿV3Oݶr 6 :BH]aB1@T7K&U:,-cVj4)m*vqx\xBȱ9| ż7(;n_#.sgkޚwHàW0dX*ûPQRPWag|!T(<`Y܃/+R(Uy!5kЅ[à2?U@)y,yϥN]u79YiLo @^`.B;coW<`'@۞o"r0 G ,AOJf5գIx'п%e9'<~gdd_ĦB?>rͫgY`◬_ @ZDZ8Lʆ>U䒟Ѿ3ŗ$%O@cV=L4Vt({ F1U B()4v`)r`4/+_2ܚII9WE֟ǓJ9B˓E2BJQ*t2G2] jn ihH+_ήũbձ,i$<п DkR5]G!ȿYWD)>TBú9+&W`\ѷ,af8=W/g狳 $!T!-oqp躚 `Q՘4A`d[HHMV$ UOB'I$64'nak10'0D"5F"˥r{bP&*DRy2*ʈ9kLF!]]ʠi1j1 q Bqevb"+y ~I,4 l!<пK?GMڊ[;Z\FI$T*$ĝB !FSaP֟ d2"1CjVe ڵ@&V9jⵡ'P53^|}{YmڴHh\[ D鿏73e骉j[z 1*_5T#})?~FVJ.lZ:E30d[; L|B 稬vϮ>Z 0Z!z5s %Yh>_ >{?ZF:n ,[1ؼaouE%nʺuzݻwo&c܎`B` wө{pbSkSD9SgxƧB i|P>8ЗK<>Ç q~8'BH |?Z2 jHZd2N#oi9^EՠcN.]N(,x{{{--JCbUjƬ`c#&BC5bI*ت}ށm*VbGh@τFihhddd ޽{_zfQOvũ{ !kZ(^Jbj#{V5EM@@CC_p~M~!C=4sxۀ| BPr9a>vhDr0ȁFf0 ۸q'O@sx&B0 P(\]]-,,@3о5L/;g"t钔$@!%KA'rEwH$)S2 hVe@9s9s5@ZW^%' ϟ ~K. UU\-<}_SS#G >o߾ 1_޵kׯAfLR *pDf]nݺ5uTL}6BSNV9s&FߺIO ׯ_O>miiIP(_ W;~EJS"AAA2JR(E3Z?}ܵkקOo TX,vtttttWbD"\[O//~T*E]z5--͛ӦMEDD5jӦM L訣:b0 `%R r %i9&EڶmMvI{{˗/o2l۷o_( \\\/_LB烡IM`2 e cbbT*%^^mllكoEDD@aÆ o߾sNB*c#=mBse.I$ڵk'L垞'h-777???mmmP;d #wT[te"^#a6hbyNI[^WWWy3''GyFb)޼ys!CB3kYzxx<UV` ּ ?E`#ֺLӴ?7 7߿444=}ذa$);;{ЌAZyyy .rJP)TTTB'1!o4.kcauN%#$Ҧݱobb0##({yyÇ{B0qƿwޕWSSSCŀr)#!Y/mjLki5i3 ټy ή+ 󃂂1^~Mќ~SVWGeU Fp T,AB& !֭p8۶mH6wfW5۷o>|f IDATEr.+рr)B\dNIdN]p,0XYYeHr6,^^| k7q'5s@b0BFnۅ̀! DEC/^<~81.[.:t ߿HP̴8t w#Asssܶmۅ ^ڵkUN(((X`ܹ[4-77LTWX{M60'Nطoߔ)SJrڶm[6m^xQSSS#={!>iҤ-[mAfKrIMSybNLm6#|-K]~}#F033+UHR`ٔп:>*BCh~XZ|iS7?<9=anC4woӚ#7aVv\._bBHEEE*&%%޽[BϞ=L&[z5?886_KGGG'==TJ "R3d,N|!t͕ǜ&qYsgϿ* BO3B߿/U!"""%%eBݻwĂŋ215kJK2d{)Z5]-!H~ zs%7+._$CE%7=JEE23K… x]vU>kĈSL R,wQ!@+D*"=?j[zi30>:iҤe˖:jjj:x`l``p̙ӧ>J] ij)CL>@6ק߭1 ZzȈD)S㛃=ztOI2U4'`KrWZUl6[PBUUj a.1Q;tN,2ݷt# fb.lzoHB ~y]¬o5,ڙ5= ܹscb:=<<_K$&&ܹsլ'*P]o˸w |]6g@:n~x۫!9bO~"_3 !DOPRƬ|F*> 3 -ĆRt.]"K.@ ֭[w UVZJ5ek;1b`[^۟pcMY=&x^G=:lg=D^w)0v;'Qɔn;%BVp ϝ -8uu3<oܸqϟ?',]tȐ!?wLMM߿? aп悷#  API_-m񲾚N;m򹝋Ϻ#I D;n}XF=TmU%9IfPh<`ȿ'\AޘsS8MǤۏߌL&4i͚5?' :t(#s>`un޼p_qFZפT.ƚzO^nEeͤ L$s } &ϓ'O󉃇ͅ@!NRŜUC\bqǽ v , 2_,|=-;o aT2I+!/=cDǏ_Ħ; :t߾}YYYG&9sfŊaaaʕBsTTkڴnݺ1躠@M ONWJű_>FF$Uy.\1x ^'䦘rZ哅RԷT(,3zh4@* %BP*rʩ(W__һ;vX<_斗S.߿//]ӧ>}B%%%={vѢEФLPXZZ֢Sd`͋m3o~pїWgWӧwˠB2H1,K-WK[UzY>Yyp_AF ƞ Oi@iܹsG :tΝS=DuĂ\&{-\5Z˷>2W8K_DF6#]Z#=KF& gbm􊭣W̝vkŋ5Ã(/_\KK~) … gvrrRӿ_, MS5bP~Kdο>Ztư6#BU͚=MBJ!!ⲿ4<6#I42?H BErKY2L؎ÈT2eV*y L/YYYn˝;wڵkp4Gf$ G T(m۶ `aa!H._ @444~R(_cqZ=Ds<]#}pw7ũUا:f 媿ߌaUesϾqr1Xν,ê;B^r6O=l>w&̴ۜPMR7k]"-]?N/]֖޽{"b !*bxASSs!""ZJYg͚>vXhM \pLd2wFhxY9ql]j͝/RɄRߨWon=Jg.;}~i_qIU n/({ L;gBc2y ]4>@hi]JKjiiYxUrroߢEwqڴicƌ޽{E6#F p8=zTxgΜyeqE<|r{{ѣG/_\(bv?п&ƽ{nz޽)7۶m &~"- H ^w-&J˫+vԊ2ܻmWcuf~;D!ϩndg=C=@*J tom+PW(.rFv|?n޼/[XXYw)//o߾k„ ɗgϞ)SsΝ;؜}dɒ7oBiHZk=p\Bp'MDJET^SvZ蚖T:hfIt}RXَſFia^s!ÇGP<==+5k<{iHٍ3fذadϜ 9v%KTs? |}} }@ι|g|L!{񱴂@\8븏P-:DRM;&ʓH"~ Ў;*jz51Nimm{nпźu-[FJAPڵ+wӧ۷o{xx=Vj`VZelliӦRy N~+9s(Äaq>?b0E%G߾|2{l B"*J˗/;|uӨECn999) ss3gT>WPPp5ܵkסC¯5"WZ2Uzj/^xߣܹTccc0QóhѢVZmٲ\ m^p8.;uԂ&yڵ*8pA=wܟBq4Aȑ#-ZH$ҸqD?7oӧ B`? sZ:Ϗ&HgϞ2 ;r^f3fh8Ƣkʎ/3 qC Yz?өS'DYxqPP?SIMmu־4 Jڃׯ{{{#Ľ;w\NN^^lv}ze#! R? 4Uoi@1wܹ|k  ԩS=WRKtt… B;wᩩx2ܱcG===|D0;;{ӦM! +Vԣ nWxTE MD:T@7Y???OO<2!IJJ JJJJMM ֖lSSS}}RgUԒb@ `4ϕJQQQx-|rĉ|2LPlmm㉼}U2gΜztBRAyduvB6 @!?????cǎ0h\ݻM (~Q355mժqfffttׯ_--HFuҲ 333111--MPswX\E\4BYodnnN$ /z-E!!wDWG:hĆL߾}+ݻw3fҤI`§O?e0 u |$400000ո\n-n]v:uj׮r "66633dchѢ׳X]Cl0PO>ݱcGEWXXӽ{i >{ٳO>𘛛#Ni&FR Ň@ fdvP(233K)+x<<-BSN2㥥`Xu) \ BPUU!4tm۶5JAh3hD>XЮ@rrr䨳2-#JqB.V[ܹeyⅫ+,  PvvQFa\nLLLHHHJJ 4777330 5400h׮.E!O c IDATBO3,t 555AA>/Hp-u?vvvbXEE}W*UwJl3zX! " BӼrM㣣3hРery%+? _~.'Hݗ,Y{]ov Xux*kjiiիW^eI&;Xus2}B' bEy%!)x.:k"W d2g P!ׯ2eJ֭KOKKم2LEE~.J}(ɌaPnnnZZH$B1L`,m۶, BFFFZi`B9sX,֚5kBABո\nE]sRQjݻwCBBxq|KΝ悦刪B&+,&Ed WOL؟1J lCZf()zkHT>(Ϟ=RYP(J/B/TUU9|>_PH$FF2 Pnݺ}?4tЧOx7o188ĉĦaʷEl* &T1 044 QQQu@$t<<4 qc+kkkS(<%EDDDCT!Q=#/:͛7?{ „L&dqٳ>}:p@Y˛:u*Pb;w(Orq7o޽{ӓ ҦMhy2řϺ-KT0l_k6j*tH"j 5m!@LHxЊ@Z.]Zzujj nݺU><<ٳÇ APt<6NdJ!f߉D""6n:%%e߾} !4qÇ}ٳgC Q~2Ι33fĉHv"0wwwDruu]t]JJJnnu.]T@622200 \.wW%NvRpXKK V^嚚Lf nժU6m~lDL pĤm۶d2922ŋ:UE1b߻w!sN֝D~ 3 77A>Ãdɒ'N,^x֭plnݺ=|s型?X,V)DZLg+.陙ހH$xeyyy߾}ΖJT*RCCC&D*jjjjlll```0`&&&=z9r$.~d2yڴi$iҥ˖-C۷OYn޼&&&gϞܸqcFF۷ocbb٤o޼@1z򥵵H$pႮ.N733cL&H$,7-qQ?_|3ťWVk tuuo߾5H/PgC Fпfׯ?>f__ϳX]vXiY׵kڭyS>Qn|AK} WY?vqq!jkkȈϱgꐒ:9tfiiyԩR2339r%{{ѣGUpX/@Z+4?O3*@Pti֬Ygjܽ{H$Jlذ/nk8:: /22Ry?fO4^tMTfÆ Vk?܆˗/_mDgʕ+?,ɔK~H7֭[cM6ݿuWuu ܹsG.Wy3C%^S@*VQ|ݻӧWy'OpJٻwoӅB=zB[{! Ѣh_~-[M ->+ðbqz.]^|\3%%eΜ9e#/_|fLԁ]rAX^4 oo} OUcY=M69::޸q]w\ ! 4T`CŮ(6Yr;zrz'X@`Wl !!!=G&[fwgw{q\666/^9r$Nwpp@:@NӸqPcccUR>;w۷Ř#0O3;ͽmiˆ|㓙٬Y3gμx[9r$==%kTTTΝccc+UX0ʀT||C|'1W.BCCGY^䱖Uq%#GѼySNhiiyiL}2LӰx @ vȔ @ (a N@C_PC@O>_ Hvrm*~UOhhVgxZXXT}u?}4q]v?p,X`ȑ 4޽;>Fs:jRMLLj"QyCjd"L&Sǯ>PpnLq8Wy~iR}ER? 2dÆ e~Qnnn#2fuK;;vw֯_III˖-[lYf͆ 2yd^}"?X,J|P(,**D@$5ioÃb国XvyOs{uY@G+abRPP ʛbLr#-Zt]P4:::::M\\\,,,rssK1:nkk[Dq`iir------Xi.]XX(ʛbXT +h[S#A\o@F&FtګP%^gŋ?|MnZtJ,GGG0ɩy3Ɲ>jR%[QFsD111111Wvttė"##y<^5ፍ]M(K[ƒp'hL&# r4p8J{Z P ZQy : Y{:!_R!!!Ç/DS՚j̙30,>>>%%m1D] ?|Pcccccc###$ NyNf`( M̫zH?&& T ў! ;.4x&&&&&&8W-}*]~}۶m~zqNfc{~/\I|>_$|JVWY(W >^zy,a>|ť=dl$4PB,N&Ӕ2`ъJpd@Ғ *T\>Ԧwcdb>8{W݀͛Yfɒ%WU*/^\lY|||֭qJ"99ξz*X,sspvv&^7 Js **ɇDrpp0RvuMejj*qEyРAfu&܏ //Zl02 T P@ 2 @)A}&F@0A&2VgN&`iI ̅>!?fO? \f͚Ç;88  2gΜM6UXoٲ%B8www+9=addTTgggDvZGQQQӦMQyAAATiӦC#LJ* LgX T P*%ȋJDhٴqQQR Bzҥ9Cp]ӞGȿ+W￟>}Z~}__#F899UgϞJ$G{qI[YXX?h5=/_YP|Ny00ӱ,Q(UFiӔRԫߙ3g]vM:U/jJkU={ @ȿ@3mڴ~tAضmFFQ-_\\޽{QyVVVYۧd3jvI cǎ{d˅}YFEE%$$C p8#P#8tP=J,lوBbbbFFFnn.033cjðBkkkdpx8&Pq]7Zlݺuy!@8? TGޱcGM<+;w\=cD0t=п>j͛wݸqt˗?zH' !G9{KRuѣGWxƍ?Z۷[#bݾ}]vwUMQ/2eJ \.X533ۺuĉk6oQ$pL$^zXu2# 0F42ӫ8jzOrW^܏u@P5j3gΜsedddggD Ě+H͛F!OͅaXnnÇ#""󳳳޽{M4Μ9h_v;wLd..ZS^g~'O,3ƃibo1{i5 ~EWWWT޽5c NؙEfs߻wo6lHKKi&//;sL'E5jʔ)999k֬o^*6޽{5J87i !  Pq Ç;tp]*$$$|5,BrdRʒd(P(411r:D)(Nx8eFitttd8)ZXX&RSS1 svvnذ+* 5ߙ g.}fogn{/7\CFa@btdxxxϞ=kڵkbŊCTV}}}cccQߡ۷+((H$Fz捹y!Wp8Æ ;wY[[U.J(ʜmjXK4ȋb1 43O&edd,B:#l6mii;H$333gkkOb1J511xhT*|رcL>ۇب-,,,--= rjY1[jgk999H@.K 8Z!$%%9BUV~'%Ҧ?lcMmAׇӋdT)Hִ!L*q6 7Ś9s&;w#".]{ӧ߿ߧOZӧ[&hlbp&GXXH$@fɒ%K,333.^ ]gyfff^5)<~VB,Z&t^.PE-J"S? (E ݿvUݑ AAAuDI h남ЩS'p'N۷Ϛ5 E㥦 B:-$%Dvv̙3i6(!!srrwr-,,tUNNL&fffxBPP#4t F733S(hu4dAh311qrrAQQQ~ҏW4i)5^KQ3( IDATi2-۾9ȯ&a"c@nݐu2PK]ϋ-:y$aRV''''0Ig/^ܸq?ӢE B0jԨK.`@#J̍(ʢ"<*QZ8'6MK@I$1bWJ{r &Jd2L&{J*((;WDx߽{WlzLyFp.X,dnnؠArQjZ3TnE ʬ'33`Pr'CoPZ0_dj;r~ckgo:B&-Z@OȨu֏=َv^^^>˗zΝ;EGGlYݼO}رON0ׄ#`x,Y`h-'3R'$i4Z `tR<3"J$Q5*)s"n  6ӧoT(YYYڪ9hoRRRóRxxxyx\\\O W\yn/^FѺv^CT=9rȑ#۹sgDDD׮]Ж7offf:::vـ6:"V!T.+ȿA.~o G`8<\Iʠf|3))dz#;ұ@[ԝcܤѦMTҶ͚n<57oo޼y͛7oӦͫWʻT*MOO޲{zgUt666h˂ z5eʔ=zԯ_G@O`6k֬ݝh|̦EEE8Q=2fh1 T%$N]te1fsD͐B֭ t-%RUVVvղ.H @ (Iׯ_k|H$;;;prr"Ȼٳg&L)GLL#EF6lF/^@rhx@TTTnnݺU%yԨQaaaXmINNڴi ̄5m3*bBavvԩStbiiI?U?&M`ҹ L0eFd @ɗ"ݵOt 9z^h:@qqqd2O>hgZŹHFo߾MKK&&&4 bfeeeeeIR###+++2.Q '3&xŋ|ܙK*}6&&F[wuuMKK077733KMMQX%..3g̘p߿Qޑx2jr܈-[ܸqv1 u.-Zeggt䥌3T33ϟ[XX8:: [n/L&3??ӧ(zj„ ,8vd28<<|Ϟ=,+;;[.+Jkkkwwvq8TJ1 dfffnnn߽l%N$ٲSv1D37cNȜ4d\n3J`PHNc |ܹ\'O?B{BJNcq>BB}5.]b%@:߼%?}뎼QٛUB6`S8{e_^^ޣG uV K[r(66 '"""LNh/_޾}{OQiӦ#F8s Rm۶_F C u+V$f EO4I/!L6h=Voݺu턄ggaÆU*xVEȍ2:p7֟h^u$4CKƃ (Li9>(_0`޼yǎve/6H~޽}vvٳv؁yT>}>OMbƍ=qDB7Ll~ZxwƍGIۛ|L? W%bwl^)D`dڤ@quUr"H$J P(5jԸq{՜477711A*ʑ7ܹ3n8<;P(#Gnڴ,_቉2 _C-MJcieeuҥf)'MK&z:Եjbky Ö-[CV^#PWD`t?սXrY'`0:uB{bccqCXjG[smH"pD=_mܸgϞ¯q'NQQPԊS$Y|ƍڅh܈WWoN ==bҥK8AŹ +GO,hAz083Xӧ+cb }oo4诏ԩS՚Q(dHP#!BA,7`|}i>8#GrB_^~ݵk:٥&%%~}B(1m@`w׮];}… Q,_ <*"R'B9}4?{Xsf:za&(ZB ?i \+q $xWpQN%+Ui+l|__s[lmm#""`0ԭl''' *^MPG@t߸qglժk>>UrWK5^z!ŜKO,9a۷oׯ_NNqٲeGk6Oa$PWiӦvQԂ脄++EՂ] RtXN.h-YDؿe\н/&:uZ AV/wϞ=sA*jΜ9FFF8;e(iDiVFy55{)1_(7Y,wXXH$sN޽kB3ȴ!&No{vɽ7iӦmܸE}_"k3acYrshTW{r. JJƭ크Eǽ<8ph9(aa̙58qbFF'pҦ.8 sO3zքӠ :66vĈo޼)88CWOu"uEnn':-\ ?Gqn޶4 aW;9m73zbQ@"d%R#ٳgH~t`]`gU_R l H훘gk(`|N8QK&ܹsG8qu¯{?&!=ZjСLM%'Jj/^Z ͋nwc?Tliɜ1IDEb:MԔodyɹsh4h7vw{V?fr`V\%1jk:E4iҮ];42l+2-_uܸq(¯zƍ~!*H#N={v uС[nMNNVb!0De]νXo'$U\<&ZY?mm@#ٲ]ZL vS,qKiڴd p~kM5 J2s3kh[|ŨCzP}4:uB ):իJ`jj}#PG@QT*͛֯_od0KQss. lIƴnV,!Tױ^vTђ4VQZ%%?MC_ AߗY2+<ٳp8| W^դXp-[t 4imݺuPPN0A`k]rX2' LKc,1RA5ɫ/Ӌ%SOXȈJϔY;nܾkRbJO>e.+={q5ؿ%:|g 쟵DҼy]v飛~(h/_gfLA-ʧ *MpN!`PAJ~`Nhrij. Up_6ۛ$ѣGǍWkmɓݻj///WWWWWWwwwWWW.V>~}v ZnM|Ʉ#P }mѢŞ={tvT*:noo-/K吘L,'X,Zmݺ^8$^DBzOo#=tTZr/7iR l} A*,}s#^NPuVa]telldɒE.#PPTL&ԩS[vvu6m>}Jw @mF,??cǎDs} x똓܌l]s/V$6X --Jū7T4qq<; .dDF&'Nzj51\pA;,R6׳g-Z:zHȕԂO9|1۷oǎ 3GFFvܹgϞ7o$Z0HN=Y`z9sx7o&@bqȩR1a`d +F>T3Ǐ&ӨQ#=*dxtJ"wO92HV$Q Qcql9VM4nɬ*fq+WR*tp|2T}73d2Kv1 (gwJ#'UPׯiԨQf͢ %%s$=ZYU1cl۶իWRŋ+P- r9][A\v?3x@"Hى&6[ڼoCs;Ud6 F0hР9wP?#uZKC Xc& OzTJű(]U rJ|^k=Ԕ*/rLxe_HgnsӮS,֖Vqĉ-BQQQ\~ճ ?m!،k6\S<|Lr) o+fJ qT ^dp6|tuuWk׮ rR' rC~Z$Zɔr3 c`ɱZR\\(f|.Rcka=gICȿE,MuݻD~(} I/}*U\zn ;{R \\\v =+܅]SLK.}*Rڰ=g^^U1G{ڿUʜ^ D$<:TP)wGM-w**B>6 "޿yDG&G> ۆfn@C-h ] >fKUt?~gΜƍ#G?@"!.Ja Κe?G:w 577/ֺ0Rxqjյdgq}NL;dޛWTp^7vOioS ң394iEbwaQЊ&###ϟO4ŏ SLT- 7(sbѢEz1p@<ԕL&s`Ĥ0hv8ڵ%|t&_!}\,wEgĵmmo[9a_~]=Nݻ7^|rBBB nFlo]2O΋6=Y=5h\ѭ尸D#ĬY  @v誙sH!*` |MYϢiP =l_mٳgdddUk@P(vU|1m{ZZ{Lh7Ay7n`f E *tpĉ`R}#Ao߾/^r_)!E@&txb /e2MǏ?>ɤ֍MT=XRJӋ&i4Ņ<;,[G'OHK{)VKjj\0rxIOWJG~xB$Ǐ,X ~P\?OFeג; Zy#T~՚xDiHAhݻwz$9r$^ᦩS7ۖ+w;oihfE^;!C̜9ߟh  4${V>{nY ej jff߿7D&ϞIsΪq֫W0,$$ξb2+N6QNc&a؅77|Z_= B1l0gg͛7Aek+P)juѢ%Pt%ڊQRE~*7hŬYP^ ömV}}}4]& N [(4Pc껉Oxwx~_Djms=,\ǏΝf'@U _PYAz!USszЀ@RJP‘+W-Ǜ6m*={677J6 /?~TǠ]"~ěn~lдs6GðGȿZٳg?(SlQYv4.75mkw# {3WFFήwz/\ROɓ'#jDr*s+{(T+1fCxw2)⟐ww2 s*AD4)?n%;wکA ( ŜF||jU@plڊ go~R7aZ.Kcmܸq׮]Qy޽*U8H$իUb7 H ;>s>bɧou_Fae\Jt7BڵkG/1ğ6Ҩ%&xFk5e9 ybXg)Q5s§O^A'O9˥*uиG)ժ20 {r#+ _ePH%ИMo zPjrHv5 ݚFf'%%U5 >}j4Ç̒:uT|…:qnQc<=^.0ji_>@b!z/정kxJ6;:z_ w&o8Th4b`ŗ^~ eA  ~ˢYYYuu<,ḷ^Iİmã62Goi+/Q+b4T^!! 5AU@p̰SxEe+K,դޕ*O4cƌaUװaC+++Çλ}41bX&,.X >B&Ol;yYA}sh#@΁db* :;*@Pur\DAYPPK6+ùw^XX؃v] D8 )Dߢ/bmbS x2Z<* : bR%b>_aNjPVYQcHT*ΝFիWf8cǎx9**꫿ߨ19Rӻwި|U<56\KT=%xiL!+((& mزcK򯮠ΆZ43"iC8a{_A7,u)Z{/?|֠T6xh'A]WϽ:RM4MB?tí?[R3y&"DZs&ѿWWPXXXe&g*6N62+_Qܹyȍ(@K+Xxf0l:u$;ARϟ9>3|Ly@Ρŝ٧T@ eS$6Й eE2TjG~FСG~sbH >ij3.o=S ٳg'1x/tI=R WT%.(߾...eʿVx{k#mDDăLR)̙%zOHHݻkE7ͧX`P{Ͼ0i-Wc0n(*ߌXVJہM{3`ilM[ձ69AO*JX=l-DRcꙁ˳EyIm%=g=u!!!D;5!ջؚ"S®NϨxY@ _obaѡnD"mI ,%4,]458=>7oR8ֿ_:C 8wl\Zw=N%x&#?*$:#Ľ.NTLcLYCxv$@kvʢT-[UͼOEx)pw%?U6cܿ_aL"bϼd2ɀӴiתl6hQQڵkkCVWn_*?^wgnfZH&ߓBvvɉK:tu.F>n<ߑA=ǹ B:+**¹u+-BEGCeg>&*RD> oH8[[[{{ GɩSjqpG'OT]N<yׯ״3l@ ٲl_Qi{k։%=gj5sAzkSD-a4JK Yf\;wraD*M֩S'Oa|@֙liYuO-9W [gL(R>y d_O͟}6a_LJ^4na0uV寵f͚ӧOD"P*#F 5 0 [tyշ@!Wuj_eb*sZ,~N $Sbu$,ՇǏSs-idd$SSScbbI+;pFvwS/.L90bO]+yZ.C˕rP8謿{rQ4X.)~g}faXz TR)Sݻw옆XN& 4(44T;F82{I]WV^!Lh3˱岐m- ܫ u@>h*Btr_ ׯ9s&$@#hrMYu0ƎĊig BM"ٹҿy26 <4i2znغt/CƏ  3ԍI^Xo`}`WKsvOPYLجG~4~x]HHȬYD8JH@6xA>:aBaMoWgem_6lXb1\c˘1cעRڱyyy{~M ð߯nB鳽Ol;:k[4H$RCs>nW}+kbLt/ D>T*ɓMMKO@`N"zν{W|Rz5u^>I?ҘO7nlHeѼlׯ߮]CCC6J*xaX<={v.]z.B ^^^+W;wnu2_>t\dPc=zHIIAd2ń29F&.<&V2/H~޸qf̘A 2*s^<;UJj-s 1 ?(c]Sg程UǏChJ]Ky|L]^VĀM* SC Κ5+**J:'zy[mϽ !>:Y۸}Ul6ʯUi+;yt c0-Z?Zz0@j}A.n *`vZj>H'U.Tlmތm/~,s}JJرc366 Aq۷ӳM6$ŨƆd~\Kf(ANNѣlҼ9BKjyw4vU yJe$HcL"R) H PſWQ>{|ڲ ȑ#_xGٲe MC_' MŠŤHɬ/[=,llz'Oxl<Ν;ǎ;t2?3&M7kݽ{J>\f=(uW:uj׮]ON4=(NݮJL҉F+^"t@AzMՇ2H${RBPPP$ i9DSv#dIMw3^d*S*._\Ve0mJ#^|nݺ#G0`]Fogrj @ ͛MA@?򩓒J+s>00T尉R)gƸ-L"Íwoj|,,, 999;;@<~z%Kj S1Rߜ2i~*\pA~Z NHHXreYvU*իWg͚Μ9# !'lk# 4ZBZZŋ9MU+ S*UIe-W0$϶XdkʒloGiDm֔ 4ZunB888@LLL-xl1$~*N-]LGjoUqi" L~تIb .rޗprr?W\yҥ/޿?99+QXXlbbK_w6ķJ?%XxٳkfJxYz6 $&c,7O8]Tp ŋݻ թ֫h0 H@22wiwdD"R|}RRR\\\TTTxx8Rjum\i19ܳ % uMA:mBoVyXgv (5'@+9_.ZϹ1YєȢqAgPBR~-Xɓiiiׯ__dIv(@Vt/{-0]G!!!5JOBf}L\ 8Tĝ0_~V,5 Z'5uTsl&kŌF[W\;v,//}9G/kS$@ȿ'Nvr޻$LzC5aL&L(۬ͭM֫Wrrr222tPY{CgZgwɃr?~׵kW|Rܴi5k1aZ#&B .>?|z`ņ#'UwG^h0{: Hl6ظ7h9޾}Kq5q3-QRi^|A=j899ݼys޼y+rر͛7@ŋhkiIo)ټe?1F gLC0G*`?TN###T~rVi#SJoǕ@6 mVBRwq)sssSL˭VmX]T@Gk޽{D(q%"dۮjV|Jm7 '«Y'.}YѨ)NU@(R/;^^ye=L\bѼ)-[j2۷55*!!aΜ9,g)g5jtcoGWJϗƍ[jz1Xc?N*DY\.B?ⲳ֞xw' Ij5fRX-XV& G[1}½|a1FLkNOO!}~#AgY2|w\M?wtg{hjKR)D|މGF"B~J%IRPiϻ=ǹNWKf|tιuޟ~_x$:99y۷o ȑ#w=k֬_6lg ͉"i n߾066޽{5`$/_L("h7"Tp0A)*ٳ?~r劧}lV% L]TlMkglm_*=z#-ϧZȥBZZOrrr͛@8p߯jREE"V>~I`DL&EQ(~~**^ƅgآ2.yӤ%~|+>>0h|7QHCvvksP_o!8nuR(l'%%Y/̙3ܹ󫚤`bb()??<oƌj@VvsZGiU./Õ:w]̕ΰȒkBʴ^F78dRU\ jاH$SwgϞZ그YdrppcmBpر^UMrww K;Q/%..eee@KcA*usJtKMyOOO6O z2-"w]ȴmw{ _~}ѣG%gΜ%- Ǜv+ sURRF)L&&ܼAC IDATD=/Q#% YHΧUbood6B&șv`4r!3]=ż}455'**_>>>[3SrܸqӦMp8?%-؝Ă RRRƌ-fggkigR@`n\znhd?k cnkw||>>ʕ+ׯ_mcLD&ɤ4xٲec{644LKK{9]4/_|r嶶VVV:uRSS%%%)))RaVVVcR(bB^VV֯_gϞaܹSMMm…gs΀uu[n i~w=xX#/*}Bz9rEDJl8bDlXU Ik:t*(zЧO;h4[[[ KKKssZ%ݻׯu9::VVV]p!::BrL199YқL:uٲeuc]AAAxwhee%f3?( K.5pC$͟?_OOݻ\.ڵk ,?~A AN|>7Xs;5^}5##+|?핕UVV*>RZ6(?8qʕ+ ƉxaR\@7 coq>~ˡZgV/`qX }Ȏ󙍟[ (_ҥK?ls\\ݠAyݻw?qDAAӧ{YGGĉbEEE[H7o.ƍT* ܴiԩS5D"5kرCWWΝ;x4 Ya Vo/R~hƓZo4/]uך7U ^M#7OGCzVqo?U3d&)i쮮***Xy?DDDa[ד'O'N(F4hԩSk׭[vsuuMJJ߿ɓ'L&$\\\||^߾}ԠAߪU455o߾g[ e0d2AZ}\nʁC{>U~U˖^ݬ(kj 5 ] j*Q/ >ct<`ˤuB9$'ɸqԩe˖Kӧ;3bĈ/_^t;vH  &HnݰaCvv{V8qbŊÝ?$//?!i Aƿ~jKr^HA!{BD/"X_+gO%c:+QDZkL,\e^^ޡC6l`kkӧ{at:?===22'DYYٓ'Oݒ(N:We 444|ѐ!Cp SS7n͡AjiӦ(zj< Z#D*Y5”k1R<=`>AY ;yFGIbjV@& [ʇW ,H! E$m&m۶̚5+!!Aի?}o>I߉þ}i,`TLN߿͛޽{ ?bƍ'԰ISO A 4c6+H}XY%!M7.7>*%իȍ9_Y^y#mw6bl8X̩Sxb ,XrJUU_~7L"ǘr_CCC==zAp8bccGyxx4@Υu/v$LMY#lMC"<%bF}H3idW+ξlgɩ= a˹bݻwo#m;vlffmzv[%GpwԿUU/_w!7g9T$^Yfh >ѴGxf?yҠaͥH Z `cջ@RhIOp;VkK-*++[f۶mxP s;JJJ$YA: wY dnJ@k7(KKKF2O25pP5N30OAn ˗/oa?mod/^XPPt Y^HAy;W\4?@7n S^7!H"a>ZMhKC9$"IG6jM+N/eQCU%''nE>>>xhl@u H/?oHaM"-}69zڔI7iS쿆_爕=ή衯V+05&W) 8q"m۶2Ck/RUUUZZ /U0kwuh4g6:~ScSYYY-8iE\0G~i0oܹsqvxDLeeeAA᥀ǬZ]Ov'4yuSu_pn!ZZZx 'npz̼~wb 8tP#1 P$Ta%?f u+wag_.zP(BErfTMlGxU=xwȡeAx5X[[O>֭ÓfΜC122 0^ HP̚D=]mzBe@?d/_f!;tqQaKɢ7o%EFpd??ϟ?mZ*:t_d^^^0tTkx~-]v4iRs]& IgoԤ8'R$43y " I v6^zsLq+(h;wvww9y S;%鉢hbb"D"[<>33kcʊ===bhl-+/큖~73XQFvaQMM!AQ6G;P2b!CbpesϦ̫WiiiTTT~~Alll7n 8pl; =@ rTjVTTݻ7xA@ #HL@{ifbE~eV;(RC/u(} bIϽDG0]W]ϭd]2<S!u3`d0aUUUE n r~#;.h FM(^db֏9{y9{xHn I%  jSvEEIN, j~)ksZHsνvUWAGOj{u/KFпC٪wP+)2{-/YDVV+WTTܼy>P H&X");}|)O.1- 3m&Ƹ!P(. > p޺ukvvvOOH/^TD!N9ז2 0>o߾mK."^Xel\!.dR6 /߻w5puu4h N 8hVXE$2˗ʟ:BTSmhDnzEeUUUIݻwM!uLMMUUUu֯܄WEr^tE}PԼ)'nΏ;~3Gr2[|>T/^@;S:"%֝Hn^ݍtÝӴ5Ԗs2oxǏ;88;x{{_p\gϞ988`بTш_3?ټeeXw@pM"bkK0h]nX-LH)YZꪺsNc tX~}```.NnnnΝ߽{߿3g@ 6$cCE;2]¥uŏD\X( Щ$5*GVVVn.]j^R\akkm6EV]qk}ďF!u7UgfB_^S(Dِ?"v ?j(|ȑ_3337oѣǯ2͡@V v;yUWDJC4B@p[tUO0aѣG sd:H2Quv5t;0ԕhuewZv1Y[rJ'ƧBv«b؁M s0`w^(v6EEEx[.u7nPPP(//D۶m[bHphCIIIppp[L @ mK1VMA| ӈs*-~DL>r'^ ( @6'O>}_  $~DLIo2ޮMM~zQkz/iB υ? zv`L3@ݦoi$C&yjjjRIp$iwDiӦ]v _=DDD]I"u(,35򫬬Wkk/ˑrG848u7'w2dɒ5|||~fBOUKqVn5DrPzgQ{Eϝ;16]42_\Lٵ?BErnÄ~] \,,YeE~r|||*çm޼++%%5w/ IDATbȑ#ϟ?9bZ@&be2N=g1lV|.ΌKIT>q3G_9oG"|>$'fVu낂~¿YoB`-ryׯ{zzbǨ(I|,&#0S4RA?\XXXVVa2yyynE9O镕Xݢ[nܸۇb1 aoo~g8T @ܙup6m (*ϡNB pƍӧOvڦxZN獵|b-;R<~.\Xi:/%Lt[cKuu˗/^|] \ȧOrlvVVV~~>bqq1DfffqALO"[Ȝ͜QYb&6+,,keHO:n```ffffffmmܡC&h4~Áׯ_>{iꟉIfffBBB^ _PKZQVVfjjZXXٸqc 8(<9I#^aۡ:.&=0ʭc΍ ȍ7vq޽FF@ 򢢢&6Ҳo߾nnnu?/G.^xѢEDb;q@w:\^'u2nTde$I1vX|`InA ژ*62,3ϺJ_ ڵ6h4ss.]XXXXZZvISS͞1cƉ':4>K.7oҒ\9a„ӧO455L3J>SwNhQGo*=:uHHH@!ȟR*5.1.1oyV`S}|}}%QGz3߱FvQQQa0+..nx|Ȑ~xjmDgϞ񚚚s̉aM׵VVVV#OLٻ6OYW>͛7n^^^/_yСC[0sTǨ[UUu̘1ʊyRmwC\9Nyyyݳ`J\fi1.H^> ⣀/9k?Jv^-0muA0?zpc%9@9GwwwOLLtd4梡&`ddԿJ\$cG3_8{՛á5C 3(ʜ9sE,`ݻw7?D!3} {Q9dDK3h4]]e˖y{{+++7zGa7 /m/4T~~~H4p@LDbxxK,_H;@?[7Z=u&CjR,"x)'''| ӦMvwwoa_ fw: U?~QP(|>ZKKKSS ^JOO*,,6L&ikk _aNׯxYEE yyyV:+WX/^<[4nܸاY@hh'pFyQ ZYX$aM~﫩ݼyo"FHZPԯ܏lN=/Sȸ8-'+{!ss ֬Y3tPP#D,P.,lcx?mN%IIN.zzzO NѲ5G=s J޽{``K:"HE8D'ϴNNJ77I3ܻwOrة ~ZP۰rX\#N%-*55]n 6wܙ>aJ [&m?wر111Do5aڵ$d+sss?|ۓ'OnԿFRFA ?&gQuLZ{LLL.^(S H~W6 1f}E/wndF" @"Eٷ`lb$q߼X?`Hf{r5;v|e\\\'O?m4@߾}kI:@@ 5$$sw/lLϞ=$,\.n݌QvNII)66***]v2dȕ+W233===ۭ B KB6/sD%|BBB$?~wަ>^pBRIԉn^!u{TZСãGmh:|d*ZqbLyp0**)NJ2Of"‘N^@PRMQLq1ښzn1BILL˃O/?Қ>_|{ūW<ҸqEl.u&|jDuFyClSLNd "4id V"B,oP(sVֆ?D߁@ /O=_8{yZ\ۚi7$x@8| CAVX?2j>ʯ\3 ).8z&ǓnO6][?444''B*HlիWxi& cJ@ϊNEE*-k׮sA7o޴Oq3|ezb+ cix>_/S63L5EiN<<^2d|lA )@lBY3yn#RXԂzye<ִ322wAAA߾}cnUQ5jIMY rGRC|eďKMM\PwdښH$޽{722YON/4TWWa͝C Hܙ$}K8䕈)lHk:t'Olll$W٥_,qJ\]Y&:r<'n`h7FRQQ!MEoIYn݊Yl|\A AR[ Tojn%IV!Q]ד݌J­+훈z}ºz OpoV;/dz,)ݓR[l=;{&6yF9@MB} aA@cB8֬ԙVF D"OjZUz YCZZڼyƎȹGӔٳҥKkhF}^H"FjZ͛7ؚ{yyi{ss%(#҅^47s4ANٽ-.jQSCvv 5tم  {իӧO=!U8Q@)YdjZH$///,éx g64Օk?~xN֬YSVVۺu+|&A uXMI鈦vGe¦/Ω>P>ܵ cJĻSZѣGƍi/11GAAAn%%%޽Wz=2E$i[Ĭx񢺺:|$A e[7@ QCҲ+1/]ߺS9xөF+ݔ~3|o3b0鲳;}6oa_ HByfРAgϖƼџ+у2qD#:fx.''W^G\3kkk4B@ ?M7RsVWs Txxr6o 8faj¥SgHvxR17 DE"1BE=xŋcƌuqqhͥDGGX,gϞ~?s ^ƗңGgϞIZ366"?MyN\.g._Z]]wW`!_\>Y՝,{x-ֆM֭ٳguuuk˦M0kVVV >|qso?tA'۷ЦcF,?(6%%׷ި4͡[cHa7N,<|\wF;ًC y5ɶ 1)}={>} _S^^tҎ;:99m޼955Yc@].呲e#;[陙>ydUUU&ΪÇ555:dMV 'O[9t(-_8KԐ55C~o|IIIK,ڵ^;O=`׌73ȧ@ HLL7o߉'$} ªUN灴b]C ?.!Wny* +$ |-s Z;͐+3tQc?꿍S7BVV ٲeKiiiC333MܣG999:upp0tXQ^gcӍ7?z(111999;;גcu[{رÇGwԿg@ FbGKpAfviVRLM26b-קe=,22֭5k։'"""^zՈV>|ÒBӭ[7'''Ç_p!99A(PX\aaׯ=z%Ɏ͆0441bau? Q[:vZO)I^tNֺQU6ӏ;Z CHΖl--7oDEEEFFC AO>}ur#F?fxeeeMcP RT ;W{ >6JrQJ*^DigOߤO=~~3 I$vԑm6wwpQldOfaaad0 SVV}{6@@ ~hq1 8(#exG/brWMfdtk 4H$"dk̬YUc'dՊv]^^(ަfffZZZ$ >?MNP Bř{=ۉ gw7 ݆rrrjjjX--3f9s۷fU{5SQQ{ݻw///_v- 77wÆ T*>2Y {[OoZM]ZQ!`|~- 0A%DQv=n:wСCǍ_N&Nx]~~~޽X ~\\t UdeeeG Ař?Mّ7/hY5_YFMnzU|DDׯW^}%;w)yBbbb\.4ڿ)))r!Z N(ӦN&?eTn;^BmѢEdD鶀J8h IDATE]:tBE9;ê&L?,cR' -qEb)ls5kyۣݻ'yIccxx's/.WhZ%M"Q1e>2=sL#;-Z #Zb@:z6@ DD_8P`#U\כii)V G~)>Glѣ7oW(++;x |dA 6%_@@˗#""|RkA&MH clll#@@ )=5PUnv9..Ν;u:;;cjzjT߾}1.((S@A GvdyFҚ{\Zpx.] ,Ĭ46bcc}t:}ȑXyÆ X^H? 0<iKCaVzڵ+Vxq |yihh<}t̘1 K+zyB^^^DD|ڛa_P3&&&Xb'O%%%1Lٳg_I{{{|ixڛ} C`C  8ҲJj%gRSS&N+Tؽ{7IGxڛu++ @hD/ҪTaN8c)u߶mBQUU韼<^@ 6BQQ/ٳg˖-Ǽ̙3͛7H9 @~D"BUPD" .`'m1-@G DfxA${\V}1W߿(@?S)(㱸*BR3f|ڵkׯ8p1PVVزe L e_ffUWeUVt+4i޽{gϞ]u`&&&C 7Tx666:::;wvpp000hA BiӦ_|_~aaaӧOԔ7n`Q}||t_+fWH]._{ҥGRo߾{n@044ttt|u, o9ky+ֿjˀ;L _UUo``\kfffΞ=[6lb&ѵYxmP)W___,Ǐ߳gOPPvXRXݶVVE"H*aɆ|> t #D:z(|0~>͛2l0EEł|,D:@`2bnee ---uJČ .]HEccc9B fΜSN͚5 Ox _KicHJmXرcUUU&. ãG{ eee`ggW~-h DӧO%|6~2?ݰZ$´Gݽ{իW>}{˛ZΝzA#럞^XXr\vM2mˈ&;vصkWhrp);;;+((ӧTx9//'J Dq/nv׷6~##wǎ7'qmݺSL177o'duu@@`x(V(*77'OZ)]wk+DRGE͉݇=zѣ|0@$W\S(WزeK^^ܹsGWWVo U,ib/og,,,%ȯ@y2B9 TTT["֘fsha3"ײÝ[ݻ;;;7CPLMM-@6~hsXeeL =3Ųcs >{azn|}}Zpʙ3g^CCUVVLMM@>~v6>ĨW1*B9*U7k( H<{,> J0>P2uA$""i˱BC#_"Q=emMo:" gH{?СCeRv(--ߺ7ҥK_~ŭ@i$ *J_.kj~2 !FP( F2TZwvjնVR_\n@ehA@6H#p5(ܑ~y8st}&++kWD/)ilkf׬Y{^zu3~z"jEEE+V嬬ZT9NV2x1Rk7K *dH {RhĉM6effݚl2BbZZtt9ـ.s A>_bŇ:2ȰWv.60ev;/O>-#T*{{w>|x~zZ|!]v0Μ9iӦ9sQY%y#*{2LvMāY34lҝZ v9oU*k !Fѕ5CBL:}FGaX۷o4hPzzƌbŊnȐ!Z^^^N9bllLиRyLQ3$l25?-33O>7iK)WK7ojpJ|fyԼ[lggnذ pĈgΜ?>=^ Ө(*t73$a1G,]e 6d%5'[6bof9K߾}if';x{{#酅-Y?HHH(O>~~~ݺucS4m8H=GVUB%̦޷L+!.8m0!3gΜ5kϯeڔ1sر#=D>?hkO?68WÜ} 系 m̿~bײV^^^~~~{Z[[ :bjAp)Y'np?T^{h'-Zҋl6o@@fLvpV$֋El |,M+tes>p݌ǚYC=͸qO:rP(|[TZ~ڿU8-ȿ,@ XJsYt)!Z~qƣЅ [9jE Im#.Z(::BTWW9؏o z8!ȿ255=|KB <}fRJRn'߳YF&8*% a} mVrr2]C@{ɿBP(tttD@Kvy-ӗYSl8t!dذa\.cq_j;z֭{?SRn]J:=hF͵h5b cǢpw77z磻T_\=eVO+NoD- ǭ[f̘Aرchh(G(j⎅_PH$NvbgEh5֯_?d___D._<~2.?|T9<9 Gn=s>9jZZ[\?NV/~[<6Zhׯo޼y„ Ry||RY_={=zyyyl6;,,Lsn&F)JZ9CӉſO5Jq9Fv$-<}r S{ٴjzŊ}yy9Y*ZXX)촴d{ m۶Mγk><34D`Ȍ3s37i~h9ٳg׮]111ifbb2eʔ>5 ϗS 5=g T+ w2K*KV>UMT)"RnU+RCH!:ޙ᝘u{NYrBe9Qȿ'TTTDFFƦ( Bunz1p@WWW:qB#WˮwVSjohn{h"sf2O[vUfBc6 Xx9g4QŽ% !EY^_'8N;L|LLmsmL}& ݇BU62筱2s|ZYH9ʎf;'$j*8k !F"t3 X,UkcecqJ2BDd&Ԙ;I(ΉL\qQvP) !JJƐVt)>3q"= kh:1箫UWTE9&bzc}CKz(*fBc6%G3;Buwca\Rޔ_^x䟳:u3T_oQA Q@nE%,rh'ݡ !<o?,`~9\Y‪Au((i4lѕyBo% (60]᷸}XBŚ5aD!p>CFI֚}g1G9[BV}0dF,Sl`jՕ8Q ;َ:r5#M"YY8u]EzFN8EH-|buwb5͞3]ş>{ٛZu>=mE+/O۞tEXV]uN|~.GyP!:783_ԏ,6 s[~:lNwi'_x>%ësJ5"=ᨮ̈́Iy)*!iX,4Fj\h˿@uQ/lb?ˀo?2ʪjBJ+/W-nNv_Z8,߹++Ot'>X>aMoVVzk5;tar)OVGoq)*,:펫4Wq|&.4yzL^q76?hA%IF^I~Fmc7?Oyoۺ]2݉ҋQ)!\NTJ6Esӥԫyty+];ިĹ٥yl'@Kq=]!%`f3wD߈zUW4С R€,Ev~-'PAPBҋ2rMjl^? B==ZJa:V٣K%eXY ~W2e;S+1' y<xo‹ERS*]ITfh%&1e)d+xJM14e+'nGE޻tl}{>}\=fRyEZMӱ`nn.+,"YI[c\-+ݷzsŞЄ*k !r3 :PMBI-5IG}^sJ[MOiIeoj0~mT샄NhD !L@]HW 7a÷nMo O^l+ BHD]-Ӝ9.3!7 RתJ8]ZSNGȝ_˓?vpҩ~=뻊T%9wSf$^WwiK#[}N3Xzn4+oow\uVsUcn&]H-t5gK9lnZ1SYYY峗SF4,q*5eseUŲBJw4Y8x뮣x.@a\~y!!mcleg9ӿ؞v~ysuC1!DRUʪJdqEYEXI! 9rЉ!׉ߦe]Godܚ[V[Vq8l.&ه~iR>VBȵ~~lb&;S+[׸BH\FBH$JaezH. RRB䊚)\lbksS/..Ãٔ*?J'D"ZVB=Ly*Ӛ vWZ6ѫ R~9o}:bA 9K: \>>Vgy#K)L6 ?!xo, IDAT# PrUCe#*]^TyG?,c? :E4N&3"%xxI;i^ϬKRn?8&|&}wes6_;跒Ū/35oe C{[w1+jK/>HМDb X2s`wm*Jσ\.oW_Ç===TpBVVVUUخ&%% 6B$ӧO>mi E''<9SEEEttttt4!ḺN6Gj5h%%%ǎ\)R (,,\hсfO~Vd,J>ݺumTTUU]vmܸqeeeyyyu 8z(j|[yy̙3FI;v 8p̘1*aر?VƍϴK˿={xxxЩrJ-uƬlR4'~9sK4ZYYOR^^L޽[,KR Db`` LMM x155555511"=U#??|'̚siMT=zt֭w^skm!ĉiii2}bccmmmqZJJJrCQTIIIQQQIIIeeeiiiNNL&+((033g/R)ĐBݻ$?~Μ9̜M6l]~``ݻw !k׮tiͻZ:t }7ZG+z[bX&|;;;BeFFFʛ7oZZZj~l]Yi``P>2df5%%UT43l||<]HJJJLLLMMeZ#Gd^umrѣ5[ha4gCjjoTT2"6@[hh{b\\\6nLь8tT f|FFF,kժUŋ>|I ϺCgee1koN?$C(|>T*D !^mmfk߿6pʊuҤIioԴ@Ӆ9s4zp8iӖ,YzĢ"fk݁c궅֭[w.]Zzudddpp榴={0|>X %&&ֺÇ3DF444011i˗/_bxi~+@KLG7rUUUkڵk!~/^dʦLw UJMMurrb<==}||lmmlnn3EQ999oo+W4z|oofQ" >>/^_oEEEݽ{,P,.Xͭ@;u@fٳ7zKMMMvv֓5?hq׮]% fϞ\#Z(<?@ ?@ ?K1;2IENDB`sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/pendulum_nonmin.svg000066400000000000000000000544571412543434000301300ustar00rootroot00000000000000 image/svg+xml L m g q1 q2 u1 u2 Nx Ny Ax Ay sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/rollingdisc.svg000066400000000000000000000224241412543434000272170ustar00rootroot00000000000000 image/svg+xml R N nz nx ny rx ry rz sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/rollingdisc_example.rst000066400000000000000000000010141412543434000307330ustar00rootroot00000000000000============== A rolling disc ============== The disc is assumed to be infinitely thin, in contact with the ground at only 1 point, and it is rolling without slip on the ground. See the image below. .. image:: rollingdisc.* :height: 350 :width: 350 :align: center We model the rolling disc in three different ways, to show more of the functionality of this module. .. toctree:: :maxdepth: 1 rollingdisc_example_kane.rst rollingdisc_example_kane_constraints.rst rollingdisc_example_lagrange.rst sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/rollingdisc_example_kane.rst000066400000000000000000000070351412543434000317420ustar00rootroot00000000000000================================== A rolling disc, with Kane's method ================================== Here the definition of the rolling disc's kinematics is formed from the contact point up, removing the need to introduce generalized speeds. Only 3 configuration and three speed variables are need to describe this system, along with the disc's mass and radius, and the local gravity (note that mass will drop out). :: >>> from sympy import symbols, sin, cos, tan >>> from sympy.physics.mechanics import * >>> q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') >>> q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) >>> r, m, g = symbols('r m g') >>> mechanics_printing(pretty_print=False) The kinematics are formed by a series of simple rotations. Each simple rotation creates a new frame, and the next rotation is defined by the new frame's basis vectors. This example uses a 3-1-2 series of rotations, or Z, X, Y series of rotations. Angular velocity for this is defined using the second frame's basis (the lean frame); it is for this reason that we defined intermediate frames, rather than using a body-three orientation. :: >>> N = ReferenceFrame('N') >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) >>> R = L.orientnew('R', 'Axis', [q3, L.y]) >>> w_R_N_qd = R.ang_vel_in(N) >>> R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) This is the translational kinematics. We create a point with no velocity in N; this is the contact point between the disc and ground. Next we form the position vector from the contact point to the disc's center of mass. Finally we form the velocity and acceleration of the disc. :: >>> C = Point('C') >>> C.set_vel(N, 0) >>> Dmc = C.locatenew('Dmc', r * L.z) >>> Dmc.v2pt_theory(C, N, R) r*u2*L.x - r*u1*L.y This is a simple way to form the inertia dyadic. The inertia of the disc does not change within the lean frame as the disc rolls; this will make for simpler equations in the end. :: >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) >>> mprint(I) m*r**2/4*(L.x|L.x) + m*r**2/2*(L.y|L.y) + m*r**2/4*(L.z|L.z) Kinematic differential equations; how the generalized coordinate time derivatives relate to generalized speeds. :: >>> kd = [dot(R.ang_vel_in(N) - w_R_N_qd, uv) for uv in L] Creation of the force list; it is the gravitational force at the center of mass of the disc. Then we create the disc by assigning a Point to the center of mass attribute, a ReferenceFrame to the frame attribute, and mass and inertia. Then we form the body list. :: >>> ForceList = [(Dmc, - m * g * Y.z)] >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) >>> BodyList = [BodyD] Finally we form the equations of motion, using the same steps we did before. Specify inertial frame, supply generalized coordinates and speeds, supply kinematic differential equation dictionary, compute Fr from the force list and Fr* from the body list, compute the mass matrix and forcing terms, then solve for the u dots (time derivatives of the generalized speeds). :: >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd) >>> (fr, frstar) = KM.kanes_equations(BodyList, ForceList) >>> MM = KM.mass_matrix >>> forcing = KM.forcing >>> rhs = MM.inv() * forcing >>> kdd = KM.kindiffdict() >>> rhs = rhs.subs(kdd) >>> rhs.simplify() >>> mprint(rhs) Matrix([ [(4*g*sin(q2) + 6*r*u2*u3 - r*u3**2*tan(q2))/(5*r)], [ -2*u1*u3/3], [ (-2*u2 + u3*tan(q2))*u1]]) sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/rollingdisc_example_kane_constraints.rst000066400000000000000000000064241412543434000343720ustar00rootroot00000000000000======================================================== A rolling disc, with Kane's method and constraint forces ======================================================== We will now revisit the rolling disc example, except this time we are bringing the non-contributing (constraint) forces into evidence. See [Kane1985]_ for a more thorough explanation of this. Here, we will turn on the automatic simplifcation done when doing vector operations. It makes the outputs nicer for small problems, but can cause larger vector operations to hang. :: >>> from sympy import symbols, sin, cos, tan >>> from sympy.physics.mechanics import * >>> mechanics_printing(pretty_print=False) >>> q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') >>> q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) >>> r, m, g = symbols('r m g') These two lines introduce the extra quantities needed to find the constraint forces. :: >>> u4, u5, u6, f1, f2, f3 = dynamicsymbols('u4 u5 u6 f1 f2 f3') Most of the main code is the same as before. :: >>> N = ReferenceFrame('N') >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) >>> R = L.orientnew('R', 'Axis', [q3, L.y]) >>> w_R_N_qd = R.ang_vel_in(N) >>> R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) The definition of rolling without slip necessitates that the velocity of the contact point is zero; as part of bringing the constraint forces into evidence, we have to introduce speeds at this point, which will by definition always be zero. They are normal to the ground, along the path which the disc is rolling, and along the ground in a perpendicular direction. :: >>> C = Point('C') >>> C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x) + u6 * Y.z) >>> Dmc = C.locatenew('Dmc', r * L.z) >>> vel = Dmc.v2pt_theory(C, N, R) >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) >>> kd = [dot(R.ang_vel_in(N) - w_R_N_qd, uv) for uv in L] Just as we previously introduced three speeds as part of this process, we also introduce three forces; they are in the same direction as the speeds, and represent the constraint forces in those directions. :: >>> ForceList = [(Dmc, - m * g * Y.z), (C, f1 * L.x + f2 * (Y.z ^ L.x) + f3 * Y.z)] >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) >>> BodyList = [BodyD] >>> KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd, ... u_auxiliary=[u4, u5, u6]) >>> (fr, frstar) = KM.kanes_equations(BodyList, ForceList) >>> MM = KM.mass_matrix >>> forcing = KM.forcing >>> rhs = MM.inv() * forcing >>> kdd = KM.kindiffdict() >>> rhs = rhs.subs(kdd) >>> rhs.simplify() >>> mprint(rhs) Matrix([ [(4*g*sin(q2) + 6*r*u2*u3 - r*u3**2*tan(q2))/(5*r)], [ -2*u1*u3/3], [ (-2*u2 + u3*tan(q2))*u1]]) >>> from sympy import trigsimp, signsimp, collect, factor_terms >>> def simplify_auxiliary_eqs(w): ... return signsimp(trigsimp(collect(collect(factor_terms(w), f2), m*r))) >>> mprint(KM.auxiliary_eqs.applyfunc(simplify_auxiliary_eqs)) Matrix([ [ -m*r*(u1*u3 + u2') + f1], [-m*r*u1**2*sin(q2) - m*r*u2*u3/cos(q2) + m*r*cos(q2)*u1' + f2], [ -g*m + m*r*(u1**2*cos(q2) + sin(q2)*u1') + f3]]) sympy-sympy-1.9/doc/src/modules/physics/mechanics/examples/rollingdisc_example_lagrange.rst000066400000000000000000000060031412543434000325760ustar00rootroot00000000000000====================================== A rolling disc using Lagrange's Method ====================================== Here the rolling disc is formed from the contact point up, removing the need to introduce generalized speeds. Only 3 configuration and 3 speed variables are needed to describe this system, along with the disc's mass and radius, and the local gravity. :: >>> from sympy import symbols, cos, sin >>> from sympy.physics.mechanics import * >>> mechanics_printing(pretty_print=False) >>> q1, q2, q3 = dynamicsymbols('q1 q2 q3') >>> q1d, q2d, q3d = dynamicsymbols('q1 q2 q3', 1) >>> r, m, g = symbols('r m g') The kinematics are formed by a series of simple rotations. Each simple rotation creates a new frame, and the next rotation is defined by the new frame's basis vectors. This example uses a 3-1-2 series of rotations, or Z, X, Y series of rotations. Angular velocity for this is defined using the second frame's basis (the lean frame). :: >>> N = ReferenceFrame('N') >>> Y = N.orientnew('Y', 'Axis', [q1, N.z]) >>> L = Y.orientnew('L', 'Axis', [q2, Y.x]) >>> R = L.orientnew('R', 'Axis', [q3, L.y]) This is the translational kinematics. We create a point with no velocity in N; this is the contact point between the disc and ground. Next we form the position vector from the contact point to the disc's center of mass. Finally we form the velocity and acceleration of the disc. :: >>> C = Point('C') >>> C.set_vel(N, 0) >>> Dmc = C.locatenew('Dmc', r * L.z) >>> Dmc.v2pt_theory(C, N, R) r*(sin(q2)*q1' + q3')*L.x - r*q2'*L.y Forming the inertia dyadic. :: >>> I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) >>> mprint(I) m*r**2/4*(L.x|L.x) + m*r**2/2*(L.y|L.y) + m*r**2/4*(L.z|L.z) >>> BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) We then set the potential energy and determine the Lagrangian of the rolling disc. :: >>> BodyD.potential_energy = - m * g * r * cos(q2) >>> Lag = Lagrangian(N, BodyD) Then the equations of motion are generated by initializing the ``LagrangesMethod`` object. Finally we solve for the generalized accelerations(q double dots) with the ``rhs`` method. :: >>> q = [q1, q2, q3] >>> l = LagrangesMethod(Lag, q) >>> le = l.form_lagranges_equations() >>> le.simplify(); le Matrix([ [m*r**2*(6*sin(q2)*q3'' + 5*sin(2*q2)*q1'*q2' + 6*cos(q2)*q2'*q3' - 5*cos(2*q2)*q1''/2 + 7*q1''/2)/4], [ m*r*(4*g*sin(q2) - 5*r*sin(2*q2)*q1'**2/2 - 6*r*cos(q2)*q1'*q3' + 5*r*q2'')/4], [ 3*m*r**2*(sin(q2)*q1'' + cos(q2)*q1'*q2' + q3'')/2]]) >>> lrhs = l.rhs(); lrhs.simplify(); lrhs Matrix([ [ q1'], [ q2'], [ q3'], [ -2*(2*tan(q2)*q1' + 3*q3'/cos(q2))*q2'], [-4*g*sin(q2)/(5*r) + sin(2*q2)*q1'**2/2 + 6*cos(q2)*q1'*q3'/5], [ (-5*cos(q2)*q1' + 6*tan(q2)*q3' + 4*q1'/cos(q2))*q2']]) sympy-sympy-1.9/doc/src/modules/physics/mechanics/index.rst000066400000000000000000000077131412543434000242140ustar00rootroot00000000000000.. _classical_mechanics: =================== Classical Mechanics =================== .. topic:: Abstract In this documentation many components of the physics/mechanics module will be discussed. :mod:`sympy.physics.mechanics` has been written to allow for creation of symbolic equations of motion for complicated multibody systems. .. module:: sympy.physics.mechanics Vector ====== This module derives the vector-related abilities and related functionalities from :mod:`sympy.physics.vector`. Please have a look at the documentation of :mod:`sympy.physics.vector` and its necessary API to understand the vector capabilities of :mod:`sympy.physics.mechanics`. Mechanics ========= In physics, mechanics describes conditions of rest (statics) or motion (dynamics). There are a few common steps to all mechanics problems. First, an idealized representation of a system is described. Next, we use physical laws to generate equations that define the system's behavior. Then, we solve these equations, sometimes analytically but usually numerically. Finally, we extract information from these equations and solutions. The current scope of the module is multi-body dynamics: the motion of systems of multiple particles and/or rigid bodies. For example, this module could be used to understand the motion of a double pendulum, planets, robotic manipulators, bicycles, and any other system of rigid bodies that may fascinate us. Often, the objective in multi-body dynamics is to obtain the trajectory of a system of rigid bodies through time. The challenge for this task is to first formulate the equations of motion of the system. Once they are formulated, they must be solved, that is, integrated forward in time. When digital computers came around, solving became the easy part of the problem. Now, we can tackle more complicated problems, which leaves the challenge of formulating the equations. The term "equations of motion" is used to describe the application of Newton's second law to multi-body systems. The form of the equations of motion depends on the method used to generate them. This package implements two of these methods: Kane's method and Lagrange's method. This module facilitates the formulation of equations of motion, which can then be solved (integrated) using generic ordinary differential equation (ODE) solvers. The approach to a particular class of dynamics problems, that of forward dynamics, has the following steps: 1. describing the system's geometry and configuration, 2. specifying the way the system can move, including constraints on its motion 3. describing the external forces and moments on the system, 4. combining the above information according to Newton's second law (:math:`\mathbf{F}=m\mathbf{a}`), and 5. organizing the resulting equations so that they can be integrated to obtain the system's trajectory through time. Together with the rest of SymPy, this module performs steps 4 and 5, provided that the user can perform 1 through 3 for the module. That is to say, the user must provide a complete representation of the free body diagrams that themselves represent the system, with which this code can provide equations of motion in a form amenable to numerical integration. Step 5 above amounts to arduous algebra for even fairly simple multi-body systems. Thus, it is desirable to use a symbolic math package, such as Sympy, to perform this step. It is for this reason that this module is a part of Sympy. Step 4 amounts to this specific module, sympy.physics.mechanics. Guide to Mechanics ================== .. toctree:: :maxdepth: 2 masses.rst kane.rst lagrange.rst symsystem.rst linearize.rst examples.rst advanced.rst reference.rst autolev_parser.rst sympy_mechanics_for_autolev_users.rst Mechanics API ============= .. toctree:: :maxdepth: 2 api/part_bod.rst api/kane_lagrange.rst api/system.rst api/linearize.rst api/expr_manip.rst api/printing.rst api/body.rst api/joint.rst sympy-sympy-1.9/doc/src/modules/physics/mechanics/kane.rst000066400000000000000000000142611412543434000240170ustar00rootroot00000000000000.. _kane_method: ================================== Kane's Method in Physics/Mechanics ================================== :mod:`sympy.physics.mechanics` provides functionality for deriving equations of motion using Kane's method [Kane1985]_. This document will describe Kane's method as used in this module, but not how the equations are actually derived. Structure of Equations ====================== In :mod:`sympy.physics.mechanics` we are assuming there are 5 basic sets of equations needed to describe a system. They are: holonomic constraints, non-holonomic constraints, kinematic differential equations, dynamic equations, and differentiated non-holonomic equations. .. math:: \mathbf{f_h}(q, t) &= 0\\ \mathbf{k_{nh}}(q, t) u + \mathbf{f_{nh}}(q, t) &= 0\\ \mathbf{k_{k\dot{q}}}(q, t) \dot{q} + \mathbf{k_{ku}}(q, t) u + \mathbf{f_k}(q, t) &= 0\\ \mathbf{k_d}(q, t) \dot{u} + \mathbf{f_d}(q, \dot{q}, u, t) &= 0\\ \mathbf{k_{dnh}}(q, t) \dot{u} + \mathbf{f_{dnh}}(q, \dot{q}, u, t) &= 0\\ In :mod:`sympy.physics.mechanics` holonomic constraints are only used for the linearization process; it is assumed that they will be too complicated to solve for the dependent coordinate(s). If you are able to easily solve a holonomic constraint, you should consider redefining your problem in terms of a smaller set of coordinates. Alternatively, the time-differentiated holonomic constraints can be supplied. Kane's method forms two expressions, :math:`F_r` and :math:`F_r^*`, whose sum is zero. In this module, these expressions are rearranged into the following form: :math:`\mathbf{M}(q, t) \dot{u} = \mathbf{f}(q, \dot{q}, u, t)` For a non-holonomic system with `o` total speeds and `m` motion constraints, we will get o - m equations. The mass-matrix/forcing equations are then augmented in the following fashion: .. math:: \mathbf{M}(q, t) &= \begin{bmatrix} \mathbf{k_d}(q, t) \\ \mathbf{k_{dnh}}(q, t) \end{bmatrix}\\ \mathbf{_{(forcing)}}(q, \dot{q}, u, t) &= \begin{bmatrix} - \mathbf{f_d}(q, \dot{q}, u, t) \\ - \mathbf{f_{dnh}}(q, \dot{q}, u, t) \end{bmatrix}\\ Kane's Method in Physics/Mechanics ================================== The formulation of the equations of motion in :mod:`sympy.physics.mechanics` starts with creation of a ``KanesMethod`` object. Upon initialization of the ``KanesMethod`` object, an inertial reference frame needs to be supplied. along with some basic system information, such as coordinates and speeds :: >>> from sympy.physics.mechanics import * >>> N = ReferenceFrame('N') >>> q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') >>> q1d, q2d, u1d, u2d = dynamicsymbols('q1 q2 u1 u2', 1) >>> KM = KanesMethod(N, [q1, q2], [u1, u2]) It is also important to supply the order of coordinates and speeds properly if there are dependent coordinates and speeds. They must be supplied after independent coordinates and speeds or as a keyword argument; this is shown later. :: >>> q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') >>> u1, u2, u3, u4 = dynamicsymbols('u1 u2 u3 u4') >>> # Here we will assume q2 is dependent, and u2 and u3 are dependent >>> # We need the constraint equations to enter them though >>> KM = KanesMethod(N, [q1, q3, q4], [u1, u4]) Additionally, if there are auxiliary speeds, they need to be identified here. See the examples for more information on this. In this example u4 is the auxiliary speed. :: >>> KM = KanesMethod(N, [q1, q3, q4], [u1, u2, u3], u_auxiliary=[u4]) Kinematic differential equations must also be supplied; there are to be provided as a list of expressions which are each equal to zero. A trivial example follows: :: >>> kd = [q1d - u1, q2d - u2] Turning on ``mechanics_printing()`` makes the expressions significantly shorter and is recommended. Alternatively, the ``mprint`` and ``mpprint`` commands can be used. If there are non-holonomic constraints, dependent speeds need to be specified (and so do dependent coordinates, but they only come into play when linearizing the system). The constraints need to be supplied in a list of expressions which are equal to zero, trivial motion and configuration constraints are shown below: :: >>> N = ReferenceFrame('N') >>> q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') >>> q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) >>> u1, u2, u3, u4 = dynamicsymbols('u1 u2 u3 u4') >>> #Here we will assume q2 is dependent, and u2 and u3 are dependent >>> speed_cons = [u2 - u1, u3 - u1 - u4] >>> coord_cons = [q2 - q1] >>> q_ind = [q1, q3, q4] >>> q_dep = [q2] >>> u_ind = [u1, u4] >>> u_dep = [u2, u3] >>> kd = [q1d - u1, q2d - u2, q3d - u3, q4d - u4] >>> KM = KanesMethod(N, q_ind, u_ind, kd, ... q_dependent=q_dep, ... configuration_constraints=coord_cons, ... u_dependent=u_dep, ... velocity_constraints=speed_cons) A dictionary returning the solved :math:`\dot{q}`'s can also be solved for: :: >>> mechanics_printing(pretty_print=False) >>> KM.kindiffdict() {q1': u1, q2': u2, q3': u3, q4': u4} The final step in forming the equations of motion is supplying a list of bodies and particles, and a list of 2-tuples of the form ``(Point, Vector)`` or ``(ReferenceFrame, Vector)`` to represent applied forces and torques. :: >>> N = ReferenceFrame('N') >>> q, u = dynamicsymbols('q u') >>> qd, ud = dynamicsymbols('q u', 1) >>> P = Point('P') >>> P.set_vel(N, u * N.x) >>> Pa = Particle('Pa', P, 5) >>> BL = [Pa] >>> FL = [(P, 7 * N.x)] >>> KM = KanesMethod(N, [q], [u], [qd - u]) >>> (fr, frstar) = KM.kanes_equations(BL, FL) >>> KM.mass_matrix Matrix([[5]]) >>> KM.forcing Matrix([[7]]) When there are motion constraints, the mass matrix is augmented by the :math:`k_{dnh}(q, t)` matrix, and the forcing vector by the :math:`f_{dnh}(q, \dot{q}, u, t)` vector. There are also the "full" mass matrix and "full" forcing vector terms, these include the kinematic differential equations; the mass matrix is of size (n + o) x (n + o), or square and the size of all coordinates and speeds. :: >>> KM.mass_matrix_full Matrix([ [1, 0], [0, 5]]) >>> KM.forcing_full Matrix([ [u], [7]]) Exploration of the provided examples is encouraged in order to gain more understanding of the ``KanesMethod`` object. sympy-sympy-1.9/doc/src/modules/physics/mechanics/lagrange.rst000066400000000000000000000111401412543434000246520ustar00rootroot00000000000000====================================== Lagrange's Method in Physics/Mechanics ====================================== :mod:`sympy.physics.mechanics` provides functionality for deriving equations of motion using `Lagrange's method `_. This document will describe Lagrange's method as used in this module, but not how the equations are actually derived. Structure of Equations ====================== In :mod:`sympy.physics.mechanics` we are assuming there are 3 basic sets of equations needed to describe a system; the constraint equations, the time differentiated constraint equations and the dynamic equations. .. math:: \mathbf{m_{c}}(q, t) \dot{q} + \mathbf{f_{c}}(q, t) &= 0\\ \mathbf{m_{dc}}(\dot{q}, q, t) \ddot{q} + \mathbf{f_{dc}}(\dot{q}, q, t) &= 0\\ \mathbf{m_d}(\dot{q}, q, t) \ddot{q} + \mathbf{\Lambda_c}(q, t) \lambda + \mathbf{f_d}(\dot{q}, q, t) &= 0\\ In this module, the expressions formed by using Lagrange's equations of the second kind are rearranged into the following form: :math:`\mathbf{M}(q, t) x = \mathbf{f}(q, \dot{q}, t)` where in the case of a system without constraints: :math:`x = \ddot{q}` For a constrained system with `n` generalized speeds and `m` constraints, we will get n - m equations. The mass-matrix/forcing equations are then augmented in the following fashion: .. math:: x = \begin{bmatrix} \ddot{q} \\ \lambda \end{bmatrix} \\ \mathbf{M}(q, t) &= \begin{bmatrix} \mathbf{m_d}(q, t) & \mathbf{\Lambda_c}(q, t) \end{bmatrix}\\ \mathbf{F}(\dot{q}, q, t) &= \begin{bmatrix} \mathbf{f_d}(q, \dot{q}, t) \end{bmatrix}\\ Lagrange's Method in Physics/Mechanics ====================================== The formulation of the equations of motion in :mod:`sympy.physics.mechanics` using Lagrange's Method starts with the creation of generalized coordinates and a Lagrangian. The Lagrangian can either be created with the ``Lagrangian`` function or can be a user supplied function. In this case we will supply the Lagrangian. :: >>> from sympy.physics.mechanics import * >>> q1, q2 = dynamicsymbols('q1 q2') >>> q1d, q2d = dynamicsymbols('q1 q2', 1) >>> L = q1d**2 + q2d**2 To formulate the equations of motion we create a ``LagrangesMethod`` object. The Lagrangian and generalized coordinates need to be supplied upon initialization. :: >>> LM = LagrangesMethod(L, [q1, q2]) With that the equations of motion can be formed. :: >>> mechanics_printing(pretty_print=False) >>> LM.form_lagranges_equations() Matrix([ [2*q1''], [2*q2'']]) It is possible to obtain the mass matrix and the forcing vector. :: >>> LM.mass_matrix Matrix([ [2, 0], [0, 2]]) >>> LM.forcing Matrix([ [0], [0]]) If there are any holonomic or non-holonomic constraints, they must be supplied as keyword arguments (``hol_coneqs`` and ``nonhol_coneqs`` respectively) in a list of expressions which are equal to zero. Modifying the example above, the equations of motion can then be generated: :: >>> LM = LagrangesMethod(L, [q1, q2], hol_coneqs=[q1 - q2]) When the equations of motion are generated in this case, the Lagrange multipliers are introduced; they are represented by ``lam1`` in this case. In general, there will be as many multipliers as there are constraint equations. :: >>> LM.form_lagranges_equations() Matrix([ [ lam1 + 2*q1''], [-lam1 + 2*q2'']]) Also in the case of systems with constraints, the 'full' mass matrix is augmented by the :math:`k_{dc}(q, t)` matrix, and the forcing vector by the :math:`f_{dc}(q, \dot{q}, t)` vector. The 'full' mass matrix is of size (2n + o) x (2n + o), i.e. it's a square matrix. :: >>> LM.mass_matrix_full Matrix([ [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 2, 0, -1], [0, 0, 0, 2, 1], [0, 0, 1, -1, 0]]) >>> LM.forcing_full Matrix([ [q1'], [q2'], [ 0], [ 0], [ 0]]) If there are any non-conservative forces or moments acting on the system, they must also be supplied as keyword arguments in a list of 2-tuples of the form ``(Point, Vector)`` or ``(ReferenceFrame, Vector)`` where the ``Vector`` represents the non-conservative forces and torques. Along with this 2-tuple, the inertial frame must also be specified as a keyword argument. This is shown below by modifying the example above: :: >>> N = ReferenceFrame('N') >>> P = Point('P') >>> P.set_vel(N, q1d * N.x) >>> FL = [(P, 7 * N.x)] >>> LM = LagrangesMethod(L, [q1, q2], forcelist=FL, frame=N) >>> LM.form_lagranges_equations() Matrix([ [2*q1'' - 7], [ 2*q2'']]) Exploration of the provided examples is encouraged in order to gain more understanding of the ``LagrangesMethod`` object. sympy-sympy-1.9/doc/src/modules/physics/mechanics/linearize.rst000066400000000000000000000325371412543434000250710ustar00rootroot00000000000000================================== Linearization in Physics/Mechanics ================================== :mod:`sympy.physics.mechanics` includes methods for linearizing the generated equations of motion (EOM) about an operating point (also known as the trim condition). Note that this operating point doesn't have to be an equilibrium position, it just needs to satisfy the equations of motion. Linearization is accomplished by taking the first order Taylor expansion of the EOM about the operating point. When there are no dependent coordinates or speeds this is simply the jacobian of the right hand side about `q` and `u`. However, in the presence of constraints more care needs to be taken. The linearization methods provided here handle these constraints correctly. Background ========== In :mod:`sympy.physics.mechanics` we assume all systems can be represented in the following general form: .. math:: f_{c}(q, t) &= 0_{l \times 1}\\ f_{v}(q, u, t) &= 0_{m \times 1}\\ f_{a}(q, \dot{q}, u, \dot{u}, t) &= 0_{m \times 1}\\ f_{0}(q, \dot{q}, t) + f_{1}(q, u, t) &= 0_{n \times 1}\\ f_{2}(q, u, \dot{u}, t) + f_{3}(q, \dot{q}, u, r, t) + f_{4}(q, \lambda, t) &= 0_{(o-m+k) \times 1} where .. math:: q, \dot{q} & \in \mathbb{R}^n\\ u, \dot{u} & \in \mathbb{R}^o\\ r & \in \mathbb{R}^s\\ \lambda & \in \mathbb{R}^k In this form, - :math:`f_{c}` represents the configuration constraint equations - :math:`f_{v}` represents the velocity constraint equations - :math:`f_{a}` represents the acceleration constraint equations - :math:`f_{0}` and :math:`f_{1}` form the kinematic differential equations - :math:`f_{2}`, :math:`f_{3}`, and :math:`f_{4}` form the dynamic differential equations - :math:`q` and :math:`\dot{q}` are the generalized coordinates and their derivatives - :math:`u` and :math:`\dot{u}` are the generalized speeds and their derivatives - :math:`r` is the system inputs - :math:`\lambda` is the Lagrange multipliers This generalized form is held inside the ``Linearizer`` class, which performs the actual linearization. Both ``KanesMethod`` and ``LagrangesMethod`` objects have methods for forming the linearizer using the ``to_linearizer`` class method. .. topic:: A Note on Dependent Coordinates and Speeds If the system being linearized contains constraint equations, this results in not all generalized coordinates being independent (i.e. `q_1` may depend on `q_2`). With `l` configuration constraints, and `m` velocity constraints, there are `l` dependent coordinates and `m` dependent speeds. In general, you may pick any of the coordinates and speeds to be dependent, but in practice some choices may result in undesirable singularites. Methods for deciding which coordinates/speeds to make dependent is behind the scope of this guide. For more information, please see [Blajer1994]_. Once the system is coerced into the generalized form, the linearized EOM can be solved for. The methods provided in :mod:`sympy.physics.mechanics` allow for two different forms of the linearized EOM: `M`, `A`, and `B` In this form, the forcing matrix is linearized into two separate matrices `A` and `B`. This is the default form of the linearized EOM. The resulting equations are: .. math:: M \begin{bmatrix} \delta \dot{q} \\ \delta \dot{u} \\ \delta \lambda \end{bmatrix} = A \begin{bmatrix} \delta q_i \\ \delta u_i \end{bmatrix} + B \begin{bmatrix} \delta r \end{bmatrix} where .. math:: M &\in \mathbb{R}^{(n+o+k) \times (n+o+k)}\\ A &\in \mathbb{R}^{(n+o+k) \times (n-l+o-m)}\\ B &\in \mathbb{R}^{(n+o+k) \times s} Note that `q_i` and `u_i` are just the independent coordinates and speeds, while `q` and `u` contains both the independent and dependent coordinates and speeds. `A` and `B` In this form, the linearized EOM are brought into explicit first order form, in terms of just the independent coordinates and speeds. This form is often used in stability analysis or control theory. The resulting equations are: .. math:: \begin{bmatrix} \delta \dot{q_i} \\ \delta \dot{u_i} \end{bmatrix} = A \begin{bmatrix} \delta q_i \\ \delta u_i \end{bmatrix} + B \begin{bmatrix} \delta r \end{bmatrix} where .. math:: A &\in \mathbb{R}^{(n-l+o-m) \times (n-l+o-m)}\\ B &\in \mathbb{R}^{(n-l+o-m) \times s} To use this form set ``A_and_B=True`` in the ``linearize`` class method. Linearizing Kane's Equations ============================ After initializing the ``KanesMethod`` object and forming `F_r` and `F_r^*` using the ``kanes_equations`` class method, linearization can be accomplished in a couple ways. The different methods will be demonstrated with a simple pendulum system: :: >>> from sympy import symbols, Matrix >>> from sympy.physics.mechanics import * >>> q1 = dynamicsymbols('q1') # Angle of pendulum >>> u1 = dynamicsymbols('u1') # Angular velocity >>> q1d = dynamicsymbols('q1', 1) >>> L, m, t, g = symbols('L, m, t, g') >>> # Compose world frame >>> N = ReferenceFrame('N') >>> pN = Point('N*') >>> pN.set_vel(N, 0) >>> # A.x is along the pendulum >>> A = N.orientnew('A', 'axis', [q1, N.z]) >>> A.set_ang_vel(N, u1*N.z) >>> # Locate point P relative to the origin N* >>> P = pN.locatenew('P', L*A.x) >>> vel_P = P.v2pt_theory(pN, N, A) >>> pP = Particle('pP', P, m) >>> # Create Kinematic Differential Equations >>> kde = Matrix([q1d - u1]) >>> # Input the force resultant at P >>> R = m*g*N.x >>> # Solve for eom with kanes method >>> KM = KanesMethod(N, q_ind=[q1], u_ind=[u1], kd_eqs=kde) >>> fr, frstar = KM.kanes_equations([pP], [(P, R)]) 1. Using the ``Linearizer`` class directly: ------------------------------------------- A linearizer object can be created using the ``to_linearizer`` class method. This coerces the representation found in the ``KanesMethod`` object into the generalized form described above. As the independent and dependent coordinates and speeds are specified upon creation of the KanesMethod object, there is no need to specify them here. :: >>> linearizer = KM.to_linearizer() The linearized EOM can then be formed with the ``linearize`` method of the ``Linearizer`` object: :: >>> M, A, B = linearizer.linearize() >>> M Matrix([ [1, 0], [0, -L**2*m]]) >>> A Matrix([ [ 0, 1], [L*g*m*cos(q1(t)), 0]]) >>> B Matrix(0, 0, []) Alternatively, the `A` and `B` form can be generated instead by specifying ``A_and_B=True``: :: >>> A, B = linearizer.linearize(A_and_B=True) >>> A Matrix([ [ 0, 1], [-g*cos(q1(t))/L, 0]]) >>> B Matrix(0, 0, []) An operating point can also be specified as a dictionary or an iterable of dictionaries. This will evaluate the linearized form at the specified point before returning the matrices: :: >>> op_point = {q1: 0, u1: 0} >>> A_op, B_op = linearizer.linearize(A_and_B=True, op_point=op_point) >>> A_op Matrix([ [ 0, 1], [-g/L, 0]]) Note that the same effect can be had by applying ``msubs`` to the matrices generated without the ``op_point`` kwarg: :: >>> assert msubs(A, op_point) == A_op Sometimes the returned matrices may not be in the most simplified form. Simplification can be performed after the fact, or the ``Linearizer`` object can be made to perform simplification internally by setting the ``simplify`` kwarg to ``True``. 2. Using the ``linearize`` class method: ---------------------------------------- The ``linearize`` method of the ``KanesMethod`` class is provided as a nice wrapper that calls ``to_linearizer`` internally, performs the linearization, and returns the result. Note that all the kwargs available in the ``linearize`` method described above are also available here: :: >>> A, B, inp_vec = KM.linearize(A_and_B=True, op_point=op_point, new_method=True) >>> A Matrix([ [ 0, 1], [-g/L, 0]]) The additional output ``inp_vec`` is a vector containing all found ``dynamicsymbols`` not included in the generalized coordinate or speed vectors. These are assumed to be inputs to the system, forming the `r` vector described in the background above. In this example there are no inputs, so the vector is empty: :: >>> inp_vec Matrix(0, 0, []) .. topic:: What's with the ``new_method`` kwarg? Previous releases of SymPy contained a linearization method for `KanesMethod`` objects. This method is deprecated, and will be removed from future releases. Until then, you must set ``new_method=True`` in all calls to ``KanesMethod.linearize``. After the old method is removed, this kwarg will no longer be needed. Linearizing Lagrange's Equations ================================ Linearization of Lagrange's equations proceeds much the same as that of Kane's equations. As before, the process will be demonstrated with a simple pendulum system: :: >>> # Redefine A and P in terms of q1d, not u1 >>> A = N.orientnew('A', 'axis', [q1, N.z]) >>> A.set_ang_vel(N, q1d*N.z) >>> P = pN.locatenew('P', L*A.x) >>> vel_P = P.v2pt_theory(pN, N, A) >>> pP = Particle('pP', P, m) >>> # Solve for eom with Lagrange's method >>> Lag = Lagrangian(N, pP) >>> LM = LagrangesMethod(Lag, [q1], forcelist=[(P, R)], frame=N) >>> lag_eqs = LM.form_lagranges_equations() 1. Using the ``Linearizer`` class directly: ------------------------------------------- A ``Linearizer`` object can be formed from a ``LagrangesMethod`` object using the ``to_linearizer`` class method. The only difference between this process and that of the ``KanesMethod`` class is that the ``LagrangesMethod`` object doesn't already have its independent and dependent coordinates and speeds specified internally. These must be specified in the call to ``to_linearizer``. In this example there are no dependent coordinates and speeds, but if there were they would be included in the ``q_dep`` and ``qd_dep`` kwargs: :: >>> linearizer = LM.to_linearizer(q_ind=[q1], qd_ind=[q1d]) Once in this form, everything is the same as it was before with the ``KanesMethod`` example: :: >>> A, B = linearizer.linearize(A_and_B=True, op_point=op_point) >>> A Matrix([ [ 0, 1], [-g/L, 0]]) 2. Using the ``linearize`` class method: ---------------------------------------- Similar to ``KanesMethod``, the ``LagrangesMethod`` class also provides a ``linearize`` method as a nice wrapper that calls ``to_linearizer`` internally, performs the linearization, and returns the result. As before, the only difference is that the independent and dependent coordinates and speeds must be specified in the call as well: :: >>> A, B, inp_vec = LM.linearize(q_ind=[q1], qd_ind=[q1d], A_and_B=True, op_point=op_point) >>> A Matrix([ [ 0, 1], [-g/L, 0]]) Potential Issues ================ While the ``Linearizer`` class *should* be able to linearize all systems, there are some potential issues that could occur. These are discussed below, along with some troubleshooting tips for solving them. 1. Symbolic linearization with ``A_and_B=True`` is slow ------------------------------------------------------- This could be due to a number of things, but the most likely one is that solving a large linear system symbolically is an expensive operation. Specifying an operating point will reduce the expression size and speed this up. If a purely symbolic solution is desired though (for application of many operating points at a later period, for example) a way to get around this is to evaluate with ``A_and_B=False``, and then solve manually after applying the operating point: :: >>> M, A, B = linearizer.linearize() >>> M_op = msubs(M, op_point) >>> A_op = msubs(A, op_point) >>> perm_mat = linearizer.perm_mat >>> A_lin = perm_mat.T * M_op.LUsolve(A_op) >>> A_lin Matrix([ [ 0, 1], [-g/L, 0]]) The fewer symbols in ``A`` and ``M`` before solving, the faster this solution will be. Thus, for large expressions, it may be to your benefit to delay conversion to the `A` and `B` form until most symbols are subbed in for their numeric values. 2. The linearized form has ``nan``, ``zoo``, or ``oo`` as matrix elements ------------------------------------------------------------------------- There are two potential causes for this. The first (and the one you should check first) is that some choices of dependent coordinates will result in singularities at certain operating points. Coordinate partitioning in a systemic manner to avoid this is beyond the scope of this guide; see [Blajer1994]_ for more information. The other potential cause for this is that the matrices may not have been in the most reduced form before the operating point was substituted in. A simple example of this behavior is: :: >>> from sympy import sin, tan >>> expr = sin(q1)/tan(q1) >>> op_point = {q1: 0} >>> expr.subs(op_point) nan Note that if this expression was simplified before substitution, the correct value results: :: >>> expr.simplify().subs(op_point) 1 A good way of avoiding this hasn't been found yet. For expressions of reasonable size, using ``msubs`` with ``smart=True`` will apply an algorithm that tries to avoid these conditions. For large expressions though this is extremely time consuming. :: >>> msubs(expr, op_point, smart=True) 1 Further Examples ================ The pendulum example used above was simple, but didn't include any dependent coordinates or speeds. For a more thorough example, the same pendulum was linearized with dependent coordinates using both Kane's and Lagrange's methods: .. toctree:: examples/lin_pend_nonmin_example.rst sympy-sympy-1.9/doc/src/modules/physics/mechanics/masses.rst000066400000000000000000000330001412543434000243640ustar00rootroot00000000000000.. _masses: ================================================================= Masses, Inertias, Particles and Rigid Bodies in Physics/Mechanics ================================================================= This document will describe how to represent masses and inertias in :mod:`sympy.physics.mechanics` and use of the ``RigidBody`` and ``Particle`` classes. It is assumed that the reader is familiar with the basics of these topics, such as finding the center of mass for a system of particles, how to manipulate an inertia tensor, and the definition of a particle and rigid body. Any advanced dynamics text can provide a reference for these details. Mass ==== The only requirement for a mass is that it needs to be a ``sympify``-able expression. Keep in mind that masses can be time varying. Particle ======== Particles are created with the class ``Particle`` in :mod:`sympy.physics.mechanics`. A ``Particle`` object has an associated point and an associated mass which are the only two attributes of the object.:: >>> from sympy.physics.mechanics import Particle, Point >>> from sympy import Symbol >>> m = Symbol('m') >>> po = Point('po') >>> # create a particle container >>> pa = Particle('pa', po, m) The associated point contains the position, velocity and acceleration of the particle. :mod:`sympy.physics.mechanics` allows one to perform kinematic analysis of points separate from their association with masses. Inertia ======= See the Inertia (Dyadics) section in 'Advanced Topics' part of :mod:`sympy.physics.vector` docs. Rigid Body ========== Rigid bodies are created in a similar fashion as particles. The ``RigidBody`` class generates objects with four attributes: mass, center of mass, a reference frame, and an inertia tuple:: >>> from sympy import Symbol >>> from sympy.physics.mechanics import ReferenceFrame, Point, RigidBody >>> from sympy.physics.mechanics import outer >>> m = Symbol('m') >>> A = ReferenceFrame('A') >>> P = Point('P') >>> I = outer(A.x, A.x) >>> # create a rigid body >>> B = RigidBody('B', P, A, m, (I, P)) The mass is specified exactly as is in a particle. Similar to the ``Particle``'s ``.point``, the ``RigidBody``'s center of mass, ``.masscenter`` must be specified. The reference frame is stored in an analogous fashion and holds information about the body's orientation and angular velocity. Finally, the inertia for a rigid body needs to be specified about a point. In :mod:`sympy.physics.mechanics`, you are allowed to specify any point for this. The most common is the center of mass, as shown in the above code. If a point is selected which is not the center of mass, ensure that the position between the point and the center of mass has been defined. The inertia is specified as a tuple of length two with the first entry being a ``Dyadic`` and the second entry being a ``Point`` of which the inertia dyadic is defined about. .. _Dyadic: Dyadic ====== In :mod:`sympy.physics.mechanics`, dyadics are used to represent inertia ([Kane1985]_, [WikiDyadics]_, [WikiDyadicProducts]_). A dyadic is a linear polynomial of component unit dyadics, similar to a vector being a linear polynomial of component unit vectors. A dyadic is the outer product between two vectors which returns a new quantity representing the juxtaposition of these two vectors. For example: .. math:: \mathbf{\hat{a}_x} \otimes \mathbf{\hat{a}_x} &= \mathbf{\hat{a}_x} \mathbf{\hat{a}_x}\\ \mathbf{\hat{a}_x} \otimes \mathbf{\hat{a}_y} &= \mathbf{\hat{a}_x} \mathbf{\hat{a}_y}\\ Where :math:`\mathbf{\hat{a}_x}\mathbf{\hat{a}_x}` and `\mathbf{\hat{a}_x}\mathbf{\hat{a}_y}` are the outer products obtained by multiplying the left side as a column vector by the right side as a row vector. Note that the order is significant. Some additional properties of a dyadic are: .. math:: (x \mathbf{v}) \otimes \mathbf{w} &= \mathbf{v} \otimes (x \mathbf{w}) = x (\mathbf{v} \otimes \mathbf{w})\\ \mathbf{v} \otimes (\mathbf{w} + \mathbf{u}) &= \mathbf{v} \otimes \mathbf{w} + \mathbf{v} \otimes \mathbf{u}\\ (\mathbf{v} + \mathbf{w}) \otimes \mathbf{u} &= \mathbf{v} \otimes \mathbf{u} + \mathbf{w} \otimes \mathbf{u}\\ A vector in a reference frame can be represented as :math:`\begin{bmatrix}a\\b\\c\end{bmatrix}` or :math:`a \mathbf{\hat{i}} + b \mathbf{\hat{j}} + c \mathbf{\hat{k}}`. Similarly, a dyadic can be represented in tensor form: .. math:: \begin{bmatrix} a_{11} & a_{12} & a_{13} \\ a_{21} & a_{22} & a_{23} \\ a_{31} & a_{32} & a_{33} \end{bmatrix}\\ or in dyadic form: .. math:: a_{11} \mathbf{\hat{a}_x}\mathbf{\hat{a}_x} + a_{12} \mathbf{\hat{a}_x}\mathbf{\hat{a}_y} + a_{13} \mathbf{\hat{a}_x}\mathbf{\hat{a}_z} + a_{21} \mathbf{\hat{a}_y}\mathbf{\hat{a}_x} + a_{22} \mathbf{\hat{a}_y}\mathbf{\hat{a}_y} + a_{23} \mathbf{\hat{a}_y}\mathbf{\hat{a}_z} + a_{31} \mathbf{\hat{a}_z}\mathbf{\hat{a}_x} + a_{32} \mathbf{\hat{a}_z}\mathbf{\hat{a}_y} + a_{33} \mathbf{\hat{a}_z}\mathbf{\hat{a}_z}\\ Just as with vectors, the later representation makes it possible to keep track of which frames the dyadic is defined with respect to. Also, the two components of each term in the dyadic need not be in the same frame. The following is valid: .. math:: \mathbf{\hat{a}_x} \otimes \mathbf{\hat{b}_y} = \mathbf{\hat{a}_x} \mathbf{\hat{b}_y} Dyadics can also be crossed and dotted with vectors; again, order matters: .. math:: \mathbf{\hat{a}_x}\mathbf{\hat{a}_x} \cdot \mathbf{\hat{a}_x} &= \mathbf{\hat{a}_x}\\ \mathbf{\hat{a}_y}\mathbf{\hat{a}_x} \cdot \mathbf{\hat{a}_x} &= \mathbf{\hat{a}_y}\\ \mathbf{\hat{a}_x}\mathbf{\hat{a}_y} \cdot \mathbf{\hat{a}_x} &= 0\\ \mathbf{\hat{a}_x} \cdot \mathbf{\hat{a}_x}\mathbf{\hat{a}_x} &= \mathbf{\hat{a}_x}\\ \mathbf{\hat{a}_x} \cdot \mathbf{\hat{a}_x}\mathbf{\hat{a}_y} &= \mathbf{\hat{a}_y}\\ \mathbf{\hat{a}_x} \cdot \mathbf{\hat{a}_y}\mathbf{\hat{a}_x} &= 0\\ \mathbf{\hat{a}_x} \times \mathbf{\hat{a}_y}\mathbf{\hat{a}_x} &= \mathbf{\hat{a}_z}\mathbf{\hat{a}_x}\\ \mathbf{\hat{a}_x} \times \mathbf{\hat{a}_x}\mathbf{\hat{a}_x} &= 0\\ \mathbf{\hat{a}_y}\mathbf{\hat{a}_x} \times \mathbf{\hat{a}_z} &= - \mathbf{\hat{a}_y}\mathbf{\hat{a}_y}\\ One can also take the time derivative of dyadics or express them in different frames, just like with vectors. Linear Momentum =============== The linear momentum of a particle P is defined as: .. math:: L_P = m\mathbf{v} where :math:`m` is the mass of the particle P and :math:`\mathbf{v}` is the velocity of the particle in the inertial frame.[Likins1973]_. Similarly the linear momentum of a rigid body is defined as: .. math:: L_B = m\mathbf{v^*} where :math:`m` is the mass of the rigid body, B, and :math:`\mathbf{v^*}` is the velocity of the mass center of B in the inertial frame. Angular Momentum ================ The angular momentum of a particle P about an arbitrary point O in an inertial frame N is defined as: .. math:: ^N \mathbf{H} ^ {P/O} = \mathbf{r} \times m\mathbf{v} where :math:`\mathbf{r}` is a position vector from point O to the particle of mass :math:`m` and :math:`\mathbf{v}` is the velocity of the particle in the inertial frame. Similarly the angular momentum of a rigid body B about a point O in an inertial frame N is defined as: .. math:: ^N \mathbf{H} ^ {B/O} = ^N \mathbf{H} ^ {B/B^*} + ^N \mathbf{H} ^ {B^*/O} where the angular momentum of the body about it's mass center is: .. math:: ^N \mathbf{H} ^ {B/B^*} = \mathbf{I^*} \cdot \omega and the angular momentum of the mass center about O is: .. math:: ^N \mathbf{H} ^ {B^*/O} = \mathbf{r^*} \times m \mathbf{v^*} where :math:`\mathbf{I^*}` is the central inertia dyadic of rigid body B, :math:`\omega` is the inertial angular velocity of B, :math:`\mathbf{r^*}` is a position vector from point O to the mass center of B, :math:`m` is the mass of B and :math:`\mathbf{v^*}` is the velocity of the mass center in the inertial frame. Using momenta functions in Mechanics ==================================== The following example shows how to use the momenta functions in :mod:`sympy.physics.mechanics`. One begins by creating the requisite symbols to describe the system. Then the reference frame is created and the kinematics are done. :: >>> from sympy import symbols >>> from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, Particle, Point, outer >>> from sympy.physics.mechanics import linear_momentum, angular_momentum >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> m, M, l1 = symbols('m M l1') >>> q1d = dynamicsymbols('q1d') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> Ac = O.locatenew('Ac', l1 * N.x) >>> P = Ac.locatenew('P', l1 * N.x) >>> a = ReferenceFrame('a') >>> a.set_ang_vel(N, q1d * N.z) >>> Ac.v2pt_theory(O, N, a) l1*q1d*N.y >>> P.v2pt_theory(O, N, a) 2*l1*q1d*N.y Finally, the bodies that make up the system are created. In this case the system consists of a particle Pa and a RigidBody A. :: >>> Pa = Particle('Pa', P, m) >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, M, (I, Ac)) Then one can either choose to evaluate the momenta of individual components of the system or of the entire system itself. :: >>> linear_momentum(N,A) M*l1*q1d*N.y >>> angular_momentum(O, N, Pa) 4*l1**2*m*q1d*N.z >>> linear_momentum(N, A, Pa) (M*l1*q1d + 2*l1*m*q1d)*N.y >>> angular_momentum(O, N, A, Pa) (M*l1**2*q1d + 4*l1**2*m*q1d + q1d)*N.z It should be noted that the user can determine either momenta in any frame in :mod:`sympy.physics.mechanics` as the user is allowed to specify the reference frame when calling the function. In other words the user is not limited to determining just inertial linear and angular momenta. Please refer to the docstrings on each function to learn more about how each function works precisely. Kinetic Energy ============== The kinetic energy of a particle P is defined as .. math:: T_P = \frac{1}{2} m \mathbf{v^2} where :math:`m` is the mass of the particle P and :math:`\mathbf{v}` is the velocity of the particle in the inertial frame. Similarly the kinetic energy of a rigid body B is defined as .. math:: T_B = T_t + T_r where the translational kinetic energy is given by: .. math:: T_t = \frac{1}{2} m \mathbf{v^*} \cdot \mathbf{v^*} and the rotational kinetic energy is given by: .. math:: T_r = \frac{1}{2} \omega \cdot \mathbf{I^*} \cdot \omega where :math:`m` is the mass of the rigid body, :math:`\mathbf{v^*}` is the velocity of the mass center in the inertial frame, :math:`\omega` is the inertial angular velocity of the body and :math:`\mathbf{I^*}` is the central inertia dyadic. Potential Energy ================ Potential energy is defined as the energy possessed by a body or system by virtue of its position or arrangement. Since there are a variety of definitions for potential energy, this is not discussed further here. One can learn more about this in any elementary text book on dynamics. Lagrangian ========== The Lagrangian of a body or a system of bodies is defined as: .. math:: \mathcal{L} = T - V where :math:`T` and :math:`V` are the kinetic and potential energies respectively. Using energy functions in Mechanics =================================== The following example shows how to use the energy functions in :mod:`sympy.physics.mechanics`. As was discussed above in the momenta functions, one first creates the system by going through an identical procedure. :: >>> from sympy import symbols >>> from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame, outer >>> from sympy.physics.mechanics import RigidBody, Particle >>> from sympy.physics.mechanics import kinetic_energy, potential_energy, Point >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> m, M, l1, g, h, H = symbols('m M l1 g h H') >>> omega = dynamicsymbols('omega') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> Ac = O.locatenew('Ac', l1 * N.x) >>> P = Ac.locatenew('P', l1 * N.x) >>> a = ReferenceFrame('a') >>> a.set_ang_vel(N, omega * N.z) >>> Ac.v2pt_theory(O, N, a) l1*omega*N.y >>> P.v2pt_theory(O, N, a) 2*l1*omega*N.y >>> Pa = Particle('Pa', P, m) >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, M, (I, Ac)) The user can then determine the kinetic energy of any number of entities of the system: :: >>> kinetic_energy(N, Pa) 2*l1**2*m*omega**2 >>> kinetic_energy(N, Pa, A) M*l1**2*omega**2/2 + 2*l1**2*m*omega**2 + omega**2/2 It should be noted that the user can determine either kinetic energy relative to any frame in :mod:`sympy.physics.mechanics` as the user is allowed to specify the reference frame when calling the function. In other words the user is not limited to determining just inertial kinetic energy. For potential energies, the user must first specify the potential energy of every entity of the system using the :obj:`sympy.physics.mechanics.rigidbody.RigidBody.potential_energy` property. The potential energy of any number of entities comprising the system can then be determined: :: >>> Pa.potential_energy = m * g * h >>> A.potential_energy = M * g * H >>> potential_energy(A, Pa) H*M*g + g*h*m One can also determine the Lagrangian for this system: :: >>> from sympy.physics.mechanics import Lagrangian >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> Lagrangian(N, Pa, A) -H*M*g + M*l1**2*omega**2/2 - g*h*m + 2*l1**2*m*omega**2 + omega**2/2 Please refer to the docstrings to learn more about each function. sympy-sympy-1.9/doc/src/modules/physics/mechanics/reference.rst000066400000000000000000000016251412543434000250370ustar00rootroot00000000000000================================ References for Physics/Mechanics ================================ .. [Blajer1994] Blajer, Wojciech, Werner Schiehlen, and Walter Schirm. "A projective criterion to the coordinate partitioning method for multibody dynamics." Archive of Applied Mechanics 64: 86-98. Print. .. [Kane1983] Kane, Thomas R., Peter W. Likins, and David A. Levinson. Spacecraft Dynamics. New York: McGraw-Hill Book, 1983. Print. .. [Kane1985] Kane, Thomas R., and David A. Levinson. Dynamics, Theory and Applications. New York: McGraw-Hill, 1985. Print. .. [Meijaard2007] Meijaard, J.P., Jim M. Papadopoulos, Andy Ruina, and A.L. Schwab. "Linearized Dynamics Equations for the Balance and Steer of a Bicycle: a Benchmark and Review." Proceedings of the Royal Society A: Mathematical, Physical and Engineering Sciences 463.2084 (2007): 1955-982. Print. sympy-sympy-1.9/doc/src/modules/physics/mechanics/sympy_mechanics_for_autolev_users.rst000066400000000000000000001351011412543434000321170ustar00rootroot00000000000000.. _sympy_mechanics_for_autolev_users: ================================= SymPy Mechanics for Autolev Users ================================= Introduction ------------ Autolev (now superseded by MotionGenesis) is a domain specific programming language which is used for symbolic multibody dynamics. The SymPy mechanics module now has enough power and functionality to be a fully featured symbolic dynamics module. The PyDy package extends the SymPy output to the numerical domain for simulation, analyses and visualization. Autolev and SymPy Mechanics have a lot in common but there are also many differences between them. This page shall expand upon their differences. It is meant to be a go-to reference for Autolev users who want to transition to SymPy Mechanics. It would be nice to have a basic understanding of SymPy and SymPy Mechanics before going over this page. If you are completely new to Python, you can check out the official `Python Tutorial `_. Check out the :ref:`SymPy Documentation `, especially the tutorial to get a feel for SymPy. For an introduction to Multibody dynamics in Python, `this `_ lecture is very helpful. You might also find the :ref:`Autolev Parser ` which is a part of SymPy to be helpful. Some Key Differences ------------------------ +-----------------------------------+-----------------------------------+ | **Autolev** | **SymPy Mechanics** | +===================================+===================================+ || || | | Autolev is a domain specific | SymPy is a library written in the | | programming language designed to | general purpose language Python. | | perform multibody dynamics. Since | Although Autolev's code is more | | it is a language of its own, it | compact, SymPy (by virtue of being| | has a very rigid language | an add on to Python) is more | | specification. It predefines, | flexible. The users have more | | assumes and computes | control over what they can do. For| | many things based on the | example, one can create a class in| | input code. Its code is a lot | their code for let's say a type of| | cleaner and concise as a result of| rigibodies with common | | this. | properties. | | | The wide array of scientific | | | Python libraries available is also| | | a big plus. | +-----------------------------------+-----------------------------------+ || || | | Autolev generates Matlab, C, or | SymPy generates numerical Python, | | Fortran code from a small set of | C or Octave/Matlab code from a | | symbolic mathematics. | large set of symbolic mathematics | | | created with SymPy. It also builds| | | on the popular scientific Python | | | stack such as NumPy, SciPy, | | | IPython, matplotlib, Cython and | | | Theano. | +-----------------------------------+-----------------------------------+ || || | | Autolev uses 1 (one) based | Python uses 0 (zero) based | | indexing. The initial element of | indexing. The initial element of | | a sequence is found using a[1]. | a sequence is found using a[0]. | +-----------------------------------+-----------------------------------+ || || | | Autolev is case insensitive. | SymPy code being Python code is | | | case sensitive. | +-----------------------------------+-----------------------------------+ || || | | One can define their own commands | SymPy code is Python code, so one | | in Autolev by making .R and .A | can define functions in their | | files which can be used in their | code. This is a lot more | | programs. | convenient. | +-----------------------------------+-----------------------------------+ || || | | Autolev is proprietary. | SymPy is open source. | +-----------------------------------+-----------------------------------+ Rough Autolev-SymPy Equivalents ---------------------------------- The tables below give rough equivalents for some common Autolev expressions. **These are not exact equivalents**, but rather should be taken as hints to get you going in the right direction. For more detail read the built-in documentation on :ref:`SymPy vectors `, :ref:`SymPy mechanics ` and `PyDy `_ . In the tables below, it is assumed that you have executed the following commands in Python: :: import sympy.physics.mechanics as me import sympy as sm Mathematical Equivalents ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +-----------------------+-----------------------+-----------------------+ | **Autolev** | **SymPy** | **Notes** | +=======================+=======================+=======================+ || || || | | ``Constants A, B`` | ``a, b = | Note that the names | | | sm.symbols(‘a | of the symbols can be | | | b’, real=True)`` | different from the | | | | names of the | | | | variables they are | | | | assigned to. We can | | | | define ``a, b = | | | | symbols(‘b a’)`` but | | | | its good practice to | | | | follow the | | | | convention. | +-----------------------+-----------------------+-----------------------+ || || || | | ``Constants C+`` | ``c = sm.symbols(‘c’, | Refer to SymPy | | | real=True, | :ref:`assumptions | | | nonnegative=True)`` | ` | | | | for more information. | +-----------------------+-----------------------+-----------------------+ || || || | | ``Constants D-`` | ``d = sm.symbols(‘d’, | | | | real=True, | | | | nonpositive=True)`` | | +-----------------------+-----------------------+-----------------------+ || || || | | ``Constants K{4}`` | ``k1, k2, k3, k4 = | | | | sm.symbols('k1 k2 k3 | | | | k4', real=True)`` | | +-----------------------+-----------------------+-----------------------+ || || || | | ``Constants a{2:4}`` | ``a2, a3, a4 = | | | | sm.symbols('a2 a3 a4',| | | | real=True)`` | | +-----------------------+-----------------------+-----------------------+ || || || | | ``Constants | ``b11, b12, b21, b22 =| | | b{1:2, 1:2}`` | sm.symbols('b11 b12 | | | | b21 b22', real=True)``| | +-----------------------+-----------------------+-----------------------+ || || || | | ``Specified Phi`` | ``phi = | | | | me.dynamicsymbols(‘phi| | | | ')`` | | +-----------------------+-----------------------+-----------------------+ || || || | | ``Variables q, s`` | ``q, s = | | | | me.dynamicsymbols(q, | | | | s)`` | | +-----------------------+-----------------------+-----------------------+ | ``Variables x’’`` | ``x = | | | | me.dynamicsymbols(‘x’ | | | | )`` | | | | | | | | ``xd = | | | | me.dynamicsymbols(‘x’ | | | | , 1)`` | | | | | | | | ``xd2 = | | | | me.dynamicsymbols(‘x’ | | | | , 2)`` | | +-----------------------+-----------------------+-----------------------+ | ``Variables y{2}’`` | ``y1 = | | | | me.dynamicsymbols(‘y1’| | | | )`` | | | | | | | | ``y2 = | | | | me.dynamicsymbols(‘y2’| | | | )`` | | | | | | | | ``y1d = | | | | me.dynamicsymbols(‘y1’| | | | , 1)`` | | | | | | | | ``y2d = | | | | me.dynamicsymbols(‘y2'| | | | , 1)`` | | +-----------------------+-----------------------+-----------------------+ | ``MotionVariables | ``u1 = | SymPy doesn’t | | u{2}`` | me.dynamicsymbols(‘u1’| differentiate between | | | )`` | variables, | | | | motionvariables and | | | ``u2 = | specifieds during | | | me.dynamicsymbols('u2'| declaration. Instead, | | | )`` | it takes different | | | | lists of these as | | | | parameters in objects | | | | like the KanesMethod. | +-----------------------+-----------------------+-----------------------+ | ``Imaginary j`` | ``j = sm.I`` | I is a sympy object | | | | which stands for the | | | | imaginary unit. One | | | | can define complex | | | | numbers using it. | | | | | | | | ``z = x + I*y`` | | | | | | | | where x, y and z are | | | | symbols. | +-----------------------+-----------------------+-----------------------+ | ``Tina = 2*pi`` | ``tina = 2*sm.pi`` | Using ``.evalf()`` | | | | will result in the | | | ``tina = | numeric value. | | | tina.evalf()`` | | | | | | | ``s = u*t + a*t^2/2`` | ``t = | | | | me.dynamicsymbols._t``| | | | | | | | ``s = u*t + a*t**2/2``| | +-----------------------+-----------------------+-----------------------+ || || || | | ``abs(x)^3 + sin(x)^2 | ``sm.abs(x)**3 | | | + acos(x)`` | + sm.sin(x)**2 + | | | | sm.acos(x)`` | | +-----------------------+-----------------------+-----------------------+ | ``E = (x+2*y)^2 + | ``E = (x+2*y)**2 + | For more information | | 3*(7+x)*(x+y)`` | 3*(7+x)*(x+y)`` | refer to | | | | :ref:`simplification. | | ``Expand(E)`` | ``sm.expand(E)`` | ` | | | | | | ``Factor(E, x)`` | ``sm.horner(E, | | | | wrt=x)`` | | | | | | | ``Coef(y, x)`` | ``y.coeff(x)`` | These SymPy functions | | | | do not work in place. | | ``Replace(y, | ``y.subs({sm.sin(x): | They just return | | sin(x)=3)`` | 3})`` | expressions. If you | | | | want to overwrite the | | ``Exclude(E,x)`` | ``e.collect(x).coeff( | original expression | | | x, 0)`` | you would have to do | | | | something like: | | ``Include(E,x)`` | ``e.collect(x).coeff( | | | | x, 1)`` | ``y = | | | | y.subs({sm.sin(x): | | ``Arrange(E,2,y)`` | ``e.collect(y)`` | 3})`` | +-----------------------+-----------------------+-----------------------+ | ``Dy = D(E, y)`` | ``E.diff(y)`` | For more information | | | | refer to | | ``Dt = Dt(E)`` | ``E.diff( | :ref:`calculus. | | | me.dynamicsymbols._t | ` | | | )`` | | | | | | | | Works if the | | | | expression is made up | | | | of dynamicsymbols. | | | ``Dt2 = Dt(V, A)`` | | | | where V is a vector | ``dt2 = v.dt(A)`` | | | and A is a frame | | | | | | | | ``Dy2 = D(V, y, A)`` | ``dy2 = v.diff(y, A)``| | | | | | +-----------------------+-----------------------+-----------------------+ | ``E = COS(X*Y)`` | ``e = sm.cos(x*y)`` | For more information | | | | refer to :ref:`series.| | ``TY = Taylor(E, | ``b = e.series(x, 0, | ` | | 0:2, x=0, y=0)`` | 2).removeO().series(y,| | | | 0, 2).removeO()`` | | | | | | +-----------------------+-----------------------+-----------------------+ | ``F = Evaluate(E, | ``E.subs([(x, a), (y, | | | x=a, y=2)`` | 2)])`` | | | | | | | | To get floating point | | | | numbers from numerical| | | | expressions use | | | | ``.evalf()`` | | | | | | | | ``E.evalf((a + | | | | sm.pi).subs({a: 3}))``| | +-----------------------+-----------------------+-----------------------+ | ``P = Polynomial([a, | ``p = | For more information | | b, c], x)`` | sm.Poly(sm.Matrix([a, | refer to | | | b, c]).reshape(1, 3), | :ref:`polys. | | | x)`` | ` | +-----------------------+-----------------------+-----------------------+ | ``Roots(Polynomial( | ``sm.solve( | For more information | | a*x^2 + b*x + c, x, | sm.Poly(a*x**2 + | refer to | | 2)`` | b*x + c))`` | :ref:`solvers`. | | | | | | ``Roots([1;2;3])`` | ``sm.solve(sm.Poly( | For numerical | | | sm.Matrix([1,2,3]). | computation related | | | reshape(3, 1), x), | to polynomials and | | | x)`` | roots refer to | | | | `mpmath/calculus. `_ | +-----------------------+-----------------------+-----------------------+ | ``Solve(A, x1, x2)`` | ``sm.linsolve(A, | For more information | | | (x1, x2))`` | refer to | | | | :ref:` | | where A is an | where A is an | solvers/solveset. | | augmented matrix that | augmented matrix | ` | | represents the linear | | | | equations and x1, x2 | | | | are the variables to | | For non linear solvers| | solve for. | | refer to | | | | ``nonlinsolve`` and | | | | ``nsolve`` in | | | | :ref:`solvers. | | | | ` | +-----------------------+-----------------------+-----------------------+ | ``RowMatrix = [1, 2, | ``row_matrix = | For more information | | 3, 4]`` | sm.Matrix([[1],[2], | refer to | | | [3],[4]])`` | :ref:`matrices. | | | | ` | | ``ColMatrix = [1; 2; | ``col_matrix = | | | 3; 4]`` | sm.Matrix([1, 2, 3, | | | | 4])`` | | | | | | | ``MO = [a, b; c, 0]`` | ``MO = sm.Matrix([[a, | | | | b], [c, 0]])`` | | | | | | | ``MO[2, 2] := d`` | ``MO[1, 1] = d`` | | | | | | | ``A + B*C`` | ``A + B*C`` | | | | | | | ``Cols(A)`` | ``A.cols`` | | | | | | | ``Cols(A, 1)`` | ``A.col(0)`` | | | | | | | ``Rows(A)`` | ``A.rows`` | | | | | | | ``Rows(A, 1)`` | ``A.row(0)`` | | | | | | | ``Det(A)`` | ``M.det()`` | | | | | | | ``Element(A, 2, 3)`` | ``M[2, 3]`` | | | | | | | ``Inv(A)`` | ``M**-1`` | | | | | | | ``Trace(A)`` | ``sm.trace(A)`` | | | | | | | ``Transpose(A)`` | ``A.T`` | | | | | | | ``Diagmat(4, 1)`` | ``sm.diag(1,1,1,1)`` | | | | | | | ``Eig(A)`` | ``A.eigenvals()`` | | | | | | | ``Eig(A, EigVal, | ``eigval = | | | EigVec)`` | A.eigenvals()`` | | | | | | | | ``eigvec = | | | | A.eigenvects()`` | | +-----------------------+-----------------------+-----------------------+ Physical Equivalents ~~~~~~~~~~~~~~~~~~~~~~~~ +-----------------------+-----------------------+-----------------------+ | **Autolev** | **SymPy** | **Notes** | +=======================+=======================+=======================+ | ``Bodies A`` | ``m =sm.symbols(‘m’)``| The 4th and 5th | | | | arguments are for the | | Declares A, its | ``Ao = | mass and inertia. | | masscenter Ao, and | sm.symbols(‘Ao’)`` | These are specified | | orthonormal vectors | | after the declaration | | A1>, A2> and A3> | ``Af = | in Autolev. | | fixed in A. | me.ReferenceFrame(‘Af’| | | | )`` | | | | | | | | ``I = | One can pass a dummy | | | me.outer(Af.x,Af.x)`` | for the parameters | | | | and use setters | | | ``P = me.Point(‘P’)`` | ``A.mass = \_`` and | | | | ``A.inertia = \_`` to | | | ``A =me.RigidBody(‘A’,| set them later. | | | Ao, Af, m, (I, P))`` | | | | | | | | Af.x, Af.y and Af.z | For more information | | | are equivalent to | refer to | | | A1>, A2> and A3>. | :ref:`mechanics/masses| | | | .` | +-----------------------+-----------------------+-----------------------+ | ``Frames A`` | ``A = | For more information | | | me.ReferenceFrame(‘A’ | refer to | | ``V1> = | )`` | :ref:`physics/vectors.| | X1*A1> + X2*A2>`` | | ` | | | ``v1 = | | | | x1*A.x + x2*A.y`` | | +-----------------------+-----------------------+-----------------------+ | ``Newtonian N`` | ``N = | SymPy doesn’t specify | | | me.ReferenceFrame(‘N’ | that a frame is | | | )`` | inertial during | | | | declaration. Many | | | | functions such as | | | | ``set_ang_vel()`` take| | | | the inertial | | | | reference frame as a | | | | parameter. | +-----------------------+-----------------------+-----------------------+ | ``Particles C`` | ``m = | The 2nd and 3rd | | | sm.symbols(‘m’)`` | arguments are for the | | | | point and mass. In | | | ``Po = | Autolev, these are | | | me.Point(‘Po’)`` | specified after the | | | | declaration. | | | ``C = me.Particle(‘C’,| | | | Po, m)`` | One can pass a dummy | | | | and use setters | | | | (``A.point = \_`` and | | | | ``A.mass = \_``) to | | | | set them later. | +-----------------------+-----------------------+-----------------------+ | ``Points P, Q`` | ``P = me.Point(‘P’)`` | | | | | | | | ``Q = me.Point(‘Q’)`` | | +-----------------------+-----------------------+-----------------------+ | ``Mass B=mB`` | ``mB = symbols(‘mB’)``| | | | | | | | ``B.mass = mB`` | | +-----------------------+-----------------------+-----------------------+ | ``Inertia B, I1, I2, | ``I = me.inertia(Bf, | For more information | | I3, I12, I23, I31`` | i1, i2, i3, i12, i23, | refer to the | | | i31)`` | :ref:`mechanics api. | | | | ` | | | ``B.inertia = (I, P)``| | | | where B is a | | | | rigidbody, Bf is the | | | | related frame and P is| | | | the center of mass of | | | | B. | | | | | | | | Inertia dyadics can | | | | also be formed using | | | | vector outer products.| | | | | | | | ``I = | | | | me.outer(N.x, N.x)`` | | +-----------------------+-----------------------+-----------------------+ | ``vec> = P_O_Q>/L`` | ``vec = | For more information | | | (Qo.pos_from(O))/L`` | refer to | | ``vec> = | | :ref:`physics/vectors.| | u1*N1> + u2*N2>`` | ``vec = | ` | | | u1*N.x + u2*N.y`` | | | ``Cross(a>, b>)`` | | | | | ``cross(a, b)`` | | | ``Dot(a>, b>)`` | | | | | ``dot(a, b)`` | | | ``Mag(v>)`` | | | | | ``v.magnitude()`` | | | ``Unitvec(v>)`` | | | | | ``v.normalize()`` | | | | | | | ``DYAD>> = 3*A1>*A1> +| ``dyad = | | | A2>*A2> + 2*A3>*A3>`` | 3*me.outer(a.x | | | | ,a.x) + me.outer(a.y, | | | | a.y) + 2*me.outer(a.z | | | | ,a.z)`` | | +-----------------------+-----------------------+-----------------------+ | ``P_O_Q> = LA*A1>`` | ``Q.point = | For more information | | | O.locatenew(‘Qo’, | refer to the | | | LA*A.x)`` | :ref:`kinematics api. | | | | ` | | ``P_P_Q> = LA*A1>`` | where A is a | | | | reference frame. | | | | | | | | ``Q.point = | | | | P.point.locatenew(‘Qo | All these vector and | | | ’, | kinematic functions | | | LA*A.x)`` | are to be used on | | | | ``Point`` objects and | | | | not ``Particle`` | | | | objects so ``.point`` | | | | must be used for | | | | particles. | +-----------------------+-----------------------+-----------------------+ | ``V_O_N> = u3*N.1> + | ``O.set_vel(N, u1*N.x | The getter would be | | u4*N.2>`` | + u2*N.y)`` | ``O.vel(N)``. | | | | | | ``Partials(V_O_N>, | ``O.partial_velocity(N| | | u3)`` | , u3)`` | | +-----------------------+-----------------------+-----------------------+ | ``A_O_N> = 0>`` | ``O.set_acc(N, 0)`` | The getter would be | | | | ``O.acc(N)``. | | Acceleration of point | | | | O in reference frame | | | | N. | | | +-----------------------+-----------------------+-----------------------+ | ``W_B_N> = qB’*B3>`` | ``B.set_ang_vel(N, | The getter would be | | | qBd*Bf.z)`` | ``B.ang_vel_in(N)``. | | Angular velocity of | | | | body B in reference | where Bf is the frame | | | frame F. | associated with the | | | | body B. | | +-----------------------+-----------------------+-----------------------+ | ``ALF_B_N> =Dt(W_B_N>,| ``B.set_ang_acc(N, | The getter would be | | N)`` | diff(B.ang_vel_in(N) | ``B.ang_acc_in(N)``. | | | )`` | | | Angular acceleration | | | | of body B in | | | | reference frame N. | | | +-----------------------+-----------------------+-----------------------+ | ``Force_O> = F1*N1> + | In SymPy one should | | | F2*N2>`` | have a list which | | | | contains all the | | | ``Torque_A> = | forces and torques. | | | -c*qA’*A3>`` | | | | | ``fL.append((O, f1*N.x| | | | + f2*N.y))`` | | | | | | | | where fL is the force | | | | list. | | | | | | | | ``fl.append((A, | | | | -c*qAd*A.z))`` | | +-----------------------+-----------------------+-----------------------+ | ``A_B = M`` | ``B.orient(A, 'DCM', | | | where M is a matrix | M)`` where M is a | | | and A, B are frames. | SymPy Matrix. | | | | | | | ``D = A_B*2 + 1`` | ``D = A.dcm(B)*2 + 1``| | +-----------------------+-----------------------+-----------------------+ | ``CM(B)`` | ``B.masscenter`` | | +-----------------------+-----------------------+-----------------------+ | ``Mass(A,B,C)`` | ``A.mass + B.mass + | | | | C.mass`` | | +-----------------------+-----------------------+-----------------------+ | ``V1pt(A,B,P,Q)`` | ``Q.v1pt_theory(P, A, | P and Q are assumed to| | | B)`` | be ``Point`` objects | | | | here. Remember to use | | | | ``.point`` for | | | | particles. | +-----------------------+-----------------------+-----------------------+ | ``V2pts(A,B,P,Q)`` | ``Q.v2pt_theory(P, A, | | | | B)`` | | +-----------------------+-----------------------+-----------------------+ | ``A1pt(A,B,P,Q)`` | ``Q.a1pt_theory(P, A, | | | | B)`` | | +-----------------------+-----------------------+-----------------------+ | ``A2pts(A,B,P,Q)`` | ``Q.a2pt_theory(P, A, | | | | B)`` | | +-----------------------+-----------------------+-----------------------+ | ``Angvel(A,B)`` | ``B.ang_vel_in(A)`` | | +-----------------------+-----------------------+-----------------------+ | ``Simprot(A, B, 1, | ``B.orient(A, ‘Axis’, | | | qA)`` | qA, A.x)`` | | +-----------------------+-----------------------+-----------------------+ | ``Gravity(G*N1>)`` | ``fL.extend(gravity( | In SymPy we must use a| | | g*N.x, P1, P2, ...))``| forceList (here fL) | | | | which contains tuples | | | | of the form ``(point, | | | | force_vector)``. This | | | | is passed to the | | | | ``kanes_equations()`` | | | | method of the | | | | KanesMethod object. | +-----------------------+-----------------------+-----------------------+ | ``CM(O,P1,R)`` | ``me.functions. | | | | center_of_mass(o, p1, | | | | r)`` | | +-----------------------+-----------------------+-----------------------+ | ``Force(P/Q, v>)`` | ``fL.append((P, -1*v),| | | | (Q, v))`` | | +-----------------------+-----------------------+-----------------------+ | ``Torque(A/B, v>)`` | ``fL.append((A, -1*v),| | | | (B, v))`` | | +-----------------------+-----------------------+-----------------------+ | ``Kindiffs(A, B ...)``| ``KM.kindiffdict()`` | | +-----------------------+-----------------------+-----------------------+ | ``Momentum(option)`` | ``linear_momentum(N, | | | | B1, B2 ...)`` | | | | | | | | reference frame | | | | followed by one or | | | | more bodies | | | | | | | | ``angular_momentum(O, | | | | N, B1, B2 ...)`` | | | | | | | | point, reference | | | | frame followed by one | | | | or more bodies | | +-----------------------+-----------------------+-----------------------+ | ``KE()`` | ``kinetic_energy(N, | | | | B1, B2 ...)`` | | | | | | | | reference frame | | | | followed by one or | | | | more bodies | | +-----------------------+-----------------------+-----------------------+ | ``Constrain(...)`` | ``velocity_constraints| For more details | | | = [...]`` | refer to | | | | :ref:`mechanics/kane | | | ``u_dependent = | ` and | | | [...]`` | the :ref:`kane api. | | | | ` | | | ``u_auxiliary = | | | | [...]`` | | | | | | | | These lists are | | | | passed to the | | | | KanesMethod object. | | +-----------------------+-----------------------+-----------------------+ | ``Fr()`` | ``KM = KanesMethod(f, | For more details | | ``FrStar()`` | q_ind, u_ind, kd_eqs, | refer to | | | q_dependent, configura| :ref:`mechanics/kane | | | tion_constraints, u_de| ` and | | | pendent, velocity_cons| the :ref:`kane api. | | | traints, acceleration_| ` | | | constraints, u_auxilia| | | | ry)`` | | | | | | | | The KanesMethod | | | | object takes a | | | | reference frame | | | | followed by multiple | | | | lists as arguments. | | | | | | | | ``(fr, frstar) = | | | | KM.kanes_equations(fL,| | | | bL)`` where fL and bL | | | | are lists of forces | | | | and bodies | | | | respectively. | | +-----------------------+-----------------------+-----------------------+ Numerical Evaluation and Visualization ---------------------------------------- Autolev’s CODE Option() command allows one to generate Matlab, C, or Fortran code for numerical evaluation and visualization. Option can be Dynamics, ODE, Nonlinear or Algebraic. Numerical evaluation for dynamics can be achieved using PyDy. One can pass in the KanesMethod object to the System class along with the values for the constants, specifieds, initial conditions and time steps. The equations of motion can then be integrated. The plotting is achieved using matlplotlib. Here is an example from the `PyDy Documentation `_ on how it is done:: from numpy import array, linspace, sin from pydy.system import System sys = System(kane, constants = {mass: 1.0, stiffness: 1.0, damping: 0.2, gravity: 9.8}, specifieds = {force: lambda x, t: sin(t)}, initial_conditions = {position: 0.1, speed:-1.0}, times = linspace(0.0, 10.0, 1000)) y = sys.integrate() import matplotlib.pyplot as plt plt.plot(sys.times, y) plt.legend((str(position), str(speed))) plt.show() For information on all the things PyDy can accomplish refer to the `PyDy Documentation `_. The tools in the PyDy workflow are : - `SymPy `_: SymPy is a Python library for symbolic computation. It provides computer algebra capabilities either as a standalone application, as a library to other applications, or live on the web as SymPy Live or SymPy Gamma. - `NumPy `_: NumPy is a library for the Python programming language, adding support for large, multi-dimensional arrays and matrices, along with a large collection of high-level mathematical functions to operate on these arrays. - `SciPy `_: SciPy is an open source Python library used for scientific computing and technical computing. SciPy contains modules for optimization, linear algebra, integration, interpolation, special functions, FFT, signal and image processing, ODE solvers and other tasks common in science and engineering. - `IPython `_: IPython is a command shell for interactive computing in multiple programming languages, originally developed for the Python programming language, that offers introspection, rich media, shell syntax, tab completion, and history. - `Aesara `_: Aesara is a numerical computation library for Python. In Aesara, computations are expressed using a NumPy-esque syntax and compiled to run efficiently on either CPU or GPU architectures. - `Cython `_: Cython is a superset of the Python programming language, designed to give C-like performance with code that is mostly written in Python. Cython is a compiled language that generates CPython extension modules. - `matplotlib `_: matplotlib is a plotting library for the Python programming language and its numerical mathematics extension NumPy. One will be able to write code equivalent to the Matlab, C or Fortran code generated by Autolev using these scientific computing tools. It is recommended to go over these modules to gain an understanding of scientific computing with Python. Links ---------- :ref:`SymPy Tutorial ` :ref:`SymPy Documentation ` :ref:`SymPy Physics Vector Documentation ` :ref:`SymPy Mechanics Documentation ` `PyDy Documentation `_ `MultiBody Dynamics with Python `_ sympy-sympy-1.9/doc/src/modules/physics/mechanics/symsystem.rst000066400000000000000000000166441412543434000251650ustar00rootroot00000000000000===================================== Symbolic Systems in Physics/Mechanics ===================================== The `SymbolicSystem` class in physics/mechanics is a location for the pertinent information of a multibody dynamic system. In its most basic form it contains the equations of motion for the dynamic system, however, it can also contain information regarding the loads that the system is subject to, the bodies that the system is comprised of and any additional equations the user feels is important for the system. The goal of this class is to provide a unified output format for the equations of motion that numerical analysis code can be designed around. SymbolicSystem Example Usage ============================ This code will go over the manual input of the equations of motion for the simple pendulum that uses the Cartesian location of the mass as the generalized coordinates into `SymbolicSystem`. The equations of motion are formed in the physics/mechanics/examples_. In that spot the variables q1 and q2 are used in place of x and y and the reference frame is rotated 90 degrees. .. _examples: ../examples/lin_pend_nonmin_example.html :: >>> from sympy import atan, symbols, Matrix >>> from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, ... Particle, Point) >>> import sympy.physics.mechanics.system as system >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) The first step will be to initialize all of the dynamic and constant symbols. :: >>> x, y, u, v, lam = dynamicsymbols('x y u v lambda') >>> m, l, g = symbols('m l g') Next step is to define the equations of motion in multiple forms: [1] Explicit form where the kinematics and dynamics are combined x' = F_1(x, t, r, p) [2] Implicit form where the kinematics and dynamics are combined M_2(x, p) x' = F_2(x, t, r, p) [3] Implicit form where the kinematics and dynamics are separate M_3(q, p) u' = F_3(q, u, t, r, p) q' = G(q, u, t, r, p) where x : states, e.g. [q, u] t : time r : specified (exogenous) inputs p : constants q : generalized coordinates u : generalized speeds F_1 : right hand side of the combined equations in explicit form F_2 : right hand side of the combined equations in implicit form F_3 : right hand side of the dynamical equations in implicit form M_2 : mass matrix of the combined equations in implicit form M_3 : mass matrix of the dynamical equations in implicit form G : right hand side of the kinematical differential equations :: >>> dyn_implicit_mat = Matrix([[1, 0, -x/m], ... [0, 1, -y/m], ... [0, 0, l**2/m]]) >>> dyn_implicit_rhs = Matrix([0, 0, u**2 + v**2 - g*y]) >>> comb_implicit_mat = Matrix([[1, 0, 0, 0, 0], ... [0, 1, 0, 0, 0], ... [0, 0, 1, 0, -x/m], ... [0, 0, 0, 1, -y/m], ... [0, 0, 0, 0, l**2/m]]) >>> comb_implicit_rhs = Matrix([u, v, 0, 0, u**2 + v**2 - g*y]) >>> kin_explicit_rhs = Matrix([u, v]) >>> comb_explicit_rhs = comb_implicit_mat.LUsolve(comb_implicit_rhs) Now the reference frames, points and particles will be set up so this information can be passed into `system.SymbolicSystem` in the form of a bodies and loads iterable. :: >>> theta = atan(x/y) >>> omega = dynamicsymbols('omega') >>> N = ReferenceFrame('N') >>> A = N.orientnew('A', 'Axis', [theta, N.z]) >>> A.set_ang_vel(N, omega * N.z) >>> O = Point('O') >>> O.set_vel(N, 0) >>> P = O.locatenew('P', l * A.x) >>> P.v2pt_theory(O, N, A) l*omega*A.y >>> Pa = Particle('Pa', P, m) Now the bodies and loads iterables need to be initialized. :: >>> bodies = [Pa] >>> loads = [(P, g * m * N.x)] The equations of motion are in the form of a differential algebraic equation (DAE) and DAE solvers need to know which of the equations are the algebraic expressions. This information is passed into `SymbolicSystem` as a list specifying which rows are the algebraic equations. In this example it is a different row based on the chosen equations of motion format. The row index should always correspond to the mass matrix that is being input to the `SymbolicSystem` class but will always correspond to the row index of the combined dynamics and kinematics when being accessed from the `SymbolicSystem` class. :: >>> alg_con = [2] >>> alg_con_full = [4] An iterable containing the states now needs to be created for the system. The `SymbolicSystem` class can determine which of the states are considered coordinates or speeds by passing in the indexes of the coordinates and speeds. If these indexes are not passed in the object will not be able to differentiate between coordinates and speeds. :: >>> states = (x, y, u, v, lam) >>> coord_idxs = (0, 1) >>> speed_idxs = (2, 3) Now the equations of motion instances can be created using the above mentioned equations of motion formats. :: >>> symsystem1 = system.SymbolicSystem(states, comb_explicit_rhs, ... alg_con=alg_con_full, bodies=bodies, ... loads=loads) >>> symsystem2 = system.SymbolicSystem(states, comb_implicit_rhs, ... mass_matrix=comb_implicit_mat, ... alg_con=alg_con_full, ... coord_idxs=coord_idxs) >>> symsystem3 = system.SymbolicSystem(states, dyn_implicit_rhs, ... mass_matrix=dyn_implicit_mat, ... coordinate_derivatives=kin_explicit_rhs, ... alg_con=alg_con, ... coord_idxs=coord_idxs, ... speed_idxs=speed_idxs) Like coordinates and speeds, the bodies and loads attributes can only be accessed if they are specified during initialization of the `SymbolicSystem` class. Lastly here are some attributes accessible from the `SymbolicSystem` class. :: >>> symsystem1.states Matrix([ [ x], [ y], [ u], [ v], [lambda]]) >>> symsystem2.coordinates Matrix([ [x], [y]]) >>> symsystem3.speeds Matrix([ [u], [v]]) >>> symsystem1.comb_explicit_rhs Matrix([ [ u], [ v], [(-g*y + u**2 + v**2)*x/l**2], [(-g*y + u**2 + v**2)*y/l**2], [m*(-g*y + u**2 + v**2)/l**2]]) >>> symsystem2.comb_implicit_rhs Matrix([ [ u], [ v], [ 0], [ 0], [-g*y + u**2 + v**2]]) >>> symsystem2.comb_implicit_mat Matrix([ [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, -x/m], [0, 0, 0, 1, -y/m], [0, 0, 0, 0, l**2/m]]) >>> symsystem3.dyn_implicit_rhs Matrix([ [ 0], [ 0], [-g*y + u**2 + v**2]]) >>> symsystem3.dyn_implicit_mat Matrix([ [1, 0, -x/m], [0, 1, -y/m], [0, 0, l**2/m]]) >>> symsystem3.kin_explicit_rhs Matrix([ [u], [v]]) >>> symsystem1.alg_con [4] >>> symsystem1.bodies (Pa,) >>> symsystem1.loads ((P, g*m*N.x),) sympy-sympy-1.9/doc/src/modules/physics/optics/000077500000000000000000000000001412543434000217125ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/optics/gaussopt.rst000066400000000000000000000001541412543434000243110ustar00rootroot00000000000000=============== Gaussian Optics =============== .. automodule:: sympy.physics.optics.gaussopt :members: sympy-sympy-1.9/doc/src/modules/physics/optics/index.rst000066400000000000000000000003451412543434000235550ustar00rootroot00000000000000============== Optics Module ============== .. topic:: Abstract Contains docstrings of Physics-Optics module .. toctree:: :maxdepth: 3 gaussopt.rst medium.rst polarization.rst utils.rst waves.rst sympy-sympy-1.9/doc/src/modules/physics/optics/medium.rst000066400000000000000000000001171412543434000237230ustar00rootroot00000000000000====== Medium ====== .. automodule:: sympy.physics.optics.medium :members: sympy-sympy-1.9/doc/src/modules/physics/optics/polarization.rst000066400000000000000000000001471412543434000251610ustar00rootroot00000000000000============ Polarization ============ .. automodule:: sympy.physics.optics.polarization :members: sympy-sympy-1.9/doc/src/modules/physics/optics/utils.rst000066400000000000000000000001151412543434000236010ustar00rootroot00000000000000Utilities --------- .. automodule:: sympy.physics.optics.utils :members: sympy-sympy-1.9/doc/src/modules/physics/optics/waves.rst000066400000000000000000000001151412543434000235660ustar00rootroot00000000000000====== Waves ====== .. automodule:: sympy.physics.optics.waves :members: sympy-sympy-1.9/doc/src/modules/physics/paulialgebra.rst000066400000000000000000000001431412543434000235710ustar00rootroot00000000000000============= Pauli Algebra ============= .. automodule:: sympy.physics.paulialgebra :members: sympy-sympy-1.9/doc/src/modules/physics/qho_1d.rst000066400000000000000000000002341412543434000223150ustar00rootroot00000000000000================================== Quantum Harmonic Oscillator in 1-D ================================== .. automodule:: sympy.physics.qho_1d :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/000077500000000000000000000000001412543434000221035ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/quantum/anticommutator.rst000066400000000000000000000001601412543434000257000ustar00rootroot00000000000000============== Anticommutator ============== .. automodule:: sympy.physics.quantum.anticommutator :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/cartesian.rst000066400000000000000000000002331412543434000246040ustar00rootroot00000000000000============================== Cartesian Operators and States ============================== .. automodule:: sympy.physics.quantum.cartesian :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/cg.rst000066400000000000000000000002131412543434000232220ustar00rootroot00000000000000=========================== Clebsch-Gordan Coefficients =========================== .. automodule:: sympy.physics.quantum.cg :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/circuitplot.rst000066400000000000000000000001471412543434000252000ustar00rootroot00000000000000============ Circuit Plot ============ .. automodule:: sympy.physics.quantum.circuitplot :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/commutator.rst000066400000000000000000000001401412543434000250220ustar00rootroot00000000000000========== Commutator ========== .. automodule:: sympy.physics.quantum.commutator :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/constants.rst000066400000000000000000000001341412543434000246470ustar00rootroot00000000000000========= Constants ========= .. automodule:: sympy.physics.quantum.constants :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/dagger.rst000066400000000000000000000001201412543434000240570ustar00rootroot00000000000000====== Dagger ====== .. automodule:: sympy.physics.quantum.dagger :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/gate.rst000066400000000000000000000001131412543434000235500ustar00rootroot00000000000000===== Gates ===== .. automodule:: sympy.physics.quantum.gate :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/grover.rst000066400000000000000000000001641412543434000241420ustar00rootroot00000000000000================== Grover's Algorithm ================== .. automodule:: sympy.physics.quantum.grover :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/hilbert.rst000066400000000000000000000001461412543434000242670ustar00rootroot00000000000000============= Hilbert Space ============= .. automodule:: sympy.physics.quantum.hilbert :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/index.rst000066400000000000000000000014061412543434000237450ustar00rootroot00000000000000================= Quantum Mechanics ================= .. topic:: Abstract Contains Docstrings of Physics-Quantum module Quantum Functions ================= .. toctree:: :maxdepth: 3 anticommutator.rst cg.rst commutator.rst constants.rst dagger.rst innerproduct.rst tensorproduct.rst States and Operators ==================== .. toctree:: :maxdepth: 3 cartesian.rst hilbert.rst operator.rst operatorset.rst qapply.rst represent.rst spin.rst state.rst Quantum Computation =================== .. toctree:: :maxdepth: 3 circuitplot.rst gate.rst grover.rst qft.rst qubit.rst shor.rst Analytic Solutions ================== .. toctree:: :maxdepth: 3 piab.rst sympy-sympy-1.9/doc/src/modules/physics/quantum/innerproduct.rst000066400000000000000000000001531412543434000253500ustar00rootroot00000000000000============= Inner Product ============= .. automodule:: sympy.physics.quantum.innerproduct :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/operator.rst000066400000000000000000000001301412543434000244620ustar00rootroot00000000000000======== Operator ======== .. automodule:: sympy.physics.quantum.operator :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/operatorset.rst000066400000000000000000000002401412543434000252000ustar00rootroot00000000000000=============================== Operator/State Helper Functions =============================== .. automodule:: sympy.physics.quantum.operatorset :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/piab.rst000066400000000000000000000001571412543434000235530ustar00rootroot00000000000000================= Particle in a Box ================= .. automodule:: sympy.physics.quantum.piab :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/qapply.rst000066400000000000000000000001201412543434000241340ustar00rootroot00000000000000====== Qapply ====== .. automodule:: sympy.physics.quantum.qapply :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/qft.rst000066400000000000000000000001041412543434000234220ustar00rootroot00000000000000=== QFT === .. automodule:: sympy.physics.quantum.qft :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/qubit.rst000066400000000000000000000001141412543434000237550ustar00rootroot00000000000000===== Qubit ===== .. automodule:: sympy.physics.quantum.qubit :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/represent.rst000066400000000000000000000001341412543434000246420ustar00rootroot00000000000000========= Represent ========= .. automodule:: sympy.physics.quantum.represent :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/shor.rst000066400000000000000000000001541412543434000236100ustar00rootroot00000000000000================ Shor's Algorithm ================ .. automodule:: sympy.physics.quantum.shor :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/spin.rst000066400000000000000000000001101412543434000235760ustar00rootroot00000000000000==== Spin ==== .. automodule:: sympy.physics.quantum.spin :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/state.rst000066400000000000000000000001141412543434000237510ustar00rootroot00000000000000===== State ===== .. automodule:: sympy.physics.quantum.state :members: sympy-sympy-1.9/doc/src/modules/physics/quantum/tensorproduct.rst000066400000000000000000000001571412543434000255530ustar00rootroot00000000000000============== Tensor Product ============== .. automodule:: sympy.physics.quantum.tensorproduct :members: sympy-sympy-1.9/doc/src/modules/physics/secondquant.rst000066400000000000000000000001641412543434000234700ustar00rootroot00000000000000=================== Second Quantization =================== .. automodule:: sympy.physics.secondquant :members: sympy-sympy-1.9/doc/src/modules/physics/sho.rst000066400000000000000000000002311412543434000217300ustar00rootroot00000000000000================================== Quantum Harmonic Oscillator in 3-D ================================== .. automodule:: sympy.physics.sho :members: sympy-sympy-1.9/doc/src/modules/physics/units/000077500000000000000000000000001412543434000215535ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/units/dimensions.rst000066400000000000000000000003471412543434000244610ustar00rootroot00000000000000================================ Dimensions and dimension systems ================================ .. automodule:: sympy.physics.units.dimensions .. autoclass:: Dimension :members: .. autoclass:: DimensionSystem :members: sympy-sympy-1.9/doc/src/modules/physics/units/examples.rst000066400000000000000000000073351412543434000241330ustar00rootroot00000000000000======== Examples ======== In the following sections we give few examples of what can be done with this module. Dimensional analysis ==================== We will start from Newton's second law .. math:: m a = F where :math:`m, a` and :math:`F` are the mass, the acceleration and the force respectively. Knowing the dimensions of :math:`m` (:math:`M`) and :math:`a` (:math:`L T^{-2}`), we will determine the dimension of :math:`F`; obviously we will find that it is a force: :math:`M L T^{-2}`. From there we will use the expression of the gravitational force between the particle of mass :math:`m` and the body of mass :math:`M`, at a distance :math:`r` .. math:: F = \frac{G m M}{r^2} to determine the dimension of the Newton's constant :math:`G`. The result should be :math:`L^3 M^{-1} T^{-2}`. >>> from sympy import symbols >>> from sympy.physics.units.systems import SI >>> from sympy.physics.units import length, mass, acceleration, force >>> from sympy.physics.units import gravitational_constant as G >>> from sympy.physics.units.systems.si import dimsys_SI >>> F = mass*acceleration >>> F Dimension(acceleration*mass) >>> dimsys_SI.get_dimensional_dependencies(F) {'length': 1, 'mass': 1, 'time': -2} >>> dimsys_SI.get_dimensional_dependencies(force) {'length': 1, 'mass': 1, 'time': -2} Dimensions cannot compared directly, even if in the SI convention they are the same: >>> F == force False Dimension system objects provide a way to test the equivalence of dimensions: >>> dimsys_SI.equivalent_dims(F, force) True >>> m1, m2, r = symbols("m1 m2 r") >>> grav_eq = G * m1 * m2 / r**2 >>> F2 = grav_eq.subs({m1: mass, m2: mass, r: length, G: G.dimension}) >>> F2 #doctest: +SKIP Dimension(mass*length*time**-2) >>> F2.get_dimensional_dependencies() #doctest: +SKIP {'length': 1, 'mass': 1, 'time': -2} Note that one should first solve the equation, and then substitute with the dimensions. Equation with quantities ======================== Using Kepler's third law .. math:: \frac{T^2}{a^3} = \frac{4 \pi^2}{GM} we can find the Venus orbital period using the known values for the other variables (taken from Wikipedia). The result should be 224.701 days. >>> from sympy import solve, symbols, pi, Eq >>> from sympy.physics.units import Quantity, length, mass >>> from sympy.physics.units import day, gravitational_constant as G >>> from sympy.physics.units import meter, kilogram >>> T = symbols("T") >>> a = Quantity("venus_a") Specify the dimension and scale in SI units: >>> SI.set_quantity_dimension(a, length) >>> SI.set_quantity_scale_factor(a, 108208000e3*meter) Add the solar mass as quantity: >>> M = Quantity("solar_mass") >>> SI.set_quantity_dimension(M, mass) >>> SI.set_quantity_scale_factor(M, 1.9891e30*kilogram) Now Kepler's law: >>> eq = Eq(T**2 / a**3, 4*pi**2 / G / M) >>> eq Eq(T**2/venus_a**3, 4*pi**2/(gravitational_constant*solar_mass)) >>> q = solve(eq, T)[1] >>> q 2*pi*venus_a**(3/2)/(sqrt(gravitational_constant)*sqrt(solar_mass)) To convert to days, use the ``convert_to`` function (and possibly approximate the outcoming result): >>> from sympy.physics.units import convert_to >>> convert_to(q, day) 71.5112118495813*pi*day >>> convert_to(q, day).n() 224.659097795948*day We could also have the solar mass and the day as units coming from the astrophysical system, but we wanted to show how to create a unit that one needs. We can see in this example that intermediate dimensions can be ill-defined, such as sqrt(G), but one should check that the final result - when all dimensions are combined - is well defined. sympy-sympy-1.9/doc/src/modules/physics/units/index.rst000066400000000000000000000021301412543434000234100ustar00rootroot00000000000000============ Unit systems ============ This module integrates unit systems into SymPy, allowing a user choose which system to use when doing their computations and providing utilities to display and convert units. Unit systems are composed of units and constants, which are themselves described from dimensions and numbers, and possibly a prefix. Quantities are defined by their unit and their numerical value, with respect to the current system. The main advantage of this implementation over the old unit module is that it divides the units in unit systems, so that the user can decide which units to use, instead of having all in the name space (for example astrophysicists can only use units with ua, Earth or Sun masses, the theoricists will use natural system, etc.). Moreover it allows a better control over the dimensions and conversions. Ideas about future developments can be found on the `Github wiki `_. .. toctree:: :maxdepth: 2 philosophy.rst examples.rst dimensions.rst prefixes.rst unitsystem.rst quantities.rst sympy-sympy-1.9/doc/src/modules/physics/units/philosophy.rst000066400000000000000000000233561412543434000245140ustar00rootroot00000000000000============================== Philosophy behind unit systems ============================== Dimensions ========== Introduction ------------ At the root of unit systems are dimension systems, whose structure mainly determines the one of unit systems. Our definition could seem rough but they are largely sufficient for our purposes. A dimension will be defined as a property which is measurable and assigned to a specific phenomenon. In this sense dimensions are different from pure numbers because they carry some extra-sense, and for this reason two different dimensions cannot be added. For example time or length are dimensions, but also any other things which has some sense for us, like angle, number of particles (moles...) or information (bits...). From this point of view the only truly dimensionless quantity are pure numbers. The idea of being dimensionless is very system-dependent, as can be seen from the :math:`(c, \hbar, G)`, in which all units appears to be dimensionless in the usual common sense. This is unavoidable for computability of generic unit systems (but at the end we can tell the program what is dimensionless). Dimensions can be composed together by taking their product or their ratio (to be defined below). For example the velocity is defined as length divided by time, or we can see the length as velocity multiplied by time, depending of what we see as the more fundamental: in general we can select a set of base dimensions from which we can describe all the others. Group structure --------------- After this short introduction whose aim was to introduce the dimensions from an intuitive perspective, we describe the mathematical structure. A dimension system with :math:`n` independent dimensions :math:`\{d_i\}_{i=1,\ldots,n}` is described by a multiplicative group :math:`G`: - there an identity element :math:`1` corresponding to pure numbers; - the product :math:`D_3 = D_1 D_2` of two elements :math:`D_1, D_2 \in G` is also in :math:`G`; - any element :math:`D \in G` has an inverse :math:`D^{-1} \in G`. We denote .. math:: D^n = \underbrace{D \times \cdots \times D}_{\text{$n$ times}}, and by definition :math:`D^0 = 1`. The :math:`\{d_i\}_{i=1,\ldots,n}` are called generators of the group since any element :math:`D \in G` can be expressed as the product of powers of the generators: .. math:: D = \prod_{i=1}^n d_i^{a_i}, \qquad a_i \in \mathbf{Z}. The identity is given for :math:`a_i = 0, \forall i`, while we recover the generator :math:`d_i` for `a_i = 1, a_j = 0, \forall j \neq i`. This group has the following properties: 1. abelian, since the generator commutes, :math:`[d_i, d_j] = 0`; 2. countable (infinite but discrete) since the elements are indexed by the powers of the generators [#]_. One can change the dimension basis :math:`\{d'_i\}_{i=1,\ldots,n}` by taking some combination of the old generators: .. math:: d'_i = \prod_{j=1}^n d_j^{P_{ij}}. Linear space representation --------------------------- It is possible to use the linear space :math:`\mathbf{Z}^n` as a representation of the group since the power coefficients :math:`a_i` carry all the information one needs (we do not distinguish between the element of the group and its representation): .. math:: (d_i)_j = \delta_{ij}, \qquad D = \begin{pmatrix} a_1 \\ \vdots \\ a_n \end{pmatrix}. The change of basis to :math:`d'_i` follows the usual rule of change of basis for linear space, the matrix being given by the coefficients :math:`P_{ij}`, which are simply the coefficients of the new vectors in term of the old basis: .. math:: d'_i = P_{ij} d_j. We will use this last solution in our algorithm. An example ---------- In order to illustrate all this formalism, we end this section with a specific example, the MKS system (m, kg, s) with dimensions (L: length, M: mass, T: time). They are represented as (we will always sort the vectors in alphabetic order) .. math:: L = \begin{pmatrix} 1 \\ 0 \\ 0 \end{pmatrix}, \qquad M = \begin{pmatrix} 0 \\ 1 \\ 0 \end{pmatrix}, \qquad T = \begin{pmatrix} 0 \\ 0 \\ 1 \end{pmatrix}. Other dimensions can be derived, for example velocity :math:`V` or action :math:`A` .. math:: V = L T^{-1}, \qquad A = M L^2 T^{-2},\\ V = \begin{pmatrix} 1 \\ 0 \\ -1 \end{pmatrix}, \qquad A = \begin{pmatrix} 2 \\ 1 \\ -2 \end{pmatrix}. We can change the basis to go to the natural system :math:`(m, c, \hbar)` with dimension (L: length, V: velocity, A: action) [#]_. In this basis the generators are .. math:: A = \begin{pmatrix} 1 \\ 0 \\ 0 \end{pmatrix}, \qquad L = \begin{pmatrix} 0 \\ 1 \\ 0 \end{pmatrix}, \qquad V = \begin{pmatrix} 0 \\ 0 \\ 1 \end{pmatrix}, whereas the mass and time are given by .. math:: T = L V^{-1}, \qquad M = A V^{-2},\\ T = \begin{pmatrix} 0 \\ 1 \\ -1 \end{pmatrix}, \qquad M = \begin{pmatrix} 1 \\ 0 \\ -2 \end{pmatrix}. Finally the inverse change of basis matrix :math:`P^{-1}` is obtained by gluing the vectors expressed in the old basis: .. math:: P^{-1} = \begin{pmatrix} 2 & 1 & 1 \\ 1 & 0 & 0 \\ -2 & 0 & -1 \end{pmatrix}. To find the change of basis matrix we just have to take the inverse .. math:: P = \begin{pmatrix} 0 & 1 & 0 \\ 1 & 0 & 1 \\ 0 & -2 & -1 \end{pmatrix}. Quantities ========== A quantity is defined by its name, dimension and factor to a canonical quantity of the same dimension. The canonical quantities are an internal reference of the units module and should not be relevant for end-users. Both units and physical constants are quantities. Units ----- Units, such as meters, seconds and kilograms, are usually reference quantities chosen by men to refer to other quantities. After defining several units of different dimensions we can form a unit system, which is basically a dimension system with a notion of scale. Constants --------- Physical constants are just quantities. They indicate that we used not to understand that two dimensions are in fact the same. For example, we see a velocity for the light different from 1 because we do not think that time is the same as space (which is normal because of our sense; but it is different at the fundamental level). For example, once there was the "heat constant" which allowed to convert between joules and calories since people did not know that heat was energy. As soon as they understood it they fixed this constant to 1 (this is a very schematic story). We can interpret the fact that now we fix the value of fundamental constants in the SI as showing that they are units (and we use them to define the other usual units). The need for a reference ======================== It is not possible to define from scratch units and unit systems: one needs to define some references, and then build the rest over them. Said in another way, we need an origin for the scales of our units (i.e. a unit with factor 1), and to be sure that all units of a given dimension are defined consistently we need to use the same origin for all of them. This can happen if we want to use a derived unit as a base units in another system: we should not define it as having a scale 1, because, even if it is inconsistent inside the system, we could not convert to the first system since we have two different units (from our point of view) of same scale (which means they are equal for the computer). We will say that the dimensions and scales defined outside systems are canonical, because we use them for all computations. On the other side the dimensions and scales obtained with reference to a system are called physical, because they ultimately carry a sense. Let's use a concrete (and important) example: the case of the mass units. We would like to define the gram as the origin. We would like to define the gram as the canonical origin for the mass, so we assign it a scale 1. Then we can define a system (e.g. in chemistry) that take it as a base unit. The MKS system prefers to use the kilogram; a naive choice would be to attribute it a scale if 1 since it is a base, but we see that we could not convert to the chemistry system because g and kg have both been given the same factor. So we need to define kg as 1000 g, and only then use it as a base in MKS. But as soon as we ask the question "what is the factor of kg in MKS?", we get the answer 1, since it is a base unit. Thus we will define all computations without referring to a system, and it is only at the end that we can plug the result into a system to give the context we are interested in. Literature ========== .. [Page52] C. H. Page, `Classes of units in the SI `_, Am. J. of Phys. 20, 1 (1952): 1. .. [Page78] C. H. Page, `Units and Dimensions in Physics `_, Am. J. of Phys. 46, 1 (1978): 78. .. [deBoer79] J. de Boer, `Group properties of quantities and units `_, Am. J. of Phys. 47, 9 (1979): 818. .. [LevyLeblond77] J.-M. Lévy-Leblond, `On the Conceptual Nature of the Physical Constants `_, La Rivista Del Nuovo Cimento 7, no. 2 (1977): 187-214. .. [NIST] `NIST reference on constants, units and uncertainties `_. .. rubric:: Footnotes .. [#] In general we will consider only dimensions with a maximum coefficient, so we can only a truncation of the group; but this is not useful for the algorithm. .. [#] We anticipate a little by considering :math:`c` and :math:`\hbar` as units and not as physical constants. sympy-sympy-1.9/doc/src/modules/physics/units/prefixes.rst000066400000000000000000000001741412543434000241340ustar00rootroot00000000000000============= Unit prefixes ============= .. automodule:: sympy.physics.units.prefixes .. autoclass:: Prefix :members: sympy-sympy-1.9/doc/src/modules/physics/units/quantities.rst000066400000000000000000000004651412543434000245000ustar00rootroot00000000000000=================== Physical quantities =================== .. automodule:: sympy.physics.units.quantities .. autoclass:: Quantity :members: ----------------------------- Conversion between quantities ----------------------------- .. automodule:: sympy.physics.units.util .. autofunction:: convert_to sympy-sympy-1.9/doc/src/modules/physics/units/unitsystem.rst000066400000000000000000000002351412543434000245310ustar00rootroot00000000000000====================== Units and unit systems ====================== .. automodule:: sympy.physics.units.unitsystem .. autoclass:: UnitSystem :members: sympy-sympy-1.9/doc/src/modules/physics/vector/000077500000000000000000000000001412543434000217135ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/vector/advanced.rst000066400000000000000000000135731412543434000242230ustar00rootroot00000000000000============================================================================ Potential Issues/Advanced Topics/Future Features in Physics/Vector Module ============================================================================ This document will describe some of the more advanced functionality that this module offers but which is not part of the "official" interface. Here, some of the features that will be implemented in the future will also be covered, along with unanswered questions about proper functionality. Also, common problems will be discussed, along with some solutions. Inertia (Dyadics) ================= A dyadic tensor is a second order tensor formed by the juxtaposition of a pair of vectors. There are various operations defined with respect to dyadics, which have been implemented in :obj:`~.sympy.physics.vector` in the form of class :obj:`sympy.physics.vector.dyadic.Dyadic`. To know more, refer to the :obj:`sympy.physics.vector.dyadic.Dyadic` and :obj:`sympy.physics.vector.vector.Vector` class APIs. Dyadics are used to define the inertia of bodies within :mod:`sympy.physics.mechanics`. Inertia dyadics can be defined explicitly but the ``inertia`` function is typically much more convenient for the user:: >>> from sympy.physics.mechanics import ReferenceFrame, inertia >>> N = ReferenceFrame('N') Supply a reference frame and the moments of inertia if the object is symmetrical: >>> inertia(N, 1, 2, 3) (N.x|N.x) + 2*(N.y|N.y) + 3*(N.z|N.z) Supply a reference frame along with the products and moments of inertia for a general object: >>> inertia(N, 1, 2, 3, 4, 5, 6) (N.x|N.x) + 4*(N.x|N.y) + 6*(N.x|N.z) + 4*(N.y|N.x) + 2*(N.y|N.y) + 5*(N.y|N.z) + 6*(N.z|N.x) + 5*(N.z|N.y) + 3*(N.z|N.z) Notice that the ``inertia`` function returns a dyadic with each component represented as two unit vectors separated by a ``|``. Refer to the :obj:`sympy.physics.vector.dyadic.Dyadic` section for more information about dyadics. Inertia is often expressed in a matrix, or tensor, form, especially for numerical purposes. Since the matrix form does not contain any information about the reference frame(s) the inertia dyadic is defined in, you must provide one or two reference frames to extract the measure numbers from the dyadic. There is a convenience function to do this:: >>> inertia(N, 1, 2, 3, 4, 5, 6).to_matrix(N) Matrix([ [1, 4, 6], [4, 2, 5], [6, 5, 3]]) Common Issues ============= Here issues with numerically integrating code, choice of `dynamicsymbols` for coordinate and speed representation, printing, differentiating, and substitution will occur. Printing -------- The default printing options are to use sorting for ``Vector`` and ``Dyadic`` measure numbers, and have unsorted output from the ``vprint``, ``vpprint``, and ``vlatex`` functions. If you are printing something large, please use one of those functions, as the sorting can increase printing time from seconds to minutes. Substitution ------------ Substitution into large expressions can be slow, and take a few minutes. Acceleration of Points ---------------------- At a minimum, points need to have their velocities defined, as the acceleration can be calculated by taking the time derivative of the velocity in the same frame. If the 1 point or 2 point theorems were used to compute the velocity, the time derivative of the velocity expression will most likely be more complex than if you were to use the acceleration level 1 point and 2 point theorems. Using the acceleration level methods can result in shorted expressions at this point, which will result in shorter expressions later (such as when forming Kane's equations). Advanced Interfaces =================== Here we will cover advanced options in: ``ReferenceFrame``, ``dynamicsymbols``, and some associated functionality. ReferenceFrame -------------- ``ReferenceFrame`` is shown as having a ``.name`` attribute and ``.x``, ``.y``, and ``.z`` attributes for accessing the basis vectors, as well as a fairly rigidly defined print output. If you wish to have a different set of indices defined, there is an option for this. This will also require a different interface for accessing the basis vectors. :: >>> from sympy.physics.vector import ReferenceFrame, vprint, vpprint, vlatex >>> N = ReferenceFrame('N', indices=['i', 'j', 'k']) >>> N['i'] N['i'] >>> N.x N['i'] >>> vlatex(N.x) '\\mathbf{\\hat{n}_{i}}' Also, the latex output can have custom strings; rather than just indices though, the entirety of each basis vector can be specified. The custom latex strings can occur without custom indices, and also overwrites the latex string that would be used if there were custom indices. :: >>> from sympy.physics.vector import ReferenceFrame, vlatex >>> N = ReferenceFrame('N', latexs=['n1','\\mathbf{n}_2','cat']) >>> vlatex(N.x) 'n1' >>> vlatex(N.y) '\\mathbf{n}_2' >>> vlatex(N.z) 'cat' dynamicsymbols -------------- The ``dynamicsymbols`` function also has 'hidden' functionality; the variable which is associated with time can be changed, as well as the notation for printing derivatives. :: >>> from sympy import symbols >>> from sympy.physics.vector import dynamicsymbols, vprint >>> q1 = dynamicsymbols('q1') >>> q1 q1(t) >>> dynamicsymbols._t = symbols('T') >>> q2 = dynamicsymbols('q2') >>> q2 q2(T) >>> q1 q1(t) >>> q1d = dynamicsymbols('q1', 1) >>> vprint(q1d) q1' >>> dynamicsymbols._str = 'd' >>> vprint(q1d) q1d >>> dynamicsymbols._str = '\'' >>> dynamicsymbols._t = symbols('t') Note that only dynamic symbols created after the change are different. The same is not true for the `._str` attribute; this affects the printing output only, so dynamic symbols created before or after will print the same way. Also note that ``Vector``'s ``.dt`` method uses the ``._t`` attribute of ``dynamicsymbols``, along with a number of other important functions and methods. Don't mix and match symbols representing time. sympy-sympy-1.9/doc/src/modules/physics/vector/api/000077500000000000000000000000001412543434000224645ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/physics/vector/api/classes.rst000066400000000000000000000006401412543434000246530ustar00rootroot00000000000000================= Essential Classes ================= CoordinateSym ============= .. autoclass:: sympy.physics.vector.frame.CoordinateSym :members: ReferenceFrame ============== .. autoclass:: sympy.physics.vector.frame.ReferenceFrame :members: Vector ====== .. autoclass:: sympy.physics.vector.vector.Vector :members: Dyadic ====== .. autoclass:: sympy.physics.vector.dyadic.Dyadic :members: sympy-sympy-1.9/doc/src/modules/physics/vector/api/fieldfunctions.rst000066400000000000000000000017651412543434000262430ustar00rootroot00000000000000==================================== Docstrings for basic field functions ==================================== Field operation functions ========================= These functions implement some basic operations pertaining to fields in general. curl ---- .. autofunction:: sympy.physics.vector.fieldfunctions.curl divergence ---------- .. autofunction:: sympy.physics.vector.fieldfunctions.divergence gradient -------- .. autofunction:: sympy.physics.vector.fieldfunctions.gradient scalar_potential ---------------- .. autofunction:: sympy.physics.vector.fieldfunctions.scalar_potential scalar_potential_difference --------------------------- .. autofunction:: sympy.physics.vector.fieldfunctions.scalar_potential_difference Checking the type of vector field ================================= is_conservative --------------- .. autofunction:: sympy.physics.vector.fieldfunctions.is_conservative is_solenoidal ------------- .. autofunction:: sympy.physics.vector.fieldfunctions.is_solenoidal sympy-sympy-1.9/doc/src/modules/physics/vector/api/functions.rst000066400000000000000000000010651412543434000252300ustar00rootroot00000000000000================================ Essential Functions (Docstrings) ================================ dynamicsymbols -------------- .. autofunction:: sympy.physics.vector.dynamicsymbols dot --- .. autofunction:: sympy.physics.vector.functions.dot cross ----- .. autofunction:: sympy.physics.vector.functions.cross outer ----- .. autofunction:: sympy.physics.vector.functions.outer express ------- .. autofunction:: sympy.physics.vector.functions.express time_derivative --------------- .. autofunction:: sympy.physics.vector.functions.time_derivative sympy-sympy-1.9/doc/src/modules/physics/vector/api/kinematics.rst000066400000000000000000000004771412543434000253550ustar00rootroot00000000000000.. _kinematics: ======================= Kinematics (Docstrings) ======================= Point ===== .. automodule:: sympy.physics.vector.point :members: kinematic_equations =================== .. automodule:: sympy.physics.vector.functions :members: kinematic_equations, partial_velocity, get_motion_params sympy-sympy-1.9/doc/src/modules/physics/vector/api/printing.rst000066400000000000000000000005731412543434000250550ustar00rootroot00000000000000===================== Printing (Docstrings) ===================== init_vprinting ============== .. autofunction:: sympy.physics.vector.printing.init_vprinting vprint ====== .. autofunction:: sympy.physics.vector.printing.vprint vpprint ======= .. autofunction:: sympy.physics.vector.printing.vpprint vlatex ====== .. autofunction:: sympy.physics.vector.printing.vlatex sympy-sympy-1.9/doc/src/modules/physics/vector/fields.rst000066400000000000000000000324721412543434000237230ustar00rootroot00000000000000===================================== Scalar and Vector Field Functionality ===================================== Introduction ============ Vectors and Scalars ------------------- In physics, we deal with two kinds of quantities – scalars and vectors. A scalar is an entity which only has a magnitude – no direction. Examples of scalar quantities include mass, electric charge, temperature, distance, etc. A vector, on the other hand, is an entity that is characterized by a magnitude and a direction. Examples of vector quantities are displacement, velocity, magnetic field, etc. A scalar can be depicted just by a number, for e.g. a temperature of 300 K. On the other hand, vectorial quantities like acceleration are usually denoted by a vector. Given a vector :math:`\mathbf{V}`, the magnitude of the corresponding quantity can be calculated as the magnitude of the vector itself :math:`\Vert \mathbf{V} \Vert`, while the direction would be specified by a unit vector in the direction of the original vector, :math:`\mathbf{\hat{V}} = \frac{\mathbf{V}}{\Vert \mathbf{V} \Vert}`. For example, consider a displacement of :math:`(3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}})` m, where , as per standard convention, :math:`\mathbf{\hat{i}}`, :math:`\mathbf{\hat{j}}` and :math:`\mathbf{\hat{k}}` represent unit vectors in the :math:`\mathbf{X}`, :math:`\mathbf{Y}` and :math:`\mathbf{Z}` directions respectively. Therefore, it can be concluded that the distance traveled is :math:`\Vert 3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}} \Vert` m = :math:`5\sqrt{2}` m. The direction of travel is given by the unit vector :math:`\frac{3}{5\sqrt{2}}\mathbf{\hat{i}} + \frac{4}{5\sqrt{2}}\mathbf{\hat{j}} + \frac{5}{5\sqrt{2}}\mathbf{\hat{k}}`. Fields ------ In general, a :math:`field` is a vector or scalar quantity that can be specified everywhere in space as a function of position (Note that in general a field may also be dependent on time and other custom variables). In this module, we deal with 3-dimensional spaces only. Hence, a field is defined as a function of the :math:`x`, :math:`y` and :math:`z` coordinates corresponding to a location in 3D space. For example, temperate in 3 dimensional space (a temperature field) can be written as :math:`T(x, y, z)` – a scalar function of the position. An example of a scalar field in electromagnetism is the electric potential. In a similar manner, a vector field can be defined as a vectorial function of the location :math:`(x, y, z)` of any point in space. For instance, every point on the earth may be considered to be in the gravitational force field of the earth. We may specify the field by the magnitude and the direction of acceleration due to gravity (i.e. force per unit mass ) :math:`g(x, y, z)` at every point in space. To give an example from electromagnetism, consider an electric potential of form :math:`2{x}^{2}y`, a scalar field in 3D space. The corresponding conservative electric field can be computed as the gradient of the electric potential function, and expressed as :math:`4xy\mathbf{\hat{i}} + 2{x}^{2}\mathbf{\hat{j}}`. The magnitude of this electric field can in turn be expressed as a scalar field of the form :math:`\sqrt{4{x}^{4} + 16{x}^{2}{y}^{2}}`. Implementation of fields in sympy.physics.vector ================================================ In :mod:`sympy.physics.vector`, every :obj:`~.ReferenceFrame` instance is assigned basis vectors corresponding to the :math:`X`, :math:`Y` and :math:`Z` directions. These can be accessed using the attributes named ``x``, ``y`` and ``z`` respectively. Hence, to define a vector :math:`\mathbf{v}` of the form :math:`3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}}` with respect to a given frame :math:`\mathbf{R}`, you would do >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> v = 3*R.x + 4*R.y + 5*R.z Vector math and basic calculus operations with respect to vectors have already been elaborated upon in other sections of this module's documentation. On the other hand, base scalars (or coordinate variables) are implemented as special SymPy :obj:`~sympy.core.symbol.Symbol`\ s assigned to every frame, one for each direction from :math:`X`, :math:`Y` and :math:`Z`. For a frame ``R``, the :math:`X`, :math:`Y` and :math:`Z` base scalar :obj:`~sympy.core.symbol.Symbol`\ s can be accessed using the ``R[0]``, ``R[1]`` and ``R[2]`` expressions respectively. Therefore, to generate the expression for the aforementioned electric potential field :math:`2{x}^{2}y`, you would have to do >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> electric_potential = 2*R[0]**2*R[1] >>> electric_potential 2*R_x**2*R_y In string representation, ``R_x`` denotes the :math:`X` base scalar assigned to :obj:`~.ReferenceFrame` ``R``. Essentially, ``R_x`` is the string representation of ``R[0]``. Scalar fields can be treated just as any other SymPy expression, for any math/calculus functionality. Hence, to differentiate the above electric potential with respect to :math:`x` (i.e. ``R[0]``), you would have to use the :obj:`~sympy.core.function.diff` function. >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> electric_potential = 2*R[0]**2*R[1] >>> from sympy import diff >>> diff(electric_potential, R[0]) 4*R_x*R_y Like vectors (and vector fields), scalar fields can also be re-expressed in other frames of reference, apart from the one they were defined in – assuming that an orientation relationship exists between the concerned frames. This can be done using the :obj:`sympy.physics.vector.vector.Vector.express` method, in a way similar to vectors - but with the ``variables`` parameter set to ``True``. >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> electric_potential = 2*R[0]**2*R[1] >>> from sympy.physics.vector import dynamicsymbols, express >>> q = dynamicsymbols('q') >>> R1 = R.orientnew('R1', rot_type = 'Axis', amounts = [q, R.z]) >>> express(electric_potential, R1, variables=True) 2*(R1_x*sin(q(t)) + R1_y*cos(q(t)))*(R1_x*cos(q(t)) - R1_y*sin(q(t)))**2 Moreover, considering scalars can also be functions of time just as vectors, differentiation with respect to time is also possible. Depending on the :obj:`~sympy.core.symbol.Symbol`\ s present in the expression and the frame with respect to which the time differentiation is being done, the output will change/remain the same. >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> electric_potential = 2*R[0]**2*R[1] >>> q = dynamicsymbols('q') >>> R1 = R.orientnew('R1', rot_type = 'Axis', amounts = [q, R.z]) >>> from sympy.physics.vector import time_derivative >>> time_derivative(electric_potential, R) 0 >>> time_derivative(electric_potential, R1).simplify() 2*(R1_x*cos(q(t)) - R1_y*sin(q(t)))*(3*R1_x**2*cos(2*q(t))/2 - R1_x**2/2 - 3*R1_x*R1_y*sin(2*q(t)) - 3*R1_y**2*cos(2*q(t))/2 - R1_y**2/2)*Derivative(q(t), t) Field operators and other related functions =========================================== Here we describe some basic field-related functionality implemented in sympy.physics.vector Curl ---- A curl is a mathematical operator that describes an infinitesimal rotation of a vector in 3D space. The direction is determined by the right-hand rule (along the axis of rotation), and the magnitude is given by the magnitude of rotation. In the 3D Cartesian system, the curl of a 3D vector :math:`\mathbf{F}` , denoted by :math:`\nabla \times \mathbf{F}` is given by - :math:`\nabla \times \mathbf{F} = \left(\frac{\partial F_z}{\partial y} - \frac{\partial F_y}{\partial z}\right) \mathbf{\hat{i}} + \left(\frac{\partial F_x}{\partial z} - \frac{\partial F_z}{\partial x}\right) \mathbf{\hat{j}} + \left(\frac{\partial F_y}{\partial x} - \frac{\partial F_x}{\partial y}\right) \mathbf{\hat{k}}` where :math:`F_x` denotes the :math:`X` component of vector :math:`\mathbf{F}`. To compute the curl of a vector field in :mod:`sympy.physics.vector`, you would do >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> from sympy.physics.vector import curl >>> field = R[0]*R[1]*R[2]*R.x >>> curl(field, R) R_x*R_y*R.y - R_x*R_z*R.z Divergence ---------- Divergence is a vector operator that measures the magnitude of a vector field's source or sink at a given point, in terms of a signed scalar. The divergence operator always returns a scalar after operating on a vector. In the 3D Cartesian system, the divergence of a 3D vector :math:`\mathbf{F}`, denoted by :math:`\nabla\cdot\mathbf{F}` is given by - :math:`\nabla\cdot\mathbf{F} =\frac{\partial U}{\partial x} +\frac{\partial V}{\partial y} +\frac{\partial W}{\partial z }` where :math:`U`, :math:`V` and :math:`W` denote the :math:`X`, :math:`Y` and :math:`Z` components of :math:`\mathbf{F}` respectively. To compute the divergence of a vector field in :mod:`sympy.physics.vector`, you would do >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> from sympy.physics.vector import divergence >>> field = R[0]*R[1]*R[2] * (R.x+R.y+R.z) >>> divergence(field, R) R_x*R_y + R_x*R_z + R_y*R_z Gradient -------- Consider a scalar field :math:`f(x, y, z)` in 3D space. The gradient of this field is defined as the vector of the 3 partial derivatives of :math:`f` with respect to :math:`x`, :math:`y` and :math:`z` in the :math:`X`, :math:`Y` and :math:`Z` directions respectively. In the 3D Cartesian system, the gradient of a scalar field :math:`f`, denoted by :math:`\nabla f` is given by - :math:`\nabla f = \frac{\partial f}{\partial x} \mathbf{\hat{i}} + \frac{\partial f}{\partial y} \mathbf{\hat{j}} + \frac{\partial f}{\partial z} \mathbf{\hat{k}}` To compute the gradient of a scalar field in :mod:`sympy.physics.vector`, you would do >>> from sympy.physics.vector import ReferenceFrame >>> R = ReferenceFrame('R') >>> from sympy.physics.vector import gradient >>> scalar_field = R[0]*R[1]*R[2] >>> gradient(scalar_field, R) R_y*R_z*R.x + R_x*R_z*R.y + R_x*R_y*R.z Conservative and Solenoidal fields ---------------------------------- In vector calculus, a conservative field is a field that is the gradient of some scalar field. Conservative fields have the property that their line integral over any path depends only on the end-points, and is independent of the path between them. A conservative vector field is also said to be 'irrotational', since the curl of a conservative field is always zero. In physics, conservative fields represent forces in physical systems where energy is conserved. To check if a vector field is conservative in :mod:`sympy.physics.vector`, use the :obj:`sympy.physics.vector.fieldfunctions.is_conservative` function. >>> from sympy.physics.vector import ReferenceFrame, is_conservative >>> R = ReferenceFrame('R') >>> field = R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z >>> is_conservative(field) True >>> curl(field, R) 0 A solenoidal field, on the other hand, is a vector field whose divergence is zero at all points in space. To check if a vector field is solenoidal in :mod:`sympy.physics.vector`, use the :obj:`sympy.physics.vector.fieldfunctions.is_solenoidal` function. >>> from sympy.physics.vector import ReferenceFrame, is_solenoidal >>> R = ReferenceFrame('R') >>> field = R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z >>> is_solenoidal(field) True >>> divergence(field, R) 0 Scalar potential functions -------------------------- We have previously mentioned that every conservative field can be defined as the gradient of some scalar field. This scalar field is also called the 'scalar potential field' corresponding to the aforementioned conservative field. The :obj:`sympy.physics.vector.fieldfunctions.scalar_potential` function in :mod:`sympy.physics.vector` calculates the scalar potential field corresponding to a given conservative vector field in 3D space - minus the extra constant of integration, of course. Example of usage - >>> from sympy.physics.vector import ReferenceFrame, scalar_potential >>> R = ReferenceFrame('R') >>> conservative_field = 4*R[0]*R[1]*R[2]*R.x + 2*R[0]**2*R[2]*R.y + 2*R[0]**2*R[1]*R.z >>> scalar_potential(conservative_field, R) 2*R_x**2*R_y*R_z Providing a non-conservative vector field as an argument to :obj:`sympy.physics.vector.fieldfunctions.scalar_potential` raises a ``ValueError``. The scalar potential difference, or simply 'potential difference', corresponding to a conservative vector field can be defined as the difference between the values of its scalar potential function at two points in space. This is useful in calculating a line integral with respect to a conservative function, since it depends only on the endpoints of the path. This computation is performed as follows in :mod:`sympy.physics.vector`. >>> from sympy.physics.vector import ReferenceFrame, Point >>> from sympy.physics.vector import scalar_potential_difference >>> R = ReferenceFrame('R') >>> O = Point('O') >>> P = O.locatenew('P', 1*R.x + 2*R.y + 3*R.z) >>> vectfield = 4*R[0]*R[1]*R.x + 2*R[0]**2*R.y >>> scalar_potential_difference(vectfield, R, O, P, O) 4 If provided with a scalar expression instead of a vector field, :obj:`sympy.physics.vector.fieldfunctions.scalar_potential_difference` returns the difference between the values of that scalar field at the two given points in space. sympy-sympy-1.9/doc/src/modules/physics/vector/index.rst000066400000000000000000000022411412543434000235530ustar00rootroot00000000000000.. _physics_vector: ========================= The Physics Vector Module ========================= .. topic:: Abstract In this documentation the components of the sympy.physics.vector module have been discussed. :mod:`sympy.physics.vector` has been written to facilitate the operations pertaining to 3-dimensional vectors, as functions of time or otherwise, in :mod:`sympy.physics`. .. module:: sympy.physics.vector References for Physics/Vector ================================ .. [WikiDyadics] "Dyadics." Wikipedia, the Free Encyclopedia. Web. 05 Aug. 2011. . .. [WikiDyadicProducts] "Dyadic Product." Wikipedia, the Free Encyclopedia. Web. 05 Aug. 2011. . .. [Likins1973] Likins, Peter W. Elements of Engineering Mechanics. McGraw-Hill, Inc. 1973. Print. Guide to Vector =============== .. toctree:: :maxdepth: 2 vectors.rst kinematics.rst advanced.rst fields.rst Vector API ========== .. toctree:: :maxdepth: 2 api/classes.rst api/kinematics.rst api/printing.rst api/functions.rst api/fieldfunctions.rst sympy-sympy-1.9/doc/src/modules/physics/vector/kin_1.svg000066400000000000000000000210231412543434000234330ustar00rootroot00000000000000 image/svg+xml P O N rOP sympy-sympy-1.9/doc/src/modules/physics/vector/kin_1pt.svg000066400000000000000000000622431412543434000240100ustar00rootroot00000000000000 image/svg+xml B N Ofixed in N Pnot fixed in B Sfixed in B sympy-sympy-1.9/doc/src/modules/physics/vector/kin_2.svg000066400000000000000000000326301412543434000234420ustar00rootroot00000000000000 image/svg+xml N nx ny nz B O P bz by bx rOP sympy-sympy-1.9/doc/src/modules/physics/vector/kin_2pt.svg000066400000000000000000000373601412543434000240130ustar00rootroot00000000000000 image/svg+xml N B Ofixed in N Pfixed in B Sfixed in B sympy-sympy-1.9/doc/src/modules/physics/vector/kin_3.svg000066400000000000000000000277531412543434000234550ustar00rootroot00000000000000 image/svg+xml nx ny bx by cx cy P Q O N B C sympy-sympy-1.9/doc/src/modules/physics/vector/kin_4.svg000066400000000000000000000431261412543434000234460ustar00rootroot00000000000000 image/svg+xml O P Q nx nz ny q1 q2 cx cy cz C N sympy-sympy-1.9/doc/src/modules/physics/vector/kin_angvel1.svg000066400000000000000000000310231412543434000246310ustar00rootroot00000000000000 image/svg+xml B N ny nx nz nx NwB=q nx sympy-sympy-1.9/doc/src/modules/physics/vector/kin_angvel2.svg000066400000000000000000000554751412543434000246530ustar00rootroot00000000000000 image/svg+xml nx ny nz q1 q2 q3 ax bz cy A B C D N sympy-sympy-1.9/doc/src/modules/physics/vector/kin_angvel3.svg000066400000000000000000000334311412543434000246400ustar00rootroot00000000000000 image/svg+xml p1 w1 w2 p2 p3 w3 sympy-sympy-1.9/doc/src/modules/physics/vector/kin_rolling.svg000066400000000000000000000253611412543434000247520ustar00rootroot00000000000000 image/svg+xml A B N P Pa is the contact point on body A Pb is the contact point on body B Rolling without slip iff: NvPa = NvPb sympy-sympy-1.9/doc/src/modules/physics/vector/kinematics.rst000066400000000000000000000523441412543434000246040ustar00rootroot00000000000000===================== Vector: Kinematics ===================== This document will give some mathematical background to describing a system's kinematics as well as how to represent the kinematics in :mod:`sympy.physics.vector`. Introduction to Kinematics ========================== The first topic is rigid motion kinematics. A rigid body is an idealized representation of a physical object which has mass and rotational inertia. Rigid bodies are obviously not flexible. We can break down rigid body motion into translational motion, and rotational motion (when dealing with particles, we only have translational motion). Rotational motion can further be broken down into simple rotations and general rotations. Translation of a rigid body is defined as a motion where the orientation of the body does not change during the motion; or during the motion any line segment would be parallel to itself at the start of the motion. Simple rotations are rotations in which the orientation of the body may change, but there is always one line which remains parallel to itself at the start of the motion. General rotations are rotations which there is not always one line parallel to itself at the start of the motion. Angular Velocity ---------------- The angular velocity of a rigid body refers to the rate of change of its orientation. The angular velocity of a body is written down as: :math:`^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}`, or the angular velocity of :math:`\mathbf{B}` in :math:`\mathbf{N}`, which is a vector. Note that here, the term rigid body was used, but reference frames can also have angular velocities. Further discussion of the distinction between a rigid body and a reference frame will occur later when describing the code representation. Angular velocity is defined as being positive in the direction which causes the orientation angles to increase (for simple rotations, or series of simple rotations). .. image:: kin_angvel1.* :height: 350 :width: 250 :align: center The angular velocity vector represents the time derivative of the orientation. As a time derivative vector quantity, like those covered in the Vector & ReferenceFrame documentation, this quantity (angular velocity) needs to be defined in a reference frame. That is what the :math:`\mathbf{N}` is in the above definition of angular velocity; the frame in which the angular velocity is defined in. The angular velocity of :math:`\mathbf{B}` in :math:`\mathbf{N}` can also be defined by: .. math:: ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}} = (\frac{^{\mathbf{N}}d \mathbf{\hat{b}_y}}{dt}\cdot\mathbf{\hat{b}_z} )\mathbf{\hat{b}_x} + (\frac{^{\mathbf{N}}d \mathbf{\hat{b}_z}}{dt}\cdot \mathbf{\hat{b}_x})\mathbf{\hat{b}_y} + (\frac{^{\mathbf{N}}d \mathbf{\hat{b}_x}}{dt}\cdot\mathbf{\hat{b}_y})\mathbf{\hat{b}_z} It is also common for a body's angular velocity to be written as: .. math:: ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}} = w_x \mathbf{\hat{b}_x} + w_y \mathbf{\hat{b}_y} + w_z \mathbf{\hat{b}_z} There are a few additional important points relating to angular velocity. The first is the addition theorem for angular velocities, a way of relating the angular velocities of multiple bodies and frames. The theorem follows: .. math:: ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{D}} = ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{A}} + ^{\mathbf{A}}\mathbf{\omega}^{\mathbf{B}} + ^{\mathbf{B}}\mathbf{\omega}^{\mathbf{C}} + ^{\mathbf{C}}\mathbf{\omega}^{\mathbf{D}} This is also shown in the following example: .. image:: kin_angvel2.* :height: 300 :width: 450 :align: center .. math:: ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{A}} &= 0\\ ^{\mathbf{A}}\mathbf{\omega}^{\mathbf{B}} &= \dot{q_1} \mathbf{\hat{a}_x}\\ ^{\mathbf{B}}\mathbf{\omega}^{\mathbf{C}} &= - \dot{q_2} \mathbf{\hat{b}_z}\\ ^{\mathbf{C}}\mathbf{\omega}^{\mathbf{D}} &= \dot{q_3} \mathbf{\hat{c}_y}\\ ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{D}} &= \dot{q_1} \mathbf{\hat{a}_x} - \dot{q_2} \mathbf{\hat{b}_z} + \dot{q_3} \mathbf{\hat{c}_y}\\ Note the signs used in the angular velocity definitions, which are related to how the displacement angle is defined in this case. This theorem makes defining angular velocities of multibody systems much easier, as the angular velocity of a body in a chain needs to only be defined to the previous body in order to be fully defined (and the first body needs to be defined in the desired reference frame). The following figure shows an example of when using this theorem can make things easier. .. image:: kin_angvel3.* :height: 250 :width: 400 :align: center Here we can easily write the angular velocity of the body :math:`\mathbf{D}` in the reference frame of the first body :math:`\mathbf{A}`: .. math:: ^\mathbf{A}\mathbf{\omega}^\mathbf{D} = w_1 \mathbf{\hat{p_1}} + w_2 \mathbf{\hat{p_2}} + w_3 \mathbf{\hat{p_3}}\\ It is very important to remember to only use this with angular velocities; you cannot use this theorem with the velocities of points. There is another theorem commonly used: the derivative theorem. It provides an alternative method (which can be easier) to calculate the time derivative of a vector in a reference frame: .. math:: \frac{^{\mathbf{N}} d \mathbf{v}}{dt} = \frac{^{\mathbf{B}} d \mathbf{v}}{dt} + ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}} \times \mathbf{v} The vector :math:`\mathbf{v}` can be any vector quantity: a position vector, a velocity vector, angular velocity vector, etc. Instead of taking the time derivative of the vector in :math:`\mathbf{N}`, we take it in :math:`\mathbf{B}`, where :math:`\mathbf{B}` can be any reference frame or body, usually one in which it is easy to take the derivative on :math:`\mathbf{v}` in (:math:`\mathbf{v}` is usually composed only of the basis vector set belonging to :math:`\mathbf{B}`). Then we add the cross product of the angular velocity of our newer frame, :math:`^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}` and our vector quantity :math:`\mathbf{v}`. Again, you can choose any alternative frame for this. Examples follow: .. % need multiple examples here showing the derivative theorem Angular Acceleration -------------------- Angular acceleration refers to the time rate of change of the angular velocity vector. Just as the angular velocity vector is for a body and is specified in a frame, the angular acceleration vector is for a body and is specified in a frame: :math:`^{\mathbf{N}}\mathbf{\alpha}^{\mathbf{B}}`, or the angular acceleration of :math:`\mathbf{B}` in :math:`\mathbf{N}`, which is a vector. Calculating the angular acceleration is relatively straight forward: .. math:: ^{\mathbf{N}}\mathbf{\alpha}^{\mathbf{B}} = \frac{^{\mathbf{N}} d ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}}{dt} Note that this can be calculated with the derivative theorem, and when the angular velocity is defined in a body fixed frame, becomes quite simple: .. math:: ^{\mathbf{N}}\mathbf{\alpha}^{\mathbf{B}} &= \frac{^{\mathbf{N}} d ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}}{dt}\\ ^{\mathbf{N}}\mathbf{\alpha}^{\mathbf{B}} &= \frac{^{\mathbf{B}} d ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}}{dt} + ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}} \times ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}\\ \textrm{if } ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}} &= w_x \mathbf{\hat{b}_x} + w_y \mathbf{\hat{b}_y} + w_z \mathbf{\hat{b}_z}\\ \textrm{then } ^{\mathbf{N}}\mathbf{\alpha}^{\mathbf{B}} &= \frac{^{\mathbf{B}} d ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}}{dt} + \underbrace{^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}} \times ^{\mathbf{N}}\mathbf{\omega}^{\mathbf{B}}}_{ \textrm{this is 0 by definition}}\\ ^{\mathbf{N}}\mathbf{\alpha}^{\mathbf{B}}&=\frac{d w_x}{dt}\mathbf{\hat{b}_x} + \frac{d w_y}{dt}\mathbf{\hat{b}_y} + \frac{d w_z}{dt}\mathbf{\hat{b}_z}\\ ^{\mathbf{N}}\mathbf{\alpha}^{\mathbf{B}}&= \dot{w_x}\mathbf{\hat{b}_x} + \dot{w_y}\mathbf{\hat{b}_y} + \dot{w_z}\mathbf{\hat{b}_z}\\ Again, this is only for the case in which the angular velocity of the body is defined in body fixed components. Point Velocity & Acceleration ----------------------------- Consider a point, :math:`P`: we can define some characteristics of the point. First, we can define a position vector from some other point to :math:`P`. Second, we can define the velocity vector of :math:`P` in a reference frame of our choice. Third, we can define the acceleration vector of :math:`P` in a reference frame of our choice. These three quantities are read as: .. math:: \mathbf{r}^{OP} \textrm{, the position vector from } O \textrm{ to }P\\ ^{\mathbf{N}}\mathbf{v}^P \textrm{, the velocity of } P \textrm{ in the reference frame } \mathbf{N}\\ ^{\mathbf{N}}\mathbf{a}^P \textrm{, the acceleration of } P \textrm{ in the reference frame } \mathbf{N}\\ Note that the position vector does not have a frame associated with it; this is because there is no time derivative involved, unlike the velocity and acceleration vectors. We can find these quantities for a simple example easily: .. image:: kin_1.* :height: 300 :width: 300 :align: center .. math:: \textrm{Let's define: } \mathbf{r}^{OP} &= q_x \mathbf{\hat{n}_x} + q_y \mathbf{\hat{n}_y}\\ ^{\mathbf{N}}\mathbf{v}^P &= \frac{^{\mathbf{N}} d \mathbf{r}^{OP}}{dt}\\ \textrm{then we can calculate: } ^{\mathbf{N}}\mathbf{v}^P &= \dot{q}_x\mathbf{\hat{n}_x} + \dot{q}_y\mathbf{\hat{n}_y}\\ \textrm{and :} ^{\mathbf{N}}\mathbf{a}^P &= \frac{^{\mathbf{N}} d ^{\mathbf{N}}\mathbf{v}^P}{dt}\\ ^{\mathbf{N}}\mathbf{a}^P &= \ddot{q}_x\mathbf{\hat{n}_x} + \ddot{q}_y\mathbf{\hat{n}_y}\\ It is critical to understand in the above example that the point :math:`O` is fixed in the reference frame :math:`\mathbf{N}`. There is no addition theorem for translational velocities; alternatives will be discussed later though. Also note that the position of every point might not always need to be defined to form the dynamic equations of motion. When you don't want to define the position vector of a point, you can start by just defining the velocity vector. For the above example: .. math:: \textrm{Let us instead define the velocity vector as: } ^{\mathbf{N}}\mathbf{v}^P &= u_x \mathbf{\hat{n}_x} + u_y \mathbf{\hat{n}_y}\\ \textrm{then acceleration can be written as: } ^{\mathbf{N}}\mathbf{a}^P &= \dot{u}_x \mathbf{\hat{n}_x} + \dot{u}_y \mathbf{\hat{n}_y}\\ There will often be cases when the velocity of a point is desired and a related point's velocity is known. For the cases in which we have two points fixed on a rigid body, we use the 2-Point Theorem: .. image:: kin_2pt.* :height: 300 :width: 300 :align: center Let's say we know the velocity of the point :math:`S` and the angular velocity of the body :math:`\mathbf{B}`, both defined in the reference frame :math:`\mathbf{N}`. We can calculate the velocity and acceleration of the point :math:`P` in :math:`\mathbf{N}` as follows: .. math:: ^{\mathbf{N}}\mathbf{v}^P &= ^\mathbf{N}\mathbf{v}^S + ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times \mathbf{r}^{SP}\\ ^{\mathbf{N}}\mathbf{a}^P &= ^\mathbf{N}\mathbf{a}^S + ^\mathbf{N}\mathbf{\alpha}^\mathbf{B} \times \mathbf{r}^{SP} + ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times (^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times \mathbf{r}^{SP})\\ When only one of the two points is fixed on a body, the 1 point theorem is used instead. .. image:: kin_1pt.* :height: 400 :width: 400 :align: center Here, the velocity of point :math:`S` is known in the frame :math:`\mathbf{N}`, the angular velocity of :math:`\mathbf{B}` is known in :math:`\mathbf{N}`, and the velocity of the point :math:`P` is known in the frame associated with body :math:`\mathbf{B}`. We can then write the velocity and acceleration of :math:`P` in :math:`\mathbf{N}` as: .. math:: ^{\mathbf{N}}\mathbf{v}^P &= ^\mathbf{B}\mathbf{v}^P + ^\mathbf{N}\mathbf{v}^S + ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times \mathbf{r}^{SP}\\ ^{\mathbf{N}}\mathbf{a}^P &= ^\mathbf{B}\mathbf{a}^S + ^\mathbf{N}\mathbf{a}^O + ^\mathbf{N}\mathbf{\alpha}^\mathbf{B} \times \mathbf{r}^{SP} + ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times (^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times \mathbf{r}^{SP}) + 2 ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times ^\mathbf{B} \mathbf{v}^P \\ Examples of applications of the 1 point and 2 point theorem follow. .. image:: kin_2.* :height: 300 :width: 400 :align: center This example has a disc translating and rotating in a plane. We can easily define the angular velocity of the body :math:`\mathbf{B}` and velocity of the point :math:`O`: .. math:: ^\mathbf{N}\mathbf{\omega}^\mathbf{B} &= u_3 \mathbf{\hat{n}_z} = u_3 \mathbf{\hat{b}_z}\\ ^\mathbf{N}\mathbf{v}^O &= u_1 \mathbf{\hat{n}_x} + u_2 \mathbf{\hat{n}_y}\\ and accelerations can be written as: .. math:: ^\mathbf{N}\mathbf{\alpha}^\mathbf{B} &= \dot{u_3} \mathbf{\hat{n}_z} = \dot{u_3} \mathbf{\hat{b}_z}\\ ^\mathbf{N}\mathbf{a}^O &= \dot{u_1} \mathbf{\hat{n}_x} + \dot{u_2} \mathbf{\hat{n}_y}\\ We can use the 2 point theorem to calculate the velocity and acceleration of point :math:`P` now. .. math:: \mathbf{r}^{OP} &= R \mathbf{\hat{b}_x}\\ ^\mathbf{N}\mathbf{v}^P &= ^\mathbf{N}\mathbf{v}^O + ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times \mathbf{r}^{OP}\\ ^\mathbf{N}\mathbf{v}^P &= u_1 \mathbf{\hat{n}_x} + u_2 \mathbf{\hat{n}_y} + u_3 \mathbf{\hat{b}_z} \times R \mathbf{\hat{b}_x} = u_1 \mathbf{\hat{n}_x} + u_2 \mathbf{\hat{n}_y} + u_3 R \mathbf{\hat{b}_y}\\ ^{\mathbf{N}}\mathbf{a}^P &= ^\mathbf{N}\mathbf{a}^O + ^\mathbf{N}\mathbf{\alpha}^\mathbf{B} \times \mathbf{r}^{OP} + ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times (^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times \mathbf{r}^{OP})\\ ^{\mathbf{N}}\mathbf{a}^P &= \dot{u_1} \mathbf{\hat{n}_x} + \dot{u_2} \mathbf{\hat{n}_y} + \dot{u_3}\mathbf{\hat{b}_z}\times R \mathbf{\hat{b}_x} +u_3\mathbf{\hat{b}_z}\times(u_3\mathbf{\hat{b}_z}\times R\mathbf{\hat{b}_x})\\ ^{\mathbf{N}}\mathbf{a}^P &= \dot{u_1} \mathbf{\hat{n}_x} + \dot{u_2} \mathbf{\hat{n}_y} + R\dot{u_3}\mathbf{\hat{b}_y} - R u_3^2 \mathbf{\hat{b}_x}\\ .. image:: kin_3.* :height: 200 :width: 200 :align: center In this example we have a double pendulum. We can use the two point theorem twice here in order to find the velocity of points :math:`Q` and :math:`P`; point :math:`O`'s velocity is zero in :math:`\mathbf{N}`. .. math:: \mathbf{r}^{OQ} &= l \mathbf{\hat{b}_x}\\ \mathbf{r}^{QP} &= l \mathbf{\hat{c}_x}\\ ^\mathbf{N}\mathbf{\omega}^\mathbf{B} &= u_1 \mathbf{\hat{b}_z}\\ ^\mathbf{N}\mathbf{\omega}^\mathbf{C} &= u_2 \mathbf{\hat{c}_z}\\ ^\mathbf{N}\mathbf{v}^Q &= ^\mathbf{N}\mathbf{v}^O + ^\mathbf{N}\mathbf{\omega}^\mathbf{B} \times \mathbf{r}^{OQ}\\ ^\mathbf{N}\mathbf{v}^Q &= u_1 l \mathbf{\hat{b}_y}\\ ^\mathbf{N}\mathbf{v}^P &= ^\mathbf{N}\mathbf{v}^Q + ^\mathbf{N}\mathbf{\omega}^\mathbf{C} \times \mathbf{r}^{QP}\\ ^\mathbf{N}\mathbf{v}^Q &= u_1 l \mathbf{\hat{b}_y} +u_2 \mathbf{\hat{c}_z} \times l \mathbf{\hat{c}_x}\\ ^\mathbf{N}\mathbf{v}^Q &= u_1 l\mathbf{\hat{b}_y}+u_2 l\mathbf{\hat{c}_y}\\ .. image:: kin_4.* :height: 400 :width: 300 :align: center In this example we have a particle moving on a ring; the ring is supported by a rod which can rotate about the :math:`\mathbf{\hat{n}_x}` axis. First we use the two point theorem to find the velocity of the center point of the ring, :math:`Q`, then use the 1 point theorem to find the velocity of the particle on the ring. .. math:: ^\mathbf{N}\mathbf{\omega}^\mathbf{C} &= u_1 \mathbf{\hat{n}_x}\\ \mathbf{r}^{OQ} &= -l \mathbf{\hat{c}_z}\\ ^\mathbf{N}\mathbf{v}^Q &= u_1 l \mathbf{\hat{c}_y}\\ \mathbf{r}^{QP} &= R(cos(q_2) \mathbf{\hat{c}_x} + sin(q_2) \mathbf{\hat{c}_y} )\\ ^\mathbf{C}\mathbf{v}^P &= R u_2 (-sin(q_2) \mathbf{\hat{c}_x} + cos(q_2) \mathbf{\hat{c}_y} )\\ ^\mathbf{N}\mathbf{v}^P &= ^\mathbf{C}\mathbf{v}^P +^\mathbf{N}\mathbf{v}^Q + ^\mathbf{N}\mathbf{\omega}^\mathbf{C} \times \mathbf{r}^{QP}\\ ^\mathbf{N}\mathbf{v}^P &= R u_2 (-sin(q_2) \mathbf{\hat{c}_x} + cos(q_2) \mathbf{\hat{c}_y} ) + u_1 l \mathbf{\hat{c}_y} + u_1 \mathbf{\hat{c}_x} \times R(cos(q_2) \mathbf{\hat{c}_x} + sin(q_2) \mathbf{\hat{c}_y}\\ ^\mathbf{N}\mathbf{v}^P &= - R u_2 sin(q_2) \mathbf{\hat{c}_x} + (R u_2 cos(q_2)+u_1 l)\mathbf{\hat{c}_y} + R u_1 sin(q_2) \mathbf{\hat{c}_z}\\ A final topic in the description of velocities of points is that of rolling, or rather, rolling without slip. Two bodies are said to be rolling without slip if and only if the point of contact on each body has the same velocity in another frame. See the following figure: .. image:: kin_rolling.* :height: 250 :width: 450 :align: center This is commonly used to form the velocity of a point on one object rolling on another fixed object, such as in the following example: .. % rolling disc kinematics here Kinematics in physics.vector ============================ It should be clear by now that the topic of kinematics here has been mostly describing the correct way to manipulate vectors into representing the velocities of points. Within :mod:`sympy.physics.vector` there are convenient methods for storing these velocities associated with frames and points. We'll now revisit the above examples and show how to represent them in :mod:`sympy`. The topic of reference frame creation has already been covered. When a ``ReferenceFrame`` is created though, it automatically calculates the angular velocity of the frame using the time derivative of the DCM and the angular velocity definition. :: >>> from sympy import Symbol, sin, cos >>> from sympy.physics.vector import * >>> init_vprinting(pretty_print=False) >>> N = ReferenceFrame('N') >>> q1 = dynamicsymbols('q1') >>> A = N.orientnew('A', 'Axis', [q1, N.x]) >>> A.ang_vel_in(N) q1'*N.x Note that the angular velocity can be defined in an alternate way: :: >>> B = ReferenceFrame('B') >>> u1 = dynamicsymbols('u1') >>> B.set_ang_vel(N, u1 * B.y) >>> B.ang_vel_in(N) u1*B.y >>> N.ang_vel_in(B) - u1*B.y Both upon frame creation during ``orientnew`` and when calling ``set_ang_vel``, the angular velocity is set in both frames involved, as seen above. .. image:: kin_angvel2.* :height: 300 :width: 450 :align: center Here we have multiple bodies with angular velocities defined relative to each other. This is coded as: :: >>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A') >>> B = ReferenceFrame('B') >>> C = ReferenceFrame('C') >>> D = ReferenceFrame('D') >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') >>> A.set_ang_vel(N, 0) >>> B.set_ang_vel(A, u1 * A.x) >>> C.set_ang_vel(B, -u2 * B.z) >>> D.set_ang_vel(C, u3 * C.y) >>> D.ang_vel_in(N) u1*A.x - u2*B.z + u3*C.y In :mod:`sympy.physics.vector` the shortest path between two frames is used when finding the angular velocity. That would mean if we went back and set: :: >>> D.set_ang_vel(N, 0) >>> D.ang_vel_in(N) 0 The path that was just defined is what is used. This can cause problems though, as now the angular velocity definitions are inconsistent. It is recommended that you avoid doing this. .. % put some stuff to go with derivative theorem here Points are a translational analog to the rotational ``ReferenceFrame``. Creating a ``Point`` can be done in two ways, like ``ReferenceFrame``: :: >>> O = Point('O') >>> P = O.locatenew('P', 3 * N.x + N.y) >>> P.pos_from(O) 3*N.x + N.y >>> Q = Point('Q') >>> Q.set_pos(P, N.z) >>> Q.pos_from(P) N.z >>> Q.pos_from(O) 3*N.x + N.y + N.z Similar to ``ReferenceFrame``, the position vector between two points is found by the shortest path (number of intermediate points) between them. Unlike rotational motion, there is no addition theorem for the velocity of points. In order to have the velocity of a ``Point`` in a ``ReferenceFrame``, you have to set the value. :: >>> O = Point('O') >>> O.set_vel(N, u1*N.x) >>> O.vel(N) u1*N.x For both translational and rotational accelerations, the value is computed by taking the time derivative of the appropriate velocity, unless the user sets it otherwise. >>> O.acc(N) u1'*N.x >>> O.set_acc(N, u2*u1*N.y) >>> O.acc(N) u1*u2*N.y Next is a description of the 2 point and 1 point theorems, as used in ``sympy``. .. image:: kin_2.* :height: 300 :width: 400 :align: center First is the translating, rotating disc. :: >>> N = ReferenceFrame('N') >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') >>> R = Symbol('R') >>> B = ReferenceFrame('B') >>> O = Point('O') >>> O.set_vel(N, u1 * N.x + u2 * N.y) >>> P = O.locatenew('P', R * B.x) >>> B.set_ang_vel(N, u3 * B.z) >>> P.v2pt_theory(O, N, B) u1*N.x + u2*N.y + R*u3*B.y >>> P.a2pt_theory(O, N, B) u1'*N.x + u2'*N.y - R*u3**2*B.x + R*u3'*B.y We will also cover implementation of the 1 point theorem. .. image:: kin_4.* :height: 400 :width: 300 :align: center This is the particle moving on a ring, again. :: >>> N = ReferenceFrame('N') >>> u1, u2 = dynamicsymbols('u1 u2') >>> q1, q2 = dynamicsymbols('q1 q2') >>> l = Symbol('l') >>> R = Symbol('R') >>> C = N.orientnew('C', 'Axis', [q1, N.x]) >>> C.set_ang_vel(N, u1 * N.x) >>> O = Point('O') >>> O.set_vel(N, 0) >>> Q = O.locatenew('Q', -l * C.z) >>> P = Q.locatenew('P', R * (cos(q2) * C.x + sin(q2) * C.y)) >>> P.set_vel(C, R * u2 * (-sin(q2) * C.x + cos(q2) * C.y)) >>> Q.v2pt_theory(O, N, C) l*u1*C.y >>> P.v1pt_theory(Q, N, C) - R*u2*sin(q2)*C.x + (R*u2*cos(q2) + l*u1)*C.y + R*u1*sin(q2)*C.z sympy-sympy-1.9/doc/src/modules/physics/vector/simp_rot.svg000066400000000000000000000243701412543434000242760ustar00rootroot00000000000000 image/svg+xml A B θ θ azbz ax bx ay by sympy-sympy-1.9/doc/src/modules/physics/vector/vec_add.svg000066400000000000000000000170521412543434000240260ustar00rootroot00000000000000 image/svg+xml a b b a a+b sympy-sympy-1.9/doc/src/modules/physics/vector/vec_cross.svg000066400000000000000000000234311412543434000244250ustar00rootroot00000000000000 image/svg+xml a x a = 0 a a b d c c / sqrt(2) 45° sympy-sympy-1.9/doc/src/modules/physics/vector/vec_dot.svg000066400000000000000000000246151412543434000240670ustar00rootroot00000000000000 image/svg+xml a b a a a c 45° a ⋅ b = 0 a ⋅ a = 1 a ⋅ c = 1/sqrt(2) sympy-sympy-1.9/doc/src/modules/physics/vector/vec_fix_notfix.svg000066400000000000000000000364311412543434000254550ustar00rootroot00000000000000 image/svg+xml A B f e d c c xd xe f Fixed in: xx A B sympy-sympy-1.9/doc/src/modules/physics/vector/vec_mul.svg000066400000000000000000000113551412543434000240730ustar00rootroot00000000000000 image/svg+xml a 2a -a sympy-sympy-1.9/doc/src/modules/physics/vector/vec_rep.svg000066400000000000000000000122771412543434000240700ustar00rootroot00000000000000 image/svg+xml Vector on page Vector outof page Vectorinto page sympy-sympy-1.9/doc/src/modules/physics/vector/vec_simp_der.svg000066400000000000000000000342771412543434000251100ustar00rootroot00000000000000 image/svg+xml A B l x ax ay bx by c θ sympy-sympy-1.9/doc/src/modules/physics/vector/vectors.rst000066400000000000000000000727461412543434000241520ustar00rootroot00000000000000======================= Vector & ReferenceFrame ======================= In :mod:`sympy.physics.vector`, vectors and reference frames are the "building blocks" of dynamic systems. This document will describe these mathematically and describe how to use them with this module's code. Vector ====== A vector is a geometric object that has a magnitude (or length) and a direction. Vectors in 3-space are often represented on paper as: .. image:: vec_rep.* :height: 175 :width: 350 :align: center Vector Algebra ============== Vector algebra is the first topic to be discussed. Two vectors are said to be equal if and only if (iff) they have the same magnitude and orientation. Vector Operations ----------------- Multiple algebraic operations can be done with vectors: addition between vectors, scalar multiplication, and vector multiplication. Vector addition as based on the parallelogram law. .. image:: vec_add.* :height: 200 :width: 200 :align: center Vector addition is also commutative: .. math:: \mathbf{a} + \mathbf{b} &= \mathbf{b} + \mathbf{a} \\ (\mathbf{a} + \mathbf{b}) + \mathbf{c} &= \mathbf{a} + (\mathbf{b} + \mathbf{c}) Scalar multiplication is the product of a vector and a scalar; the result is a vector with the same orientation but whose magnitude is scaled by the scalar. Note that multiplication by -1 is equivalent to rotating the vector by 180 degrees about an arbitrary axis in the plane perpendicular to the vector. .. image:: vec_mul.* :height: 150 :width: 200 :align: center A unit vector is simply a vector whose magnitude is equal to 1. Given any vector :math:`\mathbf{v}` we can define a unit vector as: .. math:: \mathbf{\hat{n}_v} = \frac{\mathbf{v}}{\Vert \mathbf{v} \Vert} Note that every vector can be written as the product of a scalar and unit vector. Three vector products are implemented in :mod:`sympy.physics.vector`: the dot product, the cross product, and the outer product. The dot product operation maps two vectors to a scalar. It is defined as: .. math:: \mathbf{a} \cdot \mathbf{b} = \Vert \mathbf{a} \Vert \Vert \mathbf{b} \Vert \cos(\theta)\\ where :math:`\theta` is the angle between :math:`\mathbf{a}` and :math:`\mathbf{b}`. The dot product of two unit vectors represent the magnitude of the common direction; for other vectors, it is the product of the magnitude of the common direction and the two vectors' magnitudes. The dot product of two perpendicular is zero. The figure below shows some examples: .. image:: vec_dot.* :height: 250 :width: 450 :align: center The dot product is commutative: .. math:: \mathbf{a} \cdot \mathbf{b} = \mathbf{b} \cdot \mathbf{a} The cross product vector multiplication operation of two vectors returns a vector: .. math:: \mathbf{a} \times \mathbf{b} = \mathbf{c} The vector :math:`\mathbf{c}` has the following properties: it's orientation is perpendicular to both :math:`\mathbf{a}` and :math:`\mathbf{b}`, it's magnitude is defined as :math:`\Vert \mathbf{c} \Vert = \Vert \mathbf{a} \Vert \Vert \mathbf{b} \Vert \sin(\theta)` (where :math:`\theta` is the angle between :math:`\mathbf{a}` and :math:`\mathbf{b}`), and has a sense defined by using the right hand rule between :math:`\Vert \mathbf{a} \Vert \Vert \mathbf{b} \Vert`. The figure below shows this: .. image:: vec_cross.* :height: 350 :width: 700 :align: center The cross product has the following properties: It is not commutative: .. math:: \mathbf{a} \times \mathbf{b} &\neq \mathbf{b} \times \mathbf{a} \\ \mathbf{a} \times \mathbf{b} &= - \mathbf{b} \times \mathbf{a} and not associative: .. math:: (\mathbf{a} \times \mathbf{b} ) \times \mathbf{c} \neq \mathbf{a} \times (\mathbf{b} \times \mathbf{c}) Two parallel vectors will have a zero cross product. The outer product between two vectors will not be not be discussed here, but instead in the inertia section (that is where it is used). Other useful vector properties and relationships are: .. math:: \alpha (\mathbf{a} + \mathbf{b}) &= \alpha \mathbf{a} + \alpha \mathbf{b}\\ \mathbf{a} \cdot (\mathbf{b} + \mathbf{c}) &= \mathbf{a} \cdot \mathbf{b} + \mathbf{a} \cdot \mathbf{c}\\ \mathbf{a} \times (\mathbf{b} + \mathbf{c}) &= \mathbf{a} \times \mathbf{b} + \mathbf{a} \times \mathbf{b}\\ (\mathbf{a} \times \mathbf{b}) \cdot \mathbf{c} & \textrm{ gives the scalar triple product.}\\ \mathbf{a} \times (\mathbf{b} \cdot \mathbf{c}) & \textrm{ does not work, as you cannot cross a vector and a scalar.}\\ (\mathbf{a} \times \mathbf{b}) \cdot \mathbf{c} &= \mathbf{a} \cdot (\mathbf{b} \times \mathbf{c})\\ (\mathbf{a} \times \mathbf{b}) \cdot \mathbf{c} &= (\mathbf{b} \times \mathbf{c}) \cdot \mathbf{a} = (\mathbf{c} \times \mathbf{a}) \cdot \mathbf{b}\\ (\mathbf{a} \times \mathbf{b}) \times \mathbf{c} &= \mathbf{b}(\mathbf{a} \cdot \mathbf{c}) - \mathbf{a}(\mathbf{b} \cdot \mathbf{c})\\ \mathbf{a} \times (\mathbf{b} \times \mathbf{c}) &= \mathbf{b}(\mathbf{a} \cdot \mathbf{c}) - \mathbf{c}(\mathbf{a} \cdot \mathbf{b})\\ Alternative Representation -------------------------- If we have three non-coplanar unit vectors :math:`\mathbf{\hat{n}_x},\mathbf{\hat{n}_y},\mathbf{\hat{n}_z}`, we can represent any vector :math:`\mathbf{a}` as :math:`\mathbf{a} = a_x \mathbf{\hat{n}_x} + a_y \mathbf{\hat{n}_y} + a_z \mathbf{\hat{n}_z}`. In this situation :math:`\mathbf{\hat{n}_x},\mathbf{\hat{n}_y},\mathbf{\hat{n}_z}` are referred to as a basis. :math:`a_x, a_y, a_z` are called the measure numbers. Usually the unit vectors are mutually perpendicular, in which case we can refer to them as an orthonormal basis, and they are usually right-handed. To test equality between two vectors, now we can do the following. With vectors: .. math:: \mathbf{a} &= a_x \mathbf{\hat{n}_x} + a_y \mathbf{\hat{n}_y} + a_z \mathbf{\hat{n}_z}\\ \mathbf{b} &= b_x \mathbf{\hat{n}_x} + b_y \mathbf{\hat{n}_y} + b_z \mathbf{\hat{n}_z}\\ We can claim equality if: :math:`a_x = b_x, a_y = b_y, a_z = b_z`. Vector addition is then represented, for the same two vectors, as: .. math:: \mathbf{a} + \mathbf{b} = (a_x + b_x)\mathbf{\hat{n}_x} + (a_y + b_y) \mathbf{\hat{n}_y} + (a_z + b_z) \mathbf{\hat{n}_z} Multiplication operations are now defined as: .. math:: \alpha \mathbf{b} &= \alpha b_x \mathbf{\hat{n}_x} + \alpha b_y \mathbf{\hat{n}_y} + \alpha b_z \mathbf{\hat{n}_z}\\ \mathbf{a} \cdot \mathbf{b} &= a_x b_x + a_y b_y + a_z b_z\\ \mathbf{a} \times \mathbf{b} &= \textrm{det }\begin{bmatrix} \mathbf{\hat{n}_x} & \mathbf{\hat{n}_y} & \mathbf{\hat{n}_z} \\ a_x & a_y & a_z \\ b_x & b_y & b_z \end{bmatrix}\\ (\mathbf{a} \times \mathbf{b}) \cdot \mathbf{c} &= \textrm{det }\begin{bmatrix} a_x & a_y & a_z \\ b_x & b_y & b_z \\ c_x & c_y & c_z \end{bmatrix}\\ To write a vector in a given basis, we can do the follow: .. math:: \mathbf{a} = (\mathbf{a}\cdot\mathbf{\hat{n}_x})\mathbf{\hat{n}_x} + (\mathbf{a}\cdot\mathbf{\hat{n}_y})\mathbf{\hat{n}_y} + (\mathbf{a}\cdot\mathbf{\hat{n}_z})\mathbf{\hat{n}_z}\\ Examples -------- Some numeric examples of these operations follow: .. math:: \mathbf{a} &= \mathbf{\hat{n}_x} + 5 \mathbf{\hat{n}_y}\\ \mathbf{b} &= \mathbf{\hat{n}_y} + \alpha \mathbf{\hat{n}_z}\\ \mathbf{a} + \mathbf{b} &= \mathbf{\hat{n}_x} + 6 \mathbf{\hat{n}_y} + \alpha \mathbf{\hat{n}_z}\\ \mathbf{a} \cdot \mathbf{b} &= 5\\ \mathbf{a} \cdot \mathbf{\hat{n}_y} &= 5\\ \mathbf{a} \cdot \mathbf{\hat{n}_z} &= 0\\ \mathbf{a} \times \mathbf{b} &= 5 \alpha \mathbf{\hat{n}_x} - \alpha \mathbf{\hat{n}_y} + \mathbf{\hat{n}_z}\\ \mathbf{b} \times \mathbf{a} &= -5 \alpha \mathbf{\hat{n}_x} + \alpha \mathbf{\hat{n}_y} - \mathbf{\hat{n}_z}\\ Vector Calculus =============== To deal with the calculus of vectors with moving object, we have to introduce the concept of a reference frame. A classic example is a train moving along its tracks, with you and a friend inside. If both you and your friend are sitting, the relative velocity between the two of you is zero. From an observer outside the train, you will both have velocity though. We will now apply more rigor to this definition. A reference frame is a virtual "platform" which we choose to observe vector quantities from. If we have a reference frame :math:`\mathbf{N}`, vector :math:`\mathbf{a}` is said to be fixed in the frame :math:`\mathbf{N}` if none of its properties ever change when observed from :math:`\mathbf{N}`. We will typically assign a fixed orthonormal basis vector set with each reference frame; :math:`\mathbf{N}` will have :math:`\mathbf{\hat{n}_x}, \mathbf{\hat{n}_y},\mathbf{\hat{n}_z}` as its basis vectors. Derivatives of Vectors ---------------------- A vector which is not fixed in a reference frame therefore has changing properties when observed from that frame. Calculus is the study of change, and in order to deal with the peculiarities of vectors fixed and not fixed in different reference frames, we need to be more explicit in our definitions. .. image:: vec_fix_notfix.* :height: 300 :width: 450 :align: center In the above figure, we have vectors :math:`\mathbf{c,d,e,f}`. If one were to take the derivative of :math:`\mathbf{e}` with respect to :math:`\theta`: .. math:: \frac{d \mathbf{e}}{d \theta} it is not clear what the derivative is. If you are observing from frame :math:`\mathbf{A}`, it is clearly non-zero. If you are observing from frame :math:`\mathbf{B}`, the derivative is zero. We will therefore introduce the frame as part of the derivative notation: .. math:: \frac{^{\mathbf{A}} d \mathbf{e}}{d \theta} &\neq 0 \textrm{, the derivative of } \mathbf{e} \textrm{ with respect to } \theta \textrm{ in the reference frame } \mathbf{A}\\ \frac{^{\mathbf{B}} d \mathbf{e}}{d \theta} &= 0 \textrm{, the derivative of } \mathbf{e} \textrm{ with respect to } \theta \textrm{ in the reference frame } \mathbf{B}\\ \frac{^{\mathbf{A}} d \mathbf{c}}{d \theta} &= 0 \textrm{, the derivative of } \mathbf{c} \textrm{ with respect to } \theta \textrm{ in the reference frame } \mathbf{A}\\ \frac{^{\mathbf{B}} d \mathbf{c}}{d \theta} &\neq 0 \textrm{, the derivative of } \mathbf{c} \textrm{ with respect to } \theta \textrm{ in the reference frame } \mathbf{B}\\ Here are some additional properties of derivatives of vectors in specific frames: .. math:: \frac{^{\mathbf{A}} d}{dt}(\mathbf{a} + \mathbf{b}) &= \frac{^{\mathbf{A}} d\mathbf{a}}{dt} + \frac{^{\mathbf{A}} d\mathbf{b}}{dt}\\ \frac{^{\mathbf{A}} d}{dt}\gamma \mathbf{a} &= \frac{ d \gamma}{dt}\mathbf{a} + \gamma\frac{^{\mathbf{A}} d\mathbf{a}}{dt}\\ \frac{^{\mathbf{A}} d}{dt}(\mathbf{a} \times \mathbf{b}) &= \frac{^{\mathbf{A}} d\mathbf{a}}{dt} \times \mathbf{b} + \mathbf{a} \times \frac{^{\mathbf{A}} d\mathbf{b}}{dt}\\ Relating Sets of Basis Vectors ------------------------------ We need to now define the relationship between two different reference frames; or how to relate the basis vectors of one frame to another. We can do this using a direction cosine matrix (DCM). The direction cosine matrix relates the basis vectors of one frame to another, in the following fashion: .. math:: \begin{bmatrix} \mathbf{\hat{a}_x} \\ \mathbf{\hat{a}_y} \\ \mathbf{\hat{a}_z} \\ \end{bmatrix} = \begin{bmatrix} ^{\mathbf{A}} \mathbf{C}^{\mathbf{B}} \end{bmatrix} \begin{bmatrix} \mathbf{\hat{b}_x} \\ \mathbf{\hat{b}_y} \\ \mathbf{\hat{b}_z} \\ \end{bmatrix} When two frames (say, :math:`\mathbf{A}` & :math:`\mathbf{B}`) are initially aligned, then one frame has all of its basis vectors rotated around an axis which is aligned with a basis vector, we say the frames are related by a simple rotation. The figure below shows this: .. image:: simp_rot.* :height: 250 :width: 250 :align: center The above rotation is a simple rotation about the Z axis by an angle :math:`\theta`. Note that after the rotation, the basis vectors :math:`\mathbf{\hat{a}_z}` and :math:`\mathbf{\hat{b}_z}` are still aligned. This rotation can be characterized by the following direction cosine matrix: .. math:: ^{\mathbf{A}}\mathbf{C}^{\mathbf{B}} = \begin{bmatrix} \cos(\theta) & - \sin(\theta) & 0\\ \sin(\theta) & \cos(\theta) & 0\\ 0 & 0 & 1\\ \end{bmatrix} Simple rotations about the X and Y axes are defined by: .. math:: \textrm{DCM for x-axis rotation: } \begin{bmatrix} 1 & 0 & 0\\ 0 & \cos(\theta) & -\sin(\theta)\\ 0 & \sin(\theta) & \cos(\theta) \end{bmatrix} \textrm{DCM for y-axis rotation: } \begin{bmatrix} \cos(\theta) & 0 & \sin(\theta)\\ 0 & 1 & 0\\ -\sin(\theta) & 0 & \cos(\theta)\\ \end{bmatrix} Rotation in the positive direction here will be defined by using the right-hand rule. The direction cosine matrix is also involved with the definition of the dot product between sets of basis vectors. If we have two reference frames with associated basis vectors, their direction cosine matrix can be defined as: .. math:: \begin{bmatrix} C_{xx} & C_{xy} & C_{xz}\\ C_{yx} & C_{yy} & C_{yz}\\ C_{zx} & C_{zy} & C_{zz}\\ \end{bmatrix} = \begin{bmatrix} \mathbf{\hat{a}_x}\cdot\mathbf{\hat{b}_x} & \mathbf{\hat{a}_x}\cdot\mathbf{\hat{b}_y} & \mathbf{\hat{a}_x}\cdot\mathbf{\hat{b}_z}\\ \mathbf{\hat{a}_y}\cdot\mathbf{\hat{b}_x} & \mathbf{\hat{a}_y}\cdot\mathbf{\hat{b}_y} & \mathbf{\hat{a}_y}\cdot\mathbf{\hat{b}_z}\\ \mathbf{\hat{a}_z}\cdot\mathbf{\hat{b}_x} & \mathbf{\hat{a}_z}\cdot\mathbf{\hat{b}_y} & \mathbf{\hat{a}_z}\cdot\mathbf{\hat{b}_z}\\ \end{bmatrix} Additionally, the direction cosine matrix is orthogonal, in that: .. math:: ^{\mathbf{A}}\mathbf{C}^{\mathbf{B}} = (^{\mathbf{B}}\mathbf{C}^{\mathbf{A}})^{-1}\\ = (^{\mathbf{B}}\mathbf{C}^{\mathbf{A}})^T\\ If we have reference frames :math:`\mathbf{A}` and :math:`\mathbf{B}`, which in this example have undergone a simple z-axis rotation by an amount :math:`\theta`, we will have two sets of basis vectors. We can then define two vectors: :math:`\mathbf{a} = \mathbf{\hat{a}_x} + \mathbf{\hat{a}_y} + \mathbf{\hat{a}_z}` and :math:`\mathbf{b} = \mathbf{\hat{b}_x} + \mathbf{\hat{b}_y} + \mathbf{\hat{b}_z}`. If we wish to express :math:`\mathbf{b}` in the :math:`\mathbf{A}` frame, we do the following: .. math:: \mathbf{b} &= \mathbf{\hat{b}_x} + \mathbf{\hat{b}_y} + \mathbf{\hat{b}_z}\\ \mathbf{b} &= \begin{bmatrix}\mathbf{\hat{a}_x}\cdot (\mathbf{\hat{b}_x} + \mathbf{\hat{b}_y} + \mathbf{\hat{b}_z})\end{bmatrix} \mathbf{\hat{a}_x} + \begin{bmatrix}\mathbf{\hat{a}_y}\cdot (\mathbf{\hat{b}_x} + \mathbf{\hat{b}_y} + \mathbf{\hat{b}_z})\end{bmatrix} \mathbf{\hat{a}_y} + \begin{bmatrix}\mathbf{\hat{a}_z}\cdot (\mathbf{\hat{b}_x} + \mathbf{\hat{b}_y} + \mathbf{\hat{b}_z})\end{bmatrix} \mathbf{\hat{a}_z}\\ \mathbf{b} &= (\cos(\theta) - \sin(\theta))\mathbf{\hat{a}_x} + (\sin(\theta) + \cos(\theta))\mathbf{\hat{a}_y} + \mathbf{\hat{a}_z} And if we wish to express :math:`\mathbf{a}` in the :math:`\mathbf{B}`, we do: .. math:: \mathbf{a} &= \mathbf{\hat{a}_x} + \mathbf{\hat{a}_y} + \mathbf{\hat{a}_z}\\ \mathbf{a} &= \begin{bmatrix}\mathbf{\hat{b}_x}\cdot (\mathbf{\hat{a}_x} + \mathbf{\hat{a}_y} + \mathbf{\hat{a}_z})\end{bmatrix} \mathbf{\hat{b}_x} + \begin{bmatrix}\mathbf{\hat{b}_y}\cdot (\mathbf{\hat{a}_x} + \mathbf{\hat{a}_y} + \mathbf{\hat{a}_z})\end{bmatrix} \mathbf{\hat{b}_y} + \begin{bmatrix}\mathbf{\hat{b}_z}\cdot (\mathbf{\hat{a}_x} + \mathbf{\hat{a}_y} + \mathbf{\hat{a}_z})\end{bmatrix} \mathbf{\hat{b}_z}\\ \mathbf{a} &= (\cos(\theta) + \sin(\theta))\mathbf{\hat{b}_x} + (-\sin(\theta)+\cos(\theta))\mathbf{\hat{b}_y} + \mathbf{\hat{b}_z} Derivatives with Multiple Frames -------------------------------- If we have reference frames :math:`\mathbf{A}` and :math:`\mathbf{B}` we will have two sets of basis vectors. We can then define two vectors: :math:`\mathbf{a} = a_x\mathbf{\hat{a}_x} + a_y\mathbf{\hat{a}_y} + a_z\mathbf{\hat{a}_z}` and :math:`\mathbf{b} = b_x\mathbf{\hat{b}_x} + b_y\mathbf{\hat{b}_y} + b_z\mathbf{\hat{b}_z}`. If we want to take the derivative of :math:`\mathbf{b}` in the reference frame :math:`\mathbf{A}`, we must first express it in :math:`\mathbf{A}`, and the take the derivatives of the measure numbers: .. math:: \frac{^{\mathbf{A}} d\mathbf{b}}{dx} = \frac{d (\mathbf{b}\cdot \mathbf{\hat{a}_x} )}{dx} \mathbf{\hat{a}_x} + \frac{d (\mathbf{b}\cdot \mathbf{\hat{a}_y} )}{dx} \mathbf{\hat{a}_y} + \frac{d (\mathbf{b}\cdot \mathbf{\hat{a}_z} )}{dx} \mathbf{\hat{a}_z} + Examples -------- An example of vector calculus: .. image:: vec_simp_der.* :height: 500 :width: 350 :align: center In this example we have two bodies, each with an attached reference frame. We will say that :math:`\theta` and :math:`x` are functions of time. We wish to know the time derivative of vector :math:`\mathbf{c}` in both the :math:`\mathbf{A}` and :math:`\mathbf{B}` frames. First, we need to define :math:`\mathbf{c}`; :math:`\mathbf{c}=x\mathbf{\hat{b}_x}+l\mathbf{\hat{b}_y}`. This provides a definition in the :math:`\mathbf{B}` frame. We can now do the following: .. math:: \frac{^{\mathbf{B}} d \mathbf{c}}{dt} &= \frac{dx}{dt} \mathbf{\hat{b}_x} + \frac{dl}{dt} \mathbf{\hat{b}_y}\\ &= \dot{x} \mathbf{\hat{b}_x} To take the derivative in the :math:`\mathbf{A}` frame, we have to first relate the two frames: .. math:: ^{\mathbf{A}} \mathbf{C} ^{\mathbf{B}} = \begin{bmatrix} \cos(\theta) & 0 & \sin(\theta)\\ 0 & 1 & 0\\ -\sin(\theta) & 0 & \cos(\theta)\\ \end{bmatrix} Now we can do the following: .. math:: \frac{^{\mathbf{A}} d \mathbf{c}}{dt} &= \frac{d (\mathbf{c} \cdot \mathbf{\hat{a}_x})}{dt} \mathbf{\hat{a}_x} + \frac{d (\mathbf{c} \cdot \mathbf{\hat{a}_y})}{dt} \mathbf{\hat{a}_y} + \frac{d (\mathbf{c} \cdot \mathbf{\hat{a}_z})}{dt} \mathbf{\hat{a}_z}\\ &= \frac{d (\cos(\theta) x)}{dt} \mathbf{\hat{a}_x} + \frac{d (l)}{dt} \mathbf{\hat{a}_y} + \frac{d (-\sin(\theta) x)}{dt} \mathbf{\hat{a}_z}\\ &= (-\dot{\theta}\sin(\theta)x + \cos(\theta)\dot{x}) \mathbf{\hat{a}_x} + (\dot{\theta}\cos(\theta)x + \sin(\theta)\dot{x}) \mathbf{\hat{a}_z} Note that this is the time derivative of :math:`\mathbf{c}` in :math:`\mathbf{A}`, and is expressed in the :math:`\mathbf{A}` frame. We can express it in the :math:`\mathbf{B}` frame however, and the expression will still be valid: .. math:: \frac{^{\mathbf{A}} d \mathbf{c}}{dt} &= (-\dot{\theta}\sin(\theta)x + \cos(\theta)\dot{x}) \mathbf{\hat{a}_x} + (\dot{\theta}\cos(\theta)x + \sin(\theta)\dot{x}) \mathbf{\hat{a}_z}\\ &= \dot{x}\mathbf{\hat{b}_x} - \theta x \mathbf{\hat{b}_z}\\ Note the difference in expression complexity between the two forms. They are equivalent, but one is much simpler. This is an extremely important concept, as defining vectors in the more complex forms can vastly slow down formulation of the equations of motion and increase their length, sometimes to a point where they cannot be shown on screen. Using Vectors and Reference Frames ================================== We have waited until after all of the relevant mathematical relationships have been defined for vectors and reference frames to introduce code. This is due to how vectors are formed. When starting any problem in :mod:`sympy.physics.vector`, one of the first steps is defining a reference frame (remember to import sympy.physics.vector first):: >>> from sympy.physics.vector import * >>> N = ReferenceFrame('N') Now we have created a reference frame, :math:`\mathbf{N}`. To have access to any basis vectors, first a reference frame needs to be created. Now that we have made and object representing :math:`\mathbf{N}`, we can access its basis vectors:: >>> N.x N.x >>> N.y N.y >>> N.z N.z Vector Algebra, in physics.vector --------------------------------- We can now do basic algebraic operations on these vectors.:: >>> N.x == N.x True >>> N.x == N.y False >>> N.x + N.y N.x + N.y >>> 2 * N.x + N.y 2*N.x + N.y Remember, don't add a scalar quantity to a vector (``N.x + 5``); this will raise an error. At this point, we'll use SymPy's Symbol in our vectors. Remember to refer to SymPy's Gotchas and Pitfalls when dealing with symbols.:: >>> from sympy import Symbol, symbols >>> x = Symbol('x') >>> x * N.x x*N.x >>> x*(N.x + N.y) x*N.x + x*N.y In :mod:`sympy.physics.vector` multiple interfaces to vector multiplication have been implemented, at the operator level, method level, and function level. The vector dot product can work as follows: :: >>> N.x & N.x 1 >>> N.x & N.y 0 >>> N.x.dot(N.x) 1 >>> N.x.dot(N.y) 0 >>> dot(N.x, N.x) 1 >>> dot(N.x, N.y) 0 The "official" interface is the function interface; this is what will be used in all examples. This is to avoid confusion with the attribute and methods being next to each other, and in the case of the operator operation priority. The operators used in :mod:`sympy.physics.vector` for vector multiplication do not posses the correct order of operations; this can lead to errors. Care with parentheses is needed when using operators to represent vector multiplication. The cross product is the other vector multiplication which will be discussed here. It offers similar interfaces to the dot product, and comes with the same warnings. :: >>> N.x ^ N.x 0 >>> N.x ^ N.y N.z >>> N.x.cross(N.x) 0 >>> N.x.cross(N.z) - N.y >>> cross(N.x, N.y) N.z >>> N.x ^ (N.y + N.z) - N.y + N.z Two additional operations can be done with vectors: normalizing the vector to length 1, and getting its magnitude. These are done as follows:: >>> (N.x + N.y).normalize() sqrt(2)/2*N.x + sqrt(2)/2*N.y >>> (N.x + N.y).magnitude() sqrt(2) Vectors are often expressed in a matrix form, especially for numerical purposes. Since the matrix form does not contain any information about the reference frame the vector is defined in, you must provide a reference frame to extract the measure numbers from the vector. There is a convenience function to do this:: >>> (x * N.x + 2 * x * N.y + 3 * x * N.z).to_matrix(N) Matrix([ [ x], [2*x], [3*x]]) Vector Calculus, in physics.vector ---------------------------------- We have already introduced our first reference frame. We can take the derivative in that frame right now, if we desire: :: >>> (x * N.x + N.y).diff(x, N) N.x SymPy has a ``diff`` function, but it does not currently work with :mod:`sympy.physics.vector` Vectors, so please use ``Vector``'s ``diff`` method. The reason for this is that when differentiating a ``Vector``, the frame of reference must be specified in addition to what you are taking the derivative with respect to; SymPy's ``diff`` function doesn't fit this mold. The more interesting case arise with multiple reference frames. If we introduce a second reference frame, :math:`\mathbf{A}`, we now have two frames. Note that at this point we can add components of :math:`\mathbf{N}` and :math:`\mathbf{A}` together, but cannot perform vector multiplication, as no relationship between the two frames has been defined. :: >>> A = ReferenceFrame('A') >>> A.x + N.x N.x + A.x If we want to do vector multiplication, first we have to define and orientation. The ``orient`` method of ``ReferenceFrame`` provides that functionality. :: >>> A.orient(N, 'Axis', [x, N.y]) If we desire, we can view the DCM between these two frames at any time. This can be calculated with the ``dcm`` method. This code: ``N.dcm(A)`` gives the dcm :math:`^{\mathbf{A}} \mathbf{C} ^{\mathbf{N}}`. This orients the :math:`\mathbf{A}` frame relative to the :math:`\mathbf{N}` frame by a simple rotation around the Y axis, by an amount x. Other, more complicated rotation types include Body rotations, Space rotations, quaternions, and arbitrary axis rotations. Body and space rotations are equivalent to doing 3 simple rotations in a row, each about a basis vector in the new frame. An example follows: :: >>> N = ReferenceFrame('N') >>> Bp = ReferenceFrame('Bp') >>> Bpp = ReferenceFrame('Bpp') >>> B = ReferenceFrame('B') >>> q1,q2,q3 = symbols('q1 q2 q3') >>> Bpp.orient(N,'Axis', [q1, N.x]) >>> Bp.orient(Bpp,'Axis', [q2, Bpp.y]) >>> B.orient(Bp,'Axis', [q3, Bp.z]) >>> N.dcm(B) Matrix([ [ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)], [sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)], [sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]]) >>> B.orient(N,'Body',[q1,q2,q3],'XYZ') >>> N.dcm(B) Matrix([ [ cos(q2)*cos(q3), -sin(q3)*cos(q2), sin(q2)], [sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), -sin(q1)*cos(q2)], [sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]]) Space orientations are similar to body orientation, but applied from the frame to body. Body and space rotations can involve either two or three axes: 'XYZ' works, as does 'YZX', 'ZXZ', 'YXY', etc. What is key is that each simple rotation is about a different axis than the previous one; 'ZZX' does not completely orient a set of basis vectors in 3 space. Sometimes it will be more convenient to create a new reference frame and orient relative to an existing one in one step. The ``orientnew`` method allows for this functionality, and essentially wraps the ``orient`` method. All of the things you can do in ``orient``, you can do in ``orientnew``. :: >>> C = N.orientnew('C', 'Axis', [q1, N.x]) Quaternions (or Euler Parameters) use 4 value to characterize the orientation of the frame. This and arbitrary axis rotations are described in the ``orient`` and ``orientnew`` method help, or in the references [Kane1983]_. Finally, before starting multiframe calculus operations, we will introduce another :mod:`sympy.physics.vector` tool: ``dynamicsymbols``. ``dynamicsymbols`` is a shortcut function to create undefined functions of time within SymPy. The derivative of such a 'dynamicsymbol' is shown below. :: >>> from sympy import diff >>> q1, q2, q3 = dynamicsymbols('q1 q2 q3') >>> diff(q1, Symbol('t')) Derivative(q1(t), t) The 'dynamicsymbol' printing is not very clear above; we will also introduce a few other tools here. We can use ``vprint`` instead of print for non-interactive sessions. :: >>> q1 q1(t) >>> q1d = diff(q1, Symbol('t')) >>> vprint(q1) q1 >>> vprint(q1d) q1' For interactive sessions use ``init_vprinting``. There also exist analogs for SymPy's ``vprint``, ``vpprint``, and ``latex``, ``vlatex``. :: >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> q1 q1 >>> q1d q1' A 'dynamicsymbol' should be used to represent any time varying quantity in :mod:`sympy.physics.vector`, whether it is a coordinate, varying position, or force. The primary use of a 'dynamicsymbol' is for speeds and coordinates (of which there will be more discussion in the Kinematics Section of the documentation). Now we will define the orientation of our new frames with a 'dynamicsymbol', and can take derivatives and time derivatives with ease. Some examples follow. :: >>> N = ReferenceFrame('N') >>> B = N.orientnew('B', 'Axis', [q1, N.x]) >>> (B.y*q2 + B.z).diff(q2, N) B.y >>> (B.y*q2 + B.z).dt(N) (-q1' + q2')*B.y + q2*q1'*B.z Note that the output vectors are kept in the same frames that they were provided in. This remains true for vectors with components made of basis vectors from multiple frames: :: >>> (B.y*q2 + B.z + q2*N.x).diff(q2, N) N.x + B.y How Vectors are Coded --------------------- What follows is a short description of how vectors are defined by the code in :mod:`sympy.physics.vector`. It is provided for those who want to learn more about how this part of :mod:`sympy.physics.vector` works, and does not need to be read to use this module; don't read it unless you want to learn how this module was implemented. Every ``Vector``'s main information is stored in the ``args`` attribute, which stores the three measure numbers for each basis vector in a frame, for every relevant frame. A vector does not exist in code until a ``ReferenceFrame`` is created. At this point, the ``x``, ``y``, and ``z`` attributes of the reference frame are immutable ``Vector``'s which have measure numbers of [1,0,0], [0,1,0], and [0,0,1] associated with that ``ReferenceFrame``. Once these vectors are accessible, new vectors can be created by doing algebraic operations with the basis vectors. A vector can have components from multiple frames though. That is why ``args`` is a list; it has as many elements in the list as there are unique ``ReferenceFrames`` in its components, i.e. if there are ``A`` and ``B`` frame basis vectors in our new vector, ``args`` is of length 2; if it has ``A``, ``B``, and ``C`` frame basis vector, ``args`` is of length three. Each element in the ``args`` list is a 2-tuple; the first element is a SymPy ``Matrix`` (this is where the measure numbers for each set of basis vectors are stored) and the second element is a ``ReferenceFrame`` to associate those measure numbers with. ``ReferenceFrame`` stores a few things. First, it stores the name you supply it on creation (``name`` attribute). It also stores the direction cosine matrices, defined upon creation with the ``orientnew`` method, or calling the ``orient`` method after creation. The direction cosine matrices are represented by SymPy's ``Matrix``, and are part of a dictionary where the keys are the ``ReferenceFrame`` and the value the ``Matrix``; these are set bi-directionally; in that when you orient ``A`` to ``N`` you are setting ``A``'s orientation dictionary to include ``N`` and its ``Matrix``, but you are also setting ``N``'s orientation dictionary to include ``A`` and its ``Matrix`` (that DCM being the transpose of the other). sympy-sympy-1.9/doc/src/modules/physics/wigner.rst000066400000000000000000000001401412543434000224310ustar00rootroot00000000000000============== Wigner Symbols ============== .. automodule:: sympy.physics.wigner :members: sympy-sympy-1.9/doc/src/modules/plotting.rst000066400000000000000000000215041412543434000213230ustar00rootroot00000000000000======== Plotting ======== .. module:: sympy.plotting.plot Introduction ------------ The plotting module allows you to make 2-dimensional and 3-dimensional plots. Presently the plots are rendered using ``matplotlib`` as a backend. It is also possible to plot 2-dimensional plots using a ``TextBackend`` if you don't have ``matplotlib``. The plotting module has the following functions: * plot: Plots 2D line plots. * plot_parametric: Plots 2D parametric plots. * plot_implicit: Plots 2D implicit and region plots. * plot3d: Plots 3D plots of functions in two variables. * plot3d_parametric_line: Plots 3D line plots, defined by a parameter. * plot3d_parametric_surface: Plots 3D parametric surface plots. The above functions are only for convenience and ease of use. It is possible to plot any plot by passing the corresponding ``Series`` class to ``Plot`` as argument. Plot Class ---------- .. autoclass:: sympy.plotting.plot::Plot :members: Plotting Function Reference --------------------------- .. autofunction:: plot .. autofunction:: plot_parametric .. autofunction:: plot3d .. autofunction:: plot3d_parametric_line .. autofunction:: plot3d_parametric_surface .. autofunction:: sympy.plotting.plot_implicit::plot_implicit PlotGrid Class -------------- .. autoclass:: sympy.plotting.plot::PlotGrid :members: Series Classes -------------- .. autoclass:: sympy.plotting.plot::BaseSeries :members: .. autoclass:: sympy.plotting.plot::Line2DBaseSeries :members: .. autoclass:: sympy.plotting.plot::LineOver1DRangeSeries :members: .. autoclass:: sympy.plotting.plot::Parametric2DLineSeries :members: .. autoclass:: sympy.plotting.plot::Line3DBaseSeries :members: .. autoclass:: sympy.plotting.plot::Parametric3DLineSeries :members: .. autoclass:: sympy.plotting.plot::SurfaceBaseSeries :members: .. autoclass:: sympy.plotting.plot::SurfaceOver2DRangeSeries :members: .. autoclass:: sympy.plotting.plot::ParametricSurfaceSeries :members: .. autoclass:: sympy.plotting.plot_implicit::ImplicitSeries :members: Backends -------- .. autoclass:: sympy.plotting.plot::BaseBackend :members: .. autoclass:: sympy.plotting.plot::MatplotlibBackend :members: .. autoclass:: sympy.plotting.plot::TextBackend :members: Pyglet Plotting --------------- .. module:: sympy.plotting.pygletplot This is the documentation for the old plotting module that uses pyglet. This module has some limitations and is not actively developed anymore. For an alternative you can look at the new plotting module. The pyglet plotting module can do nice 2D and 3D plots that can be controlled by console commands as well as keyboard and mouse, with the only dependency being ``pyglet``. Here is the simplest usage: >>> from sympy import var >>> from sympy.plotting.pygletplot import PygletPlot as Plot >>> var('x y z') >>> Plot(x*y**3-y*x**3) To see lots of plotting examples, see ``examples/pyglet_plotting.py`` and try running it in interactive mode (python -i plotting.py):: $ python -i examples/pyglet_plotting.py And type for instance ``example(7)`` or ``example(11)``. See also the `Plotting Module `_ wiki page for screenshots. Plot Window Controls -------------------- ====================== ======== Camera Keys ====================== ======== Sensitivity Modifier SHIFT Zoom R and F, Page Up and Down, Numpad + and - Rotate View X,Y axis Arrow Keys, A,S,D,W, Numpad 4,6,8,2 Rotate View Z axis Q and E, Numpad 7 and 9 Rotate Ordinate Z axis Z and C, Numpad 1 and 3 View XY F1 View XZ F2 View YZ F3 View Perspective F4 Reset X, Numpad 5 ====================== ======== ====================== ======== Axes Keys ====================== ======== Toggle Visible F5 Toggle Colors F6 ====================== ======== ====================== ======== Window Keys ====================== ======== Close ESCAPE Screenshot F8 ====================== ======== The mouse can be used to rotate, zoom, and translate by dragging the left, middle, and right mouse buttons respectively. Coordinate Modes ---------------- ``Plot`` supports several curvilinear coordinate modes, and they are independent for each plotted function. You can specify a coordinate mode explicitly with the 'mode' named argument, but it can be automatically determined for cartesian or parametric plots, and therefore must only be specified for polar, cylindrical, and spherical modes. Specifically, ``Plot(function arguments)`` and ``Plot.__setitem__(i, function arguments)`` (accessed using array-index syntax on the ``Plot`` instance) will interpret your arguments as a cartesian plot if you provide one function and a parametric plot if you provide two or three functions. Similarly, the arguments will be interpreted as a curve is one variable is used, and a surface if two are used. Supported mode names by number of variables: * 1 (curves): parametric, cartesian, polar * 2 (surfaces): parametric, cartesian, cylindrical, spherical :: >>> Plot(1, 'mode=spherical; color=zfade4') Note that function parameters are given as option strings of the form "key1=value1; key2 = value2" (spaces are truncated). Keyword arguments given directly to plot apply to the plot itself. Specifying Intervals for Variables ---------------------------------- The basic format for variable intervals is [var, min, max, steps]. However, the syntax is quite flexible, and arguments not specified are taken from the defaults for the current coordinate mode: >>> Plot(x**2) # implies [x,-5,5,100] >>> Plot(x**2, [], []) # [x,-1,1,40], [y,-1,1,40] >>> Plot(x**2-y**2, [100], [100]) # [x,-1,1,100], [y,-1,1,100] >>> Plot(x**2, [x,-13,13,100]) >>> Plot(x**2, [-13,13]) # [x,-13,13,100] >>> Plot(x**2, [x,-13,13]) # [x,-13,13,100] >>> Plot(1*x, [], [x], 'mode=cylindrical') # [unbound_theta,0,2*Pi,40], [x,-1,1,20] Using the Interactive Interface ------------------------------- :: >>> p = Plot(visible=False) >>> f = x**2 >>> p[1] = f >>> p[2] = f.diff(x) >>> p[3] = f.diff(x).diff(x) >>> p [1]: x**2, 'mode=cartesian' [2]: 2*x, 'mode=cartesian' [3]: 2, 'mode=cartesian' >>> p.show() >>> p.clear() >>> p >>> p[1] = x**2+y**2 >>> p[1].style = 'solid' >>> p[2] = -x**2-y**2 >>> p[2].style = 'wireframe' >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4) >>> p[1].style = 'both' >>> p[2].style = 'both' >>> p.close() Using Custom Color Functions ---------------------------- The following code plots a saddle and color it by the magnitude of its gradient: >>> fz = x**2-y**2 >>> Fx, Fy, Fz = fz.diff(x), fz.diff(y), 0 >>> p[1] = fz, 'style=solid' >>> p[1].color = (Fx**2 + Fy**2 + Fz**2)**(0.5) The coloring algorithm works like this: #. Evaluate the color function(s) across the curve or surface. #. Find the minimum and maximum value of each component. #. Scale each component to the color gradient. When not specified explicitly, the default color gradient is f(0.0)=(0.4,0.4,0.4) -> f(1.0)=(0.9,0.9,0.9). In our case, everything is gray-scale because we have applied the default color gradient uniformly for each color component. When defining a color scheme in this way, you might want to supply a color gradient as well: >>> p[1].color = (Fx**2 + Fy**2 + Fz**2)**(0.5), (0.1,0.1,0.9), (0.9,0.1,0.1) Here's a color gradient with four steps: >>> gradient = [ 0.0, (0.1,0.1,0.9), 0.3, (0.1,0.9,0.1), ... 0.7, (0.9,0.9,0.1), 1.0, (1.0,0.0,0.0) ] >>> p[1].color = (Fx**2 + Fy**2 + Fz**2)**(0.5), gradient The other way to specify a color scheme is to give a separate function for each component r, g, b. With this syntax, the default color scheme is defined: >>> p[1].color = z,y,x, (0.4,0.4,0.4), (0.9,0.9,0.9) This maps z->red, y->green, and x->blue. In some cases, you might prefer to use the following alternative syntax: >>> p[1].color = z,(0.4,0.9), y,(0.4,0.9), x,(0.4,0.9) You can still use multi-step gradients with three-function color schemes. .. _plot_geom: Plotting Geometric Entities --------------------------- The plotting module is capable of plotting some 2D geometric entities like line, circle and ellipse. The following example plots a circle centred at origin and of radius 2 units. :: >>> from sympy import * >>> x,y = symbols('x y') >>> plot_implicit(Eq(x**2+y**2, 4)) Similarly, ``plot_implicit()`` may be used to plot any 2-D geometric structure from its implicit equation. Plotting polygons (Polygon, RegularPolygon, Triangle) are not supported directly. Plotting with ASCII art ----------------------- .. autofunction:: sympy.plotting.textplot::textplot sympy-sympy-1.9/doc/src/modules/polys/000077500000000000000000000000001412543434000200755ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/polys/agca.rst000066400000000000000000000351041412543434000215250ustar00rootroot00000000000000.. _polys-agca: ======================================================== AGCA - Algebraic Geometry and Commutative Algebra Module ======================================================== Introduction ============ Algebraic geometry is a mixture of the ideas of two Mediterranean cultures. It is the superposition of the Arab science of the lightening calculation of the solutions of equations over the Greek art of position and shape. This tapestry was originally woven on European soil and is still being refined under the influence of international fashion. Algebraic geometry studies the delicate balance between the geometrically plausible and the algebraically possible. Whenever one side of this mathematical teeter-totter outweighs the other, one immediately loses interest and runs off in search of a more exciting amusement. George R. Kempf 1944 -- 2002 Algebraic Geometry refers to the study of geometric problems via algebraic methods (and sometimes vice versa). While this is a rather old topic, algebraic geometry as understood today is very much a 20th century development. Building on ideas of e.g. Riemann and Dedekind, it was realized that there is an intimate connection between properties of the set of solutions of a system of polynomial equations (called an algebraic variety) and the behavior of the set of polynomial functions on that variety (called the coordinate ring). As in many geometric disciplines, we can distinguish between local and global questions (and methods). Local investigations in algebraic geometry are essentially equivalent to the study of certain rings, their ideals and modules. This latter topic is also called commutative algebra. It is the basic local toolset of algebraic geometers, in much the same way that differential analysis is the local toolset of differential geometers. A good conceptual introduction to commutative algebra is [Atiyah69]_. An introduction more geared towards computations, and the work most of the algorithms in this module are based on, is [Greuel2008]_. This module aims to eventually allow expression and solution of both local and global geometric problems, both in the classical case over a field and in the more modern arithmetic cases. So far, however, there is no geometric functionality at all. Currently the module only provides tools for computational commutative algebra over fields. All code examples assume:: >>> from sympy import * >>> x, y, z = symbols('x,y,z') >>> init_printing(use_unicode=True, wrap_line=False) Reference ========= In this section we document the usage of the AGCA module. For convenience of the reader, some definitions and examples/explanations are interspersed. Base Rings ---------- Almost all computations in commutative algebra are relative to a "base ring". (For example, when asking questions about an ideal, the base ring is the ring the ideal is a subset of.) In principle all polys "domains" can be used as base rings. However, useful functionality is only implemented for polynomial rings over fields, and various localizations and quotients thereof. As demonstrated in the examples below, the most convenient method to create objects you are interested in is to build them up from the ground field, and then use the various methods to create new objects from old. For example, in order to create the local ring of the nodal cubic `y^2 = x^3` at the origin, over `\mathbb{Q}`, you do:: >>> lr = QQ.old_poly_ring(x, y, order="ilex") / [y**2 - x**3] >>> lr ℚ[x, y, order=ilex] ─────────────────── ╱ 3 2╲ ╲- x + y ╱ Note how the python list notation can be used as a short cut to express ideals. You can use the ``convert`` method to return ordinary sympy objects into objects understood by the AGCA module (although in many cases this will be done automatically -- for example the list was automatically turned into an ideal, and in the process the symbols `x` and `y` were automatically converted into other representations). For example:: >>> X, Y = lr.convert(x), lr.convert(y) ; X ╱ 3 2╲ x + ╲- x + y ╱ >>> x**3 == y**2 False >>> X**3 == Y**2 True When no localisation is needed, a more mathematical notation can be used. For example, let us create the coordinate ring of three-dimensional affine space `\mathbb{A}^3`:: >>> ar = QQ.old_poly_ring(x, y, z); ar ℚ[x, y, z] For more details, refer to the following class documentation. Note that the base rings, being domains, are the main point of overlap between the AGCA module and the rest of the polys module. All domains are documented in detail in the polys reference, so we show here only an abridged version, with the methods most pertinent to the AGCA module. .. autoclass:: sympy.polys.domains.ring.Ring :members: free_module, ideal, quotient_ring :noindex: .. autofunction:: sympy.polys.domains.polynomialring.PolynomialRing :noindex: .. autoclass:: sympy.polys.domains.quotientring.QuotientRing :noindex: Modules, Ideals and their Elementary Properties ----------------------------------------------- Let `A` be a ring. An `A`-module is a set `M`, together with two binary operations `+: M \times M \to M` and `\times: R \times M \to M` called addition and scalar multiplication. These are required to satisfy certain axioms, which can be found in e.g. [Atiyah69]_. In this way modules are a direct generalisation of both vector spaces (`A` being a field) and abelian groups (`A = \mathbb{Z}`). A *submodule* of the `A`-module `M` is a subset `N \subset M`, such that the binary operations restrict to `N`, and `N` becomes an `A`-module with these operations. The ring `A` itself has a natural `A`-module structure where addition and multiplication in the module coincide with addition and multiplication in the ring. This `A`-module is also written as `A`. An `A`-submodule of `A` is called an *ideal* of `A`. Ideals come up very naturally in algebraic geometry. More general modules can be seen as a technically convenient "elbow room" beyond talking only about ideals. If `M`, `N` are `A`-modules, then there is a natural (componentwise) `A`-module structure on `M \times N`. Similarly there are `A`-module structures on cartesian products of more components. (For the categorically inclined: the cartesian product of finitely many `A`-modules, with this `A`-module structure, is the finite biproduct in the category of all `A`-modules. With infinitely many components, it is the direct product (but the infinite direct sum has to be constructed differently).) As usual, repeated product of the `A`-module `M` is denoted `M, M^2, M^3 \ldots`, or `M^I` for arbitrary index sets `I`. An `A`-module `M` is called *free* if it is isomorphic to the `A`-module `A^I` for some (not necessarily finite) index set `I` (refer to the next section for a definition of isomorphism). The cardinality of `I` is called the *rank* of `M`; one may prove this is well-defined. In general, the AGCA module only works with free modules of finite rank, and other closely related modules. The easiest way to create modules is to use member methods of the objects they are made up from. For example, let us create a free module of rank 4 over the coordinate ring of `\mathbb{A}^2` we created above, together with a submodule:: >>> F = ar.free_module(4) ; F 4 ℚ[x, y, z] >>> S = F.submodule([1, x, x**2, x**3], [0, 1, 0, y]) ; S ╱⎡ 2 3⎤ ╲ ╲⎣1, x, x , x ⎦, [0, 1, 0, y]╱ Note how python lists can be used as a short-cut notation for module elements (vectors). As usual, the ``convert`` method can be used to convert sympy/python objects into the internal AGCA representation (see detailed reference below). Here is the detailed documentation of the classes for modules, free modules, and submodules: .. currentmodule:: sympy.polys.agca.modules .. autoclass:: Module :members: .. autoclass:: FreeModule :members: .. autoclass:: FreeModuleElement :members: .. autoclass:: SubModule :members: Ideals are created very similarly to modules. For example, let's verify that the nodal cubic is indeed singular at the origin:: >>> I = lr.ideal(x, y) >>> I == lr.ideal(x) False >>> I == lr.ideal(y) False We are using here the fact that a curve is non-singular at a point if and only if the maximal ideal of the local ring is principal, and that in this case at least one of `x` and `y` must be generators. This is the detailed documentation of the class ideal. Please note that most of the methods regarding properties of ideals (primality etc.) are not yet implemented. .. currentmodule:: sympy.polys.agca.ideals .. autoclass:: Ideal :members: If `M` is an `A`-module and `N` is an `A`-submodule, we can define two elements `x` and `y` of `M` to be equivalent if `x - y \in N`. The set of equivalence classes is written `M/N`, and has a natural `A`-module structure. This is called the quotient module of `M` by `N`. If `K` is a submodule of `M` containing `N`, then `K/N` is in a natural way a submodule of `M/N`. Such a module is called a subquotient. Here is the documentation of quotient and subquotient modules: .. currentmodule:: sympy.polys.agca.modules .. autoclass:: QuotientModule :members: .. autoclass:: QuotientModuleElement :members: .. autoclass:: SubQuotientModule :members: Module Homomorphisms and Syzygies --------------------------------- Let `M` and `N` be `A`-modules. A mapping `f: M \to N` satisfying various obvious properties (see [Atiyah69]_) is called an `A`-module homomorphism. In this case `M` is called the *domain* and *N* the *codomain*. The set `\{x \in M | f(x) = 0\}` is called the *kernel* `ker(f)`, whereas the set `\{f(x) | x \in M\}` is called the *image* `im(f)`. The kernel is a submodule of `M`, the image is a submodule of `N`. The homomorphism `f` is injective if and only if `ker(f) = 0` and surjective if and only if `im(f) = N`. A bijective homomorphism is called an *isomorphism*. Equivalently, `ker(f) = 0` and `im(f) = N`. (A related notion, which currently has no special name in the AGCA module, is that of the *cokernel*, `coker(f) = N/im(f)`.) Suppose now `M` is an `A`-module. `M` is called *finitely generated* if there exists a surjective homomorphism `A^n \to M` for some `n`. If such a morphism `f` is chosen, the images of the standard basis of `A^n` are called the *generators* of `M`. The module `ker(f)` is called *syzygy module* with respect to the generators. A module is called *finitely presented* if it is finitely generated with a finitely generated syzygy module. The class of finitely presented modules is essentially the largest class we can hope to be able to meaningfully compute in. It is an important theorem that, for all the rings we are considering, all submodules of finitely generated modules are finitely generated, and hence finitely generated and finitely presented modules are the same. The notion of syzygies, while it may first seem rather abstract, is actually very computational. This is because there exist (fairly easy) algorithms for computing them, and more general questions (kernels, intersections, ...) are often reduced to syzygy computation. Let us say a few words about the definition of homomorphisms in the AGCA module. Suppose first that `f : M \to N` is an arbitrary morphism of `A`-modules. Then if `K` is a submodule of `M`, `f` naturally defines a new homomorphism `g: K \to N` (via `g(x) = f(x)`), called the *restriction* of `f` to `K`. If now `K` contained in the kernel of `f`, then moreover `f` defines in a natural homomorphism `g: M/K \to N` (same formula as above!), and we say that `f` *descends* to `M/K`. Similarly, if `L` is a submodule of `N`, there is a natural homomorphism `g: M \to N/L`, we say that `g` *factors* through `f`. Finally, if now `L` contains the image of `f`, then there is a natural homomorphism `g: M \to L` (defined, again, by the same formula), and we say `g` is obtained from `f` by restriction of codomain. Observe also that each of these four operations is reversible, in the sense that given `g`, one can always (non-uniquely) find `f` such that `g` is obtained from `f` in the above way. Note that all modules implemented in AGCA are obtained from free modules by taking a succession of submodules and quotients. Hence, in order to explain how to define a homomorphism between arbitrary modules, in light of the above, we need only explain how to define homomorphisms of free modules. But, essentially by the definition of free module, a homomorphism from a free module `A^n` to any module `M` is precisely the same as giving `n` elements of `M` (the images of the standard basis), and giving an element of a free module `A^m` is precisely the same as giving `m` elements of `A`. Hence a homomorphism of free modules `A^n \to A^m` can be specified via a matrix, entirely analogously to the case of vector spaces. The functions ``restrict_domain`` etc. of the class ``Homomorphism`` can be used to carry out the operations described above, and homomorphisms of free modules can in principle be instantiated by hand. Since these operations are so common, there is a convenience function ``homomorphism`` to define a homomorphism between arbitrary modules via the method outlined above. It is essentially the only way homomorphisms need ever be created by the user. .. currentmodule:: sympy.polys.agca.homomorphisms .. autofunction:: homomorphism Finally, here is the detailed reference of the actual homomorphism class: .. autoclass:: ModuleHomomorphism :members: Finite Extensions ----------------- Let $A$ be a (commutative) ring and $B$ an extension ring of $A$. An element $t$ of $B$ is a generator of $B$ (over $A$) if all elements of $B$ can be represented as polynomials in $t$ with coefficients in $A$. The representation is unique if and only if $t$ satisfies no non-trivial polynomial relation, in which case $B$ can be identified with a (univariate) polynomial ring over $A$. The polynomials having $t$ as a root form a non-zero ideal in general. The most important case in practice is that of an ideal generated by a single monic polynomial. If $t$ satisfies such a polynomial relation, then its highest power $t^n$ can be written as linear combination of lower powers. It follows, inductively, that all higher powers of $t$ also have such a representation. Hence the lower powers $t^i$ ($i = 0, \dots, n-1$) form a basis of $B$, which is then called a finite extension of $A$, or, more precisely, a monogenic finite extension as it is generated by a single element $t$. .. currentmodule:: sympy.polys.agca.extensions .. autoclass:: MonogenicFiniteExtension :members: .. autoclass:: ExtensionElement :members: sympy-sympy-1.9/doc/src/modules/polys/basics.rst000066400000000000000000000520001412543434000220700ustar00rootroot00000000000000.. _polys-basics: ================================= Basic functionality of the module ================================= Introduction ============ This tutorial tries to give an overview of the functionality concerning polynomials within SymPy. All code examples assume:: >>> from sympy import * >>> x, y, z = symbols('x,y,z') >>> init_printing(use_unicode=False, wrap_line=False) Basic concepts ============== Polynomials ----------- Given a family `(x_i)` of symbols, or other suitable objects, including numbers, expressions derived from them by repeated addition, subtraction and multiplication are called *polynomial expressions in the generators* `x_i`. By the distributive law it is possible to perform multiplications before additions and subtractions. The products of generators thus obtained are called *monomials*. They are usually written in the form `x_1^{\nu_1}x_2^{\nu_2}\cdots x_n^{\nu_n}` where the exponents `\nu_i` are nonnegative integers. It is often convenient to write this briefly as `x^\nu` where `x = (x_1, x_2, \ldots, x_n)` denotes the family of generators and `\nu = (\nu_1, \nu_2, \ldots, \nu_n)` is the family of exponents. When all monomials having the same exponents are combined, the polynomial expression becomes a sum of products `c_\nu x^\nu`, called the *terms* of the polynomial, where the *coefficients* `c_\nu` are integers. If some of the `x_i` are manifest numbers, they are incorporated in the coefficients and not regarded as generators. Such coefficients are typically rational, real or complex numbers. Some symbolic numbers, e.g., ``pi``, can be either coefficients or generators. A polynomial expression that is a sum of terms with different monomials is uniquely determined by its family of coefficients `(c_\nu)`. Such an expression is customarily called a *polynomial*, though, more properly, that name does stand for the coefficient family once the generators are given. SymPy implements polynomials by default as dictionaries with monomials as keys and coefficients as values. Another implementation consists of nested lists of coefficients. The set of all polynomials with integer coefficients in the generators `x_i` is a *ring*, i.e., the sums, differences and products of its elements are again polynomials in the same generators. This ring is denoted `\mathbb{Z}[x_1, x_2, \ldots, x_n]`, or `\mathbb{Z}[(x_i)]`, and called the *ring of polynomials in the* `x_i` *with integer coefficients*. More generally, the coefficients of a polynomial can be elements of any commutative ring `A`, and the corresponding polynomial ring is then denoted `A[x_1, x_2, \dots, x_n]`. The ring `A` can also be a polynomial ring. In SymPy, the coefficient ring is called the ``domain`` of the polynomial ring, and it can be given as a keyword parameter. By default, it is determined by the coefficients of the polynomial arguments. Polynomial expressions can be transformed into polynomials by the method :obj:`sympy.core.expr.Expr.as_poly`:: >>> e = (x + y)*(y - 2*z) >>> e.as_poly() Poly(x*y - 2*x*z + y**2 - 2*y*z, x, y, z, domain='ZZ') If a polynomial expression contains numbers that are not integers, they are regarded as coefficients and the coefficient ring is extended accordingly. In particular, division by integers leads to rational coefficients:: >>> e = (3*x/2 + y)*(z - 1) >>> e.as_poly() Poly(3/2*x*z - 3/2*x + y*z - y, x, y, z, domain='QQ') Symbolic numbers are considered generators unless they are explicitly excluded, in which case they are adjoined to the coefficient ring:: >>> e = (x + 2*pi)*y >>> e.as_poly() Poly(x*y + 2*y*pi, x, y, pi, domain='ZZ') >>> e.as_poly(x, y) Poly(x*y + 2*pi*y, x, y, domain='ZZ[pi]') Alternatively, the coefficient domain can be specified by means of a keyword argument:: >>> e = (x + 2*pi)*y >>> e.as_poly(domain=ZZ[pi]) Poly(x*y + 2*pi*y, x, y, domain='ZZ[pi]') Note that the ring `\mathbb{Z}[\pi][x, y]` of polynomials in `x` and `y` with coefficients in `\mathbb{Z}[\pi]` is mathematically equivalent to `\mathbb{Z}[\pi, x, y]`, only their implementations differ. If an expression contains functions of the generators, other than their positive integer powers, these are interpreted as new generators:: >>> e = x*sin(y) - y >>> e.as_poly() Poly(x*(sin(y)) - y, x, y, sin(y), domain='ZZ') Since `y` and `\sin(y)` are algebraically independent they can both appear as generators in a polynomial. However, *polynomial expressions must not contain negative powers of generators*:: >>> e = x - 1/x >>> e.as_poly() Poly(x - (1/x), x, 1/x, domain='ZZ') It is important to realize that the generators `x` and `1/x = x^{-1}` are treated as algebraically independent variables. In particular, their product is not equal to 1. Hence *generators in denominators should be avoided even if they raise no error in the current implementation*. This behavior is undesirable and may change in the future. Similar problems emerge with rational powers of generators. So, for example, `x` and `\sqrt x = x^{1/2}` are not recognized as algebraically dependent. If there are algebraic numbers in an expression, it is possible to adjoin them to the coefficient ring by setting the keyword ``extension``:: >>> e = x + sqrt(2) >>> e.as_poly() Poly(x + (sqrt(2)), x, sqrt(2), domain='ZZ') >>> e.as_poly(extension=True) Poly(x + sqrt(2), x, domain='QQ') With the default setting ``extension=False``, both `x` and `\sqrt 2` are incorrectly considered algebraically independent variables. With coefficients in the extension field `\mathbb{Q}(\sqrt 2)` the square root is treated properly as an algebraic number. Setting ``extension=True`` whenever algebraic numbers are involved is definitely recommended even though it is not forced in the current implementation. Divisibility ------------ The fourth rational operation, division, or inverted multiplication, is not generally possible in rings. If `a` and `b` are two elements of a ring `A`, then there may exist a third element `q` in `A` such that `a = bq`. In fact, there may exist several such elements. If also `a = bq'` for some `q'` in `A`, then `b(q - q') = 0`. Hence either `b` or `q - q'` is zero, or they are both *zero divisors*, nonzero elements whose product is zero. Integral domains ```````````````` Commutative rings with no zero divisors are called *integral domains*. Most of the commonly encountered rings, the ring of integers, fields, and polynomial rings over integral domains are integral domains. Assume now that `A` is an integral domain, and consider the set `P` of its nonzero elements, which is closed under multiplication. If `a` and `b` are in `P`, and there exists an element `q` in `P` such that `a = bq`, then `q` is unique and called the *quotient*, `a/b`, of `a` by `b`. Moreover, it is said that - `a` is *divisible* by `b`, - `b` is a *divisor* of `a`, - `a` is a *multiple* of `b`, - `b` is a *factor* of `a`. An element `a` of `P` is a divisor of `1` if and only if it is *invertible* in `A`, with the inverse `a^{-1} = 1/a`. Such elements are called *units*. The units of the ring of integers are `1` and `-1`. The invertible elements in a polynomial ring over a field are the nonzero constant polynomials. If two elements of `P`, `a` and `b`, are divisible by each other, then the quotient `a/b` is invertible with inverse `b/a`, or equivalently, `b = ua` where `u` is a unit. Such elements are said to be *associated* with, or *associates* of, each other. The associates of an integer `n` are `n` and `-n`. In a polynomial ring over a field the associates of a polynomial are its constant multiples. Each element of `P` is divisible by its associates and the units. An element is *irreducible* if it has no other divisors and is not a unit. The irreducible elements in the ring of integers are the prime numbers `p` and their opposites `-p`. In a field, every nonzero element is invertible and there are no irreducible elements. Factorial domains ````````````````` In the ring of integers, each nonzero element can be represented as a product of irreducible elements and optionally a unit `\pm 1`. Moreover, any two such products have the same number of irreducible factors which are associated with each other in a suitable order. Integral domains having this property are called *factorial*, or *unique factorization domains*. In addition to the ring of integers, all polynomial rings over a field are factorial, and so are more generally polynomial rings over any factorial domain. Fields are trivially factorial since there are only units. The irreducible elements of a factorial domain are usually called *primes*. A family of integers has only a finite number of common divisors and the greatest of them is divisible by all of them. More generally, given a family of nonzero elements `(a_i)` in an integral domain, a common divisor `d` of the elements is called a *greatest common divisor*, abbreviated *gcd*, of the family if it is a multiple of all common divisors. A greatest common divisor, if it exists, is not unique in general; all of its associates have the same property. It is denoted by `d = \gcd(a_1,\ldots,a_n)` if there is no danger of confusion. A *least common multiple*, or *lcm*, of a family `(a_i)` is defined analogously as a common multiple `m` that divides all common multiples. It is denoted by `m = \operatorname{lcm}(a_1,\dots,a_n)`. In a factorial domain, greatest common divisors always exists. They can be found, at least in principle, by factoring each element of a family into a product of prime powers and an optional unit, and, for each prime, taking the least power that appears in the factorizations. The product of these prime powers is then a greatest common divisor. A least common multiple can be obtained from the same factorizations as the product of the greatest powers for each prime. Euclidean domains ````````````````` A practical algorithm for computing a greatest common divisor can be implemented in *Euclidean domains*. They are integral domains that can be endowed with a function `w` assigning a nonnegative integer to each nonzero element of the domain and having the following property: if `a` and `b` are nonzero, there are `q` and `r` that satisfy the *division identity* `a = qb + r` such that either `r = 0` or `w(r) < w(b)`. The ring of integers and all univariate polynomial rings over fields are Euclidean domains with `w(a) = |a|` resp. `w(a) = \deg(a)`. The division identity for integers is implemented in Python as the built-in function ``divmod`` that can also be applied to SymPy Integers:: >>> divmod(Integer(53), Integer(7)) (7, 4) For polynomials the division identity is given in SymPy by the function :func:`~.div`:: >>> f = 5*x**2 + 10*x + 3 >>> g = 2*x + 2 >>> q, r = div(f, g, domain='QQ') >>> q 5*x 5 --- + - 2 2 >>> r -2 >>> (q*g + r).expand() 2 5*x + 10*x + 3 The division identity can be used to determine the divisibility of elements in a Euclidean domain. If `r = 0` in the division identity, then `a` is divisible by `b`. Conversely, if `a = cb` for some element `c`, then `(c - q)b = r`. It follows that `c = q` and `r = 0` if `w` has the additional property: if `a` and `b` are nonzero, then `w(ab) \ge w(b)`. This is satisfied by the functions given above. (And it is always possible to redefine `w(a)` by taking the minimum of the values `w(xa)` for `x \ne 0`.) The principal application of the division identity is the efficient computation of a greatest common divisor by means of the `Euclidean algorithm `_. It applies to two elements of a Euclidean domain. A gcd of several elements can be obtained by iteration. The function for computing the greatest common divisor of integers in SymPy is currently :func:`~.igcd`:: >>> igcd(2, 4) 2 >>> igcd(5, 10, 15) 5 For univariate polynomials over a field the function has its common name :func:`~.gcd`, and the returned polynomial is monic:: >>> f = 4*x**2 - 1 >>> g = 8*x**3 + 1 >>> gcd(f, g, domain=QQ) x + 1/2 Divisibility of polynomials ``````````````````````````` The ring `A = \mathbb{Z}[x]` of univariate polynomials over the ring of integers is not Euclidean but it is still factorial. To see this, consider the divisibility in `A`. Let `f` and `g` be two nonzero polynomials in `A`. If `f` is divisible by `g` in `A`, then it is also divisible in the ring `B = \mathbb{Q}[x]` of polynomials with rational coefficients. Since `B` is Euclidean, this can be determined by means of the division identity. Assume, conversely, that `f = gh` for some polynomial `h` in `B`. Then `f` is divisible by `g` in `A` if and only if the coefficients of `h` are integers. To find out when this is true it is necessary to consider the divisibility of the coefficients. For a polynomial `f` in `A`, let `c` be the greatest common divisor of its coefficients. Then `f` is divisible by the constant polynomial `c` in `A`, and the quotient `f/c= p` is a polynomial whose coefficients are integers that have no common divisor apart from the units. Such polynomials are called *primitive*. A polynomial with rational coefficients can also be written as `f = cp`, where `c` is a rational number and `p` is a primitive polynomial. The constant `c` is called the *content* of `f`, and `p` is its *primitive part*. These components can be found by the method :obj:`sympy.core.expr.Expr.as_content_primitive`:: >>> f = 6*x**2 - 3*x + 9 >>> c, p = f.as_content_primitive() >>> c, p 2 (3, 2*x - x + 3) >>> f = x**2/3 - x/2 + 1 >>> c, p = f.as_content_primitive() >>> c, p 2 (1/6, 2*x - 3*x + 6) Let `f`, `f'` be polynomials with contents `c`, `c'` and primitive parts `p`, `p'`. Then `ff' = (cc')(pp')` where the product `pp'` is primitive by `Gauss's lemma `_. It follows that the content of a product of polynomials is the product of their contents and the primitive part of the product is the product of the primitive parts. Returning to the divisibility in the ring `\mathbb{Z}[x]`, assume that `f` and `g` are two polynomials with integer coefficients such that the division identity in `\mathbb{Q}[x]` yields the equality `f = gh` for some polynomial `h` with rational coefficients. Then the content of `f` is equal to the content of `g` multiplied by the content of `h`. As `h` has integer coefficients if and only if its content is an integer, we get the following criterion: `f` is divisible by `g` in the ring `\mathbb{Z}[x]` if and only if i. `f` is divisible by `g` in `\mathbb{Q}[x]`, and ii. the content of `f` is divisible by the content of `g` in `\mathbb{Z}`. If `f = cp` is irreducible in `\mathbb{Z}[x]`, then either `c` or `p` must be a unit. If `p` is not a unit, it must be irreducible also in `\mathbb{Q}[x]`. For if it is a product of two polynomials, it is also the product of their primitive parts, and one of them must be a unit. Hence there are two kinds of irreducible elements in `\mathbb{Z}[x]`: i. prime numbers of `\mathbb{Z}`, and ii. primitive polynomials that are irreducible in `\mathbb{Q}[x]`. It follows that each polynomial in `\mathbb{Z}[x]` is a product of irreducible elements. It suffices to factor its content and primitive part separately. These products are essentially unique; hence `\mathbb{Z}[x]` is also factorial. Another important consequence is that a greatest common divisor of two polynomials in `\mathbb{Z}[x]` can be found efficiently by applying the Euclidean algorithm separately to their contents and primitive parts in the Euclidean domains `\mathbb{Z}` and `\mathbb{Q}[x]`. This is also implemented in SymPy:: >>> f = 4*x**2 - 1 >>> g = 8*x**3 + 1 >>> gcd(f, g) 2*x + 1 >>> gcd(6*f, 3*g) 6*x + 3 Basic functionality =================== These functions provide different algorithms dealing with polynomials in the form of SymPy expression, like symbols, sums etc. Division -------- The function :func:`~.div` provides division of polynomials with remainder. That is, for polynomials ``f`` and ``g``, it computes ``q`` and ``r``, such that `f = g \cdot q + r` and `\deg(r) < \deg(q)`. For polynomials in one variables with coefficients in a field, say, the rational numbers, ``q`` and ``r`` are uniquely defined this way:: >>> f = 5*x**2 + 10*x + 3 >>> g = 2*x + 2 >>> q, r = div(f, g, domain='QQ') >>> q 5*x 5 --- + - 2 2 >>> r -2 >>> (q*g + r).expand() 2 5*x + 10*x + 3 As you can see, ``q`` has a non-integer coefficient. If you want to do division only in the ring of polynomials with integer coefficients, you can specify an additional parameter:: >>> q, r = div(f, g, domain='ZZ') >>> q 0 >>> r 2 5*x + 10*x + 3 But be warned, that this ring is no longer Euclidean and that the degree of the remainder doesn't need to be smaller than that of ``f``. Since 2 doesn't divide 5, `2 x` doesn't divide `5 x^2`, even if the degree is smaller. But:: >>> g = 5*x + 1 >>> q, r = div(f, g, domain='ZZ') >>> q x >>> r 9*x + 3 >>> (q*g + r).expand() 2 5*x + 10*x + 3 This also works for polynomials with multiple variables:: >>> f = x*y + y*z >>> g = 3*x + 3*z >>> q, r = div(f, g, domain='QQ') >>> q y - 3 >>> r 0 In the last examples, all of the three variables ``x``, ``y`` and ``z`` are assumed to be variables of the polynomials. But if you have some unrelated constant as coefficient, you can specify the variables explicitly:: >>> a, b, c = symbols('a,b,c') >>> f = a*x**2 + b*x + c >>> g = 3*x + 2 >>> q, r = div(f, g, domain='QQ') >>> q a*x 2*a b --- - --- + - 3 9 3 >>> r 4*a 2*b --- - --- + c 9 3 GCD and LCM ----------- With division, there is also the computation of the greatest common divisor and the least common multiple. When the polynomials have integer coefficients, the contents' gcd is also considered:: >>> f = (12*x + 12)*x >>> g = 16*x**2 >>> gcd(f, g) 4*x But if the polynomials have rational coefficients, then the returned polynomial is monic:: >>> f = 3*x**2/2 >>> g = 9*x/4 >>> gcd(f, g) x It also works with multiple variables. In this case, the variables are ordered alphabetically, be default, which has influence on the leading coefficient:: >>> f = x*y/2 + y**2 >>> g = 3*x + 6*y >>> gcd(f, g) x + 2*y The lcm is connected with the gcd and one can be computed using the other:: >>> f = x*y**2 + x**2*y >>> g = x**2*y**2 >>> gcd(f, g) x*y >>> lcm(f, g) 3 2 2 3 x *y + x *y >>> (f*g).expand() 4 3 3 4 x *y + x *y >>> (gcd(f, g, x, y)*lcm(f, g, x, y)).expand() 4 3 3 4 x *y + x *y Square-free factorization ------------------------- The square-free factorization of a univariate polynomial is the product of all factors (not necessarily irreducible) of degree 1, 2 etc.:: >>> f = 2*x**2 + 5*x**3 + 4*x**4 + x**5 >>> sqf_list(f) 2 (1, [(x + 2, 1), (x + x, 2)]) >>> sqf(f) 2 / 2 \ (x + 2)*\x + x/ Factorization ------------- This function provides factorization of univariate and multivariate polynomials with rational coefficients:: >>> factor(x**4/2 + 5*x**3/12 - x**2/3) 2 x *(2*x - 1)*(3*x + 4) ---------------------- 12 >>> factor(x**2 + 4*x*y + 4*y**2) 2 (x + 2*y) Groebner bases -------------- Buchberger's algorithm is implemented, supporting various monomial orders:: >>> groebner([x**2 + 1, y**4*x + x**3], x, y, order='lex') /[ 2 4 ] \ GroebnerBasis\[x + 1, y - 1], x, y, domain=ZZ, order=lex/ >>> groebner([x**2 + 1, y**4*x + x**3, x*y*z**3], x, y, z, order='grevlex') /[ 4 3 2 ] \ GroebnerBasis\[y - 1, z , x + 1], x, y, z, domain=ZZ, order=grevlex/ Solving Equations ----------------- We have (incomplete) methods to find the complex or even symbolic roots of polynomials and to solve some systems of polynomial equations:: >>> from sympy import roots, solve_poly_system >>> solve(x**3 + 2*x + 3, x) ____ ____ 1 \/ 11 *I 1 \/ 11 *I [-1, - - --------, - + --------] 2 2 2 2 >>> p = Symbol('p') >>> q = Symbol('q') >>> solve(x**2 + p*x + q, x) __________ __________ / 2 / 2 p \/ p - 4*q p \/ p - 4*q [- - - -------------, - - + -------------] 2 2 2 2 >>> solve_poly_system([y - x, x - 5], x, y) [(5, 5)] >>> solve_poly_system([y**2 - x**3 + 1, y*x], x, y) ___ ___ 1 \/ 3 *I 1 \/ 3 *I [(0, -I), (0, I), (1, 0), (- - - -------, 0), (- - + -------, 0)] 2 2 2 2 sympy-sympy-1.9/doc/src/modules/polys/domainmatrix.rst000066400000000000000000000030651412543434000233270ustar00rootroot00000000000000.. _polys-domainmatrix: =============================================== Introducing the domainmatrix of the poly module =============================================== This page introduces the idea behind domainmatrix which is used in SymPy's :mod:`sympy.polys` module. This is a relatively advanced topic so for a better understanding it is recommended to read about :py:class:`~.Domain` and :py:class:`~.DDM` along with :mod:`sympy.matrices` module. What is domainmatrix? ===================== It is way of associating Matrix with :py:class:`~.Domain`. A domainmatrix represents a matrix with elements that are in a particular Domain. Each domainmatrix internally wraps a DDM which is used for the lower-level operations. The idea is that the domainmatrix class provides the convenience routines for converting between Expr and the poly domains as well as unifying matrices with different domains. In general, we represent a matrix without concerning about the :py:class:`~.Domain` as: >>> from sympy import Matrix >>> from sympy.polys.matrices import DomainMatrix >>> A = Matrix([ ... [1, 2], ... [3, 4]]) >>> A Matrix([ [1, 2], [3, 4]]) DomainMatrix Class Reference ============================ .. :currentmodule:: sympy.polys.matrices .. autoclass:: sympy.polys.matrices.domainmatrix.DomainMatrix :members: DDM Class Reference =================== .. currentmodule:: sympy.polys.matrices.ddm .. autoclass:: DDM :members: SDM Class Reference =================== .. currentmodule:: sympy.polys.matrices.sdm .. autoclass:: SDM :members: sympy-sympy-1.9/doc/src/modules/polys/domainsintro.rst000066400000000000000000001554301412543434000233450ustar00rootroot00000000000000.. _polys-domainsintro: ========================================== Introducing the Domains of the poly module ========================================== This page introduces the idea of the "domains" that are used in SymPy's :mod:`sympy.polys` module. The emphasis is on introducing how to use the domains directly and on understanding how they are used internally as part of the :py:class:`~.Poly` class. This is a relatively advanced topic so for a more introductory understanding of the :py:class:`~.Poly` class and the :mod:`sympy.polys` module it is recommended to read :ref:`polys-basics` instead. The reference documentation for the domain classes is in :ref:`polys-domainsref`. Internal functions that make use of the domains are documented in :ref:`polys-internals`. What are the domains? ===================== For most users the domains are only really noticeable in the printed output of a :py:class:`~.Poly`:: >>> from sympy import Symbol, Poly >>> x = Symbol('x') >>> Poly(x**2 + x) Poly(x**2 + x, x, domain='ZZ') >>> Poly(x**2 + x/2) Poly(x**2 + 1/2*x, x, domain='QQ') We see here that one :py:class:`~.Poly` has domain :ref:`ZZ` representing the integers and the other has domain :ref:`QQ` representing the rationals. These indicate the "domain" from which the coefficients of the polynomial are drawn. From a high-level the domains represent formal concepts such as the set of integers `\mathbb{Z}` or rationals `\mathbb{Q}`. The word "domain" here is a reference to the mathematical concept of an `integral domain`_. .. _integral domain: https://en.wikipedia.org/wiki/Integral_domain Internally the domains correspond to different computational implementations and representations of the expressions that the polynomials correspond to. The :py:class:`~.Poly` object itself has an internal representation as a ``list`` of coefficients and a :py:attr:`~.Poly.domain` attribute representing the implementation of those coefficients:: >>> p = Poly(x**2 + x/2) >>> p Poly(x**2 + 1/2*x, x, domain='QQ') >>> p.domain QQ >>> p.rep DMP([1, 1/2, 0], QQ, None) >>> p.rep.rep [1, 1/2, 0] >>> type(p.rep.rep[0]) # doctest: +SKIP Here the domain is :ref:`QQ` which represents the implementation of the rational numbers in the domain system. The :py:class:`~.Poly` instance itself has a :py:attr:`.Poly.domain` attribute :ref:`QQ` and then a list of :py:class:`~.PythonMPQ` coefficients where :py:class:`~.PythonMPQ` is the class that implements the elements of the :ref:`QQ` domain. The list of coefficients ``[1, 1/2, 0]`` gives a standardised low-level representation of the polynomial expression ``(1)*x**2 + (1/2)*x + (0)``. This page looks at the different domains that are defined in SymPy, how they are implemented and how they can be used. It introduces how to use the domains and domain elements directly and explains how they are used internally as part of :py:class:`~.Poly` objects. This information is more relevant for development in SymPy than it is for users of the :mod:`sympy.polys` module. Representing expressions symbolically ===================================== There are many different ways that a mathematical expression can be represented symbolically. The purpose of the polynomial domains is to provide suitable implementations for different classes of expressions. This section considers the basic approaches to the symbolic representation of mathematical expressions: "tree", "dense polynomial" and "sparse polynomial". Tree representation ******************* The most general representation of symbolic expressions is as a `tree`_ and this is the representation used for most ordinary SymPy expressions which are instances of :py:class:`~.Expr` (a subclass of :py:class:`~.Basic`). We can see this representation using the :py:func:`~.srepr` function:: >>> from sympy import Symbol, srepr >>> x = Symbol('x') >>> e = 1 + 1/(2 + x**2) >>> e 1 + 1/(x**2 + 2) >>> print(srepr(e)) Add(Integer(1), Pow(Add(Pow(Symbol('x'), Integer(2)), Integer(2)), Integer(-1))) Here the expression ``e`` is represented as an :py:class:`~.Add` node which has two children ``1`` and ``1/(x**2 + 2)``. The child ``1`` is represented as an :py:class:`~.Integer` and the other child is represented as a :py:class:`~.Pow` with base ``x**2 + 2`` and exponent ``1``. Then ``x**2 + 2`` is represented as an :py:class:`~.Add` with children ``x**2`` and ``2`` and so on. In this way the expression is represented as a tree where the internal nodes are operations like :py:class:`~.Add`, :py:class:`~.Mul`, :py:class:`~.Pow` and so on and the leaf nodes are atomic expression types like :py:class:`~.Integer` and :py:class:`~.Symbol`. See :ref:`tutorial-manipulation` for more about this representation. The tree representation is core to the architecture of :py:class:`~.Expr` in SymPy. It is a highly flexible representation that can represent a very wide range of possible expressions. It can also represent equivalent expressions in different ways e.g.:: >>> e = x*(x + 1) >>> e x*(x + 1) >>> e.expand() x**2 + x These two expression although equivalent have different tree representations:: >>> print(srepr(e)) Mul(Symbol('x'), Add(Symbol('x'), Integer(1))) >>> print(srepr(e.expand())) Add(Pow(Symbol('x'), Integer(2)), Symbol('x')) Being able to represent the same expression in different ways is both a strength and a weakness. It is useful to be able to convert an expression in to different forms for different tasks but having non-unique representations makes it hard to tell when two expressions are equivalent which is in fact very important for many computational algorithms. The most important task is being able to tell when an expression is equal to zero which is undecidable in general (`Richardon's theorem`_) but is decidable in many important special cases. .. _tree: https://en.wikipedia.org/wiki/Tree_(data_structure) .. _Richardon's theorem: https://en.wikipedia.org/wiki/Richardson%27s_theorem .. _dup-representation: DUP representation ****************** Restricting the set of allowed expressions to special cases allows for much more efficient symbolic representations. As we already saw :py:class:`~.Poly` can represent a polynomial as a list of coefficients. This means that an expression like ``x**4 + x + 1`` could be represented simply as ``[1, 0, 0, 1, 1]``. This list of coefficients representation of a polynomial expression is known as the "dense univariate polynomial" (DUP) representation. Working within that representation algorithms for multiplication, addition and crucially zero-testing can be much more efficient than with the corresponding tree representations. We can see this representation from a :py:class:`~.Poly` instance by looking it its ``rep.rep`` attribute:: >>> p = Poly(x**4 + x + 1) >>> p.rep.rep [1, 0, 0, 1, 1] In the DUP representation it is not possible to represent the same expression in different ways. There is no distinction between ``x*(x + 1)`` and ``x**2 + x`` because both are just ``[1, 1, 0]``. This means that comparing two expressions is easy: they are equal if and only if all of their coefficients are equal. Zero-testing is particularly easy: the polynomial is zero if and only if all coefficients are zero (of course we need to have easy zero-testing for the coefficients themselves). We can make functions that operate on the DUP representation much more efficiently than functions that operate on the tree representation. Many operations with standard sympy expressions are in fact computed by converting to a polynomial representation and then performing the calculation. An example is the :py:func:`~.factor` function:: >>> from sympy import factor >>> e = 2*x**3 + 10*x**2 + 16*x + 8 >>> e 2*x**3 + 10*x**2 + 16*x + 8 >>> factor(e) 2*(x + 1)*(x + 2)**2 Internally :py:func:`~.factor` will convert the expression from the tree representation into the DUP representation and then use the function ``dup_factor_list``:: >>> from sympy import ZZ >>> from sympy.polys.factortools import dup_factor_list >>> p = [ZZ(2), ZZ(10), ZZ(16), ZZ(8)] >>> p [2, 10, 16, 8] >>> dup_factor_list(p, ZZ) (2, [([1, 1], 1), ([1, 2], 2)]) There are many more examples of functions with ``dup_*`` names for operating on the DUP representation that are documented in :ref:`polys-internals`. There are also functions with the ``dmp_*`` prefix for operating on multivariate polynomials. .. _dmp-representation: DMP representation ****************** A multivariate polynomial (a polynomial in multiple variables) can be represented as a polynomial with coefficients that are themselves polynomials. For example ``x**2*y + x**2 + x*y + y + 1`` can be represented as polynomial in ``x`` where the coefficients are themselves polynomials in ``y`` i.e.: ``(y + 1)*x**2 + (y)*x + (y+1)``. Since we can represent a polynomial with a list of coefficients a multivariate polynomial can be represented with a list of lists of coefficients:: >>> from sympy import symbols >>> x, y = symbols('x, y') >>> p = Poly(x**2*y + x**2 + x*y + y + 1) >>> p Poly(x**2*y + x**2 + x*y + y + 1, x, y, domain='ZZ') >>> p.rep.rep [[1, 1], [1, 0], [1, 1]] This list of lists of (lists of...) coefficients representation is known as the "dense multivariate polynomial" (DMP) representation. .. _sparse-poly-representation: Sparse polynomial representation ******************************** Instead of lists we can use a dict mapping nonzero monomial terms to their coefficients. This is known as the "sparse polynomial" representation. We can see what this would look like using the :py:meth:`~.Poly.as_dict` method:: >>> Poly(7*x**20 + 8*x + 9).rep.rep [7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 9] >>> Poly(7*x**20 + 8*x + 9).as_dict() {(0,): 9, (1,): 8, (20,): 7} The keys of this dict are the exponents of the powers of ``x`` and the values are the coefficients so e.g. ``7*x**20`` becomes ``(20,): 7`` in the dict. The key is a tuple so that in the multivariate case something like ``4*x**2*y**3`` can be represented as ``(2, 3): 4``. The sparse representation can be more efficient as it avoids the need to store and manipulate the zero coefficients. With a large number of generators (variables) the dense representation becomes particularly inefficient and it is better to use the sparse representation:: >>> from sympy import prod >>> gens = symbols('x:10') >>> gens (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) >>> p = Poly(prod(gens)) >>> p Poly(x0*x1*x2*x3*x4*x5*x6*x7*x8*x9, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, domain='ZZ') >>> p.rep.rep [[[[[[[[[[1, 0], []], [[]]], [[[]]]], [[[[]]]]], [[[[[]]]]]], [[[[[[]]]]]]], [[[[[[[]]]]]]]], [[[[[[[[]]]]]]]]], [[[[[[[[[]]]]]]]]]] >>> p.as_dict() {(1, 1, 1, 1, 1, 1, 1, 1, 1, 1): 1} The dict representation shown in the last output maps from the monomial which is represented as a tuple of powers (``(1, 1, 1, ...)`` i.e. ``x0**1 * x1**1, ...``) to the coefficient ``1``. Compared to the :ref:`dmp-representation` we have a much more flattened data structure: it is a ``dict`` with only one key and value. Algorithms for working with sparse representations would likely be much more efficient than dense algorithms for this particular example polynomial. SymPy's polynomial module has implementations of polynomial expressions based on both the dense and sparse representations. There are also other implementations of different special classes of expressions that can be used as the coefficients of those polynomials. The rest of this page discusses what those representations are and how to use them. Basic usage of domains ====================== Several domains are predefined and ready to be used such as :ref:`ZZ` and :ref:`QQ` which represent the ring of integers `\mathbb{Z}` and the field of rationals `\mathbb{Q}`. The :py:class:`~.Domain` object is used to construct elements which can then be used in ordinary arithmetic operations.:: >>> from sympy import ZZ >>> z1 = ZZ(2) >>> z1 2 >>> z1 + z1 4 >>> type(z1) # doctest: +SKIP >>> z1 in ZZ True The basic operations ``+``, ``-``, and ``*`` for addition, subtraction and multiplication will work for the elements of any domain and will produce new domain elements. Division with ``/`` (Python's "true division" operator) is not possible for all domains and should not be used with domain elements unless the domain is known to be a field. For example dividing two elements of :ref:`ZZ` gives a ``float`` which is not an element of :ref:`ZZ`:: >>> z1 / z1 1.0 >>> type(z1 / z1) # doctest: +SKIP >>> ZZ.is_Field False Most domains representing non-field rings allow floor and modulo division (remainder) with Python's floor division ``//`` and modulo division ``%`` operators. For example with :ref:`ZZ`:: >>> z1 // z1 1 >>> z1 % z1 0 The :ref:`QQ` domain represents the field of rational numbers and does allow division:: >>> from sympy import QQ >>> q1 = QQ(1, 2) >>> q1 1/2 >>> q2 = QQ(2, 3) >>> q2 2/3 >>> q1 / q2 3/4 >>> type(q1) # doctest: +SKIP In general code that is expected to work with elements of an arbitrary domain should not use the division operators ``/``, ``//`` and ``%``. Only the operators ``+``, ``-``, ``*`` and ``**`` (with nonnegative integer exponent) should be assumed to work with arbitrary domain elements. All other operations should be accessed as functions from the :py:class:`~.Domain` object:: >>> ZZ.quo(ZZ(5), ZZ(3)) # 5 // 3 1 >>> ZZ.rem(ZZ(5), ZZ(3)) # 5 % 3 2 >>> ZZ.div(ZZ(5), ZZ(3)) # divmod(5, 3) (1, 2) >>> QQ.div(QQ(5), QQ(3)) (5/3, 0) The :py:meth:`~.Domain.exquo` function is used to compute an exact quotient. This is the analogue of ``a / b`` but where the division is expected to be exact (with no remainder) or an error will be raised:: >>> QQ.exquo(QQ(5), QQ(3)) 5/3 >>> ZZ.exquo(ZZ(4), ZZ(2)) 2 >>> ZZ.exquo(ZZ(5), ZZ(3)) Traceback (most recent call last): ... ExactQuotientFailed: 3 does not divide 5 in ZZ The exact methods and attributes of the domain elements are not guaranteed in general beyond the basic arithmetic operations. It should not be presumed that e.g. :ref:`ZZ` will always be of type ``int``. If ``gmpy`` or ``gmpy2`` is installed then the ``mpz`` or ``mpq`` types are used instead for :ref:`ZZ` and :ref:`QQ`:: >>> from sympy import ZZ, QQ >>> ZZ(2) # doctest: +SKIP mpz(2) >>> QQ(2, 3) # doctest: +SKIP mpq(2, 3) The ``mpz`` type is faster than Python's standard ``int`` type for operations with large integers although for smaller integers the difference is not so significant. The ``mpq`` type representing rational numbers is implemented in C rather than Python and is many times faster than the pure Python implementation of :ref:`QQ` that is used when gmpy is not installed. In general the Python type used for the elements of a domain can be checked from the :py:attr:`~.Domain.dtype` attribute of the domain. When gmpy is installed the dtype for :ref:`ZZ` is `mpz` which is not an actual type and can not be used with `isinstance`. For this reason the :py:meth:`~.Domain.of_type` method can be used to check if an object is an element of :py:attr:`~.Domain.dtype`.:: >>> z = ZZ(2) >>> type(z) # doctest: +SKIP >>> ZZ.dtype # doctest: +SKIP >>> ZZ.of_type(z) True Domain elements vs sympy expressions ==================================== Note that domain elements are not of the same type as ordinary sympy expressions which are subclasses of :py:class:`~.Expr` such as :py:class:`~sympy.core.numbers.Integer`. Ordinary sympy expressions are created with the :py:func:`~sympy.core.sympify.sympify` function.:: >>> from sympy import sympify >>> z1_sympy = sympify(2) # Normal sympy object >>> z1_sympy 2 >>> type(z1_sympy) >>> from sympy import Expr >>> isinstance(z1_sympy, Expr) True It is important when working with the domains not to mix sympy expressions with domain elements even though it will sometimes work in simple cases. Each domain object has the methods :py:meth:`~.Domain.to_sympy` and :py:meth:`~.Domain.from_sympy` for converting back and forth between sympy expressions and domain elements:: >>> z_sympy = sympify(2) >>> z_zz = ZZ.from_sympy(z_sympy) >>> z_zz 2 >>> type(z_sympy) >>> type(z_zz) # doctest: +SKIP >>> ZZ.to_sympy(z_zz) 2 >>> type(ZZ.to_sympy(z_zz)) Any particular domain will only be able to represent some sympy expressions so conversion will fail if the expression can not be represented in the domain:: >>> from sympy import sqrt >>> e = sqrt(2) >>> e sqrt(2) >>> ZZ.from_sympy(e) Traceback (most recent call last): ... CoercionFailed: expected an integer, got sqrt(2) We have already seen that in some cases we can use the domain object itself as a constructor e.g. ``QQ(2)``. This will generally work provided the arguments given are valid for the :py:attr:`~.Domain.dtype` of the domain. Although it is convenient to use this in interactive sessions and in demonstrations it is generally better to use the :py:meth:`~.Domain.from_sympy` method for constructing domain elements from sympy expressions (or from objects that can be sympified to sympy expressions). It is important not to mix domain elements with other Python types such as ``int``, ``float``, as well as standard sympy :py:class:`~.Expr` expressions. When working in a domain, care should be taken as some Python operations will do this implicitly. for example the ``sum`` function will use the regular ``int`` value of zero so that ``sum([a, b])`` is effectively evaluated as ``(0 + a) + b`` where ``0`` is of type ``int``. Every domain is at least a ring if not a field and as such is guaranteed to have two elements in particular corresponding to `1` and `0`. The domain object provides domain elements for these as the attributes :py:attr:`~.Domain.one` and :py:attr:`~.Domain.zero`. These are useful for something like Python's ``sum`` function which allows to provide an alternative object as the "zero":: >>> ZZ.one 1 >>> ZZ.zero 0 >>> sum([ZZ(1), ZZ(2)]) # don't do this (even it sometimes works) 3 >>> sum([ZZ(1), ZZ(2)], ZZ.zero) # provide the zero from the domain 3 A standard pattern then for performing calculations in a domain is: #. Start with sympy :py:class:`~.Expr` instances representing expressions. #. Choose an appropriate domain that can represent the expressions. #. Convert all expressions to domain elements using :py:meth:`~.Domain.from_sympy`. #. Perform the calculation with the domain elements. #. Convert back to :py:class:`~.Expr` with :py:meth:`~.Domain.to_sympy`. Here is an implementation of the ``sum`` function that illustrates these steps and sums some integers but performs the calculation using the domain elements rather than standard sympy expressions:: def sum_domain(expressions_sympy): """Sum sympy expressions but performing calculations in domain ZZ""" # Convert to domain expressions_dom = [ZZ.from_sympy(e) for e in expressions_sympy] # Perform calculations in the domain result_dom = ZZ.zero for e_dom in expressions_dom: result_dom += e_dom # Convert the result back to Expr result_sympy = ZZ.to_sympy(result_dom) return result_sympy Gaussian integers and Gaussian rationals ======================================== The two example domains that we have seen so far are :ref:`ZZ` and :ref:`QQ` representing the integers and the rationals respectively. There are other simple domains such as :ref:`ZZ_I` and :ref:`QQ_I` representing the `Gaussian integers`_ and `Gaussian rationals`_. The Gaussian integers are numbers of the form `a\sqrt{-1} + b` where `a` and `b` are integers. The Gaussian rationals are defined similarly except that `a` and `b` can be rationals. We can use the Gaussian domains like:: >>> from sympy import ZZ_I, QQ_I, I >>> z = ZZ_I.from_sympy(1 + 2*I) >>> z (1 + 2*I) >>> z**2 (-3 + 4*I) Note the contrast with the way this calculation works in the tree representation where :py:func:`~.expand` is needed to get the reduced form:: >>> from sympy import expand, I >>> z = 1 + 2*I >>> z**2 (1 + 2*I)**2 >>> expand(z**2) -3 + 4*I The :ref:`ZZ_I` and :ref:`QQ_I` domains are implemented by the classes :py:class:`~.GaussianIntegerRing` and :py:class:`~.GaussianRationalField` and their elements by :py:class:`~.GaussianInteger` and :py:class:`~.GaussianRational` respectively. The internal representation for an element of :ref:`ZZ_I` or :ref:`QQ_I` is simply as a pair ``(a, b)`` of elements of :ref:`ZZ` or :ref:`QQ` respectively. The domain :ref:`ZZ_I` is a ring with similar properties to :ref:`ZZ` whereas :ref:`QQ_I` is a field much like :ref:`QQ`:: >>> ZZ.is_Field False >>> QQ.is_Field True >>> ZZ_I.is_Field False >>> QQ_I.is_Field True Since :ref:`QQ_I` is a field division by nonzero elements is always possible whereas in :ref:`ZZ_I` we have the important concept of the greatest common divisor (GCD):: >>> e1 = QQ_I.from_sympy(1+I) >>> e2 = QQ_I.from_sympy(2-I/2) >>> e1/e2 (6/17 + 10/17*I) >>> ZZ_I.gcd(ZZ_I(5), ZZ_I.from_sympy(1+2*I)) (1 + 2*I) .. _Gaussian integers: https://en.wikipedia.org/wiki/Gaussian_integer .. _Gaussian rationals: https://en.wikipedia.org/wiki/Gaussian_rational Finite fields ============= So far we have seen the domains :ref:`ZZ`, :ref:`QQ`, :ref:`ZZ_I`, and :ref:`QQ_I`. There are also domains representing the `Finite fields`_ although the implementation of these is incomplete. A finite field :ref:`GF(p)` of *prime* order can be constructed with ``FF`` or ``GF``. A domain for the finite field of prime order `p` can be constructed with :ref:`GF(p)`:: >>> from sympy import GF >>> K = GF(5) >>> two = K(2) >>> two 2 mod 5 >>> two ** 2 4 mod 5 >>> two ** 3 3 mod 5 There is also ``FF`` as an alias for ``GF`` (standing for "finite field" and "Galois field" respectively). These are equivalent and both ``FF(n)`` and ``GF(n)`` will create a domain which is an instance of :py:class:`~.FiniteField`. The associated domain elements will be instances of :py:class:`~.PythonFiniteField` or :py:class:`~.GMPYFiniteField` depending on whether or not ``gmpy`` is installed. Finite fields of order `p^n` where `n \ne 1` are not implemented. It is possible to use e.g. ``GF(6)`` or ``GF(9)`` but the resulting domain is *not* a field. It is just the integers modulo ``6`` or ``9`` and therefore has zero divisors and non-invertible elements:: >>> K = GF(6) >>> K(3) * K(2) 0 mod 6 It would be good to have a proper implementation of prime-power order finite fields but this is not yet available in SymPy (contributions welcome!). .. _Finite fields: https://en.wikipedia.org/wiki/Finite_field Real and complex fields ======================= The fields :ref:`RR` and :ref:`CC` are intended mathematically to correspond to the `reals`_ and the `complex numbers`_, `\mathbb{R}` and `\mathbb{C}` respectively. The implementation of these uses floating point arithmetic. In practice this means that these are the domains that are used to represent expressions containing floats. Elements of :ref:`RR` are instances of the class :py:class:`~.RealElement` and have an ``mpf`` tuple which is used to represent a float in ``mpmath``. Elements of :ref:`CC` are instances of :py:class:`~.ComplexElement` and have an ``mpc`` tuple which is a pair of ``mpf`` tuples representing the real and imaginary parts. See the `mpmath docs`_ for more about how floating point numbers are represented:: >>> from sympy import RR, CC >>> xr = RR(3) >>> xr 3.0 >>> xr._mpf_ (0, 3, 0, 2) >>> zc = CC(3+1j) >>> zc (3.0 + 1.0j) >>> zc._mpc_ ((0, 3, 0, 2), (0, 1, 0, 1)) The use of approximate floating point arithmetic in these domains comes with all of the usual pitfalls. Many algorithms in the :mod:`sympy.polys` module are fundamentally designed for exact arithmetic making the use of these domains potentially problematic:: >>> RR('0.1') + RR('0.2') == RR('0.3') False Since these are implemented using ``mpmath`` which is a multiprecision library it is possible to create different domains with different working precisions. The default domains :ref:`RR` and :ref:`CC` use 53 binary digits of precision much like standard `double precision`_ floating point which corresponds to approximately 15 decimal digits:: >>> from sympy.polys.domains.realfield import RealField >>> RR.precision 53 >>> RR.dps 15 >>> RR(1) / RR(3) 0.333333333333333 >>> RR100 = RealField(100) >>> RR100.precision 100 >>> RR100.dps 29 >>> RR100(1) / RR100(3) 0.33333333333333333333333333333 There is however a bug in the implementation of this so that actually a global precision setting is used by all :py:class:`~.RealElement`. This means that just creating ``RR100`` above has altered the global precision and we will need to restore it in the doctest here:: >>> RR(1) / RR(3) # wrong result! 0.33333333333333333333333333333 >>> dummy = RealField(53) # hack to restore precision >>> RR(1) / RR(3) # restored 0.333333333333333 (Obviously that should be fixed!) .. _reals: https://en.wikipedia.org/wiki/Real_number .. _complex numbers: https://en.wikipedia.org/wiki/Complex_number .. _mpmath docs: https://mpmath.org/doc/current/technical.html#representation-of-numbers .. _double precision: https://en.wikipedia.org/wiki/Double-precision_floating-point_format Algebraic number fields ======================= An `algebraic extension`_ of the rationals `\mathbb{Q}` is known as an `algebraic number field`_ and these are implemented in sympy as :ref:`QQ(a)`. The natural syntax for these would be something like ``QQ(sqrt(2))`` however ``QQ()`` is already overloaded as the constructor for elements of :ref:`QQ`. These domains are instead created using the :py:meth:`~.Domain.algebraic_field` method e.g. ``QQ.algebraic_field(sqrt(2))``. The resulting domain will be an instance of :py:class:`~.AlgebraicField` with elements that are instances of :py:class:`~.ANP`. The printing support for these is less developed but we can use :py:meth:`~.Domain.to_sympy` to take advantage of the corresponding :py:class:`~.Expr` printing support:: >>> K = QQ.algebraic_field(sqrt(2)) >>> K QQ >>> b = K.one + K.from_sympy(sqrt(2)) >>> b # doctest: +SKIP ANP([1, 1], [1, 0, -2], QQ) >>> K.to_sympy(b) 1 + sqrt(2) >>> b ** 2 # doctest: +SKIP ANP([2, 3], [1, 0, -2], QQ) >>> K.to_sympy(b**2) 2*sqrt(2) + 3 The raw printed display immediately shows the internal representation of the elements as :py:class:`~.ANP` instances. The field `\mathbb{Q}(\sqrt{2})` consists of numbers of the form `a\sqrt{2}+b` where `a` and `b` are rational numbers. Consequently every number in this field can be represented as a pair ``(a, b)`` of elements of :ref:`QQ`. The domain element stores these two in a list and also stores a list representation of the *minimal polynomial* for the extension element `\sqrt{2}`. There is a sympy function :py:func:`~.minpoly` that can compute the minimal polynomial of any algebraic expression over the rationals:: >>> from sympy import minpoly, Symbol >>> x = Symbol('x') >>> minpoly(sqrt(2), x) x**2 - 2 In the dense polynomial representation as a list of coefficients this polynomial is represented as ``[1, 0, -2]`` as seen in the :py:class:`~.ANP` display for the elements of ``QQ`` above. It is also possible to create an algebraic number field with multiple generators such as `\mathbb{Q}(\sqrt{2},\sqrt{3})`:: >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) >>> K QQ >>> sqrt2 = K.from_sympy(sqrt(2)) >>> sqrt3 = K.from_sympy(sqrt(3)) >>> p = (K.one + sqrt2) * (K.one + sqrt3) >>> p # doctest: +SKIP ANP([1/2, 1, -3/2], [1, 0, -10, 0, 1], QQ) >>> K.to_sympy(p) 1 + sqrt(2) + sqrt(3) + sqrt(6) >>> K.to_sympy(p**2) 4*sqrt(6) + 6*sqrt(3) + 8*sqrt(2) + 12 Here the algebraic extension `\mathbb{Q}(\sqrt{2},\sqrt{3})` is converted to the (isomorphic) `\mathbb{Q}(\sqrt{2}+\sqrt{3})` with a single generator `\sqrt{2}+\sqrt{3}`. It is always possible to find a single generator like this due to the `primitive element theorem`_. There is a sympy function :py:func:`~.primitive_element` that can compute the minimal polynomial for a primitive element of an extension:: >>> from sympy import primitive_element, minpoly >>> e = primitive_element([sqrt(2), sqrt(3)], x) >>> e[0] x**4 - 10*x**2 + 1 >>> e[0].subs(x, sqrt(2) + sqrt(3)).expand() 0 The minimal polynomial ``x**4 - 10*x**2 + 1`` has the dense list representation ``[1, 0, -10, 0, 1]`` as seen in the :py:class:`~.ANP` output above. What the primitive element theorem means is that all algebraic number fields can be represented as an extension of the rationals by a single generator with some minimal polynomial. Calculations over the algebraic number field only need to take advantage of the minimal polynomial and that makes it possible to compute all arithmetic operations and also to carry out higher level operations like factorisation of polynomials. .. _algebraic extension: https://en.wikipedia.org/wiki/Algebraic_extension .. _algebraic number field: https://en.wikipedia.org/wiki/Algebraic_number_field .. _primitive element theorem: https://en.wikipedia.org/wiki/Primitive_element_theorem Polynomial ring domains ======================= There are also domains implemented to represent a polynomial ring like :ref:`K[x]` which is the domain of polynomials in the generator ``x`` with coefficients over another domain ``K``:: >>> from sympy import ZZ, symbols >>> x = symbols('x') >>> K = ZZ[x] >>> K ZZ[x] >>> x_dom = K(x) >>> x_dom + K.one x + 1 All the operations discussed before will work with elements of a polynomial ring:: >>> p = x_dom + K.one >>> p x + 1 >>> p + p 2*x + 2 >>> p - p 0 >>> p * p x**2 + 2*x + 1 >>> p ** 3 x**3 + 3*x**2 + 3*x + 1 >>> K.exquo(x_dom**2 - K.one, x_dom - K.one) x + 1 The internal representation of elements of ``K[x]`` is different from the way that ordinary sympy (:py:class:`~.Expr`) expressions are represented. The :py:class:`~.Expr` representation of any expression is as a tree e.g.:: >>> from sympy import srepr >>> K = ZZ[x] >>> p_expr = x**2 + 2*x + 1 >>> p_expr x**2 + 2*x + 1 >>> srepr(p_expr) "Add(Pow(Symbol('x'), Integer(2)), Mul(Integer(2), Symbol('x')), Integer(1))" Here the expression is a tree where the top node is an :py:class:`~.Add` and its children nodes are :py:class:`~.Pow` etc. This tree representation makes it possible to represent equivalent expressions in different ways e.g.:: >>> x = symbols('x') >>> p_expr = x*(x + 1) + x >>> p_expr x*(x + 1) + x >>> p_expr.expand() x**2 + 2*x By contrast the domain ``ZZ[x]`` represents only polynomials and does so by simply storing the non-zero coefficients of the expanded polynomial (the "sparse" polynomial representation). In particular elements of ``ZZ[x]`` are represented as a Python ``dict``. Their type is :py:class:`~.PolyElement` which is a subclass of ``dict``. Converting to a normal dict shows the internal representation:: >>> x = symbols('x') >>> K = ZZ[x] >>> x_dom = K(x) >>> p_dom = K(3)*x_dom**2 + K(2)*x_dom + K(7) >>> p_dom 3*x**2 + 2*x + 7 >>> dict(p_dom) {(0,): 7, (1,): 2, (2,): 3} This internal form makes it impossible to represent unexpanded multiplications so any multiplication of elements of ``ZZ[x]`` will always be expanded:: >>> x = symbols('x') >>> K = ZZ[x] >>> x_dom = K(x) >>> p_expr = x * (x + 1) + x >>> p_expr x*(x + 1) + x >>> p_dom = x_dom * (x_dom + K.one) + x_dom >>> p_dom x**2 + 2*x These same considerations apply to powers:: >>> (x + 1) ** 2 (x + 1)**2 >>> (x_dom + K.one) ** 2 x**2 + 2*x + 1 We can also construct multivariate polynomial rings:: >>> x, y = symbols('x, y') >>> K = ZZ[x,y] >>> xk = K(x) >>> yk = K(y) >>> xk**2*yk + xk + yk x**2*y + x + y It is also possible to construct nested polynomial rings (although it is less efficient). The ring ``K[x][y]`` is formally equivalent to ``K[x,y]`` although their implementations in sympy are different:: >>> K = ZZ[x][y] >>> p = K(x**2 + x*y + y**2) >>> p y**2 + x*y + x**2 >>> dict(p) {(0,): x**2, (1,): x, (2,): 1} Here the coefficients like ``x**2`` are instances of :py:class:`~.PolyElement` as well so this is a ``dict`` where the values are also dicts. The full representation is more like:: >>> {k: dict(v) for k, v in p.items()} {(0,): {(2,): 1}, (1,): {(1,): 1}, (2,): {(0,): 1}} The multivariate ring domain ``ZZ[x,y]`` has a more efficient representation as a single flattened ``dict``:: >>> K = ZZ[x,y] >>> p = K(x**2 + x*y + y**2) >>> p x**2 + x*y + y**2 >>> dict(p) {(0, 2): 1, (1, 1): 1, (2, 0): 1} The difference in efficiency between these representations grows as the number of generators increases i.e. ``ZZ[x,y,z,t,...]`` vs ``ZZ[x][y][z][t]...``. Old (dense) polynomial rings ============================ In the last section we saw that the domain representation of a polynomial ring like :ref:`K[x]` uses a sparse representation of a polynomial as a dict mapping monomial exponents to coefficients. There is also an older version of :ref:`K[x]` that uses the dense :ref:`dmp-representation`. We can create these two versions of :ref:`K[x]` using :py:meth:`~.Domain.poly_ring` and :py:meth:`~.Domain.old_poly_ring` where the syntax ``K[x]`` is equivalent to ``K.poly_ring(x)``:: >>> K1 = ZZ.poly_ring(x) >>> K2 = ZZ.old_poly_ring(x) >>> K1 ZZ[x] >>> K2 ZZ[x] >>> K1 == ZZ[x] True >>> K2 == ZZ[x] False >>> p1 = K1.from_sympy(x**2 + 1) >>> p2 = K2.from_sympy(x**2 + 1) >>> p1 x**2 + 1 >>> p2 x**2 + 1 >>> type(K1) >>> type(p1) >>> type(K2) >>> type(p2) The internal representation of the old polynomial ring domain is the :py:class:`~.DMP` representation as a list of (lists of) coefficients:: >>> repr(p2) # doctest: +SKIP 'DMP([1, 0, 1], ZZ, ZZ[x])' The most notable use of the :py:class:`~.DMP` representation of polynomials is as the internal representation used by :py:class:`~.Poly` (this is discussed later in this page of the docs). PolyRing vs PolynomialRing ========================== You might just want to perform calculations in some particular polynomial ring without being concerned with implementing something that works for arbitrary domains. In that case you can construct the ring more directly with the :py:func:`~.ring` function:: >>> from sympy import ring >>> K, xr, yr = ring([x, y], ZZ) >>> K Polynomial ring in x, y over ZZ with lex order >>> xr**2 - yr**2 x**2 - y**2 >>> (xr**2 - yr**2) // (xr - yr) x + y The object ``K`` here represents the ring and is an instance of :py:class:`~.PolyRing` but is not a **polys domain** (it is not an instance of a subclass of :py:class:`~.Domain` so it can not be used with :py:class:`~.Poly`). In this way the implementation of polynomial rings that is used in the domain system can be used independently of the domain system. The purpose of the domain system is to provide a unified interface for working with and converting between different representations of expressions. To make the :py:class:`~.PolyRing` implementation usable in that context the :py:class:`~.PolynomialRing` class is a wrapper around the :py:class:`~.PolyRing` class that provides the interface expected in the domain system. That makes this implementation of polynomial rings usable as part of the broader codebase that is designed to work with expressions from different domains. The domain for polynomial rings is a distinct object from the ring returned by :py:func:`~.ring` although both have the same elements:: >>> K, xr, yr = ring([x, y], ZZ) >>> K Polynomial ring in x, y over ZZ with lex order >>> K2 = ZZ[x,y] >>> K2 ZZ[x,y] >>> K2.ring Polynomial ring in x, y over ZZ with lex order >>> K2.ring == K True >>> K(x+y) x + y >>> K2(x+y) x + y >>> type(K(x+y)) >>> type(K2(x+y)) >>> K(x+y) == K2(x+y) True Rational function fields ======================== Some domains are classified as fields and others are not. The principal difference between a field and a non-field domain is that in a field it is always possible to divide any element by any nonzero element. It is usually possible to convert any domain to a field that contains that domain with the :py:meth:`~.Domain.get_field` method:: >>> from sympy import ZZ, QQ, symbols >>> x, y = symbols('x, y') >>> ZZ.is_Field False >>> QQ.is_Field True >>> QQ[x] QQ[x] >>> QQ[x].is_Field False >>> QQ[x].get_field() QQ(x) >>> QQ[x].get_field().is_Field True >>> QQ.frac_field(x) QQ(x) This introduces a new kind of domain :ref:`K(x)` representing a rational function field in the generator ``x`` over another domain ``K``. It is not possible to construct the domain ``QQ(x)`` with the ``()`` syntax so the easiest ways to create it are using the domain methods :py:meth:`~.Domain.frac_field` (``QQ.frac_field(x)``) or :py:meth:`~.Domain.get_field` (``QQ[x].get_field()``). The :py:meth:`~.Domain.frac_field` method is the more direct approach. The rational function field :ref:`K(x)` is an instance of :py:class:`~.RationalField`. This domain represents functions of the form `p(x) / q(x)` for polynomials `p` and `q`. The domain elements are represented as a pair of polynomials in :ref:`K[x]`:: >>> K = QQ.frac_field(x) >>> xk = K(x) >>> f = xk / (K.one + xk**2) >>> f x/(x**2 + 1) >>> f.numer x >>> f.denom x**2 + 1 >>> QQ[x].of_type(f.numer) True >>> QQ[x].of_type(f.denom) True Cancellation between the numerator and denominator is automatic in this field:: >>> p1 = xk**2 - 1 >>> p2 = xk - 1 >>> p1 x**2 - 1 >>> p2 x - 1 >>> p1 / p2 x + 1 Computing this cancellation can be slow which makes rational function fields potentially slower than polynomial rings or algebraic fields. Just like in the case of polynomial rings there is both a new (sparse) and old (dense) version of fraction fields:: >>> K1 = QQ.frac_field(x) >>> K2 = QQ.old_frac_field(x) >>> K1 QQ(x) >>> K2 QQ(x) >>> type(K1) >>> type(K2) Also just like in the case of polynomials rings the implementation of rational function fields can be used independently of the domain system:: >>> from sympy import field >>> K, xf, yf = field([x, y], ZZ) >>> xf / (1 - yf) -x/(y - 1) Here ``K`` is an instance of :py:class:`~.FracField` rather than :py:class:`~.RationalField` as it would be for the domain ``ZZ(x,y)``. Expression domain ================= The final domain to consider is the "expression domain" which is known as :ref:`EX`. Expressions that can not be represented using the other domains can be always represented using the expression domain. An element of :ref:`EX` is actually just a wrapper around a :py:class:`~.Expr` instance:: >>> from sympy import EX >>> p = EX.from_sympy(1 + x) >>> p EX(x + 1) >>> type(p) >>> p.ex x + 1 >>> type(p.ex) For other domains the domain representation of expressions is usually more efficient than the tree representation used by :py:class:`~.Expr`. In :ref:`EX` the internal representation is :py:class:`~.Expr` so it is clearly not more efficient. The purpose of the :ref:`EX` domain is to be able to wrap up arbitrary expressions in an interface that is consistent with the other domains. The :ref:`EX` domain is used as a fallback when an appropriate domain can not be found. Although this does not offer any particular efficiency it does allow the algorithms that are implemented to work over arbitrary domains to be usable when working with expressions that do not have an appropriate domain representation. Choosing a domain ================= In the workflow described above the idea is to start with some sympy expressions, choose a domain and convert all the expressions into that domain in order to perform some calculation. The obvious question that arises is how to choose an appropriate domain to represent some sympy expressions. For this there is a function :py:func:`~.construct_domain` which takes a list of expressions and will choose a domain and convert all of the expressions to that domain:: >>> from sympy import construct_domain, Integer >>> elements_sympy = [Integer(3), Integer(2)] # elements as Expr instances >>> elements_sympy [3, 2] >>> K, elements_K = construct_domain(elements_sympy) >>> K ZZ >>> elements_K [3, 2] >>> type(elements_sympy[0]) >>> type(elements_K[0]) # doctest: +SKIP In this example we see that the two integers ``3`` and ``2`` can be represented in the domain :ref:`ZZ`. The expressions have been converted to elements of that domain which in this case means the ``int`` type rather than instances of :py:class:`~.Expr`. It is not necessary to explicitly create :py:class:`~.Expr` instances when the inputs can be sympified so e.g. ``construct_domain([3, 2])`` would give the same output as above. Given more complicated inputs :py:func:`~.construct_domain` will choose more complicated domains:: >>> from sympy import Rational, symbols >>> x, y = symbols('x, y') >>> construct_domain([Rational(1, 2), Integer(3)])[0] QQ >>> construct_domain([2*x, 3])[0] ZZ[x] >>> construct_domain([x/2, 3])[0] QQ[x] >>> construct_domain([2/x, 3])[0] ZZ(x) >>> construct_domain([x, y])[0] ZZ[x,y] If any noninteger rational numbers are found in the inputs then the ground domain will be :ref:`QQ` rather than :ref:`ZZ`. If any symbol is found in the inputs then a :py:class:`~.PolynomialRing` will be created. A multivariate polynomial ring such as ``QQ[x,y]`` can also be created if there are multiple symbols in the inputs. If any symbols appear in the denominators then a :py:class:`~.RationalField` like ``QQ(x)`` will be created instead. Some of the domains above are fields and others are (non-field) rings. In some contexts it is necessary to have a field domain so that division is possible and for this :py:func:`~.construct_domain` has an option ``field=True`` which will force the construction of a field domain even if the expressions can all be represented in a non-field ring:: >>> construct_domain([1, 2], field=True)[0] QQ >>> construct_domain([2*x, 3], field=True)[0] ZZ(x) >>> construct_domain([x/2, 3], field=True)[0] ZZ(x) >>> construct_domain([2/x, 3], field=True)[0] ZZ(x) >>> construct_domain([x, y], field=True)[0] ZZ(x,y) By default :py:func:`~.construct_domain` will not construct an algebraic extension field and will instead use the :ref:`EX` domain (:py:class:`~.ExpressionDomain`). The keyword argument ``extension=True`` can be used to construct an :py:class:`~.AlgebraicField` if the inputs are irrational but algebraic:: >>> from sympy import sqrt >>> construct_domain([sqrt(2)])[0] EX >>> construct_domain([sqrt(2)], extension=True)[0] QQ >>> construct_domain([sqrt(2), sqrt(3)], extension=True)[0] QQ When there are algebraically independent transcendentals in the inputs a :py:class:`~.PolynomialRing` or :py:class:`~.RationalField` will be constructed treating those transcendentals as generators:: >>> from sympy import sin, cos >>> construct_domain([sin(x), y])[0] ZZ[y,sin(x)] However if there is a possibility that the inputs are not algebraically independent then the domain will be :ref:`EX`:: >>> construct_domain([sin(x), cos(x)])[0] EX Here ``sin(x)`` and ``cos(x)`` are not algebraically independent since ``sin(x)**2 + cos(x)**2 = 1``. Converting elements between different domains ============================================= It is often useful to combine calculations performed over different domains. However just as it is important to avoid mixing domain elements with normal sympy expressions and other Python types it is also important to avoid mixing elements from different domains. The :py:meth:`~.Domain.convert_from` method is used to convert elements from one domain into elements of another domain:: >>> num_zz = ZZ(3) >>> ZZ.of_type(num_zz) True >>> num_qq = QQ.convert_from(num_zz, ZZ) >>> ZZ.of_type(num_qq) False >>> QQ.of_type(num_qq) True The :py:meth:`~.Domain.convert` method can be called without specifying the source domain as the second argument e.g.:: >>> QQ.convert(ZZ(2)) 2 This works because :py:meth:`~.Domain.convert` can check the type of ``ZZ(2)`` and can try to work out what domain (:ref:`ZZ`) it is an element of. Certain domains like :ref:`ZZ` and :ref:`QQ` are treated as special cases to make this work. Elements of more complicated domains are instances of subclasses of :py:class:`~.DomainElement` which has a :py:meth:`~.DomainElement.parent` method that can identify the domain that the element belongs to. For example in the polynomial ring ``ZZ[x]`` we have:: >>> from sympy import ZZ, Symbol >>> x = Symbol('x') >>> K = ZZ[x] >>> K ZZ[x] >>> p = K(x) + K.one >>> p x + 1 >>> type(p) >>> p.parent() ZZ[x] >>> p.parent() == K True It is more efficient though to call :py:meth:`~.Domain.convert_from` with the source domain specified as the second argument:: >>> QQ.convert_from(ZZ(2), ZZ) 2 Unifying domains ================ When we want to combine elements from two different domains and perform mixed calculations with them we need to #. Choose a new domain that can represent all elements of both. #. Convert all elements to the new domain. #. Perform the calculation in the new domain. The key question arising from point 1. is how to choose a domain that can represent the elements of both domains. For this there is the :py:meth:`~.Domain.unify` method:: >>> x1, K1 = ZZ(2), ZZ >>> y2, K2 = QQ(3, 2), QQ >>> K1 ZZ >>> K2 QQ >>> K3 = K1.unify(K2) >>> K3 QQ >>> x3 = K3.convert_from(x1, K1) >>> y3 = K3.convert_from(y2, K2) >>> x3 + y3 7/2 The :py:meth:`~.Domain.unify` method will find a domain that encompasses both domains so in this example ``ZZ.unify(QQ)`` gives :ref:`QQ` because every element of :ref:`ZZ` can be represented as an element of :ref:`QQ`. This means that all inputs (``x1`` and ``y2``) can be converted to the elements of the common domain ``K3`` (as ``x3`` and ``y3``). Once in the common domain we can safely use arithmetic operations like ``+``. In this example one domain is a superset of the other and we see that ``K1.unify(K2) == K2`` so it is not actually necessary to convert ``y2``. In general though ``K1.unify(K2)`` can give a new domain that is not equal to either ``K1`` or ``K2``. The :py:meth:`~.Domain.unify` method understands how to combine different polynomial ring domains and how to unify the base domain:: >>> ZZ[x].unify(ZZ[y]) ZZ[x,y] >>> ZZ[x,y].unify(ZZ[y]) ZZ[x,y] >>> ZZ[x].unify(QQ) QQ[x] It is also possible to unify algebraic fields and rational function fields as well:: >>> K1 = QQ.algebraic_field(sqrt(2))[x] >>> K2 = QQ.algebraic_field(sqrt(3))[y] >>> K1 QQ[x] >>> K2 QQ[y] >>> K1.unify(K2) QQ[x,y] >>> QQ.frac_field(x).unify(ZZ[y]) ZZ(x,y) Internals of a Poly =================== We are now in a position to understand how the :py:class:`~.Poly` class works internally. This is the public interface of :py:class:`~.Poly`:: >>> from sympy import Poly, symbols, ZZ >>> x, y, z, t = symbols('x, y, z, t') >>> p = Poly(x**2 + 1, x, domain=ZZ) >>> p Poly(x**2 + 1, x, domain='ZZ') >>> p.gens (x,) >>> p.domain ZZ >>> p.all_coeffs() [1, 0, 1] >>> p.as_expr() x**2 + 1 This is the internal implementation of :py:class:`~.Poly`:: >>> d = p.rep # internal representation of Poly >>> d DMP([1, 0, 1], ZZ, None) >>> d.rep # internal representation of DMP [1, 0, 1] >>> type(d.rep) >>> type(d.rep[0]) # doctest: +SKIP >>> d.dom ZZ The internal representation of a :py:class:`~.Poly` instance is an instance of :py:class:`~.DMP` which is the class used for domain elements in the old polynomial ring domain :py:meth:`~.Domain.old_poly_ring`. This represents the polynomial as a list of coefficients which are themselves elements of a domain and keeps a reference to their domain (:ref:`ZZ` in this example). Choosing a domain for a Poly ============================ If the domain is not specified for the :py:class:`~.Poly` constructor then it is inferred using :py:func:`~.construct_domain`. Arguments like ``field=True`` are passed along to :py:func:`~.construct_domain`:: >>> from sympy import sqrt >>> Poly(x**2 + 1, x) Poly(x**2 + 1, x, domain='ZZ') >>> Poly(x**2 + 1, x, field=True) Poly(x**2 + 1, x, domain='QQ') >>> Poly(x**2/2 + 1, x) Poly(1/2*x**2 + 1, x, domain='QQ') >>> Poly(x**2 + sqrt(2), x) Poly(x**2 + sqrt(2), x, domain='EX') >>> Poly(x**2 + sqrt(2), x, extension=True) Poly(x**2 + sqrt(2), x, domain='QQ') It is also possible to use the extension argument to specify generators of an extension even if no extension is required to represent the coefficients although this does not work when using :py:func:`~.construct_domain` directly. A list of extension elements will be passed to :py:func:`~.primitive_element` to create an appropriate :py:class:`~.AlgebraicField` domain:: >>> from sympy import construct_domain >>> Poly(x**2 + 1, x) Poly(x**2 + 1, x, domain='ZZ') >>> Poly(x**2 + 1, x, extension=sqrt(2)) Poly(x**2 + 1, x, domain='QQ') >>> Poly(x**2 + 1, x, extension=[sqrt(2), sqrt(3)]) Poly(x**2 + 1, x, domain='QQ') >>> construct_domain([1, 0, 1], extension=sqrt(2))[0] ZZ (Perhaps :py:func:`~.construct_domain` should do the same as :py:class:`~.Poly` here...) Choosing generators =================== If there are symbols other than the generators then a polynomial ring or rational function field domain will be created. The domain used for the coefficients in this case is the sparse ("new") polynomial ring:: >>> p = Poly(x**2*y + z, x) >>> p Poly(y*x**2 + z, x, domain='ZZ[y,z]') >>> p.gens (x,) >>> p.domain ZZ[y,z] >>> p.domain == ZZ[y,z] True >>> p.domain == ZZ.poly_ring(y, z) True >>> p.domain == ZZ.old_poly_ring(y, z) False >>> p.rep.rep [y, 0, z] >>> p.rep.rep[0] y >>> type(p.rep.rep[0]) >>> dict(p.rep.rep[0]) {(1, 0): 1} What we have here is a strange hybrid of dense and sparse implementations. The :py:class:`~.Poly` instance considers itself to be an univariate polynomial in the generator ``x`` but with coefficients from the domain ``ZZ[y,z]``. The internal representation of the :py:class:`~.Poly` is a list of coefficients in the "dense univariate polynomial" (DUP) format. However each coefficient is implemented as a sparse polynomial in ``y`` and ``z``. If we make ``x``, ``y`` and ``z`` all be generators for the :py:class:`~.Poly` then we get a fully dense DMP list of lists of lists representation:: >>> p = Poly(x**2*y + z, x, y, z) >>> p Poly(x**2*y + z, x, y, z, domain='ZZ') >>> p.rep DMP([[[1], []], [[]], [[1, 0]]], ZZ, None) >>> p.rep.rep [[[1], []], [[]], [[1, 0]]] >>> p.rep.rep[0][0][0] 1 >>> type(p.rep.rep[0][0][0]) # doctest: +SKIP On the other hand we can make a :py:class:`~.Poly` with a fully sparse representation by choosing a generator that is not in the expression at all:: >>> p = Poly(x**2*y + z, t) >>> p Poly(x**2*y + z, t, domain='ZZ[x,y,z]') >>> p.rep DMP([x**2*y + z], ZZ[x,y,z], None) >>> p.rep.rep[0] x**2*y + z >>> type(p.rep.rep[0]) >>> dict(p.rep.rep[0]) {(0, 0, 1): 1, (2, 1, 0): 1} If no generators are provided to the :py:class:`~.Poly` constructor then it will attempt to choose generators so that the expression is polynomial in those. In the common case that the expression is a polynomial expression in some symbols then those symbols will be taken as generators. However other non-symbol expressions can also be taken as generators:: >>> Poly(x**2*y + z) Poly(x**2*y + z, x, y, z, domain='ZZ') >>> from sympy import pi, exp >>> Poly(exp(x) + exp(2*x) + 1) Poly((exp(x))**2 + (exp(x)) + 1, exp(x), domain='ZZ') >>> Poly(pi*x) Poly(x*pi, x, pi, domain='ZZ') >>> Poly(pi*x, x) Poly(pi*x, x, domain='ZZ[pi]') Algebraically dependent generators ================================== Taking ``exp(x)`` or ``pi`` as generators for a :py:class:`~.Poly` or for its polynomial ring domain is mathematically valid because these objects are transcendental and so the ring extension containing them is isomorphic to a polynomial ring. Since ``x`` and ``exp(x)`` are algebraically independent it is also valid to use both as generators for the same :py:class:`~.Poly`. However some other combinations of generators are invalid such as ``x`` and ``sqrt(x)`` or ``sin(x)`` and ``cos(x)``. These examples are invalid because the generators are not algebraically independent (e.g. ``sqrt(x)**2 = x`` and ``sin(x)**2 + cos(x)**2 = 1``). The implementation is not able to detect these algebraic relationships though:: >>> from sympy import sin, cos, sqrt >>> Poly(x*exp(x)) # fine Poly(x*(exp(x)), x, exp(x), domain='ZZ') >>> Poly(sin(x)+cos(x)) # not fine Poly((cos(x)) + (sin(x)), cos(x), sin(x), domain='ZZ') >>> Poly(x + sqrt(x)) # not fine Poly(x + (sqrt(x)), x, sqrt(x), domain='ZZ') Calculations with a :py:class:`~.Poly` such as this are unreliable because zero-testing will not work properly in this implementation:: >>> p1 = Poly(x, x, sqrt(x)) >>> p2 = Poly(sqrt(x), x, sqrt(x)) >>> p1 Poly(x, x, sqrt(x), domain='ZZ') >>> p2 Poly((sqrt(x)), x, sqrt(x), domain='ZZ') >>> p3 = p1 - p2**2 >>> p3 # should be zero... Poly(x - (sqrt(x))**2, x, sqrt(x), domain='ZZ') >>> p3.as_expr() 0 This aspect of :py:class:`~.Poly` could be improved by: #. Expanding the domain system with new domains that can represent more classes of algebraic extension. #. Improving the detection of algebraic dependencies in :py:func:`~.construct_domain`. #. Improving the automatic selection of generators. Examples of the above are that it would be useful to have a domain that can represent more general algebraic extensions (:py:class:`~.AlgebraicField` is only for extensions of :ref:`QQ`). Improving the detection of algebraic dependencies is harder but at least common cases like ``sin(x)`` and ``cos(x)`` could be handled. When choosing generators it should be possible to recognise that ``sqrt(x)`` can be the only generator for ``x + sqrt(x)``:: >>> Poly(x + sqrt(x)) # this could be improved! Poly(x + (sqrt(x)), x, sqrt(x), domain='ZZ') >>> Poly(x + sqrt(x), sqrt(x)) # this could be improved! Poly((sqrt(x)) + x, sqrt(x), domain='ZZ[x]') sympy-sympy-1.9/doc/src/modules/polys/domainsref.rst000066400000000000000000000203541412543434000227620ustar00rootroot00000000000000.. _polys-domainsref: =================================== Reference docs for the Poly Domains =================================== This page lists the reference documentation for the domains in the polys module. For a general introduction to the polys module it is recommended to read :ref:`polys-basics` instead. For an introductory explanation of the what the domain system is and how it is used it is recommended to read :ref:`polys-domainsintro`. This page lists the reference docs for the :py:class:`~.Domain` class and its subclasses (the specific domains such as ``ZZ``) as well as the classes that represent the domain elements. Domains ======= .. currentmodule:: sympy.polys.domains Here we document the various implemented ground domains (see :ref:`polys-domainsintro` for more of an explanation). There are three types of :py:class:`~.Domain` subclass: abstract domains, concrete domains, and "implementation domains". Abstract domains cannot be (usefully) instantiated at all, and just collect together functionality shared by many other domains. Concrete domains are those meant to be instantiated and used in the polynomial manipulation algorithms. In some cases, there are various possible ways to implement the data type the domain provides. For example, depending on what libraries are available on the system, the integers are implemented either using the python built-in integers, or using gmpy. Note that various aliases are created automatically depending on the libraries available. As such e.g. ``ZZ`` always refers to the most efficient implementation of the integer ring available. Abstract Domains ================ .. autoclass:: sympy.polys.domains.domain.Domain :members: .. autoclass:: sympy.polys.domains.domainelement.DomainElement :members: .. autoclass:: sympy.polys.domains.field.Field :members: .. autoclass:: sympy.polys.domains.ring.Ring :members: .. autoclass:: sympy.polys.domains.simpledomain.SimpleDomain :members: .. autoclass:: sympy.polys.domains.compositedomain.CompositeDomain :members: .. _GF(p): GF(p) ===== .. autoclass:: FiniteField :members: .. autoclass:: PythonFiniteField :members: .. autoclass:: GMPYFiniteField :members: .. _ZZ: ZZ == The :ref:`ZZ` domain represents the `integers`_ `\mathbb{Z}` as a :py:class:`~.Domain` in the domain system (see :ref:`polys-domainsintro`). By default a :py:class:`~.Poly` created from an expression with integer coefficients will have the domain :ref:`ZZ`:: >>> from sympy import Poly, Symbol >>> x = Symbol('x') >>> p = Poly(x**2 + 1) >>> p Poly(x**2 + 1, x, domain='ZZ') >>> p.domain ZZ The corresponding `field of fractions`_ is the domain of the rationals :ref:`QQ`. Conversely :ref:`ZZ` is the `ring of integers`_ of :ref:`QQ`:: >>> from sympy import ZZ, QQ >>> ZZ.get_field() QQ >>> QQ.get_ring() ZZ When using the domain directly :ref:`ZZ` can be used as a constructor to create instances which then support the operations ``+,-,*,**,//,%`` (true division ``/`` should not be used with :ref:`ZZ` - see the :py:meth:`~.Domain.exquo` domain method):: >>> x = ZZ(5) >>> y = ZZ(2) >>> x // y # floor division 2 >>> x % y # modulo division (remainder) 1 The :py:meth:`~.Domain.gcd` method can be used to compute the `gcd`_ of any two elements:: >>> ZZ.gcd(ZZ(10), ZZ(2)) 2 There are two implementations of :ref:`ZZ` in SymPy. If ``gmpy`` or ``gmpy2`` is installed then :ref:`ZZ` will be implemented by :py:class:`GMPYIntegerRing` and the elements will be instances of the ``gmpy.mpz`` type. Otherwise if ``gmpy`` and ``gmpy2`` are not installed then :ref:`ZZ` will be implemented by :py:class:`PythonIntegerRing` which uses Python's standard builtin ``int`` type. With larger integers ``gmpy`` can be more efficient so it is preferred when available. .. autoclass:: IntegerRing :members: :exclude-members: dtype, tp .. autoclass:: PythonIntegerRing .. autoclass:: GMPYIntegerRing :members: :exclude-members: dtype, tp .. _QQ: QQ == The :ref:`QQ` domain represents the `rationals`_ `\mathbb{Q}` as a :py:class:`~.Domain` in the domain system (see :ref:`polys-domainsintro`). By default a :py:class:`~.Poly` created from an expression with rational coefficients will have the domain :ref:`QQ`:: >>> from sympy import Poly, Symbol >>> x = Symbol('x') >>> p = Poly(x**2 + x/2) >>> p Poly(x**2 + 1/2*x, x, domain='QQ') >>> p.domain QQ The corresponding `ring of integers`_ is the :py:class:`~.Domain` of the integers :ref:`ZZ`. Conversely :ref:`QQ` is the `field of fractions`_ of :ref:`ZZ`:: >>> from sympy import ZZ, QQ >>> QQ.get_ring() ZZ >>> ZZ.get_field() QQ When using the domain directly :ref:`QQ` can be used as a constructor to create instances which then support the operations ``+,-,*,**,/`` (true division ``/`` is always possible for nonzero divisors in :ref:`QQ`):: >>> x = QQ(5) >>> y = QQ(2) >>> x / y # true division 5/2 There are two implementations of :ref:`QQ` in SymPy. If ``gmpy`` or ``gmpy2`` is installed then :ref:`QQ` will be implemented by :py:class:`GMPYRationalField` and the elements will be instances of the ``gmpy.mpq`` type. Otherwise if ``gmpy`` and ``gmpy2`` are not installed then :ref:`QQ` will be implemented by :py:class:`PythonRationalField` which is a pure Python class as part of sympy. The ``gmpy`` implementation is preferred because it is significantly faster. .. autoclass:: RationalField :members: :exclude-members: dtype, tp .. autoclass:: PythonRationalField .. autoclass:: GMPYRationalField :members: :exclude-members: dtype, tp .. autoclass:: sympy.external.pythonmpq.PythonMPQ .. _MPQ: MPQ === The ``MPQ`` type is either :py:class:`~.PythonMPQ` or otherwise the ``mpq`` type from ``gmpy2``. Gaussian domains ================ The Gaussian domains :ref:`ZZ_I` and :ref:`QQ_I` share common superclasses :py:class:`~.GaussianElement` for the domain elements and :py:class:`~.GaussianDomain` for the domains themselves. .. autoclass:: sympy.polys.domains.gaussiandomains.GaussianDomain :members: .. autoclass:: sympy.polys.domains.gaussiandomains.GaussianElement :members: .. _ZZ_I: ZZ_I ==== .. autoclass:: sympy.polys.domains.gaussiandomains.GaussianIntegerRing :members: .. autoclass:: sympy.polys.domains.gaussiandomains.GaussianInteger :members: .. _QQ_I: QQ_I ==== .. autoclass:: sympy.polys.domains.gaussiandomains.GaussianRationalField :members: .. autoclass:: sympy.polys.domains.gaussiandomains.GaussianRational :members: .. _QQ(a): QQ ===== .. autoclass:: AlgebraicField :members: .. _RR: RR == .. autoclass:: RealField :members: .. autoclass:: sympy.polys.domains.mpelements.RealElement :members: .. _CC: CC == .. autoclass:: ComplexField :members: .. autoclass:: sympy.polys.domains.mpelements.ComplexElement :members: .. _K[x]: K[x] ==== .. autoclass:: PolynomialRing :members: .. _K(x): K(x) ==== .. autoclass:: FractionField :members: .. _EX: EX == .. autoclass:: ExpressionDomain :members: .. autoclass:: sympy.polys.domains.expressiondomain::ExpressionDomain.Expression :members: Quotient ring ============= .. autoclass:: sympy.polys.domains.quotientring.QuotientRing Sparse polynomials ================== .. currentmodule:: sympy.polys.rings Sparse polynomials are represented as dictionaries. .. autofunction:: ring .. autofunction:: xring .. autofunction:: vring .. autofunction:: sring .. autoclass:: PolyRing :members: .. autoclass:: PolyElement :members: Sparse rational functions ========================= .. currentmodule:: sympy.polys.fields Sparse polynomials are represented as dictionaries. .. autofunction:: field .. autofunction:: xfield .. autofunction:: vfield .. autofunction:: sfield .. autoclass:: FracField :members: .. autoclass:: FracElement :members: Dense polynomials ================= .. currentmodule:: sympy.polys.polyclasses .. autoclass:: DMP :members: .. autoclass:: DMF :members: .. autoclass:: ANP :members: .. _integers: https://en.wikipedia.org/wiki/Integer .. _rationals: https://en.wikipedia.org/wiki/Rational_number .. _gcd: https://en.wikipedia.org/wiki/Greatest_common_divisor .. _field of fractions: https://en.wikipedia.org/wiki/Field_of_fractions .. _ring of integers: https://en.wikipedia.org/wiki/Ring_of_integers sympy-sympy-1.9/doc/src/modules/polys/index.rst000066400000000000000000000015241412543434000217400ustar00rootroot00000000000000.. _polys-docs: ======================= Polynomial Manipulation ======================= Computations with polynomials are at the core of computer algebra and having a fast and robust polynomials manipulation module is a key for building a powerful symbolic manipulation system. SymPy has a dedicated module :mod:`sympy.polys` for computing in polynomial algebras over various coefficient domains. There is a vast number of methods implemented, ranging from simple tools like polynomial division, to advanced concepts including Gröbner bases and multivariate factorization over algebraic number domains. Contents ======== .. toctree:: :maxdepth: 3 basics.rst wester.rst reference.rst agca.rst domainsintro.rst domainsref.rst internals.rst ringseries.rst literature.rst solvers.rst domainmatrix.rst sympy-sympy-1.9/doc/src/modules/polys/internals.rst000066400000000000000000000605421412543434000226350ustar00rootroot00000000000000.. _polys-internals: =============================================== Internals of the Polynomial Manipulation Module =============================================== The implementation of the polynomials module is structured internally in "levels". There are four levels, called L0, L1, L2 and L3. The levels three and four contain the user-facing functionality and were described in the previous section. This section focuses on levels zero and one. Level zero provides core polynomial manipulation functionality with C-like, low-level interfaces. Level one wraps this low-level functionality into object oriented structures. These are *not* the classes seen by the user, but rather classes used internally throughout the polys module. There is one additional complication in the implementation. This comes from the fact that all polynomial manipulations are relative to a *ground domain*. For example, when factoring a polynomial like `x^{10} - 1`, one has to decide what ring the coefficients are supposed to belong to, or less trivially, what coefficients are allowed to appear in the factorization. This choice of coefficients is called a ground domain. Typical choices include the integers `\mathbb{Z}`, the rational numbers `\mathbb{Q}` or various related rings and fields. But it is perfectly legitimate (although in this case uninteresting) to factorize over polynomial rings such as `k[Y]`, where `k` is some fixed field. Thus the polynomial manipulation algorithms (both complicated ones like factoring, and simpler ones like addition or multiplication) have to rely on other code to manipulate the coefficients. In the polynomial manipulation module, such code is encapsulated in so-called "domains". A domain is basically a factory object: it takes various representations of data, and converts them into objects with unified interface. Every object created by a domain has to implement the arithmetic operations `+`, `-` and `\times`. Other operations are accessed through the domain, e.g. as in ``ZZ.quo(ZZ(4), ZZ(2))``. Note that there is some amount of *circularity*: the polynomial ring domains use the level one classes, the level one classes use the level zero functions, and level zero functions use domains. It is possible, in principle, but not in the current implementation, to work in rings like `k[X][Y]`. This would create even more layers. For this reason, working in the isomorphic ring `k[X, Y]` is preferred. Level Zero ========== Level zero contains the bulk code of the polynomial manipulation module. Manipulation of dense, multivariate polynomials *********************************************** These functions can be used to manipulate polynomials in `K[X_0, \ldots, X_u]`. Functions for manipulating multivariate polynomials in the dense representation have the prefix ``dmp_``. Functions which only apply to univariate polynomials (i.e. `u = 0`) have the prefix ``dup__``. The ground domain `K` has to be passed explicitly. For many multivariate polynomial manipulation functions also the level `u`, i.e. the number of generators minus one, has to be passed. (Note that, in many cases, ``dup_`` versions of functions are available, which may be slightly more efficient.) **Basic manipulation:** .. currentmodule:: sympy.polys.densebasic .. autofunction:: dmp_LC .. autofunction:: dmp_TC .. autofunction:: dmp_ground_LC .. autofunction:: dmp_ground_TC .. autofunction:: dmp_true_LT .. autofunction:: dmp_degree .. autofunction:: dmp_degree_in .. autofunction:: dmp_degree_list .. autofunction:: dmp_strip .. autofunction:: dmp_validate .. autofunction:: dup_reverse .. autofunction:: dmp_copy .. autofunction:: dmp_to_tuple .. autofunction:: dmp_normal .. autofunction:: dmp_convert .. autofunction:: dmp_from_sympy .. autofunction:: dmp_nth .. autofunction:: dmp_ground_nth .. autofunction:: dmp_zero_p .. autofunction:: dmp_zero .. autofunction:: dmp_one_p .. autofunction:: dmp_one .. autofunction:: dmp_ground_p .. autofunction:: dmp_ground .. autofunction:: dmp_zeros .. autofunction:: dmp_grounds .. autofunction:: dmp_negative_p .. autofunction:: dmp_positive_p .. autofunction:: dmp_from_dict .. autofunction:: dmp_to_dict .. autofunction:: dmp_swap .. autofunction:: dmp_permute .. autofunction:: dmp_nest .. autofunction:: dmp_raise .. autofunction:: dmp_deflate .. autofunction:: dmp_multi_deflate .. autofunction:: dmp_inflate .. autofunction:: dmp_exclude .. autofunction:: dmp_include .. autofunction:: dmp_inject .. autofunction:: dmp_eject .. autofunction:: dmp_terms_gcd .. autofunction:: dmp_list_terms .. autofunction:: dmp_apply_pairs .. autofunction:: dmp_slice .. autofunction:: dup_random **Arithmetic operations:** .. currentmodule:: sympy.polys.densearith .. autofunction:: dmp_add_term .. autofunction:: dmp_sub_term .. autofunction:: dmp_mul_term .. autofunction:: dmp_add_ground .. autofunction:: dmp_sub_ground .. autofunction:: dmp_mul_ground .. autofunction:: dmp_quo_ground .. autofunction:: dmp_exquo_ground .. autofunction:: dup_lshift .. autofunction:: dup_rshift .. autofunction:: dmp_abs .. autofunction:: dmp_neg .. autofunction:: dmp_add .. autofunction:: dmp_sub .. autofunction:: dmp_add_mul .. autofunction:: dmp_sub_mul .. autofunction:: dmp_mul .. autofunction:: dmp_sqr .. autofunction:: dmp_pow .. autofunction:: dmp_pdiv .. autofunction:: dmp_prem .. autofunction:: dmp_pquo .. autofunction:: dmp_pexquo .. autofunction:: dmp_rr_div .. autofunction:: dmp_ff_div .. autofunction:: dmp_div .. autofunction:: dmp_rem .. autofunction:: dmp_quo .. autofunction:: dmp_exquo .. autofunction:: dmp_max_norm .. autofunction:: dmp_l1_norm .. autofunction:: dmp_expand **Further tools:** .. currentmodule:: sympy.polys.densetools .. autofunction:: dmp_integrate .. autofunction:: dmp_integrate_in .. autofunction:: dmp_diff .. autofunction:: dmp_diff_in .. autofunction:: dmp_eval .. autofunction:: dmp_eval_in .. autofunction:: dmp_eval_tail .. autofunction:: dmp_diff_eval_in .. autofunction:: dmp_trunc .. autofunction:: dmp_ground_trunc .. autofunction:: dup_monic .. autofunction:: dmp_ground_monic .. autofunction:: dup_content .. autofunction:: dmp_ground_content .. autofunction:: dup_primitive .. autofunction:: dmp_ground_primitive .. autofunction:: dup_extract .. autofunction:: dmp_ground_extract .. autofunction:: dup_real_imag .. autofunction:: dup_mirror .. autofunction:: dup_scale .. autofunction:: dup_shift .. autofunction:: dup_transform .. autofunction:: dmp_compose .. autofunction:: dup_decompose .. autofunction:: dmp_lift .. autofunction:: dup_sign_variations .. autofunction:: dmp_clear_denoms .. autofunction:: dmp_revert Manipulation of dense, univariate polynomials with finite field coefficients **************************************************************************** .. currentmodule:: sympy.polys.galoistools Functions in this module carry the prefix ``gf_``, referring to the classical name "Galois Fields" for finite fields. Note that many polynomial factorization algorithms work by reduction to the finite field case, so having special implementations for this case is justified both by performance, and by the necessity of certain methods which do not even make sense over general fields. .. autofunction:: gf_crt .. autofunction:: gf_crt1 .. autofunction:: gf_crt2 .. autofunction:: gf_int .. autofunction:: gf_degree .. autofunction:: gf_LC .. autofunction:: gf_TC .. autofunction:: gf_strip .. autofunction:: gf_trunc .. autofunction:: gf_normal .. autofunction:: gf_from_dict .. autofunction:: gf_to_dict .. autofunction:: gf_from_int_poly .. autofunction:: gf_to_int_poly .. autofunction:: gf_neg .. autofunction:: gf_add_ground .. autofunction:: gf_sub_ground .. autofunction:: gf_mul_ground .. autofunction:: gf_quo_ground .. autofunction:: gf_add .. autofunction:: gf_sub .. autofunction:: gf_mul .. autofunction:: gf_sqr .. autofunction:: gf_add_mul .. autofunction:: gf_sub_mul .. autofunction:: gf_expand .. autofunction:: gf_div .. autofunction:: gf_rem .. autofunction:: gf_quo .. autofunction:: gf_exquo .. autofunction:: gf_lshift .. autofunction:: gf_rshift .. autofunction:: gf_pow .. autofunction:: gf_pow_mod .. autofunction:: gf_gcd .. autofunction:: gf_lcm .. autofunction:: gf_cofactors .. autofunction:: gf_gcdex .. autofunction:: gf_monic .. autofunction:: gf_diff .. autofunction:: gf_eval .. autofunction:: gf_multi_eval .. autofunction:: gf_compose .. autofunction:: gf_compose_mod .. autofunction:: gf_trace_map .. autofunction:: gf_random .. autofunction:: gf_irreducible .. autofunction:: gf_irreducible_p .. autofunction:: gf_sqf_p .. autofunction:: gf_sqf_part .. autofunction:: gf_sqf_list .. autofunction:: gf_Qmatrix .. autofunction:: gf_Qbasis .. autofunction:: gf_berlekamp .. autofunction:: gf_zassenhaus .. autofunction:: gf_shoup .. autofunction:: gf_factor_sqf .. autofunction:: gf_factor .. autofunction:: gf_value .. autofunction:: gf_csolve Manipulation of sparse, distributed polynomials and vectors *********************************************************** Dense representations quickly require infeasible amounts of storage and computation time if the number of variables increases. For this reason, there is code to manipulate polynomials in a *sparse* representation. The Ring object and elements are implemented by the classes :py:class:`~.PolyRing` and :py:class:`~.PolyElement`. In commutative algebra, one often studies not only polynomials, but also *modules* over polynomial rings. The polynomial manipulation module provides rudimentary low-level support for finitely generated free modules. This is mainly used for Groebner basis computations (see there), so manipulation functions are only provided to the extend needed. They carry the prefix ``sdm_``. Note that in examples, the generators of the free module are called `f_1, f_2, \ldots`. .. currentmodule:: sympy.polys.distributedmodules .. autofunction:: sdm_monomial_mul .. autofunction:: sdm_monomial_deg .. autofunction:: sdm_monomial_divides .. autofunction:: sdm_LC .. autofunction:: sdm_to_dict .. autofunction:: sdm_from_dict .. autofunction:: sdm_add .. autofunction:: sdm_LM .. autofunction:: sdm_LT .. autofunction:: sdm_mul_term .. autofunction:: sdm_zero .. autofunction:: sdm_deg .. autofunction:: sdm_from_vector .. autofunction:: sdm_to_vector Polynomial factorization algorithms *********************************** Many variants of Euclid's algorithm: .. currentmodule:: sympy.polys.euclidtools Classical remainder sequence ---------------------------- Let `K` be a field, and consider the ring `K[X]` of polynomials in a single indeterminate `X` with coefficients in `K`. Given two elements `f` and `g` of `K[X]` with `g\neq 0` there are unique polynomials `q` and `r` such that `f = qg + r` and `\deg(r) < \deg(g)` or `r = 0`. They are denoted by `\mathrm{quo}(f,g)` (*quotient*) and `\mathrm{rem}(f,g)` (*remainder*), so we have the *division identity* .. math:: f = \mathrm{quo}(f,g)g + \mathrm{rem}(f,g). It follows that every ideal `I` of `K[X]` is a principal ideal, generated by any element `\neq 0` of minimum degree (assuming `I` non-zero). In fact, if `g` is such a polynomial and `f` is any element of `I`, `\mathrm{rem}(f,g)` belongs to `I` as a linear combination of `f` and `g`, hence must be zero; therefore `f` is a multiple of `g`. Using this result it is possible to find a `greatest common divisor `_ (gcd) of any polynomials `f,g,\ldots` in `K[X]`. If `I` is the ideal formed by all linear combinations of the given polynomials with coefficients in `K[X]`, and `d` is its generator, then every common divisor of the polynomials also divides `d`. On the other hand, the given polynomials are multiples of the generator `d`; hence `d` is a gcd of the polynomials, denoted `\mathrm{gcd}(f,g,\ldots)`. An algorithm for the gcd of two polynomials `f` and `g` in `K[X]` can now be obtained as follows. By the division identity, `r = \mathrm{rem}(f,g)` is in the ideal generated by `f` and `g`, as well as `f` is in the ideal generated by `g` and `r`. Hence the ideals generated by the pairs `(f,g)` and `(g,r)` are the same. Set `f_0 = f`, `f_1 = g`, and define recursively `f_i = \mathrm{rem}(f_{i-2},f_{i-1})` for `i\ge 2`. The recursion ends after a finite number of steps with `f_{k+1}=0`, since the degrees of the polynomials are strictly decreasing. By the above remark, all the pairs `(f_{i-1},f_i)` generate the same ideal. In particular, the ideal generated by `f` and `g` is generated by `f_k` alone as `f_{k+1} = 0`. Hence `d = f_k` is a gcd of `f` and `g`. The sequence of polynomials `f_0`, `f_1,\ldots, f_k` is called the *Euclidean polynomial remainder sequence* determined by `(f,g)` because of the analogy with the classical `Euclidean algorithm `_ for the gcd of natural numbers. The algorithm may be extended to obtain an expression for `d` in terms of `f` and `g` by using the full division identities to write recursively each `f_i` as a linear combination of `f` and `g`. This leads to an equation .. math:: d = uf + vg\qquad (u,v \in K[X]) analogous to `Bézout's identity `_ in the case of integers. .. autofunction:: dmp_half_gcdex .. autofunction:: dmp_gcdex .. autofunction:: dmp_invert .. autofunction:: dmp_euclidean_prs Simplified remainder sequences ------------------------------ Assume, as is usual, that the coefficient field `K` is the field of fractions of an integral domain `A`. In this case the coefficients (numerators and denominators) of the polynomials in the Euclidean remainder sequence tend to grow very fast. If `A` is a unique factorization domain, the coefficients may be reduced by cancelling common factors of numerators and denominators. Further reduction is possible noting that a gcd of polynomials in `K[X]` is not unique: it may be multiplied by any (non-zero) constant factor. Any polynomial `f` in `K[X]` can be simplified by extracting the denominators and common factors of the numerators of its coefficients. This yields the representation `f = cF` where `c\in K` is the *content* of `f` and `F` is a *primitive* polynomial, i.e., a polynomial in `A[X]` with coprime coefficients. It is possible to start the algorithm by replacing the given polynomials `f` and `g` with their primitive parts. This will only modify `\mathrm{rem}(f,g)` by a constant factor. Replacing it with its primitive part and continuing recursively we obtain all the primitive parts of the polynomials in the Euclidean remainder sequence, including the primitive `\mathrm{gcd}(f,g)`. This sequence is the *primitive polynomial remainder sequence*. It is an example of *general polynomial remainder sequences* where the computed remainders are modified by constant multipliers (or divisors) in order to simplify the results. .. autofunction:: dmp_primitive_prs Subresultant sequence --------------------- The coefficients of the primitive polynomial sequence do not grow exceedingly, but the computation of the primitive parts requires extra processing effort. Besides, the method only works with fraction fields of unique factorization domains, excluding, for example, the general number fields. Collins [Collins67] realized that the so-called *subresultant polynomials* of a pair of polynomials also form a generalized remainder sequence. The coefficients of these polynomials are expressible as determinants in the coefficients of the given polynomials. Hence (the logarithm of) their size only grows linearly. In addition, if the coefficients of the given polynomials are in the subdomain `A`, so are those of the subresultant polynomials. This means that the subresultant sequence is comparable to the primitive remainder sequence without relying on unique factorization in `A`. To see how subresultants are associated with remainder sequences recall that all polynomials `h` in the sequence are linear combinations of the given polynomials `f` and `g` .. math:: h = uf+vg with polynomials `u` and `v` in `K[X]`. Moreover, as is seen from the extended Euclidean algorithm, the degrees of `u` and `v` are relatively low, with limited growth from step to step. Let `n = \deg(f)`, and `m = \deg(g)`, and assume `n\ge m`. If `\deg(h) = j < m`, the coefficients of the powers `X^k` (`k > j`) in the products `uf` and `vg` cancel each other. In particular, the products must have the same degree, say, `l`. Then `\deg(u) = l - n` and `\deg(v) = l - m` with a total of `2l -n - m + 2` coefficients to be determined. On the other hand, the equality `h = uf + vg` implies that `l - j` linear combinations of the coefficients are zero, those associated with the powers `X^i` (`j < i \leq l`), and one has a given non-zero value, namely the leading coefficient of `h`. To satisfy these `l - j + 1` linear equations the total number of coefficients to be determined cannot be lower than `l - j + 1`, in general. This leads to the inequality `l \ge n + m - j - 1`. Taking `l = n + m - j - 1`, we obtain `\deg(u) = m - j - 1` and `\deg(v) = n - j - 1`. In the case `j = 0` the matrix of the resulting system of linear equations is the `Sylvester matrix `_ `S(f,g)` associated to `f` and `g`, an `(n+m)\times (n+m)` matrix with coefficients of `f` and `g` as entries. Its determinant is the `resultant `_ `\mathrm{res}(f,g)` of the pair `(f,g)`. It is non-zero if and only if `f` and `g` are relatively prime. For any `j` in the interval from `0` to `m` the matrix of the linear system is an `(n+m-2j)\times (n+m-2j)` submatrix of the Sylvester matrix. Its determinant `s_j(f,g)` is called the `j` th *scalar subresultant* of `f` and `g`. If `s_j(f,g)` is not zero, the associated equation `h = uf + vg` has a unique solution where `\deg(h) = j` and the leading coefficient of `h` has any given value; the one with leading coefficient `s_j(f,g)` is the `j` th *subresultant polynomial* or, briefly, *subresultant* of the pair `(f,g)`, and denoted `S_j(f,g)`. This choice guarantees that the remainining coefficients are also certain subdeterminants of the Sylvester matrix. In particular, if `f` and `g` are in `A[X]`, so is `S_j(f,g)` as well. This construction of subresultants applies to any `j` between `0` and `m` regardless of the value of `s_j(f,g)`; if it is zero, then `\deg(S_j(f,g)) < j`. The properties of subresultants are as follows. Let `n_0 = \deg(f)`, `n_1 = \deg(g)`, `n_2, \ldots, n_k` be the decreasing sequence of degrees of polynomials in a remainder sequence. Let `0 \le j \le n_1`; then - `s_j(f,g)\ne 0` if and only if `j = n_i` for some `i`. - `S_j(f,g)\ne 0` if and only if `j = n_i` or `j = n_i - 1` for some `i`. Normally, `n_{i-1} - n_i = 1` for `1 < i \le k`. If `n_{i-1} - n_i > 1` for some `i` (the *abnormal* case), then `S_{n_{i-1}-1}(f,g)` and `S_{n_i}(f,g)` are constant multiples of each other. Hence either one could be included in the polynomial remainder sequence. The former is given by smaller determinants, so it is expected to have smaller coefficients. Collins defined the *subresultant remainder sequence* by setting .. math:: f_i = S_{n_{i-1}-1}(f,g) \qquad (2\le i \le k). In the normal case, these are the same as the `S_{n_i}(f,g)`. He also derived expressions for the constants `\gamma_i` in the remainder formulas .. math:: \gamma_i f_i = \mathrm{rem}(f_{i-2},f_{i-1}) in terms of the leading coefficients of `f_1,\ldots,f_{i-1}`, working in the field `K`. Brown and Traub [BrownTraub71] later developed a recursive procedure for computing the coefficients `\gamma_i`. Their algorithm deals with elements of the domain `A` exclusively (assuming `f,g\in A[X]`). However, in the abnormal case there was a problem, a division in `A` which could only be conjectured to be exact. This was subsequently justified by Brown [Brown78] who showed that the result of the division is, in fact, a scalar subresultant. More specifically, the constant appearing in the computation of `f_i` is `s_{n_{i-2}}(f,g)` (Theorem 3). The implication of this discovery is that the scalar subresultants are computed as by-products of the algorithm, all but `s_{n_k}(f,g)` which is not needed after finding `f_{k+1} = 0`. Completing the last step we obtain all non-zero scalar subresultants, including the last one which is the resultant if this does not vanish. .. autofunction:: dmp_inner_subresultants .. autofunction:: dmp_subresultants .. autofunction:: dmp_prs_resultant .. autofunction:: dmp_zz_modular_resultant .. autofunction:: dmp_zz_collins_resultant .. autofunction:: dmp_qq_collins_resultant .. autofunction:: dmp_resultant .. autofunction:: dmp_discriminant .. autofunction:: dmp_rr_prs_gcd .. autofunction:: dmp_ff_prs_gcd .. autofunction:: dmp_zz_heu_gcd .. autofunction:: dmp_qq_heu_gcd .. autofunction:: dmp_inner_gcd .. autofunction:: dmp_gcd .. autofunction:: dmp_lcm .. autofunction:: dmp_content .. autofunction:: dmp_primitive .. autofunction:: dmp_cancel Polynomial factorization in characteristic zero: .. currentmodule:: sympy.polys.factortools .. autofunction:: dmp_trial_division .. autofunction:: dmp_zz_mignotte_bound .. autofunction:: dup_zz_hensel_step .. autofunction:: dup_zz_hensel_lift .. autofunction:: dup_zz_zassenhaus .. autofunction:: dup_zz_irreducible_p .. autofunction:: dup_cyclotomic_p .. autofunction:: dup_zz_cyclotomic_poly .. autofunction:: dup_zz_cyclotomic_factor .. autofunction:: dup_zz_factor_sqf .. autofunction:: dup_zz_factor .. autofunction:: dmp_zz_wang_non_divisors .. autofunction:: dmp_zz_wang_test_points .. autofunction:: dmp_zz_wang_lead_coeffs .. autofunction:: dmp_zz_diophantine .. autofunction:: dmp_zz_wang_hensel_lifting .. autofunction:: dmp_zz_wang .. autofunction:: dmp_zz_factor .. autofunction:: dmp_ext_factor .. autofunction:: dup_gf_factor .. autofunction:: dmp_factor_list .. autofunction:: dmp_factor_list_include .. autofunction:: dmp_irreducible_p Groebner basis algorithms ************************* Groebner bases can be used to answer many problems in computational commutative algebra. Their computation in rather complicated, and very performance-sensitive. We present here various low-level implementations of Groebner basis computation algorithms; please see the previous section of the manual for usage. .. currentmodule:: sympy.polys.groebnertools .. autofunction:: groebner .. autofunction:: spoly .. autofunction:: red_groebner .. autofunction:: is_groebner .. autofunction:: is_minimal .. autofunction:: is_reduced .. currentmodule:: sympy.polys.fglmtools .. autofunction:: matrix_fglm Groebner basis algorithms for modules are also provided: .. currentmodule:: sympy.polys.distributedmodules .. autofunction:: sdm_spoly .. autofunction:: sdm_ecart .. autofunction:: sdm_nf_mora .. autofunction:: sdm_groebner Options ======= .. automodule:: sympy.polys.polyoptions .. autoclass:: sympy.polys.polyoptions.Options :members: .. autofunction:: sympy.polys.polyoptions.build_options Configuration ============= .. automodule:: sympy.polys.polyconfig .. autofunction:: sympy.polys.polyconfig.setup Exceptions ========== These are exceptions defined by the polynomials module. TODO sort and explain .. currentmodule:: sympy.polys.polyerrors .. autoclass:: BasePolynomialError :members: .. autoclass:: ExactQuotientFailed :members: .. autoclass:: OperationNotSupported :members: .. autoclass:: HeuristicGCDFailed :members: .. autoclass:: HomomorphismFailed :members: .. autoclass:: IsomorphismFailed :members: .. autoclass:: ExtraneousFactors :members: .. autoclass:: EvaluationFailed :members: .. autoclass:: RefinementFailed :members: .. autoclass:: CoercionFailed :members: .. autoclass:: NotInvertible :members: .. autoclass:: NotReversible :members: .. autoclass:: NotAlgebraic :members: .. autoclass:: DomainError :members: .. autoclass:: PolynomialError :members: .. autoclass:: UnificationFailed :members: .. autoclass:: GeneratorsNeeded :members: .. autoclass:: ComputationFailed :members: .. autoclass:: GeneratorsError :members: .. autoclass:: UnivariatePolynomialError :members: .. autoclass:: MultivariatePolynomialError :members: .. autoclass:: PolificationFailed :members: .. autoclass:: OptionError :members: .. autoclass:: FlagError :members: Reference ========= Modular GCD *********** .. currentmodule:: sympy.polys.modulargcd .. autofunction:: modgcd_univariate .. autofunction:: modgcd_bivariate .. autofunction:: modgcd_multivariate .. autofunction:: _modgcd_multivariate_p .. autofunction:: func_field_modgcd Undocumented ============ Many parts of the polys module are still undocumented, and even where there is documentation it is scarce. Please contribute! sympy-sympy-1.9/doc/src/modules/polys/literature.rst000066400000000000000000000145771412543434000230250ustar00rootroot00000000000000.. _polys-literature: ========== Literature ========== The following is a non-comprehensive list of publications that were used as a theoretical foundation for implementing polynomials manipulation module. .. [Kozen89] D. Kozen, S. Landau, Polynomial decomposition algorithms, Journal of Symbolic Computation 7 (1989), pp. 445-456 .. [Liao95] Hsin-Chao Liao, R. Fateman, Evaluation of the heuristic polynomial GCD, International Symposium on Symbolic and Algebraic Computation (ISSAC), ACM Press, Montreal, Quebec, Canada, 1995, pp. 240--247 .. [Gathen99] J. von zur Gathen, J. Gerhard, Modern Computer Algebra, First Edition, Cambridge University Press, 1999 .. [Weisstein09] Eric W. Weisstein, Cyclotomic Polynomial, From MathWorld - A Wolfram Web Resource, http://mathworld.wolfram.com/CyclotomicPolynomial.html .. [Wang78] P. S. Wang, An Improved Multivariate Polynomial Factoring Algorithm, Math. of Computation 32, 1978, pp. 1215--1231 .. [Geddes92] K. Geddes, S. R. Czapor, G. Labahn, Algorithms for Computer Algebra, Springer, 1992 .. [Monagan93] Michael Monagan, In-place Arithmetic for Polynomials over Z_n, Proceedings of DISCO '92, Springer-Verlag LNCS, 721, 1993, pp. 22--34 .. [Kaltofen98] E. Kaltofen, V. Shoup, Subquadratic-time Factoring of Polynomials over Finite Fields, Mathematics of Computation, Volume 67, Issue 223, 1998, pp. 1179--1197 .. [Shoup95] V. Shoup, A New Polynomial Factorization Algorithm and its Implementation, Journal of Symbolic Computation, Volume 20, Issue 4, 1995, pp. 363--397 .. [Gathen92] J. von zur Gathen, V. Shoup, Computing Frobenius Maps and Factoring Polynomials, ACM Symposium on Theory of Computing, 1992, pp. 187--224 .. [Shoup91] V. Shoup, A Fast Deterministic Algorithm for Factoring Polynomials over Finite Fields of Small Characteristic, In Proceedings of International Symposium on Symbolic and Algebraic Computation, 1991, pp. 14--21 .. [Cox97] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and Algorithms, Springer, Second Edition, 1997 .. [Ajwa95] I.A. Ajwa, Z. Liu, P.S. Wang, Groebner Bases Algorithm, https://citeseer.ist.psu.edu/myciteseer/login, 1995 .. [Bose03] N.K. Bose, B. Buchberger, J.P. Guiver, Multidimensional Systems Theory and Applications, Springer, 2003 .. [Giovini91] A. Giovini, T. Mora, "One sugar cube, please" or Selection strategies in Buchberger algorithm, ISSAC '91, ACM .. [Bronstein93] M. Bronstein, B. Salvy, Full partial fraction decomposition of rational functions, Proceedings ISSAC '93, ACM Press, Kiev, Ukraine, 1993, pp. 157--160 .. [Buchberger01] B. Buchberger, Groebner Bases: A Short Introduction for Systems Theorists, In: R. Moreno-Diaz, B. Buchberger, J. L. Freire, Proceedings of EUROCAST'01, February, 2001 .. [Davenport88] J.H. Davenport, Y. Siret, E. Tournier, Computer Algebra Systems and Algorithms for Algebraic Computation, Academic Press, London, 1988, pp. 124--128 .. [Greuel2008] G.-M. Greuel, Gerhard Pfister, A Singular Introduction to Commutative Algebra, Springer, 2008 .. [Atiyah69] M.F. Atiyah, I.G. MacDonald, Introduction to Commutative Algebra, Addison-Wesley, 1969 .. [Collins67] G.E. Collins, Subresultants and Reduced Polynomial Remainder Sequences. J. ACM 14 (1967) 128-142 .. [BrownTraub71] W.S. Brown, J.F. Traub, On Euclid's Algorithm and the Theory of Subresultants. J. ACM 18 (1971) 505-514 .. [Brown78] W.S. Brown, The Subresultant PRS Algorithm. ACM Transaction of Mathematical Software 4 (1978) 237-249 .. [Monagan00] M. Monagan and A. Wittkopf, On the Design and Implementation of Brown’s Algorithm over the Integers and Number Fields, Proceedings of ISSAC 2000, pp. 225-233, ACM, 2000. .. [Brown71] W.S. Brown, On Euclid's Algorithm and the Computation of Polynomial Greatest Common Divisors, J. ACM 18, 4, pp. 478-504, 1971. .. [Hoeij04] M. van Hoeij and M. Monagan, Algorithms for polynomial GCD computation over algebraic function fields, Proceedings of ISSAC 2004, pp. 297-304, ACM, 2004. .. [Wang81] P.S. Wang, A p-adic algorithm for univariate partial fractions, Proceedings of SYMSAC 1981, pp. 212-217, ACM, 1981. .. [Hoeij02] M. van Hoeij and M. Monagan, A modular GCD algorithm over number fields presented with multiple extensions, Proceedings of ISSAC 2002, pp. 109-116, ACM, 2002 .. [ManWright94] Yiu-Kwong Man and Francis J. Wright, "Fast Polynomial Dispersion Computation and its Application to Indefinite Summation", Proceedings of the International Symposium on Symbolic and Algebraic Computation, 1994, Pages 175-180 http://dl.acm.org/citation.cfm?doid=190347.190413 .. [Koepf98] Wolfram Koepf, "Hypergeometric Summation: An Algorithmic Approach to Summation and Special Function Identities", Advanced lectures in mathematics, Vieweg, 1998 .. [Abramov71] S. A. Abramov, "On the Summation of Rational Functions", USSR Computational Mathematics and Mathematical Physics, Volume 11, Issue 4, 1971, Pages 324-330 .. [Man93] Yiu-Kwong Man, "On Computing Closed Forms for Indefinite Summations", Journal of Symbolic Computation, Volume 16, Issue 4, 1993, Pages 355-376 http://www.sciencedirect.com/science/article/pii/S0747717183710539 .. [Kapur1994] Deepak Kapur, Tushar Saxena, and Lu Yang. "Algebraic and geometric reasoning using Dixon resultants", In Proceedings of the international symposium on Symbolic and algebraic computation (ISSAC '94), 1994, pages 99-107. https://www.researchgate.net/publication/2514261_Algebraic_and_Geometric_Reasoning_using_Dixon_Resultants .. [Palancz08] B Paláncz, P Zaletnyik, JL Awange, EW Grafarend. "Dixon resultant's solution of systems of geodetic polynomial equations", Journal of Geodesy, 2008, Springer, https://www.researchgate.net/publication/225607735_Dixon_resultant's_solution_of_systems_of_geodetic_polynomial_equations. .. [Bruce97] Bruce Randall Donald, Deepak Kapur, and Joseph L. Mundy (Eds.). "Symbolic and Numerical Computation for Artificial Intelligence", Chapter 2, Academic Press, Inc., Orlando, FL, USA, 1997, https://www2.cs.duke.edu/donaldlab/Books/SymbolicNumericalComputation/045-087.pdf. .. [Stiller96] P Stiller. "An introduction to the theory of resultants", Mathematics and Computer Science, T&M University, 1996, Citeseer, http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.590.2021&rep=rep1&type=pdf.sympy-sympy-1.9/doc/src/modules/polys/reference.rst000066400000000000000000000111131412543434000225620ustar00rootroot00000000000000.. _polys-reference: ========================================= Polynomials Manipulation Module Reference ========================================= .. automodule:: sympy.polys See :ref:`polys-docs` for an index of documentation for the polys module and :ref:`polys-basics` for an introductory explanation. Basic polynomial manipulation functions ======================================= .. currentmodule:: sympy.polys.polytools .. autofunction:: poly .. autofunction:: poly_from_expr .. autofunction:: parallel_poly_from_expr .. autofunction:: degree .. autofunction:: degree_list .. autofunction:: LC .. autofunction:: LM .. autofunction:: LT .. autofunction:: pdiv .. autofunction:: prem .. autofunction:: pquo .. autofunction:: pexquo .. autofunction:: div .. autofunction:: rem .. autofunction:: quo .. autofunction:: exquo .. autofunction:: half_gcdex .. autofunction:: gcdex .. autofunction:: invert .. autofunction:: subresultants .. autofunction:: resultant .. autofunction:: discriminant .. autofunction:: terms_gcd .. autofunction:: cofactors .. autofunction:: gcd .. autofunction:: gcd_list .. autofunction:: lcm .. autofunction:: lcm_list .. autofunction:: trunc .. autofunction:: monic .. autofunction:: content .. autofunction:: primitive .. autofunction:: compose .. autofunction:: decompose .. autofunction:: sturm .. autofunction:: gff_list .. autofunction:: gff .. autofunction:: sqf_norm .. autofunction:: sqf_part .. autofunction:: sqf_list .. autofunction:: sqf .. autofunction:: factor_list .. autofunction:: factor .. autofunction:: intervals .. autofunction:: refine_root .. autofunction:: count_roots .. autofunction:: real_roots .. autofunction:: nroots .. autofunction:: ground_roots .. autofunction:: nth_power_roots_poly .. autofunction:: cancel .. autofunction:: reduced .. autofunction:: groebner .. autofunction:: is_zero_dimensional .. autoclass:: Poly :members: .. autoclass:: PurePoly :members: .. autoclass:: GroebnerBasis :members: Extra polynomial manipulation functions ======================================= .. currentmodule:: sympy.polys.polyfuncs .. autofunction:: symmetrize .. autofunction:: horner .. autofunction:: interpolate .. autofunction:: viete Domain constructors =================== .. currentmodule:: sympy.polys.constructor .. autofunction:: construct_domain Algebraic number fields ======================= .. currentmodule:: sympy.polys.numberfields .. autofunction:: minimal_polynomial .. autofunction:: minpoly .. autofunction:: primitive_element .. autofunction:: field_isomorphism .. autofunction:: to_number_field .. autofunction:: isolate .. autoclass:: AlgebraicNumber :members: Monomials encoded as tuples =========================== .. currentmodule:: sympy.polys.monomials .. autoclass:: Monomial :members: .. autofunction:: itermonomials .. autofunction:: monomial_count Orderings of monomials ====================== .. currentmodule:: sympy.polys.orderings .. autoclass:: MonomialOrder :members: .. autoclass:: LexOrder :members: .. autoclass:: GradedLexOrder :members: .. autoclass:: ReversedGradedLexOrder :members: Formal manipulation of roots of polynomials =========================================== .. currentmodule:: sympy.polys.rootoftools .. autofunction:: rootof .. autoclass:: RootOf :members: .. autoclass:: ComplexRootOf :members: :private-members: .. autoclass:: RootSum :members: Symbolic root-finding algorithms ================================ .. currentmodule:: sympy.polys.polyroots .. autofunction:: roots Special polynomials =================== .. currentmodule:: sympy.polys.specialpolys .. autofunction:: swinnerton_dyer_poly .. autofunction:: interpolating_poly .. autofunction:: cyclotomic_poly .. autofunction:: symmetric_poly .. autofunction:: random_poly Orthogonal polynomials ====================== .. currentmodule:: sympy.polys.orthopolys .. autofunction:: chebyshevt_poly .. autofunction:: chebyshevu_poly .. autofunction:: gegenbauer_poly .. autofunction:: hermite_poly .. autofunction:: jacobi_poly .. autofunction:: legendre_poly .. autofunction:: laguerre_poly .. autofunction:: spherical_bessel_fn Manipulation of rational functions ================================== .. currentmodule:: sympy.polys.rationaltools .. autofunction:: together Partial fraction decomposition ============================== .. currentmodule:: sympy.polys.partfrac .. autofunction:: apart .. autofunction:: apart_list .. autofunction:: assemble_partfrac_list Dispersion of Polynomials ========================= .. currentmodule:: sympy.polys.dispersion .. autofunction:: dispersionset .. autofunction:: dispersion sympy-sympy-1.9/doc/src/modules/polys/ringseries.rst000066400000000000000000000211601412543434000230010ustar00rootroot00000000000000.. _polys-ringseries: ===================================== Series Manipulation using Polynomials ===================================== Any finite Taylor series, for all practical purposes is, in fact a polynomial. This module makes use of the efficient representation and operations of sparse polynomials for very fast multivariate series manipulations. Typical speedups compared to SymPy's ``series`` method are in the range 20-100, with the gap widening as the series being handled gets larger. All the functions expand any given series on some ring specified by the user. Thus, the coefficients of the calculated series depend on the ring being used. For example:: >>> from sympy.polys import ring, QQ, RR >>> from sympy.polys.ring_series import rs_sin >>> R, x, y = ring('x, y', QQ) >>> rs_sin(x*y, x, 5) -1/6*x**3*y**3 + x*y ``QQ`` stands for the Rational domain. Here all coefficients are rationals. It is recommended to use ``QQ`` with ring series as it automatically chooses the fastest Rational type. Similarly, if a Real domain is used:: >>> R, x, y = ring('x, y', RR) >>> rs_sin(x*y, x, 5) -0.166666666666667*x**3*y**3 + x*y Though the definition of a polynomial limits the use of Polynomial module to Taylor series, we extend it to allow Laurent and even Puiseux series (with fractional exponents):: >>> from sympy.polys.ring_series import rs_cos, rs_tan >>> R, x, y = ring('x, y', QQ) >>> rs_cos(x + x*y, x, 3)/x**3 -1/2*x**(-1)*y**2 - x**(-1)*y - 1/2*x**(-1) + x**(-3) >>> rs_tan(x**QQ(2, 5)*y**QQ(1, 2), x, 2) 1/3*x**(6/5)*y**(3/2) + x**(2/5)*y**(1/2) By default, ``PolyElement`` did not allow non-natural numbers as exponents. It converted a fraction to an integer and raised an error on getting negative exponents. The goal of the ``ring series`` module is fast series expansion, and not to use the ``polys`` module. The reason we use it as our backend is simply because it implements a sparse representation and most of the basic functions that we need. However, this default behaviour of ``polys`` was limiting for ``ring series``. Note that there is no such constraint (in having rational exponents) in the data-structure used by ``polys``- ``dict``. Sparse polynomials (``PolyElement``) use the Python dict to store a polynomial term by term, where a tuple of exponents is the key and the coefficient of that term is the value. There is no reason why we can't have rational values in the ``dict`` so as to support rational exponents. So the approach we took was to modify sparse ``polys`` to allow non-natural exponents. And it turned out to be quite simple. We only had to delete the conversion to ``int`` of exponents in the ``__pow__`` method of ``PolyElement``. So:: >>> x**QQ(3, 4) x**(3/4) and not ``1`` as was the case earlier. Though this change violates the definition of a polynomial, it doesn't break anything yet. Ideally, we shouldn't modify ``polys`` in any way. But to have all the ``series`` capabilities we want, no other simple way was found. If need be, we can separate the modified part of ``polys`` from core ``polys``. It would be great if any other elegant solution is found. All series returned by the functions of this module are instances of the ``PolyElement`` class. To use them with other SymPy types, convert them to ``Expr``:: >>> from sympy.polys.ring_series import rs_exp >>> from sympy.abc import a, b, c >>> series = rs_exp(x, x, 5) >>> a + series.as_expr() a + x**4/24 + x**3/6 + x**2/2 + x + 1 rs_series ========= Direct use of elementary ring series functions does give more control, but is limiting at the same time. Creating an appropriate ring for the desired series expansion and knowing which ring series function to call, are things not everyone might be familiar with. `rs\_series` is a function that takes an arbitrary ``Expr`` and returns its expansion by calling the appropriate ring series functions. The returned series is a polynomial over the simplest (almost) possible ring that does the job. It recursively builds the ring as it parses the given expression, adding generators to the ring when it needs them. Some examples:: >>> rs_series(sin(a + b), a, 5) # doctest: +SKIP 1/24*sin(b)*a**4 - 1/2*sin(b)*a**2 + sin(b) - 1/6*cos(b)*a**3 + cos(b)*a >>> rs_series(sin(exp(a*b) + cos(a + c)), a, 2) # doctest: +SKIP -sin(c)*cos(cos(c) + 1)*a + cos(cos(c) + 1)*a*b + sin(cos(c) + 1) >>> rs_series(sin(a + b)*cos(a + c)*tan(a**2 + b), a, 2) # doctest: +SKIP cos(b)*cos(c)*tan(b)*a - sin(b)*sin(c)*tan(b)*a + sin(b)*cos(c)*tan(b) It can expand complicated multivariate expressions involving multiple functions and most importantly, it does so blazingly fast:: >>> %timeit ((sin(a) + cos(a))**10).series(a, 0, 5) # doctest: +SKIP 1 loops, best of 3: 1.33 s per loop >>> %timeit rs_series((sin(a) + cos(a))**10, a, 5) # doctest: +SKIP 100 loops, best of 3: 4.13 ms per loop `rs\_series` is over 300 times faster. Given an expression to expand, there is some fixed overhead to parse it. Thus, for larger orders, the speed improvement becomes more prominent:: >>> %timeit rs_series((sin(a) + cos(a))**10, a, 100) # doctest: +SKIP 10 loops, best of 3: 32.8 ms per loop To figure out the right ring for a given expression, `rs\_series` uses the ``sring`` function, which in turn uses other functions of ``polys``. As explained above, non-natural exponents are not allowed. But the restriction is on exponents and not generators. So, ``polys`` allows all sorts of symbolic terms as generators to make sure that the exponent is a natural number:: >>> from sympy.polys.rings import sring >>> R, expr = sring(1/a**3 + a**QQ(3, 7)); R Polynomial ring in 1/a, a**(1/7) over ZZ with lex order In the above example, `1/a` and `a**(1/7)` will be treated as completely different atoms. For all practical purposes, we could let `b = 1/a` and `c = a**(1/7)` and do the manipulations. Effectively, expressions involving `1/a` and `a**(1/7)` (and their powers) will never simplify:: >>> expr*R(1/a) # doctest: +SKIP (1/a)**2 + (1/a)*(a**(1/7))**3 This leads to similar issues with manipulating Laurent and Puiseux series as faced earlier. Fortunately, this time we have an elegant solution and are able to isolate the ``series`` and ``polys`` behaviour from one another. We introduce a boolean flag ``series`` in the list of allowed ``Options`` for polynomials (see :class:`sympy.polys.polyoptions.Options`). Thus, when we want ``sring`` to allow rational exponents we supply a ``series=True`` flag to ``sring``:: >>> rs_series(sin(a**QQ(1, 2)), a, 3) # doctest: +SKIP -1/5040*a**(7/3) + 1/120*a**(5/3) - 1/6*a + a**(1/3) Contribute ========== `rs\_series` is not fully implemented yet. As of now, it supports only multivariate Taylor expansions of expressions involving ``sin``, ``cos``, ``exp`` and ``tan``. Adding the remaining functions is not at all difficult and they will be gradually added. If you are interested in helping, read the comments in ``ring_series.py``. Currently, it does not support Puiseux series (though the elementary functions do). This is expected to be fixed soon. You can also add more functions to ``ring_series.py``. Only elementary functions are supported currently. The long term goal is to replace SymPy's current ``series`` method with ``rs_series``. Manipulation of power series **************************************************************************** .. currentmodule:: sympy.polys.ring_series Functions in this module carry the prefix ``rs_``, standing for "ring series". They manipulate finite power series in the sparse representation provided by ``polys.ring.ring``. **Elementary functions** .. autofunction:: rs_log .. autofunction:: rs_LambertW .. autofunction:: rs_exp .. autofunction:: rs_atan .. autofunction:: rs_asin .. autofunction:: rs_tan .. autofunction:: _tan1 .. autofunction:: rs_cot .. autofunction:: rs_sin .. autofunction:: rs_cos .. autofunction:: rs_cos_sin .. autofunction:: rs_atanh .. autofunction:: rs_sinh .. autofunction:: rs_cosh .. autofunction:: rs_tanh .. autofunction:: rs_hadamard_exp **Operations** .. autofunction:: rs_mul .. autofunction:: rs_square .. autofunction:: rs_pow .. autofunction:: rs_series_inversion .. autofunction:: rs_series_reversion .. autofunction:: rs_nth_root .. autofunction:: rs_trunc .. autofunction:: rs_subs .. autofunction:: rs_diff .. autofunction:: rs_integrate .. autofunction:: rs_newton .. autofunction:: rs_compose_add **Utility functions** .. autofunction:: rs_is_puiseux .. autofunction:: rs_puiseux .. autofunction:: rs_puiseux2 .. autofunction:: rs_series_from_list .. autofunction:: rs_fun .. autofunction:: mul_xin .. autofunction:: pow_xin sympy-sympy-1.9/doc/src/modules/polys/solvers.rst000066400000000000000000000012471412543434000223300ustar00rootroot00000000000000.. _poly_solvers-docs: Poly solvers ============ This module provides functions for solving systems of linear equations that are used internally in sympy. .. module::sympy.polys.solvers .. automodule:: sympy.polys.solvers solve_lin_sys ^^^^^^^^^^^^^ .. autofunction:: sympy.polys.solvers.solve_lin_sys eqs_to_matrix ^^^^^^^^^^^^^ .. autofunction:: sympy.polys.solvers.eqs_to_matrix sympy_eqs_to_ring ^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.polys.solvers.sympy_eqs_to_ring _solve_lin_sys ^^^^^^^^^^^^^^ .. autofunction:: sympy.polys.solvers._solve_lin_sys _solve_lin_sys_component ^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.polys.solvers._solve_lin_sys_component sympy-sympy-1.9/doc/src/modules/polys/wester.rst000066400000000000000000000364001412543434000221430ustar00rootroot00000000000000.. _polys-wester: ============================== Examples from Wester's Article ============================== Introduction ============ In this tutorial we present examples from Wester's article concerning comparison and critique of mathematical abilities of several computer algebra systems (see [Wester1999]_). All the examples are related to polynomial and algebraic computations and SymPy specific remarks were added to all of them. Examples ======== All examples in this tutorial are computable, so one can just copy and paste them into a Python shell and do something useful with them. All computations were done using the following setup:: >>> from sympy import * >>> init_printing(use_unicode=True, wrap_line=False) >>> var('x,y,z,s,c,n') (x, y, z, s, c, n) Simple univariate polynomial factorization ------------------------------------------ To obtain a factorization of a polynomial use :func:`~.factor` function. By default :func:`~.factor` returns the result in unevaluated form, so the content of the input polynomial is left unexpanded, as in the following example:: >>> factor(6*x - 10) 2⋅(3⋅x - 5) To achieve the same effect in a more systematic way use :func:`~.primitive` function, which returns the content and the primitive part of the input polynomial:: >>> primitive(6*x - 10) (2, 3⋅x - 5) .. note:: The content and the primitive part can be computed only over a ring. To simplify coefficients of a polynomial over a field use :func:`~.monic`. Univariate GCD, resultant and factorization ------------------------------------------- Consider univariate polynomials ``f``, ``g`` and ``h`` over integers:: >>> f = 64*x**34 - 21*x**47 - 126*x**8 - 46*x**5 - 16*x**60 - 81 >>> g = 72*x**60 - 25*x**25 - 19*x**23 - 22*x**39 - 83*x**52 + 54*x**10 + 81 >>> h = 34*x**19 - 25*x**16 + 70*x**7 + 20*x**3 - 91*x - 86 We can compute the greatest common divisor (GCD) of two polynomials using :func:`~.gcd` function:: >>> gcd(f, g) 1 We see that ``f`` and ``g`` have no common factors. However, ``f*h`` and ``g*h`` have an obvious factor ``h``:: >>> gcd(expand(f*h), expand(g*h)) - h 0 The same can be verified using the resultant of univariate polynomials:: >>> resultant(expand(f*h), expand(g*h)) 0 Factorization of large univariate polynomials (of degree 120 in this case) over integers is also possible:: >>> factor(expand(f*g)) ⎛ 60 47 34 8 5 ⎞ ⎛ 60 52 39 25 23 10 ⎞ -⎝16⋅x + 21⋅x - 64⋅x + 126⋅x + 46⋅x + 81⎠⋅⎝72⋅x - 83⋅x - 22⋅x - 25⋅x - 19⋅x + 54⋅x + 81⎠ Multivariate GCD and factorization ---------------------------------- What can be done in univariate case, can be also done for multivariate polynomials. Consider the following polynomials ``f``, ``g`` and ``h`` in `\mathbb{Z}[x,y,z]`:: >>> f = 24*x*y**19*z**8 - 47*x**17*y**5*z**8 + 6*x**15*y**9*z**2 - 3*x**22 + 5 >>> g = 34*x**5*y**8*z**13 + 20*x**7*y**7*z**7 + 12*x**9*y**16*z**4 + 80*y**14*z >>> h = 11*x**12*y**7*z**13 - 23*x**2*y**8*z**10 + 47*x**17*y**5*z**8 As previously, we can verify that ``f`` and ``g`` have no common factors:: >>> gcd(f, g) 1 However, ``f*h`` and ``g*h`` have an obvious factor ``h``:: >>> gcd(expand(f*h), expand(g*h)) - h 0 Multivariate factorization of large polynomials is also possible:: >>> factor(expand(f*g)) 7 ⎛ 9 9 3 7 6 5 12 7⎞ ⎛ 22 17 5 8 15 9 2 19 8 ⎞ -2⋅y ⋅z⋅⎝6⋅x ⋅y ⋅z + 10⋅x ⋅z + 17⋅x ⋅y⋅z + 40⋅y ⎠⋅⎝3⋅x + 47⋅x ⋅y ⋅z - 6⋅x ⋅y ⋅z - 24⋅x⋅y ⋅z - 5⎠ Support for symbols in exponents -------------------------------- Polynomial manipulation functions provided by :mod:`sympy.polys` are mostly used with integer exponents. However, it's perfectly valid to compute with symbolic exponents, e.g.:: >>> gcd(2*x**(n + 4) - x**(n + 2), 4*x**(n + 1) + 3*x**n) n x Testing if polynomials have common zeros ---------------------------------------- To test if two polynomials have a root in common we can use :func:`~.resultant` function. The theory says that the resultant of two polynomials vanishes if there is a common zero of those polynomials. For example:: >>> resultant(3*x**4 + 3*x**3 + x**2 - x - 2, x**3 - 3*x**2 + x + 5) 0 We can visualize this fact by factoring the polynomials:: >>> factor(3*x**4 + 3*x**3 + x**2 - x - 2) ⎛ 3 ⎞ (x + 1)⋅⎝3⋅x + x - 2⎠ >>> factor(x**3 - 3*x**2 + x + 5) ⎛ 2 ⎞ (x + 1)⋅⎝x - 4⋅x + 5⎠ In both cases we obtained the factor `x + 1` which tells us that the common root is `x = -1`. Normalizing simple rational functions ------------------------------------- To remove common factors from the numerator and the denominator of a rational function the elegant way, use :func:`~.cancel` function. For example:: >>> cancel((x**2 - 4)/(x**2 + 4*x + 4)) x - 2 ───── x + 2 Expanding expressions and factoring back ---------------------------------------- One can work easily we expressions in both expanded and factored forms. Consider a polynomial ``f`` in expanded form. We differentiate it and factor the result back:: >>> f = expand((x + 1)**20) >>> g = diff(f, x) >>> factor(g) 19 20⋅(x + 1) The same can be achieved in factored form:: >>> diff((x + 1)**20, x) 19 20⋅(x + 1) Factoring in terms of cyclotomic polynomials -------------------------------------------- SymPy can very efficiently decompose polynomials of the form `x^n \pm 1` in terms of cyclotomic polynomials:: >>> factor(x**15 - 1) ⎛ 2 ⎞ ⎛ 4 3 2 ⎞ ⎛ 8 7 5 4 3 ⎞ (x - 1)⋅⎝x + x + 1⎠⋅⎝x + x + x + x + 1⎠⋅⎝x - x + x - x + x - x + 1⎠ The original Wester`s example was `x^{100} - 1`, but was truncated for readability purpose. Note that this is not a big struggle for :func:`~.factor` to decompose polynomials of degree 1000 or greater. Univariate factoring over Gaussian numbers ------------------------------------------ Consider a univariate polynomial ``f`` with integer coefficients:: >>> f = 4*x**4 + 8*x**3 + 77*x**2 + 18*x + 153 We want to obtain a factorization of ``f`` over Gaussian numbers. To do this we use :func:`~.factor` as previously, but this time we set ``gaussian`` keyword to ``True``:: >>> factor(f, gaussian=True) ⎛ 3⋅ⅈ⎞ ⎛ 3⋅ⅈ⎞ 4⋅⎜x - ───⎟⋅⎜x + ───⎟⋅(x + 1 - 4⋅ⅈ)⋅(x + 1 + 4⋅ⅈ) ⎝ 2 ⎠ ⎝ 2 ⎠ As the result we got a splitting factorization of ``f`` with monic factors (this is a general rule when computing in a field with SymPy). The ``gaussian`` keyword is useful for improving code readability, however the same result can be computed using more general syntax:: >>> factor(f, extension=I) ⎛ 3⋅ⅈ⎞ ⎛ 3⋅ⅈ⎞ 4⋅⎜x - ───⎟⋅⎜x + ───⎟⋅(x + 1 - 4⋅ⅈ)⋅(x + 1 + 4⋅ⅈ) ⎝ 2 ⎠ ⎝ 2 ⎠ Computing with automatic field extensions ----------------------------------------- Consider two univariate polynomials ``f`` and ``g``:: >>> f = x**3 + (sqrt(2) - 2)*x**2 - (2*sqrt(2) + 3)*x - 3*sqrt(2) >>> g = x**2 - 2 We would like to reduce degrees of the numerator and the denominator of a rational function ``f/g``. To do this we employ :func:`~.cancel` function:: >>> cancel(f/g) 3 2 2 x - 2⋅x + √2⋅x - 3⋅x - 2⋅√2⋅x - 3⋅√2 ─────────────────────────────────────── 2 x - 2 Unfortunately nothing interesting happened. This is because by default SymPy treats `\sqrt{2}` as a generator, obtaining a bivariate polynomial for the numerator. To make :func:`~.cancel` recognize algebraic properties of `\sqrt{2}`, one needs to use ``extension`` keyword:: >>> cancel(f/g, extension=True) 2 x - 2⋅x - 3 ──────────── x - √2 Setting ``extension=True`` tells :func:`~.cancel` to find minimal algebraic number domain for the coefficients of ``f/g``. The automatically inferred domain is `\mathbb{Q}(\sqrt{2})`. If one doesn't want to rely on automatic inference, the same result can be obtained by setting the ``extension`` keyword with an explicit algebraic number:: >>> cancel(f/g, extension=sqrt(2)) 2 x - 2⋅x - 3 ──────────── x - √2 Univariate factoring over various domains ----------------------------------------- Consider a univariate polynomial ``f`` with integer coefficients:: >>> f = x**4 - 3*x**2 + 1 With :mod:`sympy.polys` we can obtain factorizations of ``f`` over different domains, which includes: * rationals:: >>> factor(f) ⎛ 2 ⎞ ⎛ 2 ⎞ ⎝x - x - 1⎠⋅⎝x + x - 1⎠ * finite fields:: >>> factor(f, modulus=5) 2 2 (x - 2) ⋅(x + 2) * algebraic numbers:: >>> alg = AlgebraicNumber((sqrt(5) - 1)/2, alias='alpha') >>> factor(f, extension=alg) (x - α)⋅(x + α)⋅(x - 1 - α)⋅(x + α + 1) Factoring polynomials into linear factors ----------------------------------------- Currently SymPy can factor polynomials into irreducibles over various domains, which can result in a splitting factorization (into linear factors). However, there is currently no systematic way to infer a splitting field (algebraic number field) automatically. In future the following syntax will be implemented:: >>> factor(x**3 + x**2 - 7, split=True) Traceback (most recent call last): ... NotImplementedError: 'split' option is not implemented yet Note this is different from ``extension=True``, because the later only tells how expression parsing should be done, not what should be the domain of computation. One can simulate the ``split`` keyword for several classes of polynomials using :func:`~.solve` function. Advanced factoring over finite fields ------------------------------------- Consider a univariate polynomial ``f`` with integer coefficients:: >>> f = x**11 + x + 1 We can factor ``f`` over a large finite field `F_{65537}`:: >>> factor(f, modulus=65537) ⎛ 2 ⎞ ⎛ 9 8 6 5 3 2 ⎞ ⎝x + x + 1⎠⋅⎝x - x + x - x + x - x + 1⎠ and expand the resulting factorization back:: >>> expand(_) 11 x + x + 1 obtaining polynomial ``f``. This was done using symmetric polynomial representation over finite fields The same thing can be done using non-symmetric representation:: >>> factor(f, modulus=65537, symmetric=False) ⎛ 2 ⎞ ⎛ 9 8 6 5 3 2 ⎞ ⎝x + x + 1⎠⋅⎝x + 65536⋅x + x + 65536⋅x + x + 65536⋅x + 1⎠ As with symmetric representation we can expand the factorization to get the input polynomial back. This time, however, we need to truncate coefficients of the expanded polynomial modulo 65537:: >>> trunc(expand(_), 65537) 11 x + x + 1 Working with expressions as polynomials --------------------------------------- Consider a multivariate polynomial ``f`` in `\mathbb{Z}[x,y,z]`:: >>> f = expand((x - 2*y**2 + 3*z**3)**20) We want to compute factorization of ``f``. To do this we use ``factor`` as usually, however we note that the polynomial in consideration is already in expanded form, so we can tell the factorization routine to skip expanding ``f``:: >>> factor(f, expand=False) 20 ⎛ 2 3⎞ ⎝x - 2⋅y + 3⋅z ⎠ The default in :mod:`sympy.polys` is to expand all expressions given as arguments to polynomial manipulation functions and :class:`~.Poly` class. If we know that expanding is unnecessary, then by setting ``expand=False`` we can save quite a lot of time for complicated inputs. This can be really important when computing with expressions like:: >>> g = expand((sin(x) - 2*cos(y)**2 + 3*tan(z)**3)**20) >>> factor(g, expand=False) 20 ⎛ 2 3 ⎞ ⎝-sin(x) + 2⋅cos (y) - 3⋅tan (z)⎠ Computing reduced Gröbner bases ------------------------------- To compute a reduced Gröbner basis for a set of polynomials use the :func:`~sympy.polys.polytools.groebner` function. The function accepts various monomial orderings, e.g.: ``lex``, ``grlex`` and ``grevlex``, or a user defined one, via ``order`` keyword. The ``lex`` ordering is the most interesting because it has elimination property, which means that if the system of polynomial equations to :func:`~sympy.polys.polytools.groebner` is zero-dimensional (has finite number of solutions) the last element of the basis is a univariate polynomial. Consider the following example:: >>> f = expand((1 - c**2)**5 * (1 - s**2)**5 * (c**2 + s**2)**10) >>> groebner([f, c**2 + s**2 - 1]) ⎛⎡ 2 2 20 18 16 14 12 10⎤ ⎞ GroebnerBasis⎝⎣c + s - 1, c - 5⋅c + 10⋅c - 10⋅c + 5⋅c - c ⎦, s, c, domain=ℤ, order=lex⎠ The result is an ordinary Python list, so we can easily apply a function to all its elements, for example we can factor those elements:: >>> list(map(factor, _)) ⎡ 2 2 10 5 5⎤ ⎣c + s - 1, c ⋅(c - 1) ⋅(c + 1) ⎦ From the above we can easily find all solutions of the system of polynomial equations. Or we can use :func:`~.solve` to achieve this in a more systematic way:: >>> solve([f, s**2 + c**2 - 1], c, s) [(-1, 0), (0, -1), (0, 1), (1, 0)] Multivariate factoring over algebraic numbers --------------------------------------------- Computing with multivariate polynomials over various domains is as simple as in univariate case. For example consider the following factorization over `\mathbb{Q}(\sqrt{-3})`:: >>> factor(x**3 + y**3, extension=sqrt(-3)) ⎛ ⎛ 1 √3⋅ⅈ⎞⎞ ⎛ ⎛ 1 √3⋅ⅈ⎞⎞ (x + y)⋅⎜x + y⋅⎜- ─ - ────⎟⎟⋅⎜x + y⋅⎜- ─ + ────⎟⎟ ⎝ ⎝ 2 2 ⎠⎠ ⎝ ⎝ 2 2 ⎠⎠ .. note:: Currently multivariate polynomials over finite fields aren't supported. Partial fraction decomposition ------------------------------ Consider a univariate rational function ``f`` with integer coefficients:: >>> f = (x**2 + 2*x + 3)/(x**3 + 4*x**2 + 5*x + 2) To decompose ``f`` into partial fractions use :func:`~.apart` function:: >>> apart(f) 3 2 2 ───── - ───── + ──────── x + 2 x + 1 2 (x + 1) To return from partial fractions to the rational function use a composition of :func:`~.together` and :func:`~.cancel`:: >>> cancel(together(_)) 2 x + 2⋅x + 3 ─────────────────── 3 2 x + 4⋅x + 5⋅x + 2 Literature ========== .. [Wester1999] Michael J. Wester, A Critique of the Mathematical Abilities of CA Systems, 1999, ``_ sympy-sympy-1.9/doc/src/modules/printing.rst000066400000000000000000000421761412543434000213250ustar00rootroot00000000000000======== Printing ======== See the :ref:`tutorial-printing` section in tutorial for introduction into printing. This guide documents the printing system in SymPy and how it works internally. Printer Class ------------- .. automodule:: sympy.printing.printer The main class responsible for printing is ``Printer`` (see also its `source code `_): .. autoclass:: Printer :members: doprint, _print, set_global_settings, order .. autoattribute:: Printer.printmethod PrettyPrinter Class ------------------- The pretty printing subsystem is implemented in ``sympy.printing.pretty.pretty`` by the ``PrettyPrinter`` class deriving from ``Printer``. It relies on the modules ``sympy.printing.pretty.stringPict``, and ``sympy.printing.pretty.pretty_symbology`` for rendering nice-looking formulas. The module ``stringPict`` provides a base class ``stringPict`` and a derived class ``prettyForm`` that ease the creation and manipulation of formulas that span across multiple lines. The module ``pretty_symbology`` provides primitives to construct 2D shapes (hline, vline, etc) together with a technique to use unicode automatically when possible. .. module:: sympy.printing.pretty .. module:: sympy.printing.pretty.pretty .. autoclass:: PrettyPrinter :members: _use_unicode, doprint .. autoattribute:: PrettyPrinter.printmethod .. autofunction:: pretty .. autofunction:: pretty_print C code printers --------------- .. module:: sympy.printing.c This class implements C code printing, i.e. it converts Python expressions to strings of C code (see also ``C89CodePrinter``). Usage:: >>> from sympy.printing import print_ccode >>> from sympy.functions import sin, cos, Abs, gamma >>> from sympy.abc import x >>> print_ccode(sin(x)**2 + cos(x)**2, standard='C89') pow(sin(x), 2) + pow(cos(x), 2) >>> print_ccode(2*x + cos(x), assign_to="result", standard='C89') result = 2*x + cos(x); >>> print_ccode(Abs(x**2), standard='C89') fabs(pow(x, 2)) >>> print_ccode(gamma(x**2), standard='C99') tgamma(pow(x, 2)) .. autodata:: sympy.printing.c::known_functions_C89 .. autodata:: sympy.printing.c::known_functions_C99 .. autoclass:: sympy.printing.c::C89CodePrinter :members: .. autoattribute:: C89CodePrinter.printmethod .. autoclass:: sympy.printing.c::C99CodePrinter :members: .. autoattribute:: C99CodePrinter.printmethod .. autofunction:: sympy.printing.c::ccode .. autofunction:: sympy.printing.c::print_ccode C++ code printers ----------------- .. module:: sympy.printing.cxx This module contains printers for C++ code, i.e. functions to convert SymPy expressions to strings of C++ code. Usage:: >>> from sympy.printing import cxxcode >>> from sympy.functions import Min, gamma >>> from sympy.abc import x >>> print(cxxcode(Min(gamma(x) - 1, x), standard='C++11')) std::min(x, std::tgamma(x) - 1) .. autoclass:: sympy.printing.cxx::CXX98CodePrinter :members: .. autoattribute:: CXX98CodePrinter.printmethod .. autoclass:: sympy.printing.cxx::CXX11CodePrinter :members: .. autoattribute:: CXX11CodePrinter.printmethod .. autofunction:: sympy.printing.codeprinter::cxxcode RCodePrinter ------------ .. module:: sympy.printing.rcode This class implements R code printing (i.e. it converts Python expressions to strings of R code). Usage:: >>> from sympy.printing import print_rcode >>> from sympy.functions import sin, cos, Abs >>> from sympy.abc import x >>> print_rcode(sin(x)**2 + cos(x)**2) sin(x)^2 + cos(x)^2 >>> print_rcode(2*x + cos(x), assign_to="result") result = 2*x + cos(x); >>> print_rcode(Abs(x**2)) abs(x^2) .. autodata:: sympy.printing.rcode::known_functions .. autoclass:: sympy.printing.rcode::RCodePrinter :members: .. autoattribute:: RCodePrinter.printmethod .. autofunction:: sympy.printing.rcode::rcode .. autofunction:: sympy.printing.rcode::print_rcode Fortran Printing ---------------- The ``fcode`` function translates a sympy expression into Fortran code. The main purpose is to take away the burden of manually translating long mathematical expressions. Therefore the resulting expression should also require no (or very little) manual tweaking to make it compilable. The optional arguments of ``fcode`` can be used to fine-tune the behavior of ``fcode`` in such a way that manual changes in the result are no longer needed. .. module:: sympy.printing.fortran .. autofunction:: fcode .. autofunction:: print_fcode .. autoclass:: FCodePrinter :members: .. autoattribute:: FCodePrinter.printmethod Two basic examples: >>> from sympy import * >>> x = symbols("x") >>> fcode(sqrt(1-x**2)) ' sqrt(1 - x**2)' >>> fcode((3 + 4*I)/(1 - conjugate(x))) ' (cmplx(3,4))/(1 - conjg(x))' An example where line wrapping is required: >>> expr = sqrt(1-x**2).series(x,n=20).removeO() >>> print(fcode(expr)) -715.0d0/65536.0d0*x**18 - 429.0d0/32768.0d0*x**16 - 33.0d0/ @ 2048.0d0*x**14 - 21.0d0/1024.0d0*x**12 - 7.0d0/256.0d0*x**10 - @ 5.0d0/128.0d0*x**8 - 1.0d0/16.0d0*x**6 - 1.0d0/8.0d0*x**4 - 1.0d0 @ /2.0d0*x**2 + 1 In case of line wrapping, it is handy to include the assignment so that lines are wrapped properly when the assignment part is added. >>> print(fcode(expr, assign_to="var")) var = -715.0d0/65536.0d0*x**18 - 429.0d0/32768.0d0*x**16 - 33.0d0/ @ 2048.0d0*x**14 - 21.0d0/1024.0d0*x**12 - 7.0d0/256.0d0*x**10 - @ 5.0d0/128.0d0*x**8 - 1.0d0/16.0d0*x**6 - 1.0d0/8.0d0*x**4 - 1.0d0 @ /2.0d0*x**2 + 1 For piecewise functions, the ``assign_to`` option is mandatory: >>> print(fcode(Piecewise((x,x<1),(x**2,True)), assign_to="var")) if (x < 1) then var = x else var = x**2 end if Note that by default only top-level piecewise functions are supported due to the lack of a conditional operator in Fortran 77. Inline conditionals can be supported using the ``merge`` function introduced in Fortran 95 by setting of the kwarg ``standard=95``: >>> print(fcode(Piecewise((x,x<1),(x**2,True)), standard=95)) merge(x, x**2, x < 1) Loops are generated if there are Indexed objects in the expression. This also requires use of the assign_to option. >>> A, B = map(IndexedBase, ['A', 'B']) >>> m = Symbol('m', integer=True) >>> i = Idx('i', m) >>> print(fcode(2*B[i], assign_to=A[i])) do i = 1, m A(i) = 2*B(i) end do Repeated indices in an expression with Indexed objects are interpreted as summation. For instance, code for the trace of a matrix can be generated with >>> print(fcode(A[i, i], assign_to=x)) x = 0 do i = 1, m x = x + A(i, i) end do By default, number symbols such as ``pi`` and ``E`` are detected and defined as Fortran parameters. The precision of the constants can be tuned with the precision argument. Parameter definitions are easily avoided using the ``N`` function. >>> print(fcode(x - pi**2 - E)) parameter (E = 2.7182818284590452d0) parameter (pi = 3.1415926535897932d0) x - pi**2 - E >>> print(fcode(x - pi**2 - E, precision=25)) parameter (E = 2.718281828459045235360287d0) parameter (pi = 3.141592653589793238462643d0) x - pi**2 - E >>> print(fcode(N(x - pi**2, 25))) x - 9.869604401089358618834491d0 When some functions are not part of the Fortran standard, it might be desirable to introduce the names of user-defined functions in the Fortran expression. >>> print(fcode(1 - gamma(x)**2, user_functions={'gamma': 'mygamma'})) 1 - mygamma(x)**2 However, when the user_functions argument is not provided, ``fcode`` will generate code which assumes that a function of the same name will be provided by the user. A comment will be added to inform the user of the issue: >>> print(fcode(1 - gamma(x)**2)) C Not supported in Fortran: C gamma 1 - gamma(x)**2 The printer can be configured to omit these comments: >>> print(fcode(1 - gamma(x)**2, allow_unknown_functions=True)) 1 - gamma(x)**2 By default the output is human readable code, ready for copy and paste. With the option ``human=False``, the return value is suitable for post-processing with source code generators that write routines with multiple instructions. The return value is a three-tuple containing: (i) a set of number symbols that must be defined as 'Fortran parameters', (ii) a list functions that cannot be translated in pure Fortran and (iii) a string of Fortran code. A few examples: >>> fcode(1 - gamma(x)**2, human=False) (set(), {gamma(x)}, ' 1 - gamma(x)**2') >>> fcode(1 - sin(x)**2, human=False) (set(), set(), ' 1 - sin(x)**2') >>> fcode(x - pi**2, human=False) ({(pi, '3.1415926535897932d0')}, set(), ' x - pi**2') Mathematica code printing ------------------------- .. module:: sympy.printing.mathematica .. autodata:: sympy.printing.mathematica.known_functions .. autoclass:: sympy.printing.mathematica.MCodePrinter :members: .. autoattribute:: MCodePrinter.printmethod .. autofunction:: sympy.printing.mathematica.mathematica_code Maple code printing ------------------- .. module:: sympy.printing.maple .. autoclass:: sympy.printing.maple.MapleCodePrinter :members: .. autoattribute:: MapleCodePrinter.printmethod .. autofunction:: sympy.printing.maple.maple_code .. autofunction:: sympy.printing.maple.print_maple_code Javascript Code printing ------------------------ .. module:: sympy.printing.jscode .. autodata:: sympy.printing.jscode::known_functions .. autoclass:: sympy.printing.jscode::JavascriptCodePrinter :members: .. autoattribute:: JavascriptCodePrinter.printmethod .. autofunction:: sympy.printing.jscode::jscode Julia code printing --------------------------------- .. module:: sympy.printing.julia .. autodata:: sympy.printing.julia.known_fcns_src1 .. autodata:: sympy.printing.julia.known_fcns_src2 .. autoclass:: sympy.printing.julia.JuliaCodePrinter :members: .. autoattribute:: JuliaCodePrinter.printmethod .. autofunction:: sympy.printing.julia.julia_code Octave (and Matlab) Code printing --------------------------------- .. module:: sympy.printing.octave .. autodata:: sympy.printing.octave.known_fcns_src1 .. autodata:: sympy.printing.octave.known_fcns_src2 .. autoclass:: sympy.printing.octave.OctaveCodePrinter :members: .. autoattribute:: OctaveCodePrinter.printmethod .. autofunction:: sympy.printing.octave.octave_code Rust code printing ------------------ .. module:: sympy.printing.rust .. autodata:: sympy.printing.rust.known_functions .. autoclass:: sympy.printing.rust.RustCodePrinter :members: .. autoattribute:: RustCodePrinter.printmethod .. autofunction:: sympy.printing.rust.rust_code Aesara Code printing -------------------- .. module:: sympy.printing.aesaracode .. autoclass:: sympy.printing.aesaracode.AesaraPrinter :members: .. autoattribute:: AesaraPrinter.printmethod .. autofunction:: sympy.printing.aesaracode.aesara_code .. autofunction:: sympy.printing.aesaracode.aesara_function .. autofunction:: sympy.printing.aesaracode.dim_handling Gtk --- .. module:: sympy.printing.gtk You can print to a gtkmathview widget using the function ``print_gtk`` located in ``sympy.printing.gtk`` (it requires to have installed gtkmathview and libgtkmathview-bin in some systems). GtkMathView accepts MathML, so this rendering depends on the MathML representation of the expression. Usage:: from sympy import * print_gtk(x**2 + 2*exp(x**3)) .. autofunction:: print_gtk LambdaPrinter ------------- .. module:: sympy.printing.lambdarepr This classes implements printing to strings that can be used by the :py:func:`sympy.utilities.lambdify.lambdify` function. .. autoclass:: LambdaPrinter :members: .. autoattribute:: LambdaPrinter.printmethod .. autofunction:: lambdarepr LatexPrinter ------------ .. module:: sympy.printing.latex This class implements LaTeX printing. See ``sympy.printing.latex``. .. autodata:: accepted_latex_functions .. autoclass:: LatexPrinter :members: .. autoattribute:: LatexPrinter.printmethod .. autofunction:: latex .. autofunction:: print_latex MathMLPrinter ------------- .. module:: sympy.printing.mathml This class is responsible for MathML printing. See ``sympy.printing.mathml``. More info on mathml : http://www.w3.org/TR/MathML2 .. autoclass:: MathMLPrinterBase :members: .. autoclass:: MathMLContentPrinter :members: .. autoattribute:: MathMLContentPrinter.printmethod .. autoclass:: MathMLPresentationPrinter :members: .. autoattribute:: MathMLPresentationPrinter.printmethod .. autofunction:: mathml .. autofunction:: print_mathml PythonCodePrinter ----------------- .. automodule:: sympy.printing.pycode :members: PythonPrinter ------------- .. module:: sympy.printing.python This class implements Python printing. Usage:: >>> from sympy import print_python, sin >>> from sympy.abc import x >>> print_python(5*x**3 + sin(x)) x = Symbol('x') e = 5*x**3 + sin(x) srepr ----- .. module:: sympy.printing.repr This printer generates executable code. This code satisfies the identity ``eval(srepr(expr)) == expr``. ``srepr()`` gives more low level textual output than ``repr()`` Example:: >>> repr(5*x**3 + sin(x)) '5*x**3 + sin(x)' >>> srepr(5*x**3 + sin(x)) "Add(Mul(Integer(5), Pow(Symbol('x'), Integer(3))), sin(Symbol('x')))" ``srepr()`` gives the ``repr`` form, which is what ``repr()`` would normally give but for SymPy we don’t actually use ``srepr()`` for ``__repr__`` because it’s is so verbose, it is unlikely that anyone would want it called by default. Another reason is that lists call repr on their elements, like ``print([a, b, c])`` calls ``repr(a)``, ``repr(b)``, ``repr(c)``. So if we used srepr for `` __repr__`` any list with SymPy objects would include the srepr form, even if we used ``str()`` or ``print()``. .. autoclass:: ReprPrinter :members: .. autoattribute:: ReprPrinter.printmethod .. autofunction:: srepr StrPrinter ---------- .. module:: sympy.printing.str This module generates readable representations of SymPy expressions. .. autoclass:: StrPrinter :members: parenthesize, stringify, emptyPrinter .. autoattribute:: StrPrinter.printmethod .. autofunction:: sstr .. autofunction:: sstrrepr Tree Printing ------------- .. module:: sympy.printing.tree The functions in this module create a representation of an expression as a tree. .. autofunction:: pprint_nodes .. autofunction:: print_node .. autofunction:: tree .. autofunction:: print_tree Preview ------- A useful function is ``preview``: .. module:: sympy.printing.preview .. autofunction:: preview Implementation - Helper Classes/Functions ----------------------------------------- .. module:: sympy.printing.conventions .. autofunction:: split_super_sub CodePrinter +++++++++++ .. module:: sympy.printing.codeprinter This class is a base class for other classes that implement code-printing functionality, and additionally lists a number of functions that cannot be easily translated to C or Fortran. .. autoclass:: sympy.printing.codeprinter.CodePrinter :members: .. autoattribute:: CodePrinter.printmethod .. autoexception:: sympy.printing.codeprinter.AssignmentError Precedence ++++++++++ .. module:: sympy.printing.precedence .. autodata:: PRECEDENCE Default precedence values for some basic types. .. autodata:: PRECEDENCE_VALUES A dictionary assigning precedence values to certain classes. These values are treated like they were inherited, so not every single class has to be named here. .. autodata:: PRECEDENCE_FUNCTIONS Sometimes it's not enough to assign a fixed precedence value to a class. Then a function can be inserted in this dictionary that takes an instance of this class as argument and returns the appropriate precedence value. .. autofunction:: precedence Pretty-Printing Implementation Helpers -------------------------------------- .. module:: sympy.printing.pretty.pretty_symbology .. autofunction:: U .. autofunction:: pretty_use_unicode .. autofunction:: pretty_try_use_unicode .. autofunction:: xstr The following two functions return the Unicode version of the inputted Greek letter. .. autofunction:: g .. autofunction:: G .. autodata:: greek_letters .. autodata:: digit_2txt .. autodata:: symb_2txt The following functions return the Unicode subscript/superscript version of the character. .. autodata:: sub .. autodata:: sup The following functions return Unicode vertical objects. .. autofunction:: xobj .. autofunction:: vobj .. autofunction:: hobj The following constants are for rendering roots and fractions. .. autodata:: root .. autofunction:: VF .. autodata:: frac The following constants/functions are for rendering atoms and symbols. .. autofunction:: xsym .. autodata:: atoms_table .. autofunction:: pretty_atom .. autofunction:: pretty_symbol .. autofunction:: annotated .. automodule:: sympy.printing.pretty.stringpict .. autoclass:: stringPict :members: .. autoclass:: prettyForm :members: dotprint -------- .. autofunction:: sympy.printing.dot.dotprint sympy-sympy-1.9/doc/src/modules/rewriting.rst000066400000000000000000000105531412543434000214770ustar00rootroot00000000000000============== Term Rewriting ============== Term rewriting is a very general class of functionalities which are used to convert expressions of one type in terms of expressions of different kind. For example expanding, combining and converting expressions apply to term rewriting, and also simplification routines can be included here. Currently SymPy has several functions and basic built-in methods for performing various types of rewriting. Expanding --------- The simplest rewrite rule is expanding expressions into a _sparse_ form. Expanding has several flavors and include expanding complex valued expressions, arithmetic expand of products and powers but also expanding functions in terms of more general functions is possible. Below are listed all currently available expand rules. Expanding of arithmetic expressions involving products and powers: >>> from sympy import * >>> x, y, z = symbols('x,y,z') >>> ((x + y)*(x - y)).expand(basic=True) x**2 - y**2 >>> ((x + y + z)**2).expand(basic=True) x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2 Arithmetic expand is done by default in ``expand()`` so the keyword ``basic`` can be omitted. However you can set ``basic=False`` to avoid this type of expand if you use rules described below. This give complete control on what is done with the expression. Another type of expand rule is expanding complex valued expressions and putting them into a normal form. For this ``complex`` keyword is used. Note that it will always perform arithmetic expand to obtain the desired normal form: >>> (x + I*y).expand(complex=True) re(x) + I*re(y) + I*im(x) - im(y) >>> sin(x + I*y).expand(complex=True) sin(re(x) - im(y))*cosh(re(y) + im(x)) + I*cos(re(x) - im(y))*sinh(re(y) + im(x)) Note also that the same behavior can be obtained by using ``as_real_imag()`` method. However it will return a tuple containing the real part in the first place and the imaginary part in the other. This can be also done in a two step process by using ``collect`` function: >>> (x + I*y).as_real_imag() (re(x) - im(y), re(y) + im(x)) >>> collect((x + I*y).expand(complex=True), I, evaluate=False) {1: re(x) - im(y), I: re(y) + im(x)} There is also possibility for expanding expressions in terms of expressions of different kind. This is very general type of expanding and usually you would use ``rewrite()`` to do specific type of rewrite:: >>> GoldenRatio.expand(func=True) 1/2 + sqrt(5)/2 Common Subexpression Detection and Collection --------------------------------------------- .. currentmodule:: sympy.simplify.cse_main Before evaluating a large expression, it is often useful to identify common subexpressions, collect them and evaluate them at once. This is implemented in the ``cse`` function. Examples:: >>> from sympy import cse, sqrt, sin, pprint >>> from sympy.abc import x >>> pprint(cse(sqrt(sin(x))), use_unicode=True) ⎛ ⎡ ________⎤⎞ ⎝[], ⎣╲╱ sin(x) ⎦⎠ >>> pprint(cse(sqrt(sin(x)+5)*sqrt(sin(x)+4)), use_unicode=True) ⎛ ⎡ ________ ________⎤⎞ ⎝[(x₀, sin(x))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠ >>> pprint(cse(sqrt(sin(x+1) + 5 + cos(y))*sqrt(sin(x+1) + 4 + cos(y))), ... use_unicode=True) ⎛ ⎡ ________ ________⎤⎞ ⎝[(x₀, sin(x + 1) + cos(y))], ⎣╲╱ x₀ + 4 ⋅╲╱ x₀ + 5 ⎦⎠ >>> pprint(cse((x-y)*(z-y) + sqrt((x-y)*(z-y))), use_unicode=True) ⎛ ⎡ ____ ⎤⎞ ⎝[(x₀, -y), (x₁, (x + x₀)⋅(x₀ + z))], ⎣╲╱ x₁ + x₁⎦⎠ Optimizations to be performed before and after common subexpressions elimination can be passed in the``optimizations`` optional argument. A set of predefined basic optimizations can be applied by passing ``optimizations='basic'``:: >>> pprint(cse((x-y)*(z-y) + sqrt((x-y)*(z-y)), optimizations='basic'), ... use_unicode=True) ⎛ ⎡ ____ ⎤⎞ ⎝[(x₀, -(x - y)⋅(y - z))], ⎣╲╱ x₀ + x₀⎦⎠ However, these optimizations can be very slow for large expressions. Moreover, if speed is a concern, one can pass the option ``order='none'``. Order of terms will then be dependent on hashing algorithm implementation, but speed will be greatly improved. More information: .. autofunction:: cse :noindex: sympy-sympy-1.9/doc/src/modules/series/000077500000000000000000000000001412543434000202215ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/series/formal.rst000066400000000000000000000020771412543434000222410ustar00rootroot00000000000000Formal Power Series =================== Methods for computing and manipulating Formal Power Series. .. autoclass:: sympy.series.formal::FormalPowerSeries :members: .. autofunction:: sympy.series.formal::fps .. autofunction:: sympy.series.formal::compute_fps .. autoclass:: sympy.series.formal::FormalPowerSeriesCompose :members: .. autoclass:: sympy.series.formal::FormalPowerSeriesInverse :members: .. autoclass:: sympy.series.formal::FormalPowerSeriesProduct :members: .. autoclass:: sympy.series.formal::FiniteFormalPowerSeries :members: Rational Algorithm ------------------ .. autofunction:: sympy.series.formal::rational_independent .. autofunction:: sympy.series.formal::rational_algorithm Hypergeometric Algorithm ------------------------ .. autofunction:: sympy.series.formal::simpleDE .. autofunction:: sympy.series.formal::exp_re .. autofunction:: sympy.series.formal::hyper_re .. autofunction:: sympy.series.formal::rsolve_hypergeometric .. autofunction:: sympy.series.formal::solve_de .. autofunction:: sympy.series.formal::hyper_algorithm sympy-sympy-1.9/doc/src/modules/series/fourier.rst000066400000000000000000000003041412543434000224230ustar00rootroot00000000000000Fourier Series ============== Provides methods to compute Fourier series. .. autoclass:: sympy.series.fourier::FourierSeries :members: .. autofunction:: sympy.series.fourier::fourier_series sympy-sympy-1.9/doc/src/modules/series/index.rst000066400000000000000000000004051412543434000220610ustar00rootroot00000000000000.. _series-docs: ====== Series ====== The series module implements series expansions as a function and many related functions. Contents ======== .. toctree:: :maxdepth: 2 series.rst sequences.rst fourier.rst formal.rst limitseq.rst sympy-sympy-1.9/doc/src/modules/series/limitseq.rst000066400000000000000000000004241412543434000226020ustar00rootroot00000000000000Limits of Sequences =================== Provides methods to compute limit of terms having sequences at infinity. .. autofunction:: sympy.series.limitseq::difference_delta .. autofunction:: sympy.series.limitseq::dominant .. autofunction:: sympy.series.limitseq::limit_seq sympy-sympy-1.9/doc/src/modules/series/sequences.rst000066400000000000000000000012251412543434000227460ustar00rootroot00000000000000Sequences ========= A sequence is a finite or infinite lazily evaluated list. .. autofunction:: sympy.series.sequences::sequence Sequences Base --------------- .. autoclass:: sympy.series.sequences::SeqBase :members: Elementary Sequences -------------------- .. autoclass:: sympy.series.sequences::SeqFormula :members: .. autoclass:: sympy.series.sequences::SeqPer :members: Singleton Sequences -------------------- .. autoclass:: sympy.series.sequences::EmptySequence :members: Compound Sequences -------------------- .. autoclass:: sympy.series.sequences::SeqAdd :members: .. autoclass:: sympy.series.sequences::SeqMul :members: sympy-sympy-1.9/doc/src/modules/series/series.rst000066400000000000000000000123161412543434000222500ustar00rootroot00000000000000.. _series_expansions: Series Expansions ================= Limits ------ The main purpose of this module is the computation of limits. .. autofunction:: sympy.series.limits::limit .. autoclass:: sympy.series.limits::Limit :members: As is explained above, the workhorse for limit computations is the function gruntz() which implements Gruntz' algorithm for computing limits. The Gruntz Algorithm ^^^^^^^^^^^^^^^^^^^^ This section explains the basics of the algorithm used for computing limits. Most of the time the limit() function should just work. However it is still useful to keep in mind how it is implemented in case something does not work as expected. First we define an ordering on functions. Suppose `f(x)` and `g(x)` are two real-valued functions such that `\lim_{x \to \infty} f(x) = \infty` and similarly `\lim_{x \to \infty} g(x) = \infty`. We shall say that `f(x)` *dominates* `g(x)`, written `f(x) \succ g(x)`, if for all `a, b \in \mathbb{R}_{>0}` we have `\lim_{x \to \infty} \frac{f(x)^a}{g(x)^b} = \infty`. We also say that `f(x)` and `g(x)` are *of the same comparability class* if neither `f(x) \succ g(x)` nor `g(x) \succ f(x)` and shall denote it as `f(x) \asymp g(x)`. Note that whenever `a, b \in \mathbb{R}_{>0}` then `a f(x)^b \asymp f(x)`, and we shall use this to extend the definition of `\succ` to all functions which tend to `0` or `\pm \infty` as `x \to \infty`. Thus we declare that `f(x) \asymp 1/f(x)` and `f(x) \asymp -f(x)`. It is easy to show the following examples: * `e^x \succ x^m` * `e^{x^2} \succ e^{mx}` * `e^{e^x} \succ e^{x^m}` * `x^m \asymp x^n` * `e^{x + \frac{1}{x}} \asymp e^{x + \log{x}} \asymp e^x`. From the above definition, it is possible to prove the following property: Suppose `\omega`, `g_1, g_2, \ldots` are functions of `x`, `\lim_{x \to \infty} \omega = 0` and `\omega \succ g_i` for all `i`. Let `c_1, c_2, \ldots \in \mathbb{R}` with `c_1 < c_2 < \cdots`. Then `\lim_{x \to \infty} \sum_i g_i \omega^{c_i} = \lim_{x \to \infty} g_1 \omega^{c_1}`. For `g_1 = g` and `\omega` as above we also have the following easy result: * `\lim_{x \to \infty} g \omega^c = 0` for `c > 0` * `\lim_{x \to \infty} g \omega^c = \pm \infty` for `c < 0`, where the sign is determined by the (eventual) sign of `g` * `\lim_{x \to \infty} g \omega^0 = \lim_{x \to \infty} g`. Using these results yields the following strategy for computing `\lim_{x \to \infty} f(x)`: 1. Find the set of *most rapidly varying subexpressions* (MRV set) of `f(x)`. That is, from the set of all subexpressions of `f(x)`, find the elements that are maximal under the relation `\succ`. 2. Choose a function `\omega` that is in the same comparability class as the elements in the MRV set, such that `\lim_{x \to \infty} \omega = 0`. 3. Expand `f(x)` as a series in `\omega` in such a way that the antecedents of the above theorem are satisfied. 4. Apply the theorem and conclude the computation of `\lim_{x \to \infty} f(x)`, possibly by recursively working on `g_1(x)`. Notes """"" This exposition glossed over several details. Many are described in the file gruntz.py, and all can be found in Gruntz' very readable thesis. The most important points that have not been explained are: 1. Given f(x) and g(x), how do we determine if `f(x) \succ g(x)`, `g(x) \succ f(x)` or `g(x) \asymp f(x)`? 2. How do we find the MRV set of an expression? 3. How do we compute series expansions? 4. Why does the algorithm terminate? If you are interested, be sure to take a look at `Gruntz Thesis `_. Reference """"""""" .. autofunction:: sympy.series.gruntz::gruntz .. autofunction:: sympy.series.gruntz::compare .. autofunction:: sympy.series.gruntz::rewrite .. autofunction:: sympy.series.gruntz::build_expression_tree .. autofunction:: sympy.series.gruntz::mrv_leadterm .. autofunction:: sympy.series.gruntz::calculate_series .. autofunction:: sympy.series.gruntz::limitinf .. autofunction:: sympy.series.gruntz::sign .. autofunction:: sympy.series.gruntz::mrv .. autofunction:: sympy.series.gruntz::mrv_max1 .. autofunction:: sympy.series.gruntz::mrv_max3 .. autoclass:: sympy.series.gruntz::SubsSet :members: More Intuitive Series Expansion ------------------------------- This is achieved by creating a wrapper around Basic.series(). This allows for the use of series(x*cos(x),x), which is possibly more intuitive than (x*cos(x)).series(x). Examples ^^^^^^^^ >>> from sympy import Symbol, cos, series >>> x = Symbol('x') >>> series(cos(x),x) 1 - x**2/2 + x**4/24 + O(x**6) Reference ^^^^^^^^^ .. autofunction:: sympy.series.series::series Order Terms ----------- This module also implements automatic keeping track of the order of your expansion. Examples ^^^^^^^^ >>> from sympy import Symbol, Order >>> x = Symbol('x') >>> Order(x) + x**2 O(x) >>> Order(x) + 1 1 + O(x) Reference ^^^^^^^^^ .. autoclass:: sympy.series.order::Order :members: Series Acceleration ------------------- TODO Reference ^^^^^^^^^ .. autofunction:: sympy.series.acceleration::richardson .. autofunction:: sympy.series.acceleration::shanks Residues -------- TODO Reference ^^^^^^^^^ .. autofunction:: sympy.series.residues::residue sympy-sympy-1.9/doc/src/modules/sets.rst000066400000000000000000000056621412543434000204500ustar00rootroot00000000000000==== Sets ==== Basic Sets ---------- .. automodule:: sympy.sets.sets Set ^^^ .. autoclass:: Set :members: .. autofunction:: imageset Elementary Sets --------------- Interval ^^^^^^^^ .. autoclass:: Interval :members: FiniteSet ^^^^^^^^^ .. autoclass:: FiniteSet :members: Compound Sets ------------- .. module:: sympy.sets.sets :noindex: Union ^^^^^ .. autoclass:: Union :members: Intersection ^^^^^^^^^^^^ .. autoclass:: Intersection :members: ProductSet ^^^^^^^^^^ .. autoclass:: ProductSet :members: Complement ^^^^^^^^^^ .. autoclass:: Complement :members: SymmetricDifference ^^^^^^^^^^^^^^^^^^^ .. autoclass:: SymmetricDifference :members: Singleton Sets -------------- EmptySet ^^^^^^^^ .. autoclass:: EmptySet :members: UniversalSet ^^^^^^^^^^^^ .. autoclass:: UniversalSet :members: Special Sets ------------ .. automodule:: sympy.sets.fancysets Naturals ^^^^^^^^ .. autoclass:: Naturals :members: Naturals0 ^^^^^^^^^ .. autoclass:: Naturals0 :members: Integers ^^^^^^^^ .. autoclass:: Integers :members: Reals ^^^^^ .. autoclass:: Reals :members: Complexes ^^^^^^^^^ .. autoclass:: Complexes :members: ImageSet ^^^^^^^^ .. autoclass:: ImageSet :members: Range ^^^^^ .. autoclass:: Range :members: ComplexRegion ^^^^^^^^^^^^^ .. autoclass:: ComplexRegion :members: .. autoclass:: CartesianComplexRegion :members: .. autoclass:: PolarComplexRegion :members: .. autofunction:: normalize_theta_set Power sets ---------- .. automodule:: sympy.sets.powerset PowerSet ^^^^^^^^ .. autoclass:: PowerSet :members: Iteration over sets ^^^^^^^^^^^^^^^^^^^ For set unions, `\{a, b\} \cup \{x, y\}` can be treated as `\{a, b, x, y\}` for iteration regardless of the distinctiveness of the elements, however, for set intersections, assuming that `\{a, b\} \cap \{x, y\}` is `\varnothing` or `\{a, b \}` would not always be valid, since some of `a`, `b`, `x` or `y` may or may not be the elements of the intersection. Iterating over the elements of a set involving intersection, complement, or symmetric difference yields (possibly duplicate) elements of the set provided that all elements are known to be the elements of the set. If any element cannot be determined to be a member of a set then the iteration gives ``TypeError``. This happens in the same cases where ``x in y`` would give an error. There are some reasons to implement like this, even if it breaks the consistency with how the python set iterator works. We keep in mind that sympy set comprehension like ``FiniteSet(*s)`` from a existing sympy sets could be a common usage. And this approach would make ``FiniteSet(*s)`` to be consistent with any symbolic set processing methods like ``FiniteSet(*simplify(s))``. Condition Sets -------------- .. automodule:: sympy.sets.conditionset ConditionSet ^^^^^^^^^^^^ .. autoclass:: ConditionSet :members: Relations on sets ^^^^^^^^^^^^^^^^^ .. autoclass:: Contains :members: sympy-sympy-1.9/doc/src/modules/simplify/000077500000000000000000000000001412543434000205635ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/simplify/fu.rst000066400000000000000000000202761412543434000217360ustar00rootroot00000000000000=========================================== Hongguang Fu's Trigonometric Simplification =========================================== .. currentmodule:: sympy.simplify.fu Implementation of the trigsimp algorithm by Fu et al. The idea behind the Fu algorithm is to use a sequence of rules that students learn during their pre-calculus courses. The rules are applied heuristically and it uses a greedy algorithm to apply multiple rules simultaneously and choose the result with the least leaf counts. There are transform rules in which a single rule is applied to the expression tree. The following are just mnemonic in nature; see the docstrings for examples. - :func:`TR0` - simplify expression - :func:`TR1` - sec-csc to cos-sin - :func:`TR2` - tan-cot to sin-cos ratio - :func:`TR2i` - sin-cos ratio to tan - :func:`TR3` - angle canonicalization - :func:`TR4` - functions at special angles - :func:`TR5` - powers of sin to powers of cos - :func:`TR6` - powers of cos to powers of sin - :func:`TR7` - reduce cos power (increase angle) - :func:`TR8` - expand products of sin-cos to sums - :func:`TR9` - contract sums of sin-cos to products - :func:`TR10` - separate sin-cos arguments - :func:`TR10i` - collect sin-cos arguments - :func:`TR11` - reduce double angles - :func:`TR12` - separate tan arguments - :func:`TR12i` - collect tan arguments - :func:`TR13` - expand product of tan-cot - :func:`TRmorrie` - prod(cos(x*2**i), (i, 0, k - 1)) -> sin(2**k*x)/(2**k*sin(x)) - :func:`TR14` - factored powers of sin or cos to cos or sin power - :func:`TR15` - negative powers of sin to cot power - :func:`TR16` - negative powers of cos to tan power - :func:`TR22` - tan-cot powers to negative powers of sec-csc functions - :func:`TR111` - negative sin-cos-tan powers to csc-sec-cot There are 4 combination transforms (CTR1 - CTR4) in which a sequence of transformations are applied and the simplest expression is selected from a few options. Finally, there are the 2 rule lists (RL1 and RL2), which apply a sequence of transformations and combined transformations, and the ``fu`` algorithm itself, which applies rules and rule lists and selects the best expressions. There is also a function ``L`` which counts the number of trigonometric functions that appear in the expression. Other than TR0, re-writing of expressions is not done by the transformations. e.g. TR10i finds pairs of terms in a sum that are in the form like ``cos(x)*cos(y) + sin(x)*sin(y)``. Such expression are targeted in a bottom-up traversal of the expression, but no manipulation to make them appear is attempted. For example, Set-up for examples below: >>> from sympy.simplify.fu import fu, L, TR9, TR10i, TR11 >>> from sympy import factor, sin, cos, powsimp >>> from sympy.abc import x, y, z, a >>> from time import time >>> eq = cos(x + y)/cos(x) >>> TR10i(eq.expand(trig=True)) -sin(x)*sin(y)/cos(x) + cos(y) If the expression is put in "normal" form (with a common denominator) then the transformation is successful: >>> TR10i(_.normal()) cos(x + y)/cos(x) TR11's behavior is similar. It rewrites double angles as smaller angles but doesn't do any simplification of the result. >>> TR11(sin(2)**a*cos(1)**(-a), 1) (2*sin(1)*cos(1))**a/cos(1)**a >>> powsimp(_) (2*sin(1))**a The temptation is to try make these TR rules "smarter" but that should really be done at a higher level; the TR rules should try maintain the "do one thing well" principle. There is one exception, however. In TR10i and TR9 terms are recognized even when they are each multiplied by a common factor: >>> fu(a*cos(x)*cos(y) + a*sin(x)*sin(y)) a*cos(x - y) Factoring with ``factor_terms`` is used but it is "JIT"-like, being delayed until it is deemed necessary. Furthermore, if the factoring does not help with the simplification, it is not retained, so ``a*cos(x)*cos(y) + a*sin(x)*sin(z)`` does not become a factored (but unsimplified in the trigonometric sense) expression: >>> fu(a*cos(x)*cos(y) + a*sin(x)*sin(z)) a*sin(x)*sin(z) + a*cos(x)*cos(y) In some cases factoring might be a good idea, but the user is left to make that decision. For example: >>> expr=((15*sin(2*x) + 19*sin(x + y) + 17*sin(x + z) + 19*cos(x - z) + ... 25)*(20*sin(2*x) + 15*sin(x + y) + sin(y + z) + 14*cos(x - z) + ... 14*cos(y - z))*(9*sin(2*y) + 12*sin(y + z) + 10*cos(x - y) + 2*cos(y - ... z) + 18)).expand(trig=True).expand() In the expanded state, there are nearly 1000 trig functions: >>> L(expr) 932 If the expression where factored first, this would take time but the resulting expression would be transformed very quickly: >>> def clock(f, n=2): ... t=time(); f(); return round(time()-t, n) ... >>> clock(lambda: factor(expr)) # doctest: +SKIP 0.86 >>> clock(lambda: TR10i(expr), 3) # doctest: +SKIP 0.016 If the unexpanded expression is used, the transformation takes longer but not as long as it took to factor it and then transform it: >>> clock(lambda: TR10i(expr), 2) # doctest: +SKIP 0.28 So neither expansion nor factoring is used in ``TR10i``: if the expression is already factored (or partially factored) then expansion with ``trig=True`` would destroy what is already known and take longer; if the expression is expanded, factoring may take longer than simply applying the transformation itself. Although the algorithms should be canonical, always giving the same result, they may not yield the best result. This, in general, is the nature of simplification where searching all possible transformation paths is very expensive. Here is a simple example. There are 6 terms in the following sum: >>> expr = (sin(x)**2*cos(y)*cos(z) + sin(x)*sin(y)*cos(x)*cos(z) + ... sin(x)*sin(z)*cos(x)*cos(y) + sin(y)*sin(z)*cos(x)**2 + sin(y)*sin(z) + ... cos(y)*cos(z)) >>> args = expr.args Serendipitously, fu gives the best result: >>> fu(expr) 3*cos(y - z)/2 - cos(2*x + y + z)/2 But if different terms were combined, a less-optimal result might be obtained, requiring some additional work to get better simplification, but still less than optimal. The following shows an alternative form of ``expr`` that resists optimal simplification once a given step is taken since it leads to a dead end: >>> TR9(-cos(x)**2*cos(y + z) + 3*cos(y - z)/2 + ... cos(y + z)/2 + cos(-2*x + y + z)/4 - cos(2*x + y + z)/4) sin(2*x)*sin(y + z)/2 - cos(x)**2*cos(y + z) + 3*cos(y - z)/2 + cos(y + z)/2 Here is a smaller expression that exhibits the same behavior: >>> a = sin(x)*sin(z)*cos(x)*cos(y) + sin(x)*sin(y)*cos(x)*cos(z) >>> TR10i(a) sin(x)*sin(y + z)*cos(x) >>> newa = _ >>> TR10i(expr - a) # this combines two more of the remaining terms sin(x)**2*cos(y)*cos(z) + sin(y)*sin(z)*cos(x)**2 + cos(y - z) >>> TR10i(_ + newa) == _ + newa # but now there is no more simplification True Without getting lucky or trying all possible pairings of arguments, the final result may be less than optimal and impossible to find without better heuristics or brute force trial of all possibilities. Rules ===== .. autofunction:: TR0 .. autofunction:: TR1 .. autofunction:: TR2 .. autofunction:: TR2i .. autofunction:: TR3 .. autofunction:: TR4 .. autofunction:: TR5 .. autofunction:: TR6 .. autofunction:: TR7 .. autofunction:: TR8 .. autofunction:: TR9 .. autofunction:: TR10 .. autofunction:: TR10i .. autofunction:: TR11 .. autofunction:: TR12 .. autofunction:: TR12i .. autofunction:: TR13 .. autofunction:: TRmorrie .. autofunction:: TR14 .. autofunction:: TR15 .. autofunction:: TR16 .. autofunction:: TR111 .. autofunction:: TR22 .. autofunction:: TRpower .. autofunction:: fu Notes ===== This work was started by Dimitar Vlahovski at the Technological School "Electronic systems" (30.11.2011). Beyond TR13, other rules are not from the original paper, but extended in SymPy. References ========== .. [1] Fu, Hongguang, Xiuqin Zhong, and Zhenbing Zeng. "Automated and readable simplification of trigonometric expressions." Mathematical and computer modelling 44.11 (2006): 1169-1177. http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.657.2478&rep=rep1&type=pdf .. [2] A formula sheet for trigonometric functions. http://www.sosmath.com/trig/Trig5/trig5/pdf/pdf.html sympy-sympy-1.9/doc/src/modules/simplify/hyperexpand.rst000066400000000000000000000661011412543434000236500ustar00rootroot00000000000000======================== Hypergeometric Expansion ======================== .. currentmodule:: sympy.simplify.hyperexpand This page describes how the function :func:`hyperexpand` and related code work. For usage, see the documentation of the symplify module. Hypergeometric Function Expansion Algorithm =========================================== This section describes the algorithm used to expand hypergeometric functions. Most of it is based on the papers [Roach1996]_ and [Roach1997]_. Recall that the hypergeometric function is (initially) defined as .. math :: {}_pF_q\left(\begin{matrix} a_1, \cdots, a_p \\ b_1, \cdots, b_q \end{matrix} \middle| z \right) = \sum_{n=0}^\infty \frac{(a_1)_n \cdots (a_p)_n}{(b_1)_n \cdots (b_q)_n} \frac{z^n}{n!}. It turns out that there are certain differential operators that can change the `a_p` and `p_q` parameters by integers. If a sequence of such operators is known that converts the set of indices `a_r^0` and `b_s^0` into `a_p` and `b_q`, then we shall say the pair `a_p, b_q` is reachable from `a_r^0, b_s^0`. Our general strategy is thus as follows: given a set `a_p, b_q` of parameters, try to look up an origin `a_r^0, b_s^0` for which we know an expression, and then apply the sequence of differential operators to the known expression to find an expression for the Hypergeometric function we are interested in. Notation ======== In the following, the symbol `a` will always denote a numerator parameter and the symbol `b` will always denote a denominator parameter. The subscripts `p, q, r, s` denote vectors of that length, so e.g. `a_p` denotes a vector of `p` numerator parameters. The subscripts `i` and `j` denote "running indices", so they should usually be used in conjunction with a "for all `i`". E.g. `a_i < 4` for all `i`. Uppercase subscripts `I` and `J` denote a chosen, fixed index. So for example `a_I > 0` is true if the inequality holds for the one index `I` we are currently interested in. Incrementing and decrementing indices ===================================== Suppose `a_i \ne 0`. Set `A(a_i) = \frac{z}{a_i}\frac{\mathrm{d}}{dz}+1`. It is then easy to show that `A(a_i) {}_p F_q\left({a_p \atop b_q} \middle| z \right) = {}_p F_q\left({a_p + e_i \atop b_q} \middle| z \right)`, where `e_i` is the i-th unit vector. Similarly for `b_j \ne 1` we set `B(b_j) = \frac{z}{b_j-1} \frac{\mathrm{d}}{dz}+1` and find `B(b_j) {}_p F_q\left({a_p \atop b_q} \middle| z \right) = {}_p F_q\left({a_p \atop b_q - e_i} \middle| z \right)`. Thus we can increment upper and decrement lower indices at will, as long as we don't go through zero. The `A(a_i)` and `B(b_j)` are called shift operators. It is also easy to show that `\frac{\mathrm{d}}{dz} {}_p F_q\left({a_p \atop b_q} \middle| z \right) = \frac{a_1 \cdots a_p}{b_1 \cdots b_q} {}_p F_q\left({a_p + 1 \atop b_q + 1} \middle| z \right)`, where `a_p + 1` is the vector `a_1 + 1, a_2 + 1, \ldots` and similarly for `b_q + 1`. Combining this with the shift operators, we arrive at one form of the Hypergeometric differential equation: `\left[ \frac{\mathrm{d}}{dz} \prod_{j=1}^q B(b_j) - \frac{a_1 \cdots a_p}{(b_1-1) \cdots (b_q-1)} \prod_{i=1}^p A(a_i) \right] {}_p F_q\left({a_p \atop b_q} \middle| z \right) = 0`. This holds if all shift operators are defined, i.e. if no `a_i = 0` and no `b_j = 1`. Clearing denominators and multiplying through by z we arrive at the following equation: `\left[ z\frac{\mathrm{d}}{dz} \prod_{j=1}^q \left(z\frac{\mathrm{d}}{dz} + b_j-1 \right) - z \prod_{i=1}^p \left( z\frac{\mathrm{d}}{\mathrm{d}z} + a_i \right) \right] {}_p F_q\left({a_p \atop b_q} \middle| z\right) = 0`. Even though our derivation does not show it, it can be checked that this equation holds whenever the `{}_p F_q` is defined. Notice that, under suitable conditions on `a_I, b_J`, each of the operators `A(a_i)`, `B(b_j)` and `z\frac{\mathrm{d}}{\mathrm{d}z}` can be expressed in terms of `A(a_I)` or `B(b_J)`. Our next aim is to write the Hypergeometric differential equation as follows: `[X A(a_I) - r] {}_p F_q\left({a_p \atop b_q} \middle| z\right) = 0`, for some operator `X` and some constant `r` to be determined. If `r \ne 0`, then we can write this as `\frac{-1}{r} X {}_p F_q\left({a_p + e_I \atop b_q} \middle| z\right) = {}_p F_q\left({a_p \atop b_q} \middle| z\right)`, and so `\frac{-1}{r}X` undoes the shifting of `A(a_I)`, whence it will be called an inverse-shift operator. Now `A(a_I)` exists if `a_I \ne 0`, and then `z\frac{\mathrm{d}}{\mathrm{d}z} = a_I A(a_I) - a_I`. Observe also that all the operators `A(a_i)`, `B(b_j)` and `z\frac{\mathrm{d}}{\mathrm{d}z}` commute. We have `\prod_{i=1}^p \left( z\frac{\mathrm{d}}{\mathrm{d}z} + a_i \right) = \left(\prod_{i=1, i \ne I}^p \left( z\frac{\mathrm{d}}{\mathrm{d}z} + a_i \right)\right) a_I A(a_I)`, so this gives us the first half of `X`. The other half does not have such a nice expression. We find `z\frac{\mathrm{d}}{dz} \prod_{j=1}^q \left(z\frac{\mathrm{d}}{dz} + b_j-1 \right) = \left(a_I A(a_I) - a_I\right) \prod_{j=1}^q \left(a_I A(a_I) - a_I + b_j - 1\right)`. Since the first half had no constant term, we infer `r = -a_I\prod_{j=1}^q(b_j - 1 -a_I)`. This tells us under which conditions we can "un-shift" `A(a_I)`, namely when `a_I \ne 0` and `r \ne 0`. Substituting `a_I - 1` for `a_I` then tells us under what conditions we can decrement the index `a_I`. Doing a similar analysis for `B(a_J)`, we arrive at the following rules: * An index `a_I` can be decremented if `a_I \ne 1` and `a_I \ne b_j` for all `b_j`. * An index `b_J` can be incremented if `b_J \ne -1` and `b_J \ne a_i` for all `a_i`. Combined with the conditions (stated above) for the existence of shift operators, we have thus established the rules of the game! Reduction of Order ================== Notice that, quite trivially, if `a_I = b_J`, we have `{}_p F_q\left({a_p \atop b_q} \middle| z \right) = {}_{p-1} F_{q-1}\left({a_p^* \atop b_q^*} \middle| z \right)`, where `a_p^*` means `a_p` with `a_I` omitted, and similarly for `b_q^*`. We call this reduction of order. In fact, we can do even better. If `a_I - b_J \in \mathbb{Z}_{>0}`, then it is easy to see that `\frac{(a_I)_n}{(b_J)_n}` is actually a polynomial in `n`. It is also easy to see that `(z\frac{\mathrm{d}}{\mathrm{d}z})^k z^n = n^k z^n`. Combining these two remarks we find: If `a_I - b_J \in \mathbb{Z}_{>0}`, then there exists a polynomial `p(n) = p_0 + p_1 n + \cdots` (of degree `a_I - b_J`) such that `\frac{(a_I)_n}{(b_J)_n} = p(n)` and `{}_p F_q\left({a_p \atop b_q} \middle| z \right) = \left(p_0 + p_1 z\frac{\mathrm{d}}{\mathrm{d}z} + p_2 \left(z\frac{\mathrm{d}}{\mathrm{d}z}\right)^2 + \cdots \right) {}_{p-1} F_{q-1}\left({a_p^* \atop b_q^*} \middle| z \right)`. Thus any set of parameters `a_p, b_q` is reachable from a set of parameters `c_r, d_s` where `c_i - d_j \in \mathbb{Z}` implies `c_i < d_j`. Such a set of parameters `c_r, d_s` is called suitable. Our database of known formulae should only contain suitable origins. The reasons are twofold: firstly, working from suitable origins is easier, and secondly, a formula for a non-suitable origin can be deduced from a lower order formula, and we should put this one into the database instead. Moving Around in the Parameter Space ==================================== It remains to investigate the following question: suppose `a_p, b_q` and `a_p^0, b_q^0` are both suitable, and also `a_i - a_i^0 \in \mathbb{Z}`, `b_j - b_j^0 \in \mathbb{Z}`. When is `a_p, b_q` reachable from `a_p^0, b_q^0`? It is clear that we can treat all parameters independently that are incongruent mod 1. So assume that `a_i` and `b_j` are congruent to `r` mod 1, for all `i` and `j`. The same then follows for `a_i^0` and `b_j^0`. If `r \ne 0`, then any such `a_p, b_q` is reachable from any `a_p^0, b_q^0`. To see this notice that there exist constants `c, c^0`, congruent mod 1, such that `a_i < c < b_j` for all `i` and `j`, and similarly `a_i^0 < c^0 < b_j^0`. If `n = c - c^0 > 0` then we first inverse-shift all the `b_j^0` `n` times up, and then similarly shift up all the `a_i^0` `n` times. If `n < 0` then we first inverse-shift down the `a_i^0` and then shift down the `b_j^0`. This reduces to the case `c = c^0`. But evidently we can now shift or inverse-shift around the `a_i^0` arbitrarily so long as we keep them less than `c`, and similarly for the `b_j^0` so long as we keep them bigger than `c`. Thus `a_p, b_q` is reachable from `a_p^0, b_q^0`. If `r = 0` then the problem is slightly more involved. WLOG no parameter is zero. We now have one additional complication: no parameter can ever move through zero. Hence `a_p, b_q` is reachable from `a_p^0, b_q^0` if and only if the number of `a_i < 0` equals the number of `a_i^0 < 0`, and similarly for the `b_i` and `b_i^0`. But in a suitable set of parameters, all `b_j > 0`! This is because the Hypergeometric function is undefined if one of the `b_j` is a non-positive integer and all `a_i` are smaller than the `b_j`. Hence the number of `b_j \le 0` is always zero. We can thus associate to every suitable set of parameters `a_p, b_q`, where no `a_i = 0`, the following invariants: * For every `r \in [0, 1)` the number `\alpha_r` of parameters `a_i \equiv r \pmod{1}`, and similarly the number `\beta_r` of parameters `b_i \equiv r \pmod{1}`. * The number `\gamma` of integers `a_i` with `a_i < 0`. The above reasoning shows that `a_p, b_q` is reachable from `a_p^0, b_q^0` if and only if the invariants `\alpha_r, \beta_r, \gamma` all agree. Thus in particular "being reachable from" is a symmetric relation on suitable parameters without zeros. Applying the Operators ====================== If all goes well then for a given set of parameters we find an origin in our database for which we have a nice formula. We now have to apply (potentially) many differential operators to it. If we do this blindly then the result will be very messy. This is because with Hypergeometric type functions, the derivative is usually expressed as a sum of two contiguous functions. Hence if we compute `N` derivatives, then the answer will involve `2N` contiguous functions! This is clearly undesirable. In fact we know from the Hypergeometric differential equation that we need at most `\max(p, q+1)` contiguous functions to express all derivatives. Hence instead of differentiating blindly, we will work with a `\mathbb{C}(z)`-module basis: for an origin `a_r^0, b_s^0` we either store (for particularly pretty answers) or compute a set of `N` functions (typically `N = \max(r, s+1)`) with the property that the derivative of any of them is a `\mathbb{C}(z)`-linear combination of them. In formulae, we store a vector `B` of `N` functions, a matrix `M` and a vector `C` (the latter two with entries in `\mathbb{C}(z)`), with the following properties: * `{}_r F_s\left({a_r^0 \atop b_s^0} \middle| z \right) = C B` * `z\frac{\mathrm{d}}{\mathrm{d}z} B = M B`. Then we can compute as many derivatives as we want and we will always end up with `\mathbb{C}(z)`-linear combination of at most `N` special functions. As hinted above, `B`, `M` and `C` can either all be stored (for particularly pretty answers) or computed from a single `{}_p F_q` formula. Loose Ends ========== This describes the bulk of the hypergeometric function algorithm. There a few further tricks, described in the hyperexpand.py source file. The extension to Meijer G-functions is also described there. Meijer G-Functions of Finite Confluence *************************************** Slater's theorem essentially evaluates a `G`-function as a sum of residues. If all poles are simple, the resulting series can be recognised as hypergeometric series. Thus a `G`-function can be evaluated as a sum of Hypergeometric functions. If the poles are not simple, the resulting series are not hypergeometric. This is known as the "confluent" or "logarithmic" case (the latter because the resulting series tend to contain logarithms). The answer depends in a complicated way on the multiplicities of various poles, and there is no accepted notation for representing it (as far as I know). However if there are only finitely many multiple poles, we can evaluate the `G` function as a sum of hypergeometric functions, plus finitely many extra terms. I could not find any good reference for this, which is why I work it out here. Recall the general setup. We define .. math:: G(z) = \frac{1}{2\pi i} \int_L \frac{\prod_{j=1}^m \Gamma(b_j - s) \prod_{j=1}^n \Gamma(1 - a_j + s)}{\prod_{j=m+1}^q \Gamma(1 - b_j + s) \prod_{j=n+1}^p \Gamma(a_j - s)} z^s \mathrm{d}s, where `L` is a contour starting and ending at `+\infty`, enclosing all of the poles of `\Gamma(b_j - s)` for `j = 1, \ldots, n` once in the negative direction, and no other poles. Also the integral is assumed absolutely convergent. In what follows, for any complex numbers `a, b`, we write `a \equiv b \pmod{1}` if and only if there exists an integer `k` such that `a - b = k`. Thus there are double poles iff `a_i \equiv a_j \pmod{1}` for some `i \ne j \le n`. We now assume that whenever `b_j \equiv a_i \pmod{1}` for `i \le m`, `j > n` then `b_j < a_i`. This means that no quotient of the relevant gamma functions is a polynomial, and can always be achieved by "reduction of order". Fix a complex number `c` such that `\{b_i | b_i \equiv c \pmod{1}, i \le m\}` is not empty. Enumerate this set as `b, b+k_1, \ldots, b+k_u`, with `k_i` non-negative integers. Enumerate similarly `\{a_j | a_j \equiv c \pmod{1}, j > n\}` as `b + l_1, \ldots, b + l_v`. Then `l_i > k_j` for all `i, j`. For finite confluence, we need to assume `v \ge u` for all such `c`. Let `c_1, \ldots, c_w` be distinct `\pmod{1}` and exhaust the congruence classes of the `b_i`. I claim .. math :: G(z) = -\sum_{j=1}^w (F_j(z) + R_j(z)), where `F_j(z)` is a hypergeometric function and `R_j(z)` is a finite sum, both to be specified later. Indeed corresponding to every `c_j` there is a sequence of poles, at mostly finitely many of them multiple poles. This is where the `j`-th term comes from. Hence fix again `c`, enumerate the relevant `b_i` as `b, b + k_1, \ldots, b + k_u`. We will look at the `a_j` corresponding to `a + l_1, \ldots, a + l_u`. The other `a_i` are not treated specially. The corresponding gamma functions have poles at (potentially) `s = b + r` for `r = 0, 1, \ldots`. For `r \ge l_u`, pole of the integrand is simple. We thus set .. math :: R(z) = \sum_{r=0}^{l_u - 1} res_{s = r + b}. We finally need to investigate the other poles. Set `r = l_u + t`, `t \ge 0`. A computation shows .. math :: \frac{\Gamma(k_i - l_u - t)}{\Gamma(l_i - l_u - t)} = \frac{1}{(k_i - l_u - t)_{l_i - k_i}} = \frac{(-1)^{\delta_i}}{(l_u - l_i + 1)_{\delta_i}} \frac{(l_u - l_i + 1)_t}{(l_u - k_i + 1)_t}, where `\delta_i = l_i - k_i`. Also .. math :: \Gamma(b_j - l_u - b - t) = \frac{\Gamma(b_j - l_u - b)}{(-1)^t(l_u + b + 1 - b_j)_t}, \\ \Gamma(1 - a_j + l_u + b + t) = \Gamma(1 - a_j + l_u + b) (1 - a_j + l_u + b)_t and .. math :: res_{s = b + l_u + t} \Gamma(b - s) = -\frac{(-1)^{l_u + t}}{(l_u + t)!} = -\frac{(-1)^{l_u}}{l_u!} \frac{(-1)^t}{(l_u+1)_t}. Hence .. math :: res_{s = b + l_u + t} =& -z^{b + l_u} \frac{(-1)^{l_u}}{l_u!} \prod_{i=1}^{u} \frac{(-1)^{\delta_i}}{(l_u - k_i + 1)_{\delta_i}} \frac{\prod_{j=1}^n \Gamma(1 - a_j + l_u + b) \prod_{j=1}^m \Gamma(b_j - l_u - b)^*} {\prod_{j=n+1}^p \Gamma(a_j - l_u - b)^* \prod_{j=m+1}^q \Gamma(1 - b_j + l_u + b)} \\ &\times z^t \frac{(-1)^t}{(l_u+1)_t} \prod_{i=1}^{u} \frac{(l_u - l_i + 1)_t}{(l_u - k_i + 1)_t} \frac{\prod_{j=1}^n (1 - a_j + l_u + b)_t \prod_{j=n+1}^p (-1)^t (l_u + b + 1 - a_j)_t^*} {\prod_{j=1}^m (-1)^t (l_u + b + 1 - b_j)_t^* \prod_{j=m+1}^q (1 - b_j + l_u + b)_t}, where the `*` means to omit the terms we treated specially. We thus arrive at .. math :: F(z) = C \times {}_{p+1}F_{q}\left( \begin{matrix} 1, (1 + l_u - l_i), (1 + l_u + b - a_i)^* \\ 1 + l_u, (1 + l_u - k_i), (1 + l_u + b - b_i)^* \end{matrix} \middle| (-1)^{p-m-n} z\right), where `C` designates the factor in the residue independent of `t`. (This result can also be written in slightly simpler form by converting all the `l_u` etc back to `a_* - b_*`, but doing so is going to require more notation still and is not helpful for computation.) Extending The Hypergeometric Tables *********************************** Adding new formulae to the tables is straightforward. At the top of the file ``sympy/simplify/hyperexpand.py``, there is a function called ``add_formulae()``. Nested in it are defined two helpers, ``add(ap, bq, res)`` and ``addb(ap, bq, B, C, M)``, as well as dummys ``a``, ``b``, ``c``, and ``z``. The first step in adding a new formula is by using ``add(ap, bq, res)``. This declares ``hyper(ap, bq, z) == res``. Here ``ap`` and ``bq`` may use the dummys ``a``, ``b``, and ``c`` as free symbols. For example the well-known formula `\sum_0^\infty \frac{(-a)_n z^n}{n!} = (1-z)^a` is declared by the following line: ``add((-a, ), (), (1-z)**a)``. From the information provided, the matrices `B`, `C` and `M` will be computed, and the formula is now available when expanding hypergeometric functions. Next the test file ``sympy/simplify/tests/test_hyperexpand.py`` should be run, in particular the test ``test_formulae()``. This will test the newly added formula numerically. If it fails, there is (presumably) a typo in what was entered. Since all newly-added formulae are probably relatively complicated, chances are that the automatically computed basis is rather suboptimal (there is no good way of testing this, other than observing very messy output). In this case the matrices `B`, `C` and `M` should be computed by hand. Then the helper ``addb`` can be used to declare a hypergeometric formula with hand-computed basis. An example ========== Because this explanation so far might be very theoretical and difficult to understand, we walk through an explicit example now. We take the Fresnel function `C(z)` which obeys the following hypergeometric representation: .. math :: C(z) = z \cdot {}_{1}F_{2}\left.\left( \begin{matrix} \frac{1}{4} \\ \frac{1}{2}, \frac{5}{4} \end{matrix} \right| -\frac{\pi^2 z^4}{16}\right) \,. First we try to add this formula to the lookup table by using the (simpler) function ``add(ap, bq, res)``. The first two arguments are simply the lists containing the parameter sets of `{}_{1}F_{2}`. The ``res`` argument is a little bit more complicated. We only know `C(z)` in terms of `{}_{1}F_{2}(\ldots | f(z))` with `f` a function of `z`, in our case .. math :: f(z) = -\frac{\pi^2 z^4}{16} \,. What we need is a formula where the hypergeometric function has only `z` as argument `{}_{1}F_{2}(\ldots | z)`. We introduce the new complex symbol `w` and search for a function `g(w)` such that .. math :: f(g(w)) = w holds. Then we can replace every `z` in `C(z)` by `g(w)`. In the case of our example the function `g` could look like .. math :: g(w) = \frac{2}{\sqrt{\pi}} \exp\left(\frac{i \pi}{4}\right) w^{\frac{1}{4}} \,. We get these functions mainly by guessing and testing the result. Hence we proceed by computing `f(g(w))` (and simplifying naively) .. math :: f(g(w)) &= -\frac{\pi^2 g(w)^4}{16} \\ &= -\frac{\pi^2 g\left(\frac{2}{\sqrt{\pi}} \exp\left(\frac{i \pi}{4}\right) w^{\frac{1}{4}}\right)^4}{16} \\ &= -\frac{\pi^2 \frac{2^4}{\sqrt{\pi}^4} \exp\left(\frac{i \pi}{4}\right)^4 {w^{\frac{1}{4}}}^4}{16} \\ &= -\exp\left(i \pi\right) w \\ &= w and indeed get back `w`. (In case of branched functions we have to be aware of branch cuts. In that case we take `w` to be a positive real number and check the formula. If what we have found works for positive `w`, then just replace :class:`~sympy.functions.elementary.exponential.exp` inside any branched function by :class:`~sympy.functions.elementary.exponential.exp_polar` and what we get is right for `all` `w`.) Hence we can write the formula as .. math :: C(g(w)) = g(w) \cdot {}_{1}F_{2}\left.\left( \begin{matrix} \frac{1}{4} \\ \frac{1}{2}, \frac{5}{4} \end{matrix} \right| w\right) \,. and trivially .. math :: {}_{1}F_{2}\left.\left( \begin{matrix} \frac{1}{4} \\ \frac{1}{2}, \frac{5}{4} \end{matrix} \right| w\right) = \frac{C(g(w))}{g(w)} = \frac{C\left(\frac{2}{\sqrt{\pi}} \exp\left(\frac{i \pi}{4}\right) w^{\frac{1}{4}}\right)} {\frac{2}{\sqrt{\pi}} \exp\left(\frac{i \pi}{4}\right) w^{\frac{1}{4}}} which is exactly what is needed for the third parameter, ``res``, in ``add``. Finally, the whole function call to add this rule to the table looks like:: add([S(1)/4], [S(1)/2, S(5)/4], fresnelc(exp(pi*I/4)*root(z,4)*2/sqrt(pi)) / (exp(pi*I/4)*root(z,4)*2/sqrt(pi)) ) Using this rule we will find that it works but the results are not really nice in terms of simplicity and number of special function instances included. We can obtain much better results by adding the formula to the lookup table in another way. For this we use the (more complicated) function ``addb(ap, bq, B, C, M)``. The first two arguments are again the lists containing the parameter sets of `{}_{1}F_{2}`. The remaining three are the matrices mentioned earlier on this page. We know that the `n = \max{\left(p, q+1\right)}`-th derivative can be expressed as a linear combination of lower order derivatives. The matrix `B` contains the basis `\{B_0, B_1, \ldots\}` and is of shape `n \times 1`. The best way to get `B_i` is to take the first `n = \max(p, q+1)` derivatives of the expression for `{}_p F_q` and take out useful pieces. In our case we find that `n = \max{\left(1, 2+1\right)} = 3`. For computing the derivatives, we have to use the operator `z\frac{\mathrm{d}}{\mathrm{d}z}`. The first basis element `B_0` is set to the expression for `{}_1 F_2` from above: .. math :: B_0 = \frac{ \sqrt{\pi} \exp\left(-\frac{\mathbf{\imath}\pi}{4}\right) C\left( \frac{2}{\sqrt{\pi}} \exp\left(\frac{\mathbf{\imath}\pi}{4}\right) z^{\frac{1}{4}}\right)} {2 z^{\frac{1}{4}}} Next we compute `z\frac{\mathrm{d}}{\mathrm{d}z} B_0`. For this we can directly use SymPy! >>> from sympy import Symbol, sqrt, exp, I, pi, fresnelc, root, diff, expand >>> z = Symbol("z") >>> B0 = sqrt(pi)*exp(-I*pi/4)*fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))/\ ... (2*root(z,4)) >>> z * diff(B0, z) z*(cosh(2*sqrt(z))/(4*z) - sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(8*z**(5/4))) >>> expand(_) cosh(2*sqrt(z))/4 - sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(8*z**(1/4)) Formatting this result nicely we obtain .. math :: B_1^\prime = - \frac{1}{4} \frac{ \sqrt{\pi} \exp\left(-\frac{\mathbf{\imath}\pi}{4}\right) C\left( \frac{2}{\sqrt{\pi}} \exp\left(\frac{\mathbf{\imath}\pi}{4}\right) z^{\frac{1}{4}}\right) } {2 z^{\frac{1}{4}}} + \frac{1}{4} \cosh{\left( 2 \sqrt{z} \right )} Computing the second derivative we find >>> from sympy import (Symbol, cosh, sqrt, pi, exp, I, fresnelc, root, ... diff, expand) >>> z = Symbol("z") >>> B1prime = cosh(2*sqrt(z))/4 - sqrt(pi)*exp(-I*pi/4)*\ ... fresnelc(2*root(z,4)*exp(I*pi/4)/sqrt(pi))/(8*root(z,4)) >>> z * diff(B1prime, z) z*(-cosh(2*sqrt(z))/(16*z) + sinh(2*sqrt(z))/(4*sqrt(z)) + sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(32*z**(5/4))) >>> expand(_) sqrt(z)*sinh(2*sqrt(z))/4 - cosh(2*sqrt(z))/16 + sqrt(pi)*exp(-I*pi/4)*fresnelc(2*z**(1/4)*exp(I*pi/4)/sqrt(pi))/(32*z**(1/4)) which can be printed as .. math :: B_2^\prime = \frac{1}{16} \frac{ \sqrt{\pi} \exp\left(-\frac{\mathbf{\imath}\pi}{4}\right) C\left( \frac{2}{\sqrt{\pi}} \exp\left(\frac{\mathbf{\imath}\pi}{4}\right) z^{\frac{1}{4}}\right) } {2 z^{\frac{1}{4}}} - \frac{1}{16} \cosh{\left(2\sqrt{z}\right)} + \frac{1}{4} \sinh{\left(2\sqrt{z}\right)} \sqrt{z} We see the common pattern and can collect the pieces. Hence it makes sense to choose `B_1` and `B_2` as follows .. math :: B = \left( \begin{matrix} B_0 \\ B_1 \\ B_2 \end{matrix} \right) = \left( \begin{matrix} \frac{ \sqrt{\pi} \exp\left(-\frac{\mathbf{\imath}\pi}{4}\right) C\left( \frac{2}{\sqrt{\pi}} \exp\left(\frac{\mathbf{\imath}\pi}{4}\right) z^{\frac{1}{4}}\right) }{2 z^{\frac{1}{4}}} \\ \cosh\left(2\sqrt{z}\right) \\ \sinh\left(2\sqrt{z}\right) \sqrt{z} \end{matrix} \right) (This is in contrast to the basis `B = \left(B_0, B_1^\prime, B_2^\prime\right)` that would have been computed automatically if we used just ``add(ap, bq, res)``.) Because it must hold that `{}_p F_q\left(\cdots \middle| z \right) = C B` the entries of `C` are obviously .. math :: C = \left( \begin{matrix} 1 \\ 0 \\ 0 \end{matrix} \right) Finally we have to compute the entries of the `3 \times 3` matrix `M` such that `z\frac{\mathrm{d}}{\mathrm{d}z} B = M B` holds. This is easy. We already computed the first part `z\frac{\mathrm{d}}{\mathrm{d}z} B_0` above. This gives us the first row of `M`. For the second row we have: >>> from sympy import Symbol, cosh, sqrt, diff >>> z = Symbol("z") >>> B1 = cosh(2*sqrt(z)) >>> z * diff(B1, z) sqrt(z)*sinh(2*sqrt(z)) and for the third one >>> from sympy import Symbol, sinh, sqrt, expand, diff >>> z = Symbol("z") >>> B2 = sinh(2*sqrt(z))*sqrt(z) >>> expand(z * diff(B2, z)) sqrt(z)*sinh(2*sqrt(z))/2 + z*cosh(2*sqrt(z)) Now we have computed the entries of this matrix to be .. math :: M = \left( \begin{matrix} -\frac{1}{4} & \frac{1}{4} & 0 \\ 0 & 0 & 1 \\ 0 & z & \frac{1}{2} \\ \end{matrix} \right) Note that the entries of `C` and `M` should typically be rational functions in `z`, with rational coefficients. This is all we need to do in order to add a new formula to the lookup table for ``hyperexpand``. Implemented Hypergeometric Formulae *********************************** A vital part of the algorithm is a relatively large table of hypergeometric function representations. The following automatically generated list contains all the representations implemented in SymPy (of course many more are derived from them). These formulae are mostly taken from [Luke1969]_ and [Prudnikov1990]_. They are all tested numerically. .. automodule:: sympy.simplify.hyperexpand_doc References ********** .. [Roach1996] Kelly B. Roach. Hypergeometric Function Representations. In: Proceedings of the 1996 International Symposium on Symbolic and Algebraic Computation, pages 301-308, New York, 1996. ACM. .. [Roach1997] Kelly B. Roach. Meijer G Function Representations. In: Proceedings of the 1997 International Symposium on Symbolic and Algebraic Computation, pages 205-211, New York, 1997. ACM. .. [Luke1969] Luke, Y. L. (1969), The Special Functions and Their Approximations, Volume 1. .. [Prudnikov1990] A. P. Prudnikov, Yu. A. Brychkov and O. I. Marichev (1990). Integrals and Series: More Special Functions, Vol. 3, Gordon and Breach Science Publisher. sympy-sympy-1.9/doc/src/modules/simplify/index.rst000066400000000000000000000001471412543434000224260ustar00rootroot00000000000000======== Simplify ======== .. toctree:: :maxdepth: 2 simplify.rst hyperexpand.rst fu.rst sympy-sympy-1.9/doc/src/modules/simplify/simplify.rst000066400000000000000000000045731412543434000231620ustar00rootroot00000000000000======== Simplify ======== .. currentmodule:: sympy.simplify.simplify simplify -------- .. autofunction:: simplify separatevars ------------ .. autofunction:: separatevars nthroot ------- .. autofunction:: nthroot kroneckersimp ------------- .. autofunction:: kroneckersimp besselsimp ---------- .. autofunction:: besselsimp hypersimp --------- .. autofunction:: hypersimp hypersimilar ------------ .. autofunction:: hypersimilar nsimplify --------- .. autofunction:: nsimplify posify ------ .. autofunction:: posify logcombine ---------- .. autofunction:: logcombine Radsimp ------- .. module:: sympy.simplify.radsimp radsimp ^^^^^^^ .. autofunction:: radsimp rad_rationalize ^^^^^^^^^^^^^^^ .. autofunction:: rad_rationalize collect ^^^^^^^ .. autofunction:: collect .. autofunction:: rcollect collect_sqrt ^^^^^^^^^^^^ .. autofunction:: collect_sqrt collect_const ^^^^^^^^^^^^^ .. autofunction:: collect_const fraction ^^^^^^^^ .. autofunction:: fraction Ratsimp ------- .. module:: sympy.simplify.ratsimp ratsimp ^^^^^^^ .. autofunction:: ratsimp ratsimpmodprime ^^^^^^^^^^^^^^^ .. autofunction:: ratsimpmodprime Trigonometric simplification ---------------------------- .. module:: sympy.simplify.trigsimp trigsimp ^^^^^^^^ .. autofunction:: trigsimp Power simplification -------------------- .. module:: sympy.simplify.powsimp powsimp ^^^^^^^ .. autofunction:: powsimp powdenest ^^^^^^^^^ .. autofunction:: powdenest Combinatorial simplification ---------------------------- .. module:: sympy.simplify.combsimp combsimp ^^^^^^^^ .. autofunction:: combsimp Square Root Denesting --------------------- .. module:: sympy.simplify.sqrtdenest sqrtdenest ^^^^^^^^^^ .. autofunction:: sqrtdenest Common Subexpression Elimination -------------------------------- .. module:: sympy.simplify.cse_main cse ^^^ .. autofunction:: cse opt_cse ^^^^^^^ .. autofunction:: sympy.simplify.cse_main::opt_cse tree_cse ^^^^^^^^ .. autofunction:: sympy.simplify.cse_main::tree_cse Hypergeometric Function Expansion --------------------------------- .. module:: sympy.simplify.hyperexpand hyperexpand ^^^^^^^^^^^ .. autofunction:: hyperexpand Traversal Tools --------------- .. module:: sympy.simplify.traversaltools use ^^^ .. autofunction:: use EPath Tools ----------- .. module:: sympy.simplify.epathtools EPath class ^^^^^^^^^^^ .. autoclass:: EPath :members: epath ^^^^^ .. autofunction:: epath sympy-sympy-1.9/doc/src/modules/solvers/000077500000000000000000000000001412543434000204245ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/solvers/diophantine.rst000066400000000000000000000474421412543434000234730ustar00rootroot00000000000000.. _diophantine-docs: Diophantine =========== Diophantine equations --------------------- The word "Diophantine" comes with the name Diophantus, a mathematician lived in the great city of Alexandria sometime around 250 AD. Often referred to as the "father of Algebra", Diophantus in his famous work "Arithmetica" presented 150 problems that marked the early beginnings of number theory, the field of study about integers and their properties. Diophantine equations play a central and an important part in number theory. We call a "Diophantine equation" to an equation of the form, `f(x_1, x_2, \ldots x_n) = 0` where `n \geq 2` and `x_1, x_2, \ldots x_n` are integer variables. If we can find `n` integers `a_1, a_2, \ldots a_n` such that `x_1 = a_1, x_2 = a_2, \ldots x_n = a_n` satisfies the above equation, we say that the equation is solvable. You can read more about Diophantine equations in [1]_ and [2]_. Currently, following five types of Diophantine equations can be solved using :py:meth:`~sympy.solvers.diophantine.diophantine.diophantine` and other helper functions of the Diophantine module. - Linear Diophantine equations: `a_1x_1 + a_2x_2 + \ldots + a_nx_n = b`. - General binary quadratic equation: `ax^2 + bxy + cy^2 + dx + ey + f = 0` - Homogeneous ternary quadratic equation: `ax^2 + by^2 + cz^2 + dxy + eyz + fzx = 0` - Extended Pythagorean equation: `a_{1}x_{1}^2 + a_{2}x_{2}^2 + \ldots + a_{n}x_{n}^2 = a_{n+1}x_{n+1}^2` - General sum of squares: `x_{1}^2 + x_{2}^2 + \ldots + x_{n}^2 = k` Module structure ---------------- This module contains :py:meth:`~sympy.solvers.diophantine.diophantine.diophantine` and helper functions that are needed to solve certain Diophantine equations. It's structured in the following manner. - :py:meth:`~sympy.solvers.diophantine.diophantine.diophantine` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_solve` - :py:meth:`~sympy.solvers.diophantine.diophantine.classify_diop` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_linear` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_quadratic` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_ternary_quadratic` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_ternary_quadratic_normal` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_pythagorean` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_sum_of_squares` - :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_sum_of_even_powers` - :py:meth:`~sympy.solvers.diophantine.diophantine.merge_solution` When an equation is given to :py:meth:`~sympy.solvers.diophantine.diophantine.diophantine`, it factors the equation(if possible) and solves the equation given by each factor by calling :py:meth:`~sympy.solvers.diophantine.diophantine.diop_solve` separately. Then all the results are combined using :py:meth:`~sympy.solvers.diophantine.diophantine.merge_solution`. :py:meth:`~sympy.solvers.diophantine.diophantine.diop_solve` internally uses :py:meth:`~sympy.solvers.diophantine.diophantine.classify_diop` to find the type of the equation(and some other details) given to it and then calls the appropriate solver function based on the type returned. For example, if :py:meth:`~sympy.solvers.diophantine.diophantine.classify_diop` returned "linear" as the type of the equation, then :py:meth:`~sympy.solvers.diophantine.diophantine.diop_solve` calls :py:meth:`~sympy.solvers.diophantine.diophantine.diop_linear` to solve the equation. Each of the functions, :py:meth:`~sympy.solvers.diophantine.diophantine.diop_linear`, :py:meth:`~sympy.solvers.diophantine.diophantine.diop_quadratic`, :py:meth:`~sympy.solvers.diophantine.diophantine.diop_ternary_quadratic`, :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_pythagorean` and :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_sum_of_squares` solves a specific type of equations and the type can be easily guessed by it's name. Apart from these functions, there are a considerable number of other functions in the "Diophantine Module" and all of them are listed under User functions and Internal functions. Tutorial -------- First, let's import the highest API of the Diophantine module. >>> from sympy.solvers.diophantine import diophantine Before we start solving the equations, we need to define the variables. >>> from sympy import symbols >>> x, y, z = symbols("x, y, z", integer=True) Let's start by solving the easiest type of Diophantine equations, i.e. linear Diophantine equations. Let's solve `2x + 3y = 5`. Note that although we write the equation in the above form, when we input the equation to any of the functions in Diophantine module, it needs to be in the form `eq = 0`. >>> diophantine(2*x + 3*y - 5) {(3*t_0 - 5, 5 - 2*t_0)} Note that stepping one more level below the highest API, we can solve the very same equation by calling :py:meth:`~sympy.solvers.diophantine.diophantine.diop_solve`. >>> from sympy.solvers.diophantine.diophantine import diop_solve >>> diop_solve(2*x + 3*y - 5) (3*t_0 - 5, 5 - 2*t_0) Note that it returns a tuple rather than a set. :py:meth:`~sympy.solvers.diophantine.diophantine.diophantine` always return a set of tuples. But :py:meth:`~sympy.solvers.diophantine.diophantine.diop_solve` may return a single tuple or a set of tuples depending on the type of the equation given. We can also solve this equation by calling :py:meth:`~sympy.solvers.diophantine.diophantine.diop_linear`, which is what :py:meth:`~sympy.solvers.diophantine.diophantine.diop_solve` calls internally. >>> from sympy.solvers.diophantine.diophantine import diop_linear >>> diop_linear(2*x + 3*y - 5) (3*t_0 - 5, 5 - 2*t_0) If the given equation has no solutions then the outputs will look like below. >>> diophantine(2*x + 4*y - 3) set() >>> diop_solve(2*x + 4*y - 3) (None, None) >>> diop_linear(2*x + 4*y - 3) (None, None) Note that except for the highest level API, in case of no solutions, a tuple of `None` are returned. Size of the tuple is the same as the number of variables. Also, one can specifically set the parameter to be used in the solutions by passing a customized parameter. Consider the following example: >>> m = symbols("m", integer=True) >>> diop_solve(2*x + 3*y - 5, m) (3*m_0 - 5, 5 - 2*m_0) For linear Diophantine equations, the customized parameter is the prefix used for each free variable in the solution. Consider the following example: >>> diop_solve(2*x + 3*y - 5*z + 7, m) (m_0, m_0 + 5*m_1 - 14, m_0 + 3*m_1 - 7) In the solution above, m_0 and m_1 are independent free variables. Please note that for the moment, users can set the parameter only for linear Diophantine equations and binary quadratic equations. Let's try solving a binary quadratic equation which is an equation with two variables and has a degree of two. Before trying to solve these equations, an idea about various cases associated with the equation would help a lot. Please refer [3]_ and [4]_ for detailed analysis of different cases and the nature of the solutions. Let us define `\Delta = b^2 - 4ac` w.r.t. the binary quadratic `ax^2 + bxy + cy^2 + dx + ey + f = 0`. When `\Delta < 0`, there are either no solutions or only a finite number of solutions. >>> diophantine(x**2 - 4*x*y + 8*y**2 - 3*x + 7*y - 5) {(2, 1), (5, 1)} In the above equation `\Delta = (-4)^2 - 4*1*8 = -16` and hence only a finite number of solutions exist. When `\Delta = 0` we might have either no solutions or parameterized solutions. >>> diophantine(3*x**2 - 6*x*y + 3*y**2 - 3*x + 7*y - 5) set() >>> diophantine(x**2 - 4*x*y + 4*y**2 - 3*x + 7*y - 5) {(-2*t**2 - 7*t + 10, -t**2 - 3*t + 5)} >>> diophantine(x**2 + 2*x*y + y**2 - 3*x - 3*y) {(t_0, -t_0), (t_0, 3 - t_0)} The most interesting case is when `\Delta > 0` and it is not a perfect square. In this case, the equation has either no solutions or an infinite number of solutions. Consider the below cases where `\Delta = 8`. >>> diophantine(x**2 - 4*x*y + 2*y**2 - 3*x + 7*y - 5) set() >>> from sympy import sqrt >>> n = symbols("n", integer=True) >>> s = diophantine(x**2 - 2*y**2 - 2*x - 4*y, n) >>> x_1, y_1 = s.pop() >>> x_2, y_2 = s.pop() >>> x_n = -(-2*sqrt(2) + 3)**n/2 + sqrt(2)*(-2*sqrt(2) + 3)**n/2 - sqrt(2)*(2*sqrt(2) + 3)**n/2 - (2*sqrt(2) + 3)**n/2 + 1 >>> x_1 == x_n or x_2 == x_n True >>> y_n = -sqrt(2)*(-2*sqrt(2) + 3)**n/4 + (-2*sqrt(2) + 3)**n/2 + sqrt(2)*(2*sqrt(2) + 3)**n/4 + (2*sqrt(2) + 3)**n/2 - 1 >>> y_1 == y_n or y_2 == y_n True Here `n` is an integer. Although x_n and y_n may not look like integers, substituting in specific values for n (and simplifying) shows that they are. For example consider the following example where we set n equal to 9. >>> from sympy import simplify >>> simplify(x_n.subs({n: 9})) -9369318 Any binary quadratic of the form `ax^2 + bxy + cy^2 + dx + ey + f = 0` can be transformed to an equivalent form `X^2 - DY^2 = N`. >>> from sympy.solvers.diophantine.diophantine import find_DN, diop_DN, transformation_to_DN >>> find_DN(x**2 - 3*x*y + y**2 - 7*x + 5*y - 3) (5, 920) So, the above equation is equivalent to the equation `X^2 - 5Y^2 = 920` after a linear transformation. If we want to find the linear transformation, we can use :py:meth:`~sympy.solvers.diophantine.diophantine.transformation_to_DN` >>> A, B = transformation_to_DN(x**2 - 3*x*y + y**2 - 7*x + 5*y - 3) Here A is a 2 X 2 matrix and B is a 2 X 1 matrix such that the transformation .. math:: \begin{bmatrix} X\\Y \end{bmatrix} = A \begin{bmatrix} x\\y \end{bmatrix} + B gives the equation `X^2 -5Y^2 = 920`. Values of `A` and `B` are as belows. >>> A Matrix([ [1/10, 3/10], [ 0, 1/5]]) >>> B Matrix([ [ 1/5], [-11/5]]) We can solve an equation of the form `X^2 - DY^2 = N` by passing `D` and `N` to :py:meth:`~sympy.solvers.diophantine.diophantine.diop_DN` >>> diop_DN(5, 920) [] Unfortunately, our equation has no solution. Now let's turn to homogeneous ternary quadratic equations. These equations are of the form `ax^2 + by^2 + cz^2 + dxy + eyz + fzx = 0`. These type of equations either have infinitely many solutions or no solutions (except the obvious solution (0, 0, 0)) >>> diophantine(3*x**2 + 4*y**2 - 5*z**2 + 4*x*y + 6*y*z + 7*z*x) {(0, 0, 0)} >>> diophantine(3*x**2 + 4*y**2 - 5*z**2 + 4*x*y - 7*y*z + 7*z*x) {(-16*p**2 + 28*p*q + 20*q**2, 3*p**2 + 38*p*q - 25*q**2, 4*p**2 - 24*p*q + 68*q**2)} If you are only interested in a base solution rather than the parameterized general solution (to be more precise, one of the general solutions), you can use :py:meth:`~sympy.solvers.diophantine.diophantine.diop_ternary_quadratic`. >>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic >>> diop_ternary_quadratic(3*x**2 + 4*y**2 - 5*z**2 + 4*x*y - 7*y*z + 7*z*x) (-4, 5, 1) :py:meth:`~sympy.solvers.diophantine.diophantine.diop_ternary_quadratic` first converts the given equation to an equivalent equation of the form `w^2 = AX^2 + BY^2` and then it uses :py:meth:`~sympy.solvers.diophantine.diophantine.descent` to solve the latter equation. You can refer to the docs of :py:meth:`~sympy.solvers.diophantine.diophantine.transformation_to_normal` to find more on this. The equation `w^2 = AX^2 + BY^2` can be solved more easily by using the Aforementioned :py:meth:`~sympy.solvers.diophantine.diophantine.descent`. >>> from sympy.solvers.diophantine.diophantine import descent >>> descent(3, 1) # solves the equation w**2 = 3*Y**2 + Z**2 (1, 0, 1) Here the solution tuple is in the order (w, Y, Z) The extended Pythagorean equation, `a_{1}x_{1}^2 + a_{2}x_{2}^2 + \ldots + a_{n}x_{n}^2 = a_{n+1}x_{n+1}^2` and the general sum of squares equation, `x_{1}^2 + x_{2}^2 + \ldots + x_{n}^2 = k` can also be solved using the Diophantine module. >>> from sympy.abc import a, b, c, d, e, f >>> diophantine(9*a**2 + 16*b**2 + c**2 + 49*d**2 + 4*e**2 - 25*f**2) {(70*t1**2 + 70*t2**2 + 70*t3**2 + 70*t4**2 - 70*t5**2, 105*t1*t5, 420*t2*t5, 60*t3*t5, 210*t4*t5, 42*t1**2 + 42*t2**2 + 42*t3**2 + 42*t4**2 + 42*t5**2)} function :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_pythagorean` can also be called directly to solve the same equation. Either you can call :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_pythagorean` or use the high level API. For the general sum of squares, this is also true, but one advantage of calling :py:meth:`~sympy.solvers.diophantine.diophantine.diop_general_sum_of_squares` is that you can control how many solutions are returned. >>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_squares >>> eq = a**2 + b**2 + c**2 + d**2 - 18 >>> diophantine(eq) {(0, 0, 3, 3), (0, 1, 1, 4), (1, 2, 2, 3)} >>> diop_general_sum_of_squares(eq, 2) {(0, 0, 3, 3), (1, 2, 2, 3)} The :py:meth:`~sympy.solvers.diophantine.diophantine.sum_of_squares` routine will providean iterator that returns solutions and one may control whether the solutions contain zeros or not (and the solutions not containing zeros are returned first): >>> from sympy.solvers.diophantine.diophantine import sum_of_squares >>> sos = sum_of_squares(18, 4, zeros=True) >>> next(sos) (1, 2, 2, 3) >>> next(sos) (0, 0, 3, 3) Simple Eqyptian fractions can be found with the Diophantine module, too. For example, here are the ways that one might represent 1/2 as a sum of two unit fractions: >>> from sympy import Eq, S >>> diophantine(Eq(1/x + 1/y, S(1)/2)) {(-2, 1), (1, -2), (3, 6), (4, 4), (6, 3)} To get a more thorough understanding of the Diophantine module, please refer to the following blog. http://thilinaatsympy.wordpress.com/ References ---------- .. [1] Andreescu, Titu. Andrica, Dorin. Cucurezeanu, Ion. An Introduction to Diophantine Equations .. [2] Diophantine Equation, Wolfram Mathworld, [online]. Available: http://mathworld.wolfram.com/DiophantineEquation.html .. [3] Methods to solve Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0,[online], Available: http://www.alpertron.com.ar/METHODS.HTM .. [4] Solving the equation ax^2+ bxy + cy^2 + dx + ey + f= 0, [online], Available: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf User Functions -------------- This functions is imported into the global namespace with ``from sympy import *``: diophantine ^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diophantine And this function is imported with ``from sympy.solvers.diophantine import *``: classify_diop ^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::classify_diop Internal Functions ------------------ These functions are intended for internal use in the Diophantine module. diop_solve ^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_solve diop_linear ^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_linear base_solution_linear ^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::base_solution_linear diop_quadratic ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_quadratic diop_DN ^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_DN cornacchia ^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::cornacchia diop_bf_DN ^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_bf_DN transformation_to_DN ^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::transformation_to_DN transformation_to_normal ^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::transformation_to_normal find_DN ^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::find_DN diop_ternary_quadratic ^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_ternary_quadratic square_factor ^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::square_factor descent ^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::descent diop_general_pythagorean ^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_general_pythagorean diop_general_sum_of_squares ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_general_sum_of_squares diop_general_sum_of_even_powers ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_general_sum_of_even_powers power_representation ^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::power_representation partition ^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::partition sum_of_three_squares ^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::sum_of_three_squares sum_of_four_squares ^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::sum_of_four_squares sum_of_powers ^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::sum_of_powers sum_of_squares ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::sum_of_squares merge_solution ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::merge_solution divisible ^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::divisible PQa ^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::PQa equivalent ^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::equivalent parametrize_ternary_quadratic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::parametrize_ternary_quadratic diop_ternary_quadratic_normal ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::diop_ternary_quadratic_normal ldescent ^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::ldescent gaussian_reduce ^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::gaussian_reduce holzer ^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::holzer prime_as_sum_of_two_squares ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::prime_as_sum_of_two_squares sqf_normal ^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::sqf_normal reconstruct ^^^^^^^^^^^ .. autofunction:: sympy.solvers.diophantine.diophantine::reconstruct Internal Classes ------------------ These classes are intended for internal use in the Diophantine module. DiophantineSolutionSet ^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.DiophantineSolutionSet :members: DiophantineEquationType ^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.DiophantineEquationType :members: Univariate ^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.Univariate :members: Linear ^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.Linear :members: BinaryQuadratic ^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.BinaryQuadratic :members: InhomogeneousTernaryQuadratic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.InhomogeneousTernaryQuadratic :members: HomogeneousTernaryQuadraticNormal ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.HomogeneousTernaryQuadraticNormal :members: HomogeneousTernaryQuadratic ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.HomogeneousTernaryQuadratic :members: InhomogeneousGeneralQuadratic ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.InhomogeneousGeneralQuadratic :members: HomogeneousGeneralQuadratic ^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.HomogeneousGeneralQuadratic :members: GeneralSumOfSquares ^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.GeneralSumOfSquares :members: GeneralPythagorean ^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.GeneralPythagorean :members: CubicThue ^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.CubicThue :members: GeneralSumOfEvenPowers ^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.diophantine.diophantine.GeneralSumOfEvenPowers :members: sympy-sympy-1.9/doc/src/modules/solvers/inequalities.rst000066400000000000000000000007011412543434000236500ustar00rootroot00000000000000.. _inequality-docs: Inequality Solvers ================== .. module:: sympy.solvers.inequalities .. autofunction:: solve_rational_inequalities .. autofunction:: solve_poly_inequality .. autofunction:: solve_poly_inequalities .. autofunction:: reduce_rational_inequalities .. autofunction:: reduce_abs_inequality .. autofunction:: reduce_abs_inequalities .. autofunction:: reduce_inequalities .. autofunction:: solve_univariate_inequality sympy-sympy-1.9/doc/src/modules/solvers/ode.rst000066400000000000000000000247261412543434000217400ustar00rootroot00000000000000.. _ode-docs: ODE === .. module::sympy.solvers.ode .. automodule:: sympy.solvers.ode User Functions -------------- These are functions that are imported into the global namespace with ``from sympy import *``. These functions (unlike `Hint Functions`_, below) are intended for use by ordinary users of SymPy. dsolve ^^^^^^ .. autofunction:: sympy.solvers.ode::dsolve dsolve_system ^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.systems::dsolve_system classify_ode ^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode::classify_ode checkodesol ^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode::checkodesol homogeneous_order ^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode::homogeneous_order infinitesimals ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode::infinitesimals checkinfsol ^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode::checkinfsol constantsimp ^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode::constantsimp Hint Functions -------------- These functions are intended for internal use by :py:meth:`~sympy.solvers.ode.dsolve` and others. Unlike `User Functions`_, above, these are not intended for every-day use by ordinary SymPy users. Instead, functions such as :py:meth:`~sympy.solvers.ode.dsolve` should be used. Nonetheless, these functions contain useful information in their docstrings on the various ODE solving methods. For this reason, they are documented here. allhints ^^^^^^^^ .. autodata:: sympy.solvers.ode::allhints odesimp ^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::odesimp constant_renumber ^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::constant_renumber sol_simplicity ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::ode_sol_simplicity factorable ^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::Factorable :members: 1st_exact ^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single.FirstExact :members: 1st_homogeneous_coeff_best ^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::HomogeneousCoeffBest :members: 1st_homogeneous_coeff_subs_dep_div_indep ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::HomogeneousCoeffSubsDepDivIndep :members: 1st_homogeneous_coeff_subs_indep_div_dep ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::HomogeneousCoeffSubsIndepDivDep :members: 1st_linear ^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::FirstLinear :members: 1st_rational_riccati ^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::RationalRiccati :members: 2nd_linear_airy ^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::SecondLinearAiry :members: 2nd_linear_bessel ^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::SecondLinearBessel :members: Bernoulli ^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::Bernoulli :members: Liouville ^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::Liouville :members: Riccati_special_minus2 ^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::RiccatiSpecial :members: nth_linear_constant_coeff_homogeneous ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthLinearConstantCoeffHomogeneous :members: nth_linear_constant_coeff_undetermined_coefficients ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthLinearConstantCoeffUndeterminedCoefficients :members: nth_linear_constant_coeff_variation_of_parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthLinearConstantCoeffVariationOfParameters :members: nth_linear_euler_eq_homogeneous ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthLinearEulerEqHomogeneous :members: nth_linear_euler_eq_nonhomogeneous_variation_of_parameters ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthLinearEulerEqNonhomogeneousVariationOfParameters :members: nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthLinearEulerEqNonhomogeneousUndeterminedCoefficients :members: nth_algebraic ^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthAlgebraic :members: nth_order_reducible ^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::NthOrderReducible :members: separable ^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::Separable :members: almost_linear ^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::AlmostLinear :members: linear_coefficients ^^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::LinearCoefficients :members: separable_reduced ^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::SeparableReduced :members: lie_group ^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::LieGroup :members: 2nd_hypergeometric ^^^^^^^^^^^^^^^^^^ .. autoclass:: sympy.solvers.ode.single::SecondHypergeometric :members: 1st_power_series ^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::ode_1st_power_series 2nd_power_series_ordinary ^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::ode_2nd_power_series_ordinary 2nd_power_series_regular ^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::ode_2nd_power_series_regular Lie heuristics -------------- These functions are intended for internal use of the Lie Group Solver. Nonetheless, they contain useful information in their docstrings on the algorithms implemented for the various heuristics. abaco1_simple ^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_abaco1_simple abaco1_product ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_abaco1_product bivariate ^^^^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_bivariate chi ^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_chi abaco2_similar ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_abaco2_similar function_sum ^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_function_sum abaco2_unique_unknown ^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_abaco2_unique_unknown abaco2_unique_general ^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_abaco2_unique_general linear ^^^^^^ .. autofunction:: sympy.solvers.ode.lie_group::lie_heuristic_linear Rational Riccati Solver ----------------------- These functions are intended for internal use to solve a first order Riccati differential equation with atleast one rational particular solution. riccati_normal ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::riccati_normal riccati_inverse_normal ^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::riccati_inverse_normal riccati_reduced ^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::riccati_reduced construct_c ^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::construct_c construct_d ^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::construct_d rational_laurent_series ^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::rational_laurent_series compute_m_ybar ^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::compute_m_ybar solve_aux_eq ^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::solve_aux_eq remove_redundant_sols ^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::remove_redundant_sols get_gen_sol_from_part_sol ^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::get_gen_sol_from_part_sol solve_riccati ^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.riccati::solve_riccati System of ODEs -------------- These functions are intended for internal use by :py:meth:`~sympy.solvers.ode.dsolve` for system of differential equations. Linear, 2 equations, Order 1, Type 6 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_linear_2eq_order1_type6 Linear, 2 equations, Order 1, Type 7 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_linear_2eq_order1_type7 Linear ODE to matrix ^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.systems::linear_ode_to_matrix Canonical Equations Converter ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.systems::canonical_odes LinODESolve Systems Information ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.systems::linodesolve_type Matrix Exponential Jordan Form ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.systems::matrix_exp_jordan_form Matrix Exponential ^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.systems::matrix_exp Linear, n equations, Order 1 Solver ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.systems::linodesolve Nonlinear, 2 equations, Order 1, Type 1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_2eq_order1_type1 Nonlinear, 2 equations, Order 1, Type 2 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_2eq_order1_type2 Nonlinear, 2 equations, Order 1, Type 3 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_2eq_order1_type3 Nonlinear, 2 equations, Order 1, Type 4 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_2eq_order1_type4 Nonlinear, 2 equations, Order 1, Type 5 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_2eq_order1_type5 Nonlinear, 3 equations, Order 1, Type 1 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_3eq_order1_type1 Nonlinear, 3 equations, Order 1, Type 2 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_3eq_order1_type2 Nonlinear, 3 equations, Order 1, Type 3 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_3eq_order1_type3 Nonlinear, 3 equations, Order 1, Type 4 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_3eq_order1_type4 Nonlinear, 3 equations, Order 1, Type 5 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.ode.ode::_nonlinear_3eq_order1_type5 Information on the ode module ----------------------------- .. automodule:: sympy.solvers.ode.ode Internal functions ^^^^^^^^^^^^^^^^^^ These functions are not intended for end-user use. .. autofunction:: sympy.solvers.ode.ode::_handle_Integral sympy-sympy-1.9/doc/src/modules/solvers/pde.rst000066400000000000000000000024721412543434000217330ustar00rootroot00000000000000.. _pde-docs: PDE === .. module::sympy.solvers.pde User Functions -------------- These are functions that are imported into the global namespace with ``from sympy import *``. They are intended for user use. pde_separate ^^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::pde_separate pde_separate_add ^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::pde_separate_add pde_separate_mul ^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::pde_separate_mul pdsolve ^^^^^^^ .. autofunction:: sympy.solvers.pde::pdsolve classify_pde ^^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::classify_pde checkpdesol ^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::checkpdesol Hint Methods ------------ These functions are meant for internal use. However they contain useful information on the various solving methods. pde_1st_linear_constant_coeff_homogeneous ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::pde_1st_linear_constant_coeff_homogeneous pde_1st_linear_constant_coeff ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::pde_1st_linear_constant_coeff pde_1st_linear_variable_coeff ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. autofunction:: sympy.solvers.pde::pde_1st_linear_variable_coeff Information on the pde module ----------------------------- .. automodule:: sympy.solvers.pde sympy-sympy-1.9/doc/src/modules/solvers/solvers.rst000066400000000000000000000045061412543434000226600ustar00rootroot00000000000000.. _solvers: Solvers ======= .. module:: sympy.solvers The *solvers* module in SymPy implements methods for solving equations. .. note:: It is recommended to use :func:`solveset` to solve univariate equations, :func:`~.linsolve` to solve system of linear equations instead of :func:`~sympy.solvers.solvers.solve` and :func:`~.nonlinsolve` to solve system of non linear equations since sooner or later the :func:`~.solveset` will take over :func:`~sympy.solvers.solvers.solve` either internally or externally. Algebraic equations -------------------- Use :func:`~sympy.solvers.solvers.solve` to solve algebraic equations. We suppose all equations are equaled to 0, so solving x**2 == 1 translates into the following code:: >>> from sympy.solvers import solve >>> from sympy import Symbol >>> x = Symbol('x') >>> solve(x**2 - 1, x) [-1, 1] The first argument for :func:`~sympy.solvers.solvers.solve` is an equation (equaled to zero) and the second argument is the symbol that we want to solve the equation for. .. autofunction:: sympy.solvers.solvers::solve .. autofunction:: sympy.solvers.solvers::solve_linear .. autofunction:: sympy.solvers.solvers::solve_linear_system .. autofunction:: sympy.solvers.solvers::solve_linear_system_LU .. autofunction:: sympy.solvers.solvers::solve_undetermined_coeffs .. autofunction:: sympy.solvers.solvers::nsolve .. autofunction:: sympy.solvers.solvers::checksol .. autofunction:: sympy.solvers.solvers::unrad Ordinary Differential equations (ODEs) -------------------------------------- See :ref:`ode-docs`. Partial Differential Equations (PDEs) ------------------------------------- See :ref:`pde-docs`. Deutils (Utilities for solving ODE's and PDE's) ----------------------------------------------- .. autofunction:: sympy.solvers.deutils::ode_order Recurrence Equations -------------------- .. module:: sympy.solvers.recurr .. autofunction:: rsolve .. autofunction:: rsolve_poly .. autofunction:: rsolve_ratio .. autofunction:: rsolve_hyper Systems of Polynomial Equations ------------------------------- .. autofunction:: sympy.solvers.polysys::solve_poly_system .. autofunction:: sympy.solvers.polysys::solve_triangulated Diophantine Equations (DEs) --------------------------- See :ref:`diophantine-docs` Inequalities ------------ See :ref:`inequality-docs` sympy-sympy-1.9/doc/src/modules/solvers/solveset.rst000066400000000000000000000537531412543434000230370ustar00rootroot00000000000000.. _solveset: Solveset ======== .. module:: sympy.solvers.solveset This is the official documentation of the ``solveset`` module in solvers. It contains the frequently asked questions about our new module to solve equations. What's wrong with solve(): -------------------------- SymPy already has a pretty powerful ``solve`` function. But it has a lot of major issues 1. It doesn't have a consistent output for various types of solutions It needs to return a lot of types of solutions consistently: * Single solution : `x = 1` * Multiple solutions: `x^2 = 1` * No Solution: `x^2 + 1 = 0 ; x \in \mathbb{R}` * Interval of solution: `\lfloor x \rfloor = 0` * Infinitely many solutions: `sin(x) = 0` * Multivariate functions with point solutions: `x^2 + y^2 = 0` * Multivariate functions with non-point solution: `x^2 + y^2 = 1` * System of equations: `x + y = 1` and `x - y = 0` * Relational: `x > 0` * And the most important case: "We don't Know" 2. The input API is also a mess, there are a lot of parameters. Many of them are not needed and they make it hard for the user and the developers to work on solvers. 3. There are cases like finding the maxima and minima of function using critical points where it is important to know if it has returned all the solutions. ``solve`` does not guarantee this. Why Solveset? ------------- * ``solveset`` has a cleaner input and output interface: ``solveset`` returns a set object and a set object takes care of all types of output. For cases where it doesn't "know" all the solutions a ``ConditionSet`` with a partial solution is returned. For input it only takes the equation, the variables to solve for and the optional argument ``domain`` over which the equation is to be solved. * ``solveset`` can return infinitely many solutions. For example solving for `\sin{(x)} = 0` returns `\{2 n \pi | n \in \mathbb{Z}\} \cup \{2 n \pi + \pi | n \in \mathbb{Z}\}`, whereas ``solve`` only returns `[0, \pi]`. * There is a clear code level and interface level separation between solvers for equations in the complex domain and the real domain. For example solving `e^x = 1` when `x` is to be solved in the complex domain, returns the set of all solutions, that is `\{2 n i \pi | n \in \mathbb{Z}\}`, whereas if `x` is to be solved in the real domain then only `\{0\}` is returned. Why do we use Sets as an output type? ------------------------------------- SymPy has a well developed sets module, which can represent most of the set containers in Mathematics such as: * ``FiniteSet`` Represents a finite set of discrete numbers. * ``Interval`` Represents a real interval as a set. * ``ProductSet`` Represents a Cartesian product of sets. * ``ImageSet`` Represents the image of a set under a mathematical function >>> from sympy import ImageSet, S, Lambda >>> from sympy.abc import x >>> squares = ImageSet(Lambda(x, x**2), S.Naturals) # {x**2 for x in N} >>> 4 in squares True * ``ComplexRegion`` Represents the set of all complex numbers in a region in the Argand plane. * ``ConditionSet`` Represents the set of elements, which satisfies a given condition. Also, the predefined set classes such as: * ``Naturals`` `\mathbb{N}` Represents the natural numbers (or counting numbers), which are all positive integers starting from 1. * ``Naturals0`` `\mathbb{N_0}` Represents the whole numbers, which are all the non-negative integers, inclusive of 0. * ``Integers`` `\mathbb{Z}` Represents all integers: positive, negative and zero. * ``Reals`` `\mathbb{R}` Represents the set of all real numbers. * ``Complexes`` `\mathbb{C}` Represents the set of all complex numbers. * ``EmptySet`` `\phi` Represents the empty set. The above six sets are available as Singletons, like ``S.Integers``. It is capable of most of the set operations in mathematics: * ``Union`` * ``Intersection`` * ``Complement`` * ``SymmetricDifference`` The main reason for using sets as output to solvers is that it can consistently represent many types of solutions. For the single variable case it can represent: * No solution (by the empty set). * Finitely many solutions (by ``FiniteSet``). * Infinitely many solutions, both countably and uncountably infinite solutions (using the ``ImageSet`` module). * ``Interval`` * There can also be bizarre solutions to equations like the set of rational numbers. No other Python object (list, dictionary, generator, Python sets) provides the flexibility of mathematical sets which our sets module tries to emulate. The second reason to use sets is that they are close to the entities which mathematicians deal with and it makes it easier to reason about them. Set objects conform to Pythonic conventions when possible, i.e., ``x in A`` and ``for i in A`` both work when they can be computed. Another advantage of using objects closer to mathematical entities is that the user won't have to "learn" our representation and she can have her expectations transferred from her mathematical experience. For the multivariate case we represent solutions as a set of points in a n-dimensional space and a point is represented by a ``FiniteSet`` of ordered tuples, which is a point in `\mathbb{R}^n` or `\mathbb{C}^n`. Please note that, the general ``FiniteSet`` is unordered, but a ``FiniteSet`` with a tuple as its only argument becomes ordered, since a tuple is ordered. So the order in the tuple is mapped to a pre-defined order of variables while returning solutions. For example: >>> from sympy import FiniteSet >>> FiniteSet(1, 2, 3) # Unordered {1, 2, 3} >>> FiniteSet((1, 2, 3)) # Ordered {(1, 2, 3)} Why not use dicts as output? Dictionary are easy to deal with programmatically but mathematically they are not very precise and use of them can quickly lead to inconsistency and a lot of confusion. For example: * There are a lot of cases where we don't know the complete solution and we may like to output a partial solution, consider the equation `fg = 0`. The solution of this equation is the union of the solution of the following two equations: `f = 0`, `g = 0`. Let's say that we are able to solve `f = 0` but solving `g = 0` isn't supported yet. In this case we cannot represent partial solution of the given equation `fg = 0` using dicts. This problem is solved with sets using a ``ConditionSet`` object: `sol_f \cup \{x | x ∊ \mathbb{R} ∧ g = 0\}`, where `sol_f` is the solution of the equation `f = 0`. * Using a dict may lead to surprising results like: - ``solve(Eq(x**2, 1), x) != solve(Eq(y**2, 1), y)`` Mathematically, this doesn't make sense. Using ``FiniteSet`` here solves the problem. * It also cannot represent solutions for equations like `|x| < 1`, which is a disk of radius 1 in the Argand Plane. This problem is solved using complex sets implemented as ``ComplexRegion``. Input API of ``solveset`` ------------------------- ``solveset`` has a cleaner input API, unlike ``solve``. It takes a maximum of three arguments: ``solveset(equation, variable=None, domain=S.Complexes)`` * Equation(s) The equation(s) to solve. * Variable(s) The variable(s) for which the equation is to be solved. * Domain The domain in which the equation is to be solved. ``solveset`` removes the ``flags`` argument of ``solve``, which had made the input API messy and output API inconsistent. What is this domain argument about? ----------------------------------- Solveset is designed to be independent of the assumptions on the variable being solved for and instead, uses the ``domain`` argument to decide the solver to dispatch the equation to, namely ``solveset_real`` or ``solveset_complex``. It's unlike the old ``solve`` which considers the assumption on the variable. >>> from sympy import solveset, S >>> from sympy.abc import x >>> solveset(x**2 + 1, x) # domain=S.Complexes is default {-I, I} >>> solveset(x**2 + 1, x, domain=S.Reals) EmptySet What are the general methods employed by solveset to solve an equation? ----------------------------------------------------------------------- Solveset uses various methods to solve an equation, here is a brief overview of the methodology: * The ``domain`` argument is first considered to know the domain in which the user is interested to get the solution. * If the given function is a relational (``>=``, ``<=``, ``>``, ``<``), and the domain is real, then ``solve_univariate_inequality`` and solutions are returned. Solving for complex solutions of inequalities, like `x^2 < 0` is not yet supported. * Based on the ``domain``, the equation is dispatched to one of the two functions ``solveset_real`` or ``solveset_complex``, which solves the given equation in the complex or real domain, respectively. * If the given expression is a product of two or more functions, like say `gh = 0`, then the solution to the given equation is the Union of the solution of the equations `g = 0` and `h = 0`, if and only if both `g` and `h` are finite for a finite input. So, the solution is built up recursively. * If the function is trigonometric or hyperbolic, the function ``_solve_real_trig`` is called, which solves it by converting it to complex exponential form. * The function is now checked if there is any instance of a ``Piecewise`` expression, if it is, then it's converted to explicit expression and set pairs and then solved recursively. * The respective solver now tries to invert the equation using the routines ``invert_real`` and ``invert_complex``. These routines are based on the concept of mathematical inverse (though not exactly). It reduces the real/complex valued equation `f(x) = y` to a set of equations: `\{g(x) = h_1(y), g(x) = h_2(y), ..., g(x) = h_n(y) \}` where `g(x)` is a simpler function than `f(x)`. There is some work needed to be done in this to find invert of more complex expressions. * After the invert, the equations are checked for radical or Abs (Modulus), then the method ``_solve_radical`` tries to simplify the radical, by removing it using techniques like squaring, cubing etc, and ``_solve_abs`` solves nested Modulus by considering the positive and negative variants, iteratively. * If none of the above method is successful, then methods of polynomial is used as follows: - The method to solve the rational function, ``_solve_as_rational``, is called. Based on the domain, the respective poly solver ``_solve_as_poly_real`` or ``_solve_as_poly_complex`` is called to solve ``f`` as a polynomial. - The underlying method ``_solve_as_poly`` solves the equation using polynomial techniques if it's already a polynomial equation or, with a change of variables, can be made so. * The final solution set returned by ``solveset`` is the intersection of the set of solutions found above and the input domain. .. Remember to change the above part when the new solver is implemented. How do we manipulate and return an infinite solution? ----------------------------------------------------- * In the real domain, we use our ``ImageSet`` class in the sets module to return infinite solutions. ``ImageSet`` is an image of a set under a mathematical function. For example, to represent the solution of the equation `\sin{(x)} = 0`, we can use the ``ImageSet`` as: >>> from sympy import ImageSet, Lambda, pi, S, Dummy, pprint >>> n = Dummy('n') >>> pprint(ImageSet(Lambda(n, 2*pi*n), S.Integers), use_unicode=True) {2⋅n⋅π │ n ∊ ℤ} Where ``n`` is a dummy variable. It is basically the image of the set of integers under the function `2\pi n`. * In the complex domain, we use complex sets, which are implemented as the ``ComplexRegion`` class in the sets module, to represent infinite solution in the Argand plane. For example to represent the solution of the equation `|z| = 1`, which is a unit circle, we can use the ``ComplexRegion`` as: >>> from sympy import ComplexRegion, FiniteSet, Interval, pi, pprint >>> pprint(ComplexRegion(FiniteSet(1)*Interval(0, 2*pi), polar=True), use_unicode=True) {r⋅(ⅈ⋅sin(θ) + cos(θ)) │ r, θ ∊ {1} × [0, 2⋅π)} Where the ``FiniteSet`` in the ``ProductSet`` is the range of the value of `r`, which is the radius of the circle and the ``Interval`` is the range of `\theta`, the angle from the `x` axis representing a unit circle in the Argand plane. Note: We also have non-polar form notation for representing solution in rectangular form. For example, to represent first two quadrants in the Argand plane, we can write the ``ComplexRegion`` as: >>> from sympy import ComplexRegion, Interval, pi, oo, pprint >>> pprint(ComplexRegion(Interval(-oo, oo)*Interval(0, oo)), use_unicode=True) {x + y⋅ⅈ │ x, y ∊ (-∞, ∞) × [0, ∞)} where the Intervals are the range of `x` and `y` for the set of complex numbers `x + iy`. How does ``solveset`` ensure that it is not returning any wrong solution? -------------------------------------------------------------------------- Solvers in a Computer Algebra System are based on heuristic algorithms, so it's usually very hard to ensure 100% percent correctness, in every possible case. However there are still a lot of cases where we can ensure correctness. Solveset tries to verify correctness wherever it can. For example: Consider the equation `|x| = n`. A naive method to solve this equation would return ``{-n, n}`` as its solution, which is not correct since ``{-n, n}`` can be its solution if and only if ``n`` is positive. Solveset returns this information as well to ensure correctness. >>> from sympy import symbols, S, pprint, solveset >>> x, n = symbols('x, n') >>> pprint(solveset(abs(x) - n, x, domain=S.Reals), use_unicode=True) {x │ x ∊ {-n, n} ∧ (n ∈ [0, ∞))} Though, there still a lot of work needs to be done in this regard. Search based solver and step-by-step solution --------------------------------------------- Note: This is under Development. After the introduction of :py:class:`~sympy.sets.conditionset.ConditionSet`, the solving of equations can be seen as set transformations. Here is an abstract view of the things we can do to solve equations. * Apply various set transformations on the given set. * Define a metric of the usability of solutions, or a notion of some solutions being better than others. * Different transformations would be the nodes of a tree. * Suitable searching techniques could be applied to get the best solution. ``ConditionSet`` gives us the ability to represent unevaluated equations and inequalities in forms like `\{x|f(x)=0; x \in S\}` and `\{x|f(x)>0; x \in S\}` but a more powerful thing about ``ConditionSet`` is that it allows us to write the intermediate steps as set to set transformation. Some of the transformations are: * Composition: `\{x|f(g(x))=0;x \in S\} \Rightarrow \{x|g(x)=y; x \in S, y \in \{z|f(z)=0; z \in S\}\}` * Polynomial Solver: `\{x | P(x) = 0;x \in S\} \Rightarrow \{x_1,x_2, ... ,x_n\} \cap S`, where `x_i` are roots of `P(x)`. * Invert solver: `\{x|f(x)=0;x \in S\} \Rightarrow \{g(0)| \text{ all g such that } f(g(x)) = x\}` * logcombine: `\{x| \log(f(x)) + \log(g(x));x \in S\}` `\Rightarrow \{x| \log(f(x).g(x)); x \in S\} \text{ if } f(x) > 0 \text{ and } g(x) > 0` `\Rightarrow \{x| \log(f(x)) + \log(g(x));x \in S\} \text{ otherwise}` * product solve: `\{x|f(x)g(x)=0; x \in S\}` `\Rightarrow \{x|f(x)=0; x \in S\} U \{x|g(x)=0; x \in S\}` `\text{ given } f(x) \text{ and } g(x) \text{ are bounded.}` `\Rightarrow \{x|f(x)g(x)=0; x \in S\}, \text{ otherwise}` Since the output type is same as the input type any composition of these transformations is also a valid transformation. And our aim is to find the right sequence of compositions (given the atoms) which transforms the given condition set to a set which is not a condition set i.e., FiniteSet, Interval, Set of Integers and their Union, Intersection, Complement or ImageSet. We can assign a cost function to each set, such that, the more desirable that form of set is to us, the less the value of the cost function. This way our problem is now reduced to finding the path from the initial ConditionSet to the lowest valued set on a graph where the atomic transformations forms the edges. How do we deal with cases where only some of the solutions are known? --------------------------------------------------------------------- Creating a universal equation solver, which can solve each and every equation we encounter in mathematics is an ideal case for solvers in a Computer Algebra System. When cases which are not solved or can only be solved incompletely, a ``ConditionSet`` is used and acts as an unevaluated solveset object. Note that, mathematically, finding a complete set of solutions for an equation is undecidable. See `Richardson's theorem `_. ``ConditionSet`` is basically a Set of elements which satisfy a given condition. For example, to represent the solutions of the equation in the real domain: .. math:: (x^2 - 4)(\sin(x) + x) We can represent it as: `\{-2, 2\} ∪ \{x | x \in \mathbb{R} ∧ x + \sin(x) = 0\}` What will you do with the old solve? ------------------------------------ There are still a few things ``solveset`` can't do, which the old ``solve`` can, such as solving nonlinear multivariate & LambertW type equations. Hence, it's not yet a perfect replacement for old ``solve``. The ultimate goal is to: * Replace ``solve`` with ``solveset`` once solveset is at least as powerful as ``solve``, i.e., ``solveset`` does everything that ``solve`` can do currently, and * eventually rename ``solveset`` to ``solve``. How are symbolic parameters handled in solveset? ------------------------------------------------ Solveset is in its initial phase of development, so the symbolic parameters aren't handled well for all the cases, but some work has been done in this regard to depict our ideology towards symbolic parameters. As an example, consider the solving of `|x| = n` for real `x`, where `n` is a symbolic parameter. Solveset returns the value of `x` considering the domain of the symbolic parameter `n` as well: .. math:: ([0, \infty) \cap \{n\}) \cup ((-\infty, 0] \cap \{-n\}). This simply means `n` is the solution only when it belongs to the ``Interval`` `[0, \infty)` and `-n` is the solution only when `-n` belongs to the ``Interval`` `(- \infty, 0]`. There are other cases to address too, like solving `2^x + (a - 2)` for `x` where `a` is a symbolic parameter. As of now, It returns the solution as an intersection with `\mathbb{R}`, which is trivial, as it doesn't reveal the domain of `a` in the solution. Recently, we have also implemented a function to find the domain of the expression in a FiniteSet (Intersection with the interval) in which it is not-empty. It is a useful addition for dealing with symbolic parameters. For example: >>> from sympy import Symbol, FiniteSet, Interval, not_empty_in, sqrt, oo >>> from sympy.abc import x >>> not_empty_in(FiniteSet(x/2).intersect(Interval(0, 1)), x) Interval(0, 2) >>> not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x) Union(Interval(1, 2), Interval(-sqrt(2), -1)) References ---------- .. [1] https://github.com/sympy/sympy/wiki/GSoC-2015-Ideas#solvers .. [2] https://github.com/sympy/sympy/wiki/GSoC-2014-Application-Harsh-Gupta:-Solvers .. [3] https://github.com/sympy/sympy/wiki/GSoC-2015-Application-AMiT-Kumar--Solvers-:-Extending-Solveset .. [5] http://iamit.in/blog/ .. [6] https://github.com/sympy/sympy/pull/2948 : Action Plan for improving solvers. .. [7] https://github.com/sympy/sympy/issues/6659 : ``solve()`` is a giant mess .. [8] https://github.com/sympy/sympy/pull/7523 : ``solveset`` PR .. [9] https://groups.google.com/forum/#!topic/sympy/-SIbX0AFL3Q .. [10] https://github.com/sympy/sympy/pull/9696 .. [11] https://en.wikipedia.org/wiki/Richardson%27s_theorem Solveset Module Reference ------------------------- Use :func:`solveset` to solve equations or expressions (assumed to be equal to 0) for a single variable. Solving an equation like `x^2 == 1` can be done as follows:: >>> from sympy import solveset >>> from sympy import Symbol, Eq >>> x = Symbol('x') >>> solveset(Eq(x**2, 1), x) {-1, 1} Or one may manually rewrite the equation as an expression equal to 0:: >>> solveset(x**2 - 1, x) {-1, 1} The first argument for :func:`solveset` is an expression (equal to zero) or an equation and the second argument is the symbol that we want to solve the equation for. .. autofunction:: sympy.solvers.solveset::solveset .. autofunction:: sympy.solvers.solveset::solveset_real .. autofunction:: sympy.solvers.solveset::solveset_complex .. autofunction:: sympy.solvers.solveset::invert_real .. autofunction:: sympy.solvers.solveset::invert_complex .. autofunction:: sympy.solvers.solveset::domain_check .. autofunction:: sympy.solvers.solveset::solvify linear_eq_to_matrix ------------------- .. autofunction:: sympy.solvers.solveset::linear_eq_to_matrix linsolve -------- .. autofunction:: sympy.solvers.solveset::linsolve nonlinsolve ----------- .. autofunction:: sympy.solvers.solveset::nonlinsolve transolve --------- .. autofunction:: sympy.solvers.solveset::_transolve .. autofunction:: sympy.solvers.solveset::_is_exponential .. autofunction:: sympy.solvers.solveset::_solve_exponential .. autofunction:: sympy.solvers.solveset::_solve_logarithm .. autofunction:: sympy.solvers.solveset::_is_logarithmic Diophantine Equations (DEs) --------------------------- See :ref:`diophantine-docs` Inequalities ------------ See :ref:`inequality-docs` Ordinary Differential equations (ODEs) -------------------------------------- See :ref:`ode-docs`. Partial Differential Equations (PDEs) ------------------------------------- See :ref:`pde-docs`. sympy-sympy-1.9/doc/src/modules/stats.rst000066400000000000000000000171331412543434000206240ustar00rootroot00000000000000===== Stats ===== .. automodule:: sympy.stats Random Variable Types ^^^^^^^^^^^^^^^^^^^^^ Finite Types ------------ .. autofunction:: DiscreteUniform .. autofunction:: Die .. autofunction:: Bernoulli .. autofunction:: Coin .. autofunction:: Binomial .. autofunction:: BetaBinomial .. autofunction:: Hypergeometric .. autofunction:: FiniteRV .. autofunction:: Rademacher Discrete Types -------------- .. autofunction:: Geometric .. autofunction:: Hermite .. autofunction:: Poisson .. autofunction:: Logarithmic .. autofunction:: NegativeBinomial .. autofunction:: Skellam .. autofunction:: YuleSimon .. autofunction:: Zeta Continuous Types ---------------- .. autofunction:: Arcsin .. autofunction:: Benini .. autofunction:: Beta .. autofunction:: BetaNoncentral .. autofunction:: BetaPrime .. autofunction:: BoundedPareto .. autofunction:: Cauchy .. autofunction:: Chi .. autofunction:: ChiNoncentral .. autofunction:: ChiSquared .. autofunction:: Dagum .. autofunction:: Erlang .. autofunction:: ExGaussian .. autofunction:: Exponential .. autofunction:: FDistribution .. autofunction:: FisherZ .. autofunction:: Frechet .. autofunction:: Gamma .. autofunction:: GammaInverse .. autofunction:: Gompertz .. autofunction:: Gumbel .. autofunction:: Kumaraswamy .. autofunction:: Laplace .. autofunction:: Levy .. autofunction:: Logistic .. autofunction:: LogLogistic .. autofunction:: LogNormal .. autofunction:: Lomax .. autofunction:: Maxwell .. autofunction:: Moyal .. autofunction:: Nakagami .. autofunction:: Normal .. autofunction:: Pareto .. autofunction:: PowerFunction .. autofunction:: QuadraticU .. autofunction:: RaisedCosine .. autofunction:: Rayleigh .. autofunction:: Reciprocal .. autofunction:: StudentT .. autofunction:: ShiftedGompertz .. autofunction:: Trapezoidal .. autofunction:: Triangular .. autofunction:: Uniform .. autofunction:: UniformSum .. autofunction:: VonMises .. autofunction:: Wald .. autofunction:: Weibull .. autofunction:: WignerSemicircle .. autofunction:: ContinuousRV Joint Types ----------- .. autofunction:: JointRV .. autofunction:: marginal_distribution .. autofunction:: MultivariateNormal .. autofunction:: MultivariateLaplace .. autofunction:: GeneralizedMultivariateLogGamma .. autofunction:: GeneralizedMultivariateLogGammaOmega .. autofunction:: Multinomial .. autofunction:: MultivariateBeta .. autofunction:: MultivariateEwens .. autofunction:: MultivariateT .. autofunction:: NegativeMultinomial .. autofunction:: NormalGamma Stochastic Processes -------------------- .. autoclass:: DiscreteMarkovChain :members: .. autoclass:: ContinuousMarkovChain :members: .. autoclass:: BernoulliProcess :members: .. autoclass:: PoissonProcess :members: .. autoclass:: WienerProcess :members: .. autoclass:: GammaProcess :members: Matrix Distributions -------------------- .. autofunction:: MatrixGamma .. autofunction:: Wishart .. autofunction:: MatrixNormal Compound Distribution --------------------- .. autoclass:: sympy.stats.compound_rv.CompoundDistribution :members: Interface ^^^^^^^^^ .. autofunction:: P .. autoclass:: Probability :members: .. autofunction:: E .. autoclass:: Expectation :members: .. autofunction:: density .. autofunction:: entropy .. autofunction:: given .. autofunction:: where .. autofunction:: variance .. autoclass:: Variance :members: .. autofunction:: covariance .. autoclass:: Covariance :members: .. autofunction:: coskewness .. autofunction:: median .. autofunction:: std .. autofunction:: sample .. autofunction:: sample_iter .. autofunction:: factorial_moment .. autofunction:: kurtosis .. autofunction:: skewness .. autofunction:: correlation .. autofunction:: sympy.stats.rv.sampling_density .. autofunction:: sympy.stats.rv.sampling_P .. autofunction:: sympy.stats.rv.sampling_E .. autoclass:: Moment :members: .. autofunction:: moment .. autoclass:: CentralMoment :members: .. autofunction:: cmoment .. autoclass:: ExpectationMatrix :members: .. autoclass:: VarianceMatrix :members: .. autoclass:: CrossCovarianceMatrix :members: Mechanics ^^^^^^^^^ .. module:: sympy.stats.rv SymPy Stats employs a relatively complex class hierarchy. ``RandomDomain``\s are a mapping of variables to possible values. For example, we might say that the symbol ``Symbol('x')`` can take on the values `\{1,2,3,4,5,6\}`. .. class:: RandomDomain A ``PSpace``, or Probability Space, combines a ``RandomDomain`` with a density to provide probabilistic information. For example the above domain could be enhanced by a finite density ``{1:1/6, 2:1/6, 3:1/6, 4:1/6, 5:1/6, 6:1/6}`` to fully define the roll of a fair die named ``x``. .. class:: PSpace A RandomSymbol represents the PSpace's symbol 'x' inside of SymPy expressions. .. class:: RandomSymbol The RandomDomain and PSpace classes are almost never directly instantiated. Instead they are subclassed for a variety of situations. RandomDomains and PSpaces must be sufficiently general to represent domains and spaces of several variables with arbitrarily complex densities. This generality is often unnecessary. Instead we often build SingleDomains and SinglePSpaces to represent single, univariate events and processes such as a single die or a single normal variable. .. class:: SinglePSpace .. class:: SingleDomain Another common case is to collect together a set of such univariate random variables. A collection of independent SinglePSpaces or SingleDomains can be brought together to form a ProductDomain or ProductPSpace. These objects would be useful in representing three dice rolled together for example. .. class:: ProductDomain .. class:: ProductPSpace The Conditional adjective is added whenever we add a global condition to a RandomDomain or PSpace. A common example would be three independent dice where we know their sum to be greater than 12. .. class:: ConditionalDomain We specialize further into Finite and Continuous versions of these classes to represent finite (such as dice) and continuous (such as normals) random variables. .. module:: sympy.stats.frv .. class:: FiniteDomain .. class:: FinitePSpace .. module:: sympy.stats.crv .. class:: ContinuousDomain .. class:: ContinuousPSpace Additionally there are a few specialized classes that implement certain common random variable types. There is for example a DiePSpace that implements SingleFinitePSpace and a NormalPSpace that implements SingleContinuousPSpace. .. module:: sympy.stats.frv_types .. class:: DiePSpace .. module:: sympy.stats.crv_types .. class:: NormalPSpace RandomVariables can be extracted from these objects using the PSpace.values method. As previously mentioned SymPy Stats employs a relatively complex class structure. Inheritance is widely used in the implementation of end-level classes. This tactic was chosen to balance between the need to allow SymPy to represent arbitrarily defined random variables and optimizing for common cases. This complicates the code but is structured to only be important to those working on extending SymPy Stats to other random variable types. Users will not use this class structure. Instead these mechanics are exposed through variable creation functions Die, Coin, FiniteRV, Normal, Exponential, etc.... These build the appropriate SinglePSpaces and return the corresponding RandomVariable. Conditional and Product spaces are formed in the natural construction of SymPy expressions and the use of interface functions E, Given, Density, etc.... .. function:: sympy.stats.Die .. function:: sympy.stats.Normal There are some additional functions that may be useful. They are largely used internally. .. autofunction:: sympy.stats.rv.random_symbols .. autofunction:: sympy.stats.rv.pspace .. autofunction:: sympy.stats.rv.rs_swap sympy-sympy-1.9/doc/src/modules/tensor/000077500000000000000000000000001412543434000202415ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/tensor/array.rst000066400000000000000000000007631412543434000221170ustar00rootroot00000000000000.. _tensor-array: N-dim array =========== .. automodule:: sympy.tensor.array Classes ------- .. autoclass:: ImmutableDenseNDimArray :members: .. autoclass:: ImmutableSparseNDimArray :members: .. autoclass:: MutableDenseNDimArray :members: .. autoclass:: MutableSparseNDimArray :members: Functions --------- .. autofunction:: derive_by_array .. autofunction:: permutedims .. autofunction:: tensorcontraction .. autofunction:: tensorproduct .. autofunction:: tensordiagonal sympy-sympy-1.9/doc/src/modules/tensor/index.rst000066400000000000000000000003201412543434000220750ustar00rootroot00000000000000.. _tensor_module: ====== Tensor ====== .. automodule:: sympy.tensor Contents ======== .. toctree:: :maxdepth: 3 array.rst indexed.rst index_methods.rst tensor.rst toperators.rst sympy-sympy-1.9/doc/src/modules/tensor/index_methods.rst000066400000000000000000000001211412543434000236170ustar00rootroot00000000000000======= Methods ======= .. automodule:: sympy.tensor.index_methods :members: sympy-sympy-1.9/doc/src/modules/tensor/indexed.rst000066400000000000000000000001431412543434000224110ustar00rootroot00000000000000=============== Indexed Objects =============== .. automodule:: sympy.tensor.indexed :members: sympy-sympy-1.9/doc/src/modules/tensor/tensor.rst000066400000000000000000000010731412543434000223060ustar00rootroot00000000000000.. _tensor-tensor: Tensor ====== .. module:: sympy.tensor.tensor .. autoclass:: TensorIndexType :members: .. autoclass:: TensorIndex :members: .. autoclass:: TensorHead :members: .. autoclass:: TensExpr :members: .. autoclass:: TensAdd :members: .. autoclass:: TensMul :members: .. autofunction:: canon_bp .. autofunction:: riemann_cyclic_replace .. autofunction:: riemann_cyclic .. autoclass:: TensorSymmetry :members: .. autofunction:: tensorsymmetry .. autoclass:: TensorType :members: .. autoclass:: _TensorManager :members: sympy-sympy-1.9/doc/src/modules/tensor/toperators.rst000066400000000000000000000001311412543434000231700ustar00rootroot00000000000000 Tensor Operators ================ .. automodule:: sympy.tensor.toperators :members: sympy-sympy-1.9/doc/src/modules/testing/000077500000000000000000000000001412543434000204045ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/testing/index.rst000066400000000000000000000003021412543434000222400ustar00rootroot00000000000000.. _testing-docs: ======= Testing ======= .. TODO: add benchmarking.rst .. automodule:: sympy.testing Contents: .. toctree:: :maxdepth: 2 pytest.rst randtest.rst runtests.rst sympy-sympy-1.9/doc/src/modules/testing/pytest.rst000066400000000000000000000001101412543434000224560ustar00rootroot00000000000000====== pytest ====== .. automodule:: sympy.testing.pytest :members: sympy-sympy-1.9/doc/src/modules/testing/randtest.rst000066400000000000000000000001561412543434000227640ustar00rootroot00000000000000================== Randomised Testing ================== .. automodule:: sympy.testing.randtest :members: sympy-sympy-1.9/doc/src/modules/testing/runtests.rst000066400000000000000000000001231412543434000230210ustar00rootroot00000000000000========= Run Tests ========= .. automodule:: sympy.testing.runtests :members: sympy-sympy-1.9/doc/src/modules/utilities/000077500000000000000000000000001412543434000207425ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/utilities/autowrap.rst000066400000000000000000000037411412543434000233430ustar00rootroot00000000000000=============== Autowrap Module =============== The autowrap module works very well in tandem with the Indexed classes of the :ref:`tensor_module`. Here is a simple example that shows how to setup a binary routine that calculates a matrix-vector product. >>> from sympy.utilities.autowrap import autowrap >>> from sympy import symbols, IndexedBase, Idx, Eq >>> A, x, y = map(IndexedBase, ['A', 'x', 'y']) >>> m, n = symbols('m n', integer=True) >>> i = Idx('i', m) >>> j = Idx('j', n) >>> instruction = Eq(y[i], A[i, j]*x[j]); instruction Eq(y[i], A[i, j]*x[j]) Because the code printers treat Indexed objects with repeated indices as a summation, the above equality instance will be translated to low-level code for a matrix vector product. This is how you tell SymPy to generate the code, compile it and wrap it as a python function: >>> matvec = autowrap(instruction) # doctest: +SKIP That's it. Now let's test it with some numpy arrays. The default wrapper backend is f2py. The wrapper function it provides is set up to accept python lists, which it will silently convert to numpy arrays. So we can test the matrix vector product like this: >>> M = [[0, 1], ... [1, 0]] >>> matvec(M, [2, 3]) # doctest: +SKIP [ 3. 2.] Implementation details ====================== The autowrap module is implemented with a backend consisting of CodeWrapper objects. The base class ``CodeWrapper`` takes care of details about module name, filenames and options. It also contains the driver routine, which runs through all steps in the correct order, and also takes care of setting up and removing the temporary working directory. The actual compilation and wrapping is done by external resources, such as the system installed f2py command. The Cython backend runs a distutils setup script in a subprocess. Subclasses of CodeWrapper takes care of these backend-dependent details. API Reference ============= .. automodule:: sympy.utilities.autowrap :members: sympy-sympy-1.9/doc/src/modules/utilities/codegen.rst000066400000000000000000000036661412543434000231130ustar00rootroot00000000000000.. _codegen_API: ======= Codegen ======= This module provides functionality to generate directly compilable code from SymPy expressions. The ``codegen`` function is the user interface to the code generation functionality in SymPy. Some details of the implementation is given below for advanced users that may want to use the framework directly. .. note:: The ``codegen`` callable is not in the sympy namespace automatically, to use it you must first execute >>> from sympy.utilities.codegen import codegen Implementation Details ====================== Here we present the most important pieces of the internal structure, as advanced users may want to use it directly, for instance by subclassing a code generator for a specialized application. **It is very likely that you would prefer to use the codegen() function documented above.** Basic assumptions: * A generic Routine data structure describes the routine that must be translated into C/Fortran/... code. This data structure covers all features present in one or more of the supported languages. * Descendants from the CodeGen class transform multiple Routine instances into compilable code. Each derived class translates into a specific language. * In many cases, one wants a simple workflow. The friendly functions in the last part are a simple api on top of the Routine/CodeGen stuff. They are easier to use, but are less powerful. Routine ======= The Routine class is a very important piece of the codegen module. Viewing the codegen utility as a translator of mathematical expressions into a set of statements in a programming language, the Routine instances are responsible for extracting and storing information about how the math can be encapsulated in a function call. Thus, it is the Routine constructor that decides what arguments the routine will need and if there should be a return value. API Reference ============= .. automodule:: sympy.utilities.codegen :members: sympy-sympy-1.9/doc/src/modules/utilities/decorator.rst000066400000000000000000000001261412543434000234550ustar00rootroot00000000000000========= Decorator ========= .. automodule:: sympy.utilities.decorator :members: sympy-sympy-1.9/doc/src/modules/utilities/enumerative.rst000066400000000000000000000011121412543434000240130ustar00rootroot00000000000000=========== Enumerative =========== .. module:: sympy.utilities.enumerative This module includes functions and classes for enumerating and counting multiset partitions. .. autofunction:: multiset_partitions_taocp .. autofunction:: factoring_visitor .. autofunction:: list_visitor The approach of the function ``multiset_partitions_taocp`` is extended and generalized by the class ``MultisetPartitionTraverser``. .. autoclass:: MultisetPartitionTraverser :members: count_partitions, enum_all, enum_large, enum_range, enum_small sympy-sympy-1.9/doc/src/modules/utilities/index.rst000066400000000000000000000004571412543434000226110ustar00rootroot00000000000000.. _utilities-docs: ========= Utilities ========= .. automodule:: sympy.utilities Contents: .. toctree:: :maxdepth: 2 autowrap.rst codegen.rst decorator.rst enumerative.rst iterables.rst lambdify.rst memoization.rst misc.rst pkgdata.rst source.rst timeutils.rst sympy-sympy-1.9/doc/src/modules/utilities/iterables.rst000066400000000000000000000051771412543434000234600ustar00rootroot00000000000000========= Iterables ========= cartes ------ Returns the cartesian product of sequences as a generator. Examples:: >>> from sympy.utilities.iterables import cartes >>> list(cartes([1,2,3], 'ab')) [(1, 'a'), (1, 'b'), (2, 'a'), (2, 'b'), (3, 'a'), (3, 'b')] variations ---------- variations(seq, n) Returns all the variations of the list of size n. Has an optional third argument. Must be a boolean value and makes the method return the variations with repetition if set to True, or the variations without repetition if set to False. Examples:: >>> from sympy.utilities.iterables import variations >>> list(variations([1,2,3], 2)) [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1), (3, 2)] >>> list(variations([1,2,3], 2, True)) [(1, 1), (1, 2), (1, 3), (2, 1), (2, 2), (2, 3), (3, 1), (3, 2), (3, 3)] partitions ---------- Although the combinatorics module contains Partition and IntegerPartition classes for investigation and manipulation of partitions, there are a few functions to generate partitions that can be used as low-level tools for routines: ``partitions`` and ``multiset_partitions``. The former gives integer partitions, and the latter gives enumerated partitions of elements. There is also a routine ``kbins`` that will give a variety of permutations of partions. partitions:: >>> from sympy.utilities.iterables import partitions >>> [p.copy() for s, p in partitions(7, m=2, size=True) if s == 2] [{1: 1, 6: 1}, {2: 1, 5: 1}, {3: 1, 4: 1}] multiset_partitions:: >>> from sympy.utilities.iterables import multiset_partitions >>> [p for p in multiset_partitions(3, 2)] [[[0, 1], [2]], [[0, 2], [1]], [[0], [1, 2]]] >>> [p for p in multiset_partitions([1, 1, 1, 2], 2)] [[[1, 1, 1], [2]], [[1, 1, 2], [1]], [[1, 1], [1, 2]]] kbins:: >>> from sympy.utilities.iterables import kbins >>> def show(k): ... rv = [] ... for p in k: ... rv.append(','.join([''.join(j) for j in p])) ... return sorted(rv) ... >>> show(kbins("ABCD", 2)) ['A,BCD', 'AB,CD', 'ABC,D'] >>> show(kbins("ABC", 2)) ['A,BC', 'AB,C'] >>> show(kbins("ABC", 2, ordered=0)) # same as multiset_partitions ['A,BC', 'AB,C', 'AC,B'] >>> show(kbins("ABC", 2, ordered=1)) ['A,BC', 'A,CB', 'B,AC', 'B,CA', 'C,AB', 'C,BA'] >>> show(kbins("ABC", 2, ordered=10)) ['A,BC', 'AB,C', 'AC,B', 'B,AC', 'BC,A', 'C,AB'] >>> show(kbins("ABC", 2, ordered=11)) ['A,BC', 'A,CB', 'AB,C', 'AC,B', 'B,AC', 'B,CA', 'BA,C', 'BC,A', 'C,AB', 'C,BA', 'CA,B', 'CB,A'] Docstring ========= .. automodule:: sympy.utilities.iterables :members: sympy-sympy-1.9/doc/src/modules/utilities/lambdify.rst000066400000000000000000000001221412543434000232560ustar00rootroot00000000000000======== Lambdify ======== .. automodule:: sympy.utilities.lambdify :members: sympy-sympy-1.9/doc/src/modules/utilities/memoization.rst000066400000000000000000000001361412543434000240270ustar00rootroot00000000000000=========== Memoization =========== .. automodule:: sympy.utilities.memoization :members: sympy-sympy-1.9/doc/src/modules/utilities/misc.rst000066400000000000000000000001351412543434000224260ustar00rootroot00000000000000============= Miscellaneous ============= .. automodule:: sympy.utilities.misc :members: sympy-sympy-1.9/doc/src/modules/utilities/pkgdata.rst000066400000000000000000000001161412543434000231050ustar00rootroot00000000000000======= PKGDATA ======= .. automodule:: sympy.utilities.pkgdata :members: sympy-sympy-1.9/doc/src/modules/utilities/source.rst000066400000000000000000000001721412543434000227740ustar00rootroot00000000000000====================== Source Code Inspection ====================== .. automodule:: sympy.utilities.source :members: sympy-sympy-1.9/doc/src/modules/utilities/timeutils.rst000066400000000000000000000001531412543434000235120ustar00rootroot00000000000000================ Timing Utilities ================ .. automodule:: sympy.utilities.timeutils :members: sympy-sympy-1.9/doc/src/modules/vector/000077500000000000000000000000001412543434000202315ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/vector/api/000077500000000000000000000000001412543434000210025ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/modules/vector/api/classes.rst000066400000000000000000000015121412543434000231700ustar00rootroot00000000000000============================================== Essential Classes in sympy.vector (docstrings) ============================================== CoordSys3D ================= .. autoclass:: sympy.vector.coordsysrect.CoordSys3D :members: .. automethod:: sympy.vector.coordsysrect.CoordSys3D.__init__ Vector ====== .. autoclass:: sympy.vector.vector.Vector :members: Dyadic ====== .. autoclass:: sympy.vector.dyadic.Dyadic :members: Del === .. autoclass:: sympy.vector.deloperator.Del :members: ParametricRegion ================ .. autoclass:: sympy.vector.parametricregion.ParametricRegion :members: ImplicitRegion ============== .. autoclass:: sympy.vector.implicitregion.ImplicitRegion :members: ParametricIntegral ================== .. autoclass:: sympy.vector.integrals.ParametricIntegral :members: sympy-sympy-1.9/doc/src/modules/vector/api/orienterclasses.rst000066400000000000000000000014761412543434000247510ustar00rootroot00000000000000============================= Orienter classes (docstrings) ============================= Orienter ======== .. autoclass:: sympy.vector.orienters.Orienter :members: AxisOrienter ============ .. autoclass:: sympy.vector.orienters.AxisOrienter :members: .. automethod:: sympy.vector.orienters.AxisOrienter.__init__ BodyOrienter ============ .. autoclass:: sympy.vector.orienters.BodyOrienter :members: .. automethod:: sympy.vector.orienters.BodyOrienter.__init__ SpaceOrienter ============= .. autoclass:: sympy.vector.orienters.SpaceOrienter :members: .. automethod:: sympy.vector.orienters.SpaceOrienter.__init__ QuaternionOrienter ================== .. autoclass:: sympy.vector.orienters.QuaternionOrienter :members: .. automethod:: sympy.vector.orienters.QuaternionOrienter.__init__ sympy-sympy-1.9/doc/src/modules/vector/api/vectorfunctions.rst000066400000000000000000000016311412543434000247700ustar00rootroot00000000000000================================================ Essential Functions in sympy.vector (docstrings) ================================================ matrix_to_vector ---------------- .. autofunction:: sympy.vector.matrix_to_vector express ------- .. autofunction:: sympy.vector.express curl ---- .. autofunction:: sympy.vector.curl divergence ---------- .. autofunction:: sympy.vector.divergence gradient -------- .. autofunction:: sympy.vector.gradient is_conservative --------------- .. autofunction:: sympy.vector.is_conservative is_solenoidal ------------- .. autofunction:: sympy.vector.is_solenoidal scalar_potential ---------------- .. autofunction:: sympy.vector.scalar_potential scalar_potential_difference --------------------------- .. autofunction:: sympy.vector.scalar_potential_difference vector_integrate ---------------- .. autofunction:: sympy.vector.integrals.vector_integrate sympy-sympy-1.9/doc/src/modules/vector/basics.rst000066400000000000000000000171351412543434000222360ustar00rootroot00000000000000============================ Basic Implementation details ============================ Coordinate Systems and Vectors ============================== Currently, :mod:`sympy.vector` is able to deal with the Cartesian (also called rectangular), spherical and other curvilinear coordinate systems. A 3D Cartesian coordinate system can be initialized in :mod:`sympy.vector` as >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') The string parameter to the constructor denotes the name assigned to the system, and will primarily be used for printing purposes. Once a coordinate system (in essence, a ``CoordSys3D`` instance) has been defined, we can access the orthonormal unit vectors (i.e. the :math:`\mathbf{\hat{i}}`, :math:`\mathbf{\hat{j}}` and :math:`\mathbf{\hat{k}}` vectors) and coordinate variables/base scalars (i.e. the :math:`\mathbf{x}`, :math:`\mathbf{y}` and :math:`\mathbf{z}` variables) corresponding to it. We will talk about coordinate variables in the later sections. The basis vectors for the :math:`X`, :math:`Y` and :math:`Z` axes can be accessed using the ``i``, ``j`` and ``k`` properties respectively. >>> N.i N.i >>> type(N.i) As seen above, the basis vectors are all instances of a class called ``BaseVector``. When a ``BaseVector`` is multiplied by a scalar (essentially any SymPy ``Expr``), we get a ``VectorMul`` - the product of a base vector and a scalar. >>> 3*N.i 3*N.i >>> type(3*N.i) Addition of ``VectorMul`` and ``BaseVectors`` gives rise to formation of ``VectorAdd`` - except for special cases, ofcourse. >>> v = 2*N.i + N.j >>> type(v) >>> v - N.j 2*N.i >>> type(v - N.j) What about a zero vector? It can be accessed using the ``zero`` attribute assigned to class ``Vector``. Since the notion of a zero vector remains the same regardless of the coordinate system in consideration, we use ``Vector.zero`` wherever such a quantity is required. >>> from sympy.vector import Vector >>> Vector.zero 0 >>> type(Vector.zero) >>> N.i + Vector.zero N.i >>> Vector.zero == 2*Vector.zero True All the classes shown above - ``BaseVector``, ``VectorMul``, ``VectorAdd`` and ``VectorZero`` are subclasses of ``Vector``. You should never have to instantiate objects of any of the subclasses of ``Vector``. Using the ``BaseVector`` instances assigned to a ``CoordSys3D`` instance and (if needed) ``Vector.zero`` as building blocks, any sort of vectorial expression can be constructed with the basic mathematical operators ``+``, ``-``, ``*``. and ``/``. >>> v = N.i - 2*N.j >>> v/3 1/3*N.i + (-2/3)*N.j >>> v + N.k N.i + (-2)*N.j + N.k >>> Vector.zero/2 0 >>> (v/3)*4 4/3*N.i + (-8/3)*N.j In addition to the elementary mathematical operations, the vector operations of ``dot`` and ``cross`` can also be performed on ``Vector``. >>> v1 = 2*N.i + 3*N.j - N.k >>> v2 = N.i - 4*N.j + N.k >>> v1.dot(v2) -11 >>> v1.cross(v2) (-1)*N.i + (-3)*N.j + (-11)*N.k >>> v2.cross(v1) N.i + 3*N.j + 11*N.k The ``&`` and ``^`` operators have been overloaded for the ``dot`` and ``cross`` methods respectively. >>> v1 & v2 -11 >>> v1 ^ v2 (-1)*N.i + (-3)*N.j + (-11)*N.k However, this is not the recommended way of performing these operations. Using the original methods makes the code clearer and easier to follow. In addition to these operations, it is also possible to compute the outer products of ``Vector`` instances in :mod:`sympy.vector`. More on that in a little bit. SymPy operations on Vectors =========================== The SymPy operations of ``simplify``, ``trigsimp``, ``diff``, and ``factor`` work on ``Vector`` objects, with the standard SymPy API. In essence, the methods work on the measure numbers(The coefficients of the basis vectors) present in the provided vectorial expression. >>> from sympy.abc import a, b, c >>> from sympy import sin, cos, trigsimp, diff >>> v = (a*b + a*c + b**2 + b*c)*N.i + N.j >>> v.factor() ((a + b)*(b + c))*N.i + N.j >>> v = (sin(a)**2 + cos(a)**2)*N.i - (2*cos(b)**2 - 1)*N.k >>> trigsimp(v) N.i + (-cos(2*b))*N.k >>> v.simplify() N.i + (-cos(2*b))*N.k >>> diff(v, b) (4*sin(b)*cos(b))*N.k >>> from sympy import Derivative >>> Derivative(v, b).doit() (4*sin(b)*cos(b))*N.k ``Integral`` also works with ``Vector`` instances, similar to ``Derivative``. >>> from sympy import Integral >>> v1 = a*N.i + sin(a)*N.j - N.k >>> Integral(v1, a) (Integral(a, a))*N.i + (Integral(sin(a), a))*N.j + (Integral(-1, a))*N.k >>> Integral(v1, a).doit() a**2/2*N.i + (-cos(a))*N.j + (-a)*N.k Points ====== As mentioned before, every coordinate system corresponds to a unique origin point. Points, in general, have been implemented in :mod:`sympy.vector` in the form of the ``Point`` class. To access the origin of system, use the ``origin`` property of the ``CoordSys3D`` class. >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> N.origin N.origin >>> type(N.origin) You can instantiate new points in space using the ``locate_new`` method of ``Point``. The arguments include the name(string) of the new ``Point``, and its position vector with respect to the 'parent' ``Point``. >>> from sympy.abc import a, b, c >>> P = N.origin.locate_new('P', a*N.i + b*N.j + c*N.k) >>> Q = P.locate_new('Q', -b*N.j) Like ``Vector``, a user never has to expressly instantiate an object of ``Point``. This is because any location in space (albeit relative) can be pointed at by using the ``origin`` of a ``CoordSys3D`` as the reference, and then using ``locate_new`` on it and subsequent ``Point`` instances. The position vector of a ``Point`` with respect to another ``Point`` can be computed using the ``position_wrt`` method. >>> P.position_wrt(Q) b*N.j >>> Q.position_wrt(N.origin) a*N.i + c*N.k Additionally, it is possible to obtain the :math:`X`, :math:`Y` and :math:`Z` coordinates of a ``Point`` with respect to a ``CoordSys3D`` in the form of a tuple. This is done using the ``express_coordinates`` method. >>> Q.express_coordinates(N) (a, 0, c) Dyadics ======= A dyadic, or dyadic tensor, is a second-order tensor formed by the juxtaposition of pairs of vectors. Therefore, the outer products of vectors give rise to the formation of dyadics. Dyadic tensors have been implemented in :mod:`sympy.vector` in the ``Dyadic`` class. Once again, you never have to instantiate objects of ``Dyadic``. The outer products of vectors can be computed using the ``outer`` method of ``Vector``. The ``|`` operator has been overloaded for ``outer``. >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> N.i.outer(N.j) (N.i|N.j) >>> N.i|N.j (N.i|N.j) Similar to ``Vector``, ``Dyadic`` also has subsequent subclasses like ``BaseDyadic``, ``DyadicMul``, ``DyadicAdd``. As with ``Vector``, a zero dyadic can be accessed from ``Dyadic.zero``. All basic mathematical operations work with ``Dyadic`` too. >>> dyad = N.i.outer(N.k) >>> dyad*3 3*(N.i|N.k) >>> dyad - dyad 0 >>> dyad + 2*(N.j|N.i) (N.i|N.k) + 2*(N.j|N.i) ``dot`` and ``cross`` also work among ``Dyadic`` instances as well as between a ``Dyadic`` and ``Vector`` (and also vice versa) - as per the respective mathematical definitions. As with ``Vector``, ``&`` and ``^`` have been overloaded for ``dot`` and ``cross``. >>> d = N.i.outer(N.j) >>> d.dot(N.j|N.j) (N.i|N.j) >>> d.dot(N.i) 0 >>> d.dot(N.j) N.i >>> N.i.dot(d) N.j >>> N.k ^ d (N.j|N.j) sympy-sympy-1.9/doc/src/modules/vector/coordsys.rst000066400000000000000000000226171412543434000226400ustar00rootroot00000000000000============================= More about Coordinate Systems ============================= We will now look at how we can initialize new coordinate systems in :mod:`sympy.vector`, transformed in user-defined ways with respect to already-existing systems. Locating new systems ==================== We already know that the ``origin`` property of a ``CoordSys3D`` corresponds to the ``Point`` instance denoting its origin reference point. Consider a coordinate system :math:`N`. Suppose we want to define a new system :math:`M`, whose origin is located at :math:`\mathbf{3\hat{i} + 4\hat{j} + 5\hat{k}}` from :math:`N`'s origin. In other words, the coordinates of :math:`M`'s origin from N's perspective happen to be :math:`(3, 4, 5)`. Moreover, this would also mean that the coordinates of :math:`N`'s origin with respect to :math:`M` would be :math:`(-3, -4, -5)`. This can be achieved programmatically as follows - >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> M = N.locate_new('M', 3*N.i + 4*N.j + 5*N.k) >>> M.position_wrt(N) 3*N.i + 4*N.j + 5*N.k >>> N.origin.express_coordinates(M) (-3, -4, -5) It is worth noting that :math:`M`'s orientation is the same as that of :math:`N`. This means that the rotation matrix of :math: `N` with respect to :math:`M`, and also vice versa, is equal to the identity matrix of dimensions 3x3. The ``locate_new`` method initializes a ``CoordSys3D`` that is only translated in space, not re-oriented, relative to the 'parent' system. Orienting new systems ===================== Similar to 'locating' new systems, :mod:`sympy.vector` also allows for initialization of new ``CoordSys3D`` instances that are oriented in user-defined ways with respect to existing systems. Suppose you have a coordinate system :math:`A`. >>> from sympy.vector import CoordSys3D >>> A = CoordSys3D('A') You want to initialize a new coordinate system :math:`B`, that is rotated with respect to :math:`A`'s Z-axis by an angle :math:`\theta`. >>> from sympy import Symbol >>> theta = Symbol('theta') The orientation is shown in the diagram below: .. image:: coordsys_rot.* :height: 250 :width: 250 :align: center There are two ways to achieve this. Using a method of CoordSys3D directly ------------------------------------- This is the easiest, cleanest, and hence the recommended way of doing it. >>> B = A.orient_new_axis('B', theta, A.k) This initializes :math:`B` with the required orientation information with respect to :math:`A`. ``CoordSys3D`` provides the following direct orientation methods in its API- 1. ``orient_new_axis`` 2. ``orient_new_body`` 3. ``orient_new_space`` 4. ``orient_new_quaternion`` Please look at the ``CoordSys3D`` class API given in the docs of this module, to know their functionality and required arguments in detail. Using Orienter(s) and the orient_new method ------------------------------------------- You would first have to initialize an ``AxisOrienter`` instance for storing the rotation information. >>> from sympy.vector import AxisOrienter >>> axis_orienter = AxisOrienter(theta, A.k) And then apply it using the ``orient_new`` method, to obtain :math:`B`. >>> B = A.orient_new('B', axis_orienter) ``orient_new`` also lets you orient new systems using multiple ``Orienter`` instances, provided in an iterable. The rotations/orientations are applied to the new system in the order the ``Orienter`` instances appear in the iterable. >>> from sympy.vector import BodyOrienter >>> from sympy.abc import a, b, c >>> body_orienter = BodyOrienter(a, b, c, 'XYZ') >>> C = A.orient_new('C', (axis_orienter, body_orienter)) The :mod:`sympy.vector` API provides the following four ``Orienter`` classes for orientation purposes- 1. ``AxisOrienter`` 2. ``BodyOrienter`` 3. ``SpaceOrienter`` 4. ``QuaternionOrienter`` Please refer to the API of the respective classes in the docs of this module to know more. In each of the above examples, the origin of the new coordinate system coincides with the origin of the 'parent' system. >>> B.position_wrt(A) 0 To compute the rotation matrix of any coordinate system with respect to another one, use the ``rotation_matrix`` method. >>> B = A.orient_new_axis('B', a, A.k) >>> B.rotation_matrix(A) Matrix([ [ cos(a), sin(a), 0], [-sin(a), cos(a), 0], [ 0, 0, 1]]) >>> B.rotation_matrix(B) Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) Orienting AND Locating new systems ================================== What if you want to initialize a new system that is not only oriented in a pre-defined way, but also translated with respect to the parent? Each of the ``orient_new_`` methods, as well as the ``orient_new`` method, support a ``location`` keyword argument. If a ``Vector`` is supplied as the value for this ``kwarg``, the new system's origin is automatically defined to be located at that position vector with respect to the parent coordinate system. Thus, the orientation methods also act as methods to support orientation+ location of the new systems. >>> C = A.orient_new_axis('C', a, A.k, location=2*A.j) >>> C.position_wrt(A) 2*A.j >>> from sympy.vector import express >>> express(A.position_wrt(C), C) (-2*sin(a))*C.i + (-2*cos(a))*C.j More on the ``express`` function in a bit. Transforming new system ======================= The most general way of creating user-defined system is to use ``transformation`` parameter in ``CoordSys3D``. Here we can define any transformation equations. If we are interested in some typical curvilinear coordinate system different that Cartesian, we can also use some predefined ones. It could be also possible to translate or rotate system by setting appropriate transformation equations. >>> from sympy.vector import CoordSys3D >>> from sympy import sin, cos >>> A = CoordSys3D('A', transformation='spherical') >>> B = CoordSys3D('A', transformation=lambda x,y,z: (x*sin(y), x*cos(y), z)) In ``CoordSys3D`` is also dedicated method, ``create_new`` which works similarly to methods like ``locate_new``, ``orient_new_axis`` etc. >>> from sympy.vector import CoordSys3D >>> A = CoordSys3D('A') >>> B = A.create_new('B', transformation='spherical') Expression of quantities in different coordinate systems ======================================================== Vectors and Dyadics ------------------- As mentioned earlier, the same vector attains different expressions in different coordinate systems. In general, the same is true for scalar expressions and dyadic tensors. :mod:`sympy.vector` supports the expression of vector/scalar quantities in different coordinate systems using the ``express`` function. For purposes of this section, assume the following initializations- >>> from sympy.vector import CoordSys3D, express >>> from sympy.abc import a, b, c >>> N = CoordSys3D('N') >>> M = N.orient_new_axis('M', a, N.k) ``Vector`` instances can be expressed in user defined systems using ``express``. >>> v1 = N.i + N.j + N.k >>> express(v1, M) (sin(a) + cos(a))*M.i + (-sin(a) + cos(a))*M.j + M.k >>> v2 = N.i + M.j >>> express(v2, N) (1 - sin(a))*N.i + (cos(a))*N.j Apart from ``Vector`` instances, ``express`` also supports reexpression of scalars (general SymPy ``Expr``) and ``Dyadic`` objects. ``express`` also accepts a second coordinate system for re-expressing ``Dyadic`` instances. >>> d = 2*(M.i | N.j) + 3* (M.j | N.k) >>> express(d, M) (2*sin(a))*(M.i|M.i) + (2*cos(a))*(M.i|M.j) + 3*(M.j|M.k) >>> express(d, M, N) 2*(M.i|N.j) + 3*(M.j|N.k) Coordinate Variables -------------------- The location of a coordinate system's origin does not affect the re-expression of ``BaseVector`` instances. However, it does affect the way ``BaseScalar`` instances are expressed in different systems. ``BaseScalar`` instances, are coordinate 'symbols' meant to denote the variables used in the definition of vector/scalar fields in :mod:`sympy.vector`. For example, consider the scalar field :math:`\mathbf{{T}_{N}(x, y, z) = x + y + z}` defined in system :math:`N`. Thus, at a point with coordinates :math:`(a, b, c)`, the value of the field would be :math:`a + b + c`. Now consider system :math:`R`, whose origin is located at :math:`(1, 2, 3)` with respect to :math:`N` (no change of orientation). A point with coordinates :math:`(a, b, c)` in :math:`R` has coordinates :math:`(a + 1, b + 2, c + 3)` in :math:`N`. Therefore, the expression for :math:`\mathbf{{T}_{N}}` in :math:`R` becomes :math:`\mathbf{{T}_{R}}(x, y, z) = x + y + z + 6`. Coordinate variables, if present in a vector/scalar/dyadic expression, can also be re-expressed in a given coordinate system, by setting the ``variables`` keyword argument of ``express`` to ``True``. The above mentioned example, done programmatically, would look like this - >>> R = N.locate_new('R', N.i + 2*N.j + 3*N.k) >>> T_N = N.x + N.y + N.z >>> express(T_N, R, variables=True) R.x + R.y + R.z + 6 Other expression-dependent methods ---------------------------------- The ``to_matrix`` method of ``Vector`` and ``express_coordinates`` method of ``Point`` also return different results depending on the coordinate system being provided. >>> P = R.origin.locate_new('P', a*R.i + b*R.j + c*R.k) >>> P.express_coordinates(N) (a + 1, b + 2, c + 3) >>> P.express_coordinates(R) (a, b, c) >>> v = N.i + N.j + N.k >>> v.to_matrix(M) Matrix([ [ sin(a) + cos(a)], [-sin(a) + cos(a)], [ 1]]) >>> v.to_matrix(N) Matrix([ [1], [1], [1]]) sympy-sympy-1.9/doc/src/modules/vector/coordsys_rot.svg000066400000000000000000000243701412543434000235110ustar00rootroot00000000000000 image/svg+xml A B θ θ azbz ax bx ay by sympy-sympy-1.9/doc/src/modules/vector/examples.rst000066400000000000000000000065771412543434000226200ustar00rootroot00000000000000========================= General examples of usage ========================= This section details the solution of two basic problems in vector math/calculus using the :mod:`sympy.vector` package. Quadrilateral problem ===================== The Problem ----------- *OABC is any quadrilateral in 3D space. P is the midpoint of OA, Q is the midpoint of AB, R is the midpoint of BC and S is the midpoint of OC. Prove that PQ is parallel to SR* Solution -------- The solution to this problem demonstrates the usage of ``Point``, and basic operations on ``Vector``. Define a coordinate system >>> from sympy.vector import CoordSys3D >>> Sys = CoordSys3D('Sys') Define point O to be Sys' origin. We can do this without loss of generality >>> O = Sys.origin Define point A with respect to O >>> from sympy import symbols >>> a1, a2, a3 = symbols('a1 a2 a3') >>> A = O.locate_new('A', a1*Sys.i + a2*Sys.j + a3*Sys.k) Similarly define points B and C >>> b1, b2, b3 = symbols('b1 b2 b3') >>> B = O.locate_new('B', b1*Sys.i + b2*Sys.j + b3*Sys.k) >>> c1, c2, c3 = symbols('c1 c2 c3') >>> C = O.locate_new('C', c1*Sys.i + c2*Sys.j + c3*Sys.k) P is the midpoint of OA. Lets locate it with respect to O (you could also define it with respect to A). >>> P = O.locate_new('P', A.position_wrt(O) + (O.position_wrt(A) / 2)) Similarly define points Q, R and S as per the problem definitions. >>> Q = A.locate_new('Q', B.position_wrt(A) / 2) >>> R = B.locate_new('R', C.position_wrt(B) / 2) >>> S = O.locate_new('R', C.position_wrt(O) / 2) Now compute the vectors in the directions specified by PQ and SR. >>> PQ = Q.position_wrt(P) >>> SR = R.position_wrt(S) Compute cross product >>> PQ.cross(SR) 0 Since the cross product is a zero vector, the two vectors have to be parallel, thus proving that PQ || SR. Third product rule for Del operator =================================== See --- .. [WikiDel] https://en.wikipedia.org/wiki/Del The Problem ----------- Prove the third rule - :math:`\nabla \cdot (f \vec v) = f (\nabla \cdot \vec v) + \vec v \cdot (\nabla f)` Solution -------- Start with a coordinate system >>> from sympy.vector import CoordSys3D, Del >>> delop = Del() >>> C = CoordSys3D('C') The scalar field :math:`f` and the measure numbers of the vector field :math:`\vec v` are all functions of the coordinate variables of the coordinate system in general. Hence, define SymPy functions that way. >>> from sympy import symbols, Function >>> v1, v2, v3, f = symbols('v1 v2 v3 f', cls=Function) ``v1``, ``v2`` and ``v3`` are the :math:`X`, :math:`Y` and :math:`Z` components of the vector field respectively. Define the vector field as ``vfield`` and the scalar field as ``sfield``. >>> vfield = v1(C.x, C.y, C.z)*C.i + v2(C.x, C.y, C.z)*C.j + v3(C.x, C.y, C.z)*C.k >>> ffield = f(C.x, C.y, C.z) Construct the expression for the LHS of the equation using ``Del()``. >>> lhs = (delop.dot(ffield * vfield)).doit() Similarly, the RHS would be defined. >>> rhs = ((vfield.dot(delop(ffield))) + (ffield * (delop.dot(vfield)))).doit() Now, to prove the product rule, we would just need to equate the expanded and simplified versions of the lhs and the rhs, so that the SymPy expressions match. >>> lhs.expand().simplify() == rhs.expand().doit().simplify() True Thus, the general form of the third product rule mentioned above can be proven using :mod:`sympy.vector`. sympy-sympy-1.9/doc/src/modules/vector/fields.rst000066400000000000000000000310241412543434000222310ustar00rootroot00000000000000===================================== Scalar and Vector Field Functionality ===================================== Implementation in sympy.vector ============================== Scalar and vector fields ------------------------ In :mod:`sympy.vector`, every ``CoordSysCartesian`` instance is assigned basis vectors corresponding to the :math:`X`, :math:`Y` and :math:`Z` axes. These can be accessed using the properties named ``i``, ``j`` and ``k`` respectively. Hence, to define a vector :math:`\mathbf{v}` of the form :math:`3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}}` with respect to a given frame :math:`\mathbf{R}`, you would do >>> from sympy.vector import CoordSys3D >>> R = CoordSys3D('R') >>> v = 3*R.i + 4*R.j + 5*R.k Vector math and basic calculus operations with respect to vectors have already been elaborated upon in the earlier section of this module's documentation. On the other hand, base scalars (or coordinate variables) are implemented in a special class called ``BaseScalar``, and are assigned to every coordinate system, one for each axis from :math:`X`, :math:`Y` and :math:`Z`. These coordinate variables are used to form the expressions of vector or scalar fields in 3D space. For a system ``R``, the :math:`X`, :math:`Y` and :math:`Z` ``BaseScalars`` instances can be accessed using the ``R.x``, ``R.y`` and ``R.z`` expressions respectively. Therefore, to generate the expression for the aforementioned electric potential field :math:`2{x}^{2}y`, you would have to do >>> from sympy.vector import CoordSys3D >>> R = CoordSys3D('R') >>> electric_potential = 2*R.x**2*R.y >>> electric_potential 2*R.x**2*R.y It is to be noted that ``BaseScalar`` instances can be used just like any other SymPy ``Symbol``, except that they store the information about the coordinate system and axis they correspond to. Scalar fields can be treated just as any other SymPy expression, for any math/calculus functionality. Hence, to differentiate the above electric potential with respect to :math:`x` (i.e. ``R.x``), you would use the ``diff`` method. >>> from sympy.vector import CoordSys3D >>> R = CoordSys3D('R') >>> electric_potential = 2*R.x**2*R.y >>> from sympy import diff >>> diff(electric_potential, R.x) 4*R.x*R.y It is worth noting that having a ``BaseScalar`` in the expression implies that a 'field' changes with position, in 3D space. Technically speaking, a simple ``Expr`` with no ``BaseScalar`` s is still a field, though constant. Like scalar fields, vector fields that vary with position can also be constructed using ``BaseScalar`` s in the measure-number expressions. >>> from sympy.vector import CoordSys3D >>> R = CoordSys3D('R') >>> v = R.x**2*R.i + 2*R.x*R.z*R.k The Del operator ---------------- The Del, or 'Nabla' operator - written as :math:`\mathbf{\nabla}` is commonly known as the vector differential operator. Depending on its usage in a mathematical expression, it may denote the gradient of a scalar field, the divergence of a vector field, or the curl of a vector field. Essentially, :math:`\mathbf{\nabla}` is not technically an 'operator', but a convenient mathematical notation to denote any one of the aforementioned field operations. In :mod:`sympy.vector`, :math:`\mathbf{\nabla}` has been implemented as the ``Del()`` class. The instance of this class is independent of coordinate system. Hence, the :math:`\mathbf{\nabla}` operator would be accessible as ``Del()``. Given below is an example of usage of the ``Del()`` class. >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> gradient_field = delop(C.x*C.y*C.z) >>> gradient_field (Derivative(C.x*C.y*C.z, C.x))*C.i + (Derivative(C.x*C.y*C.z, C.y))*C.j + (Derivative(C.x*C.y*C.z, C.z))*C.k The above expression can be evaluated using the SymPy ``doit()`` routine. >>> gradient_field.doit() C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k Usage of the :math:`\mathbf{\nabla}` notation in :mod:`sympy.vector` has been described in greater detail in the subsequent subsections. Field operators and related functions ===================================== Here we describe some basic field-related functionality implemented in :mod:`sympy.vector`. Curl ---- A curl is a mathematical operator that describes an infinitesimal rotation of a vector in 3D space. The direction is determined by the right-hand rule (along the axis of rotation), and the magnitude is given by the magnitude of rotation. In the 3D Cartesian system, the curl of a 3D vector :math:`\mathbf{F}` , denoted by :math:`\nabla \times \mathbf{F}` is given by: :math:`\nabla \times \mathbf{F} = \left(\frac{\partial F_z}{\partial y} - \frac{\partial F_y}{\partial z}\right) \mathbf{\hat{i}} + \left(\frac{\partial F_x}{\partial z} - \frac{\partial F_z}{\partial x}\right) \mathbf{\hat{j}} + \left(\frac{\partial F_y}{\partial x} - \frac{\partial F_x}{\partial y}\right) \mathbf{\hat{k}}` where :math:`F_x` denotes the :math:`X` component of vector :math:`\mathbf{F}`. Computing the curl of a vector field in :mod:`sympy.vector` can be accomplished in two ways. One, by using the ``Del()`` class >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> delop.cross(C.x*C.y*C.z*C.i).doit() C.x*C.y*C.j + (-C.x*C.z)*C.k >>> (delop ^ C.x*C.y*C.z*C.i).doit() C.x*C.y*C.j + (-C.x*C.z)*C.k Or by using the dedicated function >>> from sympy.vector import curl >>> curl(C.x*C.y*C.z*C.i) C.x*C.y*C.j + (-C.x*C.z)*C.k Divergence ---------- Divergence is a vector operator that measures the magnitude of a vector field's source or sink at a given point, in terms of a signed scalar. The divergence operator always returns a scalar after operating on a vector. In the 3D Cartesian system, the divergence of a 3D vector :math:`\mathbf{F}`, denoted by :math:`\nabla\cdot\mathbf{F}` is given by: :math:`\nabla\cdot\mathbf{F} =\frac{\partial U}{\partial x} +\frac{\partial V}{\partial y} +\frac{\partial W}{\partial z }` where :math:`U`, :math:`V` and :math:`W` denote the :math:`X`, :math:`Y` and :math:`Z` components of :math:`\mathbf{F}` respectively. Computing the divergence of a vector field in :mod:`sympy.vector` can be accomplished in two ways. One, by using the ``Del()`` class >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> delop.dot(C.x*C.y*C.z*(C.i + C.j + C.k)).doit() C.x*C.y + C.x*C.z + C.y*C.z >>> (delop & C.x*C.y*C.z*(C.i + C.j + C.k)).doit() C.x*C.y + C.x*C.z + C.y*C.z Or by using the dedicated function >>> from sympy.vector import divergence >>> divergence(C.x*C.y*C.z*(C.i + C.j + C.k)) C.x*C.y + C.x*C.z + C.y*C.z Gradient -------- Consider a scalar field :math:`f(x, y, z)` in 3D space. The gradient of this field is defined as the vector of the 3 partial derivatives of :math:`f` with respect to :math:`x`, :math:`y` and :math:`z` in the :math:`X`, :math:`Y` and :math:`Z` axes respectively. In the 3D Cartesian system, the divergence of a scalar field :math:`f`, denoted by :math:`\nabla f` is given by - :math:`\nabla f = \frac{\partial f}{\partial x} \mathbf{\hat{i}} + \frac{\partial f}{\partial y} \mathbf{\hat{j}} + \frac{\partial f}{\partial z} \mathbf{\hat{k}}` Computing the divergence of a vector field in :mod:`sympy.vector` can be accomplished in two ways. One, by using the ``Del()`` class >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> delop.gradient(C.x*C.y*C.z).doit() C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k >>> delop(C.x*C.y*C.z).doit() C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k Or by using the dedicated function >>> from sympy.vector import gradient >>> gradient(C.x*C.y*C.z) C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k Directional Derivative ---------------------- Apart from the above three common applications of :math:`\mathbf{\nabla}`, it is also possible to compute the directional derivative of a field wrt a ``Vector`` in :mod:`sympy.vector`. By definition, the directional derivative of a field :math:`\mathbf{F}` along a vector :math:`v` at point :math:`x` represents the instantaneous rate of change of :math:`\mathbf{F}` moving through :math:`x` with the velocity :math:`v`. It is represented mathematically as: :math:`(\vec v \cdot \nabla) \, \mathbf{F}(x)`. Directional derivatives of vector and scalar fields can be computed in :mod:`sympy.vector` using the ``Del()`` class >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> vel = C.i + C.j + C.k >>> scalar_field = C.x*C.y*C.z >>> vector_field = C.x*C.y*C.z*C.i >>> (vel.dot(delop))(scalar_field) C.x*C.y + C.x*C.z + C.y*C.z >>> (vel & delop)(vector_field) (C.x*C.y + C.x*C.z + C.y*C.z)*C.i Or by using the dedicated function >>> from sympy.vector import directional_derivative >>> directional_derivative(C.x*C.y*C.z, 3*C.i + 4*C.j + C.k) C.x*C.y + 4*C.x*C.z + 3*C.y*C.z Field operator in orthogonal curvilinear coordinate system ========================================================== ``vector`` package supports calculation in different kind of orthogonal curvilinear coordinate system. To do that, scaling factor (also known as Lame coefficients) are used to express ``curl``, ``divergence`` or ``gradient`` in desired type of coordinate system. For example if we want to calculate ``gradient`` in cylindrical coordinate system all we need to do is to create proper coordinate system >>> from sympy.vector import CoordSys3D >>> c = CoordSys3D('c', transformation='cylindrical', variable_names=("r", "theta", "z")) >>> gradient(c.r*c.theta*c.z) c.theta*c.z*c.i + c.z*c.j + c.r*c.theta*c.k Conservative and Solenoidal fields ================================== In vector calculus, a conservative field is a field that is the gradient of some scalar field. Conservative fields have the property that their line integral over any path depends only on the end-points, and is independent of the path travelled. A conservative vector field is also said to be 'irrotational', since the curl of a conservative field is always zero. In physics, conservative fields represent forces in physical systems where energy is conserved. To check if a vector field is conservative in :mod:`sympy.vector`, the ``is_conservative`` function can be used. >>> from sympy.vector import CoordSys3D, is_conservative >>> R = CoordSys3D('R') >>> field = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> is_conservative(field) True >>> curl(field) 0 A solenoidal field, on the other hand, is a vector field whose divergence is zero at all points in space. To check if a vector field is solenoidal in :mod:`sympy.vector`, the ``is_solenoidal`` function can be used. >>> from sympy.vector import CoordSys3D, is_solenoidal >>> R = CoordSys3D('R') >>> field = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> is_solenoidal(field) True >>> divergence(field) 0 Scalar potential functions ========================== We have previously mentioned that every conservative field can be defined as the gradient of some scalar field. This scalar field is also called the 'scalar potential field' corresponding to the aforementioned conservative field. The ``scalar_potential`` function in :mod:`sympy.vector` calculates the scalar potential field corresponding to a given conservative vector field in 3D space - minus the extra constant of integration, of course. Example of usage - >>> from sympy.vector import CoordSys3D, scalar_potential >>> R = CoordSys3D('R') >>> conservative_field = 4*R.x*R.y*R.z*R.i + 2*R.x**2*R.z*R.j + 2*R.x**2*R.y*R.k >>> scalar_potential(conservative_field, R) 2*R.x**2*R.y*R.z Providing a non-conservative vector field as an argument to ``scalar_potential`` raises a ``ValueError``. The scalar potential difference, or simply 'potential difference', corresponding to a conservative vector field can be defined as the difference between the values of its scalar potential function at two points in space. This is useful in calculating a line integral with respect to a conservative function, since it depends only on the endpoints of the path. This computation is performed as follows in :mod:`sympy.vector`. >>> from sympy.vector import CoordSys3D, Point >>> from sympy.vector import scalar_potential_difference >>> R = CoordSys3D('R') >>> P = R.origin.locate_new('P', 1*R.i + 2*R.j + 3*R.k) >>> vectfield = 4*R.x*R.y*R.i + 2*R.x**2*R.j >>> scalar_potential_difference(vectfield, R, R.origin, P) 4 If provided with a scalar expression instead of a vector field, ``scalar_potential_difference`` returns the difference between the values of that scalar field at the two given points in space. sympy-sympy-1.9/doc/src/modules/vector/index.rst000066400000000000000000000014131412543434000220710ustar00rootroot00000000000000====== Vector ====== The vector module provides tools for basic vector math and differential calculus with respect to 3D Cartesian coordinate systems. This documentation provides an overview of all the features offered, and relevant API. .. module:: sympy.vector Guide to Vector =============== .. toctree:: :maxdepth: 2 intro.rst basics.rst coordsys.rst fields.rst examples.rst vector_integration.rst Vector API ========== .. toctree:: :maxdepth: 2 api/classes.rst api/orienterclasses.rst api/vectorfunctions.rst References for Vector ===================== .. [Dyadics] https://en.wikipedia.org/wiki/Dyadics .. [DyadicProducts] https://en.wikipedia.org/wiki/Dyadic_product .. [DelOperator] https://en.wikipedia.org/wiki/Del sympy-sympy-1.9/doc/src/modules/vector/intro.rst000066400000000000000000000125121412543434000221170ustar00rootroot00000000000000============ Introduction ============ This page gives a brief conceptual overview of the functionality present in :mod:`sympy.vector`. Vectors and Scalars =================== In vector math, we deal with two kinds of quantities – scalars and vectors. A **scalar** is an entity which only has a magnitude – no direction. Examples of scalar quantities include mass, electric charge, temperature, distance, etc. A **vector**, on the other hand, is an entity that is characterized by a magnitude and a direction. Examples of vector quantities are displacement, velocity, magnetic field, etc. A scalar can be depicted just by a number, for e.g. a temperature of 300 K. On the other hand, vectorial quantities like acceleration are usually denoted by a vector. Given a vector :math:`\mathbf{V}`, the magnitude of the corresponding quantity can be calculated as the magnitude of the vector itself :math:`\Vert \mathbf{V} \Vert`, while the direction would be specified by a unit vector in the direction of the original vector, :math:`\mathbf{\hat{V}} = \frac{\mathbf{V}}{\Vert \mathbf{V} \Vert}`. For example, consider a displacement of :math:`(3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}})` m, where , as per standard convention, :math:`\mathbf{\hat{i}}`, :math:`\mathbf{\hat{j}}` and :math:`\mathbf{\hat{k}}` represent unit vectors along the :math:`\mathbf{X}`, :math:`\mathbf{Y}` and :math:`\mathbf{Z}` axes respectively. Therefore, it can be concluded that the distance traveled is :math:`\Vert 3\mathbf{\hat{i}} + 4\mathbf{\hat{j}} + 5\mathbf{\hat{k}} \Vert` m = :math:`5\sqrt{2}` m. The direction of travel is given by the unit vector :math:`\frac{3}{5\sqrt{2}}\mathbf{\hat{i}} + \frac{4}{5\sqrt{2}}\mathbf{\hat{j}} + \frac{5}{5\sqrt{2}}\mathbf{\hat{k}}`. Coordinate Systems ================== A **coordinate system** is an abstract mathematical entity used to define the notion of directions and locations in n-dimensional spaces. This module deals with 3-dimensional spaces, with the conventional :math:`X`, :math:`Y` and :math:`Z` axes defined with respect to each coordinate system. Each coordinate system also has a special reference point called the 'origin' defined for it. This point is used either while referring to locations in 3D space, or while calculating the coordinates of pre-defined points with respect to the system. It is a pretty well-known concept that there is no absolute notion of location or orientation in space. Any given coordinate system defines a unique 'perspective' of quantifying positions and directions. Therefore, even if we assume that all systems deal with the same units of measurement, the expression of vectorial and scalar quantities differs according to the coordinate system a certain observer deals with. Consider two points :math:`P` and :math:`Q` in space. Assuming units to be common throughtout, the distance between these points remains the same regardless of the coordinate system in which the measurements are being made. However, the 3-D coordinates of each of the two points, as well as the position vector of any of the points with respect to the other, do not. In fact, these two quantities don't make sense at all, unless they are being measured keeping in mind a certain location and orientation of the measurer (essentially the coordinate system). Therefore, it is quite clear that the orientation and location (of the origin) of a coordinate system define the way different quantities will be expressed with respect to it. Neither of the two properties can be measured on an absolute scale, but rather with respect to another coordinate system. The orientation of one system with respect to another is measured using the rotation matrix, while the relative position can be quantified via the position vector of one system's origin with respect to the other. Fields ====== A **field** is a vector or scalar quantity that can be specified everywhere in space as a function of position (Note that in general a field may also be dependent on time and other custom variables). Since we only deal with 3D spaces in this module, a field is defined as a function of the :math:`x`, :math:`y` and :math:`z` coordinates corresponding to a location in the coordinate system. Here, :math:`x`, :math:`y` and :math:`z` act as scalar variables defining the position of a general point. For example, temperature in 3 dimensional space (a temperature field) can be written as :math:`T(x, y, z)` – a scalar function of the position. An example of a scalar field in electromagnetism is the electric potential. In a similar manner, a vector field can be defined as a vectorial function of the location :math:`(x, y, z)` of any point in space. For instance, every point on the earth may be considered to be in the gravitational force field of the earth. We may specify the field by the magnitude and the direction of acceleration due to gravity (i.e. force per unit mass ) :math:`\vec g(x, y, z)` at every point in space. To give an example from electromagnetism, consider an electric potential of form :math:`2{x}^{2}y`, a scalar field in 3D space. The corresponding conservative electric field can be computed as the gradient of the electric potential function, and expressed as :math:`4xy\mathbf{\hat{i}} + 2{x}^{2}\mathbf{\hat{j}}`. The magnitude of this electric field can in turn be expressed as a scalar field of the form :math:`\sqrt{4{x}^{4} + 16{x}^{2}{y}^{2}}`. sympy-sympy-1.9/doc/src/modules/vector/vector_integration.rst000066400000000000000000000137661412543434000247050ustar00rootroot00000000000000================================ Applications of Vector Integrals ================================ To integrate a scalar or vector field over a region, we have to first define a region. SymPy provides three methods for defining a region: 1. Using Parametric Equations with :class:`~sympy.vector.parametricregion.ParametricRegion`. 2. Using Implicit Equation with :class:`~sympy.vector.implicitregion.ImplicitRegion`. 3. Using objects of geometry module. The :func:`~sympy.vector.integrals.vector_integrate` function is used to integrate scalar or vector field over any type of region. It automatically determines the type of integration (line, surface, or volume) depending on the nature of the object. We define a coordinate system and make necesssary imports for examples. >>> from sympy import sin, cos, exp, pi, symbols >>> from sympy.vector import CoordSys3D, ParametricRegion, ImplicitRegion, vector_integrate >>> from sympy.abc import r, x, y, z, theta, phi >>> C = CoordSys3D('C') Calculation of Perimeter, Surface Area, and Volume ================================================== To calculate the perimeter of a circle, we need to define it. Let's define it using its parametric equation. >>> param_circle = ParametricRegion((4*cos(theta), 4*sin(theta)), (theta, 0, 2*pi)) We can also define a circle using its implicit equation. >>> implicit_circle = ImplicitRegion((x, y), x**2 + y**2 - 4) The perimeter of a figure is equal to the absolute value of its integral over a unit scalar field. >>> vector_integrate(1, param_circle) 8*pi >>> vector_integrate(1, implicit_circle) 4*pi Suppose a user wants to calculate the perimeter of a triangle. Determining the parametric representation of a triangle can be difficult. Instead, the user can use an object of :class:`~sympy.geometry.polygon.Polygon` class in the geometry module. >>> from sympy.geometry import Point, Polygon >>> triangle = Polygon(Point(1, 2), (3, 5), (1,6)) >>> vector_integrate(1, triangle) sqrt(5) + sqrt(13) + 4 To define a solid sphere, we need to use three parameters (r, theta and phi). For :class:`~sympy.vector.parametricregion.ParametricRegion` obextj, the order of limits determine the sign of the integral. >>> solidsphere = ParametricRegion((r*sin(phi)*cos(theta),r*sin(phi)*sin(theta), r*cos(phi)), ... (phi, 0, pi), (theta, 0, 2*pi), (r, 0, 3)) >>> vector_integrate(1, solidsphere) 36*pi Calculation of mass of a body ============================= Consider a triangular lamina 𝑅 with vertices (0,0), (0, 5), (5,0) and with density :math:`\rho(x, y) = xy\:kg/m^2`. Find the total mass. >>> triangle = ParametricRegion((x, y), (x, 0, 5), (y, 0, 5 - x)) >>> vector_integrate(C.x*C.y, triangle) 625/24 Find the mass of a cylinder centered on the z-axis which has height h, radius a, and density :math:`\rho = x^2 + y^2\:kg/m^2`. >>> a, h = symbols('a h', positive=True) >>> cylinder = ParametricRegion((r*cos(theta), r*sin(theta), z), ... (theta, 0, 2*pi), (z, 0, h), (r, 0, a)) >>> vector_integrate(C.x**2 + C.y**2, cylinder) pi*a**4*h/2 Calculation of Flux =================== 1. Consider a region of space in which there is a constant vectorfield :math:`E(x, y, z) = a\mathbf{\hat{k}}`. A hemisphere of radius r lies on the x-y plane. What is the flux of the field through the sphere? >>> semisphere = ParametricRegion((r*sin(phi)*cos(theta), r*sin(phi)*sin(theta), r*cos(phi)),\ ... (phi, 0, pi/2), (theta, 0, 2*pi)) >>> flux = vector_integrate(a*C.k, semisphere) >>> flux pi*a*r**2 2. Consider a region of space in which there is a vector field :math:`E(x, y, z) = x^2 \mathbf{\hat{k}}` above the x-y plane, and a field :math:`E(x, y, z) = y^2 \mathbf{\hat{k}}` below the x-y plane. What is the flux of that vector field through a cube of side length L with its center at the origin?” The field is parallel to the z-axis so only the top and bottom face of the box will contribute to flux. >>> L = symbols('L', positive=True) >>> top_face = ParametricRegion((x, y, L/2), (x, -L/2, L/2), (y, -L/2, L/2)) >>> bottom_face = ParametricRegion((x, y, -L/2), (x, -L/2, L/2), (y, -L/2, L/2)) >>> flux = vector_integrate(C.x**2*C.k, top_face) + vector_integrate(C.y**2*C.k, bottom_face) >>> flux L**4/6 Verifying Stoke's Theorem ========================= See https://en.wikipedia.org/wiki/Stokes%27_theorem Example 1 >>> from sympy.vector import curl >>> curve = ParametricRegion((cos(theta), sin(theta)), (theta, 0, pi/2)) >>> surface = ParametricRegion((r*cos(theta), r*sin(theta)), (r, 0, 1), (theta, 0, pi/2)) >>> F = C.y*C.i + C.z*C.k + C.x*C.k >>> >>> vector_integrate(F, curve) -pi/4 >>> vector_integrate(curl(F), surface) -pi/4 Example 2 >>> circle = ParametricRegion((cos(theta), sin(theta), 1), (theta, 0, 2*pi)) >>> cone = ParametricRegion((r*cos(theta), r*sin(theta), r), (r, 0, 1), (theta, 0, 2*pi)) >>> cone = ParametricRegion((r*cos(theta), r*sin(theta), r), (r, 0, 1), (theta, 0, 2*pi)) >>> f = (-C.y**3/3 + sin(C.x))*C.i + (C.x**3/3 + cos(C.y))*C.j + C.x*C.y*C.z*C.k >>> vector_integrate(f, circle) pi/2 >>> vector_integrate(curl(f), cone) pi/2 Verifying Divergence Theorem ============================ See https://en.wikipedia.org/wiki/Divergence_theorem Example 1 >>> from sympy.vector import divergence >>> sphere = ParametricRegion((4*sin(phi)*cos(theta),4*sin(phi)*sin(theta), 4*cos(phi)), ... (phi, 0, pi), (theta, 0, 2*pi)) >>> solidsphere = ParametricRegion((r*sin(phi)*cos(theta),r*sin(phi)*sin(theta), r*cos(phi)), ... (r, 0, 4),(phi, 0, pi), (theta, 0, 2*pi)) >>> field = C.x**3*C.i + C.y**3*C.j + C.z**3*C.k >>> vector_integrate(field, sphere) 12288*pi/5 >>> vector_integrate(divergence(field), solidsphere) 12288*pi/5 Example 2 >>> cube = ParametricRegion((x, y, z), (x, 0, 1), (y, 0, 1), (z, 0, 1)) >>> field = 2*C.x*C.y*C.i + 3*C.x*C.y*C.j + C.z*exp(C.x + C.y)*C.k >>> vector_integrate(divergence(field), cube) -E + 7/2 + E*(-1 + E) sympy-sympy-1.9/doc/src/outreach.rst000066400000000000000000000017221412543434000176250ustar00rootroot00000000000000SymPy Papers ------------ A list of papers which either use or mention SymPy, as well as presentations given about SymPy at conferences can be seen at `SymPy Papers `_. Planet SymPy ------------ We have a blog aggregator at http://planet.sympy.org. SymPy logos ----------- SymPy has a collection of official logos, which can be generated from `sympy.svg `_ in your local copy of SymPy by:: $ cd doc $ make logo # will be stored in the _build/logo subdirectory The license of all the logos is the same as SymPy: BSD. See the LICENSE file in the trunk for more information. .. _mailinglist: https://groups.google.com/forum/#!forum/sympy Blogs, News, Magazines ---------------------- You can see a list of blogs/news/magazines mentioning SymPy (that we know of) on our `wiki page `_. sympy-sympy-1.9/doc/src/pics/000077500000000000000000000000001412543434000162155ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/pics/consoleascii.png000066400000000000000000004236401412543434000214070ustar00rootroot00000000000000PNG  IHDR|1P iCCPICC ProfileH WgXSS@HhH ҫ^Jb/ !KZ+".l9uw̜}͜yf`D)<Lq+:&Ey6'Cyw Du3ֿw N*G9"q&$žނL7A$B\N1H16 .hl8YYDhG+B<bͅx SRS\Qvlv7lv7<6:dR؋F?Ujkф5-#9,0o 9l0U Lq ?b%E>Ir;HaPa`!dxPl~xԸ&"4Z:gdM|ϙ$v1߲PC4ZK%@(3.L9>I؇'^xp?Ø1Lq8c>0sowi KBy'L$(*ŔL )i5J/僔TPjT~SRפI KKK;JKsIo.n*+=LUR$JjzFFFFGAf@fL!K22i4'mMB@5t=I@?eN.-&RNZN_]n\\rle%o)0,R+*)R k)Ua` ]'X(gg* *+ *+*[+G*/T.Q>ĘLf s#0$IxOtm{*n*<\:*TYުɪUTj&jR;60Yidɇ'SGMCSoSi81tLܪyJ_%ڪuZ9KJaαյ%{۵u u"tV<ԥ&nmқDF>_EQk  U k э\ҍʌn퍓ww&6&|ti))eSnͲj̺2M]5aizbmvqWsr,,^[Xr,K,oXѭ|[5Z6Yﲾcða֦拭ضֶN.ή}}%rm3;dߩot=:l].,8=.]ڮl2nn\ gI_z{=yt\yzz{+zGx{?I]G w_ß_?`4\ -0,8qI8i:#`Ɩfl[6<+dVɬKB/1{1~Q$%R.rNdu(iKĨbc)Cgo;fNΜ[s .:Om^ʼ#EfK9\7Vn?ϙW{PЗ蜸%/<łWI~I''W&DԥJƥ* 4uLE9tm@qE171S r$F$Y.Y%YD.8Papa"E=e1eK/ݻ Ye5{WZI]U V]iƚkz~&G6Gs{uuX5{9<0s>'?˾>g?}!z1<Ÿ/^WW#ߨ|ke(dѻws?~h⧨Oφ||.bk###"=z`&$ދb١hT F A? *X@P3`ч1? VV d'#r 41<|y /⑑##_.cw2BM=rjm_A|m`X?h pHYs%%IR$iTXtXML:com.adobe.xmp 1810 956 Vt@IDATx u[Ii@1F; FI 1N x% I,d= h{ ,lK!-$ć4yo׹ܪ{=uouK[u|?>NREF!`!`!`!`!`@S~S{h!`!`!`!`!`Cٺ!`!`!`!`!`@.fe C` fa]CȀUS[A|}(ovyQUqϏFӋ~,C0 C0 k9ӎVIvq r,c@?&6ATƝ^wb](:琉8moi{岨HL@h[9FIQno^VйK;77xQH<%Nwn?}[t(äpPދC9^j-ԁ]@!mǙ]RSLAAk3fGd'ageVlVu;`' Srގw8"0F_DQ:}G'ԎL %9V`38dF|N_OMӆq"Q́mɪϻv̘ڶG^$f䈓LQ.da q5 pҹ^&JI߃8Aa<޳s?ۃʮZ0Zg8XB-Aڽ"cs~: 0G8vm!`!KR,lYÑu:x ]&+p(ot%)əPlřh/t>/Qx;>!|ݛ.͇q(?ȫtd!D+4v` ɸHD6: _Sq7iKIOA M5yGˑ*K&kՋpƎ:8{4:";Ek Gޏ?R0lށ?󼓲ѡWvRkq>ǩS(wgQѭ8Ξ`Lit rba݇vDsm_Fo-^L恻y.BASzjwDc{jC̉##C0 C0 J 6AɗW zW̉Cy Ɇ1 6 (+1Ficlq"ANBߍ{-NFsoWqq+eg2u^}qh-,2 eS(o6[zBmg>uw!Ng:q<_[x!`!`@8F.GFv@ @EΛO)471/n};>wa(h ^e^ڟ~h# ?`ȼos9˭vV,J1/ٗe[F먛;;n GbTuOZEš:~+U!qy?|*D~$}(.1,ĸ>~Α3y9~C9WWq]r=4qE S0(^8#]]} Nsk3# y'EyI˺]yW/vx厽fc18}<C_Lu~%"u&ѳe)!p$ߡu7ȼÜ>%A;fʉK5:&ײſz_>藚Dȣ wI<$_W4Cyš_,㙷ʠjA=#ȶGwis(ge!`!`t OJ&p<#~L3lmfX*'2LvH6on6NcxduwؽМtg=2cG}WtFG07ߕAyƥӷ寗4@w#[pq_ 3TtҦ2nFf83) OCR RYdWvXYԘk?^'ZVʯ跣EOoplbv5i#g'v1ߧ@e( 梇w2J]sJAm.|uz\ )=G,$n}C׮ c݊>]"pɡ7[{1씴h. C0 C0@m(Oh駨<R(h"9AmQ}pkcgkO37ʡ_$h26>olW4'~c6[L\{ljiȱhby{y%{9ӟ>T1F}[vL}4C^c`dٯGivY5]:=bD~L)<5C\9Vŀ]8aAg}0բ%[s֍Qx^-KrR{hFڑ̽!;?-r00iC_uxGٺ)d5Y\h6ouJf|׉9/2"iQ'TۻӂЕHγ5EG\|Bag˹i'gBVzjQ1,D;LHk!`! -pqkpibqܯ 'UzNa:Z_7?/~n)~p7=+ʈ$v2Wšn)v4 /yZ`>$lY 0INI˳07TJI-3]@ps_:i)ϠϤ6˼~S&.fe{U_]źudu}J8sGU8ǁkc\ y^cǓy*oqhob|8I>식3c>XJĊ5ۑZ }>r&2gm晭Jcp.}@ 1&)^uo"7ahgv>a-u83`&ɒNە̧vh=Ƌi̪1 qn(/wN@1*Cl5Eq8l;Pv填hC99xI^ԌB{W33@<8jg5#Ĺz>a]3".,lBߕzR]>|\ywϾ3ȩiEsYo,a˙WTlNerF"7x-4F`L ޽[CuB-yم!`!`@'xآYNv)FWc/=`iZQo=/š0q:NX1m'"<ˢABFH9i{`hAw&?iY/>Re|t,d>l |e|Ʃ<=[XgEO㰤ctށ}9B9+Rf~FPf$&_drf*ɋʐ=F9+rn&p'cKd5PԪ+= s$ΠBmg&6 0YyuZq`,Ǿq:`6掉RkԽeizA_ -ޚpb{p򏸛6~Rɢ%1 C0 C(m2vsCSzh 栬SU;.Tiyu ^5KY?i..V#q.?q8C釱vhE6 io_l=kq{MJn#8/oY V3z噷ВEРƫ.M;W0G2,aXIN(=IE\s˗8ųqki}| ߥjBQ.k{/U͎/ocge/G#,.C;6ob/B?oc|1 -`,3%g%M}#G^ȹֻ͋񽍰ϖ@g>Is)d:Dڒ(}p+ #}C#v6ȸj,zKh-!`!`@pUoz]qFpczmPOߓיDphUzJqOp #:N\D\ F_[)Fzv#(~k1*A8 .WT[<Π3 SXޝ\)yGpMNq^΁=Wi>>/ڙ,y!#uıoB{U/IC~;ы\w&/*O {*Z wɣQ_H~T=;&)^wn@TM=.9 \N{:rąlHp$oy}c ;4Gp'KRZbqE\Z$C0 C0 n#U޿= |k8Éʯ8?(ƝЕPu™uK;Byt"lHMDy";mS#\eI%]ƹ!/iU8L p/ۡlJ +%<~~q $ @R،uqOuʨTSRƱ핐>GdPg/Qn|NigyPzijˑˎT<֋ߍ{h#c&v#D QuV1̘֕'p,?r8E!66yEezok:}ϝ^z0ޢy[.t6 C0 C:;ΑLGS-ݵVjCy ebNrs~6 PkȧK:*MU'JB/CUU\9|QƑ⸴Gd'k,ʖvO6[Ӹ$~$'-wN-{؍)FNQӼgv;vFWyvJדMj'~uAnygW[w$yQjGΝե;Ģ{ RdЅ:AhPd{GǟR{+;z^6>9~]z50$:BoW~O0 C0 C(-reSq'c x^0B: _ lb3Q? 6fX4?W2v؎b,4kg\VsYXk58RHGwH~9Ǥt.$5 ?/$hH.~q7>A7LH8H= SM#J,yYt'bvw5 9<{ pqykd>yo™?Ρ,iGСŽ`-@8@ iZܒ7 C0 C0*@'r Payd^/VN6^Ġ\WM:\-Ovd~1*1:&̎a99-8N~36ʟh~UBZQt26^㨍'xoיִ̓jA(ޏ+NZNˇ {Eikx"hSD|SO'q|q3.2Έ/䡌Qt4c w&}g5фͮ= uǡz={>wՔK-sp|1-ڹ{<Qtɢ^~P˪VMqXd9vZ_ܤp3~Nw>X?Df9L97)]ze&AF!`!`@@yzW' rgүb$E<%?=Ua]]a5Iq&m EMPNGX>1X͘S1w1&xY/G%|@ *U Z^[fmY\18۹0 C0 C (Z oFs$|Eڇ|>bA"(uN 0PԎV]A&?3}Nq(Yyfn[p`v~w^Əcޓ؅bSN M[9dEKo8C3jǢlGcgR) ǹuK xJ8 2?8`W:q(1|_YQ<,lxvՐη~I f҇sN__ܸt3}HWB;-nJ_WESu*dj>z o+"-M:75Yj?Hq Δy$x7JӴ Tzt Ԫm;Gekᆀ!`!`# gQ^ :rK؆"b1<6jāM 1ވ:j(ZV,t]CQʃsp8VFlݼ]iö>!NfDߎf1 &1Emcwr*NѼs_C3e/I=ۑ,ki ݭ0>} Fg尳tkg˂]^i(1aRi^`zH8GWUf%y2>c'3&Cbd G:@{\ m(?_>wxjF>V&ΠUF="ݳvY-]™+Au_%8P>dOU+gܜ3O-o'UY?;9_eQblK!;<-M9Tu7V82JxoE=cSˎEP͒Ok4E2r2PB-A]|d[g \\5 C0 C bj_}Yqj)Fd}Q1^g=.=0 C0 CBTǡRMhe7!`D16'r YoYM9-8SW*׭'6M֚8:-kF -vFem,NK҆!`!`t+II>Y:9f v`g8 v% #CC@!9GIYaSNK&UsMMfmNvܢ{xK-ts&ca!`!P1zP^7R<Ҟ^eѹ~k2v )R˟! !г^;(VLU_hc:v1`7rۑ<Z`!`S*nMpTˉX9d!`Ljb_݈eݠ8`K!`!`Dwg(?ĹCyg&/d#C0 CUՖ1 C0 C0 C0@_v%tV!`! 6u5 C0 C0 CΡ<Ɂ3 C0 C0 C0 C0 Cnt0 C0 C0 C0 C0 C=̡n0 C0 C0 C0 C0 i9][ C0 C0 C0 C0 Ch%RE > h~(:m4j7!`!`@!,1W %Ȇ!0xwEbx3=FEGё~Rڗ%(bidN .#13%ٌ =-%@`(:@Վ~"ә)+!`tۊ<07qkݡ?̙̊!6,m^qOw iwLw,!z g9YbGiM(n2[Eg)ͤ +.T>9h+U b]Xߎ)0v|'Ɓ(,*j/п]D]v7)-4[1/WCX1-qOF5 F8$F)E=[o6TE):uMqP_Վ gf{j6vuȮM\YƼ켿_dw,:tݘxH RN)10+)TWdM 4 sq6Y+p`:K/1R>Uq8BxAgϼyb;a/0ޅa 1uoXvЎ#.Q, \bA*R:j>cyLQ֧y~*~?۫oeM.#Mq[{^7|_XEM\ƒp$hGGA6x6qymȕW`+m|kkؙ6tr5]fUa1(Li`[ DEMrD f;[0LP$s zw7Jum,4EqZ+4⡝5ϰr*kn\sanGa\)f(v__Ƕ o+?H=g׍à[(?r2cMu8;ÒyI>xQ3oA qw&E,6\סNάH9!8״R(SV*F1\JZMjsB_+ a v^})h)2cnQq@üϕ&ulcAgEګZI:̜_w(3m,f?H_rhMm e\yc/p2ϭ(q7.m~orϛQYy.Op2帰v矉ڻ 5W/DXӏ}y7x5[|cN.2a`[ケ_\XH}vXNR͡wW+gr-_dl$rܪ3Ⱥ3ʐZNv{U􅇱[c:^_W{ o!pycN9*nk[9pmTibEo|36uS2-&1L"ZSgr\OpuϜqݳɝfzCxrB~ ;hE)Kx%-aLTrd^ѳUc q E7}= %sv3AT.jyc/lwL>jK/W`. i"^L)Żx> ɟO7f~.;|XI N7{%xBdW8ٝ'v%WӷJ[_ ,jق1Npʧ *^eT`_߸5s__90/ &iv [U ?;bkRCuqp?g{;NUsؓQt33?>V|̃RwD8w&^< ̩h|vxT" ;挚z¹Sjjhq ^wC)SDp,,xMW>Φ4\#wЋRXw13ZDQ?9+#SvSb0GvAr#ǹȇ}3\2F;Efy;g(X_?>ަ#6z C):/<0 6\XokogH?UcP4\8 G;dk0.8F>V R%8>U{ ()KVUGւkqR~yG]tۥ}=68?'n#QG7#-1piZ5 |.S_} \۴Yfs1;Э0s 6'~pF3'C)_#3mÔ|C哒uˠJWK:0/<a NdLG}d8s(c@IDAT2%ʳnO|ߙ*L%qGfU`*w<ʿ.Od8ՉfM̫ȩחz$ (oE2E<,Z3M ~[*2D p=||۞r:Sm,<+MwV󯟶8D]Fr1:ib2y?oOYy0x"EhXhS !OC?Xl5 yfiE f-v&^EB Г-zT]mB)Uiw~von֛~enOL"^ͺ O;e7I#-f(缉IҮ?MTGYno}3LpI8G:G< CF$9Ƹ(؎Vp&CaF&uc\Wr ۼ $xؾR7|H& gusGR Y9|xN%;b]`oʍPj?8d3Yʑ}Uvr/_4:%Z>aV?v\|$jJg\l >;a!0uPR[av2 D$ͮS;%{X{B|ztty*Gq7]0yv8BJ4*V(T#vhHJ(S'3pFU{H);(es^1V*?TzQ)xp;u5 od!%6B&4n pO׍>kYi ]%"_NoB^K CӒUmtn{[ 1o]EwjO_nr2g"Je*vγ!H6\ :ìU _r# '~ЧCQ! d#-%v 'p񿯪1F˞z 4 @;2)}!lulUBӪ"Gp;?TDZ@; 'TI8@2?U4K䅉1 s5J?X7Ƹ VҮ >Y__R|=tu;ۡ}) +S$S;Z8l0 mT+t/-1ы*Be~(ن'\AUm\w10rׇإ7Hi"tv1|;5⥪q6ך32vife F{bv7<<-gnLH0C'Q;rqQT_f M)%+gFс~^{x8~qfc8~ӃEcSZ3HNdG7 s"K Dr#nH~M0 ZPSKHA%~xUYǍ9Xw FlO'=oN!PU&EO$8$SvGOz3N8YP(*W8ܜtɈ9z:Ѧ6iԟ]{~Ӷ8OYT3:Y!}oNFt\7'BQ^:𝙂`.`MP)AUx y>T>.UluFaz䀲,l@ܺg WU6 v㴠+Bσ)Smj.өZzjx~ ){\T?Mi<Үݚ{v,gㇲ.+j;TU^Y&Cßqqye7-, 򧉹rUgdny_f[3[_WAוj C-8*S|AiR*ʩM^ߪ!p6(^G-[ydx}|P5ޑ}a'+vo@PW"XI{>q>|9='ȱ~F:?8T>~mݣhL&o1^1w<m|ҏ|fK˙$م?^n@Em걗̅wW%|cM30^2-$;il-+4MEp/+T>~mW Xd_A'zvF8$^PjHt*Lg ' aQθ4ؼg h޲U|xN3#Ґbehe.z~"%;oYngٶ8ίuJ&vOͼ{2u7qU : B~SWG&WC/jgĿ1E9"t?˵U`Qܥ_C0*eȍSRW(ډ5Y'S)ny|QQ'l8ӉM:\]3c"GRyt:y;#E)?E -!~qQ]Rx_{Q2 ˳6wʛL{}WX7}=Y-.]5~B8%㭓>,22E@}5(ljW{E1wsEA 8,%td*$*sKc/Pz3%^-y BԣjvAUHJrMDl\݀_s5yW;4/rNCpEZ#C0&!uQUޯ89)Y&h wEQ~5T> kșl$QXxM70 ^[(}Inٙs"gێSOe-ݭ \vOJdd(j$m %y&e%xl#{ R iڸ| xS wˇ=zIsr֧01a7 dXK{xufGGt18_"ʣմ~$ m&jW'c{գ2aO1).鳢%Wvtlz [GO)^ТGUH<㽬y vkI䨊:̿ͅh?Az^8Td1|\?3GQ7p1.?:9:πڇL\,. Nov2vV.hW}uݳ<DwnX5*E=Eg'cPš,ǻ}JUl/2pR0F C0 {AcQE)ߋ} cCB\_P4\015[ijy彭0ғz=0IpۂxoŀR ꈟe1rd+J3Ok("#Jڙp(G+M(@-E9YD7c,rI>;gk|s0vZ>;T^Il@vq>R\,>MݘȞs^FO/cG&臒y|bF'{{6gFl ybdixEfM=`#%!Ksf>Bt6sg" hS~DDnA`cQ/X)B, ΏNHj} ur+utWT.h[C>tPtL8}Z~77wqʎ{0 I@ʠ(ݹ:dze~?sbd~^3I})gp;gBXrB]>]+Gȸw+| )\g$ ~S-dFgݢ2v64=JA>MEpg#YA,hr N_Wj1/;dmC'.'B#9N$q5Ffwdk|DԈ1:9R?CBDE&ٍŲ:!WVw(BlKة6א~ xO<fs 0v|H,/{anתPqAۆWG@7f0{ H" D}<'xq)~ >5I @^n؈5?o,nrf1ʧ|4[Qf^|긘?g|;$'30+[`{Nܖ mԢCC擹R!b:YU~Tw"Ytc.h/C?$ k4W#_Ia$=CE{i`f3CGO6l@nEUb],Z豊LJSʲC0G@gvʕO9Oyg’s5df{ Fc3$<1vD#yi=B|xU2Tȵ>GM?R<)C_@ѸL PvC{AߨGY?6lpނW_cD}F1ڊ83u$MҔRNӸ@BB/8UQq*,Xx#~E} Boܗ,{=y|=HyqN*P,kOJԣ7iwA[-VRyUV'3yr%Y@t(>喇Es_K?2|Hig nCOޥjBgՊ79i1v2+oMѓg~wə|+Q2?p^x+:b I4Z|xy\U. Q,Z+E\>,r]&5-*yRP"f\.!ܘZDC0!vPnNU(Σ[S!p3 %xH(i=i<gAG9 (Ux(T>Y ]uM 3J.KQvJ4j~Dž-1VC(YŸsݏ/RD}U'WYJmd~y?v-|.2C|te]էEv#CZ~pg3b?mROAȻy[RvSo¹mfO;'[ґQo_;Z#țbW &oujXQ2Sj+Y]lx@LJi=xc}6Fޭ, &B)kU=7 4 ɊxTkrwtӨի:2VXz YxWf{V\afB`|@gcőQ'chPHAr;Cэ~$= ~o4:KdWsW8gUեBܿJz6І\ )ꇡIa1Li0`X.@5ԛ.8c2L|}'0ݢ*΃X~-ؼ#n帐.j倉S9Otl {~#l}m!tDXt,BR7tm؂k_8.ϕl" $:] Y0,s_4W/J_.*߫(W+k!!`L)boku^țsOCHiRχz|p}dh6*,2;{s:+nC!8M㣭b?E'2cdBWyӫ<_3HRVAd[nXnN& \/U^bT+>&<_$g> 춁Uڟ۩Hi=EEO( QmDjf G#҄4&-aEЩ|/v\;p{b}?6ad{rWc7Ψ{l"|(iw]9㮁0fƑ=8frӐo`86 g~Mغ*swf kn1n^E"o>%N6~E*Kx%eȃ/C{HS(5q\dLJJ=zΰ"9"A6DhQ| A5IGeQrc">"]9ϧF93?O 8g(|Ѫ?ܖ:_eA[TW{I4&:!a=)tINcAus}5^iX2L7BfT#`gx/f+]Rd~A2z'2*Sܩit\wb9s|#_zdOeQcTN~ IM<ULy9tD\q!n37J8/nǀ$ѥ8L+^fw&zMĀͤ 3+l0ogl\k6\_Ѫ9d};"('B{Hy8EFf 8AroN_ꇓWH|VNq}(u)Z{1NsYw+7ɯ_b|}qp?/糳2o'~n,e:cg?RU!伮VPg6Ů; (Bȍ=>tN`+D`6,cwޏ#Lva#9轫SSܱSm։ܘ"dĮ8MޤjFbް 1f:?d~ %`+*cELpY$ ]uZ w&|Wh+̚.Yx]B>wNBX+a=iʢZ4MbYxGrh&Vw{;NgLˤbj)N<ρsJ= JAyz$ c#TxW@&p?iO}G's{Pҿ$+uHy;wV& #x1?ˈ+]~24!TDn8M+7GI2N.vW`<MDl1ъ.NOqi?t_C`! ݾ7$:Ӹ]8gR ˜bq;+iLٌE;J&N,^ϋrWjg7<7iî(:^o8ć}Խ|( 0s'lGWXʨ >~jw2)g^mn1F*Qyq 9-XH~I8%i/?$Qf3j˒?{~+eq:&8DQ3>=).P1"me7 Ñy)X[`Wqڢιs?t& <ͼ$թ=.2: ^#F_zYdP$D9u+s!FWy' X,CXHct(OOXT#v]sp ɹjGTX?[X)F:*Tga;kF+tbcz~c2.bdQ4NCìzZ!P!< ky8}ZM^ =i8dDUy JGP !yVR vܘp?ʳ,<>m{V}-|AVؐ#SYiݸzpty("&v/E(c9U+YpZ:nSn,\Bfϡ拆|H[a8pWՙl_ir^]dv@j7jis|VN΀0wClp'7Q69HkaUkwr'YEl3G܃^=ؘ>hwmk*g2Ars5,#+BbH\9|eg?0M ;[A(=ҥ#.`;euA,_Wĩ:>{V-|uijW[?i21H {G^NZ!F2x}惁9lWnޢ@ 8mFlٟY NJUܬz6"1>o8S3f>\ꤜH?:r#xXd 1ʪWI{;-{ƞ+3qc!tϝ ۹Z'A#)y%v ^XH.Vzʶco$1kN0YrCO'ԛO:תMUǧvo =lD'e;ߧW`=ǽWO.Q߫^N=mp8^VO*]x˦(mfϥԩhz5Ee\FN^c 9kWFwE_MӸ*K벊Cήs Ц(enGNUVrĤby3U ҟ;͛4Ӫ{. D=QzylGɒ@Y݈ZV{v;+P*I˭v*١LRPtoI;imxw0v?{D{:$Sr:ݨjj֎p"o;ES4cJzP׮;mG3xHo"Yߪ׼e4hs6Cbd1H7Jc'V.;@oP o_QJzXr^W~ɍ=AWUUxolܼ}Zvo^xTo@Xs/{ó$IU/@I4uɔTf2ۿƖ|n5ס:wgWQ&vy(,gt>e!=3Q >A}zfZKQ=5YXMfs?Iz{wsRpW)@D3PUa0u->3N+ja5BJCή,9M. r#xbhxUzš6ޛZi|?7oV;5(eF^R>>r aL;cWMmI v6:X^rrocyOU'R*J{|#k:BkpBvVʓDlی9gɛ~xC{HQ')m 3m 䧬kmPp%!O C1(Py+:gODܟ;Ew> ؾTromʍR{@`_UW@{sتi=T>L%͙,幝yG)+-Nkq} l0 F@J5aL(uq:n_D1VeGO։U8&&>l,-L{&~j]ʫ@?{eGq{VB" @B Xcp9 $bLx:(,[Ha1bx$z@΁Ŗ`BA(~έ;ݷT?UTկ~U]s@XAuf5fӺJY jWdcNݡ+m9՘ s+1+ 1)~rKyQe﬽o+,/p2\`@Cqsʄ>s08W"˘iI)Z;S{a.E㦷Rs/c&JԔ4¾T0E(ߝ8YK.zʶH{Ą]b r ?ZL Be=m(mWfYX _l 9\az~"A kO8#.wWTo5QU?xҾay/Ww}wW l8>,Xi8l\l@@+x*Hl\\ cF=G%" U\|q}:6d\0{f){ I `Oi]|OdR]nYEXcg;X0y#B=,?o' Gxs.O#yޗ_>fȺW?ez\BRVWaYz*ڋQ~E_v!];_Pi~ΐp'68 əgz@=t1uyv7wNꗇrY(}3sj=->Na ߰6bq"γ"SOW^'j\P [M"s)5oXx Z]X %30`wjka:VA͂,ObȰLGsa[?/TZH>v#180 O8/exFƷ|,zEEpBz01;n,DXTgA>@Ea  !kuqm<:wgȕ)5 \s{8];8k>T$&hҌHSPVx9DZNAG`Mպ}{GN74Y\S+̧  -ٍ6٣hסC$5&;_Fo_Ar0tzzҹAC ʀRoLمpU]嬫[\q{Ey]C0eR46tB?m*XYˡ L|o'daNoi0i\|0P̞?uD*¸j7̕ d hث+nb,64( 6xB.^`OPIơi0-?~0.މCnK=1re kMqazQ2 _X@<7[ #gz?QPݪ,Iyg=K0yGŦ!~m!&MDYR9<~qf.B0garE:;^ Ez޿ Q}wTߝuU|K3@D,x{W}qO0"V̯$P ʽ qw*Ʃ0 K|߽yuժChh(*߳ƹJ]kK;=6*NxH@Zj'}Q[YtG"^߅ `8>EswY'ie=5$K$@$@$@$@$@$@ HWs=FS8ܪz5P|Wo!>ؒ6} @+@|/BV>ݪ?y_X(Z^f؝st5SJ$@$@$@$@$@$@ aIĞɋwr*'q0yySL<G=| SWd6L]5:NXO'Uv3$@$@$@$@$@$@n h Mp] 0pgsR7;x{KexFY$|wJJvhVb|V*OP`oOm.2AC$@$@$@$@$@$@$@6mIxN$@$@$@$@$@$@$@$@$@$5,[#          hPn̈>HHHHHHHHHH@e          DhPNHHHHHHHHHHA)dRG}<⷏(sd!ЅlRG0J,)-}grR|/5c"    h)fKͯĬW+f?}~KiH  -ڱq 3ʀid HHHHH`3oNdx.-=@ȕG86{{R'"וڄ+oK9>ː+}Ne#     b Р\,_՗Y[tۃWHz k,t$0 _i\ovݘZr.Š[gϣ0y=,<^#     IB3F6a({m?: bv+c0$pZ}e9-3 @4ٸӍ-b+ؓWݤ@> Æ|A H|M Rd6 M$@$@$@$@$| =*n~} 'bB/)o~ ~k| eoJR3Ӑs2ԕxnųU#~ @w# *;>NP]-,Rax9l]vRg-RF]#cǓ9_Qyϔ/pWB]U.@裲#ggP=h+{ ol4ΕI=zRWb.A&t!Gw%pLWgw'+ኼoGx%̘.v8G>y/>~C4Lz ę\*-`|7 tRg#IHHHHH$),! ۱ 0(sk=O5{A& EJfWQGOr.)Bm6犨ԯNXlu#u>z)rԄps*ߑU]6lu &ݺ>'y}X!WĤ0xꗘvAl^I^\18[Xj܅eRZ+qX!_W0 \\3s |_x[C0*t Y(5{ߘX~-&wˆQ EzwaF3qfI51X]s|Y>@km^_q'u6 - ]"\+eu/8#"Q%X݃0{ [7ùwOM7[<wQ"iy|Df!'¶PZ CzKJWu}wUMK$@$@$@$@$@%0Vdè#]HW-f%Il$b${zcTEQL `11d `yQ'XVqx5ZSlr6晴5C?w An$~ck&uƓϊKu|`v%] e1 y"q}ܛYK؄ӬEUq&Mï5-j%1<>pv̎`oڋ0h4Lny' WYT^P}/<9 8& Ŋ(u~${k@'VՁWhaәN\=Ɋ-e7V+f?F_^WuS`x6'0 턁ڸW,vHX/Uaqcpߕ!5aOV'C|gq{,è-WΐK.W|\s+M}wpBzȶ3S\tzO+aJ_ `(v<#@J@qEwg HHHHH&Π}R-[tV##1XvNͺ~|, 8i_M=EW_.ثVZ a~8 9yM*]3cܟGyܔ+/XoVeԯ49\C#(^N7-F"\*e9     (@),Z[ \YNm$oĞQ!N5ȗȺثwxR7`g1nRjVE} 'Y'r1N:תWȗPްE(wem$^(aܿ]0Tb>'9;BZ1YG8\> Ge{1M7Y;d,^4rcG*;ܤ?     p@ ΔbQc]Wa uz5o[81N[3m,>E;rTL2 v> `Eu뙫]bˊGVWa5LᦐH/?QsC+$9MkZlT-ýX\sx;c&?\4U81}FN @ PQw,̘ .,ccַpS:W\u+QK`8T[UEEӸ^a0c~, 3_Wr=9` Ab ?ޥoFξׯL F_`"1Q87҇;jrD6'ⱺˮ© غ{}) I AYp,Vl>R'V `%H| 'b+)cx<+-X[?1NZO7 2^C판 iAj[ Z峲׾fD$_^4l_sZ"0 }҃ucGc/7 P;(W 6Ǘ|7b敧ٜwGЮ7ȃ `@>yply|ݤ$@$@$@$@$@$P09 J{L|G-I Vcr+^l;H't!/^mbk$w& |wix-{9 o={ 3E0t-+640(4anqm¶(yV&Ұo tZ[\ӅYHP`ø {㵃?&B ?Uρjy֏`eW&uԍ<[!]GPOLT,'A4h!*%JWha]뻁_     (epvu7=es㈰%[^+tjvy(,8_Cx-Nu0 #1hqIl~_s0?mCLb lz3\E(q} ̳k9{^U?. vqaη|/Hsv rLÙhMNan'oZ2gWw @{2>(?U]\/a@CJ}-l ekvcur^22 űm bN="ҤOė_N:8 *0aqq>WFo_C>܏-:A9ːD&H$++K&Wtf2+8!Y@ם:Bv:L>>A9ԇ@[SOD:}#D?U8R?.fl/ K@/#r#glM ]ĊPA`)Đ2EٍbXY7EZ/T>csԟ`@;{|E _(dm0wbu*~k* MkǂR2b[V_HF>^uVh3>Bw ڌAmnL\*$2' [,Cz*u(ݹ_D"~ vf+=Xe$@$@$@$@$@$@$@$ k3M_Ģ$c%0&eJr(^ $ӡװzV \^wy0A@$@$@$@$@$@$0Р<2@`\.L,>hd$| #ptbpHHHHHHHl4(ME VNFAU!zA1~;҅eQW)[f8$@$@$@$@$@$@$C85I b;)Nc45].2 5gb2#fXNt.|$A0 HHHHHHRV|&)4^?8T*,:Ǎ d oj"Ш]q IHHHHHHHu Рܺy˔ S @Ae #         hPv˓ @Ҳ)cH&4s.y#AOUj &HHHHHHHH @ ej= d%Ȭl]/vKFZ֤δ D.l{ \ӟ&tlh;jXԏƹU8idۍLoqo` F3 kSXUlwVcc+vӑ o,$O$@$@$@$@$@$@$@-E ڪTvxd3"NQJ-Moqp@> ~WN6.PꦪlF?12uA.g=dYǜ;tJ}\̍~ԷZ@G 0J#o VbU8y]rOgah>Ń{LF:` 2zpQz e;FY:|#<"       PXΙᑋ<)-L~$).H]۱jZ~b;sy䙙Dސȳ>Tn㔺XBd4og0v͕'yً8Ai q{=7LaE[0t-dzuV"? 0e0.Rr=0[mRV\~/sqNU<^ +8Ϡ >F=N8[+uGNcb C4i,`H z7b{0[8a2b_0FF)0[.<`ԯ8__y}Fj4= êq `+u¨;Kprڮ 7",ʛYKG`$-l0 Z #S[tq\*#[|a<v !W0\\3sS|#5CYyx^kPFϡMA udt$@$@$@$@$@$@$@$@%я=JWֶ[[a1ҵy=z0-dAh#61YuI_#OUlf6a%|c `l;R׍S0_%鏺uXdԦJӰxUȃ(\3.m(U# s Ec Gϝ>+^ _#lQw4P#]FysN].tz¨b/)`~EPd@_@( @ A& V( ]?UT܆-GѮūF&©%2?Օ Od/}0 ZUS>L\3DglF+A(Zs'+ ytx‘e=>hPGS'->,-ۊl >cP.+j6mvYD18#>^)1[q-e4[~ԅȠ[n̅h3QC z}Ifbœ+T+1 Lz"ɷ~0tZ{ւqi{)x| &?b r(* okWj 0cGM%C'       / y'X!A1UW̪߰`?>58v0Cc~JCaQ;MVyN. > {/:qcR[ lf|vmJW(;Bcs\uQE>*6xoDWmA1&OqNQ7G_H={$@$@$@$@$@$@$@$03RΤX{6SQB06El-oԏP=m?C89s%pȜv~+j2>`eS!9i97[եzk{s IHHHHHHHu Рܺy˔$" va%~\Jݘpa@$@$@$@$@$@$@$@Gy@Cao۸)X GzIG+ȿm9n<}9l x+Q'       Kɛחy>K$@$@$@$@$@$@$@$@$^y$@$@$@$@$@$@$@$@$@$@T @n4(FHHHHHHHHHH`rAyr3SI$@$@$@$@$@$@$@$@$@ Р!          A`H&SI$@$@$@$Jx#/\KH8= pRCg(Gǎ*@݆-OF$0L=#4((]?^)#J{/ K`}"< 7aNSjJ4T MU^z: C?p[3-LH 膾.pt=11:1?Ka2G^3: UHǛ5}|H '|x~ 'Sj7Z/!(pz0Rðn{_>@(wR71=c1'R Tꃎw`VKQ+OWE988*_(5oJAC0XANתE= n]\c I靤W|ZU`O2vǔ@꧒?9 E;t9a]o|{DU.RJ!P>8vVߨ|tݓ>L#Cb㧕h !rumQᅢv?eQ22 ua/e|]+(wٝV^bPFk;tu\c&_$T߇7 q4W9H}K 0fi}>MwڋL$ُ˲8&8o|4Wd(ڇ}G6=|:!,T!*usE[Ng@G!sx+:az\2eu?`%p[?Pj3^40NB LAA={s{ʳ"2`4aޓ-A9?*jT5nR686(_]գ0M'I~K,mЍ͍iefRߋ҇^$Şڤ9ip1Y [JWD=Bcߋ`Bk,M?K{T\^$B+or`v1:Jw#[&-J J)3mb ^&{ : MV lb< ڻ*LInL#ڋ\0yg 9h oG=yu3Y`kQ\1F> w76y7z.}qxy'a|5M(}0X%ߡ#X[[yoA])&v`/{9 T,n2ʟ~yhDL76Ộe/@zb2(c"VUZנ!dTP׃1B?MsڋψFr3b xy!]л`k+o-BOzh(H$0t3\HK@tlc!T1Ƶު}-Vt' Y]Z$j/nAI{(  y{}&6bеLfڵ θ=r8kN6a F! _:e=sabn@f9VMGﱰxbE}㦀O:ĖDϡW&D'[Sȣ'ǵГ 2Ax=6'胘Uce'텷NHH < la(X VB=+GߙG:\r0_*:4[RW鴣yLfbm,..K;xۭ֟Y87cE[2R{lx8{\_yr0٩=,eC;za{+6c$=mj(AZ[11wĄ&{g+tM(z[Lzz,\;i/ n]\ù<8ń9f_.+up&Гgv#: nWvxl|jw_|TGT |Q&30! ȔWqA׆Av;?/V+^5y\0:)q~^- _)&ӥeg0F0]q >N<0 O>1oDEqi ƿ<򈠝އ]1tB  0u#X=)~u[ʛ.9eANGQgGUԧo2"žrMga{զwBGR_kVA-[/q;P*1:Ւ>uWkz06K= z_Fʒt쪸^Hr#u_X9}lQ=|\1g~GL!G("*s욥ԓй ]Ajf];c_1z`TY)ԑPAF^w^g.-2\gЉ#Љfr|񩾻,a֌%iPv0J`ρ.oŅ_}}9i=YqquzU ˃nݝ<2>@V^Y]Q>B=z1hRjgdbtrЈmVIKK6xGs捍aG?0C"$/?`.ӨJgm+ x i"iOYQ9뇻w0/z>TŪU7p *+hCwd7 sƵu4sǯ z:3k"y/̘^ (,GsO"aݸv# XuX!S\#n0n#u:P6쐄9IWH/!:ih]nM uuF39hdPÌɚO;|Ǡ=ݍ8Wz8{lcZۘ_z!+$WCP|RR鴱"i2h|ӛ|އmP/S2-ieP-'E`Es5P@IDAT?s!_B. {V^cyi(=C߃w!e.LcZsvXiش<]dڌ~ >zAy't= 5&kAۯ18絞^_i3\eӟ?b|!?ިr'{_kHkpШ}~xGgzZoB'Ԙ=br&2N_q+o>t^aT]O]rPقcFLAPJ/kCp_5U} *`ӯvUij{1qzabE0:jvأ!$ ҿ> E:ma/'8y#0  !8q6:u[+\Pzy܊6oH|ʏJܾA/YdNӳH0f%,:egg/ [? [O:m -e҈utCU.3X]PC^ZhYje9LgΤ_ `TvW@]ˋ3 ݸIʶBڋ4gD9@듨C:ts$wKBGxem~e0{}D%U(a uz6K%I\*9AB>VB}/smd0iR+U!O.Rtw.K+x7ߍ{2$~+2uďODz[-R\ƛNs~EsW`m*ӱQL쵞ǘu16]VbyOl/?~/iU*@# }c>7C/^[Ջ1JฌoGo5}tBϜބA븖ItE +N?ŪWT˾5X][.~O{8ʨEpm1\B:ChC06ڊ!.}6c㜿> WdBF!lfW W>WS- +Gv9FBC|Oei/\aMӟ/c|&cky۝o8 +a|*cqY\xG&~76/8o(q+͇ci|/|A'(?g{:*C0<{?guFs49Y>+::{R.첒33]G '*\âkjXўct_E%5ޤ, $1w2aaT/~F'nX !|w~4,]/)u݈h J >/*Q6G^V@PoиiHK.PW8?ؕYEgp (}%MlY FJihM9z'0fWk0.7Nu!ˆ0׉^HmX#}C%\[!@yk{ FM etqjUG{W\ӆЅx8k%m n[|8g~eʫ"Oˬ>ɌP [.QկpKcV.た*R^z2mXG'va,"Zw'*:y{-ʺSn_(]ֱ&SJV=_4&ki6ѧ&aˮ;&;`d}}>Ho[eпw;KHplPW]O3;UMz`_r84`b!UU{`7t@W̚UW c tkR¿38t63BgfmY1B6~,ugbs5qS`HCUFyqgQO{#?ڌlxLga$;!jЫi~+țczux$;apj|CMnhB }w1Ø Hf7EM'ʖozI%~:L&j/mY~jZ!=/iu+(O] } fʀƿ]XPh3p%Wcnp+}hzl[1fBA_ 1} +=NPfs=U@D-b~oŁÅUm/W@v9M0c#|r~?ˤ#T.TR#t *vNNo&ۙ)'5ܯ+9M?4ck΅C;?E+ 2(⯽2E)~)srrux CYQɤJg:Q)(eC3O[a&e'$̗@2BE#> QDkJv)B0=ϧa+*]aq%v2H C]0C? !hqXV± 4LDnԯCGӦCg>INJ^[g֫2#$R˵왇a2&76fL7(_t+1irkAЖ6"twuSK\GNp?"S^IJ?745r+*Osr;q}w[@oG[}{xV01Xfk=vCx}}thK=|?fxW tif]q/gw"=FFoVA,TE r|Q9X|B}AyB\wZolȗ3Or.a2,l_\rn\VO{%ʡpD?A:E*aXS sbȃ|M?7w5F1ƷOW0P.g5)iի;*S(QR;/2/60,?0[ ,|*q#]7+PjPOHu>'% XUS}سQنEǥ-0<9_jDj/n2OB[5 әQ`TL.$f.pzZs7&z+ ޠz%$0~xHNWXQWVyt>O[]_g0 7 >* WRUm! Ҙ\ 㗭0&.=sƒpxk>'lHTu[wHхnjjxА@v9M(ZBN<8"xx'NoT )NBL y5Mˡ wڐEjt< 鏸׹̾9jGWq`Pnj.0C6FWː'mS6/YwlbE|-yȧ6T09 K(kLFcD6;]"*}^T}ϓʴ<DZ#1`>V!G*(5oЙZCGo_!tjPFu}2ISLZ]`%_@J(}sxe5'ჂX|VΰN/90( &t)ղc(x}5ȭ{UJ&ӉAev{W[8CtUHAy9y~rQWni0"<}FQ*"XMGt!>w"~cD2%E{\ܛ4WdF(a}C~Y!xEMC[loD_gCZ~tXñm ~bh'<+Gb\. ɠ NIui3(Nl5>=9%f"]C)z^qӓx¾q` qΨPEߨ/ü=!kcO@5{SZ!a|PWhwKJ͆1!lӓko  Ps3Ŭ&ԫ2ܼ1*1QоK ,VmRLNI':y]= [S17glq][F ܤu"!d{9]mWdD-%I#Oi#dy~En`W"GzDTs}Y:nmb ‰m[0g1)oD s]` 7sfϮ_6Hْ@^ 4+.sȘ8Q^]o5e?!Nua/-@yOWv&fih>w[Ȭ.qYkzkD(Sw`|FuxJ~M4yP4ˀf 8iu`>3c֬͠@R b̤Oh|P A͔K3yndcg{1;Zsu_mW& ˡ^~#A+޴.#pXmvqFA= eoLdhCT[Z[tH.'wW $uF͡an%f9OךoKڻaaHT3-9[>B//dq^ì&p͝jgk7pp.Ÿl:z!!d.Pt{Ԥ+¿ˮmڕp^.rȢ E`D hHݨWsR/.XEIIv:O_co~8i̚pC7z+jC tn.FKoŽF `P/W =^=(KjWi܇UKҦij@|ztԊNWEpENm]4a@=ytn|HC!:qo6ҫMqӅtwIP-s!ӂsqA =,_hڃNZKqI1ٶ2\FZ)_ <3PG8f[ECcuʻા7s˶_(PsY<}ЇRG^H#竲LhEoLD)Ihv]"{!7˵a;W3I!=+N[!}>Cn5g4G.;FVtsoF "_cܱ&UpOP+ sD+{.a`>=~s`Dq}[}KP|qV{֟aPVj8W:V7륎";dWQ #=(z {Y܏R]=;V@ofdBMhs!*(d}Q'Aer+8]=LD%V7A7Y[N waTsR A3n _Bَҿ&̿h~$ (Z|=zRKrfy zG5V5E:~ಾ7s_S9j>–?ܞhQ8j^ KQQi@0LrB_/@gK -w=9F/^M^"|˄2˖Vp#S{QB*)^ЫX~t]{<ڀz^xԇڃcW֠B\. K76Zzp Ҹ:p.a@rygw+P퓞jjl+o69GHj:rU}] VeM Tg?1  61KAOw[J6:fVU&g!Vsӑ\,¯vK~i:рaȼaU]#Ko!ĈWd6|܎AlT7 0eZ6pD/rtG3OԩHΫ ,8FVOR]#/F'S}7PW#ժ&35'z5<^mv+{Ѕ2)2lkPk:b IzS uhQ%8} vbg\瓘hCkC:Mq]3kPOA΂ӫt )QpZIC3 9g ~^3k~CvǽP27b'a\ZBqU}o:Vl8Wr~BR ?WnKofK*C\-л^M~|0-&8-=N_׀tP_SwЉI G06+80B? 6"X;Qn5:9 ;ziڲ,-0wa(~}Pr XлO(b2~{,~I,:$E:}cxPtzFԽ¡_yF4!\yVC1slGa#zCuUE9nv #~Ŕy,o.wI|7aU~sJ@:'z'4Vfg7r36 YDw+۱?*V,OՕՏбz* Y@uȧcE~tG{!t6SQ5,u>~U))]E^)EWQtmB];@.<=J9į6$?:%@XWgꚉ묪A7wP{z|yNUV#G:W?ַ [ ^lqUXB껫bM˅_emG =c>eOᬪN}ߟWZMxt?im]~Iz|[ PGAm/|k].+}C^Ƙk4͡>gct_u3Mi]CO|28crh vtokb ɡIq0vi] Pfz^)1(ϸ;C&4JgK$@$0NUjk~Z( N/ k^&(IHU^mtJHXyR9~S z_̗'RfDIH ]nL-8I 31avh[X>wWKЛgP.Ժ& #& GL|ϕ. Hd%gt$@$@$@$@$@$К~ DIeR=N4Q _׻PAyƾgxH Ju gT ;$@$Ez# |5RDظAcǁxB$J_'n}ʈI'+]qw70I꣣1W( L8~졜ܬ=S`  &J-3o|M 'I#     r=Z-`zu'(5\^U}\>;<]ed/ !pzC@HHHHHHZ@rr+/P+u`_!         㒇okerFƒ*u ^>^_OԖ4+J]5ph_{I㺰/2nǮ zg@8ir$O(9]OMj%dݍ|Z_7+dOVb!Q<3_3Pv# sD^]P@D:rUwmR ~YFG[FIsg9A\z)~F9eHD}a.PL\[\z,S!+%s_FtA      V&G°Tt۱ByQw'kc,a5CɂSxD@1KY^"&IpB% )TCg(1(Zc?X[ZH$,d$a~s;۷{t?==>p"vX9uz[u׈s)DZi^O3zQ>W>D/a2Z8WG`3 {k|ED Dž1Dklcz`1zqG(P`{\<\;#ilySmùK)J'\9粁:8#6.>r8/h8w3#%Ր溅9Nw>.HhiUno..y.^ĦH;||/;p νM}'/~;NOŞi,% 1[OrIOVW^{la~l=N)n2.*&sI/t|}as91ܹйp &o]H}[daA?]#S.Rf 3 +k)^;+&ܾvVGIljސ.EmNٞh5o7h*D‹ Է{c'&7hOѥroo@$>[m3o&g #N\# i)" " " " " "0d"'J6ģQ!$و= <g>+Ñ xqr M1a}0bIzxՆ`[eOQ n u[F$/Zmmp:a:wGxvdZ~n1k;8)Z>qVҴakRh$ȓ;Qwŗb<Ӱ'\$~,rub{#z~|M#%> #P?ْ8opf!HJ9xa 0;lxVsƽvsX\iyJ! #\p lM.{Ivx%Nఴ왼bk"vd^cNKaTx>d#G 3"<0F pusYyG(/|#_8uED֐TP6.PH,sZ`j?"?UatsմsQnM Hgim#ZѾ|>FMgy3WL˞M(x7zͲa)I=>4`W# 30P½?VVQ:FD@D@D@D@D@D`Ԃ6D"8.'j FZMdsbXt3D6,F ^ Co!4=qb]8lsb?Xts X so"1r>my}yhNxGCe$TF"'ϗ'ޖ5/"{93enAbƭh+]O>\u%8/z~_/4?KS]\e۳F+NmPc+Q]MWXk=U { Qn_j>mbpsKӞ4x+.6->7ї^8," " " " " " -w,:XIֽkD=}NZ? >.W^jCKp\qOF@ZҴ$:#^\ۃE>_>0f#Ϙu/XO+UZo=p#]Ք*xm'=ic fNYtj|l4oXxwyۃ." " " " " "0 (gS!.Ef/u_m(5䟍?iAXsdw\=ӦR=Ip>i"eDY0DNI-<я9rdHmÑh;Y>%Ө'` Ȟz7~$W۪1:֟fz}0VSr2Ͳg4o4E .5Wg?ʲ)|7Gvd@W0i8.A^ ȑjlWXp tk9Gts*\Q{¥S[".#"O:tD|ѡ갠y aQa=uc̛iIߘr2@D@D@D@D@D@D ruS+هȶׯ+_" C4-k#(%S m#^g,S'&igDBFR-= 5}G c^:0ZfQzXt7g[j9.*˨B# o#k2|#'Yk_ٞ.ij4*^&CE@D@D@D@D@D@@xSanyB k yĭcq>U_Wk=!u1PdwX7c7)D؃iVçwQqb?x*,/p^)]mbZ˜MA4b~gm6!fJae4S&l2i|Ǽ%LClMbQxxlBks==och6̍Pi} ZļZ\>\qx+7ea|+({/;ŹZl)LPg` ox ׃!oԥ+W^e^0`dl2vLnMbIbɄ>%M>icdRVphBPMHOh[)= $/u;׹j2cD@D@D@D@D@D@3x墜P m= fEYm5݋+ V&AmMӑg,&4$."(G4%#X\'pCN#Ti\#|C 䳱M#|䭀nO>TʊrAy͈sʕlO-}[HOzfGFN9ĕ~ۦ;';}iiV||~2[[F[Pvo"XoL,wq0?׷ w죥E˾q=IJtw.q+X#X= &sOg#|k q )J0֙0!Bdڽ0l嗤v6s^X\!~UXٸȹkl {_Fmu_綅|Ft-;J}L/jm#>e͋1^;Yk_sL#_7M1ΊwF?{G!p xn6OZrm|J|7y "^3@IDAT " " " " " qcp]7ޔwsO0b.Ddq.hBW (2Bx]Xi_f߆LbiJcyk;^]^w$>j8gt6paaΑ'c>08oxuM&*FDP/ NSzYfƦ.*dnZ9דik}Khct6C1V״a5侃Gp_iwP2s4я ;ES_,f}~O=B\0}}>&yA=y`pw$/L=p{/MHOZ1M" " " " " " "DJId</"A`كq["q/6 rҲ'!<{y&Kg9QE4bgxіJvd,+aI_-w3m+M#έ*7cL95]4a4 s!<ƵFP>ʠ`iYk_ОGPMcut9wRH>IbX|Hc+}`6X5^&W%w1uEnqA)I093]ժ/l"҅¶]kY 0߽ Q ~bpD Ǎp?}q4 i$ϋaq 1|6!&5+κ֓c`򶯝7ǤxT~Qcqy}\gx,n 6YC -^K4ps2 3K}qebY?Ri4@ oZ YљLts'S'0~t<P9G5nQ/:oA(C/" " " " " SD@rgn^9=NSX-& ӌ@ʽe|IP4fWmYon.gBZ=ͭJ]D@D@D@D@D@*\P:u.0 dE<Ms^)>͇6Ers.ܐb^b^kZ[8~QkRM=9Ν<j3*ۻ/0?MWXҵjk_u:Q cpRg`|/^|s]01k~ch x]>}njmS=]RD@D@D@D@D`JOU=q ""@YK'ؕrb箏̙\)qP7(L} ν}s_s#B?d~A[NsnG8:΋{:׹ cѝ4Fuc% ۩#jczZ從sCNOR&dQ.C G+Խ[ߎ;rv꧸( b6lSO(}_?үCBy5ҏezhDQ6WSj}nfdD3C1xK4Rv/~M#'KWʅwL1P7^˹/q/\\hqRE#K˞F볽xv`_?;V){EByc* <:w\<) YKLtRHT8" 8ӹ;5]lMQXvK݈8yyxx_c/i \2\o{s>{onǛi;q~Iu,m\N Q$i Z5,%R'SvmdG- gY:#,m}^AΙi%sr?p£n!t7нF|6]qZq% X5,][u q}u! +ԟh@BfRh&uP ؓK:}Oq/J=|8jba{Rd(n?i+:R" " " " " "Pc~r"Cz e?$ÃktX_G!d|^O+k[Y,{ZNGafݗ^eMgsij!\m!s> c $Q1fu%"x@ߋGܼPxā๾ED+ʽZjem!{_f*AVB-< .7ZA~Vbs44w8"'~rH;L+N}bz{{/c)|tnqi(w# ½al@z7nJEQ{ҮϾzQy=O(4C7fi#" " " " " 5*bu P9];w!\@2Ƀ5ky'a2NļT7{-b4{TL/w=b엇I#8aigN ?Ɠ+8e} aYz}8g-Q2*D7tϫ>#\~䵏2ʭm>GVc&,%7b1۲{%%$4cPu=<~ VL2j5))+ 0v?]àOM`" a\>cq{jIgqy/'>49G#" " " " " e X%;X`sA>S;9{Wԗ8q!k٘<aoeC# ox|'ݣF(؉@~^a}z Z@ Z4XI :i" ޽j ûq&SXFϝ5Rp\6R[{-Ǿ h3k7 _}-Nmr_5 MϼuWCOt E@D@D@D@D@D_P.O8w%`?r$2V)d0[+߫ ?qRx :

{% trans %}News{% endtrans %}

") except ValueError: error("index.html format not as expected") lines.insert(news + 2, # There is a

after the news line. Put it # after that. r""" {{ datetime(""" + release_year + """, """ + release_month + """, """ + release_day + """) }} {% trans v='""" + version + """' %}Version {{ v }} released{% endtrans %} ({% trans %}changes{% endtrans %})

""") with open(os.path.join(website_location, "templates", "index.html"), 'w') as f: print("Updating index.html template") f.write('\n'.join(lines)) print("Generating website pages") local("cd {website_location} && ./generate".format(website_location=website_location)) print("Committing") local("cd {website_location} && git commit -a -m \'Add {version} to the news\'".format(website_location=website_location, version=version)) print("Pushing") local("cd {website_location} && git push origin".format(website_location=website_location)) # ------------------------------------------------ # Uploading @task def upload(): """ Upload the files everywhere (PyPI and GitHub) """ distutils_check() GitHub_release() pypi_register() pypi_upload() test_pypi(2) test_pypi(3) @task def distutils_check(): """ Runs setup.py check """ with cd("/home/vagrant/repos/sympy"): run("python setup.py check") run("python3 setup.py check") @task def pypi_register(): """ Register a release with PyPI This should only be done for the final release. You need PyPI authentication to do this. """ with cd("/home/vagrant/repos/sympy"): run("python setup.py register") @task def pypi_upload(): """ Upload files to PyPI. You will need to enter a password. """ with cd("/home/vagrant/repos/sympy"): run("twine upload dist/*.tar.gz") run("twine upload dist/*.exe") @task def test_pypi(release='2'): """ Test that the sympy can be pip installed, and that sympy imports in the install. """ # This function is similar to test_tarball() version = get_sympy_version() release = str(release) if release not in {'2', '3'}: # TODO: Add win32 raise ValueError("release must be one of '2', '3', not %s" % release) venv = "/home/vagrant/repos/test-{release}-pip-virtualenv".format(release=release) with use_venv(release): make_virtualenv(venv) with virtualenv(venv): run("pip install sympy") run('python -c "import sympy; assert sympy.__version__ == \'{version}\'"'.format(version=version)) @task def GitHub_release_text(): """ Generate text to put in the GitHub release Markdown box """ shortversion = get_sympy_short_version() htmltable = table() out = """\ See https://github.com/sympy/sympy/wiki/release-notes-for-{shortversion} for the release notes. {htmltable} **Note**: Do not download the **Source code (zip)** or the **Source code (tar.gz)** files below. """ out = out.format(shortversion=shortversion, htmltable=htmltable) print(blue("Here are the release notes to copy into the GitHub release " "Markdown form:", bold=True)) print() print(out) return out @task def GitHub_release(username=None, user='sympy', token=None, token_file_path="~/.sympy/release-token", repo='sympy', draft=False): """ Upload the release files to GitHub. The tag must be pushed up first. You can test on another repo by changing user and repo. """ if not requests: error("requests and requests-oauthlib must be installed to upload to GitHub") release_text = GitHub_release_text() version = get_sympy_version() short_version = get_sympy_short_version() tag = 'sympy-' + version prerelease = short_version != version urls = URLs(user=user, repo=repo) if not username: username = raw_input("GitHub username: ") token = load_token_file(token_file_path) if not token: username, password, token = GitHub_authenticate(urls, username, token) # If the tag in question is not pushed up yet, then GitHub will just # create it off of master automatically, which is not what we want. We # could make it create it off the release branch, but even then, we would # not be sure that the correct commit is tagged. So we require that the # tag exist first. if not check_tag_exists(): error("The tag for this version has not been pushed yet. Cannot upload the release.") # See https://developer.github.com/v3/repos/releases/#create-a-release # First, create the release post = {} post['tag_name'] = tag post['name'] = "SymPy " + version post['body'] = release_text post['draft'] = draft post['prerelease'] = prerelease print("Creating release for tag", tag, end=' ') result = query_GitHub(urls.releases_url, username, password=None, token=token, data=json.dumps(post)).json() release_id = result['id'] print(green("Done")) # Then, upload all the files to it. for key in descriptions: tarball = get_tarball_name(key) params = {} params['name'] = tarball if tarball.endswith('gz'): headers = {'Content-Type':'application/gzip'} elif tarball.endswith('pdf'): headers = {'Content-Type':'application/pdf'} elif tarball.endswith('zip'): headers = {'Content-Type':'application/zip'} else: headers = {'Content-Type':'application/octet-stream'} print("Uploading", tarball, end=' ') sys.stdout.flush() with open(os.path.join("release", tarball), 'rb') as f: result = query_GitHub(urls.release_uploads_url % release_id, username, password=None, token=token, data=f, params=params, headers=headers).json() print(green("Done")) # TODO: download the files and check that they have the right md5 sum def GitHub_check_authentication(urls, username, password, token): """ Checks that username & password is valid. """ query_GitHub(urls.api_url, username, password, token) def GitHub_authenticate(urls, username, token=None): _login_message = """\ Enter your GitHub username & password or press ^C to quit. The password will be kept as a Python variable as long as this script is running and https to authenticate with GitHub, otherwise not saved anywhere else:\ """ if username: print("> Authenticating as %s" % username) else: print(_login_message) username = raw_input("Username: ") authenticated = False if token: print("> Authenticating using token") try: GitHub_check_authentication(urls, username, None, token) except AuthenticationFailed: print("> Authentication failed") else: print("> OK") password = None authenticated = True while not authenticated: password = getpass("Password: ") try: print("> Checking username and password ...") GitHub_check_authentication(urls, username, password, None) except AuthenticationFailed: print("> Authentication failed") else: print("> OK.") authenticated = True if password: generate = raw_input("> Generate API token? [Y/n] ") if generate.lower() in ["y", "ye", "yes", ""]: name = raw_input("> Name of token on GitHub? [SymPy Release] ") if name == "": name = "SymPy Release" token = generate_token(urls, username, password, name=name) print("Your token is", token) print("Use this token from now on as GitHub_release:token=" + token + ",username=" + username) print(red("DO NOT share this token with anyone")) save = raw_input("Do you want to save this token to a file [yes]? ") if save.lower().strip() in ['y', 'yes', 'ye', '']: save_token_file(token) return username, password, token def generate_token(urls, username, password, OTP=None, name="SymPy Release"): enc_data = json.dumps( { "scopes": ["public_repo"], "note": name } ) url = urls.authorize_url rep = query_GitHub(url, username=username, password=password, data=enc_data).json() return rep["token"] def save_token_file(token): token_file = raw_input("> Enter token file location [~/.sympy/release-token] ") token_file = token_file or "~/.sympy/release-token" token_file_expand = os.path.expanduser(token_file) token_file_expand = os.path.abspath(token_file_expand) token_folder, _ = os.path.split(token_file_expand) try: if not os.path.isdir(token_folder): os.mkdir(token_folder, 0o700) with open(token_file_expand, 'w') as f: f.write(token + '\n') os.chmod(token_file_expand, stat.S_IREAD | stat.S_IWRITE) except OSError as e: print("> Unable to create folder for token file: ", e) return except IOError as e: print("> Unable to save token file: ", e) return return token_file def load_token_file(path="~/.sympy/release-token"): print("> Using token file %s" % path) path = os.path.expanduser(path) path = os.path.abspath(path) if os.path.isfile(path): try: with open(path) as f: token = f.readline() except IOError: print("> Unable to read token file") return else: print("> Token file does not exist") return return token.strip() class URLs(object): """ This class contains URLs and templates which used in requests to GitHub API """ def __init__(self, user="sympy", repo="sympy", api_url="https://api.github.com", authorize_url="https://api.github.com/authorizations", uploads_url='https://uploads.github.com', main_url='https://github.com'): """Generates all URLs and templates""" self.user = user self.repo = repo self.api_url = api_url self.authorize_url = authorize_url self.uploads_url = uploads_url self.main_url = main_url self.pull_list_url = api_url + "/repos" + "/" + user + "/" + repo + "/pulls" self.issue_list_url = api_url + "/repos/" + user + "/" + repo + "/issues" self.releases_url = api_url + "/repos/" + user + "/" + repo + "/releases" self.single_issue_template = self.issue_list_url + "/%d" self.single_pull_template = self.pull_list_url + "/%d" self.user_info_template = api_url + "/users/%s" self.user_repos_template = api_url + "/users/%s/repos" self.issue_comment_template = (api_url + "/repos" + "/" + user + "/" + repo + "/issues/%d" + "/comments") self.release_uploads_url = (uploads_url + "/repos/" + user + "/" + repo + "/releases/%d" + "/assets") self.release_download_url = (main_url + "/" + user + "/" + repo + "/releases/download/%s/%s") class AuthenticationFailed(Exception): pass def query_GitHub(url, username=None, password=None, token=None, data=None, OTP=None, headers=None, params=None, files=None): """ Query GitHub API. In case of a multipage result, DOES NOT query the next page. """ headers = headers or {} if OTP: headers['X-GitHub-OTP'] = OTP if token: auth = OAuth2(client_id=username, token=dict(access_token=token, token_type='bearer')) else: auth = HTTPBasicAuth(username, password) if data: r = requests.post(url, auth=auth, data=data, headers=headers, params=params, files=files) else: r = requests.get(url, auth=auth, headers=headers, params=params, stream=True) if r.status_code == 401: two_factor = r.headers.get('X-GitHub-OTP') if two_factor: print("A two-factor authentication code is required:", two_factor.split(';')[1].strip()) OTP = raw_input("Authentication code: ") return query_GitHub(url, username=username, password=password, token=token, data=data, OTP=OTP) raise AuthenticationFailed("invalid username or password") r.raise_for_status() return r # ------------------------------------------------ # Vagrant related configuration @task def vagrant(): """ Run commands using vagrant """ vc = get_vagrant_config() # change from the default user to 'vagrant' env.user = vc['User'] # connect to the port-forwarded ssh env.hosts = ['%s:%s' % (vc['HostName'], vc['Port'])] # use vagrant ssh key env.key_filename = vc['IdentityFile'].strip('"') # Forward the agent if specified: env.forward_agent = vc.get('ForwardAgent', 'no') == 'yes' def get_vagrant_config(): """ Parses vagrant configuration and returns it as dict of ssh parameters and their values """ result = local('vagrant ssh-config', capture=True) conf = {} for line in iter(result.splitlines()): parts = line.split() conf[parts[0]] = ' '.join(parts[1:]) return conf @task def restart_network(): """ Do this if the VM won't connect to the internet. """ run("sudo /etc/init.d/networking restart") # --------------------------------------- # Just a simple testing command: @task def uname(): """ Get the uname in Vagrant. Useful for testing that Vagrant works. """ run('uname -a') sympy-sympy-1.9/release/github_release.py000077500000000000000000000412551412543434000207110ustar00rootroot00000000000000#!/usr/bin/env python import os import json from subprocess import check_output from collections import OrderedDict, defaultdict from collections.abc import Mapping import glob from contextlib import contextmanager import requests from requests_oauthlib import OAuth2 def main(version, push=None): """ WARNING: If push is given as --push then this will push the release to github. """ push = push == '--push' _GitHub_release(version, push) def error(msg): raise ValueError(msg) def blue(text): return "\033[34m%s\033[0m" % text def red(text): return "\033[31m%s\033[0m" % text def green(text): return "\033[32m%s\033[0m" % text def _GitHub_release(version, push, username=None, user='sympy', token=None, token_file_path="~/.sympy/release-token", repo='sympy', draft=False): """ Upload the release files to GitHub. The tag must be pushed up first. You can test on another repo by changing user and repo. """ if not requests: error("requests and requests-oauthlib must be installed to upload to GitHub") release_text = GitHub_release_text(version) short_version = get_sympy_short_version(version) tag = 'sympy-' + version prerelease = short_version != version urls = URLs(user=user, repo=repo) if not username: username = input("GitHub username: ") token = load_token_file(token_file_path) if not token: username, password, token = GitHub_authenticate(urls, username, token) # If the tag in question is not pushed up yet, then GitHub will just # create it off of master automatically, which is not what we want. We # could make it create it off the release branch, but even then, we would # not be sure that the correct commit is tagged. So we require that the # tag exist first. if not check_tag_exists(version): sys.exit(red("The tag for this version has not been pushed yet. Cannot upload the release.")) # See https://developer.github.com/v3/repos/releases/#create-a-release # First, create the release post = {} post['tag_name'] = tag post['name'] = "SymPy " + version post['body'] = release_text post['draft'] = draft post['prerelease'] = prerelease print("Creating release for tag", tag, end=' ') if push: result = query_GitHub(urls.releases_url, username, password=None, token=token, data=json.dumps(post)).json() release_id = result['id'] else: print(green("Not pushing!")) print(green("Done")) # Then, upload all the files to it. for key in descriptions: tarball = get_tarball_name(key, version) params = {} params['name'] = tarball if tarball.endswith('gz'): headers = {'Content-Type':'application/gzip'} elif tarball.endswith('pdf'): headers = {'Content-Type':'application/pdf'} elif tarball.endswith('zip'): headers = {'Content-Type':'application/zip'} else: headers = {'Content-Type':'application/octet-stream'} print("Uploading", tarball, end=' ') sys.stdout.flush() with open(os.path.join('release/release-' + version, tarball), 'rb') as f: if push: result = query_GitHub(urls.release_uploads_url % release_id, username, password=None, token=token, data=f, params=params, headers=headers).json() else: print(green("Not uploading!")) print(green("Done")) # TODO: download the files and check that they have the right sha256 sum def GitHub_release_text(version): """ Generate text to put in the GitHub release Markdown box """ shortversion = get_sympy_short_version(version) htmltable = table(version) out = """\ See https://github.com/sympy/sympy/wiki/release-notes-for-{shortversion} for the release notes. {htmltable} **Note**: Do not download the **Source code (zip)** or the **Source code (tar.gz)** files below. """ out = out.format(shortversion=shortversion, htmltable=htmltable) print(blue("Here are the release notes to copy into the GitHub release " "Markdown form:")) print() print(out) return out def get_sympy_short_version(version): """ Get the short version of SymPy being released, not including any rc tags (like 0.7.3) """ parts = version.split('.') # Remove rc tags # Handle both 1.0.rc1 and 1.1rc1 if not parts[-1].isdigit(): if parts[-1][0].isdigit(): parts[-1] = parts[-1][0] else: parts.pop(-1) return '.'.join(parts) class URLs(object): """ This class contains URLs and templates which used in requests to GitHub API """ def __init__(self, user="sympy", repo="sympy", api_url="https://api.github.com", authorize_url="https://api.github.com/authorizations", uploads_url='https://uploads.github.com', main_url='https://github.com'): """Generates all URLs and templates""" self.user = user self.repo = repo self.api_url = api_url self.authorize_url = authorize_url self.uploads_url = uploads_url self.main_url = main_url self.pull_list_url = api_url + "/repos" + "/" + user + "/" + repo + "/pulls" self.issue_list_url = api_url + "/repos/" + user + "/" + repo + "/issues" self.releases_url = api_url + "/repos/" + user + "/" + repo + "/releases" self.single_issue_template = self.issue_list_url + "/%d" self.single_pull_template = self.pull_list_url + "/%d" self.user_info_template = api_url + "/users/%s" self.user_repos_template = api_url + "/users/%s/repos" self.issue_comment_template = (api_url + "/repos" + "/" + user + "/" + repo + "/issues/%d" + "/comments") self.release_uploads_url = (uploads_url + "/repos/" + user + "/" + repo + "/releases/%d" + "/assets") self.release_download_url = (main_url + "/" + user + "/" + repo + "/releases/download/%s/%s") def load_token_file(path="~/.sympy/release-token"): print("> Using token file %s" % path) path = os.path.expanduser(path) path = os.path.abspath(path) if os.path.isfile(path): try: with open(path) as f: token = f.readline() except IOError: print("> Unable to read token file") return else: print("> Token file does not exist") return return token.strip() def GitHub_authenticate(urls, username, token=None): _login_message = """\ Enter your GitHub username & password or press ^C to quit. The password will be kept as a Python variable as long as this script is running and https to authenticate with GitHub, otherwise not saved anywhere else:\ """ if username: print("> Authenticating as %s" % username) else: print(_login_message) username = input("Username: ") authenticated = False if token: print("> Authenticating using token") try: GitHub_check_authentication(urls, username, None, token) except AuthenticationFailed: print("> Authentication failed") else: print("> OK") password = None authenticated = True while not authenticated: password = getpass("Password: ") try: print("> Checking username and password ...") GitHub_check_authentication(urls, username, password, None) except AuthenticationFailed: print("> Authentication failed") else: print("> OK.") authenticated = True if password: generate = input("> Generate API token? [Y/n] ") if generate.lower() in ["y", "ye", "yes", ""]: name = input("> Name of token on GitHub? [SymPy Release] ") if name == "": name = "SymPy Release" token = generate_token(urls, username, password, name=name) print("Your token is", token) print("Use this token from now on as GitHub_release:token=" + token + ",username=" + username) print(red("DO NOT share this token with anyone")) save = input("Do you want to save this token to a file [yes]? ") if save.lower().strip() in ['y', 'yes', 'ye', '']: save_token_file(token) return username, password, token def run(*cmdline, cwd=None): """ Run command in subprocess and get lines of output """ return check_output(cmdline, encoding='utf-8', cwd=cwd).splitlines() def check_tag_exists(version): """ Check if the tag for this release has been uploaded yet. """ tag = 'sympy-' + version all_tag_lines = run('git', 'ls-remote', '--tags', 'origin') return any(tag in tag_line for tag_line in all_tag_lines) def generate_token(urls, username, password, OTP=None, name="SymPy Release"): enc_data = json.dumps( { "scopes": ["public_repo"], "note": name } ) url = urls.authorize_url rep = query_GitHub(url, username=username, password=password, data=enc_data).json() return rep["token"] def GitHub_check_authentication(urls, username, password, token): """ Checks that username & password is valid. """ query_GitHub(urls.api_url, username, password, token) class AuthenticationFailed(Exception): pass def query_GitHub(url, username=None, password=None, token=None, data=None, OTP=None, headers=None, params=None, files=None): """ Query GitHub API. In case of a multipage result, DOES NOT query the next page. """ headers = headers or {} if OTP: headers['X-GitHub-OTP'] = OTP if token: auth = OAuth2(client_id=username, token=dict(access_token=token, token_type='bearer')) else: auth = HTTPBasicAuth(username, password) if data: r = requests.post(url, auth=auth, data=data, headers=headers, params=params, files=files) else: r = requests.get(url, auth=auth, headers=headers, params=params, stream=True) if r.status_code == 401: two_factor = r.headers.get('X-GitHub-OTP') if two_factor: print("A two-factor authentication code is required:", two_factor.split(';')[1].strip()) OTP = input("Authentication code: ") return query_GitHub(url, username=username, password=password, token=token, data=data, OTP=OTP) raise AuthenticationFailed("invalid username or password") r.raise_for_status() return r def save_token_file(token): token_file = input("> Enter token file location [~/.sympy/release-token] ") token_file = token_file or "~/.sympy/release-token" token_file_expand = os.path.expanduser(token_file) token_file_expand = os.path.abspath(token_file_expand) token_folder, _ = os.path.split(token_file_expand) try: if not os.path.isdir(token_folder): os.mkdir(token_folder, 0o700) with open(token_file_expand, 'w') as f: f.write(token + '\n') os.chmod(token_file_expand, stat.S_IREAD | stat.S_IWRITE) except OSError as e: print("> Unable to create folder for token file: ", e) return except IOError as e: print("> Unable to save token file: ", e) return return token_file def table(version): """ Make an html table of the downloads. This is for pasting into the GitHub releases page. See GitHub_release(). """ tarball_formatter_dict = dict(_tarball_format(version)) shortversion = get_sympy_short_version(version) tarball_formatter_dict['version'] = shortversion sha256s = [i.split('\t') for i in _sha256(version, print_=False, local=True).split('\n')] sha256s_dict = {name: sha256 for sha256, name in sha256s} sizes = [i.split('\t') for i in _size(version, print_=False).split('\n')] sizes_dict = {name: size for size, name in sizes} table = [] # https://docs.python.org/2/library/contextlib.html#contextlib.contextmanager. Not # recommended as a real way to generate html, but it works better than # anything else I've tried. @contextmanager def tag(name): table.append("<%s>" % name) yield table.append("" % name) @contextmanager def a_href(link): table.append("" % link) yield table.append("") with tag('table'): with tag('tr'): for headname in ["Filename", "Description", "size", "sha256"]: with tag("th"): table.append(headname) for key in descriptions: name = get_tarball_name(key, version) with tag('tr'): with tag('td'): with a_href('https://github.com/sympy/sympy/releases/download/sympy-%s/%s' % (version, name)): with tag('b'): table.append(name) with tag('td'): table.append(descriptions[key].format(**tarball_formatter_dict)) with tag('td'): table.append(sizes_dict[name]) with tag('td'): table.append(sha256s_dict[name]) out = ' '.join(table) return out descriptions = OrderedDict([ ('source', "The SymPy source installer.",), ('wheel', "A wheel of the package.",), ('html', '''Html documentation. This is the same as the online documentation.''',), ('pdf', '''Pdf version of the html documentation.''',), ]) def _size(version, print_=True): """ Print the sizes of the release files. Run locally. """ out = run(*(['du', '-h'] + release_files(version))) out = [i.split() for i in out] out = '\n'.join(["%s\t%s" % (i, os.path.split(j)[1]) for i, j in out]) if print_: print(out) return out def _sha256(version, print_=True, local=False): if local: out = run(*(['shasum', '-a', '256'] + release_files(version))) else: raise ValueError('Should not get here...') # out = run(*(['shasum', '-a', '256', '/root/release/*'])) # Remove the release/ part for printing. Useful for copy-pasting into the # release notes. out = [i.split() for i in out] out = '\n'.join(["%s\t%s" % (i, os.path.split(j)[1]) for i, j in out]) if print_: print(out) return out def get_tarball_name(file, version): """ Get the name of a tarball file should be one of source-orig: The original name of the source tarball source-orig-notar: The name of the untarred directory source: The source tarball (after renaming) wheel: The wheel html: The name of the html zip html-nozip: The name of the html, without ".zip" pdf-orig: The original name of the pdf file pdf: The name of the pdf file (after renaming) """ doctypename = defaultdict(str, {'html': 'zip', 'pdf': 'pdf'}) if file in {'source-orig', 'source'}: name = 'sympy-{version}.tar.gz' elif file == 'source-orig-notar': name = "sympy-{version}" elif file in {'html', 'pdf', 'html-nozip'}: name = "sympy-docs-{type}-{version}" if file == 'html-nozip': # zip files keep the name of the original zipped directory. See # https://github.com/sympy/sympy/issues/7087. file = 'html' else: name += ".{extension}" elif file == 'pdf-orig': name = "sympy-{version}.pdf" elif file == 'wheel': name = 'sympy-{version}-py3-none-any.whl' else: raise ValueError(file + " is not a recognized argument") ret = name.format(version=version, type=file, extension=doctypename[file]) return ret def release_files(version): """ Returns the list of local release files """ paths = glob.glob('release/release-' + version + '/*') if not paths: raise ValueError("No release files found") return paths tarball_name_types = { 'source-orig', 'source-orig-notar', 'source', 'wheel', 'html', 'html-nozip', 'pdf-orig', 'pdf', } # Have to make this lazy so that version can be defined. class _tarball_format(Mapping): def __init__(self, version): self.version = version def __getitem__(self, name): return get_tarball_name(name, self.version) def __iter__(self): return iter(tarball_name_types) def __len__(self): return len(tarball_name_types) if __name__ == "__main__": import sys main(*sys.argv[1:]) sympy-sympy-1.9/release/helpers.py000066400000000000000000000003521412543434000173570ustar00rootroot00000000000000#!/usr/bin/env python from subprocess import check_call def run(*cmdline, cwd=None, env=None): """ Run command in subprocess and get lines of output """ return check_call(cmdline, encoding='utf-8', cwd=cwd, env=env) sympy-sympy-1.9/release/pull_and_run_rever.sh000077500000000000000000000005651412543434000215750ustar00rootroot00000000000000#!/bin/bash # This is a separate script from rever so that it can pull any updates to the # rever file. The first argument should be the branch name, and the second # argument should be the version (can be omitted if it is the same as the # branch name). set -e set -x if [[ -z $2 ]]; then $2=$1 fi git pull git checkout $1 git pull shift /opt/conda/bin/rever "$@" sympy-sympy-1.9/release/release.sh000077500000000000000000000007721412543434000173300ustar00rootroot00000000000000#!/bin/bash # This is the main entrypoint script to do the release. Run it like # ./release.sh # If the version is the same as the branch you can omit it. # You may need to run the script with sudo on Linux. The only requirement for # the script to work is Docker. set -e set -x parent_path=$( cd "$(dirname "${BASH_SOURCE[0]}")" ; pwd -P ) cd "$parent_path" if [[ -z $2 ]]; then $2=$1 fi docker run -t -v "$parent_path/release-$2":/root/release sympy/sympy-release "$@" sympy-sympy-1.9/release/releasecheck.py000077500000000000000000000041401412543434000203350ustar00rootroot00000000000000#!/usr/bin/env python3 from os.path import join, basename, normpath from subprocess import check_call def main(version, prevversion, outdir): check_version(version, outdir) run_stage(['bin/mailmap_update.py']) run_stage(['bin/authors_update.py']) run_stage(['mkdir', '-p', outdir]) build_release_files('bdist_wheel', 'sympy-%s-py3-none-any.whl', outdir, version) build_release_files('sdist', 'sympy-%s.tar.gz', outdir, version) run_stage(['release/compare_tar_against_git.py', join(outdir, 'sympy-%s.tar.gz' % (version,)), '.']) run_stage(['release/test_install.py', version, outdir]) run_stage(['release/build_docs.py', version, outdir]) run_stage(['release/sha256.py', version, outdir]) run_stage(['release/authors.py', version, prevversion, outdir]) def green(text): return "\033[32m%s\033[0m" % text def red(text): return "\033[31m%s\033[0m" % text def print_header(color, *msgs): newlines = '\n' vline = '-' * 80 print(color(newlines + vline)) for msg in msgs: print(color(msg)) print(color(vline + newlines)) def run_stage(cmd): cmdline = ' $ %s' % (' '.join(cmd),) print_header(green, 'running:', cmdline) try: check_call(cmd) except Exception as e: print_header(red, 'failed:', cmdline) raise e from None else: print_header(green, 'completed:', cmdline) def build_release_files(cmd, fname, outdir, version): fname = fname % (version,) run_stage(['python', 'setup.py', '-q', cmd]) src = join('dist', fname) dst = join(outdir, fname) run_stage(['mv', src, dst]) def check_version(version, outdir): from sympy.release import __version__ as checked_out_version if version != checked_out_version: msg = "version %s does not match checkout %s" raise AssertionError(msg % (version, checked_out_version)) if basename(normpath(outdir)) != 'release-%s' % (version,): msg = "version %s does not match output directory %s" raise AssertionError(msg % (version, outdir)) if __name__ == "__main__": import sys main(*sys.argv[1:]) sympy-sympy-1.9/release/requirements.txt000066400000000000000000000031101412543434000206220ustar00rootroot00000000000000absl-py==0.13.0 aesara==2.2.1 alabaster==0.7.12 antlr4-python3-runtime==4.7.2 appnope==0.1.2 astunparse==1.6.3 autowrap==0.22.3 Babel==2.9.1 backcall==0.2.0 cachetools==4.2.2 certifi==2021.5.30 charset-normalizer==2.0.4 clang==5.0 cycler==0.10.0 Cython==0.29.24 decorator==5.0.9 docutils==0.17.1 filelock==3.0.12 flatbuffers==1.12 gast==0.4.0 google-auth==1.35.0 google-auth-oauthlib==0.4.6 google-pasta==0.2.0 grpcio==1.39.0 h5py==3.1.0 idna==3.2 imagesize==1.2.0 ipython==7.27.0 jedi==0.18.0 Jinja2==3.0.1 keras==2.6.0 Keras-Preprocessing==1.1.2 kiwisolver==1.3.2 llvmlite==0.37.0 Markdown==3.3.4 MarkupSafe==2.0.1 matplotlib==3.4.3 matplotlib-inline==0.1.2 mpmath==1.2.1 numexpr==2.7.3 numpy==1.19.5 oauthlib==3.1.1 opt-einsum==3.3.0 packaging==21.0 parso==0.8.2 pexpect==4.8.0 pickleshare==0.7.5 Pillow==8.3.2 prompt-toolkit==3.0.20 protobuf==3.17.3 ptyprocess==0.7.0 pyasn1==0.4.8 pyasn1-modules==0.2.8 Pygments==2.10.0 pyparsing==2.4.7 python-dateutil==2.8.2 pytz==2021.1 requests==2.26.0 requests-oauthlib==1.3.0 rsa==4.7.2 scipy==1.7.1 six==1.15.0 snowballstemmer==2.1.0 Sphinx==4.1.2 sphinx-math-dollar==1.2 sphinx-reredirects==0.0.1 sphinxcontrib-applehelp==1.0.2 sphinxcontrib-devhelp==1.0.2 sphinxcontrib-htmlhelp==2.0.0 sphinxcontrib-jsmath==1.0.1 sphinxcontrib-qthelp==1.0.3 sphinxcontrib-serializinghtml==1.1.5 symengine==0.7.2 tensorboard==2.6.0 tensorboard-data-server==0.6.1 tensorboard-plugin-wit==1.8.0 tensorflow==2.6.0 tensorflow-estimator==2.6.0 termcolor==1.1.0 traitlets==5.1.0 typing-extensions==3.7.4.3 urllib3==1.26.6 wcwidth==0.2.5 Werkzeug==2.0.1 wrapt==1.12.1 wurlitzer==3.0.2 sympy-sympy-1.9/release/rever.xsh000066400000000000000000000430051412543434000172140ustar00rootroot00000000000000# -*-mode: python; flycheck-mode: nil -*- $XONSH_SHOW_TRACEBACK = True $RAISE_SUBPROC_ERROR = True trace on import os import sys import unicodedata from collections import defaultdict from collections.abc import Mapping from getpass import getpass from contextlib import contextmanager import json import glob import stat import configparser import time import requests from requests.auth import HTTPBasicAuth from rever.activity import activity from rever.conda import run_in_conda_env cd .. $ACTIVITIES = [ # 'version_bump', '_version', 'mailmap_update', 'test_sympy', 'source_tarball', 'wheel', 'build_docs', 'copy_release_files', 'compare_tar_against_git', 'test_tarball35', 'test_tarball36', 'test_tarball37', 'test_tarball38', 'test_wheel35', 'test_wheel36', 'test_wheel37', 'test_wheel38', 'print_authors', 'sha256', # 'tag', ] version = $VERSION # Work around https://github.com/ergs/rever/issues/15 @activity def _version(): global version version = $VERSION $TAG_PUSH = False $VERSION_BUMP_PATTERNS = [ ('sympy/release.py', r'__version__ = ".*"', r'__version__ = "$VERSION"'), ] # ACTIVITIES @activity def mailmap_update(): with run_in_conda_env(['python=3.6', 'mpmath']): ./bin/mailmap_update.py @activity def test_sympy(): with run_in_conda_env(['mpmath', 'matplotlib>=2.2', 'numpy', 'scipy', 'aesara', 'ipython', 'gmpy2', 'symengine', 'libgfortran', 'cython', 'tensorflow', 'llvmlite', 'wurlitzer', 'autowrap', 'python-symengine=0.3.*', 'numexpr', 'antlr-python-runtime>=4.7,<4.8', 'antlr>=4.7,<4.8'], 'sympy-tests'): ./setup.py test @activity(deps={'_version', 'mailmap_update'}) def source_tarball(): with run_in_conda_env(['mpmath', 'python=3.6'], 'sympy-release'): # Assumes this is run in Docker and git is already clean ./setup.py sdist --keep-temp @activity(deps={'_version', 'mailmap_update'}) def wheel(): with run_in_conda_env(['mpmath', 'python=3.6', 'setuptools', 'pip', 'wheel'], 'sympy-release'): # Assumes this is run in Docker and git is already clean ./setup.py bdist_wheel --keep-temp @activity(deps={'_version'}) def build_docs(): with run_in_conda_env(['sphinx', 'docutils', 'numpy', 'mpmath', 'matplotlib', 'sphinx-math-dollar'], envname='sympy-release-docs'): cd doc make clean make html make man cd _build mv html @(tarball_format['html-nozip']) zip -9lr @(tarball_format['html']) @(tarball_format['html-nozip']) cp @(tarball_format['html']) ../../dist/ cd .. make clean make latex cd _build/latex make cp @(tarball_format['pdf-orig']) @("../../../dist/{pdf}".format(**tarball_format)) cd ../../../ @activity(deps={'source_tarball', 'wheel', 'build_docs'}) def copy_release_files(): ls dist cp dist/* /root/release/ @activity(deps={'source_tarball'}) def test_tarball35(): test_tarball('3.5') @activity(deps={'source_tarball'}) def test_tarball36(): test_tarball('3.6') @activity(deps={'source_tarball'}) def test_tarball37(): test_tarball('3.7') @activity(deps={'source_tarball'}) def test_tarball38(): test_tarball('3.8') @activity(deps={'wheel'}) def test_wheel35(): test_wheel('3.5') @activity(deps={'wheel'}) def test_wheel36(): test_wheel('3.6') @activity(deps={'wheel'}) def test_wheel37(): test_wheel('3.7') @activity(deps={'wheel'}) def test_wheel38(): test_wheel('3.8') @activity(deps={'source_tarball'}) def compare_tar_against_git(): """ Compare the contents of the tarball against git ls-files See the bottom of the file for the whitelists. """ release/compare_tar_against_git.py /root/release/@(tarball_format['source']) . @activity(deps={'source_tarball', 'wheel'}) def print_authors(): """ Print authors text to put at the bottom of the release notes """ authors, authorcount, newauthorcount = get_authors() print(blue("Here are the authors to put at the bottom of the release notes.")) print() print("""## Authors The following people contributed at least one patch to this release (names are given in alphabetical order by last name). A total of {authorcount} people contributed to this release. People with a * by their names contributed a patch for the first time for this release; {newauthorcount} people contributed for the first time for this release. Thanks to everyone who contributed to this release! """.format(authorcount=authorcount, newauthorcount=newauthorcount)) for name in authors: print("- " + name) print() @activity(deps={'source_tarball', 'wheel', 'build_docs'}) def sha256(): """ Print the sha256 sums of the release files """ _sha256(print_=True) def _sha256(print_=True, local=False): if local: out = $(shasum -a 256 @(release_files())) else: out = $(shasum -a 256 /root/release/*) # Remove the release/ part for printing. Useful for copy-pasting into the # release notes. out = [i.split() for i in out.strip().split('\n')] out = '\n'.join(["%s\t%s" % (i, os.path.split(j)[1]) for i, j in out]) if print_: print(out) return out @activity(deps={'mailmap_update', 'sha256', 'print_authors', 'source_tarball', 'wheel', 'build_docs', 'compare_tar_against_git', 'test_tarball35', 'test_tarball36', 'test_tarball37', 'test_tarball38', 'test_wheel35', 'test_wheel36', 'test_wheel37', 'test_wheel38', 'test_sympy'}) def release(): pass @activity(deps={'_version'}) def GitHub_release(): # _GitHub_release(version) # Run the github_release.py script pass @GitHub_release.undoer def GitHub_release(): # Prevent default undo pass @activity(deps={'_version'}) def update_docs(): _update_docs() @activity(deps={'_version'}) def update_sympy_org(): _update_sympy_org() @activity() def update_websites(): _update_docs() _update_sympy_org() # HELPER FUNCTIONS def test_tarball(py_version): """ Test that the tarball can be unpacked and installed, and that sympy imports in the install. """ if py_version not in {'3.5', '3.6', '3.7', '3.8'}: # TODO: Add win32 raise ValueError("release must be one of 3.5, 3.6, 3.7 or 3.8 not %s" % py_version) with run_in_conda_env(['python=%s' % py_version], 'test-install-%s' % py_version): cp @('/root/release/{source}'.format(**tarball_format)) @("releasetar.tar.gz".format(**tarball_format)) tar xvf releasetar.tar.gz cd @("{source-orig-notar}".format(**tarball_format)) python setup.py install python -c "import sympy; print(sympy.__version__); print('sympy installed successfully')" python -m isympy --help isympy --help def test_wheel(py_version): """ Test that the wheel can be installed, and that sympy imports in the install. """ if py_version not in {'3.5', '3.6', '3.7', '3.8'}: # TODO: Add win32 raise ValueError("release must be one of 3.5, 3.6, 3.7 or 3.8 not %s" % py_version) with run_in_conda_env(['python=%s' % py_version], 'test-install-%s' % py_version): cp @('/root/release/{wheel}'.format(**tarball_format)) @("{wheel}".format(**tarball_format)) pip install @("{wheel}".format(**tarball_format)) python -c "import sympy; print(sympy.__version__); print('sympy installed successfully')" python -m isympy --help isympy --help def get_tarball_name(file): """ Get the name of a tarball file should be one of source-orig: The original name of the source tarball source-orig-notar: The name of the untarred directory source: The source tarball (after renaming) wheel: The wheel html: The name of the html zip html-nozip: The name of the html, without ".zip" pdf-orig: The original name of the pdf file pdf: The name of the pdf file (after renaming) """ doctypename = defaultdict(str, {'html': 'zip', 'pdf': 'pdf'}) if file in {'source-orig', 'source'}: name = 'sympy-{version}.tar.gz' elif file == 'source-orig-notar': name = "sympy-{version}" elif file in {'html', 'pdf', 'html-nozip'}: name = "sympy-docs-{type}-{version}" if file == 'html-nozip': # zip files keep the name of the original zipped directory. See # https://github.com/sympy/sympy/issues/7087. file = 'html' else: name += ".{extension}" elif file == 'pdf-orig': name = "sympy-{version}.pdf" elif file == 'wheel': name = 'sympy-{version}-py3-none-any.whl' else: raise ValueError(file + " is not a recognized argument") ret = name.format(version=version, type=file, extension=doctypename[file]) return ret tarball_name_types = { 'source-orig', 'source-orig-notar', 'source', 'wheel', 'html', 'html-nozip', 'pdf-orig', 'pdf', } # Have to make this lazy so that version can be defined. class _tarball_format(Mapping): def __getitem__(self, name): return get_tarball_name(name) def __iter__(self): return iter(tarball_name_types) def __len__(self): return len(tarball_name_types) tarball_format = _tarball_format() def release_files(): """ Returns the list of local release files """ return glob.glob('release/release-' + $VERSION + '/*') def red(text): return "\033[31m%s\033[0m" % text def green(text): return "\033[32m%s\033[0m" % text def yellow(text): return "\033[33m%s\033[0m" % text def get_authors(): """ Get the list of authors since the previous release Returns the list in alphabetical order by last name. Authors who contributed for the first time for this release will have a star appended to the end of their names. Note: it's a good idea to use ./bin/mailmap_update.py (from the base sympy directory) to make AUTHORS and .mailmap up-to-date first before using this. fab vagrant release does this automatically. """ def lastnamekey(name): """ Sort key to sort by last name Note, we decided to sort based on the last name, because that way is fair. We used to sort by commit count or line number count, but that bumps up people who made lots of maintenance changes like updating mpmath or moving some files around. """ # Note, this will do the wrong thing for people who have multi-word # last names, but there are also people with middle initials. I don't # know of a perfect way to handle everyone. Feel free to fix up the # list by hand. text = name.strip().split()[-1].lower() # Convert things like Čertík to Certik return unicodedata.normalize('NFKD', text).encode('ascii', 'ignore') old_release_tag = get_previous_version_tag() releaseauthors = set($(git --no-pager log @(old_release_tag + '..') --format=%aN).strip().split('\n')) priorauthors = set($(git --no-pager log @(old_release_tag) --format=%aN).strip().split('\n')) releaseauthors = {name.strip() for name in releaseauthors if name.strip()} priorauthors = {name.strip() for name in priorauthors if name.strip()} newauthors = releaseauthors - priorauthors starred_newauthors = {name + "*" for name in newauthors} authors = releaseauthors - newauthors | starred_newauthors return (sorted(authors, key=lastnamekey), len(releaseauthors), len(newauthors)) def get_previous_version_tag(): """ Get the version of the previous release """ # We try, probably too hard, to portably get the number of the previous # release of SymPy. Our strategy is to look at the git tags. The # following assumptions are made about the git tags: # - The only tags are for releases # - The tags are given the consistent naming: # sympy-major.minor.micro[.rcnumber] # (e.g., sympy-0.7.2 or sympy-0.7.2.rc1) # In particular, it goes back in the tag history and finds the most recent # tag that doesn't contain the current short version number as a substring. shortversion = get_sympy_short_version() curcommit = "HEAD" while True: curtag = $(git describe --abbrev=0 --tags @(curcommit)).strip() if shortversion in curtag: # If the tagged commit is a merge commit, we cannot be sure # that it will go back in the right direction. This almost # never happens, so just error parents = $(git rev-list --parents -n 1 @(curtag)).strip().split() # rev-list prints the current commit and then all its parents # If the tagged commit *is* a merge commit, just comment this # out, and manually make sure `get_previous_version_tag` is correct # assert len(parents) == 2, curtag curcommit = curtag + "^" # The parent of the tagged commit else: print(blue("Using {tag} as the tag for the previous " "release.".format(tag=curtag))) return curtag sys.exit(red("Could not find the tag for the previous release.")) def get_sympy_short_version(): """ Get the short version of SymPy being released, not including any rc tags (like 0.7.3) """ parts = version.split('.') # Remove rc tags # Handle both 1.0.rc1 and 1.1rc1 if not parts[-1].isdigit(): if parts[-1][0].isdigit(): parts[-1] = parts[-1][0] else: parts.pop(-1) return '.'.join(parts) def get_location(location): """ Read/save a location from the configuration file. """ locations_file = os.path.expanduser('~/.sympy/sympy-locations') config = configparser.SafeConfigParser() config.read(locations_file) the_location = config.has_option("Locations", location) and config.get("Locations", location) if not the_location: the_location = input("Where is the SymPy {location} directory? ".format(location=location)) if not config.has_section("Locations"): config.add_section("Locations") config.set("Locations", location, the_location) save = raw_input("Save this to file [yes]? ") if save.lower().strip() in ['', 'y', 'yes']: print("saving to ", locations_file) with open(locations_file, 'w') as f: config.write(f) else: print("Reading {location} location from config".format(location=location)) return os.path.abspath(os.path.expanduser(the_location)) def _update_docs(docs_location=None): """ Update the docs hosted at docs.sympy.org """ docs_location = docs_location or get_location("docs") print("Docs location:", docs_location) current_version = version previous_version = get_previous_version_tag().lstrip('sympy-') release_dir = os.path.abspath(os.path.expanduser(os.path.join(os.path.curdir, 'release'))) docs_zip = os.path.abspath(os.path.join(release_dir, 'release-' + version, get_tarball_name('html'))) cd @(docs_location) # Check that the docs directory is clean git diff --exit-code > /dev/null git diff --cached --exit-code > /dev/null git pull print("Unzipping docs into repo") unzip @(docs_zip) > /dev/null mv @(get_tarball_name('html-nozip')) latest print("Generating indexes") ./generate_indexes.py print("Committing") git add -A latest git commit -a -m @('Updating docs to {version}'.format(version=current_version)) print("Pushing") git push origin cd @(release_dir) cd .. def _update_sympy_org(website_location=None): """ Update sympy.org This just means adding an entry to the news section. """ website_location = website_location or get_location("sympy.github.com") release_dir = os.path.abspath(os.path.expanduser(os.path.join(os.path.curdir, 'release'))) cd @(website_location) # Check that the website directory is clean git diff --exit-code > /dev/null git diff --cached --exit-code > /dev/null git pull release_date = time.gmtime(os.path.getctime(os.path.join(release_dir, 'release-' + version, tarball_format['source']))) release_year = str(release_date.tm_year) release_month = str(release_date.tm_mon) release_day = str(release_date.tm_mday) with open(os.path.join(website_location, "templates", "index.html"), 'r') as f: lines = f.read().split('\n') # We could try to use some html parser, but this way is easier try: news = lines.index(r"

{% trans %}News{% endtrans %}

") except ValueError: error("index.html format not as expected") lines.insert(news + 2, # There is a

after the news line. Put it # after that. r""" {{ datetime(""" + release_year + """, """ + release_month + """, """ + release_day + """) }} {% trans v='""" + version + """' %}Version {{ v }} released{% endtrans %} ({% trans %}changes{% endtrans %})

""") with open(os.path.join(website_location, "templates", "index.html"), 'w') as f: print("Updating index.html template") f.write('\n'.join(lines)) print("Generating website pages") ./generate print("Committing") git commit -a -m @('Add {version} to the news'.format(version=version)) print("Pushing") git push origin cd @(release_dir) cd .. sympy-sympy-1.9/release/sha256.py000077500000000000000000000016111412543434000167270ustar00rootroot00000000000000#!/usr/bin/env python3 import os from pathlib import Path from subprocess import check_output def main(version, outdir): outdir = Path(outdir) build_files = [ outdir / f'sympy-{version}.tar.gz', outdir / f'sympy-{version}-py3-none-any.whl', outdir / f'sympy-docs-html-{version}.zip', outdir / f'sympy-docs-pdf-{version}.pdf', ] out = check_output(['shasum', '-a', '256'] + build_files) out = out.decode('ascii') # Remove the release/ part for printing. Useful for copy-pasting into the # release notes. out = [i.split() for i in out.strip().split('\n')] out = '\n'.join(["%s\t%s" % (i, os.path.split(j)[1]) for i, j in out]) # Output to file and to screen with open(outdir / 'sha256.txt', 'w') as shafile: shafile.write(out) print(out) if __name__ == "__main__": import sys sys.exit(main(*sys.argv[1:])) sympy-sympy-1.9/release/test_install.py000077500000000000000000000036251412543434000204330ustar00rootroot00000000000000#!/usr/bin/env python3 from pathlib import Path from tempfile import TemporaryDirectory from subprocess import check_call PY_VERSIONS = '3.6', '3.7', '3.8', '3.9' def main(version, outdir): for pyversion in PY_VERSIONS: test_sdist(pyversion, version, outdir) test_wheel(pyversion, version, outdir) def run(cmd, cwd=None): if isinstance(cmd, str): cmd = cmd.split() return check_call(cmd, cwd=cwd) def green(text): return "\033[32m%s\033[0m" % text def test_sdist(pyversion, version, outdir, wheel=False): print(green('-' * 80)) if not wheel: print(green(' Testing Python %s (sdist)' % pyversion)) else: print(green(' Testing Python %s (wheel)' % pyversion)) print(green('-' * 80)) python_exe = f'python{pyversion}' wheelname = f'sympy-{version}-py3-none-any.whl' tarname = f'sympy-{version}.tar.gz' tardir = f'sympy-{version}' with TemporaryDirectory() as tempdir: outdir = Path(outdir) tempdir = Path(tempdir) venv = tempdir / f'venv{pyversion}' pip = venv / "bin" / "pip" python = venv / "bin" / "python" run(f'{python_exe} -m venv {venv}') run(f'{pip} install -U -q pip') if not wheel: run(f'{pip} install -q mpmath') run(f'cp {outdir/tarname} {tempdir/tarname}') run(f'tar -xzf {tempdir/tarname} -C {tempdir}') run(f'{python} setup.py -q install', cwd=tempdir/tardir) else: run(f'{pip} install -q {outdir/wheelname}') isympy = venv / "bin" / "isympy" run([python, '-c', "import sympy; print(sympy.__version__); print('sympy installed successfully')"]) run(f'{python} -m isympy --version') run(f'{isympy} --version') def test_wheel(*args): return test_sdist(*args, wheel=True) if __name__ == "__main__": import sys sys.exit(main(*sys.argv[1:])) sympy-sympy-1.9/release/update_docs.py000077500000000000000000000066111412543434000202160ustar00rootroot00000000000000#!/usr/bin/env python3 import subprocess import sys from os.path import join, splitext, basename from contextlib import contextmanager from tempfile import TemporaryDirectory from zipfile import ZipFile from shutil import copytree def main(sympy_doc_git, doc_html_zip, version, push=None): """Run this as ./update_docs.py SYMPY_DOC_GIT DOC_HTML_ZIP VERSION [--push] !!!!!!!!!!!!!!!!! NOTE: This is intended to be run as part of the release script. NOTE: This script will automatically push to the sympy_doc repo. !!!!!!!!!!!!!!!!! Args ==== SYMPY_DOC_GIT: Path to the sympy_doc repo. DOC_HTML_ZIP: Path to the zip of the built html docs. VERSION: Version string (e.g. "1.6") --push (optional): Push the results (Warning this pushes direct to github) This script automates the "release docs" step described in the README of the sympy/sympy_doc repo: https://github.com/sympy/sympy_doc#release-docs """ if push is None: push = False elif push == "--push": push = True else: raise ValueError("Invalid arguments") update_docs(sympy_doc_git, doc_html_zip, version, push) def update_docs(sympy_doc_git, doc_html_zip, version, push): # We started with a clean tree so restore it on error with git_rollback_on_error(sympy_doc_git, branch='gh-pages') as run: # Delete docs for the last version run('git', 'rm', '-rf', 'latest') # Extract new docs in replacement extract_docs(sympy_doc_git, doc_html_zip) # Commit new docs run('git', 'add', 'latest') run('git', 'commit', '-m', 'Add sympy %s docs' % version) # Update indexes run('./generate_indexes.py') run('git', 'diff') run('git', 'commit', '-a', '-m', 'Update indexes') if push: run('git', 'push') else: print('Results are committed but not pushed') @contextmanager def git_rollback_on_error(gitroot_path, branch='master'): def run(*cmdline, **kwargs): """Run subprocess with cwd in sympy_doc""" print() print('Running: $ ' + ' '.join(cmdline)) print() return subprocess.run(cmdline, cwd=gitroot_path, check=True, **kwargs) unclean_msg = "The git repo should be completely clean before running this" try: run('git', 'diff', '--exit-code') # Error if tree is unclean except subprocess.CalledProcessError: raise ValueError(unclean_msg) if run('git', 'clean', '-n', stdout=subprocess.PIPE).stdout: raise ValueError(unclean_msg) run('git', 'checkout', branch) run('git', 'pull') bsha_start = run('git', 'rev-parse', 'HEAD', stdout=subprocess.PIPE).stdout sha_start = bsha_start.strip().decode('ascii') try: yield run except Exception as e: run('git', 'reset', '--hard', sha_start) raise e from None def extract_docs(sympy_doc_git, doc_html_zip): subdirname = splitext(basename(doc_html_zip))[0] with TemporaryDirectory() as tempdir: print() print('Extracting docs to ' + tempdir) print() ZipFile(doc_html_zip).extractall(tempdir) print() print('Copying to sympy_doc/latest') print() srcpath = join(tempdir, subdirname) dstpath = join(sympy_doc_git, 'latest') copytree(srcpath, dstpath) if __name__ == "__main__": main(*sys.argv[1:]) sympy-sympy-1.9/release/update_requirements.sh000077500000000000000000000020451412543434000217700ustar00rootroot00000000000000#!/usr/bin/env bash # # Run as # # $ ./update_requirements.sh python # # where python is the name of the (on PATH) interpreter to use. This will # create a virtual environment with venv, rerun the pip install command to get # latest versions meeting the constraints and then use pip list to recreate # requirements.txt with updated versions. # # This will overwrite the requirements.txt file and show the diff if [ -z $1 ]; then python=python3 else python=$1 fi tmp_dir=$(mktemp -d -t venv-XXXX) venv_dir=$tmp_dir/venv $python -m venv $venv_dir . $venv_dir/bin/activate pip install -U pip wheel # Installing tensorflow needs a lot of memory. Give at least 2GiB memory for a # VM or it will fail printing "Collecting tensorflow... Killed" pip install\ mpmath\ matplotlib\ numpy\ scipy\ aesara\ ipython\ symengine\ tensorflow\ cython\ llvmlite\ wurlitzer\ autowrap\ numexpr\ 'antlr4-python3-runtime==4.7.*'\ sphinx\ sphinx-math-dollar\ sphinx-reredirects\ # pip freeze > requirements.txt git diff requirements.txt sympy-sympy-1.9/setup.cfg000066400000000000000000000033741412543434000155530ustar00rootroot00000000000000[metadata] long_description = file: README.md long_description_content_type = text/markdown [flake8] doctests = True ignore = F403 select = F,E722 exclude = sympy/parsing/latex/_antlr/*, sympy/parsing/autolev/_antlr/*, sympy/parsing/autolev/test-examples/*, sympy/integrals/rubi/* per-file-ignores = sympy/interactive/session.py:F821 # Global mypy settings: [mypy] # Per module settings: [mypy-sympy.integrals.rubi.*] ignore_errors = True [mypy-sympy.parsing.latex._antlr.*] ignore_errors = True [mypy-sympy.parsing.autolev._antlr.*] ignore_errors = True [mypy-sympy.testing.benchmarking.*] ignore_errors = True [mypy-sympy.benchmarks.*] ignore_errors = True [mypy-sympy.plotting.pygletplot.*] ignore_errors = True # Third-party untyped code: [mypy-antlr4.*] ignore_missing_imports = True [mypy-Cython.*] ignore_missing_imports = True [mypy-gmpy.*] ignore_missing_imports = True [mypy-gmpy2.*] ignore_missing_imports = True [mypy-IPython.*] ignore_missing_imports = True [mypy-lxml.*] ignore_missing_imports = True [mypy-matchpy.*] ignore_missing_imports = True [mypy-matplotlib.*] ignore_missing_imports = True [mypy-mpmath.*] ignore_missing_imports = True [mypy-numpy.*] ignore_missing_imports = True [mypy-PIL.*] ignore_missing_imports = True [mypy-pycosat.*] ignore_missing_imports = True [mypy-pyglet.*] ignore_missing_imports = True [mypy-pymc3.*] ignore_missing_imports = True [mypy-python-sat.*] ignore_missing_imports = True [mypy-pytest.*] ignore_missing_imports = True [mypy-_pytest.*] ignore_missing_imports = True [mypy-sage.*] ignore_missing_imports = True [mypy-scipy.*] ignore_missing_imports = True [mypy-symengine.*] ignore_missing_imports = True [mypy-aesara.*] ignore_missing_imports = True [mypy-xml.*] ignore_missing_imports = True sympy-sympy-1.9/setup.py000077500000000000000000000346341412543434000154520ustar00rootroot00000000000000#!/usr/bin/env python """Distutils based setup script for SymPy. This uses Distutils (https://python.org/sigs/distutils-sig/) the standard python mechanism for installing packages. Optionally, you can use Setuptools (https://setuptools.readthedocs.io/en/latest/) to automatically handle dependencies. For the easiest installation just type the command (you'll probably need root privileges for that): python setup.py install This will install the library in the default location. For instructions on how to customize the install procedure read the output of: python setup.py --help install In addition, there are some other commands: python setup.py clean -> will clean all trash (*.pyc and stuff) python setup.py test -> will run the complete test suite python setup.py bench -> will run the complete benchmark suite python setup.py audit -> will run pyflakes checker on source code To get a full list of available commands, read the output of: python setup.py --help-commands Or, if all else fails, feel free to write to the sympy list at sympy@googlegroups.com and ask for help. """ import sys import os import shutil import glob import subprocess from distutils.command.sdist import sdist min_mpmath_version = '0.19' # This directory dir_setup = os.path.dirname(os.path.realpath(__file__)) extra_kwargs = {} try: from setuptools import setup, Command extra_kwargs['zip_safe'] = False extra_kwargs['entry_points'] = { 'console_scripts': [ 'isympy = isympy:main', ] } except ImportError: from distutils.core import setup, Command extra_kwargs['scripts'] = ['bin/isympy'] # handle mpmath deps in the hard way: from sympy.external.importtools import version_tuple try: import mpmath if version_tuple(mpmath.__version__) < version_tuple(min_mpmath_version): raise ImportError except ImportError: print("Please install the mpmath package with a version >= %s" % min_mpmath_version) sys.exit(-1) if sys.version_info < (3, 6): print("SymPy requires Python 3.6 or newer. Python %d.%d detected" % sys.version_info[:2]) sys.exit(-1) # Check that this list is uptodate against the result of the command: # python bin/generate_module_list.py modules = [ 'sympy.algebras', 'sympy.assumptions', 'sympy.assumptions.handlers', 'sympy.assumptions.predicates', 'sympy.assumptions.relation', 'sympy.benchmarks', 'sympy.calculus', 'sympy.categories', 'sympy.codegen', 'sympy.combinatorics', 'sympy.concrete', 'sympy.core', 'sympy.core.benchmarks', 'sympy.crypto', 'sympy.diffgeom', 'sympy.discrete', 'sympy.external', 'sympy.functions', 'sympy.functions.combinatorial', 'sympy.functions.elementary', 'sympy.functions.elementary.benchmarks', 'sympy.functions.special', 'sympy.functions.special.benchmarks', 'sympy.geometry', 'sympy.holonomic', 'sympy.integrals', 'sympy.integrals.benchmarks', 'sympy.integrals.rubi', 'sympy.integrals.rubi.parsetools', 'sympy.integrals.rubi.rubi_tests', 'sympy.integrals.rubi.rules', 'sympy.interactive', 'sympy.liealgebras', 'sympy.logic', 'sympy.logic.algorithms', 'sympy.logic.utilities', 'sympy.matrices', 'sympy.matrices.benchmarks', 'sympy.matrices.expressions', 'sympy.multipledispatch', 'sympy.ntheory', 'sympy.parsing', 'sympy.parsing.autolev', 'sympy.parsing.autolev._antlr', 'sympy.parsing.c', 'sympy.parsing.fortran', 'sympy.parsing.latex', 'sympy.parsing.latex._antlr', 'sympy.physics', 'sympy.physics.continuum_mechanics', 'sympy.physics.control', 'sympy.physics.hep', 'sympy.physics.mechanics', 'sympy.physics.optics', 'sympy.physics.quantum', 'sympy.physics.units', 'sympy.physics.units.definitions', 'sympy.physics.units.systems', 'sympy.physics.vector', 'sympy.plotting', 'sympy.plotting.intervalmath', 'sympy.plotting.pygletplot', 'sympy.polys', 'sympy.polys.agca', 'sympy.polys.benchmarks', 'sympy.polys.domains', 'sympy.polys.matrices', 'sympy.printing', 'sympy.printing.pretty', 'sympy.sandbox', 'sympy.series', 'sympy.series.benchmarks', 'sympy.sets', 'sympy.sets.handlers', 'sympy.simplify', 'sympy.solvers', 'sympy.solvers.benchmarks', 'sympy.solvers.diophantine', 'sympy.solvers.ode', 'sympy.stats', 'sympy.stats.sampling', 'sympy.strategies', 'sympy.strategies.branch', 'sympy.tensor', 'sympy.tensor.array', 'sympy.tensor.array.expressions', 'sympy.testing', 'sympy.unify', 'sympy.utilities', 'sympy.utilities._compilation', 'sympy.utilities.mathml', 'sympy.vector', ] class audit(Command): """Audits SymPy's source code for following issues: - Names which are used but not defined or used before they are defined. - Names which are redefined without having been used. """ description = "Audit SymPy source with PyFlakes" user_options = [] def initialize_options(self): self.all = None def finalize_options(self): pass def run(self): try: import pyflakes.scripts.pyflakes as flakes except ImportError: print("In order to run the audit, you need to have PyFlakes installed.") sys.exit(-1) dirs = (os.path.join(*d) for d in (m.split('.') for m in modules)) warns = 0 for dir in dirs: for filename in os.listdir(dir): if filename.endswith('.py') and filename != '__init__.py': warns += flakes.checkPath(os.path.join(dir, filename)) if warns > 0: print("Audit finished with total %d warnings" % warns) class clean(Command): """Cleans *.pyc and debian trashs, so you should get the same copy as is in the VCS. """ description = "remove build files" user_options = [("all", "a", "the same")] def initialize_options(self): self.all = None def finalize_options(self): pass def run(self): curr_dir = os.getcwd() for root, dirs, files in os.walk(dir_setup): for file in files: if file.endswith('.pyc') and os.path.isfile: os.remove(os.path.join(root, file)) os.chdir(dir_setup) names = ["python-build-stamp-2.4", "MANIFEST", "build", "dist", "doc/_build", "sample.tex"] for f in names: if os.path.isfile(f): os.remove(f) elif os.path.isdir(f): shutil.rmtree(f) for name in glob.glob(os.path.join(dir_setup, "doc", "src", "modules", "physics", "vector", "*.pdf")): if os.path.isfile(name): os.remove(name) os.chdir(curr_dir) class test_sympy(Command): """Runs all tests under the sympy/ folder """ description = "run all tests and doctests; also see bin/test and bin/doctest" user_options = [] # distutils complains if this is not here. def __init__(self, *args): self.args = args[0] # so we can pass it to other classes Command.__init__(self, *args) def initialize_options(self): # distutils wants this pass def finalize_options(self): # this too pass def run(self): from sympy.utilities import runtests runtests.run_all_tests() class run_benchmarks(Command): """Runs all SymPy benchmarks""" description = "run all benchmarks" user_options = [] # distutils complains if this is not here. def __init__(self, *args): self.args = args[0] # so we can pass it to other classes Command.__init__(self, *args) def initialize_options(self): # distutils wants this pass def finalize_options(self): # this too pass # we use py.test like architecture: # # o collector -- collects benchmarks # o runner -- executes benchmarks # o presenter -- displays benchmarks results # # this is done in sympy.utilities.benchmarking on top of py.test def run(self): from sympy.utilities import benchmarking benchmarking.main(['sympy']) class antlr(Command): """Generate code with antlr4""" description = "generate parser code from antlr grammars" user_options = [] # distutils complains if this is not here. def __init__(self, *args): self.args = args[0] # so we can pass it to other classes Command.__init__(self, *args) def initialize_options(self): # distutils wants this pass def finalize_options(self): # this too pass def run(self): from sympy.parsing.latex._build_latex_antlr import build_parser if not build_parser(): sys.exit(-1) class sdist_sympy(sdist): def run(self): # Fetch git commit hash and write down to commit_hash.txt before # shipped in tarball. commit_hash = None commit_hash_filepath = 'doc/commit_hash.txt' try: commit_hash = \ subprocess.check_output(['git', 'rev-parse', 'HEAD']) commit_hash = commit_hash.decode('ascii') commit_hash = commit_hash.rstrip() print('Commit hash found : {}.'.format(commit_hash)) print('Writing it to {}.'.format(commit_hash_filepath)) except: pass if commit_hash: with open(commit_hash_filepath, 'w') as f: f.write(commit_hash) super(sdist_sympy, self).run() try: os.remove(commit_hash_filepath) print( 'Successfully removed temporary file {}.' .format(commit_hash_filepath)) except OSError as e: print("Error deleting %s - %s." % (e.filename, e.strerror)) # Check that this list is uptodate against the result of the command: # python bin/generate_test_list.py tests = [ 'sympy.algebras.tests', 'sympy.assumptions.tests', 'sympy.calculus.tests', 'sympy.categories.tests', 'sympy.codegen.tests', 'sympy.combinatorics.tests', 'sympy.concrete.tests', 'sympy.core.tests', 'sympy.crypto.tests', 'sympy.diffgeom.tests', 'sympy.discrete.tests', 'sympy.external.tests', 'sympy.functions.combinatorial.tests', 'sympy.functions.elementary.tests', 'sympy.functions.special.tests', 'sympy.geometry.tests', 'sympy.holonomic.tests', 'sympy.integrals.rubi.parsetools.tests', 'sympy.integrals.rubi.rubi_tests.tests', 'sympy.integrals.rubi.tests', 'sympy.integrals.tests', 'sympy.interactive.tests', 'sympy.liealgebras.tests', 'sympy.logic.tests', 'sympy.matrices.expressions.tests', 'sympy.matrices.tests', 'sympy.multipledispatch.tests', 'sympy.ntheory.tests', 'sympy.parsing.tests', 'sympy.physics.continuum_mechanics.tests', 'sympy.physics.control.tests', 'sympy.physics.hep.tests', 'sympy.physics.mechanics.tests', 'sympy.physics.optics.tests', 'sympy.physics.quantum.tests', 'sympy.physics.tests', 'sympy.physics.units.tests', 'sympy.physics.vector.tests', 'sympy.plotting.intervalmath.tests', 'sympy.plotting.pygletplot.tests', 'sympy.plotting.tests', 'sympy.polys.agca.tests', 'sympy.polys.domains.tests', 'sympy.polys.matrices.tests', 'sympy.polys.tests', 'sympy.printing.pretty.tests', 'sympy.printing.tests', 'sympy.sandbox.tests', 'sympy.series.tests', 'sympy.sets.tests', 'sympy.simplify.tests', 'sympy.solvers.diophantine.tests', 'sympy.solvers.ode.tests', 'sympy.solvers.tests', 'sympy.stats.sampling.tests', 'sympy.stats.tests', 'sympy.strategies.branch.tests', 'sympy.strategies.tests', 'sympy.tensor.array.expressions.tests', 'sympy.tensor.array.tests', 'sympy.tensor.tests', 'sympy.testing.tests', 'sympy.unify.tests', 'sympy.utilities._compilation.tests', 'sympy.utilities.tests', 'sympy.vector.tests', ] with open(os.path.join(dir_setup, 'sympy', 'release.py')) as f: # Defines __version__ exec(f.read()) if __name__ == '__main__': setup(name='sympy', version=__version__, description='Computer algebra system (CAS) in Python', author='SymPy development team', author_email='sympy@googlegroups.com', license='BSD', keywords="Math CAS", url='https://sympy.org', py_modules=['isympy'], packages=['sympy'] + modules + tests, ext_modules=[], package_data={ 'sympy.utilities.mathml': ['data/*.xsl'], 'sympy.logic.benchmarks': ['input/*.cnf'], 'sympy.parsing.autolev': [ '*.g4', 'test-examples/*.al', 'test-examples/*.py', 'test-examples/pydy-example-repo/*.al', 'test-examples/pydy-example-repo/*.py', 'test-examples/README.txt', ], 'sympy.parsing.latex': ['*.txt', '*.g4'], 'sympy.integrals.rubi.parsetools': ['header.py.txt'], 'sympy.plotting.tests': ['test_region_*.png'], }, data_files=[('share/man/man1', ['doc/man/isympy.1'])], cmdclass={'test': test_sympy, 'bench': run_benchmarks, 'clean': clean, 'audit': audit, 'antlr': antlr, 'sdist': sdist_sympy, }, python_requires='>=3.6', classifiers=[ 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Topic :: Scientific/Engineering', 'Topic :: Scientific/Engineering :: Mathematics', 'Topic :: Scientific/Engineering :: Physics', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3 :: Only', 'Programming Language :: Python :: Implementation :: CPython', 'Programming Language :: Python :: Implementation :: PyPy', ], install_requires=[ 'mpmath>=%s' % min_mpmath_version, ], **extra_kwargs ) sympy-sympy-1.9/setupegg.py000066400000000000000000000000611412543434000161150ustar00rootroot00000000000000import setuptools exec(open('setup.py').read()) sympy-sympy-1.9/sympy/000077500000000000000000000000001412543434000151045ustar00rootroot00000000000000sympy-sympy-1.9/sympy/__init__.py000066400000000000000000000675451412543434000172360ustar00rootroot00000000000000""" SymPy is a Python library for symbolic mathematics. It aims to become a full-featured computer algebra system (CAS) while keeping the code as simple as possible in order to be comprehensible and easily extensible. SymPy is written entirely in Python. It depends on mpmath, and other external libraries may be optionally for things like plotting support. See the webpage for more information and documentation: https://sympy.org """ import sys if sys.version_info < (3, 6): raise ImportError("Python version 3.6 or above is required for SymPy.") del sys try: import mpmath except ImportError: raise ImportError("SymPy now depends on mpmath as an external library. " "See https://docs.sympy.org/latest/install.html#mpmath for more information.") del mpmath from sympy.release import __version__ if 'dev' in __version__: def enable_warnings(): import warnings warnings.filterwarnings('default', '.*', DeprecationWarning, module='sympy.*') del warnings enable_warnings() del enable_warnings def __sympy_debug(): # helper function so we don't import os globally import os debug_str = os.getenv('SYMPY_DEBUG', 'False') if debug_str in ('True', 'False'): return eval(debug_str) else: raise RuntimeError("unrecognized value for SYMPY_DEBUG: %s" % debug_str) SYMPY_DEBUG = __sympy_debug() # type: bool from .core import (sympify, SympifyError, cacheit, Basic, Atom, preorder_traversal, S, Expr, AtomicExpr, UnevaluatedExpr, Symbol, Wild, Dummy, symbols, var, Number, Float, Rational, Integer, NumberSymbol, RealNumber, igcd, ilcm, seterr, E, I, nan, oo, pi, zoo, AlgebraicNumber, comp, mod_inverse, Pow, integer_nthroot, integer_log, Mul, prod, Add, Mod, Rel, Eq, Ne, Lt, Le, Gt, Ge, Equality, GreaterThan, LessThan, Unequality, StrictGreaterThan, StrictLessThan, vectorize, Lambda, WildFunction, Derivative, diff, FunctionClass, Function, Subs, expand, PoleError, count_ops, expand_mul, expand_log, expand_func, expand_trig, expand_complex, expand_multinomial, nfloat, expand_power_base, expand_power_exp, arity, PrecisionExhausted, N, evalf, Tuple, Dict, gcd_terms, factor_terms, factor_nc, evaluate, Catalan, EulerGamma, GoldenRatio, TribonacciConstant) from .logic import (to_cnf, to_dnf, to_nnf, And, Or, Not, Xor, Nand, Nor, Implies, Equivalent, ITE, POSform, SOPform, simplify_logic, bool_map, true, false, satisfiable) from .assumptions import (AppliedPredicate, Predicate, AssumptionsContext, assuming, Q, ask, register_handler, remove_handler, refine) from .polys import (Poly, PurePoly, poly_from_expr, parallel_poly_from_expr, degree, total_degree, degree_list, LC, LM, LT, pdiv, prem, pquo, pexquo, div, rem, quo, exquo, half_gcdex, gcdex, invert, subresultants, resultant, discriminant, cofactors, gcd_list, gcd, lcm_list, lcm, terms_gcd, trunc, monic, content, primitive, compose, decompose, sturm, gff_list, gff, sqf_norm, sqf_part, sqf_list, sqf, factor_list, factor, intervals, refine_root, count_roots, real_roots, nroots, ground_roots, nth_power_roots_poly, cancel, reduced, groebner, is_zero_dimensional, GroebnerBasis, poly, symmetrize, horner, interpolate, rational_interpolate, viete, together, BasePolynomialError, ExactQuotientFailed, PolynomialDivisionFailed, OperationNotSupported, HeuristicGCDFailed, HomomorphismFailed, IsomorphismFailed, ExtraneousFactors, EvaluationFailed, RefinementFailed, CoercionFailed, NotInvertible, NotReversible, NotAlgebraic, DomainError, PolynomialError, UnificationFailed, GeneratorsError, GeneratorsNeeded, ComputationFailed, UnivariatePolynomialError, MultivariatePolynomialError, PolificationFailed, OptionError, FlagError, minpoly, minimal_polynomial, primitive_element, field_isomorphism, to_number_field, isolate, itermonomials, Monomial, lex, grlex, grevlex, ilex, igrlex, igrevlex, CRootOf, rootof, RootOf, ComplexRootOf, RootSum, roots, Domain, FiniteField, IntegerRing, RationalField, RealField, ComplexField, PythonFiniteField, GMPYFiniteField, PythonIntegerRing, GMPYIntegerRing, PythonRational, GMPYRationalField, AlgebraicField, PolynomialRing, FractionField, ExpressionDomain, FF_python, FF_gmpy, ZZ_python, ZZ_gmpy, QQ_python, QQ_gmpy, GF, FF, ZZ, QQ, ZZ_I, QQ_I, RR, CC, EX, EXRAW, construct_domain, swinnerton_dyer_poly, cyclotomic_poly, symmetric_poly, random_poly, interpolating_poly, jacobi_poly, chebyshevt_poly, chebyshevu_poly, hermite_poly, legendre_poly, laguerre_poly, apart, apart_list, assemble_partfrac_list, Options, ring, xring, vring, sring, field, xfield, vfield, sfield) from .series import (Order, O, limit, Limit, gruntz, series, approximants, residue, EmptySequence, SeqPer, SeqFormula, sequence, SeqAdd, SeqMul, fourier_series, fps, difference_delta, limit_seq) from .functions import (factorial, factorial2, rf, ff, binomial, RisingFactorial, FallingFactorial, subfactorial, carmichael, fibonacci, lucas, motzkin, tribonacci, harmonic, bernoulli, bell, euler, catalan, genocchi, partition, sqrt, root, Min, Max, Id, real_root, cbrt, re, im, sign, Abs, conjugate, arg, polar_lift, periodic_argument, unbranched_argument, principal_branch, transpose, adjoint, polarify, unpolarify, sin, cos, tan, sec, csc, cot, sinc, asin, acos, atan, asec, acsc, acot, atan2, exp_polar, exp, ln, log, LambertW, sinh, cosh, tanh, coth, sech, csch, asinh, acosh, atanh, acoth, asech, acsch, floor, ceiling, frac, Piecewise, piecewise_fold, erf, erfc, erfi, erf2, erfinv, erfcinv, erf2inv, Ei, expint, E1, li, Li, Si, Ci, Shi, Chi, fresnels, fresnelc, gamma, lowergamma, uppergamma, polygamma, loggamma, digamma, trigamma, multigamma, dirichlet_eta, zeta, lerchphi, polylog, stieltjes, Eijk, LeviCivita, KroneckerDelta, SingularityFunction, DiracDelta, Heaviside, bspline_basis, bspline_basis_set, interpolating_spline, besselj, bessely, besseli, besselk, hankel1, hankel2, jn, yn, jn_zeros, hn1, hn2, airyai, airybi, airyaiprime, airybiprime, marcumq, hyper, meijerg, appellf1, legendre, assoc_legendre, hermite, chebyshevt, chebyshevu, chebyshevu_root, chebyshevt_root, laguerre, assoc_laguerre, gegenbauer, jacobi, jacobi_normalized, Ynm, Ynm_c, Znm, elliptic_k, elliptic_f, elliptic_e, elliptic_pi, beta, mathieus, mathieuc, mathieusprime, mathieucprime, riemann_xi, betainc, betainc_regularized) from .ntheory import (nextprime, prevprime, prime, primepi, primerange, randprime, Sieve, sieve, primorial, cycle_length, composite, compositepi, isprime, divisors, proper_divisors, factorint, multiplicity, perfect_power, pollard_pm1, pollard_rho, primefactors, totient, trailing, divisor_count, proper_divisor_count, divisor_sigma, factorrat, reduced_totient, primenu, primeomega, mersenne_prime_exponent, is_perfect, is_mersenne_prime, is_abundant, is_deficient, is_amicable, abundance, npartitions, is_primitive_root, is_quad_residue, legendre_symbol, jacobi_symbol, n_order, sqrt_mod, quadratic_residues, primitive_root, nthroot_mod, is_nthpow_residue, sqrt_mod_iter, mobius, discrete_log, quadratic_congruence, binomial_coefficients, binomial_coefficients_list, multinomial_coefficients, continued_fraction_periodic, continued_fraction_iterator, continued_fraction_reduce, continued_fraction_convergents, continued_fraction, egyptian_fraction) from .concrete import product, Product, summation, Sum from .discrete import (fft, ifft, ntt, intt, fwht, ifwht, mobius_transform, inverse_mobius_transform, convolution, covering_product, intersecting_product) from .simplify import (simplify, hypersimp, hypersimilar, logcombine, separatevars, posify, besselsimp, kroneckersimp, signsimp, bottom_up, nsimplify, FU, fu, sqrtdenest, cse, use, epath, EPath, hyperexpand, collect, rcollect, radsimp, collect_const, fraction, numer, denom, trigsimp, exptrigsimp, powsimp, powdenest, combsimp, gammasimp, ratsimp, ratsimpmodprime) from .sets import (Set, Interval, Union, EmptySet, FiniteSet, ProductSet, Intersection, DisjointUnion, imageset, Complement, SymmetricDifference, ImageSet, Range, ComplexRegion, Reals, Contains, ConditionSet, Ordinal, OmegaPower, ord0, PowerSet, Naturals, Naturals0, UniversalSet, Integers, Rationals) from .solvers import (solve, solve_linear_system, solve_linear_system_LU, solve_undetermined_coeffs, nsolve, solve_linear, checksol, det_quick, inv_quick, check_assumptions, failing_assumptions, diophantine, rsolve, rsolve_poly, rsolve_ratio, rsolve_hyper, checkodesol, classify_ode, dsolve, homogeneous_order, solve_poly_system, solve_triangulated, pde_separate, pde_separate_add, pde_separate_mul, pdsolve, classify_pde, checkpdesol, ode_order, reduce_inequalities, reduce_abs_inequality, reduce_abs_inequalities, solve_poly_inequality, solve_rational_inequalities, solve_univariate_inequality, decompogen, solveset, linsolve, linear_eq_to_matrix, nonlinsolve, substitution, Complexes) from .matrices import (ShapeError, NonSquareMatrixError, GramSchmidt, casoratian, diag, eye, hessian, jordan_cell, list2numpy, matrix2numpy, matrix_multiply_elementwise, ones, randMatrix, rot_axis1, rot_axis2, rot_axis3, symarray, wronskian, zeros, MutableDenseMatrix, DeferredVector, MatrixBase, Matrix, MutableMatrix, MutableSparseMatrix, banded, ImmutableDenseMatrix, ImmutableSparseMatrix, ImmutableMatrix, SparseMatrix, MatrixSlice, BlockDiagMatrix, BlockMatrix, FunctionMatrix, Identity, Inverse, MatAdd, MatMul, MatPow, MatrixExpr, MatrixSymbol, Trace, Transpose, ZeroMatrix, OneMatrix, blockcut, block_collapse, matrix_symbols, Adjoint, hadamard_product, HadamardProduct, HadamardPower, Determinant, det, diagonalize_vector, DiagMatrix, DiagonalMatrix, DiagonalOf, trace, DotProduct, kronecker_product, KroneckerProduct, PermutationMatrix, MatrixPermute, Permanent, per) from .geometry import (Point, Point2D, Point3D, Line, Ray, Segment, Line2D, Segment2D, Ray2D, Line3D, Segment3D, Ray3D, Plane, Ellipse, Circle, Polygon, RegularPolygon, Triangle, rad, deg, are_similar, centroid, convex_hull, idiff, intersection, closest_points, farthest_points, GeometryError, Curve, Parabola) from .utilities import (flatten, group, take, subsets, variations, numbered_symbols, cartes, capture, dict_merge, postorder_traversal, interactive_traversal, prefixes, postfixes, sift, topological_sort, unflatten, has_dups, has_variety, reshape, default_sort_key, ordered, rotations, filldedent, lambdify, source, threaded, xthreaded, public, memoize_property, timed) from .integrals import (integrate, Integral, line_integrate, mellin_transform, inverse_mellin_transform, MellinTransform, InverseMellinTransform, laplace_transform, inverse_laplace_transform, LaplaceTransform, InverseLaplaceTransform, fourier_transform, inverse_fourier_transform, FourierTransform, InverseFourierTransform, sine_transform, inverse_sine_transform, SineTransform, InverseSineTransform, cosine_transform, inverse_cosine_transform, CosineTransform, InverseCosineTransform, hankel_transform, inverse_hankel_transform, HankelTransform, InverseHankelTransform, singularityintegrate) from .tensor import (IndexedBase, Idx, Indexed, get_contraction_structure, get_indices, shape, MutableDenseNDimArray, ImmutableDenseNDimArray, MutableSparseNDimArray, ImmutableSparseNDimArray, NDimArray, tensorproduct, tensorcontraction, tensordiagonal, derive_by_array, permutedims, Array, DenseNDimArray, SparseNDimArray) from .parsing import parse_expr from .calculus import (euler_equations, singularities, is_increasing, is_strictly_increasing, is_decreasing, is_strictly_decreasing, is_monotonic, finite_diff_weights, apply_finite_diff, as_finite_diff, differentiate_finite, periodicity, not_empty_in, AccumBounds, is_convex, stationary_points, minimum, maximum) from .algebras import Quaternion from .printing import (pager_print, pretty, pretty_print, pprint, pprint_use_unicode, pprint_try_use_unicode, latex, print_latex, multiline_latex, mathml, print_mathml, python, print_python, pycode, ccode, print_ccode, glsl_code, print_glsl, cxxcode, fcode, print_fcode, rcode, print_rcode, jscode, print_jscode, julia_code, mathematica_code, octave_code, rust_code, print_gtk, preview, srepr, print_tree, StrPrinter, sstr, sstrrepr, TableForm, dotprint, maple_code, print_maple_code) from .testing import test, doctest # This module causes conflicts with other modules: # from .stats import * # Adds about .04-.05 seconds of import time # from combinatorics import * # This module is slow to import: #from physics import units from .plotting import plot, textplot, plot_backends, plot_implicit, plot_parametric from .interactive import init_session, init_printing evalf._create_evalf_table() __all__ = [ # sympy.core 'sympify', 'SympifyError', 'cacheit', 'Basic', 'Atom', 'preorder_traversal', 'S', 'Expr', 'AtomicExpr', 'UnevaluatedExpr', 'Symbol', 'Wild', 'Dummy', 'symbols', 'var', 'Number', 'Float', 'Rational', 'Integer', 'NumberSymbol', 'RealNumber', 'igcd', 'ilcm', 'seterr', 'E', 'I', 'nan', 'oo', 'pi', 'zoo', 'AlgebraicNumber', 'comp', 'mod_inverse', 'Pow', 'integer_nthroot', 'integer_log', 'Mul', 'prod', 'Add', 'Mod', 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', 'Equality', 'GreaterThan', 'LessThan', 'Unequality', 'StrictGreaterThan', 'StrictLessThan', 'vectorize', 'Lambda', 'WildFunction', 'Derivative', 'diff', 'FunctionClass', 'Function', 'Subs', 'expand', 'PoleError', 'count_ops', 'expand_mul', 'expand_log', 'expand_func', 'expand_trig', 'expand_complex', 'expand_multinomial', 'nfloat', 'expand_power_base', 'expand_power_exp', 'arity', 'PrecisionExhausted', 'N', 'evalf', 'Tuple', 'Dict', 'gcd_terms', 'factor_terms', 'factor_nc', 'evaluate', 'Catalan', 'EulerGamma', 'GoldenRatio', 'TribonacciConstant', # sympy.logic 'to_cnf', 'to_dnf', 'to_nnf', 'And', 'Or', 'Not', 'Xor', 'Nand', 'Nor', 'Implies', 'Equivalent', 'ITE', 'POSform', 'SOPform', 'simplify_logic', 'bool_map', 'true', 'false', 'satisfiable', # sympy.assumptions 'AppliedPredicate', 'Predicate', 'AssumptionsContext', 'assuming', 'Q', 'ask', 'register_handler', 'remove_handler', 'refine', # sympy.polys 'Poly', 'PurePoly', 'poly_from_expr', 'parallel_poly_from_expr', 'degree', 'total_degree', 'degree_list', 'LC', 'LM', 'LT', 'pdiv', 'prem', 'pquo', 'pexquo', 'div', 'rem', 'quo', 'exquo', 'half_gcdex', 'gcdex', 'invert', 'subresultants', 'resultant', 'discriminant', 'cofactors', 'gcd_list', 'gcd', 'lcm_list', 'lcm', 'terms_gcd', 'trunc', 'monic', 'content', 'primitive', 'compose', 'decompose', 'sturm', 'gff_list', 'gff', 'sqf_norm', 'sqf_part', 'sqf_list', 'sqf', 'factor_list', 'factor', 'intervals', 'refine_root', 'count_roots', 'real_roots', 'nroots', 'ground_roots', 'nth_power_roots_poly', 'cancel', 'reduced', 'groebner', 'is_zero_dimensional', 'GroebnerBasis', 'poly', 'symmetrize', 'horner', 'interpolate', 'rational_interpolate', 'viete', 'together', 'BasePolynomialError', 'ExactQuotientFailed', 'PolynomialDivisionFailed', 'OperationNotSupported', 'HeuristicGCDFailed', 'HomomorphismFailed', 'IsomorphismFailed', 'ExtraneousFactors', 'EvaluationFailed', 'RefinementFailed', 'CoercionFailed', 'NotInvertible', 'NotReversible', 'NotAlgebraic', 'DomainError', 'PolynomialError', 'UnificationFailed', 'GeneratorsError', 'GeneratorsNeeded', 'ComputationFailed', 'UnivariatePolynomialError', 'MultivariatePolynomialError', 'PolificationFailed', 'OptionError', 'FlagError', 'minpoly', 'minimal_polynomial', 'primitive_element', 'field_isomorphism', 'to_number_field', 'isolate', 'itermonomials', 'Monomial', 'lex', 'grlex', 'grevlex', 'ilex', 'igrlex', 'igrevlex', 'CRootOf', 'rootof', 'RootOf', 'ComplexRootOf', 'RootSum', 'roots', 'Domain', 'FiniteField', 'IntegerRing', 'RationalField', 'RealField', 'ComplexField', 'PythonFiniteField', 'GMPYFiniteField', 'PythonIntegerRing', 'GMPYIntegerRing', 'PythonRational', 'GMPYRationalField', 'AlgebraicField', 'PolynomialRing', 'FractionField', 'ExpressionDomain', 'FF_python', 'FF_gmpy', 'ZZ_python', 'ZZ_gmpy', 'QQ_python', 'QQ_gmpy', 'GF', 'FF', 'ZZ', 'QQ', 'ZZ_I', 'QQ_I', 'RR', 'CC', 'EX', 'EXRAW', 'construct_domain', 'swinnerton_dyer_poly', 'cyclotomic_poly', 'symmetric_poly', 'random_poly', 'interpolating_poly', 'jacobi_poly', 'chebyshevt_poly', 'chebyshevu_poly', 'hermite_poly', 'legendre_poly', 'laguerre_poly', 'apart', 'apart_list', 'assemble_partfrac_list', 'Options', 'ring', 'xring', 'vring', 'sring', 'field', 'xfield', 'vfield', 'sfield', # sympy.series 'Order', 'O', 'limit', 'Limit', 'gruntz', 'series', 'approximants', 'residue', 'EmptySequence', 'SeqPer', 'SeqFormula', 'sequence', 'SeqAdd', 'SeqMul', 'fourier_series', 'fps', 'difference_delta', 'limit_seq', # sympy.functions 'factorial', 'factorial2', 'rf', 'ff', 'binomial', 'RisingFactorial', 'FallingFactorial', 'subfactorial', 'carmichael', 'fibonacci', 'lucas', 'motzkin', 'tribonacci', 'harmonic', 'bernoulli', 'bell', 'euler', 'catalan', 'genocchi', 'partition', 'sqrt', 'root', 'Min', 'Max', 'Id', 'real_root', 'cbrt', 're', 'im', 'sign', 'Abs', 'conjugate', 'arg', 'polar_lift', 'periodic_argument', 'unbranched_argument', 'principal_branch', 'transpose', 'adjoint', 'polarify', 'unpolarify', 'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinc', 'asin', 'acos', 'atan', 'asec', 'acsc', 'acot', 'atan2', 'exp_polar', 'exp', 'ln', 'log', 'LambertW', 'sinh', 'cosh', 'tanh', 'coth', 'sech', 'csch', 'asinh', 'acosh', 'atanh', 'acoth', 'asech', 'acsch', 'floor', 'ceiling', 'frac', 'Piecewise', 'piecewise_fold', 'erf', 'erfc', 'erfi', 'erf2', 'erfinv', 'erfcinv', 'erf2inv', 'Ei', 'expint', 'E1', 'li', 'Li', 'Si', 'Ci', 'Shi', 'Chi', 'fresnels', 'fresnelc', 'gamma', 'lowergamma', 'uppergamma', 'polygamma', 'loggamma', 'digamma', 'trigamma', 'multigamma', 'dirichlet_eta', 'zeta', 'lerchphi', 'polylog', 'stieltjes', 'Eijk', 'LeviCivita', 'KroneckerDelta', 'SingularityFunction', 'DiracDelta', 'Heaviside', 'bspline_basis', 'bspline_basis_set', 'interpolating_spline', 'besselj', 'bessely', 'besseli', 'besselk', 'hankel1', 'hankel2', 'jn', 'yn', 'jn_zeros', 'hn1', 'hn2', 'airyai', 'airybi', 'airyaiprime', 'airybiprime', 'marcumq', 'hyper', 'meijerg', 'appellf1', 'legendre', 'assoc_legendre', 'hermite', 'chebyshevt', 'chebyshevu', 'chebyshevu_root', 'chebyshevt_root', 'laguerre', 'assoc_laguerre', 'gegenbauer', 'jacobi', 'jacobi_normalized', 'Ynm', 'Ynm_c', 'Znm', 'elliptic_k', 'elliptic_f', 'elliptic_e', 'elliptic_pi', 'beta', 'mathieus', 'mathieuc', 'mathieusprime', 'mathieucprime', 'riemann_xi','betainc', 'betainc_regularized', # sympy.ntheory 'nextprime', 'prevprime', 'prime', 'primepi', 'primerange', 'randprime', 'Sieve', 'sieve', 'primorial', 'cycle_length', 'composite', 'compositepi', 'isprime', 'divisors', 'proper_divisors', 'factorint', 'multiplicity', 'perfect_power', 'pollard_pm1', 'pollard_rho', 'primefactors', 'totient', 'trailing', 'divisor_count', 'proper_divisor_count', 'divisor_sigma', 'factorrat', 'reduced_totient', 'primenu', 'primeomega', 'mersenne_prime_exponent', 'is_perfect', 'is_mersenne_prime', 'is_abundant', 'is_deficient', 'is_amicable', 'abundance', 'npartitions', 'is_primitive_root', 'is_quad_residue', 'legendre_symbol', 'jacobi_symbol', 'n_order', 'sqrt_mod', 'quadratic_residues', 'primitive_root', 'nthroot_mod', 'is_nthpow_residue', 'sqrt_mod_iter', 'mobius', 'discrete_log', 'quadratic_congruence', 'binomial_coefficients', 'binomial_coefficients_list', 'multinomial_coefficients', 'continued_fraction_periodic', 'continued_fraction_iterator', 'continued_fraction_reduce', 'continued_fraction_convergents', 'continued_fraction', 'egyptian_fraction', # sympy.concrete 'product', 'Product', 'summation', 'Sum', # sympy.discrete 'fft', 'ifft', 'ntt', 'intt', 'fwht', 'ifwht', 'mobius_transform', 'inverse_mobius_transform', 'convolution', 'covering_product', 'intersecting_product', # sympy.simplify 'simplify', 'hypersimp', 'hypersimilar', 'logcombine', 'separatevars', 'posify', 'besselsimp', 'kroneckersimp', 'signsimp', 'bottom_up', 'nsimplify', 'FU', 'fu', 'sqrtdenest', 'cse', 'use', 'epath', 'EPath', 'hyperexpand', 'collect', 'rcollect', 'radsimp', 'collect_const', 'fraction', 'numer', 'denom', 'trigsimp', 'exptrigsimp', 'powsimp', 'powdenest', 'combsimp', 'gammasimp', 'ratsimp', 'ratsimpmodprime', # sympy.sets 'Set', 'Interval', 'Union', 'EmptySet', 'FiniteSet', 'ProductSet', 'Intersection', 'imageset', 'DisjointUnion', 'Complement', 'SymmetricDifference', 'ImageSet', 'Range', 'ComplexRegion', 'Reals', 'Contains', 'ConditionSet', 'Ordinal', 'OmegaPower', 'ord0', 'PowerSet', 'Reals', 'Naturals', 'Naturals0', 'UniversalSet', 'Integers', 'Rationals', # sympy.solvers 'solve', 'solve_linear_system', 'solve_linear_system_LU', 'solve_undetermined_coeffs', 'nsolve', 'solve_linear', 'checksol', 'det_quick', 'inv_quick', 'check_assumptions', 'failing_assumptions', 'diophantine', 'rsolve', 'rsolve_poly', 'rsolve_ratio', 'rsolve_hyper', 'checkodesol', 'classify_ode', 'dsolve', 'homogeneous_order', 'solve_poly_system', 'solve_triangulated', 'pde_separate', 'pde_separate_add', 'pde_separate_mul', 'pdsolve', 'classify_pde', 'checkpdesol', 'ode_order', 'reduce_inequalities', 'reduce_abs_inequality', 'reduce_abs_inequalities', 'solve_poly_inequality', 'solve_rational_inequalities', 'solve_univariate_inequality', 'decompogen', 'solveset', 'linsolve', 'linear_eq_to_matrix', 'nonlinsolve', 'substitution', 'Complexes', # sympy.matrices 'ShapeError', 'NonSquareMatrixError', 'GramSchmidt', 'casoratian', 'diag', 'eye', 'hessian', 'jordan_cell', 'list2numpy', 'matrix2numpy', 'matrix_multiply_elementwise', 'ones', 'randMatrix', 'rot_axis1', 'rot_axis2', 'rot_axis3', 'symarray', 'wronskian', 'zeros', 'MutableDenseMatrix', 'DeferredVector', 'MatrixBase', 'Matrix', 'MutableMatrix', 'MutableSparseMatrix', 'banded', 'ImmutableDenseMatrix', 'ImmutableSparseMatrix', 'ImmutableMatrix', 'SparseMatrix', 'MatrixSlice', 'BlockDiagMatrix', 'BlockMatrix', 'FunctionMatrix', 'Identity', 'Inverse', 'MatAdd', 'MatMul', 'MatPow', 'MatrixExpr', 'MatrixSymbol', 'Trace', 'Transpose', 'ZeroMatrix', 'OneMatrix', 'blockcut', 'block_collapse', 'matrix_symbols', 'Adjoint', 'hadamard_product', 'HadamardProduct', 'HadamardPower', 'Determinant', 'det', 'diagonalize_vector', 'DiagMatrix', 'DiagonalMatrix', 'DiagonalOf', 'trace', 'DotProduct', 'kronecker_product', 'KroneckerProduct', 'PermutationMatrix', 'MatrixPermute', 'Permanent', 'per', # sympy.geometry 'Point', 'Point2D', 'Point3D', 'Line', 'Ray', 'Segment', 'Line2D', 'Segment2D', 'Ray2D', 'Line3D', 'Segment3D', 'Ray3D', 'Plane', 'Ellipse', 'Circle', 'Polygon', 'RegularPolygon', 'Triangle', 'rad', 'deg', 'are_similar', 'centroid', 'convex_hull', 'idiff', 'intersection', 'closest_points', 'farthest_points', 'GeometryError', 'Curve', 'Parabola', # sympy.utilities 'flatten', 'group', 'take', 'subsets', 'variations', 'numbered_symbols', 'cartes', 'capture', 'dict_merge', 'postorder_traversal', 'interactive_traversal', 'prefixes', 'postfixes', 'sift', 'topological_sort', 'unflatten', 'has_dups', 'has_variety', 'reshape', 'default_sort_key', 'ordered', 'rotations', 'filldedent', 'lambdify', 'source', 'threaded', 'xthreaded', 'public', 'memoize_property', 'test', 'doctest', 'timed', # sympy.integrals 'integrate', 'Integral', 'line_integrate', 'mellin_transform', 'inverse_mellin_transform', 'MellinTransform', 'InverseMellinTransform', 'laplace_transform', 'inverse_laplace_transform', 'LaplaceTransform', 'InverseLaplaceTransform', 'fourier_transform', 'inverse_fourier_transform', 'FourierTransform', 'InverseFourierTransform', 'sine_transform', 'inverse_sine_transform', 'SineTransform', 'InverseSineTransform', 'cosine_transform', 'inverse_cosine_transform', 'CosineTransform', 'InverseCosineTransform', 'hankel_transform', 'inverse_hankel_transform', 'HankelTransform', 'InverseHankelTransform', 'singularityintegrate', # sympy.tensor 'IndexedBase', 'Idx', 'Indexed', 'get_contraction_structure', 'get_indices', 'shape', 'MutableDenseNDimArray', 'ImmutableDenseNDimArray', 'MutableSparseNDimArray', 'ImmutableSparseNDimArray', 'NDimArray', 'tensorproduct', 'tensorcontraction', 'tensordiagonal', 'derive_by_array', 'permutedims', 'Array', 'DenseNDimArray', 'SparseNDimArray', # sympy.parsing 'parse_expr', # sympy.calculus 'euler_equations', 'singularities', 'is_increasing', 'is_strictly_increasing', 'is_decreasing', 'is_strictly_decreasing', 'is_monotonic', 'finite_diff_weights', 'apply_finite_diff', 'as_finite_diff', 'differentiate_finite', 'periodicity', 'not_empty_in', 'AccumBounds', 'is_convex', 'stationary_points', 'minimum', 'maximum', # sympy.algebras 'Quaternion', # sympy.printing 'pager_print', 'pretty', 'pretty_print', 'pprint', 'pprint_use_unicode', 'pprint_try_use_unicode', 'latex', 'print_latex', 'multiline_latex', 'mathml', 'print_mathml', 'python', 'print_python', 'pycode', 'ccode', 'print_ccode', 'glsl_code', 'print_glsl', 'cxxcode', 'fcode', 'print_fcode', 'rcode', 'print_rcode', 'jscode', 'print_jscode', 'julia_code', 'mathematica_code', 'octave_code', 'rust_code', 'print_gtk', 'preview', 'srepr', 'print_tree', 'StrPrinter', 'sstr', 'sstrrepr', 'TableForm', 'dotprint', 'maple_code', 'print_maple_code', # sympy.plotting 'plot', 'textplot', 'plot_backends', 'plot_implicit', 'plot_parametric', # sympy.interactive 'init_session', 'init_printing', # sympy.testing 'test', 'doctest', ] #===========================================================================# # # # XXX: The names below were importable before sympy 1.6 using # # # # from sympy import * # # # # This happened implicitly because there was no __all__ defined in this # # __init__.py file. Not every package is imported. The list matches what # # would have been imported before. It is possible that these packages will # # not be imported by a star-import from sympy in future. # # # #===========================================================================# __all__.extend([ 'algebras', 'assumptions', 'calculus', 'concrete', 'discrete', 'external', 'functions', 'geometry', 'interactive', 'multipledispatch', 'ntheory', 'parsing', 'plotting', 'polys', 'printing', 'release', 'strategies', 'tensor', 'utilities', ]) sympy-sympy-1.9/sympy/abc.py000066400000000000000000000071161412543434000162100ustar00rootroot00000000000000""" This module exports all latin and greek letters as Symbols, so you can conveniently do >>> from sympy.abc import x, y instead of the slightly more clunky-looking >>> from sympy import symbols >>> x, y = symbols('x y') Caveats ======= 1. As of the time of writing this, the names ``O``, ``S``, ``I``, ``N``, ``E``, and ``Q`` are colliding with names defined in SymPy. If you import them from both ``sympy.abc`` and ``sympy``, the second import will "win". This is an issue only for * imports, which should only be used for short-lived code such as interactive sessions and throwaway scripts that do not survive until the next SymPy upgrade, where ``sympy`` may contain a different set of names. 2. This module does not define symbol names on demand, i.e. ``from sympy.abc import foo`` will be reported as an error because ``sympy.abc`` does not contain the name ``foo``. To get a symbol named ``foo``, you still need to use ``Symbol('foo')`` or ``symbols('foo')``. You can freely mix usage of ``sympy.abc`` and ``Symbol``/``symbols``, though sticking with one and only one way to get the symbols does tend to make the code more readable. The module also defines some special names to help detect which names clash with the default SymPy namespace. ``_clash1`` defines all the single letter variables that clash with SymPy objects; ``_clash2`` defines the multi-letter clashing symbols; and ``_clash`` is the union of both. These can be passed for ``locals`` during sympification if one desires Symbols rather than the non-Symbol objects for those names. Examples ======== >>> from sympy import S >>> from sympy.abc import _clash1, _clash2, _clash >>> S("Q & C", locals=_clash1) C & Q >>> S('pi(x)', locals=_clash2) pi(x) >>> S('pi(C, Q)', locals=_clash) pi(C, Q) """ from typing import Any, Dict import string from .core import Symbol, symbols from .core.alphabets import greeks ##### Symbol definitions ##### # Implementation note: The easiest way to avoid typos in the symbols() # parameter is to copy it from the left-hand side of the assignment. a, b, c, d, e, f, g, h, i, j = symbols('a, b, c, d, e, f, g, h, i, j') k, l, m, n, o, p, q, r, s, t = symbols('k, l, m, n, o, p, q, r, s, t') u, v, w, x, y, z = symbols('u, v, w, x, y, z') A, B, C, D, E, F, G, H, I, J = symbols('A, B, C, D, E, F, G, H, I, J') K, L, M, N, O, P, Q, R, S, T = symbols('K, L, M, N, O, P, Q, R, S, T') U, V, W, X, Y, Z = symbols('U, V, W, X, Y, Z') alpha, beta, gamma, delta = symbols('alpha, beta, gamma, delta') epsilon, zeta, eta, theta = symbols('epsilon, zeta, eta, theta') iota, kappa, lamda, mu = symbols('iota, kappa, lamda, mu') nu, xi, omicron, pi = symbols('nu, xi, omicron, pi') rho, sigma, tau, upsilon = symbols('rho, sigma, tau, upsilon') phi, chi, psi, omega = symbols('phi, chi, psi, omega') ##### Clashing-symbols diagnostics ##### # We want to know which names in SymPy collide with those in here. # This is mostly for diagnosing SymPy's namespace during SymPy development. _latin = list(string.ascii_letters) # OSINEQ should not be imported as they clash; gamma, pi and zeta clash, too _greek = list(greeks) # make a copy, so we can mutate it # Note: We import lamda since lambda is a reserved keyword in Python _greek.remove("lambda") _greek.append("lamda") ns = {} # type: Dict[str, Any] exec('from sympy import *', ns) _clash1 = {} _clash2 = {} while ns: _k, _ = ns.popitem() if _k in _greek: _clash2[_k] = None _greek.remove(_k) elif _k in _latin: _clash1[_k] = None _latin.remove(_k) _clash = {} _clash.update(_clash1) _clash.update(_clash2) del _latin, _greek, Symbol, _k sympy-sympy-1.9/sympy/algebras/000077500000000000000000000000001412543434000166645ustar00rootroot00000000000000sympy-sympy-1.9/sympy/algebras/__init__.py000066400000000000000000000000761412543434000210000ustar00rootroot00000000000000from .quaternion import Quaternion __all__ = ["Quaternion",] sympy-sympy-1.9/sympy/algebras/quaternion.py000066400000000000000000000523271412543434000214340ustar00rootroot00000000000000# References : # http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/ # https://en.wikipedia.org/wiki/Quaternion from sympy import S, Rational from sympy import re, im, conjugate, sign from sympy import sqrt, sin, cos, acos, exp, ln from sympy import trigsimp from sympy import integrate from sympy import Matrix from sympy import sympify from sympy.core.evalf import prec_to_dps from sympy.core.expr import Expr class Quaternion(Expr): """Provides basic quaternion operations. Quaternion objects can be instantiated as Quaternion(a, b, c, d) as in (a + b*i + c*j + d*k). Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> q = Quaternion(1, 2, 3, 4) >>> q 1 + 2*i + 3*j + 4*k Quaternions over complex fields can be defined as : >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import symbols, I >>> x = symbols('x') >>> q1 = Quaternion(x, x**3, x, x**2, real_field = False) >>> q2 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) >>> q1 x + x**3*i + x*j + x**2*k >>> q2 (3 + 4*I) + (2 + 5*I)*i + 0*j + (7 + 8*I)*k """ _op_priority = 11.0 is_commutative = False def __new__(cls, a=0, b=0, c=0, d=0, real_field=True): a = sympify(a) b = sympify(b) c = sympify(c) d = sympify(d) if any(i.is_commutative is False for i in [a, b, c, d]): raise ValueError("arguments have to be commutative") else: obj = Expr.__new__(cls, a, b, c, d) obj._a = a obj._b = b obj._c = c obj._d = d obj._real_field = real_field return obj @property def a(self): return self._a @property def b(self): return self._b @property def c(self): return self._c @property def d(self): return self._d @property def real_field(self): return self._real_field @classmethod def from_axis_angle(cls, vector, angle): """Returns a rotation quaternion given the axis and the angle of rotation. Parameters ========== vector : tuple of three numbers The vector representation of the given axis. angle : number The angle by which axis is rotated (in radians). Returns ======= Quaternion The normalized rotation quaternion calculated from the given axis and the angle of rotation. Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import pi, sqrt >>> q = Quaternion.from_axis_angle((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), 2*pi/3) >>> q 1/2 + 1/2*i + 1/2*j + 1/2*k """ (x, y, z) = vector norm = sqrt(x**2 + y**2 + z**2) (x, y, z) = (x / norm, y / norm, z / norm) s = sin(angle * S.Half) a = cos(angle * S.Half) b = x * s c = y * s d = z * s # note that this quaternion is already normalized by construction: # c^2 + (s*x)^2 + (s*y)^2 + (s*z)^2 = c^2 + s^2*(x^2 + y^2 + z^2) = c^2 + s^2 * 1 = c^2 + s^2 = 1 # so, what we return is a normalized quaternion return cls(a, b, c, d) @classmethod def from_rotation_matrix(cls, M): """Returns the equivalent quaternion of a matrix. The quaternion will be normalized only if the matrix is special orthogonal (orthogonal and det(M) = 1). Parameters ========== M : Matrix Input matrix to be converted to equivalent quaternion. M must be special orthogonal (orthogonal and det(M) = 1) for the quaternion to be normalized. Returns ======= Quaternion The quaternion equivalent to given matrix. Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import Matrix, symbols, cos, sin, trigsimp >>> x = symbols('x') >>> M = Matrix([[cos(x), -sin(x), 0], [sin(x), cos(x), 0], [0, 0, 1]]) >>> q = trigsimp(Quaternion.from_rotation_matrix(M)) >>> q sqrt(2)*sqrt(cos(x) + 1)/2 + 0*i + 0*j + sqrt(2 - 2*cos(x))*sign(sin(x))/2*k """ absQ = M.det()**Rational(1, 3) a = sqrt(absQ + M[0, 0] + M[1, 1] + M[2, 2]) / 2 b = sqrt(absQ + M[0, 0] - M[1, 1] - M[2, 2]) / 2 c = sqrt(absQ - M[0, 0] + M[1, 1] - M[2, 2]) / 2 d = sqrt(absQ - M[0, 0] - M[1, 1] + M[2, 2]) / 2 b = b * sign(M[2, 1] - M[1, 2]) c = c * sign(M[0, 2] - M[2, 0]) d = d * sign(M[1, 0] - M[0, 1]) return Quaternion(a, b, c, d) def __add__(self, other): return self.add(other) def __radd__(self, other): return self.add(other) def __sub__(self, other): return self.add(other*-1) def __mul__(self, other): return self._generic_mul(self, other) def __rmul__(self, other): return self._generic_mul(other, self) def __pow__(self, p): return self.pow(p) def __neg__(self): return Quaternion(-self._a, -self._b, -self._c, -self.d) def __truediv__(self, other): return self * sympify(other)**-1 def __rtruediv__(self, other): return sympify(other) * self**-1 def _eval_Integral(self, *args): return self.integrate(*args) def diff(self, *symbols, **kwargs): kwargs.setdefault('evaluate', True) return self.func(*[a.diff(*symbols, **kwargs) for a in self.args]) def add(self, other): """Adds quaternions. Parameters ========== other : Quaternion The quaternion to add to current (self) quaternion. Returns ======= Quaternion The resultant quaternion after adding self to other Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import symbols >>> q1 = Quaternion(1, 2, 3, 4) >>> q2 = Quaternion(5, 6, 7, 8) >>> q1.add(q2) 6 + 8*i + 10*j + 12*k >>> q1 + 5 6 + 2*i + 3*j + 4*k >>> x = symbols('x', real = True) >>> q1.add(x) (x + 1) + 2*i + 3*j + 4*k Quaternions over complex fields : >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import I >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) >>> q3.add(2 + 3*I) (5 + 7*I) + (2 + 5*I)*i + 0*j + (7 + 8*I)*k """ q1 = self q2 = sympify(other) # If q2 is a number or a sympy expression instead of a quaternion if not isinstance(q2, Quaternion): if q1.real_field and q2.is_complex: return Quaternion(re(q2) + q1.a, im(q2) + q1.b, q1.c, q1.d) elif q2.is_commutative: return Quaternion(q1.a + q2, q1.b, q1.c, q1.d) else: raise ValueError("Only commutative expressions can be added with a Quaternion.") return Quaternion(q1.a + q2.a, q1.b + q2.b, q1.c + q2.c, q1.d + q2.d) def mul(self, other): """Multiplies quaternions. Parameters ========== other : Quaternion or symbol The quaternion to multiply to current (self) quaternion. Returns ======= Quaternion The resultant quaternion after multiplying self with other Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import symbols >>> q1 = Quaternion(1, 2, 3, 4) >>> q2 = Quaternion(5, 6, 7, 8) >>> q1.mul(q2) (-60) + 12*i + 30*j + 24*k >>> q1.mul(2) 2 + 4*i + 6*j + 8*k >>> x = symbols('x', real = True) >>> q1.mul(x) x + 2*x*i + 3*x*j + 4*x*k Quaternions over complex fields : >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import I >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) >>> q3.mul(2 + 3*I) (2 + 3*I)*(3 + 4*I) + (2 + 3*I)*(2 + 5*I)*i + 0*j + (2 + 3*I)*(7 + 8*I)*k """ return self._generic_mul(self, other) @staticmethod def _generic_mul(q1, q2): """Generic multiplication. Parameters ========== q1 : Quaternion or symbol q2 : Quaternion or symbol It's important to note that if neither q1 nor q2 is a Quaternion, this function simply returns q1 * q2. Returns ======= Quaternion The resultant quaternion after multiplying q1 and q2 Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import Symbol >>> q1 = Quaternion(1, 2, 3, 4) >>> q2 = Quaternion(5, 6, 7, 8) >>> Quaternion._generic_mul(q1, q2) (-60) + 12*i + 30*j + 24*k >>> Quaternion._generic_mul(q1, 2) 2 + 4*i + 6*j + 8*k >>> x = Symbol('x', real = True) >>> Quaternion._generic_mul(q1, x) x + 2*x*i + 3*x*j + 4*x*k Quaternions over complex fields : >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import I >>> q3 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) >>> Quaternion._generic_mul(q3, 2 + 3*I) (2 + 3*I)*(3 + 4*I) + (2 + 3*I)*(2 + 5*I)*i + 0*j + (2 + 3*I)*(7 + 8*I)*k """ q1 = sympify(q1) q2 = sympify(q2) # None is a Quaternion: if not isinstance(q1, Quaternion) and not isinstance(q2, Quaternion): return q1 * q2 # If q1 is a number or a sympy expression instead of a quaternion if not isinstance(q1, Quaternion): if q2.real_field and q1.is_complex: return Quaternion(re(q1), im(q1), 0, 0) * q2 elif q1.is_commutative: return Quaternion(q1 * q2.a, q1 * q2.b, q1 * q2.c, q1 * q2.d) else: raise ValueError("Only commutative expressions can be multiplied with a Quaternion.") # If q2 is a number or a sympy expression instead of a quaternion if not isinstance(q2, Quaternion): if q1.real_field and q2.is_complex: return q1 * Quaternion(re(q2), im(q2), 0, 0) elif q2.is_commutative: return Quaternion(q2 * q1.a, q2 * q1.b, q2 * q1.c, q2 * q1.d) else: raise ValueError("Only commutative expressions can be multiplied with a Quaternion.") return Quaternion(-q1.b*q2.b - q1.c*q2.c - q1.d*q2.d + q1.a*q2.a, q1.b*q2.a + q1.c*q2.d - q1.d*q2.c + q1.a*q2.b, -q1.b*q2.d + q1.c*q2.a + q1.d*q2.b + q1.a*q2.c, q1.b*q2.c - q1.c*q2.b + q1.d*q2.a + q1.a * q2.d) def _eval_conjugate(self): """Returns the conjugate of the quaternion.""" q = self return Quaternion(q.a, -q.b, -q.c, -q.d) def norm(self): """Returns the norm of the quaternion.""" q = self # trigsimp is used to simplify sin(x)^2 + cos(x)^2 (these terms # arise when from_axis_angle is used). return sqrt(trigsimp(q.a**2 + q.b**2 + q.c**2 + q.d**2)) def normalize(self): """Returns the normalized form of the quaternion.""" q = self return q * (1/q.norm()) def inverse(self): """Returns the inverse of the quaternion.""" q = self if not q.norm(): raise ValueError("Cannot compute inverse for a quaternion with zero norm") return conjugate(q) * (1/q.norm()**2) def pow(self, p): """Finds the pth power of the quaternion. Parameters ========== p : int Power to be applied on quaternion. Returns ======= Quaternion Returns the p-th power of the current quaternion. Returns the inverse if p = -1. Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> q = Quaternion(1, 2, 3, 4) >>> q.pow(4) 668 + (-224)*i + (-336)*j + (-448)*k """ p = sympify(p) q = self if p == -1: return q.inverse() res = 1 if not p.is_Integer: return NotImplemented if p < 0: q, p = q.inverse(), -p while p > 0: if p % 2 == 1: res = q * res p = p//2 q = q * q return res def exp(self): """Returns the exponential of q (e^q). Returns ======= Quaternion Exponential of q (e^q). Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> q = Quaternion(1, 2, 3, 4) >>> q.exp() E*cos(sqrt(29)) + 2*sqrt(29)*E*sin(sqrt(29))/29*i + 3*sqrt(29)*E*sin(sqrt(29))/29*j + 4*sqrt(29)*E*sin(sqrt(29))/29*k """ # exp(q) = e^a(cos||v|| + v/||v||*sin||v||) q = self vector_norm = sqrt(q.b**2 + q.c**2 + q.d**2) a = exp(q.a) * cos(vector_norm) b = exp(q.a) * sin(vector_norm) * q.b / vector_norm c = exp(q.a) * sin(vector_norm) * q.c / vector_norm d = exp(q.a) * sin(vector_norm) * q.d / vector_norm return Quaternion(a, b, c, d) def _ln(self): """Returns the natural logarithm of the quaternion (_ln(q)). Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> q = Quaternion(1, 2, 3, 4) >>> q._ln() log(sqrt(30)) + 2*sqrt(29)*acos(sqrt(30)/30)/29*i + 3*sqrt(29)*acos(sqrt(30)/30)/29*j + 4*sqrt(29)*acos(sqrt(30)/30)/29*k """ # _ln(q) = _ln||q|| + v/||v||*arccos(a/||q||) q = self vector_norm = sqrt(q.b**2 + q.c**2 + q.d**2) q_norm = q.norm() a = ln(q_norm) b = q.b * acos(q.a / q_norm) / vector_norm c = q.c * acos(q.a / q_norm) / vector_norm d = q.d * acos(q.a / q_norm) / vector_norm return Quaternion(a, b, c, d) def _eval_evalf(self, prec): """Returns the floating point approximations (decimal numbers) of the quaternion. Returns ======= Quaternion Floating point approximations of quaternion(self) Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import sqrt >>> q = Quaternion(1/sqrt(1), 1/sqrt(2), 1/sqrt(3), 1/sqrt(4)) >>> q.evalf() 1.00000000000000 + 0.707106781186547*i + 0.577350269189626*j + 0.500000000000000*k """ return Quaternion(*[arg.evalf(n=prec_to_dps(prec)) for arg in self.args]) def pow_cos_sin(self, p): """Computes the pth power in the cos-sin form. Parameters ========== p : int Power to be applied on quaternion. Returns ======= Quaternion The p-th power in the cos-sin form. Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> q = Quaternion(1, 2, 3, 4) >>> q.pow_cos_sin(4) 900*cos(4*acos(sqrt(30)/30)) + 1800*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*i + 2700*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*j + 3600*sqrt(29)*sin(4*acos(sqrt(30)/30))/29*k """ # q = ||q||*(cos(a) + u*sin(a)) # q^p = ||q||^p * (cos(p*a) + u*sin(p*a)) q = self (v, angle) = q.to_axis_angle() q2 = Quaternion.from_axis_angle(v, p * angle) return q2 * (q.norm()**p) def integrate(self, *args): """Computes integration of quaternion. Returns ======= Quaternion Integration of the quaternion(self) with the given variable. Examples ======== Indefinite Integral of quaternion : >>> from sympy.algebras.quaternion import Quaternion >>> from sympy.abc import x >>> q = Quaternion(1, 2, 3, 4) >>> q.integrate(x) x + 2*x*i + 3*x*j + 4*x*k Definite integral of quaternion : >>> from sympy.algebras.quaternion import Quaternion >>> from sympy.abc import x >>> q = Quaternion(1, 2, 3, 4) >>> q.integrate((x, 1, 5)) 4 + 8*i + 12*j + 16*k """ # TODO: is this expression correct? return Quaternion(integrate(self.a, *args), integrate(self.b, *args), integrate(self.c, *args), integrate(self.d, *args)) @staticmethod def rotate_point(pin, r): """Returns the coordinates of the point pin(a 3 tuple) after rotation. Parameters ========== pin : tuple A 3-element tuple of coordinates of a point which needs to be rotated. r : Quaternion or tuple Axis and angle of rotation. It's important to note that when r is a tuple, it must be of the form (axis, angle) Returns ======= tuple The coordinates of the point after rotation. Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import symbols, trigsimp, cos, sin >>> x = symbols('x') >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2)) >>> trigsimp(Quaternion.rotate_point((1, 1, 1), q)) (sqrt(2)*cos(x + pi/4), sqrt(2)*sin(x + pi/4), 1) >>> (axis, angle) = q.to_axis_angle() >>> trigsimp(Quaternion.rotate_point((1, 1, 1), (axis, angle))) (sqrt(2)*cos(x + pi/4), sqrt(2)*sin(x + pi/4), 1) """ if isinstance(r, tuple): # if r is of the form (vector, angle) q = Quaternion.from_axis_angle(r[0], r[1]) else: # if r is a quaternion q = r.normalize() pout = q * Quaternion(0, pin[0], pin[1], pin[2]) * conjugate(q) return (pout.b, pout.c, pout.d) def to_axis_angle(self): """Returns the axis and angle of rotation of a quaternion Returns ======= tuple Tuple of (axis, angle) Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> q = Quaternion(1, 1, 1, 1) >>> (axis, angle) = q.to_axis_angle() >>> axis (sqrt(3)/3, sqrt(3)/3, sqrt(3)/3) >>> angle 2*pi/3 """ q = self if q.a.is_negative: q = q * -1 q = q.normalize() angle = trigsimp(2 * acos(q.a)) # Since quaternion is normalised, q.a is less than 1. s = sqrt(1 - q.a*q.a) x = trigsimp(q.b / s) y = trigsimp(q.c / s) z = trigsimp(q.d / s) v = (x, y, z) t = (v, angle) return t def to_rotation_matrix(self, v=None): """Returns the equivalent rotation transformation matrix of the quaternion which represents rotation about the origin if v is not passed. Parameters ========== v : tuple or None Default value: None Returns ======= tuple Returns the equivalent rotation transformation matrix of the quaternion which represents rotation about the origin if v is not passed. Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import symbols, trigsimp, cos, sin >>> x = symbols('x') >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2)) >>> trigsimp(q.to_rotation_matrix()) Matrix([ [cos(x), -sin(x), 0], [sin(x), cos(x), 0], [ 0, 0, 1]]) Generates a 4x4 transformation matrix (used for rotation about a point other than the origin) if the point(v) is passed as an argument. Examples ======== >>> from sympy.algebras.quaternion import Quaternion >>> from sympy import symbols, trigsimp, cos, sin >>> x = symbols('x') >>> q = Quaternion(cos(x/2), 0, 0, sin(x/2)) >>> trigsimp(q.to_rotation_matrix((1, 1, 1))) Matrix([ [cos(x), -sin(x), 0, sin(x) - cos(x) + 1], [sin(x), cos(x), 0, -sin(x) - cos(x) + 1], [ 0, 0, 1, 0], [ 0, 0, 0, 1]]) """ q = self s = q.norm()**-2 m00 = 1 - 2*s*(q.c**2 + q.d**2) m01 = 2*s*(q.b*q.c - q.d*q.a) m02 = 2*s*(q.b*q.d + q.c*q.a) m10 = 2*s*(q.b*q.c + q.d*q.a) m11 = 1 - 2*s*(q.b**2 + q.d**2) m12 = 2*s*(q.c*q.d - q.b*q.a) m20 = 2*s*(q.b*q.d - q.c*q.a) m21 = 2*s*(q.c*q.d + q.b*q.a) m22 = 1 - 2*s*(q.b**2 + q.c**2) if not v: return Matrix([[m00, m01, m02], [m10, m11, m12], [m20, m21, m22]]) else: (x, y, z) = v m03 = x - x*m00 - y*m01 - z*m02 m13 = y - x*m10 - y*m11 - z*m12 m23 = z - x*m20 - y*m21 - z*m22 m30 = m31 = m32 = 0 m33 = 1 return Matrix([[m00, m01, m02, m03], [m10, m11, m12, m13], [m20, m21, m22, m23], [m30, m31, m32, m33]]) sympy-sympy-1.9/sympy/algebras/tests/000077500000000000000000000000001412543434000200265ustar00rootroot00000000000000sympy-sympy-1.9/sympy/algebras/tests/__init__.py000066400000000000000000000000001412543434000221250ustar00rootroot00000000000000sympy-sympy-1.9/sympy/algebras/tests/test_quaternion.py000066400000000000000000000214231412543434000236260ustar00rootroot00000000000000from sympy import symbols, re, im, sign, I, Abs, Symbol, \ cos, sin, sqrt, conjugate, log, acos, asin, E, pi, \ Matrix, diff, integrate, trigsimp, S, Rational from sympy.algebras.quaternion import Quaternion from sympy.testing.pytest import raises w, x, y, z = symbols('w:z') phi = symbols('phi') def test_quaternion_construction(): q = Quaternion(w, x, y, z) assert q + q == Quaternion(2*w, 2*x, 2*y, 2*z) q2 = Quaternion.from_axis_angle((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), pi*Rational(2, 3)) assert q2 == Quaternion(S.Half, S.Half, S.Half, S.Half) M = Matrix([[cos(phi), -sin(phi), 0], [sin(phi), cos(phi), 0], [0, 0, 1]]) q3 = trigsimp(Quaternion.from_rotation_matrix(M)) assert q3 == Quaternion(sqrt(2)*sqrt(cos(phi) + 1)/2, 0, 0, sqrt(2 - 2*cos(phi))*sign(sin(phi))/2) nc = Symbol('nc', commutative=False) raises(ValueError, lambda: Quaternion(w, x, nc, z)) def test_quaternion_axis_angle(): test_data = [ # axis, angle, expected_quaternion ((1, 0, 0), 0, (1, 0, 0, 0)), ((1, 0, 0), pi/2, (sqrt(2)/2, sqrt(2)/2, 0, 0)), ((0, 1, 0), pi/2, (sqrt(2)/2, 0, sqrt(2)/2, 0)), ((0, 0, 1), pi/2, (sqrt(2)/2, 0, 0, sqrt(2)/2)), ((1, 0, 0), pi, (0, 1, 0, 0)), ((0, 1, 0), pi, (0, 0, 1, 0)), ((0, 0, 1), pi, (0, 0, 0, 1)), ((1, 1, 1), pi, (0, 1/sqrt(3),1/sqrt(3),1/sqrt(3))), ((sqrt(3)/3, sqrt(3)/3, sqrt(3)/3), pi*2/3, (S.Half, S.Half, S.Half, S.Half)) ] for axis, angle, expected in test_data: assert Quaternion.from_axis_angle(axis, angle) == Quaternion(*expected) def test_quaternion_axis_angle_simplification(): result = Quaternion.from_axis_angle((1, 2, 3), asin(4)) assert result.a == cos(asin(4)/2) assert result.b == sqrt(14)*sin(asin(4)/2)/14 assert result.c == sqrt(14)*sin(asin(4)/2)/7 assert result.d == 3*sqrt(14)*sin(asin(4)/2)/14 def test_quaternion_complex_real_addition(): a = symbols("a", complex=True) b = symbols("b", real=True) # This symbol is not complex: c = symbols("c", commutative=False) q = Quaternion(w, x, y, z) assert a + q == Quaternion(w + re(a), x + im(a), y, z) assert 1 + q == Quaternion(1 + w, x, y, z) assert I + q == Quaternion(w, 1 + x, y, z) assert b + q == Quaternion(w + b, x, y, z) raises(ValueError, lambda: c + q) raises(ValueError, lambda: q * c) raises(ValueError, lambda: c * q) assert -q == Quaternion(-w, -x, -y, -z) q1 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) q2 = Quaternion(1, 4, 7, 8) assert q1 + (2 + 3*I) == Quaternion(5 + 7*I, 2 + 5*I, 0, 7 + 8*I) assert q2 + (2 + 3*I) == Quaternion(3, 7, 7, 8) assert q1 * (2 + 3*I) == \ Quaternion((2 + 3*I)*(3 + 4*I), (2 + 3*I)*(2 + 5*I), 0, (2 + 3*I)*(7 + 8*I)) assert q2 * (2 + 3*I) == Quaternion(-10, 11, 38, -5) q1 = Quaternion(1, 2, 3, 4) q0 = Quaternion(0, 0, 0, 0) assert q1 + q0 == q1 assert q1 - q0 == q1 assert q1 - q1 == q0 def test_quaternion_evalf(): assert Quaternion(sqrt(2), 0, 0, sqrt(3)).evalf() == Quaternion(sqrt(2).evalf(), 0, 0, sqrt(3).evalf()) assert Quaternion(1/sqrt(2), 0, 0, 1/sqrt(2)).evalf() == Quaternion((1/sqrt(2)).evalf(), 0, 0, (1/sqrt(2)).evalf()) def test_quaternion_functions(): q = Quaternion(w, x, y, z) q1 = Quaternion(1, 2, 3, 4) q0 = Quaternion(0, 0, 0, 0) assert conjugate(q) == Quaternion(w, -x, -y, -z) assert q.norm() == sqrt(w**2 + x**2 + y**2 + z**2) assert q.normalize() == Quaternion(w, x, y, z) / sqrt(w**2 + x**2 + y**2 + z**2) assert q.inverse() == Quaternion(w, -x, -y, -z) / (w**2 + x**2 + y**2 + z**2) assert q.inverse() == q.pow(-1) raises(ValueError, lambda: q0.inverse()) assert q.pow(2) == Quaternion(w**2 - x**2 - y**2 - z**2, 2*w*x, 2*w*y, 2*w*z) assert q**(2) == Quaternion(w**2 - x**2 - y**2 - z**2, 2*w*x, 2*w*y, 2*w*z) assert q1.pow(-2) == Quaternion(Rational(-7, 225), Rational(-1, 225), Rational(-1, 150), Rational(-2, 225)) assert q1**(-2) == Quaternion(Rational(-7, 225), Rational(-1, 225), Rational(-1, 150), Rational(-2, 225)) assert q1.pow(-0.5) == NotImplemented raises(TypeError, lambda: q1**(-0.5)) assert q1.exp() == \ Quaternion(E * cos(sqrt(29)), 2 * sqrt(29) * E * sin(sqrt(29)) / 29, 3 * sqrt(29) * E * sin(sqrt(29)) / 29, 4 * sqrt(29) * E * sin(sqrt(29)) / 29) assert q1._ln() == \ Quaternion(log(sqrt(30)), 2 * sqrt(29) * acos(sqrt(30)/30) / 29, 3 * sqrt(29) * acos(sqrt(30)/30) / 29, 4 * sqrt(29) * acos(sqrt(30)/30) / 29) assert q1.pow_cos_sin(2) == \ Quaternion(30 * cos(2 * acos(sqrt(30)/30)), 60 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 90 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29, 120 * sqrt(29) * sin(2 * acos(sqrt(30)/30)) / 29) assert diff(Quaternion(x, x, x, x), x) == Quaternion(1, 1, 1, 1) assert integrate(Quaternion(x, x, x, x), x) == \ Quaternion(x**2 / 2, x**2 / 2, x**2 / 2, x**2 / 2) assert Quaternion.rotate_point((1, 1, 1), q1) == (S.One / 5, 1, S(7) / 5) n = Symbol('n') raises(TypeError, lambda: q1**n) n = Symbol('n', integer=True) raises(TypeError, lambda: q1**n) def test_quaternion_conversions(): q1 = Quaternion(1, 2, 3, 4) assert q1.to_axis_angle() == ((2 * sqrt(29)/29, 3 * sqrt(29)/29, 4 * sqrt(29)/29), 2 * acos(sqrt(30)/30)) assert q1.to_rotation_matrix() == Matrix([[Rational(-2, 3), Rational(2, 15), Rational(11, 15)], [Rational(2, 3), Rational(-1, 3), Rational(2, 3)], [Rational(1, 3), Rational(14, 15), Rational(2, 15)]]) assert q1.to_rotation_matrix((1, 1, 1)) == Matrix([[Rational(-2, 3), Rational(2, 15), Rational(11, 15), Rational(4, 5)], [Rational(2, 3), Rational(-1, 3), Rational(2, 3), S.Zero], [Rational(1, 3), Rational(14, 15), Rational(2, 15), Rational(-2, 5)], [S.Zero, S.Zero, S.Zero, S.One]]) theta = symbols("theta", real=True) q2 = Quaternion(cos(theta/2), 0, 0, sin(theta/2)) assert trigsimp(q2.to_rotation_matrix()) == Matrix([ [cos(theta), -sin(theta), 0], [sin(theta), cos(theta), 0], [0, 0, 1]]) assert q2.to_axis_angle() == ((0, 0, sin(theta/2)/Abs(sin(theta/2))), 2*acos(cos(theta/2))) assert trigsimp(q2.to_rotation_matrix((1, 1, 1))) == Matrix([ [cos(theta), -sin(theta), 0, sin(theta) - cos(theta) + 1], [sin(theta), cos(theta), 0, -sin(theta) - cos(theta) + 1], [0, 0, 1, 0], [0, 0, 0, 1]]) def test_quaternion_rotation_iss1593(): """ There was a sign mistake in the definition, of the rotation matrix. This tests that particular sign mistake. See issue 1593 for reference. See wikipedia https://en.wikipedia.org/wiki/Quaternions_and_spatial_rotation#Quaternion-derived_rotation_matrix for the correct definition """ q = Quaternion(cos(phi/2), sin(phi/2), 0, 0) assert(trigsimp(q.to_rotation_matrix()) == Matrix([ [1, 0, 0], [0, cos(phi), -sin(phi)], [0, sin(phi), cos(phi)]])) def test_quaternion_multiplication(): q1 = Quaternion(3 + 4*I, 2 + 5*I, 0, 7 + 8*I, real_field = False) q2 = Quaternion(1, 2, 3, 5) q3 = Quaternion(1, 1, 1, y) assert Quaternion._generic_mul(4, 1) == 4 assert Quaternion._generic_mul(4, q1) == Quaternion(12 + 16*I, 8 + 20*I, 0, 28 + 32*I) assert q2.mul(2) == Quaternion(2, 4, 6, 10) assert q2.mul(q3) == Quaternion(-5*y - 4, 3*y - 2, 9 - 2*y, y + 4) assert q2.mul(q3) == q2*q3 z = symbols('z', complex=True) z_quat = Quaternion(re(z), im(z), 0, 0) q = Quaternion(*symbols('q:4', real=True)) assert z * q == z_quat * q assert q * z == q * z_quat def test_issue_16318(): #for rtruediv q0 = Quaternion(0, 0, 0, 0) raises(ValueError, lambda: 1/q0) #for rotate_point q = Quaternion(1, 2, 3, 4) (axis, angle) = q.to_axis_angle() assert Quaternion.rotate_point((1, 1, 1), (axis, angle)) == (S.One / 5, 1, S(7) / 5) #test for to_axis_angle q = Quaternion(-1, 1, 1, 1) axis = (-sqrt(3)/3, -sqrt(3)/3, -sqrt(3)/3) angle = 2*pi/3 assert (axis, angle) == q.to_axis_angle() sympy-sympy-1.9/sympy/assumptions/000077500000000000000000000000001412543434000174715ustar00rootroot00000000000000sympy-sympy-1.9/sympy/assumptions/__init__.py000066400000000000000000000010461412543434000216030ustar00rootroot00000000000000""" A module to implement logical predicates and assumption system. """ from .assume import ( AppliedPredicate, Predicate, AssumptionsContext, assuming, global_assumptions ) from .ask import Q, ask, register_handler, remove_handler from .refine import refine from .relation import BinaryRelation, AppliedBinaryRelation __all__ = [ 'AppliedPredicate', 'Predicate', 'AssumptionsContext', 'assuming', 'global_assumptions', 'Q', 'ask', 'register_handler', 'remove_handler', 'refine', 'BinaryRelation', 'AppliedBinaryRelation' ] sympy-sympy-1.9/sympy/assumptions/ask.py000066400000000000000000000437651412543434000206400ustar00rootroot00000000000000"""Module for querying SymPy objects about assumptions.""" from sympy.assumptions.assume import (global_assumptions, Predicate, AppliedPredicate) from sympy.assumptions.cnf import CNF, EncodedCNF, Literal from sympy.core import sympify from sympy.core.kind import BooleanKind from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le from sympy.logic.inference import satisfiable from sympy.utilities.decorator import memoize_property from sympy.utilities.exceptions import SymPyDeprecationWarning # Memoization is necessary for the properties of AssumptionKeys to # ensure that only one object of Predicate objects are created. # This is because assumption handlers are registered on those objects. class AssumptionKeys: """ This class contains all the supported keys by ``ask``. It should be accessed via the instance ``sympy.Q``. """ # DO NOT add methods or properties other than predicate keys. # SAT solver checks the properties of Q and use them to compute the # fact system. Non-predicate attributes will break this. @memoize_property def hermitian(self): from .handlers.sets import HermitianPredicate return HermitianPredicate() @memoize_property def antihermitian(self): from .handlers.sets import AntihermitianPredicate return AntihermitianPredicate() @memoize_property def real(self): from .handlers.sets import RealPredicate return RealPredicate() @memoize_property def extended_real(self): from .handlers.sets import ExtendedRealPredicate return ExtendedRealPredicate() @memoize_property def imaginary(self): from .handlers.sets import ImaginaryPredicate return ImaginaryPredicate() @memoize_property def complex(self): from .handlers.sets import ComplexPredicate return ComplexPredicate() @memoize_property def algebraic(self): from .handlers.sets import AlgebraicPredicate return AlgebraicPredicate() @memoize_property def transcendental(self): from .predicates.sets import TranscendentalPredicate return TranscendentalPredicate() @memoize_property def integer(self): from .handlers.sets import IntegerPredicate return IntegerPredicate() @memoize_property def rational(self): from .handlers.sets import RationalPredicate return RationalPredicate() @memoize_property def irrational(self): from .handlers.sets import IrrationalPredicate return IrrationalPredicate() @memoize_property def finite(self): from .handlers.calculus import FinitePredicate return FinitePredicate() @memoize_property def infinite(self): from .handlers.calculus import InfinitePredicate return InfinitePredicate() @memoize_property def positive_infinite(self): from .handlers.calculus import PositiveInfinitePredicate return PositiveInfinitePredicate() @memoize_property def negative_infinite(self): from .handlers.calculus import NegativeInfinitePredicate return NegativeInfinitePredicate() @memoize_property def positive(self): from .handlers.order import PositivePredicate return PositivePredicate() @memoize_property def negative(self): from .handlers.order import NegativePredicate return NegativePredicate() @memoize_property def zero(self): from .handlers.order import ZeroPredicate return ZeroPredicate() @memoize_property def extended_positive(self): from .handlers.order import ExtendedPositivePredicate return ExtendedPositivePredicate() @memoize_property def extended_negative(self): from .handlers.order import ExtendedNegativePredicate return ExtendedNegativePredicate() @memoize_property def nonzero(self): from .handlers.order import NonZeroPredicate return NonZeroPredicate() @memoize_property def nonpositive(self): from .handlers.order import NonPositivePredicate return NonPositivePredicate() @memoize_property def nonnegative(self): from .handlers.order import NonNegativePredicate return NonNegativePredicate() @memoize_property def extended_nonzero(self): from .handlers.order import ExtendedNonZeroPredicate return ExtendedNonZeroPredicate() @memoize_property def extended_nonpositive(self): from .handlers.order import ExtendedNonPositivePredicate return ExtendedNonPositivePredicate() @memoize_property def extended_nonnegative(self): from .handlers.order import ExtendedNonNegativePredicate return ExtendedNonNegativePredicate() @memoize_property def even(self): from .handlers.ntheory import EvenPredicate return EvenPredicate() @memoize_property def odd(self): from .handlers.ntheory import OddPredicate return OddPredicate() @memoize_property def prime(self): from .handlers.ntheory import PrimePredicate return PrimePredicate() @memoize_property def composite(self): from .handlers.ntheory import CompositePredicate return CompositePredicate() @memoize_property def commutative(self): from .handlers.common import CommutativePredicate return CommutativePredicate() @memoize_property def is_true(self): from .handlers.common import IsTruePredicate return IsTruePredicate() @memoize_property def symmetric(self): from .handlers.matrices import SymmetricPredicate return SymmetricPredicate() @memoize_property def invertible(self): from .handlers.matrices import InvertiblePredicate return InvertiblePredicate() @memoize_property def orthogonal(self): from .handlers.matrices import OrthogonalPredicate return OrthogonalPredicate() @memoize_property def unitary(self): from .handlers.matrices import UnitaryPredicate return UnitaryPredicate() @memoize_property def positive_definite(self): from .handlers.matrices import PositiveDefinitePredicate return PositiveDefinitePredicate() @memoize_property def upper_triangular(self): from .handlers.matrices import UpperTriangularPredicate return UpperTriangularPredicate() @memoize_property def lower_triangular(self): from .handlers.matrices import LowerTriangularPredicate return LowerTriangularPredicate() @memoize_property def diagonal(self): from .handlers.matrices import DiagonalPredicate return DiagonalPredicate() @memoize_property def fullrank(self): from .handlers.matrices import FullRankPredicate return FullRankPredicate() @memoize_property def square(self): from .handlers.matrices import SquarePredicate return SquarePredicate() @memoize_property def integer_elements(self): from .handlers.matrices import IntegerElementsPredicate return IntegerElementsPredicate() @memoize_property def real_elements(self): from .handlers.matrices import RealElementsPredicate return RealElementsPredicate() @memoize_property def complex_elements(self): from .handlers.matrices import ComplexElementsPredicate return ComplexElementsPredicate() @memoize_property def singular(self): from .predicates.matrices import SingularPredicate return SingularPredicate() @memoize_property def normal(self): from .predicates.matrices import NormalPredicate return NormalPredicate() @memoize_property def triangular(self): from .predicates.matrices import TriangularPredicate return TriangularPredicate() @memoize_property def unit_triangular(self): from .predicates.matrices import UnitTriangularPredicate return UnitTriangularPredicate() @memoize_property def eq(self): from .relation.equality import EqualityPredicate return EqualityPredicate() @memoize_property def ne(self): from .relation.equality import UnequalityPredicate return UnequalityPredicate() @memoize_property def gt(self): from .relation.equality import StrictGreaterThanPredicate return StrictGreaterThanPredicate() @memoize_property def ge(self): from .relation.equality import GreaterThanPredicate return GreaterThanPredicate() @memoize_property def lt(self): from .relation.equality import StrictLessThanPredicate return StrictLessThanPredicate() @memoize_property def le(self): from .relation.equality import LessThanPredicate return LessThanPredicate() Q = AssumptionKeys() def _extract_all_facts(assump, exprs): """ Extract all relevant assumptions from *assump* with respect to given *exprs*. Parameters ========== assump : sympy.assumptions.cnf.CNF exprs : tuple of expressions Returns ======= sympy.assumptions.cnf.CNF Examples ======== >>> from sympy import Q >>> from sympy.assumptions.cnf import CNF >>> from sympy.assumptions.ask import _extract_all_facts >>> from sympy.abc import x, y >>> assump = CNF.from_prop(Q.positive(x) & Q.integer(y)) >>> exprs = (x,) >>> cnf = _extract_all_facts(assump, exprs) >>> cnf.clauses {frozenset({Literal(Q.positive, False)})} """ facts = set() for clause in assump.clauses: args = [] for literal in clause: if isinstance(literal.lit, AppliedPredicate) and len(literal.lit.arguments) == 1: if literal.lit.arg in exprs: # Add literal if it has matching in it args.append(Literal(literal.lit.function, literal.is_Not)) else: # If any of the literals doesn't have matching expr don't add the whole clause. break else: if args: facts.add(frozenset(args)) return CNF(facts) def ask(proposition, assumptions=True, context=global_assumptions): """ Function to evaluate the proposition with assumptions. Explanation =========== This function evaluates the proposition to ``True`` or ``False`` if the truth value can be determined. If not, it returns ``None``. It should be discerned from :func:`~.refine()` which, when applied to a proposition, simplifies the argument to symbolic ``Boolean`` instead of Python built-in ``True``, ``False`` or ``None``. **Syntax** * ask(proposition) Evaluate the *proposition* in global assumption context. * ask(proposition, assumptions) Evaluate the *proposition* with respect to *assumptions* in global assumption context. Parameters ========== proposition : Any boolean expression. Proposition which will be evaluated to boolean value. If this is not ``AppliedPredicate``, it will be wrapped by ``Q.is_true``. assumptions : Any boolean expression, optional. Local assumptions to evaluate the *proposition*. context : AssumptionsContext, optional. Default assumptions to evaluate the *proposition*. By default, this is ``sympy.assumptions.global_assumptions`` variable. Returns ======= ``True``, ``False``, or ``None`` Raises ====== TypeError : *proposition* or *assumptions* is not valid logical expression. ValueError : assumptions are inconsistent. Examples ======== >>> from sympy import ask, Q, pi >>> from sympy.abc import x, y >>> ask(Q.rational(pi)) False >>> ask(Q.even(x*y), Q.even(x) & Q.integer(y)) True >>> ask(Q.prime(4*x), Q.integer(x)) False If the truth value cannot be determined, ``None`` will be returned. >>> print(ask(Q.odd(3*x))) # cannot determine unless we know x None ``ValueError`` is raised if assumptions are inconsistent. >>> ask(Q.integer(x), Q.even(x) & Q.odd(x)) Traceback (most recent call last): ... ValueError: inconsistent assumptions Q.even(x) & Q.odd(x) Notes ===== Relations in assumptions are not implemented (yet), so the following will not give a meaningful result. >>> ask(Q.positive(x), x > 0) It is however a work in progress. See Also ======== sympy.assumptions.refine.refine : Simplification using assumptions. Proposition is not reduced to ``None`` if the truth value cannot be determined. """ from sympy.assumptions.satask import satask proposition = sympify(proposition) assumptions = sympify(assumptions) if isinstance(proposition, Predicate) or proposition.kind is not BooleanKind: raise TypeError("proposition must be a valid logical expression") if isinstance(assumptions, Predicate) or assumptions.kind is not BooleanKind: raise TypeError("assumptions must be a valid logical expression") binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} if isinstance(proposition, AppliedPredicate): key, args = proposition.function, proposition.arguments elif proposition.func in binrelpreds: key, args = binrelpreds[proposition.func], proposition.args else: key, args = Q.is_true, (proposition,) # convert local and global assumptions to CNF assump_cnf = CNF.from_prop(assumptions) assump_cnf.extend(context) # extract the relevant facts from assumptions with respect to args local_facts = _extract_all_facts(assump_cnf, args) # convert default facts and assumed facts to encoded CNF known_facts_cnf = get_all_known_facts() enc_cnf = EncodedCNF() enc_cnf.from_cnf(CNF(known_facts_cnf)) enc_cnf.add_from_cnf(local_facts) # check the satisfiability of given assumptions if local_facts.clauses and satisfiable(enc_cnf) is False: raise ValueError("inconsistent assumptions %s" % assumptions) # quick computation for single fact res = _ask_single_fact(key, local_facts) if res is not None: return res # direct resolution method, no logic res = key(*args)._eval_ask(assumptions) if res is not None: return bool(res) # using satask (still costly) res = satask(proposition, assumptions=assumptions, context=context) return res def _ask_single_fact(key, local_facts): """ Compute the truth value of single predicate using assumptions. Parameters ========== key : sympy.assumptions.assume.Predicate Proposition predicate. local_facts : sympy.assumptions.cnf.CNF Local assumption in CNF form. Returns ======= ``True``, ``False`` or ``None`` Examples ======== >>> from sympy import Q >>> from sympy.assumptions.cnf import CNF >>> from sympy.assumptions.ask import _ask_single_fact If prerequisite of proposition is rejected by the assumption, return ``False``. >>> key, assump = Q.zero, ~Q.zero >>> local_facts = CNF.from_prop(assump) >>> _ask_single_fact(key, local_facts) False >>> key, assump = Q.zero, ~Q.even >>> local_facts = CNF.from_prop(assump) >>> _ask_single_fact(key, local_facts) False If assumption implies the proposition, return ``True``. >>> key, assump = Q.even, Q.zero >>> local_facts = CNF.from_prop(assump) >>> _ask_single_fact(key, local_facts) True If proposition rejects the assumption, return ``False``. >>> key, assump = Q.even, Q.odd >>> local_facts = CNF.from_prop(assump) >>> _ask_single_fact(key, local_facts) False """ if local_facts.clauses: known_facts_dict = get_known_facts_dict() if len(local_facts.clauses) == 1: cl, = local_facts.clauses if len(cl) == 1: f, = cl prop_facts = known_facts_dict.get(key, None) prop_req = prop_facts[0] if prop_facts is not None else set() if f.is_Not and f.arg in prop_req: # the prerequisite of proposition is rejected return False for clause in local_facts.clauses: if len(clause) == 1: f, = clause prop_facts = known_facts_dict.get(f.arg, None) if not f.is_Not else None if prop_facts is None: continue prop_req, prop_rej = prop_facts if key in prop_req: # assumption implies the proposition return True elif key in prop_rej: # proposition rejects the assumption return False return None def register_handler(key, handler): """ Register a handler in the ask system. key must be a string and handler a class inheriting from AskHandler. .. deprecated:: 1.8. Use multipledispatch handler instead. See :obj:`~.Predicate`. """ SymPyDeprecationWarning( feature="register_handler() function", useinstead="multipledispatch handler of Predicate", issue=20873, deprecated_since_version="1.8" ).warn() if isinstance(key, Predicate): key = key.name.name Qkey = getattr(Q, key, None) if Qkey is not None: Qkey.add_handler(handler) else: setattr(Q, key, Predicate(key, handlers=[handler])) def remove_handler(key, handler): """ Removes a handler from the ask system. Same syntax as register_handler .. deprecated:: 1.8. Use multipledispatch handler instead. See :obj:`~.Predicate`. """ SymPyDeprecationWarning( feature="remove_handler() function", useinstead="multipledispatch handler of Predicate", issue=20873, deprecated_since_version="1.8" ).warn() if isinstance(key, Predicate): key = key.name.name getattr(Q, key).remove_handler(handler) from sympy.assumptions.ask_generated import (get_all_known_facts, get_known_facts_dict) sympy-sympy-1.9/sympy/assumptions/ask_generated.py000066400000000000000000000412731412543434000226460ustar00rootroot00000000000000""" Do NOT manually edit this file. Instead, run ./bin/ask_update.py. """ from sympy.assumptions.ask import Q from sympy.assumptions.cnf import Literal from sympy.core.cache import cacheit @cacheit def get_all_known_facts(): """ Known facts between unary predicates as CNF clauses. """ return { frozenset((Literal(Q.algebraic, False), Literal(Q.imaginary, True), Literal(Q.transcendental, False))), frozenset((Literal(Q.algebraic, False), Literal(Q.negative, True), Literal(Q.transcendental, False))), frozenset((Literal(Q.algebraic, False), Literal(Q.positive, True), Literal(Q.transcendental, False))), frozenset((Literal(Q.algebraic, False), Literal(Q.rational, True))), frozenset((Literal(Q.algebraic, False), Literal(Q.transcendental, False), Literal(Q.zero, True))), frozenset((Literal(Q.algebraic, True), Literal(Q.finite, False))), frozenset((Literal(Q.algebraic, True), Literal(Q.transcendental, True))), frozenset((Literal(Q.antihermitian, False), Literal(Q.hermitian, False), Literal(Q.zero, True))), frozenset((Literal(Q.antihermitian, False), Literal(Q.imaginary, True))), frozenset((Literal(Q.commutative, False), Literal(Q.finite, True))), frozenset((Literal(Q.commutative, False), Literal(Q.infinite, True))), frozenset((Literal(Q.complex_elements, False), Literal(Q.real_elements, True))), frozenset((Literal(Q.composite, False), Literal(Q.even, True), Literal(Q.positive, True), Literal(Q.prime, False))), frozenset((Literal(Q.composite, True), Literal(Q.even, False), Literal(Q.odd, False))), frozenset((Literal(Q.composite, True), Literal(Q.positive, False))), frozenset((Literal(Q.composite, True), Literal(Q.prime, True))), frozenset((Literal(Q.diagonal, False), Literal(Q.lower_triangular, True), Literal(Q.upper_triangular, True))), frozenset((Literal(Q.diagonal, True), Literal(Q.lower_triangular, False))), frozenset((Literal(Q.diagonal, True), Literal(Q.normal, False))), frozenset((Literal(Q.diagonal, True), Literal(Q.symmetric, False))), frozenset((Literal(Q.diagonal, True), Literal(Q.upper_triangular, False))), frozenset((Literal(Q.even, False), Literal(Q.odd, False), Literal(Q.prime, True))), frozenset((Literal(Q.even, False), Literal(Q.zero, True))), frozenset((Literal(Q.even, True), Literal(Q.odd, True))), frozenset((Literal(Q.even, True), Literal(Q.rational, False))), frozenset((Literal(Q.finite, False), Literal(Q.transcendental, True))), frozenset((Literal(Q.finite, True), Literal(Q.infinite, True))), frozenset((Literal(Q.fullrank, False), Literal(Q.invertible, True))), frozenset((Literal(Q.fullrank, True), Literal(Q.invertible, False), Literal(Q.square, True))), frozenset((Literal(Q.hermitian, False), Literal(Q.negative, True))), frozenset((Literal(Q.hermitian, False), Literal(Q.positive, True))), frozenset((Literal(Q.hermitian, False), Literal(Q.zero, True))), frozenset((Literal(Q.imaginary, True), Literal(Q.negative, True))), frozenset((Literal(Q.imaginary, True), Literal(Q.positive, True))), frozenset((Literal(Q.imaginary, True), Literal(Q.zero, True))), frozenset((Literal(Q.infinite, False), Literal(Q.negative_infinite, True))), frozenset((Literal(Q.infinite, False), Literal(Q.positive_infinite, True))), frozenset((Literal(Q.integer_elements, True), Literal(Q.real_elements, False))), frozenset((Literal(Q.invertible, False), Literal(Q.positive_definite, True))), frozenset((Literal(Q.invertible, False), Literal(Q.singular, False))), frozenset((Literal(Q.invertible, False), Literal(Q.unitary, True))), frozenset((Literal(Q.invertible, True), Literal(Q.singular, True))), frozenset((Literal(Q.invertible, True), Literal(Q.square, False))), frozenset((Literal(Q.irrational, False), Literal(Q.negative, True), Literal(Q.rational, False))), frozenset((Literal(Q.irrational, False), Literal(Q.positive, True), Literal(Q.rational, False))), frozenset((Literal(Q.irrational, False), Literal(Q.rational, False), Literal(Q.zero, True))), frozenset((Literal(Q.irrational, True), Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.zero, False))), frozenset((Literal(Q.irrational, True), Literal(Q.rational, True))), frozenset((Literal(Q.lower_triangular, False), Literal(Q.triangular, True), Literal(Q.upper_triangular, False))), frozenset((Literal(Q.lower_triangular, True), Literal(Q.triangular, False))), frozenset((Literal(Q.negative, False), Literal(Q.positive, False), Literal(Q.rational, True), Literal(Q.zero, False))), frozenset((Literal(Q.negative, True), Literal(Q.negative_infinite, True))), frozenset((Literal(Q.negative, True), Literal(Q.positive, True))), frozenset((Literal(Q.negative, True), Literal(Q.positive_infinite, True))), frozenset((Literal(Q.negative, True), Literal(Q.zero, True))), frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive, True))), frozenset((Literal(Q.negative_infinite, True), Literal(Q.positive_infinite, True))), frozenset((Literal(Q.negative_infinite, True), Literal(Q.zero, True))), frozenset((Literal(Q.normal, False), Literal(Q.unitary, True))), frozenset((Literal(Q.normal, True), Literal(Q.square, False))), frozenset((Literal(Q.odd, True), Literal(Q.rational, False))), frozenset((Literal(Q.orthogonal, False), Literal(Q.real_elements, True), Literal(Q.unitary, True))), frozenset((Literal(Q.orthogonal, True), Literal(Q.positive_definite, False))), frozenset((Literal(Q.orthogonal, True), Literal(Q.unitary, False))), frozenset((Literal(Q.positive, False), Literal(Q.prime, True))), frozenset((Literal(Q.positive, True), Literal(Q.positive_infinite, True))), frozenset((Literal(Q.positive, True), Literal(Q.zero, True))), frozenset((Literal(Q.positive_infinite, True), Literal(Q.zero, True))), frozenset((Literal(Q.square, False), Literal(Q.symmetric, True))), frozenset((Literal(Q.triangular, False), Literal(Q.unit_triangular, True))), frozenset((Literal(Q.triangular, False), Literal(Q.upper_triangular, True))) } @cacheit def get_known_facts_dict(): """ Logical relations between unary predicates as dictionary. Each key is a predicate, and item is two groups of predicates. First group contains the predicates which are implied by the key, and second group contains the predicates which are rejected by the key. """ return { Q.algebraic: (set([Q.algebraic, Q.commutative, Q.complex, Q.finite]), set([Q.infinite, Q.negative_infinite, Q.positive_infinite, Q.transcendental])), Q.antihermitian: (set([Q.antihermitian]), set([])), Q.commutative: (set([Q.commutative]), set([])), Q.complex: (set([Q.commutative, Q.complex, Q.finite]), set([Q.infinite, Q.negative_infinite, Q.positive_infinite])), Q.complex_elements: (set([Q.complex_elements]), set([])), Q.composite: (set([Q.algebraic, Q.commutative, Q.complex, Q.composite, Q.extended_nonnegative, Q.extended_nonzero, Q.extended_positive, Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.nonnegative, Q.nonzero, Q.positive, Q.rational, Q.real]), set([Q.extended_negative, Q.extended_nonpositive, Q.imaginary, Q.infinite, Q.irrational, Q.negative, Q.negative_infinite, Q.nonpositive, Q.positive_infinite, Q.prime, Q.transcendental, Q.zero])), Q.diagonal: (set([Q.diagonal, Q.lower_triangular, Q.normal, Q.square, Q.symmetric, Q.triangular, Q.upper_triangular]), set([])), Q.even: (set([Q.algebraic, Q.commutative, Q.complex, Q.even, Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.rational, Q.real]), set([Q.imaginary, Q.infinite, Q.irrational, Q.negative_infinite, Q.odd, Q.positive_infinite, Q.transcendental])), Q.extended_negative: (set([Q.commutative, Q.extended_negative, Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real]), set([Q.composite, Q.extended_nonnegative, Q.extended_positive, Q.imaginary, Q.nonnegative, Q.positive, Q.positive_infinite, Q.prime, Q.zero])), Q.extended_nonnegative: (set([Q.commutative, Q.extended_nonnegative, Q.extended_real]), set([Q.extended_negative, Q.imaginary, Q.negative, Q.negative_infinite])), Q.extended_nonpositive: (set([Q.commutative, Q.extended_nonpositive, Q.extended_real]), set([Q.composite, Q.extended_positive, Q.imaginary, Q.positive, Q.positive_infinite, Q.prime])), Q.extended_nonzero: (set([Q.commutative, Q.extended_nonzero, Q.extended_real]), set([Q.imaginary, Q.zero])), Q.extended_positive: (set([Q.commutative, Q.extended_nonnegative, Q.extended_nonzero, Q.extended_positive, Q.extended_real]), set([Q.extended_negative, Q.extended_nonpositive, Q.imaginary, Q.negative, Q.negative_infinite, Q.nonpositive, Q.zero])), Q.extended_real: (set([Q.commutative, Q.extended_real]), set([Q.imaginary])), Q.finite: (set([Q.commutative, Q.finite]), set([Q.infinite, Q.negative_infinite, Q.positive_infinite])), Q.fullrank: (set([Q.fullrank]), set([])), Q.hermitian: (set([Q.hermitian]), set([])), Q.imaginary: (set([Q.antihermitian, Q.commutative, Q.complex, Q.finite, Q.imaginary]), set([Q.composite, Q.even, Q.extended_negative, Q.extended_nonnegative, Q.extended_nonpositive, Q.extended_nonzero, Q.extended_positive, Q.extended_real, Q.infinite, Q.integer, Q.irrational, Q.negative, Q.negative_infinite, Q.nonnegative, Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.positive_infinite, Q.prime, Q.rational, Q.real, Q.zero])), Q.infinite: (set([Q.commutative, Q.infinite]), set([Q.algebraic, Q.complex, Q.composite, Q.even, Q.finite, Q.imaginary, Q.integer, Q.irrational, Q.negative, Q.nonnegative, Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.prime, Q.rational, Q.real, Q.transcendental, Q.zero])), Q.integer: (set([Q.algebraic, Q.commutative, Q.complex, Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.rational, Q.real]), set([Q.imaginary, Q.infinite, Q.irrational, Q.negative_infinite, Q.positive_infinite, Q.transcendental])), Q.integer_elements: (set([Q.complex_elements, Q.integer_elements, Q.real_elements]), set([])), Q.invertible: (set([Q.fullrank, Q.invertible, Q.square]), set([Q.singular])), Q.irrational: (set([Q.commutative, Q.complex, Q.extended_nonzero, Q.extended_real, Q.finite, Q.hermitian, Q.irrational, Q.nonzero, Q.real]), set([Q.composite, Q.even, Q.imaginary, Q.infinite, Q.integer, Q.negative_infinite, Q.odd, Q.positive_infinite, Q.prime, Q.rational, Q.zero])), Q.is_true: (set([Q.is_true]), set([])), Q.lower_triangular: (set([Q.lower_triangular, Q.triangular]), set([])), Q.negative: (set([Q.commutative, Q.complex, Q.extended_negative, Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real, Q.finite, Q.hermitian, Q.negative, Q.nonpositive, Q.nonzero, Q.real]), set([Q.composite, Q.extended_nonnegative, Q.extended_positive, Q.imaginary, Q.infinite, Q.negative_infinite, Q.nonnegative, Q.positive, Q.positive_infinite, Q.prime, Q.zero])), Q.negative_infinite: (set([Q.commutative, Q.extended_negative, Q.extended_nonpositive, Q.extended_nonzero, Q.extended_real, Q.infinite, Q.negative_infinite]), set([Q.algebraic, Q.complex, Q.composite, Q.even, Q.extended_nonnegative, Q.extended_positive, Q.finite, Q.imaginary, Q.integer, Q.irrational, Q.negative, Q.nonnegative, Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.positive_infinite, Q.prime, Q.rational, Q.real, Q.transcendental, Q.zero])), Q.nonnegative: (set([Q.commutative, Q.complex, Q.extended_nonnegative, Q.extended_real, Q.finite, Q.hermitian, Q.nonnegative, Q.real]), set([Q.extended_negative, Q.imaginary, Q.infinite, Q.negative, Q.negative_infinite, Q.positive_infinite])), Q.nonpositive: (set([Q.commutative, Q.complex, Q.extended_nonpositive, Q.extended_real, Q.finite, Q.hermitian, Q.nonpositive, Q.real]), set([Q.composite, Q.extended_positive, Q.imaginary, Q.infinite, Q.negative_infinite, Q.positive, Q.positive_infinite, Q.prime])), Q.nonzero: (set([Q.commutative, Q.complex, Q.extended_nonzero, Q.extended_real, Q.finite, Q.hermitian, Q.nonzero, Q.real]), set([Q.imaginary, Q.infinite, Q.negative_infinite, Q.positive_infinite, Q.zero])), Q.normal: (set([Q.normal, Q.square]), set([])), Q.odd: (set([Q.algebraic, Q.commutative, Q.complex, Q.extended_nonzero, Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.nonzero, Q.odd, Q.rational, Q.real]), set([Q.even, Q.imaginary, Q.infinite, Q.irrational, Q.negative_infinite, Q.positive_infinite, Q.transcendental, Q.zero])), Q.orthogonal: (set([Q.fullrank, Q.invertible, Q.normal, Q.orthogonal, Q.positive_definite, Q.square, Q.unitary]), set([Q.singular])), Q.positive: (set([Q.commutative, Q.complex, Q.extended_nonnegative, Q.extended_nonzero, Q.extended_positive, Q.extended_real, Q.finite, Q.hermitian, Q.nonnegative, Q.nonzero, Q.positive, Q.real]), set([Q.extended_negative, Q.extended_nonpositive, Q.imaginary, Q.infinite, Q.negative, Q.negative_infinite, Q.nonpositive, Q.positive_infinite, Q.zero])), Q.positive_definite: (set([Q.fullrank, Q.invertible, Q.positive_definite, Q.square]), set([Q.singular])), Q.positive_infinite: (set([Q.commutative, Q.extended_nonnegative, Q.extended_nonzero, Q.extended_positive, Q.extended_real, Q.infinite, Q.positive_infinite]), set([Q.algebraic, Q.complex, Q.composite, Q.even, Q.extended_negative, Q.extended_nonpositive, Q.finite, Q.imaginary, Q.integer, Q.irrational, Q.negative, Q.negative_infinite, Q.nonnegative, Q.nonpositive, Q.nonzero, Q.odd, Q.positive, Q.prime, Q.rational, Q.real, Q.transcendental, Q.zero])), Q.prime: (set([Q.algebraic, Q.commutative, Q.complex, Q.extended_nonnegative, Q.extended_nonzero, Q.extended_positive, Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.nonnegative, Q.nonzero, Q.positive, Q.prime, Q.rational, Q.real]), set([Q.composite, Q.extended_negative, Q.extended_nonpositive, Q.imaginary, Q.infinite, Q.irrational, Q.negative, Q.negative_infinite, Q.nonpositive, Q.positive_infinite, Q.transcendental, Q.zero])), Q.rational: (set([Q.algebraic, Q.commutative, Q.complex, Q.extended_real, Q.finite, Q.hermitian, Q.rational, Q.real]), set([Q.imaginary, Q.infinite, Q.irrational, Q.negative_infinite, Q.positive_infinite, Q.transcendental])), Q.real: (set([Q.commutative, Q.complex, Q.extended_real, Q.finite, Q.hermitian, Q.real]), set([Q.imaginary, Q.infinite, Q.negative_infinite, Q.positive_infinite])), Q.real_elements: (set([Q.complex_elements, Q.real_elements]), set([])), Q.singular: (set([Q.singular]), set([Q.invertible, Q.orthogonal, Q.positive_definite, Q.unitary])), Q.square: (set([Q.square]), set([])), Q.symmetric: (set([Q.square, Q.symmetric]), set([])), Q.transcendental: (set([Q.commutative, Q.complex, Q.finite, Q.transcendental]), set([Q.algebraic, Q.composite, Q.even, Q.infinite, Q.integer, Q.negative_infinite, Q.odd, Q.positive_infinite, Q.prime, Q.rational, Q.zero])), Q.triangular: (set([Q.triangular]), set([])), Q.unit_triangular: (set([Q.triangular, Q.unit_triangular]), set([])), Q.unitary: (set([Q.fullrank, Q.invertible, Q.normal, Q.square, Q.unitary]), set([Q.singular])), Q.upper_triangular: (set([Q.triangular, Q.upper_triangular]), set([])), Q.zero: (set([Q.algebraic, Q.commutative, Q.complex, Q.even, Q.extended_nonnegative, Q.extended_nonpositive, Q.extended_real, Q.finite, Q.hermitian, Q.integer, Q.nonnegative, Q.nonpositive, Q.rational, Q.real, Q.zero]), set([Q.composite, Q.extended_negative, Q.extended_nonzero, Q.extended_positive, Q.imaginary, Q.infinite, Q.irrational, Q.negative, Q.negative_infinite, Q.nonzero, Q.odd, Q.positive, Q.positive_infinite, Q.prime, Q.transcendental])), } sympy-sympy-1.9/sympy/assumptions/assume.py000066400000000000000000000337611412543434000213520ustar00rootroot00000000000000"""A module which implements predicates and assumption context.""" from contextlib import contextmanager import inspect from sympy.core.assumptions import ManagedProperties from sympy.core.symbol import Str from sympy.core.sympify import _sympify from sympy.logic.boolalg import Boolean, false, true from sympy.multipledispatch.dispatcher import Dispatcher, str_signature from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.iterables import is_sequence from sympy.utilities.source import get_class class AssumptionsContext(set): """ Set containing default assumptions which are applied to the ``ask()`` function. Explanation =========== This is used to represent global assumptions, but you can also use this class to create your own local assumptions contexts. It is basically a thin wrapper to Python's set, so see its documentation for advanced usage. Examples ======== The default assumption context is ``global_assumptions``, which is initially empty: >>> from sympy import ask, Q >>> from sympy.assumptions import global_assumptions >>> global_assumptions AssumptionsContext() You can add default assumptions: >>> from sympy.abc import x >>> global_assumptions.add(Q.real(x)) >>> global_assumptions AssumptionsContext({Q.real(x)}) >>> ask(Q.real(x)) True And remove them: >>> global_assumptions.remove(Q.real(x)) >>> print(ask(Q.real(x))) None The ``clear()`` method removes every assumption: >>> global_assumptions.add(Q.positive(x)) >>> global_assumptions AssumptionsContext({Q.positive(x)}) >>> global_assumptions.clear() >>> global_assumptions AssumptionsContext() See Also ======== assuming """ def add(self, *assumptions): """Add assumptions.""" for a in assumptions: super().add(a) def _sympystr(self, printer): if not self: return "%s()" % self.__class__.__name__ return "{}({})".format(self.__class__.__name__, printer._print_set(self)) global_assumptions = AssumptionsContext() class AppliedPredicate(Boolean): """ The class of expressions resulting from applying ``Predicate`` to the arguments. ``AppliedPredicate`` merely wraps its argument and remain unevaluated. To evaluate it, use the ``ask()`` function. Examples ======== >>> from sympy import Q, ask >>> Q.integer(1) Q.integer(1) The ``function`` attribute returns the predicate, and the ``arguments`` attribute returns the tuple of arguments. >>> type(Q.integer(1)) >>> Q.integer(1).function Q.integer >>> Q.integer(1).arguments (1,) Applied predicates can be evaluated to a boolean value with ``ask``: >>> ask(Q.integer(1)) True """ __slots__ = () def __new__(cls, predicate, *args): if not isinstance(predicate, Predicate): raise TypeError("%s is not a Predicate." % predicate) args = map(_sympify, args) return super().__new__(cls, predicate, *args) @property def arg(self): """ Return the expression used by this assumption. Examples ======== >>> from sympy import Q, Symbol >>> x = Symbol('x') >>> a = Q.integer(x + 1) >>> a.arg x + 1 """ # Will be deprecated args = self._args if len(args) == 2: # backwards compatibility return args[1] raise TypeError("'arg' property is allowed only for unary predicates.") @property def function(self): """ Return the predicate. """ # Will be changed to self.args[0] after args overridding is removed return self._args[0] @property def arguments(self): """ Return the arguments which are applied to the predicate. """ # Will be changed to self.args[1:] after args overridding is removed return self._args[1:] def _eval_ask(self, assumptions): return self.function.eval(self.arguments, assumptions) @property def binary_symbols(self): from .ask import Q if self.function == Q.is_true: i = self.arguments[0] if i.is_Boolean or i.is_Symbol: return i.binary_symbols if self.function in (Q.eq, Q.ne): if true in self.arguments or false in self.arguments: if self.arguments[0].is_Symbol: return {self.arguments[0]} elif self.arguments[1].is_Symbol: return {self.arguments[1]} return set() class PredicateMeta(ManagedProperties): def __new__(cls, clsname, bases, dct): # If handler is not defined, assign empty dispatcher. if "handler" not in dct: name = f"Ask{clsname.capitalize()}Handler" handler = Dispatcher(name, doc="Handler for key %s" % name) dct["handler"] = handler dct["_orig_doc"] = dct.get("__doc__", "") return super().__new__(cls, clsname, bases, dct) @property def __doc__(cls): handler = cls.handler doc = cls._orig_doc if cls is not Predicate and handler is not None: doc += "Handler\n" doc += " =======\n\n" # Append the handler's doc without breaking sphinx documentation. docs = [" Multiply dispatched method: %s" % handler.name] if handler.doc: for line in handler.doc.splitlines(): if not line: continue docs.append(" %s" % line) other = [] for sig in handler.ordering[::-1]: func = handler.funcs[sig] if func.__doc__: s = ' Inputs: <%s>' % str_signature(sig) lines = [] for line in func.__doc__.splitlines(): lines.append(" %s" % line) s += "\n".join(lines) docs.append(s) else: other.append(str_signature(sig)) if other: othersig = " Other signatures:" for line in other: othersig += "\n * %s" % line docs.append(othersig) doc += '\n\n'.join(docs) return doc class Predicate(Boolean, metaclass=PredicateMeta): """ Base class for mathematical predicates. It also serves as a constructor for undefined predicate objects. Explanation =========== Predicate is a function that returns a boolean value [1]. Predicate function is object, and it is instance of predicate class. When a predicate is applied to arguments, ``AppliedPredicate`` instance is returned. This merely wraps the argument and remain unevaluated. To obtain the truth value of applied predicate, use the function ``ask``. Evaluation of predicate is done by multiple dispatching. You can register new handler to the predicate to support new types. Every predicate in SymPy can be accessed via the property of ``Q``. For example, ``Q.even`` returns the predicate which checks if the argument is even number. To define a predicate which can be evaluated, you must subclass this class, make an instance of it, and register it to ``Q``. After then, dispatch the handler by argument types. If you directly construct predicate using this class, you will get ``UndefinedPredicate`` which cannot be dispatched. This is useful when you are building boolean expressions which do not need to be evaluated. Examples ======== Applying and evaluating to boolean value: >>> from sympy import Q, ask >>> ask(Q.prime(7)) True You can define a new predicate by subclassing and dispatching. Here, we define a predicate for sexy primes [2] as an example. >>> from sympy import Predicate, Integer >>> class SexyPrimePredicate(Predicate): ... name = "sexyprime" >>> Q.sexyprime = SexyPrimePredicate() >>> @Q.sexyprime.register(Integer, Integer) ... def _(int1, int2, assumptions): ... args = sorted([int1, int2]) ... if not all(ask(Q.prime(a), assumptions) for a in args): ... return False ... return args[1] - args[0] == 6 >>> ask(Q.sexyprime(5, 11)) True Direct constructing returns ``UndefinedPredicate``, which can be applied but cannot be dispatched. >>> from sympy import Predicate, Integer >>> Q.P = Predicate("P") >>> type(Q.P) >>> Q.P(1) Q.P(1) >>> Q.P.register(Integer)(lambda expr, assump: True) Traceback (most recent call last): ... TypeError: cannot be dispatched. References ========== .. [1] https://en.wikipedia.org/wiki/Predicate_(mathematical_logic) .. [2] https://en.wikipedia.org/wiki/Sexy_prime """ is_Atom = True def __new__(cls, *args, **kwargs): if cls is Predicate: return UndefinedPredicate(*args, **kwargs) obj = super().__new__(cls, *args) return obj @property def name(self): # May be overridden return type(self).__name__ @classmethod def register(cls, *types, **kwargs): """ Register the signature to the handler. """ if cls.handler is None: raise TypeError("%s cannot be dispatched." % type(cls)) return cls.handler.register(*types, **kwargs) @classmethod def register_many(cls, *types, **kwargs): """ Register multiple signatures to same handler. """ def _(func): for t in types: if not is_sequence(t): t = (t,) # for convenience, allow passing `type` to mean `(type,)` cls.register(*t, **kwargs)(func) return _ def __call__(self, *args): return AppliedPredicate(self, *args) def eval(self, args, assumptions=True): """ Evaluate ``self(*args)`` under the given assumptions. This uses only direct resolution methods, not logical inference. """ result = None try: result = self.handler(*args, assumptions=assumptions) except NotImplementedError: pass return result def _eval_refine(self, assumptions): # When Predicate is no longer Boolean, delete this method return self class UndefinedPredicate(Predicate): """ Predicate without handler. Explanation =========== This predicate is generated by using ``Predicate`` directly for construction. It does not have a handler, and evaluating this with arguments is done by SAT solver. Examples ======== >>> from sympy import Predicate, Q >>> Q.P = Predicate('P') >>> Q.P.func >>> Q.P.name Str('P') """ handler = None def __new__(cls, name, handlers=None): # "handlers" parameter supports old design if not isinstance(name, Str): name = Str(name) obj = super(Boolean, cls).__new__(cls, name) obj.handlers = handlers or [] return obj @property def name(self): return self.args[0] def _hashable_content(self): return (self.name,) def __getnewargs__(self): return (self.name,) def __call__(self, expr): return AppliedPredicate(self, expr) def add_handler(self, handler): SymPyDeprecationWarning( feature="Predicate.add_handler() method", useinstead="multipledispatch handler of Predicate", issue=20873, deprecated_since_version="1.8" ).warn() self.handlers.append(handler) def remove_handler(self, handler): SymPyDeprecationWarning( feature="Predicate.remove_handler() method", useinstead="multipledispatch handler of Predicate", issue=20873, deprecated_since_version="1.8" ).warn() self.handlers.remove(handler) def eval(self, args, assumptions=True): # Support for deprecated design # When old design is removed, this will always return None SymPyDeprecationWarning( feature="Evaluating UndefinedPredicate", useinstead="multipledispatch handler of Predicate", issue=20873, deprecated_since_version="1.8" ).warn() expr, = args res, _res = None, None mro = inspect.getmro(type(expr)) for handler in self.handlers: cls = get_class(handler) for subclass in mro: eval_ = getattr(cls, subclass.__name__, None) if eval_ is None: continue res = eval_(expr, assumptions) # Do not stop if value returned is None # Try to check for higher classes if res is None: continue if _res is None: _res = res else: # only check consistency if both resolutors have concluded if _res != res: raise ValueError('incompatible resolutors') break return res @contextmanager def assuming(*assumptions): """ Context manager for assumptions. Examples ======== >>> from sympy.assumptions import assuming, Q, ask >>> from sympy.abc import x, y >>> print(ask(Q.integer(x + y))) None >>> with assuming(Q.integer(x), Q.integer(y)): ... print(ask(Q.integer(x + y))) True """ old_global_assumptions = global_assumptions.copy() global_assumptions.update(assumptions) try: yield finally: global_assumptions.clear() global_assumptions.update(old_global_assumptions) sympy-sympy-1.9/sympy/assumptions/cnf.py000066400000000000000000000305451412543434000206200ustar00rootroot00000000000000""" The classes used here are for the internal use of assumptions system only and should not be used anywhere else as these don't possess the signatures common to SymPy objects. For general use of logic constructs please refer to sympy.logic classes And, Or, Not, etc. """ from itertools import combinations, product from sympy import S, Nor, Nand, Xor, Implies, Equivalent, ITE from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le from sympy.logic.boolalg import Or, And, Not, Xnor from itertools import zip_longest class Literal: """ The smallest element of a CNF object. Parameters ========== lit : Boolean expression is_Not : bool Examples ======== >>> from sympy import Q >>> from sympy.assumptions.cnf import Literal >>> from sympy.abc import x >>> Literal(Q.even(x)) Literal(Q.even(x), False) >>> Literal(~Q.even(x)) Literal(Q.even(x), True) """ def __new__(cls, lit, is_Not=False): if isinstance(lit, Not): lit = lit.args[0] is_Not = True elif isinstance(lit, (AND, OR, Literal)): return ~lit if is_Not else lit obj = super().__new__(cls) obj.lit = lit obj.is_Not = is_Not return obj @property def arg(self): return self.lit def rcall(self, expr): if callable(self.lit): lit = self.lit(expr) else: try: lit = self.lit.apply(expr) except AttributeError: lit = self.lit.rcall(expr) return type(self)(lit, self.is_Not) def __invert__(self): is_Not = not self.is_Not return Literal(self.lit, is_Not) def __str__(self): return '{}({}, {})'.format(type(self).__name__, self.lit, self.is_Not) __repr__ = __str__ def __eq__(self, other): return self.arg == other.arg and self.is_Not == other.is_Not def __hash__(self): h = hash((type(self).__name__, self.arg, self.is_Not)) return h class OR: """ A low-level implementation for Or """ def __init__(self, *args): self._args = args @property def args(self): return sorted(self._args, key=str) def rcall(self, expr): return type(self)(*[arg.rcall(expr) for arg in self._args ]) def __invert__(self): return AND(*[~arg for arg in self._args]) def __hash__(self): return hash((type(self).__name__,) + tuple(self.args)) def __eq__(self, other): return self.args == other.args def __str__(self): s = '(' + ' | '.join([str(arg) for arg in self.args]) + ')' return s __repr__ = __str__ class AND: """ A low-level implementation for And """ def __init__(self, *args): self._args = args def __invert__(self): return OR(*[~arg for arg in self._args]) @property def args(self): return sorted(self._args, key=str) def rcall(self, expr): return type(self)(*[arg.rcall(expr) for arg in self._args ]) def __hash__(self): return hash((type(self).__name__,) + tuple(self.args)) def __eq__(self, other): return self.args == other.args def __str__(self): s = '('+' & '.join([str(arg) for arg in self.args])+')' return s __repr__ = __str__ def to_NNF(expr, composite_map={}): """ Generates the Negation Normal Form of any boolean expression in terms of AND, OR, and Literal objects. Examples ======== >>> from sympy import Q, Eq >>> from sympy.assumptions.cnf import to_NNF >>> from sympy.abc import x, y >>> expr = Q.even(x) & ~Q.positive(x) >>> to_NNF(expr) (Literal(Q.even(x), False) & Literal(Q.positive(x), True)) Supported boolean objects are converted to corresponding predicates. >>> to_NNF(Eq(x, y)) Literal(Q.eq(x, y), False) If ``composite_map`` argument is given, ``to_NNF`` decomposes the specified predicate into a combination of primitive predicates. >>> cmap = {Q.nonpositive: Q.negative | Q.zero} >>> to_NNF(Q.nonpositive, cmap) (Literal(Q.negative, False) | Literal(Q.zero, False)) >>> to_NNF(Q.nonpositive(x), cmap) (Literal(Q.negative(x), False) | Literal(Q.zero(x), False)) """ from sympy.assumptions.ask import Q from sympy.assumptions.assume import AppliedPredicate, Predicate binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} if type(expr) in binrelpreds: pred = binrelpreds[type(expr)] expr = pred(*expr.args) if isinstance(expr, Not): arg = expr.args[0] tmp = to_NNF(arg, composite_map) # Strategy: negate the NNF of expr return ~tmp if isinstance(expr, Or): return OR(*[to_NNF(x, composite_map) for x in Or.make_args(expr)]) if isinstance(expr, And): return AND(*[to_NNF(x, composite_map) for x in And.make_args(expr)]) if isinstance(expr, Nand): tmp = AND(*[to_NNF(x, composite_map) for x in expr.args]) return ~tmp if isinstance(expr, Nor): tmp = OR(*[to_NNF(x, composite_map) for x in expr.args]) return ~tmp if isinstance(expr, Xor): cnfs = [] for i in range(0, len(expr.args) + 1, 2): for neg in combinations(expr.args, i): clause = [~to_NNF(s, composite_map) if s in neg else to_NNF(s, composite_map) for s in expr.args] cnfs.append(OR(*clause)) return AND(*cnfs) if isinstance(expr, Xnor): cnfs = [] for i in range(0, len(expr.args) + 1, 2): for neg in combinations(expr.args, i): clause = [~to_NNF(s, composite_map) if s in neg else to_NNF(s, composite_map) for s in expr.args] cnfs.append(OR(*clause)) return ~AND(*cnfs) if isinstance(expr, Implies): L, R = to_NNF(expr.args[0], composite_map), to_NNF(expr.args[1], composite_map) return OR(~L, R) if isinstance(expr, Equivalent): cnfs = [] for a, b in zip_longest(expr.args, expr.args[1:], fillvalue=expr.args[0]): a = to_NNF(a, composite_map) b = to_NNF(b, composite_map) cnfs.append(OR(~a, b)) return AND(*cnfs) if isinstance(expr, ITE): L = to_NNF(expr.args[0], composite_map) M = to_NNF(expr.args[1], composite_map) R = to_NNF(expr.args[2], composite_map) return AND(OR(~L, M), OR(L, R)) if isinstance(expr, AppliedPredicate): pred, args = expr.function, expr.arguments newpred = composite_map.get(pred, None) if newpred is not None: return to_NNF(newpred.rcall(*args), composite_map) if isinstance(expr, Predicate): newpred = composite_map.get(expr, None) if newpred is not None: return to_NNF(newpred, composite_map) return Literal(expr) def distribute_AND_over_OR(expr): """ Distributes AND over OR in the NNF expression. Returns the result( Conjunctive Normal Form of expression) as a CNF object. """ if not isinstance(expr, (AND, OR)): tmp = set() tmp.add(frozenset((expr,))) return CNF(tmp) if isinstance(expr, OR): return CNF.all_or(*[distribute_AND_over_OR(arg) for arg in expr._args]) if isinstance(expr, AND): return CNF.all_and(*[distribute_AND_over_OR(arg) for arg in expr._args]) class CNF: """ Class to represent CNF of a Boolean expression. Consists of set of clauses, which themselves are stored as frozenset of Literal objects. Examples ======== >>> from sympy import Q >>> from sympy.assumptions.cnf import CNF >>> from sympy.abc import x >>> cnf = CNF.from_prop(Q.real(x) & ~Q.zero(x)) >>> cnf.clauses {frozenset({Literal(Q.zero(x), True)}), frozenset({Literal(Q.negative(x), False), Literal(Q.positive(x), False), Literal(Q.zero(x), False)})} """ def __init__(self, clauses=None): if not clauses: clauses = set() self.clauses = clauses def add(self, prop): clauses = CNF.to_CNF(prop).clauses self.add_clauses(clauses) def __str__(self): s = ' & '.join( ['(' + ' | '.join([str(lit) for lit in clause]) +')' for clause in self.clauses] ) return s def extend(self, props): for p in props: self.add(p) return self def copy(self): return CNF(set(self.clauses)) def add_clauses(self, clauses): self.clauses |= clauses @classmethod def from_prop(cls, prop): res = cls() res.add(prop) return res def __iand__(self, other): self.add_clauses(other.clauses) return self def all_predicates(self): predicates = set() for c in self.clauses: predicates |= {arg.lit for arg in c} return predicates def _or(self, cnf): clauses = set() for a, b in product(self.clauses, cnf.clauses): tmp = set(a) for t in b: tmp.add(t) clauses.add(frozenset(tmp)) return CNF(clauses) def _and(self, cnf): clauses = self.clauses.union(cnf.clauses) return CNF(clauses) def _not(self): clss = list(self.clauses) ll = set() for x in clss[-1]: ll.add(frozenset((~x,))) ll = CNF(ll) for rest in clss[:-1]: p = set() for x in rest: p.add(frozenset((~x,))) ll = ll._or(CNF(p)) return ll def rcall(self, expr): clause_list = list() for clause in self.clauses: lits = [arg.rcall(expr) for arg in clause] clause_list.append(OR(*lits)) expr = AND(*clause_list) return distribute_AND_over_OR(expr) @classmethod def all_or(cls, *cnfs): b = cnfs[0].copy() for rest in cnfs[1:]: b = b._or(rest) return b @classmethod def all_and(cls, *cnfs): b = cnfs[0].copy() for rest in cnfs[1:]: b = b._and(rest) return b @classmethod def to_CNF(cls, expr): from sympy.assumptions.facts import get_composite_predicates expr = to_NNF(expr, get_composite_predicates()) expr = distribute_AND_over_OR(expr) return expr @classmethod def CNF_to_cnf(cls, cnf): """ Converts CNF object to SymPy's boolean expression retaining the form of expression. """ def remove_literal(arg): return Not(arg.lit) if arg.is_Not else arg.lit return And(*(Or(*(remove_literal(arg) for arg in clause)) for clause in cnf.clauses)) class EncodedCNF: """ Class for encoding the CNF expression. """ def __init__(self, data=None, encoding=None): if not data and not encoding: data = list() encoding = dict() self.data = data self.encoding = encoding self._symbols = list(encoding.keys()) def from_cnf(self, cnf): self._symbols = list(cnf.all_predicates()) n = len(self._symbols) self.encoding = dict(list(zip(self._symbols, list(range(1, n + 1))))) self.data = [self.encode(clause) for clause in cnf.clauses] @property def symbols(self): return self._symbols @property def variables(self): return range(1, len(self._symbols) + 1) def copy(self): new_data = [set(clause) for clause in self.data] return EncodedCNF(new_data, dict(self.encoding)) def add_prop(self, prop): cnf = CNF.from_prop(prop) self.add_from_cnf(cnf) def add_from_cnf(self, cnf): clauses = [self.encode(clause) for clause in cnf.clauses] self.data += clauses def encode_arg(self, arg): literal = arg.lit value = self.encoding.get(literal, None) if value is None: n = len(self._symbols) self._symbols.append(literal) value = self.encoding[literal] = n + 1 if arg.is_Not: return -value else: return value def encode(self, clause): return {self.encode_arg(arg) if not arg.lit == S.false else 0 for arg in clause} sympy-sympy-1.9/sympy/assumptions/facts.py000066400000000000000000000167341412543434000211560ustar00rootroot00000000000000""" Known facts in assumptions module. This module defines the facts between unary predicates in ``get_known_facts()``, and supports functions to generate the contents in ``sympy.assumptions.ask_generated`` file. """ from sympy.assumptions import Q from sympy.assumptions.assume import AppliedPredicate from sympy.core.cache import cacheit from sympy.core.symbol import Symbol from sympy.logic.boolalg import (to_cnf, And, Not, Implies, Equivalent, Exclusive,) from sympy.logic.inference import satisfiable @cacheit def get_composite_predicates(): # To reduce the complexity of sat solver, these predicates are # transformed into the combination of primitive predicates. return { Q.real : Q.negative | Q.zero | Q.positive, Q.integer : Q.even | Q.odd, Q.nonpositive : Q.negative | Q.zero, Q.nonzero : Q.negative | Q.positive, Q.nonnegative : Q.zero | Q.positive, Q.extended_real : Q.negative_infinite | Q.negative | Q.zero | Q.positive | Q.positive_infinite, Q.extended_positive: Q.positive | Q.positive_infinite, Q.extended_negative: Q.negative | Q.negative_infinite, Q.extended_nonzero: Q.negative_infinite | Q.negative | Q.positive | Q.positive_infinite, Q.extended_nonpositive: Q.negative_infinite | Q.negative | Q.zero, Q.extended_nonnegative: Q.zero | Q.positive | Q.positive_infinite, Q.complex : Q.algebraic | Q.transcendental } @cacheit def get_known_facts(x=None): """ Facts between unary predicates. Parameters ========== x : Symbol, optional Placeholder symbol for unary facts. Default is ``Symbol('x')``. Returns ======= fact : Known facts in conjugated normal form. """ if x is None: x = Symbol('x') fact = And( # primitive predicates for extended real exclude each other. Exclusive(Q.negative_infinite(x), Q.negative(x), Q.zero(x), Q.positive(x), Q.positive_infinite(x)), # build complex plane Exclusive(Q.real(x), Q.imaginary(x)), Implies(Q.real(x) | Q.imaginary(x), Q.complex(x)), # other subsets of complex Exclusive(Q.transcendental(x), Q.algebraic(x)), Equivalent(Q.real(x), Q.rational(x) | Q.irrational(x)), Exclusive(Q.irrational(x), Q.rational(x)), Implies(Q.rational(x), Q.algebraic(x)), # integers Exclusive(Q.even(x), Q.odd(x)), Implies(Q.integer(x), Q.rational(x)), Implies(Q.zero(x), Q.even(x)), Exclusive(Q.composite(x), Q.prime(x)), Implies(Q.composite(x) | Q.prime(x), Q.integer(x) & Q.positive(x)), Implies(Q.even(x) & Q.positive(x) & ~Q.prime(x), Q.composite(x)), # hermitian and antihermitian Implies(Q.real(x), Q.hermitian(x)), Implies(Q.imaginary(x), Q.antihermitian(x)), Implies(Q.zero(x), Q.hermitian(x) | Q.antihermitian(x)), # define finity and infinity, and build extended real line Exclusive(Q.infinite(x), Q.finite(x)), Implies(Q.complex(x), Q.finite(x)), Implies(Q.negative_infinite(x) | Q.positive_infinite(x), Q.infinite(x)), # commutativity Implies(Q.finite(x) | Q.infinite(x), Q.commutative(x)), # matrices Implies(Q.orthogonal(x), Q.positive_definite(x)), Implies(Q.orthogonal(x), Q.unitary(x)), Implies(Q.unitary(x) & Q.real_elements(x), Q.orthogonal(x)), Implies(Q.unitary(x), Q.normal(x)), Implies(Q.unitary(x), Q.invertible(x)), Implies(Q.normal(x), Q.square(x)), Implies(Q.diagonal(x), Q.normal(x)), Implies(Q.positive_definite(x), Q.invertible(x)), Implies(Q.diagonal(x), Q.upper_triangular(x)), Implies(Q.diagonal(x), Q.lower_triangular(x)), Implies(Q.lower_triangular(x), Q.triangular(x)), Implies(Q.upper_triangular(x), Q.triangular(x)), Implies(Q.triangular(x), Q.upper_triangular(x) | Q.lower_triangular(x)), Implies(Q.upper_triangular(x) & Q.lower_triangular(x), Q.diagonal(x)), Implies(Q.diagonal(x), Q.symmetric(x)), Implies(Q.unit_triangular(x), Q.triangular(x)), Implies(Q.invertible(x), Q.fullrank(x)), Implies(Q.invertible(x), Q.square(x)), Implies(Q.symmetric(x), Q.square(x)), Implies(Q.fullrank(x) & Q.square(x), Q.invertible(x)), Equivalent(Q.invertible(x), ~Q.singular(x)), Implies(Q.integer_elements(x), Q.real_elements(x)), Implies(Q.real_elements(x), Q.complex_elements(x)), ) return fact def generate_known_facts_dict(keys, fact): """ Computes and returns a dictionary which contains the relations between unary predicates. Each key is a predicate, and item is two groups of predicates. First group contains the predicates which are implied by the key, and second group contains the predicates which are rejected by the key. All predicates in *keys* and *fact* must be unary and have same placeholder symbol. Parameters ========== keys : list of AppliedPredicate instances. fact : Fact between predicates in conjugated normal form. Examples ======== >>> from sympy import Q >>> from sympy.assumptions.facts import generate_known_facts_dict >>> from sympy.logic.boolalg import And, Implies >>> from sympy.abc import x >>> keys = [Q.even(x), Q.odd(x), Q.zero(x)] >>> fact = And(Implies(Q.even(x), ~Q.odd(x)), ... Implies(Q.zero(x), Q.even(x))) >>> generate_known_facts_dict(keys, fact) {Q.even: ({Q.even}, {Q.odd}), Q.odd: ({Q.odd}, {Q.even, Q.zero}), Q.zero: ({Q.even, Q.zero}, {Q.odd})} """ fact_cnf = to_cnf(fact) mapping = single_fact_lookup(keys, fact_cnf) ret = {} for key, value in mapping.items(): implied = set() rejected = set() for expr in value: if isinstance(expr, AppliedPredicate): implied.add(expr.function) elif isinstance(expr, Not): pred = expr.args[0] rejected.add(pred.function) ret[key.function] = (implied, rejected) return ret @cacheit def get_known_facts_keys(): """ Return every unary predicates registered to ``Q``. This function is used to generate the keys for ``generate_known_facts_dict``. """ exclude = set() for pred in [Q.eq, Q.ne, Q.gt, Q.lt, Q.ge, Q.le]: # exclude polyadic predicates exclude.add(pred) result = [] for attr in Q.__class__.__dict__: if attr.startswith('__'): continue pred = getattr(Q, attr) if pred in exclude: continue result.append(pred) return result def single_fact_lookup(known_facts_keys, known_facts_cnf): # Return the dictionary for quick lookup of single fact mapping = {} for key in known_facts_keys: mapping[key] = {key} for other_key in known_facts_keys: if other_key != key: if ask_full_inference(other_key, key, known_facts_cnf): mapping[key].add(other_key) if ask_full_inference(~other_key, key, known_facts_cnf): mapping[key].add(~other_key) return mapping def ask_full_inference(proposition, assumptions, known_facts_cnf): """ Method for inferring properties about objects. """ if not satisfiable(And(known_facts_cnf, assumptions, proposition)): return False if not satisfiable(And(known_facts_cnf, assumptions, Not(proposition))): return True return None sympy-sympy-1.9/sympy/assumptions/handlers/000077500000000000000000000000001412543434000212715ustar00rootroot00000000000000sympy-sympy-1.9/sympy/assumptions/handlers/__init__.py000066400000000000000000000005121412543434000234000ustar00rootroot00000000000000""" Multipledispatch handlers for ``Predicate`` are implemented here. Handlers in this module are not directly imported to other modules in order to avoid circular import problem. """ from .common import (AskHandler, CommonHandler, test_closed_group) __all__ = [ 'AskHandler', 'CommonHandler', 'test_closed_group' ] sympy-sympy-1.9/sympy/assumptions/handlers/calculus.py000066400000000000000000000160361412543434000234640ustar00rootroot00000000000000""" This module contains query handlers responsible for calculus queries: infinitesimal, finite, etc. """ from sympy.assumptions import Q, ask from sympy.core import Add, Mul, Pow, Symbol from sympy.core.numbers import (ComplexInfinity, Exp1, GoldenRatio, ImaginaryUnit, Infinity, NaN, NegativeInfinity, Number, Pi, TribonacciConstant, E) from sympy.functions import cos, exp, log, sign, sin from sympy.logic.boolalg import conjuncts from ..predicates.calculus import (FinitePredicate, InfinitePredicate, PositiveInfinitePredicate, NegativeInfinitePredicate) # FinitePredicate @FinitePredicate.register(Symbol) def _(expr, assumptions): """ Handles Symbol. """ if expr.is_finite is not None: return expr.is_finite if Q.finite(expr) in conjuncts(assumptions): return True return None @FinitePredicate.register(Add) def _(expr, assumptions): """ Return True if expr is bounded, False if not and None if unknown. Truth Table: +-------+-----+-----------+-----------+ | | | | | | | B | U | ? | | | | | | +-------+-----+---+---+---+---+---+---+ | | | | | | | | | | | |'+'|'-'|'x'|'+'|'-'|'x'| | | | | | | | | | +-------+-----+---+---+---+---+---+---+ | | | | | | B | B | U | ? | | | | | | +---+---+-----+---+---+---+---+---+---+ | | | | | | | | | | | |'+'| | U | ? | ? | U | ? | ? | | | | | | | | | | | | +---+-----+---+---+---+---+---+---+ | | | | | | | | | | | U |'-'| | ? | U | ? | ? | U | ? | | | | | | | | | | | | +---+-----+---+---+---+---+---+---+ | | | | | | | |'x'| | ? | ? | | | | | | | +---+---+-----+---+---+---+---+---+---+ | | | | | | ? | | | ? | | | | | | +-------+-----+-----------+---+---+---+ * 'B' = Bounded * 'U' = Unbounded * '?' = unknown boundedness * '+' = positive sign * '-' = negative sign * 'x' = sign unknown * All Bounded -> True * 1 Unbounded and the rest Bounded -> False * >1 Unbounded, all with same known sign -> False * Any Unknown and unknown sign -> None * Else -> None When the signs are not the same you can have an undefined result as in oo - oo, hence 'bounded' is also undefined. """ sign = -1 # sign of unknown or infinite result = True for arg in expr.args: _bounded = ask(Q.finite(arg), assumptions) if _bounded: continue s = ask(Q.extended_positive(arg), assumptions) # if there has been more than one sign or if the sign of this arg # is None and Bounded is None or there was already # an unknown sign, return None if sign != -1 and s != sign or \ s is None and (s == _bounded or s == sign): return None else: sign = s # once False, do not change if result is not False: result = _bounded return result @FinitePredicate.register(Mul) def _(expr, assumptions): """ Return True if expr is bounded, False if not and None if unknown. Truth Table: +---+---+---+--------+ | | | | | | | B | U | ? | | | | | | +---+---+---+---+----+ | | | | | | | | | | s | /s | | | | | | | +---+---+---+---+----+ | | | | | | B | B | U | ? | | | | | | +---+---+---+---+----+ | | | | | | | U | | U | U | ? | | | | | | | +---+---+---+---+----+ | | | | | | ? | | | ? | | | | | | +---+---+---+---+----+ * B = Bounded * U = Unbounded * ? = unknown boundedness * s = signed (hence nonzero) * /s = not signed """ result = True for arg in expr.args: _bounded = ask(Q.finite(arg), assumptions) if _bounded: continue elif _bounded is None: if result is None: return None if ask(Q.extended_nonzero(arg), assumptions) is None: return None if result is not False: result = None else: result = False return result @FinitePredicate.register(Pow) def _(expr, assumptions): """ * Unbounded ** NonZero -> Unbounded * Bounded ** Bounded -> Bounded * Abs()<=1 ** Positive -> Bounded * Abs()>=1 ** Negative -> Bounded * Otherwise unknown """ if expr.base == E: return ask(Q.finite(expr.exp), assumptions) base_bounded = ask(Q.finite(expr.base), assumptions) exp_bounded = ask(Q.finite(expr.exp), assumptions) if base_bounded is None and exp_bounded is None: # Common Case return None if base_bounded is False and ask(Q.extended_nonzero(expr.exp), assumptions): return False if base_bounded and exp_bounded: return True if (abs(expr.base) <= 1) == True and ask(Q.extended_positive(expr.exp), assumptions): return True if (abs(expr.base) >= 1) == True and ask(Q.extended_negative(expr.exp), assumptions): return True if (abs(expr.base) >= 1) == True and exp_bounded is False: return False return None @FinitePredicate.register(exp) def _(expr, assumptions): return ask(Q.finite(expr.exp), assumptions) @FinitePredicate.register(log) def _(expr, assumptions): # After complex -> finite fact is registered to new assumption system, # querying Q.infinite may be removed. if ask(Q.infinite(expr.args[0]), assumptions): return False return ask(~Q.zero(expr.args[0]), assumptions) @FinitePredicate.register_many(cos, sin, Number, Pi, Exp1, GoldenRatio, TribonacciConstant, ImaginaryUnit, sign) def _(expr, assumptions): return True @FinitePredicate.register_many(ComplexInfinity, Infinity, NegativeInfinity) def _(expr, assumptions): return False @FinitePredicate.register(NaN) def _(expr, assumptions): return None # InfinitePredicate @InfinitePredicate.register_many(ComplexInfinity, Infinity, NegativeInfinity) def _(expr, assumptions): return True # PositiveInfinitePredicate @PositiveInfinitePredicate.register(Infinity) def _(expr, assumptions): return True @PositiveInfinitePredicate.register_many(NegativeInfinity, ComplexInfinity) def _(expr, assumptions): return False # NegativeInfinitePredicate @NegativeInfinitePredicate.register(NegativeInfinity) def _(expr, assumptions): return True @NegativeInfinitePredicate.register_many(Infinity, ComplexInfinity) def _(expr, assumptions): return False sympy-sympy-1.9/sympy/assumptions/handlers/common.py000066400000000000000000000075431412543434000231440ustar00rootroot00000000000000""" This module defines base class for handlers and some core handlers: ``Q.commutative`` and ``Q.is_true``. """ from sympy.assumptions import Q, ask, AppliedPredicate from sympy.core import Basic, Symbol from sympy.core.logic import _fuzzy_group from sympy.core.numbers import NaN, Number from sympy.logic.boolalg import (And, BooleanTrue, BooleanFalse, conjuncts, Equivalent, Implies, Not, Or) from sympy.utilities.exceptions import SymPyDeprecationWarning from ..predicates.common import CommutativePredicate, IsTruePredicate class AskHandler: """Base class that all Ask Handlers must inherit.""" def __new__(cls, *args, **kwargs): SymPyDeprecationWarning( feature="AskHandler() class", useinstead="multipledispatch handler", issue=20873, deprecated_since_version="1.8" ).warn() return super().__new__(cls, *args, **kwargs) class CommonHandler(AskHandler): # Deprecated """Defines some useful methods common to most Handlers. """ @staticmethod def AlwaysTrue(expr, assumptions): return True @staticmethod def AlwaysFalse(expr, assumptions): return False @staticmethod def AlwaysNone(expr, assumptions): return None NaN = AlwaysFalse # CommutativePredicate @CommutativePredicate.register(Symbol) def _(expr, assumptions): """Objects are expected to be commutative unless otherwise stated""" assumps = conjuncts(assumptions) if expr.is_commutative is not None: return expr.is_commutative and not ~Q.commutative(expr) in assumps if Q.commutative(expr) in assumps: return True elif ~Q.commutative(expr) in assumps: return False return True @CommutativePredicate.register(Basic) def _(expr, assumptions): for arg in expr.args: if not ask(Q.commutative(arg), assumptions): return False return True @CommutativePredicate.register(Number) def _(expr, assumptions): return True @CommutativePredicate.register(NaN) def _(expr, assumptions): return True # IsTruePredicate @IsTruePredicate.register(bool) def _(expr, assumptions): return expr @IsTruePredicate.register(BooleanTrue) def _(expr, assumptions): return True @IsTruePredicate.register(BooleanFalse) def _(expr, assumptions): return False @IsTruePredicate.register(AppliedPredicate) def _(expr, assumptions): return ask(expr, assumptions) @IsTruePredicate.register(Not) def _(expr, assumptions): arg = expr.args[0] if arg.is_Symbol: # symbol used as abstract boolean object return None value = ask(arg, assumptions=assumptions) if value in (True, False): return not value else: return None @IsTruePredicate.register(Or) def _(expr, assumptions): result = False for arg in expr.args: p = ask(arg, assumptions=assumptions) if p is True: return True if p is None: result = None return result @IsTruePredicate.register(And) def _(expr, assumptions): result = True for arg in expr.args: p = ask(arg, assumptions=assumptions) if p is False: return False if p is None: result = None return result @IsTruePredicate.register(Implies) def _(expr, assumptions): p, q = expr.args return ask(~p | q, assumptions=assumptions) @IsTruePredicate.register(Equivalent) def _(expr, assumptions): p, q = expr.args pt = ask(p, assumptions=assumptions) if pt is None: return None qt = ask(q, assumptions=assumptions) if qt is None: return None return pt == qt #### Helper methods def test_closed_group(expr, assumptions, key): """ Test for membership in a group with respect to the current operation. """ return _fuzzy_group( (ask(key(a), assumptions) for a in expr.args), quick_exit=True) sympy-sympy-1.9/sympy/assumptions/handlers/matrices.py000066400000000000000000000535031412543434000234600ustar00rootroot00000000000000""" This module contains query handlers responsible for Matrices queries: Square, Symmetric, Invertible etc. """ from sympy.logic.boolalg import conjuncts from sympy.assumptions import Q, ask from sympy.assumptions.handlers import test_closed_group from sympy.matrices import MatrixBase from sympy.matrices.expressions import (BlockMatrix, BlockDiagMatrix, Determinant, DiagMatrix, DiagonalMatrix, HadamardProduct, Identity, Inverse, MatAdd, MatMul, MatPow, MatrixExpr, MatrixSlice, MatrixSymbol, OneMatrix, Trace, Transpose, ZeroMatrix) from sympy.matrices.expressions.factorizations import Factorization from sympy.matrices.expressions.fourier import DFT from sympy.core.logic import fuzzy_and from sympy.utilities.iterables import sift from sympy.core import Basic from ..predicates.matrices import (SquarePredicate, SymmetricPredicate, InvertiblePredicate, OrthogonalPredicate, UnitaryPredicate, FullRankPredicate, PositiveDefinitePredicate, UpperTriangularPredicate, LowerTriangularPredicate, DiagonalPredicate, IntegerElementsPredicate, RealElementsPredicate, ComplexElementsPredicate) def _Factorization(predicate, expr, assumptions): if predicate in expr.predicates: return True # SquarePredicate @SquarePredicate.register(MatrixExpr) def _(expr, assumptions): return expr.shape[0] == expr.shape[1] # SymmetricPredicate @SymmetricPredicate.register(MatMul) def _(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if all(ask(Q.symmetric(arg), assumptions) for arg in mmul.args): return True # TODO: implement sathandlers system for the matrices. # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). if ask(Q.diagonal(expr), assumptions): return True if len(mmul.args) >= 2 and mmul.args[0] == mmul.args[-1].T: if len(mmul.args) == 2: return True return ask(Q.symmetric(MatMul(*mmul.args[1:-1])), assumptions) @SymmetricPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None non_negative = ask(~Q.negative(exp), assumptions) if (non_negative or non_negative == False and ask(Q.invertible(base), assumptions)): return ask(Q.symmetric(base), assumptions) return None @SymmetricPredicate.register(MatAdd) def _(expr, assumptions): return all(ask(Q.symmetric(arg), assumptions) for arg in expr.args) @SymmetricPredicate.register(MatrixSymbol) def _(expr, assumptions): if not expr.is_square: return False # TODO: implement sathandlers system for the matrices. # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). if ask(Q.diagonal(expr), assumptions): return True if Q.symmetric(expr) in conjuncts(assumptions): return True @SymmetricPredicate.register_many(OneMatrix, ZeroMatrix) def _(expr, assumptions): return ask(Q.square(expr), assumptions) @SymmetricPredicate.register_many(Inverse, Transpose) def _(expr, assumptions): return ask(Q.symmetric(expr.arg), assumptions) @SymmetricPredicate.register(MatrixSlice) def _(expr, assumptions): # TODO: implement sathandlers system for the matrices. # Now it duplicates the general fact: Implies(Q.diagonal, Q.symmetric). if ask(Q.diagonal(expr), assumptions): return True if not expr.on_diag: return None else: return ask(Q.symmetric(expr.parent), assumptions) @SymmetricPredicate.register(Identity) def _(expr, assumptions): return True # InvertiblePredicate @InvertiblePredicate.register(MatMul) def _(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if all(ask(Q.invertible(arg), assumptions) for arg in mmul.args): return True if any(ask(Q.invertible(arg), assumptions) is False for arg in mmul.args): return False @InvertiblePredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None if exp.is_negative == False: return ask(Q.invertible(base), assumptions) return None @InvertiblePredicate.register(MatAdd) def _(expr, assumptions): return None @InvertiblePredicate.register(MatrixSymbol) def _(expr, assumptions): if not expr.is_square: return False if Q.invertible(expr) in conjuncts(assumptions): return True @InvertiblePredicate.register_many(Identity, Inverse) def _(expr, assumptions): return True @InvertiblePredicate.register(ZeroMatrix) def _(expr, assumptions): return False @InvertiblePredicate.register(OneMatrix) def _(expr, assumptions): return expr.shape[0] == 1 and expr.shape[1] == 1 @InvertiblePredicate.register(Transpose) def _(expr, assumptions): return ask(Q.invertible(expr.arg), assumptions) @InvertiblePredicate.register(MatrixSlice) def _(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.invertible(expr.parent), assumptions) @InvertiblePredicate.register(MatrixBase) def _(expr, assumptions): if not expr.is_square: return False return expr.rank() == expr.rows @InvertiblePredicate.register(MatrixExpr) def _(expr, assumptions): if not expr.is_square: return False return None @InvertiblePredicate.register(BlockMatrix) def _(expr, assumptions): from sympy.matrices.expressions.blockmatrix import reblock_2x2 if not expr.is_square: return False if expr.blockshape == (1, 1): return ask(Q.invertible(expr.blocks[0, 0]), assumptions) expr = reblock_2x2(expr) if expr.blockshape == (2, 2): [[A, B], [C, D]] = expr.blocks.tolist() if ask(Q.invertible(A), assumptions) == True: invertible = ask(Q.invertible(D - C * A.I * B), assumptions) if invertible is not None: return invertible if ask(Q.invertible(B), assumptions) == True: invertible = ask(Q.invertible(C - D * B.I * A), assumptions) if invertible is not None: return invertible if ask(Q.invertible(C), assumptions) == True: invertible = ask(Q.invertible(B - A * C.I * D), assumptions) if invertible is not None: return invertible if ask(Q.invertible(D), assumptions) == True: invertible = ask(Q.invertible(A - B * D.I * C), assumptions) if invertible is not None: return invertible return None @InvertiblePredicate.register(BlockDiagMatrix) def _(expr, assumptions): if expr.rowblocksizes != expr.colblocksizes: return None return fuzzy_and([ask(Q.invertible(a), assumptions) for a in expr.diag]) # OrthogonalPredicate @OrthogonalPredicate.register(MatMul) def _(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if (all(ask(Q.orthogonal(arg), assumptions) for arg in mmul.args) and factor == 1): return True if any(ask(Q.invertible(arg), assumptions) is False for arg in mmul.args): return False @OrthogonalPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if int_exp: return ask(Q.orthogonal(base), assumptions) return None @OrthogonalPredicate.register(MatAdd) def _(expr, assumptions): if (len(expr.args) == 1 and ask(Q.orthogonal(expr.args[0]), assumptions)): return True @OrthogonalPredicate.register(MatrixSymbol) def _(expr, assumptions): if (not expr.is_square or ask(Q.invertible(expr), assumptions) is False): return False if Q.orthogonal(expr) in conjuncts(assumptions): return True @OrthogonalPredicate.register(Identity) def _(expr, assumptions): return True @OrthogonalPredicate.register(ZeroMatrix) def _(expr, assumptions): return False @OrthogonalPredicate.register_many(Inverse, Transpose) def _(expr, assumptions): return ask(Q.orthogonal(expr.arg), assumptions) @OrthogonalPredicate.register(MatrixSlice) def _(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.orthogonal(expr.parent), assumptions) @OrthogonalPredicate.register(Factorization) def _(expr, assumptions): return _Factorization(Q.orthogonal, expr, assumptions) # UnitaryPredicate @UnitaryPredicate.register(MatMul) def _(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if (all(ask(Q.unitary(arg), assumptions) for arg in mmul.args) and abs(factor) == 1): return True if any(ask(Q.invertible(arg), assumptions) is False for arg in mmul.args): return False @UnitaryPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if int_exp: return ask(Q.unitary(base), assumptions) return None @UnitaryPredicate.register(MatrixSymbol) def _(expr, assumptions): if (not expr.is_square or ask(Q.invertible(expr), assumptions) is False): return False if Q.unitary(expr) in conjuncts(assumptions): return True @UnitaryPredicate.register_many(Inverse, Transpose) def _(expr, assumptions): return ask(Q.unitary(expr.arg), assumptions) @UnitaryPredicate.register(MatrixSlice) def _(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.unitary(expr.parent), assumptions) @UnitaryPredicate.register_many(DFT, Identity) def _(expr, assumptions): return True @UnitaryPredicate.register(ZeroMatrix) def _(expr, assumptions): return False @UnitaryPredicate.register(Factorization) def _(expr, assumptions): return _Factorization(Q.unitary, expr, assumptions) # FullRankPredicate @FullRankPredicate.register(MatMul) def _(expr, assumptions): if all(ask(Q.fullrank(arg), assumptions) for arg in expr.args): return True @FullRankPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if int_exp and ask(~Q.negative(exp), assumptions): return ask(Q.fullrank(base), assumptions) return None @FullRankPredicate.register(Identity) def _(expr, assumptions): return True @FullRankPredicate.register(ZeroMatrix) def _(expr, assumptions): return False @FullRankPredicate.register(OneMatrix) def _(expr, assumptions): return expr.shape[0] == 1 and expr.shape[1] == 1 @FullRankPredicate.register_many(Inverse, Transpose) def _(expr, assumptions): return ask(Q.fullrank(expr.arg), assumptions) @FullRankPredicate.register(MatrixSlice) def _(expr, assumptions): if ask(Q.orthogonal(expr.parent), assumptions): return True # PositiveDefinitePredicate @PositiveDefinitePredicate.register(MatMul) def _(expr, assumptions): factor, mmul = expr.as_coeff_mmul() if (all(ask(Q.positive_definite(arg), assumptions) for arg in mmul.args) and factor > 0): return True if (len(mmul.args) >= 2 and mmul.args[0] == mmul.args[-1].T and ask(Q.fullrank(mmul.args[0]), assumptions)): return ask(Q.positive_definite( MatMul(*mmul.args[1:-1])), assumptions) @PositiveDefinitePredicate.register(MatPow) def _(expr, assumptions): # a power of a positive definite matrix is positive definite if ask(Q.positive_definite(expr.args[0]), assumptions): return True @PositiveDefinitePredicate.register(MatAdd) def _(expr, assumptions): if all(ask(Q.positive_definite(arg), assumptions) for arg in expr.args): return True @PositiveDefinitePredicate.register(MatrixSymbol) def _(expr, assumptions): if not expr.is_square: return False if Q.positive_definite(expr) in conjuncts(assumptions): return True @PositiveDefinitePredicate.register(Identity) def _(expr, assumptions): return True @PositiveDefinitePredicate.register(ZeroMatrix) def _(expr, assumptions): return False @PositiveDefinitePredicate.register(OneMatrix) def _(expr, assumptions): return expr.shape[0] == 1 and expr.shape[1] == 1 @PositiveDefinitePredicate.register_many(Inverse, Transpose) def _(expr, assumptions): return ask(Q.positive_definite(expr.arg), assumptions) @PositiveDefinitePredicate.register(MatrixSlice) def _(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.positive_definite(expr.parent), assumptions) # UpperTriangularPredicate @UpperTriangularPredicate.register(MatMul) def _(expr, assumptions): factor, matrices = expr.as_coeff_matrices() if all(ask(Q.upper_triangular(m), assumptions) for m in matrices): return True @UpperTriangularPredicate.register(MatAdd) def _(expr, assumptions): if all(ask(Q.upper_triangular(arg), assumptions) for arg in expr.args): return True @UpperTriangularPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None non_negative = ask(~Q.negative(exp), assumptions) if (non_negative or non_negative == False and ask(Q.invertible(base), assumptions)): return ask(Q.upper_triangular(base), assumptions) return None @UpperTriangularPredicate.register(MatrixSymbol) def _(expr, assumptions): if Q.upper_triangular(expr) in conjuncts(assumptions): return True @UpperTriangularPredicate.register_many(Identity, ZeroMatrix) def _(expr, assumptions): return True @UpperTriangularPredicate.register(OneMatrix) def _(expr, assumptions): return expr.shape[0] == 1 and expr.shape[1] == 1 @UpperTriangularPredicate.register(Transpose) def _(expr, assumptions): return ask(Q.lower_triangular(expr.arg), assumptions) @UpperTriangularPredicate.register(Inverse) def _(expr, assumptions): return ask(Q.upper_triangular(expr.arg), assumptions) @UpperTriangularPredicate.register(MatrixSlice) def _(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.upper_triangular(expr.parent), assumptions) @UpperTriangularPredicate.register(Factorization) def _(expr, assumptions): return _Factorization(Q.upper_triangular, expr, assumptions) # LowerTriangularPredicate @LowerTriangularPredicate.register(MatMul) def _(expr, assumptions): factor, matrices = expr.as_coeff_matrices() if all(ask(Q.lower_triangular(m), assumptions) for m in matrices): return True @LowerTriangularPredicate.register(MatAdd) def _(expr, assumptions): if all(ask(Q.lower_triangular(arg), assumptions) for arg in expr.args): return True @LowerTriangularPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None non_negative = ask(~Q.negative(exp), assumptions) if (non_negative or non_negative == False and ask(Q.invertible(base), assumptions)): return ask(Q.lower_triangular(base), assumptions) return None @LowerTriangularPredicate.register(MatrixSymbol) def _(expr, assumptions): if Q.lower_triangular(expr) in conjuncts(assumptions): return True @LowerTriangularPredicate.register_many(Identity, ZeroMatrix) def _(expr, assumptions): return True @LowerTriangularPredicate.register(OneMatrix) def _(expr, assumptions): return expr.shape[0] == 1 and expr.shape[1] == 1 @LowerTriangularPredicate.register(Transpose) def _(expr, assumptions): return ask(Q.upper_triangular(expr.arg), assumptions) @LowerTriangularPredicate.register(Inverse) def _(expr, assumptions): return ask(Q.lower_triangular(expr.arg), assumptions) @LowerTriangularPredicate.register(MatrixSlice) def _(expr, assumptions): if not expr.on_diag: return None else: return ask(Q.lower_triangular(expr.parent), assumptions) @LowerTriangularPredicate.register(Factorization) def _(expr, assumptions): return _Factorization(Q.lower_triangular, expr, assumptions) # DiagonalPredicate def _is_empty_or_1x1(expr): return expr.shape == (0, 0) or expr.shape == (1, 1) @DiagonalPredicate.register(MatMul) def _(expr, assumptions): if _is_empty_or_1x1(expr): return True factor, matrices = expr.as_coeff_matrices() if all(ask(Q.diagonal(m), assumptions) for m in matrices): return True @DiagonalPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None non_negative = ask(~Q.negative(exp), assumptions) if (non_negative or non_negative == False and ask(Q.invertible(base), assumptions)): return ask(Q.diagonal(base), assumptions) return None @DiagonalPredicate.register(MatAdd) def _(expr, assumptions): if all(ask(Q.diagonal(arg), assumptions) for arg in expr.args): return True @DiagonalPredicate.register(MatrixSymbol) def _(expr, assumptions): if _is_empty_or_1x1(expr): return True if Q.diagonal(expr) in conjuncts(assumptions): return True @DiagonalPredicate.register(OneMatrix) def _(expr, assumptions): return expr.shape[0] == 1 and expr.shape[1] == 1 @DiagonalPredicate.register_many(Inverse, Transpose) def _(expr, assumptions): return ask(Q.diagonal(expr.arg), assumptions) @DiagonalPredicate.register(MatrixSlice) def _(expr, assumptions): if _is_empty_or_1x1(expr): return True if not expr.on_diag: return None else: return ask(Q.diagonal(expr.parent), assumptions) @DiagonalPredicate.register_many(DiagonalMatrix, DiagMatrix, Identity, ZeroMatrix) def _(expr, assumptions): return True @DiagonalPredicate.register(Factorization) def _(expr, assumptions): return _Factorization(Q.diagonal, expr, assumptions) # IntegerElementsPredicate def BM_elements(predicate, expr, assumptions): """ Block Matrix elements. """ return all(ask(predicate(b), assumptions) for b in expr.blocks) def MS_elements(predicate, expr, assumptions): """ Matrix Slice elements. """ return ask(predicate(expr.parent), assumptions) def MatMul_elements(matrix_predicate, scalar_predicate, expr, assumptions): d = sift(expr.args, lambda x: isinstance(x, MatrixExpr)) factors, matrices = d[False], d[True] return fuzzy_and([ test_closed_group(Basic(*factors), assumptions, scalar_predicate), test_closed_group(Basic(*matrices), assumptions, matrix_predicate)]) @IntegerElementsPredicate.register_many(Determinant, HadamardProduct, MatAdd, Trace, Transpose) def _(expr, assumptions): return test_closed_group(expr, assumptions, Q.integer_elements) @IntegerElementsPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None if exp.is_negative == False: return ask(Q.integer_elements(base), assumptions) return None @IntegerElementsPredicate.register_many(Identity, OneMatrix, ZeroMatrix) def _(expr, assumptions): return True @IntegerElementsPredicate.register(MatMul) def _(expr, assumptions): return MatMul_elements(Q.integer_elements, Q.integer, expr, assumptions) @IntegerElementsPredicate.register(MatrixSlice) def _(expr, assumptions): return MS_elements(Q.integer_elements, expr, assumptions) @IntegerElementsPredicate.register(BlockMatrix) def _(expr, assumptions): return BM_elements(Q.integer_elements, expr, assumptions) # RealElementsPredicate @RealElementsPredicate.register_many(Determinant, Factorization, HadamardProduct, MatAdd, Trace, Transpose) def _(expr, assumptions): return test_closed_group(expr, assumptions, Q.real_elements) @RealElementsPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None non_negative = ask(~Q.negative(exp), assumptions) if (non_negative or non_negative == False and ask(Q.invertible(base), assumptions)): return ask(Q.real_elements(base), assumptions) return None @RealElementsPredicate.register(MatMul) def _(expr, assumptions): return MatMul_elements(Q.real_elements, Q.real, expr, assumptions) @RealElementsPredicate.register(MatrixSlice) def _(expr, assumptions): return MS_elements(Q.real_elements, expr, assumptions) @RealElementsPredicate.register(BlockMatrix) def _(expr, assumptions): return BM_elements(Q.real_elements, expr, assumptions) # ComplexElementsPredicate @ComplexElementsPredicate.register_many(Determinant, Factorization, HadamardProduct, Inverse, MatAdd, Trace, Transpose) def _(expr, assumptions): return test_closed_group(expr, assumptions, Q.complex_elements) @ComplexElementsPredicate.register(MatPow) def _(expr, assumptions): # only for integer powers base, exp = expr.args int_exp = ask(Q.integer(exp), assumptions) if not int_exp: return None non_negative = ask(~Q.negative(exp), assumptions) if (non_negative or non_negative == False and ask(Q.invertible(base), assumptions)): return ask(Q.complex_elements(base), assumptions) return None @ComplexElementsPredicate.register(MatMul) def _(expr, assumptions): return MatMul_elements(Q.complex_elements, Q.complex, expr, assumptions) @ComplexElementsPredicate.register(MatrixSlice) def _(expr, assumptions): return MS_elements(Q.complex_elements, expr, assumptions) @ComplexElementsPredicate.register(BlockMatrix) def _(expr, assumptions): return BM_elements(Q.complex_elements, expr, assumptions) @ComplexElementsPredicate.register(DFT) def _(expr, assumptions): return True sympy-sympy-1.9/sympy/assumptions/handlers/ntheory.py000066400000000000000000000160551412543434000233420ustar00rootroot00000000000000""" Handlers for keys related to number theory: prime, even, odd, etc. """ from sympy.assumptions import Q, ask from sympy.core import Add, Basic, Expr, Float, Mul, Pow, S from sympy.core.numbers import (ImaginaryUnit, Infinity, Integer, NaN, NegativeInfinity, NumberSymbol, Rational) from sympy.functions import Abs, im, re from sympy.ntheory import isprime from sympy.multipledispatch import MDNotImplementedError from ..predicates.ntheory import (PrimePredicate, CompositePredicate, EvenPredicate, OddPredicate) # PrimePredicate def _PrimePredicate_number(expr, assumptions): # helper method exact = not expr.atoms(Float) try: i = int(expr.round()) if (expr - i).equals(0) is False: raise TypeError except TypeError: return False if exact: return isprime(i) # when not exact, we won't give a True or False # since the number represents an approximate value @PrimePredicate.register(Expr) def _(expr, assumptions): ret = expr.is_prime if ret is None: raise MDNotImplementedError return ret @PrimePredicate.register(Basic) def _(expr, assumptions): if expr.is_number: return _PrimePredicate_number(expr, assumptions) @PrimePredicate.register(Mul) def _(expr, assumptions): if expr.is_number: return _PrimePredicate_number(expr, assumptions) for arg in expr.args: if not ask(Q.integer(arg), assumptions): return None for arg in expr.args: if arg.is_number and arg.is_composite: return False @PrimePredicate.register(Pow) def _(expr, assumptions): """ Integer**Integer -> !Prime """ if expr.is_number: return _PrimePredicate_number(expr, assumptions) if ask(Q.integer(expr.exp), assumptions) and \ ask(Q.integer(expr.base), assumptions): return False @PrimePredicate.register(Integer) def _(expr, assumptions): return isprime(expr) @PrimePredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit) def _(expr, assumptions): return False @PrimePredicate.register(Float) def _(expr, assumptions): return _PrimePredicate_number(expr, assumptions) @PrimePredicate.register(NumberSymbol) def _(expr, assumptions): return _PrimePredicate_number(expr, assumptions) @PrimePredicate.register(NaN) def _(expr, assumptions): return None # CompositePredicate @CompositePredicate.register(Expr) def _(expr, assumptions): ret = expr.is_composite if ret is None: raise MDNotImplementedError return ret @CompositePredicate.register(Basic) def _(expr, assumptions): _positive = ask(Q.positive(expr), assumptions) if _positive: _integer = ask(Q.integer(expr), assumptions) if _integer: _prime = ask(Q.prime(expr), assumptions) if _prime is None: return # Positive integer which is not prime is not # necessarily composite if expr.equals(1): return False return not _prime else: return _integer else: return _positive # EvenPredicate def _EvenPredicate_number(expr, assumptions): # helper method try: i = int(expr.round()) if not (expr - i).equals(0): raise TypeError except TypeError: return False if isinstance(expr, (float, Float)): return False return i % 2 == 0 @EvenPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_even if ret is None: raise MDNotImplementedError return ret @EvenPredicate.register(Basic) def _(expr, assumptions): if expr.is_number: return _EvenPredicate_number(expr, assumptions) @EvenPredicate.register(Mul) def _(expr, assumptions): """ Even * Integer -> Even Even * Odd -> Even Integer * Odd -> ? Odd * Odd -> Odd Even * Even -> Even Integer * Integer -> Even if Integer + Integer = Odd otherwise -> ? """ if expr.is_number: return _EvenPredicate_number(expr, assumptions) even, odd, irrational, acc = False, 0, False, 1 for arg in expr.args: # check for all integers and at least one even if ask(Q.integer(arg), assumptions): if ask(Q.even(arg), assumptions): even = True elif ask(Q.odd(arg), assumptions): odd += 1 elif not even and acc != 1: if ask(Q.odd(acc + arg), assumptions): even = True elif ask(Q.irrational(arg), assumptions): # one irrational makes the result False # two makes it undefined if irrational: break irrational = True else: break acc = arg else: if irrational: return False if even: return True if odd == len(expr.args): return False @EvenPredicate.register(Add) def _(expr, assumptions): """ Even + Odd -> Odd Even + Even -> Even Odd + Odd -> Even """ if expr.is_number: return _EvenPredicate_number(expr, assumptions) _result = True for arg in expr.args: if ask(Q.even(arg), assumptions): pass elif ask(Q.odd(arg), assumptions): _result = not _result else: break else: return _result @EvenPredicate.register(Pow) def _(expr, assumptions): if expr.is_number: return _EvenPredicate_number(expr, assumptions) if ask(Q.integer(expr.exp), assumptions): if ask(Q.positive(expr.exp), assumptions): return ask(Q.even(expr.base), assumptions) elif ask(~Q.negative(expr.exp) & Q.odd(expr.base), assumptions): return False elif expr.base is S.NegativeOne: return False @EvenPredicate.register(Integer) def _(expr, assumptions): return not bool(expr.p & 1) @EvenPredicate.register_many(Rational, Infinity, NegativeInfinity, ImaginaryUnit) def _(expr, assumptions): return False @EvenPredicate.register(NumberSymbol) def _(expr, assumptions): return _EvenPredicate_number(expr, assumptions) @EvenPredicate.register(Abs) def _(expr, assumptions): if ask(Q.real(expr.args[0]), assumptions): return ask(Q.even(expr.args[0]), assumptions) @EvenPredicate.register(re) def _(expr, assumptions): if ask(Q.real(expr.args[0]), assumptions): return ask(Q.even(expr.args[0]), assumptions) @EvenPredicate.register(im) def _(expr, assumptions): if ask(Q.real(expr.args[0]), assumptions): return True @EvenPredicate.register(NaN) def _(expr, assumptions): return None # OddPredicate @OddPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_odd if ret is None: raise MDNotImplementedError return ret @OddPredicate.register(Basic) def _(expr, assumptions): _integer = ask(Q.integer(expr), assumptions) if _integer: _even = ask(Q.even(expr), assumptions) if _even is None: return None return not _even return _integer sympy-sympy-1.9/sympy/assumptions/handlers/order.py000066400000000000000000000277731412543434000227760ustar00rootroot00000000000000""" Handlers related to order relations: positive, negative, etc. """ from sympy.assumptions import Q, ask from sympy.core import Add, Basic, Expr, Mul, Pow from sympy.core.logic import fuzzy_not, fuzzy_and, fuzzy_or from sympy.core.numbers import E, ImaginaryUnit, NaN from sympy.functions import Abs, acos, acot, asin, atan, exp, factorial, log from sympy.matrices import Determinant, Trace from sympy.matrices.expressions.matexpr import MatrixElement from sympy.multipledispatch import MDNotImplementedError from ..predicates.order import (NegativePredicate, NonNegativePredicate, NonZeroPredicate, ZeroPredicate, NonPositivePredicate, PositivePredicate, ExtendedNegativePredicate, ExtendedNonNegativePredicate, ExtendedNonPositivePredicate, ExtendedNonZeroPredicate, ExtendedPositivePredicate,) # NegativePredicate def _NegativePredicate_number(expr, assumptions): r, i = expr.as_real_imag() # If the imaginary part can symbolically be shown to be zero then # we just evaluate the real part; otherwise we evaluate the imaginary # part to see if it actually evaluates to zero and if it does then # we make the comparison between the real part and zero. if not i: r = r.evalf(2) if r._prec != 1: return r < 0 else: i = i.evalf(2) if i._prec != 1: if i != 0: return False r = r.evalf(2) if r._prec != 1: return r < 0 @NegativePredicate.register(Basic) def _(expr, assumptions): if expr.is_number: return _NegativePredicate_number(expr, assumptions) @NegativePredicate.register(Expr) def _(expr, assumptions): ret = expr.is_negative if ret is None: raise MDNotImplementedError return ret @NegativePredicate.register(Add) def _(expr, assumptions): """ Positive + Positive -> Positive, Negative + Negative -> Negative """ if expr.is_number: return _NegativePredicate_number(expr, assumptions) r = ask(Q.real(expr), assumptions) if r is not True: return r nonpos = 0 for arg in expr.args: if ask(Q.negative(arg), assumptions) is not True: if ask(Q.positive(arg), assumptions) is False: nonpos += 1 else: break else: if nonpos < len(expr.args): return True @NegativePredicate.register(Mul) def _(expr, assumptions): if expr.is_number: return _NegativePredicate_number(expr, assumptions) result = None for arg in expr.args: if result is None: result = False if ask(Q.negative(arg), assumptions): result = not result elif ask(Q.positive(arg), assumptions): pass else: return return result @NegativePredicate.register(Pow) def _(expr, assumptions): """ Real ** Even -> NonNegative Real ** Odd -> same_as_base NonNegative ** Positive -> NonNegative """ if expr.base == E: # Exponential is always positive: if ask(Q.real(expr.exp), assumptions): return False return if expr.is_number: return _NegativePredicate_number(expr, assumptions) if ask(Q.real(expr.base), assumptions): if ask(Q.positive(expr.base), assumptions): if ask(Q.real(expr.exp), assumptions): return False if ask(Q.even(expr.exp), assumptions): return False if ask(Q.odd(expr.exp), assumptions): return ask(Q.negative(expr.base), assumptions) @NegativePredicate.register_many(Abs, ImaginaryUnit) def _(expr, assumptions): return False @NegativePredicate.register(exp) def _(expr, assumptions): if ask(Q.real(expr.exp), assumptions): return False raise MDNotImplementedError # NonNegativePredicate @NonNegativePredicate.register(Basic) def _(expr, assumptions): if expr.is_number: notnegative = fuzzy_not(_NegativePredicate_number(expr, assumptions)) if notnegative: return ask(Q.real(expr), assumptions) else: return notnegative @NonNegativePredicate.register(Expr) def _(expr, assumptions): ret = expr.is_nonnegative if ret is None: raise MDNotImplementedError return ret # NonZeroPredicate @NonZeroPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_nonzero if ret is None: raise MDNotImplementedError return ret @NonZeroPredicate.register(Basic) def _(expr, assumptions): if ask(Q.real(expr)) is False: return False if expr.is_number: # if there are no symbols just evalf i = expr.evalf(2) def nonz(i): if i._prec != 1: return i != 0 return fuzzy_or(nonz(i) for i in i.as_real_imag()) @NonZeroPredicate.register(Add) def _(expr, assumptions): if all(ask(Q.positive(x), assumptions) for x in expr.args) \ or all(ask(Q.negative(x), assumptions) for x in expr.args): return True @NonZeroPredicate.register(Mul) def _(expr, assumptions): for arg in expr.args: result = ask(Q.nonzero(arg), assumptions) if result: continue return result return True @NonZeroPredicate.register(Pow) def _(expr, assumptions): return ask(Q.nonzero(expr.base), assumptions) @NonZeroPredicate.register(Abs) def _(expr, assumptions): return ask(Q.nonzero(expr.args[0]), assumptions) @NonZeroPredicate.register(NaN) def _(expr, assumptions): return None # ZeroPredicate @ZeroPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_zero if ret is None: raise MDNotImplementedError return ret @ZeroPredicate.register(Basic) def _(expr, assumptions): return fuzzy_and([fuzzy_not(ask(Q.nonzero(expr), assumptions)), ask(Q.real(expr), assumptions)]) @ZeroPredicate.register(Mul) def _(expr, assumptions): # TODO: This should be deducible from the nonzero handler return fuzzy_or(ask(Q.zero(arg), assumptions) for arg in expr.args) # NonPositivePredicate @NonPositivePredicate.register(Expr) def _(expr, assumptions): ret = expr.is_nonpositive if ret is None: raise MDNotImplementedError return ret @NonPositivePredicate.register(Basic) def _(expr, assumptions): if expr.is_number: notpositive = fuzzy_not(_PositivePredicate_number(expr, assumptions)) if notpositive: return ask(Q.real(expr), assumptions) else: return notpositive # PositivePredicate def _PositivePredicate_number(expr, assumptions): r, i = expr.as_real_imag() # If the imaginary part can symbolically be shown to be zero then # we just evaluate the real part; otherwise we evaluate the imaginary # part to see if it actually evaluates to zero and if it does then # we make the comparison between the real part and zero. if not i: r = r.evalf(2) if r._prec != 1: return r > 0 else: i = i.evalf(2) if i._prec != 1: if i != 0: return False r = r.evalf(2) if r._prec != 1: return r > 0 @PositivePredicate.register(Expr) def _(expr, assumptions): ret = expr.is_positive if ret is None: raise MDNotImplementedError return ret @PositivePredicate.register(Basic) def _(expr, assumptions): if expr.is_number: return _PositivePredicate_number(expr, assumptions) @PositivePredicate.register(Mul) def _(expr, assumptions): if expr.is_number: return _PositivePredicate_number(expr, assumptions) result = True for arg in expr.args: if ask(Q.positive(arg), assumptions): continue elif ask(Q.negative(arg), assumptions): result = result ^ True else: return return result @PositivePredicate.register(Add) def _(expr, assumptions): if expr.is_number: return _PositivePredicate_number(expr, assumptions) r = ask(Q.real(expr), assumptions) if r is not True: return r nonneg = 0 for arg in expr.args: if ask(Q.positive(arg), assumptions) is not True: if ask(Q.negative(arg), assumptions) is False: nonneg += 1 else: break else: if nonneg < len(expr.args): return True @PositivePredicate.register(Pow) def _(expr, assumptions): if expr.base == E: if ask(Q.real(expr.exp), assumptions): return True if ask(Q.imaginary(expr.exp), assumptions): from sympy import pi, I return ask(Q.even(expr.exp/(I*pi)), assumptions) return if expr.is_number: return _PositivePredicate_number(expr, assumptions) if ask(Q.positive(expr.base), assumptions): if ask(Q.real(expr.exp), assumptions): return True if ask(Q.negative(expr.base), assumptions): if ask(Q.even(expr.exp), assumptions): return True if ask(Q.odd(expr.exp), assumptions): return False @PositivePredicate.register(exp) def _(expr, assumptions): if ask(Q.real(expr.exp), assumptions): return True if ask(Q.imaginary(expr.exp), assumptions): from sympy import pi, I return ask(Q.even(expr.exp/(I*pi)), assumptions) @PositivePredicate.register(log) def _(expr, assumptions): r = ask(Q.real(expr.args[0]), assumptions) if r is not True: return r if ask(Q.positive(expr.args[0] - 1), assumptions): return True if ask(Q.negative(expr.args[0] - 1), assumptions): return False @PositivePredicate.register(factorial) def _(expr, assumptions): x = expr.args[0] if ask(Q.integer(x) & Q.positive(x), assumptions): return True @PositivePredicate.register(ImaginaryUnit) def _(expr, assumptions): return False @PositivePredicate.register(Abs) def _(expr, assumptions): return ask(Q.nonzero(expr), assumptions) @PositivePredicate.register(Trace) def _(expr, assumptions): if ask(Q.positive_definite(expr.arg), assumptions): return True @PositivePredicate.register(Determinant) def _(expr, assumptions): if ask(Q.positive_definite(expr.arg), assumptions): return True @PositivePredicate.register(MatrixElement) def _(expr, assumptions): if (expr.i == expr.j and ask(Q.positive_definite(expr.parent), assumptions)): return True @PositivePredicate.register(atan) def _(expr, assumptions): return ask(Q.positive(expr.args[0]), assumptions) @PositivePredicate.register(asin) def _(expr, assumptions): x = expr.args[0] if ask(Q.positive(x) & Q.nonpositive(x - 1), assumptions): return True if ask(Q.negative(x) & Q.nonnegative(x + 1), assumptions): return False @PositivePredicate.register(acos) def _(expr, assumptions): x = expr.args[0] if ask(Q.nonpositive(x - 1) & Q.nonnegative(x + 1), assumptions): return True @PositivePredicate.register(acot) def _(expr, assumptions): return ask(Q.real(expr.args[0]), assumptions) @PositivePredicate.register(NaN) def _(expr, assumptions): return None # ExtendedNegativePredicate @ExtendedNegativePredicate.register(object) def _(expr, assumptions): return ask(Q.negative(expr) | Q.negative_infinite(expr), assumptions) # ExtendedPositivePredicate @ExtendedPositivePredicate.register(object) def _(expr, assumptions): return ask(Q.positive(expr) | Q.positive_infinite(expr), assumptions) # ExtendedNonZeroPredicate @ExtendedNonZeroPredicate.register(object) def _(expr, assumptions): return ask( Q.negative_infinite(expr) | Q.negative(expr) | Q.positive(expr) | Q.positive_infinite(expr), assumptions) # ExtendedNonPositivePredicate @ExtendedNonPositivePredicate.register(object) def _(expr, assumptions): return ask( Q.negative_infinite(expr) | Q.negative(expr) | Q.zero(expr), assumptions) # ExtendedNonNegativePredicate @ExtendedNonNegativePredicate.register(object) def _(expr, assumptions): return ask( Q.zero(expr) | Q.positive(expr) | Q.positive_infinite(expr), assumptions) sympy-sympy-1.9/sympy/assumptions/handlers/sets.py000066400000000000000000000551741412543434000226350ustar00rootroot00000000000000""" Handlers for predicates related to set membership: integer, rational, etc. """ from sympy.assumptions import Q, ask from sympy.core import Add, Basic, Expr, Mul, Pow from sympy.core.numbers import (AlgebraicNumber, ComplexInfinity, Exp1, Float, GoldenRatio, ImaginaryUnit, Infinity, Integer, NaN, NegativeInfinity, Number, NumberSymbol, Pi, pi, Rational, TribonacciConstant, E) from sympy.core.logic import fuzzy_bool from sympy.functions import (Abs, acos, acot, asin, atan, cos, cot, exp, im, log, re, sin, tan) from sympy import I, Eq, conjugate from sympy.matrices import Determinant, MatrixBase, Trace from sympy.matrices.expressions.matexpr import MatrixElement from sympy.multipledispatch import MDNotImplementedError from .common import test_closed_group from ..predicates.sets import (IntegerPredicate, RationalPredicate, IrrationalPredicate, RealPredicate, ExtendedRealPredicate, HermitianPredicate, ComplexPredicate, ImaginaryPredicate, AntihermitianPredicate, AlgebraicPredicate) # IntegerPredicate def _IntegerPredicate_number(expr, assumptions): # helper function try: i = int(expr.round()) if not (expr - i).equals(0): raise TypeError return True except TypeError: return False @IntegerPredicate.register_many(int, Integer) def _(expr, assumptions): return True @IntegerPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity, NegativeInfinity, Pi, Rational, TribonacciConstant) def _(expr, assumptions): return False @IntegerPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_integer if ret is None: raise MDNotImplementedError return ret @IntegerPredicate.register_many(Add, Pow) def _(expr, assumptions): """ * Integer + Integer -> Integer * Integer + !Integer -> !Integer * !Integer + !Integer -> ? """ if expr.is_number: return _IntegerPredicate_number(expr, assumptions) return test_closed_group(expr, assumptions, Q.integer) @IntegerPredicate.register(Mul) def _(expr, assumptions): """ * Integer*Integer -> Integer * Integer*Irrational -> !Integer * Odd/Even -> !Integer * Integer*Rational -> ? """ if expr.is_number: return _IntegerPredicate_number(expr, assumptions) _output = True for arg in expr.args: if not ask(Q.integer(arg), assumptions): if arg.is_Rational: if arg.q == 2: return ask(Q.even(2*expr), assumptions) if ~(arg.q & 1): return None elif ask(Q.irrational(arg), assumptions): if _output: _output = False else: return else: return return _output @IntegerPredicate.register(Abs) def _(expr, assumptions): return ask(Q.integer(expr.args[0]), assumptions) @IntegerPredicate.register_many(Determinant, MatrixElement, Trace) def _(expr, assumptions): return ask(Q.integer_elements(expr.args[0]), assumptions) # RationalPredicate @RationalPredicate.register(Rational) def _(expr, assumptions): return True @RationalPredicate.register(Float) def _(expr, assumptions): return None @RationalPredicate.register_many(Exp1, GoldenRatio, ImaginaryUnit, Infinity, NegativeInfinity, Pi, TribonacciConstant) def _(expr, assumptions): return False @RationalPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_rational if ret is None: raise MDNotImplementedError return ret @RationalPredicate.register_many(Add, Mul) def _(expr, assumptions): """ * Rational + Rational -> Rational * Rational + !Rational -> !Rational * !Rational + !Rational -> ? """ if expr.is_number: if expr.as_real_imag()[1]: return False return test_closed_group(expr, assumptions, Q.rational) @RationalPredicate.register(Pow) def _(expr, assumptions): """ * Rational ** Integer -> Rational * Irrational ** Rational -> Irrational * Rational ** Irrational -> ? """ if expr.base == E: x = expr.exp if ask(Q.rational(x), assumptions): return ask(~Q.nonzero(x), assumptions) return if ask(Q.integer(expr.exp), assumptions): return ask(Q.rational(expr.base), assumptions) elif ask(Q.rational(expr.exp), assumptions): if ask(Q.prime(expr.base), assumptions): return False @RationalPredicate.register_many(asin, atan, cos, sin, tan) def _(expr, assumptions): x = expr.args[0] if ask(Q.rational(x), assumptions): return ask(~Q.nonzero(x), assumptions) @RationalPredicate.register(exp) def _(expr, assumptions): x = expr.exp if ask(Q.rational(x), assumptions): return ask(~Q.nonzero(x), assumptions) @RationalPredicate.register_many(acot, cot) def _(expr, assumptions): x = expr.args[0] if ask(Q.rational(x), assumptions): return False @RationalPredicate.register_many(acos, log) def _(expr, assumptions): x = expr.args[0] if ask(Q.rational(x), assumptions): return ask(~Q.nonzero(x - 1), assumptions) # IrrationalPredicate @IrrationalPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_irrational if ret is None: raise MDNotImplementedError return ret @IrrationalPredicate.register(Basic) def _(expr, assumptions): _real = ask(Q.real(expr), assumptions) if _real: _rational = ask(Q.rational(expr), assumptions) if _rational is None: return None return not _rational else: return _real # RealPredicate def _RealPredicate_number(expr, assumptions): # let as_real_imag() work first since the expression may # be simpler to evaluate i = expr.as_real_imag()[1].evalf(2) if i._prec != 1: return not i # allow None to be returned if we couldn't show for sure # that i was 0 @RealPredicate.register_many(Abs, Exp1, Float, GoldenRatio, im, Pi, Rational, re, TribonacciConstant) def _(expr, assumptions): return True @RealPredicate.register_many(ImaginaryUnit, Infinity, NegativeInfinity) def _(expr, assumptions): return False @RealPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_real if ret is None: raise MDNotImplementedError return ret @RealPredicate.register(Add) def _(expr, assumptions): """ * Real + Real -> Real * Real + (Complex & !Real) -> !Real """ if expr.is_number: return _RealPredicate_number(expr, assumptions) return test_closed_group(expr, assumptions, Q.real) @RealPredicate.register(Mul) def _(expr, assumptions): """ * Real*Real -> Real * Real*Imaginary -> !Real * Imaginary*Imaginary -> Real """ if expr.is_number: return _RealPredicate_number(expr, assumptions) result = True for arg in expr.args: if ask(Q.real(arg), assumptions): pass elif ask(Q.imaginary(arg), assumptions): result = result ^ True else: break else: return result @RealPredicate.register(Pow) def _(expr, assumptions): """ * Real**Integer -> Real * Positive**Real -> Real * Real**(Integer/Even) -> Real if base is nonnegative * Real**(Integer/Odd) -> Real * Imaginary**(Integer/Even) -> Real * Imaginary**(Integer/Odd) -> not Real * Imaginary**Real -> ? since Real could be 0 (giving real) or 1 (giving imaginary) * b**Imaginary -> Real if log(b) is imaginary and b != 0 and exponent != integer multiple of I*pi/log(b) * Real**Real -> ? e.g. sqrt(-1) is imaginary and sqrt(2) is not """ if expr.is_number: return _RealPredicate_number(expr, assumptions) if expr.base == E: return ask( Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions ) if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E): if ask(Q.imaginary(expr.base.exp), assumptions): if ask(Q.imaginary(expr.exp), assumptions): return True # If the i = (exp's arg)/(I*pi) is an integer or half-integer # multiple of I*pi then 2*i will be an integer. In addition, # exp(i*I*pi) = (-1)**i so the overall realness of the expr # can be determined by replacing exp(i*I*pi) with (-1)**i. i = expr.base.exp/I/pi if ask(Q.integer(2*i), assumptions): return ask(Q.real(((-1)**i)**expr.exp), assumptions) return if ask(Q.imaginary(expr.base), assumptions): if ask(Q.integer(expr.exp), assumptions): odd = ask(Q.odd(expr.exp), assumptions) if odd is not None: return not odd return if ask(Q.imaginary(expr.exp), assumptions): imlog = ask(Q.imaginary(log(expr.base)), assumptions) if imlog is not None: # I**i -> real, log(I) is imag; # (2*I)**i -> complex, log(2*I) is not imag return imlog if ask(Q.real(expr.base), assumptions): if ask(Q.real(expr.exp), assumptions): if expr.exp.is_Rational and \ ask(Q.even(expr.exp.q), assumptions): return ask(Q.positive(expr.base), assumptions) elif ask(Q.integer(expr.exp), assumptions): return True elif ask(Q.positive(expr.base), assumptions): return True elif ask(Q.negative(expr.base), assumptions): return False @RealPredicate.register_many(cos, sin) def _(expr, assumptions): if ask(Q.real(expr.args[0]), assumptions): return True @RealPredicate.register(exp) def _(expr, assumptions): return ask( Q.integer(expr.exp/I/pi) | Q.real(expr.exp), assumptions ) @RealPredicate.register(log) def _(expr, assumptions): return ask(Q.positive(expr.args[0]), assumptions) @RealPredicate.register_many(Determinant, MatrixElement, Trace) def _(expr, assumptions): return ask(Q.real_elements(expr.args[0]), assumptions) # ExtendedRealPredicate @ExtendedRealPredicate.register(object) def _(expr, assumptions): return ask(Q.negative_infinite(expr) | Q.negative(expr) | Q.zero(expr) | Q.positive(expr) | Q.positive_infinite(expr), assumptions) @ExtendedRealPredicate.register_many(Infinity, NegativeInfinity) def _(expr, assumptions): return True @ExtendedRealPredicate.register_many(Add, Mul, Pow) def _(expr, assumptions): return test_closed_group(expr, assumptions, Q.extended_real) # HermitianPredicate @HermitianPredicate.register(object) def _(expr, assumptions): if isinstance(expr, MatrixBase): return None return ask(Q.real(expr), assumptions) @HermitianPredicate.register(Add) def _(expr, assumptions): """ * Hermitian + Hermitian -> Hermitian * Hermitian + !Hermitian -> !Hermitian """ if expr.is_number: raise MDNotImplementedError return test_closed_group(expr, assumptions, Q.hermitian) @HermitianPredicate.register(Mul) def _(expr, assumptions): """ As long as there is at most only one noncommutative term: * Hermitian*Hermitian -> Hermitian * Hermitian*Antihermitian -> !Hermitian * Antihermitian*Antihermitian -> Hermitian """ if expr.is_number: raise MDNotImplementedError nccount = 0 result = True for arg in expr.args: if ask(Q.antihermitian(arg), assumptions): result = result ^ True elif not ask(Q.hermitian(arg), assumptions): break if ask(~Q.commutative(arg), assumptions): nccount += 1 if nccount > 1: break else: return result @HermitianPredicate.register(Pow) def _(expr, assumptions): """ * Hermitian**Integer -> Hermitian """ if expr.is_number: raise MDNotImplementedError if expr.base == E: if ask(Q.hermitian(expr.exp), assumptions): return True raise MDNotImplementedError if ask(Q.hermitian(expr.base), assumptions): if ask(Q.integer(expr.exp), assumptions): return True raise MDNotImplementedError @HermitianPredicate.register_many(cos, sin) def _(expr, assumptions): if ask(Q.hermitian(expr.args[0]), assumptions): return True raise MDNotImplementedError @HermitianPredicate.register(exp) def _(expr, assumptions): if ask(Q.hermitian(expr.exp), assumptions): return True raise MDNotImplementedError @HermitianPredicate.register(MatrixBase) def _(mat, assumptions): rows, cols = mat.shape ret_val = True for i in range(rows): for j in range(i, cols): cond = fuzzy_bool(Eq(mat[i, j], conjugate(mat[j, i]))) if cond is None: ret_val = None if cond == False: return False if ret_val is None: raise MDNotImplementedError return ret_val # ComplexPredicate @ComplexPredicate.register_many(Abs, cos, exp, im, ImaginaryUnit, log, Number, NumberSymbol, re, sin) def _(expr, assumptions): return True @ComplexPredicate.register_many(Infinity, NegativeInfinity) def _(expr, assumptions): return False @ComplexPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_complex if ret is None: raise MDNotImplementedError return ret @ComplexPredicate.register_many(Add, Mul) def _(expr, assumptions): return test_closed_group(expr, assumptions, Q.complex) @ComplexPredicate.register(Pow) def _(expr, assumptions): if expr.base == E: return True return test_closed_group(expr, assumptions, Q.complex) @ComplexPredicate.register_many(Determinant, MatrixElement, Trace) def _(expr, assumptions): return ask(Q.complex_elements(expr.args[0]), assumptions) @ComplexPredicate.register(NaN) def _(expr, assumptions): return None # ImaginaryPredicate def _Imaginary_number(expr, assumptions): # let as_real_imag() work first since the expression may # be simpler to evaluate r = expr.as_real_imag()[0].evalf(2) if r._prec != 1: return not r # allow None to be returned if we couldn't show for sure # that r was 0 @ImaginaryPredicate.register(ImaginaryUnit) def _(expr, assumptions): return True @ImaginaryPredicate.register(Expr) def _(expr, assumptions): ret = expr.is_imaginary if ret is None: raise MDNotImplementedError return ret @ImaginaryPredicate.register(Add) def _(expr, assumptions): """ * Imaginary + Imaginary -> Imaginary * Imaginary + Complex -> ? * Imaginary + Real -> !Imaginary """ if expr.is_number: return _Imaginary_number(expr, assumptions) reals = 0 for arg in expr.args: if ask(Q.imaginary(arg), assumptions): pass elif ask(Q.real(arg), assumptions): reals += 1 else: break else: if reals == 0: return True if reals == 1 or (len(expr.args) == reals): # two reals could sum 0 thus giving an imaginary return False @ImaginaryPredicate.register(Mul) def _(expr, assumptions): """ * Real*Imaginary -> Imaginary * Imaginary*Imaginary -> Real """ if expr.is_number: return _Imaginary_number(expr, assumptions) result = False reals = 0 for arg in expr.args: if ask(Q.imaginary(arg), assumptions): result = result ^ True elif not ask(Q.real(arg), assumptions): break else: if reals == len(expr.args): return False return result @ImaginaryPredicate.register(Pow) def _(expr, assumptions): """ * Imaginary**Odd -> Imaginary * Imaginary**Even -> Real * b**Imaginary -> !Imaginary if exponent is an integer multiple of I*pi/log(b) * Imaginary**Real -> ? * Positive**Real -> Real * Negative**Integer -> Real * Negative**(Integer/2) -> Imaginary * Negative**Real -> not Imaginary if exponent is not Rational """ if expr.is_number: return _Imaginary_number(expr, assumptions) if expr.base == E: a = expr.exp/I/pi return ask(Q.integer(2*a) & ~Q.integer(a), assumptions) if expr.base.func == exp or (expr.base.is_Pow and expr.base.base == E): if ask(Q.imaginary(expr.base.exp), assumptions): if ask(Q.imaginary(expr.exp), assumptions): return False i = expr.base.exp/I/pi if ask(Q.integer(2*i), assumptions): return ask(Q.imaginary(((-1)**i)**expr.exp), assumptions) if ask(Q.imaginary(expr.base), assumptions): if ask(Q.integer(expr.exp), assumptions): odd = ask(Q.odd(expr.exp), assumptions) if odd is not None: return odd return if ask(Q.imaginary(expr.exp), assumptions): imlog = ask(Q.imaginary(log(expr.base)), assumptions) if imlog is not None: # I**i -> real; (2*I)**i -> complex ==> not imaginary return False if ask(Q.real(expr.base) & Q.real(expr.exp), assumptions): if ask(Q.positive(expr.base), assumptions): return False else: rat = ask(Q.rational(expr.exp), assumptions) if not rat: return rat if ask(Q.integer(expr.exp), assumptions): return False else: half = ask(Q.integer(2*expr.exp), assumptions) if half: return ask(Q.negative(expr.base), assumptions) return half @ImaginaryPredicate.register(log) def _(expr, assumptions): if ask(Q.real(expr.args[0]), assumptions): if ask(Q.positive(expr.args[0]), assumptions): return False return # XXX it should be enough to do # return ask(Q.nonpositive(expr.args[0]), assumptions) # but ask(Q.nonpositive(exp(x)), Q.imaginary(x)) -> None; # it should return True since exp(x) will be either 0 or complex if expr.args[0].func == exp or (expr.args[0].is_Pow and expr.args[0].base == E): if expr.args[0].exp in [I, -I]: return True im = ask(Q.imaginary(expr.args[0]), assumptions) if im is False: return False @ImaginaryPredicate.register(exp) def _(expr, assumptions): a = expr.exp/I/pi return ask(Q.integer(2*a) & ~Q.integer(a), assumptions) @ImaginaryPredicate.register_many(Number, NumberSymbol) def _(expr, assumptions): return not (expr.as_real_imag()[1] == 0) @ImaginaryPredicate.register(NaN) def _(expr, assumptions): return None # AntihermitianPredicate @AntihermitianPredicate.register(object) def _(expr, assumptions): if isinstance(expr, MatrixBase): return None if ask(Q.zero(expr), assumptions): return True return ask(Q.imaginary(expr), assumptions) @AntihermitianPredicate.register(Add) def _(expr, assumptions): """ * Antihermitian + Antihermitian -> Antihermitian * Antihermitian + !Antihermitian -> !Antihermitian """ if expr.is_number: raise MDNotImplementedError return test_closed_group(expr, assumptions, Q.antihermitian) @AntihermitianPredicate.register(Mul) def _(expr, assumptions): """ As long as there is at most only one noncommutative term: * Hermitian*Hermitian -> !Antihermitian * Hermitian*Antihermitian -> Antihermitian * Antihermitian*Antihermitian -> !Antihermitian """ if expr.is_number: raise MDNotImplementedError nccount = 0 result = False for arg in expr.args: if ask(Q.antihermitian(arg), assumptions): result = result ^ True elif not ask(Q.hermitian(arg), assumptions): break if ask(~Q.commutative(arg), assumptions): nccount += 1 if nccount > 1: break else: return result @AntihermitianPredicate.register(Pow) def _(expr, assumptions): """ * Hermitian**Integer -> !Antihermitian * Antihermitian**Even -> !Antihermitian * Antihermitian**Odd -> Antihermitian """ if expr.is_number: raise MDNotImplementedError if ask(Q.hermitian(expr.base), assumptions): if ask(Q.integer(expr.exp), assumptions): return False elif ask(Q.antihermitian(expr.base), assumptions): if ask(Q.even(expr.exp), assumptions): return False elif ask(Q.odd(expr.exp), assumptions): return True raise MDNotImplementedError @AntihermitianPredicate.register(MatrixBase) def _(mat, assumptions): rows, cols = mat.shape ret_val = True for i in range(rows): for j in range(i, cols): cond = fuzzy_bool(Eq(mat[i, j], -conjugate(mat[j, i]))) if cond is None: ret_val = None if cond == False: return False if ret_val is None: raise MDNotImplementedError return ret_val # AlgebraicPredicate @AlgebraicPredicate.register_many(AlgebraicNumber, Float, GoldenRatio, ImaginaryUnit, TribonacciConstant) def _(expr, assumptions): return True @AlgebraicPredicate.register_many(ComplexInfinity, Exp1, Infinity, NegativeInfinity, Pi) def _(expr, assumptions): return False @AlgebraicPredicate.register_many(Add, Mul) def _(expr, assumptions): return test_closed_group(expr, assumptions, Q.algebraic) @AlgebraicPredicate.register(Pow) def _(expr, assumptions): if expr.base == E: if ask(Q.algebraic(expr.exp), assumptions): return ask(~Q.nonzero(expr.exp), assumptions) return return expr.exp.is_Rational and ask(Q.algebraic(expr.base), assumptions) @AlgebraicPredicate.register(Rational) def _(expr, assumptions): return expr.q != 0 @AlgebraicPredicate.register_many(asin, atan, cos, sin, tan) def _(expr, assumptions): x = expr.args[0] if ask(Q.algebraic(x), assumptions): return ask(~Q.nonzero(x), assumptions) @AlgebraicPredicate.register(exp) def _(expr, assumptions): x = expr.exp if ask(Q.algebraic(x), assumptions): return ask(~Q.nonzero(x), assumptions) @AlgebraicPredicate.register_many(acot, cot) def _(expr, assumptions): x = expr.args[0] if ask(Q.algebraic(x), assumptions): return False @AlgebraicPredicate.register_many(acos, log) def _(expr, assumptions): x = expr.args[0] if ask(Q.algebraic(x), assumptions): return ask(~Q.nonzero(x - 1), assumptions) sympy-sympy-1.9/sympy/assumptions/predicates/000077500000000000000000000000001412543434000216145ustar00rootroot00000000000000sympy-sympy-1.9/sympy/assumptions/predicates/__init__.py000066400000000000000000000001561412543434000237270ustar00rootroot00000000000000""" Module to implement predicate classes. Class of every predicate registered to ``Q`` is defined here. """ sympy-sympy-1.9/sympy/assumptions/predicates/calculus.py000066400000000000000000000035411412543434000240040ustar00rootroot00000000000000from sympy.assumptions import Predicate from sympy.multipledispatch import Dispatcher class FinitePredicate(Predicate): """ Finite number predicate. Explanation =========== ``Q.finite(x)`` is true if ``x`` is a number but neither an infinity nor a ``NaN``. In other words, ``ask(Q.finite(x))`` is true for all numerical ``x`` having a bounded absolute value. Examples ======== >>> from sympy import Q, ask, S, oo, I, zoo >>> from sympy.abc import x >>> ask(Q.finite(oo)) False >>> ask(Q.finite(-oo)) False >>> ask(Q.finite(zoo)) False >>> ask(Q.finite(1)) True >>> ask(Q.finite(2 + 3*I)) True >>> ask(Q.finite(x), Q.positive(x)) True >>> print(ask(Q.finite(S.NaN))) None References ========== .. [1] https://en.wikipedia.org/wiki/Finite """ name = 'finite' handler = Dispatcher( "FiniteHandler", doc=("Handler for Q.finite. Test that an expression is bounded respect" " to all its variables.") ) class InfinitePredicate(Predicate): """ Infinite number predicate. ``Q.infinite(x)`` is true iff the absolute value of ``x`` is infinity. """ # TODO: Add examples name = 'infinite' handler = Dispatcher( "InfiniteHandler", doc="""Handler for Q.infinite key.""" ) class PositiveInfinitePredicate(Predicate): """ Positive infinity predicate. ``Q.positive_infinite(x)`` is true iff ``x`` is positive infinity ``oo``. """ name = 'positive_infinite' handler = Dispatcher("PositiveInfiniteHandler") class NegativeInfinitePredicate(Predicate): """ Negative infinity predicate. ``Q.negative_infinite(x)`` is true iff ``x`` is negative infinity ``-oo``. """ name = 'negative_infinite' handler = Dispatcher("NegativeInfiniteHandler") sympy-sympy-1.9/sympy/assumptions/predicates/common.py000066400000000000000000000043531412543434000234630ustar00rootroot00000000000000from sympy.assumptions import Predicate, AppliedPredicate, Q from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le from sympy.multipledispatch import Dispatcher class CommutativePredicate(Predicate): """ Commutative predicate. Explanation =========== ``ask(Q.commutative(x))`` is true iff ``x`` commutes with any other object with respect to multiplication operation. """ # TODO: Add examples name = 'commutative' handler = Dispatcher("CommutativeHandler", doc="Handler for key 'commutative'.") binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} class IsTruePredicate(Predicate): """ Generic predicate. Explanation =========== ``ask(Q.is_true(x))`` is true iff ``x`` is true. This only makes sense if ``x`` is a boolean object. Examples ======== >>> from sympy import ask, Q >>> from sympy.abc import x, y >>> ask(Q.is_true(True)) True Wrapping another applied predicate just returns the applied predicate. >>> Q.is_true(Q.even(x)) Q.even(x) Wrapping binary relation classes in SymPy core returns applied binary relational predicates. >>> from sympy.core import Eq, Gt >>> Q.is_true(Eq(x, y)) Q.eq(x, y) >>> Q.is_true(Gt(x, y)) Q.gt(x, y) Notes ===== This class is designed to wrap the boolean objects so that they can behave as if they are applied predicates. Consequently, wrapping another applied predicate is unnecessary and thus it just returns the argument. Also, binary relation classes in SymPy core have binary predicates to represent themselves and thus wrapping them with ``Q.is_true`` converts them to these applied predicates. """ name = 'is_true' handler = Dispatcher( "IsTrueHandler", doc="Wrapper allowing to query the truth value of a boolean expression." ) def __call__(self, arg): # No need to wrap another predicate if isinstance(arg, AppliedPredicate): return arg # Convert relational predicates instead of wrapping them if getattr(arg, "is_Relational", False): pred = binrelpreds[arg.func] return pred(*arg.args) return super().__call__(arg) sympy-sympy-1.9/sympy/assumptions/predicates/matrices.py000066400000000000000000000275671412543434000240160ustar00rootroot00000000000000from sympy.assumptions import Predicate from sympy.multipledispatch import Dispatcher class SquarePredicate(Predicate): """ Square matrix predicate. Explanation =========== ``Q.square(x)`` is true iff ``x`` is a square matrix. A square matrix is a matrix with the same number of rows and columns. Examples ======== >>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix, Identity >>> X = MatrixSymbol('X', 2, 2) >>> Y = MatrixSymbol('X', 2, 3) >>> ask(Q.square(X)) True >>> ask(Q.square(Y)) False >>> ask(Q.square(ZeroMatrix(3, 3))) True >>> ask(Q.square(Identity(3))) True References ========== .. [1] https://en.wikipedia.org/wiki/Square_matrix """ name = 'square' handler = Dispatcher("SquareHandler", doc="Handler for Q.square.") class SymmetricPredicate(Predicate): """ Symmetric matrix predicate. Explanation =========== ``Q.symmetric(x)`` is true iff ``x`` is a square matrix and is equal to its transpose. Every square diagonal matrix is a symmetric matrix. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 2, 2) >>> Y = MatrixSymbol('Y', 2, 3) >>> Z = MatrixSymbol('Z', 2, 2) >>> ask(Q.symmetric(X*Z), Q.symmetric(X) & Q.symmetric(Z)) True >>> ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z)) True >>> ask(Q.symmetric(Y)) False References ========== .. [1] https://en.wikipedia.org/wiki/Symmetric_matrix """ # TODO: Add handlers to make these keys work with # actual matrices and add more examples in the docstring. name = 'symmetric' handler = Dispatcher("SymmetricHandler", doc="Handler for Q.symmetric.") class InvertiblePredicate(Predicate): """ Invertible matrix predicate. Explanation =========== ``Q.invertible(x)`` is true iff ``x`` is an invertible matrix. A square matrix is called invertible only if its determinant is 0. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 2, 2) >>> Y = MatrixSymbol('Y', 2, 3) >>> Z = MatrixSymbol('Z', 2, 2) >>> ask(Q.invertible(X*Y), Q.invertible(X)) False >>> ask(Q.invertible(X*Z), Q.invertible(X) & Q.invertible(Z)) True >>> ask(Q.invertible(X), Q.fullrank(X) & Q.square(X)) True References ========== .. [1] https://en.wikipedia.org/wiki/Invertible_matrix """ name = 'invertible' handler = Dispatcher("InvertibleHandler", doc="Handler for Q.invertible.") class OrthogonalPredicate(Predicate): """ Orthogonal matrix predicate. Explanation =========== ``Q.orthogonal(x)`` is true iff ``x`` is an orthogonal matrix. A square matrix ``M`` is an orthogonal matrix if it satisfies ``M^TM = MM^T = I`` where ``M^T`` is the transpose matrix of ``M`` and ``I`` is an identity matrix. Note that an orthogonal matrix is necessarily invertible. Examples ======== >>> from sympy import Q, ask, MatrixSymbol, Identity >>> X = MatrixSymbol('X', 2, 2) >>> Y = MatrixSymbol('Y', 2, 3) >>> Z = MatrixSymbol('Z', 2, 2) >>> ask(Q.orthogonal(Y)) False >>> ask(Q.orthogonal(X*Z*X), Q.orthogonal(X) & Q.orthogonal(Z)) True >>> ask(Q.orthogonal(Identity(3))) True >>> ask(Q.invertible(X), Q.orthogonal(X)) True References ========== .. [1] https://en.wikipedia.org/wiki/Orthogonal_matrix """ name = 'orthogonal' handler = Dispatcher("OrthogonalHandler", doc="Handler for key 'orthogonal'.") class UnitaryPredicate(Predicate): """ Unitary matrix predicate. Explanation =========== ``Q.unitary(x)`` is true iff ``x`` is a unitary matrix. Unitary matrix is an analogue to orthogonal matrix. A square matrix ``M`` with complex elements is unitary if :math:``M^TM = MM^T= I`` where :math:``M^T`` is the conjugate transpose matrix of ``M``. Examples ======== >>> from sympy import Q, ask, MatrixSymbol, Identity >>> X = MatrixSymbol('X', 2, 2) >>> Y = MatrixSymbol('Y', 2, 3) >>> Z = MatrixSymbol('Z', 2, 2) >>> ask(Q.unitary(Y)) False >>> ask(Q.unitary(X*Z*X), Q.unitary(X) & Q.unitary(Z)) True >>> ask(Q.unitary(Identity(3))) True References ========== .. [1] https://en.wikipedia.org/wiki/Unitary_matrix """ name = 'unitary' handler = Dispatcher("UnitaryHandler", doc="Handler for key 'unitary'.") class FullRankPredicate(Predicate): """ Fullrank matrix predicate. Explanation =========== ``Q.fullrank(x)`` is true iff ``x`` is a full rank matrix. A matrix is full rank if all rows and columns of the matrix are linearly independent. A square matrix is full rank iff its determinant is nonzero. Examples ======== >>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix, Identity >>> X = MatrixSymbol('X', 2, 2) >>> ask(Q.fullrank(X.T), Q.fullrank(X)) True >>> ask(Q.fullrank(ZeroMatrix(3, 3))) False >>> ask(Q.fullrank(Identity(3))) True """ name = 'fullrank' handler = Dispatcher("FullRankHandler", doc="Handler for key 'fullrank'.") class PositiveDefinitePredicate(Predicate): r""" Positive definite matrix predicate. Explanation =========== If ``M`` is a :math:``n \times n`` symmetric real matrix, it is said to be positive definite if :math:`Z^TMZ` is positive for every non-zero column vector ``Z`` of ``n`` real numbers. Examples ======== >>> from sympy import Q, ask, MatrixSymbol, Identity >>> X = MatrixSymbol('X', 2, 2) >>> Y = MatrixSymbol('Y', 2, 3) >>> Z = MatrixSymbol('Z', 2, 2) >>> ask(Q.positive_definite(Y)) False >>> ask(Q.positive_definite(Identity(3))) True >>> ask(Q.positive_definite(X + Z), Q.positive_definite(X) & ... Q.positive_definite(Z)) True References ========== .. [1] https://en.wikipedia.org/wiki/Positive-definite_matrix """ name = "positive_definite" handler = Dispatcher("PositiveDefiniteHandler", doc="Handler for key 'positive_definite'.") class UpperTriangularPredicate(Predicate): """ Upper triangular matrix predicate. Explanation =========== A matrix ``M`` is called upper triangular matrix if :math:`M_{ij}=0` for :math:`i>> from sympy import Q, ask, ZeroMatrix, Identity >>> ask(Q.upper_triangular(Identity(3))) True >>> ask(Q.upper_triangular(ZeroMatrix(3, 3))) True References ========== .. [1] http://mathworld.wolfram.com/UpperTriangularMatrix.html """ name = "upper_triangular" handler = Dispatcher("UpperTriangularHandler", doc="Handler for key 'upper_triangular'.") class LowerTriangularPredicate(Predicate): """ Lower triangular matrix predicate. Explanation =========== A matrix ``M`` is called lower triangular matrix if :math:`a_{ij}=0` for :math:`i>j`. Examples ======== >>> from sympy import Q, ask, ZeroMatrix, Identity >>> ask(Q.lower_triangular(Identity(3))) True >>> ask(Q.lower_triangular(ZeroMatrix(3, 3))) True References ========== .. [1] http://mathworld.wolfram.com/LowerTriangularMatrix.html """ name = "lower_triangular" handler = Dispatcher("LowerTriangularHandler", doc="Handler for key 'lower_triangular'.") class DiagonalPredicate(Predicate): """ Diagonal matrix predicate. Explanation =========== ``Q.diagonal(x)`` is true iff ``x`` is a diagonal matrix. A diagonal matrix is a matrix in which the entries outside the main diagonal are all zero. Examples ======== >>> from sympy import Q, ask, MatrixSymbol, ZeroMatrix >>> X = MatrixSymbol('X', 2, 2) >>> ask(Q.diagonal(ZeroMatrix(3, 3))) True >>> ask(Q.diagonal(X), Q.lower_triangular(X) & ... Q.upper_triangular(X)) True References ========== .. [1] https://en.wikipedia.org/wiki/Diagonal_matrix """ name = "diagonal" handler = Dispatcher("DiagonalHandler", doc="Handler for key 'diagonal'.") class IntegerElementsPredicate(Predicate): """ Integer elements matrix predicate. Explanation =========== ``Q.integer_elements(x)`` is true iff all the elements of ``x`` are integers. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 4, 4) >>> ask(Q.integer(X[1, 2]), Q.integer_elements(X)) True """ name = "integer_elements" handler = Dispatcher("IntegerElementsHandler", doc="Handler for key 'integer_elements'.") class RealElementsPredicate(Predicate): """ Real elements matrix predicate. Explanation =========== ``Q.real_elements(x)`` is true iff all the elements of ``x`` are real numbers. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 4, 4) >>> ask(Q.real(X[1, 2]), Q.real_elements(X)) True """ name = "real_elements" handler = Dispatcher("RealElementsHandler", doc="Handler for key 'real_elements'.") class ComplexElementsPredicate(Predicate): """ Complex elements matrix predicate. Explanation =========== ``Q.complex_elements(x)`` is true iff all the elements of ``x`` are complex numbers. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 4, 4) >>> ask(Q.complex(X[1, 2]), Q.complex_elements(X)) True >>> ask(Q.complex_elements(X), Q.integer_elements(X)) True """ name = "complex_elements" handler = Dispatcher("ComplexElementsHandler", doc="Handler for key 'complex_elements'.") class SingularPredicate(Predicate): """ Singular matrix predicate. A matrix is singular iff the value of its determinant is 0. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 4, 4) >>> ask(Q.singular(X), Q.invertible(X)) False >>> ask(Q.singular(X), ~Q.invertible(X)) True References ========== .. [1] http://mathworld.wolfram.com/SingularMatrix.html """ name = "singular" handler = Dispatcher("SingularHandler", doc="Predicate fore key 'singular'.") class NormalPredicate(Predicate): """ Normal matrix predicate. A matrix is normal if it commutes with its conjugate transpose. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 4, 4) >>> ask(Q.normal(X), Q.unitary(X)) True References ========== .. [1] https://en.wikipedia.org/wiki/Normal_matrix """ name = "normal" handler = Dispatcher("NormalHandler", doc="Predicate fore key 'normal'.") class TriangularPredicate(Predicate): """ Triangular matrix predicate. Explanation =========== ``Q.triangular(X)`` is true if ``X`` is one that is either lower triangular or upper triangular. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 4, 4) >>> ask(Q.triangular(X), Q.upper_triangular(X)) True >>> ask(Q.triangular(X), Q.lower_triangular(X)) True References ========== .. [1] https://en.wikipedia.org/wiki/Triangular_matrix """ name = "triangular" handler = Dispatcher("TriangularHandler", doc="Predicate fore key 'triangular'.") class UnitTriangularPredicate(Predicate): """ Unit triangular matrix predicate. Explanation =========== A unit triangular matrix is a triangular matrix with 1s on the diagonal. Examples ======== >>> from sympy import Q, ask, MatrixSymbol >>> X = MatrixSymbol('X', 4, 4) >>> ask(Q.triangular(X), Q.unit_triangular(X)) True """ name = "unit_triangular" handler = Dispatcher("UnitTriangularHandler", doc="Predicate fore key 'unit_triangular'.") sympy-sympy-1.9/sympy/assumptions/predicates/ntheory.py000066400000000000000000000047621412543434000236670ustar00rootroot00000000000000from sympy.assumptions import Predicate from sympy.multipledispatch import Dispatcher class PrimePredicate(Predicate): """ Prime number predicate. Explanation =========== ``ask(Q.prime(x))`` is true iff ``x`` is a natural number greater than 1 that has no positive divisors other than ``1`` and the number itself. Examples ======== >>> from sympy import Q, ask >>> ask(Q.prime(0)) False >>> ask(Q.prime(1)) False >>> ask(Q.prime(2)) True >>> ask(Q.prime(20)) False >>> ask(Q.prime(-3)) False """ name = 'prime' handler = Dispatcher( "PrimeHandler", doc=("Handler for key 'prime'. Test that an expression represents a prime" " number. When the expression is an exact number, the result (when True)" " is subject to the limitations of isprime() which is used to return the " "result.") ) class CompositePredicate(Predicate): """ Composite number predicate. Explanation =========== ``ask(Q.composite(x))`` is true iff ``x`` is a positive integer and has at least one positive divisor other than ``1`` and the number itself. Examples ======== >>> from sympy import Q, ask >>> ask(Q.composite(0)) False >>> ask(Q.composite(1)) False >>> ask(Q.composite(2)) False >>> ask(Q.composite(20)) True """ name = 'composite' handler = Dispatcher("CompositeHandler", doc="Handler for key 'composite'.") class EvenPredicate(Predicate): """ Even number predicate. Explanation =========== ``ask(Q.even(x))`` is true iff ``x`` belongs to the set of even integers. Examples ======== >>> from sympy import Q, ask, pi >>> ask(Q.even(0)) True >>> ask(Q.even(2)) True >>> ask(Q.even(3)) False >>> ask(Q.even(pi)) False """ name = 'even' handler = Dispatcher("EvenHandler", doc="Handler for key 'even'.") class OddPredicate(Predicate): """ Odd number predicate. Explanation =========== ``ask(Q.odd(x))`` is true iff ``x`` belongs to the set of odd numbers. Examples ======== >>> from sympy import Q, ask, pi >>> ask(Q.odd(0)) False >>> ask(Q.odd(2)) False >>> ask(Q.odd(3)) True >>> ask(Q.odd(pi)) False """ name = 'odd' handler = Dispatcher( "OddHandler", doc=("Handler for key 'odd'. Test that an expression represents an odd" " number.") ) sympy-sympy-1.9/sympy/assumptions/predicates/order.py000066400000000000000000000224441412543434000233070ustar00rootroot00000000000000from sympy.assumptions import Predicate from sympy.multipledispatch import Dispatcher class NegativePredicate(Predicate): r""" Negative number predicate. Explanation =========== ``Q.negative(x)`` is true iff ``x`` is a real number and :math:`x < 0`, that is, it is in the interval :math:`(-\infty, 0)`. Note in particular that negative infinity is not negative. A few important facts about negative numbers: - Note that ``Q.nonnegative`` and ``~Q.negative`` are *not* the same thing. ``~Q.negative(x)`` simply means that ``x`` is not negative, whereas ``Q.nonnegative(x)`` means that ``x`` is real and not negative, i.e., ``Q.nonnegative(x)`` is logically equivalent to ``Q.zero(x) | Q.positive(x)``. So for example, ``~Q.negative(I)`` is true, whereas ``Q.nonnegative(I)`` is false. - See the documentation of ``Q.real`` for more information about related facts. Examples ======== >>> from sympy import Q, ask, symbols, I >>> x = symbols('x') >>> ask(Q.negative(x), Q.real(x) & ~Q.positive(x) & ~Q.zero(x)) True >>> ask(Q.negative(-1)) True >>> ask(Q.nonnegative(I)) False >>> ask(~Q.negative(I)) True """ name = 'negative' handler = Dispatcher( "NegativeHandler", doc=("Handler for Q.negative. Test that an expression is strictly less" " than zero.") ) class NonNegativePredicate(Predicate): """ Nonnegative real number predicate. Explanation =========== ``ask(Q.nonnegative(x))`` is true iff ``x`` belongs to the set of positive numbers including zero. - Note that ``Q.nonnegative`` and ``~Q.negative`` are *not* the same thing. ``~Q.negative(x)`` simply means that ``x`` is not negative, whereas ``Q.nonnegative(x)`` means that ``x`` is real and not negative, i.e., ``Q.nonnegative(x)`` is logically equivalent to ``Q.zero(x) | Q.positive(x)``. So for example, ``~Q.negative(I)`` is true, whereas ``Q.nonnegative(I)`` is false. Examples ======== >>> from sympy import Q, ask, I >>> ask(Q.nonnegative(1)) True >>> ask(Q.nonnegative(0)) True >>> ask(Q.nonnegative(-1)) False >>> ask(Q.nonnegative(I)) False >>> ask(Q.nonnegative(-I)) False """ name = 'nonnegative' handler = Dispatcher( "NonNegativeHandler", doc=("Handler for Q.nonnegative.") ) class NonZeroPredicate(Predicate): """ Nonzero real number predicate. Explanation =========== ``ask(Q.nonzero(x))`` is true iff ``x`` is real and ``x`` is not zero. Note in particular that ``Q.nonzero(x)`` is false if ``x`` is not real. Use ``~Q.zero(x)`` if you want the negation of being zero without any real assumptions. A few important facts about nonzero numbers: - ``Q.nonzero`` is logically equivalent to ``Q.positive | Q.negative``. - See the documentation of ``Q.real`` for more information about related facts. Examples ======== >>> from sympy import Q, ask, symbols, I, oo >>> x = symbols('x') >>> print(ask(Q.nonzero(x), ~Q.zero(x))) None >>> ask(Q.nonzero(x), Q.positive(x)) True >>> ask(Q.nonzero(x), Q.zero(x)) False >>> ask(Q.nonzero(0)) False >>> ask(Q.nonzero(I)) False >>> ask(~Q.zero(I)) True >>> ask(Q.nonzero(oo)) False """ name = 'nonzero' handler = Dispatcher( "NonZeroHandler", doc=("Handler for key 'zero'. Test that an expression is not identically" " zero.") ) class ZeroPredicate(Predicate): """ Zero number predicate. Explanation =========== ``ask(Q.zero(x))`` is true iff the value of ``x`` is zero. Examples ======== >>> from sympy import ask, Q, oo, symbols >>> x, y = symbols('x, y') >>> ask(Q.zero(0)) True >>> ask(Q.zero(1/oo)) True >>> print(ask(Q.zero(0*oo))) None >>> ask(Q.zero(1)) False >>> ask(Q.zero(x*y), Q.zero(x) | Q.zero(y)) True """ name = 'zero' handler = Dispatcher( "ZeroHandler", doc="Handler for key 'zero'." ) class NonPositivePredicate(Predicate): """ Nonpositive real number predicate. Explanation =========== ``ask(Q.nonpositive(x))`` is true iff ``x`` belongs to the set of negative numbers including zero. - Note that ``Q.nonpositive`` and ``~Q.positive`` are *not* the same thing. ``~Q.positive(x)`` simply means that ``x`` is not positive, whereas ``Q.nonpositive(x)`` means that ``x`` is real and not positive, i.e., ``Q.nonpositive(x)`` is logically equivalent to `Q.negative(x) | Q.zero(x)``. So for example, ``~Q.positive(I)`` is true, whereas ``Q.nonpositive(I)`` is false. Examples ======== >>> from sympy import Q, ask, I >>> ask(Q.nonpositive(-1)) True >>> ask(Q.nonpositive(0)) True >>> ask(Q.nonpositive(1)) False >>> ask(Q.nonpositive(I)) False >>> ask(Q.nonpositive(-I)) False """ name = 'nonpositive' handler = Dispatcher( "NonPositiveHandler", doc="Handler for key 'nonpositive'." ) class PositivePredicate(Predicate): r""" Positive real number predicate. Explanation =========== ``Q.positive(x)`` is true iff ``x`` is real and `x > 0`, that is if ``x`` is in the interval `(0, \infty)`. In particular, infinity is not positive. A few important facts about positive numbers: - Note that ``Q.nonpositive`` and ``~Q.positive`` are *not* the same thing. ``~Q.positive(x)`` simply means that ``x`` is not positive, whereas ``Q.nonpositive(x)`` means that ``x`` is real and not positive, i.e., ``Q.nonpositive(x)`` is logically equivalent to `Q.negative(x) | Q.zero(x)``. So for example, ``~Q.positive(I)`` is true, whereas ``Q.nonpositive(I)`` is false. - See the documentation of ``Q.real`` for more information about related facts. Examples ======== >>> from sympy import Q, ask, symbols, I >>> x = symbols('x') >>> ask(Q.positive(x), Q.real(x) & ~Q.negative(x) & ~Q.zero(x)) True >>> ask(Q.positive(1)) True >>> ask(Q.nonpositive(I)) False >>> ask(~Q.positive(I)) True """ name = 'positive' handler = Dispatcher( "PositiveHandler", doc=("Handler for key 'positive'. Test that an expression is strictly" " greater than zero.") ) class ExtendedPositivePredicate(Predicate): r""" Positive extended real number predicate. Explanation =========== ``Q.extended_positive(x)`` is true iff ``x`` is extended real and `x > 0`, that is if ``x`` is in the interval `(0, \infty]`. Examples ======== >>> from sympy import ask, I, oo, Q >>> ask(Q.extended_positive(1)) True >>> ask(Q.extended_positive(oo)) True >>> ask(Q.extended_positive(I)) False """ name = 'extended_positive' handler = Dispatcher("ExtendedPositiveHandler") class ExtendedNegativePredicate(Predicate): r""" Negative extended real number predicate. Explanation =========== ``Q.extended_negative(x)`` is true iff ``x`` is extended real and `x < 0`, that is if ``x`` is in the interval `[-\infty, 0)`. Examples ======== >>> from sympy import ask, I, oo, Q >>> ask(Q.extended_negative(-1)) True >>> ask(Q.extended_negative(-oo)) True >>> ask(Q.extended_negative(-I)) False """ name = 'extended_negative' handler = Dispatcher("ExtendedNegativeHandler") class ExtendedNonZeroPredicate(Predicate): """ Nonzero extended real number predicate. Explanation =========== ``ask(Q.extended_nonzero(x))`` is true iff ``x`` is extended real and ``x`` is not zero. Examples ======== >>> from sympy import ask, I, oo, Q >>> ask(Q.extended_nonzero(-1)) True >>> ask(Q.extended_nonzero(oo)) True >>> ask(Q.extended_nonzero(I)) False """ name = 'extended_nonzero' handler = Dispatcher("ExtendedNonZeroHandler") class ExtendedNonPositivePredicate(Predicate): """ Nonpositive extended real number predicate. Explanation =========== ``ask(Q.extended_nonpositive(x))`` is true iff ``x`` is extended real and ``x`` is not positive. Examples ======== >>> from sympy import ask, I, oo, Q >>> ask(Q.extended_nonpositive(-1)) True >>> ask(Q.extended_nonpositive(oo)) False >>> ask(Q.extended_nonpositive(0)) True >>> ask(Q.extended_nonpositive(I)) False """ name = 'extended_nonpositive' handler = Dispatcher("ExtendedNonPositiveHandler") class ExtendedNonNegativePredicate(Predicate): """ Nonnegative extended real number predicate. Explanation =========== ``ask(Q.extended_nonnegative(x))`` is true iff ``x`` is extended real and ``x`` is not negative. Examples ======== >>> from sympy import ask, I, oo, Q >>> ask(Q.extended_nonnegative(-1)) False >>> ask(Q.extended_nonnegative(oo)) True >>> ask(Q.extended_nonnegative(0)) True >>> ask(Q.extended_nonnegative(I)) False """ name = 'extended_nonnegative' handler = Dispatcher("ExtendedNonNegativeHandler") sympy-sympy-1.9/sympy/assumptions/predicates/sets.py000066400000000000000000000213401412543434000231440ustar00rootroot00000000000000from sympy.assumptions import Predicate from sympy.multipledispatch import Dispatcher class IntegerPredicate(Predicate): """ Integer predicate. Explanation =========== ``Q.integer(x)`` is true iff ``x`` belongs to the set of integer numbers. Examples ======== >>> from sympy import Q, ask, S >>> ask(Q.integer(5)) True >>> ask(Q.integer(S(1)/2)) False References ========== .. [1] https://en.wikipedia.org/wiki/Integer """ name = 'integer' handler = Dispatcher( "IntegerHandler", doc=("Handler for Q.integer.\n\n" "Test that an expression belongs to the field of integer numbers.") ) class RationalPredicate(Predicate): """ Rational number predicate. Explanation =========== ``Q.rational(x)`` is true iff ``x`` belongs to the set of rational numbers. Examples ======== >>> from sympy import ask, Q, pi, S >>> ask(Q.rational(0)) True >>> ask(Q.rational(S(1)/2)) True >>> ask(Q.rational(pi)) False References ========== https://en.wikipedia.org/wiki/Rational_number """ name = 'rational' handler = Dispatcher( "RationalHandler", doc=("Handler for Q.rational.\n\n" "Test that an expression belongs to the field of rational numbers.") ) class IrrationalPredicate(Predicate): """ Irrational number predicate. Explanation =========== ``Q.irrational(x)`` is true iff ``x`` is any real number that cannot be expressed as a ratio of integers. Examples ======== >>> from sympy import ask, Q, pi, S, I >>> ask(Q.irrational(0)) False >>> ask(Q.irrational(S(1)/2)) False >>> ask(Q.irrational(pi)) True >>> ask(Q.irrational(I)) False References ========== .. [1] https://en.wikipedia.org/wiki/Irrational_number """ name = 'irrational' handler = Dispatcher( "IrrationalHandler", doc=("Handler for Q.irrational.\n\n" "Test that an expression is irrational numbers.") ) class RealPredicate(Predicate): r""" Real number predicate. Explanation =========== ``Q.real(x)`` is true iff ``x`` is a real number, i.e., it is in the interval `(-\infty, \infty)`. Note that, in particular the infinities are not real. Use ``Q.extended_real`` if you want to consider those as well. A few important facts about reals: - Every real number is positive, negative, or zero. Furthermore, because these sets are pairwise disjoint, each real number is exactly one of those three. - Every real number is also complex. - Every real number is finite. - Every real number is either rational or irrational. - Every real number is either algebraic or transcendental. - The facts ``Q.negative``, ``Q.zero``, ``Q.positive``, ``Q.nonnegative``, ``Q.nonpositive``, ``Q.nonzero``, ``Q.integer``, ``Q.rational``, and ``Q.irrational`` all imply ``Q.real``, as do all facts that imply those facts. - The facts ``Q.algebraic``, and ``Q.transcendental`` do not imply ``Q.real``; they imply ``Q.complex``. An algebraic or transcendental number may or may not be real. - The "non" facts (i.e., ``Q.nonnegative``, ``Q.nonzero``, ``Q.nonpositive`` and ``Q.noninteger``) are not equivalent to not the fact, but rather, not the fact *and* ``Q.real``. For example, ``Q.nonnegative`` means ``~Q.negative & Q.real``. So for example, ``I`` is not nonnegative, nonzero, or nonpositive. Examples ======== >>> from sympy import Q, ask, symbols >>> x = symbols('x') >>> ask(Q.real(x), Q.positive(x)) True >>> ask(Q.real(0)) True References ========== .. [1] https://en.wikipedia.org/wiki/Real_number """ name = 'real' handler = Dispatcher( "RealHandler", doc=("Handler for Q.real.\n\n" "Test that an expression belongs to the field of real numbers.") ) class ExtendedRealPredicate(Predicate): r""" Extended real predicate. Explanation =========== ``Q.extended_real(x)`` is true iff ``x`` is a real number or `\{-\infty, \infty\}`. See documentation of ``Q.real`` for more information about related facts. Examples ======== >>> from sympy import ask, Q, oo, I >>> ask(Q.extended_real(1)) True >>> ask(Q.extended_real(I)) False >>> ask(Q.extended_real(oo)) True """ name = 'extended_real' handler = Dispatcher( "ExtendedRealHandler", doc=("Handler for Q.extended_real.\n\n" "Test that an expression belongs to the field of extended real\n" "numbers, that is real numbers union {Infinity, -Infinity}.") ) class HermitianPredicate(Predicate): """ Hermitian predicate. Explanation =========== ``ask(Q.hermitian(x))`` is true iff ``x`` belongs to the set of Hermitian operators. References ========== .. [1] http://mathworld.wolfram.com/HermitianOperator.html """ # TODO: Add examples name = 'hermitian' handler = Dispatcher( "HermitianHandler", doc=("Handler for Q.hermitian.\n\n" "Test that an expression belongs to the field of Hermitian operators.") ) class ComplexPredicate(Predicate): """ Complex number predicate. Explanation =========== ``Q.complex(x)`` is true iff ``x`` belongs to the set of complex numbers. Note that every complex number is finite. Examples ======== >>> from sympy import Q, Symbol, ask, I, oo >>> x = Symbol('x') >>> ask(Q.complex(0)) True >>> ask(Q.complex(2 + 3*I)) True >>> ask(Q.complex(oo)) False References ========== .. [1] https://en.wikipedia.org/wiki/Complex_number """ name = 'complex' handler = Dispatcher( "ComplexHandler", doc=("Handler for Q.complex.\n\n" "Test that an expression belongs to the field of complex numbers.") ) class ImaginaryPredicate(Predicate): """ Imaginary number predicate. Explanation =========== ``Q.imaginary(x)`` is true iff ``x`` can be written as a real number multiplied by the imaginary unit ``I``. Please note that ``0`` is not considered to be an imaginary number. Examples ======== >>> from sympy import Q, ask, I >>> ask(Q.imaginary(3*I)) True >>> ask(Q.imaginary(2 + 3*I)) False >>> ask(Q.imaginary(0)) False References ========== .. [1] https://en.wikipedia.org/wiki/Imaginary_number """ name = 'imaginary' handler = Dispatcher( "ImaginaryHandler", doc=("Handler for Q.imaginary.\n\n" "Test that an expression belongs to the field of imaginary numbers,\n" "that is, numbers in the form x*I, where x is real.") ) class AntihermitianPredicate(Predicate): """ Antihermitian predicate. Explanation =========== ``Q.antihermitian(x)`` is true iff ``x`` belongs to the field of antihermitian operators, i.e., operators in the form ``x*I``, where ``x`` is Hermitian. References ========== .. [1] http://mathworld.wolfram.com/HermitianOperator.html """ # TODO: Add examples name = 'antihermitian' handler = Dispatcher( "AntiHermitianHandler", doc=("Handler for Q.antihermitian.\n\n" "Test that an expression belongs to the field of anti-Hermitian\n" "operators, that is, operators in the form x*I, where x is Hermitian.") ) class AlgebraicPredicate(Predicate): r""" Algebraic number predicate. Explanation =========== ``Q.algebraic(x)`` is true iff ``x`` belongs to the set of algebraic numbers. ``x`` is algebraic if there is some polynomial in ``p(x)\in \mathbb\{Q\}[x]`` such that ``p(x) = 0``. Examples ======== >>> from sympy import ask, Q, sqrt, I, pi >>> ask(Q.algebraic(sqrt(2))) True >>> ask(Q.algebraic(I)) True >>> ask(Q.algebraic(pi)) False References ========== .. [1] https://en.wikipedia.org/wiki/Algebraic_number """ name = 'algebraic' AlgebraicHandler = Dispatcher( "AlgebraicHandler", doc="""Handler for Q.algebraic key.""" ) class TranscendentalPredicate(Predicate): """ Transcedental number predicate. Explanation =========== ``Q.transcendental(x)`` is true iff ``x`` belongs to the set of transcendental numbers. A transcendental number is a real or complex number that is not algebraic. """ # TODO: Add examples name = 'transcendental' handler = Dispatcher( "Transcendental", doc="""Handler for Q.transcendental key.""" ) sympy-sympy-1.9/sympy/assumptions/refine.py000066400000000000000000000273471412543434000213300ustar00rootroot00000000000000from typing import Dict, Callable from sympy.core import S, Add, Expr, Basic, Mul from sympy.logic.boolalg import Boolean from sympy.assumptions import ask, Q # type: ignore def refine(expr, assumptions=True): """ Simplify an expression using assumptions. Explanation =========== Unlike :func:`~.simplify()` which performs structural simplification without any assumption, this function transforms the expression into the form which is only valid under certain assumptions. Note that ``simplify()`` is generally not done in refining process. Refining boolean expression involves reducing it to ``S.true`` or ``S.false``. Unlike :func:`~.ask()`, the expression will not be reduced if the truth value cannot be determined. Examples ======== >>> from sympy import refine, sqrt, Q >>> from sympy.abc import x >>> refine(sqrt(x**2), Q.real(x)) Abs(x) >>> refine(sqrt(x**2), Q.positive(x)) x >>> refine(Q.real(x), Q.positive(x)) True >>> refine(Q.positive(x), Q.real(x)) Q.positive(x) See Also ======== sympy.simplify.simplify.simplify : Structural simplification without assumptions. sympy.assumptions.ask.ask : Query for boolean expressions using assumptions. """ if not isinstance(expr, Basic): return expr if not expr.is_Atom: args = [refine(arg, assumptions) for arg in expr.args] # TODO: this will probably not work with Integral or Polynomial expr = expr.func(*args) if hasattr(expr, '_eval_refine'): ref_expr = expr._eval_refine(assumptions) if ref_expr is not None: return ref_expr name = expr.__class__.__name__ handler = handlers_dict.get(name, None) if handler is None: return expr new_expr = handler(expr, assumptions) if (new_expr is None) or (expr == new_expr): return expr if not isinstance(new_expr, Expr): return new_expr return refine(new_expr, assumptions) def refine_abs(expr, assumptions): """ Handler for the absolute value. Examples ======== >>> from sympy import Q, Abs >>> from sympy.assumptions.refine import refine_abs >>> from sympy.abc import x >>> refine_abs(Abs(x), Q.real(x)) >>> refine_abs(Abs(x), Q.positive(x)) x >>> refine_abs(Abs(x), Q.negative(x)) -x """ from sympy.core.logic import fuzzy_not from sympy import Abs arg = expr.args[0] if ask(Q.real(arg), assumptions) and \ fuzzy_not(ask(Q.negative(arg), assumptions)): # if it's nonnegative return arg if ask(Q.negative(arg), assumptions): return -arg # arg is Mul if isinstance(arg, Mul): r = [refine(abs(a), assumptions) for a in arg.args] non_abs = [] in_abs = [] for i in r: if isinstance(i, Abs): in_abs.append(i.args[0]) else: non_abs.append(i) return Mul(*non_abs) * Abs(Mul(*in_abs)) def refine_Pow(expr, assumptions): """ Handler for instances of Pow. Examples ======== >>> from sympy import Q >>> from sympy.assumptions.refine import refine_Pow >>> from sympy.abc import x,y,z >>> refine_Pow((-1)**x, Q.real(x)) >>> refine_Pow((-1)**x, Q.even(x)) 1 >>> refine_Pow((-1)**x, Q.odd(x)) -1 For powers of -1, even parts of the exponent can be simplified: >>> refine_Pow((-1)**(x+y), Q.even(x)) (-1)**y >>> refine_Pow((-1)**(x+y+z), Q.odd(x) & Q.odd(z)) (-1)**y >>> refine_Pow((-1)**(x+y+2), Q.odd(x)) (-1)**(y + 1) >>> refine_Pow((-1)**(x+3), True) (-1)**(x + 1) """ from sympy.core import Pow, Rational from sympy.functions.elementary.complexes import Abs from sympy.functions import sign if isinstance(expr.base, Abs): if ask(Q.real(expr.base.args[0]), assumptions) and \ ask(Q.even(expr.exp), assumptions): return expr.base.args[0] ** expr.exp if ask(Q.real(expr.base), assumptions): if expr.base.is_number: if ask(Q.even(expr.exp), assumptions): return abs(expr.base) ** expr.exp if ask(Q.odd(expr.exp), assumptions): return sign(expr.base) * abs(expr.base) ** expr.exp if isinstance(expr.exp, Rational): if type(expr.base) is Pow: return abs(expr.base.base) ** (expr.base.exp * expr.exp) if expr.base is S.NegativeOne: if expr.exp.is_Add: old = expr # For powers of (-1) we can remove # - even terms # - pairs of odd terms # - a single odd term + 1 # - A numerical constant N can be replaced with mod(N,2) coeff, terms = expr.exp.as_coeff_add() terms = set(terms) even_terms = set() odd_terms = set() initial_number_of_terms = len(terms) for t in terms: if ask(Q.even(t), assumptions): even_terms.add(t) elif ask(Q.odd(t), assumptions): odd_terms.add(t) terms -= even_terms if len(odd_terms) % 2: terms -= odd_terms new_coeff = (coeff + S.One) % 2 else: terms -= odd_terms new_coeff = coeff % 2 if new_coeff != coeff or len(terms) < initial_number_of_terms: terms.add(new_coeff) expr = expr.base**(Add(*terms)) # Handle (-1)**((-1)**n/2 + m/2) e2 = 2*expr.exp if ask(Q.even(e2), assumptions): if e2.could_extract_minus_sign(): e2 *= expr.base if e2.is_Add: i, p = e2.as_two_terms() if p.is_Pow and p.base is S.NegativeOne: if ask(Q.integer(p.exp), assumptions): i = (i + 1)/2 if ask(Q.even(i), assumptions): return expr.base**p.exp elif ask(Q.odd(i), assumptions): return expr.base**(p.exp + 1) else: return expr.base**(p.exp + i) if old != expr: return expr def refine_atan2(expr, assumptions): """ Handler for the atan2 function. Examples ======== >>> from sympy import Q, atan2 >>> from sympy.assumptions.refine import refine_atan2 >>> from sympy.abc import x, y >>> refine_atan2(atan2(y,x), Q.real(y) & Q.positive(x)) atan(y/x) >>> refine_atan2(atan2(y,x), Q.negative(y) & Q.negative(x)) atan(y/x) - pi >>> refine_atan2(atan2(y,x), Q.positive(y) & Q.negative(x)) atan(y/x) + pi >>> refine_atan2(atan2(y,x), Q.zero(y) & Q.negative(x)) pi >>> refine_atan2(atan2(y,x), Q.positive(y) & Q.zero(x)) pi/2 >>> refine_atan2(atan2(y,x), Q.negative(y) & Q.zero(x)) -pi/2 >>> refine_atan2(atan2(y,x), Q.zero(y) & Q.zero(x)) nan """ from sympy.functions.elementary.trigonometric import atan from sympy.core import S y, x = expr.args if ask(Q.real(y) & Q.positive(x), assumptions): return atan(y / x) elif ask(Q.negative(y) & Q.negative(x), assumptions): return atan(y / x) - S.Pi elif ask(Q.positive(y) & Q.negative(x), assumptions): return atan(y / x) + S.Pi elif ask(Q.zero(y) & Q.negative(x), assumptions): return S.Pi elif ask(Q.positive(y) & Q.zero(x), assumptions): return S.Pi/2 elif ask(Q.negative(y) & Q.zero(x), assumptions): return -S.Pi/2 elif ask(Q.zero(y) & Q.zero(x), assumptions): return S.NaN else: return expr def refine_re(expr, assumptions): """ Handler for real part. Examples ======== >>> from sympy.assumptions.refine import refine_re >>> from sympy import Q, re >>> from sympy.abc import x >>> refine_re(re(x), Q.real(x)) x >>> refine_re(re(x), Q.imaginary(x)) 0 """ arg = expr.args[0] if ask(Q.real(arg), assumptions): return arg if ask(Q.imaginary(arg), assumptions): return S.Zero return _refine_reim(expr, assumptions) def refine_im(expr, assumptions): """ Handler for imaginary part. Explanation =========== >>> from sympy.assumptions.refine import refine_im >>> from sympy import Q, im >>> from sympy.abc import x >>> refine_im(im(x), Q.real(x)) 0 >>> refine_im(im(x), Q.imaginary(x)) -I*x """ arg = expr.args[0] if ask(Q.real(arg), assumptions): return S.Zero if ask(Q.imaginary(arg), assumptions): return - S.ImaginaryUnit * arg return _refine_reim(expr, assumptions) def refine_arg(expr, assumptions): """ Handler for complex argument Explanation =========== >>> from sympy.assumptions.refine import refine_arg >>> from sympy import Q, arg >>> from sympy.abc import x >>> refine_arg(arg(x), Q.positive(x)) 0 >>> refine_arg(arg(x), Q.negative(x)) pi """ rg = expr.args[0] if ask(Q.positive(rg), assumptions): return S.Zero if ask(Q.negative(rg), assumptions): return S.Pi return None def _refine_reim(expr, assumptions): # Helper function for refine_re & refine_im expanded = expr.expand(complex = True) if expanded != expr: refined = refine(expanded, assumptions) if refined != expanded: return refined # Best to leave the expression as is return None def refine_sign(expr, assumptions): """ Handler for sign. Examples ======== >>> from sympy.assumptions.refine import refine_sign >>> from sympy import Symbol, Q, sign, im >>> x = Symbol('x', real = True) >>> expr = sign(x) >>> refine_sign(expr, Q.positive(x) & Q.nonzero(x)) 1 >>> refine_sign(expr, Q.negative(x) & Q.nonzero(x)) -1 >>> refine_sign(expr, Q.zero(x)) 0 >>> y = Symbol('y', imaginary = True) >>> expr = sign(y) >>> refine_sign(expr, Q.positive(im(y))) I >>> refine_sign(expr, Q.negative(im(y))) -I """ arg = expr.args[0] if ask(Q.zero(arg), assumptions): return S.Zero if ask(Q.real(arg)): if ask(Q.positive(arg), assumptions): return S.One if ask(Q.negative(arg), assumptions): return S.NegativeOne if ask(Q.imaginary(arg)): arg_re, arg_im = arg.as_real_imag() if ask(Q.positive(arg_im), assumptions): return S.ImaginaryUnit if ask(Q.negative(arg_im), assumptions): return -S.ImaginaryUnit return expr def refine_matrixelement(expr, assumptions): """ Handler for symmetric part. Examples ======== >>> from sympy.assumptions.refine import refine_matrixelement >>> from sympy import Q >>> from sympy.matrices.expressions.matexpr import MatrixSymbol >>> X = MatrixSymbol('X', 3, 3) >>> refine_matrixelement(X[0, 1], Q.symmetric(X)) X[0, 1] >>> refine_matrixelement(X[1, 0], Q.symmetric(X)) X[0, 1] """ from sympy.matrices.expressions.matexpr import MatrixElement matrix, i, j = expr.args if ask(Q.symmetric(matrix), assumptions): if (i - j).could_extract_minus_sign(): return expr return MatrixElement(matrix, j, i) handlers_dict = { 'Abs': refine_abs, 'Pow': refine_Pow, 'atan2': refine_atan2, 're': refine_re, 'im': refine_im, 'arg': refine_arg, 'sign': refine_sign, 'MatrixElement': refine_matrixelement } # type: Dict[str, Callable[[Expr, Boolean], Expr]] sympy-sympy-1.9/sympy/assumptions/relation/000077500000000000000000000000001412543434000213065ustar00rootroot00000000000000sympy-sympy-1.9/sympy/assumptions/relation/__init__.py000066400000000000000000000004051412543434000234160ustar00rootroot00000000000000""" A module to implement finitary relations [1] as predicate. References ========== .. [1] https://en.wikipedia.org/wiki/Finitary_relation """ __all__ = ['BinaryRelation', 'AppliedBinaryRelation'] from .binrel import BinaryRelation, AppliedBinaryRelation sympy-sympy-1.9/sympy/assumptions/relation/binrel.py000066400000000000000000000141161412543434000231360ustar00rootroot00000000000000""" General binary relations. """ from sympy import S from sympy.assumptions import AppliedPredicate, ask, Predicate, Q from sympy.core.kind import BooleanKind from sympy.core.relational import Eq, Ne, Gt, Lt, Ge, Le from sympy.logic.boolalg import conjuncts, Not __all__ = ["BinaryRelation", "AppliedBinaryRelation"] class BinaryRelation(Predicate): """ Base class for all binary relational predicates. Explanation =========== Binary relation takes two arguments and returns ``AppliedBinaryRelation`` instance. To evaluate it to boolean value, use :obj:`~.ask()` or :obj:`~.refine()` function. You can add support for new types by registering the handler to dispatcher. See :obj:`~.Predicate()` for more information about predicate dispatching. Examples ======== Applying and evaluating to boolean value: >>> from sympy import Q, ask, sin, cos >>> from sympy.abc import x >>> Q.eq(sin(x)**2+cos(x)**2, 1) Q.eq(sin(x)**2 + cos(x)**2, 1) >>> ask(_) True You can define a new binary relation by subclassing and dispatching. Here, we define a relation $R$ such that $x R y$ returns true if $x = y + 1$. >>> from sympy import ask, Number, Q >>> from sympy.assumptions import BinaryRelation >>> class MyRel(BinaryRelation): ... name = "R" ... is_reflexive = False >>> Q.R = MyRel() >>> @Q.R.register(Number, Number) ... def _(n1, n2, assumptions): ... return ask(Q.zero(n1 - n2 - 1), assumptions) >>> Q.R(2, 1) Q.R(2, 1) Now, we can use ``ask()`` to evaluate it to boolean value. >>> ask(Q.R(2, 1)) True >>> ask(Q.R(1, 2)) False ``Q.R`` returns ``False`` with minimum cost if two arguments have same structure because it is antireflexive relation [1] by ``is_reflexive = False``. >>> ask(Q.R(x, x)) False References ========== .. [1] https://en.wikipedia.org/wiki/Reflexive_relation """ is_reflexive = None is_symmetric = None def __call__(self, *args): if not len(args) == 2: raise ValueError("Binary relation takes two arguments, but got %s." % len(args)) return AppliedBinaryRelation(self, *args) @property def reversed(self): if self.is_symmetric: return self return None @property def negated(self): return None def _compare_reflexive(self, lhs, rhs): # quick exit for structurally same arguments # do not check != here because it cannot catch the # equivalent arguements with different structures. # reflexivity does not hold to NaN if lhs is S.NaN or rhs is S.NaN: return None reflexive = self.is_reflexive if reflexive is None: pass elif reflexive and (lhs == rhs): return True elif not reflexive and (lhs == rhs): return False return None def eval(self, args, assumptions=True): # quick exit for structurally same arguments ret = self._compare_reflexive(*args) if ret is not None: return ret # don't perform simplify on args here. (done by AppliedBinaryRelation._eval_ask) # evaluate by multipledispatch lhs, rhs = args ret = self.handler(lhs, rhs, assumptions=assumptions) if ret is not None: return ret # check reversed order if the relation is reflexive if self.is_reflexive: types = (type(lhs), type(rhs)) if self.handler.dispatch(*types) is not self.handler.dispatch(*reversed(types)): ret = self.handler(rhs, lhs, assumptions=assumptions) return ret class AppliedBinaryRelation(AppliedPredicate): """ The class of expressions resulting from applying ``BinaryRelation`` to the arguments. """ @property def lhs(self): """The left-hand side of the relation.""" return self.arguments[0] @property def rhs(self): """The right-hand side of the relation.""" return self.arguments[1] @property def reversed(self): """ Try to return the relationship with sides reversed. """ revfunc = self.function.reversed if revfunc is None: return self return revfunc(self.rhs, self.lhs) @property def reversedsign(self): """ Try to return the relationship with signs reversed. """ revfunc = self.function.reversed if revfunc is None: return self if not any(side.kind is BooleanKind for side in self.arguments): return revfunc(-self.lhs, -self.rhs) return self @property def negated(self): neg_rel = self.function.negated if neg_rel is None: return Not(self, evaluate=False) return neg_rel(*self.arguments) def _eval_ask(self, assumptions): conj_assumps = set() binrelpreds = {Eq: Q.eq, Ne: Q.ne, Gt: Q.gt, Lt: Q.lt, Ge: Q.ge, Le: Q.le} for a in conjuncts(assumptions): if a.func in binrelpreds: conj_assumps.add(binrelpreds[a.func](*a.args)) else: conj_assumps.add(a) # After CNF in assumptions module is modified to take polyadic # predicate, this will be removed if any(rel in conj_assumps for rel in (self, self.reversed)): return True neg_rels = (self.negated, self.reversed.negated, Not(self, evaluate=False), Not(self.reversed, evaluate=False)) if any(rel in conj_assumps for rel in neg_rels): return False # evaluation using multipledispatching ret = self.function.eval(self.arguments, assumptions) if ret is not None: return ret # simplify the args and try again args = tuple(a.simplify() for a in self.arguments) return self.function.eval(args, assumptions) def __bool__(self): ret = ask(self) if ret is None: raise TypeError("Cannot determine truth value of %s" % self) return ret sympy-sympy-1.9/sympy/assumptions/relation/equality.py000066400000000000000000000157701412543434000235270ustar00rootroot00000000000000""" Module for mathematical equality [1] and inequalities [2]. The purpose of this module is to provide the instances which represent the binary predicates in order to combine the relationals into logical inference system. Objects such as ``Q.eq``, ``Q.lt`` should remain internal to assumptions module, and user must use the classes such as :obj:`~.Eq()`, :obj:`~.Lt()` instead to construct the relational expressions. References ========== .. [1] https://en.wikipedia.org/wiki/Equality_(mathematics) .. [2] https://en.wikipedia.org/wiki/Inequality_(mathematics) """ from sympy.assumptions import Q from sympy.core.relational import is_eq, is_neq, is_gt, is_ge, is_lt, is_le from .binrel import BinaryRelation __all__ = ['EqualityPredicate', 'UnequalityPredicate', 'StrictGreaterThanPredicate', 'GreaterThanPredicate', 'StrictLessThanPredicate', 'LessThanPredicate'] class EqualityPredicate(BinaryRelation): """ Binary predicate for $=$. The purpose of this class is to provide the instance which represent the equality predicate in order to allow the logical inference. This class must remain internal to assumptions module and user must use :obj:`~.Eq()` instead to construct the equality expression. Evaluating this predicate to ``True`` or ``False`` is done by :func:`~.core.relational.is_eq()` Examples ======== >>> from sympy import ask, Q >>> Q.eq(0, 0) Q.eq(0, 0) >>> ask(_) True See Also ======== sympy.core.relational.Eq """ is_reflexive = True is_symmetric = True name = 'eq' handler = None # Do not allow dispatching by this predicate @property def negated(self): return Q.ne def eval(self, args, assumptions=True): if assumptions == True: # default assumptions for is_eq is None assumptions = None return is_eq(*args, assumptions) class UnequalityPredicate(BinaryRelation): r""" Binary predicate for $\neq$. The purpose of this class is to provide the instance which represent the inequation predicate in order to allow the logical inference. This class must remain internal to assumptions module and user must use :obj:`~.Ne()` instead to construct the inequation expression. Evaluating this predicate to ``True`` or ``False`` is done by :func:`~.core.relational.is_neq()` Examples ======== >>> from sympy import ask, Q >>> Q.ne(0, 0) Q.ne(0, 0) >>> ask(_) False See Also ======== sympy.core.relational.Ne """ is_reflexive = False is_symmetric = True name = 'ne' handler = None @property def negated(self): return Q.eq def eval(self, args, assumptions=True): if assumptions == True: # default assumptions for is_neq is None assumptions = None return is_neq(*args, assumptions) class StrictGreaterThanPredicate(BinaryRelation): """ Binary predicate for $>$. The purpose of this class is to provide the instance which represent the ">" predicate in order to allow the logical inference. This class must remain internal to assumptions module and user must use :obj:`~.Gt()` instead to construct the equality expression. Evaluating this predicate to ``True`` or ``False`` is done by :func:`~.core.relational.is_gt()` Examples ======== >>> from sympy import ask, Q >>> Q.gt(0, 0) Q.gt(0, 0) >>> ask(_) False See Also ======== sympy.core.relational.Gt """ is_reflexive = False is_symmetric = False name = 'gt' handler = None @property def reversed(self): return Q.lt @property def negated(self): return Q.le def eval(self, args, assumptions=True): if assumptions == True: # default assumptions for is_gt is None assumptions = None return is_gt(*args, assumptions) class GreaterThanPredicate(BinaryRelation): """ Binary predicate for $>=$. The purpose of this class is to provide the instance which represent the ">=" predicate in order to allow the logical inference. This class must remain internal to assumptions module and user must use :obj:`~.Ge()` instead to construct the equality expression. Evaluating this predicate to ``True`` or ``False`` is done by :func:`~.core.relational.is_ge()` Examples ======== >>> from sympy import ask, Q >>> Q.ge(0, 0) Q.ge(0, 0) >>> ask(_) True See Also ======== sympy.core.relational.Ge """ is_reflexive = True is_symmetric = False name = 'ge' handler = None @property def reversed(self): return Q.le @property def negated(self): return Q.lt def eval(self, args, assumptions=True): if assumptions == True: # default assumptions for is_ge is None assumptions = None return is_ge(*args, assumptions) class StrictLessThanPredicate(BinaryRelation): """ Binary predicate for $<$. The purpose of this class is to provide the instance which represent the "<" predicate in order to allow the logical inference. This class must remain internal to assumptions module and user must use :obj:`~.Lt()` instead to construct the equality expression. Evaluating this predicate to ``True`` or ``False`` is done by :func:`~.core.relational.is_lt()` Examples ======== >>> from sympy import ask, Q >>> Q.lt(0, 0) Q.lt(0, 0) >>> ask(_) False See Also ======== sympy.core.relational.Lt """ is_reflexive = False is_symmetric = False name = 'lt' handler = None @property def reversed(self): return Q.gt @property def negated(self): return Q.ge def eval(self, args, assumptions=True): if assumptions == True: # default assumptions for is_lt is None assumptions = None return is_lt(*args, assumptions) class LessThanPredicate(BinaryRelation): """ Binary predicate for $<=$. The purpose of this class is to provide the instance which represent the "<=" predicate in order to allow the logical inference. This class must remain internal to assumptions module and user must use :obj:`~.Le()` instead to construct the equality expression. Evaluating this predicate to ``True`` or ``False`` is done by :func:`~.core.relational.is_le()` Examples ======== >>> from sympy import ask, Q >>> Q.le(0, 0) Q.le(0, 0) >>> ask(_) True See Also ======== sympy.core.relational.Le """ is_reflexive = True is_symmetric = False name = 'le' handler = None @property def reversed(self): return Q.ge @property def negated(self): return Q.gt def eval(self, args, assumptions=True): if assumptions == True: # default assumptions for is_le is None assumptions = None return is_le(*args, assumptions) sympy-sympy-1.9/sympy/assumptions/satask.py000066400000000000000000000257431412543434000213440ustar00rootroot00000000000000""" Module to evaluate the proposition with assumptions using SAT algorithm. """ from sympy import Symbol, S from sympy.assumptions.ask_generated import get_all_known_facts from sympy.assumptions.assume import global_assumptions, AppliedPredicate from sympy.assumptions.sathandlers import class_fact_registry from sympy.core import oo from sympy.logic.inference import satisfiable from sympy.assumptions.cnf import CNF, EncodedCNF def satask(proposition, assumptions=True, context=global_assumptions, use_known_facts=True, iterations=oo): """ Function to evaluate the proposition with assumptions using SAT algorithm. This function extracts every fact relevant to the expressions composing proposition and assumptions. For example, if a predicate containing ``Abs(x)`` is proposed, then ``Q.zero(Abs(x)) | Q.positive(Abs(x))`` will be found and passed to SAT solver because ``Q.nonnegative`` is registered as a fact for ``Abs``. Proposition is evaluated to ``True`` or ``False`` if the truth value can be determined. If not, ``None`` is returned. Parameters ========== proposition : Any boolean expression. Proposition which will be evaluated to boolean value. assumptions : Any boolean expression, optional. Local assumptions to evaluate the *proposition*. context : AssumptionsContext, optional. Default assumptions to evaluate the *proposition*. By default, this is ``sympy.assumptions.global_assumptions`` variable. use_known_facts : bool, optional. If ``True``, facts from ``sympy.assumptions.ask_generated`` module are passed to SAT solver as well. iterations : int, optional. Number of times that relevant facts are recursively extracted. Default is infinite times until no new fact is found. Returns ======= ``True``, ``False``, or ``None`` Examples ======== >>> from sympy import Abs, Q >>> from sympy.assumptions.satask import satask >>> from sympy.abc import x >>> satask(Q.zero(Abs(x)), Q.zero(x)) True """ props = CNF.from_prop(proposition) _props = CNF.from_prop(~proposition) assumptions = CNF.from_prop(assumptions) context_cnf = CNF() if context: context_cnf = context_cnf.extend(context) sat = get_all_relevant_facts(props, assumptions, context_cnf, use_known_facts=use_known_facts, iterations=iterations) sat.add_from_cnf(assumptions) if context: sat.add_from_cnf(context_cnf) return check_satisfiability(props, _props, sat) def check_satisfiability(prop, _prop, factbase): sat_true = factbase.copy() sat_false = factbase.copy() sat_true.add_from_cnf(prop) sat_false.add_from_cnf(_prop) can_be_true = satisfiable(sat_true) can_be_false = satisfiable(sat_false) if can_be_true and can_be_false: return None if can_be_true and not can_be_false: return True if not can_be_true and can_be_false: return False if not can_be_true and not can_be_false: # TODO: Run additional checks to see which combination of the # assumptions, global_assumptions, and relevant_facts are # inconsistent. raise ValueError("Inconsistent assumptions") def extract_predargs(proposition, assumptions=None, context=None): """ Extract every expression in the argument of predicates from *proposition*, *assumptions* and *context*. Parameters ========== proposition : sympy.assumptions.cnf.CNF assumptions : sympy.assumptions.cnf.CNF, optional. context : sympy.assumptions.cnf.CNF, optional. CNF generated from assumptions context. Examples ======== >>> from sympy import Q, Abs >>> from sympy.assumptions.cnf import CNF >>> from sympy.assumptions.satask import extract_predargs >>> from sympy.abc import x, y >>> props = CNF.from_prop(Q.zero(Abs(x*y))) >>> assump = CNF.from_prop(Q.zero(x) & Q.zero(y)) >>> extract_predargs(props, assump) {x, y, Abs(x*y)} """ req_keys = find_symbols(proposition) keys = proposition.all_predicates() # XXX: We need this since True/False are not Basic lkeys = set() if assumptions: lkeys |= assumptions.all_predicates() if context: lkeys |= context.all_predicates() lkeys = lkeys - {S.true, S.false} tmp_keys = None while tmp_keys != set(): tmp = set() for l in lkeys: syms = find_symbols(l) if (syms & req_keys) != set(): tmp |= syms tmp_keys = tmp - req_keys req_keys |= tmp_keys keys |= {l for l in lkeys if find_symbols(l) & req_keys != set()} exprs = set() for key in keys: if isinstance(key, AppliedPredicate): exprs |= set(key.arguments) else: exprs.add(key) return exprs def find_symbols(pred): """ Find every :obj:`~.Symbol` in *pred*. Parameters ========== pred : sympy.assumptions.cnf.CNF, or any Expr. """ if isinstance(pred, CNF): symbols = set() for a in pred.all_predicates(): symbols |= find_symbols(a) return symbols return pred.atoms(Symbol) def get_relevant_clsfacts(exprs, relevant_facts=None): """ Extract relevant facts from the items in *exprs*. Facts are defined in ``assumptions.sathandlers`` module. This function is recursively called by ``get_all_relevant_facts()``. Parameters ========== exprs : set Expressions whose relevant facts are searched. relevant_facts : sympy.assumptions.cnf.CNF, optional. Pre-discovered relevant facts. Returns ======= exprs : set Candidates for next relevant fact searching. relevant_facts : sympy.assumptions.cnf.CNF Updated relevant facts. Examples ======== Here, we will see how facts relevant to ``Abs(x*y)`` are recursively extracted. On the first run, set containing the expression is passed without pre-discovered relevant facts. The result is a set containig candidates for next run, and ``CNF()`` instance containing facts which are relevant to ``Abs`` and its argument. >>> from sympy import Abs >>> from sympy.assumptions.satask import get_relevant_clsfacts >>> from sympy.abc import x, y >>> exprs = {Abs(x*y)} >>> exprs, facts = get_relevant_clsfacts(exprs) >>> exprs {x*y} >>> facts.clauses #doctest: +SKIP {frozenset({Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}), frozenset({Literal(Q.zero(Abs(x*y)), False), Literal(Q.zero(x*y), True)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True)}), frozenset({Literal(Q.zero(Abs(x*y)), True), Literal(Q.zero(x*y), False)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True), Literal(Q.odd(Abs(x*y)), False)}), frozenset({Literal(Q.positive(Abs(x*y)), False), Literal(Q.zero(Abs(x*y)), False)})} We pass the first run's results to the second run, and get the expressions for next run and updated facts. >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts) >>> exprs {x, y} On final run, no more candidate is returned thus we know that all relevant facts are successfully retrieved. >>> exprs, facts = get_relevant_clsfacts(exprs, relevant_facts=facts) >>> exprs set() """ if not relevant_facts: relevant_facts = CNF() newexprs = set() for expr in exprs: for fact in class_fact_registry(expr): newfact = CNF.to_CNF(fact) relevant_facts = relevant_facts._and(newfact) for key in newfact.all_predicates(): if isinstance(key, AppliedPredicate): newexprs |= set(key.arguments) return newexprs - exprs, relevant_facts def get_all_relevant_facts(proposition, assumptions, context, use_known_facts=True, iterations=oo): """ Extract all relevant facts from *proposition* and *assumptions*. This function extracts the facts by recursively calling ``get_relevant_clsfacts()``. Extracted facts are converted to ``EncodedCNF`` and returned. Parameters ========== proposition : sympy.assumptions.cnf.CNF CNF generated from proposition expression. assumptions : sympy.assumptions.cnf.CNF CNF generated from assumption expression. context : sympy.assumptions.cnf.CNF CNF generated from assumptions context. use_known_facts : bool, optional. If ``True``, facts from ``sympy.assumptions.ask_generated`` module are encoded as well. iterations : int, optional. Number of times that relevant facts are recursively extracted. Default is infinite times until no new fact is found. Returns ======= sympy.assumptions.cnf.EncodedCNF Examples ======== >>> from sympy import Q >>> from sympy.assumptions.cnf import CNF >>> from sympy.assumptions.satask import get_all_relevant_facts >>> from sympy.abc import x, y >>> props = CNF.from_prop(Q.nonzero(x*y)) >>> assump = CNF.from_prop(Q.nonzero(x)) >>> context = CNF.from_prop(Q.nonzero(y)) >>> get_all_relevant_facts(props, assump, context) #doctest: +SKIP """ # The relevant facts might introduce new keys, e.g., Q.zero(x*y) will # introduce the keys Q.zero(x) and Q.zero(y), so we need to run it until # we stop getting new things. Hopefully this strategy won't lead to an # infinite loop in the future. i = 0 relevant_facts = CNF() all_exprs = set() while True: if i == 0: exprs = extract_predargs(proposition, assumptions, context) all_exprs |= exprs exprs, relevant_facts = get_relevant_clsfacts(exprs, relevant_facts) i += 1 if i >= iterations: break if not exprs: break if use_known_facts: known_facts_CNF = CNF() known_facts_CNF.add_clauses(get_all_known_facts()) kf_encoded = EncodedCNF() kf_encoded.from_cnf(known_facts_CNF) def translate_literal(lit, delta): if lit > 0: return lit + delta else: return lit - delta def translate_data(data, delta): return [{translate_literal(i, delta) for i in clause} for clause in data] data = [] symbols = [] n_lit = len(kf_encoded.symbols) for i, expr in enumerate(all_exprs): symbols += [pred(expr) for pred in kf_encoded.symbols] data += translate_data(kf_encoded.data, i * n_lit) encoding = dict(list(zip(symbols, range(1, len(symbols)+1)))) ctx = EncodedCNF(data, encoding) else: ctx = EncodedCNF() ctx.add_from_cnf(relevant_facts) return ctx sympy-sympy-1.9/sympy/assumptions/sathandlers.py000066400000000000000000000223721412543434000223610ustar00rootroot00000000000000from collections import defaultdict from sympy.assumptions.ask import Q from sympy.core import (Add, Mul, Pow, Number, NumberSymbol, Symbol) from sympy.core.numbers import ImaginaryUnit from sympy.functions.elementary.complexes import Abs from sympy.logic.boolalg import (Equivalent, And, Or, Implies) from sympy.matrices.expressions import MatMul # APIs here may be subject to change ### Helper functions ### def allargs(symbol, fact, expr): """ Apply all arguments of the expression to the fact structure. Parameters ========== symbol : Symbol A placeholder symbol. fact : Boolean Resulting ``Boolean`` expression. expr : Expr Examples ======== >>> from sympy import Q >>> from sympy.assumptions.sathandlers import allargs >>> from sympy.abc import x, y >>> allargs(x, Q.negative(x) | Q.positive(x), x*y) (Q.negative(x) | Q.positive(x)) & (Q.negative(y) | Q.positive(y)) """ return And(*[fact.subs(symbol, arg) for arg in expr.args]) def anyarg(symbol, fact, expr): """ Apply any argument of the expression to the fact structure. Parameters ========== symbol : Symbol A placeholder symbol. fact : Boolean Resulting ``Boolean`` expression. expr : Expr Examples ======== >>> from sympy import Q >>> from sympy.assumptions.sathandlers import anyarg >>> from sympy.abc import x, y >>> anyarg(x, Q.negative(x) & Q.positive(x), x*y) (Q.negative(x) & Q.positive(x)) | (Q.negative(y) & Q.positive(y)) """ return Or(*[fact.subs(symbol, arg) for arg in expr.args]) def exactlyonearg(symbol, fact, expr): """ Apply exactly one argument of the expression to the fact structure. Parameters ========== symbol : Symbol A placeholder symbol. fact : Boolean Resulting ``Boolean`` expression. expr : Expr Examples ======== >>> from sympy import Q >>> from sympy.assumptions.sathandlers import exactlyonearg >>> from sympy.abc import x, y >>> exactlyonearg(x, Q.positive(x), x*y) (Q.positive(x) & ~Q.positive(y)) | (Q.positive(y) & ~Q.positive(x)) """ pred_args = [fact.subs(symbol, arg) for arg in expr.args] res = Or(*[And(pred_args[i], *[~lit for lit in pred_args[:i] + pred_args[i+1:]]) for i in range(len(pred_args))]) return res ### Fact registry ### class ClassFactRegistry: """ Register handlers against classes. Explanation =========== ``register`` method registers the handler function for a class. Here, handler function should return a single fact. ``multiregister`` method registers the handler function for multiple classes. Here, handler function should return a container of multiple facts. ``registry(expr)`` returns a set of facts for *expr*. Examples ======== Here, we register the facts for ``Abs``. >>> from sympy import Abs, Q >>> from sympy.logic.boolalg import Equivalent >>> from sympy.assumptions.sathandlers import ClassFactRegistry >>> reg = ClassFactRegistry() >>> @reg.register(Abs) ... def f1(expr): ... return Q.nonnegative(expr) >>> @reg.register(Abs) ... def f2(expr): ... arg = expr.args[0] ... return Equivalent(~Q.zero(arg), ~Q.zero(expr)) Calling the registry with expression returns the defined facts for the expression. >>> from sympy.abc import x >>> reg(Abs(x)) {Q.nonnegative(Abs(x)), Equivalent(~Q.zero(x), ~Q.zero(Abs(x)))} Multiple facts can be registered at once by ``multiregister`` method. >>> reg2 = ClassFactRegistry() >>> @reg2.multiregister(Abs) ... def _(expr): ... arg = expr.args[0] ... return [Q.even(arg) >> Q.even(expr), Q.odd(arg) >> Q.odd(expr)] >>> reg2(Abs(x)) {Implies(Q.even(x), Q.even(Abs(x))), Implies(Q.odd(x), Q.odd(Abs(x)))} """ def __init__(self): self.singlefacts = defaultdict(frozenset) self.multifacts = defaultdict(frozenset) def register(self, cls): def _(func): self.singlefacts[cls] |= {func} return func return _ def multiregister(self, *classes): def _(func): for cls in classes: self.multifacts[cls] |= {func} return func return _ def __getitem__(self, key): ret1 = self.singlefacts[key] for k in self.singlefacts: if issubclass(key, k): ret1 |= self.singlefacts[k] ret2 = self.multifacts[key] for k in self.multifacts: if issubclass(key, k): ret2 |= self.multifacts[k] return ret1, ret2 def __call__(self, expr): ret = set() handlers1, handlers2 = self[expr.func] for h in handlers1: ret.add(h(expr)) for h in handlers2: ret.update(h(expr)) return ret class_fact_registry = ClassFactRegistry() ### Class fact registration ### x = Symbol('x') ## Abs ## @class_fact_registry.multiregister(Abs) def _(expr): arg = expr.args[0] return [Q.nonnegative(expr), Equivalent(~Q.zero(arg), ~Q.zero(expr)), Q.even(arg) >> Q.even(expr), Q.odd(arg) >> Q.odd(expr), Q.integer(arg) >> Q.integer(expr), ] ### Add ## @class_fact_registry.multiregister(Add) def _(expr): return [allargs(x, Q.positive(x), expr) >> Q.positive(expr), allargs(x, Q.negative(x), expr) >> Q.negative(expr), allargs(x, Q.real(x), expr) >> Q.real(expr), allargs(x, Q.rational(x), expr) >> Q.rational(expr), allargs(x, Q.integer(x), expr) >> Q.integer(expr), exactlyonearg(x, ~Q.integer(x), expr) >> ~Q.integer(expr), ] @class_fact_registry.register(Add) def _(expr): allargs_real = allargs(x, Q.real(x), expr) onearg_irrational = exactlyonearg(x, Q.irrational(x), expr) return Implies(allargs_real, Implies(onearg_irrational, Q.irrational(expr))) ### Mul ### @class_fact_registry.multiregister(Mul) def _(expr): return [Equivalent(Q.zero(expr), anyarg(x, Q.zero(x), expr)), allargs(x, Q.positive(x), expr) >> Q.positive(expr), allargs(x, Q.real(x), expr) >> Q.real(expr), allargs(x, Q.rational(x), expr) >> Q.rational(expr), allargs(x, Q.integer(x), expr) >> Q.integer(expr), exactlyonearg(x, ~Q.rational(x), expr) >> ~Q.integer(expr), allargs(x, Q.commutative(x), expr) >> Q.commutative(expr), ] @class_fact_registry.register(Mul) def _(expr): # Implicitly assumes Mul has more than one arg # Would be allargs(x, Q.prime(x) | Q.composite(x)) except 1 is composite # More advanced prime assumptions will require inequalities, as 1 provides # a corner case. allargs_prime = allargs(x, Q.prime(x), expr) return Implies(allargs_prime, ~Q.prime(expr)) @class_fact_registry.register(Mul) def _(expr): # General Case: Odd number of imaginary args implies mul is imaginary(To be implemented) allargs_imag_or_real = allargs(x, Q.imaginary(x) | Q.real(x), expr) onearg_imaginary = exactlyonearg(x, Q.imaginary(x), expr) return Implies(allargs_imag_or_real, Implies(onearg_imaginary, Q.imaginary(expr))) @class_fact_registry.register(Mul) def _(expr): allargs_real = allargs(x, Q.real(x), expr) onearg_irrational = exactlyonearg(x, Q.irrational(x), expr) return Implies(allargs_real, Implies(onearg_irrational, Q.irrational(expr))) @class_fact_registry.register(Mul) def _(expr): # Including the integer qualification means we don't need to add any facts # for odd, since the assumptions already know that every integer is # exactly one of even or odd. allargs_integer = allargs(x, Q.integer(x), expr) anyarg_even = anyarg(x, Q.even(x), expr) return Implies(allargs_integer, Equivalent(anyarg_even, Q.even(expr))) ### MatMul ### @class_fact_registry.register(MatMul) def _(expr): allargs_square = allargs(x, Q.square(x), expr) allargs_invertible = allargs(x, Q.invertible(x), expr) return Implies(allargs_square, Equivalent(Q.invertible(expr), allargs_invertible)) ### Pow ### @class_fact_registry.multiregister(Pow) def _(expr): base, exp = expr.base, expr.exp return [ (Q.real(base) & Q.even(exp) & Q.nonnegative(exp)) >> Q.nonnegative(expr), (Q.nonnegative(base) & Q.odd(exp) & Q.nonnegative(exp)) >> Q.nonnegative(expr), (Q.nonpositive(base) & Q.odd(exp) & Q.nonnegative(exp)) >> Q.nonpositive(expr), Equivalent(Q.zero(expr), Q.zero(base) & Q.positive(exp)) ] ### Numbers ### _old_assump_getters = { Q.positive: lambda o: o.is_positive, Q.zero: lambda o: o.is_zero, Q.negative: lambda o: o.is_negative, Q.rational: lambda o: o.is_rational, Q.irrational: lambda o: o.is_irrational, Q.even: lambda o: o.is_even, Q.odd: lambda o: o.is_odd, Q.imaginary: lambda o: o.is_imaginary, Q.prime: lambda o: o.is_prime, Q.composite: lambda o: o.is_composite, } @class_fact_registry.multiregister(Number, NumberSymbol, ImaginaryUnit) def _(expr): ret = [] for p, getter in _old_assump_getters.items(): pred = p(expr) prop = getter(expr) if prop is not None: ret.append(Equivalent(pred, prop)) return ret sympy-sympy-1.9/sympy/assumptions/tests/000077500000000000000000000000001412543434000206335ustar00rootroot00000000000000sympy-sympy-1.9/sympy/assumptions/tests/__init__.py000066400000000000000000000000001412543434000227320ustar00rootroot00000000000000sympy-sympy-1.9/sympy/assumptions/tests/test_assumptions_2.py000066400000000000000000000020561412543434000250550ustar00rootroot00000000000000""" rename this to test_assumptions.py when the old assumptions system is deleted """ from sympy.abc import x, y from sympy.assumptions.assume import global_assumptions from sympy.assumptions.ask import Q from sympy.printing import pretty def test_equal(): """Test for equality""" assert Q.positive(x) == Q.positive(x) assert Q.positive(x) != ~Q.positive(x) assert ~Q.positive(x) == ~Q.positive(x) def test_pretty(): assert pretty(Q.positive(x)) == "Q.positive(x)" assert pretty( {Q.positive, Q.integer}) == "{Q.integer, Q.positive}" def test_global(): """Test for global assumptions""" global_assumptions.add(x > 0) assert (x > 0) in global_assumptions global_assumptions.remove(x > 0) assert not (x > 0) in global_assumptions # same with multiple of assumptions global_assumptions.add(x > 0, y > 0) assert (x > 0) in global_assumptions assert (y > 0) in global_assumptions global_assumptions.clear() assert not (x > 0) in global_assumptions assert not (y > 0) in global_assumptions sympy-sympy-1.9/sympy/assumptions/tests/test_context.py000066400000000000000000000022011412543434000237230ustar00rootroot00000000000000from sympy.assumptions import ask, Q from sympy.assumptions.assume import assuming, global_assumptions from sympy.abc import x, y def test_assuming(): with assuming(Q.integer(x)): assert ask(Q.integer(x)) assert not ask(Q.integer(x)) def test_assuming_nested(): assert not ask(Q.integer(x)) assert not ask(Q.integer(y)) with assuming(Q.integer(x)): assert ask(Q.integer(x)) assert not ask(Q.integer(y)) with assuming(Q.integer(y)): assert ask(Q.integer(x)) assert ask(Q.integer(y)) assert ask(Q.integer(x)) assert not ask(Q.integer(y)) assert not ask(Q.integer(x)) assert not ask(Q.integer(y)) def test_finally(): try: with assuming(Q.integer(x)): 1/0 except ZeroDivisionError: pass assert not ask(Q.integer(x)) def test_remove_safe(): global_assumptions.add(Q.integer(x)) with assuming(): assert ask(Q.integer(x)) global_assumptions.remove(Q.integer(x)) assert not ask(Q.integer(x)) assert ask(Q.integer(x)) global_assumptions.clear() # for the benefit of other tests sympy-sympy-1.9/sympy/assumptions/tests/test_matrices.py000066400000000000000000000276021412543434000240620ustar00rootroot00000000000000from sympy import Q, ask, Symbol, DiagMatrix, DiagonalMatrix from sympy.matrices.dense import Matrix from sympy.matrices.expressions import (MatrixSymbol, Identity, ZeroMatrix, OneMatrix, Trace, MatrixSlice, Determinant, BlockMatrix, BlockDiagMatrix) from sympy.matrices.expressions.factorizations import LofLU from sympy.testing.pytest import XFAIL X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 3) Z = MatrixSymbol('Z', 2, 2) A1x1 = MatrixSymbol('A1x1', 1, 1) B1x1 = MatrixSymbol('B1x1', 1, 1) C0x0 = MatrixSymbol('C0x0', 0, 0) V1 = MatrixSymbol('V1', 2, 1) V2 = MatrixSymbol('V2', 2, 1) def test_square(): assert ask(Q.square(X)) assert not ask(Q.square(Y)) assert ask(Q.square(Y*Y.T)) def test_invertible(): assert ask(Q.invertible(X), Q.invertible(X)) assert ask(Q.invertible(Y)) is False assert ask(Q.invertible(X*Y), Q.invertible(X)) is False assert ask(Q.invertible(X*Z), Q.invertible(X)) is None assert ask(Q.invertible(X*Z), Q.invertible(X) & Q.invertible(Z)) is True assert ask(Q.invertible(X.T)) is None assert ask(Q.invertible(X.T), Q.invertible(X)) is True assert ask(Q.invertible(X.I)) is True assert ask(Q.invertible(Identity(3))) is True assert ask(Q.invertible(ZeroMatrix(3, 3))) is False assert ask(Q.invertible(OneMatrix(1, 1))) is True assert ask(Q.invertible(OneMatrix(3, 3))) is False assert ask(Q.invertible(X), Q.fullrank(X) & Q.square(X)) def test_singular(): assert ask(Q.singular(X)) is None assert ask(Q.singular(X), Q.invertible(X)) is False assert ask(Q.singular(X), ~Q.invertible(X)) is True @XFAIL def test_invertible_fullrank(): assert ask(Q.invertible(X), Q.fullrank(X)) is True def test_invertible_BlockMatrix(): assert ask(Q.invertible(BlockMatrix([Identity(3)]))) == True assert ask(Q.invertible(BlockMatrix([ZeroMatrix(3, 3)]))) == False X = Matrix([[1, 2, 3], [3, 5, 4]]) Y = Matrix([[4, 2, 7], [2, 3, 5]]) # non-invertible A block assert ask(Q.invertible(BlockMatrix([ [Matrix.ones(3, 3), Y.T], [X, Matrix.eye(2)], ]))) == True # non-invertible B block assert ask(Q.invertible(BlockMatrix([ [Y.T, Matrix.ones(3, 3)], [Matrix.eye(2), X], ]))) == True # non-invertible C block assert ask(Q.invertible(BlockMatrix([ [X, Matrix.eye(2)], [Matrix.ones(3, 3), Y.T], ]))) == True # non-invertible D block assert ask(Q.invertible(BlockMatrix([ [Matrix.eye(2), X], [Y.T, Matrix.ones(3, 3)], ]))) == True def test_invertible_BlockDiagMatrix(): assert ask(Q.invertible(BlockDiagMatrix(Identity(3), Identity(5)))) == True assert ask(Q.invertible(BlockDiagMatrix(ZeroMatrix(3, 3), Identity(5)))) == False assert ask(Q.invertible(BlockDiagMatrix(Identity(3), OneMatrix(5, 5)))) == False def test_symmetric(): assert ask(Q.symmetric(X), Q.symmetric(X)) assert ask(Q.symmetric(X*Z), Q.symmetric(X)) is None assert ask(Q.symmetric(X*Z), Q.symmetric(X) & Q.symmetric(Z)) is True assert ask(Q.symmetric(X + Z), Q.symmetric(X) & Q.symmetric(Z)) is True assert ask(Q.symmetric(Y)) is False assert ask(Q.symmetric(Y*Y.T)) is True assert ask(Q.symmetric(Y.T*X*Y)) is None assert ask(Q.symmetric(Y.T*X*Y), Q.symmetric(X)) is True assert ask(Q.symmetric(X**10), Q.symmetric(X)) is True assert ask(Q.symmetric(A1x1)) is True assert ask(Q.symmetric(A1x1 + B1x1)) is True assert ask(Q.symmetric(A1x1 * B1x1)) is True assert ask(Q.symmetric(V1.T*V1)) is True assert ask(Q.symmetric(V1.T*(V1 + V2))) is True assert ask(Q.symmetric(V1.T*(V1 + V2) + A1x1)) is True assert ask(Q.symmetric(MatrixSlice(Y, (0, 1), (1, 2)))) is True assert ask(Q.symmetric(Identity(3))) is True assert ask(Q.symmetric(ZeroMatrix(3, 3))) is True assert ask(Q.symmetric(OneMatrix(3, 3))) is True def _test_orthogonal_unitary(predicate): assert ask(predicate(X), predicate(X)) assert ask(predicate(X.T), predicate(X)) is True assert ask(predicate(X.I), predicate(X)) is True assert ask(predicate(X**2), predicate(X)) assert ask(predicate(Y)) is False assert ask(predicate(X)) is None assert ask(predicate(X), ~Q.invertible(X)) is False assert ask(predicate(X*Z*X), predicate(X) & predicate(Z)) is True assert ask(predicate(Identity(3))) is True assert ask(predicate(ZeroMatrix(3, 3))) is False assert ask(Q.invertible(X), predicate(X)) assert not ask(predicate(X + Z), predicate(X) & predicate(Z)) def test_orthogonal(): _test_orthogonal_unitary(Q.orthogonal) def test_unitary(): _test_orthogonal_unitary(Q.unitary) assert ask(Q.unitary(X), Q.orthogonal(X)) def test_fullrank(): assert ask(Q.fullrank(X), Q.fullrank(X)) assert ask(Q.fullrank(X**2), Q.fullrank(X)) assert ask(Q.fullrank(X.T), Q.fullrank(X)) is True assert ask(Q.fullrank(X)) is None assert ask(Q.fullrank(Y)) is None assert ask(Q.fullrank(X*Z), Q.fullrank(X) & Q.fullrank(Z)) is True assert ask(Q.fullrank(Identity(3))) is True assert ask(Q.fullrank(ZeroMatrix(3, 3))) is False assert ask(Q.fullrank(OneMatrix(1, 1))) is True assert ask(Q.fullrank(OneMatrix(3, 3))) is False assert ask(Q.invertible(X), ~Q.fullrank(X)) == False def test_positive_definite(): assert ask(Q.positive_definite(X), Q.positive_definite(X)) assert ask(Q.positive_definite(X.T), Q.positive_definite(X)) is True assert ask(Q.positive_definite(X.I), Q.positive_definite(X)) is True assert ask(Q.positive_definite(Y)) is False assert ask(Q.positive_definite(X)) is None assert ask(Q.positive_definite(X**3), Q.positive_definite(X)) assert ask(Q.positive_definite(X*Z*X), Q.positive_definite(X) & Q.positive_definite(Z)) is True assert ask(Q.positive_definite(X), Q.orthogonal(X)) assert ask(Q.positive_definite(Y.T*X*Y), Q.positive_definite(X) & Q.fullrank(Y)) is True assert not ask(Q.positive_definite(Y.T*X*Y), Q.positive_definite(X)) assert ask(Q.positive_definite(Identity(3))) is True assert ask(Q.positive_definite(ZeroMatrix(3, 3))) is False assert ask(Q.positive_definite(OneMatrix(1, 1))) is True assert ask(Q.positive_definite(OneMatrix(3, 3))) is False assert ask(Q.positive_definite(X + Z), Q.positive_definite(X) & Q.positive_definite(Z)) is True assert not ask(Q.positive_definite(-X), Q.positive_definite(X)) assert ask(Q.positive(X[1, 1]), Q.positive_definite(X)) def test_triangular(): assert ask(Q.upper_triangular(X + Z.T + Identity(2)), Q.upper_triangular(X) & Q.lower_triangular(Z)) is True assert ask(Q.upper_triangular(X*Z.T), Q.upper_triangular(X) & Q.lower_triangular(Z)) is True assert ask(Q.lower_triangular(Identity(3))) is True assert ask(Q.lower_triangular(ZeroMatrix(3, 3))) is True assert ask(Q.upper_triangular(ZeroMatrix(3, 3))) is True assert ask(Q.lower_triangular(OneMatrix(1, 1))) is True assert ask(Q.upper_triangular(OneMatrix(1, 1))) is True assert ask(Q.lower_triangular(OneMatrix(3, 3))) is False assert ask(Q.upper_triangular(OneMatrix(3, 3))) is False assert ask(Q.triangular(X), Q.unit_triangular(X)) assert ask(Q.upper_triangular(X**3), Q.upper_triangular(X)) assert ask(Q.lower_triangular(X**3), Q.lower_triangular(X)) def test_diagonal(): assert ask(Q.diagonal(X + Z.T + Identity(2)), Q.diagonal(X) & Q.diagonal(Z)) is True assert ask(Q.diagonal(ZeroMatrix(3, 3))) assert ask(Q.diagonal(OneMatrix(1, 1))) is True assert ask(Q.diagonal(OneMatrix(3, 3))) is False assert ask(Q.lower_triangular(X) & Q.upper_triangular(X), Q.diagonal(X)) assert ask(Q.diagonal(X), Q.lower_triangular(X) & Q.upper_triangular(X)) assert ask(Q.symmetric(X), Q.diagonal(X)) assert ask(Q.triangular(X), Q.diagonal(X)) assert ask(Q.diagonal(C0x0)) assert ask(Q.diagonal(A1x1)) assert ask(Q.diagonal(A1x1 + B1x1)) assert ask(Q.diagonal(A1x1*B1x1)) assert ask(Q.diagonal(V1.T*V2)) assert ask(Q.diagonal(V1.T*(X + Z)*V1)) assert ask(Q.diagonal(MatrixSlice(Y, (0, 1), (1, 2)))) is True assert ask(Q.diagonal(V1.T*(V1 + V2))) is True assert ask(Q.diagonal(X**3), Q.diagonal(X)) assert ask(Q.diagonal(Identity(3))) assert ask(Q.diagonal(DiagMatrix(V1))) assert ask(Q.diagonal(DiagonalMatrix(X))) def test_non_atoms(): assert ask(Q.real(Trace(X)), Q.positive(Trace(X))) @XFAIL def test_non_trivial_implies(): X = MatrixSymbol('X', 3, 3) Y = MatrixSymbol('Y', 3, 3) assert ask(Q.lower_triangular(X+Y), Q.lower_triangular(X) & Q.lower_triangular(Y)) is True assert ask(Q.triangular(X), Q.lower_triangular(X)) is True assert ask(Q.triangular(X+Y), Q.lower_triangular(X) & Q.lower_triangular(Y)) is True def test_MatrixSlice(): X = MatrixSymbol('X', 4, 4) B = MatrixSlice(X, (1, 3), (1, 3)) C = MatrixSlice(X, (0, 3), (1, 3)) assert ask(Q.symmetric(B), Q.symmetric(X)) assert ask(Q.invertible(B), Q.invertible(X)) assert ask(Q.diagonal(B), Q.diagonal(X)) assert ask(Q.orthogonal(B), Q.orthogonal(X)) assert ask(Q.upper_triangular(B), Q.upper_triangular(X)) assert not ask(Q.symmetric(C), Q.symmetric(X)) assert not ask(Q.invertible(C), Q.invertible(X)) assert not ask(Q.diagonal(C), Q.diagonal(X)) assert not ask(Q.orthogonal(C), Q.orthogonal(X)) assert not ask(Q.upper_triangular(C), Q.upper_triangular(X)) def test_det_trace_positive(): X = MatrixSymbol('X', 4, 4) assert ask(Q.positive(Trace(X)), Q.positive_definite(X)) assert ask(Q.positive(Determinant(X)), Q.positive_definite(X)) def test_field_assumptions(): X = MatrixSymbol('X', 4, 4) Y = MatrixSymbol('Y', 4, 4) assert ask(Q.real_elements(X), Q.real_elements(X)) assert not ask(Q.integer_elements(X), Q.real_elements(X)) assert ask(Q.complex_elements(X), Q.real_elements(X)) assert ask(Q.complex_elements(X**2), Q.real_elements(X)) assert ask(Q.real_elements(X**2), Q.integer_elements(X)) assert ask(Q.real_elements(X+Y), Q.real_elements(X)) is None assert ask(Q.real_elements(X+Y), Q.real_elements(X) & Q.real_elements(Y)) from sympy.matrices.expressions.hadamard import HadamardProduct assert ask(Q.real_elements(HadamardProduct(X, Y)), Q.real_elements(X) & Q.real_elements(Y)) assert ask(Q.complex_elements(X+Y), Q.real_elements(X) & Q.complex_elements(Y)) assert ask(Q.real_elements(X.T), Q.real_elements(X)) assert ask(Q.real_elements(X.I), Q.real_elements(X) & Q.invertible(X)) assert ask(Q.real_elements(Trace(X)), Q.real_elements(X)) assert ask(Q.integer_elements(Determinant(X)), Q.integer_elements(X)) assert not ask(Q.integer_elements(X.I), Q.integer_elements(X)) alpha = Symbol('alpha') assert ask(Q.real_elements(alpha*X), Q.real_elements(X) & Q.real(alpha)) assert ask(Q.real_elements(LofLU(X)), Q.real_elements(X)) e = Symbol('e', integer=True, negative=True) assert ask(Q.real_elements(X**e), Q.real_elements(X) & Q.invertible(X)) assert ask(Q.real_elements(X**e), Q.real_elements(X)) is None def test_matrix_element_sets(): X = MatrixSymbol('X', 4, 4) assert ask(Q.real(X[1, 2]), Q.real_elements(X)) assert ask(Q.integer(X[1, 2]), Q.integer_elements(X)) assert ask(Q.complex(X[1, 2]), Q.complex_elements(X)) assert ask(Q.integer_elements(Identity(3))) assert ask(Q.integer_elements(ZeroMatrix(3, 3))) assert ask(Q.integer_elements(OneMatrix(3, 3))) from sympy.matrices.expressions.fourier import DFT assert ask(Q.complex_elements(DFT(3))) def test_matrix_element_sets_slices_blocks(): X = MatrixSymbol('X', 4, 4) assert ask(Q.integer_elements(X[:, 3]), Q.integer_elements(X)) assert ask(Q.integer_elements(BlockMatrix([[X], [X]])), Q.integer_elements(X)) def test_matrix_element_sets_determinant_trace(): assert ask(Q.integer(Determinant(X)), Q.integer_elements(X)) assert ask(Q.integer(Trace(X)), Q.integer_elements(X)) sympy-sympy-1.9/sympy/assumptions/tests/test_query.py000066400000000000000000002772101412543434000234220ustar00rootroot00000000000000from sympy.abc import t, w, x, y, z, n, k, m, p, i from sympy.assumptions import (ask, AssumptionsContext, Q, register_handler, remove_handler) from sympy.assumptions.assume import assuming, global_assumptions, Predicate from sympy.assumptions.cnf import CNF, Literal from sympy.assumptions.facts import (single_fact_lookup, get_known_facts, generate_known_facts_dict, get_known_facts_keys) from sympy.assumptions.handlers import AskHandler from sympy.assumptions.ask_generated import (get_all_known_facts, get_known_facts_dict) from sympy.core.add import Add from sympy.core.numbers import (I, Integer, Rational, oo, zoo, pi) from sympy.core.singleton import S from sympy.core.power import Pow from sympy.core.symbol import symbols, Symbol from sympy.functions.combinatorial.factorials import factorial from sympy.functions.elementary.complexes import (Abs, im, re, sign) from sympy.functions.elementary.exponential import (exp, log) from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import ( acos, acot, asin, atan, cos, cot, sin, tan) from sympy.logic.boolalg import Equivalent, Implies, Xor, And, to_cnf from sympy.matrices import Matrix, SparseMatrix from sympy.testing.pytest import XFAIL, slow, raises, warns_deprecated_sympy, _both_exp_pow import math def test_int_1(): z = 1 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is True assert ask(Q.rational(z)) is True assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is False assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is True assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_int_11(): z = 11 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is True assert ask(Q.rational(z)) is True assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is False assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is True assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is True assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_int_12(): z = 12 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is True assert ask(Q.rational(z)) is True assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is False assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is True assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is True assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_float_1(): z = 1.0 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is None assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is None assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False z = 7.2123 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is None assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is None assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False # test for issue #12168 assert ask(Q.rational(math.pi)) is None def test_zero_0(): z = Integer(0) assert ask(Q.nonzero(z)) is False assert ask(Q.zero(z)) is True assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is True assert ask(Q.rational(z)) is True assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is False assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is True assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is True def test_negativeone(): z = Integer(-1) assert ask(Q.nonzero(z)) is True assert ask(Q.zero(z)) is False assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is True assert ask(Q.rational(z)) is True assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is False assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is False assert ask(Q.negative(z)) is True assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is True assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_infinity(): assert ask(Q.commutative(oo)) is True assert ask(Q.integer(oo)) is False assert ask(Q.rational(oo)) is False assert ask(Q.algebraic(oo)) is False assert ask(Q.real(oo)) is False assert ask(Q.extended_real(oo)) is True assert ask(Q.complex(oo)) is False assert ask(Q.irrational(oo)) is False assert ask(Q.imaginary(oo)) is False assert ask(Q.positive(oo)) is False assert ask(Q.extended_positive(oo)) is True assert ask(Q.negative(oo)) is False assert ask(Q.even(oo)) is False assert ask(Q.odd(oo)) is False assert ask(Q.finite(oo)) is False assert ask(Q.infinite(oo)) is True assert ask(Q.prime(oo)) is False assert ask(Q.composite(oo)) is False assert ask(Q.hermitian(oo)) is False assert ask(Q.antihermitian(oo)) is False assert ask(Q.positive_infinite(oo)) is True assert ask(Q.negative_infinite(oo)) is False def test_neg_infinity(): mm = S.NegativeInfinity assert ask(Q.commutative(mm)) is True assert ask(Q.integer(mm)) is False assert ask(Q.rational(mm)) is False assert ask(Q.algebraic(mm)) is False assert ask(Q.real(mm)) is False assert ask(Q.extended_real(mm)) is True assert ask(Q.complex(mm)) is False assert ask(Q.irrational(mm)) is False assert ask(Q.imaginary(mm)) is False assert ask(Q.positive(mm)) is False assert ask(Q.negative(mm)) is False assert ask(Q.extended_negative(mm)) is True assert ask(Q.even(mm)) is False assert ask(Q.odd(mm)) is False assert ask(Q.finite(mm)) is False assert ask(Q.infinite(oo)) is True assert ask(Q.prime(mm)) is False assert ask(Q.composite(mm)) is False assert ask(Q.hermitian(mm)) is False assert ask(Q.antihermitian(mm)) is False assert ask(Q.positive_infinite(-oo)) is False assert ask(Q.negative_infinite(-oo)) is True def test_complex_infinity(): assert ask(Q.commutative(zoo)) is True assert ask(Q.integer(zoo)) is False assert ask(Q.rational(zoo)) is False assert ask(Q.algebraic(zoo)) is False assert ask(Q.real(zoo)) is False assert ask(Q.extended_real(zoo)) is False assert ask(Q.complex(zoo)) is False assert ask(Q.irrational(zoo)) is False assert ask(Q.imaginary(zoo)) is False assert ask(Q.positive(zoo)) is False assert ask(Q.negative(zoo)) is False assert ask(Q.zero(zoo)) is False assert ask(Q.nonzero(zoo)) is False assert ask(Q.even(zoo)) is False assert ask(Q.odd(zoo)) is False assert ask(Q.finite(zoo)) is False assert ask(Q.infinite(zoo)) is True assert ask(Q.prime(zoo)) is False assert ask(Q.composite(zoo)) is False assert ask(Q.hermitian(zoo)) is False assert ask(Q.antihermitian(zoo)) is False assert ask(Q.positive_infinite(zoo)) is False assert ask(Q.negative_infinite(zoo)) is False def test_nan(): nan = S.NaN assert ask(Q.commutative(nan)) is True assert ask(Q.integer(nan)) is None assert ask(Q.rational(nan)) is None assert ask(Q.algebraic(nan)) is None assert ask(Q.real(nan)) is None assert ask(Q.extended_real(nan)) is None assert ask(Q.complex(nan)) is None assert ask(Q.irrational(nan)) is None assert ask(Q.imaginary(nan)) is None assert ask(Q.positive(nan)) is None assert ask(Q.nonzero(nan)) is None assert ask(Q.zero(nan)) is None assert ask(Q.even(nan)) is None assert ask(Q.odd(nan)) is None assert ask(Q.finite(nan)) is None assert ask(Q.infinite(nan)) is None assert ask(Q.prime(nan)) is None assert ask(Q.composite(nan)) is None assert ask(Q.hermitian(nan)) is None assert ask(Q.antihermitian(nan)) is None def test_Rational_number(): r = Rational(3, 4) assert ask(Q.commutative(r)) is True assert ask(Q.integer(r)) is False assert ask(Q.rational(r)) is True assert ask(Q.real(r)) is True assert ask(Q.complex(r)) is True assert ask(Q.irrational(r)) is False assert ask(Q.imaginary(r)) is False assert ask(Q.positive(r)) is True assert ask(Q.negative(r)) is False assert ask(Q.even(r)) is False assert ask(Q.odd(r)) is False assert ask(Q.finite(r)) is True assert ask(Q.prime(r)) is False assert ask(Q.composite(r)) is False assert ask(Q.hermitian(r)) is True assert ask(Q.antihermitian(r)) is False r = Rational(1, 4) assert ask(Q.positive(r)) is True assert ask(Q.negative(r)) is False r = Rational(5, 4) assert ask(Q.negative(r)) is False assert ask(Q.positive(r)) is True r = Rational(5, 3) assert ask(Q.positive(r)) is True assert ask(Q.negative(r)) is False r = Rational(-3, 4) assert ask(Q.positive(r)) is False assert ask(Q.negative(r)) is True r = Rational(-1, 4) assert ask(Q.positive(r)) is False assert ask(Q.negative(r)) is True r = Rational(-5, 4) assert ask(Q.negative(r)) is True assert ask(Q.positive(r)) is False r = Rational(-5, 3) assert ask(Q.positive(r)) is False assert ask(Q.negative(r)) is True def test_sqrt_2(): z = sqrt(2) assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_pi(): z = S.Pi assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is False assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False z = S.Pi + 1 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is False assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False z = 2*S.Pi assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is False assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False z = S.Pi ** 2 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is False assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False z = (1 + S.Pi) ** 2 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is False assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_E(): z = S.Exp1 assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is False assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_GoldenRatio(): z = S.GoldenRatio assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is True assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_TribonacciConstant(): z = S.TribonacciConstant assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is True assert ask(Q.real(z)) is True assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is True assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is True assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is True assert ask(Q.antihermitian(z)) is False def test_I(): z = I assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is True assert ask(Q.real(z)) is False assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is False assert ask(Q.imaginary(z)) is True assert ask(Q.positive(z)) is False assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is False assert ask(Q.antihermitian(z)) is True z = 1 + I assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is True assert ask(Q.real(z)) is False assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is False assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is False assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is False assert ask(Q.antihermitian(z)) is False z = I*(1 + I) assert ask(Q.commutative(z)) is True assert ask(Q.integer(z)) is False assert ask(Q.rational(z)) is False assert ask(Q.algebraic(z)) is True assert ask(Q.real(z)) is False assert ask(Q.complex(z)) is True assert ask(Q.irrational(z)) is False assert ask(Q.imaginary(z)) is False assert ask(Q.positive(z)) is False assert ask(Q.negative(z)) is False assert ask(Q.even(z)) is False assert ask(Q.odd(z)) is False assert ask(Q.finite(z)) is True assert ask(Q.prime(z)) is False assert ask(Q.composite(z)) is False assert ask(Q.hermitian(z)) is False assert ask(Q.antihermitian(z)) is False z = I**(I) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is True z = (-I)**(I) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is True z = (3*I)**(I) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is False z = (1)**(I) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is True z = (-1)**(I) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is True z = (1+I)**(I) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is False z = (I)**(I+3) assert ask(Q.imaginary(z)) is True assert ask(Q.real(z)) is False z = (I)**(I+2) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is True z = (I)**(2) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is True z = (I)**(3) assert ask(Q.imaginary(z)) is True assert ask(Q.real(z)) is False z = (3)**(I) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is False z = (I)**(0) assert ask(Q.imaginary(z)) is False assert ask(Q.real(z)) is True def test_bounded(): x, y, z = symbols('x,y,z') assert ask(Q.finite(x)) is None assert ask(Q.finite(x), Q.finite(x)) is True assert ask(Q.finite(x), Q.finite(y)) is None assert ask(Q.finite(x), Q.complex(x)) is True assert ask(Q.finite(x), Q.extended_real(x)) is None assert ask(Q.finite(x + 1)) is None assert ask(Q.finite(x + 1), Q.finite(x)) is True a = x + y x, y = a.args # B + B assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is True assert ask(Q.finite(a), Q.positive(x) & Q.finite(y)) is True assert ask(Q.finite(a), Q.finite(x) & Q.positive(y)) is True assert ask(Q.finite(a), Q.positive(x) & Q.positive(y)) is True assert ask(Q.finite(a), Q.positive(x) & Q.finite(y) & ~Q.positive(y)) is True assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) & Q.positive(y)) is True assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & ~Q.positive(x) & ~Q.positive(y)) is True # B + U assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is False assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y)) is False assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y)) is False assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y)) is False assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) & ~Q.positive(y)) is False assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) & Q.positive_infinite(y)) is False assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) & ~Q.finite(y) & ~Q.positive(y)) is False # B + ? assert ask(Q.finite(a), Q.finite(x)) is None assert ask(Q.finite(a), Q.positive(x)) is None assert ask(Q.finite(a), Q.finite(x) & Q.extended_positive(y)) is None assert ask(Q.finite(a), Q.positive(x) & Q.extended_positive(y)) is None assert ask(Q.finite(a), Q.positive(x) & ~Q.positive(y)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) & Q.extended_positive(y)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.positive(x) & ~Q.positive(y)) is None # U + U assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.positive_infinite(y)) is False assert ask(Q.finite(a), Q.positive_infinite(x) & ~Q.finite(y) & ~Q.extended_positive(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.extended_positive(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) & ~Q.extended_positive(x) & ~Q.extended_positive(y)) is False # U + ? assert ask(Q.finite(a), ~Q.finite(y)) is None assert ask(Q.finite(a), Q.extended_positive(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), Q.positive_infinite(y)) is None assert ask(Q.finite(a), Q.extended_positive(x) & Q.positive_infinite(y)) is False assert ask(Q.finite(a), Q.extended_positive(x) & ~Q.finite(y) & ~Q.extended_positive(y)) is None assert ask(Q.finite(a), ~Q.extended_positive(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), ~Q.extended_positive(x) & ~Q.finite(y) & ~Q.extended_positive(y)) is False # ? + ? assert ask(Q.finite(a)) is None assert ask(Q.finite(a), Q.extended_positive(x)) is None assert ask(Q.finite(a), Q.extended_positive(y)) is None assert ask(Q.finite(a), Q.extended_positive(x) & Q.extended_positive(y)) is None assert ask(Q.finite(a), Q.extended_positive(x) & ~Q.extended_positive(y)) is None assert ask(Q.finite(a), ~Q.extended_positive(x) & Q.extended_positive(y)) is None assert ask(Q.finite(a), ~Q.extended_positive(x) & ~Q.extended_positive(y)) is None x, y, z = symbols('x,y,z') a = x + y + z x, y, z = a.args assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & Q.negative(z)) is True assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & Q.finite(z)) is True assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & Q.positive(z)) is True assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.negative(y)) is None assert ask(Q.finite(a), Q.negative(x) & Q.negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) & Q.finite(z)) is True assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) & Q.positive(z)) is True assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.finite(y)) is None assert ask(Q.finite(a), Q.negative(x) & Q.finite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) & Q.positive(z)) is True assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.extended_positive(y) & Q.finite(y)) is None assert ask(Q.finite(a), Q.negative(x) & Q.positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) & Q.extended_negative(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y)) is None assert ask(Q.finite(a), Q.negative(x) & Q.negative_infinite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), Q.negative(x) & ~Q.finite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.positive_infinite(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.positive_infinite(y) & Q.negative_infinite(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), Q.negative(x) & Q.positive_infinite(y) & Q.extended_positive(z)) is False assert ask(Q.finite(a), Q.negative(x) & Q.extended_negative(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.extended_negative(y)) is None assert ask(Q.finite(a), Q.negative(x) & Q.extended_negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative(x)) is None assert ask(Q.finite(a), Q.negative(x) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative(x) & Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & Q.finite(z)) is True assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & Q.positive(z)) is True assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is None assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) & Q.positive(z)) is True assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.positive(y)) is None assert ask(Q.finite(a), Q.finite(x) & Q.positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) & Q.extended_negative(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y)) is None assert ask(Q.finite(a), Q.finite(x) & Q.negative_infinite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), Q.finite(x) & Q.positive_infinite(y) & Q.extended_positive(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.extended_negative(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.extended_negative(y)) is None assert ask(Q.finite(a), Q.finite(x) & Q.extended_negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.finite(x)) is None assert ask(Q.finite(a), Q.finite(x) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.finite(x) & Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) & Q.positive(z)) is True assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.positive(y)) is None assert ask(Q.finite(a), Q.positive(x) & Q.positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) & Q.extended_negative(z)) is False assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y)) is None assert ask(Q.finite(a), Q.positive(x) & Q.negative_infinite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), Q.positive(x) & ~Q.finite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), Q.positive(x) & Q.positive_infinite(y) & Q.extended_positive(z)) is False assert ask(Q.finite(a), Q.positive(x) & Q.extended_negative(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.extended_negative(y)) is None assert ask(Q.finite(a), Q.positive(x) & Q.extended_negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive(x)) is None assert ask(Q.finite(a), Q.positive(x) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive(x) & Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.negative_infinite(y) & Q.negative_infinite(z)) is False assert ask(Q.finite(a), Q.negative_infinite(x) & Q.negative_infinite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.negative_infinite(y)& Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.negative_infinite(y) & Q.extended_negative(z)) is False assert ask(Q.finite(a), Q.negative_infinite(x) & Q.negative_infinite(y)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.negative_infinite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & ~Q.finite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & ~Q.finite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & ~Q.finite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & ~Q.finite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.positive_infinite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.positive_infinite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.positive_infinite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.extended_negative(y) & Q.extended_negative(z)) is False assert ask(Q.finite(a), Q.negative_infinite(x) & Q.extended_negative(y)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.extended_negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.negative_infinite(x) & Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(z) & ~Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y) & Q.positive_infinite(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.positive_infinite(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_negative(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_negative(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), ~Q.finite(x)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_positive(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.positive_infinite(y) & Q.positive_infinite(z)) is False assert ask(Q.finite(a), Q.positive_infinite(x) & Q.positive_infinite(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.positive_infinite(y)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.positive_infinite(y) & Q.extended_positive(z)) is False assert ask(Q.finite(a), Q.positive_infinite(x) & Q.extended_negative(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.extended_negative(y)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.extended_negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive_infinite(x)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.positive_infinite(x) & Q.extended_positive(y) & Q.extended_positive(z)) is False assert ask(Q.finite(a), Q.extended_negative(x) & Q.extended_negative(y) & Q.extended_negative(z)) is None assert ask(Q.finite(a), Q.extended_negative(x) & Q.extended_negative(y)) is None assert ask(Q.finite(a), Q.extended_negative(x) & Q.extended_negative(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.extended_negative(x)) is None assert ask(Q.finite(a), Q.extended_negative(x) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.extended_negative(x) & Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a)) is None assert ask(Q.finite(a), Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(a), Q.extended_positive(x) & Q.extended_positive(y) & Q.extended_positive(z)) is None assert ask(Q.finite(2*x)) is None assert ask(Q.finite(2*x), Q.finite(x)) is True x, y, z = symbols('x,y,z') a = x*y x, y = a.args assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is True assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is False assert ask(Q.finite(a), Q.finite(x)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y)) is False assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is False assert ask(Q.finite(a), ~Q.finite(x)) is None assert ask(Q.finite(a), Q.finite(y)) is None assert ask(Q.finite(a), ~Q.finite(y)) is None assert ask(Q.finite(a)) is None a = x*y*z x, y, z = a.args assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & Q.finite(z)) is True assert ask(Q.finite(a), Q.finite(x) & Q.finite(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.finite(x) & Q.finite(y)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) & Q.finite(z)) is False assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), Q.finite(x) & Q.finite(z)) is None assert ask(Q.finite(a), Q.finite(x) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.finite(x)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y) & Q.finite(z)) is False assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) & Q.finite(z)) is False assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y) & ~Q.finite(z)) is False assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(y)) is None assert ask(Q.finite(a), ~Q.finite(x) & Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(x) & ~Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(x)) is None assert ask(Q.finite(a), Q.finite(y) & Q.finite(z)) is None assert ask(Q.finite(a), Q.finite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), Q.finite(y)) is None assert ask(Q.finite(a), ~Q.finite(y) & Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(y) & ~Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(y)) is None assert ask(Q.finite(a), Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(z)) is None assert ask(Q.finite(a), ~Q.finite(z) & Q.extended_nonzero(x) & Q.extended_nonzero(y) & Q.extended_nonzero(z)) is None assert ask(Q.finite(a), Q.extended_nonzero(x) & ~Q.finite(y) & Q.extended_nonzero(y) & ~Q.finite(z) & Q.extended_nonzero(z)) is False x, y, z = symbols('x,y,z') assert ask(Q.finite(x**2)) is None assert ask(Q.finite(2**x)) is None assert ask(Q.finite(2**x), Q.finite(x)) is True assert ask(Q.finite(x**x)) is None assert ask(Q.finite(S.Half ** x)) is None assert ask(Q.finite(S.Half ** x), Q.extended_positive(x)) is True assert ask(Q.finite(S.Half ** x), Q.extended_negative(x)) is None assert ask(Q.finite(2**x), Q.extended_negative(x)) is True assert ask(Q.finite(sqrt(x))) is None assert ask(Q.finite(2**x), ~Q.finite(x)) is False assert ask(Q.finite(x**2), ~Q.finite(x)) is False # sign function assert ask(Q.finite(sign(x))) is True assert ask(Q.finite(sign(x)), ~Q.finite(x)) is True # exponential functions assert ask(Q.finite(log(x))) is None assert ask(Q.finite(log(x)), Q.finite(x)) is None assert ask(Q.finite(log(x)), ~Q.zero(x)) is True assert ask(Q.finite(log(x)), Q.infinite(x)) is False assert ask(Q.finite(log(x)), Q.zero(x)) is False assert ask(Q.finite(exp(x))) is None assert ask(Q.finite(exp(x)), Q.finite(x)) is True assert ask(Q.finite(exp(2))) is True # trigonometric functions assert ask(Q.finite(sin(x))) is True assert ask(Q.finite(sin(x)), ~Q.finite(x)) is True assert ask(Q.finite(cos(x))) is True assert ask(Q.finite(cos(x)), ~Q.finite(x)) is True assert ask(Q.finite(2*sin(x))) is True assert ask(Q.finite(sin(x)**2)) is True assert ask(Q.finite(cos(x)**2)) is True assert ask(Q.finite(cos(x) + sin(x))) is True @XFAIL def test_bounded_xfail(): """We need to support relations in ask for this to work""" assert ask(Q.finite(sin(x)**x)) is True assert ask(Q.finite(cos(x)**x)) is True def test_commutative(): """By default objects are Q.commutative that is why it returns True for both key=True and key=False""" assert ask(Q.commutative(x)) is True assert ask(Q.commutative(x), ~Q.commutative(x)) is False assert ask(Q.commutative(x), Q.complex(x)) is True assert ask(Q.commutative(x), Q.imaginary(x)) is True assert ask(Q.commutative(x), Q.real(x)) is True assert ask(Q.commutative(x), Q.positive(x)) is True assert ask(Q.commutative(x), ~Q.commutative(y)) is True assert ask(Q.commutative(2*x)) is True assert ask(Q.commutative(2*x), ~Q.commutative(x)) is False assert ask(Q.commutative(x + 1)) is True assert ask(Q.commutative(x + 1), ~Q.commutative(x)) is False assert ask(Q.commutative(x**2)) is True assert ask(Q.commutative(x**2), ~Q.commutative(x)) is False assert ask(Q.commutative(log(x))) is True @_both_exp_pow def test_complex(): assert ask(Q.complex(x)) is None assert ask(Q.complex(x), Q.complex(x)) is True assert ask(Q.complex(x), Q.complex(y)) is None assert ask(Q.complex(x), ~Q.complex(x)) is False assert ask(Q.complex(x), Q.real(x)) is True assert ask(Q.complex(x), ~Q.real(x)) is None assert ask(Q.complex(x), Q.rational(x)) is True assert ask(Q.complex(x), Q.irrational(x)) is True assert ask(Q.complex(x), Q.positive(x)) is True assert ask(Q.complex(x), Q.imaginary(x)) is True assert ask(Q.complex(x), Q.algebraic(x)) is True # a+b assert ask(Q.complex(x + 1), Q.complex(x)) is True assert ask(Q.complex(x + 1), Q.real(x)) is True assert ask(Q.complex(x + 1), Q.rational(x)) is True assert ask(Q.complex(x + 1), Q.irrational(x)) is True assert ask(Q.complex(x + 1), Q.imaginary(x)) is True assert ask(Q.complex(x + 1), Q.integer(x)) is True assert ask(Q.complex(x + 1), Q.even(x)) is True assert ask(Q.complex(x + 1), Q.odd(x)) is True assert ask(Q.complex(x + y), Q.complex(x) & Q.complex(y)) is True assert ask(Q.complex(x + y), Q.real(x) & Q.imaginary(y)) is True # a*x +b assert ask(Q.complex(2*x + 1), Q.complex(x)) is True assert ask(Q.complex(2*x + 1), Q.real(x)) is True assert ask(Q.complex(2*x + 1), Q.positive(x)) is True assert ask(Q.complex(2*x + 1), Q.rational(x)) is True assert ask(Q.complex(2*x + 1), Q.irrational(x)) is True assert ask(Q.complex(2*x + 1), Q.imaginary(x)) is True assert ask(Q.complex(2*x + 1), Q.integer(x)) is True assert ask(Q.complex(2*x + 1), Q.even(x)) is True assert ask(Q.complex(2*x + 1), Q.odd(x)) is True # x**2 assert ask(Q.complex(x**2), Q.complex(x)) is True assert ask(Q.complex(x**2), Q.real(x)) is True assert ask(Q.complex(x**2), Q.positive(x)) is True assert ask(Q.complex(x**2), Q.rational(x)) is True assert ask(Q.complex(x**2), Q.irrational(x)) is True assert ask(Q.complex(x**2), Q.imaginary(x)) is True assert ask(Q.complex(x**2), Q.integer(x)) is True assert ask(Q.complex(x**2), Q.even(x)) is True assert ask(Q.complex(x**2), Q.odd(x)) is True # 2**x assert ask(Q.complex(2**x), Q.complex(x)) is True assert ask(Q.complex(2**x), Q.real(x)) is True assert ask(Q.complex(2**x), Q.positive(x)) is True assert ask(Q.complex(2**x), Q.rational(x)) is True assert ask(Q.complex(2**x), Q.irrational(x)) is True assert ask(Q.complex(2**x), Q.imaginary(x)) is True assert ask(Q.complex(2**x), Q.integer(x)) is True assert ask(Q.complex(2**x), Q.even(x)) is True assert ask(Q.complex(2**x), Q.odd(x)) is True assert ask(Q.complex(x**y), Q.complex(x) & Q.complex(y)) is True # trigonometric expressions assert ask(Q.complex(sin(x))) is True assert ask(Q.complex(sin(2*x + 1))) is True assert ask(Q.complex(cos(x))) is True assert ask(Q.complex(cos(2*x + 1))) is True # exponential assert ask(Q.complex(exp(x))) is True assert ask(Q.complex(exp(x))) is True # Q.complexes assert ask(Q.complex(Abs(x))) is True assert ask(Q.complex(re(x))) is True assert ask(Q.complex(im(x))) is True def test_even_query(): assert ask(Q.even(x)) is None assert ask(Q.even(x), Q.integer(x)) is None assert ask(Q.even(x), ~Q.integer(x)) is False assert ask(Q.even(x), Q.rational(x)) is None assert ask(Q.even(x), Q.positive(x)) is None assert ask(Q.even(2*x)) is None assert ask(Q.even(2*x), Q.integer(x)) is True assert ask(Q.even(2*x), Q.even(x)) is True assert ask(Q.even(2*x), Q.irrational(x)) is False assert ask(Q.even(2*x), Q.odd(x)) is True assert ask(Q.even(2*x), ~Q.integer(x)) is None assert ask(Q.even(3*x), Q.integer(x)) is None assert ask(Q.even(3*x), Q.even(x)) is True assert ask(Q.even(3*x), Q.odd(x)) is False assert ask(Q.even(x + 1), Q.odd(x)) is True assert ask(Q.even(x + 1), Q.even(x)) is False assert ask(Q.even(x + 2), Q.odd(x)) is False assert ask(Q.even(x + 2), Q.even(x)) is True assert ask(Q.even(7 - x), Q.odd(x)) is True assert ask(Q.even(7 + x), Q.odd(x)) is True assert ask(Q.even(x + y), Q.odd(x) & Q.odd(y)) is True assert ask(Q.even(x + y), Q.odd(x) & Q.even(y)) is False assert ask(Q.even(x + y), Q.even(x) & Q.even(y)) is True assert ask(Q.even(2*x + 1), Q.integer(x)) is False assert ask(Q.even(2*x*y), Q.rational(x) & Q.rational(x)) is None assert ask(Q.even(2*x*y), Q.irrational(x) & Q.irrational(x)) is None assert ask(Q.even(x + y + z), Q.odd(x) & Q.odd(y) & Q.even(z)) is True assert ask(Q.even(x + y + z + t), Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) is None assert ask(Q.even(Abs(x)), Q.even(x)) is True assert ask(Q.even(Abs(x)), ~Q.even(x)) is None assert ask(Q.even(re(x)), Q.even(x)) is True assert ask(Q.even(re(x)), ~Q.even(x)) is None assert ask(Q.even(im(x)), Q.even(x)) is True assert ask(Q.even(im(x)), Q.real(x)) is True assert ask(Q.even((-1)**n), Q.integer(n)) is False assert ask(Q.even(k**2), Q.even(k)) is True assert ask(Q.even(n**2), Q.odd(n)) is False assert ask(Q.even(2**k), Q.even(k)) is None assert ask(Q.even(x**2)) is None assert ask(Q.even(k**m), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None assert ask(Q.even(n**m), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is False assert ask(Q.even(k**p), Q.even(k) & Q.integer(p) & Q.positive(p)) is True assert ask(Q.even(n**p), Q.odd(n) & Q.integer(p) & Q.positive(p)) is False assert ask(Q.even(m**k), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None assert ask(Q.even(p**k), Q.even(k) & Q.integer(p) & Q.positive(p)) is None assert ask(Q.even(m**n), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is None assert ask(Q.even(p**n), Q.odd(n) & Q.integer(p) & Q.positive(p)) is None assert ask(Q.even(k**x), Q.even(k)) is None assert ask(Q.even(n**x), Q.odd(n)) is None assert ask(Q.even(x*y), Q.integer(x) & Q.integer(y)) is None assert ask(Q.even(x*x), Q.integer(x)) is None assert ask(Q.even(x*(x + y)), Q.integer(x) & Q.odd(y)) is True assert ask(Q.even(x*(x + y)), Q.integer(x) & Q.even(y)) is None @XFAIL def test_evenness_in_ternary_integer_product_with_odd(): # Tests that oddness inference is independent of term ordering. # Term ordering at the point of testing depends on SymPy's symbol order, so # we try to force a different order by modifying symbol names. assert ask(Q.even(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is True assert ask(Q.even(y*x*(x + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is True def test_evenness_in_ternary_integer_product_with_even(): assert ask(Q.even(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.even(z)) is None def test_extended_real(): assert ask(Q.extended_real(x), Q.positive_infinite(x)) is True assert ask(Q.extended_real(x), Q.positive(x)) is True assert ask(Q.extended_real(x), Q.zero(x)) is True assert ask(Q.extended_real(x), Q.negative(x)) is True assert ask(Q.extended_real(x), Q.negative_infinite(x)) is True assert ask(Q.extended_real(-x), Q.positive(x)) is True assert ask(Q.extended_real(-x), Q.negative(x)) is True assert ask(Q.extended_real(x + S.Infinity), Q.real(x)) is True assert ask(Q.extended_real(x), Q.infinite(x)) is None @_both_exp_pow def test_rational(): assert ask(Q.rational(x), Q.integer(x)) is True assert ask(Q.rational(x), Q.irrational(x)) is False assert ask(Q.rational(x), Q.real(x)) is None assert ask(Q.rational(x), Q.positive(x)) is None assert ask(Q.rational(x), Q.negative(x)) is None assert ask(Q.rational(x), Q.nonzero(x)) is None assert ask(Q.rational(x), ~Q.algebraic(x)) is False assert ask(Q.rational(2*x), Q.rational(x)) is True assert ask(Q.rational(2*x), Q.integer(x)) is True assert ask(Q.rational(2*x), Q.even(x)) is True assert ask(Q.rational(2*x), Q.odd(x)) is True assert ask(Q.rational(2*x), Q.irrational(x)) is False assert ask(Q.rational(x/2), Q.rational(x)) is True assert ask(Q.rational(x/2), Q.integer(x)) is True assert ask(Q.rational(x/2), Q.even(x)) is True assert ask(Q.rational(x/2), Q.odd(x)) is True assert ask(Q.rational(x/2), Q.irrational(x)) is False assert ask(Q.rational(1/x), Q.rational(x)) is True assert ask(Q.rational(1/x), Q.integer(x)) is True assert ask(Q.rational(1/x), Q.even(x)) is True assert ask(Q.rational(1/x), Q.odd(x)) is True assert ask(Q.rational(1/x), Q.irrational(x)) is False assert ask(Q.rational(2/x), Q.rational(x)) is True assert ask(Q.rational(2/x), Q.integer(x)) is True assert ask(Q.rational(2/x), Q.even(x)) is True assert ask(Q.rational(2/x), Q.odd(x)) is True assert ask(Q.rational(2/x), Q.irrational(x)) is False assert ask(Q.rational(x), ~Q.algebraic(x)) is False # with multiple symbols assert ask(Q.rational(x*y), Q.irrational(x) & Q.irrational(y)) is None assert ask(Q.rational(y/x), Q.rational(x) & Q.rational(y)) is True assert ask(Q.rational(y/x), Q.integer(x) & Q.rational(y)) is True assert ask(Q.rational(y/x), Q.even(x) & Q.rational(y)) is True assert ask(Q.rational(y/x), Q.odd(x) & Q.rational(y)) is True assert ask(Q.rational(y/x), Q.irrational(x) & Q.rational(y)) is False for f in [exp, sin, tan, asin, atan, cos]: assert ask(Q.rational(f(7))) is False assert ask(Q.rational(f(7, evaluate=False))) is False assert ask(Q.rational(f(0, evaluate=False))) is True assert ask(Q.rational(f(x)), Q.rational(x)) is None assert ask(Q.rational(f(x)), Q.rational(x) & Q.nonzero(x)) is False for g in [log, acos]: assert ask(Q.rational(g(7))) is False assert ask(Q.rational(g(7, evaluate=False))) is False assert ask(Q.rational(g(1, evaluate=False))) is True assert ask(Q.rational(g(x)), Q.rational(x)) is None assert ask(Q.rational(g(x)), Q.rational(x) & Q.nonzero(x - 1)) is False for h in [cot, acot]: assert ask(Q.rational(h(7))) is False assert ask(Q.rational(h(7, evaluate=False))) is False assert ask(Q.rational(h(x)), Q.rational(x)) is False def test_hermitian(): assert ask(Q.hermitian(x)) is None assert ask(Q.hermitian(x), Q.antihermitian(x)) is None assert ask(Q.hermitian(x), Q.imaginary(x)) is False assert ask(Q.hermitian(x), Q.prime(x)) is True assert ask(Q.hermitian(x), Q.real(x)) is True assert ask(Q.hermitian(x), Q.zero(x)) is True assert ask(Q.hermitian(x + 1), Q.antihermitian(x)) is None assert ask(Q.hermitian(x + 1), Q.complex(x)) is None assert ask(Q.hermitian(x + 1), Q.hermitian(x)) is True assert ask(Q.hermitian(x + 1), Q.imaginary(x)) is False assert ask(Q.hermitian(x + 1), Q.real(x)) is True assert ask(Q.hermitian(x + I), Q.antihermitian(x)) is None assert ask(Q.hermitian(x + I), Q.complex(x)) is None assert ask(Q.hermitian(x + I), Q.hermitian(x)) is False assert ask(Q.hermitian(x + I), Q.imaginary(x)) is None assert ask(Q.hermitian(x + I), Q.real(x)) is False assert ask( Q.hermitian(x + y), Q.antihermitian(x) & Q.antihermitian(y)) is None assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.complex(y)) is None assert ask( Q.hermitian(x + y), Q.antihermitian(x) & Q.hermitian(y)) is None assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.imaginary(y)) is None assert ask(Q.hermitian(x + y), Q.antihermitian(x) & Q.real(y)) is None assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.complex(y)) is None assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.hermitian(y)) is True assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.imaginary(y)) is False assert ask(Q.hermitian(x + y), Q.hermitian(x) & Q.real(y)) is True assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.complex(y)) is None assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.imaginary(y)) is None assert ask(Q.hermitian(x + y), Q.imaginary(x) & Q.real(y)) is False assert ask(Q.hermitian(x + y), Q.real(x) & Q.complex(y)) is None assert ask(Q.hermitian(x + y), Q.real(x) & Q.real(y)) is True assert ask(Q.hermitian(I*x), Q.antihermitian(x)) is True assert ask(Q.hermitian(I*x), Q.complex(x)) is None assert ask(Q.hermitian(I*x), Q.hermitian(x)) is False assert ask(Q.hermitian(I*x), Q.imaginary(x)) is True assert ask(Q.hermitian(I*x), Q.real(x)) is False assert ask(Q.hermitian(x*y), Q.hermitian(x) & Q.real(y)) is True assert ask( Q.hermitian(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is True assert ask(Q.hermitian(x + y + z), Q.real(x) & Q.real(y) & Q.imaginary(z)) is False assert ask(Q.hermitian(x + y + z), Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is None assert ask(Q.hermitian(x + y + z), Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) is None assert ask(Q.antihermitian(x)) is None assert ask(Q.antihermitian(x), Q.real(x)) is False assert ask(Q.antihermitian(x), Q.prime(x)) is False assert ask(Q.antihermitian(x + 1), Q.antihermitian(x)) is False assert ask(Q.antihermitian(x + 1), Q.complex(x)) is None assert ask(Q.antihermitian(x + 1), Q.hermitian(x)) is None assert ask(Q.antihermitian(x + 1), Q.imaginary(x)) is False assert ask(Q.antihermitian(x + 1), Q.real(x)) is None assert ask(Q.antihermitian(x + I), Q.antihermitian(x)) is True assert ask(Q.antihermitian(x + I), Q.complex(x)) is None assert ask(Q.antihermitian(x + I), Q.hermitian(x)) is None assert ask(Q.antihermitian(x + I), Q.imaginary(x)) is True assert ask(Q.antihermitian(x + I), Q.real(x)) is False assert ask(Q.antihermitian(x), Q.zero(x)) is True assert ask( Q.antihermitian(x + y), Q.antihermitian(x) & Q.antihermitian(y) ) is True assert ask( Q.antihermitian(x + y), Q.antihermitian(x) & Q.complex(y)) is None assert ask( Q.antihermitian(x + y), Q.antihermitian(x) & Q.hermitian(y)) is None assert ask( Q.antihermitian(x + y), Q.antihermitian(x) & Q.imaginary(y)) is True assert ask(Q.antihermitian(x + y), Q.antihermitian(x) & Q.real(y) ) is False assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.complex(y)) is None assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.hermitian(y) ) is None assert ask( Q.antihermitian(x + y), Q.hermitian(x) & Q.imaginary(y)) is None assert ask(Q.antihermitian(x + y), Q.hermitian(x) & Q.real(y)) is None assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.complex(y)) is None assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.imaginary(y)) is True assert ask(Q.antihermitian(x + y), Q.imaginary(x) & Q.real(y)) is False assert ask(Q.antihermitian(x + y), Q.real(x) & Q.complex(y)) is None assert ask(Q.antihermitian(x + y), Q.real(x) & Q.real(y)) is None assert ask(Q.antihermitian(I*x), Q.real(x)) is True assert ask(Q.antihermitian(I*x), Q.antihermitian(x)) is False assert ask(Q.antihermitian(I*x), Q.complex(x)) is None assert ask(Q.antihermitian(x*y), Q.antihermitian(x) & Q.real(y)) is True assert ask(Q.antihermitian(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is None assert ask(Q.antihermitian(x + y + z), Q.real(x) & Q.real(y) & Q.imaginary(z)) is None assert ask(Q.antihermitian(x + y + z), Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is False assert ask(Q.antihermitian(x + y + z), Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) is True @_both_exp_pow def test_imaginary(): assert ask(Q.imaginary(x)) is None assert ask(Q.imaginary(x), Q.real(x)) is False assert ask(Q.imaginary(x), Q.prime(x)) is False assert ask(Q.imaginary(x + 1), Q.real(x)) is False assert ask(Q.imaginary(x + 1), Q.imaginary(x)) is False assert ask(Q.imaginary(x + I), Q.real(x)) is False assert ask(Q.imaginary(x + I), Q.imaginary(x)) is True assert ask(Q.imaginary(x + y), Q.imaginary(x) & Q.imaginary(y)) is True assert ask(Q.imaginary(x + y), Q.real(x) & Q.real(y)) is False assert ask(Q.imaginary(x + y), Q.imaginary(x) & Q.real(y)) is False assert ask(Q.imaginary(x + y), Q.complex(x) & Q.real(y)) is None assert ask( Q.imaginary(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is False assert ask(Q.imaginary(x + y + z), Q.real(x) & Q.real(y) & Q.imaginary(z)) is None assert ask(Q.imaginary(x + y + z), Q.real(x) & Q.imaginary(y) & Q.imaginary(z)) is False assert ask(Q.imaginary(I*x), Q.real(x)) is True assert ask(Q.imaginary(I*x), Q.imaginary(x)) is False assert ask(Q.imaginary(I*x), Q.complex(x)) is None assert ask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) is True assert ask(Q.imaginary(x*y), Q.real(x) & Q.real(y)) is False assert ask(Q.imaginary(I**x), Q.negative(x)) is None assert ask(Q.imaginary(I**x), Q.positive(x)) is None assert ask(Q.imaginary(I**x), Q.even(x)) is False assert ask(Q.imaginary(I**x), Q.odd(x)) is True assert ask(Q.imaginary(I**x), Q.imaginary(x)) is False assert ask(Q.imaginary((2*I)**x), Q.imaginary(x)) is False assert ask(Q.imaginary(x**0), Q.imaginary(x)) is False assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.imaginary(y)) is None assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.real(y)) is None assert ask(Q.imaginary(x**y), Q.real(x) & Q.imaginary(y)) is None assert ask(Q.imaginary(x**y), Q.real(x) & Q.real(y)) is None assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.integer(y)) is None assert ask(Q.imaginary(x**y), Q.imaginary(y) & Q.integer(x)) is None assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.odd(y)) is True assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.rational(y)) is None assert ask(Q.imaginary(x**y), Q.imaginary(x) & Q.even(y)) is False assert ask(Q.imaginary(x**y), Q.real(x) & Q.integer(y)) is False assert ask(Q.imaginary(x**y), Q.positive(x) & Q.real(y)) is False assert ask(Q.imaginary(x**y), Q.negative(x) & Q.real(y)) is None assert ask(Q.imaginary(x**y), Q.negative(x) & Q.real(y) & ~Q.rational(y)) is False assert ask(Q.imaginary(x**y), Q.integer(x) & Q.imaginary(y)) is None assert ask(Q.imaginary(x**y), Q.negative(x) & Q.rational(y) & Q.integer(2*y)) is True assert ask(Q.imaginary(x**y), Q.negative(x) & Q.rational(y) & ~Q.integer(2*y)) is False assert ask(Q.imaginary(x**y), Q.negative(x) & Q.rational(y)) is None assert ask(Q.imaginary(x**y), Q.real(x) & Q.rational(y) & ~Q.integer(2*y)) is False assert ask(Q.imaginary(x**y), Q.real(x) & Q.rational(y) & Q.integer(2*y)) is None # logarithm assert ask(Q.imaginary(log(I))) is True assert ask(Q.imaginary(log(2*I))) is False assert ask(Q.imaginary(log(I + 1))) is False assert ask(Q.imaginary(log(x)), Q.complex(x)) is None assert ask(Q.imaginary(log(x)), Q.imaginary(x)) is None assert ask(Q.imaginary(log(x)), Q.positive(x)) is False assert ask(Q.imaginary(log(exp(x))), Q.complex(x)) is None assert ask(Q.imaginary(log(exp(x))), Q.imaginary(x)) is None # zoo/I/a+I*b assert ask(Q.imaginary(log(exp(I)))) is True # exponential assert ask(Q.imaginary(exp(x)**x), Q.imaginary(x)) is False eq = Pow(exp(pi*I*x, evaluate=False), x, evaluate=False) assert ask(Q.imaginary(eq), Q.even(x)) is False eq = Pow(exp(pi*I*x/2, evaluate=False), x, evaluate=False) assert ask(Q.imaginary(eq), Q.odd(x)) is True assert ask(Q.imaginary(exp(3*I*pi*x)**x), Q.integer(x)) is False assert ask(Q.imaginary(exp(2*pi*I, evaluate=False))) is False assert ask(Q.imaginary(exp(pi*I/2, evaluate=False))) is True # issue 7886 assert ask(Q.imaginary(Pow(x, Rational(1, 4))), Q.real(x) & Q.negative(x)) is False def test_integer(): assert ask(Q.integer(x)) is None assert ask(Q.integer(x), Q.integer(x)) is True assert ask(Q.integer(x), ~Q.integer(x)) is False assert ask(Q.integer(x), ~Q.real(x)) is False assert ask(Q.integer(x), ~Q.positive(x)) is None assert ask(Q.integer(x), Q.even(x) | Q.odd(x)) is True assert ask(Q.integer(2*x), Q.integer(x)) is True assert ask(Q.integer(2*x), Q.even(x)) is True assert ask(Q.integer(2*x), Q.prime(x)) is True assert ask(Q.integer(2*x), Q.rational(x)) is None assert ask(Q.integer(2*x), Q.real(x)) is None assert ask(Q.integer(sqrt(2)*x), Q.integer(x)) is False assert ask(Q.integer(sqrt(2)*x), Q.irrational(x)) is None assert ask(Q.integer(x/2), Q.odd(x)) is False assert ask(Q.integer(x/2), Q.even(x)) is True assert ask(Q.integer(x/3), Q.odd(x)) is None assert ask(Q.integer(x/3), Q.even(x)) is None def test_negative(): assert ask(Q.negative(x), Q.negative(x)) is True assert ask(Q.negative(x), Q.positive(x)) is False assert ask(Q.negative(x), ~Q.real(x)) is False assert ask(Q.negative(x), Q.prime(x)) is False assert ask(Q.negative(x), ~Q.prime(x)) is None assert ask(Q.negative(-x), Q.positive(x)) is True assert ask(Q.negative(-x), ~Q.positive(x)) is None assert ask(Q.negative(-x), Q.negative(x)) is False assert ask(Q.negative(-x), Q.positive(x)) is True assert ask(Q.negative(x - 1), Q.negative(x)) is True assert ask(Q.negative(x + y)) is None assert ask(Q.negative(x + y), Q.negative(x)) is None assert ask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True assert ask(Q.negative(x + y), Q.negative(x) & Q.nonpositive(y)) is True assert ask(Q.negative(2 + I)) is False # although this could be False, it is representative of expressions # that don't evaluate to a zero with precision assert ask(Q.negative(cos(I)**2 + sin(I)**2 - 1)) is None assert ask(Q.negative(-I + I*(cos(2)**2 + sin(2)**2))) is None assert ask(Q.negative(x**2)) is None assert ask(Q.negative(x**2), Q.real(x)) is False assert ask(Q.negative(x**1.4), Q.real(x)) is None assert ask(Q.negative(x**I), Q.positive(x)) is None assert ask(Q.negative(x*y)) is None assert ask(Q.negative(x*y), Q.positive(x) & Q.positive(y)) is False assert ask(Q.negative(x*y), Q.positive(x) & Q.negative(y)) is True assert ask(Q.negative(x*y), Q.complex(x) & Q.complex(y)) is None assert ask(Q.negative(x**y)) is None assert ask(Q.negative(x**y), Q.negative(x) & Q.even(y)) is False assert ask(Q.negative(x**y), Q.negative(x) & Q.odd(y)) is True assert ask(Q.negative(x**y), Q.positive(x) & Q.integer(y)) is False assert ask(Q.negative(Abs(x))) is False def test_nonzero(): assert ask(Q.nonzero(x)) is None assert ask(Q.nonzero(x), Q.real(x)) is None assert ask(Q.nonzero(x), Q.positive(x)) is True assert ask(Q.nonzero(x), Q.negative(x)) is True assert ask(Q.nonzero(x), Q.negative(x) | Q.positive(x)) is True assert ask(Q.nonzero(x + y)) is None assert ask(Q.nonzero(x + y), Q.positive(x) & Q.positive(y)) is True assert ask(Q.nonzero(x + y), Q.positive(x) & Q.negative(y)) is None assert ask(Q.nonzero(x + y), Q.negative(x) & Q.negative(y)) is True assert ask(Q.nonzero(2*x)) is None assert ask(Q.nonzero(2*x), Q.positive(x)) is True assert ask(Q.nonzero(2*x), Q.negative(x)) is True assert ask(Q.nonzero(x*y), Q.nonzero(x)) is None assert ask(Q.nonzero(x*y), Q.nonzero(x) & Q.nonzero(y)) is True assert ask(Q.nonzero(x**y), Q.nonzero(x)) is True assert ask(Q.nonzero(Abs(x))) is None assert ask(Q.nonzero(Abs(x)), Q.nonzero(x)) is True assert ask(Q.nonzero(log(exp(2*I)))) is False # although this could be False, it is representative of expressions # that don't evaluate to a zero with precision assert ask(Q.nonzero(cos(1)**2 + sin(1)**2 - 1)) is None def test_zero(): assert ask(Q.zero(x)) is None assert ask(Q.zero(x), Q.real(x)) is None assert ask(Q.zero(x), Q.positive(x)) is False assert ask(Q.zero(x), Q.negative(x)) is False assert ask(Q.zero(x), Q.negative(x) | Q.positive(x)) is False assert ask(Q.zero(x), Q.nonnegative(x) & Q.nonpositive(x)) is True assert ask(Q.zero(x + y)) is None assert ask(Q.zero(x + y), Q.positive(x) & Q.positive(y)) is False assert ask(Q.zero(x + y), Q.positive(x) & Q.negative(y)) is None assert ask(Q.zero(x + y), Q.negative(x) & Q.negative(y)) is False assert ask(Q.zero(2*x)) is None assert ask(Q.zero(2*x), Q.positive(x)) is False assert ask(Q.zero(2*x), Q.negative(x)) is False assert ask(Q.zero(x*y), Q.nonzero(x)) is None assert ask(Q.zero(Abs(x))) is None assert ask(Q.zero(Abs(x)), Q.zero(x)) is True assert ask(Q.integer(x), Q.zero(x)) is True assert ask(Q.even(x), Q.zero(x)) is True assert ask(Q.odd(x), Q.zero(x)) is False assert ask(Q.zero(x), Q.even(x)) is None assert ask(Q.zero(x), Q.odd(x)) is False assert ask(Q.zero(x) | Q.zero(y), Q.zero(x*y)) is True def test_odd_query(): assert ask(Q.odd(x)) is None assert ask(Q.odd(x), Q.odd(x)) is True assert ask(Q.odd(x), Q.integer(x)) is None assert ask(Q.odd(x), ~Q.integer(x)) is False assert ask(Q.odd(x), Q.rational(x)) is None assert ask(Q.odd(x), Q.positive(x)) is None assert ask(Q.odd(-x), Q.odd(x)) is True assert ask(Q.odd(2*x)) is None assert ask(Q.odd(2*x), Q.integer(x)) is False assert ask(Q.odd(2*x), Q.odd(x)) is False assert ask(Q.odd(2*x), Q.irrational(x)) is False assert ask(Q.odd(2*x), ~Q.integer(x)) is None assert ask(Q.odd(3*x), Q.integer(x)) is None assert ask(Q.odd(x/3), Q.odd(x)) is None assert ask(Q.odd(x/3), Q.even(x)) is None assert ask(Q.odd(x + 1), Q.even(x)) is True assert ask(Q.odd(x + 2), Q.even(x)) is False assert ask(Q.odd(x + 2), Q.odd(x)) is True assert ask(Q.odd(3 - x), Q.odd(x)) is False assert ask(Q.odd(3 - x), Q.even(x)) is True assert ask(Q.odd(3 + x), Q.odd(x)) is False assert ask(Q.odd(3 + x), Q.even(x)) is True assert ask(Q.odd(x + y), Q.odd(x) & Q.odd(y)) is False assert ask(Q.odd(x + y), Q.odd(x) & Q.even(y)) is True assert ask(Q.odd(x - y), Q.even(x) & Q.odd(y)) is True assert ask(Q.odd(x - y), Q.odd(x) & Q.odd(y)) is False assert ask(Q.odd(x + y + z), Q.odd(x) & Q.odd(y) & Q.even(z)) is False assert ask(Q.odd(x + y + z + t), Q.odd(x) & Q.odd(y) & Q.even(z) & Q.integer(t)) is None assert ask(Q.odd(2*x + 1), Q.integer(x)) is True assert ask(Q.odd(2*x + y), Q.integer(x) & Q.odd(y)) is True assert ask(Q.odd(2*x + y), Q.integer(x) & Q.even(y)) is False assert ask(Q.odd(2*x + y), Q.integer(x) & Q.integer(y)) is None assert ask(Q.odd(x*y), Q.odd(x) & Q.even(y)) is False assert ask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True assert ask(Q.odd(2*x*y), Q.rational(x) & Q.rational(x)) is None assert ask(Q.odd(2*x*y), Q.irrational(x) & Q.irrational(x)) is None assert ask(Q.odd(Abs(x)), Q.odd(x)) is True assert ask(Q.odd((-1)**n), Q.integer(n)) is True assert ask(Q.odd(k**2), Q.even(k)) is False assert ask(Q.odd(n**2), Q.odd(n)) is True assert ask(Q.odd(3**k), Q.even(k)) is None assert ask(Q.odd(k**m), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None assert ask(Q.odd(n**m), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is True assert ask(Q.odd(k**p), Q.even(k) & Q.integer(p) & Q.positive(p)) is False assert ask(Q.odd(n**p), Q.odd(n) & Q.integer(p) & Q.positive(p)) is True assert ask(Q.odd(m**k), Q.even(k) & Q.integer(m) & ~Q.negative(m)) is None assert ask(Q.odd(p**k), Q.even(k) & Q.integer(p) & Q.positive(p)) is None assert ask(Q.odd(m**n), Q.odd(n) & Q.integer(m) & ~Q.negative(m)) is None assert ask(Q.odd(p**n), Q.odd(n) & Q.integer(p) & Q.positive(p)) is None assert ask(Q.odd(k**x), Q.even(k)) is None assert ask(Q.odd(n**x), Q.odd(n)) is None assert ask(Q.odd(x*y), Q.integer(x) & Q.integer(y)) is None assert ask(Q.odd(x*x), Q.integer(x)) is None assert ask(Q.odd(x*(x + y)), Q.integer(x) & Q.odd(y)) is False assert ask(Q.odd(x*(x + y)), Q.integer(x) & Q.even(y)) is None @XFAIL def test_oddness_in_ternary_integer_product_with_odd(): # Tests that oddness inference is independent of term ordering. # Term ordering at the point of testing depends on SymPy's symbol order, so # we try to force a different order by modifying symbol names. assert ask(Q.odd(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is False assert ask(Q.odd(y*x*(x + z)), Q.integer(x) & Q.integer(y) & Q.odd(z)) is False def test_oddness_in_ternary_integer_product_with_even(): assert ask(Q.odd(x*y*(y + z)), Q.integer(x) & Q.integer(y) & Q.even(z)) is None def test_prime(): assert ask(Q.prime(x), Q.prime(x)) is True assert ask(Q.prime(x), ~Q.prime(x)) is False assert ask(Q.prime(x), Q.integer(x)) is None assert ask(Q.prime(x), ~Q.integer(x)) is False assert ask(Q.prime(2*x), Q.integer(x)) is None assert ask(Q.prime(x*y)) is None assert ask(Q.prime(x*y), Q.prime(x)) is None assert ask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) is None assert ask(Q.prime(4*x), Q.integer(x)) is False assert ask(Q.prime(4*x)) is None assert ask(Q.prime(x**2), Q.integer(x)) is False assert ask(Q.prime(x**2), Q.prime(x)) is False assert ask(Q.prime(x**y), Q.integer(x) & Q.integer(y)) is False @_both_exp_pow def test_positive(): assert ask(Q.positive(x), Q.positive(x)) is True assert ask(Q.positive(x), Q.negative(x)) is False assert ask(Q.positive(x), Q.nonzero(x)) is None assert ask(Q.positive(-x), Q.positive(x)) is False assert ask(Q.positive(-x), Q.negative(x)) is True assert ask(Q.positive(x + y), Q.positive(x) & Q.positive(y)) is True assert ask(Q.positive(x + y), Q.positive(x) & Q.nonnegative(y)) is True assert ask(Q.positive(x + y), Q.positive(x) & Q.negative(y)) is None assert ask(Q.positive(x + y), Q.positive(x) & Q.imaginary(y)) is False assert ask(Q.positive(2*x), Q.positive(x)) is True assumptions = Q.positive(x) & Q.negative(y) & Q.negative(z) & Q.positive(w) assert ask(Q.positive(x*y*z)) is None assert ask(Q.positive(x*y*z), assumptions) is True assert ask(Q.positive(-x*y*z), assumptions) is False assert ask(Q.positive(x**I), Q.positive(x)) is None assert ask(Q.positive(x**2), Q.positive(x)) is True assert ask(Q.positive(x**2), Q.negative(x)) is True assert ask(Q.positive(x**3), Q.negative(x)) is False assert ask(Q.positive(1/(1 + x**2)), Q.real(x)) is True assert ask(Q.positive(2**I)) is False assert ask(Q.positive(2 + I)) is False # although this could be False, it is representative of expressions # that don't evaluate to a zero with precision assert ask(Q.positive(cos(I)**2 + sin(I)**2 - 1)) is None assert ask(Q.positive(-I + I*(cos(2)**2 + sin(2)**2))) is None #exponential assert ask(Q.positive(exp(x)), Q.real(x)) is True assert ask(~Q.negative(exp(x)), Q.real(x)) is True assert ask(Q.positive(x + exp(x)), Q.real(x)) is None assert ask(Q.positive(exp(x)), Q.imaginary(x)) is None assert ask(Q.positive(exp(2*pi*I, evaluate=False)), Q.imaginary(x)) is True assert ask(Q.negative(exp(pi*I, evaluate=False)), Q.imaginary(x)) is True assert ask(Q.positive(exp(x*pi*I)), Q.even(x)) is True assert ask(Q.positive(exp(x*pi*I)), Q.odd(x)) is False assert ask(Q.positive(exp(x*pi*I)), Q.real(x)) is None # logarithm assert ask(Q.positive(log(x)), Q.imaginary(x)) is False assert ask(Q.positive(log(x)), Q.negative(x)) is False assert ask(Q.positive(log(x)), Q.positive(x)) is None assert ask(Q.positive(log(x + 2)), Q.positive(x)) is True # factorial assert ask(Q.positive(factorial(x)), Q.integer(x) & Q.positive(x)) assert ask(Q.positive(factorial(x)), Q.integer(x)) is None #absolute value assert ask(Q.positive(Abs(x))) is None # Abs(0) = 0 assert ask(Q.positive(Abs(x)), Q.positive(x)) is True def test_nonpositive(): assert ask(Q.nonpositive(-1)) assert ask(Q.nonpositive(0)) assert ask(Q.nonpositive(1)) is False assert ask(~Q.positive(x), Q.nonpositive(x)) assert ask(Q.nonpositive(x), Q.positive(x)) is False assert ask(Q.nonpositive(sqrt(-1))) is False assert ask(Q.nonpositive(x), Q.imaginary(x)) is False def test_nonnegative(): assert ask(Q.nonnegative(-1)) is False assert ask(Q.nonnegative(0)) assert ask(Q.nonnegative(1)) assert ask(~Q.negative(x), Q.nonnegative(x)) assert ask(Q.nonnegative(x), Q.negative(x)) is False assert ask(Q.nonnegative(sqrt(-1))) is False assert ask(Q.nonnegative(x), Q.imaginary(x)) is False def test_real_basic(): assert ask(Q.real(x)) is None assert ask(Q.real(x), Q.real(x)) is True assert ask(Q.real(x), Q.nonzero(x)) is True assert ask(Q.real(x), Q.positive(x)) is True assert ask(Q.real(x), Q.negative(x)) is True assert ask(Q.real(x), Q.integer(x)) is True assert ask(Q.real(x), Q.even(x)) is True assert ask(Q.real(x), Q.prime(x)) is True assert ask(Q.real(x/sqrt(2)), Q.real(x)) is True assert ask(Q.real(x/sqrt(-2)), Q.real(x)) is False assert ask(Q.real(x + 1), Q.real(x)) is True assert ask(Q.real(x + I), Q.real(x)) is False assert ask(Q.real(x + I), Q.complex(x)) is None assert ask(Q.real(2*x), Q.real(x)) is True assert ask(Q.real(I*x), Q.real(x)) is False assert ask(Q.real(I*x), Q.imaginary(x)) is True assert ask(Q.real(I*x), Q.complex(x)) is None def test_real_pow(): assert ask(Q.real(x**2), Q.real(x)) is True assert ask(Q.real(sqrt(x)), Q.negative(x)) is False assert ask(Q.real(x**y), Q.real(x) & Q.integer(y)) is True assert ask(Q.real(x**y), Q.real(x) & Q.real(y)) is None assert ask(Q.real(x**y), Q.positive(x) & Q.real(y)) is True assert ask(Q.real(x**y), Q.imaginary(x) & Q.imaginary(y)) is None # I**I or (2*I)**I assert ask(Q.real(x**y), Q.imaginary(x) & Q.real(y)) is None # I**1 or I**0 assert ask(Q.real(x**y), Q.real(x) & Q.imaginary(y)) is None # could be exp(2*pi*I) or 2**I assert ask(Q.real(x**0), Q.imaginary(x)) is True assert ask(Q.real(x**y), Q.real(x) & Q.integer(y)) is True assert ask(Q.real(x**y), Q.positive(x) & Q.real(y)) is True assert ask(Q.real(x**y), Q.real(x) & Q.rational(y)) is None assert ask(Q.real(x**y), Q.imaginary(x) & Q.integer(y)) is None assert ask(Q.real(x**y), Q.imaginary(x) & Q.odd(y)) is False assert ask(Q.real(x**y), Q.imaginary(x) & Q.even(y)) is True assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.rational(y/z) & Q.even(z) & Q.positive(x)) is True assert ask(Q.real(x**(y/z)), Q.real(x) & Q.rational(y/z) & Q.even(z) & Q.negative(x)) is False assert ask(Q.real(x**(y/z)), Q.real(x) & Q.integer(y/z)) is True assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.positive(x)) is True assert ask(Q.real(x**(y/z)), Q.real(x) & Q.real(y/z) & Q.negative(x)) is False assert ask(Q.real((-I)**i), Q.imaginary(i)) is True assert ask(Q.real(I**i), Q.imaginary(i)) is True assert ask(Q.real(i**i), Q.imaginary(i)) is None # i might be 2*I assert ask(Q.real(x**i), Q.imaginary(i)) is None # x could be 0 assert ask(Q.real(x**(I*pi/log(x))), Q.real(x)) is True @_both_exp_pow def test_real_functions(): # trigonometric functions assert ask(Q.real(sin(x))) is None assert ask(Q.real(cos(x))) is None assert ask(Q.real(sin(x)), Q.real(x)) is True assert ask(Q.real(cos(x)), Q.real(x)) is True # exponential function assert ask(Q.real(exp(x))) is None assert ask(Q.real(exp(x)), Q.real(x)) is True assert ask(Q.real(x + exp(x)), Q.real(x)) is True assert ask(Q.real(exp(2*pi*I, evaluate=False))) is True assert ask(Q.real(exp(pi*I, evaluate=False))) is True assert ask(Q.real(exp(pi*I/2, evaluate=False))) is False # logarithm assert ask(Q.real(log(I))) is False assert ask(Q.real(log(2*I))) is False assert ask(Q.real(log(I + 1))) is False assert ask(Q.real(log(x)), Q.complex(x)) is None assert ask(Q.real(log(x)), Q.imaginary(x)) is False assert ask(Q.real(log(exp(x))), Q.imaginary(x)) is None # exp(2*pi*I) is 1, log(exp(pi*I)) is pi*I (disregarding periodicity) assert ask(Q.real(log(exp(x))), Q.complex(x)) is None eq = Pow(exp(2*pi*I*x, evaluate=False), x, evaluate=False) assert ask(Q.real(eq), Q.integer(x)) is True assert ask(Q.real(exp(x)**x), Q.imaginary(x)) is True assert ask(Q.real(exp(x)**x), Q.complex(x)) is None # Q.complexes assert ask(Q.real(re(x))) is True assert ask(Q.real(im(x))) is True def test_matrix(): # hermitian assert ask(Q.hermitian(Matrix([[2, 2 + I, 4], [2 - I, 3, I], [4, -I, 1]]))) == True assert ask(Q.hermitian(Matrix([[2, 2 + I, 4], [2 + I, 3, I], [4, -I, 1]]))) == False z = symbols('z', complex=True) assert ask(Q.hermitian(Matrix([[2, 2 + I, z], [2 - I, 3, I], [4, -I, 1]]))) == None assert ask(Q.hermitian(SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))))) == True assert ask(Q.hermitian(SparseMatrix(((25, 15, -5), (15, I, 0), (-5, 0, 11))))) == False assert ask(Q.hermitian(SparseMatrix(((25, 15, -5), (15, z, 0), (-5, 0, 11))))) == None # antihermitian A = Matrix([[0, -2 - I, 0], [2 - I, 0, -I], [0, -I, 0]]) B = Matrix([[-I, 2 + I, 0], [-2 + I, 0, 2 + I], [0, -2 + I, -I]]) assert ask(Q.antihermitian(A)) is True assert ask(Q.antihermitian(B)) is True assert ask(Q.antihermitian(A**2)) is False C = (B**3) C.simplify() assert ask(Q.antihermitian(C)) is True _A = Matrix([[0, -2 - I, 0], [z, 0, -I], [0, -I, 0]]) assert ask(Q.antihermitian(_A)) is None @_both_exp_pow def test_algebraic(): assert ask(Q.algebraic(x)) is None assert ask(Q.algebraic(I)) is True assert ask(Q.algebraic(2*I)) is True assert ask(Q.algebraic(I/3)) is True assert ask(Q.algebraic(sqrt(7))) is True assert ask(Q.algebraic(2*sqrt(7))) is True assert ask(Q.algebraic(sqrt(7)/3)) is True assert ask(Q.algebraic(I*sqrt(3))) is True assert ask(Q.algebraic(sqrt(1 + I*sqrt(3)))) is True assert ask(Q.algebraic(1 + I*sqrt(3)**Rational(17, 31))) is True assert ask(Q.algebraic(1 + I*sqrt(3)**(17/pi))) is False for f in [exp, sin, tan, asin, atan, cos]: assert ask(Q.algebraic(f(7))) is False assert ask(Q.algebraic(f(7, evaluate=False))) is False assert ask(Q.algebraic(f(0, evaluate=False))) is True assert ask(Q.algebraic(f(x)), Q.algebraic(x)) is None assert ask(Q.algebraic(f(x)), Q.algebraic(x) & Q.nonzero(x)) is False for g in [log, acos]: assert ask(Q.algebraic(g(7))) is False assert ask(Q.algebraic(g(7, evaluate=False))) is False assert ask(Q.algebraic(g(1, evaluate=False))) is True assert ask(Q.algebraic(g(x)), Q.algebraic(x)) is None assert ask(Q.algebraic(g(x)), Q.algebraic(x) & Q.nonzero(x - 1)) is False for h in [cot, acot]: assert ask(Q.algebraic(h(7))) is False assert ask(Q.algebraic(h(7, evaluate=False))) is False assert ask(Q.algebraic(h(x)), Q.algebraic(x)) is False assert ask(Q.algebraic(sqrt(sin(7)))) is False assert ask(Q.algebraic(sqrt(y + I*sqrt(7)))) is None assert ask(Q.algebraic(2.47)) is True assert ask(Q.algebraic(x), Q.transcendental(x)) is False assert ask(Q.transcendental(x), Q.algebraic(x)) is False def test_global(): """Test ask with global assumptions""" assert ask(Q.integer(x)) is None global_assumptions.add(Q.integer(x)) assert ask(Q.integer(x)) is True global_assumptions.clear() assert ask(Q.integer(x)) is None def test_custom_context(): """Test ask with custom assumptions context""" assert ask(Q.integer(x)) is None local_context = AssumptionsContext() local_context.add(Q.integer(x)) assert ask(Q.integer(x), context=local_context) is True assert ask(Q.integer(x)) is None def test_functions_in_assumptions(): assert ask(Q.negative(x), Q.real(x) >> Q.positive(x)) is False assert ask(Q.negative(x), Equivalent(Q.real(x), Q.positive(x))) is False assert ask(Q.negative(x), Xor(Q.real(x), Q.negative(x))) is False def test_composite_ask(): assert ask(Q.negative(x) & Q.integer(x), assumptions=Q.real(x) >> Q.positive(x)) is False def test_composite_proposition(): assert ask(True) is True assert ask(False) is False assert ask(~Q.negative(x), Q.positive(x)) is True assert ask(~Q.real(x), Q.commutative(x)) is None assert ask(Q.negative(x) & Q.integer(x), Q.positive(x)) is False assert ask(Q.negative(x) & Q.integer(x)) is None assert ask(Q.real(x) | Q.integer(x), Q.positive(x)) is True assert ask(Q.real(x) | Q.integer(x)) is None assert ask(Q.real(x) >> Q.positive(x), Q.negative(x)) is False assert ask(Implies( Q.real(x), Q.positive(x), evaluate=False), Q.negative(x)) is False assert ask(Implies(Q.real(x), Q.positive(x), evaluate=False)) is None assert ask(Equivalent(Q.integer(x), Q.even(x)), Q.even(x)) is True assert ask(Equivalent(Q.integer(x), Q.even(x))) is None assert ask(Equivalent(Q.positive(x), Q.integer(x)), Q.integer(x)) is None assert ask(Q.real(x) | Q.integer(x), Q.real(x) | Q.integer(x)) is True def test_tautology(): assert ask(Q.real(x) | ~Q.real(x)) is True assert ask(Q.real(x) & ~Q.real(x)) is False def test_composite_assumptions(): assert ask(Q.real(x), Q.real(x) & Q.real(y)) is True assert ask(Q.positive(x), Q.positive(x) | Q.positive(y)) is None assert ask(Q.positive(x), Q.real(x) >> Q.positive(y)) is None assert ask(Q.real(x), ~(Q.real(x) >> Q.real(y))) is True def test_key_extensibility(): """test that you can add keys to the ask system at runtime""" # make sure the key is not defined raises(AttributeError, lambda: ask(Q.my_key(x))) # Old handler system class MyAskHandler(AskHandler): @staticmethod def Symbol(expr, assumptions): return True try: with warns_deprecated_sympy(): register_handler('my_key', MyAskHandler) with warns_deprecated_sympy(): assert ask(Q.my_key(x)) is True with warns_deprecated_sympy(): assert ask(Q.my_key(x + 1)) is None finally: with warns_deprecated_sympy(): remove_handler('my_key', MyAskHandler) del Q.my_key raises(AttributeError, lambda: ask(Q.my_key(x))) # New handler system class MyPredicate(Predicate): pass try: Q.my_key = MyPredicate() @Q.my_key.register(Symbol) def _(expr, assumptions): return True assert ask(Q.my_key(x)) is True assert ask(Q.my_key(x+1)) is None finally: del Q.my_key raises(AttributeError, lambda: ask(Q.my_key(x))) def test_type_extensibility(): """test that new types can be added to the ask system at runtime """ from sympy.core import Basic class MyType(Basic): pass @Q.prime.register(MyType) def _(expr, assumptions): return True assert ask(Q.prime(MyType())) is True def test_single_fact_lookup(): known_facts = And(Implies(Q.integer, Q.rational), Implies(Q.rational, Q.real), Implies(Q.real, Q.complex)) known_facts_keys = {Q.integer, Q.rational, Q.real, Q.complex} known_facts_cnf = to_cnf(known_facts) mapping = single_fact_lookup(known_facts_keys, known_facts_cnf) assert mapping[Q.rational] == {Q.real, Q.rational, Q.complex} def test_generate_known_facts_dict(): known_facts = And(Implies(Q.integer(x), Q.rational(x)), Implies(Q.rational(x), Q.real(x)), Implies(Q.real(x), Q.complex(x))) known_facts_keys = {Q.integer(x), Q.rational(x), Q.real(x), Q.complex(x)} assert generate_known_facts_dict(known_facts_keys, known_facts) == \ {Q.complex: ({Q.complex}, set()), Q.integer: ({Q.complex, Q.integer, Q.rational, Q.real}, set()), Q.rational: ({Q.complex, Q.rational, Q.real}, set()), Q.real: ({Q.complex, Q.real}, set())} @slow def test_known_facts_consistent(): """"Test that ask_generated.py is up-to-date""" x = Symbol('x') fact = get_known_facts(x) # test cnf clauses of fact between unary predicates cnf = CNF.to_CNF(fact) clauses = set() for cl in cnf.clauses: clauses.add(frozenset(Literal(lit.arg.function, lit.is_Not) for lit in sorted(cl, key=str))) assert get_all_known_facts() == clauses # test dictionary of fact between unary predicates keys = [pred(x) for pred in get_known_facts_keys()] mapping = generate_known_facts_dict(keys, fact) assert get_known_facts_dict() == mapping def test_Add_queries(): assert ask(Q.prime(12345678901234567890 + (cos(1)**2 + sin(1)**2))) is True assert ask(Q.even(Add(S(2), S(2), evaluate=0))) is True assert ask(Q.prime(Add(S(2), S(2), evaluate=0))) is False assert ask(Q.integer(Add(S(2), S(2), evaluate=0))) is True def test_positive_assuming(): with assuming(Q.positive(x + 1)): assert not ask(Q.positive(x)) def test_issue_5421(): raises(TypeError, lambda: ask(pi/log(x), Q.real)) def test_issue_3906(): raises(TypeError, lambda: ask(Q.positive)) def test_issue_5833(): assert ask(Q.positive(log(x)**2), Q.positive(x)) is None assert ask(~Q.negative(log(x)**2), Q.positive(x)) is True def test_issue_6732(): raises(ValueError, lambda: ask(Q.positive(x), Q.positive(x) & Q.negative(x))) raises(ValueError, lambda: ask(Q.negative(x), Q.positive(x) & Q.negative(x))) def test_issue_7246(): assert ask(Q.positive(atan(p)), Q.positive(p)) is True assert ask(Q.positive(atan(p)), Q.negative(p)) is False assert ask(Q.positive(atan(p)), Q.zero(p)) is False assert ask(Q.positive(atan(x))) is None assert ask(Q.positive(asin(p)), Q.positive(p)) is None assert ask(Q.positive(asin(p)), Q.zero(p)) is None assert ask(Q.positive(asin(Rational(1, 7)))) is True assert ask(Q.positive(asin(x)), Q.positive(x) & Q.nonpositive(x - 1)) is True assert ask(Q.positive(asin(x)), Q.negative(x) & Q.nonnegative(x + 1)) is False assert ask(Q.positive(acos(p)), Q.positive(p)) is None assert ask(Q.positive(acos(Rational(1, 7)))) is True assert ask(Q.positive(acos(x)), Q.nonnegative(x + 1) & Q.nonpositive(x - 1)) is True assert ask(Q.positive(acos(x)), Q.nonnegative(x - 1)) is None assert ask(Q.positive(acot(x)), Q.positive(x)) is True assert ask(Q.positive(acot(x)), Q.real(x)) is True assert ask(Q.positive(acot(x)), Q.imaginary(x)) is False assert ask(Q.positive(acot(x))) is None @XFAIL def test_issue_7246_failing(): #Move this test to test_issue_7246 once #the new assumptions module is improved. assert ask(Q.positive(acos(x)), Q.zero(x)) is True def test_check_old_assumption(): x = symbols('x', real=True) assert ask(Q.real(x)) is True assert ask(Q.imaginary(x)) is False assert ask(Q.complex(x)) is True x = symbols('x', imaginary=True) assert ask(Q.real(x)) is False assert ask(Q.imaginary(x)) is True assert ask(Q.complex(x)) is True x = symbols('x', complex=True) assert ask(Q.real(x)) is None assert ask(Q.complex(x)) is True x = symbols('x', positive=True, finite=True) assert ask(Q.positive(x)) is True assert ask(Q.negative(x)) is False assert ask(Q.real(x)) is True x = symbols('x', commutative=False) assert ask(Q.commutative(x)) is False x = symbols('x', negative=True) assert ask(Q.positive(x)) is False assert ask(Q.negative(x)) is True x = symbols('x', nonnegative=True) assert ask(Q.negative(x)) is False assert ask(Q.positive(x)) is None assert ask(Q.zero(x)) is None x = symbols('x', finite=True) assert ask(Q.finite(x)) is True x = symbols('x', prime=True) assert ask(Q.prime(x)) is True assert ask(Q.composite(x)) is False x = symbols('x', composite=True) assert ask(Q.prime(x)) is False assert ask(Q.composite(x)) is True x = symbols('x', even=True) assert ask(Q.even(x)) is True assert ask(Q.odd(x)) is False x = symbols('x', odd=True) assert ask(Q.even(x)) is False assert ask(Q.odd(x)) is True x = symbols('x', nonzero=True) assert ask(Q.nonzero(x)) is True assert ask(Q.zero(x)) is False x = symbols('x', zero=True) assert ask(Q.zero(x)) is True x = symbols('x', integer=True) assert ask(Q.integer(x)) is True x = symbols('x', rational=True) assert ask(Q.rational(x)) is True assert ask(Q.irrational(x)) is False x = symbols('x', irrational=True) assert ask(Q.irrational(x)) is True assert ask(Q.rational(x)) is False def test_issue_9636(): assert ask(Q.integer(1.0)) is False assert ask(Q.prime(3.0)) is False assert ask(Q.composite(4.0)) is False assert ask(Q.even(2.0)) is False assert ask(Q.odd(3.0)) is False def test_autosimp_used_to_fail(): # See issue #9807 assert ask(Q.imaginary(0**I)) is None assert ask(Q.imaginary(0**(-I))) is None assert ask(Q.real(0**I)) is None assert ask(Q.real(0**(-I))) is None def test_custom_AskHandler(): from sympy.logic.boolalg import conjuncts # Old handler system class MersenneHandler(AskHandler): @staticmethod def Integer(expr, assumptions): from sympy import log if ask(Q.integer(log(expr + 1, 2))): return True @staticmethod def Symbol(expr, assumptions): if expr in conjuncts(assumptions): return True try: with warns_deprecated_sympy(): register_handler('mersenne', MersenneHandler) n = Symbol('n', integer=True) with warns_deprecated_sympy(): assert ask(Q.mersenne(7)) with warns_deprecated_sympy(): assert ask(Q.mersenne(n), Q.mersenne(n)) finally: del Q.mersenne # New handler system class MersennePredicate(Predicate): pass try: Q.mersenne = MersennePredicate() @Q.mersenne.register(Integer) def _(expr, assumptions): from sympy import log if ask(Q.integer(log(expr + 1, 2))): return True @Q.mersenne.register(Symbol) def _(expr, assumptions): if expr in conjuncts(assumptions): return True assert ask(Q.mersenne(7)) assert ask(Q.mersenne(n), Q.mersenne(n)) finally: del Q.mersenne def test_polyadic_predicate(): class SexyPredicate(Predicate): pass try: Q.sexyprime = SexyPredicate() @Q.sexyprime.register(Integer, Integer) def _(int1, int2, assumptions): args = sorted([int1, int2]) if not all(ask(Q.prime(a), assumptions) for a in args): return False return args[1] - args[0] == 6 @Q.sexyprime.register(Integer, Integer, Integer) def _(int1, int2, int3, assumptions): args = sorted([int1, int2, int3]) if not all(ask(Q.prime(a), assumptions) for a in args): return False return args[2] - args[1] == 6 and args[1] - args[0] == 6 assert ask(Q.sexyprime(5, 11)) assert ask(Q.sexyprime(7, 13, 19)) finally: del Q.sexyprime def test_Predicate_handler_is_unique(): # Undefined predicate does not have a handler assert Predicate('mypredicate').handler is None # Handler of defined predicate is unique to the class class MyPredicate(Predicate): pass mp1 = MyPredicate('mp1') mp2 = MyPredicate('mp2') assert mp1.handler is mp2.handler def test_relational(): assert ask(Q.eq(x, 0), Q.zero(x)) assert not ask(Q.eq(x, 0), Q.nonzero(x)) assert not ask(Q.ne(x, 0), Q.zero(x)) assert ask(Q.ne(x, 0), Q.nonzero(x)) sympy-sympy-1.9/sympy/assumptions/tests/test_refine.py000066400000000000000000000200031412543434000235070ustar00rootroot00000000000000from sympy import (Abs, exp, Expr, I, pi, Q, Rational, refine, S, sqrt, atan, atan2, nan, Symbol, re, im, sign, arg) from sympy.abc import w, x, y, z from sympy.core.relational import Eq, Ne from sympy.functions.elementary.piecewise import Piecewise from sympy.matrices.expressions.matexpr import MatrixSymbol def test_Abs(): assert refine(Abs(x), Q.positive(x)) == x assert refine(1 + Abs(x), Q.positive(x)) == 1 + x assert refine(Abs(x), Q.negative(x)) == -x assert refine(1 + Abs(x), Q.negative(x)) == 1 - x assert refine(Abs(x**2)) != x**2 assert refine(Abs(x**2), Q.real(x)) == x**2 def test_pow1(): assert refine((-1)**x, Q.even(x)) == 1 assert refine((-1)**x, Q.odd(x)) == -1 assert refine((-2)**x, Q.even(x)) == 2**x # nested powers assert refine(sqrt(x**2)) != Abs(x) assert refine(sqrt(x**2), Q.complex(x)) != Abs(x) assert refine(sqrt(x**2), Q.real(x)) == Abs(x) assert refine(sqrt(x**2), Q.positive(x)) == x assert refine((x**3)**Rational(1, 3)) != x assert refine((x**3)**Rational(1, 3), Q.real(x)) != x assert refine((x**3)**Rational(1, 3), Q.positive(x)) == x assert refine(sqrt(1/x), Q.real(x)) != 1/sqrt(x) assert refine(sqrt(1/x), Q.positive(x)) == 1/sqrt(x) # powers of (-1) assert refine((-1)**(x + y), Q.even(x)) == (-1)**y assert refine((-1)**(x + y + z), Q.odd(x) & Q.odd(z)) == (-1)**y assert refine((-1)**(x + y + 1), Q.odd(x)) == (-1)**y assert refine((-1)**(x + y + 2), Q.odd(x)) == (-1)**(y + 1) assert refine((-1)**(x + 3)) == (-1)**(x + 1) # continuation assert refine((-1)**((-1)**x/2 - S.Half), Q.integer(x)) == (-1)**x assert refine((-1)**((-1)**x/2 + S.Half), Q.integer(x)) == (-1)**(x + 1) assert refine((-1)**((-1)**x/2 + 5*S.Half), Q.integer(x)) == (-1)**(x + 1) def test_pow2(): assert refine((-1)**((-1)**x/2 - 7*S.Half), Q.integer(x)) == (-1)**(x + 1) assert refine((-1)**((-1)**x/2 - 9*S.Half), Q.integer(x)) == (-1)**x # powers of Abs assert refine(Abs(x)**2, Q.real(x)) == x**2 assert refine(Abs(x)**3, Q.real(x)) == Abs(x)**3 assert refine(Abs(x)**2) == Abs(x)**2 def test_exp(): x = Symbol('x', integer=True) assert refine(exp(pi*I*2*x)) == 1 assert refine(exp(pi*I*2*(x + S.Half))) == -1 assert refine(exp(pi*I*2*(x + Rational(1, 4)))) == I assert refine(exp(pi*I*2*(x + Rational(3, 4)))) == -I def test_Piecewise(): assert refine(Piecewise((1, x < 0), (3, True)), (x < 0)) == 1 assert refine(Piecewise((1, x < 0), (3, True)), ~(x < 0)) == 3 assert refine(Piecewise((1, x < 0), (3, True)), (y < 0)) == \ Piecewise((1, x < 0), (3, True)) assert refine(Piecewise((1, x > 0), (3, True)), (x > 0)) == 1 assert refine(Piecewise((1, x > 0), (3, True)), ~(x > 0)) == 3 assert refine(Piecewise((1, x > 0), (3, True)), (y > 0)) == \ Piecewise((1, x > 0), (3, True)) assert refine(Piecewise((1, x <= 0), (3, True)), (x <= 0)) == 1 assert refine(Piecewise((1, x <= 0), (3, True)), ~(x <= 0)) == 3 assert refine(Piecewise((1, x <= 0), (3, True)), (y <= 0)) == \ Piecewise((1, x <= 0), (3, True)) assert refine(Piecewise((1, x >= 0), (3, True)), (x >= 0)) == 1 assert refine(Piecewise((1, x >= 0), (3, True)), ~(x >= 0)) == 3 assert refine(Piecewise((1, x >= 0), (3, True)), (y >= 0)) == \ Piecewise((1, x >= 0), (3, True)) assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(x, 0)))\ == 1 assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(0, x)))\ == 1 assert refine(Piecewise((1, Eq(x, 0)), (3, True)), ~(Eq(x, 0)))\ == 3 assert refine(Piecewise((1, Eq(x, 0)), (3, True)), ~(Eq(0, x)))\ == 3 assert refine(Piecewise((1, Eq(x, 0)), (3, True)), (Eq(y, 0)))\ == Piecewise((1, Eq(x, 0)), (3, True)) assert refine(Piecewise((1, Ne(x, 0)), (3, True)), (Ne(x, 0)))\ == 1 assert refine(Piecewise((1, Ne(x, 0)), (3, True)), ~(Ne(x, 0)))\ == 3 assert refine(Piecewise((1, Ne(x, 0)), (3, True)), (Ne(y, 0)))\ == Piecewise((1, Ne(x, 0)), (3, True)) def test_atan2(): assert refine(atan2(y, x), Q.real(y) & Q.positive(x)) == atan(y/x) assert refine(atan2(y, x), Q.negative(y) & Q.positive(x)) == atan(y/x) assert refine(atan2(y, x), Q.negative(y) & Q.negative(x)) == atan(y/x) - pi assert refine(atan2(y, x), Q.positive(y) & Q.negative(x)) == atan(y/x) + pi assert refine(atan2(y, x), Q.zero(y) & Q.negative(x)) == pi assert refine(atan2(y, x), Q.positive(y) & Q.zero(x)) == pi/2 assert refine(atan2(y, x), Q.negative(y) & Q.zero(x)) == -pi/2 assert refine(atan2(y, x), Q.zero(y) & Q.zero(x)) is nan def test_re(): assert refine(re(x), Q.real(x)) == x assert refine(re(x), Q.imaginary(x)) is S.Zero assert refine(re(x+y), Q.real(x) & Q.real(y)) == x + y assert refine(re(x+y), Q.real(x) & Q.imaginary(y)) == x assert refine(re(x*y), Q.real(x) & Q.real(y)) == x * y assert refine(re(x*y), Q.real(x) & Q.imaginary(y)) == 0 assert refine(re(x*y*z), Q.real(x) & Q.real(y) & Q.real(z)) == x * y * z def test_im(): assert refine(im(x), Q.imaginary(x)) == -I*x assert refine(im(x), Q.real(x)) is S.Zero assert refine(im(x+y), Q.imaginary(x) & Q.imaginary(y)) == -I*x - I*y assert refine(im(x+y), Q.real(x) & Q.imaginary(y)) == -I*y assert refine(im(x*y), Q.imaginary(x) & Q.real(y)) == -I*x*y assert refine(im(x*y), Q.imaginary(x) & Q.imaginary(y)) == 0 assert refine(im(1/x), Q.imaginary(x)) == -I/x assert refine(im(x*y*z), Q.imaginary(x) & Q.imaginary(y) & Q.imaginary(z)) == -I*x*y*z def test_complex(): assert refine(re(1/(x + I*y)), Q.real(x) & Q.real(y)) == \ x/(x**2 + y**2) assert refine(im(1/(x + I*y)), Q.real(x) & Q.real(y)) == \ -y/(x**2 + y**2) assert refine(re((w + I*x) * (y + I*z)), Q.real(w) & Q.real(x) & Q.real(y) & Q.real(z)) == w*y - x*z assert refine(im((w + I*x) * (y + I*z)), Q.real(w) & Q.real(x) & Q.real(y) & Q.real(z)) == w*z + x*y def test_sign(): x = Symbol('x', real = True) assert refine(sign(x), Q.positive(x)) == 1 assert refine(sign(x), Q.negative(x)) == -1 assert refine(sign(x), Q.zero(x)) == 0 assert refine(sign(x), True) == sign(x) assert refine(sign(Abs(x)), Q.nonzero(x)) == 1 x = Symbol('x', imaginary=True) assert refine(sign(x), Q.positive(im(x))) == S.ImaginaryUnit assert refine(sign(x), Q.negative(im(x))) == -S.ImaginaryUnit assert refine(sign(x), True) == sign(x) x = Symbol('x', complex=True) assert refine(sign(x), Q.zero(x)) == 0 def test_arg(): x = Symbol('x', complex = True) assert refine(arg(x), Q.positive(x)) == 0 assert refine(arg(x), Q.negative(x)) == pi def test_func_args(): class MyClass(Expr): # A class with nontrivial .func def __init__(self, *args): self.my_member = "" @property def func(self): def my_func(*args): obj = MyClass(*args) obj.my_member = self.my_member return obj return my_func x = MyClass() x.my_member = "A very important value" assert x.my_member == refine(x).my_member def test_eval_refine(): from sympy.core.expr import Expr class MockExpr(Expr): def _eval_refine(self, assumptions): return True mock_obj = MockExpr() assert refine(mock_obj) def test_refine_issue_12724(): expr1 = refine(Abs(x * y), Q.positive(x)) expr2 = refine(Abs(x * y * z), Q.positive(x)) assert expr1 == x * Abs(y) assert expr2 == x * Abs(y * z) y1 = Symbol('y1', real = True) expr3 = refine(Abs(x * y1**2 * z), Q.positive(x)) assert expr3 == x * y1**2 * Abs(z) def test_matrixelement(): x = MatrixSymbol('x', 3, 3) i = Symbol('i', positive = True) j = Symbol('j', positive = True) assert refine(x[0, 1], Q.symmetric(x)) == x[0, 1] assert refine(x[1, 0], Q.symmetric(x)) == x[0, 1] assert refine(x[i, j], Q.symmetric(x)) == x[j, i] assert refine(x[j, i], Q.symmetric(x)) == x[j, i] sympy-sympy-1.9/sympy/assumptions/tests/test_satask.py000066400000000000000000000361221412543434000235360ustar00rootroot00000000000000from sympy import (S, symbols, Q, assuming, Implies, MatrixSymbol, I, pi, Abs, Eq, Gt) from sympy.assumptions.cnf import CNF, Literal from sympy.assumptions.satask import (satask, extract_predargs, get_relevant_clsfacts) from sympy.testing.pytest import raises, XFAIL x, y, z = symbols('x y z') def test_satask(): # No relevant facts assert satask(Q.real(x), Q.real(x)) is True assert satask(Q.real(x), ~Q.real(x)) is False assert satask(Q.real(x)) is None assert satask(Q.real(x), Q.positive(x)) is True assert satask(Q.positive(x), Q.real(x)) is None assert satask(Q.real(x), ~Q.positive(x)) is None assert satask(Q.positive(x), ~Q.real(x)) is False raises(ValueError, lambda: satask(Q.real(x), Q.real(x) & ~Q.real(x))) with assuming(Q.positive(x)): assert satask(Q.real(x)) is True assert satask(~Q.positive(x)) is False raises(ValueError, lambda: satask(Q.real(x), ~Q.positive(x))) assert satask(Q.zero(x), Q.nonzero(x)) is False assert satask(Q.positive(x), Q.zero(x)) is False assert satask(Q.real(x), Q.zero(x)) is True assert satask(Q.zero(x), Q.zero(x*y)) is None assert satask(Q.zero(x*y), Q.zero(x)) def test_zero(): """ Everything in this test doesn't work with the ask handlers, and most things would be very difficult or impossible to make work under that model. """ assert satask(Q.zero(x) | Q.zero(y), Q.zero(x*y)) is True assert satask(Q.zero(x*y), Q.zero(x) | Q.zero(y)) is True assert satask(Implies(Q.zero(x), Q.zero(x*y))) is True # This one in particular requires computing the fixed-point of the # relevant facts, because going from Q.nonzero(x*y) -> ~Q.zero(x*y) and # Q.zero(x*y) -> Equivalent(Q.zero(x*y), Q.zero(x) | Q.zero(y)) takes two # steps. assert satask(Q.zero(x) | Q.zero(y), Q.nonzero(x*y)) is False assert satask(Q.zero(x), Q.zero(x**2)) is True def test_zero_positive(): assert satask(Q.zero(x + y), Q.positive(x) & Q.positive(y)) is False assert satask(Q.positive(x) & Q.positive(y), Q.zero(x + y)) is False assert satask(Q.nonzero(x + y), Q.positive(x) & Q.positive(y)) is True assert satask(Q.positive(x) & Q.positive(y), Q.nonzero(x + y)) is None # This one requires several levels of forward chaining assert satask(Q.zero(x*(x + y)), Q.positive(x) & Q.positive(y)) is False assert satask(Q.positive(pi*x*y + 1), Q.positive(x) & Q.positive(y)) is True assert satask(Q.positive(pi*x*y - 5), Q.positive(x) & Q.positive(y)) is None def test_zero_pow(): assert satask(Q.zero(x**y), Q.zero(x) & Q.positive(y)) is True assert satask(Q.zero(x**y), Q.nonzero(x) & Q.zero(y)) is False assert satask(Q.zero(x), Q.zero(x**y)) is True assert satask(Q.zero(x**y), Q.zero(x)) is None @XFAIL # Requires correct Q.square calculation first def test_invertible(): A = MatrixSymbol('A', 5, 5) B = MatrixSymbol('B', 5, 5) assert satask(Q.invertible(A*B), Q.invertible(A) & Q.invertible(B)) is True assert satask(Q.invertible(A), Q.invertible(A*B)) is True assert satask(Q.invertible(A) & Q.invertible(B), Q.invertible(A*B)) is True def test_prime(): assert satask(Q.prime(5)) is True assert satask(Q.prime(6)) is False assert satask(Q.prime(-5)) is False assert satask(Q.prime(x*y), Q.integer(x) & Q.integer(y)) is None assert satask(Q.prime(x*y), Q.prime(x) & Q.prime(y)) is False def test_old_assump(): assert satask(Q.positive(1)) is True assert satask(Q.positive(-1)) is False assert satask(Q.positive(0)) is False assert satask(Q.positive(I)) is False assert satask(Q.positive(pi)) is True assert satask(Q.negative(1)) is False assert satask(Q.negative(-1)) is True assert satask(Q.negative(0)) is False assert satask(Q.negative(I)) is False assert satask(Q.negative(pi)) is False assert satask(Q.zero(1)) is False assert satask(Q.zero(-1)) is False assert satask(Q.zero(0)) is True assert satask(Q.zero(I)) is False assert satask(Q.zero(pi)) is False assert satask(Q.nonzero(1)) is True assert satask(Q.nonzero(-1)) is True assert satask(Q.nonzero(0)) is False assert satask(Q.nonzero(I)) is False assert satask(Q.nonzero(pi)) is True assert satask(Q.nonpositive(1)) is False assert satask(Q.nonpositive(-1)) is True assert satask(Q.nonpositive(0)) is True assert satask(Q.nonpositive(I)) is False assert satask(Q.nonpositive(pi)) is False assert satask(Q.nonnegative(1)) is True assert satask(Q.nonnegative(-1)) is False assert satask(Q.nonnegative(0)) is True assert satask(Q.nonnegative(I)) is False assert satask(Q.nonnegative(pi)) is True def test_rational_irrational(): assert satask(Q.irrational(2)) is False assert satask(Q.rational(2)) is True assert satask(Q.irrational(pi)) is True assert satask(Q.rational(pi)) is False assert satask(Q.irrational(I)) is False assert satask(Q.rational(I)) is False assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.irrational(y) & Q.rational(z)) is None assert satask(Q.irrational(x*y*z), Q.irrational(x) & Q.rational(y) & Q.rational(z)) is True assert satask(Q.irrational(pi*x*y), Q.rational(x) & Q.rational(y)) is True assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.irrational(y) & Q.rational(z)) is None assert satask(Q.irrational(x + y + z), Q.irrational(x) & Q.rational(y) & Q.rational(z)) is True assert satask(Q.irrational(pi + x + y), Q.rational(x) & Q.rational(y)) is True assert satask(Q.irrational(x*y*z), Q.rational(x) & Q.rational(y) & Q.rational(z)) is False assert satask(Q.rational(x*y*z), Q.rational(x) & Q.rational(y) & Q.rational(z)) is True assert satask(Q.irrational(x + y + z), Q.rational(x) & Q.rational(y) & Q.rational(z)) is False assert satask(Q.rational(x + y + z), Q.rational(x) & Q.rational(y) & Q.rational(z)) is True def test_even_satask(): assert satask(Q.even(2)) is True assert satask(Q.even(3)) is False assert satask(Q.even(x*y), Q.even(x) & Q.odd(y)) is True assert satask(Q.even(x*y), Q.even(x) & Q.integer(y)) is True assert satask(Q.even(x*y), Q.even(x) & Q.even(y)) is True assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False assert satask(Q.even(x*y), Q.even(x)) is None assert satask(Q.even(x*y), Q.odd(x) & Q.integer(y)) is None assert satask(Q.even(x*y), Q.odd(x) & Q.odd(y)) is False assert satask(Q.even(abs(x)), Q.even(x)) is True assert satask(Q.even(abs(x)), Q.odd(x)) is False assert satask(Q.even(x), Q.even(abs(x))) is None # x could be complex def test_odd_satask(): assert satask(Q.odd(2)) is False assert satask(Q.odd(3)) is True assert satask(Q.odd(x*y), Q.even(x) & Q.odd(y)) is False assert satask(Q.odd(x*y), Q.even(x) & Q.integer(y)) is False assert satask(Q.odd(x*y), Q.even(x) & Q.even(y)) is False assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True assert satask(Q.odd(x*y), Q.even(x)) is None assert satask(Q.odd(x*y), Q.odd(x) & Q.integer(y)) is None assert satask(Q.odd(x*y), Q.odd(x) & Q.odd(y)) is True assert satask(Q.odd(abs(x)), Q.even(x)) is False assert satask(Q.odd(abs(x)), Q.odd(x)) is True assert satask(Q.odd(x), Q.odd(abs(x))) is None # x could be complex def test_integer(): assert satask(Q.integer(1)) is True assert satask(Q.integer(S.Half)) is False assert satask(Q.integer(x + y), Q.integer(x) & Q.integer(y)) is True assert satask(Q.integer(x + y), Q.integer(x)) is None assert satask(Q.integer(x + y), Q.integer(x) & ~Q.integer(y)) is False assert satask(Q.integer(x + y + z), Q.integer(x) & Q.integer(y) & ~Q.integer(z)) is False assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y) & ~Q.integer(z)) is None assert satask(Q.integer(x + y + z), Q.integer(x) & ~Q.integer(y)) is None assert satask(Q.integer(x + y), Q.integer(x) & Q.irrational(y)) is False assert satask(Q.integer(x*y), Q.integer(x) & Q.integer(y)) is True assert satask(Q.integer(x*y), Q.integer(x)) is None assert satask(Q.integer(x*y), Q.integer(x) & ~Q.integer(y)) is None assert satask(Q.integer(x*y), Q.integer(x) & ~Q.rational(y)) is False assert satask(Q.integer(x*y*z), Q.integer(x) & Q.integer(y) & ~Q.rational(z)) is False assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y) & ~Q.rational(z)) is None assert satask(Q.integer(x*y*z), Q.integer(x) & ~Q.rational(y)) is None assert satask(Q.integer(x*y), Q.integer(x) & Q.irrational(y)) is False def test_abs(): assert satask(Q.nonnegative(abs(x))) is True assert satask(Q.positive(abs(x)), ~Q.zero(x)) is True assert satask(Q.zero(x), ~Q.zero(abs(x))) is False assert satask(Q.zero(x), Q.zero(abs(x))) is True assert satask(Q.nonzero(x), ~Q.zero(abs(x))) is None # x could be complex assert satask(Q.zero(abs(x)), Q.zero(x)) is True def test_imaginary(): assert satask(Q.imaginary(2*I)) is True assert satask(Q.imaginary(x*y), Q.imaginary(x)) is None assert satask(Q.imaginary(x*y), Q.imaginary(x) & Q.real(y)) is True assert satask(Q.imaginary(x), Q.real(x)) is False assert satask(Q.imaginary(1)) is False assert satask(Q.imaginary(x*y), Q.real(x) & Q.real(y)) is False assert satask(Q.imaginary(x + y), Q.real(x) & Q.real(y)) is False def test_real(): assert satask(Q.real(x*y), Q.real(x) & Q.real(y)) is True assert satask(Q.real(x + y), Q.real(x) & Q.real(y)) is True assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.real(z)) is True assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y)) is None assert satask(Q.real(x*y*z), Q.real(x) & Q.real(y) & Q.imaginary(z)) is False assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y) & Q.real(z)) is True assert satask(Q.real(x + y + z), Q.real(x) & Q.real(y)) is None def test_pos_neg(): assert satask(~Q.positive(x), Q.negative(x)) is True assert satask(~Q.negative(x), Q.positive(x)) is True assert satask(Q.positive(x + y), Q.positive(x) & Q.positive(y)) is True assert satask(Q.negative(x + y), Q.negative(x) & Q.negative(y)) is True assert satask(Q.positive(x + y), Q.negative(x) & Q.negative(y)) is False assert satask(Q.negative(x + y), Q.positive(x) & Q.positive(y)) is False def test_pow_pos_neg(): assert satask(Q.nonnegative(x**2), Q.positive(x)) is True assert satask(Q.nonpositive(x**2), Q.positive(x)) is False assert satask(Q.positive(x**2), Q.positive(x)) is True assert satask(Q.negative(x**2), Q.positive(x)) is False assert satask(Q.real(x**2), Q.positive(x)) is True assert satask(Q.nonnegative(x**2), Q.negative(x)) is True assert satask(Q.nonpositive(x**2), Q.negative(x)) is False assert satask(Q.positive(x**2), Q.negative(x)) is True assert satask(Q.negative(x**2), Q.negative(x)) is False assert satask(Q.real(x**2), Q.negative(x)) is True assert satask(Q.nonnegative(x**2), Q.nonnegative(x)) is True assert satask(Q.nonpositive(x**2), Q.nonnegative(x)) is None assert satask(Q.positive(x**2), Q.nonnegative(x)) is None assert satask(Q.negative(x**2), Q.nonnegative(x)) is False assert satask(Q.real(x**2), Q.nonnegative(x)) is True assert satask(Q.nonnegative(x**2), Q.nonpositive(x)) is True assert satask(Q.nonpositive(x**2), Q.nonpositive(x)) is None assert satask(Q.positive(x**2), Q.nonpositive(x)) is None assert satask(Q.negative(x**2), Q.nonpositive(x)) is False assert satask(Q.real(x**2), Q.nonpositive(x)) is True assert satask(Q.nonnegative(x**3), Q.positive(x)) is True assert satask(Q.nonpositive(x**3), Q.positive(x)) is False assert satask(Q.positive(x**3), Q.positive(x)) is True assert satask(Q.negative(x**3), Q.positive(x)) is False assert satask(Q.real(x**3), Q.positive(x)) is True assert satask(Q.nonnegative(x**3), Q.negative(x)) is False assert satask(Q.nonpositive(x**3), Q.negative(x)) is True assert satask(Q.positive(x**3), Q.negative(x)) is False assert satask(Q.negative(x**3), Q.negative(x)) is True assert satask(Q.real(x**3), Q.negative(x)) is True assert satask(Q.nonnegative(x**3), Q.nonnegative(x)) is True assert satask(Q.nonpositive(x**3), Q.nonnegative(x)) is None assert satask(Q.positive(x**3), Q.nonnegative(x)) is None assert satask(Q.negative(x**3), Q.nonnegative(x)) is False assert satask(Q.real(x**3), Q.nonnegative(x)) is True assert satask(Q.nonnegative(x**3), Q.nonpositive(x)) is None assert satask(Q.nonpositive(x**3), Q.nonpositive(x)) is True assert satask(Q.positive(x**3), Q.nonpositive(x)) is False assert satask(Q.negative(x**3), Q.nonpositive(x)) is None assert satask(Q.real(x**3), Q.nonpositive(x)) is True # If x is zero, x**negative is not real. assert satask(Q.nonnegative(x**-2), Q.nonpositive(x)) is None assert satask(Q.nonpositive(x**-2), Q.nonpositive(x)) is None assert satask(Q.positive(x**-2), Q.nonpositive(x)) is None assert satask(Q.negative(x**-2), Q.nonpositive(x)) is None assert satask(Q.real(x**-2), Q.nonpositive(x)) is None # We could deduce things for negative powers if x is nonzero, but it # isn't implemented yet. def test_prime_composite(): assert satask(Q.prime(x), Q.composite(x)) is False assert satask(Q.composite(x), Q.prime(x)) is False assert satask(Q.composite(x), ~Q.prime(x)) is None assert satask(Q.prime(x), ~Q.composite(x)) is None # since 1 is neither prime nor composite the following should hold assert satask(Q.prime(x), Q.integer(x) & Q.positive(x) & ~Q.composite(x)) is None assert satask(Q.prime(2)) is True assert satask(Q.prime(4)) is False assert satask(Q.prime(1)) is False assert satask(Q.composite(1)) is False def test_extract_predargs(): props = CNF.from_prop(Q.zero(Abs(x*y)) & Q.zero(x*y)) assump = CNF.from_prop(Q.zero(x)) context = CNF.from_prop(Q.zero(y)) assert extract_predargs(props) == {Abs(x*y), x*y} assert extract_predargs(props, assump) == {Abs(x*y), x*y, x} assert extract_predargs(props, assump, context) == {Abs(x*y), x*y, x, y} props = CNF.from_prop(Eq(x, y)) assump = CNF.from_prop(Gt(y, z)) assert extract_predargs(props, assump) == {x, y, z} def test_get_relevant_clsfacts(): exprs = {Abs(x*y)} exprs, facts = get_relevant_clsfacts(exprs) assert exprs == {x*y} assert facts.clauses == \ {frozenset({Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}), frozenset({Literal(Q.zero(Abs(x*y)), False), Literal(Q.zero(x*y), True)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True)}), frozenset({Literal(Q.zero(Abs(x*y)), True), Literal(Q.zero(x*y), False)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.odd(Abs(x*y)), False), Literal(Q.odd(x*y), True)}), frozenset({Literal(Q.even(Abs(x*y)), False), Literal(Q.even(x*y), True), Literal(Q.odd(Abs(x*y)), False)}), frozenset({Literal(Q.positive(Abs(x*y)), False), Literal(Q.zero(Abs(x*y)), False)})} sympy-sympy-1.9/sympy/assumptions/tests/test_sathandlers.py000066400000000000000000000032231412543434000245540ustar00rootroot00000000000000from sympy import Mul, Basic, Q, Expr, And, symbols, Or from sympy.assumptions.sathandlers import (ClassFactRegistry, allargs, anyarg, exactlyonearg,) x, y, z = symbols('x y z') def test_class_handler_registry(): my_handler_registry = ClassFactRegistry() # The predicate doesn't matter here, so just pass @my_handler_registry.register(Mul) def fact1(expr): pass @my_handler_registry.multiregister(Expr) def fact2(expr): pass assert my_handler_registry[Basic] == (frozenset(), frozenset()) assert my_handler_registry[Expr] == (frozenset(), frozenset({fact2})) assert my_handler_registry[Mul] == (frozenset({fact1}), frozenset({fact2})) def test_allargs(): assert allargs(x, Q.zero(x), x*y) == And(Q.zero(x), Q.zero(y)) assert allargs(x, Q.positive(x) | Q.negative(x), x*y) == And(Q.positive(x) | Q.negative(x), Q.positive(y) | Q.negative(y)) def test_anyarg(): assert anyarg(x, Q.zero(x), x*y) == Or(Q.zero(x), Q.zero(y)) assert anyarg(x, Q.positive(x) & Q.negative(x), x*y) == \ Or(Q.positive(x) & Q.negative(x), Q.positive(y) & Q.negative(y)) def test_exactlyonearg(): assert exactlyonearg(x, Q.zero(x), x*y) == \ Or(Q.zero(x) & ~Q.zero(y), Q.zero(y) & ~Q.zero(x)) assert exactlyonearg(x, Q.zero(x), x*y*z) == \ Or(Q.zero(x) & ~Q.zero(y) & ~Q.zero(z), Q.zero(y) & ~Q.zero(x) & ~Q.zero(z), Q.zero(z) & ~Q.zero(x) & ~Q.zero(y)) assert exactlyonearg(x, Q.positive(x) | Q.negative(x), x*y) == \ Or((Q.positive(x) | Q.negative(x)) & ~(Q.positive(y) | Q.negative(y)), (Q.positive(y) | Q.negative(y)) & ~(Q.positive(x) | Q.negative(x))) sympy-sympy-1.9/sympy/assumptions/tests/test_wrapper.py000066400000000000000000000016101412543434000237220ustar00rootroot00000000000000from sympy import Symbol, Q from sympy.assumptions.wrapper import (AssumptionsWrapper, is_infinite, is_extended_real) def test_AssumptionsWrapper(): x = Symbol('x', positive=True) y = Symbol('y') assert AssumptionsWrapper(x).is_positive assert AssumptionsWrapper(y).is_positive is None assert AssumptionsWrapper(y, Q.positive(y)).is_positive def test_is_infinite(): x = Symbol('x', infinite=True) y = Symbol('y', infinite=False) z = Symbol('z') assert is_infinite(x) assert not is_infinite(y) assert is_infinite(z) is None assert is_infinite(z, Q.infinite(z)) def test_is_extended_real(): x = Symbol('x', extended_real=True) y = Symbol('y', extended_real=False) z = Symbol('z') assert is_extended_real(x) assert not is_extended_real(y) assert is_extended_real(z) is None assert is_extended_real(z, Q.extended_real(z)) sympy-sympy-1.9/sympy/assumptions/wrapper.py000066400000000000000000000101441412543434000215230ustar00rootroot00000000000000""" Functions and wrapper object to call assumption property and predicate query with same syntax. In SymPy, there are two assumption systems. Old assumption system is defined in sympy/core/assumptions, and it can be accessed by attribute such as ``x.is_even``. New assumption system is definded in sympy/assumptions, and it can be accessed by predicates such as ``Q.even(x)``. Old assumption is fast, while new assumptions can freely take local facts. In general, old assumption is used in evaluation method and new assumption is used in refinement method. In most cases, both evaluation and refinement follow the same process, and the only difference is which assumption system is used. This module provides ``is_[...]()`` functions and ``AssumptionsWrapper()`` class which allows using two systems with same syntax so that parallel code implementation can be avoided. Examples ======== For multiple use, use ``AssumptionsWrapper()``. >>> from sympy import Q, Symbol >>> from sympy.assumptions.wrapper import AssumptionsWrapper >>> x = Symbol('x') >>> _x = AssumptionsWrapper(x, Q.even(x)) >>> _x.is_integer True >>> _x.is_odd False For single use, use ``is_[...]()`` functions. >>> from sympy.assumptions.wrapper import is_infinite >>> a = Symbol('a') >>> print(is_infinite(a)) None >>> is_infinite(a, Q.finite(a)) False """ from sympy.assumptions import ask, Q from sympy.core.assumptions import (_assume_defined, as_property, ManagedProperties) from sympy.core.basic import Basic class AssumptionsWrapperMeta(ManagedProperties): """ Metaclass to give _eval_is_[...] attributes to AssumptionsWrapper """ def __init__(cls, *args, **kws): for fact in _assume_defined: pname = "_eval_%s" % as_property(fact) setattr(cls, pname, make_eval_method(fact)) super().__init__(cls, *args, **kws) def make_eval_method(fact): def getit(self): try: pred = getattr(Q, fact) ret = ask(pred(self.expr), self.assumptions) return ret except AttributeError: return None return getit # we subclass Basic to use the fact deduction and caching class AssumptionsWrapper(Basic, metaclass=AssumptionsWrapperMeta): """ Wrapper over ``Basic`` instances to call predicate query by ``.is_[...]`` property Parameters ========== expr : Basic assumptions : Boolean, optional Examples ======== >>> from sympy import Q, Symbol >>> from sympy.assumptions.wrapper import AssumptionsWrapper >>> x = Symbol('x', even=True) >>> AssumptionsWrapper(x).is_integer True >>> y = Symbol('y') >>> AssumptionsWrapper(y, Q.even(y)).is_integer True With ``AssumptionsWrapper``, both evaluation and refinement can be supported by single implementation. >>> from sympy import Function >>> class MyAbs(Function): ... @classmethod ... def eval(cls, x, assumptions=True): ... _x = AssumptionsWrapper(x, assumptions) ... if _x.is_nonnegative: ... return x ... if _x.is_negative: ... return -x ... def _eval_refine(self, assumptions): ... return MyAbs.eval(self.args[0], assumptions) >>> MyAbs(x) MyAbs(x) >>> MyAbs(x).refine(Q.positive(x)) x >>> MyAbs(Symbol('y', negative=True)) -y """ def __new__(cls, expr, assumptions=None): if assumptions is None: return expr obj = super().__new__(cls, expr, assumptions) obj.expr = expr obj.assumptions = assumptions return obj # one shot functions which are faster than AssumptionsWrapper def is_infinite(obj, assumptions=None): if assumptions is None: return obj.is_infinite return ask(Q.infinite(obj), assumptions) def is_extended_real(obj, assumptions=None): if assumptions is None: return obj.is_extended_real return ask(Q.extended_real(obj), assumptions) def is_extended_nonnegative(obj, assumptions=None): if assumptions is None: return obj.is_extended_nonnegative return ask(Q.extended_nonnegative(obj), assumptions) sympy-sympy-1.9/sympy/benchmarks/000077500000000000000000000000001412543434000172215ustar00rootroot00000000000000sympy-sympy-1.9/sympy/benchmarks/__init__.py000066400000000000000000000000001412543434000213200ustar00rootroot00000000000000sympy-sympy-1.9/sympy/benchmarks/bench_discrete_log.py000066400000000000000000000046511412543434000234030ustar00rootroot00000000000000import sys from time import time from sympy.ntheory.residue_ntheory import (discrete_log, _discrete_log_trial_mul, _discrete_log_shanks_steps, _discrete_log_pollard_rho, _discrete_log_pohlig_hellman) # Cyclic group (Z/pZ)* with p prime, order p - 1 and generator g data_set_1 = [ # p, p - 1, g [191, 190, 19], [46639, 46638, 6], [14789363, 14789362, 2], [4254225211, 4254225210, 2], [432751500361, 432751500360, 7], [158505390797053, 158505390797052, 2], [6575202655312007, 6575202655312006, 5], [8430573471995353769, 8430573471995353768, 3], [3938471339744997827267, 3938471339744997827266, 2], [875260951364705563393093, 875260951364705563393092, 5], ] # Cyclic sub-groups of (Z/nZ)* with prime order p and generator g # (n, p are primes and n = 2 * p + 1) data_set_2 = [ # n, p, g [227, 113, 3], [2447, 1223, 2], [24527, 12263, 2], [245639, 122819, 2], [2456747, 1228373, 3], [24567899, 12283949, 3], [245679023, 122839511, 2], [2456791307, 1228395653, 3], [24567913439, 12283956719, 2], [245679135407, 122839567703, 2], [2456791354763, 1228395677381, 3], [24567913550903, 12283956775451, 2], [245679135509519, 122839567754759, 2], ] # Cyclic sub-groups of (Z/nZ)* with smooth order o and generator g data_set_3 = [ # n, o, g [2**118, 2**116, 3], ] def bench_discrete_log(data_set, algo=None): if algo is None: f = discrete_log elif algo == 'trial': f = _discrete_log_trial_mul elif algo == 'shanks': f = _discrete_log_shanks_steps elif algo == 'rho': f = _discrete_log_pollard_rho elif algo == 'ph': f = _discrete_log_pohlig_hellman else: raise ValueError("Argument 'algo' should be one" " of ('trial', 'shanks', 'rho' or 'ph')") for i, data in enumerate(data_set): for j, (n, p, g) in enumerate(data): t = time() l = f(n, pow(g, p - 1, n), g, p) t = time() - t print('[%02d-%03d] %15.10f' % (i, j, t)) assert l == p - 1 if __name__ == '__main__': algo = sys.argv[1] \ if len(sys.argv) > 1 else None data_set = [ data_set_1, data_set_2, data_set_3, ] bench_discrete_log(data_set, algo) sympy-sympy-1.9/sympy/benchmarks/bench_meijerint.py000066400000000000000000000261061412543434000227250ustar00rootroot00000000000000# conceal the implicit import from the code quality tester from sympy import (exp, gamma, integrate, oo, pi, sqrt, Symbol, symbols, besseli, laplace_transform, fourier_transform, mellin_transform, inverse_fourier_transform, inverse_laplace_transform, inverse_mellin_transform) LT = laplace_transform FT = fourier_transform MT = mellin_transform IFT = inverse_fourier_transform ILT = inverse_laplace_transform IMT = inverse_mellin_transform from sympy.abc import x, y nu, beta, rho = symbols('nu beta rho') apos, bpos, cpos, dpos, posk, p = symbols('a b c d k p', positive=True) k = Symbol('k', real=True) negk = Symbol('k', negative=True) mu1, mu2 = symbols('mu1 mu2', real=True, nonzero=True, finite=True) sigma1, sigma2 = symbols('sigma1 sigma2', real=True, nonzero=True, finite=True, positive=True) rate = Symbol('lambda', real=True, positive=True, finite=True) def normal(x, mu, sigma): return 1/sqrt(2*pi*sigma**2)*exp(-(x - mu)**2/2/sigma**2) def exponential(x, rate): return rate*exp(-rate*x) alpha, beta = symbols('alpha beta', positive=True) betadist = x**(alpha - 1)*(1 + x)**(-alpha - beta)*gamma(alpha + beta) \ /gamma(alpha)/gamma(beta) kint = Symbol('k', integer=True, positive=True) chi = 2**(1 - kint/2)*x**(kint - 1)*exp(-x**2/2)/gamma(kint/2) chisquared = 2**(-k/2)/gamma(k/2)*x**(k/2 - 1)*exp(-x/2) dagum = apos*p/x*(x/bpos)**(apos*p)/(1 + x**apos/bpos**apos)**(p + 1) d1, d2 = symbols('d1 d2', positive=True) f = sqrt(((d1*x)**d1 * d2**d2)/(d1*x + d2)**(d1 + d2))/x \ /gamma(d1/2)/gamma(d2/2)*gamma((d1 + d2)/2) nupos, sigmapos = symbols('nu sigma', positive=True) rice = x/sigmapos**2*exp(-(x**2 + nupos**2)/2/sigmapos**2)*besseli(0, x* nupos/sigmapos**2) mu = Symbol('mu', real=True) laplace = exp(-abs(x - mu)/bpos)/2/bpos u = Symbol('u', polar=True) tpos = Symbol('t', positive=True) def E(expr): integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), (x, 0, oo), (y, -oo, oo), meijerg=True) integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), (y, -oo, oo), (x, 0, oo), meijerg=True) bench = [ 'MT(x**nu*Heaviside(x - 1), x, s)', 'MT(x**nu*Heaviside(1 - x), x, s)', 'MT((1-x)**(beta - 1)*Heaviside(1-x), x, s)', 'MT((x-1)**(beta - 1)*Heaviside(x-1), x, s)', 'MT((1+x)**(-rho), x, s)', 'MT(abs(1-x)**(-rho), x, s)', 'MT((1-x)**(beta-1)*Heaviside(1-x) + a*(x-1)**(beta-1)*Heaviside(x-1), x, s)', 'MT((x**a-b**a)/(x-b), x, s)', 'MT((x**a-bpos**a)/(x-bpos), x, s)', 'MT(exp(-x), x, s)', 'MT(exp(-1/x), x, s)', 'MT(log(x)**4*Heaviside(1-x), x, s)', 'MT(log(x)**3*Heaviside(x-1), x, s)', 'MT(log(x + 1), x, s)', 'MT(log(1/x + 1), x, s)', 'MT(log(abs(1 - x)), x, s)', 'MT(log(abs(1 - 1/x)), x, s)', 'MT(log(x)/(x+1), x, s)', 'MT(log(x)**2/(x+1), x, s)', 'MT(log(x)/(x+1)**2, x, s)', 'MT(erf(sqrt(x)), x, s)', 'MT(besselj(a, 2*sqrt(x)), x, s)', 'MT(sin(sqrt(x))*besselj(a, sqrt(x)), x, s)', 'MT(cos(sqrt(x))*besselj(a, sqrt(x)), x, s)', 'MT(besselj(a, sqrt(x))**2, x, s)', 'MT(besselj(a, sqrt(x))*besselj(-a, sqrt(x)), x, s)', 'MT(besselj(a - 1, sqrt(x))*besselj(a, sqrt(x)), x, s)', 'MT(besselj(a, sqrt(x))*besselj(b, sqrt(x)), x, s)', 'MT(besselj(a, sqrt(x))**2 + besselj(-a, sqrt(x))**2, x, s)', 'MT(bessely(a, 2*sqrt(x)), x, s)', 'MT(sin(sqrt(x))*bessely(a, sqrt(x)), x, s)', 'MT(cos(sqrt(x))*bessely(a, sqrt(x)), x, s)', 'MT(besselj(a, sqrt(x))*bessely(a, sqrt(x)), x, s)', 'MT(besselj(a, sqrt(x))*bessely(b, sqrt(x)), x, s)', 'MT(bessely(a, sqrt(x))**2, x, s)', 'MT(besselk(a, 2*sqrt(x)), x, s)', 'MT(besselj(a, 2*sqrt(2*sqrt(x)))*besselk(a, 2*sqrt(2*sqrt(x))), x, s)', 'MT(besseli(a, sqrt(x))*besselk(a, sqrt(x)), x, s)', 'MT(besseli(b, sqrt(x))*besselk(a, sqrt(x)), x, s)', 'MT(exp(-x/2)*besselk(a, x/2), x, s)', # later: ILT, IMT 'LT((t-apos)**bpos*exp(-cpos*(t-apos))*Heaviside(t-apos), t, s)', 'LT(t**apos, t, s)', 'LT(Heaviside(t), t, s)', 'LT(Heaviside(t - apos), t, s)', 'LT(1 - exp(-apos*t), t, s)', 'LT((exp(2*t)-1)*exp(-bpos - t)*Heaviside(t)/2, t, s, noconds=True)', 'LT(exp(t), t, s)', 'LT(exp(2*t), t, s)', 'LT(exp(apos*t), t, s)', 'LT(log(t/apos), t, s)', 'LT(erf(t), t, s)', 'LT(sin(apos*t), t, s)', 'LT(cos(apos*t), t, s)', 'LT(exp(-apos*t)*sin(bpos*t), t, s)', 'LT(exp(-apos*t)*cos(bpos*t), t, s)', 'LT(besselj(0, t), t, s, noconds=True)', 'LT(besselj(1, t), t, s, noconds=True)', 'FT(Heaviside(1 - abs(2*apos*x)), x, k)', 'FT(Heaviside(1-abs(apos*x))*(1-abs(apos*x)), x, k)', 'FT(exp(-apos*x)*Heaviside(x), x, k)', 'IFT(1/(apos + 2*pi*I*x), x, posk, noconds=False)', 'IFT(1/(apos + 2*pi*I*x), x, -posk, noconds=False)', 'IFT(1/(apos + 2*pi*I*x), x, negk)', 'FT(x*exp(-apos*x)*Heaviside(x), x, k)', 'FT(exp(-apos*x)*sin(bpos*x)*Heaviside(x), x, k)', 'FT(exp(-apos*x**2), x, k)', 'IFT(sqrt(pi/apos)*exp(-(pi*k)**2/apos), k, x)', 'FT(exp(-apos*abs(x)), x, k)', 'integrate(normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', 'integrate(x*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', 'integrate(x**2*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', 'integrate(x**3*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True)', 'integrate(normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate(x*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate(y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate(x*y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate((x+y+1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate((x+y-1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate(x**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate(y**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2),' ' (x, -oo, oo), (y, -oo, oo), meijerg=True)', 'integrate(exponential(x, rate), (x, 0, oo), meijerg=True)', 'integrate(x*exponential(x, rate), (x, 0, oo), meijerg=True)', 'integrate(x**2*exponential(x, rate), (x, 0, oo), meijerg=True)', 'E(1)', 'E(x*y)', 'E(x*y**2)', 'E((x+y+1)**2)', 'E(x+y+1)', 'E((x+y-1)**2)', 'integrate(betadist, (x, 0, oo), meijerg=True)', 'integrate(x*betadist, (x, 0, oo), meijerg=True)', 'integrate(x**2*betadist, (x, 0, oo), meijerg=True)', 'integrate(chi, (x, 0, oo), meijerg=True)', 'integrate(x*chi, (x, 0, oo), meijerg=True)', 'integrate(x**2*chi, (x, 0, oo), meijerg=True)', 'integrate(chisquared, (x, 0, oo), meijerg=True)', 'integrate(x*chisquared, (x, 0, oo), meijerg=True)', 'integrate(x**2*chisquared, (x, 0, oo), meijerg=True)', 'integrate(((x-k)/sqrt(2*k))**3*chisquared, (x, 0, oo), meijerg=True)', 'integrate(dagum, (x, 0, oo), meijerg=True)', 'integrate(x*dagum, (x, 0, oo), meijerg=True)', 'integrate(x**2*dagum, (x, 0, oo), meijerg=True)', 'integrate(f, (x, 0, oo), meijerg=True)', 'integrate(x*f, (x, 0, oo), meijerg=True)', 'integrate(x**2*f, (x, 0, oo), meijerg=True)', 'integrate(rice, (x, 0, oo), meijerg=True)', 'integrate(laplace, (x, -oo, oo), meijerg=True)', 'integrate(x*laplace, (x, -oo, oo), meijerg=True)', 'integrate(x**2*laplace, (x, -oo, oo), meijerg=True)', 'integrate(log(x) * x**(k-1) * exp(-x) / gamma(k), (x, 0, oo))', 'integrate(sin(z*x)*(x**2-1)**(-(y+S(1)/2)), (x, 1, oo), meijerg=True)', 'integrate(besselj(0,x)*besselj(1,x)*exp(-x**2), (x, 0, oo), meijerg=True)', 'integrate(besselj(0,x)*besselj(1,x)*besselk(0,x), (x, 0, oo), meijerg=True)', 'integrate(besselj(0,x)*besselj(1,x)*exp(-x**2), (x, 0, oo), meijerg=True)', 'integrate(besselj(a,x)*besselj(b,x)/x, (x,0,oo), meijerg=True)', 'hyperexpand(meijerg((-s - a/2 + 1, -s + a/2 + 1), (-a/2 - S(1)/2, -s + a/2 + S(3)/2), (a/2, -a/2), (-a/2 - S(1)/2, -s + a/2 + S(3)/2), 1))', "gammasimp(S('2**(2*s)*(-pi*gamma(-a + 1)*gamma(a + 1)*gamma(-a - s + 1)*gamma(-a + s - 1/2)*gamma(a - s + 3/2)*gamma(a + s + 1)/(a*(a + s)) - gamma(-a - 1/2)*gamma(-a + 1)*gamma(a + 1)*gamma(a + 3/2)*gamma(-s + 3/2)*gamma(s - 1/2)*gamma(-a + s + 1)*gamma(a - s + 1)/(a*(-a + s)))*gamma(-2*s + 1)*gamma(s + 1)/(pi*s*gamma(-a - 1/2)*gamma(a + 3/2)*gamma(-s + 1)*gamma(-s + 3/2)*gamma(s - 1/2)*gamma(-a - s + 1)*gamma(-a + s - 1/2)*gamma(a - s + 1)*gamma(a - s + 3/2))'))", 'mellin_transform(E1(x), x, s)', 'inverse_mellin_transform(gamma(s)/s, s, x, (0, oo))', 'mellin_transform(expint(a, x), x, s)', 'mellin_transform(Si(x), x, s)', 'inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2)/(2*s*gamma(-s/2 + 1)), s, x, (-1, 0))', 'mellin_transform(Ci(sqrt(x)), x, s)', 'inverse_mellin_transform(-4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S(1)/2)),s, u, (0, 1))', 'laplace_transform(Ci(x), x, s)', 'laplace_transform(expint(a, x), x, s)', 'laplace_transform(expint(1, x), x, s)', 'laplace_transform(expint(2, x), x, s)', 'inverse_laplace_transform(-log(1 + s**2)/2/s, s, u)', 'inverse_laplace_transform(log(s + 1)/s, s, x)', 'inverse_laplace_transform((s - log(s + 1))/s**2, s, x)', 'laplace_transform(Chi(x), x, s)', 'laplace_transform(Shi(x), x, s)', 'integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True, conds="none")', 'integrate(exp(-z*x)/x**2, (x, 1, oo), meijerg=True, conds="none")', 'integrate(exp(-z*x)/x**3, (x, 1, oo), meijerg=True,conds="none")', 'integrate(-cos(x)/x, (x, tpos, oo), meijerg=True)', 'integrate(-sin(x)/x, (x, tpos, oo), meijerg=True)', 'integrate(sin(x)/x, (x, 0, z), meijerg=True)', 'integrate(sinh(x)/x, (x, 0, z), meijerg=True)', 'integrate(exp(-x)/x, x, meijerg=True)', 'integrate(exp(-x)/x**2, x, meijerg=True)', 'integrate(cos(u)/u, u, meijerg=True)', 'integrate(cosh(u)/u, u, meijerg=True)', 'integrate(expint(1, x), x, meijerg=True)', 'integrate(expint(2, x), x, meijerg=True)', 'integrate(Si(x), x, meijerg=True)', 'integrate(Ci(u), u, meijerg=True)', 'integrate(Shi(x), x, meijerg=True)', 'integrate(Chi(u), u, meijerg=True)', 'integrate(Si(x)*exp(-x), (x, 0, oo), meijerg=True)', 'integrate(expint(1, x)*sin(x), (x, 0, oo), meijerg=True)' ] from time import time from sympy.core.cache import clear_cache import sys timings = [] if __name__ == '__main__': for n, string in enumerate(bench): clear_cache() _t = time() exec(string) _t = time() - _t timings += [(_t, string)] sys.stdout.write('.') sys.stdout.flush() if n % (len(bench) // 10) == 0: sys.stdout.write('%s' % (10*n // len(bench))) print() timings.sort(key=lambda x: -x[0]) for ti, string in timings: print('%.2fs %s' % (ti, string)) sympy-sympy-1.9/sympy/benchmarks/bench_symbench.py000066400000000000000000000052641412543434000225510ustar00rootroot00000000000000#!/usr/bin/env python from random import random from sympy import factor, I, Integer, pi, simplify, sin, sqrt, Symbol, sympify from sympy.abc import x, y, z from timeit import default_timer as clock def bench_R1(): "real(f(f(f(f(f(f(f(f(f(f(i/2)))))))))))" def f(z): return sqrt(Integer(1)/3)*z**2 + I/3 f(f(f(f(f(f(f(f(f(f(I/2)))))))))).as_real_imag()[0] def bench_R2(): "Hermite polynomial hermite(15, y)" def hermite(n, y): if n == 1: return 2*y if n == 0: return 1 return (2*y*hermite(n - 1, y) - 2*(n - 1)*hermite(n - 2, y)).expand() hermite(15, y) def bench_R3(): "a = [bool(f==f) for _ in range(10)]" f = x + y + z [bool(f == f) for _ in range(10)] def bench_R4(): # we don't have Tuples pass def bench_R5(): "blowup(L, 8); L=uniq(L)" def blowup(L, n): for i in range(n): L.append( (L[i] + L[i + 1]) * L[i + 2] ) def uniq(x): v = set(x) return v L = [x, y, z] blowup(L, 8) L = uniq(L) def bench_R6(): "sum(simplify((x+sin(i))/x+(x-sin(i))/x) for i in range(100))" sum(simplify((x + sin(i))/x + (x - sin(i))/x) for i in range(100)) def bench_R7(): "[f.subs(x, random()) for _ in range(10**4)]" f = x**24 + 34*x**12 + 45*x**3 + 9*x**18 + 34*x**10 + 32*x**21 [f.subs(x, random()) for _ in range(10**4)] def bench_R8(): "right(x^2,0,5,10^4)" def right(f, a, b, n): a = sympify(a) b = sympify(b) n = sympify(n) x = f.atoms(Symbol).pop() Deltax = (b - a)/n c = a est = 0 for i in range(n): c += Deltax est += f.subs(x, c) return est*Deltax right(x**2, 0, 5, 10**4) def _bench_R9(): "factor(x^20 - pi^5*y^20)" factor(x**20 - pi**5*y**20) def bench_R10(): "v = [-pi,-pi+1/10..,pi]" def srange(min, max, step): v = [min] while (max - v[-1]).evalf() > 0: v.append(v[-1] + step) return v[:-1] srange(-pi, pi, sympify(1)/10) def bench_R11(): "a = [random() + random()*I for w in [0..1000]]" [random() + random()*I for w in range(1000)] def bench_S1(): "e=(x+y+z+1)**7;f=e*(e+1);f.expand()" e = (x + y + z + 1)**7 f = e*(e + 1) f.expand() if __name__ == '__main__': benchmarks = [ bench_R1, bench_R2, bench_R3, bench_R5, bench_R6, bench_R7, bench_R8, #_bench_R9, bench_R10, bench_R11, #bench_S1, ] report = [] for b in benchmarks: t = clock() b() t = clock() - t print("%s%65s: %f" % (b.__name__, b.__doc__, t)) sympy-sympy-1.9/sympy/calculus/000077500000000000000000000000001412543434000167175ustar00rootroot00000000000000sympy-sympy-1.9/sympy/calculus/__init__.py000066400000000000000000000014761412543434000210400ustar00rootroot00000000000000"""Calculus-related methods.""" from .euler import euler_equations from .singularities import (singularities, is_increasing, is_strictly_increasing, is_decreasing, is_strictly_decreasing, is_monotonic) from .finite_diff import finite_diff_weights, apply_finite_diff, as_finite_diff, differentiate_finite from .util import (periodicity, not_empty_in, AccumBounds, is_convex, stationary_points, minimum, maximum) __all__ = [ 'euler_equations', 'singularities', 'is_increasing', 'is_strictly_increasing', 'is_decreasing', 'is_strictly_decreasing', 'is_monotonic', 'finite_diff_weights', 'apply_finite_diff', 'as_finite_diff', 'differentiate_finite', 'periodicity', 'not_empty_in', 'AccumBounds', 'is_convex', 'stationary_points', 'minimum', 'maximum' ] sympy-sympy-1.9/sympy/calculus/euler.py000066400000000000000000000063001412543434000204040ustar00rootroot00000000000000""" This module implements a method to find Euler-Lagrange Equations for given Lagrangian. """ from itertools import combinations_with_replacement from sympy import Function, sympify, diff, Eq, S, Symbol, Derivative from sympy.core.compatibility import iterable def euler_equations(L, funcs=(), vars=()): r""" Find the Euler-Lagrange equations [1]_ for a given Lagrangian. Parameters ========== L : Expr The Lagrangian that should be a function of the functions listed in the second argument and their derivatives. For example, in the case of two functions `f(x,y)`, `g(x,y)` and two independent variables `x`, `y` the Lagrangian would have the form: .. math:: L\left(f(x,y),g(x,y),\frac{\partial f(x,y)}{\partial x}, \frac{\partial f(x,y)}{\partial y}, \frac{\partial g(x,y)}{\partial x}, \frac{\partial g(x,y)}{\partial y},x,y\right) In many cases it is not necessary to provide anything, except the Lagrangian, it will be auto-detected (and an error raised if this couldn't be done). funcs : Function or an iterable of Functions The functions that the Lagrangian depends on. The Euler equations are differential equations for each of these functions. vars : Symbol or an iterable of Symbols The Symbols that are the independent variables of the functions. Returns ======= eqns : list of Eq The list of differential equations, one for each function. Examples ======== >>> from sympy import Symbol, Function >>> from sympy.calculus.euler import euler_equations >>> x = Function('x') >>> t = Symbol('t') >>> L = (x(t).diff(t))**2/2 - x(t)**2/2 >>> euler_equations(L, x(t), t) [Eq(-x(t) - Derivative(x(t), (t, 2)), 0)] >>> u = Function('u') >>> x = Symbol('x') >>> L = (u(t, x).diff(t))**2/2 - (u(t, x).diff(x))**2/2 >>> euler_equations(L, u(t, x), [t, x]) [Eq(-Derivative(u(t, x), (t, 2)) + Derivative(u(t, x), (x, 2)), 0)] References ========== .. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Lagrange_equation """ funcs = tuple(funcs) if iterable(funcs) else (funcs,) if not funcs: funcs = tuple(L.atoms(Function)) else: for f in funcs: if not isinstance(f, Function): raise TypeError('Function expected, got: %s' % f) vars = tuple(vars) if iterable(vars) else (vars,) if not vars: vars = funcs[0].args else: vars = tuple(sympify(var) for var in vars) if not all(isinstance(v, Symbol) for v in vars): raise TypeError('Variables are not symbols, got %s' % vars) for f in funcs: if not vars == f.args: raise ValueError("Variables %s don't match args: %s" % (vars, f)) order = max(len(d.variables) for d in L.atoms(Derivative) if d.expr in funcs) eqns = [] for f in funcs: eq = diff(L, f) for i in range(1, order + 1): for p in combinations_with_replacement(vars, i): eq = eq + S.NegativeOne**i*diff(L, diff(f, *p), *p) eqns.append(Eq(eq, 0)) return eqns sympy-sympy-1.9/sympy/calculus/finite_diff.py000066400000000000000000000420721412543434000215440ustar00rootroot00000000000000""" Finite difference weights ========================= This module implements an algorithm for efficient generation of finite difference weights for ordinary differentials of functions for derivatives from 0 (interpolation) up to arbitrary order. The core algorithm is provided in the finite difference weight generating function (``finite_diff_weights``), and two convenience functions are provided for: - estimating a derivative (or interpolate) directly from a series of points is also provided (``apply_finite_diff``). - differentiating by using finite difference approximations (``differentiate_finite``). """ from sympy import Derivative, S from sympy.core.basic import preorder_traversal from sympy.core.compatibility import iterable from sympy.core.decorators import deprecated from sympy.core.function import Subs from sympy.utilities.exceptions import SymPyDeprecationWarning def finite_diff_weights(order, x_list, x0=S.One): """ Calculates the finite difference weights for an arbitrarily spaced one-dimensional grid (``x_list``) for derivatives at ``x0`` of order 0, 1, ..., up to ``order`` using a recursive formula. Order of accuracy is at least ``len(x_list) - order``, if ``x_list`` is defined correctly. Parameters ========== order: int Up to what derivative order weights should be calculated. 0 corresponds to interpolation. x_list: sequence Sequence of (unique) values for the independent variable. It is useful (but not necessary) to order ``x_list`` from nearest to furthest from ``x0``; see examples below. x0: Number or Symbol Root or value of the independent variable for which the finite difference weights should be generated. Default is ``S.One``. Returns ======= list A list of sublists, each corresponding to coefficients for increasing derivative order, and each containing lists of coefficients for increasing subsets of x_list. Examples ======== >>> from sympy import S >>> from sympy.calculus import finite_diff_weights >>> res = finite_diff_weights(1, [-S(1)/2, S(1)/2, S(3)/2, S(5)/2], 0) >>> res [[[1, 0, 0, 0], [1/2, 1/2, 0, 0], [3/8, 3/4, -1/8, 0], [5/16, 15/16, -5/16, 1/16]], [[0, 0, 0, 0], [-1, 1, 0, 0], [-1, 1, 0, 0], [-23/24, 7/8, 1/8, -1/24]]] >>> res[0][-1] # FD weights for 0th derivative, using full x_list [5/16, 15/16, -5/16, 1/16] >>> res[1][-1] # FD weights for 1st derivative [-23/24, 7/8, 1/8, -1/24] >>> res[1][-2] # FD weights for 1st derivative, using x_list[:-1] [-1, 1, 0, 0] >>> res[1][-1][0] # FD weight for 1st deriv. for x_list[0] -23/24 >>> res[1][-1][1] # FD weight for 1st deriv. for x_list[1], etc. 7/8 Each sublist contains the most accurate formula at the end. Note, that in the above example ``res[1][1]`` is the same as ``res[1][2]``. Since res[1][2] has an order of accuracy of ``len(x_list[:3]) - order = 3 - 1 = 2``, the same is true for ``res[1][1]``! >>> from sympy import S >>> from sympy.calculus import finite_diff_weights >>> res = finite_diff_weights(1, [S(0), S(1), -S(1), S(2), -S(2)], 0)[1] >>> res [[0, 0, 0, 0, 0], [-1, 1, 0, 0, 0], [0, 1/2, -1/2, 0, 0], [-1/2, 1, -1/3, -1/6, 0], [0, 2/3, -2/3, -1/12, 1/12]] >>> res[0] # no approximation possible, using x_list[0] only [0, 0, 0, 0, 0] >>> res[1] # classic forward step approximation [-1, 1, 0, 0, 0] >>> res[2] # classic centered approximation [0, 1/2, -1/2, 0, 0] >>> res[3:] # higher order approximations [[-1/2, 1, -1/3, -1/6, 0], [0, 2/3, -2/3, -1/12, 1/12]] Let us compare this to a differently defined ``x_list``. Pay attention to ``foo[i][k]`` corresponding to the gridpoint defined by ``x_list[k]``. >>> from sympy import S >>> from sympy.calculus import finite_diff_weights >>> foo = finite_diff_weights(1, [-S(2), -S(1), S(0), S(1), S(2)], 0)[1] >>> foo [[0, 0, 0, 0, 0], [-1, 1, 0, 0, 0], [1/2, -2, 3/2, 0, 0], [1/6, -1, 1/2, 1/3, 0], [1/12, -2/3, 0, 2/3, -1/12]] >>> foo[1] # not the same and of lower accuracy as res[1]! [-1, 1, 0, 0, 0] >>> foo[2] # classic double backward step approximation [1/2, -2, 3/2, 0, 0] >>> foo[4] # the same as res[4] [1/12, -2/3, 0, 2/3, -1/12] Note that, unless you plan on using approximations based on subsets of ``x_list``, the order of gridpoints does not matter. The capability to generate weights at arbitrary points can be used e.g. to minimize Runge's phenomenon by using Chebyshev nodes: >>> from sympy import cos, symbols, pi, simplify >>> from sympy.calculus import finite_diff_weights >>> N, (h, x) = 4, symbols('h x') >>> x_list = [x+h*cos(i*pi/(N)) for i in range(N,-1,-1)] # chebyshev nodes >>> print(x_list) [-h + x, -sqrt(2)*h/2 + x, x, sqrt(2)*h/2 + x, h + x] >>> mycoeffs = finite_diff_weights(1, x_list, 0)[1][4] >>> [simplify(c) for c in mycoeffs] #doctest: +NORMALIZE_WHITESPACE [(h**3/2 + h**2*x - 3*h*x**2 - 4*x**3)/h**4, (-sqrt(2)*h**3 - 4*h**2*x + 3*sqrt(2)*h*x**2 + 8*x**3)/h**4, (6*h**2*x - 8*x**3)/h**4, (sqrt(2)*h**3 - 4*h**2*x - 3*sqrt(2)*h*x**2 + 8*x**3)/h**4, (-h**3/2 + h**2*x + 3*h*x**2 - 4*x**3)/h**4] Notes ===== If weights for a finite difference approximation of 3rd order derivative is wanted, weights for 0th, 1st and 2nd order are calculated "for free", so are formulae using subsets of ``x_list``. This is something one can take advantage of to save computational cost. Be aware that one should define ``x_list`` from nearest to furthest from ``x0``. If not, subsets of ``x_list`` will yield poorer approximations, which might not grand an order of accuracy of ``len(x_list) - order``. See also ======== sympy.calculus.finite_diff.apply_finite_diff References ========== .. [1] Generation of Finite Difference Formulas on Arbitrarily Spaced Grids, Bengt Fornberg; Mathematics of computation; 51; 184; (1988); 699-706; doi:10.1090/S0025-5718-1988-0935077-0 """ # The notation below closely corresponds to the one used in the paper. order = S(order) if not order.is_number: raise ValueError("Cannot handle symbolic order.") if order < 0: raise ValueError("Negative derivative order illegal.") if int(order) != order: raise ValueError("Non-integer order illegal") M = order N = len(x_list) - 1 delta = [[[0 for nu in range(N+1)] for n in range(N+1)] for m in range(M+1)] delta[0][0][0] = S.One c1 = S.One for n in range(1, N+1): c2 = S.One for nu in range(0, n): c3 = x_list[n]-x_list[nu] c2 = c2 * c3 if n <= M: delta[n][n-1][nu] = 0 for m in range(0, min(n, M)+1): delta[m][n][nu] = (x_list[n]-x0)*delta[m][n-1][nu] -\ m*delta[m-1][n-1][nu] delta[m][n][nu] /= c3 for m in range(0, min(n, M)+1): delta[m][n][n] = c1/c2*(m*delta[m-1][n-1][n-1] - (x_list[n-1]-x0)*delta[m][n-1][n-1]) c1 = c2 return delta def apply_finite_diff(order, x_list, y_list, x0=S.Zero): """ Calculates the finite difference approximation of the derivative of requested order at ``x0`` from points provided in ``x_list`` and ``y_list``. Parameters ========== order: int order of derivative to approximate. 0 corresponds to interpolation. x_list: sequence Sequence of (unique) values for the independent variable. y_list: sequence The function value at corresponding values for the independent variable in x_list. x0: Number or Symbol At what value of the independent variable the derivative should be evaluated. Defaults to 0. Returns ======= sympy.core.add.Add or sympy.core.numbers.Number The finite difference expression approximating the requested derivative order at ``x0``. Examples ======== >>> from sympy.calculus import apply_finite_diff >>> cube = lambda arg: (1.0*arg)**3 >>> xlist = range(-3,3+1) >>> apply_finite_diff(2, xlist, map(cube, xlist), 2) - 12 # doctest: +SKIP -3.55271367880050e-15 we see that the example above only contain rounding errors. apply_finite_diff can also be used on more abstract objects: >>> from sympy import IndexedBase, Idx >>> from sympy.calculus import apply_finite_diff >>> x, y = map(IndexedBase, 'xy') >>> i = Idx('i') >>> x_list, y_list = zip(*[(x[i+j], y[i+j]) for j in range(-1,2)]) >>> apply_finite_diff(1, x_list, y_list, x[i]) ((x[i + 1] - x[i])/(-x[i - 1] + x[i]) - 1)*y[i]/(x[i + 1] - x[i]) - (x[i + 1] - x[i])*y[i - 1]/((x[i + 1] - x[i - 1])*(-x[i - 1] + x[i])) + (-x[i - 1] + x[i])*y[i + 1]/((x[i + 1] - x[i - 1])*(x[i + 1] - x[i])) Notes ===== Order = 0 corresponds to interpolation. Only supply so many points you think makes sense to around x0 when extracting the derivative (the function need to be well behaved within that region). Also beware of Runge's phenomenon. See also ======== sympy.calculus.finite_diff.finite_diff_weights References ========== Fortran 90 implementation with Python interface for numerics: finitediff_ .. _finitediff: https://github.com/bjodah/finitediff """ # In the original paper the following holds for the notation: # M = order # N = len(x_list) - 1 N = len(x_list) - 1 if len(x_list) != len(y_list): raise ValueError("x_list and y_list not equal in length.") delta = finite_diff_weights(order, x_list, x0) derivative = 0 for nu in range(0, len(x_list)): derivative += delta[order][N][nu]*y_list[nu] return derivative def _as_finite_diff(derivative, points=1, x0=None, wrt=None): """ Returns an approximation of a derivative of a function in the form of a finite difference formula. The expression is a weighted sum of the function at a number of discrete values of (one of) the independent variable(s). Parameters ========== derivative: a Derivative instance points: sequence or coefficient, optional If sequence: discrete values (length >= order+1) of the independent variable used for generating the finite difference weights. If it is a coefficient, it will be used as the step-size for generating an equidistant sequence of length order+1 centered around ``x0``. default: 1 (step-size 1) x0: number or Symbol, optional the value of the independent variable (``wrt``) at which the derivative is to be approximated. Default: same as ``wrt``. wrt: Symbol, optional "with respect to" the variable for which the (partial) derivative is to be approximated for. If not provided it is required that the Derivative is ordinary. Default: ``None``. Examples ======== >>> from sympy import symbols, Function, exp, sqrt, Symbol, as_finite_diff >>> from sympy.utilities.exceptions import SymPyDeprecationWarning >>> import warnings >>> warnings.simplefilter("ignore", SymPyDeprecationWarning) >>> x, h = symbols('x h') >>> f = Function('f') >>> as_finite_diff(f(x).diff(x)) -f(x - 1/2) + f(x + 1/2) The default step size and number of points are 1 and ``order + 1`` respectively. We can change the step size by passing a symbol as a parameter: >>> as_finite_diff(f(x).diff(x), h) -f(-h/2 + x)/h + f(h/2 + x)/h We can also specify the discretized values to be used in a sequence: >>> as_finite_diff(f(x).diff(x), [x, x+h, x+2*h]) -3*f(x)/(2*h) + 2*f(h + x)/h - f(2*h + x)/(2*h) The algorithm is not restricted to use equidistant spacing, nor do we need to make the approximation around ``x0``, but we can get an expression estimating the derivative at an offset: >>> e, sq2 = exp(1), sqrt(2) >>> xl = [x-h, x+h, x+e*h] >>> as_finite_diff(f(x).diff(x, 1), xl, x+h*sq2) 2*h*((h + sqrt(2)*h)/(2*h) - (-sqrt(2)*h + h)/(2*h))*f(E*h + x)/((-h + E*h)*(h + E*h)) + (-(-sqrt(2)*h + h)/(2*h) - (-sqrt(2)*h + E*h)/(2*h))*f(-h + x)/(h + E*h) + (-(h + sqrt(2)*h)/(2*h) + (-sqrt(2)*h + E*h)/(2*h))*f(h + x)/(-h + E*h) Partial derivatives are also supported: >>> y = Symbol('y') >>> d2fdxdy=f(x,y).diff(x,y) >>> as_finite_diff(d2fdxdy, wrt=x) -Derivative(f(x - 1/2, y), y) + Derivative(f(x + 1/2, y), y) See also ======== sympy.calculus.finite_diff.apply_finite_diff sympy.calculus.finite_diff.finite_diff_weights """ if derivative.is_Derivative: pass elif derivative.is_Atom: return derivative else: return derivative.fromiter( [_as_finite_diff(ar, points, x0, wrt) for ar in derivative.args], **derivative.assumptions0) if wrt is None: old = None for v in derivative.variables: if old is v: continue derivative = _as_finite_diff(derivative, points, x0, v) old = v return derivative order = derivative.variables.count(wrt) if x0 is None: x0 = wrt if not iterable(points): if getattr(points, 'is_Function', False) and wrt in points.args: points = points.subs(wrt, x0) # points is simply the step-size, let's make it a # equidistant sequence centered around x0 if order % 2 == 0: # even order => odd number of points, grid point included points = [x0 + points*i for i in range(-order//2, order//2 + 1)] else: # odd order => even number of points, half-way wrt grid point points = [x0 + points*S(i)/2 for i in range(-order, order + 1, 2)] others = [wrt, 0] for v in set(derivative.variables): if v == wrt: continue others += [v, derivative.variables.count(v)] if len(points) < order+1: raise ValueError("Too few points for order %d" % order) return apply_finite_diff(order, points, [ Derivative(derivative.expr.subs({wrt: x}), *others) for x in points], x0) as_finite_diff = deprecated( useinstead="Derivative.as_finite_difference", deprecated_since_version="1.1", issue=11410)(_as_finite_diff) as_finite_diff.__doc__ = """ Deprecated function. Use Diff.as_finite_difference instead. """ def differentiate_finite(expr, *symbols, points=1, x0=None, wrt=None, evaluate=False): r""" Differentiate expr and replace Derivatives with finite differences. Parameters ========== expr : expression \*symbols : differentiate with respect to symbols points: sequence, coefficient or undefined function, optional see ``Derivative.as_finite_difference`` x0: number or Symbol, optional see ``Derivative.as_finite_difference`` wrt: Symbol, optional see ``Derivative.as_finite_difference`` Examples ======== >>> from sympy import sin, Function, differentiate_finite >>> from sympy.abc import x, y, h >>> f, g = Function('f'), Function('g') >>> differentiate_finite(f(x)*g(x), x, points=[x-h, x+h]) -f(-h + x)*g(-h + x)/(2*h) + f(h + x)*g(h + x)/(2*h) ``differentiate_finite`` works on any expression, including the expressions with embedded derivatives: >>> differentiate_finite(f(x) + sin(x), x, 2) -2*f(x) + f(x - 1) + f(x + 1) - 2*sin(x) + sin(x - 1) + sin(x + 1) >>> differentiate_finite(f(x, y), x, y) f(x - 1/2, y - 1/2) - f(x - 1/2, y + 1/2) - f(x + 1/2, y - 1/2) + f(x + 1/2, y + 1/2) >>> differentiate_finite(f(x)*g(x).diff(x), x) (-g(x) + g(x + 1))*f(x + 1/2) - (g(x) - g(x - 1))*f(x - 1/2) To make finite difference with non-constant discretization step use undefined functions: >>> dx = Function('dx') >>> differentiate_finite(f(x)*g(x).diff(x), points=dx(x)) -(-g(x - dx(x)/2 - dx(x - dx(x)/2)/2)/dx(x - dx(x)/2) + g(x - dx(x)/2 + dx(x - dx(x)/2)/2)/dx(x - dx(x)/2))*f(x - dx(x)/2)/dx(x) + (-g(x + dx(x)/2 - dx(x + dx(x)/2)/2)/dx(x + dx(x)/2) + g(x + dx(x)/2 + dx(x + dx(x)/2)/2)/dx(x + dx(x)/2))*f(x + dx(x)/2)/dx(x) """ if any(term.is_Derivative for term in list(preorder_traversal(expr))): evaluate = False Dexpr = expr.diff(*symbols, evaluate=evaluate) if evaluate: SymPyDeprecationWarning(feature="``evaluate`` flag", issue=17881, deprecated_since_version="1.5").warn() return Dexpr.replace( lambda arg: arg.is_Derivative, lambda arg: arg.as_finite_difference(points=points, x0=x0, wrt=wrt)) else: DFexpr = Dexpr.as_finite_difference(points=points, x0=x0, wrt=wrt) return DFexpr.replace( lambda arg: isinstance(arg, Subs), lambda arg: arg.expr.as_finite_difference( points=points, x0=arg.point[0], wrt=arg.variables[0])) sympy-sympy-1.9/sympy/calculus/singularities.py000066400000000000000000000261511412543434000221600ustar00rootroot00000000000000""" Singularities ============= This module implements algorithms for finding singularities for a function and identifying types of functions. The differential calculus methods in this module include methods to identify the following function types in the given ``Interval``: - Increasing - Strictly Increasing - Decreasing - Strictly Decreasing - Monotonic """ from sympy import S, Symbol from sympy.core.sympify import sympify from sympy.solvers.solveset import solveset from sympy.utilities.misc import filldedent def singularities(expression, symbol, domain=None): """ Find singularities of a given function. Parameters ========== expression : Expr The target function in which singularities need to be found. symbol : Symbol The symbol over the values of which the singularity in expression in being searched for. Returns ======= Set A set of values for ``symbol`` for which ``expression`` has a singularity. An ``EmptySet`` is returned if ``expression`` has no singularities for any given value of ``Symbol``. Raises ====== NotImplementedError Methods for determining the singularities of this function have not been developed. Notes ===== This function does not find non-isolated singularities nor does it find branch points of the expression. Currently supported functions are: - univariate continuous (real or complex) functions References ========== .. [1] https://en.wikipedia.org/wiki/Mathematical_singularity Examples ======== >>> from sympy.calculus.singularities import singularities >>> from sympy import Symbol, log >>> x = Symbol('x', real=True) >>> y = Symbol('y', real=False) >>> singularities(x**2 + x + 1, x) EmptySet >>> singularities(1/(x + 1), x) {-1} >>> singularities(1/(y**2 + 1), y) {-I, I} >>> singularities(1/(y**3 + 1), y) {-1, 1/2 - sqrt(3)*I/2, 1/2 + sqrt(3)*I/2} >>> singularities(log(x), x) {0} """ from sympy.functions.elementary.exponential import log from sympy.functions.elementary.trigonometric import sec, csc, cot, tan, cos from sympy.core.power import Pow if domain is None: domain = S.Reals if symbol.is_real else S.Complexes try: sings = S.EmptySet for i in expression.rewrite([sec, csc, cot, tan], cos).atoms(Pow): if i.exp.is_infinite: raise NotImplementedError if i.exp.is_negative: sings += solveset(i.base, symbol, domain) for i in expression.atoms(log): sings += solveset(i.args[0], symbol, domain) return sings except NotImplementedError: raise NotImplementedError(filldedent(''' Methods for determining the singularities of this function have not been developed.''')) ########################################################################### # DIFFERENTIAL CALCULUS METHODS # ########################################################################### def monotonicity_helper(expression, predicate, interval=S.Reals, symbol=None): """ Helper function for functions checking function monotonicity. Parameters ========== expression : Expr The target function which is being checked predicate : function The property being tested for. The function takes in an integer and returns a boolean. The integer input is the derivative and the boolean result should be true if the property is being held, and false otherwise. interval : Set, optional The range of values in which we are testing, defaults to all reals. symbol : Symbol, optional The symbol present in expression which gets varied over the given range. It returns a boolean indicating whether the interval in which the function's derivative satisfies given predicate is a superset of the given interval. Returns ======= Boolean True if ``predicate`` is true for all the derivatives when ``symbol`` is varied in ``range``, False otherwise. """ expression = sympify(expression) free = expression.free_symbols if symbol is None: if len(free) > 1: raise NotImplementedError( 'The function has not yet been implemented' ' for all multivariate expressions.' ) variable = symbol or (free.pop() if free else Symbol('x')) derivative = expression.diff(variable) predicate_interval = solveset(predicate(derivative), variable, S.Reals) return interval.is_subset(predicate_interval) def is_increasing(expression, interval=S.Reals, symbol=None): """ Return whether the function is increasing in the given interval. Parameters ========== expression : Expr The target function which is being checked. interval : Set, optional The range of values in which we are testing (defaults to set of all real numbers). symbol : Symbol, optional The symbol present in expression which gets varied over the given range. Returns ======= Boolean True if ``expression`` is increasing (either strictly increasing or constant) in the given ``interval``, False otherwise. Examples ======== >>> from sympy import is_increasing >>> from sympy.abc import x, y >>> from sympy import S, Interval, oo >>> is_increasing(x**3 - 3*x**2 + 4*x, S.Reals) True >>> is_increasing(-x**2, Interval(-oo, 0)) True >>> is_increasing(-x**2, Interval(0, oo)) False >>> is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) False >>> is_increasing(x**2 + y, Interval(1, 2), x) True """ return monotonicity_helper(expression, lambda x: x >= 0, interval, symbol) def is_strictly_increasing(expression, interval=S.Reals, symbol=None): """ Return whether the function is strictly increasing in the given interval. Parameters ========== expression : Expr The target function which is being checked. interval : Set, optional The range of values in which we are testing (defaults to set of all real numbers). symbol : Symbol, optional The symbol present in expression which gets varied over the given range. Returns ======= Boolean True if ``expression`` is strictly increasing in the given ``interval``, False otherwise. Examples ======== >>> from sympy import is_strictly_increasing >>> from sympy.abc import x, y >>> from sympy import Interval, oo >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Ropen(-oo, -2)) True >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.Lopen(3, oo)) True >>> is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.open(-2, 3)) False >>> is_strictly_increasing(-x**2, Interval(0, oo)) False >>> is_strictly_increasing(-x**2 + y, Interval(-oo, 0), x) False """ return monotonicity_helper(expression, lambda x: x > 0, interval, symbol) def is_decreasing(expression, interval=S.Reals, symbol=None): """ Return whether the function is decreasing in the given interval. Parameters ========== expression : Expr The target function which is being checked. interval : Set, optional The range of values in which we are testing (defaults to set of all real numbers). symbol : Symbol, optional The symbol present in expression which gets varied over the given range. Returns ======= Boolean True if ``expression`` is decreasing (either strictly decreasing or constant) in the given ``interval``, False otherwise. Examples ======== >>> from sympy import is_decreasing >>> from sympy.abc import x, y >>> from sympy import S, Interval, oo >>> is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3)) True >>> is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo)) True >>> is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2)) False >>> is_decreasing(-x**2, Interval(-oo, 0)) False >>> is_decreasing(-x**2 + y, Interval(-oo, 0), x) False """ return monotonicity_helper(expression, lambda x: x <= 0, interval, symbol) def is_strictly_decreasing(expression, interval=S.Reals, symbol=None): """ Return whether the function is strictly decreasing in the given interval. Parameters ========== expression : Expr The target function which is being checked. interval : Set, optional The range of values in which we are testing (defaults to set of all real numbers). symbol : Symbol, optional The symbol present in expression which gets varied over the given range. Returns ======= Boolean True if ``expression`` is strictly decreasing in the given ``interval``, False otherwise. Examples ======== >>> from sympy import is_strictly_decreasing >>> from sympy.abc import x, y >>> from sympy import S, Interval, oo >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo)) True >>> is_strictly_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, S(3)/2)) False >>> is_strictly_decreasing(-x**2, Interval(-oo, 0)) False >>> is_strictly_decreasing(-x**2 + y, Interval(-oo, 0), x) False """ return monotonicity_helper(expression, lambda x: x < 0, interval, symbol) def is_monotonic(expression, interval=S.Reals, symbol=None): """ Return whether the function is monotonic in the given interval. Parameters ========== expression : Expr The target function which is being checked. interval : Set, optional The range of values in which we are testing (defaults to set of all real numbers). symbol : Symbol, optional The symbol present in expression which gets varied over the given range. Returns ======= Boolean True if ``expression`` is monotonic in the given ``interval``, False otherwise. Raises ====== NotImplementedError Monotonicity check has not been implemented for the queried function. Examples ======== >>> from sympy import is_monotonic >>> from sympy.abc import x, y >>> from sympy import S, Interval, oo >>> is_monotonic(1/(x**2 - 3*x), Interval.open(1.5, 3)) True >>> is_monotonic(1/(x**2 - 3*x), Interval.Lopen(3, oo)) True >>> is_monotonic(x**3 - 3*x**2 + 4*x, S.Reals) True >>> is_monotonic(-x**2, S.Reals) False >>> is_monotonic(x**2 + y + 1, Interval(1, 2), x) True """ expression = sympify(expression) free = expression.free_symbols if symbol is None and len(free) > 1: raise NotImplementedError( 'is_monotonic has not yet been implemented' ' for all multivariate expressions.' ) variable = symbol or (free.pop() if free else Symbol('x')) turning_points = solveset(expression.diff(variable), variable, interval) return interval.intersection(turning_points) is S.EmptySet sympy-sympy-1.9/sympy/calculus/tests/000077500000000000000000000000001412543434000200615ustar00rootroot00000000000000sympy-sympy-1.9/sympy/calculus/tests/__init__.py000066400000000000000000000000001412543434000221600ustar00rootroot00000000000000sympy-sympy-1.9/sympy/calculus/tests/test_euler.py000066400000000000000000000044221412543434000226100ustar00rootroot00000000000000from sympy import Symbol, Function, Derivative as D, Eq, cos, sin from sympy.testing.pytest import raises from sympy.calculus.euler import euler_equations as euler def test_euler_interface(): x = Function('x') y = Symbol('y') t = Symbol('t') raises(TypeError, lambda: euler()) raises(TypeError, lambda: euler(D(x(t), t)*y(t), [x(t), y])) raises(ValueError, lambda: euler(D(x(t), t)*x(y), [x(t), x(y)])) raises(TypeError, lambda: euler(D(x(t), t)**2, x(0))) raises(TypeError, lambda: euler(D(x(t), t)*y(t), [t])) assert euler(D(x(t), t)**2/2, {x(t)}) == [Eq(-D(x(t), t, t), 0)] assert euler(D(x(t), t)**2/2, x(t), {t}) == [Eq(-D(x(t), t, t), 0)] def test_euler_pendulum(): x = Function('x') t = Symbol('t') L = D(x(t), t)**2/2 + cos(x(t)) assert euler(L, x(t), t) == [Eq(-sin(x(t)) - D(x(t), t, t), 0)] def test_euler_henonheiles(): x = Function('x') y = Function('y') t = Symbol('t') L = sum(D(z(t), t)**2/2 - z(t)**2/2 for z in [x, y]) L += -x(t)**2*y(t) + y(t)**3/3 assert euler(L, [x(t), y(t)], t) == [Eq(-2*x(t)*y(t) - x(t) - D(x(t), t, t), 0), Eq(-x(t)**2 + y(t)**2 - y(t) - D(y(t), t, t), 0)] def test_euler_sineg(): psi = Function('psi') t = Symbol('t') x = Symbol('x') L = D(psi(t, x), t)**2/2 - D(psi(t, x), x)**2/2 + cos(psi(t, x)) assert euler(L, psi(t, x), [t, x]) == [Eq(-sin(psi(t, x)) - D(psi(t, x), t, t) + D(psi(t, x), x, x), 0)] def test_euler_high_order(): # an example from hep-th/0309038 m = Symbol('m') k = Symbol('k') x = Function('x') y = Function('y') t = Symbol('t') L = (m*D(x(t), t)**2/2 + m*D(y(t), t)**2/2 - k*D(x(t), t)*D(y(t), t, t) + k*D(y(t), t)*D(x(t), t, t)) assert euler(L, [x(t), y(t)]) == [Eq(2*k*D(y(t), t, t, t) - m*D(x(t), t, t), 0), Eq(-2*k*D(x(t), t, t, t) - m*D(y(t), t, t), 0)] w = Symbol('w') L = D(x(t, w), t, w)**2/2 assert euler(L) == [Eq(D(x(t, w), t, t, w, w), 0)] sympy-sympy-1.9/sympy/calculus/tests/test_finite_diff.py000066400000000000000000000171101412543434000237400ustar00rootroot00000000000000from itertools import product from sympy import S, symbols, Function, exp, diff, Rational from sympy.calculus.finite_diff import ( apply_finite_diff, differentiate_finite, finite_diff_weights, as_finite_diff ) from sympy.testing.pytest import raises, warns_deprecated_sympy, ignore_warnings from sympy.utilities.exceptions import SymPyDeprecationWarning def test_apply_finite_diff(): x, h = symbols('x h') f = Function('f') assert (apply_finite_diff(1, [x-h, x+h], [f(x-h), f(x+h)], x) - (f(x+h)-f(x-h))/(2*h)).simplify() == 0 assert (apply_finite_diff(1, [5, 6, 7], [f(5), f(6), f(7)], 5) - (Rational(-3, 2)*f(5) + 2*f(6) - S.Half*f(7))).simplify() == 0 raises(ValueError, lambda: apply_finite_diff(1, [x, h], [f(x)])) def test_finite_diff_weights(): d = finite_diff_weights(1, [5, 6, 7], 5) assert d[1][2] == [Rational(-3, 2), 2, Rational(-1, 2)] # Table 1, p. 702 in doi:10.1090/S0025-5718-1988-0935077-0 # -------------------------------------------------------- xl = [0, 1, -1, 2, -2, 3, -3, 4, -4] # d holds all coefficients d = finite_diff_weights(4, xl, S.Zero) # Zeroeth derivative for i in range(5): assert d[0][i] == [S.One] + [S.Zero]*8 # First derivative assert d[1][0] == [S.Zero]*9 assert d[1][2] == [S.Zero, S.Half, Rational(-1, 2)] + [S.Zero]*6 assert d[1][4] == [S.Zero, Rational(2, 3), Rational(-2, 3), Rational(-1, 12), Rational(1, 12)] + [S.Zero]*4 assert d[1][6] == [S.Zero, Rational(3, 4), Rational(-3, 4), Rational(-3, 20), Rational(3, 20), Rational(1, 60), Rational(-1, 60)] + [S.Zero]*2 assert d[1][8] == [S.Zero, Rational(4, 5), Rational(-4, 5), Rational(-1, 5), Rational(1, 5), Rational(4, 105), Rational(-4, 105), Rational(-1, 280), Rational(1, 280)] # Second derivative for i in range(2): assert d[2][i] == [S.Zero]*9 assert d[2][2] == [-S(2), S.One, S.One] + [S.Zero]*6 assert d[2][4] == [Rational(-5, 2), Rational(4, 3), Rational(4, 3), Rational(-1, 12), Rational(-1, 12)] + [S.Zero]*4 assert d[2][6] == [Rational(-49, 18), Rational(3, 2), Rational(3, 2), Rational(-3, 20), Rational(-3, 20), Rational(1, 90), Rational(1, 90)] + [S.Zero]*2 assert d[2][8] == [Rational(-205, 72), Rational(8, 5), Rational(8, 5), Rational(-1, 5), Rational(-1, 5), Rational(8, 315), Rational(8, 315), Rational(-1, 560), Rational(-1, 560)] # Third derivative for i in range(3): assert d[3][i] == [S.Zero]*9 assert d[3][4] == [S.Zero, -S.One, S.One, S.Half, Rational(-1, 2)] + [S.Zero]*4 assert d[3][6] == [S.Zero, Rational(-13, 8), Rational(13, 8), S.One, -S.One, Rational(-1, 8), Rational(1, 8)] + [S.Zero]*2 assert d[3][8] == [S.Zero, Rational(-61, 30), Rational(61, 30), Rational(169, 120), Rational(-169, 120), Rational(-3, 10), Rational(3, 10), Rational(7, 240), Rational(-7, 240)] # Fourth derivative for i in range(4): assert d[4][i] == [S.Zero]*9 assert d[4][4] == [S(6), -S(4), -S(4), S.One, S.One] + [S.Zero]*4 assert d[4][6] == [Rational(28, 3), Rational(-13, 2), Rational(-13, 2), S(2), S(2), Rational(-1, 6), Rational(-1, 6)] + [S.Zero]*2 assert d[4][8] == [Rational(91, 8), Rational(-122, 15), Rational(-122, 15), Rational(169, 60), Rational(169, 60), Rational(-2, 5), Rational(-2, 5), Rational(7, 240), Rational(7, 240)] # Table 2, p. 703 in doi:10.1090/S0025-5718-1988-0935077-0 # -------------------------------------------------------- xl = [[j/S(2) for j in list(range(-i*2+1, 0, 2))+list(range(1, i*2+1, 2))] for i in range(1, 5)] # d holds all coefficients d = [finite_diff_weights({0: 1, 1: 2, 2: 4, 3: 4}[i], xl[i], 0) for i in range(4)] # Zeroth derivative assert d[0][0][1] == [S.Half, S.Half] assert d[1][0][3] == [Rational(-1, 16), Rational(9, 16), Rational(9, 16), Rational(-1, 16)] assert d[2][0][5] == [Rational(3, 256), Rational(-25, 256), Rational(75, 128), Rational(75, 128), Rational(-25, 256), Rational(3, 256)] assert d[3][0][7] == [Rational(-5, 2048), Rational(49, 2048), Rational(-245, 2048), Rational(1225, 2048), Rational(1225, 2048), Rational(-245, 2048), Rational(49, 2048), Rational(-5, 2048)] # First derivative assert d[0][1][1] == [-S.One, S.One] assert d[1][1][3] == [Rational(1, 24), Rational(-9, 8), Rational(9, 8), Rational(-1, 24)] assert d[2][1][5] == [Rational(-3, 640), Rational(25, 384), Rational(-75, 64), Rational(75, 64), Rational(-25, 384), Rational(3, 640)] assert d[3][1][7] == [Rational(5, 7168), Rational(-49, 5120), Rational(245, 3072), Rational(-1225, 1024), Rational(1225, 1024), Rational(-245, 3072), Rational(49, 5120), Rational(-5, 7168)] # Reasonably the rest of the table is also correct... (testing of that # deemed excessive at the moment) raises(ValueError, lambda: finite_diff_weights(-1, [1, 2])) raises(ValueError, lambda: finite_diff_weights(1.2, [1, 2])) x = symbols('x') raises(ValueError, lambda: finite_diff_weights(x, [1, 2])) def test_as_finite_diff(): x = symbols('x') f = Function('f') dx = Function('dx') with warns_deprecated_sympy(): as_finite_diff(f(x).diff(x), [x-2, x-1, x, x+1, x+2]) # Use of undefined functions in ``points`` df_true = -f(x+dx(x)/2-dx(x+dx(x)/2)/2) / dx(x+dx(x)/2) \ + f(x+dx(x)/2+dx(x+dx(x)/2)/2) / dx(x+dx(x)/2) df_test = diff(f(x), x).as_finite_difference(points=dx(x), x0=x+dx(x)/2) assert (df_test - df_true).simplify() == 0 def test_differentiate_finite(): x, y, h = symbols('x y h') f = Function('f') with ignore_warnings(SymPyDeprecationWarning): res0 = differentiate_finite(f(x, y) + exp(42), x, y, evaluate=True) xm, xp, ym, yp = [v + sign*S.Half for v, sign in product([x, y], [-1, 1])] ref0 = f(xm, ym) + f(xp, yp) - f(xm, yp) - f(xp, ym) assert (res0 - ref0).simplify() == 0 g = Function('g') with ignore_warnings(SymPyDeprecationWarning): res1 = differentiate_finite(f(x)*g(x) + 42, x, evaluate=True) ref1 = (-f(x - S.Half) + f(x + S.Half))*g(x) + \ (-g(x - S.Half) + g(x + S.Half))*f(x) assert (res1 - ref1).simplify() == 0 res2 = differentiate_finite(f(x) + x**3 + 42, x, points=[x-1, x+1]) ref2 = (f(x + 1) + (x + 1)**3 - f(x - 1) - (x - 1)**3)/2 assert (res2 - ref2).simplify() == 0 raises(TypeError, lambda: differentiate_finite(f(x)*g(x), x, pints=[x-1, x+1])) res3 = differentiate_finite(f(x)*g(x).diff(x), x) ref3 = (-g(x) + g(x + 1))*f(x + S.Half) - (g(x) - g(x - 1))*f(x - S.Half) assert res3 == ref3 res4 = differentiate_finite(f(x)*g(x).diff(x).diff(x), x) ref4 = -((g(x - Rational(3, 2)) - 2*g(x - S.Half) + g(x + S.Half))*f(x - S.Half)) \ + (g(x - S.Half) - 2*g(x + S.Half) + g(x + Rational(3, 2)))*f(x + S.Half) assert res4 == ref4 res5_expr = f(x).diff(x)*g(x).diff(x) res5 = differentiate_finite(res5_expr, points=[x-h, x, x+h]) ref5 = (-2*f(x)/h + f(-h + x)/(2*h) + 3*f(h + x)/(2*h))*(-2*g(x)/h + g(-h + x)/(2*h) \ + 3*g(h + x)/(2*h))/(2*h) - (2*f(x)/h - 3*f(-h + x)/(2*h) - \ f(h + x)/(2*h))*(2*g(x)/h - 3*g(-h + x)/(2*h) - g(h + x)/(2*h))/(2*h) assert res5 == ref5 res6 = res5.limit(h, 0).doit() ref6 = diff(res5_expr, x) assert res6 == ref6 sympy-sympy-1.9/sympy/calculus/tests/test_singularities.py000066400000000000000000000071151412543434000243600ustar00rootroot00000000000000from sympy import Symbol, exp, log, oo, S, I, sqrt, Rational from sympy.calculus.singularities import ( singularities, is_increasing, is_strictly_increasing, is_decreasing, is_strictly_decreasing, is_monotonic ) from sympy.sets import Interval, FiniteSet from sympy.testing.pytest import raises from sympy.abc import x, y def test_singularities(): x = Symbol('x') assert singularities(x**2, x) == S.EmptySet assert singularities(x/(x**2 + 3*x + 2), x) == FiniteSet(-2, -1) assert singularities(1/(x**2 + 1), x) == FiniteSet(I, -I) assert singularities(x/(x**3 + 1), x) == \ FiniteSet(-1, (1 - sqrt(3) * I) / 2, (1 + sqrt(3) * I) / 2) assert singularities(1/(y**2 + 2*I*y + 1), y) == \ FiniteSet(-I + sqrt(2)*I, -I - sqrt(2)*I) x = Symbol('x', real=True) assert singularities(1/(x**2 + 1), x) == S.EmptySet assert singularities(exp(1/x), x, S.Reals) == FiniteSet(0) assert singularities(exp(1/x), x, Interval(1, 2)) == S.EmptySet assert singularities(log((x - 2)**2), x, Interval(1, 3)) == FiniteSet(2) raises(NotImplementedError, lambda: singularities(x**-oo, x)) def test_is_increasing(): """Test whether is_increasing returns correct value.""" a = Symbol('a', negative=True) assert is_increasing(x**3 - 3*x**2 + 4*x, S.Reals) assert is_increasing(-x**2, Interval(-oo, 0)) assert not is_increasing(-x**2, Interval(0, oo)) assert not is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) assert is_increasing(x**2 + y, Interval(1, oo), x) assert is_increasing(-x**2*a, Interval(1, oo), x) assert is_increasing(1) assert is_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval(-2, 3)) is False def test_is_strictly_increasing(): """Test whether is_strictly_increasing returns correct value.""" assert is_strictly_increasing( 4*x**3 - 6*x**2 - 72*x + 30, Interval.Ropen(-oo, -2)) assert is_strictly_increasing( 4*x**3 - 6*x**2 - 72*x + 30, Interval.Lopen(3, oo)) assert not is_strictly_increasing( 4*x**3 - 6*x**2 - 72*x + 30, Interval.open(-2, 3)) assert not is_strictly_increasing(-x**2, Interval(0, oo)) assert not is_strictly_decreasing(1) assert is_strictly_increasing(4*x**3 - 6*x**2 - 72*x + 30, Interval.open(-2, 3)) is False def test_is_decreasing(): """Test whether is_decreasing returns correct value.""" b = Symbol('b', positive=True) assert is_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3)) assert is_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo)) assert not is_decreasing(1/(x**2 - 3*x), Interval.Ropen(-oo, Rational(3, 2))) assert not is_decreasing(-x**2, Interval(-oo, 0)) assert not is_decreasing(-x**2*b, Interval(-oo, 0), x) def test_is_strictly_decreasing(): """Test whether is_strictly_decreasing returns correct value.""" assert is_strictly_decreasing(1/(x**2 - 3*x), Interval.Lopen(3, oo)) assert not is_strictly_decreasing( 1/(x**2 - 3*x), Interval.Ropen(-oo, Rational(3, 2))) assert not is_strictly_decreasing(-x**2, Interval(-oo, 0)) assert not is_strictly_decreasing(1) assert is_strictly_decreasing(1/(x**2 - 3*x), Interval.open(1.5, 3)) def test_is_monotonic(): """Test whether is_monotonic returns correct value.""" assert is_monotonic(1/(x**2 - 3*x), Interval.open(1.5, 3)) assert is_monotonic(1/(x**2 - 3*x), Interval.Lopen(3, oo)) assert is_monotonic(x**3 - 3*x**2 + 4*x, S.Reals) assert not is_monotonic(-x**2, S.Reals) assert is_monotonic(x**2 + y + 1, Interval(1, 2), x) raises(NotImplementedError, lambda: is_monotonic(x**2 + y + 1)) sympy-sympy-1.9/sympy/calculus/tests/test_util.py000066400000000000000000000604641412543434000224610ustar00rootroot00000000000000from sympy import (Symbol, S, exp, log, sqrt, oo, E, zoo, pi, tan, sin, cos, cot, sec, csc, Abs, symbols, I, re, simplify, expint, Rational, Piecewise) from sympy.calculus.util import (function_range, continuous_domain, not_empty_in, periodicity, lcim, AccumBounds, is_convex, stationary_points, minimum, maximum) from sympy.core import Add, Mul, Pow from sympy.core.expr import unchanged from sympy.sets.sets import (Interval, FiniteSet, EmptySet, Complement, Union) from sympy.testing.pytest import raises, _both_exp_pow, XFAIL from sympy.abc import x a = Symbol('a', real=True) B = AccumBounds def test_function_range(): x, y, a, b = symbols('x y a b') assert function_range(sin(x), x, Interval(-pi/2, pi/2) ) == Interval(-1, 1) assert function_range(sin(x), x, Interval(0, pi) ) == Interval(0, 1) assert function_range(tan(x), x, Interval(0, pi) ) == Interval(-oo, oo) assert function_range(tan(x), x, Interval(pi/2, pi) ) == Interval(-oo, 0) assert function_range((x + 3)/(x - 2), x, Interval(-5, 5) ) == Union(Interval(-oo, Rational(2, 7)), Interval(Rational(8, 3), oo)) assert function_range(1/(x**2), x, Interval(-1, 1) ) == Interval(1, oo) assert function_range(exp(x), x, Interval(-1, 1) ) == Interval(exp(-1), exp(1)) assert function_range(log(x) - x, x, S.Reals ) == Interval(-oo, -1) assert function_range(sqrt(3*x - 1), x, Interval(0, 2) ) == Interval(0, sqrt(5)) assert function_range(x*(x - 1) - (x**2 - x), x, S.Reals ) == FiniteSet(0) assert function_range(x*(x - 1) - (x**2 - x) + y, x, S.Reals ) == FiniteSet(y) assert function_range(sin(x), x, Union(Interval(-5, -3), FiniteSet(4)) ) == Union(Interval(-sin(3), 1), FiniteSet(sin(4))) assert function_range(cos(x), x, Interval(-oo, -4) ) == Interval(-1, 1) assert function_range(cos(x), x, S.EmptySet) == S.EmptySet assert function_range(x/sqrt(x**2+1), x, S.Reals) == Interval.open(-1,1) raises(NotImplementedError, lambda : function_range( exp(x)*(sin(x) - cos(x))/2 - x, x, S.Reals)) raises(NotImplementedError, lambda : function_range( sin(x) + x, x, S.Reals)) # issue 13273 raises(NotImplementedError, lambda : function_range( log(x), x, S.Integers)) raises(NotImplementedError, lambda : function_range( sin(x)/2, x, S.Naturals)) def test_continuous_domain(): x = Symbol('x') assert continuous_domain(sin(x), x, Interval(0, 2*pi)) == Interval(0, 2*pi) assert continuous_domain(tan(x), x, Interval(0, 2*pi)) == \ Union(Interval(0, pi/2, False, True), Interval(pi/2, pi*Rational(3, 2), True, True), Interval(pi*Rational(3, 2), 2*pi, True, False)) assert continuous_domain((x - 1)/((x - 1)**2), x, S.Reals) == \ Union(Interval(-oo, 1, True, True), Interval(1, oo, True, True)) assert continuous_domain(log(x) + log(4*x - 1), x, S.Reals) == \ Interval(Rational(1, 4), oo, True, True) assert continuous_domain(1/sqrt(x - 3), x, S.Reals) == Interval(3, oo, True, True) assert continuous_domain(1/x - 2, x, S.Reals) == \ Union(Interval.open(-oo, 0), Interval.open(0, oo)) assert continuous_domain(1/(x**2 - 4) + 2, x, S.Reals) == \ Union(Interval.open(-oo, -2), Interval.open(-2, 2), Interval.open(2, oo)) domain = continuous_domain(log(tan(x)**2 + 1), x, S.Reals) assert not domain.contains(3*pi/2) assert domain.contains(5) d = Symbol('d', even=True, zero=False) assert continuous_domain(x**(1/d), x, S.Reals) == Interval(0, oo) def test_not_empty_in(): assert not_empty_in(FiniteSet(x, 2*x).intersect(Interval(1, 2, True, False)), x) == \ Interval(S.Half, 2, True, False) assert not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x) == \ Union(Interval(-sqrt(2), -1), Interval(1, 2)) assert not_empty_in(FiniteSet(x**2 + x, x).intersect(Interval(2, 4)), x) == \ Union(Interval(-sqrt(17)/2 - S.Half, -2), Interval(1, Rational(-1, 2) + sqrt(17)/2), Interval(2, 4)) assert not_empty_in(FiniteSet(x/(x - 1)).intersect(S.Reals), x) == \ Complement(S.Reals, FiniteSet(1)) assert not_empty_in(FiniteSet(a/(a - 1)).intersect(S.Reals), a) == \ Complement(S.Reals, FiniteSet(1)) assert not_empty_in(FiniteSet((x**2 - 3*x + 2)/(x - 1)).intersect(S.Reals), x) == \ Complement(S.Reals, FiniteSet(1)) assert not_empty_in(FiniteSet(3, 4, x/(x - 1)).intersect(Interval(2, 3)), x) == \ Interval(-oo, oo) assert not_empty_in(FiniteSet(4, x/(x - 1)).intersect(Interval(2, 3)), x) == \ Interval(S(3)/2, 2) assert not_empty_in(FiniteSet(x/(x**2 - 1)).intersect(S.Reals), x) == \ Complement(S.Reals, FiniteSet(-1, 1)) assert not_empty_in(FiniteSet(x, x**2).intersect(Union(Interval(1, 3, True, True), Interval(4, 5))), x) == \ Union(Interval(-sqrt(5), -2), Interval(-sqrt(3), -1, True, True), Interval(1, 3, True, True), Interval(4, 5)) assert not_empty_in(FiniteSet(1).intersect(Interval(3, 4)), x) == S.EmptySet assert not_empty_in(FiniteSet(x**2/(x + 2)).intersect(Interval(1, oo)), x) == \ Union(Interval(-2, -1, True, False), Interval(2, oo)) raises(ValueError, lambda: not_empty_in(x)) raises(ValueError, lambda: not_empty_in(Interval(0, 1), x)) raises(NotImplementedError, lambda: not_empty_in(FiniteSet(x).intersect(S.Reals), x, a)) @_both_exp_pow def test_periodicity(): x = Symbol('x') y = Symbol('y') z = Symbol('z', real=True) assert periodicity(sin(2*x), x) == pi assert periodicity((-2)*tan(4*x), x) == pi/4 assert periodicity(sin(x)**2, x) == 2*pi assert periodicity(3**tan(3*x), x) == pi/3 assert periodicity(tan(x)*cos(x), x) == 2*pi assert periodicity(sin(x)**(tan(x)), x) == 2*pi assert periodicity(tan(x)*sec(x), x) == 2*pi assert periodicity(sin(2*x)*cos(2*x) - y, x) == pi/2 assert periodicity(tan(x) + cot(x), x) == pi assert periodicity(sin(x) - cos(2*x), x) == 2*pi assert periodicity(sin(x) - 1, x) == 2*pi assert periodicity(sin(4*x) + sin(x)*cos(x), x) == pi assert periodicity(exp(sin(x)), x) == 2*pi assert periodicity(log(cot(2*x)) - sin(cos(2*x)), x) == pi assert periodicity(sin(2*x)*exp(tan(x) - csc(2*x)), x) == pi assert periodicity(cos(sec(x) - csc(2*x)), x) == 2*pi assert periodicity(tan(sin(2*x)), x) == pi assert periodicity(2*tan(x)**2, x) == pi assert periodicity(sin(x%4), x) == 4 assert periodicity(sin(x)%4, x) == 2*pi assert periodicity(tan((3*x-2)%4), x) == Rational(4, 3) assert periodicity((sqrt(2)*(x+1)+x) % 3, x) == 3 / (sqrt(2)+1) assert periodicity((x**2+1) % x, x) is None assert periodicity(sin(re(x)), x) == 2*pi assert periodicity(sin(x)**2 + cos(x)**2, x) is S.Zero assert periodicity(tan(x), y) is S.Zero assert periodicity(sin(x) + I*cos(x), x) == 2*pi assert periodicity(x - sin(2*y), y) == pi assert periodicity(exp(x), x) is None assert periodicity(exp(I*x), x) == 2*pi assert periodicity(exp(I*z), z) == 2*pi assert periodicity(exp(z), z) is None assert periodicity(exp(log(sin(z) + I*cos(2*z)), evaluate=False), z) == 2*pi assert periodicity(exp(log(sin(2*z) + I*cos(z)), evaluate=False), z) == 2*pi assert periodicity(exp(sin(z)), z) == 2*pi assert periodicity(exp(2*I*z), z) == pi assert periodicity(exp(z + I*sin(z)), z) is None assert periodicity(exp(cos(z/2) + sin(z)), z) == 4*pi assert periodicity(log(x), x) is None assert periodicity(exp(x)**sin(x), x) is None assert periodicity(sin(x)**y, y) is None assert periodicity(Abs(sin(Abs(sin(x)))), x) == pi assert all(periodicity(Abs(f(x)), x) == pi for f in ( cos, sin, sec, csc, tan, cot)) assert periodicity(Abs(sin(tan(x))), x) == pi assert periodicity(Abs(sin(sin(x) + tan(x))), x) == 2*pi assert periodicity(sin(x) > S.Half, x) == 2*pi assert periodicity(x > 2, x) is None assert periodicity(x**3 - x**2 + 1, x) is None assert periodicity(Abs(x), x) is None assert periodicity(Abs(x**2 - 1), x) is None assert periodicity((x**2 + 4)%2, x) is None assert periodicity((E**x)%3, x) is None assert periodicity(sin(expint(1, x))/expint(1, x), x) is None # returning `None` for any Piecewise p = Piecewise((0, x < -1), (x**2, x <= 1), (log(x), True)) assert periodicity(p, x) is None def test_periodicity_check(): x = Symbol('x') y = Symbol('y') assert periodicity(tan(x), x, check=True) == pi assert periodicity(sin(x) + cos(x), x, check=True) == 2*pi assert periodicity(sec(x), x) == 2*pi assert periodicity(sin(x*y), x) == 2*pi/abs(y) assert periodicity(Abs(sec(sec(x))), x) == pi def test_lcim(): from sympy import pi assert lcim([S.Half, S(2), S(3)]) == 6 assert lcim([pi/2, pi/4, pi]) == pi assert lcim([2*pi, pi/2]) == 2*pi assert lcim([S.One, 2*pi]) is None assert lcim([S(2) + 2*E, E/3 + Rational(1, 3), S.One + E]) == S(2) + 2*E def test_is_convex(): assert is_convex(1/x, x, domain=Interval(0, oo)) == True assert is_convex(1/x, x, domain=Interval(-oo, 0)) == False assert is_convex(x**2, x, domain=Interval(0, oo)) == True assert is_convex(log(x), x) == False raises(NotImplementedError, lambda: is_convex(log(x), x, a)) def test_stationary_points(): x, y = symbols('x y') assert stationary_points(sin(x), x, Interval(-pi/2, pi/2) ) == {-pi/2, pi/2} assert stationary_points(sin(x), x, Interval.Ropen(0, pi/4) ) == EmptySet() assert stationary_points(tan(x), x, ) == EmptySet() assert stationary_points(sin(x)*cos(x), x, Interval(0, pi) ) == {pi/4, pi*Rational(3, 4)} assert stationary_points(sec(x), x, Interval(0, pi) ) == {0, pi} assert stationary_points((x+3)*(x-2), x ) == FiniteSet(Rational(-1, 2)) assert stationary_points((x + 3)/(x - 2), x, Interval(-5, 5) ) == EmptySet() assert stationary_points((x**2+3)/(x-2), x ) == {2 - sqrt(7), 2 + sqrt(7)} assert stationary_points((x**2+3)/(x-2), x, Interval(0, 5) ) == {2 + sqrt(7)} assert stationary_points(x**4 + x**3 - 5*x**2, x, S.Reals ) == FiniteSet(-2, 0, Rational(5, 4)) assert stationary_points(exp(x), x ) == EmptySet() assert stationary_points(log(x) - x, x, S.Reals ) == {1} assert stationary_points(cos(x), x, Union(Interval(0, 5), Interval(-6, -3)) ) == {0, -pi, pi} assert stationary_points(y, x, S.Reals ) == S.Reals assert stationary_points(y, x, S.EmptySet) == S.EmptySet def test_maximum(): x, y = symbols('x y') assert maximum(sin(x), x) is S.One assert maximum(sin(x), x, Interval(0, 1)) == sin(1) assert maximum(tan(x), x) is oo assert maximum(tan(x), x, Interval(-pi/4, pi/4)) is S.One assert maximum(sin(x)*cos(x), x, S.Reals) == S.Half assert simplify(maximum(sin(x)*cos(x), x, Interval(pi*Rational(3, 8), pi*Rational(5, 8))) ) == sqrt(2)/4 assert maximum((x+3)*(x-2), x) is oo assert maximum((x+3)*(x-2), x, Interval(-5, 0)) == S(14) assert maximum((x+3)/(x-2), x, Interval(-5, 0)) == Rational(2, 7) assert simplify(maximum(-x**4-x**3+x**2+10, x) ) == 41*sqrt(41)/512 + Rational(5419, 512) assert maximum(exp(x), x, Interval(-oo, 2)) == exp(2) assert maximum(log(x) - x, x, S.Reals) is S.NegativeOne assert maximum(cos(x), x, Union(Interval(0, 5), Interval(-6, -3)) ) is S.One assert maximum(cos(x)-sin(x), x, S.Reals) == sqrt(2) assert maximum(y, x, S.Reals) == y assert maximum(abs(a**3 + a), a, Interval(0, 2)) == 10 assert maximum(abs(60*a**3 + 24*a), a, Interval(0, 2)) == 528 assert maximum(abs(12*a*(5*a**2 + 2)), a, Interval(0, 2)) == 528 assert maximum(x/sqrt(x**2+1), x, S.Reals) == 1 raises(ValueError, lambda : maximum(sin(x), x, S.EmptySet)) raises(ValueError, lambda : maximum(log(cos(x)), x, S.EmptySet)) raises(ValueError, lambda : maximum(1/(x**2 + y**2 + 1), x, S.EmptySet)) raises(ValueError, lambda : maximum(sin(x), sin(x))) raises(ValueError, lambda : maximum(sin(x), x*y, S.EmptySet)) raises(ValueError, lambda : maximum(sin(x), S.One)) def test_minimum(): x, y = symbols('x y') assert minimum(sin(x), x) is S.NegativeOne assert minimum(sin(x), x, Interval(1, 4)) == sin(4) assert minimum(tan(x), x) is -oo assert minimum(tan(x), x, Interval(-pi/4, pi/4)) is S.NegativeOne assert minimum(sin(x)*cos(x), x, S.Reals) == Rational(-1, 2) assert simplify(minimum(sin(x)*cos(x), x, Interval(pi*Rational(3, 8), pi*Rational(5, 8))) ) == -sqrt(2)/4 assert minimum((x+3)*(x-2), x) == Rational(-25, 4) assert minimum((x+3)/(x-2), x, Interval(-5, 0)) == Rational(-3, 2) assert minimum(x**4-x**3+x**2+10, x) == S(10) assert minimum(exp(x), x, Interval(-2, oo)) == exp(-2) assert minimum(log(x) - x, x, S.Reals) is -oo assert minimum(cos(x), x, Union(Interval(0, 5), Interval(-6, -3)) ) is S.NegativeOne assert minimum(cos(x)-sin(x), x, S.Reals) == -sqrt(2) assert minimum(y, x, S.Reals) == y assert minimum(x/sqrt(x**2+1), x, S.Reals) == -1 raises(ValueError, lambda : minimum(sin(x), x, S.EmptySet)) raises(ValueError, lambda : minimum(log(cos(x)), x, S.EmptySet)) raises(ValueError, lambda : minimum(1/(x**2 + y**2 + 1), x, S.EmptySet)) raises(ValueError, lambda : minimum(sin(x), sin(x))) raises(ValueError, lambda : minimum(sin(x), x*y, S.EmptySet)) raises(ValueError, lambda : minimum(sin(x), S.One)) def test_issue_19869(): t = symbols('t') assert (maximum(sqrt(3)*(t - 1)/(3*sqrt(t**2 + 1)), t) ) == sqrt(3)/3 def test_AccumBounds(): assert B(1, 2).args == (1, 2) assert B(1, 2).delta is S.One assert B(1, 2).mid == Rational(3, 2) assert B(1, 3).is_real == True assert B(1, 1) is S.One assert B(1, 2) + 1 == B(2, 3) assert 1 + B(1, 2) == B(2, 3) assert B(1, 2) + B(2, 3) == B(3, 5) assert -B(1, 2) == B(-2, -1) assert B(1, 2) - 1 == B(0, 1) assert 1 - B(1, 2) == B(-1, 0) assert B(2, 3) - B(1, 2) == B(0, 2) assert x + B(1, 2) == Add(B(1, 2), x) assert a + B(1, 2) == B(1 + a, 2 + a) assert B(1, 2) - x == Add(B(1, 2), -x) assert B(-oo, 1) + oo == B(-oo, oo) assert B(1, oo) + oo is oo assert B(1, oo) - oo == B(-oo, oo) assert (-oo - B(-1, oo)) is -oo assert B(-oo, 1) - oo is -oo assert B(1, oo) - oo == B(-oo, oo) assert B(-oo, 1) - (-oo) == B(-oo, oo) assert (oo - B(1, oo)) == B(-oo, oo) assert (-oo - B(1, oo)) is -oo assert B(1, 2)/2 == B(S.Half, 1) assert 2/B(2, 3) == B(Rational(2, 3), 1) assert 1/B(-1, 1) == B(-oo, oo) assert abs(B(1, 2)) == B(1, 2) assert abs(B(-2, -1)) == B(1, 2) assert abs(B(-2, 1)) == B(0, 2) assert abs(B(-1, 2)) == B(0, 2) c = Symbol('c') raises(ValueError, lambda: B(0, c)) raises(ValueError, lambda: B(1, -1)) r = Symbol('r', real=True) raises(ValueError, lambda: B(r, r - 1)) def test_AccumBounds_mul(): assert B(1, 2)*2 == B(2, 4) assert 2*B(1, 2) == B(2, 4) assert B(1, 2)*B(2, 3) == B(2, 6) assert B(0, 2)*B(2, oo) == B(0, oo) l, r = B(-oo, oo), B(-a, a) assert l*r == B(-oo, oo) assert r*l == B(-oo, oo) l, r = B(1, oo), B(-3, -2) assert l*r == B(-oo, -2) assert r*l == B(-oo, -2) assert B(1, 2)*0 == 0 assert B(1, oo)*0 == B(0, oo) assert B(-oo, 1)*0 == B(-oo, 0) assert B(-oo, oo)*0 == B(-oo, oo) assert B(1, 2)*x == Mul(B(1, 2), x, evaluate=False) assert B(0, 2)*oo == B(0, oo) assert B(-2, 0)*oo == B(-oo, 0) assert B(0, 2)*(-oo) == B(-oo, 0) assert B(-2, 0)*(-oo) == B(0, oo) assert B(-1, 1)*oo == B(-oo, oo) assert B(-1, 1)*(-oo) == B(-oo, oo) assert B(-oo, oo)*oo == B(-oo, oo) def test_AccumBounds_div(): assert B(-1, 3)/B(3, 4) == B(Rational(-1, 3), 1) assert B(-2, 4)/B(-3, 4) == B(-oo, oo) assert B(-3, -2)/B(-4, 0) == B(S.Half, oo) # these two tests can have a better answer # after Union of B is improved assert B(-3, -2)/B(-2, 1) == B(-oo, oo) assert B(2, 3)/B(-2, 2) == B(-oo, oo) assert B(-3, -2)/B(0, 4) == B(-oo, Rational(-1, 2)) assert B(2, 4)/B(-3, 0) == B(-oo, Rational(-2, 3)) assert B(2, 4)/B(0, 3) == B(Rational(2, 3), oo) assert B(0, 1)/B(0, 1) == B(0, oo) assert B(-1, 0)/B(0, 1) == B(-oo, 0) assert B(-1, 2)/B(-2, 2) == B(-oo, oo) assert 1/B(-1, 2) == B(-oo, oo) assert 1/B(0, 2) == B(S.Half, oo) assert (-1)/B(0, 2) == B(-oo, Rational(-1, 2)) assert 1/B(-oo, 0) == B(-oo, 0) assert 1/B(-1, 0) == B(-oo, -1) assert (-2)/B(-oo, 0) == B(0, oo) assert 1/B(-oo, -1) == B(-1, 0) assert B(1, 2)/a == Mul(B(1, 2), 1/a, evaluate=False) assert B(1, 2)/0 == B(1, 2)*zoo assert B(1, oo)/oo == B(0, oo) assert B(1, oo)/(-oo) == B(-oo, 0) assert B(-oo, -1)/oo == B(-oo, 0) assert B(-oo, -1)/(-oo) == B(0, oo) assert B(-oo, oo)/oo == B(-oo, oo) assert B(-oo, oo)/(-oo) == B(-oo, oo) assert B(-1, oo)/oo == B(0, oo) assert B(-1, oo)/(-oo) == B(-oo, 0) assert B(-oo, 1)/oo == B(-oo, 0) assert B(-oo, 1)/(-oo) == B(0, oo) def test_issue_18795(): r = Symbol('r', real=True) a = B(-1,1) c = B(7, oo) b = B(-oo, oo) assert c - tan(r) == B(7-tan(r), oo) assert b + tan(r) == B(-oo, oo) assert (a + r)/a == B(-oo, oo)*B(r - 1, r + 1) assert (b + a)/a == B(-oo, oo) def test_AccumBounds_func(): assert (x**2 + 2*x + 1).subs(x, B(-1, 1)) == B(-1, 4) assert exp(B(0, 1)) == B(1, E) assert exp(B(-oo, oo)) == B(0, oo) assert log(B(3, 6)) == B(log(3), log(6)) @XFAIL def test_AccumBounds_powf(): nn = Symbol('nn', nonnegative=True) assert B(1 + nn, 2 + nn)**B(1, 2) == B(1 + nn, (2 + nn)**2) i = Symbol('i', integer=True, negative=True) assert B(1, 2)**i == B(2**i, 1) def test_AccumBounds_pow(): assert B(0, 2)**2 == B(0, 4) assert B(-1, 1)**2 == B(0, 1) assert B(1, 2)**2 == B(1, 4) assert B(-1, 2)**3 == B(-1, 8) assert B(-1, 1)**0 == 1 assert B(1, 2)**Rational(5, 2) == B(1, 4*sqrt(2)) assert B(0, 2)**S.Half == B(0, sqrt(2)) neg = Symbol('neg', negative=True) unchanged(Pow, B(neg, 1), S.Half) nn = Symbol('nn', nonnegative=True) assert B(nn, nn + 1)**S.Half == B(sqrt(nn), sqrt(nn + 1)) assert B(nn, nn + 1)**nn == B(nn**nn, (nn + 1)**nn) unchanged(Pow, B(nn, nn + 1), x) i = Symbol('i', integer=True) unchanged(Pow, B(1, 2), i) i = Symbol('i', integer=True, nonnegative=True) assert B(1, 2)**i == B(1, 2**i) assert B(0, 1)**i == B(0**i, 1) assert B(1, 5)**(-2) == B(Rational(1, 25), 1) assert B(-1, 3)**(-2) == B(0, oo) assert B(0, 2)**(-3) == B(Rational(1, 8), oo) assert B(-2, 0)**(-3) == B(-oo, -Rational(1, 8)) assert B(0, 2)**(-2) == B(Rational(1, 4), oo) assert B(-1, 2)**(-3) == B(-oo, oo) assert B(-3, -2)**(-3) == B(Rational(-1, 8), Rational(-1, 27)) assert B(-3, -2)**(-2) == B(Rational(1, 9), Rational(1, 4)) assert B(0, oo)**S.Half == B(0, oo) assert B(-oo, 0)**(-2) == B(0, oo) assert B(-2, 0)**(-2) == B(Rational(1, 4), oo) assert B(Rational(1, 3), S.Half)**oo is S.Zero assert B(0, S.Half)**oo is S.Zero assert B(S.Half, 1)**oo == B(0, oo) assert B(0, 1)**oo == B(0, oo) assert B(2, 3)**oo is oo assert B(1, 2)**oo == B(0, oo) assert B(S.Half, 3)**oo == B(0, oo) assert B(Rational(-1, 3), Rational(-1, 4))**oo is S.Zero assert B(-1, Rational(-1, 2))**oo is S.NaN assert B(-3, -2)**oo is zoo assert B(-2, -1)**oo is S.NaN assert B(-2, Rational(-1, 2))**oo is S.NaN assert B(Rational(-1, 2), S.Half)**oo is S.Zero assert B(Rational(-1, 2), 1)**oo == B(0, oo) assert B(Rational(-2, 3), 2)**oo == B(0, oo) assert B(-1, 1)**oo == B(-oo, oo) assert B(-1, S.Half)**oo == B(-oo, oo) assert B(-1, 2)**oo == B(-oo, oo) assert B(-2, S.Half)**oo == B(-oo, oo) assert B(1, 2)**x == Pow(B(1, 2), x, evaluate=False) assert B(2, 3)**(-oo) is S.Zero assert B(0, 2)**(-oo) == B(0, oo) assert B(-1, 2)**(-oo) == B(-oo, oo) assert (tan(x)**sin(2*x)).subs(x, B(0, pi/2)) == \ Pow(B(-oo, oo), B(0, 1)) def test_AccumBounds_exponent(): # base is 0 z = 0**B(a, a + S.Half) assert z.subs(a, 0) == B(0, 1) assert z.subs(a, 1) == 0 p = z.subs(a, -1) assert p.is_Pow and p.args == (0, B(-1, -S.Half)) # base > 0 # when base is 1 the type of bounds does not matter assert 1**B(a, a + 1) == 1 # otherwise we need to know if 0 is in the bounds assert S.Half**B(-2, 2) == B(S(1)/4, 4) assert 2**B(-2, 2) == B(S(1)/4, 4) # +eps may introduce +oo # if there is a negative integer exponent assert B(0, 1)**B(S(1)/2, 1) == B(0, 1) assert B(0, 1)**B(0, 1) == B(0, 1) # positive bases have positive bounds assert B(2, 3)**B(-3, -2) == B(S(1)/27, S(1)/4) assert B(2, 3)**B(-3, 2) == B(S(1)/27, 9) # bounds generating imaginary parts unevaluated unchanged(Pow, B(-1, 1), B(1, 2)) assert B(0, S(1)/2)**B(1, oo) == B(0, S(1)/2) assert B(0, 1)**B(1, oo) == B(0, oo) assert B(0, 2)**B(1, oo) == B(0, oo) assert B(0, oo)**B(1, oo) == B(0, oo) assert B(S(1)/2, 1)**B(1, oo) == B(0, oo) assert B(S(1)/2, 1)**B(-oo, -1) == B(0, oo) assert B(S(1)/2, 1)**B(-oo, oo) == B(0, oo) assert B(S(1)/2, 2)**B(1, oo) == B(0, oo) assert B(S(1)/2, 2)**B(-oo, -1) == B(0, oo) assert B(S(1)/2, 2)**B(-oo, oo) == B(0, oo) assert B(S(1)/2, oo)**B(1, oo) == B(0, oo) assert B(S(1)/2, oo)**B(-oo, -1) == B(0, oo) assert B(S(1)/2, oo)**B(-oo, oo) == B(0, oo) assert B(1, 2)**B(1, oo) == B(0, oo) assert B(1, 2)**B(-oo, -1) == B(0, oo) assert B(1, 2)**B(-oo, oo) == B(0, oo) assert B(1, oo)**B(1, oo) == B(0, oo) assert B(1, oo)**B(-oo, -1) == B(0, oo) assert B(1, oo)**B(-oo, oo) == B(0, oo) assert B(2, oo)**B(1, oo) == B(2, oo) assert B(2, oo)**B(-oo, -1) == B(0, S(1)/2) assert B(2, oo)**B(-oo, oo) == B(0, oo) def test_comparison_AccumBounds(): assert (B(1, 3) < 4) == S.true assert (B(1, 3) < -1) == S.false assert (B(1, 3) < 2).rel_op == '<' assert (B(1, 3) <= 2).rel_op == '<=' assert (B(1, 3) > 4) == S.false assert (B(1, 3) > -1) == S.true assert (B(1, 3) > 2).rel_op == '>' assert (B(1, 3) >= 2).rel_op == '>=' assert (B(1, 3) < B(4, 6)) == S.true assert (B(1, 3) < B(2, 4)).rel_op == '<' assert (B(1, 3) < B(-2, 0)) == S.false assert (B(1, 3) <= B(4, 6)) == S.true assert (B(1, 3) <= B(-2, 0)) == S.false assert (B(1, 3) > B(4, 6)) == S.false assert (B(1, 3) > B(-2, 0)) == S.true assert (B(1, 3) >= B(4, 6)) == S.false assert (B(1, 3) >= B(-2, 0)) == S.true # issue 13499 assert (cos(x) > 0).subs(x, oo) == (B(-1, 1) > 0) c = Symbol('c') raises(TypeError, lambda: (B(0, 1) < c)) raises(TypeError, lambda: (B(0, 1) <= c)) raises(TypeError, lambda: (B(0, 1) > c)) raises(TypeError, lambda: (B(0, 1) >= c)) def test_contains_AccumBounds(): assert (1 in B(1, 2)) == S.true raises(TypeError, lambda: a in B(1, 2)) assert 0 in B(-1, 0) raises(TypeError, lambda: (cos(1)**2 + sin(1)**2 - 1) in B(-1, 0)) assert (-oo in B(1, oo)) == S.true assert (oo in B(-oo, 0)) == S.true # issue 13159 assert Mul(0, B(-1, 1)) == Mul(B(-1, 1), 0) == 0 import itertools for perm in itertools.permutations([0, B(-1, 1), x]): assert Mul(*perm) == 0 def test_intersection_AccumBounds(): assert B(0, 3).intersection(B(1, 2)) == B(1, 2) assert B(0, 3).intersection(B(1, 4)) == B(1, 3) assert B(0, 3).intersection(B(-1, 2)) == B(0, 2) assert B(0, 3).intersection(B(-1, 4)) == B(0, 3) assert B(0, 1).intersection(B(2, 3)) == S.EmptySet raises(TypeError, lambda: B(0, 3).intersection(1)) def test_union_AccumBounds(): assert B(0, 3).union(B(1, 2)) == B(0, 3) assert B(0, 3).union(B(1, 4)) == B(0, 4) assert B(0, 3).union(B(-1, 2)) == B(-1, 3) assert B(0, 3).union(B(-1, 4)) == B(-1, 4) raises(TypeError, lambda: B(0, 3).union(1)) def test_issue_16469(): x = Symbol("x", real=True) f = abs(x) assert function_range(f, x, S.Reals) == Interval(0, oo, False, True) @_both_exp_pow def test_issue_18747(): assert periodicity(exp(pi*I*(x/4+S.Half/2)), x) == 8 sympy-sympy-1.9/sympy/calculus/util.py000066400000000000000000001512771412543434000202630ustar00rootroot00000000000000from sympy import Order, S, log, limit, lcm_list, im, re, Dummy, Piecewise from sympy.core import Add, Mul, Pow from sympy.core.basic import Basic from sympy.core.compatibility import iterable from sympy.core.expr import AtomicExpr, Expr from sympy.core.function import expand_mul from sympy.core.numbers import _sympifyit, oo, zoo from sympy.core.relational import is_le, is_lt, is_ge, is_gt from sympy.core.sympify import _sympify from sympy.functions.elementary.miscellaneous import Min, Max from sympy.logic.boolalg import And from sympy.sets.sets import (Interval, Intersection, FiniteSet, Union, Complement, EmptySet) from sympy.sets.fancysets import ImageSet from sympy.solvers.inequalities import solve_univariate_inequality from sympy.utilities import filldedent from sympy.multipledispatch import dispatch def continuous_domain(f, symbol, domain): """ Returns the intervals in the given domain for which the function is continuous. This method is limited by the ability to determine the various singularities and discontinuities of the given function. Parameters ========== f : Expr The concerned function. symbol : Symbol The variable for which the intervals are to be determined. domain : Interval The domain over which the continuity of the symbol has to be checked. Examples ======== >>> from sympy import Symbol, S, tan, log, pi, sqrt >>> from sympy.sets import Interval >>> from sympy.calculus.util import continuous_domain >>> x = Symbol('x') >>> continuous_domain(1/x, x, S.Reals) Union(Interval.open(-oo, 0), Interval.open(0, oo)) >>> continuous_domain(tan(x), x, Interval(0, pi)) Union(Interval.Ropen(0, pi/2), Interval.Lopen(pi/2, pi)) >>> continuous_domain(sqrt(x - 2), x, Interval(-5, 5)) Interval(2, 5) >>> continuous_domain(log(2*x - 1), x, S.Reals) Interval.open(1/2, oo) Returns ======= Interval Union of all intervals where the function is continuous. Raises ====== NotImplementedError If the method to determine continuity of such a function has not yet been developed. """ from sympy.solvers.inequalities import solve_univariate_inequality from sympy.calculus.singularities import singularities if domain.is_subset(S.Reals): constrained_interval = domain for atom in f.atoms(Pow): den = atom.exp.as_numer_denom()[1] if den.is_even and den.is_nonzero: constraint = solve_univariate_inequality(atom.base >= 0, symbol).as_set() constrained_interval = Intersection(constraint, constrained_interval) for atom in f.atoms(log): constraint = solve_univariate_inequality(atom.args[0] > 0, symbol).as_set() constrained_interval = Intersection(constraint, constrained_interval) return constrained_interval - singularities(f, symbol, domain) def function_range(f, symbol, domain): """ Finds the range of a function in a given domain. This method is limited by the ability to determine the singularities and determine limits. Parameters ========== f : Expr The concerned function. symbol : Symbol The variable for which the range of function is to be determined. domain : Interval The domain under which the range of the function has to be found. Examples ======== >>> from sympy import Symbol, S, exp, log, pi, sqrt, sin, tan >>> from sympy.sets import Interval >>> from sympy.calculus.util import function_range >>> x = Symbol('x') >>> function_range(sin(x), x, Interval(0, 2*pi)) Interval(-1, 1) >>> function_range(tan(x), x, Interval(-pi/2, pi/2)) Interval(-oo, oo) >>> function_range(1/x, x, S.Reals) Union(Interval.open(-oo, 0), Interval.open(0, oo)) >>> function_range(exp(x), x, S.Reals) Interval.open(0, oo) >>> function_range(log(x), x, S.Reals) Interval(-oo, oo) >>> function_range(sqrt(x), x , Interval(-5, 9)) Interval(0, 3) Returns ======= Interval Union of all ranges for all intervals under domain where function is continuous. Raises ====== NotImplementedError If any of the intervals, in the given domain, for which function is continuous are not finite or real, OR if the critical points of the function on the domain can't be found. """ from sympy.solvers.solveset import solveset if isinstance(domain, EmptySet): return S.EmptySet period = periodicity(f, symbol) if period == S.Zero: # the expression is constant wrt symbol return FiniteSet(f.expand()) if period is not None: if isinstance(domain, Interval): if (domain.inf - domain.sup).is_infinite: domain = Interval(0, period) elif isinstance(domain, Union): for sub_dom in domain.args: if isinstance(sub_dom, Interval) and \ ((sub_dom.inf - sub_dom.sup).is_infinite): domain = Interval(0, period) intervals = continuous_domain(f, symbol, domain) range_int = S.EmptySet if isinstance(intervals,(Interval, FiniteSet)): interval_iter = (intervals,) elif isinstance(intervals, Union): interval_iter = intervals.args else: raise NotImplementedError(filldedent(''' Unable to find range for the given domain. ''')) for interval in interval_iter: if isinstance(interval, FiniteSet): for singleton in interval: if singleton in domain: range_int += FiniteSet(f.subs(symbol, singleton)) elif isinstance(interval, Interval): vals = S.EmptySet critical_points = S.EmptySet critical_values = S.EmptySet bounds = ((interval.left_open, interval.inf, '+'), (interval.right_open, interval.sup, '-')) for is_open, limit_point, direction in bounds: if is_open: critical_values += FiniteSet(limit(f, symbol, limit_point, direction)) vals += critical_values else: vals += FiniteSet(f.subs(symbol, limit_point)) solution = solveset(f.diff(symbol), symbol, interval) if not iterable(solution): raise NotImplementedError( 'Unable to find critical points for {}'.format(f)) if isinstance(solution, ImageSet): raise NotImplementedError( 'Infinite number of critical points for {}'.format(f)) critical_points += solution for critical_point in critical_points: vals += FiniteSet(f.subs(symbol, critical_point)) left_open, right_open = False, False if critical_values is not S.EmptySet: if critical_values.inf == vals.inf: left_open = True if critical_values.sup == vals.sup: right_open = True range_int += Interval(vals.inf, vals.sup, left_open, right_open) else: raise NotImplementedError(filldedent(''' Unable to find range for the given domain. ''')) return range_int def not_empty_in(finset_intersection, *syms): """ Finds the domain of the functions in `finite_set` in which the `finite_set` is not-empty Parameters ========== finset_intersection : The unevaluated intersection of FiniteSet containing real-valued functions with Union of Sets syms : Tuple of symbols Symbol for which domain is to be found Raises ====== NotImplementedError The algorithms to find the non-emptiness of the given FiniteSet are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report it to the github issue tracker (https://github.com/sympy/sympy/issues). Examples ======== >>> from sympy import FiniteSet, Interval, not_empty_in, oo >>> from sympy.abc import x >>> not_empty_in(FiniteSet(x/2).intersect(Interval(0, 1)), x) Interval(0, 2) >>> not_empty_in(FiniteSet(x, x**2).intersect(Interval(1, 2)), x) Union(Interval(1, 2), Interval(-sqrt(2), -1)) >>> not_empty_in(FiniteSet(x**2/(x + 2)).intersect(Interval(1, oo)), x) Union(Interval.Lopen(-2, -1), Interval(2, oo)) """ # TODO: handle piecewise defined functions # TODO: handle transcendental functions # TODO: handle multivariate functions if len(syms) == 0: raise ValueError("One or more symbols must be given in syms.") if finset_intersection is S.EmptySet: return S.EmptySet if isinstance(finset_intersection, Union): elm_in_sets = finset_intersection.args[0] return Union(not_empty_in(finset_intersection.args[1], *syms), elm_in_sets) if isinstance(finset_intersection, FiniteSet): finite_set = finset_intersection _sets = S.Reals else: finite_set = finset_intersection.args[1] _sets = finset_intersection.args[0] if not isinstance(finite_set, FiniteSet): raise ValueError('A FiniteSet must be given, not %s: %s' % (type(finite_set), finite_set)) if len(syms) == 1: symb = syms[0] else: raise NotImplementedError('more than one variables %s not handled' % (syms,)) def elm_domain(expr, intrvl): """ Finds the domain of an expression in any given interval """ from sympy.solvers.solveset import solveset _start = intrvl.start _end = intrvl.end _singularities = solveset(expr.as_numer_denom()[1], symb, domain=S.Reals) if intrvl.right_open: if _end is S.Infinity: _domain1 = S.Reals else: _domain1 = solveset(expr < _end, symb, domain=S.Reals) else: _domain1 = solveset(expr <= _end, symb, domain=S.Reals) if intrvl.left_open: if _start is S.NegativeInfinity: _domain2 = S.Reals else: _domain2 = solveset(expr > _start, symb, domain=S.Reals) else: _domain2 = solveset(expr >= _start, symb, domain=S.Reals) # domain in the interval expr_with_sing = Intersection(_domain1, _domain2) expr_domain = Complement(expr_with_sing, _singularities) return expr_domain if isinstance(_sets, Interval): return Union(*[elm_domain(element, _sets) for element in finite_set]) if isinstance(_sets, Union): _domain = S.EmptySet for intrvl in _sets.args: _domain_element = Union(*[elm_domain(element, intrvl) for element in finite_set]) _domain = Union(_domain, _domain_element) return _domain def periodicity(f, symbol, check=False): """ Tests the given function for periodicity in the given symbol. Parameters ========== f : Expr. The concerned function. symbol : Symbol The variable for which the period is to be determined. check : Boolean, optional The flag to verify whether the value being returned is a period or not. Returns ======= period The period of the function is returned. `None` is returned when the function is aperiodic or has a complex period. The value of `0` is returned as the period of a constant function. Raises ====== NotImplementedError The value of the period computed cannot be verified. Notes ===== Currently, we do not support functions with a complex period. The period of functions having complex periodic values such as `exp`, `sinh` is evaluated to `None`. The value returned might not be the "fundamental" period of the given function i.e. it may not be the smallest periodic value of the function. The verification of the period through the `check` flag is not reliable due to internal simplification of the given expression. Hence, it is set to `False` by default. Examples ======== >>> from sympy import Symbol, sin, cos, tan, exp >>> from sympy.calculus.util import periodicity >>> x = Symbol('x') >>> f = sin(x) + sin(2*x) + sin(3*x) >>> periodicity(f, x) 2*pi >>> periodicity(sin(x)*cos(x), x) pi >>> periodicity(exp(tan(2*x) - 1), x) pi/2 >>> periodicity(sin(4*x)**cos(2*x), x) pi >>> periodicity(exp(x), x) """ from sympy.core.mod import Mod from sympy.core.relational import Relational from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.complexes import Abs from sympy.functions.elementary.trigonometric import ( TrigonometricFunction, sin, cos, csc, sec) from sympy.simplify.simplify import simplify from sympy.solvers.decompogen import decompogen from sympy.polys.polytools import degree temp = Dummy('x', real=True) f = f.subs(symbol, temp) symbol = temp def _check(orig_f, period): '''Return the checked period or raise an error.''' new_f = orig_f.subs(symbol, symbol + period) if new_f.equals(orig_f): return period else: raise NotImplementedError(filldedent(''' The period of the given function cannot be verified. When `%s` was replaced with `%s + %s` in `%s`, the result was `%s` which was not recognized as being the same as the original function. So either the period was wrong or the two forms were not recognized as being equal. Set check=False to obtain the value.''' % (symbol, symbol, period, orig_f, new_f))) orig_f = f period = None if isinstance(f, Relational): f = f.lhs - f.rhs f = simplify(f) if symbol not in f.free_symbols: return S.Zero if isinstance(f, TrigonometricFunction): try: period = f.period(symbol) except NotImplementedError: pass if isinstance(f, Abs): arg = f.args[0] if isinstance(arg, (sec, csc, cos)): # all but tan and cot might have a # a period that is half as large # so recast as sin arg = sin(arg.args[0]) period = periodicity(arg, symbol) if period is not None and isinstance(arg, sin): # the argument of Abs was a trigonometric other than # cot or tan; test to see if the half-period # is valid. Abs(arg) has behaviour equivalent to # orig_f, so use that for test: orig_f = Abs(arg) try: return _check(orig_f, period/2) except NotImplementedError as err: if check: raise NotImplementedError(err) # else let new orig_f and period be # checked below if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1): f = Pow(S.Exp1, expand_mul(f.exp)) if im(f) != 0: period_real = periodicity(re(f), symbol) period_imag = periodicity(im(f), symbol) if period_real is not None and period_imag is not None: period = lcim([period_real, period_imag]) if f.is_Pow and f.base != S.Exp1: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if base_has_sym and not expo_has_sym: period = periodicity(base, symbol) elif expo_has_sym and not base_has_sym: period = periodicity(expo, symbol) else: period = _periodicity(f.args, symbol) elif f.is_Mul: coeff, g = f.as_independent(symbol, as_Add=False) if isinstance(g, TrigonometricFunction) or coeff is not S.One: period = periodicity(g, symbol) else: period = _periodicity(g.args, symbol) elif f.is_Add: k, g = f.as_independent(symbol) if k is not S.Zero: return periodicity(g, symbol) period = _periodicity(g.args, symbol) elif isinstance(f, Mod): a, n = f.args if a == symbol: period = n elif isinstance(a, TrigonometricFunction): period = periodicity(a, symbol) #check if 'f' is linear in 'symbol' elif (a.is_polynomial(symbol) and degree(a, symbol) == 1 and symbol not in n.free_symbols): period = Abs(n / a.diff(symbol)) elif isinstance(f, Piecewise): pass # not handling Piecewise yet as the return type is not favorable elif period is None: from sympy.solvers.decompogen import compogen g_s = decompogen(f, symbol) num_of_gs = len(g_s) if num_of_gs > 1: for index, g in enumerate(reversed(g_s)): start_index = num_of_gs - 1 - index g = compogen(g_s[start_index:], symbol) if g != orig_f and g != f: # Fix for issue 12620 period = periodicity(g, symbol) if period is not None: break if period is not None: if check: return _check(orig_f, period) return period return None def _periodicity(args, symbol): """ Helper for `periodicity` to find the period of a list of simpler functions. It uses the `lcim` method to find the least common period of all the functions. Parameters ========== args : Tuple of Symbol All the symbols present in a function. symbol : Symbol The symbol over which the function is to be evaluated. Returns ======= period The least common period of the function for all the symbols of the function. None if for at least one of the symbols the function is aperiodic """ periods = [] for f in args: period = periodicity(f, symbol) if period is None: return None if period is not S.Zero: periods.append(period) if len(periods) > 1: return lcim(periods) if periods: return periods[0] def lcim(numbers): """Returns the least common integral multiple of a list of numbers. The numbers can be rational or irrational or a mixture of both. `None` is returned for incommensurable numbers. Parameters ========== numbers : list Numbers (rational and/or irrational) for which lcim is to be found. Returns ======= number lcim if it exists, otherwise `None` for incommensurable numbers. Examples ======== >>> from sympy import S, pi >>> from sympy.calculus.util import lcim >>> lcim([S(1)/2, S(3)/4, S(5)/6]) 15/2 >>> lcim([2*pi, 3*pi, pi, pi/2]) 6*pi >>> lcim([S(1), 2*pi]) """ result = None if all(num.is_irrational for num in numbers): factorized_nums = list(map(lambda num: num.factor(), numbers)) factors_num = list( map(lambda num: num.as_coeff_Mul(), factorized_nums)) term = factors_num[0][1] if all(factor == term for coeff, factor in factors_num): common_term = term coeffs = [coeff for coeff, factor in factors_num] result = lcm_list(coeffs) * common_term elif all(num.is_rational for num in numbers): result = lcm_list(numbers) else: pass return result def is_convex(f, *syms, domain=S.Reals): """Determines the convexity of the function passed in the argument. Parameters ========== f : Expr The concerned function. syms : Tuple of symbols The variables with respect to which the convexity is to be determined. domain : Interval, optional The domain over which the convexity of the function has to be checked. If unspecified, S.Reals will be the default domain. Returns ======= Boolean The method returns `True` if the function is convex otherwise it returns `False`. Raises ====== NotImplementedError The check for the convexity of multivariate functions is not implemented yet. Notes ===== To determine concavity of a function pass `-f` as the concerned function. To determine logarithmic convexity of a function pass log(f) as concerned function. To determine logartihmic concavity of a function pass -log(f) as concerned function. Currently, convexity check of multivariate functions is not handled. Examples ======== >>> from sympy import symbols, exp, oo, Interval >>> from sympy.calculus.util import is_convex >>> x = symbols('x') >>> is_convex(exp(x), x) True >>> is_convex(x**3, x, domain = Interval(-1, oo)) False References ========== .. [1] https://en.wikipedia.org/wiki/Convex_function .. [2] http://www.ifp.illinois.edu/~angelia/L3_convfunc.pdf .. [3] https://en.wikipedia.org/wiki/Logarithmically_convex_function .. [4] https://en.wikipedia.org/wiki/Logarithmically_concave_function .. [5] https://en.wikipedia.org/wiki/Concave_function """ if len(syms) > 1: raise NotImplementedError( "The check for the convexity of multivariate functions is not implemented yet.") f = _sympify(f) var = syms[0] condition = f.diff(var, 2) < 0 if solve_univariate_inequality(condition, var, False, domain): return False return True def stationary_points(f, symbol, domain=S.Reals): """ Returns the stationary points of a function (where derivative of the function is 0) in the given domain. Parameters ========== f : Expr The concerned function. symbol : Symbol The variable for which the stationary points are to be determined. domain : Interval The domain over which the stationary points have to be checked. If unspecified, S.Reals will be the default domain. Returns ======= Set A set of stationary points for the function. If there are no stationary point, an EmptySet is returned. Examples ======== >>> from sympy import Symbol, S, sin, pi, pprint, stationary_points >>> from sympy.sets import Interval >>> x = Symbol('x') >>> stationary_points(1/x, x, S.Reals) EmptySet >>> pprint(stationary_points(sin(x), x), use_unicode=False) pi 3*pi {2*n*pi + -- | n in Integers} U {2*n*pi + ---- | n in Integers} 2 2 >>> stationary_points(sin(x),x, Interval(0, 4*pi)) {pi/2, 3*pi/2, 5*pi/2, 7*pi/2} """ from sympy import solveset, diff if isinstance(domain, EmptySet): return S.EmptySet domain = continuous_domain(f, symbol, domain) set = solveset(diff(f, symbol), symbol, domain) return set def maximum(f, symbol, domain=S.Reals): """ Returns the maximum value of a function in the given domain. Parameters ========== f : Expr The concerned function. symbol : Symbol The variable for maximum value needs to be determined. domain : Interval The domain over which the maximum have to be checked. If unspecified, then Global maximum is returned. Returns ======= number Maximum value of the function in given domain. Examples ======== >>> from sympy import Symbol, S, sin, cos, pi, maximum >>> from sympy.sets import Interval >>> x = Symbol('x') >>> f = -x**2 + 2*x + 5 >>> maximum(f, x, S.Reals) 6 >>> maximum(sin(x), x, Interval(-pi, pi/4)) sqrt(2)/2 >>> maximum(sin(x)*cos(x), x) 1/2 """ from sympy import Symbol if isinstance(symbol, Symbol): if isinstance(domain, EmptySet): raise ValueError("Maximum value not defined for empty domain.") return function_range(f, symbol, domain).sup else: raise ValueError("%s is not a valid symbol." % symbol) def minimum(f, symbol, domain=S.Reals): """ Returns the minimum value of a function in the given domain. Parameters ========== f : Expr The concerned function. symbol : Symbol The variable for minimum value needs to be determined. domain : Interval The domain over which the minimum have to be checked. If unspecified, then Global minimum is returned. Returns ======= number Minimum value of the function in the given domain. Examples ======== >>> from sympy import Symbol, S, sin, cos, minimum >>> from sympy.sets import Interval >>> x = Symbol('x') >>> f = x**2 + 2*x + 5 >>> minimum(f, x, S.Reals) 4 >>> minimum(sin(x), x, Interval(2, 3)) sin(3) >>> minimum(sin(x)*cos(x), x) -1/2 """ from sympy import Symbol if isinstance(symbol, Symbol): if isinstance(domain, EmptySet): raise ValueError("Minimum value not defined for empty domain.") return function_range(f, symbol, domain).inf else: raise ValueError("%s is not a valid symbol." % symbol) class AccumulationBounds(AtomicExpr): r""" # Note AccumulationBounds has an alias: AccumBounds AccumulationBounds represent an interval `[a, b]`, which is always closed at the ends. Here `a` and `b` can be any value from extended real numbers. The intended meaning of AccummulationBounds is to give an approximate location of the accumulation points of a real function at a limit point. Let `a` and `b` be reals such that a <= b. `\left\langle a, b\right\rangle = \{x \in \mathbb{R} \mid a \le x \le b\}` `\left\langle -\infty, b\right\rangle = \{x \in \mathbb{R} \mid x \le b\} \cup \{-\infty, \infty\}` `\left\langle a, \infty \right\rangle = \{x \in \mathbb{R} \mid a \le x\} \cup \{-\infty, \infty\}` `\left\langle -\infty, \infty \right\rangle = \mathbb{R} \cup \{-\infty, \infty\}` `oo` and `-oo` are added to the second and third definition respectively, since if either `-oo` or `oo` is an argument, then the other one should be included (though not as an end point). This is forced, since we have, for example, `1/AccumBounds(0, 1) = AccumBounds(1, oo)`, and the limit at `0` is not one-sided. As x tends to `0-`, then `1/x -> -oo`, so `-oo` should be interpreted as belonging to `AccumBounds(1, oo)` though it need not appear explicitly. In many cases it suffices to know that the limit set is bounded. However, in some other cases more exact information could be useful. For example, all accumulation values of cos(x) + 1 are non-negative. (AccumBounds(-1, 1) + 1 = AccumBounds(0, 2)) A AccumulationBounds object is defined to be real AccumulationBounds, if its end points are finite reals. Let `X`, `Y` be real AccumulationBounds, then their sum, difference, product are defined to be the following sets: `X + Y = \{ x+y \mid x \in X \cap y \in Y\}` `X - Y = \{ x-y \mid x \in X \cap y \in Y\}` `X * Y = \{ x*y \mid x \in X \cap y \in Y\}` When an AccumBounds is raised to a negative power, if 0 is contained between the bounds then an infinite range is returned, otherwise if an endpoint is 0 then a semi-infinite range with consistent sign will be returned. AccumBounds in expressions behave a lot like Intervals but the semantics are not necessarily the same. Division (or exponentiation to a negative integer power) could be handled with *intervals* by returning a union of the results obtained after splitting the bounds between negatives and positives, but that is not done with AccumBounds. In addition, bounds are assumed to be independent of each other; if the same bound is used in more than one place in an expression, the result may not be the supremum or infimum of the expression (see below). Finally, when a boundary is ``1``, exponentiation to the power of ``oo`` yields ``oo``, neither ``1`` nor ``nan``. Examples ======== >>> from sympy import AccumBounds, sin, exp, log, pi, E, S, oo >>> from sympy.abc import x >>> AccumBounds(0, 1) + AccumBounds(1, 2) AccumBounds(1, 3) >>> AccumBounds(0, 1) - AccumBounds(0, 2) AccumBounds(-2, 1) >>> AccumBounds(-2, 3)*AccumBounds(-1, 1) AccumBounds(-3, 3) >>> AccumBounds(1, 2)*AccumBounds(3, 5) AccumBounds(3, 10) The exponentiation of AccumulationBounds is defined as follows: If 0 does not belong to `X` or `n > 0` then `X^n = \{ x^n \mid x \in X\}` >>> AccumBounds(1, 4)**(S(1)/2) AccumBounds(1, 2) otherwise, an infinite or semi-infinite result is obtained: >>> 1/AccumBounds(-1, 1) AccumBounds(-oo, oo) >>> 1/AccumBounds(0, 2) AccumBounds(1/2, oo) >>> 1/AccumBounds(-oo, 0) AccumBounds(-oo, 0) A boundary of 1 will always generate all nonnegatives: >>> AccumBounds(1, 2)**oo AccumBounds(0, oo) >>> AccumBounds(0, 1)**oo AccumBounds(0, oo) If the exponent is itself an AccumulationBounds or is not an integer then unevaluated results will be returned unless the base values are positive: >>> AccumBounds(2, 3)**AccumBounds(-1, 2) AccumBounds(1/3, 9) >>> AccumBounds(-2, 3)**AccumBounds(-1, 2) AccumBounds(-2, 3)**AccumBounds(-1, 2) >>> AccumBounds(-2, -1)**(S(1)/2) sqrt(AccumBounds(-2, -1)) Note: `^2` is not same as `*` >>> AccumBounds(-1, 1)**2 AccumBounds(0, 1) >>> AccumBounds(1, 3) < 4 True >>> AccumBounds(1, 3) < -1 False Some elementary functions can also take AccumulationBounds as input. A function `f` evaluated for some real AccumulationBounds `` is defined as `f(\left\langle a, b\right\rangle) = \{ f(x) \mid a \le x \le b \}` >>> sin(AccumBounds(pi/6, pi/3)) AccumBounds(1/2, sqrt(3)/2) >>> exp(AccumBounds(0, 1)) AccumBounds(1, E) >>> log(AccumBounds(1, E)) AccumBounds(0, 1) Some symbol in an expression can be substituted for a AccumulationBounds object. But it doesn't necessarily evaluate the AccumulationBounds for that expression. The same expression can be evaluated to different values depending upon the form it is used for substitution since each instance of an AccumulationBounds is considered independent. For example: >>> (x**2 + 2*x + 1).subs(x, AccumBounds(-1, 1)) AccumBounds(-1, 4) >>> ((x + 1)**2).subs(x, AccumBounds(-1, 1)) AccumBounds(0, 4) References ========== .. [1] https://en.wikipedia.org/wiki/Interval_arithmetic .. [2] http://fab.cba.mit.edu/classes/S62.12/docs/Hickey_interval.pdf Notes ===== Do not use ``AccumulationBounds`` for floating point interval arithmetic calculations, use ``mpmath.iv`` instead. """ is_extended_real = True def __new__(cls, min, max): min = _sympify(min) max = _sympify(max) # Only allow real intervals (use symbols with 'is_extended_real=True'). if not min.is_extended_real or not max.is_extended_real: raise ValueError("Only real AccumulationBounds are supported") if max == min: return max # Make sure that the created AccumBounds object will be valid. if max.is_number and min.is_number: bad = max.is_comparable and min.is_comparable and max < min else: bad = (max - min).is_extended_negative if bad: raise ValueError( "Lower limit should be smaller than upper limit") return Basic.__new__(cls, min, max) # setting the operation priority _op_priority = 11.0 def _eval_is_real(self): if self.min.is_real and self.max.is_real: return True @property def min(self): """ Returns the minimum possible value attained by AccumulationBounds object. Examples ======== >>> from sympy import AccumBounds >>> AccumBounds(1, 3).min 1 """ return self.args[0] @property def max(self): """ Returns the maximum possible value attained by AccumulationBounds object. Examples ======== >>> from sympy import AccumBounds >>> AccumBounds(1, 3).max 3 """ return self.args[1] @property def delta(self): """ Returns the difference of maximum possible value attained by AccumulationBounds object and minimum possible value attained by AccumulationBounds object. Examples ======== >>> from sympy import AccumBounds >>> AccumBounds(1, 3).delta 2 """ return self.max - self.min @property def mid(self): """ Returns the mean of maximum possible value attained by AccumulationBounds object and minimum possible value attained by AccumulationBounds object. Examples ======== >>> from sympy import AccumBounds >>> AccumBounds(1, 3).mid 2 """ return (self.min + self.max) / 2 @_sympifyit('other', NotImplemented) def _eval_power(self, other): return self.__pow__(other) @_sympifyit('other', NotImplemented) def __add__(self, other): if isinstance(other, Expr): if isinstance(other, AccumBounds): return AccumBounds( Add(self.min, other.min), Add(self.max, other.max)) if other is S.Infinity and self.min is S.NegativeInfinity or \ other is S.NegativeInfinity and self.max is S.Infinity: return AccumBounds(-oo, oo) elif other.is_extended_real: if self.min is S.NegativeInfinity and self.max is S.Infinity: return AccumBounds(-oo, oo) elif self.min is S.NegativeInfinity: return AccumBounds(-oo, self.max + other) elif self.max is S.Infinity: return AccumBounds(self.min + other, oo) else: return AccumBounds(Add(self.min, other), Add(self.max, other)) return Add(self, other, evaluate=False) return NotImplemented __radd__ = __add__ def __neg__(self): return AccumBounds(-self.max, -self.min) @_sympifyit('other', NotImplemented) def __sub__(self, other): if isinstance(other, Expr): if isinstance(other, AccumBounds): return AccumBounds( Add(self.min, -other.max), Add(self.max, -other.min)) if other is S.NegativeInfinity and self.min is S.NegativeInfinity or \ other is S.Infinity and self.max is S.Infinity: return AccumBounds(-oo, oo) elif other.is_extended_real: if self.min is S.NegativeInfinity and self.max is S.Infinity: return AccumBounds(-oo, oo) elif self.min is S.NegativeInfinity: return AccumBounds(-oo, self.max - other) elif self.max is S.Infinity: return AccumBounds(self.min - other, oo) else: return AccumBounds( Add(self.min, -other), Add(self.max, -other)) return Add(self, -other, evaluate=False) return NotImplemented @_sympifyit('other', NotImplemented) def __rsub__(self, other): return self.__neg__() + other @_sympifyit('other', NotImplemented) def __mul__(self, other): if self.args == (-oo, oo): return self if isinstance(other, Expr): if isinstance(other, AccumBounds): if other.args == (-oo, oo): return other v = set() for i in self.args: vi = other*i for i in vi.args or (vi,): v.add(i) return AccumBounds(Min(*v), Max(*v)) if other is S.Infinity: if self.min.is_zero: return AccumBounds(0, oo) if self.max.is_zero: return AccumBounds(-oo, 0) if other is S.NegativeInfinity: if self.min.is_zero: return AccumBounds(-oo, 0) if self.max.is_zero: return AccumBounds(0, oo) if other.is_extended_real: if other.is_zero: if self.max is S.Infinity: return AccumBounds(0, oo) if self.min is S.NegativeInfinity: return AccumBounds(-oo, 0) return S.Zero if other.is_extended_positive: return AccumBounds( Mul(self.min, other), Mul(self.max, other)) elif other.is_extended_negative: return AccumBounds( Mul(self.max, other), Mul(self.min, other)) if isinstance(other, Order): return other return Mul(self, other, evaluate=False) return NotImplemented __rmul__ = __mul__ @_sympifyit('other', NotImplemented) def __truediv__(self, other): if isinstance(other, Expr): if isinstance(other, AccumBounds): if other.min.is_positive or other.max.is_negative: return self * AccumBounds(1/other.max, 1/other.min) if (self.min.is_extended_nonpositive and self.max.is_extended_nonnegative and other.min.is_extended_nonpositive and other.max.is_extended_nonnegative): if self.min.is_zero and other.min.is_zero: return AccumBounds(0, oo) if self.max.is_zero and other.min.is_zero: return AccumBounds(-oo, 0) return AccumBounds(-oo, oo) if self.max.is_extended_negative: if other.min.is_extended_negative: if other.max.is_zero: return AccumBounds(self.max / other.min, oo) if other.max.is_extended_positive: # if we were dealing with intervals we would return # Union(Interval(-oo, self.max/other.max), # Interval(self.max/other.min, oo)) return AccumBounds(-oo, oo) if other.min.is_zero and other.max.is_extended_positive: return AccumBounds(-oo, self.max / other.max) if self.min.is_extended_positive: if other.min.is_extended_negative: if other.max.is_zero: return AccumBounds(-oo, self.min / other.min) if other.max.is_extended_positive: # if we were dealing with intervals we would return # Union(Interval(-oo, self.min/other.min), # Interval(self.min/other.max, oo)) return AccumBounds(-oo, oo) if other.min.is_zero and other.max.is_extended_positive: return AccumBounds(self.min / other.max, oo) elif other.is_extended_real: if other is S.Infinity or other is S.NegativeInfinity: if self == AccumBounds(-oo, oo): return AccumBounds(-oo, oo) if self.max is S.Infinity: return AccumBounds(Min(0, other), Max(0, other)) if self.min is S.NegativeInfinity: return AccumBounds(Min(0, -other), Max(0, -other)) if other.is_extended_positive: return AccumBounds(self.min / other, self.max / other) elif other.is_extended_negative: return AccumBounds(self.max / other, self.min / other) if (1 / other) is S.ComplexInfinity: return Mul(self, 1 / other, evaluate=False) else: return Mul(self, 1 / other) return NotImplemented @_sympifyit('other', NotImplemented) def __rtruediv__(self, other): if isinstance(other, Expr): if other.is_extended_real: if other.is_zero: return S.Zero if (self.min.is_extended_nonpositive and self.max.is_extended_nonnegative): if self.min.is_zero: if other.is_extended_positive: return AccumBounds(Mul(other, 1 / self.max), oo) if other.is_extended_negative: return AccumBounds(-oo, Mul(other, 1 / self.max)) if self.max.is_zero: if other.is_extended_positive: return AccumBounds(-oo, Mul(other, 1 / self.min)) if other.is_extended_negative: return AccumBounds(Mul(other, 1 / self.min), oo) return AccumBounds(-oo, oo) else: return AccumBounds(Min(other / self.min, other / self.max), Max(other / self.min, other / self.max)) return Mul(other, 1 / self, evaluate=False) else: return NotImplemented @_sympifyit('other', NotImplemented) def __pow__(self, other): if isinstance(other, Expr): if other is S.Infinity: if self.min.is_extended_nonnegative: if self.max < 1: return S.Zero if self.min > 1: return S.Infinity return AccumBounds(0, oo) elif self.max.is_extended_negative: if self.min > -1: return S.Zero if self.max < -1: return zoo return S.NaN else: if self.min > -1: if self.max < 1: return S.Zero return AccumBounds(0, oo) return AccumBounds(-oo, oo) if other is S.NegativeInfinity: return (1/self)**oo # generically true if (self.max - self.min).is_nonnegative: # well defined if self.min.is_nonnegative: # no 0 to worry about if other.is_nonnegative: # no infinity to worry about return self.func(self.min**other, self.max**other) if other.is_zero: return S.One # x**0 = 1 if other.is_Integer or other.is_integer: if self.min.is_extended_positive: return AccumBounds( Min(self.min**other, self.max**other), Max(self.min**other, self.max**other)) elif self.max.is_extended_negative: return AccumBounds( Min(self.max**other, self.min**other), Max(self.max**other, self.min**other)) if other % 2 == 0: if other.is_extended_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(self.min**other, oo) return AccumBounds(0, oo) return AccumBounds( S.Zero, Max(self.min**other, self.max**other)) elif other % 2 == 1: if other.is_extended_negative: if self.min.is_zero: return AccumBounds(self.max**other, oo) if self.max.is_zero: return AccumBounds(-oo, self.min**other) return AccumBounds(-oo, oo) return AccumBounds(self.min**other, self.max**other) # non-integer exponent # 0**neg or neg**frac yields complex if (other.is_number or other.is_rational) and ( self.min.is_extended_nonnegative or ( other.is_extended_nonnegative and self.min.is_extended_nonnegative)): num, den = other.as_numer_denom() if num is S.One: return AccumBounds(*[i**(1/den) for i in self.args]) elif den is not S.One: # e.g. if other is not Float return (self**num)**(1/den) # ok for non-negative base if isinstance(other, AccumBounds): if (self.min.is_extended_positive or self.min.is_extended_nonnegative and other.min.is_extended_nonnegative): p = [self**i for i in other.args] if not any(i.is_Pow for i in p): a = [j for i in p for j in i.args or (i,)] try: return self.func(min(a), max(a)) except TypeError: # can't sort pass return Pow(self, other, evaluate=False) return NotImplemented @_sympifyit('other', NotImplemented) def __rpow__(self, other): if other.is_real and other.is_extended_nonnegative and ( self.max - self.min).is_extended_positive: if other is S.One: return S.One if other.is_extended_positive: a, b = [other**i for i in self.args] if min(a, b) != a: a, b = b, a return self.func(a, b) if other.is_zero: if self.min.is_zero: return self.func(0, 1) if self.min.is_extended_positive: return S.Zero return Pow(other, self, evaluate=False) def __abs__(self): if self.max.is_extended_negative: return self.__neg__() elif self.min.is_extended_negative: return AccumBounds(S.Zero, Max(abs(self.min), self.max)) else: return self def __contains__(self, other): """ Returns True if other is contained in self, where other belongs to extended real numbers, False if not contained, otherwise TypeError is raised. Examples ======== >>> from sympy import AccumBounds, oo >>> 1 in AccumBounds(-1, 3) True -oo and oo go together as limits (in AccumulationBounds). >>> -oo in AccumBounds(1, oo) True >>> oo in AccumBounds(-oo, 0) True """ other = _sympify(other) if other is S.Infinity or other is S.NegativeInfinity: if self.min is S.NegativeInfinity or self.max is S.Infinity: return True return False rv = And(self.min <= other, self.max >= other) if rv not in (True, False): raise TypeError("input failed to evaluate") return rv def intersection(self, other): """ Returns the intersection of 'self' and 'other'. Here other can be an instance of FiniteSet or AccumulationBounds. Parameters ========== other: AccumulationBounds Another AccumulationBounds object with which the intersection has to be computed. Returns ======= AccumulationBounds Intersection of 'self' and 'other'. Examples ======== >>> from sympy import AccumBounds, FiniteSet >>> AccumBounds(1, 3).intersection(AccumBounds(2, 4)) AccumBounds(2, 3) >>> AccumBounds(1, 3).intersection(AccumBounds(4, 6)) EmptySet >>> AccumBounds(1, 4).intersection(FiniteSet(1, 2, 5)) {1, 2} """ if not isinstance(other, (AccumBounds, FiniteSet)): raise TypeError( "Input must be AccumulationBounds or FiniteSet object") if isinstance(other, FiniteSet): fin_set = S.EmptySet for i in other: if i in self: fin_set = fin_set + FiniteSet(i) return fin_set if self.max < other.min or self.min > other.max: return S.EmptySet if self.min <= other.min: if self.max <= other.max: return AccumBounds(other.min, self.max) if self.max > other.max: return other if other.min <= self.min: if other.max < self.max: return AccumBounds(self.min, other.max) if other.max > self.max: return self def union(self, other): # TODO : Devise a better method for Union of AccumBounds # this method is not actually correct and # can be made better if not isinstance(other, AccumBounds): raise TypeError( "Input must be AccumulationBounds or FiniteSet object") if self.min <= other.min and self.max >= other.min: return AccumBounds(self.min, Max(self.max, other.max)) if other.min <= self.min and other.max >= self.min: return AccumBounds(other.min, Max(self.max, other.max)) @dispatch(AccumulationBounds, AccumulationBounds) # type: ignore # noqa:F811 def _eval_is_le(lhs, rhs): # noqa:F811 if is_le(lhs.max, rhs.min): return True if is_gt(lhs.min, rhs.max): return False @dispatch(AccumulationBounds, Basic) # type: ignore # noqa:F811 def _eval_is_le(lhs, rhs): # noqa: F811 """ Returns True if range of values attained by `self` AccumulationBounds object is greater than the range of values attained by `other`, where other may be any value of type AccumulationBounds object or extended real number value, False if `other` satisfies the same property, else an unevaluated Relational. Examples ======== >>> from sympy import AccumBounds, oo >>> AccumBounds(1, 3) > AccumBounds(4, oo) False >>> AccumBounds(1, 4) > AccumBounds(3, 4) AccumBounds(1, 4) > AccumBounds(3, 4) >>> AccumBounds(1, oo) > -1 True """ if not rhs.is_extended_real: raise TypeError( "Invalid comparison of %s %s" % (type(rhs), rhs)) elif rhs.is_comparable: if is_le(lhs.max, rhs): return True if is_gt(lhs.min, rhs): return False @dispatch(AccumulationBounds, AccumulationBounds) def _eval_is_ge(lhs, rhs): # noqa:F811 if is_ge(lhs.min, rhs.max): return True if is_lt(lhs.max, rhs.min): return False @dispatch(AccumulationBounds, Expr) # type:ignore def _eval_is_ge(lhs, rhs): # noqa: F811 """ Returns True if range of values attained by `lhs` AccumulationBounds object is less that the range of values attained by `rhs`, where other may be any value of type AccumulationBounds object or extended real number value, False if `rhs` satisfies the same property, else an unevaluated Relational. Examples ======== >>> from sympy import AccumBounds, oo >>> AccumBounds(1, 3) >= AccumBounds(4, oo) False >>> AccumBounds(1, 4) >= AccumBounds(3, 4) AccumBounds(1, 4) >= AccumBounds(3, 4) >>> AccumBounds(1, oo) >= 1 True """ if not rhs.is_extended_real: raise TypeError( "Invalid comparison of %s %s" % (type(rhs), rhs)) elif rhs.is_comparable: if is_ge(lhs.min, rhs): return True if is_lt(lhs.max, rhs): return False @dispatch(Expr, AccumulationBounds) # type:ignore def _eval_is_ge(lhs, rhs): # noqa:F811 if not lhs.is_extended_real: raise TypeError( "Invalid comparison of %s %s" % (type(lhs), lhs)) elif lhs.is_comparable: if is_le(rhs.max, lhs): return True if is_gt(rhs.min, lhs): return False @dispatch(AccumulationBounds, AccumulationBounds) # type:ignore def _eval_is_ge(lhs, rhs): # noqa:F811 if is_ge(lhs.min, rhs.max): return True if is_lt(lhs.max, rhs.min): return False # setting an alias for AccumulationBounds AccumBounds = AccumulationBounds sympy-sympy-1.9/sympy/categories/000077500000000000000000000000001412543434000172315ustar00rootroot00000000000000sympy-sympy-1.9/sympy/categories/__init__.py000066400000000000000000000017301412543434000213430ustar00rootroot00000000000000""" Category Theory module. Provides some of the fundamental category-theory-related classes, including categories, morphisms, diagrams. Functors are not implemented yet. The general reference work this module tries to follow is [JoyOfCats] J. Adamek, H. Herrlich. G. E. Strecker: Abstract and Concrete Categories. The Joy of Cats. The latest version of this book should be available for free download from katmat.math.uni-bremen.de/acc/acc.pdf """ from .baseclasses import (Object, Morphism, IdentityMorphism, NamedMorphism, CompositeMorphism, Category, Diagram) from .diagram_drawing import (DiagramGrid, XypicDiagramDrawer, xypic_draw_diagram, preview_diagram) __all__ = [ 'Object', 'Morphism', 'IdentityMorphism', 'NamedMorphism', 'CompositeMorphism', 'Category', 'Diagram', 'DiagramGrid', 'XypicDiagramDrawer', 'xypic_draw_diagram', 'preview_diagram', ] sympy-sympy-1.9/sympy/categories/baseclasses.py000066400000000000000000000753241412543434000221060ustar00rootroot00000000000000from sympy.core import S, Basic, Dict, Symbol, Tuple, sympify from sympy.core.compatibility import iterable from sympy.core.symbol import Str from sympy.sets import Set, FiniteSet, EmptySet class Class(Set): r""" The base class for any kind of class in the set-theoretic sense. Explanation =========== In axiomatic set theories, everything is a class. A class which can be a member of another class is a set. A class which is not a member of another class is a proper class. The class `\{1, 2\}` is a set; the class of all sets is a proper class. This class is essentially a synonym for :class:`sympy.core.Set`. The goal of this class is to assure easier migration to the eventual proper implementation of set theory. """ is_proper = False class Object(Symbol): """ The base class for any kind of object in an abstract category. Explanation =========== While technically any instance of :class:`~.Basic` will do, this class is the recommended way to create abstract objects in abstract categories. """ class Morphism(Basic): """ The base class for any morphism in an abstract category. Explanation =========== In abstract categories, a morphism is an arrow between two category objects. The object where the arrow starts is called the domain, while the object where the arrow ends is called the codomain. Two morphisms between the same pair of objects are considered to be the same morphisms. To distinguish between morphisms between the same objects use :class:`NamedMorphism`. It is prohibited to instantiate this class. Use one of the derived classes instead. See Also ======== IdentityMorphism, NamedMorphism, CompositeMorphism """ def __new__(cls, domain, codomain): raise(NotImplementedError( "Cannot instantiate Morphism. Use derived classes instead.")) @property def domain(self): """ Returns the domain of the morphism. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> f = NamedMorphism(A, B, "f") >>> f.domain Object("A") """ return self.args[0] @property def codomain(self): """ Returns the codomain of the morphism. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> f = NamedMorphism(A, B, "f") >>> f.codomain Object("B") """ return self.args[1] def compose(self, other): r""" Composes self with the supplied morphism. The order of elements in the composition is the usual order, i.e., to construct `g\circ f` use ``g.compose(f)``. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> g * f CompositeMorphism((NamedMorphism(Object("A"), Object("B"), "f"), NamedMorphism(Object("B"), Object("C"), "g"))) >>> (g * f).domain Object("A") >>> (g * f).codomain Object("C") """ return CompositeMorphism(other, self) def __mul__(self, other): r""" Composes self with the supplied morphism. The semantics of this operation is given by the following equation: ``g * f == g.compose(f)`` for composable morphisms ``g`` and ``f``. See Also ======== compose """ return self.compose(other) class IdentityMorphism(Morphism): """ Represents an identity morphism. Explanation =========== An identity morphism is a morphism with equal domain and codomain, which acts as an identity with respect to composition. Examples ======== >>> from sympy.categories import Object, NamedMorphism, IdentityMorphism >>> A = Object("A") >>> B = Object("B") >>> f = NamedMorphism(A, B, "f") >>> id_A = IdentityMorphism(A) >>> id_B = IdentityMorphism(B) >>> f * id_A == f True >>> id_B * f == f True See Also ======== Morphism """ def __new__(cls, domain): return Basic.__new__(cls, domain) @property def codomain(self): return self.domain class NamedMorphism(Morphism): """ Represents a morphism which has a name. Explanation =========== Names are used to distinguish between morphisms which have the same domain and codomain: two named morphisms are equal if they have the same domains, codomains, and names. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> f = NamedMorphism(A, B, "f") >>> f NamedMorphism(Object("A"), Object("B"), "f") >>> f.name 'f' See Also ======== Morphism """ def __new__(cls, domain, codomain, name): if not name: raise ValueError("Empty morphism names not allowed.") if not isinstance(name, Str): name = Str(name) return Basic.__new__(cls, domain, codomain, name) @property def name(self): """ Returns the name of the morphism. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> f = NamedMorphism(A, B, "f") >>> f.name 'f' """ return self.args[2].name class CompositeMorphism(Morphism): r""" Represents a morphism which is a composition of other morphisms. Explanation =========== Two composite morphisms are equal if the morphisms they were obtained from (components) are the same and were listed in the same order. The arguments to the constructor for this class should be listed in diagram order: to obtain the composition `g\circ f` from the instances of :class:`Morphism` ``g`` and ``f`` use ``CompositeMorphism(f, g)``. Examples ======== >>> from sympy.categories import Object, NamedMorphism, CompositeMorphism >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> g * f CompositeMorphism((NamedMorphism(Object("A"), Object("B"), "f"), NamedMorphism(Object("B"), Object("C"), "g"))) >>> CompositeMorphism(f, g) == g * f True """ @staticmethod def _add_morphism(t, morphism): """ Intelligently adds ``morphism`` to tuple ``t``. Explanation =========== If ``morphism`` is a composite morphism, its components are added to the tuple. If ``morphism`` is an identity, nothing is added to the tuple. No composability checks are performed. """ if isinstance(morphism, CompositeMorphism): # ``morphism`` is a composite morphism; we have to # denest its components. return t + morphism.components elif isinstance(morphism, IdentityMorphism): # ``morphism`` is an identity. Nothing happens. return t else: return t + Tuple(morphism) def __new__(cls, *components): if components and not isinstance(components[0], Morphism): # Maybe the user has explicitly supplied a list of # morphisms. return CompositeMorphism.__new__(cls, *components[0]) normalised_components = Tuple() for current, following in zip(components, components[1:]): if not isinstance(current, Morphism) or \ not isinstance(following, Morphism): raise TypeError("All components must be morphisms.") if current.codomain != following.domain: raise ValueError("Uncomposable morphisms.") normalised_components = CompositeMorphism._add_morphism( normalised_components, current) # We haven't added the last morphism to the list of normalised # components. Add it now. normalised_components = CompositeMorphism._add_morphism( normalised_components, components[-1]) if not normalised_components: # If ``normalised_components`` is empty, only identities # were supplied. Since they all were composable, they are # all the same identities. return components[0] elif len(normalised_components) == 1: # No sense to construct a whole CompositeMorphism. return normalised_components[0] return Basic.__new__(cls, normalised_components) @property def components(self): """ Returns the components of this composite morphism. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> (g * f).components (NamedMorphism(Object("A"), Object("B"), "f"), NamedMorphism(Object("B"), Object("C"), "g")) """ return self.args[0] @property def domain(self): """ Returns the domain of this composite morphism. The domain of the composite morphism is the domain of its first component. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> (g * f).domain Object("A") """ return self.components[0].domain @property def codomain(self): """ Returns the codomain of this composite morphism. The codomain of the composite morphism is the codomain of its last component. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> (g * f).codomain Object("C") """ return self.components[-1].codomain def flatten(self, new_name): """ Forgets the composite structure of this morphism. Explanation =========== If ``new_name`` is not empty, returns a :class:`NamedMorphism` with the supplied name, otherwise returns a :class:`Morphism`. In both cases the domain of the new morphism is the domain of this composite morphism and the codomain of the new morphism is the codomain of this composite morphism. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> (g * f).flatten("h") NamedMorphism(Object("A"), Object("C"), "h") """ return NamedMorphism(self.domain, self.codomain, new_name) class Category(Basic): r""" An (abstract) category. Explanation =========== A category [JoyOfCats] is a quadruple `\mbox{K} = (O, \hom, id, \circ)` consisting of * a (set-theoretical) class `O`, whose members are called `K`-objects, * for each pair `(A, B)` of `K`-objects, a set `\hom(A, B)` whose members are called `K`-morphisms from `A` to `B`, * for a each `K`-object `A`, a morphism `id:A\rightarrow A`, called the `K`-identity of `A`, * a composition law `\circ` associating with every `K`-morphisms `f:A\rightarrow B` and `g:B\rightarrow C` a `K`-morphism `g\circ f:A\rightarrow C`, called the composite of `f` and `g`. Composition is associative, `K`-identities are identities with respect to composition, and the sets `\hom(A, B)` are pairwise disjoint. This class knows nothing about its objects and morphisms. Concrete cases of (abstract) categories should be implemented as classes derived from this one. Certain instances of :class:`Diagram` can be asserted to be commutative in a :class:`Category` by supplying the argument ``commutative_diagrams`` in the constructor. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram, Category >>> from sympy import FiniteSet >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> K = Category("K", commutative_diagrams=[d]) >>> K.commutative_diagrams == FiniteSet(d) True See Also ======== Diagram """ def __new__(cls, name, objects=EmptySet, commutative_diagrams=EmptySet): if not name: raise ValueError("A Category cannot have an empty name.") if not isinstance(name, Str): name = Str(name) if not isinstance(objects, Class): objects = Class(objects) new_category = Basic.__new__(cls, name, objects, FiniteSet(*commutative_diagrams)) return new_category @property def name(self): """ Returns the name of this category. Examples ======== >>> from sympy.categories import Category >>> K = Category("K") >>> K.name 'K' """ return self.args[0].name @property def objects(self): """ Returns the class of objects of this category. Examples ======== >>> from sympy.categories import Object, Category >>> from sympy import FiniteSet >>> A = Object("A") >>> B = Object("B") >>> K = Category("K", FiniteSet(A, B)) >>> K.objects Class({Object("A"), Object("B")}) """ return self.args[1] @property def commutative_diagrams(self): """ Returns the :class:`~.FiniteSet` of diagrams which are known to be commutative in this category. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram, Category >>> from sympy import FiniteSet >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> K = Category("K", commutative_diagrams=[d]) >>> K.commutative_diagrams == FiniteSet(d) True """ return self.args[2] def hom(self, A, B): raise NotImplementedError( "hom-sets are not implemented in Category.") def all_morphisms(self): raise NotImplementedError( "Obtaining the class of morphisms is not implemented in Category.") class Diagram(Basic): r""" Represents a diagram in a certain category. Explanation =========== Informally, a diagram is a collection of objects of a category and certain morphisms between them. A diagram is still a monoid with respect to morphism composition; i.e., identity morphisms, as well as all composites of morphisms included in the diagram belong to the diagram. For a more formal approach to this notion see [Pare1970]. The components of composite morphisms are also added to the diagram. No properties are assigned to such morphisms by default. A commutative diagram is often accompanied by a statement of the following kind: "if such morphisms with such properties exist, then such morphisms which such properties exist and the diagram is commutative". To represent this, an instance of :class:`Diagram` includes a collection of morphisms which are the premises and another collection of conclusions. ``premises`` and ``conclusions`` associate morphisms belonging to the corresponding categories with the :class:`~.FiniteSet`'s of their properties. The set of properties of a composite morphism is the intersection of the sets of properties of its components. The domain and codomain of a conclusion morphism should be among the domains and codomains of the morphisms listed as the premises of a diagram. No checks are carried out of whether the supplied object and morphisms do belong to one and the same category. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy import pprint, default_sort_key >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> premises_keys = sorted(d.premises.keys(), key=default_sort_key) >>> pprint(premises_keys, use_unicode=False) [g*f:A-->C, id:A-->A, id:B-->B, id:C-->C, f:A-->B, g:B-->C] >>> pprint(d.premises, use_unicode=False) {g*f:A-->C: EmptySet, id:A-->A: EmptySet, id:B-->B: EmptySet, id:C-->C: EmptyS et, f:A-->B: EmptySet, g:B-->C: EmptySet} >>> d = Diagram([f, g], {g * f: "unique"}) >>> pprint(d.conclusions,use_unicode=False) {g*f:A-->C: {unique}} References ========== [Pare1970] B. Pareigis: Categories and functors. Academic Press, 1970. """ @staticmethod def _set_dict_union(dictionary, key, value): """ If ``key`` is in ``dictionary``, set the new value of ``key`` to be the union between the old value and ``value``. Otherwise, set the value of ``key`` to ``value. Returns ``True`` if the key already was in the dictionary and ``False`` otherwise. """ if key in dictionary: dictionary[key] = dictionary[key] | value return True else: dictionary[key] = value return False @staticmethod def _add_morphism_closure(morphisms, morphism, props, add_identities=True, recurse_composites=True): """ Adds a morphism and its attributes to the supplied dictionary ``morphisms``. If ``add_identities`` is True, also adds the identity morphisms for the domain and the codomain of ``morphism``. """ if not Diagram._set_dict_union(morphisms, morphism, props): # We have just added a new morphism. if isinstance(morphism, IdentityMorphism): if props: # Properties for identity morphisms don't really # make sense, because very much is known about # identity morphisms already, so much that they # are trivial. Having properties for identity # morphisms would only be confusing. raise ValueError( "Instances of IdentityMorphism cannot have properties.") return if add_identities: empty = EmptySet id_dom = IdentityMorphism(morphism.domain) id_cod = IdentityMorphism(morphism.codomain) Diagram._set_dict_union(morphisms, id_dom, empty) Diagram._set_dict_union(morphisms, id_cod, empty) for existing_morphism, existing_props in list(morphisms.items()): new_props = existing_props & props if morphism.domain == existing_morphism.codomain: left = morphism * existing_morphism Diagram._set_dict_union(morphisms, left, new_props) if morphism.codomain == existing_morphism.domain: right = existing_morphism * morphism Diagram._set_dict_union(morphisms, right, new_props) if isinstance(morphism, CompositeMorphism) and recurse_composites: # This is a composite morphism, add its components as # well. empty = EmptySet for component in morphism.components: Diagram._add_morphism_closure(morphisms, component, empty, add_identities) def __new__(cls, *args): """ Construct a new instance of Diagram. Explanation =========== If no arguments are supplied, an empty diagram is created. If at least an argument is supplied, ``args[0]`` is interpreted as the premises of the diagram. If ``args[0]`` is a list, it is interpreted as a list of :class:`Morphism`'s, in which each :class:`Morphism` has an empty set of properties. If ``args[0]`` is a Python dictionary or a :class:`Dict`, it is interpreted as a dictionary associating to some :class:`Morphism`'s some properties. If at least two arguments are supplied ``args[1]`` is interpreted as the conclusions of the diagram. The type of ``args[1]`` is interpreted in exactly the same way as the type of ``args[0]``. If only one argument is supplied, the diagram has no conclusions. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import IdentityMorphism, Diagram >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> IdentityMorphism(A) in d.premises.keys() True >>> g * f in d.premises.keys() True >>> d = Diagram([f, g], {g * f: "unique"}) >>> d.conclusions[g * f] {unique} """ premises = {} conclusions = {} # Here we will keep track of the objects which appear in the # premises. objects = EmptySet if len(args) >= 1: # We've got some premises in the arguments. premises_arg = args[0] if isinstance(premises_arg, list): # The user has supplied a list of morphisms, none of # which have any attributes. empty = EmptySet for morphism in premises_arg: objects |= FiniteSet(morphism.domain, morphism.codomain) Diagram._add_morphism_closure(premises, morphism, empty) elif isinstance(premises_arg, dict) or isinstance(premises_arg, Dict): # The user has supplied a dictionary of morphisms and # their properties. for morphism, props in premises_arg.items(): objects |= FiniteSet(morphism.domain, morphism.codomain) Diagram._add_morphism_closure( premises, morphism, FiniteSet(*props) if iterable(props) else FiniteSet(props)) if len(args) >= 2: # We also have some conclusions. conclusions_arg = args[1] if isinstance(conclusions_arg, list): # The user has supplied a list of morphisms, none of # which have any attributes. empty = EmptySet for morphism in conclusions_arg: # Check that no new objects appear in conclusions. if ((sympify(objects.contains(morphism.domain)) is S.true) and (sympify(objects.contains(morphism.codomain)) is S.true)): # No need to add identities and recurse # composites this time. Diagram._add_morphism_closure( conclusions, morphism, empty, add_identities=False, recurse_composites=False) elif isinstance(conclusions_arg, dict) or \ isinstance(conclusions_arg, Dict): # The user has supplied a dictionary of morphisms and # their properties. for morphism, props in conclusions_arg.items(): # Check that no new objects appear in conclusions. if (morphism.domain in objects) and \ (morphism.codomain in objects): # No need to add identities and recurse # composites this time. Diagram._add_morphism_closure( conclusions, morphism, FiniteSet(*props) if iterable(props) else FiniteSet(props), add_identities=False, recurse_composites=False) return Basic.__new__(cls, Dict(premises), Dict(conclusions), objects) @property def premises(self): """ Returns the premises of this diagram. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import IdentityMorphism, Diagram >>> from sympy import pretty >>> A = Object("A") >>> B = Object("B") >>> f = NamedMorphism(A, B, "f") >>> id_A = IdentityMorphism(A) >>> id_B = IdentityMorphism(B) >>> d = Diagram([f]) >>> print(pretty(d.premises, use_unicode=False)) {id:A-->A: EmptySet, id:B-->B: EmptySet, f:A-->B: EmptySet} """ return self.args[0] @property def conclusions(self): """ Returns the conclusions of this diagram. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import IdentityMorphism, Diagram >>> from sympy import FiniteSet >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> IdentityMorphism(A) in d.premises.keys() True >>> g * f in d.premises.keys() True >>> d = Diagram([f, g], {g * f: "unique"}) >>> d.conclusions[g * f] == FiniteSet("unique") True """ return self.args[1] @property def objects(self): """ Returns the :class:`~.FiniteSet` of objects that appear in this diagram. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g]) >>> d.objects {Object("A"), Object("B"), Object("C")} """ return self.args[2] def hom(self, A, B): """ Returns a 2-tuple of sets of morphisms between objects ``A`` and ``B``: one set of morphisms listed as premises, and the other set of morphisms listed as conclusions. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy import pretty >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g], {g * f: "unique"}) >>> print(pretty(d.hom(A, C), use_unicode=False)) ({g*f:A-->C}, {g*f:A-->C}) See Also ======== Object, Morphism """ premises = EmptySet conclusions = EmptySet for morphism in self.premises.keys(): if (morphism.domain == A) and (morphism.codomain == B): premises |= FiniteSet(morphism) for morphism in self.conclusions.keys(): if (morphism.domain == A) and (morphism.codomain == B): conclusions |= FiniteSet(morphism) return (premises, conclusions) def is_subdiagram(self, diagram): """ Checks whether ``diagram`` is a subdiagram of ``self``. Diagram `D'` is a subdiagram of `D` if all premises (conclusions) of `D'` are contained in the premises (conclusions) of `D`. The morphisms contained both in `D'` and `D` should have the same properties for `D'` to be a subdiagram of `D`. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g], {g * f: "unique"}) >>> d1 = Diagram([f]) >>> d.is_subdiagram(d1) True >>> d1.is_subdiagram(d) False """ premises = all([(m in self.premises) and (diagram.premises[m] == self.premises[m]) for m in diagram.premises]) if not premises: return False conclusions = all([(m in self.conclusions) and (diagram.conclusions[m] == self.conclusions[m]) for m in diagram.conclusions]) # Premises is surely ``True`` here. return conclusions def subdiagram_from_objects(self, objects): """ If ``objects`` is a subset of the objects of ``self``, returns a diagram which has as premises all those premises of ``self`` which have a domains and codomains in ``objects``, likewise for conclusions. Properties are preserved. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy import FiniteSet >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g], {f: "unique", g*f: "veryunique"}) >>> d1 = d.subdiagram_from_objects(FiniteSet(A, B)) >>> d1 == Diagram([f], {f: "unique"}) True """ if not objects.is_subset(self.objects): raise ValueError( "Supplied objects should all belong to the diagram.") new_premises = {} for morphism, props in self.premises.items(): if ((sympify(objects.contains(morphism.domain)) is S.true) and (sympify(objects.contains(morphism.codomain)) is S.true)): new_premises[morphism] = props new_conclusions = {} for morphism, props in self.conclusions.items(): if ((sympify(objects.contains(morphism.domain)) is S.true) and (sympify(objects.contains(morphism.codomain)) is S.true)): new_conclusions[morphism] = props return Diagram(new_premises, new_conclusions) sympy-sympy-1.9/sympy/categories/diagram_drawing.py000066400000000000000000002724531412543434000227370ustar00rootroot00000000000000r""" This module contains the functionality to arrange the nodes of a diagram on an abstract grid, and then to produce a graphical representation of the grid. The currently supported back-ends are Xy-pic [Xypic]. Layout Algorithm ================ This section provides an overview of the algorithms implemented in :class:`DiagramGrid` to lay out diagrams. The first step of the algorithm is the removal composite and identity morphisms which do not have properties in the supplied diagram. The premises and conclusions of the diagram are then merged. The generic layout algorithm begins with the construction of the "skeleton" of the diagram. The skeleton is an undirected graph which has the objects of the diagram as vertices and has an (undirected) edge between each pair of objects between which there exist morphisms. The direction of the morphisms does not matter at this stage. The skeleton also includes an edge between each pair of vertices `A` and `C` such that there exists an object `B` which is connected via a morphism to `A`, and via a morphism to `C`. The skeleton constructed in this way has the property that every object is a vertex of a triangle formed by three edges of the skeleton. This property lies at the base of the generic layout algorithm. After the skeleton has been constructed, the algorithm lists all triangles which can be formed. Note that some triangles will not have all edges corresponding to morphisms which will actually be drawn. Triangles which have only one edge or less which will actually be drawn are immediately discarded. The list of triangles is sorted according to the number of edges which correspond to morphisms, then the triangle with the least number of such edges is selected. One of such edges is picked and the corresponding objects are placed horizontally, on a grid. This edge is recorded to be in the fringe. The algorithm then finds a "welding" of a triangle to the fringe. A welding is an edge in the fringe where a triangle could be attached. If the algorithm succeeds in finding such a welding, it adds to the grid that vertex of the triangle which was not yet included in any edge in the fringe and records the two new edges in the fringe. This process continues iteratively until all objects of the diagram has been placed or until no more weldings can be found. An edge is only removed from the fringe when a welding to this edge has been found, and there is no room around this edge to place another vertex. When no more weldings can be found, but there are still triangles left, the algorithm searches for a possibility of attaching one of the remaining triangles to the existing structure by a vertex. If such a possibility is found, the corresponding edge of the found triangle is placed in the found space and the iterative process of welding triangles restarts. When logical groups are supplied, each of these groups is laid out independently. Then a diagram is constructed in which groups are objects and any two logical groups between which there exist morphisms are connected via a morphism. This diagram is laid out. Finally, the grid which includes all objects of the initial diagram is constructed by replacing the cells which contain logical groups with the corresponding laid out grids, and by correspondingly expanding the rows and columns. The sequential layout algorithm begins by constructing the underlying undirected graph defined by the morphisms obtained after simplifying premises and conclusions and merging them (see above). The vertex with the minimal degree is then picked up and depth-first search is started from it. All objects which are located at distance `n` from the root in the depth-first search tree, are positioned in the `n`-th column of the resulting grid. The sequential layout will therefore attempt to lay the objects out along a line. References ========== [Xypic] http://xy-pic.sourceforge.net/ """ from sympy.categories import (CompositeMorphism, IdentityMorphism, NamedMorphism, Diagram) from sympy.core import Dict, Symbol from sympy.core.compatibility import iterable from sympy.printing import latex from sympy.sets import FiniteSet from sympy.utilities import default_sort_key from sympy.utilities.decorator import doctest_depends_on from itertools import chain __doctest_requires__ = {('preview_diagram',): 'pyglet'} class _GrowableGrid: """ Holds a growable grid of objects. Explanation =========== It is possible to append or prepend a row or a column to the grid using the corresponding methods. Prepending rows or columns has the effect of changing the coordinates of the already existing elements. This class currently represents a naive implementation of the functionality with little attempt at optimisation. """ def __init__(self, width, height): self._width = width self._height = height self._array = [[None for j in range(width)] for i in range(height)] @property def width(self): return self._width @property def height(self): return self._height def __getitem__(self, i_j): """ Returns the element located at in the i-th line and j-th column. """ i, j = i_j return self._array[i][j] def __setitem__(self, i_j, newvalue): """ Sets the element located at in the i-th line and j-th column. """ i, j = i_j self._array[i][j] = newvalue def append_row(self): """ Appends an empty row to the grid. """ self._height += 1 self._array.append([None for j in range(self._width)]) def append_column(self): """ Appends an empty column to the grid. """ self._width += 1 for i in range(self._height): self._array[i].append(None) def prepend_row(self): """ Prepends the grid with an empty row. """ self._height += 1 self._array.insert(0, [None for j in range(self._width)]) def prepend_column(self): """ Prepends the grid with an empty column. """ self._width += 1 for i in range(self._height): self._array[i].insert(0, None) class DiagramGrid: r""" Constructs and holds the fitting of the diagram into a grid. Explanation =========== The mission of this class is to analyse the structure of the supplied diagram and to place its objects on a grid such that, when the objects and the morphisms are actually drawn, the diagram would be "readable", in the sense that there will not be many intersections of moprhisms. This class does not perform any actual drawing. It does strive nevertheless to offer sufficient metadata to draw a diagram. Consider the following simple diagram. >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import Diagram, DiagramGrid >>> from sympy import pprint >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g]) The simplest way to have a diagram laid out is the following: >>> grid = DiagramGrid(diagram) >>> (grid.width, grid.height) (2, 2) >>> pprint(grid) A B C Sometimes one sees the diagram as consisting of logical groups. One can advise ``DiagramGrid`` as to such groups by employing the ``groups`` keyword argument. Consider the following diagram: >>> D = Object("D") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> h = NamedMorphism(D, A, "h") >>> k = NamedMorphism(D, B, "k") >>> diagram = Diagram([f, g, h, k]) Lay it out with generic layout: >>> grid = DiagramGrid(diagram) >>> pprint(grid) A B D C Now, we can group the objects `A` and `D` to have them near one another: >>> grid = DiagramGrid(diagram, groups=[[A, D], B, C]) >>> pprint(grid) B C A D Note how the positioning of the other objects changes. Further indications can be supplied to the constructor of :class:`DiagramGrid` using keyword arguments. The currently supported hints are explained in the following paragraphs. :class:`DiagramGrid` does not automatically guess which layout would suit the supplied diagram better. Consider, for example, the following linear diagram: >>> E = Object("E") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> h = NamedMorphism(C, D, "h") >>> i = NamedMorphism(D, E, "i") >>> diagram = Diagram([f, g, h, i]) When laid out with the generic layout, it does not get to look linear: >>> grid = DiagramGrid(diagram) >>> pprint(grid) A B C D E To get it laid out in a line, use ``layout="sequential"``: >>> grid = DiagramGrid(diagram, layout="sequential") >>> pprint(grid) A B C D E One may sometimes need to transpose the resulting layout. While this can always be done by hand, :class:`DiagramGrid` provides a hint for that purpose: >>> grid = DiagramGrid(diagram, layout="sequential", transpose=True) >>> pprint(grid) A B C D E Separate hints can also be provided for each group. For an example, refer to ``tests/test_drawing.py``, and see the different ways in which the five lemma [FiveLemma] can be laid out. See Also ======== Diagram References ========== .. [FiveLemma] https://en.wikipedia.org/wiki/Five_lemma """ @staticmethod def _simplify_morphisms(morphisms): """ Given a dictionary mapping morphisms to their properties, returns a new dictionary in which there are no morphisms which do not have properties, and which are compositions of other morphisms included in the dictionary. Identities are dropped as well. """ newmorphisms = {} for morphism, props in morphisms.items(): if isinstance(morphism, CompositeMorphism) and not props: continue elif isinstance(morphism, IdentityMorphism): continue else: newmorphisms[morphism] = props return newmorphisms @staticmethod def _merge_premises_conclusions(premises, conclusions): """ Given two dictionaries of morphisms and their properties, produces a single dictionary which includes elements from both dictionaries. If a morphism has some properties in premises and also in conclusions, the properties in conclusions take priority. """ return dict(chain(premises.items(), conclusions.items())) @staticmethod def _juxtapose_edges(edge1, edge2): """ If ``edge1`` and ``edge2`` have precisely one common endpoint, returns an edge which would form a triangle with ``edge1`` and ``edge2``. If ``edge1`` and ``edge2`` don't have a common endpoint, returns ``None``. If ``edge1`` and ``edge`` are the same edge, returns ``None``. """ intersection = edge1 & edge2 if len(intersection) != 1: # The edges either have no common points or are equal. return None # The edges have a common endpoint. Extract the different # endpoints and set up the new edge. return (edge1 - intersection) | (edge2 - intersection) @staticmethod def _add_edge_append(dictionary, edge, elem): """ If ``edge`` is not in ``dictionary``, adds ``edge`` to the dictionary and sets its value to ``[elem]``. Otherwise appends ``elem`` to the value of existing entry. Note that edges are undirected, thus `(A, B) = (B, A)`. """ if edge in dictionary: dictionary[edge].append(elem) else: dictionary[edge] = [elem] @staticmethod def _build_skeleton(morphisms): """ Creates a dictionary which maps edges to corresponding morphisms. Thus for a morphism `f:A\rightarrow B`, the edge `(A, B)` will be associated with `f`. This function also adds to the list those edges which are formed by juxtaposition of two edges already in the list. These new edges are not associated with any morphism and are only added to assure that the diagram can be decomposed into triangles. """ edges = {} # Create edges for morphisms. for morphism in morphisms: DiagramGrid._add_edge_append( edges, frozenset([morphism.domain, morphism.codomain]), morphism) # Create new edges by juxtaposing existing edges. edges1 = dict(edges) for w in edges1: for v in edges1: wv = DiagramGrid._juxtapose_edges(w, v) if wv and wv not in edges: edges[wv] = [] return edges @staticmethod def _list_triangles(edges): """ Builds the set of triangles formed by the supplied edges. The triangles are arbitrary and need not be commutative. A triangle is a set that contains all three of its sides. """ triangles = set() for w in edges: for v in edges: wv = DiagramGrid._juxtapose_edges(w, v) if wv and wv in edges: triangles.add(frozenset([w, v, wv])) return triangles @staticmethod def _drop_redundant_triangles(triangles, skeleton): """ Returns a list which contains only those triangles who have morphisms associated with at least two edges. """ return [tri for tri in triangles if len([e for e in tri if skeleton[e]]) >= 2] @staticmethod def _morphism_length(morphism): """ Returns the length of a morphism. The length of a morphism is the number of components it consists of. A non-composite morphism is of length 1. """ if isinstance(morphism, CompositeMorphism): return len(morphism.components) else: return 1 @staticmethod def _compute_triangle_min_sizes(triangles, edges): r""" Returns a dictionary mapping triangles to their minimal sizes. The minimal size of a triangle is the sum of maximal lengths of morphisms associated to the sides of the triangle. The length of a morphism is the number of components it consists of. A non-composite morphism is of length 1. Sorting triangles by this metric attempts to address two aspects of layout. For triangles with only simple morphisms in the edge, this assures that triangles with all three edges visible will get typeset after triangles with less visible edges, which sometimes minimizes the necessity in diagonal arrows. For triangles with composite morphisms in the edges, this assures that objects connected with shorter morphisms will be laid out first, resulting the visual proximity of those objects which are connected by shorter morphisms. """ triangle_sizes = {} for triangle in triangles: size = 0 for e in triangle: morphisms = edges[e] if morphisms: size += max(DiagramGrid._morphism_length(m) for m in morphisms) triangle_sizes[triangle] = size return triangle_sizes @staticmethod def _triangle_objects(triangle): """ Given a triangle, returns the objects included in it. """ # A triangle is a frozenset of three two-element frozensets # (the edges). This chains the three edges together and # creates a frozenset from the iterator, thus producing a # frozenset of objects of the triangle. return frozenset(chain(*tuple(triangle))) @staticmethod def _other_vertex(triangle, edge): """ Given a triangle and an edge of it, returns the vertex which opposes the edge. """ # This gets the set of objects of the triangle and then # subtracts the set of objects employed in ``edge`` to get the # vertex opposite to ``edge``. return list(DiagramGrid._triangle_objects(triangle) - set(edge))[0] @staticmethod def _empty_point(pt, grid): """ Checks if the cell at coordinates ``pt`` is either empty or out of the bounds of the grid. """ if (pt[0] < 0) or (pt[1] < 0) or \ (pt[0] >= grid.height) or (pt[1] >= grid.width): return True return grid[pt] is None @staticmethod def _put_object(coords, obj, grid, fringe): """ Places an object at the coordinate ``cords`` in ``grid``, growing the grid and updating ``fringe``, if necessary. Returns (0, 0) if no row or column has been prepended, (1, 0) if a row was prepended, (0, 1) if a column was prepended and (1, 1) if both a column and a row were prepended. """ (i, j) = coords offset = (0, 0) if i == -1: grid.prepend_row() i = 0 offset = (1, 0) for k in range(len(fringe)): ((i1, j1), (i2, j2)) = fringe[k] fringe[k] = ((i1 + 1, j1), (i2 + 1, j2)) elif i == grid.height: grid.append_row() if j == -1: j = 0 offset = (offset[0], 1) grid.prepend_column() for k in range(len(fringe)): ((i1, j1), (i2, j2)) = fringe[k] fringe[k] = ((i1, j1 + 1), (i2, j2 + 1)) elif j == grid.width: grid.append_column() grid[i, j] = obj return offset @staticmethod def _choose_target_cell(pt1, pt2, edge, obj, skeleton, grid): """ Given two points, ``pt1`` and ``pt2``, and the welding edge ``edge``, chooses one of the two points to place the opposing vertex ``obj`` of the triangle. If neither of this points fits, returns ``None``. """ pt1_empty = DiagramGrid._empty_point(pt1, grid) pt2_empty = DiagramGrid._empty_point(pt2, grid) if pt1_empty and pt2_empty: # Both cells are empty. Of these two, choose that cell # which will assure that a visible edge of the triangle # will be drawn perpendicularly to the current welding # edge. A = grid[edge[0]] if skeleton.get(frozenset([A, obj])): return pt1 else: return pt2 if pt1_empty: return pt1 elif pt2_empty: return pt2 else: return None @staticmethod def _find_triangle_to_weld(triangles, fringe, grid): """ Finds, if possible, a triangle and an edge in the ``fringe`` to which the triangle could be attached. Returns the tuple containing the triangle and the index of the corresponding edge in the ``fringe``. This function relies on the fact that objects are unique in the diagram. """ for triangle in triangles: for (a, b) in fringe: if frozenset([grid[a], grid[b]]) in triangle: return (triangle, (a, b)) return None @staticmethod def _weld_triangle(tri, welding_edge, fringe, grid, skeleton): """ If possible, welds the triangle ``tri`` to ``fringe`` and returns ``False``. If this method encounters a degenerate situation in the fringe and corrects it such that a restart of the search is required, it returns ``True`` (which means that a restart in finding triangle weldings is required). A degenerate situation is a situation when an edge listed in the fringe does not belong to the visual boundary of the diagram. """ a, b = welding_edge target_cell = None obj = DiagramGrid._other_vertex(tri, (grid[a], grid[b])) # We now have a triangle and an edge where it can be welded to # the fringe. Decide where to place the other vertex of the # triangle and check for degenerate situations en route. if (abs(a[0] - b[0]) == 1) and (abs(a[1] - b[1]) == 1): # A diagonal edge. target_cell = (a[0], b[1]) if grid[target_cell]: # That cell is already occupied. target_cell = (b[0], a[1]) if grid[target_cell]: # Degenerate situation, this edge is not # on the actual fringe. Correct the # fringe and go on. fringe.remove((a, b)) return True elif a[0] == b[0]: # A horizontal edge. We first attempt to build the # triangle in the downward direction. down_left = a[0] + 1, a[1] down_right = a[0] + 1, b[1] target_cell = DiagramGrid._choose_target_cell( down_left, down_right, (a, b), obj, skeleton, grid) if not target_cell: # No room below this edge. Check above. up_left = a[0] - 1, a[1] up_right = a[0] - 1, b[1] target_cell = DiagramGrid._choose_target_cell( up_left, up_right, (a, b), obj, skeleton, grid) if not target_cell: # This edge is not in the fringe, remove it # and restart. fringe.remove((a, b)) return True elif a[1] == b[1]: # A vertical edge. We will attempt to place the other # vertex of the triangle to the right of this edge. right_up = a[0], a[1] + 1 right_down = b[0], a[1] + 1 target_cell = DiagramGrid._choose_target_cell( right_up, right_down, (a, b), obj, skeleton, grid) if not target_cell: # No room to the left. See what's to the right. left_up = a[0], a[1] - 1 left_down = b[0], a[1] - 1 target_cell = DiagramGrid._choose_target_cell( left_up, left_down, (a, b), obj, skeleton, grid) if not target_cell: # This edge is not in the fringe, remove it # and restart. fringe.remove((a, b)) return True # We now know where to place the other vertex of the # triangle. offset = DiagramGrid._put_object(target_cell, obj, grid, fringe) # Take care of the displacement of coordinates if a row or # a column was prepended. target_cell = (target_cell[0] + offset[0], target_cell[1] + offset[1]) a = (a[0] + offset[0], a[1] + offset[1]) b = (b[0] + offset[0], b[1] + offset[1]) fringe.extend([(a, target_cell), (b, target_cell)]) # No restart is required. return False @staticmethod def _triangle_key(tri, triangle_sizes): """ Returns a key for the supplied triangle. It should be the same independently of the hash randomisation. """ objects = sorted( DiagramGrid._triangle_objects(tri), key=default_sort_key) return (triangle_sizes[tri], default_sort_key(objects)) @staticmethod def _pick_root_edge(tri, skeleton): """ For a given triangle always picks the same root edge. The root edge is the edge that will be placed first on the grid. """ candidates = [sorted(e, key=default_sort_key) for e in tri if skeleton[e]] sorted_candidates = sorted(candidates, key=default_sort_key) # Don't forget to assure the proper ordering of the vertices # in this edge. return tuple(sorted(sorted_candidates[0], key=default_sort_key)) @staticmethod def _drop_irrelevant_triangles(triangles, placed_objects): """ Returns only those triangles whose set of objects is not completely included in ``placed_objects``. """ return [tri for tri in triangles if not placed_objects.issuperset( DiagramGrid._triangle_objects(tri))] @staticmethod def _grow_pseudopod(triangles, fringe, grid, skeleton, placed_objects): """ Starting from an object in the existing structure on the ``grid``, adds an edge to which a triangle from ``triangles`` could be welded. If this method has found a way to do so, it returns the object it has just added. This method should be applied when ``_weld_triangle`` cannot find weldings any more. """ for i in range(grid.height): for j in range(grid.width): obj = grid[i, j] if not obj: continue # Here we need to choose a triangle which has only # ``obj`` in common with the existing structure. The # situations when this is not possible should be # handled elsewhere. def good_triangle(tri): objs = DiagramGrid._triangle_objects(tri) return obj in objs and \ placed_objects & (objs - {obj}) == set() tris = [tri for tri in triangles if good_triangle(tri)] if not tris: # This object is not interesting. continue # Pick the "simplest" of the triangles which could be # attached. Remember that the list of triangles is # sorted according to their "simplicity" (see # _compute_triangle_min_sizes for the metric). # # Note that ``tris`` are sequentially built from # ``triangles``, so we don't have to worry about hash # randomisation. tri = tris[0] # We have found a triangle which could be attached to # the existing structure by a vertex. candidates = sorted([e for e in tri if skeleton[e]], key=lambda e: FiniteSet(*e).sort_key()) edges = [e for e in candidates if obj in e] # Note that a meaningful edge (i.e., and edge that is # associated with a morphism) containing ``obj`` # always exists. That's because all triangles are # guaranteed to have at least two meaningful edges. # See _drop_redundant_triangles. # Get the object at the other end of the edge. edge = edges[0] other_obj = tuple(edge - frozenset([obj]))[0] # Now check for free directions. When checking for # free directions, prefer the horizontal and vertical # directions. neighbours = [(i - 1, j), (i, j + 1), (i + 1, j), (i, j - 1), (i - 1, j - 1), (i - 1, j + 1), (i + 1, j - 1), (i + 1, j + 1)] for pt in neighbours: if DiagramGrid._empty_point(pt, grid): # We have a found a place to grow the # pseudopod into. offset = DiagramGrid._put_object( pt, other_obj, grid, fringe) i += offset[0] j += offset[1] pt = (pt[0] + offset[0], pt[1] + offset[1]) fringe.append(((i, j), pt)) return other_obj # This diagram is actually cooler that I can handle. Fail cowardly. return None @staticmethod def _handle_groups(diagram, groups, merged_morphisms, hints): """ Given the slightly preprocessed morphisms of the diagram, produces a grid laid out according to ``groups``. If a group has hints, it is laid out with those hints only, without any influence from ``hints``. Otherwise, it is laid out with ``hints``. """ def lay_out_group(group, local_hints): """ If ``group`` is a set of objects, uses a ``DiagramGrid`` to lay it out and returns the grid. Otherwise returns the object (i.e., ``group``). If ``local_hints`` is not empty, it is supplied to ``DiagramGrid`` as the dictionary of hints. Otherwise, the ``hints`` argument of ``_handle_groups`` is used. """ if isinstance(group, FiniteSet): # Set up the corresponding object-to-group # mappings. for obj in group: obj_groups[obj] = group # Lay out the current group. if local_hints: groups_grids[group] = DiagramGrid( diagram.subdiagram_from_objects(group), **local_hints) else: groups_grids[group] = DiagramGrid( diagram.subdiagram_from_objects(group), **hints) else: obj_groups[group] = group def group_to_finiteset(group): """ Converts ``group`` to a :class:``FiniteSet`` if it is an iterable. """ if iterable(group): return FiniteSet(*group) else: return group obj_groups = {} groups_grids = {} # We would like to support various containers to represent # groups. To achieve that, before laying each group out, it # should be converted to a FiniteSet, because that is what the # following code expects. if isinstance(groups, dict) or isinstance(groups, Dict): finiteset_groups = {} for group, local_hints in groups.items(): finiteset_group = group_to_finiteset(group) finiteset_groups[finiteset_group] = local_hints lay_out_group(group, local_hints) groups = finiteset_groups else: finiteset_groups = [] for group in groups: finiteset_group = group_to_finiteset(group) finiteset_groups.append(finiteset_group) lay_out_group(finiteset_group, None) groups = finiteset_groups new_morphisms = [] for morphism in merged_morphisms: dom = obj_groups[morphism.domain] cod = obj_groups[morphism.codomain] # Note that we are not really interested in morphisms # which do not employ two different groups, because # these do not influence the layout. if dom != cod: # These are essentially unnamed morphisms; they are # not going to mess in the final layout. By giving # them the same names, we avoid unnecessary # duplicates. new_morphisms.append(NamedMorphism(dom, cod, "dummy")) # Lay out the new diagram. Since these are dummy morphisms, # properties and conclusions are irrelevant. top_grid = DiagramGrid(Diagram(new_morphisms)) # We now have to substitute the groups with the corresponding # grids, laid out at the beginning of this function. Compute # the size of each row and column in the grid, so that all # nested grids fit. def group_size(group): """ For the supplied group (or object, eventually), returns the size of the cell that will hold this group (object). """ if group in groups_grids: grid = groups_grids[group] return (grid.height, grid.width) else: return (1, 1) row_heights = [max(group_size(top_grid[i, j])[0] for j in range(top_grid.width)) for i in range(top_grid.height)] column_widths = [max(group_size(top_grid[i, j])[1] for i in range(top_grid.height)) for j in range(top_grid.width)] grid = _GrowableGrid(sum(column_widths), sum(row_heights)) real_row = 0 real_column = 0 for logical_row in range(top_grid.height): for logical_column in range(top_grid.width): obj = top_grid[logical_row, logical_column] if obj in groups_grids: # This is a group. Copy the corresponding grid in # place. local_grid = groups_grids[obj] for i in range(local_grid.height): for j in range(local_grid.width): grid[real_row + i, real_column + j] = local_grid[i, j] else: # This is an object. Just put it there. grid[real_row, real_column] = obj real_column += column_widths[logical_column] real_column = 0 real_row += row_heights[logical_row] return grid @staticmethod def _generic_layout(diagram, merged_morphisms): """ Produces the generic layout for the supplied diagram. """ all_objects = set(diagram.objects) if len(all_objects) == 1: # There only one object in the diagram, just put in on 1x1 # grid. grid = _GrowableGrid(1, 1) grid[0, 0] = tuple(all_objects)[0] return grid skeleton = DiagramGrid._build_skeleton(merged_morphisms) grid = _GrowableGrid(2, 1) if len(skeleton) == 1: # This diagram contains only one morphism. Draw it # horizontally. objects = sorted(all_objects, key=default_sort_key) grid[0, 0] = objects[0] grid[0, 1] = objects[1] return grid triangles = DiagramGrid._list_triangles(skeleton) triangles = DiagramGrid._drop_redundant_triangles(triangles, skeleton) triangle_sizes = DiagramGrid._compute_triangle_min_sizes( triangles, skeleton) triangles = sorted(triangles, key=lambda tri: DiagramGrid._triangle_key(tri, triangle_sizes)) # Place the first edge on the grid. root_edge = DiagramGrid._pick_root_edge(triangles[0], skeleton) grid[0, 0], grid[0, 1] = root_edge fringe = [((0, 0), (0, 1))] # Record which objects we now have on the grid. placed_objects = set(root_edge) while placed_objects != all_objects: welding = DiagramGrid._find_triangle_to_weld( triangles, fringe, grid) if welding: (triangle, welding_edge) = welding restart_required = DiagramGrid._weld_triangle( triangle, welding_edge, fringe, grid, skeleton) if restart_required: continue placed_objects.update( DiagramGrid._triangle_objects(triangle)) else: # No more weldings found. Try to attach triangles by # vertices. new_obj = DiagramGrid._grow_pseudopod( triangles, fringe, grid, skeleton, placed_objects) if not new_obj: # No more triangles can be attached, not even by # the edge. We will set up a new diagram out of # what has been left, laid it out independently, # and then attach it to this one. remaining_objects = all_objects - placed_objects remaining_diagram = diagram.subdiagram_from_objects( FiniteSet(*remaining_objects)) remaining_grid = DiagramGrid(remaining_diagram) # Now, let's glue ``remaining_grid`` to ``grid``. final_width = grid.width + remaining_grid.width final_height = max(grid.height, remaining_grid.height) final_grid = _GrowableGrid(final_width, final_height) for i in range(grid.width): for j in range(grid.height): final_grid[i, j] = grid[i, j] start_j = grid.width for i in range(remaining_grid.height): for j in range(remaining_grid.width): final_grid[i, start_j + j] = remaining_grid[i, j] return final_grid placed_objects.add(new_obj) triangles = DiagramGrid._drop_irrelevant_triangles( triangles, placed_objects) return grid @staticmethod def _get_undirected_graph(objects, merged_morphisms): """ Given the objects and the relevant morphisms of a diagram, returns the adjacency lists of the underlying undirected graph. """ adjlists = {} for obj in objects: adjlists[obj] = [] for morphism in merged_morphisms: adjlists[morphism.domain].append(morphism.codomain) adjlists[morphism.codomain].append(morphism.domain) # Assure that the objects in the adjacency list are always in # the same order. for obj in adjlists.keys(): adjlists[obj].sort(key=default_sort_key) return adjlists @staticmethod def _sequential_layout(diagram, merged_morphisms): r""" Lays out the diagram in "sequential" layout. This method will attempt to produce a result as close to a line as possible. For linear diagrams, the result will actually be a line. """ objects = diagram.objects sorted_objects = sorted(objects, key=default_sort_key) # Set up the adjacency lists of the underlying undirected # graph of ``merged_morphisms``. adjlists = DiagramGrid._get_undirected_graph(objects, merged_morphisms) # Find an object with the minimal degree. This is going to be # the root. root = sorted_objects[0] mindegree = len(adjlists[root]) for obj in sorted_objects: current_degree = len(adjlists[obj]) if current_degree < mindegree: root = obj mindegree = current_degree grid = _GrowableGrid(1, 1) grid[0, 0] = root placed_objects = {root} def place_objects(pt, placed_objects): """ Does depth-first search in the underlying graph of the diagram and places the objects en route. """ # We will start placing new objects from here. new_pt = (pt[0], pt[1] + 1) for adjacent_obj in adjlists[grid[pt]]: if adjacent_obj in placed_objects: # This object has already been placed. continue DiagramGrid._put_object(new_pt, adjacent_obj, grid, []) placed_objects.add(adjacent_obj) placed_objects.update(place_objects(new_pt, placed_objects)) new_pt = (new_pt[0] + 1, new_pt[1]) return placed_objects place_objects((0, 0), placed_objects) return grid @staticmethod def _drop_inessential_morphisms(merged_morphisms): r""" Removes those morphisms which should appear in the diagram, but which have no relevance to object layout. Currently this removes "loop" morphisms: the non-identity morphisms with the same domains and codomains. """ morphisms = [m for m in merged_morphisms if m.domain != m.codomain] return morphisms @staticmethod def _get_connected_components(objects, merged_morphisms): """ Given a container of morphisms, returns a list of connected components formed by these morphisms. A connected component is represented by a diagram consisting of the corresponding morphisms. """ component_index = {} for o in objects: component_index[o] = None # Get the underlying undirected graph of the diagram. adjlist = DiagramGrid._get_undirected_graph(objects, merged_morphisms) def traverse_component(object, current_index): """ Does a depth-first search traversal of the component containing ``object``. """ component_index[object] = current_index for o in adjlist[object]: if component_index[o] is None: traverse_component(o, current_index) # Traverse all components. current_index = 0 for o in adjlist: if component_index[o] is None: traverse_component(o, current_index) current_index += 1 # List the objects of the components. component_objects = [[] for i in range(current_index)] for o, idx in component_index.items(): component_objects[idx].append(o) # Finally, list the morphisms belonging to each component. # # Note: If some objects are isolated, they will not get any # morphisms at this stage, and since the layout algorithm # relies, we are essentially going to lose this object. # Therefore, check if there are isolated objects and, for each # of them, provide the trivial identity morphism. It will get # discarded later, but the object will be there. component_morphisms = [] for component in component_objects: current_morphisms = {} for m in merged_morphisms: if (m.domain in component) and (m.codomain in component): current_morphisms[m] = merged_morphisms[m] if len(component) == 1: # Let's add an identity morphism, for the sake of # surely having morphisms in this component. current_morphisms[IdentityMorphism(component[0])] = FiniteSet() component_morphisms.append(Diagram(current_morphisms)) return component_morphisms def __init__(self, diagram, groups=None, **hints): premises = DiagramGrid._simplify_morphisms(diagram.premises) conclusions = DiagramGrid._simplify_morphisms(diagram.conclusions) all_merged_morphisms = DiagramGrid._merge_premises_conclusions( premises, conclusions) merged_morphisms = DiagramGrid._drop_inessential_morphisms( all_merged_morphisms) # Store the merged morphisms for later use. self._morphisms = all_merged_morphisms components = DiagramGrid._get_connected_components( diagram.objects, all_merged_morphisms) if groups and (groups != diagram.objects): # Lay out the diagram according to the groups. self._grid = DiagramGrid._handle_groups( diagram, groups, merged_morphisms, hints) elif len(components) > 1: # Note that we check for connectedness _before_ checking # the layout hints because the layout strategies don't # know how to deal with disconnected diagrams. # The diagram is disconnected. Lay out the components # independently. grids = [] # Sort the components to eventually get the grids arranged # in a fixed, hash-independent order. components = sorted(components, key=default_sort_key) for component in components: grid = DiagramGrid(component, **hints) grids.append(grid) # Throw the grids together, in a line. total_width = sum(g.width for g in grids) total_height = max(g.height for g in grids) grid = _GrowableGrid(total_width, total_height) start_j = 0 for g in grids: for i in range(g.height): for j in range(g.width): grid[i, start_j + j] = g[i, j] start_j += g.width self._grid = grid elif "layout" in hints: if hints["layout"] == "sequential": self._grid = DiagramGrid._sequential_layout( diagram, merged_morphisms) else: self._grid = DiagramGrid._generic_layout(diagram, merged_morphisms) if hints.get("transpose"): # Transpose the resulting grid. grid = _GrowableGrid(self._grid.height, self._grid.width) for i in range(self._grid.height): for j in range(self._grid.width): grid[j, i] = self._grid[i, j] self._grid = grid @property def width(self): """ Returns the number of columns in this diagram layout. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import Diagram, DiagramGrid >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g]) >>> grid = DiagramGrid(diagram) >>> grid.width 2 """ return self._grid.width @property def height(self): """ Returns the number of rows in this diagram layout. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import Diagram, DiagramGrid >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g]) >>> grid = DiagramGrid(diagram) >>> grid.height 2 """ return self._grid.height def __getitem__(self, i_j): """ Returns the object placed in the row ``i`` and column ``j``. The indices are 0-based. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import Diagram, DiagramGrid >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g]) >>> grid = DiagramGrid(diagram) >>> (grid[0, 0], grid[0, 1]) (Object("A"), Object("B")) >>> (grid[1, 0], grid[1, 1]) (None, Object("C")) """ i, j = i_j return self._grid[i, j] @property def morphisms(self): """ Returns those morphisms (and their properties) which are sufficiently meaningful to be drawn. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import Diagram, DiagramGrid >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g]) >>> grid = DiagramGrid(diagram) >>> grid.morphisms {NamedMorphism(Object("A"), Object("B"), "f"): EmptySet, NamedMorphism(Object("B"), Object("C"), "g"): EmptySet} """ return self._morphisms def __str__(self): """ Produces a string representation of this class. This method returns a string representation of the underlying list of lists of objects. Examples ======== >>> from sympy.categories import Object, NamedMorphism >>> from sympy.categories import Diagram, DiagramGrid >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g]) >>> grid = DiagramGrid(diagram) >>> print(grid) [[Object("A"), Object("B")], [None, Object("C")]] """ return repr(self._grid._array) class ArrowStringDescription: r""" Stores the information necessary for producing an Xy-pic description of an arrow. The principal goal of this class is to abstract away the string representation of an arrow and to also provide the functionality to produce the actual Xy-pic string. ``unit`` sets the unit which will be used to specify the amount of curving and other distances. ``horizontal_direction`` should be a string of ``"r"`` or ``"l"`` specifying the horizontal offset of the target cell of the arrow relatively to the current one. ``vertical_direction`` should specify the vertical offset using a series of either ``"d"`` or ``"u"``. ``label_position`` should be either ``"^"``, ``"_"``, or ``"|"`` to specify that the label should be positioned above the arrow, below the arrow or just over the arrow, in a break. Note that the notions "above" and "below" are relative to arrow direction. ``label`` stores the morphism label. This works as follows (disregard the yet unexplained arguments): >>> from sympy.categories.diagram_drawing import ArrowStringDescription >>> astr = ArrowStringDescription( ... unit="mm", curving=None, curving_amount=None, ... looping_start=None, looping_end=None, horizontal_direction="d", ... vertical_direction="r", label_position="_", label="f") >>> print(str(astr)) \ar[dr]_{f} ``curving`` should be one of ``"^"``, ``"_"`` to specify in which direction the arrow is going to curve. ``curving_amount`` is a number describing how many ``unit``'s the morphism is going to curve: >>> astr = ArrowStringDescription( ... unit="mm", curving="^", curving_amount=12, ... looping_start=None, looping_end=None, horizontal_direction="d", ... vertical_direction="r", label_position="_", label="f") >>> print(str(astr)) \ar@/^12mm/[dr]_{f} ``looping_start`` and ``looping_end`` are currently only used for loop morphisms, those which have the same domain and codomain. These two attributes should store a valid Xy-pic direction and specify, correspondingly, the direction the arrow gets out into and the direction the arrow gets back from: >>> astr = ArrowStringDescription( ... unit="mm", curving=None, curving_amount=None, ... looping_start="u", looping_end="l", horizontal_direction="", ... vertical_direction="", label_position="_", label="f") >>> print(str(astr)) \ar@(u,l)[]_{f} ``label_displacement`` controls how far the arrow label is from the ends of the arrow. For example, to position the arrow label near the arrow head, use ">": >>> astr = ArrowStringDescription( ... unit="mm", curving="^", curving_amount=12, ... looping_start=None, looping_end=None, horizontal_direction="d", ... vertical_direction="r", label_position="_", label="f") >>> astr.label_displacement = ">" >>> print(str(astr)) \ar@/^12mm/[dr]_>{f} Finally, ``arrow_style`` is used to specify the arrow style. To get a dashed arrow, for example, use "{-->}" as arrow style: >>> astr = ArrowStringDescription( ... unit="mm", curving="^", curving_amount=12, ... looping_start=None, looping_end=None, horizontal_direction="d", ... vertical_direction="r", label_position="_", label="f") >>> astr.arrow_style = "{-->}" >>> print(str(astr)) \ar@/^12mm/@{-->}[dr]_{f} Notes ===== Instances of :class:`ArrowStringDescription` will be constructed by :class:`XypicDiagramDrawer` and provided for further use in formatters. The user is not expected to construct instances of :class:`ArrowStringDescription` themselves. To be able to properly utilise this class, the reader is encouraged to checkout the Xy-pic user guide, available at [Xypic]. See Also ======== XypicDiagramDrawer References ========== [Xypic] http://xy-pic.sourceforge.net/ """ def __init__(self, unit, curving, curving_amount, looping_start, looping_end, horizontal_direction, vertical_direction, label_position, label): self.unit = unit self.curving = curving self.curving_amount = curving_amount self.looping_start = looping_start self.looping_end = looping_end self.horizontal_direction = horizontal_direction self.vertical_direction = vertical_direction self.label_position = label_position self.label = label self.label_displacement = "" self.arrow_style = "" # This flag shows that the position of the label of this # morphism was set while typesetting a curved morphism and # should not be modified later. self.forced_label_position = False def __str__(self): if self.curving: curving_str = "@/%s%d%s/" % (self.curving, self.curving_amount, self.unit) else: curving_str = "" if self.looping_start and self.looping_end: looping_str = "@(%s,%s)" % (self.looping_start, self.looping_end) else: looping_str = "" if self.arrow_style: style_str = "@" + self.arrow_style else: style_str = "" return "\\ar%s%s%s[%s%s]%s%s{%s}" % \ (curving_str, looping_str, style_str, self.horizontal_direction, self.vertical_direction, self.label_position, self.label_displacement, self.label) class XypicDiagramDrawer: r""" Given a :class:`~.Diagram` and the corresponding :class:`DiagramGrid`, produces the Xy-pic representation of the diagram. The most important method in this class is ``draw``. Consider the following triangle diagram: >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy.categories import DiagramGrid, XypicDiagramDrawer >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g], {g * f: "unique"}) To draw this diagram, its objects need to be laid out with a :class:`DiagramGrid`:: >>> grid = DiagramGrid(diagram) Finally, the drawing: >>> drawer = XypicDiagramDrawer() >>> print(drawer.draw(diagram, grid)) \xymatrix{ A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ C & } For further details see the docstring of this method. To control the appearance of the arrows, formatters are used. The dictionary ``arrow_formatters`` maps morphisms to formatter functions. A formatter is accepts an :class:`ArrowStringDescription` and is allowed to modify any of the arrow properties exposed thereby. For example, to have all morphisms with the property ``unique`` appear as dashed arrows, and to have their names prepended with `\exists !`, the following should be done: >>> def formatter(astr): ... astr.label = r"\exists !" + astr.label ... astr.arrow_style = "{-->}" >>> drawer.arrow_formatters["unique"] = formatter >>> print(drawer.draw(diagram, grid)) \xymatrix{ A \ar@{-->}[d]_{\exists !g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ C & } To modify the appearance of all arrows in the diagram, set ``default_arrow_formatter``. For example, to place all morphism labels a little bit farther from the arrow head so that they look more centred, do as follows: >>> def default_formatter(astr): ... astr.label_displacement = "(0.45)" >>> drawer.default_arrow_formatter = default_formatter >>> print(drawer.draw(diagram, grid)) \xymatrix{ A \ar@{-->}[d]_(0.45){\exists !g\circ f} \ar[r]^(0.45){f} & B \ar[ld]^(0.45){g} \\ C & } In some diagrams some morphisms are drawn as curved arrows. Consider the following diagram: >>> D = Object("D") >>> E = Object("E") >>> h = NamedMorphism(D, A, "h") >>> k = NamedMorphism(D, B, "k") >>> diagram = Diagram([f, g, h, k]) >>> grid = DiagramGrid(diagram) >>> drawer = XypicDiagramDrawer() >>> print(drawer.draw(diagram, grid)) \xymatrix{ A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_3mm/[ll]_{h} \\ & C & } To control how far the morphisms are curved by default, one can use the ``unit`` and ``default_curving_amount`` attributes: >>> drawer.unit = "cm" >>> drawer.default_curving_amount = 1 >>> print(drawer.draw(diagram, grid)) \xymatrix{ A \ar[r]_{f} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_1cm/[ll]_{h} \\ & C & } In some diagrams, there are multiple curved morphisms between the same two objects. To control by how much the curving changes between two such successive morphisms, use ``default_curving_step``: >>> drawer.default_curving_step = 1 >>> h1 = NamedMorphism(A, D, "h1") >>> diagram = Diagram([f, g, h, k, h1]) >>> grid = DiagramGrid(diagram) >>> print(drawer.draw(diagram, grid)) \xymatrix{ A \ar[r]_{f} \ar@/^1cm/[rr]^{h_{1}} & B \ar[d]^{g} & D \ar[l]^{k} \ar@/_2cm/[ll]_{h} \\ & C & } The default value of ``default_curving_step`` is 4 units. See Also ======== draw, ArrowStringDescription """ def __init__(self): self.unit = "mm" self.default_curving_amount = 3 self.default_curving_step = 4 # This dictionary maps properties to the corresponding arrow # formatters. self.arrow_formatters = {} # This is the default arrow formatter which will be applied to # each arrow independently of its properties. self.default_arrow_formatter = None @staticmethod def _process_loop_morphism(i, j, grid, morphisms_str_info, object_coords): """ Produces the information required for constructing the string representation of a loop morphism. This function is invoked from ``_process_morphism``. See Also ======== _process_morphism """ curving = "" label_pos = "^" looping_start = "" looping_end = "" # This is a loop morphism. Count how many morphisms stick # in each of the four quadrants. Note that straight # vertical and horizontal morphisms count in two quadrants # at the same time (i.e., a morphism going up counts both # in the first and the second quadrants). # The usual numbering (counterclockwise) of quadrants # applies. quadrant = [0, 0, 0, 0] obj = grid[i, j] for m, m_str_info in morphisms_str_info.items(): if (m.domain == obj) and (m.codomain == obj): # That's another loop morphism. Check how it # loops and mark the corresponding quadrants as # busy. (l_s, l_e) = (m_str_info.looping_start, m_str_info.looping_end) if (l_s, l_e) == ("r", "u"): quadrant[0] += 1 elif (l_s, l_e) == ("u", "l"): quadrant[1] += 1 elif (l_s, l_e) == ("l", "d"): quadrant[2] += 1 elif (l_s, l_e) == ("d", "r"): quadrant[3] += 1 continue if m.domain == obj: (end_i, end_j) = object_coords[m.codomain] goes_out = True elif m.codomain == obj: (end_i, end_j) = object_coords[m.domain] goes_out = False else: continue d_i = end_i - i d_j = end_j - j m_curving = m_str_info.curving if (d_i != 0) and (d_j != 0): # This is really a diagonal morphism. Detect the # quadrant. if (d_i > 0) and (d_j > 0): quadrant[0] += 1 elif (d_i > 0) and (d_j < 0): quadrant[1] += 1 elif (d_i < 0) and (d_j < 0): quadrant[2] += 1 elif (d_i < 0) and (d_j > 0): quadrant[3] += 1 elif d_i == 0: # Knowing where the other end of the morphism is # and which way it goes, we now have to decide # which quadrant is now the upper one and which is # the lower one. if d_j > 0: if goes_out: upper_quadrant = 0 lower_quadrant = 3 else: upper_quadrant = 3 lower_quadrant = 0 else: if goes_out: upper_quadrant = 2 lower_quadrant = 1 else: upper_quadrant = 1 lower_quadrant = 2 if m_curving: if m_curving == "^": quadrant[upper_quadrant] += 1 elif m_curving == "_": quadrant[lower_quadrant] += 1 else: # This morphism counts in both upper and lower # quadrants. quadrant[upper_quadrant] += 1 quadrant[lower_quadrant] += 1 elif d_j == 0: # Knowing where the other end of the morphism is # and which way it goes, we now have to decide # which quadrant is now the left one and which is # the right one. if d_i < 0: if goes_out: left_quadrant = 1 right_quadrant = 0 else: left_quadrant = 0 right_quadrant = 1 else: if goes_out: left_quadrant = 3 right_quadrant = 2 else: left_quadrant = 2 right_quadrant = 3 if m_curving: if m_curving == "^": quadrant[left_quadrant] += 1 elif m_curving == "_": quadrant[right_quadrant] += 1 else: # This morphism counts in both upper and lower # quadrants. quadrant[left_quadrant] += 1 quadrant[right_quadrant] += 1 # Pick the freest quadrant to curve our morphism into. freest_quadrant = 0 for i in range(4): if quadrant[i] < quadrant[freest_quadrant]: freest_quadrant = i # Now set up proper looping. (looping_start, looping_end) = [("r", "u"), ("u", "l"), ("l", "d"), ("d", "r")][freest_quadrant] return (curving, label_pos, looping_start, looping_end) @staticmethod def _process_horizontal_morphism(i, j, target_j, grid, morphisms_str_info, object_coords): """ Produces the information required for constructing the string representation of a horizontal morphism. This function is invoked from ``_process_morphism``. See Also ======== _process_morphism """ # The arrow is horizontal. Check if it goes from left to # right (``backwards == False``) or from right to left # (``backwards == True``). backwards = False start = j end = target_j if end < start: (start, end) = (end, start) backwards = True # Let's see which objects are there between ``start`` and # ``end``, and then count how many morphisms stick out # upwards, and how many stick out downwards. # # For example, consider the situation: # # B1 C1 # | | # A--B--C--D # | # B2 # # Between the objects `A` and `D` there are two objects: # `B` and `C`. Further, there are two morphisms which # stick out upward (the ones between `B1` and `B` and # between `C` and `C1`) and one morphism which sticks out # downward (the one between `B and `B2`). # # We need this information to decide how to curve the # arrow between `A` and `D`. First of all, since there # are two objects between `A` and `D``, we must curve the # arrow. Then, we will have it curve downward, because # there is more space (less morphisms stick out downward # than upward). up = [] down = [] straight_horizontal = [] for k in range(start + 1, end): obj = grid[i, k] if not obj: continue for m in morphisms_str_info: if m.domain == obj: (end_i, end_j) = object_coords[m.codomain] elif m.codomain == obj: (end_i, end_j) = object_coords[m.domain] else: continue if end_i > i: down.append(m) elif end_i < i: up.append(m) elif not morphisms_str_info[m].curving: # This is a straight horizontal morphism, # because it has no curving. straight_horizontal.append(m) if len(up) < len(down): # More morphisms stick out downward than upward, let's # curve the morphism up. if backwards: curving = "_" label_pos = "_" else: curving = "^" label_pos = "^" # Assure that the straight horizontal morphisms have # their labels on the lower side of the arrow. for m in straight_horizontal: (i1, j1) = object_coords[m.domain] (i2, j2) = object_coords[m.codomain] m_str_info = morphisms_str_info[m] if j1 < j2: m_str_info.label_position = "_" else: m_str_info.label_position = "^" # Don't allow any further modifications of the # position of this label. m_str_info.forced_label_position = True else: # More morphisms stick out downward than upward, let's # curve the morphism up. if backwards: curving = "^" label_pos = "^" else: curving = "_" label_pos = "_" # Assure that the straight horizontal morphisms have # their labels on the upper side of the arrow. for m in straight_horizontal: (i1, j1) = object_coords[m.domain] (i2, j2) = object_coords[m.codomain] m_str_info = morphisms_str_info[m] if j1 < j2: m_str_info.label_position = "^" else: m_str_info.label_position = "_" # Don't allow any further modifications of the # position of this label. m_str_info.forced_label_position = True return (curving, label_pos) @staticmethod def _process_vertical_morphism(i, j, target_i, grid, morphisms_str_info, object_coords): """ Produces the information required for constructing the string representation of a vertical morphism. This function is invoked from ``_process_morphism``. See Also ======== _process_morphism """ # This arrow is vertical. Check if it goes from top to # bottom (``backwards == False``) or from bottom to top # (``backwards == True``). backwards = False start = i end = target_i if end < start: (start, end) = (end, start) backwards = True # Let's see which objects are there between ``start`` and # ``end``, and then count how many morphisms stick out to # the left, and how many stick out to the right. # # See the corresponding comment in the previous branch of # this if-statement for more details. left = [] right = [] straight_vertical = [] for k in range(start + 1, end): obj = grid[k, j] if not obj: continue for m in morphisms_str_info: if m.domain == obj: (end_i, end_j) = object_coords[m.codomain] elif m.codomain == obj: (end_i, end_j) = object_coords[m.domain] else: continue if end_j > j: right.append(m) elif end_j < j: left.append(m) elif not morphisms_str_info[m].curving: # This is a straight vertical morphism, # because it has no curving. straight_vertical.append(m) if len(left) < len(right): # More morphisms stick out to the left than to the # right, let's curve the morphism to the right. if backwards: curving = "^" label_pos = "^" else: curving = "_" label_pos = "_" # Assure that the straight vertical morphisms have # their labels on the left side of the arrow. for m in straight_vertical: (i1, j1) = object_coords[m.domain] (i2, j2) = object_coords[m.codomain] m_str_info = morphisms_str_info[m] if i1 < i2: m_str_info.label_position = "^" else: m_str_info.label_position = "_" # Don't allow any further modifications of the # position of this label. m_str_info.forced_label_position = True else: # More morphisms stick out to the right than to the # left, let's curve the morphism to the left. if backwards: curving = "_" label_pos = "_" else: curving = "^" label_pos = "^" # Assure that the straight vertical morphisms have # their labels on the right side of the arrow. for m in straight_vertical: (i1, j1) = object_coords[m.domain] (i2, j2) = object_coords[m.codomain] m_str_info = morphisms_str_info[m] if i1 < i2: m_str_info.label_position = "_" else: m_str_info.label_position = "^" # Don't allow any further modifications of the # position of this label. m_str_info.forced_label_position = True return (curving, label_pos) def _process_morphism(self, diagram, grid, morphism, object_coords, morphisms, morphisms_str_info): """ Given the required information, produces the string representation of ``morphism``. """ def repeat_string_cond(times, str_gt, str_lt): """ If ``times > 0``, repeats ``str_gt`` ``times`` times. Otherwise, repeats ``str_lt`` ``-times`` times. """ if times > 0: return str_gt * times else: return str_lt * (-times) def count_morphisms_undirected(A, B): """ Counts how many processed morphisms there are between the two supplied objects. """ return len([m for m in morphisms_str_info if {m.domain, m.codomain} == {A, B}]) def count_morphisms_filtered(dom, cod, curving): """ Counts the processed morphisms which go out of ``dom`` into ``cod`` with curving ``curving``. """ return len([m for m, m_str_info in morphisms_str_info.items() if (m.domain, m.codomain) == (dom, cod) and (m_str_info.curving == curving)]) (i, j) = object_coords[morphism.domain] (target_i, target_j) = object_coords[morphism.codomain] # We now need to determine the direction of # the arrow. delta_i = target_i - i delta_j = target_j - j vertical_direction = repeat_string_cond(delta_i, "d", "u") horizontal_direction = repeat_string_cond(delta_j, "r", "l") curving = "" label_pos = "^" looping_start = "" looping_end = "" if (delta_i == 0) and (delta_j == 0): # This is a loop morphism. (curving, label_pos, looping_start, looping_end) = XypicDiagramDrawer._process_loop_morphism( i, j, grid, morphisms_str_info, object_coords) elif (delta_i == 0) and (abs(j - target_j) > 1): # This is a horizontal morphism. (curving, label_pos) = XypicDiagramDrawer._process_horizontal_morphism( i, j, target_j, grid, morphisms_str_info, object_coords) elif (delta_j == 0) and (abs(i - target_i) > 1): # This is a vertical morphism. (curving, label_pos) = XypicDiagramDrawer._process_vertical_morphism( i, j, target_i, grid, morphisms_str_info, object_coords) count = count_morphisms_undirected(morphism.domain, morphism.codomain) curving_amount = "" if curving: # This morphisms should be curved anyway. curving_amount = self.default_curving_amount + count * \ self.default_curving_step elif count: # There are no objects between the domain and codomain of # the current morphism, but this is not there already are # some morphisms with the same domain and codomain, so we # have to curve this one. curving = "^" filtered_morphisms = count_morphisms_filtered( morphism.domain, morphism.codomain, curving) curving_amount = self.default_curving_amount + \ filtered_morphisms * \ self.default_curving_step # Let's now get the name of the morphism. morphism_name = "" if isinstance(morphism, IdentityMorphism): morphism_name = "id_{%s}" + latex(grid[i, j]) elif isinstance(morphism, CompositeMorphism): component_names = [latex(Symbol(component.name)) for component in morphism.components] component_names.reverse() morphism_name = "\\circ ".join(component_names) elif isinstance(morphism, NamedMorphism): morphism_name = latex(Symbol(morphism.name)) return ArrowStringDescription( self.unit, curving, curving_amount, looping_start, looping_end, horizontal_direction, vertical_direction, label_pos, morphism_name) @staticmethod def _check_free_space_horizontal(dom_i, dom_j, cod_j, grid): """ For a horizontal morphism, checks whether there is free space (i.e., space not occupied by any objects) above the morphism or below it. """ if dom_j < cod_j: (start, end) = (dom_j, cod_j) backwards = False else: (start, end) = (cod_j, dom_j) backwards = True # Check for free space above. if dom_i == 0: free_up = True else: free_up = all([grid[dom_i - 1, j] for j in range(start, end + 1)]) # Check for free space below. if dom_i == grid.height - 1: free_down = True else: free_down = all([not grid[dom_i + 1, j] for j in range(start, end + 1)]) return (free_up, free_down, backwards) @staticmethod def _check_free_space_vertical(dom_i, cod_i, dom_j, grid): """ For a vertical morphism, checks whether there is free space (i.e., space not occupied by any objects) to the left of the morphism or to the right of it. """ if dom_i < cod_i: (start, end) = (dom_i, cod_i) backwards = False else: (start, end) = (cod_i, dom_i) backwards = True # Check if there's space to the left. if dom_j == 0: free_left = True else: free_left = all([not grid[i, dom_j - 1] for i in range(start, end + 1)]) if dom_j == grid.width - 1: free_right = True else: free_right = all([not grid[i, dom_j + 1] for i in range(start, end + 1)]) return (free_left, free_right, backwards) @staticmethod def _check_free_space_diagonal(dom_i, cod_i, dom_j, cod_j, grid): """ For a diagonal morphism, checks whether there is free space (i.e., space not occupied by any objects) above the morphism or below it. """ def abs_xrange(start, end): if start < end: return range(start, end + 1) else: return range(end, start + 1) if dom_i < cod_i and dom_j < cod_j: # This morphism goes from top-left to # bottom-right. (start_i, start_j) = (dom_i, dom_j) (end_i, end_j) = (cod_i, cod_j) backwards = False elif dom_i > cod_i and dom_j > cod_j: # This morphism goes from bottom-right to # top-left. (start_i, start_j) = (cod_i, cod_j) (end_i, end_j) = (dom_i, dom_j) backwards = True if dom_i < cod_i and dom_j > cod_j: # This morphism goes from top-right to # bottom-left. (start_i, start_j) = (dom_i, dom_j) (end_i, end_j) = (cod_i, cod_j) backwards = True elif dom_i > cod_i and dom_j < cod_j: # This morphism goes from bottom-left to # top-right. (start_i, start_j) = (cod_i, cod_j) (end_i, end_j) = (dom_i, dom_j) backwards = False # This is an attempt at a fast and furious strategy to # decide where there is free space on the two sides of # a diagonal morphism. For a diagonal morphism # starting at ``(start_i, start_j)`` and ending at # ``(end_i, end_j)`` the rectangle defined by these # two points is considered. The slope of the diagonal # ``alpha`` is then computed. Then, for every cell # ``(i, j)`` within the rectangle, the slope # ``alpha1`` of the line through ``(start_i, # start_j)`` and ``(i, j)`` is considered. If # ``alpha1`` is between 0 and ``alpha``, the point # ``(i, j)`` is above the diagonal, if ``alpha1`` is # between ``alpha`` and infinity, the point is below # the diagonal. Also note that, with some beforehand # precautions, this trick works for both the main and # the secondary diagonals of the rectangle. # I have considered the possibility to only follow the # shorter diagonals immediately above and below the # main (or secondary) diagonal. This, however, # wouldn't have resulted in much performance gain or # better detection of outer edges, because of # relatively small sizes of diagram grids, while the # code would have become harder to understand. alpha = float(end_i - start_i)/(end_j - start_j) free_up = True free_down = True for i in abs_xrange(start_i, end_i): if not free_up and not free_down: break for j in abs_xrange(start_j, end_j): if not free_up and not free_down: break if (i, j) == (start_i, start_j): continue if j == start_j: alpha1 = "inf" else: alpha1 = float(i - start_i)/(j - start_j) if grid[i, j]: if (alpha1 == "inf") or (abs(alpha1) > abs(alpha)): free_down = False elif abs(alpha1) < abs(alpha): free_up = False return (free_up, free_down, backwards) def _push_labels_out(self, morphisms_str_info, grid, object_coords): """ For all straight morphisms which form the visual boundary of the laid out diagram, puts their labels on their outer sides. """ def set_label_position(free1, free2, pos1, pos2, backwards, m_str_info): """ Given the information about room available to one side and to the other side of a morphism (``free1`` and ``free2``), sets the position of the morphism label in such a way that it is on the freer side. This latter operations involves choice between ``pos1`` and ``pos2``, taking ``backwards`` in consideration. Thus this function will do nothing if either both ``free1 == True`` and ``free2 == True`` or both ``free1 == False`` and ``free2 == False``. In either case, choosing one side over the other presents no advantage. """ if backwards: (pos1, pos2) = (pos2, pos1) if free1 and not free2: m_str_info.label_position = pos1 elif free2 and not free1: m_str_info.label_position = pos2 for m, m_str_info in morphisms_str_info.items(): if m_str_info.curving or m_str_info.forced_label_position: # This is either a curved morphism, and curved # morphisms have other magic, or the position of this # label has already been fixed. continue if m.domain == m.codomain: # This is a loop morphism, their labels, again have a # different magic. continue (dom_i, dom_j) = object_coords[m.domain] (cod_i, cod_j) = object_coords[m.codomain] if dom_i == cod_i: # Horizontal morphism. (free_up, free_down, backwards) = XypicDiagramDrawer._check_free_space_horizontal( dom_i, dom_j, cod_j, grid) set_label_position(free_up, free_down, "^", "_", backwards, m_str_info) elif dom_j == cod_j: # Vertical morphism. (free_left, free_right, backwards) = XypicDiagramDrawer._check_free_space_vertical( dom_i, cod_i, dom_j, grid) set_label_position(free_left, free_right, "_", "^", backwards, m_str_info) else: # A diagonal morphism. (free_up, free_down, backwards) = XypicDiagramDrawer._check_free_space_diagonal( dom_i, cod_i, dom_j, cod_j, grid) set_label_position(free_up, free_down, "^", "_", backwards, m_str_info) @staticmethod def _morphism_sort_key(morphism, object_coords): """ Provides a morphism sorting key such that horizontal or vertical morphisms between neighbouring objects come first, then horizontal or vertical morphisms between more far away objects, and finally, all other morphisms. """ (i, j) = object_coords[morphism.domain] (target_i, target_j) = object_coords[morphism.codomain] if morphism.domain == morphism.codomain: # Loop morphisms should get after diagonal morphisms # so that the proper direction in which to curve the # loop can be determined. return (3, 0, default_sort_key(morphism)) if target_i == i: return (1, abs(target_j - j), default_sort_key(morphism)) if target_j == j: return (1, abs(target_i - i), default_sort_key(morphism)) # Diagonal morphism. return (2, 0, default_sort_key(morphism)) @staticmethod def _build_xypic_string(diagram, grid, morphisms, morphisms_str_info, diagram_format): """ Given a collection of :class:`ArrowStringDescription` describing the morphisms of a diagram and the object layout information of a diagram, produces the final Xy-pic picture. """ # Build the mapping between objects and morphisms which have # them as domains. object_morphisms = {} for obj in diagram.objects: object_morphisms[obj] = [] for morphism in morphisms: object_morphisms[morphism.domain].append(morphism) result = "\\xymatrix%s{\n" % diagram_format for i in range(grid.height): for j in range(grid.width): obj = grid[i, j] if obj: result += latex(obj) + " " morphisms_to_draw = object_morphisms[obj] for morphism in morphisms_to_draw: result += str(morphisms_str_info[morphism]) + " " # Don't put the & after the last column. if j < grid.width - 1: result += "& " # Don't put the line break after the last row. if i < grid.height - 1: result += "\\\\" result += "\n" result += "}\n" return result def draw(self, diagram, grid, masked=None, diagram_format=""): r""" Returns the Xy-pic representation of ``diagram`` laid out in ``grid``. Consider the following simple triangle diagram. >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy.categories import DiagramGrid, XypicDiagramDrawer >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g], {g * f: "unique"}) To draw this diagram, its objects need to be laid out with a :class:`DiagramGrid`:: >>> grid = DiagramGrid(diagram) Finally, the drawing: >>> drawer = XypicDiagramDrawer() >>> print(drawer.draw(diagram, grid)) \xymatrix{ A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ C & } The argument ``masked`` can be used to skip morphisms in the presentation of the diagram: >>> print(drawer.draw(diagram, grid, masked=[g * f])) \xymatrix{ A \ar[r]^{f} & B \ar[ld]^{g} \\ C & } Finally, the ``diagram_format`` argument can be used to specify the format string of the diagram. For example, to increase the spacing by 1 cm, proceeding as follows: >>> print(drawer.draw(diagram, grid, diagram_format="@+1cm")) \xymatrix@+1cm{ A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ C & } """ # This method works in several steps. It starts by removing # the masked morphisms, if necessary, and then maps objects to # their positions in the grid (coordinate tuples). Remember # that objects are unique in ``Diagram`` and in the layout # produced by ``DiagramGrid``, so every object is mapped to a # single coordinate pair. # # The next step is the central step and is concerned with # analysing the morphisms of the diagram and deciding how to # draw them. For example, how to curve the arrows is decided # at this step. The bulk of the analysis is implemented in # ``_process_morphism``, to the result of which the # appropriate formatters are applied. # # The result of the previous step is a list of # ``ArrowStringDescription``. After the analysis and # application of formatters, some extra logic tries to assure # better positioning of morphism labels (for example, an # attempt is made to avoid the situations when arrows cross # labels). This functionality constitutes the next step and # is implemented in ``_push_labels_out``. Note that label # positions which have been set via a formatter are not # affected in this step. # # Finally, at the closing step, the array of # ``ArrowStringDescription`` and the layout information # incorporated in ``DiagramGrid`` are combined to produce the # resulting Xy-pic picture. This part of code lies in # ``_build_xypic_string``. if not masked: morphisms_props = grid.morphisms else: morphisms_props = {} for m, props in grid.morphisms.items(): if m in masked: continue morphisms_props[m] = props # Build the mapping between objects and their position in the # grid. object_coords = {} for i in range(grid.height): for j in range(grid.width): if grid[i, j]: object_coords[grid[i, j]] = (i, j) morphisms = sorted(morphisms_props, key=lambda m: XypicDiagramDrawer._morphism_sort_key( m, object_coords)) # Build the tuples defining the string representations of # morphisms. morphisms_str_info = {} for morphism in morphisms: string_description = self._process_morphism( diagram, grid, morphism, object_coords, morphisms, morphisms_str_info) if self.default_arrow_formatter: self.default_arrow_formatter(string_description) for prop in morphisms_props[morphism]: # prop is a Symbol. TODO: Find out why. if prop.name in self.arrow_formatters: formatter = self.arrow_formatters[prop.name] formatter(string_description) morphisms_str_info[morphism] = string_description # Reposition the labels a bit. self._push_labels_out(morphisms_str_info, grid, object_coords) return XypicDiagramDrawer._build_xypic_string( diagram, grid, morphisms, morphisms_str_info, diagram_format) def xypic_draw_diagram(diagram, masked=None, diagram_format="", groups=None, **hints): r""" Provides a shortcut combining :class:`DiagramGrid` and :class:`XypicDiagramDrawer`. Returns an Xy-pic presentation of ``diagram``. The argument ``masked`` is a list of morphisms which will be not be drawn. The argument ``diagram_format`` is the format string inserted after "\xymatrix". ``groups`` should be a set of logical groups. The ``hints`` will be passed directly to the constructor of :class:`DiagramGrid`. For more information about the arguments, see the docstrings of :class:`DiagramGrid` and ``XypicDiagramDrawer.draw``. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy.categories import xypic_draw_diagram >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> diagram = Diagram([f, g], {g * f: "unique"}) >>> print(xypic_draw_diagram(diagram)) \xymatrix{ A \ar[d]_{g\circ f} \ar[r]^{f} & B \ar[ld]^{g} \\ C & } See Also ======== XypicDiagramDrawer, DiagramGrid """ grid = DiagramGrid(diagram, groups, **hints) drawer = XypicDiagramDrawer() return drawer.draw(diagram, grid, masked, diagram_format) @doctest_depends_on(exe=('latex', 'dvipng'), modules=('pyglet',)) def preview_diagram(diagram, masked=None, diagram_format="", groups=None, output='png', viewer=None, euler=True, **hints): """ Combines the functionality of ``xypic_draw_diagram`` and ``sympy.printing.preview``. The arguments ``masked``, ``diagram_format``, ``groups``, and ``hints`` are passed to ``xypic_draw_diagram``, while ``output``, ``viewer, and ``euler`` are passed to ``preview``. Examples ======== >>> from sympy.categories import Object, NamedMorphism, Diagram >>> from sympy.categories import preview_diagram >>> A = Object("A") >>> B = Object("B") >>> C = Object("C") >>> f = NamedMorphism(A, B, "f") >>> g = NamedMorphism(B, C, "g") >>> d = Diagram([f, g], {g * f: "unique"}) >>> preview_diagram(d) See Also ======== XypicDiagramDrawer """ from sympy.printing import preview latex_output = xypic_draw_diagram(diagram, masked, diagram_format, groups, **hints) preview(latex_output, output, viewer, euler, ("xypic",)) sympy-sympy-1.9/sympy/categories/tests/000077500000000000000000000000001412543434000203735ustar00rootroot00000000000000sympy-sympy-1.9/sympy/categories/tests/__init__.py000066400000000000000000000000001412543434000224720ustar00rootroot00000000000000sympy-sympy-1.9/sympy/categories/tests/test_baseclasses.py000066400000000000000000000131041412543434000242730ustar00rootroot00000000000000from sympy.categories import (Object, Morphism, IdentityMorphism, NamedMorphism, CompositeMorphism, Diagram, Category) from sympy.categories.baseclasses import Class from sympy.testing.pytest import raises from sympy import FiniteSet, EmptySet, Dict, Tuple def test_morphisms(): A = Object("A") B = Object("B") C = Object("C") D = Object("D") # Test the base morphism. f = NamedMorphism(A, B, "f") assert f.domain == A assert f.codomain == B assert f == NamedMorphism(A, B, "f") # Test identities. id_A = IdentityMorphism(A) id_B = IdentityMorphism(B) assert id_A.domain == A assert id_A.codomain == A assert id_A == IdentityMorphism(A) assert id_A != id_B # Test named morphisms. g = NamedMorphism(B, C, "g") assert g.name == "g" assert g != f assert g == NamedMorphism(B, C, "g") assert g != NamedMorphism(B, C, "f") # Test composite morphisms. assert f == CompositeMorphism(f) k = g.compose(f) assert k.domain == A assert k.codomain == C assert k.components == Tuple(f, g) assert g * f == k assert CompositeMorphism(f, g) == k assert CompositeMorphism(g * f) == g * f # Test the associativity of composition. h = NamedMorphism(C, D, "h") p = h * g u = h * g * f assert h * k == u assert p * f == u assert CompositeMorphism(f, g, h) == u # Test flattening. u2 = u.flatten("u") assert isinstance(u2, NamedMorphism) assert u2.name == "u" assert u2.domain == A assert u2.codomain == D # Test identities. assert f * id_A == f assert id_B * f == f assert id_A * id_A == id_A assert CompositeMorphism(id_A) == id_A # Test bad compositions. raises(ValueError, lambda: f * g) raises(TypeError, lambda: f.compose(None)) raises(TypeError, lambda: id_A.compose(None)) raises(TypeError, lambda: f * None) raises(TypeError, lambda: id_A * None) raises(TypeError, lambda: CompositeMorphism(f, None, 1)) raises(ValueError, lambda: NamedMorphism(A, B, "")) raises(NotImplementedError, lambda: Morphism(A, B)) def test_diagram(): A = Object("A") B = Object("B") C = Object("C") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") id_A = IdentityMorphism(A) id_B = IdentityMorphism(B) empty = EmptySet # Test the addition of identities. d1 = Diagram([f]) assert d1.objects == FiniteSet(A, B) assert d1.hom(A, B) == (FiniteSet(f), empty) assert d1.hom(A, A) == (FiniteSet(id_A), empty) assert d1.hom(B, B) == (FiniteSet(id_B), empty) assert d1 == Diagram([id_A, f]) assert d1 == Diagram([f, f]) # Test the addition of composites. d2 = Diagram([f, g]) homAC = d2.hom(A, C)[0] assert d2.objects == FiniteSet(A, B, C) assert g * f in d2.premises.keys() assert homAC == FiniteSet(g * f) # Test equality, inequality and hash. d11 = Diagram([f]) assert d1 == d11 assert d1 != d2 assert hash(d1) == hash(d11) d11 = Diagram({f: "unique"}) assert d1 != d11 # Make sure that (re-)adding composites (with new properties) # works as expected. d = Diagram([f, g], {g * f: "unique"}) assert d.conclusions == Dict({g * f: FiniteSet("unique")}) # Check the hom-sets when there are premises and conclusions. assert d.hom(A, C) == (FiniteSet(g * f), FiniteSet(g * f)) d = Diagram([f, g], [g * f]) assert d.hom(A, C) == (FiniteSet(g * f), FiniteSet(g * f)) # Check how the properties of composite morphisms are computed. d = Diagram({f: ["unique", "isomorphism"], g: "unique"}) assert d.premises[g * f] == FiniteSet("unique") # Check that conclusion morphisms with new objects are not allowed. d = Diagram([f], [g]) assert d.conclusions == Dict({}) # Test an empty diagram. d = Diagram() assert d.premises == Dict({}) assert d.conclusions == Dict({}) assert d.objects == empty # Check a SymPy Dict object. d = Diagram(Dict({f: FiniteSet("unique", "isomorphism"), g: "unique"})) assert d.premises[g * f] == FiniteSet("unique") # Check the addition of components of composite morphisms. d = Diagram([g * f]) assert f in d.premises assert g in d.premises # Check subdiagrams. d = Diagram([f, g], {g * f: "unique"}) d1 = Diagram([f]) assert d.is_subdiagram(d1) assert not d1.is_subdiagram(d) d = Diagram([NamedMorphism(B, A, "f'")]) assert not d.is_subdiagram(d1) assert not d1.is_subdiagram(d) d1 = Diagram([f, g], {g * f: ["unique", "something"]}) assert not d.is_subdiagram(d1) assert not d1.is_subdiagram(d) d = Diagram({f: "blooh"}) d1 = Diagram({f: "bleeh"}) assert not d.is_subdiagram(d1) assert not d1.is_subdiagram(d) d = Diagram([f, g], {f: "unique", g * f: "veryunique"}) d1 = d.subdiagram_from_objects(FiniteSet(A, B)) assert d1 == Diagram([f], {f: "unique"}) raises(ValueError, lambda: d.subdiagram_from_objects(FiniteSet(A, Object("D")))) raises(ValueError, lambda: Diagram({IdentityMorphism(A): "unique"})) def test_category(): A = Object("A") B = Object("B") C = Object("C") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") d1 = Diagram([f, g]) d2 = Diagram([f]) objects = d1.objects | d2.objects K = Category("K", objects, commutative_diagrams=[d1, d2]) assert K.name == "K" assert K.objects == Class(objects) assert K.commutative_diagrams == FiniteSet(d1, d2) raises(ValueError, lambda: Category("")) sympy-sympy-1.9/sympy/categories/tests/test_drawing.py000066400000000000000000000662761412543434000234600ustar00rootroot00000000000000from sympy.categories.diagram_drawing import _GrowableGrid, ArrowStringDescription from sympy.categories import (DiagramGrid, Object, NamedMorphism, Diagram, XypicDiagramDrawer, xypic_draw_diagram) from sympy import FiniteSet def test_GrowableGrid(): grid = _GrowableGrid(1, 2) # Check dimensions. assert grid.width == 1 assert grid.height == 2 # Check initialization of elements. assert grid[0, 0] is None assert grid[1, 0] is None # Check assignment to elements. grid[0, 0] = 1 grid[1, 0] = "two" assert grid[0, 0] == 1 assert grid[1, 0] == "two" # Check appending a row. grid.append_row() assert grid.width == 1 assert grid.height == 3 assert grid[0, 0] == 1 assert grid[1, 0] == "two" assert grid[2, 0] is None # Check appending a column. grid.append_column() assert grid.width == 2 assert grid.height == 3 assert grid[0, 0] == 1 assert grid[1, 0] == "two" assert grid[2, 0] is None assert grid[0, 1] is None assert grid[1, 1] is None assert grid[2, 1] is None grid = _GrowableGrid(1, 2) grid[0, 0] = 1 grid[1, 0] = "two" # Check prepending a row. grid.prepend_row() assert grid.width == 1 assert grid.height == 3 assert grid[0, 0] is None assert grid[1, 0] == 1 assert grid[2, 0] == "two" # Check prepending a column. grid.prepend_column() assert grid.width == 2 assert grid.height == 3 assert grid[0, 0] is None assert grid[1, 0] is None assert grid[2, 0] is None assert grid[0, 1] is None assert grid[1, 1] == 1 assert grid[2, 1] == "two" def test_DiagramGrid(): # Set up some objects and morphisms. A = Object("A") B = Object("B") C = Object("C") D = Object("D") E = Object("E") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(D, A, "h") k = NamedMorphism(D, B, "k") # A one-morphism diagram. d = Diagram([f]) grid = DiagramGrid(d) assert grid.width == 2 assert grid.height == 1 assert grid[0, 0] == A assert grid[0, 1] == B assert grid.morphisms == {f: FiniteSet()} # A triangle. d = Diagram([f, g], {g * f: "unique"}) grid = DiagramGrid(d) assert grid.width == 2 assert grid.height == 2 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[1, 0] == C assert grid[1, 1] is None assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), g * f: FiniteSet("unique")} # A triangle with a "loop" morphism. l_A = NamedMorphism(A, A, "l_A") d = Diagram([f, g, l_A]) grid = DiagramGrid(d) assert grid.width == 2 assert grid.height == 2 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[1, 0] is None assert grid[1, 1] == C assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), l_A: FiniteSet()} # A simple diagram. d = Diagram([f, g, h, k]) grid = DiagramGrid(d) assert grid.width == 3 assert grid.height == 2 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] == D assert grid[1, 0] is None assert grid[1, 1] == C assert grid[1, 2] is None assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), k: FiniteSet()} assert str(grid) == '[[Object("A"), Object("B"), Object("D")], ' \ '[None, Object("C"), None]]' # A chain of morphisms. f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(C, D, "h") k = NamedMorphism(D, E, "k") d = Diagram([f, g, h, k]) grid = DiagramGrid(d) assert grid.width == 3 assert grid.height == 3 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] is None assert grid[1, 0] is None assert grid[1, 1] == C assert grid[1, 2] == D assert grid[2, 0] is None assert grid[2, 1] is None assert grid[2, 2] == E assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), k: FiniteSet()} # A square. f = NamedMorphism(A, B, "f") g = NamedMorphism(B, D, "g") h = NamedMorphism(A, C, "h") k = NamedMorphism(C, D, "k") d = Diagram([f, g, h, k]) grid = DiagramGrid(d) assert grid.width == 2 assert grid.height == 2 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[1, 0] == C assert grid[1, 1] == D assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), k: FiniteSet()} # A strange diagram which resulted from a typo when creating a # test for five lemma, but which allowed to stop one extra problem # in the algorithm. A = Object("A") B = Object("B") C = Object("C") D = Object("D") E = Object("E") A_ = Object("A'") B_ = Object("B'") C_ = Object("C'") D_ = Object("D'") E_ = Object("E'") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(C, D, "h") i = NamedMorphism(D, E, "i") # These 4 morphisms should be between primed objects. j = NamedMorphism(A, B, "j") k = NamedMorphism(B, C, "k") l = NamedMorphism(C, D, "l") m = NamedMorphism(D, E, "m") o = NamedMorphism(A, A_, "o") p = NamedMorphism(B, B_, "p") q = NamedMorphism(C, C_, "q") r = NamedMorphism(D, D_, "r") s = NamedMorphism(E, E_, "s") d = Diagram([f, g, h, i, j, k, l, m, o, p, q, r, s]) grid = DiagramGrid(d) assert grid.width == 3 assert grid.height == 4 assert grid[0, 0] is None assert grid[0, 1] == A assert grid[0, 2] == A_ assert grid[1, 0] == C assert grid[1, 1] == B assert grid[1, 2] == B_ assert grid[2, 0] == C_ assert grid[2, 1] == D assert grid[2, 2] == D_ assert grid[3, 0] is None assert grid[3, 1] == E assert grid[3, 2] == E_ morphisms = {} for m in [f, g, h, i, j, k, l, m, o, p, q, r, s]: morphisms[m] = FiniteSet() assert grid.morphisms == morphisms # A cube. A1 = Object("A1") A2 = Object("A2") A3 = Object("A3") A4 = Object("A4") A5 = Object("A5") A6 = Object("A6") A7 = Object("A7") A8 = Object("A8") # The top face of the cube. f1 = NamedMorphism(A1, A2, "f1") f2 = NamedMorphism(A1, A3, "f2") f3 = NamedMorphism(A2, A4, "f3") f4 = NamedMorphism(A3, A4, "f3") # The bottom face of the cube. f5 = NamedMorphism(A5, A6, "f5") f6 = NamedMorphism(A5, A7, "f6") f7 = NamedMorphism(A6, A8, "f7") f8 = NamedMorphism(A7, A8, "f8") # The remaining morphisms. f9 = NamedMorphism(A1, A5, "f9") f10 = NamedMorphism(A2, A6, "f10") f11 = NamedMorphism(A3, A7, "f11") f12 = NamedMorphism(A4, A8, "f11") d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12]) grid = DiagramGrid(d) assert grid.width == 4 assert grid.height == 3 assert grid[0, 0] is None assert grid[0, 1] == A5 assert grid[0, 2] == A6 assert grid[0, 3] is None assert grid[1, 0] is None assert grid[1, 1] == A1 assert grid[1, 2] == A2 assert grid[1, 3] is None assert grid[2, 0] == A7 assert grid[2, 1] == A3 assert grid[2, 2] == A4 assert grid[2, 3] == A8 morphisms = {} for m in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12]: morphisms[m] = FiniteSet() assert grid.morphisms == morphisms # A line diagram. A = Object("A") B = Object("B") C = Object("C") D = Object("D") E = Object("E") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(C, D, "h") i = NamedMorphism(D, E, "i") d = Diagram([f, g, h, i]) grid = DiagramGrid(d, layout="sequential") assert grid.width == 5 assert grid.height == 1 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] == C assert grid[0, 3] == D assert grid[0, 4] == E assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), i: FiniteSet()} # Test the transposed version. grid = DiagramGrid(d, layout="sequential", transpose=True) assert grid.width == 1 assert grid.height == 5 assert grid[0, 0] == A assert grid[1, 0] == B assert grid[2, 0] == C assert grid[3, 0] == D assert grid[4, 0] == E assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), h: FiniteSet(), i: FiniteSet()} # A pullback. m1 = NamedMorphism(A, B, "m1") m2 = NamedMorphism(A, C, "m2") s1 = NamedMorphism(B, D, "s1") s2 = NamedMorphism(C, D, "s2") f1 = NamedMorphism(E, B, "f1") f2 = NamedMorphism(E, C, "f2") g = NamedMorphism(E, A, "g") d = Diagram([m1, m2, s1, s2, f1, f2], {g: "unique"}) grid = DiagramGrid(d) assert grid.width == 3 assert grid.height == 2 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] == E assert grid[1, 0] == C assert grid[1, 1] == D assert grid[1, 2] is None morphisms = {g: FiniteSet("unique")} for m in [m1, m2, s1, s2, f1, f2]: morphisms[m] = FiniteSet() assert grid.morphisms == morphisms # Test the pullback with sequential layout, just for stress # testing. grid = DiagramGrid(d, layout="sequential") assert grid.width == 5 assert grid.height == 1 assert grid[0, 0] == D assert grid[0, 1] == B assert grid[0, 2] == A assert grid[0, 3] == C assert grid[0, 4] == E assert grid.morphisms == morphisms # Test a pullback with object grouping. grid = DiagramGrid(d, groups=FiniteSet(E, FiniteSet(A, B, C, D))) assert grid.width == 3 assert grid.height == 2 assert grid[0, 0] == E assert grid[0, 1] == A assert grid[0, 2] == B assert grid[1, 0] is None assert grid[1, 1] == C assert grid[1, 2] == D assert grid.morphisms == morphisms # Five lemma, actually. A = Object("A") B = Object("B") C = Object("C") D = Object("D") E = Object("E") A_ = Object("A'") B_ = Object("B'") C_ = Object("C'") D_ = Object("D'") E_ = Object("E'") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(C, D, "h") i = NamedMorphism(D, E, "i") j = NamedMorphism(A_, B_, "j") k = NamedMorphism(B_, C_, "k") l = NamedMorphism(C_, D_, "l") m = NamedMorphism(D_, E_, "m") o = NamedMorphism(A, A_, "o") p = NamedMorphism(B, B_, "p") q = NamedMorphism(C, C_, "q") r = NamedMorphism(D, D_, "r") s = NamedMorphism(E, E_, "s") d = Diagram([f, g, h, i, j, k, l, m, o, p, q, r, s]) grid = DiagramGrid(d) assert grid.width == 5 assert grid.height == 3 assert grid[0, 0] is None assert grid[0, 1] == A assert grid[0, 2] == A_ assert grid[0, 3] is None assert grid[0, 4] is None assert grid[1, 0] == C assert grid[1, 1] == B assert grid[1, 2] == B_ assert grid[1, 3] == C_ assert grid[1, 4] is None assert grid[2, 0] == D assert grid[2, 1] == E assert grid[2, 2] is None assert grid[2, 3] == D_ assert grid[2, 4] == E_ morphisms = {} for m in [f, g, h, i, j, k, l, m, o, p, q, r, s]: morphisms[m] = FiniteSet() assert grid.morphisms == morphisms # Test the five lemma with object grouping. grid = DiagramGrid(d, FiniteSet( FiniteSet(A, B, C, D, E), FiniteSet(A_, B_, C_, D_, E_))) assert grid.width == 6 assert grid.height == 3 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] is None assert grid[0, 3] == A_ assert grid[0, 4] == B_ assert grid[0, 5] is None assert grid[1, 0] is None assert grid[1, 1] == C assert grid[1, 2] == D assert grid[1, 3] is None assert grid[1, 4] == C_ assert grid[1, 5] == D_ assert grid[2, 0] is None assert grid[2, 1] is None assert grid[2, 2] == E assert grid[2, 3] is None assert grid[2, 4] is None assert grid[2, 5] == E_ assert grid.morphisms == morphisms # Test the five lemma with object grouping, but mixing containers # to represent groups. grid = DiagramGrid(d, [(A, B, C, D, E), {A_, B_, C_, D_, E_}]) assert grid.width == 6 assert grid.height == 3 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] is None assert grid[0, 3] == A_ assert grid[0, 4] == B_ assert grid[0, 5] is None assert grid[1, 0] is None assert grid[1, 1] == C assert grid[1, 2] == D assert grid[1, 3] is None assert grid[1, 4] == C_ assert grid[1, 5] == D_ assert grid[2, 0] is None assert grid[2, 1] is None assert grid[2, 2] == E assert grid[2, 3] is None assert grid[2, 4] is None assert grid[2, 5] == E_ assert grid.morphisms == morphisms # Test the five lemma with object grouping and hints. grid = DiagramGrid(d, { FiniteSet(A, B, C, D, E): {"layout": "sequential", "transpose": True}, FiniteSet(A_, B_, C_, D_, E_): {"layout": "sequential", "transpose": True}}, transpose=True) assert grid.width == 5 assert grid.height == 2 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] == C assert grid[0, 3] == D assert grid[0, 4] == E assert grid[1, 0] == A_ assert grid[1, 1] == B_ assert grid[1, 2] == C_ assert grid[1, 3] == D_ assert grid[1, 4] == E_ assert grid.morphisms == morphisms # A two-triangle disconnected diagram. f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") f_ = NamedMorphism(A_, B_, "f") g_ = NamedMorphism(B_, C_, "g") d = Diagram([f, g, f_, g_], {g * f: "unique", g_ * f_: "unique"}) grid = DiagramGrid(d) assert grid.width == 4 assert grid.height == 2 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] == A_ assert grid[0, 3] == B_ assert grid[1, 0] == C assert grid[1, 1] is None assert grid[1, 2] == C_ assert grid[1, 3] is None assert grid.morphisms == {f: FiniteSet(), g: FiniteSet(), f_: FiniteSet(), g_: FiniteSet(), g * f: FiniteSet("unique"), g_ * f_: FiniteSet("unique")} # A two-morphism disconnected diagram. f = NamedMorphism(A, B, "f") g = NamedMorphism(C, D, "g") d = Diagram([f, g]) grid = DiagramGrid(d) assert grid.width == 4 assert grid.height == 1 assert grid[0, 0] == A assert grid[0, 1] == B assert grid[0, 2] == C assert grid[0, 3] == D assert grid.morphisms == {f: FiniteSet(), g: FiniteSet()} # Test a one-object diagram. f = NamedMorphism(A, A, "f") d = Diagram([f]) grid = DiagramGrid(d) assert grid.width == 1 assert grid.height == 1 assert grid[0, 0] == A # Test a two-object disconnected diagram. g = NamedMorphism(B, B, "g") d = Diagram([f, g]) grid = DiagramGrid(d) assert grid.width == 2 assert grid.height == 1 assert grid[0, 0] == A assert grid[0, 1] == B def test_DiagramGrid_pseudopod(): # Test a diagram in which even growing a pseudopod does not # eventually help. A = Object("A") B = Object("B") C = Object("C") D = Object("D") E = Object("E") F = Object("F") A_ = Object("A'") B_ = Object("B'") C_ = Object("C'") D_ = Object("D'") E_ = Object("E'") f1 = NamedMorphism(A, B, "f1") f2 = NamedMorphism(A, C, "f2") f3 = NamedMorphism(A, D, "f3") f4 = NamedMorphism(A, E, "f4") f5 = NamedMorphism(A, A_, "f5") f6 = NamedMorphism(A, B_, "f6") f7 = NamedMorphism(A, C_, "f7") f8 = NamedMorphism(A, D_, "f8") f9 = NamedMorphism(A, E_, "f9") f10 = NamedMorphism(A, F, "f10") d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10]) grid = DiagramGrid(d) assert grid.width == 5 assert grid.height == 3 assert grid[0, 0] == E assert grid[0, 1] == C assert grid[0, 2] == C_ assert grid[0, 3] == E_ assert grid[0, 4] == F assert grid[1, 0] == D assert grid[1, 1] == A assert grid[1, 2] == A_ assert grid[1, 3] is None assert grid[1, 4] is None assert grid[2, 0] == D_ assert grid[2, 1] == B assert grid[2, 2] == B_ assert grid[2, 3] is None assert grid[2, 4] is None morphisms = {} for f in [f1, f2, f3, f4, f5, f6, f7, f8, f9, f10]: morphisms[f] = FiniteSet() assert grid.morphisms == morphisms def test_ArrowStringDescription(): astr = ArrowStringDescription("cm", "", None, "", "", "d", "r", "_", "f") assert str(astr) == "\\ar[dr]_{f}" astr = ArrowStringDescription("cm", "", 12, "", "", "d", "r", "_", "f") assert str(astr) == "\\ar[dr]_{f}" astr = ArrowStringDescription("cm", "^", 12, "", "", "d", "r", "_", "f") assert str(astr) == "\\ar@/^12cm/[dr]_{f}" astr = ArrowStringDescription("cm", "", 12, "r", "", "d", "r", "_", "f") assert str(astr) == "\\ar[dr]_{f}" astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f") assert str(astr) == "\\ar@(r,u)[dr]_{f}" astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f") assert str(astr) == "\\ar@(r,u)[dr]_{f}" astr = ArrowStringDescription("cm", "", 12, "r", "u", "d", "r", "_", "f") astr.arrow_style = "{-->}" assert str(astr) == "\\ar@(r,u)@{-->}[dr]_{f}" astr = ArrowStringDescription("cm", "_", 12, "", "", "d", "r", "_", "f") astr.arrow_style = "{-->}" assert str(astr) == "\\ar@/_12cm/@{-->}[dr]_{f}" def test_XypicDiagramDrawer_line(): # A linear diagram. A = Object("A") B = Object("B") C = Object("C") D = Object("D") E = Object("E") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(C, D, "h") i = NamedMorphism(D, E, "i") d = Diagram([f, g, h, i]) grid = DiagramGrid(d, layout="sequential") drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[r]^{f} & B \\ar[r]^{g} & C \\ar[r]^{h} & D \\ar[r]^{i} & E \n" \ "}\n" # The same diagram, transposed. grid = DiagramGrid(d, layout="sequential", transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[d]^{f} \\\\\n" \ "B \\ar[d]^{g} \\\\\n" \ "C \\ar[d]^{h} \\\\\n" \ "D \\ar[d]^{i} \\\\\n" \ "E \n" \ "}\n" def test_XypicDiagramDrawer_triangle(): # A triangle diagram. A = Object("A") B = Object("B") C = Object("C") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") d = Diagram([f, g], {g * f: "unique"}) grid = DiagramGrid(d) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[d]_{g\\circ f} \\ar[r]^{f} & B \\ar[ld]^{g} \\\\\n" \ "C & \n" \ "}\n" # The same diagram, transposed. grid = DiagramGrid(d, transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[r]^{g\\circ f} \\ar[d]_{f} & C \\\\\n" \ "B \\ar[ru]_{g} & \n" \ "}\n" # The same diagram, with a masked morphism. assert drawer.draw(d, grid, masked=[g]) == "\\xymatrix{\n" \ "A \\ar[r]^{g\\circ f} \\ar[d]_{f} & C \\\\\n" \ "B & \n" \ "}\n" # The same diagram with a formatter for "unique". def formatter(astr): astr.label = "\\exists !" + astr.label astr.arrow_style = "{-->}" drawer.arrow_formatters["unique"] = formatter assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar@{-->}[r]^{\\exists !g\\circ f} \\ar[d]_{f} & C \\\\\n" \ "B \\ar[ru]_{g} & \n" \ "}\n" # The same diagram with a default formatter. def default_formatter(astr): astr.label_displacement = "(0.45)" drawer.default_arrow_formatter = default_formatter assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar@{-->}[r]^(0.45){\\exists !g\\circ f} \\ar[d]_(0.45){f} & C \\\\\n" \ "B \\ar[ru]_(0.45){g} & \n" \ "}\n" # A triangle diagram with a lot of morphisms between the same # objects. f1 = NamedMorphism(B, A, "f1") f2 = NamedMorphism(A, B, "f2") g1 = NamedMorphism(C, B, "g1") g2 = NamedMorphism(B, C, "g2") d = Diagram([f, f1, f2, g, g1, g2], {f1 * g1: "unique", g2 * f2: "unique"}) grid = DiagramGrid(d, transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid, masked=[f1*g1*g2*f2, g2*f2*f1*g1]) == \ "\\xymatrix{\n" \ "A \\ar[r]^{g_{2}\\circ f_{2}} \\ar[d]_{f} \\ar@/^3mm/[d]^{f_{2}} " \ "& C \\ar@/^3mm/[l]^{f_{1}\\circ g_{1}} \\ar@/^3mm/[ld]^{g_{1}} \\\\\n" \ "B \\ar@/^3mm/[u]^{f_{1}} \\ar[ru]_{g} \\ar@/^3mm/[ru]^{g_{2}} & \n" \ "}\n" def test_XypicDiagramDrawer_cube(): # A cube diagram. A1 = Object("A1") A2 = Object("A2") A3 = Object("A3") A4 = Object("A4") A5 = Object("A5") A6 = Object("A6") A7 = Object("A7") A8 = Object("A8") # The top face of the cube. f1 = NamedMorphism(A1, A2, "f1") f2 = NamedMorphism(A1, A3, "f2") f3 = NamedMorphism(A2, A4, "f3") f4 = NamedMorphism(A3, A4, "f3") # The bottom face of the cube. f5 = NamedMorphism(A5, A6, "f5") f6 = NamedMorphism(A5, A7, "f6") f7 = NamedMorphism(A6, A8, "f7") f8 = NamedMorphism(A7, A8, "f8") # The remaining morphisms. f9 = NamedMorphism(A1, A5, "f9") f10 = NamedMorphism(A2, A6, "f10") f11 = NamedMorphism(A3, A7, "f11") f12 = NamedMorphism(A4, A8, "f11") d = Diagram([f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12]) grid = DiagramGrid(d) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "& A_{5} \\ar[r]^{f_{5}} \\ar[ldd]_{f_{6}} & A_{6} \\ar[rdd]^{f_{7}} " \ "& \\\\\n" \ "& A_{1} \\ar[r]^{f_{1}} \\ar[d]^{f_{2}} \\ar[u]^{f_{9}} & A_{2} " \ "\\ar[d]^{f_{3}} \\ar[u]_{f_{10}} & \\\\\n" \ "A_{7} \\ar@/_3mm/[rrr]_{f_{8}} & A_{3} \\ar[r]^{f_{3}} \\ar[l]_{f_{11}} " \ "& A_{4} \\ar[r]^{f_{11}} & A_{8} \n" \ "}\n" # The same diagram, transposed. grid = DiagramGrid(d, transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "& & A_{7} \\ar@/^3mm/[ddd]^{f_{8}} \\\\\n" \ "A_{5} \\ar[d]_{f_{5}} \\ar[rru]^{f_{6}} & A_{1} \\ar[d]^{f_{1}} " \ "\\ar[r]^{f_{2}} \\ar[l]^{f_{9}} & A_{3} \\ar[d]_{f_{3}} " \ "\\ar[u]^{f_{11}} \\\\\n" \ "A_{6} \\ar[rrd]_{f_{7}} & A_{2} \\ar[r]^{f_{3}} \\ar[l]^{f_{10}} " \ "& A_{4} \\ar[d]_{f_{11}} \\\\\n" \ "& & A_{8} \n" \ "}\n" def test_XypicDiagramDrawer_curved_and_loops(): # A simple diagram, with a curved arrow. A = Object("A") B = Object("B") C = Object("C") D = Object("D") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(D, A, "h") k = NamedMorphism(D, B, "k") d = Diagram([f, g, h, k]) grid = DiagramGrid(d) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[r]_{f} & B \\ar[d]^{g} & D \\ar[l]^{k} \\ar@/_3mm/[ll]_{h} \\\\\n" \ "& C & \n" \ "}\n" # The same diagram, transposed. grid = DiagramGrid(d, transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[d]^{f} & \\\\\n" \ "B \\ar[r]^{g} & C \\\\\n" \ "D \\ar[u]_{k} \\ar@/^3mm/[uu]^{h} & \n" \ "}\n" # The same diagram, larger and rotated. assert drawer.draw(d, grid, diagram_format="@+1cm@dr") == \ "\\xymatrix@+1cm@dr{\n" \ "A \\ar[d]^{f} & \\\\\n" \ "B \\ar[r]^{g} & C \\\\\n" \ "D \\ar[u]_{k} \\ar@/^3mm/[uu]^{h} & \n" \ "}\n" # A simple diagram with three curved arrows. h1 = NamedMorphism(D, A, "h1") h2 = NamedMorphism(A, D, "h2") k = NamedMorphism(D, B, "k") d = Diagram([f, g, h, k, h1, h2]) grid = DiagramGrid(d) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} & B \\ar[d]^{g} & D \\ar[l]^{k} " \ "\\ar@/_7mm/[ll]_{h} \\ar@/_11mm/[ll]_{h_{1}} \\\\\n" \ "& C & \n" \ "}\n" # The same diagram, transposed. grid = DiagramGrid(d, transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} & \\\\\n" \ "B \\ar[r]^{g} & C \\\\\n" \ "D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} & \n" \ "}\n" # The same diagram, with "loop" morphisms. l_A = NamedMorphism(A, A, "l_A") l_D = NamedMorphism(D, D, "l_D") l_C = NamedMorphism(C, C, "l_C") d = Diagram([f, g, h, k, h1, h2, l_A, l_D, l_C]) grid = DiagramGrid(d) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} \\ar@(u,l)[]^{l_{A}} " \ "& B \\ar[d]^{g} & D \\ar[l]^{k} \\ar@/_7mm/[ll]_{h} " \ "\\ar@/_11mm/[ll]_{h_{1}} \\ar@(r,u)[]^{l_{D}} \\\\\n" \ "& C \\ar@(l,d)[]^{l_{C}} & \n" \ "}\n" # The same diagram with "loop" morphisms, transposed. grid = DiagramGrid(d, transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} \\ar@(r,u)[]^{l_{A}} & \\\\\n" \ "B \\ar[r]^{g} & C \\ar@(r,u)[]^{l_{C}} \\\\\n" \ "D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} " \ "\\ar@(l,d)[]^{l_{D}} & \n" \ "}\n" # The same diagram with two "loop" morphisms per object. l_A_ = NamedMorphism(A, A, "n_A") l_D_ = NamedMorphism(D, D, "n_D") l_C_ = NamedMorphism(C, C, "n_C") d = Diagram([f, g, h, k, h1, h2, l_A, l_D, l_C, l_A_, l_D_, l_C_]) grid = DiagramGrid(d) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[r]_{f} \\ar@/^3mm/[rr]^{h_{2}} \\ar@(u,l)[]^{l_{A}} " \ "\\ar@/^3mm/@(l,d)[]^{n_{A}} & B \\ar[d]^{g} & D \\ar[l]^{k} " \ "\\ar@/_7mm/[ll]_{h} \\ar@/_11mm/[ll]_{h_{1}} \\ar@(r,u)[]^{l_{D}} " \ "\\ar@/^3mm/@(d,r)[]^{n_{D}} \\\\\n" \ "& C \\ar@(l,d)[]^{l_{C}} \\ar@/^3mm/@(d,r)[]^{n_{C}} & \n" \ "}\n" # The same diagram with two "loop" morphisms per object, transposed. grid = DiagramGrid(d, transpose=True) drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == "\\xymatrix{\n" \ "A \\ar[d]^{f} \\ar@/_3mm/[dd]_{h_{2}} \\ar@(r,u)[]^{l_{A}} " \ "\\ar@/^3mm/@(u,l)[]^{n_{A}} & \\\\\n" \ "B \\ar[r]^{g} & C \\ar@(r,u)[]^{l_{C}} \\ar@/^3mm/@(d,r)[]^{n_{C}} \\\\\n" \ "D \\ar[u]_{k} \\ar@/^7mm/[uu]^{h} \\ar@/^11mm/[uu]^{h_{1}} " \ "\\ar@(l,d)[]^{l_{D}} \\ar@/^3mm/@(d,r)[]^{n_{D}} & \n" \ "}\n" def test_xypic_draw_diagram(): # A linear diagram. A = Object("A") B = Object("B") C = Object("C") D = Object("D") E = Object("E") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") h = NamedMorphism(C, D, "h") i = NamedMorphism(D, E, "i") d = Diagram([f, g, h, i]) grid = DiagramGrid(d, layout="sequential") drawer = XypicDiagramDrawer() assert drawer.draw(d, grid) == xypic_draw_diagram(d, layout="sequential") sympy-sympy-1.9/sympy/codegen/000077500000000000000000000000001412543434000165105ustar00rootroot00000000000000sympy-sympy-1.9/sympy/codegen/__init__.py000066400000000000000000000017161412543434000206260ustar00rootroot00000000000000""" The ``sympy.codegen`` module contains classes and functions for building abstract syntax trees of algorithms. These trees may then be printed by the code-printers in ``sympy.printing``. There are several submodules available: - ``sympy.codegen.ast``: AST nodes useful across multiple languages. - ``sympy.codegen.cnodes``: AST nodes useful for the C family of languages. - ``sympy.codegen.fnodes``: AST nodes useful for Fortran. - ``sympy.codegen.cfunctions``: functions specific to C (C99 math functions) - ``sympy.codegen.ffunctions``: functions specific to Fortran (e.g. ``kind``). """ from .ast import ( Assignment, aug_assign, CodeBlock, For, Attribute, Variable, Declaration, While, Scope, Print, FunctionPrototype, FunctionDefinition, FunctionCall ) __all__ = [ 'Assignment', 'aug_assign', 'CodeBlock', 'For', 'Attribute', 'Variable', 'Declaration', 'While', 'Scope', 'Print', 'FunctionPrototype', 'FunctionDefinition', 'FunctionCall', ] sympy-sympy-1.9/sympy/codegen/algorithms.py000066400000000000000000000114011412543434000212300ustar00rootroot00000000000000from sympy import And, Gt, Lt, Abs, Dummy, oo, Tuple, Symbol from sympy.codegen.ast import ( Assignment, AddAugmentedAssignment, CodeBlock, Declaration, FunctionDefinition, Print, Return, Scope, While, Variable, Pointer, real ) """ This module collects functions for constructing ASTs representing algorithms. """ def newtons_method(expr, wrt, atol=1e-12, delta=None, debug=False, itermax=None, counter=None): """ Generates an AST for Newton-Raphson method (a root-finding algorithm). Explanation =========== Returns an abstract syntax tree (AST) based on ``sympy.codegen.ast`` for Netwon's method of root-finding. Parameters ========== expr : expression wrt : Symbol With respect to, i.e. what is the variable. atol : number or expr Absolute tolerance (stopping criterion) delta : Symbol Will be a ``Dummy`` if ``None``. debug : bool Whether to print convergence information during iterations itermax : number or expr Maximum number of iterations. counter : Symbol Will be a ``Dummy`` if ``None``. Examples ======== >>> from sympy import symbols, cos >>> from sympy.codegen.ast import Assignment >>> from sympy.codegen.algorithms import newtons_method >>> x, dx, atol = symbols('x dx atol') >>> expr = cos(x) - x**3 >>> algo = newtons_method(expr, x, atol, dx) >>> algo.has(Assignment(dx, -expr/expr.diff(x))) True References ========== .. [1] https://en.wikipedia.org/wiki/Newton%27s_method """ if delta is None: delta = Dummy() Wrapper = Scope name_d = 'delta' else: Wrapper = lambda x: x name_d = delta.name delta_expr = -expr/expr.diff(wrt) whl_bdy = [Assignment(delta, delta_expr), AddAugmentedAssignment(wrt, delta)] if debug: prnt = Print([wrt, delta], r"{}=%12.5g {}=%12.5g\n".format(wrt.name, name_d)) whl_bdy = [whl_bdy[0], prnt] + whl_bdy[1:] req = Gt(Abs(delta), atol) declars = [Declaration(Variable(delta, type=real, value=oo))] if itermax is not None: counter = counter or Dummy(integer=True) v_counter = Variable.deduced(counter, 0) declars.append(Declaration(v_counter)) whl_bdy.append(AddAugmentedAssignment(counter, 1)) req = And(req, Lt(counter, itermax)) whl = While(req, CodeBlock(*whl_bdy)) blck = declars + [whl] return Wrapper(CodeBlock(*blck)) def _symbol_of(arg): if isinstance(arg, Declaration): arg = arg.variable.symbol elif isinstance(arg, Variable): arg = arg.symbol return arg def newtons_method_function(expr, wrt, params=None, func_name="newton", attrs=Tuple(), *, delta=None, **kwargs): """ Generates an AST for a function implementing the Newton-Raphson method. Parameters ========== expr : expression wrt : Symbol With respect to, i.e. what is the variable params : iterable of symbols Symbols appearing in expr that are taken as constants during the iterations (these will be accepted as parameters to the generated function). func_name : str Name of the generated function. attrs : Tuple Attribute instances passed as ``attrs`` to ``FunctionDefinition``. \\*\\*kwargs : Keyword arguments passed to :func:`sympy.codegen.algorithms.newtons_method`. Examples ======== >>> from sympy import symbols, cos >>> from sympy.codegen.algorithms import newtons_method_function >>> from sympy.codegen.pyutils import render_as_module >>> x = symbols('x') >>> expr = cos(x) - x**3 >>> func = newtons_method_function(expr, x) >>> py_mod = render_as_module(func) # source code as string >>> namespace = {} >>> exec(py_mod, namespace, namespace) >>> res = eval('newton(0.5)', namespace) >>> abs(res - 0.865474033102) < 1e-12 True See Also ======== sympy.codegen.algorithms.newtons_method """ if params is None: params = (wrt,) pointer_subs = {p.symbol: Symbol('(*%s)' % p.symbol.name) for p in params if isinstance(p, Pointer)} if delta is None: delta = Symbol('d_' + wrt.name) if expr.has(delta): delta = None # will use Dummy algo = newtons_method(expr, wrt, delta=delta, **kwargs).xreplace(pointer_subs) if isinstance(algo, Scope): algo = algo.body not_in_params = expr.free_symbols.difference({_symbol_of(p) for p in params}) if not_in_params: raise ValueError("Missing symbols in params: %s" % ', '.join(map(str, not_in_params))) declars = tuple(Variable(p, real) for p in params) body = CodeBlock(algo, Return(wrt)) return FunctionDefinition(real, func_name, declars, body, attrs=attrs) sympy-sympy-1.9/sympy/codegen/approximations.py000066400000000000000000000144451412543434000221470ustar00rootroot00000000000000import math from sympy import Interval from sympy.calculus.singularities import is_increasing, is_decreasing from sympy.codegen.rewriting import Optimization from sympy.core.function import UndefinedFunction """ This module collects classes useful for approimate rewriting of expressions. This can be beneficial when generating numeric code for which performance is of greater importance than precision (e.g. for preconditioners used in iterative methods). """ class SumApprox(Optimization): """ Approximates sum by neglecting small terms. Explanation =========== If terms are expressions which can be determined to be monotonic, then bounds for those expressions are added. Parameters ========== bounds : dict Mapping expressions to length 2 tuple of bounds (low, high). reltol : number Threshold for when to ignore a term. Taken relative to the largest lower bound among bounds. Examples ======== >>> from sympy import exp >>> from sympy.abc import x, y, z >>> from sympy.codegen.rewriting import optimize >>> from sympy.codegen.approximations import SumApprox >>> bounds = {x: (-1, 1), y: (1000, 2000), z: (-10, 3)} >>> sum_approx3 = SumApprox(bounds, reltol=1e-3) >>> sum_approx2 = SumApprox(bounds, reltol=1e-2) >>> sum_approx1 = SumApprox(bounds, reltol=1e-1) >>> expr = 3*(x + y + exp(z)) >>> optimize(expr, [sum_approx3]) 3*(x + y + exp(z)) >>> optimize(expr, [sum_approx2]) 3*y + 3*exp(z) >>> optimize(expr, [sum_approx1]) 3*y """ def __init__(self, bounds, reltol, **kwargs): super().__init__(**kwargs) self.bounds = bounds self.reltol = reltol def __call__(self, expr): return expr.factor().replace(self.query, lambda arg: self.value(arg)) def query(self, expr): return expr.is_Add def value(self, add): for term in add.args: if term.is_number or term in self.bounds or len(term.free_symbols) != 1: continue fs, = term.free_symbols if fs not in self.bounds: continue intrvl = Interval(*self.bounds[fs]) if is_increasing(term, intrvl, fs): self.bounds[term] = ( term.subs({fs: self.bounds[fs][0]}), term.subs({fs: self.bounds[fs][1]}) ) elif is_decreasing(term, intrvl, fs): self.bounds[term] = ( term.subs({fs: self.bounds[fs][1]}), term.subs({fs: self.bounds[fs][0]}) ) else: return add if all(term.is_number or term in self.bounds for term in add.args): bounds = [(term, term) if term.is_number else self.bounds[term] for term in add.args] largest_abs_guarantee = 0 for lo, hi in bounds: if lo <= 0 <= hi: continue largest_abs_guarantee = max(largest_abs_guarantee, min(abs(lo), abs(hi))) new_terms = [] for term, (lo, hi) in zip(add.args, bounds): if max(abs(lo), abs(hi)) >= largest_abs_guarantee*self.reltol: new_terms.append(term) return add.func(*new_terms) else: return add class SeriesApprox(Optimization): """ Approximates functions by expanding them as a series. Parameters ========== bounds : dict Mapping expressions to length 2 tuple of bounds (low, high). reltol : number Threshold for when to ignore a term. Taken relative to the largest lower bound among bounds. max_order : int Largest order to include in series expansion n_point_checks : int (even) The validity of an expansion (with respect to reltol) is checked at discrete points (linearly spaced over the bounds of the variable). The number of points used in this numerical check is given by this number. Examples ======== >>> from sympy import sin, pi >>> from sympy.abc import x, y >>> from sympy.codegen.rewriting import optimize >>> from sympy.codegen.approximations import SeriesApprox >>> bounds = {x: (-.1, .1), y: (pi-1, pi+1)} >>> series_approx2 = SeriesApprox(bounds, reltol=1e-2) >>> series_approx3 = SeriesApprox(bounds, reltol=1e-3) >>> series_approx8 = SeriesApprox(bounds, reltol=1e-8) >>> expr = sin(x)*sin(y) >>> optimize(expr, [series_approx2]) x*(-y + (y - pi)**3/6 + pi) >>> optimize(expr, [series_approx3]) (-x**3/6 + x)*sin(y) >>> optimize(expr, [series_approx8]) sin(x)*sin(y) """ def __init__(self, bounds, reltol, max_order=4, n_point_checks=4, **kwargs): super().__init__(**kwargs) self.bounds = bounds self.reltol = reltol self.max_order = max_order if n_point_checks % 2 == 1: raise ValueError("Checking the solution at expansion point is not helpful") self.n_point_checks = n_point_checks self._prec = math.ceil(-math.log10(self.reltol)) def __call__(self, expr): return expr.factor().replace(self.query, lambda arg: self.value(arg)) def query(self, expr): return (expr.is_Function and not isinstance(expr, UndefinedFunction) and len(expr.args) == 1) def value(self, fexpr): free_symbols = fexpr.free_symbols if len(free_symbols) != 1: return fexpr symb, = free_symbols if symb not in self.bounds: return fexpr lo, hi = self.bounds[symb] x0 = (lo + hi)/2 cheapest = None for n in range(self.max_order+1, 0, -1): fseri = fexpr.series(symb, x0=x0, n=n).removeO() n_ok = True for idx in range(self.n_point_checks): x = lo + idx*(hi - lo)/(self.n_point_checks - 1) val = fseri.xreplace({symb: x}) ref = fexpr.xreplace({symb: x}) if abs((1 - val/ref).evalf(self._prec)) > self.reltol: n_ok = False break if n_ok: cheapest = fseri else: break if cheapest is None: return fexpr else: return cheapest sympy-sympy-1.9/sympy/codegen/array_utils.py000066400000000000000000000017501412543434000214230ustar00rootroot00000000000000from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayContraction, ArrayAdd, \ ArrayDiagonal from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix from sympy.tensor.array.expressions.conv_indexed_to_array import convert_indexed_to_array from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="Array expressions inside the codegen module", useinstead="Experimental module in sympy.tensor.array.expressions", issue=20996, deprecated_since_version="1.8" ).warn() CodegenArrayTensorProduct = ArrayTensorProduct CodegenArrayContraction = ArrayContraction CodegenArrayElementwiseAdd = ArrayAdd CodegenArrayDiagonal = ArrayDiagonal recognize_matrix_expression = convert_array_to_matrix parse_matrix_expression = convert_matrix_to_array parse_indexed_expression = convert_indexed_to_array sympy-sympy-1.9/sympy/codegen/ast.py000066400000000000000000001533551412543434000176650ustar00rootroot00000000000000""" Types used to represent a full function/module as an Abstract Syntax Tree. Most types are small, and are merely used as tokens in the AST. A tree diagram has been included below to illustrate the relationships between the AST types. AST Type Tree ------------- :: *Basic* |--->AssignmentBase | |--->Assignment | |--->AugmentedAssignment | |--->AddAugmentedAssignment | |--->SubAugmentedAssignment | |--->MulAugmentedAssignment | |--->DivAugmentedAssignment | |--->ModAugmentedAssignment | |--->CodeBlock | | |--->Token | |--->Attribute | |--->For | |--->String | | |--->QuotedString | | |--->Comment | |--->Type | | |--->IntBaseType | | | |--->_SizedIntType | | | |--->SignedIntType | | | |--->UnsignedIntType | | |--->FloatBaseType | | |--->FloatType | | |--->ComplexBaseType | | |--->ComplexType | |--->Node | | |--->Variable | | | |---> Pointer | | |--->FunctionPrototype | | |--->FunctionDefinition | |--->Element | |--->Declaration | |--->While | |--->Scope | |--->Stream | |--->Print | |--->FunctionCall | |--->BreakToken | |--->ContinueToken | |--->NoneToken | |--->Statement |--->Return Predefined types ---------------- A number of ``Type`` instances are provided in the ``sympy.codegen.ast`` module for convenience. Perhaps the two most common ones for code-generation (of numeric codes) are ``float32`` and ``float64`` (known as single and double precision respectively). There are also precision generic versions of Types (for which the codeprinters selects the underlying data type at time of printing): ``real``, ``integer``, ``complex_``, ``bool_``. The other ``Type`` instances defined are: - ``intc``: Integer type used by C's "int". - ``intp``: Integer type used by C's "unsigned". - ``int8``, ``int16``, ``int32``, ``int64``: n-bit integers. - ``uint8``, ``uint16``, ``uint32``, ``uint64``: n-bit unsigned integers. - ``float80``: known as "extended precision" on modern x86/amd64 hardware. - ``complex64``: Complex number represented by two ``float32`` numbers - ``complex128``: Complex number represented by two ``float64`` numbers Using the nodes --------------- It is possible to construct simple algorithms using the AST nodes. Let's construct a loop applying Newton's method:: >>> from sympy import symbols, cos >>> from sympy.codegen.ast import While, Assignment, aug_assign, Print >>> t, dx, x = symbols('tol delta val') >>> expr = cos(x) - x**3 >>> whl = While(abs(dx) > t, [ ... Assignment(dx, -expr/expr.diff(x)), ... aug_assign(x, '+', dx), ... Print([x]) ... ]) >>> from sympy.printing import pycode >>> py_str = pycode(whl) >>> print(py_str) while (abs(delta) > tol): delta = (val**3 - math.cos(val))/(-3*val**2 - math.sin(val)) val += delta print(val) >>> import math >>> tol, val, delta = 1e-5, 0.5, float('inf') >>> exec(py_str) 1.1121416371 0.909672693737 0.867263818209 0.865477135298 0.865474033111 >>> print('%3.1g' % (math.cos(val) - val**3)) -3e-11 If we want to generate Fortran code for the same while loop we simple call ``fcode``:: >>> from sympy.printing import fcode >>> print(fcode(whl, standard=2003, source_format='free')) do while (abs(delta) > tol) delta = (val**3 - cos(val))/(-3*val**2 - sin(val)) val = val + delta print *, val end do There is a function constructing a loop (or a complete function) like this in :mod:`sympy.codegen.algorithms`. """ from typing import Any, Dict, List from collections import defaultdict from sympy import Lt, Le, Ge, Gt from sympy.core import Symbol, Tuple, Dummy from sympy.core.basic import Basic from sympy.core.expr import Expr from sympy.core.numbers import Float, Integer, oo from sympy.core.sympify import _sympify, sympify, SympifyError from sympy.utilities.iterables import iterable def _mk_Tuple(args): """ Create a Sympy Tuple object from an iterable, converting Python strings to AST strings. Parameters ========== args: iterable Arguments to :class:`sympy.Tuple`. Returns ======= sympy.Tuple """ args = [String(arg) if isinstance(arg, str) else arg for arg in args] return Tuple(*args) class Token(Basic): """ Base class for the AST types. Explanation =========== Defining fields are set in ``__slots__``. Attributes (defined in __slots__) are only allowed to contain instances of Basic (unless atomic, see ``String``). The arguments to ``__new__()`` correspond to the attributes in the order defined in ``__slots__`. The ``defaults`` class attribute is a dictionary mapping attribute names to their default values. Subclasses should not need to override the ``__new__()`` method. They may define a class or static method named ``_construct_`` for each attribute to process the value passed to ``__new__()``. Attributes listed in the class attribute ``not_in_args`` are not passed to :class:`~.Basic`. """ __slots__ = () defaults = {} # type: Dict[str, Any] not_in_args = [] # type: List[str] indented_args = ['body'] @property def is_Atom(self): return len(self.__slots__) == 0 @classmethod def _get_constructor(cls, attr): """ Get the constructor function for an attribute by name. """ return getattr(cls, '_construct_%s' % attr, lambda x: x) @classmethod def _construct(cls, attr, arg): """ Construct an attribute value from argument passed to ``__new__()``. """ # arg may be ``NoneToken()``, so comparation is done using == instead of ``is`` operator if arg == None: return cls.defaults.get(attr, none) else: if isinstance(arg, Dummy): # sympy's replace uses Dummy instances return arg else: return cls._get_constructor(attr)(arg) def __new__(cls, *args, **kwargs): # Pass through existing instances when given as sole argument if len(args) == 1 and not kwargs and isinstance(args[0], cls): return args[0] if len(args) > len(cls.__slots__): raise ValueError("Too many arguments (%d), expected at most %d" % (len(args), len(cls.__slots__))) attrvals = [] # Process positional arguments for attrname, argval in zip(cls.__slots__, args): if attrname in kwargs: raise TypeError('Got multiple values for attribute %r' % attrname) attrvals.append(cls._construct(attrname, argval)) # Process keyword arguments for attrname in cls.__slots__[len(args):]: if attrname in kwargs: argval = kwargs.pop(attrname) elif attrname in cls.defaults: argval = cls.defaults[attrname] else: raise TypeError('No value for %r given and attribute has no default' % attrname) attrvals.append(cls._construct(attrname, argval)) if kwargs: raise ValueError("Unknown keyword arguments: %s" % ' '.join(kwargs)) # Parent constructor basic_args = [ val for attr, val in zip(cls.__slots__, attrvals) if attr not in cls.not_in_args ] obj = Basic.__new__(cls, *basic_args) # Set attributes for attr, arg in zip(cls.__slots__, attrvals): setattr(obj, attr, arg) return obj def __eq__(self, other): if not isinstance(other, self.__class__): return False for attr in self.__slots__: if getattr(self, attr) != getattr(other, attr): return False return True def _hashable_content(self): return tuple([getattr(self, attr) for attr in self.__slots__]) def __hash__(self): return super().__hash__() def _joiner(self, k, indent_level): return (',\n' + ' '*indent_level) if k in self.indented_args else ', ' def _indented(self, printer, k, v, *args, **kwargs): il = printer._context['indent_level'] def _print(arg): if isinstance(arg, Token): return printer._print(arg, *args, joiner=self._joiner(k, il), **kwargs) else: return printer._print(arg, *args, **kwargs) if isinstance(v, Tuple): joined = self._joiner(k, il).join([_print(arg) for arg in v.args]) if k in self.indented_args: return '(\n' + ' '*il + joined + ',\n' + ' '*(il - 4) + ')' else: return ('({0},)' if len(v.args) == 1 else '({0})').format(joined) else: return _print(v) def _sympyrepr(self, printer, *args, joiner=', ', **kwargs): from sympy.printing.printer import printer_context exclude = kwargs.get('exclude', ()) values = [getattr(self, k) for k in self.__slots__] indent_level = printer._context.get('indent_level', 0) arg_reprs = [] for i, (attr, value) in enumerate(zip(self.__slots__, values)): if attr in exclude: continue # Skip attributes which have the default value if attr in self.defaults and value == self.defaults[attr]: continue ilvl = indent_level + 4 if attr in self.indented_args else 0 with printer_context(printer, indent_level=ilvl): indented = self._indented(printer, attr, value, *args, **kwargs) arg_reprs.append(('{1}' if i == 0 else '{0}={1}').format(attr, indented.lstrip())) return "{}({})".format(self.__class__.__name__, joiner.join(arg_reprs)) _sympystr = _sympyrepr def __repr__(self): # sympy.core.Basic.__repr__ uses sstr from sympy.printing import srepr return srepr(self) def kwargs(self, exclude=(), apply=None): """ Get instance's attributes as dict of keyword arguments. Parameters ========== exclude : collection of str Collection of keywords to exclude. apply : callable, optional Function to apply to all values. """ kwargs = {k: getattr(self, k) for k in self.__slots__ if k not in exclude} if apply is not None: return {k: apply(v) for k, v in kwargs.items()} else: return kwargs class BreakToken(Token): """ Represents 'break' in C/Python ('exit' in Fortran). Use the premade instance ``break_`` or instantiate manually. Examples ======== >>> from sympy.printing import ccode, fcode >>> from sympy.codegen.ast import break_ >>> ccode(break_) 'break' >>> fcode(break_, source_format='free') 'exit' """ break_ = BreakToken() class ContinueToken(Token): """ Represents 'continue' in C/Python ('cycle' in Fortran) Use the premade instance ``continue_`` or instantiate manually. Examples ======== >>> from sympy.printing import ccode, fcode >>> from sympy.codegen.ast import continue_ >>> ccode(continue_) 'continue' >>> fcode(continue_, source_format='free') 'cycle' """ continue_ = ContinueToken() class NoneToken(Token): """ The AST equivalence of Python's NoneType The corresponding instance of Python's ``None`` is ``none``. Examples ======== >>> from sympy.codegen.ast import none, Variable >>> from sympy.printing.pycode import pycode >>> print(pycode(Variable('x').as_Declaration(value=none))) x = None """ def __eq__(self, other): return other is None or isinstance(other, NoneToken) def _hashable_content(self): return () def __hash__(self): return super().__hash__() none = NoneToken() class AssignmentBase(Basic): """ Abstract base class for Assignment and AugmentedAssignment. Attributes: =========== op : str Symbol for assignment operator, e.g. "=", "+=", etc. """ def __new__(cls, lhs, rhs): lhs = _sympify(lhs) rhs = _sympify(rhs) cls._check_args(lhs, rhs) return super().__new__(cls, lhs, rhs) @property def lhs(self): return self.args[0] @property def rhs(self): return self.args[1] @classmethod def _check_args(cls, lhs, rhs): """ Check arguments to __new__ and raise exception if any problems found. Derived classes may wish to override this. """ from sympy.matrices.expressions.matexpr import ( MatrixElement, MatrixSymbol) from sympy.tensor.indexed import Indexed # Tuple of things that can be on the lhs of an assignment assignable = (Symbol, MatrixSymbol, MatrixElement, Indexed, Element, Variable) if not isinstance(lhs, assignable): raise TypeError("Cannot assign to lhs of type %s." % type(lhs)) # Indexed types implement shape, but don't define it until later. This # causes issues in assignment validation. For now, matrices are defined # as anything with a shape that is not an Indexed lhs_is_mat = hasattr(lhs, 'shape') and not isinstance(lhs, Indexed) rhs_is_mat = hasattr(rhs, 'shape') and not isinstance(rhs, Indexed) # If lhs and rhs have same structure, then this assignment is ok if lhs_is_mat: if not rhs_is_mat: raise ValueError("Cannot assign a scalar to a matrix.") elif lhs.shape != rhs.shape: raise ValueError("Dimensions of lhs and rhs don't align.") elif rhs_is_mat and not lhs_is_mat: raise ValueError("Cannot assign a matrix to a scalar.") class Assignment(AssignmentBase): """ Represents variable assignment for code generation. Parameters ========== lhs : Expr Sympy object representing the lhs of the expression. These should be singular objects, such as one would use in writing code. Notable types include Symbol, MatrixSymbol, MatrixElement, and Indexed. Types that subclass these types are also supported. rhs : Expr Sympy object representing the rhs of the expression. This can be any type, provided its shape corresponds to that of the lhs. For example, a Matrix type can be assigned to MatrixSymbol, but not to Symbol, as the dimensions will not align. Examples ======== >>> from sympy import symbols, MatrixSymbol, Matrix >>> from sympy.codegen.ast import Assignment >>> x, y, z = symbols('x, y, z') >>> Assignment(x, y) Assignment(x, y) >>> Assignment(x, 0) Assignment(x, 0) >>> A = MatrixSymbol('A', 1, 3) >>> mat = Matrix([x, y, z]).T >>> Assignment(A, mat) Assignment(A, Matrix([[x, y, z]])) >>> Assignment(A[0, 1], x) Assignment(A[0, 1], x) """ op = ':=' class AugmentedAssignment(AssignmentBase): """ Base class for augmented assignments. Attributes: =========== binop : str Symbol for binary operation being applied in the assignment, such as "+", "*", etc. """ binop = None # type: str @property def op(self): return self.binop + '=' class AddAugmentedAssignment(AugmentedAssignment): binop = '+' class SubAugmentedAssignment(AugmentedAssignment): binop = '-' class MulAugmentedAssignment(AugmentedAssignment): binop = '*' class DivAugmentedAssignment(AugmentedAssignment): binop = '/' class ModAugmentedAssignment(AugmentedAssignment): binop = '%' # Mapping from binary op strings to AugmentedAssignment subclasses augassign_classes = { cls.binop: cls for cls in [ AddAugmentedAssignment, SubAugmentedAssignment, MulAugmentedAssignment, DivAugmentedAssignment, ModAugmentedAssignment ] } def aug_assign(lhs, op, rhs): """ Create 'lhs op= rhs'. Explanation =========== Represents augmented variable assignment for code generation. This is a convenience function. You can also use the AugmentedAssignment classes directly, like AddAugmentedAssignment(x, y). Parameters ========== lhs : Expr Sympy object representing the lhs of the expression. These should be singular objects, such as one would use in writing code. Notable types include Symbol, MatrixSymbol, MatrixElement, and Indexed. Types that subclass these types are also supported. op : str Operator (+, -, /, \\*, %). rhs : Expr Sympy object representing the rhs of the expression. This can be any type, provided its shape corresponds to that of the lhs. For example, a Matrix type can be assigned to MatrixSymbol, but not to Symbol, as the dimensions will not align. Examples ======== >>> from sympy import symbols >>> from sympy.codegen.ast import aug_assign >>> x, y = symbols('x, y') >>> aug_assign(x, '+', y) AddAugmentedAssignment(x, y) """ if op not in augassign_classes: raise ValueError("Unrecognized operator %s" % op) return augassign_classes[op](lhs, rhs) class CodeBlock(Basic): """ Represents a block of code. Explanation =========== For now only assignments are supported. This restriction will be lifted in the future. Useful attributes on this object are: ``left_hand_sides``: Tuple of left-hand sides of assignments, in order. ``left_hand_sides``: Tuple of right-hand sides of assignments, in order. ``free_symbols``: Free symbols of the expressions in the right-hand sides which do not appear in the left-hand side of an assignment. Useful methods on this object are: ``topological_sort``: Class method. Return a CodeBlock with assignments sorted so that variables are assigned before they are used. ``cse``: Return a new CodeBlock with common subexpressions eliminated and pulled out as assignments. Examples ======== >>> from sympy import symbols, ccode >>> from sympy.codegen.ast import CodeBlock, Assignment >>> x, y = symbols('x y') >>> c = CodeBlock(Assignment(x, 1), Assignment(y, x + 1)) >>> print(ccode(c)) x = 1; y = x + 1; """ def __new__(cls, *args): left_hand_sides = [] right_hand_sides = [] for i in args: if isinstance(i, Assignment): lhs, rhs = i.args left_hand_sides.append(lhs) right_hand_sides.append(rhs) obj = Basic.__new__(cls, *args) obj.left_hand_sides = Tuple(*left_hand_sides) obj.right_hand_sides = Tuple(*right_hand_sides) return obj def __iter__(self): return iter(self.args) def _sympyrepr(self, printer, *args, **kwargs): il = printer._context.get('indent_level', 0) joiner = ',\n' + ' '*il joined = joiner.join(map(printer._print, self.args)) return ('{}(\n'.format(' '*(il-4) + self.__class__.__name__,) + ' '*il + joined + '\n' + ' '*(il - 4) + ')') _sympystr = _sympyrepr @property def free_symbols(self): return super().free_symbols - set(self.left_hand_sides) @classmethod def topological_sort(cls, assignments): """ Return a CodeBlock with topologically sorted assignments so that variables are assigned before they are used. Examples ======== The existing order of assignments is preserved as much as possible. This function assumes that variables are assigned to only once. This is a class constructor so that the default constructor for CodeBlock can error when variables are used before they are assigned. Examples ======== >>> from sympy import symbols >>> from sympy.codegen.ast import CodeBlock, Assignment >>> x, y, z = symbols('x y z') >>> assignments = [ ... Assignment(x, y + z), ... Assignment(y, z + 1), ... Assignment(z, 2), ... ] >>> CodeBlock.topological_sort(assignments) CodeBlock( Assignment(z, 2), Assignment(y, z + 1), Assignment(x, y + z) ) """ from sympy.utilities.iterables import topological_sort if not all(isinstance(i, Assignment) for i in assignments): # Will support more things later raise NotImplementedError("CodeBlock.topological_sort only supports Assignments") if any(isinstance(i, AugmentedAssignment) for i in assignments): raise NotImplementedError("CodeBlock.topological_sort doesn't yet work with AugmentedAssignments") # Create a graph where the nodes are assignments and there is a directed edge # between nodes that use a variable and nodes that assign that # variable, like # [(x := 1, y := x + 1), (x := 1, z := y + z), (y := x + 1, z := y + z)] # If we then topologically sort these nodes, they will be in # assignment order, like # x := 1 # y := x + 1 # z := y + z # A = The nodes # # enumerate keeps nodes in the same order they are already in if # possible. It will also allow us to handle duplicate assignments to # the same variable when those are implemented. A = list(enumerate(assignments)) # var_map = {variable: [nodes for which this variable is assigned to]} # like {x: [(1, x := y + z), (4, x := 2 * w)], ...} var_map = defaultdict(list) for node in A: i, a = node var_map[a.lhs].append(node) # E = Edges in the graph E = [] for dst_node in A: i, a = dst_node for s in a.rhs.free_symbols: for src_node in var_map[s]: E.append((src_node, dst_node)) ordered_assignments = topological_sort([A, E]) # De-enumerate the result return cls(*[a for i, a in ordered_assignments]) def cse(self, symbols=None, optimizations=None, postprocess=None, order='canonical'): """ Return a new code block with common subexpressions eliminated. Explanation =========== See the docstring of :func:`sympy.simplify.cse_main.cse` for more information. Examples ======== >>> from sympy import symbols, sin >>> from sympy.codegen.ast import CodeBlock, Assignment >>> x, y, z = symbols('x y z') >>> c = CodeBlock( ... Assignment(x, 1), ... Assignment(y, sin(x) + 1), ... Assignment(z, sin(x) - 1), ... ) ... >>> c.cse() CodeBlock( Assignment(x, 1), Assignment(x0, sin(x)), Assignment(y, x0 + 1), Assignment(z, x0 - 1) ) """ from sympy.simplify.cse_main import cse from sympy.utilities.iterables import numbered_symbols, filter_symbols # Check that the CodeBlock only contains assignments to unique variables if not all(isinstance(i, Assignment) for i in self.args): # Will support more things later raise NotImplementedError("CodeBlock.cse only supports Assignments") if any(isinstance(i, AugmentedAssignment) for i in self.args): raise NotImplementedError("CodeBlock.cse doesn't yet work with AugmentedAssignments") for i, lhs in enumerate(self.left_hand_sides): if lhs in self.left_hand_sides[:i]: raise NotImplementedError("Duplicate assignments to the same " "variable are not yet supported (%s)" % lhs) # Ensure new symbols for subexpressions do not conflict with existing existing_symbols = self.atoms(Symbol) if symbols is None: symbols = numbered_symbols() symbols = filter_symbols(symbols, existing_symbols) replacements, reduced_exprs = cse(list(self.right_hand_sides), symbols=symbols, optimizations=optimizations, postprocess=postprocess, order=order) new_block = [Assignment(var, expr) for var, expr in zip(self.left_hand_sides, reduced_exprs)] new_assignments = [Assignment(var, expr) for var, expr in replacements] return self.topological_sort(new_assignments + new_block) class For(Token): """Represents a 'for-loop' in the code. Expressions are of the form: "for target in iter: body..." Parameters ========== target : symbol iter : iterable body : CodeBlock or iterable ! When passed an iterable it is used to instantiate a CodeBlock. Examples ======== >>> from sympy import symbols, Range >>> from sympy.codegen.ast import aug_assign, For >>> x, i, j, k = symbols('x i j k') >>> for_i = For(i, Range(10), [aug_assign(x, '+', i*j*k)]) >>> for_i # doctest: -NORMALIZE_WHITESPACE For(i, iterable=Range(0, 10, 1), body=CodeBlock( AddAugmentedAssignment(x, i*j*k) )) >>> for_ji = For(j, Range(7), [for_i]) >>> for_ji # doctest: -NORMALIZE_WHITESPACE For(j, iterable=Range(0, 7, 1), body=CodeBlock( For(i, iterable=Range(0, 10, 1), body=CodeBlock( AddAugmentedAssignment(x, i*j*k) )) )) >>> for_kji =For(k, Range(5), [for_ji]) >>> for_kji # doctest: -NORMALIZE_WHITESPACE For(k, iterable=Range(0, 5, 1), body=CodeBlock( For(j, iterable=Range(0, 7, 1), body=CodeBlock( For(i, iterable=Range(0, 10, 1), body=CodeBlock( AddAugmentedAssignment(x, i*j*k) )) )) )) """ __slots__ = ('target', 'iterable', 'body') _construct_target = staticmethod(_sympify) @classmethod def _construct_body(cls, itr): if isinstance(itr, CodeBlock): return itr else: return CodeBlock(*itr) @classmethod def _construct_iterable(cls, itr): if not iterable(itr): raise TypeError("iterable must be an iterable") if isinstance(itr, list): # _sympify errors on lists because they are mutable itr = tuple(itr) return _sympify(itr) class String(Token): """ SymPy object representing a string. Atomic object which is not an expression (as opposed to Symbol). Parameters ========== text : str Examples ======== >>> from sympy.codegen.ast import String >>> f = String('foo') >>> f foo >>> str(f) 'foo' >>> f.text 'foo' >>> print(repr(f)) String('foo') """ __slots__ = ('text',) not_in_args = ['text'] is_Atom = True @classmethod def _construct_text(cls, text): if not isinstance(text, str): raise TypeError("Argument text is not a string type.") return text def _sympystr(self, printer, *args, **kwargs): return self.text class QuotedString(String): """ Represents a string which should be printed with quotes. """ class Comment(String): """ Represents a comment. """ class Node(Token): """ Subclass of Token, carrying the attribute 'attrs' (Tuple) Examples ======== >>> from sympy.codegen.ast import Node, value_const, pointer_const >>> n1 = Node([value_const]) >>> n1.attr_params('value_const') # get the parameters of attribute (by name) () >>> from sympy.codegen.fnodes import dimension >>> n2 = Node([value_const, dimension(5, 3)]) >>> n2.attr_params(value_const) # get the parameters of attribute (by Attribute instance) () >>> n2.attr_params('dimension') # get the parameters of attribute (by name) (5, 3) >>> n2.attr_params(pointer_const) is None True """ __slots__ = ('attrs',) defaults = {'attrs': Tuple()} # type: Dict[str, Any] _construct_attrs = staticmethod(_mk_Tuple) def attr_params(self, looking_for): """ Returns the parameters of the Attribute with name ``looking_for`` in self.attrs """ for attr in self.attrs: if str(attr.name) == str(looking_for): return attr.parameters class Type(Token): """ Represents a type. Explanation =========== The naming is a super-set of NumPy naming. Type has a classmethod ``from_expr`` which offer type deduction. It also has a method ``cast_check`` which casts the argument to its type, possibly raising an exception if rounding error is not within tolerances, or if the value is not representable by the underlying data type (e.g. unsigned integers). Parameters ========== name : str Name of the type, e.g. ``object``, ``int16``, ``float16`` (where the latter two would use the ``Type`` sub-classes ``IntType`` and ``FloatType`` respectively). If a ``Type`` instance is given, the said instance is returned. Examples ======== >>> from sympy.codegen.ast import Type >>> t = Type.from_expr(42) >>> t integer >>> print(repr(t)) IntBaseType(String('integer')) >>> from sympy.codegen.ast import uint8 >>> uint8.cast_check(-1) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Minimum value for data type bigger than new value. >>> from sympy.codegen.ast import float32 >>> v6 = 0.123456 >>> float32.cast_check(v6) 0.123456 >>> v10 = 12345.67894 >>> float32.cast_check(v10) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Casting gives a significantly different value. >>> boost_mp50 = Type('boost::multiprecision::cpp_dec_float_50') >>> from sympy.printing import cxxcode >>> from sympy.codegen.ast import Declaration, Variable >>> cxxcode(Declaration(Variable('x', type=boost_mp50))) 'boost::multiprecision::cpp_dec_float_50 x' References ========== .. [1] https://docs.scipy.org/doc/numpy/user/basics.types.html """ __slots__ = ('name',) _construct_name = String def _sympystr(self, printer, *args, **kwargs): return str(self.name) @classmethod def from_expr(cls, expr): """ Deduces type from an expression or a ``Symbol``. Parameters ========== expr : number or SymPy object The type will be deduced from type or properties. Examples ======== >>> from sympy.codegen.ast import Type, integer, complex_ >>> Type.from_expr(2) == integer True >>> from sympy import Symbol >>> Type.from_expr(Symbol('z', complex=True)) == complex_ True >>> Type.from_expr(sum) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Could not deduce type from expr. Raises ====== ValueError when type deduction fails. """ if isinstance(expr, (float, Float)): return real if isinstance(expr, (int, Integer)) or getattr(expr, 'is_integer', False): return integer if getattr(expr, 'is_real', False): return real if isinstance(expr, complex) or getattr(expr, 'is_complex', False): return complex_ if isinstance(expr, bool) or getattr(expr, 'is_Relational', False): return bool_ else: raise ValueError("Could not deduce type from expr.") def _check(self, value): pass def cast_check(self, value, rtol=None, atol=0, precision_targets=None): """ Casts a value to the data type of the instance. Parameters ========== value : number rtol : floating point number Relative tolerance. (will be deduced if not given). atol : floating point number Absolute tolerance (in addition to ``rtol``). type_aliases : dict Maps substitutions for Type, e.g. {integer: int64, real: float32} Examples ======== >>> from sympy.codegen.ast import integer, float32, int8 >>> integer.cast_check(3.0) == 3 True >>> float32.cast_check(1e-40) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Minimum value for data type bigger than new value. >>> int8.cast_check(256) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Maximum value for data type smaller than new value. >>> v10 = 12345.67894 >>> float32.cast_check(v10) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Casting gives a significantly different value. >>> from sympy.codegen.ast import float64 >>> float64.cast_check(v10) 12345.67894 >>> from sympy import Float >>> v18 = Float('0.123456789012345646') >>> float64.cast_check(v18) Traceback (most recent call last): ... ValueError: Casting gives a significantly different value. >>> from sympy.codegen.ast import float80 >>> float80.cast_check(v18) 0.123456789012345649 """ val = sympify(value) ten = Integer(10) exp10 = getattr(self, 'decimal_dig', None) if rtol is None: rtol = 1e-15 if exp10 is None else 2.0*ten**(-exp10) def tol(num): return atol + rtol*abs(num) new_val = self.cast_nocheck(value) self._check(new_val) delta = new_val - val if abs(delta) > tol(val): # rounding, e.g. int(3.5) != 3.5 raise ValueError("Casting gives a significantly different value.") return new_val class IntBaseType(Type): """ Integer base type, contains no size information. """ __slots__ = ('name',) cast_nocheck = lambda self, i: Integer(int(i)) class _SizedIntType(IntBaseType): __slots__ = ('name', 'nbits',) _construct_nbits = Integer def _check(self, value): if value < self.min: raise ValueError("Value is too small: %d < %d" % (value, self.min)) if value > self.max: raise ValueError("Value is too big: %d > %d" % (value, self.max)) class SignedIntType(_SizedIntType): """ Represents a signed integer type. """ @property def min(self): return -2**(self.nbits-1) @property def max(self): return 2**(self.nbits-1) - 1 class UnsignedIntType(_SizedIntType): """ Represents an unsigned integer type. """ @property def min(self): return 0 @property def max(self): return 2**self.nbits - 1 two = Integer(2) class FloatBaseType(Type): """ Represents a floating point number type. """ cast_nocheck = Float class FloatType(FloatBaseType): """ Represents a floating point type with fixed bit width. Base 2 & one sign bit is assumed. Parameters ========== name : str Name of the type. nbits : integer Number of bits used (storage). nmant : integer Number of bits used to represent the mantissa. nexp : integer Number of bits used to represent the mantissa. Examples ======== >>> from sympy import S >>> from sympy.codegen.ast import FloatType >>> half_precision = FloatType('f16', nbits=16, nmant=10, nexp=5) >>> half_precision.max 65504 >>> half_precision.tiny == S(2)**-14 True >>> half_precision.eps == S(2)**-10 True >>> half_precision.dig == 3 True >>> half_precision.decimal_dig == 5 True >>> half_precision.cast_check(1.0) 1.0 >>> half_precision.cast_check(1e5) # doctest: +ELLIPSIS Traceback (most recent call last): ... ValueError: Maximum value for data type smaller than new value. """ __slots__ = ('name', 'nbits', 'nmant', 'nexp',) _construct_nbits = _construct_nmant = _construct_nexp = Integer @property def max_exponent(self): """ The largest positive number n, such that 2**(n - 1) is a representable finite value. """ # cf. C++'s ``std::numeric_limits::max_exponent`` return two**(self.nexp - 1) @property def min_exponent(self): """ The lowest negative number n, such that 2**(n - 1) is a valid normalized number. """ # cf. C++'s ``std::numeric_limits::min_exponent`` return 3 - self.max_exponent @property def max(self): """ Maximum value representable. """ return (1 - two**-(self.nmant+1))*two**self.max_exponent @property def tiny(self): """ The minimum positive normalized value. """ # See C macros: FLT_MIN, DBL_MIN, LDBL_MIN # or C++'s ``std::numeric_limits::min`` # or numpy.finfo(dtype).tiny return two**(self.min_exponent - 1) @property def eps(self): """ Difference between 1.0 and the next representable value. """ return two**(-self.nmant) @property def dig(self): """ Number of decimal digits that are guaranteed to be preserved in text. When converting text -> float -> text, you are guaranteed that at least ``dig`` number of digits are preserved with respect to rounding or overflow. """ from sympy.functions import floor, log return floor(self.nmant * log(2)/log(10)) @property def decimal_dig(self): """ Number of digits needed to store & load without loss. Explanation =========== Number of decimal digits needed to guarantee that two consecutive conversions (float -> text -> float) to be idempotent. This is useful when one do not want to loose precision due to rounding errors when storing a floating point value as text. """ from sympy.functions import ceiling, log return ceiling((self.nmant + 1) * log(2)/log(10) + 1) def cast_nocheck(self, value): """ Casts without checking if out of bounds or subnormal. """ if value == oo: # float(oo) or oo return float(oo) elif value == -oo: # float(-oo) or -oo return float(-oo) return Float(str(sympify(value).evalf(self.decimal_dig)), self.decimal_dig) def _check(self, value): if value < -self.max: raise ValueError("Value is too small: %d < %d" % (value, -self.max)) if value > self.max: raise ValueError("Value is too big: %d > %d" % (value, self.max)) if abs(value) < self.tiny: raise ValueError("Smallest (absolute) value for data type bigger than new value.") class ComplexBaseType(FloatBaseType): def cast_nocheck(self, value): """ Casts without checking if out of bounds or subnormal. """ from sympy.functions import re, im return ( super().cast_nocheck(re(value)) + super().cast_nocheck(im(value))*1j ) def _check(self, value): from sympy.functions import re, im super()._check(re(value)) super()._check(im(value)) class ComplexType(ComplexBaseType, FloatType): """ Represents a complex floating point number. """ # NumPy types: intc = IntBaseType('intc') intp = IntBaseType('intp') int8 = SignedIntType('int8', 8) int16 = SignedIntType('int16', 16) int32 = SignedIntType('int32', 32) int64 = SignedIntType('int64', 64) uint8 = UnsignedIntType('uint8', 8) uint16 = UnsignedIntType('uint16', 16) uint32 = UnsignedIntType('uint32', 32) uint64 = UnsignedIntType('uint64', 64) float16 = FloatType('float16', 16, nexp=5, nmant=10) # IEEE 754 binary16, Half precision float32 = FloatType('float32', 32, nexp=8, nmant=23) # IEEE 754 binary32, Single precision float64 = FloatType('float64', 64, nexp=11, nmant=52) # IEEE 754 binary64, Double precision float80 = FloatType('float80', 80, nexp=15, nmant=63) # x86 extended precision (1 integer part bit), "long double" float128 = FloatType('float128', 128, nexp=15, nmant=112) # IEEE 754 binary128, Quadruple precision float256 = FloatType('float256', 256, nexp=19, nmant=236) # IEEE 754 binary256, Octuple precision complex64 = ComplexType('complex64', nbits=64, **float32.kwargs(exclude=('name', 'nbits'))) complex128 = ComplexType('complex128', nbits=128, **float64.kwargs(exclude=('name', 'nbits'))) # Generic types (precision may be chosen by code printers): untyped = Type('untyped') real = FloatBaseType('real') integer = IntBaseType('integer') complex_ = ComplexBaseType('complex') bool_ = Type('bool') class Attribute(Token): """ Attribute (possibly parametrized) For use with :class:`sympy.codegen.ast.Node` (which takes instances of ``Attribute`` as ``attrs``). Parameters ========== name : str parameters : Tuple Examples ======== >>> from sympy.codegen.ast import Attribute >>> volatile = Attribute('volatile') >>> volatile volatile >>> print(repr(volatile)) Attribute(String('volatile')) >>> a = Attribute('foo', [1, 2, 3]) >>> a foo(1, 2, 3) >>> a.parameters == (1, 2, 3) True """ __slots__ = ('name', 'parameters') defaults = {'parameters': Tuple()} _construct_name = String _construct_parameters = staticmethod(_mk_Tuple) def _sympystr(self, printer, *args, **kwargs): result = str(self.name) if self.parameters: result += '(%s)' % ', '.join(map(lambda arg: printer._print( arg, *args, **kwargs), self.parameters)) return result value_const = Attribute('value_const') pointer_const = Attribute('pointer_const') class Variable(Node): """ Represents a variable. Parameters ========== symbol : Symbol type : Type (optional) Type of the variable. attrs : iterable of Attribute instances Will be stored as a Tuple. Examples ======== >>> from sympy import Symbol >>> from sympy.codegen.ast import Variable, float32, integer >>> x = Symbol('x') >>> v = Variable(x, type=float32) >>> v.attrs () >>> v == Variable('x') False >>> v == Variable('x', type=float32) True >>> v Variable(x, type=float32) One may also construct a ``Variable`` instance with the type deduced from assumptions about the symbol using the ``deduced`` classmethod: >>> i = Symbol('i', integer=True) >>> v = Variable.deduced(i) >>> v.type == integer True >>> v == Variable('i') False >>> from sympy.codegen.ast import value_const >>> value_const in v.attrs False >>> w = Variable('w', attrs=[value_const]) >>> w Variable(w, attrs=(value_const,)) >>> value_const in w.attrs True >>> w.as_Declaration(value=42) Declaration(Variable(w, value=42, attrs=(value_const,))) """ __slots__ = ('symbol', 'type', 'value') + Node.__slots__ defaults = Node.defaults.copy() defaults.update({'type': untyped, 'value': none}) _construct_symbol = staticmethod(sympify) _construct_value = staticmethod(sympify) @classmethod def deduced(cls, symbol, value=None, attrs=Tuple(), cast_check=True): """ Alt. constructor with type deduction from ``Type.from_expr``. Deduces type primarily from ``symbol``, secondarily from ``value``. Parameters ========== symbol : Symbol value : expr (optional) value of the variable. attrs : iterable of Attribute instances cast_check : bool Whether to apply ``Type.cast_check`` on ``value``. Examples ======== >>> from sympy import Symbol >>> from sympy.codegen.ast import Variable, complex_ >>> n = Symbol('n', integer=True) >>> str(Variable.deduced(n).type) 'integer' >>> x = Symbol('x', real=True) >>> v = Variable.deduced(x) >>> v.type real >>> z = Symbol('z', complex=True) >>> Variable.deduced(z).type == complex_ True """ if isinstance(symbol, Variable): return symbol try: type_ = Type.from_expr(symbol) except ValueError: type_ = Type.from_expr(value) if value is not None and cast_check: value = type_.cast_check(value) return cls(symbol, type=type_, value=value, attrs=attrs) def as_Declaration(self, **kwargs): """ Convenience method for creating a Declaration instance. Explanation =========== If the variable of the Declaration need to wrap a modified variable keyword arguments may be passed (overriding e.g. the ``value`` of the Variable instance). Examples ======== >>> from sympy.codegen.ast import Variable, NoneToken >>> x = Variable('x') >>> decl1 = x.as_Declaration() >>> # value is special NoneToken() which must be tested with == operator >>> decl1.variable.value is None # won't work False >>> decl1.variable.value == None # not PEP-8 compliant True >>> decl1.variable.value == NoneToken() # OK True >>> decl2 = x.as_Declaration(value=42.0) >>> decl2.variable.value == 42 True """ kw = self.kwargs() kw.update(kwargs) return Declaration(self.func(**kw)) def _relation(self, rhs, op): try: rhs = _sympify(rhs) except SympifyError: raise TypeError("Invalid comparison %s < %s" % (self, rhs)) return op(self, rhs, evaluate=False) __lt__ = lambda self, other: self._relation(other, Lt) __le__ = lambda self, other: self._relation(other, Le) __ge__ = lambda self, other: self._relation(other, Ge) __gt__ = lambda self, other: self._relation(other, Gt) class Pointer(Variable): """ Represents a pointer. See ``Variable``. Examples ======== Can create instances of ``Element``: >>> from sympy import Symbol >>> from sympy.codegen.ast import Pointer >>> i = Symbol('i', integer=True) >>> p = Pointer('x') >>> p[i+1] Element(x, indices=(i + 1,)) """ def __getitem__(self, key): try: return Element(self.symbol, key) except TypeError: return Element(self.symbol, (key,)) class Element(Token): """ Element in (a possibly N-dimensional) array. Examples ======== >>> from sympy.codegen.ast import Element >>> elem = Element('x', 'ijk') >>> elem.symbol.name == 'x' True >>> elem.indices (i, j, k) >>> from sympy import ccode >>> ccode(elem) 'x[i][j][k]' >>> ccode(Element('x', 'ijk', strides='lmn', offset='o')) 'x[i*l + j*m + k*n + o]' """ __slots__ = ('symbol', 'indices', 'strides', 'offset') defaults = {'strides': none, 'offset': none} _construct_symbol = staticmethod(sympify) _construct_indices = staticmethod(lambda arg: Tuple(*arg)) _construct_strides = staticmethod(lambda arg: Tuple(*arg)) _construct_offset = staticmethod(sympify) class Declaration(Token): """ Represents a variable declaration Parameters ========== variable : Variable Examples ======== >>> from sympy.codegen.ast import Declaration, NoneToken, untyped >>> z = Declaration('z') >>> z.variable.type == untyped True >>> # value is special NoneToken() which must be tested with == operator >>> z.variable.value is None # won't work False >>> z.variable.value == None # not PEP-8 compliant True >>> z.variable.value == NoneToken() # OK True """ __slots__ = ('variable',) _construct_variable = Variable class While(Token): """ Represents a 'for-loop' in the code. Expressions are of the form: "while condition: body..." Parameters ========== condition : expression convertible to Boolean body : CodeBlock or iterable When passed an iterable it is used to instantiate a CodeBlock. Examples ======== >>> from sympy import symbols, Gt, Abs >>> from sympy.codegen import aug_assign, Assignment, While >>> x, dx = symbols('x dx') >>> expr = 1 - x**2 >>> whl = While(Gt(Abs(dx), 1e-9), [ ... Assignment(dx, -expr/expr.diff(x)), ... aug_assign(x, '+', dx) ... ]) """ __slots__ = ('condition', 'body') _construct_condition = staticmethod(lambda cond: _sympify(cond)) @classmethod def _construct_body(cls, itr): if isinstance(itr, CodeBlock): return itr else: return CodeBlock(*itr) class Scope(Token): """ Represents a scope in the code. Parameters ========== body : CodeBlock or iterable When passed an iterable it is used to instantiate a CodeBlock. """ __slots__ = ('body',) @classmethod def _construct_body(cls, itr): if isinstance(itr, CodeBlock): return itr else: return CodeBlock(*itr) class Stream(Token): """ Represents a stream. There are two predefined Stream instances ``stdout`` & ``stderr``. Parameters ========== name : str Examples ======== >>> from sympy import Symbol >>> from sympy.printing.pycode import pycode >>> from sympy.codegen.ast import Print, stderr, QuotedString >>> print(pycode(Print(['x'], file=stderr))) print(x, file=sys.stderr) >>> x = Symbol('x') >>> print(pycode(Print([QuotedString('x')], file=stderr))) # print literally "x" print("x", file=sys.stderr) """ __slots__ = ('name',) _construct_name = String stdout = Stream('stdout') stderr = Stream('stderr') class Print(Token): """ Represents print command in the code. Parameters ========== formatstring : str *args : Basic instances (or convertible to such through sympify) Examples ======== >>> from sympy.codegen.ast import Print >>> from sympy.printing.pycode import pycode >>> print(pycode(Print('x y'.split(), "coordinate: %12.5g %12.5g"))) print("coordinate: %12.5g %12.5g" % (x, y)) """ __slots__ = ('print_args', 'format_string', 'file') defaults = {'format_string': none, 'file': none} _construct_print_args = staticmethod(_mk_Tuple) _construct_format_string = QuotedString _construct_file = Stream class FunctionPrototype(Node): """ Represents a function prototype Allows the user to generate forward declaration in e.g. C/C++. Parameters ========== return_type : Type name : str parameters: iterable of Variable instances attrs : iterable of Attribute instances Examples ======== >>> from sympy import symbols >>> from sympy.codegen.ast import real, FunctionPrototype >>> from sympy.printing import ccode >>> x, y = symbols('x y', real=True) >>> fp = FunctionPrototype(real, 'foo', [x, y]) >>> ccode(fp) 'double foo(double x, double y)' """ __slots__ = ('return_type', 'name', 'parameters', 'attrs') _construct_return_type = Type _construct_name = String @staticmethod def _construct_parameters(args): def _var(arg): if isinstance(arg, Declaration): return arg.variable elif isinstance(arg, Variable): return arg else: return Variable.deduced(arg) return Tuple(*map(_var, args)) @classmethod def from_FunctionDefinition(cls, func_def): if not isinstance(func_def, FunctionDefinition): raise TypeError("func_def is not an instance of FunctionDefiniton") return cls(**func_def.kwargs(exclude=('body',))) class FunctionDefinition(FunctionPrototype): """ Represents a function definition in the code. Parameters ========== return_type : Type name : str parameters: iterable of Variable instances body : CodeBlock or iterable attrs : iterable of Attribute instances Examples ======== >>> from sympy import symbols >>> from sympy.codegen.ast import real, FunctionPrototype >>> from sympy.printing import ccode >>> x, y = symbols('x y', real=True) >>> fp = FunctionPrototype(real, 'foo', [x, y]) >>> ccode(fp) 'double foo(double x, double y)' >>> from sympy.codegen.ast import FunctionDefinition, Return >>> body = [Return(x*y)] >>> fd = FunctionDefinition.from_FunctionPrototype(fp, body) >>> print(ccode(fd)) double foo(double x, double y){ return x*y; } """ __slots__ = FunctionPrototype.__slots__[:-1] + ('body', 'attrs') @classmethod def _construct_body(cls, itr): if isinstance(itr, CodeBlock): return itr else: return CodeBlock(*itr) @classmethod def from_FunctionPrototype(cls, func_proto, body): if not isinstance(func_proto, FunctionPrototype): raise TypeError("func_proto is not an instance of FunctionPrototype") return cls(body=body, **func_proto.kwargs()) class Return(Basic): """ Represents a return command in the code. """ class FunctionCall(Token, Expr): """ Represents a call to a function in the code. Parameters ========== name : str function_args : Tuple Examples ======== >>> from sympy.codegen.ast import FunctionCall >>> from sympy.printing.pycode import pycode >>> fcall = FunctionCall('foo', 'bar baz'.split()) >>> print(pycode(fcall)) foo(bar, baz) """ __slots__ = ('name', 'function_args') _construct_name = String _construct_function_args = staticmethod(lambda args: Tuple(*args)) sympy-sympy-1.9/sympy/codegen/cfunctions.py000066400000000000000000000270521412543434000212430ustar00rootroot00000000000000""" This module contains SymPy functions mathcin corresponding to special math functions in the C standard library (since C99, also available in C++11). The functions defined in this module allows the user to express functions such as ``expm1`` as a SymPy function for symbolic manipulation. """ from sympy.core.function import ArgumentIndexError, Function from sympy.core.numbers import Rational from sympy.core.power import Pow from sympy.core.singleton import S from sympy.functions.elementary.exponential import exp, log from sympy.functions.elementary.miscellaneous import sqrt def _expm1(x): return exp(x) - S.One class expm1(Function): """ Represents the exponential function minus one. Explanation =========== The benefit of using ``expm1(x)`` over ``exp(x) - 1`` is that the latter is prone to cancellation under finite precision arithmetic when x is close to zero. Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cfunctions import expm1 >>> '%.0e' % expm1(1e-99).evalf() '1e-99' >>> from math import exp >>> exp(1e-99) - 1 0.0 >>> expm1(x).diff(x) exp(x) See Also ======== log1p """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return exp(*self.args) else: raise ArgumentIndexError(self, argindex) def _eval_expand_func(self, **hints): return _expm1(*self.args) def _eval_rewrite_as_exp(self, arg, **kwargs): return exp(arg) - S.One _eval_rewrite_as_tractable = _eval_rewrite_as_exp @classmethod def eval(cls, arg): exp_arg = exp.eval(arg) if exp_arg is not None: return exp_arg - S.One def _eval_is_real(self): return self.args[0].is_real def _eval_is_finite(self): return self.args[0].is_finite def _log1p(x): return log(x + S.One) class log1p(Function): """ Represents the natural logarithm of a number plus one. Explanation =========== The benefit of using ``log1p(x)`` over ``log(x + 1)`` is that the latter is prone to cancellation under finite precision arithmetic when x is close to zero. Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cfunctions import log1p >>> from sympy.core.function import expand_log >>> '%.0e' % expand_log(log1p(1e-99)).evalf() '1e-99' >>> from math import log >>> log(1 + 1e-99) 0.0 >>> log1p(x).diff(x) 1/(x + 1) See Also ======== expm1 """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return S.One/(self.args[0] + S.One) else: raise ArgumentIndexError(self, argindex) def _eval_expand_func(self, **hints): return _log1p(*self.args) def _eval_rewrite_as_log(self, arg, **kwargs): return _log1p(arg) _eval_rewrite_as_tractable = _eval_rewrite_as_log @classmethod def eval(cls, arg): if arg.is_Rational: return log(arg + S.One) elif not arg.is_Float: # not safe to add 1 to Float return log.eval(arg + S.One) elif arg.is_number: return log(Rational(arg) + S.One) def _eval_is_real(self): return (self.args[0] + S.One).is_nonnegative def _eval_is_finite(self): if (self.args[0] + S.One).is_zero: return False return self.args[0].is_finite def _eval_is_positive(self): return self.args[0].is_positive def _eval_is_zero(self): return self.args[0].is_zero def _eval_is_nonnegative(self): return self.args[0].is_nonnegative _Two = S(2) def _exp2(x): return Pow(_Two, x) class exp2(Function): """ Represents the exponential function with base two. Explanation =========== The benefit of using ``exp2(x)`` over ``2**x`` is that the latter is not as efficient under finite precision arithmetic. Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cfunctions import exp2 >>> exp2(2).evalf() == 4 True >>> exp2(x).diff(x) log(2)*exp2(x) See Also ======== log2 """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return self*log(_Two) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_Pow(self, arg, **kwargs): return _exp2(arg) _eval_rewrite_as_tractable = _eval_rewrite_as_Pow def _eval_expand_func(self, **hints): return _exp2(*self.args) @classmethod def eval(cls, arg): if arg.is_number: return _exp2(arg) def _log2(x): return log(x)/log(_Two) class log2(Function): """ Represents the logarithm function with base two. Explanation =========== The benefit of using ``log2(x)`` over ``log(x)/log(2)`` is that the latter is not as efficient under finite precision arithmetic. Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cfunctions import log2 >>> log2(4).evalf() == 2 True >>> log2(x).diff(x) 1/(x*log(2)) See Also ======== exp2 log10 """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return S.One/(log(_Two)*self.args[0]) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): if arg.is_number: result = log.eval(arg, base=_Two) if result.is_Atom: return result elif arg.is_Pow and arg.base == _Two: return arg.exp def _eval_evalf(self, *args, **kwargs): return self.rewrite(log).evalf(*args, **kwargs) def _eval_expand_func(self, **hints): return _log2(*self.args) def _eval_rewrite_as_log(self, arg, **kwargs): return _log2(arg) _eval_rewrite_as_tractable = _eval_rewrite_as_log def _fma(x, y, z): return x*y + z class fma(Function): """ Represents "fused multiply add". Explanation =========== The benefit of using ``fma(x, y, z)`` over ``x*y + z`` is that, under finite precision arithmetic, the former is supported by special instructions on some CPUs. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.codegen.cfunctions import fma >>> fma(x, y, z).diff(x) y """ nargs = 3 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex in (1, 2): return self.args[2 - argindex] elif argindex == 3: return S.One else: raise ArgumentIndexError(self, argindex) def _eval_expand_func(self, **hints): return _fma(*self.args) def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): return _fma(arg) _Ten = S(10) def _log10(x): return log(x)/log(_Ten) class log10(Function): """ Represents the logarithm function with base ten. Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cfunctions import log10 >>> log10(100).evalf() == 2 True >>> log10(x).diff(x) 1/(x*log(10)) See Also ======== log2 """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return S.One/(log(_Ten)*self.args[0]) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): if arg.is_number: result = log.eval(arg, base=_Ten) if result.is_Atom: return result elif arg.is_Pow and arg.base == _Ten: return arg.exp def _eval_expand_func(self, **hints): return _log10(*self.args) def _eval_rewrite_as_log(self, arg, **kwargs): return _log10(arg) _eval_rewrite_as_tractable = _eval_rewrite_as_log def _Sqrt(x): return Pow(x, S.Half) class Sqrt(Function): # 'sqrt' already defined in sympy.functions.elementary.miscellaneous """ Represents the square root function. Explanation =========== The reason why one would use ``Sqrt(x)`` over ``sqrt(x)`` is that the latter is internally represented as ``Pow(x, S.Half)`` which may not be what one wants when doing code-generation. Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cfunctions import Sqrt >>> Sqrt(x) Sqrt(x) >>> Sqrt(x).diff(x) 1/(2*sqrt(x)) See Also ======== Cbrt """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return Pow(self.args[0], Rational(-1, 2))/_Two else: raise ArgumentIndexError(self, argindex) def _eval_expand_func(self, **hints): return _Sqrt(*self.args) def _eval_rewrite_as_Pow(self, arg, **kwargs): return _Sqrt(arg) _eval_rewrite_as_tractable = _eval_rewrite_as_Pow def _Cbrt(x): return Pow(x, Rational(1, 3)) class Cbrt(Function): # 'cbrt' already defined in sympy.functions.elementary.miscellaneous """ Represents the cube root function. Explanation =========== The reason why one would use ``Cbrt(x)`` over ``cbrt(x)`` is that the latter is internally represented as ``Pow(x, Rational(1, 3))`` which may not be what one wants when doing code-generation. Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cfunctions import Cbrt >>> Cbrt(x) Cbrt(x) >>> Cbrt(x).diff(x) 1/(3*x**(2/3)) See Also ======== Sqrt """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return Pow(self.args[0], Rational(-_Two/3))/3 else: raise ArgumentIndexError(self, argindex) def _eval_expand_func(self, **hints): return _Cbrt(*self.args) def _eval_rewrite_as_Pow(self, arg, **kwargs): return _Cbrt(arg) _eval_rewrite_as_tractable = _eval_rewrite_as_Pow def _hypot(x, y): return sqrt(Pow(x, 2) + Pow(y, 2)) class hypot(Function): """ Represents the hypotenuse function. Explanation =========== The hypotenuse function is provided by e.g. the math library in the C99 standard, hence one may want to represent the function symbolically when doing code-generation. Examples ======== >>> from sympy.abc import x, y >>> from sympy.codegen.cfunctions import hypot >>> hypot(3, 4).evalf() == 5 True >>> hypot(x, y) hypot(x, y) >>> hypot(x, y).diff(x) x/hypot(x, y) """ nargs = 2 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex in (1, 2): return 2*self.args[argindex-1]/(_Two*self.func(*self.args)) else: raise ArgumentIndexError(self, argindex) def _eval_expand_func(self, **hints): return _hypot(*self.args) def _eval_rewrite_as_Pow(self, arg, **kwargs): return _hypot(arg) _eval_rewrite_as_tractable = _eval_rewrite_as_Pow sympy-sympy-1.9/sympy/codegen/cnodes.py000066400000000000000000000054121412543434000203370ustar00rootroot00000000000000""" AST nodes specific to the C family of languages """ from sympy.codegen.ast import ( Attribute, Declaration, Node, String, Token, Type, none, FunctionCall, CodeBlock ) from sympy.core.basic import Basic from sympy.core.containers import Tuple from sympy.core.sympify import sympify void = Type('void') restrict = Attribute('restrict') # guarantees no pointer aliasing volatile = Attribute('volatile') static = Attribute('static') def alignof(arg): """ Generate of FunctionCall instance for calling 'alignof' """ return FunctionCall('alignof', [String(arg) if isinstance(arg, str) else arg]) def sizeof(arg): """ Generate of FunctionCall instance for calling 'sizeof' Examples ======== >>> from sympy.codegen.ast import real >>> from sympy.codegen.cnodes import sizeof >>> from sympy.printing import ccode >>> ccode(sizeof(real)) 'sizeof(double)' """ return FunctionCall('sizeof', [String(arg) if isinstance(arg, str) else arg]) class CommaOperator(Basic): """ Represents the comma operator in C """ def __new__(cls, *args): return Basic.__new__(cls, *[sympify(arg) for arg in args]) class Label(Node): """ Label for use with e.g. goto statement. Examples ======== >>> from sympy import Symbol >>> from sympy.codegen.cnodes import Label, PreIncrement >>> from sympy.printing import ccode >>> print(ccode(Label('foo'))) foo: >>> print(ccode(Label('bar', [PreIncrement(Symbol('a'))]))) bar: ++(a); """ __slots__ = ('name', 'body') defaults = {'body': none} _construct_name = String @classmethod def _construct_body(cls, itr): if isinstance(itr, CodeBlock): return itr else: return CodeBlock(*itr) class goto(Token): """ Represents goto in C """ __slots__ = ('label',) _construct_label = Label class PreDecrement(Basic): """ Represents the pre-decrement operator Examples ======== >>> from sympy.abc import x >>> from sympy.codegen.cnodes import PreDecrement >>> from sympy.printing import ccode >>> ccode(PreDecrement(x)) '--(x)' """ nargs = 1 class PostDecrement(Basic): """ Represents the post-decrement operator """ nargs = 1 class PreIncrement(Basic): """ Represents the pre-increment operator """ nargs = 1 class PostIncrement(Basic): """ Represents the post-increment operator """ nargs = 1 class struct(Node): """ Represents a struct in C """ __slots__ = ('name', 'declarations') defaults = {'name': none} _construct_name = String @classmethod def _construct_declarations(cls, args): return Tuple(*[Declaration(arg) for arg in args]) class union(struct): """ Represents a union in C """ sympy-sympy-1.9/sympy/codegen/cutils.py000066400000000000000000000005771412543434000203760ustar00rootroot00000000000000from sympy.printing.c import C99CodePrinter def render_as_source_file(content, Printer=C99CodePrinter, settings=None): """ Renders a C source file (with required #include statements) """ printer = Printer(settings or {}) code_str = printer.doprint(content) includes = '\n'.join(['#include <%s>' % h for h in printer.headers]) return includes + '\n\n' + code_str sympy-sympy-1.9/sympy/codegen/cxxnodes.py000066400000000000000000000005141412543434000207150ustar00rootroot00000000000000""" AST nodes specific to C++. """ from sympy.codegen.ast import Attribute, String, Token, Type, none class using(Token): """ Represents a 'using' statement in C++ """ __slots__ = ('type', 'alias') defaults = {'alias': none} _construct_type = Type _construct_alias = String constexpr = Attribute('constexpr') sympy-sympy-1.9/sympy/codegen/fnodes.py000066400000000000000000000447141412543434000203520ustar00rootroot00000000000000""" AST nodes specific to Fortran. The functions defined in this module allows the user to express functions such as ``dsign`` as a SymPy function for symbolic manipulation. """ from sympy.codegen.ast import ( Attribute, CodeBlock, FunctionCall, Node, none, String, Token, _mk_Tuple, Variable ) from sympy.core.basic import Basic from sympy.core.containers import Tuple from sympy.core.expr import Expr from sympy.core.function import Function from sympy.core.numbers import Float, Integer from sympy.core.sympify import sympify from sympy.logic import true, false from sympy.utilities.iterables import iterable pure = Attribute('pure') elemental = Attribute('elemental') # (all elemental procedures are also pure) intent_in = Attribute('intent_in') intent_out = Attribute('intent_out') intent_inout = Attribute('intent_inout') allocatable = Attribute('allocatable') class Program(Token): """ Represents a 'program' block in Fortran. Examples ======== >>> from sympy.codegen.ast import Print >>> from sympy.codegen.fnodes import Program >>> prog = Program('myprogram', [Print([42])]) >>> from sympy.printing import fcode >>> print(fcode(prog, source_format='free')) program myprogram print *, 42 end program """ __slots__ = ('name', 'body') _construct_name = String _construct_body = staticmethod(lambda body: CodeBlock(*body)) class use_rename(Token): """ Represents a renaming in a use statement in Fortran. Examples ======== >>> from sympy.codegen.fnodes import use_rename, use >>> from sympy.printing import fcode >>> ren = use_rename("thingy", "convolution2d") >>> print(fcode(ren, source_format='free')) thingy => convolution2d >>> full = use('signallib', only=['snr', ren]) >>> print(fcode(full, source_format='free')) use signallib, only: snr, thingy => convolution2d """ __slots__ = ('local', 'original') _construct_local = String _construct_original = String def _name(arg): if hasattr(arg, 'name'): return arg.name else: return String(arg) class use(Token): """ Represents a use statement in Fortran. Examples ======== >>> from sympy.codegen.fnodes import use >>> from sympy.printing import fcode >>> fcode(use('signallib'), source_format='free') 'use signallib' >>> fcode(use('signallib', [('metric', 'snr')]), source_format='free') 'use signallib, metric => snr' >>> fcode(use('signallib', only=['snr', 'convolution2d']), source_format='free') 'use signallib, only: snr, convolution2d' """ __slots__ = ('namespace', 'rename', 'only') defaults = {'rename': none, 'only': none} _construct_namespace = staticmethod(_name) _construct_rename = staticmethod(lambda args: Tuple(*[arg if isinstance(arg, use_rename) else use_rename(*arg) for arg in args])) _construct_only = staticmethod(lambda args: Tuple(*[arg if isinstance(arg, use_rename) else _name(arg) for arg in args])) class Module(Token): """ Represents a module in Fortran. Examples ======== >>> from sympy.codegen.fnodes import Module >>> from sympy.printing import fcode >>> print(fcode(Module('signallib', ['implicit none'], []), source_format='free')) module signallib implicit none contains end module """ __slots__ = ('name', 'declarations', 'definitions') defaults = {'declarations': Tuple()} _construct_name = String _construct_declarations = staticmethod(lambda arg: CodeBlock(*arg)) _construct_definitions = staticmethod(lambda arg: CodeBlock(*arg)) class Subroutine(Node): """ Represents a subroutine in Fortran. Examples ======== >>> from sympy import symbols >>> from sympy.codegen.ast import Print >>> from sympy.codegen.fnodes import Subroutine >>> from sympy.printing import fcode >>> x, y = symbols('x y', real=True) >>> sub = Subroutine('mysub', [x, y], [Print([x**2 + y**2, x*y])]) >>> print(fcode(sub, source_format='free', standard=2003)) subroutine mysub(x, y) real*8 :: x real*8 :: y print *, x**2 + y**2, x*y end subroutine """ __slots__ = ('name', 'parameters', 'body', 'attrs') _construct_name = String _construct_parameters = staticmethod(lambda params: Tuple(*map(Variable.deduced, params))) @classmethod def _construct_body(cls, itr): if isinstance(itr, CodeBlock): return itr else: return CodeBlock(*itr) class SubroutineCall(Token): """ Represents a call to a subroutine in Fortran. Examples ======== >>> from sympy.codegen.fnodes import SubroutineCall >>> from sympy.printing import fcode >>> fcode(SubroutineCall('mysub', 'x y'.split())) ' call mysub(x, y)' """ __slots__ = ('name', 'subroutine_args') _construct_name = staticmethod(_name) _construct_subroutine_args = staticmethod(_mk_Tuple) class Do(Token): """ Represents a Do loop in in Fortran. Examples ======== >>> from sympy import symbols >>> from sympy.codegen.ast import aug_assign, Print >>> from sympy.codegen.fnodes import Do >>> from sympy.printing import fcode >>> i, n = symbols('i n', integer=True) >>> r = symbols('r', real=True) >>> body = [aug_assign(r, '+', 1/i), Print([i, r])] >>> do1 = Do(body, i, 1, n) >>> print(fcode(do1, source_format='free')) do i = 1, n r = r + 1d0/i print *, i, r end do >>> do2 = Do(body, i, 1, n, 2) >>> print(fcode(do2, source_format='free')) do i = 1, n, 2 r = r + 1d0/i print *, i, r end do """ __slots__ = ('body', 'counter', 'first', 'last', 'step', 'concurrent') defaults = {'step': Integer(1), 'concurrent': false} _construct_body = staticmethod(lambda body: CodeBlock(*body)) _construct_counter = staticmethod(sympify) _construct_first = staticmethod(sympify) _construct_last = staticmethod(sympify) _construct_step = staticmethod(sympify) _construct_concurrent = staticmethod(lambda arg: true if arg else false) class ArrayConstructor(Token): """ Represents an array constructor. Examples ======== >>> from sympy.printing import fcode >>> from sympy.codegen.fnodes import ArrayConstructor >>> ac = ArrayConstructor([1, 2, 3]) >>> fcode(ac, standard=95, source_format='free') '(/1, 2, 3/)' >>> fcode(ac, standard=2003, source_format='free') '[1, 2, 3]' """ __slots__ = ('elements',) _construct_elements = staticmethod(_mk_Tuple) class ImpliedDoLoop(Token): """ Represents an implied do loop in Fortran. Examples ======== >>> from sympy import Symbol, fcode >>> from sympy.codegen.fnodes import ImpliedDoLoop, ArrayConstructor >>> i = Symbol('i', integer=True) >>> idl = ImpliedDoLoop(i**3, i, -3, 3, 2) # -27, -1, 1, 27 >>> ac = ArrayConstructor([-28, idl, 28]) # -28, -27, -1, 1, 27, 28 >>> fcode(ac, standard=2003, source_format='free') '[-28, (i**3, i = -3, 3, 2), 28]' """ __slots__ = ('expr', 'counter', 'first', 'last', 'step') defaults = {'step': Integer(1)} _construct_expr = staticmethod(sympify) _construct_counter = staticmethod(sympify) _construct_first = staticmethod(sympify) _construct_last = staticmethod(sympify) _construct_step = staticmethod(sympify) class Extent(Basic): """ Represents a dimension extent. Examples ======== >>> from sympy.codegen.fnodes import Extent >>> e = Extent(-3, 3) # -3, -2, -1, 0, 1, 2, 3 >>> from sympy.printing import fcode >>> fcode(e, source_format='free') '-3:3' >>> from sympy.codegen.ast import Variable, real >>> from sympy.codegen.fnodes import dimension, intent_out >>> dim = dimension(e, e) >>> arr = Variable('x', real, attrs=[dim, intent_out]) >>> fcode(arr.as_Declaration(), source_format='free', standard=2003) 'real*8, dimension(-3:3, -3:3), intent(out) :: x' """ def __new__(cls, *args): if len(args) == 2: low, high = args return Basic.__new__(cls, sympify(low), sympify(high)) elif len(args) == 0 or (len(args) == 1 and args[0] in (':', None)): return Basic.__new__(cls) # assumed shape else: raise ValueError("Expected 0 or 2 args (or one argument == None or ':')") def _sympystr(self, printer): if len(self.args) == 0: return ':' return '%d:%d' % self.args assumed_extent = Extent() # or Extent(':'), Extent(None) def dimension(*args): """ Creates a 'dimension' Attribute with (up to 7) extents. Examples ======== >>> from sympy.printing import fcode >>> from sympy.codegen.fnodes import dimension, intent_in >>> dim = dimension('2', ':') # 2 rows, runtime determined number of columns >>> from sympy.codegen.ast import Variable, integer >>> arr = Variable('a', integer, attrs=[dim, intent_in]) >>> fcode(arr.as_Declaration(), source_format='free', standard=2003) 'integer*4, dimension(2, :), intent(in) :: a' """ if len(args) > 7: raise ValueError("Fortran only supports up to 7 dimensional arrays") parameters = [] for arg in args: if isinstance(arg, Extent): parameters.append(arg) elif isinstance(arg, str): if arg == ':': parameters.append(Extent()) else: parameters.append(String(arg)) elif iterable(arg): parameters.append(Extent(*arg)) else: parameters.append(sympify(arg)) if len(args) == 0: raise ValueError("Need at least one dimension") return Attribute('dimension', parameters) assumed_size = dimension('*') def array(symbol, dim, intent=None, *, attrs=(), value=None, type=None): """ Convenience function for creating a Variable instance for a Fortran array. Parameters ========== symbol : symbol dim : Attribute or iterable If dim is an ``Attribute`` it need to have the name 'dimension'. If it is not an ``Attribute``, then it is passsed to :func:`dimension` as ``*dim`` intent : str One of: 'in', 'out', 'inout' or None \\*\\*kwargs: Keyword arguments for ``Variable`` ('type' & 'value') Examples ======== >>> from sympy.printing import fcode >>> from sympy.codegen.ast import integer, real >>> from sympy.codegen.fnodes import array >>> arr = array('a', '*', 'in', type=integer) >>> print(fcode(arr.as_Declaration(), source_format='free', standard=2003)) integer*4, dimension(*), intent(in) :: a >>> x = array('x', [3, ':', ':'], intent='out', type=real) >>> print(fcode(x.as_Declaration(value=1), source_format='free', standard=2003)) real*8, dimension(3, :, :), intent(out) :: x = 1 """ if isinstance(dim, Attribute): if str(dim.name) != 'dimension': raise ValueError("Got an unexpected Attribute argument as dim: %s" % str(dim)) else: dim = dimension(*dim) attrs = list(attrs) + [dim] if intent is not None: if intent not in (intent_in, intent_out, intent_inout): intent = {'in': intent_in, 'out': intent_out, 'inout': intent_inout}[intent] attrs.append(intent) if type is None: return Variable.deduced(symbol, value=value, attrs=attrs) else: return Variable(symbol, type, value=value, attrs=attrs) def _printable(arg): return String(arg) if isinstance(arg, str) else sympify(arg) def allocated(array): """ Creates an AST node for a function call to Fortran's "allocated(...)" Examples ======== >>> from sympy.printing import fcode >>> from sympy.codegen.fnodes import allocated >>> alloc = allocated('x') >>> fcode(alloc, source_format='free') 'allocated(x)' """ return FunctionCall('allocated', [_printable(array)]) def lbound(array, dim=None, kind=None): """ Creates an AST node for a function call to Fortran's "lbound(...)" Parameters ========== array : Symbol or String dim : expr kind : expr Examples ======== >>> from sympy.printing import fcode >>> from sympy.codegen.fnodes import lbound >>> lb = lbound('arr', dim=2) >>> fcode(lb, source_format='free') 'lbound(arr, 2)' """ return FunctionCall( 'lbound', [_printable(array)] + ([_printable(dim)] if dim else []) + ([_printable(kind)] if kind else []) ) def ubound(array, dim=None, kind=None): return FunctionCall( 'ubound', [_printable(array)] + ([_printable(dim)] if dim else []) + ([_printable(kind)] if kind else []) ) def shape(source, kind=None): """ Creates an AST node for a function call to Fortran's "shape(...)" Parameters ========== source : Symbol or String kind : expr Examples ======== >>> from sympy.printing import fcode >>> from sympy.codegen.fnodes import shape >>> shp = shape('x') >>> fcode(shp, source_format='free') 'shape(x)' """ return FunctionCall( 'shape', [_printable(source)] + ([_printable(kind)] if kind else []) ) def size(array, dim=None, kind=None): """ Creates an AST node for a function call to Fortran's "size(...)" Examples ======== >>> from sympy import Symbol >>> from sympy.printing import fcode >>> from sympy.codegen.ast import FunctionDefinition, real, Return >>> from sympy.codegen.fnodes import array, sum_, size >>> a = Symbol('a', real=True) >>> body = [Return((sum_(a**2)/size(a))**.5)] >>> arr = array(a, dim=[':'], intent='in') >>> fd = FunctionDefinition(real, 'rms', [arr], body) >>> print(fcode(fd, source_format='free', standard=2003)) real*8 function rms(a) real*8, dimension(:), intent(in) :: a rms = sqrt(sum(a**2)*1d0/size(a)) end function """ return FunctionCall( 'size', [_printable(array)] + ([_printable(dim)] if dim else []) + ([_printable(kind)] if kind else []) ) def reshape(source, shape, pad=None, order=None): """ Creates an AST node for a function call to Fortran's "reshape(...)" Parameters ========== source : Symbol or String shape : ArrayExpr """ return FunctionCall( 'reshape', [_printable(source), _printable(shape)] + ([_printable(pad)] if pad else []) + ([_printable(order)] if pad else []) ) def bind_C(name=None): """ Creates an Attribute ``bind_C`` with a name. Parameters ========== name : str Examples ======== >>> from sympy import Symbol >>> from sympy.printing import fcode >>> from sympy.codegen.ast import FunctionDefinition, real, Return >>> from sympy.codegen.fnodes import array, sum_, bind_C >>> a = Symbol('a', real=True) >>> s = Symbol('s', integer=True) >>> arr = array(a, dim=[s], intent='in') >>> body = [Return((sum_(a**2)/s)**.5)] >>> fd = FunctionDefinition(real, 'rms', [arr, s], body, attrs=[bind_C('rms')]) >>> print(fcode(fd, source_format='free', standard=2003)) real*8 function rms(a, s) bind(C, name="rms") real*8, dimension(s), intent(in) :: a integer*4 :: s rms = sqrt(sum(a**2)/s) end function """ return Attribute('bind_C', [String(name)] if name else []) class GoTo(Token): """ Represents a goto statement in Fortran Examples ======== >>> from sympy.codegen.fnodes import GoTo >>> go = GoTo([10, 20, 30], 'i') >>> from sympy.printing import fcode >>> fcode(go, source_format='free') 'go to (10, 20, 30), i' """ __slots__ = ('labels', 'expr') defaults = {'expr': none} _construct_labels = staticmethod(_mk_Tuple) _construct_expr = staticmethod(sympify) class FortranReturn(Token): """ AST node explicitly mapped to a fortran "return". Explanation =========== Because a return statement in fortran is different from C, and in order to aid reuse of our codegen ASTs the ordinary ``.codegen.ast.Return`` is interpreted as assignment to the result variable of the function. If one for some reason needs to generate a fortran RETURN statement, this node should be used. Examples ======== >>> from sympy.codegen.fnodes import FortranReturn >>> from sympy.printing import fcode >>> fcode(FortranReturn('x')) ' return x' """ __slots__ = ('return_value',) defaults = {'return_value': none} _construct_return_value = staticmethod(sympify) class FFunction(Function): _required_standard = 77 def _fcode(self, printer): name = self.__class__.__name__ if printer._settings['standard'] < self._required_standard: raise NotImplementedError("%s requires Fortran %d or newer" % (name, self._required_standard)) return '{}({})'.format(name, ', '.join(map(printer._print, self.args))) class F95Function(FFunction): _required_standard = 95 class isign(FFunction): """ Fortran sign intrinsic for integer arguments. """ nargs = 2 class dsign(FFunction): """ Fortran sign intrinsic for double precision arguments. """ nargs = 2 class cmplx(FFunction): """ Fortran complex conversion function. """ nargs = 2 # may be extended to (2, 3) at a later point class kind(FFunction): """ Fortran kind function. """ nargs = 1 class merge(F95Function): """ Fortran merge function """ nargs = 3 class _literal(Float): _token = None # type: str _decimals = None # type: int def _fcode(self, printer, *args, **kwargs): mantissa, sgnd_ex = ('%.{}e'.format(self._decimals) % self).split('e') mantissa = mantissa.strip('0').rstrip('.') ex_sgn, ex_num = sgnd_ex[0], sgnd_ex[1:].lstrip('0') ex_sgn = '' if ex_sgn == '+' else ex_sgn return (mantissa or '0') + self._token + ex_sgn + (ex_num or '0') class literal_sp(_literal): """ Fortran single precision real literal """ _token = 'e' _decimals = 9 class literal_dp(_literal): """ Fortran double precision real literal """ _token = 'd' _decimals = 17 class sum_(Token, Expr): __slots__ = ('array', 'dim', 'mask') defaults = {'dim': none, 'mask': none} _construct_array = staticmethod(sympify) _construct_dim = staticmethod(sympify) class product_(Token, Expr): __slots__ = ('array', 'dim', 'mask') defaults = {'dim': none, 'mask': none} _construct_array = staticmethod(sympify) _construct_dim = staticmethod(sympify) sympy-sympy-1.9/sympy/codegen/futils.py000066400000000000000000000034001412543434000203650ustar00rootroot00000000000000from itertools import chain from sympy.codegen.fnodes import Module from sympy.core.symbol import Dummy from sympy.printing.fortran import FCodePrinter """ This module collects utilities for rendering Fortran code. """ def render_as_module(definitions, name, declarations=(), printer_settings=None): """ Creates a ``Module`` instance and renders it as a string. This generates Fortran source code for a module with the correct ``use`` statements. Parameters ========== definitions : iterable Passed to :class:`sympy.codegen.fnodes.Module`. name : str Passed to :class:`sympy.codegen.fnodes.Module`. declarations : iterable Passed to :class:`sympy.codegen.fnodes.Module`. It will be extended with use statements, 'implicit none' and public list generated from ``definitions``. printer_settings : dict Passed to ``FCodePrinter`` (default: ``{'standard': 2003, 'source_format': 'free'}``). """ printer_settings = printer_settings or {'standard': 2003, 'source_format': 'free'} printer = FCodePrinter(printer_settings) dummy = Dummy() if isinstance(definitions, Module): raise ValueError("This function expects to construct a module on its own.") mod = Module(name, chain(declarations, [dummy]), definitions) fstr = printer.doprint(mod) module_use_str = ' %s\n' % ' \n'.join(['use %s, only: %s' % (k, ', '.join(v)) for k, v in printer.module_uses.items()]) module_use_str += ' implicit none\n' module_use_str += ' private\n' module_use_str += ' public %s\n' % ', '.join([str(node.name) for node in definitions if getattr(node, 'name', None)]) return fstr.replace(printer.doprint(dummy), module_use_str) sympy-sympy-1.9/sympy/codegen/matrix_nodes.py000066400000000000000000000040641412543434000215620ustar00rootroot00000000000000""" Additional AST nodes for operations on matrices. The nodes in this module are meant to represent optimization of matrix expressions within codegen's target languages that cannot be represented by SymPy expressions. As an example, we can use :meth:`sympy.codegen.rewriting.optimize` and the ``matin_opt`` optimization provided in :mod:`sympy.codegen.rewriting` to transform matrix multiplication under certain assumptions: >>> from sympy import symbols, MatrixSymbol >>> n = symbols('n', integer=True) >>> A = MatrixSymbol('A', n, n) >>> x = MatrixSymbol('x', n, 1) >>> expr = A**(-1) * x >>> from sympy.assumptions import assuming, Q >>> from sympy.codegen.rewriting import matinv_opt, optimize >>> with assuming(Q.fullrank(A)): ... optimize(expr, [matinv_opt]) MatrixSolve(A, vector=x) """ from .ast import Token from sympy.matrices import MatrixExpr from sympy.core.sympify import sympify class MatrixSolve(Token, MatrixExpr): """Represents an operation to solve a linear matrix equation. Parameters ========== matrix : MatrixSymbol Matrix representing the coefficients of variables in the linear equation. This matrix must be square and full-rank (i.e. all columns must be linearly independent) for the solving operation to be valid. vector : MatrixSymbol One-column matrix representing the solutions to the equations represented in ``matrix``. Examples ======== >>> from sympy import symbols, MatrixSymbol >>> from sympy.codegen.matrix_nodes import MatrixSolve >>> n = symbols('n', integer=True) >>> A = MatrixSymbol('A', n, n) >>> x = MatrixSymbol('x', n, 1) >>> from sympy.printing.numpy import NumPyPrinter >>> NumPyPrinter().doprint(MatrixSolve(A, x)) 'numpy.linalg.solve(A, x)' >>> from sympy.printing import octave_code >>> octave_code(MatrixSolve(A, x)) 'A \\\\ x' """ __slots__ = ('matrix', 'vector') _construct_matrix = staticmethod(sympify) @property def shape(self): return self.vector.shape sympy-sympy-1.9/sympy/codegen/numpy_nodes.py000066400000000000000000000061101412543434000214200ustar00rootroot00000000000000from sympy.core.function import Add, ArgumentIndexError, Function from sympy.core.power import Pow from sympy.core.singleton import S from sympy.functions.elementary.exponential import exp, log from sympy.utilities import default_sort_key def _logaddexp(x1, x2, *, evaluate=True): return log(Add(exp(x1, evaluate=evaluate), exp(x2, evaluate=evaluate), evaluate=evaluate)) _two = S.One*2 _ln2 = log(_two) def _lb(x, *, evaluate=True): return log(x, evaluate=evaluate)/_ln2 def _exp2(x, *, evaluate=True): return Pow(_two, x, evaluate=evaluate) def _logaddexp2(x1, x2, *, evaluate=True): return _lb(Add(_exp2(x1, evaluate=evaluate), _exp2(x2, evaluate=evaluate), evaluate=evaluate)) class logaddexp(Function): """ Logarithm of the sum of exponentiations of the inputs. Helper class for use with e.g. numpy.logaddexp See Also ======== https://numpy.org/doc/stable/reference/generated/numpy.logaddexp.html """ nargs = 2 def __new__(cls, *args): return Function.__new__(cls, *sorted(args, key=default_sort_key)) def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: wrt, other = self.args elif argindex == 2: other, wrt = self.args else: raise ArgumentIndexError(self, argindex) return S.One/(S.One + exp(other-wrt)) def _eval_rewrite_as_log(self, x1, x2, **kwargs): return _logaddexp(x1, x2) def _eval_evalf(self, *args, **kwargs): return self.rewrite(log).evalf(*args, **kwargs) def _eval_simplify(self, *args, **kwargs): a, b = map(lambda x: x.simplify(**kwargs), self.args) candidate = _logaddexp(a, b) if candidate != _logaddexp(a, b, evaluate=False): return candidate else: return logaddexp(a, b) class logaddexp2(Function): """ Logarithm of the sum of exponentiations of the inputs in base-2. Helper class for use with e.g. numpy.logaddexp2 See Also ======== https://numpy.org/doc/stable/reference/generated/numpy.logaddexp2.html """ nargs = 2 def __new__(cls, *args): return Function.__new__(cls, *sorted(args, key=default_sort_key)) def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: wrt, other = self.args elif argindex == 2: other, wrt = self.args else: raise ArgumentIndexError(self, argindex) return S.One/(S.One + _exp2(other-wrt)) def _eval_rewrite_as_log(self, x1, x2, **kwargs): return _logaddexp2(x1, x2) def _eval_evalf(self, *args, **kwargs): return self.rewrite(log).evalf(*args, **kwargs) def _eval_simplify(self, *args, **kwargs): a, b = map(lambda x: x.simplify(**kwargs).factor(), self.args) candidate = _logaddexp2(a, b) if candidate != _logaddexp2(a, b, evaluate=False): return candidate else: return logaddexp2(a, b) sympy-sympy-1.9/sympy/codegen/pyutils.py000066400000000000000000000015061412543434000205750ustar00rootroot00000000000000from sympy.printing.pycode import PythonCodePrinter """ This module collects utilities for rendering Python code. """ def render_as_module(content, standard='python3'): """Renders python code as a module (with the required imports). Parameters ========== standard : See the parameter ``standard`` in :meth:`sympy.printing.pycode.pycode` """ printer = PythonCodePrinter({'standard':standard}) pystr = printer.doprint(content) if printer._settings['fully_qualified_modules']: module_imports_str = '\n'.join('import %s' % k for k in printer.module_imports) else: module_imports_str = '\n'.join(['from %s import %s' % (k, ', '.join(v)) for k, v in printer.module_imports.items()]) return module_imports_str + '\n\n' + pystr sympy-sympy-1.9/sympy/codegen/rewriting.py000066400000000000000000000257621412543434000211100ustar00rootroot00000000000000""" Classes and functions useful for rewriting expressions for optimized code generation. Some languages (or standards thereof), e.g. C99, offer specialized math functions for better performance and/or precision. Using the ``optimize`` function in this module, together with a collection of rules (represented as instances of ``Optimization``), one can rewrite the expressions for this purpose:: >>> from sympy import Symbol, exp, log >>> from sympy.codegen.rewriting import optimize, optims_c99 >>> x = Symbol('x') >>> optimize(3*exp(2*x) - 3, optims_c99) 3*expm1(2*x) >>> optimize(exp(2*x) - 1 - exp(-33), optims_c99) expm1(2*x) - exp(-33) >>> optimize(log(3*x + 3), optims_c99) log1p(x) + log(3) >>> optimize(log(2*x + 3), optims_c99) log(2*x + 3) The ``optims_c99`` imported above is tuple containing the following instances (which may be imported from ``sympy.codegen.rewriting``): - ``expm1_opt`` - ``log1p_opt`` - ``exp2_opt`` - ``log2_opt`` - ``log2const_opt`` """ from sympy import cos, exp, log, Max, Min, Wild, expand_log, sign, sin, sinc, S from sympy.assumptions import Q, ask from sympy.codegen.cfunctions import log1p, log2, exp2, expm1 from sympy.codegen.matrix_nodes import MatrixSolve from sympy.core.expr import UnevaluatedExpr from sympy.core.power import Pow from sympy.codegen.numpy_nodes import logaddexp, logaddexp2 from sympy.codegen.scipy_nodes import cosm1 from sympy.core.mul import Mul from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.utilities.iterables import sift class Optimization: """ Abstract base class for rewriting optimization. Subclasses should implement ``__call__`` taking an expression as argument. Parameters ========== cost_function : callable returning number priority : number """ def __init__(self, cost_function=None, priority=1): self.cost_function = cost_function self.priority=priority def cheapest(self, *args): return sorted(args, key=self.cost_function)[0] class ReplaceOptim(Optimization): """ Rewriting optimization calling replace on expressions. Explanation =========== The instance can be used as a function on expressions for which it will apply the ``replace`` method (see :meth:`sympy.core.basic.Basic.replace`). Parameters ========== query : First argument passed to replace. value : Second argument passed to replace. Examples ======== >>> from sympy import Symbol >>> from sympy.codegen.rewriting import ReplaceOptim >>> from sympy.codegen.cfunctions import exp2 >>> x = Symbol('x') >>> exp2_opt = ReplaceOptim(lambda p: p.is_Pow and p.base == 2, ... lambda p: exp2(p.exp)) >>> exp2_opt(2**x) exp2(x) """ def __init__(self, query, value, **kwargs): super().__init__(**kwargs) self.query = query self.value = value def __call__(self, expr): return expr.replace(self.query, self.value) def optimize(expr, optimizations): """ Apply optimizations to an expression. Parameters ========== expr : expression optimizations : iterable of ``Optimization`` instances The optimizations will be sorted with respect to ``priority`` (highest first). Examples ======== >>> from sympy import log, Symbol >>> from sympy.codegen.rewriting import optims_c99, optimize >>> x = Symbol('x') >>> optimize(log(x+3)/log(2) + log(x**2 + 1), optims_c99) log1p(x**2) + log2(x + 3) """ for optim in sorted(optimizations, key=lambda opt: opt.priority, reverse=True): new_expr = optim(expr) if optim.cost_function is None: expr = new_expr else: expr = optim.cheapest(expr, new_expr) return expr exp2_opt = ReplaceOptim( lambda p: p.is_Pow and p.base == 2, lambda p: exp2(p.exp) ) _d = Wild('d', properties=[lambda x: x.is_Dummy]) _u = Wild('u', properties=[lambda x: not x.is_number and not x.is_Add]) _v = Wild('v') _w = Wild('w') _n = Wild('n', properties=[lambda x: x.is_number]) sinc_opt1 = ReplaceOptim( sin(_w)/_w, sinc(_w) ) sinc_opt2 = ReplaceOptim( sin(_n*_w)/_w, _n*sinc(_n*_w) ) sinc_opts = (sinc_opt1, sinc_opt2) log2_opt = ReplaceOptim(_v*log(_w)/log(2), _v*log2(_w), cost_function=lambda expr: expr.count( lambda e: ( # division & eval of transcendentals are expensive floating point operations... e.is_Pow and e.exp.is_negative # division or (isinstance(e, (log, log2)) and not e.args[0].is_number)) # transcendental ) ) log2const_opt = ReplaceOptim(log(2)*log2(_w), log(_w)) logsumexp_2terms_opt = ReplaceOptim( lambda l: (isinstance(l, log) and l.args[0].is_Add and len(l.args[0].args) == 2 and all(isinstance(t, exp) for t in l.args[0].args)), lambda l: ( Max(*[e.args[0] for e in l.args[0].args]) + log1p(exp(Min(*[e.args[0] for e in l.args[0].args]))) ) ) class FuncMinusOneOptim(ReplaceOptim): """Specialization of ReplaceOptim for functions evaluating "f(x) - 1". Explanation =========== Numerical functions which go toward one as x go toward zero is often best implemented by a dedicated function in order to avoid catastrophic cancellation. One such example is ``expm1(x)`` in the C standard library which evaluates ``exp(x) - 1``. Such functions preserves many more significant digits when its argument is much smaller than one, compared to subtracting one afterwards. Parameters ========== func : The function which is subtracted by one. func_m_1 : The specialized function evaluating ``func(x) - 1``. opportunistic : bool When ``True``, apply the transformation as long as the magnitude of the remaining number terms decreases. When ``False``, only apply the transformation if it completely eliminates the number term. Examples ======== >>> from sympy import symbols, exp >>> from sympy.codegen.rewriting import FuncMinusOneOptim >>> from sympy.codegen.cfunctions import expm1 >>> x, y = symbols('x y') >>> expm1_opt = FuncMinusOneOptim(exp, expm1) >>> expm1_opt(exp(x) + 2*exp(5*y) - 3) expm1(x) + 2*expm1(5*y) """ def __init__(self, func, func_m_1, opportunistic=True): weight = 10 # <-- this is an arbitrary number (heuristic) super().__init__(lambda e: e.is_Add, self.replace_in_Add, cost_function=lambda expr: expr.count_ops() - weight*expr.count(func_m_1)) self.func = func self.func_m_1 = func_m_1 self.opportunistic = opportunistic def _group_Add_terms(self, add): numbers, non_num = sift(add.args, lambda arg: arg.is_number, binary=True) numsum = sum(numbers) terms_with_func, other = sift(non_num, lambda arg: arg.has(self.func), binary=True) return numsum, terms_with_func, other def replace_in_Add(self, e): """ passed as second argument to Basic.replace(...) """ numsum, terms_with_func, other_non_num_terms = self._group_Add_terms(e) if numsum == 0: return e substituted, untouched = [], [] for with_func in terms_with_func: if with_func.is_Mul: func, coeff = sift(with_func.args, lambda arg: arg.func == self.func, binary=True) if len(func) == 1 and len(coeff) == 1: func, coeff = func[0], coeff[0] else: coeff = None elif with_func.func == self.func: func, coeff = with_func, S.One else: coeff = None if coeff is not None and coeff.is_number and sign(coeff) == -sign(numsum): if self.opportunistic: do_substitute = abs(coeff+numsum) < abs(numsum) else: do_substitute = coeff+numsum == 0 if do_substitute: # advantageous substitution numsum += coeff substituted.append(coeff*self.func_m_1(*func.args)) continue untouched.append(with_func) return e.func(numsum, *substituted, *untouched, *other_non_num_terms) def __call__(self, expr): alt1 = super().__call__(expr) alt2 = super().__call__(expr.factor()) return self.cheapest(alt1, alt2) expm1_opt = FuncMinusOneOptim(exp, expm1) cosm1_opt = FuncMinusOneOptim(cos, cosm1) log1p_opt = ReplaceOptim( lambda e: isinstance(e, log), lambda l: expand_log(l.replace( log, lambda arg: log(arg.factor()) )).replace(log(_u+1), log1p(_u)) ) def create_expand_pow_optimization(limit, *, base_req=lambda b: b.is_symbol): """ Creates an instance of :class:`ReplaceOptim` for expanding ``Pow``. Explanation =========== The requirements for expansions are that the base needs to be a symbol and the exponent needs to be an Integer (and be less than or equal to ``limit``). Parameters ========== limit : int The highest power which is expanded into multiplication. base_req : function returning bool Requirement on base for expansion to happen, default is to return the ``is_symbol`` attribute of the base. Examples ======== >>> from sympy import Symbol, sin >>> from sympy.codegen.rewriting import create_expand_pow_optimization >>> x = Symbol('x') >>> expand_opt = create_expand_pow_optimization(3) >>> expand_opt(x**5 + x**3) x**5 + x*x*x >>> expand_opt(x**5 + x**3 + sin(x)**3) x**5 + sin(x)**3 + x*x*x >>> opt2 = create_expand_pow_optimization(3 , base_req=lambda b: not b.is_Function) >>> opt2((x+1)**2 + sin(x)**2) sin(x)**2 + (x + 1)*(x + 1) """ return ReplaceOptim( lambda e: e.is_Pow and base_req(e.base) and e.exp.is_Integer and abs(e.exp) <= limit, lambda p: ( UnevaluatedExpr(Mul(*([p.base]*+p.exp), evaluate=False)) if p.exp > 0 else 1/UnevaluatedExpr(Mul(*([p.base]*-p.exp), evaluate=False)) )) # Optimization procedures for turning A**(-1) * x into MatrixSolve(A, x) def _matinv_predicate(expr): # TODO: We should be able to support more than 2 elements if expr.is_MatMul and len(expr.args) == 2: left, right = expr.args if left.is_Inverse and right.shape[1] == 1: inv_arg = left.arg if isinstance(inv_arg, MatrixSymbol): return bool(ask(Q.fullrank(left.arg))) return False def _matinv_transform(expr): left, right = expr.args inv_arg = left.arg return MatrixSolve(inv_arg, right) matinv_opt = ReplaceOptim(_matinv_predicate, _matinv_transform) logaddexp_opt = ReplaceOptim(log(exp(_v)+exp(_w)), logaddexp(_v, _w)) logaddexp2_opt = ReplaceOptim(log(Pow(2, _v)+Pow(2, _w)), logaddexp2(_v, _w)*log(2)) # Collections of optimizations: optims_c99 = (expm1_opt, log1p_opt, exp2_opt, log2_opt, log2const_opt) optims_numpy = optims_c99 + (logaddexp_opt, logaddexp2_opt,) + sinc_opts optims_scipy = (cosm1_opt,) sympy-sympy-1.9/sympy/codegen/scipy_nodes.py000066400000000000000000000022301412543434000213760ustar00rootroot00000000000000from sympy.core.function import Add, ArgumentIndexError, Function from sympy.core.singleton import S from sympy.functions.elementary.trigonometric import cos, sin def _cosm1(x, *, evaluate=True): return Add(cos(x, evaluate=evaluate), -S.One, evaluate=evaluate) class cosm1(Function): """ Minus one plus cosine of x, i.e. cos(x) - 1. For use when x is close to zero. Helper class for use with e.g. scipy.special.cosm1 See: https://docs.scipy.org/doc/scipy/reference/generated/scipy.special.cosm1.html """ nargs = 1 def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return -sin(*self.args) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_cos(self, x, **kwargs): return _cosm1(x) def _eval_evalf(self, *args, **kwargs): return self.rewrite(cos).evalf(*args, **kwargs) def _eval_simplify(self, x, **kwargs): candidate = _cosm1(x.simplify(**kwargs)) if candidate != _cosm1(x, evaluate=False): return candidate else: return cosm1(x) sympy-sympy-1.9/sympy/codegen/tests/000077500000000000000000000000001412543434000176525ustar00rootroot00000000000000sympy-sympy-1.9/sympy/codegen/tests/__init__.py000066400000000000000000000000001412543434000217510ustar00rootroot00000000000000sympy-sympy-1.9/sympy/codegen/tests/test_algorithms.py000066400000000000000000000111361412543434000234360ustar00rootroot00000000000000import tempfile import sympy as sp from sympy.codegen.ast import Assignment from sympy.codegen.algorithms import newtons_method, newtons_method_function from sympy.codegen.fnodes import bind_C from sympy.codegen.futils import render_as_module as f_module from sympy.codegen.pyutils import render_as_module as py_module from sympy.external import import_module from sympy.printing.codeprinter import ccode from sympy.utilities._compilation import compile_link_import_strings, has_c, has_fortran from sympy.utilities._compilation.util import may_xfail from sympy.testing.pytest import skip, raises cython = import_module('cython') wurlitzer = import_module('wurlitzer') def test_newtons_method(): x, dx, atol = sp.symbols('x dx atol') expr = sp.cos(x) - x**3 algo = newtons_method(expr, x, atol, dx) assert algo.has(Assignment(dx, -expr/expr.diff(x))) @may_xfail def test_newtons_method_function__ccode(): x = sp.Symbol('x', real=True) expr = sp.cos(x) - x**3 func = newtons_method_function(expr, x) if not cython: skip("cython not installed.") if not has_c(): skip("No C compiler found.") compile_kw = dict(std='c99') with tempfile.TemporaryDirectory() as folder: mod, info = compile_link_import_strings([ ('newton.c', ('#include \n' '#include \n') + ccode(func)), ('_newton.pyx', ("#cython: language_level={}\n".format("3") + "cdef extern double newton(double)\n" "def py_newton(x):\n" " return newton(x)\n")) ], build_dir=folder, compile_kwargs=compile_kw) assert abs(mod.py_newton(0.5) - 0.865474033102) < 1e-12 @may_xfail def test_newtons_method_function__fcode(): x = sp.Symbol('x', real=True) expr = sp.cos(x) - x**3 func = newtons_method_function(expr, x, attrs=[bind_C(name='newton')]) if not cython: skip("cython not installed.") if not has_fortran(): skip("No Fortran compiler found.") f_mod = f_module([func], 'mod_newton') with tempfile.TemporaryDirectory() as folder: mod, info = compile_link_import_strings([ ('newton.f90', f_mod), ('_newton.pyx', ("#cython: language_level={}\n".format("3") + "cdef extern double newton(double*)\n" "def py_newton(double x):\n" " return newton(&x)\n")) ], build_dir=folder) assert abs(mod.py_newton(0.5) - 0.865474033102) < 1e-12 def test_newtons_method_function__pycode(): x = sp.Symbol('x', real=True) expr = sp.cos(x) - x**3 func = newtons_method_function(expr, x) py_mod = py_module(func) namespace = {} exec(py_mod, namespace, namespace) res = eval('newton(0.5)', namespace) assert abs(res - 0.865474033102) < 1e-12 @may_xfail def test_newtons_method_function__ccode_parameters(): args = x, A, k, p = sp.symbols('x A k p') expr = A*sp.cos(k*x) - p*x**3 raises(ValueError, lambda: newtons_method_function(expr, x)) use_wurlitzer = wurlitzer func = newtons_method_function(expr, x, args, debug=use_wurlitzer) if not has_c(): skip("No C compiler found.") if not cython: skip("cython not installed.") compile_kw = dict(std='c99') with tempfile.TemporaryDirectory() as folder: mod, info = compile_link_import_strings([ ('newton_par.c', ('#include \n' '#include \n') + ccode(func)), ('_newton_par.pyx', ("#cython: language_level={}\n".format("3") + "cdef extern double newton(double, double, double, double)\n" "def py_newton(x, A=1, k=1, p=1):\n" " return newton(x, A, k, p)\n")) ], compile_kwargs=compile_kw, build_dir=folder) if use_wurlitzer: with wurlitzer.pipes() as (out, err): result = mod.py_newton(0.5) else: result = mod.py_newton(0.5) assert abs(result - 0.865474033102) < 1e-12 if not use_wurlitzer: skip("C-level output only tested when package 'wurlitzer' is available.") out, err = out.read(), err.read() assert err == '' assert out == """\ x= 0.5 d_x= 0.61214 x= 1.1121 d_x= -0.20247 x= 0.90967 d_x= -0.042409 x= 0.86726 d_x= -0.0017867 x= 0.86548 d_x= -3.1022e-06 x= 0.86547 d_x= -9.3421e-12 x= 0.86547 d_x= 3.6902e-17 """ # try to run tests with LC_ALL=C if this assertion fails sympy-sympy-1.9/sympy/codegen/tests/test_applications.py000066400000000000000000000042161412543434000237540ustar00rootroot00000000000000# This file contains tests that exercise multiple AST nodes import tempfile from sympy.external import import_module from sympy.printing.codeprinter import ccode from sympy.utilities._compilation import compile_link_import_strings, has_c from sympy.utilities._compilation.util import may_xfail from sympy.testing.pytest import skip from sympy.codegen.ast import ( FunctionDefinition, FunctionPrototype, Variable, Pointer, real, Assignment, integer, CodeBlock, While ) from sympy.codegen.cnodes import void, PreIncrement from sympy.codegen.cutils import render_as_source_file cython = import_module('cython') np = import_module('numpy') def _mk_func1(): declars = n, inp, out = Variable('n', integer), Pointer('inp', real), Pointer('out', real) i = Variable('i', integer) whl = While(i double func_unchanged(double x) { return %(unchanged)s; } double func_rewritten(double x) { return %(rewritten)s; } ''' % dict(unchanged=ccode(unchanged.n(NUMBER_OF_DIGITS)), rewritten=ccode(rewritten.n(NUMBER_OF_DIGITS))) func_pyx = ''' #cython: language_level=3 cdef extern double func_unchanged(double) cdef extern double func_rewritten(double) def py_unchanged(x): return func_unchanged(x) def py_rewritten(x): return func_rewritten(x) ''' with tempfile.TemporaryDirectory() as folder: mod, info = compile_link_import_strings( [('func.c', func_c), ('_func.pyx', func_pyx)], build_dir=folder, compile_kwargs=dict(std='c99') ) err_rewritten = abs(mod.py_rewritten(1e-11) - ref) err_unchanged = abs(mod.py_unchanged(1e-11) - ref) assert 1e-27 < err_rewritten < 1e-25 # highly accurate. assert 1e-19 < err_unchanged < 1e-16 # quite poor. # Tolerances used above were determined as follows: # >>> no_opt = unchanged.subs(x, xval.evalf()).evalf() # >>> with_opt = rewritten.n(25).subs(x, 1e-11).evalf() # >>> with_opt - ref, no_opt - ref # (1.1536301877952077e-26, 1.6547074214222335e-18) sympy-sympy-1.9/sympy/codegen/tests/test_scipy_nodes.py000066400000000000000000000011151412543434000236000ustar00rootroot00000000000000from itertools import product from sympy import symbols, cos from sympy.core.numbers import pi from sympy.codegen.scipy_nodes import cosm1 x, y, z = symbols('x y z') def test_cosm1(): cm1_xy = cosm1(x*y) ref_xy = cos(x*y) - 1 for wrt, deriv_order in product([x, y, z], range(0, 3)): assert ( cm1_xy.diff(wrt, deriv_order) - ref_xy.diff(wrt, deriv_order) ).rewrite(cos).simplify() == 0 expr_minus2 = cosm1(pi) assert expr_minus2.rewrite(cos) == -2 assert cosm1(3.14).simplify() == cosm1(3.14) # cannot simplify with 3.14 sympy-sympy-1.9/sympy/combinatorics/000077500000000000000000000000001412543434000177405ustar00rootroot00000000000000sympy-sympy-1.9/sympy/combinatorics/__init__.py000066400000000000000000000026221412543434000220530ustar00rootroot00000000000000from sympy.combinatorics.permutations import Permutation, Cycle from sympy.combinatorics.prufer import Prufer from sympy.combinatorics.generators import cyclic, alternating, symmetric, dihedral from sympy.combinatorics.subsets import Subset from sympy.combinatorics.partitions import (Partition, IntegerPartition, RGS_rank, RGS_unrank, RGS_enum) from sympy.combinatorics.polyhedron import (Polyhedron, tetrahedron, cube, octahedron, dodecahedron, icosahedron) from sympy.combinatorics.perm_groups import PermutationGroup, Coset, SymmetricPermutationGroup from sympy.combinatorics.group_constructs import DirectProduct from sympy.combinatorics.graycode import GrayCode from sympy.combinatorics.named_groups import (SymmetricGroup, DihedralGroup, CyclicGroup, AlternatingGroup, AbelianGroup, RubikGroup) from sympy.combinatorics.pc_groups import PolycyclicGroup, Collector __all__ = [ 'Permutation', 'Cycle', 'Prufer', 'cyclic', 'alternating', 'symmetric', 'dihedral', 'Subset', 'Partition', 'IntegerPartition', 'RGS_rank', 'RGS_unrank', 'RGS_enum', 'Polyhedron', 'tetrahedron', 'cube', 'octahedron', 'dodecahedron', 'icosahedron', 'PermutationGroup', 'Coset', 'SymmetricPermutationGroup', 'DirectProduct', 'GrayCode', 'SymmetricGroup', 'DihedralGroup', 'CyclicGroup', 'AlternatingGroup', 'AbelianGroup', 'RubikGroup', 'PolycyclicGroup', 'Collector', ] sympy-sympy-1.9/sympy/combinatorics/coset_table.py000066400000000000000000001237141412543434000226060ustar00rootroot00000000000000from sympy.combinatorics.free_groups import free_group from sympy.printing.defaults import DefaultPrinting from itertools import chain, product from bisect import bisect_left ############################################################################### # COSET TABLE # ############################################################################### class CosetTable(DefaultPrinting): # coset_table: Mathematically a coset table # represented using a list of lists # alpha: Mathematically a coset (precisely, a live coset) # represented by an integer between i with 1 <= i <= n # alpha in c # x: Mathematically an element of "A" (set of generators and # their inverses), represented using "FpGroupElement" # fp_grp: Finitely Presented Group with < X|R > as presentation. # H: subgroup of fp_grp. # NOTE: We start with H as being only a list of words in generators # of "fp_grp". Since `.subgroup` method has not been implemented. r""" Properties ========== [1] `0 \in \Omega` and `\tau(1) = \epsilon` [2] `\alpha^x = \beta \Leftrightarrow \beta^{x^{-1}} = \alpha` [3] If `\alpha^x = \beta`, then `H \tau(\alpha)x = H \tau(\beta)` [4] `\forall \alpha \in \Omega, 1^{\tau(\alpha)} = \alpha` References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" .. [2] John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490. "Implementation and Analysis of the Todd-Coxeter Algorithm" """ # default limit for the number of cosets allowed in a # coset enumeration. coset_table_max_limit = 4096000 # limit for the current instance coset_table_limit = None # maximum size of deduction stack above or equal to # which it is emptied max_stack_size = 100 def __init__(self, fp_grp, subgroup, max_cosets=None): if not max_cosets: max_cosets = CosetTable.coset_table_max_limit self.fp_group = fp_grp self.subgroup = subgroup self.coset_table_limit = max_cosets # "p" is setup independent of Omega and n self.p = [0] # a list of the form `[gen_1, gen_1^{-1}, ... , gen_k, gen_k^{-1}]` self.A = list(chain.from_iterable((gen, gen**-1) \ for gen in self.fp_group.generators)) #P[alpha, x] Only defined when alpha^x is defined. self.P = [[None]*len(self.A)] # the mathematical coset table which is a list of lists self.table = [[None]*len(self.A)] self.A_dict = {x: self.A.index(x) for x in self.A} self.A_dict_inv = {} for x, index in self.A_dict.items(): if index % 2 == 0: self.A_dict_inv[x] = self.A_dict[x] + 1 else: self.A_dict_inv[x] = self.A_dict[x] - 1 # used in the coset-table based method of coset enumeration. Each of # the element is called a "deduction" which is the form (alpha, x) whenever # a value is assigned to alpha^x during a definition or "deduction process" self.deduction_stack = [] # Attributes for modified methods. H = self.subgroup self._grp = free_group(', ' .join(["a_%d" % i for i in range(len(H))]))[0] self.P = [[None]*len(self.A)] self.p_p = {} @property def omega(self): """Set of live cosets. """ return [coset for coset in range(len(self.p)) if self.p[coset] == coset] def copy(self): """ Return a shallow copy of Coset Table instance ``self``. """ self_copy = self.__class__(self.fp_group, self.subgroup) self_copy.table = [list(perm_rep) for perm_rep in self.table] self_copy.p = list(self.p) self_copy.deduction_stack = list(self.deduction_stack) return self_copy def __str__(self): return "Coset Table on %s with %s as subgroup generators" \ % (self.fp_group, self.subgroup) __repr__ = __str__ @property def n(self): """The number `n` represents the length of the sublist containing the live cosets. """ if not self.table: return 0 return max(self.omega) + 1 # Pg. 152 [1] def is_complete(self): r""" The coset table is called complete if it has no undefined entries on the live cosets; that is, `\alpha^x` is defined for all `\alpha \in \Omega` and `x \in A`. """ return not any(None in self.table[coset] for coset in self.omega) # Pg. 153 [1] def define(self, alpha, x, modified=False): r""" This routine is used in the relator-based strategy of Todd-Coxeter algorithm if some `\alpha^x` is undefined. We check whether there is space available for defining a new coset. If there is enough space then we remedy this by adjoining a new coset `\beta` to `\Omega` (i.e to set of live cosets) and put that equal to `\alpha^x`, then make an assignment satisfying Property[1]. If there is not enough space then we halt the Coset Table creation. The maximum amount of space that can be used by Coset Table can be manipulated using the class variable ``CosetTable.coset_table_max_limit``. See Also ======== define_c """ A = self.A table = self.table len_table = len(table) if len_table >= self.coset_table_limit: # abort the further generation of cosets raise ValueError("the coset enumeration has defined more than " "%s cosets. Try with a greater value max number of cosets " % self.coset_table_limit) table.append([None]*len(A)) self.P.append([None]*len(self.A)) # beta is the new coset generated beta = len_table self.p.append(beta) table[alpha][self.A_dict[x]] = beta table[beta][self.A_dict_inv[x]] = alpha # P[alpha][x] = epsilon, P[beta][x**-1] = epsilon if modified: self.P[alpha][self.A_dict[x]] = self._grp.identity self.P[beta][self.A_dict_inv[x]] = self._grp.identity self.p_p[beta] = self._grp.identity def define_c(self, alpha, x): r""" A variation of ``define`` routine, described on Pg. 165 [1], used in the coset table-based strategy of Todd-Coxeter algorithm. It differs from ``define`` routine in that for each definition it also adds the tuple `(\alpha, x)` to the deduction stack. See Also ======== define """ A = self.A table = self.table len_table = len(table) if len_table >= self.coset_table_limit: # abort the further generation of cosets raise ValueError("the coset enumeration has defined more than " "%s cosets. Try with a greater value max number of cosets " % self.coset_table_limit) table.append([None]*len(A)) # beta is the new coset generated beta = len_table self.p.append(beta) table[alpha][self.A_dict[x]] = beta table[beta][self.A_dict_inv[x]] = alpha # append to deduction stack self.deduction_stack.append((alpha, x)) def scan_c(self, alpha, word): """ A variation of ``scan`` routine, described on pg. 165 of [1], which puts at tuple, whenever a deduction occurs, to deduction stack. See Also ======== scan, scan_check, scan_and_fill, scan_and_fill_c """ # alpha is an integer representing a "coset" # since scanning can be in two cases # 1. for alpha=0 and w in Y (i.e generating set of H) # 2. alpha in Omega (set of live cosets), w in R (relators) A_dict = self.A_dict A_dict_inv = self.A_dict_inv table = self.table f = alpha i = 0 r = len(word) b = alpha j = r - 1 # list of union of generators and their inverses while i <= j and table[f][A_dict[word[i]]] is not None: f = table[f][A_dict[word[i]]] i += 1 if i > j: if f != b: self.coincidence_c(f, b) return while j >= i and table[b][A_dict_inv[word[j]]] is not None: b = table[b][A_dict_inv[word[j]]] j -= 1 if j < i: # we have an incorrect completed scan with coincidence f ~ b # run the "coincidence" routine self.coincidence_c(f, b) elif j == i: # deduction process table[f][A_dict[word[i]]] = b table[b][A_dict_inv[word[i]]] = f self.deduction_stack.append((f, word[i])) # otherwise scan is incomplete and yields no information # alpha, beta coincide, i.e. alpha, beta represent the pair of cosets where # coincidence occurs def coincidence_c(self, alpha, beta): """ A variation of ``coincidence`` routine used in the coset-table based method of coset enumeration. The only difference being on addition of a new coset in coset table(i.e new coset introduction), then it is appended to ``deduction_stack``. See Also ======== coincidence """ A_dict = self.A_dict A_dict_inv = self.A_dict_inv table = self.table # behaves as a queue q = [] self.merge(alpha, beta, q) while len(q) > 0: gamma = q.pop(0) for x in A_dict: delta = table[gamma][A_dict[x]] if delta is not None: table[delta][A_dict_inv[x]] = None # only line of difference from ``coincidence`` routine self.deduction_stack.append((delta, x**-1)) mu = self.rep(gamma) nu = self.rep(delta) if table[mu][A_dict[x]] is not None: self.merge(nu, table[mu][A_dict[x]], q) elif table[nu][A_dict_inv[x]] is not None: self.merge(mu, table[nu][A_dict_inv[x]], q) else: table[mu][A_dict[x]] = nu table[nu][A_dict_inv[x]] = mu def scan(self, alpha, word, y=None, fill=False, modified=False): r""" ``scan`` performs a scanning process on the input ``word``. It first locates the largest prefix ``s`` of ``word`` for which `\alpha^s` is defined (i.e is not ``None``), ``s`` may be empty. Let ``word=sv``, let ``t`` be the longest suffix of ``v`` for which `\alpha^{t^{-1}}` is defined, and let ``v=ut``. Then three possibilities are there: 1. If ``t=v``, then we say that the scan completes, and if, in addition `\alpha^s = \alpha^{t^{-1}}`, then we say that the scan completes correctly. 2. It can also happen that scan does not complete, but `|u|=1`; that is, the word ``u`` consists of a single generator `x \in A`. In that case, if `\alpha^s = \beta` and `\alpha^{t^{-1}} = \gamma`, then we can set `\beta^x = \gamma` and `\gamma^{x^{-1}} = \beta`. These assignments are known as deductions and enable the scan to complete correctly. 3. See ``coicidence`` routine for explanation of third condition. Notes ===== The code for the procedure of scanning `\alpha \in \Omega` under `w \in A*` is defined on pg. 155 [1] See Also ======== scan_c, scan_check, scan_and_fill, scan_and_fill_c Scan and Fill ============= Performed when the default argument fill=True. Modified Scan ============= Performed when the default argument modified=True """ # alpha is an integer representing a "coset" # since scanning can be in two cases # 1. for alpha=0 and w in Y (i.e generating set of H) # 2. alpha in Omega (set of live cosets), w in R (relators) A_dict = self.A_dict A_dict_inv = self.A_dict_inv table = self.table f = alpha i = 0 r = len(word) b = alpha j = r - 1 b_p = y if modified: f_p = self._grp.identity flag = 0 while fill or flag == 0: flag = 1 while i <= j and table[f][A_dict[word[i]]] is not None: if modified: f_p = f_p*self.P[f][A_dict[word[i]]] f = table[f][A_dict[word[i]]] i += 1 if i > j: if f != b: if modified: self.modified_coincidence(f, b, f_p**-1*y) else: self.coincidence(f, b) return while j >= i and table[b][A_dict_inv[word[j]]] is not None: if modified: b_p = b_p*self.P[b][self.A_dict_inv[word[j]]] b = table[b][A_dict_inv[word[j]]] j -= 1 if j < i: # we have an incorrect completed scan with coincidence f ~ b # run the "coincidence" routine if modified: self.modified_coincidence(f, b, f_p**-1*b_p) else: self.coincidence(f, b) elif j == i: # deduction process table[f][A_dict[word[i]]] = b table[b][A_dict_inv[word[i]]] = f if modified: self.P[f][self.A_dict[word[i]]] = f_p**-1*b_p self.P[b][self.A_dict_inv[word[i]]] = b_p**-1*f_p return elif fill: self.define(f, word[i], modified=modified) # otherwise scan is incomplete and yields no information # used in the low-index subgroups algorithm def scan_check(self, alpha, word): r""" Another version of ``scan`` routine, described on, it checks whether `\alpha` scans correctly under `word`, it is a straightforward modification of ``scan``. ``scan_check`` returns ``False`` (rather than calling ``coincidence``) if the scan completes incorrectly; otherwise it returns ``True``. See Also ======== scan, scan_c, scan_and_fill, scan_and_fill_c """ # alpha is an integer representing a "coset" # since scanning can be in two cases # 1. for alpha=0 and w in Y (i.e generating set of H) # 2. alpha in Omega (set of live cosets), w in R (relators) A_dict = self.A_dict A_dict_inv = self.A_dict_inv table = self.table f = alpha i = 0 r = len(word) b = alpha j = r - 1 while i <= j and table[f][A_dict[word[i]]] is not None: f = table[f][A_dict[word[i]]] i += 1 if i > j: return f == b while j >= i and table[b][A_dict_inv[word[j]]] is not None: b = table[b][A_dict_inv[word[j]]] j -= 1 if j < i: # we have an incorrect completed scan with coincidence f ~ b # return False, instead of calling coincidence routine return False elif j == i: # deduction process table[f][A_dict[word[i]]] = b table[b][A_dict_inv[word[i]]] = f return True def merge(self, k, lamda, q, w=None, modified=False): """ Merge two classes with representatives ``k`` and ``lamda``, described on Pg. 157 [1] (for pseudocode), start by putting ``p[k] = lamda``. It is more efficient to choose the new representative from the larger of the two classes being merged, i.e larger among ``k`` and ``lamda``. procedure ``merge`` performs the merging operation, adds the deleted class representative to the queue ``q``. Parameters ========== 'k', 'lamda' being the two class representatives to be merged. Notes ===== Pg. 86-87 [1] contains a description of this method. See Also ======== coincidence, rep """ p = self.p rep = self.rep phi = rep(k, modified=modified) psi = rep(lamda, modified=modified) if phi != psi: mu = min(phi, psi) v = max(phi, psi) p[v] = mu if modified: if v == phi: self.p_p[phi] = self.p_p[k]**-1*w*self.p_p[lamda] else: self.p_p[psi] = self.p_p[lamda]**-1*w**-1*self.p_p[k] q.append(v) def rep(self, k, modified=False): r""" Parameters ========== `k \in [0 \ldots n-1]`, as for ``self`` only array ``p`` is used Returns ======= Representative of the class containing ``k``. Returns the representative of `\sim` class containing ``k``, it also makes some modification to array ``p`` of ``self`` to ease further computations, described on Pg. 157 [1]. The information on classes under `\sim` is stored in array `p` of ``self`` argument, which will always satisfy the property: `p[\alpha] \sim \alpha` and `p[\alpha]=\alpha \iff \alpha=rep(\alpha)` `\forall \in [0 \ldots n-1]`. So, for `\alpha \in [0 \ldots n-1]`, we find `rep(self, \alpha)` by continually replacing `\alpha` by `p[\alpha]` until it becomes constant (i.e satisfies `p[\alpha] = \alpha`):w To increase the efficiency of later ``rep`` calculations, whenever we find `rep(self, \alpha)=\beta`, we set `p[\gamma] = \beta \forall \gamma \in p-chain` from `\alpha` to `\beta` Notes ===== ``rep`` routine is also described on Pg. 85-87 [1] in Atkinson's algorithm, this results from the fact that ``coincidence`` routine introduces functionality similar to that introduced by the ``minimal_block`` routine on Pg. 85-87 [1]. See Also ======== coincidence, merge """ p = self.p lamda = k rho = p[lamda] if modified: s = p[:] while rho != lamda: if modified: s[rho] = lamda lamda = rho rho = p[lamda] if modified: rho = s[lamda] while rho != k: mu = rho rho = s[mu] p[rho] = lamda self.p_p[rho] = self.p_p[rho]*self.p_p[mu] else: mu = k rho = p[mu] while rho != lamda: p[mu] = lamda mu = rho rho = p[mu] return lamda # alpha, beta coincide, i.e. alpha, beta represent the pair of cosets # where coincidence occurs def coincidence(self, alpha, beta, w=None, modified=False): r""" The third situation described in ``scan`` routine is handled by this routine, described on Pg. 156-161 [1]. The unfortunate situation when the scan completes but not correctly, then ``coincidence`` routine is run. i.e when for some `i` with `1 \le i \le r+1`, we have `w=st` with `s=x_1*x_2 ... x_{i-1}`, `t=x_i*x_{i+1} ... x_r`, and `\beta = \alpha^s` and `\gamma = \alph^{t-1}` are defined but unequal. This means that `\beta` and `\gamma` represent the same coset of `H` in `G`. Described on Pg. 156 [1]. ``rep`` See Also ======== scan """ A_dict = self.A_dict A_dict_inv = self.A_dict_inv table = self.table # behaves as a queue q = [] if modified: self.modified_merge(alpha, beta, w, q) else: self.merge(alpha, beta, q) while len(q) > 0: gamma = q.pop(0) for x in A_dict: delta = table[gamma][A_dict[x]] if delta is not None: table[delta][A_dict_inv[x]] = None mu = self.rep(gamma, modified=modified) nu = self.rep(delta, modified=modified) if table[mu][A_dict[x]] is not None: if modified: v = self.p_p[delta]**-1*self.P[gamma][self.A_dict[x]]**-1 v = v*self.p_p[gamma]*self.P[mu][self.A_dict[x]] self.modified_merge(nu, table[mu][self.A_dict[x]], v, q) else: self.merge(nu, table[mu][A_dict[x]], q) elif table[nu][A_dict_inv[x]] is not None: if modified: v = self.p_p[gamma]**-1*self.P[gamma][self.A_dict[x]] v = v*self.p_p[delta]*self.P[mu][self.A_dict_inv[x]] self.modified_merge(mu, table[nu][self.A_dict_inv[x]], v, q) else: self.merge(mu, table[nu][A_dict_inv[x]], q) else: table[mu][A_dict[x]] = nu table[nu][A_dict_inv[x]] = mu if modified: v = self.p_p[gamma]**-1*self.P[gamma][self.A_dict[x]]*self.p_p[delta] self.P[mu][self.A_dict[x]] = v self.P[nu][self.A_dict_inv[x]] = v**-1 # method used in the HLT strategy def scan_and_fill(self, alpha, word): """ A modified version of ``scan`` routine used in the relator-based method of coset enumeration, described on pg. 162-163 [1], which follows the idea that whenever the procedure is called and the scan is incomplete then it makes new definitions to enable the scan to complete; i.e it fills in the gaps in the scan of the relator or subgroup generator. """ self.scan(alpha, word, fill=True) def scan_and_fill_c(self, alpha, word): """ A modified version of ``scan`` routine, described on Pg. 165 second para. [1], with modification similar to that of ``scan_anf_fill`` the only difference being it calls the coincidence procedure used in the coset-table based method i.e. the routine ``coincidence_c`` is used. See Also ======== scan, scan_and_fill """ A_dict = self.A_dict A_dict_inv = self.A_dict_inv table = self.table r = len(word) f = alpha i = 0 b = alpha j = r - 1 # loop until it has filled the alpha row in the table. while True: # do the forward scanning while i <= j and table[f][A_dict[word[i]]] is not None: f = table[f][A_dict[word[i]]] i += 1 if i > j: if f != b: self.coincidence_c(f, b) return # forward scan was incomplete, scan backwards while j >= i and table[b][A_dict_inv[word[j]]] is not None: b = table[b][A_dict_inv[word[j]]] j -= 1 if j < i: self.coincidence_c(f, b) elif j == i: table[f][A_dict[word[i]]] = b table[b][A_dict_inv[word[i]]] = f self.deduction_stack.append((f, word[i])) else: self.define_c(f, word[i]) # method used in the HLT strategy def look_ahead(self): """ When combined with the HLT method this is known as HLT+Lookahead method of coset enumeration, described on pg. 164 [1]. Whenever ``define`` aborts due to lack of space available this procedure is executed. This routine helps in recovering space resulting from "coincidence" of cosets. """ R = self.fp_group.relators p = self.p # complete scan all relators under all cosets(obviously live) # without making new definitions for beta in self.omega: for w in R: self.scan(beta, w) if p[beta] < beta: break # Pg. 166 def process_deductions(self, R_c_x, R_c_x_inv): """ Processes the deductions that have been pushed onto ``deduction_stack``, described on Pg. 166 [1] and is used in coset-table based enumeration. See Also ======== deduction_stack """ p = self.p table = self.table while len(self.deduction_stack) > 0: if len(self.deduction_stack) >= CosetTable.max_stack_size: self.look_ahead() del self.deduction_stack[:] continue else: alpha, x = self.deduction_stack.pop() if p[alpha] == alpha: for w in R_c_x: self.scan_c(alpha, w) if p[alpha] < alpha: break beta = table[alpha][self.A_dict[x]] if beta is not None and p[beta] == beta: for w in R_c_x_inv: self.scan_c(beta, w) if p[beta] < beta: break def process_deductions_check(self, R_c_x, R_c_x_inv): """ A variation of ``process_deductions``, this calls ``scan_check`` wherever ``process_deductions`` calls ``scan``, described on Pg. [1]. See Also ======== process_deductions """ table = self.table while len(self.deduction_stack) > 0: alpha, x = self.deduction_stack.pop() for w in R_c_x: if not self.scan_check(alpha, w): return False beta = table[alpha][self.A_dict[x]] if beta is not None: for w in R_c_x_inv: if not self.scan_check(beta, w): return False return True def switch(self, beta, gamma): r"""Switch the elements `\beta, \gamma \in \Omega` of ``self``, used by the ``standardize`` procedure, described on Pg. 167 [1]. See Also ======== standardize """ A = self.A A_dict = self.A_dict table = self.table for x in A: z = table[gamma][A_dict[x]] table[gamma][A_dict[x]] = table[beta][A_dict[x]] table[beta][A_dict[x]] = z for alpha in range(len(self.p)): if self.p[alpha] == alpha: if table[alpha][A_dict[x]] == beta: table[alpha][A_dict[x]] = gamma elif table[alpha][A_dict[x]] == gamma: table[alpha][A_dict[x]] = beta def standardize(self): r""" A coset table is standardized if when running through the cosets and within each coset through the generator images (ignoring generator inverses), the cosets appear in order of the integers `0, 1, , \ldots, n`. "Standardize" reorders the elements of `\Omega` such that, if we scan the coset table first by elements of `\Omega` and then by elements of A, then the cosets occur in ascending order. ``standardize()`` is used at the end of an enumeration to permute the cosets so that they occur in some sort of standard order. Notes ===== procedure is described on pg. 167-168 [1], it also makes use of the ``switch`` routine to replace by smaller integer value. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r >>> F, x, y = free_group("x, y") # Example 5.3 from [1] >>> f = FpGroup(F, [x**2*y**2, x**3*y**5]) >>> C = coset_enumeration_r(f, []) >>> C.compress() >>> C.table [[1, 3, 1, 3], [2, 0, 2, 0], [3, 1, 3, 1], [0, 2, 0, 2]] >>> C.standardize() >>> C.table [[1, 2, 1, 2], [3, 0, 3, 0], [0, 3, 0, 3], [2, 1, 2, 1]] """ A = self.A A_dict = self.A_dict gamma = 1 for alpha, x in product(range(self.n), A): beta = self.table[alpha][A_dict[x]] if beta >= gamma: if beta > gamma: self.switch(gamma, beta) gamma += 1 if gamma == self.n: return # Compression of a Coset Table def compress(self): """Removes the non-live cosets from the coset table, described on pg. 167 [1]. """ gamma = -1 A = self.A A_dict = self.A_dict A_dict_inv = self.A_dict_inv table = self.table chi = tuple([i for i in range(len(self.p)) if self.p[i] != i]) for alpha in self.omega: gamma += 1 if gamma != alpha: # replace alpha by gamma in coset table for x in A: beta = table[alpha][A_dict[x]] table[gamma][A_dict[x]] = beta table[beta][A_dict_inv[x]] == gamma # all the cosets in the table are live cosets self.p = list(range(gamma + 1)) # delete the useless columns del table[len(self.p):] # re-define values for row in table: for j in range(len(self.A)): row[j] -= bisect_left(chi, row[j]) def conjugates(self, R): R_c = list(chain.from_iterable((rel.cyclic_conjugates(), \ (rel**-1).cyclic_conjugates()) for rel in R)) R_set = set() for conjugate in R_c: R_set = R_set.union(conjugate) R_c_list = [] for x in self.A: r = {word for word in R_set if word[0] == x} R_c_list.append(r) R_set.difference_update(r) return R_c_list def coset_representative(self, coset): ''' Compute the coset representative of a given coset. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) >>> C = coset_enumeration_r(f, [x]) >>> C.compress() >>> C.table [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1]] >>> C.coset_representative(0) >>> C.coset_representative(1) y >>> C.coset_representative(2) y**-1 ''' for x in self.A: gamma = self.table[coset][self.A_dict[x]] if coset == 0: return self.fp_group.identity if gamma < coset: return self.coset_representative(gamma)*x**-1 ############################## # Modified Methods # ############################## def modified_define(self, alpha, x): r""" Define a function p_p from from [1..n] to A* as an additional component of the modified coset table. Parameters ========== \alpha \in \Omega x \in A* See Also ======== define """ self.define(alpha, x, modified=True) def modified_scan(self, alpha, w, y, fill=False): r""" Parameters ========== \alpha \in \Omega w \in A* y \in (YUY^-1) fill -- `modified_scan_and_fill` when set to True. See Also ======== scan """ self.scan(alpha, w, y=y, fill=fill, modified=True) def modified_scan_and_fill(self, alpha, w, y): self.modified_scan(alpha, w, y, fill=True) def modified_merge(self, k, lamda, w, q): r""" Parameters ========== 'k', 'lamda' -- the two class representatives to be merged. q -- queue of length l of elements to be deleted from `\Omega` *. w -- Word in (YUY^-1) See Also ======== merge """ self.merge(k, lamda, q, w=w, modified=True) def modified_rep(self, k): r""" Parameters ========== `k \in [0 \ldots n-1]` See Also ======== rep """ self.rep(k, modified=True) def modified_coincidence(self, alpha, beta, w): r""" Parameters ========== A coincident pair `\alpha, \beta \in \Omega, w \in Y \cup Y^{-1}` See Also ======== coincidence """ self.coincidence(alpha, beta, w=w, modified=True) ############################################################################### # COSET ENUMERATION # ############################################################################### # relator-based method def coset_enumeration_r(fp_grp, Y, max_cosets=None, draft=None, incomplete=False, modified=False): """ This is easier of the two implemented methods of coset enumeration. and is often called the HLT method, after Hazelgrove, Leech, Trotter The idea is that we make use of ``scan_and_fill`` makes new definitions whenever the scan is incomplete to enable the scan to complete; this way we fill in the gaps in the scan of the relator or subgroup generator, that's why the name relator-based method. An instance of `CosetTable` for `fp_grp` can be passed as the keyword argument `draft` in which case the coset enumeration will start with that instance and attempt to complete it. When `incomplete` is `True` and the function is unable to complete for some reason, the partially complete table will be returned. # TODO: complete the docstring See Also ======== scan_and_fill, Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r >>> F, x, y = free_group("x, y") # Example 5.1 from [1] >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) >>> C = coset_enumeration_r(f, [x]) >>> for i in range(len(C.p)): ... if C.p[i] == i: ... print(C.table[i]) [0, 0, 1, 2] [1, 1, 2, 0] [2, 2, 0, 1] >>> C.p [0, 1, 2, 1, 1] # Example from exercises Q2 [1] >>> f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3]) >>> C = coset_enumeration_r(f, []) >>> C.compress(); C.standardize() >>> C.table [[1, 2, 3, 4], [5, 0, 6, 7], [0, 5, 7, 6], [7, 6, 5, 0], [6, 7, 0, 5], [2, 1, 4, 3], [3, 4, 2, 1], [4, 3, 1, 2]] # Example 5.2 >>> f = FpGroup(F, [x**2, y**3, (x*y)**3]) >>> Y = [x*y] >>> C = coset_enumeration_r(f, Y) >>> for i in range(len(C.p)): ... if C.p[i] == i: ... print(C.table[i]) [1, 1, 2, 1] [0, 0, 0, 2] [3, 3, 1, 0] [2, 2, 3, 3] # Example 5.3 >>> f = FpGroup(F, [x**2*y**2, x**3*y**5]) >>> Y = [] >>> C = coset_enumeration_r(f, Y) >>> for i in range(len(C.p)): ... if C.p[i] == i: ... print(C.table[i]) [1, 3, 1, 3] [2, 0, 2, 0] [3, 1, 3, 1] [0, 2, 0, 2] # Example 5.4 >>> F, a, b, c, d, e = free_group("a, b, c, d, e") >>> f = FpGroup(F, [a*b*c**-1, b*c*d**-1, c*d*e**-1, d*e*a**-1, e*a*b**-1]) >>> Y = [a] >>> C = coset_enumeration_r(f, Y) >>> for i in range(len(C.p)): ... if C.p[i] == i: ... print(C.table[i]) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] # example of "compress" method >>> C.compress() >>> C.table [[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]] # Exercises Pg. 161, Q2. >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3]) >>> Y = [] >>> C = coset_enumeration_r(f, Y) >>> C.compress() >>> C.standardize() >>> C.table [[1, 2, 3, 4], [5, 0, 6, 7], [0, 5, 7, 6], [7, 6, 5, 0], [6, 7, 0, 5], [2, 1, 4, 3], [3, 4, 2, 1], [4, 3, 1, 2]] # John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson # Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490 # from 1973chwd.pdf # Table 1. Ex. 1 >>> F, r, s, t = free_group("r, s, t") >>> E1 = FpGroup(F, [t**-1*r*t*r**-2, r**-1*s*r*s**-2, s**-1*t*s*t**-2]) >>> C = coset_enumeration_r(E1, [r]) >>> for i in range(len(C.p)): ... if C.p[i] == i: ... print(C.table[i]) [0, 0, 0, 0, 0, 0] Ex. 2 >>> F, a, b = free_group("a, b") >>> Cox = FpGroup(F, [a**6, b**6, (a*b)**2, (a**2*b**2)**2, (a**3*b**3)**5]) >>> C = coset_enumeration_r(Cox, [a]) >>> index = 0 >>> for i in range(len(C.p)): ... if C.p[i] == i: ... index += 1 >>> index 500 # Ex. 3 >>> F, a, b = free_group("a, b") >>> B_2_4 = FpGroup(F, [a**4, b**4, (a*b)**4, (a**-1*b)**4, (a**2*b)**4, \ (a*b**2)**4, (a**2*b**2)**4, (a**-1*b*a*b)**4, (a*b**-1*a*b)**4]) >>> C = coset_enumeration_r(B_2_4, [a]) >>> index = 0 >>> for i in range(len(C.p)): ... if C.p[i] == i: ... index += 1 >>> index 1024 References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of computational group theory" """ # 1. Initialize a coset table C for < X|R > C = CosetTable(fp_grp, Y, max_cosets=max_cosets) # Define coset table methods. if modified: _scan_and_fill = C.modified_scan_and_fill _define = C.modified_define else: _scan_and_fill = C.scan_and_fill _define = C.define if draft: C.table = draft.table[:] C.p = draft.p[:] R = fp_grp.relators A_dict = C.A_dict p = C.p for i in range(0, len(Y)): if modified: _scan_and_fill(0, Y[i], C._grp.generators[i]) else: _scan_and_fill(0, Y[i]) alpha = 0 while alpha < C.n: if p[alpha] == alpha: try: for w in R: if modified: _scan_and_fill(alpha, w, C._grp.identity) else: _scan_and_fill(alpha, w) # if alpha was eliminated during the scan then break if p[alpha] < alpha: break if p[alpha] == alpha: for x in A_dict: if C.table[alpha][A_dict[x]] is None: _define(alpha, x) except ValueError as e: if incomplete: return C raise e alpha += 1 return C def modified_coset_enumeration_r(fp_grp, Y, max_cosets=None, draft=None, incomplete=False): r""" Introduce a new set of symbols y \in Y that correspond to the generators of the subgroup. Store the elements of Y as a word P[\alpha, x] and compute the coset table similar to that of the regular coset enumeration methods. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup >>> from sympy.combinatorics.coset_table import modified_coset_enumeration_r >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) >>> C = modified_coset_enumeration_r(f, [x]) >>> C.table [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1], [None, 1, None, None], [1, 3, None, None]] See Also ======== coset_enumertation_r References ========== .. [1] Holt, D., Eick, B., O'Brien, E., "Handbook of Computational Group Theory", Section 5.3.2 """ return coset_enumeration_r(fp_grp, Y, max_cosets=max_cosets, draft=draft, incomplete=incomplete, modified=True) # Pg. 166 # coset-table based method def coset_enumeration_c(fp_grp, Y, max_cosets=None, draft=None, incomplete=False): """ >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_c >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) >>> C = coset_enumeration_c(f, [x]) >>> C.table [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1]] """ # Initialize a coset table C for < X|R > X = fp_grp.generators R = fp_grp.relators C = CosetTable(fp_grp, Y, max_cosets=max_cosets) if draft: C.table = draft.table[:] C.p = draft.p[:] C.deduction_stack = draft.deduction_stack for alpha, x in product(range(len(C.table)), X): if not C.table[alpha][C.A_dict[x]] is None: C.deduction_stack.append((alpha, x)) A = C.A # replace all the elements by cyclic reductions R_cyc_red = [rel.identity_cyclic_reduction() for rel in R] R_c = list(chain.from_iterable((rel.cyclic_conjugates(), (rel**-1).cyclic_conjugates()) \ for rel in R_cyc_red)) R_set = set() for conjugate in R_c: R_set = R_set.union(conjugate) # a list of subsets of R_c whose words start with "x". R_c_list = [] for x in C.A: r = {word for word in R_set if word[0] == x} R_c_list.append(r) R_set.difference_update(r) for w in Y: C.scan_and_fill_c(0, w) for x in A: C.process_deductions(R_c_list[C.A_dict[x]], R_c_list[C.A_dict_inv[x]]) alpha = 0 while alpha < len(C.table): if C.p[alpha] == alpha: try: for x in C.A: if C.p[alpha] != alpha: break if C.table[alpha][C.A_dict[x]] is None: C.define_c(alpha, x) C.process_deductions(R_c_list[C.A_dict[x]], R_c_list[C.A_dict_inv[x]]) except ValueError as e: if incomplete: return C raise e alpha += 1 return C sympy-sympy-1.9/sympy/combinatorics/fp_groups.py000066400000000000000000001355511412543434000223300ustar00rootroot00000000000000"""Finitely Presented Groups and its algorithms. """ from sympy import S from sympy.combinatorics.free_groups import (FreeGroup, FreeGroupElement, free_group) from sympy.combinatorics.rewritingsystem import RewritingSystem from sympy.combinatorics.coset_table import (CosetTable, coset_enumeration_r, coset_enumeration_c) from sympy.combinatorics import PermutationGroup from sympy.printing.defaults import DefaultPrinting from sympy.utilities import public from sympy.utilities.magic import pollute from sympy import symbols from itertools import product @public def fp_group(fr_grp, relators=[]): _fp_group = FpGroup(fr_grp, relators) return (_fp_group,) + tuple(_fp_group._generators) @public def xfp_group(fr_grp, relators=[]): _fp_group = FpGroup(fr_grp, relators) return (_fp_group, _fp_group._generators) # Does not work. Both symbols and pollute are undefined. Never tested. @public def vfp_group(fr_grpm, relators): _fp_group = FpGroup(symbols, relators) pollute([sym.name for sym in _fp_group.symbols], _fp_group.generators) return _fp_group def _parse_relators(rels): """Parse the passed relators.""" return rels ############################################################################### # FINITELY PRESENTED GROUPS # ############################################################################### class FpGroup(DefaultPrinting): """ The FpGroup would take a FreeGroup and a list/tuple of relators, the relators would be specified in such a way that each of them be equal to the identity of the provided free group. """ is_group = True is_FpGroup = True is_PermutationGroup = False def __init__(self, fr_grp, relators): relators = _parse_relators(relators) self.free_group = fr_grp self.relators = relators self.generators = self._generators() self.dtype = type("FpGroupElement", (FpGroupElement,), {"group": self}) # CosetTable instance on identity subgroup self._coset_table = None # returns whether coset table on identity subgroup # has been standardized self._is_standardized = False self._order = None self._center = None self._rewriting_system = RewritingSystem(self) self._perm_isomorphism = None return def _generators(self): return self.free_group.generators def make_confluent(self): ''' Try to make the group's rewriting system confluent ''' self._rewriting_system.make_confluent() return def reduce(self, word): ''' Return the reduced form of `word` in `self` according to the group's rewriting system. If it's confluent, the reduced form is the unique normal form of the word in the group. ''' return self._rewriting_system.reduce(word) def equals(self, word1, word2): ''' Compare `word1` and `word2` for equality in the group using the group's rewriting system. If the system is confluent, the returned answer is necessarily correct. (If it isn't, `False` could be returned in some cases where in fact `word1 == word2`) ''' if self.reduce(word1*word2**-1) == self.identity: return True elif self._rewriting_system.is_confluent: return False return None @property def identity(self): return self.free_group.identity def __contains__(self, g): return g in self.free_group def subgroup(self, gens, C=None, homomorphism=False): ''' Return the subgroup generated by `gens` using the Reidemeister-Schreier algorithm homomorphism -- When set to True, return a dictionary containing the images of the presentation generators in the original group. Examples ======== >>> from sympy.combinatorics.fp_groups import FpGroup >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**3, y**5, (x*y)**2]) >>> H = [x*y, x**-1*y**-1*x*y*x] >>> K, T = f.subgroup(H, homomorphism=True) >>> T(K.generators) [x*y, x**-1*y**2*x**-1] ''' if not all([isinstance(g, FreeGroupElement) for g in gens]): raise ValueError("Generators must be `FreeGroupElement`s") if not all([g.group == self.free_group for g in gens]): raise ValueError("Given generators are not members of the group") if homomorphism: g, rels, _gens = reidemeister_presentation(self, gens, C=C, homomorphism=True) else: g, rels = reidemeister_presentation(self, gens, C=C) if g: g = FpGroup(g[0].group, rels) else: g = FpGroup(free_group('')[0], []) if homomorphism: from sympy.combinatorics.homomorphisms import homomorphism return g, homomorphism(g, self, g.generators, _gens, check=False) return g def coset_enumeration(self, H, strategy="relator_based", max_cosets=None, draft=None, incomplete=False): """ Return an instance of ``coset table``, when Todd-Coxeter algorithm is run over the ``self`` with ``H`` as subgroup, using ``strategy`` argument as strategy. The returned coset table is compressed but not standardized. An instance of `CosetTable` for `fp_grp` can be passed as the keyword argument `draft` in which case the coset enumeration will start with that instance and attempt to complete it. When `incomplete` is `True` and the function is unable to complete for some reason, the partially complete table will be returned. """ if not max_cosets: max_cosets = CosetTable.coset_table_max_limit if strategy == 'relator_based': C = coset_enumeration_r(self, H, max_cosets=max_cosets, draft=draft, incomplete=incomplete) else: C = coset_enumeration_c(self, H, max_cosets=max_cosets, draft=draft, incomplete=incomplete) if C.is_complete(): C.compress() return C def standardize_coset_table(self): """ Standardized the coset table ``self`` and makes the internal variable ``_is_standardized`` equal to ``True``. """ self._coset_table.standardize() self._is_standardized = True def coset_table(self, H, strategy="relator_based", max_cosets=None, draft=None, incomplete=False): """ Return the mathematical coset table of ``self`` in ``H``. """ if not H: if self._coset_table is not None: if not self._is_standardized: self.standardize_coset_table() else: C = self.coset_enumeration([], strategy, max_cosets=max_cosets, draft=draft, incomplete=incomplete) self._coset_table = C self.standardize_coset_table() return self._coset_table.table else: C = self.coset_enumeration(H, strategy, max_cosets=max_cosets, draft=draft, incomplete=incomplete) C.standardize() return C.table def order(self, strategy="relator_based"): """ Returns the order of the finitely presented group ``self``. It uses the coset enumeration with identity group as subgroup, i.e ``H=[]``. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x, y**2]) >>> f.order(strategy="coset_table_based") 2 """ from sympy import S, gcd if self._order is not None: return self._order if self._coset_table is not None: self._order = len(self._coset_table.table) elif len(self.relators) == 0: self._order = self.free_group.order() elif len(self.generators) == 1: self._order = abs(gcd([r.array_form[0][1] for r in self.relators])) elif self._is_infinite(): self._order = S.Infinity else: gens, C = self._finite_index_subgroup() if C: ind = len(C.table) self._order = ind*self.subgroup(gens, C=C).order() else: self._order = self.index([]) return self._order def _is_infinite(self): ''' Test if the group is infinite. Return `True` if the test succeeds and `None` otherwise ''' used_gens = set() for r in self.relators: used_gens.update(r.contains_generators()) if any([g not in used_gens for g in self.generators]): return True # Abelianisation test: check is the abelianisation is infinite abelian_rels = [] from sympy.matrices.normalforms import invariant_factors from sympy.matrices import Matrix for rel in self.relators: abelian_rels.append([rel.exponent_sum(g) for g in self.generators]) m = Matrix(Matrix(abelian_rels)) if 0 in invariant_factors(m): return True else: return None def _finite_index_subgroup(self, s=[]): ''' Find the elements of `self` that generate a finite index subgroup and, if found, return the list of elements and the coset table of `self` by the subgroup, otherwise return `(None, None)` ''' gen = self.most_frequent_generator() rels = list(self.generators) rels.extend(self.relators) if not s: if len(self.generators) == 2: s = [gen] + [g for g in self.generators if g != gen] else: rand = self.free_group.identity i = 0 while ((rand in rels or rand**-1 in rels or rand.is_identity) and i<10): rand = self.random() i += 1 s = [gen, rand] + [g for g in self.generators if g != gen] mid = (len(s)+1)//2 half1 = s[:mid] half2 = s[mid:] draft1 = None draft2 = None m = 200 C = None while not C and (m/2 < CosetTable.coset_table_max_limit): m = min(m, CosetTable.coset_table_max_limit) draft1 = self.coset_enumeration(half1, max_cosets=m, draft=draft1, incomplete=True) if draft1.is_complete(): C = draft1 half = half1 else: draft2 = self.coset_enumeration(half2, max_cosets=m, draft=draft2, incomplete=True) if draft2.is_complete(): C = draft2 half = half2 if not C: m *= 2 if not C: return None, None C.compress() return half, C def most_frequent_generator(self): gens = self.generators rels = self.relators freqs = [sum([r.generator_count(g) for r in rels]) for g in gens] return gens[freqs.index(max(freqs))] def random(self): import random r = self.free_group.identity for i in range(random.randint(2,3)): r = r*random.choice(self.generators)**random.choice([1,-1]) return r def index(self, H, strategy="relator_based"): """ Return the index of subgroup ``H`` in group ``self``. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**5, y**4, y*x*y**3*x**3]) >>> f.index([x]) 4 """ # TODO: use |G:H| = |G|/|H| (currently H can't be made into a group) # when we know |G| and |H| if H == []: return self.order() else: C = self.coset_enumeration(H, strategy) return len(C.table) def __str__(self): if self.free_group.rank > 30: str_form = "" % self.free_group.rank else: str_form = "" % str(self.generators) return str_form __repr__ = __str__ #============================================================================== # PERMUTATION GROUP METHODS #============================================================================== def _to_perm_group(self): ''' Return an isomorphic permutation group and the isomorphism. The implementation is dependent on coset enumeration so will only terminate for finite groups. ''' from sympy.combinatorics import Permutation, PermutationGroup from sympy.combinatorics.homomorphisms import homomorphism if self.order() is S.Infinity: raise NotImplementedError("Permutation presentation of infinite " "groups is not implemented") if self._perm_isomorphism: T = self._perm_isomorphism P = T.image() else: C = self.coset_table([]) gens = self.generators images = [[C[i][2*gens.index(g)] for i in range(len(C))] for g in gens] images = [Permutation(i) for i in images] P = PermutationGroup(images) T = homomorphism(self, P, gens, images, check=False) self._perm_isomorphism = T return P, T def _perm_group_list(self, method_name, *args): ''' Given the name of a `PermutationGroup` method (returning a subgroup or a list of subgroups) and (optionally) additional arguments it takes, return a list or a list of lists containing the generators of this (or these) subgroups in terms of the generators of `self`. ''' P, T = self._to_perm_group() perm_result = getattr(P, method_name)(*args) single = False if isinstance(perm_result, PermutationGroup): perm_result, single = [perm_result], True result = [] for group in perm_result: gens = group.generators result.append(T.invert(gens)) return result[0] if single else result def derived_series(self): ''' Return the list of lists containing the generators of the subgroups in the derived series of `self`. ''' return self._perm_group_list('derived_series') def lower_central_series(self): ''' Return the list of lists containing the generators of the subgroups in the lower central series of `self`. ''' return self._perm_group_list('lower_central_series') def center(self): ''' Return the list of generators of the center of `self`. ''' return self._perm_group_list('center') def derived_subgroup(self): ''' Return the list of generators of the derived subgroup of `self`. ''' return self._perm_group_list('derived_subgroup') def centralizer(self, other): ''' Return the list of generators of the centralizer of `other` (a list of elements of `self`) in `self`. ''' T = self._to_perm_group()[1] other = T(other) return self._perm_group_list('centralizer', other) def normal_closure(self, other): ''' Return the list of generators of the normal closure of `other` (a list of elements of `self`) in `self`. ''' T = self._to_perm_group()[1] other = T(other) return self._perm_group_list('normal_closure', other) def _perm_property(self, attr): ''' Given an attribute of a `PermutationGroup`, return its value for a permutation group isomorphic to `self`. ''' P = self._to_perm_group()[0] return getattr(P, attr) @property def is_abelian(self): ''' Check if `self` is abelian. ''' return self._perm_property("is_abelian") @property def is_nilpotent(self): ''' Check if `self` is nilpotent. ''' return self._perm_property("is_nilpotent") @property def is_solvable(self): ''' Check if `self` is solvable. ''' return self._perm_property("is_solvable") @property def elements(self): ''' List the elements of `self`. ''' P, T = self._to_perm_group() return T.invert(P._elements) @property def is_cyclic(self): """ Return ``True`` if group is Cyclic. """ if len(self.generators) <= 1: return True try: P, T = self._to_perm_group() except NotImplementedError: raise NotImplementedError("Check for infinite Cyclic group " "is not implemented") return P.is_cyclic def abelian_invariants(self): """ Return Abelian Invariants of a group. """ try: P, T = self._to_perm_group() except NotImplementedError: raise NotImplementedError("abelian invariants is not implemented" "for infinite group") return P.abelian_invariants() def composition_series(self): """ Return subnormal series of maximum length for a group. """ try: P, T = self._to_perm_group() except NotImplementedError: raise NotImplementedError("composition series is not implemented" "for infinite group") return P.composition_series() class FpSubgroup(DefaultPrinting): ''' The class implementing a subgroup of an FpGroup or a FreeGroup (only finite index subgroups are supported at this point). This is to be used if one wishes to check if an element of the original group belongs to the subgroup ''' def __init__(self, G, gens, normal=False): super().__init__() self.parent = G self.generators = list({g for g in gens if g != G.identity}) self._min_words = None #for use in __contains__ self.C = None self.normal = normal def __contains__(self, g): if isinstance(self.parent, FreeGroup): if self._min_words is None: # make _min_words - a list of subwords such that # g is in the subgroup if and only if it can be # partitioned into these subwords. Infinite families of # subwords are presented by tuples, e.g. (r, w) # stands for the family of subwords r*w**n*r**-1 def _process(w): # this is to be used before adding new words # into _min_words; if the word w is not cyclically # reduced, it will generate an infinite family of # subwords so should be written as a tuple; # if it is, w**-1 should be added to the list # as well p, r = w.cyclic_reduction(removed=True) if not r.is_identity: return [(r, p)] else: return [w, w**-1] # make the initial list gens = [] for w in self.generators: if self.normal: w = w.cyclic_reduction() gens.extend(_process(w)) for w1 in gens: for w2 in gens: # if w1 and w2 are equal or are inverses, continue if w1 == w2 or (not isinstance(w1, tuple) and w1**-1 == w2): continue # if the start of one word is the inverse of the # end of the other, their multiple should be added # to _min_words because of cancellation if isinstance(w1, tuple): # start, end s1, s2 = w1[0][0], w1[0][0]**-1 else: s1, s2 = w1[0], w1[len(w1)-1] if isinstance(w2, tuple): # start, end r1, r2 = w2[0][0], w2[0][0]**-1 else: r1, r2 = w2[0], w2[len(w1)-1] # p1 and p2 are w1 and w2 or, in case when # w1 or w2 is an infinite family, a representative p1, p2 = w1, w2 if isinstance(w1, tuple): p1 = w1[0]*w1[1]*w1[0]**-1 if isinstance(w2, tuple): p2 = w2[0]*w2[1]*w2[0]**-1 # add the product of the words to the list is necessary if r1**-1 == s2 and not (p1*p2).is_identity: new = _process(p1*p2) if not new in gens: gens.extend(new) if r2**-1 == s1 and not (p2*p1).is_identity: new = _process(p2*p1) if not new in gens: gens.extend(new) self._min_words = gens min_words = self._min_words def _is_subword(w): # check if w is a word in _min_words or one of # the infinite families in it w, r = w.cyclic_reduction(removed=True) if r.is_identity or self.normal: return w in min_words else: t = [s[1] for s in min_words if isinstance(s, tuple) and s[0] == r] return [s for s in t if w.power_of(s)] != [] # store the solution of words for which the result of # _word_break (below) is known known = {} def _word_break(w): # check if w can be written as a product of words # in min_words if len(w) == 0: return True i = 0 while i < len(w): i += 1 prefix = w.subword(0, i) if not _is_subword(prefix): continue rest = w.subword(i, len(w)) if rest not in known: known[rest] = _word_break(rest) if known[rest]: return True return False if self.normal: g = g.cyclic_reduction() return _word_break(g) else: if self.C is None: C = self.parent.coset_enumeration(self.generators) self.C = C i = 0 C = self.C for j in range(len(g)): i = C.table[i][C.A_dict[g[j]]] return i == 0 def order(self): from sympy import S if not self.generators: return 1 if isinstance(self.parent, FreeGroup): return S.Infinity if self.C is None: C = self.parent.coset_enumeration(self.generators) self.C = C # This is valid because `len(self.C.table)` (the index of the subgroup) # will always be finite - otherwise coset enumeration doesn't terminate return self.parent.order()/len(self.C.table) def to_FpGroup(self): if isinstance(self.parent, FreeGroup): gen_syms = [('x_%d'%i) for i in range(len(self.generators))] return free_group(', '.join(gen_syms))[0] return self.parent.subgroup(C=self.C) def __str__(self): if len(self.generators) > 30: str_form = "" % len(self.generators) else: str_form = "" % str(self.generators) return str_form __repr__ = __str__ ############################################################################### # LOW INDEX SUBGROUPS # ############################################################################### def low_index_subgroups(G, N, Y=[]): """ Implements the Low Index Subgroups algorithm, i.e find all subgroups of ``G`` upto a given index ``N``. This implements the method described in [Sim94]. This procedure involves a backtrack search over incomplete Coset Tables, rather than over forced coincidences. Parameters ========== G: An FpGroup < X|R > N: positive integer, representing the maximum index value for subgroups Y: (an optional argument) specifying a list of subgroup generators, such that each of the resulting subgroup contains the subgroup generated by Y. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, low_index_subgroups >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**2, y**3, (x*y)**4]) >>> L = low_index_subgroups(f, 4) >>> for coset_table in L: ... print(coset_table.table) [[0, 0, 0, 0]] [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 3, 3]] [[0, 0, 1, 2], [2, 2, 2, 0], [1, 1, 0, 1]] [[1, 1, 0, 0], [0, 0, 1, 1]] References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" Section 5.4 .. [2] Marston Conder and Peter Dobcsanyi "Applications and Adaptions of the Low Index Subgroups Procedure" """ C = CosetTable(G, []) R = G.relators # length chosen for the length of the short relators len_short_rel = 5 # elements of R2 only checked at the last step for complete # coset tables R2 = {rel for rel in R if len(rel) > len_short_rel} # elements of R1 are used in inner parts of the process to prune # branches of the search tree, R1 = {rel.identity_cyclic_reduction() for rel in set(R) - R2} R1_c_list = C.conjugates(R1) S = [] descendant_subgroups(S, C, R1_c_list, C.A[0], R2, N, Y) return S def descendant_subgroups(S, C, R1_c_list, x, R2, N, Y): A_dict = C.A_dict A_dict_inv = C.A_dict_inv if C.is_complete(): # if C is complete then it only needs to test # whether the relators in R2 are satisfied for w, alpha in product(R2, C.omega): if not C.scan_check(alpha, w): return # relators in R2 are satisfied, append the table to list S.append(C) else: # find the first undefined entry in Coset Table for alpha, x in product(range(len(C.table)), C.A): if C.table[alpha][A_dict[x]] is None: # this is "x" in pseudo-code (using "y" makes it clear) undefined_coset, undefined_gen = alpha, x break # for filling up the undefine entry we try all possible values # of beta in Omega or beta = n where beta^(undefined_gen^-1) is undefined reach = C.omega + [C.n] for beta in reach: if beta < N: if beta == C.n or C.table[beta][A_dict_inv[undefined_gen]] is None: try_descendant(S, C, R1_c_list, R2, N, undefined_coset, \ undefined_gen, beta, Y) def try_descendant(S, C, R1_c_list, R2, N, alpha, x, beta, Y): r""" Solves the problem of trying out each individual possibility for `\alpha^x. """ D = C.copy() if beta == D.n and beta < N: D.table.append([None]*len(D.A)) D.p.append(beta) D.table[alpha][D.A_dict[x]] = beta D.table[beta][D.A_dict_inv[x]] = alpha D.deduction_stack.append((alpha, x)) if not D.process_deductions_check(R1_c_list[D.A_dict[x]], \ R1_c_list[D.A_dict_inv[x]]): return for w in Y: if not D.scan_check(0, w): return if first_in_class(D, Y): descendant_subgroups(S, D, R1_c_list, x, R2, N, Y) def first_in_class(C, Y=[]): """ Checks whether the subgroup ``H=G1`` corresponding to the Coset Table could possibly be the canonical representative of its conjugacy class. Parameters ========== C: CosetTable Returns ======= bool: True/False If this returns False, then no descendant of C can have that property, and so we can abandon C. If it returns True, then we need to process further the node of the search tree corresponding to C, and so we call ``descendant_subgroups`` recursively on C. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, CosetTable, first_in_class >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**2, y**3, (x*y)**4]) >>> C = CosetTable(f, []) >>> C.table = [[0, 0, None, None]] >>> first_in_class(C) True >>> C.table = [[1, 1, 1, None], [0, 0, None, 1]]; C.p = [0, 1] >>> first_in_class(C) True >>> C.table = [[1, 1, 2, 1], [0, 0, 0, None], [None, None, None, 0]] >>> C.p = [0, 1, 2] >>> first_in_class(C) False >>> C.table = [[1, 1, 1, 2], [0, 0, 2, 0], [2, None, 0, 1]] >>> first_in_class(C) False # TODO:: Sims points out in [Sim94] that performance can be improved by # remembering some of the information computed by ``first_in_class``. If # the ``continue alpha`` statement is executed at line 14, then the same thing # will happen for that value of alpha in any descendant of the table C, and so # the values the values of alpha for which this occurs could profitably be # stored and passed through to the descendants of C. Of course this would # make the code more complicated. # The code below is taken directly from the function on page 208 of [Sim94] # nu[alpha] """ n = C.n # lamda is the largest numbered point in Omega_c_alpha which is currently defined lamda = -1 # for alpha in Omega_c, nu[alpha] is the point in Omega_c_alpha corresponding to alpha nu = [None]*n # for alpha in Omega_c_alpha, mu[alpha] is the point in Omega_c corresponding to alpha mu = [None]*n # mutually nu and mu are the mutually-inverse equivalence maps between # Omega_c_alpha and Omega_c next_alpha = False # For each 0!=alpha in [0 .. nc-1], we start by constructing the equivalent # standardized coset table C_alpha corresponding to H_alpha for alpha in range(1, n): # reset nu to "None" after previous value of alpha for beta in range(lamda+1): nu[mu[beta]] = None # we only want to reject our current table in favour of a preceding # table in the ordering in which 1 is replaced by alpha, if the subgroup # G_alpha corresponding to this preceding table definitely contains the # given subgroup for w in Y: # TODO: this should support input of a list of general words # not just the words which are in "A" (i.e gen and gen^-1) if C.table[alpha][C.A_dict[w]] != alpha: # continue with alpha next_alpha = True break if next_alpha: next_alpha = False continue # try alpha as the new point 0 in Omega_C_alpha mu[0] = alpha nu[alpha] = 0 # compare corresponding entries in C and C_alpha lamda = 0 for beta in range(n): for x in C.A: gamma = C.table[beta][C.A_dict[x]] delta = C.table[mu[beta]][C.A_dict[x]] # if either of the entries is undefined, # we move with next alpha if gamma is None or delta is None: # continue with alpha next_alpha = True break if nu[delta] is None: # delta becomes the next point in Omega_C_alpha lamda += 1 nu[delta] = lamda mu[lamda] = delta if nu[delta] < gamma: return False if nu[delta] > gamma: # continue with alpha next_alpha = True break if next_alpha: next_alpha = False break return True #======================================================================== # Simplifying Presentation #======================================================================== def simplify_presentation(*args, change_gens=False): ''' For an instance of `FpGroup`, return a simplified isomorphic copy of the group (e.g. remove redundant generators or relators). Alternatively, a list of generators and relators can be passed in which case the simplified lists will be returned. By default, the generators of the group are unchanged. If you would like to remove redundant generators, set the keyword argument `change_gens = True`. ''' if len(args) == 1: if not isinstance(args[0], FpGroup): raise TypeError("The argument must be an instance of FpGroup") G = args[0] gens, rels = simplify_presentation(G.generators, G.relators, change_gens=change_gens) if gens: return FpGroup(gens[0].group, rels) return FpGroup(FreeGroup([]), []) elif len(args) == 2: gens, rels = args[0][:], args[1][:] if not gens: return gens, rels identity = gens[0].group.identity else: if len(args) == 0: m = "Not enough arguments" else: m = "Too many arguments" raise RuntimeError(m) prev_gens = [] prev_rels = [] while not set(prev_rels) == set(rels): prev_rels = rels while change_gens and not set(prev_gens) == set(gens): prev_gens = gens gens, rels = elimination_technique_1(gens, rels, identity) rels = _simplify_relators(rels, identity) if change_gens: syms = [g.array_form[0][0] for g in gens] F = free_group(syms)[0] identity = F.identity gens = F.generators subs = dict(zip(syms, gens)) for j, r in enumerate(rels): a = r.array_form rel = identity for sym, p in a: rel = rel*subs[sym]**p rels[j] = rel return gens, rels def _simplify_relators(rels, identity): """Relies upon ``_simplification_technique_1`` for its functioning. """ rels = rels[:] rels = list(set(_simplification_technique_1(rels))) rels.sort() rels = [r.identity_cyclic_reduction() for r in rels] try: rels.remove(identity) except ValueError: pass return rels # Pg 350, section 2.5.1 from [2] def elimination_technique_1(gens, rels, identity): rels = rels[:] # the shorter relators are examined first so that generators selected for # elimination will have shorter strings as equivalent rels.sort() gens = gens[:] redundant_gens = {} redundant_rels = [] used_gens = set() # examine each relator in relator list for any generator occurring exactly # once for rel in rels: # don't look for a redundant generator in a relator which # depends on previously found ones contained_gens = rel.contains_generators() if any([g in contained_gens for g in redundant_gens]): continue contained_gens = list(contained_gens) contained_gens.sort(reverse = True) for gen in contained_gens: if rel.generator_count(gen) == 1 and gen not in used_gens: k = rel.exponent_sum(gen) gen_index = rel.index(gen**k) bk = rel.subword(gen_index + 1, len(rel)) fw = rel.subword(0, gen_index) chi = bk*fw redundant_gens[gen] = chi**(-1*k) used_gens.update(chi.contains_generators()) redundant_rels.append(rel) break rels = [r for r in rels if r not in redundant_rels] # eliminate the redundant generators from remaining relators rels = [r.eliminate_words(redundant_gens, _all = True).identity_cyclic_reduction() for r in rels] rels = list(set(rels)) try: rels.remove(identity) except ValueError: pass gens = [g for g in gens if g not in redundant_gens] return gens, rels def _simplification_technique_1(rels): """ All relators are checked to see if they are of the form `gen^n`. If any such relators are found then all other relators are processed for strings in the `gen` known order. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import _simplification_technique_1 >>> F, x, y = free_group("x, y") >>> w1 = [x**2*y**4, x**3] >>> _simplification_technique_1(w1) [x**-1*y**4, x**3] >>> w2 = [x**2*y**-4*x**5, x**3, x**2*y**8, y**5] >>> _simplification_technique_1(w2) [x**-1*y*x**-1, x**3, x**-1*y**-2, y**5] >>> w3 = [x**6*y**4, x**4] >>> _simplification_technique_1(w3) [x**2*y**4, x**4] """ from sympy import gcd rels = rels[:] # dictionary with "gen: n" where gen^n is one of the relators exps = {} for i in range(len(rels)): rel = rels[i] if rel.number_syllables() == 1: g = rel[0] exp = abs(rel.array_form[0][1]) if rel.array_form[0][1] < 0: rels[i] = rels[i]**-1 g = g**-1 if g in exps: exp = gcd(exp, exps[g].array_form[0][1]) exps[g] = g**exp one_syllables_words = exps.values() # decrease some of the exponents in relators, making use of the single # syllable relators for i in range(len(rels)): rel = rels[i] if rel in one_syllables_words: continue rel = rel.eliminate_words(one_syllables_words, _all = True) # if rels[i] contains g**n where abs(n) is greater than half of the power p # of g in exps, g**n can be replaced by g**(n-p) (or g**(p-n) if n<0) for g in rel.contains_generators(): if g in exps: exp = exps[g].array_form[0][1] max_exp = (exp + 1)//2 rel = rel.eliminate_word(g**(max_exp), g**(max_exp-exp), _all = True) rel = rel.eliminate_word(g**(-max_exp), g**(-(max_exp-exp)), _all = True) rels[i] = rel rels = [r.identity_cyclic_reduction() for r in rels] return rels ############################################################################### # SUBGROUP PRESENTATIONS # ############################################################################### # Pg 175 [1] def define_schreier_generators(C, homomorphism=False): ''' Parameters ========== C -- Coset table. homomorphism -- When set to True, return a dictionary containing the images of the presentation generators in the original group. ''' y = [] gamma = 1 f = C.fp_group X = f.generators if homomorphism: # `_gens` stores the elements of the parent group to # to which the schreier generators correspond to. _gens = {} # compute the schreier Traversal tau = {} tau[0] = f.identity C.P = [[None]*len(C.A) for i in range(C.n)] for alpha, x in product(C.omega, C.A): beta = C.table[alpha][C.A_dict[x]] if beta == gamma: C.P[alpha][C.A_dict[x]] = "" C.P[beta][C.A_dict_inv[x]] = "" gamma += 1 if homomorphism: tau[beta] = tau[alpha]*x elif x in X and C.P[alpha][C.A_dict[x]] is None: y_alpha_x = '%s_%s' % (x, alpha) y.append(y_alpha_x) C.P[alpha][C.A_dict[x]] = y_alpha_x if homomorphism: _gens[y_alpha_x] = tau[alpha]*x*tau[beta]**-1 grp_gens = list(free_group(', '.join(y))) C._schreier_free_group = grp_gens.pop(0) C._schreier_generators = grp_gens if homomorphism: C._schreier_gen_elem = _gens # replace all elements of P by, free group elements for i, j in product(range(len(C.P)), range(len(C.A))): # if equals "", replace by identity element if C.P[i][j] == "": C.P[i][j] = C._schreier_free_group.identity elif isinstance(C.P[i][j], str): r = C._schreier_generators[y.index(C.P[i][j])] C.P[i][j] = r beta = C.table[i][j] C.P[beta][j + 1] = r**-1 def reidemeister_relators(C): R = C.fp_group.relators rels = [rewrite(C, coset, word) for word in R for coset in range(C.n)] order_1_gens = {i for i in rels if len(i) == 1} # remove all the order 1 generators from relators rels = list(filter(lambda rel: rel not in order_1_gens, rels)) # replace order 1 generators by identity element in reidemeister relators for i in range(len(rels)): w = rels[i] w = w.eliminate_words(order_1_gens, _all=True) rels[i] = w C._schreier_generators = [i for i in C._schreier_generators if not (i in order_1_gens or i**-1 in order_1_gens)] # Tietze transformation 1 i.e TT_1 # remove cyclic conjugate elements from relators i = 0 while i < len(rels): w = rels[i] j = i + 1 while j < len(rels): if w.is_cyclic_conjugate(rels[j]): del rels[j] else: j += 1 i += 1 C._reidemeister_relators = rels def rewrite(C, alpha, w): """ Parameters ========== C: CosetTable alpha: A live coset w: A word in `A*` Returns ======= rho(tau(alpha), w) Examples ======== >>> from sympy.combinatorics.fp_groups import FpGroup, CosetTable, define_schreier_generators, rewrite >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x ,y") >>> f = FpGroup(F, [x**2, y**3, (x*y)**6]) >>> C = CosetTable(f, []) >>> C.table = [[1, 1, 2, 3], [0, 0, 4, 5], [4, 4, 3, 0], [5, 5, 0, 2], [2, 2, 5, 1], [3, 3, 1, 4]] >>> C.p = [0, 1, 2, 3, 4, 5] >>> define_schreier_generators(C) >>> rewrite(C, 0, (x*y)**6) x_4*y_2*x_3*x_1*x_2*y_4*x_5 """ v = C._schreier_free_group.identity for i in range(len(w)): x_i = w[i] v = v*C.P[alpha][C.A_dict[x_i]] alpha = C.table[alpha][C.A_dict[x_i]] return v # Pg 350, section 2.5.2 from [2] def elimination_technique_2(C): """ This technique eliminates one generator at a time. Heuristically this seems superior in that we may select for elimination the generator with shortest equivalent string at each stage. >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, coset_enumeration_r, \ reidemeister_relators, define_schreier_generators, elimination_technique_2 >>> F, x, y = free_group("x, y") >>> f = FpGroup(F, [x**3, y**5, (x*y)**2]); H = [x*y, x**-1*y**-1*x*y*x] >>> C = coset_enumeration_r(f, H) >>> C.compress(); C.standardize() >>> define_schreier_generators(C) >>> reidemeister_relators(C) >>> elimination_technique_2(C) ([y_1, y_2], [y_2**-3, y_2*y_1*y_2*y_1*y_2*y_1, y_1**2]) """ rels = C._reidemeister_relators rels.sort(reverse=True) gens = C._schreier_generators for i in range(len(gens) - 1, -1, -1): rel = rels[i] for j in range(len(gens) - 1, -1, -1): gen = gens[j] if rel.generator_count(gen) == 1: k = rel.exponent_sum(gen) gen_index = rel.index(gen**k) bk = rel.subword(gen_index + 1, len(rel)) fw = rel.subword(0, gen_index) rep_by = (bk*fw)**(-1*k) del rels[i]; del gens[j] for l in range(len(rels)): rels[l] = rels[l].eliminate_word(gen, rep_by) break C._reidemeister_relators = rels C._schreier_generators = gens return C._schreier_generators, C._reidemeister_relators def reidemeister_presentation(fp_grp, H, C=None, homomorphism=False): """ Parameters ========== fp_group: A finitely presented group, an instance of FpGroup H: A subgroup whose presentation is to be found, given as a list of words in generators of `fp_grp` homomorphism: When set to True, return a homomorphism from the subgroup to the parent group Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup, reidemeister_presentation >>> F, x, y = free_group("x, y") Example 5.6 Pg. 177 from [1] >>> f = FpGroup(F, [x**3, y**5, (x*y)**2]) >>> H = [x*y, x**-1*y**-1*x*y*x] >>> reidemeister_presentation(f, H) ((y_1, y_2), (y_1**2, y_2**3, y_2*y_1*y_2*y_1*y_2*y_1)) Example 5.8 Pg. 183 from [1] >>> f = FpGroup(F, [x**3, y**3, (x*y)**3]) >>> H = [x*y, x*y**-1] >>> reidemeister_presentation(f, H) ((x_0, y_0), (x_0**3, y_0**3, x_0*y_0*x_0*y_0*x_0*y_0)) Exercises Q2. Pg 187 from [1] >>> f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3]) >>> H = [x] >>> reidemeister_presentation(f, H) ((x_0,), (x_0**4,)) Example 5.9 Pg. 183 from [1] >>> f = FpGroup(F, [x**3*y**-3, (x*y)**3, (x*y**-1)**2]) >>> H = [x] >>> reidemeister_presentation(f, H) ((x_0,), (x_0**6,)) """ if not C: C = coset_enumeration_r(fp_grp, H) C.compress(); C.standardize() define_schreier_generators(C, homomorphism=homomorphism) reidemeister_relators(C) gens, rels = C._schreier_generators, C._reidemeister_relators gens, rels = simplify_presentation(gens, rels, change_gens=True) C.schreier_generators = tuple(gens) C.reidemeister_relators = tuple(rels) if homomorphism: _gens = [] for gen in gens: _gens.append(C._schreier_gen_elem[str(gen)]) return C.schreier_generators, C.reidemeister_relators, _gens return C.schreier_generators, C.reidemeister_relators FpGroupElement = FreeGroupElement sympy-sympy-1.9/sympy/combinatorics/free_groups.py000066400000000000000000001161031412543434000226340ustar00rootroot00000000000000from typing import Dict, List from sympy.core import S from sympy.core.compatibility import is_sequence, as_int from sympy.core.expr import Expr from sympy.core.symbol import Symbol, symbols as _symbols from sympy.core.sympify import CantSympify from sympy.printing.defaults import DefaultPrinting from sympy.utilities import public from sympy.utilities.iterables import flatten from sympy.utilities.magic import pollute @public def free_group(symbols): """Construct a free group returning ``(FreeGroup, (f_0, f_1, ..., f_(n-1))``. Parameters ========== symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty) Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y, z = free_group("x, y, z") >>> F >>> x**2*y**-1 x**2*y**-1 >>> type(_) """ _free_group = FreeGroup(symbols) return (_free_group,) + tuple(_free_group.generators) @public def xfree_group(symbols): """Construct a free group returning ``(FreeGroup, (f_0, f_1, ..., f_(n-1)))``. Parameters ========== symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty) Examples ======== >>> from sympy.combinatorics.free_groups import xfree_group >>> F, (x, y, z) = xfree_group("x, y, z") >>> F >>> y**2*x**-2*z**-1 y**2*x**-2*z**-1 >>> type(_) """ _free_group = FreeGroup(symbols) return (_free_group, _free_group.generators) @public def vfree_group(symbols): """Construct a free group and inject ``f_0, f_1, ..., f_(n-1)`` as symbols into the global namespace. Parameters ========== symbols : str, Symbol/Expr or sequence of str, Symbol/Expr (may be empty) Examples ======== >>> from sympy.combinatorics.free_groups import vfree_group >>> vfree_group("x, y, z") >>> x**2*y**-2*z # noqa: F821 x**2*y**-2*z >>> type(_) """ _free_group = FreeGroup(symbols) pollute([sym.name for sym in _free_group.symbols], _free_group.generators) return _free_group def _parse_symbols(symbols): if not symbols: return tuple() if isinstance(symbols, str): return _symbols(symbols, seq=True) elif isinstance(symbols, Expr or FreeGroupElement): return (symbols,) elif is_sequence(symbols): if all(isinstance(s, str) for s in symbols): return _symbols(symbols) elif all(isinstance(s, Expr) for s in symbols): return symbols raise ValueError("The type of `symbols` must be one of the following: " "a str, Symbol/Expr or a sequence of " "one of these types") ############################################################################## # FREE GROUP # ############################################################################## _free_group_cache = {} # type: Dict[int, FreeGroup] class FreeGroup(DefaultPrinting): """ Free group with finite or infinite number of generators. Its input API is that of a str, Symbol/Expr or a sequence of one of these types (which may be empty) See Also ======== sympy.polys.rings.PolyRing References ========== .. [1] http://www.gap-system.org/Manuals/doc/ref/chap37.html .. [2] https://en.wikipedia.org/wiki/Free_group """ is_associative = True is_group = True is_FreeGroup = True is_PermutationGroup = False relators = [] # type: List[Expr] def __new__(cls, symbols): symbols = tuple(_parse_symbols(symbols)) rank = len(symbols) _hash = hash((cls.__name__, symbols, rank)) obj = _free_group_cache.get(_hash) if obj is None: obj = object.__new__(cls) obj._hash = _hash obj._rank = rank # dtype method is used to create new instances of FreeGroupElement obj.dtype = type("FreeGroupElement", (FreeGroupElement,), {"group": obj}) obj.symbols = symbols obj.generators = obj._generators() obj._gens_set = set(obj.generators) for symbol, generator in zip(obj.symbols, obj.generators): if isinstance(symbol, Symbol): name = symbol.name if hasattr(obj, name): setattr(obj, name, generator) _free_group_cache[_hash] = obj return obj def _generators(group): """Returns the generators of the FreeGroup. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y, z = free_group("x, y, z") >>> F.generators (x, y, z) """ gens = [] for sym in group.symbols: elm = ((sym, 1),) gens.append(group.dtype(elm)) return tuple(gens) def clone(self, symbols=None): return self.__class__(symbols or self.symbols) def __contains__(self, i): """Return True if ``i`` is contained in FreeGroup.""" if not isinstance(i, FreeGroupElement): return False group = i.group return self == group def __hash__(self): return self._hash def __len__(self): return self.rank def __str__(self): if self.rank > 30: str_form = "" % self.rank else: str_form = "" return str_form __repr__ = __str__ def __getitem__(self, index): symbols = self.symbols[index] return self.clone(symbols=symbols) def __eq__(self, other): """No ``FreeGroup`` is equal to any "other" ``FreeGroup``. """ return self is other def index(self, gen): """Return the index of the generator `gen` from ``(f_0, ..., f_(n-1))``. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> F.index(y) 1 >>> F.index(x) 0 """ if isinstance(gen, self.dtype): return self.generators.index(gen) else: raise ValueError("expected a generator of Free Group %s, got %s" % (self, gen)) def order(self): """Return the order of the free group. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> F.order() oo >>> free_group("")[0].order() 1 """ if self.rank == 0: return 1 else: return S.Infinity @property def elements(self): """ Return the elements of the free group. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> (z,) = free_group("") >>> z.elements {} """ if self.rank == 0: # A set containing Identity element of `FreeGroup` self is returned return {self.identity} else: raise ValueError("Group contains infinitely many elements" ", hence can't be represented") @property def rank(self): r""" In group theory, the `rank` of a group `G`, denoted `G.rank`, can refer to the smallest cardinality of a generating set for G, that is \operatorname{rank}(G)=\min\{ |X|: X\subseteq G, \left\langle X\right\rangle =G\}. """ return self._rank @property def is_abelian(self): """Returns if the group is Abelian. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y, z = free_group("x y z") >>> f.is_abelian False """ if self.rank == 0 or self.rank == 1: return True else: return False @property def identity(self): """Returns the identity element of free group.""" return self.dtype() def contains(self, g): """Tests if Free Group element ``g`` belong to self, ``G``. In mathematical terms any linear combination of generators of a Free Group is contained in it. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y, z = free_group("x y z") >>> f.contains(x**3*y**2) True """ if not isinstance(g, FreeGroupElement): return False elif self != g.group: return False else: return True def center(self): """Returns the center of the free group `self`.""" return {self.identity} ############################################################################ # FreeGroupElement # ############################################################################ class FreeGroupElement(CantSympify, DefaultPrinting, tuple): """Used to create elements of FreeGroup. It can not be used directly to create a free group element. It is called by the `dtype` method of the `FreeGroup` class. """ is_assoc_word = True def new(self, init): return self.__class__(init) _hash = None def __hash__(self): _hash = self._hash if _hash is None: self._hash = _hash = hash((self.group, frozenset(tuple(self)))) return _hash def copy(self): return self.new(self) @property def is_identity(self): if self.array_form == tuple(): return True else: return False @property def array_form(self): """ SymPy provides two different internal kinds of representation of associative words. The first one is called the `array_form` which is a tuple containing `tuples` as its elements, where the size of each tuple is two. At the first position the tuple contains the `symbol-generator`, while at the second position of tuple contains the exponent of that generator at the position. Since elements (i.e. words) don't commute, the indexing of tuple makes that property to stay. The structure in ``array_form`` of ``FreeGroupElement`` is of form: ``( ( symbol_of_gen , exponent ), ( , ), ... ( , ) )`` Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y, z = free_group("x y z") >>> (x*z).array_form ((x, 1), (z, 1)) >>> (x**2*z*y*x**2).array_form ((x, 2), (z, 1), (y, 1), (x, 2)) See Also ======== letter_repr """ return tuple(self) @property def letter_form(self): """ The letter representation of a ``FreeGroupElement`` is a tuple of generator symbols, with each entry corresponding to a group generator. Inverses of the generators are represented by negative generator symbols. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b, c, d = free_group("a b c d") >>> (a**3).letter_form (a, a, a) >>> (a**2*d**-2*a*b**-4).letter_form (a, a, -d, -d, a, -b, -b, -b, -b) >>> (a**-2*b**3*d).letter_form (-a, -a, b, b, b, d) See Also ======== array_form """ return tuple(flatten([(i,)*j if j > 0 else (-i,)*(-j) for i, j in self.array_form])) def __getitem__(self, i): group = self.group r = self.letter_form[i] if r.is_Symbol: return group.dtype(((r, 1),)) else: return group.dtype(((-r, -1),)) def index(self, gen): if len(gen) != 1: raise ValueError() return (self.letter_form).index(gen.letter_form[0]) @property def letter_form_elm(self): """ """ group = self.group r = self.letter_form return [group.dtype(((elm,1),)) if elm.is_Symbol \ else group.dtype(((-elm,-1),)) for elm in r] @property def ext_rep(self): """This is called the External Representation of ``FreeGroupElement`` """ return tuple(flatten(self.array_form)) def __contains__(self, gen): return gen.array_form[0][0] in tuple([r[0] for r in self.array_form]) def __str__(self): if self.is_identity: return "" str_form = "" array_form = self.array_form for i in range(len(array_form)): if i == len(array_form) - 1: if array_form[i][1] == 1: str_form += str(array_form[i][0]) else: str_form += str(array_form[i][0]) + \ "**" + str(array_form[i][1]) else: if array_form[i][1] == 1: str_form += str(array_form[i][0]) + "*" else: str_form += str(array_form[i][0]) + \ "**" + str(array_form[i][1]) + "*" return str_form __repr__ = __str__ def __pow__(self, n): n = as_int(n) group = self.group if n == 0: return group.identity if n < 0: n = -n return (self.inverse())**n result = self for i in range(n - 1): result = result*self # this method can be improved instead of just returning the # multiplication of elements return result def __mul__(self, other): """Returns the product of elements belonging to the same ``FreeGroup``. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y, z = free_group("x y z") >>> x*y**2*y**-4 x*y**-2 >>> z*y**-2 z*y**-2 >>> x**2*y*y**-1*x**-2 """ group = self.group if not isinstance(other, group.dtype): raise TypeError("only FreeGroup elements of same FreeGroup can " "be multiplied") if self.is_identity: return other if other.is_identity: return self r = list(self.array_form + other.array_form) zero_mul_simp(r, len(self.array_form) - 1) return group.dtype(tuple(r)) def __truediv__(self, other): group = self.group if not isinstance(other, group.dtype): raise TypeError("only FreeGroup elements of same FreeGroup can " "be multiplied") return self*(other.inverse()) def __rtruediv__(self, other): group = self.group if not isinstance(other, group.dtype): raise TypeError("only FreeGroup elements of same FreeGroup can " "be multiplied") return other*(self.inverse()) def __add__(self, other): return NotImplemented def inverse(self): """ Returns the inverse of a ``FreeGroupElement`` element Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y, z = free_group("x y z") >>> x.inverse() x**-1 >>> (x*y).inverse() y**-1*x**-1 """ group = self.group r = tuple([(i, -j) for i, j in self.array_form[::-1]]) return group.dtype(r) def order(self): """Find the order of a ``FreeGroupElement``. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y = free_group("x y") >>> (x**2*y*y**-1*x**-2).order() 1 """ if self.is_identity: return 1 else: return S.Infinity def commutator(self, other): """ Return the commutator of `self` and `x`: ``~x*~self*x*self`` """ group = self.group if not isinstance(other, group.dtype): raise ValueError("commutator of only FreeGroupElement of the same " "FreeGroup exists") else: return self.inverse()*other.inverse()*self*other def eliminate_words(self, words, _all=False, inverse=True): ''' Replace each subword from the dictionary `words` by words[subword]. If words is a list, replace the words by the identity. ''' again = True new = self if isinstance(words, dict): while again: again = False for sub in words: prev = new new = new.eliminate_word(sub, words[sub], _all=_all, inverse=inverse) if new != prev: again = True else: while again: again = False for sub in words: prev = new new = new.eliminate_word(sub, _all=_all, inverse=inverse) if new != prev: again = True return new def eliminate_word(self, gen, by=None, _all=False, inverse=True): """ For an associative word `self`, a subword `gen`, and an associative word `by` (identity by default), return the associative word obtained by replacing each occurrence of `gen` in `self` by `by`. If `_all = True`, the occurrences of `gen` that may appear after the first substitution will also be replaced and so on until no occurrences are found. This might not always terminate (e.g. `(x).eliminate_word(x, x**2, _all=True)`). Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y = free_group("x y") >>> w = x**5*y*x**2*y**-4*x >>> w.eliminate_word( x, x**2 ) x**10*y*x**4*y**-4*x**2 >>> w.eliminate_word( x, y**-1 ) y**-11 >>> w.eliminate_word(x**5) y*x**2*y**-4*x >>> w.eliminate_word(x*y, y) x**4*y*x**2*y**-4*x See Also ======== substituted_word """ if by is None: by = self.group.identity if self.is_independent(gen) or gen == by: return self if gen == self: return by if gen**-1 == by: _all = False word = self l = len(gen) try: i = word.subword_index(gen) k = 1 except ValueError: if not inverse: return word try: i = word.subword_index(gen**-1) k = -1 except ValueError: return word word = word.subword(0, i)*by**k*word.subword(i+l, len(word)).eliminate_word(gen, by) if _all: return word.eliminate_word(gen, by, _all=True, inverse=inverse) else: return word def __len__(self): """ For an associative word `self`, returns the number of letters in it. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b = free_group("a b") >>> w = a**5*b*a**2*b**-4*a >>> len(w) 13 >>> len(a**17) 17 >>> len(w**0) 0 """ return sum(abs(j) for (i, j) in self) def __eq__(self, other): """ Two associative words are equal if they are words over the same alphabet and if they are sequences of the same letters. This is equivalent to saying that the external representations of the words are equal. There is no "universal" empty word, every alphabet has its own empty word. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, swapnil0, swapnil1 = free_group("swapnil0 swapnil1") >>> f >>> g, swap0, swap1 = free_group("swap0 swap1") >>> g >>> swapnil0 == swapnil1 False >>> swapnil0*swapnil1 == swapnil1/swapnil1*swapnil0*swapnil1 True >>> swapnil0*swapnil1 == swapnil1*swapnil0 False >>> swapnil1**0 == swap0**0 False """ group = self.group if not isinstance(other, group.dtype): return False return tuple.__eq__(self, other) def __lt__(self, other): """ The ordering of associative words is defined by length and lexicography (this ordering is called short-lex ordering), that is, shorter words are smaller than longer words, and words of the same length are compared w.r.t. the lexicographical ordering induced by the ordering of generators. Generators are sorted according to the order in which they were created. If the generators are invertible then each generator `g` is larger than its inverse `g^{-1}`, and `g^{-1}` is larger than every generator that is smaller than `g`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b = free_group("a b") >>> b < a False >>> a < a.inverse() False """ group = self.group if not isinstance(other, group.dtype): raise TypeError("only FreeGroup elements of same FreeGroup can " "be compared") l = len(self) m = len(other) # implement lenlex order if l < m: return True elif l > m: return False for i in range(l): a = self[i].array_form[0] b = other[i].array_form[0] p = group.symbols.index(a[0]) q = group.symbols.index(b[0]) if p < q: return True elif p > q: return False elif a[1] < b[1]: return True elif a[1] > b[1]: return False return False def __le__(self, other): return (self == other or self < other) def __gt__(self, other): """ Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, x, y, z = free_group("x y z") >>> y**2 > x**2 True >>> y*z > z*y False >>> x > x.inverse() True """ group = self.group if not isinstance(other, group.dtype): raise TypeError("only FreeGroup elements of same FreeGroup can " "be compared") return not self <= other def __ge__(self, other): return not self < other def exponent_sum(self, gen): """ For an associative word `self` and a generator or inverse of generator `gen`, ``exponent_sum`` returns the number of times `gen` appears in `self` minus the number of times its inverse appears in `self`. If neither `gen` nor its inverse occur in `self` then 0 is returned. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> w = x**2*y**3 >>> w.exponent_sum(x) 2 >>> w.exponent_sum(x**-1) -2 >>> w = x**2*y**4*x**-3 >>> w.exponent_sum(x) -1 See Also ======== generator_count """ if len(gen) != 1: raise ValueError("gen must be a generator or inverse of a generator") s = gen.array_form[0] return s[1]*sum([i[1] for i in self.array_form if i[0] == s[0]]) def generator_count(self, gen): """ For an associative word `self` and a generator `gen`, ``generator_count`` returns the multiplicity of generator `gen` in `self`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> w = x**2*y**3 >>> w.generator_count(x) 2 >>> w = x**2*y**4*x**-3 >>> w.generator_count(x) 5 See Also ======== exponent_sum """ if len(gen) != 1 or gen.array_form[0][1] < 0: raise ValueError("gen must be a generator") s = gen.array_form[0] return s[1]*sum([abs(i[1]) for i in self.array_form if i[0] == s[0]]) def subword(self, from_i, to_j, strict=True): """ For an associative word `self` and two positive integers `from_i` and `to_j`, `subword` returns the subword of `self` that begins at position `from_i` and ends at `to_j - 1`, indexing is done with origin 0. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b = free_group("a b") >>> w = a**5*b*a**2*b**-4*a >>> w.subword(2, 6) a**3*b """ group = self.group if not strict: from_i = max(from_i, 0) to_j = min(len(self), to_j) if from_i < 0 or to_j > len(self): raise ValueError("`from_i`, `to_j` must be positive and no greater than " "the length of associative word") if to_j <= from_i: return group.identity else: letter_form = self.letter_form[from_i: to_j] array_form = letter_form_to_array_form(letter_form, group) return group.dtype(array_form) def subword_index(self, word, start = 0): ''' Find the index of `word` in `self`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b = free_group("a b") >>> w = a**2*b*a*b**3 >>> w.subword_index(a*b*a*b) 1 ''' l = len(word) self_lf = self.letter_form word_lf = word.letter_form index = None for i in range(start,len(self_lf)-l+1): if self_lf[i:i+l] == word_lf: index = i break if index is not None: return index else: raise ValueError("The given word is not a subword of self") def is_dependent(self, word): """ Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> (x**4*y**-3).is_dependent(x**4*y**-2) True >>> (x**2*y**-1).is_dependent(x*y) False >>> (x*y**2*x*y**2).is_dependent(x*y**2) True >>> (x**12).is_dependent(x**-4) True See Also ======== is_independent """ try: return self.subword_index(word) is not None except ValueError: pass try: return self.subword_index(word**-1) is not None except ValueError: return False def is_independent(self, word): """ See Also ======== is_dependent """ return not self.is_dependent(word) def contains_generators(self): """ Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y, z = free_group("x, y, z") >>> (x**2*y**-1).contains_generators() {x, y} >>> (x**3*z).contains_generators() {x, z} """ group = self.group gens = set() for syllable in self.array_form: gens.add(group.dtype(((syllable[0], 1),))) return set(gens) def cyclic_subword(self, from_i, to_j): group = self.group l = len(self) letter_form = self.letter_form period1 = int(from_i/l) if from_i >= l: from_i -= l*period1 to_j -= l*period1 diff = to_j - from_i word = letter_form[from_i: to_j] period2 = int(to_j/l) - 1 word += letter_form*period2 + letter_form[:diff-l+from_i-l*period2] word = letter_form_to_array_form(word, group) return group.dtype(word) def cyclic_conjugates(self): """Returns a words which are cyclic to the word `self`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> w = x*y*x*y*x >>> w.cyclic_conjugates() {x*y*x**2*y, x**2*y*x*y, y*x*y*x**2, y*x**2*y*x, x*y*x*y*x} >>> s = x*y*x**2*y*x >>> s.cyclic_conjugates() {x**2*y*x**2*y, y*x**2*y*x**2, x*y*x**2*y*x} References ========== http://planetmath.org/cyclicpermutation """ return {self.cyclic_subword(i, i+len(self)) for i in range(len(self))} def is_cyclic_conjugate(self, w): """ Checks whether words ``self``, ``w`` are cyclic conjugates. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> w1 = x**2*y**5 >>> w2 = x*y**5*x >>> w1.is_cyclic_conjugate(w2) True >>> w3 = x**-1*y**5*x**-1 >>> w3.is_cyclic_conjugate(w2) False """ l1 = len(self) l2 = len(w) if l1 != l2: return False w1 = self.identity_cyclic_reduction() w2 = w.identity_cyclic_reduction() letter1 = w1.letter_form letter2 = w2.letter_form str1 = ' '.join(map(str, letter1)) str2 = ' '.join(map(str, letter2)) if len(str1) != len(str2): return False return str1 in str2 + ' ' + str2 def number_syllables(self): """Returns the number of syllables of the associative word `self`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, swapnil0, swapnil1 = free_group("swapnil0 swapnil1") >>> (swapnil1**3*swapnil0*swapnil1**-1).number_syllables() 3 """ return len(self.array_form) def exponent_syllable(self, i): """ Returns the exponent of the `i`-th syllable of the associative word `self`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b = free_group("a b") >>> w = a**5*b*a**2*b**-4*a >>> w.exponent_syllable( 2 ) 2 """ return self.array_form[i][1] def generator_syllable(self, i): """ Returns the symbol of the generator that is involved in the i-th syllable of the associative word `self`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b = free_group("a b") >>> w = a**5*b*a**2*b**-4*a >>> w.generator_syllable( 3 ) b """ return self.array_form[i][0] def sub_syllables(self, from_i, to_j): """ `sub_syllables` returns the subword of the associative word `self` that consists of syllables from positions `from_to` to `to_j`, where `from_to` and `to_j` must be positive integers and indexing is done with origin 0. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> f, a, b = free_group("a, b") >>> w = a**5*b*a**2*b**-4*a >>> w.sub_syllables(1, 2) b >>> w.sub_syllables(3, 3) """ if not isinstance(from_i, int) or not isinstance(to_j, int): raise ValueError("both arguments should be integers") group = self.group if to_j <= from_i: return group.identity else: r = tuple(self.array_form[from_i: to_j]) return group.dtype(r) def substituted_word(self, from_i, to_j, by): """ Returns the associative word obtained by replacing the subword of `self` that begins at position `from_i` and ends at position `to_j - 1` by the associative word `by`. `from_i` and `to_j` must be positive integers, indexing is done with origin 0. In other words, `w.substituted_word(w, from_i, to_j, by)` is the product of the three words: `w.subword(0, from_i)`, `by`, and `w.subword(to_j len(w))`. See Also ======== eliminate_word """ lw = len(self) if from_i >= to_j or from_i > lw or to_j > lw: raise ValueError("values should be within bounds") # otherwise there are four possibilities # first if from=1 and to=lw then if from_i == 0 and to_j == lw: return by elif from_i == 0: # second if from_i=1 (and to_j < lw) then return by*self.subword(to_j, lw) elif to_j == lw: # third if to_j=1 (and from_i > 1) then return self.subword(0, from_i)*by else: # finally return self.subword(0, from_i)*by*self.subword(to_j, lw) def is_cyclically_reduced(self): r"""Returns whether the word is cyclically reduced or not. A word is cyclically reduced if by forming the cycle of the word, the word is not reduced, i.e a word w = `a_1 ... a_n` is called cyclically reduced if `a_1 \ne a_n^{-1}`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> (x**2*y**-1*x**-1).is_cyclically_reduced() False >>> (y*x**2*y**2).is_cyclically_reduced() True """ if not self: return True return self[0] != self[-1]**-1 def identity_cyclic_reduction(self): """Return a unique cyclically reduced version of the word. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> (x**2*y**2*x**-1).identity_cyclic_reduction() x*y**2 >>> (x**-3*y**-1*x**5).identity_cyclic_reduction() x**2*y**-1 References ========== http://planetmath.org/cyclicallyreduced """ word = self.copy() group = self.group while not word.is_cyclically_reduced(): exp1 = word.exponent_syllable(0) exp2 = word.exponent_syllable(-1) r = exp1 + exp2 if r == 0: rep = word.array_form[1: word.number_syllables() - 1] else: rep = ((word.generator_syllable(0), exp1 + exp2),) + \ word.array_form[1: word.number_syllables() - 1] word = group.dtype(rep) return word def cyclic_reduction(self, removed=False): """Return a cyclically reduced version of the word. Unlike `identity_cyclic_reduction`, this will not cyclically permute the reduced word - just remove the "unreduced" bits on either side of it. Compare the examples with those of `identity_cyclic_reduction`. When `removed` is `True`, return a tuple `(word, r)` where self `r` is such that before the reduction the word was either `r*word*r**-1`. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> (x**2*y**2*x**-1).cyclic_reduction() x*y**2 >>> (x**-3*y**-1*x**5).cyclic_reduction() y**-1*x**2 >>> (x**-3*y**-1*x**5).cyclic_reduction(removed=True) (y**-1*x**2, x**-3) """ word = self.copy() g = self.group.identity while not word.is_cyclically_reduced(): exp1 = abs(word.exponent_syllable(0)) exp2 = abs(word.exponent_syllable(-1)) exp = min(exp1, exp2) start = word[0]**abs(exp) end = word[-1]**abs(exp) word = start**-1*word*end**-1 g = g*start if removed: return word, g return word def power_of(self, other): ''' Check if `self == other**n` for some integer n. Examples ======== >>> from sympy.combinatorics.free_groups import free_group >>> F, x, y = free_group("x, y") >>> ((x*y)**2).power_of(x*y) True >>> (x**-3*y**-2*x**3).power_of(x**-3*y*x**3) True ''' if self.is_identity: return True l = len(other) if l == 1: # self has to be a power of one generator gens = self.contains_generators() s = other in gens or other**-1 in gens return len(gens) == 1 and s # if self is not cyclically reduced and it is a power of other, # other isn't cyclically reduced and the parts removed during # their reduction must be equal reduced, r1 = self.cyclic_reduction(removed=True) if not r1.is_identity: other, r2 = other.cyclic_reduction(removed=True) if r1 == r2: return reduced.power_of(other) return False if len(self) < l or len(self) % l: return False prefix = self.subword(0, l) if prefix == other or prefix**-1 == other: rest = self.subword(l, len(self)) return rest.power_of(other) return False def letter_form_to_array_form(array_form, group): """ This method converts a list given with possible repetitions of elements in it. It returns a new list such that repetitions of consecutive elements is removed and replace with a tuple element of size two such that the first index contains `value` and the second index contains the number of consecutive repetitions of `value`. """ a = list(array_form[:]) new_array = [] n = 1 symbols = group.symbols for i in range(len(a)): if i == len(a) - 1: if a[i] == a[i - 1]: if (-a[i]) in symbols: new_array.append((-a[i], -n)) else: new_array.append((a[i], n)) else: if (-a[i]) in symbols: new_array.append((-a[i], -1)) else: new_array.append((a[i], 1)) return new_array elif a[i] == a[i + 1]: n += 1 else: if (-a[i]) in symbols: new_array.append((-a[i], -n)) else: new_array.append((a[i], n)) n = 1 def zero_mul_simp(l, index): """Used to combine two reduced words.""" while index >=0 and index < len(l) - 1 and l[index][0] == l[index + 1][0]: exp = l[index][1] + l[index + 1][1] base = l[index][0] l[index] = (base, exp) del l[index + 1] if l[index][1] == 0: del l[index] index -= 1 sympy-sympy-1.9/sympy/combinatorics/generators.py000066400000000000000000000165041412543434000224710ustar00rootroot00000000000000from sympy.combinatorics.permutations import Permutation from sympy.core.symbol import symbols from sympy.matrices import Matrix from sympy.utilities.iterables import variations, rotate_left def symmetric(n): """ Generates the symmetric group of order n, Sn. Examples ======== >>> from sympy.combinatorics.generators import symmetric >>> list(symmetric(3)) [(2), (1 2), (2)(0 1), (0 1 2), (0 2 1), (0 2)] """ for perm in variations(list(range(n)), n): yield Permutation(perm) def cyclic(n): """ Generates the cyclic group of order n, Cn. Examples ======== >>> from sympy.combinatorics.generators import cyclic >>> list(cyclic(5)) [(4), (0 1 2 3 4), (0 2 4 1 3), (0 3 1 4 2), (0 4 3 2 1)] See Also ======== dihedral """ gen = list(range(n)) for i in range(n): yield Permutation(gen) gen = rotate_left(gen, 1) def alternating(n): """ Generates the alternating group of order n, An. Examples ======== >>> from sympy.combinatorics.generators import alternating >>> list(alternating(3)) [(2), (0 1 2), (0 2 1)] """ for perm in variations(list(range(n)), n): p = Permutation(perm) if p.is_even: yield p def dihedral(n): """ Generates the dihedral group of order 2n, Dn. The result is given as a subgroup of Sn, except for the special cases n=1 (the group S2) and n=2 (the Klein 4-group) where that's not possible and embeddings in S2 and S4 respectively are given. Examples ======== >>> from sympy.combinatorics.generators import dihedral >>> list(dihedral(3)) [(2), (0 2), (0 1 2), (1 2), (0 2 1), (2)(0 1)] See Also ======== cyclic """ if n == 1: yield Permutation([0, 1]) yield Permutation([1, 0]) elif n == 2: yield Permutation([0, 1, 2, 3]) yield Permutation([1, 0, 3, 2]) yield Permutation([2, 3, 0, 1]) yield Permutation([3, 2, 1, 0]) else: gen = list(range(n)) for i in range(n): yield Permutation(gen) yield Permutation(gen[::-1]) gen = rotate_left(gen, 1) def rubik_cube_generators(): """Return the permutations of the 3x3 Rubik's cube, see http://www.gap-system.org/Doc/Examples/rubik.html """ a = [ [(1, 3, 8, 6), (2, 5, 7, 4), (9, 33, 25, 17), (10, 34, 26, 18), (11, 35, 27, 19)], [(9, 11, 16, 14), (10, 13, 15, 12), (1, 17, 41, 40), (4, 20, 44, 37), (6, 22, 46, 35)], [(17, 19, 24, 22), (18, 21, 23, 20), (6, 25, 43, 16), (7, 28, 42, 13), (8, 30, 41, 11)], [(25, 27, 32, 30), (26, 29, 31, 28), (3, 38, 43, 19), (5, 36, 45, 21), (8, 33, 48, 24)], [(33, 35, 40, 38), (34, 37, 39, 36), (3, 9, 46, 32), (2, 12, 47, 29), (1, 14, 48, 27)], [(41, 43, 48, 46), (42, 45, 47, 44), (14, 22, 30, 38), (15, 23, 31, 39), (16, 24, 32, 40)] ] return [Permutation([[i - 1 for i in xi] for xi in x], size=48) for x in a] def rubik(n): """Return permutations for an nxn Rubik's cube. Permutations returned are for rotation of each of the slice from the face up to the last face for each of the 3 sides (in this order): front, right and bottom. Hence, the first n - 1 permutations are for the slices from the front. """ if n < 2: raise ValueError('dimension of cube must be > 1') # 1-based reference to rows and columns in Matrix def getr(f, i): return faces[f].col(n - i) def getl(f, i): return faces[f].col(i - 1) def getu(f, i): return faces[f].row(i - 1) def getd(f, i): return faces[f].row(n - i) def setr(f, i, s): faces[f][:, n - i] = Matrix(n, 1, s) def setl(f, i, s): faces[f][:, i - 1] = Matrix(n, 1, s) def setu(f, i, s): faces[f][i - 1, :] = Matrix(1, n, s) def setd(f, i, s): faces[f][n - i, :] = Matrix(1, n, s) # motion of a single face def cw(F, r=1): for _ in range(r): face = faces[F] rv = [] for c in range(n): for r in range(n - 1, -1, -1): rv.append(face[r, c]) faces[F] = Matrix(n, n, rv) def ccw(F): cw(F, 3) # motion of plane i from the F side; # fcw(0) moves the F face, fcw(1) moves the plane # just behind the front face, etc... def fcw(i, r=1): for _ in range(r): if i == 0: cw(F) i += 1 temp = getr(L, i) setr(L, i, list(getu(D, i))) setu(D, i, list(reversed(getl(R, i)))) setl(R, i, list(getd(U, i))) setd(U, i, list(reversed(temp))) i -= 1 def fccw(i): fcw(i, 3) # motion of the entire cube from the F side def FCW(r=1): for _ in range(r): cw(F) ccw(B) cw(U) t = faces[U] cw(L) faces[U] = faces[L] cw(D) faces[L] = faces[D] cw(R) faces[D] = faces[R] faces[R] = t def FCCW(): FCW(3) # motion of the entire cube from the U side def UCW(r=1): for _ in range(r): cw(U) ccw(D) t = faces[F] faces[F] = faces[R] faces[R] = faces[B] faces[B] = faces[L] faces[L] = t def UCCW(): UCW(3) # defining the permutations for the cube U, F, R, B, L, D = names = symbols('U, F, R, B, L, D') # the faces are represented by nxn matrices faces = {} count = 0 for fi in range(6): f = [] for a in range(n**2): f.append(count) count += 1 faces[names[fi]] = Matrix(n, n, f) # this will either return the value of the current permutation # (show != 1) or else append the permutation to the group, g def perm(show=0): # add perm to the list of perms p = [] for f in names: p.extend(faces[f]) if show: return p g.append(Permutation(p)) g = [] # container for the group's permutations I = list(range(6*n**2)) # the identity permutation used for checking # define permutations corresponding to cw rotations of the planes # up TO the last plane from that direction; by not including the # last plane, the orientation of the cube is maintained. # F slices for i in range(n - 1): fcw(i) perm() fccw(i) # restore assert perm(1) == I # R slices # bring R to front UCW() for i in range(n - 1): fcw(i) # put it back in place UCCW() # record perm() # restore # bring face to front UCW() fccw(i) # restore UCCW() assert perm(1) == I # D slices # bring up bottom FCW() UCCW() FCCW() for i in range(n - 1): # turn strip fcw(i) # put bottom back on the bottom FCW() UCW() FCCW() # record perm() # restore # bring up bottom FCW() UCCW() FCCW() # turn strip fccw(i) # put bottom back on the bottom FCW() UCW() FCCW() assert perm(1) == I return g sympy-sympy-1.9/sympy/combinatorics/graycode.py000066400000000000000000000257451412543434000221240ustar00rootroot00000000000000from sympy.core import Basic import random class GrayCode(Basic): """ A Gray code is essentially a Hamiltonian walk on a n-dimensional cube with edge length of one. The vertices of the cube are represented by vectors whose values are binary. The Hamilton walk visits each vertex exactly once. The Gray code for a 3d cube is ['000','100','110','010','011','111','101', '001']. A Gray code solves the problem of sequentially generating all possible subsets of n objects in such a way that each subset is obtained from the previous one by either deleting or adding a single object. In the above example, 1 indicates that the object is present, and 0 indicates that its absent. Gray codes have applications in statistics as well when we want to compute various statistics related to subsets in an efficient manner. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(3) >>> list(a.generate_gray()) ['000', '001', '011', '010', '110', '111', '101', '100'] >>> a = GrayCode(4) >>> list(a.generate_gray()) ['0000', '0001', '0011', '0010', '0110', '0111', '0101', '0100', \ '1100', '1101', '1111', '1110', '1010', '1011', '1001', '1000'] References ========== .. [1] Nijenhuis,A. and Wilf,H.S.(1978). Combinatorial Algorithms. Academic Press. .. [2] Knuth, D. (2011). The Art of Computer Programming, Vol 4 Addison Wesley """ _skip = False _current = 0 _rank = None def __new__(cls, n, *args, **kw_args): """ Default constructor. It takes a single argument ``n`` which gives the dimension of the Gray code. The starting Gray code string (``start``) or the starting ``rank`` may also be given; the default is to start at rank = 0 ('0...0'). Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(3) >>> a GrayCode(3) >>> a.n 3 >>> a = GrayCode(3, start='100') >>> a.current '100' >>> a = GrayCode(4, rank=4) >>> a.current '0110' >>> a.rank 4 """ if n < 1 or int(n) != n: raise ValueError( 'Gray code dimension must be a positive integer, not %i' % n) n = int(n) args = (n,) + args obj = Basic.__new__(cls, *args) if 'start' in kw_args: obj._current = kw_args["start"] if len(obj._current) > n: raise ValueError('Gray code start has length %i but ' 'should not be greater than %i' % (len(obj._current), n)) elif 'rank' in kw_args: if int(kw_args["rank"]) != kw_args["rank"]: raise ValueError('Gray code rank must be a positive integer, ' 'not %i' % kw_args["rank"]) obj._rank = int(kw_args["rank"]) % obj.selections obj._current = obj.unrank(n, obj._rank) return obj def next(self, delta=1): """ Returns the Gray code a distance ``delta`` (default = 1) from the current value in canonical order. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(3, start='110') >>> a.next().current '111' >>> a.next(-1).current '010' """ return GrayCode(self.n, rank=(self.rank + delta) % self.selections) @property def selections(self): """ Returns the number of bit vectors in the Gray code. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(3) >>> a.selections 8 """ return 2**self.n @property def n(self): """ Returns the dimension of the Gray code. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(5) >>> a.n 5 """ return self.args[0] def generate_gray(self, **hints): """ Generates the sequence of bit vectors of a Gray Code. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(3) >>> list(a.generate_gray()) ['000', '001', '011', '010', '110', '111', '101', '100'] >>> list(a.generate_gray(start='011')) ['011', '010', '110', '111', '101', '100'] >>> list(a.generate_gray(rank=4)) ['110', '111', '101', '100'] See Also ======== skip References ========== .. [1] Knuth, D. (2011). The Art of Computer Programming, Vol 4, Addison Wesley """ bits = self.n start = None if "start" in hints: start = hints["start"] elif "rank" in hints: start = GrayCode.unrank(self.n, hints["rank"]) if start is not None: self._current = start current = self.current graycode_bin = gray_to_bin(current) if len(graycode_bin) > self.n: raise ValueError('Gray code start has length %i but should ' 'not be greater than %i' % (len(graycode_bin), bits)) self._current = int(current, 2) graycode_int = int(''.join(graycode_bin), 2) for i in range(graycode_int, 1 << bits): if self._skip: self._skip = False else: yield self.current bbtc = (i ^ (i + 1)) gbtc = (bbtc ^ (bbtc >> 1)) self._current = (self._current ^ gbtc) self._current = 0 def skip(self): """ Skips the bit generation. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(3) >>> for i in a.generate_gray(): ... if i == '010': ... a.skip() ... print(i) ... 000 001 011 010 111 101 100 See Also ======== generate_gray """ self._skip = True @property def rank(self): """ Ranks the Gray code. A ranking algorithm determines the position (or rank) of a combinatorial object among all the objects w.r.t. a given order. For example, the 4 bit binary reflected Gray code (BRGC) '0101' has a rank of 6 as it appears in the 6th position in the canonical ordering of the family of 4 bit Gray codes. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> a = GrayCode(3) >>> list(a.generate_gray()) ['000', '001', '011', '010', '110', '111', '101', '100'] >>> GrayCode(3, start='100').rank 7 >>> GrayCode(3, rank=7).current '100' See Also ======== unrank References ========== .. [1] http://statweb.stanford.edu/~susan/courses/s208/node12.html """ if self._rank is None: self._rank = int(gray_to_bin(self.current), 2) return self._rank @property def current(self): """ Returns the currently referenced Gray code as a bit string. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> GrayCode(3, start='100').current '100' """ rv = self._current or '0' if type(rv) is not str: rv = bin(rv)[2:] return rv.rjust(self.n, '0') @classmethod def unrank(self, n, rank): """ Unranks an n-bit sized Gray code of rank k. This method exists so that a derivative GrayCode class can define its own code of a given rank. The string here is generated in reverse order to allow for tail-call optimization. Examples ======== >>> from sympy.combinatorics.graycode import GrayCode >>> GrayCode(5, rank=3).current '00010' >>> GrayCode.unrank(5, 3) '00010' See Also ======== rank """ def _unrank(k, n): if n == 1: return str(k % 2) m = 2**(n - 1) if k < m: return '0' + _unrank(k, n - 1) return '1' + _unrank(m - (k % m) - 1, n - 1) return _unrank(rank, n) def random_bitstring(n): """ Generates a random bitlist of length n. Examples ======== >>> from sympy.combinatorics.graycode import random_bitstring >>> random_bitstring(3) # doctest: +SKIP 100 """ return ''.join([random.choice('01') for i in range(n)]) def gray_to_bin(bin_list): """ Convert from Gray coding to binary coding. We assume big endian encoding. Examples ======== >>> from sympy.combinatorics.graycode import gray_to_bin >>> gray_to_bin('100') '111' See Also ======== bin_to_gray """ b = [bin_list[0]] for i in range(1, len(bin_list)): b += str(int(b[i - 1] != bin_list[i])) return ''.join(b) def bin_to_gray(bin_list): """ Convert from binary coding to gray coding. We assume big endian encoding. Examples ======== >>> from sympy.combinatorics.graycode import bin_to_gray >>> bin_to_gray('111') '100' See Also ======== gray_to_bin """ b = [bin_list[0]] for i in range(1, len(bin_list)): b += str(int(bin_list[i]) ^ int(bin_list[i - 1])) return ''.join(b) def get_subset_from_bitstring(super_set, bitstring): """ Gets the subset defined by the bitstring. Examples ======== >>> from sympy.combinatorics.graycode import get_subset_from_bitstring >>> get_subset_from_bitstring(['a', 'b', 'c', 'd'], '0011') ['c', 'd'] >>> get_subset_from_bitstring(['c', 'a', 'c', 'c'], '1100') ['c', 'a'] See Also ======== graycode_subsets """ if len(super_set) != len(bitstring): raise ValueError("The sizes of the lists are not equal") return [super_set[i] for i, j in enumerate(bitstring) if bitstring[i] == '1'] def graycode_subsets(gray_code_set): """ Generates the subsets as enumerated by a Gray code. Examples ======== >>> from sympy.combinatorics.graycode import graycode_subsets >>> list(graycode_subsets(['a', 'b', 'c'])) [[], ['c'], ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'], \ ['a', 'c'], ['a']] >>> list(graycode_subsets(['a', 'b', 'c', 'c'])) [[], ['c'], ['c', 'c'], ['c'], ['b', 'c'], ['b', 'c', 'c'], \ ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'b', 'c', 'c'], \ ['a', 'b', 'c'], ['a', 'c'], ['a', 'c', 'c'], ['a', 'c'], ['a']] See Also ======== get_subset_from_bitstring """ for bitstring in list(GrayCode(len(gray_code_set)).generate_gray()): yield get_subset_from_bitstring(gray_code_set, bitstring) sympy-sympy-1.9/sympy/combinatorics/group_constructs.py000066400000000000000000000037451412543434000237460ustar00rootroot00000000000000from sympy.combinatorics.perm_groups import PermutationGroup from sympy.combinatorics.permutations import Permutation from sympy.utilities.iterables import uniq _af_new = Permutation._af_new def DirectProduct(*groups): """ Returns the direct product of several groups as a permutation group. Explanation =========== This is implemented much like the __mul__ procedure for taking the direct product of two permutation groups, but the idea of shifting the generators is realized in the case of an arbitrary number of groups. A call to DirectProduct(G1, G2, ..., Gn) is generally expected to be faster than a call to G1*G2*...*Gn (and thus the need for this algorithm). Examples ======== >>> from sympy.combinatorics.group_constructs import DirectProduct >>> from sympy.combinatorics.named_groups import CyclicGroup >>> C = CyclicGroup(4) >>> G = DirectProduct(C, C, C) >>> G.order() 64 See Also ======== sympy.combinatorics.perm_groups.PermutationGroup.__mul__ """ degrees = [] gens_count = [] total_degree = 0 total_gens = 0 for group in groups: current_deg = group.degree current_num_gens = len(group.generators) degrees.append(current_deg) total_degree += current_deg gens_count.append(current_num_gens) total_gens += current_num_gens array_gens = [] for i in range(total_gens): array_gens.append(list(range(total_degree))) current_gen = 0 current_deg = 0 for i in range(len(gens_count)): for j in range(current_gen, current_gen + gens_count[i]): gen = ((groups[i].generators)[j - current_gen]).array_form array_gens[j][current_deg:current_deg + degrees[i]] = \ [x + current_deg for x in gen] current_gen += gens_count[i] current_deg += degrees[i] perm_gens = list(uniq([_af_new(list(a)) for a in array_gens])) return PermutationGroup(perm_gens, dups=False) sympy-sympy-1.9/sympy/combinatorics/homomorphisms.py000066400000000000000000000456151412543434000232310ustar00rootroot00000000000000import itertools from sympy.combinatorics.fp_groups import FpGroup, FpSubgroup, simplify_presentation from sympy.combinatorics.free_groups import FreeGroup from sympy.combinatorics.perm_groups import PermutationGroup from sympy.core.numbers import igcd from sympy.ntheory.factor_ import totient from sympy import S class GroupHomomorphism: ''' A class representing group homomorphisms. Instantiate using `homomorphism()`. References ========== .. [1] Holt, D., Eick, B. and O'Brien, E. (2005). Handbook of computational group theory. ''' def __init__(self, domain, codomain, images): self.domain = domain self.codomain = codomain self.images = images self._inverses = None self._kernel = None self._image = None def _invs(self): ''' Return a dictionary with `{gen: inverse}` where `gen` is a rewriting generator of `codomain` (e.g. strong generator for permutation groups) and `inverse` is an element of its preimage ''' image = self.image() inverses = {} for k in list(self.images.keys()): v = self.images[k] if not (v in inverses or v.is_identity): inverses[v] = k if isinstance(self.codomain, PermutationGroup): gens = image.strong_gens else: gens = image.generators for g in gens: if g in inverses or g.is_identity: continue w = self.domain.identity if isinstance(self.codomain, PermutationGroup): parts = image._strong_gens_slp[g][::-1] else: parts = g for s in parts: if s in inverses: w = w*inverses[s] else: w = w*inverses[s**-1]**-1 inverses[g] = w return inverses def invert(self, g): ''' Return an element of the preimage of ``g`` or of each element of ``g`` if ``g`` is a list. Explanation =========== If the codomain is an FpGroup, the inverse for equal elements might not always be the same unless the FpGroup's rewriting system is confluent. However, making a system confluent can be time-consuming. If it's important, try `self.codomain.make_confluent()` first. ''' from sympy.combinatorics import Permutation from sympy.combinatorics.free_groups import FreeGroupElement if isinstance(g, (Permutation, FreeGroupElement)): if isinstance(self.codomain, FpGroup): g = self.codomain.reduce(g) if self._inverses is None: self._inverses = self._invs() image = self.image() w = self.domain.identity if isinstance(self.codomain, PermutationGroup): gens = image.generator_product(g)[::-1] else: gens = g # the following can't be "for s in gens:" # because that would be equivalent to # "for s in gens.array_form:" when g is # a FreeGroupElement. On the other hand, # when you call gens by index, the generator # (or inverse) at position i is returned. for i in range(len(gens)): s = gens[i] if s.is_identity: continue if s in self._inverses: w = w*self._inverses[s] else: w = w*self._inverses[s**-1]**-1 return w elif isinstance(g, list): return [self.invert(e) for e in g] def kernel(self): ''' Compute the kernel of `self`. ''' if self._kernel is None: self._kernel = self._compute_kernel() return self._kernel def _compute_kernel(self): from sympy import S G = self.domain G_order = G.order() if G_order is S.Infinity: raise NotImplementedError( "Kernel computation is not implemented for infinite groups") gens = [] if isinstance(G, PermutationGroup): K = PermutationGroup(G.identity) else: K = FpSubgroup(G, gens, normal=True) i = self.image().order() while K.order()*i != G_order: r = G.random() k = r*self.invert(self(r))**-1 if not k in K: gens.append(k) if isinstance(G, PermutationGroup): K = PermutationGroup(gens) else: K = FpSubgroup(G, gens, normal=True) return K def image(self): ''' Compute the image of `self`. ''' if self._image is None: values = list(set(self.images.values())) if isinstance(self.codomain, PermutationGroup): self._image = self.codomain.subgroup(values) else: self._image = FpSubgroup(self.codomain, values) return self._image def _apply(self, elem): ''' Apply `self` to `elem`. ''' if not elem in self.domain: if isinstance(elem, (list, tuple)): return [self._apply(e) for e in elem] raise ValueError("The supplied element doesn't belong to the domain") if elem.is_identity: return self.codomain.identity else: images = self.images value = self.codomain.identity if isinstance(self.domain, PermutationGroup): gens = self.domain.generator_product(elem, original=True) for g in gens: if g in self.images: value = images[g]*value else: value = images[g**-1]**-1*value else: i = 0 for _, p in elem.array_form: if p < 0: g = elem[i]**-1 else: g = elem[i] value = value*images[g]**p i += abs(p) return value def __call__(self, elem): return self._apply(elem) def is_injective(self): ''' Check if the homomorphism is injective ''' return self.kernel().order() == 1 def is_surjective(self): ''' Check if the homomorphism is surjective ''' from sympy import S im = self.image().order() oth = self.codomain.order() if im is S.Infinity and oth is S.Infinity: return None else: return im == oth def is_isomorphism(self): ''' Check if `self` is an isomorphism. ''' return self.is_injective() and self.is_surjective() def is_trivial(self): ''' Check is `self` is a trivial homomorphism, i.e. all elements are mapped to the identity. ''' return self.image().order() == 1 def compose(self, other): ''' Return the composition of `self` and `other`, i.e. the homomorphism phi such that for all g in the domain of `other`, phi(g) = self(other(g)) ''' if not other.image().is_subgroup(self.domain): raise ValueError("The image of `other` must be a subgroup of " "the domain of `self`") images = {g: self(other(g)) for g in other.images} return GroupHomomorphism(other.domain, self.codomain, images) def restrict_to(self, H): ''' Return the restriction of the homomorphism to the subgroup `H` of the domain. ''' if not isinstance(H, PermutationGroup) or not H.is_subgroup(self.domain): raise ValueError("Given H is not a subgroup of the domain") domain = H images = {g: self(g) for g in H.generators} return GroupHomomorphism(domain, self.codomain, images) def invert_subgroup(self, H): ''' Return the subgroup of the domain that is the inverse image of the subgroup ``H`` of the homomorphism image ''' if not H.is_subgroup(self.image()): raise ValueError("Given H is not a subgroup of the image") gens = [] P = PermutationGroup(self.image().identity) for h in H.generators: h_i = self.invert(h) if h_i not in P: gens.append(h_i) P = PermutationGroup(gens) for k in self.kernel().generators: if k*h_i not in P: gens.append(k*h_i) P = PermutationGroup(gens) return P def homomorphism(domain, codomain, gens, images=[], check=True): ''' Create (if possible) a group homomorphism from the group ``domain`` to the group ``codomain`` defined by the images of the domain's generators ``gens``. ``gens`` and ``images`` can be either lists or tuples of equal sizes. If ``gens`` is a proper subset of the group's generators, the unspecified generators will be mapped to the identity. If the images are not specified, a trivial homomorphism will be created. If the given images of the generators do not define a homomorphism, an exception is raised. If ``check`` is ``False``, don't check whether the given images actually define a homomorphism. ''' if not isinstance(domain, (PermutationGroup, FpGroup, FreeGroup)): raise TypeError("The domain must be a group") if not isinstance(codomain, (PermutationGroup, FpGroup, FreeGroup)): raise TypeError("The codomain must be a group") generators = domain.generators if any([g not in generators for g in gens]): raise ValueError("The supplied generators must be a subset of the domain's generators") if any([g not in codomain for g in images]): raise ValueError("The images must be elements of the codomain") if images and len(images) != len(gens): raise ValueError("The number of images must be equal to the number of generators") gens = list(gens) images = list(images) images.extend([codomain.identity]*(len(generators)-len(images))) gens.extend([g for g in generators if g not in gens]) images = dict(zip(gens,images)) if check and not _check_homomorphism(domain, codomain, images): raise ValueError("The given images do not define a homomorphism") return GroupHomomorphism(domain, codomain, images) def _check_homomorphism(domain, codomain, images): if hasattr(domain, 'relators'): rels = domain.relators else: gens = domain.presentation().generators rels = domain.presentation().relators identity = codomain.identity def _image(r): if r.is_identity: return identity else: w = identity r_arr = r.array_form i = 0 j = 0 # i is the index for r and j is for # r_arr. r_arr[j] is the tuple (sym, p) # where sym is the generator symbol # and p is the power to which it is # raised while r[i] is a generator # (not just its symbol) or the inverse of # a generator - hence the need for # both indices while i < len(r): power = r_arr[j][1] if isinstance(domain, PermutationGroup) and r[i] in gens: s = domain.generators[gens.index(r[i])] else: s = r[i] if s in images: w = w*images[s]**power elif s**-1 in images: w = w*images[s**-1]**power i += abs(power) j += 1 return w for r in rels: if isinstance(codomain, FpGroup): s = codomain.equals(_image(r), identity) if s is None: # only try to make the rewriting system # confluent when it can't determine the # truth of equality otherwise success = codomain.make_confluent() s = codomain.equals(_image(r), identity) if s is None and not success: raise RuntimeError("Can't determine if the images " "define a homomorphism. Try increasing " "the maximum number of rewriting rules " "(group._rewriting_system.set_max(new_value); " "the current value is stored in group._rewriting" "_system.maxeqns)") else: s = _image(r).is_identity if not s: return False return True def orbit_homomorphism(group, omega): ''' Return the homomorphism induced by the action of the permutation group ``group`` on the set ``omega`` that is closed under the action. ''' from sympy.combinatorics import Permutation from sympy.combinatorics.named_groups import SymmetricGroup codomain = SymmetricGroup(len(omega)) identity = codomain.identity omega = list(omega) images = {g: identity*Permutation([omega.index(o^g) for o in omega]) for g in group.generators} group._schreier_sims(base=omega) H = GroupHomomorphism(group, codomain, images) if len(group.basic_stabilizers) > len(omega): H._kernel = group.basic_stabilizers[len(omega)] else: H._kernel = PermutationGroup([group.identity]) return H def block_homomorphism(group, blocks): ''' Return the homomorphism induced by the action of the permutation group ``group`` on the block system ``blocks``. The latter should be of the same form as returned by the ``minimal_block`` method for permutation groups, namely a list of length ``group.degree`` where the i-th entry is a representative of the block i belongs to. ''' from sympy.combinatorics import Permutation from sympy.combinatorics.named_groups import SymmetricGroup n = len(blocks) # number the blocks; m is the total number, # b is such that b[i] is the number of the block i belongs to, # p is the list of length m such that p[i] is the representative # of the i-th block m = 0 p = [] b = [None]*n for i in range(n): if blocks[i] == i: p.append(i) b[i] = m m += 1 for i in range(n): b[i] = b[blocks[i]] codomain = SymmetricGroup(m) # the list corresponding to the identity permutation in codomain identity = range(m) images = {g: Permutation([b[p[i]^g] for i in identity]) for g in group.generators} H = GroupHomomorphism(group, codomain, images) return H def group_isomorphism(G, H, isomorphism=True): ''' Compute an isomorphism between 2 given groups. Parameters ========== G : A finite ``FpGroup`` or a ``PermutationGroup``. First group. H : A finite ``FpGroup`` or a ``PermutationGroup`` Second group. isomorphism : bool This is used to avoid the computation of homomorphism when the user only wants to check if there exists an isomorphism between the groups. Returns ======= If isomorphism = False -- Returns a boolean. If isomorphism = True -- Returns a boolean and an isomorphism between `G` and `H`. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup >>> from sympy.combinatorics.homomorphisms import group_isomorphism >>> from sympy.combinatorics.named_groups import DihedralGroup, AlternatingGroup >>> D = DihedralGroup(8) >>> p = Permutation(0, 1, 2, 3, 4, 5, 6, 7) >>> P = PermutationGroup(p) >>> group_isomorphism(D, P) (False, None) >>> F, a, b = free_group("a, b") >>> G = FpGroup(F, [a**3, b**3, (a*b)**2]) >>> H = AlternatingGroup(4) >>> (check, T) = group_isomorphism(G, H) >>> check True >>> T(b*a*b**-1*a**-1*b**-1) (0 2 3) Notes ===== Uses the approach suggested by Robert Tarjan to compute the isomorphism between two groups. First, the generators of ``G`` are mapped to the elements of ``H`` and we check if the mapping induces an isomorphism. ''' if not isinstance(G, (PermutationGroup, FpGroup)): raise TypeError("The group must be a PermutationGroup or an FpGroup") if not isinstance(H, (PermutationGroup, FpGroup)): raise TypeError("The group must be a PermutationGroup or an FpGroup") if isinstance(G, FpGroup) and isinstance(H, FpGroup): G = simplify_presentation(G) H = simplify_presentation(H) # Two infinite FpGroups with the same generators are isomorphic # when the relators are same but are ordered differently. if G.generators == H.generators and (G.relators).sort() == (H.relators).sort(): if not isomorphism: return True return (True, homomorphism(G, H, G.generators, H.generators)) # `_H` is the permutation group isomorphic to `H`. _H = H g_order = G.order() h_order = H.order() if g_order is S.Infinity: raise NotImplementedError("Isomorphism methods are not implemented for infinite groups.") if isinstance(H, FpGroup): if h_order is S.Infinity: raise NotImplementedError("Isomorphism methods are not implemented for infinite groups.") _H, h_isomorphism = H._to_perm_group() if (g_order != h_order) or (G.is_abelian != H.is_abelian): if not isomorphism: return False return (False, None) if not isomorphism: # Two groups of the same cyclic numbered order # are isomorphic to each other. n = g_order if (igcd(n, totient(n))) == 1: return True # Match the generators of `G` with subsets of `_H` gens = list(G.generators) for subset in itertools.permutations(_H, len(gens)): images = list(subset) images.extend([_H.identity]*(len(G.generators)-len(images))) _images = dict(zip(gens,images)) if _check_homomorphism(G, _H, _images): if isinstance(H, FpGroup): images = h_isomorphism.invert(images) T = homomorphism(G, H, G.generators, images, check=False) if T.is_isomorphism(): # It is a valid isomorphism if not isomorphism: return True return (True, T) if not isomorphism: return False return (False, None) def is_isomorphic(G, H): ''' Check if the groups are isomorphic to each other Parameters ========== G : A finite ``FpGroup`` or a ``PermutationGroup`` First group. H : A finite ``FpGroup`` or a ``PermutationGroup`` Second group. Returns ======= boolean ''' return group_isomorphism(G, H, isomorphism=False) sympy-sympy-1.9/sympy/combinatorics/named_groups.py000066400000000000000000000173341412543434000230050ustar00rootroot00000000000000from sympy.combinatorics.group_constructs import DirectProduct from sympy.combinatorics.perm_groups import PermutationGroup from sympy.combinatorics.permutations import Permutation _af_new = Permutation._af_new def AbelianGroup(*cyclic_orders): """ Returns the direct product of cyclic groups with the given orders. Explanation =========== According to the structure theorem for finite abelian groups ([1]), every finite abelian group can be written as the direct product of finitely many cyclic groups. Examples ======== >>> from sympy.combinatorics.named_groups import AbelianGroup >>> AbelianGroup(3, 4) PermutationGroup([ (6)(0 1 2), (3 4 5 6)]) >>> _.is_group True See Also ======== DirectProduct References ========== .. [1] http://groupprops.subwiki.org/wiki/Structure_theorem_for_finitely_generated_abelian_groups """ groups = [] degree = 0 order = 1 for size in cyclic_orders: degree += size order *= size groups.append(CyclicGroup(size)) G = DirectProduct(*groups) G._is_abelian = True G._degree = degree G._order = order return G def AlternatingGroup(n): """ Generates the alternating group on ``n`` elements as a permutation group. Explanation =========== For ``n > 2``, the generators taken are ``(0 1 2), (0 1 2 ... n-1)`` for ``n`` odd and ``(0 1 2), (1 2 ... n-1)`` for ``n`` even (See [1], p.31, ex.6.9.). After the group is generated, some of its basic properties are set. The cases ``n = 1, 2`` are handled separately. Examples ======== >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> G = AlternatingGroup(4) >>> G.is_group True >>> a = list(G.generate_dimino()) >>> len(a) 12 >>> all(perm.is_even for perm in a) True See Also ======== SymmetricGroup, CyclicGroup, DihedralGroup References ========== .. [1] Armstrong, M. "Groups and Symmetry" """ # small cases are special if n in (1, 2): return PermutationGroup([Permutation([0])]) a = list(range(n)) a[0], a[1], a[2] = a[1], a[2], a[0] gen1 = a if n % 2: a = list(range(1, n)) a.append(0) gen2 = a else: a = list(range(2, n)) a.append(1) a.insert(0, 0) gen2 = a gens = [gen1, gen2] if gen1 == gen2: gens = gens[:1] G = PermutationGroup([_af_new(a) for a in gens], dups=False) if n < 4: G._is_abelian = True G._is_nilpotent = True else: G._is_abelian = False G._is_nilpotent = False if n < 5: G._is_solvable = True else: G._is_solvable = False G._degree = n G._is_transitive = True G._is_alt = True return G def CyclicGroup(n): """ Generates the cyclic group of order ``n`` as a permutation group. Explanation =========== The generator taken is the ``n``-cycle ``(0 1 2 ... n-1)`` (in cycle notation). After the group is generated, some of its basic properties are set. Examples ======== >>> from sympy.combinatorics.named_groups import CyclicGroup >>> G = CyclicGroup(6) >>> G.is_group True >>> G.order() 6 >>> list(G.generate_schreier_sims(af=True)) [[0, 1, 2, 3, 4, 5], [1, 2, 3, 4, 5, 0], [2, 3, 4, 5, 0, 1], [3, 4, 5, 0, 1, 2], [4, 5, 0, 1, 2, 3], [5, 0, 1, 2, 3, 4]] See Also ======== SymmetricGroup, DihedralGroup, AlternatingGroup """ a = list(range(1, n)) a.append(0) gen = _af_new(a) G = PermutationGroup([gen]) G._is_abelian = True G._is_nilpotent = True G._is_solvable = True G._degree = n G._is_transitive = True G._order = n return G def DihedralGroup(n): r""" Generates the dihedral group `D_n` as a permutation group. Explanation =========== The dihedral group `D_n` is the group of symmetries of the regular ``n``-gon. The generators taken are the ``n``-cycle ``a = (0 1 2 ... n-1)`` (a rotation of the ``n``-gon) and ``b = (0 n-1)(1 n-2)...`` (a reflection of the ``n``-gon) in cycle rotation. It is easy to see that these satisfy ``a**n = b**2 = 1`` and ``bab = ~a`` so they indeed generate `D_n` (See [1]). After the group is generated, some of its basic properties are set. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> G = DihedralGroup(5) >>> G.is_group True >>> a = list(G.generate_dimino()) >>> [perm.cyclic_form for perm in a] [[], [[0, 1, 2, 3, 4]], [[0, 2, 4, 1, 3]], [[0, 3, 1, 4, 2]], [[0, 4, 3, 2, 1]], [[0, 4], [1, 3]], [[1, 4], [2, 3]], [[0, 1], [2, 4]], [[0, 2], [3, 4]], [[0, 3], [1, 2]]] See Also ======== SymmetricGroup, CyclicGroup, AlternatingGroup References ========== .. [1] https://en.wikipedia.org/wiki/Dihedral_group """ # small cases are special if n == 1: return PermutationGroup([Permutation([1, 0])]) if n == 2: return PermutationGroup([Permutation([1, 0, 3, 2]), Permutation([2, 3, 0, 1]), Permutation([3, 2, 1, 0])]) a = list(range(1, n)) a.append(0) gen1 = _af_new(a) a = list(range(n)) a.reverse() gen2 = _af_new(a) G = PermutationGroup([gen1, gen2]) # if n is a power of 2, group is nilpotent if n & (n-1) == 0: G._is_nilpotent = True else: G._is_nilpotent = False G._is_abelian = False G._is_solvable = True G._degree = n G._is_transitive = True G._order = 2*n return G def SymmetricGroup(n): """ Generates the symmetric group on ``n`` elements as a permutation group. Explanation =========== The generators taken are the ``n``-cycle ``(0 1 2 ... n-1)`` and the transposition ``(0 1)`` (in cycle notation). (See [1]). After the group is generated, some of its basic properties are set. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(4) >>> G.is_group True >>> G.order() 24 >>> list(G.generate_schreier_sims(af=True)) [[0, 1, 2, 3], [1, 2, 3, 0], [2, 3, 0, 1], [3, 1, 2, 0], [0, 2, 3, 1], [1, 3, 0, 2], [2, 0, 1, 3], [3, 2, 0, 1], [0, 3, 1, 2], [1, 0, 2, 3], [2, 1, 3, 0], [3, 0, 1, 2], [0, 1, 3, 2], [1, 2, 0, 3], [2, 3, 1, 0], [3, 1, 0, 2], [0, 2, 1, 3], [1, 3, 2, 0], [2, 0, 3, 1], [3, 2, 1, 0], [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3], [3, 0, 2, 1]] See Also ======== CyclicGroup, DihedralGroup, AlternatingGroup References ========== .. [1] https://en.wikipedia.org/wiki/Symmetric_group#Generators_and_relations """ if n == 1: G = PermutationGroup([Permutation([0])]) elif n == 2: G = PermutationGroup([Permutation([1, 0])]) else: a = list(range(1, n)) a.append(0) gen1 = _af_new(a) a = list(range(n)) a[0], a[1] = a[1], a[0] gen2 = _af_new(a) G = PermutationGroup([gen1, gen2]) if n < 3: G._is_abelian = True G._is_nilpotent = True else: G._is_abelian = False G._is_nilpotent = False if n < 5: G._is_solvable = True else: G._is_solvable = False G._degree = n G._is_transitive = True G._is_sym = True return G def RubikGroup(n): """Return a group of Rubik's cube generators >>> from sympy.combinatorics.named_groups import RubikGroup >>> RubikGroup(2).is_group True """ from sympy.combinatorics.generators import rubik if n <= 1: raise ValueError("Invalid cube. n has to be greater than 1") return PermutationGroup(rubik(n)) sympy-sympy-1.9/sympy/combinatorics/partitions.py000066400000000000000000000506531412543434000225170ustar00rootroot00000000000000from sympy.core import Basic, Dict, sympify from sympy.core.compatibility import as_int, default_sort_key from sympy.core.sympify import _sympify from sympy.functions.combinatorial.numbers import bell from sympy.matrices import zeros from sympy.sets.sets import FiniteSet, Union from sympy.utilities.iterables import flatten, group from collections import defaultdict class Partition(FiniteSet): """ This class represents an abstract partition. A partition is a set of disjoint sets whose union equals a given set. See Also ======== sympy.utilities.iterables.partitions, sympy.utilities.iterables.multiset_partitions """ _rank = None _partition = None def __new__(cls, *partition): """ Generates a new partition object. This method also verifies if the arguments passed are valid and raises a ValueError if they are not. Examples ======== Creating Partition from Python lists: >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3]) >>> a Partition({3}, {1, 2}) >>> a.partition [[1, 2], [3]] >>> len(a) 2 >>> a.members (1, 2, 3) Creating Partition from Python sets: >>> Partition({1, 2, 3}, {4, 5}) Partition({4, 5}, {1, 2, 3}) Creating Partition from SymPy finite sets: >>> from sympy.sets.sets import FiniteSet >>> a = FiniteSet(1, 2, 3) >>> b = FiniteSet(4, 5) >>> Partition(a, b) Partition({4, 5}, {1, 2, 3}) """ args = [] dups = False for arg in partition: if isinstance(arg, list): as_set = set(arg) if len(as_set) < len(arg): dups = True break # error below arg = as_set args.append(_sympify(arg)) if not all(isinstance(part, FiniteSet) for part in args): raise ValueError( "Each argument to Partition should be " \ "a list, set, or a FiniteSet") # sort so we have a canonical reference for RGS U = Union(*args) if dups or len(U) < sum(len(arg) for arg in args): raise ValueError("Partition contained duplicate elements.") obj = FiniteSet.__new__(cls, *args) obj.members = tuple(U) obj.size = len(U) return obj def sort_key(self, order=None): """Return a canonical key that can be used for sorting. Ordering is based on the size and sorted elements of the partition and ties are broken with the rank. Examples ======== >>> from sympy.utilities.iterables import default_sort_key >>> from sympy.combinatorics.partitions import Partition >>> from sympy.abc import x >>> a = Partition([1, 2]) >>> b = Partition([3, 4]) >>> c = Partition([1, x]) >>> d = Partition(list(range(4))) >>> l = [d, b, a + 1, a, c] >>> l.sort(key=default_sort_key); l [Partition({1, 2}), Partition({1}, {2}), Partition({1, x}), Partition({3, 4}), Partition({0, 1, 2, 3})] """ if order is None: members = self.members else: members = tuple(sorted(self.members, key=lambda w: default_sort_key(w, order))) return tuple(map(default_sort_key, (self.size, members, self.rank))) @property def partition(self): """Return partition as a sorted list of lists. Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> Partition([1], [2, 3]).partition [[1], [2, 3]] """ if self._partition is None: self._partition = sorted([sorted(p, key=default_sort_key) for p in self.args]) return self._partition def __add__(self, other): """ Return permutation whose rank is ``other`` greater than current rank, (mod the maximum rank for the set). Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3]) >>> a.rank 1 >>> (a + 1).rank 2 >>> (a + 100).rank 1 """ other = as_int(other) offset = self.rank + other result = RGS_unrank((offset) % RGS_enum(self.size), self.size) return Partition.from_rgs(result, self.members) def __sub__(self, other): """ Return permutation whose rank is ``other`` less than current rank, (mod the maximum rank for the set). Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3]) >>> a.rank 1 >>> (a - 1).rank 0 >>> (a - 100).rank 1 """ return self.__add__(-other) def __le__(self, other): """ Checks if a partition is less than or equal to the other based on rank. Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3, 4, 5]) >>> b = Partition([1], [2, 3], [4], [5]) >>> a.rank, b.rank (9, 34) >>> a <= a True >>> a <= b True """ return self.sort_key() <= sympify(other).sort_key() def __lt__(self, other): """ Checks if a partition is less than the other. Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3, 4, 5]) >>> b = Partition([1], [2, 3], [4], [5]) >>> a.rank, b.rank (9, 34) >>> a < b True """ return self.sort_key() < sympify(other).sort_key() @property def rank(self): """ Gets the rank of a partition. Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3], [4, 5]) >>> a.rank 13 """ if self._rank is not None: return self._rank self._rank = RGS_rank(self.RGS) return self._rank @property def RGS(self): """ Returns the "restricted growth string" of the partition. Explanation =========== The RGS is returned as a list of indices, L, where L[i] indicates the block in which element i appears. For example, in a partition of 3 elements (a, b, c) into 2 blocks ([c], [a, b]) the RGS is [1, 1, 0]: "a" is in block 1, "b" is in block 1 and "c" is in block 0. Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> a = Partition([1, 2], [3], [4, 5]) >>> a.members (1, 2, 3, 4, 5) >>> a.RGS (0, 0, 1, 2, 2) >>> a + 1 Partition({3}, {4}, {5}, {1, 2}) >>> _.RGS (0, 0, 1, 2, 3) """ rgs = {} partition = self.partition for i, part in enumerate(partition): for j in part: rgs[j] = i return tuple([rgs[i] for i in sorted( [i for p in partition for i in p], key=default_sort_key)]) @classmethod def from_rgs(self, rgs, elements): """ Creates a set partition from a restricted growth string. Explanation =========== The indices given in rgs are assumed to be the index of the element as given in elements *as provided* (the elements are not sorted by this routine). Block numbering starts from 0. If any block was not referenced in ``rgs`` an error will be raised. Examples ======== >>> from sympy.combinatorics.partitions import Partition >>> Partition.from_rgs([0, 1, 2, 0, 1], list('abcde')) Partition({c}, {a, d}, {b, e}) >>> Partition.from_rgs([0, 1, 2, 0, 1], list('cbead')) Partition({e}, {a, c}, {b, d}) >>> a = Partition([1, 4], [2], [3, 5]) >>> Partition.from_rgs(a.RGS, a.members) Partition({2}, {1, 4}, {3, 5}) """ if len(rgs) != len(elements): raise ValueError('mismatch in rgs and element lengths') max_elem = max(rgs) + 1 partition = [[] for i in range(max_elem)] j = 0 for i in rgs: partition[i].append(elements[j]) j += 1 if not all(p for p in partition): raise ValueError('some blocks of the partition were empty.') return Partition(*partition) class IntegerPartition(Basic): """ This class represents an integer partition. Explanation =========== In number theory and combinatorics, a partition of a positive integer, ``n``, also called an integer partition, is a way of writing ``n`` as a list of positive integers that sum to n. Two partitions that differ only in the order of summands are considered to be the same partition; if order matters then the partitions are referred to as compositions. For example, 4 has five partitions: [4], [3, 1], [2, 2], [2, 1, 1], and [1, 1, 1, 1]; the compositions [1, 2, 1] and [1, 1, 2] are the same as partition [2, 1, 1]. See Also ======== sympy.utilities.iterables.partitions, sympy.utilities.iterables.multiset_partitions References ========== https://en.wikipedia.org/wiki/Partition_%28number_theory%29 """ _dict = None _keys = None def __new__(cls, partition, integer=None): """ Generates a new IntegerPartition object from a list or dictionary. Explantion ========== The partition can be given as a list of positive integers or a dictionary of (integer, multiplicity) items. If the partition is preceded by an integer an error will be raised if the partition does not sum to that given integer. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> a = IntegerPartition([5, 4, 3, 1, 1]) >>> a IntegerPartition(14, (5, 4, 3, 1, 1)) >>> print(a) [5, 4, 3, 1, 1] >>> IntegerPartition({1:3, 2:1}) IntegerPartition(5, (2, 1, 1, 1)) If the value that the partition should sum to is given first, a check will be made to see n error will be raised if there is a discrepancy: >>> IntegerPartition(10, [5, 4, 3, 1]) Traceback (most recent call last): ... ValueError: The partition is not valid """ if integer is not None: integer, partition = partition, integer if isinstance(partition, (dict, Dict)): _ = [] for k, v in sorted(list(partition.items()), reverse=True): if not v: continue k, v = as_int(k), as_int(v) _.extend([k]*v) partition = tuple(_) else: partition = tuple(sorted(map(as_int, partition), reverse=True)) sum_ok = False if integer is None: integer = sum(partition) sum_ok = True else: integer = as_int(integer) if not sum_ok and sum(partition) != integer: raise ValueError("Partition did not add to %s" % integer) if any(i < 1 for i in partition): raise ValueError("All integer summands must be greater than one") obj = Basic.__new__(cls, integer, partition) obj.partition = list(partition) obj.integer = integer return obj def prev_lex(self): """Return the previous partition of the integer, n, in lexical order, wrapping around to [1, ..., 1] if the partition is [n]. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> p = IntegerPartition([4]) >>> print(p.prev_lex()) [3, 1] >>> p.partition > p.prev_lex().partition True """ d = defaultdict(int) d.update(self.as_dict()) keys = self._keys if keys == [1]: return IntegerPartition({self.integer: 1}) if keys[-1] != 1: d[keys[-1]] -= 1 if keys[-1] == 2: d[1] = 2 else: d[keys[-1] - 1] = d[1] = 1 else: d[keys[-2]] -= 1 left = d[1] + keys[-2] new = keys[-2] d[1] = 0 while left: new -= 1 if left - new >= 0: d[new] += left//new left -= d[new]*new return IntegerPartition(self.integer, d) def next_lex(self): """Return the next partition of the integer, n, in lexical order, wrapping around to [n] if the partition is [1, ..., 1]. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> p = IntegerPartition([3, 1]) >>> print(p.next_lex()) [4] >>> p.partition < p.next_lex().partition True """ d = defaultdict(int) d.update(self.as_dict()) key = self._keys a = key[-1] if a == self.integer: d.clear() d[1] = self.integer elif a == 1: if d[a] > 1: d[a + 1] += 1 d[a] -= 2 else: b = key[-2] d[b + 1] += 1 d[1] = (d[b] - 1)*b d[b] = 0 else: if d[a] > 1: if len(key) == 1: d.clear() d[a + 1] = 1 d[1] = self.integer - a - 1 else: a1 = a + 1 d[a1] += 1 d[1] = d[a]*a - a1 d[a] = 0 else: b = key[-2] b1 = b + 1 d[b1] += 1 need = d[b]*b + d[a]*a - b1 d[a] = d[b] = 0 d[1] = need return IntegerPartition(self.integer, d) def as_dict(self): """Return the partition as a dictionary whose keys are the partition integers and the values are the multiplicity of that integer. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> IntegerPartition([1]*3 + [2] + [3]*4).as_dict() {1: 3, 2: 1, 3: 4} """ if self._dict is None: groups = group(self.partition, multiple=False) self._keys = [g[0] for g in groups] self._dict = dict(groups) return self._dict @property def conjugate(self): """ Computes the conjugate partition of itself. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> a = IntegerPartition([6, 3, 3, 2, 1]) >>> a.conjugate [5, 4, 3, 1, 1, 1] """ j = 1 temp_arr = list(self.partition) + [0] k = temp_arr[0] b = [0]*k while k > 0: while k > temp_arr[j]: b[k - 1] = j k -= 1 j += 1 return b def __lt__(self, other): """Return True if self is less than other when the partition is listed from smallest to biggest. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> a = IntegerPartition([3, 1]) >>> a < a False >>> b = a.next_lex() >>> a < b True >>> a == b False """ return list(reversed(self.partition)) < list(reversed(other.partition)) def __le__(self, other): """Return True if self is less than other when the partition is listed from smallest to biggest. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> a = IntegerPartition([4]) >>> a <= a True """ return list(reversed(self.partition)) <= list(reversed(other.partition)) def as_ferrers(self, char='#'): """ Prints the ferrer diagram of a partition. Examples ======== >>> from sympy.combinatorics.partitions import IntegerPartition >>> print(IntegerPartition([1, 1, 5]).as_ferrers()) ##### # # """ return "\n".join([char*i for i in self.partition]) def __str__(self): return str(list(self.partition)) def random_integer_partition(n, seed=None): """ Generates a random integer partition summing to ``n`` as a list of reverse-sorted integers. Examples ======== >>> from sympy.combinatorics.partitions import random_integer_partition For the following, a seed is given so a known value can be shown; in practice, the seed would not be given. >>> random_integer_partition(100, seed=[1, 1, 12, 1, 2, 1, 85, 1]) [85, 12, 2, 1] >>> random_integer_partition(10, seed=[1, 2, 3, 1, 5, 1]) [5, 3, 1, 1] >>> random_integer_partition(1) [1] """ from sympy.testing.randtest import _randint n = as_int(n) if n < 1: raise ValueError('n must be a positive integer') randint = _randint(seed) partition = [] while (n > 0): k = randint(1, n) mult = randint(1, n//k) partition.append((k, mult)) n -= k*mult partition.sort(reverse=True) partition = flatten([[k]*m for k, m in partition]) return partition def RGS_generalized(m): """ Computes the m + 1 generalized unrestricted growth strings and returns them as rows in matrix. Examples ======== >>> from sympy.combinatorics.partitions import RGS_generalized >>> RGS_generalized(6) Matrix([ [ 1, 1, 1, 1, 1, 1, 1], [ 1, 2, 3, 4, 5, 6, 0], [ 2, 5, 10, 17, 26, 0, 0], [ 5, 15, 37, 77, 0, 0, 0], [ 15, 52, 151, 0, 0, 0, 0], [ 52, 203, 0, 0, 0, 0, 0], [203, 0, 0, 0, 0, 0, 0]]) """ d = zeros(m + 1) for i in range(0, m + 1): d[0, i] = 1 for i in range(1, m + 1): for j in range(m): if j <= m - i: d[i, j] = j * d[i - 1, j] + d[i - 1, j + 1] else: d[i, j] = 0 return d def RGS_enum(m): """ RGS_enum computes the total number of restricted growth strings possible for a superset of size m. Examples ======== >>> from sympy.combinatorics.partitions import RGS_enum >>> from sympy.combinatorics.partitions import Partition >>> RGS_enum(4) 15 >>> RGS_enum(5) 52 >>> RGS_enum(6) 203 We can check that the enumeration is correct by actually generating the partitions. Here, the 15 partitions of 4 items are generated: >>> a = Partition(list(range(4))) >>> s = set() >>> for i in range(20): ... s.add(a) ... a += 1 ... >>> assert len(s) == 15 """ if (m < 1): return 0 elif (m == 1): return 1 else: return bell(m) def RGS_unrank(rank, m): """ Gives the unranked restricted growth string for a given superset size. Examples ======== >>> from sympy.combinatorics.partitions import RGS_unrank >>> RGS_unrank(14, 4) [0, 1, 2, 3] >>> RGS_unrank(0, 4) [0, 0, 0, 0] """ if m < 1: raise ValueError("The superset size must be >= 1") if rank < 0 or RGS_enum(m) <= rank: raise ValueError("Invalid arguments") L = [1] * (m + 1) j = 1 D = RGS_generalized(m) for i in range(2, m + 1): v = D[m - i, j] cr = j*v if cr <= rank: L[i] = j + 1 rank -= cr j += 1 else: L[i] = int(rank / v + 1) rank %= v return [x - 1 for x in L[1:]] def RGS_rank(rgs): """ Computes the rank of a restricted growth string. Examples ======== >>> from sympy.combinatorics.partitions import RGS_rank, RGS_unrank >>> RGS_rank([0, 1, 2, 1, 3]) 42 >>> RGS_rank(RGS_unrank(4, 7)) 4 """ rgs_size = len(rgs) rank = 0 D = RGS_generalized(rgs_size) for i in range(1, rgs_size): n = len(rgs[(i + 1):]) m = max(rgs[0:i]) rank += D[n, m + 1] * rgs[i] return rank sympy-sympy-1.9/sympy/combinatorics/pc_groups.py000066400000000000000000000514671412543434000223300ustar00rootroot00000000000000from sympy import isprime from sympy.combinatorics.perm_groups import PermutationGroup from sympy.printing.defaults import DefaultPrinting from sympy.combinatorics.free_groups import free_group class PolycyclicGroup(DefaultPrinting): is_group = True is_solvable = True def __init__(self, pc_sequence, pc_series, relative_order, collector=None): """ Parameters ========== pc_sequence : list A sequence of elements whose classes generate the cyclic factor groups of pc_series. pc_series : list A subnormal sequence of subgroups where each factor group is cyclic. relative_order : list The orders of factor groups of pc_series. collector : Collector By default, it is None. Collector class provides the polycyclic presentation with various other functionalities. """ self.pcgs = pc_sequence self.pc_series = pc_series self.relative_order = relative_order self.collector = Collector(self.pcgs, pc_series, relative_order) if not collector else collector def is_prime_order(self): return all(isprime(order) for order in self.relative_order) def length(self): return len(self.pcgs) class Collector(DefaultPrinting): """ References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" Section 8.1.3 """ def __init__(self, pcgs, pc_series, relative_order, free_group_=None, pc_presentation=None): """ Most of the parameters for the Collector class are the same as for PolycyclicGroup. Others are described below. Parameters ========== free_group_ : tuple free_group_ provides the mapping of polycyclic generating sequence with the free group elements. pc_presentation : dict Provides the presentation of polycyclic groups with the help of power and conjugate relators. See Also ======== PolycyclicGroup """ self.pcgs = pcgs self.pc_series = pc_series self.relative_order = relative_order self.free_group = free_group('x:{}'.format(len(pcgs)))[0] if not free_group_ else free_group_ self.index = {s: i for i, s in enumerate(self.free_group.symbols)} self.pc_presentation = self.pc_relators() def minimal_uncollected_subword(self, word): r""" Returns the minimal uncollected subwords. Explanation =========== A word ``v`` defined on generators in ``X`` is a minimal uncollected subword of the word ``w`` if ``v`` is a subword of ``w`` and it has one of the following form * `v = {x_{i+1}}^{a_j}x_i` * `v = {x_{i+1}}^{a_j}{x_i}^{-1}` * `v = {x_i}^{a_j}` for `a_j` not in `\{1, \ldots, s-1\}`. Where, ``s`` is the power exponent of the corresponding generator. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.free_groups import free_group >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> F, x1, x2 = free_group("x1, x2") >>> word = x2**2*x1**7 >>> collector.minimal_uncollected_subword(word) ((x2, 2),) """ # To handle the case word = if not word: return None array = word.array_form re = self.relative_order index = self.index for i in range(len(array)): s1, e1 = array[i] if re[index[s1]] and (e1 < 0 or e1 > re[index[s1]]-1): return ((s1, e1), ) for i in range(len(array)-1): s1, e1 = array[i] s2, e2 = array[i+1] if index[s1] > index[s2]: e = 1 if e2 > 0 else -1 return ((s1, e1), (s2, e)) return None def relations(self): """ Separates the given relators of pc presentation in power and conjugate relations. Returns ======= (power_rel, conj_rel) Separates pc presentation into power and conjugate relations. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(3) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> power_rel, conj_rel = collector.relations() >>> power_rel {x0**2: (), x1**3: ()} >>> conj_rel {x0**-1*x1*x0: x1**2} See Also ======== pc_relators """ power_relators = {} conjugate_relators = {} for key, value in self.pc_presentation.items(): if len(key.array_form) == 1: power_relators[key] = value else: conjugate_relators[key] = value return power_relators, conjugate_relators def subword_index(self, word, w): """ Returns the start and ending index of a given subword in a word. Parameters ========== word : FreeGroupElement word defined on free group elements for a polycyclic group. w : FreeGroupElement subword of a given word, whose starting and ending index to be computed. Returns ======= (i, j) A tuple containing starting and ending index of ``w`` in the given word. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.free_groups import free_group >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> F, x1, x2 = free_group("x1, x2") >>> word = x2**2*x1**7 >>> w = x2**2*x1 >>> collector.subword_index(word, w) (0, 3) >>> w = x1**7 >>> collector.subword_index(word, w) (2, 9) """ low = -1 high = -1 for i in range(len(word)-len(w)+1): if word.subword(i, i+len(w)) == w: low = i high = i+len(w) break if low == high == -1: return -1, -1 return low, high def map_relation(self, w): """ Return a conjugate relation. Explanation =========== Given a word formed by two free group elements, the corresponding conjugate relation with those free group elements is formed and mapped with the collected word in the polycyclic presentation. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.free_groups import free_group >>> G = SymmetricGroup(3) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> F, x0, x1 = free_group("x0, x1") >>> w = x1*x0 >>> collector.map_relation(w) x1**2 See Also ======== pc_presentation """ array = w.array_form s1 = array[0][0] s2 = array[1][0] key = ((s2, -1), (s1, 1), (s2, 1)) key = self.free_group.dtype(key) return self.pc_presentation[key] def collected_word(self, word): r""" Return the collected form of a word. Explanation =========== A word ``w`` is called collected, if `w = {x_{i_1}}^{a_1} * \ldots * {x_{i_r}}^{a_r}` with `i_1 < i_2< \ldots < i_r` and `a_j` is in `\{1, \ldots, {s_j}-1\}`. Otherwise w is uncollected. Parameters ========== word : FreeGroupElement An uncollected word. Returns ======= word A collected word of form `w = {x_{i_1}}^{a_1}, \ldots, {x_{i_r}}^{a_r}` with `i_1, i_2, \ldots, i_r` and `a_j \in \{1, \ldots, {s_j}-1\}`. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics.free_groups import free_group >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> F, x0, x1, x2, x3 = free_group("x0, x1, x2, x3") >>> word = x3*x2*x1*x0 >>> collected_word = collector.collected_word(word) >>> free_to_perm = {} >>> free_group = collector.free_group >>> for sym, gen in zip(free_group.symbols, collector.pcgs): ... free_to_perm[sym] = gen >>> G1 = PermutationGroup() >>> for w in word: ... sym = w[0] ... perm = free_to_perm[sym] ... G1 = PermutationGroup([perm] + G1.generators) >>> G2 = PermutationGroup() >>> for w in collected_word: ... sym = w[0] ... perm = free_to_perm[sym] ... G2 = PermutationGroup([perm] + G2.generators) >>> G1 == G2 True See Also ======== minimal_uncollected_subword """ free_group = self.free_group while True: w = self.minimal_uncollected_subword(word) if not w: break low, high = self.subword_index(word, free_group.dtype(w)) if low == -1: continue s1, e1 = w[0] if len(w) == 1: re = self.relative_order[self.index[s1]] q = e1 // re r = e1-q*re key = ((w[0][0], re), ) key = free_group.dtype(key) if self.pc_presentation[key]: presentation = self.pc_presentation[key].array_form sym, exp = presentation[0] word_ = ((w[0][0], r), (sym, q*exp)) word_ = free_group.dtype(word_) else: if r != 0: word_ = ((w[0][0], r), ) word_ = free_group.dtype(word_) else: word_ = None word = word.eliminate_word(free_group.dtype(w), word_) if len(w) == 2 and w[1][1] > 0: s2, e2 = w[1] s2 = ((s2, 1), ) s2 = free_group.dtype(s2) word_ = self.map_relation(free_group.dtype(w)) word_ = s2*word_**e1 word_ = free_group.dtype(word_) word = word.substituted_word(low, high, word_) elif len(w) == 2 and w[1][1] < 0: s2, e2 = w[1] s2 = ((s2, 1), ) s2 = free_group.dtype(s2) word_ = self.map_relation(free_group.dtype(w)) word_ = s2**-1*word_**e1 word_ = free_group.dtype(word_) word = word.substituted_word(low, high, word_) return word def pc_relators(self): r""" Return the polycyclic presentation. Explanation =========== There are two types of relations used in polycyclic presentation. * ``Power relations`` : Power relators are of the form `x_i^{re_i}`, where `i \in \{0, \ldots, \mathrm{len(pcgs)}\}`, ``x`` represents polycyclic generator and ``re`` is the corresponding relative order. * ``Conjugate relations`` : Conjugate relators are of the form `x_j^-1x_ix_j`, where `j < i \in \{0, \ldots, \mathrm{len(pcgs)}\}`. Returns ======= A dictionary with power and conjugate relations as key and their collected form as corresponding values. Notes ===== Identity Permutation is mapped with empty ``()``. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.permutations import Permutation >>> S = SymmetricGroup(49).sylow_subgroup(7) >>> der = S.derived_series() >>> G = der[len(der)-2] >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> pcgs = PcGroup.pcgs >>> len(pcgs) 6 >>> free_group = collector.free_group >>> pc_resentation = collector.pc_presentation >>> free_to_perm = {} >>> for s, g in zip(free_group.symbols, pcgs): ... free_to_perm[s] = g >>> for k, v in pc_resentation.items(): ... k_array = k.array_form ... if v != (): ... v_array = v.array_form ... lhs = Permutation() ... for gen in k_array: ... s = gen[0] ... e = gen[1] ... lhs = lhs*free_to_perm[s]**e ... if v == (): ... assert lhs.is_identity ... continue ... rhs = Permutation() ... for gen in v_array: ... s = gen[0] ... e = gen[1] ... rhs = rhs*free_to_perm[s]**e ... assert lhs == rhs """ free_group = self.free_group rel_order = self.relative_order pc_relators = {} perm_to_free = {} pcgs = self.pcgs for gen, s in zip(pcgs, free_group.generators): perm_to_free[gen**-1] = s**-1 perm_to_free[gen] = s pcgs = pcgs[::-1] series = self.pc_series[::-1] rel_order = rel_order[::-1] collected_gens = [] for i, gen in enumerate(pcgs): re = rel_order[i] relation = perm_to_free[gen]**re G = series[i] l = G.generator_product(gen**re, original = True) l.reverse() word = free_group.identity for g in l: word = word*perm_to_free[g] word = self.collected_word(word) pc_relators[relation] = word if word else () self.pc_presentation = pc_relators collected_gens.append(gen) if len(collected_gens) > 1: conj = collected_gens[len(collected_gens)-1] conjugator = perm_to_free[conj] for j in range(len(collected_gens)-1): conjugated = perm_to_free[collected_gens[j]] relation = conjugator**-1*conjugated*conjugator gens = conj**-1*collected_gens[j]*conj l = G.generator_product(gens, original = True) l.reverse() word = free_group.identity for g in l: word = word*perm_to_free[g] word = self.collected_word(word) pc_relators[relation] = word if word else () self.pc_presentation = pc_relators return pc_relators def exponent_vector(self, element): r""" Return the exponent vector of length equal to the length of polycyclic generating sequence. Explanation =========== For a given generator/element ``g`` of the polycyclic group, it can be represented as `g = {x_1}^{e_1}, \ldots, {x_n}^{e_n}`, where `x_i` represents polycyclic generators and ``n`` is the number of generators in the free_group equal to the length of pcgs. Parameters ========== element : Permutation Generator of a polycyclic group. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.permutations import Permutation >>> G = SymmetricGroup(4) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> pcgs = PcGroup.pcgs >>> collector.exponent_vector(G[0]) [1, 0, 0, 0] >>> exp = collector.exponent_vector(G[1]) >>> g = Permutation() >>> for i in range(len(exp)): ... g = g*pcgs[i]**exp[i] if exp[i] else g >>> assert g == G[1] References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" Section 8.1.1, Definition 8.4 """ free_group = self.free_group G = PermutationGroup() for g in self.pcgs: G = PermutationGroup([g] + G.generators) gens = G.generator_product(element, original = True) gens.reverse() perm_to_free = {} for sym, g in zip(free_group.generators, self.pcgs): perm_to_free[g**-1] = sym**-1 perm_to_free[g] = sym w = free_group.identity for g in gens: w = w*perm_to_free[g] word = self.collected_word(w) index = self.index exp_vector = [0]*len(free_group) word = word.array_form for t in word: exp_vector[index[t[0]]] = t[1] return exp_vector def depth(self, element): r""" Return the depth of a given element. Explanation =========== The depth of a given element ``g`` is defined by `\mathrm{dep}[g] = i` if `e_1 = e_2 = \ldots = e_{i-1} = 0` and `e_i != 0`, where ``e`` represents the exponent-vector. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(3) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> collector.depth(G[0]) 2 >>> collector.depth(G[1]) 1 References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" Section 8.1.1, Definition 8.5 """ exp_vector = self.exponent_vector(element) return next((i+1 for i, x in enumerate(exp_vector) if x), len(self.pcgs)+1) def leading_exponent(self, element): r""" Return the leading non-zero exponent. Explanation =========== The leading exponent for a given element `g` is defined by `\mathrm{leading\_exponent}[g]` `= e_i`, if `\mathrm{depth}[g] = i`. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> G = SymmetricGroup(3) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> collector.leading_exponent(G[1]) 1 """ exp_vector = self.exponent_vector(element) depth = self.depth(element) if depth != len(self.pcgs)+1: return exp_vector[depth-1] return None def _sift(self, z, g): h = g d = self.depth(h) while d < len(self.pcgs) and z[d-1] != 1: k = z[d-1] e = self.leading_exponent(h)*(self.leading_exponent(k))**-1 e = e % self.relative_order[d-1] h = k**-e*h d = self.depth(h) return h def induced_pcgs(self, gens): """ Parameters ========== gens : list A list of generators on which polycyclic subgroup is to be defined. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> S = SymmetricGroup(8) >>> G = S.sylow_subgroup(2) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> gens = [G[0], G[1]] >>> ipcgs = collector.induced_pcgs(gens) >>> [gen.order() for gen in ipcgs] [2, 2, 2] >>> G = S.sylow_subgroup(3) >>> PcGroup = G.polycyclic_group() >>> collector = PcGroup.collector >>> gens = [G[0], G[1]] >>> ipcgs = collector.induced_pcgs(gens) >>> [gen.order() for gen in ipcgs] [3] """ z = [1]*len(self.pcgs) G = gens while G: g = G.pop(0) h = self._sift(z, g) d = self.depth(h) if d < len(self.pcgs): for gen in z: if gen != 1: G.append(h**-1*gen**-1*h*gen) z[d-1] = h; z = [gen for gen in z if gen != 1] return z def constructive_membership_test(self, ipcgs, g): """ Return the exponent vector for induced pcgs. """ e = [0]*len(ipcgs) h = g d = self.depth(h) for i, gen in enumerate(ipcgs): while self.depth(gen) == d: f = self.leading_exponent(h)*self.leading_exponent(gen) f = f % self.relative_order[d-1] h = gen**(-f)*h e[i] = f d = self.depth(h) if h == 1: return e return False sympy-sympy-1.9/sympy/combinatorics/perm_groups.py000066400000000000000000005470211412543434000226650ustar00rootroot00000000000000from random import randrange, choice from math import log from sympy.ntheory import primefactors from sympy import multiplicity, factorint, Symbol from sympy.combinatorics import Permutation from sympy.combinatorics.permutations import (_af_commutes_with, _af_invert, _af_rmul, _af_rmuln, _af_pow, Cycle) from sympy.combinatorics.util import (_check_cycles_alt_sym, _distribute_gens_by_base, _orbits_transversals_from_bsgs, _handle_precomputed_bsgs, _base_ordering, _strong_gens_from_distr, _strip, _strip_af) from sympy.core import Basic from sympy.functions.combinatorial.factorials import factorial from sympy.ntheory import sieve from sympy.utilities.iterables import has_variety, is_sequence, uniq from sympy.testing.randtest import _randrange from itertools import islice from sympy.core.sympify import _sympify rmul = Permutation.rmul_with_af _af_new = Permutation._af_new class PermutationGroup(Basic): """The class defining a Permutation group. Explanation =========== PermutationGroup([p1, p2, ..., pn]) returns the permutation group generated by the list of permutations. This group can be supplied to Polyhedron if one desires to decorate the elements to which the indices of the permutation refer. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.polyhedron import Polyhedron >>> from sympy.combinatorics.perm_groups import PermutationGroup The permutations corresponding to motion of the front, right and bottom face of a 2x2 Rubik's cube are defined: >>> F = Permutation(2, 19, 21, 8)(3, 17, 20, 10)(4, 6, 7, 5) >>> R = Permutation(1, 5, 21, 14)(3, 7, 23, 12)(8, 10, 11, 9) >>> D = Permutation(6, 18, 14, 10)(7, 19, 15, 11)(20, 22, 23, 21) These are passed as permutations to PermutationGroup: >>> G = PermutationGroup(F, R, D) >>> G.order() 3674160 The group can be supplied to a Polyhedron in order to track the objects being moved. An example involving the 2x2 Rubik's cube is given there, but here is a simple demonstration: >>> a = Permutation(2, 1) >>> b = Permutation(1, 0) >>> G = PermutationGroup(a, b) >>> P = Polyhedron(list('ABC'), pgroup=G) >>> P.corners (A, B, C) >>> P.rotate(0) # apply permutation 0 >>> P.corners (A, C, B) >>> P.reset() >>> P.corners (A, B, C) Or one can make a permutation as a product of selected permutations and apply them to an iterable directly: >>> P10 = G.make_perm([0, 1]) >>> P10('ABC') ['C', 'A', 'B'] See Also ======== sympy.combinatorics.polyhedron.Polyhedron, sympy.combinatorics.permutations.Permutation References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" .. [2] Seress, A. "Permutation Group Algorithms" .. [3] https://en.wikipedia.org/wiki/Schreier_vector .. [4] https://en.wikipedia.org/wiki/Nielsen_transformation#Product_replacement_algorithm .. [5] Frank Celler, Charles R.Leedham-Green, Scott H.Murray, Alice C.Niemeyer, and E.A.O'Brien. "Generating Random Elements of a Finite Group" .. [6] https://en.wikipedia.org/wiki/Block_%28permutation_group_theory%29 .. [7] http://www.algorithmist.com/index.php/Union_Find .. [8] https://en.wikipedia.org/wiki/Multiply_transitive_group#Multiply_transitive_groups .. [9] https://en.wikipedia.org/wiki/Center_%28group_theory%29 .. [10] https://en.wikipedia.org/wiki/Centralizer_and_normalizer .. [11] http://groupprops.subwiki.org/wiki/Derived_subgroup .. [12] https://en.wikipedia.org/wiki/Nilpotent_group .. [13] http://www.math.colostate.edu/~hulpke/CGT/cgtnotes.pdf .. [14] https://www.gap-system.org/Manuals/doc/ref/manual.pdf """ is_group = True def __new__(cls, *args, dups=True, **kwargs): """The default constructor. Accepts Cycle and Permutation forms. Removes duplicates unless ``dups`` keyword is ``False``. """ if not args: args = [Permutation()] else: args = list(args[0] if is_sequence(args[0]) else args) if not args: args = [Permutation()] if any(isinstance(a, Cycle) for a in args): args = [Permutation(a) for a in args] if has_variety(a.size for a in args): degree = kwargs.pop('degree', None) if degree is None: degree = max(a.size for a in args) for i in range(len(args)): if args[i].size != degree: args[i] = Permutation(args[i], size=degree) if dups: args = list(uniq([_af_new(list(a)) for a in args])) if len(args) > 1: args = [g for g in args if not g.is_identity] obj = Basic.__new__(cls, *args, **kwargs) obj._generators = args obj._order = None obj._center = [] obj._is_abelian = None obj._is_transitive = None obj._is_sym = None obj._is_alt = None obj._is_primitive = None obj._is_nilpotent = None obj._is_solvable = None obj._is_trivial = None obj._transitivity_degree = None obj._max_div = None obj._is_perfect = None obj._is_cyclic = None obj._r = len(obj._generators) obj._degree = obj._generators[0].size # these attributes are assigned after running schreier_sims obj._base = [] obj._strong_gens = [] obj._strong_gens_slp = [] obj._basic_orbits = [] obj._transversals = [] obj._transversal_slp = [] # these attributes are assigned after running _random_pr_init obj._random_gens = [] # finite presentation of the group as an instance of `FpGroup` obj._fp_presentation = None return obj def __getitem__(self, i): return self._generators[i] def __contains__(self, i): """Return ``True`` if *i* is contained in PermutationGroup. Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup >>> p = Permutation(1, 2, 3) >>> Permutation(3) in PermutationGroup(p) True """ if not isinstance(i, Permutation): raise TypeError("A PermutationGroup contains only Permutations as " "elements, not elements of type %s" % type(i)) return self.contains(i) def __len__(self): return len(self._generators) def __eq__(self, other): """Return ``True`` if PermutationGroup generated by elements in the group are same i.e they represent the same PermutationGroup. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> p = Permutation(0, 1, 2, 3, 4, 5) >>> G = PermutationGroup([p, p**2]) >>> H = PermutationGroup([p**2, p]) >>> G.generators == H.generators False >>> G == H True """ if not isinstance(other, PermutationGroup): return False set_self_gens = set(self.generators) set_other_gens = set(other.generators) # before reaching the general case there are also certain # optimisation and obvious cases requiring less or no actual # computation. if set_self_gens == set_other_gens: return True # in the most general case it will check that each generator of # one group belongs to the other PermutationGroup and vice-versa for gen1 in set_self_gens: if not other.contains(gen1): return False for gen2 in set_other_gens: if not self.contains(gen2): return False return True def __hash__(self): return super().__hash__() def __mul__(self, other): """ Return the direct product of two permutation groups as a permutation group. Explanation =========== This implementation realizes the direct product by shifting the index set for the generators of the second group: so if we have ``G`` acting on ``n1`` points and ``H`` acting on ``n2`` points, ``G*H`` acts on ``n1 + n2`` points. Examples ======== >>> from sympy.combinatorics.named_groups import CyclicGroup >>> G = CyclicGroup(5) >>> H = G*G >>> H PermutationGroup([ (9)(0 1 2 3 4), (5 6 7 8 9)]) >>> H.order() 25 """ if isinstance(other, Permutation): return Coset(other, self, dir='+') gens1 = [perm._array_form for perm in self.generators] gens2 = [perm._array_form for perm in other.generators] n1 = self._degree n2 = other._degree start = list(range(n1)) end = list(range(n1, n1 + n2)) for i in range(len(gens2)): gens2[i] = [x + n1 for x in gens2[i]] gens2 = [start + gen for gen in gens2] gens1 = [gen + end for gen in gens1] together = gens1 + gens2 gens = [_af_new(x) for x in together] return PermutationGroup(gens) def _random_pr_init(self, r, n, _random_prec_n=None): r"""Initialize random generators for the product replacement algorithm. Explanation =========== The implementation uses a modification of the original product replacement algorithm due to Leedham-Green, as described in [1], pp. 69-71; also, see [2], pp. 27-29 for a detailed theoretical analysis of the original product replacement algorithm, and [4]. The product replacement algorithm is used for producing random, uniformly distributed elements of a group `G` with a set of generators `S`. For the initialization ``_random_pr_init``, a list ``R`` of `\max\{r, |S|\}` group generators is created as the attribute ``G._random_gens``, repeating elements of `S` if necessary, and the identity element of `G` is appended to ``R`` - we shall refer to this last element as the accumulator. Then the function ``random_pr()`` is called ``n`` times, randomizing the list ``R`` while preserving the generation of `G` by ``R``. The function ``random_pr()`` itself takes two random elements ``g, h`` among all elements of ``R`` but the accumulator and replaces ``g`` with a randomly chosen element from `\{gh, g(~h), hg, (~h)g\}`. Then the accumulator is multiplied by whatever ``g`` was replaced by. The new value of the accumulator is then returned by ``random_pr()``. The elements returned will eventually (for ``n`` large enough) become uniformly distributed across `G` ([5]). For practical purposes however, the values ``n = 50, r = 11`` are suggested in [1]. Notes ===== THIS FUNCTION HAS SIDE EFFECTS: it changes the attribute self._random_gens See Also ======== random_pr """ deg = self.degree random_gens = [x._array_form for x in self.generators] k = len(random_gens) if k < r: for i in range(k, r): random_gens.append(random_gens[i - k]) acc = list(range(deg)) random_gens.append(acc) self._random_gens = random_gens # handle randomized input for testing purposes if _random_prec_n is None: for i in range(n): self.random_pr() else: for i in range(n): self.random_pr(_random_prec=_random_prec_n[i]) def _union_find_merge(self, first, second, ranks, parents, not_rep): """Merges two classes in a union-find data structure. Explanation =========== Used in the implementation of Atkinson's algorithm as suggested in [1], pp. 83-87. The class merging process uses union by rank as an optimization. ([7]) Notes ===== THIS FUNCTION HAS SIDE EFFECTS: the list of class representatives, ``parents``, the list of class sizes, ``ranks``, and the list of elements that are not representatives, ``not_rep``, are changed due to class merging. See Also ======== minimal_block, _union_find_rep References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of computational group theory" .. [7] http://www.algorithmist.com/index.php/Union_Find """ rep_first = self._union_find_rep(first, parents) rep_second = self._union_find_rep(second, parents) if rep_first != rep_second: # union by rank if ranks[rep_first] >= ranks[rep_second]: new_1, new_2 = rep_first, rep_second else: new_1, new_2 = rep_second, rep_first total_rank = ranks[new_1] + ranks[new_2] if total_rank > self.max_div: return -1 parents[new_2] = new_1 ranks[new_1] = total_rank not_rep.append(new_2) return 1 return 0 def _union_find_rep(self, num, parents): """Find representative of a class in a union-find data structure. Explanation =========== Used in the implementation of Atkinson's algorithm as suggested in [1], pp. 83-87. After the representative of the class to which ``num`` belongs is found, path compression is performed as an optimization ([7]). Notes ===== THIS FUNCTION HAS SIDE EFFECTS: the list of class representatives, ``parents``, is altered due to path compression. See Also ======== minimal_block, _union_find_merge References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of computational group theory" .. [7] http://www.algorithmist.com/index.php/Union_Find """ rep, parent = num, parents[num] while parent != rep: rep = parent parent = parents[rep] # path compression temp, parent = num, parents[num] while parent != rep: parents[temp] = rep temp = parent parent = parents[temp] return rep @property def base(self): """Return a base from the Schreier-Sims algorithm. Explanation =========== For a permutation group `G`, a base is a sequence of points `B = (b_1, b_2, ..., b_k)` such that no element of `G` apart from the identity fixes all the points in `B`. The concepts of a base and strong generating set and their applications are discussed in depth in [1], pp. 87-89 and [2], pp. 55-57. An alternative way to think of `B` is that it gives the indices of the stabilizer cosets that contain more than the identity permutation. Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup >>> G = PermutationGroup([Permutation(0, 1, 3)(2, 4)]) >>> G.base [0, 2] See Also ======== strong_gens, basic_transversals, basic_orbits, basic_stabilizers """ if self._base == []: self.schreier_sims() return self._base def baseswap(self, base, strong_gens, pos, randomized=False, transversals=None, basic_orbits=None, strong_gens_distr=None): r"""Swap two consecutive base points in base and strong generating set. Explanation =========== If a base for a group `G` is given by `(b_1, b_2, ..., b_k)`, this function returns a base `(b_1, b_2, ..., b_{i+1}, b_i, ..., b_k)`, where `i` is given by ``pos``, and a strong generating set relative to that base. The original base and strong generating set are not modified. The randomized version (default) is of Las Vegas type. Parameters ========== base, strong_gens The base and strong generating set. pos The position at which swapping is performed. randomized A switch between randomized and deterministic version. transversals The transversals for the basic orbits, if known. basic_orbits The basic orbits, if known. strong_gens_distr The strong generators distributed by basic stabilizers, if known. Returns ======= (base, strong_gens) ``base`` is the new base, and ``strong_gens`` is a generating set relative to it. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.testutil import _verify_bsgs >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> S = SymmetricGroup(4) >>> S.schreier_sims() >>> S.base [0, 1, 2] >>> base, gens = S.baseswap(S.base, S.strong_gens, 1, randomized=False) >>> base, gens ([0, 2, 1], [(0 1 2 3), (3)(0 1), (1 3 2), (2 3), (1 3)]) check that base, gens is a BSGS >>> S1 = PermutationGroup(gens) >>> _verify_bsgs(S1, base, gens) True See Also ======== schreier_sims Notes ===== The deterministic version of the algorithm is discussed in [1], pp. 102-103; the randomized version is discussed in [1], p.103, and [2], p.98. It is of Las Vegas type. Notice that [1] contains a mistake in the pseudocode and discussion of BASESWAP: on line 3 of the pseudocode, `|\beta_{i+1}^{\left\langle T\right\rangle}|` should be replaced by `|\beta_{i}^{\left\langle T\right\rangle}|`, and the same for the discussion of the algorithm. """ # construct the basic orbits, generators for the stabilizer chain # and transversal elements from whatever was provided transversals, basic_orbits, strong_gens_distr = \ _handle_precomputed_bsgs(base, strong_gens, transversals, basic_orbits, strong_gens_distr) base_len = len(base) degree = self.degree # size of orbit of base[pos] under the stabilizer we seek to insert # in the stabilizer chain at position pos + 1 size = len(basic_orbits[pos])*len(basic_orbits[pos + 1]) \ //len(_orbit(degree, strong_gens_distr[pos], base[pos + 1])) # initialize the wanted stabilizer by a subgroup if pos + 2 > base_len - 1: T = [] else: T = strong_gens_distr[pos + 2][:] # randomized version if randomized is True: stab_pos = PermutationGroup(strong_gens_distr[pos]) schreier_vector = stab_pos.schreier_vector(base[pos + 1]) # add random elements of the stabilizer until they generate it while len(_orbit(degree, T, base[pos])) != size: new = stab_pos.random_stab(base[pos + 1], schreier_vector=schreier_vector) T.append(new) # deterministic version else: Gamma = set(basic_orbits[pos]) Gamma.remove(base[pos]) if base[pos + 1] in Gamma: Gamma.remove(base[pos + 1]) # add elements of the stabilizer until they generate it by # ruling out member of the basic orbit of base[pos] along the way while len(_orbit(degree, T, base[pos])) != size: gamma = next(iter(Gamma)) x = transversals[pos][gamma] temp = x._array_form.index(base[pos + 1]) # (~x)(base[pos + 1]) if temp not in basic_orbits[pos + 1]: Gamma = Gamma - _orbit(degree, T, gamma) else: y = transversals[pos + 1][temp] el = rmul(x, y) if el(base[pos]) not in _orbit(degree, T, base[pos]): T.append(el) Gamma = Gamma - _orbit(degree, T, base[pos]) # build the new base and strong generating set strong_gens_new_distr = strong_gens_distr[:] strong_gens_new_distr[pos + 1] = T base_new = base[:] base_new[pos], base_new[pos + 1] = base_new[pos + 1], base_new[pos] strong_gens_new = _strong_gens_from_distr(strong_gens_new_distr) for gen in T: if gen not in strong_gens_new: strong_gens_new.append(gen) return base_new, strong_gens_new @property def basic_orbits(self): """ Return the basic orbits relative to a base and strong generating set. Explanation =========== If `(b_1, b_2, ..., b_k)` is a base for a group `G`, and `G^{(i)} = G_{b_1, b_2, ..., b_{i-1}}` is the ``i``-th basic stabilizer (so that `G^{(1)} = G`), the ``i``-th basic orbit relative to this base is the orbit of `b_i` under `G^{(i)}`. See [1], pp. 87-89 for more information. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> S = SymmetricGroup(4) >>> S.basic_orbits [[0, 1, 2, 3], [1, 2, 3], [2, 3]] See Also ======== base, strong_gens, basic_transversals, basic_stabilizers """ if self._basic_orbits == []: self.schreier_sims() return self._basic_orbits @property def basic_stabilizers(self): """ Return a chain of stabilizers relative to a base and strong generating set. Explanation =========== The ``i``-th basic stabilizer `G^{(i)}` relative to a base `(b_1, b_2, ..., b_k)` is `G_{b_1, b_2, ..., b_{i-1}}`. For more information, see [1], pp. 87-89. Examples ======== >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> A = AlternatingGroup(4) >>> A.schreier_sims() >>> A.base [0, 1] >>> for g in A.basic_stabilizers: ... print(g) ... PermutationGroup([ (3)(0 1 2), (1 2 3)]) PermutationGroup([ (1 2 3)]) See Also ======== base, strong_gens, basic_orbits, basic_transversals """ if self._transversals == []: self.schreier_sims() strong_gens = self._strong_gens base = self._base if not base: # e.g. if self is trivial return [] strong_gens_distr = _distribute_gens_by_base(base, strong_gens) basic_stabilizers = [] for gens in strong_gens_distr: basic_stabilizers.append(PermutationGroup(gens)) return basic_stabilizers @property def basic_transversals(self): """ Return basic transversals relative to a base and strong generating set. Explanation =========== The basic transversals are transversals of the basic orbits. They are provided as a list of dictionaries, each dictionary having keys - the elements of one of the basic orbits, and values - the corresponding transversal elements. See [1], pp. 87-89 for more information. Examples ======== >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> A = AlternatingGroup(4) >>> A.basic_transversals [{0: (3), 1: (3)(0 1 2), 2: (3)(0 2 1), 3: (0 3 1)}, {1: (3), 2: (1 2 3), 3: (1 3 2)}] See Also ======== strong_gens, base, basic_orbits, basic_stabilizers """ if self._transversals == []: self.schreier_sims() return self._transversals def composition_series(self): r""" Return the composition series for a group as a list of permutation groups. Explanation =========== The composition series for a group `G` is defined as a subnormal series `G = H_0 > H_1 > H_2 \ldots` A composition series is a subnormal series such that each factor group `H(i+1) / H(i)` is simple. A subnormal series is a composition series only if it is of maximum length. The algorithm works as follows: Starting with the derived series the idea is to fill the gap between `G = der[i]` and `H = der[i+1]` for each `i` independently. Since, all subgroups of the abelian group `G/H` are normal so, first step is to take the generators `g` of `G` and add them to generators of `H` one by one. The factor groups formed are not simple in general. Each group is obtained from the previous one by adding one generator `g`, if the previous group is denoted by `H` then the next group `K` is generated by `g` and `H`. The factor group `K/H` is cyclic and it's order is `K.order()//G.order()`. The series is then extended between `K` and `H` by groups generated by powers of `g` and `H`. The series formed is then prepended to the already existing series. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.named_groups import CyclicGroup >>> S = SymmetricGroup(12) >>> G = S.sylow_subgroup(2) >>> C = G.composition_series() >>> [H.order() for H in C] [1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 1] >>> G = S.sylow_subgroup(3) >>> C = G.composition_series() >>> [H.order() for H in C] [243, 81, 27, 9, 3, 1] >>> G = CyclicGroup(12) >>> C = G.composition_series() >>> [H.order() for H in C] [12, 6, 3, 1] """ der = self.derived_series() if not (all(g.is_identity for g in der[-1].generators)): raise NotImplementedError('Group should be solvable') series = [] for i in range(len(der)-1): H = der[i+1] up_seg = [] for g in der[i].generators: K = PermutationGroup([g] + H.generators) order = K.order() // H.order() down_seg = [] for p, e in factorint(order).items(): for j in range(e): down_seg.append(PermutationGroup([g] + H.generators)) g = g**p up_seg = down_seg + up_seg H = K up_seg[0] = der[i] series.extend(up_seg) series.append(der[-1]) return series def coset_transversal(self, H): """Return a transversal of the right cosets of self by its subgroup H using the second method described in [1], Subsection 4.6.7 """ if not H.is_subgroup(self): raise ValueError("The argument must be a subgroup") if H.order() == 1: return self._elements self._schreier_sims(base=H.base) # make G.base an extension of H.base base = self.base base_ordering = _base_ordering(base, self.degree) identity = Permutation(self.degree - 1) transversals = self.basic_transversals[:] # transversals is a list of dictionaries. Get rid of the keys # so that it is a list of lists and sort each list in # the increasing order of base[l]^x for l, t in enumerate(transversals): transversals[l] = sorted(t.values(), key = lambda x: base_ordering[base[l]^x]) orbits = H.basic_orbits h_stabs = H.basic_stabilizers g_stabs = self.basic_stabilizers indices = [x.order()//y.order() for x, y in zip(g_stabs, h_stabs)] # T^(l) should be a right transversal of H^(l) in G^(l) for # 1<=l<=len(base). While H^(l) is the trivial group, T^(l) # contains all the elements of G^(l) so we might just as well # start with l = len(h_stabs)-1 if len(g_stabs) > len(h_stabs): T = g_stabs[len(h_stabs)]._elements else: T = [identity] l = len(h_stabs)-1 t_len = len(T) while l > -1: T_next = [] for u in transversals[l]: if u == identity: continue b = base_ordering[base[l]^u] for t in T: p = t*u if all([base_ordering[h^p] >= b for h in orbits[l]]): T_next.append(p) if t_len + len(T_next) == indices[l]: break if t_len + len(T_next) == indices[l]: break T += T_next t_len += len(T_next) l -= 1 T.remove(identity) T = [identity] + T return T def _coset_representative(self, g, H): """Return the representative of Hg from the transversal that would be computed by ``self.coset_transversal(H)``. """ if H.order() == 1: return g # The base of self must be an extension of H.base. if not(self.base[:len(H.base)] == H.base): self._schreier_sims(base=H.base) orbits = H.basic_orbits[:] h_transversals = [list(_.values()) for _ in H.basic_transversals] transversals = [list(_.values()) for _ in self.basic_transversals] base = self.base base_ordering = _base_ordering(base, self.degree) def step(l, x): gamma = sorted(orbits[l], key = lambda y: base_ordering[y^x])[0] i = [base[l]^h for h in h_transversals[l]].index(gamma) x = h_transversals[l][i]*x if l < len(orbits)-1: for u in transversals[l]: if base[l]^u == base[l]^x: break x = step(l+1, x*u**-1)*u return x return step(0, g) def coset_table(self, H): """Return the standardised (right) coset table of self in H as a list of lists. """ # Maybe this should be made to return an instance of CosetTable # from fp_groups.py but the class would need to be changed first # to be compatible with PermutationGroups from itertools import chain, product if not H.is_subgroup(self): raise ValueError("The argument must be a subgroup") T = self.coset_transversal(H) n = len(T) A = list(chain.from_iterable((gen, gen**-1) for gen in self.generators)) table = [] for i in range(n): row = [self._coset_representative(T[i]*x, H) for x in A] row = [T.index(r) for r in row] table.append(row) # standardize (this is the same as the algorithm used in coset_table) # If CosetTable is made compatible with PermutationGroups, this # should be replaced by table.standardize() A = range(len(A)) gamma = 1 for alpha, a in product(range(n), A): beta = table[alpha][a] if beta >= gamma: if beta > gamma: for x in A: z = table[gamma][x] table[gamma][x] = table[beta][x] table[beta][x] = z for i in range(n): if table[i][x] == beta: table[i][x] = gamma elif table[i][x] == gamma: table[i][x] = beta gamma += 1 if gamma >= n-1: return table def center(self): r""" Return the center of a permutation group. Explanation =========== The center for a group `G` is defined as `Z(G) = \{z\in G | \forall g\in G, zg = gz \}`, the set of elements of `G` that commute with all elements of `G`. It is equal to the centralizer of `G` inside `G`, and is naturally a subgroup of `G` ([9]). Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> D = DihedralGroup(4) >>> G = D.center() >>> G.order() 2 See Also ======== centralizer Notes ===== This is a naive implementation that is a straightforward application of ``.centralizer()`` """ return self.centralizer(self) def centralizer(self, other): r""" Return the centralizer of a group/set/element. Explanation =========== The centralizer of a set of permutations ``S`` inside a group ``G`` is the set of elements of ``G`` that commute with all elements of ``S``:: `C_G(S) = \{ g \in G | gs = sg \forall s \in S\}` ([10]) Usually, ``S`` is a subset of ``G``, but if ``G`` is a proper subgroup of the full symmetric group, we allow for ``S`` to have elements outside ``G``. It is naturally a subgroup of ``G``; the centralizer of a permutation group is equal to the centralizer of any set of generators for that group, since any element commuting with the generators commutes with any product of the generators. Parameters ========== other a permutation group/list of permutations/single permutation Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... CyclicGroup) >>> S = SymmetricGroup(6) >>> C = CyclicGroup(6) >>> H = S.centralizer(C) >>> H.is_subgroup(C) True See Also ======== subgroup_search Notes ===== The implementation is an application of ``.subgroup_search()`` with tests using a specific base for the group ``G``. """ if hasattr(other, 'generators'): if other.is_trivial or self.is_trivial: return self degree = self.degree identity = _af_new(list(range(degree))) orbits = other.orbits() num_orbits = len(orbits) orbits.sort(key=lambda x: -len(x)) long_base = [] orbit_reps = [None]*num_orbits orbit_reps_indices = [None]*num_orbits orbit_descr = [None]*degree for i in range(num_orbits): orbit = list(orbits[i]) orbit_reps[i] = orbit[0] orbit_reps_indices[i] = len(long_base) for point in orbit: orbit_descr[point] = i long_base = long_base + orbit base, strong_gens = self.schreier_sims_incremental(base=long_base) strong_gens_distr = _distribute_gens_by_base(base, strong_gens) i = 0 for i in range(len(base)): if strong_gens_distr[i] == [identity]: break base = base[:i] base_len = i for j in range(num_orbits): if base[base_len - 1] in orbits[j]: break rel_orbits = orbits[: j + 1] num_rel_orbits = len(rel_orbits) transversals = [None]*num_rel_orbits for j in range(num_rel_orbits): rep = orbit_reps[j] transversals[j] = dict( other.orbit_transversal(rep, pairs=True)) trivial_test = lambda x: True tests = [None]*base_len for l in range(base_len): if base[l] in orbit_reps: tests[l] = trivial_test else: def test(computed_words, l=l): g = computed_words[l] rep_orb_index = orbit_descr[base[l]] rep = orbit_reps[rep_orb_index] im = g._array_form[base[l]] im_rep = g._array_form[rep] tr_el = transversals[rep_orb_index][base[l]] # using the definition of transversal, # base[l]^g = rep^(tr_el*g); # if g belongs to the centralizer, then # base[l]^g = (rep^g)^tr_el return im == tr_el._array_form[im_rep] tests[l] = test def prop(g): return [rmul(g, gen) for gen in other.generators] == \ [rmul(gen, g) for gen in other.generators] return self.subgroup_search(prop, base=base, strong_gens=strong_gens, tests=tests) elif hasattr(other, '__getitem__'): gens = list(other) return self.centralizer(PermutationGroup(gens)) elif hasattr(other, 'array_form'): return self.centralizer(PermutationGroup([other])) def commutator(self, G, H): """ Return the commutator of two subgroups. Explanation =========== For a permutation group ``K`` and subgroups ``G``, ``H``, the commutator of ``G`` and ``H`` is defined as the group generated by all the commutators `[g, h] = hgh^{-1}g^{-1}` for ``g`` in ``G`` and ``h`` in ``H``. It is naturally a subgroup of ``K`` ([1], p.27). Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... AlternatingGroup) >>> S = SymmetricGroup(5) >>> A = AlternatingGroup(5) >>> G = S.commutator(S, A) >>> G.is_subgroup(A) True See Also ======== derived_subgroup Notes ===== The commutator of two subgroups `H, G` is equal to the normal closure of the commutators of all the generators, i.e. `hgh^{-1}g^{-1}` for `h` a generator of `H` and `g` a generator of `G` ([1], p.28) """ ggens = G.generators hgens = H.generators commutators = [] for ggen in ggens: for hgen in hgens: commutator = rmul(hgen, ggen, ~hgen, ~ggen) if commutator not in commutators: commutators.append(commutator) res = self.normal_closure(commutators) return res def coset_factor(self, g, factor_index=False): """Return ``G``'s (self's) coset factorization of ``g`` Explanation =========== If ``g`` is an element of ``G`` then it can be written as the product of permutations drawn from the Schreier-Sims coset decomposition, The permutations returned in ``f`` are those for which the product gives ``g``: ``g = f[n]*...f[1]*f[0]`` where ``n = len(B)`` and ``B = G.base``. f[i] is one of the permutations in ``self._basic_orbits[i]``. If factor_index==True, returns a tuple ``[b[0],..,b[n]]``, where ``b[i]`` belongs to ``self._basic_orbits[i]`` Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup >>> a = Permutation(0, 1, 3, 7, 6, 4)(2, 5) >>> b = Permutation(0, 1, 3, 2)(4, 5, 7, 6) >>> G = PermutationGroup([a, b]) Define g: >>> g = Permutation(7)(1, 2, 4)(3, 6, 5) Confirm that it is an element of G: >>> G.contains(g) True Thus, it can be written as a product of factors (up to 3) drawn from u. See below that a factor from u1 and u2 and the Identity permutation have been used: >>> f = G.coset_factor(g) >>> f[2]*f[1]*f[0] == g True >>> f1 = G.coset_factor(g, True); f1 [0, 4, 4] >>> tr = G.basic_transversals >>> f[0] == tr[0][f1[0]] True If g is not an element of G then [] is returned: >>> c = Permutation(5, 6, 7) >>> G.coset_factor(c) [] See Also ======== sympy.combinatorics.util._strip """ if isinstance(g, (Cycle, Permutation)): g = g.list() if len(g) != self._degree: # this could either adjust the size or return [] immediately # but we don't choose between the two and just signal a possible # error raise ValueError('g should be the same size as permutations of G') I = list(range(self._degree)) basic_orbits = self.basic_orbits transversals = self._transversals factors = [] base = self.base h = g for i in range(len(base)): beta = h[base[i]] if beta == base[i]: factors.append(beta) continue if beta not in basic_orbits[i]: return [] u = transversals[i][beta]._array_form h = _af_rmul(_af_invert(u), h) factors.append(beta) if h != I: return [] if factor_index: return factors tr = self.basic_transversals factors = [tr[i][factors[i]] for i in range(len(base))] return factors def generator_product(self, g, original=False): ''' Return a list of strong generators `[s1, ..., sn]` s.t `g = sn*...*s1`. If `original=True`, make the list contain only the original group generators ''' product = [] if g.is_identity: return [] if g in self.strong_gens: if not original or g in self.generators: return [g] else: slp = self._strong_gens_slp[g] for s in slp: product.extend(self.generator_product(s, original=True)) return product elif g**-1 in self.strong_gens: g = g**-1 if not original or g in self.generators: return [g**-1] else: slp = self._strong_gens_slp[g] for s in slp: product.extend(self.generator_product(s, original=True)) l = len(product) product = [product[l-i-1]**-1 for i in range(l)] return product f = self.coset_factor(g, True) for i, j in enumerate(f): slp = self._transversal_slp[i][j] for s in slp: if not original: product.append(self.strong_gens[s]) else: s = self.strong_gens[s] product.extend(self.generator_product(s, original=True)) return product def coset_rank(self, g): """rank using Schreier-Sims representation. Explanation =========== The coset rank of ``g`` is the ordering number in which it appears in the lexicographic listing according to the coset decomposition The ordering is the same as in G.generate(method='coset'). If ``g`` does not belong to the group it returns None. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation(0, 1, 3, 7, 6, 4)(2, 5) >>> b = Permutation(0, 1, 3, 2)(4, 5, 7, 6) >>> G = PermutationGroup([a, b]) >>> c = Permutation(7)(2, 4)(3, 5) >>> G.coset_rank(c) 16 >>> G.coset_unrank(16) (7)(2 4)(3 5) See Also ======== coset_factor """ factors = self.coset_factor(g, True) if not factors: return None rank = 0 b = 1 transversals = self._transversals base = self._base basic_orbits = self._basic_orbits for i in range(len(base)): k = factors[i] j = basic_orbits[i].index(k) rank += b*j b = b*len(transversals[i]) return rank def coset_unrank(self, rank, af=False): """unrank using Schreier-Sims representation coset_unrank is the inverse operation of coset_rank if 0 <= rank < order; otherwise it returns None. """ if rank < 0 or rank >= self.order(): return None base = self.base transversals = self.basic_transversals basic_orbits = self.basic_orbits m = len(base) v = [0]*m for i in range(m): rank, c = divmod(rank, len(transversals[i])) v[i] = basic_orbits[i][c] a = [transversals[i][v[i]]._array_form for i in range(m)] h = _af_rmuln(*a) if af: return h else: return _af_new(h) @property def degree(self): """Returns the size of the permutations in the group. Explanation =========== The number of permutations comprising the group is given by ``len(group)``; the number of permutations that can be generated by the group is given by ``group.order()``. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([1, 0, 2]) >>> G = PermutationGroup([a]) >>> G.degree 3 >>> len(G) 1 >>> G.order() 2 >>> list(G.generate()) [(2), (2)(0 1)] See Also ======== order """ return self._degree @property def identity(self): ''' Return the identity element of the permutation group. ''' return _af_new(list(range(self.degree))) @property def elements(self): """Returns all the elements of the permutation group as a set Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup >>> p = PermutationGroup(Permutation(1, 3), Permutation(1, 2)) >>> p.elements {(1 2 3), (1 3 2), (1 3), (2 3), (3), (3)(1 2)} """ return set(self._elements) @property def _elements(self): """Returns all the elements of the permutation group as a list Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup >>> p = PermutationGroup(Permutation(1, 3), Permutation(1, 2)) >>> p._elements [(3), (3)(1 2), (1 3), (2 3), (1 2 3), (1 3 2)] """ return list(islice(self.generate(), None)) def derived_series(self): r"""Return the derived series for the group. Explanation =========== The derived series for a group `G` is defined as `G = G_0 > G_1 > G_2 > \ldots` where `G_i = [G_{i-1}, G_{i-1}]`, i.e. `G_i` is the derived subgroup of `G_{i-1}`, for `i\in\mathbb{N}`. When we have `G_k = G_{k-1}` for some `k\in\mathbb{N}`, the series terminates. Returns ======= A list of permutation groups containing the members of the derived series in the order `G = G_0, G_1, G_2, \ldots`. Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... AlternatingGroup, DihedralGroup) >>> A = AlternatingGroup(5) >>> len(A.derived_series()) 1 >>> S = SymmetricGroup(4) >>> len(S.derived_series()) 4 >>> S.derived_series()[1].is_subgroup(AlternatingGroup(4)) True >>> S.derived_series()[2].is_subgroup(DihedralGroup(2)) True See Also ======== derived_subgroup """ res = [self] current = self next = self.derived_subgroup() while not current.is_subgroup(next): res.append(next) current = next next = next.derived_subgroup() return res def derived_subgroup(self): r"""Compute the derived subgroup. Explanation =========== The derived subgroup, or commutator subgroup is the subgroup generated by all commutators `[g, h] = hgh^{-1}g^{-1}` for `g, h\in G` ; it is equal to the normal closure of the set of commutators of the generators ([1], p.28, [11]). Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([1, 0, 2, 4, 3]) >>> b = Permutation([0, 1, 3, 2, 4]) >>> G = PermutationGroup([a, b]) >>> C = G.derived_subgroup() >>> list(C.generate(af=True)) [[0, 1, 2, 3, 4], [0, 1, 3, 4, 2], [0, 1, 4, 2, 3]] See Also ======== derived_series """ r = self._r gens = [p._array_form for p in self.generators] set_commutators = set() degree = self._degree rng = list(range(degree)) for i in range(r): for j in range(r): p1 = gens[i] p2 = gens[j] c = list(range(degree)) for k in rng: c[p2[p1[k]]] = p1[p2[k]] ct = tuple(c) if not ct in set_commutators: set_commutators.add(ct) cms = [_af_new(p) for p in set_commutators] G2 = self.normal_closure(cms) return G2 def generate(self, method="coset", af=False): """Return iterator to generate the elements of the group. Explanation =========== Iteration is done with one of these methods:: method='coset' using the Schreier-Sims coset representation method='dimino' using the Dimino method If ``af = True`` it yields the array form of the permutations Examples ======== >>> from sympy.combinatorics import PermutationGroup >>> from sympy.combinatorics.polyhedron import tetrahedron The permutation group given in the tetrahedron object is also true groups: >>> G = tetrahedron.pgroup >>> G.is_group True Also the group generated by the permutations in the tetrahedron pgroup -- even the first two -- is a proper group: >>> H = PermutationGroup(G[0], G[1]) >>> J = PermutationGroup(list(H.generate())); J PermutationGroup([ (0 1)(2 3), (1 2 3), (1 3 2), (0 3 1), (0 2 3), (0 3)(1 2), (0 1 3), (3)(0 2 1), (0 3 2), (3)(0 1 2), (0 2)(1 3)]) >>> _.is_group True """ if method == "coset": return self.generate_schreier_sims(af) elif method == "dimino": return self.generate_dimino(af) else: raise NotImplementedError('No generation defined for %s' % method) def generate_dimino(self, af=False): """Yield group elements using Dimino's algorithm. If ``af == True`` it yields the array form of the permutations. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1, 3]) >>> b = Permutation([0, 2, 3, 1]) >>> g = PermutationGroup([a, b]) >>> list(g.generate_dimino(af=True)) [[0, 1, 2, 3], [0, 2, 1, 3], [0, 2, 3, 1], [0, 1, 3, 2], [0, 3, 2, 1], [0, 3, 1, 2]] References ========== .. [1] The Implementation of Various Algorithms for Permutation Groups in the Computer Algebra System: AXIOM, N.J. Doye, M.Sc. Thesis """ idn = list(range(self.degree)) order = 0 element_list = [idn] set_element_list = {tuple(idn)} if af: yield idn else: yield _af_new(idn) gens = [p._array_form for p in self.generators] for i in range(len(gens)): # D elements of the subgroup G_i generated by gens[:i] D = element_list[:] N = [idn] while N: A = N N = [] for a in A: for g in gens[:i + 1]: ag = _af_rmul(a, g) if tuple(ag) not in set_element_list: # produce G_i*g for d in D: order += 1 ap = _af_rmul(d, ag) if af: yield ap else: p = _af_new(ap) yield p element_list.append(ap) set_element_list.add(tuple(ap)) N.append(ap) self._order = len(element_list) def generate_schreier_sims(self, af=False): """Yield group elements using the Schreier-Sims representation in coset_rank order If ``af = True`` it yields the array form of the permutations Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1, 3]) >>> b = Permutation([0, 2, 3, 1]) >>> g = PermutationGroup([a, b]) >>> list(g.generate_schreier_sims(af=True)) [[0, 1, 2, 3], [0, 2, 1, 3], [0, 3, 2, 1], [0, 1, 3, 2], [0, 2, 3, 1], [0, 3, 1, 2]] """ n = self._degree u = self.basic_transversals basic_orbits = self._basic_orbits if len(u) == 0: for x in self.generators: if af: yield x._array_form else: yield x return if len(u) == 1: for i in basic_orbits[0]: if af: yield u[0][i]._array_form else: yield u[0][i] return u = list(reversed(u)) basic_orbits = basic_orbits[::-1] # stg stack of group elements stg = [list(range(n))] posmax = [len(x) for x in u] n1 = len(posmax) - 1 pos = [0]*n1 h = 0 while 1: # backtrack when finished iterating over coset if pos[h] >= posmax[h]: if h == 0: return pos[h] = 0 h -= 1 stg.pop() continue p = _af_rmul(u[h][basic_orbits[h][pos[h]]]._array_form, stg[-1]) pos[h] += 1 stg.append(p) h += 1 if h == n1: if af: for i in basic_orbits[-1]: p = _af_rmul(u[-1][i]._array_form, stg[-1]) yield p else: for i in basic_orbits[-1]: p = _af_rmul(u[-1][i]._array_form, stg[-1]) p1 = _af_new(p) yield p1 stg.pop() h -= 1 @property def generators(self): """Returns the generators of the group. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G.generators [(1 2), (2)(0 1)] """ return self._generators def contains(self, g, strict=True): """Test if permutation ``g`` belong to self, ``G``. Explanation =========== If ``g`` is an element of ``G`` it can be written as a product of factors drawn from the cosets of ``G``'s stabilizers. To see if ``g`` is one of the actual generators defining the group use ``G.has(g)``. If ``strict`` is not ``True``, ``g`` will be resized, if necessary, to match the size of permutations in ``self``. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation(1, 2) >>> b = Permutation(2, 3, 1) >>> G = PermutationGroup(a, b, degree=5) >>> G.contains(G[0]) # trivial check True >>> elem = Permutation([[2, 3]], size=5) >>> G.contains(elem) True >>> G.contains(Permutation(4)(0, 1, 2, 3)) False If strict is False, a permutation will be resized, if necessary: >>> H = PermutationGroup(Permutation(5)) >>> H.contains(Permutation(3)) False >>> H.contains(Permutation(3), strict=False) True To test if a given permutation is present in the group: >>> elem in G.generators False >>> G.has(elem) False See Also ======== coset_factor, sympy.core.basic.Basic.has, __contains__ """ if not isinstance(g, Permutation): return False if g.size != self.degree: if strict: return False g = Permutation(g, size=self.degree) if g in self.generators: return True return bool(self.coset_factor(g.array_form, True)) @property def is_perfect(self): """Return ``True`` if the group is perfect. A group is perfect if it equals to its derived subgroup. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation(1,2,3)(4,5) >>> b = Permutation(1,2,3,4,5) >>> G = PermutationGroup([a, b]) >>> G.is_perfect False """ if self._is_perfect is None: self._is_perfect = self == self.derived_subgroup() return self._is_perfect @property def is_abelian(self): """Test if the group is Abelian. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G.is_abelian False >>> a = Permutation([0, 2, 1]) >>> G = PermutationGroup([a]) >>> G.is_abelian True """ if self._is_abelian is not None: return self._is_abelian self._is_abelian = True gens = [p._array_form for p in self.generators] for x in gens: for y in gens: if y <= x: continue if not _af_commutes_with(x, y): self._is_abelian = False return False return True def abelian_invariants(self): """ Returns the abelian invariants for the given group. Let ``G`` be a nontrivial finite abelian group. Then G is isomorphic to the direct product of finitely many nontrivial cyclic groups of prime-power order. Explanation =========== The prime-powers that occur as the orders of the factors are uniquely determined by G. More precisely, the primes that occur in the orders of the factors in any such decomposition of ``G`` are exactly the primes that divide ``|G|`` and for any such prime ``p``, if the orders of the factors that are p-groups in one such decomposition of ``G`` are ``p^{t_1} >= p^{t_2} >= ... p^{t_r}``, then the orders of the factors that are p-groups in any such decomposition of ``G`` are ``p^{t_1} >= p^{t_2} >= ... p^{t_r}``. The uniquely determined integers ``p^{t_1} >= p^{t_2} >= ... p^{t_r}``, taken for all primes that divide ``|G|`` are called the invariants of the nontrivial group ``G`` as suggested in ([14], p. 542). Notes ===== We adopt the convention that the invariants of a trivial group are []. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G.abelian_invariants() [2] >>> from sympy.combinatorics.named_groups import CyclicGroup >>> G = CyclicGroup(7) >>> G.abelian_invariants() [7] """ if self.is_trivial: return [] gns = self.generators inv = [] G = self H = G.derived_subgroup() Hgens = H.generators for p in primefactors(G.order()): ranks = [] while True: pows = [] for g in gns: elm = g**p if not H.contains(elm): pows.append(elm) K = PermutationGroup(Hgens + pows) if pows else H r = G.order()//K.order() G = K gns = pows if r == 1: break; ranks.append(multiplicity(p, r)) if ranks: pows = [1]*ranks[0] for i in ranks: for j in range(0, i): pows[j] = pows[j]*p inv.extend(pows) inv.sort() return inv def is_elementary(self, p): """Return ``True`` if the group is elementary abelian. An elementary abelian group is a finite abelian group, where every nontrivial element has order `p`, where `p` is a prime. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1]) >>> G = PermutationGroup([a]) >>> G.is_elementary(2) True >>> a = Permutation([0, 2, 1, 3]) >>> b = Permutation([3, 1, 2, 0]) >>> G = PermutationGroup([a, b]) >>> G.is_elementary(2) True >>> G.is_elementary(3) False """ return self.is_abelian and all(g.order() == p for g in self.generators) def _eval_is_alt_sym_naive(self, only_sym=False, only_alt=False): """A naive test using the group order.""" if only_sym and only_alt: raise ValueError( "Both {} and {} cannot be set to True" .format(only_sym, only_alt)) n = self.degree sym_order = 1 for i in range(2, n+1): sym_order *= i order = self.order() if order == sym_order: self._is_sym = True self._is_alt = False if only_alt: return False return True elif 2*order == sym_order: self._is_sym = False self._is_alt = True if only_sym: return False return True return False def _eval_is_alt_sym_monte_carlo(self, eps=0.05, perms=None): """A test using monte-carlo algorithm. Parameters ========== eps : float, optional The criterion for the incorrect ``False`` return. perms : list[Permutation], optional If explicitly given, it tests over the given candidats for testing. If ``None``, it randomly computes ``N_eps`` and chooses ``N_eps`` sample of the permutation from the group. See Also ======== _check_cycles_alt_sym """ if perms is None: n = self.degree if n < 17: c_n = 0.34 else: c_n = 0.57 d_n = (c_n*log(2))/log(n) N_eps = int(-log(eps)/d_n) perms = (self.random_pr() for i in range(N_eps)) return self._eval_is_alt_sym_monte_carlo(perms=perms) for perm in perms: if _check_cycles_alt_sym(perm): return True return False def is_alt_sym(self, eps=0.05, _random_prec=None): r"""Monte Carlo test for the symmetric/alternating group for degrees >= 8. Explanation =========== More specifically, it is one-sided Monte Carlo with the answer True (i.e., G is symmetric/alternating) guaranteed to be correct, and the answer False being incorrect with probability eps. For degree < 8, the order of the group is checked so the test is deterministic. Notes ===== The algorithm itself uses some nontrivial results from group theory and number theory: 1) If a transitive group ``G`` of degree ``n`` contains an element with a cycle of length ``n/2 < p < n-2`` for ``p`` a prime, ``G`` is the symmetric or alternating group ([1], pp. 81-82) 2) The proportion of elements in the symmetric/alternating group having the property described in 1) is approximately `\log(2)/\log(n)` ([1], p.82; [2], pp. 226-227). The helper function ``_check_cycles_alt_sym`` is used to go over the cycles in a permutation and look for ones satisfying 1). Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> D = DihedralGroup(10) >>> D.is_alt_sym() False See Also ======== _check_cycles_alt_sym """ if _random_prec is not None: N_eps = _random_prec['N_eps'] perms= (_random_prec[i] for i in range(N_eps)) return self._eval_is_alt_sym_monte_carlo(perms=perms) if self._is_sym or self._is_alt: return True if self._is_sym is False and self._is_alt is False: return False n = self.degree if n < 8: return self._eval_is_alt_sym_naive() elif self.is_transitive(): return self._eval_is_alt_sym_monte_carlo(eps=eps) self._is_sym, self._is_alt = False, False return False @property def is_nilpotent(self): """Test if the group is nilpotent. Explanation =========== A group `G` is nilpotent if it has a central series of finite length. Alternatively, `G` is nilpotent if its lower central series terminates with the trivial group. Every nilpotent group is also solvable ([1], p.29, [12]). Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... CyclicGroup) >>> C = CyclicGroup(6) >>> C.is_nilpotent True >>> S = SymmetricGroup(5) >>> S.is_nilpotent False See Also ======== lower_central_series, is_solvable """ if self._is_nilpotent is None: lcs = self.lower_central_series() terminator = lcs[len(lcs) - 1] gens = terminator.generators degree = self.degree identity = _af_new(list(range(degree))) if all(g == identity for g in gens): self._is_solvable = True self._is_nilpotent = True return True else: self._is_nilpotent = False return False else: return self._is_nilpotent def is_normal(self, gr, strict=True): """Test if ``G=self`` is a normal subgroup of ``gr``. Explanation =========== G is normal in gr if for each g2 in G, g1 in gr, ``g = g1*g2*g1**-1`` belongs to G It is sufficient to check this for each g1 in gr.generators and g2 in G.generators. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([1, 2, 0]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G1 = PermutationGroup([a, Permutation([2, 0, 1])]) >>> G1.is_normal(G) True """ if not self.is_subgroup(gr, strict=strict): return False d_self = self.degree d_gr = gr.degree if self.is_trivial and (d_self == d_gr or not strict): return True if self._is_abelian: return True new_self = self.copy() if not strict and d_self != d_gr: if d_self < d_gr: new_self = PermGroup(new_self.generators + [Permutation(d_gr - 1)]) else: gr = PermGroup(gr.generators + [Permutation(d_self - 1)]) gens2 = [p._array_form for p in new_self.generators] gens1 = [p._array_form for p in gr.generators] for g1 in gens1: for g2 in gens2: p = _af_rmuln(g1, g2, _af_invert(g1)) if not new_self.coset_factor(p, True): return False return True def is_primitive(self, randomized=True): r"""Test if a group is primitive. Explanation =========== A permutation group ``G`` acting on a set ``S`` is called primitive if ``S`` contains no nontrivial block under the action of ``G`` (a block is nontrivial if its cardinality is more than ``1``). Notes ===== The algorithm is described in [1], p.83, and uses the function minimal_block to search for blocks of the form `\{0, k\}` for ``k`` ranging over representatives for the orbits of `G_0`, the stabilizer of ``0``. This algorithm has complexity `O(n^2)` where ``n`` is the degree of the group, and will perform badly if `G_0` is small. There are two implementations offered: one finds `G_0` deterministically using the function ``stabilizer``, and the other (default) produces random elements of `G_0` using ``random_stab``, hoping that they generate a subgroup of `G_0` with not too many more orbits than `G_0` (this is suggested in [1], p.83). Behavior is changed by the ``randomized`` flag. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> D = DihedralGroup(10) >>> D.is_primitive() False See Also ======== minimal_block, random_stab """ if self._is_primitive is not None: return self._is_primitive if self.is_transitive() is False: return False if randomized: random_stab_gens = [] v = self.schreier_vector(0) for i in range(len(self)): random_stab_gens.append(self.random_stab(0, v)) stab = PermutationGroup(random_stab_gens) else: stab = self.stabilizer(0) orbits = stab.orbits() for orb in orbits: x = orb.pop() if x != 0 and any(e != 0 for e in self.minimal_block([0, x])): self._is_primitive = False return False self._is_primitive = True return True def minimal_blocks(self, randomized=True): ''' For a transitive group, return the list of all minimal block systems. If a group is intransitive, return `False`. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics.named_groups import DihedralGroup >>> DihedralGroup(6).minimal_blocks() [[0, 1, 0, 1, 0, 1], [0, 1, 2, 0, 1, 2]] >>> G = PermutationGroup(Permutation(1,2,5)) >>> G.minimal_blocks() False See Also ======== minimal_block, is_transitive, is_primitive ''' def _number_blocks(blocks): # number the blocks of a block system # in order and return the number of # blocks and the tuple with the # reordering n = len(blocks) appeared = {} m = 0 b = [None]*n for i in range(n): if blocks[i] not in appeared: appeared[blocks[i]] = m b[i] = m m += 1 else: b[i] = appeared[blocks[i]] return tuple(b), m if not self.is_transitive(): return False blocks = [] num_blocks = [] rep_blocks = [] if randomized: random_stab_gens = [] v = self.schreier_vector(0) for i in range(len(self)): random_stab_gens.append(self.random_stab(0, v)) stab = PermutationGroup(random_stab_gens) else: stab = self.stabilizer(0) orbits = stab.orbits() for orb in orbits: x = orb.pop() if x != 0: block = self.minimal_block([0, x]) num_block, m = _number_blocks(block) # a representative block (containing 0) rep = {j for j in range(self.degree) if num_block[j] == 0} # check if the system is minimal with # respect to the already discovere ones minimal = True blocks_remove_mask = [False] * len(blocks) for i, r in enumerate(rep_blocks): if len(r) > len(rep) and rep.issubset(r): # i-th block system is not minimal blocks_remove_mask[i] = True elif len(r) < len(rep) and r.issubset(rep): # the system being checked is not minimal minimal = False break # remove non-minimal representative blocks blocks = [b for i, b in enumerate(blocks) if not blocks_remove_mask[i]] num_blocks = [n for i, n in enumerate(num_blocks) if not blocks_remove_mask[i]] rep_blocks = [r for i, r in enumerate(rep_blocks) if not blocks_remove_mask[i]] if minimal and num_block not in num_blocks: blocks.append(block) num_blocks.append(num_block) rep_blocks.append(rep) return blocks @property def is_solvable(self): """Test if the group is solvable. ``G`` is solvable if its derived series terminates with the trivial group ([1], p.29). Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> S = SymmetricGroup(3) >>> S.is_solvable True See Also ======== is_nilpotent, derived_series """ if self._is_solvable is None: if self.order() % 2 != 0: return True ds = self.derived_series() terminator = ds[len(ds) - 1] gens = terminator.generators degree = self.degree identity = _af_new(list(range(degree))) if all(g == identity for g in gens): self._is_solvable = True return True else: self._is_solvable = False return False else: return self._is_solvable def is_subgroup(self, G, strict=True): """Return ``True`` if all elements of ``self`` belong to ``G``. If ``strict`` is ``False`` then if ``self``'s degree is smaller than ``G``'s, the elements will be resized to have the same degree. Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... CyclicGroup) Testing is strict by default: the degree of each group must be the same: >>> p = Permutation(0, 1, 2, 3, 4, 5) >>> G1 = PermutationGroup([Permutation(0, 1, 2), Permutation(0, 1)]) >>> G2 = PermutationGroup([Permutation(0, 2), Permutation(0, 1, 2)]) >>> G3 = PermutationGroup([p, p**2]) >>> assert G1.order() == G2.order() == G3.order() == 6 >>> G1.is_subgroup(G2) True >>> G1.is_subgroup(G3) False >>> G3.is_subgroup(PermutationGroup(G3[1])) False >>> G3.is_subgroup(PermutationGroup(G3[0])) True To ignore the size, set ``strict`` to ``False``: >>> S3 = SymmetricGroup(3) >>> S5 = SymmetricGroup(5) >>> S3.is_subgroup(S5, strict=False) True >>> C7 = CyclicGroup(7) >>> G = S5*C7 >>> S5.is_subgroup(G, False) True >>> C7.is_subgroup(G, 0) False """ if isinstance(G, SymmetricPermutationGroup): if self.degree != G.degree: return False return True if not isinstance(G, PermutationGroup): return False if self == G or self.generators[0]==Permutation(): return True if G.order() % self.order() != 0: return False if self.degree == G.degree or \ (self.degree < G.degree and not strict): gens = self.generators else: return False return all(G.contains(g, strict=strict) for g in gens) @property def is_polycyclic(self): """Return ``True`` if a group is polycyclic. A group is polycyclic if it has a subnormal series with cyclic factors. For finite groups, this is the same as if the group is solvable. Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup >>> a = Permutation([0, 2, 1, 3]) >>> b = Permutation([2, 0, 1, 3]) >>> G = PermutationGroup([a, b]) >>> G.is_polycyclic True """ return self.is_solvable def is_transitive(self, strict=True): """Test if the group is transitive. Explanation =========== A group is transitive if it has a single orbit. If ``strict`` is ``False`` the group is transitive if it has a single orbit of length different from 1. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1, 3]) >>> b = Permutation([2, 0, 1, 3]) >>> G1 = PermutationGroup([a, b]) >>> G1.is_transitive() False >>> G1.is_transitive(strict=False) True >>> c = Permutation([2, 3, 0, 1]) >>> G2 = PermutationGroup([a, c]) >>> G2.is_transitive() True >>> d = Permutation([1, 0, 2, 3]) >>> e = Permutation([0, 1, 3, 2]) >>> G3 = PermutationGroup([d, e]) >>> G3.is_transitive() or G3.is_transitive(strict=False) False """ if self._is_transitive: # strict or not, if True then True return self._is_transitive if strict: if self._is_transitive is not None: # we only store strict=True return self._is_transitive ans = len(self.orbit(0)) == self.degree self._is_transitive = ans return ans got_orb = False for x in self.orbits(): if len(x) > 1: if got_orb: return False got_orb = True return got_orb @property def is_trivial(self): """Test if the group is the trivial group. This is true if the group contains only the identity permutation. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> G = PermutationGroup([Permutation([0, 1, 2])]) >>> G.is_trivial True """ if self._is_trivial is None: self._is_trivial = len(self) == 1 and self[0].is_Identity return self._is_trivial def lower_central_series(self): r"""Return the lower central series for the group. The lower central series for a group `G` is the series `G = G_0 > G_1 > G_2 > \ldots` where `G_k = [G, G_{k-1}]`, i.e. every term after the first is equal to the commutator of `G` and the previous term in `G1` ([1], p.29). Returns ======= A list of permutation groups in the order `G = G_0, G_1, G_2, \ldots` Examples ======== >>> from sympy.combinatorics.named_groups import (AlternatingGroup, ... DihedralGroup) >>> A = AlternatingGroup(4) >>> len(A.lower_central_series()) 2 >>> A.lower_central_series()[1].is_subgroup(DihedralGroup(2)) True See Also ======== commutator, derived_series """ res = [self] current = self next = self.commutator(self, current) while not current.is_subgroup(next): res.append(next) current = next next = self.commutator(self, current) return res @property def max_div(self): """Maximum proper divisor of the degree of a permutation group. Explanation =========== Obviously, this is the degree divided by its minimal proper divisor (larger than ``1``, if one exists). As it is guaranteed to be prime, the ``sieve`` from ``sympy.ntheory`` is used. This function is also used as an optimization tool for the functions ``minimal_block`` and ``_union_find_merge``. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> G = PermutationGroup([Permutation([0, 2, 1, 3])]) >>> G.max_div 2 See Also ======== minimal_block, _union_find_merge """ if self._max_div is not None: return self._max_div n = self.degree if n == 1: return 1 for x in sieve: if n % x == 0: d = n//x self._max_div = d return d def minimal_block(self, points): r"""For a transitive group, finds the block system generated by ``points``. Explanation =========== If a group ``G`` acts on a set ``S``, a nonempty subset ``B`` of ``S`` is called a block under the action of ``G`` if for all ``g`` in ``G`` we have ``gB = B`` (``g`` fixes ``B``) or ``gB`` and ``B`` have no common points (``g`` moves ``B`` entirely). ([1], p.23; [6]). The distinct translates ``gB`` of a block ``B`` for ``g`` in ``G`` partition the set ``S`` and this set of translates is known as a block system. Moreover, we obviously have that all blocks in the partition have the same size, hence the block size divides ``|S|`` ([1], p.23). A ``G``-congruence is an equivalence relation ``~`` on the set ``S`` such that ``a ~ b`` implies ``g(a) ~ g(b)`` for all ``g`` in ``G``. For a transitive group, the equivalence classes of a ``G``-congruence and the blocks of a block system are the same thing ([1], p.23). The algorithm below checks the group for transitivity, and then finds the ``G``-congruence generated by the pairs ``(p_0, p_1), (p_0, p_2), ..., (p_0,p_{k-1})`` which is the same as finding the maximal block system (i.e., the one with minimum block size) such that ``p_0, ..., p_{k-1}`` are in the same block ([1], p.83). It is an implementation of Atkinson's algorithm, as suggested in [1], and manipulates an equivalence relation on the set ``S`` using a union-find data structure. The running time is just above `O(|points||S|)`. ([1], pp. 83-87; [7]). Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> D = DihedralGroup(10) >>> D.minimal_block([0, 5]) [0, 1, 2, 3, 4, 0, 1, 2, 3, 4] >>> D.minimal_block([0, 1]) [0, 0, 0, 0, 0, 0, 0, 0, 0, 0] See Also ======== _union_find_rep, _union_find_merge, is_transitive, is_primitive """ if not self.is_transitive(): return False n = self.degree gens = self.generators # initialize the list of equivalence class representatives parents = list(range(n)) ranks = [1]*n not_rep = [] k = len(points) # the block size must divide the degree of the group if k > self.max_div: return [0]*n for i in range(k - 1): parents[points[i + 1]] = points[0] not_rep.append(points[i + 1]) ranks[points[0]] = k i = 0 len_not_rep = k - 1 while i < len_not_rep: gamma = not_rep[i] i += 1 for gen in gens: # find has side effects: performs path compression on the list # of representatives delta = self._union_find_rep(gamma, parents) # union has side effects: performs union by rank on the list # of representatives temp = self._union_find_merge(gen(gamma), gen(delta), ranks, parents, not_rep) if temp == -1: return [0]*n len_not_rep += temp for i in range(n): # force path compression to get the final state of the equivalence # relation self._union_find_rep(i, parents) # rewrite result so that block representatives are minimal new_reps = {} return [new_reps.setdefault(r, i) for i, r in enumerate(parents)] def conjugacy_class(self, x): r"""Return the conjugacy class of an element in the group. Explanation =========== The conjugacy class of an element ``g`` in a group ``G`` is the set of elements ``x`` in ``G`` that are conjugate with ``g``, i.e. for which ``g = xax^{-1}`` for some ``a`` in ``G``. Note that conjugacy is an equivalence relation, and therefore that conjugacy classes are partitions of ``G``. For a list of all the conjugacy classes of the group, use the conjugacy_classes() method. In a permutation group, each conjugacy class corresponds to a particular `cycle structure': for example, in ``S_3``, the conjugacy classes are: * the identity class, ``{()}`` * all transpositions, ``{(1 2), (1 3), (2 3)}`` * all 3-cycles, ``{(1 2 3), (1 3 2)}`` Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> S3 = SymmetricGroup(3) >>> S3.conjugacy_class(Permutation(0, 1, 2)) {(0 1 2), (0 2 1)} Notes ===== This procedure computes the conjugacy class directly by finding the orbit of the element under conjugation in G. This algorithm is only feasible for permutation groups of relatively small order, but is like the orbit() function itself in that respect. """ # Ref: "Computing the conjugacy classes of finite groups"; Butler, G. # Groups '93 Galway/St Andrews; edited by Campbell, C. M. new_class = {x} last_iteration = new_class while len(last_iteration) > 0: this_iteration = set() for y in last_iteration: for s in self.generators: conjugated = s * y * (~s) if conjugated not in new_class: this_iteration.add(conjugated) new_class.update(last_iteration) last_iteration = this_iteration return new_class def conjugacy_classes(self): r"""Return the conjugacy classes of the group. Explanation =========== As described in the documentation for the .conjugacy_class() function, conjugacy is an equivalence relation on a group G which partitions the set of elements. This method returns a list of all these conjugacy classes of G. Examples ======== >>> from sympy.combinatorics import SymmetricGroup >>> SymmetricGroup(3).conjugacy_classes() [{(2)}, {(0 1 2), (0 2 1)}, {(0 2), (1 2), (2)(0 1)}] """ identity = _af_new(list(range(self.degree))) known_elements = {identity} classes = [known_elements.copy()] for x in self.generate(): if x not in known_elements: new_class = self.conjugacy_class(x) classes.append(new_class) known_elements.update(new_class) return classes def normal_closure(self, other, k=10): r"""Return the normal closure of a subgroup/set of permutations. Explanation =========== If ``S`` is a subset of a group ``G``, the normal closure of ``A`` in ``G`` is defined as the intersection of all normal subgroups of ``G`` that contain ``A`` ([1], p.14). Alternatively, it is the group generated by the conjugates ``x^{-1}yx`` for ``x`` a generator of ``G`` and ``y`` a generator of the subgroup ``\left\langle S\right\rangle`` generated by ``S`` (for some chosen generating set for ``\left\langle S\right\rangle``) ([1], p.73). Parameters ========== other a subgroup/list of permutations/single permutation k an implementation-specific parameter that determines the number of conjugates that are adjoined to ``other`` at once Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... CyclicGroup, AlternatingGroup) >>> S = SymmetricGroup(5) >>> C = CyclicGroup(5) >>> G = S.normal_closure(C) >>> G.order() 60 >>> G.is_subgroup(AlternatingGroup(5)) True See Also ======== commutator, derived_subgroup, random_pr Notes ===== The algorithm is described in [1], pp. 73-74; it makes use of the generation of random elements for permutation groups by the product replacement algorithm. """ if hasattr(other, 'generators'): degree = self.degree identity = _af_new(list(range(degree))) if all(g == identity for g in other.generators): return other Z = PermutationGroup(other.generators[:]) base, strong_gens = Z.schreier_sims_incremental() strong_gens_distr = _distribute_gens_by_base(base, strong_gens) basic_orbits, basic_transversals = \ _orbits_transversals_from_bsgs(base, strong_gens_distr) self._random_pr_init(r=10, n=20) _loop = True while _loop: Z._random_pr_init(r=10, n=10) for i in range(k): g = self.random_pr() h = Z.random_pr() conj = h^g res = _strip(conj, base, basic_orbits, basic_transversals) if res[0] != identity or res[1] != len(base) + 1: gens = Z.generators gens.append(conj) Z = PermutationGroup(gens) strong_gens.append(conj) temp_base, temp_strong_gens = \ Z.schreier_sims_incremental(base, strong_gens) base, strong_gens = temp_base, temp_strong_gens strong_gens_distr = \ _distribute_gens_by_base(base, strong_gens) basic_orbits, basic_transversals = \ _orbits_transversals_from_bsgs(base, strong_gens_distr) _loop = False for g in self.generators: for h in Z.generators: conj = h^g res = _strip(conj, base, basic_orbits, basic_transversals) if res[0] != identity or res[1] != len(base) + 1: _loop = True break if _loop: break return Z elif hasattr(other, '__getitem__'): return self.normal_closure(PermutationGroup(other)) elif hasattr(other, 'array_form'): return self.normal_closure(PermutationGroup([other])) def orbit(self, alpha, action='tuples'): r"""Compute the orbit of alpha `\{g(\alpha) | g \in G\}` as a set. Explanation =========== The time complexity of the algorithm used here is `O(|Orb|*r)` where `|Orb|` is the size of the orbit and ``r`` is the number of generators of the group. For a more detailed analysis, see [1], p.78, [2], pp. 19-21. Here alpha can be a single point, or a list of points. If alpha is a single point, the ordinary orbit is computed. if alpha is a list of points, there are three available options: 'union' - computes the union of the orbits of the points in the list 'tuples' - computes the orbit of the list interpreted as an ordered tuple under the group action ( i.e., g((1,2,3)) = (g(1), g(2), g(3)) ) 'sets' - computes the orbit of the list interpreted as a sets Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([1, 2, 0, 4, 5, 6, 3]) >>> G = PermutationGroup([a]) >>> G.orbit(0) {0, 1, 2} >>> G.orbit([0, 4], 'union') {0, 1, 2, 3, 4, 5, 6} See Also ======== orbit_transversal """ return _orbit(self.degree, self.generators, alpha, action) def orbit_rep(self, alpha, beta, schreier_vector=None): """Return a group element which sends ``alpha`` to ``beta``. Explanation =========== If ``beta`` is not in the orbit of ``alpha``, the function returns ``False``. This implementation makes use of the schreier vector. For a proof of correctness, see [1], p.80 Examples ======== >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> G = AlternatingGroup(5) >>> G.orbit_rep(0, 4) (0 4 1 2 3) See Also ======== schreier_vector """ if schreier_vector is None: schreier_vector = self.schreier_vector(alpha) if schreier_vector[beta] is None: return False k = schreier_vector[beta] gens = [x._array_form for x in self.generators] a = [] while k != -1: a.append(gens[k]) beta = gens[k].index(beta) # beta = (~gens[k])(beta) k = schreier_vector[beta] if a: return _af_new(_af_rmuln(*a)) else: return _af_new(list(range(self._degree))) def orbit_transversal(self, alpha, pairs=False): r"""Computes a transversal for the orbit of ``alpha`` as a set. Explanation =========== For a permutation group `G`, a transversal for the orbit `Orb = \{g(\alpha) | g \in G\}` is a set `\{g_\beta | g_\beta(\alpha) = \beta\}` for `\beta \in Orb`. Note that there may be more than one possible transversal. If ``pairs`` is set to ``True``, it returns the list of pairs `(\beta, g_\beta)`. For a proof of correctness, see [1], p.79 Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> G = DihedralGroup(6) >>> G.orbit_transversal(0) [(5), (0 1 2 3 4 5), (0 5)(1 4)(2 3), (0 2 4)(1 3 5), (5)(0 4)(1 3), (0 3)(1 4)(2 5)] See Also ======== orbit """ return _orbit_transversal(self._degree, self.generators, alpha, pairs) def orbits(self, rep=False): """Return the orbits of ``self``, ordered according to lowest element in each orbit. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation(1, 5)(2, 3)(4, 0, 6) >>> b = Permutation(1, 5)(3, 4)(2, 6, 0) >>> G = PermutationGroup([a, b]) >>> G.orbits() [{0, 2, 3, 4, 6}, {1, 5}] """ return _orbits(self._degree, self._generators) def order(self): """Return the order of the group: the number of permutations that can be generated from elements of the group. The number of permutations comprising the group is given by ``len(group)``; the length of each permutation in the group is given by ``group.size``. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([1, 0, 2]) >>> G = PermutationGroup([a]) >>> G.degree 3 >>> len(G) 1 >>> G.order() 2 >>> list(G.generate()) [(2), (2)(0 1)] >>> a = Permutation([0, 2, 1]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G.order() 6 See Also ======== degree """ if self._order is not None: return self._order if self._is_sym: n = self._degree self._order = factorial(n) return self._order if self._is_alt: n = self._degree self._order = factorial(n)/2 return self._order basic_transversals = self.basic_transversals m = 1 for x in basic_transversals: m *= len(x) self._order = m return m def index(self, H): """ Returns the index of a permutation group. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation(1,2,3) >>> b =Permutation(3) >>> G = PermutationGroup([a]) >>> H = PermutationGroup([b]) >>> G.index(H) 3 """ if H.is_subgroup(self): return self.order()//H.order() @property def is_symmetric(self): """Return ``True`` if the group is symmetric. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> g = SymmetricGroup(5) >>> g.is_symmetric True >>> from sympy.combinatorics import Permutation, PermutationGroup >>> g = PermutationGroup( ... Permutation(0, 1, 2, 3, 4), ... Permutation(2, 3)) >>> g.is_symmetric True Notes ===== This uses a naive test involving the computation of the full group order. If you need more quicker taxonomy for large groups, you can use :meth:`PermutationGroup.is_alt_sym`. However, :meth:`PermutationGroup.is_alt_sym` may not be accurate and is not able to distinguish between an alternating group and a symmetric group. See Also ======== is_alt_sym """ _is_sym = self._is_sym if _is_sym is not None: return _is_sym n = self.degree if n >= 8: if self.is_transitive(): _is_alt_sym = self._eval_is_alt_sym_monte_carlo() if _is_alt_sym: if any(g.is_odd for g in self.generators): self._is_sym, self._is_alt = True, False return True self._is_sym, self._is_alt = False, True return False return self._eval_is_alt_sym_naive(only_sym=True) self._is_sym, self._is_alt = False, False return False return self._eval_is_alt_sym_naive(only_sym=True) @property def is_alternating(self): """Return ``True`` if the group is alternating. Examples ======== >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> g = AlternatingGroup(5) >>> g.is_alternating True >>> from sympy.combinatorics import Permutation, PermutationGroup >>> g = PermutationGroup( ... Permutation(0, 1, 2, 3, 4), ... Permutation(2, 3, 4)) >>> g.is_alternating True Notes ===== This uses a naive test involving the computation of the full group order. If you need more quicker taxonomy for large groups, you can use :meth:`PermutationGroup.is_alt_sym`. However, :meth:`PermutationGroup.is_alt_sym` may not be accurate and is not able to distinguish between an alternating group and a symmetric group. See Also ======== is_alt_sym """ _is_alt = self._is_alt if _is_alt is not None: return _is_alt n = self.degree if n >= 8: if self.is_transitive(): _is_alt_sym = self._eval_is_alt_sym_monte_carlo() if _is_alt_sym: if all(g.is_even for g in self.generators): self._is_sym, self._is_alt = False, True return True self._is_sym, self._is_alt = True, False return False return self._eval_is_alt_sym_naive(only_alt=True) self._is_sym, self._is_alt = False, False return False return self._eval_is_alt_sym_naive(only_alt=True) @classmethod def _distinct_primes_lemma(cls, primes): """Subroutine to test if there is only one cyclic group for the order.""" primes = sorted(primes) l = len(primes) for i in range(l): for j in range(i+1, l): if primes[j] % primes[i] == 1: return None return True @property def is_cyclic(self): r""" Return ``True`` if the group is Cyclic. Examples ======== >>> from sympy.combinatorics.named_groups import AbelianGroup >>> G = AbelianGroup(3, 4) >>> G.is_cyclic True >>> G = AbelianGroup(4, 4) >>> G.is_cyclic False Notes ===== If the order of a group $n$ can be factored into the distinct primes $p_1, p_2, ... , p_s$ and if .. math:: \forall i, j \in \{1, 2, \ldots, s \}: p_i \not \equiv 1 \pmod {p_j} holds true, there is only one group of the order $n$ which is a cyclic group. [1]_ This is a generalization of the lemma that the group of order $15, 35, ...$ are cyclic. And also, these additional lemmas can be used to test if a group is cyclic if the order of the group is already found. - If the group is abelian and the order of the group is square-free, the group is cyclic. - If the order of the group is less than $6$ and is not $4$, the group is cyclic. - If the order of the group is prime, the group is cyclic. References ========== .. [1] 1978: John S. Rose: A Course on Group Theory, Introduction to Finite Group Theory: 1.4 """ if self._is_cyclic is not None: return self._is_cyclic if len(self.generators) == 1: self._is_cyclic = True self._is_abelian = True return True if self._is_abelian is False: self._is_cyclic = False return False order = self.order() if order < 6: self._is_abelian == True if order != 4: self._is_cyclic == True return True factors = factorint(order) if all(v == 1 for v in factors.values()): if self._is_abelian: self._is_cyclic = True return True primes = list(factors.keys()) if PermutationGroup._distinct_primes_lemma(primes) is True: self._is_cyclic = True self._is_abelian = True return True for p in factors: pgens = [] for g in self.generators: pgens.append(g**p) if self.index(self.subgroup(pgens)) != p: self._is_cyclic = False return False self._is_cyclic = True self._is_abelian = True return True def pointwise_stabilizer(self, points, incremental=True): r"""Return the pointwise stabilizer for a set of points. Explanation =========== For a permutation group `G` and a set of points `\{p_1, p_2,\ldots, p_k\}`, the pointwise stabilizer of `p_1, p_2, \ldots, p_k` is defined as `G_{p_1,\ldots, p_k} = \{g\in G | g(p_i) = p_i \forall i\in\{1, 2,\ldots,k\}\}` ([1],p20). It is a subgroup of `G`. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> S = SymmetricGroup(7) >>> Stab = S.pointwise_stabilizer([2, 3, 5]) >>> Stab.is_subgroup(S.stabilizer(2).stabilizer(3).stabilizer(5)) True See Also ======== stabilizer, schreier_sims_incremental Notes ===== When incremental == True, rather than the obvious implementation using successive calls to ``.stabilizer()``, this uses the incremental Schreier-Sims algorithm to obtain a base with starting segment - the given points. """ if incremental: base, strong_gens = self.schreier_sims_incremental(base=points) stab_gens = [] degree = self.degree for gen in strong_gens: if [gen(point) for point in points] == points: stab_gens.append(gen) if not stab_gens: stab_gens = _af_new(list(range(degree))) return PermutationGroup(stab_gens) else: gens = self._generators degree = self.degree for x in points: gens = _stabilizer(degree, gens, x) return PermutationGroup(gens) def make_perm(self, n, seed=None): """ Multiply ``n`` randomly selected permutations from pgroup together, starting with the identity permutation. If ``n`` is a list of integers, those integers will be used to select the permutations and they will be applied in L to R order: make_perm((A, B, C)) will give CBA(I) where I is the identity permutation. ``seed`` is used to set the seed for the random selection of permutations from pgroup. If this is a list of integers, the corresponding permutations from pgroup will be selected in the order give. This is mainly used for testing purposes. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a, b = [Permutation([1, 0, 3, 2]), Permutation([1, 3, 0, 2])] >>> G = PermutationGroup([a, b]) >>> G.make_perm(1, [0]) (0 1)(2 3) >>> G.make_perm(3, [0, 1, 0]) (0 2 3 1) >>> G.make_perm([0, 1, 0]) (0 2 3 1) See Also ======== random """ if is_sequence(n): if seed is not None: raise ValueError('If n is a sequence, seed should be None') n, seed = len(n), n else: try: n = int(n) except TypeError: raise ValueError('n must be an integer or a sequence.') randrange = _randrange(seed) # start with the identity permutation result = Permutation(list(range(self.degree))) m = len(self) for i in range(n): p = self[randrange(m)] result = rmul(result, p) return result def random(self, af=False): """Return a random group element """ rank = randrange(self.order()) return self.coset_unrank(rank, af) def random_pr(self, gen_count=11, iterations=50, _random_prec=None): """Return a random group element using product replacement. Explanation =========== For the details of the product replacement algorithm, see ``_random_pr_init`` In ``random_pr`` the actual 'product replacement' is performed. Notice that if the attribute ``_random_gens`` is empty, it needs to be initialized by ``_random_pr_init``. See Also ======== _random_pr_init """ if self._random_gens == []: self._random_pr_init(gen_count, iterations) random_gens = self._random_gens r = len(random_gens) - 1 # handle randomized input for testing purposes if _random_prec is None: s = randrange(r) t = randrange(r - 1) if t == s: t = r - 1 x = choice([1, 2]) e = choice([-1, 1]) else: s = _random_prec['s'] t = _random_prec['t'] if t == s: t = r - 1 x = _random_prec['x'] e = _random_prec['e'] if x == 1: random_gens[s] = _af_rmul(random_gens[s], _af_pow(random_gens[t], e)) random_gens[r] = _af_rmul(random_gens[r], random_gens[s]) else: random_gens[s] = _af_rmul(_af_pow(random_gens[t], e), random_gens[s]) random_gens[r] = _af_rmul(random_gens[s], random_gens[r]) return _af_new(random_gens[r]) def random_stab(self, alpha, schreier_vector=None, _random_prec=None): """Random element from the stabilizer of ``alpha``. The schreier vector for ``alpha`` is an optional argument used for speeding up repeated calls. The algorithm is described in [1], p.81 See Also ======== random_pr, orbit_rep """ if schreier_vector is None: schreier_vector = self.schreier_vector(alpha) if _random_prec is None: rand = self.random_pr() else: rand = _random_prec['rand'] beta = rand(alpha) h = self.orbit_rep(alpha, beta, schreier_vector) return rmul(~h, rand) def schreier_sims(self): """Schreier-Sims algorithm. Explanation =========== It computes the generators of the chain of stabilizers `G > G_{b_1} > .. > G_{b1,..,b_r} > 1` in which `G_{b_1,..,b_i}` stabilizes `b_1,..,b_i`, and the corresponding ``s`` cosets. An element of the group can be written as the product `h_1*..*h_s`. We use the incremental Schreier-Sims algorithm. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> a = Permutation([0, 2, 1]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G.schreier_sims() >>> G.basic_transversals [{0: (2)(0 1), 1: (2), 2: (1 2)}, {0: (2), 2: (0 2)}] """ if self._transversals: return self._schreier_sims() return def _schreier_sims(self, base=None): schreier = self.schreier_sims_incremental(base=base, slp_dict=True) base, strong_gens = schreier[:2] self._base = base self._strong_gens = strong_gens self._strong_gens_slp = schreier[2] if not base: self._transversals = [] self._basic_orbits = [] return strong_gens_distr = _distribute_gens_by_base(base, strong_gens) basic_orbits, transversals, slps = _orbits_transversals_from_bsgs(base,\ strong_gens_distr, slp=True) # rewrite the indices stored in slps in terms of strong_gens for i, slp in enumerate(slps): gens = strong_gens_distr[i] for k in slp: slp[k] = [strong_gens.index(gens[s]) for s in slp[k]] self._transversals = transversals self._basic_orbits = [sorted(x) for x in basic_orbits] self._transversal_slp = slps def schreier_sims_incremental(self, base=None, gens=None, slp_dict=False): """Extend a sequence of points and generating set to a base and strong generating set. Parameters ========== base The sequence of points to be extended to a base. Optional parameter with default value ``[]``. gens The generating set to be extended to a strong generating set relative to the base obtained. Optional parameter with default value ``self.generators``. slp_dict If `True`, return a dictionary `{g: gens}` for each strong generator `g` where `gens` is a list of strong generators coming before `g` in `strong_gens`, such that the product of the elements of `gens` is equal to `g`. Returns ======= (base, strong_gens) ``base`` is the base obtained, and ``strong_gens`` is the strong generating set relative to it. The original parameters ``base``, ``gens`` remain unchanged. Examples ======== >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> from sympy.combinatorics.testutil import _verify_bsgs >>> A = AlternatingGroup(7) >>> base = [2, 3] >>> seq = [2, 3] >>> base, strong_gens = A.schreier_sims_incremental(base=seq) >>> _verify_bsgs(A, base, strong_gens) True >>> base[:2] [2, 3] Notes ===== This version of the Schreier-Sims algorithm runs in polynomial time. There are certain assumptions in the implementation - if the trivial group is provided, ``base`` and ``gens`` are returned immediately, as any sequence of points is a base for the trivial group. If the identity is present in the generators ``gens``, it is removed as it is a redundant generator. The implementation is described in [1], pp. 90-93. See Also ======== schreier_sims, schreier_sims_random """ if base is None: base = [] if gens is None: gens = self.generators[:] degree = self.degree id_af = list(range(degree)) # handle the trivial group if len(gens) == 1 and gens[0].is_Identity: if slp_dict: return base, gens, {gens[0]: [gens[0]]} return base, gens # prevent side effects _base, _gens = base[:], gens[:] # remove the identity as a generator _gens = [x for x in _gens if not x.is_Identity] # make sure no generator fixes all base points for gen in _gens: if all(x == gen._array_form[x] for x in _base): for new in id_af: if gen._array_form[new] != new: break else: assert None # can this ever happen? _base.append(new) # distribute generators according to basic stabilizers strong_gens_distr = _distribute_gens_by_base(_base, _gens) strong_gens_slp = [] # initialize the basic stabilizers, basic orbits and basic transversals orbs = {} transversals = {} slps = {} base_len = len(_base) for i in range(base_len): transversals[i], slps[i] = _orbit_transversal(degree, strong_gens_distr[i], _base[i], pairs=True, af=True, slp=True) transversals[i] = dict(transversals[i]) orbs[i] = list(transversals[i].keys()) # main loop: amend the stabilizer chain until we have generators # for all stabilizers i = base_len - 1 while i >= 0: # this flag is used to continue with the main loop from inside # a nested loop continue_i = False # test the generators for being a strong generating set db = {} for beta, u_beta in list(transversals[i].items()): for j, gen in enumerate(strong_gens_distr[i]): gb = gen._array_form[beta] u1 = transversals[i][gb] g1 = _af_rmul(gen._array_form, u_beta) slp = [(i, g) for g in slps[i][beta]] slp = [(i, j)] + slp if g1 != u1: # test if the schreier generator is in the i+1-th # would-be basic stabilizer y = True try: u1_inv = db[gb] except KeyError: u1_inv = db[gb] = _af_invert(u1) schreier_gen = _af_rmul(u1_inv, g1) u1_inv_slp = slps[i][gb][:] u1_inv_slp.reverse() u1_inv_slp = [(i, (g,)) for g in u1_inv_slp] slp = u1_inv_slp + slp h, j, slp = _strip_af(schreier_gen, _base, orbs, transversals, i, slp=slp, slps=slps) if j <= base_len: # new strong generator h at level j y = False elif h: # h fixes all base points y = False moved = 0 while h[moved] == moved: moved += 1 _base.append(moved) base_len += 1 strong_gens_distr.append([]) if y is False: # if a new strong generator is found, update the # data structures and start over h = _af_new(h) strong_gens_slp.append((h, slp)) for l in range(i + 1, j): strong_gens_distr[l].append(h) transversals[l], slps[l] =\ _orbit_transversal(degree, strong_gens_distr[l], _base[l], pairs=True, af=True, slp=True) transversals[l] = dict(transversals[l]) orbs[l] = list(transversals[l].keys()) i = j - 1 # continue main loop using the flag continue_i = True if continue_i is True: break if continue_i is True: break if continue_i is True: continue i -= 1 strong_gens = _gens[:] if slp_dict: # create the list of the strong generators strong_gens and # rewrite the indices of strong_gens_slp in terms of the # elements of strong_gens for k, slp in strong_gens_slp: strong_gens.append(k) for i in range(len(slp)): s = slp[i] if isinstance(s[1], tuple): slp[i] = strong_gens_distr[s[0]][s[1][0]]**-1 else: slp[i] = strong_gens_distr[s[0]][s[1]] strong_gens_slp = dict(strong_gens_slp) # add the original generators for g in _gens: strong_gens_slp[g] = [g] return (_base, strong_gens, strong_gens_slp) strong_gens.extend([k for k, _ in strong_gens_slp]) return _base, strong_gens def schreier_sims_random(self, base=None, gens=None, consec_succ=10, _random_prec=None): r"""Randomized Schreier-Sims algorithm. Explanation =========== The randomized Schreier-Sims algorithm takes the sequence ``base`` and the generating set ``gens``, and extends ``base`` to a base, and ``gens`` to a strong generating set relative to that base with probability of a wrong answer at most `2^{-consec\_succ}`, provided the random generators are sufficiently random. Parameters ========== base The sequence to be extended to a base. gens The generating set to be extended to a strong generating set. consec_succ The parameter defining the probability of a wrong answer. _random_prec An internal parameter used for testing purposes. Returns ======= (base, strong_gens) ``base`` is the base and ``strong_gens`` is the strong generating set relative to it. Examples ======== >>> from sympy.combinatorics.testutil import _verify_bsgs >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> S = SymmetricGroup(5) >>> base, strong_gens = S.schreier_sims_random(consec_succ=5) >>> _verify_bsgs(S, base, strong_gens) #doctest: +SKIP True Notes ===== The algorithm is described in detail in [1], pp. 97-98. It extends the orbits ``orbs`` and the permutation groups ``stabs`` to basic orbits and basic stabilizers for the base and strong generating set produced in the end. The idea of the extension process is to "sift" random group elements through the stabilizer chain and amend the stabilizers/orbits along the way when a sift is not successful. The helper function ``_strip`` is used to attempt to decompose a random group element according to the current state of the stabilizer chain and report whether the element was fully decomposed (successful sift) or not (unsuccessful sift). In the latter case, the level at which the sift failed is reported and used to amend ``stabs``, ``base``, ``gens`` and ``orbs`` accordingly. The halting condition is for ``consec_succ`` consecutive successful sifts to pass. This makes sure that the current ``base`` and ``gens`` form a BSGS with probability at least `1 - 1/\text{consec\_succ}`. See Also ======== schreier_sims """ if base is None: base = [] if gens is None: gens = self.generators base_len = len(base) n = self.degree # make sure no generator fixes all base points for gen in gens: if all(gen(x) == x for x in base): new = 0 while gen._array_form[new] == new: new += 1 base.append(new) base_len += 1 # distribute generators according to basic stabilizers strong_gens_distr = _distribute_gens_by_base(base, gens) # initialize the basic stabilizers, basic transversals and basic orbits transversals = {} orbs = {} for i in range(base_len): transversals[i] = dict(_orbit_transversal(n, strong_gens_distr[i], base[i], pairs=True)) orbs[i] = list(transversals[i].keys()) # initialize the number of consecutive elements sifted c = 0 # start sifting random elements while the number of consecutive sifts # is less than consec_succ while c < consec_succ: if _random_prec is None: g = self.random_pr() else: g = _random_prec['g'].pop() h, j = _strip(g, base, orbs, transversals) y = True # determine whether a new base point is needed if j <= base_len: y = False elif not h.is_Identity: y = False moved = 0 while h(moved) == moved: moved += 1 base.append(moved) base_len += 1 strong_gens_distr.append([]) # if the element doesn't sift, amend the strong generators and # associated stabilizers and orbits if y is False: for l in range(1, j): strong_gens_distr[l].append(h) transversals[l] = dict(_orbit_transversal(n, strong_gens_distr[l], base[l], pairs=True)) orbs[l] = list(transversals[l].keys()) c = 0 else: c += 1 # build the strong generating set strong_gens = strong_gens_distr[0][:] for gen in strong_gens_distr[1]: if gen not in strong_gens: strong_gens.append(gen) return base, strong_gens def schreier_vector(self, alpha): """Computes the schreier vector for ``alpha``. Explanation =========== The Schreier vector efficiently stores information about the orbit of ``alpha``. It can later be used to quickly obtain elements of the group that send ``alpha`` to a particular element in the orbit. Notice that the Schreier vector depends on the order in which the group generators are listed. For a definition, see [3]. Since list indices start from zero, we adopt the convention to use "None" instead of 0 to signify that an element doesn't belong to the orbit. For the algorithm and its correctness, see [2], pp.78-80. Examples ======== >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics.permutations import Permutation >>> a = Permutation([2, 4, 6, 3, 1, 5, 0]) >>> b = Permutation([0, 1, 3, 5, 4, 6, 2]) >>> G = PermutationGroup([a, b]) >>> G.schreier_vector(0) [-1, None, 0, 1, None, 1, 0] See Also ======== orbit """ n = self.degree v = [None]*n v[alpha] = -1 orb = [alpha] used = [False]*n used[alpha] = True gens = self.generators r = len(gens) for b in orb: for i in range(r): temp = gens[i]._array_form[b] if used[temp] is False: orb.append(temp) used[temp] = True v[temp] = i return v def stabilizer(self, alpha): r"""Return the stabilizer subgroup of ``alpha``. Explanation =========== The stabilizer of `\alpha` is the group `G_\alpha = \{g \in G | g(\alpha) = \alpha\}`. For a proof of correctness, see [1], p.79. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> G = DihedralGroup(6) >>> G.stabilizer(5) PermutationGroup([ (5)(0 4)(1 3)]) See Also ======== orbit """ return PermGroup(_stabilizer(self._degree, self._generators, alpha)) @property def strong_gens(self): r"""Return a strong generating set from the Schreier-Sims algorithm. Explanation =========== A generating set `S = \{g_1, g_2, ..., g_t\}` for a permutation group `G` is a strong generating set relative to the sequence of points (referred to as a "base") `(b_1, b_2, ..., b_k)` if, for `1 \leq i \leq k` we have that the intersection of the pointwise stabilizer `G^{(i+1)} := G_{b_1, b_2, ..., b_i}` with `S` generates the pointwise stabilizer `G^{(i+1)}`. The concepts of a base and strong generating set and their applications are discussed in depth in [1], pp. 87-89 and [2], pp. 55-57. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> D = DihedralGroup(4) >>> D.strong_gens [(0 1 2 3), (0 3)(1 2), (1 3)] >>> D.base [0, 1] See Also ======== base, basic_transversals, basic_orbits, basic_stabilizers """ if self._strong_gens == []: self.schreier_sims() return self._strong_gens def subgroup(self, gens): """ Return the subgroup generated by `gens` which is a list of elements of the group """ if not all([g in self for g in gens]): raise ValueError("The group doesn't contain the supplied generators") G = PermutationGroup(gens) return G def subgroup_search(self, prop, base=None, strong_gens=None, tests=None, init_subgroup=None): """Find the subgroup of all elements satisfying the property ``prop``. Explanation =========== This is done by a depth-first search with respect to base images that uses several tests to prune the search tree. Parameters ========== prop The property to be used. Has to be callable on group elements and always return ``True`` or ``False``. It is assumed that all group elements satisfying ``prop`` indeed form a subgroup. base A base for the supergroup. strong_gens A strong generating set for the supergroup. tests A list of callables of length equal to the length of ``base``. These are used to rule out group elements by partial base images, so that ``tests[l](g)`` returns False if the element ``g`` is known not to satisfy prop base on where g sends the first ``l + 1`` base points. init_subgroup if a subgroup of the sought group is known in advance, it can be passed to the function as this parameter. Returns ======= res The subgroup of all elements satisfying ``prop``. The generating set for this group is guaranteed to be a strong generating set relative to the base ``base``. Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... AlternatingGroup) >>> from sympy.combinatorics.testutil import _verify_bsgs >>> S = SymmetricGroup(7) >>> prop_even = lambda x: x.is_even >>> base, strong_gens = S.schreier_sims_incremental() >>> G = S.subgroup_search(prop_even, base=base, strong_gens=strong_gens) >>> G.is_subgroup(AlternatingGroup(7)) True >>> _verify_bsgs(G, base, G.generators) True Notes ===== This function is extremely lengthy and complicated and will require some careful attention. The implementation is described in [1], pp. 114-117, and the comments for the code here follow the lines of the pseudocode in the book for clarity. The complexity is exponential in general, since the search process by itself visits all members of the supergroup. However, there are a lot of tests which are used to prune the search tree, and users can define their own tests via the ``tests`` parameter, so in practice, and for some computations, it's not terrible. A crucial part in the procedure is the frequent base change performed (this is line 11 in the pseudocode) in order to obtain a new basic stabilizer. The book mentiones that this can be done by using ``.baseswap(...)``, however the current implementation uses a more straightforward way to find the next basic stabilizer - calling the function ``.stabilizer(...)`` on the previous basic stabilizer. """ # initialize BSGS and basic group properties def get_reps(orbits): # get the minimal element in the base ordering return [min(orbit, key = lambda x: base_ordering[x]) \ for orbit in orbits] def update_nu(l): temp_index = len(basic_orbits[l]) + 1 -\ len(res_basic_orbits_init_base[l]) # this corresponds to the element larger than all points if temp_index >= len(sorted_orbits[l]): nu[l] = base_ordering[degree] else: nu[l] = sorted_orbits[l][temp_index] if base is None: base, strong_gens = self.schreier_sims_incremental() base_len = len(base) degree = self.degree identity = _af_new(list(range(degree))) base_ordering = _base_ordering(base, degree) # add an element larger than all points base_ordering.append(degree) # add an element smaller than all points base_ordering.append(-1) # compute BSGS-related structures strong_gens_distr = _distribute_gens_by_base(base, strong_gens) basic_orbits, transversals = _orbits_transversals_from_bsgs(base, strong_gens_distr) # handle subgroup initialization and tests if init_subgroup is None: init_subgroup = PermutationGroup([identity]) if tests is None: trivial_test = lambda x: True tests = [] for i in range(base_len): tests.append(trivial_test) # line 1: more initializations. res = init_subgroup f = base_len - 1 l = base_len - 1 # line 2: set the base for K to the base for G res_base = base[:] # line 3: compute BSGS and related structures for K res_base, res_strong_gens = res.schreier_sims_incremental( base=res_base) res_strong_gens_distr = _distribute_gens_by_base(res_base, res_strong_gens) res_generators = res.generators res_basic_orbits_init_base = \ [_orbit(degree, res_strong_gens_distr[i], res_base[i])\ for i in range(base_len)] # initialize orbit representatives orbit_reps = [None]*base_len # line 4: orbit representatives for f-th basic stabilizer of K orbits = _orbits(degree, res_strong_gens_distr[f]) orbit_reps[f] = get_reps(orbits) # line 5: remove the base point from the representatives to avoid # getting the identity element as a generator for K orbit_reps[f].remove(base[f]) # line 6: more initializations c = [0]*base_len u = [identity]*base_len sorted_orbits = [None]*base_len for i in range(base_len): sorted_orbits[i] = basic_orbits[i][:] sorted_orbits[i].sort(key=lambda point: base_ordering[point]) # line 7: initializations mu = [None]*base_len nu = [None]*base_len # this corresponds to the element smaller than all points mu[l] = degree + 1 update_nu(l) # initialize computed words computed_words = [identity]*base_len # line 8: main loop while True: # apply all the tests while l < base_len - 1 and \ computed_words[l](base[l]) in orbit_reps[l] and \ base_ordering[mu[l]] < \ base_ordering[computed_words[l](base[l])] < \ base_ordering[nu[l]] and \ tests[l](computed_words): # line 11: change the (partial) base of K new_point = computed_words[l](base[l]) res_base[l] = new_point new_stab_gens = _stabilizer(degree, res_strong_gens_distr[l], new_point) res_strong_gens_distr[l + 1] = new_stab_gens # line 12: calculate minimal orbit representatives for the # l+1-th basic stabilizer orbits = _orbits(degree, new_stab_gens) orbit_reps[l + 1] = get_reps(orbits) # line 13: amend sorted orbits l += 1 temp_orbit = [computed_words[l - 1](point) for point in basic_orbits[l]] temp_orbit.sort(key=lambda point: base_ordering[point]) sorted_orbits[l] = temp_orbit # lines 14 and 15: update variables used minimality tests new_mu = degree + 1 for i in range(l): if base[l] in res_basic_orbits_init_base[i]: candidate = computed_words[i](base[i]) if base_ordering[candidate] > base_ordering[new_mu]: new_mu = candidate mu[l] = new_mu update_nu(l) # line 16: determine the new transversal element c[l] = 0 temp_point = sorted_orbits[l][c[l]] gamma = computed_words[l - 1]._array_form.index(temp_point) u[l] = transversals[l][gamma] # update computed words computed_words[l] = rmul(computed_words[l - 1], u[l]) # lines 17 & 18: apply the tests to the group element found g = computed_words[l] temp_point = g(base[l]) if l == base_len - 1 and \ base_ordering[mu[l]] < \ base_ordering[temp_point] < base_ordering[nu[l]] and \ temp_point in orbit_reps[l] and \ tests[l](computed_words) and \ prop(g): # line 19: reset the base of K res_generators.append(g) res_base = base[:] # line 20: recalculate basic orbits (and transversals) res_strong_gens.append(g) res_strong_gens_distr = _distribute_gens_by_base(res_base, res_strong_gens) res_basic_orbits_init_base = \ [_orbit(degree, res_strong_gens_distr[i], res_base[i]) \ for i in range(base_len)] # line 21: recalculate orbit representatives # line 22: reset the search depth orbit_reps[f] = get_reps(orbits) l = f # line 23: go up the tree until in the first branch not fully # searched while l >= 0 and c[l] == len(basic_orbits[l]) - 1: l = l - 1 # line 24: if the entire tree is traversed, return K if l == -1: return PermutationGroup(res_generators) # lines 25-27: update orbit representatives if l < f: # line 26 f = l c[l] = 0 # line 27 temp_orbits = _orbits(degree, res_strong_gens_distr[f]) orbit_reps[f] = get_reps(temp_orbits) # line 28: update variables used for minimality testing mu[l] = degree + 1 temp_index = len(basic_orbits[l]) + 1 - \ len(res_basic_orbits_init_base[l]) if temp_index >= len(sorted_orbits[l]): nu[l] = base_ordering[degree] else: nu[l] = sorted_orbits[l][temp_index] # line 29: set the next element from the current branch and update # accordingly c[l] += 1 if l == 0: gamma = sorted_orbits[l][c[l]] else: gamma = computed_words[l - 1]._array_form.index(sorted_orbits[l][c[l]]) u[l] = transversals[l][gamma] if l == 0: computed_words[l] = u[l] else: computed_words[l] = rmul(computed_words[l - 1], u[l]) @property def transitivity_degree(self): r"""Compute the degree of transitivity of the group. Explanation =========== A permutation group `G` acting on `\Omega = \{0, 1, ..., n-1\}` is ``k``-fold transitive, if, for any k points `(a_1, a_2, ..., a_k)\in\Omega` and any k points `(b_1, b_2, ..., b_k)\in\Omega` there exists `g\in G` such that `g(a_1)=b_1, g(a_2)=b_2, ..., g(a_k)=b_k` The degree of transitivity of `G` is the maximum ``k`` such that `G` is ``k``-fold transitive. ([8]) Examples ======== >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics.permutations import Permutation >>> a = Permutation([1, 2, 0]) >>> b = Permutation([1, 0, 2]) >>> G = PermutationGroup([a, b]) >>> G.transitivity_degree 3 See Also ======== is_transitive, orbit """ if self._transitivity_degree is None: n = self.degree G = self # if G is k-transitive, a tuple (a_0,..,a_k) # can be brought to (b_0,...,b_(k-1), b_k) # where b_0,...,b_(k-1) are fixed points; # consider the group G_k which stabilizes b_0,...,b_(k-1) # if G_k is transitive on the subset excluding b_0,...,b_(k-1) # then G is (k+1)-transitive for i in range(n): orb = G.orbit(i) if len(orb) != n - i: self._transitivity_degree = i return i G = G.stabilizer(i) self._transitivity_degree = n return n else: return self._transitivity_degree def _p_elements_group(G, p): ''' For an abelian p-group G return the subgroup consisting of all elements of order p (and the identity) ''' gens = G.generators[:] gens = sorted(gens, key=lambda x: x.order(), reverse=True) gens_p = [g**(g.order()/p) for g in gens] gens_r = [] for i in range(len(gens)): x = gens[i] x_order = x.order() # x_p has order p x_p = x**(x_order/p) if i > 0: P = PermutationGroup(gens_p[:i]) else: P = PermutationGroup(G.identity) if x**(x_order/p) not in P: gens_r.append(x**(x_order/p)) else: # replace x by an element of order (x.order()/p) # so that gens still generates G g = P.generator_product(x_p, original=True) for s in g: x = x*s**-1 x_order = x_order/p # insert x to gens so that the sorting is preserved del gens[i] del gens_p[i] j = i - 1 while j < len(gens) and gens[j].order() >= x_order: j += 1 gens = gens[:j] + [x] + gens[j:] gens_p = gens_p[:j] + [x] + gens_p[j:] return PermutationGroup(gens_r) def _sylow_alt_sym(self, p): ''' Return a p-Sylow subgroup of a symmetric or an alternating group. Explanation =========== The algorithm for this is hinted at in [1], Chapter 4, Exercise 4. For Sym(n) with n = p^i, the idea is as follows. Partition the interval [0..n-1] into p equal parts, each of length p^(i-1): [0..p^(i-1)-1], [p^(i-1)..2*p^(i-1)-1]...[(p-1)*p^(i-1)..p^i-1]. Find a p-Sylow subgroup of Sym(p^(i-1)) (treated as a subgroup of ``self``) acting on each of the parts. Call the subgroups P_1, P_2...P_p. The generators for the subgroups P_2...P_p can be obtained from those of P_1 by applying a "shifting" permutation to them, that is, a permutation mapping [0..p^(i-1)-1] to the second part (the other parts are obtained by using the shift multiple times). The union of this permutation and the generators of P_1 is a p-Sylow subgroup of ``self``. For n not equal to a power of p, partition [0..n-1] in accordance with how n would be written in base p. E.g. for p=2 and n=11, 11 = 2^3 + 2^2 + 1 so the partition is [[0..7], [8..9], {10}]. To generate a p-Sylow subgroup, take the union of the generators for each of the parts. For the above example, {(0 1), (0 2)(1 3), (0 4), (1 5)(2 7)} from the first part, {(8 9)} from the second part and nothing from the third. This gives 4 generators in total, and the subgroup they generate is p-Sylow. Alternating groups are treated the same except when p=2. In this case, (0 1)(s s+1) should be added for an appropriate s (the start of a part) for each part in the partitions. See Also ======== sylow_subgroup, is_alt_sym ''' n = self.degree gens = [] identity = Permutation(n-1) # the case of 2-sylow subgroups of alternating groups # needs special treatment alt = p == 2 and all(g.is_even for g in self.generators) # find the presentation of n in base p coeffs = [] m = n while m > 0: coeffs.append(m % p) m = m // p power = len(coeffs)-1 # for a symmetric group, gens[:i] is the generating # set for a p-Sylow subgroup on [0..p**(i-1)-1]. For # alternating groups, the same is given by gens[:2*(i-1)] for i in range(1, power+1): if i == 1 and alt: # (0 1) shouldn't be added for alternating groups continue gen = Permutation([(j + p**(i-1)) % p**i for j in range(p**i)]) gens.append(identity*gen) if alt: gen = Permutation(0, 1)*gen*Permutation(0, 1)*gen gens.append(gen) # the first point in the current part (see the algorithm # description in the docstring) start = 0 while power > 0: a = coeffs[power] # make the permutation shifting the start of the first # part ([0..p^i-1] for some i) to the current one for s in range(a): shift = Permutation() if start > 0: for i in range(p**power): shift = shift(i, start + i) if alt: gen = Permutation(0, 1)*shift*Permutation(0, 1)*shift gens.append(gen) j = 2*(power - 1) else: j = power for i, gen in enumerate(gens[:j]): if alt and i % 2 == 1: continue # shift the generator to the start of the # partition part gen = shift*gen*shift gens.append(gen) start += p**power power = power-1 return gens def sylow_subgroup(self, p): ''' Return a p-Sylow subgroup of the group. The algorithm is described in [1], Chapter 4, Section 7 Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> D = DihedralGroup(6) >>> S = D.sylow_subgroup(2) >>> S.order() 4 >>> G = SymmetricGroup(6) >>> S = G.sylow_subgroup(5) >>> S.order() 5 >>> G1 = AlternatingGroup(3) >>> G2 = AlternatingGroup(5) >>> G3 = AlternatingGroup(9) >>> S1 = G1.sylow_subgroup(3) >>> S2 = G2.sylow_subgroup(3) >>> S3 = G3.sylow_subgroup(3) >>> len1 = len(S1.lower_central_series()) >>> len2 = len(S2.lower_central_series()) >>> len3 = len(S3.lower_central_series()) >>> len1 == len2 True >>> len1 < len3 True ''' from sympy.combinatorics.homomorphisms import ( orbit_homomorphism, block_homomorphism) from sympy.ntheory.primetest import isprime if not isprime(p): raise ValueError("p must be a prime") def is_p_group(G): # check if the order of G is a power of p # and return the power m = G.order() n = 0 while m % p == 0: m = m/p n += 1 if m == 1: return True, n return False, n def _sylow_reduce(mu, nu): # reduction based on two homomorphisms # mu and nu with trivially intersecting # kernels Q = mu.image().sylow_subgroup(p) Q = mu.invert_subgroup(Q) nu = nu.restrict_to(Q) R = nu.image().sylow_subgroup(p) return nu.invert_subgroup(R) order = self.order() if order % p != 0: return PermutationGroup([self.identity]) p_group, n = is_p_group(self) if p_group: return self if self.is_alt_sym(): return PermutationGroup(self._sylow_alt_sym(p)) # if there is a non-trivial orbit with size not divisible # by p, the sylow subgroup is contained in its stabilizer # (by orbit-stabilizer theorem) orbits = self.orbits() non_p_orbits = [o for o in orbits if len(o) % p != 0 and len(o) != 1] if non_p_orbits: G = self.stabilizer(list(non_p_orbits[0]).pop()) return G.sylow_subgroup(p) if not self.is_transitive(): # apply _sylow_reduce to orbit actions orbits = sorted(orbits, key = lambda x: len(x)) omega1 = orbits.pop() omega2 = orbits[0].union(*orbits) mu = orbit_homomorphism(self, omega1) nu = orbit_homomorphism(self, omega2) return _sylow_reduce(mu, nu) blocks = self.minimal_blocks() if len(blocks) > 1: # apply _sylow_reduce to block system actions mu = block_homomorphism(self, blocks[0]) nu = block_homomorphism(self, blocks[1]) return _sylow_reduce(mu, nu) elif len(blocks) == 1: block = list(blocks)[0] if any(e != 0 for e in block): # self is imprimitive mu = block_homomorphism(self, block) if not is_p_group(mu.image())[0]: S = mu.image().sylow_subgroup(p) return mu.invert_subgroup(S).sylow_subgroup(p) # find an element of order p g = self.random() g_order = g.order() while g_order % p != 0 or g_order == 0: g = self.random() g_order = g.order() g = g**(g_order // p) if order % p**2 != 0: return PermutationGroup(g) C = self.centralizer(g) while C.order() % p**n != 0: S = C.sylow_subgroup(p) s_order = S.order() Z = S.center() P = Z._p_elements_group(p) h = P.random() C_h = self.centralizer(h) while C_h.order() % p*s_order != 0: h = P.random() C_h = self.centralizer(h) C = C_h return C.sylow_subgroup(p) def _block_verify(H, L, alpha): delta = sorted(list(H.orbit(alpha))) H_gens = H.generators # p[i] will be the number of the block # delta[i] belongs to p = [-1]*len(delta) blocks = [-1]*len(delta) B = [[]] # future list of blocks u = [0]*len(delta) # u[i] in L s.t. alpha^u[i] = B[0][i] t = L.orbit_transversal(alpha, pairs=True) for a, beta in t: B[0].append(a) i_a = delta.index(a) p[i_a] = 0 blocks[i_a] = alpha u[i_a] = beta rho = 0 m = 0 # number of blocks - 1 while rho <= m: beta = B[rho][0] for g in H_gens: d = beta^g i_d = delta.index(d) sigma = p[i_d] if sigma < 0: # define a new block m += 1 sigma = m u[i_d] = u[delta.index(beta)]*g p[i_d] = sigma rep = d blocks[i_d] = rep newb = [rep] for gamma in B[rho][1:]: i_gamma = delta.index(gamma) d = gamma^g i_d = delta.index(d) if p[i_d] < 0: u[i_d] = u[i_gamma]*g p[i_d] = sigma blocks[i_d] = rep newb.append(d) else: # B[rho] is not a block s = u[i_gamma]*g*u[i_d]**(-1) return False, s B.append(newb) else: for h in B[rho][1:]: if not h^g in B[sigma]: # B[rho] is not a block s = u[delta.index(beta)]*g*u[i_d]**(-1) return False, s rho += 1 return True, blocks def _verify(H, K, phi, z, alpha): ''' Return a list of relators ``rels`` in generators ``gens`_h` that are mapped to ``H.generators`` by ``phi`` so that given a finite presentation of ``K`` on a subset of ``gens_h`` is a finite presentation of ``H``. Explanation =========== ``H`` should be generated by the union of ``K.generators`` and ``z`` (a single generator), and ``H.stabilizer(alpha) == K``; ``phi`` is a canonical injection from a free group into a permutation group containing ``H``. The algorithm is described in [1], Chapter 6. Examples ======== >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.homomorphisms import homomorphism >>> from sympy.combinatorics.free_groups import free_group >>> from sympy.combinatorics.fp_groups import FpGroup >>> H = PermutationGroup(Permutation(0, 2), Permutation (1, 5)) >>> K = PermutationGroup(Permutation(5)(0, 2)) >>> F = free_group("x_0 x_1")[0] >>> gens = F.generators >>> phi = homomorphism(F, H, F.generators, H.generators) >>> rels_k = [gens[0]**2] # relators for presentation of K >>> z= Permutation(1, 5) >>> check, rels_h = H._verify(K, phi, z, 1) >>> check True >>> rels = rels_k + rels_h >>> G = FpGroup(F, rels) # presentation of H >>> G.order() == H.order() True See also ======== strong_presentation, presentation, stabilizer ''' orbit = H.orbit(alpha) beta = alpha^(z**-1) K_beta = K.stabilizer(beta) # orbit representatives of K_beta gammas = [alpha, beta] orbits = list({tuple(K_beta.orbit(o)) for o in orbit}) orbit_reps = [orb[0] for orb in orbits] for rep in orbit_reps: if rep not in gammas: gammas.append(rep) # orbit transversal of K betas = [alpha, beta] transversal = {alpha: phi.invert(H.identity), beta: phi.invert(z**-1)} for s, g in K.orbit_transversal(beta, pairs=True): if not s in transversal: transversal[s] = transversal[beta]*phi.invert(g) union = K.orbit(alpha).union(K.orbit(beta)) while (len(union) < len(orbit)): for gamma in gammas: if gamma in union: r = gamma^z if r not in union: betas.append(r) transversal[r] = transversal[gamma]*phi.invert(z) for s, g in K.orbit_transversal(r, pairs=True): if not s in transversal: transversal[s] = transversal[r]*phi.invert(g) union = union.union(K.orbit(r)) break # compute relators rels = [] for b in betas: k_gens = K.stabilizer(b).generators for y in k_gens: new_rel = transversal[b] gens = K.generator_product(y, original=True) for g in gens[::-1]: new_rel = new_rel*phi.invert(g) new_rel = new_rel*transversal[b]**-1 perm = phi(new_rel) try: gens = K.generator_product(perm, original=True) except ValueError: return False, perm for g in gens: new_rel = new_rel*phi.invert(g)**-1 if new_rel not in rels: rels.append(new_rel) for gamma in gammas: new_rel = transversal[gamma]*phi.invert(z)*transversal[gamma^z]**-1 perm = phi(new_rel) try: gens = K.generator_product(perm, original=True) except ValueError: return False, perm for g in gens: new_rel = new_rel*phi.invert(g)**-1 if new_rel not in rels: rels.append(new_rel) return True, rels def strong_presentation(G): ''' Return a strong finite presentation of `G`. The generators of the returned group are in the same order as the strong generators of `G`. The algorithm is based on Sims' Verify algorithm described in [1], Chapter 6. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> P = DihedralGroup(4) >>> G = P.strong_presentation() >>> P.order() == G.order() True See Also ======== presentation, _verify ''' from sympy.combinatorics.fp_groups import (FpGroup, simplify_presentation) from sympy.combinatorics.free_groups import free_group from sympy.combinatorics.homomorphisms import (block_homomorphism, homomorphism, GroupHomomorphism) strong_gens = G.strong_gens[:] stabs = G.basic_stabilizers[:] base = G.base[:] # injection from a free group on len(strong_gens) # generators into G gen_syms = [('x_%d'%i) for i in range(len(strong_gens))] F = free_group(', '.join(gen_syms))[0] phi = homomorphism(F, G, F.generators, strong_gens) H = PermutationGroup(G.identity) while stabs: alpha = base.pop() K = H H = stabs.pop() new_gens = [g for g in H.generators if g not in K] if K.order() == 1: z = new_gens.pop() rels = [F.generators[-1]**z.order()] intermediate_gens = [z] K = PermutationGroup(intermediate_gens) # add generators one at a time building up from K to H while new_gens: z = new_gens.pop() intermediate_gens = [z] + intermediate_gens K_s = PermutationGroup(intermediate_gens) orbit = K_s.orbit(alpha) orbit_k = K.orbit(alpha) # split into cases based on the orbit of K_s if orbit_k == orbit: if z in K: rel = phi.invert(z) perm = z else: t = K.orbit_rep(alpha, alpha^z) rel = phi.invert(z)*phi.invert(t)**-1 perm = z*t**-1 for g in K.generator_product(perm, original=True): rel = rel*phi.invert(g)**-1 new_rels = [rel] elif len(orbit_k) == 1: # `success` is always true because `strong_gens` # and `base` are already a verified BSGS. Later # this could be changed to start with a randomly # generated (potential) BSGS, and then new elements # would have to be appended to it when `success` # is false. success, new_rels = K_s._verify(K, phi, z, alpha) else: # K.orbit(alpha) should be a block # under the action of K_s on K_s.orbit(alpha) check, block = K_s._block_verify(K, alpha) if check: # apply _verify to the action of K_s # on the block system; for convenience, # add the blocks as additional points # that K_s should act on t = block_homomorphism(K_s, block) m = t.codomain.degree # number of blocks d = K_s.degree # conjugating with p will shift # permutations in t.image() to # higher numbers, e.g. # p*(0 1)*p = (m m+1) p = Permutation() for i in range(m): p *= Permutation(i, i+d) t_img = t.images # combine generators of K_s with their # action on the block system images = {g: g*p*t_img[g]*p for g in t_img} for g in G.strong_gens[:-len(K_s.generators)]: images[g] = g K_s_act = PermutationGroup(list(images.values())) f = GroupHomomorphism(G, K_s_act, images) K_act = PermutationGroup([f(g) for g in K.generators]) success, new_rels = K_s_act._verify(K_act, f.compose(phi), f(z), d) for n in new_rels: if not n in rels: rels.append(n) K = K_s group = FpGroup(F, rels) return simplify_presentation(group) def presentation(G, eliminate_gens=True): ''' Return an `FpGroup` presentation of the group. The algorithm is described in [1], Chapter 6.1. ''' from sympy.combinatorics.fp_groups import (FpGroup, simplify_presentation) from sympy.combinatorics.coset_table import CosetTable from sympy.combinatorics.free_groups import free_group from sympy.combinatorics.homomorphisms import homomorphism from itertools import product if G._fp_presentation: return G._fp_presentation if G._fp_presentation: return G._fp_presentation def _factor_group_by_rels(G, rels): if isinstance(G, FpGroup): rels.extend(G.relators) return FpGroup(G.free_group, list(set(rels))) return FpGroup(G, rels) gens = G.generators len_g = len(gens) if len_g == 1: order = gens[0].order() # handle the trivial group if order == 1: return free_group([])[0] F, x = free_group('x') return FpGroup(F, [x**order]) if G.order() > 20: half_gens = G.generators[0:(len_g+1)//2] else: half_gens = [] H = PermutationGroup(half_gens) H_p = H.presentation() len_h = len(H_p.generators) C = G.coset_table(H) n = len(C) # subgroup index gen_syms = [('x_%d'%i) for i in range(len(gens))] F = free_group(', '.join(gen_syms))[0] # mapping generators of H_p to those of F images = [F.generators[i] for i in range(len_h)] R = homomorphism(H_p, F, H_p.generators, images, check=False) # rewrite relators rels = R(H_p.relators) G_p = FpGroup(F, rels) # injective homomorphism from G_p into G T = homomorphism(G_p, G, G_p.generators, gens) C_p = CosetTable(G_p, []) C_p.table = [[None]*(2*len_g) for i in range(n)] # initiate the coset transversal transversal = [None]*n transversal[0] = G_p.identity # fill in the coset table as much as possible for i in range(2*len_h): C_p.table[0][i] = 0 gamma = 1 for alpha, x in product(range(0, n), range(2*len_g)): beta = C[alpha][x] if beta == gamma: gen = G_p.generators[x//2]**((-1)**(x % 2)) transversal[beta] = transversal[alpha]*gen C_p.table[alpha][x] = beta C_p.table[beta][x + (-1)**(x % 2)] = alpha gamma += 1 if gamma == n: break C_p.p = list(range(n)) beta = x = 0 while not C_p.is_complete(): # find the first undefined entry while C_p.table[beta][x] == C[beta][x]: x = (x + 1) % (2*len_g) if x == 0: beta = (beta + 1) % n # define a new relator gen = G_p.generators[x//2]**((-1)**(x % 2)) new_rel = transversal[beta]*gen*transversal[C[beta][x]]**-1 perm = T(new_rel) next = G_p.identity for s in H.generator_product(perm, original=True): next = next*T.invert(s)**-1 new_rel = new_rel*next # continue coset enumeration G_p = _factor_group_by_rels(G_p, [new_rel]) C_p.scan_and_fill(0, new_rel) C_p = G_p.coset_enumeration([], strategy="coset_table", draft=C_p, max_cosets=n, incomplete=True) G._fp_presentation = simplify_presentation(G_p) return G._fp_presentation def polycyclic_group(self): """ Return the PolycyclicGroup instance with below parameters: Explanation =========== * ``pc_sequence`` : Polycyclic sequence is formed by collecting all the missing generators between the adjacent groups in the derived series of given permutation group. * ``pc_series`` : Polycyclic series is formed by adding all the missing generators of ``der[i+1]`` in ``der[i]``, where ``der`` represents the derived series. * ``relative_order`` : A list, computed by the ratio of adjacent groups in pc_series. """ from sympy.combinatorics.pc_groups import PolycyclicGroup if not self.is_polycyclic: raise ValueError("The group must be solvable") der = self.derived_series() pc_series = [] pc_sequence = [] relative_order = [] pc_series.append(der[-1]) der.reverse() for i in range(len(der)-1): H = der[i] for g in der[i+1].generators: if g not in H: H = PermutationGroup([g] + H.generators) pc_series.insert(0, H) pc_sequence.insert(0, g) G1 = pc_series[0].order() G2 = pc_series[1].order() relative_order.insert(0, G1 // G2) return PolycyclicGroup(pc_sequence, pc_series, relative_order, collector=None) def _orbit(degree, generators, alpha, action='tuples'): r"""Compute the orbit of alpha `\{g(\alpha) | g \in G\}` as a set. Explanation =========== The time complexity of the algorithm used here is `O(|Orb|*r)` where `|Orb|` is the size of the orbit and ``r`` is the number of generators of the group. For a more detailed analysis, see [1], p.78, [2], pp. 19-21. Here alpha can be a single point, or a list of points. If alpha is a single point, the ordinary orbit is computed. if alpha is a list of points, there are three available options: 'union' - computes the union of the orbits of the points in the list 'tuples' - computes the orbit of the list interpreted as an ordered tuple under the group action ( i.e., g((1, 2, 3)) = (g(1), g(2), g(3)) ) 'sets' - computes the orbit of the list interpreted as a sets Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup, _orbit >>> a = Permutation([1, 2, 0, 4, 5, 6, 3]) >>> G = PermutationGroup([a]) >>> _orbit(G.degree, G.generators, 0) {0, 1, 2} >>> _orbit(G.degree, G.generators, [0, 4], 'union') {0, 1, 2, 3, 4, 5, 6} See Also ======== orbit, orbit_transversal """ if not hasattr(alpha, '__getitem__'): alpha = [alpha] gens = [x._array_form for x in generators] if len(alpha) == 1 or action == 'union': orb = alpha used = [False]*degree for el in alpha: used[el] = True for b in orb: for gen in gens: temp = gen[b] if used[temp] == False: orb.append(temp) used[temp] = True return set(orb) elif action == 'tuples': alpha = tuple(alpha) orb = [alpha] used = {alpha} for b in orb: for gen in gens: temp = tuple([gen[x] for x in b]) if temp not in used: orb.append(temp) used.add(temp) return set(orb) elif action == 'sets': alpha = frozenset(alpha) orb = [alpha] used = {alpha} for b in orb: for gen in gens: temp = frozenset([gen[x] for x in b]) if temp not in used: orb.append(temp) used.add(temp) return {tuple(x) for x in orb} def _orbits(degree, generators): """Compute the orbits of G. If ``rep=False`` it returns a list of sets else it returns a list of representatives of the orbits Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.perm_groups import _orbits >>> a = Permutation([0, 2, 1]) >>> b = Permutation([1, 0, 2]) >>> _orbits(a.size, [a, b]) [{0, 1, 2}] """ orbs = [] sorted_I = list(range(degree)) I = set(sorted_I) while I: i = sorted_I[0] orb = _orbit(degree, generators, i) orbs.append(orb) # remove all indices that are in this orbit I -= orb sorted_I = [i for i in sorted_I if i not in orb] return orbs def _orbit_transversal(degree, generators, alpha, pairs, af=False, slp=False): r"""Computes a transversal for the orbit of ``alpha`` as a set. Explanation =========== generators generators of the group ``G`` For a permutation group ``G``, a transversal for the orbit `Orb = \{g(\alpha) | g \in G\}` is a set `\{g_\beta | g_\beta(\alpha) = \beta\}` for `\beta \in Orb`. Note that there may be more than one possible transversal. If ``pairs`` is set to ``True``, it returns the list of pairs `(\beta, g_\beta)`. For a proof of correctness, see [1], p.79 if ``af`` is ``True``, the transversal elements are given in array form. If `slp` is `True`, a dictionary `{beta: slp_beta}` is returned for `\beta \in Orb` where `slp_beta` is a list of indices of the generators in `generators` s.t. if `slp_beta = [i_1 ... i_n]` `g_\beta = generators[i_n]*...*generators[i_1]`. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> from sympy.combinatorics.perm_groups import _orbit_transversal >>> G = DihedralGroup(6) >>> _orbit_transversal(G.degree, G.generators, 0, False) [(5), (0 1 2 3 4 5), (0 5)(1 4)(2 3), (0 2 4)(1 3 5), (5)(0 4)(1 3), (0 3)(1 4)(2 5)] """ tr = [(alpha, list(range(degree)))] slp_dict = {alpha: []} used = [False]*degree used[alpha] = True gens = [x._array_form for x in generators] for x, px in tr: px_slp = slp_dict[x] for gen in gens: temp = gen[x] if used[temp] == False: slp_dict[temp] = [gens.index(gen)] + px_slp tr.append((temp, _af_rmul(gen, px))) used[temp] = True if pairs: if not af: tr = [(x, _af_new(y)) for x, y in tr] if not slp: return tr return tr, slp_dict if af: tr = [y for _, y in tr] if not slp: return tr return tr, slp_dict tr = [_af_new(y) for _, y in tr] if not slp: return tr return tr, slp_dict def _stabilizer(degree, generators, alpha): r"""Return the stabilizer subgroup of ``alpha``. Explanation =========== The stabilizer of `\alpha` is the group `G_\alpha = \{g \in G | g(\alpha) = \alpha\}`. For a proof of correctness, see [1], p.79. degree : degree of G generators : generators of G Examples ======== >>> from sympy.combinatorics.perm_groups import _stabilizer >>> from sympy.combinatorics.named_groups import DihedralGroup >>> G = DihedralGroup(6) >>> _stabilizer(G.degree, G.generators, 5) [(5)(0 4)(1 3), (5)] See Also ======== orbit """ orb = [alpha] table = {alpha: list(range(degree))} table_inv = {alpha: list(range(degree))} used = [False]*degree used[alpha] = True gens = [x._array_form for x in generators] stab_gens = [] for b in orb: for gen in gens: temp = gen[b] if used[temp] is False: gen_temp = _af_rmul(gen, table[b]) orb.append(temp) table[temp] = gen_temp table_inv[temp] = _af_invert(gen_temp) used[temp] = True else: schreier_gen = _af_rmuln(table_inv[temp], gen, table[b]) if schreier_gen not in stab_gens: stab_gens.append(schreier_gen) return [_af_new(x) for x in stab_gens] PermGroup = PermutationGroup class SymmetricPermutationGroup(Basic): """ The class defining the lazy form of SymmetricGroup. deg : int """ def __new__(cls, deg): deg = _sympify(deg) obj = Basic.__new__(cls, deg) obj._deg = deg obj._order = None return obj def __contains__(self, i): """Return ``True`` if *i* is contained in SymmetricPermutationGroup. Examples ======== >>> from sympy.combinatorics import Permutation, SymmetricPermutationGroup >>> G = SymmetricPermutationGroup(4) >>> Permutation(1, 2, 3) in G True """ if not isinstance(i, Permutation): raise TypeError("A SymmetricPermutationGroup contains only Permutations as " "elements, not elements of type %s" % type(i)) return i.size == self.degree def order(self): """ Return the order of the SymmetricPermutationGroup. Examples ======== >>> from sympy.combinatorics import SymmetricPermutationGroup >>> G = SymmetricPermutationGroup(4) >>> G.order() 24 """ if self._order is not None: return self._order n = self._deg self._order = factorial(n) return self._order @property def degree(self): """ Return the degree of the SymmetricPermutationGroup. Examples ======== >>> from sympy.combinatorics import SymmetricPermutationGroup >>> G = SymmetricPermutationGroup(4) >>> G.degree 4 """ return self._deg @property def identity(self): ''' Return the identity element of the SymmetricPermutationGroup. Examples ======== >>> from sympy.combinatorics import SymmetricPermutationGroup >>> G = SymmetricPermutationGroup(4) >>> G.identity() (3) ''' return _af_new(list(range(self._deg))) class Coset(Basic): """A left coset of a permutation group with respect to an element. Parameters ========== g : Permutation H : PermutationGroup dir : "+" or "-", If not specified by default it will be "+" here ``dir`` specified the type of coset "+" represent the right coset and "-" represent the left coset. G : PermutationGroup, optional The group which contains *H* as its subgroup and *g* as its element. If not specified, it would automatically become a symmetric group ``SymmetricPermutationGroup(g.size)`` and ``SymmetricPermutationGroup(H.degree)`` if ``g.size`` and ``H.degree`` are matching.``SymmetricPermutationGroup`` is a lazy form of SymmetricGroup used for representation purpose. """ def __new__(cls, g, H, G=None, dir="+"): g = _sympify(g) if not isinstance(g, Permutation): raise NotImplementedError H = _sympify(H) if not isinstance(H, PermutationGroup): raise NotImplementedError if G is not None: G = _sympify(G) if not isinstance(G, PermutationGroup) and not isinstance(G, SymmetricPermutationGroup): raise NotImplementedError if not H.is_subgroup(G): raise ValueError("{} must be a subgroup of {}.".format(H, G)) if g not in G: raise ValueError("{} must be an element of {}.".format(g, G)) else: g_size = g.size h_degree = H.degree if g_size != h_degree: raise ValueError( "The size of the permutation {} and the degree of " "the permutation group {} should be matching " .format(g, H)) G = SymmetricPermutationGroup(g.size) if isinstance(dir, str): dir = Symbol(dir) elif not isinstance(dir, Symbol): raise TypeError("dir must be of type basestring or " "Symbol, not %s" % type(dir)) if str(dir) not in ('+', '-'): raise ValueError("dir must be one of '+' or '-' not %s" % dir) obj = Basic.__new__(cls, g, H, G, dir) obj._dir = dir return obj @property def is_left_coset(self): """ Check if the coset is left coset that is ``gH``. Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup, Coset >>> a = Permutation(1, 2) >>> b = Permutation(0, 1) >>> G = PermutationGroup([a, b]) >>> cst = Coset(a, G, dir="-") >>> cst.is_left_coset True """ return str(self._dir) == '-' @property def is_right_coset(self): """ Check if the coset is right coset that is ``Hg``. Examples ======== >>> from sympy.combinatorics import Permutation, PermutationGroup, Coset >>> a = Permutation(1, 2) >>> b = Permutation(0, 1) >>> G = PermutationGroup([a, b]) >>> cst = Coset(a, G, dir="+") >>> cst.is_right_coset True """ return str(self._dir) == '+' def as_list(self): """ Return all the elements of coset in the form of list. """ g = self.args[0] H = self.args[1] cst = [] if str(self._dir) == '+': for h in H.elements: cst.append(h*g) else: for h in H.elements: cst.append(g*h) return cst sympy-sympy-1.9/sympy/combinatorics/permutations.py000066400000000000000000002530371412543434000230560ustar00rootroot00000000000000import random from collections import defaultdict from collections.abc import Iterable from functools import reduce from sympy.core.parameters import global_parameters from sympy.core.basic import Atom from sympy.core.expr import Expr from sympy.core.compatibility import \ is_sequence, as_int from sympy.core.numbers import Integer from sympy.core.sympify import _sympify from sympy.matrices import zeros from sympy.polys.polytools import lcm from sympy.utilities.iterables import (flatten, has_variety, minlex, has_dups, runs) from mpmath.libmp.libintmath import ifac from sympy.multipledispatch import dispatch def _af_rmul(a, b): """ Return the product b*a; input and output are array forms. The ith value is a[b[i]]. Examples ======== >>> from sympy.combinatorics.permutations import _af_rmul, Permutation >>> a, b = [1, 0, 2], [0, 2, 1] >>> _af_rmul(a, b) [1, 2, 0] >>> [a[b[i]] for i in range(3)] [1, 2, 0] This handles the operands in reverse order compared to the ``*`` operator: >>> a = Permutation(a) >>> b = Permutation(b) >>> list(a*b) [2, 0, 1] >>> [b(a(i)) for i in range(3)] [2, 0, 1] See Also ======== rmul, _af_rmuln """ return [a[i] for i in b] def _af_rmuln(*abc): """ Given [a, b, c, ...] return the product of ...*c*b*a using array forms. The ith value is a[b[c[i]]]. Examples ======== >>> from sympy.combinatorics.permutations import _af_rmul, Permutation >>> a, b = [1, 0, 2], [0, 2, 1] >>> _af_rmul(a, b) [1, 2, 0] >>> [a[b[i]] for i in range(3)] [1, 2, 0] This handles the operands in reverse order compared to the ``*`` operator: >>> a = Permutation(a); b = Permutation(b) >>> list(a*b) [2, 0, 1] >>> [b(a(i)) for i in range(3)] [2, 0, 1] See Also ======== rmul, _af_rmul """ a = abc m = len(a) if m == 3: p0, p1, p2 = a return [p0[p1[i]] for i in p2] if m == 4: p0, p1, p2, p3 = a return [p0[p1[p2[i]]] for i in p3] if m == 5: p0, p1, p2, p3, p4 = a return [p0[p1[p2[p3[i]]]] for i in p4] if m == 6: p0, p1, p2, p3, p4, p5 = a return [p0[p1[p2[p3[p4[i]]]]] for i in p5] if m == 7: p0, p1, p2, p3, p4, p5, p6 = a return [p0[p1[p2[p3[p4[p5[i]]]]]] for i in p6] if m == 8: p0, p1, p2, p3, p4, p5, p6, p7 = a return [p0[p1[p2[p3[p4[p5[p6[i]]]]]]] for i in p7] if m == 1: return a[0][:] if m == 2: a, b = a return [a[i] for i in b] if m == 0: raise ValueError("String must not be empty") p0 = _af_rmuln(*a[:m//2]) p1 = _af_rmuln(*a[m//2:]) return [p0[i] for i in p1] def _af_parity(pi): """ Computes the parity of a permutation in array form. Explanation =========== The parity of a permutation reflects the parity of the number of inversions in the permutation, i.e., the number of pairs of x and y such that x > y but p[x] < p[y]. Examples ======== >>> from sympy.combinatorics.permutations import _af_parity >>> _af_parity([0, 1, 2, 3]) 0 >>> _af_parity([3, 2, 0, 1]) 1 See Also ======== Permutation """ n = len(pi) a = [0] * n c = 0 for j in range(n): if a[j] == 0: c += 1 a[j] = 1 i = j while pi[i] != j: i = pi[i] a[i] = 1 return (n - c) % 2 def _af_invert(a): """ Finds the inverse, ~A, of a permutation, A, given in array form. Examples ======== >>> from sympy.combinatorics.permutations import _af_invert, _af_rmul >>> A = [1, 2, 0, 3] >>> _af_invert(A) [2, 0, 1, 3] >>> _af_rmul(_, A) [0, 1, 2, 3] See Also ======== Permutation, __invert__ """ inv_form = [0] * len(a) for i, ai in enumerate(a): inv_form[ai] = i return inv_form def _af_pow(a, n): """ Routine for finding powers of a permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation, _af_pow >>> p = Permutation([2, 0, 3, 1]) >>> p.order() 4 >>> _af_pow(p._array_form, 4) [0, 1, 2, 3] """ if n == 0: return list(range(len(a))) if n < 0: return _af_pow(_af_invert(a), -n) if n == 1: return a[:] elif n == 2: b = [a[i] for i in a] elif n == 3: b = [a[a[i]] for i in a] elif n == 4: b = [a[a[a[i]]] for i in a] else: # use binary multiplication b = list(range(len(a))) while 1: if n & 1: b = [b[i] for i in a] n -= 1 if not n: break if n % 4 == 0: a = [a[a[a[i]]] for i in a] n = n // 4 elif n % 2 == 0: a = [a[i] for i in a] n = n // 2 return b def _af_commutes_with(a, b): """ Checks if the two permutations with array forms given by ``a`` and ``b`` commute. Examples ======== >>> from sympy.combinatorics.permutations import _af_commutes_with >>> _af_commutes_with([1, 2, 0], [0, 2, 1]) False See Also ======== Permutation, commutes_with """ return not any(a[b[i]] != b[a[i]] for i in range(len(a) - 1)) class Cycle(dict): """ Wrapper around dict which provides the functionality of a disjoint cycle. Explanation =========== A cycle shows the rule to use to move subsets of elements to obtain a permutation. The Cycle class is more flexible than Permutation in that 1) all elements need not be present in order to investigate how multiple cycles act in sequence and 2) it can contain singletons: >>> from sympy.combinatorics.permutations import Perm, Cycle A Cycle will automatically parse a cycle given as a tuple on the rhs: >>> Cycle(1, 2)(2, 3) (1 3 2) The identity cycle, Cycle(), can be used to start a product: >>> Cycle()(1, 2)(2, 3) (1 3 2) The array form of a Cycle can be obtained by calling the list method (or passing it to the list function) and all elements from 0 will be shown: >>> a = Cycle(1, 2) >>> a.list() [0, 2, 1] >>> list(a) [0, 2, 1] If a larger (or smaller) range is desired use the list method and provide the desired size -- but the Cycle cannot be truncated to a size smaller than the largest element that is out of place: >>> b = Cycle(2, 4)(1, 2)(3, 1, 4)(1, 3) >>> b.list() [0, 2, 1, 3, 4] >>> b.list(b.size + 1) [0, 2, 1, 3, 4, 5] >>> b.list(-1) [0, 2, 1] Singletons are not shown when printing with one exception: the largest element is always shown -- as a singleton if necessary: >>> Cycle(1, 4, 10)(4, 5) (1 5 4 10) >>> Cycle(1, 2)(4)(5)(10) (1 2)(10) The array form can be used to instantiate a Permutation so other properties of the permutation can be investigated: >>> Perm(Cycle(1, 2)(3, 4).list()).transpositions() [(1, 2), (3, 4)] Notes ===== The underlying structure of the Cycle is a dictionary and although the __iter__ method has been redefined to give the array form of the cycle, the underlying dictionary items are still available with the such methods as items(): >>> list(Cycle(1, 2).items()) [(1, 2), (2, 1)] See Also ======== Permutation """ def __missing__(self, arg): """Enter arg into dictionary and return arg.""" return as_int(arg) def __iter__(self): yield from self.list() def __call__(self, *other): """Return product of cycles processed from R to L. Examples ======== >>> from sympy.combinatorics.permutations import Cycle as C >>> C(1, 2)(2, 3) (1 3 2) An instance of a Cycle will automatically parse list-like objects and Permutations that are on the right. It is more flexible than the Permutation in that all elements need not be present: >>> a = C(1, 2) >>> a(2, 3) (1 3 2) >>> a(2, 3)(4, 5) (1 3 2)(4 5) """ rv = Cycle(*other) for k, v in zip(list(self.keys()), [rv[self[k]] for k in self.keys()]): rv[k] = v return rv def list(self, size=None): """Return the cycles as an explicit list starting from 0 up to the greater of the largest value in the cycles and size. Truncation of trailing unmoved items will occur when size is less than the maximum element in the cycle; if this is desired, setting ``size=-1`` will guarantee such trimming. Examples ======== >>> from sympy.combinatorics.permutations import Cycle >>> p = Cycle(2, 3)(4, 5) >>> p.list() [0, 1, 3, 2, 5, 4] >>> p.list(10) [0, 1, 3, 2, 5, 4, 6, 7, 8, 9] Passing a length too small will trim trailing, unchanged elements in the permutation: >>> Cycle(2, 4)(1, 2, 4).list(-1) [0, 2, 1] """ if not self and size is None: raise ValueError('must give size for empty Cycle') if size is not None: big = max([i for i in self.keys() if self[i] != i] + [0]) size = max(size, big + 1) else: size = self.size return [self[i] for i in range(size)] def __repr__(self): """We want it to print as a Cycle, not as a dict. Examples ======== >>> from sympy.combinatorics import Cycle >>> Cycle(1, 2) (1 2) >>> print(_) (1 2) >>> list(Cycle(1, 2).items()) [(1, 2), (2, 1)] """ if not self: return 'Cycle()' cycles = Permutation(self).cyclic_form s = ''.join(str(tuple(c)) for c in cycles) big = self.size - 1 if not any(i == big for c in cycles for i in c): s += '(%s)' % big return 'Cycle%s' % s def __str__(self): """We want it to be printed in a Cycle notation with no comma in-between. Examples ======== >>> from sympy.combinatorics import Cycle >>> Cycle(1, 2) (1 2) >>> Cycle(1, 2, 4)(5, 6) (1 2 4)(5 6) """ if not self: return '()' cycles = Permutation(self).cyclic_form s = ''.join(str(tuple(c)) for c in cycles) big = self.size - 1 if not any(i == big for c in cycles for i in c): s += '(%s)' % big s = s.replace(',', '') return s def __init__(self, *args): """Load up a Cycle instance with the values for the cycle. Examples ======== >>> from sympy.combinatorics.permutations import Cycle >>> Cycle(1, 2, 6) (1 2 6) """ if not args: return if len(args) == 1: if isinstance(args[0], Permutation): for c in args[0].cyclic_form: self.update(self(*c)) return elif isinstance(args[0], Cycle): for k, v in args[0].items(): self[k] = v return args = [as_int(a) for a in args] if any(i < 0 for i in args): raise ValueError('negative integers are not allowed in a cycle.') if has_dups(args): raise ValueError('All elements must be unique in a cycle.') for i in range(-len(args), 0): self[args[i]] = args[i + 1] @property def size(self): if not self: return 0 return max(self.keys()) + 1 def copy(self): return Cycle(self) class Permutation(Atom): """ A permutation, alternatively known as an 'arrangement number' or 'ordering' is an arrangement of the elements of an ordered list into a one-to-one mapping with itself. The permutation of a given arrangement is given by indicating the positions of the elements after re-arrangement [2]_. For example, if one started with elements [x, y, a, b] (in that order) and they were reordered as [x, y, b, a] then the permutation would be [0, 1, 3, 2]. Notice that (in SymPy) the first element is always referred to as 0 and the permutation uses the indices of the elements in the original ordering, not the elements (a, b, etc...) themselves. >>> from sympy.combinatorics import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) Permutations Notation ===================== Permutations are commonly represented in disjoint cycle or array forms. Array Notation and 2-line Form ------------------------------------ In the 2-line form, the elements and their final positions are shown as a matrix with 2 rows: [0 1 2 ... n-1] [p(0) p(1) p(2) ... p(n-1)] Since the first line is always range(n), where n is the size of p, it is sufficient to represent the permutation by the second line, referred to as the "array form" of the permutation. This is entered in brackets as the argument to the Permutation class: >>> p = Permutation([0, 2, 1]); p Permutation([0, 2, 1]) Given i in range(p.size), the permutation maps i to i^p >>> [i^p for i in range(p.size)] [0, 2, 1] The composite of two permutations p*q means first apply p, then q, so i^(p*q) = (i^p)^q which is i^p^q according to Python precedence rules: >>> q = Permutation([2, 1, 0]) >>> [i^p^q for i in range(3)] [2, 0, 1] >>> [i^(p*q) for i in range(3)] [2, 0, 1] One can use also the notation p(i) = i^p, but then the composition rule is (p*q)(i) = q(p(i)), not p(q(i)): >>> [(p*q)(i) for i in range(p.size)] [2, 0, 1] >>> [q(p(i)) for i in range(p.size)] [2, 0, 1] >>> [p(q(i)) for i in range(p.size)] [1, 2, 0] Disjoint Cycle Notation ----------------------- In disjoint cycle notation, only the elements that have shifted are indicated. In the above case, the 2 and 1 switched places. This can be entered in two ways: >>> Permutation(1, 2) == Permutation([[1, 2]]) == p True Only the relative ordering of elements in a cycle matter: >>> Permutation(1,2,3) == Permutation(2,3,1) == Permutation(3,1,2) True The disjoint cycle notation is convenient when representing permutations that have several cycles in them: >>> Permutation(1, 2)(3, 5) == Permutation([[1, 2], [3, 5]]) True It also provides some economy in entry when computing products of permutations that are written in disjoint cycle notation: >>> Permutation(1, 2)(1, 3)(2, 3) Permutation([0, 3, 2, 1]) >>> _ == Permutation([[1, 2]])*Permutation([[1, 3]])*Permutation([[2, 3]]) True Caution: when the cycles have common elements between them then the order in which the permutations are applied matters. The convention is that the permutations are applied from *right to left*. In the following, the transposition of elements 2 and 3 is followed by the transposition of elements 1 and 2: >>> Permutation(1, 2)(2, 3) == Permutation([(1, 2), (2, 3)]) True >>> Permutation(1, 2)(2, 3).list() [0, 3, 1, 2] If the first and second elements had been swapped first, followed by the swapping of the second and third, the result would have been [0, 2, 3, 1]. If, for some reason, you want to apply the cycles in the order they are entered, you can simply reverse the order of cycles: >>> Permutation([(1, 2), (2, 3)][::-1]).list() [0, 2, 3, 1] Entering a singleton in a permutation is a way to indicate the size of the permutation. The ``size`` keyword can also be used. Array-form entry: >>> Permutation([[1, 2], [9]]) Permutation([0, 2, 1], size=10) >>> Permutation([[1, 2]], size=10) Permutation([0, 2, 1], size=10) Cyclic-form entry: >>> Permutation(1, 2, size=10) Permutation([0, 2, 1], size=10) >>> Permutation(9)(1, 2) Permutation([0, 2, 1], size=10) Caution: no singleton containing an element larger than the largest in any previous cycle can be entered. This is an important difference in how Permutation and Cycle handle the __call__ syntax. A singleton argument at the start of a Permutation performs instantiation of the Permutation and is permitted: >>> Permutation(5) Permutation([], size=6) A singleton entered after instantiation is a call to the permutation -- a function call -- and if the argument is out of range it will trigger an error. For this reason, it is better to start the cycle with the singleton: The following fails because there is no element 3: >>> Permutation(1, 2)(3) Traceback (most recent call last): ... IndexError: list index out of range This is ok: only the call to an out of range singleton is prohibited; otherwise the permutation autosizes: >>> Permutation(3)(1, 2) Permutation([0, 2, 1, 3]) >>> Permutation(1, 2)(3, 4) == Permutation(3, 4)(1, 2) True Equality testing ---------------- The array forms must be the same in order for permutations to be equal: >>> Permutation([1, 0, 2, 3]) == Permutation([1, 0]) False Identity Permutation -------------------- The identity permutation is a permutation in which no element is out of place. It can be entered in a variety of ways. All the following create an identity permutation of size 4: >>> I = Permutation([0, 1, 2, 3]) >>> all(p == I for p in [ ... Permutation(3), ... Permutation(range(4)), ... Permutation([], size=4), ... Permutation(size=4)]) True Watch out for entering the range *inside* a set of brackets (which is cycle notation): >>> I == Permutation([range(4)]) False Permutation Printing ==================== There are a few things to note about how Permutations are printed. 1) If you prefer one form (array or cycle) over another, you can set ``init_printing`` with the ``perm_cyclic`` flag. >>> from sympy import init_printing >>> p = Permutation(1, 2)(4, 5)(3, 4) >>> p Permutation([0, 2, 1, 4, 5, 3]) >>> init_printing(perm_cyclic=True, pretty_print=False) >>> p (1 2)(3 4 5) 2) Regardless of the setting, a list of elements in the array for cyclic form can be obtained and either of those can be copied and supplied as the argument to Permutation: >>> p.array_form [0, 2, 1, 4, 5, 3] >>> p.cyclic_form [[1, 2], [3, 4, 5]] >>> Permutation(_) == p True 3) Printing is economical in that as little as possible is printed while retaining all information about the size of the permutation: >>> init_printing(perm_cyclic=False, pretty_print=False) >>> Permutation([1, 0, 2, 3]) Permutation([1, 0, 2, 3]) >>> Permutation([1, 0, 2, 3], size=20) Permutation([1, 0], size=20) >>> Permutation([1, 0, 2, 4, 3, 5, 6], size=20) Permutation([1, 0, 2, 4, 3], size=20) >>> p = Permutation([1, 0, 2, 3]) >>> init_printing(perm_cyclic=True, pretty_print=False) >>> p (3)(0 1) >>> init_printing(perm_cyclic=False, pretty_print=False) The 2 was not printed but it is still there as can be seen with the array_form and size methods: >>> p.array_form [1, 0, 2, 3] >>> p.size 4 Short introduction to other methods =================================== The permutation can act as a bijective function, telling what element is located at a given position >>> q = Permutation([5, 2, 3, 4, 1, 0]) >>> q.array_form[1] # the hard way 2 >>> q(1) # the easy way 2 >>> {i: q(i) for i in range(q.size)} # showing the bijection {0: 5, 1: 2, 2: 3, 3: 4, 4: 1, 5: 0} The full cyclic form (including singletons) can be obtained: >>> p.full_cyclic_form [[0, 1], [2], [3]] Any permutation can be factored into transpositions of pairs of elements: >>> Permutation([[1, 2], [3, 4, 5]]).transpositions() [(1, 2), (3, 5), (3, 4)] >>> Permutation.rmul(*[Permutation([ti], size=6) for ti in _]).cyclic_form [[1, 2], [3, 4, 5]] The number of permutations on a set of n elements is given by n! and is called the cardinality. >>> p.size 4 >>> p.cardinality 24 A given permutation has a rank among all the possible permutations of the same elements, but what that rank is depends on how the permutations are enumerated. (There are a number of different methods of doing so.) The lexicographic rank is given by the rank method and this rank is used to increment a permutation with addition/subtraction: >>> p.rank() 6 >>> p + 1 Permutation([1, 0, 3, 2]) >>> p.next_lex() Permutation([1, 0, 3, 2]) >>> _.rank() 7 >>> p.unrank_lex(p.size, rank=7) Permutation([1, 0, 3, 2]) The product of two permutations p and q is defined as their composition as functions, (p*q)(i) = q(p(i)) [6]_. >>> p = Permutation([1, 0, 2, 3]) >>> q = Permutation([2, 3, 1, 0]) >>> list(q*p) [2, 3, 0, 1] >>> list(p*q) [3, 2, 1, 0] >>> [q(p(i)) for i in range(p.size)] [3, 2, 1, 0] The permutation can be 'applied' to any list-like object, not only Permutations: >>> p(['zero', 'one', 'four', 'two']) ['one', 'zero', 'four', 'two'] >>> p('zo42') ['o', 'z', '4', '2'] If you have a list of arbitrary elements, the corresponding permutation can be found with the from_sequence method: >>> Permutation.from_sequence('SymPy') Permutation([1, 3, 2, 0, 4]) Checking if a Permutation is contained in a Group ================================================= Generally if you have a group of permutations G on n symbols, and you're checking if a permutation on less than n symbols is part of that group, the check will fail. Here is an example for n=5 and we check if the cycle (1,2,3) is in G: >>> from sympy import init_printing >>> init_printing(perm_cyclic=True, pretty_print=False) >>> from sympy.combinatorics import Cycle, Permutation >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> G = PermutationGroup(Cycle(2, 3)(4, 5), Cycle(1, 2, 3, 4, 5)) >>> p1 = Permutation(Cycle(2, 5, 3)) >>> p2 = Permutation(Cycle(1, 2, 3)) >>> a1 = Permutation(Cycle(1, 2, 3).list(6)) >>> a2 = Permutation(Cycle(1, 2, 3)(5)) >>> a3 = Permutation(Cycle(1, 2, 3),size=6) >>> for p in [p1,p2,a1,a2,a3]: p, G.contains(p) ((2 5 3), True) ((1 2 3), False) ((5)(1 2 3), True) ((5)(1 2 3), True) ((5)(1 2 3), True) The check for p2 above will fail. Checking if p1 is in G works because SymPy knows G is a group on 5 symbols, and p1 is also on 5 symbols (its largest element is 5). For ``a1``, the ``.list(6)`` call will extend the permutation to 5 symbols, so the test will work as well. In the case of ``a2`` the permutation is being extended to 5 symbols by using a singleton, and in the case of ``a3`` it's extended through the constructor argument ``size=6``. There is another way to do this, which is to tell the ``contains`` method that the number of symbols the group is on doesn't need to match perfectly the number of symbols for the permutation: >>> G.contains(p2,strict=False) True This can be via the ``strict`` argument to the ``contains`` method, and SymPy will try to extend the permutation on its own and then perform the containment check. See Also ======== Cycle References ========== .. [1] Skiena, S. 'Permutations.' 1.1 in Implementing Discrete Mathematics Combinatorics and Graph Theory with Mathematica. Reading, MA: Addison-Wesley, pp. 3-16, 1990. .. [2] Knuth, D. E. The Art of Computer Programming, Vol. 4: Combinatorial Algorithms, 1st ed. Reading, MA: Addison-Wesley, 2011. .. [3] Wendy Myrvold and Frank Ruskey. 2001. Ranking and unranking permutations in linear time. Inf. Process. Lett. 79, 6 (September 2001), 281-284. DOI=10.1016/S0020-0190(01)00141-7 .. [4] D. L. Kreher, D. R. Stinson 'Combinatorial Algorithms' CRC Press, 1999 .. [5] Graham, R. L.; Knuth, D. E.; and Patashnik, O. Concrete Mathematics: A Foundation for Computer Science, 2nd ed. Reading, MA: Addison-Wesley, 1994. .. [6] https://en.wikipedia.org/wiki/Permutation#Product_and_inverse .. [7] https://en.wikipedia.org/wiki/Lehmer_code """ is_Permutation = True _array_form = None _cyclic_form = None _cycle_structure = None _size = None _rank = None def __new__(cls, *args, size=None, **kwargs): """ Constructor for the Permutation object from a list or a list of lists in which all elements of the permutation may appear only once. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) Permutations entered in array-form are left unaltered: >>> Permutation([0, 2, 1]) Permutation([0, 2, 1]) Permutations entered in cyclic form are converted to array form; singletons need not be entered, but can be entered to indicate the largest element: >>> Permutation([[4, 5, 6], [0, 1]]) Permutation([1, 0, 2, 3, 5, 6, 4]) >>> Permutation([[4, 5, 6], [0, 1], [19]]) Permutation([1, 0, 2, 3, 5, 6, 4], size=20) All manipulation of permutations assumes that the smallest element is 0 (in keeping with 0-based indexing in Python) so if the 0 is missing when entering a permutation in array form, an error will be raised: >>> Permutation([2, 1]) Traceback (most recent call last): ... ValueError: Integers 0 through 2 must be present. If a permutation is entered in cyclic form, it can be entered without singletons and the ``size`` specified so those values can be filled in, otherwise the array form will only extend to the maximum value in the cycles: >>> Permutation([[1, 4], [3, 5, 2]], size=10) Permutation([0, 4, 3, 5, 1, 2], size=10) >>> _.array_form [0, 4, 3, 5, 1, 2, 6, 7, 8, 9] """ if size is not None: size = int(size) #a) () #b) (1) = identity #c) (1, 2) = cycle #d) ([1, 2, 3]) = array form #e) ([[1, 2]]) = cyclic form #f) (Cycle) = conversion to permutation #g) (Permutation) = adjust size or return copy ok = True if not args: # a return cls._af_new(list(range(size or 0))) elif len(args) > 1: # c return cls._af_new(Cycle(*args).list(size)) if len(args) == 1: a = args[0] if isinstance(a, cls): # g if size is None or size == a.size: return a return cls(a.array_form, size=size) if isinstance(a, Cycle): # f return cls._af_new(a.list(size)) if not is_sequence(a): # b if size is not None and a + 1 > size: raise ValueError('size is too small when max is %s' % a) return cls._af_new(list(range(a + 1))) if has_variety(is_sequence(ai) for ai in a): ok = False else: ok = False if not ok: raise ValueError("Permutation argument must be a list of ints, " "a list of lists, Permutation or Cycle.") # safe to assume args are valid; this also makes a copy # of the args args = list(args[0]) is_cycle = args and is_sequence(args[0]) if is_cycle: # e args = [[int(i) for i in c] for c in args] else: # d args = [int(i) for i in args] # if there are n elements present, 0, 1, ..., n-1 should be present # unless a cycle notation has been provided. A 0 will be added # for convenience in case one wants to enter permutations where # counting starts from 1. temp = flatten(args) if has_dups(temp) and not is_cycle: raise ValueError('there were repeated elements.') temp = set(temp) if not is_cycle: if any(i not in temp for i in range(len(temp))): raise ValueError('Integers 0 through %s must be present.' % max(temp)) if size is not None and temp and max(temp) + 1 > size: raise ValueError('max element should not exceed %s' % (size - 1)) if is_cycle: # it's not necessarily canonical so we won't store # it -- use the array form instead c = Cycle() for ci in args: c = c(*ci) aform = c.list() else: aform = list(args) if size and size > len(aform): # don't allow for truncation of permutation which # might split a cycle and lead to an invalid aform # but do allow the permutation size to be increased aform.extend(list(range(len(aform), size))) return cls._af_new(aform) @classmethod def _af_new(cls, perm): """A method to produce a Permutation object from a list; the list is bound to the _array_form attribute, so it must not be modified; this method is meant for internal use only; the list ``a`` is supposed to be generated as a temporary value in a method, so p = Perm._af_new(a) is the only object to hold a reference to ``a``:: Examples ======== >>> from sympy.combinatorics.permutations import Perm >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> a = [2, 1, 3, 0] >>> p = Perm._af_new(a) >>> p Permutation([2, 1, 3, 0]) """ p = super().__new__(cls) p._array_form = perm p._size = len(perm) return p def _hashable_content(self): # the array_form (a list) is the Permutation arg, so we need to # return a tuple, instead return tuple(self.array_form) @property def array_form(self): """ Return a copy of the attribute _array_form Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([[2, 0], [3, 1]]) >>> p.array_form [2, 3, 0, 1] >>> Permutation([[2, 0, 3, 1]]).array_form [3, 2, 0, 1] >>> Permutation([2, 0, 3, 1]).array_form [2, 0, 3, 1] >>> Permutation([[1, 2], [4, 5]]).array_form [0, 2, 1, 3, 5, 4] """ return self._array_form[:] def list(self, size=None): """Return the permutation as an explicit list, possibly trimming unmoved elements if size is less than the maximum element in the permutation; if this is desired, setting ``size=-1`` will guarantee such trimming. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation(2, 3)(4, 5) >>> p.list() [0, 1, 3, 2, 5, 4] >>> p.list(10) [0, 1, 3, 2, 5, 4, 6, 7, 8, 9] Passing a length too small will trim trailing, unchanged elements in the permutation: >>> Permutation(2, 4)(1, 2, 4).list(-1) [0, 2, 1] >>> Permutation(3).list(-1) [] """ if not self and size is None: raise ValueError('must give size for empty Cycle') rv = self.array_form if size is not None: if size > self.size: rv.extend(list(range(self.size, size))) else: # find first value from rhs where rv[i] != i i = self.size - 1 while rv: if rv[-1] != i: break rv.pop() i -= 1 return rv @property def cyclic_form(self): """ This is used to convert to the cyclic notation from the canonical notation. Singletons are omitted. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 3, 1, 2]) >>> p.cyclic_form [[1, 3, 2]] >>> Permutation([1, 0, 2, 4, 3, 5]).cyclic_form [[0, 1], [3, 4]] See Also ======== array_form, full_cyclic_form """ if self._cyclic_form is not None: return list(self._cyclic_form) array_form = self.array_form unchecked = [True] * len(array_form) cyclic_form = [] for i in range(len(array_form)): if unchecked[i]: cycle = [] cycle.append(i) unchecked[i] = False j = i while unchecked[array_form[j]]: j = array_form[j] cycle.append(j) unchecked[j] = False if len(cycle) > 1: cyclic_form.append(cycle) assert cycle == list(minlex(cycle)) cyclic_form.sort() self._cyclic_form = cyclic_form[:] return cyclic_form @property def full_cyclic_form(self): """Return permutation in cyclic form including singletons. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> Permutation([0, 2, 1]).full_cyclic_form [[0], [1, 2]] """ need = set(range(self.size)) - set(flatten(self.cyclic_form)) rv = self.cyclic_form rv.extend([[i] for i in need]) rv.sort() return rv @property def size(self): """ Returns the number of elements in the permutation. Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation([[3, 2], [0, 1]]).size 4 See Also ======== cardinality, length, order, rank """ return self._size def support(self): """Return the elements in permutation, P, for which P[i] != i. Examples ======== >>> from sympy.combinatorics import Permutation >>> p = Permutation([[3, 2], [0, 1], [4]]) >>> p.array_form [1, 0, 3, 2, 4] >>> p.support() [0, 1, 2, 3] """ a = self.array_form return [i for i, e in enumerate(a) if a[i] != i] def __add__(self, other): """Return permutation that is other higher in rank than self. The rank is the lexicographical rank, with the identity permutation having rank of 0. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> I = Permutation([0, 1, 2, 3]) >>> a = Permutation([2, 1, 3, 0]) >>> I + a.rank() == a True See Also ======== __sub__, inversion_vector """ rank = (self.rank() + other) % self.cardinality rv = self.unrank_lex(self.size, rank) rv._rank = rank return rv def __sub__(self, other): """Return the permutation that is other lower in rank than self. See Also ======== __add__ """ return self.__add__(-other) @staticmethod def rmul(*args): """ Return product of Permutations [a, b, c, ...] as the Permutation whose ith value is a(b(c(i))). a, b, c, ... can be Permutation objects or tuples. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> a, b = [1, 0, 2], [0, 2, 1] >>> a = Permutation(a); b = Permutation(b) >>> list(Permutation.rmul(a, b)) [1, 2, 0] >>> [a(b(i)) for i in range(3)] [1, 2, 0] This handles the operands in reverse order compared to the ``*`` operator: >>> a = Permutation(a); b = Permutation(b) >>> list(a*b) [2, 0, 1] >>> [b(a(i)) for i in range(3)] [2, 0, 1] Notes ===== All items in the sequence will be parsed by Permutation as necessary as long as the first item is a Permutation: >>> Permutation.rmul(a, [0, 2, 1]) == Permutation.rmul(a, b) True The reverse order of arguments will raise a TypeError. """ rv = args[0] for i in range(1, len(args)): rv = args[i]*rv return rv @classmethod def rmul_with_af(cls, *args): """ same as rmul, but the elements of args are Permutation objects which have _array_form """ a = [x._array_form for x in args] rv = cls._af_new(_af_rmuln(*a)) return rv def mul_inv(self, other): """ other*~self, self and other have _array_form """ a = _af_invert(self._array_form) b = other._array_form return self._af_new(_af_rmul(a, b)) def __rmul__(self, other): """This is needed to coerce other to Permutation in rmul.""" cls = type(self) return cls(other)*self def __mul__(self, other): """ Return the product a*b as a Permutation; the ith value is b(a(i)). Examples ======== >>> from sympy.combinatorics.permutations import _af_rmul, Permutation >>> a, b = [1, 0, 2], [0, 2, 1] >>> a = Permutation(a); b = Permutation(b) >>> list(a*b) [2, 0, 1] >>> [b(a(i)) for i in range(3)] [2, 0, 1] This handles operands in reverse order compared to _af_rmul and rmul: >>> al = list(a); bl = list(b) >>> _af_rmul(al, bl) [1, 2, 0] >>> [al[bl[i]] for i in range(3)] [1, 2, 0] It is acceptable for the arrays to have different lengths; the shorter one will be padded to match the longer one: >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> b*Permutation([1, 0]) Permutation([1, 2, 0]) >>> Permutation([1, 0])*b Permutation([2, 0, 1]) It is also acceptable to allow coercion to handle conversion of a single list to the left of a Permutation: >>> [0, 1]*a # no change: 2-element identity Permutation([1, 0, 2]) >>> [[0, 1]]*a # exchange first two elements Permutation([0, 1, 2]) You cannot use more than 1 cycle notation in a product of cycles since coercion can only handle one argument to the left. To handle multiple cycles it is convenient to use Cycle instead of Permutation: >>> [[1, 2]]*[[2, 3]]*Permutation([]) # doctest: +SKIP >>> from sympy.combinatorics.permutations import Cycle >>> Cycle(1, 2)(2, 3) (1 3 2) """ from sympy.combinatorics.perm_groups import PermutationGroup, Coset if isinstance(other, PermutationGroup): return Coset(self, other, dir='-') a = self.array_form # __rmul__ makes sure the other is a Permutation b = other.array_form if not b: perm = a else: b.extend(list(range(len(b), len(a)))) perm = [b[i] for i in a] + b[len(a):] return self._af_new(perm) def commutes_with(self, other): """ Checks if the elements are commuting. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> a = Permutation([1, 4, 3, 0, 2, 5]) >>> b = Permutation([0, 1, 2, 3, 4, 5]) >>> a.commutes_with(b) True >>> b = Permutation([2, 3, 5, 4, 1, 0]) >>> a.commutes_with(b) False """ a = self.array_form b = other.array_form return _af_commutes_with(a, b) def __pow__(self, n): """ Routine for finding powers of a permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> p = Permutation([2, 0, 3, 1]) >>> p.order() 4 >>> p**4 Permutation([0, 1, 2, 3]) """ if isinstance(n, Permutation): raise NotImplementedError( 'p**p is not defined; do you mean p^p (conjugate)?') n = int(n) return self._af_new(_af_pow(self.array_form, n)) def __rxor__(self, i): """Return self(i) when ``i`` is an int. Examples ======== >>> from sympy.combinatorics import Permutation >>> p = Permutation(1, 2, 9) >>> 2^p == p(2) == 9 True """ if int(i) == i: return self(i) else: raise NotImplementedError( "i^p = p(i) when i is an integer, not %s." % i) def __xor__(self, h): """Return the conjugate permutation ``~h*self*h` `. Explanation =========== If ``a`` and ``b`` are conjugates, ``a = h*b*~h`` and ``b = ~h*a*h`` and both have the same cycle structure. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation(1, 2, 9) >>> q = Permutation(6, 9, 8) >>> p*q != q*p True Calculate and check properties of the conjugate: >>> c = p^q >>> c == ~q*p*q and p == q*c*~q True The expression q^p^r is equivalent to q^(p*r): >>> r = Permutation(9)(4, 6, 8) >>> q^p^r == q^(p*r) True If the term to the left of the conjugate operator, i, is an integer then this is interpreted as selecting the ith element from the permutation to the right: >>> all(i^p == p(i) for i in range(p.size)) True Note that the * operator as higher precedence than the ^ operator: >>> q^r*p^r == q^(r*p)^r == Permutation(9)(1, 6, 4) True Notes ===== In Python the precedence rule is p^q^r = (p^q)^r which differs in general from p^(q^r) >>> q^p^r (9)(1 4 8) >>> q^(p^r) (9)(1 8 6) For a given r and p, both of the following are conjugates of p: ~r*p*r and r*p*~r. But these are not necessarily the same: >>> ~r*p*r == r*p*~r True >>> p = Permutation(1, 2, 9)(5, 6) >>> ~r*p*r == r*p*~r False The conjugate ~r*p*r was chosen so that ``p^q^r`` would be equivalent to ``p^(q*r)`` rather than ``p^(r*q)``. To obtain r*p*~r, pass ~r to this method: >>> p^~r == r*p*~r True """ if self.size != h.size: raise ValueError("The permutations must be of equal size.") a = [None]*self.size h = h._array_form p = self._array_form for i in range(self.size): a[h[i]] = h[p[i]] return self._af_new(a) def transpositions(self): """ Return the permutation decomposed into a list of transpositions. Explanation =========== It is always possible to express a permutation as the product of transpositions, see [1] Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([[1, 2, 3], [0, 4, 5, 6, 7]]) >>> t = p.transpositions() >>> t [(0, 7), (0, 6), (0, 5), (0, 4), (1, 3), (1, 2)] >>> print(''.join(str(c) for c in t)) (0, 7)(0, 6)(0, 5)(0, 4)(1, 3)(1, 2) >>> Permutation.rmul(*[Permutation([ti], size=p.size) for ti in t]) == p True References ========== .. [1] https://en.wikipedia.org/wiki/Transposition_%28mathematics%29#Properties """ a = self.cyclic_form res = [] for x in a: nx = len(x) if nx == 2: res.append(tuple(x)) elif nx > 2: first = x[0] for y in x[nx - 1:0:-1]: res.append((first, y)) return res @classmethod def from_sequence(self, i, key=None): """Return the permutation needed to obtain ``i`` from the sorted elements of ``i``. If custom sorting is desired, a key can be given. Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation.from_sequence('SymPy') (4)(0 1 3) >>> _(sorted("SymPy")) ['S', 'y', 'm', 'P', 'y'] >>> Permutation.from_sequence('SymPy', key=lambda x: x.lower()) (4)(0 2)(1 3) """ ic = list(zip(i, list(range(len(i))))) if key: ic.sort(key=lambda x: key(x[0])) else: ic.sort() return ~Permutation([i[1] for i in ic]) def __invert__(self): """ Return the inverse of the permutation. A permutation multiplied by its inverse is the identity permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> p = Permutation([[2, 0], [3, 1]]) >>> ~p Permutation([2, 3, 0, 1]) >>> _ == p**-1 True >>> p*~p == ~p*p == Permutation([0, 1, 2, 3]) True """ return self._af_new(_af_invert(self._array_form)) def __iter__(self): """Yield elements from array form. Examples ======== >>> from sympy.combinatorics import Permutation >>> list(Permutation(range(3))) [0, 1, 2] """ yield from self.array_form def __repr__(self): from sympy.printing.repr import srepr return srepr(self) def __call__(self, *i): """ Allows applying a permutation instance as a bijective function. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([[2, 0], [3, 1]]) >>> p.array_form [2, 3, 0, 1] >>> [p(i) for i in range(4)] [2, 3, 0, 1] If an array is given then the permutation selects the items from the array (i.e. the permutation is applied to the array): >>> from sympy.abc import x >>> p([x, 1, 0, x**2]) [0, x**2, x, 1] """ # list indices can be Integer or int; leave this # as it is (don't test or convert it) because this # gets called a lot and should be fast if len(i) == 1: i = i[0] if not isinstance(i, Iterable): i = as_int(i) if i < 0 or i > self.size: raise TypeError( "{} should be an integer between 0 and {}" .format(i, self.size-1)) return self._array_form[i] # P([a, b, c]) if len(i) != self.size: raise TypeError( "{} should have the length {}.".format(i, self.size)) return [i[j] for j in self._array_form] # P(1, 2, 3) return self*Permutation(Cycle(*i), size=self.size) def atoms(self): """ Returns all the elements of a permutation Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation([0, 1, 2, 3, 4, 5]).atoms() {0, 1, 2, 3, 4, 5} >>> Permutation([[0, 1], [2, 3], [4, 5]]).atoms() {0, 1, 2, 3, 4, 5} """ return set(self.array_form) def apply(self, i): r"""Apply the permutation to an expression. Parameters ========== i : Expr It should be an integer between $0$ and $n-1$ where $n$ is the size of the permutation. If it is a symbol or a symbolic expression that can have integer values, an ``AppliedPermutation`` object will be returned which can represent an unevaluated function. Notes ===== Any permutation can be defined as a bijective function $\sigma : \{ 0, 1, ..., n-1 \} \rightarrow \{ 0, 1, ..., n-1 \}$ where $n$ denotes the size of the permutation. The definition may even be extended for any set with distinctive elements, such that the permutation can even be applied for real numbers or such, however, it is not implemented for now for computational reasons and the integrity with the group theory module. This function is similar to the ``__call__`` magic, however, ``__call__`` magic already has some other applications like permuting an array or attatching new cycles, which would not always be mathematically consistent. This also guarantees that the return type is a SymPy integer, which guarantees the safety to use assumptions. """ i = _sympify(i) if i.is_integer is False: raise NotImplementedError("{} should be an integer.".format(i)) n = self.size if (i < 0) == True or (i >= n) == True: raise NotImplementedError( "{} should be an integer between 0 and {}".format(i, n-1)) if i.is_Integer: return Integer(self._array_form[i]) return AppliedPermutation(self, i) def next_lex(self): """ Returns the next permutation in lexicographical order. If self is the last permutation in lexicographical order it returns None. See [4] section 2.4. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([2, 3, 1, 0]) >>> p = Permutation([2, 3, 1, 0]); p.rank() 17 >>> p = p.next_lex(); p.rank() 18 See Also ======== rank, unrank_lex """ perm = self.array_form[:] n = len(perm) i = n - 2 while perm[i + 1] < perm[i]: i -= 1 if i == -1: return None else: j = n - 1 while perm[j] < perm[i]: j -= 1 perm[j], perm[i] = perm[i], perm[j] i += 1 j = n - 1 while i < j: perm[j], perm[i] = perm[i], perm[j] i += 1 j -= 1 return self._af_new(perm) @classmethod def unrank_nonlex(self, n, r): """ This is a linear time unranking algorithm that does not respect lexicographic order [3]. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> Permutation.unrank_nonlex(4, 5) Permutation([2, 0, 3, 1]) >>> Permutation.unrank_nonlex(4, -1) Permutation([0, 1, 2, 3]) See Also ======== next_nonlex, rank_nonlex """ def _unrank1(n, r, a): if n > 0: a[n - 1], a[r % n] = a[r % n], a[n - 1] _unrank1(n - 1, r//n, a) id_perm = list(range(n)) n = int(n) r = r % ifac(n) _unrank1(n, r, id_perm) return self._af_new(id_perm) def rank_nonlex(self, inv_perm=None): """ This is a linear time ranking algorithm that does not enforce lexicographic order [3]. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3]) >>> p.rank_nonlex() 23 See Also ======== next_nonlex, unrank_nonlex """ def _rank1(n, perm, inv_perm): if n == 1: return 0 s = perm[n - 1] t = inv_perm[n - 1] perm[n - 1], perm[t] = perm[t], s inv_perm[n - 1], inv_perm[s] = inv_perm[s], t return s + n*_rank1(n - 1, perm, inv_perm) if inv_perm is None: inv_perm = (~self).array_form if not inv_perm: return 0 perm = self.array_form[:] r = _rank1(len(perm), perm, inv_perm) return r def next_nonlex(self): """ Returns the next permutation in nonlex order [3]. If self is the last permutation in this order it returns None. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> p = Permutation([2, 0, 3, 1]); p.rank_nonlex() 5 >>> p = p.next_nonlex(); p Permutation([3, 0, 1, 2]) >>> p.rank_nonlex() 6 See Also ======== rank_nonlex, unrank_nonlex """ r = self.rank_nonlex() if r == ifac(self.size) - 1: return None return self.unrank_nonlex(self.size, r + 1) def rank(self): """ Returns the lexicographic rank of the permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3]) >>> p.rank() 0 >>> p = Permutation([3, 2, 1, 0]) >>> p.rank() 23 See Also ======== next_lex, unrank_lex, cardinality, length, order, size """ if not self._rank is None: return self._rank rank = 0 rho = self.array_form[:] n = self.size - 1 size = n + 1 psize = int(ifac(n)) for j in range(size - 1): rank += rho[j]*psize for i in range(j + 1, size): if rho[i] > rho[j]: rho[i] -= 1 psize //= n n -= 1 self._rank = rank return rank @property def cardinality(self): """ Returns the number of all possible permutations. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3]) >>> p.cardinality 24 See Also ======== length, order, rank, size """ return int(ifac(self.size)) def parity(self): """ Computes the parity of a permutation. Explanation =========== The parity of a permutation reflects the parity of the number of inversions in the permutation, i.e., the number of pairs of x and y such that ``x > y`` but ``p[x] < p[y]``. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3]) >>> p.parity() 0 >>> p = Permutation([3, 2, 0, 1]) >>> p.parity() 1 See Also ======== _af_parity """ if self._cyclic_form is not None: return (self.size - self.cycles) % 2 return _af_parity(self.array_form) @property def is_even(self): """ Checks if a permutation is even. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3]) >>> p.is_even True >>> p = Permutation([3, 2, 1, 0]) >>> p.is_even True See Also ======== is_odd """ return not self.is_odd @property def is_odd(self): """ Checks if a permutation is odd. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3]) >>> p.is_odd False >>> p = Permutation([3, 2, 0, 1]) >>> p.is_odd True See Also ======== is_even """ return bool(self.parity() % 2) @property def is_Singleton(self): """ Checks to see if the permutation contains only one number and is thus the only possible permutation of this set of numbers Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation([0]).is_Singleton True >>> Permutation([0, 1]).is_Singleton False See Also ======== is_Empty """ return self.size == 1 @property def is_Empty(self): """ Checks to see if the permutation is a set with zero elements Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation([]).is_Empty True >>> Permutation([0]).is_Empty False See Also ======== is_Singleton """ return self.size == 0 @property def is_identity(self): return self.is_Identity @property def is_Identity(self): """ Returns True if the Permutation is an identity permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([]) >>> p.is_Identity True >>> p = Permutation([[0], [1], [2]]) >>> p.is_Identity True >>> p = Permutation([0, 1, 2]) >>> p.is_Identity True >>> p = Permutation([0, 2, 1]) >>> p.is_Identity False See Also ======== order """ af = self.array_form return not af or all(i == af[i] for i in range(self.size)) def ascents(self): """ Returns the positions of ascents in a permutation, ie, the location where p[i] < p[i+1] Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([4, 0, 1, 3, 2]) >>> p.ascents() [1, 2] See Also ======== descents, inversions, min, max """ a = self.array_form pos = [i for i in range(len(a) - 1) if a[i] < a[i + 1]] return pos def descents(self): """ Returns the positions of descents in a permutation, ie, the location where p[i] > p[i+1] Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([4, 0, 1, 3, 2]) >>> p.descents() [0, 3] See Also ======== ascents, inversions, min, max """ a = self.array_form pos = [i for i in range(len(a) - 1) if a[i] > a[i + 1]] return pos def max(self): """ The maximum element moved by the permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([1, 0, 2, 3, 4]) >>> p.max() 1 See Also ======== min, descents, ascents, inversions """ max = 0 a = self.array_form for i in range(len(a)): if a[i] != i and a[i] > max: max = a[i] return max def min(self): """ The minimum element moved by the permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 4, 3, 2]) >>> p.min() 2 See Also ======== max, descents, ascents, inversions """ a = self.array_form min = len(a) for i in range(len(a)): if a[i] != i and a[i] < min: min = a[i] return min def inversions(self): """ Computes the number of inversions of a permutation. Explanation =========== An inversion is where i > j but p[i] < p[j]. For small length of p, it iterates over all i and j values and calculates the number of inversions. For large length of p, it uses a variation of merge sort to calculate the number of inversions. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3, 4, 5]) >>> p.inversions() 0 >>> Permutation([3, 2, 1, 0]).inversions() 6 See Also ======== descents, ascents, min, max References ========== .. [1] http://www.cp.eng.chula.ac.th/~piak/teaching/algo/algo2008/count-inv.htm """ inversions = 0 a = self.array_form n = len(a) if n < 130: for i in range(n - 1): b = a[i] for c in a[i + 1:]: if b > c: inversions += 1 else: k = 1 right = 0 arr = a[:] temp = a[:] while k < n: i = 0 while i + k < n: right = i + k * 2 - 1 if right >= n: right = n - 1 inversions += _merge(arr, temp, i, i + k, right) i = i + k * 2 k = k * 2 return inversions def commutator(self, x): """Return the commutator of ``self`` and ``x``: ``~x*~self*x*self`` If f and g are part of a group, G, then the commutator of f and g is the group identity iff f and g commute, i.e. fg == gf. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> p = Permutation([0, 2, 3, 1]) >>> x = Permutation([2, 0, 3, 1]) >>> c = p.commutator(x); c Permutation([2, 1, 3, 0]) >>> c == ~x*~p*x*p True >>> I = Permutation(3) >>> p = [I + i for i in range(6)] >>> for i in range(len(p)): ... for j in range(len(p)): ... c = p[i].commutator(p[j]) ... if p[i]*p[j] == p[j]*p[i]: ... assert c == I ... else: ... assert c != I ... References ========== https://en.wikipedia.org/wiki/Commutator """ a = self.array_form b = x.array_form n = len(a) if len(b) != n: raise ValueError("The permutations must be of equal size.") inva = [None]*n for i in range(n): inva[a[i]] = i invb = [None]*n for i in range(n): invb[b[i]] = i return self._af_new([a[b[inva[i]]] for i in invb]) def signature(self): """ Gives the signature of the permutation needed to place the elements of the permutation in canonical order. The signature is calculated as (-1)^ Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2]) >>> p.inversions() 0 >>> p.signature() 1 >>> q = Permutation([0,2,1]) >>> q.inversions() 1 >>> q.signature() -1 See Also ======== inversions """ if self.is_even: return 1 return -1 def order(self): """ Computes the order of a permutation. When the permutation is raised to the power of its order it equals the identity permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> p = Permutation([3, 1, 5, 2, 4, 0]) >>> p.order() 4 >>> (p**(p.order())) Permutation([], size=6) See Also ======== identity, cardinality, length, rank, size """ return reduce(lcm, [len(cycle) for cycle in self.cyclic_form], 1) def length(self): """ Returns the number of integers moved by a permutation. Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation([0, 3, 2, 1]).length() 2 >>> Permutation([[0, 1], [2, 3]]).length() 4 See Also ======== min, max, support, cardinality, order, rank, size """ return len(self.support()) @property def cycle_structure(self): """Return the cycle structure of the permutation as a dictionary indicating the multiplicity of each cycle length. Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation(3).cycle_structure {1: 4} >>> Permutation(0, 4, 3)(1, 2)(5, 6).cycle_structure {2: 2, 3: 1} """ if self._cycle_structure: rv = self._cycle_structure else: rv = defaultdict(int) singletons = self.size for c in self.cyclic_form: rv[len(c)] += 1 singletons -= len(c) if singletons: rv[1] = singletons self._cycle_structure = rv return dict(rv) # make a copy @property def cycles(self): """ Returns the number of cycles contained in the permutation (including singletons). Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation([0, 1, 2]).cycles 3 >>> Permutation([0, 1, 2]).full_cyclic_form [[0], [1], [2]] >>> Permutation(0, 1)(2, 3).cycles 2 See Also ======== sympy.functions.combinatorial.numbers.stirling """ return len(self.full_cyclic_form) def index(self): """ Returns the index of a permutation. The index of a permutation is the sum of all subscripts j such that p[j] is greater than p[j+1]. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([3, 0, 2, 1, 4]) >>> p.index() 2 """ a = self.array_form return sum([j for j in range(len(a) - 1) if a[j] > a[j + 1]]) def runs(self): """ Returns the runs of a permutation. An ascending sequence in a permutation is called a run [5]. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([2, 5, 7, 3, 6, 0, 1, 4, 8]) >>> p.runs() [[2, 5, 7], [3, 6], [0, 1, 4, 8]] >>> q = Permutation([1,3,2,0]) >>> q.runs() [[1, 3], [2], [0]] """ return runs(self.array_form) def inversion_vector(self): """Return the inversion vector of the permutation. The inversion vector consists of elements whose value indicates the number of elements in the permutation that are lesser than it and lie on its right hand side. The inversion vector is the same as the Lehmer encoding of a permutation. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([4, 8, 0, 7, 1, 5, 3, 6, 2]) >>> p.inversion_vector() [4, 7, 0, 5, 0, 2, 1, 1] >>> p = Permutation([3, 2, 1, 0]) >>> p.inversion_vector() [3, 2, 1] The inversion vector increases lexicographically with the rank of the permutation, the -ith element cycling through 0..i. >>> p = Permutation(2) >>> while p: ... print('%s %s %s' % (p, p.inversion_vector(), p.rank())) ... p = p.next_lex() (2) [0, 0] 0 (1 2) [0, 1] 1 (2)(0 1) [1, 0] 2 (0 1 2) [1, 1] 3 (0 2 1) [2, 0] 4 (0 2) [2, 1] 5 See Also ======== from_inversion_vector """ self_array_form = self.array_form n = len(self_array_form) inversion_vector = [0] * (n - 1) for i in range(n - 1): val = 0 for j in range(i + 1, n): if self_array_form[j] < self_array_form[i]: val += 1 inversion_vector[i] = val return inversion_vector def rank_trotterjohnson(self): """ Returns the Trotter Johnson rank, which we get from the minimal change algorithm. See [4] section 2.4. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 1, 2, 3]) >>> p.rank_trotterjohnson() 0 >>> p = Permutation([0, 2, 1, 3]) >>> p.rank_trotterjohnson() 7 See Also ======== unrank_trotterjohnson, next_trotterjohnson """ if self.array_form == [] or self.is_Identity: return 0 if self.array_form == [1, 0]: return 1 perm = self.array_form n = self.size rank = 0 for j in range(1, n): k = 1 i = 0 while perm[i] != j: if perm[i] < j: k += 1 i += 1 j1 = j + 1 if rank % 2 == 0: rank = j1*rank + j1 - k else: rank = j1*rank + k - 1 return rank @classmethod def unrank_trotterjohnson(cls, size, rank): """ Trotter Johnson permutation unranking. See [4] section 2.4. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> Permutation.unrank_trotterjohnson(5, 10) Permutation([0, 3, 1, 2, 4]) See Also ======== rank_trotterjohnson, next_trotterjohnson """ perm = [0]*size r2 = 0 n = ifac(size) pj = 1 for j in range(2, size + 1): pj *= j r1 = (rank * pj) // n k = r1 - j*r2 if r2 % 2 == 0: for i in range(j - 1, j - k - 1, -1): perm[i] = perm[i - 1] perm[j - k - 1] = j - 1 else: for i in range(j - 1, k, -1): perm[i] = perm[i - 1] perm[k] = j - 1 r2 = r1 return cls._af_new(perm) def next_trotterjohnson(self): """ Returns the next permutation in Trotter-Johnson order. If self is the last permutation it returns None. See [4] section 2.4. If it is desired to generate all such permutations, they can be generated in order more quickly with the ``generate_bell`` function. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> p = Permutation([3, 0, 2, 1]) >>> p.rank_trotterjohnson() 4 >>> p = p.next_trotterjohnson(); p Permutation([0, 3, 2, 1]) >>> p.rank_trotterjohnson() 5 See Also ======== rank_trotterjohnson, unrank_trotterjohnson, sympy.utilities.iterables.generate_bell """ pi = self.array_form[:] n = len(pi) st = 0 rho = pi[:] done = False m = n-1 while m > 0 and not done: d = rho.index(m) for i in range(d, m): rho[i] = rho[i + 1] par = _af_parity(rho[:m]) if par == 1: if d == m: m -= 1 else: pi[st + d], pi[st + d + 1] = pi[st + d + 1], pi[st + d] done = True else: if d == 0: m -= 1 st += 1 else: pi[st + d], pi[st + d - 1] = pi[st + d - 1], pi[st + d] done = True if m == 0: return None return self._af_new(pi) def get_precedence_matrix(self): """ Gets the precedence matrix. This is used for computing the distance between two permutations. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> p = Permutation.josephus(3, 6, 1) >>> p Permutation([2, 5, 3, 1, 4, 0]) >>> p.get_precedence_matrix() Matrix([ [0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 1, 0], [1, 1, 0, 1, 1, 1], [1, 1, 0, 0, 1, 0], [1, 0, 0, 0, 0, 0], [1, 1, 0, 1, 1, 0]]) See Also ======== get_precedence_distance, get_adjacency_matrix, get_adjacency_distance """ m = zeros(self.size) perm = self.array_form for i in range(m.rows): for j in range(i + 1, m.cols): m[perm[i], perm[j]] = 1 return m def get_precedence_distance(self, other): """ Computes the precedence distance between two permutations. Explanation =========== Suppose p and p' represent n jobs. The precedence metric counts the number of times a job j is preceded by job i in both p and p'. This metric is commutative. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([2, 0, 4, 3, 1]) >>> q = Permutation([3, 1, 2, 4, 0]) >>> p.get_precedence_distance(q) 7 >>> q.get_precedence_distance(p) 7 See Also ======== get_precedence_matrix, get_adjacency_matrix, get_adjacency_distance """ if self.size != other.size: raise ValueError("The permutations must be of equal size.") self_prec_mat = self.get_precedence_matrix() other_prec_mat = other.get_precedence_matrix() n_prec = 0 for i in range(self.size): for j in range(self.size): if i == j: continue if self_prec_mat[i, j] * other_prec_mat[i, j] == 1: n_prec += 1 d = self.size * (self.size - 1)//2 - n_prec return d def get_adjacency_matrix(self): """ Computes the adjacency matrix of a permutation. Explanation =========== If job i is adjacent to job j in a permutation p then we set m[i, j] = 1 where m is the adjacency matrix of p. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation.josephus(3, 6, 1) >>> p.get_adjacency_matrix() Matrix([ [0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1], [0, 1, 0, 0, 0, 0], [1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0]]) >>> q = Permutation([0, 1, 2, 3]) >>> q.get_adjacency_matrix() Matrix([ [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [0, 0, 0, 0]]) See Also ======== get_precedence_matrix, get_precedence_distance, get_adjacency_distance """ m = zeros(self.size) perm = self.array_form for i in range(self.size - 1): m[perm[i], perm[i + 1]] = 1 return m def get_adjacency_distance(self, other): """ Computes the adjacency distance between two permutations. Explanation =========== This metric counts the number of times a pair i,j of jobs is adjacent in both p and p'. If n_adj is this quantity then the adjacency distance is n - n_adj - 1 [1] [1] Reeves, Colin R. Landscapes, Operators and Heuristic search, Annals of Operational Research, 86, pp 473-490. (1999) Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 3, 1, 2, 4]) >>> q = Permutation.josephus(4, 5, 2) >>> p.get_adjacency_distance(q) 3 >>> r = Permutation([0, 2, 1, 4, 3]) >>> p.get_adjacency_distance(r) 4 See Also ======== get_precedence_matrix, get_precedence_distance, get_adjacency_matrix """ if self.size != other.size: raise ValueError("The permutations must be of the same size.") self_adj_mat = self.get_adjacency_matrix() other_adj_mat = other.get_adjacency_matrix() n_adj = 0 for i in range(self.size): for j in range(self.size): if i == j: continue if self_adj_mat[i, j] * other_adj_mat[i, j] == 1: n_adj += 1 d = self.size - n_adj - 1 return d def get_positional_distance(self, other): """ Computes the positional distance between two permutations. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> p = Permutation([0, 3, 1, 2, 4]) >>> q = Permutation.josephus(4, 5, 2) >>> r = Permutation([3, 1, 4, 0, 2]) >>> p.get_positional_distance(q) 12 >>> p.get_positional_distance(r) 12 See Also ======== get_precedence_distance, get_adjacency_distance """ a = self.array_form b = other.array_form if len(a) != len(b): raise ValueError("The permutations must be of the same size.") return sum([abs(a[i] - b[i]) for i in range(len(a))]) @classmethod def josephus(cls, m, n, s=1): """Return as a permutation the shuffling of range(n) using the Josephus scheme in which every m-th item is selected until all have been chosen. The returned permutation has elements listed by the order in which they were selected. The parameter ``s`` stops the selection process when there are ``s`` items remaining and these are selected by continuing the selection, counting by 1 rather than by ``m``. Consider selecting every 3rd item from 6 until only 2 remain:: choices chosen ======== ====== 012345 01 345 2 01 34 25 01 4 253 0 4 2531 0 25314 253140 Examples ======== >>> from sympy.combinatorics import Permutation >>> Permutation.josephus(3, 6, 2).array_form [2, 5, 3, 1, 4, 0] References ========== .. [1] https://en.wikipedia.org/wiki/Flavius_Josephus .. [2] https://en.wikipedia.org/wiki/Josephus_problem .. [3] http://www.wou.edu/~burtonl/josephus.html """ from collections import deque m -= 1 Q = deque(list(range(n))) perm = [] while len(Q) > max(s, 1): for dp in range(m): Q.append(Q.popleft()) perm.append(Q.popleft()) perm.extend(list(Q)) return cls(perm) @classmethod def from_inversion_vector(cls, inversion): """ Calculates the permutation from the inversion vector. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> Permutation.from_inversion_vector([3, 2, 1, 0, 0]) Permutation([3, 2, 1, 0, 4, 5]) """ size = len(inversion) N = list(range(size + 1)) perm = [] try: for k in range(size): val = N[inversion[k]] perm.append(val) N.remove(val) except IndexError: raise ValueError("The inversion vector is not valid.") perm.extend(N) return cls._af_new(perm) @classmethod def random(cls, n): """ Generates a random permutation of length ``n``. Uses the underlying Python pseudo-random number generator. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> Permutation.random(2) in (Permutation([1, 0]), Permutation([0, 1])) True """ perm_array = list(range(n)) random.shuffle(perm_array) return cls._af_new(perm_array) @classmethod def unrank_lex(cls, size, rank): """ Lexicographic permutation unranking. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> init_printing(perm_cyclic=False, pretty_print=False) >>> a = Permutation.unrank_lex(5, 10) >>> a.rank() 10 >>> a Permutation([0, 2, 4, 1, 3]) See Also ======== rank, next_lex """ perm_array = [0] * size psize = 1 for i in range(size): new_psize = psize*(i + 1) d = (rank % new_psize) // psize rank -= d*psize perm_array[size - i - 1] = d for j in range(size - i, size): if perm_array[j] > d - 1: perm_array[j] += 1 psize = new_psize return cls._af_new(perm_array) def resize(self, n): """Resize the permutation to the new size ``n``. Parameters ========== n : int The new size of the permutation. Raises ====== ValueError If the permutation cannot be resized to the given size. This may only happen when resized to a smaller size than the original. Examples ======== >>> from sympy.combinatorics.permutations import Permutation Increasing the size of a permutation: >>> p = Permutation(0, 1, 2) >>> p = p.resize(5) >>> p (4)(0 1 2) Decreasing the size of the permutation: >>> p = p.resize(4) >>> p (3)(0 1 2) If resizing to the specific size breaks the cycles: >>> p.resize(2) Traceback (most recent call last): ... ValueError: The permutation can not be resized to 2 because the cycle (0, 1, 2) may break. """ aform = self.array_form l = len(aform) if n > l: aform += list(range(l, n)) return Permutation._af_new(aform) elif n < l: cyclic_form = self.full_cyclic_form new_cyclic_form = [] for cycle in cyclic_form: cycle_min = min(cycle) cycle_max = max(cycle) if cycle_min <= n-1: if cycle_max > n-1: raise ValueError( "The permutation can not be resized to {} " "because the cycle {} may break." .format(n, tuple(cycle))) new_cyclic_form.append(cycle) return Permutation(new_cyclic_form) return self # XXX Deprecated flag print_cyclic = None def _merge(arr, temp, left, mid, right): """ Merges two sorted arrays and calculates the inversion count. Helper function for calculating inversions. This method is for internal use only. """ i = k = left j = mid inv_count = 0 while i < mid and j <= right: if arr[i] < arr[j]: temp[k] = arr[i] k += 1 i += 1 else: temp[k] = arr[j] k += 1 j += 1 inv_count += (mid -i) while i < mid: temp[k] = arr[i] k += 1 i += 1 if j <= right: k += right - j + 1 j += right - j + 1 arr[left:k + 1] = temp[left:k + 1] else: arr[left:right + 1] = temp[left:right + 1] return inv_count Perm = Permutation _af_new = Perm._af_new class AppliedPermutation(Expr): """A permutation applied to a symbolic variable. Parameters ========== perm : Permutation x : Expr Examples ======== >>> from sympy import Symbol >>> from sympy.combinatorics import Permutation Creating a symbolic permutation function application: >>> x = Symbol('x') >>> p = Permutation(0, 1, 2) >>> p.apply(x) AppliedPermutation((0 1 2), x) >>> _.subs(x, 1) 2 """ def __new__(cls, perm, x, evaluate=None): if evaluate is None: evaluate = global_parameters.evaluate perm = _sympify(perm) x = _sympify(x) if not isinstance(perm, Permutation): raise ValueError("{} must be a Permutation instance." .format(perm)) if evaluate: if x.is_Integer: return perm.apply(x) obj = super().__new__(cls, perm, x) return obj @dispatch(Permutation, Permutation) def _eval_is_eq(lhs, rhs): if lhs._size != rhs._size: return None return lhs._array_form == rhs._array_form sympy-sympy-1.9/sympy/combinatorics/polyhedron.py000066400000000000000000001062671412543434000225110ustar00rootroot00000000000000from sympy.combinatorics import Permutation as Perm from sympy.combinatorics.perm_groups import PermutationGroup from sympy.core import Basic, Tuple from sympy.core.compatibility import as_int from sympy.sets import FiniteSet from sympy.utilities.iterables import (minlex, unflatten, flatten, default_sort_key) rmul = Perm.rmul class Polyhedron(Basic): """ Represents the polyhedral symmetry group (PSG). Explanation =========== The PSG is one of the symmetry groups of the Platonic solids. There are three polyhedral groups: the tetrahedral group of order 12, the octahedral group of order 24, and the icosahedral group of order 60. All doctests have been given in the docstring of the constructor of the object. References ========== .. [1] http://mathworld.wolfram.com/PolyhedralGroup.html """ _edges = None def __new__(cls, corners, faces=[], pgroup=[]): """ The constructor of the Polyhedron group object. Explanation =========== It takes up to three parameters: the corners, faces, and allowed transformations. The corners/vertices are entered as a list of arbitrary expressions that are used to identify each vertex. The faces are entered as a list of tuples of indices; a tuple of indices identifies the vertices which define the face. They should be entered in a cw or ccw order; they will be standardized by reversal and rotation to be give the lowest lexical ordering. If no faces are given then no edges will be computed. >>> from sympy.combinatorics.polyhedron import Polyhedron >>> Polyhedron(list('abc'), [(1, 2, 0)]).faces {(0, 1, 2)} >>> Polyhedron(list('abc'), [(1, 0, 2)]).faces {(0, 1, 2)} The allowed transformations are entered as allowable permutations of the vertices for the polyhedron. Instance of Permutations (as with faces) should refer to the supplied vertices by index. These permutation are stored as a PermutationGroup. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.interactive import init_printing >>> from sympy.abc import w, x, y, z >>> init_printing(pretty_print=False, perm_cyclic=False) Here we construct the Polyhedron object for a tetrahedron. >>> corners = [w, x, y, z] >>> faces = [(0, 1, 2), (0, 2, 3), (0, 3, 1), (1, 2, 3)] Next, allowed transformations of the polyhedron must be given. This is given as permutations of vertices. Although the vertices of a tetrahedron can be numbered in 24 (4!) different ways, there are only 12 different orientations for a physical tetrahedron. The following permutations, applied once or twice, will generate all 12 of the orientations. (The identity permutation, Permutation(range(4)), is not included since it does not change the orientation of the vertices.) >>> pgroup = [Permutation([[0, 1, 2], [3]]), \ Permutation([[0, 1, 3], [2]]), \ Permutation([[0, 2, 3], [1]]), \ Permutation([[1, 2, 3], [0]]), \ Permutation([[0, 1], [2, 3]]), \ Permutation([[0, 2], [1, 3]]), \ Permutation([[0, 3], [1, 2]])] The Polyhedron is now constructed and demonstrated: >>> tetra = Polyhedron(corners, faces, pgroup) >>> tetra.size 4 >>> tetra.edges {(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} >>> tetra.corners (w, x, y, z) It can be rotated with an arbitrary permutation of vertices, e.g. the following permutation is not in the pgroup: >>> tetra.rotate(Permutation([0, 1, 3, 2])) >>> tetra.corners (w, x, z, y) An allowed permutation of the vertices can be constructed by repeatedly applying permutations from the pgroup to the vertices. Here is a demonstration that applying p and p**2 for every p in pgroup generates all the orientations of a tetrahedron and no others: >>> all = ( (w, x, y, z), \ (x, y, w, z), \ (y, w, x, z), \ (w, z, x, y), \ (z, w, y, x), \ (w, y, z, x), \ (y, z, w, x), \ (x, z, y, w), \ (z, y, x, w), \ (y, x, z, w), \ (x, w, z, y), \ (z, x, w, y) ) >>> got = [] >>> for p in (pgroup + [p**2 for p in pgroup]): ... h = Polyhedron(corners) ... h.rotate(p) ... got.append(h.corners) ... >>> set(got) == set(all) True The make_perm method of a PermutationGroup will randomly pick permutations, multiply them together, and return the permutation that can be applied to the polyhedron to give the orientation produced by those individual permutations. Here, 3 permutations are used: >>> tetra.pgroup.make_perm(3) # doctest: +SKIP Permutation([0, 3, 1, 2]) To select the permutations that should be used, supply a list of indices to the permutations in pgroup in the order they should be applied: >>> use = [0, 0, 2] >>> p002 = tetra.pgroup.make_perm(3, use) >>> p002 Permutation([1, 0, 3, 2]) Apply them one at a time: >>> tetra.reset() >>> for i in use: ... tetra.rotate(pgroup[i]) ... >>> tetra.vertices (x, w, z, y) >>> sequentially = tetra.vertices Apply the composite permutation: >>> tetra.reset() >>> tetra.rotate(p002) >>> tetra.corners (x, w, z, y) >>> tetra.corners in all and tetra.corners == sequentially True Notes ===== Defining permutation groups --------------------------- It is not necessary to enter any permutations, nor is necessary to enter a complete set of transformations. In fact, for a polyhedron, all configurations can be constructed from just two permutations. For example, the orientations of a tetrahedron can be generated from an axis passing through a vertex and face and another axis passing through a different vertex or from an axis passing through the midpoints of two edges opposite of each other. For simplicity of presentation, consider a square -- not a cube -- with vertices 1, 2, 3, and 4: 1-----2 We could think of axes of rotation being: | | 1) through the face | | 2) from midpoint 1-2 to 3-4 or 1-3 to 2-4 3-----4 3) lines 1-4 or 2-3 To determine how to write the permutations, imagine 4 cameras, one at each corner, labeled A-D: A B A B 1-----2 1-----3 vertex index: | | | | 1 0 | | | | 2 1 3-----4 2-----4 3 2 C D C D 4 3 original after rotation along 1-4 A diagonal and a face axis will be chosen for the "permutation group" from which any orientation can be constructed. >>> pgroup = [] Imagine a clockwise rotation when viewing 1-4 from camera A. The new orientation is (in camera-order): 1, 3, 2, 4 so the permutation is given using the *indices* of the vertices as: >>> pgroup.append(Permutation((0, 2, 1, 3))) Now imagine rotating clockwise when looking down an axis entering the center of the square as viewed. The new camera-order would be 3, 1, 4, 2 so the permutation is (using indices): >>> pgroup.append(Permutation((2, 0, 3, 1))) The square can now be constructed: ** use real-world labels for the vertices, entering them in camera order ** for the faces we use zero-based indices of the vertices in *edge-order* as the face is traversed; neither the direction nor the starting point matter -- the faces are only used to define edges (if so desired). >>> square = Polyhedron((1, 2, 3, 4), [(0, 1, 3, 2)], pgroup) To rotate the square with a single permutation we can do: >>> square.rotate(square.pgroup[0]) >>> square.corners (1, 3, 2, 4) To use more than one permutation (or to use one permutation more than once) it is more convenient to use the make_perm method: >>> p011 = square.pgroup.make_perm([0, 1, 1]) # diag flip + 2 rotations >>> square.reset() # return to initial orientation >>> square.rotate(p011) >>> square.corners (4, 2, 3, 1) Thinking outside the box ------------------------ Although the Polyhedron object has a direct physical meaning, it actually has broader application. In the most general sense it is just a decorated PermutationGroup, allowing one to connect the permutations to something physical. For example, a Rubik's cube is not a proper polyhedron, but the Polyhedron class can be used to represent it in a way that helps to visualize the Rubik's cube. >>> from sympy.utilities.iterables import flatten, unflatten >>> from sympy import symbols >>> from sympy.combinatorics import RubikGroup >>> facelets = flatten([symbols(s+'1:5') for s in 'UFRBLD']) >>> def show(): ... pairs = unflatten(r2.corners, 2) ... print(pairs[::2]) ... print(pairs[1::2]) ... >>> r2 = Polyhedron(facelets, pgroup=RubikGroup(2)) >>> show() [(U1, U2), (F1, F2), (R1, R2), (B1, B2), (L1, L2), (D1, D2)] [(U3, U4), (F3, F4), (R3, R4), (B3, B4), (L3, L4), (D3, D4)] >>> r2.rotate(0) # cw rotation of F >>> show() [(U1, U2), (F3, F1), (U3, R2), (B1, B2), (L1, D1), (R3, R1)] [(L4, L2), (F4, F2), (U4, R4), (B3, B4), (L3, D2), (D3, D4)] Predefined Polyhedra ==================== For convenience, the vertices and faces are defined for the following standard solids along with a permutation group for transformations. When the polyhedron is oriented as indicated below, the vertices in a given horizontal plane are numbered in ccw direction, starting from the vertex that will give the lowest indices in a given face. (In the net of the vertices, indices preceded by "-" indicate replication of the lhs index in the net.) tetrahedron, tetrahedron_faces ------------------------------ 4 vertices (vertex up) net: 0 0-0 1 2 3-1 4 faces: (0, 1, 2) (0, 2, 3) (0, 3, 1) (1, 2, 3) cube, cube_faces ---------------- 8 vertices (face up) net: 0 1 2 3-0 4 5 6 7-4 6 faces: (0, 1, 2, 3) (0, 1, 5, 4) (1, 2, 6, 5) (2, 3, 7, 6) (0, 3, 7, 4) (4, 5, 6, 7) octahedron, octahedron_faces ---------------------------- 6 vertices (vertex up) net: 0 0 0-0 1 2 3 4-1 5 5 5-5 8 faces: (0, 1, 2) (0, 2, 3) (0, 3, 4) (0, 1, 4) (1, 2, 5) (2, 3, 5) (3, 4, 5) (1, 4, 5) dodecahedron, dodecahedron_faces -------------------------------- 20 vertices (vertex up) net: 0 1 2 3 4 -0 5 6 7 8 9 -5 14 10 11 12 13-14 15 16 17 18 19-15 12 faces: (0, 1, 2, 3, 4) (0, 1, 6, 10, 5) (1, 2, 7, 11, 6) (2, 3, 8, 12, 7) (3, 4, 9, 13, 8) (0, 4, 9, 14, 5) (5, 10, 16, 15, 14) (6, 10, 16, 17, 11) (7, 11, 17, 18, 12) (8, 12, 18, 19, 13) (9, 13, 19, 15, 14)(15, 16, 17, 18, 19) icosahedron, icosahedron_faces ------------------------------ 12 vertices (face up) net: 0 0 0 0 -0 1 2 3 4 5 -1 6 7 8 9 10 -6 11 11 11 11 -11 20 faces: (0, 1, 2) (0, 2, 3) (0, 3, 4) (0, 4, 5) (0, 1, 5) (1, 2, 6) (2, 3, 7) (3, 4, 8) (4, 5, 9) (1, 5, 10) (2, 6, 7) (3, 7, 8) (4, 8, 9) (5, 9, 10) (1, 6, 10) (6, 7, 11) (7, 8, 11) (8, 9, 11) (9, 10, 11) (6, 10, 11) >>> from sympy.combinatorics.polyhedron import cube >>> cube.edges {(0, 1), (0, 3), (0, 4), (1, 2), (1, 5), (2, 3), (2, 6), (3, 7), (4, 5), (4, 7), (5, 6), (6, 7)} If you want to use letters or other names for the corners you can still use the pre-calculated faces: >>> corners = list('abcdefgh') >>> Polyhedron(corners, cube.faces).corners (a, b, c, d, e, f, g, h) References ========== .. [1] www.ocf.berkeley.edu/~wwu/articles/platonicsolids.pdf """ faces = [minlex(f, directed=False, key=default_sort_key) for f in faces] corners, faces, pgroup = args = \ [Tuple(*a) for a in (corners, faces, pgroup)] obj = Basic.__new__(cls, *args) obj._corners = tuple(corners) # in order given obj._faces = FiniteSet(*faces) if pgroup and pgroup[0].size != len(corners): raise ValueError("Permutation size unequal to number of corners.") # use the identity permutation if none are given obj._pgroup = PermutationGroup( pgroup or [Perm(range(len(corners)))] ) return obj @property def corners(self): """ Get the corners of the Polyhedron. The method ``vertices`` is an alias for ``corners``. Examples ======== >>> from sympy.combinatorics import Polyhedron >>> from sympy.abc import a, b, c, d >>> p = Polyhedron(list('abcd')) >>> p.corners == p.vertices == (a, b, c, d) True See Also ======== array_form, cyclic_form """ return self._corners vertices = corners @property def array_form(self): """Return the indices of the corners. The indices are given relative to the original position of corners. Examples ======== >>> from sympy.combinatorics.polyhedron import tetrahedron >>> tetrahedron = tetrahedron.copy() >>> tetrahedron.array_form [0, 1, 2, 3] >>> tetrahedron.rotate(0) >>> tetrahedron.array_form [0, 2, 3, 1] >>> tetrahedron.pgroup[0].array_form [0, 2, 3, 1] See Also ======== corners, cyclic_form """ corners = list(self.args[0]) return [corners.index(c) for c in self.corners] @property def cyclic_form(self): """Return the indices of the corners in cyclic notation. The indices are given relative to the original position of corners. See Also ======== corners, array_form """ return Perm._af_new(self.array_form).cyclic_form @property def size(self): """ Get the number of corners of the Polyhedron. """ return len(self._corners) @property def faces(self): """ Get the faces of the Polyhedron. """ return self._faces @property def pgroup(self): """ Get the permutations of the Polyhedron. """ return self._pgroup @property def edges(self): """ Given the faces of the polyhedra we can get the edges. Examples ======== >>> from sympy.combinatorics import Polyhedron >>> from sympy.abc import a, b, c >>> corners = (a, b, c) >>> faces = [(0, 1, 2)] >>> Polyhedron(corners, faces).edges {(0, 1), (0, 2), (1, 2)} """ if self._edges is None: output = set() for face in self.faces: for i in range(len(face)): edge = tuple(sorted([face[i], face[i - 1]])) output.add(edge) self._edges = FiniteSet(*output) return self._edges def rotate(self, perm): """ Apply a permutation to the polyhedron *in place*. The permutation may be given as a Permutation instance or an integer indicating which permutation from pgroup of the Polyhedron should be applied. This is an operation that is analogous to rotation about an axis by a fixed increment. Notes ===== When a Permutation is applied, no check is done to see if that is a valid permutation for the Polyhedron. For example, a cube could be given a permutation which effectively swaps only 2 vertices. A valid permutation (that rotates the object in a physical way) will be obtained if one only uses permutations from the ``pgroup`` of the Polyhedron. On the other hand, allowing arbitrary rotations (applications of permutations) gives a way to follow named elements rather than indices since Polyhedron allows vertices to be named while Permutation works only with indices. Examples ======== >>> from sympy.combinatorics import Polyhedron, Permutation >>> from sympy.combinatorics.polyhedron import cube >>> cube = cube.copy() >>> cube.corners (0, 1, 2, 3, 4, 5, 6, 7) >>> cube.rotate(0) >>> cube.corners (1, 2, 3, 0, 5, 6, 7, 4) A non-physical "rotation" that is not prohibited by this method: >>> cube.reset() >>> cube.rotate(Permutation([[1, 2]], size=8)) >>> cube.corners (0, 2, 1, 3, 4, 5, 6, 7) Polyhedron can be used to follow elements of set that are identified by letters instead of integers: >>> shadow = h5 = Polyhedron(list('abcde')) >>> p = Permutation([3, 0, 1, 2, 4]) >>> h5.rotate(p) >>> h5.corners (d, a, b, c, e) >>> _ == shadow.corners True >>> copy = h5.copy() >>> h5.rotate(p) >>> h5.corners == copy.corners False """ if not isinstance(perm, Perm): perm = self.pgroup[perm] # and we know it's valid else: if perm.size != self.size: raise ValueError('Polyhedron and Permutation sizes differ.') a = perm.array_form corners = [self.corners[a[i]] for i in range(len(self.corners))] self._corners = tuple(corners) def reset(self): """Return corners to their original positions. Examples ======== >>> from sympy.combinatorics.polyhedron import tetrahedron as T >>> T = T.copy() >>> T.corners (0, 1, 2, 3) >>> T.rotate(0) >>> T.corners (0, 2, 3, 1) >>> T.reset() >>> T.corners (0, 1, 2, 3) """ self._corners = self.args[0] def _pgroup_calcs(): """Return the permutation groups for each of the polyhedra and the face definitions: tetrahedron, cube, octahedron, dodecahedron, icosahedron, tetrahedron_faces, cube_faces, octahedron_faces, dodecahedron_faces, icosahedron_faces Explanation =========== (This author didn't find and didn't know of a better way to do it though there likely is such a way.) Although only 2 permutations are needed for a polyhedron in order to generate all the possible orientations, a group of permutations is provided instead. A set of permutations is called a "group" if:: a*b = c (for any pair of permutations in the group, a and b, their product, c, is in the group) a*(b*c) = (a*b)*c (for any 3 permutations in the group associativity holds) there is an identity permutation, I, such that I*a = a*I for all elements in the group a*b = I (the inverse of each permutation is also in the group) None of the polyhedron groups defined follow these definitions of a group. Instead, they are selected to contain those permutations whose powers alone will construct all orientations of the polyhedron, i.e. for permutations ``a``, ``b``, etc... in the group, ``a, a**2, ..., a**o_a``, ``b, b**2, ..., b**o_b``, etc... (where ``o_i`` is the order of permutation ``i``) generate all permutations of the polyhedron instead of mixed products like ``a*b``, ``a*b**2``, etc.... Note that for a polyhedron with n vertices, the valid permutations of the vertices exclude those that do not maintain its faces. e.g. the permutation BCDE of a square's four corners, ABCD, is a valid permutation while CBDE is not (because this would twist the square). Examples ======== The is_group checks for: closure, the presence of the Identity permutation, and the presence of the inverse for each of the elements in the group. This confirms that none of the polyhedra are true groups: >>> from sympy.combinatorics.polyhedron import ( ... tetrahedron, cube, octahedron, dodecahedron, icosahedron) ... >>> polyhedra = (tetrahedron, cube, octahedron, dodecahedron, icosahedron) >>> [h.pgroup.is_group for h in polyhedra] ... [True, True, True, True, True] Although tests in polyhedron's test suite check that powers of the permutations in the groups generate all permutations of the vertices of the polyhedron, here we also demonstrate the powers of the given permutations create a complete group for the tetrahedron: >>> from sympy.combinatorics import Permutation, PermutationGroup >>> for h in polyhedra[:1]: ... G = h.pgroup ... perms = set() ... for g in G: ... for e in range(g.order()): ... p = tuple((g**e).array_form) ... perms.add(p) ... ... perms = [Permutation(p) for p in perms] ... assert PermutationGroup(perms).is_group In addition to doing the above, the tests in the suite confirm that the faces are all present after the application of each permutation. References ========== .. [1] http://dogschool.tripod.com/trianglegroup.html """ def _pgroup_of_double(polyh, ordered_faces, pgroup): n = len(ordered_faces[0]) # the vertices of the double which sits inside a give polyhedron # can be found by tracking the faces of the outer polyhedron. # A map between face and the vertex of the double is made so that # after rotation the position of the vertices can be located fmap = dict(zip(ordered_faces, range(len(ordered_faces)))) flat_faces = flatten(ordered_faces) new_pgroup = [] for i, p in enumerate(pgroup): h = polyh.copy() h.rotate(p) c = h.corners # reorder corners in the order they should appear when # enumerating the faces reorder = unflatten([c[j] for j in flat_faces], n) # make them canonical reorder = [tuple(map(as_int, minlex(f, directed=False))) for f in reorder] # map face to vertex: the resulting list of vertices are the # permutation that we seek for the double new_pgroup.append(Perm([fmap[f] for f in reorder])) return new_pgroup tetrahedron_faces = [ (0, 1, 2), (0, 2, 3), (0, 3, 1), # upper 3 (1, 2, 3), # bottom ] # cw from top # _t_pgroup = [ Perm([[1, 2, 3], [0]]), # cw from top Perm([[0, 1, 2], [3]]), # cw from front face Perm([[0, 3, 2], [1]]), # cw from back right face Perm([[0, 3, 1], [2]]), # cw from back left face Perm([[0, 1], [2, 3]]), # through front left edge Perm([[0, 2], [1, 3]]), # through front right edge Perm([[0, 3], [1, 2]]), # through back edge ] tetrahedron = Polyhedron( range(4), tetrahedron_faces, _t_pgroup) cube_faces = [ (0, 1, 2, 3), # upper (0, 1, 5, 4), (1, 2, 6, 5), (2, 3, 7, 6), (0, 3, 7, 4), # middle 4 (4, 5, 6, 7), # lower ] # U, D, F, B, L, R = up, down, front, back, left, right _c_pgroup = [Perm(p) for p in [ [1, 2, 3, 0, 5, 6, 7, 4], # cw from top, U [4, 0, 3, 7, 5, 1, 2, 6], # cw from F face [4, 5, 1, 0, 7, 6, 2, 3], # cw from R face [1, 0, 4, 5, 2, 3, 7, 6], # cw through UF edge [6, 2, 1, 5, 7, 3, 0, 4], # cw through UR edge [6, 7, 3, 2, 5, 4, 0, 1], # cw through UB edge [3, 7, 4, 0, 2, 6, 5, 1], # cw through UL edge [4, 7, 6, 5, 0, 3, 2, 1], # cw through FL edge [6, 5, 4, 7, 2, 1, 0, 3], # cw through FR edge [0, 3, 7, 4, 1, 2, 6, 5], # cw through UFL vertex [5, 1, 0, 4, 6, 2, 3, 7], # cw through UFR vertex [5, 6, 2, 1, 4, 7, 3, 0], # cw through UBR vertex [7, 4, 0, 3, 6, 5, 1, 2], # cw through UBL ]] cube = Polyhedron( range(8), cube_faces, _c_pgroup) octahedron_faces = [ (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 1, 4), # top 4 (1, 2, 5), (2, 3, 5), (3, 4, 5), (1, 4, 5), # bottom 4 ] octahedron = Polyhedron( range(6), octahedron_faces, _pgroup_of_double(cube, cube_faces, _c_pgroup)) dodecahedron_faces = [ (0, 1, 2, 3, 4), # top (0, 1, 6, 10, 5), (1, 2, 7, 11, 6), (2, 3, 8, 12, 7), # upper 5 (3, 4, 9, 13, 8), (0, 4, 9, 14, 5), (5, 10, 16, 15, 14), (6, 10, 16, 17, 11), (7, 11, 17, 18, 12), # lower 5 (8, 12, 18, 19, 13), (9, 13, 19, 15, 14), (15, 16, 17, 18, 19) # bottom ] def _string_to_perm(s): rv = [Perm(range(20))] p = None for si in s: if si not in '01': count = int(si) - 1 else: count = 1 if si == '0': p = _f0 elif si == '1': p = _f1 rv.extend([p]*count) return Perm.rmul(*rv) # top face cw _f0 = Perm([ 1, 2, 3, 4, 0, 6, 7, 8, 9, 5, 11, 12, 13, 14, 10, 16, 17, 18, 19, 15]) # front face cw _f1 = Perm([ 5, 0, 4, 9, 14, 10, 1, 3, 13, 15, 6, 2, 8, 19, 16, 17, 11, 7, 12, 18]) # the strings below, like 0104 are shorthand for F0*F1*F0**4 and are # the remaining 4 face rotations, 15 edge permutations, and the # 10 vertex rotations. _dodeca_pgroup = [_f0, _f1] + [_string_to_perm(s) for s in ''' 0104 140 014 0410 010 1403 03104 04103 102 120 1304 01303 021302 03130 0412041 041204103 04120410 041204104 041204102 10 01 1402 0140 04102 0412 1204 1302 0130 03120'''.strip().split()] dodecahedron = Polyhedron( range(20), dodecahedron_faces, _dodeca_pgroup) icosahedron_faces = [ (0, 1, 2), (0, 2, 3), (0, 3, 4), (0, 4, 5), (0, 1, 5), (1, 6, 7), (1, 2, 7), (2, 7, 8), (2, 3, 8), (3, 8, 9), (3, 4, 9), (4, 9, 10), (4, 5, 10), (5, 6, 10), (1, 5, 6), (6, 7, 11), (7, 8, 11), (8, 9, 11), (9, 10, 11), (6, 10, 11)] icosahedron = Polyhedron( range(12), icosahedron_faces, _pgroup_of_double( dodecahedron, dodecahedron_faces, _dodeca_pgroup)) return (tetrahedron, cube, octahedron, dodecahedron, icosahedron, tetrahedron_faces, cube_faces, octahedron_faces, dodecahedron_faces, icosahedron_faces) # ----------------------------------------------------------------------- # Standard Polyhedron groups # # These are generated using _pgroup_calcs() above. However to save # import time we encode them explicitly here. # ----------------------------------------------------------------------- tetrahedron = Polyhedron( Tuple(0, 1, 2, 3), Tuple( Tuple(0, 1, 2), Tuple(0, 2, 3), Tuple(0, 1, 3), Tuple(1, 2, 3)), Tuple( Perm(1, 2, 3), Perm(3)(0, 1, 2), Perm(0, 3, 2), Perm(0, 3, 1), Perm(0, 1)(2, 3), Perm(0, 2)(1, 3), Perm(0, 3)(1, 2) )) cube = Polyhedron( Tuple(0, 1, 2, 3, 4, 5, 6, 7), Tuple( Tuple(0, 1, 2, 3), Tuple(0, 1, 5, 4), Tuple(1, 2, 6, 5), Tuple(2, 3, 7, 6), Tuple(0, 3, 7, 4), Tuple(4, 5, 6, 7)), Tuple( Perm(0, 1, 2, 3)(4, 5, 6, 7), Perm(0, 4, 5, 1)(2, 3, 7, 6), Perm(0, 4, 7, 3)(1, 5, 6, 2), Perm(0, 1)(2, 4)(3, 5)(6, 7), Perm(0, 6)(1, 2)(3, 5)(4, 7), Perm(0, 6)(1, 7)(2, 3)(4, 5), Perm(0, 3)(1, 7)(2, 4)(5, 6), Perm(0, 4)(1, 7)(2, 6)(3, 5), Perm(0, 6)(1, 5)(2, 4)(3, 7), Perm(1, 3, 4)(2, 7, 5), Perm(7)(0, 5, 2)(3, 4, 6), Perm(0, 5, 7)(1, 6, 3), Perm(0, 7, 2)(1, 4, 6))) octahedron = Polyhedron( Tuple(0, 1, 2, 3, 4, 5), Tuple( Tuple(0, 1, 2), Tuple(0, 2, 3), Tuple(0, 3, 4), Tuple(0, 1, 4), Tuple(1, 2, 5), Tuple(2, 3, 5), Tuple(3, 4, 5), Tuple(1, 4, 5)), Tuple( Perm(5)(1, 2, 3, 4), Perm(0, 4, 5, 2), Perm(0, 1, 5, 3), Perm(0, 1)(2, 4)(3, 5), Perm(0, 2)(1, 3)(4, 5), Perm(0, 3)(1, 5)(2, 4), Perm(0, 4)(1, 3)(2, 5), Perm(0, 5)(1, 4)(2, 3), Perm(0, 5)(1, 2)(3, 4), Perm(0, 4, 1)(2, 3, 5), Perm(0, 1, 2)(3, 4, 5), Perm(0, 2, 3)(1, 5, 4), Perm(0, 4, 3)(1, 5, 2))) dodecahedron = Polyhedron( Tuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), Tuple( Tuple(0, 1, 2, 3, 4), Tuple(0, 1, 6, 10, 5), Tuple(1, 2, 7, 11, 6), Tuple(2, 3, 8, 12, 7), Tuple(3, 4, 9, 13, 8), Tuple(0, 4, 9, 14, 5), Tuple(5, 10, 16, 15, 14), Tuple(6, 10, 16, 17, 11), Tuple(7, 11, 17, 18, 12), Tuple(8, 12, 18, 19, 13), Tuple(9, 13, 19, 15, 14), Tuple(15, 16, 17, 18, 19)), Tuple( Perm(0, 1, 2, 3, 4)(5, 6, 7, 8, 9)(10, 11, 12, 13, 14)(15, 16, 17, 18, 19), Perm(0, 5, 10, 6, 1)(2, 4, 14, 16, 11)(3, 9, 15, 17, 7)(8, 13, 19, 18, 12), Perm(0, 10, 17, 12, 3)(1, 6, 11, 7, 2)(4, 5, 16, 18, 8)(9, 14, 15, 19, 13), Perm(0, 6, 17, 19, 9)(1, 11, 18, 13, 4)(2, 7, 12, 8, 3)(5, 10, 16, 15, 14), Perm(0, 2, 12, 19, 14)(1, 7, 18, 15, 5)(3, 8, 13, 9, 4)(6, 11, 17, 16, 10), Perm(0, 4, 9, 14, 5)(1, 3, 13, 15, 10)(2, 8, 19, 16, 6)(7, 12, 18, 17, 11), Perm(0, 1)(2, 5)(3, 10)(4, 6)(7, 14)(8, 16)(9, 11)(12, 15)(13, 17)(18, 19), Perm(0, 7)(1, 2)(3, 6)(4, 11)(5, 12)(8, 10)(9, 17)(13, 16)(14, 18)(15, 19), Perm(0, 12)(1, 8)(2, 3)(4, 7)(5, 18)(6, 13)(9, 11)(10, 19)(14, 17)(15, 16), Perm(0, 8)(1, 13)(2, 9)(3, 4)(5, 12)(6, 19)(7, 14)(10, 18)(11, 15)(16, 17), Perm(0, 4)(1, 9)(2, 14)(3, 5)(6, 13)(7, 15)(8, 10)(11, 19)(12, 16)(17, 18), Perm(0, 5)(1, 14)(2, 15)(3, 16)(4, 10)(6, 9)(7, 19)(8, 17)(11, 13)(12, 18), Perm(0, 11)(1, 6)(2, 10)(3, 16)(4, 17)(5, 7)(8, 15)(9, 18)(12, 14)(13, 19), Perm(0, 18)(1, 12)(2, 7)(3, 11)(4, 17)(5, 19)(6, 8)(9, 16)(10, 13)(14, 15), Perm(0, 18)(1, 19)(2, 13)(3, 8)(4, 12)(5, 17)(6, 15)(7, 9)(10, 16)(11, 14), Perm(0, 13)(1, 19)(2, 15)(3, 14)(4, 9)(5, 8)(6, 18)(7, 16)(10, 12)(11, 17), Perm(0, 16)(1, 15)(2, 19)(3, 18)(4, 17)(5, 10)(6, 14)(7, 13)(8, 12)(9, 11), Perm(0, 18)(1, 17)(2, 16)(3, 15)(4, 19)(5, 12)(6, 11)(7, 10)(8, 14)(9, 13), Perm(0, 15)(1, 19)(2, 18)(3, 17)(4, 16)(5, 14)(6, 13)(7, 12)(8, 11)(9, 10), Perm(0, 17)(1, 16)(2, 15)(3, 19)(4, 18)(5, 11)(6, 10)(7, 14)(8, 13)(9, 12), Perm(0, 19)(1, 18)(2, 17)(3, 16)(4, 15)(5, 13)(6, 12)(7, 11)(8, 10)(9, 14), Perm(1, 4, 5)(2, 9, 10)(3, 14, 6)(7, 13, 16)(8, 15, 11)(12, 19, 17), Perm(19)(0, 6, 2)(3, 5, 11)(4, 10, 7)(8, 14, 17)(9, 16, 12)(13, 15, 18), Perm(0, 11, 8)(1, 7, 3)(4, 6, 12)(5, 17, 13)(9, 10, 18)(14, 16, 19), Perm(0, 7, 13)(1, 12, 9)(2, 8, 4)(5, 11, 19)(6, 18, 14)(10, 17, 15), Perm(0, 3, 9)(1, 8, 14)(2, 13, 5)(6, 12, 15)(7, 19, 10)(11, 18, 16), Perm(0, 14, 10)(1, 9, 16)(2, 13, 17)(3, 19, 11)(4, 15, 6)(7, 8, 18), Perm(0, 16, 7)(1, 10, 11)(2, 5, 17)(3, 14, 18)(4, 15, 12)(8, 9, 19), Perm(0, 16, 13)(1, 17, 8)(2, 11, 12)(3, 6, 18)(4, 10, 19)(5, 15, 9), Perm(0, 11, 15)(1, 17, 14)(2, 18, 9)(3, 12, 13)(4, 7, 19)(5, 6, 16), Perm(0, 8, 15)(1, 12, 16)(2, 18, 10)(3, 19, 5)(4, 13, 14)(6, 7, 17))) icosahedron = Polyhedron( Tuple(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), Tuple( Tuple(0, 1, 2), Tuple(0, 2, 3), Tuple(0, 3, 4), Tuple(0, 4, 5), Tuple(0, 1, 5), Tuple(1, 6, 7), Tuple(1, 2, 7), Tuple(2, 7, 8), Tuple(2, 3, 8), Tuple(3, 8, 9), Tuple(3, 4, 9), Tuple(4, 9, 10), Tuple(4, 5, 10), Tuple(5, 6, 10), Tuple(1, 5, 6), Tuple(6, 7, 11), Tuple(7, 8, 11), Tuple(8, 9, 11), Tuple(9, 10, 11), Tuple(6, 10, 11)), Tuple( Perm(11)(1, 2, 3, 4, 5)(6, 7, 8, 9, 10), Perm(0, 5, 6, 7, 2)(3, 4, 10, 11, 8), Perm(0, 1, 7, 8, 3)(4, 5, 6, 11, 9), Perm(0, 2, 8, 9, 4)(1, 7, 11, 10, 5), Perm(0, 3, 9, 10, 5)(1, 2, 8, 11, 6), Perm(0, 4, 10, 6, 1)(2, 3, 9, 11, 7), Perm(0, 1)(2, 5)(3, 6)(4, 7)(8, 10)(9, 11), Perm(0, 2)(1, 3)(4, 7)(5, 8)(6, 9)(10, 11), Perm(0, 3)(1, 9)(2, 4)(5, 8)(6, 11)(7, 10), Perm(0, 4)(1, 9)(2, 10)(3, 5)(6, 8)(7, 11), Perm(0, 5)(1, 4)(2, 10)(3, 6)(7, 9)(8, 11), Perm(0, 6)(1, 5)(2, 10)(3, 11)(4, 7)(8, 9), Perm(0, 7)(1, 2)(3, 6)(4, 11)(5, 8)(9, 10), Perm(0, 8)(1, 9)(2, 3)(4, 7)(5, 11)(6, 10), Perm(0, 9)(1, 11)(2, 10)(3, 4)(5, 8)(6, 7), Perm(0, 10)(1, 9)(2, 11)(3, 6)(4, 5)(7, 8), Perm(0, 11)(1, 6)(2, 10)(3, 9)(4, 8)(5, 7), Perm(0, 11)(1, 8)(2, 7)(3, 6)(4, 10)(5, 9), Perm(0, 11)(1, 10)(2, 9)(3, 8)(4, 7)(5, 6), Perm(0, 11)(1, 7)(2, 6)(3, 10)(4, 9)(5, 8), Perm(0, 11)(1, 9)(2, 8)(3, 7)(4, 6)(5, 10), Perm(0, 5, 1)(2, 4, 6)(3, 10, 7)(8, 9, 11), Perm(0, 1, 2)(3, 5, 7)(4, 6, 8)(9, 10, 11), Perm(0, 2, 3)(1, 8, 4)(5, 7, 9)(6, 11, 10), Perm(0, 3, 4)(1, 8, 10)(2, 9, 5)(6, 7, 11), Perm(0, 4, 5)(1, 3, 10)(2, 9, 6)(7, 8, 11), Perm(0, 10, 7)(1, 5, 6)(2, 4, 11)(3, 9, 8), Perm(0, 6, 8)(1, 7, 2)(3, 5, 11)(4, 10, 9), Perm(0, 7, 9)(1, 11, 4)(2, 8, 3)(5, 6, 10), Perm(0, 8, 10)(1, 7, 6)(2, 11, 5)(3, 9, 4), Perm(0, 9, 6)(1, 3, 11)(2, 8, 7)(4, 10, 5))) tetrahedron_faces = list(tuple(arg) for arg in tetrahedron.faces) cube_faces = list(tuple(arg) for arg in cube.faces) octahedron_faces = list(tuple(arg) for arg in octahedron.faces) dodecahedron_faces = list(tuple(arg) for arg in dodecahedron.faces) icosahedron_faces = list(tuple(arg) for arg in icosahedron.faces) sympy-sympy-1.9/sympy/combinatorics/prufer.py000066400000000000000000000271231412543434000216220ustar00rootroot00000000000000from sympy.core import Basic from sympy.core.compatibility import iterable, as_int from sympy.utilities.iterables import flatten from collections import defaultdict class Prufer(Basic): """ The Prufer correspondence is an algorithm that describes the bijection between labeled trees and the Prufer code. A Prufer code of a labeled tree is unique up to isomorphism and has a length of n - 2. Prufer sequences were first used by Heinz Prufer to give a proof of Cayley's formula. References ========== .. [1] http://mathworld.wolfram.com/LabeledTree.html """ _prufer_repr = None _tree_repr = None _nodes = None _rank = None @property def prufer_repr(self): """Returns Prufer sequence for the Prufer object. This sequence is found by removing the highest numbered vertex, recording the node it was attached to, and continuing until only two vertices remain. The Prufer sequence is the list of recorded nodes. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).prufer_repr [3, 3, 3, 4] >>> Prufer([1, 0, 0]).prufer_repr [1, 0, 0] See Also ======== to_prufer """ if self._prufer_repr is None: self._prufer_repr = self.to_prufer(self._tree_repr[:], self.nodes) return self._prufer_repr @property def tree_repr(self): """Returns the tree representation of the Prufer object. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).tree_repr [[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]] >>> Prufer([1, 0, 0]).tree_repr [[1, 2], [0, 1], [0, 3], [0, 4]] See Also ======== to_tree """ if self._tree_repr is None: self._tree_repr = self.to_tree(self._prufer_repr[:]) return self._tree_repr @property def nodes(self): """Returns the number of nodes in the tree. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]).nodes 6 >>> Prufer([1, 0, 0]).nodes 5 """ return self._nodes @property def rank(self): """Returns the rank of the Prufer sequence. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> p = Prufer([[0, 3], [1, 3], [2, 3], [3, 4], [4, 5]]) >>> p.rank 778 >>> p.next(1).rank 779 >>> p.prev().rank 777 See Also ======== prufer_rank, next, prev, size """ if self._rank is None: self._rank = self.prufer_rank() return self._rank @property def size(self): """Return the number of possible trees of this Prufer object. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> Prufer([0]*4).size == Prufer([6]*4).size == 1296 True See Also ======== prufer_rank, rank, next, prev """ return self.prev(self.rank).prev().rank + 1 @staticmethod def to_prufer(tree, n): """Return the Prufer sequence for a tree given as a list of edges where ``n`` is the number of nodes in the tree. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) >>> a.prufer_repr [0, 0] >>> Prufer.to_prufer([[0, 1], [0, 2], [0, 3]], 4) [0, 0] See Also ======== prufer_repr: returns Prufer sequence of a Prufer object. """ d = defaultdict(int) L = [] for edge in tree: # Increment the value of the corresponding # node in the degree list as we encounter an # edge involving it. d[edge[0]] += 1 d[edge[1]] += 1 for i in range(n - 2): # find the smallest leaf for x in range(n): if d[x] == 1: break # find the node it was connected to y = None for edge in tree: if x == edge[0]: y = edge[1] elif x == edge[1]: y = edge[0] if y is not None: break # record and update L.append(y) for j in (x, y): d[j] -= 1 if not d[j]: d.pop(j) tree.remove(edge) return L @staticmethod def to_tree(prufer): """Return the tree (as a list of edges) of the given Prufer sequence. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> a = Prufer([0, 2], 4) >>> a.tree_repr [[0, 1], [0, 2], [2, 3]] >>> Prufer.to_tree([0, 2]) [[0, 1], [0, 2], [2, 3]] References ========== - https://hamberg.no/erlend/posts/2010-11-06-prufer-sequence-compact-tree-representation.html See Also ======== tree_repr: returns tree representation of a Prufer object. """ tree = [] last = [] n = len(prufer) + 2 d = defaultdict(lambda: 1) for p in prufer: d[p] += 1 for i in prufer: for j in range(n): # find the smallest leaf (degree = 1) if d[j] == 1: break # (i, j) is the new edge that we append to the tree # and remove from the degree dictionary d[i] -= 1 d[j] -= 1 tree.append(sorted([i, j])) last = [i for i in range(n) if d[i] == 1] or [0, 1] tree.append(last) return tree @staticmethod def edges(*runs): """Return a list of edges and the number of nodes from the given runs that connect nodes in an integer-labelled tree. All node numbers will be shifted so that the minimum node is 0. It is not a problem if edges are repeated in the runs; only unique edges are returned. There is no assumption made about what the range of the node labels should be, but all nodes from the smallest through the largest must be present. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> Prufer.edges([1, 2, 3], [2, 4, 5]) # a T ([[0, 1], [1, 2], [1, 3], [3, 4]], 5) Duplicate edges are removed: >>> Prufer.edges([0, 1, 2, 3], [1, 4, 5], [1, 4, 6]) # a K ([[0, 1], [1, 2], [1, 4], [2, 3], [4, 5], [4, 6]], 7) """ e = set() nmin = runs[0][0] for r in runs: for i in range(len(r) - 1): a, b = r[i: i + 2] if b < a: a, b = b, a e.add((a, b)) rv = [] got = set() nmin = nmax = None for ei in e: for i in ei: got.add(i) nmin = min(ei[0], nmin) if nmin is not None else ei[0] nmax = max(ei[1], nmax) if nmax is not None else ei[1] rv.append(list(ei)) missing = set(range(nmin, nmax + 1)) - got if missing: missing = [i + nmin for i in missing] if len(missing) == 1: msg = 'Node %s is missing.' % missing.pop() else: msg = 'Nodes %s are missing.' % list(sorted(missing)) raise ValueError(msg) if nmin != 0: for i, ei in enumerate(rv): rv[i] = [n - nmin for n in ei] nmax -= nmin return sorted(rv), nmax + 1 def prufer_rank(self): """Computes the rank of a Prufer sequence. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) >>> a.prufer_rank() 0 See Also ======== rank, next, prev, size """ r = 0 p = 1 for i in range(self.nodes - 3, -1, -1): r += p*self.prufer_repr[i] p *= self.nodes return r @classmethod def unrank(self, rank, n): """Finds the unranked Prufer sequence. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> Prufer.unrank(0, 4) Prufer([0, 0]) """ n, rank = as_int(n), as_int(rank) L = defaultdict(int) for i in range(n - 3, -1, -1): L[i] = rank % n rank = (rank - L[i])//n return Prufer([L[i] for i in range(len(L))]) def __new__(cls, *args, **kw_args): """The constructor for the Prufer object. Examples ======== >>> from sympy.combinatorics.prufer import Prufer A Prufer object can be constructed from a list of edges: >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) >>> a.prufer_repr [0, 0] If the number of nodes is given, no checking of the nodes will be performed; it will be assumed that nodes 0 through n - 1 are present: >>> Prufer([[0, 1], [0, 2], [0, 3]], 4) Prufer([[0, 1], [0, 2], [0, 3]], 4) A Prufer object can be constructed from a Prufer sequence: >>> b = Prufer([1, 3]) >>> b.tree_repr [[0, 1], [1, 3], [2, 3]] """ ret_obj = Basic.__new__(cls, *args, **kw_args) args = [list(args[0])] if args[0] and iterable(args[0][0]): if not args[0][0]: raise ValueError( 'Prufer expects at least one edge in the tree.') if len(args) > 1: nnodes = args[1] else: nodes = set(flatten(args[0])) nnodes = max(nodes) + 1 if nnodes != len(nodes): missing = set(range(nnodes)) - nodes if len(missing) == 1: msg = 'Node %s is missing.' % missing.pop() else: msg = 'Nodes %s are missing.' % list(sorted(missing)) raise ValueError(msg) ret_obj._tree_repr = [list(i) for i in args[0]] ret_obj._nodes = nnodes else: ret_obj._prufer_repr = args[0] ret_obj._nodes = len(ret_obj._prufer_repr) + 2 return ret_obj def next(self, delta=1): """Generates the Prufer sequence that is delta beyond the current one. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> a = Prufer([[0, 1], [0, 2], [0, 3]]) >>> b = a.next(1) # == a.next() >>> b.tree_repr [[0, 2], [0, 1], [1, 3]] >>> b.rank 1 See Also ======== prufer_rank, rank, prev, size """ return Prufer.unrank(self.rank + delta, self.nodes) def prev(self, delta=1): """Generates the Prufer sequence that is -delta before the current one. Examples ======== >>> from sympy.combinatorics.prufer import Prufer >>> a = Prufer([[0, 1], [1, 2], [2, 3], [1, 4]]) >>> a.rank 36 >>> b = a.prev() >>> b Prufer([1, 2, 0]) >>> b.rank 35 See Also ======== prufer_rank, rank, next, size """ return Prufer.unrank(self.rank -delta, self.nodes) sympy-sympy-1.9/sympy/combinatorics/rewritingsystem.py000066400000000000000000000414271412543434000236010ustar00rootroot00000000000000from sympy.combinatorics.rewritingsystem_fsm import StateMachine class RewritingSystem: ''' A class implementing rewriting systems for `FpGroup`s. References ========== .. [1] Epstein, D., Holt, D. and Rees, S. (1991). The use of Knuth-Bendix methods to solve the word problem in automatic groups. Journal of Symbolic Computation, 12(4-5), pp.397-414. .. [2] GAP's Manual on its KBMAG package https://www.gap-system.org/Manuals/pkg/kbmag-1.5.3/doc/manual.pdf ''' def __init__(self, group): from collections import deque self.group = group self.alphabet = group.generators self._is_confluent = None # these values are taken from [2] self.maxeqns = 32767 # max rules self.tidyint = 100 # rules before tidying # _max_exceeded is True if maxeqns is exceeded # at any point self._max_exceeded = False # Reduction automaton self.reduction_automaton = None self._new_rules = {} # dictionary of reductions self.rules = {} self.rules_cache = deque([], 50) self._init_rules() # All the transition symbols in the automaton generators = list(self.alphabet) generators += [gen**-1 for gen in generators] # Create a finite state machine as an instance of the StateMachine object self.reduction_automaton = StateMachine('Reduction automaton for '+ repr(self.group), generators) self.construct_automaton() def set_max(self, n): ''' Set the maximum number of rules that can be defined ''' if n > self.maxeqns: self._max_exceeded = False self.maxeqns = n return @property def is_confluent(self): ''' Return `True` if the system is confluent ''' if self._is_confluent is None: self._is_confluent = self._check_confluence() return self._is_confluent def _init_rules(self): identity = self.group.free_group.identity for r in self.group.relators: self.add_rule(r, identity) self._remove_redundancies() return def _add_rule(self, r1, r2): ''' Add the rule r1 -> r2 with no checking or further deductions ''' if len(self.rules) + 1 > self.maxeqns: self._is_confluent = self._check_confluence() self._max_exceeded = True raise RuntimeError("Too many rules were defined.") self.rules[r1] = r2 # Add the newly added rule to the `new_rules` dictionary. if self.reduction_automaton: self._new_rules[r1] = r2 def add_rule(self, w1, w2, check=False): new_keys = set() if w1 == w2: return new_keys if w1 < w2: w1, w2 = w2, w1 if (w1, w2) in self.rules_cache: return new_keys self.rules_cache.append((w1, w2)) s1, s2 = w1, w2 # The following is the equivalent of checking # s1 for overlaps with the implicit reductions # {g*g**-1 -> } and {g**-1*g -> } # for any generator g without installing the # redundant rules that would result from processing # the overlaps. See [1], Section 3 for details. if len(s1) - len(s2) < 3: if s1 not in self.rules: new_keys.add(s1) if not check: self._add_rule(s1, s2) if s2**-1 > s1**-1 and s2**-1 not in self.rules: new_keys.add(s2**-1) if not check: self._add_rule(s2**-1, s1**-1) # overlaps on the right while len(s1) - len(s2) > -1: g = s1[len(s1)-1] s1 = s1.subword(0, len(s1)-1) s2 = s2*g**-1 if len(s1) - len(s2) < 0: if s2 not in self.rules: if not check: self._add_rule(s2, s1) new_keys.add(s2) elif len(s1) - len(s2) < 3: new = self.add_rule(s1, s2, check) new_keys.update(new) # overlaps on the left while len(w1) - len(w2) > -1: g = w1[0] w1 = w1.subword(1, len(w1)) w2 = g**-1*w2 if len(w1) - len(w2) < 0: if w2 not in self.rules: if not check: self._add_rule(w2, w1) new_keys.add(w2) elif len(w1) - len(w2) < 3: new = self.add_rule(w1, w2, check) new_keys.update(new) return new_keys def _remove_redundancies(self, changes=False): ''' Reduce left- and right-hand sides of reduction rules and remove redundant equations (i.e. those for which lhs == rhs). If `changes` is `True`, return a set containing the removed keys and a set containing the added keys ''' removed = set() added = set() rules = self.rules.copy() for r in rules: v = self.reduce(r, exclude=r) w = self.reduce(rules[r]) if v != r: del self.rules[r] removed.add(r) if v > w: added.add(v) self.rules[v] = w elif v < w: added.add(w) self.rules[w] = v else: self.rules[v] = w if changes: return removed, added return def make_confluent(self, check=False): ''' Try to make the system confluent using the Knuth-Bendix completion algorithm ''' if self._max_exceeded: return self._is_confluent lhs = list(self.rules.keys()) def _overlaps(r1, r2): len1 = len(r1) len2 = len(r2) result = [] for j in range(1, len1 + len2): if (r1.subword(len1 - j, len1 + len2 - j, strict=False) == r2.subword(j - len1, j, strict=False)): a = r1.subword(0, len1-j, strict=False) a = a*r2.subword(0, j-len1, strict=False) b = r2.subword(j-len1, j, strict=False) c = r2.subword(j, len2, strict=False) c = c*r1.subword(len1 + len2 - j, len1, strict=False) result.append(a*b*c) return result def _process_overlap(w, r1, r2, check): s = w.eliminate_word(r1, self.rules[r1]) s = self.reduce(s) t = w.eliminate_word(r2, self.rules[r2]) t = self.reduce(t) if s != t: if check: # system not confluent return [0] try: new_keys = self.add_rule(t, s, check) return new_keys except RuntimeError: return False return added = 0 i = 0 while i < len(lhs): r1 = lhs[i] i += 1 # j could be i+1 to not # check each pair twice but lhs # is extended in the loop and the new # elements have to be checked with the # preceding ones. there is probably a better way # to handle this j = 0 while j < len(lhs): r2 = lhs[j] j += 1 if r1 == r2: continue overlaps = _overlaps(r1, r2) overlaps.extend(_overlaps(r1**-1, r2)) if not overlaps: continue for w in overlaps: new_keys = _process_overlap(w, r1, r2, check) if new_keys: if check: return False lhs.extend(new_keys) added += len(new_keys) elif new_keys == False: # too many rules were added so the process # couldn't complete return self._is_confluent if added > self.tidyint and not check: # tidy up r, a = self._remove_redundancies(changes=True) added = 0 if r: # reset i since some elements were removed i = min([lhs.index(s) for s in r]) lhs = [l for l in lhs if l not in r] lhs.extend(a) if r1 in r: # r1 was removed as redundant break self._is_confluent = True if not check: self._remove_redundancies() return True def _check_confluence(self): return self.make_confluent(check=True) def reduce(self, word, exclude=None): ''' Apply reduction rules to `word` excluding the reduction rule for the lhs equal to `exclude` ''' rules = {r: self.rules[r] for r in self.rules if r != exclude} # the following is essentially `eliminate_words()` code from the # `FreeGroupElement` class, the only difference being the first # "if" statement again = True new = word while again: again = False for r in rules: prev = new if rules[r]**-1 > r**-1: new = new.eliminate_word(r, rules[r], _all=True, inverse=False) else: new = new.eliminate_word(r, rules[r], _all=True) if new != prev: again = True return new def _compute_inverse_rules(self, rules): ''' Compute the inverse rules for a given set of rules. The inverse rules are used in the automaton for word reduction. Arguments: rules (dictionary): Rules for which the inverse rules are to computed. Returns: Dictionary of inverse_rules. ''' inverse_rules = {} for r in rules: rule_key_inverse = r**-1 rule_value_inverse = (rules[r])**-1 if (rule_value_inverse < rule_key_inverse): inverse_rules[rule_key_inverse] = rule_value_inverse else: inverse_rules[rule_value_inverse] = rule_key_inverse return inverse_rules def construct_automaton(self): ''' Construct the automaton based on the set of reduction rules of the system. Automata Design: The accept states of the automaton are the proper prefixes of the left hand side of the rules. The complete left hand side of the rules are the dead states of the automaton. ''' self._add_to_automaton(self.rules) def _add_to_automaton(self, rules): ''' Add new states and transitions to the automaton. Summary: States corresponding to the new rules added to the system are computed and added to the automaton. Transitions in the previously added states are also modified if necessary. Arguments: rules (dictionary) -- Dictionary of the newly added rules. ''' # Automaton variables automaton_alphabet = [] proper_prefixes = {} # compute the inverses of all the new rules added all_rules = rules inverse_rules = self._compute_inverse_rules(all_rules) all_rules.update(inverse_rules) # Keep track of the accept_states. accept_states = [] for rule in all_rules: # The symbols present in the new rules are the symbols to be verified at each state. # computes the automaton_alphabet, as the transitions solely depend upon the new states. automaton_alphabet += rule.letter_form_elm # Compute the proper prefixes for every rule. proper_prefixes[rule] = [] letter_word_array = [s for s in rule.letter_form_elm] len_letter_word_array = len(letter_word_array) for i in range (1, len_letter_word_array): letter_word_array[i] = letter_word_array[i-1]*letter_word_array[i] # Add accept states. elem = letter_word_array[i-1] if not elem in self.reduction_automaton.states: self.reduction_automaton.add_state(elem, state_type='a') accept_states.append(elem) proper_prefixes[rule] = letter_word_array # Check for overlaps between dead and accept states. if rule in accept_states: self.reduction_automaton.states[rule].state_type = 'd' self.reduction_automaton.states[rule].rh_rule = all_rules[rule] accept_states.remove(rule) # Add dead states if not rule in self.reduction_automaton.states: self.reduction_automaton.add_state(rule, state_type='d', rh_rule=all_rules[rule]) automaton_alphabet = set(automaton_alphabet) # Add new transitions for every state. for state in self.reduction_automaton.states: current_state_name = state current_state_type = self.reduction_automaton.states[state].state_type # Transitions will be modified only when suffixes of the current_state # belongs to the proper_prefixes of the new rules. # The rest are ignored if they cannot lead to a dead state after a finite number of transisitons. if current_state_type == 's': for letter in automaton_alphabet: if letter in self.reduction_automaton.states: self.reduction_automaton.states[state].add_transition(letter, letter) else: self.reduction_automaton.states[state].add_transition(letter, current_state_name) elif current_state_type == 'a': # Check if the transition to any new state in possible. for letter in automaton_alphabet: _next = current_state_name*letter while len(_next) and _next not in self.reduction_automaton.states: _next = _next.subword(1, len(_next)) if not len(_next): _next = 'start' self.reduction_automaton.states[state].add_transition(letter, _next) # Add transitions for new states. All symbols used in the automaton are considered here. # Ignore this if `reduction_automaton.automaton_alphabet` = `automaton_alphabet`. if len(self.reduction_automaton.automaton_alphabet) != len(automaton_alphabet): for state in accept_states: current_state_name = state for letter in self.reduction_automaton.automaton_alphabet: _next = current_state_name*letter while len(_next) and _next not in self.reduction_automaton.states: _next = _next.subword(1, len(_next)) if not len(_next): _next = 'start' self.reduction_automaton.states[state].add_transition(letter, _next) def reduce_using_automaton(self, word): ''' Reduce a word using an automaton. Summary: All the symbols of the word are stored in an array and are given as the input to the automaton. If the automaton reaches a dead state that subword is replaced and the automaton is run from the beginning. The complete word has to be replaced when the word is read and the automaton reaches a dead state. So, this process is repeated until the word is read completely and the automaton reaches the accept state. Arguments: word (instance of FreeGroupElement) -- Word that needs to be reduced. ''' # Modify the automaton if new rules are found. if self._new_rules: self._add_to_automaton(self._new_rules) self._new_rules = {} flag = 1 while flag: flag = 0 current_state = self.reduction_automaton.states['start'] word_array = [s for s in word.letter_form_elm] for i in range (0, len(word_array)): next_state_name = current_state.transitions[word_array[i]] next_state = self.reduction_automaton.states[next_state_name] if next_state.state_type == 'd': subst = next_state.rh_rule word = word.substituted_word(i - len(next_state_name) + 1, i+1, subst) flag = 1 break current_state = next_state return word sympy-sympy-1.9/sympy/combinatorics/rewritingsystem_fsm.py000066400000000000000000000046011412543434000244370ustar00rootroot00000000000000class State: ''' A representation of a state managed by a ``StateMachine``. Attributes: name (instance of FreeGroupElement or string) -- State name which is also assigned to the Machine. transisitons (OrderedDict) -- Represents all the transitions of the state object. state_type (string) -- Denotes the type (accept/start/dead) of the state. rh_rule (instance of FreeGroupElement) -- right hand rule for dead state. state_machine (instance of StateMachine object) -- The finite state machine that the state belongs to. ''' def __init__(self, name, state_machine, state_type=None, rh_rule=None): self.name = name self.transitions = {} self.state_machine = state_machine self.state_type = state_type[0] self.rh_rule = rh_rule def add_transition(self, letter, state): ''' Add a transition from the current state to a new state. Keyword Arguments: letter -- The alphabet element the current state reads to make the state transition. state -- This will be an instance of the State object which represents a new state after in the transition after the alphabet is read. ''' self.transitions[letter] = state class StateMachine: ''' Representation of a finite state machine the manages the states and the transitions of the automaton. Attributes: states (dictionary) -- Collection of all registered `State` objects. name (str) -- Name of the state machine. ''' def __init__(self, name, automaton_alphabet): self.name = name self.automaton_alphabet = automaton_alphabet self.states = {} # Contains all the states in the machine. self.add_state('start', state_type='s') def add_state(self, state_name, state_type=None, rh_rule=None): ''' Instantiate a state object and stores it in the 'states' dictionary. Arguments: state_name (instance of FreeGroupElement or string) -- name of the new states. state_type (string) -- Denotes the type (accept/start/dead) of the state added. rh_rule (instance of FreeGroupElement) -- right hand rule for dead state. ''' new_state = State(state_name, self, state_type, rh_rule) self.states[state_name] = new_state def __repr__(self): return "%s" % (self.name) sympy-sympy-1.9/sympy/combinatorics/schur_number.py000066400000000000000000000100401412543434000230010ustar00rootroot00000000000000""" The Schur number S(k) is the largest integer n for which the interval [1,n] can be partitioned into k sum-free sets.(http://mathworld.wolfram.com/SchurNumber.html) """ import math from sympy.core import S from sympy.core.basic import Basic from sympy.core.function import Function from sympy.core.numbers import Integer class SchurNumber(Function): """ This function creates a SchurNumber object which is evaluated for k <= 4 otherwise only the lower bound information can be retrieved. Examples ======== >>> from sympy.combinatorics.schur_number import SchurNumber Since S(3) = 13, hence the output is a number >>> SchurNumber(3) 13 We don't know the schur number for values greater than 4, hence only the object is returned >>> SchurNumber(6) SchurNumber(6) Now, the lower bound information can be retrieved using lower_bound() method >>> SchurNumber(6).lower_bound() 364 """ @classmethod def eval(cls, k): if k.is_Number: if k is S.Infinity: return S.Infinity if k.is_zero: return 0 if not k.is_integer or k.is_negative: raise ValueError("k should be a positive integer") first_known_schur_numbers = {1: 1, 2: 4, 3: 13, 4: 44} if k <= 4: return Integer(first_known_schur_numbers[k]) def lower_bound(self): f_ = self.args[0] return (3**f_ - 1)/2 def _schur_subsets_number(n): if n is S.Infinity: raise ValueError("Input must be finite") if n <= 0: raise ValueError("n must be a non-zero positive integer.") elif n <= 3: min_k = 1 else: min_k = math.ceil(math.log(2*n + 1, 3)) return Integer(min_k) def schur_partition(n): """ This function returns the partition in the minimum number of sum-free subsets according to the lower bound given by the Schur Number. Parameters ========== n: a number n is the upper limit of the range [1, n] for which we need to find and return the minimum number of free subsets according to the lower bound of schur number Returns ======= List of lists List of the minimum number of sum-free subsets Notes ===== It is possible for some n to make the partition into less subsets since the only known Schur numbers are: S(1) = 1, S(2) = 4 , S(3) = 13, S(4) = 44. e.g for n = 44 the lower bound from the function above is 5 subsets but it has been proven that can be done with 4 subsets. Examples ======== For n = 1, 2, 3 the answer is the set itself >>> from sympy.combinatorics.schur_number import schur_partition >>> schur_partition(2) [[1, 2]] For n > 3, the answer is the minimum number of sum-free subsets: >>> schur_partition(5) [[3, 2], [5], [1, 4]] >>> schur_partition(8) [[3, 2], [6, 5, 8], [1, 4, 7]] """ if isinstance(n, Basic) and not n.is_Number: raise ValueError("Input value must be a number") number_of_subsets = _schur_subsets_number(n) if n == 1: sum_free_subsets = [[1]] elif n == 2: sum_free_subsets = [[1, 2]] elif n == 3: sum_free_subsets = [[1, 2, 3]] else: sum_free_subsets = [[1, 4], [2, 3]] while len(sum_free_subsets) < number_of_subsets: sum_free_subsets = _generate_next_list(sum_free_subsets, n) missed_elements = [3*k + 1 for k in range(len(sum_free_subsets), (n-1)//3 + 1)] sum_free_subsets[-1] += missed_elements return sum_free_subsets def _generate_next_list(current_list, n): new_list = [] for item in current_list: temp_1 = [number*3 for number in item if number*3 <= n] temp_2 = [number*3 - 1 for number in item if number*3 - 1 <= n] new_item = temp_1 + temp_2 new_list.append(new_item) last_list = [3*k + 1 for k in range(0, len(current_list)+1) if 3*k + 1 <= n] new_list.append(last_list) current_list = new_list return current_list sympy-sympy-1.9/sympy/combinatorics/subsets.py000066400000000000000000000367621412543434000220200ustar00rootroot00000000000000from itertools import combinations from sympy.combinatorics.graycode import GrayCode from sympy.core import Basic class Subset(Basic): """ Represents a basic subset object. Explanation =========== We generate subsets using essentially two techniques, binary enumeration and lexicographic enumeration. The Subset class takes two arguments, the first one describes the initial subset to consider and the second describes the superset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.next_binary().subset ['b'] >>> a.prev_binary().subset ['c'] """ _rank_binary = None _rank_lex = None _rank_graycode = None _subset = None _superset = None def __new__(cls, subset, superset): """ Default constructor. It takes the ``subset`` and its ``superset`` as its parameters. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.subset ['c', 'd'] >>> a.superset ['a', 'b', 'c', 'd'] >>> a.size 2 """ if len(subset) > len(superset): raise ValueError('Invalid arguments have been provided. The ' 'superset must be larger than the subset.') for elem in subset: if elem not in superset: raise ValueError('The superset provided is invalid as it does ' 'not contain the element {}'.format(elem)) obj = Basic.__new__(cls) obj._subset = subset obj._superset = superset return obj def iterate_binary(self, k): """ This is a helper function. It iterates over the binary subsets by ``k`` steps. This variable can be both positive or negative. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.iterate_binary(-2).subset ['d'] >>> a = Subset(['a', 'b', 'c'], ['a', 'b', 'c', 'd']) >>> a.iterate_binary(2).subset [] See Also ======== next_binary, prev_binary """ bin_list = Subset.bitlist_from_subset(self.subset, self.superset) n = (int(''.join(bin_list), 2) + k) % 2**self.superset_size bits = bin(n)[2:].rjust(self.superset_size, '0') return Subset.subset_from_bitlist(self.superset, bits) def next_binary(self): """ Generates the next binary ordered subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.next_binary().subset ['b'] >>> a = Subset(['a', 'b', 'c', 'd'], ['a', 'b', 'c', 'd']) >>> a.next_binary().subset [] See Also ======== prev_binary, iterate_binary """ return self.iterate_binary(1) def prev_binary(self): """ Generates the previous binary ordered subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset([], ['a', 'b', 'c', 'd']) >>> a.prev_binary().subset ['a', 'b', 'c', 'd'] >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.prev_binary().subset ['c'] See Also ======== next_binary, iterate_binary """ return self.iterate_binary(-1) def next_lexicographic(self): """ Generates the next lexicographically ordered subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.next_lexicographic().subset ['d'] >>> a = Subset(['d'], ['a', 'b', 'c', 'd']) >>> a.next_lexicographic().subset [] See Also ======== prev_lexicographic """ i = self.superset_size - 1 indices = Subset.subset_indices(self.subset, self.superset) if i in indices: if i - 1 in indices: indices.remove(i - 1) else: indices.remove(i) i = i - 1 while not i in indices and i >= 0: i = i - 1 if i >= 0: indices.remove(i) indices.append(i+1) else: while i not in indices and i >= 0: i = i - 1 indices.append(i + 1) ret_set = [] super_set = self.superset for i in indices: ret_set.append(super_set[i]) return Subset(ret_set, super_set) def prev_lexicographic(self): """ Generates the previous lexicographically ordered subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset([], ['a', 'b', 'c', 'd']) >>> a.prev_lexicographic().subset ['d'] >>> a = Subset(['c','d'], ['a', 'b', 'c', 'd']) >>> a.prev_lexicographic().subset ['c'] See Also ======== next_lexicographic """ i = self.superset_size - 1 indices = Subset.subset_indices(self.subset, self.superset) while i not in indices and i >= 0: i = i - 1 if i - 1 in indices or i == 0: indices.remove(i) else: if i >= 0: indices.remove(i) indices.append(i - 1) indices.append(self.superset_size - 1) ret_set = [] super_set = self.superset for i in indices: ret_set.append(super_set[i]) return Subset(ret_set, super_set) def iterate_graycode(self, k): """ Helper function used for prev_gray and next_gray. It performs ``k`` step overs to get the respective Gray codes. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset([1, 2, 3], [1, 2, 3, 4]) >>> a.iterate_graycode(3).subset [1, 4] >>> a.iterate_graycode(-2).subset [1, 2, 4] See Also ======== next_gray, prev_gray """ unranked_code = GrayCode.unrank(self.superset_size, (self.rank_gray + k) % self.cardinality) return Subset.subset_from_bitlist(self.superset, unranked_code) def next_gray(self): """ Generates the next Gray code ordered subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset([1, 2, 3], [1, 2, 3, 4]) >>> a.next_gray().subset [1, 3] See Also ======== iterate_graycode, prev_gray """ return self.iterate_graycode(1) def prev_gray(self): """ Generates the previous Gray code ordered subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset([2, 3, 4], [1, 2, 3, 4, 5]) >>> a.prev_gray().subset [2, 3, 4, 5] See Also ======== iterate_graycode, next_gray """ return self.iterate_graycode(-1) @property def rank_binary(self): """ Computes the binary ordered rank. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset([], ['a','b','c','d']) >>> a.rank_binary 0 >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.rank_binary 3 See Also ======== iterate_binary, unrank_binary """ if self._rank_binary is None: self._rank_binary = int("".join( Subset.bitlist_from_subset(self.subset, self.superset)), 2) return self._rank_binary @property def rank_lexicographic(self): """ Computes the lexicographic ranking of the subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.rank_lexicographic 14 >>> a = Subset([2, 4, 5], [1, 2, 3, 4, 5, 6]) >>> a.rank_lexicographic 43 """ if self._rank_lex is None: def _ranklex(self, subset_index, i, n): if subset_index == [] or i > n: return 0 if i in subset_index: subset_index.remove(i) return 1 + _ranklex(self, subset_index, i + 1, n) return 2**(n - i - 1) + _ranklex(self, subset_index, i + 1, n) indices = Subset.subset_indices(self.subset, self.superset) self._rank_lex = _ranklex(self, indices, 0, self.superset_size) return self._rank_lex @property def rank_gray(self): """ Computes the Gray code ranking of the subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c','d'], ['a','b','c','d']) >>> a.rank_gray 2 >>> a = Subset([2, 4, 5], [1, 2, 3, 4, 5, 6]) >>> a.rank_gray 27 See Also ======== iterate_graycode, unrank_gray """ if self._rank_graycode is None: bits = Subset.bitlist_from_subset(self.subset, self.superset) self._rank_graycode = GrayCode(len(bits), start=bits).rank return self._rank_graycode @property def subset(self): """ Gets the subset represented by the current instance. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.subset ['c', 'd'] See Also ======== superset, size, superset_size, cardinality """ return self._subset @property def size(self): """ Gets the size of the subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.size 2 See Also ======== subset, superset, superset_size, cardinality """ return len(self.subset) @property def superset(self): """ Gets the superset of the subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.superset ['a', 'b', 'c', 'd'] See Also ======== subset, size, superset_size, cardinality """ return self._superset @property def superset_size(self): """ Returns the size of the superset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.superset_size 4 See Also ======== subset, superset, size, cardinality """ return len(self.superset) @property def cardinality(self): """ Returns the number of all possible subsets. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) >>> a.cardinality 16 See Also ======== subset, superset, size, superset_size """ return 2**(self.superset_size) @classmethod def subset_from_bitlist(self, super_set, bitlist): """ Gets the subset defined by the bitlist. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> Subset.subset_from_bitlist(['a', 'b', 'c', 'd'], '0011').subset ['c', 'd'] See Also ======== bitlist_from_subset """ if len(super_set) != len(bitlist): raise ValueError("The sizes of the lists are not equal") ret_set = [] for i in range(len(bitlist)): if bitlist[i] == '1': ret_set.append(super_set[i]) return Subset(ret_set, super_set) @classmethod def bitlist_from_subset(self, subset, superset): """ Gets the bitlist corresponding to a subset. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> Subset.bitlist_from_subset(['c', 'd'], ['a', 'b', 'c', 'd']) '0011' See Also ======== subset_from_bitlist """ bitlist = ['0'] * len(superset) if type(subset) is Subset: subset = subset.subset for i in Subset.subset_indices(subset, superset): bitlist[i] = '1' return ''.join(bitlist) @classmethod def unrank_binary(self, rank, superset): """ Gets the binary ordered subset of the specified rank. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> Subset.unrank_binary(4, ['a', 'b', 'c', 'd']).subset ['b'] See Also ======== iterate_binary, rank_binary """ bits = bin(rank)[2:].rjust(len(superset), '0') return Subset.subset_from_bitlist(superset, bits) @classmethod def unrank_gray(self, rank, superset): """ Gets the Gray code ordered subset of the specified rank. Examples ======== >>> from sympy.combinatorics.subsets import Subset >>> Subset.unrank_gray(4, ['a', 'b', 'c']).subset ['a', 'b'] >>> Subset.unrank_gray(0, ['a', 'b', 'c']).subset [] See Also ======== iterate_graycode, rank_gray """ graycode_bitlist = GrayCode.unrank(len(superset), rank) return Subset.subset_from_bitlist(superset, graycode_bitlist) @classmethod def subset_indices(self, subset, superset): """Return indices of subset in superset in a list; the list is empty if all elements of ``subset`` are not in ``superset``. Examples ======== >>> from sympy.combinatorics import Subset >>> superset = [1, 3, 2, 5, 4] >>> Subset.subset_indices([3, 2, 1], superset) [1, 2, 0] >>> Subset.subset_indices([1, 6], superset) [] >>> Subset.subset_indices([], superset) [] """ a, b = superset, subset sb = set(b) d = {} for i, ai in enumerate(a): if ai in sb: d[ai] = i sb.remove(ai) if not sb: break else: return list() return [d[bi] for bi in b] def ksubsets(superset, k): """ Finds the subsets of size ``k`` in lexicographic order. This uses the itertools generator. Examples ======== >>> from sympy.combinatorics.subsets import ksubsets >>> list(ksubsets([1, 2, 3], 2)) [(1, 2), (1, 3), (2, 3)] >>> list(ksubsets([1, 2, 3, 4, 5], 2)) [(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), \ (2, 5), (3, 4), (3, 5), (4, 5)] See Also ======== Subset """ return combinations(superset, k) sympy-sympy-1.9/sympy/combinatorics/tensor_can.py000066400000000000000000001174661412543434000224640ustar00rootroot00000000000000from sympy.combinatorics.permutations import Permutation, _af_rmul, \ _af_invert, _af_new from sympy.combinatorics.perm_groups import PermutationGroup, _orbit, \ _orbit_transversal from sympy.combinatorics.util import _distribute_gens_by_base, \ _orbits_transversals_from_bsgs """ References for tensor canonicalization: [1] R. Portugal "Algorithmic simplification of tensor expressions", J. Phys. A 32 (1999) 7779-7789 [2] R. Portugal, B.F. Svaiter "Group-theoretic Approach for Symbolic Tensor Manipulation: I. Free Indices" arXiv:math-ph/0107031v1 [3] L.R.U. Manssur, R. Portugal "Group-theoretic Approach for Symbolic Tensor Manipulation: II. Dummy Indices" arXiv:math-ph/0107032v1 [4] xperm.c part of XPerm written by J. M. Martin-Garcia http://www.xact.es/index.html """ def dummy_sgs(dummies, sym, n): """ Return the strong generators for dummy indices. Parameters ========== dummies : List of dummy indices. `dummies[2k], dummies[2k+1]` are paired indices. In base form, the dummy indices are always in consecutive positions. sym : symmetry under interchange of contracted dummies:: * None no symmetry * 0 commuting * 1 anticommuting n : number of indices Examples ======== >>> from sympy.combinatorics.tensor_can import dummy_sgs >>> dummy_sgs(list(range(2, 8)), 0, 8) [[0, 1, 3, 2, 4, 5, 6, 7, 8, 9], [0, 1, 2, 3, 5, 4, 6, 7, 8, 9], [0, 1, 2, 3, 4, 5, 7, 6, 8, 9], [0, 1, 4, 5, 2, 3, 6, 7, 8, 9], [0, 1, 2, 3, 6, 7, 4, 5, 8, 9]] """ if len(dummies) > n: raise ValueError("List too large") res = [] # exchange of contravariant and covariant indices if sym is not None: for j in dummies[::2]: a = list(range(n + 2)) if sym == 1: a[n] = n + 1 a[n + 1] = n a[j], a[j + 1] = a[j + 1], a[j] res.append(a) # rename dummy indices for j in dummies[:-3:2]: a = list(range(n + 2)) a[j:j + 4] = a[j + 2], a[j + 3], a[j], a[j + 1] res.append(a) return res def _min_dummies(dummies, sym, indices): """ Return list of minima of the orbits of indices in group of dummies. See ``double_coset_can_rep`` for the description of ``dummies`` and ``sym``. ``indices`` is the initial list of dummy indices. Examples ======== >>> from sympy.combinatorics.tensor_can import _min_dummies >>> _min_dummies([list(range(2, 8))], [0], list(range(10))) [0, 1, 2, 2, 2, 2, 2, 2, 8, 9] """ num_types = len(sym) m = [] for dx in dummies: if dx: m.append(min(dx)) else: m.append(None) res = indices[:] for i in range(num_types): for c, i in enumerate(indices): for j in range(num_types): if i in dummies[j]: res[c] = m[j] break return res def _trace_S(s, j, b, S_cosets): """ Return the representative h satisfying s[h[b]] == j If there is not such a representative return None """ for h in S_cosets[b]: if s[h[b]] == j: return h return None def _trace_D(gj, p_i, Dxtrav): """ Return the representative h satisfying h[gj] == p_i If there is not such a representative return None """ for h in Dxtrav: if h[gj] == p_i: return h return None def _dumx_remove(dumx, dumx_flat, p0): """ remove p0 from dumx """ res = [] for dx in dumx: if p0 not in dx: res.append(dx) continue k = dx.index(p0) if k % 2 == 0: p0_paired = dx[k + 1] else: p0_paired = dx[k - 1] dx.remove(p0) dx.remove(p0_paired) dumx_flat.remove(p0) dumx_flat.remove(p0_paired) res.append(dx) def transversal2coset(size, base, transversal): a = [] j = 0 for i in range(size): if i in base: a.append(sorted(transversal[j].values())) j += 1 else: a.append([list(range(size))]) j = len(a) - 1 while a[j] == [list(range(size))]: j -= 1 return a[:j + 1] def double_coset_can_rep(dummies, sym, b_S, sgens, S_transversals, g): """ Butler-Portugal algorithm for tensor canonicalization with dummy indices. Parameters ========== dummies list of lists of dummy indices, one list for each type of index; the dummy indices are put in order contravariant, covariant [d0, -d0, d1, -d1, ...]. sym list of the symmetries of the index metric for each type. possible symmetries of the metrics * 0 symmetric * 1 antisymmetric * None no symmetry b_S base of a minimal slot symmetry BSGS. sgens generators of the slot symmetry BSGS. S_transversals transversals for the slot BSGS. g permutation representing the tensor. Returns ======= Return 0 if the tensor is zero, else return the array form of the permutation representing the canonical form of the tensor. Notes ===== A tensor with dummy indices can be represented in a number of equivalent ways which typically grows exponentially with the number of indices. To be able to establish if two tensors with many indices are equal becomes computationally very slow in absence of an efficient algorithm. The Butler-Portugal algorithm [3] is an efficient algorithm to put tensors in canonical form, solving the above problem. Portugal observed that a tensor can be represented by a permutation, and that the class of tensors equivalent to it under slot and dummy symmetries is equivalent to the double coset `D*g*S` (Note: in this documentation we use the conventions for multiplication of permutations p, q with (p*q)(i) = p[q[i]] which is opposite to the one used in the Permutation class) Using the algorithm by Butler to find a representative of the double coset one can find a canonical form for the tensor. To see this correspondence, let `g` be a permutation in array form; a tensor with indices `ind` (the indices including both the contravariant and the covariant ones) can be written as `t = T(ind[g[0]],..., ind[g[n-1]])`, where `n= len(ind)`; `g` has size `n + 2`, the last two indices for the sign of the tensor (trick introduced in [4]). A slot symmetry transformation `s` is a permutation acting on the slots `t -> T(ind[(g*s)[0]],..., ind[(g*s)[n-1]])` A dummy symmetry transformation acts on `ind` `t -> T(ind[(d*g)[0]],..., ind[(d*g)[n-1]])` Being interested only in the transformations of the tensor under these symmetries, one can represent the tensor by `g`, which transforms as `g -> d*g*s`, so it belongs to the coset `D*g*S`, or in other words to the set of all permutations allowed by the slot and dummy symmetries. Let us explain the conventions by an example. Given a tensor `T^{d3 d2 d1}{}_{d1 d2 d3}` with the slot symmetries `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}` `T^{a0 a1 a2 a3 a4 a5} = -T^{a4 a1 a2 a3 a0 a5}` and symmetric metric, find the tensor equivalent to it which is the lowest under the ordering of indices: lexicographic ordering `d1, d2, d3` and then contravariant before covariant index; that is the canonical form of the tensor. The canonical form is `-T^{d1 d2 d3}{}_{d1 d2 d3}` obtained using `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}`. To convert this problem in the input for this function, use the following ordering of the index names (- for covariant for short) `d1, -d1, d2, -d2, d3, -d3` `T^{d3 d2 d1}{}_{d1 d2 d3}` corresponds to `g = [4, 2, 0, 1, 3, 5, 6, 7]` where the last two indices are for the sign `sgens = [Permutation(0, 2)(6, 7), Permutation(0, 4)(6, 7)]` sgens[0] is the slot symmetry `-(0, 2)` `T^{a0 a1 a2 a3 a4 a5} = -T^{a2 a1 a0 a3 a4 a5}` sgens[1] is the slot symmetry `-(0, 4)` `T^{a0 a1 a2 a3 a4 a5} = -T^{a4 a1 a2 a3 a0 a5}` The dummy symmetry group D is generated by the strong base generators `[(0, 1), (2, 3), (4, 5), (0, 2)(1, 3), (0, 4)(1, 5)]` where the first three interchange covariant and contravariant positions of the same index (d1 <-> -d1) and the last two interchange the dummy indices themselves (d1 <-> d2). The dummy symmetry acts from the left `d = [1, 0, 2, 3, 4, 5, 6, 7]` exchange `d1 <-> -d1` `T^{d3 d2 d1}{}_{d1 d2 d3} == T^{d3 d2}{}_{d1}{}^{d1}{}_{d2 d3}` `g=[4, 2, 0, 1, 3, 5, 6, 7] -> [4, 2, 1, 0, 3, 5, 6, 7] = _af_rmul(d, g)` which differs from `_af_rmul(g, d)`. The slot symmetry acts from the right `s = [2, 1, 0, 3, 4, 5, 7, 6]` exchanges slots 0 and 2 and changes sign `T^{d3 d2 d1}{}_{d1 d2 d3} == -T^{d1 d2 d3}{}_{d1 d2 d3}` `g=[4,2,0,1,3,5,6,7] -> [0, 2, 4, 1, 3, 5, 7, 6] = _af_rmul(g, s)` Example in which the tensor is zero, same slot symmetries as above: `T^{d2}{}_{d1 d3}{}^{d1 d3}{}_{d2}` `= -T^{d3}{}_{d1 d3}{}^{d1 d2}{}_{d2}` under slot symmetry `-(0,4)`; `= T_{d3 d1}{}^{d3}{}^{d1 d2}{}_{d2}` under slot symmetry `-(0,2)`; `= T^{d3}{}_{d1 d3}{}^{d1 d2}{}_{d2}` symmetric metric; `= 0` since two of these lines have tensors differ only for the sign. The double coset D*g*S consists of permutations `h = d*g*s` corresponding to equivalent tensors; if there are two `h` which are the same apart from the sign, return zero; otherwise choose as representative the tensor with indices ordered lexicographically according to `[d1, -d1, d2, -d2, d3, -d3]` that is `rep = min(D*g*S) = min([d*g*s for d in D for s in S])` The indices are fixed one by one; first choose the lowest index for slot 0, then the lowest remaining index for slot 1, etc. Doing this one obtains a chain of stabilizers `S -> S_{b0} -> S_{b0,b1} -> ...` and `D -> D_{p0} -> D_{p0,p1} -> ...` where `[b0, b1, ...] = range(b)` is a base of the symmetric group; the strong base `b_S` of S is an ordered sublist of it; therefore it is sufficient to compute once the strong base generators of S using the Schreier-Sims algorithm; the stabilizers of the strong base generators are the strong base generators of the stabilizer subgroup. `dbase = [p0, p1, ...]` is not in general in lexicographic order, so that one must recompute the strong base generators each time; however this is trivial, there is no need to use the Schreier-Sims algorithm for D. The algorithm keeps a TAB of elements `(s_i, d_i, h_i)` where `h_i = d_i*g*s_i` satisfying `h_i[j] = p_j` for `0 <= j < i` starting from `s_0 = id, d_0 = id, h_0 = g`. The equations `h_0[0] = p_0, h_1[1] = p_1,...` are solved in this order, choosing each time the lowest possible value of p_i For `j < i` `d_i*g*s_i*S_{b_0,...,b_{i-1}}*b_j = D_{p_0,...,p_{i-1}}*p_j` so that for dx in `D_{p_0,...,p_{i-1}}` and sx in `S_{base[0],...,base[i-1]}` one has `dx*d_i*g*s_i*sx*b_j = p_j` Search for dx, sx such that this equation holds for `j = i`; it can be written as `s_i*sx*b_j = J, dx*d_i*g*J = p_j` `sx*b_j = s_i**-1*J; sx = trace(s_i**-1, S_{b_0,...,b_{i-1}})` `dx**-1*p_j = d_i*g*J; dx = trace(d_i*g*J, D_{p_0,...,p_{i-1}})` `s_{i+1} = s_i*trace(s_i**-1*J, S_{b_0,...,b_{i-1}})` `d_{i+1} = trace(d_i*g*J, D_{p_0,...,p_{i-1}})**-1*d_i` `h_{i+1}*b_i = d_{i+1}*g*s_{i+1}*b_i = p_i` `h_n*b_j = p_j` for all j, so that `h_n` is the solution. Add the found `(s, d, h)` to TAB1. At the end of the iteration sort TAB1 with respect to the `h`; if there are two consecutive `h` in TAB1 which differ only for the sign, the tensor is zero, so return 0; if there are two consecutive `h` which are equal, keep only one. Then stabilize the slot generators under `i` and the dummy generators under `p_i`. Assign `TAB = TAB1` at the end of the iteration step. At the end `TAB` contains a unique `(s, d, h)`, since all the slots of the tensor `h` have been fixed to have the minimum value according to the symmetries. The algorithm returns `h`. It is important that the slot BSGS has lexicographic minimal base, otherwise there is an `i` which does not belong to the slot base for which `p_i` is fixed by the dummy symmetry only, while `i` is not invariant from the slot stabilizer, so `p_i` is not in general the minimal value. This algorithm differs slightly from the original algorithm [3]: the canonical form is minimal lexicographically, and the BSGS has minimal base under lexicographic order. Equal tensors `h` are eliminated from TAB. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.tensor_can import double_coset_can_rep, get_transversals >>> gens = [Permutation(x) for x in [[2, 1, 0, 3, 4, 5, 7, 6], [4, 1, 2, 3, 0, 5, 7, 6]]] >>> base = [0, 2] >>> g = Permutation([4, 2, 0, 1, 3, 5, 6, 7]) >>> transversals = get_transversals(base, gens) >>> double_coset_can_rep([list(range(6))], [0], base, gens, transversals, g) [0, 1, 2, 3, 4, 5, 7, 6] >>> g = Permutation([4, 1, 3, 0, 5, 2, 6, 7]) >>> double_coset_can_rep([list(range(6))], [0], base, gens, transversals, g) 0 """ size = g.size g = g.array_form num_dummies = size - 2 indices = list(range(num_dummies)) all_metrics_with_sym = all([_ is not None for _ in sym]) num_types = len(sym) dumx = dummies[:] dumx_flat = [] for dx in dumx: dumx_flat.extend(dx) b_S = b_S[:] sgensx = [h._array_form for h in sgens] if b_S: S_transversals = transversal2coset(size, b_S, S_transversals) # strong generating set for D dsgsx = [] for i in range(num_types): dsgsx.extend(dummy_sgs(dumx[i], sym[i], num_dummies)) idn = list(range(size)) # TAB = list of entries (s, d, h) where h = _af_rmuln(d,g,s) # for short, in the following d*g*s means _af_rmuln(d,g,s) TAB = [(idn, idn, g)] for i in range(size - 2): b = i testb = b in b_S and sgensx if testb: sgensx1 = [_af_new(_) for _ in sgensx] deltab = _orbit(size, sgensx1, b) else: deltab = {b} # p1 = min(IMAGES) = min(Union D_p*h*deltab for h in TAB) if all_metrics_with_sym: md = _min_dummies(dumx, sym, indices) else: md = [min(_orbit(size, [_af_new( ddx) for ddx in dsgsx], ii)) for ii in range(size - 2)] p_i = min([min([md[h[x]] for x in deltab]) for s, d, h in TAB]) dsgsx1 = [_af_new(_) for _ in dsgsx] Dxtrav = _orbit_transversal(size, dsgsx1, p_i, False, af=True) \ if dsgsx else None if Dxtrav: Dxtrav = [_af_invert(x) for x in Dxtrav] # compute the orbit of p_i for ii in range(num_types): if p_i in dumx[ii]: # the orbit is made by all the indices in dum[ii] if sym[ii] is not None: deltap = dumx[ii] else: # the orbit is made by all the even indices if p_i # is even, by all the odd indices if p_i is odd p_i_index = dumx[ii].index(p_i) % 2 deltap = dumx[ii][p_i_index::2] break else: deltap = [p_i] TAB1 = [] while TAB: s, d, h = TAB.pop() if min([md[h[x]] for x in deltab]) != p_i: continue deltab1 = [x for x in deltab if md[h[x]] == p_i] # NEXT = s*deltab1 intersection (d*g)**-1*deltap dg = _af_rmul(d, g) dginv = _af_invert(dg) sdeltab = [s[x] for x in deltab1] gdeltap = [dginv[x] for x in deltap] NEXT = [x for x in sdeltab if x in gdeltap] # d, s satisfy # d*g*s*base[i-1] = p_{i-1}; using the stabilizers # d*g*s*S_{base[0],...,base[i-1]}*base[i-1] = # D_{p_0,...,p_{i-1}}*p_{i-1} # so that to find d1, s1 satisfying d1*g*s1*b = p_i # one can look for dx in D_{p_0,...,p_{i-1}} and # sx in S_{base[0],...,base[i-1]} # d1 = dx*d; s1 = s*sx # d1*g*s1*b = dx*d*g*s*sx*b = p_i for j in NEXT: if testb: # solve s1*b = j with s1 = s*sx for some element sx # of the stabilizer of ..., base[i-1] # sx*b = s**-1*j; sx = _trace_S(s, j,...) # s1 = s*trace_S(s**-1*j,...) s1 = _trace_S(s, j, b, S_transversals) if not s1: continue else: s1 = [s[ix] for ix in s1] else: s1 = s # assert s1[b] == j # invariant # solve d1*g*j = p_i with d1 = dx*d for some element dg # of the stabilizer of ..., p_{i-1} # dx**-1*p_i = d*g*j; dx**-1 = trace_D(d*g*j,...) # d1 = trace_D(d*g*j,...)**-1*d # to save an inversion in the inner loop; notice we did # Dxtrav = [perm_af_invert(x) for x in Dxtrav] out of the loop if Dxtrav: d1 = _trace_D(dg[j], p_i, Dxtrav) if not d1: continue else: if p_i != dg[j]: continue d1 = idn assert d1[dg[j]] == p_i # invariant d1 = [d1[ix] for ix in d] h1 = [d1[g[ix]] for ix in s1] # assert h1[b] == p_i # invariant TAB1.append((s1, d1, h1)) # if TAB contains equal permutations, keep only one of them; # if TAB contains equal permutations up to the sign, return 0 TAB1.sort(key=lambda x: x[-1]) prev = [0] * size while TAB1: s, d, h = TAB1.pop() if h[:-2] == prev[:-2]: if h[-1] != prev[-1]: return 0 else: TAB.append((s, d, h)) prev = h # stabilize the SGS sgensx = [h for h in sgensx if h[b] == b] if b in b_S: b_S.remove(b) _dumx_remove(dumx, dumx_flat, p_i) dsgsx = [] for i in range(num_types): dsgsx.extend(dummy_sgs(dumx[i], sym[i], num_dummies)) return TAB[0][-1] def canonical_free(base, gens, g, num_free): """ Canonicalization of a tensor with respect to free indices choosing the minimum with respect to lexicographical ordering in the free indices. Explanation =========== ``base``, ``gens`` BSGS for slot permutation group ``g`` permutation representing the tensor ``num_free`` number of free indices The indices must be ordered with first the free indices See explanation in double_coset_can_rep The algorithm is a variation of the one given in [2]. Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.tensor_can import canonical_free >>> gens = [[1, 0, 2, 3, 5, 4], [2, 3, 0, 1, 4, 5],[0, 1, 3, 2, 5, 4]] >>> gens = [Permutation(h) for h in gens] >>> base = [0, 2] >>> g = Permutation([2, 1, 0, 3, 4, 5]) >>> canonical_free(base, gens, g, 4) [0, 3, 1, 2, 5, 4] Consider the product of Riemann tensors ``T = R^{a}_{d0}^{d1,d2}*R_{d2,d1}^{d0,b}`` The order of the indices is ``[a, b, d0, -d0, d1, -d1, d2, -d2]`` The permutation corresponding to the tensor is ``g = [0, 3, 4, 6, 7, 5, 2, 1, 8, 9]`` In particular ``a`` is position ``0``, ``b`` is in position ``9``. Use the slot symmetries to get `T` is a form which is the minimal in lexicographic order in the free indices ``a`` and ``b``, e.g. ``-R^{a}_{d0}^{d1,d2}*R^{b,d0}_{d2,d1}`` corresponding to ``[0, 3, 4, 6, 1, 2, 7, 5, 9, 8]`` >>> from sympy.combinatorics.tensor_can import riemann_bsgs, tensor_gens >>> base, gens = riemann_bsgs >>> size, sbase, sgens = tensor_gens(base, gens, [[], []], 0) >>> g = Permutation([0, 3, 4, 6, 7, 5, 2, 1, 8, 9]) >>> canonical_free(sbase, [Permutation(h) for h in sgens], g, 2) [0, 3, 4, 6, 1, 2, 7, 5, 9, 8] """ g = g.array_form size = len(g) if not base: return g[:] transversals = get_transversals(base, gens) for x in sorted(g[:-2]): if x not in base: base.append(x) h = g for i, transv in enumerate(transversals): h_i = [size]*num_free # find the element s in transversals[i] such that # _af_rmul(h, s) has its free elements with the lowest position in h s = None for sk in transv.values(): h1 = _af_rmul(h, sk) hi = [h1.index(ix) for ix in range(num_free)] if hi < h_i: h_i = hi s = sk if s: h = _af_rmul(h, s) return h def _get_map_slots(size, fixed_slots): res = list(range(size)) pos = 0 for i in range(size): if i in fixed_slots: continue res[i] = pos pos += 1 return res def _lift_sgens(size, fixed_slots, free, s): a = [] j = k = 0 fd = list(zip(fixed_slots, free)) fd = [y for x, y in sorted(fd)] num_free = len(free) for i in range(size): if i in fixed_slots: a.append(fd[k]) k += 1 else: a.append(s[j] + num_free) j += 1 return a def canonicalize(g, dummies, msym, *v): """ canonicalize tensor formed by tensors Parameters ========== g : permutation representing the tensor dummies : list representing the dummy indices it can be a list of dummy indices of the same type or a list of lists of dummy indices, one list for each type of index; the dummy indices must come after the free indices, and put in order contravariant, covariant [d0, -d0, d1,-d1,...] msym : symmetry of the metric(s) it can be an integer or a list; in the first case it is the symmetry of the dummy index metric; in the second case it is the list of the symmetries of the index metric for each type v : list, (base_i, gens_i, n_i, sym_i) for tensors of type `i` base_i, gens_i : BSGS for tensors of this type. The BSGS should have minimal base under lexicographic ordering; if not, an attempt is made do get the minimal BSGS; in case of failure, canonicalize_naive is used, which is much slower. n_i : number of tensors of type `i`. sym_i : symmetry under exchange of component tensors of type `i`. Both for msym and sym_i the cases are * None no symmetry * 0 commuting * 1 anticommuting Returns ======= 0 if the tensor is zero, else return the array form of the permutation representing the canonical form of the tensor. Algorithm ========= First one uses canonical_free to get the minimum tensor under lexicographic order, using only the slot symmetries. If the component tensors have not minimal BSGS, it is attempted to find it; if the attempt fails canonicalize_naive is used instead. Compute the residual slot symmetry keeping fixed the free indices using tensor_gens(base, gens, list_free_indices, sym). Reduce the problem eliminating the free indices. Then use double_coset_can_rep and lift back the result reintroducing the free indices. Examples ======== one type of index with commuting metric; `A_{a b}` and `B_{a b}` antisymmetric and commuting `T = A_{d0 d1} * B^{d0}{}_{d2} * B^{d2 d1}` `ord = [d0,-d0,d1,-d1,d2,-d2]` order of the indices g = [1, 3, 0, 5, 4, 2, 6, 7] `T_c = 0` >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize, bsgs_direct_product >>> from sympy.combinatorics import Permutation >>> base2a, gens2a = get_symmetric_group_sgs(2, 1) >>> t0 = (base2a, gens2a, 1, 0) >>> t1 = (base2a, gens2a, 2, 0) >>> g = Permutation([1, 3, 0, 5, 4, 2, 6, 7]) >>> canonicalize(g, range(6), 0, t0, t1) 0 same as above, but with `B_{a b}` anticommuting `T_c = -A^{d0 d1} * B_{d0}{}^{d2} * B_{d1 d2}` can = [0,2,1,4,3,5,7,6] >>> t1 = (base2a, gens2a, 2, 1) >>> canonicalize(g, range(6), 0, t0, t1) [0, 2, 1, 4, 3, 5, 7, 6] two types of indices `[a,b,c,d,e,f]` and `[m,n]`, in this order, both with commuting metric `f^{a b c}` antisymmetric, commuting `A_{m a}` no symmetry, commuting `T = f^c{}_{d a} * f^f{}_{e b} * A_m{}^d * A^{m b} * A_n{}^a * A^{n e}` ord = [c,f,a,-a,b,-b,d,-d,e,-e,m,-m,n,-n] g = [0,7,3, 1,9,5, 11,6, 10,4, 13,2, 12,8, 14,15] The canonical tensor is `T_c = -f^{c a b} * f^{f d e} * A^m{}_a * A_{m d} * A^n{}_b * A_{n e}` can = [0,2,4, 1,6,8, 10,3, 11,7, 12,5, 13,9, 15,14] >>> base_f, gens_f = get_symmetric_group_sgs(3, 1) >>> base1, gens1 = get_symmetric_group_sgs(1) >>> base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) >>> t0 = (base_f, gens_f, 2, 0) >>> t1 = (base_A, gens_A, 4, 0) >>> dummies = [range(2, 10), range(10, 14)] >>> g = Permutation([0, 7, 3, 1, 9, 5, 11, 6, 10, 4, 13, 2, 12, 8, 14, 15]) >>> canonicalize(g, dummies, [0, 0], t0, t1) [0, 2, 4, 1, 6, 8, 10, 3, 11, 7, 12, 5, 13, 9, 15, 14] """ from sympy.combinatorics.testutil import canonicalize_naive if not isinstance(msym, list): if not msym in [0, 1, None]: raise ValueError('msym must be 0, 1 or None') num_types = 1 else: num_types = len(msym) if not all(msymx in [0, 1, None] for msymx in msym): raise ValueError('msym entries must be 0, 1 or None') if len(dummies) != num_types: raise ValueError( 'dummies and msym must have the same number of elements') size = g.size num_tensors = 0 v1 = [] for i in range(len(v)): base_i, gens_i, n_i, sym_i = v[i] # check that the BSGS is minimal; # this property is used in double_coset_can_rep; # if it is not minimal use canonicalize_naive if not _is_minimal_bsgs(base_i, gens_i): mbsgs = get_minimal_bsgs(base_i, gens_i) if not mbsgs: can = canonicalize_naive(g, dummies, msym, *v) return can base_i, gens_i = mbsgs v1.append((base_i, gens_i, [[]] * n_i, sym_i)) num_tensors += n_i if num_types == 1 and not isinstance(msym, list): dummies = [dummies] msym = [msym] flat_dummies = [] for dumx in dummies: flat_dummies.extend(dumx) if flat_dummies and flat_dummies != list(range(flat_dummies[0], flat_dummies[-1] + 1)): raise ValueError('dummies is not valid') # slot symmetry of the tensor size1, sbase, sgens = gens_products(*v1) if size != size1: raise ValueError( 'g has size %d, generators have size %d' % (size, size1)) free = [i for i in range(size - 2) if i not in flat_dummies] num_free = len(free) # g1 minimal tensor under slot symmetry g1 = canonical_free(sbase, sgens, g, num_free) if not flat_dummies: return g1 # save the sign of g1 sign = 0 if g1[-1] == size - 1 else 1 # the free indices are kept fixed. # Determine free_i, the list of slots of tensors which are fixed # since they are occupied by free indices, which are fixed. start = 0 for i in range(len(v)): free_i = [] base_i, gens_i, n_i, sym_i = v[i] len_tens = gens_i[0].size - 2 # for each component tensor get a list od fixed islots for j in range(n_i): # get the elements corresponding to the component tensor h = g1[start:(start + len_tens)] fr = [] # get the positions of the fixed elements in h for k in free: if k in h: fr.append(h.index(k)) free_i.append(fr) start += len_tens v1[i] = (base_i, gens_i, free_i, sym_i) # BSGS of the tensor with fixed free indices # if tensor_gens fails in gens_product, use canonicalize_naive size, sbase, sgens = gens_products(*v1) # reduce the permutations getting rid of the free indices pos_free = [g1.index(x) for x in range(num_free)] size_red = size - num_free g1_red = [x - num_free for x in g1 if x in flat_dummies] if sign: g1_red.extend([size_red - 1, size_red - 2]) else: g1_red.extend([size_red - 2, size_red - 1]) map_slots = _get_map_slots(size, pos_free) sbase_red = [map_slots[i] for i in sbase if i not in pos_free] sgens_red = [_af_new([map_slots[i] for i in y._array_form if i not in pos_free]) for y in sgens] dummies_red = [[x - num_free for x in y] for y in dummies] transv_red = get_transversals(sbase_red, sgens_red) g1_red = _af_new(g1_red) g2 = double_coset_can_rep( dummies_red, msym, sbase_red, sgens_red, transv_red, g1_red) if g2 == 0: return 0 # lift to the case with the free indices g3 = _lift_sgens(size, pos_free, free, g2) return g3 def perm_af_direct_product(gens1, gens2, signed=True): """ Direct products of the generators gens1 and gens2. Examples ======== >>> from sympy.combinatorics.tensor_can import perm_af_direct_product >>> gens1 = [[1, 0, 2, 3], [0, 1, 3, 2]] >>> gens2 = [[1, 0]] >>> perm_af_direct_product(gens1, gens2, False) [[1, 0, 2, 3, 4, 5], [0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 5, 4]] >>> gens1 = [[1, 0, 2, 3, 5, 4], [0, 1, 3, 2, 4, 5]] >>> gens2 = [[1, 0, 2, 3]] >>> perm_af_direct_product(gens1, gens2, True) [[1, 0, 2, 3, 4, 5, 7, 6], [0, 1, 3, 2, 4, 5, 6, 7], [0, 1, 2, 3, 5, 4, 6, 7]] """ gens1 = [list(x) for x in gens1] gens2 = [list(x) for x in gens2] s = 2 if signed else 0 n1 = len(gens1[0]) - s n2 = len(gens2[0]) - s start = list(range(n1)) end = list(range(n1, n1 + n2)) if signed: gens1 = [gen[:-2] + end + [gen[-2] + n2, gen[-1] + n2] for gen in gens1] gens2 = [start + [x + n1 for x in gen] for gen in gens2] else: gens1 = [gen + end for gen in gens1] gens2 = [start + [x + n1 for x in gen] for gen in gens2] res = gens1 + gens2 return res def bsgs_direct_product(base1, gens1, base2, gens2, signed=True): """ Direct product of two BSGS. Parameters ========== base1 : base of the first BSGS. gens1 : strong generating sequence of the first BSGS. base2, gens2 : similarly for the second BSGS. signed : flag for signed permutations. Examples ======== >>> from sympy.combinatorics.tensor_can import (get_symmetric_group_sgs, bsgs_direct_product) >>> base1, gens1 = get_symmetric_group_sgs(1) >>> base2, gens2 = get_symmetric_group_sgs(2) >>> bsgs_direct_product(base1, gens1, base2, gens2) ([1], [(4)(1 2)]) """ s = 2 if signed else 0 n1 = gens1[0].size - s base = list(base1) base += [x + n1 for x in base2] gens1 = [h._array_form for h in gens1] gens2 = [h._array_form for h in gens2] gens = perm_af_direct_product(gens1, gens2, signed) size = len(gens[0]) id_af = list(range(size)) gens = [h for h in gens if h != id_af] if not gens: gens = [id_af] return base, [_af_new(h) for h in gens] def get_symmetric_group_sgs(n, antisym=False): """ Return base, gens of the minimal BSGS for (anti)symmetric tensor Parameters ========== ``n``: rank of the tensor ``antisym`` : bool ``antisym = False`` symmetric tensor ``antisym = True`` antisymmetric tensor Examples ======== >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs >>> get_symmetric_group_sgs(3) ([0, 1], [(4)(0 1), (4)(1 2)]) """ if n == 1: return [], [_af_new(list(range(3)))] gens = [Permutation(n - 1)(i, i + 1)._array_form for i in range(n - 1)] if antisym == 0: gens = [x + [n, n + 1] for x in gens] else: gens = [x + [n + 1, n] for x in gens] base = list(range(n - 1)) return base, [_af_new(h) for h in gens] riemann_bsgs = [0, 2], [Permutation(0, 1)(4, 5), Permutation(2, 3)(4, 5), Permutation(5)(0, 2)(1, 3)] def get_transversals(base, gens): """ Return transversals for the group with BSGS base, gens """ if not base: return [] stabs = _distribute_gens_by_base(base, gens) orbits, transversals = _orbits_transversals_from_bsgs(base, stabs) transversals = [{x: h._array_form for x, h in y.items()} for y in transversals] return transversals def _is_minimal_bsgs(base, gens): """ Check if the BSGS has minimal base under lexigographic order. base, gens BSGS Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.tensor_can import riemann_bsgs, _is_minimal_bsgs >>> _is_minimal_bsgs(*riemann_bsgs) True >>> riemann_bsgs1 = ([2, 0], ([Permutation(5)(0, 1)(4, 5), Permutation(5)(0, 2)(1, 3)])) >>> _is_minimal_bsgs(*riemann_bsgs1) False """ base1 = [] sgs1 = gens[:] size = gens[0].size for i in range(size): if not all(h._array_form[i] == i for h in sgs1): base1.append(i) sgs1 = [h for h in sgs1 if h._array_form[i] == i] return base1 == base def get_minimal_bsgs(base, gens): """ Compute a minimal GSGS base, gens BSGS If base, gens is a minimal BSGS return it; else return a minimal BSGS if it fails in finding one, it returns None TODO: use baseswap in the case in which if it fails in finding a minimal BSGS Examples ======== >>> from sympy.combinatorics import Permutation >>> from sympy.combinatorics.tensor_can import get_minimal_bsgs >>> riemann_bsgs1 = ([2, 0], ([Permutation(5)(0, 1)(4, 5), Permutation(5)(0, 2)(1, 3)])) >>> get_minimal_bsgs(*riemann_bsgs1) ([0, 2], [(0 1)(4 5), (5)(0 2)(1 3), (2 3)(4 5)]) """ G = PermutationGroup(gens) base, gens = G.schreier_sims_incremental() if not _is_minimal_bsgs(base, gens): return None return base, gens def tensor_gens(base, gens, list_free_indices, sym=0): """ Returns size, res_base, res_gens BSGS for n tensors of the same type. Explanation =========== base, gens BSGS for tensors of this type list_free_indices list of the slots occupied by fixed indices for each of the tensors sym symmetry under commutation of two tensors sym None no symmetry sym 0 commuting sym 1 anticommuting Examples ======== >>> from sympy.combinatorics.tensor_can import tensor_gens, get_symmetric_group_sgs two symmetric tensors with 3 indices without free indices >>> base, gens = get_symmetric_group_sgs(3) >>> tensor_gens(base, gens, [[], []]) (8, [0, 1, 3, 4], [(7)(0 1), (7)(1 2), (7)(3 4), (7)(4 5), (7)(0 3)(1 4)(2 5)]) two symmetric tensors with 3 indices with free indices in slot 1 and 0 >>> tensor_gens(base, gens, [[1], [0]]) (8, [0, 4], [(7)(0 2), (7)(4 5)]) four symmetric tensors with 3 indices, two of which with free indices """ def _get_bsgs(G, base, gens, free_indices): """ return the BSGS for G.pointwise_stabilizer(free_indices) """ if not free_indices: return base[:], gens[:] else: H = G.pointwise_stabilizer(free_indices) base, sgs = H.schreier_sims_incremental() return base, sgs # if not base there is no slot symmetry for the component tensors # if list_free_indices.count([]) < 2 there is no commutation symmetry # so there is no resulting slot symmetry if not base and list_free_indices.count([]) < 2: n = len(list_free_indices) size = gens[0].size size = n * (size - 2) + 2 return size, [], [_af_new(list(range(size)))] # if any(list_free_indices) one needs to compute the pointwise # stabilizer, so G is needed if any(list_free_indices): G = PermutationGroup(gens) else: G = None # no_free list of lists of indices for component tensors without fixed # indices no_free = [] size = gens[0].size id_af = list(range(size)) num_indices = size - 2 if not list_free_indices[0]: no_free.append(list(range(num_indices))) res_base, res_gens = _get_bsgs(G, base, gens, list_free_indices[0]) for i in range(1, len(list_free_indices)): base1, gens1 = _get_bsgs(G, base, gens, list_free_indices[i]) res_base, res_gens = bsgs_direct_product(res_base, res_gens, base1, gens1, 1) if not list_free_indices[i]: no_free.append(list(range(size - 2, size - 2 + num_indices))) size += num_indices nr = size - 2 res_gens = [h for h in res_gens if h._array_form != id_af] # if sym there are no commuting tensors stop here if sym is None or not no_free: if not res_gens: res_gens = [_af_new(id_af)] return size, res_base, res_gens # if the component tensors have moinimal BSGS, so is their direct # product P; the slot symmetry group is S = P*C, where C is the group # to (anti)commute the component tensors with no free indices # a stabilizer has the property S_i = P_i*C_i; # the BSGS of P*C has SGS_P + SGS_C and the base is # the ordered union of the bases of P and C. # If P has minimal BSGS, so has S with this base. base_comm = [] for i in range(len(no_free) - 1): ind1 = no_free[i] ind2 = no_free[i + 1] a = list(range(ind1[0])) a.extend(ind2) a.extend(ind1) base_comm.append(ind1[0]) a.extend(list(range(ind2[-1] + 1, nr))) if sym == 0: a.extend([nr, nr + 1]) else: a.extend([nr + 1, nr]) res_gens.append(_af_new(a)) res_base = list(res_base) # each base is ordered; order the union of the two bases for i in base_comm: if i not in res_base: res_base.append(i) res_base.sort() if not res_gens: res_gens = [_af_new(id_af)] return size, res_base, res_gens def gens_products(*v): """ Returns size, res_base, res_gens BSGS for n tensors of different types. Explanation =========== v is a sequence of (base_i, gens_i, free_i, sym_i) where base_i, gens_i BSGS of tensor of type `i` free_i list of the fixed slots for each of the tensors of type `i`; if there are `n_i` tensors of type `i` and none of them have fixed slots, `free = [[]]*n_i` sym 0 (1) if the tensors of type `i` (anti)commute among themselves Examples ======== >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, gens_products >>> base, gens = get_symmetric_group_sgs(2) >>> gens_products((base, gens, [[], []], 0)) (6, [0, 2], [(5)(0 1), (5)(2 3), (5)(0 2)(1 3)]) >>> gens_products((base, gens, [[1], []], 0)) (6, [2], [(5)(2 3)]) """ res_size, res_base, res_gens = tensor_gens(*v[0]) for i in range(1, len(v)): size, base, gens = tensor_gens(*v[i]) res_base, res_gens = bsgs_direct_product(res_base, res_gens, base, gens, 1) res_size = res_gens[0].size id_af = list(range(res_size)) res_gens = [h for h in res_gens if h != id_af] if not res_gens: res_gens = [id_af] return res_size, res_base, res_gens sympy-sympy-1.9/sympy/combinatorics/tests/000077500000000000000000000000001412543434000211025ustar00rootroot00000000000000sympy-sympy-1.9/sympy/combinatorics/tests/__init__.py000066400000000000000000000000001412543434000232010ustar00rootroot00000000000000sympy-sympy-1.9/sympy/combinatorics/tests/test_coset_table.py000066400000000000000000000674541412543434000250170ustar00rootroot00000000000000from sympy.combinatorics.fp_groups import FpGroup from sympy.combinatorics.coset_table import (CosetTable, coset_enumeration_r, coset_enumeration_c) from sympy.combinatorics.coset_table import modified_coset_enumeration_r from sympy.combinatorics.free_groups import free_group from sympy.testing.pytest import slow """ References ========== [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" [2] John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490. "Implementation and Analysis of the Todd-Coxeter Algorithm" """ def test_scan_1(): # Example 5.1 from [1] F, x, y = free_group("x, y") f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) c = CosetTable(f, [x]) c.scan_and_fill(0, x) assert c.table == [[0, 0, None, None]] assert c.p == [0] assert c.n == 1 assert c.omega == [0] c.scan_and_fill(0, x**3) assert c.table == [[0, 0, None, None]] assert c.p == [0] assert c.n == 1 assert c.omega == [0] c.scan_and_fill(0, y**3) assert c.table == [[0, 0, 1, 2], [None, None, 2, 0], [None, None, 0, 1]] assert c.p == [0, 1, 2] assert c.n == 3 assert c.omega == [0, 1, 2] c.scan_and_fill(0, x**-1*y**-1*x*y) assert c.table == [[0, 0, 1, 2], [None, None, 2, 0], [2, 2, 0, 1]] assert c.p == [0, 1, 2] assert c.n == 3 assert c.omega == [0, 1, 2] c.scan_and_fill(1, x**3) assert c.table == [[0, 0, 1, 2], [3, 4, 2, 0], [2, 2, 0, 1], \ [4, 1, None, None], [1, 3, None, None]] assert c.p == [0, 1, 2, 3, 4] assert c.n == 5 assert c.omega == [0, 1, 2, 3, 4] c.scan_and_fill(1, y**3) assert c.table == [[0, 0, 1, 2], [3, 4, 2, 0], [2, 2, 0, 1], \ [4, 1, None, None], [1, 3, None, None]] assert c.p == [0, 1, 2, 3, 4] assert c.n == 5 assert c.omega == [0, 1, 2, 3, 4] c.scan_and_fill(1, x**-1*y**-1*x*y) assert c.table == [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1], \ [None, 1, None, None], [1, 3, None, None]] assert c.p == [0, 1, 2, 1, 1] assert c.n == 3 assert c.omega == [0, 1, 2] # Example 5.2 from [1] f = FpGroup(F, [x**2, y**3, (x*y)**3]) c = CosetTable(f, [x*y]) c.scan_and_fill(0, x*y) assert c.table == [[1, None, None, 1], [None, 0, 0, None]] assert c.p == [0, 1] assert c.n == 2 assert c.omega == [0, 1] c.scan_and_fill(0, x**2) assert c.table == [[1, 1, None, 1], [0, 0, 0, None]] assert c.p == [0, 1] assert c.n == 2 assert c.omega == [0, 1] c.scan_and_fill(0, y**3) assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]] assert c.p == [0, 1, 2] assert c.n == 3 assert c.omega == [0, 1, 2] c.scan_and_fill(0, (x*y)**3) assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]] assert c.p == [0, 1, 2] assert c.n == 3 assert c.omega == [0, 1, 2] c.scan_and_fill(1, x**2) assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]] assert c.p == [0, 1, 2] assert c.n == 3 assert c.omega == [0, 1, 2] c.scan_and_fill(1, y**3) assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [None, None, 1, 0]] assert c.p == [0, 1, 2] assert c.n == 3 assert c.omega == [0, 1, 2] c.scan_and_fill(1, (x*y)**3) assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [3, 4, 1, 0], [None, 2, 4, None], [2, None, None, 3]] assert c.p == [0, 1, 2, 3, 4] assert c.n == 5 assert c.omega == [0, 1, 2, 3, 4] c.scan_and_fill(2, x**2) assert c.table == [[1, 1, 2, 1], [0, 0, 0, 2], [3, 3, 1, 0], [2, 2, 3, 3], [2, None, None, 3]] assert c.p == [0, 1, 2, 3, 3] assert c.n == 4 assert c.omega == [0, 1, 2, 3] @slow def test_coset_enumeration(): # this test function contains the combined tests for the two strategies # i.e. HLT and Felsch strategies. # Example 5.1 from [1] F, x, y = free_group("x, y") f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) C_r = coset_enumeration_r(f, [x]) C_r.compress(); C_r.standardize() C_c = coset_enumeration_c(f, [x]) C_c.compress(); C_c.standardize() table1 = [[0, 0, 1, 2], [1, 1, 2, 0], [2, 2, 0, 1]] assert C_r.table == table1 assert C_c.table == table1 # E1 from [2] Pg. 474 F, r, s, t = free_group("r, s, t") E1 = FpGroup(F, [t**-1*r*t*r**-2, r**-1*s*r*s**-2, s**-1*t*s*t**-2]) C_r = coset_enumeration_r(E1, []) C_r.compress() C_c = coset_enumeration_c(E1, []) C_c.compress() table2 = [[0, 0, 0, 0, 0, 0]] assert C_r.table == table2 # test for issue #11449 assert C_c.table == table2 # Cox group from [2] Pg. 474 F, a, b = free_group("a, b") Cox = FpGroup(F, [a**6, b**6, (a*b)**2, (a**2*b**2)**2, (a**3*b**3)**5]) C_r = coset_enumeration_r(Cox, [a]) C_r.compress(); C_r.standardize() C_c = coset_enumeration_c(Cox, [a]) C_c.compress(); C_c.standardize() table3 = [[0, 0, 1, 2], [2, 3, 4, 0], [5, 1, 0, 6], [1, 7, 8, 9], [9, 10, 11, 1], [12, 2, 9, 13], [14, 9, 2, 11], [3, 12, 15, 16], [16, 17, 18, 3], [6, 4, 3, 5], [4, 19, 20, 21], [21, 22, 6, 4], [7, 5, 23, 24], [25, 23, 5, 18], [19, 6, 22, 26], [24, 27, 28, 7], [29, 8, 7, 30], [8, 31, 32, 33], [33, 34, 13, 8], [10, 14, 35, 35], [35, 36, 37, 10], [30, 11, 10, 29], [11, 38, 39, 14], [13, 39, 38, 12], [40, 15, 12, 41], [42, 13, 34, 43], [44, 35, 14, 45], [15, 46, 47, 34], [34, 48, 49, 15], [50, 16, 21, 51], [52, 21, 16, 49], [17, 50, 53, 54], [54, 55, 56, 17], [41, 18, 17, 40], [18, 28, 27, 25], [26, 20, 19, 19], [20, 57, 58, 59], [59, 60, 51, 20], [22, 52, 61, 23], [23, 62, 63, 22], [64, 24, 33, 65], [48, 33, 24, 61], [62, 25, 54, 66], [67, 54, 25, 68], [57, 26, 59, 69], [70, 59, 26, 63], [27, 64, 71, 72], [72, 73, 68, 27], [28, 41, 74, 75], [75, 76, 30, 28], [31, 29, 77, 78], [79, 77, 29, 37], [38, 30, 76, 80], [78, 81, 82, 31], [43, 32, 31, 42], [32, 83, 84, 85], [85, 86, 65, 32], [36, 44, 87, 88], [88, 89, 90, 36], [45, 37, 36, 44], [37, 82, 81, 79], [80, 74, 41, 38], [39, 42, 91, 92], [92, 93, 45, 39], [46, 40, 94, 95], [96, 94, 40, 56], [97, 91, 42, 82], [83, 43, 98, 99], [100, 98, 43, 47], [101, 87, 44, 90], [82, 45, 93, 97], [95, 102, 103, 46], [104, 47, 46, 105], [47, 106, 107, 100], [61, 108, 109, 48], [105, 49, 48, 104], [49, 110, 111, 52], [51, 111, 110, 50], [112, 53, 50, 113], [114, 51, 60, 115], [116, 61, 52, 117], [53, 118, 119, 60], [60, 70, 66, 53], [55, 67, 120, 121], [121, 122, 123, 55], [113, 56, 55, 112], [56, 103, 102, 96], [69, 124, 125, 57], [115, 58, 57, 114], [58, 126, 127, 128], [128, 128, 69, 58], [66, 129, 130, 62], [117, 63, 62, 116], [63, 125, 124, 70], [65, 109, 108, 64], [131, 71, 64, 132], [133, 65, 86, 134], [135, 66, 70, 136], [68, 130, 129, 67], [137, 120, 67, 138], [132, 68, 73, 131], [139, 69, 128, 140], [71, 141, 142, 86], [86, 143, 144, 71], [145, 72, 75, 146], [147, 75, 72, 144], [73, 145, 148, 120], [120, 149, 150, 73], [74, 151, 152, 94], [94, 153, 146, 74], [76, 147, 154, 77], [77, 155, 156, 76], [157, 78, 85, 158], [143, 85, 78, 154], [155, 79, 88, 159], [160, 88, 79, 161], [151, 80, 92, 162], [163, 92, 80, 156], [81, 157, 164, 165], [165, 166, 161, 81], [99, 107, 106, 83], [134, 84, 83, 133], [84, 167, 168, 169], [169, 170, 158, 84], [87, 171, 172, 93], [93, 163, 159, 87], [89, 160, 173, 174], [174, 175, 176, 89], [90, 90, 89, 101], [91, 177, 178, 98], [98, 179, 162, 91], [180, 95, 100, 181], [179, 100, 95, 152], [153, 96, 121, 148], [182, 121, 96, 183], [177, 97, 165, 184], [185, 165, 97, 172], [186, 99, 169, 187], [188, 169, 99, 178], [171, 101, 174, 189], [190, 174, 101, 176], [102, 180, 191, 192], [192, 193, 183, 102], [103, 113, 194, 195], [195, 196, 105, 103], [106, 104, 197, 198], [199, 197, 104, 109], [110, 105, 196, 200], [198, 201, 133, 106], [107, 186, 202, 203], [203, 204, 181, 107], [108, 116, 205, 206], [206, 207, 132, 108], [109, 133, 201, 199], [200, 194, 113, 110], [111, 114, 208, 209], [209, 210, 117, 111], [118, 112, 211, 212], [213, 211, 112, 123], [214, 208, 114, 125], [126, 115, 215, 216], [217, 215, 115, 119], [218, 205, 116, 130], [125, 117, 210, 214], [212, 219, 220, 118], [136, 119, 118, 135], [119, 221, 222, 217], [122, 182, 223, 224], [224, 225, 226, 122], [138, 123, 122, 137], [123, 220, 219, 213], [124, 139, 227, 228], [228, 229, 136, 124], [216, 222, 221, 126], [140, 127, 126, 139], [127, 230, 231, 232], [232, 233, 140, 127], [129, 135, 234, 235], [235, 236, 138, 129], [130, 132, 207, 218], [141, 131, 237, 238], [239, 237, 131, 150], [167, 134, 240, 241], [242, 240, 134, 142], [243, 234, 135, 220], [221, 136, 229, 244], [149, 137, 245, 246], [247, 245, 137, 226], [220, 138, 236, 243], [244, 227, 139, 221], [230, 140, 233, 248], [238, 249, 250, 141], [251, 142, 141, 252], [142, 253, 254, 242], [154, 255, 256, 143], [252, 144, 143, 251], [144, 257, 258, 147], [146, 258, 257, 145], [259, 148, 145, 260], [261, 146, 153, 262], [263, 154, 147, 264], [148, 265, 266, 153], [246, 267, 268, 149], [260, 150, 149, 259], [150, 250, 249, 239], [162, 269, 270, 151], [262, 152, 151, 261], [152, 271, 272, 179], [159, 273, 274, 155], [264, 156, 155, 263], [156, 270, 269, 163], [158, 256, 255, 157], [275, 164, 157, 276], [277, 158, 170, 278], [279, 159, 163, 280], [161, 274, 273, 160], [281, 173, 160, 282], [276, 161, 166, 275], [283, 162, 179, 284], [164, 285, 286, 170], [170, 188, 184, 164], [166, 185, 189, 173], [173, 287, 288, 166], [241, 254, 253, 167], [278, 168, 167, 277], [168, 289, 290, 291], [291, 292, 187, 168], [189, 293, 294, 171], [280, 172, 171, 279], [172, 295, 296, 185], [175, 190, 297, 297], [297, 298, 299, 175], [282, 176, 175, 281], [176, 294, 293, 190], [184, 296, 295, 177], [284, 178, 177, 283], [178, 300, 301, 188], [181, 272, 271, 180], [302, 191, 180, 303], [304, 181, 204, 305], [183, 266, 265, 182], [306, 223, 182, 307], [303, 183, 193, 302], [308, 184, 188, 309], [310, 189, 185, 311], [187, 301, 300, 186], [305, 202, 186, 304], [312, 187, 292, 313], [314, 297, 190, 315], [191, 316, 317, 204], [204, 318, 319, 191], [320, 192, 195, 321], [322, 195, 192, 319], [193, 320, 323, 223], [223, 324, 325, 193], [194, 326, 327, 211], [211, 328, 321, 194], [196, 322, 329, 197], [197, 330, 331, 196], [332, 198, 203, 333], [318, 203, 198, 329], [330, 199, 206, 334], [335, 206, 199, 336], [326, 200, 209, 337], [338, 209, 200, 331], [201, 332, 339, 240], [240, 340, 336, 201], [202, 341, 342, 292], [292, 343, 333, 202], [205, 344, 345, 210], [210, 338, 334, 205], [207, 335, 346, 237], [237, 347, 348, 207], [208, 349, 350, 215], [215, 351, 337, 208], [352, 212, 217, 353], [351, 217, 212, 327], [328, 213, 224, 323], [354, 224, 213, 355], [349, 214, 228, 356], [357, 228, 214, 345], [358, 216, 232, 359], [360, 232, 216, 350], [344, 218, 235, 361], [362, 235, 218, 348], [219, 352, 363, 364], [364, 365, 355, 219], [222, 358, 366, 367], [367, 368, 353, 222], [225, 354, 369, 370], [370, 371, 372, 225], [307, 226, 225, 306], [226, 268, 267, 247], [227, 373, 374, 233], [233, 360, 356, 227], [229, 357, 361, 234], [234, 375, 376, 229], [248, 231, 230, 230], [231, 377, 378, 379], [379, 380, 359, 231], [236, 362, 381, 245], [245, 382, 383, 236], [384, 238, 242, 385], [340, 242, 238, 346], [347, 239, 246, 381], [386, 246, 239, 387], [388, 241, 291, 389], [343, 291, 241, 339], [375, 243, 364, 390], [391, 364, 243, 383], [373, 244, 367, 392], [393, 367, 244, 376], [382, 247, 370, 394], [395, 370, 247, 396], [377, 248, 379, 397], [398, 379, 248, 374], [249, 384, 399, 400], [400, 401, 387, 249], [250, 260, 402, 403], [403, 404, 252, 250], [253, 251, 405, 406], [407, 405, 251, 256], [257, 252, 404, 408], [406, 409, 277, 253], [254, 388, 410, 411], [411, 412, 385, 254], [255, 263, 413, 414], [414, 415, 276, 255], [256, 277, 409, 407], [408, 402, 260, 257], [258, 261, 416, 417], [417, 418, 264, 258], [265, 259, 419, 420], [421, 419, 259, 268], [422, 416, 261, 270], [271, 262, 423, 424], [425, 423, 262, 266], [426, 413, 263, 274], [270, 264, 418, 422], [420, 427, 307, 265], [266, 303, 428, 425], [267, 386, 429, 430], [430, 431, 396, 267], [268, 307, 427, 421], [269, 283, 432, 433], [433, 434, 280, 269], [424, 428, 303, 271], [272, 304, 435, 436], [436, 437, 284, 272], [273, 279, 438, 439], [439, 440, 282, 273], [274, 276, 415, 426], [285, 275, 441, 442], [443, 441, 275, 288], [289, 278, 444, 445], [446, 444, 278, 286], [447, 438, 279, 294], [295, 280, 434, 448], [287, 281, 449, 450], [451, 449, 281, 299], [294, 282, 440, 447], [448, 432, 283, 295], [300, 284, 437, 452], [442, 453, 454, 285], [309, 286, 285, 308], [286, 455, 456, 446], [450, 457, 458, 287], [311, 288, 287, 310], [288, 454, 453, 443], [445, 456, 455, 289], [313, 290, 289, 312], [290, 459, 460, 461], [461, 462, 389, 290], [293, 310, 463, 464], [464, 465, 315, 293], [296, 308, 466, 467], [467, 468, 311, 296], [298, 314, 469, 470], [470, 471, 472, 298], [315, 299, 298, 314], [299, 458, 457, 451], [452, 435, 304, 300], [301, 312, 473, 474], [474, 475, 309, 301], [316, 302, 476, 477], [478, 476, 302, 325], [341, 305, 479, 480], [481, 479, 305, 317], [324, 306, 482, 483], [484, 482, 306, 372], [485, 466, 308, 454], [455, 309, 475, 486], [487, 463, 310, 458], [454, 311, 468, 485], [486, 473, 312, 455], [459, 313, 488, 489], [490, 488, 313, 342], [491, 469, 314, 472], [458, 315, 465, 487], [477, 492, 485, 316], [463, 317, 316, 468], [317, 487, 493, 481], [329, 447, 464, 318], [468, 319, 318, 463], [319, 467, 448, 322], [321, 448, 467, 320], [475, 323, 320, 466], [432, 321, 328, 437], [438, 329, 322, 434], [323, 474, 452, 328], [483, 494, 486, 324], [466, 325, 324, 475], [325, 485, 492, 478], [337, 422, 433, 326], [437, 327, 326, 432], [327, 436, 424, 351], [334, 426, 439, 330], [434, 331, 330, 438], [331, 433, 422, 338], [333, 464, 447, 332], [449, 339, 332, 440], [465, 333, 343, 469], [413, 334, 338, 418], [336, 439, 426, 335], [441, 346, 335, 415], [440, 336, 340, 449], [416, 337, 351, 423], [339, 451, 470, 343], [346, 443, 450, 340], [480, 493, 487, 341], [469, 342, 341, 465], [342, 491, 495, 490], [361, 407, 414, 344], [418, 345, 344, 413], [345, 417, 408, 357], [381, 446, 442, 347], [415, 348, 347, 441], [348, 414, 407, 362], [356, 408, 417, 349], [423, 350, 349, 416], [350, 425, 420, 360], [353, 424, 436, 352], [479, 363, 352, 435], [428, 353, 368, 476], [355, 452, 474, 354], [488, 369, 354, 473], [435, 355, 365, 479], [402, 356, 360, 419], [405, 361, 357, 404], [359, 420, 425, 358], [476, 366, 358, 428], [427, 359, 380, 482], [444, 381, 362, 409], [363, 481, 477, 368], [368, 393, 390, 363], [365, 391, 394, 369], [369, 490, 480, 365], [366, 478, 483, 380], [380, 398, 392, 366], [371, 395, 496, 497], [497, 498, 489, 371], [473, 372, 371, 488], [372, 486, 494, 484], [392, 400, 403, 373], [419, 374, 373, 402], [374, 421, 430, 398], [390, 411, 406, 375], [404, 376, 375, 405], [376, 403, 400, 393], [397, 430, 421, 377], [482, 378, 377, 427], [378, 484, 497, 499], [499, 499, 397, 378], [394, 461, 445, 382], [409, 383, 382, 444], [383, 406, 411, 391], [385, 450, 443, 384], [492, 399, 384, 453], [457, 385, 412, 493], [387, 442, 446, 386], [494, 429, 386, 456], [453, 387, 401, 492], [389, 470, 451, 388], [493, 410, 388, 457], [471, 389, 462, 495], [412, 390, 393, 399], [462, 394, 391, 410], [401, 392, 398, 429], [396, 445, 461, 395], [498, 496, 395, 460], [456, 396, 431, 494], [431, 397, 499, 496], [399, 477, 481, 412], [429, 483, 478, 401], [410, 480, 490, 462], [496, 497, 484, 431], [489, 495, 491, 459], [495, 460, 459, 471], [460, 489, 498, 498], [472, 472, 471, 491]] C_r.table == table3 C_c.table == table3 # Group denoted by B2,4 from [2] Pg. 474 F, a, b = free_group("a, b") B_2_4 = FpGroup(F, [a**4, b**4, (a*b)**4, (a**-1*b)**4, (a**2*b)**4, \ (a*b**2)**4, (a**2*b**2)**4, (a**-1*b*a*b)**4, (a*b**-1*a*b)**4]) C_r = coset_enumeration_r(B_2_4, [a]) C_c = coset_enumeration_c(B_2_4, [a]) index_r = 0 for i in range(len(C_r.p)): if C_r.p[i] == i: index_r += 1 assert index_r == 1024 index_c = 0 for i in range(len(C_c.p)): if C_c.p[i] == i: index_c += 1 assert index_c == 1024 # trivial Macdonald group G(2,2) from [2] Pg. 480 M = FpGroup(F, [b**-1*a**-1*b*a*b**-1*a*b*a**-2, a**-1*b**-1*a*b*a**-1*b*a*b**-2]) C_r = coset_enumeration_r(M, [a]) C_r.compress(); C_r.standardize() C_c = coset_enumeration_c(M, [a]) C_c.compress(); C_c.standardize() table4 = [[0, 0, 0, 0]] assert C_r.table == table4 assert C_c.table == table4 def test_look_ahead(): # Section 3.2 [Test Example] Example (d) from [2] F, a, b, c = free_group("a, b, c") f = FpGroup(F, [a**11, b**5, c**4, (a*c)**3, b**2*c**-1*b**-1*c, a**4*b**-1*a**-1*b]) H = [c, b, c**2] table0 = [[1, 2, 0, 0, 0, 0], [3, 0, 4, 5, 6, 7], [0, 8, 9, 10, 11, 12], [5, 1, 10, 13, 14, 15], [16, 5, 16, 1, 17, 18], [4, 3, 1, 8, 19, 20], [12, 21, 22, 23, 24, 1], [25, 26, 27, 28, 1, 24], [2, 10, 5, 16, 22, 28], [10, 13, 13, 2, 29, 30]] CosetTable.max_stack_size = 10 C_c = coset_enumeration_c(f, H) C_c.compress(); C_c.standardize() assert C_c.table[: 10] == table0 def test_modified_methods(): ''' Tests for modified coset table methods. Example 5.7 from [1] Holt, D., Eick, B., O'Brien "Handbook of Computational Group Theory". ''' F, x, y = free_group("x, y") f = FpGroup(F, [x**3, y**5, (x*y)**2]) H = [x*y, x**-1*y**-1*x*y*x] C = CosetTable(f, H) C.modified_define(0, x) identity = C._grp.identity a_0 = C._grp.generators[0] a_1 = C._grp.generators[1] assert C.P == [[identity, None, None, None], [None, identity, None, None]] assert C.table == [[1, None, None, None], [None, 0, None, None]] C.modified_define(1, x) assert C.table == [[1, None, None, None], [2, 0, None, None], [None, 1, None, None]] assert C.P == [[identity, None, None, None], [identity, identity, None, None], [None, identity, None, None]] C.modified_scan(0, x**3, C._grp.identity, fill=False) assert C.P == [[identity, identity, None, None], [identity, identity, None, None], [identity, identity, None, None]] assert C.table == [[1, 2, None, None], [2, 0, None, None], [0, 1, None, None]] C.modified_scan(0, x*y, C._grp.generators[0], fill=False) assert C.P == [[identity, identity, None, a_0**-1], [identity, identity, a_0, None], [identity, identity, None, None]] assert C.table == [[1, 2, None, 1], [2, 0, 0, None], [0, 1, None, None]] C.modified_define(2, y**-1) assert C.table == [[1, 2, None, 1], [2, 0, 0, None], [0, 1, None, 3], [None, None, 2, None]] assert C.P == [[identity, identity, None, a_0**-1], [identity, identity, a_0, None], [identity, identity, None, identity], [None, None, identity, None]] C.modified_scan(0, x**-1*y**-1*x*y*x, C._grp.generators[1]) assert C.table == [[1, 2, None, 1], [2, 0, 0, None], [0, 1, None, 3], [3, 3, 2, None]] assert C.P == [[identity, identity, None, a_0**-1], [identity, identity, a_0, None], [identity, identity, None, identity], [a_1, a_1**-1, identity, None]] C.modified_scan(2, (x*y)**2, C._grp.identity) assert C.table == [[1, 2, 3, 1], [2, 0, 0, None], [0, 1, None, 3], [3, 3, 2, 0]] assert C.P == [[identity, identity, a_1**-1, a_0**-1], [identity, identity, a_0, None], [identity, identity, None, identity], [a_1, a_1**-1, identity, a_1]] C.modified_define(2, y) assert C.table == [[1, 2, 3, 1], [2, 0, 0, None], [0, 1, 4, 3], [3, 3, 2, 0], [None, None, None, 2]] assert C.P == [[identity, identity, a_1**-1, a_0**-1], [identity, identity, a_0, None], [identity, identity, identity, identity], [a_1, a_1**-1, identity, a_1], [None, None, None, identity]] C.modified_scan(0, y**5, C._grp.identity) assert C.table == [[1, 2, 3, 1], [2, 0, 0, 4], [0, 1, 4, 3], [3, 3, 2, 0], [None, None, 1, 2]] assert C.P == [[identity, identity, a_1**-1, a_0**-1], [identity, identity, a_0, a_0*a_1**-1], [identity, identity, identity, identity], [a_1, a_1**-1, identity, a_1], [None, None, a_1*a_0**-1, identity]] C.modified_scan(1, (x*y)**2, C._grp.identity) assert C.table == [[1, 2, 3, 1], [2, 0, 0, 4], [0, 1, 4, 3], [3, 3, 2, 0], [4, 4, 1, 2]] assert C.P == [[identity, identity, a_1**-1, a_0**-1], [identity, identity, a_0, a_0*a_1**-1], [identity, identity, identity, identity], [a_1, a_1**-1, identity, a_1], [a_0*a_1**-1, a_1*a_0**-1, a_1*a_0**-1, identity]] # Modified coset enumeration test f = FpGroup(F, [x**3, y**3, x**-1*y**-1*x*y]) C = coset_enumeration_r(f, [x]) C_m = modified_coset_enumeration_r(f, [x]) assert C_m.table == C.table sympy-sympy-1.9/sympy/combinatorics/tests/test_fp_groups.py000066400000000000000000000234331412543434000245240ustar00rootroot00000000000000from sympy import S from sympy.combinatorics.fp_groups import (FpGroup, low_index_subgroups, reidemeister_presentation, FpSubgroup, simplify_presentation) from sympy.combinatorics.free_groups import (free_group, FreeGroup) from sympy.testing.pytest import slow """ References ========== [1] Holt, D., Eick, B., O'Brien, E. "Handbook of Computational Group Theory" [2] John J. Cannon; Lucien A. Dimino; George Havas; Jane M. Watson Mathematics of Computation, Vol. 27, No. 123. (Jul., 1973), pp. 463-490. "Implementation and Analysis of the Todd-Coxeter Algorithm" [3] PROC. SECOND INTERNAT. CONF. THEORY OF GROUPS, CANBERRA 1973, pp. 347-356. "A Reidemeister-Schreier program" by George Havas. http://staff.itee.uq.edu.au/havas/1973cdhw.pdf """ def test_low_index_subgroups(): F, x, y = free_group("x, y") # Example 5.10 from [1] Pg. 194 f = FpGroup(F, [x**2, y**3, (x*y)**4]) L = low_index_subgroups(f, 4) t1 = [[[0, 0, 0, 0]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 3, 3]], [[0, 0, 1, 2], [2, 2, 2, 0], [1, 1, 0, 1]], [[1, 1, 0, 0], [0, 0, 1, 1]]] for i in range(len(t1)): assert L[i].table == t1[i] f = FpGroup(F, [x**2, y**3, (x*y)**7]) L = low_index_subgroups(f, 15) t2 = [[[0, 0, 0, 0]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [4, 4, 5, 3], [6, 6, 3, 4], [5, 5, 6, 6]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [6, 6, 5, 3], [5, 5, 3, 4], [4, 4, 6, 6]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [6, 6, 5, 3], [7, 7, 3, 4], [4, 4, 8, 9], [5, 5, 10, 11], [11, 11, 9, 6], [9, 9, 6, 8], [12, 12, 11, 7], [8, 8, 7, 10], [10, 10, 13, 14], [14, 14, 14, 12], [13, 13, 12, 13]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [6, 6, 5, 3], [7, 7, 3, 4], [4, 4, 8, 9], [5, 5, 10, 11], [11, 11, 9, 6], [12, 12, 6, 8], [10, 10, 11, 7], [8, 8, 7, 10], [9, 9, 13, 14], [14, 14, 14, 12], [13, 13, 12, 13]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [6, 6, 5, 3], [7, 7, 3, 4], [4, 4, 8, 9], [5, 5, 10, 11], [11, 11, 9, 6], [12, 12, 6, 8], [13, 13, 11, 7], [8, 8, 7, 10], [9, 9, 12, 12], [10, 10, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 3, 3], [2, 2, 5, 6] , [7, 7, 6, 4], [8, 8, 4, 5], [5, 5, 8, 9], [6, 6, 9, 7], [10, 10, 7, 8], [9, 9, 11, 12], [11, 11, 12, 10], [13, 13, 10, 11], [12, 12, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 3, 3], [2, 2, 5, 6] , [7, 7, 6, 4], [8, 8, 4, 5], [5, 5, 8, 9], [6, 6, 9, 7], [10, 10, 7, 8], [9, 9, 11, 12], [13, 13, 12, 10], [12, 12, 10, 11], [11, 11, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 4, 4] , [7, 7, 6, 3], [8, 8, 3, 5], [5, 5, 8, 9], [6, 6, 9, 7], [10, 10, 7, 8], [9, 9, 11, 12], [13, 13, 12, 10], [12, 12, 10, 11], [11, 11, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8] , [5, 5, 6, 3], [9, 9, 3, 5], [10, 10, 8, 4], [8, 8, 4, 7], [6, 6, 10, 11], [7, 7, 11, 9], [12, 12, 9, 10], [11, 11, 13, 14], [14, 14, 14, 12], [13, 13, 12, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8] , [6, 6, 6, 3], [5, 5, 3, 5], [8, 8, 8, 4], [7, 7, 4, 7]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8] , [9, 9, 6, 3], [6, 6, 3, 5], [10, 10, 8, 4], [11, 11, 4, 7], [5, 5, 10, 12], [7, 7, 12, 9], [8, 8, 11, 11], [13, 13, 9, 10], [12, 12, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8] , [9, 9, 6, 3], [6, 6, 3, 5], [10, 10, 8, 4], [11, 11, 4, 7], [5, 5, 12, 11], [7, 7, 10, 10], [8, 8, 9, 12], [13, 13, 11, 9], [12, 12, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8] , [9, 9, 6, 3], [10, 10, 3, 5], [7, 7, 8, 4], [11, 11, 4, 7], [5, 5, 9, 9], [6, 6, 11, 12], [8, 8, 12, 10], [13, 13, 10, 11], [12, 12, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8] , [9, 9, 6, 3], [10, 10, 3, 5], [7, 7, 8, 4], [11, 11, 4, 7], [5, 5, 12, 11], [6, 6, 10, 10], [8, 8, 9, 12], [13, 13, 11, 9], [12, 12, 13, 13]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8] , [9, 9, 6, 3], [10, 10, 3, 5], [11, 11, 8, 4], [12, 12, 4, 7], [5, 5, 9, 9], [6, 6, 12, 13], [7, 7, 11, 11], [8, 8, 13, 10], [13, 13, 10, 12]], [[1, 1, 0, 0], [0, 0, 2, 3], [4, 4, 3, 1], [5, 5, 1, 2], [2, 2, 4, 4] , [3, 3, 6, 7], [7, 7, 7, 5], [6, 6, 5, 6]]] for i in range(len(t2)): assert L[i].table == t2[i] f = FpGroup(F, [x**2, y**3, (x*y)**7]) L = low_index_subgroups(f, 10, [x]) t3 = [[[0, 0, 0, 0]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [4, 4, 5, 3], [6, 6, 3, 4], [5, 5, 6, 6]], [[0, 0, 1, 2], [1, 1, 2, 0], [3, 3, 0, 1], [2, 2, 4, 5], [6, 6, 5, 3], [5, 5, 3, 4], [4, 4, 6, 6]], [[0, 0, 1, 2], [3, 3, 2, 0], [4, 4, 0, 1], [1, 1, 5, 6], [2, 2, 7, 8], [6, 6, 6, 3], [5, 5, 3, 5], [8, 8, 8, 4], [7, 7, 4, 7]]] for i in range(len(t3)): assert L[i].table == t3[i] def test_subgroup_presentations(): F, x, y = free_group("x, y") f = FpGroup(F, [x**3, y**5, (x*y)**2]) H = [x*y, x**-1*y**-1*x*y*x] p1 = reidemeister_presentation(f, H) assert str(p1) == "((y_1, y_2), (y_1**2, y_2**3, y_2*y_1*y_2*y_1*y_2*y_1))" H = f.subgroup(H) assert (H.generators, H.relators) == p1 f = FpGroup(F, [x**3, y**3, (x*y)**3]) H = [x*y, x*y**-1] p2 = reidemeister_presentation(f, H) assert str(p2) == "((x_0, y_0), (x_0**3, y_0**3, x_0*y_0*x_0*y_0*x_0*y_0))" f = FpGroup(F, [x**2*y**2, y**-1*x*y*x**-3]) H = [x] p3 = reidemeister_presentation(f, H) assert str(p3) == "((x_0,), (x_0**4,))" f = FpGroup(F, [x**3*y**-3, (x*y)**3, (x*y**-1)**2]) H = [x] p4 = reidemeister_presentation(f, H) assert str(p4) == "((x_0,), (x_0**6,))" # this presentation can be improved, the most simplified form # of presentation is # See [2] Pg 474 group PSL_2(11) # This is the group PSL_2(11) F, a, b, c = free_group("a, b, c") f = FpGroup(F, [a**11, b**5, c**4, (b*c**2)**2, (a*b*c)**3, (a**4*c**2)**3, b**2*c**-1*b**-1*c, a**4*b**-1*a**-1*b]) H = [a, b, c**2] gens, rels = reidemeister_presentation(f, H) assert str(gens) == "(b_1, c_3)" assert len(rels) == 18 @slow def test_order(): F, x, y = free_group("x, y") f = FpGroup(F, [x**4, y**2, x*y*x**-1*y]) assert f.order() == 8 f = FpGroup(F, [x*y*x**-1*y**-1, y**2]) assert f.order() is S.Infinity F, a, b, c = free_group("a, b, c") f = FpGroup(F, [a**250, b**2, c*b*c**-1*b, c**4, c**-1*a**-1*c*a, a**-1*b**-1*a*b]) assert f.order() == 2000 F, x = free_group("x") f = FpGroup(F, []) assert f.order() is S.Infinity f = FpGroup(free_group('')[0], []) assert f.order() == 1 def test_fp_subgroup(): def _test_subgroup(K, T, S): _gens = T(K.generators) assert all(elem in S for elem in _gens) assert T.is_injective() assert T.image().order() == S.order() F, x, y = free_group("x, y") f = FpGroup(F, [x**4, y**2, x*y*x**-1*y]) S = FpSubgroup(f, [x*y]) assert (x*y)**-3 in S K, T = f.subgroup([x*y], homomorphism=True) assert T(K.generators) == [y*x**-1] _test_subgroup(K, T, S) S = FpSubgroup(f, [x**-1*y*x]) assert x**-1*y**4*x in S assert x**-1*y**4*x**2 not in S K, T = f.subgroup([x**-1*y*x], homomorphism=True) assert T(K.generators[0]**3) == y**3 _test_subgroup(K, T, S) f = FpGroup(F, [x**3, y**5, (x*y)**2]) H = [x*y, x**-1*y**-1*x*y*x] K, T = f.subgroup(H, homomorphism=True) S = FpSubgroup(f, H) _test_subgroup(K, T, S) def test_permutation_methods(): from sympy.combinatorics.fp_groups import FpSubgroup F, x, y = free_group("x, y") # DihedralGroup(8) G = FpGroup(F, [x**2, y**8, x*y*x**-1*y]) T = G._to_perm_group()[1] assert T.is_isomorphism() assert G.center() == [y**4] # DiheadralGroup(4) G = FpGroup(F, [x**2, y**4, x*y*x**-1*y]) S = FpSubgroup(G, G.normal_closure([x])) assert x in S assert y**-1*x*y in S # Z_5xZ_4 G = FpGroup(F, [x*y*x**-1*y**-1, y**5, x**4]) assert G.is_abelian assert G.is_solvable # AlternatingGroup(5) G = FpGroup(F, [x**3, y**2, (x*y)**5]) assert not G.is_solvable # AlternatingGroup(4) G = FpGroup(F, [x**3, y**2, (x*y)**3]) assert len(G.derived_series()) == 3 S = FpSubgroup(G, G.derived_subgroup()) assert S.order() == 4 def test_simplify_presentation(): # ref #16083 G = simplify_presentation(FpGroup(FreeGroup([]), [])) assert not G.generators assert not G.relators def test_cyclic(): F, x, y = free_group("x, y") f = FpGroup(F, [x*y, x**-1*y**-1*x*y*x]) assert f.is_cyclic f = FpGroup(F, [x*y, x*y**-1]) assert f.is_cyclic f = FpGroup(F, [x**4, y**2, x*y*x**-1*y]) assert not f.is_cyclic def test_abelian_invariants(): F, x, y = free_group("x, y") f = FpGroup(F, [x*y, x**-1*y**-1*x*y*x]) assert f.abelian_invariants() == [] f = FpGroup(F, [x*y, x*y**-1]) assert f.abelian_invariants() == [2] f = FpGroup(F, [x**4, y**2, x*y*x**-1*y]) assert f.abelian_invariants() == [2, 4] sympy-sympy-1.9/sympy/combinatorics/tests/test_free_groups.py000066400000000000000000000140041412543434000250320ustar00rootroot00000000000000from sympy.combinatorics.free_groups import free_group, FreeGroup from sympy.core import Symbol from sympy.testing.pytest import raises from sympy import oo F, x, y, z = free_group("x, y, z") def test_FreeGroup__init__(): x, y, z = map(Symbol, "xyz") assert len(FreeGroup("x, y, z").generators) == 3 assert len(FreeGroup(x).generators) == 1 assert len(FreeGroup(("x", "y", "z"))) == 3 assert len(FreeGroup((x, y, z)).generators) == 3 def test_free_group(): G, a, b, c = free_group("a, b, c") assert F.generators == (x, y, z) assert x*z**2 in F assert x in F assert y*z**-1 in F assert (y*z)**0 in F assert a not in F assert a**0 not in F assert len(F) == 3 assert str(F) == '' assert not F == G assert F.order() is oo assert F.is_abelian == False assert F.center() == {F.identity} (e,) = free_group("") assert e.order() == 1 assert e.generators == () assert e.elements == {e.identity} assert e.is_abelian == True def test_FreeGroup__hash__(): assert hash(F) def test_FreeGroup__eq__(): assert free_group("x, y, z")[0] == free_group("x, y, z")[0] assert free_group("x, y, z")[0] is free_group("x, y, z")[0] assert free_group("x, y, z")[0] != free_group("a, x, y")[0] assert free_group("x, y, z")[0] is not free_group("a, x, y")[0] assert free_group("x, y")[0] != free_group("x, y, z")[0] assert free_group("x, y")[0] is not free_group("x, y, z")[0] assert free_group("x, y, z")[0] != free_group("x, y")[0] assert free_group("x, y, z")[0] is not free_group("x, y")[0] def test_FreeGroup__getitem__(): assert F[0:] == FreeGroup("x, y, z") assert F[1:] == FreeGroup("y, z") assert F[2:] == FreeGroup("z") def test_FreeGroupElm__hash__(): assert hash(x*y*z) def test_FreeGroupElm_copy(): f = x*y*z**3 g = f.copy() h = x*y*z**7 assert f == g assert f != h def test_FreeGroupElm_inverse(): assert x.inverse() == x**-1 assert (x*y).inverse() == y**-1*x**-1 assert (y*x*y**-1).inverse() == y*x**-1*y**-1 assert (y**2*x**-1).inverse() == x*y**-2 def test_FreeGroupElm_type_error(): raises(TypeError, lambda: 2/x) raises(TypeError, lambda: x**2 + y**2) raises(TypeError, lambda: x/2) def test_FreeGroupElm_methods(): assert (x**0).order() == 1 assert (y**2).order() is oo assert (x**-1*y).commutator(x) == y**-1*x**-1*y*x assert len(x**2*y**-1) == 3 assert len(x**-1*y**3*z) == 5 def test_FreeGroupElm_eliminate_word(): w = x**5*y*x**2*y**-4*x assert w.eliminate_word( x, x**2 ) == x**10*y*x**4*y**-4*x**2 w3 = x**2*y**3*x**-1*y assert w3.eliminate_word(x, x**2) == x**4*y**3*x**-2*y assert w3.eliminate_word(x, y) == y**5 assert w3.eliminate_word(x, y**4) == y**8 assert w3.eliminate_word(y, x**-1) == x**-3 assert w3.eliminate_word(x, y*z) == y*z*y*z*y**3*z**-1 assert (y**-3).eliminate_word(y, x**-1*z**-1) == z*x*z*x*z*x #assert w3.eliminate_word(x, y*x) == y*x*y*x**2*y*x*y*x*y*x*z**3 #assert w3.eliminate_word(x, x*y) == x*y*x**2*y*x*y*x*y*x*y*z**3 def test_FreeGroupElm_array_form(): assert (x*z).array_form == ((Symbol('x'), 1), (Symbol('z'), 1)) assert (x**2*z*y*x**-2).array_form == \ ((Symbol('x'), 2), (Symbol('z'), 1), (Symbol('y'), 1), (Symbol('x'), -2)) assert (x**-2*y**-1).array_form == ((Symbol('x'), -2), (Symbol('y'), -1)) def test_FreeGroupElm_letter_form(): assert (x**3).letter_form == (Symbol('x'), Symbol('x'), Symbol('x')) assert (x**2*z**-2*x).letter_form == \ (Symbol('x'), Symbol('x'), -Symbol('z'), -Symbol('z'), Symbol('x')) def test_FreeGroupElm_ext_rep(): assert (x**2*z**-2*x).ext_rep == \ (Symbol('x'), 2, Symbol('z'), -2, Symbol('x'), 1) assert (x**-2*y**-1).ext_rep == (Symbol('x'), -2, Symbol('y'), -1) assert (x*z).ext_rep == (Symbol('x'), 1, Symbol('z'), 1) def test_FreeGroupElm__mul__pow__(): x1 = x.group.dtype(((Symbol('x'), 1),)) assert x**2 == x1*x assert (x**2*y*x**-2)**4 == x**2*y**4*x**-2 assert (x**2)**2 == x**4 assert (x**-1)**-1 == x assert (x**-1)**0 == F.identity assert (y**2)**-2 == y**-4 assert x**2*x**-1 == x assert x**2*y**2*y**-1 == x**2*y assert x*x**-1 == F.identity assert x/x == F.identity assert x/x**2 == x**-1 assert (x**2*y)/(x**2*y**-1) == x**2*y**2*x**-2 assert (x**2*y)/(y**-1*x**2) == x**2*y*x**-2*y assert x*(x**-1*y*z*y**-1) == y*z*y**-1 assert x**2*(x**-2*y**-1*z**2*y) == y**-1*z**2*y def test_FreeGroupElm__len__(): assert len(x**5*y*x**2*y**-4*x) == 13 assert len(x**17) == 17 assert len(y**0) == 0 def test_FreeGroupElm_comparison(): assert not (x*y == y*x) assert x**0 == y**0 assert x**2 < y**3 assert not x**3 < y**2 assert x*y < x**2*y assert x**2*y**2 < y**4 assert not y**4 < y**-4 assert not y**4 < x**-4 assert y**-2 < y**2 assert x**2 <= y**2 assert x**2 <= x**2 assert not y*z > z*y assert x > x**-1 assert not x**2 >= y**2 def test_FreeGroupElm_syllables(): w = x**5*y*x**2*y**-4*x assert w.number_syllables() == 5 assert w.exponent_syllable(2) == 2 assert w.generator_syllable(3) == Symbol('y') assert w.sub_syllables(1, 2) == y assert w.sub_syllables(3, 3) == F.identity def test_FreeGroup_exponents(): w1 = x**2*y**3 assert w1.exponent_sum(x) == 2 assert w1.exponent_sum(x**-1) == -2 assert w1.generator_count(x) == 2 w2 = x**2*y**4*x**-3 assert w2.exponent_sum(x) == -1 assert w2.generator_count(x) == 5 def test_FreeGroup_generators(): assert (x**2*y**4*z**-1).contains_generators() == {x, y, z} assert (x**-1*y**3).contains_generators() == {x, y} def test_FreeGroupElm_words(): w = x**5*y*x**2*y**-4*x assert w.subword(2, 6) == x**3*y assert w.subword(3, 2) == F.identity assert w.subword(6, 10) == x**2*y**-2 assert w.substituted_word(0, 7, y**-1) == y**-1*x*y**-4*x assert w.substituted_word(0, 7, y**2*x) == y**2*x**2*y**-4*x sympy-sympy-1.9/sympy/combinatorics/tests/test_generators.py000066400000000000000000000067571412543434000247030ustar00rootroot00000000000000from sympy.combinatorics.generators import symmetric, cyclic, alternating, \ dihedral, rubik from sympy.combinatorics.permutations import Permutation from sympy.testing.pytest import raises def test_generators(): assert list(cyclic(6)) == [ Permutation([0, 1, 2, 3, 4, 5]), Permutation([1, 2, 3, 4, 5, 0]), Permutation([2, 3, 4, 5, 0, 1]), Permutation([3, 4, 5, 0, 1, 2]), Permutation([4, 5, 0, 1, 2, 3]), Permutation([5, 0, 1, 2, 3, 4])] assert list(cyclic(10)) == [ Permutation([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), Permutation([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]), Permutation([2, 3, 4, 5, 6, 7, 8, 9, 0, 1]), Permutation([3, 4, 5, 6, 7, 8, 9, 0, 1, 2]), Permutation([4, 5, 6, 7, 8, 9, 0, 1, 2, 3]), Permutation([5, 6, 7, 8, 9, 0, 1, 2, 3, 4]), Permutation([6, 7, 8, 9, 0, 1, 2, 3, 4, 5]), Permutation([7, 8, 9, 0, 1, 2, 3, 4, 5, 6]), Permutation([8, 9, 0, 1, 2, 3, 4, 5, 6, 7]), Permutation([9, 0, 1, 2, 3, 4, 5, 6, 7, 8])] assert list(alternating(4)) == [ Permutation([0, 1, 2, 3]), Permutation([0, 2, 3, 1]), Permutation([0, 3, 1, 2]), Permutation([1, 0, 3, 2]), Permutation([1, 2, 0, 3]), Permutation([1, 3, 2, 0]), Permutation([2, 0, 1, 3]), Permutation([2, 1, 3, 0]), Permutation([2, 3, 0, 1]), Permutation([3, 0, 2, 1]), Permutation([3, 1, 0, 2]), Permutation([3, 2, 1, 0])] assert list(symmetric(3)) == [ Permutation([0, 1, 2]), Permutation([0, 2, 1]), Permutation([1, 0, 2]), Permutation([1, 2, 0]), Permutation([2, 0, 1]), Permutation([2, 1, 0])] assert list(symmetric(4)) == [ Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2]), Permutation([0, 2, 1, 3]), Permutation([0, 2, 3, 1]), Permutation([0, 3, 1, 2]), Permutation([0, 3, 2, 1]), Permutation([1, 0, 2, 3]), Permutation([1, 0, 3, 2]), Permutation([1, 2, 0, 3]), Permutation([1, 2, 3, 0]), Permutation([1, 3, 0, 2]), Permutation([1, 3, 2, 0]), Permutation([2, 0, 1, 3]), Permutation([2, 0, 3, 1]), Permutation([2, 1, 0, 3]), Permutation([2, 1, 3, 0]), Permutation([2, 3, 0, 1]), Permutation([2, 3, 1, 0]), Permutation([3, 0, 1, 2]), Permutation([3, 0, 2, 1]), Permutation([3, 1, 0, 2]), Permutation([3, 1, 2, 0]), Permutation([3, 2, 0, 1]), Permutation([3, 2, 1, 0])] assert list(dihedral(1)) == [ Permutation([0, 1]), Permutation([1, 0])] assert list(dihedral(2)) == [ Permutation([0, 1, 2, 3]), Permutation([1, 0, 3, 2]), Permutation([2, 3, 0, 1]), Permutation([3, 2, 1, 0])] assert list(dihedral(3)) == [ Permutation([0, 1, 2]), Permutation([2, 1, 0]), Permutation([1, 2, 0]), Permutation([0, 2, 1]), Permutation([2, 0, 1]), Permutation([1, 0, 2])] assert list(dihedral(5)) == [ Permutation([0, 1, 2, 3, 4]), Permutation([4, 3, 2, 1, 0]), Permutation([1, 2, 3, 4, 0]), Permutation([0, 4, 3, 2, 1]), Permutation([2, 3, 4, 0, 1]), Permutation([1, 0, 4, 3, 2]), Permutation([3, 4, 0, 1, 2]), Permutation([2, 1, 0, 4, 3]), Permutation([4, 0, 1, 2, 3]), Permutation([3, 2, 1, 0, 4])] raises(ValueError, lambda: rubik(1)) sympy-sympy-1.9/sympy/combinatorics/tests/test_graycode.py000066400000000000000000000053601412543434000243140ustar00rootroot00000000000000from sympy.combinatorics.graycode import (GrayCode, bin_to_gray, random_bitstring, get_subset_from_bitstring, graycode_subsets, gray_to_bin) from sympy.testing.pytest import raises def test_graycode(): g = GrayCode(2) got = [] for i in g.generate_gray(): if i.startswith('0'): g.skip() got.append(i) assert got == '00 11 10'.split() a = GrayCode(6) assert a.current == '0'*6 assert a.rank == 0 assert len(list(a.generate_gray())) == 64 codes = ['011001', '011011', '011010', '011110', '011111', '011101', '011100', '010100', '010101', '010111', '010110', '010010', '010011', '010001', '010000', '110000', '110001', '110011', '110010', '110110', '110111', '110101', '110100', '111100', '111101', '111111', '111110', '111010', '111011', '111001', '111000', '101000', '101001', '101011', '101010', '101110', '101111', '101101', '101100', '100100', '100101', '100111', '100110', '100010', '100011', '100001', '100000'] assert list(a.generate_gray(start='011001')) == codes assert list( a.generate_gray(rank=GrayCode(6, start='011001').rank)) == codes assert a.next().current == '000001' assert a.next(2).current == '000011' assert a.next(-1).current == '100000' a = GrayCode(5, start='10010') assert a.rank == 28 a = GrayCode(6, start='101000') assert a.rank == 48 assert GrayCode(6, rank=4).current == '000110' assert GrayCode(6, rank=4).rank == 4 assert [GrayCode(4, start=s).rank for s in GrayCode(4).generate_gray()] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] a = GrayCode(15, rank=15) assert a.current == '000000000001000' assert bin_to_gray('111') == '100' a = random_bitstring(5) assert type(a) is str assert len(a) == 5 assert all(i in ['0', '1'] for i in a) assert get_subset_from_bitstring( ['a', 'b', 'c', 'd'], '0011') == ['c', 'd'] assert get_subset_from_bitstring('abcd', '1001') == ['a', 'd'] assert list(graycode_subsets(['a', 'b', 'c'])) == \ [[], ['c'], ['b', 'c'], ['b'], ['a', 'b'], ['a', 'b', 'c'], ['a', 'c'], ['a']] raises(ValueError, lambda: GrayCode(0)) raises(ValueError, lambda: GrayCode(2.2)) raises(ValueError, lambda: GrayCode(2, start=[1, 1, 0])) raises(ValueError, lambda: GrayCode(2, rank=2.5)) raises(ValueError, lambda: get_subset_from_bitstring(['c', 'a', 'c'], '1100')) raises(ValueError, lambda: list(GrayCode(3).generate_gray(start="1111"))) def test_live_issue_117(): assert bin_to_gray('0100') == '0110' assert bin_to_gray('0101') == '0111' for bits in ('0100', '0101'): assert gray_to_bin(bin_to_gray(bits)) == bits sympy-sympy-1.9/sympy/combinatorics/tests/test_group_constructs.py000066400000000000000000000007021412543434000261350ustar00rootroot00000000000000from sympy.combinatorics.group_constructs import DirectProduct from sympy.combinatorics.named_groups import CyclicGroup, DihedralGroup def test_direct_product_n(): C = CyclicGroup(4) D = DihedralGroup(4) G = DirectProduct(C, C, C) assert G.order() == 64 assert G.degree == 12 assert len(G.orbits()) == 3 assert G.is_abelian is True H = DirectProduct(D, C) assert H.order() == 32 assert H.is_abelian is False sympy-sympy-1.9/sympy/combinatorics/tests/test_homomorphisms.py000066400000000000000000000070451412543434000254250ustar00rootroot00000000000000from sympy.combinatorics import Permutation from sympy.combinatorics.perm_groups import PermutationGroup from sympy.combinatorics.homomorphisms import homomorphism, group_isomorphism, is_isomorphic from sympy.combinatorics.free_groups import free_group from sympy.combinatorics.fp_groups import FpGroup from sympy.combinatorics.named_groups import AlternatingGroup, DihedralGroup, CyclicGroup from sympy.testing.pytest import raises def test_homomorphism(): # FpGroup -> PermutationGroup F, a, b = free_group("a, b") G = FpGroup(F, [a**3, b**3, (a*b)**2]) c = Permutation(3)(0, 1, 2) d = Permutation(3)(1, 2, 3) A = AlternatingGroup(4) T = homomorphism(G, A, [a, b], [c, d]) assert T(a*b**2*a**-1) == c*d**2*c**-1 assert T.is_isomorphism() assert T(T.invert(Permutation(3)(0, 2, 3))) == Permutation(3)(0, 2, 3) T = homomorphism(G, AlternatingGroup(4), G.generators) assert T.is_trivial() assert T.kernel().order() == G.order() E, e = free_group("e") G = FpGroup(E, [e**8]) P = PermutationGroup([Permutation(0, 1, 2, 3), Permutation(0, 2)]) T = homomorphism(G, P, [e], [Permutation(0, 1, 2, 3)]) assert T.image().order() == 4 assert T(T.invert(Permutation(0, 2)(1, 3))) == Permutation(0, 2)(1, 3) T = homomorphism(E, AlternatingGroup(4), E.generators, [c]) assert T.invert(c**2) == e**-1 #order(c) == 3 so c**2 == c**-1 # FreeGroup -> FreeGroup T = homomorphism(F, E, [a], [e]) assert T(a**-2*b**4*a**2).is_identity # FreeGroup -> FpGroup G = FpGroup(F, [a*b*a**-1*b**-1]) T = homomorphism(F, G, F.generators, G.generators) assert T.invert(a**-1*b**-1*a**2) == a*b**-1 # PermutationGroup -> PermutationGroup D = DihedralGroup(8) p = Permutation(0, 1, 2, 3, 4, 5, 6, 7) P = PermutationGroup(p) T = homomorphism(P, D, [p], [p]) assert T.is_injective() assert not T.is_isomorphism() assert T.invert(p**3) == p**3 T2 = homomorphism(F, P, [F.generators[0]], P.generators) T = T.compose(T2) assert T.domain == F assert T.codomain == D assert T(a*b) == p def test_isomorphisms(): F, a, b = free_group("a, b") E, c, d = free_group("c, d") # Infinite groups with differently ordered relators. G = FpGroup(F, [a**2, b**3]) H = FpGroup(F, [b**3, a**2]) assert is_isomorphic(G, H) # Trivial Case # FpGroup -> FpGroup H = FpGroup(F, [a**3, b**3, (a*b)**2]) F, c, d = free_group("c, d") G = FpGroup(F, [c**3, d**3, (c*d)**2]) check, T = group_isomorphism(G, H) assert check T(c**3*d**2) == a**3*b**2 # FpGroup -> PermutationGroup # FpGroup is converted to the equivalent isomorphic group. F, a, b = free_group("a, b") G = FpGroup(F, [a**3, b**3, (a*b)**2]) H = AlternatingGroup(4) check, T = group_isomorphism(G, H) assert check assert T(b*a*b**-1*a**-1*b**-1) == Permutation(0, 2, 3) assert T(b*a*b*a**-1*b**-1) == Permutation(0, 3, 2) # PermutationGroup -> PermutationGroup D = DihedralGroup(8) p = Permutation(0, 1, 2, 3, 4, 5, 6, 7) P = PermutationGroup(p) assert not is_isomorphic(D, P) A = CyclicGroup(5) B = CyclicGroup(7) assert not is_isomorphic(A, B) # Two groups of the same prime order are isomorphic to each other. G = FpGroup(F, [a, b**5]) H = CyclicGroup(5) assert G.order() == H.order() assert is_isomorphic(G, H) def test_check_homomorphism(): a = Permutation(1,2,3,4) b = Permutation(1,3) G = PermutationGroup([a, b]) raises(ValueError, lambda: homomorphism(G, G, [a], [a])) sympy-sympy-1.9/sympy/combinatorics/tests/test_named_groups.py000066400000000000000000000036131412543434000252010ustar00rootroot00000000000000from sympy.combinatorics.named_groups import (SymmetricGroup, CyclicGroup, DihedralGroup, AlternatingGroup, AbelianGroup, RubikGroup) from sympy.testing.pytest import raises def test_SymmetricGroup(): G = SymmetricGroup(5) elements = list(G.generate()) assert (G.generators[0]).size == 5 assert len(elements) == 120 assert G.is_solvable is False assert G.is_abelian is False assert G.is_nilpotent is False assert G.is_transitive() is True H = SymmetricGroup(1) assert H.order() == 1 L = SymmetricGroup(2) assert L.order() == 2 def test_CyclicGroup(): G = CyclicGroup(10) elements = list(G.generate()) assert len(elements) == 10 assert (G.derived_subgroup()).order() == 1 assert G.is_abelian is True assert G.is_solvable is True assert G.is_nilpotent is True H = CyclicGroup(1) assert H.order() == 1 L = CyclicGroup(2) assert L.order() == 2 def test_DihedralGroup(): G = DihedralGroup(6) elements = list(G.generate()) assert len(elements) == 12 assert G.is_transitive() is True assert G.is_abelian is False assert G.is_solvable is True assert G.is_nilpotent is False H = DihedralGroup(1) assert H.order() == 2 L = DihedralGroup(2) assert L.order() == 4 assert L.is_abelian is True assert L.is_nilpotent is True def test_AlternatingGroup(): G = AlternatingGroup(5) elements = list(G.generate()) assert len(elements) == 60 assert [perm.is_even for perm in elements] == [True]*60 H = AlternatingGroup(1) assert H.order() == 1 L = AlternatingGroup(2) assert L.order() == 1 def test_AbelianGroup(): A = AbelianGroup(3, 3, 3) assert A.order() == 27 assert A.is_abelian is True def test_RubikGroup(): raises(ValueError, lambda: RubikGroup(1)) sympy-sympy-1.9/sympy/combinatorics/tests/test_partitions.py000066400000000000000000000100071412543434000247050ustar00rootroot00000000000000from sympy.core.compatibility import ordered from sympy.combinatorics.partitions import (Partition, IntegerPartition, RGS_enum, RGS_unrank, RGS_rank, random_integer_partition) from sympy.testing.pytest import raises from sympy.utilities.iterables import default_sort_key, partitions from sympy.sets.sets import Set, FiniteSet def test_partition_constructor(): raises(ValueError, lambda: Partition([1, 1, 2])) raises(ValueError, lambda: Partition([1, 2, 3], [2, 3, 4])) raises(ValueError, lambda: Partition(1, 2, 3)) raises(ValueError, lambda: Partition(*list(range(3)))) assert Partition([1, 2, 3], [4, 5]) == Partition([4, 5], [1, 2, 3]) assert Partition({1, 2, 3}, {4, 5}) == Partition([1, 2, 3], [4, 5]) a = FiniteSet(1, 2, 3) b = FiniteSet(4, 5) assert Partition(a, b) == Partition([1, 2, 3], [4, 5]) assert Partition({a, b}) == Partition(FiniteSet(a, b)) assert Partition({a, b}) != Partition(a, b) def test_partition(): from sympy.abc import x a = Partition([1, 2, 3], [4]) b = Partition([1, 2], [3, 4]) c = Partition([x]) l = [a, b, c] l.sort(key=default_sort_key) assert l == [c, a, b] l.sort(key=lambda w: default_sort_key(w, order='rev-lex')) assert l == [c, a, b] assert (a == b) is False assert a <= b assert (a > b) is False assert a != b assert a < b assert (a + 2).partition == [[1, 2], [3, 4]] assert (b - 1).partition == [[1, 2, 4], [3]] assert (a - 1).partition == [[1, 2, 3, 4]] assert (a + 1).partition == [[1, 2, 4], [3]] assert (b + 1).partition == [[1, 2], [3], [4]] assert a.rank == 1 assert b.rank == 3 assert a.RGS == (0, 0, 0, 1) assert b.RGS == (0, 0, 1, 1) def test_integer_partition(): # no zeros in partition raises(ValueError, lambda: IntegerPartition(list(range(3)))) # check fails since 1 + 2 != 100 raises(ValueError, lambda: IntegerPartition(100, list(range(1, 3)))) a = IntegerPartition(8, [1, 3, 4]) b = a.next_lex() c = IntegerPartition([1, 3, 4]) d = IntegerPartition(8, {1: 3, 3: 1, 2: 1}) assert a == c assert a.integer == d.integer assert a.conjugate == [3, 2, 2, 1] assert (a == b) is False assert a <= b assert (a > b) is False assert a != b for i in range(1, 11): next = set() prev = set() a = IntegerPartition([i]) ans = {IntegerPartition(p) for p in partitions(i)} n = len(ans) for j in range(n): next.add(a) a = a.next_lex() IntegerPartition(i, a.partition) # check it by giving i for j in range(n): prev.add(a) a = a.prev_lex() IntegerPartition(i, a.partition) # check it by giving i assert next == ans assert prev == ans assert IntegerPartition([1, 2, 3]).as_ferrers() == '###\n##\n#' assert IntegerPartition([1, 1, 3]).as_ferrers('o') == 'ooo\no\no' assert str(IntegerPartition([1, 1, 3])) == '[3, 1, 1]' assert IntegerPartition([1, 1, 3]).partition == [3, 1, 1] raises(ValueError, lambda: random_integer_partition(-1)) assert random_integer_partition(1) == [1] assert random_integer_partition(10, seed=[1, 3, 2, 1, 5, 1] ) == [5, 2, 1, 1, 1] def test_rgs(): raises(ValueError, lambda: RGS_unrank(-1, 3)) raises(ValueError, lambda: RGS_unrank(3, 0)) raises(ValueError, lambda: RGS_unrank(10, 1)) raises(ValueError, lambda: Partition.from_rgs(list(range(3)), list(range(2)))) raises(ValueError, lambda: Partition.from_rgs(list(range(1, 3)), list(range(2)))) assert RGS_enum(-1) == 0 assert RGS_enum(1) == 1 assert RGS_unrank(7, 5) == [0, 0, 1, 0, 2] assert RGS_unrank(23, 14) == [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 2] assert RGS_rank(RGS_unrank(40, 100)) == 40 def test_ordered_partition_9608(): a = Partition([1, 2, 3], [4]) b = Partition([1, 2], [3, 4]) assert list(ordered([a,b], Set._infimum_key)) sympy-sympy-1.9/sympy/combinatorics/tests/test_pc_groups.py000066400000000000000000000052631412543434000245220ustar00rootroot00000000000000from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.named_groups import SymmetricGroup, AlternatingGroup, DihedralGroup from sympy.matrices import Matrix def test_pc_presentation(): Groups = [SymmetricGroup(3), SymmetricGroup(4), SymmetricGroup(9).sylow_subgroup(3), SymmetricGroup(9).sylow_subgroup(2), SymmetricGroup(8).sylow_subgroup(2), DihedralGroup(10)] S = SymmetricGroup(125).sylow_subgroup(5) G = S.derived_series()[2] Groups.append(G) G = SymmetricGroup(25).sylow_subgroup(5) Groups.append(G) S = SymmetricGroup(11**2).sylow_subgroup(11) G = S.derived_series()[2] Groups.append(G) for G in Groups: PcGroup = G.polycyclic_group() collector = PcGroup.collector pc_presentation = collector.pc_presentation pcgs = PcGroup.pcgs free_group = collector.free_group free_to_perm = {} for s, g in zip(free_group.symbols, pcgs): free_to_perm[s] = g for k, v in pc_presentation.items(): k_array = k.array_form if v != (): v_array = v.array_form lhs = Permutation() for gen in k_array: s = gen[0] e = gen[1] lhs = lhs*free_to_perm[s]**e if v == (): assert lhs.is_identity continue rhs = Permutation() for gen in v_array: s = gen[0] e = gen[1] rhs = rhs*free_to_perm[s]**e assert lhs == rhs def test_exponent_vector(): Groups = [SymmetricGroup(3), SymmetricGroup(4), SymmetricGroup(9).sylow_subgroup(3), SymmetricGroup(9).sylow_subgroup(2), SymmetricGroup(8).sylow_subgroup(2)] for G in Groups: PcGroup = G.polycyclic_group() collector = PcGroup.collector pcgs = PcGroup.pcgs # free_group = collector.free_group for gen in G.generators: exp = collector.exponent_vector(gen) g = Permutation() for i in range(len(exp)): g = g*pcgs[i]**exp[i] if exp[i] else g assert g == gen def test_induced_pcgs(): G = [SymmetricGroup(9).sylow_subgroup(3), SymmetricGroup(20).sylow_subgroup(2), AlternatingGroup(4), DihedralGroup(4), DihedralGroup(10), DihedralGroup(9), SymmetricGroup(3), SymmetricGroup(4)] for g in G: PcGroup = g.polycyclic_group() collector = PcGroup.collector gens = [gen for gen in g.generators] ipcgs = collector.induced_pcgs(gens) m = [] for i in ipcgs: m.append(collector.exponent_vector(i)) assert Matrix(m).is_upper sympy-sympy-1.9/sympy/combinatorics/tests/test_perm_groups.py000066400000000000000000001146521412543434000250660ustar00rootroot00000000000000from sympy.combinatorics.perm_groups import (PermutationGroup, _orbit_transversal, Coset, SymmetricPermutationGroup) from sympy.combinatorics.named_groups import SymmetricGroup, CyclicGroup,\ DihedralGroup, AlternatingGroup, AbelianGroup, RubikGroup from sympy.combinatorics.permutations import Permutation from sympy.testing.pytest import skip, XFAIL from sympy.combinatorics.generators import rubik_cube_generators from sympy.combinatorics.polyhedron import tetrahedron as Tetra, cube from sympy.combinatorics.testutil import _verify_bsgs, _verify_centralizer,\ _verify_normal_closure from sympy.testing.pytest import slow from sympy.combinatorics.homomorphisms import is_isomorphic rmul = Permutation.rmul def test_has(): a = Permutation([1, 0]) G = PermutationGroup([a]) assert G.is_abelian a = Permutation([2, 0, 1]) b = Permutation([2, 1, 0]) G = PermutationGroup([a, b]) assert not G.is_abelian G = PermutationGroup([a]) assert G.has(a) assert not G.has(b) a = Permutation([2, 0, 1, 3, 4, 5]) b = Permutation([0, 2, 1, 3, 4]) assert PermutationGroup(a, b).degree == \ PermutationGroup(a, b).degree == 6 def test_generate(): a = Permutation([1, 0]) g = list(PermutationGroup([a]).generate()) assert g == [Permutation([0, 1]), Permutation([1, 0])] assert len(list(PermutationGroup(Permutation((0, 1))).generate())) == 1 g = PermutationGroup([a]).generate(method='dimino') assert list(g) == [Permutation([0, 1]), Permutation([1, 0])] a = Permutation([2, 0, 1]) b = Permutation([2, 1, 0]) G = PermutationGroup([a, b]) g = G.generate() v1 = [p.array_form for p in list(g)] v1.sort() assert v1 == [[0, 1, 2], [0, 2, 1], [1, 0, 2], [1, 2, 0], [2, 0, 1], [2, 1, 0]] v2 = list(G.generate(method='dimino', af=True)) assert v1 == sorted(v2) a = Permutation([2, 0, 1, 3, 4, 5]) b = Permutation([2, 1, 3, 4, 5, 0]) g = PermutationGroup([a, b]).generate(af=True) assert len(list(g)) == 360 def test_order(): a = Permutation([2, 0, 1, 3, 4, 5, 6, 7, 8, 9]) b = Permutation([2, 1, 3, 4, 5, 6, 7, 8, 9, 0]) g = PermutationGroup([a, b]) assert g.order() == 1814400 assert PermutationGroup().order() == 1 def test_equality(): p_1 = Permutation(0, 1, 3) p_2 = Permutation(0, 2, 3) p_3 = Permutation(0, 1, 2) p_4 = Permutation(0, 1, 3) g_1 = PermutationGroup(p_1, p_2) g_2 = PermutationGroup(p_3, p_4) g_3 = PermutationGroup(p_2, p_1) assert g_1 == g_2 assert g_1.generators != g_2.generators assert g_1 == g_3 def test_stabilizer(): S = SymmetricGroup(2) H = S.stabilizer(0) assert H.generators == [Permutation(1)] a = Permutation([2, 0, 1, 3, 4, 5]) b = Permutation([2, 1, 3, 4, 5, 0]) G = PermutationGroup([a, b]) G0 = G.stabilizer(0) assert G0.order() == 60 gens_cube = [[1, 3, 5, 7, 0, 2, 4, 6], [1, 3, 0, 2, 5, 7, 4, 6]] gens = [Permutation(p) for p in gens_cube] G = PermutationGroup(gens) G2 = G.stabilizer(2) assert G2.order() == 6 G2_1 = G2.stabilizer(1) v = list(G2_1.generate(af=True)) assert v == [[0, 1, 2, 3, 4, 5, 6, 7], [3, 1, 2, 0, 7, 5, 6, 4]] gens = ( (1, 2, 0, 4, 5, 3, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19), (0, 1, 2, 3, 4, 5, 19, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, 7, 17, 18), (0, 1, 2, 3, 4, 5, 6, 7, 9, 18, 16, 11, 12, 13, 14, 15, 8, 17, 10, 19)) gens = [Permutation(p) for p in gens] G = PermutationGroup(gens) G2 = G.stabilizer(2) assert G2.order() == 181440 S = SymmetricGroup(3) assert [G.order() for G in S.basic_stabilizers] == [6, 2] def test_center(): # the center of the dihedral group D_n is of order 2 for even n for i in (4, 6, 10): D = DihedralGroup(i) assert (D.center()).order() == 2 # the center of the dihedral group D_n is of order 1 for odd n>2 for i in (3, 5, 7): D = DihedralGroup(i) assert (D.center()).order() == 1 # the center of an abelian group is the group itself for i in (2, 3, 5): for j in (1, 5, 7): for k in (1, 1, 11): G = AbelianGroup(i, j, k) assert G.center().is_subgroup(G) # the center of a nonabelian simple group is trivial for i in(1, 5, 9): A = AlternatingGroup(i) assert (A.center()).order() == 1 # brute-force verifications D = DihedralGroup(5) A = AlternatingGroup(3) C = CyclicGroup(4) G.is_subgroup(D*A*C) assert _verify_centralizer(G, G) def test_centralizer(): # the centralizer of the trivial group is the entire group S = SymmetricGroup(2) assert S.centralizer(Permutation(list(range(2)))).is_subgroup(S) A = AlternatingGroup(5) assert A.centralizer(Permutation(list(range(5)))).is_subgroup(A) # a centralizer in the trivial group is the trivial group itself triv = PermutationGroup([Permutation([0, 1, 2, 3])]) D = DihedralGroup(4) assert triv.centralizer(D).is_subgroup(triv) # brute-force verifications for centralizers of groups for i in (4, 5, 6): S = SymmetricGroup(i) A = AlternatingGroup(i) C = CyclicGroup(i) D = DihedralGroup(i) for gp in (S, A, C, D): for gp2 in (S, A, C, D): if not gp2.is_subgroup(gp): assert _verify_centralizer(gp, gp2) # verify the centralizer for all elements of several groups S = SymmetricGroup(5) elements = list(S.generate_dimino()) for element in elements: assert _verify_centralizer(S, element) A = AlternatingGroup(5) elements = list(A.generate_dimino()) for element in elements: assert _verify_centralizer(A, element) D = DihedralGroup(7) elements = list(D.generate_dimino()) for element in elements: assert _verify_centralizer(D, element) # verify centralizers of small groups within small groups small = [] for i in (1, 2, 3): small.append(SymmetricGroup(i)) small.append(AlternatingGroup(i)) small.append(DihedralGroup(i)) small.append(CyclicGroup(i)) for gp in small: for gp2 in small: if gp.degree == gp2.degree: assert _verify_centralizer(gp, gp2) def test_coset_rank(): gens_cube = [[1, 3, 5, 7, 0, 2, 4, 6], [1, 3, 0, 2, 5, 7, 4, 6]] gens = [Permutation(p) for p in gens_cube] G = PermutationGroup(gens) i = 0 for h in G.generate(af=True): rk = G.coset_rank(h) assert rk == i h1 = G.coset_unrank(rk, af=True) assert h == h1 i += 1 assert G.coset_unrank(48) == None assert G.coset_unrank(G.coset_rank(gens[0])) == gens[0] def test_coset_factor(): a = Permutation([0, 2, 1]) G = PermutationGroup([a]) c = Permutation([2, 1, 0]) assert not G.coset_factor(c) assert G.coset_rank(c) is None a = Permutation([2, 0, 1, 3, 4, 5]) b = Permutation([2, 1, 3, 4, 5, 0]) g = PermutationGroup([a, b]) assert g.order() == 360 d = Permutation([1, 0, 2, 3, 4, 5]) assert not g.coset_factor(d.array_form) assert not g.contains(d) assert Permutation(2) in G c = Permutation([1, 0, 2, 3, 5, 4]) v = g.coset_factor(c, True) tr = g.basic_transversals p = Permutation.rmul(*[tr[i][v[i]] for i in range(len(g.base))]) assert p == c v = g.coset_factor(c) p = Permutation.rmul(*v) assert p == c assert g.contains(c) G = PermutationGroup([Permutation([2, 1, 0])]) p = Permutation([1, 0, 2]) assert G.coset_factor(p) == [] def test_orbits(): a = Permutation([2, 0, 1]) b = Permutation([2, 1, 0]) g = PermutationGroup([a, b]) assert g.orbit(0) == {0, 1, 2} assert g.orbits() == [{0, 1, 2}] assert g.is_transitive() and g.is_transitive(strict=False) assert g.orbit_transversal(0) == \ [Permutation( [0, 1, 2]), Permutation([2, 0, 1]), Permutation([1, 2, 0])] assert g.orbit_transversal(0, True) == \ [(0, Permutation([0, 1, 2])), (2, Permutation([2, 0, 1])), (1, Permutation([1, 2, 0]))] G = DihedralGroup(6) transversal, slps = _orbit_transversal(G.degree, G.generators, 0, True, slp=True) for i, t in transversal: slp = slps[i] w = G.identity for s in slp: w = G.generators[s]*w assert w == t a = Permutation(list(range(1, 100)) + [0]) G = PermutationGroup([a]) assert [min(o) for o in G.orbits()] == [0] G = PermutationGroup(rubik_cube_generators()) assert [min(o) for o in G.orbits()] == [0, 1] assert not G.is_transitive() and not G.is_transitive(strict=False) G = PermutationGroup([Permutation(0, 1, 3), Permutation(3)(0, 1)]) assert not G.is_transitive() and G.is_transitive(strict=False) assert PermutationGroup( Permutation(3)).is_transitive(strict=False) is False def test_is_normal(): gens_s5 = [Permutation(p) for p in [[1, 2, 3, 4, 0], [2, 1, 4, 0, 3]]] G1 = PermutationGroup(gens_s5) assert G1.order() == 120 gens_a5 = [Permutation(p) for p in [[1, 0, 3, 2, 4], [2, 1, 4, 3, 0]]] G2 = PermutationGroup(gens_a5) assert G2.order() == 60 assert G2.is_normal(G1) gens3 = [Permutation(p) for p in [[2, 1, 3, 0, 4], [1, 2, 0, 3, 4]]] G3 = PermutationGroup(gens3) assert not G3.is_normal(G1) assert G3.order() == 12 G4 = G1.normal_closure(G3.generators) assert G4.order() == 60 gens5 = [Permutation(p) for p in [[1, 2, 3, 0, 4], [1, 2, 0, 3, 4]]] G5 = PermutationGroup(gens5) assert G5.order() == 24 G6 = G1.normal_closure(G5.generators) assert G6.order() == 120 assert G1.is_subgroup(G6) assert not G1.is_subgroup(G4) assert G2.is_subgroup(G4) I5 = PermutationGroup(Permutation(4)) assert I5.is_normal(G5) assert I5.is_normal(G6, strict=False) p1 = Permutation([1, 0, 2, 3, 4]) p2 = Permutation([0, 1, 2, 4, 3]) p3 = Permutation([3, 4, 2, 1, 0]) id_ = Permutation([0, 1, 2, 3, 4]) H = PermutationGroup([p1, p3]) H_n1 = PermutationGroup([p1, p2]) H_n2_1 = PermutationGroup(p1) H_n2_2 = PermutationGroup(p2) H_id = PermutationGroup(id_) assert H_n1.is_normal(H) assert H_n2_1.is_normal(H_n1) assert H_n2_2.is_normal(H_n1) assert H_id.is_normal(H_n2_1) assert H_id.is_normal(H_n1) assert H_id.is_normal(H) assert not H_n2_1.is_normal(H) assert not H_n2_2.is_normal(H) def test_eq(): a = [[1, 2, 0, 3, 4, 5], [1, 0, 2, 3, 4, 5], [2, 1, 0, 3, 4, 5], [ 1, 2, 0, 3, 4, 5]] a = [Permutation(p) for p in a + [[1, 2, 3, 4, 5, 0]]] g = Permutation([1, 2, 3, 4, 5, 0]) G1, G2, G3 = [PermutationGroup(x) for x in [a[:2], a[2:4], [g, g**2]]] assert G1.order() == G2.order() == G3.order() == 6 assert G1.is_subgroup(G2) assert not G1.is_subgroup(G3) G4 = PermutationGroup([Permutation([0, 1])]) assert not G1.is_subgroup(G4) assert G4.is_subgroup(G1, 0) assert PermutationGroup(g, g).is_subgroup(PermutationGroup(g)) assert SymmetricGroup(3).is_subgroup(SymmetricGroup(4), 0) assert SymmetricGroup(3).is_subgroup(SymmetricGroup(3)*CyclicGroup(5), 0) assert not CyclicGroup(5).is_subgroup(SymmetricGroup(3)*CyclicGroup(5), 0) assert CyclicGroup(3).is_subgroup(SymmetricGroup(3)*CyclicGroup(5), 0) def test_derived_subgroup(): a = Permutation([1, 0, 2, 4, 3]) b = Permutation([0, 1, 3, 2, 4]) G = PermutationGroup([a, b]) C = G.derived_subgroup() assert C.order() == 3 assert C.is_normal(G) assert C.is_subgroup(G, 0) assert not G.is_subgroup(C, 0) gens_cube = [[1, 3, 5, 7, 0, 2, 4, 6], [1, 3, 0, 2, 5, 7, 4, 6]] gens = [Permutation(p) for p in gens_cube] G = PermutationGroup(gens) C = G.derived_subgroup() assert C.order() == 12 def test_is_solvable(): a = Permutation([1, 2, 0]) b = Permutation([1, 0, 2]) G = PermutationGroup([a, b]) assert G.is_solvable G = PermutationGroup([a]) assert G.is_solvable a = Permutation([1, 2, 3, 4, 0]) b = Permutation([1, 0, 2, 3, 4]) G = PermutationGroup([a, b]) assert not G.is_solvable P = SymmetricGroup(10) S = P.sylow_subgroup(3) assert S.is_solvable def test_rubik1(): gens = rubik_cube_generators() gens1 = [gens[-1]] + [p**2 for p in gens[1:]] G1 = PermutationGroup(gens1) assert G1.order() == 19508428800 gens2 = [p**2 for p in gens] G2 = PermutationGroup(gens2) assert G2.order() == 663552 assert G2.is_subgroup(G1, 0) C1 = G1.derived_subgroup() assert C1.order() == 4877107200 assert C1.is_subgroup(G1, 0) assert not G2.is_subgroup(C1, 0) G = RubikGroup(2) assert G.order() == 3674160 @XFAIL def test_rubik(): skip('takes too much time') G = PermutationGroup(rubik_cube_generators()) assert G.order() == 43252003274489856000 G1 = PermutationGroup(G[:3]) assert G1.order() == 170659735142400 assert not G1.is_normal(G) G2 = G.normal_closure(G1.generators) assert G2.is_subgroup(G) def test_direct_product(): C = CyclicGroup(4) D = DihedralGroup(4) G = C*C*C assert G.order() == 64 assert G.degree == 12 assert len(G.orbits()) == 3 assert G.is_abelian is True H = D*C assert H.order() == 32 assert H.is_abelian is False def test_orbit_rep(): G = DihedralGroup(6) assert G.orbit_rep(1, 3) in [Permutation([2, 3, 4, 5, 0, 1]), Permutation([4, 3, 2, 1, 0, 5])] H = CyclicGroup(4)*G assert H.orbit_rep(1, 5) is False def test_schreier_vector(): G = CyclicGroup(50) v = [0]*50 v[23] = -1 assert G.schreier_vector(23) == v H = DihedralGroup(8) assert H.schreier_vector(2) == [0, 1, -1, 0, 0, 1, 0, 0] L = SymmetricGroup(4) assert L.schreier_vector(1) == [1, -1, 0, 0] def test_random_pr(): D = DihedralGroup(6) r = 11 n = 3 _random_prec_n = {} _random_prec_n[0] = {'s': 7, 't': 3, 'x': 2, 'e': -1} _random_prec_n[1] = {'s': 5, 't': 5, 'x': 1, 'e': -1} _random_prec_n[2] = {'s': 3, 't': 4, 'x': 2, 'e': 1} D._random_pr_init(r, n, _random_prec_n=_random_prec_n) assert D._random_gens[11] == [0, 1, 2, 3, 4, 5] _random_prec = {'s': 2, 't': 9, 'x': 1, 'e': -1} assert D.random_pr(_random_prec=_random_prec) == \ Permutation([0, 5, 4, 3, 2, 1]) def test_is_alt_sym(): G = DihedralGroup(10) assert G.is_alt_sym() is False assert G._eval_is_alt_sym_naive() is False assert G._eval_is_alt_sym_naive(only_alt=True) is False assert G._eval_is_alt_sym_naive(only_sym=True) is False S = SymmetricGroup(10) assert S._eval_is_alt_sym_naive() is True assert S._eval_is_alt_sym_naive(only_alt=True) is False assert S._eval_is_alt_sym_naive(only_sym=True) is True N_eps = 10 _random_prec = {'N_eps': N_eps, 0: Permutation([[2], [1, 4], [0, 6, 7, 8, 9, 3, 5]]), 1: Permutation([[1, 8, 7, 6, 3, 5, 2, 9], [0, 4]]), 2: Permutation([[5, 8], [4, 7], [0, 1, 2, 3, 6, 9]]), 3: Permutation([[3], [0, 8, 2, 7, 4, 1, 6, 9, 5]]), 4: Permutation([[8], [4, 7, 9], [3, 6], [0, 5, 1, 2]]), 5: Permutation([[6], [0, 2, 4, 5, 1, 8, 3, 9, 7]]), 6: Permutation([[6, 9, 8], [4, 5], [1, 3, 7], [0, 2]]), 7: Permutation([[4], [0, 2, 9, 1, 3, 8, 6, 5, 7]]), 8: Permutation([[1, 5, 6, 3], [0, 2, 7, 8, 4, 9]]), 9: Permutation([[8], [6, 7], [2, 3, 4, 5], [0, 1, 9]])} assert S.is_alt_sym(_random_prec=_random_prec) is True A = AlternatingGroup(10) assert A._eval_is_alt_sym_naive() is True assert A._eval_is_alt_sym_naive(only_alt=True) is True assert A._eval_is_alt_sym_naive(only_sym=True) is False _random_prec = {'N_eps': N_eps, 0: Permutation([[1, 6, 4, 2, 7, 8, 5, 9, 3], [0]]), 1: Permutation([[1], [0, 5, 8, 4, 9, 2, 3, 6, 7]]), 2: Permutation([[1, 9, 8, 3, 2, 5], [0, 6, 7, 4]]), 3: Permutation([[6, 8, 9], [4, 5], [1, 3, 7, 2], [0]]), 4: Permutation([[8], [5], [4], [2, 6, 9, 3], [1], [0, 7]]), 5: Permutation([[3, 6], [0, 8, 1, 7, 5, 9, 4, 2]]), 6: Permutation([[5], [2, 9], [1, 8, 3], [0, 4, 7, 6]]), 7: Permutation([[1, 8, 4, 7, 2, 3], [0, 6, 9, 5]]), 8: Permutation([[5, 8, 7], [3], [1, 4, 2, 6], [0, 9]]), 9: Permutation([[4, 9, 6], [3, 8], [1, 2], [0, 5, 7]])} assert A.is_alt_sym(_random_prec=_random_prec) is False G = PermutationGroup( Permutation(1, 3, size=8)(0, 2, 4, 6), Permutation(5, 7, size=8)(0, 2, 4, 6)) assert G.is_alt_sym() is False # Tests for monte-carlo c_n parameter setting, and which guarantees # to give False. G = DihedralGroup(10) assert G._eval_is_alt_sym_monte_carlo() is False G = DihedralGroup(20) assert G._eval_is_alt_sym_monte_carlo() is False # A dry-running test to check if it looks up for the updated cache. G = DihedralGroup(6) G.is_alt_sym() assert G.is_alt_sym() == False def test_minimal_block(): D = DihedralGroup(6) block_system = D.minimal_block([0, 3]) for i in range(3): assert block_system[i] == block_system[i + 3] S = SymmetricGroup(6) assert S.minimal_block([0, 1]) == [0, 0, 0, 0, 0, 0] assert Tetra.pgroup.minimal_block([0, 1]) == [0, 0, 0, 0] P1 = PermutationGroup(Permutation(1, 5)(2, 4), Permutation(0, 1, 2, 3, 4, 5)) P2 = PermutationGroup(Permutation(0, 1, 2, 3, 4, 5), Permutation(1, 5)(2, 4)) assert P1.minimal_block([0, 2]) == [0, 1, 0, 1, 0, 1] assert P2.minimal_block([0, 2]) == [0, 1, 0, 1, 0, 1] def test_minimal_blocks(): P = PermutationGroup(Permutation(1, 5)(2, 4), Permutation(0, 1, 2, 3, 4, 5)) assert P.minimal_blocks() == [[0, 1, 0, 1, 0, 1], [0, 1, 2, 0, 1, 2]] P = SymmetricGroup(5) assert P.minimal_blocks() == [[0]*5] P = PermutationGroup(Permutation(0, 3)) assert P.minimal_blocks() == False def test_max_div(): S = SymmetricGroup(10) assert S.max_div == 5 def test_is_primitive(): S = SymmetricGroup(5) assert S.is_primitive() is True C = CyclicGroup(7) assert C.is_primitive() is True a = Permutation(0, 1, 2, size=6) b = Permutation(3, 4, 5, size=6) G = PermutationGroup(a, b) assert G.is_primitive() is False def test_random_stab(): S = SymmetricGroup(5) _random_el = Permutation([1, 3, 2, 0, 4]) _random_prec = {'rand': _random_el} g = S.random_stab(2, _random_prec=_random_prec) assert g == Permutation([1, 3, 2, 0, 4]) h = S.random_stab(1) assert h(1) == 1 def test_transitivity_degree(): perm = Permutation([1, 2, 0]) C = PermutationGroup([perm]) assert C.transitivity_degree == 1 gen1 = Permutation([1, 2, 0, 3, 4]) gen2 = Permutation([1, 2, 3, 4, 0]) # alternating group of degree 5 Alt = PermutationGroup([gen1, gen2]) assert Alt.transitivity_degree == 3 def test_schreier_sims_random(): assert sorted(Tetra.pgroup.base) == [0, 1] S = SymmetricGroup(3) base = [0, 1] strong_gens = [Permutation([1, 2, 0]), Permutation([1, 0, 2]), Permutation([0, 2, 1])] assert S.schreier_sims_random(base, strong_gens, 5) == (base, strong_gens) D = DihedralGroup(3) _random_prec = {'g': [Permutation([2, 0, 1]), Permutation([1, 2, 0]), Permutation([1, 0, 2])]} base = [0, 1] strong_gens = [Permutation([1, 2, 0]), Permutation([2, 1, 0]), Permutation([0, 2, 1])] assert D.schreier_sims_random([], D.generators, 2, _random_prec=_random_prec) == (base, strong_gens) def test_baseswap(): S = SymmetricGroup(4) S.schreier_sims() base = S.base strong_gens = S.strong_gens assert base == [0, 1, 2] deterministic = S.baseswap(base, strong_gens, 1, randomized=False) randomized = S.baseswap(base, strong_gens, 1) assert deterministic[0] == [0, 2, 1] assert _verify_bsgs(S, deterministic[0], deterministic[1]) is True assert randomized[0] == [0, 2, 1] assert _verify_bsgs(S, randomized[0], randomized[1]) is True def test_schreier_sims_incremental(): identity = Permutation([0, 1, 2, 3, 4]) TrivialGroup = PermutationGroup([identity]) base, strong_gens = TrivialGroup.schreier_sims_incremental(base=[0, 1, 2]) assert _verify_bsgs(TrivialGroup, base, strong_gens) is True S = SymmetricGroup(5) base, strong_gens = S.schreier_sims_incremental(base=[0, 1, 2]) assert _verify_bsgs(S, base, strong_gens) is True D = DihedralGroup(2) base, strong_gens = D.schreier_sims_incremental(base=[1]) assert _verify_bsgs(D, base, strong_gens) is True A = AlternatingGroup(7) gens = A.generators[:] gen0 = gens[0] gen1 = gens[1] gen1 = rmul(gen1, ~gen0) gen0 = rmul(gen0, gen1) gen1 = rmul(gen0, gen1) base, strong_gens = A.schreier_sims_incremental(base=[0, 1], gens=gens) assert _verify_bsgs(A, base, strong_gens) is True C = CyclicGroup(11) gen = C.generators[0] base, strong_gens = C.schreier_sims_incremental(gens=[gen**3]) assert _verify_bsgs(C, base, strong_gens) is True def _subgroup_search(i, j, k): prop_true = lambda x: True prop_fix_points = lambda x: [x(point) for point in points] == points prop_comm_g = lambda x: rmul(x, g) == rmul(g, x) prop_even = lambda x: x.is_even for i in range(i, j, k): S = SymmetricGroup(i) A = AlternatingGroup(i) C = CyclicGroup(i) Sym = S.subgroup_search(prop_true) assert Sym.is_subgroup(S) Alt = S.subgroup_search(prop_even) assert Alt.is_subgroup(A) Sym = S.subgroup_search(prop_true, init_subgroup=C) assert Sym.is_subgroup(S) points = [7] assert S.stabilizer(7).is_subgroup(S.subgroup_search(prop_fix_points)) points = [3, 4] assert S.stabilizer(3).stabilizer(4).is_subgroup( S.subgroup_search(prop_fix_points)) points = [3, 5] fix35 = A.subgroup_search(prop_fix_points) points = [5] fix5 = A.subgroup_search(prop_fix_points) assert A.subgroup_search(prop_fix_points, init_subgroup=fix35 ).is_subgroup(fix5) base, strong_gens = A.schreier_sims_incremental() g = A.generators[0] comm_g = \ A.subgroup_search(prop_comm_g, base=base, strong_gens=strong_gens) assert _verify_bsgs(comm_g, base, comm_g.generators) is True assert [prop_comm_g(gen) is True for gen in comm_g.generators] def test_subgroup_search(): _subgroup_search(10, 15, 2) @XFAIL def test_subgroup_search2(): skip('takes too much time') _subgroup_search(16, 17, 1) def test_normal_closure(): # the normal closure of the trivial group is trivial S = SymmetricGroup(3) identity = Permutation([0, 1, 2]) closure = S.normal_closure(identity) assert closure.is_trivial # the normal closure of the entire group is the entire group A = AlternatingGroup(4) assert A.normal_closure(A).is_subgroup(A) # brute-force verifications for subgroups for i in (3, 4, 5): S = SymmetricGroup(i) A = AlternatingGroup(i) D = DihedralGroup(i) C = CyclicGroup(i) for gp in (A, D, C): assert _verify_normal_closure(S, gp) # brute-force verifications for all elements of a group S = SymmetricGroup(5) elements = list(S.generate_dimino()) for element in elements: assert _verify_normal_closure(S, element) # small groups small = [] for i in (1, 2, 3): small.append(SymmetricGroup(i)) small.append(AlternatingGroup(i)) small.append(DihedralGroup(i)) small.append(CyclicGroup(i)) for gp in small: for gp2 in small: if gp2.is_subgroup(gp, 0) and gp2.degree == gp.degree: assert _verify_normal_closure(gp, gp2) def test_derived_series(): # the derived series of the trivial group consists only of the trivial group triv = PermutationGroup([Permutation([0, 1, 2])]) assert triv.derived_series()[0].is_subgroup(triv) # the derived series for a simple group consists only of the group itself for i in (5, 6, 7): A = AlternatingGroup(i) assert A.derived_series()[0].is_subgroup(A) # the derived series for S_4 is S_4 > A_4 > K_4 > triv S = SymmetricGroup(4) series = S.derived_series() assert series[1].is_subgroup(AlternatingGroup(4)) assert series[2].is_subgroup(DihedralGroup(2)) assert series[3].is_trivial def test_lower_central_series(): # the lower central series of the trivial group consists of the trivial # group triv = PermutationGroup([Permutation([0, 1, 2])]) assert triv.lower_central_series()[0].is_subgroup(triv) # the lower central series of a simple group consists of the group itself for i in (5, 6, 7): A = AlternatingGroup(i) assert A.lower_central_series()[0].is_subgroup(A) # GAP-verified example S = SymmetricGroup(6) series = S.lower_central_series() assert len(series) == 2 assert series[1].is_subgroup(AlternatingGroup(6)) def test_commutator(): # the commutator of the trivial group and the trivial group is trivial S = SymmetricGroup(3) triv = PermutationGroup([Permutation([0, 1, 2])]) assert S.commutator(triv, triv).is_subgroup(triv) # the commutator of the trivial group and any other group is again trivial A = AlternatingGroup(3) assert S.commutator(triv, A).is_subgroup(triv) # the commutator is commutative for i in (3, 4, 5): S = SymmetricGroup(i) A = AlternatingGroup(i) D = DihedralGroup(i) assert S.commutator(A, D).is_subgroup(S.commutator(D, A)) # the commutator of an abelian group is trivial S = SymmetricGroup(7) A1 = AbelianGroup(2, 5) A2 = AbelianGroup(3, 4) triv = PermutationGroup([Permutation([0, 1, 2, 3, 4, 5, 6])]) assert S.commutator(A1, A1).is_subgroup(triv) assert S.commutator(A2, A2).is_subgroup(triv) # examples calculated by hand S = SymmetricGroup(3) A = AlternatingGroup(3) assert S.commutator(A, S).is_subgroup(A) def test_is_nilpotent(): # every abelian group is nilpotent for i in (1, 2, 3): C = CyclicGroup(i) Ab = AbelianGroup(i, i + 2) assert C.is_nilpotent assert Ab.is_nilpotent Ab = AbelianGroup(5, 7, 10) assert Ab.is_nilpotent # A_5 is not solvable and thus not nilpotent assert AlternatingGroup(5).is_nilpotent is False def test_is_trivial(): for i in range(5): triv = PermutationGroup([Permutation(list(range(i)))]) assert triv.is_trivial def test_pointwise_stabilizer(): S = SymmetricGroup(2) stab = S.pointwise_stabilizer([0]) assert stab.generators == [Permutation(1)] S = SymmetricGroup(5) points = [] stab = S for point in (2, 0, 3, 4, 1): stab = stab.stabilizer(point) points.append(point) assert S.pointwise_stabilizer(points).is_subgroup(stab) def test_make_perm(): assert cube.pgroup.make_perm(5, seed=list(range(5))) == \ Permutation([4, 7, 6, 5, 0, 3, 2, 1]) assert cube.pgroup.make_perm(7, seed=list(range(7))) == \ Permutation([6, 7, 3, 2, 5, 4, 0, 1]) def test_elements(): from sympy.sets.sets import FiniteSet p = Permutation(2, 3) assert PermutationGroup(p).elements == {Permutation(3), Permutation(2, 3)} assert FiniteSet(*PermutationGroup(p).elements) \ == FiniteSet(Permutation(2, 3), Permutation(3)) def test_is_group(): assert PermutationGroup(Permutation(1,2), Permutation(2,4)).is_group == True assert SymmetricGroup(4).is_group == True def test_PermutationGroup(): assert PermutationGroup() == PermutationGroup(Permutation()) assert (PermutationGroup() == 0) is False def test_coset_transvesal(): G = AlternatingGroup(5) H = PermutationGroup(Permutation(0,1,2),Permutation(1,2)(3,4)) assert G.coset_transversal(H) == \ [Permutation(4), Permutation(2, 3, 4), Permutation(2, 4, 3), Permutation(1, 2, 4), Permutation(4)(1, 2, 3), Permutation(1, 3)(2, 4), Permutation(0, 1, 2, 3, 4), Permutation(0, 1, 2, 4, 3), Permutation(0, 1, 3, 2, 4), Permutation(0, 2, 4, 1, 3)] def test_coset_table(): G = PermutationGroup(Permutation(0,1,2,3), Permutation(0,1,2), Permutation(0,4,2,7), Permutation(5,6), Permutation(0,7)); H = PermutationGroup(Permutation(0,1,2,3), Permutation(0,7)) assert G.coset_table(H) == \ [[0, 0, 0, 0, 1, 2, 3, 3, 0, 0], [4, 5, 2, 5, 6, 0, 7, 7, 1, 1], [5, 4, 5, 1, 0, 6, 8, 8, 6, 6], [3, 3, 3, 3, 7, 8, 0, 0, 3, 3], [2, 1, 4, 4, 4, 4, 9, 9, 4, 4], [1, 2, 1, 2, 5, 5, 10, 10, 5, 5], [6, 6, 6, 6, 2, 1, 11, 11, 2, 2], [9, 10, 8, 10, 11, 3, 1, 1, 7, 7], [10, 9, 10, 7, 3, 11, 2, 2, 11, 11], [8, 7, 9, 9, 9, 9, 4, 4, 9, 9], [7, 8, 7, 8, 10, 10, 5, 5, 10, 10], [11, 11, 11, 11, 8, 7, 6, 6, 8, 8]] def test_subgroup(): G = PermutationGroup(Permutation(0,1,2), Permutation(0,2,3)) H = G.subgroup([Permutation(0,1,3)]) assert H.is_subgroup(G) def test_generator_product(): G = SymmetricGroup(5) p = Permutation(0, 2, 3)(1, 4) gens = G.generator_product(p) assert all(g in G.strong_gens for g in gens) w = G.identity for g in gens: w = g*w assert w == p def test_sylow_subgroup(): P = PermutationGroup(Permutation(1, 5)(2, 4), Permutation(0, 1, 2, 3, 4, 5)) S = P.sylow_subgroup(2) assert S.order() == 4 P = DihedralGroup(12) S = P.sylow_subgroup(3) assert S.order() == 3 P = PermutationGroup(Permutation(1, 5)(2, 4), Permutation(0, 1, 2, 3, 4, 5), Permutation(0, 2)) S = P.sylow_subgroup(3) assert S.order() == 9 S = P.sylow_subgroup(2) assert S.order() == 8 P = SymmetricGroup(10) S = P.sylow_subgroup(2) assert S.order() == 256 S = P.sylow_subgroup(3) assert S.order() == 81 S = P.sylow_subgroup(5) assert S.order() == 25 # the length of the lower central series # of a p-Sylow subgroup of Sym(n) grows with # the highest exponent exp of p such # that n >= p**exp exp = 1 length = 0 for i in range(2, 9): P = SymmetricGroup(i) S = P.sylow_subgroup(2) ls = S.lower_central_series() if i // 2**exp > 0: # length increases with exponent assert len(ls) > length length = len(ls) exp += 1 else: assert len(ls) == length G = SymmetricGroup(100) S = G.sylow_subgroup(3) assert G.order() % S.order() == 0 assert G.order()/S.order() % 3 > 0 G = AlternatingGroup(100) S = G.sylow_subgroup(2) assert G.order() % S.order() == 0 assert G.order()/S.order() % 2 > 0 G = DihedralGroup(18) S = G.sylow_subgroup(p=2) assert S.order() == 4 G = DihedralGroup(50) S = G.sylow_subgroup(p=2) assert S.order() == 4 @slow def test_presentation(): def _test(P): G = P.presentation() return G.order() == P.order() def _strong_test(P): G = P.strong_presentation() chk = len(G.generators) == len(P.strong_gens) return chk and G.order() == P.order() P = PermutationGroup(Permutation(0,1,5,2)(3,7,4,6), Permutation(0,3,5,4)(1,6,2,7)) assert _test(P) P = AlternatingGroup(5) assert _test(P) P = SymmetricGroup(5) assert _test(P) P = PermutationGroup([Permutation(0,3,1,2), Permutation(3)(0,1), Permutation(0,1)(2,3)]) assert _strong_test(P) P = DihedralGroup(6) assert _strong_test(P) a = Permutation(0,1)(2,3) b = Permutation(0,2)(3,1) c = Permutation(4,5) P = PermutationGroup(c, a, b) assert _strong_test(P) def test_polycyclic(): a = Permutation([0, 1, 2]) b = Permutation([2, 1, 0]) G = PermutationGroup([a, b]) assert G.is_polycyclic == True a = Permutation([1, 2, 3, 4, 0]) b = Permutation([1, 0, 2, 3, 4]) G = PermutationGroup([a, b]) assert G.is_polycyclic == False def test_elementary(): a = Permutation([1, 5, 2, 0, 3, 6, 4]) G = PermutationGroup([a]) assert G.is_elementary(7) == False a = Permutation(0, 1)(2, 3) b = Permutation(0, 2)(3, 1) G = PermutationGroup([a, b]) assert G.is_elementary(2) == True c = Permutation(4, 5, 6) G = PermutationGroup([a, b, c]) assert G.is_elementary(2) == False G = SymmetricGroup(4).sylow_subgroup(2) assert G.is_elementary(2) == False H = AlternatingGroup(4).sylow_subgroup(2) assert H.is_elementary(2) == True def test_perfect(): G = AlternatingGroup(3) assert G.is_perfect == False G = AlternatingGroup(5) assert G.is_perfect == True def test_index(): G = PermutationGroup(Permutation(0,1,2), Permutation(0,2,3)) H = G.subgroup([Permutation(0,1,3)]) assert G.index(H) == 4 def test_cyclic(): G = SymmetricGroup(2) assert G.is_cyclic G = AbelianGroup(3, 7) assert G.is_cyclic G = AbelianGroup(7, 7) assert not G.is_cyclic G = AlternatingGroup(3) assert G.is_cyclic G = AlternatingGroup(4) assert not G.is_cyclic # Order less than 6 G = PermutationGroup(Permutation(0, 1, 2), Permutation(0, 2, 1)) assert G.is_cyclic G = PermutationGroup( Permutation(0, 1, 2, 3), Permutation(0, 2)(1, 3) ) assert G.is_cyclic G = PermutationGroup( Permutation(3), Permutation(0, 1)(2, 3), Permutation(0, 2)(1, 3), Permutation(0, 3)(1, 2) ) assert G.is_cyclic is False # Order 15 G = PermutationGroup( Permutation(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), Permutation(0, 2, 4, 6, 8, 10, 12, 14, 1, 3, 5, 7, 9, 11, 13) ) assert G.is_cyclic # Distinct prime orders assert PermutationGroup._distinct_primes_lemma([3, 5]) is True assert PermutationGroup._distinct_primes_lemma([5, 7]) is True assert PermutationGroup._distinct_primes_lemma([2, 3]) is None assert PermutationGroup._distinct_primes_lemma([3, 5, 7]) is None assert PermutationGroup._distinct_primes_lemma([5, 7, 13]) is True G = PermutationGroup( Permutation(0, 1, 2, 3), Permutation(0, 2)(1, 3)) assert G.is_cyclic assert G._is_abelian def test_abelian_invariants(): G = AbelianGroup(2, 3, 4) assert G.abelian_invariants() == [2, 3, 4] G=PermutationGroup([Permutation(1, 2, 3, 4), Permutation(1, 2), Permutation(5, 6)]) assert G.abelian_invariants() == [2, 2] G = AlternatingGroup(7) assert G.abelian_invariants() == [] G = AlternatingGroup(4) assert G.abelian_invariants() == [3] G = DihedralGroup(4) assert G.abelian_invariants() == [2, 2] G = PermutationGroup([Permutation(1, 2, 3, 4, 5, 6, 7)]) assert G.abelian_invariants() == [7] G = DihedralGroup(12) S = G.sylow_subgroup(3) assert S.abelian_invariants() == [3] G = PermutationGroup(Permutation(0, 1, 2), Permutation(0, 2, 3)) assert G.abelian_invariants() == [3] G = PermutationGroup([Permutation(0, 1), Permutation(0, 2, 4, 6)(1, 3, 5, 7)]) assert G.abelian_invariants() == [2, 4] G = SymmetricGroup(30) S = G.sylow_subgroup(2) assert S.abelian_invariants() == [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] S = G.sylow_subgroup(3) assert S.abelian_invariants() == [3, 3, 3, 3] S = G.sylow_subgroup(5) assert S.abelian_invariants() == [5, 5, 5] def test_composition_series(): a = Permutation(1, 2, 3) b = Permutation(1, 2) G = PermutationGroup([a, b]) comp_series = G.composition_series() assert comp_series == G.derived_series() # The first group in the composition series is always the group itself and # the last group in the series is the trivial group. S = SymmetricGroup(4) assert S.composition_series()[0] == S assert len(S.composition_series()) == 5 A = AlternatingGroup(4) assert A.composition_series()[0] == A assert len(A.composition_series()) == 4 # the composition series for C_8 is C_8 > C_4 > C_2 > triv G = CyclicGroup(8) series = G.composition_series() assert is_isomorphic(series[1], CyclicGroup(4)) assert is_isomorphic(series[2], CyclicGroup(2)) assert series[3].is_trivial def test_is_symmetric(): a = Permutation(0, 1, 2) b = Permutation(0, 1, size=3) assert PermutationGroup(a, b).is_symmetric == True a = Permutation(0, 2, 1) b = Permutation(1, 2, size=3) assert PermutationGroup(a, b).is_symmetric == True a = Permutation(0, 1, 2, 3) b = Permutation(0, 3)(1, 2) assert PermutationGroup(a, b).is_symmetric == False def test_conjugacy_class(): S = SymmetricGroup(4) x = Permutation(1, 2, 3) C = {Permutation(0, 1, 2, size = 4), Permutation(0, 1, 3), Permutation(0, 2, 1, size = 4), Permutation(0, 2, 3), Permutation(0, 3, 1), Permutation(0, 3, 2), Permutation(1, 2, 3), Permutation(1, 3, 2)} assert S.conjugacy_class(x) == C def test_conjugacy_classes(): S = SymmetricGroup(3) expected = [{Permutation(size = 3)}, {Permutation(0, 1, size = 3), Permutation(0, 2), Permutation(1, 2)}, {Permutation(0, 1, 2), Permutation(0, 2, 1)}] computed = S.conjugacy_classes() assert len(expected) == len(computed) assert all(e in computed for e in expected) def test_coset_class(): a = Permutation(1, 2) b = Permutation(0, 1) G = PermutationGroup([a, b]) #Creating right coset rht_coset = G*a #Checking whether it is left coset or right coset assert rht_coset.is_right_coset assert not rht_coset.is_left_coset #Creating list representation of coset list_repr = rht_coset.as_list() expected = [Permutation(0, 2), Permutation(0, 2, 1), Permutation(1, 2), Permutation(2), Permutation(2)(0, 1), Permutation(0, 1, 2)] for ele in list_repr: assert ele in expected #Creating left coset left_coset = a*G #Checking whether it is left coset or right coset assert not left_coset.is_right_coset assert left_coset.is_left_coset #Creating list representation of Coset list_repr = left_coset.as_list() expected = [Permutation(2)(0, 1), Permutation(0, 1, 2), Permutation(1, 2), Permutation(2), Permutation(0, 2), Permutation(0, 2, 1)] for ele in list_repr: assert ele in expected G = PermutationGroup(Permutation(1, 2, 3, 4), Permutation(2, 3, 4)) H = PermutationGroup(Permutation(1, 2, 3, 4)) g = Permutation(1, 3)(2, 4) rht_coset = Coset(g, H, G, dir='+') assert rht_coset.is_right_coset list_repr = rht_coset.as_list() expected = [Permutation(1, 2, 3, 4), Permutation(4), Permutation(1, 3)(2, 4), Permutation(1, 4, 3, 2)] for ele in list_repr: assert ele in expected def test_symmetricpermutationgroup(): a = SymmetricPermutationGroup(5) assert a.degree == 5 assert a.order() == 120 assert a.identity() == Permutation(4) sympy-sympy-1.9/sympy/combinatorics/tests/test_permutations.py000066400000000000000000000473471412543434000252640ustar00rootroot00000000000000from itertools import permutations from sympy.core.expr import unchanged from sympy.core.numbers import Integer from sympy.core.relational import Eq from sympy.core.symbol import Symbol from sympy.core.singleton import S from sympy.combinatorics.permutations import \ Permutation, _af_parity, _af_rmul, _af_rmuln, AppliedPermutation, Cycle from sympy.printing import sstr, srepr, pretty, latex from sympy.testing.pytest import raises, warns_deprecated_sympy rmul = Permutation.rmul a = Symbol('a', integer=True) def test_Permutation(): # don't auto fill 0 raises(ValueError, lambda: Permutation([1])) p = Permutation([0, 1, 2, 3]) # call as bijective assert [p(i) for i in range(p.size)] == list(p) # call as operator assert p(list(range(p.size))) == list(p) # call as function assert list(p(1, 2)) == [0, 2, 1, 3] raises(TypeError, lambda: p(-1)) raises(TypeError, lambda: p(5)) # conversion to list assert list(p) == list(range(4)) assert Permutation(size=4) == Permutation(3) assert Permutation(Permutation(3), size=5) == Permutation(4) # cycle form with size assert Permutation([[1, 2]], size=4) == Permutation([[1, 2], [0], [3]]) # random generation assert Permutation.random(2) in (Permutation([1, 0]), Permutation([0, 1])) p = Permutation([2, 5, 1, 6, 3, 0, 4]) q = Permutation([[1], [0, 3, 5, 6, 2, 4]]) assert len({p, p}) == 1 r = Permutation([1, 3, 2, 0, 4, 6, 5]) ans = Permutation(_af_rmuln(*[w.array_form for w in (p, q, r)])).array_form assert rmul(p, q, r).array_form == ans # make sure no other permutation of p, q, r could have given # that answer for a, b, c in permutations((p, q, r)): if (a, b, c) == (p, q, r): continue assert rmul(a, b, c).array_form != ans assert p.support() == list(range(7)) assert q.support() == [0, 2, 3, 4, 5, 6] assert Permutation(p.cyclic_form).array_form == p.array_form assert p.cardinality == 5040 assert q.cardinality == 5040 assert q.cycles == 2 assert rmul(q, p) == Permutation([4, 6, 1, 2, 5, 3, 0]) assert rmul(p, q) == Permutation([6, 5, 3, 0, 2, 4, 1]) assert _af_rmul(p.array_form, q.array_form) == \ [6, 5, 3, 0, 2, 4, 1] assert rmul(Permutation([[1, 2, 3], [0, 4]]), Permutation([[1, 2, 4], [0], [3]])).cyclic_form == \ [[0, 4, 2], [1, 3]] assert q.array_form == [3, 1, 4, 5, 0, 6, 2] assert q.cyclic_form == [[0, 3, 5, 6, 2, 4]] assert q.full_cyclic_form == [[0, 3, 5, 6, 2, 4], [1]] assert p.cyclic_form == [[0, 2, 1, 5], [3, 6, 4]] t = p.transpositions() assert t == [(0, 5), (0, 1), (0, 2), (3, 4), (3, 6)] assert Permutation.rmul(*[Permutation(Cycle(*ti)) for ti in (t)]) assert Permutation([1, 0]).transpositions() == [(0, 1)] assert p**13 == p assert q**0 == Permutation(list(range(q.size))) assert q**-2 == ~q**2 assert q**2 == Permutation([5, 1, 0, 6, 3, 2, 4]) assert q**3 == q**2*q assert q**4 == q**2*q**2 a = Permutation(1, 3) b = Permutation(2, 0, 3) I = Permutation(3) assert ~a == a**-1 assert a*~a == I assert a*b**-1 == a*~b ans = Permutation(0, 5, 3, 1, 6)(2, 4) assert (p + q.rank()).rank() == ans.rank() assert (p + q.rank())._rank == ans.rank() assert (q + p.rank()).rank() == ans.rank() raises(TypeError, lambda: p + Permutation(list(range(10)))) assert (p - q.rank()).rank() == Permutation(0, 6, 3, 1, 2, 5, 4).rank() assert p.rank() - q.rank() < 0 # for coverage: make sure mod is used assert (q - p.rank()).rank() == Permutation(1, 4, 6, 2)(3, 5).rank() assert p*q == Permutation(_af_rmuln(*[list(w) for w in (q, p)])) assert p*Permutation([]) == p assert Permutation([])*p == p assert p*Permutation([[0, 1]]) == Permutation([2, 5, 0, 6, 3, 1, 4]) assert Permutation([[0, 1]])*p == Permutation([5, 2, 1, 6, 3, 0, 4]) pq = p ^ q assert pq == Permutation([5, 6, 0, 4, 1, 2, 3]) assert pq == rmul(q, p, ~q) qp = q ^ p assert qp == Permutation([4, 3, 6, 2, 1, 5, 0]) assert qp == rmul(p, q, ~p) raises(ValueError, lambda: p ^ Permutation([])) assert p.commutator(q) == Permutation(0, 1, 3, 4, 6, 5, 2) assert q.commutator(p) == Permutation(0, 2, 5, 6, 4, 3, 1) assert p.commutator(q) == ~q.commutator(p) raises(ValueError, lambda: p.commutator(Permutation([]))) assert len(p.atoms()) == 7 assert q.atoms() == {0, 1, 2, 3, 4, 5, 6} assert p.inversion_vector() == [2, 4, 1, 3, 1, 0] assert q.inversion_vector() == [3, 1, 2, 2, 0, 1] assert Permutation.from_inversion_vector(p.inversion_vector()) == p assert Permutation.from_inversion_vector(q.inversion_vector()).array_form\ == q.array_form raises(ValueError, lambda: Permutation.from_inversion_vector([0, 2])) assert Permutation([i for i in range(500, -1, -1)]).inversions() == 125250 s = Permutation([0, 4, 1, 3, 2]) assert s.parity() == 0 _ = s.cyclic_form # needed to create a value for _cyclic_form assert len(s._cyclic_form) != s.size and s.parity() == 0 assert not s.is_odd assert s.is_even assert Permutation([0, 1, 4, 3, 2]).parity() == 1 assert _af_parity([0, 4, 1, 3, 2]) == 0 assert _af_parity([0, 1, 4, 3, 2]) == 1 s = Permutation([0]) assert s.is_Singleton assert Permutation([]).is_Empty r = Permutation([3, 2, 1, 0]) assert (r**2).is_Identity assert rmul(~p, p).is_Identity assert (~p)**13 == Permutation([5, 2, 0, 4, 6, 1, 3]) assert ~(r**2).is_Identity assert p.max() == 6 assert p.min() == 0 q = Permutation([[6], [5], [0, 1, 2, 3, 4]]) assert q.max() == 4 assert q.min() == 0 p = Permutation([1, 5, 2, 0, 3, 6, 4]) q = Permutation([[1, 2, 3, 5, 6], [0, 4]]) assert p.ascents() == [0, 3, 4] assert q.ascents() == [1, 2, 4] assert r.ascents() == [] assert p.descents() == [1, 2, 5] assert q.descents() == [0, 3, 5] assert Permutation(r.descents()).is_Identity assert p.inversions() == 7 # test the merge-sort with a longer permutation big = list(p) + list(range(p.max() + 1, p.max() + 130)) assert Permutation(big).inversions() == 7 assert p.signature() == -1 assert q.inversions() == 11 assert q.signature() == -1 assert rmul(p, ~p).inversions() == 0 assert rmul(p, ~p).signature() == 1 assert p.order() == 6 assert q.order() == 10 assert (p**(p.order())).is_Identity assert p.length() == 6 assert q.length() == 7 assert r.length() == 4 assert p.runs() == [[1, 5], [2], [0, 3, 6], [4]] assert q.runs() == [[4], [2, 3, 5], [0, 6], [1]] assert r.runs() == [[3], [2], [1], [0]] assert p.index() == 8 assert q.index() == 8 assert r.index() == 3 assert p.get_precedence_distance(q) == q.get_precedence_distance(p) assert p.get_adjacency_distance(q) == p.get_adjacency_distance(q) assert p.get_positional_distance(q) == p.get_positional_distance(q) p = Permutation([0, 1, 2, 3]) q = Permutation([3, 2, 1, 0]) assert p.get_precedence_distance(q) == 6 assert p.get_adjacency_distance(q) == 3 assert p.get_positional_distance(q) == 8 p = Permutation([0, 3, 1, 2, 4]) q = Permutation.josephus(4, 5, 2) assert p.get_adjacency_distance(q) == 3 raises(ValueError, lambda: p.get_adjacency_distance(Permutation([]))) raises(ValueError, lambda: p.get_positional_distance(Permutation([]))) raises(ValueError, lambda: p.get_precedence_distance(Permutation([]))) a = [Permutation.unrank_nonlex(4, i) for i in range(5)] iden = Permutation([0, 1, 2, 3]) for i in range(5): for j in range(i + 1, 5): assert a[i].commutes_with(a[j]) == \ (rmul(a[i], a[j]) == rmul(a[j], a[i])) if a[i].commutes_with(a[j]): assert a[i].commutator(a[j]) == iden assert a[j].commutator(a[i]) == iden a = Permutation(3) b = Permutation(0, 6, 3)(1, 2) assert a.cycle_structure == {1: 4} assert b.cycle_structure == {2: 1, 3: 1, 1: 2} # issue 11130 raises(ValueError, lambda: Permutation(3, size=3)) raises(ValueError, lambda: Permutation([1, 2, 0, 3], size=3)) def test_Permutation_subclassing(): # Subclass that adds permutation application on iterables class CustomPermutation(Permutation): def __call__(self, *i): try: return super().__call__(*i) except TypeError: pass try: perm_obj = i[0] return [self._array_form[j] for j in perm_obj] except TypeError: raise TypeError('unrecognized argument') def __eq__(self, other): if isinstance(other, Permutation): return self._hashable_content() == other._hashable_content() else: return super().__eq__(other) def __hash__(self): return super().__hash__() p = CustomPermutation([1, 2, 3, 0]) q = Permutation([1, 2, 3, 0]) assert p == q raises(TypeError, lambda: q([1, 2])) assert [2, 3] == p([1, 2]) assert type(p * q) == CustomPermutation assert type(q * p) == Permutation # True because q.__mul__(p) is called! # Run all tests for the Permutation class also on the subclass def wrapped_test_Permutation(): # Monkeypatch the class definition in the globals globals()['__Perm'] = globals()['Permutation'] globals()['Permutation'] = CustomPermutation test_Permutation() globals()['Permutation'] = globals()['__Perm'] # Restore del globals()['__Perm'] wrapped_test_Permutation() def test_josephus(): assert Permutation.josephus(4, 6, 1) == Permutation([3, 1, 0, 2, 5, 4]) assert Permutation.josephus(1, 5, 1).is_Identity def test_ranking(): assert Permutation.unrank_lex(5, 10).rank() == 10 p = Permutation.unrank_lex(15, 225) assert p.rank() == 225 p1 = p.next_lex() assert p1.rank() == 226 assert Permutation.unrank_lex(15, 225).rank() == 225 assert Permutation.unrank_lex(10, 0).is_Identity p = Permutation.unrank_lex(4, 23) assert p.rank() == 23 assert p.array_form == [3, 2, 1, 0] assert p.next_lex() is None p = Permutation([1, 5, 2, 0, 3, 6, 4]) q = Permutation([[1, 2, 3, 5, 6], [0, 4]]) a = [Permutation.unrank_trotterjohnson(4, i).array_form for i in range(5)] assert a == [[0, 1, 2, 3], [0, 1, 3, 2], [0, 3, 1, 2], [3, 0, 1, 2], [3, 0, 2, 1] ] assert [Permutation(pa).rank_trotterjohnson() for pa in a] == list(range(5)) assert Permutation([0, 1, 2, 3]).next_trotterjohnson() == \ Permutation([0, 1, 3, 2]) assert q.rank_trotterjohnson() == 2283 assert p.rank_trotterjohnson() == 3389 assert Permutation([1, 0]).rank_trotterjohnson() == 1 a = Permutation(list(range(3))) b = a l = [] tj = [] for i in range(6): l.append(a) tj.append(b) a = a.next_lex() b = b.next_trotterjohnson() assert a == b is None assert {tuple(a) for a in l} == {tuple(a) for a in tj} p = Permutation([2, 5, 1, 6, 3, 0, 4]) q = Permutation([[6], [5], [0, 1, 2, 3, 4]]) assert p.rank() == 1964 assert q.rank() == 870 assert Permutation([]).rank_nonlex() == 0 prank = p.rank_nonlex() assert prank == 1600 assert Permutation.unrank_nonlex(7, 1600) == p qrank = q.rank_nonlex() assert qrank == 41 assert Permutation.unrank_nonlex(7, 41) == Permutation(q.array_form) a = [Permutation.unrank_nonlex(4, i).array_form for i in range(24)] assert a == [ [1, 2, 3, 0], [3, 2, 0, 1], [1, 3, 0, 2], [1, 2, 0, 3], [2, 3, 1, 0], [2, 0, 3, 1], [3, 0, 1, 2], [2, 0, 1, 3], [1, 3, 2, 0], [3, 0, 2, 1], [1, 0, 3, 2], [1, 0, 2, 3], [2, 1, 3, 0], [2, 3, 0, 1], [3, 1, 0, 2], [2, 1, 0, 3], [3, 2, 1, 0], [0, 2, 3, 1], [0, 3, 1, 2], [0, 2, 1, 3], [3, 1, 2, 0], [0, 3, 2, 1], [0, 1, 3, 2], [0, 1, 2, 3]] N = 10 p1 = Permutation(a[0]) for i in range(1, N+1): p1 = p1*Permutation(a[i]) p2 = Permutation.rmul_with_af(*[Permutation(h) for h in a[N::-1]]) assert p1 == p2 ok = [] p = Permutation([1, 0]) for i in range(3): ok.append(p.array_form) p = p.next_nonlex() if p is None: ok.append(None) break assert ok == [[1, 0], [0, 1], None] assert Permutation([3, 2, 0, 1]).next_nonlex() == Permutation([1, 3, 0, 2]) assert [Permutation(pa).rank_nonlex() for pa in a] == list(range(24)) def test_mul(): a, b = [0, 2, 1, 3], [0, 1, 3, 2] assert _af_rmul(a, b) == [0, 2, 3, 1] assert _af_rmuln(a, b, list(range(4))) == [0, 2, 3, 1] assert rmul(Permutation(a), Permutation(b)).array_form == [0, 2, 3, 1] a = Permutation([0, 2, 1, 3]) b = (0, 1, 3, 2) c = (3, 1, 2, 0) assert Permutation.rmul(a, b, c) == Permutation([1, 2, 3, 0]) assert Permutation.rmul(a, c) == Permutation([3, 2, 1, 0]) raises(TypeError, lambda: Permutation.rmul(b, c)) n = 6 m = 8 a = [Permutation.unrank_nonlex(n, i).array_form for i in range(m)] h = list(range(n)) for i in range(m): h = _af_rmul(h, a[i]) h2 = _af_rmuln(*a[:i + 1]) assert h == h2 def test_args(): p = Permutation([(0, 3, 1, 2), (4, 5)]) assert p._cyclic_form is None assert Permutation(p) == p assert p.cyclic_form == [[0, 3, 1, 2], [4, 5]] assert p._array_form == [3, 2, 0, 1, 5, 4] p = Permutation((0, 3, 1, 2)) assert p._cyclic_form is None assert p._array_form == [0, 3, 1, 2] assert Permutation([0]) == Permutation((0, )) assert Permutation([[0], [1]]) == Permutation(((0, ), (1, ))) == \ Permutation(((0, ), [1])) assert Permutation([[1, 2]]) == Permutation([0, 2, 1]) assert Permutation([[1], [4, 2]]) == Permutation([0, 1, 4, 3, 2]) assert Permutation([[1], [4, 2]], size=1) == Permutation([0, 1, 4, 3, 2]) assert Permutation( [[1], [4, 2]], size=6) == Permutation([0, 1, 4, 3, 2, 5]) assert Permutation([[0, 1], [0, 2]]) == Permutation(0, 1, 2) assert Permutation([], size=3) == Permutation([0, 1, 2]) assert Permutation(3).list(5) == [0, 1, 2, 3, 4] assert Permutation(3).list(-1) == [] assert Permutation(5)(1, 2).list(-1) == [0, 2, 1] assert Permutation(5)(1, 2).list() == [0, 2, 1, 3, 4, 5] raises(ValueError, lambda: Permutation([1, 2], [0])) # enclosing brackets needed raises(ValueError, lambda: Permutation([[1, 2], 0])) # enclosing brackets needed on 0 raises(ValueError, lambda: Permutation([1, 1, 0])) raises(ValueError, lambda: Permutation([4, 5], size=10)) # where are 0-3? # but this is ok because cycles imply that only those listed moved assert Permutation(4, 5) == Permutation([0, 1, 2, 3, 5, 4]) def test_Cycle(): assert str(Cycle()) == '()' assert Cycle(Cycle(1,2)) == Cycle(1, 2) assert Cycle(1,2).copy() == Cycle(1,2) assert list(Cycle(1, 3, 2)) == [0, 3, 1, 2] assert Cycle(1, 2)(2, 3) == Cycle(1, 3, 2) assert Cycle(1, 2)(2, 3)(4, 5) == Cycle(1, 3, 2)(4, 5) assert Permutation(Cycle(1, 2)(2, 1, 0, 3)).cyclic_form, Cycle(0, 2, 1) raises(ValueError, lambda: Cycle().list()) assert Cycle(1, 2).list() == [0, 2, 1] assert Cycle(1, 2).list(4) == [0, 2, 1, 3] assert Cycle(3).list(2) == [0, 1] assert Cycle(3).list(6) == [0, 1, 2, 3, 4, 5] assert Permutation(Cycle(1, 2), size=4) == \ Permutation([0, 2, 1, 3]) assert str(Cycle(1, 2)(4, 5)) == '(1 2)(4 5)' assert str(Cycle(1, 2)) == '(1 2)' assert Cycle(Permutation(list(range(3)))) == Cycle() assert Cycle(1, 2).list() == [0, 2, 1] assert Cycle(1, 2).list(4) == [0, 2, 1, 3] assert Cycle().size == 0 raises(ValueError, lambda: Cycle((1, 2))) raises(ValueError, lambda: Cycle(1, 2, 1)) raises(TypeError, lambda: Cycle(1, 2)*{}) raises(ValueError, lambda: Cycle(4)[a]) raises(ValueError, lambda: Cycle(2, -4, 3)) # check round-trip p = Permutation([[1, 2], [4, 3]], size=5) assert Permutation(Cycle(p)) == p def test_from_sequence(): assert Permutation.from_sequence('SymPy') == Permutation(4)(0, 1, 3) assert Permutation.from_sequence('SymPy', key=lambda x: x.lower()) == \ Permutation(4)(0, 2)(1, 3) def test_resize(): p = Permutation(0, 1, 2) assert p.resize(5) == Permutation(0, 1, 2, size=5) assert p.resize(4) == Permutation(0, 1, 2, size=4) assert p.resize(3) == p raises(ValueError, lambda: p.resize(2)) p = Permutation(0, 1, 2)(3, 4)(5, 6) assert p.resize(3) == Permutation(0, 1, 2) raises(ValueError, lambda: p.resize(4)) def test_printing_cyclic(): p1 = Permutation([0, 2, 1]) assert repr(p1) == 'Permutation(1, 2)' assert str(p1) == '(1 2)' p2 = Permutation() assert repr(p2) == 'Permutation()' assert str(p2) == '()' p3 = Permutation([1, 2, 0, 3]) assert repr(p3) == 'Permutation(3)(0, 1, 2)' def test_printing_non_cyclic(): from sympy.printing import sstr, srepr p1 = Permutation([0, 1, 2, 3, 4, 5]) assert srepr(p1, perm_cyclic=False) == 'Permutation([], size=6)' assert sstr(p1, perm_cyclic=False) == 'Permutation([], size=6)' p2 = Permutation([0, 1, 2]) assert srepr(p2, perm_cyclic=False) == 'Permutation([0, 1, 2])' assert sstr(p2, perm_cyclic=False) == 'Permutation([0, 1, 2])' p3 = Permutation([0, 2, 1]) assert srepr(p3, perm_cyclic=False) == 'Permutation([0, 2, 1])' assert sstr(p3, perm_cyclic=False) == 'Permutation([0, 2, 1])' p4 = Permutation([0, 1, 3, 2, 4, 5, 6, 7]) assert srepr(p4, perm_cyclic=False) == 'Permutation([0, 1, 3, 2], size=8)' def test_deprecated_print_cyclic(): p = Permutation(0, 1, 2) try: Permutation.print_cyclic = True with warns_deprecated_sympy(): assert sstr(p) == '(0 1 2)' with warns_deprecated_sympy(): assert srepr(p) == 'Permutation(0, 1, 2)' with warns_deprecated_sympy(): assert pretty(p) == '(0 1 2)' with warns_deprecated_sympy(): assert latex(p) == r'\left( 0\; 1\; 2\right)' Permutation.print_cyclic = False with warns_deprecated_sympy(): assert sstr(p) == 'Permutation([1, 2, 0])' with warns_deprecated_sympy(): assert srepr(p) == 'Permutation([1, 2, 0])' with warns_deprecated_sympy(): assert pretty(p, use_unicode=False) == '/0 1 2\\\n\\1 2 0/' with warns_deprecated_sympy(): assert latex(p) == \ r'\begin{pmatrix} 0 & 1 & 2 \\ 1 & 2 & 0 \end{pmatrix}' finally: Permutation.print_cyclic = None def test_permutation_equality(): a = Permutation(0, 1, 2) b = Permutation(0, 1, 2) assert Eq(a, b) is S.true c = Permutation(0, 2, 1) assert Eq(a, c) is S.false d = Permutation(0, 1, 2, size=4) assert unchanged(Eq, a, d) e = Permutation(0, 2, 1, size=4) assert unchanged(Eq, a, e) i = Permutation() assert unchanged(Eq, i, 0) assert unchanged(Eq, 0, i) def test_issue_17661(): c1 = Cycle(1,2) c2 = Cycle(1,2) assert c1 == c2 assert repr(c1) == 'Cycle(1, 2)' assert c1 == c2 def test_permutation_apply(): x = Symbol('x') p = Permutation(0, 1, 2) assert p.apply(0) == 1 assert isinstance(p.apply(0), Integer) assert p.apply(x) == AppliedPermutation(p, x) assert AppliedPermutation(p, x).subs(x, 0) == 1 x = Symbol('x', integer=False) raises(NotImplementedError, lambda: p.apply(x)) x = Symbol('x', negative=True) raises(NotImplementedError, lambda: p.apply(x)) def test_AppliedPermutation(): x = Symbol('x') p = Permutation(0, 1, 2) raises(ValueError, lambda: AppliedPermutation((0, 1, 2), x)) assert AppliedPermutation(p, 1, evaluate=True) == 2 assert AppliedPermutation(p, 1, evaluate=False).__class__ == \ AppliedPermutation sympy-sympy-1.9/sympy/combinatorics/tests/test_polyhedron.py000066400000000000000000000101711412543434000246760ustar00rootroot00000000000000from sympy import symbols, FiniteSet from sympy.combinatorics.polyhedron import (Polyhedron, tetrahedron, cube as square, octahedron, dodecahedron, icosahedron, cube_faces) from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.perm_groups import PermutationGroup from sympy.testing.pytest import raises rmul = Permutation.rmul def test_polyhedron(): raises(ValueError, lambda: Polyhedron(list('ab'), pgroup=[Permutation([0])])) pgroup = [Permutation([[0, 7, 2, 5], [6, 1, 4, 3]]), Permutation([[0, 7, 1, 6], [5, 2, 4, 3]]), Permutation([[3, 6, 0, 5], [4, 1, 7, 2]]), Permutation([[7, 4, 5], [1, 3, 0], [2], [6]]), Permutation([[1, 3, 2], [7, 6, 5], [4], [0]]), Permutation([[4, 7, 6], [2, 0, 3], [1], [5]]), Permutation([[1, 2, 0], [4, 5, 6], [3], [7]]), Permutation([[4, 2], [0, 6], [3, 7], [1, 5]]), Permutation([[3, 5], [7, 1], [2, 6], [0, 4]]), Permutation([[2, 5], [1, 6], [0, 4], [3, 7]]), Permutation([[4, 3], [7, 0], [5, 1], [6, 2]]), Permutation([[4, 1], [0, 5], [6, 2], [7, 3]]), Permutation([[7, 2], [3, 6], [0, 4], [1, 5]]), Permutation([0, 1, 2, 3, 4, 5, 6, 7])] corners = tuple(symbols('A:H')) faces = cube_faces cube = Polyhedron(corners, faces, pgroup) assert cube.edges == FiniteSet(*( (0, 1), (6, 7), (1, 2), (5, 6), (0, 3), (2, 3), (4, 7), (4, 5), (3, 7), (1, 5), (0, 4), (2, 6))) for i in range(3): # add 180 degree face rotations cube.rotate(cube.pgroup[i]**2) assert cube.corners == corners for i in range(3, 7): # add 240 degree axial corner rotations cube.rotate(cube.pgroup[i]**2) assert cube.corners == corners cube.rotate(1) raises(ValueError, lambda: cube.rotate(Permutation([0, 1]))) assert cube.corners != corners assert cube.array_form == [7, 6, 4, 5, 3, 2, 0, 1] assert cube.cyclic_form == [[0, 7, 1, 6], [2, 4, 3, 5]] cube.reset() assert cube.corners == corners def check(h, size, rpt, target): assert len(h.faces) + len(h.vertices) - len(h.edges) == 2 assert h.size == size got = set() for p in h.pgroup: # make sure it restores original P = h.copy() hit = P.corners for i in range(rpt): P.rotate(p) if P.corners == hit: break else: print('error in permutation', p.array_form) for i in range(rpt): P.rotate(p) got.add(tuple(P.corners)) c = P.corners f = [[c[i] for i in f] for f in P.faces] assert h.faces == Polyhedron(c, f).faces assert len(got) == target assert PermutationGroup([Permutation(g) for g in got]).is_group for h, size, rpt, target in zip( (tetrahedron, square, octahedron, dodecahedron, icosahedron), (4, 8, 6, 20, 12), (3, 4, 4, 5, 5), (12, 24, 24, 60, 60)): check(h, size, rpt, target) def test_pgroups(): from sympy.combinatorics.polyhedron import (tetrahedron, cube, octahedron, dodecahedron, icosahedron, tetrahedron_faces, cube_faces, octahedron_faces, dodecahedron_faces, icosahedron_faces) from sympy.combinatorics.polyhedron import _pgroup_calcs (tetrahedron2, cube2, octahedron2, dodecahedron2, icosahedron2, tetrahedron_faces2, cube_faces2, octahedron_faces2, dodecahedron_faces2, icosahedron_faces2) = _pgroup_calcs() assert tetrahedron == tetrahedron2 assert cube == cube2 assert octahedron == octahedron2 assert dodecahedron == dodecahedron2 assert icosahedron == icosahedron2 assert sorted(map(sorted, tetrahedron_faces)) == sorted(map(sorted, tetrahedron_faces2)) assert sorted(cube_faces) == sorted(cube_faces2) assert sorted(octahedron_faces) == sorted(octahedron_faces2) assert sorted(dodecahedron_faces) == sorted(dodecahedron_faces2) assert sorted(icosahedron_faces) == sorted(icosahedron_faces2) sympy-sympy-1.9/sympy/combinatorics/tests/test_prufer.py000066400000000000000000000051311412543434000240160ustar00rootroot00000000000000from sympy.combinatorics.prufer import Prufer from sympy.testing.pytest import raises def test_prufer(): # number of nodes is optional assert Prufer([[0, 1], [0, 2], [0, 3], [0, 4]], 5).nodes == 5 assert Prufer([[0, 1], [0, 2], [0, 3], [0, 4]]).nodes == 5 a = Prufer([[0, 1], [0, 2], [0, 3], [0, 4]]) assert a.rank == 0 assert a.nodes == 5 assert a.prufer_repr == [0, 0, 0] a = Prufer([[2, 4], [1, 4], [1, 3], [0, 5], [0, 4]]) assert a.rank == 924 assert a.nodes == 6 assert a.tree_repr == [[2, 4], [1, 4], [1, 3], [0, 5], [0, 4]] assert a.prufer_repr == [4, 1, 4, 0] assert Prufer.edges([0, 1, 2, 3], [1, 4, 5], [1, 4, 6]) == \ ([[0, 1], [1, 2], [1, 4], [2, 3], [4, 5], [4, 6]], 7) assert Prufer([0]*4).size == Prufer([6]*4).size == 1296 # accept iterables but convert to list of lists tree = [(0, 1), (1, 5), (0, 3), (0, 2), (2, 6), (4, 7), (2, 4)] tree_lists = [list(t) for t in tree] assert Prufer(tree).tree_repr == tree_lists assert sorted(Prufer(set(tree)).tree_repr) == sorted(tree_lists) raises(ValueError, lambda: Prufer([[1, 2], [3, 4]])) # 0 is missing raises(ValueError, lambda: Prufer([[2, 3], [3, 4]])) # 0, 1 are missing assert Prufer(*Prufer.edges([1, 2], [3, 4])).prufer_repr == [1, 3] raises(ValueError, lambda: Prufer.edges( [1, 3], [3, 4])) # a broken tree but edges doesn't care raises(ValueError, lambda: Prufer.edges([1, 2], [5, 6])) raises(ValueError, lambda: Prufer([[]])) a = Prufer([[0, 1], [0, 2], [0, 3]]) b = a.next() assert b.tree_repr == [[0, 2], [0, 1], [1, 3]] assert b.rank == 1 def test_round_trip(): def doit(t, b): e, n = Prufer.edges(*t) t = Prufer(e, n) a = sorted(t.tree_repr) b = [i - 1 for i in b] assert t.prufer_repr == b assert sorted(Prufer(b).tree_repr) == a assert Prufer.unrank(t.rank, n).prufer_repr == b doit([[1, 2]], []) doit([[2, 1, 3]], [1]) doit([[1, 3, 2]], [3]) doit([[1, 2, 3]], [2]) doit([[2, 1, 4], [1, 3]], [1, 1]) doit([[3, 2, 1, 4]], [2, 1]) doit([[3, 2, 1], [2, 4]], [2, 2]) doit([[1, 3, 2, 4]], [3, 2]) doit([[1, 4, 2, 3]], [4, 2]) doit([[3, 1, 4, 2]], [4, 1]) doit([[4, 2, 1, 3]], [1, 2]) doit([[1, 2, 4, 3]], [2, 4]) doit([[1, 3, 4, 2]], [3, 4]) doit([[2, 4, 1], [4, 3]], [4, 4]) doit([[1, 2, 3, 4]], [2, 3]) doit([[2, 3, 1], [3, 4]], [3, 3]) doit([[1, 4, 3, 2]], [4, 3]) doit([[2, 1, 4, 3]], [1, 4]) doit([[2, 1, 3, 4]], [1, 3]) doit([[6, 2, 1, 4], [1, 3, 5, 8], [3, 7]], [1, 2, 1, 3, 3, 5]) sympy-sympy-1.9/sympy/combinatorics/tests/test_rewriting.py000066400000000000000000000033731412543434000245330ustar00rootroot00000000000000from sympy.combinatorics.fp_groups import FpGroup from sympy.combinatorics.free_groups import free_group from sympy.testing.pytest import raises def test_rewriting(): F, a, b = free_group("a, b") G = FpGroup(F, [a*b*a**-1*b**-1]) a, b = G.generators R = G._rewriting_system assert R.is_confluent assert G.reduce(b**-1*a) == a*b**-1 assert G.reduce(b**3*a**4*b**-2*a) == a**5*b assert G.equals(b**2*a**-1*b, b**4*a**-1*b**-1) assert R.reduce_using_automaton(b*a*a**2*b**-1) == a**3 assert R.reduce_using_automaton(b**3*a**4*b**-2*a) == a**5*b assert R.reduce_using_automaton(b**-1*a) == a*b**-1 G = FpGroup(F, [a**3, b**3, (a*b)**2]) R = G._rewriting_system R.make_confluent() # R._is_confluent should be set to True after # a successful run of make_confluent assert R.is_confluent # but also the system should actually be confluent assert R._check_confluence() assert G.reduce(b*a**-1*b**-1*a**3*b**4*a**-1*b**-15) == a**-1*b**-1 # check for automaton reduction assert R.reduce_using_automaton(b*a**-1*b**-1*a**3*b**4*a**-1*b**-15) == a**-1*b**-1 G = FpGroup(F, [a**2, b**3, (a*b)**4]) R = G._rewriting_system assert G.reduce(a**2*b**-2*a**2*b) == b**-1 assert R.reduce_using_automaton(a**2*b**-2*a**2*b) == b**-1 assert G.reduce(a**3*b**-2*a**2*b) == a**-1*b**-1 assert R.reduce_using_automaton(a**3*b**-2*a**2*b) == a**-1*b**-1 # Check after adding a rule R.add_rule(a**2, b) assert R.reduce_using_automaton(a**2*b**-2*a**2*b) == b**-1 assert R.reduce_using_automaton(a**4*b**-2*a**2*b**3) == b R.set_max(15) raises(RuntimeError, lambda: R.add_rule(a**-3, b)) R.set_max(20) R.add_rule(a**-3, b) assert R.add_rule(a, a) == set() sympy-sympy-1.9/sympy/combinatorics/tests/test_schur_number.py000066400000000000000000000032731412543434000252140ustar00rootroot00000000000000from sympy.core import S, Rational from sympy.combinatorics.schur_number import schur_partition, SchurNumber from sympy.testing.randtest import _randint from sympy.testing.pytest import raises from sympy.core.symbol import symbols def _sum_free_test(subset): """ Checks if subset is sum-free(There are no x,y,z in the subset such that x + y = z) """ for i in subset: for j in subset: assert (i + j in subset) is False def test_schur_partition(): raises(ValueError, lambda: schur_partition(S.Infinity)) raises(ValueError, lambda: schur_partition(-1)) raises(ValueError, lambda: schur_partition(0)) assert schur_partition(2) == [[1, 2]] random_number_generator = _randint(1000) for _ in range(5): n = random_number_generator(1, 1000) result = schur_partition(n) t = 0 numbers = [] for item in result: _sum_free_test(item) """ Checks if the occurance of all numbers is exactly one """ t += len(item) for l in item: assert (l in numbers) is False numbers.append(l) assert n == t x = symbols("x") raises(ValueError, lambda: schur_partition(x)) def test_schur_number(): first_known_schur_numbers = {1: 1, 2: 4, 3: 13, 4: 44} for k in first_known_schur_numbers: assert SchurNumber(k) == first_known_schur_numbers[k] assert SchurNumber(S.Infinity) == S.Infinity assert SchurNumber(0) == 0 raises(ValueError, lambda: SchurNumber(0.5)) n = symbols("n") assert SchurNumber(n).lower_bound() == 3**n/2 - Rational(1, 2) assert SchurNumber(6).lower_bound() == 364 sympy-sympy-1.9/sympy/combinatorics/tests/test_subsets.py000066400000000000000000000047071412543434000242130ustar00rootroot00000000000000from sympy.combinatorics.subsets import Subset, ksubsets from sympy.testing.pytest import raises def test_subset(): a = Subset(['c', 'd'], ['a', 'b', 'c', 'd']) assert a.next_binary() == Subset(['b'], ['a', 'b', 'c', 'd']) assert a.prev_binary() == Subset(['c'], ['a', 'b', 'c', 'd']) assert a.next_lexicographic() == Subset(['d'], ['a', 'b', 'c', 'd']) assert a.prev_lexicographic() == Subset(['c'], ['a', 'b', 'c', 'd']) assert a.next_gray() == Subset(['c'], ['a', 'b', 'c', 'd']) assert a.prev_gray() == Subset(['d'], ['a', 'b', 'c', 'd']) assert a.rank_binary == 3 assert a.rank_lexicographic == 14 assert a.rank_gray == 2 assert a.cardinality == 16 assert a.size == 2 assert Subset.bitlist_from_subset(a, ['a', 'b', 'c', 'd']) == '0011' a = Subset([2, 5, 7], [1, 2, 3, 4, 5, 6, 7]) assert a.next_binary() == Subset([2, 5, 6], [1, 2, 3, 4, 5, 6, 7]) assert a.prev_binary() == Subset([2, 5], [1, 2, 3, 4, 5, 6, 7]) assert a.next_lexicographic() == Subset([2, 6], [1, 2, 3, 4, 5, 6, 7]) assert a.prev_lexicographic() == Subset([2, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7]) assert a.next_gray() == Subset([2, 5, 6, 7], [1, 2, 3, 4, 5, 6, 7]) assert a.prev_gray() == Subset([2, 5], [1, 2, 3, 4, 5, 6, 7]) assert a.rank_binary == 37 assert a.rank_lexicographic == 93 assert a.rank_gray == 57 assert a.cardinality == 128 superset = ['a', 'b', 'c', 'd'] assert Subset.unrank_binary(4, superset).rank_binary == 4 assert Subset.unrank_gray(10, superset).rank_gray == 10 superset = [1, 2, 3, 4, 5, 6, 7, 8, 9] assert Subset.unrank_binary(33, superset).rank_binary == 33 assert Subset.unrank_gray(25, superset).rank_gray == 25 a = Subset([], ['a', 'b', 'c', 'd']) i = 1 while a.subset != Subset(['d'], ['a', 'b', 'c', 'd']).subset: a = a.next_lexicographic() i = i + 1 assert i == 16 i = 1 while a.subset != Subset([], ['a', 'b', 'c', 'd']).subset: a = a.prev_lexicographic() i = i + 1 assert i == 16 raises(ValueError, lambda: Subset(['a', 'b'], ['a'])) raises(ValueError, lambda: Subset(['a'], ['b', 'c'])) raises(ValueError, lambda: Subset.subset_from_bitlist(['a', 'b'], '010')) def test_ksubsets(): assert list(ksubsets([1, 2, 3], 2)) == [(1, 2), (1, 3), (2, 3)] assert list(ksubsets([1, 2, 3, 4, 5], 2)) == [(1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5), (3, 4), (3, 5), (4, 5)] sympy-sympy-1.9/sympy/combinatorics/tests/test_tensor_can.py000066400000000000000000000601441412543434000246530ustar00rootroot00000000000000from sympy.combinatorics.permutations import Permutation, Perm from sympy.combinatorics.tensor_can import (perm_af_direct_product, dummy_sgs, riemann_bsgs, get_symmetric_group_sgs, canonicalize, bsgs_direct_product) from sympy.combinatorics.testutil import canonicalize_naive, graph_certificate from sympy.testing.pytest import skip, XFAIL def test_perm_af_direct_product(): gens1 = [[1,0,2,3], [0,1,3,2]] gens2 = [[1,0]] assert perm_af_direct_product(gens1, gens2, 0) == [[1, 0, 2, 3, 4, 5], [0, 1, 3, 2, 4, 5], [0, 1, 2, 3, 5, 4]] gens1 = [[1,0,2,3,5,4], [0,1,3,2,4,5]] gens2 = [[1,0,2,3]] assert [[1, 0, 2, 3, 4, 5, 7, 6], [0, 1, 3, 2, 4, 5, 6, 7], [0, 1, 2, 3, 5, 4, 6, 7]] def test_dummy_sgs(): a = dummy_sgs([1,2], 0, 4) assert a == [[0,2,1,3,4,5]] a = dummy_sgs([2,3,4,5], 0, 8) assert a == [x._array_form for x in [Perm(9)(2,3), Perm(9)(4,5), Perm(9)(2,4)(3,5)]] a = dummy_sgs([2,3,4,5], 1, 8) assert a == [x._array_form for x in [Perm(2,3)(8,9), Perm(4,5)(8,9), Perm(9)(2,4)(3,5)]] def test_get_symmetric_group_sgs(): assert get_symmetric_group_sgs(2) == ([0], [Permutation(3)(0,1)]) assert get_symmetric_group_sgs(2, 1) == ([0], [Permutation(0,1)(2,3)]) assert get_symmetric_group_sgs(3) == ([0,1], [Permutation(4)(0,1), Permutation(4)(1,2)]) assert get_symmetric_group_sgs(3, 1) == ([0,1], [Permutation(0,1)(3,4), Permutation(1,2)(3,4)]) assert get_symmetric_group_sgs(4) == ([0,1,2], [Permutation(5)(0,1), Permutation(5)(1,2), Permutation(5)(2,3)]) assert get_symmetric_group_sgs(4, 1) == ([0,1,2], [Permutation(0,1)(4,5), Permutation(1,2)(4,5), Permutation(2,3)(4,5)]) def test_canonicalize_no_slot_sym(): # cases in which there is no slot symmetry after fixing the # free indices; here and in the following if the symmetry of the # metric is not specified, it is assumed to be symmetric. # If it is not specified, tensors are commuting. # A_d0 * B^d0; g = [1,0, 2,3]; T_c = A^d0*B_d0; can = [0,1,2,3] base1, gens1 = get_symmetric_group_sgs(1) dummies = [0, 1] g = Permutation([1,0,2,3]) can = canonicalize(g, dummies, 0, (base1,gens1,1,0), (base1,gens1,1,0)) assert can == [0,1,2,3] # equivalently can = canonicalize(g, dummies, 0, (base1, gens1, 2, None)) assert can == [0,1,2,3] # with antisymmetric metric; T_c = -A^d0*B_d0; can = [0,1,3,2] can = canonicalize(g, dummies, 1, (base1,gens1,1,0), (base1,gens1,1,0)) assert can == [0,1,3,2] # A^a * B^b; ord = [a,b]; g = [0,1,2,3]; can = g g = Permutation([0,1,2,3]) dummies = [] t0 = t1 = (base1, gens1, 1, 0) can = canonicalize(g, dummies, 0, t0, t1) assert can == [0,1,2,3] # B^b * A^a g = Permutation([1,0,2,3]) can = canonicalize(g, dummies, 0, t0, t1) assert can == [1,0,2,3] # A symmetric # A^{b}_{d0}*A^{d0, a} order a,b,d0,-d0; T_c = A^{a d0}*A{b}_{d0} # g = [1,3,2,0,4,5]; can = [0,2,1,3,4,5] base2, gens2 = get_symmetric_group_sgs(2) dummies = [2,3] g = Permutation([1,3,2,0,4,5]) can = canonicalize(g, dummies, 0, (base2, gens2, 2, 0)) assert can == [0, 2, 1, 3, 4, 5] # with antisymmetric metric can = canonicalize(g, dummies, 1, (base2, gens2, 2, 0)) assert can == [0, 2, 1, 3, 4, 5] # A^{a}_{d0}*A^{d0, b} g = Permutation([0,3,2,1,4,5]) can = canonicalize(g, dummies, 1, (base2, gens2, 2, 0)) assert can == [0, 2, 1, 3, 5, 4] # A, B symmetric # A^b_d0*B^{d0,a}; g=[1,3,2,0,4,5] # T_c = A^{b,d0}*B_{a,d0}; can = [1,2,0,3,4,5] dummies = [2,3] g = Permutation([1,3,2,0,4,5]) can = canonicalize(g, dummies, 0, (base2,gens2,1,0), (base2,gens2,1,0)) assert can == [1,2,0,3,4,5] # same with antisymmetric metric can = canonicalize(g, dummies, 1, (base2,gens2,1,0), (base2,gens2,1,0)) assert can == [1,2,0,3,5,4] # A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5] # T_c = A^{d0 d1}*B_d0*C_d1; can = [0,2,1,3,4,5] base1, gens1 = get_symmetric_group_sgs(1) base2, gens2 = get_symmetric_group_sgs(2) g = Permutation([2,1,0,3,4,5]) dummies = [0,1,2,3] t0 = (base2, gens2, 1, 0) t1 = t2 = (base1, gens1, 1, 0) can = canonicalize(g, dummies, 0, t0, t1, t2) assert can == [0, 2, 1, 3, 4, 5] # A without symmetry # A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5] # T_c = A^{d0 d1}*B_d1*C_d0; can = [0,2,3,1,4,5] g = Permutation([2,1,0,3,4,5]) dummies = [0,1,2,3] t0 = ([], [Permutation(list(range(4)))], 1, 0) can = canonicalize(g, dummies, 0, t0, t1, t2) assert can == [0,2,3,1,4,5] # A, B without symmetry # A^{d1}_{d0}*B_{d1}^{d0}; g = [2,1,3,0,4,5] # T_c = A^{d0 d1}*B_{d0 d1}; can = [0,2,1,3,4,5] t0 = t1 = ([], [Permutation(list(range(4)))], 1, 0) dummies = [0,1,2,3] g = Permutation([2,1,3,0,4,5]) can = canonicalize(g, dummies, 0, t0, t1) assert can == [0, 2, 1, 3, 4, 5] # A_{d0}^{d1}*B_{d1}^{d0}; g = [1,2,3,0,4,5] # T_c = A^{d0 d1}*B_{d1 d0}; can = [0,2,3,1,4,5] g = Permutation([1,2,3,0,4,5]) can = canonicalize(g, dummies, 0, t0, t1) assert can == [0,2,3,1,4,5] # A, B, C without symmetry # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] # g=[4,2,0,3,5,1,6,7] # T_c=A^{d0 d1}*B_{a d1}*C_{d0 b}; can = [2,4,0,5,3,1,6,7] t0 = t1 = t2 = ([], [Permutation(list(range(4)))], 1, 0) dummies = [2,3,4,5] g = Permutation([4,2,0,3,5,1,6,7]) can = canonicalize(g, dummies, 0, t0, t1, t2) assert can == [2,4,0,5,3,1,6,7] # A symmetric, B and C without symmetry # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] # g=[4,2,0,3,5,1,6,7] # T_c = A^{d0 d1}*B_{a d0}*C_{d1 b}; can = [2,4,0,3,5,1,6,7] t0 = (base2,gens2,1,0) t1 = t2 = ([], [Permutation(list(range(4)))], 1, 0) dummies = [2,3,4,5] g = Permutation([4,2,0,3,5,1,6,7]) can = canonicalize(g, dummies, 0, t0, t1, t2) assert can == [2,4,0,3,5,1,6,7] # A and C symmetric, B without symmetry # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] # g=[4,2,0,3,5,1,6,7] # T_c = A^{d0 d1}*B_{a d0}*C_{b d1}; can = [2,4,0,3,1,5,6,7] t0 = t2 = (base2,gens2,1,0) t1 = ([], [Permutation(list(range(4)))], 1, 0) dummies = [2,3,4,5] g = Permutation([4,2,0,3,5,1,6,7]) can = canonicalize(g, dummies, 0, t0, t1, t2) assert can == [2,4,0,3,1,5,6,7] # A symmetric, B without symmetry, C antisymmetric # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] # g=[4,2,0,3,5,1,6,7] # T_c = -A^{d0 d1}*B_{a d0}*C_{b d1}; can = [2,4,0,3,1,5,7,6] t0 = (base2,gens2, 1, 0) t1 = ([], [Permutation(list(range(4)))], 1, 0) base2a, gens2a = get_symmetric_group_sgs(2, 1) t2 = (base2a, gens2a, 1, 0) dummies = [2,3,4,5] g = Permutation([4,2,0,3,5,1,6,7]) can = canonicalize(g, dummies, 0, t0, t1, t2) assert can == [2,4,0,3,1,5,7,6] def test_canonicalize_no_dummies(): base1, gens1 = get_symmetric_group_sgs(1) base2, gens2 = get_symmetric_group_sgs(2) base2a, gens2a = get_symmetric_group_sgs(2, 1) # A commuting # A^c A^b A^a; ord = [a,b,c]; g = [2,1,0,3,4] # T_c = A^a A^b A^c; can = list(range(5)) g = Permutation([2,1,0,3,4]) can = canonicalize(g, [], 0, (base1, gens1, 3, 0)) assert can == list(range(5)) # A anticommuting # A^c A^b A^a; ord = [a,b,c]; g = [2,1,0,3,4] # T_c = -A^a A^b A^c; can = [0,1,2,4,3] g = Permutation([2,1,0,3,4]) can = canonicalize(g, [], 0, (base1, gens1, 3, 1)) assert can == [0,1,2,4,3] # A commuting and symmetric # A^{b,d}*A^{c,a}; ord = [a,b,c,d]; g = [1,3,2,0,4,5] # T_c = A^{a c}*A^{b d}; can = [0,2,1,3,4,5] g = Permutation([1,3,2,0,4,5]) can = canonicalize(g, [], 0, (base2, gens2, 2, 0)) assert can == [0,2,1,3,4,5] # A anticommuting and symmetric # A^{b,d}*A^{c,a}; ord = [a,b,c,d]; g = [1,3,2,0,4,5] # T_c = -A^{a c}*A^{b d}; can = [0,2,1,3,5,4] g = Permutation([1,3,2,0,4,5]) can = canonicalize(g, [], 0, (base2, gens2, 2, 1)) assert can == [0,2,1,3,5,4] # A^{c,a}*A^{b,d} ; g = [2,0,1,3,4,5] # T_c = A^{a c}*A^{b d}; can = [0,2,1,3,4,5] g = Permutation([2,0,1,3,4,5]) can = canonicalize(g, [], 0, (base2, gens2, 2, 1)) assert can == [0,2,1,3,4,5] def test_no_metric_symmetry(): # no metric symmetry # A^d1_d0 * A^d0_d1; ord = [d0,-d0,d1,-d1]; g= [2,1,0,3,4,5] # T_c = A^d0_d1 * A^d1_d0; can = [0,3,2,1,4,5] g = Permutation([2,1,0,3,4,5]) can = canonicalize(g, list(range(4)), None, [[], [Permutation(list(range(4)))], 2, 0]) assert can == [0,3,2,1,4,5] # A^d1_d2 * A^d0_d3 * A^d2_d1 * A^d3_d0 # ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3] # 0 1 2 3 4 5 6 7 # g = [2,5,0,7,4,3,6,1,8,9] # T_c = A^d0_d1 * A^d1_d0 * A^d2_d3 * A^d3_d2 # can = [0,3,2,1,4,7,6,5,8,9] g = Permutation([2,5,0,7,4,3,6,1,8,9]) #can = canonicalize(g, list(range(8)), 0, [[], [list(range(4))], 4, 0]) #assert can == [0, 2, 3, 1, 4, 6, 7, 5, 8, 9] can = canonicalize(g, list(range(8)), None, [[], [Permutation(list(range(4)))], 4, 0]) assert can == [0, 3, 2, 1, 4, 7, 6, 5, 8, 9] # A^d0_d2 * A^d1_d3 * A^d3_d0 * A^d2_d1 # g = [0,5,2,7,6,1,4,3,8,9] # T_c = A^d0_d1 * A^d1_d2 * A^d2_d3 * A^d3_d0 # can = [0,3,2,5,4,7,6,1,8,9] g = Permutation([0,5,2,7,6,1,4,3,8,9]) can = canonicalize(g, list(range(8)), None, [[], [Permutation(list(range(4)))], 4, 0]) assert can == [0,3,2,5,4,7,6,1,8,9] g = Permutation([12,7,10,3,14,13,4,11,6,1,2,9,0,15,8,5,16,17]) can = canonicalize(g, list(range(16)), None, [[], [Permutation(list(range(4)))], 8, 0]) assert can == [0,3,2,5,4,7,6,1,8,11,10,13,12,15,14,9,16,17] def test_canonical_free(): # t = A^{d0 a1}*A_d0^a0 # ord = [a0,a1,d0,-d0]; g = [2,1,3,0,4,5]; dummies = [[2,3]] # t_c = A_d0^a0*A^{d0 a1} # can = [3,0, 2,1, 4,5] g = Permutation([2,1,3,0,4,5]) dummies = [[2,3]] can = canonicalize(g, dummies, [None], ([], [Permutation(3)], 2, 0)) assert can == [3,0, 2,1, 4,5] def test_canonicalize1(): base1, gens1 = get_symmetric_group_sgs(1) base1a, gens1a = get_symmetric_group_sgs(1, 1) base2, gens2 = get_symmetric_group_sgs(2) base3, gens3 = get_symmetric_group_sgs(3) base2a, gens2a = get_symmetric_group_sgs(2, 1) base3a, gens3a = get_symmetric_group_sgs(3, 1) # A_d0*A^d0; ord = [d0,-d0]; g = [1,0,2,3] # T_c = A^d0*A_d0; can = [0,1,2,3] g = Permutation([1,0,2,3]) can = canonicalize(g, [0, 1], 0, (base1, gens1, 2, 0)) assert can == list(range(4)) # A commuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] # g = [1,3,5,4,2,0,6,7] # T_c = A^d0*A_d0*A^d1*A_d1*A^d2*A_d2; can = list(range(8)) g = Permutation([1,3,5,4,2,0,6,7]) can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 0)) assert can == list(range(8)) # A anticommuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0; ord=[d0,-d0,d1,-d1,d2,-d2] # g = [1,3,5,4,2,0,6,7] # T_c 0; can = 0 g = Permutation([1,3,5,4,2,0,6,7]) can = canonicalize(g, list(range(6)), 0, (base1, gens1, 6, 1)) assert can == 0 can1 = canonicalize_naive(g, list(range(6)), 0, (base1, gens1, 6, 1)) assert can1 == 0 # A commuting symmetric # A^{d0 b}*A^a_d1*A^d1_d0; ord=[a,b,d0,-d0,d1,-d1] # g = [2,1,0,5,4,3,6,7] # T_c = A^{a d0}*A^{b d1}*A_{d0 d1}; can = [0,2,1,4,3,5,6,7] g = Permutation([2,1,0,5,4,3,6,7]) can = canonicalize(g, list(range(2,6)), 0, (base2, gens2, 3, 0)) assert can == [0,2,1,4,3,5,6,7] # A, B commuting symmetric # A^{d0 b}*A^d1_d0*B^a_d1; ord=[a,b,d0,-d0,d1,-d1] # g = [2,1,4,3,0,5,6,7] # T_c = A^{b d0}*A_d0^d1*B^a_d1; can = [1,2,3,4,0,5,6,7] g = Permutation([2,1,4,3,0,5,6,7]) can = canonicalize(g, list(range(2,6)), 0, (base2,gens2,2,0), (base2,gens2,1,0)) assert can == [1,2,3,4,0,5,6,7] # A commuting symmetric # A^{d1 d0 b}*A^{a}_{d1 d0}; ord=[a,b, d0,-d0,d1,-d1] # g = [4,2,1,0,5,3,6,7] # T_c = A^{a d0 d1}*A^{b}_{d0 d1}; can = [0,2,4,1,3,5,6,7] g = Permutation([4,2,1,0,5,3,6,7]) can = canonicalize(g, list(range(2,6)), 0, (base3, gens3, 2, 0)) assert can == [0,2,4,1,3,5,6,7] # A^{d3 d0 d2}*A^a0_{d1 d2}*A^d1_d3^a1*A^{a2 a3}_d0 # ord = [a0,a1,a2,a3,d0,-d0,d1,-d1,d2,-d2,d3,-d3] # 0 1 2 3 4 5 6 7 8 9 10 11 # g = [10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13] # T_c = A^{a0 d0 d1}*A^a1_d0^d2*A^{a2 a3 d3}*A_{d1 d2 d3} # can = [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13] g = Permutation([10,4,8, 0,7,9, 6,11,1, 2,3,5, 12,13]) can = canonicalize(g, list(range(4,12)), 0, (base3, gens3, 4, 0)) assert can == [0,4,6, 1,5,8, 2,3,10, 7,9,11, 12,13] # A commuting symmetric, B antisymmetric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # ord = [d0,-d0,d1,-d1,d2,-d2,d3,-d3] # g = [0,2,4,5,7,3,1,6,8,9] # in this esxample and in the next three, # renaming dummy indices and using symmetry of A, # T = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 # can = 0 g = Permutation([0,2,4,5,7,3,1,6,8,9]) can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,0), (base2a,gens2a,1,0)) assert can == 0 # A anticommuting symmetric, B anticommuting # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} # can = [0,2,4, 1,3,6, 5,7, 8,9] can = canonicalize(g, list(range(8)), 0, (base3, gens3,2,1), (base2a,gens2a,1,0)) assert can == [0,2,4, 1,3,6, 5,7, 8,9] # A anticommuting symmetric, B antisymmetric commuting, antisymmetric metric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = -A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} # can = [0,2,4, 1,3,6, 5,7, 9,8] can = canonicalize(g, list(range(8)), 1, (base3, gens3,2,1), (base2a,gens2a,1,0)) assert can == [0,2,4, 1,3,6, 5,7, 9,8] # A anticommuting symmetric, B anticommuting anticommuting, # no metric symmetry # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 # can = [0,2,4, 1,3,7, 5,6, 8,9] can = canonicalize(g, list(range(8)), None, (base3, gens3,2,1), (base2a,gens2a,1,0)) assert can == [0,2,4,1,3,7,5,6,8,9] # Gamma anticommuting # Gamma_{mu nu} * gamma^rho * Gamma^{nu mu alpha} # ord = [alpha, rho, mu,-mu,nu,-nu] # g = [3,5,1,4,2,0,6,7] # T_c = -Gamma^{mu nu} * gamma^rho * Gamma_{alpha mu nu} # can = [2,4,1,0,3,5,7,6]] g = Permutation([3,5,1,4,2,0,6,7]) t0 = (base2a, gens2a, 1, None) t1 = (base1, gens1, 1, None) t2 = (base3a, gens3a, 1, None) can = canonicalize(g, list(range(2, 6)), 0, t0, t1, t2) assert can == [2,4,1,0,3,5,7,6] # Gamma_{mu nu} * Gamma^{gamma beta} * gamma_rho * Gamma^{nu mu alpha} # ord = [alpha, beta, gamma, -rho, mu,-mu,nu,-nu] # 0 1 2 3 4 5 6 7 # g = [5,7,2,1,3,6,4,0,8,9] # T_c = Gamma^{mu nu} * Gamma^{beta gamma} * gamma_rho * Gamma^alpha_{mu nu} # can = [4,6,1,2,3,0,5,7,8,9] t0 = (base2a, gens2a, 2, None) g = Permutation([5,7,2,1,3,6,4,0,8,9]) can = canonicalize(g, list(range(4, 8)), 0, t0, t1, t2) assert can == [4,6,1,2,3,0,5,7,8,9] # f^a_{b,c} antisymmetric in b,c; A_mu^a no symmetry # f^c_{d a} * f_{c e b} * A_mu^d * A_nu^a * A^{nu e} * A^{mu b} # ord = [mu,-mu,nu,-nu,a,-a,b,-b,c,-c,d,-d, e, -e] # 0 1 2 3 4 5 6 7 8 9 10 11 12 13 # g = [8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15] # T_c = -f^{a b c} * f_a^{d e} * A^mu_b * A_{mu d} * A^nu_c * A_{nu e} # can = [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14] g = Permutation([8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15]) base_f, gens_f = bsgs_direct_product(base1, gens1, base2a, gens2a) base_A, gens_A = bsgs_direct_product(base1, gens1, base1, gens1) t0 = (base_f, gens_f, 2, 0) t1 = (base_A, gens_A, 4, 0) can = canonicalize(g, [list(range(4)), list(range(4, 14))], [0, 0], t0, t1) assert can == [4,6,8, 5,10,12, 0,7, 1,11, 2,9, 3,13, 15,14] def test_riemann_invariants(): baser, gensr = riemann_bsgs # R^{d0 d1}_{d1 d0}; ord = [d0,-d0,d1,-d1]; g = [0,2,3,1,4,5] # T_c = -R^{d0 d1}_{d0 d1}; can = [0,2,1,3,5,4] g = Permutation([0,2,3,1,4,5]) can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0)) assert can == [0,2,1,3,5,4] # use a non minimal BSGS can = canonicalize(g, list(range(2, 4)), 0, ([2, 0], [Permutation([1,0,2,3,5,4]), Permutation([2,3,0,1,4,5])], 1, 0)) assert can == [0,2,1,3,5,4] """ The following tests in test_riemann_invariants and in test_riemann_invariants1 have been checked using xperm.c from XPerm in in [1] and with an older version contained in [2] [1] xperm.c part of xPerm written by J. M. Martin-Garcia http://www.xact.es/index.html [2] test_xperm.cc in cadabra by Kasper Peeters, http://cadabra.phi-sci.com/ """ # R_d11^d1_d0^d5 * R^{d6 d4 d0}_d5 * R_{d7 d2 d8 d9} * # R_{d10 d3 d6 d4} * R^{d2 d7 d11}_d1 * R^{d8 d9 d3 d10} # ord: contravariant d_k ->2*k, covariant d_k -> 2*k+1 # T_c = R^{d0 d1 d2 d3} * R_{d0 d1}^{d4 d5} * R_{d2 d3}^{d6 d7} * # R_{d4 d5}^{d8 d9} * R_{d6 d7}^{d10 d11} * R_{d8 d9 d10 d11} g = Permutation([23,2,1,10,12,8,0,11,15,5,17,19,21,7,13,9,4,14,22,3,16,18,6,20,24,25]) can = canonicalize(g, list(range(24)), 0, (baser, gensr, 6, 0)) assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,21,23,24,25] # use a non minimal BSGS can = canonicalize(g, list(range(24)), 0, ([2, 0], [Permutation([1,0,2,3,5,4]), Permutation([2,3,0,1,4,5])], 6, 0)) assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,21,23,24,25] g = Permutation([0,2,5,7,4,6,9,11,8,10,13,15,12,14,17,19,16,18,21,23,20,22,25,27,24,26,29,31,28,30,33,35,32,34,37,39,36,38,1,3,40,41]) can = canonicalize(g, list(range(40)), 0, (baser, gensr, 10, 0)) assert can == [0,2,4,6,1,3,8,10,5,7,12,14,9,11,16,18,13,15,20,22,17,19,24,26,21,23,28,30,25,27,32,34,29,31,36,38,33,35,37,39,40,41] @XFAIL def test_riemann_invariants1(): skip('takes too much time') baser, gensr = riemann_bsgs g = Permutation([17, 44, 11, 3, 0, 19, 23, 15, 38, 4, 25, 27, 43, 36, 22, 14, 8, 30, 41, 20, 2, 10, 12, 28, 18, 1, 29, 13, 37, 42, 33, 7, 9, 31, 24, 26, 39, 5, 34, 47, 32, 6, 21, 40, 35, 46, 45, 16, 48, 49]) can = canonicalize(g, list(range(48)), 0, (baser, gensr, 12, 0)) assert can == [0, 2, 4, 6, 1, 3, 8, 10, 5, 7, 12, 14, 9, 11, 16, 18, 13, 15, 20, 22, 17, 19, 24, 26, 21, 23, 28, 30, 25, 27, 32, 34, 29, 31, 36, 38, 33, 35, 40, 42, 37, 39, 44, 46, 41, 43, 45, 47, 48, 49] g = Permutation([0,2,4,6, 7,8,10,12, 14,16,18,20, 19,22,24,26, 5,21,28,30, 32,34,36,38, 40,42,44,46, 13,48,50,52, 15,49,54,56, 17,33,41,58, 9,23,60,62, 29,35,63,64, 3,45,66,68, 25,37,47,57, 11,31,69,70, 27,39,53,72, 1,59,73,74, 55,61,67,76, 43,65,75,78, 51,71,77,79, 80,81]) can = canonicalize(g, list(range(80)), 0, (baser, gensr, 20, 0)) assert can == [0,2,4,6, 1,8,10,12, 3,14,16,18, 5,20,22,24, 7,26,28,30, 9,15,32,34, 11,36,23,38, 13,40,42,44, 17,39,29,46, 19,48,43,50, 21,45,52,54, 25,56,33,58, 27,60,53,62, 31,51,64,66, 35,65,47,68, 37,70,49,72, 41,74,57,76, 55,67,59,78, 61,69,71,75, 63,79,73,77, 80,81] def test_riemann_products(): baser, gensr = riemann_bsgs base1, gens1 = get_symmetric_group_sgs(1) base2, gens2 = get_symmetric_group_sgs(2) base2a, gens2a = get_symmetric_group_sgs(2, 1) # R^{a b d0}_d0 = 0 g = Permutation([0,1,2,3,4,5]) can = canonicalize(g, list(range(2,4)), 0, (baser, gensr, 1, 0)) assert can == 0 # R^{d0 b a}_d0 ; ord = [a,b,d0,-d0}; g = [2,1,0,3,4,5] # T_c = -R^{a d0 b}_d0; can = [0,2,1,3,5,4] g = Permutation([2,1,0,3,4,5]) can = canonicalize(g, list(range(2, 4)), 0, (baser, gensr, 1, 0)) assert can == [0,2,1,3,5,4] # R^d1_d2^b_d0 * R^{d0 a}_d1^d2; ord=[a,b,d0,-d0,d1,-d1,d2,-d2] # g = [4,7,1,3,2,0,5,6,8,9] # T_c = -R^{a d0 d1 d2}* R^b_{d0 d1 d2} # can = [0,2,4,6,1,3,5,7,9,8] g = Permutation([4,7,1,3,2,0,5,6,8,9]) can = canonicalize(g, list(range(2,8)), 0, (baser, gensr, 2, 0)) assert can == [0,2,4,6,1,3,5,7,9,8] can1 = canonicalize_naive(g, list(range(2,8)), 0, (baser, gensr, 2, 0)) assert can == can1 # A symmetric commuting # R^{d6 d5}_d2^d1 * R^{d4 d0 d2 d3} * A_{d6 d0} A_{d3 d1} * A_{d4 d5} # g = [12,10,5,2, 8,0,4,6, 13,1, 7,3, 9,11,14,15] # T_c = -R^{d0 d1 d2 d3} * R_d0^{d4 d5 d6} * A_{d1 d4}*A_{d2 d5}*A_{d3 d6} g = Permutation([12,10,5,2,8,0,4,6,13,1,7,3,9,11,14,15]) can = canonicalize(g, list(range(14)), 0, ((baser,gensr,2,0)), (base2,gens2,3,0)) assert can == [0, 2, 4, 6, 1, 8, 10, 12, 3, 9, 5, 11, 7, 13, 15, 14] # R^{d2 a0 a2 d0} * R^d1_d2^{a1 a3} * R^{a4 a5}_{d0 d1} # ord = [a0,a1,a2,a3,a4,a5,d0,-d0,d1,-d1,d2,-d2] # 0 1 2 3 4 5 6 7 8 9 10 11 # can = [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] # T_c = R^{a0 d0 a2 d1}*R^{a1 a3}_d0^d2*R^{a4 a5}_{d1 d2} g = Permutation([10,0,2,6,8,11,1,3,4,5,7,9,12,13]) can = canonicalize(g, list(range(6,12)), 0, (baser, gensr, 3, 0)) assert can == [0, 6, 2, 8, 1, 3, 7, 10, 4, 5, 9, 11, 12, 13] #can1 = canonicalize_naive(g, list(range(6,12)), 0, (baser, gensr, 3, 0)) #assert can == can1 # A^n_{i, j} antisymmetric in i,j # A_m0^d0_a1 * A_m1^a0_d0; ord = [m0,m1,a0,a1,d0,-d0] # g = [0,4,3,1,2,5,6,7] # T_c = -A_{m a1}^d0 * A_m1^a0_d0 # can = [0,3,4,1,2,5,7,6] base, gens = bsgs_direct_product(base1, gens1, base2a, gens2a) dummies = list(range(4, 6)) g = Permutation([0,4,3,1,2,5,6,7]) can = canonicalize(g, dummies, 0, (base, gens, 2, 0)) assert can == [0, 3, 4, 1, 2, 5, 7, 6] # A^n_{i, j} symmetric in i,j # A^m0_a0^d2 * A^n0_d2^d1 * A^n1_d1^d0 * A_{m0 d0}^a1 # ordering: first the free indices; then first n, then d # ord=[n0,n1,a0,a1, m0,-m0,d0,-d0,d1,-d1,d2,-d2] # 0 1 2 3 4 5 6 7 8 9 10 11] # g = [4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13] # if the dummy indices m_i and d_i were separated, # one gets # T_c = A^{n0 d0 d1} * A^n1_d0^d2 * A^m0^a0_d1 * A_m0^a1_d2 # can = [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] # If they are not, so can is # T_c = A^{n0 m0 d0} A^n1_m0^d1 A^{d2 a0}_d0 A_d2^a1_d1 # can = [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] # case with single type of indices base, gens = bsgs_direct_product(base1, gens1, base2, gens2) dummies = list(range(4, 12)) g = Permutation([4,2,10, 0,11,8, 1,9,6, 5,7,3, 12,13]) can = canonicalize(g, dummies, 0, (base, gens, 4, 0)) assert can == [0, 4, 6, 1, 5, 8, 10, 2, 7, 11, 3, 9, 12, 13] # case with separated indices dummies = [list(range(4, 6)), list(range(6,12))] sym = [0, 0] can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 12, 13] # case with separated indices with the second type of index # with antisymmetric metric: there is a sign change sym = [0, 1] can = canonicalize(g, dummies, sym, (base, gens, 4, 0)) assert can == [0, 6, 8, 1, 7, 10, 4, 2, 9, 5, 3, 11, 13, 12] def test_graph_certificate(): # test tensor invariants constructed from random regular graphs; # checked graph isomorphism with networkx import random def randomize_graph(size, g): p = list(range(size)) random.shuffle(p) g1a = {} for k, v in g1.items(): g1a[p[k]] = [p[i] for i in v] return g1a g1 = {0: [2, 3, 7], 1: [4, 5, 7], 2: [0, 4, 6], 3: [0, 6, 7], 4: [1, 2, 5], 5: [1, 4, 6], 6: [2, 3, 5], 7: [0, 1, 3]} g2 = {0: [2, 3, 7], 1: [2, 4, 5], 2: [0, 1, 5], 3: [0, 6, 7], 4: [1, 5, 6], 5: [1, 2, 4], 6: [3, 4, 7], 7: [0, 3, 6]} c1 = graph_certificate(g1) c2 = graph_certificate(g2) assert c1 != c2 g1a = randomize_graph(8, g1) c1a = graph_certificate(g1a) assert c1 == c1a g1 = {0: [8, 1, 9, 7], 1: [0, 9, 3, 4], 2: [3, 4, 6, 7], 3: [1, 2, 5, 6], 4: [8, 1, 2, 5], 5: [9, 3, 4, 7], 6: [8, 2, 3, 7], 7: [0, 2, 5, 6], 8: [0, 9, 4, 6], 9: [8, 0, 5, 1]} g2 = {0: [1, 2, 5, 6], 1: [0, 9, 5, 7], 2: [0, 4, 6, 7], 3: [8, 9, 6, 7], 4: [8, 2, 6, 7], 5: [0, 9, 8, 1], 6: [0, 2, 3, 4], 7: [1, 2, 3, 4], 8: [9, 3, 4, 5], 9: [8, 1, 3, 5]} c1 = graph_certificate(g1) c2 = graph_certificate(g2) assert c1 != c2 g1a = randomize_graph(10, g1) c1a = graph_certificate(g1a) assert c1 == c1a sympy-sympy-1.9/sympy/combinatorics/tests/test_testutil.py000066400000000000000000000032661412543434000243770ustar00rootroot00000000000000from sympy.combinatorics.named_groups import SymmetricGroup, AlternatingGroup,\ CyclicGroup from sympy.combinatorics.testutil import _verify_bsgs, _cmp_perm_lists,\ _naive_list_centralizer, _verify_centralizer,\ _verify_normal_closure from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.perm_groups import PermutationGroup from random import shuffle def test_cmp_perm_lists(): S = SymmetricGroup(4) els = list(S.generate_dimino()) other = els[:] shuffle(other) assert _cmp_perm_lists(els, other) is True def test_naive_list_centralizer(): # verified by GAP S = SymmetricGroup(3) A = AlternatingGroup(3) assert _naive_list_centralizer(S, S) == [Permutation([0, 1, 2])] assert PermutationGroup(_naive_list_centralizer(S, A)).is_subgroup(A) def test_verify_bsgs(): S = SymmetricGroup(5) S.schreier_sims() base = S.base strong_gens = S.strong_gens assert _verify_bsgs(S, base, strong_gens) is True assert _verify_bsgs(S, base[:-1], strong_gens) is False assert _verify_bsgs(S, base, S.generators) is False def test_verify_centralizer(): # verified by GAP S = SymmetricGroup(3) A = AlternatingGroup(3) triv = PermutationGroup([Permutation([0, 1, 2])]) assert _verify_centralizer(S, S, centr=triv) assert _verify_centralizer(S, A, centr=A) def test_verify_normal_closure(): # verified by GAP S = SymmetricGroup(3) A = AlternatingGroup(3) assert _verify_normal_closure(S, A, closure=A) S = SymmetricGroup(5) A = AlternatingGroup(5) C = CyclicGroup(5) assert _verify_normal_closure(S, A, closure=A) assert _verify_normal_closure(S, C, closure=A) sympy-sympy-1.9/sympy/combinatorics/tests/test_util.py000066400000000000000000000106231412543434000234720ustar00rootroot00000000000000from sympy.combinatorics.named_groups import SymmetricGroup, DihedralGroup,\ AlternatingGroup from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.util import _check_cycles_alt_sym, _strip,\ _distribute_gens_by_base, _strong_gens_from_distr,\ _orbits_transversals_from_bsgs, _handle_precomputed_bsgs, _base_ordering,\ _remove_gens from sympy.combinatorics.testutil import _verify_bsgs def test_check_cycles_alt_sym(): perm1 = Permutation([[0, 1, 2, 3, 4, 5, 6], [7], [8], [9]]) perm2 = Permutation([[0, 1, 2, 3, 4, 5], [6, 7, 8, 9]]) perm3 = Permutation([[0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) assert _check_cycles_alt_sym(perm1) is True assert _check_cycles_alt_sym(perm2) is False assert _check_cycles_alt_sym(perm3) is False def test_strip(): D = DihedralGroup(5) D.schreier_sims() member = Permutation([4, 0, 1, 2, 3]) not_member1 = Permutation([0, 1, 4, 3, 2]) not_member2 = Permutation([3, 1, 4, 2, 0]) identity = Permutation([0, 1, 2, 3, 4]) res1 = _strip(member, D.base, D.basic_orbits, D.basic_transversals) res2 = _strip(not_member1, D.base, D.basic_orbits, D.basic_transversals) res3 = _strip(not_member2, D.base, D.basic_orbits, D.basic_transversals) assert res1[0] == identity assert res1[1] == len(D.base) + 1 assert res2[0] == not_member1 assert res2[1] == len(D.base) + 1 assert res3[0] != identity assert res3[1] == 2 def test_distribute_gens_by_base(): base = [0, 1, 2] gens = [Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2]), Permutation([0, 2, 3, 1]), Permutation([3, 2, 1, 0])] assert _distribute_gens_by_base(base, gens) == [gens, [Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2]), Permutation([0, 2, 3, 1])], [Permutation([0, 1, 2, 3]), Permutation([0, 1, 3, 2])]] def test_strong_gens_from_distr(): strong_gens_distr = [[Permutation([0, 2, 1]), Permutation([1, 2, 0]), Permutation([1, 0, 2])], [Permutation([0, 2, 1])]] assert _strong_gens_from_distr(strong_gens_distr) == \ [Permutation([0, 2, 1]), Permutation([1, 2, 0]), Permutation([1, 0, 2])] def test_orbits_transversals_from_bsgs(): S = SymmetricGroup(4) S.schreier_sims() base = S.base strong_gens = S.strong_gens strong_gens_distr = _distribute_gens_by_base(base, strong_gens) result = _orbits_transversals_from_bsgs(base, strong_gens_distr) orbits = result[0] transversals = result[1] base_len = len(base) for i in range(base_len): for el in orbits[i]: assert transversals[i][el](base[i]) == el for j in range(i): assert transversals[i][el](base[j]) == base[j] order = 1 for i in range(base_len): order *= len(orbits[i]) assert S.order() == order def test_handle_precomputed_bsgs(): A = AlternatingGroup(5) A.schreier_sims() base = A.base strong_gens = A.strong_gens result = _handle_precomputed_bsgs(base, strong_gens) strong_gens_distr = _distribute_gens_by_base(base, strong_gens) assert strong_gens_distr == result[2] transversals = result[0] orbits = result[1] base_len = len(base) for i in range(base_len): for el in orbits[i]: assert transversals[i][el](base[i]) == el for j in range(i): assert transversals[i][el](base[j]) == base[j] order = 1 for i in range(base_len): order *= len(orbits[i]) assert A.order() == order def test_base_ordering(): base = [2, 4, 5] degree = 7 assert _base_ordering(base, degree) == [3, 4, 0, 5, 1, 2, 6] def test_remove_gens(): S = SymmetricGroup(10) base, strong_gens = S.schreier_sims_incremental() new_gens = _remove_gens(base, strong_gens) assert _verify_bsgs(S, base, new_gens) is True A = AlternatingGroup(7) base, strong_gens = A.schreier_sims_incremental() new_gens = _remove_gens(base, strong_gens) assert _verify_bsgs(A, base, new_gens) is True D = DihedralGroup(2) base, strong_gens = D.schreier_sims_incremental() new_gens = _remove_gens(base, strong_gens) assert _verify_bsgs(D, base, new_gens) is True sympy-sympy-1.9/sympy/combinatorics/testutil.py000066400000000000000000000256351412543434000222020ustar00rootroot00000000000000from sympy.combinatorics import Permutation from sympy.combinatorics.util import _distribute_gens_by_base rmul = Permutation.rmul def _cmp_perm_lists(first, second): """ Compare two lists of permutations as sets. Explanation =========== This is used for testing purposes. Since the array form of a permutation is currently a list, Permutation is not hashable and cannot be put into a set. Examples ======== >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.testutil import _cmp_perm_lists >>> a = Permutation([0, 2, 3, 4, 1]) >>> b = Permutation([1, 2, 0, 4, 3]) >>> c = Permutation([3, 4, 0, 1, 2]) >>> ls1 = [a, b, c] >>> ls2 = [b, c, a] >>> _cmp_perm_lists(ls1, ls2) True """ return {tuple(a) for a in first} == \ {tuple(a) for a in second} def _naive_list_centralizer(self, other, af=False): from sympy.combinatorics.perm_groups import PermutationGroup """ Return a list of elements for the centralizer of a subgroup/set/element. Explanation =========== This is a brute force implementation that goes over all elements of the group and checks for membership in the centralizer. It is used to test ``.centralizer()`` from ``sympy.combinatorics.perm_groups``. Examples ======== >>> from sympy.combinatorics.testutil import _naive_list_centralizer >>> from sympy.combinatorics.named_groups import DihedralGroup >>> D = DihedralGroup(4) >>> _naive_list_centralizer(D, D) [Permutation([0, 1, 2, 3]), Permutation([2, 3, 0, 1])] See Also ======== sympy.combinatorics.perm_groups.centralizer """ from sympy.combinatorics.permutations import _af_commutes_with if hasattr(other, 'generators'): elements = list(self.generate_dimino(af=True)) gens = [x._array_form for x in other.generators] commutes_with_gens = lambda x: all(_af_commutes_with(x, gen) for gen in gens) centralizer_list = [] if not af: for element in elements: if commutes_with_gens(element): centralizer_list.append(Permutation._af_new(element)) else: for element in elements: if commutes_with_gens(element): centralizer_list.append(element) return centralizer_list elif hasattr(other, 'getitem'): return _naive_list_centralizer(self, PermutationGroup(other), af) elif hasattr(other, 'array_form'): return _naive_list_centralizer(self, PermutationGroup([other]), af) def _verify_bsgs(group, base, gens): """ Verify the correctness of a base and strong generating set. Explanation =========== This is a naive implementation using the definition of a base and a strong generating set relative to it. There are other procedures for verifying a base and strong generating set, but this one will serve for more robust testing. Examples ======== >>> from sympy.combinatorics.named_groups import AlternatingGroup >>> from sympy.combinatorics.testutil import _verify_bsgs >>> A = AlternatingGroup(4) >>> A.schreier_sims() >>> _verify_bsgs(A, A.base, A.strong_gens) True See Also ======== sympy.combinatorics.perm_groups.PermutationGroup.schreier_sims """ from sympy.combinatorics.perm_groups import PermutationGroup strong_gens_distr = _distribute_gens_by_base(base, gens) current_stabilizer = group for i in range(len(base)): candidate = PermutationGroup(strong_gens_distr[i]) if current_stabilizer.order() != candidate.order(): return False current_stabilizer = current_stabilizer.stabilizer(base[i]) if current_stabilizer.order() != 1: return False return True def _verify_centralizer(group, arg, centr=None): """ Verify the centralizer of a group/set/element inside another group. This is used for testing ``.centralizer()`` from ``sympy.combinatorics.perm_groups`` Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... AlternatingGroup) >>> from sympy.combinatorics.perm_groups import PermutationGroup >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.testutil import _verify_centralizer >>> S = SymmetricGroup(5) >>> A = AlternatingGroup(5) >>> centr = PermutationGroup([Permutation([0, 1, 2, 3, 4])]) >>> _verify_centralizer(S, A, centr) True See Also ======== _naive_list_centralizer, sympy.combinatorics.perm_groups.PermutationGroup.centralizer, _cmp_perm_lists """ if centr is None: centr = group.centralizer(arg) centr_list = list(centr.generate_dimino(af=True)) centr_list_naive = _naive_list_centralizer(group, arg, af=True) return _cmp_perm_lists(centr_list, centr_list_naive) def _verify_normal_closure(group, arg, closure=None): from sympy.combinatorics.perm_groups import PermutationGroup """ Verify the normal closure of a subgroup/subset/element in a group. This is used to test sympy.combinatorics.perm_groups.PermutationGroup.normal_closure Examples ======== >>> from sympy.combinatorics.named_groups import (SymmetricGroup, ... AlternatingGroup) >>> from sympy.combinatorics.testutil import _verify_normal_closure >>> S = SymmetricGroup(3) >>> A = AlternatingGroup(3) >>> _verify_normal_closure(S, A, closure=A) True See Also ======== sympy.combinatorics.perm_groups.PermutationGroup.normal_closure """ if closure is None: closure = group.normal_closure(arg) conjugates = set() if hasattr(arg, 'generators'): subgr_gens = arg.generators elif hasattr(arg, '__getitem__'): subgr_gens = arg elif hasattr(arg, 'array_form'): subgr_gens = [arg] for el in group.generate_dimino(): for gen in subgr_gens: conjugates.add(gen ^ el) naive_closure = PermutationGroup(list(conjugates)) return closure.is_subgroup(naive_closure) def canonicalize_naive(g, dummies, sym, *v): """ Canonicalize tensor formed by tensors of the different types. Explanation =========== sym_i symmetry under exchange of two component tensors of type `i` None no symmetry 0 commuting 1 anticommuting Parameters ========== g : Permutation representing the tensor. dummies : List of dummy indices. msym : Symmetry of the metric. v : A list of (base_i, gens_i, n_i, sym_i) for tensors of type `i`. base_i, gens_i BSGS for tensors of this type n_i number ot tensors of type `i` Returns ======= Returns 0 if the tensor is zero, else returns the array form of the permutation representing the canonical form of the tensor. Examples ======== >>> from sympy.combinatorics.testutil import canonicalize_naive >>> from sympy.combinatorics.tensor_can import get_symmetric_group_sgs >>> from sympy.combinatorics import Permutation >>> g = Permutation([1, 3, 2, 0, 4, 5]) >>> base2, gens2 = get_symmetric_group_sgs(2) >>> canonicalize_naive(g, [2, 3], 0, (base2, gens2, 2, 0)) [0, 2, 1, 3, 4, 5] """ from sympy.combinatorics.perm_groups import PermutationGroup from sympy.combinatorics.tensor_can import gens_products, dummy_sgs from sympy.combinatorics.permutations import Permutation, _af_rmul v1 = [] for i in range(len(v)): base_i, gens_i, n_i, sym_i = v[i] v1.append((base_i, gens_i, [[]]*n_i, sym_i)) size, sbase, sgens = gens_products(*v1) dgens = dummy_sgs(dummies, sym, size-2) if isinstance(sym, int): num_types = 1 dummies = [dummies] sym = [sym] else: num_types = len(sym) dgens = [] for i in range(num_types): dgens.extend(dummy_sgs(dummies[i], sym[i], size - 2)) S = PermutationGroup(sgens) D = PermutationGroup([Permutation(x) for x in dgens]) dlist = list(D.generate(af=True)) g = g.array_form st = set() for s in S.generate(af=True): h = _af_rmul(g, s) for d in dlist: q = tuple(_af_rmul(d, h)) st.add(q) a = list(st) a.sort() prev = (0,)*size for h in a: if h[:-2] == prev[:-2]: if h[-1] != prev[-1]: return 0 prev = h return list(a[0]) def graph_certificate(gr): """ Return a certificate for the graph Parameters ========== gr : adjacency list Explanation =========== The graph is assumed to be unoriented and without external lines. Associate to each vertex of the graph a symmetric tensor with number of indices equal to the degree of the vertex; indices are contracted when they correspond to the same line of the graph. The canonical form of the tensor gives a certificate for the graph. This is not an efficient algorithm to get the certificate of a graph. Examples ======== >>> from sympy.combinatorics.testutil import graph_certificate >>> gr1 = {0:[1, 2, 3, 5], 1:[0, 2, 4], 2:[0, 1, 3, 4], 3:[0, 2, 4], 4:[1, 2, 3, 5], 5:[0, 4]} >>> gr2 = {0:[1, 5], 1:[0, 2, 3, 4], 2:[1, 3, 5], 3:[1, 2, 4, 5], 4:[1, 3, 5], 5:[0, 2, 3, 4]} >>> c1 = graph_certificate(gr1) >>> c2 = graph_certificate(gr2) >>> c1 [0, 2, 4, 6, 1, 8, 10, 12, 3, 14, 16, 18, 5, 9, 15, 7, 11, 17, 13, 19, 20, 21] >>> c1 == c2 True """ from sympy.combinatorics.permutations import _af_invert from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, canonicalize items = list(gr.items()) items.sort(key=lambda x: len(x[1]), reverse=True) pvert = [x[0] for x in items] pvert = _af_invert(pvert) # the indices of the tensor are twice the number of lines of the graph num_indices = 0 for v, neigh in items: num_indices += len(neigh) # associate to each vertex its indices; for each line # between two vertices assign the # even index to the vertex which comes first in items, # the odd index to the other vertex vertices = [[] for i in items] i = 0 for v, neigh in items: for v2 in neigh: if pvert[v] < pvert[v2]: vertices[pvert[v]].append(i) vertices[pvert[v2]].append(i+1) i += 2 g = [] for v in vertices: g.extend(v) assert len(g) == num_indices g += [num_indices, num_indices + 1] size = num_indices + 2 assert sorted(g) == list(range(size)) g = Permutation(g) vlen = [0]*(len(vertices[0])+1) for neigh in vertices: vlen[len(neigh)] += 1 v = [] for i in range(len(vlen)): n = vlen[i] if n: base, gens = get_symmetric_group_sgs(i) v.append((base, gens, n, 0)) v.reverse() dummies = list(range(num_indices)) can = canonicalize(g, dummies, 0, *v) return can sympy-sympy-1.9/sympy/combinatorics/util.py000066400000000000000000000400471412543434000212740ustar00rootroot00000000000000from sympy.combinatorics.permutations import Permutation, _af_invert, _af_rmul from sympy.ntheory import isprime rmul = Permutation.rmul _af_new = Permutation._af_new ############################################ # # Utilities for computational group theory # ############################################ def _base_ordering(base, degree): r""" Order `\{0, 1, ..., n-1\}` so that base points come first and in order. Parameters ========== ``base`` : the base ``degree`` : the degree of the associated permutation group Returns ======= A list ``base_ordering`` such that ``base_ordering[point]`` is the number of ``point`` in the ordering. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.util import _base_ordering >>> S = SymmetricGroup(4) >>> S.schreier_sims() >>> _base_ordering(S.base, S.degree) [0, 1, 2, 3] Notes ===== This is used in backtrack searches, when we define a relation `<<` on the underlying set for a permutation group of degree `n`, `\{0, 1, ..., n-1\}`, so that if `(b_1, b_2, ..., b_k)` is a base we have `b_i << b_j` whenever `i>> from sympy.combinatorics.util import _check_cycles_alt_sym >>> from sympy.combinatorics.permutations import Permutation >>> a = Permutation([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], [11, 12]]) >>> _check_cycles_alt_sym(a) False >>> b = Permutation([[0, 1, 2, 3, 4, 5, 6], [7, 8, 9, 10]]) >>> _check_cycles_alt_sym(b) True See Also ======== sympy.combinatorics.perm_groups.PermutationGroup.is_alt_sym """ n = perm.size af = perm.array_form current_len = 0 total_len = 0 used = set() for i in range(n//2): if not i in used and i < n//2 - total_len: current_len = 1 used.add(i) j = i while af[j] != i: current_len += 1 j = af[j] used.add(j) total_len += current_len if current_len > n//2 and current_len < n - 2 and isprime(current_len): return True return False def _distribute_gens_by_base(base, gens): r""" Distribute the group elements ``gens`` by membership in basic stabilizers. Explanation =========== Notice that for a base `(b_1, b_2, ..., b_k)`, the basic stabilizers are defined as `G^{(i)} = G_{b_1, ..., b_{i-1}}` for `i \in\{1, 2, ..., k\}`. Parameters ========== ``base`` : a sequence of points in `\{0, 1, ..., n-1\}` ``gens`` : a list of elements of a permutation group of degree `n`. Returns ======= List of length `k`, where `k` is the length of ``base``. The `i`-th entry contains those elements in ``gens`` which fix the first `i` elements of ``base`` (so that the `0`-th entry is equal to ``gens`` itself). If no element fixes the first `i` elements of ``base``, the `i`-th element is set to a list containing the identity element. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> from sympy.combinatorics.util import _distribute_gens_by_base >>> D = DihedralGroup(3) >>> D.schreier_sims() >>> D.strong_gens [(0 1 2), (0 2), (1 2)] >>> D.base [0, 1] >>> _distribute_gens_by_base(D.base, D.strong_gens) [[(0 1 2), (0 2), (1 2)], [(1 2)]] See Also ======== _strong_gens_from_distr, _orbits_transversals_from_bsgs, _handle_precomputed_bsgs """ base_len = len(base) degree = gens[0].size stabs = [[] for _ in range(base_len)] max_stab_index = 0 for gen in gens: j = 0 while j < base_len - 1 and gen._array_form[base[j]] == base[j]: j += 1 if j > max_stab_index: max_stab_index = j for k in range(j + 1): stabs[k].append(gen) for i in range(max_stab_index + 1, base_len): stabs[i].append(_af_new(list(range(degree)))) return stabs def _handle_precomputed_bsgs(base, strong_gens, transversals=None, basic_orbits=None, strong_gens_distr=None): """ Calculate BSGS-related structures from those present. Explanation =========== The base and strong generating set must be provided; if any of the transversals, basic orbits or distributed strong generators are not provided, they will be calculated from the base and strong generating set. Parameters ========== ``base`` - the base ``strong_gens`` - the strong generators ``transversals`` - basic transversals ``basic_orbits`` - basic orbits ``strong_gens_distr`` - strong generators distributed by membership in basic stabilizers Returns ======= ``(transversals, basic_orbits, strong_gens_distr)`` where ``transversals`` are the basic transversals, ``basic_orbits`` are the basic orbits, and ``strong_gens_distr`` are the strong generators distributed by membership in basic stabilizers. Examples ======== >>> from sympy.combinatorics.named_groups import DihedralGroup >>> from sympy.combinatorics.util import _handle_precomputed_bsgs >>> D = DihedralGroup(3) >>> D.schreier_sims() >>> _handle_precomputed_bsgs(D.base, D.strong_gens, ... basic_orbits=D.basic_orbits) ([{0: (2), 1: (0 1 2), 2: (0 2)}, {1: (2), 2: (1 2)}], [[0, 1, 2], [1, 2]], [[(0 1 2), (0 2), (1 2)], [(1 2)]]) See Also ======== _orbits_transversals_from_bsgs, _distribute_gens_by_base """ if strong_gens_distr is None: strong_gens_distr = _distribute_gens_by_base(base, strong_gens) if transversals is None: if basic_orbits is None: basic_orbits, transversals = \ _orbits_transversals_from_bsgs(base, strong_gens_distr) else: transversals = \ _orbits_transversals_from_bsgs(base, strong_gens_distr, transversals_only=True) else: if basic_orbits is None: base_len = len(base) basic_orbits = [None]*base_len for i in range(base_len): basic_orbits[i] = list(transversals[i].keys()) return transversals, basic_orbits, strong_gens_distr def _orbits_transversals_from_bsgs(base, strong_gens_distr, transversals_only=False, slp=False): """ Compute basic orbits and transversals from a base and strong generating set. Explanation =========== The generators are provided as distributed across the basic stabilizers. If the optional argument ``transversals_only`` is set to True, only the transversals are returned. Parameters ========== ``base`` - The base. ``strong_gens_distr`` - Strong generators distributed by membership in basic stabilizers. ``transversals_only`` - bool A flag switching between returning only the transversals and both orbits and transversals. ``slp`` - If ``True``, return a list of dictionaries containing the generator presentations of the elements of the transversals, i.e. the list of indices of generators from ``strong_gens_distr[i]`` such that their product is the relevant transversal element. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.util import _distribute_gens_by_base >>> S = SymmetricGroup(3) >>> S.schreier_sims() >>> strong_gens_distr = _distribute_gens_by_base(S.base, S.strong_gens) >>> (S.base, strong_gens_distr) ([0, 1], [[(0 1 2), (2)(0 1), (1 2)], [(1 2)]]) See Also ======== _distribute_gens_by_base, _handle_precomputed_bsgs """ from sympy.combinatorics.perm_groups import _orbit_transversal base_len = len(base) degree = strong_gens_distr[0][0].size transversals = [None]*base_len slps = [None]*base_len if transversals_only is False: basic_orbits = [None]*base_len for i in range(base_len): transversals[i], slps[i] = _orbit_transversal(degree, strong_gens_distr[i], base[i], pairs=True, slp=True) transversals[i] = dict(transversals[i]) if transversals_only is False: basic_orbits[i] = list(transversals[i].keys()) if transversals_only: return transversals else: if not slp: return basic_orbits, transversals return basic_orbits, transversals, slps def _remove_gens(base, strong_gens, basic_orbits=None, strong_gens_distr=None): """ Remove redundant generators from a strong generating set. Parameters ========== ``base`` - a base ``strong_gens`` - a strong generating set relative to ``base`` ``basic_orbits`` - basic orbits ``strong_gens_distr`` - strong generators distributed by membership in basic stabilizers Returns ======= A strong generating set with respect to ``base`` which is a subset of ``strong_gens``. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.util import _remove_gens >>> from sympy.combinatorics.testutil import _verify_bsgs >>> S = SymmetricGroup(15) >>> base, strong_gens = S.schreier_sims_incremental() >>> new_gens = _remove_gens(base, strong_gens) >>> len(new_gens) 14 >>> _verify_bsgs(S, base, new_gens) True Notes ===== This procedure is outlined in [1],p.95. References ========== .. [1] Holt, D., Eick, B., O'Brien, E. "Handbook of computational group theory" """ from sympy.combinatorics.perm_groups import _orbit base_len = len(base) degree = strong_gens[0].size if strong_gens_distr is None: strong_gens_distr = _distribute_gens_by_base(base, strong_gens) if basic_orbits is None: basic_orbits = [] for i in range(base_len): basic_orbit = _orbit(degree, strong_gens_distr[i], base[i]) basic_orbits.append(basic_orbit) strong_gens_distr.append([]) res = strong_gens[:] for i in range(base_len - 1, -1, -1): gens_copy = strong_gens_distr[i][:] for gen in strong_gens_distr[i]: if gen not in strong_gens_distr[i + 1]: temp_gens = gens_copy[:] temp_gens.remove(gen) if temp_gens == []: continue temp_orbit = _orbit(degree, temp_gens, base[i]) if temp_orbit == basic_orbits[i]: gens_copy.remove(gen) res.remove(gen) return res def _strip(g, base, orbits, transversals): """ Attempt to decompose a permutation using a (possibly partial) BSGS structure. Explanation =========== This is done by treating the sequence ``base`` as an actual base, and the orbits ``orbits`` and transversals ``transversals`` as basic orbits and transversals relative to it. This process is called "sifting". A sift is unsuccessful when a certain orbit element is not found or when after the sift the decomposition doesn't end with the identity element. The argument ``transversals`` is a list of dictionaries that provides transversal elements for the orbits ``orbits``. Parameters ========== ``g`` - permutation to be decomposed ``base`` - sequence of points ``orbits`` - a list in which the ``i``-th entry is an orbit of ``base[i]`` under some subgroup of the pointwise stabilizer of ` `base[0], base[1], ..., base[i - 1]``. The groups themselves are implicit in this function since the only information we need is encoded in the orbits and transversals ``transversals`` - a list of orbit transversals associated with the orbits ``orbits``. Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.permutations import Permutation >>> from sympy.combinatorics.util import _strip >>> S = SymmetricGroup(5) >>> S.schreier_sims() >>> g = Permutation([0, 2, 3, 1, 4]) >>> _strip(g, S.base, S.basic_orbits, S.basic_transversals) ((4), 5) Notes ===== The algorithm is described in [1],pp.89-90. The reason for returning both the current state of the element being decomposed and the level at which the sifting ends is that they provide important information for the randomized version of the Schreier-Sims algorithm. References ========== .. [1] Holt, D., Eick, B., O'Brien, E."Handbook of computational group theory" See Also ======== sympy.combinatorics.perm_groups.PermutationGroup.schreier_sims sympy.combinatorics.perm_groups.PermutationGroup.schreier_sims_random """ h = g._array_form base_len = len(base) for i in range(base_len): beta = h[base[i]] if beta == base[i]: continue if beta not in orbits[i]: return _af_new(h), i + 1 u = transversals[i][beta]._array_form h = _af_rmul(_af_invert(u), h) return _af_new(h), base_len + 1 def _strip_af(h, base, orbits, transversals, j, slp=[], slps={}): """ optimized _strip, with h, transversals and result in array form if the stripped elements is the identity, it returns False, base_len + 1 j h[base[i]] == base[i] for i <= j """ base_len = len(base) for i in range(j+1, base_len): beta = h[base[i]] if beta == base[i]: continue if beta not in orbits[i]: if not slp: return h, i + 1 return h, i + 1, slp u = transversals[i][beta] if h == u: if not slp: return False, base_len + 1 return False, base_len + 1, slp h = _af_rmul(_af_invert(u), h) if slp: u_slp = slps[i][beta][:] u_slp.reverse() u_slp = [(i, (g,)) for g in u_slp] slp = u_slp + slp if not slp: return h, base_len + 1 return h, base_len + 1, slp def _strong_gens_from_distr(strong_gens_distr): """ Retrieve strong generating set from generators of basic stabilizers. This is just the union of the generators of the first and second basic stabilizers. Parameters ========== ``strong_gens_distr`` - strong generators distributed by membership in basic stabilizers Examples ======== >>> from sympy.combinatorics.named_groups import SymmetricGroup >>> from sympy.combinatorics.util import (_strong_gens_from_distr, ... _distribute_gens_by_base) >>> S = SymmetricGroup(3) >>> S.schreier_sims() >>> S.strong_gens [(0 1 2), (2)(0 1), (1 2)] >>> strong_gens_distr = _distribute_gens_by_base(S.base, S.strong_gens) >>> _strong_gens_from_distr(strong_gens_distr) [(0 1 2), (2)(0 1), (1 2)] See Also ======== _distribute_gens_by_base """ if len(strong_gens_distr) == 1: return strong_gens_distr[0][:] else: result = strong_gens_distr[0] for gen in strong_gens_distr[1]: if gen not in result: result.append(gen) return result sympy-sympy-1.9/sympy/concrete/000077500000000000000000000000001412543434000167065ustar00rootroot00000000000000sympy-sympy-1.9/sympy/concrete/__init__.py000066400000000000000000000002201412543434000210110ustar00rootroot00000000000000from .products import product, Product from .summations import summation, Sum __all__ = [ 'product', 'Product', 'summation', 'Sum', ] sympy-sympy-1.9/sympy/concrete/delta.py000066400000000000000000000235671412543434000203660ustar00rootroot00000000000000""" This module implements sums and products containing the Kronecker Delta function. References ========== .. [1] http://mathworld.wolfram.com/KroneckerDelta.html """ from sympy.core import Add, Mul, S, Dummy from sympy.core.cache import cacheit from sympy.core.compatibility import default_sort_key from sympy.functions import KroneckerDelta, Piecewise, piecewise_fold from sympy.sets import Interval @cacheit def _expand_delta(expr, index): """ Expand the first Add containing a simple KroneckerDelta. """ if not expr.is_Mul: return expr delta = None func = Add terms = [S.One] for h in expr.args: if delta is None and h.is_Add and _has_simple_delta(h, index): delta = True func = h.func terms = [terms[0]*t for t in h.args] else: terms = [t*h for t in terms] return func(*terms) @cacheit def _extract_delta(expr, index): """ Extract a simple KroneckerDelta from the expression. Explanation =========== Returns the tuple ``(delta, newexpr)`` where: - ``delta`` is a simple KroneckerDelta expression if one was found, or ``None`` if no simple KroneckerDelta expression was found. - ``newexpr`` is a Mul containing the remaining terms; ``expr`` is returned unchanged if no simple KroneckerDelta expression was found. Examples ======== >>> from sympy import KroneckerDelta >>> from sympy.concrete.delta import _extract_delta >>> from sympy.abc import x, y, i, j, k >>> _extract_delta(4*x*y*KroneckerDelta(i, j), i) (KroneckerDelta(i, j), 4*x*y) >>> _extract_delta(4*x*y*KroneckerDelta(i, j), k) (None, 4*x*y*KroneckerDelta(i, j)) See Also ======== sympy.functions.special.tensor_functions.KroneckerDelta deltaproduct deltasummation """ if not _has_simple_delta(expr, index): return (None, expr) if isinstance(expr, KroneckerDelta): return (expr, S.One) if not expr.is_Mul: raise ValueError("Incorrect expr") delta = None terms = [] for arg in expr.args: if delta is None and _is_simple_delta(arg, index): delta = arg else: terms.append(arg) return (delta, expr.func(*terms)) @cacheit def _has_simple_delta(expr, index): """ Returns True if ``expr`` is an expression that contains a KroneckerDelta that is simple in the index ``index``, meaning that this KroneckerDelta is nonzero for a single value of the index ``index``. """ if expr.has(KroneckerDelta): if _is_simple_delta(expr, index): return True if expr.is_Add or expr.is_Mul: for arg in expr.args: if _has_simple_delta(arg, index): return True return False @cacheit def _is_simple_delta(delta, index): """ Returns True if ``delta`` is a KroneckerDelta and is nonzero for a single value of the index ``index``. """ if isinstance(delta, KroneckerDelta) and delta.has(index): p = (delta.args[0] - delta.args[1]).as_poly(index) if p: return p.degree() == 1 return False @cacheit def _remove_multiple_delta(expr): """ Evaluate products of KroneckerDelta's. """ from sympy.solvers import solve if expr.is_Add: return expr.func(*list(map(_remove_multiple_delta, expr.args))) if not expr.is_Mul: return expr eqs = [] newargs = [] for arg in expr.args: if isinstance(arg, KroneckerDelta): eqs.append(arg.args[0] - arg.args[1]) else: newargs.append(arg) if not eqs: return expr solns = solve(eqs, dict=True) if len(solns) == 0: return S.Zero elif len(solns) == 1: for key in solns[0].keys(): newargs.append(KroneckerDelta(key, solns[0][key])) expr2 = expr.func(*newargs) if expr != expr2: return _remove_multiple_delta(expr2) return expr @cacheit def _simplify_delta(expr): """ Rewrite a KroneckerDelta's indices in its simplest form. """ from sympy.solvers import solve if isinstance(expr, KroneckerDelta): try: slns = solve(expr.args[0] - expr.args[1], dict=True) if slns and len(slns) == 1: return Mul(*[KroneckerDelta(*(key, value)) for key, value in slns[0].items()]) except NotImplementedError: pass return expr @cacheit def deltaproduct(f, limit): """ Handle products containing a KroneckerDelta. See Also ======== deltasummation sympy.functions.special.tensor_functions.KroneckerDelta sympy.concrete.products.product """ from sympy.concrete.products import product if ((limit[2] - limit[1]) < 0) == True: return S.One if not f.has(KroneckerDelta): return product(f, limit) if f.is_Add: # Identify the term in the Add that has a simple KroneckerDelta delta = None terms = [] for arg in sorted(f.args, key=default_sort_key): if delta is None and _has_simple_delta(arg, limit[0]): delta = arg else: terms.append(arg) newexpr = f.func(*terms) k = Dummy("kprime", integer=True) if isinstance(limit[1], int) and isinstance(limit[2], int): result = deltaproduct(newexpr, limit) + sum([ deltaproduct(newexpr, (limit[0], limit[1], ik - 1)) * delta.subs(limit[0], ik) * deltaproduct(newexpr, (limit[0], ik + 1, limit[2])) for ik in range(int(limit[1]), int(limit[2] + 1))] ) else: result = deltaproduct(newexpr, limit) + deltasummation( deltaproduct(newexpr, (limit[0], limit[1], k - 1)) * delta.subs(limit[0], k) * deltaproduct(newexpr, (limit[0], k + 1, limit[2])), (k, limit[1], limit[2]), no_piecewise=_has_simple_delta(newexpr, limit[0]) ) return _remove_multiple_delta(result) delta, _ = _extract_delta(f, limit[0]) if not delta: g = _expand_delta(f, limit[0]) if f != g: from sympy import factor try: return factor(deltaproduct(g, limit)) except AssertionError: return deltaproduct(g, limit) return product(f, limit) return _remove_multiple_delta(f.subs(limit[0], limit[1])*KroneckerDelta(limit[2], limit[1])) + \ S.One*_simplify_delta(KroneckerDelta(limit[2], limit[1] - 1)) @cacheit def deltasummation(f, limit, no_piecewise=False): """ Handle summations containing a KroneckerDelta. Explanation =========== The idea for summation is the following: - If we are dealing with a KroneckerDelta expression, i.e. KroneckerDelta(g(x), j), we try to simplify it. If we could simplify it, then we sum the resulting expression. We already know we can sum a simplified expression, because only simple KroneckerDelta expressions are involved. If we couldn't simplify it, there are two cases: 1) The expression is a simple expression: we return the summation, taking care if we are dealing with a Derivative or with a proper KroneckerDelta. 2) The expression is not simple (i.e. KroneckerDelta(cos(x))): we can do nothing at all. - If the expr is a multiplication expr having a KroneckerDelta term: First we expand it. If the expansion did work, then we try to sum the expansion. If not, we try to extract a simple KroneckerDelta term, then we have two cases: 1) We have a simple KroneckerDelta term, so we return the summation. 2) We didn't have a simple term, but we do have an expression with simplified KroneckerDelta terms, so we sum this expression. Examples ======== >>> from sympy import oo, symbols >>> from sympy.abc import k >>> i, j = symbols('i, j', integer=True, finite=True) >>> from sympy.concrete.delta import deltasummation >>> from sympy import KroneckerDelta >>> deltasummation(KroneckerDelta(i, k), (k, -oo, oo)) 1 >>> deltasummation(KroneckerDelta(i, k), (k, 0, oo)) Piecewise((1, i >= 0), (0, True)) >>> deltasummation(KroneckerDelta(i, k), (k, 1, 3)) Piecewise((1, (i >= 1) & (i <= 3)), (0, True)) >>> deltasummation(k*KroneckerDelta(i, j)*KroneckerDelta(j, k), (k, -oo, oo)) j*KroneckerDelta(i, j) >>> deltasummation(j*KroneckerDelta(i, j), (j, -oo, oo)) i >>> deltasummation(i*KroneckerDelta(i, j), (i, -oo, oo)) j See Also ======== deltaproduct sympy.functions.special.tensor_functions.KroneckerDelta sympy.concrete.sums.summation """ from sympy.concrete.summations import summation from sympy.solvers import solve if ((limit[2] - limit[1]) < 0) == True: return S.Zero if not f.has(KroneckerDelta): return summation(f, limit) x = limit[0] g = _expand_delta(f, x) if g.is_Add: return piecewise_fold( g.func(*[deltasummation(h, limit, no_piecewise) for h in g.args])) # try to extract a simple KroneckerDelta term delta, expr = _extract_delta(g, x) if (delta is not None) and (delta.delta_range is not None): dinf, dsup = delta.delta_range if (limit[1] - dinf <= 0) == True and (limit[2] - dsup >= 0) == True: no_piecewise = True if not delta: return summation(f, limit) solns = solve(delta.args[0] - delta.args[1], x) if len(solns) == 0: return S.Zero elif len(solns) != 1: from sympy.concrete.summations import Sum return Sum(f, limit) value = solns[0] if no_piecewise: return expr.subs(x, value) return Piecewise( (expr.subs(x, value), Interval(*limit[1:3]).as_relational(value)), (S.Zero, True) ) sympy-sympy-1.9/sympy/concrete/expr_with_intlimits.py000066400000000000000000000261041412543434000233700ustar00rootroot00000000000000from sympy.concrete.expr_with_limits import ExprWithLimits from sympy.core.singleton import S from sympy.core.relational import Eq class ReorderError(NotImplementedError): """ Exception raised when trying to reorder dependent limits. """ def __init__(self, expr, msg): super().__init__( "%s could not be reordered: %s." % (expr, msg)) class ExprWithIntLimits(ExprWithLimits): """ Superclass for Product and Sum. See Also ======== sympy.concrete.expr_with_limits.ExprWithLimits sympy.concrete.products.Product sympy.concrete.summations.Sum """ def change_index(self, var, trafo, newvar=None): r""" Change index of a Sum or Product. Perform a linear transformation `x \mapsto a x + b` on the index variable `x`. For `a` the only values allowed are `\pm 1`. A new variable to be used after the change of index can also be specified. Explanation =========== ``change_index(expr, var, trafo, newvar=None)`` where ``var`` specifies the index variable `x` to transform. The transformation ``trafo`` must be linear and given in terms of ``var``. If the optional argument ``newvar`` is provided then ``var`` gets replaced by ``newvar`` in the final expression. Examples ======== >>> from sympy import Sum, Product, simplify >>> from sympy.abc import x, y, a, b, c, d, u, v, i, j, k, l >>> S = Sum(x, (x, a, b)) >>> S.doit() -a**2/2 + a/2 + b**2/2 + b/2 >>> Sn = S.change_index(x, x + 1, y) >>> Sn Sum(y - 1, (y, a + 1, b + 1)) >>> Sn.doit() -a**2/2 + a/2 + b**2/2 + b/2 >>> Sn = S.change_index(x, -x, y) >>> Sn Sum(-y, (y, -b, -a)) >>> Sn.doit() -a**2/2 + a/2 + b**2/2 + b/2 >>> Sn = S.change_index(x, x+u) >>> Sn Sum(-u + x, (x, a + u, b + u)) >>> Sn.doit() -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u >>> simplify(Sn.doit()) -a**2/2 + a/2 + b**2/2 + b/2 >>> Sn = S.change_index(x, -x - u, y) >>> Sn Sum(-u - y, (y, -b - u, -a - u)) >>> Sn.doit() -a**2/2 - a*u + a/2 + b**2/2 + b*u + b/2 - u*(-a + b + 1) + u >>> simplify(Sn.doit()) -a**2/2 + a/2 + b**2/2 + b/2 >>> P = Product(i*j**2, (i, a, b), (j, c, d)) >>> P Product(i*j**2, (i, a, b), (j, c, d)) >>> P2 = P.change_index(i, i+3, k) >>> P2 Product(j**2*(k - 3), (k, a + 3, b + 3), (j, c, d)) >>> P3 = P2.change_index(j, -j, l) >>> P3 Product(l**2*(k - 3), (k, a + 3, b + 3), (l, -d, -c)) When dealing with symbols only, we can make a general linear transformation: >>> Sn = S.change_index(x, u*x+v, y) >>> Sn Sum((-v + y)/u, (y, b*u + v, a*u + v)) >>> Sn.doit() -v*(a*u - b*u + 1)/u + (a**2*u**2/2 + a*u*v + a*u/2 - b**2*u**2/2 - b*u*v + b*u/2 + v)/u >>> simplify(Sn.doit()) a**2*u/2 + a/2 - b**2*u/2 + b/2 However, the last result can be inconsistent with usual summation where the index increment is always 1. This is obvious as we get back the original value only for ``u`` equal +1 or -1. See Also ======== sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index, reorder_limit, sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder, sympy.concrete.summations.Sum.reverse_order, sympy.concrete.products.Product.reverse_order """ if newvar is None: newvar = var limits = [] for limit in self.limits: if limit[0] == var: p = trafo.as_poly(var) if p.degree() != 1: raise ValueError("Index transformation is not linear") alpha = p.coeff_monomial(var) beta = p.coeff_monomial(S.One) if alpha.is_number: if alpha == S.One: limits.append((newvar, alpha*limit[1] + beta, alpha*limit[2] + beta)) elif alpha == S.NegativeOne: limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta)) else: raise ValueError("Linear transformation results in non-linear summation stepsize") else: # Note that the case of alpha being symbolic can give issues if alpha < 0. limits.append((newvar, alpha*limit[2] + beta, alpha*limit[1] + beta)) else: limits.append(limit) function = self.function.subs(var, (var - beta)/alpha) function = function.subs(var, newvar) return self.func(function, *limits) def index(expr, x): """ Return the index of a dummy variable in the list of limits. Explanation =========== ``index(expr, x)`` returns the index of the dummy variable ``x`` in the limits of ``expr``. Note that we start counting with 0 at the inner-most limits tuple. Examples ======== >>> from sympy.abc import x, y, a, b, c, d >>> from sympy import Sum, Product >>> Sum(x*y, (x, a, b), (y, c, d)).index(x) 0 >>> Sum(x*y, (x, a, b), (y, c, d)).index(y) 1 >>> Product(x*y, (x, a, b), (y, c, d)).index(x) 0 >>> Product(x*y, (x, a, b), (y, c, d)).index(y) 1 See Also ======== reorder_limit, reorder, sympy.concrete.summations.Sum.reverse_order, sympy.concrete.products.Product.reverse_order """ variables = [limit[0] for limit in expr.limits] if variables.count(x) != 1: raise ValueError(expr, "Number of instances of variable not equal to one") else: return variables.index(x) def reorder(expr, *arg): """ Reorder limits in a expression containing a Sum or a Product. Explanation =========== ``expr.reorder(*arg)`` reorders the limits in the expression ``expr`` according to the list of tuples given by ``arg``. These tuples can contain numerical indices or index variable names or involve both. Examples ======== >>> from sympy import Sum, Product >>> from sympy.abc import x, y, z, a, b, c, d, e, f >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((x, y)) Sum(x*y, (y, c, d), (x, a, b)) >>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder((x, y), (x, z), (y, z)) Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b)) >>> P = Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)) >>> P.reorder((x, y), (x, z), (y, z)) Product(x*y*z, (z, e, f), (y, c, d), (x, a, b)) We can also select the index variables by counting them, starting with the inner-most one: >>> Sum(x**2, (x, a, b), (x, c, d)).reorder((0, 1)) Sum(x**2, (x, c, d), (x, a, b)) And of course we can mix both schemes: >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, x)) Sum(x*y, (y, c, d), (x, a, b)) >>> Sum(x*y, (x, a, b), (y, c, d)).reorder((y, 0)) Sum(x*y, (y, c, d), (x, a, b)) See Also ======== reorder_limit, index, sympy.concrete.summations.Sum.reverse_order, sympy.concrete.products.Product.reverse_order """ new_expr = expr for r in arg: if len(r) != 2: raise ValueError(r, "Invalid number of arguments") index1 = r[0] index2 = r[1] if not isinstance(r[0], int): index1 = expr.index(r[0]) if not isinstance(r[1], int): index2 = expr.index(r[1]) new_expr = new_expr.reorder_limit(index1, index2) return new_expr def reorder_limit(expr, x, y): """ Interchange two limit tuples of a Sum or Product expression. Explanation =========== ``expr.reorder_limit(x, y)`` interchanges two limit tuples. The arguments ``x`` and ``y`` are integers corresponding to the index variables of the two limits which are to be interchanged. The expression ``expr`` has to be either a Sum or a Product. Examples ======== >>> from sympy.abc import x, y, z, a, b, c, d, e, f >>> from sympy import Sum, Product >>> Sum(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2) Sum(x*y*z, (z, e, f), (y, c, d), (x, a, b)) >>> Sum(x**2, (x, a, b), (x, c, d)).reorder_limit(1, 0) Sum(x**2, (x, c, d), (x, a, b)) >>> Product(x*y*z, (x, a, b), (y, c, d), (z, e, f)).reorder_limit(0, 2) Product(x*y*z, (z, e, f), (y, c, d), (x, a, b)) See Also ======== index, reorder, sympy.concrete.summations.Sum.reverse_order, sympy.concrete.products.Product.reverse_order """ var = {limit[0] for limit in expr.limits} limit_x = expr.limits[x] limit_y = expr.limits[y] if (len(set(limit_x[1].free_symbols).intersection(var)) == 0 and len(set(limit_x[2].free_symbols).intersection(var)) == 0 and len(set(limit_y[1].free_symbols).intersection(var)) == 0 and len(set(limit_y[2].free_symbols).intersection(var)) == 0): limits = [] for i, limit in enumerate(expr.limits): if i == x: limits.append(limit_y) elif i == y: limits.append(limit_x) else: limits.append(limit) return type(expr)(expr.function, *limits) else: raise ReorderError(expr, "could not interchange the two limits specified") @property def has_empty_sequence(self): """ Returns True if the Sum or Product is computed for an empty sequence. Examples ======== >>> from sympy import Sum, Product, Symbol >>> m = Symbol('m') >>> Sum(m, (m, 1, 0)).has_empty_sequence True >>> Sum(m, (m, 1, 1)).has_empty_sequence False >>> M = Symbol('M', integer=True, positive=True) >>> Product(m, (m, 1, M)).has_empty_sequence False >>> Product(m, (m, 2, M)).has_empty_sequence >>> Product(m, (m, M + 1, M)).has_empty_sequence True >>> N = Symbol('N', integer=True, positive=True) >>> Sum(m, (m, N, M)).has_empty_sequence >>> N = Symbol('N', integer=True, negative=True) >>> Sum(m, (m, N, M)).has_empty_sequence False See Also ======== has_reversed_limits has_finite_limits """ ret_None = False for lim in self.limits: dif = lim[1] - lim[2] eq = Eq(dif, 1) if eq == True: return True elif eq == False: continue else: ret_None = True if ret_None: return None return False sympy-sympy-1.9/sympy/concrete/expr_with_limits.py000066400000000000000000000457111412543434000226620ustar00rootroot00000000000000from sympy.core.add import Add from sympy.core.compatibility import is_sequence from sympy.core.containers import Tuple from sympy.core.expr import Expr from sympy.core.mul import Mul from sympy.core.relational import Equality, Relational from sympy.core.singleton import S from sympy.core.symbol import Symbol, Dummy from sympy.core.sympify import sympify from sympy.functions.elementary.piecewise import (piecewise_fold, Piecewise) from sympy.logic.boolalg import BooleanFunction from sympy.tensor.indexed import Idx from sympy.sets.sets import Interval from sympy.sets.fancysets import Range from sympy.utilities import flatten from sympy.utilities.iterables import sift from sympy.utilities.exceptions import SymPyDeprecationWarning def _common_new(cls, function, *symbols, **assumptions): """Return either a special return value or the tuple, (function, limits, orientation). This code is common to both ExprWithLimits and AddWithLimits.""" function = sympify(function) if isinstance(function, Equality): # This transforms e.g. Integral(Eq(x, y)) to Eq(Integral(x), Integral(y)) # but that is only valid for definite integrals. limits, orientation = _process_limits(*symbols) if not (limits and all(len(limit) == 3 for limit in limits)): SymPyDeprecationWarning( feature='Integral(Eq(x, y))', useinstead='Eq(Integral(x, z), Integral(y, z))', issue=18053, deprecated_since_version=1.6, ).warn() lhs = function.lhs rhs = function.rhs return Equality(cls(lhs, *symbols, **assumptions), \ cls(rhs, *symbols, **assumptions)) if function is S.NaN: return S.NaN if symbols: limits, orientation = _process_limits(*symbols) for i, li in enumerate(limits): if len(li) == 4: function = function.subs(li[0], li[-1]) limits[i] = Tuple(*li[:-1]) else: # symbol not provided -- we can still try to compute a general form free = function.free_symbols if len(free) != 1: raise ValueError( "specify dummy variables for %s" % function) limits, orientation = [Tuple(s) for s in free], 1 # denest any nested calls while cls == type(function): limits = list(function.limits) + limits function = function.function # Any embedded piecewise functions need to be brought out to the # top level. We only fold Piecewise that contain the integration # variable. reps = {} symbols_of_integration = {i[0] for i in limits} for p in function.atoms(Piecewise): if not p.has(*symbols_of_integration): reps[p] = Dummy() # mask off those that don't function = function.xreplace(reps) # do the fold function = piecewise_fold(function) # remove the masking function = function.xreplace({v: k for k, v in reps.items()}) return function, limits, orientation def _process_limits(*symbols): """Process the list of symbols and convert them to canonical limits, storing them as Tuple(symbol, lower, upper). The orientation of the function is also returned when the upper limit is missing so (x, 1, None) becomes (x, None, 1) and the orientation is changed. """ limits = [] orientation = 1 for V in symbols: if isinstance(V, (Relational, BooleanFunction)): variable = V.atoms(Symbol).pop() V = (variable, V.as_set()) if isinstance(V, Symbol) or getattr(V, '_diff_wrt', False): if isinstance(V, Idx): if V.lower is None or V.upper is None: limits.append(Tuple(V)) else: limits.append(Tuple(V, V.lower, V.upper)) else: limits.append(Tuple(V)) continue elif is_sequence(V, Tuple): if len(V) == 2 and isinstance(V[1], Range): lo = V[1].inf hi = V[1].sup dx = abs(V[1].step) V = [V[0]] + [0, (hi - lo)//dx, dx*V[0] + lo] V = sympify(flatten(V)) # a list of sympified elements if isinstance(V[0], (Symbol, Idx)) or getattr(V[0], '_diff_wrt', False): newsymbol = V[0] if len(V) == 2 and isinstance(V[1], Interval): # 2 -> 3 # Interval V[1:] = [V[1].start, V[1].end] elif len(V) == 3: # general case if V[2] is None and not V[1] is None: orientation *= -1 V = [newsymbol] + [i for i in V[1:] if i is not None] if not isinstance(newsymbol, Idx) or len(V) == 3: if len(V) == 4: limits.append(Tuple(*V)) continue if len(V) == 3: if isinstance(newsymbol, Idx): # Idx represents an integer which may have # specified values it can take on; if it is # given such a value, an error is raised here # if the summation would try to give it a larger # or smaller value than permitted. None and Symbolic # values will not raise an error. lo, hi = newsymbol.lower, newsymbol.upper try: if lo is not None and not bool(V[1] >= lo): raise ValueError("Summation will set Idx value too low.") except TypeError: pass try: if hi is not None and not bool(V[2] <= hi): raise ValueError("Summation will set Idx value too high.") except TypeError: pass limits.append(Tuple(*V)) continue if len(V) == 1 or (len(V) == 2 and V[1] is None): limits.append(Tuple(newsymbol)) continue elif len(V) == 2: limits.append(Tuple(newsymbol, V[1])) continue raise ValueError('Invalid limits given: %s' % str(symbols)) return limits, orientation class ExprWithLimits(Expr): __slots__ = ('is_commutative',) def __new__(cls, function, *symbols, **assumptions): pre = _common_new(cls, function, *symbols, **assumptions) if type(pre) is tuple: function, limits, _ = pre else: return pre # limits must have upper and lower bounds; the indefinite form # is not supported. This restriction does not apply to AddWithLimits if any(len(l) != 3 or None in l for l in limits): raise ValueError('ExprWithLimits requires values for lower and upper bounds.') obj = Expr.__new__(cls, **assumptions) arglist = [function] arglist.extend(limits) obj._args = tuple(arglist) obj.is_commutative = function.is_commutative # limits already checked return obj @property def function(self): """Return the function applied across limits. Examples ======== >>> from sympy import Integral >>> from sympy.abc import x >>> Integral(x**2, (x,)).function x**2 See Also ======== limits, variables, free_symbols """ return self._args[0] @property def kind(self): return self.function.kind @property def limits(self): """Return the limits of expression. Examples ======== >>> from sympy import Integral >>> from sympy.abc import x, i >>> Integral(x**i, (i, 1, 3)).limits ((i, 1, 3),) See Also ======== function, variables, free_symbols """ return self._args[1:] @property def variables(self): """Return a list of the limit variables. >>> from sympy import Sum >>> from sympy.abc import x, i >>> Sum(x**i, (i, 1, 3)).variables [i] See Also ======== function, limits, free_symbols as_dummy : Rename dummy variables sympy.integrals.integrals.Integral.transform : Perform mapping on the dummy variable """ return [l[0] for l in self.limits] @property def bound_symbols(self): """Return only variables that are dummy variables. Examples ======== >>> from sympy import Integral >>> from sympy.abc import x, i, j, k >>> Integral(x**i, (i, 1, 3), (j, 2), k).bound_symbols [i, j] See Also ======== function, limits, free_symbols as_dummy : Rename dummy variables sympy.integrals.integrals.Integral.transform : Perform mapping on the dummy variable """ return [l[0] for l in self.limits if len(l) != 1] @property def free_symbols(self): """ This method returns the symbols in the object, excluding those that take on a specific value (i.e. the dummy symbols). Examples ======== >>> from sympy import Sum >>> from sympy.abc import x, y >>> Sum(x, (x, y, 1)).free_symbols {y} """ # don't test for any special values -- nominal free symbols # should be returned, e.g. don't return set() if the # function is zero -- treat it like an unevaluated expression. function, limits = self.function, self.limits isyms = function.free_symbols for xab in limits: if len(xab) == 1: isyms.add(xab[0]) continue # take out the target symbol if xab[0] in isyms: isyms.remove(xab[0]) # add in the new symbols for i in xab[1:]: isyms.update(i.free_symbols) return isyms @property def is_number(self): """Return True if the Sum has no free symbols, else False.""" return not self.free_symbols def _eval_interval(self, x, a, b): limits = [(i if i[0] != x else (x, a, b)) for i in self.limits] integrand = self.function return self.func(integrand, *limits) def _eval_subs(self, old, new): """ Perform substitutions over non-dummy variables of an expression with limits. Also, can be used to specify point-evaluation of an abstract antiderivative. Examples ======== >>> from sympy import Sum, oo >>> from sympy.abc import s, n >>> Sum(1/n**s, (n, 1, oo)).subs(s, 2) Sum(n**(-2), (n, 1, oo)) >>> from sympy import Integral >>> from sympy.abc import x, a >>> Integral(a*x**2, x).subs(x, 4) Integral(a*x**2, (x, 4)) See Also ======== variables : Lists the integration variables transform : Perform mapping on the dummy variable for integrals change_index : Perform mapping on the sum and product dummy variables """ from sympy.core.function import AppliedUndef, UndefinedFunction func, limits = self.function, list(self.limits) # If one of the expressions we are replacing is used as a func index # one of two things happens. # - the old variable first appears as a free variable # so we perform all free substitutions before it becomes # a func index. # - the old variable first appears as a func index, in # which case we ignore. See change_index. # Reorder limits to match standard mathematical practice for scoping limits.reverse() if not isinstance(old, Symbol) or \ old.free_symbols.intersection(self.free_symbols): sub_into_func = True for i, xab in enumerate(limits): if 1 == len(xab) and old == xab[0]: if new._diff_wrt: xab = (new,) else: xab = (old, old) limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]]) if len(xab[0].free_symbols.intersection(old.free_symbols)) != 0: sub_into_func = False break if isinstance(old, AppliedUndef) or isinstance(old, UndefinedFunction): sy2 = set(self.variables).intersection(set(new.atoms(Symbol))) sy1 = set(self.variables).intersection(set(old.args)) if not sy2.issubset(sy1): raise ValueError( "substitution can not create dummy dependencies") sub_into_func = True if sub_into_func: func = func.subs(old, new) else: # old is a Symbol and a dummy variable of some limit for i, xab in enumerate(limits): if len(xab) == 3: limits[i] = Tuple(xab[0], *[l._subs(old, new) for l in xab[1:]]) if old == xab[0]: break # simplify redundant limits (x, x) to (x, ) for i, xab in enumerate(limits): if len(xab) == 2 and (xab[0] - xab[1]).is_zero: limits[i] = Tuple(xab[0], ) # Reorder limits back to representation-form limits.reverse() return self.func(func, *limits) @property def has_finite_limits(self): """ Returns True if the limits are known to be finite, either by the explicit bounds, assumptions on the bounds, or assumptions on the variables. False if known to be infinite, based on the bounds. None if not enough information is available to determine. Examples ======== >>> from sympy import Sum, Integral, Product, oo, Symbol >>> x = Symbol('x') >>> Sum(x, (x, 1, 8)).has_finite_limits True >>> Integral(x, (x, 1, oo)).has_finite_limits False >>> M = Symbol('M') >>> Sum(x, (x, 1, M)).has_finite_limits >>> N = Symbol('N', integer=True) >>> Product(x, (x, 1, N)).has_finite_limits True See Also ======== has_reversed_limits """ ret_None = False for lim in self.limits: if len(lim) == 3: if any(l.is_infinite for l in lim[1:]): # Any of the bounds are +/-oo return False elif any(l.is_infinite is None for l in lim[1:]): # Maybe there are assumptions on the variable? if lim[0].is_infinite is None: ret_None = True else: if lim[0].is_infinite is None: ret_None = True if ret_None: return None return True @property def has_reversed_limits(self): """ Returns True if the limits are known to be in reversed order, either by the explicit bounds, assumptions on the bounds, or assumptions on the variables. False if known to be in normal order, based on the bounds. None if not enough information is available to determine. Examples ======== >>> from sympy import Sum, Integral, Product, oo, Symbol >>> x = Symbol('x') >>> Sum(x, (x, 8, 1)).has_reversed_limits True >>> Sum(x, (x, 1, oo)).has_reversed_limits False >>> M = Symbol('M') >>> Integral(x, (x, 1, M)).has_reversed_limits >>> N = Symbol('N', integer=True, positive=True) >>> Sum(x, (x, 1, N)).has_reversed_limits False >>> Product(x, (x, 2, N)).has_reversed_limits >>> Product(x, (x, 2, N)).subs(N, N + 2).has_reversed_limits False See Also ======== sympy.concrete.expr_with_intlimits.ExprWithIntLimits.has_empty_sequence """ ret_None = False for lim in self.limits: if len(lim) == 3: var, a, b = lim dif = b - a if dif.is_extended_negative: return True elif dif.is_extended_nonnegative: continue else: ret_None = True else: return None if ret_None: return None return False class AddWithLimits(ExprWithLimits): r"""Represents unevaluated oriented additions. Parent class for Integral and Sum. """ def __new__(cls, function, *symbols, **assumptions): pre = _common_new(cls, function, *symbols, **assumptions) if type(pre) is tuple: function, limits, orientation = pre else: return pre obj = Expr.__new__(cls, **assumptions) arglist = [orientation*function] # orientation not used in ExprWithLimits arglist.extend(limits) obj._args = tuple(arglist) obj.is_commutative = function.is_commutative # limits already checked return obj def _eval_adjoint(self): if all([x.is_real for x in flatten(self.limits)]): return self.func(self.function.adjoint(), *self.limits) return None def _eval_conjugate(self): if all([x.is_real for x in flatten(self.limits)]): return self.func(self.function.conjugate(), *self.limits) return None def _eval_transpose(self): if all([x.is_real for x in flatten(self.limits)]): return self.func(self.function.transpose(), *self.limits) return None def _eval_factor(self, **hints): if 1 == len(self.limits): summand = self.function.factor(**hints) if summand.is_Mul: out = sift(summand.args, lambda w: w.is_commutative \ and not set(self.variables) & w.free_symbols) return Mul(*out[True])*self.func(Mul(*out[False]), \ *self.limits) else: summand = self.func(self.function, *self.limits[0:-1]).factor() if not summand.has(self.variables[-1]): return self.func(1, [self.limits[-1]]).doit()*summand elif isinstance(summand, Mul): return self.func(summand, self.limits[-1]).factor() return self def _eval_expand_basic(self, **hints): from sympy.matrices.matrices import MatrixBase summand = self.function.expand(**hints) if summand.is_Add and summand.is_commutative: return Add(*[self.func(i, *self.limits) for i in summand.args]) elif isinstance(summand, MatrixBase): return summand.applyfunc(lambda x: self.func(x, *self.limits)) elif summand != self.function: return self.func(summand, *self.limits) return self sympy-sympy-1.9/sympy/concrete/gosper.py000066400000000000000000000126671412543434000205730ustar00rootroot00000000000000"""Gosper's algorithm for hypergeometric summation. """ from sympy.core import S, Dummy, symbols from sympy.core.compatibility import is_sequence from sympy.polys import Poly, parallel_poly_from_expr, factor from sympy.solvers import solve from sympy.simplify import hypersimp def gosper_normal(f, g, n, polys=True): r""" Compute the Gosper's normal form of ``f`` and ``g``. Explanation =========== Given relatively prime univariate polynomials ``f`` and ``g``, rewrite their quotient to a normal form defined as follows: .. math:: \frac{f(n)}{g(n)} = Z \cdot \frac{A(n) C(n+1)}{B(n) C(n)} where ``Z`` is an arbitrary constant and ``A``, ``B``, ``C`` are monic polynomials in ``n`` with the following properties: 1. `\gcd(A(n), B(n+h)) = 1 \forall h \in \mathbb{N}` 2. `\gcd(B(n), C(n+1)) = 1` 3. `\gcd(A(n), C(n)) = 1` This normal form, or rational factorization in other words, is a crucial step in Gosper's algorithm and in solving of difference equations. It can be also used to decide if two hypergeometric terms are similar or not. This procedure will return a tuple containing elements of this factorization in the form ``(Z*A, B, C)``. Examples ======== >>> from sympy.concrete.gosper import gosper_normal >>> from sympy.abc import n >>> gosper_normal(4*n+5, 2*(4*n+1)*(2*n+3), n, polys=False) (1/4, n + 3/2, n + 1/4) """ (p, q), opt = parallel_poly_from_expr( (f, g), n, field=True, extension=True) a, A = p.LC(), p.monic() b, B = q.LC(), q.monic() C, Z = A.one, a/b h = Dummy('h') D = Poly(n + h, n, h, domain=opt.domain) R = A.resultant(B.compose(D)) roots = set(R.ground_roots().keys()) for r in set(roots): if not r.is_Integer or r < 0: roots.remove(r) for i in sorted(roots): d = A.gcd(B.shift(+i)) A = A.quo(d) B = B.quo(d.shift(-i)) for j in range(1, i + 1): C *= d.shift(-j) A = A.mul_ground(Z) if not polys: A = A.as_expr() B = B.as_expr() C = C.as_expr() return A, B, C def gosper_term(f, n): r""" Compute Gosper's hypergeometric term for ``f``. Explanation =========== Suppose ``f`` is a hypergeometric term such that: .. math:: s_n = \sum_{k=0}^{n-1} f_k and `f_k` doesn't depend on `n`. Returns a hypergeometric term `g_n` such that `g_{n+1} - g_n = f_n`. Examples ======== >>> from sympy.concrete.gosper import gosper_term >>> from sympy.functions import factorial >>> from sympy.abc import n >>> gosper_term((4*n + 1)*factorial(n)/factorial(2*n + 1), n) (-n - 1/2)/(n + 1/4) """ r = hypersimp(f, n) if r is None: return None # 'f' is *not* a hypergeometric term p, q = r.as_numer_denom() A, B, C = gosper_normal(p, q, n) B = B.shift(-1) N = S(A.degree()) M = S(B.degree()) K = S(C.degree()) if (N != M) or (A.LC() != B.LC()): D = {K - max(N, M)} elif not N: D = {K - N + 1, S.Zero} else: D = {K - N + 1, (B.nth(N - 1) - A.nth(N - 1))/A.LC()} for d in set(D): if not d.is_Integer or d < 0: D.remove(d) if not D: return None # 'f(n)' is *not* Gosper-summable d = max(D) coeffs = symbols('c:%s' % (d + 1), cls=Dummy) domain = A.get_domain().inject(*coeffs) x = Poly(coeffs, n, domain=domain) H = A*x.shift(1) - B*x - C solution = solve(H.coeffs(), coeffs) if solution is None: return None # 'f(n)' is *not* Gosper-summable x = x.as_expr().subs(solution) for coeff in coeffs: if coeff not in solution: x = x.subs(coeff, 0) if x.is_zero: return None # 'f(n)' is *not* Gosper-summable else: return B.as_expr()*x/C.as_expr() def gosper_sum(f, k): r""" Gosper's hypergeometric summation algorithm. Explanation =========== Given a hypergeometric term ``f`` such that: .. math :: s_n = \sum_{k=0}^{n-1} f_k and `f(n)` doesn't depend on `n`, returns `g_{n} - g(0)` where `g_{n+1} - g_n = f_n`, or ``None`` if `s_n` can not be expressed in closed form as a sum of hypergeometric terms. Examples ======== >>> from sympy.concrete.gosper import gosper_sum >>> from sympy.functions import factorial >>> from sympy.abc import n, k >>> f = (4*k + 1)*factorial(k)/factorial(2*k + 1) >>> gosper_sum(f, (k, 0, n)) (-factorial(n) + 2*factorial(2*n + 1))/factorial(2*n + 1) >>> _.subs(n, 2) == sum(f.subs(k, i) for i in [0, 1, 2]) True >>> gosper_sum(f, (k, 3, n)) (-60*factorial(n) + factorial(2*n + 1))/(60*factorial(2*n + 1)) >>> _.subs(n, 5) == sum(f.subs(k, i) for i in [3, 4, 5]) True References ========== .. [1] Marko Petkovsek, Herbert S. Wilf, Doron Zeilberger, A = B, AK Peters, Ltd., Wellesley, MA, USA, 1997, pp. 73--100 """ indefinite = False if is_sequence(k): k, a, b = k else: indefinite = True g = gosper_term(f, k) if g is None: return None if indefinite: result = f*g else: result = (f*(g + 1)).subs(k, b) - (f*g).subs(k, a) if result is S.NaN: try: result = (f*(g + 1)).limit(k, b) - (f*g).limit(k, a) except NotImplementedError: result = None return factor(result) sympy-sympy-1.9/sympy/concrete/guess.py000066400000000000000000000417351412543434000204200ustar00rootroot00000000000000"""Various algorithms for helping identifying numbers and sequences.""" from sympy.utilities import public from sympy.core import Function, Symbol from sympy.core.numbers import Zero from sympy import (sympify, floor, lcm, denom, Integer, Rational, exp, integrate, symbols, Product, product) from sympy.polys.polyfuncs import rational_interpolate as rinterp @public def find_simple_recurrence_vector(l): """ This function is used internally by other functions from the sympy.concrete.guess module. While most users may want to rather use the function find_simple_recurrence when looking for recurrence relations among rational numbers, the current function may still be useful when some post-processing has to be done. Explanation =========== The function returns a vector of length n when a recurrence relation of order n is detected in the sequence of rational numbers v. If the returned vector has a length 1, then the returned value is always the list [0], which means that no relation has been found. While the functions is intended to be used with rational numbers, it should work for other kinds of real numbers except for some cases involving quadratic numbers; for that reason it should be used with some caution when the argument is not a list of rational numbers. Examples ======== >>> from sympy.concrete.guess import find_simple_recurrence_vector >>> from sympy import fibonacci >>> find_simple_recurrence_vector([fibonacci(k) for k in range(12)]) [1, -1, -1] See Also ======== See the function sympy.concrete.guess.find_simple_recurrence which is more user-friendly. """ q1 = [0] q2 = [Integer(1)] b, z = 0, len(l) >> 1 while len(q2) <= z: while l[b]==0: b += 1 if b == len(l): c = 1 for x in q2: c = lcm(c, denom(x)) if q2[0]*c < 0: c = -c for k in range(len(q2)): q2[k] = int(q2[k]*c) return q2 a = Integer(1)/l[b] m = [a] for k in range(b+1, len(l)): m.append(-sum(l[j+1]*m[b-j-1] for j in range(b, k))*a) l, m = m, [0] * max(len(q2), b+len(q1)) for k in range(len(q2)): m[k] = a*q2[k] for k in range(b, b+len(q1)): m[k] += q1[k-b] while m[-1]==0: m.pop() # because trailing zeros can occur q1, q2, b = q2, m, 1 return [0] @public def find_simple_recurrence(v, A=Function('a'), N=Symbol('n')): """ Detects and returns a recurrence relation from a sequence of several integer (or rational) terms. The name of the function in the returned expression is 'a' by default; the main variable is 'n' by default. The smallest index in the returned expression is always n (and never n-1, n-2, etc.). Examples ======== >>> from sympy.concrete.guess import find_simple_recurrence >>> from sympy import fibonacci >>> find_simple_recurrence([fibonacci(k) for k in range(12)]) -a(n) - a(n + 1) + a(n + 2) >>> from sympy import Function, Symbol >>> a = [1, 1, 1] >>> for k in range(15): a.append(5*a[-1]-3*a[-2]+8*a[-3]) >>> find_simple_recurrence(a, A=Function('f'), N=Symbol('i')) -8*f(i) + 3*f(i + 1) - 5*f(i + 2) + f(i + 3) """ p = find_simple_recurrence_vector(v) n = len(p) if n <= 1: return Zero() rel = Zero() for k in range(n): rel += A(N+n-1-k)*p[k] return rel @public def rationalize(x, maxcoeff=10000): """ Helps identifying a rational number from a float (or mpmath.mpf) value by using a continued fraction. The algorithm stops as soon as a large partial quotient is detected (greater than 10000 by default). Examples ======== >>> from sympy.concrete.guess import rationalize >>> from mpmath import cos, pi >>> rationalize(cos(pi/3)) 1/2 >>> from mpmath import mpf >>> rationalize(mpf("0.333333333333333")) 1/3 While the function is rather intended to help 'identifying' rational values, it may be used in some cases for approximating real numbers. (Though other functions may be more relevant in that case.) >>> rationalize(pi, maxcoeff = 250) 355/113 See Also ======== Several other methods can approximate a real number as a rational, like: * fractions.Fraction.from_decimal * fractions.Fraction.from_float * mpmath.identify * mpmath.pslq by using the following syntax: mpmath.pslq([x, 1]) * mpmath.findpoly by using the following syntax: mpmath.findpoly(x, 1) * sympy.simplify.nsimplify (which is a more general function) The main difference between the current function and all these variants is that control focuses on magnitude of partial quotients here rather than on global precision of the approximation. If the real is "known to be" a rational number, the current function should be able to detect it correctly with the default settings even when denominator is great (unless its expansion contains unusually big partial quotients) which may occur when studying sequences of increasing numbers. If the user cares more on getting simple fractions, other methods may be more convenient. """ p0, p1 = 0, 1 q0, q1 = 1, 0 a = floor(x) while a < maxcoeff or q1==0: p = a*p1 + p0 q = a*q1 + q0 p0, p1 = p1, p q0, q1 = q1, q if x==a: break x = 1/(x-a) a = floor(x) return sympify(p) / q @public def guess_generating_function_rational(v, X=Symbol('x')): """ Tries to "guess" a rational generating function for a sequence of rational numbers v. Examples ======== >>> from sympy.concrete.guess import guess_generating_function_rational >>> from sympy import fibonacci >>> l = [fibonacci(k) for k in range(5,15)] >>> guess_generating_function_rational(l) (3*x + 5)/(-x**2 - x + 1) See Also ======== sympy.series.approximants mpmath.pade """ # a) compute the denominator as q q = find_simple_recurrence_vector(v) n = len(q) if n <= 1: return None # b) compute the numerator as p p = [sum(v[i-k]*q[k] for k in range(min(i+1, n))) for i in range(len(v)>>1)] return (sum(p[k]*X**k for k in range(len(p))) / sum(q[k]*X**k for k in range(n))) @public def guess_generating_function(v, X=Symbol('x'), types=['all'], maxsqrtn=2): """ Tries to "guess" a generating function for a sequence of rational numbers v. Only a few patterns are implemented yet. Explanation =========== The function returns a dictionary where keys are the name of a given type of generating function. Six types are currently implemented: type | formal definition -------+---------------------------------------------------------------- ogf | f(x) = Sum( a_k * x^k , k: 0..infinity ) egf | f(x) = Sum( a_k * x^k / k! , k: 0..infinity ) lgf | f(x) = Sum( (-1)^(k+1) a_k * x^k / k , k: 1..infinity ) | (with initial index being hold as 1 rather than 0) hlgf | f(x) = Sum( a_k * x^k / k , k: 1..infinity ) | (with initial index being hold as 1 rather than 0) lgdogf | f(x) = derivate( log(Sum( a_k * x^k, k: 0..infinity )), x) lgdegf | f(x) = derivate( log(Sum( a_k * x^k / k!, k: 0..infinity )), x) In order to spare time, the user can select only some types of generating functions (default being ['all']). While forgetting to use a list in the case of a single type may seem to work most of the time as in: types='ogf' this (convenient) syntax may lead to unexpected extra results in some cases. Discarding a type when calling the function does not mean that the type will not be present in the returned dictionary; it only means that no extra computation will be performed for that type, but the function may still add it in the result when it can be easily converted from another type. Two generating functions (lgdogf and lgdegf) are not even computed if the initial term of the sequence is 0; it may be useful in that case to try again after having removed the leading zeros. Examples ======== >>> from sympy.concrete.guess import guess_generating_function as ggf >>> ggf([k+1 for k in range(12)], types=['ogf', 'lgf', 'hlgf']) {'hlgf': 1/(1 - x), 'lgf': 1/(x + 1), 'ogf': 1/(x**2 - 2*x + 1)} >>> from sympy import sympify >>> l = sympify("[3/2, 11/2, 0, -121/2, -363/2, 121]") >>> ggf(l) {'ogf': (x + 3/2)/(11*x**2 - 3*x + 1)} >>> from sympy import fibonacci >>> ggf([fibonacci(k) for k in range(5, 15)], types=['ogf']) {'ogf': (3*x + 5)/(-x**2 - x + 1)} >>> from sympy import factorial >>> ggf([factorial(k) for k in range(12)], types=['ogf', 'egf', 'lgf']) {'egf': 1/(1 - x)} >>> ggf([k+1 for k in range(12)], types=['egf']) {'egf': (x + 1)*exp(x), 'lgdegf': (x + 2)/(x + 1)} N-th root of a rational function can also be detected (below is an example coming from the sequence A108626 from http://oeis.org). The greatest n-th root to be tested is specified as maxsqrtn (default 2). >>> ggf([1, 2, 5, 14, 41, 124, 383, 1200, 3799, 12122, 38919])['ogf'] sqrt(1/(x**4 + 2*x**2 - 4*x + 1)) References ========== .. [1] "Concrete Mathematics", R.L. Graham, D.E. Knuth, O. Patashnik .. [2] https://oeis.org/wiki/Generating_functions """ # List of all types of all g.f. known by the algorithm if 'all' in types: types = ['ogf', 'egf', 'lgf', 'hlgf', 'lgdogf', 'lgdegf'] result = {} # Ordinary Generating Function (ogf) if 'ogf' in types: # Perform some convolutions of the sequence with itself t = [1 if k==0 else 0 for k in range(len(v))] for d in range(max(1, maxsqrtn)): t = [sum(t[n-i]*v[i] for i in range(n+1)) for n in range(len(v))] g = guess_generating_function_rational(t, X=X) if g: result['ogf'] = g**Rational(1, d+1) break # Exponential Generating Function (egf) if 'egf' in types: # Transform sequence (division by factorial) w, f = [], Integer(1) for i, k in enumerate(v): f *= i if i else 1 w.append(k/f) # Perform some convolutions of the sequence with itself t = [1 if k==0 else 0 for k in range(len(w))] for d in range(max(1, maxsqrtn)): t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] g = guess_generating_function_rational(t, X=X) if g: result['egf'] = g**Rational(1, d+1) break # Logarithmic Generating Function (lgf) if 'lgf' in types: # Transform sequence (multiplication by (-1)^(n+1) / n) w, f = [], Integer(-1) for i, k in enumerate(v): f = -f w.append(f*k/Integer(i+1)) # Perform some convolutions of the sequence with itself t = [1 if k==0 else 0 for k in range(len(w))] for d in range(max(1, maxsqrtn)): t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] g = guess_generating_function_rational(t, X=X) if g: result['lgf'] = g**Rational(1, d+1) break # Hyperbolic logarithmic Generating Function (hlgf) if 'hlgf' in types: # Transform sequence (division by n+1) w = [] for i, k in enumerate(v): w.append(k/Integer(i+1)) # Perform some convolutions of the sequence with itself t = [1 if k==0 else 0 for k in range(len(w))] for d in range(max(1, maxsqrtn)): t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] g = guess_generating_function_rational(t, X=X) if g: result['hlgf'] = g**Rational(1, d+1) break # Logarithmic derivative of ordinary generating Function (lgdogf) if v[0] != 0 and ('lgdogf' in types or ('ogf' in types and 'ogf' not in result)): # Transform sequence by computing f'(x)/f(x) # because log(f(x)) = integrate( f'(x)/f(x) ) a, w = sympify(v[0]), [] for n in range(len(v)-1): w.append( (v[n+1]*(n+1) - sum(w[-i-1]*v[i+1] for i in range(n)))/a) # Perform some convolutions of the sequence with itself t = [1 if k==0 else 0 for k in range(len(w))] for d in range(max(1, maxsqrtn)): t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] g = guess_generating_function_rational(t, X=X) if g: result['lgdogf'] = g**Rational(1, d+1) if 'ogf' not in result: result['ogf'] = exp(integrate(result['lgdogf'], X)) break # Logarithmic derivative of exponential generating Function (lgdegf) if v[0] != 0 and ('lgdegf' in types or ('egf' in types and 'egf' not in result)): # Transform sequence / step 1 (division by factorial) z, f = [], Integer(1) for i, k in enumerate(v): f *= i if i else 1 z.append(k/f) # Transform sequence / step 2 by computing f'(x)/f(x) # because log(f(x)) = integrate( f'(x)/f(x) ) a, w = z[0], [] for n in range(len(z)-1): w.append( (z[n+1]*(n+1) - sum(w[-i-1]*z[i+1] for i in range(n)))/a) # Perform some convolutions of the sequence with itself t = [1 if k==0 else 0 for k in range(len(w))] for d in range(max(1, maxsqrtn)): t = [sum(t[n-i]*w[i] for i in range(n+1)) for n in range(len(w))] g = guess_generating_function_rational(t, X=X) if g: result['lgdegf'] = g**Rational(1, d+1) if 'egf' not in result: result['egf'] = exp(integrate(result['lgdegf'], X)) break return result @public def guess(l, all=False, evaluate=True, niter=2, variables=None): """ This function is adapted from the Rate.m package for Mathematica written by Christian Krattenthaler. It tries to guess a formula from a given sequence of rational numbers. Explanation =========== In order to speed up the process, the 'all' variable is set to False by default, stopping the computation as some results are returned during an iteration; the variable can be set to True if more iterations are needed (other formulas may be found; however they may be equivalent to the first ones). Another option is the 'evaluate' variable (default is True); setting it to False will leave the involved products unevaluated. By default, the number of iterations is set to 2 but a greater value (up to len(l)-1) can be specified with the optional 'niter' variable. More and more convoluted results are found when the order of the iteration gets higher: * first iteration returns polynomial or rational functions; * second iteration returns products of rising factorials and their inverses; * third iteration returns products of products of rising factorials and their inverses; * etc. The returned formulas contain symbols i0, i1, i2, ... where the main variables is i0 (and auxiliary variables are i1, i2, ...). A list of other symbols can be provided in the 'variables' option; the length of the least should be the value of 'niter' (more is acceptable but only the first symbols will be used); in this case, the main variable will be the first symbol in the list. Examples ======== >>> from sympy.concrete.guess import guess >>> guess([1,2,6,24,120], evaluate=False) [Product(i1 + 1, (i1, 1, i0 - 1))] >>> from sympy import symbols >>> r = guess([1,2,7,42,429,7436,218348,10850216], niter=4) >>> i0 = symbols("i0") >>> [r[0].subs(i0,n).doit() for n in range(1,10)] [1, 2, 7, 42, 429, 7436, 218348, 10850216, 911835460] """ if any(a==0 for a in l[:-1]): return [] N = len(l) niter = min(N-1, niter) myprod = product if evaluate else Product g = [] res = [] if variables is None: symb = symbols('i:'+str(niter)) else: symb = variables for k, s in enumerate(symb): g.append(l) n, r = len(l), [] for i in range(n-2-1, -1, -1): ri = rinterp(enumerate(g[k][:-1], start=1), i, X=s) if ((denom(ri).subs({s:n}) != 0) and (ri.subs({s:n}) - g[k][-1] == 0) and ri not in r): r.append(ri) if r: for i in range(k-1, -1, -1): r = list(map(lambda v: g[i][0] * myprod(v, (symb[i+1], 1, symb[i]-1)), r)) if not all: return r res += r l = [Rational(l[i+1], l[i]) for i in range(N-k-1)] return res sympy-sympy-1.9/sympy/concrete/products.py000066400000000000000000000444301412543434000211300ustar00rootroot00000000000000from sympy.core.mul import Mul from sympy.core.singleton import S from sympy.concrete.expr_with_intlimits import ExprWithIntLimits from sympy.core.exprtools import factor_terms from sympy.functions.elementary.exponential import exp, log from sympy.polys import quo, roots from sympy.simplify import powsimp from sympy.core.function import Derivative from sympy.core.symbol import Dummy, Symbol class Product(ExprWithIntLimits): r""" Represents unevaluated products. Explanation =========== ``Product`` represents a finite or infinite product, with the first argument being the general form of terms in the series, and the second argument being ``(dummy_variable, start, end)``, with ``dummy_variable`` taking all integer values from ``start`` through ``end``. In accordance with long-standing mathematical convention, the end term is included in the product. Finite products =============== For finite products (and products with symbolic limits assumed to be finite) we follow the analogue of the summation convention described by Karr [1], especially definition 3 of section 1.4. The product: .. math:: \prod_{m \leq i < n} f(i) has *the obvious meaning* for `m < n`, namely: .. math:: \prod_{m \leq i < n} f(i) = f(m) f(m+1) \cdot \ldots \cdot f(n-2) f(n-1) with the upper limit value `f(n)` excluded. The product over an empty set is one if and only if `m = n`: .. math:: \prod_{m \leq i < n} f(i) = 1 \quad \mathrm{for} \quad m = n Finally, for all other products over empty sets we assume the following definition: .. math:: \prod_{m \leq i < n} f(i) = \frac{1}{\prod_{n \leq i < m} f(i)} \quad \mathrm{for} \quad m > n It is important to note that above we define all products with the upper limit being exclusive. This is in contrast to the usual mathematical notation, but does not affect the product convention. Indeed we have: .. math:: \prod_{m \leq i < n} f(i) = \prod_{i = m}^{n - 1} f(i) where the difference in notation is intentional to emphasize the meaning, with limits typeset on the top being inclusive. Examples ======== >>> from sympy.abc import a, b, i, k, m, n, x >>> from sympy import Product, oo >>> Product(k, (k, 1, m)) Product(k, (k, 1, m)) >>> Product(k, (k, 1, m)).doit() factorial(m) >>> Product(k**2,(k, 1, m)) Product(k**2, (k, 1, m)) >>> Product(k**2,(k, 1, m)).doit() factorial(m)**2 Wallis' product for pi: >>> W = Product(2*i/(2*i-1) * 2*i/(2*i+1), (i, 1, oo)) >>> W Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, oo)) Direct computation currently fails: >>> W.doit() Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, oo)) But we can approach the infinite product by a limit of finite products: >>> from sympy import limit >>> W2 = Product(2*i/(2*i-1)*2*i/(2*i+1), (i, 1, n)) >>> W2 Product(4*i**2/((2*i - 1)*(2*i + 1)), (i, 1, n)) >>> W2e = W2.doit() >>> W2e 4**n*factorial(n)**2/(2**(2*n)*RisingFactorial(1/2, n)*RisingFactorial(3/2, n)) >>> limit(W2e, n, oo) pi/2 By the same formula we can compute sin(pi/2): >>> from sympy import combsimp, pi, gamma, simplify >>> P = pi * x * Product(1 - x**2/k**2, (k, 1, n)) >>> P = P.subs(x, pi/2) >>> P pi**2*Product(1 - pi**2/(4*k**2), (k, 1, n))/2 >>> Pe = P.doit() >>> Pe pi**2*RisingFactorial(1 - pi/2, n)*RisingFactorial(1 + pi/2, n)/(2*factorial(n)**2) >>> limit(Pe, n, oo).gammasimp() sin(pi**2/2) >>> Pe.rewrite(gamma) (-1)**n*pi**2*gamma(pi/2)*gamma(n + 1 + pi/2)/(2*gamma(1 + pi/2)*gamma(-n + pi/2)*gamma(n + 1)**2) Products with the lower limit being larger than the upper one: >>> Product(1/i, (i, 6, 1)).doit() 120 >>> Product(i, (i, 2, 5)).doit() 120 The empty product: >>> Product(i, (i, n, n-1)).doit() 1 An example showing that the symbolic result of a product is still valid for seemingly nonsensical values of the limits. Then the Karr convention allows us to give a perfectly valid interpretation to those products by interchanging the limits according to the above rules: >>> P = Product(2, (i, 10, n)).doit() >>> P 2**(n - 9) >>> P.subs(n, 5) 1/16 >>> Product(2, (i, 10, 5)).doit() 1/16 >>> 1/Product(2, (i, 6, 9)).doit() 1/16 An explicit example of the Karr summation convention applied to products: >>> P1 = Product(x, (i, a, b)).doit() >>> P1 x**(-a + b + 1) >>> P2 = Product(x, (i, b+1, a-1)).doit() >>> P2 x**(a - b - 1) >>> simplify(P1 * P2) 1 And another one: >>> P1 = Product(i, (i, b, a)).doit() >>> P1 RisingFactorial(b, a - b + 1) >>> P2 = Product(i, (i, a+1, b-1)).doit() >>> P2 RisingFactorial(a + 1, -a + b - 1) >>> P1 * P2 RisingFactorial(b, a - b + 1)*RisingFactorial(a + 1, -a + b - 1) >>> combsimp(P1 * P2) 1 See Also ======== Sum, summation product References ========== .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, Volume 28 Issue 2, April 1981, Pages 305-350 http://dl.acm.org/citation.cfm?doid=322248.322255 .. [2] https://en.wikipedia.org/wiki/Multiplication#Capital_Pi_notation .. [3] https://en.wikipedia.org/wiki/Empty_product """ __slots__ = ('is_commutative',) def __new__(cls, function, *symbols, **assumptions): obj = ExprWithIntLimits.__new__(cls, function, *symbols, **assumptions) return obj def _eval_rewrite_as_Sum(self, *args, **kwargs): from sympy.concrete.summations import Sum return exp(Sum(log(self.function), *self.limits)) @property def term(self): return self._args[0] function = term def _eval_is_zero(self): if self.has_empty_sequence: return False z = self.term.is_zero if z is True: return True if self.has_finite_limits: # A Product is zero only if its term is zero assuming finite limits. return z def _eval_is_extended_real(self): if self.has_empty_sequence: return True return self.function.is_extended_real def _eval_is_positive(self): if self.has_empty_sequence: return True if self.function.is_positive and self.has_finite_limits: return True def _eval_is_nonnegative(self): if self.has_empty_sequence: return True if self.function.is_nonnegative and self.has_finite_limits: return True def _eval_is_extended_nonnegative(self): if self.has_empty_sequence: return True if self.function.is_extended_nonnegative: return True def _eval_is_extended_nonpositive(self): if self.has_empty_sequence: return True def _eval_is_finite(self): if self.has_finite_limits and self.function.is_finite: return True def doit(self, **hints): # first make sure any definite limits have product # variables with matching assumptions reps = {} for xab in self.limits: # Must be imported here to avoid circular imports from .summations import _dummy_with_inherited_properties_concrete d = _dummy_with_inherited_properties_concrete(xab) if d: reps[xab[0]] = d if reps: undo = {v: k for k, v in reps.items()} did = self.xreplace(reps).doit(**hints) if type(did) is tuple: # when separate=True did = tuple([i.xreplace(undo) for i in did]) else: did = did.xreplace(undo) return did f = self.function for index, limit in enumerate(self.limits): i, a, b = limit dif = b - a if dif.is_integer and dif.is_negative: a, b = b + 1, a - 1 f = 1 / f g = self._eval_product(f, (i, a, b)) if g in (None, S.NaN): return self.func(powsimp(f), *self.limits[index:]) else: f = g if hints.get('deep', True): return f.doit(**hints) else: return powsimp(f) def _eval_adjoint(self): if self.is_commutative: return self.func(self.function.adjoint(), *self.limits) return None def _eval_conjugate(self): return self.func(self.function.conjugate(), *self.limits) def _eval_product(self, term, limits): from sympy.concrete.delta import deltaproduct, _has_simple_delta from sympy.concrete.summations import summation from sympy.functions import KroneckerDelta, RisingFactorial (k, a, n) = limits if k not in term.free_symbols: if (term - 1).is_zero: return S.One return term**(n - a + 1) if a == n: return term.subs(k, a) if term.has(KroneckerDelta) and _has_simple_delta(term, limits[0]): return deltaproduct(term, limits) dif = n - a definite = dif.is_Integer if definite and (dif < 100): return self._eval_product_direct(term, limits) elif term.is_polynomial(k): poly = term.as_poly(k) A = B = Q = S.One all_roots = roots(poly) M = 0 for r, m in all_roots.items(): M += m A *= RisingFactorial(a - r, n - a + 1)**m Q *= (n - r)**m if M < poly.degree(): arg = quo(poly, Q.as_poly(k)) B = self.func(arg, (k, a, n)).doit() return poly.LC()**(n - a + 1) * A * B elif term.is_Add: factored = factor_terms(term, fraction=True) if factored.is_Mul: return self._eval_product(factored, (k, a, n)) elif term.is_Mul: # Factor in part without the summation variable and part with without_k, with_k = term.as_coeff_mul(k) if len(with_k) >= 2: # More than one term including k, so still a multiplication exclude, include = [], [] for t in with_k: p = self._eval_product(t, (k, a, n)) if p is not None: exclude.append(p) else: include.append(t) if not exclude: return None else: arg = term._new_rawargs(*include) A = Mul(*exclude) B = self.func(arg, (k, a, n)).doit() return without_k**(n - a + 1)*A * B else: # Just a single term p = self._eval_product(with_k[0], (k, a, n)) if p is None: p = self.func(with_k[0], (k, a, n)).doit() return without_k**(n - a + 1)*p elif term.is_Pow: if not term.base.has(k): s = summation(term.exp, (k, a, n)) return term.base**s elif not term.exp.has(k): p = self._eval_product(term.base, (k, a, n)) if p is not None: return p**term.exp elif isinstance(term, Product): evaluated = term.doit() f = self._eval_product(evaluated, limits) if f is None: return self.func(evaluated, limits) else: return f if definite: return self._eval_product_direct(term, limits) def _eval_simplify(self, **kwargs): from sympy.simplify.simplify import product_simplify rv = product_simplify(self) return rv.doit() if kwargs['doit'] else rv def _eval_transpose(self): if self.is_commutative: return self.func(self.function.transpose(), *self.limits) return None def _eval_product_direct(self, term, limits): (k, a, n) = limits return Mul(*[term.subs(k, a + i) for i in range(n - a + 1)]) def _eval_derivative(self, x): from sympy.concrete.summations import Sum if isinstance(x, Symbol) and x not in self.free_symbols: return S.Zero f, limits = self.function, list(self.limits) limit = limits.pop(-1) if limits: f = self.func(f, *limits) i, a, b = limit if x in a.free_symbols or x in b.free_symbols: return None h = Dummy() rv = Sum( Product(f, (i, a, h - 1)) * Product(f, (i, h + 1, b)) * Derivative(f, x, evaluate=True).subs(i, h), (h, a, b)) return rv def is_convergent(self): r""" See docs of :obj:`.Sum.is_convergent()` for explanation of convergence in SymPy. Explanation =========== The infinite product: .. math:: \prod_{1 \leq i < \infty} f(i) is defined by the sequence of partial products: .. math:: \prod_{i=1}^{n} f(i) = f(1) f(2) \cdots f(n) as n increases without bound. The product converges to a non-zero value if and only if the sum: .. math:: \sum_{1 \leq i < \infty} \log{f(n)} converges. Examples ======== >>> from sympy import Product, Symbol, cos, pi, exp, oo >>> n = Symbol('n', integer=True) >>> Product(n/(n + 1), (n, 1, oo)).is_convergent() False >>> Product(1/n**2, (n, 1, oo)).is_convergent() False >>> Product(cos(pi/n), (n, 1, oo)).is_convergent() True >>> Product(exp(-n**2), (n, 1, oo)).is_convergent() False References ========== .. [1] https://en.wikipedia.org/wiki/Infinite_product """ from sympy.concrete.summations import Sum sequence_term = self.function log_sum = log(sequence_term) lim = self.limits try: is_conv = Sum(log_sum, *lim).is_convergent() except NotImplementedError: if Sum(sequence_term - 1, *lim).is_absolutely_convergent() is S.true: return S.true raise NotImplementedError("The algorithm to find the product convergence of %s " "is not yet implemented" % (sequence_term)) return is_conv def reverse_order(expr, *indices): """ Reverse the order of a limit in a Product. Explanation =========== ``reverse_order(expr, *indices)`` reverses some limits in the expression ``expr`` which can be either a ``Sum`` or a ``Product``. The selectors in the argument ``indices`` specify some indices whose limits get reversed. These selectors are either variable names or numerical indices counted starting from the inner-most limit tuple. Examples ======== >>> from sympy import gamma, Product, simplify, Sum >>> from sympy.abc import x, y, a, b, c, d >>> P = Product(x, (x, a, b)) >>> Pr = P.reverse_order(x) >>> Pr Product(1/x, (x, b + 1, a - 1)) >>> Pr = Pr.doit() >>> Pr 1/RisingFactorial(b + 1, a - b - 1) >>> simplify(Pr.rewrite(gamma)) Piecewise((gamma(b + 1)/gamma(a), b > -1), ((-1)**(-a + b + 1)*gamma(1 - a)/gamma(-b), True)) >>> P = P.doit() >>> P RisingFactorial(a, -a + b + 1) >>> simplify(P.rewrite(gamma)) Piecewise((gamma(b + 1)/gamma(a), a > 0), ((-1)**(-a + b + 1)*gamma(1 - a)/gamma(-b), True)) While one should prefer variable names when specifying which limits to reverse, the index counting notation comes in handy in case there are several symbols with the same name. >>> S = Sum(x*y, (x, a, b), (y, c, d)) >>> S Sum(x*y, (x, a, b), (y, c, d)) >>> S0 = S.reverse_order(0) >>> S0 Sum(-x*y, (x, b + 1, a - 1), (y, c, d)) >>> S1 = S0.reverse_order(1) >>> S1 Sum(x*y, (x, b + 1, a - 1), (y, d + 1, c - 1)) Of course we can mix both notations: >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(x, 1) Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(y, x) Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) See Also ======== sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index, reorder_limit, sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder References ========== .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, Volume 28 Issue 2, April 1981, Pages 305-350 http://dl.acm.org/citation.cfm?doid=322248.322255 """ l_indices = list(indices) for i, indx in enumerate(l_indices): if not isinstance(indx, int): l_indices[i] = expr.index(indx) e = 1 limits = [] for i, limit in enumerate(expr.limits): l = limit if i in l_indices: e = -e l = (limit[0], limit[2] + 1, limit[1] - 1) limits.append(l) return Product(expr.function ** e, *limits) def product(*args, **kwargs): r""" Compute the product. Explanation =========== The notation for symbols is similar to the notation used in Sum or Integral. product(f, (i, a, b)) computes the product of f with respect to i from a to b, i.e., :: b _____ product(f(n), (i, a, b)) = | | f(n) | | i = a If it cannot compute the product, it returns an unevaluated Product object. Repeated products can be computed by introducing additional symbols tuples:: Examples ======== >>> from sympy import product, symbols >>> i, n, m, k = symbols('i n m k', integer=True) >>> product(i, (i, 1, k)) factorial(k) >>> product(m, (i, 1, k)) m**k >>> product(i, (i, 1, k), (k, 1, n)) Product(factorial(k), (k, 1, n)) """ prod = Product(*args, **kwargs) if isinstance(prod, Product): return prod.doit(deep=False) else: return prod sympy-sympy-1.9/sympy/concrete/summations.py000066400000000000000000001510111412543434000214560ustar00rootroot00000000000000from sympy.calculus.singularities import is_decreasing from sympy.calculus.util import AccumulationBounds from sympy.concrete.expr_with_limits import AddWithLimits from sympy.concrete.expr_with_intlimits import ExprWithIntLimits from sympy.concrete.gosper import gosper_sum from sympy.core.add import Add from sympy.core.function import Derivative from sympy.core.mul import Mul from sympy.core.relational import Eq from sympy.core.singleton import S from sympy.core.symbol import Dummy, Wild, Symbol from sympy.functions.special.zeta_functions import zeta from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import cot, csc from sympy.logic.boolalg import And from sympy.polys import apart, together from sympy.polys.polyerrors import PolynomialError, PolificationFailed from sympy.polys.polytools import parallel_poly_from_expr from sympy.series.limitseq import limit_seq from sympy.series.order import O from sympy.series.residues import residue from sympy.sets.sets import FiniteSet from sympy.simplify import denom from sympy.simplify.combsimp import combsimp from sympy.simplify.powsimp import powsimp from sympy.solvers import solve from sympy.solvers.solveset import solveset from sympy.utilities.iterables import sift import itertools class Sum(AddWithLimits, ExprWithIntLimits): r""" Represents unevaluated summation. Explanation =========== ``Sum`` represents a finite or infinite series, with the first argument being the general form of terms in the series, and the second argument being ``(dummy_variable, start, end)``, with ``dummy_variable`` taking all integer values from ``start`` through ``end``. In accordance with long-standing mathematical convention, the end term is included in the summation. Finite sums =========== For finite sums (and sums with symbolic limits assumed to be finite) we follow the summation convention described by Karr [1], especially definition 3 of section 1.4. The sum: .. math:: \sum_{m \leq i < n} f(i) has *the obvious meaning* for `m < n`, namely: .. math:: \sum_{m \leq i < n} f(i) = f(m) + f(m+1) + \ldots + f(n-2) + f(n-1) with the upper limit value `f(n)` excluded. The sum over an empty set is zero if and only if `m = n`: .. math:: \sum_{m \leq i < n} f(i) = 0 \quad \mathrm{for} \quad m = n Finally, for all other sums over empty sets we assume the following definition: .. math:: \sum_{m \leq i < n} f(i) = - \sum_{n \leq i < m} f(i) \quad \mathrm{for} \quad m > n It is important to note that Karr defines all sums with the upper limit being exclusive. This is in contrast to the usual mathematical notation, but does not affect the summation convention. Indeed we have: .. math:: \sum_{m \leq i < n} f(i) = \sum_{i = m}^{n - 1} f(i) where the difference in notation is intentional to emphasize the meaning, with limits typeset on the top being inclusive. Examples ======== >>> from sympy.abc import i, k, m, n, x >>> from sympy import Sum, factorial, oo, IndexedBase, Function >>> Sum(k, (k, 1, m)) Sum(k, (k, 1, m)) >>> Sum(k, (k, 1, m)).doit() m**2/2 + m/2 >>> Sum(k**2, (k, 1, m)) Sum(k**2, (k, 1, m)) >>> Sum(k**2, (k, 1, m)).doit() m**3/3 + m**2/2 + m/6 >>> Sum(x**k, (k, 0, oo)) Sum(x**k, (k, 0, oo)) >>> Sum(x**k, (k, 0, oo)).doit() Piecewise((1/(1 - x), Abs(x) < 1), (Sum(x**k, (k, 0, oo)), True)) >>> Sum(x**k/factorial(k), (k, 0, oo)).doit() exp(x) Here are examples to do summation with symbolic indices. You can use either Function of IndexedBase classes: >>> f = Function('f') >>> Sum(f(n), (n, 0, 3)).doit() f(0) + f(1) + f(2) + f(3) >>> Sum(f(n), (n, 0, oo)).doit() Sum(f(n), (n, 0, oo)) >>> f = IndexedBase('f') >>> Sum(f[n]**2, (n, 0, 3)).doit() f[0]**2 + f[1]**2 + f[2]**2 + f[3]**2 An example showing that the symbolic result of a summation is still valid for seemingly nonsensical values of the limits. Then the Karr convention allows us to give a perfectly valid interpretation to those sums by interchanging the limits according to the above rules: >>> S = Sum(i, (i, 1, n)).doit() >>> S n**2/2 + n/2 >>> S.subs(n, -4) 6 >>> Sum(i, (i, 1, -4)).doit() 6 >>> Sum(-i, (i, -3, 0)).doit() 6 An explicit example of the Karr summation convention: >>> S1 = Sum(i**2, (i, m, m+n-1)).doit() >>> S1 m**2*n + m*n**2 - m*n + n**3/3 - n**2/2 + n/6 >>> S2 = Sum(i**2, (i, m+n, m-1)).doit() >>> S2 -m**2*n - m*n**2 + m*n - n**3/3 + n**2/2 - n/6 >>> S1 + S2 0 >>> S3 = Sum(i, (i, m, m-1)).doit() >>> S3 0 See Also ======== summation Product, sympy.concrete.products.product References ========== .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, Volume 28 Issue 2, April 1981, Pages 305-350 http://dl.acm.org/citation.cfm?doid=322248.322255 .. [2] https://en.wikipedia.org/wiki/Summation#Capital-sigma_notation .. [3] https://en.wikipedia.org/wiki/Empty_sum """ __slots__ = ('is_commutative',) def __new__(cls, function, *symbols, **assumptions): obj = AddWithLimits.__new__(cls, function, *symbols, **assumptions) if not hasattr(obj, 'limits'): return obj if any(len(l) != 3 or None in l for l in obj.limits): raise ValueError('Sum requires values for lower and upper bounds.') return obj def _eval_is_zero(self): # a Sum is only zero if its function is zero or if all terms # cancel out. This only answers whether the summand is zero; if # not then None is returned since we don't analyze whether all # terms cancel out. if self.function.is_zero or self.has_empty_sequence: return True def _eval_is_extended_real(self): if self.has_empty_sequence: return True return self.function.is_extended_real def _eval_is_positive(self): if self.has_finite_limits and self.has_reversed_limits is False: return self.function.is_positive def _eval_is_negative(self): if self.has_finite_limits and self.has_reversed_limits is False: return self.function.is_negative def _eval_is_finite(self): if self.has_finite_limits and self.function.is_finite: return True def doit(self, **hints): if hints.get('deep', True): f = self.function.doit(**hints) else: f = self.function # first make sure any definite limits have summation # variables with matching assumptions reps = {} for xab in self.limits: d = _dummy_with_inherited_properties_concrete(xab) if d: reps[xab[0]] = d if reps: undo = {v: k for k, v in reps.items()} did = self.xreplace(reps).doit(**hints) if type(did) is tuple: # when separate=True did = tuple([i.xreplace(undo) for i in did]) elif did is not None: did = did.xreplace(undo) else: did = self return did if self.function.is_Matrix: expanded = self.expand() if self != expanded: return expanded.doit() return _eval_matrix_sum(self) for n, limit in enumerate(self.limits): i, a, b = limit dif = b - a if dif == -1: # Any summation over an empty set is zero return S.Zero if dif.is_integer and dif.is_negative: a, b = b + 1, a - 1 f = -f newf = eval_sum(f, (i, a, b)) if newf is None: if f == self.function: zeta_function = self.eval_zeta_function(f, (i, a, b)) if zeta_function is not None: return zeta_function return self else: return self.func(f, *self.limits[n:]) f = newf if hints.get('deep', True): # eval_sum could return partially unevaluated # result with Piecewise. In this case we won't # doit() recursively. if not isinstance(f, Piecewise): return f.doit(**hints) return f def eval_zeta_function(self, f, limits): """ Check whether the function matches with the zeta function. If it matches, then return a `Piecewise` expression because zeta function does not converge unless `s > 1` and `q > 0` """ i, a, b = limits w, y, z = Wild('w', exclude=[i]), Wild('y', exclude=[i]), Wild('z', exclude=[i]) result = f.match((w * i + y) ** (-z)) if result is not None and b is S.Infinity: coeff = 1 / result[w] ** result[z] s = result[z] q = result[y] / result[w] + a return Piecewise((coeff * zeta(s, q), And(q > 0, s > 1)), (self, True)) def _eval_derivative(self, x): """ Differentiate wrt x as long as x is not in the free symbols of any of the upper or lower limits. Explanation =========== Sum(a*b*x, (x, 1, a)) can be differentiated wrt x or b but not `a` since the value of the sum is discontinuous in `a`. In a case involving a limit variable, the unevaluated derivative is returned. """ # diff already confirmed that x is in the free symbols of self, but we # don't want to differentiate wrt any free symbol in the upper or lower # limits # XXX remove this test for free_symbols when the default _eval_derivative is in if isinstance(x, Symbol) and x not in self.free_symbols: return S.Zero # get limits and the function f, limits = self.function, list(self.limits) limit = limits.pop(-1) if limits: # f is the argument to a Sum f = self.func(f, *limits) _, a, b = limit if x in a.free_symbols or x in b.free_symbols: return None df = Derivative(f, x, evaluate=True) rv = self.func(df, limit) return rv def _eval_difference_delta(self, n, step): k, _, upper = self.args[-1] new_upper = upper.subs(n, n + step) if len(self.args) == 2: f = self.args[0] else: f = self.func(*self.args[:-1]) return Sum(f, (k, upper + 1, new_upper)).doit() def _eval_simplify(self, **kwargs): from sympy.simplify.simplify import factor_sum, sum_combine from sympy.core.function import expand from sympy.core.mul import Mul # split the function into adds terms = Add.make_args(expand(self.function)) s_t = [] # Sum Terms o_t = [] # Other Terms for term in terms: if term.has(Sum): # if there is an embedded sum here # it is of the form x * (Sum(whatever)) # hence we make a Mul out of it, and simplify all interior sum terms subterms = Mul.make_args(expand(term)) out_terms = [] for subterm in subterms: # go through each term if isinstance(subterm, Sum): # if it's a sum, simplify it out_terms.append(subterm._eval_simplify()) else: # otherwise, add it as is out_terms.append(subterm) # turn it back into a Mul s_t.append(Mul(*out_terms)) else: o_t.append(term) # next try to combine any interior sums for further simplification result = Add(sum_combine(s_t), *o_t) return factor_sum(result, limits=self.limits) def is_convergent(self): r""" Checks for the convergence of a Sum. Explanation =========== We divide the study of convergence of infinite sums and products in two parts. First Part: One part is the question whether all the terms are well defined, i.e., they are finite in a sum and also non-zero in a product. Zero is the analogy of (minus) infinity in products as :math:`e^{-\infty} = 0`. Second Part: The second part is the question of convergence after infinities, and zeros in products, have been omitted assuming that their number is finite. This means that we only consider the tail of the sum or product, starting from some point after which all terms are well defined. For example, in a sum of the form: .. math:: \sum_{1 \leq i < \infty} \frac{1}{n^2 + an + b} where a and b are numbers. The routine will return true, even if there are infinities in the term sequence (at most two). An analogous product would be: .. math:: \prod_{1 \leq i < \infty} e^{\frac{1}{n^2 + an + b}} This is how convergence is interpreted. It is concerned with what happens at the limit. Finding the bad terms is another independent matter. Note: It is responsibility of user to see that the sum or product is well defined. There are various tests employed to check the convergence like divergence test, root test, integral test, alternating series test, comparison tests, Dirichlet tests. It returns true if Sum is convergent and false if divergent and NotImplementedError if it can not be checked. References ========== .. [1] https://en.wikipedia.org/wiki/Convergence_tests Examples ======== >>> from sympy import factorial, S, Sum, Symbol, oo >>> n = Symbol('n', integer=True) >>> Sum(n/(n - 1), (n, 4, 7)).is_convergent() True >>> Sum(n/(2*n + 1), (n, 1, oo)).is_convergent() False >>> Sum(factorial(n)/5**n, (n, 1, oo)).is_convergent() False >>> Sum(1/n**(S(6)/5), (n, 1, oo)).is_convergent() True See Also ======== Sum.is_absolutely_convergent() sympy.concrete.products.Product.is_convergent() """ from sympy import Interval, Integral, log, symbols, simplify p, q, r = symbols('p q r', cls=Wild) sym = self.limits[0][0] lower_limit = self.limits[0][1] upper_limit = self.limits[0][2] sequence_term = self.function.simplify() if len(sequence_term.free_symbols) > 1: raise NotImplementedError("convergence checking for more than one symbol " "containing series is not handled") if lower_limit.is_finite and upper_limit.is_finite: return S.true # transform sym -> -sym and swap the upper_limit = S.Infinity # and lower_limit = - upper_limit if lower_limit is S.NegativeInfinity: if upper_limit is S.Infinity: return Sum(sequence_term, (sym, 0, S.Infinity)).is_convergent() and \ Sum(sequence_term, (sym, S.NegativeInfinity, 0)).is_convergent() sequence_term = simplify(sequence_term.xreplace({sym: -sym})) lower_limit = -upper_limit upper_limit = S.Infinity sym_ = Dummy(sym.name, integer=True, positive=True) sequence_term = sequence_term.xreplace({sym: sym_}) sym = sym_ interval = Interval(lower_limit, upper_limit) # Piecewise function handle if sequence_term.is_Piecewise: for func, cond in sequence_term.args: # see if it represents something going to oo if cond == True or cond.as_set().sup is S.Infinity: s = Sum(func, (sym, lower_limit, upper_limit)) return s.is_convergent() return S.true ### -------- Divergence test ----------- ### try: lim_val = limit_seq(sequence_term, sym) if lim_val is not None and lim_val.is_zero is False: return S.false except NotImplementedError: pass try: lim_val_abs = limit_seq(abs(sequence_term), sym) if lim_val_abs is not None and lim_val_abs.is_zero is False: return S.false except NotImplementedError: pass order = O(sequence_term, (sym, S.Infinity)) ### --------- p-series test (1/n**p) ---------- ### p_series_test = order.expr.match(sym**p) if p_series_test is not None: if p_series_test[p] < -1: return S.true if p_series_test[p] >= -1: return S.false ### ------------- comparison test ------------- ### # 1/(n**p*log(n)**q*log(log(n))**r) comparison n_log_test = order.expr.match(1/(sym**p*log(sym)**q*log(log(sym))**r)) if n_log_test is not None: if (n_log_test[p] > 1 or (n_log_test[p] == 1 and n_log_test[q] > 1) or (n_log_test[p] == n_log_test[q] == 1 and n_log_test[r] > 1)): return S.true return S.false ### ------------- Limit comparison test -----------### # (1/n) comparison try: lim_comp = limit_seq(sym*sequence_term, sym) if lim_comp is not None and lim_comp.is_number and lim_comp > 0: return S.false except NotImplementedError: pass ### ----------- ratio test ---------------- ### next_sequence_term = sequence_term.xreplace({sym: sym + 1}) ratio = combsimp(powsimp(next_sequence_term/sequence_term)) try: lim_ratio = limit_seq(ratio, sym) if lim_ratio is not None and lim_ratio.is_number: if abs(lim_ratio) > 1: return S.false if abs(lim_ratio) < 1: return S.true except NotImplementedError: lim_ratio = None ### ---------- Raabe's test -------------- ### if lim_ratio == 1: # ratio test inconclusive test_val = sym*(sequence_term/ sequence_term.subs(sym, sym + 1) - 1) test_val = test_val.gammasimp() try: lim_val = limit_seq(test_val, sym) if lim_val is not None and lim_val.is_number: if lim_val > 1: return S.true if lim_val < 1: return S.false except NotImplementedError: pass ### ----------- root test ---------------- ### # lim = Limit(abs(sequence_term)**(1/sym), sym, S.Infinity) try: lim_evaluated = limit_seq(abs(sequence_term)**(1/sym), sym) if lim_evaluated is not None and lim_evaluated.is_number: if lim_evaluated < 1: return S.true if lim_evaluated > 1: return S.false except NotImplementedError: pass ### ------------- alternating series test ----------- ### dict_val = sequence_term.match((-1)**(sym + p)*q) if not dict_val[p].has(sym) and is_decreasing(dict_val[q], interval): return S.true ### ------------- integral test -------------- ### check_interval = None maxima = solveset(sequence_term.diff(sym), sym, interval) if not maxima: check_interval = interval elif isinstance(maxima, FiniteSet) and maxima.sup.is_number: check_interval = Interval(maxima.sup, interval.sup) if (check_interval is not None and (is_decreasing(sequence_term, check_interval) or is_decreasing(-sequence_term, check_interval))): integral_val = Integral( sequence_term, (sym, lower_limit, upper_limit)) try: integral_val_evaluated = integral_val.doit() if integral_val_evaluated.is_number: return S(integral_val_evaluated.is_finite) except NotImplementedError: pass ### ----- Dirichlet and bounded times convergent tests ----- ### # TODO # # Dirichlet_test # https://en.wikipedia.org/wiki/Dirichlet%27s_test # # Bounded times convergent test # It is based on comparison theorems for series. # In particular, if the general term of a series can # be written as a product of two terms a_n and b_n # and if a_n is bounded and if Sum(b_n) is absolutely # convergent, then the original series Sum(a_n * b_n) # is absolutely convergent and so convergent. # # The following code can grows like 2**n where n is the # number of args in order.expr # Possibly combined with the potentially slow checks # inside the loop, could make this test extremely slow # for larger summation expressions. if order.expr.is_Mul: args = order.expr.args argset = set(args) ### -------------- Dirichlet tests -------------- ### m = Dummy('m', integer=True) def _dirichlet_test(g_n): try: ing_val = limit_seq(Sum(g_n, (sym, interval.inf, m)).doit(), m) if ing_val is not None and ing_val.is_finite: return S.true except NotImplementedError: pass ### -------- bounded times convergent test ---------### def _bounded_convergent_test(g1_n, g2_n): try: lim_val = limit_seq(g1_n, sym) if lim_val is not None and (lim_val.is_finite or ( isinstance(lim_val, AccumulationBounds) and (lim_val.max - lim_val.min).is_finite)): if Sum(g2_n, (sym, lower_limit, upper_limit)).is_absolutely_convergent(): return S.true except NotImplementedError: pass for n in range(1, len(argset)): for a_tuple in itertools.combinations(args, n): b_set = argset - set(a_tuple) a_n = Mul(*a_tuple) b_n = Mul(*b_set) if is_decreasing(a_n, interval): dirich = _dirichlet_test(b_n) if dirich is not None: return dirich bc_test = _bounded_convergent_test(a_n, b_n) if bc_test is not None: return bc_test _sym = self.limits[0][0] sequence_term = sequence_term.xreplace({sym: _sym}) raise NotImplementedError("The algorithm to find the Sum convergence of %s " "is not yet implemented" % (sequence_term)) def is_absolutely_convergent(self): """ Checks for the absolute convergence of an infinite series. Same as checking convergence of absolute value of sequence_term of an infinite series. References ========== .. [1] https://en.wikipedia.org/wiki/Absolute_convergence Examples ======== >>> from sympy import Sum, Symbol, oo >>> n = Symbol('n', integer=True) >>> Sum((-1)**n, (n, 1, oo)).is_absolutely_convergent() False >>> Sum((-1)**n/n**2, (n, 1, oo)).is_absolutely_convergent() True See Also ======== Sum.is_convergent() """ return Sum(abs(self.function), self.limits).is_convergent() def euler_maclaurin(self, m=0, n=0, eps=0, eval_integral=True): """ Return an Euler-Maclaurin approximation of self, where m is the number of leading terms to sum directly and n is the number of terms in the tail. With m = n = 0, this is simply the corresponding integral plus a first-order endpoint correction. Returns (s, e) where s is the Euler-Maclaurin approximation and e is the estimated error (taken to be the magnitude of the first omitted term in the tail): >>> from sympy.abc import k, a, b >>> from sympy import Sum >>> Sum(1/k, (k, 2, 5)).doit().evalf() 1.28333333333333 >>> s, e = Sum(1/k, (k, 2, 5)).euler_maclaurin() >>> s -log(2) + 7/20 + log(5) >>> from sympy import sstr >>> print(sstr((s.evalf(), e.evalf()), full_prec=True)) (1.26629073187415, 0.0175000000000000) The endpoints may be symbolic: >>> s, e = Sum(1/k, (k, a, b)).euler_maclaurin() >>> s -log(a) + log(b) + 1/(2*b) + 1/(2*a) >>> e Abs(1/(12*b**2) - 1/(12*a**2)) If the function is a polynomial of degree at most 2n+1, the Euler-Maclaurin formula becomes exact (and e = 0 is returned): >>> Sum(k, (k, 2, b)).euler_maclaurin() (b**2/2 + b/2 - 1, 0) >>> Sum(k, (k, 2, b)).doit() b**2/2 + b/2 - 1 With a nonzero eps specified, the summation is ended as soon as the remainder term is less than the epsilon. """ from sympy.functions import bernoulli, factorial from sympy.integrals import Integral m = int(m) n = int(n) f = self.function if len(self.limits) != 1: raise ValueError("More than 1 limit") i, a, b = self.limits[0] if (a > b) == True: if a - b == 1: return S.Zero, S.Zero a, b = b + 1, a - 1 f = -f s = S.Zero if m: if b.is_Integer and a.is_Integer: m = min(m, b - a + 1) if not eps or f.is_polynomial(i): for k in range(m): s += f.subs(i, a + k) else: term = f.subs(i, a) if term: test = abs(term.evalf(3)) < eps if test == True: return s, abs(term) elif not (test == False): # a symbolic Relational class, can't go further return term, S.Zero s += term for k in range(1, m): term = f.subs(i, a + k) if abs(term.evalf(3)) < eps and term != 0: return s, abs(term) s += term if b - a + 1 == m: return s, S.Zero a += m x = Dummy('x') I = Integral(f.subs(i, x), (x, a, b)) if eval_integral: I = I.doit() s += I def fpoint(expr): if b is S.Infinity: return expr.subs(i, a), 0 return expr.subs(i, a), expr.subs(i, b) fa, fb = fpoint(f) iterm = (fa + fb)/2 g = f.diff(i) for k in range(1, n + 2): ga, gb = fpoint(g) term = bernoulli(2*k)/factorial(2*k)*(gb - ga) if (eps and term and abs(term.evalf(3)) < eps) or (k > n): break s += term g = g.diff(i, 2, simplify=False) return s + iterm, abs(term) def reverse_order(self, *indices): """ Reverse the order of a limit in a Sum. Explanation =========== ``reverse_order(self, *indices)`` reverses some limits in the expression ``self`` which can be either a ``Sum`` or a ``Product``. The selectors in the argument ``indices`` specify some indices whose limits get reversed. These selectors are either variable names or numerical indices counted starting from the inner-most limit tuple. Examples ======== >>> from sympy import Sum >>> from sympy.abc import x, y, a, b, c, d >>> Sum(x, (x, 0, 3)).reverse_order(x) Sum(-x, (x, 4, -1)) >>> Sum(x*y, (x, 1, 5), (y, 0, 6)).reverse_order(x, y) Sum(x*y, (x, 6, 0), (y, 7, -1)) >>> Sum(x, (x, a, b)).reverse_order(x) Sum(-x, (x, b + 1, a - 1)) >>> Sum(x, (x, a, b)).reverse_order(0) Sum(-x, (x, b + 1, a - 1)) While one should prefer variable names when specifying which limits to reverse, the index counting notation comes in handy in case there are several symbols with the same name. >>> S = Sum(x**2, (x, a, b), (x, c, d)) >>> S Sum(x**2, (x, a, b), (x, c, d)) >>> S0 = S.reverse_order(0) >>> S0 Sum(-x**2, (x, b + 1, a - 1), (x, c, d)) >>> S1 = S0.reverse_order(1) >>> S1 Sum(x**2, (x, b + 1, a - 1), (x, d + 1, c - 1)) Of course we can mix both notations: >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(x, 1) Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) >>> Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(y, x) Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) See Also ======== sympy.concrete.expr_with_intlimits.ExprWithIntLimits.index, reorder_limit, sympy.concrete.expr_with_intlimits.ExprWithIntLimits.reorder References ========== .. [1] Michael Karr, "Summation in Finite Terms", Journal of the ACM, Volume 28 Issue 2, April 1981, Pages 305-350 http://dl.acm.org/citation.cfm?doid=322248.322255 """ l_indices = list(indices) for i, indx in enumerate(l_indices): if not isinstance(indx, int): l_indices[i] = self.index(indx) e = 1 limits = [] for i, limit in enumerate(self.limits): l = limit if i in l_indices: e = -e l = (limit[0], limit[2] + 1, limit[1] - 1) limits.append(l) return Sum(e * self.function, *limits) def summation(f, *symbols, **kwargs): r""" Compute the summation of f with respect to symbols. Explanation =========== The notation for symbols is similar to the notation used in Integral. summation(f, (i, a, b)) computes the sum of f with respect to i from a to b, i.e., :: b ____ \ ` summation(f, (i, a, b)) = ) f /___, i = a If it cannot compute the sum, it returns an unevaluated Sum object. Repeated sums can be computed by introducing additional symbols tuples:: Examples ======== >>> from sympy import summation, oo, symbols, log >>> i, n, m = symbols('i n m', integer=True) >>> summation(2*i - 1, (i, 1, n)) n**2 >>> summation(1/2**i, (i, 0, oo)) 2 >>> summation(1/log(n)**n, (n, 2, oo)) Sum(log(n)**(-n), (n, 2, oo)) >>> summation(i, (i, 0, n), (n, 0, m)) m**3/6 + m**2/2 + m/3 >>> from sympy.abc import x >>> from sympy import factorial >>> summation(x**n/factorial(n), (n, 0, oo)) exp(x) See Also ======== Sum Product, sympy.concrete.products.product """ return Sum(f, *symbols, **kwargs).doit(deep=False) def telescopic_direct(L, R, n, limits): """ Returns the direct summation of the terms of a telescopic sum Explanation =========== L is the term with lower index R is the term with higher index n difference between the indexes of L and R Examples ======== >>> from sympy.concrete.summations import telescopic_direct >>> from sympy.abc import k, a, b >>> telescopic_direct(1/k, -1/(k+2), 2, (k, a, b)) -1/(b + 2) - 1/(b + 1) + 1/(a + 1) + 1/a """ (i, a, b) = limits s = 0 for m in range(n): s += L.subs(i, a + m) + R.subs(i, b - m) return s def telescopic(L, R, limits): ''' Tries to perform the summation using the telescopic property. Return None if not possible. ''' (i, a, b) = limits if L.is_Add or R.is_Add: return None # We want to solve(L.subs(i, i + m) + R, m) # First we try a simple match since this does things that # solve doesn't do, e.g. solve(f(k+m)-f(k), m) fails k = Wild("k") sol = (-R).match(L.subs(i, i + k)) s = None if sol and k in sol: s = sol[k] if not (s.is_Integer and L.subs(i, i + s) == -R): # sometimes match fail(f(x+2).match(-f(x+k))->{k: -2 - 2x})) s = None # But there are things that match doesn't do that solve # can do, e.g. determine that 1/(x + m) = 1/(1 - x) when m = 1 if s is None: m = Dummy('m') try: sol = solve(L.subs(i, i + m) + R, m) or [] except NotImplementedError: return None sol = [si for si in sol if si.is_Integer and (L.subs(i, i + si) + R).expand().is_zero] if len(sol) != 1: return None s = sol[0] if s < 0: return telescopic_direct(R, L, abs(s), (i, a, b)) elif s > 0: return telescopic_direct(L, R, s, (i, a, b)) def eval_sum(f, limits): from sympy.concrete.delta import deltasummation, _has_simple_delta from sympy.functions import KroneckerDelta (i, a, b) = limits if f.is_zero: return S.Zero if i not in f.free_symbols: return f*(b - a + 1) if a == b: return f.subs(i, a) if isinstance(f, Piecewise): if not any(i in arg.args[1].free_symbols for arg in f.args): # Piecewise conditions do not depend on the dummy summation variable, # therefore we can fold: Sum(Piecewise((e, c), ...), limits) # --> Piecewise((Sum(e, limits), c), ...) newargs = [] for arg in f.args: newexpr = eval_sum(arg.expr, limits) if newexpr is None: return None newargs.append((newexpr, arg.cond)) return f.func(*newargs) if f.has(KroneckerDelta): f = f.replace( lambda x: isinstance(x, Sum), lambda x: x.factor() ) if _has_simple_delta(f, limits[0]): return deltasummation(f, limits) dif = b - a definite = dif.is_Integer # Doing it directly may be faster if there are very few terms. if definite and (dif < 100): return eval_sum_direct(f, (i, a, b)) if isinstance(f, Piecewise): return None # Try to do it symbolically. Even when the number of terms is known, # this can save time when b-a is big. # We should try to transform to partial fractions value = eval_sum_symbolic(f.expand(), (i, a, b)) if value is not None: return value # Do it directly if definite: return eval_sum_direct(f, (i, a, b)) def eval_sum_direct(expr, limits): """ Evaluate expression directly, but perform some simple checks first to possibly result in a smaller expression and faster execution. """ from sympy.core import Add (i, a, b) = limits dif = b - a # Linearity if expr.is_Mul: # Try factor out everything not including i without_i, with_i = expr.as_independent(i) if without_i != 1: s = eval_sum_direct(with_i, (i, a, b)) if s: r = without_i*s if r is not S.NaN: return r else: # Try term by term L, R = expr.as_two_terms() if not L.has(i): sR = eval_sum_direct(R, (i, a, b)) if sR: return L*sR if not R.has(i): sL = eval_sum_direct(L, (i, a, b)) if sL: return sL*R try: expr = apart(expr, i) # see if it becomes an Add except PolynomialError: pass if expr.is_Add: # Try factor out everything not including i without_i, with_i = expr.as_independent(i) if without_i != 0: s = eval_sum_direct(with_i, (i, a, b)) if s: r = without_i*(dif + 1) + s if r is not S.NaN: return r else: # Try term by term L, R = expr.as_two_terms() lsum = eval_sum_direct(L, (i, a, b)) rsum = eval_sum_direct(R, (i, a, b)) if None not in (lsum, rsum): r = lsum + rsum if r is not S.NaN: return r return Add(*[expr.subs(i, a + j) for j in range(dif + 1)]) def eval_sum_symbolic(f, limits): from sympy.functions import harmonic, bernoulli f_orig = f (i, a, b) = limits if not f.has(i): return f*(b - a + 1) # Linearity if f.is_Mul: # Try factor out everything not including i without_i, with_i = f.as_independent(i) if without_i != 1: s = eval_sum_symbolic(with_i, (i, a, b)) if s: r = without_i*s if r is not S.NaN: return r else: # Try term by term L, R = f.as_two_terms() if not L.has(i): sR = eval_sum_symbolic(R, (i, a, b)) if sR: return L*sR if not R.has(i): sL = eval_sum_symbolic(L, (i, a, b)) if sL: return sL*R try: f = apart(f, i) # see if it becomes an Add except PolynomialError: pass if f.is_Add: L, R = f.as_two_terms() lrsum = telescopic(L, R, (i, a, b)) if lrsum: return lrsum # Try factor out everything not including i without_i, with_i = f.as_independent(i) if without_i != 0: s = eval_sum_symbolic(with_i, (i, a, b)) if s: r = without_i*(b - a + 1) + s if r is not S.NaN: return r else: # Try term by term lsum = eval_sum_symbolic(L, (i, a, b)) rsum = eval_sum_symbolic(R, (i, a, b)) if None not in (lsum, rsum): r = lsum + rsum if r is not S.NaN: return r # Polynomial terms with Faulhaber's formula n = Wild('n') result = f.match(i**n) if result is not None: n = result[n] if n.is_Integer: if n >= 0: if (b is S.Infinity and not a is S.NegativeInfinity) or \ (a is S.NegativeInfinity and not b is S.Infinity): return S.Infinity return ((bernoulli(n + 1, b + 1) - bernoulli(n + 1, a))/(n + 1)).expand() elif a.is_Integer and a >= 1: if n == -1: return harmonic(b) - harmonic(a - 1) else: return harmonic(b, abs(n)) - harmonic(a - 1, abs(n)) if not (a.has(S.Infinity, S.NegativeInfinity) or b.has(S.Infinity, S.NegativeInfinity)): # Geometric terms c1 = Wild('c1', exclude=[i]) c2 = Wild('c2', exclude=[i]) c3 = Wild('c3', exclude=[i]) wexp = Wild('wexp') # Here we first attempt powsimp on f for easier matching with the # exponential pattern, and attempt expansion on the exponent for easier # matching with the linear pattern. e = f.powsimp().match(c1 ** wexp) if e is not None: e_exp = e.pop(wexp).expand().match(c2*i + c3) if e_exp is not None: e.update(e_exp) p = (c1**c3).subs(e) q = (c1**c2).subs(e) r = p*(q**a - q**(b + 1))/(1 - q) l = p*(b - a + 1) return Piecewise((l, Eq(q, S.One)), (r, True)) r = gosper_sum(f, (i, a, b)) if isinstance(r, (Mul,Add)): from sympy import ordered, Tuple non_limit = r.free_symbols - Tuple(*limits[1:]).free_symbols den = denom(together(r)) den_sym = non_limit & den.free_symbols args = [] for v in ordered(den_sym): try: s = solve(den, v) m = Eq(v, s[0]) if s else S.false if m != False: args.append((Sum(f_orig.subs(*m.args), limits).doit(), m)) break except NotImplementedError: continue args.append((r, True)) return Piecewise(*args) if not r in (None, S.NaN): return r h = eval_sum_hyper(f_orig, (i, a, b)) if h is not None: return h r = eval_sum_residue(f_orig, (i, a, b)) if r is not None: return r factored = f_orig.factor() if factored != f_orig: return eval_sum_symbolic(factored, (i, a, b)) def _eval_sum_hyper(f, i, a): """ Returns (res, cond). Sums from a to oo. """ from sympy.functions import hyper from sympy.simplify import hyperexpand, hypersimp, fraction, simplify from sympy.polys.polytools import Poly, factor from sympy.core.numbers import Float if a != 0: return _eval_sum_hyper(f.subs(i, i + a), i, 0) if f.subs(i, 0) == 0: if simplify(f.subs(i, Dummy('i', integer=True, positive=True))) == 0: return S.Zero, True return _eval_sum_hyper(f.subs(i, i + 1), i, 0) hs = hypersimp(f, i) if hs is None: return None if isinstance(hs, Float): from sympy.simplify.simplify import nsimplify hs = nsimplify(hs) numer, denom = fraction(factor(hs)) top, topl = numer.as_coeff_mul(i) bot, botl = denom.as_coeff_mul(i) ab = [top, bot] factors = [topl, botl] params = [[], []] for k in range(2): for fac in factors[k]: mul = 1 if fac.is_Pow: mul = fac.exp fac = fac.base if not mul.is_Integer: return None p = Poly(fac, i) if p.degree() != 1: return None m, n = p.all_coeffs() ab[k] *= m**mul params[k] += [n/m]*mul # Add "1" to numerator parameters, to account for implicit n! in # hypergeometric series. ap = params[0] + [1] bq = params[1] x = ab[0]/ab[1] h = hyper(ap, bq, x) f = combsimp(f) return f.subs(i, 0)*hyperexpand(h), h.convergence_statement def eval_sum_hyper(f, i_a_b): from sympy.logic.boolalg import And i, a, b = i_a_b if (b - a).is_Integer: # We are never going to do better than doing the sum in the obvious way return None old_sum = Sum(f, (i, a, b)) if b != S.Infinity: if a is S.NegativeInfinity: res = _eval_sum_hyper(f.subs(i, -i), i, -b) if res is not None: return Piecewise(res, (old_sum, True)) else: res1 = _eval_sum_hyper(f, i, a) res2 = _eval_sum_hyper(f, i, b + 1) if res1 is None or res2 is None: return None (res1, cond1), (res2, cond2) = res1, res2 cond = And(cond1, cond2) if cond == False: return None return Piecewise((res1 - res2, cond), (old_sum, True)) if a is S.NegativeInfinity: res1 = _eval_sum_hyper(f.subs(i, -i), i, 1) res2 = _eval_sum_hyper(f, i, 0) if res1 is None or res2 is None: return None res1, cond1 = res1 res2, cond2 = res2 cond = And(cond1, cond2) if cond == False or cond.as_set() == S.EmptySet: return None return Piecewise((res1 + res2, cond), (old_sum, True)) # Now b == oo, a != -oo res = _eval_sum_hyper(f, i, a) if res is not None: r, c = res if c == False: if r.is_number: f = f.subs(i, Dummy('i', integer=True, positive=True) + a) if f.is_positive or f.is_zero: return S.Infinity elif f.is_negative: return S.NegativeInfinity return None return Piecewise(res, (old_sum, True)) def eval_sum_residue(f, i_a_b): r"""Compute the infinite summation with residues Notes ===== If $f(n), g(n)$ are polynomials with $\deg(g(n)) - \deg(f(n)) >= 2$, some infinite summations can be computed by the following residue evaluations. .. math:: \sum_{n=-\infty, g(n) \ne 0}^{\infty} \frac{f(n)}{g(n)} = -\pi \sum_{\alpha|g(\alpha)=0} \text{Res}(\cot(\pi x) \frac{f(x)}{g(x)}, \alpha) .. math:: \sum_{n=-\infty, g(n) \ne 0}^{\infty} (-1)^n \frac{f(n)}{g(n)} = -\pi \sum_{\alpha|g(\alpha)=0} \text{Res}(\csc(\pi x) \frac{f(x)}{g(x)}, \alpha) Examples ======== >>> from sympy import Sum, oo, Symbol >>> x = Symbol('x') Doubly infinite series of rational functions. >>> Sum(1 / (x**2 + 1), (x, -oo, oo)).doit() pi/tanh(pi) Doubly infinite alternating series of rational functions. >>> Sum((-1)**x / (x**2 + 1), (x, -oo, oo)).doit() pi/sinh(pi) Infinite series of even rational functions. >>> Sum(1 / (x**2 + 1), (x, 0, oo)).doit() 1/2 + pi/(2*tanh(pi)) Infinite series of alternating even rational functions. >>> Sum((-1)**x / (x**2 + 1), (x, 0, oo)).doit() pi/(2*sinh(pi)) + 1/2 This also have heuristics to transform arbitrarily shifted summand or arbitrarily shifted summation range to the canonical problem the formula can handle. >>> Sum(1 / (x**2 + 2*x + 2), (x, -1, oo)).doit() 1/2 + pi/(2*tanh(pi)) >>> Sum(1 / (x**2 + 4*x + 5), (x, -2, oo)).doit() 1/2 + pi/(2*tanh(pi)) >>> Sum(1 / (x**2 + 1), (x, 1, oo)).doit() -1/2 + pi/(2*tanh(pi)) >>> Sum(1 / (x**2 + 1), (x, 2, oo)).doit() -1 + pi/(2*tanh(pi)) References ========== .. [#] http://www.supermath.info/InfiniteSeriesandtheResidueTheorem.pdf .. [#] Asmar N.H., Grafakos L. (2018) Residue Theory. In: Complex Analysis with Applications. Undergraduate Texts in Mathematics. Springer, Cham. https://doi.org/10.1007/978-3-319-94063-2_5 """ i, a, b = i_a_b def is_even_function(numer, denom): """Test if the rational function is an even function""" numer_even = all([i % 2 == 0 for (i,) in numer.monoms()]) denom_even = all([i % 2 == 0 for (i,) in denom.monoms()]) numer_odd = all([i % 2 == 1 for (i,) in numer.monoms()]) denom_odd = all([i % 2 == 1 for (i,) in denom.monoms()]) return (numer_even and denom_even) or (numer_odd and denom_odd) def match_rational(f, i): numer, denom = f.as_numer_denom() try: (numer, denom), opt = parallel_poly_from_expr((numer, denom), i) except (PolificationFailed, PolynomialError): return None return numer, denom def get_poles(denom): roots = denom.sqf_part().all_roots() roots = sift(roots, lambda x: x.is_integer) if None in roots: return None int_roots, nonint_roots = roots[True], roots[False] return int_roots, nonint_roots def get_shift(denom): n = denom.degree(i) a = denom.coeff_monomial(i**n) b = denom.coeff_monomial(i**(n-1)) shift = - b / a / n return shift def get_residue_factor(numer, denom, alternating): if not alternating: residue_factor = (numer.as_expr() / denom.as_expr()) * cot(S.Pi * i) else: residue_factor = (numer.as_expr() / denom.as_expr()) * csc(S.Pi * i) return residue_factor # We don't know how to deal with symbolic constants in summand if f.free_symbols - set([i]): return None if not (a.is_Integer or a in (S.Infinity, S.NegativeInfinity)): return None if not (b.is_Integer or b in (S.Infinity, S.NegativeInfinity)): return None # Quick exit heuristic for the sums which doesn't have infinite range if a != S.NegativeInfinity and b != S.Infinity: return None match = match_rational(f, i) if match: alternating = False numer, denom = match else: match = match_rational(f / (-1)**i, i) if match: alternating = True numer, denom = match else: return None if denom.degree(i) - numer.degree(i) < 2: return None if (a, b) == (S.NegativeInfinity, S.Infinity): poles = get_poles(denom) if poles is None: return None int_roots, nonint_roots = poles if int_roots: return None residue_factor = get_residue_factor(numer, denom, alternating) residues = [residue(residue_factor, i, root) for root in nonint_roots] return -S.Pi * sum(residues) if not (a.is_finite and b is S.Infinity): return None if not is_even_function(numer, denom): # Try shifting summation and check if the summand can be made # and even function from the origin. # Sum(f(n), (n, a, b)) => Sum(f(n + s), (n, a - s, b - s)) shift = get_shift(denom) if not shift.is_Integer: return None if shift == 0: return None numer = numer.shift(shift) denom = denom.shift(shift) if not is_even_function(numer, denom): return None if alternating: f = (-1)**i * ((-1)**shift * numer.as_expr() / denom.as_expr()) else: f = numer.as_expr() / denom.as_expr() return eval_sum_residue(f, (i, a-shift, b-shift)) poles = get_poles(denom) if poles is None: return None int_roots, nonint_roots = poles if int_roots: int_roots = [int(root) for root in int_roots] int_roots_max = max(int_roots) int_roots_min = min(int_roots) # Integer valued poles must be next to each other # and also symmetric from origin (Because the function is even) if not len(int_roots) == int_roots_max - int_roots_min + 1: return None # Check whether the summation indices contain poles if a <= max(int_roots): return None residue_factor = get_residue_factor(numer, denom, alternating) residues = [residue(residue_factor, i, root) for root in int_roots + nonint_roots] full_sum = -S.Pi * sum(residues) if not int_roots: # Compute Sum(f, (i, 0, oo)) by adding a extraneous evaluation # at the origin. half_sum = (full_sum + f.xreplace({i: 0})) / 2 # Add and subtract extraneous evaluations extraneous_neg = [f.xreplace({i: i0}) for i0 in range(int(a), 0)] extraneous_pos = [f.xreplace({i: i0}) for i0 in range(0, int(a))] result = half_sum + sum(extraneous_neg) - sum(extraneous_pos) return result # Compute Sum(f, (i, min(poles) + 1, oo)) half_sum = full_sum / 2 # Subtract extraneous evaluations extraneous = [f.xreplace({i: i0}) for i0 in range(max(int_roots) + 1, int(a))] result = half_sum - sum(extraneous) return result def _eval_matrix_sum(expression): f = expression.function for n, limit in enumerate(expression.limits): i, a, b = limit dif = b - a if dif.is_Integer: if (dif < 0) == True: a, b = b + 1, a - 1 f = -f newf = eval_sum_direct(f, (i, a, b)) if newf is not None: return newf.doit() def _dummy_with_inherited_properties_concrete(limits): """ Return a Dummy symbol that inherits as many assumptions as possible from the provided symbol and limits. If the symbol already has all True assumption shared by the limits then return None. """ x, a, b = limits l = [a, b] assumptions_to_consider = ['extended_nonnegative', 'nonnegative', 'extended_nonpositive', 'nonpositive', 'extended_positive', 'positive', 'extended_negative', 'negative', 'integer', 'rational', 'finite', 'zero', 'real', 'extended_real'] assumptions_to_keep = {} assumptions_to_add = {} for assum in assumptions_to_consider: assum_true = x._assumptions.get(assum, None) if assum_true: assumptions_to_keep[assum] = True elif all([getattr(i, 'is_' + assum) for i in l]): assumptions_to_add[assum] = True if assumptions_to_add: assumptions_to_keep.update(assumptions_to_add) return Dummy('d', **assumptions_to_keep) sympy-sympy-1.9/sympy/concrete/tests/000077500000000000000000000000001412543434000200505ustar00rootroot00000000000000sympy-sympy-1.9/sympy/concrete/tests/__init__.py000066400000000000000000000000001412543434000221470ustar00rootroot00000000000000sympy-sympy-1.9/sympy/concrete/tests/test_delta.py000066400000000000000000000562161412543434000225640ustar00rootroot00000000000000from sympy.concrete import Sum from sympy.concrete.delta import deltaproduct as dp, deltasummation as ds, _extract_delta from sympy.core import Eq, S, symbols, oo from sympy.functions import KroneckerDelta as KD, Piecewise, piecewise_fold from sympy.logic import And from sympy.testing.pytest import raises i, j, k, l, m = symbols("i j k l m", integer=True, finite=True) x, y = symbols("x y", commutative=False) def test_deltaproduct_trivial(): assert dp(x, (j, 1, 0)) == 1 assert dp(x, (j, 1, 3)) == x**3 assert dp(x + y, (j, 1, 3)) == (x + y)**3 assert dp(x*y, (j, 1, 3)) == (x*y)**3 assert dp(KD(i, j), (k, 1, 3)) == KD(i, j) assert dp(x*KD(i, j), (k, 1, 3)) == x**3*KD(i, j) assert dp(x*y*KD(i, j), (k, 1, 3)) == (x*y)**3*KD(i, j) def test_deltaproduct_basic(): assert dp(KD(i, j), (j, 1, 3)) == 0 assert dp(KD(i, j), (j, 1, 1)) == KD(i, 1) assert dp(KD(i, j), (j, 2, 2)) == KD(i, 2) assert dp(KD(i, j), (j, 3, 3)) == KD(i, 3) assert dp(KD(i, j), (j, 1, k)) == KD(i, 1)*KD(k, 1) + KD(k, 0) assert dp(KD(i, j), (j, k, 3)) == KD(i, 3)*KD(k, 3) + KD(k, 4) assert dp(KD(i, j), (j, k, l)) == KD(i, l)*KD(k, l) + KD(k, l + 1) def test_deltaproduct_mul_x_kd(): assert dp(x*KD(i, j), (j, 1, 3)) == 0 assert dp(x*KD(i, j), (j, 1, 1)) == x*KD(i, 1) assert dp(x*KD(i, j), (j, 2, 2)) == x*KD(i, 2) assert dp(x*KD(i, j), (j, 3, 3)) == x*KD(i, 3) assert dp(x*KD(i, j), (j, 1, k)) == x*KD(i, 1)*KD(k, 1) + KD(k, 0) assert dp(x*KD(i, j), (j, k, 3)) == x*KD(i, 3)*KD(k, 3) + KD(k, 4) assert dp(x*KD(i, j), (j, k, l)) == x*KD(i, l)*KD(k, l) + KD(k, l + 1) def test_deltaproduct_mul_add_x_y_kd(): assert dp((x + y)*KD(i, j), (j, 1, 3)) == 0 assert dp((x + y)*KD(i, j), (j, 1, 1)) == (x + y)*KD(i, 1) assert dp((x + y)*KD(i, j), (j, 2, 2)) == (x + y)*KD(i, 2) assert dp((x + y)*KD(i, j), (j, 3, 3)) == (x + y)*KD(i, 3) assert dp((x + y)*KD(i, j), (j, 1, k)) == \ (x + y)*KD(i, 1)*KD(k, 1) + KD(k, 0) assert dp((x + y)*KD(i, j), (j, k, 3)) == \ (x + y)*KD(i, 3)*KD(k, 3) + KD(k, 4) assert dp((x + y)*KD(i, j), (j, k, l)) == \ (x + y)*KD(i, l)*KD(k, l) + KD(k, l + 1) def test_deltaproduct_add_kd_kd(): assert dp(KD(i, k) + KD(j, k), (k, 1, 3)) == 0 assert dp(KD(i, k) + KD(j, k), (k, 1, 1)) == KD(i, 1) + KD(j, 1) assert dp(KD(i, k) + KD(j, k), (k, 2, 2)) == KD(i, 2) + KD(j, 2) assert dp(KD(i, k) + KD(j, k), (k, 3, 3)) == KD(i, 3) + KD(j, 3) assert dp(KD(i, k) + KD(j, k), (k, 1, l)) == KD(l, 0) + \ KD(i, 1)*KD(l, 1) + KD(j, 1)*KD(l, 1) + \ KD(i, 1)*KD(j, 2)*KD(l, 2) + KD(j, 1)*KD(i, 2)*KD(l, 2) assert dp(KD(i, k) + KD(j, k), (k, l, 3)) == KD(l, 4) + \ KD(i, 3)*KD(l, 3) + KD(j, 3)*KD(l, 3) + \ KD(i, 2)*KD(j, 3)*KD(l, 2) + KD(i, 3)*KD(j, 2)*KD(l, 2) assert dp(KD(i, k) + KD(j, k), (k, l, m)) == KD(l, m + 1) + \ KD(i, m)*KD(l, m) + KD(j, m)*KD(l, m) + \ KD(i, m)*KD(j, m - 1)*KD(l, m - 1) + KD(i, m - 1)*KD(j, m)*KD(l, m - 1) def test_deltaproduct_mul_x_add_kd_kd(): assert dp(x*(KD(i, k) + KD(j, k)), (k, 1, 3)) == 0 assert dp(x*(KD(i, k) + KD(j, k)), (k, 1, 1)) == x*(KD(i, 1) + KD(j, 1)) assert dp(x*(KD(i, k) + KD(j, k)), (k, 2, 2)) == x*(KD(i, 2) + KD(j, 2)) assert dp(x*(KD(i, k) + KD(j, k)), (k, 3, 3)) == x*(KD(i, 3) + KD(j, 3)) assert dp(x*(KD(i, k) + KD(j, k)), (k, 1, l)) == KD(l, 0) + \ x*KD(i, 1)*KD(l, 1) + x*KD(j, 1)*KD(l, 1) + \ x**2*KD(i, 1)*KD(j, 2)*KD(l, 2) + x**2*KD(j, 1)*KD(i, 2)*KD(l, 2) assert dp(x*(KD(i, k) + KD(j, k)), (k, l, 3)) == KD(l, 4) + \ x*KD(i, 3)*KD(l, 3) + x*KD(j, 3)*KD(l, 3) + \ x**2*KD(i, 2)*KD(j, 3)*KD(l, 2) + x**2*KD(i, 3)*KD(j, 2)*KD(l, 2) assert dp(x*(KD(i, k) + KD(j, k)), (k, l, m)) == KD(l, m + 1) + \ x*KD(i, m)*KD(l, m) + x*KD(j, m)*KD(l, m) + \ x**2*KD(i, m - 1)*KD(j, m)*KD(l, m - 1) + \ x**2*KD(i, m)*KD(j, m - 1)*KD(l, m - 1) def test_deltaproduct_mul_add_x_y_add_kd_kd(): assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 3)) == 0 assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 1)) == \ (x + y)*(KD(i, 1) + KD(j, 1)) assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 2, 2)) == \ (x + y)*(KD(i, 2) + KD(j, 2)) assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 3, 3)) == \ (x + y)*(KD(i, 3) + KD(j, 3)) assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, 1, l)) == KD(l, 0) + \ (x + y)*KD(i, 1)*KD(l, 1) + (x + y)*KD(j, 1)*KD(l, 1) + \ (x + y)**2*KD(i, 1)*KD(j, 2)*KD(l, 2) + \ (x + y)**2*KD(j, 1)*KD(i, 2)*KD(l, 2) assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, l, 3)) == KD(l, 4) + \ (x + y)*KD(i, 3)*KD(l, 3) + (x + y)*KD(j, 3)*KD(l, 3) + \ (x + y)**2*KD(i, 2)*KD(j, 3)*KD(l, 2) + \ (x + y)**2*KD(i, 3)*KD(j, 2)*KD(l, 2) assert dp((x + y)*(KD(i, k) + KD(j, k)), (k, l, m)) == KD(l, m + 1) + \ (x + y)*KD(i, m)*KD(l, m) + (x + y)*KD(j, m)*KD(l, m) + \ (x + y)**2*KD(i, m - 1)*KD(j, m)*KD(l, m - 1) + \ (x + y)**2*KD(i, m)*KD(j, m - 1)*KD(l, m - 1) def test_deltaproduct_add_mul_x_y_mul_x_kd(): assert dp(x*y + x*KD(i, j), (j, 1, 3)) == (x*y)**3 + \ x*(x*y)**2*KD(i, 1) + (x*y)*x*(x*y)*KD(i, 2) + (x*y)**2*x*KD(i, 3) assert dp(x*y + x*KD(i, j), (j, 1, 1)) == x*y + x*KD(i, 1) assert dp(x*y + x*KD(i, j), (j, 2, 2)) == x*y + x*KD(i, 2) assert dp(x*y + x*KD(i, j), (j, 3, 3)) == x*y + x*KD(i, 3) assert dp(x*y + x*KD(i, j), (j, 1, k)) == \ (x*y)**k + Piecewise( ((x*y)**(i - 1)*x*(x*y)**(k - i), And(1 <= i, i <= k)), (0, True) ) assert dp(x*y + x*KD(i, j), (j, k, 3)) == \ (x*y)**(-k + 4) + Piecewise( ((x*y)**(i - k)*x*(x*y)**(3 - i), And(k <= i, i <= 3)), (0, True) ) assert dp(x*y + x*KD(i, j), (j, k, l)) == \ (x*y)**(-k + l + 1) + Piecewise( ((x*y)**(i - k)*x*(x*y)**(l - i), And(k <= i, i <= l)), (0, True) ) def test_deltaproduct_mul_x_add_y_kd(): assert dp(x*(y + KD(i, j)), (j, 1, 3)) == (x*y)**3 + \ x*(x*y)**2*KD(i, 1) + (x*y)*x*(x*y)*KD(i, 2) + (x*y)**2*x*KD(i, 3) assert dp(x*(y + KD(i, j)), (j, 1, 1)) == x*(y + KD(i, 1)) assert dp(x*(y + KD(i, j)), (j, 2, 2)) == x*(y + KD(i, 2)) assert dp(x*(y + KD(i, j)), (j, 3, 3)) == x*(y + KD(i, 3)) assert dp(x*(y + KD(i, j)), (j, 1, k)) == \ (x*y)**k + Piecewise( ((x*y)**(i - 1)*x*(x*y)**(k - i), And(1 <= i, i <= k)), (0, True) ) assert dp(x*(y + KD(i, j)), (j, k, 3)) == \ (x*y)**(-k + 4) + Piecewise( ((x*y)**(i - k)*x*(x*y)**(3 - i), And(k <= i, i <= 3)), (0, True) ) assert dp(x*(y + KD(i, j)), (j, k, l)) == \ (x*y)**(-k + l + 1) + Piecewise( ((x*y)**(i - k)*x*(x*y)**(l - i), And(k <= i, i <= l)), (0, True) ) def test_deltaproduct_mul_x_add_y_twokd(): assert dp(x*(y + 2*KD(i, j)), (j, 1, 3)) == (x*y)**3 + \ 2*x*(x*y)**2*KD(i, 1) + 2*x*y*x*x*y*KD(i, 2) + 2*(x*y)**2*x*KD(i, 3) assert dp(x*(y + 2*KD(i, j)), (j, 1, 1)) == x*(y + 2*KD(i, 1)) assert dp(x*(y + 2*KD(i, j)), (j, 2, 2)) == x*(y + 2*KD(i, 2)) assert dp(x*(y + 2*KD(i, j)), (j, 3, 3)) == x*(y + 2*KD(i, 3)) assert dp(x*(y + 2*KD(i, j)), (j, 1, k)) == \ (x*y)**k + Piecewise( (2*(x*y)**(i - 1)*x*(x*y)**(k - i), And(1 <= i, i <= k)), (0, True) ) assert dp(x*(y + 2*KD(i, j)), (j, k, 3)) == \ (x*y)**(-k + 4) + Piecewise( (2*(x*y)**(i - k)*x*(x*y)**(3 - i), And(k <= i, i <= 3)), (0, True) ) assert dp(x*(y + 2*KD(i, j)), (j, k, l)) == \ (x*y)**(-k + l + 1) + Piecewise( (2*(x*y)**(i - k)*x*(x*y)**(l - i), And(k <= i, i <= l)), (0, True) ) def test_deltaproduct_mul_add_x_y_add_y_kd(): assert dp((x + y)*(y + KD(i, j)), (j, 1, 3)) == ((x + y)*y)**3 + \ (x + y)*((x + y)*y)**2*KD(i, 1) + \ (x + y)*y*(x + y)**2*y*KD(i, 2) + \ ((x + y)*y)**2*(x + y)*KD(i, 3) assert dp((x + y)*(y + KD(i, j)), (j, 1, 1)) == (x + y)*(y + KD(i, 1)) assert dp((x + y)*(y + KD(i, j)), (j, 2, 2)) == (x + y)*(y + KD(i, 2)) assert dp((x + y)*(y + KD(i, j)), (j, 3, 3)) == (x + y)*(y + KD(i, 3)) assert dp((x + y)*(y + KD(i, j)), (j, 1, k)) == \ ((x + y)*y)**k + Piecewise( (((x + y)*y)**(i - 1)*(x + y)*((x + y)*y)**(k - i), And(1 <= i, i <= k)), (0, True) ) assert dp((x + y)*(y + KD(i, j)), (j, k, 3)) == \ ((x + y)*y)**(-k + 4) + Piecewise( (((x + y)*y)**(i - k)*(x + y)*((x + y)*y)**(3 - i), And(k <= i, i <= 3)), (0, True) ) assert dp((x + y)*(y + KD(i, j)), (j, k, l)) == \ ((x + y)*y)**(-k + l + 1) + Piecewise( (((x + y)*y)**(i - k)*(x + y)*((x + y)*y)**(l - i), And(k <= i, i <= l)), (0, True) ) def test_deltaproduct_mul_add_x_kd_add_y_kd(): assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 1, 3)) == \ KD(i, 1)*(KD(i, k) + x)*((KD(i, k) + x)*y)**2 + \ KD(i, 2)*(KD(i, k) + x)*y*(KD(i, k) + x)**2*y + \ KD(i, 3)*((KD(i, k) + x)*y)**2*(KD(i, k) + x) + \ ((KD(i, k) + x)*y)**3 assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 1, 1)) == \ (x + KD(i, k))*(y + KD(i, 1)) assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 2, 2)) == \ (x + KD(i, k))*(y + KD(i, 2)) assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 3, 3)) == \ (x + KD(i, k))*(y + KD(i, 3)) assert dp((x + KD(i, k))*(y + KD(i, j)), (j, 1, k)) == \ ((x + KD(i, k))*y)**k + Piecewise( (((x + KD(i, k))*y)**(i - 1)*(x + KD(i, k))* ((x + KD(i, k))*y)**(-i + k), And(1 <= i, i <= k)), (0, True) ) assert dp((x + KD(i, k))*(y + KD(i, j)), (j, k, 3)) == \ ((x + KD(i, k))*y)**(4 - k) + Piecewise( (((x + KD(i, k))*y)**(i - k)*(x + KD(i, k))* ((x + KD(i, k))*y)**(-i + 3), And(k <= i, i <= 3)), (0, True) ) assert dp((x + KD(i, k))*(y + KD(i, j)), (j, k, l)) == \ ((x + KD(i, k))*y)**(-k + l + 1) + Piecewise( (((x + KD(i, k))*y)**(i - k)*(x + KD(i, k))* ((x + KD(i, k))*y)**(-i + l), And(k <= i, i <= l)), (0, True) ) def test_deltasummation_trivial(): assert ds(x, (j, 1, 0)) == 0 assert ds(x, (j, 1, 3)) == 3*x assert ds(x + y, (j, 1, 3)) == 3*(x + y) assert ds(x*y, (j, 1, 3)) == 3*x*y assert ds(KD(i, j), (k, 1, 3)) == 3*KD(i, j) assert ds(x*KD(i, j), (k, 1, 3)) == 3*x*KD(i, j) assert ds(x*y*KD(i, j), (k, 1, 3)) == 3*x*y*KD(i, j) def test_deltasummation_basic_numerical(): n = symbols('n', integer=True, nonzero=True) assert ds(KD(n, 0), (n, 1, 3)) == 0 # return unevaluated, until it gets implemented assert ds(KD(i**2, j**2), (j, -oo, oo)) == \ Sum(KD(i**2, j**2), (j, -oo, oo)) assert Piecewise((KD(i, k), And(1 <= i, i <= 3)), (0, True)) == \ ds(KD(i, j)*KD(j, k), (j, 1, 3)) == \ ds(KD(j, k)*KD(i, j), (j, 1, 3)) assert ds(KD(i, k), (k, -oo, oo)) == 1 assert ds(KD(i, k), (k, 0, oo)) == Piecewise((1, S.Zero <= i), (0, True)) assert ds(KD(i, k), (k, 1, 3)) == \ Piecewise((1, And(1 <= i, i <= 3)), (0, True)) assert ds(k*KD(i, j)*KD(j, k), (k, -oo, oo)) == j*KD(i, j) assert ds(j*KD(i, j), (j, -oo, oo)) == i assert ds(i*KD(i, j), (i, -oo, oo)) == j assert ds(x, (i, 1, 3)) == 3*x assert ds((i + j)*KD(i, j), (j, -oo, oo)) == 2*i def test_deltasummation_basic_symbolic(): assert ds(KD(i, j), (j, 1, 3)) == \ Piecewise((1, And(1 <= i, i <= 3)), (0, True)) assert ds(KD(i, j), (j, 1, 1)) == Piecewise((1, Eq(i, 1)), (0, True)) assert ds(KD(i, j), (j, 2, 2)) == Piecewise((1, Eq(i, 2)), (0, True)) assert ds(KD(i, j), (j, 3, 3)) == Piecewise((1, Eq(i, 3)), (0, True)) assert ds(KD(i, j), (j, 1, k)) == \ Piecewise((1, And(1 <= i, i <= k)), (0, True)) assert ds(KD(i, j), (j, k, 3)) == \ Piecewise((1, And(k <= i, i <= 3)), (0, True)) assert ds(KD(i, j), (j, k, l)) == \ Piecewise((1, And(k <= i, i <= l)), (0, True)) def test_deltasummation_mul_x_kd(): assert ds(x*KD(i, j), (j, 1, 3)) == \ Piecewise((x, And(1 <= i, i <= 3)), (0, True)) assert ds(x*KD(i, j), (j, 1, 1)) == Piecewise((x, Eq(i, 1)), (0, True)) assert ds(x*KD(i, j), (j, 2, 2)) == Piecewise((x, Eq(i, 2)), (0, True)) assert ds(x*KD(i, j), (j, 3, 3)) == Piecewise((x, Eq(i, 3)), (0, True)) assert ds(x*KD(i, j), (j, 1, k)) == \ Piecewise((x, And(1 <= i, i <= k)), (0, True)) assert ds(x*KD(i, j), (j, k, 3)) == \ Piecewise((x, And(k <= i, i <= 3)), (0, True)) assert ds(x*KD(i, j), (j, k, l)) == \ Piecewise((x, And(k <= i, i <= l)), (0, True)) def test_deltasummation_mul_add_x_y_kd(): assert ds((x + y)*KD(i, j), (j, 1, 3)) == \ Piecewise((x + y, And(1 <= i, i <= 3)), (0, True)) assert ds((x + y)*KD(i, j), (j, 1, 1)) == \ Piecewise((x + y, Eq(i, 1)), (0, True)) assert ds((x + y)*KD(i, j), (j, 2, 2)) == \ Piecewise((x + y, Eq(i, 2)), (0, True)) assert ds((x + y)*KD(i, j), (j, 3, 3)) == \ Piecewise((x + y, Eq(i, 3)), (0, True)) assert ds((x + y)*KD(i, j), (j, 1, k)) == \ Piecewise((x + y, And(1 <= i, i <= k)), (0, True)) assert ds((x + y)*KD(i, j), (j, k, 3)) == \ Piecewise((x + y, And(k <= i, i <= 3)), (0, True)) assert ds((x + y)*KD(i, j), (j, k, l)) == \ Piecewise((x + y, And(k <= i, i <= l)), (0, True)) def test_deltasummation_add_kd_kd(): assert ds(KD(i, k) + KD(j, k), (k, 1, 3)) == piecewise_fold( Piecewise((1, And(1 <= i, i <= 3)), (0, True)) + Piecewise((1, And(1 <= j, j <= 3)), (0, True))) assert ds(KD(i, k) + KD(j, k), (k, 1, 1)) == piecewise_fold( Piecewise((1, Eq(i, 1)), (0, True)) + Piecewise((1, Eq(j, 1)), (0, True))) assert ds(KD(i, k) + KD(j, k), (k, 2, 2)) == piecewise_fold( Piecewise((1, Eq(i, 2)), (0, True)) + Piecewise((1, Eq(j, 2)), (0, True))) assert ds(KD(i, k) + KD(j, k), (k, 3, 3)) == piecewise_fold( Piecewise((1, Eq(i, 3)), (0, True)) + Piecewise((1, Eq(j, 3)), (0, True))) assert ds(KD(i, k) + KD(j, k), (k, 1, l)) == piecewise_fold( Piecewise((1, And(1 <= i, i <= l)), (0, True)) + Piecewise((1, And(1 <= j, j <= l)), (0, True))) assert ds(KD(i, k) + KD(j, k), (k, l, 3)) == piecewise_fold( Piecewise((1, And(l <= i, i <= 3)), (0, True)) + Piecewise((1, And(l <= j, j <= 3)), (0, True))) assert ds(KD(i, k) + KD(j, k), (k, l, m)) == piecewise_fold( Piecewise((1, And(l <= i, i <= m)), (0, True)) + Piecewise((1, And(l <= j, j <= m)), (0, True))) def test_deltasummation_add_mul_x_kd_kd(): assert ds(x*KD(i, k) + KD(j, k), (k, 1, 3)) == piecewise_fold( Piecewise((x, And(1 <= i, i <= 3)), (0, True)) + Piecewise((1, And(1 <= j, j <= 3)), (0, True))) assert ds(x*KD(i, k) + KD(j, k), (k, 1, 1)) == piecewise_fold( Piecewise((x, Eq(i, 1)), (0, True)) + Piecewise((1, Eq(j, 1)), (0, True))) assert ds(x*KD(i, k) + KD(j, k), (k, 2, 2)) == piecewise_fold( Piecewise((x, Eq(i, 2)), (0, True)) + Piecewise((1, Eq(j, 2)), (0, True))) assert ds(x*KD(i, k) + KD(j, k), (k, 3, 3)) == piecewise_fold( Piecewise((x, Eq(i, 3)), (0, True)) + Piecewise((1, Eq(j, 3)), (0, True))) assert ds(x*KD(i, k) + KD(j, k), (k, 1, l)) == piecewise_fold( Piecewise((x, And(1 <= i, i <= l)), (0, True)) + Piecewise((1, And(1 <= j, j <= l)), (0, True))) assert ds(x*KD(i, k) + KD(j, k), (k, l, 3)) == piecewise_fold( Piecewise((x, And(l <= i, i <= 3)), (0, True)) + Piecewise((1, And(l <= j, j <= 3)), (0, True))) assert ds(x*KD(i, k) + KD(j, k), (k, l, m)) == piecewise_fold( Piecewise((x, And(l <= i, i <= m)), (0, True)) + Piecewise((1, And(l <= j, j <= m)), (0, True))) def test_deltasummation_mul_x_add_kd_kd(): assert ds(x*(KD(i, k) + KD(j, k)), (k, 1, 3)) == piecewise_fold( Piecewise((x, And(1 <= i, i <= 3)), (0, True)) + Piecewise((x, And(1 <= j, j <= 3)), (0, True))) assert ds(x*(KD(i, k) + KD(j, k)), (k, 1, 1)) == piecewise_fold( Piecewise((x, Eq(i, 1)), (0, True)) + Piecewise((x, Eq(j, 1)), (0, True))) assert ds(x*(KD(i, k) + KD(j, k)), (k, 2, 2)) == piecewise_fold( Piecewise((x, Eq(i, 2)), (0, True)) + Piecewise((x, Eq(j, 2)), (0, True))) assert ds(x*(KD(i, k) + KD(j, k)), (k, 3, 3)) == piecewise_fold( Piecewise((x, Eq(i, 3)), (0, True)) + Piecewise((x, Eq(j, 3)), (0, True))) assert ds(x*(KD(i, k) + KD(j, k)), (k, 1, l)) == piecewise_fold( Piecewise((x, And(1 <= i, i <= l)), (0, True)) + Piecewise((x, And(1 <= j, j <= l)), (0, True))) assert ds(x*(KD(i, k) + KD(j, k)), (k, l, 3)) == piecewise_fold( Piecewise((x, And(l <= i, i <= 3)), (0, True)) + Piecewise((x, And(l <= j, j <= 3)), (0, True))) assert ds(x*(KD(i, k) + KD(j, k)), (k, l, m)) == piecewise_fold( Piecewise((x, And(l <= i, i <= m)), (0, True)) + Piecewise((x, And(l <= j, j <= m)), (0, True))) def test_deltasummation_mul_add_x_y_add_kd_kd(): assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 3)) == piecewise_fold( Piecewise((x + y, And(1 <= i, i <= 3)), (0, True)) + Piecewise((x + y, And(1 <= j, j <= 3)), (0, True))) assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 1, 1)) == piecewise_fold( Piecewise((x + y, Eq(i, 1)), (0, True)) + Piecewise((x + y, Eq(j, 1)), (0, True))) assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 2, 2)) == piecewise_fold( Piecewise((x + y, Eq(i, 2)), (0, True)) + Piecewise((x + y, Eq(j, 2)), (0, True))) assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 3, 3)) == piecewise_fold( Piecewise((x + y, Eq(i, 3)), (0, True)) + Piecewise((x + y, Eq(j, 3)), (0, True))) assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, 1, l)) == piecewise_fold( Piecewise((x + y, And(1 <= i, i <= l)), (0, True)) + Piecewise((x + y, And(1 <= j, j <= l)), (0, True))) assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, l, 3)) == piecewise_fold( Piecewise((x + y, And(l <= i, i <= 3)), (0, True)) + Piecewise((x + y, And(l <= j, j <= 3)), (0, True))) assert ds((x + y)*(KD(i, k) + KD(j, k)), (k, l, m)) == piecewise_fold( Piecewise((x + y, And(l <= i, i <= m)), (0, True)) + Piecewise((x + y, And(l <= j, j <= m)), (0, True))) def test_deltasummation_add_mul_x_y_mul_x_kd(): assert ds(x*y + x*KD(i, j), (j, 1, 3)) == \ Piecewise((3*x*y + x, And(1 <= i, i <= 3)), (3*x*y, True)) assert ds(x*y + x*KD(i, j), (j, 1, 1)) == \ Piecewise((x*y + x, Eq(i, 1)), (x*y, True)) assert ds(x*y + x*KD(i, j), (j, 2, 2)) == \ Piecewise((x*y + x, Eq(i, 2)), (x*y, True)) assert ds(x*y + x*KD(i, j), (j, 3, 3)) == \ Piecewise((x*y + x, Eq(i, 3)), (x*y, True)) assert ds(x*y + x*KD(i, j), (j, 1, k)) == \ Piecewise((k*x*y + x, And(1 <= i, i <= k)), (k*x*y, True)) assert ds(x*y + x*KD(i, j), (j, k, 3)) == \ Piecewise(((4 - k)*x*y + x, And(k <= i, i <= 3)), ((4 - k)*x*y, True)) assert ds(x*y + x*KD(i, j), (j, k, l)) == Piecewise( ((l - k + 1)*x*y + x, And(k <= i, i <= l)), ((l - k + 1)*x*y, True)) def test_deltasummation_mul_x_add_y_kd(): assert ds(x*(y + KD(i, j)), (j, 1, 3)) == \ Piecewise((3*x*y + x, And(1 <= i, i <= 3)), (3*x*y, True)) assert ds(x*(y + KD(i, j)), (j, 1, 1)) == \ Piecewise((x*y + x, Eq(i, 1)), (x*y, True)) assert ds(x*(y + KD(i, j)), (j, 2, 2)) == \ Piecewise((x*y + x, Eq(i, 2)), (x*y, True)) assert ds(x*(y + KD(i, j)), (j, 3, 3)) == \ Piecewise((x*y + x, Eq(i, 3)), (x*y, True)) assert ds(x*(y + KD(i, j)), (j, 1, k)) == \ Piecewise((k*x*y + x, And(1 <= i, i <= k)), (k*x*y, True)) assert ds(x*(y + KD(i, j)), (j, k, 3)) == \ Piecewise(((4 - k)*x*y + x, And(k <= i, i <= 3)), ((4 - k)*x*y, True)) assert ds(x*(y + KD(i, j)), (j, k, l)) == Piecewise( ((l - k + 1)*x*y + x, And(k <= i, i <= l)), ((l - k + 1)*x*y, True)) def test_deltasummation_mul_x_add_y_twokd(): assert ds(x*(y + 2*KD(i, j)), (j, 1, 3)) == \ Piecewise((3*x*y + 2*x, And(1 <= i, i <= 3)), (3*x*y, True)) assert ds(x*(y + 2*KD(i, j)), (j, 1, 1)) == \ Piecewise((x*y + 2*x, Eq(i, 1)), (x*y, True)) assert ds(x*(y + 2*KD(i, j)), (j, 2, 2)) == \ Piecewise((x*y + 2*x, Eq(i, 2)), (x*y, True)) assert ds(x*(y + 2*KD(i, j)), (j, 3, 3)) == \ Piecewise((x*y + 2*x, Eq(i, 3)), (x*y, True)) assert ds(x*(y + 2*KD(i, j)), (j, 1, k)) == \ Piecewise((k*x*y + 2*x, And(1 <= i, i <= k)), (k*x*y, True)) assert ds(x*(y + 2*KD(i, j)), (j, k, 3)) == Piecewise( ((4 - k)*x*y + 2*x, And(k <= i, i <= 3)), ((4 - k)*x*y, True)) assert ds(x*(y + 2*KD(i, j)), (j, k, l)) == Piecewise( ((l - k + 1)*x*y + 2*x, And(k <= i, i <= l)), ((l - k + 1)*x*y, True)) def test_deltasummation_mul_add_x_y_add_y_kd(): assert ds((x + y)*(y + KD(i, j)), (j, 1, 3)) == Piecewise( (3*(x + y)*y + x + y, And(1 <= i, i <= 3)), (3*(x + y)*y, True)) assert ds((x + y)*(y + KD(i, j)), (j, 1, 1)) == \ Piecewise(((x + y)*y + x + y, Eq(i, 1)), ((x + y)*y, True)) assert ds((x + y)*(y + KD(i, j)), (j, 2, 2)) == \ Piecewise(((x + y)*y + x + y, Eq(i, 2)), ((x + y)*y, True)) assert ds((x + y)*(y + KD(i, j)), (j, 3, 3)) == \ Piecewise(((x + y)*y + x + y, Eq(i, 3)), ((x + y)*y, True)) assert ds((x + y)*(y + KD(i, j)), (j, 1, k)) == Piecewise( (k*(x + y)*y + x + y, And(1 <= i, i <= k)), (k*(x + y)*y, True)) assert ds((x + y)*(y + KD(i, j)), (j, k, 3)) == Piecewise( ((4 - k)*(x + y)*y + x + y, And(k <= i, i <= 3)), ((4 - k)*(x + y)*y, True)) assert ds((x + y)*(y + KD(i, j)), (j, k, l)) == Piecewise( ((l - k + 1)*(x + y)*y + x + y, And(k <= i, i <= l)), ((l - k + 1)*(x + y)*y, True)) def test_deltasummation_mul_add_x_kd_add_y_kd(): assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 1, 3)) == piecewise_fold( Piecewise((KD(i, k) + x, And(1 <= i, i <= 3)), (0, True)) + 3*(KD(i, k) + x)*y) assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 1, 1)) == piecewise_fold( Piecewise((KD(i, k) + x, Eq(i, 1)), (0, True)) + (KD(i, k) + x)*y) assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 2, 2)) == piecewise_fold( Piecewise((KD(i, k) + x, Eq(i, 2)), (0, True)) + (KD(i, k) + x)*y) assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 3, 3)) == piecewise_fold( Piecewise((KD(i, k) + x, Eq(i, 3)), (0, True)) + (KD(i, k) + x)*y) assert ds((x + KD(i, k))*(y + KD(i, j)), (j, 1, k)) == piecewise_fold( Piecewise((KD(i, k) + x, And(1 <= i, i <= k)), (0, True)) + k*(KD(i, k) + x)*y) assert ds((x + KD(i, k))*(y + KD(i, j)), (j, k, 3)) == piecewise_fold( Piecewise((KD(i, k) + x, And(k <= i, i <= 3)), (0, True)) + (4 - k)*(KD(i, k) + x)*y) assert ds((x + KD(i, k))*(y + KD(i, j)), (j, k, l)) == piecewise_fold( Piecewise((KD(i, k) + x, And(k <= i, i <= l)), (0, True)) + (l - k + 1)*(KD(i, k) + x)*y) def test_extract_delta(): raises(ValueError, lambda: _extract_delta(KD(i, j) + KD(k, l), i)) sympy-sympy-1.9/sympy/concrete/tests/test_gosper.py000066400000000000000000000167301412543434000227670ustar00rootroot00000000000000"""Tests for Gosper's algorithm for hypergeometric summation. """ from sympy import binomial, factorial, gamma, Poly, S, simplify, sqrt, exp, \ log, Symbol, pi, Rational from sympy.abc import a, b, j, k, m, n, r, x from sympy.concrete.gosper import gosper_normal, gosper_sum, gosper_term def test_gosper_normal(): eq = 4*n + 5, 2*(4*n + 1)*(2*n + 3), n assert gosper_normal(*eq) == \ (Poly(Rational(1, 4), n), Poly(n + Rational(3, 2)), Poly(n + Rational(1, 4))) assert gosper_normal(*eq, polys=False) == \ (Rational(1, 4), n + Rational(3, 2), n + Rational(1, 4)) def test_gosper_term(): assert gosper_term((4*k + 1)*factorial( k)/factorial(2*k + 1), k) == (-k - S.Half)/(k + Rational(1, 4)) def test_gosper_sum(): assert gosper_sum(1, (k, 0, n)) == 1 + n assert gosper_sum(k, (k, 0, n)) == n*(1 + n)/2 assert gosper_sum(k**2, (k, 0, n)) == n*(1 + n)*(1 + 2*n)/6 assert gosper_sum(k**3, (k, 0, n)) == n**2*(1 + n)**2/4 assert gosper_sum(2**k, (k, 0, n)) == 2*2**n - 1 assert gosper_sum(factorial(k), (k, 0, n)) is None assert gosper_sum(binomial(n, k), (k, 0, n)) is None assert gosper_sum(factorial(k)/k**2, (k, 0, n)) is None assert gosper_sum((k - 3)*factorial(k), (k, 0, n)) is None assert gosper_sum(k*factorial(k), k) == factorial(k) assert gosper_sum( k*factorial(k), (k, 0, n)) == n*factorial(n) + factorial(n) - 1 assert gosper_sum((-1)**k*binomial(n, k), (k, 0, n)) == 0 assert gosper_sum(( -1)**k*binomial(n, k), (k, 0, m)) == -(-1)**m*(m - n)*binomial(n, m)/n assert gosper_sum((4*k + 1)*factorial(k)/factorial(2*k + 1), (k, 0, n)) == \ (2*factorial(2*n + 1) - factorial(n))/factorial(2*n + 1) # issue 6033: assert gosper_sum( n*(n + a + b)*a**n*b**n/(factorial(n + a)*factorial(n + b)), \ (n, 0, m)).simplify() == -exp(m*log(a) + m*log(b))*gamma(a + 1) \ *gamma(b + 1)/(gamma(a)*gamma(b)*gamma(a + m + 1)*gamma(b + m + 1)) \ + 1/(gamma(a)*gamma(b)) def test_gosper_sum_indefinite(): assert gosper_sum(k, k) == k*(k - 1)/2 assert gosper_sum(k**2, k) == k*(k - 1)*(2*k - 1)/6 assert gosper_sum(1/(k*(k + 1)), k) == -1/k assert gosper_sum(-(27*k**4 + 158*k**3 + 430*k**2 + 678*k + 445)*gamma(2*k + 4)/(3*(3*k + 7)*gamma(3*k + 6)), k) == \ (3*k + 5)*(k**2 + 2*k + 5)*gamma(2*k + 4)/gamma(3*k + 6) def test_gosper_sum_parametric(): assert gosper_sum(binomial(S.Half, m - j + 1)*binomial(S.Half, m + j), (j, 1, n)) == \ n*(1 + m - n)*(-1 + 2*m + 2*n)*binomial(S.Half, 1 + m - n)* \ binomial(S.Half, m + n)/(m*(1 + 2*m)) def test_gosper_sum_algebraic(): assert gosper_sum( n**2 + sqrt(2), (n, 0, m)) == (m + 1)*(2*m**2 + m + 6*sqrt(2))/6 def test_gosper_sum_iterated(): f1 = binomial(2*k, k)/4**k f2 = (1 + 2*n)*binomial(2*n, n)/4**n f3 = (1 + 2*n)*(3 + 2*n)*binomial(2*n, n)/(3*4**n) f4 = (1 + 2*n)*(3 + 2*n)*(5 + 2*n)*binomial(2*n, n)/(15*4**n) f5 = (1 + 2*n)*(3 + 2*n)*(5 + 2*n)*(7 + 2*n)*binomial(2*n, n)/(105*4**n) assert gosper_sum(f1, (k, 0, n)) == f2 assert gosper_sum(f2, (n, 0, n)) == f3 assert gosper_sum(f3, (n, 0, n)) == f4 assert gosper_sum(f4, (n, 0, n)) == f5 # the AeqB tests test expressions given in # www.math.upenn.edu/~wilf/AeqB.pdf def test_gosper_sum_AeqB_part1(): f1a = n**4 f1b = n**3*2**n f1c = 1/(n**2 + sqrt(5)*n - 1) f1d = n**4*4**n/binomial(2*n, n) f1e = factorial(3*n)/(factorial(n)*factorial(n + 1)*factorial(n + 2)*27**n) f1f = binomial(2*n, n)**2/((n + 1)*4**(2*n)) f1g = (4*n - 1)*binomial(2*n, n)**2/((2*n - 1)**2*4**(2*n)) f1h = n*factorial(n - S.Half)**2/factorial(n + 1)**2 g1a = m*(m + 1)*(2*m + 1)*(3*m**2 + 3*m - 1)/30 g1b = 26 + 2**(m + 1)*(m**3 - 3*m**2 + 9*m - 13) g1c = (m + 1)*(m*(m**2 - 7*m + 3)*sqrt(5) - ( 3*m**3 - 7*m**2 + 19*m - 6))/(2*m**3*sqrt(5) + m**4 + 5*m**2 - 1)/6 g1d = Rational(-2, 231) + 2*4**m*(m + 1)*(63*m**4 + 112*m**3 + 18*m**2 - 22*m + 3)/(693*binomial(2*m, m)) g1e = Rational(-9, 2) + (81*m**2 + 261*m + 200)*factorial( 3*m + 2)/(40*27**m*factorial(m)*factorial(m + 1)*factorial(m + 2)) g1f = (2*m + 1)**2*binomial(2*m, m)**2/(4**(2*m)*(m + 1)) g1g = -binomial(2*m, m)**2/4**(2*m) g1h = 4*pi -(2*m + 1)**2*(3*m + 4)*factorial(m - S.Half)**2/factorial(m + 1)**2 g = gosper_sum(f1a, (n, 0, m)) assert g is not None and simplify(g - g1a) == 0 g = gosper_sum(f1b, (n, 0, m)) assert g is not None and simplify(g - g1b) == 0 g = gosper_sum(f1c, (n, 0, m)) assert g is not None and simplify(g - g1c) == 0 g = gosper_sum(f1d, (n, 0, m)) assert g is not None and simplify(g - g1d) == 0 g = gosper_sum(f1e, (n, 0, m)) assert g is not None and simplify(g - g1e) == 0 g = gosper_sum(f1f, (n, 0, m)) assert g is not None and simplify(g - g1f) == 0 g = gosper_sum(f1g, (n, 0, m)) assert g is not None and simplify(g - g1g) == 0 g = gosper_sum(f1h, (n, 0, m)) # need to call rewrite(gamma) here because we have terms involving # factorial(1/2) assert g is not None and simplify(g - g1h).rewrite(gamma) == 0 def test_gosper_sum_AeqB_part2(): f2a = n**2*a**n f2b = (n - r/2)*binomial(r, n) f2c = factorial(n - 1)**2/(factorial(n - x)*factorial(n + x)) g2a = -a*(a + 1)/(a - 1)**3 + a**( m + 1)*(a**2*m**2 - 2*a*m**2 + m**2 - 2*a*m + 2*m + a + 1)/(a - 1)**3 g2b = (m - r)*binomial(r, m)/2 ff = factorial(1 - x)*factorial(1 + x) g2c = 1/ff*( 1 - 1/x**2) + factorial(m)**2/(x**2*factorial(m - x)*factorial(m + x)) g = gosper_sum(f2a, (n, 0, m)) assert g is not None and simplify(g - g2a) == 0 g = gosper_sum(f2b, (n, 0, m)) assert g is not None and simplify(g - g2b) == 0 g = gosper_sum(f2c, (n, 1, m)) assert g is not None and simplify(g - g2c) == 0 def test_gosper_nan(): a = Symbol('a', positive=True) b = Symbol('b', positive=True) n = Symbol('n', integer=True) m = Symbol('m', integer=True) f2d = n*(n + a + b)*a**n*b**n/(factorial(n + a)*factorial(n + b)) g2d = 1/(factorial(a - 1)*factorial( b - 1)) - a**(m + 1)*b**(m + 1)/(factorial(a + m)*factorial(b + m)) g = gosper_sum(f2d, (n, 0, m)) assert simplify(g - g2d) == 0 def test_gosper_sum_AeqB_part3(): f3a = 1/n**4 f3b = (6*n + 3)/(4*n**4 + 8*n**3 + 8*n**2 + 4*n + 3) f3c = 2**n*(n**2 - 2*n - 1)/(n**2*(n + 1)**2) f3d = n**2*4**n/((n + 1)*(n + 2)) f3e = 2**n/(n + 1) f3f = 4*(n - 1)*(n**2 - 2*n - 1)/(n**2*(n + 1)**2*(n - 2)**2*(n - 3)**2) f3g = (n**4 - 14*n**2 - 24*n - 9)*2**n/(n**2*(n + 1)**2*(n + 2)**2* (n + 3)**2) # g3a -> no closed form g3b = m*(m + 2)/(2*m**2 + 4*m + 3) g3c = 2**m/m**2 - 2 g3d = Rational(2, 3) + 4**(m + 1)*(m - 1)/(m + 2)/3 # g3e -> no closed form g3f = -(Rational(-1, 16) + 1/((m - 2)**2*(m + 1)**2)) # the AeqB key is wrong g3g = Rational(-2, 9) + 2**(m + 1)/((m + 1)**2*(m + 3)**2) g = gosper_sum(f3a, (n, 1, m)) assert g is None g = gosper_sum(f3b, (n, 1, m)) assert g is not None and simplify(g - g3b) == 0 g = gosper_sum(f3c, (n, 1, m - 1)) assert g is not None and simplify(g - g3c) == 0 g = gosper_sum(f3d, (n, 1, m)) assert g is not None and simplify(g - g3d) == 0 g = gosper_sum(f3e, (n, 0, m - 1)) assert g is None g = gosper_sum(f3f, (n, 4, m)) assert g is not None and simplify(g - g3f) == 0 g = gosper_sum(f3g, (n, 1, m)) assert g is not None and simplify(g - g3g) == 0 sympy-sympy-1.9/sympy/concrete/tests/test_guess.py000066400000000000000000000057631412543434000226220ustar00rootroot00000000000000from sympy.concrete.guess import ( find_simple_recurrence_vector, find_simple_recurrence, rationalize, guess_generating_function_rational, guess_generating_function, guess ) from sympy import (Function, Symbol, sympify, Rational, symbols, S, fibonacci, factorial, exp, Product, RisingFactorial) def test_find_simple_recurrence_vector(): assert find_simple_recurrence_vector( [fibonacci(k) for k in range(12)]) == [1, -1, -1] def test_find_simple_recurrence(): a = Function('a') n = Symbol('n') assert find_simple_recurrence([fibonacci(k) for k in range(12)]) == ( -a(n) - a(n + 1) + a(n + 2)) f = Function('a') i = Symbol('n') a = [1, 1, 1] for k in range(15): a.append(5*a[-1]-3*a[-2]+8*a[-3]) assert find_simple_recurrence(a, A=f, N=i) == ( -8*f(i) + 3*f(i + 1) - 5*f(i + 2) + f(i + 3)) assert find_simple_recurrence([0, 2, 15, 74, 12, 3, 0, 1, 2, 85, 4, 5, 63]) == 0 def test_rationalize(): from mpmath import cos, pi, mpf assert rationalize(cos(pi/3)) == S.Half assert rationalize(mpf("0.333333333333333")) == Rational(1, 3) assert rationalize(mpf("-0.333333333333333")) == Rational(-1, 3) assert rationalize(pi, maxcoeff = 250) == Rational(355, 113) def test_guess_generating_function_rational(): x = Symbol('x') assert guess_generating_function_rational([fibonacci(k) for k in range(5, 15)]) == ((3*x + 5)/(-x**2 - x + 1)) def test_guess_generating_function(): x = Symbol('x') assert guess_generating_function([fibonacci(k) for k in range(5, 15)])['ogf'] == ((3*x + 5)/(-x**2 - x + 1)) assert guess_generating_function( [1, 2, 5, 14, 41, 124, 383, 1200, 3799, 12122, 38919])['ogf'] == ( (1/(x**4 + 2*x**2 - 4*x + 1))**S.Half) assert guess_generating_function(sympify( "[3/2, 11/2, 0, -121/2, -363/2, 121, 4719/2, 11495/2, -8712, -178717/2]") )['ogf'] == (x + Rational(3, 2))/(11*x**2 - 3*x + 1) assert guess_generating_function([factorial(k) for k in range(12)], types=['egf'])['egf'] == 1/(-x + 1) assert guess_generating_function([k+1 for k in range(12)], types=['egf']) == {'egf': (x + 1)*exp(x), 'lgdegf': (x + 2)/(x + 1)} def test_guess(): i0, i1 = symbols('i0 i1') assert guess([1, 2, 6, 24, 120], evaluate=False) == [Product(i1 + 1, (i1, 1, i0 - 1))] assert guess([1, 2, 6, 24, 120]) == [RisingFactorial(2, i0 - 1)] assert guess([1, 2, 7, 42, 429, 7436, 218348, 10850216], niter=4) == [ 2**(i0 - 1)*(Rational(27, 16))**(i0**2/2 - 3*i0/2 + 1)*Product(RisingFactorial(Rational(5, 3), i1 - 1)*RisingFactorial(Rational(7, 3), i1 - 1)/(RisingFactorial(Rational(3, 2), i1 - 1)*RisingFactorial(Rational(5, 2), i1 - 1)), (i1, 1, i0 - 1))] assert guess([1, 0, 2]) == [] x, y = symbols('x y') guess([1, 2, 6, 24, 120], variables=[x, y]) == [RisingFactorial(2, x - 1)] sympy-sympy-1.9/sympy/concrete/tests/test_products.py000066400000000000000000000325471412543434000233370ustar00rootroot00000000000000from sympy import (symbols, Symbol, product, combsimp, factorial, rf, sqrt, cos, Function, Product, Rational, Sum, oo, exp, log, S, pi, KroneckerDelta, Derivative, diff, sin, Dummy) from sympy.testing.pytest import raises from sympy import simplify a, k, n, m, x = symbols('a,k,n,m,x', integer=True) f = Function('f') def test_karr_convention(): # Test the Karr product convention that we want to hold. # See his paper "Summation in Finite Terms" for a detailed # reasoning why we really want exactly this definition. # The convention is described for sums on page 309 and # essentially in section 1.4, definition 3. For products # we can find in analogy: # # \prod_{m <= i < n} f(i) 'has the obvious meaning' for m < n # \prod_{m <= i < n} f(i) = 0 for m = n # \prod_{m <= i < n} f(i) = 1 / \prod_{n <= i < m} f(i) for m > n # # It is important to note that he defines all products with # the upper limit being *exclusive*. # In contrast, sympy and the usual mathematical notation has: # # prod_{i = a}^b f(i) = f(a) * f(a+1) * ... * f(b-1) * f(b) # # with the upper limit *inclusive*. So translating between # the two we find that: # # \prod_{m <= i < n} f(i) = \prod_{i = m}^{n-1} f(i) # # where we intentionally used two different ways to typeset the # products and its limits. i = Symbol("i", integer=True) k = Symbol("k", integer=True) j = Symbol("j", integer=True, positive=True) # A simple example with a concrete factors and symbolic limits. # The normal product: m = k and n = k + j and therefore m < n: m = k n = k + j a = m b = n - 1 S1 = Product(i**2, (i, a, b)).doit() # The reversed product: m = k + j and n = k and therefore m > n: m = k + j n = k a = m b = n - 1 S2 = Product(i**2, (i, a, b)).doit() assert S1 * S2 == 1 # Test the empty product: m = k and n = k and therefore m = n: m = k n = k a = m b = n - 1 Sz = Product(i**2, (i, a, b)).doit() assert Sz == 1 # Another example this time with an unspecified factor and # numeric limits. (We can not do both tests in the same example.) f = Function("f") # The normal product with m < n: m = 2 n = 11 a = m b = n - 1 S1 = Product(f(i), (i, a, b)).doit() # The reversed product with m > n: m = 11 n = 2 a = m b = n - 1 S2 = Product(f(i), (i, a, b)).doit() assert simplify(S1 * S2) == 1 # Test the empty product with m = n: m = 5 n = 5 a = m b = n - 1 Sz = Product(f(i), (i, a, b)).doit() assert Sz == 1 def test_karr_proposition_2a(): # Test Karr, page 309, proposition 2, part a i, u, v = symbols('i u v', integer=True) def test_the_product(m, n): # g g = i**3 + 2*i**2 - 3*i # f = Delta g f = simplify(g.subs(i, i+1) / g) # The product a = m b = n - 1 P = Product(f, (i, a, b)).doit() # Test if Product_{m <= i < n} f(i) = g(n) / g(m) assert combsimp(P / (g.subs(i, n) / g.subs(i, m))) == 1 # m < n test_the_product(u, u + v) # m = n test_the_product(u, u) # m > n test_the_product(u + v, u) def test_karr_proposition_2b(): # Test Karr, page 309, proposition 2, part b i, u, v, w = symbols('i u v w', integer=True) def test_the_product(l, n, m): # Productmand s = i**3 # First product a = l b = n - 1 S1 = Product(s, (i, a, b)).doit() # Second product a = l b = m - 1 S2 = Product(s, (i, a, b)).doit() # Third product a = m b = n - 1 S3 = Product(s, (i, a, b)).doit() # Test if S1 = S2 * S3 as required assert combsimp(S1 / (S2 * S3)) == 1 # l < m < n test_the_product(u, u + v, u + v + w) # l < m = n test_the_product(u, u + v, u + v) # l < m > n test_the_product(u, u + v + w, v) # l = m < n test_the_product(u, u, u + v) # l = m = n test_the_product(u, u, u) # l = m > n test_the_product(u + v, u + v, u) # l > m < n test_the_product(u + v, u, u + w) # l > m = n test_the_product(u + v, u, u) # l > m > n test_the_product(u + v + w, u + v, u) def test_simple_products(): assert product(2, (k, a, n)) == 2**(n - a + 1) assert product(k, (k, 1, n)) == factorial(n) assert product(k**3, (k, 1, n)) == factorial(n)**3 assert product(k + 1, (k, 0, n - 1)) == factorial(n) assert product(k + 1, (k, a, n - 1)) == rf(1 + a, n - a) assert product(cos(k), (k, 0, 5)) == cos(1)*cos(2)*cos(3)*cos(4)*cos(5) assert product(cos(k), (k, 3, 5)) == cos(3)*cos(4)*cos(5) assert product(cos(k), (k, 1, Rational(5, 2))) != cos(1)*cos(2) assert isinstance(product(k**k, (k, 1, n)), Product) assert Product(x**k, (k, 1, n)).variables == [k] raises(ValueError, lambda: Product(n)) raises(ValueError, lambda: Product(n, k)) raises(ValueError, lambda: Product(n, k, 1)) raises(ValueError, lambda: Product(n, k, 1, 10)) raises(ValueError, lambda: Product(n, (k, 1))) assert product(1, (n, 1, oo)) == 1 # issue 8301 assert product(2, (n, 1, oo)) is oo assert product(-1, (n, 1, oo)).func is Product def test_multiple_products(): assert product(x, (n, 1, k), (k, 1, m)) == x**(m**2/2 + m/2) assert product(f(n), ( n, 1, m), (m, 1, k)) == Product(f(n), (n, 1, m), (m, 1, k)).doit() assert Product(f(n), (m, 1, k), (n, 1, k)).doit() == \ Product(Product(f(n), (m, 1, k)), (n, 1, k)).doit() == \ product(f(n), (m, 1, k), (n, 1, k)) == \ product(product(f(n), (m, 1, k)), (n, 1, k)) == \ Product(f(n)**k, (n, 1, k)) assert Product( x, (x, 1, k), (k, 1, n)).doit() == Product(factorial(k), (k, 1, n)) assert Product(x**k, (n, 1, k), (k, 1, m)).variables == [n, k] def test_rational_products(): assert product(1 + 1/k, (k, 1, n)) == rf(2, n)/factorial(n) def test_special_products(): # Wallis product assert product((4*k)**2 / (4*k**2 - 1), (k, 1, n)) == \ 4**n*factorial(n)**2/rf(S.Half, n)/rf(Rational(3, 2), n) # Euler's product formula for sin assert product(1 + a/k**2, (k, 1, n)) == \ rf(1 - sqrt(-a), n)*rf(1 + sqrt(-a), n)/factorial(n)**2 def test__eval_product(): from sympy.abc import i, n # issue 4809 a = Function('a') assert product(2*a(i), (i, 1, n)) == 2**n * Product(a(i), (i, 1, n)) # issue 4810 assert product(2**i, (i, 1, n)) == 2**(n/2 + n**2/2) k, m = symbols('k m', integer=True) assert product(2**i, (i, k, m)) == 2**(-k**2/2 + k/2 + m**2/2 + m/2) n = Symbol('n', negative=True, integer=True) p = Symbol('p', positive=True, integer=True) assert product(2**i, (i, n, p)) == 2**(-n**2/2 + n/2 + p**2/2 + p/2) assert product(2**i, (i, p, n)) == 2**(n**2/2 + n/2 - p**2/2 + p/2) def test_product_pow(): # issue 4817 assert product(2**f(k), (k, 1, n)) == 2**Sum(f(k), (k, 1, n)) assert product(2**(2*f(k)), (k, 1, n)) == 2**Sum(2*f(k), (k, 1, n)) def test_infinite_product(): # issue 5737 assert isinstance(Product(2**(1/factorial(n)), (n, 0, oo)), Product) def test_conjugate_transpose(): p = Product(x**k, (k, 1, 3)) assert p.adjoint().doit() == p.doit().adjoint() assert p.conjugate().doit() == p.doit().conjugate() assert p.transpose().doit() == p.doit().transpose() A, B = symbols("A B", commutative=False) p = Product(A*B**k, (k, 1, 3)) assert p.adjoint().doit() == p.doit().adjoint() assert p.conjugate().doit() == p.doit().conjugate() assert p.transpose().doit() == p.doit().transpose() p = Product(B**k*A, (k, 1, 3)) assert p.adjoint().doit() == p.doit().adjoint() assert p.conjugate().doit() == p.doit().conjugate() assert p.transpose().doit() == p.doit().transpose() def test_simplify_prod(): y, t, b, c = symbols('y, t, b, c', integer = True) _simplify = lambda e: simplify(e, doit=False) assert _simplify(Product(x*y, (x, n, m), (y, a, k)) * \ Product(y, (x, n, m), (y, a, k))) == \ Product(x*y**2, (x, n, m), (y, a, k)) assert _simplify(3 * y* Product(x, (x, n, m)) * Product(x, (x, m + 1, a))) \ == 3 * y * Product(x, (x, n, a)) assert _simplify(Product(x, (x, k + 1, a)) * Product(x, (x, n, k))) == \ Product(x, (x, n, a)) assert _simplify(Product(x, (x, k + 1, a)) * Product(x + 1, (x, n, k))) == \ Product(x, (x, k + 1, a)) * Product(x + 1, (x, n, k)) assert _simplify(Product(x, (t, a, b)) * Product(y, (t, a, b)) * \ Product(x, (t, b+1, c))) == Product(x*y, (t, a, b)) * \ Product(x, (t, b+1, c)) assert _simplify(Product(x, (t, a, b)) * Product(x, (t, b+1, c)) * \ Product(y, (t, a, b))) == Product(x*y, (t, a, b)) * \ Product(x, (t, b+1, c)) def test_change_index(): b, y, c, d, z = symbols('b, y, c, d, z', integer = True) assert Product(x, (x, a, b)).change_index(x, x + 1, y) == \ Product(y - 1, (y, a + 1, b + 1)) assert Product(x**2, (x, a, b)).change_index(x, x - 1) == \ Product((x + 1)**2, (x, a - 1, b - 1)) assert Product(x**2, (x, a, b)).change_index(x, -x, y) == \ Product((-y)**2, (y, -b, -a)) assert Product(x, (x, a, b)).change_index(x, -x - 1) == \ Product(-x - 1, (x, - b - 1, -a - 1)) assert Product(x*y, (x, a, b), (y, c, d)).change_index(x, x - 1, z) == \ Product((z + 1)*y, (z, a - 1, b - 1), (y, c, d)) def test_reorder(): b, y, c, d, z = symbols('b, y, c, d, z', integer = True) assert Product(x*y, (x, a, b), (y, c, d)).reorder((0, 1)) == \ Product(x*y, (y, c, d), (x, a, b)) assert Product(x, (x, a, b), (x, c, d)).reorder((0, 1)) == \ Product(x, (x, c, d), (x, a, b)) assert Product(x*y + z, (x, a, b), (z, m, n), (y, c, d)).reorder(\ (2, 0), (0, 1)) == Product(x*y + z, (z, m, n), (y, c, d), (x, a, b)) assert Product(x*y*z, (x, a, b), (y, c, d), (z, m, n)).reorder(\ (0, 1), (1, 2), (0, 2)) == \ Product(x*y*z, (x, a, b), (z, m, n), (y, c, d)) assert Product(x*y*z, (x, a, b), (y, c, d), (z, m, n)).reorder(\ (x, y), (y, z), (x, z)) == \ Product(x*y*z, (x, a, b), (z, m, n), (y, c, d)) assert Product(x*y, (x, a, b), (y, c, d)).reorder((x, 1)) == \ Product(x*y, (y, c, d), (x, a, b)) assert Product(x*y, (x, a, b), (y, c, d)).reorder((y, x)) == \ Product(x*y, (y, c, d), (x, a, b)) def test_Product_is_convergent(): assert Product(1/n**2, (n, 1, oo)).is_convergent() is S.false assert Product(exp(1/n**2), (n, 1, oo)).is_convergent() is S.true assert Product(1/n, (n, 1, oo)).is_convergent() is S.false assert Product(1 + 1/n, (n, 1, oo)).is_convergent() is S.false assert Product(1 + 1/n**2, (n, 1, oo)).is_convergent() is S.true def test_reverse_order(): x, y, a, b, c, d= symbols('x, y, a, b, c, d', integer = True) assert Product(x, (x, 0, 3)).reverse_order(0) == Product(1/x, (x, 4, -1)) assert Product(x*y, (x, 1, 5), (y, 0, 6)).reverse_order(0, 1) == \ Product(x*y, (x, 6, 0), (y, 7, -1)) assert Product(x, (x, 1, 2)).reverse_order(0) == Product(1/x, (x, 3, 0)) assert Product(x, (x, 1, 3)).reverse_order(0) == Product(1/x, (x, 4, 0)) assert Product(x, (x, 1, a)).reverse_order(0) == Product(1/x, (x, a + 1, 0)) assert Product(x, (x, a, 5)).reverse_order(0) == Product(1/x, (x, 6, a - 1)) assert Product(x, (x, a + 1, a + 5)).reverse_order(0) == \ Product(1/x, (x, a + 6, a)) assert Product(x, (x, a + 1, a + 2)).reverse_order(0) == \ Product(1/x, (x, a + 3, a)) assert Product(x, (x, a + 1, a + 1)).reverse_order(0) == \ Product(1/x, (x, a + 2, a)) assert Product(x, (x, a, b)).reverse_order(0) == Product(1/x, (x, b + 1, a - 1)) assert Product(x, (x, a, b)).reverse_order(x) == Product(1/x, (x, b + 1, a - 1)) assert Product(x*y, (x, a, b), (y, 2, 5)).reverse_order(x, 1) == \ Product(x*y, (x, b + 1, a - 1), (y, 6, 1)) assert Product(x*y, (x, a, b), (y, 2, 5)).reverse_order(y, x) == \ Product(x*y, (x, b + 1, a - 1), (y, 6, 1)) def test_issue_9983(): n = Symbol('n', integer=True, positive=True) p = Product(1 + 1/n**Rational(2, 3), (n, 1, oo)) assert p.is_convergent() is S.false assert product(1 + 1/n**Rational(2, 3), (n, 1, oo)) == p.doit() def test_issue_13546(): n = Symbol('n') k = Symbol('k') p = Product(n + 1 / 2**k, (k, 0, n-1)).doit() assert p.subs(n, 2).doit() == Rational(15, 2) def test_issue_14036(): a, n = symbols('a n') assert product(1 - a**2 / (n*pi)**2, [n, 1, oo]) != 0 def test_rewrite_Sum(): assert Product(1 - S.Half**2/k**2, (k, 1, oo)).rewrite(Sum) == \ exp(Sum(log(1 - 1/(4*k**2)), (k, 1, oo))) def test_KroneckerDelta_Product(): y = Symbol('y') assert Product(x*KroneckerDelta(x, y), (x, 0, 1)).doit() == 0 def test_issue_20848(): _i = Dummy('i') t, y, z = symbols('t y z') assert diff(Product(x, (y, 1, z)), x).as_dummy() == Sum(Product(x, (y, 1, _i - 1))*Product(x, (y, _i + 1, z)), (_i, 1, z)).as_dummy() assert diff(Product(x, (y, 1, z)), x).doit() == x**z*z/x assert diff(Product(x, (y, x, z)), x) == Derivative(Product(x, (y, x, z)), x) assert diff(Product(t, (x, 1, z)), x) == S(0) assert Product(sin(n*x), (n, -1, 1)).diff(x).doit() == S(0) sympy-sympy-1.9/sympy/concrete/tests/test_sums_products.py000066400000000000000000001621431412543434000244020ustar00rootroot00000000000000from sympy import ( Abs, And, binomial, Catalan, combsimp, cos, Derivative, E, Eq, exp, EulerGamma, factorial, Function, harmonic, I, Integral, KroneckerDelta, log, nan, oo, pi, Piecewise, Product, product, Rational, S, simplify, Identity, sin, sqrt, Sum, summation, Symbol, symbols, sympify, zeta, gamma, Indexed, Idx, IndexedBase, prod, Dummy, lowergamma, Range, floor, rf, MatrixSymbol, tanh, sinh) from sympy.abc import a, b, c, d, k, m, x, y, z from sympy.concrete.summations import ( telescopic, _dummy_with_inherited_properties_concrete, eval_sum_residue) from sympy.concrete.expr_with_intlimits import ReorderError from sympy.core.facts import InconsistentAssumptions from sympy.testing.pytest import XFAIL, raises, slow from sympy.matrices import \ Matrix, SparseMatrix, ImmutableDenseMatrix, ImmutableSparseMatrix from sympy.core.mod import Mod n = Symbol('n', integer=True) def test_karr_convention(): # Test the Karr summation convention that we want to hold. # See his paper "Summation in Finite Terms" for a detailed # reasoning why we really want exactly this definition. # The convention is described on page 309 and essentially # in section 1.4, definition 3: # # \sum_{m <= i < n} f(i) 'has the obvious meaning' for m < n # \sum_{m <= i < n} f(i) = 0 for m = n # \sum_{m <= i < n} f(i) = - \sum_{n <= i < m} f(i) for m > n # # It is important to note that he defines all sums with # the upper limit being *exclusive*. # In contrast, sympy and the usual mathematical notation has: # # sum_{i = a}^b f(i) = f(a) + f(a+1) + ... + f(b-1) + f(b) # # with the upper limit *inclusive*. So translating between # the two we find that: # # \sum_{m <= i < n} f(i) = \sum_{i = m}^{n-1} f(i) # # where we intentionally used two different ways to typeset the # sum and its limits. i = Symbol("i", integer=True) k = Symbol("k", integer=True) j = Symbol("j", integer=True) # A simple example with a concrete summand and symbolic limits. # The normal sum: m = k and n = k + j and therefore m < n: m = k n = k + j a = m b = n - 1 S1 = Sum(i**2, (i, a, b)).doit() # The reversed sum: m = k + j and n = k and therefore m > n: m = k + j n = k a = m b = n - 1 S2 = Sum(i**2, (i, a, b)).doit() assert simplify(S1 + S2) == 0 # Test the empty sum: m = k and n = k and therefore m = n: m = k n = k a = m b = n - 1 Sz = Sum(i**2, (i, a, b)).doit() assert Sz == 0 # Another example this time with an unspecified summand and # numeric limits. (We can not do both tests in the same example.) f = Function("f") # The normal sum with m < n: m = 2 n = 11 a = m b = n - 1 S1 = Sum(f(i), (i, a, b)).doit() # The reversed sum with m > n: m = 11 n = 2 a = m b = n - 1 S2 = Sum(f(i), (i, a, b)).doit() assert simplify(S1 + S2) == 0 # Test the empty sum with m = n: m = 5 n = 5 a = m b = n - 1 Sz = Sum(f(i), (i, a, b)).doit() assert Sz == 0 e = Piecewise((exp(-i), Mod(i, 2) > 0), (0, True)) s = Sum(e, (i, 0, 11)) assert s.n(3) == s.doit().n(3) def test_karr_proposition_2a(): # Test Karr, page 309, proposition 2, part a i = Symbol("i", integer=True) u = Symbol("u", integer=True) v = Symbol("v", integer=True) def test_the_sum(m, n): # g g = i**3 + 2*i**2 - 3*i # f = Delta g f = simplify(g.subs(i, i+1) - g) # The sum a = m b = n - 1 S = Sum(f, (i, a, b)).doit() # Test if Sum_{m <= i < n} f(i) = g(n) - g(m) assert simplify(S - (g.subs(i, n) - g.subs(i, m))) == 0 # m < n test_the_sum(u, u+v) # m = n test_the_sum(u, u ) # m > n test_the_sum(u+v, u ) def test_karr_proposition_2b(): # Test Karr, page 309, proposition 2, part b i = Symbol("i", integer=True) u = Symbol("u", integer=True) v = Symbol("v", integer=True) w = Symbol("w", integer=True) def test_the_sum(l, n, m): # Summand s = i**3 # First sum a = l b = n - 1 S1 = Sum(s, (i, a, b)).doit() # Second sum a = l b = m - 1 S2 = Sum(s, (i, a, b)).doit() # Third sum a = m b = n - 1 S3 = Sum(s, (i, a, b)).doit() # Test if S1 = S2 + S3 as required assert S1 - (S2 + S3) == 0 # l < m < n test_the_sum(u, u+v, u+v+w) # l < m = n test_the_sum(u, u+v, u+v ) # l < m > n test_the_sum(u, u+v+w, v ) # l = m < n test_the_sum(u, u, u+v ) # l = m = n test_the_sum(u, u, u ) # l = m > n test_the_sum(u+v, u+v, u ) # l > m < n test_the_sum(u+v, u, u+w ) # l > m = n test_the_sum(u+v, u, u ) # l > m > n test_the_sum(u+v+w, u+v, u ) def test_arithmetic_sums(): assert summation(1, (n, a, b)) == b - a + 1 assert Sum(S.NaN, (n, a, b)) is S.NaN assert Sum(x, (n, a, a)).doit() == x assert Sum(x, (x, a, a)).doit() == a assert Sum(x, (n, 1, a)).doit() == a*x assert Sum(x, (x, Range(1, 11))).doit() == 55 assert Sum(x, (x, Range(1, 11, 2))).doit() == 25 assert Sum(x, (x, Range(1, 10, 2))) == Sum(x, (x, Range(9, 0, -2))) lo, hi = 1, 2 s1 = Sum(n, (n, lo, hi)) s2 = Sum(n, (n, hi, lo)) assert s1 != s2 assert s1.doit() == 3 and s2.doit() == 0 lo, hi = x, x + 1 s1 = Sum(n, (n, lo, hi)) s2 = Sum(n, (n, hi, lo)) assert s1 != s2 assert s1.doit() == 2*x + 1 and s2.doit() == 0 assert Sum(Integral(x, (x, 1, y)) + x, (x, 1, 2)).doit() == \ y**2 + 2 assert summation(1, (n, 1, 10)) == 10 assert summation(2*n, (n, 0, 10**10)) == 100000000010000000000 assert summation(4*n*m, (n, a, 1), (m, 1, d)).expand() == \ 2*d + 2*d**2 + a*d + a*d**2 - d*a**2 - a**2*d**2 assert summation(cos(n), (n, -2, 1)) == cos(-2) + cos(-1) + cos(0) + cos(1) assert summation(cos(n), (n, x, x + 2)) == cos(x) + cos(x + 1) + cos(x + 2) assert isinstance(summation(cos(n), (n, x, x + S.Half)), Sum) assert summation(k, (k, 0, oo)) is oo assert summation(k, (k, Range(1, 11))) == 55 def test_polynomial_sums(): assert summation(n**2, (n, 3, 8)) == 199 assert summation(n, (n, a, b)) == \ ((a + b)*(b - a + 1)/2).expand() assert summation(n**2, (n, 1, b)) == \ ((2*b**3 + 3*b**2 + b)/6).expand() assert summation(n**3, (n, 1, b)) == \ ((b**4 + 2*b**3 + b**2)/4).expand() assert summation(n**6, (n, 1, b)) == \ ((6*b**7 + 21*b**6 + 21*b**5 - 7*b**3 + b)/42).expand() def test_geometric_sums(): assert summation(pi**n, (n, 0, b)) == (1 - pi**(b + 1)) / (1 - pi) assert summation(2 * 3**n, (n, 0, b)) == 3**(b + 1) - 1 assert summation(S.Half**n, (n, 1, oo)) == 1 assert summation(2**n, (n, 0, b)) == 2**(b + 1) - 1 assert summation(2**n, (n, 1, oo)) is oo assert summation(2**(-n), (n, 1, oo)) == 1 assert summation(3**(-n), (n, 4, oo)) == Rational(1, 54) assert summation(2**(-4*n + 3), (n, 1, oo)) == Rational(8, 15) assert summation(2**(n + 1), (n, 1, b)).expand() == 4*(2**b - 1) # issue 6664: assert summation(x**n, (n, 0, oo)) == \ Piecewise((1/(-x + 1), Abs(x) < 1), (Sum(x**n, (n, 0, oo)), True)) assert summation(-2**n, (n, 0, oo)) is -oo assert summation(I**n, (n, 0, oo)) == Sum(I**n, (n, 0, oo)) # issue 6802: assert summation((-1)**(2*x + 2), (x, 0, n)) == n + 1 assert summation((-2)**(2*x + 2), (x, 0, n)) == 4*4**(n + 1)/S(3) - Rational(4, 3) assert summation((-1)**x, (x, 0, n)) == -(-1)**(n + 1)/S(2) + S.Half assert summation(y**x, (x, a, b)) == \ Piecewise((-a + b + 1, Eq(y, 1)), ((y**a - y**(b + 1))/(-y + 1), True)) assert summation((-2)**(y*x + 2), (x, 0, n)) == \ 4*Piecewise((n + 1, Eq((-2)**y, 1)), ((-(-2)**(y*(n + 1)) + 1)/(-(-2)**y + 1), True)) # issue 8251: assert summation((1/(n + 1)**2)*n**2, (n, 0, oo)) is oo #issue 9908: assert Sum(1/(n**3 - 1), (n, -oo, -2)).doit() == summation(1/(n**3 - 1), (n, -oo, -2)) #issue 11642: result = Sum(0.5**n, (n, 1, oo)).doit() assert result == 1 assert result.is_Float result = Sum(0.25**n, (n, 1, oo)).doit() assert result == 1/3. assert result.is_Float result = Sum(0.99999**n, (n, 1, oo)).doit() assert result == 99999 assert result.is_Float result = Sum(S.Half**n, (n, 1, oo)).doit() assert result == 1 assert not result.is_Float result = Sum(Rational(3, 5)**n, (n, 1, oo)).doit() assert result == Rational(3, 2) assert not result.is_Float assert Sum(1.0**n, (n, 1, oo)).doit() is oo assert Sum(2.43**n, (n, 1, oo)).doit() is oo # Issue 13979 i, k, q = symbols('i k q', integer=True) result = summation( exp(-2*I*pi*k*i/n) * exp(2*I*pi*q*i/n) / n, (i, 0, n - 1) ) assert result.simplify() == Piecewise( (1, Eq(exp(-2*I*pi*(k - q)/n), 1)), (0, True) ) def test_harmonic_sums(): assert summation(1/k, (k, 0, n)) == Sum(1/k, (k, 0, n)) assert summation(1/k, (k, 1, n)) == harmonic(n) assert summation(n/k, (k, 1, n)) == n*harmonic(n) assert summation(1/k, (k, 5, n)) == harmonic(n) - harmonic(4) def test_composite_sums(): f = S.Half*(7 - 6*n + Rational(1, 7)*n**3) s = summation(f, (n, a, b)) assert not isinstance(s, Sum) A = 0 for i in range(-3, 5): A += f.subs(n, i) B = s.subs(a, -3).subs(b, 4) assert A == B def test_hypergeometric_sums(): assert summation( binomial(2*k, k)/4**k, (k, 0, n)) == (1 + 2*n)*binomial(2*n, n)/4**n assert summation(binomial(2*k, k)/5**k, (k, -oo, oo)) == sqrt(5) def test_other_sums(): f = m**2 + m*exp(m) g = 3*exp(Rational(3, 2))/2 + exp(S.Half)/2 - exp(Rational(-1, 2))/2 - 3*exp(Rational(-3, 2))/2 + 5 assert summation(f, (m, Rational(-3, 2), Rational(3, 2))) == g assert summation(f, (m, -1.5, 1.5)).evalf().epsilon_eq(g.evalf(), 1e-10) fac = factorial def NS(e, n=15, **options): return str(sympify(e).evalf(n, **options)) def test_evalf_fast_series(): # Euler transformed series for sqrt(1+x) assert NS(Sum( fac(2*n + 1)/fac(n)**2/2**(3*n + 1), (n, 0, oo)), 100) == NS(sqrt(2), 100) # Some series for exp(1) estr = NS(E, 100) assert NS(Sum(1/fac(n), (n, 0, oo)), 100) == estr assert NS(1/Sum((1 - 2*n)/fac(2*n), (n, 0, oo)), 100) == estr assert NS(Sum((2*n + 1)/fac(2*n), (n, 0, oo)), 100) == estr assert NS(Sum((4*n + 3)/2**(2*n + 1)/fac(2*n + 1), (n, 0, oo))**2, 100) == estr pistr = NS(pi, 100) # Ramanujan series for pi assert NS(9801/sqrt(8)/Sum(fac( 4*n)*(1103 + 26390*n)/fac(n)**4/396**(4*n), (n, 0, oo)), 100) == pistr assert NS(1/Sum( binomial(2*n, n)**3 * (42*n + 5)/2**(12*n + 4), (n, 0, oo)), 100) == pistr # Machin's formula for pi assert NS(16*Sum((-1)**n/(2*n + 1)/5**(2*n + 1), (n, 0, oo)) - 4*Sum((-1)**n/(2*n + 1)/239**(2*n + 1), (n, 0, oo)), 100) == pistr # Apery's constant astr = NS(zeta(3), 100) P = 126392*n**5 + 412708*n**4 + 531578*n**3 + 336367*n**2 + 104000* \ n + 12463 assert NS(Sum((-1)**n * P / 24 * (fac(2*n + 1)*fac(2*n)*fac( n))**3 / fac(3*n + 2) / fac(4*n + 3)**3, (n, 0, oo)), 100) == astr assert NS(Sum((-1)**n * (205*n**2 + 250*n + 77)/64 * fac(n)**10 / fac(2*n + 1)**5, (n, 0, oo)), 100) == astr def test_evalf_fast_series_issue_4021(): # Catalan's constant assert NS(Sum((-1)**(n - 1)*2**(8*n)*(40*n**2 - 24*n + 3)*fac(2*n)**3* fac(n)**2/n**3/(2*n - 1)/fac(4*n)**2, (n, 1, oo))/64, 100) == \ NS(Catalan, 100) astr = NS(zeta(3), 100) assert NS(5*Sum( (-1)**(n - 1)*fac(n)**2 / n**3 / fac(2*n), (n, 1, oo))/2, 100) == astr assert NS(Sum((-1)**(n - 1)*(56*n**2 - 32*n + 5) / (2*n - 1)**2 * fac(n - 1) **3 / fac(3*n), (n, 1, oo))/4, 100) == astr def test_evalf_slow_series(): assert NS(Sum((-1)**n / n, (n, 1, oo)), 15) == NS(-log(2), 15) assert NS(Sum((-1)**n / n, (n, 1, oo)), 50) == NS(-log(2), 50) assert NS(Sum(1/n**2, (n, 1, oo)), 15) == NS(pi**2/6, 15) assert NS(Sum(1/n**2, (n, 1, oo)), 100) == NS(pi**2/6, 100) assert NS(Sum(1/n**2, (n, 1, oo)), 500) == NS(pi**2/6, 500) assert NS(Sum((-1)**n / (2*n + 1)**3, (n, 0, oo)), 15) == NS(pi**3/32, 15) assert NS(Sum((-1)**n / (2*n + 1)**3, (n, 0, oo)), 50) == NS(pi**3/32, 50) def test_euler_maclaurin(): # Exact polynomial sums with E-M def check_exact(f, a, b, m, n): A = Sum(f, (k, a, b)) s, e = A.euler_maclaurin(m, n) assert (e == 0) and (s.expand() == A.doit()) check_exact(k**4, a, b, 0, 2) check_exact(k**4 + 2*k, a, b, 1, 2) check_exact(k**4 + k**2, a, b, 1, 5) check_exact(k**5, 2, 6, 1, 2) check_exact(k**5, 2, 6, 1, 3) assert Sum(x-1, (x, 0, 2)).euler_maclaurin(m=30, n=30, eps=2**-15) == (0, 0) # Not exact assert Sum(k**6, (k, a, b)).euler_maclaurin(0, 2)[1] != 0 # Numerical test for mi, ni in [(2, 4), (2, 20), (10, 20), (18, 20)]: A = Sum(1/k**3, (k, 1, oo)) s, e = A.euler_maclaurin(mi, ni) assert abs((s - zeta(3)).evalf()) < e.evalf() raises(ValueError, lambda: Sum(1, (x, 0, 1), (k, 0, 1)).euler_maclaurin()) @slow def test_evalf_euler_maclaurin(): assert NS(Sum(1/k**k, (k, 1, oo)), 15) == '1.29128599706266' assert NS(Sum(1/k**k, (k, 1, oo)), 50) == '1.2912859970626635404072825905956005414986193682745' assert NS(Sum(1/k - log(1 + 1/k), (k, 1, oo)), 15) == NS(EulerGamma, 15) assert NS(Sum(1/k - log(1 + 1/k), (k, 1, oo)), 50) == NS(EulerGamma, 50) assert NS(Sum(log(k)/k**2, (k, 1, oo)), 15) == '0.937548254315844' assert NS(Sum(log(k)/k**2, (k, 1, oo)), 50) == '0.93754825431584375370257409456786497789786028861483' assert NS(Sum(1/k, (k, 1000000, 2000000)), 15) == '0.693147930560008' assert NS(Sum(1/k, (k, 1000000, 2000000)), 50) == '0.69314793056000780941723211364567656807940638436025' def test_evalf_symbolic(): f, g = symbols('f g', cls=Function) # issue 6328 expr = Sum(f(x), (x, 1, 3)) + Sum(g(x), (x, 1, 3)) assert expr.evalf() == expr def test_evalf_issue_3273(): assert Sum(0, (k, 1, oo)).evalf() == 0 def test_simple_products(): assert Product(S.NaN, (x, 1, 3)) is S.NaN assert product(S.NaN, (x, 1, 3)) is S.NaN assert Product(x, (n, a, a)).doit() == x assert Product(x, (x, a, a)).doit() == a assert Product(x, (y, 1, a)).doit() == x**a lo, hi = 1, 2 s1 = Product(n, (n, lo, hi)) s2 = Product(n, (n, hi, lo)) assert s1 != s2 # This IS correct according to Karr product convention assert s1.doit() == 2 assert s2.doit() == 1 lo, hi = x, x + 1 s1 = Product(n, (n, lo, hi)) s2 = Product(n, (n, hi, lo)) s3 = 1 / Product(n, (n, hi + 1, lo - 1)) assert s1 != s2 # This IS correct according to Karr product convention assert s1.doit() == x*(x + 1) assert s2.doit() == 1 assert s3.doit() == x*(x + 1) assert Product(Integral(2*x, (x, 1, y)) + 2*x, (x, 1, 2)).doit() == \ (y**2 + 1)*(y**2 + 3) assert product(2, (n, a, b)) == 2**(b - a + 1) assert product(n, (n, 1, b)) == factorial(b) assert product(n**3, (n, 1, b)) == factorial(b)**3 assert product(3**(2 + n), (n, a, b)) \ == 3**(2*(1 - a + b) + b/2 + (b**2)/2 + a/2 - (a**2)/2) assert product(cos(n), (n, 3, 5)) == cos(3)*cos(4)*cos(5) assert product(cos(n), (n, x, x + 2)) == cos(x)*cos(x + 1)*cos(x + 2) assert isinstance(product(cos(n), (n, x, x + S.Half)), Product) # If Product managed to evaluate this one, it most likely got it wrong! assert isinstance(Product(n**n, (n, 1, b)), Product) def test_rational_products(): assert combsimp(product(1 + 1/n, (n, a, b))) == (1 + b)/a assert combsimp(product(n + 1, (n, a, b))) == gamma(2 + b)/gamma(1 + a) assert combsimp(product((n + 1)/(n - 1), (n, a, b))) == b*(1 + b)/(a*(a - 1)) assert combsimp(product(n/(n + 1)/(n + 2), (n, a, b))) == \ a*gamma(a + 2)/(b + 1)/gamma(b + 3) assert combsimp(product(n*(n + 1)/(n - 1)/(n - 2), (n, a, b))) == \ b**2*(b - 1)*(1 + b)/(a - 1)**2/(a*(a - 2)) def test_wallis_product(): # Wallis product, given in two different forms to ensure that Product # can factor simple rational expressions A = Product(4*n**2 / (4*n**2 - 1), (n, 1, b)) B = Product((2*n)*(2*n)/(2*n - 1)/(2*n + 1), (n, 1, b)) R = pi*gamma(b + 1)**2/(2*gamma(b + S.Half)*gamma(b + Rational(3, 2))) assert simplify(A.doit()) == R assert simplify(B.doit()) == R # This one should eventually also be doable (Euler's product formula for sin) # assert Product(1+x/n**2, (n, 1, b)) == ... def test_telescopic_sums(): #checks also input 2 of comment 1 issue 4127 assert Sum(1/k - 1/(k + 1), (k, 1, n)).doit() == 1 - 1/(1 + n) f = Function("f") assert Sum( f(k) - f(k + 2), (k, m, n)).doit() == -f(1 + n) - f(2 + n) + f(m) + f(1 + m) assert Sum(cos(k) - cos(k + 3), (k, 1, n)).doit() == -cos(1 + n) - \ cos(2 + n) - cos(3 + n) + cos(1) + cos(2) + cos(3) # dummy variable shouldn't matter assert telescopic(1/m, -m/(1 + m), (m, n - 1, n)) == \ telescopic(1/k, -k/(1 + k), (k, n - 1, n)) assert Sum(1/x/(x - 1), (x, a, b)).doit() == -((a - b - 1)/(b*(a - 1))) def test_sum_reconstruct(): s = Sum(n**2, (n, -1, 1)) assert s == Sum(*s.args) raises(ValueError, lambda: Sum(x, x)) raises(ValueError, lambda: Sum(x, (x, 1))) def test_limit_subs(): for F in (Sum, Product, Integral): assert F(a*exp(a), (a, -2, 2)) == F(a*exp(a), (a, -b, b)).subs(b, 2) assert F(a, (a, F(b, (b, 1, 2)), 4)).subs(F(b, (b, 1, 2)), c) == \ F(a, (a, c, 4)) assert F(x, (x, 1, x + y)).subs(x, 1) == F(x, (x, 1, y + 1)) def test_function_subs(): f = Function("f") S = Sum(x*f(y),(x,0,oo),(y,0,oo)) assert S.subs(f(y),y) == Sum(x*y,(x,0,oo),(y,0,oo)) assert S.subs(f(x),x) == S raises(ValueError, lambda: S.subs(f(y),x+y) ) S = Sum(x*log(y),(x,0,oo),(y,0,oo)) assert S.subs(log(y),y) == S S = Sum(x*f(y),(x,0,oo),(y,0,oo)) assert S.subs(f(y),y) == Sum(x*y,(x,0,oo),(y,0,oo)) def test_equality(): # if this fails remove special handling below raises(ValueError, lambda: Sum(x, x)) r = symbols('x', real=True) for F in (Sum, Product, Integral): try: assert F(x, x) != F(y, y) assert F(x, (x, 1, 2)) != F(x, x) assert F(x, (x, x)) != F(x, x) # or else they print the same assert F(1, x) != F(1, y) except ValueError: pass assert F(a, (x, 1, 2)) != F(a, (x, 1, 3)) # diff limit assert F(a, (x, 1, x)) != F(a, (y, 1, y)) assert F(a, (x, 1, 2)) != F(b, (x, 1, 2)) # diff expression assert F(x, (x, 1, 2)) != F(r, (r, 1, 2)) # diff assumptions assert F(1, (x, 1, x)) != F(1, (y, 1, x)) # only dummy is diff assert F(1, (x, 1, x)).dummy_eq(F(1, (y, 1, x))) # issue 5265 assert Sum(x, (x, 1, x)).subs(x, a) == Sum(x, (x, 1, a)) def test_Sum_doit(): f = Function('f') assert Sum(n*Integral(a**2), (n, 0, 2)).doit() == a**3 assert Sum(n*Integral(a**2), (n, 0, 2)).doit(deep=False) == \ 3*Integral(a**2) assert summation(n*Integral(a**2), (n, 0, 2)) == 3*Integral(a**2) # test nested sum evaluation s = Sum( Sum( Sum(2,(z,1,n+1)), (y,x+1,n)), (x,1,n)) assert 0 == (s.doit() - n*(n+1)*(n-1)).factor() # Integer assumes finite assert Sum(KroneckerDelta(x, y), (x, -oo, oo)).doit() == Piecewise((1, And(-oo <= y, y < oo)), (0, True)) assert Sum(KroneckerDelta(m, n), (m, -oo, oo)).doit() == 1 assert Sum(m*KroneckerDelta(x, y), (x, -oo, oo)).doit() == Piecewise((m, And(-oo <= y, y < oo)), (0, True)) assert Sum(x*KroneckerDelta(m, n), (m, -oo, oo)).doit() == x assert Sum(Sum(KroneckerDelta(m, n), (m, 1, 3)), (n, 1, 3)).doit() == 3 assert Sum(Sum(KroneckerDelta(k, m), (m, 1, 3)), (n, 1, 3)).doit() == \ 3 * Piecewise((1, And(1 <= k, k <= 3)), (0, True)) assert Sum(f(n) * Sum(KroneckerDelta(m, n), (m, 0, oo)), (n, 1, 3)).doit() == \ f(1) + f(2) + f(3) assert Sum(f(n) * Sum(KroneckerDelta(m, n), (m, 0, oo)), (n, 1, oo)).doit() == \ Sum(f(n), (n, 1, oo)) # issue 2597 nmax = symbols('N', integer=True, positive=True) pw = Piecewise((1, And(1 <= n, n <= nmax)), (0, True)) assert Sum(pw, (n, 1, nmax)).doit() == Sum(Piecewise((1, nmax >= n), (0, True)), (n, 1, nmax)) q, s = symbols('q, s') assert summation(1/n**(2*s), (n, 1, oo)) == Piecewise((zeta(2*s), 2*s > 1), (Sum(n**(-2*s), (n, 1, oo)), True)) assert summation(1/(n+1)**s, (n, 0, oo)) == Piecewise((zeta(s), s > 1), (Sum((n + 1)**(-s), (n, 0, oo)), True)) assert summation(1/(n+q)**s, (n, 0, oo)) == Piecewise( (zeta(s, q), And(q > 0, s > 1)), (Sum((n + q)**(-s), (n, 0, oo)), True)) assert summation(1/(n+q)**s, (n, q, oo)) == Piecewise( (zeta(s, 2*q), And(2*q > 0, s > 1)), (Sum((n + q)**(-s), (n, q, oo)), True)) assert summation(1/n**2, (n, 1, oo)) == zeta(2) assert summation(1/n**s, (n, 0, oo)) == Sum(n**(-s), (n, 0, oo)) def test_Product_doit(): assert Product(n*Integral(a**2), (n, 1, 3)).doit() == 2 * a**9 / 9 assert Product(n*Integral(a**2), (n, 1, 3)).doit(deep=False) == \ 6*Integral(a**2)**3 assert product(n*Integral(a**2), (n, 1, 3)) == 6*Integral(a**2)**3 def test_Sum_interface(): assert isinstance(Sum(0, (n, 0, 2)), Sum) assert Sum(nan, (n, 0, 2)) is nan assert Sum(nan, (n, 0, oo)) is nan assert Sum(0, (n, 0, 2)).doit() == 0 assert isinstance(Sum(0, (n, 0, oo)), Sum) assert Sum(0, (n, 0, oo)).doit() == 0 raises(ValueError, lambda: Sum(1)) raises(ValueError, lambda: summation(1)) def test_diff(): assert Sum(x, (x, 1, 2)).diff(x) == 0 assert Sum(x*y, (x, 1, 2)).diff(x) == 0 assert Sum(x*y, (y, 1, 2)).diff(x) == Sum(y, (y, 1, 2)) e = Sum(x*y, (x, 1, a)) assert e.diff(a) == Derivative(e, a) assert Sum(x*y, (x, 1, 3), (a, 2, 5)).diff(y).doit() == \ Sum(x*y, (x, 1, 3), (a, 2, 5)).doit().diff(y) == 24 assert Sum(x, (x, 1, 2)).diff(y) == 0 def test_hypersum(): from sympy import sin assert simplify(summation(x**n/fac(n), (n, 1, oo))) == -1 + exp(x) assert summation((-1)**n * x**(2*n) / fac(2*n), (n, 0, oo)) == cos(x) assert simplify(summation((-1)**n*x**(2*n + 1) / factorial(2*n + 1), (n, 3, oo))) == -x + sin(x) + x**3/6 - x**5/120 assert summation(1/(n + 2)**3, (n, 1, oo)) == Rational(-9, 8) + zeta(3) assert summation(1/n**4, (n, 1, oo)) == pi**4/90 s = summation(x**n*n, (n, -oo, 0)) assert s.is_Piecewise assert s.args[0].args[0] == -1/(x*(1 - 1/x)**2) assert s.args[0].args[1] == (abs(1/x) < 1) m = Symbol('n', integer=True, positive=True) assert summation(binomial(m, k), (k, 0, m)) == 2**m def test_issue_4170(): assert summation(1/factorial(k), (k, 0, oo)) == E def test_is_commutative(): from sympy.physics.secondquant import NO, F, Fd m = Symbol('m', commutative=False) for f in (Sum, Product, Integral): assert f(z, (z, 1, 1)).is_commutative is True assert f(z*y, (z, 1, 6)).is_commutative is True assert f(m*x, (x, 1, 2)).is_commutative is False assert f(NO(Fd(x)*F(y))*z, (z, 1, 2)).is_commutative is False def test_is_zero(): for func in [Sum, Product]: assert func(0, (x, 1, 1)).is_zero is True assert func(x, (x, 1, 1)).is_zero is None assert Sum(0, (x, 1, 0)).is_zero is True assert Product(0, (x, 1, 0)).is_zero is False def test_is_number(): # is number should not rely on evaluation or assumptions, # it should be equivalent to `not foo.free_symbols` assert Sum(1, (x, 1, 1)).is_number is True assert Sum(1, (x, 1, x)).is_number is False assert Sum(0, (x, y, z)).is_number is False assert Sum(x, (y, 1, 2)).is_number is False assert Sum(x, (y, 1, 1)).is_number is False assert Sum(x, (x, 1, 2)).is_number is True assert Sum(x*y, (x, 1, 2), (y, 1, 3)).is_number is True assert Product(2, (x, 1, 1)).is_number is True assert Product(2, (x, 1, y)).is_number is False assert Product(0, (x, y, z)).is_number is False assert Product(1, (x, y, z)).is_number is False assert Product(x, (y, 1, x)).is_number is False assert Product(x, (y, 1, 2)).is_number is False assert Product(x, (y, 1, 1)).is_number is False assert Product(x, (x, 1, 2)).is_number is True def test_free_symbols(): for func in [Sum, Product]: assert func(1, (x, 1, 2)).free_symbols == set() assert func(0, (x, 1, y)).free_symbols == {y} assert func(2, (x, 1, y)).free_symbols == {y} assert func(x, (x, 1, 2)).free_symbols == set() assert func(x, (x, 1, y)).free_symbols == {y} assert func(x, (y, 1, y)).free_symbols == {x, y} assert func(x, (y, 1, 2)).free_symbols == {x} assert func(x, (y, 1, 1)).free_symbols == {x} assert func(x, (y, 1, z)).free_symbols == {x, z} assert func(x, (x, 1, y), (y, 1, 2)).free_symbols == set() assert func(x, (x, 1, y), (y, 1, z)).free_symbols == {z} assert func(x, (x, 1, y), (y, 1, y)).free_symbols == {y} assert func(x, (y, 1, y), (y, 1, z)).free_symbols == {x, z} assert Sum(1, (x, 1, y)).free_symbols == {y} # free_symbols answers whether the object *as written* has free symbols, # not whether the evaluated expression has free symbols assert Product(1, (x, 1, y)).free_symbols == {y} def test_conjugate_transpose(): A, B = symbols("A B", commutative=False) p = Sum(A*B**n, (n, 1, 3)) assert p.adjoint().doit() == p.doit().adjoint() assert p.conjugate().doit() == p.doit().conjugate() assert p.transpose().doit() == p.doit().transpose() p = Sum(B**n*A, (n, 1, 3)) assert p.adjoint().doit() == p.doit().adjoint() assert p.conjugate().doit() == p.doit().conjugate() assert p.transpose().doit() == p.doit().transpose() def test_noncommutativity_honoured(): A, B = symbols("A B", commutative=False) M = symbols('M', integer=True, positive=True) p = Sum(A*B**n, (n, 1, M)) assert p.doit() == A*Piecewise((M, Eq(B, 1)), ((B - B**(M + 1))*(1 - B)**(-1), True)) p = Sum(B**n*A, (n, 1, M)) assert p.doit() == Piecewise((M, Eq(B, 1)), ((B - B**(M + 1))*(1 - B)**(-1), True))*A p = Sum(B**n*A*B**n, (n, 1, M)) assert p.doit() == p def test_issue_4171(): assert summation(factorial(2*k + 1)/factorial(2*k), (k, 0, oo)) is oo assert summation(2*k + 1, (k, 0, oo)) is oo def test_issue_6273(): assert Sum(x, (x, 1, n)).n(2, subs={n: 1}) == 1 def test_issue_6274(): assert Sum(x, (x, 1, 0)).doit() == 0 assert NS(Sum(x, (x, 1, 0))) == '0' assert Sum(n, (n, 10, 5)).doit() == -30 assert NS(Sum(n, (n, 10, 5))) == '-30.0000000000000' def test_simplify_sum(): y, t, v = symbols('y, t, v') _simplify = lambda e: simplify(e, doit=False) assert _simplify(Sum(x*y, (x, n, m), (y, a, k)) + \ Sum(y, (x, n, m), (y, a, k))) == Sum(y * (x + 1), (x, n, m), (y, a, k)) assert _simplify(Sum(x, (x, n, m)) + Sum(x, (x, m + 1, a))) == \ Sum(x, (x, n, a)) assert _simplify(Sum(x, (x, k + 1, a)) + Sum(x, (x, n, k))) == \ Sum(x, (x, n, a)) assert _simplify(Sum(x, (x, k + 1, a)) + Sum(x + 1, (x, n, k))) == \ Sum(x, (x, n, a)) + Sum(1, (x, n, k)) assert _simplify(Sum(x, (x, 0, 3)) * 3 + 3 * Sum(x, (x, 4, 6)) + \ 4 * Sum(z, (z, 0, 1))) == 4*Sum(z, (z, 0, 1)) + 3*Sum(x, (x, 0, 6)) assert _simplify(3*Sum(x**2, (x, a, b)) + Sum(x, (x, a, b))) == \ Sum(x*(3*x + 1), (x, a, b)) assert _simplify(Sum(x**3, (x, n, k)) * 3 + 3 * Sum(x, (x, n, k)) + \ 4 * y * Sum(z, (z, n, k))) + 1 == \ 4*y*Sum(z, (z, n, k)) + 3*Sum(x**3 + x, (x, n, k)) + 1 assert _simplify(Sum(x, (x, a, b)) + 1 + Sum(x, (x, b + 1, c))) == \ 1 + Sum(x, (x, a, c)) assert _simplify(Sum(x, (t, a, b)) + Sum(y, (t, a, b)) + \ Sum(x, (t, b+1, c))) == x * Sum(1, (t, a, c)) + y * Sum(1, (t, a, b)) assert _simplify(Sum(x, (t, a, b)) + Sum(x, (t, b+1, c)) + \ Sum(y, (t, a, b))) == x * Sum(1, (t, a, c)) + y * Sum(1, (t, a, b)) assert _simplify(Sum(x, (t, a, b)) + 2 * Sum(x, (t, b+1, c))) == \ _simplify(Sum(x, (t, a, b)) + Sum(x, (t, b+1, c)) + Sum(x, (t, b+1, c))) assert _simplify(Sum(x, (x, a, b))*Sum(x**2, (x, a, b))) == \ Sum(x, (x, a, b)) * Sum(x**2, (x, a, b)) assert _simplify(Sum(x, (t, a, b)) + Sum(y, (t, a, b)) + Sum(z, (t, a, b))) \ == (x + y + z) * Sum(1, (t, a, b)) # issue 8596 assert _simplify(Sum(x, (t, a, b)) + Sum(y, (t, a, b)) + Sum(z, (t, a, b)) + \ Sum(v, (t, a, b))) == (x + y + z + v) * Sum(1, (t, a, b)) # issue 8596 assert _simplify(Sum(x * y, (x, a, b)) / (3 * y)) == \ (Sum(x, (x, a, b)) / 3) assert _simplify(Sum(Function('f')(x) * y * z, (x, a, b)) / (y * z)) \ == Sum(Function('f')(x), (x, a, b)) assert _simplify(Sum(c * x, (x, a, b)) - c * Sum(x, (x, a, b))) == 0 assert _simplify(c * (Sum(x, (x, a, b)) + y)) == c * (y + Sum(x, (x, a, b))) assert _simplify(c * (Sum(x, (x, a, b)) + y * Sum(x, (x, a, b)))) == \ c * (y + 1) * Sum(x, (x, a, b)) assert _simplify(Sum(Sum(c * x, (x, a, b)), (y, a, b))) == \ c * Sum(x, (x, a, b), (y, a, b)) assert _simplify(Sum((3 + y) * Sum(c * x, (x, a, b)), (y, a, b))) == \ c * Sum((3 + y), (y, a, b)) * Sum(x, (x, a, b)) assert _simplify(Sum((3 + t) * Sum(c * t, (x, a, b)), (y, a, b))) == \ c*t*(t + 3)*Sum(1, (x, a, b))*Sum(1, (y, a, b)) assert _simplify(Sum(Sum(d * t, (x, a, b - 1)) + \ Sum(d * t, (x, b, c)), (t, a, b))) == \ d * Sum(1, (x, a, c)) * Sum(t, (t, a, b)) def test_change_index(): b, v, w = symbols('b, v, w', integer = True) assert Sum(x, (x, a, b)).change_index(x, x + 1, y) == \ Sum(y - 1, (y, a + 1, b + 1)) assert Sum(x**2, (x, a, b)).change_index( x, x - 1) == \ Sum((x+1)**2, (x, a - 1, b - 1)) assert Sum(x**2, (x, a, b)).change_index( x, -x, y) == \ Sum((-y)**2, (y, -b, -a)) assert Sum(x, (x, a, b)).change_index( x, -x - 1) == \ Sum(-x - 1, (x, -b - 1, -a - 1)) assert Sum(x*y, (x, a, b), (y, c, d)).change_index( x, x - 1, z) == \ Sum((z + 1)*y, (z, a - 1, b - 1), (y, c, d)) assert Sum(x, (x, a, b)).change_index( x, x + v) == \ Sum(-v + x, (x, a + v, b + v)) assert Sum(x, (x, a, b)).change_index( x, -x - v) == \ Sum(-v - x, (x, -b - v, -a - v)) assert Sum(x, (x, a, b)).change_index(x, w*x, v) == \ Sum(v/w, (v, b*w, a*w)) raises(ValueError, lambda: Sum(x, (x, a, b)).change_index(x, 2*x)) def test_reorder(): b, y, c, d, z = symbols('b, y, c, d, z', integer = True) assert Sum(x*y, (x, a, b), (y, c, d)).reorder((0, 1)) == \ Sum(x*y, (y, c, d), (x, a, b)) assert Sum(x, (x, a, b), (x, c, d)).reorder((0, 1)) == \ Sum(x, (x, c, d), (x, a, b)) assert Sum(x*y + z, (x, a, b), (z, m, n), (y, c, d)).reorder(\ (2, 0), (0, 1)) == Sum(x*y + z, (z, m, n), (y, c, d), (x, a, b)) assert Sum(x*y*z, (x, a, b), (y, c, d), (z, m, n)).reorder(\ (0, 1), (1, 2), (0, 2)) == Sum(x*y*z, (x, a, b), (z, m, n), (y, c, d)) assert Sum(x*y*z, (x, a, b), (y, c, d), (z, m, n)).reorder(\ (x, y), (y, z), (x, z)) == Sum(x*y*z, (x, a, b), (z, m, n), (y, c, d)) assert Sum(x*y, (x, a, b), (y, c, d)).reorder((x, 1)) == \ Sum(x*y, (y, c, d), (x, a, b)) assert Sum(x*y, (x, a, b), (y, c, d)).reorder((y, x)) == \ Sum(x*y, (y, c, d), (x, a, b)) def test_reverse_order(): assert Sum(x, (x, 0, 3)).reverse_order(0) == Sum(-x, (x, 4, -1)) assert Sum(x*y, (x, 1, 5), (y, 0, 6)).reverse_order(0, 1) == \ Sum(x*y, (x, 6, 0), (y, 7, -1)) assert Sum(x, (x, 1, 2)).reverse_order(0) == Sum(-x, (x, 3, 0)) assert Sum(x, (x, 1, 3)).reverse_order(0) == Sum(-x, (x, 4, 0)) assert Sum(x, (x, 1, a)).reverse_order(0) == Sum(-x, (x, a + 1, 0)) assert Sum(x, (x, a, 5)).reverse_order(0) == Sum(-x, (x, 6, a - 1)) assert Sum(x, (x, a + 1, a + 5)).reverse_order(0) == \ Sum(-x, (x, a + 6, a)) assert Sum(x, (x, a + 1, a + 2)).reverse_order(0) == \ Sum(-x, (x, a + 3, a)) assert Sum(x, (x, a + 1, a + 1)).reverse_order(0) == \ Sum(-x, (x, a + 2, a)) assert Sum(x, (x, a, b)).reverse_order(0) == Sum(-x, (x, b + 1, a - 1)) assert Sum(x, (x, a, b)).reverse_order(x) == Sum(-x, (x, b + 1, a - 1)) assert Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(x, 1) == \ Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) assert Sum(x*y, (x, a, b), (y, 2, 5)).reverse_order(y, x) == \ Sum(x*y, (x, b + 1, a - 1), (y, 6, 1)) def test_issue_7097(): assert sum(x**n/n for n in range(1, 401)) == summation(x**n/n, (n, 1, 400)) def test_factor_expand_subs(): # test factoring assert Sum(4 * x, (x, 1, y)).factor() == 4 * Sum(x, (x, 1, y)) assert Sum(x * a, (x, 1, y)).factor() == a * Sum(x, (x, 1, y)) assert Sum(4 * x * a, (x, 1, y)).factor() == 4 * a * Sum(x, (x, 1, y)) assert Sum(4 * x * y, (x, 1, y)).factor() == 4 * y * Sum(x, (x, 1, y)) # test expand assert Sum(x+1,(x,1,y)).expand() == Sum(x,(x,1,y)) + Sum(1,(x,1,y)) assert Sum(x+a*x**2,(x,1,y)).expand() == Sum(x,(x,1,y)) + Sum(a*x**2,(x,1,y)) assert Sum(x**(n + 1)*(n + 1), (n, -1, oo)).expand() \ == Sum(x*x**n, (n, -1, oo)) + Sum(n*x*x**n, (n, -1, oo)) assert Sum(x**(n + 1)*(n + 1), (n, -1, oo)).expand(power_exp=False) \ == Sum(n*x**(n+1), (n, -1, oo)) + Sum(x**(n+1), (n, -1, oo)) assert Sum(a*n+a*n**2,(n,0,4)).expand() \ == Sum(a*n,(n,0,4)) + Sum(a*n**2,(n,0,4)) assert Sum(x**a*x**n,(x,0,3)) \ == Sum(x**(a+n),(x,0,3)).expand(power_exp=True) assert Sum(x**(a+n),(x,0,3)) \ == Sum(x**(a+n),(x,0,3)).expand(power_exp=False) # test subs assert Sum(1/(1+a*x**2),(x,0,3)).subs([(a,3)]) == Sum(1/(1+3*x**2),(x,0,3)) assert Sum(x*y,(x,0,y),(y,0,x)).subs([(x,3)]) == Sum(x*y,(x,0,y),(y,0,3)) assert Sum(x,(x,1,10)).subs([(x,y-2)]) == Sum(x,(x,1,10)) assert Sum(1/x,(x,1,10)).subs([(x,(3+n)**3)]) == Sum(1/x,(x,1,10)) assert Sum(1/x,(x,1,10)).subs([(x,3*x-2)]) == Sum(1/x,(x,1,10)) def test_distribution_over_equality(): f = Function('f') assert Product(Eq(x*2, f(x)), (x, 1, 3)).doit() == Eq(48, f(1)*f(2)*f(3)) assert Sum(Eq(f(x), x**2), (x, 0, y)) == \ Eq(Sum(f(x), (x, 0, y)), Sum(x**2, (x, 0, y))) def test_issue_2787(): n, k = symbols('n k', positive=True, integer=True) p = symbols('p', positive=True) binomial_dist = binomial(n, k)*p**k*(1 - p)**(n - k) s = Sum(binomial_dist*k, (k, 0, n)) res = s.doit().simplify() assert res == Piecewise( (n*p, p/Abs(p - 1) <= 1), ((-p + 1)**n*Sum(k*p**k*(-p + 1)**(-k)*binomial(n, k), (k, 0, n)), True)) # Issue #17165: make sure that another simplify does not change/increase # the result assert res == res.simplify() def test_issue_4668(): assert summation(1/n, (n, 2, oo)) is oo def test_matrix_sum(): A = Matrix([[0, 1], [n, 0]]) result = Sum(A, (n, 0, 3)).doit() assert result == Matrix([[0, 4], [6, 0]]) assert result.__class__ == ImmutableDenseMatrix A = SparseMatrix([[0, 1], [n, 0]]) result = Sum(A, (n, 0, 3)).doit() assert result.__class__ == ImmutableSparseMatrix def test_failing_matrix_sum(): n = Symbol('n') # TODO Implement matrix geometric series summation. A = Matrix([[0, 1, 0], [-1, 0, 0], [0, 0, 0]]) assert Sum(A ** n, (n, 1, 4)).doit() == \ Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) # issue sympy/sympy#16989 assert summation(A**n, (n, 1, 1)) == A def test_indexed_idx_sum(): i = symbols('i', cls=Idx) r = Indexed('r', i) assert Sum(r, (i, 0, 3)).doit() == sum([r.xreplace({i: j}) for j in range(4)]) assert Product(r, (i, 0, 3)).doit() == prod([r.xreplace({i: j}) for j in range(4)]) j = symbols('j', integer=True) assert Sum(r, (i, j, j+2)).doit() == sum([r.xreplace({i: j+k}) for k in range(3)]) assert Product(r, (i, j, j+2)).doit() == prod([r.xreplace({i: j+k}) for k in range(3)]) k = Idx('k', range=(1, 3)) A = IndexedBase('A') assert Sum(A[k], k).doit() == sum([A[Idx(j, (1, 3))] for j in range(1, 4)]) assert Product(A[k], k).doit() == prod([A[Idx(j, (1, 3))] for j in range(1, 4)]) raises(ValueError, lambda: Sum(A[k], (k, 1, 4))) raises(ValueError, lambda: Sum(A[k], (k, 0, 3))) raises(ValueError, lambda: Sum(A[k], (k, 2, oo))) raises(ValueError, lambda: Product(A[k], (k, 1, 4))) raises(ValueError, lambda: Product(A[k], (k, 0, 3))) raises(ValueError, lambda: Product(A[k], (k, 2, oo))) @slow def test_is_convergent(): # divergence tests -- assert Sum(n/(2*n + 1), (n, 1, oo)).is_convergent() is S.false assert Sum(factorial(n)/5**n, (n, 1, oo)).is_convergent() is S.false assert Sum(3**(-2*n - 1)*n**n, (n, 1, oo)).is_convergent() is S.false assert Sum((-1)**n*n, (n, 3, oo)).is_convergent() is S.false assert Sum((-1)**n, (n, 1, oo)).is_convergent() is S.false assert Sum(log(1/n), (n, 2, oo)).is_convergent() is S.false # Raabe's test -- assert Sum(Product((3*m),(m,1,n))/Product((3*m+4),(m,1,n)),(n,1,oo)).is_convergent() is S.true # root test -- assert Sum((-12)**n/n, (n, 1, oo)).is_convergent() is S.false # integral test -- # p-series test -- assert Sum(1/(n**2 + 1), (n, 1, oo)).is_convergent() is S.true assert Sum(1/n**Rational(6, 5), (n, 1, oo)).is_convergent() is S.true assert Sum(2/(n*sqrt(n - 1)), (n, 2, oo)).is_convergent() is S.true assert Sum(1/(sqrt(n)*sqrt(n)), (n, 2, oo)).is_convergent() is S.false assert Sum(factorial(n) / factorial(n+2), (n, 1, oo)).is_convergent() is S.true assert Sum(rf(5,n)/rf(7,n),(n,1,oo)).is_convergent() is S.true assert Sum((rf(1, n)*rf(2, n))/(rf(3, n)*factorial(n)),(n,1,oo)).is_convergent() is S.false # comparison test -- assert Sum(1/(n + log(n)), (n, 1, oo)).is_convergent() is S.false assert Sum(1/(n**2*log(n)), (n, 2, oo)).is_convergent() is S.true assert Sum(1/(n*log(n)), (n, 2, oo)).is_convergent() is S.false assert Sum(2/(n*log(n)*log(log(n))**2), (n, 5, oo)).is_convergent() is S.true assert Sum(2/(n*log(n)**2), (n, 2, oo)).is_convergent() is S.true assert Sum((n - 1)/(n**2*log(n)**3), (n, 2, oo)).is_convergent() is S.true assert Sum(1/(n*log(n)*log(log(n))), (n, 5, oo)).is_convergent() is S.false assert Sum((n - 1)/(n*log(n)**3), (n, 3, oo)).is_convergent() is S.false assert Sum(2/(n**2*log(n)), (n, 2, oo)).is_convergent() is S.true assert Sum(1/(n*sqrt(log(n))*log(log(n))), (n, 100, oo)).is_convergent() is S.false assert Sum(log(log(n))/(n*log(n)**2), (n, 100, oo)).is_convergent() is S.true assert Sum(log(n)/n**2, (n, 5, oo)).is_convergent() is S.true # alternating series tests -- assert Sum((-1)**(n - 1)/(n**2 - 1), (n, 3, oo)).is_convergent() is S.true # with -negativeInfinite Limits assert Sum(1/(n**2 + 1), (n, -oo, 1)).is_convergent() is S.true assert Sum(1/(n - 1), (n, -oo, -1)).is_convergent() is S.false assert Sum(1/(n**2 - 1), (n, -oo, -5)).is_convergent() is S.true assert Sum(1/(n**2 - 1), (n, -oo, 2)).is_convergent() is S.true assert Sum(1/(n**2 - 1), (n, -oo, oo)).is_convergent() is S.true # piecewise functions f = Piecewise((n**(-2), n <= 1), (n**2, n > 1)) assert Sum(f, (n, 1, oo)).is_convergent() is S.false assert Sum(f, (n, -oo, oo)).is_convergent() is S.false assert Sum(f, (n, 1, 100)).is_convergent() is S.true #assert Sum(f, (n, -oo, 1)).is_convergent() is S.true # integral test assert Sum(log(n)/n**3, (n, 1, oo)).is_convergent() is S.true assert Sum(-log(n)/n**3, (n, 1, oo)).is_convergent() is S.true # the following function has maxima located at (x, y) = # (1.2, 0.43), (3.0, -0.25) and (6.8, 0.050) eq = (x - 2)*(x**2 - 6*x + 4)*exp(-x) assert Sum(eq, (x, 1, oo)).is_convergent() is S.true assert Sum(eq, (x, 1, 2)).is_convergent() is S.true assert Sum(1/(x**3), (x, 1, oo)).is_convergent() is S.true assert Sum(1/(x**S.Half), (x, 1, oo)).is_convergent() is S.false # issue 19545 assert Sum(1/n - 3/(3*n +2), (n, 1, oo)).is_convergent() is S.true # issue 19836 assert Sum(4/(n + 2) - 5/(n + 1) + 1/n,(n, 7, oo)).is_convergent() is S.true def test_is_absolutely_convergent(): assert Sum((-1)**n, (n, 1, oo)).is_absolutely_convergent() is S.false assert Sum((-1)**n/n**2, (n, 1, oo)).is_absolutely_convergent() is S.true @XFAIL def test_convergent_failing(): # dirichlet tests assert Sum(sin(n)/n, (n, 1, oo)).is_convergent() is S.true assert Sum(sin(2*n)/n, (n, 1, oo)).is_convergent() is S.true def test_issue_6966(): i, k, m = symbols('i k m', integer=True) z_i, q_i = symbols('z_i q_i') a_k = Sum(-q_i*z_i/k,(i,1,m)) b_k = a_k.diff(z_i) assert isinstance(b_k, Sum) assert b_k == Sum(-q_i/k,(i,1,m)) def test_issue_10156(): cx = Sum(2*y**2*x, (x, 1,3)) e = 2*y*Sum(2*cx*x**2, (x, 1, 9)) assert e.factor() == \ 8*y**3*Sum(x, (x, 1, 3))*Sum(x**2, (x, 1, 9)) def test_issue_10973(): assert Sum((-n + (n**3 + 1)**(S(1)/3))/log(n), (n, 1, oo)).is_convergent() is S.true def test_issue_14129(): assert Sum( k*x**k, (k, 0, n-1)).doit() == \ Piecewise((n**2/2 - n/2, Eq(x, 1)), ((n*x*x**n - n*x**n - x*x**n + x)/(x - 1)**2, True)) assert Sum( x**k, (k, 0, n-1)).doit() == \ Piecewise((n, Eq(x, 1)), ((-x**n + 1)/(-x + 1), True)) assert Sum( k*(x/y+x)**k, (k, 0, n-1)).doit() == \ Piecewise((n*(n - 1)/2, Eq(x, y/(y + 1))), (x*(y + 1)*(n*x*y*(x + x/y)**n/(x + x/y) + n*x*(x + x/y)**n/(x + x/y) - n*y*(x + x/y)**n/(x + x/y) - x*y*(x + x/y)**n/(x + x/y) - x*(x + x/y)**n/(x + x/y) + y)/(x*y + x - y)**2, True)) def test_issue_14112(): assert Sum((-1)**n/sqrt(n), (n, 1, oo)).is_absolutely_convergent() is S.false assert Sum((-1)**(2*n)/n, (n, 1, oo)).is_convergent() is S.false assert Sum((-2)**n + (-3)**n, (n, 1, oo)).is_convergent() is S.false def test_sin_times_absolutely_convergent(): assert Sum(sin(n) / n**3, (n, 1, oo)).is_convergent() is S.true assert Sum(sin(n) * log(n) / n**3, (n, 1, oo)).is_convergent() is S.true def test_issue_14111(): assert Sum(1/log(log(n)), (n, 22, oo)).is_convergent() is S.false def test_issue_14484(): assert Sum(sin(n)/log(log(n)), (n, 22, oo)).is_convergent() is S.false def test_issue_14640(): i, n = symbols("i n", integer=True) a, b, c = symbols("a b c") assert Sum(a**-i/(a - b), (i, 0, n)).doit() == Sum( 1/(a*a**i - a**i*b), (i, 0, n)).doit() == Piecewise( (n + 1, Eq(1/a, 1)), ((-a**(-n - 1) + 1)/(1 - 1/a), True))/(a - b) assert Sum((b*a**i - c*a**i)**-2, (i, 0, n)).doit() == Piecewise( (n + 1, Eq(a**(-2), 1)), ((-a**(-2*n - 2) + 1)/(1 - 1/a**2), True))/(b - c)**2 s = Sum(i*(a**(n - i) - b**(n - i))/(a - b), (i, 0, n)).doit() assert not s.has(Sum) assert s.subs({a: 2, b: 3, n: 5}) == 122 def test_issue_15943(): s = Sum(binomial(n, k)*factorial(n - k), (k, 0, n)).doit().rewrite(gamma) assert s == -E*(n + 1)*gamma(n + 1)*lowergamma(n + 1, 1)/gamma(n + 2 ) + E*gamma(n + 1) assert s.simplify() == E*(factorial(n) - lowergamma(n + 1, 1)) def test_Sum_dummy_eq(): assert not Sum(x, (x, a, b)).dummy_eq(1) assert not Sum(x, (x, a, b)).dummy_eq(Sum(x, (x, a, b), (a, 1, 2))) assert not Sum(x, (x, a, b)).dummy_eq(Sum(x, (x, a, c))) assert Sum(x, (x, a, b)).dummy_eq(Sum(x, (x, a, b))) d = Dummy() assert Sum(x, (x, a, d)).dummy_eq(Sum(x, (x, a, c)), c) assert not Sum(x, (x, a, d)).dummy_eq(Sum(x, (x, a, c))) assert Sum(x, (x, a, c)).dummy_eq(Sum(y, (y, a, c))) assert Sum(x, (x, a, d)).dummy_eq(Sum(y, (y, a, c)), c) assert not Sum(x, (x, a, d)).dummy_eq(Sum(y, (y, a, c))) def test_issue_15852(): assert summation(x**y*y, (y, -oo, oo)).doit() == Sum(x**y*y, (y, -oo, oo)) def test_exceptions(): S = Sum(x, (x, a, b)) raises(ValueError, lambda: S.change_index(x, x**2, y)) S = Sum(x, (x, a, b), (x, 1, 4)) raises(ValueError, lambda: S.index(x)) S = Sum(x, (x, a, b), (y, 1, 4)) raises(ValueError, lambda: S.reorder([x])) S = Sum(x, (x, y, b), (y, 1, 4)) raises(ReorderError, lambda: S.reorder_limit(0, 1)) S = Sum(x*y, (x, a, b), (y, 1, 4)) raises(NotImplementedError, lambda: S.is_convergent()) def test_sumproducts_assumptions(): M = Symbol('M', integer=True, positive=True) m = Symbol('m', integer=True) for func in [Sum, Product]: assert func(m, (m, -M, M)).is_positive is None assert func(m, (m, -M, M)).is_nonpositive is None assert func(m, (m, -M, M)).is_negative is None assert func(m, (m, -M, M)).is_nonnegative is None assert func(m, (m, -M, M)).is_finite is True m = Symbol('m', integer=True, nonnegative=True) for func in [Sum, Product]: assert func(m, (m, 0, M)).is_positive is None assert func(m, (m, 0, M)).is_nonpositive is None assert func(m, (m, 0, M)).is_negative is False assert func(m, (m, 0, M)).is_nonnegative is True assert func(m, (m, 0, M)).is_finite is True m = Symbol('m', integer=True, positive=True) for func in [Sum, Product]: assert func(m, (m, 1, M)).is_positive is True assert func(m, (m, 1, M)).is_nonpositive is False assert func(m, (m, 1, M)).is_negative is False assert func(m, (m, 1, M)).is_nonnegative is True assert func(m, (m, 1, M)).is_finite is True m = Symbol('m', integer=True, negative=True) assert Sum(m, (m, -M, -1)).is_positive is False assert Sum(m, (m, -M, -1)).is_nonpositive is True assert Sum(m, (m, -M, -1)).is_negative is True assert Sum(m, (m, -M, -1)).is_nonnegative is False assert Sum(m, (m, -M, -1)).is_finite is True assert Product(m, (m, -M, -1)).is_positive is None assert Product(m, (m, -M, -1)).is_nonpositive is None assert Product(m, (m, -M, -1)).is_negative is None assert Product(m, (m, -M, -1)).is_nonnegative is None assert Product(m, (m, -M, -1)).is_finite is True m = Symbol('m', integer=True, nonpositive=True) assert Sum(m, (m, -M, 0)).is_positive is False assert Sum(m, (m, -M, 0)).is_nonpositive is True assert Sum(m, (m, -M, 0)).is_negative is None assert Sum(m, (m, -M, 0)).is_nonnegative is None assert Sum(m, (m, -M, 0)).is_finite is True assert Product(m, (m, -M, 0)).is_positive is None assert Product(m, (m, -M, 0)).is_nonpositive is None assert Product(m, (m, -M, 0)).is_negative is None assert Product(m, (m, -M, 0)).is_nonnegative is None assert Product(m, (m, -M, 0)).is_finite is True m = Symbol('m', integer=True) assert Sum(2, (m, 0, oo)).is_positive is None assert Sum(2, (m, 0, oo)).is_nonpositive is None assert Sum(2, (m, 0, oo)).is_negative is None assert Sum(2, (m, 0, oo)).is_nonnegative is None assert Sum(2, (m, 0, oo)).is_finite is None assert Product(2, (m, 0, oo)).is_positive is None assert Product(2, (m, 0, oo)).is_nonpositive is None assert Product(2, (m, 0, oo)).is_negative is False assert Product(2, (m, 0, oo)).is_nonnegative is None assert Product(2, (m, 0, oo)).is_finite is None assert Product(0, (x, M, M-1)).is_positive is True assert Product(0, (x, M, M-1)).is_finite is True def test_expand_with_assumptions(): M = Symbol('M', integer=True, positive=True) x = Symbol('x', positive=True) m = Symbol('m', nonnegative=True) assert log(Product(x**m, (m, 0, M))).expand() == Sum(m*log(x), (m, 0, M)) assert log(Product(exp(x**m), (m, 0, M))).expand() == Sum(x**m, (m, 0, M)) assert log(Product(x**m, (m, 0, M))).rewrite(Sum).expand() == Sum(m*log(x), (m, 0, M)) assert log(Product(exp(x**m), (m, 0, M))).rewrite(Sum).expand() == Sum(x**m, (m, 0, M)) n = Symbol('n', nonnegative=True) i, j = symbols('i,j', positive=True, integer=True) x, y = symbols('x,y', positive=True) assert log(Product(x**i*y**j, (i, 1, n), (j, 1, m))).expand() \ == Sum(i*log(x) + j*log(y), (i, 1, n), (j, 1, m)) def test_has_finite_limits(): x = Symbol('x') assert Sum(1, (x, 1, 9)).has_finite_limits is True assert Sum(1, (x, 1, oo)).has_finite_limits is False M = Symbol('M') assert Sum(1, (x, 1, M)).has_finite_limits is None M = Symbol('M', positive=True) assert Sum(1, (x, 1, M)).has_finite_limits is True x = Symbol('x', positive=True) M = Symbol('M') assert Sum(1, (x, 1, M)).has_finite_limits is True assert Sum(1, (x, 1, M), (y, -oo, oo)).has_finite_limits is False def test_has_reversed_limits(): assert Sum(1, (x, 1, 1)).has_reversed_limits is False assert Sum(1, (x, 1, 9)).has_reversed_limits is False assert Sum(1, (x, 1, -9)).has_reversed_limits is True assert Sum(1, (x, 1, 0)).has_reversed_limits is True assert Sum(1, (x, 1, oo)).has_reversed_limits is False M = Symbol('M') assert Sum(1, (x, 1, M)).has_reversed_limits is None M = Symbol('M', positive=True, integer=True) assert Sum(1, (x, 1, M)).has_reversed_limits is False assert Sum(1, (x, 1, M), (y, -oo, oo)).has_reversed_limits is False M = Symbol('M', negative=True) assert Sum(1, (x, 1, M)).has_reversed_limits is True assert Sum(1, (x, 1, M), (y, -oo, oo)).has_reversed_limits is True assert Sum(1, (x, oo, oo)).has_reversed_limits is None def test_has_empty_sequence(): assert Sum(1, (x, 1, 1)).has_empty_sequence is False assert Sum(1, (x, 1, 9)).has_empty_sequence is False assert Sum(1, (x, 1, -9)).has_empty_sequence is False assert Sum(1, (x, 1, 0)).has_empty_sequence is True assert Sum(1, (x, y, y - 1)).has_empty_sequence is True assert Sum(1, (x, 3, 2), (y, -oo, oo)).has_empty_sequence is True assert Sum(1, (y, -oo, oo), (x, 3, 2)).has_empty_sequence is True assert Sum(1, (x, oo, oo)).has_empty_sequence is False def test_empty_sequence(): assert Product(x*y, (x, -oo, oo), (y, 1, 0)).doit() == 1 assert Product(x*y, (y, 1, 0), (x, -oo, oo)).doit() == 1 assert Sum(x, (x, -oo, oo), (y, 1, 0)).doit() == 0 assert Sum(x, (y, 1, 0), (x, -oo, oo)).doit() == 0 def test_issue_8016(): k = Symbol('k', integer=True) n, m = symbols('n, m', integer=True, positive=True) s = Sum(binomial(m, k)*binomial(m, n - k)*(-1)**k, (k, 0, n)) assert s.doit().simplify() == \ cos(pi*n/2)*gamma(m + 1)/gamma(n/2 + 1)/gamma(m - n/2 + 1) def test_issue_14313(): assert Sum(S.Half**floor(n/2), (n, 1, oo)).is_convergent() def test_issue_14563(): # The assertion was failing due to no assumptions methods in Sums and Product assert 1 % Sum(1, (x, 0, 1)) == 1 def test_issue_16735(): assert Sum(5**n/gamma(n+1), (n, 1, oo)).is_convergent() is S.true def test_issue_14871(): assert Sum((Rational(1, 10))**n*rf(0, n)/factorial(n), (n, 0, oo)).rewrite(factorial).doit() == 1 def test_issue_17165(): n = symbols("n", integer=True) x = symbols('x') s = (x*Sum(x**n, (n, -1, oo))) ssimp = s.doit().simplify() assert ssimp == Piecewise((-1/(x - 1), Abs(x) < 1), (x*Sum(x**n, (n, -1, oo)), True)) assert ssimp == ssimp.simplify() def test_issue_19379(): assert Sum(factorial(n)/factorial(n + 2), (n, 1, oo)).is_convergent() is S.true def test_issue_20777(): assert Sum(exp(x*sin(n/m)), (n, 1, m)).doit() == Sum(exp(x*sin(n/m)), (n, 1, m)) def test__dummy_with_inherited_properties_concrete(): x = Symbol('x') from sympy import Tuple d = _dummy_with_inherited_properties_concrete(Tuple(x, 0, 5)) assert d.is_real assert d.is_integer assert d.is_nonnegative assert d.is_extended_nonnegative d = _dummy_with_inherited_properties_concrete(Tuple(x, 1, 9)) assert d.is_real assert d.is_integer assert d.is_positive assert d.is_odd is None d = _dummy_with_inherited_properties_concrete(Tuple(x, -5, 5)) assert d.is_real assert d.is_integer assert d.is_positive is None assert d.is_extended_nonnegative is None assert d.is_odd is None d = _dummy_with_inherited_properties_concrete(Tuple(x, -1.5, 1.5)) assert d.is_real assert d.is_integer is None assert d.is_positive is None assert d.is_extended_nonnegative is None N = Symbol('N', integer=True, positive=True) d = _dummy_with_inherited_properties_concrete(Tuple(x, 2, N)) assert d.is_real assert d.is_positive assert d.is_integer # Return None if no assumptions are added N = Symbol('N', integer=True, positive=True) d = _dummy_with_inherited_properties_concrete(Tuple(N, 2, 4)) assert d is None x = Symbol('x', negative=True) raises(InconsistentAssumptions, lambda: _dummy_with_inherited_properties_concrete(Tuple(x, 1, 5))) def test_matrixsymbol_summation_numerical_limits(): A = MatrixSymbol('A', 3, 3) n = Symbol('n', integer=True) assert Sum(A**n, (n, 0, 2)).doit() == Identity(3) + A + A**2 assert Sum(A, (n, 0, 2)).doit() == 3*A assert Sum(n*A, (n, 0, 2)).doit() == 3*A B = Matrix([[0, n, 0], [-1, 0, 0], [0, 0, 2]]) ans = Matrix([[0, 6, 0], [-4, 0, 0], [0, 0, 8]]) + 4*A assert Sum(A+B, (n, 0, 3)).doit() == ans ans = A*Matrix([[0, 6, 0], [-4, 0, 0], [0, 0, 8]]) assert Sum(A*B, (n, 0, 3)).doit() == ans ans = (A**2*Matrix([[-2, 0, 0], [0,-2, 0], [0, 0, 4]]) + A**3*Matrix([[0, -9, 0], [3, 0, 0], [0, 0, 8]]) + A*Matrix([[0, 1, 0], [-1, 0, 0], [0, 0, 2]])) assert Sum(A**n*B**n, (n, 1, 3)).doit() == ans def test_issue_21651(): from sympy import floor, Sum, Symbol i = Symbol('i') a = Sum(floor(2*2**(-i)), (i, S.One, 2)) assert a.doit() == S.One @XFAIL def test_matrixsymbol_summation_symbolic_limits(): N = Symbol('N', integer=True, positive=True) A = MatrixSymbol('A', 3, 3) n = Symbol('n', integer=True) assert Sum(A, (n, 0, N)).doit() == (N+1)*A assert Sum(n*A, (n, 0, N)).doit() == (N**2/2+N/2)*A def test_summation_by_residues(): x = Symbol('x') # Examples from Nakhle H. Asmar, Loukas Grafakos, # Complex Analysis with Applications assert eval_sum_residue(1 / (x**2 + 1), (x, -oo, oo)) == pi/tanh(pi) assert eval_sum_residue(1 / x**6, (x, S(1), oo)) == pi**6/945 assert eval_sum_residue(1 / (x**2 + 9), (x, -oo, oo)) == pi/(3*tanh(3*pi)) assert eval_sum_residue(1 / (x**2 + 1)**2, (x, -oo, oo)).cancel() == \ (-pi**2*tanh(pi)**2 + pi*tanh(pi) + pi**2)/(2*tanh(pi)**2) assert eval_sum_residue(x**2 / (x**2 + 1)**2, (x, -oo, oo)).cancel() == \ (-pi**2 + pi*tanh(pi) + pi**2*tanh(pi)**2)/(2*tanh(pi)**2) assert eval_sum_residue(1 / (4*x**2 - 1), (x, -oo, oo)) == 0 assert eval_sum_residue(x**2 / (x**2 - S(1)/4)**2, (x, -oo, oo)) == pi**2/2 assert eval_sum_residue(1 / (4*x**2 - 1)**2, (x, -oo, oo)) == pi**2/8 assert eval_sum_residue(1 / ((x - S(1)/2)**2 + 1), (x, -oo, oo)) == pi*tanh(pi) assert eval_sum_residue(1 / x**2, (x, S(1), oo)) == pi**2/6 assert eval_sum_residue(1 / x**4, (x, S(1), oo)) == pi**4/90 assert eval_sum_residue(1 / x**2 / (x**2 + 4), (x, S(1), oo)) == \ -pi*(-pi/12 - 1/(16*pi) + 1/(8*tanh(2*pi)))/2 # Some examples made from 1 / (x**2 + 1) assert eval_sum_residue(1 / (x**2 + 1), (x, S(0), oo)) == \ S(1)/2 + pi/(2*tanh(pi)) assert eval_sum_residue(1 / (x**2 + 1), (x, S(1), oo)) == \ -S(1)/2 + pi/(2*tanh(pi)) assert eval_sum_residue(1 / (x**2 + 1), (x, S(-1), oo)) == \ 1 + pi/(2*tanh(pi)) assert eval_sum_residue((-1)**x / (x**2 + 1), (x, -oo, oo)) == \ pi/sinh(pi) assert eval_sum_residue((-1)**x / (x**2 + 1), (x, S(0), oo)) == \ pi/(2*sinh(pi)) + S(1)/2 assert eval_sum_residue((-1)**x / (x**2 + 1), (x, S(1), oo)) == \ -S(1)/2 + pi/(2*sinh(pi)) assert eval_sum_residue((-1)**x / (x**2 + 1), (x, S(-1), oo)) == \ pi/(2*sinh(pi)) # Some examples made from shifting of 1 / (x**2 + 1) assert eval_sum_residue(1 / (x**2 + 2*x + 2), (x, S(-1), oo)) == S(1)/2 + pi/(2*tanh(pi)) assert eval_sum_residue(1 / (x**2 + 4*x + 5), (x, S(-2), oo)) == S(1)/2 + pi/(2*tanh(pi)) assert eval_sum_residue(1 / (x**2 - 2*x + 2), (x, S(1), oo)) == S(1)/2 + pi/(2*tanh(pi)) assert eval_sum_residue(1 / (x**2 - 4*x + 5), (x, S(2), oo)) == S(1)/2 + pi/(2*tanh(pi)) assert eval_sum_residue((-1)**x * -1 / (x**2 + 2*x + 2), (x, S(-1), oo)) == S(1)/2 + pi/(2*sinh(pi)) assert eval_sum_residue((-1)**x * -1 / (x**2 -2*x + 2), (x, S(1), oo)) == S(1)/2 + pi/(2*sinh(pi)) # Some examples made from 1 / x**2 assert eval_sum_residue(1 / x**2, (x, S(2), oo)) == -1 + pi**2/6 assert eval_sum_residue(1 / x**2, (x, S(3), oo)) == -S(5)/4 + pi**2/6 assert eval_sum_residue((-1)**x / x**2, (x, S(1), oo)) == -pi**2/12 assert eval_sum_residue((-1)**x / x**2, (x, S(2), oo)) == 1 - pi**2/12 @slow def test_summation_by_residues_failing(): x = Symbol('x') # Failing because of the bug in residue computation assert eval_sum_residue(x**2 / (x**4 + 1), (x, S(1), oo)) assert eval_sum_residue(1 / ((x - 1)*(x - 2) + 1), (x, -oo, oo)) != 0 sympy-sympy-1.9/sympy/conftest.py000066400000000000000000000043551412543434000173120ustar00rootroot00000000000000import sys sys._running_pytest = True # type: ignore from sympy.external.importtools import version_tuple import pytest from sympy.core.cache import clear_cache import re sp = re.compile(r'([0-9]+)/([1-9][0-9]*)') def process_split(config, items): split = config.getoption("--split") if not split: return m = sp.match(split) if not m: raise ValueError("split must be a string of the form a/b " "where a and b are ints.") i, t = map(int, m.groups()) start, end = (i-1)*len(items)//t, i*len(items)//t if i < t: # remove elements from end of list first del items[end:] del items[:start] def pytest_report_header(config): from sympy.utilities.misc import ARCH s = "architecture: %s\n" % ARCH from sympy.core.cache import USE_CACHE s += "cache: %s\n" % USE_CACHE from sympy.external.gmpy import GROUND_TYPES, HAS_GMPY version = '' if GROUND_TYPES =='gmpy': if HAS_GMPY == 1: import gmpy elif HAS_GMPY == 2: import gmpy2 as gmpy version = gmpy.version() s += "ground types: %s %s\n" % (GROUND_TYPES, version) return s def pytest_terminal_summary(terminalreporter): if (terminalreporter.stats.get('error', None) or terminalreporter.stats.get('failed', None)): terminalreporter.write_sep( ' ', 'DO *NOT* COMMIT!', red=True, bold=True) def pytest_addoption(parser): parser.addoption("--split", action="store", default="", help="split tests") def pytest_collection_modifyitems(config, items): """ pytest hook. """ # handle splits process_split(config, items) @pytest.fixture(autouse=True, scope='module') def file_clear_cache(): clear_cache() @pytest.fixture(autouse=True, scope='module') def check_disabled(request): if getattr(request.module, 'disabled', False): pytest.skip("test requirements not met.") elif getattr(request.module, 'ipython', False): # need to check version and options for ipython tests if (version_tuple(pytest.__version__) < version_tuple('2.6.3') and pytest.config.getvalue('-s') != 'no'): pytest.skip("run py.test with -s or upgrade to newer version.") sympy-sympy-1.9/sympy/core/000077500000000000000000000000001412543434000160345ustar00rootroot00000000000000sympy-sympy-1.9/sympy/core/__init__.py000066400000000000000000000054541412543434000201550ustar00rootroot00000000000000"""Core module. Provides the basic operations needed in sympy. """ from .sympify import sympify, SympifyError from .cache import cacheit from .assumptions import assumptions, check_assumptions, failing_assumptions, common_assumptions from .basic import Basic, Atom, preorder_traversal from .singleton import S from .expr import Expr, AtomicExpr, UnevaluatedExpr from .symbol import Symbol, Wild, Dummy, symbols, var from .numbers import Number, Float, Rational, Integer, NumberSymbol, \ RealNumber, igcd, ilcm, seterr, E, I, nan, oo, pi, zoo, \ AlgebraicNumber, comp, mod_inverse from .power import Pow, integer_nthroot, integer_log from .mul import Mul, prod from .add import Add from .mod import Mod from .relational import ( Rel, Eq, Ne, Lt, Le, Gt, Ge, Equality, GreaterThan, LessThan, Unequality, StrictGreaterThan, StrictLessThan ) from .multidimensional import vectorize from .function import Lambda, WildFunction, Derivative, diff, FunctionClass, \ Function, Subs, expand, PoleError, count_ops, \ expand_mul, expand_log, expand_func, \ expand_trig, expand_complex, expand_multinomial, nfloat, \ expand_power_base, expand_power_exp, arity from .evalf import PrecisionExhausted, N from .containers import Tuple, Dict from .exprtools import gcd_terms, factor_terms, factor_nc from .parameters import evaluate from .kind import UndefinedKind, NumberKind, BooleanKind # expose singletons Catalan = S.Catalan EulerGamma = S.EulerGamma GoldenRatio = S.GoldenRatio TribonacciConstant = S.TribonacciConstant __all__ = [ 'sympify', 'SympifyError', 'cacheit', 'assumptions', 'check_assumptions', 'failing_assumptions', 'common_assumptions', 'Basic', 'Atom', 'preorder_traversal', 'S', 'Expr', 'AtomicExpr', 'UnevaluatedExpr', 'Symbol', 'Wild', 'Dummy', 'symbols', 'var', 'Number', 'Float', 'Rational', 'Integer', 'NumberSymbol', 'RealNumber', 'igcd', 'ilcm', 'seterr', 'E', 'I', 'nan', 'oo', 'pi', 'zoo', 'AlgebraicNumber', 'comp', 'mod_inverse', 'Pow', 'integer_nthroot', 'integer_log', 'Mul', 'prod', 'Add', 'Mod', 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', 'Equality', 'GreaterThan', 'LessThan', 'Unequality', 'StrictGreaterThan', 'StrictLessThan', 'vectorize', 'Lambda', 'WildFunction', 'Derivative', 'diff', 'FunctionClass', 'Function', 'Subs', 'expand', 'PoleError', 'count_ops', 'expand_mul', 'expand_log', 'expand_func', 'expand_trig', 'expand_complex', 'expand_multinomial', 'nfloat', 'expand_power_base', 'expand_power_exp', 'arity', 'PrecisionExhausted', 'N', 'evalf', # The module? 'Tuple', 'Dict', 'gcd_terms', 'factor_terms', 'factor_nc', 'evaluate', 'Catalan', 'EulerGamma', 'GoldenRatio', 'TribonacciConstant', 'UndefinedKind', 'NumberKind', 'BooleanKind', ] sympy-sympy-1.9/sympy/core/_print_helpers.py000066400000000000000000000045241412543434000214300ustar00rootroot00000000000000""" Base class to provide str and repr hooks that `init_printing` can overwrite. This is exposed publicly in the `printing.defaults` module, but cannot be defined there without causing circular imports. """ class Printable: """ The default implementation of printing for SymPy classes. This implements a hack that allows us to print elements of built-in Python containers in a readable way. Natively Python uses ``repr()`` even if ``str()`` was explicitly requested. Mix in this trait into a class to get proper default printing. This also adds support for LaTeX printing in jupyter notebooks. """ # Since this class is used as a mixin we set empty slots. That means that # instances of any subclasses that use slots will not need to have a # __dict__. __slots__ = () # Note, we always use the default ordering (lex) in __str__ and __repr__, # regardless of the global setting. See issue 5487. def __str__(self): from sympy.printing.str import sstr return sstr(self, order=None) __repr__ = __str__ def _repr_disabled(self): """ No-op repr function used to disable jupyter display hooks. When :func:`sympy.init_printing` is used to disable certain display formats, this function is copied into the appropriate ``_repr_*_`` attributes. While we could just set the attributes to `None``, doing it this way allows derived classes to call `super()`. """ return None # We don't implement _repr_png_ here because it would add a large amount of # data to any notebook containing SymPy expressions, without adding # anything useful to the notebook. It can still enabled manually, e.g., # for the qtconsole, with init_printing(). _repr_png_ = _repr_disabled _repr_svg_ = _repr_disabled def _repr_latex_(self): """ IPython/Jupyter LaTeX printing To change the behavior of this (e.g., pass in some settings to LaTeX), use init_printing(). init_printing() will also enable LaTeX printing for built in numeric types like ints and container types that contain SymPy objects, like lists and dictionaries of expressions. """ from sympy.printing.latex import latex s = latex(self, mode='plain') return "$\\displaystyle %s$" % s sympy-sympy-1.9/sympy/core/add.py000066400000000000000000001212661412543434000171460ustar00rootroot00000000000000from collections import defaultdict from functools import cmp_to_key, reduce from operator import attrgetter from .basic import Basic from .compatibility import is_sequence from .parameters import global_parameters from .logic import _fuzzy_group, fuzzy_or, fuzzy_not from .singleton import S from .operations import AssocOp, AssocOpDispatcher from .cache import cacheit from .numbers import ilcm, igcd from .expr import Expr from .kind import UndefinedKind # Key for sorting commutative args in canonical order _args_sortkey = cmp_to_key(Basic.compare) def _addsort(args): # in-place sorting of args args.sort(key=_args_sortkey) def _unevaluated_Add(*args): """Return a well-formed unevaluated Add: Numbers are collected and put in slot 0 and args are sorted. Use this when args have changed but you still want to return an unevaluated Add. Examples ======== >>> from sympy.core.add import _unevaluated_Add as uAdd >>> from sympy import S, Add >>> from sympy.abc import x, y >>> a = uAdd(*[S(1.0), x, S(2)]) >>> a.args[0] 3.00000000000000 >>> a.args[1] x Beyond the Number being in slot 0, there is no other assurance of order for the arguments since they are hash sorted. So, for testing purposes, output produced by this in some other function can only be tested against the output of this function or as one of several options: >>> opts = (Add(x, y, evaluate=False), Add(y, x, evaluate=False)) >>> a = uAdd(x, y) >>> assert a in opts and a == uAdd(x, y) >>> uAdd(x + 1, x + 2) x + x + 3 """ args = list(args) newargs = [] co = S.Zero while args: a = args.pop() if a.is_Add: # this will keep nesting from building up # so that x + (x + 1) -> x + x + 1 (3 args) args.extend(a.args) elif a.is_Number: co += a else: newargs.append(a) _addsort(newargs) if co: newargs.insert(0, co) return Add._from_args(newargs) class Add(Expr, AssocOp): """ Expression representing addition operation for algebraic group. Every argument of ``Add()`` must be ``Expr``. Infix operator ``+`` on most scalar objects in SymPy calls this class. Another use of ``Add()`` is to represent the structure of abstract addition so that its arguments can be substituted to return different class. Refer to examples section for this. ``Add()`` evaluates the argument unless ``evaluate=False`` is passed. The evaluation logic includes: 1. Flattening ``Add(x, Add(y, z))`` -> ``Add(x, y, z)`` 2. Identity removing ``Add(x, 0, y)`` -> ``Add(x, y)`` 3. Coefficient collecting by ``.as_coeff_Mul()`` ``Add(x, 2*x)`` -> ``Mul(3, x)`` 4. Term sorting ``Add(y, x, 2)`` -> ``Add(2, x, y)`` If no argument is passed, identity element 0 is returned. If single element is passed, that element is returned. Note that ``Add(*args)`` is more efficient than ``sum(args)`` because it flattens the arguments. ``sum(a, b, c, ...)`` recursively adds the arguments as ``a + (b + (c + ...))``, which has quadratic complexity. On the other hand, ``Add(a, b, c, d)`` does not assume nested structure, making the complexity linear. Since addition is group operation, every argument should have the same :obj:`sympy.core.kind.Kind()`. Examples ======== >>> from sympy import Add, I >>> from sympy.abc import x, y >>> Add(x, 1) x + 1 >>> Add(x, x) 2*x >>> 2*x**2 + 3*x + I*y + 2*y + 2*x/5 + 1.0*y + 1 2*x**2 + 17*x/5 + 3.0*y + I*y + 1 If ``evaluate=False`` is passed, result is not evaluated. >>> Add(1, 2, evaluate=False) 1 + 2 >>> Add(x, x, evaluate=False) x + x ``Add()`` also represents the general structure of addition operation. >>> from sympy import MatrixSymbol >>> A,B = MatrixSymbol('A', 2,2), MatrixSymbol('B', 2,2) >>> expr = Add(x,y).subs({x:A, y:B}) >>> expr A + B >>> type(expr) Note that the printers don't display in args order. >>> Add(x, 1) x + 1 >>> Add(x, 1).args (1, x) See Also ======== MatAdd """ __slots__ = () is_Add = True _args_type = Expr @classmethod def flatten(cls, seq): """ Takes the sequence "seq" of nested Adds and returns a flatten list. Returns: (commutative_part, noncommutative_part, order_symbols) Applies associativity, all terms are commutable with respect to addition. NB: the removal of 0 is already handled by AssocOp.__new__ See also ======== sympy.core.mul.Mul.flatten """ from sympy.calculus.util import AccumBounds from sympy.matrices.expressions import MatrixExpr from sympy.tensor.tensor import TensExpr rv = None if len(seq) == 2: a, b = seq if b.is_Rational: a, b = b, a if a.is_Rational: if b.is_Mul: rv = [a, b], [], None if rv: if all(s.is_commutative for s in rv[0]): return rv return [], rv[0], None terms = {} # term -> coeff # e.g. x**2 -> 5 for ... + 5*x**2 + ... coeff = S.Zero # coefficient (Number or zoo) to always be in slot 0 # e.g. 3 + ... order_factors = [] extra = [] for o in seq: # O(x) if o.is_Order: if o.expr.is_zero: continue for o1 in order_factors: if o1.contains(o): o = None break if o is None: continue order_factors = [o] + [ o1 for o1 in order_factors if not o.contains(o1)] continue # 3 or NaN elif o.is_Number: if (o is S.NaN or coeff is S.ComplexInfinity and o.is_finite is False) and not extra: # we know for sure the result will be nan return [S.NaN], [], None if coeff.is_Number or isinstance(coeff, AccumBounds): coeff += o if coeff is S.NaN and not extra: # we know for sure the result will be nan return [S.NaN], [], None continue elif isinstance(o, AccumBounds): coeff = o.__add__(coeff) continue elif isinstance(o, MatrixExpr): # can't add 0 to Matrix so make sure coeff is not 0 extra.append(o) continue elif isinstance(o, TensExpr): coeff = o.__add__(coeff) if coeff else o continue elif o is S.ComplexInfinity: if coeff.is_finite is False and not extra: # we know for sure the result will be nan return [S.NaN], [], None coeff = S.ComplexInfinity continue # Add([...]) elif o.is_Add: # NB: here we assume Add is always commutative seq.extend(o.args) # TODO zerocopy? continue # Mul([...]) elif o.is_Mul: c, s = o.as_coeff_Mul() # check for unevaluated Pow, e.g. 2**3 or 2**(-1/2) elif o.is_Pow: b, e = o.as_base_exp() if b.is_Number and (e.is_Integer or (e.is_Rational and e.is_negative)): seq.append(b**e) continue c, s = S.One, o else: # everything else c = S.One s = o # now we have: # o = c*s, where # # c is a Number # s is an expression with number factor extracted # let's collect terms with the same s, so e.g. # 2*x**2 + 3*x**2 -> 5*x**2 if s in terms: terms[s] += c if terms[s] is S.NaN and not extra: # we know for sure the result will be nan return [S.NaN], [], None else: terms[s] = c # now let's construct new args: # [2*x**2, x**3, 7*x**4, pi, ...] newseq = [] noncommutative = False for s, c in terms.items(): # 0*s if c.is_zero: continue # 1*s elif c is S.One: newseq.append(s) # c*s else: if s.is_Mul: # Mul, already keeps its arguments in perfect order. # so we can simply put c in slot0 and go the fast way. cs = s._new_rawargs(*((c,) + s.args)) newseq.append(cs) elif s.is_Add: # we just re-create the unevaluated Mul newseq.append(Mul(c, s, evaluate=False)) else: # alternatively we have to call all Mul's machinery (slow) newseq.append(Mul(c, s)) noncommutative = noncommutative or not s.is_commutative # oo, -oo if coeff is S.Infinity: newseq = [f for f in newseq if not (f.is_extended_nonnegative or f.is_real)] elif coeff is S.NegativeInfinity: newseq = [f for f in newseq if not (f.is_extended_nonpositive or f.is_real)] if coeff is S.ComplexInfinity: # zoo might be # infinite_real + finite_im # finite_real + infinite_im # infinite_real + infinite_im # addition of a finite real or imaginary number won't be able to # change the zoo nature; adding an infinite qualtity would result # in a NaN condition if it had sign opposite of the infinite # portion of zoo, e.g., infinite_real - infinite_real. newseq = [c for c in newseq if not (c.is_finite and c.is_extended_real is not None)] # process O(x) if order_factors: newseq2 = [] for t in newseq: for o in order_factors: # x + O(x) -> O(x) if o.contains(t): t = None break # x + O(x**2) -> x + O(x**2) if t is not None: newseq2.append(t) newseq = newseq2 + order_factors # 1 + O(1) -> O(1) for o in order_factors: if o.contains(coeff): coeff = S.Zero break # order args canonically _addsort(newseq) # current code expects coeff to be first if coeff is not S.Zero: newseq.insert(0, coeff) if extra: newseq += extra noncommutative = True # we are done if noncommutative: return [], newseq, None else: return newseq, [], None @classmethod def class_key(cls): """Nice order of classes""" return 3, 1, cls.__name__ @property def kind(self): k = attrgetter('kind') kinds = map(k, self.args) kinds = frozenset(kinds) if len(kinds) != 1: # Since addition is group operator, kind must be same. # We know that this is unexpected signature, so return this. result = UndefinedKind else: result, = kinds return result def as_coefficients_dict(a): """Return a dictionary mapping terms to their Rational coefficient. Since the dictionary is a defaultdict, inquiries about terms which were not present will return a coefficient of 0. If an expression is not an Add it is considered to have a single term. Examples ======== >>> from sympy.abc import a, x >>> (3*x + a*x + 4).as_coefficients_dict() {1: 4, x: 3, a*x: 1} >>> _[a] 0 >>> (3*a*x).as_coefficients_dict() {a*x: 3} """ d = defaultdict(list) for ai in a.args: c, m = ai.as_coeff_Mul() d[m].append(c) for k, v in d.items(): if len(v) == 1: d[k] = v[0] else: d[k] = Add(*v) di = defaultdict(int) di.update(d) return di @cacheit def as_coeff_add(self, *deps): """ Returns a tuple (coeff, args) where self is treated as an Add and coeff is the Number term and args is a tuple of all other terms. Examples ======== >>> from sympy.abc import x >>> (7 + 3*x).as_coeff_add() (7, (3*x,)) >>> (7*x).as_coeff_add() (0, (7*x,)) """ if deps: from sympy.utilities.iterables import sift l1, l2 = sift(self.args, lambda x: x.has(*deps), binary=True) return self._new_rawargs(*l2), tuple(l1) coeff, notrat = self.args[0].as_coeff_add() if coeff is not S.Zero: return coeff, notrat + self.args[1:] return S.Zero, self.args def as_coeff_Add(self, rational=False, deps=None): """ Efficiently extract the coefficient of a summation. """ coeff, args = self.args[0], self.args[1:] if coeff.is_Number and not rational or coeff.is_Rational: return coeff, self._new_rawargs(*args) return S.Zero, self # Note, we intentionally do not implement Add.as_coeff_mul(). Rather, we # let Expr.as_coeff_mul() just always return (S.One, self) for an Add. See # issue 5524. def _eval_power(self, e): if e.is_Rational and self.is_number: from sympy.core.evalf import pure_complex from sympy.core.mul import _unevaluated_Mul from sympy.core.exprtools import factor_terms from sympy.core.function import expand_multinomial from sympy.functions.elementary.complexes import sign from sympy.functions.elementary.miscellaneous import sqrt ri = pure_complex(self) if ri: r, i = ri if e.q == 2: D = sqrt(r**2 + i**2) if D.is_Rational: # (r, i, D) is a Pythagorean triple root = sqrt(factor_terms((D - r)/2))**e.p return root*expand_multinomial(( # principle value (D + r)/abs(i) + sign(i)*S.ImaginaryUnit)**e.p) elif e == -1: return _unevaluated_Mul( r - i*S.ImaginaryUnit, 1/(r**2 + i**2)) elif e.is_Number and abs(e) != 1: # handle the Float case: (2.0 + 4*x)**e -> 4**e*(0.5 + x)**e c, m = zip(*[i.as_coeff_Mul() for i in self.args]) if any(i.is_Float for i in c): # XXX should this always be done? big = -1 for i in c: if abs(i) >= big: big = abs(i) if big > 0 and big != 1: from sympy.functions.elementary.complexes import sign bigs = (big, -big) c = [sign(i) if i in bigs else i/big for i in c] addpow = Add(*[c*m for c, m in zip(c, m)])**e return big**e*addpow @cacheit def _eval_derivative(self, s): return self.func(*[a.diff(s) for a in self.args]) def _eval_nseries(self, x, n, logx, cdir=0): terms = [t.nseries(x, n=n, logx=logx, cdir=cdir) for t in self.args] return self.func(*terms) def _matches_simple(self, expr, repl_dict): # handle (w+3).matches('x+5') -> {w: x+2} coeff, terms = self.as_coeff_add() if len(terms) == 1: return terms[0].matches(expr - coeff, repl_dict) return def matches(self, expr, repl_dict={}, old=False): return self._matches_commutative(expr, repl_dict, old) @staticmethod def _combine_inverse(lhs, rhs): """ Returns lhs - rhs, but treats oo like a symbol so oo - oo returns 0, instead of a nan. """ from sympy.simplify.simplify import signsimp from sympy.core.symbol import Dummy inf = (S.Infinity, S.NegativeInfinity) if lhs.has(*inf) or rhs.has(*inf): oo = Dummy('oo') reps = { S.Infinity: oo, S.NegativeInfinity: -oo} ireps = {v: k for k, v in reps.items()} eq = lhs.xreplace(reps) - rhs.xreplace(reps) if eq.has(oo): eq = eq.replace( lambda x: x.is_Pow and x.base is oo, lambda x: x.base) rv = eq.xreplace(ireps) else: rv = lhs - rhs srv = signsimp(rv) return srv if srv.is_Number else rv @cacheit def as_two_terms(self): """Return head and tail of self. This is the most efficient way to get the head and tail of an expression. - if you want only the head, use self.args[0]; - if you want to process the arguments of the tail then use self.as_coef_add() which gives the head and a tuple containing the arguments of the tail when treated as an Add. - if you want the coefficient when self is treated as a Mul then use self.as_coeff_mul()[0] >>> from sympy.abc import x, y >>> (3*x - 2*y + 5).as_two_terms() (5, 3*x - 2*y) """ return self.args[0], self._new_rawargs(*self.args[1:]) def as_numer_denom(self): """ Decomposes an expression to its numerator part and its denominator part. Examples ======== >>> from sympy.abc import x, y, z >>> (x*y/z).as_numer_denom() (x*y, z) >>> (x*(y + 1)/y**7).as_numer_denom() (x*(y + 1), y**7) See Also ======== sympy.core.expr.Expr.as_numer_denom """ # clear rational denominator content, expr = self.primitive() ncon, dcon = content.as_numer_denom() # collect numerators and denominators of the terms nd = defaultdict(list) for f in expr.args: ni, di = f.as_numer_denom() nd[di].append(ni) # check for quick exit if len(nd) == 1: d, n = nd.popitem() return self.func( *[_keep_coeff(ncon, ni) for ni in n]), _keep_coeff(dcon, d) # sum up the terms having a common denominator for d, n in nd.items(): if len(n) == 1: nd[d] = n[0] else: nd[d] = self.func(*n) # assemble single numerator and denominator denoms, numers = [list(i) for i in zip(*iter(nd.items()))] n, d = self.func(*[Mul(*(denoms[:i] + [numers[i]] + denoms[i + 1:])) for i in range(len(numers))]), Mul(*denoms) return _keep_coeff(ncon, n), _keep_coeff(dcon, d) def _eval_is_polynomial(self, syms): return all(term._eval_is_polynomial(syms) for term in self.args) def _eval_is_rational_function(self, syms): return all(term._eval_is_rational_function(syms) for term in self.args) def _eval_is_meromorphic(self, x, a): return _fuzzy_group((arg.is_meromorphic(x, a) for arg in self.args), quick_exit=True) def _eval_is_algebraic_expr(self, syms): return all(term._eval_is_algebraic_expr(syms) for term in self.args) # assumption methods _eval_is_real = lambda self: _fuzzy_group( (a.is_real for a in self.args), quick_exit=True) _eval_is_extended_real = lambda self: _fuzzy_group( (a.is_extended_real for a in self.args), quick_exit=True) _eval_is_complex = lambda self: _fuzzy_group( (a.is_complex for a in self.args), quick_exit=True) _eval_is_antihermitian = lambda self: _fuzzy_group( (a.is_antihermitian for a in self.args), quick_exit=True) _eval_is_finite = lambda self: _fuzzy_group( (a.is_finite for a in self.args), quick_exit=True) _eval_is_hermitian = lambda self: _fuzzy_group( (a.is_hermitian for a in self.args), quick_exit=True) _eval_is_integer = lambda self: _fuzzy_group( (a.is_integer for a in self.args), quick_exit=True) _eval_is_rational = lambda self: _fuzzy_group( (a.is_rational for a in self.args), quick_exit=True) _eval_is_algebraic = lambda self: _fuzzy_group( (a.is_algebraic for a in self.args), quick_exit=True) _eval_is_commutative = lambda self: _fuzzy_group( a.is_commutative for a in self.args) def _eval_is_infinite(self): sawinf = False for a in self.args: ainf = a.is_infinite if ainf is None: return None elif ainf is True: # infinite+infinite might not be infinite if sawinf is True: return None sawinf = True return sawinf def _eval_is_imaginary(self): nz = [] im_I = [] for a in self.args: if a.is_extended_real: if a.is_zero: pass elif a.is_zero is False: nz.append(a) else: return elif a.is_imaginary: im_I.append(a*S.ImaginaryUnit) elif (S.ImaginaryUnit*a).is_extended_real: im_I.append(a*S.ImaginaryUnit) else: return b = self.func(*nz) if b.is_zero: return fuzzy_not(self.func(*im_I).is_zero) elif b.is_zero is False: return False def _eval_is_zero(self): if self.is_commutative is False: # issue 10528: there is no way to know if a nc symbol # is zero or not return nz = [] z = 0 im_or_z = False im = 0 for a in self.args: if a.is_extended_real: if a.is_zero: z += 1 elif a.is_zero is False: nz.append(a) else: return elif a.is_imaginary: im += 1 elif (S.ImaginaryUnit*a).is_extended_real: im_or_z = True else: return if z == len(self.args): return True if len(nz) == 0 or len(nz) == len(self.args): return None b = self.func(*nz) if b.is_zero: if not im_or_z: if im == 0: return True elif im == 1: return False if b.is_zero is False: return False def _eval_is_odd(self): l = [f for f in self.args if not (f.is_even is True)] if not l: return False if l[0].is_odd: return self._new_rawargs(*l[1:]).is_even def _eval_is_irrational(self): for t in self.args: a = t.is_irrational if a: others = list(self.args) others.remove(t) if all(x.is_rational is True for x in others): return True return None if a is None: return return False def _eval_is_extended_positive(self): from sympy.core.exprtools import _monotonic_sign if self.is_number: return super()._eval_is_extended_positive() c, a = self.as_coeff_Add() if not c.is_zero: v = _monotonic_sign(a) if v is not None: s = v + c if s != self and s.is_extended_positive and a.is_extended_nonnegative: return True if len(self.free_symbols) == 1: v = _monotonic_sign(self) if v is not None and v != self and v.is_extended_positive: return True pos = nonneg = nonpos = unknown_sign = False saw_INF = set() args = [a for a in self.args if not a.is_zero] if not args: return False for a in args: ispos = a.is_extended_positive infinite = a.is_infinite if infinite: saw_INF.add(fuzzy_or((ispos, a.is_extended_nonnegative))) if True in saw_INF and False in saw_INF: return if ispos: pos = True continue elif a.is_extended_nonnegative: nonneg = True continue elif a.is_extended_nonpositive: nonpos = True continue if infinite is None: return unknown_sign = True if saw_INF: if len(saw_INF) > 1: return return saw_INF.pop() elif unknown_sign: return elif not nonpos and not nonneg and pos: return True elif not nonpos and pos: return True elif not pos and not nonneg: return False def _eval_is_extended_nonnegative(self): from sympy.core.exprtools import _monotonic_sign if not self.is_number: c, a = self.as_coeff_Add() if not c.is_zero and a.is_extended_nonnegative: v = _monotonic_sign(a) if v is not None: s = v + c if s != self and s.is_extended_nonnegative: return True if len(self.free_symbols) == 1: v = _monotonic_sign(self) if v is not None and v != self and v.is_extended_nonnegative: return True def _eval_is_extended_nonpositive(self): from sympy.core.exprtools import _monotonic_sign if not self.is_number: c, a = self.as_coeff_Add() if not c.is_zero and a.is_extended_nonpositive: v = _monotonic_sign(a) if v is not None: s = v + c if s != self and s.is_extended_nonpositive: return True if len(self.free_symbols) == 1: v = _monotonic_sign(self) if v is not None and v != self and v.is_extended_nonpositive: return True def _eval_is_extended_negative(self): from sympy.core.exprtools import _monotonic_sign if self.is_number: return super()._eval_is_extended_negative() c, a = self.as_coeff_Add() if not c.is_zero: v = _monotonic_sign(a) if v is not None: s = v + c if s != self and s.is_extended_negative and a.is_extended_nonpositive: return True if len(self.free_symbols) == 1: v = _monotonic_sign(self) if v is not None and v != self and v.is_extended_negative: return True neg = nonpos = nonneg = unknown_sign = False saw_INF = set() args = [a for a in self.args if not a.is_zero] if not args: return False for a in args: isneg = a.is_extended_negative infinite = a.is_infinite if infinite: saw_INF.add(fuzzy_or((isneg, a.is_extended_nonpositive))) if True in saw_INF and False in saw_INF: return if isneg: neg = True continue elif a.is_extended_nonpositive: nonpos = True continue elif a.is_extended_nonnegative: nonneg = True continue if infinite is None: return unknown_sign = True if saw_INF: if len(saw_INF) > 1: return return saw_INF.pop() elif unknown_sign: return elif not nonneg and not nonpos and neg: return True elif not nonneg and neg: return True elif not neg and not nonpos: return False def _eval_subs(self, old, new): if not old.is_Add: if old is S.Infinity and -old in self.args: # foo - oo is foo + (-oo) internally return self.xreplace({-old: -new}) return None coeff_self, terms_self = self.as_coeff_Add() coeff_old, terms_old = old.as_coeff_Add() if coeff_self.is_Rational and coeff_old.is_Rational: if terms_self == terms_old: # (2 + a).subs( 3 + a, y) -> -1 + y return self.func(new, coeff_self, -coeff_old) if terms_self == -terms_old: # (2 + a).subs(-3 - a, y) -> -1 - y return self.func(-new, coeff_self, coeff_old) if coeff_self.is_Rational and coeff_old.is_Rational \ or coeff_self == coeff_old: args_old, args_self = self.func.make_args( terms_old), self.func.make_args(terms_self) if len(args_old) < len(args_self): # (a+b+c).subs(b+c,x) -> a+x self_set = set(args_self) old_set = set(args_old) if old_set < self_set: ret_set = self_set - old_set return self.func(new, coeff_self, -coeff_old, *[s._subs(old, new) for s in ret_set]) args_old = self.func.make_args( -terms_old) # (a+b+c+d).subs(-b-c,x) -> a-x+d old_set = set(args_old) if old_set < self_set: ret_set = self_set - old_set return self.func(-new, coeff_self, coeff_old, *[s._subs(old, new) for s in ret_set]) def removeO(self): args = [a for a in self.args if not a.is_Order] return self._new_rawargs(*args) def getO(self): args = [a for a in self.args if a.is_Order] if args: return self._new_rawargs(*args) @cacheit def extract_leading_order(self, symbols, point=None): """ Returns the leading term and its order. Examples ======== >>> from sympy.abc import x >>> (x + 1 + 1/x**5).extract_leading_order(x) ((x**(-5), O(x**(-5))),) >>> (1 + x).extract_leading_order(x) ((1, O(1)),) >>> (x + x**2).extract_leading_order(x) ((x, O(x)),) """ from sympy import Order lst = [] symbols = list(symbols if is_sequence(symbols) else [symbols]) if not point: point = [0]*len(symbols) seq = [(f, Order(f, *zip(symbols, point))) for f in self.args] for ef, of in seq: for e, o in lst: if o.contains(of) and o != of: of = None break if of is None: continue new_lst = [(ef, of)] for e, o in lst: if of.contains(o) and o != of: continue new_lst.append((e, o)) lst = new_lst return tuple(lst) def as_real_imag(self, deep=True, **hints): """ returns a tuple representing a complex number Examples ======== >>> from sympy import I >>> (7 + 9*I).as_real_imag() (7, 9) >>> ((1 + I)/(1 - I)).as_real_imag() (0, 1) >>> ((1 + 2*I)*(1 + 3*I)).as_real_imag() (-5, 5) """ sargs = self.args re_part, im_part = [], [] for term in sargs: re, im = term.as_real_imag(deep=deep) re_part.append(re) im_part.append(im) return (self.func(*re_part), self.func(*im_part)) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import expand_mul, Order, Piecewise, piecewise_fold, log old = self if old.has(Piecewise): old = piecewise_fold(old) # This expansion is the last part of expand_log. expand_log also calls # expand_mul with factor=True, which would be more expensive if any(isinstance(a, log) for a in self.args): logflags = dict(deep=True, log=True, mul=False, power_exp=False, power_base=False, multinomial=False, basic=False, force=False, factor=False) old = old.expand(**logflags) expr = expand_mul(old) if not expr.is_Add: return expr.as_leading_term(x, logx=logx, cdir=cdir) infinite = [t for t in expr.args if t.is_infinite] leading_terms = [t.as_leading_term(x, logx=logx, cdir=cdir) for t in expr.args] min, new_expr = Order(0), 0 try: for term in leading_terms: order = Order(term, x) if not min or order not in min: min = order new_expr = term elif min in order: new_expr += term except TypeError: return expr is_zero = new_expr.is_zero if is_zero is None: new_expr = new_expr.trigsimp().cancel() is_zero = new_expr.is_zero if is_zero is True: # simple leading term analysis gave us cancelled terms but we have to send # back a term, so compute the leading term (via series) n0 = min.getn() res = Order(1) incr = S.One while res.is_Order: res = old._eval_nseries(x, n=n0+incr, logx=None, cdir=cdir).cancel().powsimp().trigsimp() incr *= 2 return res.as_leading_term(x, logx=logx, cdir=cdir) elif new_expr is S.NaN: return old.func._from_args(infinite) else: return new_expr def _eval_adjoint(self): return self.func(*[t.adjoint() for t in self.args]) def _eval_conjugate(self): return self.func(*[t.conjugate() for t in self.args]) def _eval_transpose(self): return self.func(*[t.transpose() for t in self.args]) def primitive(self): """ Return ``(R, self/R)`` where ``R``` is the Rational GCD of ``self```. ``R`` is collected only from the leading coefficient of each term. Examples ======== >>> from sympy.abc import x, y >>> (2*x + 4*y).primitive() (2, x + 2*y) >>> (2*x/3 + 4*y/9).primitive() (2/9, 3*x + 2*y) >>> (2*x/3 + 4.2*y).primitive() (1/3, 2*x + 12.6*y) No subprocessing of term factors is performed: >>> ((2 + 2*x)*x + 2).primitive() (1, x*(2*x + 2) + 2) Recursive processing can be done with the ``as_content_primitive()`` method: >>> ((2 + 2*x)*x + 2).as_content_primitive() (2, x*(x + 1) + 1) See also: primitive() function in polytools.py """ terms = [] inf = False for a in self.args: c, m = a.as_coeff_Mul() if not c.is_Rational: c = S.One m = a inf = inf or m is S.ComplexInfinity terms.append((c.p, c.q, m)) if not inf: ngcd = reduce(igcd, [t[0] for t in terms], 0) dlcm = reduce(ilcm, [t[1] for t in terms], 1) else: ngcd = reduce(igcd, [t[0] for t in terms if t[1]], 0) dlcm = reduce(ilcm, [t[1] for t in terms if t[1]], 1) if ngcd == dlcm == 1: return S.One, self if not inf: for i, (p, q, term) in enumerate(terms): terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term) else: for i, (p, q, term) in enumerate(terms): if q: terms[i] = _keep_coeff(Rational((p//ngcd)*(dlcm//q)), term) else: terms[i] = _keep_coeff(Rational(p, q), term) # we don't need a complete re-flattening since no new terms will join # so we just use the same sort as is used in Add.flatten. When the # coefficient changes, the ordering of terms may change, e.g. # (3*x, 6*y) -> (2*y, x) # # We do need to make sure that term[0] stays in position 0, however. # if terms[0].is_Number or terms[0] is S.ComplexInfinity: c = terms.pop(0) else: c = None _addsort(terms) if c: terms.insert(0, c) return Rational(ngcd, dlcm), self._new_rawargs(*terms) def as_content_primitive(self, radical=False, clear=True): """Return the tuple (R, self/R) where R is the positive Rational extracted from self. If radical is True (default is False) then common radicals will be removed and included as a factor of the primitive expression. Examples ======== >>> from sympy import sqrt >>> (3 + 3*sqrt(2)).as_content_primitive() (3, 1 + sqrt(2)) Radical content can also be factored out of the primitive: >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True) (2, sqrt(2)*(1 + 2*sqrt(5))) See docstring of Expr.as_content_primitive for more examples. """ con, prim = self.func(*[_keep_coeff(*a.as_content_primitive( radical=radical, clear=clear)) for a in self.args]).primitive() if not clear and not con.is_Integer and prim.is_Add: con, d = con.as_numer_denom() _p = prim/d if any(a.as_coeff_Mul()[0].is_Integer for a in _p.args): prim = _p else: con /= d if radical and prim.is_Add: # look for common radicals that can be removed args = prim.args rads = [] common_q = None for m in args: term_rads = defaultdict(list) for ai in Mul.make_args(m): if ai.is_Pow: b, e = ai.as_base_exp() if e.is_Rational and b.is_Integer: term_rads[e.q].append(abs(int(b))**e.p) if not term_rads: break if common_q is None: common_q = set(term_rads.keys()) else: common_q = common_q & set(term_rads.keys()) if not common_q: break rads.append(term_rads) else: # process rads # keep only those in common_q for r in rads: for q in list(r.keys()): if q not in common_q: r.pop(q) for q in r: r[q] = prod(r[q]) # find the gcd of bases for each q G = [] for q in common_q: g = reduce(igcd, [r[q] for r in rads], 0) if g != 1: G.append(g**Rational(1, q)) if G: G = Mul(*G) args = [ai/G for ai in args] prim = G*prim.func(*args) return con, prim @property def _sorted_args(self): from sympy.core.compatibility import default_sort_key return tuple(sorted(self.args, key=default_sort_key)) def _eval_difference_delta(self, n, step): from sympy.series.limitseq import difference_delta as dd return self.func(*[dd(a, n, step) for a in self.args]) @property def _mpc_(self): """ Convert self to an mpmath mpc if possible """ from sympy.core.numbers import I, Float re_part, rest = self.as_coeff_Add() im_part, imag_unit = rest.as_coeff_Mul() if not imag_unit == I: # ValueError may seem more reasonable but since it's a @property, # we need to use AttributeError to keep from confusing things like # hasattr. raise AttributeError("Cannot convert Add to mpc. Must be of the form Number + Number*I") return (Float(re_part)._mpf_, Float(im_part)._mpf_) def __neg__(self): if not global_parameters.distribute: return super().__neg__() return Add(*[-i for i in self.args]) add = AssocOpDispatcher('add') from .mul import Mul, _keep_coeff, prod from sympy.core.numbers import Rational sympy-sympy-1.9/sympy/core/alphabets.py000066400000000000000000000004121412543434000203460ustar00rootroot00000000000000greeks = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota', 'kappa', 'lambda', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi', 'omega') sympy-sympy-1.9/sympy/core/assumptions.py000066400000000000000000000426441412543434000210050ustar00rootroot00000000000000""" This module contains the machinery handling assumptions. All symbolic objects have assumption attributes that can be accessed via .is_ attribute. Assumptions determine certain properties of symbolic objects and can have 3 possible values: True, False, None. True is returned if the object has the property and False is returned if it doesn't or can't (i.e. doesn't make sense): >>> from sympy import I >>> I.is_algebraic True >>> I.is_real False >>> I.is_prime False When the property cannot be determined (or when a method is not implemented) None will be returned, e.g. a generic symbol, x, may or may not be positive so a value of None is returned for x.is_positive. By default, all symbolic values are in the largest set in the given context without specifying the property. For example, a symbol that has a property being integer, is also real, complex, etc. Here follows a list of possible assumption names: .. glossary:: commutative object commutes with any other object with respect to multiplication operation. complex object can have only values from the set of complex numbers. imaginary object value is a number that can be written as a real number multiplied by the imaginary unit ``I``. See [3]_. Please note that ``0`` is not considered to be an imaginary number, see `issue #7649 `_. real object can have only values from the set of real numbers. integer object can have only values from the set of integers. odd even object can have only values from the set of odd (even) integers [2]_. prime object is a natural number greater than ``1`` that has no positive divisors other than ``1`` and itself. See [6]_. composite object is a positive integer that has at least one positive divisor other than ``1`` or the number itself. See [4]_. zero object has the value of ``0``. nonzero object is a real number that is not zero. rational object can have only values from the set of rationals. algebraic object can have only values from the set of algebraic numbers [11]_. transcendental object can have only values from the set of transcendental numbers [10]_. irrational object value cannot be represented exactly by Rational, see [5]_. finite infinite object absolute value is bounded (arbitrarily large). See [7]_, [8]_, [9]_. negative nonnegative object can have only negative (nonnegative) values [1]_. positive nonpositive object can have only positive (only nonpositive) values. hermitian antihermitian object belongs to the field of hermitian (antihermitian) operators. Examples ======== >>> from sympy import Symbol >>> x = Symbol('x', real=True); x x >>> x.is_real True >>> x.is_complex True See Also ======== .. seealso:: :py:class:`sympy.core.numbers.ImaginaryUnit` :py:class:`sympy.core.numbers.Zero` :py:class:`sympy.core.numbers.One` Notes ===== The fully-resolved assumptions for any SymPy expression can be obtained as follows: >>> from sympy.core.assumptions import assumptions >>> x = Symbol('x',positive=True) >>> assumptions(x + I) {'commutative': True, 'complex': True, 'composite': False, 'even': False, 'extended_negative': False, 'extended_nonnegative': False, 'extended_nonpositive': False, 'extended_nonzero': False, 'extended_positive': False, 'extended_real': False, 'finite': True, 'imaginary': False, 'infinite': False, 'integer': False, 'irrational': False, 'negative': False, 'noninteger': False, 'nonnegative': False, 'nonpositive': False, 'nonzero': False, 'odd': False, 'positive': False, 'prime': False, 'rational': False, 'real': False, 'zero': False} Developers Notes ================ The current (and possibly incomplete) values are stored in the ``obj._assumptions dictionary``; queries to getter methods (with property decorators) or attributes of objects/classes will return values and update the dictionary. >>> eq = x**2 + I >>> eq._assumptions {} >>> eq.is_finite True >>> eq._assumptions {'finite': True, 'infinite': False} For a Symbol, there are two locations for assumptions that may be of interest. The ``assumptions0`` attribute gives the full set of assumptions derived from a given set of initial assumptions. The latter assumptions are stored as ``Symbol._assumptions.generator`` >>> Symbol('x', prime=True, even=True)._assumptions.generator {'even': True, 'prime': True} The ``generator`` is not necessarily canonical nor is it filtered in any way: it records the assumptions used to instantiate a Symbol and (for storage purposes) represents a more compact representation of the assumptions needed to recreate the full set in `Symbol.assumptions0`. References ========== .. [1] https://en.wikipedia.org/wiki/Negative_number .. [2] https://en.wikipedia.org/wiki/Parity_%28mathematics%29 .. [3] https://en.wikipedia.org/wiki/Imaginary_number .. [4] https://en.wikipedia.org/wiki/Composite_number .. [5] https://en.wikipedia.org/wiki/Irrational_number .. [6] https://en.wikipedia.org/wiki/Prime_number .. [7] https://en.wikipedia.org/wiki/Finite .. [8] https://docs.python.org/3/library/math.html#math.isfinite .. [9] http://docs.scipy.org/doc/numpy/reference/generated/numpy.isfinite.html .. [10] https://en.wikipedia.org/wiki/Transcendental_number .. [11] https://en.wikipedia.org/wiki/Algebraic_number """ from sympy.core.facts import FactRules, FactKB from sympy.core.core import BasicMeta from sympy.core.sympify import sympify from random import shuffle _assume_rules = FactRules([ 'integer -> rational', 'rational -> real', 'rational -> algebraic', 'algebraic -> complex', 'transcendental == complex & !algebraic', 'real -> hermitian', 'imaginary -> complex', 'imaginary -> antihermitian', 'extended_real -> commutative', 'complex -> commutative', 'complex -> finite', 'odd == integer & !even', 'even == integer & !odd', 'real -> complex', 'extended_real -> real | infinite', 'real == extended_real & finite', 'extended_real == extended_negative | zero | extended_positive', 'extended_negative == extended_nonpositive & extended_nonzero', 'extended_positive == extended_nonnegative & extended_nonzero', 'extended_nonpositive == extended_real & !extended_positive', 'extended_nonnegative == extended_real & !extended_negative', 'real == negative | zero | positive', 'negative == nonpositive & nonzero', 'positive == nonnegative & nonzero', 'nonpositive == real & !positive', 'nonnegative == real & !negative', 'positive == extended_positive & finite', 'negative == extended_negative & finite', 'nonpositive == extended_nonpositive & finite', 'nonnegative == extended_nonnegative & finite', 'nonzero == extended_nonzero & finite', 'zero -> even & finite', 'zero == extended_nonnegative & extended_nonpositive', 'zero == nonnegative & nonpositive', 'nonzero -> real', 'prime -> integer & positive', 'composite -> integer & positive & !prime', '!composite -> !positive | !even | prime', 'irrational == real & !rational', 'imaginary -> !extended_real', 'infinite == !finite', 'noninteger == extended_real & !integer', 'extended_nonzero == extended_real & !zero', ]) _assume_defined = _assume_rules.defined_facts.copy() _assume_defined.add('polar') _assume_defined = frozenset(_assume_defined) def assumptions(expr, _check=None): """return the T/F assumptions of ``expr``""" n = sympify(expr) if n.is_Symbol: rv = n.assumptions0 # are any important ones missing? if _check is not None: rv = {k: rv[k] for k in set(rv) & set(_check)} return rv rv = {} for k in _assume_defined if _check is None else _check: v = getattr(n, 'is_{}'.format(k)) if v is not None: rv[k] = v return rv def common_assumptions(exprs, check=None): """return those assumptions which have the same True or False value for all the given expressions. Examples ======== >>> from sympy.core.assumptions import common_assumptions >>> from sympy import oo, pi, sqrt >>> common_assumptions([-4, 0, sqrt(2), 2, pi, oo]) {'commutative': True, 'composite': False, 'extended_real': True, 'imaginary': False, 'odd': False} By default, all assumptions are tested; pass an iterable of the assumptions to limit those that are reported: >>> common_assumptions([0, 1, 2], ['positive', 'integer']) {'integer': True} """ check = _assume_defined if check is None else set(check) if not check or not exprs: return {} # get all assumptions for each assume = [assumptions(i, _check=check) for i in sympify(exprs)] # focus on those of interest that are True for i, e in enumerate(assume): assume[i] = {k: e[k] for k in set(e) & check} # what assumptions are in common? common = set.intersection(*[set(i) for i in assume]) # which ones hold the same value a = assume[0] return {k: a[k] for k in common if all(a[k] == b[k] for b in assume)} def failing_assumptions(expr, **assumptions): """ Return a dictionary containing assumptions with values not matching those of the passed assumptions. Examples ======== >>> from sympy import failing_assumptions, Symbol >>> x = Symbol('x', real=True, positive=True) >>> y = Symbol('y') >>> failing_assumptions(6*x + y, real=True, positive=True) {'positive': None, 'real': None} >>> failing_assumptions(x**2 - 1, positive=True) {'positive': None} If *expr* satisfies all of the assumptions, an empty dictionary is returned. >>> failing_assumptions(x**2, positive=True) {} """ expr = sympify(expr) failed = {} for k in assumptions: test = getattr(expr, 'is_%s' % k, None) if test is not assumptions[k]: failed[k] = test return failed # {} or {assumption: value != desired} def check_assumptions(expr, against=None, **assume): """ Checks whether assumptions of ``expr`` match the T/F assumptions given (or possessed by ``against``). True is returned if all assumptions match; False is returned if there is a mismatch and the assumption in ``expr`` is not None; else None is returned. Explanation =========== *assume* is a dict of assumptions with True or False values Examples ======== >>> from sympy import Symbol, pi, I, exp, check_assumptions >>> check_assumptions(-5, integer=True) True >>> check_assumptions(pi, real=True, integer=False) True >>> check_assumptions(pi, real=True, negative=True) False >>> check_assumptions(exp(I*pi/7), real=False) True >>> x = Symbol('x', real=True, positive=True) >>> check_assumptions(2*x + 1, real=True, positive=True) True >>> check_assumptions(-2*x - 5, real=True, positive=True) False To check assumptions of *expr* against another variable or expression, pass the expression or variable as ``against``. >>> check_assumptions(2*x + 1, x) True To see if a number matches the assumptions of an expression, pass the number as the first argument, else its specific assumptions may not have a non-None value in the expression: >>> check_assumptions(x, 3) >>> check_assumptions(3, x) True ``None`` is returned if ``check_assumptions()`` could not conclude. >>> check_assumptions(2*x - 1, x) >>> z = Symbol('z') >>> check_assumptions(z, real=True) See Also ======== failing_assumptions """ expr = sympify(expr) if against is not None: if assume: raise ValueError( 'Expecting `against` or `assume`, not both.') assume = assumptions(against) known = True for k, v in assume.items(): if v is None: continue e = getattr(expr, 'is_' + k, None) if e is None: known = None elif v != e: return False return known class StdFactKB(FactKB): """A FactKB specialized for the built-in rules This is the only kind of FactKB that Basic objects should use. """ def __init__(self, facts=None): super().__init__(_assume_rules) # save a copy of the facts dict if not facts: self._generator = {} elif not isinstance(facts, FactKB): self._generator = facts.copy() else: self._generator = facts.generator if facts: self.deduce_all_facts(facts) def copy(self): return self.__class__(self) @property def generator(self): return self._generator.copy() def as_property(fact): """Convert a fact name to the name of the corresponding property""" return 'is_%s' % fact def make_property(fact): """Create the automagic property corresponding to a fact.""" def getit(self): try: return self._assumptions[fact] except KeyError: if self._assumptions is self.default_assumptions: self._assumptions = self.default_assumptions.copy() return _ask(fact, self) getit.func_name = as_property(fact) return property(getit) def _ask(fact, obj): """ Find the truth value for a property of an object. This function is called when a request is made to see what a fact value is. For this we use several techniques: First, the fact-evaluation function is tried, if it exists (for example _eval_is_integer). Then we try related facts. For example rational --> integer another example is joined rule: integer & !odd --> even so in the latter case if we are looking at what 'even' value is, 'integer' and 'odd' facts will be asked. In all cases, when we settle on some fact value, its implications are deduced, and the result is cached in ._assumptions. """ assumptions = obj._assumptions handler_map = obj._prop_handler # Store None into the assumptions so that recursive attempts at # evaluating the same fact don't trigger infinite recursion. assumptions._tell(fact, None) # First try the assumption evaluation function if it exists try: evaluate = handler_map[fact] except KeyError: pass else: a = evaluate(obj) if a is not None: assumptions.deduce_all_facts(((fact, a),)) return a # Try assumption's prerequisites prereq = list(_assume_rules.prereq[fact]) shuffle(prereq) for pk in prereq: if pk in assumptions: continue if pk in handler_map: _ask(pk, obj) # we might have found the value of fact ret_val = assumptions.get(fact) if ret_val is not None: return ret_val # Note: the result has already been cached return None class ManagedProperties(BasicMeta): """Metaclass for classes with old-style assumptions""" def __init__(cls, *args, **kws): BasicMeta.__init__(cls, *args, **kws) local_defs = {} for k in _assume_defined: attrname = as_property(k) v = cls.__dict__.get(attrname, '') if isinstance(v, (bool, int, type(None))): if v is not None: v = bool(v) local_defs[k] = v defs = {} for base in reversed(cls.__bases__): assumptions = getattr(base, '_explicit_class_assumptions', None) if assumptions is not None: defs.update(assumptions) defs.update(local_defs) cls._explicit_class_assumptions = defs cls.default_assumptions = StdFactKB(defs) cls._prop_handler = {} for k in _assume_defined: eval_is_meth = getattr(cls, '_eval_is_%s' % k, None) if eval_is_meth is not None: cls._prop_handler[k] = eval_is_meth # Put definite results directly into the class dict, for speed for k, v in cls.default_assumptions.items(): setattr(cls, as_property(k), v) # protection e.g. for Integer.is_even=F <- (Rational.is_integer=F) derived_from_bases = set() for base in cls.__bases__: default_assumptions = getattr(base, 'default_assumptions', None) # is an assumption-aware class if default_assumptions is not None: derived_from_bases.update(default_assumptions) for fact in derived_from_bases - set(cls.default_assumptions): pname = as_property(fact) if pname not in cls.__dict__: setattr(cls, pname, make_property(fact)) # Finally, add any missing automagic property (e.g. for Basic) for fact in _assume_defined: pname = as_property(fact) if not hasattr(cls, pname): setattr(cls, pname, make_property(fact)) sympy-sympy-1.9/sympy/core/backend.py000066400000000000000000000062171412543434000200030ustar00rootroot00000000000000import os USE_SYMENGINE = os.getenv('USE_SYMENGINE', '0') USE_SYMENGINE = USE_SYMENGINE.lower() in ('1', 't', 'true') # type: ignore if USE_SYMENGINE: from symengine import (Symbol, Integer, sympify, S, SympifyError, exp, log, gamma, sqrt, I, E, pi, Matrix, sin, cos, tan, cot, csc, sec, asin, acos, atan, acot, acsc, asec, sinh, cosh, tanh, coth, asinh, acosh, atanh, acoth, lambdify, symarray, diff, zeros, eye, diag, ones, expand, Function, symbols, var, Add, Mul, Derivative, ImmutableMatrix, MatrixBase, Rational, Basic) from symengine.lib.symengine_wrapper import gcd as igcd from symengine import AppliedUndef else: from sympy import (Symbol, Integer, sympify, S, SympifyError, exp, log, gamma, sqrt, I, E, pi, Matrix, sin, cos, tan, cot, csc, sec, asin, acos, atan, acot, acsc, asec, sinh, cosh, tanh, coth, asinh, acosh, atanh, acoth, lambdify, symarray, diff, zeros, eye, diag, ones, expand, Function, symbols, var, Add, Mul, Derivative, ImmutableMatrix, MatrixBase, Rational, Basic, igcd) from sympy.core.function import AppliedUndef # # XXX: Handling of immutable and mutable matrices in SymEngine is inconsistent # with SymPy's matrix classes in at least SymEngine version 0.7.0. Until that # is fixed the function below is needed for consistent behaviour when # attempting to simplify a matrix. # # Expected behaviour of a SymPy mutable/immutable matrix .simplify() method: # # Matrix.simplify() : works in place, returns None # ImmutableMatrix.simplify() : returns a simplified copy # # In SymEngine both mutable and immutable matrices simplify in place and return # None. This is inconsistent with the matrix being "immutable" and also the # returned None leads to problems in the mechanics module. # # The simplify function should not be used because simplify(M) sympifies the # matrix M and the SymEngine matrices all sympify to SymPy matrices. If we want # to work with SymEngine matrices then we need to use their .simplify() method # but that method does not work correctly with immutable matrices. # # The _simplify_matrix function can be removed when the SymEngine bug is fixed. # Since this should be a temporary problem we do not make this function part of # the public API. # # SymEngine issue: https://github.com/symengine/symengine.py/issues/363 # def _simplify_matrix(M): """Return a simplified copy of the matrix M""" assert isinstance(M, (Matrix, ImmutableMatrix)) Mnew = M.as_mutable() # makes a copy if mutable Mnew.simplify() if isinstance(M, ImmutableMatrix): Mnew = Mnew.as_immutable() return Mnew __all__ = [ 'Symbol', 'Integer', 'sympify', 'S', 'SympifyError', 'exp', 'log', 'gamma', 'sqrt', 'I', 'E', 'pi', 'Matrix', 'sin', 'cos', 'tan', 'cot', 'csc', 'sec', 'asin', 'acos', 'atan', 'acot', 'acsc', 'asec', 'sinh', 'cosh', 'tanh', 'coth', 'asinh', 'acosh', 'atanh', 'acoth', 'lambdify', 'symarray', 'diff', 'zeros', 'eye', 'diag', 'ones', 'expand', 'Function', 'symbols', 'var', 'Add', 'Mul', 'Derivative', 'ImmutableMatrix', 'MatrixBase', 'Rational', 'Basic', 'igcd', 'AppliedUndef', ] sympy-sympy-1.9/sympy/core/basic.py000066400000000000000000002070311412543434000174720ustar00rootroot00000000000000"""Base class for all the objects in SymPy""" from collections import defaultdict from collections.abc import Mapping from itertools import chain, zip_longest from .assumptions import BasicMeta, ManagedProperties from .cache import cacheit from .sympify import _sympify, sympify, SympifyError from .compatibility import iterable, ordered from .kind import UndefinedKind from ._print_helpers import Printable from inspect import getmro def as_Basic(expr): """Return expr as a Basic instance using strict sympify or raise a TypeError; this is just a wrapper to _sympify, raising a TypeError instead of a SympifyError.""" from sympy.utilities.misc import func_name try: return _sympify(expr) except SympifyError: raise TypeError( 'Argument must be a Basic object, not `%s`' % func_name( expr)) class Basic(Printable, metaclass=ManagedProperties): """ Base class for all SymPy objects. Notes and conventions ===================== 1) Always use ``.args``, when accessing parameters of some instance: >>> from sympy import cot >>> from sympy.abc import x, y >>> cot(x).args (x,) >>> cot(x).args[0] x >>> (x*y).args (x, y) >>> (x*y).args[1] y 2) Never use internal methods or variables (the ones prefixed with ``_``): >>> cot(x)._args # do not use this, use cot(x).args instead (x,) 3) By "SymPy object" we mean something that can be returned by ``sympify``. But not all objects one encounters using SymPy are subclasses of Basic. For example, mutable objects are not: >>> from sympy import Basic, Matrix, sympify >>> A = Matrix([[1, 2], [3, 4]]).as_mutable() >>> isinstance(A, Basic) False >>> B = sympify(A) >>> isinstance(B, Basic) True """ __slots__ = ('_mhash', # hash value '_args', # arguments '_assumptions' ) # To be overridden with True in the appropriate subclasses is_number = False is_Atom = False is_Symbol = False is_symbol = False is_Indexed = False is_Dummy = False is_Wild = False is_Function = False is_Add = False is_Mul = False is_Pow = False is_Number = False is_Float = False is_Rational = False is_Integer = False is_NumberSymbol = False is_Order = False is_Derivative = False is_Piecewise = False is_Poly = False is_AlgebraicNumber = False is_Relational = False is_Equality = False is_Boolean = False is_Not = False is_Matrix = False is_Vector = False is_Point = False is_MatAdd = False is_MatMul = False kind = UndefinedKind def __new__(cls, *args): obj = object.__new__(cls) obj._assumptions = cls.default_assumptions obj._mhash = None # will be set by __hash__ method. obj._args = args # all items in args must be Basic objects return obj def copy(self): return self.func(*self.args) def __getnewargs__(self): return self.args def __getstate__(self): return None def __reduce_ex__(self, protocol): if protocol < 2: msg = "Only pickle protocol 2 or higher is supported by sympy" raise NotImplementedError(msg) return super().__reduce_ex__(protocol) def __hash__(self): # hash cannot be cached using cache_it because infinite recurrence # occurs as hash is needed for setting cache dictionary keys h = self._mhash if h is None: h = hash((type(self).__name__,) + self._hashable_content()) self._mhash = h return h def _hashable_content(self): """Return a tuple of information about self that can be used to compute the hash. If a class defines additional attributes, like ``name`` in Symbol, then this method should be updated accordingly to return such relevant attributes. Defining more than _hashable_content is necessary if __eq__ has been defined by a class. See note about this in Basic.__eq__.""" return self._args @property def assumptions0(self): """ Return object `type` assumptions. For example: Symbol('x', real=True) Symbol('x', integer=True) are different objects. In other words, besides Python type (Symbol in this case), the initial assumptions are also forming their typeinfo. Examples ======== >>> from sympy import Symbol >>> from sympy.abc import x >>> x.assumptions0 {'commutative': True} >>> x = Symbol("x", positive=True) >>> x.assumptions0 {'commutative': True, 'complex': True, 'extended_negative': False, 'extended_nonnegative': True, 'extended_nonpositive': False, 'extended_nonzero': True, 'extended_positive': True, 'extended_real': True, 'finite': True, 'hermitian': True, 'imaginary': False, 'infinite': False, 'negative': False, 'nonnegative': True, 'nonpositive': False, 'nonzero': True, 'positive': True, 'real': True, 'zero': False} """ return {} def compare(self, other): """ Return -1, 0, 1 if the object is smaller, equal, or greater than other. Not in the mathematical sense. If the object is of a different type from the "other" then their classes are ordered according to the sorted_classes list. Examples ======== >>> from sympy.abc import x, y >>> x.compare(y) -1 >>> x.compare(x) 0 >>> y.compare(x) 1 """ # all redefinitions of __cmp__ method should start with the # following lines: if self is other: return 0 n1 = self.__class__ n2 = other.__class__ c = (n1 > n2) - (n1 < n2) if c: return c # st = self._hashable_content() ot = other._hashable_content() c = (len(st) > len(ot)) - (len(st) < len(ot)) if c: return c for l, r in zip(st, ot): l = Basic(*l) if isinstance(l, frozenset) else l r = Basic(*r) if isinstance(r, frozenset) else r if isinstance(l, Basic): c = l.compare(r) else: c = (l > r) - (l < r) if c: return c return 0 @staticmethod def _compare_pretty(a, b): from sympy.series.order import Order if isinstance(a, Order) and not isinstance(b, Order): return 1 if not isinstance(a, Order) and isinstance(b, Order): return -1 if a.is_Rational and b.is_Rational: l = a.p * b.q r = b.p * a.q return (l > r) - (l < r) else: from sympy.core.symbol import Wild p1, p2, p3 = Wild("p1"), Wild("p2"), Wild("p3") r_a = a.match(p1 * p2**p3) if r_a and p3 in r_a: a3 = r_a[p3] r_b = b.match(p1 * p2**p3) if r_b and p3 in r_b: b3 = r_b[p3] c = Basic.compare(a3, b3) if c != 0: return c return Basic.compare(a, b) @classmethod def fromiter(cls, args, **assumptions): """ Create a new object from an iterable. This is a convenience function that allows one to create objects from any iterable, without having to convert to a list or tuple first. Examples ======== >>> from sympy import Tuple >>> Tuple.fromiter(i for i in range(5)) (0, 1, 2, 3, 4) """ return cls(*tuple(args), **assumptions) @classmethod def class_key(cls): """Nice order of classes. """ return 5, 0, cls.__name__ @cacheit def sort_key(self, order=None): """ Return a sort key. Examples ======== >>> from sympy.core import S, I >>> sorted([S(1)/2, I, -I], key=lambda x: x.sort_key()) [1/2, -I, I] >>> S("[x, 1/x, 1/x**2, x**2, x**(1/2), x**(1/4), x**(3/2)]") [x, 1/x, x**(-2), x**2, sqrt(x), x**(1/4), x**(3/2)] >>> sorted(_, key=lambda x: x.sort_key()) [x**(-2), 1/x, x**(1/4), sqrt(x), x, x**(3/2), x**2] """ # XXX: remove this when issue 5169 is fixed def inner_key(arg): if isinstance(arg, Basic): return arg.sort_key(order) else: return arg args = self._sorted_args args = len(args), tuple([inner_key(arg) for arg in args]) return self.class_key(), args, S.One.sort_key(), S.One def __eq__(self, other): """Return a boolean indicating whether a == b on the basis of their symbolic trees. This is the same as a.compare(b) == 0 but faster. Notes ===== If a class that overrides __eq__() needs to retain the implementation of __hash__() from a parent class, the interpreter must be told this explicitly by setting __hash__ = .__hash__. Otherwise the inheritance of __hash__() will be blocked, just as if __hash__ had been explicitly set to None. References ========== from http://docs.python.org/dev/reference/datamodel.html#object.__hash__ """ if self is other: return True tself = type(self) tother = type(other) if tself is not tother: try: other = _sympify(other) tother = type(other) except SympifyError: return NotImplemented # As long as we have the ordering of classes (sympy.core), # comparing types will be slow in Python 2, because it uses # __cmp__. Until we can remove it # (https://github.com/sympy/sympy/issues/4269), we only compare # types in Python 2 directly if they actually have __ne__. if type(tself).__ne__ is not type.__ne__: if tself != tother: return False elif tself is not tother: return False return self._hashable_content() == other._hashable_content() def __ne__(self, other): """``a != b`` -> Compare two symbolic trees and see whether they are different this is the same as: ``a.compare(b) != 0`` but faster """ return not self == other def dummy_eq(self, other, symbol=None): """ Compare two expressions and handle dummy symbols. Examples ======== >>> from sympy import Dummy >>> from sympy.abc import x, y >>> u = Dummy('u') >>> (u**2 + 1).dummy_eq(x**2 + 1) True >>> (u**2 + 1) == (x**2 + 1) False >>> (u**2 + y).dummy_eq(x**2 + y, x) True >>> (u**2 + y).dummy_eq(x**2 + y, y) False """ s = self.as_dummy() o = _sympify(other) o = o.as_dummy() dummy_symbols = [i for i in s.free_symbols if i.is_Dummy] if len(dummy_symbols) == 1: dummy = dummy_symbols.pop() else: return s == o if symbol is None: symbols = o.free_symbols if len(symbols) == 1: symbol = symbols.pop() else: return s == o tmp = dummy.__class__() return s.xreplace({dummy: tmp}) == o.xreplace({symbol: tmp}) def atoms(self, *types): """Returns the atoms that form the current object. By default, only objects that are truly atomic and can't be divided into smaller pieces are returned: symbols, numbers, and number symbols like I and pi. It is possible to request atoms of any type, however, as demonstrated below. Examples ======== >>> from sympy import I, pi, sin >>> from sympy.abc import x, y >>> (1 + x + 2*sin(y + I*pi)).atoms() {1, 2, I, pi, x, y} If one or more types are given, the results will contain only those types of atoms. >>> from sympy import Number, NumberSymbol, Symbol >>> (1 + x + 2*sin(y + I*pi)).atoms(Symbol) {x, y} >>> (1 + x + 2*sin(y + I*pi)).atoms(Number) {1, 2} >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol) {1, 2, pi} >>> (1 + x + 2*sin(y + I*pi)).atoms(Number, NumberSymbol, I) {1, 2, I, pi} Note that I (imaginary unit) and zoo (complex infinity) are special types of number symbols and are not part of the NumberSymbol class. The type can be given implicitly, too: >>> (1 + x + 2*sin(y + I*pi)).atoms(x) # x is a Symbol {x, y} Be careful to check your assumptions when using the implicit option since ``S(1).is_Integer = True`` but ``type(S(1))`` is ``One``, a special type of sympy atom, while ``type(S(2))`` is type ``Integer`` and will find all integers in an expression: >>> from sympy import S >>> (1 + x + 2*sin(y + I*pi)).atoms(S(1)) {1} >>> (1 + x + 2*sin(y + I*pi)).atoms(S(2)) {1, 2} Finally, arguments to atoms() can select more than atomic atoms: any sympy type (loaded in core/__init__.py) can be listed as an argument and those types of "atoms" as found in scanning the arguments of the expression recursively: >>> from sympy import Function, Mul >>> from sympy.core.function import AppliedUndef >>> f = Function('f') >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(Function) {f(x), sin(y + I*pi)} >>> (1 + f(x) + 2*sin(y + I*pi)).atoms(AppliedUndef) {f(x)} >>> (1 + x + 2*sin(y + I*pi)).atoms(Mul) {I*pi, 2*sin(y + I*pi)} """ if types: types = tuple( [t if isinstance(t, type) else type(t) for t in types]) nodes = preorder_traversal(self) if types: result = {node for node in nodes if isinstance(node, types)} else: result = {node for node in nodes if not node.args} return result @property def free_symbols(self): """Return from the atoms of self those which are free symbols. For most expressions, all symbols are free symbols. For some classes this is not true. e.g. Integrals use Symbols for the dummy variables which are bound variables, so Integral has a method to return all symbols except those. Derivative keeps track of symbols with respect to which it will perform a derivative; those are bound variables, too, so it has its own free_symbols method. Any other method that uses bound variables should implement a free_symbols method.""" return set().union(*[a.free_symbols for a in self.args]) @property def expr_free_symbols(self): from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning(feature="expr_free_symbols method", issue=21494, deprecated_since_version="1.9").warn() return set() def as_dummy(self): """Return the expression with any objects having structurally bound symbols replaced with unique, canonical symbols within the object in which they appear and having only the default assumption for commutativity being True. When applied to a symbol a new symbol having only the same commutativity will be returned. Examples ======== >>> from sympy import Integral, Symbol >>> from sympy.abc import x >>> r = Symbol('r', real=True) >>> Integral(r, (r, x)).as_dummy() Integral(_0, (_0, x)) >>> _.variables[0].is_real is None True >>> r.as_dummy() _r Notes ===== Any object that has structurally bound variables should have a property, `bound_symbols` that returns those symbols appearing in the object. """ from sympy.core.symbol import Dummy, Symbol def can(x): # mask free that shadow bound free = x.free_symbols bound = set(x.bound_symbols) d = {i: Dummy() for i in bound & free} x = x.subs(d) # replace bound with canonical names x = x.xreplace(x.canonical_variables) # return after undoing masking return x.xreplace({v: k for k, v in d.items()}) if not self.has(Symbol): return self return self.replace( lambda x: hasattr(x, 'bound_symbols'), lambda x: can(x), simultaneous=False) @property def canonical_variables(self): """Return a dictionary mapping any variable defined in ``self.bound_symbols`` to Symbols that do not clash with any free symbols in the expression. Examples ======== >>> from sympy import Lambda >>> from sympy.abc import x >>> Lambda(x, 2*x).canonical_variables {x: _0} """ from sympy.utilities.iterables import numbered_symbols if not hasattr(self, 'bound_symbols'): return {} dums = numbered_symbols('_') reps = {} # watch out for free symbol that are not in bound symbols; # those that are in bound symbols are about to get changed bound = self.bound_symbols names = {i.name for i in self.free_symbols - set(bound)} for b in bound: d = next(dums) if b.is_Symbol: while d.name in names: d = next(dums) reps[b] = d return reps def rcall(self, *args): """Apply on the argument recursively through the expression tree. This method is used to simulate a common abuse of notation for operators. For instance in SymPy the the following will not work: ``(x+Lambda(y, 2*y))(z) == x+2*z``, however you can use >>> from sympy import Lambda >>> from sympy.abc import x, y, z >>> (x + Lambda(y, 2*y)).rcall(z) x + 2*z """ return Basic._recursive_call(self, args) @staticmethod def _recursive_call(expr_to_call, on_args): """Helper for rcall method.""" from sympy import Symbol def the_call_method_is_overridden(expr): for cls in getmro(type(expr)): if '__call__' in cls.__dict__: return cls != Basic if callable(expr_to_call) and the_call_method_is_overridden(expr_to_call): if isinstance(expr_to_call, Symbol): # XXX When you call a Symbol it is return expr_to_call # transformed into an UndefFunction else: return expr_to_call(*on_args) elif expr_to_call.args: args = [Basic._recursive_call( sub, on_args) for sub in expr_to_call.args] return type(expr_to_call)(*args) else: return expr_to_call def is_hypergeometric(self, k): from sympy.simplify import hypersimp from sympy.functions import Piecewise if self.has(Piecewise): return None return hypersimp(self, k) is not None @property def is_comparable(self): """Return True if self can be computed to a real number (or already is a real number) with precision, else False. Examples ======== >>> from sympy import exp_polar, pi, I >>> (I*exp_polar(I*pi/2)).is_comparable True >>> (I*exp_polar(I*pi*2)).is_comparable False A False result does not mean that `self` cannot be rewritten into a form that would be comparable. For example, the difference computed below is zero but without simplification it does not evaluate to a zero with precision: >>> e = 2**pi*(1 + 2**pi) >>> dif = e - e.expand() >>> dif.is_comparable False >>> dif.n(2)._prec 1 """ is_extended_real = self.is_extended_real if is_extended_real is False: return False if not self.is_number: return False # don't re-eval numbers that are already evaluated since # this will create spurious precision n, i = [p.evalf(2) if not p.is_Number else p for p in self.as_real_imag()] if not (i.is_Number and n.is_Number): return False if i: # if _prec = 1 we can't decide and if not, # the answer is False because numbers with # imaginary parts can't be compared # so return False return False else: return n._prec != 1 @property def func(self): """ The top-level function in an expression. The following should hold for all objects:: >> x == x.func(*x.args) Examples ======== >>> from sympy.abc import x >>> a = 2*x >>> a.func >>> a.args (2, x) >>> a.func(*a.args) 2*x >>> a == a.func(*a.args) True """ return self.__class__ @property def args(self): """Returns a tuple of arguments of 'self'. Examples ======== >>> from sympy import cot >>> from sympy.abc import x, y >>> cot(x).args (x,) >>> cot(x).args[0] x >>> (x*y).args (x, y) >>> (x*y).args[1] y Notes ===== Never use self._args, always use self.args. Only use _args in __new__ when creating a new function. Don't override .args() from Basic (so that it's easy to change the interface in the future if needed). """ return self._args @property def _sorted_args(self): """ The same as ``args``. Derived classes which don't fix an order on their arguments should override this method to produce the sorted representation. """ return self.args def as_content_primitive(self, radical=False, clear=True): """A stub to allow Basic args (like Tuple) to be skipped when computing the content and primitive components of an expression. See Also ======== sympy.core.expr.Expr.as_content_primitive """ return S.One, self def subs(self, *args, **kwargs): """ Substitutes old for new in an expression after sympifying args. `args` is either: - two arguments, e.g. foo.subs(old, new) - one iterable argument, e.g. foo.subs(iterable). The iterable may be o an iterable container with (old, new) pairs. In this case the replacements are processed in the order given with successive patterns possibly affecting replacements already made. o a dict or set whose key/value items correspond to old/new pairs. In this case the old/new pairs will be sorted by op count and in case of a tie, by number of args and the default_sort_key. The resulting sorted list is then processed as an iterable container (see previous). If the keyword ``simultaneous`` is True, the subexpressions will not be evaluated until all the substitutions have been made. Examples ======== >>> from sympy import pi, exp, limit, oo >>> from sympy.abc import x, y >>> (1 + x*y).subs(x, pi) pi*y + 1 >>> (1 + x*y).subs({x:pi, y:2}) 1 + 2*pi >>> (1 + x*y).subs([(x, pi), (y, 2)]) 1 + 2*pi >>> reps = [(y, x**2), (x, 2)] >>> (x + y).subs(reps) 6 >>> (x + y).subs(reversed(reps)) x**2 + 2 >>> (x**2 + x**4).subs(x**2, y) y**2 + y To replace only the x**2 but not the x**4, use xreplace: >>> (x**2 + x**4).xreplace({x**2: y}) x**4 + y To delay evaluation until all substitutions have been made, set the keyword ``simultaneous`` to True: >>> (x/y).subs([(x, 0), (y, 0)]) 0 >>> (x/y).subs([(x, 0), (y, 0)], simultaneous=True) nan This has the added feature of not allowing subsequent substitutions to affect those already made: >>> ((x + y)/y).subs({x + y: y, y: x + y}) 1 >>> ((x + y)/y).subs({x + y: y, y: x + y}, simultaneous=True) y/(x + y) In order to obtain a canonical result, unordered iterables are sorted by count_op length, number of arguments and by the default_sort_key to break any ties. All other iterables are left unsorted. >>> from sympy import sqrt, sin, cos >>> from sympy.abc import a, b, c, d, e >>> A = (sqrt(sin(2*x)), a) >>> B = (sin(2*x), b) >>> C = (cos(2*x), c) >>> D = (x, d) >>> E = (exp(x), e) >>> expr = sqrt(sin(2*x))*sin(exp(x)*x)*cos(2*x) + sin(2*x) >>> expr.subs(dict([A, B, C, D, E])) a*c*sin(d*e) + b The resulting expression represents a literal replacement of the old arguments with the new arguments. This may not reflect the limiting behavior of the expression: >>> (x**3 - 3*x).subs({x: oo}) nan >>> limit(x**3 - 3*x, x, oo) oo If the substitution will be followed by numerical evaluation, it is better to pass the substitution to evalf as >>> (1/x).evalf(subs={x: 3.0}, n=21) 0.333333333333333333333 rather than >>> (1/x).subs({x: 3.0}).evalf(21) 0.333333333333333314830 as the former will ensure that the desired level of precision is obtained. See Also ======== replace: replacement capable of doing wildcard-like matching, parsing of match, and conditional replacements xreplace: exact node replacement in expr tree; also capable of using matching rules sympy.core.evalf.EvalfMixin.evalf: calculates the given formula to a desired level of precision """ from sympy.core.compatibility import _nodes, default_sort_key from sympy.core.containers import Dict from sympy.core.symbol import Dummy, Symbol from sympy.utilities.misc import filldedent unordered = False if len(args) == 1: sequence = args[0] if isinstance(sequence, set): unordered = True elif isinstance(sequence, (Dict, Mapping)): unordered = True sequence = sequence.items() elif not iterable(sequence): raise ValueError(filldedent(""" When a single argument is passed to subs it should be a dictionary of old: new pairs or an iterable of (old, new) tuples.""")) elif len(args) == 2: sequence = [args] else: raise ValueError("subs accepts either 1 or 2 arguments") sequence = list(sequence) for i, s in enumerate(sequence): if isinstance(s[0], str): # when old is a string we prefer Symbol s = Symbol(s[0]), s[1] try: s = [sympify(_, strict=not isinstance(_, (str, type))) for _ in s] except SympifyError: # if it can't be sympified, skip it sequence[i] = None continue # skip if there is no change sequence[i] = None if _aresame(*s) else tuple(s) sequence = list(filter(None, sequence)) if unordered: sequence = dict(sequence) # order so more complex items are first and items # of identical complexity are ordered so # f(x) < f(y) < x < y # \___ 2 __/ \_1_/ <- number of nodes # # For more complex ordering use an unordered sequence. k = list(ordered(sequence, default=False, keys=( lambda x: -_nodes(x), lambda x: default_sort_key(x), ))) sequence = [(k, sequence[k]) for k in k] if kwargs.pop('simultaneous', False): # XXX should this be the default for dict subs? reps = {} rv = self kwargs['hack2'] = True m = Dummy('subs_m') for old, new in sequence: com = new.is_commutative if com is None: com = True d = Dummy('subs_d', commutative=com) # using d*m so Subs will be used on dummy variables # in things like Derivative(f(x, y), x) in which x # is both free and bound rv = rv._subs(old, d*m, **kwargs) if not isinstance(rv, Basic): break reps[d] = new reps[m] = S.One # get rid of m return rv.xreplace(reps) else: rv = self for old, new in sequence: rv = rv._subs(old, new, **kwargs) if not isinstance(rv, Basic): break return rv @cacheit def _subs(self, old, new, **hints): """Substitutes an expression old -> new. If self is not equal to old then _eval_subs is called. If _eval_subs doesn't want to make any special replacement then a None is received which indicates that the fallback should be applied wherein a search for replacements is made amongst the arguments of self. >>> from sympy import Add >>> from sympy.abc import x, y, z Examples ======== Add's _eval_subs knows how to target x + y in the following so it makes the change: >>> (x + y + z).subs(x + y, 1) z + 1 Add's _eval_subs doesn't need to know how to find x + y in the following: >>> Add._eval_subs(z*(x + y) + 3, x + y, 1) is None True The returned None will cause the fallback routine to traverse the args and pass the z*(x + y) arg to Mul where the change will take place and the substitution will succeed: >>> (z*(x + y) + 3).subs(x + y, 1) z + 3 ** Developers Notes ** An _eval_subs routine for a class should be written if: 1) any arguments are not instances of Basic (e.g. bool, tuple); 2) some arguments should not be targeted (as in integration variables); 3) if there is something other than a literal replacement that should be attempted (as in Piecewise where the condition may be updated without doing a replacement). If it is overridden, here are some special cases that might arise: 1) If it turns out that no special change was made and all the original sub-arguments should be checked for replacements then None should be returned. 2) If it is necessary to do substitutions on a portion of the expression then _subs should be called. _subs will handle the case of any sub-expression being equal to old (which usually would not be the case) while its fallback will handle the recursion into the sub-arguments. For example, after Add's _eval_subs removes some matching terms it must process the remaining terms so it calls _subs on each of the un-matched terms and then adds them onto the terms previously obtained. 3) If the initial expression should remain unchanged then the original expression should be returned. (Whenever an expression is returned, modified or not, no further substitution of old -> new is attempted.) Sum's _eval_subs routine uses this strategy when a substitution is attempted on any of its summation variables. """ def fallback(self, old, new): """ Try to replace old with new in any of self's arguments. """ hit = False args = list(self.args) for i, arg in enumerate(args): if not hasattr(arg, '_eval_subs'): continue arg = arg._subs(old, new, **hints) if not _aresame(arg, args[i]): hit = True args[i] = arg if hit: rv = self.func(*args) hack2 = hints.get('hack2', False) if hack2 and self.is_Mul and not rv.is_Mul: # 2-arg hack coeff = S.One nonnumber = [] for i in args: if i.is_Number: coeff *= i else: nonnumber.append(i) nonnumber = self.func(*nonnumber) if coeff is S.One: return nonnumber else: return self.func(coeff, nonnumber, evaluate=False) return rv return self if _aresame(self, old): return new rv = self._eval_subs(old, new) if rv is None: rv = fallback(self, old, new) return rv def _eval_subs(self, old, new): """Override this stub if you want to do anything more than attempt a replacement of old with new in the arguments of self. See also ======== _subs """ return None def xreplace(self, rule): """ Replace occurrences of objects within the expression. Parameters ========== rule : dict-like Expresses a replacement rule Returns ======= xreplace : the result of the replacement Examples ======== >>> from sympy import symbols, pi, exp >>> x, y, z = symbols('x y z') >>> (1 + x*y).xreplace({x: pi}) pi*y + 1 >>> (1 + x*y).xreplace({x: pi, y: 2}) 1 + 2*pi Replacements occur only if an entire node in the expression tree is matched: >>> (x*y + z).xreplace({x*y: pi}) z + pi >>> (x*y*z).xreplace({x*y: pi}) x*y*z >>> (2*x).xreplace({2*x: y, x: z}) y >>> (2*2*x).xreplace({2*x: y, x: z}) 4*z >>> (x + y + 2).xreplace({x + y: 2}) x + y + 2 >>> (x + 2 + exp(x + 2)).xreplace({x + 2: y}) x + exp(y) + 2 xreplace doesn't differentiate between free and bound symbols. In the following, subs(x, y) would not change x since it is a bound symbol, but xreplace does: >>> from sympy import Integral >>> Integral(x, (x, 1, 2*x)).xreplace({x: y}) Integral(y, (y, 1, 2*y)) Trying to replace x with an expression raises an error: >>> Integral(x, (x, 1, 2*x)).xreplace({x: 2*y}) # doctest: +SKIP ValueError: Invalid limits given: ((2*y, 1, 4*y),) See Also ======== replace: replacement capable of doing wildcard-like matching, parsing of match, and conditional replacements subs: substitution of subexpressions as defined by the objects themselves. """ value, _ = self._xreplace(rule) return value def _xreplace(self, rule): """ Helper for xreplace. Tracks whether a replacement actually occurred. """ if self in rule: return rule[self], True elif rule: args = [] changed = False for a in self.args: _xreplace = getattr(a, '_xreplace', None) if _xreplace is not None: a_xr = _xreplace(rule) args.append(a_xr[0]) changed |= a_xr[1] else: args.append(a) args = tuple(args) if changed: return self.func(*args), True return self, False @cacheit def has(self, *patterns): """ Test whether any subexpression matches any of the patterns. Examples ======== >>> from sympy import sin >>> from sympy.abc import x, y, z >>> (x**2 + sin(x*y)).has(z) False >>> (x**2 + sin(x*y)).has(x, y, z) True >>> x.has(x) True Note ``has`` is a structural algorithm with no knowledge of mathematics. Consider the following half-open interval: >>> from sympy.sets import Interval >>> i = Interval.Lopen(0, 5); i Interval.Lopen(0, 5) >>> i.args (0, 5, True, False) >>> i.has(4) # there is no "4" in the arguments False >>> i.has(0) # there *is* a "0" in the arguments True Instead, use ``contains`` to determine whether a number is in the interval or not: >>> i.contains(4) True >>> i.contains(0) False Note that ``expr.has(*patterns)`` is exactly equivalent to ``any(expr.has(p) for p in patterns)``. In particular, ``False`` is returned when the list of patterns is empty. >>> x.has() False """ return any(self._has(pattern) for pattern in patterns) def _has(self, pattern): """Helper for .has()""" from sympy.core.function import UndefinedFunction, Function if isinstance(pattern, UndefinedFunction): return any(f.func == pattern or f == pattern for f in self.atoms(Function, UndefinedFunction)) if isinstance(pattern, BasicMeta): subtrees = preorder_traversal(self) return any(isinstance(arg, pattern) for arg in subtrees) pattern = _sympify(pattern) _has_matcher = getattr(pattern, '_has_matcher', None) if _has_matcher is not None: match = _has_matcher() return any(match(arg) for arg in preorder_traversal(self)) else: return any(arg == pattern for arg in preorder_traversal(self)) def _has_matcher(self): """Helper for .has()""" return lambda other: self == other def replace(self, query, value, map=False, simultaneous=True, exact=None): """ Replace matching subexpressions of ``self`` with ``value``. If ``map = True`` then also return the mapping {old: new} where ``old`` was a sub-expression found with query and ``new`` is the replacement value for it. If the expression itself doesn't match the query, then the returned value will be ``self.xreplace(map)`` otherwise it should be ``self.subs(ordered(map.items()))``. Traverses an expression tree and performs replacement of matching subexpressions from the bottom to the top of the tree. The default approach is to do the replacement in a simultaneous fashion so changes made are targeted only once. If this is not desired or causes problems, ``simultaneous`` can be set to False. In addition, if an expression containing more than one Wild symbol is being used to match subexpressions and the ``exact`` flag is None it will be set to True so the match will only succeed if all non-zero values are received for each Wild that appears in the match pattern. Setting this to False accepts a match of 0; while setting it True accepts all matches that have a 0 in them. See example below for cautions. The list of possible combinations of queries and replacement values is listed below: Examples ======== Initial setup >>> from sympy import log, sin, cos, tan, Wild, Mul, Add >>> from sympy.abc import x, y >>> f = log(sin(x)) + tan(sin(x**2)) 1.1. type -> type obj.replace(type, newtype) When object of type ``type`` is found, replace it with the result of passing its argument(s) to ``newtype``. >>> f.replace(sin, cos) log(cos(x)) + tan(cos(x**2)) >>> sin(x).replace(sin, cos, map=True) (cos(x), {sin(x): cos(x)}) >>> (x*y).replace(Mul, Add) x + y 1.2. type -> func obj.replace(type, func) When object of type ``type`` is found, apply ``func`` to its argument(s). ``func`` must be written to handle the number of arguments of ``type``. >>> f.replace(sin, lambda arg: sin(2*arg)) log(sin(2*x)) + tan(sin(2*x**2)) >>> (x*y).replace(Mul, lambda *args: sin(2*Mul(*args))) sin(2*x*y) 2.1. pattern -> expr obj.replace(pattern(wild), expr(wild)) Replace subexpressions matching ``pattern`` with the expression written in terms of the Wild symbols in ``pattern``. >>> a, b = map(Wild, 'ab') >>> f.replace(sin(a), tan(a)) log(tan(x)) + tan(tan(x**2)) >>> f.replace(sin(a), tan(a/2)) log(tan(x/2)) + tan(tan(x**2/2)) >>> f.replace(sin(a), a) log(x) + tan(x**2) >>> (x*y).replace(a*x, a) y Matching is exact by default when more than one Wild symbol is used: matching fails unless the match gives non-zero values for all Wild symbols: >>> (2*x + y).replace(a*x + b, b - a) y - 2 >>> (2*x).replace(a*x + b, b - a) 2*x When set to False, the results may be non-intuitive: >>> (2*x).replace(a*x + b, b - a, exact=False) 2/x 2.2. pattern -> func obj.replace(pattern(wild), lambda wild: expr(wild)) All behavior is the same as in 2.1 but now a function in terms of pattern variables is used rather than an expression: >>> f.replace(sin(a), lambda a: sin(2*a)) log(sin(2*x)) + tan(sin(2*x**2)) 3.1. func -> func obj.replace(filter, func) Replace subexpression ``e`` with ``func(e)`` if ``filter(e)`` is True. >>> g = 2*sin(x**3) >>> g.replace(lambda expr: expr.is_Number, lambda expr: expr**2) 4*sin(x**9) The expression itself is also targeted by the query but is done in such a fashion that changes are not made twice. >>> e = x*(x*y + 1) >>> e.replace(lambda x: x.is_Mul, lambda x: 2*x) 2*x*(2*x*y + 1) When matching a single symbol, `exact` will default to True, but this may or may not be the behavior that is desired: Here, we want `exact=False`: >>> from sympy import Function >>> f = Function('f') >>> e = f(1) + f(0) >>> q = f(a), lambda a: f(a + 1) >>> e.replace(*q, exact=False) f(1) + f(2) >>> e.replace(*q, exact=True) f(0) + f(2) But here, the nature of matching makes selecting the right setting tricky: >>> e = x**(1 + y) >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=False) x >>> (x**(1 + y)).replace(x**(1 + a), lambda a: x**-a, exact=True) x**(-x - y + 1) >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=False) x >>> (x**y).replace(x**(1 + a), lambda a: x**-a, exact=True) x**(1 - y) It is probably better to use a different form of the query that describes the target expression more precisely: >>> (1 + x**(1 + y)).replace( ... lambda x: x.is_Pow and x.exp.is_Add and x.exp.args[0] == 1, ... lambda x: x.base**(1 - (x.exp - 1))) ... x**(1 - y) + 1 See Also ======== subs: substitution of subexpressions as defined by the objects themselves. xreplace: exact node replacement in expr tree; also capable of using matching rules """ from sympy.core.symbol import Wild try: query = _sympify(query) except SympifyError: pass try: value = _sympify(value) except SympifyError: pass if isinstance(query, type): _query = lambda expr: isinstance(expr, query) if isinstance(value, type): _value = lambda expr, result: value(*expr.args) elif callable(value): _value = lambda expr, result: value(*expr.args) else: raise TypeError( "given a type, replace() expects another " "type or a callable") elif isinstance(query, Basic): _query = lambda expr: expr.match(query) if exact is None: exact = (len(query.atoms(Wild)) > 1) if isinstance(value, Basic): if exact: _value = lambda expr, result: (value.subs(result) if all(result.values()) else expr) else: _value = lambda expr, result: value.subs(result) elif callable(value): # match dictionary keys get the trailing underscore stripped # from them and are then passed as keywords to the callable; # if ``exact`` is True, only accept match if there are no null # values amongst those matched. if exact: _value = lambda expr, result: (value(** {str(k)[:-1]: v for k, v in result.items()}) if all(val for val in result.values()) else expr) else: _value = lambda expr, result: value(** {str(k)[:-1]: v for k, v in result.items()}) else: raise TypeError( "given an expression, replace() expects " "another expression or a callable") elif callable(query): _query = query if callable(value): _value = lambda expr, result: value(expr) else: raise TypeError( "given a callable, replace() expects " "another callable") else: raise TypeError( "first argument to replace() must be a " "type, an expression or a callable") def walk(rv, F): """Apply ``F`` to args and then to result. """ args = getattr(rv, 'args', None) if args is not None: if args: newargs = tuple([walk(a, F) for a in args]) if args != newargs: rv = rv.func(*newargs) if simultaneous: # if rv is something that was already # matched (that was changed) then skip # applying F again for i, e in enumerate(args): if rv == e and e != newargs[i]: return rv rv = F(rv) return rv mapping = {} # changes that took place def rec_replace(expr): result = _query(expr) if result or result == {}: v = _value(expr, result) if v is not None and v != expr: if map: mapping[expr] = v expr = v return expr rv = walk(self, rec_replace) return (rv, mapping) if map else rv def find(self, query, group=False): """Find all subexpressions matching a query. """ query = _make_find_query(query) results = list(filter(query, preorder_traversal(self))) if not group: return set(results) else: groups = {} for result in results: if result in groups: groups[result] += 1 else: groups[result] = 1 return groups def count(self, query): """Count the number of matching subexpressions. """ query = _make_find_query(query) return sum(bool(query(sub)) for sub in preorder_traversal(self)) def matches(self, expr, repl_dict={}, old=False): """ Helper method for match() that looks for a match between Wild symbols in self and expressions in expr. Examples ======== >>> from sympy import symbols, Wild, Basic >>> a, b, c = symbols('a b c') >>> x = Wild('x') >>> Basic(a + x, x).matches(Basic(a + b, c)) is None True >>> Basic(a + x, x).matches(Basic(a + b + c, b + c)) {x_: b + c} """ repl_dict = repl_dict.copy() expr = sympify(expr) if not isinstance(expr, self.__class__): return None if self == expr: return repl_dict if len(self.args) != len(expr.args): return None d = repl_dict.copy() for arg, other_arg in zip(self.args, expr.args): if arg == other_arg: continue d = arg.xreplace(d).matches(other_arg, d, old=old) if d is None: return None return d def match(self, pattern, old=False): """ Pattern matching. Wild symbols match all. Return ``None`` when expression (self) does not match with pattern. Otherwise return a dictionary such that:: pattern.xreplace(self.match(pattern)) == self Examples ======== >>> from sympy import Wild, Sum >>> from sympy.abc import x, y >>> p = Wild("p") >>> q = Wild("q") >>> r = Wild("r") >>> e = (x+y)**(x+y) >>> e.match(p**p) {p_: x + y} >>> e.match(p**q) {p_: x + y, q_: x + y} >>> e = (2*x)**2 >>> e.match(p*q**r) {p_: 4, q_: x, r_: 2} >>> (p*q**r).xreplace(e.match(p*q**r)) 4*x**2 Structurally bound symbols are ignored during matching: >>> Sum(x, (x, 1, 2)).match(Sum(y, (y, 1, p))) {p_: 2} But they can be identified if desired: >>> Sum(x, (x, 1, 2)).match(Sum(q, (q, 1, p))) {p_: 2, q_: x} The ``old`` flag will give the old-style pattern matching where expressions and patterns are essentially solved to give the match. Both of the following give None unless ``old=True``: >>> (x - 2).match(p - x, old=True) {p_: 2*x - 2} >>> (2/x).match(p*x, old=True) {p_: 2/x**2} """ from sympy.core.symbol import Wild from sympy.core.function import WildFunction from sympy.utilities.misc import filldedent pattern = sympify(pattern) # match non-bound symbols canonical = lambda x: x if x.is_Symbol else x.as_dummy() m = canonical(pattern).matches(canonical(self), old=old) if m is None: return m wild = pattern.atoms(Wild, WildFunction) # sanity check if set(m) - wild: raise ValueError(filldedent(''' Some `matches` routine did not use a copy of repl_dict and injected unexpected symbols. Report this as an error at https://github.com/sympy/sympy/issues''')) # now see if bound symbols were requested bwild = wild - set(m) if not bwild: return m # replace free-Wild symbols in pattern with match result # so they will match but not be in the next match wpat = pattern.xreplace(m) # identify remaining bound wild w = wpat.matches(self, old=old) # add them to m if w: m.update(w) # done return m def count_ops(self, visual=None): """wrapper for count_ops that returns the operation count.""" from sympy import count_ops return count_ops(self, visual) def doit(self, **hints): """Evaluate objects that are not evaluated by default like limits, integrals, sums and products. All objects of this kind will be evaluated recursively, unless some species were excluded via 'hints' or unless the 'deep' hint was set to 'False'. >>> from sympy import Integral >>> from sympy.abc import x >>> 2*Integral(x, x) 2*Integral(x, x) >>> (2*Integral(x, x)).doit() x**2 >>> (2*Integral(x, x)).doit(deep=False) 2*Integral(x, x) """ if hints.get('deep', True): terms = [term.doit(**hints) if isinstance(term, Basic) else term for term in self.args] return self.func(*terms) else: return self def simplify(self, **kwargs): """See the simplify function in sympy.simplify""" from sympy.simplify import simplify return simplify(self, **kwargs) def refine(self, assumption=True): """See the refine function in sympy.assumptions""" from sympy.assumptions import refine return refine(self, assumption) def _eval_derivative_n_times(self, s, n): # This is the default evaluator for derivatives (as called by `diff` # and `Derivative`), it will attempt a loop to derive the expression # `n` times by calling the corresponding `_eval_derivative` method, # while leaving the derivative unevaluated if `n` is symbolic. This # method should be overridden if the object has a closed form for its # symbolic n-th derivative. from sympy import Integer if isinstance(n, (int, Integer)): obj = self for i in range(n): obj2 = obj._eval_derivative(s) if obj == obj2 or obj2 is None: break obj = obj2 return obj2 else: return None def rewrite(self, *args, deep=True, **hints): """ Rewrite *self* using a defined rule. Rewriting transforms an expression to another, which is mathematically equivalent but structurally different. For example you can rewrite trigonometric functions as complex exponentials or combinatorial functions as gamma function. This method takes a *pattern* and a *rule* as positional arguments. *pattern* is optional parameter which defines the types of expressions that will be transformed. If it is not passed, all possible expressions will be rewritten. *rule* defines how the expression will be rewritten. Parameters ========== args : *rule*, or *pattern* and *rule*. - *pattern* is a type or an iterable of types. - *rule* can be any object. deep : bool, optional. If ``True``, subexpressions are recursively transformed. Default is ``True``. Examples ======== If *pattern* is unspecified, all possible expressions are transformed. >>> from sympy import cos, sin, exp, I >>> from sympy.abc import x >>> expr = cos(x) + I*sin(x) >>> expr.rewrite(exp) exp(I*x) Pattern can be a type or an iterable of types. >>> expr.rewrite(sin, exp) exp(I*x)/2 + cos(x) - exp(-I*x)/2 >>> expr.rewrite([cos,], exp) exp(I*x)/2 + I*sin(x) + exp(-I*x)/2 >>> expr.rewrite([cos, sin], exp) exp(I*x) Rewriting behavior can be implemented by defining ``_eval_rewrite()`` method. >>> from sympy import Expr, sqrt, pi >>> class MySin(Expr): ... def _eval_rewrite(self, rule, args, **hints): ... x, = args ... if rule == cos: ... return cos(pi/2 - x, evaluate=False) ... if rule == sqrt: ... return sqrt(1 - cos(x)**2) >>> MySin(MySin(x)).rewrite(cos) cos(-cos(-x + pi/2) + pi/2) >>> MySin(x).rewrite(sqrt) sqrt(1 - cos(x)**2) Defining ``_eval_rewrite_as_[...]()`` method is supported for backwards compatibility reason. This may be removed in the future and using it is discouraged. >>> class MySin(Expr): ... def _eval_rewrite_as_cos(self, *args, **hints): ... x, = args ... return cos(pi/2 - x, evaluate=False) >>> MySin(x).rewrite(cos) cos(-x + pi/2) """ if not args: return self hints.update(deep=deep) pattern = args[:-1] rule = args[-1] # support old design by _eval_rewrite_as_[...] method if isinstance(rule, str): method = "_eval_rewrite_as_%s" % rule elif hasattr(rule, "__name__"): # rule is class or function clsname = rule.__name__ method = "_eval_rewrite_as_%s" % clsname else: # rule is instance clsname = rule.__class__.__name__ method = "_eval_rewrite_as_%s" % clsname if pattern: if iterable(pattern[0]): pattern = pattern[0] pattern = tuple(p for p in pattern if self.has(p)) if not pattern: return self # hereafter, empty pattern is interpreted as all pattern. return self._rewrite(pattern, rule, method, **hints) def _rewrite(self, pattern, rule, method, **hints): deep = hints.pop('deep', True) if deep: args = [a._rewrite(pattern, rule, method, **hints) for a in self.args] else: args = self.args if not pattern or any(isinstance(self, p) for p in pattern): meth = getattr(self, method, None) if meth is not None: rewritten = meth(*args, **hints) else: rewritten = self._eval_rewrite(rule, args, **hints) if rewritten is not None: return rewritten if not args: return self return self.func(*args) def _eval_rewrite(self, rule, args, **hints): return None _constructor_postprocessor_mapping = {} # type: ignore @classmethod def _exec_constructor_postprocessors(cls, obj): # WARNING: This API is experimental. # This is an experimental API that introduces constructor # postprosessors for SymPy Core elements. If an argument of a SymPy # expression has a `_constructor_postprocessor_mapping` attribute, it will # be interpreted as a dictionary containing lists of postprocessing # functions for matching expression node names. clsname = obj.__class__.__name__ postprocessors = defaultdict(list) for i in obj.args: try: postprocessor_mappings = ( Basic._constructor_postprocessor_mapping[cls].items() for cls in type(i).mro() if cls in Basic._constructor_postprocessor_mapping ) for k, v in chain.from_iterable(postprocessor_mappings): postprocessors[k].extend([j for j in v if j not in postprocessors[k]]) except TypeError: pass for f in postprocessors.get(clsname, []): obj = f(obj) return obj def _sage_(self): """ Convert *self* to a symbolic expression of SageMath. This version of the method is merely a placeholder. """ old_method = self._sage_ from sage.interfaces.sympy import sympy_init sympy_init() # may monkey-patch _sage_ method into self's class or superclasses if old_method == self._sage_: raise NotImplementedError('conversion to SageMath is not implemented') else: # call the freshly monkey-patched method return self._sage_() class Atom(Basic): """ A parent class for atomic things. An atom is an expression with no subexpressions. Examples ======== Symbol, Number, Rational, Integer, ... But not: Add, Mul, Pow, ... """ is_Atom = True __slots__ = () def matches(self, expr, repl_dict={}, old=False): if self == expr: return repl_dict.copy() def xreplace(self, rule, hack2=False): return rule.get(self, self) def doit(self, **hints): return self @classmethod def class_key(cls): return 2, 0, cls.__name__ @cacheit def sort_key(self, order=None): return self.class_key(), (1, (str(self),)), S.One.sort_key(), S.One def _eval_simplify(self, **kwargs): return self @property def _sorted_args(self): # this is here as a safeguard against accidentally using _sorted_args # on Atoms -- they cannot be rebuilt as atom.func(*atom._sorted_args) # since there are no args. So the calling routine should be checking # to see that this property is not called for Atoms. raise AttributeError('Atoms have no args. It might be necessary' ' to make a check for Atoms in the calling code.') def _aresame(a, b): """Return True if a and b are structurally the same, else False. Examples ======== In SymPy (as in Python) two numbers compare the same if they have the same underlying base-2 representation even though they may not be the same type: >>> from sympy import S >>> 2.0 == S(2) True >>> 0.5 == S.Half True This routine was written to provide a query for such cases that would give false when the types do not match: >>> from sympy.core.basic import _aresame >>> _aresame(S(2.0), S(2)) False """ from .numbers import Number from .function import AppliedUndef, UndefinedFunction as UndefFunc if isinstance(a, Number) and isinstance(b, Number): return a == b and a.__class__ == b.__class__ for i, j in zip_longest(preorder_traversal(a), preorder_traversal(b)): if i != j or type(i) != type(j): if ((isinstance(i, UndefFunc) and isinstance(j, UndefFunc)) or (isinstance(i, AppliedUndef) and isinstance(j, AppliedUndef))): if i.class_key() != j.class_key(): return False else: return False return True def _ne(a, b): # use this as a second test after `a != b` if you want to make # sure that things are truly equal, e.g. # a, b = 0.5, S.Half # a !=b or _ne(a, b) -> True from .numbers import Number # 0.5 == S.Half if isinstance(a, Number) and isinstance(b, Number): return a.__class__ != b.__class__ def _atomic(e, recursive=False): """Return atom-like quantities as far as substitution is concerned: Derivatives, Functions and Symbols. Don't return any 'atoms' that are inside such quantities unless they also appear outside, too, unless `recursive` is True. Examples ======== >>> from sympy import Derivative, Function, cos >>> from sympy.abc import x, y >>> from sympy.core.basic import _atomic >>> f = Function('f') >>> _atomic(x + y) {x, y} >>> _atomic(x + f(y)) {x, f(y)} >>> _atomic(Derivative(f(x), x) + cos(x) + y) {y, cos(x), Derivative(f(x), x)} """ from sympy import Derivative, Function, Symbol pot = preorder_traversal(e) seen = set() if isinstance(e, Basic): free = getattr(e, "free_symbols", None) if free is None: return {e} else: return set() atoms = set() for p in pot: if p in seen: pot.skip() continue seen.add(p) if isinstance(p, Symbol) and p in free: atoms.add(p) elif isinstance(p, (Derivative, Function)): if not recursive: pot.skip() atoms.add(p) return atoms class preorder_traversal: """ Do a pre-order traversal of a tree. This iterator recursively yields nodes that it has visited in a pre-order fashion. That is, it yields the current node then descends through the tree breadth-first to yield all of a node's children's pre-order traversal. For an expression, the order of the traversal depends on the order of .args, which in many cases can be arbitrary. Parameters ========== node : sympy expression The expression to traverse. keys : (default None) sort key(s) The key(s) used to sort args of Basic objects. When None, args of Basic objects are processed in arbitrary order. If key is defined, it will be passed along to ordered() as the only key(s) to use to sort the arguments; if ``key`` is simply True then the default keys of ordered will be used. Yields ====== subtree : sympy expression All of the subtrees in the tree. Examples ======== >>> from sympy import symbols >>> from sympy.core.basic import preorder_traversal >>> x, y, z = symbols('x y z') The nodes are returned in the order that they are encountered unless key is given; simply passing key=True will guarantee that the traversal is unique. >>> list(preorder_traversal((x + y)*z, keys=None)) # doctest: +SKIP [z*(x + y), z, x + y, y, x] >>> list(preorder_traversal((x + y)*z, keys=True)) [z*(x + y), z, x + y, x, y] """ def __init__(self, node, keys=None): self._skip_flag = False self._pt = self._preorder_traversal(node, keys) def _preorder_traversal(self, node, keys): yield node if self._skip_flag: self._skip_flag = False return if isinstance(node, Basic): if not keys and hasattr(node, '_argset'): # LatticeOp keeps args as a set. We should use this if we # don't care about the order, to prevent unnecessary sorting. args = node._argset else: args = node.args if keys: if keys != True: args = ordered(args, keys, default=False) else: args = ordered(args) for arg in args: yield from self._preorder_traversal(arg, keys) elif iterable(node): for item in node: yield from self._preorder_traversal(item, keys) def skip(self): """ Skip yielding current node's (last yielded node's) subtrees. Examples ======== >>> from sympy.core import symbols >>> from sympy.core.basic import preorder_traversal >>> x, y, z = symbols('x y z') >>> pt = preorder_traversal((x+y*z)*z) >>> for i in pt: ... print(i) ... if i == x+y*z: ... pt.skip() z*(x + y*z) z x + y*z """ self._skip_flag = True def __next__(self): return next(self._pt) def __iter__(self): return self def _make_find_query(query): """Convert the argument of Basic.find() into a callable""" try: query = _sympify(query) except SympifyError: pass if isinstance(query, type): return lambda expr: isinstance(expr, query) elif isinstance(query, Basic): return lambda expr: expr.match(query) is not None return query # Delayed to avoid cyclic import from .singleton import S sympy-sympy-1.9/sympy/core/benchmarks/000077500000000000000000000000001412543434000201515ustar00rootroot00000000000000sympy-sympy-1.9/sympy/core/benchmarks/__init__.py000066400000000000000000000000001412543434000222500ustar00rootroot00000000000000sympy-sympy-1.9/sympy/core/benchmarks/bench_arit.py000066400000000000000000000006341412543434000226240ustar00rootroot00000000000000from sympy.core import Add, Mul, symbols x, y, z = symbols('x,y,z') def timeit_neg(): -x def timeit_Add_x1(): x + 1 def timeit_Add_1x(): 1 + x def timeit_Add_x05(): x + 0.5 def timeit_Add_xy(): x + y def timeit_Add_xyz(): Add(*[x, y, z]) def timeit_Mul_xy(): x*y def timeit_Mul_xyz(): Mul(*[x, y, z]) def timeit_Div_xy(): x/y def timeit_Div_2y(): 2/y sympy-sympy-1.9/sympy/core/benchmarks/bench_assumptions.py000066400000000000000000000002611412543434000242460ustar00rootroot00000000000000from sympy.core import Symbol, Integer x = Symbol('x') i3 = Integer(3) def timeit_x_is_integer(): x.is_integer def timeit_Integer_is_irrational(): i3.is_irrational sympy-sympy-1.9/sympy/core/benchmarks/bench_basic.py000066400000000000000000000003221412543434000227400ustar00rootroot00000000000000from sympy.core import symbols, S x, y = symbols('x,y') def timeit_Symbol_meth_lookup(): x.diff # no call, just method lookup def timeit_S_lookup(): S.Exp1 def timeit_Symbol_eq_xy(): x == y sympy-sympy-1.9/sympy/core/benchmarks/bench_expand.py000066400000000000000000000006531412543434000231450ustar00rootroot00000000000000from sympy.core import symbols, I x, y, z = symbols('x,y,z') p = 3*x**2*y*z**7 + 7*x*y*z**2 + 4*x + x*y**4 e = (x + y + z + 1)**32 def timeit_expand_nothing_todo(): p.expand() def bench_expand_32(): """(x+y+z+1)**32 -> expand""" e.expand() def timeit_expand_complex_number_1(): ((2 + 3*I)**1000).expand(complex=True) def timeit_expand_complex_number_2(): ((2 + 3*I/4)**1000).expand(complex=True) sympy-sympy-1.9/sympy/core/benchmarks/bench_numbers.py000066400000000000000000000021021412543434000233300ustar00rootroot00000000000000from sympy.core.numbers import Integer, Rational, integer_nthroot, igcd from sympy import S, pi, oo i3 = Integer(3) i4 = Integer(4) r34 = Rational(3, 4) q45 = Rational(4, 5) def timeit_Integer_create(): Integer(2) def timeit_Integer_int(): int(i3) def timeit_neg_one(): -S.One def timeit_Integer_neg(): -i3 def timeit_Integer_abs(): abs(i3) def timeit_Integer_sub(): i3 - i3 def timeit_abs_pi(): abs(pi) def timeit_neg_oo(): -oo def timeit_Integer_add_i1(): i3 + 1 def timeit_Integer_add_ij(): i3 + i4 def timeit_Integer_add_Rational(): i3 + r34 def timeit_Integer_mul_i4(): i3*4 def timeit_Integer_mul_ij(): i3*i4 def timeit_Integer_mul_Rational(): i3*r34 def timeit_Integer_eq_i3(): i3 == 3 def timeit_Integer_ed_Rational(): i3 == r34 def timeit_integer_nthroot(): integer_nthroot(100, 2) def timeit_number_igcd_23_17(): igcd(23, 17) def timeit_number_igcd_60_3600(): igcd(60, 3600) def timeit_Rational_add_r1(): r34 + 1 def timeit_Rational_add_rq(): r34 + q45 sympy-sympy-1.9/sympy/core/benchmarks/bench_sympify.py000066400000000000000000000002121412543434000233550ustar00rootroot00000000000000from sympy.core import sympify, Symbol x = Symbol('x') def timeit_sympify_1(): sympify(1) def timeit_sympify_x(): sympify(x) sympy-sympy-1.9/sympy/core/cache.py000066400000000000000000000103401412543434000174470ustar00rootroot00000000000000""" Caching facility for SymPy """ class _cache(list): """ List of cached functions """ def print_cache(self): """print cache info""" for item in self: name = item.__name__ myfunc = item while hasattr(myfunc, '__wrapped__'): if hasattr(myfunc, 'cache_info'): info = myfunc.cache_info() break else: myfunc = myfunc.__wrapped__ else: info = None print(name, info) def clear_cache(self): """clear cache content""" for item in self: myfunc = item while hasattr(myfunc, '__wrapped__'): if hasattr(myfunc, 'cache_clear'): myfunc.cache_clear() break else: myfunc = myfunc.__wrapped__ # global cache registry: CACHE = _cache() # make clear and print methods available print_cache = CACHE.print_cache clear_cache = CACHE.clear_cache from functools import lru_cache def __cacheit(maxsize): """caching decorator. important: the result of cached function must be *immutable* Examples ======== >>> from sympy.core.cache import cacheit >>> @cacheit ... def f(a, b): ... return a+b >>> @cacheit ... def f(a, b): # noqa: F811 ... return [a, b] # <-- WRONG, returns mutable object to force cacheit to check returned results mutability and consistency, set environment variable SYMPY_USE_CACHE to 'debug' """ def func_wrapper(func): from .decorators import wraps cfunc = lru_cache(maxsize, typed=True)(func) @wraps(func) def wrapper(*args, **kwargs): try: retval = cfunc(*args, **kwargs) except TypeError as e: if not e.args or not e.args[0].startswith('unhashable type:'): raise retval = func(*args, **kwargs) return retval wrapper.cache_info = cfunc.cache_info wrapper.cache_clear = cfunc.cache_clear CACHE.append(wrapper) return wrapper return func_wrapper ######################################## def __cacheit_nocache(func): return func def __cacheit_debug(maxsize): """cacheit + code to check cache consistency""" def func_wrapper(func): from .decorators import wraps cfunc = __cacheit(maxsize)(func) @wraps(func) def wrapper(*args, **kw_args): # always call function itself and compare it with cached version r1 = func(*args, **kw_args) r2 = cfunc(*args, **kw_args) # try to see if the result is immutable # # this works because: # # hash([1,2,3]) -> raise TypeError # hash({'a':1, 'b':2}) -> raise TypeError # hash((1,[2,3])) -> raise TypeError # # hash((1,2,3)) -> just computes the hash hash(r1), hash(r2) # also see if returned values are the same if r1 != r2: raise RuntimeError("Returned values are not the same") return r1 return wrapper return func_wrapper def _getenv(key, default=None): from os import getenv return getenv(key, default) # SYMPY_USE_CACHE=yes/no/debug USE_CACHE = _getenv('SYMPY_USE_CACHE', 'yes').lower() # SYMPY_CACHE_SIZE=some_integer/None # special cases : # SYMPY_CACHE_SIZE=0 -> No caching # SYMPY_CACHE_SIZE=None -> Unbounded caching scs = _getenv('SYMPY_CACHE_SIZE', '1000') if scs.lower() == 'none': SYMPY_CACHE_SIZE = None else: try: SYMPY_CACHE_SIZE = int(scs) except ValueError: raise RuntimeError( 'SYMPY_CACHE_SIZE must be a valid integer or None. ' + \ 'Got: %s' % SYMPY_CACHE_SIZE) if USE_CACHE == 'no': cacheit = __cacheit_nocache elif USE_CACHE == 'yes': cacheit = __cacheit(SYMPY_CACHE_SIZE) elif USE_CACHE == 'debug': cacheit = __cacheit_debug(SYMPY_CACHE_SIZE) # a lot slower else: raise RuntimeError( 'unrecognized value for SYMPY_USE_CACHE: %s' % USE_CACHE) sympy-sympy-1.9/sympy/core/compatibility.py000066400000000000000000000463711412543434000212720ustar00rootroot00000000000000""" Reimplementations of constructs introduced in later versions of Python than we support. Also some functions that are needed SymPy-wide and are located here for easy import. """ import operator from collections import defaultdict from time import perf_counter as clock from sympy.external.gmpy import SYMPY_INTS, HAS_GMPY, GROUND_TYPES, gmpy """ Python 2 and Python 3 compatible imports String and Unicode compatible changes: * `unicode()` removed in Python 3, import `unicode` for Python 2/3 compatible function * Use `u()` for escaped unicode sequences (e.g. u'\u2020' -> u('\u2020')) * Use `u_decode()` to decode utf-8 formatted unicode strings Renamed function attributes: * Python 2 `.func_code`, Python 3 `.__func__`, access with `get_function_code()` * Python 2 `.func_globals`, Python 3 `.__globals__`, access with `get_function_globals()` * Python 2 `.func_name`, Python 3 `.__name__`, access with `get_function_name()` Moved modules: * `reduce()` * `StringIO()` * `cStringIO()` (same as `StingIO()` in Python 3) * Python 2 `__builtin__`, access with Python 3 name, `builtins` exec: * Use `exec_()`, with parameters `exec_(code, globs=None, locs=None)` Metaclasses: * Use `with_metaclass()`, examples below * Define class `Foo` with metaclass `Meta`, and no parent: class Foo(with_metaclass(Meta)): pass * Define class `Foo` with metaclass `Meta` and parent class `Bar`: class Foo(with_metaclass(Meta, Bar)): pass """ __all__ = [ 'PY3', 'int_info', 'SYMPY_INTS', 'clock', 'unicode', 'u_decode', 'get_function_code', 'gmpy', 'get_function_globals', 'get_function_name', 'builtins', 'reduce', 'StringIO', 'cStringIO', 'exec_', 'Mapping', 'Callable', 'MutableMapping', 'MutableSet', 'Iterable', 'Hashable', 'unwrap', 'accumulate', 'with_metaclass', 'NotIterable', 'iterable', 'is_sequence', 'as_int', 'default_sort_key', 'ordered', 'GROUND_TYPES', 'HAS_GMPY', ] import sys PY3 = True int_info = sys.int_info # String / unicode compatibility unicode = str def u_decode(x): return x # Moved definitions get_function_code = operator.attrgetter("__code__") get_function_globals = operator.attrgetter("__globals__") get_function_name = operator.attrgetter("__name__") import builtins from functools import reduce from io import StringIO cStringIO = StringIO exec_ = getattr(builtins, "exec") from collections.abc import (Mapping, Callable, MutableMapping, MutableSet, Iterable, Hashable) from inspect import unwrap from itertools import accumulate def with_metaclass(meta, *bases): """ Create a base class with a metaclass. For example, if you have the metaclass >>> class Meta(type): ... pass Use this as the metaclass by doing >>> from sympy.core.compatibility import with_metaclass >>> class MyClass(with_metaclass(Meta, object)): ... pass This is equivalent to the Python 2:: class MyClass(object): __metaclass__ = Meta or Python 3:: class MyClass(object, metaclass=Meta): pass That is, the first argument is the metaclass, and the remaining arguments are the base classes. Note that if the base class is just ``object``, you may omit it. >>> MyClass.__mro__ (, <... 'object'>) >>> type(MyClass) """ # This requires a bit of explanation: the basic idea is to make a dummy # metaclass for one level of class instantiation that replaces itself with # the actual metaclass. # Code copied from the 'six' library. class metaclass(meta): def __new__(cls, name, this_bases, d): return meta(name, bases, d) return type.__new__(metaclass, "NewBase", (), {}) # These are in here because telling if something is an iterable just by calling # hasattr(obj, "__iter__") behaves differently in Python 2 and Python 3. In # particular, hasattr(str, "__iter__") is False in Python 2 and True in Python 3. # I think putting them here also makes it easier to use them in the core. class NotIterable: """ Use this as mixin when creating a class which is not supposed to return true when iterable() is called on its instances because calling list() on the instance, for example, would result in an infinite loop. """ pass def iterable(i, exclude=(str, dict, NotIterable)): """ Return a boolean indicating whether ``i`` is SymPy iterable. True also indicates that the iterator is finite, e.g. you can call list(...) on the instance. When SymPy is working with iterables, it is almost always assuming that the iterable is not a string or a mapping, so those are excluded by default. If you want a pure Python definition, make exclude=None. To exclude multiple items, pass them as a tuple. You can also set the _iterable attribute to True or False on your class, which will override the checks here, including the exclude test. As a rule of thumb, some SymPy functions use this to check if they should recursively map over an object. If an object is technically iterable in the Python sense but does not desire this behavior (e.g., because its iteration is not finite, or because iteration might induce an unwanted computation), it should disable it by setting the _iterable attribute to False. See also: is_sequence Examples ======== >>> from sympy.utilities.iterables import iterable >>> from sympy import Tuple >>> things = [[1], (1,), set([1]), Tuple(1), (j for j in [1, 2]), {1:2}, '1', 1] >>> for i in things: ... print('%s %s' % (iterable(i), type(i))) True <... 'list'> True <... 'tuple'> True <... 'set'> True True <... 'generator'> False <... 'dict'> False <... 'str'> False <... 'int'> >>> iterable({}, exclude=None) True >>> iterable({}, exclude=str) True >>> iterable("no", exclude=str) False """ if hasattr(i, '_iterable'): return i._iterable try: iter(i) except TypeError: return False if exclude: return not isinstance(i, exclude) return True def is_sequence(i, include=None): """ Return a boolean indicating whether ``i`` is a sequence in the SymPy sense. If anything that fails the test below should be included as being a sequence for your application, set 'include' to that object's type; multiple types should be passed as a tuple of types. Note: although generators can generate a sequence, they often need special handling to make sure their elements are captured before the generator is exhausted, so these are not included by default in the definition of a sequence. See also: iterable Examples ======== >>> from sympy.utilities.iterables import is_sequence >>> from types import GeneratorType >>> is_sequence([]) True >>> is_sequence(set()) False >>> is_sequence('abc') False >>> is_sequence('abc', include=str) True >>> generator = (c for c in 'abc') >>> is_sequence(generator) False >>> is_sequence(generator, include=(str, GeneratorType)) True """ return (hasattr(i, '__getitem__') and iterable(i) or bool(include) and isinstance(i, include)) def as_int(n, strict=True): """ Convert the argument to a builtin integer. The return value is guaranteed to be equal to the input. ValueError is raised if the input has a non-integral value. When ``strict`` is True, this uses `__index__ `_ and when it is False it uses ``int``. Examples ======== >>> from sympy.core.compatibility import as_int >>> from sympy import sqrt, S The function is primarily concerned with sanitizing input for functions that need to work with builtin integers, so anything that is unambiguously an integer should be returned as an int: >>> as_int(S(3)) 3 Floats, being of limited precision, are not assumed to be exact and will raise an error unless the ``strict`` flag is False. This precision issue becomes apparent for large floating point numbers: >>> big = 1e23 >>> type(big) is float True >>> big == int(big) True >>> as_int(big) Traceback (most recent call last): ... ValueError: ... is not an integer >>> as_int(big, strict=False) 99999999999999991611392 Input that might be a complex representation of an integer value is also rejected by default: >>> one = sqrt(3 + 2*sqrt(2)) - sqrt(2) >>> int(one) == 1 True >>> as_int(one) Traceback (most recent call last): ... ValueError: ... is not an integer """ if strict: try: if type(n) is bool: raise TypeError return operator.index(n) except TypeError: raise ValueError('%s is not an integer' % (n,)) else: try: result = int(n) except TypeError: raise ValueError('%s is not an integer' % (n,)) if n != result: raise ValueError('%s is not an integer' % (n,)) return result def default_sort_key(item, order=None): """Return a key that can be used for sorting. The key has the structure: (class_key, (len(args), args), exponent.sort_key(), coefficient) This key is supplied by the sort_key routine of Basic objects when ``item`` is a Basic object or an object (other than a string) that sympifies to a Basic object. Otherwise, this function produces the key. The ``order`` argument is passed along to the sort_key routine and is used to determine how the terms *within* an expression are ordered. (See examples below) ``order`` options are: 'lex', 'grlex', 'grevlex', and reversed values of the same (e.g. 'rev-lex'). The default order value is None (which translates to 'lex'). Examples ======== >>> from sympy import S, I, default_sort_key, sin, cos, sqrt >>> from sympy.core.function import UndefinedFunction >>> from sympy.abc import x The following are equivalent ways of getting the key for an object: >>> x.sort_key() == default_sort_key(x) True Here are some examples of the key that is produced: >>> default_sort_key(UndefinedFunction('f')) ((0, 0, 'UndefinedFunction'), (1, ('f',)), ((1, 0, 'Number'), (0, ()), (), 1), 1) >>> default_sort_key('1') ((0, 0, 'str'), (1, ('1',)), ((1, 0, 'Number'), (0, ()), (), 1), 1) >>> default_sort_key(S.One) ((1, 0, 'Number'), (0, ()), (), 1) >>> default_sort_key(2) ((1, 0, 'Number'), (0, ()), (), 2) While sort_key is a method only defined for SymPy objects, default_sort_key will accept anything as an argument so it is more robust as a sorting key. For the following, using key= lambda i: i.sort_key() would fail because 2 doesn't have a sort_key method; that's why default_sort_key is used. Note, that it also handles sympification of non-string items likes ints: >>> a = [2, I, -I] >>> sorted(a, key=default_sort_key) [2, -I, I] The returned key can be used anywhere that a key can be specified for a function, e.g. sort, min, max, etc...: >>> a.sort(key=default_sort_key); a[0] 2 >>> min(a, key=default_sort_key) 2 Note ---- The key returned is useful for getting items into a canonical order that will be the same across platforms. It is not directly useful for sorting lists of expressions: >>> a, b = x, 1/x Since ``a`` has only 1 term, its value of sort_key is unaffected by ``order``: >>> a.sort_key() == a.sort_key('rev-lex') True If ``a`` and ``b`` are combined then the key will differ because there are terms that can be ordered: >>> eq = a + b >>> eq.sort_key() == eq.sort_key('rev-lex') False >>> eq.as_ordered_terms() [x, 1/x] >>> eq.as_ordered_terms('rev-lex') [1/x, x] But since the keys for each of these terms are independent of ``order``'s value, they don't sort differently when they appear separately in a list: >>> sorted(eq.args, key=default_sort_key) [1/x, x] >>> sorted(eq.args, key=lambda i: default_sort_key(i, order='rev-lex')) [1/x, x] The order of terms obtained when using these keys is the order that would be obtained if those terms were *factors* in a product. Although it is useful for quickly putting expressions in canonical order, it does not sort expressions based on their complexity defined by the number of operations, power of variables and others: >>> sorted([sin(x)*cos(x), sin(x)], key=default_sort_key) [sin(x)*cos(x), sin(x)] >>> sorted([x, x**2, sqrt(x), x**3], key=default_sort_key) [sqrt(x), x, x**2, x**3] See Also ======== ordered, sympy.core.expr.as_ordered_factors, sympy.core.expr.as_ordered_terms """ from .singleton import S from .basic import Basic from .sympify import sympify, SympifyError from .compatibility import iterable if isinstance(item, Basic): return item.sort_key(order=order) if iterable(item, exclude=str): if isinstance(item, dict): args = item.items() unordered = True elif isinstance(item, set): args = item unordered = True else: # e.g. tuple, list args = list(item) unordered = False args = [default_sort_key(arg, order=order) for arg in args] if unordered: # e.g. dict, set args = sorted(args) cls_index, args = 10, (len(args), tuple(args)) else: if not isinstance(item, str): try: item = sympify(item, strict=True) except SympifyError: # e.g. lambda x: x pass else: if isinstance(item, Basic): # e.g int -> Integer return default_sort_key(item) # e.g. UndefinedFunction # e.g. str cls_index, args = 0, (1, (str(item),)) return (cls_index, 0, item.__class__.__name__ ), args, S.One.sort_key(), S.One def _node_count(e): return 1 + sum(map(_node_count, e.args)) def _nodes(e): """ A helper for ordered() which returns the node count of ``e`` which for Basic objects is the number of Basic nodes in the expression tree but for other objects is 1 (unless the object is an iterable or dict for which the sum of nodes is returned). """ from .basic import Basic from .function import Derivative if isinstance(e, Basic): if isinstance(e, Derivative): return _nodes(e.expr) + len(e.variables) return _node_count(e) elif iterable(e): return 1 + sum(_nodes(ei) for ei in e) elif isinstance(e, dict): return 1 + sum(_nodes(k) + _nodes(v) for k, v in e.items()) else: return 1 def ordered(seq, keys=None, default=True, warn=False): """Return an iterator of the seq where keys are used to break ties in a conservative fashion: if, after applying a key, there are no ties then no other keys will be computed. Two default keys will be applied if 1) keys are not provided or 2) the given keys don't resolve all ties (but only if ``default`` is True). The two keys are ``_nodes`` (which places smaller expressions before large) and ``default_sort_key`` which (if the ``sort_key`` for an object is defined properly) should resolve any ties. If ``warn`` is True then an error will be raised if there were no keys remaining to break ties. This can be used if it was expected that there should be no ties between items that are not identical. Examples ======== >>> from sympy.utilities.iterables import ordered >>> from sympy import count_ops >>> from sympy.abc import x, y The count_ops is not sufficient to break ties in this list and the first two items appear in their original order (i.e. the sorting is stable): >>> list(ordered([y + 2, x + 2, x**2 + y + 3], ... count_ops, default=False, warn=False)) ... [y + 2, x + 2, x**2 + y + 3] The default_sort_key allows the tie to be broken: >>> list(ordered([y + 2, x + 2, x**2 + y + 3])) ... [x + 2, y + 2, x**2 + y + 3] Here, sequences are sorted by length, then sum: >>> seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], [ ... lambda x: len(x), ... lambda x: sum(x)]] ... >>> list(ordered(seq, keys, default=False, warn=False)) [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]] If ``warn`` is True, an error will be raised if there were not enough keys to break ties: >>> list(ordered(seq, keys, default=False, warn=True)) Traceback (most recent call last): ... ValueError: not enough keys to break ties Notes ===== The decorated sort is one of the fastest ways to sort a sequence for which special item comparison is desired: the sequence is decorated, sorted on the basis of the decoration (e.g. making all letters lower case) and then undecorated. If one wants to break ties for items that have the same decorated value, a second key can be used. But if the second key is expensive to compute then it is inefficient to decorate all items with both keys: only those items having identical first key values need to be decorated. This function applies keys successively only when needed to break ties. By yielding an iterator, use of the tie-breaker is delayed as long as possible. This function is best used in cases when use of the first key is expected to be a good hashing function; if there are no unique hashes from application of a key, then that key should not have been used. The exception, however, is that even if there are many collisions, if the first group is small and one does not need to process all items in the list then time will not be wasted sorting what one was not interested in. For example, if one were looking for the minimum in a list and there were several criteria used to define the sort order, then this function would be good at returning that quickly if the first group of candidates is small relative to the number of items being processed. """ d = defaultdict(list) if keys: if not isinstance(keys, (list, tuple)): keys = [keys] keys = list(keys) f = keys.pop(0) for a in seq: d[f(a)].append(a) else: if not default: raise ValueError('if default=False then keys must be provided') d[None].extend(seq) for k in sorted(d.keys()): if len(d[k]) > 1: if keys: d[k] = ordered(d[k], keys, default, warn) elif default: d[k] = ordered(d[k], (_nodes, default_sort_key,), default=False, warn=warn) elif warn: from sympy.utilities.iterables import uniq u = list(uniq(d[k])) if len(u) > 1: raise ValueError( 'not enough keys to break ties: %s' % u) yield from d[k] d.pop(k) sympy-sympy-1.9/sympy/core/containers.py000066400000000000000000000233211412543434000205540ustar00rootroot00000000000000"""Module for SymPy containers (SymPy objects that store other SymPy objects) The containers implemented in this module are subclassed to Basic. They are supposed to work seamlessly within the SymPy framework. """ from collections import OrderedDict from collections.abc import MutableSet from sympy.core.basic import Basic from sympy.core.compatibility import as_int from sympy.core.sympify import _sympify, sympify, converter, SympifyError from sympy.utilities.iterables import iterable class Tuple(Basic): """ Wrapper around the builtin tuple object. Explanation =========== The Tuple is a subclass of Basic, so that it works well in the SymPy framework. The wrapped tuple is available as self.args, but you can also access elements or slices with [:] syntax. Parameters ========== sympify : bool If ``False``, ``sympify`` is not called on ``args``. This can be used for speedups for very large tuples where the elements are known to already be sympy objects. Examples ======== >>> from sympy import symbols >>> from sympy.core.containers import Tuple >>> a, b, c, d = symbols('a b c d') >>> Tuple(a, b, c)[1:] (b, c) >>> Tuple(a, b, c).subs(a, d) (d, b, c) """ def __new__(cls, *args, **kwargs): if kwargs.get('sympify', True): args = (sympify(arg) for arg in args) obj = Basic.__new__(cls, *args) return obj def __getitem__(self, i): if isinstance(i, slice): indices = i.indices(len(self)) return Tuple(*(self.args[j] for j in range(*indices))) return self.args[i] def __len__(self): return len(self.args) def __contains__(self, item): return item in self.args def __iter__(self): return iter(self.args) def __add__(self, other): if isinstance(other, Tuple): return Tuple(*(self.args + other.args)) elif isinstance(other, tuple): return Tuple(*(self.args + other)) else: return NotImplemented def __radd__(self, other): if isinstance(other, Tuple): return Tuple(*(other.args + self.args)) elif isinstance(other, tuple): return Tuple(*(other + self.args)) else: return NotImplemented def __mul__(self, other): try: n = as_int(other) except ValueError: raise TypeError("Can't multiply sequence by non-integer of type '%s'" % type(other)) return self.func(*(self.args*n)) __rmul__ = __mul__ def __eq__(self, other): if isinstance(other, Basic): return super().__eq__(other) return self.args == other def __ne__(self, other): if isinstance(other, Basic): return super().__ne__(other) return self.args != other def __hash__(self): return hash(self.args) def _to_mpmath(self, prec): return tuple(a._to_mpmath(prec) for a in self.args) def __lt__(self, other): return _sympify(self.args < other.args) def __le__(self, other): return _sympify(self.args <= other.args) # XXX: Basic defines count() as something different, so we can't # redefine it here. Originally this lead to cse() test failure. def tuple_count(self, value): """T.count(value) -> integer -- return number of occurrences of value""" return self.args.count(value) def index(self, value, start=None, stop=None): """Searches and returns the first index of the value.""" # XXX: One would expect: # # return self.args.index(value, start, stop) # # here. Any trouble with that? Yes: # # >>> (1,).index(1, None, None) # Traceback (most recent call last): # File "", line 1, in # TypeError: slice indices must be integers or None or have an __index__ method # # See: http://bugs.python.org/issue13340 if start is None and stop is None: return self.args.index(value) elif stop is None: return self.args.index(value, start) else: return self.args.index(value, start, stop) converter[tuple] = lambda tup: Tuple(*tup) def tuple_wrapper(method): """ Decorator that converts any tuple in the function arguments into a Tuple. Explanation =========== The motivation for this is to provide simple user interfaces. The user can call a function with regular tuples in the argument, and the wrapper will convert them to Tuples before handing them to the function. Explanation =========== >>> from sympy.core.containers import tuple_wrapper >>> def f(*args): ... return args >>> g = tuple_wrapper(f) The decorated function g sees only the Tuple argument: >>> g(0, (1, 2), 3) (0, (1, 2), 3) """ def wrap_tuples(*args, **kw_args): newargs = [] for arg in args: if type(arg) is tuple: newargs.append(Tuple(*arg)) else: newargs.append(arg) return method(*newargs, **kw_args) return wrap_tuples class Dict(Basic): """ Wrapper around the builtin dict object Explanation =========== The Dict is a subclass of Basic, so that it works well in the SymPy framework. Because it is immutable, it may be included in sets, but its values must all be given at instantiation and cannot be changed afterwards. Otherwise it behaves identically to the Python dict. Examples ======== >>> from sympy import Symbol >>> from sympy.core.containers import Dict >>> D = Dict({1: 'one', 2: 'two'}) >>> for key in D: ... if key == 1: ... print('%s %s' % (key, D[key])) 1 one The args are sympified so the 1 and 2 are Integers and the values are Symbols. Queries automatically sympify args so the following work: >>> 1 in D True >>> D.has(Symbol('one')) # searches keys and values True >>> 'one' in D # not in the keys False >>> D[1] one """ def __new__(cls, *args): if len(args) == 1 and isinstance(args[0], (dict, Dict)): items = [Tuple(k, v) for k, v in args[0].items()] elif iterable(args) and all(len(arg) == 2 for arg in args): items = [Tuple(k, v) for k, v in args] else: raise TypeError('Pass Dict args as Dict((k1, v1), ...) or Dict({k1: v1, ...})') elements = frozenset(items) obj = Basic.__new__(cls, elements) obj.elements = elements obj._dict = dict(items) # In case Tuple decides it wants to sympify return obj def __getitem__(self, key): """x.__getitem__(y) <==> x[y]""" try: key = _sympify(key) except SympifyError: raise KeyError(key) return self._dict[key] def __setitem__(self, key, value): raise NotImplementedError("SymPy Dicts are Immutable") @property def args(self): """Returns a tuple of arguments of 'self'. See Also ======== sympy.core.basic.Basic.args """ return tuple(self.elements) def items(self): '''Returns a set-like object providing a view on dict's items. ''' return self._dict.items() def keys(self): '''Returns the list of the dict's keys.''' return self._dict.keys() def values(self): '''Returns the list of the dict's values.''' return self._dict.values() def __iter__(self): '''x.__iter__() <==> iter(x)''' return iter(self._dict) def __len__(self): '''x.__len__() <==> len(x)''' return self._dict.__len__() def get(self, key, default=None): '''Returns the value for key if the key is in the dictionary.''' try: key = _sympify(key) except SympifyError: return default return self._dict.get(key, default) def __contains__(self, key): '''D.__contains__(k) -> True if D has a key k, else False''' try: key = _sympify(key) except SympifyError: return False return key in self._dict def __lt__(self, other): return _sympify(self.args < other.args) @property def _sorted_args(self): from sympy.utilities import default_sort_key return tuple(sorted(self.args, key=default_sort_key)) # this handles dict, defaultdict, OrderedDict converter[dict] = lambda d: Dict(*d.items()) class OrderedSet(MutableSet): def __init__(self, iterable=None): if iterable: self.map = OrderedDict((item, None) for item in iterable) else: self.map = OrderedDict() def __len__(self): return len(self.map) def __contains__(self, key): return key in self.map def add(self, key): self.map[key] = None def discard(self, key): self.map.pop(key) def pop(self, last=True): return self.map.popitem(last=last)[0] def __iter__(self): yield from self.map.keys() def __repr__(self): if not self.map: return '%s()' % (self.__class__.__name__,) return '%s(%r)' % (self.__class__.__name__, list(self.map.keys())) def intersection(self, other): result = [] for val in self: if val in other: result.append(val) return self.__class__(result) def difference(self, other): result = [] for val in self: if val not in other: result.append(val) return self.__class__(result) def update(self, iterable): for val in iterable: self.add(val) sympy-sympy-1.9/sympy/core/core.py000066400000000000000000000054661412543434000173510ustar00rootroot00000000000000""" The core's core. """ # used for canonical ordering of symbolic sequences # via __cmp__ method: # FIXME this is *so* irrelevant and outdated! ordering_of_classes = [ # singleton numbers 'Zero', 'One', 'Half', 'Infinity', 'NaN', 'NegativeOne', 'NegativeInfinity', # numbers 'Integer', 'Rational', 'Float', # singleton symbols 'Exp1', 'Pi', 'ImaginaryUnit', # symbols 'Symbol', 'Wild', 'Temporary', # arithmetic operations 'Pow', 'Mul', 'Add', # function values 'Derivative', 'Integral', # defined singleton functions 'Abs', 'Sign', 'Sqrt', 'Floor', 'Ceiling', 'Re', 'Im', 'Arg', 'Conjugate', 'Exp', 'Log', 'Sin', 'Cos', 'Tan', 'Cot', 'ASin', 'ACos', 'ATan', 'ACot', 'Sinh', 'Cosh', 'Tanh', 'Coth', 'ASinh', 'ACosh', 'ATanh', 'ACoth', 'RisingFactorial', 'FallingFactorial', 'factorial', 'binomial', 'Gamma', 'LowerGamma', 'UpperGamma', 'PolyGamma', 'Erf', # special polynomials 'Chebyshev', 'Chebyshev2', # undefined functions 'Function', 'WildFunction', # anonymous functions 'Lambda', # Landau O symbol 'Order', # relational operations 'Equality', 'Unequality', 'StrictGreaterThan', 'StrictLessThan', 'GreaterThan', 'LessThan', ] class Registry: """ Base class for registry objects. Registries map a name to an object using attribute notation. Registry classes behave singletonically: all their instances share the same state, which is stored in the class object. All subclasses should set `__slots__ = ()`. """ __slots__ = () def __setattr__(self, name, obj): setattr(self.__class__, name, obj) def __delattr__(self, name): delattr(self.__class__, name) #A set containing all sympy class objects all_classes = set() class BasicMeta(type): def __init__(cls, *args, **kws): all_classes.add(cls) cls.__sympy__ = property(lambda self: True) def __cmp__(cls, other): # If the other object is not a Basic subclass, then we are not equal to # it. if not isinstance(other, BasicMeta): return -1 n1 = cls.__name__ n2 = other.__name__ if n1 == n2: return 0 UNKNOWN = len(ordering_of_classes) + 1 try: i1 = ordering_of_classes.index(n1) except ValueError: i1 = UNKNOWN try: i2 = ordering_of_classes.index(n2) except ValueError: i2 = UNKNOWN if i1 == UNKNOWN and i2 == UNKNOWN: return (n1 > n2) - (n1 < n2) return (i1 > i2) - (i1 < i2) def __lt__(cls, other): if cls.__cmp__(other) == -1: return True return False def __gt__(cls, other): if cls.__cmp__(other) == 1: return True return False sympy-sympy-1.9/sympy/core/coreerrors.py000066400000000000000000000004201412543434000205670ustar00rootroot00000000000000"""Definitions of common exceptions for :mod:`sympy.core` module. """ class BaseCoreError(Exception): """Base class for core related exceptions. """ class NonCommutativeExpression(BaseCoreError): """Raised when expression didn't have commutative property. """ sympy-sympy-1.9/sympy/core/decorators.py000066400000000000000000000223241412543434000205560ustar00rootroot00000000000000""" SymPy core decorators. The purpose of this module is to expose decorators without any other dependencies, so that they can be easily imported anywhere in sympy/core. """ from functools import wraps from .sympify import SympifyError, sympify def deprecated(**decorator_kwargs): """This is a decorator which can be used to mark functions as deprecated. It will result in a warning being emitted when the function is used.""" from sympy.utilities.exceptions import SymPyDeprecationWarning def _warn_deprecation(wrapped, stacklevel): decorator_kwargs.setdefault('feature', wrapped.__name__) SymPyDeprecationWarning(**decorator_kwargs).warn(stacklevel=stacklevel) def deprecated_decorator(wrapped): if hasattr(wrapped, '__mro__'): # wrapped is actually a class class wrapper(wrapped): __doc__ = wrapped.__doc__ __name__ = wrapped.__name__ __module__ = wrapped.__module__ _sympy_deprecated_func = wrapped def __init__(self, *args, **kwargs): _warn_deprecation(wrapped, 4) super().__init__(*args, **kwargs) else: @wraps(wrapped) def wrapper(*args, **kwargs): _warn_deprecation(wrapped, 3) return wrapped(*args, **kwargs) wrapper._sympy_deprecated_func = wrapped return wrapper return deprecated_decorator def _sympifyit(arg, retval=None): """ decorator to smartly _sympify function arguments Explanation =========== @_sympifyit('other', NotImplemented) def add(self, other): ... In add, other can be thought of as already being a SymPy object. If it is not, the code is likely to catch an exception, then other will be explicitly _sympified, and the whole code restarted. if _sympify(arg) fails, NotImplemented will be returned See also ======== __sympifyit """ def deco(func): return __sympifyit(func, arg, retval) return deco def __sympifyit(func, arg, retval=None): """decorator to _sympify `arg` argument for function `func` don't use directly -- use _sympifyit instead """ # we support f(a,b) only if not func.__code__.co_argcount: raise LookupError("func not found") # only b is _sympified assert func.__code__.co_varnames[1] == arg if retval is None: @wraps(func) def __sympifyit_wrapper(a, b): return func(a, sympify(b, strict=True)) else: @wraps(func) def __sympifyit_wrapper(a, b): try: # If an external class has _op_priority, it knows how to deal # with sympy objects. Otherwise, it must be converted. if not hasattr(b, '_op_priority'): b = sympify(b, strict=True) return func(a, b) except SympifyError: return retval return __sympifyit_wrapper def call_highest_priority(method_name): """A decorator for binary special methods to handle _op_priority. Explanation =========== Binary special methods in Expr and its subclasses use a special attribute '_op_priority' to determine whose special method will be called to handle the operation. In general, the object having the highest value of '_op_priority' will handle the operation. Expr and subclasses that define custom binary special methods (__mul__, etc.) should decorate those methods with this decorator to add the priority logic. The ``method_name`` argument is the name of the method of the other class that will be called. Use this decorator in the following manner:: # Call other.__rmul__ if other._op_priority > self._op_priority @call_highest_priority('__rmul__') def __mul__(self, other): ... # Call other.__mul__ if other._op_priority > self._op_priority @call_highest_priority('__mul__') def __rmul__(self, other): ... """ def priority_decorator(func): @wraps(func) def binary_op_wrapper(self, other): if hasattr(other, '_op_priority'): if other._op_priority > self._op_priority: f = getattr(other, method_name, None) if f is not None: return f(self) return func(self, other) return binary_op_wrapper return priority_decorator def sympify_method_args(cls): '''Decorator for a class with methods that sympify arguments. Explanation =========== The sympify_method_args decorator is to be used with the sympify_return decorator for automatic sympification of method arguments. This is intended for the common idiom of writing a class like : Examples ======== >>> from sympy.core.basic import Basic >>> from sympy.core.sympify import _sympify, SympifyError >>> class MyTuple(Basic): ... def __add__(self, other): ... try: ... other = _sympify(other) ... except SympifyError: ... return NotImplemented ... if not isinstance(other, MyTuple): ... return NotImplemented ... return MyTuple(*(self.args + other.args)) >>> MyTuple(1, 2) + MyTuple(3, 4) MyTuple(1, 2, 3, 4) In the above it is important that we return NotImplemented when other is not sympifiable and also when the sympified result is not of the expected type. This allows the MyTuple class to be used cooperatively with other classes that overload __add__ and want to do something else in combination with instance of Tuple. Using this decorator the above can be written as >>> from sympy.core.decorators import sympify_method_args, sympify_return >>> @sympify_method_args ... class MyTuple(Basic): ... @sympify_return([('other', 'MyTuple')], NotImplemented) ... def __add__(self, other): ... return MyTuple(*(self.args + other.args)) >>> MyTuple(1, 2) + MyTuple(3, 4) MyTuple(1, 2, 3, 4) The idea here is that the decorators take care of the boiler-plate code for making this happen in each method that potentially needs to accept unsympified arguments. Then the body of e.g. the __add__ method can be written without needing to worry about calling _sympify or checking the type of the resulting object. The parameters for sympify_return are a list of tuples of the form (parameter_name, expected_type) and the value to return (e.g. NotImplemented). The expected_type parameter can be a type e.g. Tuple or a string 'Tuple'. Using a string is useful for specifying a Type within its class body (as in the above example). Notes: Currently sympify_return only works for methods that take a single argument (not including self). Specifying an expected_type as a string only works for the class in which the method is defined. ''' # Extract the wrapped methods from each of the wrapper objects created by # the sympify_return decorator. Doing this here allows us to provide the # cls argument which is used for forward string referencing. for attrname, obj in cls.__dict__.items(): if isinstance(obj, _SympifyWrapper): setattr(cls, attrname, obj.make_wrapped(cls)) return cls def sympify_return(*args): '''Function/method decorator to sympify arguments automatically See the docstring of sympify_method_args for explanation. ''' # Store a wrapper object for the decorated method def wrapper(func): return _SympifyWrapper(func, args) return wrapper class _SympifyWrapper: '''Internal class used by sympify_return and sympify_method_args''' def __init__(self, func, args): self.func = func self.args = args def make_wrapped(self, cls): func = self.func parameters, retval = self.args # XXX: Handle more than one parameter? [(parameter, expectedcls)] = parameters # Handle forward references to the current class using strings if expectedcls == cls.__name__: expectedcls = cls # Raise RuntimeError since this is a failure at import time and should # not be recoverable. nargs = func.__code__.co_argcount # we support f(a, b) only if nargs != 2: raise RuntimeError('sympify_return can only be used with 2 argument functions') # only b is _sympified if func.__code__.co_varnames[1] != parameter: raise RuntimeError('parameter name mismatch "%s" in %s' % (parameter, func.__name__)) @wraps(func) def _func(self, other): # XXX: The check for _op_priority here should be removed. It is # needed to stop mutable matrices from being sympified to # immutable matrices which breaks things in quantum... if not hasattr(other, '_op_priority'): try: other = sympify(other, strict=True) except SympifyError: return retval if not isinstance(other, expectedcls): return retval return func(self, other) return _func sympy-sympy-1.9/sympy/core/evalf.py000066400000000000000000001520151412543434000175070ustar00rootroot00000000000000""" Adaptive numerical evaluation of SymPy expressions, using mpmath for mathematical functions. """ from typing import Tuple import math import mpmath.libmp as libmp from mpmath import ( make_mpc, make_mpf, mp, mpc, mpf, nsum, quadts, quadosc, workprec) from mpmath import inf as mpmath_inf from mpmath.libmp import (from_int, from_man_exp, from_rational, fhalf, fnan, fnone, fone, fzero, mpf_abs, mpf_add, mpf_atan, mpf_atan2, mpf_cmp, mpf_cos, mpf_e, mpf_exp, mpf_log, mpf_lt, mpf_mul, mpf_neg, mpf_pi, mpf_pow, mpf_pow_int, mpf_shift, mpf_sin, mpf_sqrt, normalize, round_nearest, to_int, to_str) from mpmath.libmp import bitcount as mpmath_bitcount from mpmath.libmp.backend import MPZ from mpmath.libmp.libmpc import _infs_nan from mpmath.libmp.libmpf import dps_to_prec, prec_to_dps from mpmath.libmp.gammazeta import mpf_bernoulli from .compatibility import SYMPY_INTS from .sympify import sympify from .singleton import S from sympy.utilities.iterables import is_sequence LG10 = math.log(10, 2) rnd = round_nearest def bitcount(n): """Return smallest integer, b, such that |n|/2**b < 1. """ return mpmath_bitcount(abs(int(n))) # Used in a few places as placeholder values to denote exponents and # precision levels, e.g. of exact numbers. Must be careful to avoid # passing these to mpmath functions or returning them in final results. INF = float(mpmath_inf) MINUS_INF = float(-mpmath_inf) # ~= 100 digits. Real men set this to INF. DEFAULT_MAXPREC = 333 class PrecisionExhausted(ArithmeticError): pass #----------------------------------------------------------------------------# # # # Helper functions for arithmetic and complex parts # # # #----------------------------------------------------------------------------# """ An mpf value tuple is a tuple of integers (sign, man, exp, bc) representing a floating-point number: [1, -1][sign]*man*2**exp where sign is 0 or 1 and bc should correspond to the number of bits used to represent the mantissa (man) in binary notation, e.g. Explanation =========== >>> from sympy.core.evalf import bitcount >>> sign, man, exp, bc = 0, 5, 1, 3 >>> n = [1, -1][sign]*man*2**exp >>> n, bitcount(man) (10, 3) A temporary result is a tuple (re, im, re_acc, im_acc) where re and im are nonzero mpf value tuples representing approximate numbers, or None to denote exact zeros. re_acc, im_acc are integers denoting log2(e) where e is the estimated relative accuracy of the respective complex part, but may be anything if the corresponding complex part is None. """ def fastlog(x): """Fast approximation of log2(x) for an mpf value tuple x. Explanation =========== Calculated as exponent + width of mantissa. This is an approximation for two reasons: 1) it gives the ceil(log2(abs(x))) value and 2) it is too high by 1 in the case that x is an exact power of 2. Although this is easy to remedy by testing to see if the odd mpf mantissa is 1 (indicating that one was dealing with an exact power of 2) that would decrease the speed and is not necessary as this is only being used as an approximation for the number of bits in x. The correct return value could be written as "x[2] + (x[3] if x[1] != 1 else 0)". Since mpf tuples always have an odd mantissa, no check is done to see if the mantissa is a multiple of 2 (in which case the result would be too large by 1). Examples ======== >>> from sympy import log >>> from sympy.core.evalf import fastlog, bitcount >>> s, m, e = 0, 5, 1 >>> bc = bitcount(m) >>> n = [1, -1][s]*m*2**e >>> n, (log(n)/log(2)).evalf(2), fastlog((s, m, e, bc)) (10, 3.3, 4) """ if not x or x == fzero: return MINUS_INF return x[2] + x[3] def pure_complex(v, or_real=False): """Return a and b if v matches a + I*b where b is not zero and a and b are Numbers, else None. If `or_real` is True then 0 will be returned for `b` if `v` is a real number. Examples ======== >>> from sympy.core.evalf import pure_complex >>> from sympy import sqrt, I, S >>> a, b, surd = S(2), S(3), sqrt(2) >>> pure_complex(a) >>> pure_complex(a, or_real=True) (2, 0) >>> pure_complex(surd) >>> pure_complex(a + b*I) (2, 3) >>> pure_complex(I) (0, 1) """ h, t = v.as_coeff_Add() if not t: if or_real: return h, t return c, i = t.as_coeff_Mul() if i is S.ImaginaryUnit: return h, c def scaled_zero(mag, sign=1): """Return an mpf representing a power of two with magnitude ``mag`` and -1 for precision. Or, if ``mag`` is a scaled_zero tuple, then just remove the sign from within the list that it was initially wrapped in. Examples ======== >>> from sympy.core.evalf import scaled_zero >>> from sympy import Float >>> z, p = scaled_zero(100) >>> z, p (([0], 1, 100, 1), -1) >>> ok = scaled_zero(z) >>> ok (0, 1, 100, 1) >>> Float(ok) 1.26765060022823e+30 >>> Float(ok, p) 0.e+30 >>> ok, p = scaled_zero(100, -1) >>> Float(scaled_zero(ok), p) -0.e+30 """ if type(mag) is tuple and len(mag) == 4 and iszero(mag, scaled=True): return (mag[0][0],) + mag[1:] elif isinstance(mag, SYMPY_INTS): if sign not in [-1, 1]: raise ValueError('sign must be +/-1') rv, p = mpf_shift(fone, mag), -1 s = 0 if sign == 1 else 1 rv = ([s],) + rv[1:] return rv, p else: raise ValueError('scaled zero expects int or scaled_zero tuple.') def iszero(mpf, scaled=False): if not scaled: return not mpf or not mpf[1] and not mpf[-1] return mpf and type(mpf[0]) is list and mpf[1] == mpf[-1] == 1 def complex_accuracy(result): """ Returns relative accuracy of a complex number with given accuracies for the real and imaginary parts. The relative accuracy is defined in the complex norm sense as ||z|+|error|| / |z| where error is equal to (real absolute error) + (imag absolute error)*i. The full expression for the (logarithmic) error can be approximated easily by using the max norm to approximate the complex norm. In the worst case (re and im equal), this is wrong by a factor sqrt(2), or by log2(sqrt(2)) = 0.5 bit. """ re, im, re_acc, im_acc = result if not im: if not re: return INF return re_acc if not re: return im_acc re_size = fastlog(re) im_size = fastlog(im) absolute_error = max(re_size - re_acc, im_size - im_acc) relative_error = absolute_error - max(re_size, im_size) return -relative_error def get_abs(expr, prec, options): re, im, re_acc, im_acc = evalf(expr, prec + 2, options) if not re: re, re_acc, im, im_acc = im, im_acc, re, re_acc if im: if expr.is_number: abs_expr, _, acc, _ = evalf(abs(N(expr, prec + 2)), prec + 2, options) return abs_expr, None, acc, None else: if 'subs' in options: return libmp.mpc_abs((re, im), prec), None, re_acc, None return abs(expr), None, prec, None elif re: return mpf_abs(re), None, re_acc, None else: return None, None, None, None def get_complex_part(expr, no, prec, options): """no = 0 for real part, no = 1 for imaginary part""" workprec = prec i = 0 while 1: res = evalf(expr, workprec, options) value, accuracy = res[no::2] # XXX is the last one correct? Consider re((1+I)**2).n() if (not value) or accuracy >= prec or -value[2] > prec: return value, None, accuracy, None workprec += max(30, 2**i) i += 1 def evalf_abs(expr, prec, options): return get_abs(expr.args[0], prec, options) def evalf_re(expr, prec, options): return get_complex_part(expr.args[0], 0, prec, options) def evalf_im(expr, prec, options): return get_complex_part(expr.args[0], 1, prec, options) def finalize_complex(re, im, prec): if re == fzero and im == fzero: raise ValueError("got complex zero with unknown accuracy") elif re == fzero: return None, im, None, prec elif im == fzero: return re, None, prec, None size_re = fastlog(re) size_im = fastlog(im) if size_re > size_im: re_acc = prec im_acc = prec + min(-(size_re - size_im), 0) else: im_acc = prec re_acc = prec + min(-(size_im - size_re), 0) return re, im, re_acc, im_acc def chop_parts(value, prec): """ Chop off tiny real or complex parts. """ re, im, re_acc, im_acc = value # Method 1: chop based on absolute value if re and re not in _infs_nan and (fastlog(re) < -prec + 4): re, re_acc = None, None if im and im not in _infs_nan and (fastlog(im) < -prec + 4): im, im_acc = None, None # Method 2: chop if inaccurate and relatively small if re and im: delta = fastlog(re) - fastlog(im) if re_acc < 2 and (delta - re_acc <= -prec + 4): re, re_acc = None, None if im_acc < 2 and (delta - im_acc >= prec - 4): im, im_acc = None, None return re, im, re_acc, im_acc def check_target(expr, result, prec): a = complex_accuracy(result) if a < prec: raise PrecisionExhausted("Failed to distinguish the expression: \n\n%s\n\n" "from zero. Try simplifying the input, using chop=True, or providing " "a higher maxn for evalf" % (expr)) def get_integer_part(expr, no, options, return_ints=False): """ With no = 1, computes ceiling(expr) With no = -1, computes floor(expr) Note: this function either gives the exact result or signals failure. """ from sympy.functions.elementary.complexes import re, im # The expression is likely less than 2^30 or so assumed_size = 30 ire, iim, ire_acc, iim_acc = evalf(expr, assumed_size, options) # We now know the size, so we can calculate how much extra precision # (if any) is needed to get within the nearest integer if ire and iim: gap = max(fastlog(ire) - ire_acc, fastlog(iim) - iim_acc) elif ire: gap = fastlog(ire) - ire_acc elif iim: gap = fastlog(iim) - iim_acc else: # ... or maybe the expression was exactly zero if return_ints: return 0, 0 else: return None, None, None, None margin = 10 if gap >= -margin: prec = margin + assumed_size + gap ire, iim, ire_acc, iim_acc = evalf( expr, prec, options) else: prec = assumed_size # We can now easily find the nearest integer, but to find floor/ceil, we # must also calculate whether the difference to the nearest integer is # positive or negative (which may fail if very close). def calc_part(re_im, nexpr): from sympy.core.add import Add _, _, exponent, _ = nexpr is_int = exponent == 0 nint = int(to_int(nexpr, rnd)) if is_int: # make sure that we had enough precision to distinguish # between nint and the re or im part (re_im) of expr that # was passed to calc_part ire, iim, ire_acc, iim_acc = evalf( re_im - nint, 10, options) # don't need much precision assert not iim size = -fastlog(ire) + 2 # -ve b/c ire is less than 1 if size > prec: ire, iim, ire_acc, iim_acc = evalf( re_im, size, options) assert not iim nexpr = ire nint = int(to_int(nexpr, rnd)) _, _, new_exp, _ = ire is_int = new_exp == 0 if not is_int: # if there are subs and they all contain integer re/im parts # then we can (hopefully) safely substitute them into the # expression s = options.get('subs', False) if s: doit = True from sympy.core.compatibility import as_int # use strict=False with as_int because we take # 2.0 == 2 for v in s.values(): try: as_int(v, strict=False) except ValueError: try: [as_int(i, strict=False) for i in v.as_real_imag()] continue except (ValueError, AttributeError): doit = False break if doit: re_im = re_im.subs(s) re_im = Add(re_im, -nint, evaluate=False) x, _, x_acc, _ = evalf(re_im, 10, options) try: check_target(re_im, (x, None, x_acc, None), 3) except PrecisionExhausted: if not re_im.equals(0): raise PrecisionExhausted x = fzero nint += int(no*(mpf_cmp(x or fzero, fzero) == no)) nint = from_int(nint) return nint, INF re_, im_, re_acc, im_acc = None, None, None, None if ire: re_, re_acc = calc_part(re(expr, evaluate=False), ire) if iim: im_, im_acc = calc_part(im(expr, evaluate=False), iim) if return_ints: return int(to_int(re_ or fzero)), int(to_int(im_ or fzero)) return re_, im_, re_acc, im_acc def evalf_ceiling(expr, prec, options): return get_integer_part(expr.args[0], 1, options) def evalf_floor(expr, prec, options): return get_integer_part(expr.args[0], -1, options) #----------------------------------------------------------------------------# # # # Arithmetic operations # # # #----------------------------------------------------------------------------# def add_terms(terms, prec, target_prec): """ Helper for evalf_add. Adds a list of (mpfval, accuracy) terms. Returns ======= - None, None if there are no non-zero terms; - terms[0] if there is only 1 term; - scaled_zero if the sum of the terms produces a zero by cancellation e.g. mpfs representing 1 and -1 would produce a scaled zero which need special handling since they are not actually zero and they are purposely malformed to ensure that they can't be used in anything but accuracy calculations; - a tuple that is scaled to target_prec that corresponds to the sum of the terms. The returned mpf tuple will be normalized to target_prec; the input prec is used to define the working precision. XXX explain why this is needed and why one can't just loop using mpf_add """ terms = [t for t in terms if not iszero(t[0])] if not terms: return None, None elif len(terms) == 1: return terms[0] # see if any argument is NaN or oo and thus warrants a special return special = [] from sympy.core.numbers import Float for t in terms: arg = Float._new(t[0], 1) if arg is S.NaN or arg.is_infinite: special.append(arg) if special: from sympy.core.add import Add rv = evalf(Add(*special), prec + 4, {}) return rv[0], rv[2] working_prec = 2*prec sum_man, sum_exp, absolute_error = 0, 0, MINUS_INF for x, accuracy in terms: sign, man, exp, bc = x if sign: man = -man absolute_error = max(absolute_error, bc + exp - accuracy) delta = exp - sum_exp if exp >= sum_exp: # x much larger than existing sum? # first: quick test if ((delta > working_prec) and ((not sum_man) or delta - bitcount(abs(sum_man)) > working_prec)): sum_man = man sum_exp = exp else: sum_man += (man << delta) else: delta = -delta # x much smaller than existing sum? if delta - bc > working_prec: if not sum_man: sum_man, sum_exp = man, exp else: sum_man = (sum_man << delta) + man sum_exp = exp if not sum_man: return scaled_zero(absolute_error) if sum_man < 0: sum_sign = 1 sum_man = -sum_man else: sum_sign = 0 sum_bc = bitcount(sum_man) sum_accuracy = sum_exp + sum_bc - absolute_error r = normalize(sum_sign, sum_man, sum_exp, sum_bc, target_prec, rnd), sum_accuracy return r def evalf_add(v, prec, options): res = pure_complex(v) if res: h, c = res re, _, re_acc, _ = evalf(h, prec, options) im, _, im_acc, _ = evalf(c, prec, options) return re, im, re_acc, im_acc oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) i = 0 target_prec = prec while 1: options['maxprec'] = min(oldmaxprec, 2*prec) terms = [evalf(arg, prec + 10, options) for arg in v.args] re, re_acc = add_terms( [a[0::2] for a in terms if a[0]], prec, target_prec) im, im_acc = add_terms( [a[1::2] for a in terms if a[1]], prec, target_prec) acc = complex_accuracy((re, im, re_acc, im_acc)) if acc >= target_prec: if options.get('verbose'): print("ADD: wanted", target_prec, "accurate bits, got", re_acc, im_acc) break else: if (prec - target_prec) > options['maxprec']: break prec = prec + max(10 + 2**i, target_prec - acc) i += 1 if options.get('verbose'): print("ADD: restarting with prec", prec) options['maxprec'] = oldmaxprec if iszero(re, scaled=True): re = scaled_zero(re) if iszero(im, scaled=True): im = scaled_zero(im) return re, im, re_acc, im_acc def evalf_mul(v, prec, options): res = pure_complex(v) if res: # the only pure complex that is a mul is h*I _, h = res im, _, im_acc, _ = evalf(h, prec, options) return None, im, None, im_acc args = list(v.args) # see if any argument is NaN or oo and thus warrants a special return special = [] from sympy.core.numbers import Float for arg in args: arg = evalf(arg, prec, options) if arg[0] is None: continue arg = Float._new(arg[0], 1) if arg is S.NaN or arg.is_infinite: special.append(arg) if special: from sympy.core.mul import Mul special = Mul(*special) return evalf(special, prec + 4, {}) # With guard digits, multiplication in the real case does not destroy # accuracy. This is also true in the complex case when considering the # total accuracy; however accuracy for the real or imaginary parts # separately may be lower. acc = prec # XXX: big overestimate working_prec = prec + len(args) + 5 # Empty product is 1 start = man, exp, bc = MPZ(1), 0, 1 # First, we multiply all pure real or pure imaginary numbers. # direction tells us that the result should be multiplied by # I**direction; all other numbers get put into complex_factors # to be multiplied out after the first phase. last = len(args) direction = 0 args.append(S.One) complex_factors = [] for i, arg in enumerate(args): if i != last and pure_complex(arg): args[-1] = (args[-1]*arg).expand() continue elif i == last and arg is S.One: continue re, im, re_acc, im_acc = evalf(arg, working_prec, options) if re and im: complex_factors.append((re, im, re_acc, im_acc)) continue elif re: (s, m, e, b), w_acc = re, re_acc elif im: (s, m, e, b), w_acc = im, im_acc direction += 1 else: return None, None, None, None direction += 2*s man *= m exp += e bc += b if bc > 3*working_prec: man >>= working_prec exp += working_prec acc = min(acc, w_acc) sign = (direction & 2) >> 1 if not complex_factors: v = normalize(sign, man, exp, bitcount(man), prec, rnd) # multiply by i if direction & 1: return None, v, None, acc else: return v, None, acc, None else: # initialize with the first term if (man, exp, bc) != start: # there was a real part; give it an imaginary part re, im = (sign, man, exp, bitcount(man)), (0, MPZ(0), 0, 0) i0 = 0 else: # there is no real part to start (other than the starting 1) wre, wim, wre_acc, wim_acc = complex_factors[0] acc = min(acc, complex_accuracy((wre, wim, wre_acc, wim_acc))) re = wre im = wim i0 = 1 for wre, wim, wre_acc, wim_acc in complex_factors[i0:]: # acc is the overall accuracy of the product; we aren't # computing exact accuracies of the product. acc = min(acc, complex_accuracy((wre, wim, wre_acc, wim_acc))) use_prec = working_prec A = mpf_mul(re, wre, use_prec) B = mpf_mul(mpf_neg(im), wim, use_prec) C = mpf_mul(re, wim, use_prec) D = mpf_mul(im, wre, use_prec) re = mpf_add(A, B, use_prec) im = mpf_add(C, D, use_prec) if options.get('verbose'): print("MUL: wanted", prec, "accurate bits, got", acc) # multiply by I if direction & 1: re, im = mpf_neg(im), re return re, im, acc, acc def evalf_pow(v, prec, options): target_prec = prec base, exp = v.args # We handle x**n separately. This has two purposes: 1) it is much # faster, because we avoid calling evalf on the exponent, and 2) it # allows better handling of real/imaginary parts that are exactly zero if exp.is_Integer: p = exp.p # Exact if not p: return fone, None, prec, None # Exponentiation by p magnifies relative error by |p|, so the # base must be evaluated with increased precision if p is large prec += int(math.log(abs(p), 2)) re, im, re_acc, im_acc = evalf(base, prec + 5, options) # Real to integer power if re and not im: return mpf_pow_int(re, p, target_prec), None, target_prec, None # (x*I)**n = I**n * x**n if im and not re: z = mpf_pow_int(im, p, target_prec) case = p % 4 if case == 0: return z, None, target_prec, None if case == 1: return None, z, None, target_prec if case == 2: return mpf_neg(z), None, target_prec, None if case == 3: return None, mpf_neg(z), None, target_prec # Zero raised to an integer power if not re: return None, None, None, None # General complex number to arbitrary integer power re, im = libmp.mpc_pow_int((re, im), p, prec) # Assumes full accuracy in input return finalize_complex(re, im, target_prec) # Pure square root if exp is S.Half: xre, xim, _, _ = evalf(base, prec + 5, options) # General complex square root if xim: re, im = libmp.mpc_sqrt((xre or fzero, xim), prec) return finalize_complex(re, im, prec) if not xre: return None, None, None, None # Square root of a negative real number if mpf_lt(xre, fzero): return None, mpf_sqrt(mpf_neg(xre), prec), None, prec # Positive square root return mpf_sqrt(xre, prec), None, prec, None # We first evaluate the exponent to find its magnitude # This determines the working precision that must be used prec += 10 yre, yim, _, _ = evalf(exp, prec, options) # Special cases: x**0 if not (yre or yim): return fone, None, prec, None ysize = fastlog(yre) # Restart if too big # XXX: prec + ysize might exceed maxprec if ysize > 5: prec += ysize yre, yim, _, _ = evalf(exp, prec, options) # Pure exponential function; no need to evalf the base if base is S.Exp1: if yim: re, im = libmp.mpc_exp((yre or fzero, yim), prec) return finalize_complex(re, im, target_prec) return mpf_exp(yre, target_prec), None, target_prec, None xre, xim, _, _ = evalf(base, prec + 5, options) # 0**y if not (xre or xim): return None, None, None, None # (real ** complex) or (complex ** complex) if yim: re, im = libmp.mpc_pow( (xre or fzero, xim or fzero), (yre or fzero, yim), target_prec) return finalize_complex(re, im, target_prec) # complex ** real if xim: re, im = libmp.mpc_pow_mpf((xre or fzero, xim), yre, target_prec) return finalize_complex(re, im, target_prec) # negative ** real elif mpf_lt(xre, fzero): re, im = libmp.mpc_pow_mpf((xre, fzero), yre, target_prec) return finalize_complex(re, im, target_prec) # positive ** real else: return mpf_pow(xre, yre, target_prec), None, target_prec, None #----------------------------------------------------------------------------# # # # Special functions # # # #----------------------------------------------------------------------------# def evalf_trig(v, prec, options): """ This function handles sin and cos of complex arguments. TODO: should also handle tan of complex arguments. """ from sympy import cos, sin if isinstance(v, cos): func = mpf_cos elif isinstance(v, sin): func = mpf_sin else: raise NotImplementedError arg = v.args[0] # 20 extra bits is possibly overkill. It does make the need # to restart very unlikely xprec = prec + 20 re, im, re_acc, im_acc = evalf(arg, xprec, options) if im: if 'subs' in options: v = v.subs(options['subs']) return evalf(v._eval_evalf(prec), prec, options) if not re: if isinstance(v, cos): return fone, None, prec, None elif isinstance(v, sin): return None, None, None, None else: raise NotImplementedError # For trigonometric functions, we are interested in the # fixed-point (absolute) accuracy of the argument. xsize = fastlog(re) # Magnitude <= 1.0. OK to compute directly, because there is no # danger of hitting the first root of cos (with sin, magnitude # <= 2.0 would actually be ok) if xsize < 1: return func(re, prec, rnd), None, prec, None # Very large if xsize >= 10: xprec = prec + xsize re, im, re_acc, im_acc = evalf(arg, xprec, options) # Need to repeat in case the argument is very close to a # multiple of pi (or pi/2), hitting close to a root while 1: y = func(re, prec, rnd) ysize = fastlog(y) gap = -ysize accuracy = (xprec - xsize) - gap if accuracy < prec: if options.get('verbose'): print("SIN/COS", accuracy, "wanted", prec, "gap", gap) print(to_str(y, 10)) if xprec > options.get('maxprec', DEFAULT_MAXPREC): return y, None, accuracy, None xprec += gap re, im, re_acc, im_acc = evalf(arg, xprec, options) continue else: return y, None, prec, None def evalf_log(expr, prec, options): from sympy import Abs, Add, log if len(expr.args)>1: expr = expr.doit() return evalf(expr, prec, options) arg = expr.args[0] workprec = prec + 10 xre, xim, xacc, _ = evalf(arg, workprec, options) # evalf can return NoneTypes if chop=True # issue 18516, 19623 if xre is xim is None: # Dear reviewer, I do not know what -inf is; # it looks to be (1, 0, -789, -3) # but I'm not sure in general, # so we just let mpmath figure # it out by taking log of 0 directly. # It would be better to return -inf instead. xre = fzero if xim: # XXX: use get_abs etc instead re = evalf_log( log(Abs(arg, evaluate=False), evaluate=False), prec, options) im = mpf_atan2(xim, xre or fzero, prec) return re[0], im, re[2], prec imaginary_term = (mpf_cmp(xre, fzero) < 0) re = mpf_log(mpf_abs(xre), prec, rnd) size = fastlog(re) if prec - size > workprec and re != fzero: # We actually need to compute 1+x accurately, not x arg = Add(S.NegativeOne, arg, evaluate=False) xre, xim, _, _ = evalf_add(arg, prec, options) prec2 = workprec - fastlog(xre) # xre is now x - 1 so we add 1 back here to calculate x re = mpf_log(mpf_abs(mpf_add(xre, fone, prec2)), prec, rnd) re_acc = prec if imaginary_term: return re, mpf_pi(prec), re_acc, prec else: return re, None, re_acc, None def evalf_atan(v, prec, options): arg = v.args[0] xre, xim, reacc, imacc = evalf(arg, prec + 5, options) if xre is xim is None: return (None,)*4 if xim: raise NotImplementedError return mpf_atan(xre, prec, rnd), None, prec, None def evalf_subs(prec, subs): """ Change all Float entries in `subs` to have precision prec. """ newsubs = {} for a, b in subs.items(): b = S(b) if b.is_Float: b = b._eval_evalf(prec) newsubs[a] = b return newsubs def evalf_piecewise(expr, prec, options): from sympy import Float, Integer if 'subs' in options: expr = expr.subs(evalf_subs(prec, options['subs'])) newopts = options.copy() del newopts['subs'] if hasattr(expr, 'func'): return evalf(expr, prec, newopts) if type(expr) == float: return evalf(Float(expr), prec, newopts) if type(expr) == int: return evalf(Integer(expr), prec, newopts) # We still have undefined symbols raise NotImplementedError def evalf_bernoulli(expr, prec, options): arg = expr.args[0] if not arg.is_Integer: raise ValueError("Bernoulli number index must be an integer") n = int(arg) b = mpf_bernoulli(n, prec, rnd) if b == fzero: return None, None, None, None return b, None, prec, None #----------------------------------------------------------------------------# # # # High-level operations # # # #----------------------------------------------------------------------------# def as_mpmath(x, prec, options): from sympy.core.numbers import Infinity, NegativeInfinity, Zero x = sympify(x) if isinstance(x, Zero) or x == 0: return mpf(0) if isinstance(x, Infinity): return mpf('inf') if isinstance(x, NegativeInfinity): return mpf('-inf') # XXX re, im, _, _ = evalf(x, prec, options) if im: return mpc(re or fzero, im) return mpf(re) def do_integral(expr, prec, options): func = expr.args[0] x, xlow, xhigh = expr.args[1] if xlow == xhigh: xlow = xhigh = 0 elif x not in func.free_symbols: # only the difference in limits matters in this case # so if there is a symbol in common that will cancel # out when taking the difference, then use that # difference if xhigh.free_symbols & xlow.free_symbols: diff = xhigh - xlow if diff.is_number: xlow, xhigh = 0, diff oldmaxprec = options.get('maxprec', DEFAULT_MAXPREC) options['maxprec'] = min(oldmaxprec, 2*prec) with workprec(prec + 5): xlow = as_mpmath(xlow, prec + 15, options) xhigh = as_mpmath(xhigh, prec + 15, options) # Integration is like summation, and we can phone home from # the integrand function to update accuracy summation style # Note that this accuracy is inaccurate, since it fails # to account for the variable quadrature weights, # but it is better than nothing from sympy import cos, sin, Wild have_part = [False, False] max_real_term = [MINUS_INF] max_imag_term = [MINUS_INF] def f(t): re, im, re_acc, im_acc = evalf(func, mp.prec, {'subs': {x: t}}) have_part[0] = re or have_part[0] have_part[1] = im or have_part[1] max_real_term[0] = max(max_real_term[0], fastlog(re)) max_imag_term[0] = max(max_imag_term[0], fastlog(im)) if im: return mpc(re or fzero, im) return mpf(re or fzero) if options.get('quad') == 'osc': A = Wild('A', exclude=[x]) B = Wild('B', exclude=[x]) D = Wild('D') m = func.match(cos(A*x + B)*D) if not m: m = func.match(sin(A*x + B)*D) if not m: raise ValueError("An integrand of the form sin(A*x+B)*f(x) " "or cos(A*x+B)*f(x) is required for oscillatory quadrature") period = as_mpmath(2*S.Pi/m[A], prec + 15, options) result = quadosc(f, [xlow, xhigh], period=period) # XXX: quadosc does not do error detection yet quadrature_error = MINUS_INF else: result, quadrature_error = quadts(f, [xlow, xhigh], error=1) quadrature_error = fastlog(quadrature_error._mpf_) options['maxprec'] = oldmaxprec if have_part[0]: re = result.real._mpf_ if re == fzero: re, re_acc = scaled_zero( min(-prec, -max_real_term[0], -quadrature_error)) re = scaled_zero(re) # handled ok in evalf_integral else: re_acc = -max(max_real_term[0] - fastlog(re) - prec, quadrature_error) else: re, re_acc = None, None if have_part[1]: im = result.imag._mpf_ if im == fzero: im, im_acc = scaled_zero( min(-prec, -max_imag_term[0], -quadrature_error)) im = scaled_zero(im) # handled ok in evalf_integral else: im_acc = -max(max_imag_term[0] - fastlog(im) - prec, quadrature_error) else: im, im_acc = None, None result = re, im, re_acc, im_acc return result def evalf_integral(expr, prec, options): limits = expr.limits if len(limits) != 1 or len(limits[0]) != 3: raise NotImplementedError workprec = prec i = 0 maxprec = options.get('maxprec', INF) while 1: result = do_integral(expr, workprec, options) accuracy = complex_accuracy(result) if accuracy >= prec: # achieved desired precision break if workprec >= maxprec: # can't increase accuracy any more break if accuracy == -1: # maybe the answer really is zero and maybe we just haven't increased # the precision enough. So increase by doubling to not take too long # to get to maxprec. workprec *= 2 else: workprec += max(prec, 2**i) workprec = min(workprec, maxprec) i += 1 return result def check_convergence(numer, denom, n): """ Returns ======= (h, g, p) where -- h is: > 0 for convergence of rate 1/factorial(n)**h < 0 for divergence of rate factorial(n)**(-h) = 0 for geometric or polynomial convergence or divergence -- abs(g) is: > 1 for geometric convergence of rate 1/h**n < 1 for geometric divergence of rate h**n = 1 for polynomial convergence or divergence (g < 0 indicates an alternating series) -- p is: > 1 for polynomial convergence of rate 1/n**h <= 1 for polynomial divergence of rate n**(-h) """ from sympy import Poly npol = Poly(numer, n) dpol = Poly(denom, n) p = npol.degree() q = dpol.degree() rate = q - p if rate: return rate, None, None constant = dpol.LC() / npol.LC() if abs(constant) != 1: return rate, constant, None if npol.degree() == dpol.degree() == 0: return rate, constant, 0 pc = npol.all_coeffs()[1] qc = dpol.all_coeffs()[1] return rate, constant, (qc - pc)/dpol.LC() def hypsum(expr, n, start, prec): """ Sum a rapidly convergent infinite hypergeometric series with given general term, e.g. e = hypsum(1/factorial(n), n). The quotient between successive terms must be a quotient of integer polynomials. """ from sympy import Float, hypersimp, lambdify if prec == float('inf'): raise NotImplementedError('does not support inf prec') if start: expr = expr.subs(n, n + start) hs = hypersimp(expr, n) if hs is None: raise NotImplementedError("a hypergeometric series is required") num, den = hs.as_numer_denom() func1 = lambdify(n, num) func2 = lambdify(n, den) h, g, p = check_convergence(num, den, n) if h < 0: raise ValueError("Sum diverges like (n!)^%i" % (-h)) term = expr.subs(n, 0) if not term.is_Rational: raise NotImplementedError("Non rational term functionality is not implemented.") # Direct summation if geometric or faster if h > 0 or (h == 0 and abs(g) > 1): term = (MPZ(term.p) << prec) // term.q s = term k = 1 while abs(term) > 5: term *= MPZ(func1(k - 1)) term //= MPZ(func2(k - 1)) s += term k += 1 return from_man_exp(s, -prec) else: alt = g < 0 if abs(g) < 1: raise ValueError("Sum diverges like (%i)^n" % abs(1/g)) if p < 1 or (p == 1 and not alt): raise ValueError("Sum diverges like n^%i" % (-p)) # We have polynomial convergence: use Richardson extrapolation vold = None ndig = prec_to_dps(prec) while True: # Need to use at least quad precision because a lot of cancellation # might occur in the extrapolation process; we check the answer to # make sure that the desired precision has been reached, too. prec2 = 4*prec term0 = (MPZ(term.p) << prec2) // term.q def summand(k, _term=[term0]): if k: k = int(k) _term[0] *= MPZ(func1(k - 1)) _term[0] //= MPZ(func2(k - 1)) return make_mpf(from_man_exp(_term[0], -prec2)) with workprec(prec): v = nsum(summand, [0, mpmath_inf], method='richardson') vf = Float(v, ndig) if vold is not None and vold == vf: break prec += prec # double precision each time vold = vf return v._mpf_ def evalf_prod(expr, prec, options): from sympy import Sum if all((l[1] - l[2]).is_Integer for l in expr.limits): re, im, re_acc, im_acc = evalf(expr.doit(), prec=prec, options=options) else: re, im, re_acc, im_acc = evalf(expr.rewrite(Sum), prec=prec, options=options) return re, im, re_acc, im_acc def evalf_sum(expr, prec, options): from sympy import Float if 'subs' in options: expr = expr.subs(options['subs']) func = expr.function limits = expr.limits if len(limits) != 1 or len(limits[0]) != 3: raise NotImplementedError if func.is_zero: return None, None, prec, None prec2 = prec + 10 try: n, a, b = limits[0] if b != S.Infinity or a != int(a): raise NotImplementedError # Use fast hypergeometric summation if possible v = hypsum(func, n, int(a), prec2) delta = prec - fastlog(v) if fastlog(v) < -10: v = hypsum(func, n, int(a), delta) return v, None, min(prec, delta), None except NotImplementedError: # Euler-Maclaurin summation for general series eps = Float(2.0)**(-prec) for i in range(1, 5): m = n = 2**i * prec s, err = expr.euler_maclaurin(m=m, n=n, eps=eps, eval_integral=False) err = err.evalf() if err <= eps: break err = fastlog(evalf(abs(err), 20, options)[0]) re, im, re_acc, im_acc = evalf(s, prec2, options) if re_acc is None: re_acc = -err if im_acc is None: im_acc = -err return re, im, re_acc, im_acc #----------------------------------------------------------------------------# # # # Symbolic interface # # # #----------------------------------------------------------------------------# def evalf_symbol(x, prec, options): val = options['subs'][x] if isinstance(val, mpf): if not val: return None, None, None, None return val._mpf_, None, prec, None else: if not '_cache' in options: options['_cache'] = {} cache = options['_cache'] cached, cached_prec = cache.get(x, (None, MINUS_INF)) if cached_prec >= prec: return cached v = evalf(sympify(val), prec, options) cache[x] = (v, prec) return v evalf_table = None def _create_evalf_table(): global evalf_table from sympy.functions.combinatorial.numbers import bernoulli from sympy.concrete.products import Product from sympy.concrete.summations import Sum from sympy.core.add import Add from sympy.core.mul import Mul from sympy.core.numbers import Exp1, Float, Half, ImaginaryUnit, Integer, NaN, NegativeOne, One, Pi, Rational, Zero from sympy.core.power import Pow from sympy.core.symbol import Dummy, Symbol from sympy.functions.elementary.complexes import Abs, im, re from sympy.functions.elementary.exponential import exp, log from sympy.functions.elementary.integers import ceiling, floor from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import atan, cos, sin from sympy.integrals.integrals import Integral evalf_table = { Symbol: evalf_symbol, Dummy: evalf_symbol, Float: lambda x, prec, options: (x._mpf_, None, prec, None), Rational: lambda x, prec, options: (from_rational(x.p, x.q, prec), None, prec, None), Integer: lambda x, prec, options: (from_int(x.p, prec), None, prec, None), Zero: lambda x, prec, options: (None, None, prec, None), One: lambda x, prec, options: (fone, None, prec, None), Half: lambda x, prec, options: (fhalf, None, prec, None), Pi: lambda x, prec, options: (mpf_pi(prec), None, prec, None), Exp1: lambda x, prec, options: (mpf_e(prec), None, prec, None), ImaginaryUnit: lambda x, prec, options: (None, fone, None, prec), NegativeOne: lambda x, prec, options: (fnone, None, prec, None), NaN: lambda x, prec, options: (fnan, None, prec, None), exp: lambda x, prec, options: evalf_pow( Pow(S.Exp1, x.exp, evaluate=False), prec, options), cos: evalf_trig, sin: evalf_trig, Add: evalf_add, Mul: evalf_mul, Pow: evalf_pow, log: evalf_log, atan: evalf_atan, Abs: evalf_abs, re: evalf_re, im: evalf_im, floor: evalf_floor, ceiling: evalf_ceiling, Integral: evalf_integral, Sum: evalf_sum, Product: evalf_prod, Piecewise: evalf_piecewise, bernoulli: evalf_bernoulli, } def evalf(x, prec, options): """ Evaluate the ``Basic`` instance, ``x`` to a binary precision of ``prec``. This function is supposed to be used internally. Parameters ========== x : Basic The formula to evaluate to a float. prec : int The binary precision that the output should have. options : dict A dictionary with the same entries as ``EvalfMixin.evalf`` and in addition, ``maxprec`` which is the maximum working precision. Returns ======= An optional tuple, ``(re, im, re_acc, im_acc)`` which are the real, imaginary, real accuracy and imaginary accuracy respectively. ``re`` is an mpf value tuple and so is ``im``. ``re_acc`` and ``im_acc`` are ints. NB: all these return values can be ``None``. If all values are ``None``, then that represents 0. Note that 0 is also represented as ``fzero = (0, 0, 0, 0)``. """ from sympy import re as re_, im as im_ try: rf = evalf_table[x.func] r = rf(x, prec, options) except KeyError: # Fall back to ordinary evalf if possible if 'subs' in options: x = x.subs(evalf_subs(prec, options['subs'])) xe = x._eval_evalf(prec) if xe is None: raise NotImplementedError as_real_imag = getattr(xe, "as_real_imag", None) if as_real_imag is None: raise NotImplementedError # e.g. FiniteSet(-1.0, 1.0).evalf() re, im = as_real_imag() if re.has(re_) or im.has(im_): raise NotImplementedError if re == 0: re = None reprec = None elif re.is_number: re = re._to_mpmath(prec, allow_ints=False)._mpf_ reprec = prec else: raise NotImplementedError if im == 0: im = None imprec = None elif im.is_number: im = im._to_mpmath(prec, allow_ints=False)._mpf_ imprec = prec else: raise NotImplementedError r = re, im, reprec, imprec if options.get("verbose"): print("### input", x) print("### output", to_str(r[0] or fzero, 50)) print("### raw", r) # r[0], r[2] print() chop = options.get('chop', False) if chop: if chop is True: chop_prec = prec else: # convert (approximately) from given tolerance; # the formula here will will make 1e-i rounds to 0 for # i in the range +/-27 while 2e-i will not be chopped chop_prec = int(round(-3.321*math.log10(chop) + 2.5)) if chop_prec == 3: chop_prec -= 1 r = chop_parts(r, chop_prec) if options.get("strict"): check_target(x, r, prec) return r class EvalfMixin: """Mixin class adding evalf capabililty.""" __slots__ = () # type: Tuple[str, ...] def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): """ Evaluate the given formula to an accuracy of *n* digits. Parameters ========== subs : dict, optional Substitute numerical values for symbols, e.g. ``subs={x:3, y:1+pi}``. The substitutions must be given as a dictionary. maxn : int, optional Allow a maximum temporary working precision of maxn digits. chop : bool or number, optional Specifies how to replace tiny real or imaginary parts in subresults by exact zeros. When ``True`` the chop value defaults to standard precision. Otherwise the chop value is used to determine the magnitude of "small" for purposes of chopping. >>> from sympy import N >>> x = 1e-4 >>> N(x, chop=True) 0.000100000000000000 >>> N(x, chop=1e-5) 0.000100000000000000 >>> N(x, chop=1e-4) 0 strict : bool, optional Raise ``PrecisionExhausted`` if any subresult fails to evaluate to full accuracy, given the available maxprec. quad : str, optional Choose algorithm for numerical quadrature. By default, tanh-sinh quadrature is used. For oscillatory integrals on an infinite interval, try ``quad='osc'``. verbose : bool, optional Print debug information. Notes ===== When Floats are naively substituted into an expression, precision errors may adversely affect the result. For example, adding 1e16 (a Float) to 1 will truncate to 1e16; if 1e16 is then subtracted, the result will be 0. That is exactly what happens in the following: >>> from sympy.abc import x, y, z >>> values = {x: 1e16, y: 1, z: 1e16} >>> (x + y - z).subs(values) 0 Using the subs argument for evalf is the accurate way to evaluate such an expression: >>> (x + y - z).evalf(subs=values) 1.00000000000000 """ from sympy import Float, Number n = n if n is not None else 15 if subs and is_sequence(subs): raise TypeError('subs must be given as a dictionary') # for sake of sage that doesn't like evalf(1) if n == 1 and isinstance(self, Number): from sympy.core.expr import _mag rv = self.evalf(2, subs, maxn, chop, strict, quad, verbose) m = _mag(rv) rv = rv.round(1 - m) return rv if not evalf_table: _create_evalf_table() prec = dps_to_prec(n) options = {'maxprec': max(prec, int(maxn*LG10)), 'chop': chop, 'strict': strict, 'verbose': verbose} if subs is not None: options['subs'] = subs if quad is not None: options['quad'] = quad try: result = evalf(self, prec + 4, options) except NotImplementedError: # Fall back to the ordinary evalf if hasattr(self, 'subs') and subs is not None: # issue 20291 v = self.subs(subs)._eval_evalf(prec) else: v = self._eval_evalf(prec) if v is None: return self elif not v.is_number: return v try: # If the result is numerical, normalize it result = evalf(v, prec, options) except NotImplementedError: # Probably contains symbols or unknown functions return v re, im, re_acc, im_acc = result if re: p = max(min(prec, re_acc), 1) re = Float._new(re, p) else: re = S.Zero if im: p = max(min(prec, im_acc), 1) im = Float._new(im, p) return re + im*S.ImaginaryUnit else: return re n = evalf def _evalf(self, prec): """Helper for evalf. Does the same thing but takes binary precision""" r = self._eval_evalf(prec) if r is None: r = self return r def _eval_evalf(self, prec): return def _to_mpmath(self, prec, allow_ints=True): # mpmath functions accept ints as input errmsg = "cannot convert to mpmath number" if allow_ints and self.is_Integer: return self.p if hasattr(self, '_as_mpf_val'): return make_mpf(self._as_mpf_val(prec)) try: re, im, _, _ = evalf(self, prec, {}) if im: if not re: re = fzero return make_mpc((re, im)) elif re: return make_mpf(re) else: return make_mpf(fzero) except NotImplementedError: v = self._eval_evalf(prec) if v is None: raise ValueError(errmsg) if v.is_Float: return make_mpf(v._mpf_) # Number + Number*I is also fine re, im = v.as_real_imag() if allow_ints and re.is_Integer: re = from_int(re.p) elif re.is_Float: re = re._mpf_ else: raise ValueError(errmsg) if allow_ints and im.is_Integer: im = from_int(im.p) elif im.is_Float: im = im._mpf_ else: raise ValueError(errmsg) return make_mpc((re, im)) def N(x, n=15, **options): r""" Calls x.evalf(n, \*\*options). Explanations ============ Both .n() and N() are equivalent to .evalf(); use the one that you like better. See also the docstring of .evalf() for information on the options. Examples ======== >>> from sympy import Sum, oo, N >>> from sympy.abc import k >>> Sum(1/k**k, (k, 1, oo)) Sum(k**(-k), (k, 1, oo)) >>> N(_, 4) 1.291 """ # by using rational=True, any evaluation of a string # will be done using exact values for the Floats return sympify(x, rational=True).evalf(n, **options) sympy-sympy-1.9/sympy/core/expr.py000066400000000000000000004222231412543434000173710ustar00rootroot00000000000000from typing import Tuple as tTuple from collections.abc import Iterable from functools import reduce from .sympify import sympify, _sympify, SympifyError from .basic import Basic, Atom from .singleton import S from .evalf import EvalfMixin, pure_complex from .decorators import call_highest_priority, sympify_method_args, sympify_return from .cache import cacheit from .compatibility import as_int, default_sort_key from .kind import NumberKind from sympy.utilities.misc import func_name from mpmath.libmp import mpf_log, prec_to_dps from collections import defaultdict @sympify_method_args class Expr(Basic, EvalfMixin): """ Base class for algebraic expressions. Explanation =========== Everything that requires arithmetic operations to be defined should subclass this class, instead of Basic (which should be used only for argument storage and expression manipulation, i.e. pattern matching, substitutions, etc). If you want to override the comparisons of expressions: Should use _eval_is_ge for inequality, or _eval_is_eq, with multiple dispatch. _eval_is_ge return true if x >= y, false if x < y, and None if the two types are not comparable or the comparison is indeterminate See Also ======== sympy.core.basic.Basic """ __slots__ = () # type: tTuple[str, ...] is_scalar = True # self derivative is 1 @property def _diff_wrt(self): """Return True if one can differentiate with respect to this object, else False. Explanation =========== Subclasses such as Symbol, Function and Derivative return True to enable derivatives wrt them. The implementation in Derivative separates the Symbol and non-Symbol (_diff_wrt=True) variables and temporarily converts the non-Symbols into Symbols when performing the differentiation. By default, any object deriving from Expr will behave like a scalar with self.diff(self) == 1. If this is not desired then the object must also set `is_scalar = False` or else define an _eval_derivative routine. Note, see the docstring of Derivative for how this should work mathematically. In particular, note that expr.subs(yourclass, Symbol) should be well-defined on a structural level, or this will lead to inconsistent results. Examples ======== >>> from sympy import Expr >>> e = Expr() >>> e._diff_wrt False >>> class MyScalar(Expr): ... _diff_wrt = True ... >>> MyScalar().diff(MyScalar()) 1 >>> class MySymbol(Expr): ... _diff_wrt = True ... is_scalar = False ... >>> MySymbol().diff(MySymbol()) Derivative(MySymbol(), MySymbol()) """ return False @cacheit def sort_key(self, order=None): coeff, expr = self.as_coeff_Mul() if expr.is_Pow: if expr.base is S.Exp1: # If we remove this, many doctests will go crazy: # (keeps E**x sorted like the exp(x) function, # part of exp(x) to E**x transition) expr, exp = Function("exp")(expr.exp), S.One else: expr, exp = expr.args else: expr, exp = expr, S.One if expr.is_Dummy: args = (expr.sort_key(),) elif expr.is_Atom: args = (str(expr),) else: if expr.is_Add: args = expr.as_ordered_terms(order=order) elif expr.is_Mul: args = expr.as_ordered_factors(order=order) else: args = expr.args args = tuple( [ default_sort_key(arg, order=order) for arg in args ]) args = (len(args), tuple(args)) exp = exp.sort_key(order=order) return expr.class_key(), args, exp, coeff def __hash__(self) -> int: # hash cannot be cached using cache_it because infinite recurrence # occurs as hash is needed for setting cache dictionary keys h = self._mhash if h is None: h = hash((type(self).__name__,) + self._hashable_content()) self._mhash = h return h def _hashable_content(self): """Return a tuple of information about self that can be used to compute the hash. If a class defines additional attributes, like ``name`` in Symbol, then this method should be updated accordingly to return such relevant attributes. Defining more than _hashable_content is necessary if __eq__ has been defined by a class. See note about this in Basic.__eq__.""" return self._args def __eq__(self, other): try: other = _sympify(other) if not isinstance(other, Expr): return False except (SympifyError, SyntaxError): return False # check for pure number expr if not (self.is_Number and other.is_Number) and ( type(self) != type(other)): return False a, b = self._hashable_content(), other._hashable_content() if a != b: return False # check number *in* an expression for a, b in zip(a, b): if not isinstance(a, Expr): continue if a.is_Number and type(a) != type(b): return False return True # *************** # * Arithmetics * # *************** # Expr and its sublcasses use _op_priority to determine which object # passed to a binary special method (__mul__, etc.) will handle the # operation. In general, the 'call_highest_priority' decorator will choose # the object with the highest _op_priority to handle the call. # Custom subclasses that want to define their own binary special methods # should set an _op_priority value that is higher than the default. # # **NOTE**: # This is a temporary fix, and will eventually be replaced with # something better and more powerful. See issue 5510. _op_priority = 10.0 @property def _add_handler(self): return Add @property def _mul_handler(self): return Mul def __pos__(self): return self def __neg__(self): # Mul has its own __neg__ routine, so we just # create a 2-args Mul with the -1 in the canonical # slot 0. c = self.is_commutative return Mul._from_args((S.NegativeOne, self), c) def __abs__(self): from sympy import Abs return Abs(self) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__radd__') def __add__(self, other): return Add(self, other) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__add__') def __radd__(self, other): return Add(other, self) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__rsub__') def __sub__(self, other): return Add(self, -other) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__sub__') def __rsub__(self, other): return Add(other, -self) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__rmul__') def __mul__(self, other): return Mul(self, other) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__mul__') def __rmul__(self, other): return Mul(other, self) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__rpow__') def _pow(self, other): return Pow(self, other) def __pow__(self, other, mod=None): if mod is None: return self._pow(other) try: _self, other, mod = as_int(self), as_int(other), as_int(mod) if other >= 0: return pow(_self, other, mod) else: from sympy.core.numbers import mod_inverse return mod_inverse(pow(_self, -other, mod), mod) except ValueError: power = self._pow(other) try: return power%mod except TypeError: return NotImplemented @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__pow__') def __rpow__(self, other): return Pow(other, self) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__rtruediv__') def __truediv__(self, other): denom = Pow(other, S.NegativeOne) if self is S.One: return denom else: return Mul(self, denom) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__truediv__') def __rtruediv__(self, other): denom = Pow(self, S.NegativeOne) if other is S.One: return denom else: return Mul(other, denom) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__rmod__') def __mod__(self, other): return Mod(self, other) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__mod__') def __rmod__(self, other): return Mod(other, self) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__rfloordiv__') def __floordiv__(self, other): from sympy.functions.elementary.integers import floor return floor(self / other) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__floordiv__') def __rfloordiv__(self, other): from sympy.functions.elementary.integers import floor return floor(other / self) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__rdivmod__') def __divmod__(self, other): from sympy.functions.elementary.integers import floor return floor(self / other), Mod(self, other) @sympify_return([('other', 'Expr')], NotImplemented) @call_highest_priority('__divmod__') def __rdivmod__(self, other): from sympy.functions.elementary.integers import floor return floor(other / self), Mod(other, self) def __int__(self): # Although we only need to round to the units position, we'll # get one more digit so the extra testing below can be avoided # unless the rounded value rounded to an integer, e.g. if an # expression were equal to 1.9 and we rounded to the unit position # we would get a 2 and would not know if this rounded up or not # without doing a test (as done below). But if we keep an extra # digit we know that 1.9 is not the same as 1 and there is no # need for further testing: our int value is correct. If the value # were 1.99, however, this would round to 2.0 and our int value is # off by one. So...if our round value is the same as the int value # (regardless of how much extra work we do to calculate extra decimal # places) we need to test whether we are off by one. from sympy import Dummy if not self.is_number: raise TypeError("can't convert symbols to int") r = self.round(2) if not r.is_Number: raise TypeError("can't convert complex to int") if r in (S.NaN, S.Infinity, S.NegativeInfinity): raise TypeError("can't convert %s to int" % r) i = int(r) if not i: return 0 # off-by-one check if i == r and not (self - i).equals(0): isign = 1 if i > 0 else -1 x = Dummy() # in the following (self - i).evalf(2) will not always work while # (self - r).evalf(2) and the use of subs does; if the test that # was added when this comment was added passes, it might be safe # to simply use sign to compute this rather than doing this by hand: diff_sign = 1 if (self - x).evalf(2, subs={x: i}) > 0 else -1 if diff_sign != isign: i -= isign return i def __float__(self): # Don't bother testing if it's a number; if it's not this is going # to fail, and if it is we still need to check that it evalf'ed to # a number. result = self.evalf() if result.is_Number: return float(result) if result.is_number and result.as_real_imag()[1]: raise TypeError("can't convert complex to float") raise TypeError("can't convert expression to float") def __complex__(self): result = self.evalf() re, im = result.as_real_imag() return complex(float(re), float(im)) @sympify_return([('other', 'Expr')], NotImplemented) def __ge__(self, other): from .relational import GreaterThan return GreaterThan(self, other) @sympify_return([('other', 'Expr')], NotImplemented) def __le__(self, other): from .relational import LessThan return LessThan(self, other) @sympify_return([('other', 'Expr')], NotImplemented) def __gt__(self, other): from .relational import StrictGreaterThan return StrictGreaterThan(self, other) @sympify_return([('other', 'Expr')], NotImplemented) def __lt__(self, other): from .relational import StrictLessThan return StrictLessThan(self, other) def __trunc__(self): if not self.is_number: raise TypeError("can't truncate symbols and expressions") else: return Integer(self) @staticmethod def _from_mpmath(x, prec): from sympy import Float if hasattr(x, "_mpf_"): return Float._new(x._mpf_, prec) elif hasattr(x, "_mpc_"): re, im = x._mpc_ re = Float._new(re, prec) im = Float._new(im, prec)*S.ImaginaryUnit return re + im else: raise TypeError("expected mpmath number (mpf or mpc)") @property def is_number(self): """Returns True if ``self`` has no free symbols and no undefined functions (AppliedUndef, to be precise). It will be faster than ``if not self.free_symbols``, however, since ``is_number`` will fail as soon as it hits a free symbol or undefined function. Examples ======== >>> from sympy import Integral, cos, sin, pi >>> from sympy.core.function import Function >>> from sympy.abc import x >>> f = Function('f') >>> x.is_number False >>> f(1).is_number False >>> (2*x).is_number False >>> (2 + Integral(2, x)).is_number False >>> (2 + Integral(2, (x, 1, 2))).is_number True Not all numbers are Numbers in the SymPy sense: >>> pi.is_number, pi.is_Number (True, False) If something is a number it should evaluate to a number with real and imaginary parts that are Numbers; the result may not be comparable, however, since the real and/or imaginary part of the result may not have precision. >>> cos(1).is_number and cos(1).is_comparable True >>> z = cos(1)**2 + sin(1)**2 - 1 >>> z.is_number True >>> z.is_comparable False See Also ======== sympy.core.basic.Basic.is_comparable """ return all(obj.is_number for obj in self.args) def _random(self, n=None, re_min=-1, im_min=-1, re_max=1, im_max=1): """Return self evaluated, if possible, replacing free symbols with random complex values, if necessary. Explanation =========== The random complex value for each free symbol is generated by the random_complex_number routine giving real and imaginary parts in the range given by the re_min, re_max, im_min, and im_max values. The returned value is evaluated to a precision of n (if given) else the maximum of 15 and the precision needed to get more than 1 digit of precision. If the expression could not be evaluated to a number, or could not be evaluated to more than 1 digit of precision, then None is returned. Examples ======== >>> from sympy import sqrt >>> from sympy.abc import x, y >>> x._random() # doctest: +SKIP 0.0392918155679172 + 0.916050214307199*I >>> x._random(2) # doctest: +SKIP -0.77 - 0.87*I >>> (x + y/2)._random(2) # doctest: +SKIP -0.57 + 0.16*I >>> sqrt(2)._random(2) 1.4 See Also ======== sympy.testing.randtest.random_complex_number """ free = self.free_symbols prec = 1 if free: from sympy.testing.randtest import random_complex_number a, c, b, d = re_min, re_max, im_min, im_max reps = dict(list(zip(free, [random_complex_number(a, b, c, d, rational=True) for zi in free]))) try: nmag = abs(self.evalf(2, subs=reps)) except (ValueError, TypeError): # if an out of range value resulted in evalf problems # then return None -- XXX is there a way to know how to # select a good random number for a given expression? # e.g. when calculating n! negative values for n should not # be used return None else: reps = {} nmag = abs(self.evalf(2)) if not hasattr(nmag, '_prec'): # e.g. exp_polar(2*I*pi) doesn't evaluate but is_number is True return None if nmag._prec == 1: # increase the precision up to the default maximum # precision to see if we can get any significance from mpmath.libmp.libintmath import giant_steps from sympy.core.evalf import DEFAULT_MAXPREC as target # evaluate for prec in giant_steps(2, target): nmag = abs(self.evalf(prec, subs=reps)) if nmag._prec != 1: break if nmag._prec != 1: if n is None: n = max(prec, 15) return self.evalf(n, subs=reps) # never got any significance return None def is_constant(self, *wrt, **flags): """Return True if self is constant, False if not, or None if the constancy could not be determined conclusively. Explanation =========== If an expression has no free symbols then it is a constant. If there are free symbols it is possible that the expression is a constant, perhaps (but not necessarily) zero. To test such expressions, a few strategies are tried: 1) numerical evaluation at two random points. If two such evaluations give two different values and the values have a precision greater than 1 then self is not constant. If the evaluations agree or could not be obtained with any precision, no decision is made. The numerical testing is done only if ``wrt`` is different than the free symbols. 2) differentiation with respect to variables in 'wrt' (or all free symbols if omitted) to see if the expression is constant or not. This will not always lead to an expression that is zero even though an expression is constant (see added test in test_expr.py). If all derivatives are zero then self is constant with respect to the given symbols. 3) finding out zeros of denominator expression with free_symbols. It won't be constant if there are zeros. It gives more negative answers for expression that are not constant. If neither evaluation nor differentiation can prove the expression is constant, None is returned unless two numerical values happened to be the same and the flag ``failing_number`` is True -- in that case the numerical value will be returned. If flag simplify=False is passed, self will not be simplified; the default is True since self should be simplified before testing. Examples ======== >>> from sympy import cos, sin, Sum, S, pi >>> from sympy.abc import a, n, x, y >>> x.is_constant() False >>> S(2).is_constant() True >>> Sum(x, (x, 1, 10)).is_constant() True >>> Sum(x, (x, 1, n)).is_constant() False >>> Sum(x, (x, 1, n)).is_constant(y) True >>> Sum(x, (x, 1, n)).is_constant(n) False >>> Sum(x, (x, 1, n)).is_constant(x) True >>> eq = a*cos(x)**2 + a*sin(x)**2 - a >>> eq.is_constant() True >>> eq.subs({x: pi, a: 2}) == eq.subs({x: pi, a: 3}) == 0 True >>> (0**x).is_constant() False >>> x.is_constant() False >>> (x**x).is_constant() False >>> one = cos(x)**2 + sin(x)**2 >>> one.is_constant() True >>> ((one - 1)**(x + 1)).is_constant() in (True, False) # could be 0 or 1 True """ def check_denominator_zeros(expression): from sympy.solvers.solvers import denoms retNone = False for den in denoms(expression): z = den.is_zero if z is True: return True if z is None: retNone = True if retNone: return None return False simplify = flags.get('simplify', True) if self.is_number: return True free = self.free_symbols if not free: return True # assume f(1) is some constant # if we are only interested in some symbols and they are not in the # free symbols then this expression is constant wrt those symbols wrt = set(wrt) if wrt and not wrt & free: return True wrt = wrt or free # simplify unless this has already been done expr = self if simplify: expr = expr.simplify() # is_zero should be a quick assumptions check; it can be wrong for # numbers (see test_is_not_constant test), giving False when it # shouldn't, but hopefully it will never give True unless it is sure. if expr.is_zero: return True # Don't attempt subsitution or differentiation with non-number symbols wrt_number = {sym for sym in wrt if sym.kind is NumberKind} # try numerical evaluation to see if we get two different values failing_number = None if wrt_number == free: # try 0 (for a) and 1 (for b) try: a = expr.subs(list(zip(free, [0]*len(free))), simultaneous=True) if a is S.NaN: # evaluation may succeed when substitution fails a = expr._random(None, 0, 0, 0, 0) except ZeroDivisionError: a = None if a is not None and a is not S.NaN: try: b = expr.subs(list(zip(free, [1]*len(free))), simultaneous=True) if b is S.NaN: # evaluation may succeed when substitution fails b = expr._random(None, 1, 0, 1, 0) except ZeroDivisionError: b = None if b is not None and b is not S.NaN and b.equals(a) is False: return False # try random real b = expr._random(None, -1, 0, 1, 0) if b is not None and b is not S.NaN and b.equals(a) is False: return False # try random complex b = expr._random() if b is not None and b is not S.NaN: if b.equals(a) is False: return False failing_number = a if a.is_number else b # now we will test each wrt symbol (or all free symbols) to see if the # expression depends on them or not using differentiation. This is # not sufficient for all expressions, however, so we don't return # False if we get a derivative other than 0 with free symbols. for w in wrt_number: deriv = expr.diff(w) if simplify: deriv = deriv.simplify() if deriv != 0: if not (pure_complex(deriv, or_real=True)): if flags.get('failing_number', False): return failing_number elif deriv.free_symbols: # dead line provided _random returns None in such cases return None return False cd = check_denominator_zeros(self) if cd is True: return False elif cd is None: return None return True def equals(self, other, failing_expression=False): """Return True if self == other, False if it doesn't, or None. If failing_expression is True then the expression which did not simplify to a 0 will be returned instead of None. Explanation =========== If ``self`` is a Number (or complex number) that is not zero, then the result is False. If ``self`` is a number and has not evaluated to zero, evalf will be used to test whether the expression evaluates to zero. If it does so and the result has significance (i.e. the precision is either -1, for a Rational result, or is greater than 1) then the evalf value will be used to return True or False. """ from sympy.simplify.simplify import nsimplify, simplify from sympy.solvers.solvers import solve from sympy.polys.polyerrors import NotAlgebraic from sympy.polys.numberfields import minimal_polynomial other = sympify(other) if self == other: return True # they aren't the same so see if we can make the difference 0; # don't worry about doing simplification steps one at a time # because if the expression ever goes to 0 then the subsequent # simplification steps that are done will be very fast. diff = factor_terms(simplify(self - other), radical=True) if not diff: return True if not diff.has(Add, Mod): # if there is no expanding to be done after simplifying # then this can't be a zero return False constant = diff.is_constant(simplify=False, failing_number=True) if constant is False: return False if not diff.is_number: if constant is None: # e.g. unless the right simplification is done, a symbolic # zero is possible (see expression of issue 6829: without # simplification constant will be None). return if constant is True: # this gives a number whether there are free symbols or not ndiff = diff._random() # is_comparable will work whether the result is real # or complex; it could be None, however. if ndiff and ndiff.is_comparable: return False # sometimes we can use a simplified result to give a clue as to # what the expression should be; if the expression is *not* zero # then we should have been able to compute that and so now # we can just consider the cases where the approximation appears # to be zero -- we try to prove it via minimal_polynomial. # # removed # ns = nsimplify(diff) # if diff.is_number and (not ns or ns == diff): # # The thought was that if it nsimplifies to 0 that's a sure sign # to try the following to prove it; or if it changed but wasn't # zero that might be a sign that it's not going to be easy to # prove. But tests seem to be working without that logic. # if diff.is_number: # try to prove via self-consistency surds = [s for s in diff.atoms(Pow) if s.args[0].is_Integer] # it seems to work better to try big ones first surds.sort(key=lambda x: -x.args[0]) for s in surds: try: # simplify is False here -- this expression has already # been identified as being hard to identify as zero; # we will handle the checking ourselves using nsimplify # to see if we are in the right ballpark or not and if so # *then* the simplification will be attempted. sol = solve(diff, s, simplify=False) if sol: if s in sol: # the self-consistent result is present return True if all(si.is_Integer for si in sol): # perfect powers are removed at instantiation # so surd s cannot be an integer return False if all(i.is_algebraic is False for i in sol): # a surd is algebraic return False if any(si in surds for si in sol): # it wasn't equal to s but it is in surds # and different surds are not equal return False if any(nsimplify(s - si) == 0 and simplify(s - si) == 0 for si in sol): return True if s.is_real: if any(nsimplify(si, [s]) == s and simplify(si) == s for si in sol): return True except NotImplementedError: pass # try to prove with minimal_polynomial but know when # *not* to use this or else it can take a long time. e.g. issue 8354 if True: # change True to condition that assures non-hang try: mp = minimal_polynomial(diff) if mp.is_Symbol: return True return False except (NotAlgebraic, NotImplementedError): pass # diff has not simplified to zero; constant is either None, True # or the number with significance (is_comparable) that was randomly # calculated twice as the same value. if constant not in (True, None) and constant != 0: return False if failing_expression: return diff return None def _eval_is_positive(self): finite = self.is_finite if finite is False: return False extended_positive = self.is_extended_positive if finite is True: return extended_positive if extended_positive is False: return False def _eval_is_negative(self): finite = self.is_finite if finite is False: return False extended_negative = self.is_extended_negative if finite is True: return extended_negative if extended_negative is False: return False def _eval_is_extended_positive_negative(self, positive): from sympy.core.numbers import pure_complex from sympy.polys.numberfields import minimal_polynomial from sympy.polys.polyerrors import NotAlgebraic if self.is_number: if self.is_extended_real is False: return False # check to see that we can get a value try: n2 = self._eval_evalf(2) # XXX: This shouldn't be caught here # Catches ValueError: hypsum() failed to converge to the requested # 34 bits of accuracy except ValueError: return None if n2 is None: return None if getattr(n2, '_prec', 1) == 1: # no significance return None if n2 is S.NaN: return None f = self.evalf(2) if f.is_Float: match = f, S.Zero else: match = pure_complex(f) if match is None: return False r, i = match if not (i.is_Number and r.is_Number): return False if r._prec != 1 and i._prec != 1: return bool(not i and ((r > 0) if positive else (r < 0))) elif r._prec == 1 and (not i or i._prec == 1) and \ self.is_algebraic and not self.has(Function): try: if minimal_polynomial(self).is_Symbol: return False except (NotAlgebraic, NotImplementedError): pass def _eval_is_extended_positive(self): return self._eval_is_extended_positive_negative(positive=True) def _eval_is_extended_negative(self): return self._eval_is_extended_positive_negative(positive=False) def _eval_interval(self, x, a, b): """ Returns evaluation over an interval. For most functions this is: self.subs(x, b) - self.subs(x, a), possibly using limit() if NaN is returned from subs, or if singularities are found between a and b. If b or a is None, it only evaluates -self.subs(x, a) or self.subs(b, x), respectively. """ from sympy.series import limit, Limit from sympy.solvers.solveset import solveset from sympy.sets.sets import Interval from sympy.functions.elementary.exponential import log from sympy.calculus.util import AccumBounds if (a is None and b is None): raise ValueError('Both interval ends cannot be None.') def _eval_endpoint(left): c = a if left else b if c is None: return 0 else: C = self.subs(x, c) if C.has(S.NaN, S.Infinity, S.NegativeInfinity, S.ComplexInfinity, AccumBounds): if (a < b) != False: C = limit(self, x, c, "+" if left else "-") else: C = limit(self, x, c, "-" if left else "+") if isinstance(C, Limit): raise NotImplementedError("Could not compute limit") return C if a == b: return 0 A = _eval_endpoint(left=True) if A is S.NaN: return A B = _eval_endpoint(left=False) if (a and b) is None: return B - A value = B - A if a.is_comparable and b.is_comparable: if a < b: domain = Interval(a, b) else: domain = Interval(b, a) # check the singularities of self within the interval # if singularities is a ConditionSet (not iterable), catch the exception and pass singularities = solveset(self.cancel().as_numer_denom()[1], x, domain=domain) for logterm in self.atoms(log): singularities = singularities | solveset(logterm.args[0], x, domain=domain) try: for s in singularities: if value is S.NaN: # no need to keep adding, it will stay NaN break if not s.is_comparable: continue if (a < s) == (s < b) == True: value += -limit(self, x, s, "+") + limit(self, x, s, "-") elif (b < s) == (s < a) == True: value += limit(self, x, s, "+") - limit(self, x, s, "-") except TypeError: pass return value def _eval_power(self, other): # subclass to compute self**other for cases when # other is not NaN, 0, or 1 return None def _eval_conjugate(self): if self.is_extended_real: return self elif self.is_imaginary: return -self def conjugate(self): """Returns the complex conjugate of 'self'.""" from sympy.functions.elementary.complexes import conjugate as c return c(self) def dir(self, x, cdir): from sympy import log minexp = S.Zero if self.is_zero: return S.Zero arg = self while arg: minexp += S.One arg = arg.diff(x) coeff = arg.subs(x, 0) if coeff is S.NaN: coeff = arg.limit(x, 0) if coeff is S.ComplexInfinity: try: coeff, _ = arg.leadterm(x) if coeff.has(log(x)): raise ValueError() except ValueError: coeff = arg.limit(x, 0) if coeff != S.Zero: break return coeff*cdir**minexp def _eval_transpose(self): from sympy.functions.elementary.complexes import conjugate if (self.is_complex or self.is_infinite): return self elif self.is_hermitian: return conjugate(self) elif self.is_antihermitian: return -conjugate(self) def transpose(self): from sympy.functions.elementary.complexes import transpose return transpose(self) def _eval_adjoint(self): from sympy.functions.elementary.complexes import conjugate, transpose if self.is_hermitian: return self elif self.is_antihermitian: return -self obj = self._eval_conjugate() if obj is not None: return transpose(obj) obj = self._eval_transpose() if obj is not None: return conjugate(obj) def adjoint(self): from sympy.functions.elementary.complexes import adjoint return adjoint(self) @classmethod def _parse_order(cls, order): """Parse and configure the ordering of terms. """ from sympy.polys.orderings import monomial_key startswith = getattr(order, "startswith", None) if startswith is None: reverse = False else: reverse = startswith('rev-') if reverse: order = order[4:] monom_key = monomial_key(order) def neg(monom): result = [] for m in monom: if isinstance(m, tuple): result.append(neg(m)) else: result.append(-m) return tuple(result) def key(term): _, ((re, im), monom, ncpart) = term monom = neg(monom_key(monom)) ncpart = tuple([e.sort_key(order=order) for e in ncpart]) coeff = ((bool(im), im), (re, im)) return monom, ncpart, coeff return key, reverse def as_ordered_factors(self, order=None): """Return list of ordered factors (if Mul) else [self].""" return [self] def as_poly(self, *gens, **args): """Converts ``self`` to a polynomial or returns ``None``. Explanation =========== >>> from sympy import sin >>> from sympy.abc import x, y >>> print((x**2 + x*y).as_poly()) Poly(x**2 + x*y, x, y, domain='ZZ') >>> print((x**2 + x*y).as_poly(x, y)) Poly(x**2 + x*y, x, y, domain='ZZ') >>> print((x**2 + sin(y)).as_poly(x, y)) None """ from sympy.polys import Poly, PolynomialError try: poly = Poly(self, *gens, **args) if not poly.is_Poly: return None else: return poly except PolynomialError: return None def as_ordered_terms(self, order=None, data=False): """ Transform an expression to an ordered list of terms. Examples ======== >>> from sympy import sin, cos >>> from sympy.abc import x >>> (sin(x)**2*cos(x) + sin(x)**2 + 1).as_ordered_terms() [sin(x)**2*cos(x), sin(x)**2, 1] """ from .numbers import Number, NumberSymbol if order is None and self.is_Add: # Spot the special case of Add(Number, Mul(Number, expr)) with the # first number positive and thhe second number nagative key = lambda x:not isinstance(x, (Number, NumberSymbol)) add_args = sorted(Add.make_args(self), key=key) if (len(add_args) == 2 and isinstance(add_args[0], (Number, NumberSymbol)) and isinstance(add_args[1], Mul)): mul_args = sorted(Mul.make_args(add_args[1]), key=key) if (len(mul_args) == 2 and isinstance(mul_args[0], Number) and add_args[0].is_positive and mul_args[0].is_negative): return add_args key, reverse = self._parse_order(order) terms, gens = self.as_terms() if not any(term.is_Order for term, _ in terms): ordered = sorted(terms, key=key, reverse=reverse) else: _terms, _order = [], [] for term, repr in terms: if not term.is_Order: _terms.append((term, repr)) else: _order.append((term, repr)) ordered = sorted(_terms, key=key, reverse=True) \ + sorted(_order, key=key, reverse=True) if data: return ordered, gens else: return [term for term, _ in ordered] def as_terms(self): """Transform an expression to a list of terms. """ from .add import Add from .mul import Mul from .exprtools import decompose_power gens, terms = set(), [] for term in Add.make_args(self): coeff, _term = term.as_coeff_Mul() coeff = complex(coeff) cpart, ncpart = {}, [] if _term is not S.One: for factor in Mul.make_args(_term): if factor.is_number: try: coeff *= complex(factor) except (TypeError, ValueError): pass else: continue if factor.is_commutative: base, exp = decompose_power(factor) cpart[base] = exp gens.add(base) else: ncpart.append(factor) coeff = coeff.real, coeff.imag ncpart = tuple(ncpart) terms.append((term, (coeff, cpart, ncpart))) gens = sorted(gens, key=default_sort_key) k, indices = len(gens), {} for i, g in enumerate(gens): indices[g] = i result = [] for term, (coeff, cpart, ncpart) in terms: monom = [0]*k for base, exp in cpart.items(): monom[indices[base]] = exp result.append((term, (coeff, tuple(monom), ncpart))) return result, gens def removeO(self): """Removes the additive O(..) symbol if there is one""" return self def getO(self): """Returns the additive O(..) symbol if there is one, else None.""" return None def getn(self): """ Returns the order of the expression. Explanation =========== The order is determined either from the O(...) term. If there is no O(...) term, it returns None. Examples ======== >>> from sympy import O >>> from sympy.abc import x >>> (1 + x + O(x**2)).getn() 2 >>> (1 + x).getn() """ from sympy import Dummy, Symbol o = self.getO() if o is None: return None elif o.is_Order: o = o.expr if o is S.One: return S.Zero if o.is_Symbol: return S.One if o.is_Pow: return o.args[1] if o.is_Mul: # x**n*log(x)**n or x**n/log(x)**n for oi in o.args: if oi.is_Symbol: return S.One if oi.is_Pow: syms = oi.atoms(Symbol) if len(syms) == 1: x = syms.pop() oi = oi.subs(x, Dummy('x', positive=True)) if oi.base.is_Symbol and oi.exp.is_Rational: return abs(oi.exp) raise NotImplementedError('not sure of order of %s' % o) def count_ops(self, visual=None): """wrapper for count_ops that returns the operation count.""" from .function import count_ops return count_ops(self, visual) def args_cnc(self, cset=False, warn=True, split_1=True): """Return [commutative factors, non-commutative factors] of self. Explanation =========== self is treated as a Mul and the ordering of the factors is maintained. If ``cset`` is True the commutative factors will be returned in a set. If there were repeated factors (as may happen with an unevaluated Mul) then an error will be raised unless it is explicitly suppressed by setting ``warn`` to False. Note: -1 is always separated from a Number unless split_1 is False. Examples ======== >>> from sympy import symbols, oo >>> A, B = symbols('A B', commutative=0) >>> x, y = symbols('x y') >>> (-2*x*y).args_cnc() [[-1, 2, x, y], []] >>> (-2.5*x).args_cnc() [[-1, 2.5, x], []] >>> (-2*x*A*B*y).args_cnc() [[-1, 2, x, y], [A, B]] >>> (-2*x*A*B*y).args_cnc(split_1=False) [[-2, x, y], [A, B]] >>> (-2*x*y).args_cnc(cset=True) [{-1, 2, x, y}, []] The arg is always treated as a Mul: >>> (-2 + x + A).args_cnc() [[], [x - 2 + A]] >>> (-oo).args_cnc() # -oo is a singleton [[-1, oo], []] """ if self.is_Mul: args = list(self.args) else: args = [self] for i, mi in enumerate(args): if not mi.is_commutative: c = args[:i] nc = args[i:] break else: c = args nc = [] if c and split_1 and ( c[0].is_Number and c[0].is_extended_negative and c[0] is not S.NegativeOne): c[:1] = [S.NegativeOne, -c[0]] if cset: clen = len(c) c = set(c) if clen and warn and len(c) != clen: raise ValueError('repeated commutative arguments: %s' % [ci for ci in c if list(self.args).count(ci) > 1]) return [c, nc] def coeff(self, x, n=1, right=False): """ Returns the coefficient from the term(s) containing ``x**n``. If ``n`` is zero then all terms independent of ``x`` will be returned. Explanation =========== When ``x`` is noncommutative, the coefficient to the left (default) or right of ``x`` can be returned. The keyword 'right' is ignored when ``x`` is commutative. Examples ======== >>> from sympy import symbols >>> from sympy.abc import x, y, z You can select terms that have an explicit negative in front of them: >>> (-x + 2*y).coeff(-1) x >>> (x - 2*y).coeff(-1) 2*y You can select terms with no Rational coefficient: >>> (x + 2*y).coeff(1) x >>> (3 + 2*x + 4*x**2).coeff(1) 0 You can select terms independent of x by making n=0; in this case expr.as_independent(x)[0] is returned (and 0 will be returned instead of None): >>> (3 + 2*x + 4*x**2).coeff(x, 0) 3 >>> eq = ((x + 1)**3).expand() + 1 >>> eq x**3 + 3*x**2 + 3*x + 2 >>> [eq.coeff(x, i) for i in reversed(range(4))] [1, 3, 3, 2] >>> eq -= 2 >>> [eq.coeff(x, i) for i in reversed(range(4))] [1, 3, 3, 0] You can select terms that have a numerical term in front of them: >>> (-x - 2*y).coeff(2) -y >>> from sympy import sqrt >>> (x + sqrt(2)*x).coeff(sqrt(2)) x The matching is exact: >>> (3 + 2*x + 4*x**2).coeff(x) 2 >>> (3 + 2*x + 4*x**2).coeff(x**2) 4 >>> (3 + 2*x + 4*x**2).coeff(x**3) 0 >>> (z*(x + y)**2).coeff((x + y)**2) z >>> (z*(x + y)**2).coeff(x + y) 0 In addition, no factoring is done, so 1 + z*(1 + y) is not obtained from the following: >>> (x + z*(x + x*y)).coeff(x) 1 If such factoring is desired, factor_terms can be used first: >>> from sympy import factor_terms >>> factor_terms(x + z*(x + x*y)).coeff(x) z*(y + 1) + 1 >>> n, m, o = symbols('n m o', commutative=False) >>> n.coeff(n) 1 >>> (3*n).coeff(n) 3 >>> (n*m + m*n*m).coeff(n) # = (1 + m)*n*m 1 + m >>> (n*m + m*n*m).coeff(n, right=True) # = (1 + m)*n*m m If there is more than one possible coefficient 0 is returned: >>> (n*m + m*n).coeff(n) 0 If there is only one possible coefficient, it is returned: >>> (n*m + x*m*n).coeff(m*n) x >>> (n*m + x*m*n).coeff(m*n, right=1) 1 See Also ======== as_coefficient: separate the expression into a coefficient and factor as_coeff_Add: separate the additive constant from an expression as_coeff_Mul: separate the multiplicative constant from an expression as_independent: separate x-dependent terms/factors from others sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used """ x = sympify(x) if not isinstance(x, Basic): return S.Zero n = as_int(n) if not x: return S.Zero if x == self: if n == 1: return S.One return S.Zero if x is S.One: co = [a for a in Add.make_args(self) if a.as_coeff_Mul()[0] is S.One] if not co: return S.Zero return Add(*co) if n == 0: if x.is_Add and self.is_Add: c = self.coeff(x, right=right) if not c: return S.Zero if not right: return self - Add(*[a*x for a in Add.make_args(c)]) return self - Add(*[x*a for a in Add.make_args(c)]) return self.as_independent(x, as_Add=True)[0] # continue with the full method, looking for this power of x: x = x**n def incommon(l1, l2): if not l1 or not l2: return [] n = min(len(l1), len(l2)) for i in range(n): if l1[i] != l2[i]: return l1[:i] return l1[:] def find(l, sub, first=True): """ Find where list sub appears in list l. When ``first`` is True the first occurrence from the left is returned, else the last occurrence is returned. Return None if sub is not in l. Examples ======== >> l = range(5)*2 >> find(l, [2, 3]) 2 >> find(l, [2, 3], first=0) 7 >> find(l, [2, 4]) None """ if not sub or not l or len(sub) > len(l): return None n = len(sub) if not first: l.reverse() sub.reverse() for i in range(0, len(l) - n + 1): if all(l[i + j] == sub[j] for j in range(n)): break else: i = None if not first: l.reverse() sub.reverse() if i is not None and not first: i = len(l) - (i + n) return i co = [] args = Add.make_args(self) self_c = self.is_commutative x_c = x.is_commutative if self_c and not x_c: return S.Zero one_c = self_c or x_c xargs, nx = x.args_cnc(cset=True, warn=bool(not x_c)) # find the parts that pass the commutative terms for a in args: margs, nc = a.args_cnc(cset=True, warn=bool(not self_c)) if nc is None: nc = [] if len(xargs) > len(margs): continue resid = margs.difference(xargs) if len(resid) + len(xargs) == len(margs): if one_c: co.append(Mul(*(list(resid) + nc))) else: co.append((resid, nc)) if one_c: if co == []: return S.Zero elif co: return Add(*co) else: # both nc # now check the non-comm parts if not co: return S.Zero if all(n == co[0][1] for r, n in co): ii = find(co[0][1], nx, right) if ii is not None: if not right: return Mul(Add(*[Mul(*r) for r, c in co]), Mul(*co[0][1][:ii])) else: return Mul(*co[0][1][ii + len(nx):]) beg = reduce(incommon, (n[1] for n in co)) if beg: ii = find(beg, nx, right) if ii is not None: if not right: gcdc = co[0][0] for i in range(1, len(co)): gcdc = gcdc.intersection(co[i][0]) if not gcdc: break return Mul(*(list(gcdc) + beg[:ii])) else: m = ii + len(nx) return Add(*[Mul(*(list(r) + n[m:])) for r, n in co]) end = list(reversed( reduce(incommon, (list(reversed(n[1])) for n in co)))) if end: ii = find(end, nx, right) if ii is not None: if not right: return Add(*[Mul(*(list(r) + n[:-len(end) + ii])) for r, n in co]) else: return Mul(*end[ii + len(nx):]) # look for single match hit = None for i, (r, n) in enumerate(co): ii = find(n, nx, right) if ii is not None: if not hit: hit = ii, r, n else: break else: if hit: ii, r, n = hit if not right: return Mul(*(list(r) + n[:ii])) else: return Mul(*n[ii + len(nx):]) return S.Zero def as_expr(self, *gens): """ Convert a polynomial to a SymPy expression. Examples ======== >>> from sympy import sin >>> from sympy.abc import x, y >>> f = (x**2 + x*y).as_poly(x, y) >>> f.as_expr() x**2 + x*y >>> sin(x).as_expr() sin(x) """ return self def as_coefficient(self, expr): """ Extracts symbolic coefficient at the given expression. In other words, this functions separates 'self' into the product of 'expr' and 'expr'-free coefficient. If such separation is not possible it will return None. Examples ======== >>> from sympy import E, pi, sin, I, Poly >>> from sympy.abc import x >>> E.as_coefficient(E) 1 >>> (2*E).as_coefficient(E) 2 >>> (2*sin(E)*E).as_coefficient(E) Two terms have E in them so a sum is returned. (If one were desiring the coefficient of the term exactly matching E then the constant from the returned expression could be selected. Or, for greater precision, a method of Poly can be used to indicate the desired term from which the coefficient is desired.) >>> (2*E + x*E).as_coefficient(E) x + 2 >>> _.args[0] # just want the exact match 2 >>> p = Poly(2*E + x*E); p Poly(x*E + 2*E, x, E, domain='ZZ') >>> p.coeff_monomial(E) 2 >>> p.nth(0, 1) 2 Since the following cannot be written as a product containing E as a factor, None is returned. (If the coefficient ``2*x`` is desired then the ``coeff`` method should be used.) >>> (2*E*x + x).as_coefficient(E) >>> (2*E*x + x).coeff(E) 2*x >>> (E*(x + 1) + x).as_coefficient(E) >>> (2*pi*I).as_coefficient(pi*I) 2 >>> (2*I).as_coefficient(pi*I) See Also ======== coeff: return sum of terms have a given factor as_coeff_Add: separate the additive constant from an expression as_coeff_Mul: separate the multiplicative constant from an expression as_independent: separate x-dependent terms/factors from others sympy.polys.polytools.Poly.coeff_monomial: efficiently find the single coefficient of a monomial in Poly sympy.polys.polytools.Poly.nth: like coeff_monomial but powers of monomial terms are used """ r = self.extract_multiplicatively(expr) if r and not r.has(expr): return r def as_independent(self, *deps, **hint): """ A mostly naive separation of a Mul or Add into arguments that are not are dependent on deps. To obtain as complete a separation of variables as possible, use a separation method first, e.g.: * separatevars() to change Mul, Add and Pow (including exp) into Mul * .expand(mul=True) to change Add or Mul into Add * .expand(log=True) to change log expr into an Add The only non-naive thing that is done here is to respect noncommutative ordering of variables and to always return (0, 0) for `self` of zero regardless of hints. For nonzero `self`, the returned tuple (i, d) has the following interpretation: * i will has no variable that appears in deps * d will either have terms that contain variables that are in deps, or be equal to 0 (when self is an Add) or 1 (when self is a Mul) * if self is an Add then self = i + d * if self is a Mul then self = i*d * otherwise (self, S.One) or (S.One, self) is returned. To force the expression to be treated as an Add, use the hint as_Add=True Examples ======== -- self is an Add >>> from sympy import sin, cos, exp >>> from sympy.abc import x, y, z >>> (x + x*y).as_independent(x) (0, x*y + x) >>> (x + x*y).as_independent(y) (x, x*y) >>> (2*x*sin(x) + y + x + z).as_independent(x) (y + z, 2*x*sin(x) + x) >>> (2*x*sin(x) + y + x + z).as_independent(x, y) (z, 2*x*sin(x) + x + y) -- self is a Mul >>> (x*sin(x)*cos(y)).as_independent(x) (cos(y), x*sin(x)) non-commutative terms cannot always be separated out when self is a Mul >>> from sympy import symbols >>> n1, n2, n3 = symbols('n1 n2 n3', commutative=False) >>> (n1 + n1*n2).as_independent(n2) (n1, n1*n2) >>> (n2*n1 + n1*n2).as_independent(n2) (0, n1*n2 + n2*n1) >>> (n1*n2*n3).as_independent(n1) (1, n1*n2*n3) >>> (n1*n2*n3).as_independent(n2) (n1, n2*n3) >>> ((x-n1)*(x-y)).as_independent(x) (1, (x - y)*(x - n1)) -- self is anything else: >>> (sin(x)).as_independent(x) (1, sin(x)) >>> (sin(x)).as_independent(y) (sin(x), 1) >>> exp(x+y).as_independent(x) (1, exp(x + y)) -- force self to be treated as an Add: >>> (3*x).as_independent(x, as_Add=True) (0, 3*x) -- force self to be treated as a Mul: >>> (3+x).as_independent(x, as_Add=False) (1, x + 3) >>> (-3+x).as_independent(x, as_Add=False) (1, x - 3) Note how the below differs from the above in making the constant on the dep term positive. >>> (y*(-3+x)).as_independent(x) (y, x - 3) -- use .as_independent() for true independence testing instead of .has(). The former considers only symbols in the free symbols while the latter considers all symbols >>> from sympy import Integral >>> I = Integral(x, (x, 1, 2)) >>> I.has(x) True >>> x in I.free_symbols False >>> I.as_independent(x) == (I, 1) True >>> (I + x).as_independent(x) == (I, x) True Note: when trying to get independent terms, a separation method might need to be used first. In this case, it is important to keep track of what you send to this routine so you know how to interpret the returned values >>> from sympy import separatevars, log >>> separatevars(exp(x+y)).as_independent(x) (exp(y), exp(x)) >>> (x + x*y).as_independent(y) (x, x*y) >>> separatevars(x + x*y).as_independent(y) (x, y + 1) >>> (x*(1 + y)).as_independent(y) (x, y + 1) >>> (x*(1 + y)).expand(mul=True).as_independent(y) (x, x*y) >>> a, b=symbols('a b', positive=True) >>> (log(a*b).expand(log=True)).as_independent(b) (log(a), log(b)) See Also ======== .separatevars(), .expand(log=True), sympy.core.add.Add.as_two_terms(), sympy.core.mul.Mul.as_two_terms(), .as_coeff_add(), .as_coeff_mul() """ from .symbol import Symbol from .add import _unevaluated_Add from .mul import _unevaluated_Mul from sympy.utilities.iterables import sift if self.is_zero: return S.Zero, S.Zero func = self.func if hint.get('as_Add', isinstance(self, Add) ): want = Add else: want = Mul # sift out deps into symbolic and other and ignore # all symbols but those that are in the free symbols sym = set() other = [] for d in deps: if isinstance(d, Symbol): # Symbol.is_Symbol is True sym.add(d) else: other.append(d) def has(e): """return the standard has() if there are no literal symbols, else check to see that symbol-deps are in the free symbols.""" has_other = e.has(*other) if not sym: return has_other return has_other or e.has(*(e.free_symbols & sym)) if (want is not func or func is not Add and func is not Mul): if has(self): return (want.identity, self) else: return (self, want.identity) else: if func is Add: args = list(self.args) else: args, nc = self.args_cnc() d = sift(args, lambda x: has(x)) depend = d[True] indep = d[False] if func is Add: # all terms were treated as commutative return (Add(*indep), _unevaluated_Add(*depend)) else: # handle noncommutative by stopping at first dependent term for i, n in enumerate(nc): if has(n): depend.extend(nc[i:]) break indep.append(n) return Mul(*indep), ( Mul(*depend, evaluate=False) if nc else _unevaluated_Mul(*depend)) def as_real_imag(self, deep=True, **hints): """Performs complex expansion on 'self' and returns a tuple containing collected both real and imaginary parts. This method can't be confused with re() and im() functions, which does not perform complex expansion at evaluation. However it is possible to expand both re() and im() functions and get exactly the same results as with a single call to this function. >>> from sympy import symbols, I >>> x, y = symbols('x,y', real=True) >>> (x + y*I).as_real_imag() (x, y) >>> from sympy.abc import z, w >>> (z + w*I).as_real_imag() (re(z) - im(w), re(w) + im(z)) """ from sympy import im, re if hints.get('ignore') == self: return None else: return (re(self), im(self)) def as_powers_dict(self): """Return self as a dictionary of factors with each factor being treated as a power. The keys are the bases of the factors and the values, the corresponding exponents. The resulting dictionary should be used with caution if the expression is a Mul and contains non- commutative factors since the order that they appeared will be lost in the dictionary. See Also ======== as_ordered_factors: An alternative for noncommutative applications, returning an ordered list of factors. args_cnc: Similar to as_ordered_factors, but guarantees separation of commutative and noncommutative factors. """ d = defaultdict(int) d.update(dict([self.as_base_exp()])) return d def as_coefficients_dict(self): """Return a dictionary mapping terms to their Rational coefficient. Since the dictionary is a defaultdict, inquiries about terms which were not present will return a coefficient of 0. If an expression is not an Add it is considered to have a single term. Examples ======== >>> from sympy.abc import a, x >>> (3*x + a*x + 4).as_coefficients_dict() {1: 4, x: 3, a*x: 1} >>> _[a] 0 >>> (3*a*x).as_coefficients_dict() {a*x: 3} """ c, m = self.as_coeff_Mul() if not c.is_Rational: c = S.One m = self d = defaultdict(int) d.update({m: c}) return d def as_base_exp(self): # a -> b ** e return self, S.One def as_coeff_mul(self, *deps, **kwargs): """Return the tuple (c, args) where self is written as a Mul, ``m``. c should be a Rational multiplied by any factors of the Mul that are independent of deps. args should be a tuple of all other factors of m; args is empty if self is a Number or if self is independent of deps (when given). This should be used when you don't know if self is a Mul or not but you want to treat self as a Mul or if you want to process the individual arguments of the tail of self as a Mul. - if you know self is a Mul and want only the head, use self.args[0]; - if you don't want to process the arguments of the tail but need the tail then use self.as_two_terms() which gives the head and tail; - if you want to split self into an independent and dependent parts use ``self.as_independent(*deps)`` >>> from sympy import S >>> from sympy.abc import x, y >>> (S(3)).as_coeff_mul() (3, ()) >>> (3*x*y).as_coeff_mul() (3, (x, y)) >>> (3*x*y).as_coeff_mul(x) (3*y, (x,)) >>> (3*y).as_coeff_mul(x) (3*y, ()) """ if deps: if not self.has(*deps): return self, tuple() return S.One, (self,) def as_coeff_add(self, *deps): """Return the tuple (c, args) where self is written as an Add, ``a``. c should be a Rational added to any terms of the Add that are independent of deps. args should be a tuple of all other terms of ``a``; args is empty if self is a Number or if self is independent of deps (when given). This should be used when you don't know if self is an Add or not but you want to treat self as an Add or if you want to process the individual arguments of the tail of self as an Add. - if you know self is an Add and want only the head, use self.args[0]; - if you don't want to process the arguments of the tail but need the tail then use self.as_two_terms() which gives the head and tail. - if you want to split self into an independent and dependent parts use ``self.as_independent(*deps)`` >>> from sympy import S >>> from sympy.abc import x, y >>> (S(3)).as_coeff_add() (3, ()) >>> (3 + x).as_coeff_add() (3, (x,)) >>> (3 + x + y).as_coeff_add(x) (y + 3, (x,)) >>> (3 + y).as_coeff_add(x) (y + 3, ()) """ if deps: if not self.has(*deps): return self, tuple() return S.Zero, (self,) def primitive(self): """Return the positive Rational that can be extracted non-recursively from every term of self (i.e., self is treated like an Add). This is like the as_coeff_Mul() method but primitive always extracts a positive Rational (never a negative or a Float). Examples ======== >>> from sympy.abc import x >>> (3*(x + 1)**2).primitive() (3, (x + 1)**2) >>> a = (6*x + 2); a.primitive() (2, 3*x + 1) >>> b = (x/2 + 3); b.primitive() (1/2, x + 6) >>> (a*b).primitive() == (1, a*b) True """ if not self: return S.One, S.Zero c, r = self.as_coeff_Mul(rational=True) if c.is_negative: c, r = -c, -r return c, r def as_content_primitive(self, radical=False, clear=True): """This method should recursively remove a Rational from all arguments and return that (content) and the new self (primitive). The content should always be positive and ``Mul(*foo.as_content_primitive()) == foo``. The primitive need not be in canonical form and should try to preserve the underlying structure if possible (i.e. expand_mul should not be applied to self). Examples ======== >>> from sympy import sqrt >>> from sympy.abc import x, y, z >>> eq = 2 + 2*x + 2*y*(3 + 3*y) The as_content_primitive function is recursive and retains structure: >>> eq.as_content_primitive() (2, x + 3*y*(y + 1) + 1) Integer powers will have Rationals extracted from the base: >>> ((2 + 6*x)**2).as_content_primitive() (4, (3*x + 1)**2) >>> ((2 + 6*x)**(2*y)).as_content_primitive() (1, (2*(3*x + 1))**(2*y)) Terms may end up joining once their as_content_primitives are added: >>> ((5*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive() (11, x*(y + 1)) >>> ((3*(x*(1 + y)) + 2*x*(3 + 3*y))).as_content_primitive() (9, x*(y + 1)) >>> ((3*(z*(1 + y)) + 2.0*x*(3 + 3*y))).as_content_primitive() (1, 6.0*x*(y + 1) + 3*z*(y + 1)) >>> ((5*(x*(1 + y)) + 2*x*(3 + 3*y))**2).as_content_primitive() (121, x**2*(y + 1)**2) >>> ((x*(1 + y) + 0.4*x*(3 + 3*y))**2).as_content_primitive() (1, 4.84*x**2*(y + 1)**2) Radical content can also be factored out of the primitive: >>> (2*sqrt(2) + 4*sqrt(10)).as_content_primitive(radical=True) (2, sqrt(2)*(1 + 2*sqrt(5))) If clear=False (default is True) then content will not be removed from an Add if it can be distributed to leave one or more terms with integer coefficients. >>> (x/2 + y).as_content_primitive() (1/2, x + 2*y) >>> (x/2 + y).as_content_primitive(clear=False) (1, x/2 + y) """ return S.One, self def as_numer_denom(self): """ expression -> a/b -> a, b This is just a stub that should be defined by an object's class methods to get anything else. See Also ======== normal: return ``a/b`` instead of ``(a, b)`` """ return self, S.One def normal(self): """ expression -> a/b See Also ======== as_numer_denom: return ``(a, b)`` instead of ``a/b`` """ from .mul import _unevaluated_Mul n, d = self.as_numer_denom() if d is S.One: return n if d.is_Number: return _unevaluated_Mul(n, 1/d) else: return n/d def extract_multiplicatively(self, c): """Return None if it's not possible to make self in the form c * something in a nice way, i.e. preserving the properties of arguments of self. Examples ======== >>> from sympy import symbols, Rational >>> x, y = symbols('x,y', real=True) >>> ((x*y)**3).extract_multiplicatively(x**2 * y) x*y**2 >>> ((x*y)**3).extract_multiplicatively(x**4 * y) >>> (2*x).extract_multiplicatively(2) x >>> (2*x).extract_multiplicatively(3) >>> (Rational(1, 2)*x).extract_multiplicatively(3) x/6 """ from .add import _unevaluated_Add c = sympify(c) if self is S.NaN: return None if c is S.One: return self elif c == self: return S.One if c.is_Add: cc, pc = c.primitive() if cc is not S.One: c = Mul(cc, pc, evaluate=False) if c.is_Mul: a, b = c.as_two_terms() x = self.extract_multiplicatively(a) if x is not None: return x.extract_multiplicatively(b) else: return x quotient = self / c if self.is_Number: if self is S.Infinity: if c.is_positive: return S.Infinity elif self is S.NegativeInfinity: if c.is_negative: return S.Infinity elif c.is_positive: return S.NegativeInfinity elif self is S.ComplexInfinity: if not c.is_zero: return S.ComplexInfinity elif self.is_Integer: if not quotient.is_Integer: return None elif self.is_positive and quotient.is_negative: return None else: return quotient elif self.is_Rational: if not quotient.is_Rational: return None elif self.is_positive and quotient.is_negative: return None else: return quotient elif self.is_Float: if not quotient.is_Float: return None elif self.is_positive and quotient.is_negative: return None else: return quotient elif self.is_NumberSymbol or self.is_Symbol or self is S.ImaginaryUnit: if quotient.is_Mul and len(quotient.args) == 2: if quotient.args[0].is_Integer and quotient.args[0].is_positive and quotient.args[1] == self: return quotient elif quotient.is_Integer and c.is_Number: return quotient elif self.is_Add: cs, ps = self.primitive() # assert cs >= 1 if c.is_Number and c is not S.NegativeOne: # assert c != 1 (handled at top) if cs is not S.One: if c.is_negative: xc = -(cs.extract_multiplicatively(-c)) else: xc = cs.extract_multiplicatively(c) if xc is not None: return xc*ps # rely on 2-arg Mul to restore Add return # |c| != 1 can only be extracted from cs if c == ps: return cs # check args of ps newargs = [] for arg in ps.args: newarg = arg.extract_multiplicatively(c) if newarg is None: return # all or nothing newargs.append(newarg) if cs is not S.One: args = [cs*t for t in newargs] # args may be in different order return _unevaluated_Add(*args) else: return Add._from_args(newargs) elif self.is_Mul: args = list(self.args) for i, arg in enumerate(args): newarg = arg.extract_multiplicatively(c) if newarg is not None: args[i] = newarg return Mul(*args) elif self.is_Pow: if c.is_Pow and c.base == self.base: new_exp = self.exp.extract_additively(c.exp) if new_exp is not None: return self.base ** (new_exp) elif c == self.base: new_exp = self.exp.extract_additively(1) if new_exp is not None: return self.base ** (new_exp) def extract_additively(self, c): """Return self - c if it's possible to subtract c from self and make all matching coefficients move towards zero, else return None. Examples ======== >>> from sympy.abc import x, y >>> e = 2*x + 3 >>> e.extract_additively(x + 1) x + 2 >>> e.extract_additively(3*x) >>> e.extract_additively(4) >>> (y*(x + 1)).extract_additively(x + 1) >>> ((x + 1)*(x + 2*y + 1) + 3).extract_additively(x + 1) (x + 1)*(x + 2*y) + 3 Sometimes auto-expansion will return a less simplified result than desired; gcd_terms might be used in such cases: >>> from sympy import gcd_terms >>> (4*x*(y + 1) + y).extract_additively(x) 4*x*(y + 1) + x*(4*y + 3) - x*(4*y + 4) + y >>> gcd_terms(_) x*(4*y + 3) + y See Also ======== extract_multiplicatively coeff as_coefficient """ c = sympify(c) if self is S.NaN: return None if c.is_zero: return self elif c == self: return S.Zero elif self == S.Zero: return None if self.is_Number: if not c.is_Number: return None co = self diff = co - c # XXX should we match types? i.e should 3 - .1 succeed? if (co > 0 and diff > 0 and diff < co or co < 0 and diff < 0 and diff > co): return diff return None if c.is_Number: co, t = self.as_coeff_Add() xa = co.extract_additively(c) if xa is None: return None return xa + t # handle the args[0].is_Number case separately # since we will have trouble looking for the coeff of # a number. if c.is_Add and c.args[0].is_Number: # whole term as a term factor co = self.coeff(c) xa0 = (co.extract_additively(1) or 0)*c if xa0: diff = self - co*c return (xa0 + (diff.extract_additively(c) or diff)) or None # term-wise h, t = c.as_coeff_Add() sh, st = self.as_coeff_Add() xa = sh.extract_additively(h) if xa is None: return None xa2 = st.extract_additively(t) if xa2 is None: return None return xa + xa2 # whole term as a term factor co = self.coeff(c) xa0 = (co.extract_additively(1) or 0)*c if xa0: diff = self - co*c return (xa0 + (diff.extract_additively(c) or diff)) or None # term-wise coeffs = [] for a in Add.make_args(c): ac, at = a.as_coeff_Mul() co = self.coeff(at) if not co: return None coc, cot = co.as_coeff_Add() xa = coc.extract_additively(ac) if xa is None: return None self -= co*at coeffs.append((cot + xa)*at) coeffs.append(self) return Add(*coeffs) @property def expr_free_symbols(self): """ Like ``free_symbols``, but returns the free symbols only if they are contained in an expression node. Examples ======== >>> from sympy.utilities.exceptions import SymPyDeprecationWarning >>> import warnings >>> warnings.simplefilter("ignore", SymPyDeprecationWarning) >>> from sympy.abc import x, y >>> (x + y).expr_free_symbols {x, y} If the expression is contained in a non-expression object, don't return the free symbols. Compare: >>> from sympy import Tuple >>> t = Tuple(x + y) >>> t.expr_free_symbols set() >>> t.free_symbols {x, y} """ from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning(feature="expr_free_symbols method", issue=21494, deprecated_since_version="1.9").warn() return {j for i in self.args for j in i.expr_free_symbols} def could_extract_minus_sign(self): """Return True if self is not in a canonical form with respect to its sign. For most expressions, e, there will be a difference in e and -e. When there is, True will be returned for one and False for the other; False will be returned if there is no difference. Examples ======== >>> from sympy.abc import x, y >>> e = x - y >>> {i.could_extract_minus_sign() for i in (e, -e)} {False, True} """ negative_self = -self if self == negative_self: return False # e.g. zoo*x == -zoo*x self_has_minus = (self.extract_multiplicatively(-1) is not None) negative_self_has_minus = ( (negative_self).extract_multiplicatively(-1) is not None) if self_has_minus != negative_self_has_minus: return self_has_minus else: if self.is_Add: # We choose the one with less arguments with minus signs all_args = len(self.args) negative_args = len([False for arg in self.args if arg.could_extract_minus_sign()]) positive_args = all_args - negative_args if positive_args > negative_args: return False elif positive_args < negative_args: return True elif self.is_Mul: # We choose the one with an odd number of minus signs num, den = self.as_numer_denom() args = Mul.make_args(num) + Mul.make_args(den) arg_signs = [arg.could_extract_minus_sign() for arg in args] negative_args = list(filter(None, arg_signs)) return len(negative_args) % 2 == 1 # As a last resort, we choose the one with greater value of .sort_key() return bool(self.sort_key() < negative_self.sort_key()) def extract_branch_factor(self, allow_half=False): """ Try to write self as ``exp_polar(2*pi*I*n)*z`` in a nice way. Return (z, n). >>> from sympy import exp_polar, I, pi >>> from sympy.abc import x, y >>> exp_polar(I*pi).extract_branch_factor() (exp_polar(I*pi), 0) >>> exp_polar(2*I*pi).extract_branch_factor() (1, 1) >>> exp_polar(-pi*I).extract_branch_factor() (exp_polar(I*pi), -1) >>> exp_polar(3*pi*I + x).extract_branch_factor() (exp_polar(x + I*pi), 1) >>> (y*exp_polar(-5*pi*I)*exp_polar(3*pi*I + 2*pi*x)).extract_branch_factor() (y*exp_polar(2*pi*x), -1) >>> exp_polar(-I*pi/2).extract_branch_factor() (exp_polar(-I*pi/2), 0) If allow_half is True, also extract exp_polar(I*pi): >>> exp_polar(I*pi).extract_branch_factor(allow_half=True) (1, 1/2) >>> exp_polar(2*I*pi).extract_branch_factor(allow_half=True) (1, 1) >>> exp_polar(3*I*pi).extract_branch_factor(allow_half=True) (1, 3/2) >>> exp_polar(-I*pi).extract_branch_factor(allow_half=True) (1, -1/2) """ from sympy import exp_polar, pi, I, ceiling, Add n = S.Zero res = S.One args = Mul.make_args(self) exps = [] for arg in args: if isinstance(arg, exp_polar): exps += [arg.exp] else: res *= arg piimult = S.Zero extras = [] while exps: exp = exps.pop() if exp.is_Add: exps += exp.args continue if exp.is_Mul: coeff = exp.as_coefficient(pi*I) if coeff is not None: piimult += coeff continue extras += [exp] if piimult.is_number: coeff = piimult tail = () else: coeff, tail = piimult.as_coeff_add(*piimult.free_symbols) # round down to nearest multiple of 2 branchfact = ceiling(coeff/2 - S.Half)*2 n += branchfact/2 c = coeff - branchfact if allow_half: nc = c.extract_additively(1) if nc is not None: n += S.Half c = nc newexp = pi*I*Add(*((c, ) + tail)) + Add(*extras) if newexp != 0: res *= exp_polar(newexp) return res, n def _eval_is_polynomial(self, syms): if self.free_symbols.intersection(syms) == set(): return True return False def is_polynomial(self, *syms): r""" Return True if self is a polynomial in syms and False otherwise. This checks if self is an exact polynomial in syms. This function returns False for expressions that are "polynomials" with symbolic exponents. Thus, you should be able to apply polynomial algorithms to expressions for which this returns True, and Poly(expr, \*syms) should work if and only if expr.is_polynomial(\*syms) returns True. The polynomial does not have to be in expanded form. If no symbols are given, all free symbols in the expression will be used. This is not part of the assumptions system. You cannot do Symbol('z', polynomial=True). Examples ======== >>> from sympy import Symbol >>> x = Symbol('x') >>> ((x**2 + 1)**4).is_polynomial(x) True >>> ((x**2 + 1)**4).is_polynomial() True >>> (2**x + 1).is_polynomial(x) False >>> n = Symbol('n', nonnegative=True, integer=True) >>> (x**n + 1).is_polynomial(x) False This function does not attempt any nontrivial simplifications that may result in an expression that does not appear to be a polynomial to become one. >>> from sympy import sqrt, factor, cancel >>> y = Symbol('y', positive=True) >>> a = sqrt(y**2 + 2*y + 1) >>> a.is_polynomial(y) False >>> factor(a) y + 1 >>> factor(a).is_polynomial(y) True >>> b = (y**2 + 2*y + 1)/(y + 1) >>> b.is_polynomial(y) False >>> cancel(b) y + 1 >>> cancel(b).is_polynomial(y) True See also .is_rational_function() """ if syms: syms = set(map(sympify, syms)) else: syms = self.free_symbols if syms.intersection(self.free_symbols) == set(): # constant polynomial return True else: return self._eval_is_polynomial(syms) def _eval_is_rational_function(self, syms): if self.free_symbols.intersection(syms) == set(): return True return False def is_rational_function(self, *syms): """ Test whether function is a ratio of two polynomials in the given symbols, syms. When syms is not given, all free symbols will be used. The rational function does not have to be in expanded or in any kind of canonical form. This function returns False for expressions that are "rational functions" with symbolic exponents. Thus, you should be able to call .as_numer_denom() and apply polynomial algorithms to the result for expressions for which this returns True. This is not part of the assumptions system. You cannot do Symbol('z', rational_function=True). Examples ======== >>> from sympy import Symbol, sin >>> from sympy.abc import x, y >>> (x/y).is_rational_function() True >>> (x**2).is_rational_function() True >>> (x/sin(y)).is_rational_function(y) False >>> n = Symbol('n', integer=True) >>> (x**n + 1).is_rational_function(x) False This function does not attempt any nontrivial simplifications that may result in an expression that does not appear to be a rational function to become one. >>> from sympy import sqrt, factor >>> y = Symbol('y', positive=True) >>> a = sqrt(y**2 + 2*y + 1)/y >>> a.is_rational_function(y) False >>> factor(a) (y + 1)/y >>> factor(a).is_rational_function(y) True See also is_algebraic_expr(). """ if self in [S.NaN, S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: return False if syms: syms = set(map(sympify, syms)) else: syms = self.free_symbols if syms.intersection(self.free_symbols) == set(): # constant rational function return True else: return self._eval_is_rational_function(syms) def _eval_is_meromorphic(self, x, a): # Default implementation, return True for constants. return None if self.has(x) else True def is_meromorphic(self, x, a): """ This tests whether an expression is meromorphic as a function of the given symbol ``x`` at the point ``a``. This method is intended as a quick test that will return None if no decision can be made without simplification or more detailed analysis. Examples ======== >>> from sympy import zoo, log, sin, sqrt >>> from sympy.abc import x >>> f = 1/x**2 + 1 - 2*x**3 >>> f.is_meromorphic(x, 0) True >>> f.is_meromorphic(x, 1) True >>> f.is_meromorphic(x, zoo) True >>> g = x**log(3) >>> g.is_meromorphic(x, 0) False >>> g.is_meromorphic(x, 1) True >>> g.is_meromorphic(x, zoo) False >>> h = sin(1/x)*x**2 >>> h.is_meromorphic(x, 0) False >>> h.is_meromorphic(x, 1) True >>> h.is_meromorphic(x, zoo) True Multivalued functions are considered meromorphic when their branches are meromorphic. Thus most functions are meromorphic everywhere except at essential singularities and branch points. In particular, they will be meromorphic also on branch cuts except at their endpoints. >>> log(x).is_meromorphic(x, -1) True >>> log(x).is_meromorphic(x, 0) False >>> sqrt(x).is_meromorphic(x, -1) True >>> sqrt(x).is_meromorphic(x, 0) False """ if not x.is_symbol: raise TypeError("{} should be of symbol type".format(x)) a = sympify(a) return self._eval_is_meromorphic(x, a) def _eval_is_algebraic_expr(self, syms): if self.free_symbols.intersection(syms) == set(): return True return False def is_algebraic_expr(self, *syms): """ This tests whether a given expression is algebraic or not, in the given symbols, syms. When syms is not given, all free symbols will be used. The rational function does not have to be in expanded or in any kind of canonical form. This function returns False for expressions that are "algebraic expressions" with symbolic exponents. This is a simple extension to the is_rational_function, including rational exponentiation. Examples ======== >>> from sympy import Symbol, sqrt >>> x = Symbol('x', real=True) >>> sqrt(1 + x).is_rational_function() False >>> sqrt(1 + x).is_algebraic_expr() True This function does not attempt any nontrivial simplifications that may result in an expression that does not appear to be an algebraic expression to become one. >>> from sympy import exp, factor >>> a = sqrt(exp(x)**2 + 2*exp(x) + 1)/(exp(x) + 1) >>> a.is_algebraic_expr(x) False >>> factor(a).is_algebraic_expr() True See Also ======== is_rational_function() References ========== - https://en.wikipedia.org/wiki/Algebraic_expression """ if syms: syms = set(map(sympify, syms)) else: syms = self.free_symbols if syms.intersection(self.free_symbols) == set(): # constant algebraic expression return True else: return self._eval_is_algebraic_expr(syms) ################################################################################### ##################### SERIES, LEADING TERM, LIMIT, ORDER METHODS ################## ################################################################################### def series(self, x=None, x0=0, n=6, dir="+", logx=None, cdir=0): """ Series expansion of "self" around ``x = x0`` yielding either terms of the series one by one (the lazy series given when n=None), else all the terms at once when n != None. Returns the series expansion of "self" around the point ``x = x0`` with respect to ``x`` up to ``O((x - x0)**n, x, x0)`` (default n is 6). If ``x=None`` and ``self`` is univariate, the univariate symbol will be supplied, otherwise an error will be raised. Parameters ========== expr : Expression The expression whose series is to be expanded. x : Symbol It is the variable of the expression to be calculated. x0 : Value The value around which ``x`` is calculated. Can be any value from ``-oo`` to ``oo``. n : Value The number of terms upto which the series is to be expanded. dir : String, optional The series-expansion can be bi-directional. If ``dir="+"``, then (x->x0+). If ``dir="-", then (x->x0-). For infinite ``x0`` (``oo`` or ``-oo``), the ``dir`` argument is determined from the direction of the infinity (i.e., ``dir="-"`` for ``oo``). logx : optional It is used to replace any log(x) in the returned series with a symbolic value rather than evaluating the actual value. cdir : optional It stands for complex direction, and indicates the direction from which the expansion needs to be evaluated. Examples ======== >>> from sympy import cos, exp, tan >>> from sympy.abc import x, y >>> cos(x).series() 1 - x**2/2 + x**4/24 + O(x**6) >>> cos(x).series(n=4) 1 - x**2/2 + O(x**4) >>> cos(x).series(x, x0=1, n=2) cos(1) - (x - 1)*sin(1) + O((x - 1)**2, (x, 1)) >>> e = cos(x + exp(y)) >>> e.series(y, n=2) cos(x + 1) - y*sin(x + 1) + O(y**2) >>> e.series(x, n=2) cos(exp(y)) - x*sin(exp(y)) + O(x**2) If ``n=None`` then a generator of the series terms will be returned. >>> term=cos(x).series(n=None) >>> [next(term) for i in range(2)] [1, -x**2/2] For ``dir=+`` (default) the series is calculated from the right and for ``dir=-`` the series from the left. For smooth functions this flag will not alter the results. >>> abs(x).series(dir="+") x >>> abs(x).series(dir="-") -x >>> f = tan(x) >>> f.series(x, 2, 6, "+") tan(2) + (1 + tan(2)**2)*(x - 2) + (x - 2)**2*(tan(2)**3 + tan(2)) + (x - 2)**3*(1/3 + 4*tan(2)**2/3 + tan(2)**4) + (x - 2)**4*(tan(2)**5 + 5*tan(2)**3/3 + 2*tan(2)/3) + (x - 2)**5*(2/15 + 17*tan(2)**2/15 + 2*tan(2)**4 + tan(2)**6) + O((x - 2)**6, (x, 2)) >>> f.series(x, 2, 3, "-") tan(2) + (2 - x)*(-tan(2)**2 - 1) + (2 - x)**2*(tan(2)**3 + tan(2)) + O((x - 2)**3, (x, 2)) Returns ======= Expr : Expression Series expansion of the expression about x0 Raises ====== TypeError If "n" and "x0" are infinity objects PoleError If "x0" is an infinity object """ from sympy import collect, Dummy, Order, Rational, Symbol, ceiling, PoleError if x is None: syms = self.free_symbols if not syms: return self elif len(syms) > 1: raise ValueError('x must be given for multivariate functions.') x = syms.pop() if isinstance(x, Symbol): dep = x in self.free_symbols else: d = Dummy() dep = d in self.xreplace({x: d}).free_symbols if not dep: if n is None: return (s for s in [self]) else: return self if len(dir) != 1 or dir not in '+-': raise ValueError("Dir must be '+' or '-'") if x0 in [S.Infinity, S.NegativeInfinity]: try: sgn = 1 if x0 is S.Infinity else -1 s = self.subs(x, sgn/x).series(x, n=n, dir='+', cdir=cdir) if n is None: return (si.subs(x, sgn/x) for si in s) return s.subs(x, sgn/x) except PoleError: s = self.subs(x, sgn*x).aseries(x, n=n) return s.subs(x, sgn*x) # use rep to shift origin to x0 and change sign (if dir is negative) # and undo the process with rep2 if x0 or dir == '-': if dir == '-': rep = -x + x0 rep2 = -x rep2b = x0 else: rep = x + x0 rep2 = x rep2b = -x0 s = self.subs(x, rep).series(x, x0=0, n=n, dir='+', logx=logx, cdir=cdir) if n is None: # lseries... return (si.subs(x, rep2 + rep2b) for si in s) return s.subs(x, rep2 + rep2b) # from here on it's x0=0 and dir='+' handling if x.is_positive is x.is_negative is None or x.is_Symbol is not True: # replace x with an x that has a positive assumption xpos = Dummy('x', positive=True, finite=True) rv = self.subs(x, xpos).series(xpos, x0, n, dir, logx=logx, cdir=cdir) if n is None: return (s.subs(xpos, x) for s in rv) else: return rv.subs(xpos, x) if n is not None: # nseries handling s1 = self._eval_nseries(x, n=n, logx=logx, cdir=cdir) o = s1.getO() or S.Zero if o: # make sure the requested order is returned ngot = o.getn() if ngot > n: # leave o in its current form (e.g. with x*log(x)) so # it eats terms properly, then replace it below if n != 0: s1 += o.subs(x, x**Rational(n, ngot)) else: s1 += Order(1, x) elif ngot < n: # increase the requested number of terms to get the desired # number keep increasing (up to 9) until the received order # is different than the original order and then predict how # many additional terms are needed for more in range(1, 9): s1 = self._eval_nseries(x, n=n + more, logx=logx, cdir=cdir) newn = s1.getn() if newn != ngot: ndo = n + ceiling((n - ngot)*more/(newn - ngot)) s1 = self._eval_nseries(x, n=ndo, logx=logx, cdir=cdir) while s1.getn() < n: s1 = self._eval_nseries(x, n=ndo, logx=logx, cdir=cdir) ndo += 1 break else: raise ValueError('Could not calculate %s terms for %s' % (str(n), self)) s1 += Order(x**n, x) o = s1.getO() s1 = s1.removeO() elif s1.has(Order): # asymptotic expansion return s1 else: o = Order(x**n, x) s1done = s1.doit() if (s1done + o).removeO() == s1done: o = S.Zero try: return collect(s1, x) + o except NotImplementedError: return s1 + o else: # lseries handling def yield_lseries(s): """Return terms of lseries one at a time.""" for si in s: if not si.is_Add: yield si continue # yield terms 1 at a time if possible # by increasing order until all the # terms have been returned yielded = 0 o = Order(si, x)*x ndid = 0 ndo = len(si.args) while 1: do = (si - yielded + o).removeO() o *= x if not do or do.is_Order: continue if do.is_Add: ndid += len(do.args) else: ndid += 1 yield do if ndid == ndo: break yielded += do return yield_lseries(self.removeO()._eval_lseries(x, logx=logx, cdir=cdir)) def aseries(self, x=None, n=6, bound=0, hir=False): """Asymptotic Series expansion of self. This is equivalent to ``self.series(x, oo, n)``. Parameters ========== self : Expression The expression whose series is to be expanded. x : Symbol It is the variable of the expression to be calculated. n : Value The number of terms upto which the series is to be expanded. hir : Boolean Set this parameter to be True to produce hierarchical series. It stops the recursion at an early level and may provide nicer and more useful results. bound : Value, Integer Use the ``bound`` parameter to give limit on rewriting coefficients in its normalised form. Examples ======== >>> from sympy import sin, exp >>> from sympy.abc import x >>> e = sin(1/x + exp(-x)) - sin(1/x) >>> e.aseries(x) (1/(24*x**4) - 1/(2*x**2) + 1 + O(x**(-6), (x, oo)))*exp(-x) >>> e.aseries(x, n=3, hir=True) -exp(-2*x)*sin(1/x)/2 + exp(-x)*cos(1/x) + O(exp(-3*x), (x, oo)) >>> e = exp(exp(x)/(1 - 1/x)) >>> e.aseries(x) exp(exp(x)/(1 - 1/x)) >>> e.aseries(x, bound=3) # doctest: +SKIP exp(exp(x)/x**2)*exp(exp(x)/x)*exp(-exp(x) + exp(x)/(1 - 1/x) - exp(x)/x - exp(x)/x**2)*exp(exp(x)) Returns ======= Expr Asymptotic series expansion of the expression. Notes ===== This algorithm is directly induced from the limit computational algorithm provided by Gruntz. It majorly uses the mrv and rewrite sub-routines. The overall idea of this algorithm is first to look for the most rapidly varying subexpression w of a given expression f and then expands f in a series in w. Then same thing is recursively done on the leading coefficient till we get constant coefficients. If the most rapidly varying subexpression of a given expression f is f itself, the algorithm tries to find a normalised representation of the mrv set and rewrites f using this normalised representation. If the expansion contains an order term, it will be either ``O(x ** (-n))`` or ``O(w ** (-n))`` where ``w`` belongs to the most rapidly varying expression of ``self``. References ========== .. [1] A New Algorithm for Computing Asymptotic Series - Dominik Gruntz .. [2] Gruntz thesis - p90 .. [3] http://en.wikipedia.org/wiki/Asymptotic_expansion See Also ======== Expr.aseries: See the docstring of this function for complete details of this wrapper. """ from sympy import Order, Dummy, PoleError from sympy.functions import exp, log from sympy.series.gruntz import mrv, rewrite if x.is_positive is x.is_negative is None: xpos = Dummy('x', positive=True) return self.subs(x, xpos).aseries(xpos, n, bound, hir).subs(xpos, x) try: om, exps = mrv(self, x) except PoleError: return self # We move one level up by replacing `x` by `exp(x)`, and then # computing the asymptotic series for f(exp(x)). Then asymptotic series # can be obtained by moving one-step back, by replacing x by ln(x). if x in om: s = self.subs(x, exp(x)).aseries(x, n, bound, hir).subs(x, log(x)) if s.getO(): return s + Order(1/x**n, (x, S.Infinity)) return s k = Dummy('k', positive=True) # f is rewritten in terms of omega func, logw = rewrite(exps, om, x, k) if self in om: if bound <= 0: return self s = (self.exp).aseries(x, n, bound=bound) s = s.func(*[t.removeO() for t in s.args]) try: res = exp(s.subs(x, 1/x).as_leading_term(x).subs(x, 1/x)) except PoleError: res = self func = exp(self.args[0] - res.args[0]) / k logw = log(1/res) s = func.series(k, 0, n) # Hierarchical series if hir: return s.subs(k, exp(logw)) o = s.getO() terms = sorted(Add.make_args(s.removeO()), key=lambda i: int(i.as_coeff_exponent(k)[1])) s = S.Zero has_ord = False # Then we recursively expand these coefficients one by one into # their asymptotic series in terms of their most rapidly varying subexpressions. for t in terms: coeff, expo = t.as_coeff_exponent(k) if coeff.has(x): # Recursive step snew = coeff.aseries(x, n, bound=bound-1) if has_ord and snew.getO(): break elif snew.getO(): has_ord = True s += (snew * k**expo) else: s += t if not o or has_ord: return s.subs(k, exp(logw)) return (s + o).subs(k, exp(logw)) def taylor_term(self, n, x, *previous_terms): """General method for the taylor term. This method is slow, because it differentiates n-times. Subclasses can redefine it to make it faster by using the "previous_terms". """ from sympy import Dummy, factorial x = sympify(x) _x = Dummy('x') return self.subs(x, _x).diff(_x, n).subs(_x, x).subs(x, 0) * x**n / factorial(n) def lseries(self, x=None, x0=0, dir='+', logx=None, cdir=0): """ Wrapper for series yielding an iterator of the terms of the series. Note: an infinite series will yield an infinite iterator. The following, for exaxmple, will never terminate. It will just keep printing terms of the sin(x) series:: for term in sin(x).lseries(x): print term The advantage of lseries() over nseries() is that many times you are just interested in the next term in the series (i.e. the first term for example), but you don't know how many you should ask for in nseries() using the "n" parameter. See also nseries(). """ return self.series(x, x0, n=None, dir=dir, logx=logx, cdir=cdir) def _eval_lseries(self, x, logx=None, cdir=0): # default implementation of lseries is using nseries(), and adaptively # increasing the "n". As you can see, it is not very efficient, because # we are calculating the series over and over again. Subclasses should # override this method and implement much more efficient yielding of # terms. n = 0 series = self._eval_nseries(x, n=n, logx=logx, cdir=cdir) while series.is_Order: n += 1 series = self._eval_nseries(x, n=n, logx=logx, cdir=cdir) e = series.removeO() yield e if e is S.Zero: return while 1: while 1: n += 1 series = self._eval_nseries(x, n=n, logx=logx, cdir=cdir).removeO() if e != series: break if (series - self).cancel() is S.Zero: return yield series - e e = series def nseries(self, x=None, x0=0, n=6, dir='+', logx=None, cdir=0): """ Wrapper to _eval_nseries if assumptions allow, else to series. If x is given, x0 is 0, dir='+', and self has x, then _eval_nseries is called. This calculates "n" terms in the innermost expressions and then builds up the final series just by "cross-multiplying" everything out. The optional ``logx`` parameter can be used to replace any log(x) in the returned series with a symbolic value to avoid evaluating log(x) at 0. A symbol to use in place of log(x) should be provided. Advantage -- it's fast, because we don't have to determine how many terms we need to calculate in advance. Disadvantage -- you may end up with less terms than you may have expected, but the O(x**n) term appended will always be correct and so the result, though perhaps shorter, will also be correct. If any of those assumptions is not met, this is treated like a wrapper to series which will try harder to return the correct number of terms. See also lseries(). Examples ======== >>> from sympy import sin, log, Symbol >>> from sympy.abc import x, y >>> sin(x).nseries(x, 0, 6) x - x**3/6 + x**5/120 + O(x**6) >>> log(x+1).nseries(x, 0, 5) x - x**2/2 + x**3/3 - x**4/4 + O(x**5) Handling of the ``logx`` parameter --- in the following example the expansion fails since ``sin`` does not have an asymptotic expansion at -oo (the limit of log(x) as x approaches 0): >>> e = sin(log(x)) >>> e.nseries(x, 0, 6) Traceback (most recent call last): ... PoleError: ... ... >>> logx = Symbol('logx') >>> e.nseries(x, 0, 6, logx=logx) sin(logx) In the following example, the expansion works but gives only an Order term unless the ``logx`` parameter is used: >>> e = x**y >>> e.nseries(x, 0, 2) O(log(x)**2) >>> e.nseries(x, 0, 2, logx=logx) exp(logx*y) """ if x and not x in self.free_symbols: return self if x is None or x0 or dir != '+': # {see XPOS above} or (x.is_positive == x.is_negative == None): return self.series(x, x0, n, dir, cdir=cdir) else: return self._eval_nseries(x, n=n, logx=logx, cdir=cdir) def _eval_nseries(self, x, n, logx, cdir): """ Return terms of series for self up to O(x**n) at x=0 from the positive direction. This is a method that should be overridden in subclasses. Users should never call this method directly (use .nseries() instead), so you don't have to write docstrings for _eval_nseries(). """ from sympy.utilities.misc import filldedent raise NotImplementedError(filldedent(""" The _eval_nseries method should be added to %s to give terms up to O(x**n) at x=0 from the positive direction so it is available when nseries calls it.""" % self.func) ) def limit(self, x, xlim, dir='+'): """ Compute limit x->xlim. """ from sympy.series.limits import limit return limit(self, x, xlim, dir) def compute_leading_term(self, x, logx=None): """ as_leading_term is only allowed for results of .series() This is a wrapper to compute a series first. """ from sympy import Dummy, log, Piecewise, piecewise_fold from sympy.series.gruntz import calculate_series if self.has(Piecewise): expr = piecewise_fold(self) else: expr = self if self.removeO() == 0: return self if logx is None: d = Dummy('logx') s = calculate_series(expr, x, d).subs(d, log(x)) else: s = calculate_series(expr, x, logx) return s.as_leading_term(x) @cacheit def as_leading_term(self, *symbols, logx=None, cdir=0): """ Returns the leading (nonzero) term of the series expansion of self. The _eval_as_leading_term routines are used to do this, and they must always return a non-zero value. Examples ======== >>> from sympy.abc import x >>> (1 + x + x**2).as_leading_term(x) 1 >>> (1/x**2 + x + x**2).as_leading_term(x) x**(-2) """ from sympy import powsimp if len(symbols) > 1: c = self for x in symbols: c = c.as_leading_term(x, logx=logx, cdir=cdir) return c elif not symbols: return self x = sympify(symbols[0]) if not x.is_symbol: raise ValueError('expecting a Symbol but got %s' % x) if x not in self.free_symbols: return self obj = self._eval_as_leading_term(x, logx=logx, cdir=cdir) if obj is not None: return powsimp(obj, deep=True, combine='exp') raise NotImplementedError('as_leading_term(%s, %s)' % (self, x)) def _eval_as_leading_term(self, x, logx=None, cdir=0): return self def as_coeff_exponent(self, x): """ ``c*x**e -> c,e`` where x can be any symbolic expression. """ from sympy import collect s = collect(self, x) c, p = s.as_coeff_mul(x) if len(p) == 1: b, e = p[0].as_base_exp() if b == x: return c, e return s, S.Zero def leadterm(self, x, logx=None, cdir=0): """ Returns the leading term a*x**b as a tuple (a, b). Examples ======== >>> from sympy.abc import x >>> (1+x+x**2).leadterm(x) (1, 0) >>> (1/x**2+x+x**2).leadterm(x) (1, -2) """ from sympy import Dummy, log l = self.as_leading_term(x, logx=logx, cdir=cdir) d = Dummy('logx') if l.has(log(x)): l = l.subs(log(x), d) c, e = l.as_coeff_exponent(x) if x in c.free_symbols: from sympy.utilities.misc import filldedent raise ValueError(filldedent(""" cannot compute leadterm(%s, %s). The coefficient should have been free of %s but got %s""" % (self, x, x, c))) c = c.subs(d, log(x)) return c, e def as_coeff_Mul(self, rational=False): """Efficiently extract the coefficient of a product. """ return S.One, self def as_coeff_Add(self, rational=False): """Efficiently extract the coefficient of a summation. """ return S.Zero, self def fps(self, x=None, x0=0, dir=1, hyper=True, order=4, rational=True, full=False): """ Compute formal power power series of self. See the docstring of the :func:`fps` function in sympy.series.formal for more information. """ from sympy.series.formal import fps return fps(self, x, x0, dir, hyper, order, rational, full) def fourier_series(self, limits=None): """Compute fourier sine/cosine series of self. See the docstring of the :func:`fourier_series` in sympy.series.fourier for more information. """ from sympy.series.fourier import fourier_series return fourier_series(self, limits) ################################################################################### ##################### DERIVATIVE, INTEGRAL, FUNCTIONAL METHODS #################### ################################################################################### def diff(self, *symbols, **assumptions): assumptions.setdefault("evaluate", True) return _derivative_dispatch(self, *symbols, **assumptions) ########################################################################### ###################### EXPRESSION EXPANSION METHODS ####################### ########################################################################### # Relevant subclasses should override _eval_expand_hint() methods. See # the docstring of expand() for more info. def _eval_expand_complex(self, **hints): real, imag = self.as_real_imag(**hints) return real + S.ImaginaryUnit*imag @staticmethod def _expand_hint(expr, hint, deep=True, **hints): """ Helper for ``expand()``. Recursively calls ``expr._eval_expand_hint()``. Returns ``(expr, hit)``, where expr is the (possibly) expanded ``expr`` and ``hit`` is ``True`` if ``expr`` was truly expanded and ``False`` otherwise. """ hit = False # XXX: Hack to support non-Basic args # | # V if deep and getattr(expr, 'args', ()) and not expr.is_Atom: sargs = [] for arg in expr.args: arg, arghit = Expr._expand_hint(arg, hint, **hints) hit |= arghit sargs.append(arg) if hit: expr = expr.func(*sargs) if hasattr(expr, hint): newexpr = getattr(expr, hint)(**hints) if newexpr != expr: return (newexpr, True) return (expr, hit) @cacheit def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, mul=True, log=True, multinomial=True, basic=True, **hints): """ Expand an expression using hints. See the docstring of the expand() function in sympy.core.function for more information. """ from sympy.simplify.radsimp import fraction hints.update(power_base=power_base, power_exp=power_exp, mul=mul, log=log, multinomial=multinomial, basic=basic) expr = self if hints.pop('frac', False): n, d = [a.expand(deep=deep, modulus=modulus, **hints) for a in fraction(self)] return n/d elif hints.pop('denom', False): n, d = fraction(self) return n/d.expand(deep=deep, modulus=modulus, **hints) elif hints.pop('numer', False): n, d = fraction(self) return n.expand(deep=deep, modulus=modulus, **hints)/d # Although the hints are sorted here, an earlier hint may get applied # at a given node in the expression tree before another because of how # the hints are applied. e.g. expand(log(x*(y + z))) -> log(x*y + # x*z) because while applying log at the top level, log and mul are # applied at the deeper level in the tree so that when the log at the # upper level gets applied, the mul has already been applied at the # lower level. # Additionally, because hints are only applied once, the expression # may not be expanded all the way. For example, if mul is applied # before multinomial, x*(x + 1)**2 won't be expanded all the way. For # now, we just use a special case to make multinomial run before mul, # so that at least polynomials will be expanded all the way. In the # future, smarter heuristics should be applied. # TODO: Smarter heuristics def _expand_hint_key(hint): """Make multinomial come before mul""" if hint == 'mul': return 'mulz' return hint for hint in sorted(hints.keys(), key=_expand_hint_key): use_hint = hints[hint] if use_hint: hint = '_eval_expand_' + hint expr, hit = Expr._expand_hint(expr, hint, deep=deep, **hints) while True: was = expr if hints.get('multinomial', False): expr, _ = Expr._expand_hint( expr, '_eval_expand_multinomial', deep=deep, **hints) if hints.get('mul', False): expr, _ = Expr._expand_hint( expr, '_eval_expand_mul', deep=deep, **hints) if hints.get('log', False): expr, _ = Expr._expand_hint( expr, '_eval_expand_log', deep=deep, **hints) if expr == was: break if modulus is not None: modulus = sympify(modulus) if not modulus.is_Integer or modulus <= 0: raise ValueError( "modulus must be a positive integer, got %s" % modulus) terms = [] for term in Add.make_args(expr): coeff, tail = term.as_coeff_Mul(rational=True) coeff %= modulus if coeff: terms.append(coeff*tail) expr = Add(*terms) return expr ########################################################################### ################### GLOBAL ACTION VERB WRAPPER METHODS #################### ########################################################################### def integrate(self, *args, **kwargs): """See the integrate function in sympy.integrals""" from sympy.integrals import integrate return integrate(self, *args, **kwargs) def nsimplify(self, constants=[], tolerance=None, full=False): """See the nsimplify function in sympy.simplify""" from sympy.simplify import nsimplify return nsimplify(self, constants, tolerance, full) def separate(self, deep=False, force=False): """See the separate function in sympy.simplify""" from sympy.core.function import expand_power_base return expand_power_base(self, deep=deep, force=force) def collect(self, syms, func=None, evaluate=True, exact=False, distribute_order_term=True): """See the collect function in sympy.simplify""" from sympy.simplify import collect return collect(self, syms, func, evaluate, exact, distribute_order_term) def together(self, *args, **kwargs): """See the together function in sympy.polys""" from sympy.polys import together return together(self, *args, **kwargs) def apart(self, x=None, **args): """See the apart function in sympy.polys""" from sympy.polys import apart return apart(self, x, **args) def ratsimp(self): """See the ratsimp function in sympy.simplify""" from sympy.simplify import ratsimp return ratsimp(self) def trigsimp(self, **args): """See the trigsimp function in sympy.simplify""" from sympy.simplify import trigsimp return trigsimp(self, **args) def radsimp(self, **kwargs): """See the radsimp function in sympy.simplify""" from sympy.simplify import radsimp return radsimp(self, **kwargs) def powsimp(self, *args, **kwargs): """See the powsimp function in sympy.simplify""" from sympy.simplify import powsimp return powsimp(self, *args, **kwargs) def combsimp(self): """See the combsimp function in sympy.simplify""" from sympy.simplify import combsimp return combsimp(self) def gammasimp(self): """See the gammasimp function in sympy.simplify""" from sympy.simplify import gammasimp return gammasimp(self) def factor(self, *gens, **args): """See the factor() function in sympy.polys.polytools""" from sympy.polys import factor return factor(self, *gens, **args) def cancel(self, *gens, **args): """See the cancel function in sympy.polys""" from sympy.polys import cancel return cancel(self, *gens, **args) def invert(self, g, *gens, **args): """Return the multiplicative inverse of ``self`` mod ``g`` where ``self`` (and ``g``) may be symbolic expressions). See Also ======== sympy.core.numbers.mod_inverse, sympy.polys.polytools.invert """ from sympy.polys.polytools import invert from sympy.core.numbers import mod_inverse if self.is_number and getattr(g, 'is_number', True): return mod_inverse(self, g) return invert(self, g, *gens, **args) def round(self, n=None): """Return x rounded to the given decimal place. If a complex number would results, apply round to the real and imaginary components of the number. Examples ======== >>> from sympy import pi, E, I, S, Number >>> pi.round() 3 >>> pi.round(2) 3.14 >>> (2*pi + E*I).round() 6 + 3*I The round method has a chopping effect: >>> (2*pi + I/10).round() 6 >>> (pi/10 + 2*I).round() 2*I >>> (pi/10 + E*I).round(2) 0.31 + 2.72*I Notes ===== The Python ``round`` function uses the SymPy ``round`` method so it will always return a SymPy number (not a Python float or int): >>> isinstance(round(S(123), -2), Number) True """ from sympy.core.numbers import Float x = self if not x.is_number: raise TypeError("can't round symbolic expression") if not x.is_Atom: if not pure_complex(x.n(2), or_real=True): raise TypeError( 'Expected a number but got %s:' % func_name(x)) elif x in (S.NaN, S.Infinity, S.NegativeInfinity, S.ComplexInfinity): return x if x.is_extended_real is False: r, i = x.as_real_imag() return r.round(n) + S.ImaginaryUnit*i.round(n) if not x: return S.Zero if n is None else x p = as_int(n or 0) if x.is_Integer: return Integer(round(int(x), p)) digits_to_decimal = _mag(x) # _mag(12) = 2, _mag(.012) = -1 allow = digits_to_decimal + p precs = [f._prec for f in x.atoms(Float)] dps = prec_to_dps(max(precs)) if precs else None if dps is None: # assume everything is exact so use the Python # float default or whatever was requested dps = max(15, allow) else: allow = min(allow, dps) # this will shift all digits to right of decimal # and give us dps to work with as an int shift = -digits_to_decimal + dps extra = 1 # how far we look past known digits # NOTE # mpmath will calculate the binary representation to # an arbitrary number of digits but we must base our # answer on a finite number of those digits, e.g. # .575 2589569785738035/2**52 in binary. # mpmath shows us that the first 18 digits are # >>> Float(.575).n(18) # 0.574999999999999956 # The default precision is 15 digits and if we ask # for 15 we get # >>> Float(.575).n(15) # 0.575000000000000 # mpmath handles rounding at the 15th digit. But we # need to be careful since the user might be asking # for rounding at the last digit and our semantics # are to round toward the even final digit when there # is a tie. So the extra digit will be used to make # that decision. In this case, the value is the same # to 15 digits: # >>> Float(.575).n(16) # 0.5750000000000000 # Now converting this to the 15 known digits gives # 575000000000000.0 # which rounds to integer # 5750000000000000 # And now we can round to the desired digt, e.g. at # the second from the left and we get # 5800000000000000 # and rescaling that gives # 0.58 # as the final result. # If the value is made slightly less than 0.575 we might # still obtain the same value: # >>> Float(.575-1e-16).n(16)*10**15 # 574999999999999.8 # What 15 digits best represents the known digits (which are # to the left of the decimal? 5750000000000000, the same as # before. The only way we will round down (in this case) is # if we declared that we had more than 15 digits of precision. # For example, if we use 16 digits of precision, the integer # we deal with is # >>> Float(.575-1e-16).n(17)*10**16 # 5749999999999998.4 # and this now rounds to 5749999999999998 and (if we round to # the 2nd digit from the left) we get 5700000000000000. # xf = x.n(dps + extra)*Pow(10, shift) xi = Integer(xf) # use the last digit to select the value of xi # nearest to x before rounding at the desired digit sign = 1 if x > 0 else -1 dif2 = sign*(xf - xi).n(extra) if dif2 < 0: raise NotImplementedError( 'not expecting int(x) to round away from 0') if dif2 > .5: xi += sign # round away from 0 elif dif2 == .5: xi += sign if xi%2 else -sign # round toward even # shift p to the new position ip = p - shift # let Python handle the int rounding then rescale xr = round(xi.p, ip) # restore scale rv = Rational(xr, Pow(10, shift)) # return Float or Integer if rv.is_Integer: if n is None: # the single-arg case return rv # use str or else it won't be a float return Float(str(rv), dps) # keep same precision else: if not allow and rv > self: allow += 1 return Float(rv, allow) __round__ = round def _eval_derivative_matrix_lines(self, x): from sympy.matrices.expressions.matexpr import _LeftRightArgs return [_LeftRightArgs([S.One, S.One], higher=self._eval_derivative(x))] class AtomicExpr(Atom, Expr): """ A parent class for object which are both atoms and Exprs. For example: Symbol, Number, Rational, Integer, ... But not: Add, Mul, Pow, ... """ is_number = False is_Atom = True __slots__ = () def _eval_derivative(self, s): if self == s: return S.One return S.Zero def _eval_derivative_n_times(self, s, n): from sympy import Piecewise, Eq from sympy import Tuple, MatrixExpr from sympy.matrices.common import MatrixCommon if isinstance(s, (MatrixCommon, Tuple, Iterable, MatrixExpr)): return super()._eval_derivative_n_times(s, n) if self == s: return Piecewise((self, Eq(n, 0)), (1, Eq(n, 1)), (0, True)) else: return Piecewise((self, Eq(n, 0)), (0, True)) def _eval_is_polynomial(self, syms): return True def _eval_is_rational_function(self, syms): return True def _eval_is_meromorphic(self, x, a): from sympy.calculus.util import AccumBounds return (not self.is_Number or self.is_finite) and not isinstance(self, AccumBounds) def _eval_is_algebraic_expr(self, syms): return True def _eval_nseries(self, x, n, logx, cdir=0): return self @property def expr_free_symbols(self): from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning(feature="expr_free_symbols method", issue=21494, deprecated_since_version="1.9").warn() return {self} def _mag(x): """Return integer ``i`` such that .1 <= x/10**i < 1 Examples ======== >>> from sympy.core.expr import _mag >>> from sympy import Float >>> _mag(Float(.1)) 0 >>> _mag(Float(.01)) -1 >>> _mag(Float(1234)) 4 """ from math import log10, ceil, log from sympy import Float xpos = abs(x.n()) if not xpos: return S.Zero try: mag_first_dig = int(ceil(log10(xpos))) except (ValueError, OverflowError): mag_first_dig = int(ceil(Float(mpf_log(xpos._mpf_, 53))/log(10))) # check that we aren't off by 1 if (xpos/10**mag_first_dig) >= 1: assert 1 <= (xpos/10**mag_first_dig) < 10 mag_first_dig += 1 return mag_first_dig class UnevaluatedExpr(Expr): """ Expression that is not evaluated unless released. Examples ======== >>> from sympy import UnevaluatedExpr >>> from sympy.abc import x >>> x*(1/x) 1 >>> x*UnevaluatedExpr(1/x) x*1/x """ def __new__(cls, arg, **kwargs): arg = _sympify(arg) obj = Expr.__new__(cls, arg, **kwargs) return obj def doit(self, **kwargs): if kwargs.get("deep", True): return self.args[0].doit(**kwargs) else: return self.args[0] def unchanged(func, *args): """Return True if `func` applied to the `args` is unchanged. Can be used instead of `assert foo == foo`. Examples ======== >>> from sympy import Piecewise, cos, pi >>> from sympy.core.expr import unchanged >>> from sympy.abc import x >>> unchanged(cos, 1) # instead of assert cos(1) == cos(1) True >>> unchanged(cos, pi) False Comparison of args uses the builtin capabilities of the object's arguments to test for equality so args can be defined loosely. Here, the ExprCondPair arguments of Piecewise compare as equal to the tuples that can be used to create the Piecewise: >>> unchanged(Piecewise, (x, x > 1), (0, True)) True """ f = func(*args) return f.func == func and f.args == args class ExprBuilder: def __init__(self, op, args=[], validator=None, check=True): if not hasattr(op, "__call__"): raise TypeError("op {} needs to be callable".format(op)) self.op = op self.args = args self.validator = validator if (validator is not None) and check: self.validate() @staticmethod def _build_args(args): return [i.build() if isinstance(i, ExprBuilder) else i for i in args] def validate(self): if self.validator is None: return args = self._build_args(self.args) self.validator(*args) def build(self, check=True): args = self._build_args(self.args) if self.validator and check: self.validator(*args) return self.op(*args) def append_argument(self, arg, check=True): self.args.append(arg) if self.validator and check: self.validate(*self.args) def __getitem__(self, item): if item == 0: return self.op else: return self.args[item-1] def __repr__(self): return str(self.build()) def search_element(self, elem): for i, arg in enumerate(self.args): if isinstance(arg, ExprBuilder): ret = arg.search_index(elem) if ret is not None: return (i,) + ret elif id(arg) == id(elem): return (i,) return None from .mul import Mul from .add import Add from .power import Pow from .function import Function, _derivative_dispatch from .mod import Mod from .exprtools import factor_terms from .numbers import Integer, Rational sympy-sympy-1.9/sympy/core/exprtools.py000066400000000000000000001440711412543434000204540ustar00rootroot00000000000000"""Tools for manipulating of large commutative expressions. """ from sympy.core.add import Add from sympy.core.compatibility import iterable, is_sequence, SYMPY_INTS from sympy.core.mul import Mul, _keep_coeff from sympy.core.power import Pow from sympy.core.basic import Basic, preorder_traversal from sympy.core.expr import Expr from sympy.core.sympify import sympify from sympy.core.numbers import Rational, Integer, Number, I from sympy.core.singleton import S from sympy.core.symbol import Dummy from sympy.core.coreerrors import NonCommutativeExpression from sympy.core.containers import Tuple, Dict from sympy.utilities import default_sort_key from sympy.utilities.iterables import (common_prefix, common_suffix, variations, ordered) from collections import defaultdict _eps = Dummy(positive=True) def _isnumber(i): return isinstance(i, (SYMPY_INTS, float)) or i.is_Number def _monotonic_sign(self): """Return the value closest to 0 that ``self`` may have if all symbols are signed and the result is uniformly the same sign for all values of symbols. If a symbol is only signed but not known to be an integer or the result is 0 then a symbol representative of the sign of self will be returned. Otherwise, None is returned if a) the sign could be positive or negative or b) self is not in one of the following forms: - L(x, y, ...) + A: a function linear in all symbols x, y, ... with an additive constant; if A is zero then the function can be a monomial whose sign is monotonic over the range of the variables, e.g. (x + 1)**3 if x is nonnegative. - A/L(x, y, ...) + B: the inverse of a function linear in all symbols x, y, ... that does not have a sign change from positive to negative for any set of values for the variables. - M(x, y, ...) + A: a monomial M whose factors are all signed and a constant, A. - A/M(x, y, ...) + B: the inverse of a monomial and constants A and B. - P(x): a univariate polynomial Examples ======== >>> from sympy.core.exprtools import _monotonic_sign as F >>> from sympy import Dummy >>> nn = Dummy(integer=True, nonnegative=True) >>> p = Dummy(integer=True, positive=True) >>> p2 = Dummy(integer=True, positive=True) >>> F(nn + 1) 1 >>> F(p - 1) _nneg >>> F(nn*p + 1) 1 >>> F(p2*p + 1) 2 >>> F(nn - 1) # could be negative, zero or positive """ if not self.is_extended_real: return if (-self).is_Symbol: rv = _monotonic_sign(-self) return rv if rv is None else -rv if not self.is_Add and self.as_numer_denom()[1].is_number: s = self if s.is_prime: if s.is_odd: return S(3) else: return S(2) elif s.is_composite: if s.is_odd: return S(9) else: return S(4) elif s.is_positive: if s.is_even: if s.is_prime is False: return S(4) else: return S(2) elif s.is_integer: return S.One else: return _eps elif s.is_extended_negative: if s.is_even: return S(-2) elif s.is_integer: return S.NegativeOne else: return -_eps if s.is_zero or s.is_extended_nonpositive or s.is_extended_nonnegative: return S.Zero return None # univariate polynomial free = self.free_symbols if len(free) == 1: if self.is_polynomial(): from sympy.polys.polytools import real_roots from sympy.polys.polyroots import roots from sympy.polys.polyerrors import PolynomialError x = free.pop() x0 = _monotonic_sign(x) if x0 == _eps or x0 == -_eps: x0 = S.Zero if x0 is not None: d = self.diff(x) if d.is_number: currentroots = [] else: try: currentroots = real_roots(d) except (PolynomialError, NotImplementedError): currentroots = [r for r in roots(d, x) if r.is_extended_real] y = self.subs(x, x0) if x.is_nonnegative and all(r <= x0 for r in currentroots): if y.is_nonnegative and d.is_positive: if y: return y if y.is_positive else Dummy('pos', positive=True) else: return Dummy('nneg', nonnegative=True) if y.is_nonpositive and d.is_negative: if y: return y if y.is_negative else Dummy('neg', negative=True) else: return Dummy('npos', nonpositive=True) elif x.is_nonpositive and all(r >= x0 for r in currentroots): if y.is_nonnegative and d.is_negative: if y: return Dummy('pos', positive=True) else: return Dummy('nneg', nonnegative=True) if y.is_nonpositive and d.is_positive: if y: return Dummy('neg', negative=True) else: return Dummy('npos', nonpositive=True) else: n, d = self.as_numer_denom() den = None if n.is_number: den = _monotonic_sign(d) elif not d.is_number: if _monotonic_sign(n) is not None: den = _monotonic_sign(d) if den is not None and (den.is_positive or den.is_negative): v = n*den if v.is_positive: return Dummy('pos', positive=True) elif v.is_nonnegative: return Dummy('nneg', nonnegative=True) elif v.is_negative: return Dummy('neg', negative=True) elif v.is_nonpositive: return Dummy('npos', nonpositive=True) return None # multivariate c, a = self.as_coeff_Add() v = None if not a.is_polynomial(): # F/A or A/F where A is a number and F is a signed, rational monomial n, d = a.as_numer_denom() if not (n.is_number or d.is_number): return if ( a.is_Mul or a.is_Pow) and \ a.is_rational and \ all(p.exp.is_Integer for p in a.atoms(Pow) if p.is_Pow) and \ (a.is_positive or a.is_negative): v = S.One for ai in Mul.make_args(a): if ai.is_number: v *= ai continue reps = {} for x in ai.free_symbols: reps[x] = _monotonic_sign(x) if reps[x] is None: return v *= ai.subs(reps) elif c: # signed linear expression if not any(p for p in a.atoms(Pow) if not p.is_number) and (a.is_nonpositive or a.is_nonnegative): free = list(a.free_symbols) p = {} for i in free: v = _monotonic_sign(i) if v is None: return p[i] = v or (_eps if i.is_nonnegative else -_eps) v = a.xreplace(p) if v is not None: rv = v + c if v.is_nonnegative and rv.is_positive: return rv.subs(_eps, 0) if v.is_nonpositive and rv.is_negative: return rv.subs(_eps, 0) def decompose_power(expr): """ Decompose power into symbolic base and integer exponent. Explanation =========== This is strictly only valid if the exponent from which the integer is extracted is itself an integer or the base is positive. These conditions are assumed and not checked here. Examples ======== >>> from sympy.core.exprtools import decompose_power >>> from sympy.abc import x, y >>> decompose_power(x) (x, 1) >>> decompose_power(x**2) (x, 2) >>> decompose_power(x**(2*y)) (x**y, 2) >>> decompose_power(x**(2*y/3)) (x**(y/3), 2) """ base, exp = expr.as_base_exp() if exp.is_Number: if exp.is_Rational: if not exp.is_Integer: base = Pow(base, Rational(1, exp.q)) exp = exp.p else: base, exp = expr, 1 else: exp, tail = exp.as_coeff_Mul(rational=True) if exp is S.NegativeOne: base, exp = Pow(base, tail), -1 elif exp is not S.One: tail = _keep_coeff(Rational(1, exp.q), tail) base, exp = Pow(base, tail), exp.p else: base, exp = expr, 1 return base, exp def decompose_power_rat(expr): """ Decompose power into symbolic base and rational exponent. """ base, exp = expr.as_base_exp() if exp.is_Number: if not exp.is_Rational: base, exp = expr, 1 else: exp, tail = exp.as_coeff_Mul(rational=True) if exp is S.NegativeOne: base, exp = Pow(base, tail), -1 elif exp is not S.One: tail = _keep_coeff(Rational(1, exp.q), tail) base, exp = Pow(base, tail), exp.p else: base, exp = expr, 1 return base, exp class Factors: """Efficient representation of ``f_1*f_2*...*f_n``.""" __slots__ = ('factors', 'gens') def __init__(self, factors=None): # Factors """Initialize Factors from dict or expr. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x >>> from sympy import I >>> e = 2*x**3 >>> Factors(e) Factors({2: 1, x: 3}) >>> Factors(e.as_powers_dict()) Factors({2: 1, x: 3}) >>> f = _ >>> f.factors # underlying dictionary {2: 1, x: 3} >>> f.gens # base of each factor frozenset({2, x}) >>> Factors(0) Factors({0: 1}) >>> Factors(I) Factors({I: 1}) Notes ===== Although a dictionary can be passed, only minimal checking is performed: powers of -1 and I are made canonical. """ if isinstance(factors, (SYMPY_INTS, float)): factors = S(factors) if isinstance(factors, Factors): factors = factors.factors.copy() elif factors is None or factors is S.One: factors = {} elif factors is S.Zero or factors == 0: factors = {S.Zero: S.One} elif isinstance(factors, Number): n = factors factors = {} if n < 0: factors[S.NegativeOne] = S.One n = -n if n is not S.One: if n.is_Float or n.is_Integer or n is S.Infinity: factors[n] = S.One elif n.is_Rational: # since we're processing Numbers, the denominator is # stored with a negative exponent; all other factors # are left . if n.p != 1: factors[Integer(n.p)] = S.One factors[Integer(n.q)] = S.NegativeOne else: raise ValueError('Expected Float|Rational|Integer, not %s' % n) elif isinstance(factors, Basic) and not factors.args: factors = {factors: S.One} elif isinstance(factors, Expr): c, nc = factors.args_cnc() i = c.count(I) for _ in range(i): c.remove(I) factors = dict(Mul._from_args(c).as_powers_dict()) # Handle all rational Coefficients for f in list(factors.keys()): if isinstance(f, Rational) and not isinstance(f, Integer): p, q = Integer(f.p), Integer(f.q) factors[p] = (factors[p] if p in factors else S.Zero) + factors[f] factors[q] = (factors[q] if q in factors else S.Zero) - factors[f] factors.pop(f) if i: factors[I] = factors.get(I, S.Zero) + i if nc: factors[Mul(*nc, evaluate=False)] = S.One else: factors = factors.copy() # /!\ should be dict-like # tidy up -/+1 and I exponents if Rational handle = [] for k in factors: if k is I or k in (-1, 1): handle.append(k) if handle: i1 = S.One for k in handle: if not _isnumber(factors[k]): continue i1 *= k**factors.pop(k) if i1 is not S.One: for a in i1.args if i1.is_Mul else [i1]: # at worst, -1.0*I*(-1)**e if a is S.NegativeOne: factors[a] = S.One elif a is I: factors[I] = S.One elif a.is_Pow: factors[a.base] = factors.get(a.base, S.Zero) + a.exp elif a == 1: factors[a] = S.One elif a == -1: factors[-a] = S.One factors[S.NegativeOne] = S.One else: raise ValueError('unexpected factor in i1: %s' % a) self.factors = factors keys = getattr(factors, 'keys', None) if keys is None: raise TypeError('expecting Expr or dictionary') self.gens = frozenset(keys()) def __hash__(self): # Factors keys = tuple(ordered(self.factors.keys())) values = [self.factors[k] for k in keys] return hash((keys, values)) def __repr__(self): # Factors return "Factors({%s})" % ', '.join( ['%s: %s' % (k, v) for k, v in ordered(self.factors.items())]) @property def is_zero(self): # Factors """ >>> from sympy.core.exprtools import Factors >>> Factors(0).is_zero True """ f = self.factors return len(f) == 1 and S.Zero in f @property def is_one(self): # Factors """ >>> from sympy.core.exprtools import Factors >>> Factors(1).is_one True """ return not self.factors def as_expr(self): # Factors """Return the underlying expression. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y >>> Factors((x*y**2).as_powers_dict()).as_expr() x*y**2 """ args = [] for factor, exp in self.factors.items(): if exp != 1: if isinstance(exp, Integer): b, e = factor.as_base_exp() e = _keep_coeff(exp, e) args.append(b**e) else: args.append(factor**exp) else: args.append(factor) return Mul(*args) def mul(self, other): # Factors """Return Factors of ``self * other``. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y, z >>> a = Factors((x*y**2).as_powers_dict()) >>> b = Factors((x*y/z).as_powers_dict()) >>> a.mul(b) Factors({x: 2, y: 3, z: -1}) >>> a*b Factors({x: 2, y: 3, z: -1}) """ if not isinstance(other, Factors): other = Factors(other) if any(f.is_zero for f in (self, other)): return Factors(S.Zero) factors = dict(self.factors) for factor, exp in other.factors.items(): if factor in factors: exp = factors[factor] + exp if not exp: del factors[factor] continue factors[factor] = exp return Factors(factors) def normal(self, other): """Return ``self`` and ``other`` with ``gcd`` removed from each. The only differences between this and method ``div`` is that this is 1) optimized for the case when there are few factors in common and 2) this does not raise an error if ``other`` is zero. See Also ======== div """ if not isinstance(other, Factors): other = Factors(other) if other.is_zero: return (Factors(), Factors(S.Zero)) if self.is_zero: return (Factors(S.Zero), Factors()) self_factors = dict(self.factors) other_factors = dict(other.factors) for factor, self_exp in self.factors.items(): try: other_exp = other.factors[factor] except KeyError: continue exp = self_exp - other_exp if not exp: del self_factors[factor] del other_factors[factor] elif _isnumber(exp): if exp > 0: self_factors[factor] = exp del other_factors[factor] else: del self_factors[factor] other_factors[factor] = -exp else: r = self_exp.extract_additively(other_exp) if r is not None: if r: self_factors[factor] = r del other_factors[factor] else: # should be handled already del self_factors[factor] del other_factors[factor] else: sc, sa = self_exp.as_coeff_Add() if sc: oc, oa = other_exp.as_coeff_Add() diff = sc - oc if diff > 0: self_factors[factor] -= oc other_exp = oa elif diff < 0: self_factors[factor] -= sc other_factors[factor] -= sc other_exp = oa - diff else: self_factors[factor] = sa other_exp = oa if other_exp: other_factors[factor] = other_exp else: del other_factors[factor] return Factors(self_factors), Factors(other_factors) def div(self, other): # Factors """Return ``self`` and ``other`` with ``gcd`` removed from each. This is optimized for the case when there are many factors in common. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y, z >>> from sympy import S >>> a = Factors((x*y**2).as_powers_dict()) >>> a.div(a) (Factors({}), Factors({})) >>> a.div(x*z) (Factors({y: 2}), Factors({z: 1})) The ``/`` operator only gives ``quo``: >>> a/x Factors({y: 2}) Factors treats its factors as though they are all in the numerator, so if you violate this assumption the results will be correct but will not strictly correspond to the numerator and denominator of the ratio: >>> a.div(x/z) (Factors({y: 2}), Factors({z: -1})) Factors is also naive about bases: it does not attempt any denesting of Rational-base terms, for example the following does not become 2**(2*x)/2. >>> Factors(2**(2*x + 2)).div(S(8)) (Factors({2: 2*x + 2}), Factors({8: 1})) factor_terms can clean up such Rational-bases powers: >>> from sympy.core.exprtools import factor_terms >>> n, d = Factors(2**(2*x + 2)).div(S(8)) >>> n.as_expr()/d.as_expr() 2**(2*x + 2)/8 >>> factor_terms(_) 2**(2*x)/2 """ quo, rem = dict(self.factors), {} if not isinstance(other, Factors): other = Factors(other) if other.is_zero: raise ZeroDivisionError if self.is_zero: return (Factors(S.Zero), Factors()) for factor, exp in other.factors.items(): if factor in quo: d = quo[factor] - exp if _isnumber(d): if d <= 0: del quo[factor] if d >= 0: if d: quo[factor] = d continue exp = -d else: r = quo[factor].extract_additively(exp) if r is not None: if r: quo[factor] = r else: # should be handled already del quo[factor] else: other_exp = exp sc, sa = quo[factor].as_coeff_Add() if sc: oc, oa = other_exp.as_coeff_Add() diff = sc - oc if diff > 0: quo[factor] -= oc other_exp = oa elif diff < 0: quo[factor] -= sc other_exp = oa - diff else: quo[factor] = sa other_exp = oa if other_exp: rem[factor] = other_exp else: assert factor not in rem continue rem[factor] = exp return Factors(quo), Factors(rem) def quo(self, other): # Factors """Return numerator Factor of ``self / other``. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y, z >>> a = Factors((x*y**2).as_powers_dict()) >>> b = Factors((x*y/z).as_powers_dict()) >>> a.quo(b) # same as a/b Factors({y: 1}) """ return self.div(other)[0] def rem(self, other): # Factors """Return denominator Factors of ``self / other``. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y, z >>> a = Factors((x*y**2).as_powers_dict()) >>> b = Factors((x*y/z).as_powers_dict()) >>> a.rem(b) Factors({z: -1}) >>> a.rem(a) Factors({}) """ return self.div(other)[1] def pow(self, other): # Factors """Return self raised to a non-negative integer power. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y >>> a = Factors((x*y**2).as_powers_dict()) >>> a**2 Factors({x: 2, y: 4}) """ if isinstance(other, Factors): other = other.as_expr() if other.is_Integer: other = int(other) if isinstance(other, SYMPY_INTS) and other >= 0: factors = {} if other: for factor, exp in self.factors.items(): factors[factor] = exp*other return Factors(factors) else: raise ValueError("expected non-negative integer, got %s" % other) def gcd(self, other): # Factors """Return Factors of ``gcd(self, other)``. The keys are the intersection of factors with the minimum exponent for each factor. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y, z >>> a = Factors((x*y**2).as_powers_dict()) >>> b = Factors((x*y/z).as_powers_dict()) >>> a.gcd(b) Factors({x: 1, y: 1}) """ if not isinstance(other, Factors): other = Factors(other) if other.is_zero: return Factors(self.factors) factors = {} for factor, exp in self.factors.items(): factor, exp = sympify(factor), sympify(exp) if factor in other.factors: lt = (exp - other.factors[factor]).is_negative if lt == True: factors[factor] = exp elif lt == False: factors[factor] = other.factors[factor] return Factors(factors) def lcm(self, other): # Factors """Return Factors of ``lcm(self, other)`` which are the union of factors with the maximum exponent for each factor. Examples ======== >>> from sympy.core.exprtools import Factors >>> from sympy.abc import x, y, z >>> a = Factors((x*y**2).as_powers_dict()) >>> b = Factors((x*y/z).as_powers_dict()) >>> a.lcm(b) Factors({x: 1, y: 2, z: -1}) """ if not isinstance(other, Factors): other = Factors(other) if any(f.is_zero for f in (self, other)): return Factors(S.Zero) factors = dict(self.factors) for factor, exp in other.factors.items(): if factor in factors: exp = max(exp, factors[factor]) factors[factor] = exp return Factors(factors) def __mul__(self, other): # Factors return self.mul(other) def __divmod__(self, other): # Factors return self.div(other) def __truediv__(self, other): # Factors return self.quo(other) def __mod__(self, other): # Factors return self.rem(other) def __pow__(self, other): # Factors return self.pow(other) def __eq__(self, other): # Factors if not isinstance(other, Factors): other = Factors(other) return self.factors == other.factors def __ne__(self, other): # Factors return not self == other class Term: """Efficient representation of ``coeff*(numer/denom)``. """ __slots__ = ('coeff', 'numer', 'denom') def __init__(self, term, numer=None, denom=None): # Term if numer is None and denom is None: if not term.is_commutative: raise NonCommutativeExpression( 'commutative expression expected') coeff, factors = term.as_coeff_mul() numer, denom = defaultdict(int), defaultdict(int) for factor in factors: base, exp = decompose_power(factor) if base.is_Add: cont, base = base.primitive() coeff *= cont**exp if exp > 0: numer[base] += exp else: denom[base] += -exp numer = Factors(numer) denom = Factors(denom) else: coeff = term if numer is None: numer = Factors() if denom is None: denom = Factors() self.coeff = coeff self.numer = numer self.denom = denom def __hash__(self): # Term return hash((self.coeff, self.numer, self.denom)) def __repr__(self): # Term return "Term(%s, %s, %s)" % (self.coeff, self.numer, self.denom) def as_expr(self): # Term return self.coeff*(self.numer.as_expr()/self.denom.as_expr()) def mul(self, other): # Term coeff = self.coeff*other.coeff numer = self.numer.mul(other.numer) denom = self.denom.mul(other.denom) numer, denom = numer.normal(denom) return Term(coeff, numer, denom) def inv(self): # Term return Term(1/self.coeff, self.denom, self.numer) def quo(self, other): # Term return self.mul(other.inv()) def pow(self, other): # Term if other < 0: return self.inv().pow(-other) else: return Term(self.coeff ** other, self.numer.pow(other), self.denom.pow(other)) def gcd(self, other): # Term return Term(self.coeff.gcd(other.coeff), self.numer.gcd(other.numer), self.denom.gcd(other.denom)) def lcm(self, other): # Term return Term(self.coeff.lcm(other.coeff), self.numer.lcm(other.numer), self.denom.lcm(other.denom)) def __mul__(self, other): # Term if isinstance(other, Term): return self.mul(other) else: return NotImplemented def __truediv__(self, other): # Term if isinstance(other, Term): return self.quo(other) else: return NotImplemented def __pow__(self, other): # Term if isinstance(other, SYMPY_INTS): return self.pow(other) else: return NotImplemented def __eq__(self, other): # Term return (self.coeff == other.coeff and self.numer == other.numer and self.denom == other.denom) def __ne__(self, other): # Term return not self == other def _gcd_terms(terms, isprimitive=False, fraction=True): """Helper function for :func:`gcd_terms`. Parameters ========== isprimitive : boolean, optional If ``isprimitive`` is True then the call to primitive for an Add will be skipped. This is useful when the content has already been extrated. fraction : boolean, optional If ``fraction`` is True then the expression will appear over a common denominator, the lcm of all term denominators. """ if isinstance(terms, Basic) and not isinstance(terms, Tuple): terms = Add.make_args(terms) terms = list(map(Term, [t for t in terms if t])) # there is some simplification that may happen if we leave this # here rather than duplicate it before the mapping of Term onto # the terms if len(terms) == 0: return S.Zero, S.Zero, S.One if len(terms) == 1: cont = terms[0].coeff numer = terms[0].numer.as_expr() denom = terms[0].denom.as_expr() else: cont = terms[0] for term in terms[1:]: cont = cont.gcd(term) for i, term in enumerate(terms): terms[i] = term.quo(cont) if fraction: denom = terms[0].denom for term in terms[1:]: denom = denom.lcm(term.denom) numers = [] for term in terms: numer = term.numer.mul(denom.quo(term.denom)) numers.append(term.coeff*numer.as_expr()) else: numers = [t.as_expr() for t in terms] denom = Term(S.One).numer cont = cont.as_expr() numer = Add(*numers) denom = denom.as_expr() if not isprimitive and numer.is_Add: _cont, numer = numer.primitive() cont *= _cont return cont, numer, denom def gcd_terms(terms, isprimitive=False, clear=True, fraction=True): """Compute the GCD of ``terms`` and put them together. Parameters ========== terms : Expr Can be an expression or a non-Basic sequence of expressions which will be handled as though they are terms from a sum. isprimitive : bool, optional If ``isprimitive`` is True the _gcd_terms will not run the primitive method on the terms. clear : bool, optional It controls the removal of integers from the denominator of an Add expression. When True (default), all numerical denominator will be cleared; when False the denominators will be cleared only if all terms had numerical denominators other than 1. fraction : bool, optional When True (default), will put the expression over a common denominator. Examples ======== >>> from sympy.core import gcd_terms >>> from sympy.abc import x, y >>> gcd_terms((x + 1)**2*y + (x + 1)*y**2) y*(x + 1)*(x + y + 1) >>> gcd_terms(x/2 + 1) (x + 2)/2 >>> gcd_terms(x/2 + 1, clear=False) x/2 + 1 >>> gcd_terms(x/2 + y/2, clear=False) (x + y)/2 >>> gcd_terms(x/2 + 1/x) (x**2 + 2)/(2*x) >>> gcd_terms(x/2 + 1/x, fraction=False) (x + 2/x)/2 >>> gcd_terms(x/2 + 1/x, fraction=False, clear=False) x/2 + 1/x >>> gcd_terms(x/2/y + 1/x/y) (x**2 + 2)/(2*x*y) >>> gcd_terms(x/2/y + 1/x/y, clear=False) (x**2/2 + 1)/(x*y) >>> gcd_terms(x/2/y + 1/x/y, clear=False, fraction=False) (x/2 + 1/x)/y The ``clear`` flag was ignored in this case because the returned expression was a rational expression, not a simple sum. See Also ======== factor_terms, sympy.polys.polytools.terms_gcd """ def mask(terms): """replace nc portions of each term with a unique Dummy symbols and return the replacements to restore them""" args = [(a, []) if a.is_commutative else a.args_cnc() for a in terms] reps = [] for i, (c, nc) in enumerate(args): if nc: nc = Mul(*nc) d = Dummy() reps.append((d, nc)) c.append(d) args[i] = Mul(*c) else: args[i] = c return args, dict(reps) isadd = isinstance(terms, Add) addlike = isadd or not isinstance(terms, Basic) and \ is_sequence(terms, include=set) and \ not isinstance(terms, Dict) if addlike: if isadd: # i.e. an Add terms = list(terms.args) else: terms = sympify(terms) terms, reps = mask(terms) cont, numer, denom = _gcd_terms(terms, isprimitive, fraction) numer = numer.xreplace(reps) coeff, factors = cont.as_coeff_Mul() if not clear: c, _coeff = coeff.as_coeff_Mul() if not c.is_Integer and not clear and numer.is_Add: n, d = c.as_numer_denom() _numer = numer/d if any(a.as_coeff_Mul()[0].is_Integer for a in _numer.args): numer = _numer coeff = n*_coeff return _keep_coeff(coeff, factors*numer/denom, clear=clear) if not isinstance(terms, Basic): return terms if terms.is_Atom: return terms if terms.is_Mul: c, args = terms.as_coeff_mul() return _keep_coeff(c, Mul(*[gcd_terms(i, isprimitive, clear, fraction) for i in args]), clear=clear) def handle(a): # don't treat internal args like terms of an Add if not isinstance(a, Expr): if isinstance(a, Basic): if not a.args: return a return a.func(*[handle(i) for i in a.args]) return type(a)([handle(i) for i in a]) return gcd_terms(a, isprimitive, clear, fraction) if isinstance(terms, Dict): return Dict(*[(k, handle(v)) for k, v in terms.args]) return terms.func(*[handle(i) for i in terms.args]) def _factor_sum_int(expr, **kwargs): """Return Sum or Integral object with factors that are not in the wrt variables removed. In cases where there are additive terms in the function of the object that are independent, the object will be separated into two objects. Examples ======== >>> from sympy import Sum, factor_terms >>> from sympy.abc import x, y >>> factor_terms(Sum(x + y, (x, 1, 3))) y*Sum(1, (x, 1, 3)) + Sum(x, (x, 1, 3)) >>> factor_terms(Sum(x*y, (x, 1, 3))) y*Sum(x, (x, 1, 3)) Notes ===== If a function in the summand or integrand is replaced with a symbol, then this simplification should not be done or else an incorrect result will be obtained when the symbol is replaced with an expression that depends on the variables of summation/integration: >>> eq = Sum(y, (x, 1, 3)) >>> factor_terms(eq).subs(y, x).doit() 3*x >>> eq.subs(y, x).doit() 6 """ result = expr.function if result == 0: return S.Zero limits = expr.limits # get the wrt variables wrt = {i.args[0] for i in limits} # factor out any common terms that are independent of wrt f = factor_terms(result, **kwargs) i, d = f.as_independent(*wrt) if isinstance(f, Add): return i * expr.func(1, *limits) + expr.func(d, *limits) else: return i * expr.func(d, *limits) def factor_terms(expr, radical=False, clear=False, fraction=False, sign=True): """Remove common factors from terms in all arguments without changing the underlying structure of the expr. No expansion or simplification (and no processing of non-commutatives) is performed. Parameters ========== radical: bool, optional If radical=True then a radical common to all terms will be factored out of any Add sub-expressions of the expr. clear : bool, optional If clear=False (default) then coefficients will not be separated from a single Add if they can be distributed to leave one or more terms with integer coefficients. fraction : bool, optional If fraction=True (default is False) then a common denominator will be constructed for the expression. sign : bool, optional If sign=True (default) then even if the only factor in common is a -1, it will be factored out of the expression. Examples ======== >>> from sympy import factor_terms, Symbol >>> from sympy.abc import x, y >>> factor_terms(x + x*(2 + 4*y)**3) x*(8*(2*y + 1)**3 + 1) >>> A = Symbol('A', commutative=False) >>> factor_terms(x*A + x*A + x*y*A) x*(y*A + 2*A) When ``clear`` is False, a rational will only be factored out of an Add expression if all terms of the Add have coefficients that are fractions: >>> factor_terms(x/2 + 1, clear=False) x/2 + 1 >>> factor_terms(x/2 + 1, clear=True) (x + 2)/2 If a -1 is all that can be factored out, to *not* factor it out, the flag ``sign`` must be False: >>> factor_terms(-x - y) -(x + y) >>> factor_terms(-x - y, sign=False) -x - y >>> factor_terms(-2*x - 2*y, sign=False) -2*(x + y) See Also ======== gcd_terms, sympy.polys.polytools.terms_gcd """ def do(expr): from sympy.concrete.summations import Sum from sympy.integrals.integrals import Integral is_iterable = iterable(expr) if not isinstance(expr, Basic) or expr.is_Atom: if is_iterable: return type(expr)([do(i) for i in expr]) return expr if expr.is_Pow or expr.is_Function or \ is_iterable or not hasattr(expr, 'args_cnc'): args = expr.args newargs = tuple([do(i) for i in args]) if newargs == args: return expr return expr.func(*newargs) if isinstance(expr, (Sum, Integral)): return _factor_sum_int(expr, radical=radical, clear=clear, fraction=fraction, sign=sign) cont, p = expr.as_content_primitive(radical=radical, clear=clear) if p.is_Add: list_args = [do(a) for a in Add.make_args(p)] # get a common negative (if there) which gcd_terms does not remove if all(a.as_coeff_Mul()[0].extract_multiplicatively(-1) is not None for a in list_args): cont = -cont list_args = [-a for a in list_args] # watch out for exp(-(x+2)) which gcd_terms will change to exp(-x-2) special = {} for i, a in enumerate(list_args): b, e = a.as_base_exp() if e.is_Mul and e != Mul(*e.args): list_args[i] = Dummy() special[list_args[i]] = a # rebuild p not worrying about the order which gcd_terms will fix p = Add._from_args(list_args) p = gcd_terms(p, isprimitive=True, clear=clear, fraction=fraction).xreplace(special) elif p.args: p = p.func( *[do(a) for a in p.args]) rv = _keep_coeff(cont, p, clear=clear, sign=sign) return rv expr = sympify(expr) return do(expr) def _mask_nc(eq, name=None): """ Return ``eq`` with non-commutative objects replaced with Dummy symbols. A dictionary that can be used to restore the original values is returned: if it is None, the expression is noncommutative and cannot be made commutative. The third value returned is a list of any non-commutative symbols that appear in the returned equation. Explanation =========== All non-commutative objects other than Symbols are replaced with a non-commutative Symbol. Identical objects will be identified by identical symbols. If there is only 1 non-commutative object in an expression it will be replaced with a commutative symbol. Otherwise, the non-commutative entities are retained and the calling routine should handle replacements in this case since some care must be taken to keep track of the ordering of symbols when they occur within Muls. Parameters ========== name : str ``name``, if given, is the name that will be used with numbered Dummy variables that will replace the non-commutative objects and is mainly used for doctesting purposes. Examples ======== >>> from sympy.physics.secondquant import Commutator, NO, F, Fd >>> from sympy import symbols >>> from sympy.core.exprtools import _mask_nc >>> from sympy.abc import x, y >>> A, B, C = symbols('A,B,C', commutative=False) One nc-symbol: >>> _mask_nc(A**2 - x**2, 'd') (_d0**2 - x**2, {_d0: A}, []) Multiple nc-symbols: >>> _mask_nc(A**2 - B**2, 'd') (A**2 - B**2, {}, [A, B]) An nc-object with nc-symbols but no others outside of it: >>> _mask_nc(1 + x*Commutator(A, B), 'd') (_d0*x + 1, {_d0: Commutator(A, B)}, []) >>> _mask_nc(NO(Fd(x)*F(y)), 'd') (_d0, {_d0: NO(CreateFermion(x)*AnnihilateFermion(y))}, []) Multiple nc-objects: >>> eq = x*Commutator(A, B) + x*Commutator(A, C)*Commutator(A, B) >>> _mask_nc(eq, 'd') (x*_d0 + x*_d1*_d0, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1]) Multiple nc-objects and nc-symbols: >>> eq = A*Commutator(A, B) + B*Commutator(A, C) >>> _mask_nc(eq, 'd') (A*_d0 + B*_d1, {_d0: Commutator(A, B), _d1: Commutator(A, C)}, [_d0, _d1, A, B]) """ name = name or 'mask' # Make Dummy() append sequential numbers to the name def numbered_names(): i = 0 while True: yield name + str(i) i += 1 names = numbered_names() def Dummy(*args, **kwargs): from sympy import Dummy return Dummy(next(names), *args, **kwargs) expr = eq if expr.is_commutative: return eq, {}, [] # identify nc-objects; symbols and other rep = [] nc_obj = set() nc_syms = set() pot = preorder_traversal(expr, keys=default_sort_key) for i, a in enumerate(pot): if any(a == r[0] for r in rep): pot.skip() elif not a.is_commutative: if a.is_symbol: nc_syms.add(a) pot.skip() elif not (a.is_Add or a.is_Mul or a.is_Pow): nc_obj.add(a) pot.skip() # If there is only one nc symbol or object, it can be factored regularly # but polys is going to complain, so replace it with a Dummy. if len(nc_obj) == 1 and not nc_syms: rep.append((nc_obj.pop(), Dummy())) elif len(nc_syms) == 1 and not nc_obj: rep.append((nc_syms.pop(), Dummy())) # Any remaining nc-objects will be replaced with an nc-Dummy and # identified as an nc-Symbol to watch out for nc_obj = sorted(nc_obj, key=default_sort_key) for n in nc_obj: nc = Dummy(commutative=False) rep.append((n, nc)) nc_syms.add(nc) expr = expr.subs(rep) nc_syms = list(nc_syms) nc_syms.sort(key=default_sort_key) return expr, {v: k for k, v in rep}, nc_syms def factor_nc(expr): """Return the factored form of ``expr`` while handling non-commutative expressions. Examples ======== >>> from sympy.core.exprtools import factor_nc >>> from sympy import Symbol >>> from sympy.abc import x >>> A = Symbol('A', commutative=False) >>> B = Symbol('B', commutative=False) >>> factor_nc((x**2 + 2*A*x + A**2).expand()) (x + A)**2 >>> factor_nc(((x + A)*(x + B)).expand()) (x + A)*(x + B) """ from sympy.simplify.simplify import powsimp from sympy.polys import gcd, factor def _pemexpand(expr): "Expand with the minimal set of hints necessary to check the result." return expr.expand(deep=True, mul=True, power_exp=True, power_base=False, basic=False, multinomial=True, log=False) expr = sympify(expr) if not isinstance(expr, Expr) or not expr.args: return expr if not expr.is_Add: return expr.func(*[factor_nc(a) for a in expr.args]) expr, rep, nc_symbols = _mask_nc(expr) if rep: return factor(expr).subs(rep) else: args = [a.args_cnc() for a in Add.make_args(expr)] c = g = l = r = S.One hit = False # find any commutative gcd term for i, a in enumerate(args): if i == 0: c = Mul._from_args(a[0]) elif a[0]: c = gcd(c, Mul._from_args(a[0])) else: c = S.One if c is not S.One: hit = True c, g = c.as_coeff_Mul() if g is not S.One: for i, (cc, _) in enumerate(args): cc = list(Mul.make_args(Mul._from_args(list(cc))/g)) args[i][0] = cc for i, (cc, _) in enumerate(args): cc[0] = cc[0]/c args[i][0] = cc # find any noncommutative common prefix for i, a in enumerate(args): if i == 0: n = a[1][:] else: n = common_prefix(n, a[1]) if not n: # is there a power that can be extracted? if not args[0][1]: break b, e = args[0][1][0].as_base_exp() ok = False if e.is_Integer: for t in args: if not t[1]: break bt, et = t[1][0].as_base_exp() if et.is_Integer and bt == b: e = min(e, et) else: break else: ok = hit = True l = b**e il = b**-e for _ in args: _[1][0] = il*_[1][0] break if not ok: break else: hit = True lenn = len(n) l = Mul(*n) for _ in args: _[1] = _[1][lenn:] # find any noncommutative common suffix for i, a in enumerate(args): if i == 0: n = a[1][:] else: n = common_suffix(n, a[1]) if not n: # is there a power that can be extracted? if not args[0][1]: break b, e = args[0][1][-1].as_base_exp() ok = False if e.is_Integer: for t in args: if not t[1]: break bt, et = t[1][-1].as_base_exp() if et.is_Integer and bt == b: e = min(e, et) else: break else: ok = hit = True r = b**e il = b**-e for _ in args: _[1][-1] = _[1][-1]*il break if not ok: break else: hit = True lenn = len(n) r = Mul(*n) for _ in args: _[1] = _[1][:len(_[1]) - lenn] if hit: mid = Add(*[Mul(*cc)*Mul(*nc) for cc, nc in args]) else: mid = expr # sort the symbols so the Dummys would appear in the same # order as the original symbols, otherwise you may introduce # a factor of -1, e.g. A**2 - B**2) -- {A:y, B:x} --> y**2 - x**2 # and the former factors into two terms, (A - B)*(A + B) while the # latter factors into 3 terms, (-1)*(x - y)*(x + y) rep1 = [(n, Dummy()) for n in sorted(nc_symbols, key=default_sort_key)] unrep1 = [(v, k) for k, v in rep1] unrep1.reverse() new_mid, r2, _ = _mask_nc(mid.subs(rep1)) new_mid = powsimp(factor(new_mid)) new_mid = new_mid.subs(r2).subs(unrep1) if new_mid.is_Pow: return _keep_coeff(c, g*l*new_mid*r) if new_mid.is_Mul: # XXX TODO there should be a way to inspect what order the terms # must be in and just select the plausible ordering without # checking permutations cfac = [] ncfac = [] for f in new_mid.args: if f.is_commutative: cfac.append(f) else: b, e = f.as_base_exp() if e.is_Integer: ncfac.extend([b]*e) else: ncfac.append(f) pre_mid = g*Mul(*cfac)*l target = _pemexpand(expr/c) for s in variations(ncfac, len(ncfac)): ok = pre_mid*Mul(*s)*r if _pemexpand(ok) == target: return _keep_coeff(c, ok) # mid was an Add that didn't factor successfully return _keep_coeff(c, g*l*mid*r) sympy-sympy-1.9/sympy/core/facts.py000066400000000000000000000365671412543434000175270ustar00rootroot00000000000000r"""This is rule-based deduction system for SymPy The whole thing is split into two parts - rules compilation and preparation of tables - runtime inference For rule-based inference engines, the classical work is RETE algorithm [1], [2] Although we are not implementing it in full (or even significantly) it's still still worth a read to understand the underlying ideas. In short, every rule in a system of rules is one of two forms: - atom -> ... (alpha rule) - And(atom1, atom2, ...) -> ... (beta rule) The major complexity is in efficient beta-rules processing and usually for an expert system a lot of effort goes into code that operates on beta-rules. Here we take minimalistic approach to get something usable first. - (preparation) of alpha- and beta- networks, everything except - (runtime) FactRules.deduce_all_facts _____________________________________ ( Kirr: I've never thought that doing ) ( logic stuff is that difficult... ) ------------------------------------- o ^__^ o (oo)\_______ (__)\ )\/\ ||----w | || || Some references on the topic ---------------------------- [1] https://en.wikipedia.org/wiki/Rete_algorithm [2] http://reports-archive.adm.cs.cmu.edu/anon/1995/CMU-CS-95-113.pdf https://en.wikipedia.org/wiki/Propositional_formula https://en.wikipedia.org/wiki/Inference_rule https://en.wikipedia.org/wiki/List_of_rules_of_inference """ from collections import defaultdict from .logic import Logic, And, Or, Not def _base_fact(atom): """Return the literal fact of an atom. Effectively, this merely strips the Not around a fact. """ if isinstance(atom, Not): return atom.arg else: return atom def _as_pair(atom): if isinstance(atom, Not): return (atom.arg, False) else: return (atom, True) # XXX this prepares forward-chaining rules for alpha-network def transitive_closure(implications): """ Computes the transitive closure of a list of implications Uses Warshall's algorithm, as described at http://www.cs.hope.edu/~cusack/Notes/Notes/DiscreteMath/Warshall.pdf. """ full_implications = set(implications) literals = set().union(*map(set, full_implications)) for k in literals: for i in literals: if (i, k) in full_implications: for j in literals: if (k, j) in full_implications: full_implications.add((i, j)) return full_implications def deduce_alpha_implications(implications): """deduce all implications Description by example ---------------------- given set of logic rules: a -> b b -> c we deduce all possible rules: a -> b, c b -> c implications: [] of (a,b) return: {} of a -> set([b, c, ...]) """ implications = implications + [(Not(j), Not(i)) for (i, j) in implications] res = defaultdict(set) full_implications = transitive_closure(implications) for a, b in full_implications: if a == b: continue # skip a->a cyclic input res[a].add(b) # Clean up tautologies and check consistency for a, impl in res.items(): impl.discard(a) na = Not(a) if na in impl: raise ValueError( 'implications are inconsistent: %s -> %s %s' % (a, na, impl)) return res def apply_beta_to_alpha_route(alpha_implications, beta_rules): """apply additional beta-rules (And conditions) to already-built alpha implication tables TODO: write about - static extension of alpha-chains - attaching refs to beta-nodes to alpha chains e.g. alpha_implications: a -> [b, !c, d] b -> [d] ... beta_rules: &(b,d) -> e then we'll extend a's rule to the following a -> [b, !c, d, e] """ x_impl = {} for x in alpha_implications.keys(): x_impl[x] = (set(alpha_implications[x]), []) for bcond, bimpl in beta_rules: for bk in bcond.args: if bk in x_impl: continue x_impl[bk] = (set(), []) # static extensions to alpha rules: # A: x -> a,b B: &(a,b) -> c ==> A: x -> a,b,c seen_static_extension = True while seen_static_extension: seen_static_extension = False for bcond, bimpl in beta_rules: if not isinstance(bcond, And): raise TypeError("Cond is not And") bargs = set(bcond.args) for x, (ximpls, bb) in x_impl.items(): x_all = ximpls | {x} # A: ... -> a B: &(...) -> a is non-informative if bimpl not in x_all and bargs.issubset(x_all): ximpls.add(bimpl) # we introduced new implication - now we have to restore # completeness of the whole set. bimpl_impl = x_impl.get(bimpl) if bimpl_impl is not None: ximpls |= bimpl_impl[0] seen_static_extension = True # attach beta-nodes which can be possibly triggered by an alpha-chain for bidx, (bcond, bimpl) in enumerate(beta_rules): bargs = set(bcond.args) for x, (ximpls, bb) in x_impl.items(): x_all = ximpls | {x} # A: ... -> a B: &(...) -> a (non-informative) if bimpl in x_all: continue # A: x -> a... B: &(!a,...) -> ... (will never trigger) # A: x -> a... B: &(...) -> !a (will never trigger) if any(Not(xi) in bargs or Not(xi) == bimpl for xi in x_all): continue if bargs & x_all: bb.append(bidx) return x_impl def rules_2prereq(rules): """build prerequisites table from rules Description by example ---------------------- given set of logic rules: a -> b, c b -> c we build prerequisites (from what points something can be deduced): b <- a c <- a, b rules: {} of a -> [b, c, ...] return: {} of c <- [a, b, ...] Note however, that this prerequisites may be *not* enough to prove a fact. An example is 'a -> b' rule, where prereq(a) is b, and prereq(b) is a. That's because a=T -> b=T, and b=F -> a=F, but a=F -> b=? """ prereq = defaultdict(set) for (a, _), impl in rules.items(): if isinstance(a, Not): a = a.args[0] for (i, _) in impl: if isinstance(i, Not): i = i.args[0] prereq[i].add(a) return prereq ################ # RULES PROVER # ################ class TautologyDetected(Exception): """(internal) Prover uses it for reporting detected tautology""" pass class Prover: """ai - prover of logic rules given a set of initial rules, Prover tries to prove all possible rules which follow from given premises. As a result proved_rules are always either in one of two forms: alpha or beta: Alpha rules ----------- This are rules of the form:: a -> b & c & d & ... Beta rules ---------- This are rules of the form:: &(a,b,...) -> c & d & ... i.e. beta rules are join conditions that say that something follows when *several* facts are true at the same time. """ def __init__(self): self.proved_rules = [] self._rules_seen = set() def split_alpha_beta(self): """split proved rules into alpha and beta chains""" rules_alpha = [] # a -> b rules_beta = [] # &(...) -> b for a, b in self.proved_rules: if isinstance(a, And): rules_beta.append((a, b)) else: rules_alpha.append((a, b)) return rules_alpha, rules_beta @property def rules_alpha(self): return self.split_alpha_beta()[0] @property def rules_beta(self): return self.split_alpha_beta()[1] def process_rule(self, a, b): """process a -> b rule""" # TODO write more? if (not a) or isinstance(b, bool): return if isinstance(a, bool): return if (a, b) in self._rules_seen: return else: self._rules_seen.add((a, b)) # this is the core of processing try: self._process_rule(a, b) except TautologyDetected: pass def _process_rule(self, a, b): # right part first # a -> b & c --> a -> b ; a -> c # (?) FIXME this is only correct when b & c != null ! if isinstance(b, And): for barg in b.args: self.process_rule(a, barg) # a -> b | c --> !b & !c -> !a # --> a & !b -> c # --> a & !c -> b elif isinstance(b, Or): # detect tautology first if not isinstance(a, Logic): # Atom # tautology: a -> a|c|... if a in b.args: raise TautologyDetected(a, b, 'a -> a|c|...') self.process_rule(And(*[Not(barg) for barg in b.args]), Not(a)) for bidx in range(len(b.args)): barg = b.args[bidx] brest = b.args[:bidx] + b.args[bidx + 1:] self.process_rule(And(a, Not(barg)), Or(*brest)) # left part # a & b -> c --> IRREDUCIBLE CASE -- WE STORE IT AS IS # (this will be the basis of beta-network) elif isinstance(a, And): if b in a.args: raise TautologyDetected(a, b, 'a & b -> a') self.proved_rules.append((a, b)) # XXX NOTE at present we ignore !c -> !a | !b elif isinstance(a, Or): if b in a.args: raise TautologyDetected(a, b, 'a | b -> a') for aarg in a.args: self.process_rule(aarg, b) else: # both `a` and `b` are atoms self.proved_rules.append((a, b)) # a -> b self.proved_rules.append((Not(b), Not(a))) # !b -> !a ######################################## class FactRules: """Rules that describe how to deduce facts in logic space When defined, these rules allow implications to quickly be determined for a set of facts. For this precomputed deduction tables are used. see `deduce_all_facts` (forward-chaining) Also it is possible to gather prerequisites for a fact, which is tried to be proven. (backward-chaining) Definition Syntax ----------------- a -> b -- a=T -> b=T (and automatically b=F -> a=F) a -> !b -- a=T -> b=F a == b -- a -> b & b -> a a -> b & c -- a=T -> b=T & c=T # TODO b | c Internals --------- .full_implications[k, v]: all the implications of fact k=v .beta_triggers[k, v]: beta rules that might be triggered when k=v .prereq -- {} k <- [] of k's prerequisites .defined_facts -- set of defined fact names """ def __init__(self, rules): """Compile rules into internal lookup tables""" if isinstance(rules, str): rules = rules.splitlines() # --- parse and process rules --- P = Prover() for rule in rules: # XXX `a` is hardcoded to be always atom a, op, b = rule.split(None, 2) a = Logic.fromstring(a) b = Logic.fromstring(b) if op == '->': P.process_rule(a, b) elif op == '==': P.process_rule(a, b) P.process_rule(b, a) else: raise ValueError('unknown op %r' % op) # --- build deduction networks --- self.beta_rules = [] for bcond, bimpl in P.rules_beta: self.beta_rules.append( ({_as_pair(a) for a in bcond.args}, _as_pair(bimpl))) # deduce alpha implications impl_a = deduce_alpha_implications(P.rules_alpha) # now: # - apply beta rules to alpha chains (static extension), and # - further associate beta rules to alpha chain (for inference # at runtime) impl_ab = apply_beta_to_alpha_route(impl_a, P.rules_beta) # extract defined fact names self.defined_facts = {_base_fact(k) for k in impl_ab.keys()} # build rels (forward chains) full_implications = defaultdict(set) beta_triggers = defaultdict(set) for k, (impl, betaidxs) in impl_ab.items(): full_implications[_as_pair(k)] = {_as_pair(i) for i in impl} beta_triggers[_as_pair(k)] = betaidxs self.full_implications = full_implications self.beta_triggers = beta_triggers # build prereq (backward chains) prereq = defaultdict(set) rel_prereq = rules_2prereq(full_implications) for k, pitems in rel_prereq.items(): prereq[k] |= pitems self.prereq = prereq class InconsistentAssumptions(ValueError): def __str__(self): kb, fact, value = self.args return "%s, %s=%s" % (kb, fact, value) class FactKB(dict): """ A simple propositional knowledge base relying on compiled inference rules. """ def __str__(self): return '{\n%s}' % ',\n'.join( ["\t%s: %s" % i for i in sorted(self.items())]) def __init__(self, rules): self.rules = rules def _tell(self, k, v): """Add fact k=v to the knowledge base. Returns True if the KB has actually been updated, False otherwise. """ if k in self and self[k] is not None: if self[k] == v: return False else: raise InconsistentAssumptions(self, k, v) else: self[k] = v return True # ********************************************* # * This is the workhorse, so keep it *fast*. * # ********************************************* def deduce_all_facts(self, facts): """ Update the KB with all the implications of a list of facts. Facts can be specified as a dictionary or as a list of (key, value) pairs. """ # keep frequently used attributes locally, so we'll avoid extra # attribute access overhead full_implications = self.rules.full_implications beta_triggers = self.rules.beta_triggers beta_rules = self.rules.beta_rules if isinstance(facts, dict): facts = facts.items() while facts: beta_maytrigger = set() # --- alpha chains --- for k, v in facts: if not self._tell(k, v) or v is None: continue # lookup routing tables for key, value in full_implications[k, v]: self._tell(key, value) beta_maytrigger.update(beta_triggers[k, v]) # --- beta chains --- facts = [] for bidx in beta_maytrigger: bcond, bimpl = beta_rules[bidx] if all(self.get(k) is v for k, v in bcond): facts.append(bimpl) sympy-sympy-1.9/sympy/core/function.py000066400000000000000000003376601412543434000202520ustar00rootroot00000000000000""" There are three types of functions implemented in SymPy: 1) defined functions (in the sense that they can be evaluated) like exp or sin; they have a name and a body: f = exp 2) undefined function which have a name but no body. Undefined functions can be defined using a Function class as follows: f = Function('f') (the result will be a Function instance) 3) anonymous function (or lambda function) which have a body (defined with dummy variables) but have no name: f = Lambda(x, exp(x)*x) f = Lambda((x, y), exp(x)*y) The fourth type of functions are composites, like (sin + cos)(x); these work in SymPy core, but are not yet part of SymPy. Examples ======== >>> import sympy >>> f = sympy.Function("f") >>> from sympy.abc import x >>> f(x) f(x) >>> print(sympy.srepr(f(x).func)) Function('f') >>> f(x).args (x,) """ from typing import Any, Dict as tDict, Optional, Set as tSet, Tuple as tTuple, Union from .add import Add from .assumptions import ManagedProperties from .basic import Basic, _atomic from .cache import cacheit from .compatibility import iterable, is_sequence, as_int, ordered, Iterable from .decorators import _sympifyit from .expr import Expr, AtomicExpr from .numbers import Rational, Float from .operations import LatticeOp from .rules import Transform from .singleton import S from .sympify import sympify from sympy.core.containers import Tuple, Dict from sympy.core.parameters import global_parameters from sympy.core.logic import fuzzy_and, fuzzy_or, fuzzy_not, FuzzyBool from sympy.utilities import default_sort_key from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.iterables import has_dups, sift from sympy.utilities.misc import filldedent import mpmath import mpmath.libmp as mlib import inspect from collections import Counter def _coeff_isneg(a): """Return True if the leading Number is negative. Examples ======== >>> from sympy.core.function import _coeff_isneg >>> from sympy import S, Symbol, oo, pi >>> _coeff_isneg(-3*pi) True >>> _coeff_isneg(S(3)) False >>> _coeff_isneg(-oo) True >>> _coeff_isneg(Symbol('n', negative=True)) # coeff is 1 False For matrix expressions: >>> from sympy import MatrixSymbol, sqrt >>> A = MatrixSymbol("A", 3, 3) >>> _coeff_isneg(-sqrt(2)*A) True >>> _coeff_isneg(sqrt(2)*A) False """ if a.is_MatMul: a = a.args[0] if a.is_Mul: a = a.args[0] return a.is_Number and a.is_extended_negative class PoleError(Exception): pass class ArgumentIndexError(ValueError): def __str__(self): return ("Invalid operation with argument number %s for Function %s" % (self.args[1], self.args[0])) class BadSignatureError(TypeError): '''Raised when a Lambda is created with an invalid signature''' pass class BadArgumentsError(TypeError): '''Raised when a Lambda is called with an incorrect number of arguments''' pass # Python 2/3 version that does not raise a Deprecation warning def arity(cls): """Return the arity of the function if it is known, else None. Explanation =========== When default values are specified for some arguments, they are optional and the arity is reported as a tuple of possible values. Examples ======== >>> from sympy.core.function import arity >>> from sympy import log >>> arity(lambda x: x) 1 >>> arity(log) (1, 2) >>> arity(lambda *x: sum(x)) is None True """ eval_ = getattr(cls, 'eval', cls) parameters = inspect.signature(eval_).parameters.items() if [p for _, p in parameters if p.kind == p.VAR_POSITIONAL]: return p_or_k = [p for _, p in parameters if p.kind == p.POSITIONAL_OR_KEYWORD] # how many have no default and how many have a default value no, yes = map(len, sift(p_or_k, lambda p:p.default == p.empty, binary=True)) return no if not yes else tuple(range(no, no + yes + 1)) class FunctionClass(ManagedProperties): """ Base class for function classes. FunctionClass is a subclass of type. Use Function('' [ , signature ]) to create undefined function classes. """ _new = type.__new__ def __init__(cls, *args, **kwargs): # honor kwarg value or class-defined value before using # the number of arguments in the eval function (if present) nargs = kwargs.pop('nargs', cls.__dict__.get('nargs', arity(cls))) if nargs is None and 'nargs' not in cls.__dict__: for supcls in cls.__mro__: if hasattr(supcls, '_nargs'): nargs = supcls._nargs break else: continue # Canonicalize nargs here; change to set in nargs. if is_sequence(nargs): if not nargs: raise ValueError(filldedent(''' Incorrectly specified nargs as %s: if there are no arguments, it should be `nargs = 0`; if there are any number of arguments, it should be `nargs = None`''' % str(nargs))) nargs = tuple(ordered(set(nargs))) elif nargs is not None: nargs = (as_int(nargs),) cls._nargs = nargs super().__init__(*args, **kwargs) @property def __signature__(self): """ Allow Python 3's inspect.signature to give a useful signature for Function subclasses. """ # Python 3 only, but backports (like the one in IPython) still might # call this. try: from inspect import signature except ImportError: return None # TODO: Look at nargs return signature(self.eval) @property def free_symbols(self): return set() @property def xreplace(self): # Function needs args so we define a property that returns # a function that takes args...and then use that function # to return the right value return lambda rule, **_: rule.get(self, self) @property def nargs(self): """Return a set of the allowed number of arguments for the function. Examples ======== >>> from sympy.core.function import Function >>> f = Function('f') If the function can take any number of arguments, the set of whole numbers is returned: >>> Function('f').nargs Naturals0 If the function was initialized to accept one or more arguments, a corresponding set will be returned: >>> Function('f', nargs=1).nargs {1} >>> Function('f', nargs=(2, 1)).nargs {1, 2} The undefined function, after application, also has the nargs attribute; the actual number of arguments is always available by checking the ``args`` attribute: >>> f = Function('f') >>> f(1).nargs Naturals0 >>> len(f(1).args) 1 """ from sympy.sets.sets import FiniteSet # XXX it would be nice to handle this in __init__ but there are import # problems with trying to import FiniteSet there return FiniteSet(*self._nargs) if self._nargs else S.Naturals0 def __repr__(cls): return cls.__name__ class Application(Basic, metaclass=FunctionClass): """ Base class for applied functions. Explanation =========== Instances of Application represent the result of applying an application of any type to any object. """ is_Function = True @cacheit def __new__(cls, *args, **options): from sympy.sets.fancysets import Naturals0 from sympy.sets.sets import FiniteSet args = list(map(sympify, args)) evaluate = options.pop('evaluate', global_parameters.evaluate) # WildFunction (and anything else like it) may have nargs defined # and we throw that value away here options.pop('nargs', None) if options: raise ValueError("Unknown options: %s" % options) if evaluate: evaluated = cls.eval(*args) if evaluated is not None: return evaluated obj = super().__new__(cls, *args, **options) # make nargs uniform here sentinel = object() objnargs = getattr(obj, "nargs", sentinel) if objnargs is not sentinel: # things passing through here: # - functions subclassed from Function (e.g. myfunc(1).nargs) # - functions like cos(1).nargs # - AppliedUndef with given nargs like Function('f', nargs=1)(1).nargs # Canonicalize nargs here if is_sequence(objnargs): nargs = tuple(ordered(set(objnargs))) elif objnargs is not None: nargs = (as_int(objnargs),) else: nargs = None else: # things passing through here: # - WildFunction('f').nargs # - AppliedUndef with no nargs like Function('f')(1).nargs nargs = obj._nargs # note the underscore here # convert to FiniteSet obj.nargs = FiniteSet(*nargs) if nargs else Naturals0() return obj @classmethod def eval(cls, *args): """ Returns a canonical form of cls applied to arguments args. Explanation =========== The eval() method is called when the class cls is about to be instantiated and it should return either some simplified instance (possible of some other class), or if the class cls should be unmodified, return None. Examples of eval() for the function "sign" --------------------------------------------- .. code-block:: python @classmethod def eval(cls, arg): if arg is S.NaN: return S.NaN if arg.is_zero: return S.Zero if arg.is_positive: return S.One if arg.is_negative: return S.NegativeOne if isinstance(arg, Mul): coeff, terms = arg.as_coeff_Mul(rational=True) if coeff is not S.One: return cls(coeff) * cls(terms) """ return @property def func(self): return self.__class__ def _eval_subs(self, old, new): if (old.is_Function and new.is_Function and callable(old) and callable(new) and old == self.func and len(self.args) in new.nargs): return new(*[i._subs(old, new) for i in self.args]) class Function(Application, Expr): """ Base class for applied mathematical functions. It also serves as a constructor for undefined function classes. Examples ======== First example shows how to use Function as a constructor for undefined function classes: >>> from sympy import Function, Symbol >>> x = Symbol('x') >>> f = Function('f') >>> g = Function('g')(x) >>> f f >>> f(x) f(x) >>> g g(x) >>> f(x).diff(x) Derivative(f(x), x) >>> g.diff(x) Derivative(g(x), x) Assumptions can be passed to Function, and if function is initialized with a Symbol, the function inherits the name and assumptions associated with the Symbol: >>> f_real = Function('f', real=True) >>> f_real(x).is_real True >>> f_real_inherit = Function(Symbol('f', real=True)) >>> f_real_inherit(x).is_real True Note that assumptions on a function are unrelated to the assumptions on the variable it is called on. If you want to add a relationship, subclass Function and define the appropriate ``_eval_is_assumption`` methods. In the following example Function is used as a base class for ``my_func`` that represents a mathematical function *my_func*. Suppose that it is well known, that *my_func(0)* is *1* and *my_func* at infinity goes to *0*, so we want those two simplifications to occur automatically. Suppose also that *my_func(x)* is real exactly when *x* is real. Here is an implementation that honours those requirements: >>> from sympy import Function, S, oo, I, sin >>> class my_func(Function): ... ... @classmethod ... def eval(cls, x): ... if x.is_Number: ... if x.is_zero: ... return S.One ... elif x is S.Infinity: ... return S.Zero ... ... def _eval_is_real(self): ... return self.args[0].is_real ... >>> x = S('x') >>> my_func(0) + sin(0) 1 >>> my_func(oo) 0 >>> my_func(3.54).n() # Not yet implemented for my_func. my_func(3.54) >>> my_func(I).is_real False In order for ``my_func`` to become useful, several other methods would need to be implemented. See source code of some of the already implemented functions for more complete examples. Also, if the function can take more than one argument, then ``nargs`` must be defined, e.g. if ``my_func`` can take one or two arguments then, >>> class my_func(Function): ... nargs = (1, 2) ... >>> """ @property def _diff_wrt(self): return False @cacheit def __new__(cls, *args, **options): # Handle calls like Function('f') if cls is Function: return UndefinedFunction(*args, **options) n = len(args) if n not in cls.nargs: # XXX: exception message must be in exactly this format to # make it work with NumPy's functions like vectorize(). See, # for example, https://github.com/numpy/numpy/issues/1697. # The ideal solution would be just to attach metadata to # the exception and change NumPy to take advantage of this. temp = ('%(name)s takes %(qual)s %(args)s ' 'argument%(plural)s (%(given)s given)') raise TypeError(temp % { 'name': cls, 'qual': 'exactly' if len(cls.nargs) == 1 else 'at least', 'args': min(cls.nargs), 'plural': 's'*(min(cls.nargs) != 1), 'given': n}) evaluate = options.get('evaluate', global_parameters.evaluate) result = super().__new__(cls, *args, **options) if evaluate and isinstance(result, cls) and result.args: pr2 = min(cls._should_evalf(a) for a in result.args) if pr2 > 0: pr = max(cls._should_evalf(a) for a in result.args) result = result.evalf(mlib.libmpf.prec_to_dps(pr)) return result @classmethod def _should_evalf(cls, arg): """ Decide if the function should automatically evalf(). Explanation =========== By default (in this implementation), this happens if (and only if) the ARG is a floating point number. This function is used by __new__. Returns the precision to evalf to, or -1 if it shouldn't evalf. """ from sympy.core.evalf import pure_complex if arg.is_Float: return arg._prec if not arg.is_Add: return -1 m = pure_complex(arg) if m is None or not (m[0].is_Float or m[1].is_Float): return -1 l = [i._prec for i in m if i.is_Float] l.append(-1) return max(l) @classmethod def class_key(cls): from sympy.sets.fancysets import Naturals0 funcs = { 'exp': 10, 'log': 11, 'sin': 20, 'cos': 21, 'tan': 22, 'cot': 23, 'sinh': 30, 'cosh': 31, 'tanh': 32, 'coth': 33, 'conjugate': 40, 're': 41, 'im': 42, 'arg': 43, } name = cls.__name__ try: i = funcs[name] except KeyError: i = 0 if isinstance(cls.nargs, Naturals0) else 10000 return 4, i, name def _eval_evalf(self, prec): def _get_mpmath_func(fname): """Lookup mpmath function based on name""" if isinstance(self, AppliedUndef): # Shouldn't lookup in mpmath but might have ._imp_ return None if not hasattr(mpmath, fname): from sympy.utilities.lambdify import MPMATH_TRANSLATIONS fname = MPMATH_TRANSLATIONS.get(fname, None) if fname is None: return None return getattr(mpmath, fname) _eval_mpmath = getattr(self, '_eval_mpmath', None) if _eval_mpmath is None: func = _get_mpmath_func(self.func.__name__) args = self.args else: func, args = _eval_mpmath() # Fall-back evaluation if func is None: imp = getattr(self, '_imp_', None) if imp is None: return None try: return Float(imp(*[i.evalf(prec) for i in self.args]), prec) except (TypeError, ValueError): return None # Convert all args to mpf or mpc # Convert the arguments to *higher* precision than requested for the # final result. # XXX + 5 is a guess, it is similar to what is used in evalf.py. Should # we be more intelligent about it? try: args = [arg._to_mpmath(prec + 5) for arg in args] def bad(m): from mpmath import mpf, mpc # the precision of an mpf value is the last element # if that is 1 (and m[1] is not 1 which would indicate a # power of 2), then the eval failed; so check that none of # the arguments failed to compute to a finite precision. # Note: An mpc value has two parts, the re and imag tuple; # check each of those parts, too. Anything else is allowed to # pass if isinstance(m, mpf): m = m._mpf_ return m[1] !=1 and m[-1] == 1 elif isinstance(m, mpc): m, n = m._mpc_ return m[1] !=1 and m[-1] == 1 and \ n[1] !=1 and n[-1] == 1 else: return False if any(bad(a) for a in args): raise ValueError # one or more args failed to compute with significance except ValueError: return with mpmath.workprec(prec): v = func(*args) return Expr._from_mpmath(v, prec) def _eval_derivative(self, s): # f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s) i = 0 l = [] for a in self.args: i += 1 da = a.diff(s) if da.is_zero: continue try: df = self.fdiff(i) except ArgumentIndexError: df = Function.fdiff(self, i) l.append(df * da) return Add(*l) def _eval_is_commutative(self): return fuzzy_and(a.is_commutative for a in self.args) def _eval_is_meromorphic(self, x, a): if not self.args: return True if any(arg.has(x) for arg in self.args[1:]): return False arg = self.args[0] if not arg._eval_is_meromorphic(x, a): return None return fuzzy_not(type(self).is_singular(arg.subs(x, a))) _singularities = None # type: Union[FuzzyBool, tTuple[Expr, ...]] @classmethod def is_singular(cls, a): """ Tests whether the argument is an essential singularity or a branch point, or the functions is non-holomorphic. """ ss = cls._singularities if ss in (True, None, False): return ss return fuzzy_or(a.is_infinite if s is S.ComplexInfinity else (a - s).is_zero for s in ss) def as_base_exp(self): """ Returns the method as the 2-tuple (base, exponent). """ return self, S.One def _eval_aseries(self, n, args0, x, logx): """ Compute an asymptotic expansion around args0, in terms of self.args. This function is only used internally by _eval_nseries and should not be called directly; derived classes can overwrite this to implement asymptotic expansions. """ from sympy.utilities.misc import filldedent raise PoleError(filldedent(''' Asymptotic expansion of %s around %s is not implemented.''' % (type(self), args0))) def _eval_nseries(self, x, n, logx, cdir=0): """ This function does compute series for multivariate functions, but the expansion is always in terms of *one* variable. Examples ======== >>> from sympy import atan2 >>> from sympy.abc import x, y >>> atan2(x, y).series(x, n=2) atan2(0, y) + x/y + O(x**2) >>> atan2(x, y).series(y, n=2) -y/x + atan2(x, 0) + O(y**2) This function also computes asymptotic expansions, if necessary and possible: >>> from sympy import loggamma >>> loggamma(1/x)._eval_nseries(x,0,None) -1/x - log(x)/x + log(x)/2 + O(1) """ from sympy import Order from sympy.core.symbol import uniquely_named_symbol from sympy.sets.sets import FiniteSet args = self.args args0 = [t.limit(x, 0) for t in args] if any(t.is_finite is False for t in args0): from sympy import oo, zoo, nan # XXX could use t.as_leading_term(x) here but it's a little # slower a = [t.compute_leading_term(x, logx=logx) for t in args] a0 = [t.limit(x, 0) for t in a] if any([t.has(oo, -oo, zoo, nan) for t in a0]): return self._eval_aseries(n, args0, x, logx) # Careful: the argument goes to oo, but only logarithmically so. We # are supposed to do a power series expansion "around the # logarithmic term". e.g. # f(1+x+log(x)) # -> f(1+logx) + x*f'(1+logx) + O(x**2) # where 'logx' is given in the argument a = [t._eval_nseries(x, n, logx) for t in args] z = [r - r0 for (r, r0) in zip(a, a0)] p = [Dummy() for _ in z] q = [] v = None for ai, zi, pi in zip(a0, z, p): if zi.has(x): if v is not None: raise NotImplementedError q.append(ai + pi) v = pi else: q.append(ai) e1 = self.func(*q) if v is None: return e1 s = e1._eval_nseries(v, n, logx) o = s.getO() s = s.removeO() s = s.subs(v, zi).expand() + Order(o.expr.subs(v, zi), x) return s if (self.func.nargs is S.Naturals0 or (self.func.nargs == FiniteSet(1) and args0[0]) or any(c > 1 for c in self.func.nargs)): e = self e1 = e.expand() if e == e1: #for example when e = sin(x+1) or e = sin(cos(x)) #let's try the general algorithm if len(e.args) == 1: # issue 14411 e = e.func(e.args[0].cancel()) term = e.subs(x, S.Zero) if term.is_finite is False or term is S.NaN: raise PoleError("Cannot expand %s around 0" % (self)) series = term fact = S.One _x = uniquely_named_symbol('xi', self) e = e.subs(x, _x) for i in range(n - 1): i += 1 fact *= Rational(i) e = e.diff(_x) subs = e.subs(_x, S.Zero) if subs is S.NaN: # try to evaluate a limit if we have to subs = e.limit(_x, S.Zero) if subs.is_finite is False: raise PoleError("Cannot expand %s around 0" % (self)) term = subs*(x**i)/fact term = term.expand() series += term return series + Order(x**n, x) return e1.nseries(x, n=n, logx=logx) arg = self.args[0] l = [] g = None # try to predict a number of terms needed nterms = n + 2 cf = Order(arg.as_leading_term(x), x).getn() if cf != 0: nterms = (n/cf).ceiling() for i in range(nterms): g = self.taylor_term(i, arg, g) g = g.nseries(x, n=n, logx=logx) l.append(g) return Add(*l) + Order(x**n, x) def fdiff(self, argindex=1): """ Returns the first derivative of the function. """ if not (1 <= argindex <= len(self.args)): raise ArgumentIndexError(self, argindex) ix = argindex - 1 A = self.args[ix] if A._diff_wrt: if len(self.args) == 1 or not A.is_Symbol: return _derivative_dispatch(self, A) for i, v in enumerate(self.args): if i != ix and A in v.free_symbols: # it can't be in any other argument's free symbols # issue 8510 break else: return _derivative_dispatch(self, A) # See issue 4624 and issue 4719, 5600 and 8510 D = Dummy('xi_%i' % argindex, dummy_index=hash(A)) args = self.args[:ix] + (D,) + self.args[ix + 1:] return Subs(Derivative(self.func(*args), D), D, A) def _eval_as_leading_term(self, x, logx=None, cdir=0): """Stub that should be overridden by new Functions to return the first non-zero term in a series if ever an x-dependent argument whose leading term vanishes as x -> 0 might be encountered. See, for example, cos._eval_as_leading_term. """ from sympy import Order args = [a.as_leading_term(x, logx=logx) for a in self.args] o = Order(1, x) if any(x in a.free_symbols and o.contains(a) for a in args): # Whereas x and any finite number are contained in O(1, x), # expressions like 1/x are not. If any arg simplified to a # vanishing expression as x -> 0 (like x or x**2, but not # 3, 1/x, etc...) then the _eval_as_leading_term is needed # to supply the first non-zero term of the series, # # e.g. expression leading term # ---------- ------------ # cos(1/x) cos(1/x) # cos(cos(x)) cos(1) # cos(x) 1 <- _eval_as_leading_term needed # sin(x) x <- _eval_as_leading_term needed # raise NotImplementedError( '%s has no _eval_as_leading_term routine' % self.func) else: return self.func(*args) class AppliedUndef(Function): """ Base class for expressions resulting from the application of an undefined function. """ is_number = False def __new__(cls, *args, **options): args = list(map(sympify, args)) u = [a.name for a in args if isinstance(a, UndefinedFunction)] if u: raise TypeError('Invalid argument: expecting an expression, not UndefinedFunction%s: %s' % ( 's'*(len(u) > 1), ', '.join(u))) obj = super().__new__(cls, *args, **options) return obj def _eval_as_leading_term(self, x, logx=None, cdir=0): return self @property def _diff_wrt(self): """ Allow derivatives wrt to undefined functions. Examples ======== >>> from sympy import Function, Symbol >>> f = Function('f') >>> x = Symbol('x') >>> f(x)._diff_wrt True >>> f(x).diff(x) Derivative(f(x), x) """ return True class UndefSageHelper: """ Helper to facilitate Sage conversion. """ def __get__(self, ins, typ): import sage.all as sage if ins is None: return lambda: sage.function(typ.__name__) else: args = [arg._sage_() for arg in ins.args] return lambda : sage.function(ins.__class__.__name__)(*args) _undef_sage_helper = UndefSageHelper() class UndefinedFunction(FunctionClass): """ The (meta)class of undefined functions. """ def __new__(mcl, name, bases=(AppliedUndef,), __dict__=None, **kwargs): from .symbol import _filter_assumptions # Allow Function('f', real=True) # and/or Function(Symbol('f', real=True)) assumptions, kwargs = _filter_assumptions(kwargs) if isinstance(name, Symbol): assumptions = name._merge(assumptions) name = name.name elif not isinstance(name, str): raise TypeError('expecting string or Symbol for name') else: commutative = assumptions.get('commutative', None) assumptions = Symbol(name, **assumptions).assumptions0 if commutative is None: assumptions.pop('commutative') __dict__ = __dict__ or {} # put the `is_*` for into __dict__ __dict__.update({'is_%s' % k: v for k, v in assumptions.items()}) # You can add other attributes, although they do have to be hashable # (but seriously, if you want to add anything other than assumptions, # just subclass Function) __dict__.update(kwargs) # add back the sanitized assumptions without the is_ prefix kwargs.update(assumptions) # Save these for __eq__ __dict__.update({'_kwargs': kwargs}) # do this for pickling __dict__['__module__'] = None obj = super().__new__(mcl, name, bases, __dict__) obj.name = name obj._sage_ = _undef_sage_helper return obj def __instancecheck__(cls, instance): return cls in type(instance).__mro__ _kwargs = {} # type: tDict[str, Optional[bool]] def __hash__(self): return hash((self.class_key(), frozenset(self._kwargs.items()))) def __eq__(self, other): return (isinstance(other, self.__class__) and self.class_key() == other.class_key() and self._kwargs == other._kwargs) def __ne__(self, other): return not self == other @property def _diff_wrt(self): return False # XXX: The type: ignore on WildFunction is because mypy complains: # # sympy/core/function.py:939: error: Cannot determine type of 'sort_key' in # base class 'Expr' # # Somehow this is because of the @cacheit decorator but it is not clear how to # fix it. class WildFunction(Function, AtomicExpr): # type: ignore """ A WildFunction function matches any function (with its arguments). Examples ======== >>> from sympy import WildFunction, Function, cos >>> from sympy.abc import x, y >>> F = WildFunction('F') >>> f = Function('f') >>> F.nargs Naturals0 >>> x.match(F) >>> F.match(F) {F_: F_} >>> f(x).match(F) {F_: f(x)} >>> cos(x).match(F) {F_: cos(x)} >>> f(x, y).match(F) {F_: f(x, y)} To match functions with a given number of arguments, set ``nargs`` to the desired value at instantiation: >>> F = WildFunction('F', nargs=2) >>> F.nargs {2} >>> f(x).match(F) >>> f(x, y).match(F) {F_: f(x, y)} To match functions with a range of arguments, set ``nargs`` to a tuple containing the desired number of arguments, e.g. if ``nargs = (1, 2)`` then functions with 1 or 2 arguments will be matched. >>> F = WildFunction('F', nargs=(1, 2)) >>> F.nargs {1, 2} >>> f(x).match(F) {F_: f(x)} >>> f(x, y).match(F) {F_: f(x, y)} >>> f(x, y, 1).match(F) """ # XXX: What is this class attribute used for? include = set() # type: tSet[Any] def __init__(cls, name, **assumptions): from sympy.sets.sets import Set, FiniteSet cls.name = name nargs = assumptions.pop('nargs', S.Naturals0) if not isinstance(nargs, Set): # Canonicalize nargs here. See also FunctionClass. if is_sequence(nargs): nargs = tuple(ordered(set(nargs))) elif nargs is not None: nargs = (as_int(nargs),) nargs = FiniteSet(*nargs) cls.nargs = nargs def matches(self, expr, repl_dict={}, old=False): if not isinstance(expr, (AppliedUndef, Function)): return None if len(expr.args) not in self.nargs: return None repl_dict = repl_dict.copy() repl_dict[self] = expr return repl_dict class Derivative(Expr): """ Carries out differentiation of the given expression with respect to symbols. Examples ======== >>> from sympy import Derivative, Function, symbols, Subs >>> from sympy.abc import x, y >>> f, g = symbols('f g', cls=Function) >>> Derivative(x**2, x, evaluate=True) 2*x Denesting of derivatives retains the ordering of variables: >>> Derivative(Derivative(f(x, y), y), x) Derivative(f(x, y), y, x) Contiguously identical symbols are merged into a tuple giving the symbol and the count: >>> Derivative(f(x), x, x, y, x) Derivative(f(x), (x, 2), y, x) If the derivative cannot be performed, and evaluate is True, the order of the variables of differentiation will be made canonical: >>> Derivative(f(x, y), y, x, evaluate=True) Derivative(f(x, y), x, y) Derivatives with respect to undefined functions can be calculated: >>> Derivative(f(x)**2, f(x), evaluate=True) 2*f(x) Such derivatives will show up when the chain rule is used to evalulate a derivative: >>> f(g(x)).diff(x) Derivative(f(g(x)), g(x))*Derivative(g(x), x) Substitution is used to represent derivatives of functions with arguments that are not symbols or functions: >>> f(2*x + 3).diff(x) == 2*Subs(f(y).diff(y), y, 2*x + 3) True Notes ===== Simplification of high-order derivatives: Because there can be a significant amount of simplification that can be done when multiple differentiations are performed, results will be automatically simplified in a fairly conservative fashion unless the keyword ``simplify`` is set to False. >>> from sympy import sqrt, diff, Function, symbols >>> from sympy.abc import x, y, z >>> f, g = symbols('f,g', cls=Function) >>> e = sqrt((x + 1)**2 + x) >>> diff(e, (x, 5), simplify=False).count_ops() 136 >>> diff(e, (x, 5)).count_ops() 30 Ordering of variables: If evaluate is set to True and the expression cannot be evaluated, the list of differentiation symbols will be sorted, that is, the expression is assumed to have continuous derivatives up to the order asked. Derivative wrt non-Symbols: For the most part, one may not differentiate wrt non-symbols. For example, we do not allow differentiation wrt `x*y` because there are multiple ways of structurally defining where x*y appears in an expression: a very strict definition would make (x*y*z).diff(x*y) == 0. Derivatives wrt defined functions (like cos(x)) are not allowed, either: >>> (x*y*z).diff(x*y) Traceback (most recent call last): ... ValueError: Can't calculate derivative wrt x*y. To make it easier to work with variational calculus, however, derivatives wrt AppliedUndef and Derivatives are allowed. For example, in the Euler-Lagrange method one may write F(t, u, v) where u = f(t) and v = f'(t). These variables can be written explicitly as functions of time:: >>> from sympy.abc import t >>> F = Function('F') >>> U = f(t) >>> V = U.diff(t) The derivative wrt f(t) can be obtained directly: >>> direct = F(t, U, V).diff(U) When differentiation wrt a non-Symbol is attempted, the non-Symbol is temporarily converted to a Symbol while the differentiation is performed and the same answer is obtained: >>> indirect = F(t, U, V).subs(U, x).diff(x).subs(x, U) >>> assert direct == indirect The implication of this non-symbol replacement is that all functions are treated as independent of other functions and the symbols are independent of the functions that contain them:: >>> x.diff(f(x)) 0 >>> g(x).diff(f(x)) 0 It also means that derivatives are assumed to depend only on the variables of differentiation, not on anything contained within the expression being differentiated:: >>> F = f(x) >>> Fx = F.diff(x) >>> Fx.diff(F) # derivative depends on x, not F 0 >>> Fxx = Fx.diff(x) >>> Fxx.diff(Fx) # derivative depends on x, not Fx 0 The last example can be made explicit by showing the replacement of Fx in Fxx with y: >>> Fxx.subs(Fx, y) Derivative(y, x) Since that in itself will evaluate to zero, differentiating wrt Fx will also be zero: >>> _.doit() 0 Replacing undefined functions with concrete expressions One must be careful to replace undefined functions with expressions that contain variables consistent with the function definition and the variables of differentiation or else insconsistent result will be obtained. Consider the following example: >>> eq = f(x)*g(y) >>> eq.subs(f(x), x*y).diff(x, y).doit() y*Derivative(g(y), y) + g(y) >>> eq.diff(x, y).subs(f(x), x*y).doit() y*Derivative(g(y), y) The results differ because `f(x)` was replaced with an expression that involved both variables of differentiation. In the abstract case, differentiation of `f(x)` by `y` is 0; in the concrete case, the presence of `y` made that derivative nonvanishing and produced the extra `g(y)` term. Defining differentiation for an object An object must define ._eval_derivative(symbol) method that returns the differentiation result. This function only needs to consider the non-trivial case where expr contains symbol and it should call the diff() method internally (not _eval_derivative); Derivative should be the only one to call _eval_derivative. Any class can allow derivatives to be taken with respect to itself (while indicating its scalar nature). See the docstring of Expr._diff_wrt. See Also ======== _sort_variable_count """ is_Derivative = True @property def _diff_wrt(self): """An expression may be differentiated wrt a Derivative if it is in elementary form. Examples ======== >>> from sympy import Function, Derivative, cos >>> from sympy.abc import x >>> f = Function('f') >>> Derivative(f(x), x)._diff_wrt True >>> Derivative(cos(x), x)._diff_wrt False >>> Derivative(x + 1, x)._diff_wrt False A Derivative might be an unevaluated form of what will not be a valid variable of differentiation if evaluated. For example, >>> Derivative(f(f(x)), x).doit() Derivative(f(x), x)*Derivative(f(f(x)), f(x)) Such an expression will present the same ambiguities as arise when dealing with any other product, like ``2*x``, so ``_diff_wrt`` is False: >>> Derivative(f(f(x)), x)._diff_wrt False """ return self.expr._diff_wrt and isinstance(self.doit(), Derivative) def __new__(cls, expr, *variables, **kwargs): from sympy.matrices.common import MatrixCommon from sympy import Integer, MatrixExpr from sympy.tensor.array import Array, NDimArray from sympy.utilities.misc import filldedent expr = sympify(expr) symbols_or_none = getattr(expr, "free_symbols", None) has_symbol_set = isinstance(symbols_or_none, set) if not has_symbol_set: raise ValueError(filldedent(''' Since there are no variables in the expression %s, it cannot be differentiated.''' % expr)) # determine value for variables if it wasn't given if not variables: variables = expr.free_symbols if len(variables) != 1: if expr.is_number: return S.Zero if len(variables) == 0: raise ValueError(filldedent(''' Since there are no variables in the expression, the variable(s) of differentiation must be supplied to differentiate %s''' % expr)) else: raise ValueError(filldedent(''' Since there is more than one variable in the expression, the variable(s) of differentiation must be supplied to differentiate %s''' % expr)) # Standardize the variables by sympifying them: variables = list(sympify(variables)) # Split the list of variables into a list of the variables we are diff # wrt, where each element of the list has the form (s, count) where # s is the entity to diff wrt and count is the order of the # derivative. variable_count = [] array_likes = (tuple, list, Tuple) for i, v in enumerate(variables): if isinstance(v, Integer): if i == 0: raise ValueError("First variable cannot be a number: %i" % v) count = v prev, prevcount = variable_count[-1] if prevcount != 1: raise TypeError("tuple {} followed by number {}".format((prev, prevcount), v)) if count == 0: variable_count.pop() else: variable_count[-1] = Tuple(prev, count) else: if isinstance(v, array_likes): if len(v) == 0: # Ignore empty tuples: Derivative(expr, ... , (), ... ) continue if isinstance(v[0], array_likes): # Derive by array: Derivative(expr, ... , [[x, y, z]], ... ) if len(v) == 1: v = Array(v[0]) count = 1 else: v, count = v v = Array(v) else: v, count = v if count == 0: continue elif isinstance(v, UndefinedFunction): raise TypeError( "cannot differentiate wrt " "UndefinedFunction: %s" % v) else: count = 1 variable_count.append(Tuple(v, count)) # light evaluation of contiguous, identical # items: (x, 1), (x, 1) -> (x, 2) merged = [] for t in variable_count: v, c = t if c.is_negative: raise ValueError( 'order of differentiation must be nonnegative') if merged and merged[-1][0] == v: c += merged[-1][1] if not c: merged.pop() else: merged[-1] = Tuple(v, c) else: merged.append(t) variable_count = merged # sanity check of variables of differentation; we waited # until the counts were computed since some variables may # have been removed because the count was 0 for v, c in variable_count: # v must have _diff_wrt True if not v._diff_wrt: __ = '' # filler to make error message neater raise ValueError(filldedent(''' Can't calculate derivative wrt %s.%s''' % (v, __))) # We make a special case for 0th derivative, because there is no # good way to unambiguously print this. if len(variable_count) == 0: return expr evaluate = kwargs.get('evaluate', False) if evaluate: if isinstance(expr, Derivative): expr = expr.canonical variable_count = [ (v.canonical if isinstance(v, Derivative) else v, c) for v, c in variable_count] # Look for a quick exit if there are symbols that don't appear in # expression at all. Note, this cannot check non-symbols like # Derivatives as those can be created by intermediate # derivatives. zero = False free = expr.free_symbols for v, c in variable_count: vfree = v.free_symbols if c.is_positive and vfree: if isinstance(v, AppliedUndef): # these match exactly since # x.diff(f(x)) == g(x).diff(f(x)) == 0 # and are not created by differentiation D = Dummy() if not expr.xreplace({v: D}).has(D): zero = True break elif isinstance(v, MatrixExpr): zero = False break elif isinstance(v, Symbol) and v not in free: zero = True break else: if not free & vfree: # e.g. v is IndexedBase or Matrix zero = True break if zero: return cls._get_zero_with_shape_like(expr) # make the order of symbols canonical #TODO: check if assumption of discontinuous derivatives exist variable_count = cls._sort_variable_count(variable_count) # denest if isinstance(expr, Derivative): variable_count = list(expr.variable_count) + variable_count expr = expr.expr return _derivative_dispatch(expr, *variable_count, **kwargs) # we return here if evaluate is False or if there is no # _eval_derivative method if not evaluate or not hasattr(expr, '_eval_derivative'): # return an unevaluated Derivative if evaluate and variable_count == [(expr, 1)] and expr.is_scalar: # special hack providing evaluation for classes # that have defined is_scalar=True but have no # _eval_derivative defined return S.One return Expr.__new__(cls, expr, *variable_count) # evaluate the derivative by calling _eval_derivative method # of expr for each variable # ------------------------------------------------------------- nderivs = 0 # how many derivatives were performed unhandled = [] for i, (v, count) in enumerate(variable_count): old_expr = expr old_v = None is_symbol = v.is_symbol or isinstance(v, (Iterable, Tuple, MatrixCommon, NDimArray)) if not is_symbol: old_v = v v = Dummy('xi') expr = expr.xreplace({old_v: v}) # Derivatives and UndefinedFunctions are independent # of all others clashing = not (isinstance(old_v, Derivative) or \ isinstance(old_v, AppliedUndef)) if not v in expr.free_symbols and not clashing: return expr.diff(v) # expr's version of 0 if not old_v.is_scalar and not hasattr( old_v, '_eval_derivative'): # special hack providing evaluation for classes # that have defined is_scalar=True but have no # _eval_derivative defined expr *= old_v.diff(old_v) obj = cls._dispatch_eval_derivative_n_times(expr, v, count) if obj is not None and obj.is_zero: return obj nderivs += count if old_v is not None: if obj is not None: # remove the dummy that was used obj = obj.subs(v, old_v) # restore expr expr = old_expr if obj is None: # we've already checked for quick-exit conditions # that give 0 so the remaining variables # are contained in the expression but the expression # did not compute a derivative so we stop taking # derivatives unhandled = variable_count[i:] break expr = obj # what we have so far can be made canonical expr = expr.replace( lambda x: isinstance(x, Derivative), lambda x: x.canonical) if unhandled: if isinstance(expr, Derivative): unhandled = list(expr.variable_count) + unhandled expr = expr.expr expr = Expr.__new__(cls, expr, *unhandled) if (nderivs > 1) == True and kwargs.get('simplify', True): from sympy.core.exprtools import factor_terms from sympy.simplify.simplify import signsimp expr = factor_terms(signsimp(expr)) return expr @property def canonical(cls): return cls.func(cls.expr, *Derivative._sort_variable_count(cls.variable_count)) @classmethod def _sort_variable_count(cls, vc): """ Sort (variable, count) pairs into canonical order while retaining order of variables that do not commute during differentiation: * symbols and functions commute with each other * derivatives commute with each other * a derivative doesn't commute with anything it contains * any other object is not allowed to commute if it has free symbols in common with another object Examples ======== >>> from sympy import Derivative, Function, symbols >>> vsort = Derivative._sort_variable_count >>> x, y, z = symbols('x y z') >>> f, g, h = symbols('f g h', cls=Function) Contiguous items are collapsed into one pair: >>> vsort([(x, 1), (x, 1)]) [(x, 2)] >>> vsort([(y, 1), (f(x), 1), (y, 1), (f(x), 1)]) [(y, 2), (f(x), 2)] Ordering is canonical. >>> def vsort0(*v): ... # docstring helper to ... # change vi -> (vi, 0), sort, and return vi vals ... return [i[0] for i in vsort([(i, 0) for i in v])] >>> vsort0(y, x) [x, y] >>> vsort0(g(y), g(x), f(y)) [f(y), g(x), g(y)] Symbols are sorted as far to the left as possible but never move to the left of a derivative having the same symbol in its variables; the same applies to AppliedUndef which are always sorted after Symbols: >>> dfx = f(x).diff(x) >>> assert vsort0(dfx, y) == [y, dfx] >>> assert vsort0(dfx, x) == [dfx, x] """ from sympy.utilities.iterables import uniq, topological_sort if not vc: return [] vc = list(vc) if len(vc) == 1: return [Tuple(*vc[0])] V = list(range(len(vc))) E = [] v = lambda i: vc[i][0] D = Dummy() def _block(d, v, wrt=False): # return True if v should not come before d else False if d == v: return wrt if d.is_Symbol: return False if isinstance(d, Derivative): # a derivative blocks if any of it's variables contain # v; the wrt flag will return True for an exact match # and will cause an AppliedUndef to block if v is in # the arguments if any(_block(k, v, wrt=True) for k in d._wrt_variables): return True return False if not wrt and isinstance(d, AppliedUndef): return False if v.is_Symbol: return v in d.free_symbols if isinstance(v, AppliedUndef): return _block(d.xreplace({v: D}), D) return d.free_symbols & v.free_symbols for i in range(len(vc)): for j in range(i): if _block(v(j), v(i)): E.append((j,i)) # this is the default ordering to use in case of ties O = dict(zip(ordered(uniq([i for i, c in vc])), range(len(vc)))) ix = topological_sort((V, E), key=lambda i: O[v(i)]) # merge counts of contiguously identical items merged = [] for v, c in [vc[i] for i in ix]: if merged and merged[-1][0] == v: merged[-1][1] += c else: merged.append([v, c]) return [Tuple(*i) for i in merged] def _eval_is_commutative(self): return self.expr.is_commutative def _eval_derivative(self, v): # If v (the variable of differentiation) is not in # self.variables, we might be able to take the derivative. if v not in self._wrt_variables: dedv = self.expr.diff(v) if isinstance(dedv, Derivative): return dedv.func(dedv.expr, *(self.variable_count + dedv.variable_count)) # dedv (d(self.expr)/dv) could have simplified things such that the # derivative wrt things in self.variables can now be done. Thus, # we set evaluate=True to see if there are any other derivatives # that can be done. The most common case is when dedv is a simple # number so that the derivative wrt anything else will vanish. return self.func(dedv, *self.variables, evaluate=True) # In this case v was in self.variables so the derivative wrt v has # already been attempted and was not computed, either because it # couldn't be or evaluate=False originally. variable_count = list(self.variable_count) variable_count.append((v, 1)) return self.func(self.expr, *variable_count, evaluate=False) def doit(self, **hints): expr = self.expr if hints.get('deep', True): expr = expr.doit(**hints) hints['evaluate'] = True rv = self.func(expr, *self.variable_count, **hints) if rv!= self and rv.has(Derivative): rv = rv.doit(**hints) return rv @_sympifyit('z0', NotImplementedError) def doit_numerically(self, z0): """ Evaluate the derivative at z numerically. When we can represent derivatives at a point, this should be folded into the normal evalf. For now, we need a special method. """ if len(self.free_symbols) != 1 or len(self.variables) != 1: raise NotImplementedError('partials and higher order derivatives') z = list(self.free_symbols)[0] def eval(x): f0 = self.expr.subs(z, Expr._from_mpmath(x, prec=mpmath.mp.prec)) f0 = f0.evalf(mlib.libmpf.prec_to_dps(mpmath.mp.prec)) return f0._to_mpmath(mpmath.mp.prec) return Expr._from_mpmath(mpmath.diff(eval, z0._to_mpmath(mpmath.mp.prec)), mpmath.mp.prec) @property def expr(self): return self._args[0] @property def _wrt_variables(self): # return the variables of differentiation without # respect to the type of count (int or symbolic) return [i[0] for i in self.variable_count] @property def variables(self): # TODO: deprecate? YES, make this 'enumerated_variables' and # name _wrt_variables as variables # TODO: support for `d^n`? rv = [] for v, count in self.variable_count: if not count.is_Integer: raise TypeError(filldedent(''' Cannot give expansion for symbolic count. If you just want a list of all variables of differentiation, use _wrt_variables.''')) rv.extend([v]*count) return tuple(rv) @property def variable_count(self): return self._args[1:] @property def derivative_count(self): return sum([count for var, count in self.variable_count], 0) @property def free_symbols(self): ret = self.expr.free_symbols # Add symbolic counts to free_symbols for var, count in self.variable_count: ret.update(count.free_symbols) return ret @property def kind(self): return self.args[0].kind def _eval_subs(self, old, new): # The substitution (old, new) cannot be done inside # Derivative(expr, vars) for a variety of reasons # as handled below. if old in self._wrt_variables: # first handle the counts expr = self.func(self.expr, *[(v, c.subs(old, new)) for v, c in self.variable_count]) if expr != self: return expr._eval_subs(old, new) # quick exit case if not getattr(new, '_diff_wrt', False): # case (0): new is not a valid variable of # differentiation if isinstance(old, Symbol): # don't introduce a new symbol if the old will do return Subs(self, old, new) else: xi = Dummy('xi') return Subs(self.xreplace({old: xi}), xi, new) # If both are Derivatives with the same expr, check if old is # equivalent to self or if old is a subderivative of self. if old.is_Derivative and old.expr == self.expr: if self.canonical == old.canonical: return new # collections.Counter doesn't have __le__ def _subset(a, b): return all((a[i] <= b[i]) == True for i in a) old_vars = Counter(dict(reversed(old.variable_count))) self_vars = Counter(dict(reversed(self.variable_count))) if _subset(old_vars, self_vars): return _derivative_dispatch(new, *(self_vars - old_vars).items()).canonical args = list(self.args) newargs = list(x._subs(old, new) for x in args) if args[0] == old: # complete replacement of self.expr # we already checked that the new is valid so we know # it won't be a problem should it appear in variables return _derivative_dispatch(*newargs) if newargs[0] != args[0]: # case (1) can't change expr by introducing something that is in # the _wrt_variables if it was already in the expr # e.g. # for Derivative(f(x, g(y)), y), x cannot be replaced with # anything that has y in it; for f(g(x), g(y)).diff(g(y)) # g(x) cannot be replaced with anything that has g(y) syms = {vi: Dummy() for vi in self._wrt_variables if not vi.is_Symbol} wrt = {syms.get(vi, vi) for vi in self._wrt_variables} forbidden = args[0].xreplace(syms).free_symbols & wrt nfree = new.xreplace(syms).free_symbols ofree = old.xreplace(syms).free_symbols if (nfree - ofree) & forbidden: return Subs(self, old, new) viter = ((i, j) for ((i, _), (j, _)) in zip(newargs[1:], args[1:])) if any(i != j for i, j in viter): # a wrt-variable change # case (2) can't change vars by introducing a variable # that is contained in expr, e.g. # for Derivative(f(z, g(h(x), y)), y), y cannot be changed to # x, h(x), or g(h(x), y) for a in _atomic(self.expr, recursive=True): for i in range(1, len(newargs)): vi, _ = newargs[i] if a == vi and vi != args[i][0]: return Subs(self, old, new) # more arg-wise checks vc = newargs[1:] oldv = self._wrt_variables newe = self.expr subs = [] for i, (vi, ci) in enumerate(vc): if not vi._diff_wrt: # case (3) invalid differentiation expression so # create a replacement dummy xi = Dummy('xi_%i' % i) # replace the old valid variable with the dummy # in the expression newe = newe.xreplace({oldv[i]: xi}) # and replace the bad variable with the dummy vc[i] = (xi, ci) # and record the dummy with the new (invalid) # differentiation expression subs.append((xi, vi)) if subs: # handle any residual substitution in the expression newe = newe._subs(old, new) # return the Subs-wrapped derivative return Subs(Derivative(newe, *vc), *zip(*subs)) # everything was ok return _derivative_dispatch(*newargs) def _eval_lseries(self, x, logx, cdir=0): dx = self.variables for term in self.expr.lseries(x, logx=logx, cdir=cdir): yield self.func(term, *dx) def _eval_nseries(self, x, n, logx, cdir=0): arg = self.expr.nseries(x, n=n, logx=logx) o = arg.getO() dx = self.variables rv = [self.func(a, *dx) for a in Add.make_args(arg.removeO())] if o: rv.append(o/x) return Add(*rv) def _eval_as_leading_term(self, x, logx=None, cdir=0): series_gen = self.expr.lseries(x) d = S.Zero for leading_term in series_gen: d = diff(leading_term, *self.variables) if d != 0: break return d def as_finite_difference(self, points=1, x0=None, wrt=None): """ Expresses a Derivative instance as a finite difference. Parameters ========== points : sequence or coefficient, optional If sequence: discrete values (length >= order+1) of the independent variable used for generating the finite difference weights. If it is a coefficient, it will be used as the step-size for generating an equidistant sequence of length order+1 centered around ``x0``. Default: 1 (step-size 1) x0 : number or Symbol, optional the value of the independent variable (``wrt``) at which the derivative is to be approximated. Default: same as ``wrt``. wrt : Symbol, optional "with respect to" the variable for which the (partial) derivative is to be approximated for. If not provided it is required that the derivative is ordinary. Default: ``None``. Examples ======== >>> from sympy import symbols, Function, exp, sqrt, Symbol >>> x, h = symbols('x h') >>> f = Function('f') >>> f(x).diff(x).as_finite_difference() -f(x - 1/2) + f(x + 1/2) The default step size and number of points are 1 and ``order + 1`` respectively. We can change the step size by passing a symbol as a parameter: >>> f(x).diff(x).as_finite_difference(h) -f(-h/2 + x)/h + f(h/2 + x)/h We can also specify the discretized values to be used in a sequence: >>> f(x).diff(x).as_finite_difference([x, x+h, x+2*h]) -3*f(x)/(2*h) + 2*f(h + x)/h - f(2*h + x)/(2*h) The algorithm is not restricted to use equidistant spacing, nor do we need to make the approximation around ``x0``, but we can get an expression estimating the derivative at an offset: >>> e, sq2 = exp(1), sqrt(2) >>> xl = [x-h, x+h, x+e*h] >>> f(x).diff(x, 1).as_finite_difference(xl, x+h*sq2) # doctest: +ELLIPSIS 2*h*((h + sqrt(2)*h)/(2*h) - (-sqrt(2)*h + h)/(2*h))*f(E*h + x)/... To approximate ``Derivative`` around ``x0`` using a non-equidistant spacing step, the algorithm supports assignment of undefined functions to ``points``: >>> dx = Function('dx') >>> f(x).diff(x).as_finite_difference(points=dx(x), x0=x-h) -f(-h + x - dx(-h + x)/2)/dx(-h + x) + f(-h + x + dx(-h + x)/2)/dx(-h + x) Partial derivatives are also supported: >>> y = Symbol('y') >>> d2fdxdy=f(x,y).diff(x,y) >>> d2fdxdy.as_finite_difference(wrt=x) -Derivative(f(x - 1/2, y), y) + Derivative(f(x + 1/2, y), y) We can apply ``as_finite_difference`` to ``Derivative`` instances in compound expressions using ``replace``: >>> (1 + 42**f(x).diff(x)).replace(lambda arg: arg.is_Derivative, ... lambda arg: arg.as_finite_difference()) 42**(-f(x - 1/2) + f(x + 1/2)) + 1 See also ======== sympy.calculus.finite_diff.apply_finite_diff sympy.calculus.finite_diff.differentiate_finite sympy.calculus.finite_diff.finite_diff_weights """ from ..calculus.finite_diff import _as_finite_diff return _as_finite_diff(self, points, x0, wrt) @classmethod def _get_zero_with_shape_like(cls, expr): return S.Zero @classmethod def _dispatch_eval_derivative_n_times(cls, expr, v, count): # Evaluate the derivative `n` times. If # `_eval_derivative_n_times` is not overridden by the current # object, the default in `Basic` will call a loop over # `_eval_derivative`: return expr._eval_derivative_n_times(v, count) def _derivative_dispatch(expr, *variables, **kwargs): from sympy.matrices.common import MatrixCommon from sympy import MatrixExpr from sympy import NDimArray array_types = (MatrixCommon, MatrixExpr, NDimArray, list, tuple, Tuple) if isinstance(expr, array_types) or any(isinstance(i[0], array_types) if isinstance(i, (tuple, list, Tuple)) else isinstance(i, array_types) for i in variables): from sympy.tensor.array.array_derivatives import ArrayDerivative return ArrayDerivative(expr, *variables, **kwargs) return Derivative(expr, *variables, **kwargs) class Lambda(Expr): """ Lambda(x, expr) represents a lambda function similar to Python's 'lambda x: expr'. A function of several variables is written as Lambda((x, y, ...), expr). Examples ======== A simple example: >>> from sympy import Lambda >>> from sympy.abc import x >>> f = Lambda(x, x**2) >>> f(4) 16 For multivariate functions, use: >>> from sympy.abc import y, z, t >>> f2 = Lambda((x, y, z, t), x + y**z + t**z) >>> f2(1, 2, 3, 4) 73 It is also possible to unpack tuple arguments: >>> f = Lambda( ((x, y), z) , x + y + z) >>> f((1, 2), 3) 6 A handy shortcut for lots of arguments: >>> p = x, y, z >>> f = Lambda(p, x + y*z) >>> f(*p) x + y*z """ is_Function = True def __new__(cls, signature, expr): if iterable(signature) and not isinstance(signature, (tuple, Tuple)): SymPyDeprecationWarning( feature="non tuple iterable of argument symbols to Lambda", useinstead="tuple of argument symbols", issue=17474, deprecated_since_version="1.5").warn() signature = tuple(signature) sig = signature if iterable(signature) else (signature,) sig = sympify(sig) cls._check_signature(sig) if len(sig) == 1 and sig[0] == expr: return S.IdentityFunction return Expr.__new__(cls, sig, sympify(expr)) @classmethod def _check_signature(cls, sig): syms = set() def rcheck(args): for a in args: if a.is_symbol: if a in syms: raise BadSignatureError("Duplicate symbol %s" % a) syms.add(a) elif isinstance(a, Tuple): rcheck(a) else: raise BadSignatureError("Lambda signature should be only tuples" " and symbols, not %s" % a) if not isinstance(sig, Tuple): raise BadSignatureError("Lambda signature should be a tuple not %s" % sig) # Recurse through the signature: rcheck(sig) @property def signature(self): """The expected form of the arguments to be unpacked into variables""" return self._args[0] @property def expr(self): """The return value of the function""" return self._args[1] @property def variables(self): """The variables used in the internal representation of the function""" def _variables(args): if isinstance(args, Tuple): for arg in args: yield from _variables(arg) else: yield args return tuple(_variables(self.signature)) @property def nargs(self): from sympy.sets.sets import FiniteSet return FiniteSet(len(self.signature)) bound_symbols = variables @property def free_symbols(self): return self.expr.free_symbols - set(self.variables) def __call__(self, *args): n = len(args) if n not in self.nargs: # Lambda only ever has 1 value in nargs # XXX: exception message must be in exactly this format to # make it work with NumPy's functions like vectorize(). See, # for example, https://github.com/numpy/numpy/issues/1697. # The ideal solution would be just to attach metadata to # the exception and change NumPy to take advantage of this. ## XXX does this apply to Lambda? If not, remove this comment. temp = ('%(name)s takes exactly %(args)s ' 'argument%(plural)s (%(given)s given)') raise BadArgumentsError(temp % { 'name': self, 'args': list(self.nargs)[0], 'plural': 's'*(list(self.nargs)[0] != 1), 'given': n}) d = self._match_signature(self.signature, args) return self.expr.xreplace(d) def _match_signature(self, sig, args): symargmap = {} def rmatch(pars, args): for par, arg in zip(pars, args): if par.is_symbol: symargmap[par] = arg elif isinstance(par, Tuple): if not isinstance(arg, (tuple, Tuple)) or len(args) != len(pars): raise BadArgumentsError("Can't match %s and %s" % (args, pars)) rmatch(par, arg) rmatch(sig, args) return symargmap @property def is_identity(self): """Return ``True`` if this ``Lambda`` is an identity function. """ return self.signature == self.expr def _eval_evalf(self, prec): from sympy.core.evalf import prec_to_dps return self.func(self.args[0], self.args[1].evalf(n=prec_to_dps(prec))) class Subs(Expr): """ Represents unevaluated substitutions of an expression. ``Subs(expr, x, x0)`` represents the expression resulting from substituting x with x0 in expr. Parameters ========== expr : Expr An expression. x : tuple, variable A variable or list of distinct variables. x0 : tuple or list of tuples A point or list of evaluation points corresponding to those variables. Notes ===== ``Subs`` objects are generally useful to represent unevaluated derivatives calculated at a point. The variables may be expressions, but they are subjected to the limitations of subs(), so it is usually a good practice to use only symbols for variables, since in that case there can be no ambiguity. There's no automatic expansion - use the method .doit() to effect all possible substitutions of the object and also of objects inside the expression. When evaluating derivatives at a point that is not a symbol, a Subs object is returned. One is also able to calculate derivatives of Subs objects - in this case the expression is always expanded (for the unevaluated form, use Derivative()). Examples ======== >>> from sympy import Subs, Function, sin, cos >>> from sympy.abc import x, y, z >>> f = Function('f') Subs are created when a particular substitution cannot be made. The x in the derivative cannot be replaced with 0 because 0 is not a valid variables of differentiation: >>> f(x).diff(x).subs(x, 0) Subs(Derivative(f(x), x), x, 0) Once f is known, the derivative and evaluation at 0 can be done: >>> _.subs(f, sin).doit() == sin(x).diff(x).subs(x, 0) == cos(0) True Subs can also be created directly with one or more variables: >>> Subs(f(x)*sin(y) + z, (x, y), (0, 1)) Subs(z + f(x)*sin(y), (x, y), (0, 1)) >>> _.doit() z + f(0)*sin(1) Notes ===== In order to allow expressions to combine before doit is done, a representation of the Subs expression is used internally to make expressions that are superficially different compare the same: >>> a, b = Subs(x, x, 0), Subs(y, y, 0) >>> a + b 2*Subs(x, x, 0) This can lead to unexpected consequences when using methods like `has` that are cached: >>> s = Subs(x, x, 0) >>> s.has(x), s.has(y) (True, False) >>> ss = s.subs(x, y) >>> ss.has(x), ss.has(y) (True, False) >>> s, ss (Subs(x, x, 0), Subs(y, y, 0)) """ def __new__(cls, expr, variables, point, **assumptions): from sympy import Symbol if not is_sequence(variables, Tuple): variables = [variables] variables = Tuple(*variables) if has_dups(variables): repeated = [str(v) for v, i in Counter(variables).items() if i > 1] __ = ', '.join(repeated) raise ValueError(filldedent(''' The following expressions appear more than once: %s ''' % __)) point = Tuple(*(point if is_sequence(point, Tuple) else [point])) if len(point) != len(variables): raise ValueError('Number of point values must be the same as ' 'the number of variables.') if not point: return sympify(expr) # denest if isinstance(expr, Subs): variables = expr.variables + variables point = expr.point + point expr = expr.expr else: expr = sympify(expr) # use symbols with names equal to the point value (with prepended _) # to give a variable-independent expression pre = "_" pts = sorted(set(point), key=default_sort_key) from sympy.printing import StrPrinter class CustomStrPrinter(StrPrinter): def _print_Dummy(self, expr): return str(expr) + str(expr.dummy_index) def mystr(expr, **settings): p = CustomStrPrinter(settings) return p.doprint(expr) while 1: s_pts = {p: Symbol(pre + mystr(p)) for p in pts} reps = [(v, s_pts[p]) for v, p in zip(variables, point)] # if any underscore-prepended symbol is already a free symbol # and is a variable with a different point value, then there # is a clash, e.g. _0 clashes in Subs(_0 + _1, (_0, _1), (1, 0)) # because the new symbol that would be created is _1 but _1 # is already mapped to 0 so __0 and __1 are used for the new # symbols if any(r in expr.free_symbols and r in variables and Symbol(pre + mystr(point[variables.index(r)])) != r for _, r in reps): pre += "_" continue break obj = Expr.__new__(cls, expr, Tuple(*variables), point) obj._expr = expr.xreplace(dict(reps)) return obj def _eval_is_commutative(self): return self.expr.is_commutative def doit(self, **hints): e, v, p = self.args # remove self mappings for i, (vi, pi) in enumerate(zip(v, p)): if vi == pi: v = v[:i] + v[i + 1:] p = p[:i] + p[i + 1:] if not v: return self.expr if isinstance(e, Derivative): # apply functions first, e.g. f -> cos undone = [] for i, vi in enumerate(v): if isinstance(vi, FunctionClass): e = e.subs(vi, p[i]) else: undone.append((vi, p[i])) if not isinstance(e, Derivative): e = e.doit() if isinstance(e, Derivative): # do Subs that aren't related to differentiation undone2 = [] D = Dummy() arg = e.args[0] for vi, pi in undone: if D not in e.xreplace({vi: D}).free_symbols: if arg.has(vi): e = e.subs(vi, pi) else: undone2.append((vi, pi)) undone = undone2 # differentiate wrt variables that are present wrt = [] D = Dummy() expr = e.expr free = expr.free_symbols for vi, ci in e.variable_count: if isinstance(vi, Symbol) and vi in free: expr = expr.diff((vi, ci)) elif D in expr.subs(vi, D).free_symbols: expr = expr.diff((vi, ci)) else: wrt.append((vi, ci)) # inject remaining subs rv = expr.subs(undone) # do remaining differentiation *in order given* for vc in wrt: rv = rv.diff(vc) else: # inject remaining subs rv = e.subs(undone) else: rv = e.doit(**hints).subs(list(zip(v, p))) if hints.get('deep', True) and rv != self: rv = rv.doit(**hints) return rv def evalf(self, prec=None, **options): return self.doit().evalf(prec, **options) n = evalf @property def variables(self): """The variables to be evaluated""" return self._args[1] bound_symbols = variables @property def expr(self): """The expression on which the substitution operates""" return self._args[0] @property def point(self): """The values for which the variables are to be substituted""" return self._args[2] @property def free_symbols(self): return (self.expr.free_symbols - set(self.variables) | set(self.point.free_symbols)) @property def expr_free_symbols(self): from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning(feature="expr_free_symbols method", issue=21494, deprecated_since_version="1.9").warn() return (self.expr.expr_free_symbols - set(self.variables) | set(self.point.expr_free_symbols)) def __eq__(self, other): if not isinstance(other, Subs): return False return self._hashable_content() == other._hashable_content() def __ne__(self, other): return not(self == other) def __hash__(self): return super().__hash__() def _hashable_content(self): return (self._expr.xreplace(self.canonical_variables), ) + tuple(ordered([(v, p) for v, p in zip(self.variables, self.point) if not self.expr.has(v)])) def _eval_subs(self, old, new): # Subs doit will do the variables in order; the semantics # of subs for Subs is have the following invariant for # Subs object foo: # foo.doit().subs(reps) == foo.subs(reps).doit() pt = list(self.point) if old in self.variables: if _atomic(new) == {new} and not any( i.has(new) for i in self.args): # the substitution is neutral return self.xreplace({old: new}) # any occurrence of old before this point will get # handled by replacements from here on i = self.variables.index(old) for j in range(i, len(self.variables)): pt[j] = pt[j]._subs(old, new) return self.func(self.expr, self.variables, pt) v = [i._subs(old, new) for i in self.variables] if v != list(self.variables): return self.func(self.expr, self.variables + (old,), pt + [new]) expr = self.expr._subs(old, new) pt = [i._subs(old, new) for i in self.point] return self.func(expr, v, pt) def _eval_derivative(self, s): # Apply the chain rule of the derivative on the substitution variables: f = self.expr vp = V, P = self.variables, self.point val = Add.fromiter(p.diff(s)*Subs(f.diff(v), *vp).doit() for v, p in zip(V, P)) # these are all the free symbols in the expr efree = f.free_symbols # some symbols like IndexedBase include themselves and args # as free symbols compound = {i for i in efree if len(i.free_symbols) > 1} # hide them and see what independent free symbols remain dums = {Dummy() for i in compound} masked = f.xreplace(dict(zip(compound, dums))) ifree = masked.free_symbols - dums # include the compound symbols free = ifree | compound # remove the variables already handled free -= set(V) # add back any free symbols of remaining compound symbols free |= {i for j in free & compound for i in j.free_symbols} # if symbols of s are in free then there is more to do if free & s.free_symbols: val += Subs(f.diff(s), self.variables, self.point).doit() return val def _eval_nseries(self, x, n, logx, cdir=0): if x in self.point: # x is the variable being substituted into apos = self.point.index(x) other = self.variables[apos] else: other = x arg = self.expr.nseries(other, n=n, logx=logx) o = arg.getO() terms = Add.make_args(arg.removeO()) rv = Add(*[self.func(a, *self.args[1:]) for a in terms]) if o: rv += o.subs(other, x) return rv def _eval_as_leading_term(self, x, logx=None, cdir=0): if x in self.point: ipos = self.point.index(x) xvar = self.variables[ipos] return self.expr.as_leading_term(xvar) if x in self.variables: # if `x` is a dummy variable, it means it won't exist after the # substitution has been performed: return self # The variable is independent of the substitution: return self.expr.as_leading_term(x) def diff(f, *symbols, **kwargs): """ Differentiate f with respect to symbols. Explanation =========== This is just a wrapper to unify .diff() and the Derivative class; its interface is similar to that of integrate(). You can use the same shortcuts for multiple variables as with Derivative. For example, diff(f(x), x, x, x) and diff(f(x), x, 3) both return the third derivative of f(x). You can pass evaluate=False to get an unevaluated Derivative class. Note that if there are 0 symbols (such as diff(f(x), x, 0), then the result will be the function (the zeroth derivative), even if evaluate=False. Examples ======== >>> from sympy import sin, cos, Function, diff >>> from sympy.abc import x, y >>> f = Function('f') >>> diff(sin(x), x) cos(x) >>> diff(f(x), x, x, x) Derivative(f(x), (x, 3)) >>> diff(f(x), x, 3) Derivative(f(x), (x, 3)) >>> diff(sin(x)*cos(y), x, 2, y, 2) sin(x)*cos(y) >>> type(diff(sin(x), x)) cos >>> type(diff(sin(x), x, evaluate=False)) >>> type(diff(sin(x), x, 0)) sin >>> type(diff(sin(x), x, 0, evaluate=False)) sin >>> diff(sin(x)) cos(x) >>> diff(sin(x*y)) Traceback (most recent call last): ... ValueError: specify differentiation variables to differentiate sin(x*y) Note that ``diff(sin(x))`` syntax is meant only for convenience in interactive sessions and should be avoided in library code. References ========== http://reference.wolfram.com/legacy/v5_2/Built-inFunctions/AlgebraicComputation/Calculus/D.html See Also ======== Derivative idiff: computes the derivative implicitly """ if hasattr(f, 'diff'): return f.diff(*symbols, **kwargs) kwargs.setdefault('evaluate', True) return _derivative_dispatch(f, *symbols, **kwargs) def expand(e, deep=True, modulus=None, power_base=True, power_exp=True, mul=True, log=True, multinomial=True, basic=True, **hints): r""" Expand an expression using methods given as hints. Explanation =========== Hints evaluated unless explicitly set to False are: ``basic``, ``log``, ``multinomial``, ``mul``, ``power_base``, and ``power_exp`` The following hints are supported but not applied unless set to True: ``complex``, ``func``, and ``trig``. In addition, the following meta-hints are supported by some or all of the other hints: ``frac``, ``numer``, ``denom``, ``modulus``, and ``force``. ``deep`` is supported by all hints. Additionally, subclasses of Expr may define their own hints or meta-hints. The ``basic`` hint is used for any special rewriting of an object that should be done automatically (along with the other hints like ``mul``) when expand is called. This is a catch-all hint to handle any sort of expansion that may not be described by the existing hint names. To use this hint an object should override the ``_eval_expand_basic`` method. Objects may also define their own expand methods, which are not run by default. See the API section below. If ``deep`` is set to ``True`` (the default), things like arguments of functions are recursively expanded. Use ``deep=False`` to only expand on the top level. If the ``force`` hint is used, assumptions about variables will be ignored in making the expansion. Hints ===== These hints are run by default mul --- Distributes multiplication over addition: >>> from sympy import cos, exp, sin >>> from sympy.abc import x, y, z >>> (y*(x + z)).expand(mul=True) x*y + y*z multinomial ----------- Expand (x + y + ...)**n where n is a positive integer. >>> ((x + y + z)**2).expand(multinomial=True) x**2 + 2*x*y + 2*x*z + y**2 + 2*y*z + z**2 power_exp --------- Expand addition in exponents into multiplied bases. >>> exp(x + y).expand(power_exp=True) exp(x)*exp(y) >>> (2**(x + y)).expand(power_exp=True) 2**x*2**y power_base ---------- Split powers of multiplied bases. This only happens by default if assumptions allow, or if the ``force`` meta-hint is used: >>> ((x*y)**z).expand(power_base=True) (x*y)**z >>> ((x*y)**z).expand(power_base=True, force=True) x**z*y**z >>> ((2*y)**z).expand(power_base=True) 2**z*y**z Note that in some cases where this expansion always holds, SymPy performs it automatically: >>> (x*y)**2 x**2*y**2 log --- Pull out power of an argument as a coefficient and split logs products into sums of logs. Note that these only work if the arguments of the log function have the proper assumptions--the arguments must be positive and the exponents must be real--or else the ``force`` hint must be True: >>> from sympy import log, symbols >>> log(x**2*y).expand(log=True) log(x**2*y) >>> log(x**2*y).expand(log=True, force=True) 2*log(x) + log(y) >>> x, y = symbols('x,y', positive=True) >>> log(x**2*y).expand(log=True) 2*log(x) + log(y) basic ----- This hint is intended primarily as a way for custom subclasses to enable expansion by default. These hints are not run by default: complex ------- Split an expression into real and imaginary parts. >>> x, y = symbols('x,y') >>> (x + y).expand(complex=True) re(x) + re(y) + I*im(x) + I*im(y) >>> cos(x).expand(complex=True) -I*sin(re(x))*sinh(im(x)) + cos(re(x))*cosh(im(x)) Note that this is just a wrapper around ``as_real_imag()``. Most objects that wish to redefine ``_eval_expand_complex()`` should consider redefining ``as_real_imag()`` instead. func ---- Expand other functions. >>> from sympy import gamma >>> gamma(x + 1).expand(func=True) x*gamma(x) trig ---- Do trigonometric expansions. >>> cos(x + y).expand(trig=True) -sin(x)*sin(y) + cos(x)*cos(y) >>> sin(2*x).expand(trig=True) 2*sin(x)*cos(x) Note that the forms of ``sin(n*x)`` and ``cos(n*x)`` in terms of ``sin(x)`` and ``cos(x)`` are not unique, due to the identity `\sin^2(x) + \cos^2(x) = 1`. The current implementation uses the form obtained from Chebyshev polynomials, but this may change. See `this MathWorld article `_ for more information. Notes ===== - You can shut off unwanted methods:: >>> (exp(x + y)*(x + y)).expand() x*exp(x)*exp(y) + y*exp(x)*exp(y) >>> (exp(x + y)*(x + y)).expand(power_exp=False) x*exp(x + y) + y*exp(x + y) >>> (exp(x + y)*(x + y)).expand(mul=False) (x + y)*exp(x)*exp(y) - Use deep=False to only expand on the top level:: >>> exp(x + exp(x + y)).expand() exp(x)*exp(exp(x)*exp(y)) >>> exp(x + exp(x + y)).expand(deep=False) exp(x)*exp(exp(x + y)) - Hints are applied in an arbitrary, but consistent order (in the current implementation, they are applied in alphabetical order, except multinomial comes before mul, but this may change). Because of this, some hints may prevent expansion by other hints if they are applied first. For example, ``mul`` may distribute multiplications and prevent ``log`` and ``power_base`` from expanding them. Also, if ``mul`` is applied before ``multinomial`, the expression might not be fully distributed. The solution is to use the various ``expand_hint`` helper functions or to use ``hint=False`` to this function to finely control which hints are applied. Here are some examples:: >>> from sympy import expand, expand_mul, expand_power_base >>> x, y, z = symbols('x,y,z', positive=True) >>> expand(log(x*(y + z))) log(x) + log(y + z) Here, we see that ``log`` was applied before ``mul``. To get the mul expanded form, either of the following will work:: >>> expand_mul(log(x*(y + z))) log(x*y + x*z) >>> expand(log(x*(y + z)), log=False) log(x*y + x*z) A similar thing can happen with the ``power_base`` hint:: >>> expand((x*(y + z))**x) (x*y + x*z)**x To get the ``power_base`` expanded form, either of the following will work:: >>> expand((x*(y + z))**x, mul=False) x**x*(y + z)**x >>> expand_power_base((x*(y + z))**x) x**x*(y + z)**x >>> expand((x + y)*y/x) y + y**2/x The parts of a rational expression can be targeted:: >>> expand((x + y)*y/x/(x + 1), frac=True) (x*y + y**2)/(x**2 + x) >>> expand((x + y)*y/x/(x + 1), numer=True) (x*y + y**2)/(x*(x + 1)) >>> expand((x + y)*y/x/(x + 1), denom=True) y*(x + y)/(x**2 + x) - The ``modulus`` meta-hint can be used to reduce the coefficients of an expression post-expansion:: >>> expand((3*x + 1)**2) 9*x**2 + 6*x + 1 >>> expand((3*x + 1)**2, modulus=5) 4*x**2 + x + 1 - Either ``expand()`` the function or ``.expand()`` the method can be used. Both are equivalent:: >>> expand((x + 1)**2) x**2 + 2*x + 1 >>> ((x + 1)**2).expand() x**2 + 2*x + 1 API === Objects can define their own expand hints by defining ``_eval_expand_hint()``. The function should take the form:: def _eval_expand_hint(self, **hints): # Only apply the method to the top-level expression ... See also the example below. Objects should define ``_eval_expand_hint()`` methods only if ``hint`` applies to that specific object. The generic ``_eval_expand_hint()`` method defined in Expr will handle the no-op case. Each hint should be responsible for expanding that hint only. Furthermore, the expansion should be applied to the top-level expression only. ``expand()`` takes care of the recursion that happens when ``deep=True``. You should only call ``_eval_expand_hint()`` methods directly if you are 100% sure that the object has the method, as otherwise you are liable to get unexpected ``AttributeError``s. Note, again, that you do not need to recursively apply the hint to args of your object: this is handled automatically by ``expand()``. ``_eval_expand_hint()`` should generally not be used at all outside of an ``_eval_expand_hint()`` method. If you want to apply a specific expansion from within another method, use the public ``expand()`` function, method, or ``expand_hint()`` functions. In order for expand to work, objects must be rebuildable by their args, i.e., ``obj.func(*obj.args) == obj`` must hold. Expand methods are passed ``**hints`` so that expand hints may use 'metahints'--hints that control how different expand methods are applied. For example, the ``force=True`` hint described above that causes ``expand(log=True)`` to ignore assumptions is such a metahint. The ``deep`` meta-hint is handled exclusively by ``expand()`` and is not passed to ``_eval_expand_hint()`` methods. Note that expansion hints should generally be methods that perform some kind of 'expansion'. For hints that simply rewrite an expression, use the .rewrite() API. Examples ======== >>> from sympy import Expr, sympify >>> class MyClass(Expr): ... def __new__(cls, *args): ... args = sympify(args) ... return Expr.__new__(cls, *args) ... ... def _eval_expand_double(self, *, force=False, **hints): ... ''' ... Doubles the args of MyClass. ... ... If there more than four args, doubling is not performed, ... unless force=True is also used (False by default). ... ''' ... if not force and len(self.args) > 4: ... return self ... return self.func(*(self.args + self.args)) ... >>> a = MyClass(1, 2, MyClass(3, 4)) >>> a MyClass(1, 2, MyClass(3, 4)) >>> a.expand(double=True) MyClass(1, 2, MyClass(3, 4, 3, 4), 1, 2, MyClass(3, 4, 3, 4)) >>> a.expand(double=True, deep=False) MyClass(1, 2, MyClass(3, 4), 1, 2, MyClass(3, 4)) >>> b = MyClass(1, 2, 3, 4, 5) >>> b.expand(double=True) MyClass(1, 2, 3, 4, 5) >>> b.expand(double=True, force=True) MyClass(1, 2, 3, 4, 5, 1, 2, 3, 4, 5) See Also ======== expand_log, expand_mul, expand_multinomial, expand_complex, expand_trig, expand_power_base, expand_power_exp, expand_func, sympy.simplify.hyperexpand.hyperexpand """ # don't modify this; modify the Expr.expand method hints['power_base'] = power_base hints['power_exp'] = power_exp hints['mul'] = mul hints['log'] = log hints['multinomial'] = multinomial hints['basic'] = basic return sympify(e).expand(deep=deep, modulus=modulus, **hints) # This is a special application of two hints def _mexpand(expr, recursive=False): # expand multinomials and then expand products; this may not always # be sufficient to give a fully expanded expression (see # test_issue_8247_8354 in test_arit) if expr is None: return was = None while was != expr: was, expr = expr, expand_mul(expand_multinomial(expr)) if not recursive: break return expr # These are simple wrappers around single hints. def expand_mul(expr, deep=True): """ Wrapper around expand that only uses the mul hint. See the expand docstring for more information. Examples ======== >>> from sympy import symbols, expand_mul, exp, log >>> x, y = symbols('x,y', positive=True) >>> expand_mul(exp(x+y)*(x+y)*log(x*y**2)) x*exp(x + y)*log(x*y**2) + y*exp(x + y)*log(x*y**2) """ return sympify(expr).expand(deep=deep, mul=True, power_exp=False, power_base=False, basic=False, multinomial=False, log=False) def expand_multinomial(expr, deep=True): """ Wrapper around expand that only uses the multinomial hint. See the expand docstring for more information. Examples ======== >>> from sympy import symbols, expand_multinomial, exp >>> x, y = symbols('x y', positive=True) >>> expand_multinomial((x + exp(x + 1))**2) x**2 + 2*x*exp(x + 1) + exp(2*x + 2) """ return sympify(expr).expand(deep=deep, mul=False, power_exp=False, power_base=False, basic=False, multinomial=True, log=False) def expand_log(expr, deep=True, force=False, factor=False): """ Wrapper around expand that only uses the log hint. See the expand docstring for more information. Examples ======== >>> from sympy import symbols, expand_log, exp, log >>> x, y = symbols('x,y', positive=True) >>> expand_log(exp(x+y)*(x+y)*log(x*y**2)) (x + y)*(log(x) + 2*log(y))*exp(x + y) """ from sympy import Mul, log if factor is False: def _handle(x): x1 = expand_mul(expand_log(x, deep=deep, force=force, factor=True)) if x1.count(log) <= x.count(log): return x1 return x expr = expr.replace( lambda x: x.is_Mul and all(any(isinstance(i, log) and i.args[0].is_Rational for i in Mul.make_args(j)) for j in x.as_numer_denom()), lambda x: _handle(x)) return sympify(expr).expand(deep=deep, log=True, mul=False, power_exp=False, power_base=False, multinomial=False, basic=False, force=force, factor=factor) def expand_func(expr, deep=True): """ Wrapper around expand that only uses the func hint. See the expand docstring for more information. Examples ======== >>> from sympy import expand_func, gamma >>> from sympy.abc import x >>> expand_func(gamma(x + 2)) x*(x + 1)*gamma(x) """ return sympify(expr).expand(deep=deep, func=True, basic=False, log=False, mul=False, power_exp=False, power_base=False, multinomial=False) def expand_trig(expr, deep=True): """ Wrapper around expand that only uses the trig hint. See the expand docstring for more information. Examples ======== >>> from sympy import expand_trig, sin >>> from sympy.abc import x, y >>> expand_trig(sin(x+y)*(x+y)) (x + y)*(sin(x)*cos(y) + sin(y)*cos(x)) """ return sympify(expr).expand(deep=deep, trig=True, basic=False, log=False, mul=False, power_exp=False, power_base=False, multinomial=False) def expand_complex(expr, deep=True): """ Wrapper around expand that only uses the complex hint. See the expand docstring for more information. Examples ======== >>> from sympy import expand_complex, exp, sqrt, I >>> from sympy.abc import z >>> expand_complex(exp(z)) I*exp(re(z))*sin(im(z)) + exp(re(z))*cos(im(z)) >>> expand_complex(sqrt(I)) sqrt(2)/2 + sqrt(2)*I/2 See Also ======== sympy.core.expr.Expr.as_real_imag """ return sympify(expr).expand(deep=deep, complex=True, basic=False, log=False, mul=False, power_exp=False, power_base=False, multinomial=False) def expand_power_base(expr, deep=True, force=False): """ Wrapper around expand that only uses the power_base hint. A wrapper to expand(power_base=True) which separates a power with a base that is a Mul into a product of powers, without performing any other expansions, provided that assumptions about the power's base and exponent allow. deep=False (default is True) will only apply to the top-level expression. force=True (default is False) will cause the expansion to ignore assumptions about the base and exponent. When False, the expansion will only happen if the base is non-negative or the exponent is an integer. >>> from sympy.abc import x, y, z >>> from sympy import expand_power_base, sin, cos, exp >>> (x*y)**2 x**2*y**2 >>> (2*x)**y (2*x)**y >>> expand_power_base(_) 2**y*x**y >>> expand_power_base((x*y)**z) (x*y)**z >>> expand_power_base((x*y)**z, force=True) x**z*y**z >>> expand_power_base(sin((x*y)**z), deep=False) sin((x*y)**z) >>> expand_power_base(sin((x*y)**z), force=True) sin(x**z*y**z) >>> expand_power_base((2*sin(x))**y + (2*cos(x))**y) 2**y*sin(x)**y + 2**y*cos(x)**y >>> expand_power_base((2*exp(y))**x) 2**x*exp(y)**x >>> expand_power_base((2*cos(x))**y) 2**y*cos(x)**y Notice that sums are left untouched. If this is not the desired behavior, apply full ``expand()`` to the expression: >>> expand_power_base(((x+y)*z)**2) z**2*(x + y)**2 >>> (((x+y)*z)**2).expand() x**2*z**2 + 2*x*y*z**2 + y**2*z**2 >>> expand_power_base((2*y)**(1+z)) 2**(z + 1)*y**(z + 1) >>> ((2*y)**(1+z)).expand() 2*2**z*y*y**z See Also ======== expand """ return sympify(expr).expand(deep=deep, log=False, mul=False, power_exp=False, power_base=True, multinomial=False, basic=False, force=force) def expand_power_exp(expr, deep=True): """ Wrapper around expand that only uses the power_exp hint. See the expand docstring for more information. Examples ======== >>> from sympy import expand_power_exp >>> from sympy.abc import x, y >>> expand_power_exp(x**(y + 2)) x**2*x**y """ return sympify(expr).expand(deep=deep, complex=False, basic=False, log=False, mul=False, power_exp=True, power_base=False, multinomial=False) def count_ops(expr, visual=False): """ Return a representation (integer or expression) of the operations in expr. Parameters ========== expr : Expr If expr is an iterable, the sum of the op counts of the items will be returned. visual : bool, optional If ``False`` (default) then the sum of the coefficients of the visual expression will be returned. If ``True`` then the number of each type of operation is shown with the core class types (or their virtual equivalent) multiplied by the number of times they occur. Examples ======== >>> from sympy.abc import a, b, x, y >>> from sympy import sin, count_ops Although there isn't a SUB object, minus signs are interpreted as either negations or subtractions: >>> (x - y).count_ops(visual=True) SUB >>> (-x).count_ops(visual=True) NEG Here, there are two Adds and a Pow: >>> (1 + a + b**2).count_ops(visual=True) 2*ADD + POW In the following, an Add, Mul, Pow and two functions: >>> (sin(x)*x + sin(x)**2).count_ops(visual=True) ADD + MUL + POW + 2*SIN for a total of 5: >>> (sin(x)*x + sin(x)**2).count_ops(visual=False) 5 Note that "what you type" is not always what you get. The expression 1/x/y is translated by sympy into 1/(x*y) so it gives a DIV and MUL rather than two DIVs: >>> (1/x/y).count_ops(visual=True) DIV + MUL The visual option can be used to demonstrate the difference in operations for expressions in different forms. Here, the Horner representation is compared with the expanded form of a polynomial: >>> eq=x*(1 + x*(2 + x*(3 + x))) >>> count_ops(eq.expand(), visual=True) - count_ops(eq, visual=True) -MUL + 3*POW The count_ops function also handles iterables: >>> count_ops([x, sin(x), None, True, x + 2], visual=False) 2 >>> count_ops([x, sin(x), None, True, x + 2], visual=True) ADD + SIN >>> count_ops({x: sin(x), x + 2: y + 1}, visual=True) 2*ADD + SIN """ from sympy import Integral, Sum, Symbol from sympy.core.relational import Relational from sympy.simplify.radsimp import fraction from sympy.logic.boolalg import BooleanFunction from sympy.utilities.misc import func_name expr = sympify(expr) if isinstance(expr, Expr) and not expr.is_Relational: ops = [] args = [expr] NEG = Symbol('NEG') DIV = Symbol('DIV') SUB = Symbol('SUB') ADD = Symbol('ADD') EXP = Symbol('EXP') while args: a = args.pop() if a.is_Rational: #-1/3 = NEG + DIV if a is not S.One: if a.p < 0: ops.append(NEG) if a.q != 1: ops.append(DIV) continue elif a.is_Mul or a.is_MatMul: if _coeff_isneg(a): ops.append(NEG) if a.args[0] is S.NegativeOne: a = a.as_two_terms()[1] else: a = -a n, d = fraction(a) if n.is_Integer: ops.append(DIV) if n < 0: ops.append(NEG) args.append(d) continue # won't be -Mul but could be Add elif d is not S.One: if not d.is_Integer: args.append(d) ops.append(DIV) args.append(n) continue # could be -Mul elif a.is_Add or a.is_MatAdd: aargs = list(a.args) negs = 0 for i, ai in enumerate(aargs): if _coeff_isneg(ai): negs += 1 args.append(-ai) if i > 0: ops.append(SUB) else: args.append(ai) if i > 0: ops.append(ADD) if negs == len(aargs): # -x - y = NEG + SUB ops.append(NEG) elif _coeff_isneg(aargs[0]): # -x + y = SUB, but already recorded ADD ops.append(SUB - ADD) continue if a.is_Pow and a.exp is S.NegativeOne: ops.append(DIV) args.append(a.base) # won't be -Mul but could be Add continue if a == S.Exp1: ops.append(EXP) continue if a.is_Pow and a.base == S.Exp1: ops.append(EXP) args.append(a.exp) continue if a.is_Mul or isinstance(a, LatticeOp): o = Symbol(a.func.__name__.upper()) # count the args ops.append(o*(len(a.args) - 1)) elif a.args and ( a.is_Pow or a.is_Function or isinstance(a, Derivative) or isinstance(a, Integral) or isinstance(a, Sum)): # if it's not in the list above we don't # consider a.func something to count, e.g. # Tuple, MatrixSymbol, etc... o = Symbol(a.func.__name__.upper()) ops.append(o) if not a.is_Symbol: args.extend(a.args) elif isinstance(expr, Dict): ops = [count_ops(k, visual=visual) + count_ops(v, visual=visual) for k, v in expr.items()] elif iterable(expr): ops = [count_ops(i, visual=visual) for i in expr] elif isinstance(expr, (Relational, BooleanFunction)): ops = [] for arg in expr.args: ops.append(count_ops(arg, visual=True)) o = Symbol(func_name(expr, short=True).upper()) ops.append(o) elif not isinstance(expr, Basic): ops = [] else: # it's Basic not isinstance(expr, Expr): if not isinstance(expr, Basic): raise TypeError("Invalid type of expr") else: ops = [] args = [expr] while args: a = args.pop() if a.args: o = Symbol(type(a).__name__.upper()) if a.is_Boolean: ops.append(o*(len(a.args)-1)) else: ops.append(o) args.extend(a.args) if not ops: if visual: return S.Zero return 0 ops = Add(*ops) if visual: return ops if ops.is_Number: return int(ops) return sum(int((a.args or [1])[0]) for a in Add.make_args(ops)) def nfloat(expr, n=15, exponent=False, dkeys=False): """Make all Rationals in expr Floats except those in exponents (unless the exponents flag is set to True). When processing dictionaries, don't modify the keys unless ``dkeys=True``. Examples ======== >>> from sympy.core.function import nfloat >>> from sympy.abc import x, y >>> from sympy import cos, pi, sqrt >>> nfloat(x**4 + x/2 + cos(pi/3) + 1 + sqrt(y)) x**4 + 0.5*x + sqrt(y) + 1.5 >>> nfloat(x**4 + sqrt(y), exponent=True) x**4.0 + y**0.5 Container types are not modified: >>> type(nfloat((1, 2))) is tuple True """ from sympy.core.power import Pow from sympy.polys.rootoftools import RootOf from sympy import MatrixBase kw = dict(n=n, exponent=exponent, dkeys=dkeys) if isinstance(expr, MatrixBase): return expr.applyfunc(lambda e: nfloat(e, **kw)) # handling of iterable containers if iterable(expr, exclude=str): if isinstance(expr, (dict, Dict)): if dkeys: args = [tuple(map(lambda i: nfloat(i, **kw), a)) for a in expr.items()] else: args = [(k, nfloat(v, **kw)) for k, v in expr.items()] if isinstance(expr, dict): return type(expr)(args) else: return expr.func(*args) elif isinstance(expr, Basic): return expr.func(*[nfloat(a, **kw) for a in expr.args]) return type(expr)([nfloat(a, **kw) for a in expr]) rv = sympify(expr) if rv.is_Number: return Float(rv, n) elif rv.is_number: # evalf doesn't always set the precision rv = rv.n(n) if rv.is_Number: rv = Float(rv.n(n), n) else: pass # pure_complex(rv) is likely True return rv elif rv.is_Atom: return rv elif rv.is_Relational: args_nfloat = (nfloat(arg, **kw) for arg in rv.args) return rv.func(*args_nfloat) # watch out for RootOf instances that don't like to have # their exponents replaced with Dummies and also sometimes have # problems with evaluating at low precision (issue 6393) rv = rv.xreplace({ro: ro.n(n) for ro in rv.atoms(RootOf)}) if not exponent: reps = [(p, Pow(p.base, Dummy())) for p in rv.atoms(Pow)] rv = rv.xreplace(dict(reps)) rv = rv.n(n) if not exponent: rv = rv.xreplace({d.exp: p.exp for p, d in reps}) else: # Pow._eval_evalf special cases Integer exponents so if # exponent is suppose to be handled we have to do so here rv = rv.xreplace(Transform( lambda x: Pow(x.base, Float(x.exp, n)), lambda x: x.is_Pow and x.exp.is_Integer)) return rv.xreplace(Transform( lambda x: x.func(*nfloat(x.args, n, exponent)), lambda x: isinstance(x, Function))) from sympy.core.symbol import Dummy, Symbol sympy-sympy-1.9/sympy/core/kind.py000066400000000000000000000265031412543434000173410ustar00rootroot00000000000000""" Module to efficiently partition SymPy objects. This system is introduced because class of SymPy object does not always represent the mathematical classification of the entity. For example, ``Integral(1, x)`` and ``Integral(Matrix([1,2]), x)`` are both instance of ``Integral`` class. However the former is number and the latter is matrix. One way to resolve this is defining subclass for each mathematical type, such as ``MatAdd`` for the addition between matrices. Basic algebraic operation such as addition or multiplication take this approach, but defining every class for every mathematical object is not scalable. Therefore, we define the "kind" of the object and let the expression infer the kind of itself from its arguments. Function and class can filter the arguments by their kind, and behave differently according to the type of itself. This module defines basic kinds for core objects. Other kinds such as ``ArrayKind`` or ``MatrixKind`` can be found in corresponding modules. .. notes:: This approach is experimental, and can be replaced or deleted in the future. See https://github.com/sympy/sympy/pull/20549. """ from collections import defaultdict from sympy.core.cache import cacheit from sympy.multipledispatch.dispatcher import (Dispatcher, ambiguity_warn, ambiguity_register_error_ignore_dup, str_signature, RaiseNotImplementedError) class KindMeta(type): """ Metaclass for ``Kind``. Assigns empty ``dict`` as class attribute ``_inst`` for every class, in order to endow singleton-like behavior. """ def __new__(cls, clsname, bases, dct): dct['_inst'] = {} return super().__new__(cls, clsname, bases, dct) class Kind(object, metaclass=KindMeta): """ Base class for kinds. Kind of the object represents the mathematical classification that the entity falls into. It is expected that functions and classes recognize and filter the argument by its kind. Kind of every object must be carefully selected so that it shows the intention of design. Expressions may have different kind according to the kind of its arguements. For example, arguements of ``Add`` must have common kind since addition is group operator, and the resulting ``Add()`` has the same kind. For the performance, each kind is as broad as possible and is not based on set theory. For example, ``NumberKind`` includes not only complex number but expression containing ``S.Infinity`` or ``S.NaN`` which are not strictly number. Kind may have arguments as parameter. For example, ``MatrixKind()`` may be constructed with one element which represents the kind of its elements. ``Kind`` behaves in singleton-like fashion. Same signature will return the same object. """ def __new__(cls, *args): if args in cls._inst: inst = cls._inst[args] else: inst = super().__new__(cls) cls._inst[args] = inst return inst class _UndefinedKind(Kind): """ Default kind for all SymPy object. If the kind is not defined for the object, or if the object cannot infer the kind from its arguments, this will be returned. Examples ======== >>> from sympy import Expr >>> Expr().kind UndefinedKind """ def __new__(cls): return super().__new__(cls) def __repr__(self): return "UndefinedKind" UndefinedKind = _UndefinedKind() class _NumberKind(Kind): """ Kind for all numeric object. This kind represents every number, including complex numbers, infinity and ``S.NaN``. Other objects such as quaternions do not have this kind. Most ``Expr`` are initially designed to represent the number, so this will be the most common kind in SymPy core. For example ``Symbol()``, which represents a scalar, has this kind as long as it is commutative. Numbers form a field. Any operation between number-kind objects will result this kind as well. Examples ======== >>> from sympy import S, oo, Symbol >>> S.One.kind NumberKind >>> (-oo).kind NumberKind >>> S.NaN.kind NumberKind Commutative symbol are treated as number. >>> x = Symbol('x') >>> x.kind NumberKind >>> Symbol('y', commutative=False).kind UndefinedKind Operation between numbers results number. >>> (x+1).kind NumberKind See Also ======== sympy.core.expr.Expr.is_Number : check if the object is strictly subclass of ``Number`` class. sympy.core.expr.Expr.is_number : check if the object is number without any free symbol. """ def __new__(cls): return super().__new__(cls) def __repr__(self): return "NumberKind" NumberKind = _NumberKind() class _BooleanKind(Kind): """ Kind for boolean objects. SymPy's ``S.true``, ``S.false``, and built-in ``True`` and ``False`` have this kind. Boolean number ``1`` and ``0`` are not relevent. Examples ======== >>> from sympy import S, Q >>> S.true.kind BooleanKind >>> Q.even(3).kind BooleanKind """ def __new__(cls): return super().__new__(cls) def __repr__(self): return "BooleanKind" BooleanKind = _BooleanKind() class KindDispatcher: """ Dispatcher to select a kind from multiple kinds by binary dispatching. .. notes:: This approach is experimental, and can be replaced or deleted in the future. Explanation =========== SymPy object's :obj:`sympy.core.kind.Kind()` vaguely represents the algebraic structure where the object belongs to. Therefore, with given operation, we can always find a dominating kind among the different kinds. This class selects the kind by recursive binary dispatching. If the result cannot be determined, ``UndefinedKind`` is returned. Examples ======== Multiplication between numbers return number. >>> from sympy import Mul >>> from sympy.core import NumberKind >>> Mul._kind_dispatcher(NumberKind, NumberKind) NumberKind Multiplication between number and unknown-kind object returns unknown kind. >>> from sympy.core import UndefinedKind >>> Mul._kind_dispatcher(NumberKind, UndefinedKind) UndefinedKind Any number and order of kinds is allowed. >>> Mul._kind_dispatcher(UndefinedKind, NumberKind) UndefinedKind >>> Mul._kind_dispatcher(NumberKind, UndefinedKind, NumberKind) UndefinedKind Since matrix forms a vector space over scalar field, multiplication between matrix with numeric element and number returns matrix with numeric element. >>> from sympy.matrices import MatrixKind >>> Mul._kind_dispatcher(MatrixKind(NumberKind), NumberKind) MatrixKind(NumberKind) If a matrix with number element and another matrix with unknown-kind element are multiplied, we know that the result is matrix but the kind of its elements is unknown. >>> Mul._kind_dispatcher(MatrixKind(NumberKind), MatrixKind(UndefinedKind)) MatrixKind(UndefinedKind) Parameters ========== name : str commutative : bool, optional If True, binary dispatch will be automatically registered in reversed order as well. doc : str, optional """ def __init__(self, name, commutative=False, doc=None): self.name = name self.doc = doc self.commutative = commutative self._dispatcher = Dispatcher(name) def __repr__(self): return "" % self.name def register(self, *types, **kwargs): """ Register the binary dispatcher for two kind classes. If *self.commutative* is ``True``, signature in reversed order is automatically registered as well. """ on_ambiguity = kwargs.pop("on_ambiguity", None) if not on_ambiguity: if self.commutative: on_ambiguity = ambiguity_register_error_ignore_dup else: on_ambiguity = ambiguity_warn kwargs.update(on_ambiguity=on_ambiguity) if not len(types) == 2: raise RuntimeError( "Only binary dispatch is supported, but got %s types: <%s>." % ( len(types), str_signature(types) )) def _(func): self._dispatcher.add(types, func, **kwargs) if self.commutative: self._dispatcher.add(tuple(reversed(types)), func, **kwargs) return _ def __call__(self, *args, **kwargs): if self.commutative: kinds = frozenset(args) else: kinds = [] prev = None for a in args: if prev is not a: kinds.append(a) prev = a return self.dispatch_kinds(kinds, **kwargs) @cacheit def dispatch_kinds(self, kinds, **kwargs): # Quick exit for the case where all kinds are same if len(kinds) == 1: result, = kinds if not isinstance(result, Kind): raise RuntimeError("%s is not a kind." % result) return result for i,kind in enumerate(kinds): if not isinstance(kind, Kind): raise RuntimeError("%s is not a kind." % kind) if i == 0: result = kind else: prev_kind = result t1, t2 = type(prev_kind), type(kind) k1, k2 = prev_kind, kind func = self._dispatcher.dispatch(t1, t2) if func is None and self.commutative: # try reversed order func = self._dispatcher.dispatch(t2, t1) k1, k2 = k2, k1 if func is None: # unregistered kind relation result = UndefinedKind else: result = func(k1, k2) if not isinstance(result, Kind): raise RuntimeError( "Dispatcher for {!r} and {!r} must return a Kind, but got {!r}".format( prev_kind, kind, result )) return result @property def __doc__(self): docs = [ "Kind dispatcher : %s" % self.name, "Note that support for this is experimental. See the docs for :class:`KindDispatcher` for details" ] if self.doc: docs.append(self.doc) s = "Registered kind classes\n" s += '=' * len(s) docs.append(s) amb_sigs = [] typ_sigs = defaultdict(list) for sigs in self._dispatcher.ordering[::-1]: key = self._dispatcher.funcs[sigs] typ_sigs[key].append(sigs) for func, sigs in typ_sigs.items(): sigs_str = ', '.join('<%s>' % str_signature(sig) for sig in sigs) if isinstance(func, RaiseNotImplementedError): amb_sigs.append(sigs_str) continue s = 'Inputs: %s\n' % sigs_str s += '-' * len(s) + '\n' if func.__doc__: s += func.__doc__.strip() else: s += func.__name__ docs.append(s) if amb_sigs: s = "Ambiguous kind classes\n" s += '=' * len(s) docs.append(s) s = '\n'.join(amb_sigs) docs.append(s) return '\n\n'.join(docs) sympy-sympy-1.9/sympy/core/logic.py000066400000000000000000000251771412543434000175170ustar00rootroot00000000000000"""Logic expressions handling NOTE ---- at present this is mainly needed for facts.py , feel free however to improve this stuff for general purpose. """ from typing import Dict, Type, Union # Type of a fuzzy bool FuzzyBool = Union[bool, None] def _torf(args): """Return True if all args are True, False if they are all False, else None. >>> from sympy.core.logic import _torf >>> _torf((True, True)) True >>> _torf((False, False)) False >>> _torf((True, False)) """ sawT = sawF = False for a in args: if a is True: if sawF: return sawT = True elif a is False: if sawT: return sawF = True else: return return sawT def _fuzzy_group(args, quick_exit=False): """Return True if all args are True, None if there is any None else False unless ``quick_exit`` is True (then return None as soon as a second False is seen. ``_fuzzy_group`` is like ``fuzzy_and`` except that it is more conservative in returning a False, waiting to make sure that all arguments are True or False and returning None if any arguments are None. It also has the capability of permiting only a single False and returning None if more than one is seen. For example, the presence of a single transcendental amongst rationals would indicate that the group is no longer rational; but a second transcendental in the group would make the determination impossible. Examples ======== >>> from sympy.core.logic import _fuzzy_group By default, multiple Falses mean the group is broken: >>> _fuzzy_group([False, False, True]) False If multiple Falses mean the group status is unknown then set `quick_exit` to True so None can be returned when the 2nd False is seen: >>> _fuzzy_group([False, False, True], quick_exit=True) But if only a single False is seen then the group is known to be broken: >>> _fuzzy_group([False, True, True], quick_exit=True) False """ saw_other = False for a in args: if a is True: continue if a is None: return if quick_exit and saw_other: return saw_other = True return not saw_other def fuzzy_bool(x): """Return True, False or None according to x. Whereas bool(x) returns True or False, fuzzy_bool allows for the None value and non-false values (which become None), too. Examples ======== >>> from sympy.core.logic import fuzzy_bool >>> from sympy.abc import x >>> fuzzy_bool(x), fuzzy_bool(None) (None, None) >>> bool(x), bool(None) (True, False) """ if x is None: return None if x in (True, False): return bool(x) def fuzzy_and(args): """Return True (all True), False (any False) or None. Examples ======== >>> from sympy.core.logic import fuzzy_and >>> from sympy import Dummy If you had a list of objects to test the commutivity of and you want the fuzzy_and logic applied, passing an iterator will allow the commutativity to only be computed as many times as necessary. With this list, False can be returned after analyzing the first symbol: >>> syms = [Dummy(commutative=False), Dummy()] >>> fuzzy_and(s.is_commutative for s in syms) False That False would require less work than if a list of pre-computed items was sent: >>> fuzzy_and([s.is_commutative for s in syms]) False """ rv = True for ai in args: ai = fuzzy_bool(ai) if ai is False: return False if rv: # this will stop updating if a None is ever trapped rv = ai return rv def fuzzy_not(v): """ Not in fuzzy logic Return None if `v` is None else `not v`. Examples ======== >>> from sympy.core.logic import fuzzy_not >>> fuzzy_not(True) False >>> fuzzy_not(None) >>> fuzzy_not(False) True """ if v is None: return v else: return not v def fuzzy_or(args): """ Or in fuzzy logic. Returns True (any True), False (all False), or None See the docstrings of fuzzy_and and fuzzy_not for more info. fuzzy_or is related to the two by the standard De Morgan's law. >>> from sympy.core.logic import fuzzy_or >>> fuzzy_or([True, False]) True >>> fuzzy_or([True, None]) True >>> fuzzy_or([False, False]) False >>> print(fuzzy_or([False, None])) None """ rv = False for ai in args: ai = fuzzy_bool(ai) if ai is True: return True if rv is False: # this will stop updating if a None is ever trapped rv = ai return rv def fuzzy_xor(args): """Return None if any element of args is not True or False, else True (if there are an odd number of True elements), else False.""" t = f = 0 for a in args: ai = fuzzy_bool(a) if ai: t += 1 elif ai is False: f += 1 else: return return t % 2 == 1 def fuzzy_nand(args): """Return False if all args are True, True if they are all False, else None.""" return fuzzy_not(fuzzy_and(args)) class Logic: """Logical expression""" # {} 'op' -> LogicClass op_2class = {} # type: Dict[str, Type[Logic]] def __new__(cls, *args): obj = object.__new__(cls) obj.args = args return obj def __getnewargs__(self): return self.args def __hash__(self): return hash((type(self).__name__,) + tuple(self.args)) def __eq__(a, b): if not isinstance(b, type(a)): return False else: return a.args == b.args def __ne__(a, b): if not isinstance(b, type(a)): return True else: return a.args != b.args def __lt__(self, other): if self.__cmp__(other) == -1: return True return False def __cmp__(self, other): if type(self) is not type(other): a = str(type(self)) b = str(type(other)) else: a = self.args b = other.args return (a > b) - (a < b) def __str__(self): return '%s(%s)' % (self.__class__.__name__, ', '.join(str(a) for a in self.args)) __repr__ = __str__ @staticmethod def fromstring(text): """Logic from string with space around & and | but none after !. e.g. !a & b | c """ lexpr = None # current logical expression schedop = None # scheduled operation for term in text.split(): # operation symbol if term in '&|': if schedop is not None: raise ValueError( 'double op forbidden: "%s %s"' % (term, schedop)) if lexpr is None: raise ValueError( '%s cannot be in the beginning of expression' % term) schedop = term continue if '&' in term or '|' in term: raise ValueError('& and | must have space around them') if term[0] == '!': if len(term) == 1: raise ValueError('do not include space after "!"') term = Not(term[1:]) # already scheduled operation, e.g. '&' if schedop: lexpr = Logic.op_2class[schedop](lexpr, term) schedop = None continue # this should be atom if lexpr is not None: raise ValueError( 'missing op between "%s" and "%s"' % (lexpr, term)) lexpr = term # let's check that we ended up in correct state if schedop is not None: raise ValueError('premature end-of-expression in "%s"' % text) if lexpr is None: raise ValueError('"%s" is empty' % text) # everything looks good now return lexpr class AndOr_Base(Logic): def __new__(cls, *args): bargs = [] for a in args: if a == cls.op_x_notx: return a elif a == (not cls.op_x_notx): continue # skip this argument bargs.append(a) args = sorted(set(cls.flatten(bargs)), key=hash) for a in args: if Not(a) in args: return cls.op_x_notx if len(args) == 1: return args.pop() elif len(args) == 0: return not cls.op_x_notx return Logic.__new__(cls, *args) @classmethod def flatten(cls, args): # quick-n-dirty flattening for And and Or args_queue = list(args) res = [] while True: try: arg = args_queue.pop(0) except IndexError: break if isinstance(arg, Logic): if isinstance(arg, cls): args_queue.extend(arg.args) continue res.append(arg) args = tuple(res) return args class And(AndOr_Base): op_x_notx = False def _eval_propagate_not(self): # !(a&b&c ...) == !a | !b | !c ... return Or(*[Not(a) for a in self.args]) # (a|b|...) & c == (a&c) | (b&c) | ... def expand(self): # first locate Or for i in range(len(self.args)): arg = self.args[i] if isinstance(arg, Or): arest = self.args[:i] + self.args[i + 1:] orterms = [And(*(arest + (a,))) for a in arg.args] for j in range(len(orterms)): if isinstance(orterms[j], Logic): orterms[j] = orterms[j].expand() res = Or(*orterms) return res return self class Or(AndOr_Base): op_x_notx = True def _eval_propagate_not(self): # !(a|b|c ...) == !a & !b & !c ... return And(*[Not(a) for a in self.args]) class Not(Logic): def __new__(cls, arg): if isinstance(arg, str): return Logic.__new__(cls, arg) elif isinstance(arg, bool): return not arg elif isinstance(arg, Not): return arg.args[0] elif isinstance(arg, Logic): # XXX this is a hack to expand right from the beginning arg = arg._eval_propagate_not() return arg else: raise ValueError('Not: unknown argument %r' % (arg,)) @property def arg(self): return self.args[0] Logic.op_2class['&'] = And Logic.op_2class['|'] = Or Logic.op_2class['!'] = Not sympy-sympy-1.9/sympy/core/mod.py000066400000000000000000000166151412543434000171760ustar00rootroot00000000000000from sympy.core.numbers import nan from .function import Function from .kind import NumberKind class Mod(Function): """Represents a modulo operation on symbolic expressions. Parameters ========== p : Expr Dividend. q : Expr Divisor. Notes ===== The convention used is the same as Python's: the remainder always has the same sign as the divisor. Examples ======== >>> from sympy.abc import x, y >>> x**2 % y Mod(x**2, y) >>> _.subs({x: 5, y: 6}) 1 """ kind = NumberKind @classmethod def eval(cls, p, q): from sympy.core.add import Add from sympy.core.mul import Mul from sympy.core.singleton import S from sympy.core.exprtools import gcd_terms from sympy.polys.polyerrors import PolynomialError from sympy.polys.polytools import gcd def doit(p, q): """Try to return p % q if both are numbers or +/-p is known to be less than or equal q. """ if q.is_zero: raise ZeroDivisionError("Modulo by zero") if p.is_finite is False or q.is_finite is False or p is nan or q is nan: return nan if p is S.Zero or p == q or p == -q or (p.is_integer and q == 1): return S.Zero if q.is_Number: if p.is_Number: return p%q if q == 2: if p.is_even: return S.Zero elif p.is_odd: return S.One if hasattr(p, '_eval_Mod'): rv = getattr(p, '_eval_Mod')(q) if rv is not None: return rv # by ratio r = p/q if r.is_integer: return S.Zero try: d = int(r) except TypeError: pass else: if isinstance(d, int): rv = p - d*q if (rv*q < 0) == True: rv += q return rv # by difference # -2|q| < p < 2|q| d = abs(p) for _ in range(2): d -= abs(q) if d.is_negative: if q.is_positive: if p.is_positive: return d + q elif p.is_negative: return -d elif q.is_negative: if p.is_positive: return d elif p.is_negative: return -d + q break rv = doit(p, q) if rv is not None: return rv # denest if isinstance(p, cls): qinner = p.args[1] if qinner % q == 0: return cls(p.args[0], q) elif (qinner*(q - qinner)).is_nonnegative: # |qinner| < |q| and have same sign return p elif isinstance(-p, cls): qinner = (-p).args[1] if qinner % q == 0: return cls(-(-p).args[0], q) elif (qinner*(q + qinner)).is_nonpositive: # |qinner| < |q| and have different sign return p elif isinstance(p, Add): # separating into modulus and non modulus both_l = non_mod_l, mod_l = [], [] for arg in p.args: both_l[isinstance(arg, cls)].append(arg) # if q same for all if mod_l and all(inner.args[1] == q for inner in mod_l): net = Add(*non_mod_l) + Add(*[i.args[0] for i in mod_l]) return cls(net, q) elif isinstance(p, Mul): # separating into modulus and non modulus both_l = non_mod_l, mod_l = [], [] for arg in p.args: both_l[isinstance(arg, cls)].append(arg) if mod_l and all(inner.args[1] == q for inner in mod_l): # finding distributive term non_mod_l = [cls(x, q) for x in non_mod_l] mod = [] non_mod = [] for j in non_mod_l: if isinstance(j, cls): mod.append(j.args[0]) else: non_mod.append(j) prod_mod = Mul(*mod) prod_non_mod = Mul(*non_mod) prod_mod1 = Mul(*[i.args[0] for i in mod_l]) net = prod_mod1*prod_mod return prod_non_mod*cls(net, q) if q.is_Integer and q is not S.One: _ = [] for i in non_mod_l: if i.is_Integer and (i % q is not S.Zero): _.append(i%q) else: _.append(i) non_mod_l = _ p = Mul(*(non_mod_l + mod_l)) # XXX other possibilities? # extract gcd; any further simplification should be done by the user try: G = gcd(p, q) if G != 1: p, q = [gcd_terms(i/G, clear=False, fraction=False) for i in (p, q)] except PolynomialError: # issue 21373 G = S.One pwas, qwas = p, q # simplify terms # (x + y + 2) % x -> Mod(y + 2, x) if p.is_Add: args = [] for i in p.args: a = cls(i, q) if a.count(cls) > i.count(cls): args.append(i) else: args.append(a) if args != list(p.args): p = Add(*args) else: # handle coefficients if they are not Rational # since those are not handled by factor_terms # e.g. Mod(.6*x, .3*y) -> 0.3*Mod(2*x, y) cp, p = p.as_coeff_Mul() cq, q = q.as_coeff_Mul() ok = False if not cp.is_Rational or not cq.is_Rational: r = cp % cq if r == 0: G *= cq p *= int(cp/cq) ok = True if not ok: p = cp*p q = cq*q # simple -1 extraction if p.could_extract_minus_sign() and q.could_extract_minus_sign(): G, p, q = [-i for i in (G, p, q)] # check again to see if p and q can now be handled as numbers rv = doit(p, q) if rv is not None: return rv*G # put 1.0 from G on inside if G.is_Float and G == 1: p *= G return cls(p, q, evaluate=False) elif G.is_Mul and G.args[0].is_Float and G.args[0] == 1: p = G.args[0]*p G = Mul._from_args(G.args[1:]) return G*cls(p, q, evaluate=(p, q) != (pwas, qwas)) def _eval_is_integer(self): from sympy.core.logic import fuzzy_and, fuzzy_not p, q = self.args if fuzzy_and([p.is_integer, q.is_integer, fuzzy_not(q.is_zero)]): return True def _eval_is_nonnegative(self): if self.args[1].is_positive: return True def _eval_is_nonpositive(self): if self.args[1].is_negative: return True def _eval_rewrite_as_floor(self, a, b, **kwargs): from sympy.functions.elementary.integers import floor return a - b*floor(a/b) sympy-sympy-1.9/sympy/core/mul.py000066400000000000000000002232161412543434000172110ustar00rootroot00000000000000from collections import defaultdict from functools import cmp_to_key, reduce import operator from .sympify import sympify from .basic import Basic from .singleton import S from .operations import AssocOp, AssocOpDispatcher from .cache import cacheit from .logic import fuzzy_not, _fuzzy_group from .expr import Expr from .parameters import global_parameters from .kind import KindDispatcher # internal marker to indicate: # "there are still non-commutative objects -- don't forget to process them" class NC_Marker: is_Order = False is_Mul = False is_Number = False is_Poly = False is_commutative = False # Key for sorting commutative args in canonical order _args_sortkey = cmp_to_key(Basic.compare) def _mulsort(args): # in-place sorting of args args.sort(key=_args_sortkey) def _unevaluated_Mul(*args): """Return a well-formed unevaluated Mul: Numbers are collected and put in slot 0, any arguments that are Muls will be flattened, and args are sorted. Use this when args have changed but you still want to return an unevaluated Mul. Examples ======== >>> from sympy.core.mul import _unevaluated_Mul as uMul >>> from sympy import S, sqrt, Mul >>> from sympy.abc import x >>> a = uMul(*[S(3.0), x, S(2)]) >>> a.args[0] 6.00000000000000 >>> a.args[1] x Two unevaluated Muls with the same arguments will always compare as equal during testing: >>> m = uMul(sqrt(2), sqrt(3)) >>> m == uMul(sqrt(3), sqrt(2)) True >>> u = Mul(sqrt(3), sqrt(2), evaluate=False) >>> m == uMul(u) True >>> m == Mul(*m.args) False """ args = list(args) newargs = [] ncargs = [] co = S.One while args: a = args.pop() if a.is_Mul: c, nc = a.args_cnc() args.extend(c) if nc: ncargs.append(Mul._from_args(nc)) elif a.is_Number: co *= a else: newargs.append(a) _mulsort(newargs) if co is not S.One: newargs.insert(0, co) if ncargs: newargs.append(Mul._from_args(ncargs)) return Mul._from_args(newargs) class Mul(Expr, AssocOp): """ Expression representing multiplication operation for algebraic field. Every argument of ``Mul()`` must be ``Expr``. Infix operator ``*`` on most scalar objects in SymPy calls this class. Another use of ``Mul()`` is to represent the structure of abstract multiplication so that its arguments can be substituted to return different class. Refer to examples section for this. ``Mul()`` evaluates the argument unless ``evaluate=False`` is passed. The evaluation logic includes: 1. Flattening ``Mul(x, Mul(y, z))`` -> ``Mul(x, y, z)`` 2. Identity removing ``Mul(x, 1, y)`` -> ``Mul(x, y)`` 3. Exponent collecting by ``.as_base_exp()`` ``Mul(x, x**2)`` -> ``Pow(x, 3)`` 4. Term sorting ``Mul(y, x, 2)`` -> ``Mul(2, x, y)`` Since multiplication can be vector space operation, arguments may have the different :obj:`sympy.core.kind.Kind()`. Kind of the resulting object is automatically inferred. Examples ======== >>> from sympy import Mul >>> from sympy.abc import x, y >>> Mul(x, 1) x >>> Mul(x, x) x**2 If ``evaluate=False`` is passed, result is not evaluated. >>> Mul(1, 2, evaluate=False) 1*2 >>> Mul(x, x, evaluate=False) x*x ``Mul()`` also represents the general structure of multiplication operation. >>> from sympy import MatrixSymbol >>> A = MatrixSymbol('A', 2,2) >>> expr = Mul(x,y).subs({y:A}) >>> expr x*A >>> type(expr) See Also ======== MatMul """ __slots__ = () is_Mul = True _args_type = Expr _kind_dispatcher = KindDispatcher("Mul_kind_dispatcher", commutative=True) @property def kind(self): arg_kinds = (a.kind for a in self.args) return self._kind_dispatcher(*arg_kinds) def __neg__(self): c, args = self.as_coeff_mul() c = -c if c is not S.One: if args[0].is_Number: args = list(args) if c is S.NegativeOne: args[0] = -args[0] else: args[0] *= c else: args = (c,) + args return self._from_args(args, self.is_commutative) @classmethod def flatten(cls, seq): """Return commutative, noncommutative and order arguments by combining related terms. Notes ===== * In an expression like ``a*b*c``, python process this through sympy as ``Mul(Mul(a, b), c)``. This can have undesirable consequences. - Sometimes terms are not combined as one would like: {c.f. https://github.com/sympy/sympy/issues/4596} >>> from sympy import Mul, sqrt >>> from sympy.abc import x, y, z >>> 2*(x + 1) # this is the 2-arg Mul behavior 2*x + 2 >>> y*(x + 1)*2 2*y*(x + 1) >>> 2*(x + 1)*y # 2-arg result will be obtained first y*(2*x + 2) >>> Mul(2, x + 1, y) # all 3 args simultaneously processed 2*y*(x + 1) >>> 2*((x + 1)*y) # parentheses can control this behavior 2*y*(x + 1) Powers with compound bases may not find a single base to combine with unless all arguments are processed at once. Post-processing may be necessary in such cases. {c.f. https://github.com/sympy/sympy/issues/5728} >>> a = sqrt(x*sqrt(y)) >>> a**3 (x*sqrt(y))**(3/2) >>> Mul(a,a,a) (x*sqrt(y))**(3/2) >>> a*a*a x*sqrt(y)*sqrt(x*sqrt(y)) >>> _.subs(a.base, z).subs(z, a.base) (x*sqrt(y))**(3/2) - If more than two terms are being multiplied then all the previous terms will be re-processed for each new argument. So if each of ``a``, ``b`` and ``c`` were :class:`Mul` expression, then ``a*b*c`` (or building up the product with ``*=``) will process all the arguments of ``a`` and ``b`` twice: once when ``a*b`` is computed and again when ``c`` is multiplied. Using ``Mul(a, b, c)`` will process all arguments once. * The results of Mul are cached according to arguments, so flatten will only be called once for ``Mul(a, b, c)``. If you can structure a calculation so the arguments are most likely to be repeats then this can save time in computing the answer. For example, say you had a Mul, M, that you wished to divide by ``d[i]`` and multiply by ``n[i]`` and you suspect there are many repeats in ``n``. It would be better to compute ``M*n[i]/d[i]`` rather than ``M/d[i]*n[i]`` since every time n[i] is a repeat, the product, ``M*n[i]`` will be returned without flattening -- the cached value will be returned. If you divide by the ``d[i]`` first (and those are more unique than the ``n[i]``) then that will create a new Mul, ``M/d[i]`` the args of which will be traversed again when it is multiplied by ``n[i]``. {c.f. https://github.com/sympy/sympy/issues/5706} This consideration is moot if the cache is turned off. NB -- The validity of the above notes depends on the implementation details of Mul and flatten which may change at any time. Therefore, you should only consider them when your code is highly performance sensitive. Removal of 1 from the sequence is already handled by AssocOp.__new__. """ from sympy.calculus.util import AccumBounds from sympy.matrices.expressions import MatrixExpr rv = None if len(seq) == 2: a, b = seq if b.is_Rational: a, b = b, a seq = [a, b] assert not a is S.One if not a.is_zero and a.is_Rational: r, b = b.as_coeff_Mul() if b.is_Add: if r is not S.One: # 2-arg hack # leave the Mul as a Mul? ar = a*r if ar is S.One: arb = b else: arb = cls(a*r, b, evaluate=False) rv = [arb], [], None elif global_parameters.distribute and b.is_commutative: r, b = b.as_coeff_Add() bargs = [_keep_coeff(a, bi) for bi in Add.make_args(b)] _addsort(bargs) ar = a*r if ar: bargs.insert(0, ar) bargs = [Add._from_args(bargs)] rv = bargs, [], None if rv: return rv # apply associativity, separate commutative part of seq c_part = [] # out: commutative factors nc_part = [] # out: non-commutative factors nc_seq = [] coeff = S.One # standalone term # e.g. 3 * ... c_powers = [] # (base,exp) n # e.g. (x,n) for x num_exp = [] # (num-base, exp) y # e.g. (3, y) for ... * 3 * ... neg1e = S.Zero # exponent on -1 extracted from Number-based Pow and I pnum_rat = {} # (num-base, Rat-exp) 1/2 # e.g. (3, 1/2) for ... * 3 * ... order_symbols = None # --- PART 1 --- # # "collect powers and coeff": # # o coeff # o c_powers # o num_exp # o neg1e # o pnum_rat # # NOTE: this is optimized for all-objects-are-commutative case for o in seq: # O(x) if o.is_Order: o, order_symbols = o.as_expr_variables(order_symbols) # Mul([...]) if o.is_Mul: if o.is_commutative: seq.extend(o.args) # XXX zerocopy? else: # NCMul can have commutative parts as well for q in o.args: if q.is_commutative: seq.append(q) else: nc_seq.append(q) # append non-commutative marker, so we don't forget to # process scheduled non-commutative objects seq.append(NC_Marker) continue # 3 elif o.is_Number: if o is S.NaN or coeff is S.ComplexInfinity and o.is_zero: # we know for sure the result will be nan return [S.NaN], [], None elif coeff.is_Number or isinstance(coeff, AccumBounds): # it could be zoo coeff *= o if coeff is S.NaN: # we know for sure the result will be nan return [S.NaN], [], None continue elif isinstance(o, AccumBounds): coeff = o.__mul__(coeff) continue elif o is S.ComplexInfinity: if not coeff: # 0 * zoo = NaN return [S.NaN], [], None coeff = S.ComplexInfinity continue elif o is S.ImaginaryUnit: neg1e += S.Half continue elif o.is_commutative: # e # o = b b, e = o.as_base_exp() # y # 3 if o.is_Pow: if b.is_Number: # get all the factors with numeric base so they can be # combined below, but don't combine negatives unless # the exponent is an integer if e.is_Rational: if e.is_Integer: coeff *= Pow(b, e) # it is an unevaluated power continue elif e.is_negative: # also a sign of an unevaluated power seq.append(Pow(b, e)) continue elif b.is_negative: neg1e += e b = -b if b is not S.One: pnum_rat.setdefault(b, []).append(e) continue elif b.is_positive or e.is_integer: num_exp.append((b, e)) continue c_powers.append((b, e)) # NON-COMMUTATIVE # TODO: Make non-commutative exponents not combine automatically else: if o is not NC_Marker: nc_seq.append(o) # process nc_seq (if any) while nc_seq: o = nc_seq.pop(0) if not nc_part: nc_part.append(o) continue # b c b+c # try to combine last terms: a * a -> a o1 = nc_part.pop() b1, e1 = o1.as_base_exp() b2, e2 = o.as_base_exp() new_exp = e1 + e2 # Only allow powers to combine if the new exponent is # not an Add. This allow things like a**2*b**3 == a**5 # if a.is_commutative == False, but prohibits # a**x*a**y and x**a*x**b from combining (x,y commute). if b1 == b2 and (not new_exp.is_Add): o12 = b1 ** new_exp # now o12 could be a commutative object if o12.is_commutative: seq.append(o12) continue else: nc_seq.insert(0, o12) else: nc_part.append(o1) nc_part.append(o) # We do want a combined exponent if it would not be an Add, such as # y 2y 3y # x * x -> x # We determine if two exponents have the same term by using # as_coeff_Mul. # # Unfortunately, this isn't smart enough to consider combining into # exponents that might already be adds, so things like: # z - y y # x * x will be left alone. This is because checking every possible # combination can slow things down. # gather exponents of common bases... def _gather(c_powers): common_b = {} # b:e for b, e in c_powers: co = e.as_coeff_Mul() common_b.setdefault(b, {}).setdefault( co[1], []).append(co[0]) for b, d in common_b.items(): for di, li in d.items(): d[di] = Add(*li) new_c_powers = [] for b, e in common_b.items(): new_c_powers.extend([(b, c*t) for t, c in e.items()]) return new_c_powers # in c_powers c_powers = _gather(c_powers) # and in num_exp num_exp = _gather(num_exp) # --- PART 2 --- # # o process collected powers (x**0 -> 1; x**1 -> x; otherwise Pow) # o combine collected powers (2**x * 3**x -> 6**x) # with numeric base # ................................ # now we have: # - coeff: # - c_powers: (b, e) # - num_exp: (2, e) # - pnum_rat: {(1/3, [1/3, 2/3, 1/4])} # 0 1 # x -> 1 x -> x # this should only need to run twice; if it fails because # it needs to be run more times, perhaps this should be # changed to a "while True" loop -- the only reason it # isn't such now is to allow a less-than-perfect result to # be obtained rather than raising an error or entering an # infinite loop for i in range(2): new_c_powers = [] changed = False for b, e in c_powers: if e.is_zero: # canceling out infinities yields NaN if (b.is_Add or b.is_Mul) and any(infty in b.args for infty in (S.ComplexInfinity, S.Infinity, S.NegativeInfinity)): return [S.NaN], [], None continue if e is S.One: if b.is_Number: coeff *= b continue p = b if e is not S.One: p = Pow(b, e) # check to make sure that the base doesn't change # after exponentiation; to allow for unevaluated # Pow, we only do so if b is not already a Pow if p.is_Pow and not b.is_Pow: bi = b b, e = p.as_base_exp() if b != bi: changed = True c_part.append(p) new_c_powers.append((b, e)) # there might have been a change, but unless the base # matches some other base, there is nothing to do if changed and len({ b for b, e in new_c_powers}) != len(new_c_powers): # start over again c_part = [] c_powers = _gather(new_c_powers) else: break # x x x # 2 * 3 -> 6 inv_exp_dict = {} # exp:Mul(num-bases) x x # e.g. x:6 for ... * 2 * 3 * ... for b, e in num_exp: inv_exp_dict.setdefault(e, []).append(b) for e, b in inv_exp_dict.items(): inv_exp_dict[e] = cls(*b) c_part.extend([Pow(b, e) for e, b in inv_exp_dict.items() if e]) # b, e -> e' = sum(e), b # {(1/5, [1/3]), (1/2, [1/12, 1/4]} -> {(1/3, [1/5, 1/2])} comb_e = {} for b, e in pnum_rat.items(): comb_e.setdefault(Add(*e), []).append(b) del pnum_rat # process them, reducing exponents to values less than 1 # and updating coeff if necessary else adding them to # num_rat for further processing num_rat = [] for e, b in comb_e.items(): b = cls(*b) if e.q == 1: coeff *= Pow(b, e) continue if e.p > e.q: e_i, ep = divmod(e.p, e.q) coeff *= Pow(b, e_i) e = Rational(ep, e.q) num_rat.append((b, e)) del comb_e # extract gcd of bases in num_rat # 2**(1/3)*6**(1/4) -> 2**(1/3+1/4)*3**(1/4) pnew = defaultdict(list) i = 0 # steps through num_rat which may grow while i < len(num_rat): bi, ei = num_rat[i] grow = [] for j in range(i + 1, len(num_rat)): bj, ej = num_rat[j] g = bi.gcd(bj) if g is not S.One: # 4**r1*6**r2 -> 2**(r1+r2) * 2**r1 * 3**r2 # this might have a gcd with something else e = ei + ej if e.q == 1: coeff *= Pow(g, e) else: if e.p > e.q: e_i, ep = divmod(e.p, e.q) # change e in place coeff *= Pow(g, e_i) e = Rational(ep, e.q) grow.append((g, e)) # update the jth item num_rat[j] = (bj/g, ej) # update bi that we are checking with bi = bi/g if bi is S.One: break if bi is not S.One: obj = Pow(bi, ei) if obj.is_Number: coeff *= obj else: # changes like sqrt(12) -> 2*sqrt(3) for obj in Mul.make_args(obj): if obj.is_Number: coeff *= obj else: assert obj.is_Pow bi, ei = obj.args pnew[ei].append(bi) num_rat.extend(grow) i += 1 # combine bases of the new powers for e, b in pnew.items(): pnew[e] = cls(*b) # handle -1 and I if neg1e: # treat I as (-1)**(1/2) and compute -1's total exponent p, q = neg1e.as_numer_denom() # if the integer part is odd, extract -1 n, p = divmod(p, q) if n % 2: coeff = -coeff # if it's a multiple of 1/2 extract I if q == 2: c_part.append(S.ImaginaryUnit) elif p: # see if there is any positive base this power of # -1 can join neg1e = Rational(p, q) for e, b in pnew.items(): if e == neg1e and b.is_positive: pnew[e] = -b break else: # keep it separate; we've already evaluated it as # much as possible so evaluate=False c_part.append(Pow(S.NegativeOne, neg1e, evaluate=False)) # add all the pnew powers c_part.extend([Pow(b, e) for e, b in pnew.items()]) # oo, -oo if (coeff is S.Infinity) or (coeff is S.NegativeInfinity): def _handle_for_oo(c_part, coeff_sign): new_c_part = [] for t in c_part: if t.is_extended_positive: continue if t.is_extended_negative: coeff_sign *= -1 continue new_c_part.append(t) return new_c_part, coeff_sign c_part, coeff_sign = _handle_for_oo(c_part, 1) nc_part, coeff_sign = _handle_for_oo(nc_part, coeff_sign) coeff *= coeff_sign # zoo if coeff is S.ComplexInfinity: # zoo might be # infinite_real + bounded_im # bounded_real + infinite_im # infinite_real + infinite_im # and non-zero real or imaginary will not change that status. c_part = [c for c in c_part if not (fuzzy_not(c.is_zero) and c.is_extended_real is not None)] nc_part = [c for c in nc_part if not (fuzzy_not(c.is_zero) and c.is_extended_real is not None)] # 0 elif coeff.is_zero: # we know for sure the result will be 0 except the multiplicand # is infinity or a matrix if any(isinstance(c, MatrixExpr) for c in nc_part): return [coeff], nc_part, order_symbols if any(c.is_finite == False for c in c_part): return [S.NaN], [], order_symbols return [coeff], [], order_symbols # check for straggling Numbers that were produced _new = [] for i in c_part: if i.is_Number: coeff *= i else: _new.append(i) c_part = _new # order commutative part canonically _mulsort(c_part) # current code expects coeff to be always in slot-0 if coeff is not S.One: c_part.insert(0, coeff) # we are done if (global_parameters.distribute and not nc_part and len(c_part) == 2 and c_part[0].is_Number and c_part[0].is_finite and c_part[1].is_Add): # 2*(1+a) -> 2 + 2 * a coeff = c_part[0] c_part = [Add(*[coeff*f for f in c_part[1].args])] return c_part, nc_part, order_symbols def _eval_power(self, e): # don't break up NC terms: (A*B)**3 != A**3*B**3, it is A*B*A*B*A*B cargs, nc = self.args_cnc(split_1=False) if e.is_Integer: return Mul(*[Pow(b, e, evaluate=False) for b in cargs]) * \ Pow(Mul._from_args(nc), e, evaluate=False) if e.is_Rational and e.q == 2: from sympy.core.power import integer_nthroot from sympy.functions.elementary.complexes import sign if self.is_imaginary: a = self.as_real_imag()[1] if a.is_Rational: n, d = abs(a/2).as_numer_denom() n, t = integer_nthroot(n, 2) if t: d, t = integer_nthroot(d, 2) if t: r = sympify(n)/d return _unevaluated_Mul(r**e.p, (1 + sign(a)*S.ImaginaryUnit)**e.p) p = Pow(self, e, evaluate=False) if e.is_Rational or e.is_Float: return p._eval_expand_power_base() return p @classmethod def class_key(cls): return 3, 0, cls.__name__ def _eval_evalf(self, prec): c, m = self.as_coeff_Mul() if c is S.NegativeOne: if m.is_Mul: rv = -AssocOp._eval_evalf(m, prec) else: mnew = m._eval_evalf(prec) if mnew is not None: m = mnew rv = -m else: rv = AssocOp._eval_evalf(self, prec) if rv.is_number: return rv.expand() return rv @property def _mpc_(self): """ Convert self to an mpmath mpc if possible """ from sympy.core.numbers import I, Float im_part, imag_unit = self.as_coeff_Mul() if not imag_unit == I: # ValueError may seem more reasonable but since it's a @property, # we need to use AttributeError to keep from confusing things like # hasattr. raise AttributeError("Cannot convert Mul to mpc. Must be of the form Number*I") return (Float(0)._mpf_, Float(im_part)._mpf_) @cacheit def as_two_terms(self): """Return head and tail of self. This is the most efficient way to get the head and tail of an expression. - if you want only the head, use self.args[0]; - if you want to process the arguments of the tail then use self.as_coef_mul() which gives the head and a tuple containing the arguments of the tail when treated as a Mul. - if you want the coefficient when self is treated as an Add then use self.as_coeff_add()[0] Examples ======== >>> from sympy.abc import x, y >>> (3*x*y).as_two_terms() (3, x*y) """ args = self.args if len(args) == 1: return S.One, self elif len(args) == 2: return args else: return args[0], self._new_rawargs(*args[1:]) @cacheit def as_coefficients_dict(self): """Return a dictionary mapping terms to their coefficient. Since the dictionary is a defaultdict, inquiries about terms which were not present will return a coefficient of 0. The dictionary is considered to have a single term. Examples ======== >>> from sympy.abc import a, x >>> (3*a*x).as_coefficients_dict() {a*x: 3} >>> _[a] 0 """ d = defaultdict(int) args = self.args if len(args) == 1 or not args[0].is_Number: d[self] = S.One else: d[self._new_rawargs(*args[1:])] = args[0] return d @cacheit def as_coeff_mul(self, *deps, rational=True, **kwargs): if deps: from sympy.utilities.iterables import sift l1, l2 = sift(self.args, lambda x: x.has(*deps), binary=True) return self._new_rawargs(*l2), tuple(l1) args = self.args if args[0].is_Number: if not rational or args[0].is_Rational: return args[0], args[1:] elif args[0].is_extended_negative: return S.NegativeOne, (-args[0],) + args[1:] return S.One, args def as_coeff_Mul(self, rational=False): """ Efficiently extract the coefficient of a product. """ coeff, args = self.args[0], self.args[1:] if coeff.is_Number: if not rational or coeff.is_Rational: if len(args) == 1: return coeff, args[0] else: return coeff, self._new_rawargs(*args) elif coeff.is_extended_negative: return S.NegativeOne, self._new_rawargs(*((-coeff,) + args)) return S.One, self def as_real_imag(self, deep=True, **hints): from sympy import Abs, expand_mul, im, re other = [] coeffr = [] coeffi = [] addterms = S.One for a in self.args: r, i = a.as_real_imag() if i.is_zero: coeffr.append(r) elif r.is_zero: coeffi.append(i*S.ImaginaryUnit) elif a.is_commutative: # search for complex conjugate pairs: for i, x in enumerate(other): if x == a.conjugate(): coeffr.append(Abs(x)**2) del other[i] break else: if a.is_Add: addterms *= a else: other.append(a) else: other.append(a) m = self.func(*other) if hints.get('ignore') == m: return if len(coeffi) % 2: imco = im(coeffi.pop(0)) # all other pairs make a real factor; they will be # put into reco below else: imco = S.Zero reco = self.func(*(coeffr + coeffi)) r, i = (reco*re(m), reco*im(m)) if addterms == 1: if m == 1: if imco.is_zero: return (reco, S.Zero) else: return (S.Zero, reco*imco) if imco is S.Zero: return (r, i) return (-imco*i, imco*r) addre, addim = expand_mul(addterms, deep=False).as_real_imag() if imco is S.Zero: return (r*addre - i*addim, i*addre + r*addim) else: r, i = -imco*i, imco*r return (r*addre - i*addim, r*addim + i*addre) @staticmethod def _expandsums(sums): """ Helper function for _eval_expand_mul. sums must be a list of instances of Basic. """ L = len(sums) if L == 1: return sums[0].args terms = [] left = Mul._expandsums(sums[:L//2]) right = Mul._expandsums(sums[L//2:]) terms = [Mul(a, b) for a in left for b in right] added = Add(*terms) return Add.make_args(added) # it may have collapsed down to one term def _eval_expand_mul(self, **hints): from sympy import fraction # Handle things like 1/(x*(x + 1)), which are automatically converted # to 1/x*1/(x + 1) expr = self n, d = fraction(expr) if d.is_Mul: n, d = [i._eval_expand_mul(**hints) if i.is_Mul else i for i in (n, d)] expr = n/d if not expr.is_Mul: return expr plain, sums, rewrite = [], [], False for factor in expr.args: if factor.is_Add: sums.append(factor) rewrite = True else: if factor.is_commutative: plain.append(factor) else: sums.append(Basic(factor)) # Wrapper if not rewrite: return expr else: plain = self.func(*plain) if sums: deep = hints.get("deep", False) terms = self.func._expandsums(sums) args = [] for term in terms: t = self.func(plain, term) if t.is_Mul and any(a.is_Add for a in t.args) and deep: t = t._eval_expand_mul() args.append(t) return Add(*args) else: return plain @cacheit def _eval_derivative(self, s): args = list(self.args) terms = [] for i in range(len(args)): d = args[i].diff(s) if d: # Note: reduce is used in step of Mul as Mul is unable to # handle subtypes and operation priority: terms.append(reduce(lambda x, y: x*y, (args[:i] + [d] + args[i + 1:]), S.One)) return Add.fromiter(terms) @cacheit def _eval_derivative_n_times(self, s, n): from sympy import Integer, factorial, prod, Sum, Max from sympy.ntheory.multinomial import multinomial_coefficients_iterator from .function import AppliedUndef from .symbol import Symbol, symbols, Dummy if not isinstance(s, AppliedUndef) and not isinstance(s, Symbol): # other types of s may not be well behaved, e.g. # (cos(x)*sin(y)).diff([[x, y, z]]) return super()._eval_derivative_n_times(s, n) args = self.args m = len(args) if isinstance(n, (int, Integer)): # https://en.wikipedia.org/wiki/General_Leibniz_rule#More_than_two_factors terms = [] for kvals, c in multinomial_coefficients_iterator(m, n): p = prod([arg.diff((s, k)) for k, arg in zip(kvals, args)]) terms.append(c * p) return Add(*terms) kvals = symbols("k1:%i" % m, cls=Dummy) klast = n - sum(kvals) nfact = factorial(n) e, l = (# better to use the multinomial? nfact/prod(map(factorial, kvals))/factorial(klast)*\ prod([args[t].diff((s, kvals[t])) for t in range(m-1)])*\ args[-1].diff((s, Max(0, klast))), [(k, 0, n) for k in kvals]) return Sum(e, *l) def _eval_difference_delta(self, n, step): from sympy.series.limitseq import difference_delta as dd arg0 = self.args[0] rest = Mul(*self.args[1:]) return (arg0.subs(n, n + step) * dd(rest, n, step) + dd(arg0, n, step) * rest) def _matches_simple(self, expr, repl_dict): # handle (w*3).matches('x*5') -> {w: x*5/3} coeff, terms = self.as_coeff_Mul() terms = Mul.make_args(terms) if len(terms) == 1: newexpr = self.__class__._combine_inverse(expr, coeff) return terms[0].matches(newexpr, repl_dict) return def matches(self, expr, repl_dict={}, old=False): expr = sympify(expr) repl_dict = repl_dict.copy() if self.is_commutative and expr.is_commutative: return self._matches_commutative(expr, repl_dict, old) elif self.is_commutative is not expr.is_commutative: return None # Proceed only if both both expressions are non-commutative c1, nc1 = self.args_cnc() c2, nc2 = expr.args_cnc() c1, c2 = [c or [1] for c in [c1, c2]] # TODO: Should these be self.func? comm_mul_self = Mul(*c1) comm_mul_expr = Mul(*c2) repl_dict = comm_mul_self.matches(comm_mul_expr, repl_dict, old) # If the commutative arguments didn't match and aren't equal, then # then the expression as a whole doesn't match if repl_dict is None and c1 != c2: return None # Now match the non-commutative arguments, expanding powers to # multiplications nc1 = Mul._matches_expand_pows(nc1) nc2 = Mul._matches_expand_pows(nc2) repl_dict = Mul._matches_noncomm(nc1, nc2, repl_dict) return repl_dict or None @staticmethod def _matches_expand_pows(arg_list): new_args = [] for arg in arg_list: if arg.is_Pow and arg.exp > 0: new_args.extend([arg.base] * arg.exp) else: new_args.append(arg) return new_args @staticmethod def _matches_noncomm(nodes, targets, repl_dict={}): """Non-commutative multiplication matcher. `nodes` is a list of symbols within the matcher multiplication expression, while `targets` is a list of arguments in the multiplication expression being matched against. """ repl_dict = repl_dict.copy() # List of possible future states to be considered agenda = [] # The current matching state, storing index in nodes and targets state = (0, 0) node_ind, target_ind = state # Mapping between wildcard indices and the index ranges they match wildcard_dict = {} repl_dict = repl_dict.copy() while target_ind < len(targets) and node_ind < len(nodes): node = nodes[node_ind] if node.is_Wild: Mul._matches_add_wildcard(wildcard_dict, state) states_matches = Mul._matches_new_states(wildcard_dict, state, nodes, targets) if states_matches: new_states, new_matches = states_matches agenda.extend(new_states) if new_matches: for match in new_matches: repl_dict[match] = new_matches[match] if not agenda: return None else: state = agenda.pop() node_ind, target_ind = state return repl_dict @staticmethod def _matches_add_wildcard(dictionary, state): node_ind, target_ind = state if node_ind in dictionary: begin, end = dictionary[node_ind] dictionary[node_ind] = (begin, target_ind) else: dictionary[node_ind] = (target_ind, target_ind) @staticmethod def _matches_new_states(dictionary, state, nodes, targets): node_ind, target_ind = state node = nodes[node_ind] target = targets[target_ind] # Don't advance at all if we've exhausted the targets but not the nodes if target_ind >= len(targets) - 1 and node_ind < len(nodes) - 1: return None if node.is_Wild: match_attempt = Mul._matches_match_wilds(dictionary, node_ind, nodes, targets) if match_attempt: # If the same node has been matched before, don't return # anything if the current match is diverging from the previous # match other_node_inds = Mul._matches_get_other_nodes(dictionary, nodes, node_ind) for ind in other_node_inds: other_begin, other_end = dictionary[ind] curr_begin, curr_end = dictionary[node_ind] other_targets = targets[other_begin:other_end + 1] current_targets = targets[curr_begin:curr_end + 1] for curr, other in zip(current_targets, other_targets): if curr != other: return None # A wildcard node can match more than one target, so only the # target index is advanced new_state = [(node_ind, target_ind + 1)] # Only move on to the next node if there is one if node_ind < len(nodes) - 1: new_state.append((node_ind + 1, target_ind + 1)) return new_state, match_attempt else: # If we're not at a wildcard, then make sure we haven't exhausted # nodes but not targets, since in this case one node can only match # one target if node_ind >= len(nodes) - 1 and target_ind < len(targets) - 1: return None match_attempt = node.matches(target) if match_attempt: return [(node_ind + 1, target_ind + 1)], match_attempt elif node == target: return [(node_ind + 1, target_ind + 1)], None else: return None @staticmethod def _matches_match_wilds(dictionary, wildcard_ind, nodes, targets): """Determine matches of a wildcard with sub-expression in `target`.""" wildcard = nodes[wildcard_ind] begin, end = dictionary[wildcard_ind] terms = targets[begin:end + 1] # TODO: Should this be self.func? mul = Mul(*terms) if len(terms) > 1 else terms[0] return wildcard.matches(mul) @staticmethod def _matches_get_other_nodes(dictionary, nodes, node_ind): """Find other wildcards that may have already been matched.""" other_node_inds = [] for ind in dictionary: if nodes[ind] == nodes[node_ind]: other_node_inds.append(ind) return other_node_inds @staticmethod def _combine_inverse(lhs, rhs): """ Returns lhs/rhs, but treats arguments like symbols, so things like oo/oo return 1 (instead of a nan) and ``I`` behaves like a symbol instead of sqrt(-1). """ from sympy.simplify.simplify import signsimp from .symbol import Dummy if lhs == rhs: return S.One def check(l, r): if l.is_Float and r.is_comparable: # if both objects are added to 0 they will share the same "normalization" # and are more likely to compare the same. Since Add(foo, 0) will not allow # the 0 to pass, we use __add__ directly. return l.__add__(0) == r.evalf().__add__(0) return False if check(lhs, rhs) or check(rhs, lhs): return S.One if any(i.is_Pow or i.is_Mul for i in (lhs, rhs)): # gruntz and limit wants a literal I to not combine # with a power of -1 d = Dummy('I') _i = {S.ImaginaryUnit: d} i_ = {d: S.ImaginaryUnit} a = lhs.xreplace(_i).as_powers_dict() b = rhs.xreplace(_i).as_powers_dict() blen = len(b) for bi in tuple(b.keys()): if bi in a: a[bi] -= b.pop(bi) if not a[bi]: a.pop(bi) if len(b) != blen: lhs = Mul(*[k**v for k, v in a.items()]).xreplace(i_) rhs = Mul(*[k**v for k, v in b.items()]).xreplace(i_) rv = lhs/rhs srv = signsimp(rv) return srv if srv.is_Number else rv def as_powers_dict(self): d = defaultdict(int) for term in self.args: for b, e in term.as_powers_dict().items(): d[b] += e return d def as_numer_denom(self): # don't use _from_args to rebuild the numerators and denominators # as the order is not guaranteed to be the same once they have # been separated from each other numers, denoms = list(zip(*[f.as_numer_denom() for f in self.args])) return self.func(*numers), self.func(*denoms) def as_base_exp(self): e1 = None bases = [] nc = 0 for m in self.args: b, e = m.as_base_exp() if not b.is_commutative: nc += 1 if e1 is None: e1 = e elif e != e1 or nc > 1: return self, S.One bases.append(b) return self.func(*bases), e1 def _eval_is_polynomial(self, syms): return all(term._eval_is_polynomial(syms) for term in self.args) def _eval_is_rational_function(self, syms): return all(term._eval_is_rational_function(syms) for term in self.args) def _eval_is_meromorphic(self, x, a): return _fuzzy_group((arg.is_meromorphic(x, a) for arg in self.args), quick_exit=True) def _eval_is_algebraic_expr(self, syms): return all(term._eval_is_algebraic_expr(syms) for term in self.args) _eval_is_commutative = lambda self: _fuzzy_group( a.is_commutative for a in self.args) def _eval_is_complex(self): comp = _fuzzy_group(a.is_complex for a in self.args) if comp is False: if any(a.is_infinite for a in self.args): if any(a.is_zero is not False for a in self.args): return None return False return comp def _eval_is_finite(self): if all(a.is_finite for a in self.args): return True if any(a.is_infinite for a in self.args): if all(a.is_zero is False for a in self.args): return False def _eval_is_infinite(self): if any(a.is_infinite for a in self.args): if any(a.is_zero for a in self.args): return S.NaN.is_infinite if any(a.is_zero is None for a in self.args): return None return True def _eval_is_rational(self): r = _fuzzy_group((a.is_rational for a in self.args), quick_exit=True) if r: return r elif r is False: return self.is_zero def _eval_is_algebraic(self): r = _fuzzy_group((a.is_algebraic for a in self.args), quick_exit=True) if r: return r elif r is False: return self.is_zero def _eval_is_zero(self): zero = infinite = False for a in self.args: z = a.is_zero if z: if infinite: return # 0*oo is nan and nan.is_zero is None zero = True else: if not a.is_finite: if zero: return # 0*oo is nan and nan.is_zero is None infinite = True if zero is False and z is None: # trap None zero = None return zero # without involving odd/even checks this code would suffice: #_eval_is_integer = lambda self: _fuzzy_group( # (a.is_integer for a in self.args), quick_exit=True) def _eval_is_integer(self): from sympy import trailing is_rational = self._eval_is_rational() if is_rational is False: return False numerators = [] denominators = [] for a in self.args: if a.is_integer: if abs(a) is not S.One: numerators.append(a) elif a.is_Rational: n, d = a.as_numer_denom() if abs(n) is not S.One: numerators.append(n) if d is not S.One: denominators.append(d) elif a.is_Pow: b, e = a.as_base_exp() if not b.is_integer or not e.is_integer: return if e.is_negative: denominators.append(2 if a is S.Half else Pow(a, S.NegativeOne)) else: # for integer b and positive integer e: a = b**e would be integer assert not e.is_positive # for self being rational and e equal to zero: a = b**e would be 1 assert not e.is_zero return # sign of e unknown -> self.is_integer cannot be decided else: return if not denominators: return True allodd = lambda x: all(i.is_odd for i in x) alleven = lambda x: all(i.is_even for i in x) anyeven = lambda x: any(i.is_even for i in x) if allodd(numerators) and anyeven(denominators): return False elif anyeven(numerators) and denominators == [2]: return True elif alleven(numerators) and allodd(denominators ) and (Mul(*denominators, evaluate=False) - 1 ).is_positive: return False if len(denominators) == 1: d = denominators[0] if d.is_Integer and d.is_even: # if minimal power of 2 in num vs den is not # negative then we have an integer if (Add(*[i.as_base_exp()[1] for i in numerators if i.is_even]) - trailing(d.p) ).is_nonnegative: return True if len(numerators) == 1: n = numerators[0] if n.is_Integer and n.is_even: # if minimal power of 2 in den vs num is positive # then we have have a non-integer if (Add(*[i.as_base_exp()[1] for i in denominators if i.is_even]) - trailing(n.p) ).is_positive: return False def _eval_is_polar(self): has_polar = any(arg.is_polar for arg in self.args) return has_polar and \ all(arg.is_polar or arg.is_positive for arg in self.args) def _eval_is_extended_real(self): return self._eval_real_imag(True) def _eval_real_imag(self, real): zero = False t_not_re_im = None for t in self.args: if (t.is_complex or t.is_infinite) is False and t.is_extended_real is False: return False elif t.is_imaginary: # I real = not real elif t.is_extended_real: # 2 if not zero: z = t.is_zero if not z and zero is False: zero = z elif z: if all(a.is_finite for a in self.args): return True return elif t.is_extended_real is False: # symbolic or literal like `2 + I` or symbolic imaginary if t_not_re_im: return # complex terms might cancel t_not_re_im = t elif t.is_imaginary is False: # symbolic like `2` or `2 + I` if t_not_re_im: return # complex terms might cancel t_not_re_im = t else: return if t_not_re_im: if t_not_re_im.is_extended_real is False: if real: # like 3 return zero # 3*(smthng like 2 + I or i) is not real if t_not_re_im.is_imaginary is False: # symbolic 2 or 2 + I if not real: # like I return zero # I*(smthng like 2 or 2 + I) is not real elif zero is False: return real # can't be trumped by 0 elif real: return real # doesn't matter what zero is def _eval_is_imaginary(self): z = self.is_zero if z: return False if self.is_finite is False: return False elif z is False and self.is_finite is True: return self._eval_real_imag(False) def _eval_is_hermitian(self): return self._eval_herm_antiherm(True) def _eval_herm_antiherm(self, real): one_nc = zero = one_neither = False for t in self.args: if not t.is_commutative: if one_nc: return one_nc = True if t.is_antihermitian: real = not real elif t.is_hermitian: if not zero: z = t.is_zero if not z and zero is False: zero = z elif z: if all(a.is_finite for a in self.args): return True return elif t.is_hermitian is False: if one_neither: return one_neither = True else: return if one_neither: if real: return zero elif zero is False or real: return real def _eval_is_antihermitian(self): z = self.is_zero if z: return False elif z is False: return self._eval_herm_antiherm(False) def _eval_is_irrational(self): for t in self.args: a = t.is_irrational if a: others = list(self.args) others.remove(t) if all((x.is_rational and fuzzy_not(x.is_zero)) is True for x in others): return True return if a is None: return if all(x.is_real for x in self.args): return False def _eval_is_extended_positive(self): """Return True if self is positive, False if not, and None if it cannot be determined. Explanation =========== This algorithm is non-recursive and works by keeping track of the sign which changes when a negative or nonpositive is encountered. Whether a nonpositive or nonnegative is seen is also tracked since the presence of these makes it impossible to return True, but possible to return False if the end result is nonpositive. e.g. pos * neg * nonpositive -> pos or zero -> None is returned pos * neg * nonnegative -> neg or zero -> False is returned """ return self._eval_pos_neg(1) def _eval_pos_neg(self, sign): saw_NON = saw_NOT = False for t in self.args: if t.is_extended_positive: continue elif t.is_extended_negative: sign = -sign elif t.is_zero: if all(a.is_finite for a in self.args): return False return elif t.is_extended_nonpositive: sign = -sign saw_NON = True elif t.is_extended_nonnegative: saw_NON = True # FIXME: is_positive/is_negative is False doesn't take account of # Symbol('x', infinite=True, extended_real=True) which has # e.g. is_positive is False but has uncertain sign. elif t.is_positive is False: sign = -sign if saw_NOT: return saw_NOT = True elif t.is_negative is False: if saw_NOT: return saw_NOT = True else: return if sign == 1 and saw_NON is False and saw_NOT is False: return True if sign < 0: return False def _eval_is_extended_negative(self): return self._eval_pos_neg(-1) def _eval_is_odd(self): from sympy import trailing, fraction is_integer = self.is_integer if is_integer: if self.is_zero: return False n, d = fraction(self) if d.is_Integer and d.is_even: # if minimal power of 2 in num vs den is # positive then we have an even number if (Add(*[i.as_base_exp()[1] for i in Mul.make_args(n) if i.is_even]) - trailing(d.p) ).is_positive: return False return r, acc = True, 1 for t in self.args: if abs(t) is S.One: continue assert t.is_integer if t.is_even: return False if r is False: pass elif acc != 1 and (acc + t).is_odd: r = False elif t.is_even is None: r = None acc = t return r return is_integer # !integer -> !odd def _eval_is_even(self): from sympy import trailing, fraction is_integer = self.is_integer if is_integer: return fuzzy_not(self.is_odd) n, d = fraction(self) if n.is_Integer and n.is_even: # if minimal power of 2 in den vs num is not # negative then this is not an integer and # can't be even if (Add(*[i.as_base_exp()[1] for i in Mul.make_args(d) if i.is_even]) - trailing(n.p) ).is_nonnegative: return False return is_integer def _eval_is_composite(self): """ Here we count the number of arguments that have a minimum value greater than two. If there are more than one of such a symbol then the result is composite. Else, the result cannot be determined. """ number_of_args = 0 # count of symbols with minimum value greater than one for arg in self.args: if not (arg.is_integer and arg.is_positive): return None if (arg-1).is_positive: number_of_args += 1 if number_of_args > 1: return True def _eval_subs(self, old, new): from sympy.functions.elementary.complexes import sign from sympy.ntheory.factor_ import multiplicity from sympy.simplify.powsimp import powdenest from sympy.simplify.radsimp import fraction if not old.is_Mul: return None # try keep replacement literal so -2*x doesn't replace 4*x if old.args[0].is_Number and old.args[0] < 0: if self.args[0].is_Number: if self.args[0] < 0: return self._subs(-old, -new) return None def base_exp(a): # if I and -1 are in a Mul, they get both end up with # a -1 base (see issue 6421); all we want here are the # true Pow or exp separated into base and exponent from sympy import exp if a.is_Pow or isinstance(a, exp): return a.as_base_exp() return a, S.One def breakup(eq): """break up powers of eq when treated as a Mul: b**(Rational*e) -> b**e, Rational commutatives come back as a dictionary {b**e: Rational} noncommutatives come back as a list [(b**e, Rational)] """ (c, nc) = (defaultdict(int), list()) for a in Mul.make_args(eq): a = powdenest(a) (b, e) = base_exp(a) if e is not S.One: (co, _) = e.as_coeff_mul() b = Pow(b, e/co) e = co if a.is_commutative: c[b] += e else: nc.append([b, e]) return (c, nc) def rejoin(b, co): """ Put rational back with exponent; in general this is not ok, but since we took it from the exponent for analysis, it's ok to put it back. """ (b, e) = base_exp(b) return Pow(b, e*co) def ndiv(a, b): """if b divides a in an extractive way (like 1/4 divides 1/2 but not vice versa, and 2/5 does not divide 1/3) then return the integer number of times it divides, else return 0. """ if not b.q % a.q or not a.q % b.q: return int(a/b) return 0 # give Muls in the denominator a chance to be changed (see issue 5651) # rv will be the default return value rv = None n, d = fraction(self) self2 = self if d is not S.One: self2 = n._subs(old, new)/d._subs(old, new) if not self2.is_Mul: return self2._subs(old, new) if self2 != self: rv = self2 # Now continue with regular substitution. # handle the leading coefficient and use it to decide if anything # should even be started; we always know where to find the Rational # so it's a quick test co_self = self2.args[0] co_old = old.args[0] co_xmul = None if co_old.is_Rational and co_self.is_Rational: # if coeffs are the same there will be no updating to do # below after breakup() step; so skip (and keep co_xmul=None) if co_old != co_self: co_xmul = co_self.extract_multiplicatively(co_old) elif co_old.is_Rational: return rv # break self and old into factors (c, nc) = breakup(self2) (old_c, old_nc) = breakup(old) # update the coefficients if we had an extraction # e.g. if co_self were 2*(3/35*x)**2 and co_old = 3/5 # then co_self in c is replaced by (3/5)**2 and co_residual # is 2*(1/7)**2 if co_xmul and co_xmul.is_Rational and abs(co_old) != 1: mult = S(multiplicity(abs(co_old), co_self)) c.pop(co_self) if co_old in c: c[co_old] += mult else: c[co_old] = mult co_residual = co_self/co_old**mult else: co_residual = 1 # do quick tests to see if we can't succeed ok = True if len(old_nc) > len(nc): # more non-commutative terms ok = False elif len(old_c) > len(c): # more commutative terms ok = False elif {i[0] for i in old_nc}.difference({i[0] for i in nc}): # unmatched non-commutative bases ok = False elif set(old_c).difference(set(c)): # unmatched commutative terms ok = False elif any(sign(c[b]) != sign(old_c[b]) for b in old_c): # differences in sign ok = False if not ok: return rv if not old_c: cdid = None else: rat = [] for (b, old_e) in old_c.items(): c_e = c[b] rat.append(ndiv(c_e, old_e)) if not rat[-1]: return rv cdid = min(rat) if not old_nc: ncdid = None for i in range(len(nc)): nc[i] = rejoin(*nc[i]) else: ncdid = 0 # number of nc replacements we did take = len(old_nc) # how much to look at each time limit = cdid or S.Infinity # max number that we can take failed = [] # failed terms will need subs if other terms pass i = 0 while limit and i + take <= len(nc): hit = False # the bases must be equivalent in succession, and # the powers must be extractively compatible on the # first and last factor but equal in between. rat = [] for j in range(take): if nc[i + j][0] != old_nc[j][0]: break elif j == 0: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif j == take - 1: rat.append(ndiv(nc[i + j][1], old_nc[j][1])) elif nc[i + j][1] != old_nc[j][1]: break else: rat.append(1) j += 1 else: ndo = min(rat) if ndo: if take == 1: if cdid: ndo = min(cdid, ndo) nc[i] = Pow(new, ndo)*rejoin(nc[i][0], nc[i][1] - ndo*old_nc[0][1]) else: ndo = 1 # the left residual l = rejoin(nc[i][0], nc[i][1] - ndo* old_nc[0][1]) # eliminate all middle terms mid = new # the right residual (which may be the same as the middle if take == 2) ir = i + take - 1 r = (nc[ir][0], nc[ir][1] - ndo* old_nc[-1][1]) if r[1]: if i + take < len(nc): nc[i:i + take] = [l*mid, r] else: r = rejoin(*r) nc[i:i + take] = [l*mid*r] else: # there was nothing left on the right nc[i:i + take] = [l*mid] limit -= ndo ncdid += ndo hit = True if not hit: # do the subs on this failing factor failed.append(i) i += 1 else: if not ncdid: return rv # although we didn't fail, certain nc terms may have # failed so we rebuild them after attempting a partial # subs on them failed.extend(range(i, len(nc))) for i in failed: nc[i] = rejoin(*nc[i]).subs(old, new) # rebuild the expression if cdid is None: do = ncdid elif ncdid is None: do = cdid else: do = min(ncdid, cdid) margs = [] for b in c: if b in old_c: # calculate the new exponent e = c[b] - old_c[b]*do margs.append(rejoin(b, e)) else: margs.append(rejoin(b.subs(old, new), c[b])) if cdid and not ncdid: # in case we are replacing commutative with non-commutative, # we want the new term to come at the front just like the # rest of this routine margs = [Pow(new, cdid)] + margs return co_residual*self2.func(*margs)*self2.func(*nc) def _eval_nseries(self, x, n, logx, cdir=0): from sympy import degree, Mul, Order, ceiling, powsimp, PolynomialError, PoleError from itertools import product def coeff_exp(term, x): lt = term.as_coeff_exponent(x) if lt[0].has(x): try: lt = term.leadterm(x) except ValueError: return term, S.Zero return lt ords = [] try: for t in self.args: coeff, exp = t.leadterm(x, logx=logx) if not coeff.has(x): ords.append((t, exp)) else: raise ValueError n0 = sum(t[1] for t in ords if t[1].is_number) facs = [] for t, m in ords: n1 = ceiling(n - n0 + (m if m.is_number else 0)) s = t.nseries(x, n=n1, logx=logx, cdir=cdir) ns = s.getn() if ns is not None: if ns < n1: # less than expected n -= n1 - ns # reduce n facs.append(s) except (ValueError, NotImplementedError, TypeError, AttributeError, PoleError): n0 = sympify(sum(t[1] for t in ords if t[1].is_number)) if n0.is_nonnegative: n0 = S.Zero facs = [t.nseries(x, n=ceiling(n-n0), logx=logx, cdir=cdir) for t in self.args] res = powsimp(self.func(*facs).expand(), combine='exp', deep=True) if res.has(Order): res += Order(x**n, x) return res res = S.Zero ords2 = [Add.make_args(factor) for factor in facs] for fac in product(*ords2): ords3 = [coeff_exp(term, x) for term in fac] coeffs, powers = zip(*ords3) power = sum(powers) if (power - n).is_negative: res += Mul(*coeffs)*(x**power) def max_degree(e, x): if e is x: return S.One if e.is_Atom: return S.Zero if e.is_Add: return max(max_degree(a, x) for a in e.args) if e.is_Mul: return Add(*[max_degree(a, x) for a in e.args]) if e.is_Pow: return max_degree(e.base, x)*e.exp return S.Zero if self.is_polynomial(x): try: if max_degree(self, x) >= n or degree(self, x) != degree(res, x): res += Order(x**n, x) except PolynomialError: pass else: return res if res != self: res += Order(x**n, x) return res def _eval_as_leading_term(self, x, logx=None, cdir=0): return self.func(*[t.as_leading_term(x, logx=logx, cdir=cdir) for t in self.args]) def _eval_conjugate(self): return self.func(*[t.conjugate() for t in self.args]) def _eval_transpose(self): return self.func(*[t.transpose() for t in self.args[::-1]]) def _eval_adjoint(self): return self.func(*[t.adjoint() for t in self.args[::-1]]) def as_content_primitive(self, radical=False, clear=True): """Return the tuple (R, self/R) where R is the positive Rational extracted from self. Examples ======== >>> from sympy import sqrt >>> (-3*sqrt(2)*(2 - 2*sqrt(2))).as_content_primitive() (6, -sqrt(2)*(1 - sqrt(2))) See docstring of Expr.as_content_primitive for more examples. """ coef = S.One args = [] for i, a in enumerate(self.args): c, p = a.as_content_primitive(radical=radical, clear=clear) coef *= c if p is not S.One: args.append(p) # don't use self._from_args here to reconstruct args # since there may be identical args now that should be combined # e.g. (2+2*x)*(3+3*x) should be (6, (1 + x)**2) not (6, (1+x)*(1+x)) return coef, self.func(*args) def as_ordered_factors(self, order=None): """Transform an expression into an ordered list of factors. Examples ======== >>> from sympy import sin, cos >>> from sympy.abc import x, y >>> (2*x*y*sin(x)*cos(x)).as_ordered_factors() [2, x, y, sin(x), cos(x)] """ cpart, ncpart = self.args_cnc() cpart.sort(key=lambda expr: expr.sort_key(order=order)) return cpart + ncpart @property def _sorted_args(self): return tuple(self.as_ordered_factors()) mul = AssocOpDispatcher('mul') def prod(a, start=1): """Return product of elements of a. Start with int 1 so if only ints are included then an int result is returned. Examples ======== >>> from sympy import prod, S >>> prod(range(3)) 0 >>> type(_) is int True >>> prod([S(2), 3]) 6 >>> _.is_Integer True You can start the product at something other than 1: >>> prod([1, 2], 3) 6 """ return reduce(operator.mul, a, start) def _keep_coeff(coeff, factors, clear=True, sign=False): """Return ``coeff*factors`` unevaluated if necessary. If ``clear`` is False, do not keep the coefficient as a factor if it can be distributed on a single factor such that one or more terms will still have integer coefficients. If ``sign`` is True, allow a coefficient of -1 to remain factored out. Examples ======== >>> from sympy.core.mul import _keep_coeff >>> from sympy.abc import x, y >>> from sympy import S >>> _keep_coeff(S.Half, x + 2) (x + 2)/2 >>> _keep_coeff(S.Half, x + 2, clear=False) x/2 + 1 >>> _keep_coeff(S.Half, (x + 2)*y, clear=False) y*(x + 2)/2 >>> _keep_coeff(S(-1), x + y) -x - y >>> _keep_coeff(S(-1), x + y, sign=True) -(x + y) """ if not coeff.is_Number: if factors.is_Number: factors, coeff = coeff, factors else: return coeff*factors if factors is S.One: return coeff if coeff is S.One: return factors elif coeff is S.NegativeOne and not sign: return -factors elif factors.is_Add: if not clear and coeff.is_Rational and coeff.q != 1: args = [i.as_coeff_Mul() for i in factors.args] args = [(_keep_coeff(c, coeff), m) for c, m in args] if any(c == int(c) for c, _ in args): return Add._from_args([Mul._from_args( i[1:] if i[0] == 1 else i) for i in args]) return Mul(coeff, factors, evaluate=False) elif factors.is_Mul: margs = list(factors.args) if margs[0].is_Number: margs[0] *= coeff if margs[0] == 1: margs.pop(0) else: margs.insert(0, coeff) return Mul._from_args(margs) else: m = coeff*factors if m.is_Number and not factors.is_Number: m = Mul._from_args((coeff, factors)) return m def expand_2arg(e): from sympy.simplify.simplify import bottom_up def do(e): if e.is_Mul: c, r = e.as_coeff_Mul() if c.is_Number and r.is_Add: return _unevaluated_Add(*[c*ri for ri in r.args]) return e return bottom_up(e, do) from .numbers import Rational from .power import Pow from .add import Add, _addsort, _unevaluated_Add sympy-sympy-1.9/sympy/core/multidimensional.py000066400000000000000000000104221412543434000217620ustar00rootroot00000000000000""" Provides functionality for multidimensional usage of scalar-functions. Read the vectorize docstring for more details. """ from sympy.core.decorators import wraps def apply_on_element(f, args, kwargs, n): """ Returns a structure with the same dimension as the specified argument, where each basic element is replaced by the function f applied on it. All other arguments stay the same. """ # Get the specified argument. if isinstance(n, int): structure = args[n] is_arg = True elif isinstance(n, str): structure = kwargs[n] is_arg = False # Define reduced function that is only dependent on the specified argument. def f_reduced(x): if hasattr(x, "__iter__"): return list(map(f_reduced, x)) else: if is_arg: args[n] = x else: kwargs[n] = x return f(*args, **kwargs) # f_reduced will call itself recursively so that in the end f is applied to # all basic elements. return list(map(f_reduced, structure)) def iter_copy(structure): """ Returns a copy of an iterable object (also copying all embedded iterables). """ l = [] for i in structure: if hasattr(i, "__iter__"): l.append(iter_copy(i)) else: l.append(i) return l def structure_copy(structure): """ Returns a copy of the given structure (numpy-array, list, iterable, ..). """ if hasattr(structure, "copy"): return structure.copy() return iter_copy(structure) class vectorize: """ Generalizes a function taking scalars to accept multidimensional arguments. Examples ======== >>> from sympy import diff, sin, symbols, Function >>> from sympy.core.multidimensional import vectorize >>> x, y, z = symbols('x y z') >>> f, g, h = list(map(Function, 'fgh')) >>> @vectorize(0) ... def vsin(x): ... return sin(x) >>> vsin([1, x, y]) [sin(1), sin(x), sin(y)] >>> @vectorize(0, 1) ... def vdiff(f, y): ... return diff(f, y) >>> vdiff([f(x, y, z), g(x, y, z), h(x, y, z)], [x, y, z]) [[Derivative(f(x, y, z), x), Derivative(f(x, y, z), y), Derivative(f(x, y, z), z)], [Derivative(g(x, y, z), x), Derivative(g(x, y, z), y), Derivative(g(x, y, z), z)], [Derivative(h(x, y, z), x), Derivative(h(x, y, z), y), Derivative(h(x, y, z), z)]] """ def __init__(self, *mdargs): """ The given numbers and strings characterize the arguments that will be treated as data structures, where the decorated function will be applied to every single element. If no argument is given, everything is treated multidimensional. """ for a in mdargs: if not isinstance(a, (int, str)): raise TypeError("a is of invalid type") self.mdargs = mdargs def __call__(self, f): """ Returns a wrapper for the one-dimensional function that can handle multidimensional arguments. """ @wraps(f) def wrapper(*args, **kwargs): # Get arguments that should be treated multidimensional if self.mdargs: mdargs = self.mdargs else: mdargs = range(len(args)) + kwargs.keys() arglength = len(args) for n in mdargs: if isinstance(n, int): if n >= arglength: continue entry = args[n] is_arg = True elif isinstance(n, str): try: entry = kwargs[n] except KeyError: continue is_arg = False if hasattr(entry, "__iter__"): # Create now a copy of the given array and manipulate then # the entries directly. if is_arg: args = list(args) args[n] = structure_copy(entry) else: kwargs[n] = structure_copy(entry) result = apply_on_element(wrapper, args, kwargs, n) return result return f(*args, **kwargs) return wrapper sympy-sympy-1.9/sympy/core/numbers.py000066400000000000000000003561161412543434000200750ustar00rootroot00000000000000import numbers import decimal import fractions import math import re as regex import sys from .containers import Tuple from .sympify import (SympifyError, converter, sympify, _convert_numpy_types, _sympify, _is_numpy_instance) from .singleton import S, Singleton from .expr import Expr, AtomicExpr from .evalf import pure_complex from .decorators import _sympifyit from .cache import cacheit, clear_cache from .logic import fuzzy_not from sympy.core.compatibility import (as_int, HAS_GMPY, SYMPY_INTS, gmpy) from sympy.core.cache import lru_cache from .kind import NumberKind from sympy.multipledispatch import dispatch import mpmath import mpmath.libmp as mlib from mpmath.libmp import bitcount from mpmath.libmp.backend import MPZ from mpmath.libmp import mpf_pow, mpf_pi, mpf_e, phi_fixed from mpmath.ctx_mp import mpnumeric from mpmath.libmp.libmpf import ( finf as _mpf_inf, fninf as _mpf_ninf, fnan as _mpf_nan, fzero, _normalize as mpf_normalize, prec_to_dps) from sympy.utilities.misc import debug, filldedent from .parameters import global_parameters from sympy.utilities.exceptions import SymPyDeprecationWarning rnd = mlib.round_nearest _LOG2 = math.log(2) def comp(z1, z2, tol=None): """Return a bool indicating whether the error between z1 and z2 is <= tol. Examples ======== If ``tol`` is None then True will be returned if ``abs(z1 - z2)*10**p <= 5`` where ``p`` is minimum value of the decimal precision of each value. >>> from sympy.core.numbers import comp, pi >>> pi4 = pi.n(4); pi4 3.142 >>> comp(_, 3.142) True >>> comp(pi4, 3.141) False >>> comp(pi4, 3.143) False A comparison of strings will be made if ``z1`` is a Number and ``z2`` is a string or ``tol`` is ''. >>> comp(pi4, 3.1415) True >>> comp(pi4, 3.1415, '') False When ``tol`` is provided and ``z2`` is non-zero and ``|z1| > 1`` the error is normalized by ``|z1|``: >>> abs(pi4 - 3.14)/pi4 0.000509791731426756 >>> comp(pi4, 3.14, .001) # difference less than 0.1% True >>> comp(pi4, 3.14, .0005) # difference less than 0.1% False When ``|z1| <= 1`` the absolute error is used: >>> 1/pi4 0.3183 >>> abs(1/pi4 - 0.3183)/(1/pi4) 3.07371499106316e-5 >>> abs(1/pi4 - 0.3183) 9.78393554684764e-6 >>> comp(1/pi4, 0.3183, 1e-5) True To see if the absolute error between ``z1`` and ``z2`` is less than or equal to ``tol``, call this as ``comp(z1 - z2, 0, tol)`` or ``comp(z1 - z2, tol=tol)``: >>> abs(pi4 - 3.14) 0.00160156249999988 >>> comp(pi4 - 3.14, 0, .002) True >>> comp(pi4 - 3.14, 0, .001) False """ if type(z2) is str: if not pure_complex(z1, or_real=True): raise ValueError('when z2 is a str z1 must be a Number') return str(z1) == z2 if not z1: z1, z2 = z2, z1 if not z1: return True if not tol: a, b = z1, z2 if tol == '': return str(a) == str(b) if tol is None: a, b = sympify(a), sympify(b) if not all(i.is_number for i in (a, b)): raise ValueError('expecting 2 numbers') fa = a.atoms(Float) fb = b.atoms(Float) if not fa and not fb: # no floats -- compare exactly return a == b # get a to be pure_complex for do in range(2): ca = pure_complex(a, or_real=True) if not ca: if fa: a = a.n(prec_to_dps(min([i._prec for i in fa]))) ca = pure_complex(a, or_real=True) break else: fa, fb = fb, fa a, b = b, a cb = pure_complex(b) if not cb and fb: b = b.n(prec_to_dps(min([i._prec for i in fb]))) cb = pure_complex(b, or_real=True) if ca and cb and (ca[1] or cb[1]): return all(comp(i, j) for i, j in zip(ca, cb)) tol = 10**prec_to_dps(min(a._prec, getattr(b, '_prec', a._prec))) return int(abs(a - b)*tol) <= 5 diff = abs(z1 - z2) az1 = abs(z1) if z2 and az1 > 1: return diff/az1 <= tol else: return diff <= tol def mpf_norm(mpf, prec): """Return the mpf tuple normalized appropriately for the indicated precision after doing a check to see if zero should be returned or not when the mantissa is 0. ``mpf_normlize`` always assumes that this is zero, but it may not be since the mantissa for mpf's values "+inf", "-inf" and "nan" have a mantissa of zero, too. Note: this is not intended to validate a given mpf tuple, so sending mpf tuples that were not created by mpmath may produce bad results. This is only a wrapper to ``mpf_normalize`` which provides the check for non- zero mpfs that have a 0 for the mantissa. """ sign, man, expt, bc = mpf if not man: # hack for mpf_normalize which does not do this; # it assumes that if man is zero the result is 0 # (see issue 6639) if not bc: return fzero else: # don't change anything; this should already # be a well formed mpf tuple return mpf # Necessary if mpmath is using the gmpy backend from mpmath.libmp.backend import MPZ rv = mpf_normalize(sign, MPZ(man), expt, bc, prec, rnd) return rv # TODO: we should use the warnings module _errdict = {"divide": False} def seterr(divide=False): """ Should sympy raise an exception on 0/0 or return a nan? divide == True .... raise an exception divide == False ... return nan """ if _errdict["divide"] != divide: clear_cache() _errdict["divide"] = divide def _as_integer_ratio(p): neg_pow, man, expt, bc = getattr(p, '_mpf_', mpmath.mpf(p)._mpf_) p = [1, -1][neg_pow % 2]*man if expt < 0: q = 2**-expt else: q = 1 p *= 2**expt return int(p), int(q) def _decimal_to_Rational_prec(dec): """Convert an ordinary decimal instance to a Rational.""" if not dec.is_finite(): raise TypeError("dec must be finite, got %s." % dec) s, d, e = dec.as_tuple() prec = len(d) if e >= 0: # it's an integer rv = Integer(int(dec)) else: s = (-1)**s d = sum([di*10**i for i, di in enumerate(reversed(d))]) rv = Rational(s*d, 10**-e) return rv, prec _floatpat = regex.compile(r"[-+]?((\d*\.\d+)|(\d+\.?))") def _literal_float(f): """Return True if n starts like a floating point number.""" return bool(_floatpat.match(f)) # (a,b) -> gcd(a,b) # TODO caching with decorator, but not to degrade performance @lru_cache(1024) def igcd(*args): """Computes nonnegative integer greatest common divisor. Explanation =========== The algorithm is based on the well known Euclid's algorithm. To improve speed, igcd() has its own caching mechanism implemented. Examples ======== >>> from sympy.core.numbers import igcd >>> igcd(2, 4) 2 >>> igcd(5, 10, 15) 5 """ if len(args) < 2: raise TypeError( 'igcd() takes at least 2 arguments (%s given)' % len(args)) args_temp = [abs(as_int(i)) for i in args] if 1 in args_temp: return 1 a = args_temp.pop() if HAS_GMPY: # Using gmpy if present to speed up. for b in args_temp: a = gmpy.gcd(a, b) if b else a return as_int(a) for b in args_temp: a = math.gcd(a, b) return a igcd2 = math.gcd def igcd_lehmer(a, b): """Computes greatest common divisor of two integers. Explanation =========== Euclid's algorithm for the computation of the greatest common divisor gcd(a, b) of two (positive) integers a and b is based on the division identity a = q*b + r, where the quotient q and the remainder r are integers and 0 <= r < b. Then each common divisor of a and b divides r, and it follows that gcd(a, b) == gcd(b, r). The algorithm works by constructing the sequence r0, r1, r2, ..., where r0 = a, r1 = b, and each rn is the remainder from the division of the two preceding elements. In Python, q = a // b and r = a % b are obtained by the floor division and the remainder operations, respectively. These are the most expensive arithmetic operations, especially for large a and b. Lehmer's algorithm is based on the observation that the quotients qn = r(n-1) // rn are in general small integers even when a and b are very large. Hence the quotients can be usually determined from a relatively small number of most significant bits. The efficiency of the algorithm is further enhanced by not computing each long remainder in Euclid's sequence. The remainders are linear combinations of a and b with integer coefficients derived from the quotients. The coefficients can be computed as far as the quotients can be determined from the chosen most significant parts of a and b. Only then a new pair of consecutive remainders is computed and the algorithm starts anew with this pair. References ========== .. [1] https://en.wikipedia.org/wiki/Lehmer%27s_GCD_algorithm """ a, b = abs(as_int(a)), abs(as_int(b)) if a < b: a, b = b, a # The algorithm works by using one or two digit division # whenever possible. The outer loop will replace the # pair (a, b) with a pair of shorter consecutive elements # of the Euclidean gcd sequence until a and b # fit into two Python (long) int digits. nbits = 2*sys.int_info.bits_per_digit while a.bit_length() > nbits and b != 0: # Quotients are mostly small integers that can # be determined from most significant bits. n = a.bit_length() - nbits x, y = int(a >> n), int(b >> n) # most significant bits # Elements of the Euclidean gcd sequence are linear # combinations of a and b with integer coefficients. # Compute the coefficients of consecutive pairs # a' = A*a + B*b, b' = C*a + D*b # using small integer arithmetic as far as possible. A, B, C, D = 1, 0, 0, 1 # initial values while True: # The coefficients alternate in sign while looping. # The inner loop combines two steps to keep track # of the signs. # At this point we have # A > 0, B <= 0, C <= 0, D > 0, # x' = x + B <= x < x" = x + A, # y' = y + C <= y < y" = y + D, # and # x'*N <= a' < x"*N, y'*N <= b' < y"*N, # where N = 2**n. # Now, if y' > 0, and x"//y' and x'//y" agree, # then their common value is equal to q = a'//b'. # In addition, # x'%y" = x' - q*y" < x" - q*y' = x"%y', # and # (x'%y")*N < a'%b' < (x"%y')*N. # On the other hand, we also have x//y == q, # and therefore # x'%y" = x + B - q*(y + D) = x%y + B', # x"%y' = x + A - q*(y + C) = x%y + A', # where # B' = B - q*D < 0, A' = A - q*C > 0. if y + C <= 0: break q = (x + A) // (y + C) # Now x'//y" <= q, and equality holds if # x' - q*y" = (x - q*y) + (B - q*D) >= 0. # This is a minor optimization to avoid division. x_qy, B_qD = x - q*y, B - q*D if x_qy + B_qD < 0: break # Next step in the Euclidean sequence. x, y = y, x_qy A, B, C, D = C, D, A - q*C, B_qD # At this point the signs of the coefficients # change and their roles are interchanged. # A <= 0, B > 0, C > 0, D < 0, # x' = x + A <= x < x" = x + B, # y' = y + D < y < y" = y + C. if y + D <= 0: break q = (x + B) // (y + D) x_qy, A_qC = x - q*y, A - q*C if x_qy + A_qC < 0: break x, y = y, x_qy A, B, C, D = C, D, A_qC, B - q*D # Now the conditions on top of the loop # are again satisfied. # A > 0, B < 0, C < 0, D > 0. if B == 0: # This can only happen when y == 0 in the beginning # and the inner loop does nothing. # Long division is forced. a, b = b, a % b continue # Compute new long arguments using the coefficients. a, b = A*a + B*b, C*a + D*b # Small divisors. Finish with the standard algorithm. while b: a, b = b, a % b return a def ilcm(*args): """Computes integer least common multiple. Examples ======== >>> from sympy.core.numbers import ilcm >>> ilcm(5, 10) 10 >>> ilcm(7, 3) 21 >>> ilcm(5, 10, 15) 30 """ if len(args) < 2: raise TypeError( 'ilcm() takes at least 2 arguments (%s given)' % len(args)) if 0 in args: return 0 a = args[0] for b in args[1:]: a = a // igcd(a, b) * b # since gcd(a,b) | a return a def igcdex(a, b): """Returns x, y, g such that g = x*a + y*b = gcd(a, b). Examples ======== >>> from sympy.core.numbers import igcdex >>> igcdex(2, 3) (-1, 1, 1) >>> igcdex(10, 12) (-1, 1, 2) >>> x, y, g = igcdex(100, 2004) >>> x, y, g (-20, 1, 4) >>> x*100 + y*2004 4 """ if (not a) and (not b): return (0, 1, 0) if not a: return (0, b//abs(b), abs(b)) if not b: return (a//abs(a), 0, abs(a)) if a < 0: a, x_sign = -a, -1 else: x_sign = 1 if b < 0: b, y_sign = -b, -1 else: y_sign = 1 x, y, r, s = 1, 0, 0, 1 while b: (c, q) = (a % b, a // b) (a, b, r, s, x, y) = (b, c, x - q*r, y - q*s, r, s) return (x*x_sign, y*y_sign, a) def mod_inverse(a, m): """ Return the number c such that, (a * c) = 1 (mod m) where c has the same sign as m. If no such value exists, a ValueError is raised. Examples ======== >>> from sympy import S >>> from sympy.core.numbers import mod_inverse Suppose we wish to find multiplicative inverse x of 3 modulo 11. This is the same as finding x such that 3 * x = 1 (mod 11). One value of x that satisfies this congruence is 4. Because 3 * 4 = 12 and 12 = 1 (mod 11). This is the value returned by mod_inverse: >>> mod_inverse(3, 11) 4 >>> mod_inverse(-3, 11) 7 When there is a common factor between the numerators of ``a`` and ``m`` the inverse does not exist: >>> mod_inverse(2, 4) Traceback (most recent call last): ... ValueError: inverse of 2 mod 4 does not exist >>> mod_inverse(S(2)/7, S(5)/2) 7/2 References ========== .. [1] https://en.wikipedia.org/wiki/Modular_multiplicative_inverse .. [2] https://en.wikipedia.org/wiki/Extended_Euclidean_algorithm """ c = None try: a, m = as_int(a), as_int(m) if m != 1 and m != -1: x, y, g = igcdex(a, m) if g == 1: c = x % m except ValueError: a, m = sympify(a), sympify(m) if not (a.is_number and m.is_number): raise TypeError(filldedent(''' Expected numbers for arguments; symbolic `mod_inverse` is not implemented but symbolic expressions can be handled with the similar function, sympy.polys.polytools.invert''')) big = (m > 1) if not (big is S.true or big is S.false): raise ValueError('m > 1 did not evaluate; try to simplify %s' % m) elif big: c = 1/a if c is None: raise ValueError('inverse of %s (mod %s) does not exist' % (a, m)) return c class Number(AtomicExpr): """Represents atomic numbers in SymPy. Explanation =========== Floating point numbers are represented by the Float class. Rational numbers (of any size) are represented by the Rational class. Integer numbers (of any size) are represented by the Integer class. Float and Rational are subclasses of Number; Integer is a subclass of Rational. For example, ``2/3`` is represented as ``Rational(2, 3)`` which is a different object from the floating point number obtained with Python division ``2/3``. Even for numbers that are exactly represented in binary, there is a difference between how two forms, such as ``Rational(1, 2)`` and ``Float(0.5)``, are used in SymPy. The rational form is to be preferred in symbolic computations. Other kinds of numbers, such as algebraic numbers ``sqrt(2)`` or complex numbers ``3 + 4*I``, are not instances of Number class as they are not atomic. See Also ======== Float, Integer, Rational """ is_commutative = True is_number = True is_Number = True __slots__ = () # Used to make max(x._prec, y._prec) return x._prec when only x is a float _prec = -1 kind = NumberKind def __new__(cls, *obj): if len(obj) == 1: obj = obj[0] if isinstance(obj, Number): return obj if isinstance(obj, SYMPY_INTS): return Integer(obj) if isinstance(obj, tuple) and len(obj) == 2: return Rational(*obj) if isinstance(obj, (float, mpmath.mpf, decimal.Decimal)): return Float(obj) if isinstance(obj, str): _obj = obj.lower() # float('INF') == float('inf') if _obj == 'nan': return S.NaN elif _obj == 'inf': return S.Infinity elif _obj == '+inf': return S.Infinity elif _obj == '-inf': return S.NegativeInfinity val = sympify(obj) if isinstance(val, Number): return val else: raise ValueError('String "%s" does not denote a Number' % obj) msg = "expected str|int|long|float|Decimal|Number object but got %r" raise TypeError(msg % type(obj).__name__) def invert(self, other, *gens, **args): from sympy.polys.polytools import invert if getattr(other, 'is_number', True): return mod_inverse(self, other) return invert(self, other, *gens, **args) def __divmod__(self, other): from .containers import Tuple from sympy.functions.elementary.complexes import sign try: other = Number(other) if self.is_infinite or S.NaN in (self, other): return (S.NaN, S.NaN) except TypeError: return NotImplemented if not other: raise ZeroDivisionError('modulo by zero') if self.is_Integer and other.is_Integer: return Tuple(*divmod(self.p, other.p)) elif isinstance(other, Float): rat = self/Rational(other) else: rat = self/other if other.is_finite: w = int(rat) if rat >= 0 else int(rat) - 1 r = self - other*w else: w = 0 if not self or (sign(self) == sign(other)) else -1 r = other if w else self return Tuple(w, r) def __rdivmod__(self, other): try: other = Number(other) except TypeError: return NotImplemented return divmod(other, self) def _as_mpf_val(self, prec): """Evaluation of mpf tuple accurate to at least prec bits.""" raise NotImplementedError('%s needs ._as_mpf_val() method' % (self.__class__.__name__)) def _eval_evalf(self, prec): return Float._new(self._as_mpf_val(prec), prec) def _as_mpf_op(self, prec): prec = max(prec, self._prec) return self._as_mpf_val(prec), prec def __float__(self): return mlib.to_float(self._as_mpf_val(53)) def floor(self): raise NotImplementedError('%s needs .floor() method' % (self.__class__.__name__)) def ceiling(self): raise NotImplementedError('%s needs .ceiling() method' % (self.__class__.__name__)) def __floor__(self): return self.floor() def __ceil__(self): return self.ceiling() def _eval_conjugate(self): return self def _eval_order(self, *symbols): from sympy import Order # Order(5, x, y) -> Order(1,x,y) return Order(S.One, *symbols) def _eval_subs(self, old, new): if old == -self: return -new return self # there is no other possibility def _eval_is_finite(self): return True @classmethod def class_key(cls): return 1, 0, 'Number' @cacheit def sort_key(self, order=None): return self.class_key(), (0, ()), (), self @_sympifyit('other', NotImplemented) def __add__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.NaN: return S.NaN elif other is S.Infinity: return S.Infinity elif other is S.NegativeInfinity: return S.NegativeInfinity return AtomicExpr.__add__(self, other) @_sympifyit('other', NotImplemented) def __sub__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.NaN: return S.NaN elif other is S.Infinity: return S.NegativeInfinity elif other is S.NegativeInfinity: return S.Infinity return AtomicExpr.__sub__(self, other) @_sympifyit('other', NotImplemented) def __mul__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.NaN: return S.NaN elif other is S.Infinity: if self.is_zero: return S.NaN elif self.is_positive: return S.Infinity else: return S.NegativeInfinity elif other is S.NegativeInfinity: if self.is_zero: return S.NaN elif self.is_positive: return S.NegativeInfinity else: return S.Infinity elif isinstance(other, Tuple): return NotImplemented return AtomicExpr.__mul__(self, other) @_sympifyit('other', NotImplemented) def __truediv__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.NaN: return S.NaN elif other is S.Infinity or other is S.NegativeInfinity: return S.Zero return AtomicExpr.__truediv__(self, other) def __eq__(self, other): raise NotImplementedError('%s needs .__eq__() method' % (self.__class__.__name__)) def __ne__(self, other): raise NotImplementedError('%s needs .__ne__() method' % (self.__class__.__name__)) def __lt__(self, other): try: other = _sympify(other) except SympifyError: raise TypeError("Invalid comparison %s < %s" % (self, other)) raise NotImplementedError('%s needs .__lt__() method' % (self.__class__.__name__)) def __le__(self, other): try: other = _sympify(other) except SympifyError: raise TypeError("Invalid comparison %s <= %s" % (self, other)) raise NotImplementedError('%s needs .__le__() method' % (self.__class__.__name__)) def __gt__(self, other): try: other = _sympify(other) except SympifyError: raise TypeError("Invalid comparison %s > %s" % (self, other)) return _sympify(other).__lt__(self) def __ge__(self, other): try: other = _sympify(other) except SympifyError: raise TypeError("Invalid comparison %s >= %s" % (self, other)) return _sympify(other).__le__(self) def __hash__(self): return super().__hash__() def is_constant(self, *wrt, **flags): return True def as_coeff_mul(self, *deps, rational=True, **kwargs): # a -> c*t if self.is_Rational or not rational: return self, tuple() elif self.is_negative: return S.NegativeOne, (-self,) return S.One, (self,) def as_coeff_add(self, *deps): # a -> c + t if self.is_Rational: return self, tuple() return S.Zero, (self,) def as_coeff_Mul(self, rational=False): """Efficiently extract the coefficient of a product. """ if rational and not self.is_Rational: return S.One, self return (self, S.One) if self else (S.One, self) def as_coeff_Add(self, rational=False): """Efficiently extract the coefficient of a summation. """ if not rational: return self, S.Zero return S.Zero, self def gcd(self, other): """Compute GCD of `self` and `other`. """ from sympy.polys import gcd return gcd(self, other) def lcm(self, other): """Compute LCM of `self` and `other`. """ from sympy.polys import lcm return lcm(self, other) def cofactors(self, other): """Compute GCD and cofactors of `self` and `other`. """ from sympy.polys import cofactors return cofactors(self, other) class Float(Number): """Represent a floating-point number of arbitrary precision. Examples ======== >>> from sympy import Float >>> Float(3.5) 3.50000000000000 >>> Float(3) 3.00000000000000 Creating Floats from strings (and Python ``int`` and ``long`` types) will give a minimum precision of 15 digits, but the precision will automatically increase to capture all digits entered. >>> Float(1) 1.00000000000000 >>> Float(10**20) 100000000000000000000. >>> Float('1e20') 100000000000000000000. However, *floating-point* numbers (Python ``float`` types) retain only 15 digits of precision: >>> Float(1e20) 1.00000000000000e+20 >>> Float(1.23456789123456789) 1.23456789123457 It may be preferable to enter high-precision decimal numbers as strings: >>> Float('1.23456789123456789') 1.23456789123456789 The desired number of digits can also be specified: >>> Float('1e-3', 3) 0.00100 >>> Float(100, 4) 100.0 Float can automatically count significant figures if a null string is sent for the precision; spaces or underscores are also allowed. (Auto- counting is only allowed for strings, ints and longs). >>> Float('123 456 789.123_456', '') 123456789.123456 >>> Float('12e-3', '') 0.012 >>> Float(3, '') 3. If a number is written in scientific notation, only the digits before the exponent are considered significant if a decimal appears, otherwise the "e" signifies only how to move the decimal: >>> Float('60.e2', '') # 2 digits significant 6.0e+3 >>> Float('60e2', '') # 4 digits significant 6000. >>> Float('600e-2', '') # 3 digits significant 6.00 Notes ===== Floats are inexact by their nature unless their value is a binary-exact value. >>> approx, exact = Float(.1, 1), Float(.125, 1) For calculation purposes, evalf needs to be able to change the precision but this will not increase the accuracy of the inexact value. The following is the most accurate 5-digit approximation of a value of 0.1 that had only 1 digit of precision: >>> approx.evalf(5) 0.099609 By contrast, 0.125 is exact in binary (as it is in base 10) and so it can be passed to Float or evalf to obtain an arbitrary precision with matching accuracy: >>> Float(exact, 5) 0.12500 >>> exact.evalf(20) 0.12500000000000000000 Trying to make a high-precision Float from a float is not disallowed, but one must keep in mind that the *underlying float* (not the apparent decimal value) is being obtained with high precision. For example, 0.3 does not have a finite binary representation. The closest rational is the fraction 5404319552844595/2**54. So if you try to obtain a Float of 0.3 to 20 digits of precision you will not see the same thing as 0.3 followed by 19 zeros: >>> Float(0.3, 20) 0.29999999999999998890 If you want a 20-digit value of the decimal 0.3 (not the floating point approximation of 0.3) you should send the 0.3 as a string. The underlying representation is still binary but a higher precision than Python's float is used: >>> Float('0.3', 20) 0.30000000000000000000 Although you can increase the precision of an existing Float using Float it will not increase the accuracy -- the underlying value is not changed: >>> def show(f): # binary rep of Float ... from sympy import Mul, Pow ... s, m, e, b = f._mpf_ ... v = Mul(int(m), Pow(2, int(e), evaluate=False), evaluate=False) ... print('%s at prec=%s' % (v, f._prec)) ... >>> t = Float('0.3', 3) >>> show(t) 4915/2**14 at prec=13 >>> show(Float(t, 20)) # higher prec, not higher accuracy 4915/2**14 at prec=70 >>> show(Float(t, 2)) # lower prec 307/2**10 at prec=10 The same thing happens when evalf is used on a Float: >>> show(t.evalf(20)) 4915/2**14 at prec=70 >>> show(t.evalf(2)) 307/2**10 at prec=10 Finally, Floats can be instantiated with an mpf tuple (n, c, p) to produce the number (-1)**n*c*2**p: >>> n, c, p = 1, 5, 0 >>> (-1)**n*c*2**p -5 >>> Float((1, 5, 0)) -5.00000000000000 An actual mpf tuple also contains the number of bits in c as the last element of the tuple: >>> _._mpf_ (1, 5, 0, 3) This is not needed for instantiation and is not the same thing as the precision. The mpf tuple and the precision are two separate quantities that Float tracks. In SymPy, a Float is a number that can be computed with arbitrary precision. Although floating point 'inf' and 'nan' are not such numbers, Float can create these numbers: >>> Float('-inf') -oo >>> _.is_Float False """ __slots__ = ('_mpf_', '_prec') # A Float represents many real numbers, # both rational and irrational. is_rational = None is_irrational = None is_number = True is_real = True is_extended_real = True is_Float = True def __new__(cls, num, dps=None, prec=None, precision=None): if prec is not None: SymPyDeprecationWarning( feature="Using 'prec=XX' to denote decimal precision", useinstead="'dps=XX' for decimal precision and 'precision=XX' "\ "for binary precision", issue=12820, deprecated_since_version="1.1").warn() dps = prec del prec # avoid using this deprecated kwarg if dps is not None and precision is not None: raise ValueError('Both decimal and binary precision supplied. ' 'Supply only one. ') if isinstance(num, str): # Float accepts spaces as digit separators num = num.replace(' ', '').lower() # in Py 3.6 # underscores are allowed. In anticipation of that, we ignore # legally placed underscores if '_' in num: parts = num.split('_') if not (all(parts) and all(parts[i][-1].isdigit() for i in range(0, len(parts), 2)) and all(parts[i][0].isdigit() for i in range(1, len(parts), 2))): # copy Py 3.6 error raise ValueError("could not convert string to float: '%s'" % num) num = ''.join(parts) if num.startswith('.') and len(num) > 1: num = '0' + num elif num.startswith('-.') and len(num) > 2: num = '-0.' + num[2:] elif num in ('inf', '+inf'): return S.Infinity elif num == '-inf': return S.NegativeInfinity elif isinstance(num, float) and num == 0: num = '0' elif isinstance(num, float) and num == float('inf'): return S.Infinity elif isinstance(num, float) and num == float('-inf'): return S.NegativeInfinity elif isinstance(num, float) and num == float('nan'): return S.NaN elif isinstance(num, (SYMPY_INTS, Integer)): num = str(num) elif num is S.Infinity: return num elif num is S.NegativeInfinity: return num elif num is S.NaN: return num elif _is_numpy_instance(num): # support for numpy datatypes num = _convert_numpy_types(num) elif isinstance(num, mpmath.mpf): if precision is None: if dps is None: precision = num.context.prec num = num._mpf_ if dps is None and precision is None: dps = 15 if isinstance(num, Float): return num if isinstance(num, str) and _literal_float(num): try: Num = decimal.Decimal(num) except decimal.InvalidOperation: pass else: isint = '.' not in num num, dps = _decimal_to_Rational_prec(Num) if num.is_Integer and isint: dps = max(dps, len(str(num).lstrip('-'))) dps = max(15, dps) precision = mlib.libmpf.dps_to_prec(dps) elif precision == '' and dps is None or precision is None and dps == '': if not isinstance(num, str): raise ValueError('The null string can only be used when ' 'the number to Float is passed as a string or an integer.') ok = None if _literal_float(num): try: Num = decimal.Decimal(num) except decimal.InvalidOperation: pass else: isint = '.' not in num num, dps = _decimal_to_Rational_prec(Num) if num.is_Integer and isint: dps = max(dps, len(str(num).lstrip('-'))) precision = mlib.libmpf.dps_to_prec(dps) ok = True if ok is None: raise ValueError('string-float not recognized: %s' % num) # decimal precision(dps) is set and maybe binary precision(precision) # as well.From here on binary precision is used to compute the Float. # Hence, if supplied use binary precision else translate from decimal # precision. if precision is None or precision == '': precision = mlib.libmpf.dps_to_prec(dps) precision = int(precision) if isinstance(num, float): _mpf_ = mlib.from_float(num, precision, rnd) elif isinstance(num, str): _mpf_ = mlib.from_str(num, precision, rnd) elif isinstance(num, decimal.Decimal): if num.is_finite(): _mpf_ = mlib.from_str(str(num), precision, rnd) elif num.is_nan(): return S.NaN elif num.is_infinite(): if num > 0: return S.Infinity return S.NegativeInfinity else: raise ValueError("unexpected decimal value %s" % str(num)) elif isinstance(num, tuple) and len(num) in (3, 4): if type(num[1]) is str: # it's a hexadecimal (coming from a pickled object) # assume that it is in standard form num = list(num) # If we're loading an object pickled in Python 2 into # Python 3, we may need to strip a tailing 'L' because # of a shim for int on Python 3, see issue #13470. if num[1].endswith('L'): num[1] = num[1][:-1] num[1] = MPZ(num[1], 16) _mpf_ = tuple(num) else: if len(num) == 4: # handle normalization hack return Float._new(num, precision) else: if not all(( num[0] in (0, 1), num[1] >= 0, all(type(i) in (int, int) for i in num) )): raise ValueError('malformed mpf: %s' % (num,)) # don't compute number or else it may # over/underflow return Float._new( (num[0], num[1], num[2], bitcount(num[1])), precision) else: try: _mpf_ = num._as_mpf_val(precision) except (NotImplementedError, AttributeError): _mpf_ = mpmath.mpf(num, prec=precision)._mpf_ return cls._new(_mpf_, precision, zero=False) @classmethod def _new(cls, _mpf_, _prec, zero=True): # special cases if zero and _mpf_ == fzero: return S.Zero # Float(0) -> 0.0; Float._new((0,0,0,0)) -> 0 elif _mpf_ == _mpf_nan: return S.NaN elif _mpf_ == _mpf_inf: return S.Infinity elif _mpf_ == _mpf_ninf: return S.NegativeInfinity obj = Expr.__new__(cls) obj._mpf_ = mpf_norm(_mpf_, _prec) obj._prec = _prec return obj # mpz can't be pickled def __getnewargs_ex__(self): return ((mlib.to_pickable(self._mpf_),), {'precision': self._prec}) def _hashable_content(self): return (self._mpf_, self._prec) def floor(self): return Integer(int(mlib.to_int( mlib.mpf_floor(self._mpf_, self._prec)))) def ceiling(self): return Integer(int(mlib.to_int( mlib.mpf_ceil(self._mpf_, self._prec)))) def __floor__(self): return self.floor() def __ceil__(self): return self.ceiling() @property def num(self): return mpmath.mpf(self._mpf_) def _as_mpf_val(self, prec): rv = mpf_norm(self._mpf_, prec) if rv != self._mpf_ and self._prec == prec: debug(self._mpf_, rv) return rv def _as_mpf_op(self, prec): return self._mpf_, max(prec, self._prec) def _eval_is_finite(self): if self._mpf_ in (_mpf_inf, _mpf_ninf): return False return True def _eval_is_infinite(self): if self._mpf_ in (_mpf_inf, _mpf_ninf): return True return False def _eval_is_integer(self): return self._mpf_ == fzero def _eval_is_negative(self): if self._mpf_ == _mpf_ninf or self._mpf_ == _mpf_inf: return False return self.num < 0 def _eval_is_positive(self): if self._mpf_ == _mpf_ninf or self._mpf_ == _mpf_inf: return False return self.num > 0 def _eval_is_extended_negative(self): if self._mpf_ == _mpf_ninf: return True if self._mpf_ == _mpf_inf: return False return self.num < 0 def _eval_is_extended_positive(self): if self._mpf_ == _mpf_inf: return True if self._mpf_ == _mpf_ninf: return False return self.num > 0 def _eval_is_zero(self): return self._mpf_ == fzero def __bool__(self): return self._mpf_ != fzero def __neg__(self): return Float._new(mlib.mpf_neg(self._mpf_), self._prec) @_sympifyit('other', NotImplemented) def __add__(self, other): if isinstance(other, Number) and global_parameters.evaluate: rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_add(self._mpf_, rhs, prec, rnd), prec) return Number.__add__(self, other) @_sympifyit('other', NotImplemented) def __sub__(self, other): if isinstance(other, Number) and global_parameters.evaluate: rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_sub(self._mpf_, rhs, prec, rnd), prec) return Number.__sub__(self, other) @_sympifyit('other', NotImplemented) def __mul__(self, other): if isinstance(other, Number) and global_parameters.evaluate: rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_mul(self._mpf_, rhs, prec, rnd), prec) return Number.__mul__(self, other) @_sympifyit('other', NotImplemented) def __truediv__(self, other): if isinstance(other, Number) and other != 0 and global_parameters.evaluate: rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_div(self._mpf_, rhs, prec, rnd), prec) return Number.__truediv__(self, other) @_sympifyit('other', NotImplemented) def __mod__(self, other): if isinstance(other, Rational) and other.q != 1 and global_parameters.evaluate: # calculate mod with Rationals, *then* round the result return Float(Rational.__mod__(Rational(self), other), precision=self._prec) if isinstance(other, Float) and global_parameters.evaluate: r = self/other if r == int(r): return Float(0, precision=max(self._prec, other._prec)) if isinstance(other, Number) and global_parameters.evaluate: rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_mod(self._mpf_, rhs, prec, rnd), prec) return Number.__mod__(self, other) @_sympifyit('other', NotImplemented) def __rmod__(self, other): if isinstance(other, Float) and global_parameters.evaluate: return other.__mod__(self) if isinstance(other, Number) and global_parameters.evaluate: rhs, prec = other._as_mpf_op(self._prec) return Float._new(mlib.mpf_mod(rhs, self._mpf_, prec, rnd), prec) return Number.__rmod__(self, other) def _eval_power(self, expt): """ expt is symbolic object but not equal to 0, 1 (-p)**r -> exp(r*log(-p)) -> exp(r*(log(p) + I*Pi)) -> -> p**r*(sin(Pi*r) + cos(Pi*r)*I) """ if self == 0: if expt.is_positive: return S.Zero if expt.is_negative: return S.Infinity if isinstance(expt, Number): if isinstance(expt, Integer): prec = self._prec return Float._new( mlib.mpf_pow_int(self._mpf_, expt.p, prec, rnd), prec) elif isinstance(expt, Rational) and \ expt.p == 1 and expt.q % 2 and self.is_negative: return Pow(S.NegativeOne, expt, evaluate=False)*( -self)._eval_power(expt) expt, prec = expt._as_mpf_op(self._prec) mpfself = self._mpf_ try: y = mpf_pow(mpfself, expt, prec, rnd) return Float._new(y, prec) except mlib.ComplexResult: re, im = mlib.mpc_pow( (mpfself, fzero), (expt, fzero), prec, rnd) return Float._new(re, prec) + \ Float._new(im, prec)*S.ImaginaryUnit def __abs__(self): return Float._new(mlib.mpf_abs(self._mpf_), self._prec) def __int__(self): if self._mpf_ == fzero: return 0 return int(mlib.to_int(self._mpf_)) # uses round_fast = round_down def __eq__(self, other): from sympy.logic.boolalg import Boolean try: other = _sympify(other) except SympifyError: return NotImplemented if isinstance(other, Boolean): return False if other.is_NumberSymbol: if other.is_irrational: return False return other.__eq__(self) if other.is_Float: # comparison is exact # so Float(.1, 3) != Float(.1, 33) return self._mpf_ == other._mpf_ if other.is_Rational: return other.__eq__(self) if other.is_Number: # numbers should compare at the same precision; # all _as_mpf_val routines should be sure to abide # by the request to change the prec if necessary; if # they don't, the equality test will fail since it compares # the mpf tuples ompf = other._as_mpf_val(self._prec) return bool(mlib.mpf_eq(self._mpf_, ompf)) if not self: return not other return False # Float != non-Number def __ne__(self, other): return not self == other def _Frel(self, other, op): from sympy.core.numbers import prec_to_dps try: other = _sympify(other) except SympifyError: return NotImplemented if other.is_Rational: # test self*other.q other.p without losing precision ''' >>> f = Float(.1,2) >>> i = 1234567890 >>> (f*i)._mpf_ (0, 471, 18, 9) >>> mlib.mpf_mul(f._mpf_, mlib.from_int(i)) (0, 505555550955, -12, 39) ''' smpf = mlib.mpf_mul(self._mpf_, mlib.from_int(other.q)) ompf = mlib.from_int(other.p) return _sympify(bool(op(smpf, ompf))) elif other.is_Float: return _sympify(bool( op(self._mpf_, other._mpf_))) elif other.is_comparable and other not in ( S.Infinity, S.NegativeInfinity): other = other.evalf(prec_to_dps(self._prec)) if other._prec > 1: if other.is_Number: return _sympify(bool( op(self._mpf_, other._as_mpf_val(self._prec)))) def __gt__(self, other): if isinstance(other, NumberSymbol): return other.__lt__(self) rv = self._Frel(other, mlib.mpf_gt) if rv is None: return Expr.__gt__(self, other) return rv def __ge__(self, other): if isinstance(other, NumberSymbol): return other.__le__(self) rv = self._Frel(other, mlib.mpf_ge) if rv is None: return Expr.__ge__(self, other) return rv def __lt__(self, other): if isinstance(other, NumberSymbol): return other.__gt__(self) rv = self._Frel(other, mlib.mpf_lt) if rv is None: return Expr.__lt__(self, other) return rv def __le__(self, other): if isinstance(other, NumberSymbol): return other.__ge__(self) rv = self._Frel(other, mlib.mpf_le) if rv is None: return Expr.__le__(self, other) return rv def __hash__(self): return super().__hash__() def epsilon_eq(self, other, epsilon="1e-15"): return abs(self - other) < Float(epsilon) def __format__(self, format_spec): return format(decimal.Decimal(str(self)), format_spec) # Add sympify converters converter[float] = converter[decimal.Decimal] = Float # this is here to work nicely in Sage RealNumber = Float class Rational(Number): """Represents rational numbers (p/q) of any size. Examples ======== >>> from sympy import Rational, nsimplify, S, pi >>> Rational(1, 2) 1/2 Rational is unprejudiced in accepting input. If a float is passed, the underlying value of the binary representation will be returned: >>> Rational(.5) 1/2 >>> Rational(.2) 3602879701896397/18014398509481984 If the simpler representation of the float is desired then consider limiting the denominator to the desired value or convert the float to a string (which is roughly equivalent to limiting the denominator to 10**12): >>> Rational(str(.2)) 1/5 >>> Rational(.2).limit_denominator(10**12) 1/5 An arbitrarily precise Rational is obtained when a string literal is passed: >>> Rational("1.23") 123/100 >>> Rational('1e-2') 1/100 >>> Rational(".1") 1/10 >>> Rational('1e-2/3.2') 1/320 The conversion of other types of strings can be handled by the sympify() function, and conversion of floats to expressions or simple fractions can be handled with nsimplify: >>> S('.[3]') # repeating digits in brackets 1/3 >>> S('3**2/10') # general expressions 9/10 >>> nsimplify(.3) # numbers that have a simple form 3/10 But if the input does not reduce to a literal Rational, an error will be raised: >>> Rational(pi) Traceback (most recent call last): ... TypeError: invalid input: pi Low-level --------- Access numerator and denominator as .p and .q: >>> r = Rational(3, 4) >>> r 3/4 >>> r.p 3 >>> r.q 4 Note that p and q return integers (not SymPy Integers) so some care is needed when using them in expressions: >>> r.p/r.q 0.75 If an unevaluated Rational is desired, ``gcd=1`` can be passed and this will keep common divisors of the numerator and denominator from being eliminated. It is not possible, however, to leave a negative value in the denominator. >>> Rational(2, 4, gcd=1) 2/4 >>> Rational(2, -4, gcd=1).q 4 See Also ======== sympy.core.sympify.sympify, sympy.simplify.simplify.nsimplify """ is_real = True is_integer = False is_rational = True is_number = True __slots__ = ('p', 'q') is_Rational = True @cacheit def __new__(cls, p, q=None, gcd=None): if q is None: if isinstance(p, Rational): return p if isinstance(p, SYMPY_INTS): pass else: if isinstance(p, (float, Float)): return Rational(*_as_integer_ratio(p)) if not isinstance(p, str): try: p = sympify(p) except (SympifyError, SyntaxError): pass # error will raise below else: if p.count('/') > 1: raise TypeError('invalid input: %s' % p) p = p.replace(' ', '') pq = p.rsplit('/', 1) if len(pq) == 2: p, q = pq fp = fractions.Fraction(p) fq = fractions.Fraction(q) p = fp/fq try: p = fractions.Fraction(p) except ValueError: pass # error will raise below else: return Rational(p.numerator, p.denominator, 1) if not isinstance(p, Rational): raise TypeError('invalid input: %s' % p) q = 1 gcd = 1 if not isinstance(p, SYMPY_INTS): p = Rational(p) q *= p.q p = p.p else: p = int(p) if not isinstance(q, SYMPY_INTS): q = Rational(q) p *= q.q q = q.p else: q = int(q) # p and q are now ints if q == 0: if p == 0: if _errdict["divide"]: raise ValueError("Indeterminate 0/0") else: return S.NaN return S.ComplexInfinity if q < 0: q = -q p = -p if not gcd: gcd = igcd(abs(p), q) if gcd > 1: p //= gcd q //= gcd if q == 1: return Integer(p) if p == 1 and q == 2: return S.Half obj = Expr.__new__(cls) obj.p = p obj.q = q return obj def limit_denominator(self, max_denominator=1000000): """Closest Rational to self with denominator at most max_denominator. Examples ======== >>> from sympy import Rational >>> Rational('3.141592653589793').limit_denominator(10) 22/7 >>> Rational('3.141592653589793').limit_denominator(100) 311/99 """ f = fractions.Fraction(self.p, self.q) return Rational(f.limit_denominator(fractions.Fraction(int(max_denominator)))) def __getnewargs__(self): return (self.p, self.q) def _hashable_content(self): return (self.p, self.q) def _eval_is_positive(self): return self.p > 0 def _eval_is_zero(self): return self.p == 0 def __neg__(self): return Rational(-self.p, self.q) @_sympifyit('other', NotImplemented) def __add__(self, other): if global_parameters.evaluate: if isinstance(other, Integer): return Rational(self.p + self.q*other.p, self.q, 1) elif isinstance(other, Rational): #TODO: this can probably be optimized more return Rational(self.p*other.q + self.q*other.p, self.q*other.q) elif isinstance(other, Float): return other + self else: return Number.__add__(self, other) return Number.__add__(self, other) __radd__ = __add__ @_sympifyit('other', NotImplemented) def __sub__(self, other): if global_parameters.evaluate: if isinstance(other, Integer): return Rational(self.p - self.q*other.p, self.q, 1) elif isinstance(other, Rational): return Rational(self.p*other.q - self.q*other.p, self.q*other.q) elif isinstance(other, Float): return -other + self else: return Number.__sub__(self, other) return Number.__sub__(self, other) @_sympifyit('other', NotImplemented) def __rsub__(self, other): if global_parameters.evaluate: if isinstance(other, Integer): return Rational(self.q*other.p - self.p, self.q, 1) elif isinstance(other, Rational): return Rational(self.q*other.p - self.p*other.q, self.q*other.q) elif isinstance(other, Float): return -self + other else: return Number.__rsub__(self, other) return Number.__rsub__(self, other) @_sympifyit('other', NotImplemented) def __mul__(self, other): if global_parameters.evaluate: if isinstance(other, Integer): return Rational(self.p*other.p, self.q, igcd(other.p, self.q)) elif isinstance(other, Rational): return Rational(self.p*other.p, self.q*other.q, igcd(self.p, other.q)*igcd(self.q, other.p)) elif isinstance(other, Float): return other*self else: return Number.__mul__(self, other) return Number.__mul__(self, other) __rmul__ = __mul__ @_sympifyit('other', NotImplemented) def __truediv__(self, other): if global_parameters.evaluate: if isinstance(other, Integer): if self.p and other.p == S.Zero: return S.ComplexInfinity else: return Rational(self.p, self.q*other.p, igcd(self.p, other.p)) elif isinstance(other, Rational): return Rational(self.p*other.q, self.q*other.p, igcd(self.p, other.p)*igcd(self.q, other.q)) elif isinstance(other, Float): return self*(1/other) else: return Number.__truediv__(self, other) return Number.__truediv__(self, other) @_sympifyit('other', NotImplemented) def __rtruediv__(self, other): if global_parameters.evaluate: if isinstance(other, Integer): return Rational(other.p*self.q, self.p, igcd(self.p, other.p)) elif isinstance(other, Rational): return Rational(other.p*self.q, other.q*self.p, igcd(self.p, other.p)*igcd(self.q, other.q)) elif isinstance(other, Float): return other*(1/self) else: return Number.__rtruediv__(self, other) return Number.__rtruediv__(self, other) @_sympifyit('other', NotImplemented) def __mod__(self, other): if global_parameters.evaluate: if isinstance(other, Rational): n = (self.p*other.q) // (other.p*self.q) return Rational(self.p*other.q - n*other.p*self.q, self.q*other.q) if isinstance(other, Float): # calculate mod with Rationals, *then* round the answer return Float(self.__mod__(Rational(other)), precision=other._prec) return Number.__mod__(self, other) return Number.__mod__(self, other) @_sympifyit('other', NotImplemented) def __rmod__(self, other): if isinstance(other, Rational): return Rational.__mod__(other, self) return Number.__rmod__(self, other) def _eval_power(self, expt): if isinstance(expt, Number): if isinstance(expt, Float): return self._eval_evalf(expt._prec)**expt if expt.is_extended_negative: # (3/4)**-2 -> (4/3)**2 ne = -expt if (ne is S.One): return Rational(self.q, self.p) if self.is_negative: return S.NegativeOne**expt*Rational(self.q, -self.p)**ne else: return Rational(self.q, self.p)**ne if expt is S.Infinity: # -oo already caught by test for negative if self.p > self.q: # (3/2)**oo -> oo return S.Infinity if self.p < -self.q: # (-3/2)**oo -> oo + I*oo return S.Infinity + S.Infinity*S.ImaginaryUnit return S.Zero if isinstance(expt, Integer): # (4/3)**2 -> 4**2 / 3**2 return Rational(self.p**expt.p, self.q**expt.p, 1) if isinstance(expt, Rational): intpart = expt.p // expt.q if intpart: intpart += 1 remfracpart = intpart*expt.q - expt.p ratfracpart = Rational(remfracpart, expt.q) if self.p != 1: return Integer(self.p)**expt*Integer(self.q)**ratfracpart*Rational(1, self.q**intpart, 1) return Integer(self.q)**ratfracpart*Rational(1, self.q**intpart, 1) else: remfracpart = expt.q - expt.p ratfracpart = Rational(remfracpart, expt.q) if self.p != 1: return Integer(self.p)**expt*Integer(self.q)**ratfracpart*Rational(1, self.q, 1) return Integer(self.q)**ratfracpart*Rational(1, self.q, 1) if self.is_extended_negative and expt.is_even: return (-self)**expt return def _as_mpf_val(self, prec): return mlib.from_rational(self.p, self.q, prec, rnd) def _mpmath_(self, prec, rnd): return mpmath.make_mpf(mlib.from_rational(self.p, self.q, prec, rnd)) def __abs__(self): return Rational(abs(self.p), self.q) def __int__(self): p, q = self.p, self.q if p < 0: return -int(-p//q) return int(p//q) def floor(self): return Integer(self.p // self.q) def ceiling(self): return -Integer(-self.p // self.q) def __floor__(self): return self.floor() def __ceil__(self): return self.ceiling() def __eq__(self, other): from sympy.core.power import integer_log try: other = _sympify(other) except SympifyError: return NotImplemented if not isinstance(other, Number): # S(0) == S.false is False # S(0) == False is True return False if not self: return not other if other.is_NumberSymbol: if other.is_irrational: return False return other.__eq__(self) if other.is_Rational: # a Rational is always in reduced form so will never be 2/4 # so we can just check equivalence of args return self.p == other.p and self.q == other.q if other.is_Float: # all Floats have a denominator that is a power of 2 # so if self doesn't, it can't be equal to other if self.q & (self.q - 1): return False s, m, t = other._mpf_[:3] if s: m = -m if not t: # other is an odd integer if not self.is_Integer or self.is_even: return False return m == self.p if t > 0: # other is an even integer if not self.is_Integer: return False # does m*2**t == self.p return self.p and not self.p % m and \ integer_log(self.p//m, 2) == (t, True) # does non-integer s*m/2**-t = p/q? if self.is_Integer: return False return m == self.p and integer_log(self.q, 2) == (-t, True) return False def __ne__(self, other): return not self == other def _Rrel(self, other, attr): # if you want self < other, pass self, other, __gt__ try: other = _sympify(other) except SympifyError: return NotImplemented if other.is_Number: op = None s, o = self, other if other.is_NumberSymbol: op = getattr(o, attr) elif other.is_Float: op = getattr(o, attr) elif other.is_Rational: s, o = Integer(s.p*o.q), Integer(s.q*o.p) op = getattr(o, attr) if op: return op(s) if o.is_number and o.is_extended_real: return Integer(s.p), s.q*o def __gt__(self, other): rv = self._Rrel(other, '__lt__') if rv is None: rv = self, other elif not type(rv) is tuple: return rv return Expr.__gt__(*rv) def __ge__(self, other): rv = self._Rrel(other, '__le__') if rv is None: rv = self, other elif not type(rv) is tuple: return rv return Expr.__ge__(*rv) def __lt__(self, other): rv = self._Rrel(other, '__gt__') if rv is None: rv = self, other elif not type(rv) is tuple: return rv return Expr.__lt__(*rv) def __le__(self, other): rv = self._Rrel(other, '__ge__') if rv is None: rv = self, other elif not type(rv) is tuple: return rv return Expr.__le__(*rv) def __hash__(self): return super().__hash__() def factors(self, limit=None, use_trial=True, use_rho=False, use_pm1=False, verbose=False, visual=False): """A wrapper to factorint which return factors of self that are smaller than limit (or cheap to compute). Special methods of factoring are disabled by default so that only trial division is used. """ from sympy.ntheory import factorrat return factorrat(self, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose).copy() @property def numerator(self): return self.p @property def denominator(self): return self.q @_sympifyit('other', NotImplemented) def gcd(self, other): if isinstance(other, Rational): if other == S.Zero: return other return Rational( Integer(igcd(self.p, other.p)), Integer(ilcm(self.q, other.q))) return Number.gcd(self, other) @_sympifyit('other', NotImplemented) def lcm(self, other): if isinstance(other, Rational): return Rational( self.p // igcd(self.p, other.p) * other.p, igcd(self.q, other.q)) return Number.lcm(self, other) def as_numer_denom(self): return Integer(self.p), Integer(self.q) def as_content_primitive(self, radical=False, clear=True): """Return the tuple (R, self/R) where R is the positive Rational extracted from self. Examples ======== >>> from sympy import S >>> (S(-3)/2).as_content_primitive() (3/2, -1) See docstring of Expr.as_content_primitive for more examples. """ if self: if self.is_positive: return self, S.One return -self, S.NegativeOne return S.One, self def as_coeff_Mul(self, rational=False): """Efficiently extract the coefficient of a product. """ return self, S.One def as_coeff_Add(self, rational=False): """Efficiently extract the coefficient of a summation. """ return self, S.Zero class Integer(Rational): """Represents integer numbers of any size. Examples ======== >>> from sympy import Integer >>> Integer(3) 3 If a float or a rational is passed to Integer, the fractional part will be discarded; the effect is of rounding toward zero. >>> Integer(3.8) 3 >>> Integer(-3.8) -3 A string is acceptable input if it can be parsed as an integer: >>> Integer("9" * 20) 99999999999999999999 It is rarely needed to explicitly instantiate an Integer, because Python integers are automatically converted to Integer when they are used in SymPy expressions. """ q = 1 is_integer = True is_number = True is_Integer = True __slots__ = ('p',) def _as_mpf_val(self, prec): return mlib.from_int(self.p, prec, rnd) def _mpmath_(self, prec, rnd): return mpmath.make_mpf(self._as_mpf_val(prec)) @cacheit def __new__(cls, i): if isinstance(i, str): i = i.replace(' ', '') # whereas we cannot, in general, make a Rational from an # arbitrary expression, we can make an Integer unambiguously # (except when a non-integer expression happens to round to # an integer). So we proceed by taking int() of the input and # let the int routines determine whether the expression can # be made into an int or whether an error should be raised. try: ival = int(i) except TypeError: raise TypeError( "Argument of Integer should be of numeric type, got %s." % i) # We only work with well-behaved integer types. This converts, for # example, numpy.int32 instances. if ival == 1: return S.One if ival == -1: return S.NegativeOne if ival == 0: return S.Zero obj = Expr.__new__(cls) obj.p = ival return obj def __getnewargs__(self): return (self.p,) # Arithmetic operations are here for efficiency def __int__(self): return self.p def floor(self): return Integer(self.p) def ceiling(self): return Integer(self.p) def __floor__(self): return self.floor() def __ceil__(self): return self.ceiling() def __neg__(self): return Integer(-self.p) def __abs__(self): if self.p >= 0: return self else: return Integer(-self.p) def __divmod__(self, other): from .containers import Tuple if isinstance(other, Integer) and global_parameters.evaluate: return Tuple(*(divmod(self.p, other.p))) else: return Number.__divmod__(self, other) def __rdivmod__(self, other): from .containers import Tuple if isinstance(other, int) and global_parameters.evaluate: return Tuple(*(divmod(other, self.p))) else: try: other = Number(other) except TypeError: msg = "unsupported operand type(s) for divmod(): '%s' and '%s'" oname = type(other).__name__ sname = type(self).__name__ raise TypeError(msg % (oname, sname)) return Number.__divmod__(other, self) # TODO make it decorator + bytecodehacks? def __add__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(self.p + other) elif isinstance(other, Integer): return Integer(self.p + other.p) elif isinstance(other, Rational): return Rational(self.p*other.q + other.p, other.q, 1) return Rational.__add__(self, other) else: return Add(self, other) def __radd__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(other + self.p) elif isinstance(other, Rational): return Rational(other.p + self.p*other.q, other.q, 1) return Rational.__radd__(self, other) return Rational.__radd__(self, other) def __sub__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(self.p - other) elif isinstance(other, Integer): return Integer(self.p - other.p) elif isinstance(other, Rational): return Rational(self.p*other.q - other.p, other.q, 1) return Rational.__sub__(self, other) return Rational.__sub__(self, other) def __rsub__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(other - self.p) elif isinstance(other, Rational): return Rational(other.p - self.p*other.q, other.q, 1) return Rational.__rsub__(self, other) return Rational.__rsub__(self, other) def __mul__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(self.p*other) elif isinstance(other, Integer): return Integer(self.p*other.p) elif isinstance(other, Rational): return Rational(self.p*other.p, other.q, igcd(self.p, other.q)) return Rational.__mul__(self, other) return Rational.__mul__(self, other) def __rmul__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(other*self.p) elif isinstance(other, Rational): return Rational(other.p*self.p, other.q, igcd(self.p, other.q)) return Rational.__rmul__(self, other) return Rational.__rmul__(self, other) def __mod__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(self.p % other) elif isinstance(other, Integer): return Integer(self.p % other.p) return Rational.__mod__(self, other) return Rational.__mod__(self, other) def __rmod__(self, other): if global_parameters.evaluate: if isinstance(other, int): return Integer(other % self.p) elif isinstance(other, Integer): return Integer(other.p % self.p) return Rational.__rmod__(self, other) return Rational.__rmod__(self, other) def __eq__(self, other): if isinstance(other, int): return (self.p == other) elif isinstance(other, Integer): return (self.p == other.p) return Rational.__eq__(self, other) def __ne__(self, other): return not self == other def __gt__(self, other): try: other = _sympify(other) except SympifyError: return NotImplemented if other.is_Integer: return _sympify(self.p > other.p) return Rational.__gt__(self, other) def __lt__(self, other): try: other = _sympify(other) except SympifyError: return NotImplemented if other.is_Integer: return _sympify(self.p < other.p) return Rational.__lt__(self, other) def __ge__(self, other): try: other = _sympify(other) except SympifyError: return NotImplemented if other.is_Integer: return _sympify(self.p >= other.p) return Rational.__ge__(self, other) def __le__(self, other): try: other = _sympify(other) except SympifyError: return NotImplemented if other.is_Integer: return _sympify(self.p <= other.p) return Rational.__le__(self, other) def __hash__(self): return hash(self.p) def __index__(self): return self.p ######################################## def _eval_is_odd(self): return bool(self.p % 2) def _eval_power(self, expt): """ Tries to do some simplifications on self**expt Returns None if no further simplifications can be done. Explanation =========== When exponent is a fraction (so we have for example a square root), we try to find a simpler representation by factoring the argument up to factors of 2**15, e.g. - sqrt(4) becomes 2 - sqrt(-4) becomes 2*I - (2**(3+7)*3**(6+7))**Rational(1,7) becomes 6*18**(3/7) Further simplification would require a special call to factorint on the argument which is not done here for sake of speed. """ from sympy.ntheory.factor_ import perfect_power if expt is S.Infinity: if self.p > S.One: return S.Infinity # cases -1, 0, 1 are done in their respective classes return S.Infinity + S.ImaginaryUnit*S.Infinity if expt is S.NegativeInfinity: return Rational(1, self, 1)**S.Infinity if not isinstance(expt, Number): # simplify when expt is even # (-2)**k --> 2**k if self.is_negative and expt.is_even: return (-self)**expt if isinstance(expt, Float): # Rational knows how to exponentiate by a Float return super()._eval_power(expt) if not isinstance(expt, Rational): return if expt is S.Half and self.is_negative: # we extract I for this special case since everyone is doing so return S.ImaginaryUnit*Pow(-self, expt) if expt.is_negative: # invert base and change sign on exponent ne = -expt if self.is_negative: return S.NegativeOne**expt*Rational(1, -self, 1)**ne else: return Rational(1, self.p, 1)**ne # see if base is a perfect root, sqrt(4) --> 2 x, xexact = integer_nthroot(abs(self.p), expt.q) if xexact: # if it's a perfect root we've finished result = Integer(x**abs(expt.p)) if self.is_negative: result *= S.NegativeOne**expt return result # The following is an algorithm where we collect perfect roots # from the factors of base. # if it's not an nth root, it still might be a perfect power b_pos = int(abs(self.p)) p = perfect_power(b_pos) if p is not False: dict = {p[0]: p[1]} else: dict = Integer(b_pos).factors(limit=2**15) # now process the dict of factors out_int = 1 # integer part out_rad = 1 # extracted radicals sqr_int = 1 sqr_gcd = 0 sqr_dict = {} for prime, exponent in dict.items(): exponent *= expt.p # remove multiples of expt.q: (2**12)**(1/10) -> 2*(2**2)**(1/10) div_e, div_m = divmod(exponent, expt.q) if div_e > 0: out_int *= prime**div_e if div_m > 0: # see if the reduced exponent shares a gcd with e.q # (2**2)**(1/10) -> 2**(1/5) g = igcd(div_m, expt.q) if g != 1: out_rad *= Pow(prime, Rational(div_m//g, expt.q//g, 1)) else: sqr_dict[prime] = div_m # identify gcd of remaining powers for p, ex in sqr_dict.items(): if sqr_gcd == 0: sqr_gcd = ex else: sqr_gcd = igcd(sqr_gcd, ex) if sqr_gcd == 1: break for k, v in sqr_dict.items(): sqr_int *= k**(v//sqr_gcd) if sqr_int == b_pos and out_int == 1 and out_rad == 1: result = None else: result = out_int*out_rad*Pow(sqr_int, Rational(sqr_gcd, expt.q)) if self.is_negative: result *= Pow(S.NegativeOne, expt) return result def _eval_is_prime(self): from sympy.ntheory import isprime return isprime(self) def _eval_is_composite(self): if self > 1: return fuzzy_not(self.is_prime) else: return False def as_numer_denom(self): return self, S.One @_sympifyit('other', NotImplemented) def __floordiv__(self, other): if not isinstance(other, Expr): return NotImplemented if isinstance(other, Integer): return Integer(self.p // other) return Integer(divmod(self, other)[0]) def __rfloordiv__(self, other): return Integer(Integer(other).p // self.p) # These bitwise operations (__lshift__, __rlshift__, ..., __invert__) are defined # for Integer only and not for general sympy expressions. This is to achieve # compatibility with the numbers.Integral ABC which only defines these operations # among instances of numbers.Integral. Therefore, these methods check explicitly for # integer types rather than using sympify because they should not accept arbitrary # symbolic expressions and there is no symbolic analogue of numbers.Integral's # bitwise operations. def __lshift__(self, other): if isinstance(other, (int, Integer, numbers.Integral)): return Integer(self.p << int(other)) else: return NotImplemented def __rlshift__(self, other): if isinstance(other, (int, numbers.Integral)): return Integer(int(other) << self.p) else: return NotImplemented def __rshift__(self, other): if isinstance(other, (int, Integer, numbers.Integral)): return Integer(self.p >> int(other)) else: return NotImplemented def __rrshift__(self, other): if isinstance(other, (int, numbers.Integral)): return Integer(int(other) >> self.p) else: return NotImplemented def __and__(self, other): if isinstance(other, (int, Integer, numbers.Integral)): return Integer(self.p & int(other)) else: return NotImplemented def __rand__(self, other): if isinstance(other, (int, numbers.Integral)): return Integer(int(other) & self.p) else: return NotImplemented def __xor__(self, other): if isinstance(other, (int, Integer, numbers.Integral)): return Integer(self.p ^ int(other)) else: return NotImplemented def __rxor__(self, other): if isinstance(other, (int, numbers.Integral)): return Integer(int(other) ^ self.p) else: return NotImplemented def __or__(self, other): if isinstance(other, (int, Integer, numbers.Integral)): return Integer(self.p | int(other)) else: return NotImplemented def __ror__(self, other): if isinstance(other, (int, numbers.Integral)): return Integer(int(other) | self.p) else: return NotImplemented def __invert__(self): return Integer(~self.p) # Add sympify converters converter[int] = Integer class AlgebraicNumber(Expr): """Class for representing algebraic numbers in SymPy. """ __slots__ = ('rep', 'root', 'alias', 'minpoly') is_AlgebraicNumber = True is_algebraic = True is_number = True kind = NumberKind # Optional alias symbol is not free. # Actually, alias should be a Str, but some methods # expect that it be an instance of Expr. free_symbols = set() def __new__(cls, expr, coeffs=None, alias=None, **args): """Construct a new algebraic number. """ from sympy import Poly from sympy.polys.polyclasses import ANP, DMP from sympy.polys.numberfields import minimal_polynomial from sympy.core.symbol import Symbol expr = sympify(expr) if isinstance(expr, (tuple, Tuple)): minpoly, root = expr if not minpoly.is_Poly: minpoly = Poly(minpoly) elif expr.is_AlgebraicNumber: minpoly, root = expr.minpoly, expr.root else: minpoly, root = minimal_polynomial( expr, args.get('gen'), polys=True), expr dom = minpoly.get_domain() if coeffs is not None: if not isinstance(coeffs, ANP): rep = DMP.from_sympy_list(sympify(coeffs), 0, dom) scoeffs = Tuple(*coeffs) else: rep = DMP.from_list(coeffs.to_list(), 0, dom) scoeffs = Tuple(*coeffs.to_list()) if rep.degree() >= minpoly.degree(): rep = rep.rem(minpoly.rep) else: rep = DMP.from_list([1, 0], 0, dom) scoeffs = Tuple(1, 0) sargs = (root, scoeffs) if alias is not None: if not isinstance(alias, Symbol): alias = Symbol(alias) sargs = sargs + (alias,) obj = Expr.__new__(cls, *sargs) obj.rep = rep obj.root = root obj.alias = alias obj.minpoly = minpoly return obj def __hash__(self): return super().__hash__() def _eval_evalf(self, prec): return self.as_expr()._evalf(prec) @property def is_aliased(self): """Returns ``True`` if ``alias`` was set. """ return self.alias is not None def as_poly(self, x=None): """Create a Poly instance from ``self``. """ from sympy import Dummy, Poly, PurePoly if x is not None: return Poly.new(self.rep, x) else: if self.alias is not None: return Poly.new(self.rep, self.alias) else: return PurePoly.new(self.rep, Dummy('x')) def as_expr(self, x=None): """Create a Basic expression from ``self``. """ return self.as_poly(x or self.root).as_expr().expand() def coeffs(self): """Returns all SymPy coefficients of an algebraic number. """ return [ self.rep.dom.to_sympy(c) for c in self.rep.all_coeffs() ] def native_coeffs(self): """Returns all native coefficients of an algebraic number. """ return self.rep.all_coeffs() def to_algebraic_integer(self): """Convert ``self`` to an algebraic integer. """ from sympy import Poly f = self.minpoly if f.LC() == 1: return self coeff = f.LC()**(f.degree() - 1) poly = f.compose(Poly(f.gen/f.LC())) minpoly = poly*coeff root = f.LC()*self.root return AlgebraicNumber((minpoly, root), self.coeffs()) def _eval_simplify(self, **kwargs): from sympy.polys import CRootOf, minpoly measure, ratio = kwargs['measure'], kwargs['ratio'] for r in [r for r in self.minpoly.all_roots() if r.func != CRootOf]: if minpoly(self.root - r).is_Symbol: # use the matching root if it's simpler if measure(r) < ratio*measure(self.root): return AlgebraicNumber(r) return self class RationalConstant(Rational): """ Abstract base class for rationals with specific behaviors Derived classes must define class attributes p and q and should probably all be singletons. """ __slots__ = () def __new__(cls): return AtomicExpr.__new__(cls) class IntegerConstant(Integer): __slots__ = () def __new__(cls): return AtomicExpr.__new__(cls) class Zero(IntegerConstant, metaclass=Singleton): """The number zero. Zero is a singleton, and can be accessed by ``S.Zero`` Examples ======== >>> from sympy import S, Integer >>> Integer(0) is S.Zero True >>> 1/S.Zero zoo References ========== .. [1] https://en.wikipedia.org/wiki/Zero """ p = 0 q = 1 is_positive = False is_negative = False is_zero = True is_number = True is_comparable = True __slots__ = () def __getnewargs__(self): return () @staticmethod def __abs__(): return S.Zero @staticmethod def __neg__(): return S.Zero def _eval_power(self, expt): if expt.is_positive: return self if expt.is_negative: return S.ComplexInfinity if expt.is_extended_real is False: return S.NaN # infinities are already handled with pos and neg # tests above; now throw away leading numbers on Mul # exponent coeff, terms = expt.as_coeff_Mul() if coeff.is_negative: return S.ComplexInfinity**terms if coeff is not S.One: # there is a Number to discard return self**terms def _eval_order(self, *symbols): # Order(0,x) -> 0 return self def __bool__(self): return False def as_coeff_Mul(self, rational=False): # XXX this routine should be deleted """Efficiently extract the coefficient of a summation. """ return S.One, self class One(IntegerConstant, metaclass=Singleton): """The number one. One is a singleton, and can be accessed by ``S.One``. Examples ======== >>> from sympy import S, Integer >>> Integer(1) is S.One True References ========== .. [1] https://en.wikipedia.org/wiki/1_%28number%29 """ is_number = True is_positive = True p = 1 q = 1 __slots__ = () def __getnewargs__(self): return () @staticmethod def __abs__(): return S.One @staticmethod def __neg__(): return S.NegativeOne def _eval_power(self, expt): return self def _eval_order(self, *symbols): return @staticmethod def factors(limit=None, use_trial=True, use_rho=False, use_pm1=False, verbose=False, visual=False): if visual: return S.One else: return {} class NegativeOne(IntegerConstant, metaclass=Singleton): """The number negative one. NegativeOne is a singleton, and can be accessed by ``S.NegativeOne``. Examples ======== >>> from sympy import S, Integer >>> Integer(-1) is S.NegativeOne True See Also ======== One References ========== .. [1] https://en.wikipedia.org/wiki/%E2%88%921_%28number%29 """ is_number = True p = -1 q = 1 __slots__ = () def __getnewargs__(self): return () @staticmethod def __abs__(): return S.One @staticmethod def __neg__(): return S.One def _eval_power(self, expt): if expt.is_odd: return S.NegativeOne if expt.is_even: return S.One if isinstance(expt, Number): if isinstance(expt, Float): return Float(-1.0)**expt if expt is S.NaN: return S.NaN if expt is S.Infinity or expt is S.NegativeInfinity: return S.NaN if expt is S.Half: return S.ImaginaryUnit if isinstance(expt, Rational): if expt.q == 2: return S.ImaginaryUnit**Integer(expt.p) i, r = divmod(expt.p, expt.q) if i: return self**i*self**Rational(r, expt.q) return class Half(RationalConstant, metaclass=Singleton): """The rational number 1/2. Half is a singleton, and can be accessed by ``S.Half``. Examples ======== >>> from sympy import S, Rational >>> Rational(1, 2) is S.Half True References ========== .. [1] https://en.wikipedia.org/wiki/One_half """ is_number = True p = 1 q = 2 __slots__ = () def __getnewargs__(self): return () @staticmethod def __abs__(): return S.Half class Infinity(Number, metaclass=Singleton): r"""Positive infinite quantity. Explanation =========== In real analysis the symbol `\infty` denotes an unbounded limit: `x\to\infty` means that `x` grows without bound. Infinity is often used not only to define a limit but as a value in the affinely extended real number system. Points labeled `+\infty` and `-\infty` can be added to the topological space of the real numbers, producing the two-point compactification of the real numbers. Adding algebraic properties to this gives us the extended real numbers. Infinity is a singleton, and can be accessed by ``S.Infinity``, or can be imported as ``oo``. Examples ======== >>> from sympy import oo, exp, limit, Symbol >>> 1 + oo oo >>> 42/oo 0 >>> x = Symbol('x') >>> limit(exp(x), x, oo) oo See Also ======== NegativeInfinity, NaN References ========== .. [1] https://en.wikipedia.org/wiki/Infinity """ is_commutative = True is_number = True is_complex = False is_extended_real = True is_infinite = True is_comparable = True is_extended_positive = True is_prime = False __slots__ = () def __new__(cls): return AtomicExpr.__new__(cls) def _latex(self, printer): return r"\infty" def _eval_subs(self, old, new): if self == old: return new def _eval_evalf(self, prec=None): return Float('inf') def evalf(self, prec=None, **options): return self._eval_evalf(prec) @_sympifyit('other', NotImplemented) def __add__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.NegativeInfinity or other is S.NaN: return S.NaN return self return Number.__add__(self, other) __radd__ = __add__ @_sympifyit('other', NotImplemented) def __sub__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.Infinity or other is S.NaN: return S.NaN return self return Number.__sub__(self, other) @_sympifyit('other', NotImplemented) def __rsub__(self, other): return (-self).__add__(other) @_sympifyit('other', NotImplemented) def __mul__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other.is_zero or other is S.NaN: return S.NaN if other.is_extended_positive: return self return S.NegativeInfinity return Number.__mul__(self, other) __rmul__ = __mul__ @_sympifyit('other', NotImplemented) def __truediv__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.Infinity or \ other is S.NegativeInfinity or \ other is S.NaN: return S.NaN if other.is_extended_nonnegative: return self return S.NegativeInfinity return Number.__truediv__(self, other) def __abs__(self): return S.Infinity def __neg__(self): return S.NegativeInfinity def _eval_power(self, expt): """ ``expt`` is symbolic object but not equal to 0 or 1. ================ ======= ============================== Expression Result Notes ================ ======= ============================== ``oo ** nan`` ``nan`` ``oo ** -p`` ``0`` ``p`` is number, ``oo`` ================ ======= ============================== See Also ======== Pow NaN NegativeInfinity """ from sympy.functions import re if expt.is_extended_positive: return S.Infinity if expt.is_extended_negative: return S.Zero if expt is S.NaN: return S.NaN if expt is S.ComplexInfinity: return S.NaN if expt.is_extended_real is False and expt.is_number: expt_real = re(expt) if expt_real.is_positive: return S.ComplexInfinity if expt_real.is_negative: return S.Zero if expt_real.is_zero: return S.NaN return self**expt.evalf() def _as_mpf_val(self, prec): return mlib.finf def __hash__(self): return super().__hash__() def __eq__(self, other): return other is S.Infinity or other == float('inf') def __ne__(self, other): return other is not S.Infinity and other != float('inf') __gt__ = Expr.__gt__ __ge__ = Expr.__ge__ __lt__ = Expr.__lt__ __le__ = Expr.__le__ @_sympifyit('other', NotImplemented) def __mod__(self, other): if not isinstance(other, Expr): return NotImplemented return S.NaN __rmod__ = __mod__ def floor(self): return self def ceiling(self): return self oo = S.Infinity class NegativeInfinity(Number, metaclass=Singleton): """Negative infinite quantity. NegativeInfinity is a singleton, and can be accessed by ``S.NegativeInfinity``. See Also ======== Infinity """ is_extended_real = True is_complex = False is_commutative = True is_infinite = True is_comparable = True is_extended_negative = True is_number = True is_prime = False __slots__ = () def __new__(cls): return AtomicExpr.__new__(cls) def _latex(self, printer): return r"-\infty" def _eval_subs(self, old, new): if self == old: return new def _eval_evalf(self, prec=None): return Float('-inf') def evalf(self, prec=None, **options): return self._eval_evalf(prec) @_sympifyit('other', NotImplemented) def __add__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.Infinity or other is S.NaN: return S.NaN return self return Number.__add__(self, other) __radd__ = __add__ @_sympifyit('other', NotImplemented) def __sub__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.NegativeInfinity or other is S.NaN: return S.NaN return self return Number.__sub__(self, other) @_sympifyit('other', NotImplemented) def __rsub__(self, other): return (-self).__add__(other) @_sympifyit('other', NotImplemented) def __mul__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other.is_zero or other is S.NaN: return S.NaN if other.is_extended_positive: return self return S.Infinity return Number.__mul__(self, other) __rmul__ = __mul__ @_sympifyit('other', NotImplemented) def __truediv__(self, other): if isinstance(other, Number) and global_parameters.evaluate: if other is S.Infinity or \ other is S.NegativeInfinity or \ other is S.NaN: return S.NaN if other.is_extended_nonnegative: return self return S.Infinity return Number.__truediv__(self, other) def __abs__(self): return S.Infinity def __neg__(self): return S.Infinity def _eval_power(self, expt): """ ``expt`` is symbolic object but not equal to 0 or 1. ================ ======= ============================== Expression Result Notes ================ ======= ============================== ``(-oo) ** nan`` ``nan`` ``(-oo) ** oo`` ``nan`` ``(-oo) ** -oo`` ``nan`` ``(-oo) ** e`` ``oo`` ``e`` is positive even integer ``(-oo) ** o`` ``-oo`` ``o`` is positive odd integer ================ ======= ============================== See Also ======== Infinity Pow NaN """ if expt.is_number: if expt is S.NaN or \ expt is S.Infinity or \ expt is S.NegativeInfinity: return S.NaN if isinstance(expt, Integer) and expt.is_extended_positive: if expt.is_odd: return S.NegativeInfinity else: return S.Infinity return S.NegativeOne**expt*S.Infinity**expt def _as_mpf_val(self, prec): return mlib.fninf def __hash__(self): return super().__hash__() def __eq__(self, other): return other is S.NegativeInfinity or other == float('-inf') def __ne__(self, other): return other is not S.NegativeInfinity and other != float('-inf') __gt__ = Expr.__gt__ __ge__ = Expr.__ge__ __lt__ = Expr.__lt__ __le__ = Expr.__le__ @_sympifyit('other', NotImplemented) def __mod__(self, other): if not isinstance(other, Expr): return NotImplemented return S.NaN __rmod__ = __mod__ def floor(self): return self def ceiling(self): return self def as_powers_dict(self): return {S.NegativeOne: 1, S.Infinity: 1} class NaN(Number, metaclass=Singleton): """ Not a Number. Explanation =========== This serves as a place holder for numeric values that are indeterminate. Most operations on NaN, produce another NaN. Most indeterminate forms, such as ``0/0`` or ``oo - oo` produce NaN. Two exceptions are ``0**0`` and ``oo**0``, which all produce ``1`` (this is consistent with Python's float). NaN is loosely related to floating point nan, which is defined in the IEEE 754 floating point standard, and corresponds to the Python ``float('nan')``. Differences are noted below. NaN is mathematically not equal to anything else, even NaN itself. This explains the initially counter-intuitive results with ``Eq`` and ``==`` in the examples below. NaN is not comparable so inequalities raise a TypeError. This is in contrast with floating point nan where all inequalities are false. NaN is a singleton, and can be accessed by ``S.NaN``, or can be imported as ``nan``. Examples ======== >>> from sympy import nan, S, oo, Eq >>> nan is S.NaN True >>> oo - oo nan >>> nan + 1 nan >>> Eq(nan, nan) # mathematical equality False >>> nan == nan # structural equality True References ========== .. [1] https://en.wikipedia.org/wiki/NaN """ is_commutative = True is_extended_real = None is_real = None is_rational = None is_algebraic = None is_transcendental = None is_integer = None is_comparable = False is_finite = None is_zero = None is_prime = None is_positive = None is_negative = None is_number = True __slots__ = () def __new__(cls): return AtomicExpr.__new__(cls) def _latex(self, printer): return r"\text{NaN}" def __neg__(self): return self @_sympifyit('other', NotImplemented) def __add__(self, other): return self @_sympifyit('other', NotImplemented) def __sub__(self, other): return self @_sympifyit('other', NotImplemented) def __mul__(self, other): return self @_sympifyit('other', NotImplemented) def __truediv__(self, other): return self def floor(self): return self def ceiling(self): return self def _as_mpf_val(self, prec): return _mpf_nan def __hash__(self): return super().__hash__() def __eq__(self, other): # NaN is structurally equal to another NaN return other is S.NaN def __ne__(self, other): return other is not S.NaN # Expr will _sympify and raise TypeError __gt__ = Expr.__gt__ __ge__ = Expr.__ge__ __lt__ = Expr.__lt__ __le__ = Expr.__le__ nan = S.NaN @dispatch(NaN, Expr) # type:ignore def _eval_is_eq(a, b): # noqa:F811 return False class ComplexInfinity(AtomicExpr, metaclass=Singleton): r"""Complex infinity. Explanation =========== In complex analysis the symbol `\tilde\infty`, called "complex infinity", represents a quantity with infinite magnitude, but undetermined complex phase. ComplexInfinity is a singleton, and can be accessed by ``S.ComplexInfinity``, or can be imported as ``zoo``. Examples ======== >>> from sympy import zoo >>> zoo + 42 zoo >>> 42/zoo 0 >>> zoo + zoo nan >>> zoo*zoo zoo See Also ======== Infinity """ is_commutative = True is_infinite = True is_number = True is_prime = False is_complex = False is_extended_real = False kind = NumberKind __slots__ = () def __new__(cls): return AtomicExpr.__new__(cls) def _latex(self, printer): return r"\tilde{\infty}" @staticmethod def __abs__(): return S.Infinity def floor(self): return self def ceiling(self): return self @staticmethod def __neg__(): return S.ComplexInfinity def _eval_power(self, expt): if expt is S.ComplexInfinity: return S.NaN if isinstance(expt, Number): if expt.is_zero: return S.NaN else: if expt.is_positive: return S.ComplexInfinity else: return S.Zero zoo = S.ComplexInfinity class NumberSymbol(AtomicExpr): is_commutative = True is_finite = True is_number = True __slots__ = () is_NumberSymbol = True kind = NumberKind def __new__(cls): return AtomicExpr.__new__(cls) def approximation(self, number_cls): """ Return an interval with number_cls endpoints that contains the value of NumberSymbol. If not implemented, then return None. """ def _eval_evalf(self, prec): return Float._new(self._as_mpf_val(prec), prec) def __eq__(self, other): try: other = _sympify(other) except SympifyError: return NotImplemented if self is other: return True if other.is_Number and self.is_irrational: return False return False # NumberSymbol != non-(Number|self) def __ne__(self, other): return not self == other def __le__(self, other): if self is other: return S.true return Expr.__le__(self, other) def __ge__(self, other): if self is other: return S.true return Expr.__ge__(self, other) def __int__(self): # subclass with appropriate return value raise NotImplementedError def __hash__(self): return super().__hash__() class Exp1(NumberSymbol, metaclass=Singleton): r"""The `e` constant. Explanation =========== The transcendental number `e = 2.718281828\ldots` is the base of the natural logarithm and of the exponential function, `e = \exp(1)`. Sometimes called Euler's number or Napier's constant. Exp1 is a singleton, and can be accessed by ``S.Exp1``, or can be imported as ``E``. Examples ======== >>> from sympy import exp, log, E >>> E is exp(1) True >>> log(E) 1 References ========== .. [1] https://en.wikipedia.org/wiki/E_%28mathematical_constant%29 """ is_real = True is_positive = True is_negative = False # XXX Forces is_negative/is_nonnegative is_irrational = True is_number = True is_algebraic = False is_transcendental = True __slots__ = () def _latex(self, printer): return r"e" @staticmethod def __abs__(): return S.Exp1 def __int__(self): return 2 def _as_mpf_val(self, prec): return mpf_e(prec) def approximation_interval(self, number_cls): if issubclass(number_cls, Integer): return (Integer(2), Integer(3)) elif issubclass(number_cls, Rational): pass def _eval_power(self, expt): from sympy import exp if global_parameters.exp_is_pow: return self._eval_power_exp_is_pow(expt) else: return exp(expt) def _eval_power_exp_is_pow(self, arg): from ..functions.elementary.exponential import log from . import Add, Mul, Pow if arg.is_Number: if arg is oo: return oo elif arg == -oo: return S.Zero elif isinstance(arg, log): return arg.args[0] # don't autoexpand Pow or Mul (see the issue 3351): elif not arg.is_Add: Ioo = I*oo if arg in [Ioo, -Ioo]: return nan coeff = arg.coeff(pi*I) if coeff: if (2*coeff).is_integer: if coeff.is_even: return S.One elif coeff.is_odd: return S.NegativeOne elif (coeff + S.Half).is_even: return -I elif (coeff + S.Half).is_odd: return I elif coeff.is_Rational: ncoeff = coeff % 2 # restrict to [0, 2pi) if ncoeff > 1: # restrict to (-pi, pi] ncoeff -= 2 if ncoeff != coeff: return S.Exp1**(ncoeff*S.Pi*S.ImaginaryUnit) # Warning: code in risch.py will be very sensitive to changes # in this (see DifferentialExtension). # look for a single log factor coeff, terms = arg.as_coeff_Mul() # but it can't be multiplied by oo if coeff in (oo, -oo): return coeffs, log_term = [coeff], None for term in Mul.make_args(terms): if isinstance(term, log): if log_term is None: log_term = term.args[0] else: return elif term.is_comparable: coeffs.append(term) else: return return log_term**Mul(*coeffs) if log_term else None elif arg.is_Add: out = [] add = [] argchanged = False for a in arg.args: if a is S.One: add.append(a) continue newa = self**a if isinstance(newa, Pow) and newa.base is self: if newa.exp != a: add.append(newa.exp) argchanged = True else: add.append(a) else: out.append(newa) if out or argchanged: return Mul(*out)*Pow(self, Add(*add), evaluate=False) elif arg.is_Matrix: return arg.exp() def _eval_rewrite_as_sin(self, **kwargs): from sympy import sin I = S.ImaginaryUnit return sin(I + S.Pi/2) - I*sin(I) def _eval_rewrite_as_cos(self, **kwargs): from sympy import cos I = S.ImaginaryUnit return cos(I) + I*cos(I + S.Pi/2) E = S.Exp1 class Pi(NumberSymbol, metaclass=Singleton): r"""The `\pi` constant. Explanation =========== The transcendental number `\pi = 3.141592654\ldots` represents the ratio of a circle's circumference to its diameter, the area of the unit circle, the half-period of trigonometric functions, and many other things in mathematics. Pi is a singleton, and can be accessed by ``S.Pi``, or can be imported as ``pi``. Examples ======== >>> from sympy import S, pi, oo, sin, exp, integrate, Symbol >>> S.Pi pi >>> pi > 3 True >>> pi.is_irrational True >>> x = Symbol('x') >>> sin(x + 2*pi) sin(x) >>> integrate(exp(-x**2), (x, -oo, oo)) sqrt(pi) References ========== .. [1] https://en.wikipedia.org/wiki/Pi """ is_real = True is_positive = True is_negative = False is_irrational = True is_number = True is_algebraic = False is_transcendental = True __slots__ = () def _latex(self, printer): return r"\pi" @staticmethod def __abs__(): return S.Pi def __int__(self): return 3 def _as_mpf_val(self, prec): return mpf_pi(prec) def approximation_interval(self, number_cls): if issubclass(number_cls, Integer): return (Integer(3), Integer(4)) elif issubclass(number_cls, Rational): return (Rational(223, 71, 1), Rational(22, 7, 1)) pi = S.Pi class GoldenRatio(NumberSymbol, metaclass=Singleton): r"""The golden ratio, `\phi`. Explanation =========== `\phi = \frac{1 + \sqrt{5}}{2}` is algebraic number. Two quantities are in the golden ratio if their ratio is the same as the ratio of their sum to the larger of the two quantities, i.e. their maximum. GoldenRatio is a singleton, and can be accessed by ``S.GoldenRatio``. Examples ======== >>> from sympy import S >>> S.GoldenRatio > 1 True >>> S.GoldenRatio.expand(func=True) 1/2 + sqrt(5)/2 >>> S.GoldenRatio.is_irrational True References ========== .. [1] https://en.wikipedia.org/wiki/Golden_ratio """ is_real = True is_positive = True is_negative = False is_irrational = True is_number = True is_algebraic = True is_transcendental = False __slots__ = () def _latex(self, printer): return r"\phi" def __int__(self): return 1 def _as_mpf_val(self, prec): # XXX track down why this has to be increased rv = mlib.from_man_exp(phi_fixed(prec + 10), -prec - 10) return mpf_norm(rv, prec) def _eval_expand_func(self, **hints): from sympy import sqrt return S.Half + S.Half*sqrt(5) def approximation_interval(self, number_cls): if issubclass(number_cls, Integer): return (S.One, Rational(2)) elif issubclass(number_cls, Rational): pass _eval_rewrite_as_sqrt = _eval_expand_func class TribonacciConstant(NumberSymbol, metaclass=Singleton): r"""The tribonacci constant. Explanation =========== The tribonacci numbers are like the Fibonacci numbers, but instead of starting with two predetermined terms, the sequence starts with three predetermined terms and each term afterwards is the sum of the preceding three terms. The tribonacci constant is the ratio toward which adjacent tribonacci numbers tend. It is a root of the polynomial `x^3 - x^2 - x - 1 = 0`, and also satisfies the equation `x + x^{-3} = 2`. TribonacciConstant is a singleton, and can be accessed by ``S.TribonacciConstant``. Examples ======== >>> from sympy import S >>> S.TribonacciConstant > 1 True >>> S.TribonacciConstant.expand(func=True) 1/3 + (19 - 3*sqrt(33))**(1/3)/3 + (3*sqrt(33) + 19)**(1/3)/3 >>> S.TribonacciConstant.is_irrational True >>> S.TribonacciConstant.n(20) 1.8392867552141611326 References ========== .. [1] https://en.wikipedia.org/wiki/Generalizations_of_Fibonacci_numbers#Tribonacci_numbers """ is_real = True is_positive = True is_negative = False is_irrational = True is_number = True is_algebraic = True is_transcendental = False __slots__ = () def _latex(self, printer): return r"\text{TribonacciConstant}" def __int__(self): return 1 def _eval_evalf(self, prec): rv = self._eval_expand_func(function=True)._eval_evalf(prec + 4) return Float(rv, precision=prec) def _eval_expand_func(self, **hints): from sympy import sqrt, cbrt return (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 def approximation_interval(self, number_cls): if issubclass(number_cls, Integer): return (S.One, Rational(2)) elif issubclass(number_cls, Rational): pass _eval_rewrite_as_sqrt = _eval_expand_func class EulerGamma(NumberSymbol, metaclass=Singleton): r"""The Euler-Mascheroni constant. Explanation =========== `\gamma = 0.5772157\ldots` (also called Euler's constant) is a mathematical constant recurring in analysis and number theory. It is defined as the limiting difference between the harmonic series and the natural logarithm: .. math:: \gamma = \lim\limits_{n\to\infty} \left(\sum\limits_{k=1}^n\frac{1}{k} - \ln n\right) EulerGamma is a singleton, and can be accessed by ``S.EulerGamma``. Examples ======== >>> from sympy import S >>> S.EulerGamma.is_irrational >>> S.EulerGamma > 0 True >>> S.EulerGamma > 1 False References ========== .. [1] https://en.wikipedia.org/wiki/Euler%E2%80%93Mascheroni_constant """ is_real = True is_positive = True is_negative = False is_irrational = None is_number = True __slots__ = () def _latex(self, printer): return r"\gamma" def __int__(self): return 0 def _as_mpf_val(self, prec): # XXX track down why this has to be increased v = mlib.libhyper.euler_fixed(prec + 10) rv = mlib.from_man_exp(v, -prec - 10) return mpf_norm(rv, prec) def approximation_interval(self, number_cls): if issubclass(number_cls, Integer): return (S.Zero, S.One) elif issubclass(number_cls, Rational): return (S.Half, Rational(3, 5, 1)) class Catalan(NumberSymbol, metaclass=Singleton): r"""Catalan's constant. Explanation =========== `K = 0.91596559\ldots` is given by the infinite series .. math:: K = \sum_{k=0}^{\infty} \frac{(-1)^k}{(2k+1)^2} Catalan is a singleton, and can be accessed by ``S.Catalan``. Examples ======== >>> from sympy import S >>> S.Catalan.is_irrational >>> S.Catalan > 0 True >>> S.Catalan > 1 False References ========== .. [1] https://en.wikipedia.org/wiki/Catalan%27s_constant """ is_real = True is_positive = True is_negative = False is_irrational = None is_number = True __slots__ = () def __int__(self): return 0 def _as_mpf_val(self, prec): # XXX track down why this has to be increased v = mlib.catalan_fixed(prec + 10) rv = mlib.from_man_exp(v, -prec - 10) return mpf_norm(rv, prec) def approximation_interval(self, number_cls): if issubclass(number_cls, Integer): return (S.Zero, S.One) elif issubclass(number_cls, Rational): return (Rational(9, 10, 1), S.One) def _eval_rewrite_as_Sum(self, k_sym=None, symbols=None): from sympy import Sum, Dummy if (k_sym is not None) or (symbols is not None): return self k = Dummy('k', integer=True, nonnegative=True) return Sum((-1)**k / (2*k+1)**2, (k, 0, S.Infinity)) class ImaginaryUnit(AtomicExpr, metaclass=Singleton): r"""The imaginary unit, `i = \sqrt{-1}`. I is a singleton, and can be accessed by ``S.I``, or can be imported as ``I``. Examples ======== >>> from sympy import I, sqrt >>> sqrt(-1) I >>> I*I -1 >>> 1/I -I References ========== .. [1] https://en.wikipedia.org/wiki/Imaginary_unit """ is_commutative = True is_imaginary = True is_finite = True is_number = True is_algebraic = True is_transcendental = False kind = NumberKind __slots__ = () def _latex(self, printer): return printer._settings['imaginary_unit_latex'] @staticmethod def __abs__(): return S.One def _eval_evalf(self, prec): return self def _eval_conjugate(self): return -S.ImaginaryUnit def _eval_power(self, expt): """ b is I = sqrt(-1) e is symbolic object but not equal to 0, 1 I**r -> (-1)**(r/2) -> exp(r/2*Pi*I) -> sin(Pi*r/2) + cos(Pi*r/2)*I, r is decimal I**0 mod 4 -> 1 I**1 mod 4 -> I I**2 mod 4 -> -1 I**3 mod 4 -> -I """ if isinstance(expt, Integer): expt = expt % 4 if expt == 0: return S.One elif expt == 1: return S.ImaginaryUnit elif expt == 2: return S.NegativeOne elif expt == 3: return -S.ImaginaryUnit if isinstance(expt, Rational): i, r = divmod(expt, 2) rv = Pow(S.ImaginaryUnit, r, evaluate=False) if i % 2: return Mul(S.NegativeOne, rv, evaluate=False) return rv def as_base_exp(self): return S.NegativeOne, S.Half @property def _mpc_(self): return (Float(0)._mpf_, Float(1)._mpf_) I = S.ImaginaryUnit @dispatch(Tuple, Number) # type:ignore def _eval_is_eq(self, other): # noqa: F811 return False def sympify_fractions(f): return Rational(f.numerator, f.denominator, 1) converter[fractions.Fraction] = sympify_fractions if HAS_GMPY: def sympify_mpz(x): return Integer(int(x)) # XXX: The sympify_mpq function here was never used because it is # overridden by the other sympify_mpq function below. Maybe it should just # be removed or maybe it should be used for something... def sympify_mpq(x): return Rational(int(x.numerator), int(x.denominator)) converter[type(gmpy.mpz(1))] = sympify_mpz converter[type(gmpy.mpq(1, 2))] = sympify_mpq def sympify_mpmath_mpq(x): p, q = x._mpq_ return Rational(p, q, 1) converter[type(mpmath.rational.mpq(1, 2))] = sympify_mpmath_mpq def sympify_mpmath(x): return Expr._from_mpmath(x, x.context.prec) converter[mpnumeric] = sympify_mpmath def sympify_complex(a): real, imag = list(map(sympify, (a.real, a.imag))) return real + S.ImaginaryUnit*imag converter[complex] = sympify_complex from .power import Pow, integer_nthroot from .mul import Mul Mul.identity = One() from .add import Add Add.identity = Zero() def _register_classes(): numbers.Number.register(Number) numbers.Real.register(Float) numbers.Rational.register(Rational) numbers.Integral.register(Integer) _register_classes() sympy-sympy-1.9/sympy/core/operations.py000066400000000000000000000574001412543434000205770ustar00rootroot00000000000000from operator import attrgetter from typing import Tuple, Type from collections import defaultdict from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.core.sympify import _sympify as _sympify_, sympify from sympy.core.basic import Basic from sympy.core.cache import cacheit from sympy.core.compatibility import ordered from sympy.core.logic import fuzzy_and from sympy.core.parameters import global_parameters from sympy.utilities.iterables import sift from sympy.multipledispatch.dispatcher import (Dispatcher, ambiguity_register_error_ignore_dup, str_signature, RaiseNotImplementedError) class AssocOp(Basic): """ Associative operations, can separate noncommutative and commutative parts. (a op b) op c == a op (b op c) == a op b op c. Base class for Add and Mul. This is an abstract base class, concrete derived classes must define the attribute `identity`. Parameters ========== *args : Arguments which are operated evaluate : bool, optional Evaluate the operation. If not passed, refer to ``global_parameters.evaluate``. """ # for performance reason, we don't let is_commutative go to assumptions, # and keep it right here __slots__ = ('is_commutative',) # type: Tuple[str, ...] _args_type = None # type: Type[Basic] @cacheit def __new__(cls, *args, evaluate=None, _sympify=True): from sympy import Order # Allow faster processing by passing ``_sympify=False``, if all arguments # are already sympified. if _sympify: args = list(map(_sympify_, args)) # Disallow non-Expr args in Add/Mul typ = cls._args_type if typ is not None: from sympy.core.relational import Relational if any(isinstance(arg, Relational) for arg in args): raise TypeError("Relational can not be used in %s" % cls.__name__) # This should raise TypeError once deprecation period is over: if not all(isinstance(arg, typ) for arg in args): SymPyDeprecationWarning( feature="Add/Mul with non-Expr args", useinstead="Expr args", issue=19445, deprecated_since_version="1.7" ).warn() if evaluate is None: evaluate = global_parameters.evaluate if not evaluate: obj = cls._from_args(args) obj = cls._exec_constructor_postprocessors(obj) return obj args = [a for a in args if a is not cls.identity] if len(args) == 0: return cls.identity if len(args) == 1: return args[0] c_part, nc_part, order_symbols = cls.flatten(args) is_commutative = not nc_part obj = cls._from_args(c_part + nc_part, is_commutative) obj = cls._exec_constructor_postprocessors(obj) if order_symbols is not None: return Order(obj, *order_symbols) return obj @classmethod def _from_args(cls, args, is_commutative=None): """Create new instance with already-processed args. If the args are not in canonical order, then a non-canonical result will be returned, so use with caution. The order of args may change if the sign of the args is changed.""" if len(args) == 0: return cls.identity elif len(args) == 1: return args[0] obj = super().__new__(cls, *args) if is_commutative is None: is_commutative = fuzzy_and(a.is_commutative for a in args) obj.is_commutative = is_commutative return obj def _new_rawargs(self, *args, reeval=True, **kwargs): """Create new instance of own class with args exactly as provided by caller but returning the self class identity if args is empty. Examples ======== This is handy when we want to optimize things, e.g. >>> from sympy import Mul, S >>> from sympy.abc import x, y >>> e = Mul(3, x, y) >>> e.args (3, x, y) >>> Mul(*e.args[1:]) x*y >>> e._new_rawargs(*e.args[1:]) # the same as above, but faster x*y Note: use this with caution. There is no checking of arguments at all. This is best used when you are rebuilding an Add or Mul after simply removing one or more args. If, for example, modifications, result in extra 1s being inserted they will show up in the result: >>> m = (x*y)._new_rawargs(S.One, x); m 1*x >>> m == x False >>> m.is_Mul True Another issue to be aware of is that the commutativity of the result is based on the commutativity of self. If you are rebuilding the terms that came from a commutative object then there will be no problem, but if self was non-commutative then what you are rebuilding may now be commutative. Although this routine tries to do as little as possible with the input, getting the commutativity right is important, so this level of safety is enforced: commutativity will always be recomputed if self is non-commutative and kwarg `reeval=False` has not been passed. """ if reeval and self.is_commutative is False: is_commutative = None else: is_commutative = self.is_commutative return self._from_args(args, is_commutative) @classmethod def flatten(cls, seq): """Return seq so that none of the elements are of type `cls`. This is the vanilla routine that will be used if a class derived from AssocOp does not define its own flatten routine.""" # apply associativity, no commutativity property is used new_seq = [] while seq: o = seq.pop() if o.__class__ is cls: # classes must match exactly seq.extend(o.args) else: new_seq.append(o) new_seq.reverse() # c_part, nc_part, order_symbols return [], new_seq, None def _matches_commutative(self, expr, repl_dict={}, old=False): """ Matches Add/Mul "pattern" to an expression "expr". repl_dict ... a dictionary of (wild: expression) pairs, that get returned with the results This function is the main workhorse for Add/Mul. Examples ======== >>> from sympy import symbols, Wild, sin >>> a = Wild("a") >>> b = Wild("b") >>> c = Wild("c") >>> x, y, z = symbols("x y z") >>> (a+sin(b)*c)._matches_commutative(x+sin(y)*z) {a_: x, b_: y, c_: z} In the example above, "a+sin(b)*c" is the pattern, and "x+sin(y)*z" is the expression. The repl_dict contains parts that were already matched. For example here: >>> (x+sin(b)*c)._matches_commutative(x+sin(y)*z, repl_dict={a: x}) {a_: x, b_: y, c_: z} the only function of the repl_dict is to return it in the result, e.g. if you omit it: >>> (x+sin(b)*c)._matches_commutative(x+sin(y)*z) {b_: y, c_: z} the "a: x" is not returned in the result, but otherwise it is equivalent. """ # make sure expr is Expr if pattern is Expr from .expr import Add, Expr from sympy import Mul repl_dict = repl_dict.copy() if isinstance(self, Expr) and not isinstance(expr, Expr): return None # handle simple patterns if self == expr: return repl_dict d = self._matches_simple(expr, repl_dict) if d is not None: return d # eliminate exact part from pattern: (2+a+w1+w2).matches(expr) -> (w1+w2).matches(expr-a-2) from .function import WildFunction from .symbol import Wild wild_part, exact_part = sift(self.args, lambda p: p.has(Wild, WildFunction) and not expr.has(p), binary=True) if not exact_part: wild_part = list(ordered(wild_part)) if self.is_Add: # in addition to normal ordered keys, impose # sorting on Muls with leading Number to put # them in order wild_part = sorted(wild_part, key=lambda x: x.args[0] if x.is_Mul and x.args[0].is_Number else 0) else: exact = self._new_rawargs(*exact_part) free = expr.free_symbols if free and (exact.free_symbols - free): # there are symbols in the exact part that are not # in the expr; but if there are no free symbols, let # the matching continue return None newexpr = self._combine_inverse(expr, exact) if not old and (expr.is_Add or expr.is_Mul): if newexpr.count_ops() > expr.count_ops(): return None newpattern = self._new_rawargs(*wild_part) return newpattern.matches(newexpr, repl_dict) # now to real work ;) i = 0 saw = set() while expr not in saw: saw.add(expr) args = tuple(ordered(self.make_args(expr))) if self.is_Add and expr.is_Add: # in addition to normal ordered keys, impose # sorting on Muls with leading Number to put # them in order args = tuple(sorted(args, key=lambda x: x.args[0] if x.is_Mul and x.args[0].is_Number else 0)) expr_list = (self.identity,) + args for last_op in reversed(expr_list): for w in reversed(wild_part): d1 = w.matches(last_op, repl_dict) if d1 is not None: d2 = self.xreplace(d1).matches(expr, d1) if d2 is not None: return d2 if i == 0: if self.is_Mul: # make e**i look like Mul if expr.is_Pow and expr.exp.is_Integer: if expr.exp > 0: expr = Mul(*[expr.base, expr.base**(expr.exp - 1)], evaluate=False) else: expr = Mul(*[1/expr.base, expr.base**(expr.exp + 1)], evaluate=False) i += 1 continue elif self.is_Add: # make i*e look like Add c, e = expr.as_coeff_Mul() if abs(c) > 1: if c > 0: expr = Add(*[e, (c - 1)*e], evaluate=False) else: expr = Add(*[-e, (c + 1)*e], evaluate=False) i += 1 continue # try collection on non-Wild symbols from sympy.simplify.radsimp import collect was = expr did = set() for w in reversed(wild_part): c, w = w.as_coeff_mul(Wild) free = c.free_symbols - did if free: did.update(free) expr = collect(expr, free) if expr != was: i += 0 continue break # if we didn't continue, there is nothing more to do return def _has_matcher(self): """Helper for .has()""" def _ncsplit(expr): # this is not the same as args_cnc because here # we don't assume expr is a Mul -- hence deal with args -- # and always return a set. cpart, ncpart = sift(expr.args, lambda arg: arg.is_commutative is True, binary=True) return set(cpart), ncpart c, nc = _ncsplit(self) cls = self.__class__ def is_in(expr): if expr == self: return True elif not isinstance(expr, Basic): return False elif isinstance(expr, cls): _c, _nc = _ncsplit(expr) if (c & _c) == c: if not nc: return True elif len(nc) <= len(_nc): for i in range(len(_nc) - len(nc) + 1): if _nc[i:i + len(nc)] == nc: return True return False return is_in def _eval_evalf(self, prec): """ Evaluate the parts of self that are numbers; if the whole thing was a number with no functions it would have been evaluated, but it wasn't so we must judiciously extract the numbers and reconstruct the object. This is *not* simply replacing numbers with evaluated numbers. Numbers should be handled in the largest pure-number expression as possible. So the code below separates ``self`` into number and non-number parts and evaluates the number parts and walks the args of the non-number part recursively (doing the same thing). """ from .add import Add from .mul import Mul from .symbol import Symbol from .function import AppliedUndef if isinstance(self, (Mul, Add)): x, tail = self.as_independent(Symbol, AppliedUndef) # if x is an AssocOp Function then the _evalf below will # call _eval_evalf (here) so we must break the recursion if not (tail is self.identity or isinstance(x, AssocOp) and x.is_Function or x is self.identity and isinstance(tail, AssocOp)): # here, we have a number so we just call to _evalf with prec; # prec is not the same as n, it is the binary precision so # that's why we don't call to evalf. x = x._evalf(prec) if x is not self.identity else self.identity args = [] tail_args = tuple(self.func.make_args(tail)) for a in tail_args: # here we call to _eval_evalf since we don't know what we # are dealing with and all other _eval_evalf routines should # be doing the same thing (i.e. taking binary prec and # finding the evalf-able args) newa = a._eval_evalf(prec) if newa is None: args.append(a) else: args.append(newa) return self.func(x, *args) # this is the same as above, but there were no pure-number args to # deal with args = [] for a in self.args: newa = a._eval_evalf(prec) if newa is None: args.append(a) else: args.append(newa) return self.func(*args) @classmethod def make_args(cls, expr): """ Return a sequence of elements `args` such that cls(*args) == expr Examples ======== >>> from sympy import Symbol, Mul, Add >>> x, y = map(Symbol, 'xy') >>> Mul.make_args(x*y) (x, y) >>> Add.make_args(x*y) (x*y,) >>> set(Add.make_args(x*y + y)) == set([y, x*y]) True """ if isinstance(expr, cls): return expr.args else: return (sympify(expr),) def doit(self, **hints): if hints.get('deep', True): terms = [term.doit(**hints) for term in self.args] else: terms = self.args return self.func(*terms, evaluate=True) class ShortCircuit(Exception): pass class LatticeOp(AssocOp): """ Join/meet operations of an algebraic lattice[1]. Explanation =========== These binary operations are associative (op(op(a, b), c) = op(a, op(b, c))), commutative (op(a, b) = op(b, a)) and idempotent (op(a, a) = op(a) = a). Common examples are AND, OR, Union, Intersection, max or min. They have an identity element (op(identity, a) = a) and an absorbing element conventionally called zero (op(zero, a) = zero). This is an abstract base class, concrete derived classes must declare attributes zero and identity. All defining properties are then respected. Examples ======== >>> from sympy import Integer >>> from sympy.core.operations import LatticeOp >>> class my_join(LatticeOp): ... zero = Integer(0) ... identity = Integer(1) >>> my_join(2, 3) == my_join(3, 2) True >>> my_join(2, my_join(3, 4)) == my_join(2, 3, 4) True >>> my_join(0, 1, 4, 2, 3, 4) 0 >>> my_join(1, 2) 2 References: .. [1] https://en.wikipedia.org/wiki/Lattice_%28order%29 """ is_commutative = True def __new__(cls, *args, **options): args = (_sympify_(arg) for arg in args) try: # /!\ args is a generator and _new_args_filter # must be careful to handle as such; this # is done so short-circuiting can be done # without having to sympify all values _args = frozenset(cls._new_args_filter(args)) except ShortCircuit: return sympify(cls.zero) if not _args: return sympify(cls.identity) elif len(_args) == 1: return set(_args).pop() else: # XXX in almost every other case for __new__, *_args is # passed along, but the expectation here is for _args obj = super(AssocOp, cls).__new__(cls, *ordered(_args)) obj._argset = _args return obj @classmethod def _new_args_filter(cls, arg_sequence, call_cls=None): """Generator filtering args""" ncls = call_cls or cls for arg in arg_sequence: if arg == ncls.zero: raise ShortCircuit(arg) elif arg == ncls.identity: continue elif arg.func == ncls: yield from arg.args else: yield arg @classmethod def make_args(cls, expr): """ Return a set of args such that cls(*arg_set) == expr. """ if isinstance(expr, cls): return expr._argset else: return frozenset([sympify(expr)]) @staticmethod def _compare_pretty(a, b): return (str(a) > str(b)) - (str(a) < str(b)) class AssocOpDispatcher: """ Handler dispatcher for associative operators .. notes:: This approach is experimental, and can be replaced or deleted in the future. See https://github.com/sympy/sympy/pull/19463. Explanation =========== If arguments of different types are passed, the classes which handle the operation for each type are collected. Then, a class which performs the operation is selected by recursive binary dispatching. Dispatching relation can be registered by ``register_handlerclass`` method. Priority registration is unordered. You cannot make ``A*B`` and ``B*A`` refer to different handler classes. All logic dealing with the order of arguments must be implemented in the handler class. Examples ======== >>> from sympy import Add, Expr, Symbol >>> from sympy.core.add import add >>> class NewExpr(Expr): ... @property ... def _add_handler(self): ... return NewAdd >>> class NewAdd(NewExpr, Add): ... pass >>> add.register_handlerclass((Add, NewAdd), NewAdd) >>> a, b = Symbol('a'), NewExpr() >>> add(a, b) == NewAdd(a, b) True """ def __init__(self, name, doc=None): self.name = name self.doc = doc self.handlerattr = "_%s_handler" % name self._handlergetter = attrgetter(self.handlerattr) self._dispatcher = Dispatcher(name) def __repr__(self): return "" % self.name def register_handlerclass(self, classes, typ, on_ambiguity=ambiguity_register_error_ignore_dup): """ Register the handler class for two classes, in both straight and reversed order. Paramteters =========== classes : tuple of two types Classes who are compared with each other. typ: Class which is registered to represent *cls1* and *cls2*. Handler method of *self* must be implemented in this class. """ if not len(classes) == 2: raise RuntimeError( "Only binary dispatch is supported, but got %s types: <%s>." % ( len(classes), str_signature(classes) )) if len(set(classes)) == 1: raise RuntimeError( "Duplicate types <%s> cannot be dispatched." % str_signature(classes) ) self._dispatcher.add(tuple(classes), typ, on_ambiguity=on_ambiguity) self._dispatcher.add(tuple(reversed(classes)), typ, on_ambiguity=on_ambiguity) @cacheit def __call__(self, *args, _sympify=True, **kwargs): """ Parameters ========== *args : Arguments which are operated """ if _sympify: args = tuple(map(_sympify_, args)) handlers = frozenset(map(self._handlergetter, args)) # no need to sympify again return self.dispatch(handlers)(*args, _sympify=False, **kwargs) @cacheit def dispatch(self, handlers): """ Select the handler class, and return its handler method. """ # Quick exit for the case where all handlers are same if len(handlers) == 1: h, = handlers if not isinstance(h, type): raise RuntimeError("Handler {!r} is not a type.".format(h)) return h # Recursively select with registered binary priority for i, typ in enumerate(handlers): if not isinstance(typ, type): raise RuntimeError("Handler {!r} is not a type.".format(typ)) if i == 0: handler = typ else: prev_handler = handler handler = self._dispatcher.dispatch(prev_handler, typ) if not isinstance(handler, type): raise RuntimeError( "Dispatcher for {!r} and {!r} must return a type, but got {!r}".format( prev_handler, typ, handler )) # return handler class return handler @property def __doc__(self): docs = [ "Multiply dispatched associative operator: %s" % self.name, "Note that support for this is experimental, see the docs for :class:`AssocOpDispatcher` for details" ] if self.doc: docs.append(self.doc) s = "Registered handler classes\n" s += '=' * len(s) docs.append(s) amb_sigs = [] typ_sigs = defaultdict(list) for sigs in self._dispatcher.ordering[::-1]: key = self._dispatcher.funcs[sigs] typ_sigs[key].append(sigs) for typ, sigs in typ_sigs.items(): sigs_str = ', '.join('<%s>' % str_signature(sig) for sig in sigs) if isinstance(typ, RaiseNotImplementedError): amb_sigs.append(sigs_str) continue s = 'Inputs: %s\n' % sigs_str s += '-' * len(s) + '\n' s += typ.__name__ docs.append(s) if amb_sigs: s = "Ambiguous handler classes\n" s += '=' * len(s) docs.append(s) s = '\n'.join(amb_sigs) docs.append(s) return '\n\n'.join(docs) sympy-sympy-1.9/sympy/core/parameters.py000066400000000000000000000072451412543434000205610ustar00rootroot00000000000000"""Thread-safe global parameters""" from .cache import clear_cache from contextlib import contextmanager from threading import local class _global_parameters(local): """ Thread-local global parameters. Explanation =========== This class generates thread-local container for SymPy's global parameters. Every global parameters must be passed as keyword argument when generating its instance. A variable, `global_parameters` is provided as default instance for this class. WARNING! Although the global parameters are thread-local, SymPy's cache is not by now. This may lead to undesired result in multi-threading operations. Examples ======== >>> from sympy.abc import x >>> from sympy.core.cache import clear_cache >>> from sympy.core.parameters import global_parameters as gp >>> gp.evaluate True >>> x+x 2*x >>> log = [] >>> def f(): ... clear_cache() ... gp.evaluate = False ... log.append(x+x) ... clear_cache() >>> import threading >>> thread = threading.Thread(target=f) >>> thread.start() >>> thread.join() >>> print(log) [x + x] >>> gp.evaluate True >>> x+x 2*x References ========== .. [1] https://docs.python.org/3/library/threading.html """ def __init__(self, **kwargs): self.__dict__.update(kwargs) def __setattr__(self, name, value): if getattr(self, name) != value: clear_cache() return super().__setattr__(name, value) global_parameters = _global_parameters(evaluate=True, distribute=True, exp_is_pow=False) @contextmanager def evaluate(x): """ Control automatic evaluation Explanation =========== This context manager controls whether or not all SymPy functions evaluate by default. Note that much of SymPy expects evaluated expressions. This functionality is experimental and is unlikely to function as intended on large expressions. Examples ======== >>> from sympy.abc import x >>> from sympy.core.parameters import evaluate >>> print(x + x) 2*x >>> with evaluate(False): ... print(x + x) x + x """ old = global_parameters.evaluate try: global_parameters.evaluate = x yield finally: global_parameters.evaluate = old @contextmanager def distribute(x): """ Control automatic distribution of Number over Add Explanation =========== This context manager controls whether or not Mul distribute Number over Add. Plan is to avoid distributing Number over Add in all of sympy. Once that is done, this contextmanager will be removed. Examples ======== >>> from sympy.abc import x >>> from sympy.core.parameters import distribute >>> print(2*(x + 1)) 2*x + 2 >>> with distribute(False): ... print(2*(x + 1)) 2*(x + 1) """ old = global_parameters.distribute try: global_parameters.distribute = x yield finally: global_parameters.distribute = old @contextmanager def _exp_is_pow(x): """ Control whether `e^x` should be represented as ``exp(x)`` or a ``Pow(E, x)``. Examples ======== >>> from sympy import exp >>> from sympy.abc import x >>> from sympy.core.parameters import _exp_is_pow >>> with _exp_is_pow(True): print(type(exp(x))) >>> with _exp_is_pow(False): print(type(exp(x))) exp """ old = global_parameters.exp_is_pow clear_cache() try: global_parameters.exp_is_pow = x yield finally: clear_cache() global_parameters.exp_is_pow = old sympy-sympy-1.9/sympy/core/power.py000066400000000000000000002142321412543434000175460ustar00rootroot00000000000000from typing import Callable from math import log as _log from .sympify import _sympify from .cache import cacheit from .singleton import S from .expr import Expr from .evalf import PrecisionExhausted from .function import (_coeff_isneg, expand_complex, expand_multinomial, expand_mul, _mexpand) from .logic import fuzzy_bool, fuzzy_not, fuzzy_and, fuzzy_or from .compatibility import as_int, HAS_GMPY, gmpy from .parameters import global_parameters from .kind import NumberKind, UndefinedKind from sympy.utilities.iterables import sift from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.multipledispatch import Dispatcher from mpmath.libmp import sqrtrem as mpmath_sqrtrem from math import sqrt as _sqrt def isqrt(n): """Return the largest integer less than or equal to sqrt(n).""" if n < 0: raise ValueError("n must be nonnegative") n = int(n) # Fast path: with IEEE 754 binary64 floats and a correctly-rounded # math.sqrt, int(math.sqrt(n)) works for any integer n satisfying 0 <= n < # 4503599761588224 = 2**52 + 2**27. But Python doesn't guarantee either # IEEE 754 format floats *or* correct rounding of math.sqrt, so check the # answer and fall back to the slow method if necessary. if n < 4503599761588224: s = int(_sqrt(n)) if 0 <= n - s*s <= 2*s: return s return integer_nthroot(n, 2)[0] def integer_nthroot(y, n): """ Return a tuple containing x = floor(y**(1/n)) and a boolean indicating whether the result is exact (that is, whether x**n == y). Examples ======== >>> from sympy import integer_nthroot >>> integer_nthroot(16, 2) (4, True) >>> integer_nthroot(26, 2) (5, False) To simply determine if a number is a perfect square, the is_square function should be used: >>> from sympy.ntheory.primetest import is_square >>> is_square(26) False See Also ======== sympy.ntheory.primetest.is_square integer_log """ y, n = as_int(y), as_int(n) if y < 0: raise ValueError("y must be nonnegative") if n < 1: raise ValueError("n must be positive") if HAS_GMPY and n < 2**63: # Currently it works only for n < 2**63, else it produces TypeError # sympy issue: https://github.com/sympy/sympy/issues/18374 # gmpy2 issue: https://github.com/aleaxit/gmpy/issues/257 if HAS_GMPY >= 2: x, t = gmpy.iroot(y, n) else: x, t = gmpy.root(y, n) return as_int(x), bool(t) return _integer_nthroot_python(y, n) def _integer_nthroot_python(y, n): if y in (0, 1): return y, True if n == 1: return y, True if n == 2: x, rem = mpmath_sqrtrem(y) return int(x), not rem if n > y: return 1, False # Get initial estimate for Newton's method. Care must be taken to # avoid overflow try: guess = int(y**(1./n) + 0.5) except OverflowError: exp = _log(y, 2)/n if exp > 53: shift = int(exp - 53) guess = int(2.0**(exp - shift) + 1) << shift else: guess = int(2.0**exp) if guess > 2**50: # Newton iteration xprev, x = -1, guess while 1: t = x**(n - 1) xprev, x = x, ((n - 1)*x + y//t)//n if abs(x - xprev) < 2: break else: x = guess # Compensate t = x**n while t < y: x += 1 t = x**n while t > y: x -= 1 t = x**n return int(x), t == y # int converts long to int if possible def integer_log(y, x): r""" Returns ``(e, bool)`` where e is the largest nonnegative integer such that :math:`|y| \geq |x^e|` and ``bool`` is True if $y = x^e$. Examples ======== >>> from sympy import integer_log >>> integer_log(125, 5) (3, True) >>> integer_log(17, 9) (1, False) >>> integer_log(4, -2) (2, True) >>> integer_log(-125,-5) (3, True) See Also ======== integer_nthroot sympy.ntheory.primetest.is_square sympy.ntheory.factor_.multiplicity sympy.ntheory.factor_.perfect_power """ if x == 1: raise ValueError('x cannot take value as 1') if y == 0: raise ValueError('y cannot take value as 0') if x in (-2, 2): x = int(x) y = as_int(y) e = y.bit_length() - 1 return e, x**e == y if x < 0: n, b = integer_log(y if y > 0 else -y, -x) return n, b and bool(n % 2 if y < 0 else not n % 2) x = as_int(x) y = as_int(y) r = e = 0 while y >= x: d = x m = 1 while y >= d: y, rem = divmod(y, d) r = r or rem e += m if y > d: d *= d m *= 2 return e, r == 0 and y == 1 class Pow(Expr): """ Defines the expression x**y as "x raised to a power y" Singleton definitions involving (0, 1, -1, oo, -oo, I, -I): +--------------+---------+-----------------------------------------------+ | expr | value | reason | +==============+=========+===============================================+ | z**0 | 1 | Although arguments over 0**0 exist, see [2]. | +--------------+---------+-----------------------------------------------+ | z**1 | z | | +--------------+---------+-----------------------------------------------+ | (-oo)**(-1) | 0 | | +--------------+---------+-----------------------------------------------+ | (-1)**-1 | -1 | | +--------------+---------+-----------------------------------------------+ | S.Zero**-1 | zoo | This is not strictly true, as 0**-1 may be | | | | undefined, but is convenient in some contexts | | | | where the base is assumed to be positive. | +--------------+---------+-----------------------------------------------+ | 1**-1 | 1 | | +--------------+---------+-----------------------------------------------+ | oo**-1 | 0 | | +--------------+---------+-----------------------------------------------+ | 0**oo | 0 | Because for all complex numbers z near | | | | 0, z**oo -> 0. | +--------------+---------+-----------------------------------------------+ | 0**-oo | zoo | This is not strictly true, as 0**oo may be | | | | oscillating between positive and negative | | | | values or rotating in the complex plane. | | | | It is convenient, however, when the base | | | | is positive. | +--------------+---------+-----------------------------------------------+ | 1**oo | nan | Because there are various cases where | | 1**-oo | | lim(x(t),t)=1, lim(y(t),t)=oo (or -oo), | | | | but lim( x(t)**y(t), t) != 1. See [3]. | +--------------+---------+-----------------------------------------------+ | b**zoo | nan | Because b**z has no limit as z -> zoo | +--------------+---------+-----------------------------------------------+ | (-1)**oo | nan | Because of oscillations in the limit. | | (-1)**(-oo) | | | +--------------+---------+-----------------------------------------------+ | oo**oo | oo | | +--------------+---------+-----------------------------------------------+ | oo**-oo | 0 | | +--------------+---------+-----------------------------------------------+ | (-oo)**oo | nan | | | (-oo)**-oo | | | +--------------+---------+-----------------------------------------------+ | oo**I | nan | oo**e could probably be best thought of as | | (-oo)**I | | the limit of x**e for real x as x tends to | | | | oo. If e is I, then the limit does not exist | | | | and nan is used to indicate that. | +--------------+---------+-----------------------------------------------+ | oo**(1+I) | zoo | If the real part of e is positive, then the | | (-oo)**(1+I) | | limit of abs(x**e) is oo. So the limit value | | | | is zoo. | +--------------+---------+-----------------------------------------------+ | oo**(-1+I) | 0 | If the real part of e is negative, then the | | -oo**(-1+I) | | limit is 0. | +--------------+---------+-----------------------------------------------+ Because symbolic computations are more flexible that floating point calculations and we prefer to never return an incorrect answer, we choose not to conform to all IEEE 754 conventions. This helps us avoid extra test-case code in the calculation of limits. See Also ======== sympy.core.numbers.Infinity sympy.core.numbers.NegativeInfinity sympy.core.numbers.NaN References ========== .. [1] https://en.wikipedia.org/wiki/Exponentiation .. [2] https://en.wikipedia.org/wiki/Exponentiation#Zero_to_the_power_of_zero .. [3] https://en.wikipedia.org/wiki/Indeterminate_forms """ is_Pow = True __slots__ = ('is_commutative',) @cacheit def __new__(cls, b, e, evaluate=None): if evaluate is None: evaluate = global_parameters.evaluate from sympy.functions.elementary.exponential import exp_polar b = _sympify(b) e = _sympify(e) # XXX: This can be removed when non-Expr args are disallowed rather # than deprecated. from sympy.core.relational import Relational if isinstance(b, Relational) or isinstance(e, Relational): raise TypeError('Relational can not be used in Pow') # XXX: This should raise TypeError once deprecation period is over: if not (isinstance(b, Expr) and isinstance(e, Expr)): SymPyDeprecationWarning( feature="Pow with non-Expr args", useinstead="Expr args", issue=19445, deprecated_since_version="1.7" ).warn() if evaluate: if b is S.Zero and e is S.NegativeInfinity: return S.ComplexInfinity if e is S.ComplexInfinity: return S.NaN if e is S.Zero: return S.One elif e is S.One: return b elif e == -1 and not b: return S.ComplexInfinity elif e.__class__.__name__ == "AccumulationBounds": if b == S.Exp1: from sympy import AccumBounds return AccumBounds(Pow(b, e.min), Pow(b, e.max)) # Only perform autosimplification if exponent or base is a Symbol or number elif (b.is_Symbol or b.is_number) and (e.is_Symbol or e.is_number) and\ e.is_integer and _coeff_isneg(b): if e.is_even: b = -b elif e.is_odd: return -Pow(-b, e) if S.NaN in (b, e): # XXX S.NaN**x -> S.NaN under assumption that x != 0 return S.NaN elif b is S.One: if abs(e).is_infinite: return S.NaN return S.One else: # recognize base as E if not e.is_Atom and b is not S.Exp1 and not isinstance(b, exp_polar): from sympy import numer, denom, log, sign, im, factor_terms c, ex = factor_terms(e, sign=False).as_coeff_Mul() den = denom(ex) if isinstance(den, log) and den.args[0] == b: return S.Exp1**(c*numer(ex)) elif den.is_Add: s = sign(im(b)) if s.is_Number and s and den == \ log(-factor_terms(b, sign=False)) + s*S.ImaginaryUnit*S.Pi: return S.Exp1**(c*numer(ex)) obj = b._eval_power(e) if obj is not None: return obj obj = Expr.__new__(cls, b, e) obj = cls._exec_constructor_postprocessors(obj) if not isinstance(obj, Pow): return obj obj.is_commutative = (b.is_commutative and e.is_commutative) return obj def inverse(self, argindex=1): if self.base == S.Exp1: from sympy import log return log return None @property def base(self): return self._args[0] @property def exp(self): return self._args[1] @property def kind(self): if self.exp.kind is NumberKind: return self.base.kind else: return UndefinedKind @classmethod def class_key(cls): return 3, 2, cls.__name__ def _eval_refine(self, assumptions): from sympy.assumptions.ask import ask, Q b, e = self.as_base_exp() if ask(Q.integer(e), assumptions) and _coeff_isneg(b): if ask(Q.even(e), assumptions): return Pow(-b, e) elif ask(Q.odd(e), assumptions): return -Pow(-b, e) def _eval_power(self, other): from sympy import arg, exp, floor, im, log, re, sign b, e = self.as_base_exp() if b is S.NaN: return (b**e)**other # let __new__ handle it s = None if other.is_integer: s = 1 elif b.is_polar: # e.g. exp_polar, besselj, var('p', polar=True)... s = 1 elif e.is_extended_real is not None: # helper functions =========================== def _half(e): """Return True if the exponent has a literal 2 as the denominator, else None.""" if getattr(e, 'q', None) == 2: return True n, d = e.as_numer_denom() if n.is_integer and d == 2: return True def _n2(e): """Return ``e`` evaluated to a Number with 2 significant digits, else None.""" try: rv = e.evalf(2, strict=True) if rv.is_Number: return rv except PrecisionExhausted: pass # =================================================== if e.is_extended_real: # we need _half(other) with constant floor or # floor(S.Half - e*arg(b)/2/pi) == 0 # handle -1 as special case if e == -1: # floor arg. is 1/2 + arg(b)/2/pi if _half(other): if b.is_negative is True: return S.NegativeOne**other*Pow(-b, e*other) elif b.is_negative is False: return Pow(b, -other) elif e.is_even: if b.is_extended_real: b = abs(b) if b.is_imaginary: b = abs(im(b))*S.ImaginaryUnit if (abs(e) < 1) == True or e == 1: s = 1 # floor = 0 elif b.is_extended_nonnegative: s = 1 # floor = 0 elif re(b).is_extended_nonnegative and (abs(e) < 2) == True: s = 1 # floor = 0 elif fuzzy_not(im(b).is_zero) and abs(e) == 2: s = 1 # floor = 0 elif _half(other): s = exp(2*S.Pi*S.ImaginaryUnit*other*floor( S.Half - e*arg(b)/(2*S.Pi))) if s.is_extended_real and _n2(sign(s) - s) == 0: s = sign(s) else: s = None else: # e.is_extended_real is False requires: # _half(other) with constant floor or # floor(S.Half - im(e*log(b))/2/pi) == 0 try: s = exp(2*S.ImaginaryUnit*S.Pi*other* floor(S.Half - im(e*log(b))/2/S.Pi)) # be careful to test that s is -1 or 1 b/c sign(I) == I: # so check that s is real if s.is_extended_real and _n2(sign(s) - s) == 0: s = sign(s) else: s = None except PrecisionExhausted: s = None if s is not None: return s*Pow(b, e*other) def _eval_Mod(self, q): r"""A dispatched function to compute `b^e \bmod q`, dispatched by ``Mod``. Notes ===== Algorithms: 1. For unevaluated integer power, use built-in ``pow`` function with 3 arguments, if powers are not too large wrt base. 2. For very large powers, use totient reduction if e >= lg(m). Bound on m, is for safe factorization memory wise ie m^(1/4). For pollard-rho to be faster than built-in pow lg(e) > m^(1/4) check is added. 3. For any unevaluated power found in `b` or `e`, the step 2 will be recursed down to the base and the exponent such that the `b \bmod q` becomes the new base and ``\phi(q) + e \bmod \phi(q)`` becomes the new exponent, and then the computation for the reduced expression can be done. """ from sympy.ntheory import totient from .mod import Mod base, exp = self.base, self.exp if exp.is_integer and exp.is_positive: if q.is_integer and base % q == 0: return S.Zero if base.is_Integer and exp.is_Integer and q.is_Integer: b, e, m = int(base), int(exp), int(q) mb = m.bit_length() if mb <= 80 and e >= mb and e.bit_length()**4 >= m: phi = totient(m) return Integer(pow(b, phi + e%phi, m)) return Integer(pow(b, e, m)) if isinstance(base, Pow) and base.is_integer and base.is_number: base = Mod(base, q) return Mod(Pow(base, exp, evaluate=False), q) if isinstance(exp, Pow) and exp.is_integer and exp.is_number: bit_length = int(q).bit_length() # XXX Mod-Pow actually attempts to do a hanging evaluation # if this dispatched function returns None. # May need some fixes in the dispatcher itself. if bit_length <= 80: phi = totient(q) exp = phi + Mod(exp, phi) return Mod(Pow(base, exp, evaluate=False), q) def _eval_is_even(self): if self.exp.is_integer and self.exp.is_positive: return self.base.is_even def _eval_is_negative(self): ext_neg = Pow._eval_is_extended_negative(self) if ext_neg is True: return self.is_finite return ext_neg def _eval_is_positive(self): ext_pos = Pow._eval_is_extended_positive(self) if ext_pos is True: return self.is_finite return ext_pos def _eval_is_extended_positive(self): from sympy import log if self.base == self.exp: if self.base.is_extended_nonnegative: return True elif self.base.is_positive: if self.exp.is_real: return True elif self.base.is_extended_negative: if self.exp.is_even: return True if self.exp.is_odd: return False elif self.base.is_zero: if self.exp.is_extended_real: return self.exp.is_zero elif self.base.is_extended_nonpositive: if self.exp.is_odd: return False elif self.base.is_imaginary: if self.exp.is_integer: m = self.exp % 4 if m.is_zero: return True if m.is_integer and m.is_zero is False: return False if self.exp.is_imaginary: return log(self.base).is_imaginary def _eval_is_extended_negative(self): if self.exp is S(1)/2: if self.base.is_complex or self.base.is_extended_real: return False if self.base.is_extended_negative: if self.exp.is_odd and self.base.is_finite: return True if self.exp.is_even: return False elif self.base.is_extended_positive: if self.exp.is_extended_real: return False elif self.base.is_zero: if self.exp.is_extended_real: return False elif self.base.is_extended_nonnegative: if self.exp.is_extended_nonnegative: return False elif self.base.is_extended_nonpositive: if self.exp.is_even: return False elif self.base.is_extended_real: if self.exp.is_even: return False def _eval_is_zero(self): if self.base.is_zero: if self.exp.is_extended_positive: return True elif self.exp.is_extended_nonpositive: return False elif self.base == S.Exp1: return self.exp is S.NegativeInfinity elif self.base.is_zero is False: if self.base.is_finite and self.exp.is_finite: return False elif self.exp.is_negative: return self.base.is_infinite elif self.exp.is_nonnegative: return False elif self.exp.is_infinite and self.exp.is_extended_real: if (1 - abs(self.base)).is_extended_positive: return self.exp.is_extended_positive elif (1 - abs(self.base)).is_extended_negative: return self.exp.is_extended_negative elif self.base.is_finite and self.exp.is_negative: # when self.base.is_zero is None return False def _eval_is_integer(self): b, e = self.args if b.is_rational: if b.is_integer is False and e.is_positive: return False # rat**nonneg if b.is_integer and e.is_integer: if b is S.NegativeOne: return True if e.is_nonnegative or e.is_positive: return True if b.is_integer and e.is_negative and (e.is_finite or e.is_integer): if fuzzy_not((b - 1).is_zero) and fuzzy_not((b + 1).is_zero): return False if b.is_Number and e.is_Number: check = self.func(*self.args) return check.is_Integer if e.is_negative and b.is_positive and (b - 1).is_positive: return False if e.is_negative and b.is_negative and (b + 1).is_negative: return False def _eval_is_extended_real(self): from ..functions import arg, log, exp from .mul import Mul if self.base is S.Exp1: if self.exp.is_extended_real: return True elif self.exp.is_imaginary: return (2*S.ImaginaryUnit*self.exp/S.Pi).is_even real_b = self.base.is_extended_real if real_b is None: if self.base.func == exp and self.base.exp.is_imaginary: return self.exp.is_imaginary if self.base.func == Pow and self.base.base is S.Exp1 and self.base.exp.is_imaginary: return self.exp.is_imaginary return real_e = self.exp.is_extended_real if real_e is None: return if real_b and real_e: if self.base.is_extended_positive: return True elif self.base.is_extended_nonnegative and self.exp.is_extended_nonnegative: return True elif self.exp.is_integer and self.base.is_extended_nonzero: return True elif self.exp.is_integer and self.exp.is_nonnegative: return True elif self.base.is_extended_negative: if self.exp.is_Rational: return False if real_e and self.exp.is_extended_negative and self.base.is_zero is False: return Pow(self.base, -self.exp).is_extended_real im_b = self.base.is_imaginary im_e = self.exp.is_imaginary if im_b: if self.exp.is_integer: if self.exp.is_even: return True elif self.exp.is_odd: return False elif im_e and log(self.base).is_imaginary: return True elif self.exp.is_Add: c, a = self.exp.as_coeff_Add() if c and c.is_Integer: return Mul( self.base**c, self.base**a, evaluate=False).is_extended_real elif self.base in (-S.ImaginaryUnit, S.ImaginaryUnit): if (self.exp/2).is_integer is False: return False if real_b and im_e: if self.base is S.NegativeOne: return True c = self.exp.coeff(S.ImaginaryUnit) if c: if self.base.is_rational and c.is_rational: if self.base.is_nonzero and (self.base - 1).is_nonzero and c.is_nonzero: return False ok = (c*log(self.base)/S.Pi).is_integer if ok is not None: return ok if real_b is False: # we already know it's not imag i = arg(self.base)*self.exp/S.Pi if i.is_complex: # finite return i.is_integer def _eval_is_complex(self): if self.base == S.Exp1: return fuzzy_or([self.exp.is_complex, self.exp.is_extended_negative]) if all(a.is_complex for a in self.args) and self._eval_is_finite(): return True def _eval_is_imaginary(self): from sympy import arg, log if self.base.is_imaginary: if self.exp.is_integer: odd = self.exp.is_odd if odd is not None: return odd return if self.base == S.Exp1: f = 2 * self.exp / (S.Pi*S.ImaginaryUnit) # exp(pi*integer) = 1 or -1, so not imaginary if f.is_even: return False # exp(pi*integer + pi/2) = I or -I, so it is imaginary if f.is_odd: return True return None if self.exp.is_imaginary: imlog = log(self.base).is_imaginary if imlog is not None: return False # I**i -> real; (2*I)**i -> complex ==> not imaginary if self.base.is_extended_real and self.exp.is_extended_real: if self.base.is_positive: return False else: rat = self.exp.is_rational if not rat: return rat if self.exp.is_integer: return False else: half = (2*self.exp).is_integer if half: return self.base.is_negative return half if self.base.is_extended_real is False: # we already know it's not imag i = arg(self.base)*self.exp/S.Pi isodd = (2*i).is_odd if isodd is not None: return isodd def _eval_is_odd(self): if self.exp.is_integer: if self.exp.is_positive: return self.base.is_odd elif self.exp.is_nonnegative and self.base.is_odd: return True elif self.base is S.NegativeOne: return True def _eval_is_finite(self): if self.exp.is_negative: if self.base.is_zero: return False if self.base.is_infinite or self.base.is_nonzero: return True c1 = self.base.is_finite if c1 is None: return c2 = self.exp.is_finite if c2 is None: return if c1 and c2: if self.exp.is_nonnegative or fuzzy_not(self.base.is_zero): return True def _eval_is_prime(self): ''' An integer raised to the n(>=2)-th power cannot be a prime. ''' if self.base.is_integer and self.exp.is_integer and (self.exp - 1).is_positive: return False def _eval_is_composite(self): """ A power is composite if both base and exponent are greater than 1 """ if (self.base.is_integer and self.exp.is_integer and ((self.base - 1).is_positive and (self.exp - 1).is_positive or (self.base + 1).is_negative and self.exp.is_positive and self.exp.is_even)): return True def _eval_is_polar(self): return self.base.is_polar def _eval_subs(self, old, new): from sympy import exp, log, Symbol, AccumBounds if isinstance(self.exp, AccumBounds): b = self.base.subs(old, new) e = self.exp.subs(old, new) if isinstance(e, AccumBounds): return e.__rpow__(b) return self.func(b, e) def _check(ct1, ct2, old): """Return (bool, pow, remainder_pow) where, if bool is True, then the exponent of Pow `old` will combine with `pow` so the substitution is valid, otherwise bool will be False. For noncommutative objects, `pow` will be an integer, and a factor `Pow(old.base, remainder_pow)` needs to be included. If there is no such factor, None is returned. For commutative objects, remainder_pow is always None. cti are the coefficient and terms of an exponent of self or old In this _eval_subs routine a change like (b**(2*x)).subs(b**x, y) will give y**2 since (b**x)**2 == b**(2*x); if that equality does not hold then the substitution should not occur so `bool` will be False. """ coeff1, terms1 = ct1 coeff2, terms2 = ct2 if terms1 == terms2: if old.is_commutative: # Allow fractional powers for commutative objects pow = coeff1/coeff2 try: as_int(pow, strict=False) combines = True except ValueError: combines = isinstance(Pow._eval_power( Pow(*old.as_base_exp(), evaluate=False), pow), (Pow, exp, Symbol)) return combines, pow, None else: # With noncommutative symbols, substitute only integer powers if not isinstance(terms1, tuple): terms1 = (terms1,) if not all(term.is_integer for term in terms1): return False, None, None try: # Round pow toward zero pow, remainder = divmod(as_int(coeff1), as_int(coeff2)) if pow < 0 and remainder != 0: pow += 1 remainder -= as_int(coeff2) if remainder == 0: remainder_pow = None else: remainder_pow = Mul(remainder, *terms1) return True, pow, remainder_pow except ValueError: # Can't substitute pass return False, None, None if old == self.base or (old == exp and self.base == S.Exp1): if new.is_Function and isinstance(new, Callable): return new(self.exp._subs(old, new)) else: return new**self.exp._subs(old, new) # issue 10829: (4**x - 3*y + 2).subs(2**x, y) -> y**2 - 3*y + 2 if isinstance(old, self.func) and self.exp == old.exp: l = log(self.base, old.base) if l.is_Number: return Pow(new, l) if isinstance(old, self.func) and self.base == old.base: if self.exp.is_Add is False: ct1 = self.exp.as_independent(Symbol, as_Add=False) ct2 = old.exp.as_independent(Symbol, as_Add=False) ok, pow, remainder_pow = _check(ct1, ct2, old) if ok: # issue 5180: (x**(6*y)).subs(x**(3*y),z)->z**2 result = self.func(new, pow) if remainder_pow is not None: result = Mul(result, Pow(old.base, remainder_pow)) return result else: # b**(6*x + a).subs(b**(3*x), y) -> y**2 * b**a # exp(exp(x) + exp(x**2)).subs(exp(exp(x)), w) -> w * exp(exp(x**2)) oarg = old.exp new_l = [] o_al = [] ct2 = oarg.as_coeff_mul() for a in self.exp.args: newa = a._subs(old, new) ct1 = newa.as_coeff_mul() ok, pow, remainder_pow = _check(ct1, ct2, old) if ok: new_l.append(new**pow) if remainder_pow is not None: o_al.append(remainder_pow) continue elif not old.is_commutative and not newa.is_integer: # If any term in the exponent is non-integer, # we do not do any substitutions in the noncommutative case return o_al.append(newa) if new_l: expo = Add(*o_al) new_l.append(Pow(self.base, expo, evaluate=False) if expo != 1 else self.base) return Mul(*new_l) if (isinstance(old, exp) or (old.is_Pow and old.base is S.Exp1)) and self.exp.is_extended_real and self.base.is_positive: ct1 = old.exp.as_independent(Symbol, as_Add=False) ct2 = (self.exp*log(self.base)).as_independent( Symbol, as_Add=False) ok, pow, remainder_pow = _check(ct1, ct2, old) if ok: result = self.func(new, pow) # (2**x).subs(exp(x*log(2)), z) -> z if remainder_pow is not None: result = Mul(result, Pow(old.base, remainder_pow)) return result def as_base_exp(self): """Return base and exp of self. Explnation ========== If base is 1/Integer, then return Integer, -exp. If this extra processing is not needed, the base and exp properties will give the raw arguments Examples ======== >>> from sympy import Pow, S >>> p = Pow(S.Half, 2, evaluate=False) >>> p.as_base_exp() (2, -2) >>> p.args (1/2, 2) """ b, e = self.args if b.is_Rational and b.p == 1 and b.q != 1: return Integer(b.q), -e return b, e def _eval_adjoint(self): from sympy.functions.elementary.complexes import adjoint i, p = self.exp.is_integer, self.base.is_positive if i: return adjoint(self.base)**self.exp if p: return self.base**adjoint(self.exp) if i is False and p is False: expanded = expand_complex(self) if expanded != self: return adjoint(expanded) def _eval_conjugate(self): from sympy.functions.elementary.complexes import conjugate as c i, p = self.exp.is_integer, self.base.is_positive if i: return c(self.base)**self.exp if p: return self.base**c(self.exp) if i is False and p is False: expanded = expand_complex(self) if expanded != self: return c(expanded) if self.is_extended_real: return self def _eval_transpose(self): from sympy.functions.elementary.complexes import transpose if self.base == S.Exp1: return self.func(S.Exp1, self.exp.transpose()) i, p = self.exp.is_integer, (self.base.is_complex or self.base.is_infinite) if p: return self.base**self.exp if i: return transpose(self.base)**self.exp if i is False and p is False: expanded = expand_complex(self) if expanded != self: return transpose(expanded) def _eval_expand_power_exp(self, **hints): """a**(n + m) -> a**n*a**m""" b = self.base e = self.exp if b == S.Exp1: from sympy import Sum, Product if isinstance(e, Sum) and e.is_commutative: return Product(self.func(b, e.function), *e.limits) if e.is_Add and e.is_commutative: expr = [] for x in e.args: expr.append(self.func(b, x)) return Mul(*expr) return self.func(b, e) def _eval_expand_power_base(self, **hints): """(a*b)**n -> a**n * b**n""" force = hints.get('force', False) b = self.base e = self.exp if not b.is_Mul: return self cargs, nc = b.args_cnc(split_1=False) # expand each term - this is top-level-only # expansion but we have to watch out for things # that don't have an _eval_expand method if nc: nc = [i._eval_expand_power_base(**hints) if hasattr(i, '_eval_expand_power_base') else i for i in nc] if e.is_Integer: if e.is_positive: rv = Mul(*nc*e) else: rv = Mul(*[i**-1 for i in nc[::-1]]*-e) if cargs: rv *= Mul(*cargs)**e return rv if not cargs: return self.func(Mul(*nc), e, evaluate=False) nc = [Mul(*nc)] # sift the commutative bases other, maybe_real = sift(cargs, lambda x: x.is_extended_real is False, binary=True) def pred(x): if x is S.ImaginaryUnit: return S.ImaginaryUnit polar = x.is_polar if polar: return True if polar is None: return fuzzy_bool(x.is_extended_nonnegative) sifted = sift(maybe_real, pred) nonneg = sifted[True] other += sifted[None] neg = sifted[False] imag = sifted[S.ImaginaryUnit] if imag: I = S.ImaginaryUnit i = len(imag) % 4 if i == 0: pass elif i == 1: other.append(I) elif i == 2: if neg: nonn = -neg.pop() if nonn is not S.One: nonneg.append(nonn) else: neg.append(S.NegativeOne) else: if neg: nonn = -neg.pop() if nonn is not S.One: nonneg.append(nonn) else: neg.append(S.NegativeOne) other.append(I) del imag # bring out the bases that can be separated from the base if force or e.is_integer: # treat all commutatives the same and put nc in other cargs = nonneg + neg + other other = nc else: # this is just like what is happening automatically, except # that now we are doing it for an arbitrary exponent for which # no automatic expansion is done assert not e.is_Integer # handle negatives by making them all positive and putting # the residual -1 in other if len(neg) > 1: o = S.One if not other and neg[0].is_Number: o *= neg.pop(0) if len(neg) % 2: o = -o for n in neg: nonneg.append(-n) if o is not S.One: other.append(o) elif neg and other: if neg[0].is_Number and neg[0] is not S.NegativeOne: other.append(S.NegativeOne) nonneg.append(-neg[0]) else: other.extend(neg) else: other.extend(neg) del neg cargs = nonneg other += nc rv = S.One if cargs: if e.is_Rational: npow, cargs = sift(cargs, lambda x: x.is_Pow and x.exp.is_Rational and x.base.is_number, binary=True) rv = Mul(*[self.func(b.func(*b.args), e) for b in npow]) rv *= Mul(*[self.func(b, e, evaluate=False) for b in cargs]) if other: rv *= self.func(Mul(*other), e, evaluate=False) return rv def _eval_expand_multinomial(self, **hints): """(a + b + ..)**n -> a**n + n*a**(n-1)*b + .., n is nonzero integer""" base, exp = self.args result = self if exp.is_Rational and exp.p > 0 and base.is_Add: if not exp.is_Integer: n = Integer(exp.p // exp.q) if not n: return result else: radical, result = self.func(base, exp - n), [] expanded_base_n = self.func(base, n) if expanded_base_n.is_Pow: expanded_base_n = \ expanded_base_n._eval_expand_multinomial() for term in Add.make_args(expanded_base_n): result.append(term*radical) return Add(*result) n = int(exp) if base.is_commutative: order_terms, other_terms = [], [] for b in base.args: if b.is_Order: order_terms.append(b) else: other_terms.append(b) if order_terms: # (f(x) + O(x^n))^m -> f(x)^m + m*f(x)^{m-1} *O(x^n) f = Add(*other_terms) o = Add(*order_terms) if n == 2: return expand_multinomial(f**n, deep=False) + n*f*o else: g = expand_multinomial(f**(n - 1), deep=False) return expand_mul(f*g, deep=False) + n*g*o if base.is_number: # Efficiently expand expressions of the form (a + b*I)**n # where 'a' and 'b' are real numbers and 'n' is integer. a, b = base.as_real_imag() if a.is_Rational and b.is_Rational: if not a.is_Integer: if not b.is_Integer: k = self.func(a.q * b.q, n) a, b = a.p*b.q, a.q*b.p else: k = self.func(a.q, n) a, b = a.p, a.q*b elif not b.is_Integer: k = self.func(b.q, n) a, b = a*b.q, b.p else: k = 1 a, b, c, d = int(a), int(b), 1, 0 while n: if n & 1: c, d = a*c - b*d, b*c + a*d n -= 1 a, b = a*a - b*b, 2*a*b n //= 2 I = S.ImaginaryUnit if k == 1: return c + I*d else: return Integer(c)/k + I*d/k p = other_terms # (x + y)**3 -> x**3 + 3*x**2*y + 3*x*y**2 + y**3 # in this particular example: # p = [x,y]; n = 3 # so now it's easy to get the correct result -- we get the # coefficients first: from sympy import multinomial_coefficients from sympy.polys.polyutils import basic_from_dict expansion_dict = multinomial_coefficients(len(p), n) # in our example: {(3, 0): 1, (1, 2): 3, (0, 3): 1, (2, 1): 3} # and now construct the expression. return basic_from_dict(expansion_dict, *p) else: if n == 2: return Add(*[f*g for f in base.args for g in base.args]) else: multi = (base**(n - 1))._eval_expand_multinomial() if multi.is_Add: return Add(*[f*g for f in base.args for g in multi.args]) else: # XXX can this ever happen if base was an Add? return Add(*[f*multi for f in base.args]) elif (exp.is_Rational and exp.p < 0 and base.is_Add and abs(exp.p) > exp.q): return 1 / self.func(base, -exp)._eval_expand_multinomial() elif exp.is_Add and base.is_Number: # a + b a b # n --> n n , where n, a, b are Numbers coeff, tail = S.One, S.Zero for term in exp.args: if term.is_Number: coeff *= self.func(base, term) else: tail += term return coeff * self.func(base, tail) else: return result def as_real_imag(self, deep=True, **hints): from sympy import atan2, cos, im, re, sin from sympy.polys.polytools import poly if self.exp.is_Integer: exp = self.exp re_e, im_e = self.base.as_real_imag(deep=deep) if not im_e: return self, S.Zero a, b = symbols('a b', cls=Dummy) if exp >= 0: if re_e.is_Number and im_e.is_Number: # We can be more efficient in this case expr = expand_multinomial(self.base**exp) if expr != self: return expr.as_real_imag() expr = poly( (a + b)**exp) # a = re, b = im; expr = (a + b*I)**exp else: mag = re_e**2 + im_e**2 re_e, im_e = re_e/mag, -im_e/mag if re_e.is_Number and im_e.is_Number: # We can be more efficient in this case expr = expand_multinomial((re_e + im_e*S.ImaginaryUnit)**-exp) if expr != self: return expr.as_real_imag() expr = poly((a + b)**-exp) # Terms with even b powers will be real r = [i for i in expr.terms() if not i[0][1] % 2] re_part = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) # Terms with odd b powers will be imaginary r = [i for i in expr.terms() if i[0][1] % 4 == 1] im_part1 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) r = [i for i in expr.terms() if i[0][1] % 4 == 3] im_part3 = Add(*[cc*a**aa*b**bb for (aa, bb), cc in r]) return (re_part.subs({a: re_e, b: S.ImaginaryUnit*im_e}), im_part1.subs({a: re_e, b: im_e}) + im_part3.subs({a: re_e, b: -im_e})) elif self.exp.is_Rational: re_e, im_e = self.base.as_real_imag(deep=deep) if im_e.is_zero and self.exp is S.Half: if re_e.is_extended_nonnegative: return self, S.Zero if re_e.is_extended_nonpositive: return S.Zero, (-self.base)**self.exp # XXX: This is not totally correct since for x**(p/q) with # x being imaginary there are actually q roots, but # only a single one is returned from here. r = self.func(self.func(re_e, 2) + self.func(im_e, 2), S.Half) t = atan2(im_e, re_e) rp, tp = self.func(r, self.exp), t*self.exp return rp*cos(tp), rp*sin(tp) elif self.base is S.Exp1: from ..functions import exp re_e, im_e = self.exp.as_real_imag() if deep: re_e = re_e.expand(deep, **hints) im_e = im_e.expand(deep, **hints) c, s = cos(im_e), sin(im_e) return exp(re_e)*c, exp(re_e)*s else: if deep: hints['complex'] = False expanded = self.expand(deep, **hints) if hints.get('ignore') == expanded: return None else: return (re(expanded), im(expanded)) else: return re(self), im(self) def _eval_derivative(self, s): from sympy import log dbase = self.base.diff(s) dexp = self.exp.diff(s) return self * (dexp * log(self.base) + dbase * self.exp/self.base) def _eval_evalf(self, prec): base, exp = self.as_base_exp() if base == S.Exp1: # Use mpmath function associated to class "exp": from sympy import exp as exp_function return exp_function(self.exp, evaluate=False)._eval_evalf(prec) base = base._evalf(prec) if not exp.is_Integer: exp = exp._evalf(prec) if exp.is_negative and base.is_number and base.is_extended_real is False: base = base.conjugate() / (base * base.conjugate())._evalf(prec) exp = -exp return self.func(base, exp).expand() return self.func(base, exp) def _eval_is_polynomial(self, syms): if self.exp.has(*syms): return False if self.base.has(*syms): return bool(self.base._eval_is_polynomial(syms) and self.exp.is_Integer and (self.exp >= 0)) else: return True def _eval_is_rational(self): # The evaluation of self.func below can be very expensive in the case # of integer**integer if the exponent is large. We should try to exit # before that if possible: if (self.exp.is_integer and self.base.is_rational and fuzzy_not(fuzzy_and([self.exp.is_negative, self.base.is_zero]))): return True p = self.func(*self.as_base_exp()) # in case it's unevaluated if not p.is_Pow: return p.is_rational b, e = p.as_base_exp() if e.is_Rational and b.is_Rational: # we didn't check that e is not an Integer # because Rational**Integer autosimplifies return False if e.is_integer: if b.is_rational: if fuzzy_not(b.is_zero) or e.is_nonnegative: return True if b == e: # always rational, even for 0**0 return True elif b.is_irrational: return e.is_zero if b is S.Exp1: if e.is_rational and e.is_nonzero: return False def _eval_is_algebraic(self): def _is_one(expr): try: return (expr - 1).is_zero except ValueError: # when the operation is not allowed return False if self.base.is_zero or _is_one(self.base): return True elif self.base is S.Exp1: s = self.func(*self.args) if s.func == self.func: if self.exp.is_nonzero: if self.exp.is_algebraic: return False elif (self.exp/S.Pi).is_rational: return False elif (self.exp/(S.ImaginaryUnit*S.Pi)).is_rational: return True else: return s.is_algebraic elif self.exp.is_rational: if self.base.is_algebraic is False: return self.exp.is_zero if self.base.is_zero is False: if self.exp.is_nonzero: return self.base.is_algebraic elif self.base.is_algebraic: return True if self.exp.is_positive: return self.base.is_algebraic elif self.base.is_algebraic and self.exp.is_algebraic: if ((fuzzy_not(self.base.is_zero) and fuzzy_not(_is_one(self.base))) or self.base.is_integer is False or self.base.is_irrational): return self.exp.is_rational def _eval_is_rational_function(self, syms): if self.exp.has(*syms): return False if self.base.has(*syms): return self.base._eval_is_rational_function(syms) and \ self.exp.is_Integer else: return True def _eval_is_meromorphic(self, x, a): # f**g is meromorphic if g is an integer and f is meromorphic. # E**(log(f)*g) is meromorphic if log(f)*g is meromorphic # and finite. base_merom = self.base._eval_is_meromorphic(x, a) exp_integer = self.exp.is_Integer if exp_integer: return base_merom exp_merom = self.exp._eval_is_meromorphic(x, a) if base_merom is False: # f**g = E**(log(f)*g) may be meromorphic if the # singularities of log(f) and g cancel each other, # for example, if g = 1/log(f). Hence, return False if exp_merom else None elif base_merom is None: return None b = self.base.subs(x, a) # b is extended complex as base is meromorphic. # log(base) is finite and meromorphic when b != 0, zoo. b_zero = b.is_zero if b_zero: log_defined = False else: log_defined = fuzzy_and((b.is_finite, fuzzy_not(b_zero))) if log_defined is False: # zero or pole of base return exp_integer # False or None elif log_defined is None: return None if not exp_merom: return exp_merom # False or None return self.exp.subs(x, a).is_finite def _eval_is_algebraic_expr(self, syms): if self.exp.has(*syms): return False if self.base.has(*syms): return self.base._eval_is_algebraic_expr(syms) and \ self.exp.is_Rational else: return True def _eval_rewrite_as_exp(self, base, expo, **kwargs): from sympy import exp, log, I, arg if base.is_zero or base.has(exp) or expo.has(exp): return base**expo if base.has(Symbol): # delay evaluation if expo is non symbolic # (as exp(x*log(5)) automatically reduces to x**5) if global_parameters.exp_is_pow: return Pow(S.Exp1, log(base)*expo, evaluate=expo.has(Symbol)) else: return exp(log(base)*expo, evaluate=expo.has(Symbol)) else: return exp((log(abs(base)) + I*arg(base))*expo) def as_numer_denom(self): if not self.is_commutative: return self, S.One base, exp = self.as_base_exp() n, d = base.as_numer_denom() # this should be the same as ExpBase.as_numer_denom wrt # exponent handling neg_exp = exp.is_negative if not neg_exp and not (-exp).is_negative: neg_exp = _coeff_isneg(exp) int_exp = exp.is_integer # the denominator cannot be separated from the numerator if # its sign is unknown unless the exponent is an integer, e.g. # sqrt(a/b) != sqrt(a)/sqrt(b) when a=1 and b=-1. But if the # denominator is negative the numerator and denominator can # be negated and the denominator (now positive) separated. if not (d.is_extended_real or int_exp): n = base d = S.One dnonpos = d.is_nonpositive if dnonpos: n, d = -n, -d elif dnonpos is None and not int_exp: n = base d = S.One if neg_exp: n, d = d, n exp = -exp if exp.is_infinite: if n is S.One and d is not S.One: return n, self.func(d, exp) if n is not S.One and d is S.One: return self.func(n, exp), d return self.func(n, exp), self.func(d, exp) def matches(self, expr, repl_dict={}, old=False): expr = _sympify(expr) repl_dict = repl_dict.copy() # special case, pattern = 1 and expr.exp can match to 0 if expr is S.One: d = self.exp.matches(S.Zero, repl_dict) if d is not None: return d # make sure the expression to be matched is an Expr if not isinstance(expr, Expr): return None b, e = expr.as_base_exp() # special case number sb, se = self.as_base_exp() if sb.is_Symbol and se.is_Integer and expr: if e.is_rational: return sb.matches(b**(e/se), repl_dict) return sb.matches(expr**(1/se), repl_dict) d = repl_dict.copy() d = self.base.matches(b, d) if d is None: return None d = self.exp.xreplace(d).matches(e, d) if d is None: return Expr.matches(self, expr, repl_dict) return d def _eval_nseries(self, x, n, logx, cdir=0): # NOTE! This function is an important part of the gruntz algorithm # for computing limits. It has to return a generalized power # series with coefficients in C(log, log(x)). In more detail: # It has to return an expression # c_0*x**e_0 + c_1*x**e_1 + ... (finitely many terms) # where e_i are numbers (not necessarily integers) and c_i are # expressions involving only numbers, the log function, and log(x). # The series expansion of b**e is computed as follows: # 1) We express b as f*(1 + g) where f is the leading term of b. # g has order O(x**d) where d is strictly positive. # 2) Then b**e = (f**e)*((1 + g)**e). # (1 + g)**e is computed using binomial series. from sympy import im, I, ceiling, polygamma, logcombine, EulerGamma, nan, zoo, factorial, ff, PoleError, O, powdenest, Wild from itertools import product from ..functions import exp, log from ..series import Order, limit from ..simplify import powsimp if self.base is S.Exp1: e_series = self.exp.nseries(x, n=n, logx=logx) if e_series.is_Order: return 1 + e_series e0 = limit(e_series.removeO(), x, 0) if e0 is S.NegativeInfinity: return Order(x**n, x) if e0 is S.Infinity: return self t = e_series - e0 exp_series = term = exp(e0) # series of exp(e0 + t) in t for i in range(1, n): term *= t/i term = term.nseries(x, n=n, logx=logx) exp_series += term exp_series += Order(t**n, x) return powsimp(exp_series, deep=True, combine='exp') self = powdenest(self, force=True).trigsimp() b, e = self.as_base_exp() if e.has(S.Infinity, S.NegativeInfinity, S.ComplexInfinity, S.NaN): raise PoleError() if e.has(x): return exp(e*log(b))._eval_nseries(x, n=n, logx=logx, cdir=cdir) if logx is not None and b.has(log): c, ex = symbols('c, ex', cls=Wild, exclude=[x]) b = b.replace(log(c*x**ex), log(c) + ex*logx) self = b**e b = b.removeO() try: if b.has(polygamma, EulerGamma) and logx is not None: raise ValueError() _, m = b.leadterm(x) except (ValueError, NotImplementedError, PoleError): b = b._eval_nseries(x, n=max(2, n), logx=logx, cdir=cdir).removeO() if b.has(nan, zoo): raise NotImplementedError() _, m = b.leadterm(x) if e.has(log): e = logcombine(e).cancel() if not (m.is_zero or e.is_number and e.is_real): return exp(e*log(b))._eval_nseries(x, n=n, logx=logx, cdir=cdir) f = b.as_leading_term(x, logx=logx) g = (b/f - S.One).cancel(expand=False) if not m.is_number: raise NotImplementedError() maxpow = n - m*e if maxpow.is_negative: return O(x**(m*e), x) if g.is_zero: r = f**e if r != self: r += Order(x**n, x) return r def coeff_exp(term, x): coeff, exp = S.One, S.Zero for factor in Mul.make_args(term): if factor.has(x): base, exp = factor.as_base_exp() if base != x: try: return term.leadterm(x) except ValueError: return term, S.Zero else: coeff *= factor return coeff, exp def mul(d1, d2): res = {} for e1, e2 in product(d1, d2): ex = e1 + e2 if ex < maxpow: res[ex] = res.get(ex, S.Zero) + d1[e1]*d2[e2] return res try: _, d = g.leadterm(x) except (ValueError, NotImplementedError): if limit(g/x**maxpow, x, 0) == 0: # g has higher order zero return f**e + e*f**e*g # first term of binomial series else: raise NotImplementedError() if not d.is_positive: g = g.simplify() _, d = g.leadterm(x) if not d.is_positive: raise NotImplementedError() gpoly = g._eval_nseries(x, n=ceiling(maxpow), logx=logx, cdir=cdir).removeO() gterms = {} for term in Add.make_args(gpoly): co1, e1 = coeff_exp(term, x) gterms[e1] = gterms.get(e1, S.Zero) + co1 k = S.One terms = {S.Zero: S.One} tk = gterms while (k*d - maxpow).is_negative: coeff = ff(e, k)/factorial(k) for ex in tk: terms[ex] = terms.get(ex, S.Zero) + coeff*tk[ex] tk = mul(tk, gterms) k += S.One if (not e.is_integer and m.is_zero and f.is_real and f.is_negative and im((b - f).dir(x, cdir)).is_negative): inco, inex = coeff_exp(f**e*exp(-2*e*S.Pi*I), x) else: inco, inex = coeff_exp(f**e, x) res = S.Zero for e1 in terms: ex = e1 + inex res += terms[e1]*inco*x**(ex) if not (e.is_integer and e.is_positive and (e*d - n).is_nonpositive and res == _mexpand(self)): res += O(x**n, x) return res def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import exp, I, im, log, PoleError e = self.exp b = self.base if self.base is S.Exp1: arg = e.as_leading_term(x, logx=logx) arg0 = arg.subs(x, 0) if arg0 is S.NaN: arg0 = arg.limit(x, 0) if arg0.is_infinite is False: return S.Exp1**arg0 raise PoleError("Cannot expand %s around 0" % (self)) elif e.has(x): lt = exp(e * log(b)) try: lt = lt.as_leading_term(x, logx=logx, cdir=cdir) except PoleError: pass return lt else: f = b.as_leading_term(x, logx=logx, cdir=cdir) if (not e.is_integer and f.is_constant() and f.is_real and f.is_negative and im((b - f).dir(x, cdir)).is_negative): return self.func(f, e) * exp(-2 * e * S.Pi * I) return self.func(f, e) @cacheit def _taylor_term(self, n, x, *previous_terms): # of (1 + x)**e from sympy import binomial return binomial(self.exp, n) * self.func(x, n) def taylor_term(self, n, x, *previous_terms): if self.base is not S.Exp1: return super().taylor_term(n, x, *previous_terms) from sympy import sympify, factorial if n < 0: return S.Zero if n == 0: return S.One x = sympify(x) if previous_terms: p = previous_terms[-1] if p is not None: return p * x / n return x**n/factorial(n) def _eval_rewrite_as_sin(self, base, exp): from ..functions import sin if self.base is S.Exp1: return sin(S.ImaginaryUnit*self.exp + S.Pi/2) - S.ImaginaryUnit*sin(S.ImaginaryUnit*self.exp) def _eval_rewrite_as_cos(self, base, exp): from ..functions import cos if self.base is S.Exp1: return cos(S.ImaginaryUnit*self.exp) + S.ImaginaryUnit*cos(S.ImaginaryUnit*self.exp + S.Pi/2) def _eval_rewrite_as_tanh(self, base, exp): from ..functions import tanh if self.base is S.Exp1: return (1 + tanh(self.exp/2))/(1 - tanh(self.exp/2)) def _eval_rewrite_as_sqrt(self, base, exp, **kwargs): from sympy.functions.elementary.trigonometric import sin, cos if base is not S.Exp1: return None if exp.is_Mul: coeff = exp.coeff(S.Pi * S.ImaginaryUnit) if coeff and coeff.is_number: cosine, sine = cos(S.Pi*coeff), sin(S.Pi*coeff) if not isinstance(cosine, cos) and not isinstance (sine, sin): return cosine + S.ImaginaryUnit*sine def as_content_primitive(self, radical=False, clear=True): """Return the tuple (R, self/R) where R is the positive Rational extracted from self. Examples ======== >>> from sympy import sqrt >>> sqrt(4 + 4*sqrt(2)).as_content_primitive() (2, sqrt(1 + sqrt(2))) >>> sqrt(3 + 3*sqrt(2)).as_content_primitive() (1, sqrt(3)*sqrt(1 + sqrt(2))) >>> from sympy import expand_power_base, powsimp, Mul >>> from sympy.abc import x, y >>> ((2*x + 2)**2).as_content_primitive() (4, (x + 1)**2) >>> (4**((1 + y)/2)).as_content_primitive() (2, 4**(y/2)) >>> (3**((1 + y)/2)).as_content_primitive() (1, 3**((y + 1)/2)) >>> (3**((5 + y)/2)).as_content_primitive() (9, 3**((y + 1)/2)) >>> eq = 3**(2 + 2*x) >>> powsimp(eq) == eq True >>> eq.as_content_primitive() (9, 3**(2*x)) >>> powsimp(Mul(*_)) 3**(2*x + 2) >>> eq = (2 + 2*x)**y >>> s = expand_power_base(eq); s.is_Mul, s (False, (2*x + 2)**y) >>> eq.as_content_primitive() (1, (2*(x + 1))**y) >>> s = expand_power_base(_[1]); s.is_Mul, s (True, 2**y*(x + 1)**y) See docstring of Expr.as_content_primitive for more examples. """ b, e = self.as_base_exp() b = _keep_coeff(*b.as_content_primitive(radical=radical, clear=clear)) ce, pe = e.as_content_primitive(radical=radical, clear=clear) if b.is_Rational: #e #= ce*pe #= ce*(h + t) #= ce*h + ce*t #=> self #= b**(ce*h)*b**(ce*t) #= b**(cehp/cehq)*b**(ce*t) #= b**(iceh + r/cehq)*b**(ce*t) #= b**(iceh)*b**(r/cehq)*b**(ce*t) #= b**(iceh)*b**(ce*t + r/cehq) h, t = pe.as_coeff_Add() if h.is_Rational: ceh = ce*h c = self.func(b, ceh) r = S.Zero if not c.is_Rational: iceh, r = divmod(ceh.p, ceh.q) c = self.func(b, iceh) return c, self.func(b, _keep_coeff(ce, t + r/ce/ceh.q)) e = _keep_coeff(ce, pe) # b**e = (h*t)**e = h**e*t**e = c*m*t**e if e.is_Rational and b.is_Mul: h, t = b.as_content_primitive(radical=radical, clear=clear) # h is positive c, m = self.func(h, e).as_coeff_Mul() # so c is positive m, me = m.as_base_exp() if m is S.One or me == e: # probably always true # return the following, not return c, m*Pow(t, e) # which would change Pow into Mul; we let sympy # decide what to do by using the unevaluated Mul, e.g # should it stay as sqrt(2 + 2*sqrt(5)) or become # sqrt(2)*sqrt(1 + sqrt(5)) return c, self.func(_keep_coeff(m, t), e) return S.One, self.func(b, e) def is_constant(self, *wrt, **flags): expr = self if flags.get('simplify', True): expr = expr.simplify() b, e = expr.as_base_exp() bz = b.equals(0) if bz: # recalculate with assumptions in case it's unevaluated new = b**e if new != expr: return new.is_constant() econ = e.is_constant(*wrt) bcon = b.is_constant(*wrt) if bcon: if econ: return True bz = b.equals(0) if bz is False: return False elif bcon is None: return None return e.equals(0) def _eval_difference_delta(self, n, step): b, e = self.args if e.has(n) and not b.has(n): new_e = e.subs(n, n + step) return (b**(new_e - e) - 1) * self power = Dispatcher('power') power.add((object, object), Pow) from .add import Add from .numbers import Integer from .mul import Mul, _keep_coeff from .symbol import Symbol, Dummy, symbols sympy-sympy-1.9/sympy/core/relational.py000066400000000000000000001324751412543434000205540ustar00rootroot00000000000000from typing import Dict, Union, Type from sympy.utilities.exceptions import SymPyDeprecationWarning from .basic import S, Atom from .compatibility import ordered from .basic import Basic from .evalf import EvalfMixin from .function import AppliedUndef from .sympify import _sympify, SympifyError from .parameters import global_parameters from sympy.core.logic import fuzzy_bool, fuzzy_xor, fuzzy_and, fuzzy_not from sympy.logic.boolalg import Boolean, BooleanAtom __all__ = ( 'Rel', 'Eq', 'Ne', 'Lt', 'Le', 'Gt', 'Ge', 'Relational', 'Equality', 'Unequality', 'StrictLessThan', 'LessThan', 'StrictGreaterThan', 'GreaterThan', ) from .expr import Expr from sympy.multipledispatch import dispatch from .containers import Tuple from .symbol import Symbol def _nontrivBool(side): return isinstance(side, Boolean) and \ not isinstance(side, Atom) # Note, see issue 4986. Ideally, we wouldn't want to subclass both Boolean # and Expr. # from .. import Expr def _canonical(cond): # return a condition in which all relationals are canonical reps = {r: r.canonical for r in cond.atoms(Relational)} return cond.xreplace(reps) # XXX: AttributeError was being caught here but it wasn't triggered by any of # the tests so I've removed it... class Relational(Boolean, EvalfMixin): """Base class for all relation types. Explanation =========== Subclasses of Relational should generally be instantiated directly, but Relational can be instantiated with a valid ``rop`` value to dispatch to the appropriate subclass. Parameters ========== rop : str or None Indicates what subclass to instantiate. Valid values can be found in the keys of Relational.ValidRelationOperator. Examples ======== >>> from sympy import Rel >>> from sympy.abc import x, y >>> Rel(y, x + x**2, '==') Eq(y, x**2 + x) """ __slots__ = () ValidRelationOperator = {} # type: Dict[Union[str, None], Type[Relational]] is_Relational = True # ValidRelationOperator - Defined below, because the necessary classes # have not yet been defined def __new__(cls, lhs, rhs, rop=None, **assumptions): # If called by a subclass, do nothing special and pass on to Basic. if cls is not Relational: return Basic.__new__(cls, lhs, rhs, **assumptions) # XXX: Why do this? There should be a separate function to make a # particular subclass of Relational from a string. # # If called directly with an operator, look up the subclass # corresponding to that operator and delegate to it cls = cls.ValidRelationOperator.get(rop, None) if cls is None: raise ValueError("Invalid relational operator symbol: %r" % rop) if not issubclass(cls, (Eq, Ne)): # validate that Booleans are not being used in a relational # other than Eq/Ne; # Note: Symbol is a subclass of Boolean but is considered # acceptable here. if any(map(_nontrivBool, (lhs, rhs))): from sympy.utilities.misc import filldedent raise TypeError(filldedent(''' A Boolean argument can only be used in Eq and Ne; all other relationals expect real expressions. ''')) return cls(lhs, rhs, **assumptions) @property def lhs(self): """The left-hand side of the relation.""" return self._args[0] @property def rhs(self): """The right-hand side of the relation.""" return self._args[1] @property def reversed(self): """Return the relationship with sides reversed. Examples ======== >>> from sympy import Eq >>> from sympy.abc import x >>> Eq(x, 1) Eq(x, 1) >>> _.reversed Eq(1, x) >>> x < 1 x < 1 >>> _.reversed 1 > x """ ops = {Eq: Eq, Gt: Lt, Ge: Le, Lt: Gt, Le: Ge, Ne: Ne} a, b = self.args return Relational.__new__(ops.get(self.func, self.func), b, a) @property def reversedsign(self): """Return the relationship with signs reversed. Examples ======== >>> from sympy import Eq >>> from sympy.abc import x >>> Eq(x, 1) Eq(x, 1) >>> _.reversedsign Eq(-x, -1) >>> x < 1 x < 1 >>> _.reversedsign -x > -1 """ a, b = self.args if not (isinstance(a, BooleanAtom) or isinstance(b, BooleanAtom)): ops = {Eq: Eq, Gt: Lt, Ge: Le, Lt: Gt, Le: Ge, Ne: Ne} return Relational.__new__(ops.get(self.func, self.func), -a, -b) else: return self @property def negated(self): """Return the negated relationship. Examples ======== >>> from sympy import Eq >>> from sympy.abc import x >>> Eq(x, 1) Eq(x, 1) >>> _.negated Ne(x, 1) >>> x < 1 x < 1 >>> _.negated x >= 1 Notes ===== This works more or less identical to ``~``/``Not``. The difference is that ``negated`` returns the relationship even if ``evaluate=False``. Hence, this is useful in code when checking for e.g. negated relations to existing ones as it will not be affected by the `evaluate` flag. """ ops = {Eq: Ne, Ge: Lt, Gt: Le, Le: Gt, Lt: Ge, Ne: Eq} # If there ever will be new Relational subclasses, the following line # will work until it is properly sorted out # return ops.get(self.func, lambda a, b, evaluate=False: ~(self.func(a, # b, evaluate=evaluate)))(*self.args, evaluate=False) return Relational.__new__(ops.get(self.func), *self.args) def _eval_evalf(self, prec): return self.func(*[s._evalf(prec) for s in self.args]) @property def canonical(self): """Return a canonical form of the relational by putting a number on the rhs, canonically removing a sign or else ordering the args canonically. No other simplification is attempted. Examples ======== >>> from sympy.abc import x, y >>> x < 2 x < 2 >>> _.reversed.canonical x < 2 >>> (-y < x).canonical x > -y >>> (-y > x).canonical x < -y >>> (-y < -x).canonical x < y """ args = self.args r = self if r.rhs.is_number: if r.rhs.is_Number and r.lhs.is_Number and r.lhs > r.rhs: r = r.reversed elif r.lhs.is_number: r = r.reversed elif tuple(ordered(args)) != args: r = r.reversed LHS_CEMS = getattr(r.lhs, 'could_extract_minus_sign', None) RHS_CEMS = getattr(r.rhs, 'could_extract_minus_sign', None) if isinstance(r.lhs, BooleanAtom) or isinstance(r.rhs, BooleanAtom): return r # Check if first value has negative sign if LHS_CEMS and LHS_CEMS(): return r.reversedsign elif not r.rhs.is_number and RHS_CEMS and RHS_CEMS(): # Right hand side has a minus, but not lhs. # How does the expression with reversed signs behave? # This is so that expressions of the type # Eq(x, -y) and Eq(-x, y) # have the same canonical representation expr1, _ = ordered([r.lhs, -r.rhs]) if expr1 != r.lhs: return r.reversed.reversedsign return r def equals(self, other, failing_expression=False): """Return True if the sides of the relationship are mathematically identical and the type of relationship is the same. If failing_expression is True, return the expression whose truth value was unknown.""" if isinstance(other, Relational): if self == other or self.reversed == other: return True a, b = self, other if a.func in (Eq, Ne) or b.func in (Eq, Ne): if a.func != b.func: return False left, right = [i.equals(j, failing_expression=failing_expression) for i, j in zip(a.args, b.args)] if left is True: return right if right is True: return left lr, rl = [i.equals(j, failing_expression=failing_expression) for i, j in zip(a.args, b.reversed.args)] if lr is True: return rl if rl is True: return lr e = (left, right, lr, rl) if all(i is False for i in e): return False for i in e: if i not in (True, False): return i else: if b.func != a.func: b = b.reversed if a.func != b.func: return False left = a.lhs.equals(b.lhs, failing_expression=failing_expression) if left is False: return False right = a.rhs.equals(b.rhs, failing_expression=failing_expression) if right is False: return False if left is True: return right return left def _eval_simplify(self, **kwargs): from .add import Add from sympy.core.expr import Expr r = self r = r.func(*[i.simplify(**kwargs) for i in r.args]) if r.is_Relational: if not isinstance(r.lhs, Expr) or not isinstance(r.rhs, Expr): return r dif = r.lhs - r.rhs # replace dif with a valid Number that will # allow a definitive comparison with 0 v = None if dif.is_comparable: v = dif.n(2) elif dif.equals(0): # XXX this is expensive v = S.Zero if v is not None: r = r.func._eval_relation(v, S.Zero) r = r.canonical # If there is only one symbol in the expression, # try to write it on a simplified form free = list(filter(lambda x: x.is_real is not False, r.free_symbols)) if len(free) == 1: try: from sympy.solvers.solveset import linear_coeffs x = free.pop() dif = r.lhs - r.rhs m, b = linear_coeffs(dif, x) if m.is_zero is False: if m.is_negative: # Dividing with a negative number, so change order of arguments # canonical will put the symbol back on the lhs later r = r.func(-b / m, x) else: r = r.func(x, -b / m) else: r = r.func(b, S.Zero) except ValueError: # maybe not a linear function, try polynomial from sympy.polys import Poly, poly, PolynomialError, gcd try: p = poly(dif, x) c = p.all_coeffs() constant = c[-1] c[-1] = 0 scale = gcd(c) c = [ctmp / scale for ctmp in c] r = r.func(Poly.from_list(c, x).as_expr(), -constant / scale) except PolynomialError: pass elif len(free) >= 2: try: from sympy.solvers.solveset import linear_coeffs from sympy.polys import gcd free = list(ordered(free)) dif = r.lhs - r.rhs m = linear_coeffs(dif, *free) constant = m[-1] del m[-1] scale = gcd(m) m = [mtmp / scale for mtmp in m] nzm = list(filter(lambda f: f[0] != 0, list(zip(m, free)))) if scale.is_zero is False: if constant != 0: # lhs: expression, rhs: constant newexpr = Add(*[i * j for i, j in nzm]) r = r.func(newexpr, -constant / scale) else: # keep first term on lhs lhsterm = nzm[0][0] * nzm[0][1] del nzm[0] newexpr = Add(*[i * j for i, j in nzm]) r = r.func(lhsterm, -newexpr) else: r = r.func(constant, S.Zero) except ValueError: pass # Did we get a simplified result? r = r.canonical measure = kwargs['measure'] if measure(r) < kwargs['ratio'] * measure(self): return r else: return self def _eval_trigsimp(self, **opts): from sympy.simplify import trigsimp return self.func(trigsimp(self.lhs, **opts), trigsimp(self.rhs, **opts)) def expand(self, **kwargs): args = (arg.expand(**kwargs) for arg in self.args) return self.func(*args) def __bool__(self): raise TypeError("cannot determine truth value of Relational") def _eval_as_set(self): # self is univariate and periodicity(self, x) in (0, None) from sympy.solvers.inequalities import solve_univariate_inequality from sympy.sets.conditionset import ConditionSet syms = self.free_symbols assert len(syms) == 1 x = syms.pop() try: xset = solve_univariate_inequality(self, x, relational=False) except NotImplementedError: # solve_univariate_inequality raises NotImplementedError for # unsolvable equations/inequalities. xset = ConditionSet(x, self, S.Reals) return xset @property def binary_symbols(self): # override where necessary return set() Rel = Relational class Equality(Relational): """An equal relation between two objects. Explanation =========== Represents that two objects are equal. If they can be easily shown to be definitively equal (or unequal), this will reduce to True (or False). Otherwise, the relation is maintained as an unevaluated Equality object. Use the ``simplify`` function on this object for more nontrivial evaluation of the equality relation. As usual, the keyword argument ``evaluate=False`` can be used to prevent any evaluation. Examples ======== >>> from sympy import Eq, simplify, exp, cos >>> from sympy.abc import x, y >>> Eq(y, x + x**2) Eq(y, x**2 + x) >>> Eq(2, 5) False >>> Eq(2, 5, evaluate=False) Eq(2, 5) >>> _.doit() False >>> Eq(exp(x), exp(x).rewrite(cos)) Eq(exp(x), sinh(x) + cosh(x)) >>> simplify(_) True See Also ======== sympy.logic.boolalg.Equivalent : for representing equality between two boolean expressions Notes ===== Python treats 1 and True (and 0 and False) as being equal; SymPy does not. And integer will always compare as unequal to a Boolean: >>> Eq(True, 1), True == 1 (False, True) This class is not the same as the == operator. The == operator tests for exact structural equality between two expressions; this class compares expressions mathematically. If either object defines an ``_eval_Eq`` method, it can be used in place of the default algorithm. If ``lhs._eval_Eq(rhs)`` or ``rhs._eval_Eq(lhs)`` returns anything other than None, that return value will be substituted for the Equality. If None is returned by ``_eval_Eq``, an Equality object will be created as usual. Since this object is already an expression, it does not respond to the method ``as_expr`` if one tries to create `x - y` from ``Eq(x, y)``. This can be done with the ``rewrite(Add)`` method. """ rel_op = '==' __slots__ = () is_Equality = True def __new__(cls, lhs, rhs=None, **options): if rhs is None: SymPyDeprecationWarning( feature="Eq(expr) with rhs default to 0", useinstead="Eq(expr, 0)", issue=16587, deprecated_since_version="1.5" ).warn() rhs = 0 evaluate = options.pop('evaluate', global_parameters.evaluate) lhs = _sympify(lhs) rhs = _sympify(rhs) if evaluate: val = is_eq(lhs, rhs) if val is None: return cls(lhs, rhs, evaluate=False) else: return _sympify(val) return Relational.__new__(cls, lhs, rhs) @classmethod def _eval_relation(cls, lhs, rhs): return _sympify(lhs == rhs) def _eval_rewrite_as_Add(self, *args, **kwargs): """ return Eq(L, R) as L - R. To control the evaluation of the result set pass `evaluate=True` to give L - R; if `evaluate=None` then terms in L and R will not cancel but they will be listed in canonical order; otherwise non-canonical args will be returned. Examples ======== >>> from sympy import Eq, Add >>> from sympy.abc import b, x >>> eq = Eq(x + b, x - b) >>> eq.rewrite(Add) 2*b >>> eq.rewrite(Add, evaluate=None).args (b, b, x, -x) >>> eq.rewrite(Add, evaluate=False).args (b, x, b, -x) """ from .add import _unevaluated_Add, Add L, R = args evaluate = kwargs.get('evaluate', True) if evaluate: # allow cancellation of args return L - R args = Add.make_args(L) + Add.make_args(-R) if evaluate is None: # no cancellation, but canonical return _unevaluated_Add(*args) # no cancellation, not canonical return Add._from_args(args) @property def binary_symbols(self): if S.true in self.args or S.false in self.args: if self.lhs.is_Symbol: return {self.lhs} elif self.rhs.is_Symbol: return {self.rhs} return set() def _eval_simplify(self, **kwargs): from .add import Add from sympy.core.expr import Expr from sympy.solvers.solveset import linear_coeffs # standard simplify e = super()._eval_simplify(**kwargs) if not isinstance(e, Equality): return e if not isinstance(e.lhs, Expr) or not isinstance(e.rhs, Expr): return e free = self.free_symbols if len(free) == 1: try: x = free.pop() m, b = linear_coeffs( e.rewrite(Add, evaluate=False), x) if m.is_zero is False: enew = e.func(x, -b / m) else: enew = e.func(m * x, -b) measure = kwargs['measure'] if measure(enew) <= kwargs['ratio'] * measure(e): e = enew except ValueError: pass return e.canonical def integrate(self, *args, **kwargs): """See the integrate function in sympy.integrals""" from sympy.integrals import integrate return integrate(self, *args, **kwargs) def as_poly(self, *gens, **kwargs): '''Returns lhs-rhs as a Poly Examples ======== >>> from sympy import Eq >>> from sympy.abc import x >>> Eq(x**2, 1).as_poly(x) Poly(x**2 - 1, x, domain='ZZ') ''' return (self.lhs - self.rhs).as_poly(*gens, **kwargs) Eq = Equality class Unequality(Relational): """An unequal relation between two objects. Explanation =========== Represents that two objects are not equal. If they can be shown to be definitively equal, this will reduce to False; if definitively unequal, this will reduce to True. Otherwise, the relation is maintained as an Unequality object. Examples ======== >>> from sympy import Ne >>> from sympy.abc import x, y >>> Ne(y, x+x**2) Ne(y, x**2 + x) See Also ======== Equality Notes ===== This class is not the same as the != operator. The != operator tests for exact structural equality between two expressions; this class compares expressions mathematically. This class is effectively the inverse of Equality. As such, it uses the same algorithms, including any available `_eval_Eq` methods. """ rel_op = '!=' __slots__ = () def __new__(cls, lhs, rhs, **options): lhs = _sympify(lhs) rhs = _sympify(rhs) evaluate = options.pop('evaluate', global_parameters.evaluate) if evaluate: val = is_neq(lhs, rhs) if val is None: return cls(lhs, rhs, evaluate=False) else: return _sympify(val) return Relational.__new__(cls, lhs, rhs, **options) @classmethod def _eval_relation(cls, lhs, rhs): return _sympify(lhs != rhs) @property def binary_symbols(self): if S.true in self.args or S.false in self.args: if self.lhs.is_Symbol: return {self.lhs} elif self.rhs.is_Symbol: return {self.rhs} return set() def _eval_simplify(self, **kwargs): # simplify as an equality eq = Equality(*self.args)._eval_simplify(**kwargs) if isinstance(eq, Equality): # send back Ne with the new args return self.func(*eq.args) return eq.negated # result of Ne is the negated Eq Ne = Unequality class _Inequality(Relational): """Internal base class for all *Than types. Each subclass must implement _eval_relation to provide the method for comparing two real numbers. """ __slots__ = () def __new__(cls, lhs, rhs, **options): try: lhs = _sympify(lhs) rhs = _sympify(rhs) except SympifyError: return NotImplemented evaluate = options.pop('evaluate', global_parameters.evaluate) if evaluate: for me in (lhs, rhs): if me.is_extended_real is False: raise TypeError("Invalid comparison of non-real %s" % me) if me is S.NaN: raise TypeError("Invalid NaN comparison") # First we invoke the appropriate inequality method of `lhs` # (e.g., `lhs.__lt__`). That method will try to reduce to # boolean or raise an exception. It may keep calling # superclasses until it reaches `Expr` (e.g., `Expr.__lt__`). # In some cases, `Expr` will just invoke us again (if neither it # nor a subclass was able to reduce to boolean or raise an # exception). In that case, it must call us with # `evaluate=False` to prevent infinite recursion. return cls._eval_relation(lhs, rhs, **options) # make a "non-evaluated" Expr for the inequality return Relational.__new__(cls, lhs, rhs, **options) @classmethod def _eval_relation(cls, lhs, rhs, **options): val = cls._eval_fuzzy_relation(lhs, rhs) if val is None: return cls(lhs, rhs, evaluate=False) else: return _sympify(val) class _Greater(_Inequality): """Not intended for general use _Greater is only used so that GreaterThan and StrictGreaterThan may subclass it for the .gts and .lts properties. """ __slots__ = () @property def gts(self): return self._args[0] @property def lts(self): return self._args[1] class _Less(_Inequality): """Not intended for general use. _Less is only used so that LessThan and StrictLessThan may subclass it for the .gts and .lts properties. """ __slots__ = () @property def gts(self): return self._args[1] @property def lts(self): return self._args[0] class GreaterThan(_Greater): """Class representations of inequalities. Explanation =========== The ``*Than`` classes represent inequal relationships, where the left-hand side is generally bigger or smaller than the right-hand side. For example, the GreaterThan class represents an inequal relationship where the left-hand side is at least as big as the right side, if not bigger. In mathematical notation: lhs >= rhs In total, there are four ``*Than`` classes, to represent the four inequalities: +-----------------+--------+ |Class Name | Symbol | +=================+========+ |GreaterThan | (>=) | +-----------------+--------+ |LessThan | (<=) | +-----------------+--------+ |StrictGreaterThan| (>) | +-----------------+--------+ |StrictLessThan | (<) | +-----------------+--------+ All classes take two arguments, lhs and rhs. +----------------------------+-----------------+ |Signature Example | Math equivalent | +============================+=================+ |GreaterThan(lhs, rhs) | lhs >= rhs | +----------------------------+-----------------+ |LessThan(lhs, rhs) | lhs <= rhs | +----------------------------+-----------------+ |StrictGreaterThan(lhs, rhs) | lhs > rhs | +----------------------------+-----------------+ |StrictLessThan(lhs, rhs) | lhs < rhs | +----------------------------+-----------------+ In addition to the normal .lhs and .rhs of Relations, ``*Than`` inequality objects also have the .lts and .gts properties, which represent the "less than side" and "greater than side" of the operator. Use of .lts and .gts in an algorithm rather than .lhs and .rhs as an assumption of inequality direction will make more explicit the intent of a certain section of code, and will make it similarly more robust to client code changes: >>> from sympy import GreaterThan, StrictGreaterThan >>> from sympy import LessThan, StrictLessThan >>> from sympy import And, Ge, Gt, Le, Lt, Rel, S >>> from sympy.abc import x, y, z >>> from sympy.core.relational import Relational >>> e = GreaterThan(x, 1) >>> e x >= 1 >>> '%s >= %s is the same as %s <= %s' % (e.gts, e.lts, e.lts, e.gts) 'x >= 1 is the same as 1 <= x' Examples ======== One generally does not instantiate these classes directly, but uses various convenience methods: >>> for f in [Ge, Gt, Le, Lt]: # convenience wrappers ... print(f(x, 2)) x >= 2 x > 2 x <= 2 x < 2 Another option is to use the Python inequality operators (>=, >, <=, <) directly. Their main advantage over the Ge, Gt, Le, and Lt counterparts, is that one can write a more "mathematical looking" statement rather than littering the math with oddball function calls. However there are certain (minor) caveats of which to be aware (search for 'gotcha', below). >>> x >= 2 x >= 2 >>> _ == Ge(x, 2) True However, it is also perfectly valid to instantiate a ``*Than`` class less succinctly and less conveniently: >>> Rel(x, 1, ">") x > 1 >>> Relational(x, 1, ">") x > 1 >>> StrictGreaterThan(x, 1) x > 1 >>> GreaterThan(x, 1) x >= 1 >>> LessThan(x, 1) x <= 1 >>> StrictLessThan(x, 1) x < 1 Notes ===== There are a couple of "gotchas" to be aware of when using Python's operators. The first is that what your write is not always what you get: >>> 1 < x x > 1 Due to the order that Python parses a statement, it may not immediately find two objects comparable. When "1 < x" is evaluated, Python recognizes that the number 1 is a native number and that x is *not*. Because a native Python number does not know how to compare itself with a SymPy object Python will try the reflective operation, "x > 1" and that is the form that gets evaluated, hence returned. If the order of the statement is important (for visual output to the console, perhaps), one can work around this annoyance in a couple ways: (1) "sympify" the literal before comparison >>> S(1) < x 1 < x (2) use one of the wrappers or less succinct methods described above >>> Lt(1, x) 1 < x >>> Relational(1, x, "<") 1 < x The second gotcha involves writing equality tests between relationals when one or both sides of the test involve a literal relational: >>> e = x < 1; e x < 1 >>> e == e # neither side is a literal True >>> e == x < 1 # expecting True, too False >>> e != x < 1 # expecting False x < 1 >>> x < 1 != x < 1 # expecting False or the same thing as before Traceback (most recent call last): ... TypeError: cannot determine truth value of Relational The solution for this case is to wrap literal relationals in parentheses: >>> e == (x < 1) True >>> e != (x < 1) False >>> (x < 1) != (x < 1) False The third gotcha involves chained inequalities not involving '==' or '!='. Occasionally, one may be tempted to write: >>> e = x < y < z Traceback (most recent call last): ... TypeError: symbolic boolean expression has no truth value. Due to an implementation detail or decision of Python [1]_, there is no way for SymPy to create a chained inequality with that syntax so one must use And: >>> e = And(x < y, y < z) >>> type( e ) And >>> e (x < y) & (y < z) Although this can also be done with the '&' operator, it cannot be done with the 'and' operarator: >>> (x < y) & (y < z) (x < y) & (y < z) >>> (x < y) and (y < z) Traceback (most recent call last): ... TypeError: cannot determine truth value of Relational .. [1] This implementation detail is that Python provides no reliable method to determine that a chained inequality is being built. Chained comparison operators are evaluated pairwise, using "and" logic (see http://docs.python.org/reference/expressions.html#not-in). This is done in an efficient way, so that each object being compared is only evaluated once and the comparison can short-circuit. For example, ``1 > 2 > 3`` is evaluated by Python as ``(1 > 2) and (2 > 3)``. The ``and`` operator coerces each side into a bool, returning the object itself when it short-circuits. The bool of the --Than operators will raise TypeError on purpose, because SymPy cannot determine the mathematical ordering of symbolic expressions. Thus, if we were to compute ``x > y > z``, with ``x``, ``y``, and ``z`` being Symbols, Python converts the statement (roughly) into these steps: (1) x > y > z (2) (x > y) and (y > z) (3) (GreaterThanObject) and (y > z) (4) (GreaterThanObject.__bool__()) and (y > z) (5) TypeError Because of the "and" added at step 2, the statement gets turned into a weak ternary statement, and the first object's __bool__ method will raise TypeError. Thus, creating a chained inequality is not possible. In Python, there is no way to override the ``and`` operator, or to control how it short circuits, so it is impossible to make something like ``x > y > z`` work. There was a PEP to change this, :pep:`335`, but it was officially closed in March, 2012. """ __slots__ = () rel_op = '>=' @classmethod def _eval_fuzzy_relation(cls, lhs, rhs): return is_ge(lhs, rhs) Ge = GreaterThan class LessThan(_Less): __doc__ = GreaterThan.__doc__ __slots__ = () rel_op = '<=' @classmethod def _eval_fuzzy_relation(cls, lhs, rhs): return is_le(lhs, rhs) Le = LessThan class StrictGreaterThan(_Greater): __doc__ = GreaterThan.__doc__ __slots__ = () rel_op = '>' @classmethod def _eval_fuzzy_relation(cls, lhs, rhs): return is_gt(lhs, rhs) Gt = StrictGreaterThan class StrictLessThan(_Less): __doc__ = GreaterThan.__doc__ __slots__ = () rel_op = '<' @classmethod def _eval_fuzzy_relation(cls, lhs, rhs): return is_lt(lhs, rhs) Lt = StrictLessThan # A class-specific (not object-specific) data item used for a minor speedup. # It is defined here, rather than directly in the class, because the classes # that it references have not been defined until now (e.g. StrictLessThan). Relational.ValidRelationOperator = { None: Equality, '==': Equality, 'eq': Equality, '!=': Unequality, '<>': Unequality, 'ne': Unequality, '>=': GreaterThan, 'ge': GreaterThan, '<=': LessThan, 'le': LessThan, '>': StrictGreaterThan, 'gt': StrictGreaterThan, '<': StrictLessThan, 'lt': StrictLessThan, } def _n2(a, b): """Return (a - b).evalf(2) if a and b are comparable, else None. This should only be used when a and b are already sympified. """ # /!\ it is very important (see issue 8245) not to # use a re-evaluated number in the calculation of dif if a.is_comparable and b.is_comparable: dif = (a - b).evalf(2) if dif.is_comparable: return dif @dispatch(Expr, Expr) def _eval_is_ge(lhs, rhs): return None @dispatch(Basic, Basic) def _eval_is_eq(lhs, rhs): return None @dispatch(Tuple, Expr) # type: ignore def _eval_is_eq(lhs, rhs): # noqa:F811 return False @dispatch(Tuple, AppliedUndef) # type: ignore def _eval_is_eq(lhs, rhs): # noqa:F811 return None @dispatch(Tuple, Symbol) # type: ignore def _eval_is_eq(lhs, rhs): # noqa:F811 return None @dispatch(Tuple, Tuple) # type: ignore def _eval_is_eq(lhs, rhs): # noqa:F811 if len(lhs) != len(rhs): return False return fuzzy_and(fuzzy_bool(is_eq(s, o)) for s, o in zip(lhs, rhs)) def is_lt(lhs, rhs, assumptions=None): """Fuzzy bool for lhs is strictly less than rhs. See the docstring for :func:`~.is_ge` for more. """ return fuzzy_not(is_ge(lhs, rhs, assumptions)) def is_gt(lhs, rhs, assumptions=None): """Fuzzy bool for lhs is strictly greater than rhs. See the docstring for :func:`~.is_ge` for more. """ return fuzzy_not(is_le(lhs, rhs, assumptions)) def is_le(lhs, rhs, assumptions=None): """Fuzzy bool for lhs is less than or equal to rhs. See the docstring for :func:`~.is_ge` for more. """ return is_ge(rhs, lhs, assumptions) def is_ge(lhs, rhs, assumptions=None): """ Fuzzy bool for *lhs* is greater than or equal to *rhs*. Parameters ========== lhs : Expr The left-hand side of the expression, must be sympified, and an instance of expression. Throws an exception if lhs is not an instance of expression. rhs : Expr The right-hand side of the expression, must be sympified and an instance of expression. Throws an exception if lhs is not an instance of expression. assumptions: Boolean, optional Assumptions taken to evaluate the inequality. Returns ======= ``True`` if *lhs* is greater than or equal to *rhs*, ``False`` if *lhs* is less than *rhs*, and ``None`` if the comparison between *lhs* and *rhs* is indeterminate. Explanation =========== This function is intended to give a relatively fast determination and deliberately does not attempt slow calculations that might help in obtaining a determination of True or False in more difficult cases. The four comparison functions ``is_le``, ``is_lt``, ``is_ge``, and ``is_gt`` are each implemented in terms of ``is_ge`` in the following way: is_ge(x, y) := is_ge(x, y) is_le(x, y) := is_ge(y, x) is_lt(x, y) := fuzzy_not(is_ge(x, y)) is_gt(x, y) := fuzzy_not(is_ge(y, x)) Therefore, supporting new type with this function will ensure behavior for other three functions as well. To maintain these equivalences in fuzzy logic it is important that in cases where either x or y is non-real all comparisons will give None. Examples ======== >>> from sympy import S, Q >>> from sympy.core.relational import is_ge, is_le, is_gt, is_lt >>> from sympy.abc import x >>> is_ge(S(2), S(0)) True >>> is_ge(S(0), S(2)) False >>> is_le(S(0), S(2)) True >>> is_gt(S(0), S(2)) False >>> is_lt(S(2), S(0)) False Assumptions can be passed to evaluate the quality which is otherwise indeterminate. >>> print(is_ge(x, S(0))) None >>> is_ge(x, S(0), assumptions=Q.positive(x)) True New types can be supported by dispatching to ``_eval_is_ge``. >>> from sympy import Expr, sympify >>> from sympy.multipledispatch import dispatch >>> class MyExpr(Expr): ... def __new__(cls, arg): ... return super().__new__(cls, sympify(arg)) ... @property ... def value(self): ... return self.args[0] >>> @dispatch(MyExpr, MyExpr) ... def _eval_is_ge(a, b): ... return is_ge(a.value, b.value) >>> a = MyExpr(1) >>> b = MyExpr(2) >>> is_ge(b, a) True >>> is_le(a, b) True """ from sympy.assumptions.wrapper import AssumptionsWrapper, is_extended_nonnegative if not (isinstance(lhs, Expr) and isinstance(rhs, Expr)): raise TypeError("Can only compare inequalities with Expr") retval = _eval_is_ge(lhs, rhs) if retval is not None: return retval else: n2 = _n2(lhs, rhs) if n2 is not None: # use float comparison for infinity. # otherwise get stuck in infinite recursion if n2 in (S.Infinity, S.NegativeInfinity): n2 = float(n2) return n2 >= 0 _lhs = AssumptionsWrapper(lhs, assumptions) _rhs = AssumptionsWrapper(rhs, assumptions) if _lhs.is_extended_real and _rhs.is_extended_real: if (_lhs.is_infinite and _lhs.is_extended_positive) or (_rhs.is_infinite and _rhs.is_extended_negative): return True diff = lhs - rhs if diff is not S.NaN: rv = is_extended_nonnegative(diff, assumptions) if rv is not None: return rv def is_neq(lhs, rhs, assumptions=None): """Fuzzy bool for lhs does not equal rhs. See the docstring for :func:`~.is_eq` for more. """ return fuzzy_not(is_eq(lhs, rhs, assumptions)) def is_eq(lhs, rhs, assumptions=None): """ Fuzzy bool representing mathematical equality between *lhs* and *rhs*. Parameters ========== lhs : Expr The left-hand side of the expression, must be sympified. rhs : Expr The right-hand side of the expression, must be sympified. assumptions: Boolean, optional Assumptions taken to evaluate the equality. Returns ======= ``True`` if *lhs* is equal to *rhs*, ``False`` is *lhs* is not equal to *rhs*, and ``None`` if the comparison between *lhs* and *rhs* is indeterminate. Explanation =========== This function is intended to give a relatively fast determination and deliberately does not attempt slow calculations that might help in obtaining a determination of True or False in more difficult cases. :func:`~.is_neq` calls this function to return its value, so supporting new type with this function will ensure correct behavior for ``is_neq`` as well. Examples ======== >>> from sympy import Q, S >>> from sympy.core.relational import is_eq, is_neq >>> from sympy.abc import x >>> is_eq(S(0), S(0)) True >>> is_neq(S(0), S(0)) False >>> is_eq(S(0), S(2)) False >>> is_neq(S(0), S(2)) True Assumptions can be passed to evaluate the equality which is otherwise indeterminate. >>> print(is_eq(x, S(0))) None >>> is_eq(x, S(0), assumptions=Q.zero(x)) True New types can be supported by dispatching to ``_eval_is_eq``. >>> from sympy import Basic, sympify >>> from sympy.multipledispatch import dispatch >>> class MyBasic(Basic): ... def __new__(cls, arg): ... return Basic.__new__(cls, sympify(arg)) ... @property ... def value(self): ... return self.args[0] ... >>> @dispatch(MyBasic, MyBasic) ... def _eval_is_eq(a, b): ... return is_eq(a.value, b.value) ... >>> a = MyBasic(1) >>> b = MyBasic(1) >>> is_eq(a, b) True >>> is_neq(a, b) False """ from sympy.assumptions.wrapper import (AssumptionsWrapper, is_infinite, is_extended_real) from sympy.core.add import Add from sympy.functions.elementary.complexes import arg from sympy.simplify.simplify import clear_coefficients from sympy.utilities.iterables import sift # here, _eval_Eq is only called for backwards compatibility # new code should use is_eq with multiple dispatch as # outlined in the docstring for side1, side2 in (lhs, rhs), (rhs, lhs): eval_func = getattr(side1, '_eval_Eq', None) if eval_func is not None: retval = eval_func(side2) if retval is not None: return retval retval = _eval_is_eq(lhs, rhs) if retval is not None: return retval if dispatch(type(lhs), type(rhs)) != dispatch(type(rhs), type(lhs)): retval = _eval_is_eq(rhs, lhs) if retval is not None: return retval # retval is still None, so go through the equality logic # If expressions have the same structure, they must be equal. if lhs == rhs: return True # e.g. True == True elif all(isinstance(i, BooleanAtom) for i in (rhs, lhs)): return False # True != False elif not (lhs.is_Symbol or rhs.is_Symbol) and ( isinstance(lhs, Boolean) != isinstance(rhs, Boolean)): return False # only Booleans can equal Booleans _lhs = AssumptionsWrapper(lhs, assumptions) _rhs = AssumptionsWrapper(rhs, assumptions) if _lhs.is_infinite or _rhs.is_infinite: if fuzzy_xor([_lhs.is_infinite, _rhs.is_infinite]): return False if fuzzy_xor([_lhs.is_extended_real, _rhs.is_extended_real]): return False if fuzzy_and([_lhs.is_extended_real, _rhs.is_extended_real]): return fuzzy_xor([_lhs.is_extended_positive, fuzzy_not(_rhs.is_extended_positive)]) # Try to split real/imaginary parts and equate them I = S.ImaginaryUnit def split_real_imag(expr): real_imag = lambda t: ( 'real' if is_extended_real(t, assumptions) else 'imag' if is_extended_real(I*t, assumptions) else None) return sift(Add.make_args(expr), real_imag) lhs_ri = split_real_imag(lhs) if not lhs_ri[None]: rhs_ri = split_real_imag(rhs) if not rhs_ri[None]: eq_real = is_eq(Add(*lhs_ri['real']), Add(*rhs_ri['real']), assumptions) eq_imag = is_eq(I * Add(*lhs_ri['imag']), I * Add(*rhs_ri['imag']), assumptions) return fuzzy_and(map(fuzzy_bool, [eq_real, eq_imag])) # Compare e.g. zoo with 1+I*oo by comparing args arglhs = arg(lhs) argrhs = arg(rhs) # Guard against Eq(nan, nan) -> False if not (arglhs == S.NaN and argrhs == S.NaN): return fuzzy_bool(is_eq(arglhs, argrhs, assumptions)) if all(isinstance(i, Expr) for i in (lhs, rhs)): # see if the difference evaluates dif = lhs - rhs _dif = AssumptionsWrapper(dif, assumptions) z = _dif.is_zero if z is not None: if z is False and _dif.is_commutative: # issue 10728 return False if z: return True n2 = _n2(lhs, rhs) if n2 is not None: return _sympify(n2 == 0) # see if the ratio evaluates n, d = dif.as_numer_denom() rv = None _n = AssumptionsWrapper(n, assumptions) _d = AssumptionsWrapper(d, assumptions) if _n.is_zero: rv = _d.is_nonzero elif _n.is_finite: if _d.is_infinite: rv = True elif _n.is_zero is False: rv = _d.is_infinite if rv is None: # if the condition that makes the denominator # infinite does not make the original expression # True then False can be returned l, r = clear_coefficients(d, S.Infinity) args = [_.subs(l, r) for _ in (lhs, rhs)] if args != [lhs, rhs]: rv = fuzzy_bool(is_eq(*args, assumptions)) if rv is True: rv = None elif any(is_infinite(a, assumptions) for a in Add.make_args(n)): # (inf or nan)/x != 0 rv = False if rv is not None: return rv sympy-sympy-1.9/sympy/core/rules.py000066400000000000000000000027301412543434000175420ustar00rootroot00000000000000""" Replacement rules. """ class Transform: """ Immutable mapping that can be used as a generic transformation rule. Parameters ========== transform : callable Computes the value corresponding to any key. filter : callable, optional If supplied, specifies which objects are in the mapping. Examples ======== >>> from sympy.core.rules import Transform >>> from sympy.abc import x This Transform will return, as a value, one more than the key: >>> add1 = Transform(lambda x: x + 1) >>> add1[1] 2 >>> add1[x] x + 1 By default, all values are considered to be in the dictionary. If a filter is supplied, only the objects for which it returns True are considered as being in the dictionary: >>> add1_odd = Transform(lambda x: x + 1, lambda x: x%2 == 1) >>> 2 in add1_odd False >>> add1_odd.get(2, 0) 0 >>> 3 in add1_odd True >>> add1_odd[3] 4 >>> add1_odd.get(3, 0) 4 """ def __init__(self, transform, filter=lambda x: True): self._transform = transform self._filter = filter def __contains__(self, item): return self._filter(item) def __getitem__(self, key): if self._filter(key): return self._transform(key) else: raise KeyError(key) def get(self, item, default=None): if item in self: return self[item] else: return default sympy-sympy-1.9/sympy/core/singleton.py000066400000000000000000000155071412543434000204200ustar00rootroot00000000000000"""Singleton mechanism""" from .core import Registry from .assumptions import ManagedProperties from .sympify import sympify class SingletonRegistry(Registry): """ The registry for the singleton classes (accessible as ``S``). Explanation =========== This class serves as two separate things. The first thing it is is the ``SingletonRegistry``. Several classes in SymPy appear so often that they are singletonized, that is, using some metaprogramming they are made so that they can only be instantiated once (see the :class:`sympy.core.singleton.Singleton` class for details). For instance, every time you create ``Integer(0)``, this will return the same instance, :class:`sympy.core.numbers.Zero`. All singleton instances are attributes of the ``S`` object, so ``Integer(0)`` can also be accessed as ``S.Zero``. Singletonization offers two advantages: it saves memory, and it allows fast comparison. It saves memory because no matter how many times the singletonized objects appear in expressions in memory, they all point to the same single instance in memory. The fast comparison comes from the fact that you can use ``is`` to compare exact instances in Python (usually, you need to use ``==`` to compare things). ``is`` compares objects by memory address, and is very fast. Examples ======== >>> from sympy import S, Integer >>> a = Integer(0) >>> a is S.Zero True For the most part, the fact that certain objects are singletonized is an implementation detail that users shouldn't need to worry about. In SymPy library code, ``is`` comparison is often used for performance purposes The primary advantage of ``S`` for end users is the convenient access to certain instances that are otherwise difficult to type, like ``S.Half`` (instead of ``Rational(1, 2)``). When using ``is`` comparison, make sure the argument is sympified. For instance, >>> x = 0 >>> x is S.Zero False This problem is not an issue when using ``==``, which is recommended for most use-cases: >>> 0 == S.Zero True The second thing ``S`` is is a shortcut for :func:`sympy.core.sympify.sympify`. :func:`sympy.core.sympify.sympify` is the function that converts Python objects such as ``int(1)`` into SymPy objects such as ``Integer(1)``. It also converts the string form of an expression into a SymPy expression, like ``sympify("x**2")`` -> ``Symbol("x")**2``. ``S(1)`` is the same thing as ``sympify(1)`` (basically, ``S.__call__`` has been defined to call ``sympify``). This is for convenience, since ``S`` is a single letter. It's mostly useful for defining rational numbers. Consider an expression like ``x + 1/2``. If you enter this directly in Python, it will evaluate the ``1/2`` and give ``0.5`` (or just ``0`` in Python 2, because of integer division), because both arguments are ints (see also :ref:`tutorial-gotchas-final-notes`). However, in SymPy, you usually want the quotient of two integers to give an exact rational number. The way Python's evaluation works, at least one side of an operator needs to be a SymPy object for the SymPy evaluation to take over. You could write this as ``x + Rational(1, 2)``, but this is a lot more typing. A shorter version is ``x + S(1)/2``. Since ``S(1)`` returns ``Integer(1)``, the division will return a ``Rational`` type, since it will call ``Integer.__truediv__``, which knows how to return a ``Rational``. """ __slots__ = () # Also allow things like S(5) __call__ = staticmethod(sympify) def __init__(self): self._classes_to_install = {} # Dict of classes that have been registered, but that have not have been # installed as an attribute of this SingletonRegistry. # Installation automatically happens at the first attempt to access the # attribute. # The purpose of this is to allow registration during class # initialization during import, but not trigger object creation until # actual use (which should not happen until after all imports are # finished). def register(self, cls): # Make sure a duplicate class overwrites the old one if hasattr(self, cls.__name__): delattr(self, cls.__name__) self._classes_to_install[cls.__name__] = cls def __getattr__(self, name): """Python calls __getattr__ if no attribute of that name was installed yet. Explanation =========== This __getattr__ checks whether a class with the requested name was already registered but not installed; if no, raises an AttributeError. Otherwise, retrieves the class, calculates its singleton value, installs it as an attribute of the given name, and unregisters the class.""" if name not in self._classes_to_install: raise AttributeError( "Attribute '%s' was not installed on SymPy registry %s" % ( name, self)) class_to_install = self._classes_to_install[name] value_to_install = class_to_install() self.__setattr__(name, value_to_install) del self._classes_to_install[name] return value_to_install def __repr__(self): return "S" S = SingletonRegistry() class Singleton(ManagedProperties): """ Metaclass for singleton classes. Explanation =========== A singleton class has only one instance which is returned every time the class is instantiated. Additionally, this instance can be accessed through the global registry object ``S`` as ``S.``. Examples ======== >>> from sympy import S, Basic >>> from sympy.core.singleton import Singleton >>> class MySingleton(Basic, metaclass=Singleton): ... pass >>> Basic() is Basic() False >>> MySingleton() is MySingleton() True >>> S.MySingleton is MySingleton() True Notes ===== Instance creation is delayed until the first time the value is accessed. (SymPy versions before 1.0 would create the instance during class creation time, which would be prone to import cycles.) This metaclass is a subclass of ManagedProperties because that is the metaclass of many classes that need to be Singletons (Python does not allow subclasses to have a different metaclass than the superclass, except the subclass may use a subclassed metaclass). """ def __init__(cls, *args, **kwargs): super().__init__(cls, *args, **kwargs) cls._instance = obj = Basic.__new__(cls) cls.__new__ = lambda cls: obj cls.__getnewargs__ = lambda obj: () cls.__getstate__ = lambda obj: None S.register(cls) # Delayed to avoid cyclic import from .basic import Basic sympy-sympy-1.9/sympy/core/symbol.py000066400000000000000000000642171412543434000177250ustar00rootroot00000000000000from sympy.core.assumptions import StdFactKB, _assume_defined from sympy.core.compatibility import is_sequence, ordered from .basic import Basic, Atom from .sympify import sympify from .singleton import S from .expr import Expr, AtomicExpr from .cache import cacheit from .function import FunctionClass from .kind import NumberKind, UndefinedKind from sympy.core.logic import fuzzy_bool from sympy.logic.boolalg import Boolean from sympy.utilities.iterables import cartes, sift from sympy.core.containers import Tuple import string import re as _re import random class Str(Atom): """ Represents string in SymPy. Explanation =========== Previously, ``Symbol`` was used where string is needed in ``args`` of SymPy objects, e.g. denoting the name of the instance. However, since ``Symbol`` represents mathematical scalar, this class should be used instead. """ __slots__ = ('name',) def __new__(cls, name, **kwargs): if not isinstance(name, str): raise TypeError("name should be a string, not %s" % repr(type(name))) obj = Expr.__new__(cls, **kwargs) obj.name = name return obj def __getnewargs__(self): return (self.name,) def _hashable_content(self): return (self.name,) def _filter_assumptions(kwargs): """Split the given dict into assumptions and non-assumptions. Keys are taken as assumptions if they correspond to an entry in ``_assume_defined``. """ assumptions, nonassumptions = map(dict, sift(kwargs.items(), lambda i: i[0] in _assume_defined, binary=True)) Symbol._sanitize(assumptions) return assumptions, nonassumptions def _symbol(s, matching_symbol=None, **assumptions): """Return s if s is a Symbol, else if s is a string, return either the matching_symbol if the names are the same or else a new symbol with the same assumptions as the matching symbol (or the assumptions as provided). Examples ======== >>> from sympy import Symbol >>> from sympy.core.symbol import _symbol >>> _symbol('y') y >>> _.is_real is None True >>> _symbol('y', real=True).is_real True >>> x = Symbol('x') >>> _symbol(x, real=True) x >>> _.is_real is None # ignore attribute if s is a Symbol True Below, the variable sym has the name 'foo': >>> sym = Symbol('foo', real=True) Since 'x' is not the same as sym's name, a new symbol is created: >>> _symbol('x', sym).name 'x' It will acquire any assumptions give: >>> _symbol('x', sym, real=False).is_real False Since 'foo' is the same as sym's name, sym is returned >>> _symbol('foo', sym) foo Any assumptions given are ignored: >>> _symbol('foo', sym, real=False).is_real True NB: the symbol here may not be the same as a symbol with the same name defined elsewhere as a result of different assumptions. See Also ======== sympy.core.symbol.Symbol """ if isinstance(s, str): if matching_symbol and matching_symbol.name == s: return matching_symbol return Symbol(s, **assumptions) elif isinstance(s, Symbol): return s else: raise ValueError('symbol must be string for symbol name or Symbol') def uniquely_named_symbol(xname, exprs=(), compare=str, modify=None, **assumptions): """Return a symbol which, when printed, will have a name unique from any other already in the expressions given. The name is made unique by appending numbers (default) but this can be customized with the keyword 'modify'. Parameters ========== xname : a string or a Symbol (when symbol xname <- str(xname)) compare : a single arg function that takes a symbol and returns a string to be compared with xname (the default is the str function which indicates how the name will look when it is printed, e.g. this includes underscores that appear on Dummy symbols) modify : a single arg function that changes its string argument in some way (the default is to append numbers) Examples ======== >>> from sympy.core.symbol import uniquely_named_symbol >>> from sympy.abc import x >>> uniquely_named_symbol('x', x) x0 """ from sympy.core.function import AppliedUndef def numbered_string_incr(s, start=0): if not s: return str(start) i = len(s) - 1 while i != -1: if not s[i].isdigit(): break i -= 1 n = str(int(s[i + 1:] or start - 1) + 1) return s[:i + 1] + n default = None if is_sequence(xname): xname, default = xname x = str(xname) if not exprs: return _symbol(x, default, **assumptions) if not is_sequence(exprs): exprs = [exprs] names = set().union( [i.name for e in exprs for i in e.atoms(Symbol)] + [i.func.name for e in exprs for i in e.atoms(AppliedUndef)]) if modify is None: modify = numbered_string_incr while any(x == compare(s) for s in names): x = modify(x) return _symbol(x, default, **assumptions) _uniquely_named_symbol = uniquely_named_symbol class Symbol(AtomicExpr, Boolean): """ Assumptions: commutative = True You can override the default assumptions in the constructor. Examples ======== >>> from sympy import symbols >>> A,B = symbols('A,B', commutative = False) >>> bool(A*B != B*A) True >>> bool(A*B*2 == 2*A*B) == True # multiplication by scalars is commutative True """ is_comparable = False __slots__ = ('name',) is_Symbol = True is_symbol = True @property def kind(self): if self.is_commutative: return NumberKind return UndefinedKind @property def _diff_wrt(self): """Allow derivatives wrt Symbols. Examples ======== >>> from sympy import Symbol >>> x = Symbol('x') >>> x._diff_wrt True """ return True @staticmethod def _sanitize(assumptions, obj=None): """Remove None, covert values to bool, check commutativity *in place*. """ # be strict about commutativity: cannot be None is_commutative = fuzzy_bool(assumptions.get('commutative', True)) if is_commutative is None: whose = '%s ' % obj.__name__ if obj else '' raise ValueError( '%scommutativity must be True or False.' % whose) # sanitize other assumptions so 1 -> True and 0 -> False for key in list(assumptions.keys()): v = assumptions[key] if v is None: assumptions.pop(key) continue assumptions[key] = bool(v) def _merge(self, assumptions): base = self.assumptions0 for k in set(assumptions) & set(base): if assumptions[k] != base[k]: from sympy.utilities.misc import filldedent raise ValueError(filldedent(''' non-matching assumptions for %s: existing value is %s and new value is %s''' % ( k, base[k], assumptions[k]))) base.update(assumptions) return base def __new__(cls, name, **assumptions): """Symbols are identified by name and assumptions:: >>> from sympy import Symbol >>> Symbol("x") == Symbol("x") True >>> Symbol("x", real=True) == Symbol("x", real=False) False """ cls._sanitize(assumptions, cls) return Symbol.__xnew_cached_(cls, name, **assumptions) def __new_stage2__(cls, name, **assumptions): if not isinstance(name, str): raise TypeError("name should be a string, not %s" % repr(type(name))) obj = Expr.__new__(cls) obj.name = name # TODO: Issue #8873: Forcing the commutative assumption here means # later code such as ``srepr()`` cannot tell whether the user # specified ``commutative=True`` or omitted it. To workaround this, # we keep a copy of the assumptions dict, then create the StdFactKB, # and finally overwrite its ``._generator`` with the dict copy. This # is a bit of a hack because we assume StdFactKB merely copies the # given dict as ``._generator``, but future modification might, e.g., # compute a minimal equivalent assumption set. tmp_asm_copy = assumptions.copy() # be strict about commutativity is_commutative = fuzzy_bool(assumptions.get('commutative', True)) assumptions['commutative'] = is_commutative obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = tmp_asm_copy # Issue #8873 return obj __xnew__ = staticmethod( __new_stage2__) # never cached (e.g. dummy) __xnew_cached_ = staticmethod( cacheit(__new_stage2__)) # symbols are always cached def __getnewargs_ex__(self): return ((self.name,), self.assumptions0) def _hashable_content(self): # Note: user-specified assumptions not hashed, just derived ones return (self.name,) + tuple(sorted(self.assumptions0.items())) def _eval_subs(self, old, new): from sympy.core.power import Pow if old.is_Pow: return Pow(self, S.One, evaluate=False)._eval_subs(old, new) def _eval_refine(self, assumptions): return self @property def assumptions0(self): return {key: value for key, value in self._assumptions.items() if value is not None} @cacheit def sort_key(self, order=None): return self.class_key(), (1, (self.name,)), S.One.sort_key(), S.One def as_dummy(self): # only put commutativity in explicitly if it is False return Dummy(self.name) if self.is_commutative is not False \ else Dummy(self.name, commutative=self.is_commutative) def as_real_imag(self, deep=True, **hints): from sympy import im, re if hints.get('ignore') == self: return None else: return (re(self), im(self)) def is_constant(self, *wrt, **flags): if not wrt: return False return not self in wrt @property def free_symbols(self): return {self} binary_symbols = free_symbols # in this case, not always def as_set(self): return S.UniversalSet class Dummy(Symbol): """Dummy symbols are each unique, even if they have the same name: Examples ======== >>> from sympy import Dummy >>> Dummy("x") == Dummy("x") False If a name is not supplied then a string value of an internal count will be used. This is useful when a temporary variable is needed and the name of the variable used in the expression is not important. >>> Dummy() #doctest: +SKIP _Dummy_10 """ # In the rare event that a Dummy object needs to be recreated, both the # `name` and `dummy_index` should be passed. This is used by `srepr` for # example: # >>> d1 = Dummy() # >>> d2 = eval(srepr(d1)) # >>> d2 == d1 # True # # If a new session is started between `srepr` and `eval`, there is a very # small chance that `d2` will be equal to a previously-created Dummy. _count = 0 _prng = random.Random() _base_dummy_index = _prng.randint(10**6, 9*10**6) __slots__ = ('dummy_index',) is_Dummy = True def __new__(cls, name=None, dummy_index=None, **assumptions): if dummy_index is not None: assert name is not None, "If you specify a dummy_index, you must also provide a name" if name is None: name = "Dummy_" + str(Dummy._count) if dummy_index is None: dummy_index = Dummy._base_dummy_index + Dummy._count Dummy._count += 1 cls._sanitize(assumptions, cls) obj = Symbol.__xnew__(cls, name, **assumptions) obj.dummy_index = dummy_index return obj def __getnewargs_ex__(self): return ((self.name, self.dummy_index), self.assumptions0) @cacheit def sort_key(self, order=None): return self.class_key(), ( 2, (self.name, self.dummy_index)), S.One.sort_key(), S.One def _hashable_content(self): return Symbol._hashable_content(self) + (self.dummy_index,) class Wild(Symbol): """ A Wild symbol matches anything, or anything without whatever is explicitly excluded. Parameters ========== name : str Name of the Wild instance. exclude : iterable, optional Instances in ``exclude`` will not be matched. properties : iterable of functions, optional Functions, each taking an expressions as input and returns a ``bool``. All functions in ``properties`` need to return ``True`` in order for the Wild instance to match the expression. Examples ======== >>> from sympy import Wild, WildFunction, cos, pi >>> from sympy.abc import x, y, z >>> a = Wild('a') >>> x.match(a) {a_: x} >>> pi.match(a) {a_: pi} >>> (3*x**2).match(a*x) {a_: 3*x} >>> cos(x).match(a) {a_: cos(x)} >>> b = Wild('b', exclude=[x]) >>> (3*x**2).match(b*x) >>> b.match(a) {a_: b_} >>> A = WildFunction('A') >>> A.match(a) {a_: A_} Tips ==== When using Wild, be sure to use the exclude keyword to make the pattern more precise. Without the exclude pattern, you may get matches that are technically correct, but not what you wanted. For example, using the above without exclude: >>> from sympy import symbols >>> a, b = symbols('a b', cls=Wild) >>> (2 + 3*y).match(a*x + b*y) {a_: 2/x, b_: 3} This is technically correct, because (2/x)*x + 3*y == 2 + 3*y, but you probably wanted it to not match at all. The issue is that you really didn't want a and b to include x and y, and the exclude parameter lets you specify exactly this. With the exclude parameter, the pattern will not match. >>> a = Wild('a', exclude=[x, y]) >>> b = Wild('b', exclude=[x, y]) >>> (2 + 3*y).match(a*x + b*y) Exclude also helps remove ambiguity from matches. >>> E = 2*x**3*y*z >>> a, b = symbols('a b', cls=Wild) >>> E.match(a*b) {a_: 2*y*z, b_: x**3} >>> a = Wild('a', exclude=[x, y]) >>> E.match(a*b) {a_: z, b_: 2*x**3*y} >>> a = Wild('a', exclude=[x, y, z]) >>> E.match(a*b) {a_: 2, b_: x**3*y*z} Wild also accepts a ``properties`` parameter: >>> a = Wild('a', properties=[lambda k: k.is_Integer]) >>> E.match(a*b) {a_: 2, b_: x**3*y*z} """ is_Wild = True __slots__ = ('exclude', 'properties') def __new__(cls, name, exclude=(), properties=(), **assumptions): exclude = tuple([sympify(x) for x in exclude]) properties = tuple(properties) cls._sanitize(assumptions, cls) return Wild.__xnew__(cls, name, exclude, properties, **assumptions) def __getnewargs__(self): return (self.name, self.exclude, self.properties) @staticmethod @cacheit def __xnew__(cls, name, exclude, properties, **assumptions): obj = Symbol.__xnew__(cls, name, **assumptions) obj.exclude = exclude obj.properties = properties return obj def _hashable_content(self): return super()._hashable_content() + (self.exclude, self.properties) # TODO add check against another Wild def matches(self, expr, repl_dict={}, old=False): if any(expr.has(x) for x in self.exclude): return None if any(not f(expr) for f in self.properties): return None repl_dict = repl_dict.copy() repl_dict[self] = expr return repl_dict _range = _re.compile('([0-9]*:[0-9]+|[a-zA-Z]?:[a-zA-Z])') def symbols(names, *, cls=Symbol, **args): r""" Transform strings into instances of :class:`Symbol` class. :func:`symbols` function returns a sequence of symbols with names taken from ``names`` argument, which can be a comma or whitespace delimited string, or a sequence of strings:: >>> from sympy import symbols, Function >>> x, y, z = symbols('x,y,z') >>> a, b, c = symbols('a b c') The type of output is dependent on the properties of input arguments:: >>> symbols('x') x >>> symbols('x,') (x,) >>> symbols('x,y') (x, y) >>> symbols(('a', 'b', 'c')) (a, b, c) >>> symbols(['a', 'b', 'c']) [a, b, c] >>> symbols({'a', 'b', 'c'}) {a, b, c} If an iterable container is needed for a single symbol, set the ``seq`` argument to ``True`` or terminate the symbol name with a comma:: >>> symbols('x', seq=True) (x,) To reduce typing, range syntax is supported to create indexed symbols. Ranges are indicated by a colon and the type of range is determined by the character to the right of the colon. If the character is a digit then all contiguous digits to the left are taken as the nonnegative starting value (or 0 if there is no digit left of the colon) and all contiguous digits to the right are taken as 1 greater than the ending value:: >>> symbols('x:10') (x0, x1, x2, x3, x4, x5, x6, x7, x8, x9) >>> symbols('x5:10') (x5, x6, x7, x8, x9) >>> symbols('x5(:2)') (x50, x51) >>> symbols('x5:10,y:5') (x5, x6, x7, x8, x9, y0, y1, y2, y3, y4) >>> symbols(('x5:10', 'y:5')) ((x5, x6, x7, x8, x9), (y0, y1, y2, y3, y4)) If the character to the right of the colon is a letter, then the single letter to the left (or 'a' if there is none) is taken as the start and all characters in the lexicographic range *through* the letter to the right are used as the range:: >>> symbols('x:z') (x, y, z) >>> symbols('x:c') # null range () >>> symbols('x(:c)') (xa, xb, xc) >>> symbols(':c') (a, b, c) >>> symbols('a:d, x:z') (a, b, c, d, x, y, z) >>> symbols(('a:d', 'x:z')) ((a, b, c, d), (x, y, z)) Multiple ranges are supported; contiguous numerical ranges should be separated by parentheses to disambiguate the ending number of one range from the starting number of the next:: >>> symbols('x:2(1:3)') (x01, x02, x11, x12) >>> symbols(':3:2') # parsing is from left to right (00, 01, 10, 11, 20, 21) Only one pair of parentheses surrounding ranges are removed, so to include parentheses around ranges, double them. And to include spaces, commas, or colons, escape them with a backslash:: >>> symbols('x((a:b))') (x(a), x(b)) >>> symbols(r'x(:1\,:2)') # or r'x((:1)\,(:2))' (x(0,0), x(0,1)) All newly created symbols have assumptions set according to ``args``:: >>> a = symbols('a', integer=True) >>> a.is_integer True >>> x, y, z = symbols('x,y,z', real=True) >>> x.is_real and y.is_real and z.is_real True Despite its name, :func:`symbols` can create symbol-like objects like instances of Function or Wild classes. To achieve this, set ``cls`` keyword argument to the desired type:: >>> symbols('f,g,h', cls=Function) (f, g, h) >>> type(_[0]) """ result = [] if isinstance(names, str): marker = 0 literals = [r'\,', r'\:', r'\ '] for i in range(len(literals)): lit = literals.pop(0) if lit in names: while chr(marker) in names: marker += 1 lit_char = chr(marker) marker += 1 names = names.replace(lit, lit_char) literals.append((lit_char, lit[1:])) def literal(s): if literals: for c, l in literals: s = s.replace(c, l) return s names = names.strip() as_seq = names.endswith(',') if as_seq: names = names[:-1].rstrip() if not names: raise ValueError('no symbols given') # split on commas names = [n.strip() for n in names.split(',')] if not all(n for n in names): raise ValueError('missing symbol between commas') # split on spaces for i in range(len(names) - 1, -1, -1): names[i: i + 1] = names[i].split() seq = args.pop('seq', as_seq) for name in names: if not name: raise ValueError('missing symbol') if ':' not in name: symbol = cls(literal(name), **args) result.append(symbol) continue split = _range.split(name) # remove 1 layer of bounding parentheses around ranges for i in range(len(split) - 1): if i and ':' in split[i] and split[i] != ':' and \ split[i - 1].endswith('(') and \ split[i + 1].startswith(')'): split[i - 1] = split[i - 1][:-1] split[i + 1] = split[i + 1][1:] for i, s in enumerate(split): if ':' in s: if s[-1].endswith(':'): raise ValueError('missing end range') a, b = s.split(':') if b[-1] in string.digits: a = 0 if not a else int(a) b = int(b) split[i] = [str(c) for c in range(a, b)] else: a = a or 'a' split[i] = [string.ascii_letters[c] for c in range( string.ascii_letters.index(a), string.ascii_letters.index(b) + 1)] # inclusive if not split[i]: break else: split[i] = [s] else: seq = True if len(split) == 1: names = split[0] else: names = [''.join(s) for s in cartes(*split)] if literals: result.extend([cls(literal(s), **args) for s in names]) else: result.extend([cls(s, **args) for s in names]) if not seq and len(result) <= 1: if not result: return () return result[0] return tuple(result) else: for name in names: result.append(symbols(name, **args)) return type(names)(result) def var(names, **args): """ Create symbols and inject them into the global namespace. Explanation =========== This calls :func:`symbols` with the same arguments and puts the results into the *global* namespace. It's recommended not to use :func:`var` in library code, where :func:`symbols` has to be used:: Examples ======== >>> from sympy import var >>> var('x') x >>> x # noqa: F821 x >>> var('a,ab,abc') (a, ab, abc) >>> abc # noqa: F821 abc >>> var('x,y', real=True) (x, y) >>> x.is_real and y.is_real # noqa: F821 True See :func:`symbols` documentation for more details on what kinds of arguments can be passed to :func:`var`. """ def traverse(symbols, frame): """Recursively inject symbols to the global namespace. """ for symbol in symbols: if isinstance(symbol, Basic): frame.f_globals[symbol.name] = symbol elif isinstance(symbol, FunctionClass): frame.f_globals[symbol.__name__] = symbol else: traverse(symbol, frame) from inspect import currentframe frame = currentframe().f_back try: syms = symbols(names, **args) if syms is not None: if isinstance(syms, Basic): frame.f_globals[syms.name] = syms elif isinstance(syms, FunctionClass): frame.f_globals[syms.__name__] = syms else: traverse(syms, frame) finally: del frame # break cyclic dependencies as stated in inspect docs return syms def disambiguate(*iter): """ Return a Tuple containing the passed expressions with symbols that appear the same when printed replaced with numerically subscripted symbols, and all Dummy symbols replaced with Symbols. Parameters ========== iter: list of symbols or expressions. Examples ======== >>> from sympy.core.symbol import disambiguate >>> from sympy import Dummy, Symbol, Tuple >>> from sympy.abc import y >>> tup = Symbol('_x'), Dummy('x'), Dummy('x') >>> disambiguate(*tup) (x_2, x, x_1) >>> eqs = Tuple(Symbol('x')/y, Dummy('x')/y) >>> disambiguate(*eqs) (x_1/y, x/y) >>> ix = Symbol('x', integer=True) >>> vx = Symbol('x') >>> disambiguate(vx + ix) (x + x_1,) To make your own mapping of symbols to use, pass only the free symbols of the expressions and create a dictionary: >>> free = eqs.free_symbols >>> mapping = dict(zip(free, disambiguate(*free))) >>> eqs.xreplace(mapping) (x_1/y, x/y) """ new_iter = Tuple(*iter) key = lambda x:tuple(sorted(x.assumptions0.items())) syms = ordered(new_iter.free_symbols, keys=key) mapping = {} for s in syms: mapping.setdefault(str(s).lstrip('_'), []).append(s) reps = {} for k in mapping: # the first or only symbol doesn't get subscripted but make # sure that it's a Symbol, not a Dummy mapk0 = Symbol("%s" % (k), **mapping[k][0].assumptions0) if mapping[k][0] != mapk0: reps[mapping[k][0]] = mapk0 # the others get subscripts (and are made into Symbols) skip = 0 for i in range(1, len(mapping[k])): while True: name = "%s_%i" % (k, i + skip) if name not in mapping: break skip += 1 ki = mapping[k][i] reps[ki] = Symbol(name, **ki.assumptions0) return new_iter.xreplace(reps) sympy-sympy-1.9/sympy/core/sympify.py000066400000000000000000000457331412543434000201220ustar00rootroot00000000000000"""sympify -- convert objects SymPy internal format""" import typing if typing.TYPE_CHECKING: from typing import Any, Callable, Dict, Type from inspect import getmro from .compatibility import iterable from .parameters import global_parameters class SympifyError(ValueError): def __init__(self, expr, base_exc=None): self.expr = expr self.base_exc = base_exc def __str__(self): if self.base_exc is None: return "SympifyError: %r" % (self.expr,) return ("Sympify of expression '%s' failed, because of exception being " "raised:\n%s: %s" % (self.expr, self.base_exc.__class__.__name__, str(self.base_exc))) # See sympify docstring. converter = {} # type: Dict[Type[Any], Callable[[Any], Basic]] class CantSympify: """ Mix in this trait to a class to disallow sympification of its instances. Examples ======== >>> from sympy.core.sympify import sympify, CantSympify >>> class Something(dict): ... pass ... >>> sympify(Something()) {} >>> class Something(dict, CantSympify): ... pass ... >>> sympify(Something()) Traceback (most recent call last): ... SympifyError: SympifyError: {} """ pass def _is_numpy_instance(a): """ Checks if an object is an instance of a type from the numpy module. """ # This check avoids unnecessarily importing NumPy. We check the whole # __mro__ in case any base type is a numpy type. return any(type_.__module__ == 'numpy' for type_ in type(a).__mro__) def _convert_numpy_types(a, **sympify_args): """ Converts a numpy datatype input to an appropriate SymPy type. """ import numpy as np if not isinstance(a, np.floating): if np.iscomplex(a): return converter[complex](a.item()) else: return sympify(a.item(), **sympify_args) else: try: from sympy.core.numbers import Float prec = np.finfo(a).nmant + 1 # E.g. double precision means prec=53 but nmant=52 # Leading bit of mantissa is always 1, so is not stored a = str(list(np.reshape(np.asarray(a), (1, np.size(a)))[0]))[1:-1] return Float(a, precision=prec) except NotImplementedError: raise SympifyError('Translation for numpy float : %s ' 'is not implemented' % a) def sympify(a, locals=None, convert_xor=True, strict=False, rational=False, evaluate=None): """ Converts an arbitrary expression to a type that can be used inside SymPy. Explanation =========== It will convert Python ints into instances of sympy.Integer, floats into instances of sympy.Float, etc. It is also able to coerce symbolic expressions which inherit from Basic. This can be useful in cooperation with SAGE. .. warning:: Note that this function uses ``eval``, and thus shouldn't be used on unsanitized input. If the argument is already a type that SymPy understands, it will do nothing but return that value. This can be used at the beginning of a function to ensure you are working with the correct type. Examples ======== >>> from sympy import sympify >>> sympify(2).is_integer True >>> sympify(2).is_real True >>> sympify(2.0).is_real True >>> sympify("2.0").is_real True >>> sympify("2e-45").is_real True If the expression could not be converted, a SympifyError is raised. >>> sympify("x***2") Traceback (most recent call last): ... SympifyError: SympifyError: "could not parse 'x***2'" Locals ------ The sympification happens with access to everything that is loaded by ``from sympy import *``; anything used in a string that is not defined by that import will be converted to a symbol. In the following, the ``bitcount`` function is treated as a symbol and the ``O`` is interpreted as the Order object (used with series) and it raises an error when used improperly: >>> s = 'bitcount(42)' >>> sympify(s) bitcount(42) >>> sympify("O(x)") O(x) >>> sympify("O + 1") Traceback (most recent call last): ... TypeError: unbound method... In order to have ``bitcount`` be recognized it can be imported into a namespace dictionary and passed as locals: >>> ns = {} >>> exec('from sympy.core.evalf import bitcount', ns) >>> sympify(s, locals=ns) 6 In order to have the ``O`` interpreted as a Symbol, identify it as such in the namespace dictionary. This can be done in a variety of ways; all three of the following are possibilities: >>> from sympy import Symbol >>> ns["O"] = Symbol("O") # method 1 >>> exec('from sympy.abc import O', ns) # method 2 >>> ns.update(dict(O=Symbol("O"))) # method 3 >>> sympify("O + 1", locals=ns) O + 1 If you want *all* single-letter and Greek-letter variables to be symbols then you can use the clashing-symbols dictionaries that have been defined there as private variables: _clash1 (single-letter variables), _clash2 (the multi-letter Greek names) or _clash (both single and multi-letter names that are defined in abc). >>> from sympy.abc import _clash1 >>> set(_clash1) {'E', 'I', 'N', 'O', 'Q', 'S'} >>> sympify('I & Q', _clash1) I & Q Strict ------ If the option ``strict`` is set to ``True``, only the types for which an explicit conversion has been defined are converted. In the other cases, a SympifyError is raised. >>> print(sympify(None)) None >>> sympify(None, strict=True) Traceback (most recent call last): ... SympifyError: SympifyError: None Evaluation ---------- If the option ``evaluate`` is set to ``False``, then arithmetic and operators will be converted into their SymPy equivalents and the ``evaluate=False`` option will be added. Nested ``Add`` or ``Mul`` will be denested first. This is done via an AST transformation that replaces operators with their SymPy equivalents, so if an operand redefines any of those operations, the redefined operators will not be used. If argument a is not a string, the mathematical expression is evaluated before being passed to sympify, so adding evaluate=False will still return the evaluated result of expression. >>> sympify('2**2 / 3 + 5') 19/3 >>> sympify('2**2 / 3 + 5', evaluate=False) 2**2/3 + 5 >>> sympify('4/2+7', evaluate=True) 9 >>> sympify('4/2+7', evaluate=False) 4/2 + 7 >>> sympify(4/2+7, evaluate=False) 9.00000000000000 Extending --------- To extend ``sympify`` to convert custom objects (not derived from ``Basic``), just define a ``_sympy_`` method to your class. You can do that even to classes that you do not own by subclassing or adding the method at runtime. >>> from sympy import Matrix >>> class MyList1(object): ... def __iter__(self): ... yield 1 ... yield 2 ... return ... def __getitem__(self, i): return list(self)[i] ... def _sympy_(self): return Matrix(self) >>> sympify(MyList1()) Matrix([ [1], [2]]) If you do not have control over the class definition you could also use the ``converter`` global dictionary. The key is the class and the value is a function that takes a single argument and returns the desired SymPy object, e.g. ``converter[MyList] = lambda x: Matrix(x)``. >>> class MyList2(object): # XXX Do not do this if you control the class! ... def __iter__(self): # Use _sympy_! ... yield 1 ... yield 2 ... return ... def __getitem__(self, i): return list(self)[i] >>> from sympy.core.sympify import converter >>> converter[MyList2] = lambda x: Matrix(x) >>> sympify(MyList2()) Matrix([ [1], [2]]) Notes ===== The keywords ``rational`` and ``convert_xor`` are only used when the input is a string. convert_xor ----------- >>> sympify('x^y',convert_xor=True) x**y >>> sympify('x^y',convert_xor=False) x ^ y rational -------- >>> sympify('0.1',rational=False) 0.1 >>> sympify('0.1',rational=True) 1/10 Sometimes autosimplification during sympification results in expressions that are very different in structure than what was entered. Until such autosimplification is no longer done, the ``kernS`` function might be of some use. In the example below you can see how an expression reduces to -1 by autosimplification, but does not do so when ``kernS`` is used. >>> from sympy.core.sympify import kernS >>> from sympy.abc import x >>> -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 -1 >>> s = '-2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1' >>> sympify(s) -1 >>> kernS(s) -2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) - 1 Parameters ========== a : - any object defined in SymPy - standard numeric python types: int, long, float, Decimal - strings (like "0.09", "2e-19" or 'sin(x)') - booleans, including ``None`` (will leave ``None`` unchanged) - dict, lists, sets or tuples containing any of the above convert_xor : boolean, optional If true, treats XOR as exponentiation. If False, treats XOR as XOR itself. Used only when input is a string. locals : any object defined in SymPy, optional In order to have strings be recognized it can be imported into a namespace dictionary and passed as locals. strict : boolean, optional If the option strict is set to True, only the types for which an explicit conversion has been defined are converted. In the other cases, a SympifyError is raised. rational : boolean, optional If true, converts floats into Rational. If false, it lets floats remain as it is. Used only when input is a string. evaluate : boolean, optional If False, then arithmetic and operators will be converted into their SymPy equivalents. If True the expression will be evaluated and the result will be returned. """ # XXX: If a is a Basic subclass rather than instance (e.g. sin rather than # sin(x)) then a.__sympy__ will be the property. Only on the instance will # a.__sympy__ give the *value* of the property (True). Since sympify(sin) # was used for a long time we allow it to pass. However if strict=True as # is the case in internal calls to _sympify then we only allow # is_sympy=True. # # https://github.com/sympy/sympy/issues/20124 is_sympy = getattr(a, '__sympy__', None) if is_sympy is True: return a elif is_sympy is not None: if not strict: return a else: raise SympifyError(a) if isinstance(a, CantSympify): raise SympifyError(a) cls = getattr(a, "__class__", None) if cls is None: cls = type(a) # Probably an old-style class conv = converter.get(cls, None) if conv is not None: return conv(a) for superclass in getmro(cls): try: return converter[superclass](a) except KeyError: continue if cls is type(None): if strict: raise SympifyError(a) else: return a if evaluate is None: evaluate = global_parameters.evaluate # Support for basic numpy datatypes if _is_numpy_instance(a): import numpy as np if np.isscalar(a): return _convert_numpy_types(a, locals=locals, convert_xor=convert_xor, strict=strict, rational=rational, evaluate=evaluate) _sympy_ = getattr(a, "_sympy_", None) if _sympy_ is not None: try: return a._sympy_() # XXX: Catches AttributeError: 'SympyConverter' object has no # attribute 'tuple' # This is probably a bug somewhere but for now we catch it here. except AttributeError: pass if not strict: # Put numpy array conversion _before_ float/int, see # . flat = getattr(a, "flat", None) if flat is not None: shape = getattr(a, "shape", None) if shape is not None: from ..tensor.array import Array return Array(a.flat, a.shape) # works with e.g. NumPy arrays if not isinstance(a, str): if _is_numpy_instance(a): import numpy as np assert not isinstance(a, np.number) if isinstance(a, np.ndarray): # Scalar arrays (those with zero dimensions) have sympify # called on the scalar element. if a.ndim == 0: try: return sympify(a.item(), locals=locals, convert_xor=convert_xor, strict=strict, rational=rational, evaluate=evaluate) except SympifyError: pass else: # float and int can coerce size-one numpy arrays to their lone # element. See issue https://github.com/numpy/numpy/issues/10404. for coerce in (float, int): try: return sympify(coerce(a)) except (TypeError, ValueError, AttributeError, SympifyError): continue if strict: raise SympifyError(a) if iterable(a): try: return type(a)([sympify(x, locals=locals, convert_xor=convert_xor, rational=rational, evaluate=evaluate) for x in a]) except TypeError: # Not all iterables are rebuildable with their type. pass if not isinstance(a, str): try: a = str(a) except Exception as exc: raise SympifyError(a, exc) from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="String fallback in sympify", useinstead= \ 'sympify(str(obj)) or ' + \ 'sympy.core.sympify.converter or obj._sympy_', issue=18066, deprecated_since_version='1.6' ).warn() from sympy.parsing.sympy_parser import (parse_expr, TokenError, standard_transformations) from sympy.parsing.sympy_parser import convert_xor as t_convert_xor from sympy.parsing.sympy_parser import rationalize as t_rationalize transformations = standard_transformations if rational: transformations += (t_rationalize,) if convert_xor: transformations += (t_convert_xor,) try: a = a.replace('\n', '') expr = parse_expr(a, local_dict=locals, transformations=transformations, evaluate=evaluate) except (TokenError, SyntaxError) as exc: raise SympifyError('could not parse %r' % a, exc) return expr def _sympify(a): """ Short version of sympify for internal usage for __add__ and __eq__ methods where it is ok to allow some things (like Python integers and floats) in the expression. This excludes things (like strings) that are unwise to allow into such an expression. >>> from sympy import Integer >>> Integer(1) == 1 True >>> Integer(1) == '1' False >>> from sympy.abc import x >>> x + 1 x + 1 >>> x + '1' Traceback (most recent call last): ... TypeError: unsupported operand type(s) for +: 'Symbol' and 'str' see: sympify """ return sympify(a, strict=True) def kernS(s): """Use a hack to try keep autosimplification from distributing a a number into an Add; this modification doesn't prevent the 2-arg Mul from becoming an Add, however. Examples ======== >>> from sympy.core.sympify import kernS >>> from sympy.abc import x, y The 2-arg Mul distributes a number (or minus sign) across the terms of an expression, but kernS will prevent that: >>> 2*(x + y), -(x + 1) (2*x + 2*y, -x - 1) >>> kernS('2*(x + y)') 2*(x + y) >>> kernS('-(x + 1)') -(x + 1) If use of the hack fails, the un-hacked string will be passed to sympify... and you get what you get. XXX This hack should not be necessary once issue 4596 has been resolved. """ import string from random import choice from sympy.core.symbol import Symbol hit = False quoted = '"' in s or "'" in s if '(' in s and not quoted: if s.count('(') != s.count(")"): raise SympifyError('unmatched left parenthesis') # strip all space from s s = ''.join(s.split()) olds = s # now use space to represent a symbol that # will # step 1. turn potential 2-arg Muls into 3-arg versions # 1a. *( -> * *( s = s.replace('*(', '* *(') # 1b. close up exponentials s = s.replace('** *', '**') # 2. handle the implied multiplication of a negated # parenthesized expression in two steps # 2a: -(...) --> -( *(...) target = '-( *(' s = s.replace('-(', target) # 2b: double the matching closing parenthesis # -( *(...) --> -( *(...)) i = nest = 0 assert target.endswith('(') # assumption below while True: j = s.find(target, i) if j == -1: break j += len(target) - 1 for j in range(j, len(s)): if s[j] == "(": nest += 1 elif s[j] == ")": nest -= 1 if nest == 0: break s = s[:j] + ")" + s[j:] i = j + 2 # the first char after 2nd ) if ' ' in s: # get a unique kern kern = '_' while kern in s: kern += choice(string.ascii_letters + string.digits) s = s.replace(' ', kern) hit = kern in s else: hit = False for i in range(2): try: expr = sympify(s) break except TypeError: # the kern might cause unknown errors... if hit: s = olds # maybe it didn't like the kern; use un-kerned s hit = False continue expr = sympify(s) # let original error raise if not hit: return expr rep = {Symbol(kern): 1} def _clear(expr): if isinstance(expr, (list, tuple, set)): return type(expr)([_clear(e) for e in expr]) if hasattr(expr, 'subs'): return expr.subs(rep, hack2=True) return expr expr = _clear(expr) # hope that kern is not there anymore return expr # Avoid circular import from .basic import Basic sympy-sympy-1.9/sympy/core/tests/000077500000000000000000000000001412543434000171765ustar00rootroot00000000000000sympy-sympy-1.9/sympy/core/tests/__init__.py000066400000000000000000000000001412543434000212750ustar00rootroot00000000000000sympy-sympy-1.9/sympy/core/tests/test_args.py000066400000000000000000005310471412543434000215550ustar00rootroot00000000000000"""Test whether all elements of cls.args are instances of Basic. """ # NOTE: keep tests sorted by (module, class name) key. If a class can't # be instantiated, add it here anyway with @SKIP("abstract class) (see # e.g. Function). import os import re from sympy import (Basic, S, symbols, sqrt, sin, oo, Interval, exp, Lambda, pi, Eq, log, Function, Rational, Q) from sympy.testing.pytest import XFAIL, SKIP a, b, c, x, y, z = symbols('a,b,c,x,y,z') whitelist = [ "sympy.assumptions.predicates", # tested by test_predicates() "sympy.assumptions.relation.equality", # tested by test_predicates() ] def test_all_classes_are_tested(): this = os.path.split(__file__)[0] path = os.path.join(this, os.pardir, os.pardir) sympy_path = os.path.abspath(path) prefix = os.path.split(sympy_path)[0] + os.sep re_cls = re.compile(r"^class ([A-Za-z][A-Za-z0-9_]*)\s*\(", re.MULTILINE) modules = {} for root, dirs, files in os.walk(sympy_path): module = root.replace(prefix, "").replace(os.sep, ".") for file in files: if file.startswith(("_", "test_", "bench_")): continue if not file.endswith(".py"): continue with open(os.path.join(root, file), encoding='utf-8') as f: text = f.read() submodule = module + '.' + file[:-3] if any(submodule.startswith(wpath) for wpath in whitelist): continue names = re_cls.findall(text) if not names: continue try: mod = __import__(submodule, fromlist=names) except ImportError: continue def is_Basic(name): cls = getattr(mod, name) if hasattr(cls, '_sympy_deprecated_func'): cls = cls._sympy_deprecated_func if not isinstance(cls, type): # check instance of singleton class with same name cls = type(cls) return issubclass(cls, Basic) names = list(filter(is_Basic, names)) if names: modules[submodule] = names ns = globals() failed = [] for module, names in modules.items(): mod = module.replace('.', '__') for name in names: test = 'test_' + mod + '__' + name if test not in ns: failed.append(module + '.' + name) assert not failed, "Missing classes: %s. Please add tests for these to sympy/core/tests/test_args.py." % ", ".join(failed) def _test_args(obj): all_basic = all(isinstance(arg, Basic) for arg in obj.args) # Ideally obj.func(*obj.args) would always recreate the object, but for # now, we only require it for objects with non-empty .args recreatable = not obj.args or obj.func(*obj.args) == obj return all_basic and recreatable def test_sympy__assumptions__assume__AppliedPredicate(): from sympy.assumptions.assume import AppliedPredicate, Predicate assert _test_args(AppliedPredicate(Predicate("test"), 2)) assert _test_args(Q.is_true(True)) @SKIP("abstract class") def test_sympy__assumptions__assume__Predicate(): pass def test_predicates(): predicates = [ getattr(Q, attr) for attr in Q.__class__.__dict__ if not attr.startswith('__')] for p in predicates: assert _test_args(p) def test_sympy__assumptions__assume__UndefinedPredicate(): from sympy.assumptions.assume import Predicate assert _test_args(Predicate("test")) @SKIP('abstract class') def test_sympy__assumptions__relation__binrel__BinaryRelation(): pass def test_sympy__assumptions__relation__binrel__AppliedBinaryRelation(): assert _test_args(Q.eq(1, 2)) def test_sympy__assumptions__wrapper__AssumptionsWrapper(): from sympy.assumptions.wrapper import AssumptionsWrapper assert _test_args(AssumptionsWrapper(x, Q.positive(x))) @SKIP("abstract Class") def test_sympy__codegen__ast__AssignmentBase(): from sympy.codegen.ast import AssignmentBase assert _test_args(AssignmentBase(x, 1)) @SKIP("abstract Class") def test_sympy__codegen__ast__AugmentedAssignment(): from sympy.codegen.ast import AugmentedAssignment assert _test_args(AugmentedAssignment(x, 1)) def test_sympy__codegen__ast__AddAugmentedAssignment(): from sympy.codegen.ast import AddAugmentedAssignment assert _test_args(AddAugmentedAssignment(x, 1)) def test_sympy__codegen__ast__SubAugmentedAssignment(): from sympy.codegen.ast import SubAugmentedAssignment assert _test_args(SubAugmentedAssignment(x, 1)) def test_sympy__codegen__ast__MulAugmentedAssignment(): from sympy.codegen.ast import MulAugmentedAssignment assert _test_args(MulAugmentedAssignment(x, 1)) def test_sympy__codegen__ast__DivAugmentedAssignment(): from sympy.codegen.ast import DivAugmentedAssignment assert _test_args(DivAugmentedAssignment(x, 1)) def test_sympy__codegen__ast__ModAugmentedAssignment(): from sympy.codegen.ast import ModAugmentedAssignment assert _test_args(ModAugmentedAssignment(x, 1)) def test_sympy__codegen__ast__CodeBlock(): from sympy.codegen.ast import CodeBlock, Assignment assert _test_args(CodeBlock(Assignment(x, 1), Assignment(y, 2))) def test_sympy__codegen__ast__For(): from sympy.codegen.ast import For, CodeBlock, AddAugmentedAssignment from sympy import Range assert _test_args(For(x, Range(10), CodeBlock(AddAugmentedAssignment(y, 1)))) def test_sympy__codegen__ast__Token(): from sympy.codegen.ast import Token assert _test_args(Token()) def test_sympy__codegen__ast__ContinueToken(): from sympy.codegen.ast import ContinueToken assert _test_args(ContinueToken()) def test_sympy__codegen__ast__BreakToken(): from sympy.codegen.ast import BreakToken assert _test_args(BreakToken()) def test_sympy__codegen__ast__NoneToken(): from sympy.codegen.ast import NoneToken assert _test_args(NoneToken()) def test_sympy__codegen__ast__String(): from sympy.codegen.ast import String assert _test_args(String('foobar')) def test_sympy__codegen__ast__QuotedString(): from sympy.codegen.ast import QuotedString assert _test_args(QuotedString('foobar')) def test_sympy__codegen__ast__Comment(): from sympy.codegen.ast import Comment assert _test_args(Comment('this is a comment')) def test_sympy__codegen__ast__Node(): from sympy.codegen.ast import Node assert _test_args(Node()) assert _test_args(Node(attrs={1, 2, 3})) def test_sympy__codegen__ast__Type(): from sympy.codegen.ast import Type assert _test_args(Type('float128')) def test_sympy__codegen__ast__IntBaseType(): from sympy.codegen.ast import IntBaseType assert _test_args(IntBaseType('bigint')) def test_sympy__codegen__ast___SizedIntType(): from sympy.codegen.ast import _SizedIntType assert _test_args(_SizedIntType('int128', 128)) def test_sympy__codegen__ast__SignedIntType(): from sympy.codegen.ast import SignedIntType assert _test_args(SignedIntType('int128_with_sign', 128)) def test_sympy__codegen__ast__UnsignedIntType(): from sympy.codegen.ast import UnsignedIntType assert _test_args(UnsignedIntType('unt128', 128)) def test_sympy__codegen__ast__FloatBaseType(): from sympy.codegen.ast import FloatBaseType assert _test_args(FloatBaseType('positive_real')) def test_sympy__codegen__ast__FloatType(): from sympy.codegen.ast import FloatType assert _test_args(FloatType('float242', 242, nmant=142, nexp=99)) def test_sympy__codegen__ast__ComplexBaseType(): from sympy.codegen.ast import ComplexBaseType assert _test_args(ComplexBaseType('positive_cmplx')) def test_sympy__codegen__ast__ComplexType(): from sympy.codegen.ast import ComplexType assert _test_args(ComplexType('complex42', 42, nmant=15, nexp=5)) def test_sympy__codegen__ast__Attribute(): from sympy.codegen.ast import Attribute assert _test_args(Attribute('noexcept')) def test_sympy__codegen__ast__Variable(): from sympy.codegen.ast import Variable, Type, value_const assert _test_args(Variable(x)) assert _test_args(Variable(y, Type('float32'), {value_const})) assert _test_args(Variable(z, type=Type('float64'))) def test_sympy__codegen__ast__Pointer(): from sympy.codegen.ast import Pointer, Type, pointer_const assert _test_args(Pointer(x)) assert _test_args(Pointer(y, type=Type('float32'))) assert _test_args(Pointer(z, Type('float64'), {pointer_const})) def test_sympy__codegen__ast__Declaration(): from sympy.codegen.ast import Declaration, Variable, Type vx = Variable(x, type=Type('float')) assert _test_args(Declaration(vx)) def test_sympy__codegen__ast__While(): from sympy.codegen.ast import While, AddAugmentedAssignment assert _test_args(While(abs(x) < 1, [AddAugmentedAssignment(x, -1)])) def test_sympy__codegen__ast__Scope(): from sympy.codegen.ast import Scope, AddAugmentedAssignment assert _test_args(Scope([AddAugmentedAssignment(x, -1)])) def test_sympy__codegen__ast__Stream(): from sympy.codegen.ast import Stream assert _test_args(Stream('stdin')) def test_sympy__codegen__ast__Print(): from sympy.codegen.ast import Print assert _test_args(Print([x, y])) assert _test_args(Print([x, y], "%d %d")) def test_sympy__codegen__ast__FunctionPrototype(): from sympy.codegen.ast import FunctionPrototype, real, Declaration, Variable inp_x = Declaration(Variable(x, type=real)) assert _test_args(FunctionPrototype(real, 'pwer', [inp_x])) def test_sympy__codegen__ast__FunctionDefinition(): from sympy.codegen.ast import FunctionDefinition, real, Declaration, Variable, Assignment inp_x = Declaration(Variable(x, type=real)) assert _test_args(FunctionDefinition(real, 'pwer', [inp_x], [Assignment(x, x**2)])) def test_sympy__codegen__ast__Return(): from sympy.codegen.ast import Return assert _test_args(Return(x)) def test_sympy__codegen__ast__FunctionCall(): from sympy.codegen.ast import FunctionCall assert _test_args(FunctionCall('pwer', [x])) def test_sympy__codegen__ast__Element(): from sympy.codegen.ast import Element assert _test_args(Element('x', range(3))) def test_sympy__codegen__cnodes__CommaOperator(): from sympy.codegen.cnodes import CommaOperator assert _test_args(CommaOperator(1, 2)) def test_sympy__codegen__cnodes__goto(): from sympy.codegen.cnodes import goto assert _test_args(goto('early_exit')) def test_sympy__codegen__cnodes__Label(): from sympy.codegen.cnodes import Label assert _test_args(Label('early_exit')) def test_sympy__codegen__cnodes__PreDecrement(): from sympy.codegen.cnodes import PreDecrement assert _test_args(PreDecrement(x)) def test_sympy__codegen__cnodes__PostDecrement(): from sympy.codegen.cnodes import PostDecrement assert _test_args(PostDecrement(x)) def test_sympy__codegen__cnodes__PreIncrement(): from sympy.codegen.cnodes import PreIncrement assert _test_args(PreIncrement(x)) def test_sympy__codegen__cnodes__PostIncrement(): from sympy.codegen.cnodes import PostIncrement assert _test_args(PostIncrement(x)) def test_sympy__codegen__cnodes__struct(): from sympy.codegen.ast import real, Variable from sympy.codegen.cnodes import struct assert _test_args(struct(declarations=[ Variable(x, type=real), Variable(y, type=real) ])) def test_sympy__codegen__cnodes__union(): from sympy.codegen.ast import float32, int32, Variable from sympy.codegen.cnodes import union assert _test_args(union(declarations=[ Variable(x, type=float32), Variable(y, type=int32) ])) def test_sympy__codegen__cxxnodes__using(): from sympy.codegen.cxxnodes import using assert _test_args(using('std::vector')) assert _test_args(using('std::vector', 'vec')) def test_sympy__codegen__fnodes__Program(): from sympy.codegen.fnodes import Program assert _test_args(Program('foobar', [])) def test_sympy__codegen__fnodes__Module(): from sympy.codegen.fnodes import Module assert _test_args(Module('foobar', [], [])) def test_sympy__codegen__fnodes__Subroutine(): from sympy.codegen.fnodes import Subroutine x = symbols('x', real=True) assert _test_args(Subroutine('foo', [x], [])) def test_sympy__codegen__fnodes__GoTo(): from sympy.codegen.fnodes import GoTo assert _test_args(GoTo([10])) assert _test_args(GoTo([10, 20], x > 1)) def test_sympy__codegen__fnodes__FortranReturn(): from sympy.codegen.fnodes import FortranReturn assert _test_args(FortranReturn(10)) def test_sympy__codegen__fnodes__Extent(): from sympy.codegen.fnodes import Extent assert _test_args(Extent()) assert _test_args(Extent(None)) assert _test_args(Extent(':')) assert _test_args(Extent(-3, 4)) assert _test_args(Extent(x, y)) def test_sympy__codegen__fnodes__use_rename(): from sympy.codegen.fnodes import use_rename assert _test_args(use_rename('loc', 'glob')) def test_sympy__codegen__fnodes__use(): from sympy.codegen.fnodes import use assert _test_args(use('modfoo', only='bar')) def test_sympy__codegen__fnodes__SubroutineCall(): from sympy.codegen.fnodes import SubroutineCall assert _test_args(SubroutineCall('foo', ['bar', 'baz'])) def test_sympy__codegen__fnodes__Do(): from sympy.codegen.fnodes import Do assert _test_args(Do([], 'i', 1, 42)) def test_sympy__codegen__fnodes__ImpliedDoLoop(): from sympy.codegen.fnodes import ImpliedDoLoop assert _test_args(ImpliedDoLoop('i', 'i', 1, 42)) def test_sympy__codegen__fnodes__ArrayConstructor(): from sympy.codegen.fnodes import ArrayConstructor assert _test_args(ArrayConstructor([1, 2, 3])) from sympy.codegen.fnodes import ImpliedDoLoop idl = ImpliedDoLoop('i', 'i', 1, 42) assert _test_args(ArrayConstructor([1, idl, 3])) def test_sympy__codegen__fnodes__sum_(): from sympy.codegen.fnodes import sum_ assert _test_args(sum_('arr')) def test_sympy__codegen__fnodes__product_(): from sympy.codegen.fnodes import product_ assert _test_args(product_('arr')) def test_sympy__codegen__numpy_nodes__logaddexp(): from sympy.codegen.numpy_nodes import logaddexp assert _test_args(logaddexp(x, y)) def test_sympy__codegen__numpy_nodes__logaddexp2(): from sympy.codegen.numpy_nodes import logaddexp2 assert _test_args(logaddexp2(x, y)) def test_sympy__codegen__scipy_nodes__cosm1(): from sympy.codegen.scipy_nodes import cosm1 assert _test_args(cosm1(x)) @XFAIL def test_sympy__combinatorics__graycode__GrayCode(): from sympy.combinatorics.graycode import GrayCode # an integer is given and returned from GrayCode as the arg assert _test_args(GrayCode(3, start='100')) assert _test_args(GrayCode(3, rank=1)) def test_sympy__combinatorics__subsets__Subset(): from sympy.combinatorics.subsets import Subset assert _test_args(Subset([0, 1], [0, 1, 2, 3])) assert _test_args(Subset(['c', 'd'], ['a', 'b', 'c', 'd'])) def test_sympy__combinatorics__permutations__Permutation(): from sympy.combinatorics.permutations import Permutation assert _test_args(Permutation([0, 1, 2, 3])) def test_sympy__combinatorics__permutations__AppliedPermutation(): from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.permutations import AppliedPermutation p = Permutation([0, 1, 2, 3]) assert _test_args(AppliedPermutation(p, 1)) def test_sympy__combinatorics__perm_groups__PermutationGroup(): from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.perm_groups import PermutationGroup assert _test_args(PermutationGroup([Permutation([0, 1])])) def test_sympy__combinatorics__polyhedron__Polyhedron(): from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.polyhedron import Polyhedron from sympy.abc import w, x, y, z pgroup = [Permutation([[0, 1, 2], [3]]), Permutation([[0, 1, 3], [2]]), Permutation([[0, 2, 3], [1]]), Permutation([[1, 2, 3], [0]]), Permutation([[0, 1], [2, 3]]), Permutation([[0, 2], [1, 3]]), Permutation([[0, 3], [1, 2]]), Permutation([[0, 1, 2, 3]])] corners = [w, x, y, z] faces = [(w, x, y), (w, y, z), (w, z, x), (x, y, z)] assert _test_args(Polyhedron(corners, faces, pgroup)) @XFAIL def test_sympy__combinatorics__prufer__Prufer(): from sympy.combinatorics.prufer import Prufer assert _test_args(Prufer([[0, 1], [0, 2], [0, 3]], 4)) def test_sympy__combinatorics__partitions__Partition(): from sympy.combinatorics.partitions import Partition assert _test_args(Partition([1])) @XFAIL def test_sympy__combinatorics__partitions__IntegerPartition(): from sympy.combinatorics.partitions import IntegerPartition assert _test_args(IntegerPartition([1])) def test_sympy__concrete__products__Product(): from sympy.concrete.products import Product assert _test_args(Product(x, (x, 0, 10))) assert _test_args(Product(x, (x, 0, y), (y, 0, 10))) @SKIP("abstract Class") def test_sympy__concrete__expr_with_limits__ExprWithLimits(): from sympy.concrete.expr_with_limits import ExprWithLimits assert _test_args(ExprWithLimits(x, (x, 0, 10))) assert _test_args(ExprWithLimits(x*y, (x, 0, 10.),(y,1.,3))) @SKIP("abstract Class") def test_sympy__concrete__expr_with_limits__AddWithLimits(): from sympy.concrete.expr_with_limits import AddWithLimits assert _test_args(AddWithLimits(x, (x, 0, 10))) assert _test_args(AddWithLimits(x*y, (x, 0, 10),(y,1,3))) @SKIP("abstract Class") def test_sympy__concrete__expr_with_intlimits__ExprWithIntLimits(): from sympy.concrete.expr_with_intlimits import ExprWithIntLimits assert _test_args(ExprWithIntLimits(x, (x, 0, 10))) assert _test_args(ExprWithIntLimits(x*y, (x, 0, 10),(y,1,3))) def test_sympy__concrete__summations__Sum(): from sympy.concrete.summations import Sum assert _test_args(Sum(x, (x, 0, 10))) assert _test_args(Sum(x, (x, 0, y), (y, 0, 10))) def test_sympy__core__add__Add(): from sympy.core.add import Add assert _test_args(Add(x, y, z, 2)) def test_sympy__core__basic__Atom(): from sympy.core.basic import Atom assert _test_args(Atom()) def test_sympy__core__basic__Basic(): from sympy.core.basic import Basic assert _test_args(Basic()) def test_sympy__core__containers__Dict(): from sympy.core.containers import Dict assert _test_args(Dict({x: y, y: z})) def test_sympy__core__containers__Tuple(): from sympy.core.containers import Tuple assert _test_args(Tuple(x, y, z, 2)) def test_sympy__core__expr__AtomicExpr(): from sympy.core.expr import AtomicExpr assert _test_args(AtomicExpr()) def test_sympy__core__expr__Expr(): from sympy.core.expr import Expr assert _test_args(Expr()) def test_sympy__core__expr__UnevaluatedExpr(): from sympy.core.expr import UnevaluatedExpr from sympy.abc import x assert _test_args(UnevaluatedExpr(x)) def test_sympy__core__function__Application(): from sympy.core.function import Application assert _test_args(Application(1, 2, 3)) def test_sympy__core__function__AppliedUndef(): from sympy.core.function import AppliedUndef assert _test_args(AppliedUndef(1, 2, 3)) def test_sympy__core__function__Derivative(): from sympy.core.function import Derivative assert _test_args(Derivative(2, x, y, 3)) @SKIP("abstract class") def test_sympy__core__function__Function(): pass def test_sympy__core__function__Lambda(): assert _test_args(Lambda((x, y), x + y + z)) def test_sympy__core__function__Subs(): from sympy.core.function import Subs assert _test_args(Subs(x + y, x, 2)) def test_sympy__core__function__WildFunction(): from sympy.core.function import WildFunction assert _test_args(WildFunction('f')) def test_sympy__core__mod__Mod(): from sympy.core.mod import Mod assert _test_args(Mod(x, 2)) def test_sympy__core__mul__Mul(): from sympy.core.mul import Mul assert _test_args(Mul(2, x, y, z)) def test_sympy__core__numbers__Catalan(): from sympy.core.numbers import Catalan assert _test_args(Catalan()) def test_sympy__core__numbers__ComplexInfinity(): from sympy.core.numbers import ComplexInfinity assert _test_args(ComplexInfinity()) def test_sympy__core__numbers__EulerGamma(): from sympy.core.numbers import EulerGamma assert _test_args(EulerGamma()) def test_sympy__core__numbers__Exp1(): from sympy.core.numbers import Exp1 assert _test_args(Exp1()) def test_sympy__core__numbers__Float(): from sympy.core.numbers import Float assert _test_args(Float(1.23)) def test_sympy__core__numbers__GoldenRatio(): from sympy.core.numbers import GoldenRatio assert _test_args(GoldenRatio()) def test_sympy__core__numbers__TribonacciConstant(): from sympy.core.numbers import TribonacciConstant assert _test_args(TribonacciConstant()) def test_sympy__core__numbers__Half(): from sympy.core.numbers import Half assert _test_args(Half()) def test_sympy__core__numbers__ImaginaryUnit(): from sympy.core.numbers import ImaginaryUnit assert _test_args(ImaginaryUnit()) def test_sympy__core__numbers__Infinity(): from sympy.core.numbers import Infinity assert _test_args(Infinity()) def test_sympy__core__numbers__Integer(): from sympy.core.numbers import Integer assert _test_args(Integer(7)) @SKIP("abstract class") def test_sympy__core__numbers__IntegerConstant(): pass def test_sympy__core__numbers__NaN(): from sympy.core.numbers import NaN assert _test_args(NaN()) def test_sympy__core__numbers__NegativeInfinity(): from sympy.core.numbers import NegativeInfinity assert _test_args(NegativeInfinity()) def test_sympy__core__numbers__NegativeOne(): from sympy.core.numbers import NegativeOne assert _test_args(NegativeOne()) def test_sympy__core__numbers__Number(): from sympy.core.numbers import Number assert _test_args(Number(1, 7)) def test_sympy__core__numbers__NumberSymbol(): from sympy.core.numbers import NumberSymbol assert _test_args(NumberSymbol()) def test_sympy__core__numbers__One(): from sympy.core.numbers import One assert _test_args(One()) def test_sympy__core__numbers__Pi(): from sympy.core.numbers import Pi assert _test_args(Pi()) def test_sympy__core__numbers__Rational(): from sympy.core.numbers import Rational assert _test_args(Rational(1, 7)) @SKIP("abstract class") def test_sympy__core__numbers__RationalConstant(): pass def test_sympy__core__numbers__Zero(): from sympy.core.numbers import Zero assert _test_args(Zero()) @SKIP("abstract class") def test_sympy__core__operations__AssocOp(): pass @SKIP("abstract class") def test_sympy__core__operations__LatticeOp(): pass def test_sympy__core__power__Pow(): from sympy.core.power import Pow assert _test_args(Pow(x, 2)) def test_sympy__algebras__quaternion__Quaternion(): from sympy.algebras.quaternion import Quaternion assert _test_args(Quaternion(x, 1, 2, 3)) def test_sympy__core__relational__Equality(): from sympy.core.relational import Equality assert _test_args(Equality(x, 2)) def test_sympy__core__relational__GreaterThan(): from sympy.core.relational import GreaterThan assert _test_args(GreaterThan(x, 2)) def test_sympy__core__relational__LessThan(): from sympy.core.relational import LessThan assert _test_args(LessThan(x, 2)) @SKIP("abstract class") def test_sympy__core__relational__Relational(): pass def test_sympy__core__relational__StrictGreaterThan(): from sympy.core.relational import StrictGreaterThan assert _test_args(StrictGreaterThan(x, 2)) def test_sympy__core__relational__StrictLessThan(): from sympy.core.relational import StrictLessThan assert _test_args(StrictLessThan(x, 2)) def test_sympy__core__relational__Unequality(): from sympy.core.relational import Unequality assert _test_args(Unequality(x, 2)) def test_sympy__sandbox__indexed_integrals__IndexedIntegral(): from sympy.tensor import IndexedBase, Idx from sympy.sandbox.indexed_integrals import IndexedIntegral A = IndexedBase('A') i, j = symbols('i j', integer=True) a1, a2 = symbols('a1:3', cls=Idx) assert _test_args(IndexedIntegral(A[a1], A[a2])) assert _test_args(IndexedIntegral(A[i], A[j])) def test_sympy__calculus__util__AccumulationBounds(): from sympy.calculus.util import AccumulationBounds assert _test_args(AccumulationBounds(0, 1)) def test_sympy__sets__ordinals__OmegaPower(): from sympy.sets.ordinals import OmegaPower assert _test_args(OmegaPower(1, 1)) def test_sympy__sets__ordinals__Ordinal(): from sympy.sets.ordinals import Ordinal, OmegaPower assert _test_args(Ordinal(OmegaPower(2, 1))) def test_sympy__sets__ordinals__OrdinalOmega(): from sympy.sets.ordinals import OrdinalOmega assert _test_args(OrdinalOmega()) def test_sympy__sets__ordinals__OrdinalZero(): from sympy.sets.ordinals import OrdinalZero assert _test_args(OrdinalZero()) def test_sympy__sets__powerset__PowerSet(): from sympy.sets.powerset import PowerSet from sympy.core.singleton import S assert _test_args(PowerSet(S.EmptySet)) def test_sympy__sets__sets__EmptySet(): from sympy.sets.sets import EmptySet assert _test_args(EmptySet()) def test_sympy__sets__sets__UniversalSet(): from sympy.sets.sets import UniversalSet assert _test_args(UniversalSet()) def test_sympy__sets__sets__FiniteSet(): from sympy.sets.sets import FiniteSet assert _test_args(FiniteSet(x, y, z)) def test_sympy__sets__sets__Interval(): from sympy.sets.sets import Interval assert _test_args(Interval(0, 1)) def test_sympy__sets__sets__ProductSet(): from sympy.sets.sets import ProductSet, Interval assert _test_args(ProductSet(Interval(0, 1), Interval(0, 1))) @SKIP("does it make sense to test this?") def test_sympy__sets__sets__Set(): from sympy.sets.sets import Set assert _test_args(Set()) def test_sympy__sets__sets__Intersection(): from sympy.sets.sets import Intersection, Interval from sympy.core.symbol import Symbol x = Symbol('x') y = Symbol('y') S = Intersection(Interval(0, x), Interval(y, 1)) assert isinstance(S, Intersection) assert _test_args(S) def test_sympy__sets__sets__Union(): from sympy.sets.sets import Union, Interval assert _test_args(Union(Interval(0, 1), Interval(2, 3))) def test_sympy__sets__sets__Complement(): from sympy.sets.sets import Complement assert _test_args(Complement(Interval(0, 2), Interval(0, 1))) def test_sympy__sets__sets__SymmetricDifference(): from sympy.sets.sets import FiniteSet, SymmetricDifference assert _test_args(SymmetricDifference(FiniteSet(1, 2, 3), \ FiniteSet(2, 3, 4))) def test_sympy__sets__sets__DisjointUnion(): from sympy.sets.sets import FiniteSet, DisjointUnion assert _test_args(DisjointUnion(FiniteSet(1, 2, 3), \ FiniteSet(2, 3, 4))) def test_sympy__core__trace__Tr(): from sympy.core.trace import Tr a, b = symbols('a b') assert _test_args(Tr(a + b)) def test_sympy__sets__setexpr__SetExpr(): from sympy.sets.setexpr import SetExpr assert _test_args(SetExpr(Interval(0, 1))) def test_sympy__sets__fancysets__Rationals(): from sympy.sets.fancysets import Rationals assert _test_args(Rationals()) def test_sympy__sets__fancysets__Naturals(): from sympy.sets.fancysets import Naturals assert _test_args(Naturals()) def test_sympy__sets__fancysets__Naturals0(): from sympy.sets.fancysets import Naturals0 assert _test_args(Naturals0()) def test_sympy__sets__fancysets__Integers(): from sympy.sets.fancysets import Integers assert _test_args(Integers()) def test_sympy__sets__fancysets__Reals(): from sympy.sets.fancysets import Reals assert _test_args(Reals()) def test_sympy__sets__fancysets__Complexes(): from sympy.sets.fancysets import Complexes assert _test_args(Complexes()) def test_sympy__sets__fancysets__ComplexRegion(): from sympy.sets.fancysets import ComplexRegion from sympy import S from sympy.sets import Interval a = Interval(0, 1) b = Interval(2, 3) theta = Interval(0, 2*S.Pi) assert _test_args(ComplexRegion(a*b)) assert _test_args(ComplexRegion(a*theta, polar=True)) def test_sympy__sets__fancysets__CartesianComplexRegion(): from sympy.sets.fancysets import CartesianComplexRegion from sympy.sets import Interval a = Interval(0, 1) b = Interval(2, 3) assert _test_args(CartesianComplexRegion(a*b)) def test_sympy__sets__fancysets__PolarComplexRegion(): from sympy.sets.fancysets import PolarComplexRegion from sympy import S from sympy.sets import Interval a = Interval(0, 1) theta = Interval(0, 2*S.Pi) assert _test_args(PolarComplexRegion(a*theta)) def test_sympy__sets__fancysets__ImageSet(): from sympy.sets.fancysets import ImageSet from sympy import S, Symbol x = Symbol('x') assert _test_args(ImageSet(Lambda(x, x**2), S.Naturals)) def test_sympy__sets__fancysets__Range(): from sympy.sets.fancysets import Range assert _test_args(Range(1, 5, 1)) def test_sympy__sets__conditionset__ConditionSet(): from sympy.sets.conditionset import ConditionSet from sympy import S, Symbol x = Symbol('x') assert _test_args(ConditionSet(x, Eq(x**2, 1), S.Reals)) def test_sympy__sets__contains__Contains(): from sympy.sets.fancysets import Range from sympy.sets.contains import Contains assert _test_args(Contains(x, Range(0, 10, 2))) # STATS from sympy.stats.crv_types import NormalDistribution nd = NormalDistribution(0, 1) from sympy.stats.frv_types import DieDistribution die = DieDistribution(6) def test_sympy__stats__crv__ContinuousDomain(): from sympy.stats.crv import ContinuousDomain assert _test_args(ContinuousDomain({x}, Interval(-oo, oo))) def test_sympy__stats__crv__SingleContinuousDomain(): from sympy.stats.crv import SingleContinuousDomain assert _test_args(SingleContinuousDomain(x, Interval(-oo, oo))) def test_sympy__stats__crv__ProductContinuousDomain(): from sympy.stats.crv import SingleContinuousDomain, ProductContinuousDomain D = SingleContinuousDomain(x, Interval(-oo, oo)) E = SingleContinuousDomain(y, Interval(0, oo)) assert _test_args(ProductContinuousDomain(D, E)) def test_sympy__stats__crv__ConditionalContinuousDomain(): from sympy.stats.crv import (SingleContinuousDomain, ConditionalContinuousDomain) D = SingleContinuousDomain(x, Interval(-oo, oo)) assert _test_args(ConditionalContinuousDomain(D, x > 0)) def test_sympy__stats__crv__ContinuousPSpace(): from sympy.stats.crv import ContinuousPSpace, SingleContinuousDomain D = SingleContinuousDomain(x, Interval(-oo, oo)) assert _test_args(ContinuousPSpace(D, nd)) def test_sympy__stats__crv__SingleContinuousPSpace(): from sympy.stats.crv import SingleContinuousPSpace assert _test_args(SingleContinuousPSpace(x, nd)) @SKIP("abstract class") def test_sympy__stats__rv__Distribution(): pass @SKIP("abstract class") def test_sympy__stats__crv__SingleContinuousDistribution(): pass def test_sympy__stats__drv__SingleDiscreteDomain(): from sympy.stats.drv import SingleDiscreteDomain assert _test_args(SingleDiscreteDomain(x, S.Naturals)) def test_sympy__stats__drv__ProductDiscreteDomain(): from sympy.stats.drv import SingleDiscreteDomain, ProductDiscreteDomain X = SingleDiscreteDomain(x, S.Naturals) Y = SingleDiscreteDomain(y, S.Integers) assert _test_args(ProductDiscreteDomain(X, Y)) def test_sympy__stats__drv__SingleDiscretePSpace(): from sympy.stats.drv import SingleDiscretePSpace from sympy.stats.drv_types import PoissonDistribution assert _test_args(SingleDiscretePSpace(x, PoissonDistribution(1))) def test_sympy__stats__drv__DiscretePSpace(): from sympy.stats.drv import DiscretePSpace, SingleDiscreteDomain density = Lambda(x, 2**(-x)) domain = SingleDiscreteDomain(x, S.Naturals) assert _test_args(DiscretePSpace(domain, density)) def test_sympy__stats__drv__ConditionalDiscreteDomain(): from sympy.stats.drv import ConditionalDiscreteDomain, SingleDiscreteDomain X = SingleDiscreteDomain(x, S.Naturals0) assert _test_args(ConditionalDiscreteDomain(X, x > 2)) def test_sympy__stats__joint_rv__JointPSpace(): from sympy.stats.joint_rv import JointPSpace, JointDistribution assert _test_args(JointPSpace('X', JointDistribution(1))) def test_sympy__stats__joint_rv__JointRandomSymbol(): from sympy.stats.joint_rv import JointRandomSymbol assert _test_args(JointRandomSymbol(x)) def test_sympy__stats__joint_rv_types__JointDistributionHandmade(): from sympy import Indexed from sympy.stats.joint_rv_types import JointDistributionHandmade x1, x2 = (Indexed('x', i) for i in (1, 2)) assert _test_args(JointDistributionHandmade(x1 + x2, S.Reals**2)) def test_sympy__stats__joint_rv__MarginalDistribution(): from sympy.stats.rv import RandomSymbol from sympy.stats.joint_rv import MarginalDistribution r = RandomSymbol(S('r')) assert _test_args(MarginalDistribution(r, (r,))) def test_sympy__stats__compound_rv__CompoundDistribution(): from sympy.stats.compound_rv import CompoundDistribution from sympy.stats.drv_types import PoissonDistribution, Poisson r = Poisson('r', 10) assert _test_args(CompoundDistribution(PoissonDistribution(r))) def test_sympy__stats__compound_rv__CompoundPSpace(): from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution from sympy.stats.drv_types import PoissonDistribution, Poisson r = Poisson('r', 5) C = CompoundDistribution(PoissonDistribution(r)) assert _test_args(CompoundPSpace('C', C)) @SKIP("abstract class") def test_sympy__stats__drv__SingleDiscreteDistribution(): pass @SKIP("abstract class") def test_sympy__stats__drv__DiscreteDistribution(): pass @SKIP("abstract class") def test_sympy__stats__drv__DiscreteDomain(): pass def test_sympy__stats__rv__RandomDomain(): from sympy.stats.rv import RandomDomain from sympy.sets.sets import FiniteSet assert _test_args(RandomDomain(FiniteSet(x), FiniteSet(1, 2, 3))) def test_sympy__stats__rv__SingleDomain(): from sympy.stats.rv import SingleDomain from sympy.sets.sets import FiniteSet assert _test_args(SingleDomain(x, FiniteSet(1, 2, 3))) def test_sympy__stats__rv__ConditionalDomain(): from sympy.stats.rv import ConditionalDomain, RandomDomain from sympy.sets.sets import FiniteSet D = RandomDomain(FiniteSet(x), FiniteSet(1, 2)) assert _test_args(ConditionalDomain(D, x > 1)) def test_sympy__stats__rv__MatrixDomain(): from sympy.stats.rv import MatrixDomain from sympy.matrices import MatrixSet from sympy import S assert _test_args(MatrixDomain(x, MatrixSet(2, 2, S.Reals))) def test_sympy__stats__rv__PSpace(): from sympy.stats.rv import PSpace, RandomDomain from sympy import FiniteSet D = RandomDomain(FiniteSet(x), FiniteSet(1, 2, 3, 4, 5, 6)) assert _test_args(PSpace(D, die)) @SKIP("abstract Class") def test_sympy__stats__rv__SinglePSpace(): pass def test_sympy__stats__rv__RandomSymbol(): from sympy.stats.rv import RandomSymbol from sympy.stats.crv import SingleContinuousPSpace A = SingleContinuousPSpace(x, nd) assert _test_args(RandomSymbol(x, A)) @SKIP("abstract Class") def test_sympy__stats__rv__ProductPSpace(): pass def test_sympy__stats__rv__IndependentProductPSpace(): from sympy.stats.rv import IndependentProductPSpace from sympy.stats.crv import SingleContinuousPSpace A = SingleContinuousPSpace(x, nd) B = SingleContinuousPSpace(y, nd) assert _test_args(IndependentProductPSpace(A, B)) def test_sympy__stats__rv__ProductDomain(): from sympy.stats.rv import ProductDomain, SingleDomain D = SingleDomain(x, Interval(-oo, oo)) E = SingleDomain(y, Interval(0, oo)) assert _test_args(ProductDomain(D, E)) def test_sympy__stats__symbolic_probability__Probability(): from sympy.stats.symbolic_probability import Probability from sympy.stats import Normal X = Normal('X', 0, 1) assert _test_args(Probability(X > 0)) def test_sympy__stats__symbolic_probability__Expectation(): from sympy.stats.symbolic_probability import Expectation from sympy.stats import Normal X = Normal('X', 0, 1) assert _test_args(Expectation(X > 0)) def test_sympy__stats__symbolic_probability__Covariance(): from sympy.stats.symbolic_probability import Covariance from sympy.stats import Normal X = Normal('X', 0, 1) Y = Normal('Y', 0, 3) assert _test_args(Covariance(X, Y)) def test_sympy__stats__symbolic_probability__Variance(): from sympy.stats.symbolic_probability import Variance from sympy.stats import Normal X = Normal('X', 0, 1) assert _test_args(Variance(X)) def test_sympy__stats__symbolic_probability__Moment(): from sympy.stats.symbolic_probability import Moment from sympy.stats import Normal X = Normal('X', 0, 1) assert _test_args(Moment(X, 3, 2, X > 3)) def test_sympy__stats__symbolic_probability__CentralMoment(): from sympy.stats.symbolic_probability import CentralMoment from sympy.stats import Normal X = Normal('X', 0, 1) assert _test_args(CentralMoment(X, 2, X > 1)) def test_sympy__stats__frv_types__DiscreteUniformDistribution(): from sympy.stats.frv_types import DiscreteUniformDistribution from sympy.core.containers import Tuple assert _test_args(DiscreteUniformDistribution(Tuple(*list(range(6))))) def test_sympy__stats__frv_types__DieDistribution(): assert _test_args(die) def test_sympy__stats__frv_types__BernoulliDistribution(): from sympy.stats.frv_types import BernoulliDistribution assert _test_args(BernoulliDistribution(S.Half, 0, 1)) def test_sympy__stats__frv_types__BinomialDistribution(): from sympy.stats.frv_types import BinomialDistribution assert _test_args(BinomialDistribution(5, S.Half, 1, 0)) def test_sympy__stats__frv_types__BetaBinomialDistribution(): from sympy.stats.frv_types import BetaBinomialDistribution assert _test_args(BetaBinomialDistribution(5, 1, 1)) def test_sympy__stats__frv_types__HypergeometricDistribution(): from sympy.stats.frv_types import HypergeometricDistribution assert _test_args(HypergeometricDistribution(10, 5, 3)) def test_sympy__stats__frv_types__RademacherDistribution(): from sympy.stats.frv_types import RademacherDistribution assert _test_args(RademacherDistribution()) def test_sympy__stats__frv_types__IdealSolitonDistribution(): from sympy.stats.frv_types import IdealSolitonDistribution assert _test_args(IdealSolitonDistribution(10)) def test_sympy__stats__frv_types__RobustSolitonDistribution(): from sympy.stats.frv_types import RobustSolitonDistribution assert _test_args(RobustSolitonDistribution(1000, 0.5, 0.1)) def test_sympy__stats__frv__FiniteDomain(): from sympy.stats.frv import FiniteDomain assert _test_args(FiniteDomain({(x, 1), (x, 2)})) # x can be 1 or 2 def test_sympy__stats__frv__SingleFiniteDomain(): from sympy.stats.frv import SingleFiniteDomain assert _test_args(SingleFiniteDomain(x, {1, 2})) # x can be 1 or 2 def test_sympy__stats__frv__ProductFiniteDomain(): from sympy.stats.frv import SingleFiniteDomain, ProductFiniteDomain xd = SingleFiniteDomain(x, {1, 2}) yd = SingleFiniteDomain(y, {1, 2}) assert _test_args(ProductFiniteDomain(xd, yd)) def test_sympy__stats__frv__ConditionalFiniteDomain(): from sympy.stats.frv import SingleFiniteDomain, ConditionalFiniteDomain xd = SingleFiniteDomain(x, {1, 2}) assert _test_args(ConditionalFiniteDomain(xd, x > 1)) def test_sympy__stats__frv__FinitePSpace(): from sympy.stats.frv import FinitePSpace, SingleFiniteDomain xd = SingleFiniteDomain(x, {1, 2, 3, 4, 5, 6}) assert _test_args(FinitePSpace(xd, {(x, 1): S.Half, (x, 2): S.Half})) xd = SingleFiniteDomain(x, {1, 2}) assert _test_args(FinitePSpace(xd, {(x, 1): S.Half, (x, 2): S.Half})) def test_sympy__stats__frv__SingleFinitePSpace(): from sympy.stats.frv import SingleFinitePSpace from sympy import Symbol assert _test_args(SingleFinitePSpace(Symbol('x'), die)) def test_sympy__stats__frv__ProductFinitePSpace(): from sympy.stats.frv import SingleFinitePSpace, ProductFinitePSpace from sympy import Symbol xp = SingleFinitePSpace(Symbol('x'), die) yp = SingleFinitePSpace(Symbol('y'), die) assert _test_args(ProductFinitePSpace(xp, yp)) @SKIP("abstract class") def test_sympy__stats__frv__SingleFiniteDistribution(): pass @SKIP("abstract class") def test_sympy__stats__crv__ContinuousDistribution(): pass def test_sympy__stats__frv_types__FiniteDistributionHandmade(): from sympy.stats.frv_types import FiniteDistributionHandmade from sympy import Dict assert _test_args(FiniteDistributionHandmade(Dict({1: 1}))) def test_sympy__stats__crv_types__ContinuousDistributionHandmade(): from sympy.stats.crv_types import ContinuousDistributionHandmade from sympy import Interval, Lambda from sympy.abc import x assert _test_args(ContinuousDistributionHandmade(Lambda(x, 2*x), Interval(0, 1))) def test_sympy__stats__drv_types__DiscreteDistributionHandmade(): from sympy.stats.drv_types import DiscreteDistributionHandmade from sympy import Lambda, FiniteSet from sympy.abc import x assert _test_args(DiscreteDistributionHandmade(Lambda(x, Rational(1, 10)), FiniteSet(*range(10)))) def test_sympy__stats__rv__Density(): from sympy.stats.rv import Density from sympy.stats.crv_types import Normal assert _test_args(Density(Normal('x', 0, 1))) def test_sympy__stats__crv_types__ArcsinDistribution(): from sympy.stats.crv_types import ArcsinDistribution assert _test_args(ArcsinDistribution(0, 1)) def test_sympy__stats__crv_types__BeniniDistribution(): from sympy.stats.crv_types import BeniniDistribution assert _test_args(BeniniDistribution(1, 1, 1)) def test_sympy__stats__crv_types__BetaDistribution(): from sympy.stats.crv_types import BetaDistribution assert _test_args(BetaDistribution(1, 1)) def test_sympy__stats__crv_types__BetaNoncentralDistribution(): from sympy.stats.crv_types import BetaNoncentralDistribution assert _test_args(BetaNoncentralDistribution(1, 1, 1)) def test_sympy__stats__crv_types__BetaPrimeDistribution(): from sympy.stats.crv_types import BetaPrimeDistribution assert _test_args(BetaPrimeDistribution(1, 1)) def test_sympy__stats__crv_types__BoundedParetoDistribution(): from sympy.stats.crv_types import BoundedParetoDistribution assert _test_args(BoundedParetoDistribution(1, 1, 2)) def test_sympy__stats__crv_types__CauchyDistribution(): from sympy.stats.crv_types import CauchyDistribution assert _test_args(CauchyDistribution(0, 1)) def test_sympy__stats__crv_types__ChiDistribution(): from sympy.stats.crv_types import ChiDistribution assert _test_args(ChiDistribution(1)) def test_sympy__stats__crv_types__ChiNoncentralDistribution(): from sympy.stats.crv_types import ChiNoncentralDistribution assert _test_args(ChiNoncentralDistribution(1,1)) def test_sympy__stats__crv_types__ChiSquaredDistribution(): from sympy.stats.crv_types import ChiSquaredDistribution assert _test_args(ChiSquaredDistribution(1)) def test_sympy__stats__crv_types__DagumDistribution(): from sympy.stats.crv_types import DagumDistribution assert _test_args(DagumDistribution(1, 1, 1)) def test_sympy__stats__crv_types__ExGaussianDistribution(): from sympy.stats.crv_types import ExGaussianDistribution assert _test_args(ExGaussianDistribution(1, 1, 1)) def test_sympy__stats__crv_types__ExponentialDistribution(): from sympy.stats.crv_types import ExponentialDistribution assert _test_args(ExponentialDistribution(1)) def test_sympy__stats__crv_types__ExponentialPowerDistribution(): from sympy.stats.crv_types import ExponentialPowerDistribution assert _test_args(ExponentialPowerDistribution(0, 1, 1)) def test_sympy__stats__crv_types__FDistributionDistribution(): from sympy.stats.crv_types import FDistributionDistribution assert _test_args(FDistributionDistribution(1, 1)) def test_sympy__stats__crv_types__FisherZDistribution(): from sympy.stats.crv_types import FisherZDistribution assert _test_args(FisherZDistribution(1, 1)) def test_sympy__stats__crv_types__FrechetDistribution(): from sympy.stats.crv_types import FrechetDistribution assert _test_args(FrechetDistribution(1, 1, 1)) def test_sympy__stats__crv_types__GammaInverseDistribution(): from sympy.stats.crv_types import GammaInverseDistribution assert _test_args(GammaInverseDistribution(1, 1)) def test_sympy__stats__crv_types__GammaDistribution(): from sympy.stats.crv_types import GammaDistribution assert _test_args(GammaDistribution(1, 1)) def test_sympy__stats__crv_types__GumbelDistribution(): from sympy.stats.crv_types import GumbelDistribution assert _test_args(GumbelDistribution(1, 1, False)) def test_sympy__stats__crv_types__GompertzDistribution(): from sympy.stats.crv_types import GompertzDistribution assert _test_args(GompertzDistribution(1, 1)) def test_sympy__stats__crv_types__KumaraswamyDistribution(): from sympy.stats.crv_types import KumaraswamyDistribution assert _test_args(KumaraswamyDistribution(1, 1)) def test_sympy__stats__crv_types__LaplaceDistribution(): from sympy.stats.crv_types import LaplaceDistribution assert _test_args(LaplaceDistribution(0, 1)) def test_sympy__stats__crv_types__LevyDistribution(): from sympy.stats.crv_types import LevyDistribution assert _test_args(LevyDistribution(0, 1)) def test_sympy__stats__crv_types__LogCauchyDistribution(): from sympy.stats.crv_types import LogCauchyDistribution assert _test_args(LogCauchyDistribution(0, 1)) def test_sympy__stats__crv_types__LogisticDistribution(): from sympy.stats.crv_types import LogisticDistribution assert _test_args(LogisticDistribution(0, 1)) def test_sympy__stats__crv_types__LogLogisticDistribution(): from sympy.stats.crv_types import LogLogisticDistribution assert _test_args(LogLogisticDistribution(1, 1)) def test_sympy__stats__crv_types__LogitNormalDistribution(): from sympy.stats.crv_types import LogitNormalDistribution assert _test_args(LogitNormalDistribution(0, 1)) def test_sympy__stats__crv_types__LogNormalDistribution(): from sympy.stats.crv_types import LogNormalDistribution assert _test_args(LogNormalDistribution(0, 1)) def test_sympy__stats__crv_types__LomaxDistribution(): from sympy.stats.crv_types import LomaxDistribution assert _test_args(LomaxDistribution(1, 2)) def test_sympy__stats__crv_types__MaxwellDistribution(): from sympy.stats.crv_types import MaxwellDistribution assert _test_args(MaxwellDistribution(1)) def test_sympy__stats__crv_types__MoyalDistribution(): from sympy.stats.crv_types import MoyalDistribution assert _test_args(MoyalDistribution(1,2)) def test_sympy__stats__crv_types__NakagamiDistribution(): from sympy.stats.crv_types import NakagamiDistribution assert _test_args(NakagamiDistribution(1, 1)) def test_sympy__stats__crv_types__NormalDistribution(): from sympy.stats.crv_types import NormalDistribution assert _test_args(NormalDistribution(0, 1)) def test_sympy__stats__crv_types__GaussianInverseDistribution(): from sympy.stats.crv_types import GaussianInverseDistribution assert _test_args(GaussianInverseDistribution(1, 1)) def test_sympy__stats__crv_types__ParetoDistribution(): from sympy.stats.crv_types import ParetoDistribution assert _test_args(ParetoDistribution(1, 1)) def test_sympy__stats__crv_types__PowerFunctionDistribution(): from sympy.stats.crv_types import PowerFunctionDistribution assert _test_args(PowerFunctionDistribution(2,0,1)) def test_sympy__stats__crv_types__QuadraticUDistribution(): from sympy.stats.crv_types import QuadraticUDistribution assert _test_args(QuadraticUDistribution(1, 2)) def test_sympy__stats__crv_types__RaisedCosineDistribution(): from sympy.stats.crv_types import RaisedCosineDistribution assert _test_args(RaisedCosineDistribution(1, 1)) def test_sympy__stats__crv_types__RayleighDistribution(): from sympy.stats.crv_types import RayleighDistribution assert _test_args(RayleighDistribution(1)) def test_sympy__stats__crv_types__ReciprocalDistribution(): from sympy.stats.crv_types import ReciprocalDistribution assert _test_args(ReciprocalDistribution(5, 30)) def test_sympy__stats__crv_types__ShiftedGompertzDistribution(): from sympy.stats.crv_types import ShiftedGompertzDistribution assert _test_args(ShiftedGompertzDistribution(1, 1)) def test_sympy__stats__crv_types__StudentTDistribution(): from sympy.stats.crv_types import StudentTDistribution assert _test_args(StudentTDistribution(1)) def test_sympy__stats__crv_types__TrapezoidalDistribution(): from sympy.stats.crv_types import TrapezoidalDistribution assert _test_args(TrapezoidalDistribution(1, 2, 3, 4)) def test_sympy__stats__crv_types__TriangularDistribution(): from sympy.stats.crv_types import TriangularDistribution assert _test_args(TriangularDistribution(-1, 0, 1)) def test_sympy__stats__crv_types__UniformDistribution(): from sympy.stats.crv_types import UniformDistribution assert _test_args(UniformDistribution(0, 1)) def test_sympy__stats__crv_types__UniformSumDistribution(): from sympy.stats.crv_types import UniformSumDistribution assert _test_args(UniformSumDistribution(1)) def test_sympy__stats__crv_types__VonMisesDistribution(): from sympy.stats.crv_types import VonMisesDistribution assert _test_args(VonMisesDistribution(1, 1)) def test_sympy__stats__crv_types__WeibullDistribution(): from sympy.stats.crv_types import WeibullDistribution assert _test_args(WeibullDistribution(1, 1)) def test_sympy__stats__crv_types__WignerSemicircleDistribution(): from sympy.stats.crv_types import WignerSemicircleDistribution assert _test_args(WignerSemicircleDistribution(1)) def test_sympy__stats__drv_types__GeometricDistribution(): from sympy.stats.drv_types import GeometricDistribution assert _test_args(GeometricDistribution(.5)) def test_sympy__stats__drv_types__HermiteDistribution(): from sympy.stats.drv_types import HermiteDistribution assert _test_args(HermiteDistribution(1, 2)) def test_sympy__stats__drv_types__LogarithmicDistribution(): from sympy.stats.drv_types import LogarithmicDistribution assert _test_args(LogarithmicDistribution(.5)) def test_sympy__stats__drv_types__NegativeBinomialDistribution(): from sympy.stats.drv_types import NegativeBinomialDistribution assert _test_args(NegativeBinomialDistribution(.5, .5)) def test_sympy__stats__drv_types__FlorySchulzDistribution(): from sympy.stats.drv_types import FlorySchulzDistribution assert _test_args(FlorySchulzDistribution(.5)) def test_sympy__stats__drv_types__PoissonDistribution(): from sympy.stats.drv_types import PoissonDistribution assert _test_args(PoissonDistribution(1)) def test_sympy__stats__drv_types__SkellamDistribution(): from sympy.stats.drv_types import SkellamDistribution assert _test_args(SkellamDistribution(1, 1)) def test_sympy__stats__drv_types__YuleSimonDistribution(): from sympy.stats.drv_types import YuleSimonDistribution assert _test_args(YuleSimonDistribution(.5)) def test_sympy__stats__drv_types__ZetaDistribution(): from sympy.stats.drv_types import ZetaDistribution assert _test_args(ZetaDistribution(1.5)) def test_sympy__stats__joint_rv__JointDistribution(): from sympy.stats.joint_rv import JointDistribution assert _test_args(JointDistribution(1, 2, 3, 4)) def test_sympy__stats__joint_rv_types__MultivariateNormalDistribution(): from sympy.stats.joint_rv_types import MultivariateNormalDistribution assert _test_args( MultivariateNormalDistribution([0, 1], [[1, 0],[0, 1]])) def test_sympy__stats__joint_rv_types__MultivariateLaplaceDistribution(): from sympy.stats.joint_rv_types import MultivariateLaplaceDistribution assert _test_args(MultivariateLaplaceDistribution([0, 1], [[1, 0],[0, 1]])) def test_sympy__stats__joint_rv_types__MultivariateTDistribution(): from sympy.stats.joint_rv_types import MultivariateTDistribution assert _test_args(MultivariateTDistribution([0, 1], [[1, 0],[0, 1]], 1)) def test_sympy__stats__joint_rv_types__NormalGammaDistribution(): from sympy.stats.joint_rv_types import NormalGammaDistribution assert _test_args(NormalGammaDistribution(1, 2, 3, 4)) def test_sympy__stats__joint_rv_types__GeneralizedMultivariateLogGammaDistribution(): from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGammaDistribution v, l, mu = (4, [1, 2, 3, 4], [1, 2, 3, 4]) assert _test_args(GeneralizedMultivariateLogGammaDistribution(S.Half, v, l, mu)) def test_sympy__stats__joint_rv_types__MultivariateBetaDistribution(): from sympy.stats.joint_rv_types import MultivariateBetaDistribution assert _test_args(MultivariateBetaDistribution([1, 2, 3])) def test_sympy__stats__joint_rv_types__MultivariateEwensDistribution(): from sympy.stats.joint_rv_types import MultivariateEwensDistribution assert _test_args(MultivariateEwensDistribution(5, 1)) def test_sympy__stats__joint_rv_types__MultinomialDistribution(): from sympy.stats.joint_rv_types import MultinomialDistribution assert _test_args(MultinomialDistribution(5, [0.5, 0.1, 0.3])) def test_sympy__stats__joint_rv_types__NegativeMultinomialDistribution(): from sympy.stats.joint_rv_types import NegativeMultinomialDistribution assert _test_args(NegativeMultinomialDistribution(5, [0.5, 0.1, 0.3])) def test_sympy__stats__rv__RandomIndexedSymbol(): from sympy.stats.rv import RandomIndexedSymbol, pspace from sympy.stats.stochastic_process_types import DiscreteMarkovChain X = DiscreteMarkovChain("X") assert _test_args(RandomIndexedSymbol(X[0].symbol, pspace(X[0]))) def test_sympy__stats__rv__RandomMatrixSymbol(): from sympy.stats.rv import RandomMatrixSymbol from sympy.stats.random_matrix import RandomMatrixPSpace pspace = RandomMatrixPSpace('P') assert _test_args(RandomMatrixSymbol('M', 3, 3, pspace)) def test_sympy__stats__stochastic_process__StochasticPSpace(): from sympy.stats.stochastic_process import StochasticPSpace from sympy.stats.stochastic_process_types import StochasticProcess from sympy.stats.frv_types import BernoulliDistribution assert _test_args(StochasticPSpace("Y", StochasticProcess("Y", [1, 2, 3]), BernoulliDistribution(S.Half, 1, 0))) def test_sympy__stats__stochastic_process_types__StochasticProcess(): from sympy.stats.stochastic_process_types import StochasticProcess assert _test_args(StochasticProcess("Y", [1, 2, 3])) def test_sympy__stats__stochastic_process_types__MarkovProcess(): from sympy.stats.stochastic_process_types import MarkovProcess assert _test_args(MarkovProcess("Y", [1, 2, 3])) def test_sympy__stats__stochastic_process_types__DiscreteTimeStochasticProcess(): from sympy.stats.stochastic_process_types import DiscreteTimeStochasticProcess assert _test_args(DiscreteTimeStochasticProcess("Y", [1, 2, 3])) def test_sympy__stats__stochastic_process_types__ContinuousTimeStochasticProcess(): from sympy.stats.stochastic_process_types import ContinuousTimeStochasticProcess assert _test_args(ContinuousTimeStochasticProcess("Y", [1, 2, 3])) def test_sympy__stats__stochastic_process_types__TransitionMatrixOf(): from sympy.stats.stochastic_process_types import TransitionMatrixOf, DiscreteMarkovChain from sympy import MatrixSymbol DMC = DiscreteMarkovChain("Y") assert _test_args(TransitionMatrixOf(DMC, MatrixSymbol('T', 3, 3))) def test_sympy__stats__stochastic_process_types__GeneratorMatrixOf(): from sympy.stats.stochastic_process_types import GeneratorMatrixOf, ContinuousMarkovChain from sympy import MatrixSymbol DMC = ContinuousMarkovChain("Y") assert _test_args(GeneratorMatrixOf(DMC, MatrixSymbol('T', 3, 3))) def test_sympy__stats__stochastic_process_types__StochasticStateSpaceOf(): from sympy.stats.stochastic_process_types import StochasticStateSpaceOf, DiscreteMarkovChain DMC = DiscreteMarkovChain("Y") assert _test_args(StochasticStateSpaceOf(DMC, [0, 1, 2])) def test_sympy__stats__stochastic_process_types__DiscreteMarkovChain(): from sympy.stats.stochastic_process_types import DiscreteMarkovChain from sympy import MatrixSymbol assert _test_args(DiscreteMarkovChain("Y", [0, 1, 2], MatrixSymbol('T', 3, 3))) def test_sympy__stats__stochastic_process_types__ContinuousMarkovChain(): from sympy.stats.stochastic_process_types import ContinuousMarkovChain from sympy import MatrixSymbol assert _test_args(ContinuousMarkovChain("Y", [0, 1, 2], MatrixSymbol('T', 3, 3))) def test_sympy__stats__stochastic_process_types__BernoulliProcess(): from sympy.stats.stochastic_process_types import BernoulliProcess assert _test_args(BernoulliProcess("B", 0.5, 1, 0)) def test_sympy__stats__stochastic_process_types__CountingProcess(): from sympy.stats.stochastic_process_types import CountingProcess assert _test_args(CountingProcess("C")) def test_sympy__stats__stochastic_process_types__PoissonProcess(): from sympy.stats.stochastic_process_types import PoissonProcess assert _test_args(PoissonProcess("X", 2)) def test_sympy__stats__stochastic_process_types__WienerProcess(): from sympy.stats.stochastic_process_types import WienerProcess assert _test_args(WienerProcess("X")) def test_sympy__stats__stochastic_process_types__GammaProcess(): from sympy.stats.stochastic_process_types import GammaProcess assert _test_args(GammaProcess("X", 1, 2)) def test_sympy__stats__random_matrix__RandomMatrixPSpace(): from sympy.stats.random_matrix import RandomMatrixPSpace from sympy.stats.random_matrix_models import RandomMatrixEnsembleModel model = RandomMatrixEnsembleModel('R', 3) assert _test_args(RandomMatrixPSpace('P', model=model)) def test_sympy__stats__random_matrix_models__RandomMatrixEnsembleModel(): from sympy.stats.random_matrix_models import RandomMatrixEnsembleModel assert _test_args(RandomMatrixEnsembleModel('R', 3)) def test_sympy__stats__random_matrix_models__GaussianEnsembleModel(): from sympy.stats.random_matrix_models import GaussianEnsembleModel assert _test_args(GaussianEnsembleModel('G', 3)) def test_sympy__stats__random_matrix_models__GaussianUnitaryEnsembleModel(): from sympy.stats.random_matrix_models import GaussianUnitaryEnsembleModel assert _test_args(GaussianUnitaryEnsembleModel('U', 3)) def test_sympy__stats__random_matrix_models__GaussianOrthogonalEnsembleModel(): from sympy.stats.random_matrix_models import GaussianOrthogonalEnsembleModel assert _test_args(GaussianOrthogonalEnsembleModel('U', 3)) def test_sympy__stats__random_matrix_models__GaussianSymplecticEnsembleModel(): from sympy.stats.random_matrix_models import GaussianSymplecticEnsembleModel assert _test_args(GaussianSymplecticEnsembleModel('U', 3)) def test_sympy__stats__random_matrix_models__CircularEnsembleModel(): from sympy.stats.random_matrix_models import CircularEnsembleModel assert _test_args(CircularEnsembleModel('C', 3)) def test_sympy__stats__random_matrix_models__CircularUnitaryEnsembleModel(): from sympy.stats.random_matrix_models import CircularUnitaryEnsembleModel assert _test_args(CircularUnitaryEnsembleModel('U', 3)) def test_sympy__stats__random_matrix_models__CircularOrthogonalEnsembleModel(): from sympy.stats.random_matrix_models import CircularOrthogonalEnsembleModel assert _test_args(CircularOrthogonalEnsembleModel('O', 3)) def test_sympy__stats__random_matrix_models__CircularSymplecticEnsembleModel(): from sympy.stats.random_matrix_models import CircularSymplecticEnsembleModel assert _test_args(CircularSymplecticEnsembleModel('S', 3)) def test_sympy__stats__symbolic_multivariate_probability__ExpectationMatrix(): from sympy.stats import ExpectationMatrix from sympy.stats.rv import RandomMatrixSymbol assert _test_args(ExpectationMatrix(RandomMatrixSymbol('R', 2, 1))) def test_sympy__stats__symbolic_multivariate_probability__VarianceMatrix(): from sympy.stats import VarianceMatrix from sympy.stats.rv import RandomMatrixSymbol assert _test_args(VarianceMatrix(RandomMatrixSymbol('R', 3, 1))) def test_sympy__stats__symbolic_multivariate_probability__CrossCovarianceMatrix(): from sympy.stats import CrossCovarianceMatrix from sympy.stats.rv import RandomMatrixSymbol assert _test_args(CrossCovarianceMatrix(RandomMatrixSymbol('R', 3, 1), RandomMatrixSymbol('X', 3, 1))) def test_sympy__stats__matrix_distributions__MatrixPSpace(): from sympy.stats.matrix_distributions import MatrixDistribution, MatrixPSpace from sympy import Matrix M = MatrixDistribution(1, Matrix([[1, 0], [0, 1]])) assert _test_args(MatrixPSpace('M', M, 2, 2)) def test_sympy__stats__matrix_distributions__MatrixDistribution(): from sympy.stats.matrix_distributions import MatrixDistribution from sympy import Matrix assert _test_args(MatrixDistribution(1, Matrix([[1, 0], [0, 1]]))) def test_sympy__stats__matrix_distributions__MatrixGammaDistribution(): from sympy.stats.matrix_distributions import MatrixGammaDistribution from sympy import Matrix assert _test_args(MatrixGammaDistribution(3, 4, Matrix([[1, 0], [0, 1]]))) def test_sympy__stats__matrix_distributions__WishartDistribution(): from sympy.stats.matrix_distributions import WishartDistribution from sympy import Matrix assert _test_args(WishartDistribution(3, Matrix([[1, 0], [0, 1]]))) def test_sympy__stats__matrix_distributions__MatrixNormalDistribution(): from sympy.stats.matrix_distributions import MatrixNormalDistribution from sympy import MatrixSymbol L = MatrixSymbol('L', 1, 2) S1 = MatrixSymbol('S1', 1, 1) S2 = MatrixSymbol('S2', 2, 2) assert _test_args(MatrixNormalDistribution(L, S1, S2)) def test_sympy__stats__matrix_distributions__MatrixStudentTDistribution(): from sympy.stats.matrix_distributions import MatrixStudentTDistribution from sympy import MatrixSymbol v = symbols('v', positive=True) Omega = MatrixSymbol('Omega', 3, 3) Sigma = MatrixSymbol('Sigma', 1, 1) Location = MatrixSymbol('Location', 1, 3) assert _test_args(MatrixStudentTDistribution(v, Location, Omega, Sigma)) def test_sympy__utilities__matchpy_connector__WildDot(): from sympy.utilities.matchpy_connector import WildDot assert _test_args(WildDot("w_")) def test_sympy__utilities__matchpy_connector__WildPlus(): from sympy.utilities.matchpy_connector import WildPlus assert _test_args(WildPlus("w__")) def test_sympy__utilities__matchpy_connector__WildStar(): from sympy.utilities.matchpy_connector import WildStar assert _test_args(WildStar("w___")) def test_sympy__core__symbol__Str(): from sympy.core.symbol import Str assert _test_args(Str('t')) def test_sympy__core__symbol__Dummy(): from sympy.core.symbol import Dummy assert _test_args(Dummy('t')) def test_sympy__core__symbol__Symbol(): from sympy.core.symbol import Symbol assert _test_args(Symbol('t')) def test_sympy__core__symbol__Wild(): from sympy.core.symbol import Wild assert _test_args(Wild('x', exclude=[x])) @SKIP("abstract class") def test_sympy__functions__combinatorial__factorials__CombinatorialFunction(): pass def test_sympy__functions__combinatorial__factorials__FallingFactorial(): from sympy.functions.combinatorial.factorials import FallingFactorial assert _test_args(FallingFactorial(2, x)) def test_sympy__functions__combinatorial__factorials__MultiFactorial(): from sympy.functions.combinatorial.factorials import MultiFactorial assert _test_args(MultiFactorial(x)) def test_sympy__functions__combinatorial__factorials__RisingFactorial(): from sympy.functions.combinatorial.factorials import RisingFactorial assert _test_args(RisingFactorial(2, x)) def test_sympy__functions__combinatorial__factorials__binomial(): from sympy.functions.combinatorial.factorials import binomial assert _test_args(binomial(2, x)) def test_sympy__functions__combinatorial__factorials__subfactorial(): from sympy.functions.combinatorial.factorials import subfactorial assert _test_args(subfactorial(1)) def test_sympy__functions__combinatorial__factorials__factorial(): from sympy.functions.combinatorial.factorials import factorial assert _test_args(factorial(x)) def test_sympy__functions__combinatorial__factorials__factorial2(): from sympy.functions.combinatorial.factorials import factorial2 assert _test_args(factorial2(x)) def test_sympy__functions__combinatorial__numbers__bell(): from sympy.functions.combinatorial.numbers import bell assert _test_args(bell(x, y)) def test_sympy__functions__combinatorial__numbers__bernoulli(): from sympy.functions.combinatorial.numbers import bernoulli assert _test_args(bernoulli(x)) def test_sympy__functions__combinatorial__numbers__catalan(): from sympy.functions.combinatorial.numbers import catalan assert _test_args(catalan(x)) def test_sympy__functions__combinatorial__numbers__genocchi(): from sympy.functions.combinatorial.numbers import genocchi assert _test_args(genocchi(x)) def test_sympy__functions__combinatorial__numbers__euler(): from sympy.functions.combinatorial.numbers import euler assert _test_args(euler(x)) def test_sympy__functions__combinatorial__numbers__carmichael(): from sympy.functions.combinatorial.numbers import carmichael assert _test_args(carmichael(x)) def test_sympy__functions__combinatorial__numbers__motzkin(): from sympy.functions.combinatorial.numbers import motzkin assert _test_args(motzkin(5)) def test_sympy__functions__combinatorial__numbers__fibonacci(): from sympy.functions.combinatorial.numbers import fibonacci assert _test_args(fibonacci(x)) def test_sympy__functions__combinatorial__numbers__tribonacci(): from sympy.functions.combinatorial.numbers import tribonacci assert _test_args(tribonacci(x)) def test_sympy__functions__combinatorial__numbers__harmonic(): from sympy.functions.combinatorial.numbers import harmonic assert _test_args(harmonic(x, 2)) def test_sympy__functions__combinatorial__numbers__lucas(): from sympy.functions.combinatorial.numbers import lucas assert _test_args(lucas(x)) def test_sympy__functions__combinatorial__numbers__partition(): from sympy.core.symbol import Symbol from sympy.functions.combinatorial.numbers import partition assert _test_args(partition(Symbol('a', integer=True))) def test_sympy__functions__elementary__complexes__Abs(): from sympy.functions.elementary.complexes import Abs assert _test_args(Abs(x)) def test_sympy__functions__elementary__complexes__adjoint(): from sympy.functions.elementary.complexes import adjoint assert _test_args(adjoint(x)) def test_sympy__functions__elementary__complexes__arg(): from sympy.functions.elementary.complexes import arg assert _test_args(arg(x)) def test_sympy__functions__elementary__complexes__conjugate(): from sympy.functions.elementary.complexes import conjugate assert _test_args(conjugate(x)) def test_sympy__functions__elementary__complexes__im(): from sympy.functions.elementary.complexes import im assert _test_args(im(x)) def test_sympy__functions__elementary__complexes__re(): from sympy.functions.elementary.complexes import re assert _test_args(re(x)) def test_sympy__functions__elementary__complexes__sign(): from sympy.functions.elementary.complexes import sign assert _test_args(sign(x)) def test_sympy__functions__elementary__complexes__polar_lift(): from sympy.functions.elementary.complexes import polar_lift assert _test_args(polar_lift(x)) def test_sympy__functions__elementary__complexes__periodic_argument(): from sympy.functions.elementary.complexes import periodic_argument assert _test_args(periodic_argument(x, y)) def test_sympy__functions__elementary__complexes__principal_branch(): from sympy.functions.elementary.complexes import principal_branch assert _test_args(principal_branch(x, y)) def test_sympy__functions__elementary__complexes__transpose(): from sympy.functions.elementary.complexes import transpose assert _test_args(transpose(x)) def test_sympy__functions__elementary__exponential__LambertW(): from sympy.functions.elementary.exponential import LambertW assert _test_args(LambertW(2)) @SKIP("abstract class") def test_sympy__functions__elementary__exponential__ExpBase(): pass def test_sympy__functions__elementary__exponential__exp(): from sympy.functions.elementary.exponential import exp assert _test_args(exp(2)) def test_sympy__functions__elementary__exponential__exp_polar(): from sympy.functions.elementary.exponential import exp_polar assert _test_args(exp_polar(2)) def test_sympy__functions__elementary__exponential__log(): from sympy.functions.elementary.exponential import log assert _test_args(log(2)) @SKIP("abstract class") def test_sympy__functions__elementary__hyperbolic__HyperbolicFunction(): pass @SKIP("abstract class") def test_sympy__functions__elementary__hyperbolic__ReciprocalHyperbolicFunction(): pass @SKIP("abstract class") def test_sympy__functions__elementary__hyperbolic__InverseHyperbolicFunction(): pass def test_sympy__functions__elementary__hyperbolic__acosh(): from sympy.functions.elementary.hyperbolic import acosh assert _test_args(acosh(2)) def test_sympy__functions__elementary__hyperbolic__acoth(): from sympy.functions.elementary.hyperbolic import acoth assert _test_args(acoth(2)) def test_sympy__functions__elementary__hyperbolic__asinh(): from sympy.functions.elementary.hyperbolic import asinh assert _test_args(asinh(2)) def test_sympy__functions__elementary__hyperbolic__atanh(): from sympy.functions.elementary.hyperbolic import atanh assert _test_args(atanh(2)) def test_sympy__functions__elementary__hyperbolic__asech(): from sympy.functions.elementary.hyperbolic import asech assert _test_args(asech(2)) def test_sympy__functions__elementary__hyperbolic__acsch(): from sympy.functions.elementary.hyperbolic import acsch assert _test_args(acsch(2)) def test_sympy__functions__elementary__hyperbolic__cosh(): from sympy.functions.elementary.hyperbolic import cosh assert _test_args(cosh(2)) def test_sympy__functions__elementary__hyperbolic__coth(): from sympy.functions.elementary.hyperbolic import coth assert _test_args(coth(2)) def test_sympy__functions__elementary__hyperbolic__csch(): from sympy.functions.elementary.hyperbolic import csch assert _test_args(csch(2)) def test_sympy__functions__elementary__hyperbolic__sech(): from sympy.functions.elementary.hyperbolic import sech assert _test_args(sech(2)) def test_sympy__functions__elementary__hyperbolic__sinh(): from sympy.functions.elementary.hyperbolic import sinh assert _test_args(sinh(2)) def test_sympy__functions__elementary__hyperbolic__tanh(): from sympy.functions.elementary.hyperbolic import tanh assert _test_args(tanh(2)) @SKIP("does this work at all?") def test_sympy__functions__elementary__integers__RoundFunction(): from sympy.functions.elementary.integers import RoundFunction assert _test_args(RoundFunction()) def test_sympy__functions__elementary__integers__ceiling(): from sympy.functions.elementary.integers import ceiling assert _test_args(ceiling(x)) def test_sympy__functions__elementary__integers__floor(): from sympy.functions.elementary.integers import floor assert _test_args(floor(x)) def test_sympy__functions__elementary__integers__frac(): from sympy.functions.elementary.integers import frac assert _test_args(frac(x)) def test_sympy__functions__elementary__miscellaneous__IdentityFunction(): from sympy.functions.elementary.miscellaneous import IdentityFunction assert _test_args(IdentityFunction()) def test_sympy__functions__elementary__miscellaneous__Max(): from sympy.functions.elementary.miscellaneous import Max assert _test_args(Max(x, 2)) def test_sympy__functions__elementary__miscellaneous__Min(): from sympy.functions.elementary.miscellaneous import Min assert _test_args(Min(x, 2)) @SKIP("abstract class") def test_sympy__functions__elementary__miscellaneous__MinMaxBase(): pass def test_sympy__functions__elementary__piecewise__ExprCondPair(): from sympy.functions.elementary.piecewise import ExprCondPair assert _test_args(ExprCondPair(1, True)) def test_sympy__functions__elementary__piecewise__Piecewise(): from sympy.functions.elementary.piecewise import Piecewise assert _test_args(Piecewise((1, x >= 0), (0, True))) @SKIP("abstract class") def test_sympy__functions__elementary__trigonometric__TrigonometricFunction(): pass @SKIP("abstract class") def test_sympy__functions__elementary__trigonometric__ReciprocalTrigonometricFunction(): pass @SKIP("abstract class") def test_sympy__functions__elementary__trigonometric__InverseTrigonometricFunction(): pass def test_sympy__functions__elementary__trigonometric__acos(): from sympy.functions.elementary.trigonometric import acos assert _test_args(acos(2)) def test_sympy__functions__elementary__trigonometric__acot(): from sympy.functions.elementary.trigonometric import acot assert _test_args(acot(2)) def test_sympy__functions__elementary__trigonometric__asin(): from sympy.functions.elementary.trigonometric import asin assert _test_args(asin(2)) def test_sympy__functions__elementary__trigonometric__asec(): from sympy.functions.elementary.trigonometric import asec assert _test_args(asec(2)) def test_sympy__functions__elementary__trigonometric__acsc(): from sympy.functions.elementary.trigonometric import acsc assert _test_args(acsc(2)) def test_sympy__functions__elementary__trigonometric__atan(): from sympy.functions.elementary.trigonometric import atan assert _test_args(atan(2)) def test_sympy__functions__elementary__trigonometric__atan2(): from sympy.functions.elementary.trigonometric import atan2 assert _test_args(atan2(2, 3)) def test_sympy__functions__elementary__trigonometric__cos(): from sympy.functions.elementary.trigonometric import cos assert _test_args(cos(2)) def test_sympy__functions__elementary__trigonometric__csc(): from sympy.functions.elementary.trigonometric import csc assert _test_args(csc(2)) def test_sympy__functions__elementary__trigonometric__cot(): from sympy.functions.elementary.trigonometric import cot assert _test_args(cot(2)) def test_sympy__functions__elementary__trigonometric__sin(): assert _test_args(sin(2)) def test_sympy__functions__elementary__trigonometric__sinc(): from sympy.functions.elementary.trigonometric import sinc assert _test_args(sinc(2)) def test_sympy__functions__elementary__trigonometric__sec(): from sympy.functions.elementary.trigonometric import sec assert _test_args(sec(2)) def test_sympy__functions__elementary__trigonometric__tan(): from sympy.functions.elementary.trigonometric import tan assert _test_args(tan(2)) @SKIP("abstract class") def test_sympy__functions__special__bessel__BesselBase(): pass @SKIP("abstract class") def test_sympy__functions__special__bessel__SphericalBesselBase(): pass @SKIP("abstract class") def test_sympy__functions__special__bessel__SphericalHankelBase(): pass def test_sympy__functions__special__bessel__besseli(): from sympy.functions.special.bessel import besseli assert _test_args(besseli(x, 1)) def test_sympy__functions__special__bessel__besselj(): from sympy.functions.special.bessel import besselj assert _test_args(besselj(x, 1)) def test_sympy__functions__special__bessel__besselk(): from sympy.functions.special.bessel import besselk assert _test_args(besselk(x, 1)) def test_sympy__functions__special__bessel__bessely(): from sympy.functions.special.bessel import bessely assert _test_args(bessely(x, 1)) def test_sympy__functions__special__bessel__hankel1(): from sympy.functions.special.bessel import hankel1 assert _test_args(hankel1(x, 1)) def test_sympy__functions__special__bessel__hankel2(): from sympy.functions.special.bessel import hankel2 assert _test_args(hankel2(x, 1)) def test_sympy__functions__special__bessel__jn(): from sympy.functions.special.bessel import jn assert _test_args(jn(0, x)) def test_sympy__functions__special__bessel__yn(): from sympy.functions.special.bessel import yn assert _test_args(yn(0, x)) def test_sympy__functions__special__bessel__hn1(): from sympy.functions.special.bessel import hn1 assert _test_args(hn1(0, x)) def test_sympy__functions__special__bessel__hn2(): from sympy.functions.special.bessel import hn2 assert _test_args(hn2(0, x)) def test_sympy__functions__special__bessel__AiryBase(): pass def test_sympy__functions__special__bessel__airyai(): from sympy.functions.special.bessel import airyai assert _test_args(airyai(2)) def test_sympy__functions__special__bessel__airybi(): from sympy.functions.special.bessel import airybi assert _test_args(airybi(2)) def test_sympy__functions__special__bessel__airyaiprime(): from sympy.functions.special.bessel import airyaiprime assert _test_args(airyaiprime(2)) def test_sympy__functions__special__bessel__airybiprime(): from sympy.functions.special.bessel import airybiprime assert _test_args(airybiprime(2)) def test_sympy__functions__special__bessel__marcumq(): from sympy.functions.special.bessel import marcumq assert _test_args(marcumq(x, y, z)) def test_sympy__functions__special__elliptic_integrals__elliptic_k(): from sympy.functions.special.elliptic_integrals import elliptic_k as K assert _test_args(K(x)) def test_sympy__functions__special__elliptic_integrals__elliptic_f(): from sympy.functions.special.elliptic_integrals import elliptic_f as F assert _test_args(F(x, y)) def test_sympy__functions__special__elliptic_integrals__elliptic_e(): from sympy.functions.special.elliptic_integrals import elliptic_e as E assert _test_args(E(x)) assert _test_args(E(x, y)) def test_sympy__functions__special__elliptic_integrals__elliptic_pi(): from sympy.functions.special.elliptic_integrals import elliptic_pi as P assert _test_args(P(x, y)) assert _test_args(P(x, y, z)) def test_sympy__functions__special__delta_functions__DiracDelta(): from sympy.functions.special.delta_functions import DiracDelta assert _test_args(DiracDelta(x, 1)) def test_sympy__functions__special__singularity_functions__SingularityFunction(): from sympy.functions.special.singularity_functions import SingularityFunction assert _test_args(SingularityFunction(x, y, z)) def test_sympy__functions__special__delta_functions__Heaviside(): from sympy.functions.special.delta_functions import Heaviside assert _test_args(Heaviside(x)) def test_sympy__functions__special__error_functions__erf(): from sympy.functions.special.error_functions import erf assert _test_args(erf(2)) def test_sympy__functions__special__error_functions__erfc(): from sympy.functions.special.error_functions import erfc assert _test_args(erfc(2)) def test_sympy__functions__special__error_functions__erfi(): from sympy.functions.special.error_functions import erfi assert _test_args(erfi(2)) def test_sympy__functions__special__error_functions__erf2(): from sympy.functions.special.error_functions import erf2 assert _test_args(erf2(2, 3)) def test_sympy__functions__special__error_functions__erfinv(): from sympy.functions.special.error_functions import erfinv assert _test_args(erfinv(2)) def test_sympy__functions__special__error_functions__erfcinv(): from sympy.functions.special.error_functions import erfcinv assert _test_args(erfcinv(2)) def test_sympy__functions__special__error_functions__erf2inv(): from sympy.functions.special.error_functions import erf2inv assert _test_args(erf2inv(2, 3)) @SKIP("abstract class") def test_sympy__functions__special__error_functions__FresnelIntegral(): pass def test_sympy__functions__special__error_functions__fresnels(): from sympy.functions.special.error_functions import fresnels assert _test_args(fresnels(2)) def test_sympy__functions__special__error_functions__fresnelc(): from sympy.functions.special.error_functions import fresnelc assert _test_args(fresnelc(2)) def test_sympy__functions__special__error_functions__erfs(): from sympy.functions.special.error_functions import _erfs assert _test_args(_erfs(2)) def test_sympy__functions__special__error_functions__Ei(): from sympy.functions.special.error_functions import Ei assert _test_args(Ei(2)) def test_sympy__functions__special__error_functions__li(): from sympy.functions.special.error_functions import li assert _test_args(li(2)) def test_sympy__functions__special__error_functions__Li(): from sympy.functions.special.error_functions import Li assert _test_args(Li(2)) @SKIP("abstract class") def test_sympy__functions__special__error_functions__TrigonometricIntegral(): pass def test_sympy__functions__special__error_functions__Si(): from sympy.functions.special.error_functions import Si assert _test_args(Si(2)) def test_sympy__functions__special__error_functions__Ci(): from sympy.functions.special.error_functions import Ci assert _test_args(Ci(2)) def test_sympy__functions__special__error_functions__Shi(): from sympy.functions.special.error_functions import Shi assert _test_args(Shi(2)) def test_sympy__functions__special__error_functions__Chi(): from sympy.functions.special.error_functions import Chi assert _test_args(Chi(2)) def test_sympy__functions__special__error_functions__expint(): from sympy.functions.special.error_functions import expint assert _test_args(expint(y, x)) def test_sympy__functions__special__gamma_functions__gamma(): from sympy.functions.special.gamma_functions import gamma assert _test_args(gamma(x)) def test_sympy__functions__special__gamma_functions__loggamma(): from sympy.functions.special.gamma_functions import loggamma assert _test_args(loggamma(2)) def test_sympy__functions__special__gamma_functions__lowergamma(): from sympy.functions.special.gamma_functions import lowergamma assert _test_args(lowergamma(x, 2)) def test_sympy__functions__special__gamma_functions__polygamma(): from sympy.functions.special.gamma_functions import polygamma assert _test_args(polygamma(x, 2)) def test_sympy__functions__special__gamma_functions__digamma(): from sympy.functions.special.gamma_functions import digamma assert _test_args(digamma(x)) def test_sympy__functions__special__gamma_functions__trigamma(): from sympy.functions.special.gamma_functions import trigamma assert _test_args(trigamma(x)) def test_sympy__functions__special__gamma_functions__uppergamma(): from sympy.functions.special.gamma_functions import uppergamma assert _test_args(uppergamma(x, 2)) def test_sympy__functions__special__gamma_functions__multigamma(): from sympy.functions.special.gamma_functions import multigamma assert _test_args(multigamma(x, 1)) def test_sympy__functions__special__beta_functions__beta(): from sympy.functions.special.beta_functions import beta assert _test_args(beta(x)) assert _test_args(beta(x, x)) def test_sympy__functions__special__beta_functions__betainc(): from sympy.functions.special.beta_functions import betainc assert _test_args(betainc(a, b, x, y)) def test_sympy__functions__special__beta_functions__betainc_regularized(): from sympy.functions.special.beta_functions import betainc_regularized assert _test_args(betainc_regularized(a, b, x, y)) def test_sympy__functions__special__mathieu_functions__MathieuBase(): pass def test_sympy__functions__special__mathieu_functions__mathieus(): from sympy.functions.special.mathieu_functions import mathieus assert _test_args(mathieus(1, 1, 1)) def test_sympy__functions__special__mathieu_functions__mathieuc(): from sympy.functions.special.mathieu_functions import mathieuc assert _test_args(mathieuc(1, 1, 1)) def test_sympy__functions__special__mathieu_functions__mathieusprime(): from sympy.functions.special.mathieu_functions import mathieusprime assert _test_args(mathieusprime(1, 1, 1)) def test_sympy__functions__special__mathieu_functions__mathieucprime(): from sympy.functions.special.mathieu_functions import mathieucprime assert _test_args(mathieucprime(1, 1, 1)) @SKIP("abstract class") def test_sympy__functions__special__hyper__TupleParametersBase(): pass @SKIP("abstract class") def test_sympy__functions__special__hyper__TupleArg(): pass def test_sympy__functions__special__hyper__hyper(): from sympy.functions.special.hyper import hyper assert _test_args(hyper([1, 2, 3], [4, 5], x)) def test_sympy__functions__special__hyper__meijerg(): from sympy.functions.special.hyper import meijerg assert _test_args(meijerg([1, 2, 3], [4, 5], [6], [], x)) @SKIP("abstract class") def test_sympy__functions__special__hyper__HyperRep(): pass def test_sympy__functions__special__hyper__HyperRep_power1(): from sympy.functions.special.hyper import HyperRep_power1 assert _test_args(HyperRep_power1(x, y)) def test_sympy__functions__special__hyper__HyperRep_power2(): from sympy.functions.special.hyper import HyperRep_power2 assert _test_args(HyperRep_power2(x, y)) def test_sympy__functions__special__hyper__HyperRep_log1(): from sympy.functions.special.hyper import HyperRep_log1 assert _test_args(HyperRep_log1(x)) def test_sympy__functions__special__hyper__HyperRep_atanh(): from sympy.functions.special.hyper import HyperRep_atanh assert _test_args(HyperRep_atanh(x)) def test_sympy__functions__special__hyper__HyperRep_asin1(): from sympy.functions.special.hyper import HyperRep_asin1 assert _test_args(HyperRep_asin1(x)) def test_sympy__functions__special__hyper__HyperRep_asin2(): from sympy.functions.special.hyper import HyperRep_asin2 assert _test_args(HyperRep_asin2(x)) def test_sympy__functions__special__hyper__HyperRep_sqrts1(): from sympy.functions.special.hyper import HyperRep_sqrts1 assert _test_args(HyperRep_sqrts1(x, y)) def test_sympy__functions__special__hyper__HyperRep_sqrts2(): from sympy.functions.special.hyper import HyperRep_sqrts2 assert _test_args(HyperRep_sqrts2(x, y)) def test_sympy__functions__special__hyper__HyperRep_log2(): from sympy.functions.special.hyper import HyperRep_log2 assert _test_args(HyperRep_log2(x)) def test_sympy__functions__special__hyper__HyperRep_cosasin(): from sympy.functions.special.hyper import HyperRep_cosasin assert _test_args(HyperRep_cosasin(x, y)) def test_sympy__functions__special__hyper__HyperRep_sinasin(): from sympy.functions.special.hyper import HyperRep_sinasin assert _test_args(HyperRep_sinasin(x, y)) def test_sympy__functions__special__hyper__appellf1(): from sympy.functions.special.hyper import appellf1 a, b1, b2, c, x, y = symbols('a b1 b2 c x y') assert _test_args(appellf1(a, b1, b2, c, x, y)) @SKIP("abstract class") def test_sympy__functions__special__polynomials__OrthogonalPolynomial(): pass def test_sympy__functions__special__polynomials__jacobi(): from sympy.functions.special.polynomials import jacobi assert _test_args(jacobi(x, 2, 2, 2)) def test_sympy__functions__special__polynomials__gegenbauer(): from sympy.functions.special.polynomials import gegenbauer assert _test_args(gegenbauer(x, 2, 2)) def test_sympy__functions__special__polynomials__chebyshevt(): from sympy.functions.special.polynomials import chebyshevt assert _test_args(chebyshevt(x, 2)) def test_sympy__functions__special__polynomials__chebyshevt_root(): from sympy.functions.special.polynomials import chebyshevt_root assert _test_args(chebyshevt_root(3, 2)) def test_sympy__functions__special__polynomials__chebyshevu(): from sympy.functions.special.polynomials import chebyshevu assert _test_args(chebyshevu(x, 2)) def test_sympy__functions__special__polynomials__chebyshevu_root(): from sympy.functions.special.polynomials import chebyshevu_root assert _test_args(chebyshevu_root(3, 2)) def test_sympy__functions__special__polynomials__hermite(): from sympy.functions.special.polynomials import hermite assert _test_args(hermite(x, 2)) def test_sympy__functions__special__polynomials__legendre(): from sympy.functions.special.polynomials import legendre assert _test_args(legendre(x, 2)) def test_sympy__functions__special__polynomials__assoc_legendre(): from sympy.functions.special.polynomials import assoc_legendre assert _test_args(assoc_legendre(x, 0, y)) def test_sympy__functions__special__polynomials__laguerre(): from sympy.functions.special.polynomials import laguerre assert _test_args(laguerre(x, 2)) def test_sympy__functions__special__polynomials__assoc_laguerre(): from sympy.functions.special.polynomials import assoc_laguerre assert _test_args(assoc_laguerre(x, 0, y)) def test_sympy__functions__special__spherical_harmonics__Ynm(): from sympy.functions.special.spherical_harmonics import Ynm assert _test_args(Ynm(1, 1, x, y)) def test_sympy__functions__special__spherical_harmonics__Znm(): from sympy.functions.special.spherical_harmonics import Znm assert _test_args(Znm(1, 1, x, y)) def test_sympy__functions__special__tensor_functions__LeviCivita(): from sympy.functions.special.tensor_functions import LeviCivita assert _test_args(LeviCivita(x, y, 2)) def test_sympy__functions__special__tensor_functions__KroneckerDelta(): from sympy.functions.special.tensor_functions import KroneckerDelta assert _test_args(KroneckerDelta(x, y)) def test_sympy__functions__special__zeta_functions__dirichlet_eta(): from sympy.functions.special.zeta_functions import dirichlet_eta assert _test_args(dirichlet_eta(x)) def test_sympy__functions__special__zeta_functions__riemann_xi(): from sympy.functions.special.zeta_functions import riemann_xi assert _test_args(riemann_xi(x)) def test_sympy__functions__special__zeta_functions__zeta(): from sympy.functions.special.zeta_functions import zeta assert _test_args(zeta(101)) def test_sympy__functions__special__zeta_functions__lerchphi(): from sympy.functions.special.zeta_functions import lerchphi assert _test_args(lerchphi(x, y, z)) def test_sympy__functions__special__zeta_functions__polylog(): from sympy.functions.special.zeta_functions import polylog assert _test_args(polylog(x, y)) def test_sympy__functions__special__zeta_functions__stieltjes(): from sympy.functions.special.zeta_functions import stieltjes assert _test_args(stieltjes(x, y)) def test_sympy__integrals__integrals__Integral(): from sympy.integrals.integrals import Integral assert _test_args(Integral(2, (x, 0, 1))) def test_sympy__integrals__risch__NonElementaryIntegral(): from sympy.integrals.risch import NonElementaryIntegral assert _test_args(NonElementaryIntegral(exp(-x**2), x)) @SKIP("abstract class") def test_sympy__integrals__transforms__IntegralTransform(): pass def test_sympy__integrals__transforms__MellinTransform(): from sympy.integrals.transforms import MellinTransform assert _test_args(MellinTransform(2, x, y)) def test_sympy__integrals__transforms__InverseMellinTransform(): from sympy.integrals.transforms import InverseMellinTransform assert _test_args(InverseMellinTransform(2, x, y, 0, 1)) def test_sympy__integrals__transforms__LaplaceTransform(): from sympy.integrals.transforms import LaplaceTransform assert _test_args(LaplaceTransform(2, x, y)) def test_sympy__integrals__transforms__InverseLaplaceTransform(): from sympy.integrals.transforms import InverseLaplaceTransform assert _test_args(InverseLaplaceTransform(2, x, y, 0)) @SKIP("abstract class") def test_sympy__integrals__transforms__FourierTypeTransform(): pass def test_sympy__integrals__transforms__InverseFourierTransform(): from sympy.integrals.transforms import InverseFourierTransform assert _test_args(InverseFourierTransform(2, x, y)) def test_sympy__integrals__transforms__FourierTransform(): from sympy.integrals.transforms import FourierTransform assert _test_args(FourierTransform(2, x, y)) @SKIP("abstract class") def test_sympy__integrals__transforms__SineCosineTypeTransform(): pass def test_sympy__integrals__transforms__InverseSineTransform(): from sympy.integrals.transforms import InverseSineTransform assert _test_args(InverseSineTransform(2, x, y)) def test_sympy__integrals__transforms__SineTransform(): from sympy.integrals.transforms import SineTransform assert _test_args(SineTransform(2, x, y)) def test_sympy__integrals__transforms__InverseCosineTransform(): from sympy.integrals.transforms import InverseCosineTransform assert _test_args(InverseCosineTransform(2, x, y)) def test_sympy__integrals__transforms__CosineTransform(): from sympy.integrals.transforms import CosineTransform assert _test_args(CosineTransform(2, x, y)) @SKIP("abstract class") def test_sympy__integrals__transforms__HankelTypeTransform(): pass def test_sympy__integrals__transforms__InverseHankelTransform(): from sympy.integrals.transforms import InverseHankelTransform assert _test_args(InverseHankelTransform(2, x, y, 0)) def test_sympy__integrals__transforms__HankelTransform(): from sympy.integrals.transforms import HankelTransform assert _test_args(HankelTransform(2, x, y, 0)) @XFAIL def test_sympy__liealgebras__cartan_type__CartanType_generator(): from sympy.liealgebras.cartan_type import CartanType_generator assert _test_args(CartanType_generator("A2")) @XFAIL def test_sympy__liealgebras__cartan_type__Standard_Cartan(): from sympy.liealgebras.cartan_type import Standard_Cartan assert _test_args(Standard_Cartan("A", 2)) @XFAIL def test_sympy__liealgebras__weyl_group__WeylGroup(): from sympy.liealgebras.weyl_group import WeylGroup assert _test_args(WeylGroup("B4")) @XFAIL def test_sympy__liealgebras__root_system__RootSystem(): from sympy.liealgebras.root_system import RootSystem assert _test_args(RootSystem("A2")) @XFAIL def test_sympy__liealgebras__type_a__TypeA(): from sympy.liealgebras.type_a import TypeA assert _test_args(TypeA(2)) @XFAIL def test_sympy__liealgebras__type_b__TypeB(): from sympy.liealgebras.type_b import TypeB assert _test_args(TypeB(4)) @XFAIL def test_sympy__liealgebras__type_c__TypeC(): from sympy.liealgebras.type_c import TypeC assert _test_args(TypeC(4)) @XFAIL def test_sympy__liealgebras__type_d__TypeD(): from sympy.liealgebras.type_d import TypeD assert _test_args(TypeD(4)) @XFAIL def test_sympy__liealgebras__type_e__TypeE(): from sympy.liealgebras.type_e import TypeE assert _test_args(TypeE(6)) @XFAIL def test_sympy__liealgebras__type_f__TypeF(): from sympy.liealgebras.type_f import TypeF assert _test_args(TypeF(4)) @XFAIL def test_sympy__liealgebras__type_g__TypeG(): from sympy.liealgebras.type_g import TypeG assert _test_args(TypeG(2)) def test_sympy__logic__boolalg__And(): from sympy.logic.boolalg import And assert _test_args(And(x, y, 1)) @SKIP("abstract class") def test_sympy__logic__boolalg__Boolean(): pass def test_sympy__logic__boolalg__BooleanFunction(): from sympy.logic.boolalg import BooleanFunction assert _test_args(BooleanFunction(1, 2, 3)) @SKIP("abstract class") def test_sympy__logic__boolalg__BooleanAtom(): pass def test_sympy__logic__boolalg__BooleanTrue(): from sympy.logic.boolalg import true assert _test_args(true) def test_sympy__logic__boolalg__BooleanFalse(): from sympy.logic.boolalg import false assert _test_args(false) def test_sympy__logic__boolalg__Equivalent(): from sympy.logic.boolalg import Equivalent assert _test_args(Equivalent(x, 2)) def test_sympy__logic__boolalg__ITE(): from sympy.logic.boolalg import ITE assert _test_args(ITE(x, y, 1)) def test_sympy__logic__boolalg__Implies(): from sympy.logic.boolalg import Implies assert _test_args(Implies(x, y)) def test_sympy__logic__boolalg__Nand(): from sympy.logic.boolalg import Nand assert _test_args(Nand(x, y, 1)) def test_sympy__logic__boolalg__Nor(): from sympy.logic.boolalg import Nor assert _test_args(Nor(x, y)) def test_sympy__logic__boolalg__Not(): from sympy.logic.boolalg import Not assert _test_args(Not(x)) def test_sympy__logic__boolalg__Or(): from sympy.logic.boolalg import Or assert _test_args(Or(x, y)) def test_sympy__logic__boolalg__Xor(): from sympy.logic.boolalg import Xor assert _test_args(Xor(x, y, 2)) def test_sympy__logic__boolalg__Xnor(): from sympy.logic.boolalg import Xnor assert _test_args(Xnor(x, y, 2)) def test_sympy__logic__boolalg__Exclusive(): from sympy.logic.boolalg import Exclusive assert _test_args(Exclusive(x, y, z)) def test_sympy__matrices__matrices__DeferredVector(): from sympy.matrices.matrices import DeferredVector assert _test_args(DeferredVector("X")) @SKIP("abstract class") def test_sympy__matrices__expressions__matexpr__MatrixBase(): pass @SKIP("abstract class") def test_sympy__matrices__immutable__ImmutableRepMatrix(): pass def test_sympy__matrices__immutable__ImmutableDenseMatrix(): from sympy.matrices.immutable import ImmutableDenseMatrix m = ImmutableDenseMatrix([[1, 2], [3, 4]]) assert _test_args(m) assert _test_args(Basic(*list(m))) m = ImmutableDenseMatrix(1, 1, [1]) assert _test_args(m) assert _test_args(Basic(*list(m))) m = ImmutableDenseMatrix(2, 2, lambda i, j: 1) assert m[0, 0] is S.One m = ImmutableDenseMatrix(2, 2, lambda i, j: 1/(1 + i) + 1/(1 + j)) assert m[1, 1] is S.One # true div. will give 1.0 if i,j not sympified assert _test_args(m) assert _test_args(Basic(*list(m))) def test_sympy__matrices__immutable__ImmutableSparseMatrix(): from sympy.matrices.immutable import ImmutableSparseMatrix m = ImmutableSparseMatrix([[1, 2], [3, 4]]) assert _test_args(m) assert _test_args(Basic(*list(m))) m = ImmutableSparseMatrix(1, 1, {(0, 0): 1}) assert _test_args(m) assert _test_args(Basic(*list(m))) m = ImmutableSparseMatrix(1, 1, [1]) assert _test_args(m) assert _test_args(Basic(*list(m))) m = ImmutableSparseMatrix(2, 2, lambda i, j: 1) assert m[0, 0] is S.One m = ImmutableSparseMatrix(2, 2, lambda i, j: 1/(1 + i) + 1/(1 + j)) assert m[1, 1] is S.One # true div. will give 1.0 if i,j not sympified assert _test_args(m) assert _test_args(Basic(*list(m))) def test_sympy__matrices__expressions__slice__MatrixSlice(): from sympy.matrices.expressions.slice import MatrixSlice from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', 4, 4) assert _test_args(MatrixSlice(X, (0, 2), (0, 2))) def test_sympy__matrices__expressions__applyfunc__ElementwiseApplyFunction(): from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol("X", x, x) func = Lambda(x, x**2) assert _test_args(ElementwiseApplyFunction(func, X)) def test_sympy__matrices__expressions__blockmatrix__BlockDiagMatrix(): from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, x) Y = MatrixSymbol('Y', y, y) assert _test_args(BlockDiagMatrix(X, Y)) def test_sympy__matrices__expressions__blockmatrix__BlockMatrix(): from sympy.matrices.expressions.blockmatrix import BlockMatrix from sympy.matrices.expressions import MatrixSymbol, ZeroMatrix X = MatrixSymbol('X', x, x) Y = MatrixSymbol('Y', y, y) Z = MatrixSymbol('Z', x, y) O = ZeroMatrix(y, x) assert _test_args(BlockMatrix([[X, Z], [O, Y]])) def test_sympy__matrices__expressions__inverse__Inverse(): from sympy.matrices.expressions.inverse import Inverse from sympy.matrices.expressions import MatrixSymbol assert _test_args(Inverse(MatrixSymbol('A', 3, 3))) def test_sympy__matrices__expressions__matadd__MatAdd(): from sympy.matrices.expressions.matadd import MatAdd from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, y) Y = MatrixSymbol('Y', x, y) assert _test_args(MatAdd(X, Y)) @SKIP("abstract class") def test_sympy__matrices__expressions__matexpr__MatrixExpr(): pass def test_sympy__matrices__expressions__matexpr__MatrixElement(): from sympy.matrices.expressions.matexpr import MatrixSymbol, MatrixElement from sympy import S assert _test_args(MatrixElement(MatrixSymbol('A', 3, 5), S(2), S(3))) def test_sympy__matrices__expressions__matexpr__MatrixSymbol(): from sympy.matrices.expressions.matexpr import MatrixSymbol assert _test_args(MatrixSymbol('A', 3, 5)) def test_sympy__matrices__expressions__special__OneMatrix(): from sympy.matrices.expressions.special import OneMatrix assert _test_args(OneMatrix(3, 5)) def test_sympy__matrices__expressions__special__ZeroMatrix(): from sympy.matrices.expressions.special import ZeroMatrix assert _test_args(ZeroMatrix(3, 5)) def test_sympy__matrices__expressions__special__GenericZeroMatrix(): from sympy.matrices.expressions.special import GenericZeroMatrix assert _test_args(GenericZeroMatrix()) def test_sympy__matrices__expressions__special__Identity(): from sympy.matrices.expressions.special import Identity assert _test_args(Identity(3)) def test_sympy__matrices__expressions__special__GenericIdentity(): from sympy.matrices.expressions.special import GenericIdentity assert _test_args(GenericIdentity()) def test_sympy__matrices__expressions__sets__MatrixSet(): from sympy.matrices.expressions.sets import MatrixSet from sympy import S assert _test_args(MatrixSet(2, 2, S.Reals)) def test_sympy__matrices__expressions__matmul__MatMul(): from sympy.matrices.expressions.matmul import MatMul from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, y) Y = MatrixSymbol('Y', y, x) assert _test_args(MatMul(X, Y)) def test_sympy__matrices__expressions__dotproduct__DotProduct(): from sympy.matrices.expressions.dotproduct import DotProduct from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, 1) Y = MatrixSymbol('Y', x, 1) assert _test_args(DotProduct(X, Y)) def test_sympy__matrices__expressions__diagonal__DiagonalMatrix(): from sympy.matrices.expressions.diagonal import DiagonalMatrix from sympy.matrices.expressions import MatrixSymbol x = MatrixSymbol('x', 10, 1) assert _test_args(DiagonalMatrix(x)) def test_sympy__matrices__expressions__diagonal__DiagonalOf(): from sympy.matrices.expressions.diagonal import DiagonalOf from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('x', 10, 10) assert _test_args(DiagonalOf(X)) def test_sympy__matrices__expressions__diagonal__DiagMatrix(): from sympy.matrices.expressions.diagonal import DiagMatrix from sympy.matrices.expressions import MatrixSymbol x = MatrixSymbol('x', 10, 1) assert _test_args(DiagMatrix(x)) def test_sympy__matrices__expressions__hadamard__HadamardProduct(): from sympy.matrices.expressions.hadamard import HadamardProduct from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, y) Y = MatrixSymbol('Y', x, y) assert _test_args(HadamardProduct(X, Y)) def test_sympy__matrices__expressions__hadamard__HadamardPower(): from sympy.matrices.expressions.hadamard import HadamardPower from sympy.matrices.expressions import MatrixSymbol from sympy import Symbol X = MatrixSymbol('X', x, y) n = Symbol("n") assert _test_args(HadamardPower(X, n)) def test_sympy__matrices__expressions__kronecker__KroneckerProduct(): from sympy.matrices.expressions.kronecker import KroneckerProduct from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, y) Y = MatrixSymbol('Y', x, y) assert _test_args(KroneckerProduct(X, Y)) def test_sympy__matrices__expressions__matpow__MatPow(): from sympy.matrices.expressions.matpow import MatPow from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', x, x) assert _test_args(MatPow(X, 2)) def test_sympy__matrices__expressions__transpose__Transpose(): from sympy.matrices.expressions.transpose import Transpose from sympy.matrices.expressions import MatrixSymbol assert _test_args(Transpose(MatrixSymbol('A', 3, 5))) def test_sympy__matrices__expressions__adjoint__Adjoint(): from sympy.matrices.expressions.adjoint import Adjoint from sympy.matrices.expressions import MatrixSymbol assert _test_args(Adjoint(MatrixSymbol('A', 3, 5))) def test_sympy__matrices__expressions__trace__Trace(): from sympy.matrices.expressions.trace import Trace from sympy.matrices.expressions import MatrixSymbol assert _test_args(Trace(MatrixSymbol('A', 3, 3))) def test_sympy__matrices__expressions__determinant__Determinant(): from sympy.matrices.expressions.determinant import Determinant from sympy.matrices.expressions import MatrixSymbol assert _test_args(Determinant(MatrixSymbol('A', 3, 3))) def test_sympy__matrices__expressions__determinant__Permanent(): from sympy.matrices.expressions.determinant import Permanent from sympy.matrices.expressions import MatrixSymbol assert _test_args(Permanent(MatrixSymbol('A', 3, 4))) def test_sympy__matrices__expressions__funcmatrix__FunctionMatrix(): from sympy.matrices.expressions.funcmatrix import FunctionMatrix from sympy import symbols i, j = symbols('i,j') assert _test_args(FunctionMatrix(3, 3, Lambda((i, j), i - j) )) def test_sympy__matrices__expressions__fourier__DFT(): from sympy.matrices.expressions.fourier import DFT from sympy import S assert _test_args(DFT(S(2))) def test_sympy__matrices__expressions__fourier__IDFT(): from sympy.matrices.expressions.fourier import IDFT from sympy import S assert _test_args(IDFT(S(2))) from sympy.matrices.expressions import MatrixSymbol X = MatrixSymbol('X', 10, 10) def test_sympy__matrices__expressions__factorizations__LofLU(): from sympy.matrices.expressions.factorizations import LofLU assert _test_args(LofLU(X)) def test_sympy__matrices__expressions__factorizations__UofLU(): from sympy.matrices.expressions.factorizations import UofLU assert _test_args(UofLU(X)) def test_sympy__matrices__expressions__factorizations__QofQR(): from sympy.matrices.expressions.factorizations import QofQR assert _test_args(QofQR(X)) def test_sympy__matrices__expressions__factorizations__RofQR(): from sympy.matrices.expressions.factorizations import RofQR assert _test_args(RofQR(X)) def test_sympy__matrices__expressions__factorizations__LofCholesky(): from sympy.matrices.expressions.factorizations import LofCholesky assert _test_args(LofCholesky(X)) def test_sympy__matrices__expressions__factorizations__UofCholesky(): from sympy.matrices.expressions.factorizations import UofCholesky assert _test_args(UofCholesky(X)) def test_sympy__matrices__expressions__factorizations__EigenVectors(): from sympy.matrices.expressions.factorizations import EigenVectors assert _test_args(EigenVectors(X)) def test_sympy__matrices__expressions__factorizations__EigenValues(): from sympy.matrices.expressions.factorizations import EigenValues assert _test_args(EigenValues(X)) def test_sympy__matrices__expressions__factorizations__UofSVD(): from sympy.matrices.expressions.factorizations import UofSVD assert _test_args(UofSVD(X)) def test_sympy__matrices__expressions__factorizations__VofSVD(): from sympy.matrices.expressions.factorizations import VofSVD assert _test_args(VofSVD(X)) def test_sympy__matrices__expressions__factorizations__SofSVD(): from sympy.matrices.expressions.factorizations import SofSVD assert _test_args(SofSVD(X)) @SKIP("abstract class") def test_sympy__matrices__expressions__factorizations__Factorization(): pass def test_sympy__matrices__expressions__permutation__PermutationMatrix(): from sympy.combinatorics import Permutation from sympy.matrices.expressions.permutation import PermutationMatrix assert _test_args(PermutationMatrix(Permutation([2, 0, 1]))) def test_sympy__matrices__expressions__permutation__MatrixPermute(): from sympy.combinatorics import Permutation from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.matrices.expressions.permutation import MatrixPermute A = MatrixSymbol('A', 3, 3) assert _test_args(MatrixPermute(A, Permutation([2, 0, 1]))) def test_sympy__matrices__expressions__companion__CompanionMatrix(): from sympy.core.symbol import Symbol from sympy.matrices.expressions.companion import CompanionMatrix from sympy.polys.polytools import Poly x = Symbol('x') p = Poly([1, 2, 3], x) assert _test_args(CompanionMatrix(p)) def test_sympy__physics__vector__frame__CoordinateSym(): from sympy.physics.vector import CoordinateSym from sympy.physics.vector import ReferenceFrame assert _test_args(CoordinateSym('R_x', ReferenceFrame('R'), 0)) def test_sympy__physics__paulialgebra__Pauli(): from sympy.physics.paulialgebra import Pauli assert _test_args(Pauli(1)) def test_sympy__physics__quantum__anticommutator__AntiCommutator(): from sympy.physics.quantum.anticommutator import AntiCommutator assert _test_args(AntiCommutator(x, y)) def test_sympy__physics__quantum__cartesian__PositionBra3D(): from sympy.physics.quantum.cartesian import PositionBra3D assert _test_args(PositionBra3D(x, y, z)) def test_sympy__physics__quantum__cartesian__PositionKet3D(): from sympy.physics.quantum.cartesian import PositionKet3D assert _test_args(PositionKet3D(x, y, z)) def test_sympy__physics__quantum__cartesian__PositionState3D(): from sympy.physics.quantum.cartesian import PositionState3D assert _test_args(PositionState3D(x, y, z)) def test_sympy__physics__quantum__cartesian__PxBra(): from sympy.physics.quantum.cartesian import PxBra assert _test_args(PxBra(x, y, z)) def test_sympy__physics__quantum__cartesian__PxKet(): from sympy.physics.quantum.cartesian import PxKet assert _test_args(PxKet(x, y, z)) def test_sympy__physics__quantum__cartesian__PxOp(): from sympy.physics.quantum.cartesian import PxOp assert _test_args(PxOp(x, y, z)) def test_sympy__physics__quantum__cartesian__XBra(): from sympy.physics.quantum.cartesian import XBra assert _test_args(XBra(x)) def test_sympy__physics__quantum__cartesian__XKet(): from sympy.physics.quantum.cartesian import XKet assert _test_args(XKet(x)) def test_sympy__physics__quantum__cartesian__XOp(): from sympy.physics.quantum.cartesian import XOp assert _test_args(XOp(x)) def test_sympy__physics__quantum__cartesian__YOp(): from sympy.physics.quantum.cartesian import YOp assert _test_args(YOp(x)) def test_sympy__physics__quantum__cartesian__ZOp(): from sympy.physics.quantum.cartesian import ZOp assert _test_args(ZOp(x)) def test_sympy__physics__quantum__cg__CG(): from sympy.physics.quantum.cg import CG from sympy import S assert _test_args(CG(Rational(3, 2), Rational(3, 2), S.Half, Rational(-1, 2), 1, 1)) def test_sympy__physics__quantum__cg__Wigner3j(): from sympy.physics.quantum.cg import Wigner3j assert _test_args(Wigner3j(6, 0, 4, 0, 2, 0)) def test_sympy__physics__quantum__cg__Wigner6j(): from sympy.physics.quantum.cg import Wigner6j assert _test_args(Wigner6j(1, 2, 3, 2, 1, 2)) def test_sympy__physics__quantum__cg__Wigner9j(): from sympy.physics.quantum.cg import Wigner9j assert _test_args(Wigner9j(2, 1, 1, Rational(3, 2), S.Half, 1, S.Half, S.Half, 0)) def test_sympy__physics__quantum__circuitplot__Mz(): from sympy.physics.quantum.circuitplot import Mz assert _test_args(Mz(0)) def test_sympy__physics__quantum__circuitplot__Mx(): from sympy.physics.quantum.circuitplot import Mx assert _test_args(Mx(0)) def test_sympy__physics__quantum__commutator__Commutator(): from sympy.physics.quantum.commutator import Commutator A, B = symbols('A,B', commutative=False) assert _test_args(Commutator(A, B)) def test_sympy__physics__quantum__constants__HBar(): from sympy.physics.quantum.constants import HBar assert _test_args(HBar()) def test_sympy__physics__quantum__dagger__Dagger(): from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.state import Ket assert _test_args(Dagger(Dagger(Ket('psi')))) def test_sympy__physics__quantum__gate__CGate(): from sympy.physics.quantum.gate import CGate, Gate assert _test_args(CGate((0, 1), Gate(2))) def test_sympy__physics__quantum__gate__CGateS(): from sympy.physics.quantum.gate import CGateS, Gate assert _test_args(CGateS((0, 1), Gate(2))) def test_sympy__physics__quantum__gate__CNotGate(): from sympy.physics.quantum.gate import CNotGate assert _test_args(CNotGate(0, 1)) def test_sympy__physics__quantum__gate__Gate(): from sympy.physics.quantum.gate import Gate assert _test_args(Gate(0)) def test_sympy__physics__quantum__gate__HadamardGate(): from sympy.physics.quantum.gate import HadamardGate assert _test_args(HadamardGate(0)) def test_sympy__physics__quantum__gate__IdentityGate(): from sympy.physics.quantum.gate import IdentityGate assert _test_args(IdentityGate(0)) def test_sympy__physics__quantum__gate__OneQubitGate(): from sympy.physics.quantum.gate import OneQubitGate assert _test_args(OneQubitGate(0)) def test_sympy__physics__quantum__gate__PhaseGate(): from sympy.physics.quantum.gate import PhaseGate assert _test_args(PhaseGate(0)) def test_sympy__physics__quantum__gate__SwapGate(): from sympy.physics.quantum.gate import SwapGate assert _test_args(SwapGate(0, 1)) def test_sympy__physics__quantum__gate__TGate(): from sympy.physics.quantum.gate import TGate assert _test_args(TGate(0)) def test_sympy__physics__quantum__gate__TwoQubitGate(): from sympy.physics.quantum.gate import TwoQubitGate assert _test_args(TwoQubitGate(0)) def test_sympy__physics__quantum__gate__UGate(): from sympy.physics.quantum.gate import UGate from sympy.matrices.immutable import ImmutableDenseMatrix from sympy import Integer, Tuple assert _test_args( UGate(Tuple(Integer(1)), ImmutableDenseMatrix([[1, 0], [0, 2]]))) def test_sympy__physics__quantum__gate__XGate(): from sympy.physics.quantum.gate import XGate assert _test_args(XGate(0)) def test_sympy__physics__quantum__gate__YGate(): from sympy.physics.quantum.gate import YGate assert _test_args(YGate(0)) def test_sympy__physics__quantum__gate__ZGate(): from sympy.physics.quantum.gate import ZGate assert _test_args(ZGate(0)) @SKIP("TODO: sympy.physics") def test_sympy__physics__quantum__grover__OracleGate(): from sympy.physics.quantum.grover import OracleGate assert _test_args(OracleGate()) def test_sympy__physics__quantum__grover__WGate(): from sympy.physics.quantum.grover import WGate assert _test_args(WGate(1)) def test_sympy__physics__quantum__hilbert__ComplexSpace(): from sympy.physics.quantum.hilbert import ComplexSpace assert _test_args(ComplexSpace(x)) def test_sympy__physics__quantum__hilbert__DirectSumHilbertSpace(): from sympy.physics.quantum.hilbert import DirectSumHilbertSpace, ComplexSpace, FockSpace c = ComplexSpace(2) f = FockSpace() assert _test_args(DirectSumHilbertSpace(c, f)) def test_sympy__physics__quantum__hilbert__FockSpace(): from sympy.physics.quantum.hilbert import FockSpace assert _test_args(FockSpace()) def test_sympy__physics__quantum__hilbert__HilbertSpace(): from sympy.physics.quantum.hilbert import HilbertSpace assert _test_args(HilbertSpace()) def test_sympy__physics__quantum__hilbert__L2(): from sympy.physics.quantum.hilbert import L2 from sympy import oo, Interval assert _test_args(L2(Interval(0, oo))) def test_sympy__physics__quantum__hilbert__TensorPowerHilbertSpace(): from sympy.physics.quantum.hilbert import TensorPowerHilbertSpace, FockSpace f = FockSpace() assert _test_args(TensorPowerHilbertSpace(f, 2)) def test_sympy__physics__quantum__hilbert__TensorProductHilbertSpace(): from sympy.physics.quantum.hilbert import TensorProductHilbertSpace, FockSpace, ComplexSpace c = ComplexSpace(2) f = FockSpace() assert _test_args(TensorProductHilbertSpace(f, c)) def test_sympy__physics__quantum__innerproduct__InnerProduct(): from sympy.physics.quantum import Bra, Ket, InnerProduct b = Bra('b') k = Ket('k') assert _test_args(InnerProduct(b, k)) def test_sympy__physics__quantum__operator__DifferentialOperator(): from sympy.physics.quantum.operator import DifferentialOperator from sympy import Derivative, Function f = Function('f') assert _test_args(DifferentialOperator(1/x*Derivative(f(x), x), f(x))) def test_sympy__physics__quantum__operator__HermitianOperator(): from sympy.physics.quantum.operator import HermitianOperator assert _test_args(HermitianOperator('H')) def test_sympy__physics__quantum__operator__IdentityOperator(): from sympy.physics.quantum.operator import IdentityOperator assert _test_args(IdentityOperator(5)) def test_sympy__physics__quantum__operator__Operator(): from sympy.physics.quantum.operator import Operator assert _test_args(Operator('A')) def test_sympy__physics__quantum__operator__OuterProduct(): from sympy.physics.quantum.operator import OuterProduct from sympy.physics.quantum import Ket, Bra b = Bra('b') k = Ket('k') assert _test_args(OuterProduct(k, b)) def test_sympy__physics__quantum__operator__UnitaryOperator(): from sympy.physics.quantum.operator import UnitaryOperator assert _test_args(UnitaryOperator('U')) def test_sympy__physics__quantum__piab__PIABBra(): from sympy.physics.quantum.piab import PIABBra assert _test_args(PIABBra('B')) def test_sympy__physics__quantum__boson__BosonOp(): from sympy.physics.quantum.boson import BosonOp assert _test_args(BosonOp('a')) assert _test_args(BosonOp('a', False)) def test_sympy__physics__quantum__boson__BosonFockKet(): from sympy.physics.quantum.boson import BosonFockKet assert _test_args(BosonFockKet(1)) def test_sympy__physics__quantum__boson__BosonFockBra(): from sympy.physics.quantum.boson import BosonFockBra assert _test_args(BosonFockBra(1)) def test_sympy__physics__quantum__boson__BosonCoherentKet(): from sympy.physics.quantum.boson import BosonCoherentKet assert _test_args(BosonCoherentKet(1)) def test_sympy__physics__quantum__boson__BosonCoherentBra(): from sympy.physics.quantum.boson import BosonCoherentBra assert _test_args(BosonCoherentBra(1)) def test_sympy__physics__quantum__fermion__FermionOp(): from sympy.physics.quantum.fermion import FermionOp assert _test_args(FermionOp('c')) assert _test_args(FermionOp('c', False)) def test_sympy__physics__quantum__fermion__FermionFockKet(): from sympy.physics.quantum.fermion import FermionFockKet assert _test_args(FermionFockKet(1)) def test_sympy__physics__quantum__fermion__FermionFockBra(): from sympy.physics.quantum.fermion import FermionFockBra assert _test_args(FermionFockBra(1)) def test_sympy__physics__quantum__pauli__SigmaOpBase(): from sympy.physics.quantum.pauli import SigmaOpBase assert _test_args(SigmaOpBase()) def test_sympy__physics__quantum__pauli__SigmaX(): from sympy.physics.quantum.pauli import SigmaX assert _test_args(SigmaX()) def test_sympy__physics__quantum__pauli__SigmaY(): from sympy.physics.quantum.pauli import SigmaY assert _test_args(SigmaY()) def test_sympy__physics__quantum__pauli__SigmaZ(): from sympy.physics.quantum.pauli import SigmaZ assert _test_args(SigmaZ()) def test_sympy__physics__quantum__pauli__SigmaMinus(): from sympy.physics.quantum.pauli import SigmaMinus assert _test_args(SigmaMinus()) def test_sympy__physics__quantum__pauli__SigmaPlus(): from sympy.physics.quantum.pauli import SigmaPlus assert _test_args(SigmaPlus()) def test_sympy__physics__quantum__pauli__SigmaZKet(): from sympy.physics.quantum.pauli import SigmaZKet assert _test_args(SigmaZKet(0)) def test_sympy__physics__quantum__pauli__SigmaZBra(): from sympy.physics.quantum.pauli import SigmaZBra assert _test_args(SigmaZBra(0)) def test_sympy__physics__quantum__piab__PIABHamiltonian(): from sympy.physics.quantum.piab import PIABHamiltonian assert _test_args(PIABHamiltonian('P')) def test_sympy__physics__quantum__piab__PIABKet(): from sympy.physics.quantum.piab import PIABKet assert _test_args(PIABKet('K')) def test_sympy__physics__quantum__qexpr__QExpr(): from sympy.physics.quantum.qexpr import QExpr assert _test_args(QExpr(0)) def test_sympy__physics__quantum__qft__Fourier(): from sympy.physics.quantum.qft import Fourier assert _test_args(Fourier(0, 1)) def test_sympy__physics__quantum__qft__IQFT(): from sympy.physics.quantum.qft import IQFT assert _test_args(IQFT(0, 1)) def test_sympy__physics__quantum__qft__QFT(): from sympy.physics.quantum.qft import QFT assert _test_args(QFT(0, 1)) def test_sympy__physics__quantum__qft__RkGate(): from sympy.physics.quantum.qft import RkGate assert _test_args(RkGate(0, 1)) def test_sympy__physics__quantum__qubit__IntQubit(): from sympy.physics.quantum.qubit import IntQubit assert _test_args(IntQubit(0)) def test_sympy__physics__quantum__qubit__IntQubitBra(): from sympy.physics.quantum.qubit import IntQubitBra assert _test_args(IntQubitBra(0)) def test_sympy__physics__quantum__qubit__IntQubitState(): from sympy.physics.quantum.qubit import IntQubitState, QubitState assert _test_args(IntQubitState(QubitState(0, 1))) def test_sympy__physics__quantum__qubit__Qubit(): from sympy.physics.quantum.qubit import Qubit assert _test_args(Qubit(0, 0, 0)) def test_sympy__physics__quantum__qubit__QubitBra(): from sympy.physics.quantum.qubit import QubitBra assert _test_args(QubitBra('1', 0)) def test_sympy__physics__quantum__qubit__QubitState(): from sympy.physics.quantum.qubit import QubitState assert _test_args(QubitState(0, 1)) def test_sympy__physics__quantum__density__Density(): from sympy.physics.quantum.density import Density from sympy.physics.quantum.state import Ket assert _test_args(Density([Ket(0), 0.5], [Ket(1), 0.5])) @SKIP("TODO: sympy.physics.quantum.shor: Cmod Not Implemented") def test_sympy__physics__quantum__shor__CMod(): from sympy.physics.quantum.shor import CMod assert _test_args(CMod()) def test_sympy__physics__quantum__spin__CoupledSpinState(): from sympy.physics.quantum.spin import CoupledSpinState assert _test_args(CoupledSpinState(1, 0, (1, 1))) assert _test_args(CoupledSpinState(1, 0, (1, S.Half, S.Half))) assert _test_args(CoupledSpinState( 1, 0, (1, S.Half, S.Half), ((2, 3, S.Half), (1, 2, 1)) )) j, m, j1, j2, j3, j12, x = symbols('j m j1:4 j12 x') assert CoupledSpinState( j, m, (j1, j2, j3)).subs(j2, x) == CoupledSpinState(j, m, (j1, x, j3)) assert CoupledSpinState(j, m, (j1, j2, j3), ((1, 3, j12), (1, 2, j)) ).subs(j12, x) == \ CoupledSpinState(j, m, (j1, j2, j3), ((1, 3, x), (1, 2, j)) ) def test_sympy__physics__quantum__spin__J2Op(): from sympy.physics.quantum.spin import J2Op assert _test_args(J2Op('J')) def test_sympy__physics__quantum__spin__JminusOp(): from sympy.physics.quantum.spin import JminusOp assert _test_args(JminusOp('J')) def test_sympy__physics__quantum__spin__JplusOp(): from sympy.physics.quantum.spin import JplusOp assert _test_args(JplusOp('J')) def test_sympy__physics__quantum__spin__JxBra(): from sympy.physics.quantum.spin import JxBra assert _test_args(JxBra(1, 0)) def test_sympy__physics__quantum__spin__JxBraCoupled(): from sympy.physics.quantum.spin import JxBraCoupled assert _test_args(JxBraCoupled(1, 0, (1, 1))) def test_sympy__physics__quantum__spin__JxKet(): from sympy.physics.quantum.spin import JxKet assert _test_args(JxKet(1, 0)) def test_sympy__physics__quantum__spin__JxKetCoupled(): from sympy.physics.quantum.spin import JxKetCoupled assert _test_args(JxKetCoupled(1, 0, (1, 1))) def test_sympy__physics__quantum__spin__JxOp(): from sympy.physics.quantum.spin import JxOp assert _test_args(JxOp('J')) def test_sympy__physics__quantum__spin__JyBra(): from sympy.physics.quantum.spin import JyBra assert _test_args(JyBra(1, 0)) def test_sympy__physics__quantum__spin__JyBraCoupled(): from sympy.physics.quantum.spin import JyBraCoupled assert _test_args(JyBraCoupled(1, 0, (1, 1))) def test_sympy__physics__quantum__spin__JyKet(): from sympy.physics.quantum.spin import JyKet assert _test_args(JyKet(1, 0)) def test_sympy__physics__quantum__spin__JyKetCoupled(): from sympy.physics.quantum.spin import JyKetCoupled assert _test_args(JyKetCoupled(1, 0, (1, 1))) def test_sympy__physics__quantum__spin__JyOp(): from sympy.physics.quantum.spin import JyOp assert _test_args(JyOp('J')) def test_sympy__physics__quantum__spin__JzBra(): from sympy.physics.quantum.spin import JzBra assert _test_args(JzBra(1, 0)) def test_sympy__physics__quantum__spin__JzBraCoupled(): from sympy.physics.quantum.spin import JzBraCoupled assert _test_args(JzBraCoupled(1, 0, (1, 1))) def test_sympy__physics__quantum__spin__JzKet(): from sympy.physics.quantum.spin import JzKet assert _test_args(JzKet(1, 0)) def test_sympy__physics__quantum__spin__JzKetCoupled(): from sympy.physics.quantum.spin import JzKetCoupled assert _test_args(JzKetCoupled(1, 0, (1, 1))) def test_sympy__physics__quantum__spin__JzOp(): from sympy.physics.quantum.spin import JzOp assert _test_args(JzOp('J')) def test_sympy__physics__quantum__spin__Rotation(): from sympy.physics.quantum.spin import Rotation assert _test_args(Rotation(pi, 0, pi/2)) def test_sympy__physics__quantum__spin__SpinState(): from sympy.physics.quantum.spin import SpinState assert _test_args(SpinState(1, 0)) def test_sympy__physics__quantum__spin__WignerD(): from sympy.physics.quantum.spin import WignerD assert _test_args(WignerD(0, 1, 2, 3, 4, 5)) def test_sympy__physics__quantum__state__Bra(): from sympy.physics.quantum.state import Bra assert _test_args(Bra(0)) def test_sympy__physics__quantum__state__BraBase(): from sympy.physics.quantum.state import BraBase assert _test_args(BraBase(0)) def test_sympy__physics__quantum__state__Ket(): from sympy.physics.quantum.state import Ket assert _test_args(Ket(0)) def test_sympy__physics__quantum__state__KetBase(): from sympy.physics.quantum.state import KetBase assert _test_args(KetBase(0)) def test_sympy__physics__quantum__state__State(): from sympy.physics.quantum.state import State assert _test_args(State(0)) def test_sympy__physics__quantum__state__StateBase(): from sympy.physics.quantum.state import StateBase assert _test_args(StateBase(0)) def test_sympy__physics__quantum__state__OrthogonalBra(): from sympy.physics.quantum.state import OrthogonalBra assert _test_args(OrthogonalBra(0)) def test_sympy__physics__quantum__state__OrthogonalKet(): from sympy.physics.quantum.state import OrthogonalKet assert _test_args(OrthogonalKet(0)) def test_sympy__physics__quantum__state__OrthogonalState(): from sympy.physics.quantum.state import OrthogonalState assert _test_args(OrthogonalState(0)) def test_sympy__physics__quantum__state__TimeDepBra(): from sympy.physics.quantum.state import TimeDepBra assert _test_args(TimeDepBra('psi', 't')) def test_sympy__physics__quantum__state__TimeDepKet(): from sympy.physics.quantum.state import TimeDepKet assert _test_args(TimeDepKet('psi', 't')) def test_sympy__physics__quantum__state__TimeDepState(): from sympy.physics.quantum.state import TimeDepState assert _test_args(TimeDepState('psi', 't')) def test_sympy__physics__quantum__state__Wavefunction(): from sympy.physics.quantum.state import Wavefunction from sympy.functions import sin from sympy import Piecewise n = 1 L = 1 g = Piecewise((0, x < 0), (0, x > L), (sqrt(2//L)*sin(n*pi*x/L), True)) assert _test_args(Wavefunction(g, x)) def test_sympy__physics__quantum__tensorproduct__TensorProduct(): from sympy.physics.quantum.tensorproduct import TensorProduct assert _test_args(TensorProduct(x, y)) def test_sympy__physics__quantum__identitysearch__GateIdentity(): from sympy.physics.quantum.gate import X from sympy.physics.quantum.identitysearch import GateIdentity assert _test_args(GateIdentity(X(0), X(0))) def test_sympy__physics__quantum__sho1d__SHOOp(): from sympy.physics.quantum.sho1d import SHOOp assert _test_args(SHOOp('a')) def test_sympy__physics__quantum__sho1d__RaisingOp(): from sympy.physics.quantum.sho1d import RaisingOp assert _test_args(RaisingOp('a')) def test_sympy__physics__quantum__sho1d__LoweringOp(): from sympy.physics.quantum.sho1d import LoweringOp assert _test_args(LoweringOp('a')) def test_sympy__physics__quantum__sho1d__NumberOp(): from sympy.physics.quantum.sho1d import NumberOp assert _test_args(NumberOp('N')) def test_sympy__physics__quantum__sho1d__Hamiltonian(): from sympy.physics.quantum.sho1d import Hamiltonian assert _test_args(Hamiltonian('H')) def test_sympy__physics__quantum__sho1d__SHOState(): from sympy.physics.quantum.sho1d import SHOState assert _test_args(SHOState(0)) def test_sympy__physics__quantum__sho1d__SHOKet(): from sympy.physics.quantum.sho1d import SHOKet assert _test_args(SHOKet(0)) def test_sympy__physics__quantum__sho1d__SHOBra(): from sympy.physics.quantum.sho1d import SHOBra assert _test_args(SHOBra(0)) def test_sympy__physics__secondquant__AnnihilateBoson(): from sympy.physics.secondquant import AnnihilateBoson assert _test_args(AnnihilateBoson(0)) def test_sympy__physics__secondquant__AnnihilateFermion(): from sympy.physics.secondquant import AnnihilateFermion assert _test_args(AnnihilateFermion(0)) @SKIP("abstract class") def test_sympy__physics__secondquant__Annihilator(): pass def test_sympy__physics__secondquant__AntiSymmetricTensor(): from sympy.physics.secondquant import AntiSymmetricTensor i, j = symbols('i j', below_fermi=True) a, b = symbols('a b', above_fermi=True) assert _test_args(AntiSymmetricTensor('v', (a, i), (b, j))) def test_sympy__physics__secondquant__BosonState(): from sympy.physics.secondquant import BosonState assert _test_args(BosonState((0, 1))) @SKIP("abstract class") def test_sympy__physics__secondquant__BosonicOperator(): pass def test_sympy__physics__secondquant__Commutator(): from sympy.physics.secondquant import Commutator assert _test_args(Commutator(x, y)) def test_sympy__physics__secondquant__CreateBoson(): from sympy.physics.secondquant import CreateBoson assert _test_args(CreateBoson(0)) def test_sympy__physics__secondquant__CreateFermion(): from sympy.physics.secondquant import CreateFermion assert _test_args(CreateFermion(0)) @SKIP("abstract class") def test_sympy__physics__secondquant__Creator(): pass def test_sympy__physics__secondquant__Dagger(): from sympy.physics.secondquant import Dagger from sympy import I assert _test_args(Dagger(2*I)) def test_sympy__physics__secondquant__FermionState(): from sympy.physics.secondquant import FermionState assert _test_args(FermionState((0, 1))) def test_sympy__physics__secondquant__FermionicOperator(): from sympy.physics.secondquant import FermionicOperator assert _test_args(FermionicOperator(0)) def test_sympy__physics__secondquant__FockState(): from sympy.physics.secondquant import FockState assert _test_args(FockState((0, 1))) def test_sympy__physics__secondquant__FockStateBosonBra(): from sympy.physics.secondquant import FockStateBosonBra assert _test_args(FockStateBosonBra((0, 1))) def test_sympy__physics__secondquant__FockStateBosonKet(): from sympy.physics.secondquant import FockStateBosonKet assert _test_args(FockStateBosonKet((0, 1))) def test_sympy__physics__secondquant__FockStateBra(): from sympy.physics.secondquant import FockStateBra assert _test_args(FockStateBra((0, 1))) def test_sympy__physics__secondquant__FockStateFermionBra(): from sympy.physics.secondquant import FockStateFermionBra assert _test_args(FockStateFermionBra((0, 1))) def test_sympy__physics__secondquant__FockStateFermionKet(): from sympy.physics.secondquant import FockStateFermionKet assert _test_args(FockStateFermionKet((0, 1))) def test_sympy__physics__secondquant__FockStateKet(): from sympy.physics.secondquant import FockStateKet assert _test_args(FockStateKet((0, 1))) def test_sympy__physics__secondquant__InnerProduct(): from sympy.physics.secondquant import InnerProduct from sympy.physics.secondquant import FockStateKet, FockStateBra assert _test_args(InnerProduct(FockStateBra((0, 1)), FockStateKet((0, 1)))) def test_sympy__physics__secondquant__NO(): from sympy.physics.secondquant import NO, F, Fd assert _test_args(NO(Fd(x)*F(y))) def test_sympy__physics__secondquant__PermutationOperator(): from sympy.physics.secondquant import PermutationOperator assert _test_args(PermutationOperator(0, 1)) def test_sympy__physics__secondquant__SqOperator(): from sympy.physics.secondquant import SqOperator assert _test_args(SqOperator(0)) def test_sympy__physics__secondquant__TensorSymbol(): from sympy.physics.secondquant import TensorSymbol assert _test_args(TensorSymbol(x)) def test_sympy__physics__control__lti__LinearTimeInvariant(): # Direct instances of LinearTimeInvariant class are not allowed. # func(*args) tests for its derived classes (TransferFunction, # Series, Parallel and TransferFunctionMatrix) should pass. pass def test_sympy__physics__control__lti__SISOLinearTimeInvariant(): # Direct instances of SISOLinearTimeInvariant class are not allowed. pass def test_sympy__physics__control__lti__MIMOLinearTimeInvariant(): # Direct instances of MIMOLinearTimeInvariant class are not allowed. pass def test_sympy__physics__control__lti__TransferFunction(): from sympy.physics.control.lti import TransferFunction assert _test_args(TransferFunction(2, 3, x)) def test_sympy__physics__control__lti__Series(): from sympy.physics.control import Series, TransferFunction tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) assert _test_args(Series(tf1, tf2)) def test_sympy__physics__control__lti__MIMOSeries(): from sympy.physics.control import MIMOSeries, TransferFunction, TransferFunctionMatrix tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) tfm_1 = TransferFunctionMatrix([[tf2, tf1]]) tfm_2 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) tfm_3 = TransferFunctionMatrix([[tf1], [tf2]]) assert _test_args(MIMOSeries(tfm_3, tfm_2, tfm_1)) def test_sympy__physics__control__lti__Parallel(): from sympy.physics.control import Parallel, TransferFunction tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) assert _test_args(Parallel(tf1, tf2)) def test_sympy__physics__control__lti__MIMOParallel(): from sympy.physics.control import MIMOParallel, TransferFunction, TransferFunctionMatrix tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) assert _test_args(MIMOParallel(tfm_1, tfm_2)) def test_sympy__physics__control__lti__Feedback(): from sympy.physics.control import TransferFunction, Feedback tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) assert _test_args(Feedback(tf1, tf2)) assert _test_args(Feedback(tf1, tf2, 1)) def test_sympy__physics__control__lti__MIMOFeedback(): from sympy.physics.control import TransferFunction, MIMOFeedback, TransferFunctionMatrix tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) tfm_1 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) tfm_2 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) assert _test_args(MIMOFeedback(tfm_1, tfm_2)) assert _test_args(MIMOFeedback(tfm_1, tfm_2, 1)) def test_sympy__physics__control__lti__TransferFunctionMatrix(): from sympy.physics.control import TransferFunction, TransferFunctionMatrix tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) assert _test_args(TransferFunctionMatrix([[tf1, tf2]])) def test_sympy__physics__units__dimensions__Dimension(): from sympy.physics.units.dimensions import Dimension assert _test_args(Dimension("length", "L")) def test_sympy__physics__units__dimensions__DimensionSystem(): from sympy.physics.units.dimensions import DimensionSystem from sympy.physics.units.definitions.dimension_definitions import length, time, velocity assert _test_args(DimensionSystem((length, time), (velocity,))) def test_sympy__physics__units__quantities__Quantity(): from sympy.physics.units.quantities import Quantity assert _test_args(Quantity("dam")) def test_sympy__physics__units__prefixes__Prefix(): from sympy.physics.units.prefixes import Prefix assert _test_args(Prefix('kilo', 'k', 3)) def test_sympy__core__numbers__AlgebraicNumber(): from sympy.core.numbers import AlgebraicNumber assert _test_args(AlgebraicNumber(sqrt(2), [1, 2, 3])) def test_sympy__polys__polytools__GroebnerBasis(): from sympy.polys.polytools import GroebnerBasis assert _test_args(GroebnerBasis([x, y, z], x, y, z)) def test_sympy__polys__polytools__Poly(): from sympy.polys.polytools import Poly assert _test_args(Poly(2, x, y)) def test_sympy__polys__polytools__PurePoly(): from sympy.polys.polytools import PurePoly assert _test_args(PurePoly(2, x, y)) @SKIP('abstract class') def test_sympy__polys__rootoftools__RootOf(): pass def test_sympy__polys__rootoftools__ComplexRootOf(): from sympy.polys.rootoftools import ComplexRootOf assert _test_args(ComplexRootOf(x**3 + x + 1, 0)) def test_sympy__polys__rootoftools__RootSum(): from sympy.polys.rootoftools import RootSum assert _test_args(RootSum(x**3 + x + 1, sin)) def test_sympy__series__limits__Limit(): from sympy.series.limits import Limit assert _test_args(Limit(x, x, 0, dir='-')) def test_sympy__series__order__Order(): from sympy.series.order import Order assert _test_args(Order(1, x, y)) @SKIP('Abstract Class') def test_sympy__series__sequences__SeqBase(): pass def test_sympy__series__sequences__EmptySequence(): # Need to imort the instance from series not the class from # series.sequence from sympy.series import EmptySequence assert _test_args(EmptySequence) @SKIP('Abstract Class') def test_sympy__series__sequences__SeqExpr(): pass def test_sympy__series__sequences__SeqPer(): from sympy.series.sequences import SeqPer assert _test_args(SeqPer((1, 2, 3), (0, 10))) def test_sympy__series__sequences__SeqFormula(): from sympy.series.sequences import SeqFormula assert _test_args(SeqFormula(x**2, (0, 10))) def test_sympy__series__sequences__RecursiveSeq(): from sympy.series.sequences import RecursiveSeq y = Function("y") n = symbols("n") assert _test_args(RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, (0, 1))) assert _test_args(RecursiveSeq(y(n - 1) + y(n - 2), y(n), n)) def test_sympy__series__sequences__SeqExprOp(): from sympy.series.sequences import SeqExprOp, sequence s1 = sequence((1, 2, 3)) s2 = sequence(x**2) assert _test_args(SeqExprOp(s1, s2)) def test_sympy__series__sequences__SeqAdd(): from sympy.series.sequences import SeqAdd, sequence s1 = sequence((1, 2, 3)) s2 = sequence(x**2) assert _test_args(SeqAdd(s1, s2)) def test_sympy__series__sequences__SeqMul(): from sympy.series.sequences import SeqMul, sequence s1 = sequence((1, 2, 3)) s2 = sequence(x**2) assert _test_args(SeqMul(s1, s2)) @SKIP('Abstract Class') def test_sympy__series__series_class__SeriesBase(): pass def test_sympy__series__fourier__FourierSeries(): from sympy.series.fourier import fourier_series assert _test_args(fourier_series(x, (x, -pi, pi))) def test_sympy__series__fourier__FiniteFourierSeries(): from sympy.series.fourier import fourier_series assert _test_args(fourier_series(sin(pi*x), (x, -1, 1))) def test_sympy__series__formal__FormalPowerSeries(): from sympy.series.formal import fps assert _test_args(fps(log(1 + x), x)) def test_sympy__series__formal__Coeff(): from sympy.series.formal import fps assert _test_args(fps(x**2 + x + 1, x)) @SKIP('Abstract Class') def test_sympy__series__formal__FiniteFormalPowerSeries(): pass def test_sympy__series__formal__FormalPowerSeriesProduct(): from sympy.series.formal import fps f1, f2 = fps(sin(x)), fps(exp(x)) assert _test_args(f1.product(f2, x)) def test_sympy__series__formal__FormalPowerSeriesCompose(): from sympy.series.formal import fps f1, f2 = fps(exp(x)), fps(sin(x)) assert _test_args(f1.compose(f2, x)) def test_sympy__series__formal__FormalPowerSeriesInverse(): from sympy.series.formal import fps f1 = fps(exp(x)) assert _test_args(f1.inverse(x)) def test_sympy__simplify__hyperexpand__Hyper_Function(): from sympy.simplify.hyperexpand import Hyper_Function assert _test_args(Hyper_Function([2], [1])) def test_sympy__simplify__hyperexpand__G_Function(): from sympy.simplify.hyperexpand import G_Function assert _test_args(G_Function([2], [1], [], [])) @SKIP("abstract class") def test_sympy__tensor__array__ndim_array__ImmutableNDimArray(): pass def test_sympy__tensor__array__dense_ndim_array__ImmutableDenseNDimArray(): from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray densarr = ImmutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert _test_args(densarr) def test_sympy__tensor__array__sparse_ndim_array__ImmutableSparseNDimArray(): from sympy.tensor.array.sparse_ndim_array import ImmutableSparseNDimArray sparr = ImmutableSparseNDimArray(range(10, 34), (2, 3, 4)) assert _test_args(sparr) def test_sympy__tensor__array__array_comprehension__ArrayComprehension(): from sympy.tensor.array.array_comprehension import ArrayComprehension arrcom = ArrayComprehension(x, (x, 1, 5)) assert _test_args(arrcom) def test_sympy__tensor__array__array_comprehension__ArrayComprehensionMap(): from sympy.tensor.array.array_comprehension import ArrayComprehensionMap arrcomma = ArrayComprehensionMap(lambda: 0, (x, 1, 5)) assert _test_args(arrcomma) def test_sympy__tensor__array__arrayop__Flatten(): from sympy.tensor.array.arrayop import Flatten from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray fla = Flatten(ImmutableDenseNDimArray(range(24)).reshape(2, 3, 4)) assert _test_args(fla) def test_sympy__tensor__array__array_derivatives__ArrayDerivative(): from sympy.tensor.array.array_derivatives import ArrayDerivative A = MatrixSymbol("A", 2, 2) arrder = ArrayDerivative(A, A, evaluate=False) assert _test_args(arrder) def test_sympy__tensor__array__expressions__array_expressions__ArraySymbol(): from sympy.tensor.array.expressions.array_expressions import ArraySymbol m, n, k = symbols("m n k") array = ArraySymbol("A", m, n, k, 2) assert _test_args(array) def test_sympy__tensor__array__expressions__array_expressions__ArrayElement(): from sympy.tensor.array.expressions.array_expressions import ArrayElement m, n, k = symbols("m n k") ae = ArrayElement("A", (m, n, k, 2)) assert _test_args(ae) def test_sympy__tensor__array__expressions__array_expressions__ZeroArray(): from sympy.tensor.array.expressions.array_expressions import ZeroArray m, n, k = symbols("m n k") za = ZeroArray(m, n, k, 2) assert _test_args(za) def test_sympy__tensor__array__expressions__array_expressions__OneArray(): from sympy.tensor.array.expressions.array_expressions import OneArray m, n, k = symbols("m n k") za = OneArray(m, n, k, 2) assert _test_args(za) def test_sympy__tensor__functions__TensorProduct(): from sympy.tensor.functions import TensorProduct A = MatrixSymbol('A', 3, 3) B = MatrixSymbol('B', 3, 3) tp = TensorProduct(A, B) assert _test_args(tp) def test_sympy__tensor__indexed__Idx(): from sympy.tensor.indexed import Idx assert _test_args(Idx('test')) assert _test_args(Idx(1, (0, 10))) def test_sympy__tensor__indexed__Indexed(): from sympy.tensor.indexed import Indexed, Idx assert _test_args(Indexed('A', Idx('i'), Idx('j'))) def test_sympy__tensor__indexed__IndexedBase(): from sympy.tensor.indexed import IndexedBase assert _test_args(IndexedBase('A', shape=(x, y))) assert _test_args(IndexedBase('A', 1)) assert _test_args(IndexedBase('A')[0, 1]) def test_sympy__tensor__tensor__TensorIndexType(): from sympy.tensor.tensor import TensorIndexType assert _test_args(TensorIndexType('Lorentz')) @SKIP("deprecated class") def test_sympy__tensor__tensor__TensorType(): pass def test_sympy__tensor__tensor__TensorSymmetry(): from sympy.tensor.tensor import TensorSymmetry, get_symmetric_group_sgs assert _test_args(TensorSymmetry(get_symmetric_group_sgs(2))) def test_sympy__tensor__tensor__TensorHead(): from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, TensorHead Lorentz = TensorIndexType('Lorentz', dummy_name='L') sym = TensorSymmetry(get_symmetric_group_sgs(1)) assert _test_args(TensorHead('p', [Lorentz], sym, 0)) def test_sympy__tensor__tensor__TensorIndex(): from sympy.tensor.tensor import TensorIndexType, TensorIndex Lorentz = TensorIndexType('Lorentz', dummy_name='L') assert _test_args(TensorIndex('i', Lorentz)) @SKIP("abstract class") def test_sympy__tensor__tensor__TensExpr(): pass def test_sympy__tensor__tensor__TensAdd(): from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, tensor_indices, TensAdd, tensor_heads Lorentz = TensorIndexType('Lorentz', dummy_name='L') a, b = tensor_indices('a,b', Lorentz) sym = TensorSymmetry(get_symmetric_group_sgs(1)) p, q = tensor_heads('p,q', [Lorentz], sym) t1 = p(a) t2 = q(a) assert _test_args(TensAdd(t1, t2)) def test_sympy__tensor__tensor__Tensor(): from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, tensor_indices, TensorHead Lorentz = TensorIndexType('Lorentz', dummy_name='L') a, b = tensor_indices('a,b', Lorentz) sym = TensorSymmetry(get_symmetric_group_sgs(1)) p = TensorHead('p', [Lorentz], sym) assert _test_args(p(a)) def test_sympy__tensor__tensor__TensMul(): from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, tensor_indices, tensor_heads Lorentz = TensorIndexType('Lorentz', dummy_name='L') a, b = tensor_indices('a,b', Lorentz) sym = TensorSymmetry(get_symmetric_group_sgs(1)) p, q = tensor_heads('p, q', [Lorentz], sym) assert _test_args(3*p(a)*q(b)) def test_sympy__tensor__tensor__TensorElement(): from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorElement L = TensorIndexType("L") A = TensorHead("A", [L, L]) telem = TensorElement(A(x, y), {x: 1}) assert _test_args(telem) def test_sympy__tensor__toperators__PartialDerivative(): from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead from sympy.tensor.toperators import PartialDerivative Lorentz = TensorIndexType('Lorentz', dummy_name='L') a, b = tensor_indices('a,b', Lorentz) A = TensorHead("A", [Lorentz]) assert _test_args(PartialDerivative(A(a), A(b))) def test_as_coeff_add(): assert (7, (3*x, 4*x**2)) == (7 + 3*x + 4*x**2).as_coeff_add() def test_sympy__geometry__curve__Curve(): from sympy.geometry.curve import Curve assert _test_args(Curve((x, 1), (x, 0, 1))) def test_sympy__geometry__point__Point(): from sympy.geometry.point import Point assert _test_args(Point(0, 1)) def test_sympy__geometry__point__Point2D(): from sympy.geometry.point import Point2D assert _test_args(Point2D(0, 1)) def test_sympy__geometry__point__Point3D(): from sympy.geometry.point import Point3D assert _test_args(Point3D(0, 1, 2)) def test_sympy__geometry__ellipse__Ellipse(): from sympy.geometry.ellipse import Ellipse assert _test_args(Ellipse((0, 1), 2, 3)) def test_sympy__geometry__ellipse__Circle(): from sympy.geometry.ellipse import Circle assert _test_args(Circle((0, 1), 2)) def test_sympy__geometry__parabola__Parabola(): from sympy.geometry.parabola import Parabola from sympy.geometry.line import Line assert _test_args(Parabola((0, 0), Line((2, 3), (4, 3)))) @SKIP("abstract class") def test_sympy__geometry__line__LinearEntity(): pass def test_sympy__geometry__line__Line(): from sympy.geometry.line import Line assert _test_args(Line((0, 1), (2, 3))) def test_sympy__geometry__line__Ray(): from sympy.geometry.line import Ray assert _test_args(Ray((0, 1), (2, 3))) def test_sympy__geometry__line__Segment(): from sympy.geometry.line import Segment assert _test_args(Segment((0, 1), (2, 3))) @SKIP("abstract class") def test_sympy__geometry__line__LinearEntity2D(): pass def test_sympy__geometry__line__Line2D(): from sympy.geometry.line import Line2D assert _test_args(Line2D((0, 1), (2, 3))) def test_sympy__geometry__line__Ray2D(): from sympy.geometry.line import Ray2D assert _test_args(Ray2D((0, 1), (2, 3))) def test_sympy__geometry__line__Segment2D(): from sympy.geometry.line import Segment2D assert _test_args(Segment2D((0, 1), (2, 3))) @SKIP("abstract class") def test_sympy__geometry__line__LinearEntity3D(): pass def test_sympy__geometry__line__Line3D(): from sympy.geometry.line import Line3D assert _test_args(Line3D((0, 1, 1), (2, 3, 4))) def test_sympy__geometry__line__Segment3D(): from sympy.geometry.line import Segment3D assert _test_args(Segment3D((0, 1, 1), (2, 3, 4))) def test_sympy__geometry__line__Ray3D(): from sympy.geometry.line import Ray3D assert _test_args(Ray3D((0, 1, 1), (2, 3, 4))) def test_sympy__geometry__plane__Plane(): from sympy.geometry.plane import Plane assert _test_args(Plane((1, 1, 1), (-3, 4, -2), (1, 2, 3))) def test_sympy__geometry__polygon__Polygon(): from sympy.geometry.polygon import Polygon assert _test_args(Polygon((0, 1), (2, 3), (4, 5), (6, 7))) def test_sympy__geometry__polygon__RegularPolygon(): from sympy.geometry.polygon import RegularPolygon assert _test_args(RegularPolygon((0, 1), 2, 3, 4)) def test_sympy__geometry__polygon__Triangle(): from sympy.geometry.polygon import Triangle assert _test_args(Triangle((0, 1), (2, 3), (4, 5))) def test_sympy__geometry__entity__GeometryEntity(): from sympy.geometry.entity import GeometryEntity from sympy.geometry.point import Point assert _test_args(GeometryEntity(Point(1, 0), 1, [1, 2])) @SKIP("abstract class") def test_sympy__geometry__entity__GeometrySet(): pass def test_sympy__diffgeom__diffgeom__Manifold(): from sympy.diffgeom import Manifold assert _test_args(Manifold('name', 3)) def test_sympy__diffgeom__diffgeom__Patch(): from sympy.diffgeom import Manifold, Patch assert _test_args(Patch('name', Manifold('name', 3))) def test_sympy__diffgeom__diffgeom__CoordSystem(): from sympy.diffgeom import Manifold, Patch, CoordSystem assert _test_args(CoordSystem('name', Patch('name', Manifold('name', 3)))) assert _test_args(CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c])) def test_sympy__diffgeom__diffgeom__CoordinateSymbol(): from sympy.diffgeom import Manifold, Patch, CoordSystem, CoordinateSymbol assert _test_args(CoordinateSymbol(CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]), 0)) def test_sympy__diffgeom__diffgeom__Point(): from sympy.diffgeom import Manifold, Patch, CoordSystem, Point assert _test_args(Point( CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]), [x, y])) def test_sympy__diffgeom__diffgeom__BaseScalarField(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) assert _test_args(BaseScalarField(cs, 0)) def test_sympy__diffgeom__diffgeom__BaseVectorField(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseVectorField cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) assert _test_args(BaseVectorField(cs, 0)) def test_sympy__diffgeom__diffgeom__Differential(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) assert _test_args(Differential(BaseScalarField(cs, 0))) def test_sympy__diffgeom__diffgeom__Commutator(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseVectorField, Commutator cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) cs1 = CoordSystem('name1', Patch('name', Manifold('name', 3)), [a, b, c]) v = BaseVectorField(cs, 0) v1 = BaseVectorField(cs1, 0) assert _test_args(Commutator(v, v1)) def test_sympy__diffgeom__diffgeom__TensorProduct(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential, TensorProduct cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) d = Differential(BaseScalarField(cs, 0)) assert _test_args(TensorProduct(d, d)) def test_sympy__diffgeom__diffgeom__WedgeProduct(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential, WedgeProduct cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) d = Differential(BaseScalarField(cs, 0)) d1 = Differential(BaseScalarField(cs, 1)) assert _test_args(WedgeProduct(d, d1)) def test_sympy__diffgeom__diffgeom__LieDerivative(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential, BaseVectorField, LieDerivative cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) d = Differential(BaseScalarField(cs, 0)) v = BaseVectorField(cs, 0) assert _test_args(LieDerivative(v, d)) @XFAIL def test_sympy__diffgeom__diffgeom__BaseCovarDerivativeOp(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseCovarDerivativeOp cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) assert _test_args(BaseCovarDerivativeOp(cs, 0, [[[0, ]*3, ]*3, ]*3)) def test_sympy__diffgeom__diffgeom__CovarDerivativeOp(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseVectorField, CovarDerivativeOp cs = CoordSystem('name', Patch('name', Manifold('name', 3)), [a, b, c]) v = BaseVectorField(cs, 0) _test_args(CovarDerivativeOp(v, [[[0, ]*3, ]*3, ]*3)) def test_sympy__categories__baseclasses__Class(): from sympy.categories.baseclasses import Class assert _test_args(Class()) def test_sympy__categories__baseclasses__Object(): from sympy.categories import Object assert _test_args(Object("A")) @XFAIL def test_sympy__categories__baseclasses__Morphism(): from sympy.categories import Object, Morphism assert _test_args(Morphism(Object("A"), Object("B"))) def test_sympy__categories__baseclasses__IdentityMorphism(): from sympy.categories import Object, IdentityMorphism assert _test_args(IdentityMorphism(Object("A"))) def test_sympy__categories__baseclasses__NamedMorphism(): from sympy.categories import Object, NamedMorphism assert _test_args(NamedMorphism(Object("A"), Object("B"), "f")) def test_sympy__categories__baseclasses__CompositeMorphism(): from sympy.categories import Object, NamedMorphism, CompositeMorphism A = Object("A") B = Object("B") C = Object("C") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") assert _test_args(CompositeMorphism(f, g)) def test_sympy__categories__baseclasses__Diagram(): from sympy.categories import Object, NamedMorphism, Diagram A = Object("A") B = Object("B") f = NamedMorphism(A, B, "f") d = Diagram([f]) assert _test_args(d) def test_sympy__categories__baseclasses__Category(): from sympy.categories import Object, NamedMorphism, Diagram, Category A = Object("A") B = Object("B") C = Object("C") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") d1 = Diagram([f, g]) d2 = Diagram([f]) K = Category("K", commutative_diagrams=[d1, d2]) assert _test_args(K) def test_sympy__ntheory__factor___totient(): from sympy.ntheory.factor_ import totient k = symbols('k', integer=True) t = totient(k) assert _test_args(t) def test_sympy__ntheory__factor___reduced_totient(): from sympy.ntheory.factor_ import reduced_totient k = symbols('k', integer=True) t = reduced_totient(k) assert _test_args(t) def test_sympy__ntheory__factor___divisor_sigma(): from sympy.ntheory.factor_ import divisor_sigma k = symbols('k', integer=True) n = symbols('n', integer=True) t = divisor_sigma(n, k) assert _test_args(t) def test_sympy__ntheory__factor___udivisor_sigma(): from sympy.ntheory.factor_ import udivisor_sigma k = symbols('k', integer=True) n = symbols('n', integer=True) t = udivisor_sigma(n, k) assert _test_args(t) def test_sympy__ntheory__factor___primenu(): from sympy.ntheory.factor_ import primenu n = symbols('n', integer=True) t = primenu(n) assert _test_args(t) def test_sympy__ntheory__factor___primeomega(): from sympy.ntheory.factor_ import primeomega n = symbols('n', integer=True) t = primeomega(n) assert _test_args(t) def test_sympy__ntheory__residue_ntheory__mobius(): from sympy.ntheory import mobius assert _test_args(mobius(2)) def test_sympy__ntheory__generate__primepi(): from sympy.ntheory import primepi n = symbols('n') t = primepi(n) assert _test_args(t) def test_sympy__physics__optics__waves__TWave(): from sympy.physics.optics import TWave A, f, phi = symbols('A, f, phi') assert _test_args(TWave(A, f, phi)) def test_sympy__physics__optics__gaussopt__BeamParameter(): from sympy.physics.optics import BeamParameter assert _test_args(BeamParameter(530e-9, 1, w=1e-3)) def test_sympy__physics__optics__medium__Medium(): from sympy.physics.optics import Medium assert _test_args(Medium('m')) def test_sympy__tensor__array__expressions__array_expressions__ArrayContraction(): from sympy.tensor.array.expressions.array_expressions import ArrayContraction from sympy import IndexedBase A = symbols("A", cls=IndexedBase) assert _test_args(ArrayContraction(A, (0, 1))) def test_sympy__tensor__array__expressions__array_expressions__ArrayDiagonal(): from sympy.tensor.array.expressions.array_expressions import ArrayDiagonal from sympy import IndexedBase A = symbols("A", cls=IndexedBase) assert _test_args(ArrayDiagonal(A, (0, 1))) def test_sympy__tensor__array__expressions__array_expressions__ArrayTensorProduct(): from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct from sympy import IndexedBase A, B = symbols("A B", cls=IndexedBase) assert _test_args(ArrayTensorProduct(A, B)) def test_sympy__tensor__array__expressions__array_expressions__ArrayAdd(): from sympy.tensor.array.expressions.array_expressions import ArrayAdd from sympy import IndexedBase A, B = symbols("A B", cls=IndexedBase) assert _test_args(ArrayAdd(A, B)) def test_sympy__tensor__array__expressions__array_expressions__PermuteDims(): from sympy.tensor.array.expressions.array_expressions import PermuteDims A = MatrixSymbol("A", 4, 4) assert _test_args(PermuteDims(A, (1, 0))) def test_sympy__tensor__array__expressions__array_expressions__ArrayElementwiseApplyFunc(): from sympy.tensor.array.expressions.array_expressions import ArraySymbol, ArrayElementwiseApplyFunc A = ArraySymbol("A", 4) assert _test_args(ArrayElementwiseApplyFunc(exp, A)) def test_sympy__codegen__ast__Assignment(): from sympy.codegen.ast import Assignment assert _test_args(Assignment(x, y)) def test_sympy__codegen__cfunctions__expm1(): from sympy.codegen.cfunctions import expm1 assert _test_args(expm1(x)) def test_sympy__codegen__cfunctions__log1p(): from sympy.codegen.cfunctions import log1p assert _test_args(log1p(x)) def test_sympy__codegen__cfunctions__exp2(): from sympy.codegen.cfunctions import exp2 assert _test_args(exp2(x)) def test_sympy__codegen__cfunctions__log2(): from sympy.codegen.cfunctions import log2 assert _test_args(log2(x)) def test_sympy__codegen__cfunctions__fma(): from sympy.codegen.cfunctions import fma assert _test_args(fma(x, y, z)) def test_sympy__codegen__cfunctions__log10(): from sympy.codegen.cfunctions import log10 assert _test_args(log10(x)) def test_sympy__codegen__cfunctions__Sqrt(): from sympy.codegen.cfunctions import Sqrt assert _test_args(Sqrt(x)) def test_sympy__codegen__cfunctions__Cbrt(): from sympy.codegen.cfunctions import Cbrt assert _test_args(Cbrt(x)) def test_sympy__codegen__cfunctions__hypot(): from sympy.codegen.cfunctions import hypot assert _test_args(hypot(x, y)) def test_sympy__codegen__fnodes__FFunction(): from sympy.codegen.fnodes import FFunction assert _test_args(FFunction('f')) def test_sympy__codegen__fnodes__F95Function(): from sympy.codegen.fnodes import F95Function assert _test_args(F95Function('f')) def test_sympy__codegen__fnodes__isign(): from sympy.codegen.fnodes import isign assert _test_args(isign(1, x)) def test_sympy__codegen__fnodes__dsign(): from sympy.codegen.fnodes import dsign assert _test_args(dsign(1, x)) def test_sympy__codegen__fnodes__cmplx(): from sympy.codegen.fnodes import cmplx assert _test_args(cmplx(x, y)) def test_sympy__codegen__fnodes__kind(): from sympy.codegen.fnodes import kind assert _test_args(kind(x)) def test_sympy__codegen__fnodes__merge(): from sympy.codegen.fnodes import merge assert _test_args(merge(1, 2, Eq(x, 0))) def test_sympy__codegen__fnodes___literal(): from sympy.codegen.fnodes import _literal assert _test_args(_literal(1)) def test_sympy__codegen__fnodes__literal_sp(): from sympy.codegen.fnodes import literal_sp assert _test_args(literal_sp(1)) def test_sympy__codegen__fnodes__literal_dp(): from sympy.codegen.fnodes import literal_dp assert _test_args(literal_dp(1)) def test_sympy__codegen__matrix_nodes__MatrixSolve(): from sympy.matrices import MatrixSymbol from sympy.codegen.matrix_nodes import MatrixSolve A = MatrixSymbol('A', 3, 3) v = MatrixSymbol('x', 3, 1) assert _test_args(MatrixSolve(A, v)) def test_sympy__vector__coordsysrect__CoordSys3D(): from sympy.vector.coordsysrect import CoordSys3D assert _test_args(CoordSys3D('C')) def test_sympy__vector__point__Point(): from sympy.vector.point import Point assert _test_args(Point('P')) def test_sympy__vector__basisdependent__BasisDependent(): #from sympy.vector.basisdependent import BasisDependent #These classes have been created to maintain an OOP hierarchy #for Vectors and Dyadics. Are NOT meant to be initialized pass def test_sympy__vector__basisdependent__BasisDependentMul(): #from sympy.vector.basisdependent import BasisDependentMul #These classes have been created to maintain an OOP hierarchy #for Vectors and Dyadics. Are NOT meant to be initialized pass def test_sympy__vector__basisdependent__BasisDependentAdd(): #from sympy.vector.basisdependent import BasisDependentAdd #These classes have been created to maintain an OOP hierarchy #for Vectors and Dyadics. Are NOT meant to be initialized pass def test_sympy__vector__basisdependent__BasisDependentZero(): #from sympy.vector.basisdependent import BasisDependentZero #These classes have been created to maintain an OOP hierarchy #for Vectors and Dyadics. Are NOT meant to be initialized pass def test_sympy__vector__vector__BaseVector(): from sympy.vector.vector import BaseVector from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(BaseVector(0, C, ' ', ' ')) def test_sympy__vector__vector__VectorAdd(): from sympy.vector.vector import VectorAdd, VectorMul from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') from sympy.abc import a, b, c, x, y, z v1 = a*C.i + b*C.j + c*C.k v2 = x*C.i + y*C.j + z*C.k assert _test_args(VectorAdd(v1, v2)) assert _test_args(VectorMul(x, v1)) def test_sympy__vector__vector__VectorMul(): from sympy.vector.vector import VectorMul from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') from sympy.abc import a assert _test_args(VectorMul(a, C.i)) def test_sympy__vector__vector__VectorZero(): from sympy.vector.vector import VectorZero assert _test_args(VectorZero()) def test_sympy__vector__vector__Vector(): #from sympy.vector.vector import Vector #Vector is never to be initialized using args pass def test_sympy__vector__vector__Cross(): from sympy.vector.vector import Cross from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') _test_args(Cross(C.i, C.j)) def test_sympy__vector__vector__Dot(): from sympy.vector.vector import Dot from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') _test_args(Dot(C.i, C.j)) def test_sympy__vector__dyadic__Dyadic(): #from sympy.vector.dyadic import Dyadic #Dyadic is never to be initialized using args pass def test_sympy__vector__dyadic__BaseDyadic(): from sympy.vector.dyadic import BaseDyadic from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(BaseDyadic(C.i, C.j)) def test_sympy__vector__dyadic__DyadicMul(): from sympy.vector.dyadic import BaseDyadic, DyadicMul from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(DyadicMul(3, BaseDyadic(C.i, C.j))) def test_sympy__vector__dyadic__DyadicAdd(): from sympy.vector.dyadic import BaseDyadic, DyadicAdd from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(2 * DyadicAdd(BaseDyadic(C.i, C.i), BaseDyadic(C.i, C.j))) def test_sympy__vector__dyadic__DyadicZero(): from sympy.vector.dyadic import DyadicZero assert _test_args(DyadicZero()) def test_sympy__vector__deloperator__Del(): from sympy.vector.deloperator import Del assert _test_args(Del()) def test_sympy__vector__implicitregion__ImplicitRegion(): from sympy.vector.implicitregion import ImplicitRegion from sympy.abc import x, y assert _test_args(ImplicitRegion((x, y), y**3 - 4*x)) def test_sympy__vector__integrals__ParametricIntegral(): from sympy.vector.integrals import ParametricIntegral from sympy.vector.parametricregion import ParametricRegion from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(ParametricIntegral(C.y*C.i - 10*C.j,\ ParametricRegion((x, y), (x, 1, 3), (y, -2, 2)))) def test_sympy__vector__operators__Curl(): from sympy.vector.operators import Curl from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(Curl(C.i)) def test_sympy__vector__operators__Laplacian(): from sympy.vector.operators import Laplacian from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(Laplacian(C.i)) def test_sympy__vector__operators__Divergence(): from sympy.vector.operators import Divergence from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(Divergence(C.i)) def test_sympy__vector__operators__Gradient(): from sympy.vector.operators import Gradient from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(Gradient(C.x)) def test_sympy__vector__orienters__Orienter(): #from sympy.vector.orienters import Orienter #Not to be initialized pass def test_sympy__vector__orienters__ThreeAngleOrienter(): #from sympy.vector.orienters import ThreeAngleOrienter #Not to be initialized pass def test_sympy__vector__orienters__AxisOrienter(): from sympy.vector.orienters import AxisOrienter from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(AxisOrienter(x, C.i)) def test_sympy__vector__orienters__BodyOrienter(): from sympy.vector.orienters import BodyOrienter assert _test_args(BodyOrienter(x, y, z, '123')) def test_sympy__vector__orienters__SpaceOrienter(): from sympy.vector.orienters import SpaceOrienter assert _test_args(SpaceOrienter(x, y, z, '123')) def test_sympy__vector__orienters__QuaternionOrienter(): from sympy.vector.orienters import QuaternionOrienter a, b, c, d = symbols('a b c d') assert _test_args(QuaternionOrienter(a, b, c, d)) def test_sympy__vector__parametricregion__ParametricRegion(): from sympy.abc import t from sympy.vector.parametricregion import ParametricRegion assert _test_args(ParametricRegion((t, t**3), (t, 0, 2))) def test_sympy__vector__scalar__BaseScalar(): from sympy.vector.scalar import BaseScalar from sympy.vector.coordsysrect import CoordSys3D C = CoordSys3D('C') assert _test_args(BaseScalar(0, C, ' ', ' ')) def test_sympy__physics__wigner__Wigner3j(): from sympy.physics.wigner import Wigner3j assert _test_args(Wigner3j(0, 0, 0, 0, 0, 0)) def test_sympy__integrals__rubi__symbol__matchpyWC(): from sympy.integrals.rubi.symbol import matchpyWC assert _test_args(matchpyWC(1, True, 'a')) def test_sympy__integrals__rubi__utility_function__rubi_unevaluated_expr(): from sympy.integrals.rubi.utility_function import rubi_unevaluated_expr a = symbols('a') assert _test_args(rubi_unevaluated_expr(a)) def test_sympy__integrals__rubi__utility_function__rubi_exp(): from sympy.integrals.rubi.utility_function import rubi_exp assert _test_args(rubi_exp(5)) def test_sympy__integrals__rubi__utility_function__rubi_log(): from sympy.integrals.rubi.utility_function import rubi_log assert _test_args(rubi_log(5)) def test_sympy__integrals__rubi__utility_function__Int(): from sympy.integrals.rubi.utility_function import Int assert _test_args(Int(5, x)) def test_sympy__integrals__rubi__utility_function__Util_Coefficient(): from sympy.integrals.rubi.utility_function import Util_Coefficient a, x = symbols('a x') assert _test_args(Util_Coefficient(a, x)) def test_sympy__integrals__rubi__utility_function__Gamma(): from sympy.integrals.rubi.utility_function import Gamma assert _test_args(Gamma(5)) def test_sympy__integrals__rubi__utility_function__Util_Part(): from sympy.integrals.rubi.utility_function import Util_Part a, b = symbols('a b') assert _test_args(Util_Part(a + b, 0)) def test_sympy__integrals__rubi__utility_function__PolyGamma(): from sympy.integrals.rubi.utility_function import PolyGamma assert _test_args(PolyGamma(1, 1)) def test_sympy__integrals__rubi__utility_function__ProductLog(): from sympy.integrals.rubi.utility_function import ProductLog assert _test_args(ProductLog(1)) def test_sympy__combinatorics__schur_number__SchurNumber(): from sympy.combinatorics.schur_number import SchurNumber assert _test_args(SchurNumber(1)) def test_sympy__combinatorics__perm_groups__SymmetricPermutationGroup(): from sympy.combinatorics.perm_groups import SymmetricPermutationGroup assert _test_args(SymmetricPermutationGroup(5)) def test_sympy__combinatorics__perm_groups__Coset(): from sympy.combinatorics.permutations import Permutation from sympy.combinatorics.perm_groups import PermutationGroup, Coset a = Permutation(1, 2) b = Permutation(0, 1) G = PermutationGroup([a, b]) assert _test_args(Coset(a, G)) sympy-sympy-1.9/sympy/core/tests/test_arit.py000066400000000000000000002205711412543434000215550ustar00rootroot00000000000000from sympy import (Basic, Symbol, sin, cos, atan, exp, sqrt, Rational, Float, re, pi, sympify, Add, Mul, Pow, Mod, I, log, S, Max, symbols, oo, zoo, Integer, sign, im, nan, Dummy, factorial, comp, floor, Poly, FiniteSet ) from sympy.core.parameters import distribute from sympy.core.expr import unchanged from sympy.utilities.iterables import cartes from sympy.testing.pytest import XFAIL, raises, warns_deprecated_sympy from sympy.testing.randtest import verify_numerically from sympy.functions.elementary.trigonometric import asin a, c, x, y, z = symbols('a,c,x,y,z') b = Symbol("b", positive=True) def same_and_same_prec(a, b): # stricter matching for Floats return a == b and a._prec == b._prec def test_bug1(): assert re(x) != x x.series(x, 0, 1) assert re(x) != x def test_Symbol(): e = a*b assert e == a*b assert a*b*b == a*b**2 assert a*b*b + c == c + a*b**2 assert a*b*b - c == -c + a*b**2 x = Symbol('x', complex=True, real=False) assert x.is_imaginary is None # could be I or 1 + I x = Symbol('x', complex=True, imaginary=False) assert x.is_real is None # could be 1 or 1 + I x = Symbol('x', real=True) assert x.is_complex x = Symbol('x', imaginary=True) assert x.is_complex x = Symbol('x', real=False, imaginary=False) assert x.is_complex is None # might be a non-number def test_arit0(): p = Rational(5) e = a*b assert e == a*b e = a*b + b*a assert e == 2*a*b e = a*b + b*a + a*b + p*b*a assert e == 8*a*b e = a*b + b*a + a*b + p*b*a + a assert e == a + 8*a*b e = a + a assert e == 2*a e = a + b + a assert e == b + 2*a e = a + b*b + a + b*b assert e == 2*a + 2*b**2 e = a + Rational(2) + b*b + a + b*b + p assert e == 7 + 2*a + 2*b**2 e = (a + b*b + a + b*b)*p assert e == 5*(2*a + 2*b**2) e = (a*b*c + c*b*a + b*a*c)*p assert e == 15*a*b*c e = (a*b*c + c*b*a + b*a*c)*p - Rational(15)*a*b*c assert e == Rational(0) e = Rational(50)*(a - a) assert e == Rational(0) e = b*a - b - a*b + b assert e == Rational(0) e = a*b + c**p assert e == a*b + c**5 e = a/b assert e == a*b**(-1) e = a*2*2 assert e == 4*a e = 2 + a*2/2 assert e == 2 + a e = 2 - a - 2 assert e == -a e = 2*a*2 assert e == 4*a e = 2/a/2 assert e == a**(-1) e = 2**a**2 assert e == 2**(a**2) e = -(1 + a) assert e == -1 - a e = S.Half*(1 + a) assert e == S.Half + a/2 def test_div(): e = a/b assert e == a*b**(-1) e = a/b + c/2 assert e == a*b**(-1) + Rational(1)/2*c e = (1 - b)/(b - 1) assert e == (1 + -b)*((-1) + b)**(-1) def test_pow(): n1 = Rational(1) n2 = Rational(2) n5 = Rational(5) e = a*a assert e == a**2 e = a*a*a assert e == a**3 e = a*a*a*a**Rational(6) assert e == a**9 e = a*a*a*a**Rational(6) - a**Rational(9) assert e == Rational(0) e = a**(b - b) assert e == Rational(1) e = (a + Rational(1) - a)**b assert e == Rational(1) e = (a + b + c)**n2 assert e == (a + b + c)**2 assert e.expand() == 2*b*c + 2*a*c + 2*a*b + a**2 + c**2 + b**2 e = (a + b)**n2 assert e == (a + b)**2 assert e.expand() == 2*a*b + a**2 + b**2 e = (a + b)**(n1/n2) assert e == sqrt(a + b) assert e.expand() == sqrt(a + b) n = n5**(n1/n2) assert n == sqrt(5) e = n*a*b - n*b*a assert e == Rational(0) e = n*a*b + n*b*a assert e == 2*a*b*sqrt(5) assert e.diff(a) == 2*b*sqrt(5) assert e.diff(a) == 2*b*sqrt(5) e = a/b**2 assert e == a*b**(-2) assert sqrt(2*(1 + sqrt(2))) == (2*(1 + 2**S.Half))**S.Half x = Symbol('x') y = Symbol('y') assert ((x*y)**3).expand() == y**3 * x**3 assert ((x*y)**-3).expand() == y**-3 * x**-3 assert (x**5*(3*x)**(3)).expand() == 27 * x**8 assert (x**5*(-3*x)**(3)).expand() == -27 * x**8 assert (x**5*(3*x)**(-3)).expand() == x**2 * Rational(1, 27) assert (x**5*(-3*x)**(-3)).expand() == x**2 * Rational(-1, 27) # expand_power_exp assert (x**(y**(x + exp(x + y)) + z)).expand(deep=False) == \ x**z*x**(y**(x + exp(x + y))) assert (x**(y**(x + exp(x + y)) + z)).expand() == \ x**z*x**(y**x*y**(exp(x)*exp(y))) n = Symbol('n', even=False) k = Symbol('k', even=True) o = Symbol('o', odd=True) assert unchanged(Pow, -1, x) assert unchanged(Pow, -1, n) assert (-2)**k == 2**k assert (-1)**k == 1 assert (-1)**o == -1 def test_pow2(): # x**(2*y) is always (x**y)**2 but is only (x**2)**y if # x.is_positive or y.is_integer # let x = 1 to see why the following are not true. assert (-x)**Rational(2, 3) != x**Rational(2, 3) assert (-x)**Rational(5, 7) != -x**Rational(5, 7) assert ((-x)**2)**Rational(1, 3) != ((-x)**Rational(1, 3))**2 assert sqrt(x**2) != x def test_pow3(): assert sqrt(2)**3 == 2 * sqrt(2) assert sqrt(2)**3 == sqrt(8) def test_mod_pow(): for s, t, u, v in [(4, 13, 497, 445), (4, -3, 497, 365), (3.2, 2.1, 1.9, 0.1031015682350942), (S(3)/2, 5, S(5)/6, S(3)/32)]: assert pow(S(s), t, u) == v assert pow(S(s), S(t), u) == v assert pow(S(s), t, S(u)) == v assert pow(S(s), S(t), S(u)) == v assert pow(S(2), S(10000000000), S(3)) == 1 assert pow(x, y, z) == x**y%z raises(TypeError, lambda: pow(S(4), "13", 497)) raises(TypeError, lambda: pow(S(4), 13, "497")) def test_pow_E(): assert 2**(y/log(2)) == S.Exp1**y assert 2**(y/log(2)/3) == S.Exp1**(y/3) assert 3**(1/log(-3)) != S.Exp1 assert (3 + 2*I)**(1/(log(-3 - 2*I) + I*pi)) == S.Exp1 assert (4 + 2*I)**(1/(log(-4 - 2*I) + I*pi)) == S.Exp1 assert (3 + 2*I)**(1/(log(-3 - 2*I, 3)/2 + I*pi/log(3)/2)) == 9 assert (3 + 2*I)**(1/(log(3 + 2*I, 3)/2)) == 9 # every time tests are run they will affirm with a different random # value that this identity holds while 1: b = x._random() r, i = b.as_real_imag() if i: break assert verify_numerically(b**(1/(log(-b) + sign(i)*I*pi).n()), S.Exp1) def test_pow_issue_3516(): assert 4**Rational(1, 4) == sqrt(2) def test_pow_im(): for m in (-2, -1, 2): for d in (3, 4, 5): b = m*I for i in range(1, 4*d + 1): e = Rational(i, d) assert (b**e - b.n()**e.n()).n(2, chop=1e-10) == 0 e = Rational(7, 3) assert (2*x*I)**e == 4*2**Rational(1, 3)*(I*x)**e # same as Wolfram Alpha im = symbols('im', imaginary=True) assert (2*im*I)**e == 4*2**Rational(1, 3)*(I*im)**e args = [I, I, I, I, 2] e = Rational(1, 3) ans = 2**e assert Mul(*args, evaluate=False)**e == ans assert Mul(*args)**e == ans args = [I, I, I, 2] e = Rational(1, 3) ans = 2**e*(-I)**e assert Mul(*args, evaluate=False)**e == ans assert Mul(*args)**e == ans args.append(-3) ans = (6*I)**e assert Mul(*args, evaluate=False)**e == ans assert Mul(*args)**e == ans args.append(-1) ans = (-6*I)**e assert Mul(*args, evaluate=False)**e == ans assert Mul(*args)**e == ans args = [I, I, 2] e = Rational(1, 3) ans = (-2)**e assert Mul(*args, evaluate=False)**e == ans assert Mul(*args)**e == ans args.append(-3) ans = (6)**e assert Mul(*args, evaluate=False)**e == ans assert Mul(*args)**e == ans args.append(-1) ans = (-6)**e assert Mul(*args, evaluate=False)**e == ans assert Mul(*args)**e == ans assert Mul(Pow(-1, Rational(3, 2), evaluate=False), I, I) == I assert Mul(I*Pow(I, S.Half, evaluate=False)) == sqrt(I)*I def test_real_mul(): assert Float(0) * pi * x == 0 assert set((Float(1) * pi * x).args) == {Float(1), pi, x} def test_ncmul(): A = Symbol("A", commutative=False) B = Symbol("B", commutative=False) C = Symbol("C", commutative=False) assert A*B != B*A assert A*B*C != C*B*A assert A*b*B*3*C == 3*b*A*B*C assert A*b*B*3*C != 3*b*B*A*C assert A*b*B*3*C == 3*A*B*C*b assert A + B == B + A assert (A + B)*C != C*(A + B) assert C*(A + B)*C != C*C*(A + B) assert A*A == A**2 assert (A + B)*(A + B) == (A + B)**2 assert A**-1 * A == 1 assert A/A == 1 assert A/(A**2) == 1/A assert A/(1 + A) == A/(1 + A) assert set((A + B + 2*(A + B)).args) == \ {A, B, 2*(A + B)} def test_mul_add_identity(): m = Mul(1, 2) assert isinstance(m, Rational) and m.p == 2 and m.q == 1 m = Mul(1, 2, evaluate=False) assert isinstance(m, Mul) and m.args == (1, 2) m = Mul(0, 1) assert m is S.Zero m = Mul(0, 1, evaluate=False) assert isinstance(m, Mul) and m.args == (0, 1) m = Add(0, 1) assert m is S.One m = Add(0, 1, evaluate=False) assert isinstance(m, Add) and m.args == (0, 1) def test_ncpow(): x = Symbol('x', commutative=False) y = Symbol('y', commutative=False) z = Symbol('z', commutative=False) a = Symbol('a') b = Symbol('b') c = Symbol('c') assert (x**2)*(y**2) != (y**2)*(x**2) assert (x**-2)*y != y*(x**2) assert 2**x*2**y != 2**(x + y) assert 2**x*2**y*2**z != 2**(x + y + z) assert 2**x*2**(2*x) == 2**(3*x) assert 2**x*2**(2*x)*2**x == 2**(4*x) assert exp(x)*exp(y) != exp(y)*exp(x) assert exp(x)*exp(y)*exp(z) != exp(y)*exp(x)*exp(z) assert exp(x)*exp(y)*exp(z) != exp(x + y + z) assert x**a*x**b != x**(a + b) assert x**a*x**b*x**c != x**(a + b + c) assert x**3*x**4 == x**7 assert x**3*x**4*x**2 == x**9 assert x**a*x**(4*a) == x**(5*a) assert x**a*x**(4*a)*x**a == x**(6*a) def test_powerbug(): x = Symbol("x") assert x**1 != (-x)**1 assert x**2 == (-x)**2 assert x**3 != (-x)**3 assert x**4 == (-x)**4 assert x**5 != (-x)**5 assert x**6 == (-x)**6 assert x**128 == (-x)**128 assert x**129 != (-x)**129 assert (2*x)**2 == (-2*x)**2 def test_Mul_doesnt_expand_exp(): x = Symbol('x') y = Symbol('y') assert unchanged(Mul, exp(x), exp(y)) assert unchanged(Mul, 2**x, 2**y) assert x**2*x**3 == x**5 assert 2**x*3**x == 6**x assert x**(y)*x**(2*y) == x**(3*y) assert sqrt(2)*sqrt(2) == 2 assert 2**x*2**(2*x) == 2**(3*x) assert sqrt(2)*2**Rational(1, 4)*5**Rational(3, 4) == 10**Rational(3, 4) assert (x**(-log(5)/log(3))*x)/(x*x**( - log(5)/log(3))) == sympify(1) def test_Mul_is_integer(): k = Symbol('k', integer=True) n = Symbol('n', integer=True) nr = Symbol('nr', rational=False) nz = Symbol('nz', integer=True, zero=False) e = Symbol('e', even=True) o = Symbol('o', odd=True) i2 = Symbol('2', prime=True, even=True) assert (k/3).is_integer is None assert (nz/3).is_integer is None assert (nr/3).is_integer is False assert (x*k*n).is_integer is None assert (e/2).is_integer is True assert (e**2/2).is_integer is True assert (2/k).is_integer is None assert (2/k**2).is_integer is None assert ((-1)**k*n).is_integer is True assert (3*k*e/2).is_integer is True assert (2*k*e/3).is_integer is None assert (e/o).is_integer is None assert (o/e).is_integer is False assert (o/i2).is_integer is False assert Mul(k, 1/k, evaluate=False).is_integer is None assert Mul(2., S.Half, evaluate=False).is_integer is None assert (2*sqrt(k)).is_integer is None assert (2*k**n).is_integer is None s = 2**2**2**Pow(2, 1000, evaluate=False) m = Mul(s, s, evaluate=False) assert m.is_integer # broken in 1.6 and before, see #20161 xq = Symbol('xq', rational=True) yq = Symbol('yq', rational=True) assert (xq*yq).is_integer is None e_20161 = Mul(-1,Mul(1,Pow(2,-1,evaluate=False),evaluate=False),evaluate=False) assert e_20161.is_integer is not True # expand(e_20161) -> -1/2, but no need to see that in the assumption without evaluation def test_Add_Mul_is_integer(): x = Symbol('x') k = Symbol('k', integer=True) n = Symbol('n', integer=True) nk = Symbol('nk', integer=False) nr = Symbol('nr', rational=False) nz = Symbol('nz', integer=True, zero=False) assert (-nk).is_integer is None assert (-nr).is_integer is False assert (2*k).is_integer is True assert (-k).is_integer is True assert (k + nk).is_integer is False assert (k + n).is_integer is True assert (k + x).is_integer is None assert (k + n*x).is_integer is None assert (k + n/3).is_integer is None assert (k + nz/3).is_integer is None assert (k + nr/3).is_integer is False assert ((1 + sqrt(3))*(-sqrt(3) + 1)).is_integer is not False assert (1 + (1 + sqrt(3))*(-sqrt(3) + 1)).is_integer is not False def test_Add_Mul_is_finite(): x = Symbol('x', extended_real=True, finite=False) assert sin(x).is_finite is True assert (x*sin(x)).is_finite is None assert (x*atan(x)).is_finite is False assert (1024*sin(x)).is_finite is True assert (sin(x)*exp(x)).is_finite is None assert (sin(x)*cos(x)).is_finite is True assert (x*sin(x)*exp(x)).is_finite is None assert (sin(x) - 67).is_finite is True assert (sin(x) + exp(x)).is_finite is not True assert (1 + x).is_finite is False assert (1 + x**2 + (1 + x)*(1 - x)).is_finite is None assert (sqrt(2)*(1 + x)).is_finite is False assert (sqrt(2)*(1 + x)*(1 - x)).is_finite is False def test_Mul_is_even_odd(): x = Symbol('x', integer=True) y = Symbol('y', integer=True) k = Symbol('k', odd=True) n = Symbol('n', odd=True) m = Symbol('m', even=True) assert (2*x).is_even is True assert (2*x).is_odd is False assert (3*x).is_even is None assert (3*x).is_odd is None assert (k/3).is_integer is None assert (k/3).is_even is None assert (k/3).is_odd is None assert (2*n).is_even is True assert (2*n).is_odd is False assert (2*m).is_even is True assert (2*m).is_odd is False assert (-n).is_even is False assert (-n).is_odd is True assert (k*n).is_even is False assert (k*n).is_odd is True assert (k*m).is_even is True assert (k*m).is_odd is False assert (k*n*m).is_even is True assert (k*n*m).is_odd is False assert (k*m*x).is_even is True assert (k*m*x).is_odd is False # issue 6791: assert (x/2).is_integer is None assert (k/2).is_integer is False assert (m/2).is_integer is True assert (x*y).is_even is None assert (x*x).is_even is None assert (x*(x + k)).is_even is True assert (x*(x + m)).is_even is None assert (x*y).is_odd is None assert (x*x).is_odd is None assert (x*(x + k)).is_odd is False assert (x*(x + m)).is_odd is None # issue 8648 assert (m**2/2).is_even assert (m**2/3).is_even is False assert (2/m**2).is_odd is False assert (2/m).is_odd is None @XFAIL def test_evenness_in_ternary_integer_product_with_odd(): # Tests that oddness inference is independent of term ordering. # Term ordering at the point of testing depends on SymPy's symbol order, so # we try to force a different order by modifying symbol names. x = Symbol('x', integer=True) y = Symbol('y', integer=True) k = Symbol('k', odd=True) assert (x*y*(y + k)).is_even is True assert (y*x*(x + k)).is_even is True def test_evenness_in_ternary_integer_product_with_even(): x = Symbol('x', integer=True) y = Symbol('y', integer=True) m = Symbol('m', even=True) assert (x*y*(y + m)).is_even is None @XFAIL def test_oddness_in_ternary_integer_product_with_odd(): # Tests that oddness inference is independent of term ordering. # Term ordering at the point of testing depends on SymPy's symbol order, so # we try to force a different order by modifying symbol names. x = Symbol('x', integer=True) y = Symbol('y', integer=True) k = Symbol('k', odd=True) assert (x*y*(y + k)).is_odd is False assert (y*x*(x + k)).is_odd is False def test_oddness_in_ternary_integer_product_with_even(): x = Symbol('x', integer=True) y = Symbol('y', integer=True) m = Symbol('m', even=True) assert (x*y*(y + m)).is_odd is None def test_Mul_is_rational(): x = Symbol('x') n = Symbol('n', integer=True) m = Symbol('m', integer=True, nonzero=True) assert (n/m).is_rational is True assert (x/pi).is_rational is None assert (x/n).is_rational is None assert (m/pi).is_rational is False r = Symbol('r', rational=True) assert (pi*r).is_rational is None # issue 8008 z = Symbol('z', zero=True) i = Symbol('i', imaginary=True) assert (z*i).is_rational is True bi = Symbol('i', imaginary=True, finite=True) assert (z*bi).is_zero is True def test_Add_is_rational(): x = Symbol('x') n = Symbol('n', rational=True) m = Symbol('m', rational=True) assert (n + m).is_rational is True assert (x + pi).is_rational is None assert (x + n).is_rational is None assert (n + pi).is_rational is False def test_Add_is_even_odd(): x = Symbol('x', integer=True) k = Symbol('k', odd=True) n = Symbol('n', odd=True) m = Symbol('m', even=True) assert (k + 7).is_even is True assert (k + 7).is_odd is False assert (-k + 7).is_even is True assert (-k + 7).is_odd is False assert (k - 12).is_even is False assert (k - 12).is_odd is True assert (-k - 12).is_even is False assert (-k - 12).is_odd is True assert (k + n).is_even is True assert (k + n).is_odd is False assert (k + m).is_even is False assert (k + m).is_odd is True assert (k + n + m).is_even is True assert (k + n + m).is_odd is False assert (k + n + x + m).is_even is None assert (k + n + x + m).is_odd is None def test_Mul_is_negative_positive(): x = Symbol('x', real=True) y = Symbol('y', extended_real=False, complex=True) z = Symbol('z', zero=True) e = 2*z assert e.is_Mul and e.is_positive is False and e.is_negative is False neg = Symbol('neg', negative=True) pos = Symbol('pos', positive=True) nneg = Symbol('nneg', nonnegative=True) npos = Symbol('npos', nonpositive=True) assert neg.is_negative is True assert (-neg).is_negative is False assert (2*neg).is_negative is True assert (2*pos)._eval_is_extended_negative() is False assert (2*pos).is_negative is False assert pos.is_negative is False assert (-pos).is_negative is True assert (2*pos).is_negative is False assert (pos*neg).is_negative is True assert (2*pos*neg).is_negative is True assert (-pos*neg).is_negative is False assert (pos*neg*y).is_negative is False # y.is_real=F; !real -> !neg assert nneg.is_negative is False assert (-nneg).is_negative is None assert (2*nneg).is_negative is False assert npos.is_negative is None assert (-npos).is_negative is False assert (2*npos).is_negative is None assert (nneg*npos).is_negative is None assert (neg*nneg).is_negative is None assert (neg*npos).is_negative is False assert (pos*nneg).is_negative is False assert (pos*npos).is_negative is None assert (npos*neg*nneg).is_negative is False assert (npos*pos*nneg).is_negative is None assert (-npos*neg*nneg).is_negative is None assert (-npos*pos*nneg).is_negative is False assert (17*npos*neg*nneg).is_negative is False assert (17*npos*pos*nneg).is_negative is None assert (neg*npos*pos*nneg).is_negative is False assert (x*neg).is_negative is None assert (nneg*npos*pos*x*neg).is_negative is None assert neg.is_positive is False assert (-neg).is_positive is True assert (2*neg).is_positive is False assert pos.is_positive is True assert (-pos).is_positive is False assert (2*pos).is_positive is True assert (pos*neg).is_positive is False assert (2*pos*neg).is_positive is False assert (-pos*neg).is_positive is True assert (-pos*neg*y).is_positive is False # y.is_real=F; !real -> !neg assert nneg.is_positive is None assert (-nneg).is_positive is False assert (2*nneg).is_positive is None assert npos.is_positive is False assert (-npos).is_positive is None assert (2*npos).is_positive is False assert (nneg*npos).is_positive is False assert (neg*nneg).is_positive is False assert (neg*npos).is_positive is None assert (pos*nneg).is_positive is None assert (pos*npos).is_positive is False assert (npos*neg*nneg).is_positive is None assert (npos*pos*nneg).is_positive is False assert (-npos*neg*nneg).is_positive is False assert (-npos*pos*nneg).is_positive is None assert (17*npos*neg*nneg).is_positive is None assert (17*npos*pos*nneg).is_positive is False assert (neg*npos*pos*nneg).is_positive is None assert (x*neg).is_positive is None assert (nneg*npos*pos*x*neg).is_positive is None def test_Mul_is_negative_positive_2(): a = Symbol('a', nonnegative=True) b = Symbol('b', nonnegative=True) c = Symbol('c', nonpositive=True) d = Symbol('d', nonpositive=True) assert (a*b).is_nonnegative is True assert (a*b).is_negative is False assert (a*b).is_zero is None assert (a*b).is_positive is None assert (c*d).is_nonnegative is True assert (c*d).is_negative is False assert (c*d).is_zero is None assert (c*d).is_positive is None assert (a*c).is_nonpositive is True assert (a*c).is_positive is False assert (a*c).is_zero is None assert (a*c).is_negative is None def test_Mul_is_nonpositive_nonnegative(): x = Symbol('x', real=True) k = Symbol('k', negative=True) n = Symbol('n', positive=True) u = Symbol('u', nonnegative=True) v = Symbol('v', nonpositive=True) assert k.is_nonpositive is True assert (-k).is_nonpositive is False assert (2*k).is_nonpositive is True assert n.is_nonpositive is False assert (-n).is_nonpositive is True assert (2*n).is_nonpositive is False assert (n*k).is_nonpositive is True assert (2*n*k).is_nonpositive is True assert (-n*k).is_nonpositive is False assert u.is_nonpositive is None assert (-u).is_nonpositive is True assert (2*u).is_nonpositive is None assert v.is_nonpositive is True assert (-v).is_nonpositive is None assert (2*v).is_nonpositive is True assert (u*v).is_nonpositive is True assert (k*u).is_nonpositive is True assert (k*v).is_nonpositive is None assert (n*u).is_nonpositive is None assert (n*v).is_nonpositive is True assert (v*k*u).is_nonpositive is None assert (v*n*u).is_nonpositive is True assert (-v*k*u).is_nonpositive is True assert (-v*n*u).is_nonpositive is None assert (17*v*k*u).is_nonpositive is None assert (17*v*n*u).is_nonpositive is True assert (k*v*n*u).is_nonpositive is None assert (x*k).is_nonpositive is None assert (u*v*n*x*k).is_nonpositive is None assert k.is_nonnegative is False assert (-k).is_nonnegative is True assert (2*k).is_nonnegative is False assert n.is_nonnegative is True assert (-n).is_nonnegative is False assert (2*n).is_nonnegative is True assert (n*k).is_nonnegative is False assert (2*n*k).is_nonnegative is False assert (-n*k).is_nonnegative is True assert u.is_nonnegative is True assert (-u).is_nonnegative is None assert (2*u).is_nonnegative is True assert v.is_nonnegative is None assert (-v).is_nonnegative is True assert (2*v).is_nonnegative is None assert (u*v).is_nonnegative is None assert (k*u).is_nonnegative is None assert (k*v).is_nonnegative is True assert (n*u).is_nonnegative is True assert (n*v).is_nonnegative is None assert (v*k*u).is_nonnegative is True assert (v*n*u).is_nonnegative is None assert (-v*k*u).is_nonnegative is None assert (-v*n*u).is_nonnegative is True assert (17*v*k*u).is_nonnegative is True assert (17*v*n*u).is_nonnegative is None assert (k*v*n*u).is_nonnegative is True assert (x*k).is_nonnegative is None assert (u*v*n*x*k).is_nonnegative is None def test_Add_is_negative_positive(): x = Symbol('x', real=True) k = Symbol('k', negative=True) n = Symbol('n', positive=True) u = Symbol('u', nonnegative=True) v = Symbol('v', nonpositive=True) assert (k - 2).is_negative is True assert (k + 17).is_negative is None assert (-k - 5).is_negative is None assert (-k + 123).is_negative is False assert (k - n).is_negative is True assert (k + n).is_negative is None assert (-k - n).is_negative is None assert (-k + n).is_negative is False assert (k - n - 2).is_negative is True assert (k + n + 17).is_negative is None assert (-k - n - 5).is_negative is None assert (-k + n + 123).is_negative is False assert (-2*k + 123*n + 17).is_negative is False assert (k + u).is_negative is None assert (k + v).is_negative is True assert (n + u).is_negative is False assert (n + v).is_negative is None assert (u - v).is_negative is False assert (u + v).is_negative is None assert (-u - v).is_negative is None assert (-u + v).is_negative is None assert (u - v + n + 2).is_negative is False assert (u + v + n + 2).is_negative is None assert (-u - v + n + 2).is_negative is None assert (-u + v + n + 2).is_negative is None assert (k + x).is_negative is None assert (k + x - n).is_negative is None assert (k - 2).is_positive is False assert (k + 17).is_positive is None assert (-k - 5).is_positive is None assert (-k + 123).is_positive is True assert (k - n).is_positive is False assert (k + n).is_positive is None assert (-k - n).is_positive is None assert (-k + n).is_positive is True assert (k - n - 2).is_positive is False assert (k + n + 17).is_positive is None assert (-k - n - 5).is_positive is None assert (-k + n + 123).is_positive is True assert (-2*k + 123*n + 17).is_positive is True assert (k + u).is_positive is None assert (k + v).is_positive is False assert (n + u).is_positive is True assert (n + v).is_positive is None assert (u - v).is_positive is None assert (u + v).is_positive is None assert (-u - v).is_positive is None assert (-u + v).is_positive is False assert (u - v - n - 2).is_positive is None assert (u + v - n - 2).is_positive is None assert (-u - v - n - 2).is_positive is None assert (-u + v - n - 2).is_positive is False assert (n + x).is_positive is None assert (n + x - k).is_positive is None z = (-3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2) assert z.is_zero z = sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) - sqrt(10 + 6*sqrt(3)) assert z.is_zero def test_Add_is_nonpositive_nonnegative(): x = Symbol('x', real=True) k = Symbol('k', negative=True) n = Symbol('n', positive=True) u = Symbol('u', nonnegative=True) v = Symbol('v', nonpositive=True) assert (u - 2).is_nonpositive is None assert (u + 17).is_nonpositive is False assert (-u - 5).is_nonpositive is True assert (-u + 123).is_nonpositive is None assert (u - v).is_nonpositive is None assert (u + v).is_nonpositive is None assert (-u - v).is_nonpositive is None assert (-u + v).is_nonpositive is True assert (u - v - 2).is_nonpositive is None assert (u + v + 17).is_nonpositive is None assert (-u - v - 5).is_nonpositive is None assert (-u + v - 123).is_nonpositive is True assert (-2*u + 123*v - 17).is_nonpositive is True assert (k + u).is_nonpositive is None assert (k + v).is_nonpositive is True assert (n + u).is_nonpositive is False assert (n + v).is_nonpositive is None assert (k - n).is_nonpositive is True assert (k + n).is_nonpositive is None assert (-k - n).is_nonpositive is None assert (-k + n).is_nonpositive is False assert (k - n + u + 2).is_nonpositive is None assert (k + n + u + 2).is_nonpositive is None assert (-k - n + u + 2).is_nonpositive is None assert (-k + n + u + 2).is_nonpositive is False assert (u + x).is_nonpositive is None assert (v - x - n).is_nonpositive is None assert (u - 2).is_nonnegative is None assert (u + 17).is_nonnegative is True assert (-u - 5).is_nonnegative is False assert (-u + 123).is_nonnegative is None assert (u - v).is_nonnegative is True assert (u + v).is_nonnegative is None assert (-u - v).is_nonnegative is None assert (-u + v).is_nonnegative is None assert (u - v + 2).is_nonnegative is True assert (u + v + 17).is_nonnegative is None assert (-u - v - 5).is_nonnegative is None assert (-u + v - 123).is_nonnegative is False assert (2*u - 123*v + 17).is_nonnegative is True assert (k + u).is_nonnegative is None assert (k + v).is_nonnegative is False assert (n + u).is_nonnegative is True assert (n + v).is_nonnegative is None assert (k - n).is_nonnegative is False assert (k + n).is_nonnegative is None assert (-k - n).is_nonnegative is None assert (-k + n).is_nonnegative is True assert (k - n - u - 2).is_nonnegative is False assert (k + n - u - 2).is_nonnegative is None assert (-k - n - u - 2).is_nonnegative is None assert (-k + n - u - 2).is_nonnegative is None assert (u - x).is_nonnegative is None assert (v + x + n).is_nonnegative is None def test_Pow_is_integer(): x = Symbol('x') k = Symbol('k', integer=True) n = Symbol('n', integer=True, nonnegative=True) m = Symbol('m', integer=True, positive=True) assert (k**2).is_integer is True assert (k**(-2)).is_integer is None assert ((m + 1)**(-2)).is_integer is False assert (m**(-1)).is_integer is None # issue 8580 assert (2**k).is_integer is None assert (2**(-k)).is_integer is None assert (2**n).is_integer is True assert (2**(-n)).is_integer is None assert (2**m).is_integer is True assert (2**(-m)).is_integer is False assert (x**2).is_integer is None assert (2**x).is_integer is None assert (k**n).is_integer is True assert (k**(-n)).is_integer is None assert (k**x).is_integer is None assert (x**k).is_integer is None assert (k**(n*m)).is_integer is True assert (k**(-n*m)).is_integer is None assert sqrt(3).is_integer is False assert sqrt(.3).is_integer is False assert Pow(3, 2, evaluate=False).is_integer is True assert Pow(3, 0, evaluate=False).is_integer is True assert Pow(3, -2, evaluate=False).is_integer is False assert Pow(S.Half, 3, evaluate=False).is_integer is False # decided by re-evaluating assert Pow(3, S.Half, evaluate=False).is_integer is False assert Pow(3, S.Half, evaluate=False).is_integer is False assert Pow(4, S.Half, evaluate=False).is_integer is True assert Pow(S.Half, -2, evaluate=False).is_integer is True assert ((-1)**k).is_integer # issue 8641 x = Symbol('x', real=True, integer=False) assert (x**2).is_integer is None # issue 10458 x = Symbol('x', positive=True) assert (1/(x + 1)).is_integer is False assert (1/(-x - 1)).is_integer is False # issue 8648-like k = Symbol('k', even=True) assert (k**3/2).is_integer assert (k**3/8).is_integer assert (k**3/16).is_integer is None assert (2/k).is_integer is None assert (2/k**2).is_integer is False o = Symbol('o', odd=True) assert (k/o).is_integer is None o = Symbol('o', odd=True, prime=True) assert (k/o).is_integer is False def test_Pow_is_real(): x = Symbol('x', real=True) y = Symbol('y', real=True, positive=True) assert (x**2).is_real is True assert (x**3).is_real is True assert (x**x).is_real is None assert (y**x).is_real is True assert (x**Rational(1, 3)).is_real is None assert (y**Rational(1, 3)).is_real is True assert sqrt(-1 - sqrt(2)).is_real is False i = Symbol('i', imaginary=True) assert (i**i).is_real is None assert (I**i).is_extended_real is True assert ((-I)**i).is_extended_real is True assert (2**i).is_real is None # (2**(pi/log(2) * I)) is real, 2**I is not assert (2**I).is_real is False assert (2**-I).is_real is False assert (i**2).is_extended_real is True assert (i**3).is_extended_real is False assert (i**x).is_real is None # could be (-I)**(2/3) e = Symbol('e', even=True) o = Symbol('o', odd=True) k = Symbol('k', integer=True) assert (i**e).is_extended_real is True assert (i**o).is_extended_real is False assert (i**k).is_real is None assert (i**(4*k)).is_extended_real is True x = Symbol("x", nonnegative=True) y = Symbol("y", nonnegative=True) assert im(x**y).expand(complex=True) is S.Zero assert (x**y).is_real is True i = Symbol('i', imaginary=True) assert (exp(i)**I).is_extended_real is True assert log(exp(i)).is_imaginary is None # i could be 2*pi*I c = Symbol('c', complex=True) assert log(c).is_real is None # c could be 0 or 2, too assert log(exp(c)).is_real is None # log(0), log(E), ... n = Symbol('n', negative=False) assert log(n).is_real is None n = Symbol('n', nonnegative=True) assert log(n).is_real is None assert sqrt(-I).is_real is False # issue 7843 i = Symbol('i', integer=True) assert (1/(i-1)).is_real is None assert (1/(i-1)).is_extended_real is None # test issue 20715 from sympy.core.parameters import evaluate x = S(-1) with evaluate(False): assert x.is_negative is True f = Pow(x, -1) with evaluate(False): assert f.is_imaginary is False def test_real_Pow(): k = Symbol('k', integer=True, nonzero=True) assert (k**(I*pi/log(k))).is_real def test_Pow_is_finite(): xe = Symbol('xe', extended_real=True) xr = Symbol('xr', real=True) p = Symbol('p', positive=True) n = Symbol('n', negative=True) i = Symbol('i', integer=True) assert (xe**2).is_finite is None # xe could be oo assert (xr**2).is_finite is True assert (xe**xe).is_finite is None assert (xr**xe).is_finite is None assert (xe**xr).is_finite is None # FIXME: The line below should be True rather than None # assert (xr**xr).is_finite is True assert (xr**xr).is_finite is None assert (p**xe).is_finite is None assert (p**xr).is_finite is True assert (n**xe).is_finite is None assert (n**xr).is_finite is True assert (sin(xe)**2).is_finite is True assert (sin(xr)**2).is_finite is True assert (sin(xe)**xe).is_finite is None # xe, xr could be -pi assert (sin(xr)**xr).is_finite is None # FIXME: Should the line below be True rather than None? assert (sin(xe)**exp(xe)).is_finite is None assert (sin(xr)**exp(xr)).is_finite is True assert (1/sin(xe)).is_finite is None # if zero, no, otherwise yes assert (1/sin(xr)).is_finite is None assert (1/exp(xe)).is_finite is None # xe could be -oo assert (1/exp(xr)).is_finite is True assert (1/S.Pi).is_finite is True assert (1/(i-1)).is_finite is None def test_Pow_is_even_odd(): x = Symbol('x') k = Symbol('k', even=True) n = Symbol('n', odd=True) m = Symbol('m', integer=True, nonnegative=True) p = Symbol('p', integer=True, positive=True) assert ((-1)**n).is_odd assert ((-1)**k).is_odd assert ((-1)**(m - p)).is_odd assert (k**2).is_even is True assert (n**2).is_even is False assert (2**k).is_even is None assert (x**2).is_even is None assert (k**m).is_even is None assert (n**m).is_even is False assert (k**p).is_even is True assert (n**p).is_even is False assert (m**k).is_even is None assert (p**k).is_even is None assert (m**n).is_even is None assert (p**n).is_even is None assert (k**x).is_even is None assert (n**x).is_even is None assert (k**2).is_odd is False assert (n**2).is_odd is True assert (3**k).is_odd is None assert (k**m).is_odd is None assert (n**m).is_odd is True assert (k**p).is_odd is False assert (n**p).is_odd is True assert (m**k).is_odd is None assert (p**k).is_odd is None assert (m**n).is_odd is None assert (p**n).is_odd is None assert (k**x).is_odd is None assert (n**x).is_odd is None def test_Pow_is_negative_positive(): r = Symbol('r', real=True) k = Symbol('k', integer=True, positive=True) n = Symbol('n', even=True) m = Symbol('m', odd=True) x = Symbol('x') assert (2**r).is_positive is True assert ((-2)**r).is_positive is None assert ((-2)**n).is_positive is True assert ((-2)**m).is_positive is False assert (k**2).is_positive is True assert (k**(-2)).is_positive is True assert (k**r).is_positive is True assert ((-k)**r).is_positive is None assert ((-k)**n).is_positive is True assert ((-k)**m).is_positive is False assert (2**r).is_negative is False assert ((-2)**r).is_negative is None assert ((-2)**n).is_negative is False assert ((-2)**m).is_negative is True assert (k**2).is_negative is False assert (k**(-2)).is_negative is False assert (k**r).is_negative is False assert ((-k)**r).is_negative is None assert ((-k)**n).is_negative is False assert ((-k)**m).is_negative is True assert (2**x).is_positive is None assert (2**x).is_negative is None def test_Pow_is_zero(): z = Symbol('z', zero=True) e = z**2 assert e.is_zero assert e.is_positive is False assert e.is_negative is False assert Pow(0, 0, evaluate=False).is_zero is False assert Pow(0, 3, evaluate=False).is_zero assert Pow(0, oo, evaluate=False).is_zero assert Pow(0, -3, evaluate=False).is_zero is False assert Pow(0, -oo, evaluate=False).is_zero is False assert Pow(2, 2, evaluate=False).is_zero is False a = Symbol('a', zero=False) assert Pow(a, 3).is_zero is False # issue 7965 assert Pow(2, oo, evaluate=False).is_zero is False assert Pow(2, -oo, evaluate=False).is_zero assert Pow(S.Half, oo, evaluate=False).is_zero assert Pow(S.Half, -oo, evaluate=False).is_zero is False # All combinations of real/complex base/exponent h = S.Half T = True F = False N = None pow_iszero = [ ['**', 0, h, 1, 2, -h, -1,-2,-2*I,-I/2,I/2,1+I,oo,-oo,zoo], [ 0, F, T, T, T, F, F, F, F, F, F, N, T, F, N], [ h, F, F, F, F, F, F, F, F, F, F, F, T, F, N], [ 1, F, F, F, F, F, F, F, F, F, F, F, F, F, N], [ 2, F, F, F, F, F, F, F, F, F, F, F, F, T, N], [ -h, F, F, F, F, F, F, F, F, F, F, F, T, F, N], [ -1, F, F, F, F, F, F, F, F, F, F, F, F, F, N], [ -2, F, F, F, F, F, F, F, F, F, F, F, F, T, N], [-2*I, F, F, F, F, F, F, F, F, F, F, F, F, T, N], [-I/2, F, F, F, F, F, F, F, F, F, F, F, T, F, N], [ I/2, F, F, F, F, F, F, F, F, F, F, F, T, F, N], [ 1+I, F, F, F, F, F, F, F, F, F, F, F, F, T, N], [ oo, F, F, F, F, T, T, T, F, F, F, F, F, T, N], [ -oo, F, F, F, F, T, T, T, F, F, F, F, F, T, N], [ zoo, F, F, F, F, T, T, T, N, N, N, N, F, T, N] ] def test_table(table): n = len(table[0]) for row in range(1, n): base = table[row][0] for col in range(1, n): exp = table[0][col] is_zero = table[row][col] # The actual test here: assert Pow(base, exp, evaluate=False).is_zero is is_zero test_table(pow_iszero) # A zero symbol... zo, zo2 = symbols('zo, zo2', zero=True) # All combinations of finite symbols zf, zf2 = symbols('zf, zf2', finite=True) wf, wf2 = symbols('wf, wf2', nonzero=True) xf, xf2 = symbols('xf, xf2', real=True) yf, yf2 = symbols('yf, yf2', nonzero=True) af, af2 = symbols('af, af2', positive=True) bf, bf2 = symbols('bf, bf2', nonnegative=True) cf, cf2 = symbols('cf, cf2', negative=True) df, df2 = symbols('df, df2', nonpositive=True) # Without finiteness: zi, zi2 = symbols('zi, zi2') wi, wi2 = symbols('wi, wi2', zero=False) xi, xi2 = symbols('xi, xi2', extended_real=True) yi, yi2 = symbols('yi, yi2', zero=False, extended_real=True) ai, ai2 = symbols('ai, ai2', extended_positive=True) bi, bi2 = symbols('bi, bi2', extended_nonnegative=True) ci, ci2 = symbols('ci, ci2', extended_negative=True) di, di2 = symbols('di, di2', extended_nonpositive=True) pow_iszero_sym = [ ['**',zo,wf,yf,af,cf,zf,xf,bf,df,zi,wi,xi,yi,ai,bi,ci,di], [ zo2, F, N, N, T, F, N, N, N, F, N, N, N, N, T, N, F, F], [ wf2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], [ yf2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], [ af2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], [ cf2, F, F, F, F, F, F, F, F, F, N, N, N, N, N, N, N, N], [ zf2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], [ xf2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], [ bf2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], [ df2, N, N, N, N, F, N, N, N, N, N, N, N, N, N, N, N, N], [ zi2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N], [ wi2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], [ xi2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N], [ yi2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], [ ai2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], [ bi2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N], [ ci2, F, N, N, F, N, N, N, F, N, N, N, N, N, N, N, N, N], [ di2, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N] ] test_table(pow_iszero_sym) # In some cases (x**x).is_zero is different from (x**y).is_zero even if y # has the same assumptions as x. assert (zo ** zo).is_zero is False assert (wf ** wf).is_zero is False assert (yf ** yf).is_zero is False assert (af ** af).is_zero is False assert (cf ** cf).is_zero is False assert (zf ** zf).is_zero is None assert (xf ** xf).is_zero is None assert (bf ** bf).is_zero is False # None in table assert (df ** df).is_zero is None assert (zi ** zi).is_zero is None assert (wi ** wi).is_zero is None assert (xi ** xi).is_zero is None assert (yi ** yi).is_zero is None assert (ai ** ai).is_zero is False # None in table assert (bi ** bi).is_zero is False # None in table assert (ci ** ci).is_zero is None assert (di ** di).is_zero is None def test_Pow_is_nonpositive_nonnegative(): x = Symbol('x', real=True) k = Symbol('k', integer=True, nonnegative=True) l = Symbol('l', integer=True, positive=True) n = Symbol('n', even=True) m = Symbol('m', odd=True) assert (x**(4*k)).is_nonnegative is True assert (2**x).is_nonnegative is True assert ((-2)**x).is_nonnegative is None assert ((-2)**n).is_nonnegative is True assert ((-2)**m).is_nonnegative is False assert (k**2).is_nonnegative is True assert (k**(-2)).is_nonnegative is None assert (k**k).is_nonnegative is True assert (k**x).is_nonnegative is None # NOTE (0**x).is_real = U assert (l**x).is_nonnegative is True assert (l**x).is_positive is True assert ((-k)**x).is_nonnegative is None assert ((-k)**m).is_nonnegative is None assert (2**x).is_nonpositive is False assert ((-2)**x).is_nonpositive is None assert ((-2)**n).is_nonpositive is False assert ((-2)**m).is_nonpositive is True assert (k**2).is_nonpositive is None assert (k**(-2)).is_nonpositive is None assert (k**x).is_nonpositive is None assert ((-k)**x).is_nonpositive is None assert ((-k)**n).is_nonpositive is None assert (x**2).is_nonnegative is True i = symbols('i', imaginary=True) assert (i**2).is_nonpositive is True assert (i**4).is_nonpositive is False assert (i**3).is_nonpositive is False assert (I**i).is_nonnegative is True assert (exp(I)**i).is_nonnegative is True assert ((-l)**n).is_nonnegative is True assert ((-l)**m).is_nonpositive is True assert ((-k)**n).is_nonnegative is None assert ((-k)**m).is_nonpositive is None def test_Mul_is_imaginary_real(): r = Symbol('r', real=True) p = Symbol('p', positive=True) i1 = Symbol('i1', imaginary=True) i2 = Symbol('i2', imaginary=True) x = Symbol('x') assert I.is_imaginary is True assert I.is_real is False assert (-I).is_imaginary is True assert (-I).is_real is False assert (3*I).is_imaginary is True assert (3*I).is_real is False assert (I*I).is_imaginary is False assert (I*I).is_real is True e = (p + p*I) j = Symbol('j', integer=True, zero=False) assert (e**j).is_real is None assert (e**(2*j)).is_real is None assert (e**j).is_imaginary is None assert (e**(2*j)).is_imaginary is None assert (e**-1).is_imaginary is False assert (e**2).is_imaginary assert (e**3).is_imaginary is False assert (e**4).is_imaginary is False assert (e**5).is_imaginary is False assert (e**-1).is_real is False assert (e**2).is_real is False assert (e**3).is_real is False assert (e**4).is_real is True assert (e**5).is_real is False assert (e**3).is_complex assert (r*i1).is_imaginary is None assert (r*i1).is_real is None assert (x*i1).is_imaginary is None assert (x*i1).is_real is None assert (i1*i2).is_imaginary is False assert (i1*i2).is_real is True assert (r*i1*i2).is_imaginary is False assert (r*i1*i2).is_real is True # Github's issue 5874: nr = Symbol('nr', real=False, complex=True) # e.g. I or 1 + I a = Symbol('a', real=True, nonzero=True) b = Symbol('b', real=True) assert (i1*nr).is_real is None assert (a*nr).is_real is False assert (b*nr).is_real is None ni = Symbol('ni', imaginary=False, complex=True) # e.g. 2 or 1 + I a = Symbol('a', real=True, nonzero=True) b = Symbol('b', real=True) assert (i1*ni).is_real is False assert (a*ni).is_real is None assert (b*ni).is_real is None def test_Mul_hermitian_antihermitian(): a = Symbol('a', hermitian=True, zero=False) b = Symbol('b', hermitian=True) c = Symbol('c', hermitian=False) d = Symbol('d', antihermitian=True) e1 = Mul(a, b, c, evaluate=False) e2 = Mul(b, a, c, evaluate=False) e3 = Mul(a, b, c, d, evaluate=False) e4 = Mul(b, a, c, d, evaluate=False) e5 = Mul(a, c, evaluate=False) e6 = Mul(a, c, d, evaluate=False) assert e1.is_hermitian is None assert e2.is_hermitian is None assert e1.is_antihermitian is None assert e2.is_antihermitian is None assert e3.is_antihermitian is None assert e4.is_antihermitian is None assert e5.is_antihermitian is None assert e6.is_antihermitian is None def test_Add_is_comparable(): assert (x + y).is_comparable is False assert (x + 1).is_comparable is False assert (Rational(1, 3) - sqrt(8)).is_comparable is True def test_Mul_is_comparable(): assert (x*y).is_comparable is False assert (x*2).is_comparable is False assert (sqrt(2)*Rational(1, 3)).is_comparable is True def test_Pow_is_comparable(): assert (x**y).is_comparable is False assert (x**2).is_comparable is False assert (sqrt(Rational(1, 3))).is_comparable is True def test_Add_is_positive_2(): e = Rational(1, 3) - sqrt(8) assert e.is_positive is False assert e.is_negative is True e = pi - 1 assert e.is_positive is True assert e.is_negative is False def test_Add_is_irrational(): i = Symbol('i', irrational=True) assert i.is_irrational is True assert i.is_rational is False assert (i + 1).is_irrational is True assert (i + 1).is_rational is False def test_Mul_is_irrational(): expr = Mul(1, 2, 3, evaluate=False) assert expr.is_irrational is False expr = Mul(1, I, I, evaluate=False) assert expr.is_rational is None # I * I = -1 but *no evaluation allowed* # sqrt(2) * I * I = -sqrt(2) is irrational but # this can't be determined without evaluating the # expression and the eval_is routines shouldn't do that expr = Mul(sqrt(2), I, I, evaluate=False) assert expr.is_irrational is None def test_issue_3531(): # https://github.com/sympy/sympy/issues/3531 # https://github.com/sympy/sympy/pull/18116 class MightyNumeric(tuple): def __rtruediv__(self, other): return "something" assert sympify(1)/MightyNumeric((1, 2)) == "something" def test_issue_3531b(): class Foo: def __init__(self): self.field = 1.0 def __mul__(self, other): self.field = self.field * other def __rmul__(self, other): self.field = other * self.field f = Foo() x = Symbol("x") assert f*x == x*f def test_bug3(): a = Symbol("a") b = Symbol("b", positive=True) e = 2*a + b f = b + 2*a assert e == f def test_suppressed_evaluation(): a = Add(0, 3, 2, evaluate=False) b = Mul(1, 3, 2, evaluate=False) c = Pow(3, 2, evaluate=False) assert a != 6 assert a.func is Add assert a.args == (0, 3, 2) assert b != 6 assert b.func is Mul assert b.args == (1, 3, 2) assert c != 9 assert c.func is Pow assert c.args == (3, 2) def test_AssocOp_doit(): a = Add(x,x, evaluate=False) b = Mul(y,y, evaluate=False) c = Add(b,b, evaluate=False) d = Mul(a,a, evaluate=False) assert c.doit(deep=False).func == Mul assert c.doit(deep=False).args == (2,y,y) assert c.doit().func == Mul assert c.doit().args == (2, Pow(y,2)) assert d.doit(deep=False).func == Pow assert d.doit(deep=False).args == (a, 2*S.One) assert d.doit().func == Mul assert d.doit().args == (4*S.One, Pow(x,2)) def test_Add_Mul_Expr_args(): nonexpr = [Basic(), Poly(x, x), FiniteSet(x)] for typ in [Add, Mul]: for obj in nonexpr: with warns_deprecated_sympy(): typ(obj, 1) def test_Add_as_coeff_mul(): # issue 5524. These should all be (1, self) assert (x + 1).as_coeff_mul() == (1, (x + 1,)) assert (x + 2).as_coeff_mul() == (1, (x + 2,)) assert (x + 3).as_coeff_mul() == (1, (x + 3,)) assert (x - 1).as_coeff_mul() == (1, (x - 1,)) assert (x - 2).as_coeff_mul() == (1, (x - 2,)) assert (x - 3).as_coeff_mul() == (1, (x - 3,)) n = Symbol('n', integer=True) assert (n + 1).as_coeff_mul() == (1, (n + 1,)) assert (n + 2).as_coeff_mul() == (1, (n + 2,)) assert (n + 3).as_coeff_mul() == (1, (n + 3,)) assert (n - 1).as_coeff_mul() == (1, (n - 1,)) assert (n - 2).as_coeff_mul() == (1, (n - 2,)) assert (n - 3).as_coeff_mul() == (1, (n - 3,)) def test_Pow_as_coeff_mul_doesnt_expand(): assert exp(x + y).as_coeff_mul() == (1, (exp(x + y),)) assert exp(x + exp(x + y)) != exp(x + exp(x)*exp(y)) def test_issue_3514_18626(): assert sqrt(S.Half) * sqrt(6) == 2 * sqrt(3)/2 assert S.Half*sqrt(6)*sqrt(2) == sqrt(3) assert sqrt(6)/2*sqrt(2) == sqrt(3) assert sqrt(6)*sqrt(2)/2 == sqrt(3) assert sqrt(8)**Rational(2, 3) == 2 def test_make_args(): assert Add.make_args(x) == (x,) assert Mul.make_args(x) == (x,) assert Add.make_args(x*y*z) == (x*y*z,) assert Mul.make_args(x*y*z) == (x*y*z).args assert Add.make_args(x + y + z) == (x + y + z).args assert Mul.make_args(x + y + z) == (x + y + z,) assert Add.make_args((x + y)**z) == ((x + y)**z,) assert Mul.make_args((x + y)**z) == ((x + y)**z,) def test_issue_5126(): assert (-2)**x*(-3)**x != 6**x i = Symbol('i', integer=1) assert (-2)**i*(-3)**i == 6**i def test_Rational_as_content_primitive(): c, p = S.One, S.Zero assert (c*p).as_content_primitive() == (c, p) c, p = S.Half, S.One assert (c*p).as_content_primitive() == (c, p) def test_Add_as_content_primitive(): assert (x + 2).as_content_primitive() == (1, x + 2) assert (3*x + 2).as_content_primitive() == (1, 3*x + 2) assert (3*x + 3).as_content_primitive() == (3, x + 1) assert (3*x + 6).as_content_primitive() == (3, x + 2) assert (3*x + 2*y).as_content_primitive() == (1, 3*x + 2*y) assert (3*x + 3*y).as_content_primitive() == (3, x + y) assert (3*x + 6*y).as_content_primitive() == (3, x + 2*y) assert (3/x + 2*x*y*z**2).as_content_primitive() == (1, 3/x + 2*x*y*z**2) assert (3/x + 3*x*y*z**2).as_content_primitive() == (3, 1/x + x*y*z**2) assert (3/x + 6*x*y*z**2).as_content_primitive() == (3, 1/x + 2*x*y*z**2) assert (2*x/3 + 4*y/9).as_content_primitive() == \ (Rational(2, 9), 3*x + 2*y) assert (2*x/3 + 2.5*y).as_content_primitive() == \ (Rational(1, 3), 2*x + 7.5*y) # the coefficient may sort to a position other than 0 p = 3 + x + y assert (2*p).expand().as_content_primitive() == (2, p) assert (2.0*p).expand().as_content_primitive() == (1, 2.*p) p *= -1 assert (2*p).expand().as_content_primitive() == (2, p) def test_Mul_as_content_primitive(): assert (2*x).as_content_primitive() == (2, x) assert (x*(2 + 2*x)).as_content_primitive() == (2, x*(1 + x)) assert (x*(2 + 2*y)*(3*x + 3)**2).as_content_primitive() == \ (18, x*(1 + y)*(x + 1)**2) assert ((2 + 2*x)**2*(3 + 6*x) + S.Half).as_content_primitive() == \ (S.Half, 24*(x + 1)**2*(2*x + 1) + 1) def test_Pow_as_content_primitive(): assert (x**y).as_content_primitive() == (1, x**y) assert ((2*x + 2)**y).as_content_primitive() == \ (1, (Mul(2, (x + 1), evaluate=False))**y) assert ((2*x + 2)**3).as_content_primitive() == (8, (x + 1)**3) def test_issue_5460(): u = Mul(2, (1 + x), evaluate=False) assert (2 + u).args == (2, u) def test_product_irrational(): assert (I*pi).is_irrational is False # The following used to be deduced from the above bug: assert (I*pi).is_positive is False def test_issue_5919(): assert (x/(y*(1 + y))).expand() == x/(y**2 + y) def test_Mod(): assert Mod(x, 1).func is Mod assert pi % pi is S.Zero assert Mod(5, 3) == 2 assert Mod(-5, 3) == 1 assert Mod(5, -3) == -1 assert Mod(-5, -3) == -2 assert type(Mod(3.2, 2, evaluate=False)) == Mod assert 5 % x == Mod(5, x) assert x % 5 == Mod(x, 5) assert x % y == Mod(x, y) assert (x % y).subs({x: 5, y: 3}) == 2 assert Mod(nan, 1) is nan assert Mod(1, nan) is nan assert Mod(nan, nan) is nan Mod(0, x) == 0 with raises(ZeroDivisionError): Mod(x, 0) k = Symbol('k', integer=True) m = Symbol('m', integer=True, positive=True) assert (x**m % x).func is Mod assert (k**(-m) % k).func is Mod assert k**m % k == 0 assert (-2*k)**m % k == 0 # Float handling point3 = Float(3.3) % 1 assert (x - 3.3) % 1 == Mod(1.*x + 1 - point3, 1) assert Mod(-3.3, 1) == 1 - point3 assert Mod(0.7, 1) == Float(0.7) e = Mod(1.3, 1) assert comp(e, .3) and e.is_Float e = Mod(1.3, .7) assert comp(e, .6) and e.is_Float e = Mod(1.3, Rational(7, 10)) assert comp(e, .6) and e.is_Float e = Mod(Rational(13, 10), 0.7) assert comp(e, .6) and e.is_Float e = Mod(Rational(13, 10), Rational(7, 10)) assert comp(e, .6) and e.is_Rational # check that sign is right r2 = sqrt(2) r3 = sqrt(3) for i in [-r3, -r2, r2, r3]: for j in [-r3, -r2, r2, r3]: assert verify_numerically(i % j, i.n() % j.n()) for _x in range(4): for _y in range(9): reps = [(x, _x), (y, _y)] assert Mod(3*x + y, 9).subs(reps) == (3*_x + _y) % 9 # denesting t = Symbol('t', real=True) assert Mod(Mod(x, t), t) == Mod(x, t) assert Mod(-Mod(x, t), t) == Mod(-x, t) assert Mod(Mod(x, 2*t), t) == Mod(x, t) assert Mod(-Mod(x, 2*t), t) == Mod(-x, t) assert Mod(Mod(x, t), 2*t) == Mod(x, t) assert Mod(-Mod(x, t), -2*t) == -Mod(x, t) for i in [-4, -2, 2, 4]: for j in [-4, -2, 2, 4]: for k in range(4): assert Mod(Mod(x, i), j).subs({x: k}) == (k % i) % j assert Mod(-Mod(x, i), j).subs({x: k}) == -(k % i) % j # known difference assert Mod(5*sqrt(2), sqrt(5)) == 5*sqrt(2) - 3*sqrt(5) p = symbols('p', positive=True) assert Mod(2, p + 3) == 2 assert Mod(-2, p + 3) == p + 1 assert Mod(2, -p - 3) == -p - 1 assert Mod(-2, -p - 3) == -2 assert Mod(p + 5, p + 3) == 2 assert Mod(-p - 5, p + 3) == p + 1 assert Mod(p + 5, -p - 3) == -p - 1 assert Mod(-p - 5, -p - 3) == -2 assert Mod(p + 1, p - 1).func is Mod # handling sums assert (x + 3) % 1 == Mod(x, 1) assert (x + 3.0) % 1 == Mod(1.*x, 1) assert (x - S(33)/10) % 1 == Mod(x + S(7)/10, 1) a = Mod(.6*x + y, .3*y) b = Mod(0.1*y + 0.6*x, 0.3*y) # Test that a, b are equal, with 1e-14 accuracy in coefficients eps = 1e-14 assert abs((a.args[0] - b.args[0]).subs({x: 1, y: 1})) < eps assert abs((a.args[1] - b.args[1]).subs({x: 1, y: 1})) < eps assert (x + 1) % x == 1 % x assert (x + y) % x == y % x assert (x + y + 2) % x == (y + 2) % x assert (a + 3*x + 1) % (2*x) == Mod(a + x + 1, 2*x) assert (12*x + 18*y) % (3*x) == 3*Mod(6*y, x) # gcd extraction assert (-3*x) % (-2*y) == -Mod(3*x, 2*y) assert (.6*pi) % (.3*x*pi) == 0.3*pi*Mod(2, x) assert (.6*pi) % (.31*x*pi) == pi*Mod(0.6, 0.31*x) assert (6*pi) % (.3*x*pi) == 0.3*pi*Mod(20, x) assert (6*pi) % (.31*x*pi) == pi*Mod(6, 0.31*x) assert (6*pi) % (.42*x*pi) == pi*Mod(6, 0.42*x) assert (12*x) % (2*y) == 2*Mod(6*x, y) assert (12*x) % (3*5*y) == 3*Mod(4*x, 5*y) assert (12*x) % (15*x*y) == 3*x*Mod(4, 5*y) assert (-2*pi) % (3*pi) == pi assert (2*x + 2) % (x + 1) == 0 assert (x*(x + 1)) % (x + 1) == (x + 1)*Mod(x, 1) assert Mod(5.0*x, 0.1*y) == 0.1*Mod(50*x, y) i = Symbol('i', integer=True) assert (3*i*x) % (2*i*y) == i*Mod(3*x, 2*y) assert Mod(4*i, 4) == 0 # issue 8677 n = Symbol('n', integer=True, positive=True) assert factorial(n) % n == 0 assert factorial(n + 2) % n == 0 assert (factorial(n + 4) % (n + 5)).func is Mod # Wilson's theorem factorial(18042, evaluate=False) % 18043 == 18042 p = Symbol('n', prime=True) factorial(p - 1) % p == p - 1 factorial(p - 1) % -p == -1 (factorial(3, evaluate=False) % 4).doit() == 2 n = Symbol('n', composite=True, odd=True) factorial(n - 1) % n == 0 # symbolic with known parity n = Symbol('n', even=True) assert Mod(n, 2) == 0 n = Symbol('n', odd=True) assert Mod(n, 2) == 1 # issue 10963 assert (x**6000%400).args[1] == 400 #issue 13543 assert Mod(Mod(x + 1, 2) + 1 , 2) == Mod(x,2) assert Mod(Mod(x + 2, 4)*(x + 4), 4) == Mod(x*(x + 2), 4) assert Mod(Mod(x + 2, 4)*4, 4) == 0 # issue 15493 i, j = symbols('i j', integer=True, positive=True) assert Mod(3*i, 2) == Mod(i, 2) assert Mod(8*i/j, 4) == 4*Mod(2*i/j, 1) assert Mod(8*i, 4) == 0 # rewrite assert Mod(x, y).rewrite(floor) == x - y*floor(x/y) assert ((x - Mod(x, y))/y).rewrite(floor) == floor(x/y) # issue 21373 from sympy.functions.elementary.trigonometric import sinh from sympy.functions.elementary.piecewise import Piecewise x_r, y_r = symbols('x_r y_r', real=True) (Piecewise((x_r, y_r > x_r), (y_r, True)) / z) % 1 expr = exp(sinh(Piecewise((x_r, y_r > x_r), (y_r, True)) / z)) expr.subs({1: 1.0}) sinh(Piecewise((x_r, y_r > x_r), (y_r, True)) * z ** -1.0).is_zero def test_Mod_Pow(): # modular exponentiation assert isinstance(Mod(Pow(2, 2, evaluate=False), 3), Integer) assert Mod(Pow(4, 13, evaluate=False), 497) == Mod(Pow(4, 13), 497) assert Mod(Pow(2, 10000000000, evaluate=False), 3) == 1 assert Mod(Pow(32131231232, 9**10**6, evaluate=False),10**12) == \ pow(32131231232,9**10**6,10**12) assert Mod(Pow(33284959323, 123**999, evaluate=False),11**13) == \ pow(33284959323,123**999,11**13) assert Mod(Pow(78789849597, 333**555, evaluate=False),12**9) == \ pow(78789849597,333**555,12**9) # modular nested exponentiation expr = Pow(2, 2, evaluate=False) expr = Pow(2, expr, evaluate=False) assert Mod(expr, 3**10) == 16 expr = Pow(2, expr, evaluate=False) assert Mod(expr, 3**10) == 6487 expr = Pow(2, expr, evaluate=False) assert Mod(expr, 3**10) == 32191 expr = Pow(2, expr, evaluate=False) assert Mod(expr, 3**10) == 18016 expr = Pow(2, expr, evaluate=False) assert Mod(expr, 3**10) == 5137 expr = Pow(2, 2, evaluate=False) expr = Pow(expr, 2, evaluate=False) assert Mod(expr, 3**10) == 16 expr = Pow(expr, 2, evaluate=False) assert Mod(expr, 3**10) == 256 expr = Pow(expr, 2, evaluate=False) assert Mod(expr, 3**10) == 6487 expr = Pow(expr, 2, evaluate=False) assert Mod(expr, 3**10) == 38281 expr = Pow(expr, 2, evaluate=False) assert Mod(expr, 3**10) == 15928 expr = Pow(2, 2, evaluate=False) expr = Pow(expr, expr, evaluate=False) assert Mod(expr, 3**10) == 256 expr = Pow(expr, expr, evaluate=False) assert Mod(expr, 3**10) == 9229 expr = Pow(expr, expr, evaluate=False) assert Mod(expr, 3**10) == 25708 expr = Pow(expr, expr, evaluate=False) assert Mod(expr, 3**10) == 26608 expr = Pow(expr, expr, evaluate=False) # XXX This used to fail in a nondeterministic way because of overflow # error. assert Mod(expr, 3**10) == 1966 def test_Mod_is_integer(): p = Symbol('p', integer=True) q1 = Symbol('q1', integer=True) q2 = Symbol('q2', integer=True, nonzero=True) assert Mod(x, y).is_integer is None assert Mod(p, q1).is_integer is None assert Mod(x, q2).is_integer is None assert Mod(p, q2).is_integer def test_Mod_is_nonposneg(): n = Symbol('n', integer=True) k = Symbol('k', integer=True, positive=True) assert (n%3).is_nonnegative assert Mod(n, -3).is_nonpositive assert Mod(n, k).is_nonnegative assert Mod(n, -k).is_nonpositive assert Mod(k, n).is_nonnegative is None def test_issue_6001(): A = Symbol("A", commutative=False) eq = A + A**2 # it doesn't matter whether it's True or False; they should # just all be the same assert ( eq.is_commutative == (eq + 1).is_commutative == (A + 1).is_commutative) B = Symbol("B", commutative=False) # Although commutative terms could cancel we return True # meaning "there are non-commutative symbols; aftersubstitution # that definition can change, e.g. (A*B).subs(B,A**-1) -> 1 assert (sqrt(2)*A).is_commutative is False assert (sqrt(2)*A*B).is_commutative is False def test_polar(): from sympy import polar_lift p = Symbol('p', polar=True) x = Symbol('x') assert p.is_polar assert x.is_polar is None assert S.One.is_polar is None assert (p**x).is_polar is True assert (x**p).is_polar is None assert ((2*p)**x).is_polar is True assert (2*p).is_polar is True assert (-2*p).is_polar is not True assert (polar_lift(-2)*p).is_polar is True q = Symbol('q', polar=True) assert (p*q)**2 == p**2 * q**2 assert (2*q)**2 == 4 * q**2 assert ((p*q)**x).expand() == p**x * q**x def test_issue_6040(): a, b = Pow(1, 2, evaluate=False), S.One assert a != b assert b != a assert not (a == b) assert not (b == a) def test_issue_6082(): # Comparison is symmetric assert Basic.compare(Max(x, 1), Max(x, 2)) == \ - Basic.compare(Max(x, 2), Max(x, 1)) # Equal expressions compare equal assert Basic.compare(Max(x, 1), Max(x, 1)) == 0 # Basic subtypes (such as Max) compare different than standard types assert Basic.compare(Max(1, x), frozenset((1, x))) != 0 def test_issue_6077(): assert x**2.0/x == x**1.0 assert x/x**2.0 == x**-1.0 assert x*x**2.0 == x**3.0 assert x**1.5*x**2.5 == x**4.0 assert 2**(2.0*x)/2**x == 2**(1.0*x) assert 2**x/2**(2.0*x) == 2**(-1.0*x) assert 2**x*2**(2.0*x) == 2**(3.0*x) assert 2**(1.5*x)*2**(2.5*x) == 2**(4.0*x) def test_mul_flatten_oo(): p = symbols('p', positive=True) n, m = symbols('n,m', negative=True) x_im = symbols('x_im', imaginary=True) assert n*oo is -oo assert n*m*oo is oo assert p*oo is oo assert x_im*oo != I*oo # i could be +/- 3*I -> +/-oo def test_add_flatten(): # see https://github.com/sympy/sympy/issues/2633#issuecomment-29545524 a = oo + I*oo b = oo - I*oo assert a + b is nan assert a - b is nan # FIXME: This evaluates as: # >>> 1/a # 0*(oo + oo*I) # which should not simplify to 0. Should be fixed in Pow.eval #assert (1/a).simplify() == (1/b).simplify() == 0 a = Pow(2, 3, evaluate=False) assert a + a == 16 def test_issue_5160_6087_6089_6090(): # issue 6087 assert ((-2*x*y**y)**3.2).n(2) == (2**3.2*(-x*y**y)**3.2).n(2) # issue 6089 A, B, C = symbols('A,B,C', commutative=False) assert (2.*B*C)**3 == 8.0*(B*C)**3 assert (-2.*B*C)**3 == -8.0*(B*C)**3 assert (-2*B*C)**2 == 4*(B*C)**2 # issue 5160 assert sqrt(-1.0*x) == 1.0*sqrt(-x) assert sqrt(1.0*x) == 1.0*sqrt(x) # issue 6090 assert (-2*x*y*A*B)**2 == 4*x**2*y**2*(A*B)**2 def test_float_int_round(): assert int(float(sqrt(10))) == int(sqrt(10)) assert int(pi**1000) % 10 == 2 assert int(Float('1.123456789012345678901234567890e20', '')) == \ int(112345678901234567890) assert int(Float('1.123456789012345678901234567890e25', '')) == \ int(11234567890123456789012345) # decimal forces float so it's not an exact integer ending in 000000 assert int(Float('1.123456789012345678901234567890e35', '')) == \ 112345678901234567890123456789000192 assert int(Float('123456789012345678901234567890e5', '')) == \ 12345678901234567890123456789000000 assert Integer(Float('1.123456789012345678901234567890e20', '')) == \ 112345678901234567890 assert Integer(Float('1.123456789012345678901234567890e25', '')) == \ 11234567890123456789012345 # decimal forces float so it's not an exact integer ending in 000000 assert Integer(Float('1.123456789012345678901234567890e35', '')) == \ 112345678901234567890123456789000192 assert Integer(Float('123456789012345678901234567890e5', '')) == \ 12345678901234567890123456789000000 assert same_and_same_prec(Float('123000e-2',''), Float('1230.00', '')) assert same_and_same_prec(Float('123000e2',''), Float('12300000', '')) assert int(1 + Rational('.9999999999999999999999999')) == 1 assert int(pi/1e20) == 0 assert int(1 + pi/1e20) == 1 assert int(Add(1.2, -2, evaluate=False)) == int(1.2 - 2) assert int(Add(1.2, +2, evaluate=False)) == int(1.2 + 2) assert int(Add(1 + Float('.99999999999999999', ''), evaluate=False)) == 1 raises(TypeError, lambda: float(x)) raises(TypeError, lambda: float(sqrt(-1))) assert int(12345678901234567890 + cos(1)**2 + sin(1)**2) == \ 12345678901234567891 def test_issue_6611a(): assert Mul.flatten([3**Rational(1, 3), Pow(-Rational(1, 9), Rational(2, 3), evaluate=False)]) == \ ([Rational(1, 3), (-1)**Rational(2, 3)], [], None) def test_denest_add_mul(): # when working with evaluated expressions make sure they denest eq = x + 1 eq = Add(eq, 2, evaluate=False) eq = Add(eq, 2, evaluate=False) assert Add(*eq.args) == x + 5 eq = x*2 eq = Mul(eq, 2, evaluate=False) eq = Mul(eq, 2, evaluate=False) assert Mul(*eq.args) == 8*x # but don't let them denest unecessarily eq = Mul(-2, x - 2, evaluate=False) assert 2*eq == Mul(-4, x - 2, evaluate=False) assert -eq == Mul(2, x - 2, evaluate=False) def test_mul_coeff(): # It is important that all Numbers be removed from the seq; # This can be tricky when powers combine to produce those numbers p = exp(I*pi/3) assert p**2*x*p*y*p*x*p**2 == x**2*y def test_mul_zero_detection(): nz = Dummy(real=True, zero=False) r = Dummy(extended_real=True) c = Dummy(real=False, complex=True) c2 = Dummy(real=False, complex=True) i = Dummy(imaginary=True) e = nz*r*c assert e.is_imaginary is None assert e.is_extended_real is None e = nz*c assert e.is_imaginary is None assert e.is_extended_real is False e = nz*i*c assert e.is_imaginary is False assert e.is_extended_real is None # check for more than one complex; it is important to use # uniquely named Symbols to ensure that two factors appear # e.g. if the symbols have the same name they just become # a single factor, a power. e = nz*i*c*c2 assert e.is_imaginary is None assert e.is_extended_real is None # _eval_is_extended_real and _eval_is_zero both employ trapping of the # zero value so args should be tested in both directions and # TO AVOID GETTING THE CACHED RESULT, Dummy MUST BE USED # real is unknown def test(z, b, e): if z.is_zero and b.is_finite: assert e.is_extended_real and e.is_zero else: assert e.is_extended_real is None if b.is_finite: if z.is_zero: assert e.is_zero else: assert e.is_zero is None elif b.is_finite is False: if z.is_zero is None: assert e.is_zero is None else: assert e.is_zero is False for iz, ib in cartes(*[[True, False, None]]*2): z = Dummy('z', nonzero=iz) b = Dummy('f', finite=ib) e = Mul(z, b, evaluate=False) test(z, b, e) z = Dummy('nz', nonzero=iz) b = Dummy('f', finite=ib) e = Mul(b, z, evaluate=False) test(z, b, e) # real is True def test(z, b, e): if z.is_zero and not b.is_finite: assert e.is_extended_real is None else: assert e.is_extended_real is True for iz, ib in cartes(*[[True, False, None]]*2): z = Dummy('z', nonzero=iz, extended_real=True) b = Dummy('b', finite=ib, extended_real=True) e = Mul(z, b, evaluate=False) test(z, b, e) z = Dummy('z', nonzero=iz, extended_real=True) b = Dummy('b', finite=ib, extended_real=True) e = Mul(b, z, evaluate=False) test(z, b, e) def test_Mul_with_zero_infinite(): zer = Dummy(zero=True) inf = Dummy(finite=False) e = Mul(zer, inf, evaluate=False) assert e.is_extended_positive is None assert e.is_hermitian is None e = Mul(inf, zer, evaluate=False) assert e.is_extended_positive is None assert e.is_hermitian is None def test_Mul_does_not_cancel_infinities(): a, b = symbols('a b') assert ((zoo + 3*a)/(3*a + zoo)) is nan assert ((b - oo)/(b - oo)) is nan # issue 13904 expr = (1/(a+b) + 1/(a-b))/(1/(a+b) - 1/(a-b)) assert expr.subs(b, a) is nan def test_Mul_does_not_distribute_infinity(): a, b = symbols('a b') assert ((1 + I)*oo).is_Mul assert ((a + b)*(-oo)).is_Mul assert ((a + 1)*zoo).is_Mul assert ((1 + I)*oo).is_finite is False z = (1 + I)*oo assert ((1 - I)*z).expand() is oo def test_issue_8247_8354(): from sympy import tan z = sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) - sqrt(10 + 6*sqrt(3)) assert z.is_positive is False # it's 0 z = S('''-2**(1/3)*(3*sqrt(93) + 29)**2 - 4*(3*sqrt(93) + 29)**(4/3) + 12*sqrt(93)*(3*sqrt(93) + 29)**(1/3) + 116*(3*sqrt(93) + 29)**(1/3) + 174*2**(1/3)*sqrt(93) + 1678*2**(1/3)''') assert z.is_positive is False # it's 0 z = 2*(-3*tan(19*pi/90) + sqrt(3))*cos(11*pi/90)*cos(19*pi/90) - \ sqrt(3)*(-3 + 4*cos(19*pi/90)**2) assert z.is_positive is not True # it's zero and it shouldn't hang z = S('''9*(3*sqrt(93) + 29)**(2/3)*((3*sqrt(93) + 29)**(1/3)*(-2**(2/3)*(3*sqrt(93) + 29)**(1/3) - 2) - 2*2**(1/3))**3 + 72*(3*sqrt(93) + 29)**(2/3)*(81*sqrt(93) + 783) + (162*sqrt(93) + 1566)*((3*sqrt(93) + 29)**(1/3)*(-2**(2/3)*(3*sqrt(93) + 29)**(1/3) - 2) - 2*2**(1/3))**2''') assert z.is_positive is False # it's 0 (and a single _mexpand isn't enough) def test_Add_is_zero(): x, y = symbols('x y', zero=True) assert (x + y).is_zero # Issue 15873 e = -2*I + (1 + I)**2 assert e.is_zero is None def test_issue_14392(): assert (sin(zoo)**2).as_real_imag() == (nan, nan) def test_divmod(): assert divmod(x, y) == (x//y, x % y) assert divmod(x, 3) == (x//3, x % 3) assert divmod(3, x) == (3//x, 3 % x) def test__neg__(): assert -(x*y) == -x*y assert -(-x*y) == x*y assert -(1.*x) == -1.*x assert -(-1.*x) == 1.*x assert -(2.*x) == -2.*x assert -(-2.*x) == 2.*x with distribute(False): eq = -(x + y) assert eq.is_Mul and eq.args == (-1, x + y) def test_issue_18507(): assert Mul(zoo, zoo, 0) is nan def test_issue_17130(): e = Add(b, -b, I, -I, evaluate=False) assert e.is_zero is None # ideally this would be True def test_issue_21034(): e = -I*log((re(asin(5)) + I*im(asin(5)))/sqrt(re(asin(5))**2 + im(asin(5))**2))/pi assert e.round(2) sympy-sympy-1.9/sympy/core/tests/test_assumptions.py000066400000000000000000001156501412543434000232040ustar00rootroot00000000000000from sympy import I, sqrt, log, exp, sin, asin, factorial, Mod, pi, oo from sympy.core import Symbol, S, Rational, Integer, Dummy, Wild, Pow from sympy.core.assumptions import (assumptions, check_assumptions, failing_assumptions, common_assumptions) from sympy.core.facts import InconsistentAssumptions from sympy import simplify from sympy.testing.pytest import raises, XFAIL def test_symbol_unset(): x = Symbol('x', real=True, integer=True) assert x.is_real is True assert x.is_integer is True assert x.is_imaginary is False assert x.is_noninteger is False assert x.is_number is False def test_zero(): z = Integer(0) assert z.is_commutative is True assert z.is_integer is True assert z.is_rational is True assert z.is_algebraic is True assert z.is_transcendental is False assert z.is_real is True assert z.is_complex is True assert z.is_noninteger is False assert z.is_irrational is False assert z.is_imaginary is False assert z.is_positive is False assert z.is_negative is False assert z.is_nonpositive is True assert z.is_nonnegative is True assert z.is_even is True assert z.is_odd is False assert z.is_finite is True assert z.is_infinite is False assert z.is_comparable is True assert z.is_prime is False assert z.is_composite is False assert z.is_number is True def test_one(): z = Integer(1) assert z.is_commutative is True assert z.is_integer is True assert z.is_rational is True assert z.is_algebraic is True assert z.is_transcendental is False assert z.is_real is True assert z.is_complex is True assert z.is_noninteger is False assert z.is_irrational is False assert z.is_imaginary is False assert z.is_positive is True assert z.is_negative is False assert z.is_nonpositive is False assert z.is_nonnegative is True assert z.is_even is False assert z.is_odd is True assert z.is_finite is True assert z.is_infinite is False assert z.is_comparable is True assert z.is_prime is False assert z.is_number is True assert z.is_composite is False # issue 8807 def test_negativeone(): z = Integer(-1) assert z.is_commutative is True assert z.is_integer is True assert z.is_rational is True assert z.is_algebraic is True assert z.is_transcendental is False assert z.is_real is True assert z.is_complex is True assert z.is_noninteger is False assert z.is_irrational is False assert z.is_imaginary is False assert z.is_positive is False assert z.is_negative is True assert z.is_nonpositive is True assert z.is_nonnegative is False assert z.is_even is False assert z.is_odd is True assert z.is_finite is True assert z.is_infinite is False assert z.is_comparable is True assert z.is_prime is False assert z.is_composite is False assert z.is_number is True def test_infinity(): oo = S.Infinity assert oo.is_commutative is True assert oo.is_integer is False assert oo.is_rational is False assert oo.is_algebraic is False assert oo.is_transcendental is False assert oo.is_extended_real is True assert oo.is_real is False assert oo.is_complex is False assert oo.is_noninteger is True assert oo.is_irrational is False assert oo.is_imaginary is False assert oo.is_nonzero is False assert oo.is_positive is False assert oo.is_negative is False assert oo.is_nonpositive is False assert oo.is_nonnegative is False assert oo.is_extended_nonzero is True assert oo.is_extended_positive is True assert oo.is_extended_negative is False assert oo.is_extended_nonpositive is False assert oo.is_extended_nonnegative is True assert oo.is_even is False assert oo.is_odd is False assert oo.is_finite is False assert oo.is_infinite is True assert oo.is_comparable is True assert oo.is_prime is False assert oo.is_composite is False assert oo.is_number is True def test_neg_infinity(): mm = S.NegativeInfinity assert mm.is_commutative is True assert mm.is_integer is False assert mm.is_rational is False assert mm.is_algebraic is False assert mm.is_transcendental is False assert mm.is_extended_real is True assert mm.is_real is False assert mm.is_complex is False assert mm.is_noninteger is True assert mm.is_irrational is False assert mm.is_imaginary is False assert mm.is_nonzero is False assert mm.is_positive is False assert mm.is_negative is False assert mm.is_nonpositive is False assert mm.is_nonnegative is False assert mm.is_extended_nonzero is True assert mm.is_extended_positive is False assert mm.is_extended_negative is True assert mm.is_extended_nonpositive is True assert mm.is_extended_nonnegative is False assert mm.is_even is False assert mm.is_odd is False assert mm.is_finite is False assert mm.is_infinite is True assert mm.is_comparable is True assert mm.is_prime is False assert mm.is_composite is False assert mm.is_number is True def test_zoo(): zoo = S.ComplexInfinity assert zoo.is_complex is False assert zoo.is_real is False assert zoo.is_prime is False def test_nan(): nan = S.NaN assert nan.is_commutative is True assert nan.is_integer is None assert nan.is_rational is None assert nan.is_algebraic is None assert nan.is_transcendental is None assert nan.is_real is None assert nan.is_complex is None assert nan.is_noninteger is None assert nan.is_irrational is None assert nan.is_imaginary is None assert nan.is_positive is None assert nan.is_negative is None assert nan.is_nonpositive is None assert nan.is_nonnegative is None assert nan.is_even is None assert nan.is_odd is None assert nan.is_finite is None assert nan.is_infinite is None assert nan.is_comparable is False assert nan.is_prime is None assert nan.is_composite is None assert nan.is_number is True def test_pos_rational(): r = Rational(3, 4) assert r.is_commutative is True assert r.is_integer is False assert r.is_rational is True assert r.is_algebraic is True assert r.is_transcendental is False assert r.is_real is True assert r.is_complex is True assert r.is_noninteger is True assert r.is_irrational is False assert r.is_imaginary is False assert r.is_positive is True assert r.is_negative is False assert r.is_nonpositive is False assert r.is_nonnegative is True assert r.is_even is False assert r.is_odd is False assert r.is_finite is True assert r.is_infinite is False assert r.is_comparable is True assert r.is_prime is False assert r.is_composite is False r = Rational(1, 4) assert r.is_nonpositive is False assert r.is_positive is True assert r.is_negative is False assert r.is_nonnegative is True r = Rational(5, 4) assert r.is_negative is False assert r.is_positive is True assert r.is_nonpositive is False assert r.is_nonnegative is True r = Rational(5, 3) assert r.is_nonnegative is True assert r.is_positive is True assert r.is_negative is False assert r.is_nonpositive is False def test_neg_rational(): r = Rational(-3, 4) assert r.is_positive is False assert r.is_nonpositive is True assert r.is_negative is True assert r.is_nonnegative is False r = Rational(-1, 4) assert r.is_nonpositive is True assert r.is_positive is False assert r.is_negative is True assert r.is_nonnegative is False r = Rational(-5, 4) assert r.is_negative is True assert r.is_positive is False assert r.is_nonpositive is True assert r.is_nonnegative is False r = Rational(-5, 3) assert r.is_nonnegative is False assert r.is_positive is False assert r.is_negative is True assert r.is_nonpositive is True def test_pi(): z = S.Pi assert z.is_commutative is True assert z.is_integer is False assert z.is_rational is False assert z.is_algebraic is False assert z.is_transcendental is True assert z.is_real is True assert z.is_complex is True assert z.is_noninteger is True assert z.is_irrational is True assert z.is_imaginary is False assert z.is_positive is True assert z.is_negative is False assert z.is_nonpositive is False assert z.is_nonnegative is True assert z.is_even is False assert z.is_odd is False assert z.is_finite is True assert z.is_infinite is False assert z.is_comparable is True assert z.is_prime is False assert z.is_composite is False def test_E(): z = S.Exp1 assert z.is_commutative is True assert z.is_integer is False assert z.is_rational is False assert z.is_algebraic is False assert z.is_transcendental is True assert z.is_real is True assert z.is_complex is True assert z.is_noninteger is True assert z.is_irrational is True assert z.is_imaginary is False assert z.is_positive is True assert z.is_negative is False assert z.is_nonpositive is False assert z.is_nonnegative is True assert z.is_even is False assert z.is_odd is False assert z.is_finite is True assert z.is_infinite is False assert z.is_comparable is True assert z.is_prime is False assert z.is_composite is False def test_I(): z = S.ImaginaryUnit assert z.is_commutative is True assert z.is_integer is False assert z.is_rational is False assert z.is_algebraic is True assert z.is_transcendental is False assert z.is_real is False assert z.is_complex is True assert z.is_noninteger is False assert z.is_irrational is False assert z.is_imaginary is True assert z.is_positive is False assert z.is_negative is False assert z.is_nonpositive is False assert z.is_nonnegative is False assert z.is_even is False assert z.is_odd is False assert z.is_finite is True assert z.is_infinite is False assert z.is_comparable is False assert z.is_prime is False assert z.is_composite is False def test_symbol_real_false(): # issue 3848 a = Symbol('a', real=False) assert a.is_real is False assert a.is_integer is False assert a.is_zero is False assert a.is_negative is False assert a.is_positive is False assert a.is_nonnegative is False assert a.is_nonpositive is False assert a.is_nonzero is False assert a.is_extended_negative is None assert a.is_extended_positive is None assert a.is_extended_nonnegative is None assert a.is_extended_nonpositive is None assert a.is_extended_nonzero is None def test_symbol_extended_real_false(): # issue 3848 a = Symbol('a', extended_real=False) assert a.is_real is False assert a.is_integer is False assert a.is_zero is False assert a.is_negative is False assert a.is_positive is False assert a.is_nonnegative is False assert a.is_nonpositive is False assert a.is_nonzero is False assert a.is_extended_negative is False assert a.is_extended_positive is False assert a.is_extended_nonnegative is False assert a.is_extended_nonpositive is False assert a.is_extended_nonzero is False def test_symbol_imaginary(): a = Symbol('a', imaginary=True) assert a.is_real is False assert a.is_integer is False assert a.is_negative is False assert a.is_positive is False assert a.is_nonnegative is False assert a.is_nonpositive is False assert a.is_zero is False assert a.is_nonzero is False # since nonzero -> real def test_symbol_zero(): x = Symbol('x', zero=True) assert x.is_positive is False assert x.is_nonpositive assert x.is_negative is False assert x.is_nonnegative assert x.is_zero is True # TODO Change to x.is_nonzero is None # See https://github.com/sympy/sympy/pull/9583 assert x.is_nonzero is False assert x.is_finite is True def test_symbol_positive(): x = Symbol('x', positive=True) assert x.is_positive is True assert x.is_nonpositive is False assert x.is_negative is False assert x.is_nonnegative is True assert x.is_zero is False assert x.is_nonzero is True def test_neg_symbol_positive(): x = -Symbol('x', positive=True) assert x.is_positive is False assert x.is_nonpositive is True assert x.is_negative is True assert x.is_nonnegative is False assert x.is_zero is False assert x.is_nonzero is True def test_symbol_nonpositive(): x = Symbol('x', nonpositive=True) assert x.is_positive is False assert x.is_nonpositive is True assert x.is_negative is None assert x.is_nonnegative is None assert x.is_zero is None assert x.is_nonzero is None def test_neg_symbol_nonpositive(): x = -Symbol('x', nonpositive=True) assert x.is_positive is None assert x.is_nonpositive is None assert x.is_negative is False assert x.is_nonnegative is True assert x.is_zero is None assert x.is_nonzero is None def test_symbol_falsepositive(): x = Symbol('x', positive=False) assert x.is_positive is False assert x.is_nonpositive is None assert x.is_negative is None assert x.is_nonnegative is None assert x.is_zero is None assert x.is_nonzero is None def test_symbol_falsepositive_mul(): # To test pull request 9379 # Explicit handling of arg.is_positive=False was added to Mul._eval_is_positive x = 2*Symbol('x', positive=False) assert x.is_positive is False # This was None before assert x.is_nonpositive is None assert x.is_negative is None assert x.is_nonnegative is None assert x.is_zero is None assert x.is_nonzero is None @XFAIL def test_symbol_infinitereal_mul(): ix = Symbol('ix', infinite=True, extended_real=True) assert (-ix).is_extended_positive is None def test_neg_symbol_falsepositive(): x = -Symbol('x', positive=False) assert x.is_positive is None assert x.is_nonpositive is None assert x.is_negative is False assert x.is_nonnegative is None assert x.is_zero is None assert x.is_nonzero is None def test_neg_symbol_falsenegative(): # To test pull request 9379 # Explicit handling of arg.is_negative=False was added to Mul._eval_is_positive x = -Symbol('x', negative=False) assert x.is_positive is False # This was None before assert x.is_nonpositive is None assert x.is_negative is None assert x.is_nonnegative is None assert x.is_zero is None assert x.is_nonzero is None def test_symbol_falsepositive_real(): x = Symbol('x', positive=False, real=True) assert x.is_positive is False assert x.is_nonpositive is True assert x.is_negative is None assert x.is_nonnegative is None assert x.is_zero is None assert x.is_nonzero is None def test_neg_symbol_falsepositive_real(): x = -Symbol('x', positive=False, real=True) assert x.is_positive is None assert x.is_nonpositive is None assert x.is_negative is False assert x.is_nonnegative is True assert x.is_zero is None assert x.is_nonzero is None def test_symbol_falsenonnegative(): x = Symbol('x', nonnegative=False) assert x.is_positive is False assert x.is_nonpositive is None assert x.is_negative is None assert x.is_nonnegative is False assert x.is_zero is False assert x.is_nonzero is None @XFAIL def test_neg_symbol_falsenonnegative(): x = -Symbol('x', nonnegative=False) assert x.is_positive is None assert x.is_nonpositive is False # this currently returns None assert x.is_negative is False # this currently returns None assert x.is_nonnegative is None assert x.is_zero is False # this currently returns None assert x.is_nonzero is True # this currently returns None def test_symbol_falsenonnegative_real(): x = Symbol('x', nonnegative=False, real=True) assert x.is_positive is False assert x.is_nonpositive is True assert x.is_negative is True assert x.is_nonnegative is False assert x.is_zero is False assert x.is_nonzero is True def test_neg_symbol_falsenonnegative_real(): x = -Symbol('x', nonnegative=False, real=True) assert x.is_positive is True assert x.is_nonpositive is False assert x.is_negative is False assert x.is_nonnegative is True assert x.is_zero is False assert x.is_nonzero is True def test_prime(): assert S.NegativeOne.is_prime is False assert S(-2).is_prime is False assert S(-4).is_prime is False assert S.Zero.is_prime is False assert S.One.is_prime is False assert S(2).is_prime is True assert S(17).is_prime is True assert S(4).is_prime is False def test_composite(): assert S.NegativeOne.is_composite is False assert S(-2).is_composite is False assert S(-4).is_composite is False assert S.Zero.is_composite is False assert S(2).is_composite is False assert S(17).is_composite is False assert S(4).is_composite is True x = Dummy(integer=True, positive=True, prime=False) assert x.is_composite is None # x could be 1 assert (x + 1).is_composite is None x = Dummy(positive=True, even=True, prime=False) assert x.is_integer is True assert x.is_composite is True def test_prime_symbol(): x = Symbol('x', prime=True) assert x.is_prime is True assert x.is_integer is True assert x.is_positive is True assert x.is_negative is False assert x.is_nonpositive is False assert x.is_nonnegative is True x = Symbol('x', prime=False) assert x.is_prime is False assert x.is_integer is None assert x.is_positive is None assert x.is_negative is None assert x.is_nonpositive is None assert x.is_nonnegative is None def test_symbol_noncommutative(): x = Symbol('x', commutative=True) assert x.is_complex is None x = Symbol('x', commutative=False) assert x.is_integer is False assert x.is_rational is False assert x.is_algebraic is False assert x.is_irrational is False assert x.is_real is False assert x.is_complex is False def test_other_symbol(): x = Symbol('x', integer=True) assert x.is_integer is True assert x.is_real is True assert x.is_finite is True x = Symbol('x', integer=True, nonnegative=True) assert x.is_integer is True assert x.is_nonnegative is True assert x.is_negative is False assert x.is_positive is None assert x.is_finite is True x = Symbol('x', integer=True, nonpositive=True) assert x.is_integer is True assert x.is_nonpositive is True assert x.is_positive is False assert x.is_negative is None assert x.is_finite is True x = Symbol('x', odd=True) assert x.is_odd is True assert x.is_even is False assert x.is_integer is True assert x.is_finite is True x = Symbol('x', odd=False) assert x.is_odd is False assert x.is_even is None assert x.is_integer is None assert x.is_finite is None x = Symbol('x', even=True) assert x.is_even is True assert x.is_odd is False assert x.is_integer is True assert x.is_finite is True x = Symbol('x', even=False) assert x.is_even is False assert x.is_odd is None assert x.is_integer is None assert x.is_finite is None x = Symbol('x', integer=True, nonnegative=True) assert x.is_integer is True assert x.is_nonnegative is True assert x.is_finite is True x = Symbol('x', integer=True, nonpositive=True) assert x.is_integer is True assert x.is_nonpositive is True assert x.is_finite is True x = Symbol('x', rational=True) assert x.is_real is True assert x.is_finite is True x = Symbol('x', rational=False) assert x.is_real is None assert x.is_finite is None x = Symbol('x', irrational=True) assert x.is_real is True assert x.is_finite is True x = Symbol('x', irrational=False) assert x.is_real is None assert x.is_finite is None with raises(AttributeError): x.is_real = False x = Symbol('x', algebraic=True) assert x.is_transcendental is False x = Symbol('x', transcendental=True) assert x.is_algebraic is False assert x.is_rational is False assert x.is_integer is False def test_issue_3825(): """catch: hash instability""" x = Symbol("x") y = Symbol("y") a1 = x + y a2 = y + x a2.is_comparable h1 = hash(a1) h2 = hash(a2) assert h1 == h2 def test_issue_4822(): z = (-1)**Rational(1, 3)*(1 - I*sqrt(3)) assert z.is_real in [True, None] def test_hash_vs_typeinfo(): """seemingly different typeinfo, but in fact equal""" # the following two are semantically equal x1 = Symbol('x', even=True) x2 = Symbol('x', integer=True, odd=False) assert hash(x1) == hash(x2) assert x1 == x2 def test_hash_vs_typeinfo_2(): """different typeinfo should mean !eq""" # the following two are semantically different x = Symbol('x') x1 = Symbol('x', even=True) assert x != x1 assert hash(x) != hash(x1) # This might fail with very low probability def test_hash_vs_eq(): """catch: different hash for equal objects""" a = 1 + S.Pi # important: do not fold it into a Number instance ha = hash(a) # it should be Add/Mul/... to trigger the bug a.is_positive # this uses .evalf() and deduces it is positive assert a.is_positive is True # be sure that hash stayed the same assert ha == hash(a) # now b should be the same expression b = a.expand(trig=True) hb = hash(b) assert a == b assert ha == hb def test_Add_is_pos_neg(): # these cover lines not covered by the rest of tests in core n = Symbol('n', extended_negative=True, infinite=True) nn = Symbol('n', extended_nonnegative=True, infinite=True) np = Symbol('n', extended_nonpositive=True, infinite=True) p = Symbol('p', extended_positive=True, infinite=True) r = Dummy(extended_real=True, finite=False) x = Symbol('x') xf = Symbol('xf', finite=True) assert (n + p).is_extended_positive is None assert (n + x).is_extended_positive is None assert (p + x).is_extended_positive is None assert (n + p).is_extended_negative is None assert (n + x).is_extended_negative is None assert (p + x).is_extended_negative is None assert (n + xf).is_extended_positive is False assert (p + xf).is_extended_positive is True assert (n + xf).is_extended_negative is True assert (p + xf).is_extended_negative is False assert (x - S.Infinity).is_extended_negative is None # issue 7798 # issue 8046, 16.2 assert (p + nn).is_extended_positive assert (n + np).is_extended_negative assert (p + r).is_extended_positive is None def test_Add_is_imaginary(): nn = Dummy(nonnegative=True) assert (I*nn + I).is_imaginary # issue 8046, 17 def test_Add_is_algebraic(): a = Symbol('a', algebraic=True) b = Symbol('a', algebraic=True) na = Symbol('na', algebraic=False) nb = Symbol('nb', algebraic=False) x = Symbol('x') assert (a + b).is_algebraic assert (na + nb).is_algebraic is None assert (a + na).is_algebraic is False assert (a + x).is_algebraic is None assert (na + x).is_algebraic is None def test_Mul_is_algebraic(): a = Symbol('a', algebraic=True) b = Symbol('b', algebraic=True) na = Symbol('na', algebraic=False) an = Symbol('an', algebraic=True, nonzero=True) nb = Symbol('nb', algebraic=False) x = Symbol('x') assert (a*b).is_algebraic is True assert (na*nb).is_algebraic is None assert (a*na).is_algebraic is None assert (an*na).is_algebraic is False assert (a*x).is_algebraic is None assert (na*x).is_algebraic is None def test_Pow_is_algebraic(): e = Symbol('e', algebraic=True) assert Pow(1, e, evaluate=False).is_algebraic assert Pow(0, e, evaluate=False).is_algebraic a = Symbol('a', algebraic=True) azf = Symbol('azf', algebraic=True, zero=False) na = Symbol('na', algebraic=False) ia = Symbol('ia', algebraic=True, irrational=True) ib = Symbol('ib', algebraic=True, irrational=True) r = Symbol('r', rational=True) x = Symbol('x') assert (a**2).is_algebraic is True assert (a**r).is_algebraic is None assert (azf**r).is_algebraic is True assert (a**x).is_algebraic is None assert (na**r).is_algebraic is None assert (ia**r).is_algebraic is True assert (ia**ib).is_algebraic is False assert (a**e).is_algebraic is None # Gelfond-Schneider constant: assert Pow(2, sqrt(2), evaluate=False).is_algebraic is False assert Pow(S.GoldenRatio, sqrt(3), evaluate=False).is_algebraic is False # issue 8649 t = Symbol('t', real=True, transcendental=True) n = Symbol('n', integer=True) assert (t**n).is_algebraic is None assert (t**n).is_integer is None assert (pi**3).is_algebraic is False r = Symbol('r', zero=True) assert (pi**r).is_algebraic is True def test_Mul_is_prime_composite(): x = Symbol('x', positive=True, integer=True) y = Symbol('y', positive=True, integer=True) assert (x*y).is_prime is None assert ( (x+1)*(y+1) ).is_prime is False assert ( (x+1)*(y+1) ).is_composite is True x = Symbol('x', positive=True) assert ( (x+1)*(y+1) ).is_prime is None assert ( (x+1)*(y+1) ).is_composite is None def test_Pow_is_pos_neg(): z = Symbol('z', real=True) w = Symbol('w', nonpositive=True) assert (S.NegativeOne**S(2)).is_positive is True assert (S.One**z).is_positive is True assert (S.NegativeOne**S(3)).is_positive is False assert (S.Zero**S.Zero).is_positive is True # 0**0 is 1 assert (w**S(3)).is_positive is False assert (w**S(2)).is_positive is None assert (I**2).is_positive is False assert (I**4).is_positive is True # tests emerging from #16332 issue p = Symbol('p', zero=True) q = Symbol('q', zero=False, real=True) j = Symbol('j', zero=False, even=True) x = Symbol('x', zero=True) y = Symbol('y', zero=True) assert (p**q).is_positive is False assert (p**q).is_negative is False assert (p**j).is_positive is False assert (x**y).is_positive is True # 0**0 assert (x**y).is_negative is False def test_Pow_is_prime_composite(): x = Symbol('x', positive=True, integer=True) y = Symbol('y', positive=True, integer=True) assert (x**y).is_prime is None assert ( x**(y+1) ).is_prime is False assert ( x**(y+1) ).is_composite is None assert ( (x+1)**(y+1) ).is_composite is True assert ( (-x-1)**(2*y) ).is_composite is True x = Symbol('x', positive=True) assert (x**y).is_prime is None def test_Mul_is_infinite(): x = Symbol('x') f = Symbol('f', finite=True) i = Symbol('i', infinite=True) z = Dummy(zero=True) nzf = Dummy(finite=True, zero=False) from sympy import Mul assert (x*f).is_finite is None assert (x*i).is_finite is None assert (f*i).is_finite is None assert (x*f*i).is_finite is None assert (z*i).is_finite is None assert (nzf*i).is_finite is False assert (z*f).is_finite is True assert Mul(0, f, evaluate=False).is_finite is True assert Mul(0, i, evaluate=False).is_finite is None assert (x*f).is_infinite is None assert (x*i).is_infinite is None assert (f*i).is_infinite is None assert (x*f*i).is_infinite is None assert (z*i).is_infinite is S.NaN.is_infinite assert (nzf*i).is_infinite is True assert (z*f).is_infinite is False assert Mul(0, f, evaluate=False).is_infinite is False assert Mul(0, i, evaluate=False).is_infinite is S.NaN.is_infinite def test_Add_is_infinite(): x = Symbol('x') f = Symbol('f', finite=True) i = Symbol('i', infinite=True) i2 = Symbol('i2', infinite=True) z = Dummy(zero=True) nzf = Dummy(finite=True, zero=False) from sympy import Add assert (x+f).is_finite is None assert (x+i).is_finite is None assert (f+i).is_finite is False assert (x+f+i).is_finite is None assert (z+i).is_finite is False assert (nzf+i).is_finite is False assert (z+f).is_finite is True assert (i+i2).is_finite is None assert Add(0, f, evaluate=False).is_finite is True assert Add(0, i, evaluate=False).is_finite is False assert (x+f).is_infinite is None assert (x+i).is_infinite is None assert (f+i).is_infinite is True assert (x+f+i).is_infinite is None assert (z+i).is_infinite is True assert (nzf+i).is_infinite is True assert (z+f).is_infinite is False assert (i+i2).is_infinite is None assert Add(0, f, evaluate=False).is_infinite is False assert Add(0, i, evaluate=False).is_infinite is True def test_special_is_rational(): i = Symbol('i', integer=True) i2 = Symbol('i2', integer=True) ni = Symbol('ni', integer=True, nonzero=True) r = Symbol('r', rational=True) rn = Symbol('r', rational=True, nonzero=True) nr = Symbol('nr', irrational=True) x = Symbol('x') assert sqrt(3).is_rational is False assert (3 + sqrt(3)).is_rational is False assert (3*sqrt(3)).is_rational is False assert exp(3).is_rational is False assert exp(ni).is_rational is False assert exp(rn).is_rational is False assert exp(x).is_rational is None assert exp(log(3), evaluate=False).is_rational is True assert log(exp(3), evaluate=False).is_rational is True assert log(3).is_rational is False assert log(ni + 1).is_rational is False assert log(rn + 1).is_rational is False assert log(x).is_rational is None assert (sqrt(3) + sqrt(5)).is_rational is None assert (sqrt(3) + S.Pi).is_rational is False assert (x**i).is_rational is None assert (i**i).is_rational is True assert (i**i2).is_rational is None assert (r**i).is_rational is None assert (r**r).is_rational is None assert (r**x).is_rational is None assert (nr**i).is_rational is None # issue 8598 assert (nr**Symbol('z', zero=True)).is_rational assert sin(1).is_rational is False assert sin(ni).is_rational is False assert sin(rn).is_rational is False assert sin(x).is_rational is None assert asin(r).is_rational is False assert sin(asin(3), evaluate=False).is_rational is True @XFAIL def test_issue_6275(): x = Symbol('x') # both zero or both Muls...but neither "change would be very appreciated. # This is similar to x/x => 1 even though if x = 0, it is really nan. assert isinstance(x*0, type(0*S.Infinity)) if 0*S.Infinity is S.NaN: b = Symbol('b', finite=None) assert (b*0).is_zero is None def test_sanitize_assumptions(): # issue 6666 for cls in (Symbol, Dummy, Wild): x = cls('x', real=1, positive=0) assert x.is_real is True assert x.is_positive is False assert cls('', real=True, positive=None).is_positive is None raises(ValueError, lambda: cls('', commutative=None)) raises(ValueError, lambda: Symbol._sanitize(dict(commutative=None))) def test_special_assumptions(): e = -3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2 assert simplify(e < 0) is S.false assert simplify(e > 0) is S.false assert (e == 0) is False # it's not a literal 0 assert e.equals(0) is True def test_inconsistent(): # cf. issues 5795 and 5545 raises(InconsistentAssumptions, lambda: Symbol('x', real=True, commutative=False)) def test_issue_6631(): assert ((-1)**(I)).is_real is True assert ((-1)**(I*2)).is_real is True assert ((-1)**(I/2)).is_real is True assert ((-1)**(I*S.Pi)).is_real is True assert (I**(I + 2)).is_real is True def test_issue_2730(): assert (1/(1 + I)).is_real is False def test_issue_4149(): assert (3 + I).is_complex assert (3 + I).is_imaginary is False assert (3*I + S.Pi*I).is_imaginary # as Zero.is_imaginary is False, see issue 7649 y = Symbol('y', real=True) assert (3*I + S.Pi*I + y*I).is_imaginary is None p = Symbol('p', positive=True) assert (3*I + S.Pi*I + p*I).is_imaginary n = Symbol('n', negative=True) assert (-3*I - S.Pi*I + n*I).is_imaginary i = Symbol('i', imaginary=True) assert ([(i**a).is_imaginary for a in range(4)] == [False, True, False, True]) # tests from the PR #7887: e = S("-sqrt(3)*I/2 + 0.866025403784439*I") assert e.is_real is False assert e.is_imaginary def test_issue_2920(): n = Symbol('n', negative=True) assert sqrt(n).is_imaginary def test_issue_7899(): x = Symbol('x', real=True) assert (I*x).is_real is None assert ((x - I)*(x - 1)).is_zero is None assert ((x - I)*(x - 1)).is_real is None @XFAIL def test_issue_7993(): x = Dummy(integer=True) y = Dummy(noninteger=True) assert (x - y).is_zero is False def test_issue_8075(): raises(InconsistentAssumptions, lambda: Dummy(zero=True, finite=False)) raises(InconsistentAssumptions, lambda: Dummy(zero=True, infinite=True)) def test_issue_8642(): x = Symbol('x', real=True, integer=False) assert (x*2).is_integer is None, (x*2).is_integer def test_issues_8632_8633_8638_8675_8992(): p = Dummy(integer=True, positive=True) nn = Dummy(integer=True, nonnegative=True) assert (p - S.Half).is_positive assert (p - 1).is_nonnegative assert (nn + 1).is_positive assert (-p + 1).is_nonpositive assert (-nn - 1).is_negative prime = Dummy(prime=True) assert (prime - 2).is_nonnegative assert (prime - 3).is_nonnegative is None even = Dummy(positive=True, even=True) assert (even - 2).is_nonnegative p = Dummy(positive=True) assert (p/(p + 1) - 1).is_negative assert ((p + 2)**3 - S.Half).is_positive n = Dummy(negative=True) assert (n - 3).is_nonpositive def test_issue_9115_9150(): n = Dummy('n', integer=True, nonnegative=True) assert (factorial(n) >= 1) == True assert (factorial(n) < 1) == False assert factorial(n + 1).is_even is None assert factorial(n + 2).is_even is True assert factorial(n + 2) >= 2 def test_issue_9165(): z = Symbol('z', zero=True) f = Symbol('f', finite=False) assert 0/z is S.NaN assert 0*(1/z) is S.NaN assert 0*f is S.NaN def test_issue_10024(): x = Dummy('x') assert Mod(x, 2*pi).is_zero is None def test_issue_10302(): x = Symbol('x') r = Symbol('r', real=True) u = -(3*2**pi)**(1/pi) + 2*3**(1/pi) i = u + u*I assert i.is_real is None # w/o simplification this should fail assert (u + i).is_zero is None assert (1 + i).is_zero is False a = Dummy('a', zero=True) assert (a + I).is_zero is False assert (a + r*I).is_zero is None assert (a + I).is_imaginary assert (a + x + I).is_imaginary is None assert (a + r*I + I).is_imaginary is None def test_complex_reciprocal_imaginary(): assert (1 / (4 + 3*I)).is_imaginary is False def test_issue_16313(): x = Symbol('x', extended_real=False) k = Symbol('k', real=True) l = Symbol('l', real=True, zero=False) assert (-x).is_real is False assert (k*x).is_real is None # k can be zero also assert (l*x).is_real is False assert (l*x*x).is_real is None # since x*x can be a real number assert (-x).is_positive is False def test_issue_16579(): # extended_real -> finite | infinite x = Symbol('x', extended_real=True, infinite=False) y = Symbol('y', extended_real=True, finite=False) assert x.is_finite is True assert y.is_infinite is True # With PR 16978, complex now implies finite c = Symbol('c', complex=True) assert c.is_finite is True raises(InconsistentAssumptions, lambda: Dummy(complex=True, finite=False)) # Now infinite == !finite nf = Symbol('nf', finite=False) assert nf.is_infinite is True def test_issue_17556(): z = I*oo assert z.is_imaginary is False assert z.is_finite is False def test_issue_21651(): k = Symbol('k', positive=True, integer=True) exp = 2*2**(-k) assert exp.is_integer is None def test_assumptions_copy(): assert assumptions(Symbol('x'), dict(commutative=True) ) == {'commutative': True} assert assumptions(Symbol('x'), ['integer']) == {} assert assumptions(Symbol('x'), ['commutative'] ) == {'commutative': True} assert assumptions(Symbol('x')) == {'commutative': True} assert assumptions(1)['positive'] assert assumptions(3 + I) == { 'algebraic': True, 'commutative': True, 'complex': True, 'composite': False, 'even': False, 'extended_negative': False, 'extended_nonnegative': False, 'extended_nonpositive': False, 'extended_nonzero': False, 'extended_positive': False, 'extended_real': False, 'finite': True, 'imaginary': False, 'infinite': False, 'integer': False, 'irrational': False, 'negative': False, 'noninteger': False, 'nonnegative': False, 'nonpositive': False, 'nonzero': False, 'odd': False, 'positive': False, 'prime': False, 'rational': False, 'real': False, 'transcendental': False, 'zero': False} def test_check_assumptions(): assert check_assumptions(1, 0) is False x = Symbol('x', positive=True) assert check_assumptions(1, x) is True assert check_assumptions(1, 1) is True assert check_assumptions(-1, 1) is False i = Symbol('i', integer=True) # don't know if i is positive (or prime, etc...) assert check_assumptions(i, 1) is None assert check_assumptions(Dummy(integer=None), integer=True) is None assert check_assumptions(Dummy(integer=None), integer=False) is None assert check_assumptions(Dummy(integer=False), integer=True) is False assert check_assumptions(Dummy(integer=True), integer=False) is False # no T/F assumptions to check assert check_assumptions(Dummy(integer=False), integer=None) is True raises(ValueError, lambda: check_assumptions(2*x, x, positive=True)) def test_failing_assumptions(): x = Symbol('x', real=True, positive=True) y = Symbol('y') assert failing_assumptions(6*x + y, **x.assumptions0) == \ {'real': None, 'imaginary': None, 'complex': None, 'hermitian': None, 'positive': None, 'nonpositive': None, 'nonnegative': None, 'nonzero': None, 'negative': None, 'zero': None, 'extended_real': None, 'finite': None, 'infinite': None, 'extended_negative': None, 'extended_nonnegative': None, 'extended_nonpositive': None, 'extended_nonzero': None, 'extended_positive': None } def test_common_assumptions(): assert common_assumptions([0, 1, 2] ) == {'algebraic': True, 'irrational': False, 'hermitian': True, 'extended_real': True, 'real': True, 'extended_negative': False, 'extended_nonnegative': True, 'integer': True, 'rational': True, 'imaginary': False, 'complex': True, 'commutative': True,'noninteger': False, 'composite': False, 'infinite': False, 'nonnegative': True, 'finite': True, 'transcendental': False,'negative': False} assert common_assumptions([0, 1, 2], 'positive integer'.split() ) == {'integer': True} assert common_assumptions([0, 1, 2], []) == {} assert common_assumptions([], ['integer']) == {} assert common_assumptions([0], ['integer']) == {'integer': True} sympy-sympy-1.9/sympy/core/tests/test_basic.py000066400000000000000000000227341412543434000217000ustar00rootroot00000000000000"""This tests sympy/core/basic.py with (ideally) no reference to subclasses of Basic or Atom.""" import collections from sympy.core.basic import (Basic, Atom, preorder_traversal, as_Basic, _atomic, _aresame) from sympy.core.singleton import S from sympy.core.symbol import symbols, Symbol, Dummy from sympy.core.sympify import SympifyError from sympy.core.function import Function, Lambda from sympy.core.compatibility import default_sort_key from sympy import sin, Q, cos, gamma, Tuple, Integral, Sum from sympy.functions.elementary.exponential import exp from sympy.testing.pytest import raises from sympy.core import I, pi b1 = Basic() b2 = Basic(b1) b3 = Basic(b2) b21 = Basic(b2, b1) def test__aresame(): assert not _aresame(Basic([]), Basic()) assert not _aresame(Basic([]), Basic(())) assert not _aresame(Basic(2), Basic(2.)) def test_structure(): assert b21.args == (b2, b1) assert b21.func(*b21.args) == b21 assert bool(b1) def test_immutable(): assert not hasattr(b1, '__dict__') with raises(AttributeError): b1.x = 1 def test_equality(): instances = [b1, b2, b3, b21, Basic(b1, b1, b1), Basic] for i, b_i in enumerate(instances): for j, b_j in enumerate(instances): assert (b_i == b_j) == (i == j) assert (b_i != b_j) == (i != j) assert Basic() != [] assert not(Basic() == []) assert Basic() != 0 assert not(Basic() == 0) class Foo: """ Class that is unaware of Basic, and relies on both classes returning the NotImplemented singleton for equivalence to evaluate to False. """ b = Basic() foo = Foo() assert b != foo assert foo != b assert not b == foo assert not foo == b class Bar: """ Class that considers itself equal to any instance of Basic, and relies on Basic returning the NotImplemented singleton in order to achieve a symmetric equivalence relation. """ def __eq__(self, other): if isinstance(other, Basic): return True return NotImplemented def __ne__(self, other): return not self == other bar = Bar() assert b == bar assert bar == b assert not b != bar assert not bar != b def test_matches_basic(): instances = [Basic(b1, b1, b2), Basic(b1, b2, b1), Basic(b2, b1, b1), Basic(b1, b2), Basic(b2, b1), b2, b1] for i, b_i in enumerate(instances): for j, b_j in enumerate(instances): if i == j: assert b_i.matches(b_j) == {} else: assert b_i.matches(b_j) is None assert b1.match(b1) == {} def test_has(): assert b21.has(b1) assert b21.has(b3, b1) assert b21.has(Basic) assert not b1.has(b21, b3) assert not b21.has() raises(SympifyError, lambda: Symbol("x").has("x")) def test_subs(): assert b21.subs(b2, b1) == Basic(b1, b1) assert b21.subs(b2, b21) == Basic(b21, b1) assert b3.subs(b2, b1) == b2 assert b21.subs([(b2, b1), (b1, b2)]) == Basic(b2, b2) assert b21.subs({b1: b2, b2: b1}) == Basic(b2, b2) assert b21.subs(collections.ChainMap({b1: b2}, {b2: b1})) == Basic(b2, b2) assert b21.subs(collections.OrderedDict([(b2, b1), (b1, b2)])) == Basic(b2, b2) raises(ValueError, lambda: b21.subs('bad arg')) raises(ValueError, lambda: b21.subs(b1, b2, b3)) # dict(b1=foo) creates a string 'b1' but leaves foo unchanged; subs # will convert the first to a symbol but will raise an error if foo # cannot be sympified; sympification is strict if foo is not string raises(ValueError, lambda: b21.subs(b1='bad arg')) assert Symbol("text").subs({"text": b1}) == b1 assert Symbol("s").subs({"s": 1}) == 1 def test_subs_with_unicode_symbols(): expr = Symbol('var1') replaced = expr.subs('var1', 'x') assert replaced.name == 'x' replaced = expr.subs('var1', 'x') assert replaced.name == 'x' def test_atoms(): assert b21.atoms() == {Basic()} def test_free_symbols_empty(): assert b21.free_symbols == set() def test_doit(): assert b21.doit() == b21 assert b21.doit(deep=False) == b21 def test_S(): assert repr(S) == 'S' def test_xreplace(): assert b21.xreplace({b2: b1}) == Basic(b1, b1) assert b21.xreplace({b2: b21}) == Basic(b21, b1) assert b3.xreplace({b2: b1}) == b2 assert Basic(b1, b2).xreplace({b1: b2, b2: b1}) == Basic(b2, b1) assert Atom(b1).xreplace({b1: b2}) == Atom(b1) assert Atom(b1).xreplace({Atom(b1): b2}) == b2 raises(TypeError, lambda: b1.xreplace()) raises(TypeError, lambda: b1.xreplace([b1, b2])) for f in (exp, Function('f')): assert f.xreplace({}) == f assert f.xreplace({}, hack2=True) == f assert f.xreplace({f: b1}) == b1 assert f.xreplace({f: b1}, hack2=True) == b1 def test_preorder_traversal(): expr = Basic(b21, b3) assert list( preorder_traversal(expr)) == [expr, b21, b2, b1, b1, b3, b2, b1] assert list(preorder_traversal(('abc', ('d', 'ef')))) == [ ('abc', ('d', 'ef')), 'abc', ('d', 'ef'), 'd', 'ef'] result = [] pt = preorder_traversal(expr) for i in pt: result.append(i) if i == b2: pt.skip() assert result == [expr, b21, b2, b1, b3, b2] w, x, y, z = symbols('w:z') expr = z + w*(x + y) assert list(preorder_traversal([expr], keys=default_sort_key)) == \ [[w*(x + y) + z], w*(x + y) + z, z, w*(x + y), w, x + y, x, y] assert list(preorder_traversal((x + y)*z, keys=True)) == \ [z*(x + y), z, x + y, x, y] def test_sorted_args(): x = symbols('x') assert b21._sorted_args == b21.args raises(AttributeError, lambda: x._sorted_args) def test_call(): x, y = symbols('x y') # See the long history of this in issues 5026 and 5105. raises(TypeError, lambda: sin(x)({ x : 1, sin(x) : 2})) raises(TypeError, lambda: sin(x)(1)) # No effect as there are no callables assert sin(x).rcall(1) == sin(x) assert (1 + sin(x)).rcall(1) == 1 + sin(x) # Effect in the pressence of callables l = Lambda(x, 2*x) assert (l + x).rcall(y) == 2*y + x assert (x**l).rcall(2) == x**4 # TODO UndefinedFunction does not subclass Expr #f = Function('f') #assert (2*f)(x) == 2*f(x) assert (Q.real & Q.positive).rcall(x) == Q.real(x) & Q.positive(x) def test_rewrite(): x, y, z = symbols('x y z') a, b = symbols('a b') f1 = sin(x) + cos(x) assert f1.rewrite(cos,exp) == exp(I*x)/2 + sin(x) + exp(-I*x)/2 assert f1.rewrite([cos],sin) == sin(x) + sin(x + pi/2, evaluate=False) f2 = sin(x) + cos(y)/gamma(z) assert f2.rewrite(sin,exp) == -I*(exp(I*x) - exp(-I*x))/2 + cos(y)/gamma(z) assert f1.rewrite() == f1 def test_literal_evalf_is_number_is_zero_is_comparable(): from sympy.integrals.integrals import Integral from sympy.core.symbol import symbols from sympy.core.function import Function from sympy.functions.elementary.trigonometric import cos, sin x = symbols('x') f = Function('f') # issue 5033 assert f.is_number is False # issue 6646 assert f(1).is_number is False i = Integral(0, (x, x, x)) # expressions that are symbolically 0 can be difficult to prove # so in case there is some easy way to know if something is 0 # it should appear in the is_zero property for that object; # if is_zero is true evalf should always be able to compute that # zero assert i.n() == 0 assert i.is_zero assert i.is_number is False assert i.evalf(2, strict=False) == 0 # issue 10268 n = sin(1)**2 + cos(1)**2 - 1 assert n.is_comparable is False assert n.n(2).is_comparable is False assert n.n(2).n(2).is_comparable def test_as_Basic(): assert as_Basic(1) is S.One assert as_Basic(()) == Tuple() raises(TypeError, lambda: as_Basic([])) def test_atomic(): g, h = map(Function, 'gh') x = symbols('x') assert _atomic(g(x + h(x))) == {g(x + h(x))} assert _atomic(g(x + h(x)), recursive=True) == {h(x), x, g(x + h(x))} assert _atomic(1) == set() assert _atomic(Basic(1,2)) == {Basic(1, 2)} def test_as_dummy(): u, v, x, y, z, _0, _1 = symbols('u v x y z _0 _1') assert Lambda(x, x + 1).as_dummy() == Lambda(_0, _0 + 1) assert Lambda(x, x + _0).as_dummy() == Lambda(_1, _0 + _1) eq = (1 + Sum(x, (x, 1, x))) ans = 1 + Sum(_0, (_0, 1, x)) once = eq.as_dummy() assert once == ans twice = once.as_dummy() assert twice == ans assert Integral(x + _0, (x, x + 1), (_0, 1, 2) ).as_dummy() == Integral(_0 + _1, (_0, x + 1), (_1, 1, 2)) for T in (Symbol, Dummy): d = T('x', real=True) D = d.as_dummy() assert D != d and D.func == Dummy and D.is_real is None assert Dummy().as_dummy().is_commutative assert Dummy(commutative=False).as_dummy().is_commutative is False def test_canonical_variables(): x, i0, i1 = symbols('x _:2') assert Integral(x, (x, x + 1)).canonical_variables == {x: i0} assert Integral(x, (x, x + 1), (i0, 1, 2)).canonical_variables == { x: i0, i0: i1} assert Integral(x, (x, x + i0)).canonical_variables == {x: i1} def test_replace_exceptions(): from sympy import Wild x, y = symbols('x y') e = (x**2 + x*y) raises(TypeError, lambda: e.replace(sin, 2)) b = Wild('b') c = Wild('c') raises(TypeError, lambda: e.replace(b*c, c.is_real)) raises(TypeError, lambda: e.replace(b.is_real, 1)) raises(TypeError, lambda: e.replace(lambda d: d.is_Number, 1)) sympy-sympy-1.9/sympy/core/tests/test_cache.py000066400000000000000000000021371412543434000216550ustar00rootroot00000000000000from sympy.core.cache import cacheit from sympy.testing.pytest import raises def test_cacheit_doc(): @cacheit def testfn(): "test docstring" pass assert testfn.__doc__ == "test docstring" assert testfn.__name__ == "testfn" def test_cacheit_unhashable(): @cacheit def testit(x): return x assert testit(1) == 1 assert testit(1) == 1 a = {} assert testit(a) == {} a[1] = 2 assert testit(a) == {1: 2} def test_cachit_exception(): # Make sure the cache doesn't call functions multiple times when they # raise TypeError a = [] @cacheit def testf(x): a.append(0) raise TypeError raises(TypeError, lambda: testf(1)) assert len(a) == 1 a.clear() # Unhashable type raises(TypeError, lambda: testf([])) assert len(a) == 1 @cacheit def testf2(x): a.append(0) raise TypeError("Error") a.clear() raises(TypeError, lambda: testf2(1)) assert len(a) == 1 a.clear() # Unhashable type raises(TypeError, lambda: testf2([])) assert len(a) == 1 sympy-sympy-1.9/sympy/core/tests/test_compatibility.py000066400000000000000000000046321412543434000234650ustar00rootroot00000000000000from sympy.core.compatibility import (default_sort_key, as_int, ordered, iterable, NotIterable) from sympy.core.singleton import S from sympy.testing.pytest import raises from sympy.abc import x def test_default_sort_key(): func = lambda x: x assert sorted([func, x, func], key=default_sort_key) == [func, func, x] class C: def __repr__(self): return 'x.y' func = C() assert sorted([x, func], key=default_sort_key) == [func, x] def test_as_int(): raises(ValueError, lambda : as_int(True)) raises(ValueError, lambda : as_int(1.1)) raises(ValueError, lambda : as_int([])) raises(ValueError, lambda : as_int(S.NaN)) raises(ValueError, lambda : as_int(S.Infinity)) raises(ValueError, lambda : as_int(S.NegativeInfinity)) raises(ValueError, lambda : as_int(S.ComplexInfinity)) # for the following, limited precision makes int(arg) == arg # but the int value is not necessarily what a user might have # expected; Q.prime is more nuanced in its response for # expressions which might be complex representations of an # integer. This is not -- by design -- as_ints role. raises(ValueError, lambda : as_int(1e23)) raises(ValueError, lambda : as_int(S('1.'+'0'*20+'1'))) assert as_int(True, strict=False) == 1 def test_iterable(): assert iterable(0) is False assert iterable(1) is False assert iterable(None) is False class Test1(NotIterable): pass assert iterable(Test1()) is False class Test2(NotIterable): _iterable = True assert iterable(Test2()) is True class Test3: pass assert iterable(Test3()) is False class Test4: _iterable = True assert iterable(Test4()) is True class Test5: def __iter__(self): yield 1 assert iterable(Test5()) is True class Test6(Test5): _iterable = False assert iterable(Test6()) is False def test_ordered(): # Issue 7210 - this had been failing with python2/3 problems assert (list(ordered([{1:3, 2:4, 9:10}, {1:3}])) == \ [{1: 3}, {1: 3, 2: 4, 9: 10}]) # warnings should not be raised for identical items l = [1, 1] assert list(ordered(l, warn=True)) == l l = [[1], [2], [1]] assert list(ordered(l, warn=True)) == [[1], [1], [2]] raises(ValueError, lambda: list(ordered(['a', 'ab'], keys=[lambda x: x[0]], default=False, warn=True))) sympy-sympy-1.9/sympy/core/tests/test_complex.py000066400000000000000000000520151412543434000222610ustar00rootroot00000000000000from sympy import (S, Symbol, sqrt, I, Integer, Rational, cos, sin, im, re, Abs, exp, sinh, cosh, tan, tanh, conjugate, sign, cot, coth, pi, symbols, expand_complex, Pow) def test_complex(): a = Symbol("a", real=True) b = Symbol("b", real=True) e = (a + I*b)*(a - I*b) assert e.expand() == a**2 + b**2 assert sqrt(I) == Pow(I, S.Half) def test_conjugate(): a = Symbol("a", real=True) b = Symbol("b", real=True) c = Symbol("c", imaginary=True) d = Symbol("d", imaginary=True) x = Symbol('x') z = a + I*b + c + I*d zc = a - I*b - c + I*d assert conjugate(z) == zc assert conjugate(exp(z)) == exp(zc) assert conjugate(exp(I*x)) == exp(-I*conjugate(x)) assert conjugate(z**5) == zc**5 assert conjugate(abs(x)) == abs(x) assert conjugate(sign(z)) == sign(zc) assert conjugate(sin(z)) == sin(zc) assert conjugate(cos(z)) == cos(zc) assert conjugate(tan(z)) == tan(zc) assert conjugate(cot(z)) == cot(zc) assert conjugate(sinh(z)) == sinh(zc) assert conjugate(cosh(z)) == cosh(zc) assert conjugate(tanh(z)) == tanh(zc) assert conjugate(coth(z)) == coth(zc) def test_abs1(): a = Symbol("a", real=True) b = Symbol("b", real=True) assert abs(a) == Abs(a) assert abs(-a) == abs(a) assert abs(a + I*b) == sqrt(a**2 + b**2) def test_abs2(): a = Symbol("a", real=False) b = Symbol("b", real=False) assert abs(a) != a assert abs(-a) != a assert abs(a + I*b) != sqrt(a**2 + b**2) def test_evalc(): x = Symbol("x", real=True) y = Symbol("y", real=True) z = Symbol("z") assert ((x + I*y)**2).expand(complex=True) == x**2 + 2*I*x*y - y**2 assert expand_complex(z**(2*I)) == (re((re(z) + I*im(z))**(2*I)) + I*im((re(z) + I*im(z))**(2*I))) assert expand_complex( z**(2*I), deep=False) == I*im(z**(2*I)) + re(z**(2*I)) assert exp(I*x) != cos(x) + I*sin(x) assert exp(I*x).expand(complex=True) == cos(x) + I*sin(x) assert exp(I*x + y).expand(complex=True) == exp(y)*cos(x) + I*sin(x)*exp(y) assert sin(I*x).expand(complex=True) == I * sinh(x) assert sin(x + I*y).expand(complex=True) == sin(x)*cosh(y) + \ I * sinh(y) * cos(x) assert cos(I*x).expand(complex=True) == cosh(x) assert cos(x + I*y).expand(complex=True) == cos(x)*cosh(y) - \ I * sinh(y) * sin(x) assert tan(I*x).expand(complex=True) == tanh(x) * I assert tan(x + I*y).expand(complex=True) == ( sin(2*x)/(cos(2*x) + cosh(2*y)) + I*sinh(2*y)/(cos(2*x) + cosh(2*y))) assert sinh(I*x).expand(complex=True) == I * sin(x) assert sinh(x + I*y).expand(complex=True) == sinh(x)*cos(y) + \ I * sin(y) * cosh(x) assert cosh(I*x).expand(complex=True) == cos(x) assert cosh(x + I*y).expand(complex=True) == cosh(x)*cos(y) + \ I * sin(y) * sinh(x) assert tanh(I*x).expand(complex=True) == tan(x) * I assert tanh(x + I*y).expand(complex=True) == ( (sinh(x)*cosh(x) + I*cos(y)*sin(y)) / (sinh(x)**2 + cos(y)**2)).expand() def test_pythoncomplex(): x = Symbol("x") assert 4j*x != 4*x*I assert 4j*x == 4.0*x*I assert 4.1j*x != 4*x*I def test_rootcomplex(): R = Rational assert ((+1 + I)**R(1, 2)).expand( complex=True) == 2**R(1, 4)*cos( pi/8) + 2**R(1, 4)*sin( pi/8)*I assert ((-1 - I)**R(1, 2)).expand( complex=True) == 2**R(1, 4)*cos(3*pi/8) - 2**R(1, 4)*sin(3*pi/8)*I assert (sqrt(-10)*I).as_real_imag() == (-sqrt(10), 0) def test_expand_inverse(): assert (1/(1 + I)).expand(complex=True) == (1 - I)/2 assert ((1 + 2*I)**(-2)).expand(complex=True) == (-3 - 4*I)/25 assert ((1 + I)**(-8)).expand(complex=True) == Rational(1, 16) def test_expand_complex(): assert ((2 + 3*I)**10).expand(complex=True) == -341525 - 145668*I # the following two tests are to ensure the SymPy uses an efficient # algorithm for calculating powers of complex numbers. They should execute # in something like 0.01s. assert ((2 + 3*I)**1000).expand(complex=True) == \ -81079464736246615951519029367296227340216902563389546989376269312984127074385455204551402940331021387412262494620336565547972162814110386834027871072723273110439771695255662375718498785908345629702081336606863762777939617745464755635193139022811989314881997210583159045854968310911252660312523907616129080027594310008539817935736331124833163907518549408018652090650537035647520296539436440394920287688149200763245475036722326561143851304795139005599209239350981457301460233967137708519975586996623552182807311159141501424576682074392689622074945519232029999 + \ 46938745946789557590804551905243206242164799136976022474337918748798900569942573265747576032611189047943842446167719177749107138603040963603119861476016947257034472364028585381714774667326478071264878108114128915685688115488744955550920239128462489496563930809677159214598114273887061533057125164518549173898349061972857446844052995037423459472376202251620778517659247970283904820245958198842631651569984310559418135975795868314764489884749573052997832686979294085577689571149679540256349988338406458116270429842222666345146926395233040564229555893248370000*I assert ((2 + 3*I/4)**1000).expand(complex=True) == \ Integer(1)*37079892761199059751745775382463070250205990218394308874593455293485167797989691280095867197640410033222367257278387021789651672598831503296531725827158233077451476545928116965316544607115843772405184272449644892857783761260737279675075819921259597776770965829089907990486964515784097181964312256560561065607846661496055417619388874421218472707497847700629822858068783288579581649321248495739224020822198695759609598745114438265083593711851665996586461937988748911532242908776883696631067311443171682974330675406616373422505939887984366289623091300746049101284856530270685577940283077888955692921951247230006346681086274961362500646889925803654263491848309446197554307105991537357310209426736453173441104334496173618419659521888945605315751089087820455852582920963561495787655250624781448951403353654348109893478206364632640344111022531861683064175862889459084900614967785405977231549003280842218501570429860550379522498497412180001/114813069527425452423283320117768198402231770208869520047764273682576626139237031385665948631650626991844596463898746277344711896086305533142593135616665318539129989145312280000688779148240044871428926990063486244781615463646388363947317026040466353970904996558162398808944629605623311649536164221970332681344168908984458505602379484807914058900934776500429002716706625830522008132236281291761267883317206598995396418127021779858404042159853183251540889433902091920554957783589672039160081957216630582755380425583726015528348786419432054508915275783882625175435528800822842770817965453762184851149029376 + \ I*421638390580169706973991429333213477486930178424989246669892530737775352519112934278994501272111385966211392610029433824534634841747911783746811994443436271013377059560245191441549885048056920190833693041257216263519792201852046825443439142932464031501882145407459174948712992271510309541474392303461939389368955986650538525895866713074543004916049550090364398070215427272240155060576252568700906004691224321432509053286859100920489253598392100207663785243368195857086816912514025693453058403158416856847185079684216151337200057494966741268925263085619240941610301610538225414050394612058339070756009433535451561664522479191267503989904464718368605684297071150902631208673621618217106272361061676184840810762902463998065947687814692402219182668782278472952758690939877465065070481351343206840649517150634973307937551168752642148704904383991876969408056379195860410677814566225456558230131911142229028179902418223009651437985670625/1793954211366022694113801876840128100034871409513586250746316776290259783425578615401030447369541046747571819748417910583511123376348523955353017744010395602173906080395504375010762174191250701116076984219741972574712741619474818186676828531882286780795390571221287481389759837587864244524002565968286448146002639202882164150037179450123657170327105882819203167448541028601906377066191895183769810676831353109303069033234715310287563158747705988305326397404720186258671215368588625611876280581509852855552819149745718992630449787803625851701801184123166018366180137512856918294030710215034138299203584 assert ((2 + 3*I)**-1000).expand(complex=True) == \ Integer(1)*-81079464736246615951519029367296227340216902563389546989376269312984127074385455204551402940331021387412262494620336565547972162814110386834027871072723273110439771695255662375718498785908345629702081336606863762777939617745464755635193139022811989314881997210583159045854968310911252660312523907616129080027594310008539817935736331124833163907518549408018652090650537035647520296539436440394920287688149200763245475036722326561143851304795139005599209239350981457301460233967137708519975586996623552182807311159141501424576682074392689622074945519232029999/8777125472973511649630750050295188683351430110097915876250894978429797369155961290321829625004920141758416719066805645579710744290541337680113772670040386863849283653078324415471816788604945889094925784900885812724984087843737442111926413818245854362613018058774368703971604921858023116665586358870612944209398056562604561248859926344335598822815885851096698226775053153403320782439987679978321289537645645163767251396759519805603090332694449553371530571613352311006350058217982509738362083094920649452123351717366337410243853659113315547584871655479914439219520157174729130746351059075207407866012574386726064196992865627149566238044625779078186624347183905913357718850537058578084932880569701242598663149911276357125355850792073635533676541250531086757377369962506979378337216411188347761901006460813413505861461267545723590468627854202034450569581626648934062198718362303420281555886394558137408159453103395918783625713213314350531051312551733021627153081075080140680608080529736975658786227362251632725009435866547613598753584705455955419696609282059191031962604169242974038517575645939316377801594539335940001 - Integer(1)*46938745946789557590804551905243206242164799136976022474337918748798900569942573265747576032611189047943842446167719177749107138603040963603119861476016947257034472364028585381714774667326478071264878108114128915685688115488744955550920239128462489496563930809677159214598114273887061533057125164518549173898349061972857446844052995037423459472376202251620778517659247970283904820245958198842631651569984310559418135975795868314764489884749573052997832686979294085577689571149679540256349988338406458116270429842222666345146926395233040564229555893248370000*I/8777125472973511649630750050295188683351430110097915876250894978429797369155961290321829625004920141758416719066805645579710744290541337680113772670040386863849283653078324415471816788604945889094925784900885812724984087843737442111926413818245854362613018058774368703971604921858023116665586358870612944209398056562604561248859926344335598822815885851096698226775053153403320782439987679978321289537645645163767251396759519805603090332694449553371530571613352311006350058217982509738362083094920649452123351717366337410243853659113315547584871655479914439219520157174729130746351059075207407866012574386726064196992865627149566238044625779078186624347183905913357718850537058578084932880569701242598663149911276357125355850792073635533676541250531086757377369962506979378337216411188347761901006460813413505861461267545723590468627854202034450569581626648934062198718362303420281555886394558137408159453103395918783625713213314350531051312551733021627153081075080140680608080529736975658786227362251632725009435866547613598753584705455955419696609282059191031962604169242974038517575645939316377801594539335940001 assert ((2 + 3*I/4)**-1000).expand(complex=True) == \ Integer(1)*4257256305661027385394552848555894604806501409793288342610746813288539790051927148781268212212078237301273165351052934681382567968787279534591114913777456610214738290619922068269909423637926549603264174216950025398244509039145410016404821694746262142525173737175066432954496592560621330313807235750500564940782099283410261748370262433487444897446779072067625787246390824312580440138770014838135245148574339248259670887549732495841810961088930810608893772914812838358159009303794863047635845688453859317690488124382253918725010358589723156019888846606295866740117645571396817375322724096486161308083462637370825829567578309445855481578518239186117686659177284332344643124760453112513611749309168470605289172320376911472635805822082051716625171429727162039621902266619821870482519063133136820085579315127038372190224739238686708451840610064871885616258831386810233957438253532027049148030157164346719204500373766157143311767338973363806106967439378604898250533766359989107510507493549529158818602327525235240510049484816090584478644771183158342479140194633579061295740839490629457435283873180259847394582069479062820225159699506175855369539201399183443253793905149785994830358114153241481884290274629611529758663543080724574566578220908907477622643689220814376054314972190402285121776593824615083669045183404206291739005554569305329760211752815718335731118664756831942466773261465213581616104242113894521054475516019456867271362053692785300826523328020796670205463390909136593859765912483565093461468865534470710132881677639651348709376/2103100954337624833663208713697737151593634525061637972297915388685604042449504336765884978184588688426595940401280828953096857809292320006227881797146858511436638446932833617514351442216409828605662238790280753075176269765767010004889778647709740770757817960711900340755635772183674511158570690702969774966791073165467918123298694584729211212414462628433370481195120564586361368504153395406845170075275051749019600057116719726628746724489572189061061036426955163696859127711110719502594479795200686212257570291758725259007379710596548777812659422174199194837355646482046783616494013289495563083118517507178847555801163089723056310287760875135196081975602765511153122381201303871673391366630940702817360340900568748719988954847590748960761446218262344767250783946365392689256634180417145926390656439421745644011831124277463643383712803287985472471755648426749842410972650924240795946699346613614779460399530274263580007672855851663196114585312432954432654691485867618908420370875753749297487803461900447407917655296784879220450937110470920633595689721819488638484547259978337741496090602390463594556401615298457456112485536498177883358587125449801777718900375736758266215245325999241624148841915093787519330809347240990363802360596034171167818310322276373120180985148650099673289383722502488957717848531612020897298448601714154586319660314294591620415272119454982220034319689607295960162971300417552364254983071768070124456169427638371140064235083443242844616326538396503937972586505546495649094344512270582463639152160238137952390380581401171977159154009407415523525096743009110916334144716516647041176989758534635251844947906038080852185583742296318878233394998111078843229681030277039104786225656992262073797524057992347971177720807155842376332851559276430280477639539393920006008737472164850104411971830120295750221200029811143140323763349636629725073624360001 - Integer(1)*3098214262599218784594285246258841485430681674561917573155883806818465520660668045042109232930382494608383663464454841313154390741655282039877410154577448327874989496074260116195788919037407420625081798124301494353693248757853222257918294662198297114746822817460991242508743651430439120439020484502408313310689912381846149597061657483084652685283853595100434135149479564507015504022249330340259111426799121454516345905101620532787348293877485702600390665276070250119465888154331218827342488849948540687659846652377277250614246402784754153678374932540789808703029043827352976139228402417432199779415751301480406673762521987999573209628597459357964214510139892316208670927074795773830798600837815329291912002136924506221066071242281626618211060464126372574400100990746934953437169840312584285942093951405864225230033279614235191326102697164613004299868695519642598882914862568516635347204441042798206770888274175592401790040170576311989738272102077819127459014286741435419468254146418098278519775722104890854275995510700298782146199325790002255362719776098816136732897323406228294203133323296591166026338391813696715894870956511298793595675308998014158717167429941371979636895553724830981754579086664608880698350866487717403917070872269853194118364230971216854931998642990452908852258008095741042117326241406479532880476938937997238098399302185675832474590293188864060116934035867037219176916416481757918864533515526389079998129329045569609325290897577497835388451456680707076072624629697883854217331728051953671643278797380171857920000*I/2103100954337624833663208713697737151593634525061637972297915388685604042449504336765884978184588688426595940401280828953096857809292320006227881797146858511436638446932833617514351442216409828605662238790280753075176269765767010004889778647709740770757817960711900340755635772183674511158570690702969774966791073165467918123298694584729211212414462628433370481195120564586361368504153395406845170075275051749019600057116719726628746724489572189061061036426955163696859127711110719502594479795200686212257570291758725259007379710596548777812659422174199194837355646482046783616494013289495563083118517507178847555801163089723056310287760875135196081975602765511153122381201303871673391366630940702817360340900568748719988954847590748960761446218262344767250783946365392689256634180417145926390656439421745644011831124277463643383712803287985472471755648426749842410972650924240795946699346613614779460399530274263580007672855851663196114585312432954432654691485867618908420370875753749297487803461900447407917655296784879220450937110470920633595689721819488638484547259978337741496090602390463594556401615298457456112485536498177883358587125449801777718900375736758266215245325999241624148841915093787519330809347240990363802360596034171167818310322276373120180985148650099673289383722502488957717848531612020897298448601714154586319660314294591620415272119454982220034319689607295960162971300417552364254983071768070124456169427638371140064235083443242844616326538396503937972586505546495649094344512270582463639152160238137952390380581401171977159154009407415523525096743009110916334144716516647041176989758534635251844947906038080852185583742296318878233394998111078843229681030277039104786225656992262073797524057992347971177720807155842376332851559276430280477639539393920006008737472164850104411971830120295750221200029811143140323763349636629725073624360001 a = Symbol('a', real=True) b = Symbol('b', real=True) assert exp(a*(2 + I*b)).expand(complex=True) == \ I*exp(2*a)*sin(a*b) + exp(2*a)*cos(a*b) def test_expand(): f = (16 - 2*sqrt(29))**2 assert f.expand() == 372 - 64*sqrt(29) f = (Integer(1)/2 + I/2)**10 assert f.expand() == I/32 f = (Integer(1)/2 + I)**10 assert f.expand() == Integer(237)/1024 - 779*I/256 def test_re_im1652(): x = Symbol('x') assert re(x) == re(conjugate(x)) assert im(x) == - im(conjugate(x)) assert im(x)*re(conjugate(x)) + im(conjugate(x)) * re(x) == 0 def test_issue_5084(): x = Symbol('x') assert ((x + x*I)/(1 + I)).as_real_imag() == (re((x + I*x)/(1 + I) ), im((x + I*x)/(1 + I))) def test_issue_5236(): assert (cos(1 + I)**3).as_real_imag() == (-3*sin(1)**2*sinh(1)**2*cos(1)*cosh(1) + cos(1)**3*cosh(1)**3, -3*cos(1)**2*cosh(1)**2*sin(1)*sinh(1) + sin(1)**3*sinh(1)**3) def test_real_imag(): x, y, z = symbols('x, y, z') X, Y, Z = symbols('X, Y, Z', commutative=False) a = Symbol('a', real=True) assert (2*a*x).as_real_imag() == (2*a*re(x), 2*a*im(x)) # issue 5395: assert (x*x.conjugate()).as_real_imag() == (Abs(x)**2, 0) assert im(x*x.conjugate()) == 0 assert im(x*y.conjugate()*z*y) == im(x*z)*Abs(y)**2 assert im(x*y.conjugate()*x*y) == im(x**2)*Abs(y)**2 assert im(Z*y.conjugate()*X*y) == im(Z*X)*Abs(y)**2 assert im(X*X.conjugate()) == im(X*X.conjugate(), evaluate=False) assert (sin(x)*sin(x).conjugate()).as_real_imag() == \ (Abs(sin(x))**2, 0) # issue 6573: assert (x**2).as_real_imag() == (re(x)**2 - im(x)**2, 2*re(x)*im(x)) # issue 6428: r = Symbol('r', real=True) i = Symbol('i', imaginary=True) assert (i*r*x).as_real_imag() == (I*i*r*im(x), -I*i*r*re(x)) assert (i*r*x*(y + 2)).as_real_imag() == ( I*i*r*(re(y) + 2)*im(x) + I*i*r*re(x)*im(y), -I*i*r*(re(y) + 2)*re(x) + I*i*r*im(x)*im(y)) # issue 7106: assert ((1 + I)/(1 - I)).as_real_imag() == (0, 1) assert ((1 + 2*I)*(1 + 3*I)).as_real_imag() == (-5, 5) def test_pow_issue_1724(): e = ((S.NegativeOne)**(S.One/3)) assert e.conjugate().n() == e.n().conjugate() e = S('-2/3 - (-29/54 + sqrt(93)/18)**(1/3) - 1/(9*(-29/54 + sqrt(93)/18)**(1/3))') assert e.conjugate().n() == e.n().conjugate() e = 2**I assert e.conjugate().n() == e.n().conjugate() def test_issue_5429(): assert sqrt(I).conjugate() != sqrt(I) def test_issue_4124(): from sympy import oo assert expand_complex(I*oo) == oo*I def test_issue_11518(): x = Symbol("x", real=True) y = Symbol("y", real=True) r = sqrt(x**2 + y**2) assert conjugate(r) == r s = abs(x + I * y) assert conjugate(s) == r sympy-sympy-1.9/sympy/core/tests/test_constructor_postprocessor.py000066400000000000000000000045051412543434000262050ustar00rootroot00000000000000from sympy import Symbol, Mul, symbols, Basic from sympy.testing.pytest import XFAIL class SymbolInMulOnce(Symbol): # Test class for a symbol that can only appear once in a `Mul` expression. pass Basic._constructor_postprocessor_mapping[SymbolInMulOnce] = { "Mul": [lambda x: x], "Pow": [lambda x: x.base if isinstance(x.base, SymbolInMulOnce) else x], "Add": [lambda x: x], } def _postprocess_SymbolRemovesOtherSymbols(expr): args = tuple(i for i in expr.args if not isinstance(i, Symbol) or isinstance(i, SymbolRemovesOtherSymbols)) if args == expr.args: return expr return Mul.fromiter(args) class SymbolRemovesOtherSymbols(Symbol): # Test class for a symbol that removes other symbols in `Mul`. pass Basic._constructor_postprocessor_mapping[SymbolRemovesOtherSymbols] = { "Mul": [_postprocess_SymbolRemovesOtherSymbols], } class SubclassSymbolInMulOnce(SymbolInMulOnce): pass class SubclassSymbolRemovesOtherSymbols(SymbolRemovesOtherSymbols): pass def test_constructor_postprocessors1(): x = SymbolInMulOnce("x") y = SymbolInMulOnce("y") assert isinstance(3*x, Mul) assert (3*x).args == (3, x) assert x*x == x assert 3*x*x == 3*x assert 2*x*x + x == 3*x assert x**3*y*y == x*y assert x**5 + y*x**3 == x + x*y w = SymbolRemovesOtherSymbols("w") assert x*w == w assert (3*w).args == (3, w) assert set((w + x).args) == {x, w} def test_constructor_postprocessors2(): x = SubclassSymbolInMulOnce("x") y = SubclassSymbolInMulOnce("y") assert isinstance(3*x, Mul) assert (3*x).args == (3, x) assert x*x == x assert 3*x*x == 3*x assert 2*x*x + x == 3*x assert x**3*y*y == x*y assert x**5 + y*x**3 == x + x*y w = SubclassSymbolRemovesOtherSymbols("w") assert x*w == w assert (3*w).args == (3, w) assert set((w + x).args) == {x, w} @XFAIL def test_subexpression_postprocessors(): # The postprocessors used to work with subexpressions, but the # functionality was removed. See #15948. a = symbols("a") x = SymbolInMulOnce("x") w = SymbolRemovesOtherSymbols("w") assert 3*a*w**2 == 3*w**2 assert 3*a*x**3*w**2 == 3*w**2 x = SubclassSymbolInMulOnce("x") w = SubclassSymbolRemovesOtherSymbols("w") assert 3*a*w**2 == 3*w**2 assert 3*a*x**3*w**2 == 3*w**2 sympy-sympy-1.9/sympy/core/tests/test_containers.py000066400000000000000000000153231412543434000227600ustar00rootroot00000000000000from collections import defaultdict from sympy import Matrix, Tuple, symbols, sympify, Basic, Dict, S, FiniteSet, Integer from sympy.core.compatibility import is_sequence, iterable from sympy.core.containers import tuple_wrapper from sympy.core.expr import unchanged from sympy.core.function import Function, Lambda from sympy.core.relational import Eq from sympy.testing.pytest import raises from sympy.abc import x, y def test_Tuple(): t = (1, 2, 3, 4) st = Tuple(*t) assert set(sympify(t)) == set(st) assert len(t) == len(st) assert set(sympify(t[:2])) == set(st[:2]) assert isinstance(st[:], Tuple) assert st == Tuple(1, 2, 3, 4) assert st.func(*st.args) == st p, q, r, s = symbols('p q r s') t2 = (p, q, r, s) st2 = Tuple(*t2) assert st2.atoms() == set(t2) assert st == st2.subs({p: 1, q: 2, r: 3, s: 4}) # issue 5505 assert all(isinstance(arg, Basic) for arg in st.args) assert Tuple(p, 1).subs(p, 0) == Tuple(0, 1) assert Tuple(p, Tuple(p, 1)).subs(p, 0) == Tuple(0, Tuple(0, 1)) assert Tuple(t2) == Tuple(Tuple(*t2)) assert Tuple.fromiter(t2) == Tuple(*t2) assert Tuple.fromiter(x for x in range(4)) == Tuple(0, 1, 2, 3) assert st2.fromiter(st2.args) == st2 def test_Tuple_contains(): t1, t2 = Tuple(1), Tuple(2) assert t1 in Tuple(1, 2, 3, t1, Tuple(t2)) assert t2 not in Tuple(1, 2, 3, t1, Tuple(t2)) def test_Tuple_concatenation(): assert Tuple(1, 2) + Tuple(3, 4) == Tuple(1, 2, 3, 4) assert (1, 2) + Tuple(3, 4) == Tuple(1, 2, 3, 4) assert Tuple(1, 2) + (3, 4) == Tuple(1, 2, 3, 4) raises(TypeError, lambda: Tuple(1, 2) + 3) raises(TypeError, lambda: 1 + Tuple(2, 3)) #the Tuple case in __radd__ is only reached when a subclass is involved class Tuple2(Tuple): def __radd__(self, other): return Tuple.__radd__(self, other + other) assert Tuple(1, 2) + Tuple2(3, 4) == Tuple(1, 2, 1, 2, 3, 4) assert Tuple2(1, 2) + Tuple(3, 4) == Tuple(1, 2, 3, 4) def test_Tuple_equality(): assert not isinstance(Tuple(1, 2), tuple) assert (Tuple(1, 2) == (1, 2)) is True assert (Tuple(1, 2) != (1, 2)) is False assert (Tuple(1, 2) == (1, 3)) is False assert (Tuple(1, 2) != (1, 3)) is True assert (Tuple(1, 2) == Tuple(1, 2)) is True assert (Tuple(1, 2) != Tuple(1, 2)) is False assert (Tuple(1, 2) == Tuple(1, 3)) is False assert (Tuple(1, 2) != Tuple(1, 3)) is True def test_Tuple_Eq(): assert Eq(Tuple(), Tuple()) is S.true assert Eq(Tuple(1), 1) is S.false assert Eq(Tuple(1, 2), Tuple(1)) is S.false assert Eq(Tuple(1), Tuple(1)) is S.true assert Eq(Tuple(1, 2), Tuple(1, 3)) is S.false assert Eq(Tuple(1, 2), Tuple(1, 2)) is S.true assert unchanged(Eq, Tuple(1, x), Tuple(1, 2)) assert Eq(Tuple(1, x), Tuple(1, 2)).subs(x, 2) is S.true assert unchanged(Eq, Tuple(1, 2), x) f = Function('f') assert unchanged(Eq, Tuple(1), f(x)) assert Eq(Tuple(1), f(x)).subs(x, 1).subs(f, Lambda(y, (y,))) is S.true def test_Tuple_comparision(): assert (Tuple(1, 3) >= Tuple(-10, 30)) is S.true assert (Tuple(1, 3) <= Tuple(-10, 30)) is S.false assert (Tuple(1, 3) >= Tuple(1, 3)) is S.true assert (Tuple(1, 3) <= Tuple(1, 3)) is S.true def test_Tuple_tuple_count(): assert Tuple(0, 1, 2, 3).tuple_count(4) == 0 assert Tuple(0, 4, 1, 2, 3).tuple_count(4) == 1 assert Tuple(0, 4, 1, 4, 2, 3).tuple_count(4) == 2 assert Tuple(0, 4, 1, 4, 2, 4, 3).tuple_count(4) == 3 def test_Tuple_index(): assert Tuple(4, 0, 1, 2, 3).index(4) == 0 assert Tuple(0, 4, 1, 2, 3).index(4) == 1 assert Tuple(0, 1, 4, 2, 3).index(4) == 2 assert Tuple(0, 1, 2, 4, 3).index(4) == 3 assert Tuple(0, 1, 2, 3, 4).index(4) == 4 raises(ValueError, lambda: Tuple(0, 1, 2, 3).index(4)) raises(ValueError, lambda: Tuple(4, 0, 1, 2, 3).index(4, 1)) raises(ValueError, lambda: Tuple(0, 1, 2, 3, 4).index(4, 1, 4)) def test_Tuple_mul(): assert Tuple(1, 2, 3)*2 == Tuple(1, 2, 3, 1, 2, 3) assert 2*Tuple(1, 2, 3) == Tuple(1, 2, 3, 1, 2, 3) assert Tuple(1, 2, 3)*Integer(2) == Tuple(1, 2, 3, 1, 2, 3) assert Integer(2)*Tuple(1, 2, 3) == Tuple(1, 2, 3, 1, 2, 3) raises(TypeError, lambda: Tuple(1, 2, 3)*S.Half) raises(TypeError, lambda: S.Half*Tuple(1, 2, 3)) def test_tuple_wrapper(): @tuple_wrapper def wrap_tuples_and_return(*t): return t p = symbols('p') assert wrap_tuples_and_return(p, 1) == (p, 1) assert wrap_tuples_and_return((p, 1)) == (Tuple(p, 1),) assert wrap_tuples_and_return(1, (p, 2), 3) == (1, Tuple(p, 2), 3) def test_iterable_is_sequence(): ordered = [list(), tuple(), Tuple(), Matrix([[]])] unordered = [set()] not_sympy_iterable = [{}, '', ''] assert all(is_sequence(i) for i in ordered) assert all(not is_sequence(i) for i in unordered) assert all(iterable(i) for i in ordered + unordered) assert all(not iterable(i) for i in not_sympy_iterable) assert all(iterable(i, exclude=None) for i in not_sympy_iterable) def test_Dict(): x, y, z = symbols('x y z') d = Dict({x: 1, y: 2, z: 3}) assert d[x] == 1 assert d[y] == 2 raises(KeyError, lambda: d[2]) raises(KeyError, lambda: d['2']) assert len(d) == 3 assert set(d.keys()) == {x, y, z} assert set(d.values()) == {S.One, S(2), S(3)} assert d.get(5, 'default') == 'default' assert d.get('5', 'default') == 'default' assert x in d and z in d and not 5 in d and not '5' in d assert d.has(x) and d.has(1) # SymPy Basic .has method # Test input types # input - a python dict # input - items as args - SymPy style assert (Dict({x: 1, y: 2, z: 3}) == Dict((x, 1), (y, 2), (z, 3))) raises(TypeError, lambda: Dict(((x, 1), (y, 2), (z, 3)))) with raises(NotImplementedError): d[5] = 6 # assert immutability assert set( d.items()) == {Tuple(x, S.One), Tuple(y, S(2)), Tuple(z, S(3))} assert set(d) == {x, y, z} assert str(d) == '{x: 1, y: 2, z: 3}' assert d.__repr__() == '{x: 1, y: 2, z: 3}' # Test creating a Dict from a Dict. d = Dict({x: 1, y: 2, z: 3}) assert d == Dict(d) # Test for supporting defaultdict d = defaultdict(int) assert d[x] == 0 assert d[y] == 0 assert d[z] == 0 assert Dict(d) d = Dict(d) assert len(d) == 3 assert set(d.keys()) == {x, y, z} assert set(d.values()) == {S.Zero, S.Zero, S.Zero} def test_issue_5788(): args = [(1, 2), (2, 1)] for o in [Dict, Tuple, FiniteSet]: # __eq__ and arg handling if o != Tuple: assert o(*args) == o(*reversed(args)) pair = [o(*args), o(*reversed(args))] assert sorted(pair) == sorted(reversed(pair)) assert set(o(*args)) # doesn't fail sympy-sympy-1.9/sympy/core/tests/test_count_ops.py000066400000000000000000000116311412543434000226220ustar00rootroot00000000000000from sympy import symbols, sin, exp, cos, Derivative, Integral, Basic, \ count_ops, S, And, I, pi, Eq, Or, Not, Xor, Nand, Nor, Implies, \ Equivalent, MatrixSymbol, Symbol, ITE, Rel, Rational, Sum from sympy.core.containers import Tuple x, y, z = symbols('x,y,z') a, b, c = symbols('a,b,c') def test_count_ops_non_visual(): def count(val): return count_ops(val, visual=False) assert count(x) == 0 assert count(x) is not S.Zero assert count(x + y) == 1 assert count(x + y) is not S.One assert count(x + y*x + 2*y) == 4 assert count({x + y: x}) == 1 assert count({x + y: S(2) + x}) is not S.One assert count(x < y) == 1 assert count(Or(x,y)) == 1 assert count(And(x,y)) == 1 assert count(Not(x)) == 1 assert count(Nor(x,y)) == 2 assert count(Nand(x,y)) == 2 assert count(Xor(x,y)) == 1 assert count(Implies(x,y)) == 1 assert count(Equivalent(x,y)) == 1 assert count(ITE(x,y,z)) == 1 assert count(ITE(True,x,y)) == 0 def test_count_ops_visual(): ADD, MUL, POW, SIN, COS, EXP, AND, D, G, M = symbols( 'Add Mul Pow sin cos exp And Derivative Integral Sum'.upper()) DIV, SUB, NEG = symbols('DIV SUB NEG') LT, LE, GT, GE, EQ, NE = symbols('LT LE GT GE EQ NE') NOT, OR, AND, XOR, IMPLIES, EQUIVALENT, _ITE, BASIC, TUPLE = symbols( 'Not Or And Xor Implies Equivalent ITE Basic Tuple'.upper()) def count(val): return count_ops(val, visual=True) assert count(7) is S.Zero assert count(S(7)) is S.Zero assert count(-1) == NEG assert count(-2) == NEG assert count(S(2)/3) == DIV assert count(Rational(2, 3)) == DIV assert count(pi/3) == DIV assert count(-pi/3) == DIV + NEG assert count(I - 1) == SUB assert count(1 - I) == SUB assert count(1 - 2*I) == SUB + MUL assert count(x) is S.Zero assert count(-x) == NEG assert count(-2*x/3) == NEG + DIV + MUL assert count(Rational(-2, 3)*x) == NEG + DIV + MUL assert count(1/x) == DIV assert count(1/(x*y)) == DIV + MUL assert count(-1/x) == NEG + DIV assert count(-2/x) == NEG + DIV assert count(x/y) == DIV assert count(-x/y) == NEG + DIV assert count(x**2) == POW assert count(-x**2) == POW + NEG assert count(-2*x**2) == POW + MUL + NEG assert count(x + pi/3) == ADD + DIV assert count(x + S.One/3) == ADD + DIV assert count(x + Rational(1, 3)) == ADD + DIV assert count(x + y) == ADD assert count(x - y) == SUB assert count(y - x) == SUB assert count(-1/(x - y)) == DIV + NEG + SUB assert count(-1/(y - x)) == DIV + NEG + SUB assert count(1 + x**y) == ADD + POW assert count(1 + x + y) == 2*ADD assert count(1 + x + y + z) == 3*ADD assert count(1 + x**y + 2*x*y + y**2) == 3*ADD + 2*POW + 2*MUL assert count(2*z + y + x + 1) == 3*ADD + MUL assert count(2*z + y**17 + x + 1) == 3*ADD + MUL + POW assert count(2*z + y**17 + x + sin(x)) == 3*ADD + POW + MUL + SIN assert count(2*z + y**17 + x + sin(x**2)) == 3*ADD + MUL + 2*POW + SIN assert count(2*z + y**17 + x + sin( x**2) + exp(cos(x))) == 4*ADD + MUL + 2*POW + EXP + COS + SIN assert count(Derivative(x, x)) == D assert count(Integral(x, x) + 2*x/(1 + x)) == G + DIV + MUL + 2*ADD assert count(Sum(x, (x, 1, x + 1)) + 2*x/(1 + x)) == M + DIV + MUL + 3*ADD assert count(Basic()) is S.Zero assert count({x + 1: sin(x)}) == ADD + SIN assert count([x + 1, sin(x) + y, None]) == ADD + SIN + ADD assert count({x + 1: sin(x), y: cos(x) + 1}) == SIN + COS + 2*ADD assert count({}) is S.Zero assert count([x + 1, sin(x)*y, None]) == SIN + ADD + MUL assert count([]) is S.Zero assert count(Basic()) == 0 assert count(Basic(Basic(),Basic(x,x+y))) == ADD + 2*BASIC assert count(Basic(x, x + y)) == ADD + BASIC assert [count(Rel(x, y, op)) for op in '< <= > >= == <> !='.split() ] == [LT, LE, GT, GE, EQ, NE, NE] assert count(Or(x, y)) == OR assert count(And(x, y)) == AND assert count(Or(x, Or(y, And(z, a)))) == AND + OR assert count(Nor(x, y)) == NOT + OR assert count(Nand(x, y)) == NOT + AND assert count(Xor(x, y)) == XOR assert count(Implies(x, y)) == IMPLIES assert count(Equivalent(x, y)) == EQUIVALENT assert count(ITE(x, y, z)) == _ITE assert count([Or(x, y), And(x, y), Basic(x + y)] ) == ADD + AND + BASIC + OR assert count(Basic(Tuple(x))) == BASIC + TUPLE #It checks that TUPLE is counted as an operation. assert count(Eq(x + y, S(2))) == ADD + EQ def test_issue_9324(): def count(val): return count_ops(val, visual=False) M = MatrixSymbol('M', 10, 10) assert count(M[0, 0]) == 0 assert count(2 * M[0, 0] + M[5, 7]) == 2 P = MatrixSymbol('P', 3, 3) Q = MatrixSymbol('Q', 3, 3) assert count(P + Q) == 1 m = Symbol('m', integer=True) n = Symbol('n', integer=True) M = MatrixSymbol('M', m + n, m * m) assert count(M[0, 1]) == 2 sympy-sympy-1.9/sympy/core/tests/test_diff.py000066400000000000000000000124551412543434000215260ustar00rootroot00000000000000from sympy.concrete.summations import Sum from sympy.core.expr import Expr from sympy.core.function import (Derivative, Function, diff, Subs) from sympy.core.numbers import (I, Rational, pi) from sympy.core.relational import Eq from sympy.core.singleton import S from sympy.core.symbol import Symbol from sympy.functions.combinatorial.factorials import factorial from sympy.functions.elementary.complexes import (im, re) from sympy.functions.elementary.exponential import (exp, log) from sympy.functions.elementary.miscellaneous import Max from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import (cos, cot, sin, tan) from sympy.tensor.array.ndim_array import NDimArray from sympy.testing.pytest import raises from sympy.abc import a, b, c, x, y, z def test_diff(): assert Rational(1, 3).diff(x) is S.Zero assert I.diff(x) is S.Zero assert pi.diff(x) is S.Zero assert x.diff(x, 0) == x assert (x**2).diff(x, 2, x) == 0 assert (x**2).diff((x, 2), x) == 0 assert (x**2).diff((x, 1), x) == 2 assert (x**2).diff((x, 1), (x, 1)) == 2 assert (x**2).diff((x, 2)) == 2 assert (x**2).diff(x, y, 0) == 2*x assert (x**2).diff(x, (y, 0)) == 2*x assert (x**2).diff(x, y) == 0 raises(ValueError, lambda: x.diff(1, x)) p = Rational(5) e = a*b + b**p assert e.diff(a) == b assert e.diff(b) == a + 5*b**4 assert e.diff(b).diff(a) == Rational(1) e = a*(b + c) assert e.diff(a) == b + c assert e.diff(b) == a assert e.diff(b).diff(a) == Rational(1) e = c**p assert e.diff(c, 6) == Rational(0) assert e.diff(c, 5) == Rational(120) e = c**Rational(2) assert e.diff(c) == 2*c e = a*b*c assert e.diff(c) == a*b def test_diff2(): n3 = Rational(3) n2 = Rational(2) n6 = Rational(6) e = n3*(-n2 + x**n2)*cos(x) + x*(-n6 + x**n2)*sin(x) assert e == 3*(-2 + x**2)*cos(x) + x*(-6 + x**2)*sin(x) assert e.diff(x).expand() == x**3*cos(x) e = (x + 1)**3 assert e.diff(x) == 3*(x + 1)**2 e = x*(x + 1)**3 assert e.diff(x) == (x + 1)**3 + 3*x*(x + 1)**2 e = 2*exp(x*x)*x assert e.diff(x) == 2*exp(x**2) + 4*x**2*exp(x**2) def test_diff3(): p = Rational(5) e = a*b + sin(b**p) assert e == a*b + sin(b**5) assert e.diff(a) == b assert e.diff(b) == a + 5*b**4*cos(b**5) e = tan(c) assert e == tan(c) assert e.diff(c) in [cos(c)**(-2), 1 + sin(c)**2/cos(c)**2, 1 + tan(c)**2] e = c*log(c) - c assert e == -c + c*log(c) assert e.diff(c) == log(c) e = log(sin(c)) assert e == log(sin(c)) assert e.diff(c) in [sin(c)**(-1)*cos(c), cot(c)] e = (Rational(2)**a/log(Rational(2))) assert e == 2**a*log(Rational(2))**(-1) assert e.diff(a) == 2**a def test_diff_no_eval_derivative(): class My(Expr): def __new__(cls, x): return Expr.__new__(cls, x) # My doesn't have its own _eval_derivative method assert My(x).diff(x).func is Derivative assert My(x).diff(x, 3).func is Derivative assert re(x).diff(x, 2) == Derivative(re(x), (x, 2)) # issue 15518 assert diff(NDimArray([re(x), im(x)]), (x, 2)) == NDimArray( [Derivative(re(x), (x, 2)), Derivative(im(x), (x, 2))]) # it doesn't have y so it shouldn't need a method for this case assert My(x).diff(y) == 0 def test_speed(): # this should return in 0.0s. If it takes forever, it's wrong. assert x.diff(x, 10**8) == 0 def test_deriv_noncommutative(): A = Symbol("A", commutative=False) f = Function("f") assert A*f(x)*A == f(x)*A**2 assert A*f(x).diff(x)*A == f(x).diff(x) * A**2 def test_diff_nth_derivative(): f = Function("f") n = Symbol("n", integer=True) expr = diff(sin(x), (x, n)) expr2 = diff(f(x), (x, 2)) expr3 = diff(f(x), (x, n)) assert expr.subs(sin(x), cos(-x)) == Derivative(cos(-x), (x, n)) assert expr.subs(n, 1).doit() == cos(x) assert expr.subs(n, 2).doit() == -sin(x) assert expr2.subs(Derivative(f(x), x), y) == Derivative(y, x) # Currently not supported (cannot determine if `n > 1`): #assert expr3.subs(Derivative(f(x), x), y) == Derivative(y, (x, n-1)) assert expr3 == Derivative(f(x), (x, n)) assert diff(x, (x, n)) == Piecewise((x, Eq(n, 0)), (1, Eq(n, 1)), (0, True)) assert diff(2*x, (x, n)).dummy_eq( Sum(Piecewise((2*x*factorial(n)/(factorial(y)*factorial(-y + n)), Eq(y, 0) & Eq(Max(0, -y + n), 0)), (2*factorial(n)/(factorial(y)*factorial(-y + n)), Eq(y, 0) & Eq(Max(0, -y + n), 1)), (0, True)), (y, 0, n))) # TODO: assert diff(x**2, (x, n)) == x**(2-n)*ff(2, n) exprm = x*sin(x) mul_diff = diff(exprm, (x, n)) assert isinstance(mul_diff, Sum) for i in range(5): assert mul_diff.subs(n, i).doit() == exprm.diff((x, i)).expand() exprm2 = 2*y*x*sin(x)*cos(x)*log(x)*exp(x) dex = exprm2.diff((x, n)) assert isinstance(dex, Sum) for i in range(7): assert dex.subs(n, i).doit().expand() == \ exprm2.diff((x, i)).expand() assert (cos(x)*sin(y)).diff([[x, y, z]]) == NDimArray([ -sin(x)*sin(y), cos(x)*cos(y), 0]) def test_issue_16160(): assert Derivative(x**3, (x, x)).subs(x, 2) == Subs( Derivative(x**3, (x, 2)), x, 2) assert Derivative(1 + x**3, (x, x)).subs(x, 0 ) == Derivative(1 + y**3, (y, 0)).subs(y, 0) sympy-sympy-1.9/sympy/core/tests/test_equal.py000066400000000000000000000030601412543434000217150ustar00rootroot00000000000000from sympy import Symbol, Dummy, Rational, exp def test_equal(): b = Symbol("b") a = Symbol("a") e1 = a + b e2 = 2*a*b e3 = a**3*b**2 e4 = a*b + b*a assert not e1 == e2 assert not e1 == e2 assert e1 != e2 assert e2 == e4 assert e2 != e3 assert not e2 == e3 x = Symbol("x") e1 = exp(x + 1/x) y = Symbol("x") e2 = exp(y + 1/y) assert e1 == e2 assert not e1 != e2 y = Symbol("y") e2 = exp(y + 1/y) assert not e1 == e2 assert e1 != e2 e5 = Rational(3) + 2*x - x - x assert e5 == 3 assert 3 == e5 assert e5 != 4 assert 4 != e5 assert e5 != 3 + x assert 3 + x != e5 def test_expevalbug(): x = Symbol("x") e1 = exp(1*x) e3 = exp(x) assert e1 == e3 def test_cmp_bug1(): class T: pass t = T() x = Symbol("x") assert not (x == t) assert (x != t) def test_cmp_bug2(): class T: pass t = T() assert not (Symbol == t) assert (Symbol != t) def test_cmp_issue_4357(): """ Check that Basic subclasses can be compared with sympifiable objects. https://github.com/sympy/sympy/issues/4357 """ assert not (Symbol == 1) assert (Symbol != 1) assert not (Symbol == 'x') assert (Symbol != 'x') def test_dummy_eq(): x = Symbol('x') y = Symbol('y') u = Dummy('u') assert (u**2 + 1).dummy_eq(x**2 + 1) is True assert ((u**2 + 1) == (x**2 + 1)) is False assert (u**2 + y).dummy_eq(x**2 + y, x) is True assert (u**2 + y).dummy_eq(x**2 + y, y) is False sympy-sympy-1.9/sympy/core/tests/test_eval.py000066400000000000000000000040671412543434000215450ustar00rootroot00000000000000from sympy import Symbol, Function, exp, sqrt, Rational, I, cos, tan, S from sympy.testing.pytest import XFAIL def test_add_eval(): a = Symbol("a") b = Symbol("b") c = Rational(1) p = Rational(5) assert a*b + c + p == a*b + 6 assert c + a + p == a + 6 assert c + a - p == a + (-4) assert a + a == 2*a assert a + p + a == 2*a + 5 assert c + p == Rational(6) assert b + a - b == a def test_addmul_eval(): a = Symbol("a") b = Symbol("b") c = Rational(1) p = Rational(5) assert c + a + b*c + a - p == 2*a + b + (-4) assert a*2 + p + a == a*2 + 5 + a assert a*2 + p + a == 3*a + 5 assert a*2 + a == 3*a def test_pow_eval(): # XXX Pow does not fully support conversion of negative numbers # to their complex equivalent assert sqrt(-1) == I assert sqrt(-4) == 2*I assert sqrt( 4) == 2 assert (8)**Rational(1, 3) == 2 assert (-8)**Rational(1, 3) == 2*((-1)**Rational(1, 3)) assert sqrt(-2) == I*sqrt(2) assert (-1)**Rational(1, 3) != I assert (-10)**Rational(1, 3) != I*((10)**Rational(1, 3)) assert (-2)**Rational(1, 4) != (2)**Rational(1, 4) assert 64**Rational(1, 3) == 4 assert 64**Rational(2, 3) == 16 assert 24/sqrt(64) == 3 assert (-27)**Rational(1, 3) == 3*(-1)**Rational(1, 3) assert (cos(2) / tan(2))**2 == (cos(2) / tan(2))**2 @XFAIL def test_pow_eval_X1(): assert (-1)**Rational(1, 3) == S.Half + S.Half*I*sqrt(3) def test_mulpow_eval(): x = Symbol('x') assert sqrt(50)/(sqrt(2)*x) == 5/x assert sqrt(27)/sqrt(3) == 3 def test_evalpow_bug(): x = Symbol("x") assert 1/(1/x) == x assert 1/(-1/x) == -x def test_symbol_expand(): x = Symbol('x') y = Symbol('y') f = x**4*y**4 assert f == x**4*y**4 assert f == f.expand() g = (x*y)**4 assert g == f assert g.expand() == f assert g.expand() == g.expand().expand() def test_function(): f, l = map(Function, 'fl') x = Symbol('x') assert exp(l(x))*l(x)/exp(l(x)) == l(x) assert exp(f(x))*f(x)/exp(f(x)) == f(x) sympy-sympy-1.9/sympy/core/tests/test_evalf.py000066400000000000000000000544311412543434000217130ustar00rootroot00000000000000from sympy import (Abs, Add, atan, ceiling, cos, E, Eq, exp, factor, factorial, fibonacci, floor, Function, GoldenRatio, I, Integral, integrate, log, Mul, N, oo, pi, Pow, product, Product, tan, Rational, S, Sum, simplify, sin, sqrt, sstr, sympify, Symbol, Max, nfloat, cosh, acosh, acos) from sympy.core.numbers import comp from sympy.core.evalf import (complex_accuracy, PrecisionExhausted, scaled_zero, get_integer_part, as_mpmath, evalf) from mpmath import inf, ninf from mpmath.libmp.libmpf import from_float from sympy.core.expr import unchanged from sympy.testing.pytest import raises, XFAIL from sympy.abc import n, x, y def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) def test_evalf_helpers(): assert complex_accuracy((from_float(2.0), None, 35, None)) == 35 assert complex_accuracy((from_float(2.0), from_float(10.0), 35, 100)) == 37 assert complex_accuracy( (from_float(2.0), from_float(1000.0), 35, 100)) == 43 assert complex_accuracy((from_float(2.0), from_float(10.0), 100, 35)) == 35 assert complex_accuracy( (from_float(2.0), from_float(1000.0), 100, 35)) == 35 def test_evalf_basic(): assert NS('pi', 15) == '3.14159265358979' assert NS('2/3', 10) == '0.6666666667' assert NS('355/113-pi', 6) == '2.66764e-7' assert NS('16*atan(1/5)-4*atan(1/239)', 15) == '3.14159265358979' def test_cancellation(): assert NS(Add(pi, Rational(1, 10**1000), -pi, evaluate=False), 15, maxn=1200) == '1.00000000000000e-1000' def test_evalf_powers(): assert NS('pi**(10**20)', 10) == '1.339148777e+49714987269413385435' assert NS(pi**(10**100), 10) == ('4.946362032e+4971498726941338543512682882' '9089887365167832438044244613405349992494711208' '95526746555473864642912223') assert NS('2**(1/10**50)', 15) == '1.00000000000000' assert NS('2**(1/10**50)-1', 15) == '6.93147180559945e-51' # Evaluation of Rump's ill-conditioned polynomial def test_evalf_rump(): a = 1335*y**6/4 + x**2*(11*x**2*y**2 - y**6 - 121*y**4 - 2) + 11*y**8/2 + x/(2*y) assert NS(a, 15, subs={x: 77617, y: 33096}) == '-0.827396059946821' def test_evalf_complex(): assert NS('2*sqrt(pi)*I', 10) == '3.544907702*I' assert NS('3+3*I', 15) == '3.00000000000000 + 3.00000000000000*I' assert NS('E+pi*I', 15) == '2.71828182845905 + 3.14159265358979*I' assert NS('pi * (3+4*I)', 15) == '9.42477796076938 + 12.5663706143592*I' assert NS('I*(2+I)', 15) == '-1.00000000000000 + 2.00000000000000*I' @XFAIL def test_evalf_complex_bug(): assert NS('(pi+E*I)*(E+pi*I)', 15) in ('0.e-15 + 17.25866050002*I', '0.e-17 + 17.25866050002*I', '-0.e-17 + 17.25866050002*I') def test_evalf_complex_powers(): assert NS('(E+pi*I)**100000000000000000') == \ '-3.58896782867793e+61850354284995199 + 4.58581754997159e+61850354284995199*I' # XXX: rewrite if a+a*I simplification introduced in sympy #assert NS('(pi + pi*I)**2') in ('0.e-15 + 19.7392088021787*I', '0.e-16 + 19.7392088021787*I') assert NS('(pi + pi*I)**2', chop=True) == '19.7392088021787*I' assert NS( '(pi + 1/10**8 + pi*I)**2') == '6.2831853e-8 + 19.7392088650106*I' assert NS('(pi + 1/10**12 + pi*I)**2') == '6.283e-12 + 19.7392088021850*I' assert NS('(pi + pi*I)**4', chop=True) == '-389.636364136010' assert NS( '(pi + 1/10**8 + pi*I)**4') == '-389.636366616512 + 2.4805021e-6*I' assert NS('(pi + 1/10**12 + pi*I)**4') == '-389.636364136258 + 2.481e-10*I' assert NS( '(10000*pi + 10000*pi*I)**4', chop=True) == '-3.89636364136010e+18' @XFAIL def test_evalf_complex_powers_bug(): assert NS('(pi + pi*I)**4') == '-389.63636413601 + 0.e-14*I' def test_evalf_exponentiation(): assert NS(sqrt(-pi)) == '1.77245385090552*I' assert NS(Pow(pi*I, Rational( 1, 2), evaluate=False)) == '1.25331413731550 + 1.25331413731550*I' assert NS(pi**I) == '0.413292116101594 + 0.910598499212615*I' assert NS(pi**(E + I/3)) == '20.8438653991931 + 8.36343473930031*I' assert NS((pi + I/3)**(E + I/3)) == '17.2442906093590 + 13.6839376767037*I' assert NS(exp(pi)) == '23.1406926327793' assert NS(exp(pi + E*I)) == '-21.0981542849657 + 9.50576358282422*I' assert NS(pi**pi) == '36.4621596072079' assert NS((-pi)**pi) == '-32.9138577418939 - 15.6897116534332*I' assert NS((-pi)**(-pi)) == '-0.0247567717232697 + 0.0118013091280262*I' # An example from Smith, "Multiple Precision Complex Arithmetic and Functions" def test_evalf_complex_cancellation(): A = Rational('63287/100000') B = Rational('52498/100000') C = Rational('69301/100000') D = Rational('83542/100000') F = Rational('2231321613/2500000000') # XXX: the number of returned mantissa digits in the real part could # change with the implementation. What matters is that the returned digits are # correct; those that are showing now are correct. # >>> ((A+B*I)*(C+D*I)).expand() # 64471/10000000000 + 2231321613*I/2500000000 # >>> 2231321613*4 # 8925286452L assert NS((A + B*I)*(C + D*I), 6) == '6.44710e-6 + 0.892529*I' assert NS((A + B*I)*(C + D*I), 10) == '6.447100000e-6 + 0.8925286452*I' assert NS((A + B*I)*( C + D*I) - F*I, 5) in ('6.4471e-6 + 0.e-14*I', '6.4471e-6 - 0.e-14*I') def test_evalf_logs(): assert NS("log(3+pi*I)", 15) == '1.46877619736226 + 0.808448792630022*I' assert NS("log(pi*I)", 15) == '1.14472988584940 + 1.57079632679490*I' assert NS('log(-1 + 0.00001)', 2) == '-1.0e-5 + 3.1*I' assert NS('log(100, 10, evaluate=False)', 15) == '2.00000000000000' assert NS('-2*I*log(-(-1)**(S(1)/9))', 15) == '-5.58505360638185' def test_evalf_trig(): assert NS('sin(1)', 15) == '0.841470984807897' assert NS('cos(1)', 15) == '0.540302305868140' assert NS('sin(10**-6)', 15) == '9.99999999999833e-7' assert NS('cos(10**-6)', 15) == '0.999999999999500' assert NS('sin(E*10**100)', 15) == '0.409160531722613' # Some input near roots assert NS(sin(exp(pi*sqrt(163))*pi), 15) == '-2.35596641936785e-12' assert NS(sin(pi*10**100 + Rational(7, 10**5), evaluate=False), 15, maxn=120) == \ '6.99999999428333e-5' assert NS(sin(Rational(7, 10**5), evaluate=False), 15) == \ '6.99999999428333e-5' # Check detection of various false identities def test_evalf_near_integers(): # Binet's formula f = lambda n: ((1 + sqrt(5))**n)/(2**n * sqrt(5)) assert NS(f(5000) - fibonacci(5000), 10, maxn=1500) == '5.156009964e-1046' # Some near-integer identities from # http://mathworld.wolfram.com/AlmostInteger.html assert NS('sin(2017*2**(1/5))', 15) == '-1.00000000000000' assert NS('sin(2017*2**(1/5))', 20) == '-0.99999999999999997857' assert NS('1+sin(2017*2**(1/5))', 15) == '2.14322287389390e-17' assert NS('45 - 613*E/37 + 35/991', 15) == '6.03764498766326e-11' def test_evalf_ramanujan(): assert NS(exp(pi*sqrt(163)) - 640320**3 - 744, 10) == '-7.499274028e-13' # A related identity A = 262537412640768744*exp(-pi*sqrt(163)) B = 196884*exp(-2*pi*sqrt(163)) C = 103378831900730205293632*exp(-3*pi*sqrt(163)) assert NS(1 - A - B + C, 10) == '1.613679005e-59' # Input that for various reasons have failed at some point def test_evalf_bugs(): assert NS(sin(1) + exp(-10**10), 10) == NS(sin(1), 10) assert NS(exp(10**10) + sin(1), 10) == NS(exp(10**10), 10) assert NS('expand_log(log(1+1/10**50))', 20) == '1.0000000000000000000e-50' assert NS('log(10**100,10)', 10) == '100.0000000' assert NS('log(2)', 10) == '0.6931471806' assert NS( '(sin(x)-x)/x**3', 15, subs={x: '1/10**50'}) == '-0.166666666666667' assert NS(sin(1) + Rational( 1, 10**100)*I, 15) == '0.841470984807897 + 1.00000000000000e-100*I' assert x.evalf() == x assert NS((1 + I)**2*I, 6) == '-2.00000' d = {n: ( -1)**Rational(6, 7), y: (-1)**Rational(4, 7), x: (-1)**Rational(2, 7)} assert NS((x*(1 + y*(1 + n))).subs(d).evalf(), 6) == '0.346011 + 0.433884*I' assert NS(((-I - sqrt(2)*I)**2).evalf()) == '-5.82842712474619' assert NS((1 + I)**2*I, 15) == '-2.00000000000000' # issue 4758 (1/2): assert NS(pi.evalf(69) - pi) == '-4.43863937855894e-71' # issue 4758 (2/2): With the bug present, this still only fails if the # terms are in the order given here. This is not generally the case, # because the order depends on the hashes of the terms. assert NS(20 - 5008329267844*n**25 - 477638700*n**37 - 19*n, subs={n: .01}) == '19.8100000000000' assert NS(((x - 1)*(1 - x)**1000).n() ) == '(1.00000000000000 - x)**1000*(x - 1.00000000000000)' assert NS((-x).n()) == '-x' assert NS((-2*x).n()) == '-2.00000000000000*x' assert NS((-2*x*y).n()) == '-2.00000000000000*x*y' assert cos(x).n(subs={x: 1+I}) == cos(x).subs(x, 1+I).n() # issue 6660. Also NaN != mpmath.nan # In this order: # 0*nan, 0/nan, 0*inf, 0/inf # 0+nan, 0-nan, 0+inf, 0-inf # >>> n = Some Number # n*nan, n/nan, n*inf, n/inf # n+nan, n-nan, n+inf, n-inf assert (0*E**(oo)).n() is S.NaN assert (0/E**(oo)).n() is S.Zero assert (0+E**(oo)).n() is S.Infinity assert (0-E**(oo)).n() is S.NegativeInfinity assert (5*E**(oo)).n() is S.Infinity assert (5/E**(oo)).n() is S.Zero assert (5+E**(oo)).n() is S.Infinity assert (5-E**(oo)).n() is S.NegativeInfinity #issue 7416 assert as_mpmath(0.0, 10, {'chop': True}) == 0 #issue 5412 assert ((oo*I).n() == S.Infinity*I) assert ((oo+oo*I).n() == S.Infinity + S.Infinity*I) #issue 11518 assert NS(2*x**2.5, 5) == '2.0000*x**2.5000' #issue 13076 assert NS(Mul(Max(0, y), x, evaluate=False).evalf()) == 'x*Max(0, y)' #issue 18516 assert NS(log(S(3273390607896141870013189696827599152216642046043064789483291368096133796404674554883270092325904157150886684127560071009217256545885393053328527589376)/36360291795869936842385267079543319118023385026001623040346035832580600191583895484198508262979388783308179702534403855752855931517013066142992430916562025780021771247847643450125342836565813209972590371590152578728008385990139795377610001).evalf(15, chop=True)) == '-oo' def test_evalf_integer_parts(): a = floor(log(8)/log(2) - exp(-1000), evaluate=False) b = floor(log(8)/log(2), evaluate=False) assert a.evalf() == 3 assert b.evalf() == 3 # equals, as a fallback, can still fail but it might succeed as here assert ceiling(10*(sin(1)**2 + cos(1)**2)) == 10 assert int(floor(factorial(50)/E, evaluate=False).evalf(70)) == \ int(11188719610782480504630258070757734324011354208865721592720336800) assert int(ceiling(factorial(50)/E, evaluate=False).evalf(70)) == \ int(11188719610782480504630258070757734324011354208865721592720336801) assert int(floor(GoldenRatio**999 / sqrt(5) + S.Half) .evalf(1000)) == fibonacci(999) assert int(floor(GoldenRatio**1000 / sqrt(5) + S.Half) .evalf(1000)) == fibonacci(1000) assert ceiling(x).evalf(subs={x: 3}) == 3 assert ceiling(x).evalf(subs={x: 3*I}) == 3.0*I assert ceiling(x).evalf(subs={x: 2 + 3*I}) == 2.0 + 3.0*I assert ceiling(x).evalf(subs={x: 3.}) == 3 assert ceiling(x).evalf(subs={x: 3.*I}) == 3.0*I assert ceiling(x).evalf(subs={x: 2. + 3*I}) == 2.0 + 3.0*I assert float((floor(1.5, evaluate=False)+1/9).evalf()) == 1 + 1/9 assert float((floor(0.5, evaluate=False)+20).evalf()) == 20 # issue 19991 n = 1169809367327212570704813632106852886389036911 r = 744723773141314414542111064094745678855643068 assert floor(n / (pi / 2)) == r assert floor(80782 * sqrt(2)) == 114242 # issue 20076 assert 260515 - floor(260515/pi + 1/2) * pi == atan(tan(260515)) def test_evalf_trig_zero_detection(): a = sin(160*pi, evaluate=False) t = a.evalf(maxn=100) assert abs(t) < 1e-100 assert t._prec < 2 assert a.evalf(chop=True) == 0 raises(PrecisionExhausted, lambda: a.evalf(strict=True)) def test_evalf_sum(): assert Sum(n,(n,1,2)).evalf() == 3. assert Sum(n,(n,1,2)).doit().evalf() == 3. # the next test should return instantly assert Sum(1/n,(n,1,2)).evalf() == 1.5 # issue 8219 assert Sum(E/factorial(n), (n, 0, oo)).evalf() == (E*E).evalf() # issue 8254 assert Sum(2**n*n/factorial(n), (n, 0, oo)).evalf() == (2*E*E).evalf() # issue 8411 s = Sum(1/x**2, (x, 100, oo)) assert s.n() == s.doit().n() def test_evalf_divergent_series(): raises(ValueError, lambda: Sum(1/n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum(n/(n**2 + 1), (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum((-1)**n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum((-1)**n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum(n**2, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum(2**n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum((-2)**n, (n, 1, oo)).evalf()) raises(ValueError, lambda: Sum((2*n + 3)/(3*n**2 + 4), (n, 0, oo)).evalf()) raises(ValueError, lambda: Sum((0.5*n**3)/(n**4 + 1), (n, 0, oo)).evalf()) def test_evalf_product(): assert Product(n, (n, 1, 10)).evalf() == 3628800. assert comp(Product(1 - S.Half**2/n**2, (n, 1, oo)).n(5), 0.63662) assert Product(n, (n, -1, 3)).evalf() == 0 def test_evalf_py_methods(): assert abs(float(pi + 1) - 4.1415926535897932) < 1e-10 assert abs(complex(pi + 1) - 4.1415926535897932) < 1e-10 assert abs( complex(pi + E*I) - (3.1415926535897931 + 2.7182818284590451j)) < 1e-10 raises(TypeError, lambda: float(pi + x)) def test_evalf_power_subs_bugs(): assert (x**2).evalf(subs={x: 0}) == 0 assert sqrt(x).evalf(subs={x: 0}) == 0 assert (x**Rational(2, 3)).evalf(subs={x: 0}) == 0 assert (x**x).evalf(subs={x: 0}) == 1 assert (3**x).evalf(subs={x: 0}) == 1 assert exp(x).evalf(subs={x: 0}) == 1 assert ((2 + I)**x).evalf(subs={x: 0}) == 1 assert (0**x).evalf(subs={x: 0}) == 1 def test_evalf_arguments(): raises(TypeError, lambda: pi.evalf(method="garbage")) def test_implemented_function_evalf(): from sympy.utilities.lambdify import implemented_function f = Function('f') f = implemented_function(f, lambda x: x + 1) assert str(f(x)) == "f(x)" assert str(f(2)) == "f(2)" assert f(2).evalf() == 3 assert f(x).evalf() == f(x) f = implemented_function(Function('sin'), lambda x: x + 1) assert f(2).evalf() != sin(2) del f._imp_ # XXX: due to caching _imp_ would influence all other tests def test_evaluate_false(): for no in [0, False]: assert Add(3, 2, evaluate=no).is_Add assert Mul(3, 2, evaluate=no).is_Mul assert Pow(3, 2, evaluate=no).is_Pow assert Pow(y, 2, evaluate=True) - Pow(y, 2, evaluate=True) == 0 def test_evalf_relational(): assert Eq(x/5, y/10).evalf() == Eq(0.2*x, 0.1*y) # if this first assertion fails it should be replaced with # one that doesn't assert unchanged(Eq, (3 - I)**2/2 + I, 0) assert Eq((3 - I)**2/2 + I, 0).n() is S.false assert nfloat(Eq((3 - I)**2 + I, 0)) == S.false def test_issue_5486(): assert not cos(sqrt(0.5 + I)).n().is_Function def test_issue_5486_bug(): from sympy import I, Expr assert abs(Expr._from_mpmath(I._to_mpmath(15), 15) - I) < 1.0e-15 def test_bugs(): from sympy import polar_lift, re assert abs(re((1 + I)**2)) < 1e-15 # anything that evalf's to 0 will do in place of polar_lift assert abs(polar_lift(0)).n() == 0 def test_subs(): assert NS('besseli(-x, y) - besseli(x, y)', subs={x: 3.5, y: 20.0}) == \ '-4.92535585957223e-10' assert NS('Piecewise((x, x>0)) + Piecewise((1-x, x>0))', subs={x: 0.1}) == \ '1.00000000000000' raises(TypeError, lambda: x.evalf(subs=(x, 1))) def test_issue_4956_5204(): # issue 4956 v = S('''(-27*12**(1/3)*sqrt(31)*I + 27*2**(2/3)*3**(1/3)*sqrt(31)*I)/(-2511*2**(2/3)*3**(1/3) + (29*18**(1/3) + 9*2**(1/3)*3**(2/3)*sqrt(31)*I + 87*2**(1/3)*3**(1/6)*I)**2)''') assert NS(v, 1) == '0.e-118 - 0.e-118*I' # issue 5204 v = S('''-(357587765856 + 18873261792*249**(1/2) + 56619785376*I*83**(1/2) + 108755765856*I*3**(1/2) + 41281887168*6**(1/3)*(1422 + 54*249**(1/2))**(1/3) - 1239810624*6**(1/3)*249**(1/2)*(1422 + 54*249**(1/2))**(1/3) - 3110400000*I*6**(1/3)*83**(1/2)*(1422 + 54*249**(1/2))**(1/3) + 13478400000*I*3**(1/2)*6**(1/3)*(1422 + 54*249**(1/2))**(1/3) + 1274950152*6**(2/3)*(1422 + 54*249**(1/2))**(2/3) + 32347944*6**(2/3)*249**(1/2)*(1422 + 54*249**(1/2))**(2/3) - 1758790152*I*3**(1/2)*6**(2/3)*(1422 + 54*249**(1/2))**(2/3) - 304403832*I*6**(2/3)*83**(1/2)*(1422 + 4*249**(1/2))**(2/3))/(175732658352 + (1106028 + 25596*249**(1/2) + 76788*I*83**(1/2))**2)''') assert NS(v, 5) == '0.077284 + 1.1104*I' assert NS(v, 1) == '0.08 + 1.*I' def test_old_docstring(): a = (E + pi*I)*(E - pi*I) assert NS(a) == '17.2586605000200' assert a.n() == 17.25866050002001 def test_issue_4806(): assert integrate(atan(x)**2, (x, -1, 1)).evalf().round(1) == 0.5 assert atan(0, evaluate=False).n() == 0 def test_evalf_mul(): # sympy should not try to expand this; it should be handled term-wise # in evalf through mpmath assert NS(product(1 + sqrt(n)*I, (n, 1, 500)), 1) == '5.e+567 + 2.e+568*I' def test_scaled_zero(): a, b = (([0], 1, 100, 1), -1) assert scaled_zero(100) == (a, b) assert scaled_zero(a) == (0, 1, 100, 1) a, b = (([1], 1, 100, 1), -1) assert scaled_zero(100, -1) == (a, b) assert scaled_zero(a) == (1, 1, 100, 1) raises(ValueError, lambda: scaled_zero(scaled_zero(100))) raises(ValueError, lambda: scaled_zero(100, 2)) raises(ValueError, lambda: scaled_zero(100, 0)) raises(ValueError, lambda: scaled_zero((1, 5, 1, 3))) def test_chop_value(): for i in range(-27, 28): assert (Pow(10, i)*2).n(chop=10**i) and not (Pow(10, i)).n(chop=10**i) def test_infinities(): assert oo.evalf(chop=True) == inf assert (-oo).evalf(chop=True) == ninf def test_to_mpmath(): assert sqrt(3)._to_mpmath(20)._mpf_ == (0, int(908093), -19, 20) assert S(3.2)._to_mpmath(20)._mpf_ == (0, int(838861), -18, 20) def test_issue_6632_evalf(): add = (-100000*sqrt(2500000001) + 5000000001) assert add.n() == 9.999999998e-11 assert (add*add).n() == 9.999999996e-21 def test_issue_4945(): from sympy.abc import H from sympy import zoo assert (H/0).evalf(subs={H:1}) == zoo*H def test_evalf_integral(): # test that workprec has to increase in order to get a result other than 0 eps = Rational(1, 1000000) assert Integral(sin(x), (x, -pi, pi + eps)).n(2)._prec == 10 def test_issue_8821_highprec_from_str(): s = str(pi.evalf(128)) p = N(s) assert Abs(sin(p)) < 1e-15 p = N(s, 64) assert Abs(sin(p)) < 1e-64 def test_issue_8853(): p = Symbol('x', even=True, positive=True) assert floor(-p - S.Half).is_even == False assert floor(-p + S.Half).is_even == True assert ceiling(p - S.Half).is_even == True assert ceiling(p + S.Half).is_even == False assert get_integer_part(S.Half, -1, {}, True) == (0, 0) assert get_integer_part(S.Half, 1, {}, True) == (1, 0) assert get_integer_part(Rational(-1, 2), -1, {}, True) == (-1, 0) assert get_integer_part(Rational(-1, 2), 1, {}, True) == (0, 0) def test_issue_17681(): class identity_func(Function): def _eval_evalf(self, *args, **kwargs): return self.args[0].evalf(*args, **kwargs) assert floor(identity_func(S(0))) == 0 assert get_integer_part(S(0), 1, {}, True) == (0, 0) def test_issue_9326(): from sympy import Dummy d1 = Dummy('d') d2 = Dummy('d') e = d1 + d2 assert e.evalf(subs = {d1: 1, d2: 2}) == 3 def test_issue_10323(): assert ceiling(sqrt(2**30 + 1)) == 2**15 + 1 def test_AssocOp_Function(): # the first arg of Min is not comparable in the imaginary part raises(ValueError, lambda: S(''' Min(-sqrt(3)*cos(pi/18)/6 + re(1/((-1/2 - sqrt(3)*I/2)*(1/6 + sqrt(3)*I/18)**(1/3)))/3 + sin(pi/18)/2 + 2 + I*(-cos(pi/18)/2 - sqrt(3)*sin(pi/18)/6 + im(1/((-1/2 - sqrt(3)*I/2)*(1/6 + sqrt(3)*I/18)**(1/3)))/3), re(1/((-1/2 + sqrt(3)*I/2)*(1/6 + sqrt(3)*I/18)**(1/3)))/3 - sqrt(3)*cos(pi/18)/6 - sin(pi/18)/2 + 2 + I*(im(1/((-1/2 + sqrt(3)*I/2)*(1/6 + sqrt(3)*I/18)**(1/3)))/3 - sqrt(3)*sin(pi/18)/6 + cos(pi/18)/2))''')) # if that is changed so a non-comparable number remains as # an arg, then the Min/Max instantiation needs to be changed # to watch out for non-comparable args when making simplifications # and the following test should be added instead (with e being # the sympified expression above): # raises(ValueError, lambda: e._eval_evalf(2)) def test_issue_10395(): eq = x*Max(0, y) assert nfloat(eq) == eq eq = x*Max(y, -1.1) assert nfloat(eq) == eq assert Max(y, 4).n() == Max(4.0, y) def test_issue_13098(): assert floor(log(S('9.'+'9'*20), 10)) == 0 assert ceiling(log(S('9.'+'9'*20), 10)) == 1 assert floor(log(20 - S('9.'+'9'*20), 10)) == 1 assert ceiling(log(20 - S('9.'+'9'*20), 10)) == 2 def test_issue_14601(): e = 5*x*y/2 - y*(35*(x**3)/2 - 15*x/2) subst = {x:0.0, y:0.0} e2 = e.evalf(subs=subst) assert float(e2) == 0.0 assert float((x + x*(x**2 + x)).evalf(subs={x: 0.0})) == 0.0 def test_issue_11151(): z = S.Zero e = Sum(z, (x, 1, 2)) assert e != z # it shouldn't evaluate # when it does evaluate, this is what it should give assert evalf(e, 15, {}) == \ evalf(z, 15, {}) == (None, None, 15, None) # so this shouldn't fail assert (e/2).n() == 0 # this was where the issue appeared expr0 = Sum(x**2 + x, (x, 1, 2)) expr1 = Sum(0, (x, 1, 2)) expr2 = expr1/expr0 assert simplify(factor(expr2) - expr2) == 0 def test_issue_13425(): assert N('2**.5', 30) == N('sqrt(2)', 30) assert N('x - x', 30) == 0 assert abs((N('pi*.1', 22)*10 - pi).n()) < 1e-22 def test_issue_17421(): assert N(acos(-I + acosh(cosh(cosh(1) + I)))) == 1.0*I def test_issue_20291(): from sympy import FiniteSet, Complement, Intersection, Reals, EmptySet a = Symbol('a') b = Symbol('b') A = FiniteSet(a, b) assert A.evalf(subs={a: 1, b: 2}) == FiniteSet(1.0, 2.0) B = FiniteSet(a-b, 1) assert B.evalf(subs={a: 1, b: 2}) == FiniteSet(-1.0, 1.0) sol = Complement(Intersection(FiniteSet(-b/2 - sqrt(b**2-4*pi)/2), Reals), FiniteSet(0)) assert sol.evalf(subs={b: 1}) == EmptySet sympy-sympy-1.9/sympy/core/tests/test_expand.py000066400000000000000000000271211412543434000220710ustar00rootroot00000000000000from sympy import (log, sqrt, Rational as R, Symbol, I, exp, pi, S, cos, sin, Mul, Pow, O) from sympy.simplify.radsimp import expand_numer from sympy.core.function import expand, expand_multinomial, expand_power_base from sympy.testing.pytest import raises from sympy.testing.randtest import verify_numerically from sympy.abc import x, y, z def test_expand_no_log(): assert ( (1 + log(x**4))**2).expand(log=False) == 1 + 2*log(x**4) + log(x**4)**2 assert ((1 + log(x**4))*(1 + log(x**3))).expand( log=False) == 1 + log(x**4) + log(x**3) + log(x**4)*log(x**3) def test_expand_no_multinomial(): assert ((1 + x)*(1 + (1 + x)**4)).expand(multinomial=False) == \ 1 + x + (1 + x)**4 + x*(1 + x)**4 def test_expand_negative_integer_powers(): expr = (x + y)**(-2) assert expr.expand() == 1 / (2*x*y + x**2 + y**2) assert expr.expand(multinomial=False) == (x + y)**(-2) expr = (x + y)**(-3) assert expr.expand() == 1 / (3*x*x*y + 3*x*y*y + x**3 + y**3) assert expr.expand(multinomial=False) == (x + y)**(-3) expr = (x + y)**(2) * (x + y)**(-4) assert expr.expand() == 1 / (2*x*y + x**2 + y**2) assert expr.expand(multinomial=False) == (x + y)**(-2) def test_expand_non_commutative(): A = Symbol('A', commutative=False) B = Symbol('B', commutative=False) C = Symbol('C', commutative=False) a = Symbol('a') b = Symbol('b') i = Symbol('i', integer=True) n = Symbol('n', negative=True) m = Symbol('m', negative=True) p = Symbol('p', polar=True) np = Symbol('p', polar=False) assert (C*(A + B)).expand() == C*A + C*B assert (C*(A + B)).expand() != A*C + B*C assert ((A + B)**2).expand() == A**2 + A*B + B*A + B**2 assert ((A + B)**3).expand() == (A**2*B + B**2*A + A*B**2 + B*A**2 + A**3 + B**3 + A*B*A + B*A*B) # issue 6219 assert ((a*A*B*A**-1)**2).expand() == a**2*A*B**2/A # Note that (a*A*B*A**-1)**2 is automatically converted to a**2*(A*B*A**-1)**2 assert ((a*A*B*A**-1)**2).expand(deep=False) == a**2*(A*B*A**-1)**2 assert ((a*A*B*A**-1)**2).expand() == a**2*(A*B**2*A**-1) assert ((a*A*B*A**-1)**2).expand(force=True) == a**2*A*B**2*A**(-1) assert ((a*A*B)**2).expand() == a**2*A*B*A*B assert ((a*A)**2).expand() == a**2*A**2 assert ((a*A*B)**i).expand() == a**i*(A*B)**i assert ((a*A*(B*(A*B/A)**2))**i).expand() == a**i*(A*B*A*B**2/A)**i # issue 6558 assert (A*B*(A*B)**-1).expand() == 1 assert ((a*A)**i).expand() == a**i*A**i assert ((a*A*B*A**-1)**3).expand() == a**3*A*B**3/A assert ((a*A*B*A*B/A)**3).expand() == \ a**3*A*B*(A*B**2)*(A*B**2)*A*B*A**(-1) assert ((a*A*B*A*B/A)**-2).expand() == \ A*B**-1*A**-1*B**-2*A**-1*B**-1*A**-1/a**2 assert ((a*b*A*B*A**-1)**i).expand() == a**i*b**i*(A*B/A)**i assert ((a*(a*b)**i)**i).expand() == a**i*a**(i**2)*b**(i**2) e = Pow(Mul(a, 1/a, A, B, evaluate=False), S(2), evaluate=False) assert e.expand() == A*B*A*B assert sqrt(a*(A*b)**i).expand() == sqrt(a*b**i*A**i) assert (sqrt(-a)**a).expand() == sqrt(-a)**a assert expand((-2*n)**(i/3)) == 2**(i/3)*(-n)**(i/3) assert expand((-2*n*m)**(i/a)) == (-2)**(i/a)*(-n)**(i/a)*(-m)**(i/a) assert expand((-2*a*p)**b) == 2**b*p**b*(-a)**b assert expand((-2*a*np)**b) == 2**b*(-a*np)**b assert expand(sqrt(A*B)) == sqrt(A*B) assert expand(sqrt(-2*a*b)) == sqrt(2)*sqrt(-a*b) def test_expand_radicals(): a = (x + y)**R(1, 2) assert (a**1).expand() == a assert (a**3).expand() == x*a + y*a assert (a**5).expand() == x**2*a + 2*x*y*a + y**2*a assert (1/a**1).expand() == 1/a assert (1/a**3).expand() == 1/(x*a + y*a) assert (1/a**5).expand() == 1/(x**2*a + 2*x*y*a + y**2*a) a = (x + y)**R(1, 3) assert (a**1).expand() == a assert (a**2).expand() == a**2 assert (a**4).expand() == x*a + y*a assert (a**5).expand() == x*a**2 + y*a**2 assert (a**7).expand() == x**2*a + 2*x*y*a + y**2*a def test_expand_modulus(): assert ((x + y)**11).expand(modulus=11) == x**11 + y**11 assert ((x + sqrt(2)*y)**11).expand(modulus=11) == x**11 + 10*sqrt(2)*y**11 assert (x + y/2).expand(modulus=1) == y/2 raises(ValueError, lambda: ((x + y)**11).expand(modulus=0)) raises(ValueError, lambda: ((x + y)**11).expand(modulus=x)) def test_issue_5743(): assert (x*sqrt( x + y)*(1 + sqrt(x + y))).expand() == x**2 + x*y + x*sqrt(x + y) assert (x*sqrt( x + y)*(1 + x*sqrt(x + y))).expand() == x**3 + x**2*y + x*sqrt(x + y) def test_expand_frac(): assert expand((x + y)*y/x/(x + 1), frac=True) == \ (x*y + y**2)/(x**2 + x) assert expand((x + y)*y/x/(x + 1), numer=True) == \ (x*y + y**2)/(x*(x + 1)) assert expand((x + y)*y/x/(x + 1), denom=True) == \ y*(x + y)/(x**2 + x) eq = (x + 1)**2/y assert expand_numer(eq, multinomial=False) == eq def test_issue_6121(): eq = -I*exp(-3*I*pi/4)/(4*pi**(S(3)/2)*sqrt(x)) assert eq.expand(complex=True) # does not give oo recursion eq = -I*exp(-3*I*pi/4)/(4*pi**(R(3, 2))*sqrt(x)) assert eq.expand(complex=True) # does not give oo recursion def test_expand_power_base(): assert expand_power_base((x*y*z)**4) == x**4*y**4*z**4 assert expand_power_base((x*y*z)**x).is_Pow assert expand_power_base((x*y*z)**x, force=True) == x**x*y**x*z**x assert expand_power_base((x*(y*z)**2)**3) == x**3*y**6*z**6 assert expand_power_base((sin((x*y)**2)*y)**z).is_Pow assert expand_power_base( (sin((x*y)**2)*y)**z, force=True) == sin((x*y)**2)**z*y**z assert expand_power_base( (sin((x*y)**2)*y)**z, deep=True) == (sin(x**2*y**2)*y)**z assert expand_power_base(exp(x)**2) == exp(2*x) assert expand_power_base((exp(x)*exp(y))**2) == exp(2*x)*exp(2*y) assert expand_power_base( (exp((x*y)**z)*exp(y))**2) == exp(2*(x*y)**z)*exp(2*y) assert expand_power_base((exp((x*y)**z)*exp( y))**2, deep=True, force=True) == exp(2*x**z*y**z)*exp(2*y) assert expand_power_base((exp(x)*exp(y))**z).is_Pow assert expand_power_base( (exp(x)*exp(y))**z, force=True) == exp(x)**z*exp(y)**z def test_expand_arit(): a = Symbol("a") b = Symbol("b", positive=True) c = Symbol("c") p = R(5) e = (a + b)*c assert e == c*(a + b) assert (e.expand() - a*c - b*c) == R(0) e = (a + b)*(a + b) assert e == (a + b)**2 assert e.expand() == 2*a*b + a**2 + b**2 e = (a + b)*(a + b)**R(2) assert e == (a + b)**3 assert e.expand() == 3*b*a**2 + 3*a*b**2 + a**3 + b**3 assert e.expand() == 3*b*a**2 + 3*a*b**2 + a**3 + b**3 e = (a + b)*(a + c)*(b + c) assert e == (a + c)*(a + b)*(b + c) assert e.expand() == 2*a*b*c + b*a**2 + c*a**2 + b*c**2 + a*c**2 + c*b**2 + a*b**2 e = (a + R(1))**p assert e == (1 + a)**5 assert e.expand() == 1 + 5*a + 10*a**2 + 10*a**3 + 5*a**4 + a**5 e = (a + b + c)*(a + c + p) assert e == (5 + a + c)*(a + b + c) assert e.expand() == 5*a + 5*b + 5*c + 2*a*c + b*c + a*b + a**2 + c**2 x = Symbol("x") s = exp(x*x) - 1 e = s.nseries(x, 0, 6)/x**2 assert e.expand() == 1 + x**2/2 + O(x**4) e = (x*(y + z))**(x*(y + z))*(x + y) assert e.expand(power_exp=False, power_base=False) == x*(x*y + x* z)**(x*y + x*z) + y*(x*y + x*z)**(x*y + x*z) assert e.expand(power_exp=False, power_base=False, deep=False) == x* \ (x*(y + z))**(x*(y + z)) + y*(x*(y + z))**(x*(y + z)) e = x * (x + (y + 1)**2) assert e.expand(deep=False) == x**2 + x*(y + 1)**2 e = (x*(y + z))**z assert e.expand(power_base=True, mul=True, deep=True) in [x**z*(y + z)**z, (x*y + x*z)**z] assert ((2*y)**z).expand() == 2**z*y**z p = Symbol('p', positive=True) assert sqrt(-x).expand().is_Pow assert sqrt(-x).expand(force=True) == I*sqrt(x) assert ((2*y*p)**z).expand() == 2**z*p**z*y**z assert ((2*y*p*x)**z).expand() == 2**z*p**z*(x*y)**z assert ((2*y*p*x)**z).expand(force=True) == 2**z*p**z*x**z*y**z assert ((2*y*p*-pi)**z).expand() == 2**z*pi**z*p**z*(-y)**z assert ((2*y*p*-pi*x)**z).expand() == 2**z*pi**z*p**z*(-x*y)**z n = Symbol('n', negative=True) m = Symbol('m', negative=True) assert ((-2*x*y*n)**z).expand() == 2**z*(-n)**z*(x*y)**z assert ((-2*x*y*n*m)**z).expand() == 2**z*(-m)**z*(-n)**z*(-x*y)**z # issue 5482 assert sqrt(-2*x*n) == sqrt(2)*sqrt(-n)*sqrt(x) # issue 5605 (2) assert (cos(x + y)**2).expand(trig=True) in [ (-sin(x)*sin(y) + cos(x)*cos(y))**2, sin(x)**2*sin(y)**2 - 2*sin(x)*sin(y)*cos(x)*cos(y) + cos(x)**2*cos(y)**2 ] # Check that this isn't too slow x = Symbol('x') W = 1 for i in range(1, 21): W = W * (x - i) W = W.expand() assert W.has(-1672280820*x**15) def test_expand_mul(): # part of issue 20597 e = Mul(2, 3, evaluate=False) assert e.expand() == 6 e = Mul(2, 3, 1/x, evaluate = False) assert e.expand() == 6/x e = Mul(2, R(1, 3), evaluate=False) assert e.expand() == R(2, 3) def test_power_expand(): """Test for Pow.expand()""" a = Symbol('a') b = Symbol('b') p = (a + b)**2 assert p.expand() == a**2 + b**2 + 2*a*b p = (1 + 2*(1 + a))**2 assert p.expand() == 9 + 4*(a**2) + 12*a p = 2**(a + b) assert p.expand() == 2**a*2**b A = Symbol('A', commutative=False) B = Symbol('B', commutative=False) assert (2**(A + B)).expand() == 2**(A + B) assert (A**(a + b)).expand() != A**(a + b) def test_issues_5919_6830(): # issue 5919 n = -1 + 1/x z = n/x/(-n)**2 - 1/n/x assert expand(z) == 1/(x**2 - 2*x + 1) - 1/(x - 2 + 1/x) - 1/(-x + 1) # issue 6830 p = (1 + x)**2 assert expand_multinomial((1 + x*p)**2) == ( x**2*(x**4 + 4*x**3 + 6*x**2 + 4*x + 1) + 2*x*(x**2 + 2*x + 1) + 1) assert expand_multinomial((1 + (y + x)*p)**2) == ( 2*((x + y)*(x**2 + 2*x + 1)) + (x**2 + 2*x*y + y**2)* (x**4 + 4*x**3 + 6*x**2 + 4*x + 1) + 1) A = Symbol('A', commutative=False) p = (1 + A)**2 assert expand_multinomial((1 + x*p)**2) == ( x**2*(1 + 4*A + 6*A**2 + 4*A**3 + A**4) + 2*x*(1 + 2*A + A**2) + 1) assert expand_multinomial((1 + (y + x)*p)**2) == ( (x + y)*(1 + 2*A + A**2)*2 + (x**2 + 2*x*y + y**2)* (1 + 4*A + 6*A**2 + 4*A**3 + A**4) + 1) assert expand_multinomial((1 + (y + x)*p)**3) == ( (x + y)*(1 + 2*A + A**2)*3 + (x**2 + 2*x*y + y**2)*(1 + 4*A + 6*A**2 + 4*A**3 + A**4)*3 + (x**3 + 3*x**2*y + 3*x*y**2 + y**3)*(1 + 6*A + 15*A**2 + 20*A**3 + 15*A**4 + 6*A**5 + A**6) + 1) # unevaluate powers eq = (Pow((x + 1)*((A + 1)**2), 2, evaluate=False)) # - in this case the base is not an Add so no further # expansion is done assert expand_multinomial(eq) == \ (x**2 + 2*x + 1)*(1 + 4*A + 6*A**2 + 4*A**3 + A**4) # - but here, the expanded base *is* an Add so it gets expanded eq = (Pow(((A + 1)**2), 2, evaluate=False)) assert expand_multinomial(eq) == 1 + 4*A + 6*A**2 + 4*A**3 + A**4 # coverage def ok(a, b, n): e = (a + I*b)**n return verify_numerically(e, expand_multinomial(e)) for a in [2, S.Half]: for b in [3, R(1, 3)]: for n in range(2, 6): assert ok(a, b, n) assert expand_multinomial((x + 1 + O(z))**2) == \ 1 + 2*x + x**2 + O(z) assert expand_multinomial((x + 1 + O(z))**3) == \ 1 + 3*x + 3*x**2 + x**3 + O(z) assert expand_multinomial(3**(x + y + 3)) == 27*3**(x + y) def test_expand_log(): t = Symbol('t', positive=True) # after first expansion, -2*log(2) + log(4); then 0 after second assert expand(log(t**2) - log(t**2/4) - 2*log(2)) == 0 sympy-sympy-1.9/sympy/core/tests/test_expr.py000066400000000000000000002143411412543434000215720ustar00rootroot00000000000000from sympy import (Add, Basic, Expr, S, Symbol, Wild, Float, Integer, Rational, I, sin, cos, tan, exp, log, nan, oo, sqrt, symbols, Integral, sympify, WildFunction, Poly, Function, Derivative, Number, pi, NumberSymbol, zoo, Piecewise, Mul, Pow, nsimplify, ratsimp, trigsimp, radsimp, powsimp, simplify, together, collect, factorial, apart, combsimp, factor, refine, cancel, Tuple, default_sort_key, DiracDelta, gamma, Dummy, Sum, E, exp_polar, expand, diff, O, Heaviside, Si, Max, UnevaluatedExpr, integrate, gammasimp, Gt) from sympy.core.expr import ExprBuilder, unchanged from sympy.core.function import AppliedUndef from sympy.physics.secondquant import FockState from sympy.physics.units import meter from sympy.testing.pytest import raises, XFAIL from sympy.abc import a, b, c, n, t, u, x, y, z class DummyNumber: """ Minimal implementation of a number that works with SymPy. If one has a Number class (e.g. Sage Integer, or some other custom class) that one wants to work well with SymPy, one has to implement at least the methods of this class DummyNumber, resp. its subclasses I5 and F1_1. Basically, one just needs to implement either __int__() or __float__() and then one needs to make sure that the class works with Python integers and with itself. """ def __radd__(self, a): if isinstance(a, (int, float)): return a + self.number return NotImplemented def __add__(self, a): if isinstance(a, (int, float, DummyNumber)): return self.number + a return NotImplemented def __rsub__(self, a): if isinstance(a, (int, float)): return a - self.number return NotImplemented def __sub__(self, a): if isinstance(a, (int, float, DummyNumber)): return self.number - a return NotImplemented def __rmul__(self, a): if isinstance(a, (int, float)): return a * self.number return NotImplemented def __mul__(self, a): if isinstance(a, (int, float, DummyNumber)): return self.number * a return NotImplemented def __rtruediv__(self, a): if isinstance(a, (int, float)): return a / self.number return NotImplemented def __truediv__(self, a): if isinstance(a, (int, float, DummyNumber)): return self.number / a return NotImplemented def __rpow__(self, a): if isinstance(a, (int, float)): return a ** self.number return NotImplemented def __pow__(self, a): if isinstance(a, (int, float, DummyNumber)): return self.number ** a return NotImplemented def __pos__(self): return self.number def __neg__(self): return - self.number class I5(DummyNumber): number = 5 def __int__(self): return self.number class F1_1(DummyNumber): number = 1.1 def __float__(self): return self.number i5 = I5() f1_1 = F1_1() # basic sympy objects basic_objs = [ Rational(2), Float("1.3"), x, y, pow(x, y)*y, ] # all supported objects all_objs = basic_objs + [ 5, 5.5, i5, f1_1 ] def dotest(s): for xo in all_objs: for yo in all_objs: s(xo, yo) return True def test_basic(): def j(a, b): x = a x = +a x = -a x = a + b x = a - b x = a*b x = a/b x = a**b del x assert dotest(j) def test_ibasic(): def s(a, b): x = a x += b x = a x -= b x = a x *= b x = a x /= b assert dotest(s) class NonBasic: '''This class represents an object that knows how to implement binary operations like +, -, etc with Expr but is not a subclass of Basic itself. The NonExpr subclass below does subclass Basic but not Expr. For both NonBasic and NonExpr it should be possible for them to override Expr.__add__ etc because Expr.__add__ should be returning NotImplemented for non Expr classes. Otherwise Expr.__add__ would create meaningless objects like Add(Integer(1), FiniteSet(2)) and it wouldn't be possible for other classes to override these operations when interacting with Expr. ''' def __add__(self, other): return SpecialOp('+', self, other) def __radd__(self, other): return SpecialOp('+', other, self) def __sub__(self, other): return SpecialOp('-', self, other) def __rsub__(self, other): return SpecialOp('-', other, self) def __mul__(self, other): return SpecialOp('*', self, other) def __rmul__(self, other): return SpecialOp('*', other, self) def __truediv__(self, other): return SpecialOp('/', self, other) def __rtruediv__(self, other): return SpecialOp('/', other, self) def __floordiv__(self, other): return SpecialOp('//', self, other) def __rfloordiv__(self, other): return SpecialOp('//', other, self) def __mod__(self, other): return SpecialOp('%', self, other) def __rmod__(self, other): return SpecialOp('%', other, self) def __divmod__(self, other): return SpecialOp('divmod', self, other) def __rdivmod__(self, other): return SpecialOp('divmod', other, self) def __pow__(self, other): return SpecialOp('**', self, other) def __rpow__(self, other): return SpecialOp('**', other, self) def __lt__(self, other): return SpecialOp('<', self, other) def __gt__(self, other): return SpecialOp('>', self, other) def __le__(self, other): return SpecialOp('<=', self, other) def __ge__(self, other): return SpecialOp('>=', self, other) class NonExpr(Basic, NonBasic): '''Like NonBasic above except this is a subclass of Basic but not Expr''' pass class SpecialOp(Basic): '''Represents the results of operations with NonBasic and NonExpr''' def __new__(cls, op, arg1, arg2): return Basic.__new__(cls, op, arg1, arg2) class NonArithmetic(Basic): '''Represents a Basic subclass that does not support arithmetic operations''' pass def test_cooperative_operations(): '''Tests that Expr uses binary operations cooperatively. In particular it should be possible for non-Expr classes to override binary operators like +, - etc when used with Expr instances. This should work for non-Expr classes whether they are Basic subclasses or not. Also non-Expr classes that do not define binary operators with Expr should give TypeError. ''' # A bunch of instances of Expr subclasses exprs = [ Expr(), S.Zero, S.One, S.Infinity, S.NegativeInfinity, S.ComplexInfinity, S.Half, Float(0.5), Integer(2), Symbol('x'), Mul(2, Symbol('x')), Add(2, Symbol('x')), Pow(2, Symbol('x')), ] for e in exprs: # Test that these classes can override arithmetic operations in # combination with various Expr types. for ne in [NonBasic(), NonExpr()]: results = [ (ne + e, ('+', ne, e)), (e + ne, ('+', e, ne)), (ne - e, ('-', ne, e)), (e - ne, ('-', e, ne)), (ne * e, ('*', ne, e)), (e * ne, ('*', e, ne)), (ne / e, ('/', ne, e)), (e / ne, ('/', e, ne)), (ne // e, ('//', ne, e)), (e // ne, ('//', e, ne)), (ne % e, ('%', ne, e)), (e % ne, ('%', e, ne)), (divmod(ne, e), ('divmod', ne, e)), (divmod(e, ne), ('divmod', e, ne)), (ne ** e, ('**', ne, e)), (e ** ne, ('**', e, ne)), (e < ne, ('>', ne, e)), (ne < e, ('<', ne, e)), (e > ne, ('<', ne, e)), (ne > e, ('>', ne, e)), (e <= ne, ('>=', ne, e)), (ne <= e, ('<=', ne, e)), (e >= ne, ('<=', ne, e)), (ne >= e, ('>=', ne, e)), ] for res, args in results: assert type(res) is SpecialOp and res.args == args # These classes do not support binary operators with Expr. Every # operation should raise in combination with any of the Expr types. for na in [NonArithmetic(), object()]: raises(TypeError, lambda : e + na) raises(TypeError, lambda : na + e) raises(TypeError, lambda : e - na) raises(TypeError, lambda : na - e) raises(TypeError, lambda : e * na) raises(TypeError, lambda : na * e) raises(TypeError, lambda : e / na) raises(TypeError, lambda : na / e) raises(TypeError, lambda : e // na) raises(TypeError, lambda : na // e) raises(TypeError, lambda : e % na) raises(TypeError, lambda : na % e) raises(TypeError, lambda : divmod(e, na)) raises(TypeError, lambda : divmod(na, e)) raises(TypeError, lambda : e ** na) raises(TypeError, lambda : na ** e) raises(TypeError, lambda : e > na) raises(TypeError, lambda : na > e) raises(TypeError, lambda : e < na) raises(TypeError, lambda : na < e) raises(TypeError, lambda : e >= na) raises(TypeError, lambda : na >= e) raises(TypeError, lambda : e <= na) raises(TypeError, lambda : na <= e) def test_relational(): from sympy import Lt assert (pi < 3) is S.false assert (pi <= 3) is S.false assert (pi > 3) is S.true assert (pi >= 3) is S.true assert (-pi < 3) is S.true assert (-pi <= 3) is S.true assert (-pi > 3) is S.false assert (-pi >= 3) is S.false r = Symbol('r', real=True) assert (r - 2 < r - 3) is S.false assert Lt(x + I, x + I + 2).func == Lt # issue 8288 def test_relational_assumptions(): from sympy import Lt, Gt, Le, Ge m1 = Symbol("m1", nonnegative=False) m2 = Symbol("m2", positive=False) m3 = Symbol("m3", nonpositive=False) m4 = Symbol("m4", negative=False) assert (m1 < 0) == Lt(m1, 0) assert (m2 <= 0) == Le(m2, 0) assert (m3 > 0) == Gt(m3, 0) assert (m4 >= 0) == Ge(m4, 0) m1 = Symbol("m1", nonnegative=False, real=True) m2 = Symbol("m2", positive=False, real=True) m3 = Symbol("m3", nonpositive=False, real=True) m4 = Symbol("m4", negative=False, real=True) assert (m1 < 0) is S.true assert (m2 <= 0) is S.true assert (m3 > 0) is S.true assert (m4 >= 0) is S.true m1 = Symbol("m1", negative=True) m2 = Symbol("m2", nonpositive=True) m3 = Symbol("m3", positive=True) m4 = Symbol("m4", nonnegative=True) assert (m1 < 0) is S.true assert (m2 <= 0) is S.true assert (m3 > 0) is S.true assert (m4 >= 0) is S.true m1 = Symbol("m1", negative=False, real=True) m2 = Symbol("m2", nonpositive=False, real=True) m3 = Symbol("m3", positive=False, real=True) m4 = Symbol("m4", nonnegative=False, real=True) assert (m1 < 0) is S.false assert (m2 <= 0) is S.false assert (m3 > 0) is S.false assert (m4 >= 0) is S.false # See https://github.com/sympy/sympy/issues/17708 #def test_relational_noncommutative(): # from sympy import Lt, Gt, Le, Ge # A, B = symbols('A,B', commutative=False) # assert (A < B) == Lt(A, B) # assert (A <= B) == Le(A, B) # assert (A > B) == Gt(A, B) # assert (A >= B) == Ge(A, B) def test_basic_nostr(): for obj in basic_objs: raises(TypeError, lambda: obj + '1') raises(TypeError, lambda: obj - '1') if obj == 2: assert obj * '1' == '11' else: raises(TypeError, lambda: obj * '1') raises(TypeError, lambda: obj / '1') raises(TypeError, lambda: obj ** '1') def test_series_expansion_for_uniform_order(): assert (1/x + y + x).series(x, 0, 0) == 1/x + O(1, x) assert (1/x + y + x).series(x, 0, 1) == 1/x + y + O(x) assert (1/x + 1 + x).series(x, 0, 0) == 1/x + O(1, x) assert (1/x + 1 + x).series(x, 0, 1) == 1/x + 1 + O(x) assert (1/x + x).series(x, 0, 0) == 1/x + O(1, x) assert (1/x + y + y*x + x).series(x, 0, 0) == 1/x + O(1, x) assert (1/x + y + y*x + x).series(x, 0, 1) == 1/x + y + O(x) def test_leadterm(): assert (3 + 2*x**(log(3)/log(2) - 1)).leadterm(x) == (3, 0) assert (1/x**2 + 1 + x + x**2).leadterm(x)[1] == -2 assert (1/x + 1 + x + x**2).leadterm(x)[1] == -1 assert (x**2 + 1/x).leadterm(x)[1] == -1 assert (1 + x**2).leadterm(x)[1] == 0 assert (x + 1).leadterm(x)[1] == 0 assert (x + x**2).leadterm(x)[1] == 1 assert (x**2).leadterm(x)[1] == 2 def test_as_leading_term(): assert (3 + 2*x**(log(3)/log(2) - 1)).as_leading_term(x) == 3 assert (1/x**2 + 1 + x + x**2).as_leading_term(x) == 1/x**2 assert (1/x + 1 + x + x**2).as_leading_term(x) == 1/x assert (x**2 + 1/x).as_leading_term(x) == 1/x assert (1 + x**2).as_leading_term(x) == 1 assert (x + 1).as_leading_term(x) == 1 assert (x + x**2).as_leading_term(x) == x assert (x**2).as_leading_term(x) == x**2 assert (x + oo).as_leading_term(x) is oo raises(ValueError, lambda: (x + 1).as_leading_term(1)) # https://github.com/sympy/sympy/issues/21177 f = -3*x + (x + Rational(3, 2) - sqrt(3)*S.ImaginaryUnit/2)**2\ - Rational(3, 2) + 3*sqrt(3)*S.ImaginaryUnit/2 assert f.as_leading_term(x) == \ (12*sqrt(3)*x - 12*S.ImaginaryUnit*x)/(4*sqrt(3) + 12*S.ImaginaryUnit) # https://github.com/sympy/sympy/issues/21245 f = 1 - x - x**2 fi = (1 + sqrt(5))/2 assert f.subs(x, y + 1/fi).as_leading_term(y) == \ (-576*sqrt(5)*y - 1280*y)/(256*sqrt(5) + 576) def test_leadterm2(): assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).leadterm(x) == \ (sin(1 + sin(1)), 0) def test_leadterm3(): assert (y + z + x).leadterm(x) == (y + z, 0) def test_as_leading_term2(): assert (x*cos(1)*cos(1 + sin(1)) + sin(1 + sin(1))).as_leading_term(x) == \ sin(1 + sin(1)) def test_as_leading_term3(): assert (2 + pi + x).as_leading_term(x) == 2 + pi assert (2*x + pi*x + x**2).as_leading_term(x) == 2*x + pi*x def test_as_leading_term4(): # see issue 6843 n = Symbol('n', integer=True, positive=True) r = -n**3/(2*n**2 + 4*n + 2) - n**2/(n**2 + 2*n + 1) + \ n**2/(n + 1) - n/(2*n**2 + 4*n + 2) + n/(n*x + x) + 2*n/(n + 1) - \ 1 + 1/(n*x + x) + 1/(n + 1) - 1/x assert r.as_leading_term(x).cancel() == n/2 def test_as_leading_term_stub(): class foo(Function): pass assert foo(1/x).as_leading_term(x) == foo(1/x) assert foo(1).as_leading_term(x) == foo(1) raises(NotImplementedError, lambda: foo(x).as_leading_term(x)) def test_as_leading_term_deriv_integral(): # related to issue 11313 assert Derivative(x ** 3, x).as_leading_term(x) == 3*x**2 assert Derivative(x ** 3, y).as_leading_term(x) == 0 assert Integral(x ** 3, x).as_leading_term(x) == x**4/4 assert Integral(x ** 3, y).as_leading_term(x) == y*x**3 assert Derivative(exp(x), x).as_leading_term(x) == 1 assert Derivative(log(x), x).as_leading_term(x) == (1/x).as_leading_term(x) def test_atoms(): assert x.atoms() == {x} assert (1 + x).atoms() == {x, S.One} assert (1 + 2*cos(x)).atoms(Symbol) == {x} assert (1 + 2*cos(x)).atoms(Symbol, Number) == {S.One, S(2), x} assert (2*(x**(y**x))).atoms() == {S(2), x, y} assert S.Half.atoms() == {S.Half} assert S.Half.atoms(Symbol) == set() assert sin(oo).atoms(oo) == set() assert Poly(0, x).atoms() == {S.Zero, x} assert Poly(1, x).atoms() == {S.One, x} assert Poly(x, x).atoms() == {x} assert Poly(x, x, y).atoms() == {x, y} assert Poly(x + y, x, y).atoms() == {x, y} assert Poly(x + y, x, y, z).atoms() == {x, y, z} assert Poly(x + y*t, x, y, z).atoms() == {t, x, y, z} assert (I*pi).atoms(NumberSymbol) == {pi} assert (I*pi).atoms(NumberSymbol, I) == \ (I*pi).atoms(I, NumberSymbol) == {pi, I} assert exp(exp(x)).atoms(exp) == {exp(exp(x)), exp(x)} assert (1 + x*(2 + y) + exp(3 + z)).atoms(Add) == \ {1 + x*(2 + y) + exp(3 + z), 2 + y, 3 + z} # issue 6132 f = Function('f') e = (f(x) + sin(x) + 2) assert e.atoms(AppliedUndef) == \ {f(x)} assert e.atoms(AppliedUndef, Function) == \ {f(x), sin(x)} assert e.atoms(Function) == \ {f(x), sin(x)} assert e.atoms(AppliedUndef, Number) == \ {f(x), S(2)} assert e.atoms(Function, Number) == \ {S(2), sin(x), f(x)} def test_is_polynomial(): k = Symbol('k', nonnegative=True, integer=True) assert Rational(2).is_polynomial(x, y, z) is True assert (S.Pi).is_polynomial(x, y, z) is True assert x.is_polynomial(x) is True assert x.is_polynomial(y) is True assert (x**2).is_polynomial(x) is True assert (x**2).is_polynomial(y) is True assert (x**(-2)).is_polynomial(x) is False assert (x**(-2)).is_polynomial(y) is True assert (2**x).is_polynomial(x) is False assert (2**x).is_polynomial(y) is True assert (x**k).is_polynomial(x) is False assert (x**k).is_polynomial(k) is False assert (x**x).is_polynomial(x) is False assert (k**k).is_polynomial(k) is False assert (k**x).is_polynomial(k) is False assert (x**(-k)).is_polynomial(x) is False assert ((2*x)**k).is_polynomial(x) is False assert (x**2 + 3*x - 8).is_polynomial(x) is True assert (x**2 + 3*x - 8).is_polynomial(y) is True assert (x**2 + 3*x - 8).is_polynomial() is True assert sqrt(x).is_polynomial(x) is False assert (sqrt(x)**3).is_polynomial(x) is False assert (x**2 + 3*x*sqrt(y) - 8).is_polynomial(x) is True assert (x**2 + 3*x*sqrt(y) - 8).is_polynomial(y) is False assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(2)).is_polynomial() is True assert ((x**2)*(y**2) + x*(y**2) + y*x + exp(x)).is_polynomial() is False assert ( (x**2)*(y**2) + x*(y**2) + y*x + exp(2)).is_polynomial(x, y) is True assert ( (x**2)*(y**2) + x*(y**2) + y*x + exp(x)).is_polynomial(x, y) is False def test_is_rational_function(): assert Integer(1).is_rational_function() is True assert Integer(1).is_rational_function(x) is True assert Rational(17, 54).is_rational_function() is True assert Rational(17, 54).is_rational_function(x) is True assert (12/x).is_rational_function() is True assert (12/x).is_rational_function(x) is True assert (x/y).is_rational_function() is True assert (x/y).is_rational_function(x) is True assert (x/y).is_rational_function(x, y) is True assert (x**2 + 1/x/y).is_rational_function() is True assert (x**2 + 1/x/y).is_rational_function(x) is True assert (x**2 + 1/x/y).is_rational_function(x, y) is True assert (sin(y)/x).is_rational_function() is False assert (sin(y)/x).is_rational_function(y) is False assert (sin(y)/x).is_rational_function(x) is True assert (sin(y)/x).is_rational_function(x, y) is False assert (S.NaN).is_rational_function() is False assert (S.Infinity).is_rational_function() is False assert (S.NegativeInfinity).is_rational_function() is False assert (S.ComplexInfinity).is_rational_function() is False def test_is_meromorphic(): f = a/x**2 + b + x + c*x**2 assert f.is_meromorphic(x, 0) is True assert f.is_meromorphic(x, 1) is True assert f.is_meromorphic(x, zoo) is True g = 3 + 2*x**(log(3)/log(2) - 1) assert g.is_meromorphic(x, 0) is False assert g.is_meromorphic(x, 1) is True assert g.is_meromorphic(x, zoo) is False n = Symbol('n', integer=True) h = sin(1/x)**n*x assert h.is_meromorphic(x, 0) is False assert h.is_meromorphic(x, 1) is True assert h.is_meromorphic(x, zoo) is False e = log(x)**pi assert e.is_meromorphic(x, 0) is False assert e.is_meromorphic(x, 1) is False assert e.is_meromorphic(x, 2) is True assert e.is_meromorphic(x, zoo) is False assert (log(x)**a).is_meromorphic(x, 0) is False assert (log(x)**a).is_meromorphic(x, 1) is False assert (a**log(x)).is_meromorphic(x, 0) is None assert (3**log(x)).is_meromorphic(x, 0) is False assert (3**log(x)).is_meromorphic(x, 1) is True def test_is_algebraic_expr(): assert sqrt(3).is_algebraic_expr(x) is True assert sqrt(3).is_algebraic_expr() is True eq = ((1 + x**2)/(1 - y**2))**(S.One/3) assert eq.is_algebraic_expr(x) is True assert eq.is_algebraic_expr(y) is True assert (sqrt(x) + y**(S(2)/3)).is_algebraic_expr(x) is True assert (sqrt(x) + y**(S(2)/3)).is_algebraic_expr(y) is True assert (sqrt(x) + y**(S(2)/3)).is_algebraic_expr() is True assert (cos(y)/sqrt(x)).is_algebraic_expr() is False assert (cos(y)/sqrt(x)).is_algebraic_expr(x) is True assert (cos(y)/sqrt(x)).is_algebraic_expr(y) is False assert (cos(y)/sqrt(x)).is_algebraic_expr(x, y) is False def test_SAGE1(): #see https://github.com/sympy/sympy/issues/3346 class MyInt: def _sympy_(self): return Integer(5) m = MyInt() e = Rational(2)*m assert e == 10 raises(TypeError, lambda: Rational(2)*MyInt) def test_SAGE2(): class MyInt: def __int__(self): return 5 assert sympify(MyInt()) == 5 e = Rational(2)*MyInt() assert e == 10 raises(TypeError, lambda: Rational(2)*MyInt) def test_SAGE3(): class MySymbol: def __rmul__(self, other): return ('mys', other, self) o = MySymbol() e = x*o assert e == ('mys', x, o) def test_len(): e = x*y assert len(e.args) == 2 e = x + y + z assert len(e.args) == 3 def test_doit(): a = Integral(x**2, x) assert isinstance(a.doit(), Integral) is False assert isinstance(a.doit(integrals=True), Integral) is False assert isinstance(a.doit(integrals=False), Integral) is True assert (2*Integral(x, x)).doit() == x**2 def test_attribute_error(): raises(AttributeError, lambda: x.cos()) raises(AttributeError, lambda: x.sin()) raises(AttributeError, lambda: x.exp()) def test_args(): assert (x*y).args in ((x, y), (y, x)) assert (x + y).args in ((x, y), (y, x)) assert (x*y + 1).args in ((x*y, 1), (1, x*y)) assert sin(x*y).args == (x*y,) assert sin(x*y).args[0] == x*y assert (x**y).args == (x, y) assert (x**y).args[0] == x assert (x**y).args[1] == y def test_noncommutative_expand_issue_3757(): A, B, C = symbols('A,B,C', commutative=False) assert A*B - B*A != 0 assert (A*(A + B)*B).expand() == A**2*B + A*B**2 assert (A*(A + B + C)*B).expand() == A**2*B + A*B**2 + A*C*B def test_as_numer_denom(): a, b, c = symbols('a, b, c') assert nan.as_numer_denom() == (nan, 1) assert oo.as_numer_denom() == (oo, 1) assert (-oo).as_numer_denom() == (-oo, 1) assert zoo.as_numer_denom() == (zoo, 1) assert (-zoo).as_numer_denom() == (zoo, 1) assert x.as_numer_denom() == (x, 1) assert (1/x).as_numer_denom() == (1, x) assert (x/y).as_numer_denom() == (x, y) assert (x/2).as_numer_denom() == (x, 2) assert (x*y/z).as_numer_denom() == (x*y, z) assert (x/(y*z)).as_numer_denom() == (x, y*z) assert S.Half.as_numer_denom() == (1, 2) assert (1/y**2).as_numer_denom() == (1, y**2) assert (x/y**2).as_numer_denom() == (x, y**2) assert ((x**2 + 1)/y).as_numer_denom() == (x**2 + 1, y) assert (x*(y + 1)/y**7).as_numer_denom() == (x*(y + 1), y**7) assert (x**-2).as_numer_denom() == (1, x**2) assert (a/x + b/2/x + c/3/x).as_numer_denom() == \ (6*a + 3*b + 2*c, 6*x) assert (a/x + b/2/x + c/3/y).as_numer_denom() == \ (2*c*x + y*(6*a + 3*b), 6*x*y) assert (a/x + b/2/x + c/.5/x).as_numer_denom() == \ (2*a + b + 4.0*c, 2*x) # this should take no more than a few seconds assert int(log(Add(*[Dummy()/i/x for i in range(1, 705)] ).as_numer_denom()[1]/x).n(4)) == 705 for i in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: assert (i + x/3).as_numer_denom() == \ (x + i, 3) assert (S.Infinity + x/3 + y/4).as_numer_denom() == \ (4*x + 3*y + S.Infinity, 12) assert (oo*x + zoo*y).as_numer_denom() == \ (zoo*y + oo*x, 1) A, B, C = symbols('A,B,C', commutative=False) assert (A*B*C**-1).as_numer_denom() == (A*B*C**-1, 1) assert (A*B*C**-1/x).as_numer_denom() == (A*B*C**-1, x) assert (C**-1*A*B).as_numer_denom() == (C**-1*A*B, 1) assert (C**-1*A*B/x).as_numer_denom() == (C**-1*A*B, x) assert ((A*B*C)**-1).as_numer_denom() == ((A*B*C)**-1, 1) assert ((A*B*C)**-1/x).as_numer_denom() == ((A*B*C)**-1, x) def test_trunc(): import math x, y = symbols('x y') assert math.trunc(2) == 2 assert math.trunc(4.57) == 4 assert math.trunc(-5.79) == -5 assert math.trunc(pi) == 3 assert math.trunc(log(7)) == 1 assert math.trunc(exp(5)) == 148 assert math.trunc(cos(pi)) == -1 assert math.trunc(sin(5)) == 0 raises(TypeError, lambda: math.trunc(x)) raises(TypeError, lambda: math.trunc(x + y**2)) raises(TypeError, lambda: math.trunc(oo)) def test_as_independent(): assert S.Zero.as_independent(x, as_Add=True) == (0, 0) assert S.Zero.as_independent(x, as_Add=False) == (0, 0) assert (2*x*sin(x) + y + x).as_independent(x) == (y, x + 2*x*sin(x)) assert (2*x*sin(x) + y + x).as_independent(y) == (x + 2*x*sin(x), y) assert (2*x*sin(x) + y + x).as_independent(x, y) == (0, y + x + 2*x*sin(x)) assert (x*sin(x)*cos(y)).as_independent(x) == (cos(y), x*sin(x)) assert (x*sin(x)*cos(y)).as_independent(y) == (x*sin(x), cos(y)) assert (x*sin(x)*cos(y)).as_independent(x, y) == (1, x*sin(x)*cos(y)) assert (sin(x)).as_independent(x) == (1, sin(x)) assert (sin(x)).as_independent(y) == (sin(x), 1) assert (2*sin(x)).as_independent(x) == (2, sin(x)) assert (2*sin(x)).as_independent(y) == (2*sin(x), 1) # issue 4903 = 1766b n1, n2, n3 = symbols('n1 n2 n3', commutative=False) assert (n1 + n1*n2).as_independent(n2) == (n1, n1*n2) assert (n2*n1 + n1*n2).as_independent(n2) == (0, n1*n2 + n2*n1) assert (n1*n2*n1).as_independent(n2) == (n1, n2*n1) assert (n1*n2*n1).as_independent(n1) == (1, n1*n2*n1) assert (3*x).as_independent(x, as_Add=True) == (0, 3*x) assert (3*x).as_independent(x, as_Add=False) == (3, x) assert (3 + x).as_independent(x, as_Add=True) == (3, x) assert (3 + x).as_independent(x, as_Add=False) == (1, 3 + x) # issue 5479 assert (3*x).as_independent(Symbol) == (3, x) # issue 5648 assert (n1*x*y).as_independent(x) == (n1*y, x) assert ((x + n1)*(x - y)).as_independent(x) == (1, (x + n1)*(x - y)) assert ((x + n1)*(x - y)).as_independent(y) == (x + n1, x - y) assert (DiracDelta(x - n1)*DiracDelta(x - y)).as_independent(x) \ == (1, DiracDelta(x - n1)*DiracDelta(x - y)) assert (x*y*n1*n2*n3).as_independent(n2) == (x*y*n1, n2*n3) assert (x*y*n1*n2*n3).as_independent(n1) == (x*y, n1*n2*n3) assert (x*y*n1*n2*n3).as_independent(n3) == (x*y*n1*n2, n3) assert (DiracDelta(x - n1)*DiracDelta(y - n1)*DiracDelta(x - n2)).as_independent(y) == \ (DiracDelta(x - n1)*DiracDelta(x - n2), DiracDelta(y - n1)) # issue 5784 assert (x + Integral(x, (x, 1, 2))).as_independent(x, strict=True) == \ (Integral(x, (x, 1, 2)), x) eq = Add(x, -x, 2, -3, evaluate=False) assert eq.as_independent(x) == (-1, Add(x, -x, evaluate=False)) eq = Mul(x, 1/x, 2, -3, evaluate=False) eq.as_independent(x) == (-6, Mul(x, 1/x, evaluate=False)) assert (x*y).as_independent(z, as_Add=True) == (x*y, 0) @XFAIL def test_call_2(): # TODO UndefinedFunction does not subclass Expr f = Function('f') assert (2*f)(x) == 2*f(x) def test_replace(): f = log(sin(x)) + tan(sin(x**2)) assert f.replace(sin, cos) == log(cos(x)) + tan(cos(x**2)) assert f.replace( sin, lambda a: sin(2*a)) == log(sin(2*x)) + tan(sin(2*x**2)) a = Wild('a') b = Wild('b') assert f.replace(sin(a), cos(a)) == log(cos(x)) + tan(cos(x**2)) assert f.replace( sin(a), lambda a: sin(2*a)) == log(sin(2*x)) + tan(sin(2*x**2)) # test exact assert (2*x).replace(a*x + b, b - a, exact=True) == 2*x assert (2*x).replace(a*x + b, b - a) == 2*x assert (2*x).replace(a*x + b, b - a, exact=False) == 2/x assert (2*x).replace(a*x + b, lambda a, b: b - a, exact=True) == 2*x assert (2*x).replace(a*x + b, lambda a, b: b - a) == 2*x assert (2*x).replace(a*x + b, lambda a, b: b - a, exact=False) == 2/x g = 2*sin(x**3) assert g.replace( lambda expr: expr.is_Number, lambda expr: expr**2) == 4*sin(x**9) assert cos(x).replace(cos, sin, map=True) == (sin(x), {cos(x): sin(x)}) assert sin(x).replace(cos, sin) == sin(x) cond, func = lambda x: x.is_Mul, lambda x: 2*x assert (x*y).replace(cond, func, map=True) == (2*x*y, {x*y: 2*x*y}) assert (x*(1 + x*y)).replace(cond, func, map=True) == \ (2*x*(2*x*y + 1), {x*(2*x*y + 1): 2*x*(2*x*y + 1), x*y: 2*x*y}) assert (y*sin(x)).replace(sin, lambda expr: sin(expr)/y, map=True) == \ (sin(x), {sin(x): sin(x)/y}) # if not simultaneous then y*sin(x) -> y*sin(x)/y = sin(x) -> sin(x)/y assert (y*sin(x)).replace(sin, lambda expr: sin(expr)/y, simultaneous=False) == sin(x)/y assert (x**2 + O(x**3)).replace(Pow, lambda b, e: b**e/e ) == x**2/2 + O(x**3) assert (x**2 + O(x**3)).replace(Pow, lambda b, e: b**e/e, simultaneous=False) == x**2/2 + O(x**3) assert (x*(x*y + 3)).replace(lambda x: x.is_Mul, lambda x: 2 + x) == \ x*(x*y + 5) + 2 e = (x*y + 1)*(2*x*y + 1) + 1 assert e.replace(cond, func, map=True) == ( 2*((2*x*y + 1)*(4*x*y + 1)) + 1, {2*x*y: 4*x*y, x*y: 2*x*y, (2*x*y + 1)*(4*x*y + 1): 2*((2*x*y + 1)*(4*x*y + 1))}) assert x.replace(x, y) == y assert (x + 1).replace(1, 2) == x + 2 # https://groups.google.com/forum/#!topic/sympy/8wCgeC95tz0 n1, n2, n3 = symbols('n1:4', commutative=False) f = Function('f') assert (n1*f(n2)).replace(f, lambda x: x) == n1*n2 assert (n3*f(n2)).replace(f, lambda x: x) == n3*n2 # issue 16725 assert S.Zero.replace(Wild('x'), 1) == 1 # let the user override the default decision of False assert S.Zero.replace(Wild('x'), 1, exact=True) == 0 def test_find(): expr = (x + y + 2 + sin(3*x)) assert expr.find(lambda u: u.is_Integer) == {S(2), S(3)} assert expr.find(lambda u: u.is_Symbol) == {x, y} assert expr.find(lambda u: u.is_Integer, group=True) == {S(2): 1, S(3): 1} assert expr.find(lambda u: u.is_Symbol, group=True) == {x: 2, y: 1} assert expr.find(Integer) == {S(2), S(3)} assert expr.find(Symbol) == {x, y} assert expr.find(Integer, group=True) == {S(2): 1, S(3): 1} assert expr.find(Symbol, group=True) == {x: 2, y: 1} a = Wild('a') expr = sin(sin(x)) + sin(x) + cos(x) + x assert expr.find(lambda u: type(u) is sin) == {sin(x), sin(sin(x))} assert expr.find( lambda u: type(u) is sin, group=True) == {sin(x): 2, sin(sin(x)): 1} assert expr.find(sin(a)) == {sin(x), sin(sin(x))} assert expr.find(sin(a), group=True) == {sin(x): 2, sin(sin(x)): 1} assert expr.find(sin) == {sin(x), sin(sin(x))} assert expr.find(sin, group=True) == {sin(x): 2, sin(sin(x)): 1} def test_count(): expr = (x + y + 2 + sin(3*x)) assert expr.count(lambda u: u.is_Integer) == 2 assert expr.count(lambda u: u.is_Symbol) == 3 assert expr.count(Integer) == 2 assert expr.count(Symbol) == 3 assert expr.count(2) == 1 a = Wild('a') assert expr.count(sin) == 1 assert expr.count(sin(a)) == 1 assert expr.count(lambda u: type(u) is sin) == 1 f = Function('f') assert f(x).count(f(x)) == 1 assert f(x).diff(x).count(f(x)) == 1 assert f(x).diff(x).count(x) == 2 def test_has_basics(): f = Function('f') g = Function('g') p = Wild('p') assert sin(x).has(x) assert sin(x).has(sin) assert not sin(x).has(y) assert not sin(x).has(cos) assert f(x).has(x) assert f(x).has(f) assert not f(x).has(y) assert not f(x).has(g) assert f(x).diff(x).has(x) assert f(x).diff(x).has(f) assert f(x).diff(x).has(Derivative) assert not f(x).diff(x).has(y) assert not f(x).diff(x).has(g) assert not f(x).diff(x).has(sin) assert (x**2).has(Symbol) assert not (x**2).has(Wild) assert (2*p).has(Wild) assert not x.has() def test_has_multiple(): f = x**2*y + sin(2**t + log(z)) assert f.has(x) assert f.has(y) assert f.has(z) assert f.has(t) assert not f.has(u) assert f.has(x, y, z, t) assert f.has(x, y, z, t, u) i = Integer(4400) assert not i.has(x) assert (i*x**i).has(x) assert not (i*y**i).has(x) assert (i*y**i).has(x, y) assert not (i*y**i).has(x, z) def test_has_piecewise(): f = (x*y + 3/y)**(3 + 2) g = Function('g') h = Function('h') p = Piecewise((g(x), x < -1), (1, x <= 1), (f, True)) assert p.has(x) assert p.has(y) assert not p.has(z) assert p.has(1) assert p.has(3) assert not p.has(4) assert p.has(f) assert p.has(g) assert not p.has(h) def test_has_iterative(): A, B, C = symbols('A,B,C', commutative=False) f = x*gamma(x)*sin(x)*exp(x*y)*A*B*C*cos(x*A*B) assert f.has(x) assert f.has(x*y) assert f.has(x*sin(x)) assert not f.has(x*sin(y)) assert f.has(x*A) assert f.has(x*A*B) assert not f.has(x*A*C) assert f.has(x*A*B*C) assert not f.has(x*A*C*B) assert f.has(x*sin(x)*A*B*C) assert not f.has(x*sin(x)*A*C*B) assert not f.has(x*sin(y)*A*B*C) assert f.has(x*gamma(x)) assert not f.has(x + sin(x)) assert (x & y & z).has(x & z) def test_has_integrals(): f = Integral(x**2 + sin(x*y*z), (x, 0, x + y + z)) assert f.has(x + y) assert f.has(x + z) assert f.has(y + z) assert f.has(x*y) assert f.has(x*z) assert f.has(y*z) assert not f.has(2*x + y) assert not f.has(2*x*y) def test_has_tuple(): f = Function('f') g = Function('g') h = Function('h') assert Tuple(x, y).has(x) assert not Tuple(x, y).has(z) assert Tuple(f(x), g(x)).has(x) assert not Tuple(f(x), g(x)).has(y) assert Tuple(f(x), g(x)).has(f) assert Tuple(f(x), g(x)).has(f(x)) assert not Tuple(f, g).has(x) assert Tuple(f, g).has(f) assert not Tuple(f, g).has(h) assert Tuple(True).has(True) is True # .has(1) will also be True def test_has_units(): from sympy.physics.units import m, s assert (x*m/s).has(x) assert (x*m/s).has(y, z) is False def test_has_polys(): poly = Poly(x**2 + x*y*sin(z), x, y, t) assert poly.has(x) assert poly.has(x, y, z) assert poly.has(x, y, z, t) def test_has_physics(): assert FockState((x, y)).has(x) def test_as_poly_as_expr(): f = x**2 + 2*x*y assert f.as_poly().as_expr() == f assert f.as_poly(x, y).as_expr() == f assert (f + sin(x)).as_poly(x, y) is None p = Poly(f, x, y) assert p.as_poly() == p raises(AttributeError, lambda: Tuple(x, x).as_poly(x)) raises(AttributeError, lambda: Tuple(x ** 2, x, y).as_poly(x)) def test_nonzero(): assert bool(S.Zero) is False assert bool(S.One) is True assert bool(x) is True assert bool(x + y) is True assert bool(x - x) is False assert bool(x*y) is True assert bool(x*1) is True assert bool(x*0) is False def test_is_number(): assert Float(3.14).is_number is True assert Integer(737).is_number is True assert Rational(3, 2).is_number is True assert Rational(8).is_number is True assert x.is_number is False assert (2*x).is_number is False assert (x + y).is_number is False assert log(2).is_number is True assert log(x).is_number is False assert (2 + log(2)).is_number is True assert (8 + log(2)).is_number is True assert (2 + log(x)).is_number is False assert (8 + log(2) + x).is_number is False assert (1 + x**2/x - x).is_number is True assert Tuple(Integer(1)).is_number is False assert Add(2, x).is_number is False assert Mul(3, 4).is_number is True assert Pow(log(2), 2).is_number is True assert oo.is_number is True g = WildFunction('g') assert g.is_number is False assert (2*g).is_number is False assert (x**2).subs(x, 3).is_number is True # test extensibility of .is_number # on subinstances of Basic class A(Basic): pass a = A() assert a.is_number is False def test_as_coeff_add(): assert S(2).as_coeff_add() == (2, ()) assert S(3.0).as_coeff_add() == (0, (S(3.0),)) assert S(-3.0).as_coeff_add() == (0, (S(-3.0),)) assert x.as_coeff_add() == (0, (x,)) assert (x - 1).as_coeff_add() == (-1, (x,)) assert (x + 1).as_coeff_add() == (1, (x,)) assert (x + 2).as_coeff_add() == (2, (x,)) assert (x + y).as_coeff_add(y) == (x, (y,)) assert (3*x).as_coeff_add(y) == (3*x, ()) # don't do expansion e = (x + y)**2 assert e.as_coeff_add(y) == (0, (e,)) def test_as_coeff_mul(): assert S(2).as_coeff_mul() == (2, ()) assert S(3.0).as_coeff_mul() == (1, (S(3.0),)) assert S(-3.0).as_coeff_mul() == (-1, (S(3.0),)) assert S(-3.0).as_coeff_mul(rational=False) == (-S(3.0), ()) assert x.as_coeff_mul() == (1, (x,)) assert (-x).as_coeff_mul() == (-1, (x,)) assert (2*x).as_coeff_mul() == (2, (x,)) assert (x*y).as_coeff_mul(y) == (x, (y,)) assert (3 + x).as_coeff_mul() == (1, (3 + x,)) assert (3 + x).as_coeff_mul(y) == (3 + x, ()) # don't do expansion e = exp(x + y) assert e.as_coeff_mul(y) == (1, (e,)) e = 2**(x + y) assert e.as_coeff_mul(y) == (1, (e,)) assert (1.1*x).as_coeff_mul(rational=False) == (1.1, (x,)) assert (1.1*x).as_coeff_mul() == (1, (1.1, x)) assert (-oo*x).as_coeff_mul(rational=True) == (-1, (oo, x)) def test_as_coeff_exponent(): assert (3*x**4).as_coeff_exponent(x) == (3, 4) assert (2*x**3).as_coeff_exponent(x) == (2, 3) assert (4*x**2).as_coeff_exponent(x) == (4, 2) assert (6*x**1).as_coeff_exponent(x) == (6, 1) assert (3*x**0).as_coeff_exponent(x) == (3, 0) assert (2*x**0).as_coeff_exponent(x) == (2, 0) assert (1*x**0).as_coeff_exponent(x) == (1, 0) assert (0*x**0).as_coeff_exponent(x) == (0, 0) assert (-1*x**0).as_coeff_exponent(x) == (-1, 0) assert (-2*x**0).as_coeff_exponent(x) == (-2, 0) assert (2*x**3 + pi*x**3).as_coeff_exponent(x) == (2 + pi, 3) assert (x*log(2)/(2*x + pi*x)).as_coeff_exponent(x) == \ (log(2)/(2 + pi), 0) # issue 4784 D = Derivative f = Function('f') fx = D(f(x), x) assert fx.as_coeff_exponent(f(x)) == (fx, 0) def test_extractions(): assert ((x*y)**3).extract_multiplicatively(x**2 * y) == x*y**2 assert ((x*y)**3).extract_multiplicatively(x**4 * y) is None assert (2*x).extract_multiplicatively(2) == x assert (2*x).extract_multiplicatively(3) is None assert (2*x).extract_multiplicatively(-1) is None assert (S.Half*x).extract_multiplicatively(3) == x/6 assert (sqrt(x)).extract_multiplicatively(x) is None assert (sqrt(x)).extract_multiplicatively(1/x) is None assert x.extract_multiplicatively(-x) is None assert (-2 - 4*I).extract_multiplicatively(-2) == 1 + 2*I assert (-2 - 4*I).extract_multiplicatively(3) is None assert (-2*x - 4*y - 8).extract_multiplicatively(-2) == x + 2*y + 4 assert (-2*x*y - 4*x**2*y).extract_multiplicatively(-2*y) == 2*x**2 + x assert (2*x*y + 4*x**2*y).extract_multiplicatively(2*y) == 2*x**2 + x assert (-4*y**2*x).extract_multiplicatively(-3*y) is None assert (2*x).extract_multiplicatively(1) == 2*x assert (-oo).extract_multiplicatively(5) is -oo assert (oo).extract_multiplicatively(5) is oo assert ((x*y)**3).extract_additively(1) is None assert (x + 1).extract_additively(x) == 1 assert (x + 1).extract_additively(2*x) is None assert (x + 1).extract_additively(-x) is None assert (-x + 1).extract_additively(2*x) is None assert (2*x + 3).extract_additively(x) == x + 3 assert (2*x + 3).extract_additively(2) == 2*x + 1 assert (2*x + 3).extract_additively(3) == 2*x assert (2*x + 3).extract_additively(-2) is None assert (2*x + 3).extract_additively(3*x) is None assert (2*x + 3).extract_additively(2*x) == 3 assert x.extract_additively(0) == x assert S(2).extract_additively(x) is None assert S(2.).extract_additively(2) is S.Zero assert S(2*x + 3).extract_additively(x + 1) == x + 2 assert S(2*x + 3).extract_additively(y + 1) is None assert S(2*x - 3).extract_additively(x + 1) is None assert S(2*x - 3).extract_additively(y + z) is None assert ((a + 1)*x*4 + y).extract_additively(x).expand() == \ 4*a*x + 3*x + y assert ((a + 1)*x*4 + 3*y).extract_additively(x + 2*y).expand() == \ 4*a*x + 3*x + y assert (y*(x + 1)).extract_additively(x + 1) is None assert ((y + 1)*(x + 1) + 3).extract_additively(x + 1) == \ y*(x + 1) + 3 assert ((x + y)*(x + 1) + x + y + 3).extract_additively(x + y) == \ x*(x + y) + 3 assert (x + y + 2*((x + y)*(x + 1)) + 3).extract_additively((x + y)*(x + 1)) == \ x + y + (x + 1)*(x + y) + 3 assert ((y + 1)*(x + 2*y + 1) + 3).extract_additively(y + 1) == \ (x + 2*y)*(y + 1) + 3 n = Symbol("n", integer=True) assert (Integer(-3)).could_extract_minus_sign() is True assert (-n*x + x).could_extract_minus_sign() != \ (n*x - x).could_extract_minus_sign() assert (x - y).could_extract_minus_sign() != \ (-x + y).could_extract_minus_sign() assert (1 - x - y).could_extract_minus_sign() is True assert (1 - x + y).could_extract_minus_sign() is False assert ((-x - x*y)/y).could_extract_minus_sign() is True assert (-(x + x*y)/y).could_extract_minus_sign() is True assert ((x + x*y)/(-y)).could_extract_minus_sign() is True assert ((x + x*y)/y).could_extract_minus_sign() is False assert (x*(-x - x**3)).could_extract_minus_sign() is True assert ((-x - y)/(x + y)).could_extract_minus_sign() is True class sign_invariant(Function, Expr): nargs = 1 def __neg__(self): return self foo = sign_invariant(x) assert foo == -foo assert foo.could_extract_minus_sign() is False # The results of each of these will vary on different machines, e.g. # the first one might be False and the other (then) is true or vice versa, # so both are included. assert ((-x - y)/(x - y)).could_extract_minus_sign() is False or \ ((-x - y)/(y - x)).could_extract_minus_sign() is False assert (x - y).could_extract_minus_sign() is False assert (-x + y).could_extract_minus_sign() is True # check that result is canonical eq = (3*x + 15*y).extract_multiplicatively(3) assert eq.args == eq.func(*eq.args).args def test_nan_extractions(): for r in (1, 0, I, nan): assert nan.extract_additively(r) is None assert nan.extract_multiplicatively(r) is None def test_coeff(): assert (x + 1).coeff(x + 1) == 1 assert (3*x).coeff(0) == 0 assert (z*(1 + x)*x**2).coeff(1 + x) == z*x**2 assert (1 + 2*x*x**(1 + x)).coeff(x*x**(1 + x)) == 2 assert (1 + 2*x**(y + z)).coeff(x**(y + z)) == 2 assert (3 + 2*x + 4*x**2).coeff(1) == 0 assert (3 + 2*x + 4*x**2).coeff(-1) == 0 assert (3 + 2*x + 4*x**2).coeff(x) == 2 assert (3 + 2*x + 4*x**2).coeff(x**2) == 4 assert (3 + 2*x + 4*x**2).coeff(x**3) == 0 assert (-x/8 + x*y).coeff(x) == Rational(-1, 8) + y assert (-x/8 + x*y).coeff(-x) == S.One/8 assert (4*x).coeff(2*x) == 0 assert (2*x).coeff(2*x) == 1 assert (-oo*x).coeff(x*oo) == -1 assert (10*x).coeff(x, 0) == 0 assert (10*x).coeff(10*x, 0) == 0 n1, n2 = symbols('n1 n2', commutative=False) assert (n1*n2).coeff(n1) == 1 assert (n1*n2).coeff(n2) == n1 assert (n1*n2 + x*n1).coeff(n1) == 1 # 1*n1*(n2+x) assert (n2*n1 + x*n1).coeff(n1) == n2 + x assert (n2*n1 + x*n1**2).coeff(n1) == n2 assert (n1**x).coeff(n1) == 0 assert (n1*n2 + n2*n1).coeff(n1) == 0 assert (2*(n1 + n2)*n2).coeff(n1 + n2, right=1) == n2 assert (2*(n1 + n2)*n2).coeff(n1 + n2, right=0) == 2 f = Function('f') assert (2*f(x) + 3*f(x).diff(x)).coeff(f(x)) == 2 expr = z*(x + y)**2 expr2 = z*(x + y)**2 + z*(2*x + 2*y)**2 assert expr.coeff(z) == (x + y)**2 assert expr.coeff(x + y) == 0 assert expr2.coeff(z) == (x + y)**2 + (2*x + 2*y)**2 assert (x + y + 3*z).coeff(1) == x + y assert (-x + 2*y).coeff(-1) == x assert (x - 2*y).coeff(-1) == 2*y assert (3 + 2*x + 4*x**2).coeff(1) == 0 assert (-x - 2*y).coeff(2) == -y assert (x + sqrt(2)*x).coeff(sqrt(2)) == x assert (3 + 2*x + 4*x**2).coeff(x) == 2 assert (3 + 2*x + 4*x**2).coeff(x**2) == 4 assert (3 + 2*x + 4*x**2).coeff(x**3) == 0 assert (z*(x + y)**2).coeff((x + y)**2) == z assert (z*(x + y)**2).coeff(x + y) == 0 assert (2 + 2*x + (x + 1)*y).coeff(x + 1) == y assert (x + 2*y + 3).coeff(1) == x assert (x + 2*y + 3).coeff(x, 0) == 2*y + 3 assert (x**2 + 2*y + 3*x).coeff(x**2, 0) == 2*y + 3*x assert x.coeff(0, 0) == 0 assert x.coeff(x, 0) == 0 n, m, o, l = symbols('n m o l', commutative=False) assert n.coeff(n) == 1 assert y.coeff(n) == 0 assert (3*n).coeff(n) == 3 assert (2 + n).coeff(x*m) == 0 assert (2*x*n*m).coeff(x) == 2*n*m assert (2 + n).coeff(x*m*n + y) == 0 assert (2*x*n*m).coeff(3*n) == 0 assert (n*m + m*n*m).coeff(n) == 1 + m assert (n*m + m*n*m).coeff(n, right=True) == m # = (1 + m)*n*m assert (n*m + m*n).coeff(n) == 0 assert (n*m + o*m*n).coeff(m*n) == o assert (n*m + o*m*n).coeff(m*n, right=1) == 1 assert (n*m + n*m*n).coeff(n*m, right=1) == 1 + n # = n*m*(n + 1) assert (x*y).coeff(z, 0) == x*y def test_coeff2(): r, kappa = symbols('r, kappa') psi = Function("psi") g = 1/r**2 * (2*r*psi(r).diff(r, 1) + r**2 * psi(r).diff(r, 2)) g = g.expand() assert g.coeff(psi(r).diff(r)) == 2/r def test_coeff2_0(): r, kappa = symbols('r, kappa') psi = Function("psi") g = 1/r**2 * (2*r*psi(r).diff(r, 1) + r**2 * psi(r).diff(r, 2)) g = g.expand() assert g.coeff(psi(r).diff(r, 2)) == 1 def test_coeff_expand(): expr = z*(x + y)**2 expr2 = z*(x + y)**2 + z*(2*x + 2*y)**2 assert expr.coeff(z) == (x + y)**2 assert expr2.coeff(z) == (x + y)**2 + (2*x + 2*y)**2 def test_integrate(): assert x.integrate(x) == x**2/2 assert x.integrate((x, 0, 1)) == S.Half def test_as_base_exp(): assert x.as_base_exp() == (x, S.One) assert (x*y*z).as_base_exp() == (x*y*z, S.One) assert (x + y + z).as_base_exp() == (x + y + z, S.One) assert ((x + y)**z).as_base_exp() == (x + y, z) def test_issue_4963(): assert hasattr(Mul(x, y), "is_commutative") assert hasattr(Mul(x, y, evaluate=False), "is_commutative") assert hasattr(Pow(x, y), "is_commutative") assert hasattr(Pow(x, y, evaluate=False), "is_commutative") expr = Mul(Pow(2, 2, evaluate=False), 3, evaluate=False) + 1 assert hasattr(expr, "is_commutative") def test_action_verbs(): assert nsimplify(1/(exp(3*pi*x/5) + 1)) == \ (1/(exp(3*pi*x/5) + 1)).nsimplify() assert ratsimp(1/x + 1/y) == (1/x + 1/y).ratsimp() assert trigsimp(log(x), deep=True) == (log(x)).trigsimp(deep=True) assert radsimp(1/(2 + sqrt(2))) == (1/(2 + sqrt(2))).radsimp() assert radsimp(1/(a + b*sqrt(c)), symbolic=False) == \ (1/(a + b*sqrt(c))).radsimp(symbolic=False) assert powsimp(x**y*x**z*y**z, combine='all') == \ (x**y*x**z*y**z).powsimp(combine='all') assert (x**t*y**t).powsimp(force=True) == (x*y)**t assert simplify(x**y*x**z*y**z) == (x**y*x**z*y**z).simplify() assert together(1/x + 1/y) == (1/x + 1/y).together() assert collect(a*x**2 + b*x**2 + a*x - b*x + c, x) == \ (a*x**2 + b*x**2 + a*x - b*x + c).collect(x) assert apart(y/(y + 2)/(y + 1), y) == (y/(y + 2)/(y + 1)).apart(y) assert combsimp(y/(x + 2)/(x + 1)) == (y/(x + 2)/(x + 1)).combsimp() assert gammasimp(gamma(x)/gamma(x-5)) == (gamma(x)/gamma(x-5)).gammasimp() assert factor(x**2 + 5*x + 6) == (x**2 + 5*x + 6).factor() assert refine(sqrt(x**2)) == sqrt(x**2).refine() assert cancel((x**2 + 5*x + 6)/(x + 2)) == ((x**2 + 5*x + 6)/(x + 2)).cancel() def test_as_powers_dict(): assert x.as_powers_dict() == {x: 1} assert (x**y*z).as_powers_dict() == {x: y, z: 1} assert Mul(2, 2, evaluate=False).as_powers_dict() == {S(2): S(2)} assert (x*y).as_powers_dict()[z] == 0 assert (x + y).as_powers_dict()[z] == 0 def test_as_coefficients_dict(): check = [S.One, x, y, x*y, 1] assert [Add(3*x, 2*x, y, 3).as_coefficients_dict()[i] for i in check] == \ [3, 5, 1, 0, 3] assert [Add(3*x, 2*x, y, 3, evaluate=False).as_coefficients_dict()[i] for i in check] == [3, 5, 1, 0, 3] assert [(3*x*y).as_coefficients_dict()[i] for i in check] == \ [0, 0, 0, 3, 0] assert [(3.0*x*y).as_coefficients_dict()[i] for i in check] == \ [0, 0, 0, 3.0, 0] assert (3.0*x*y).as_coefficients_dict()[3.0*x*y] == 0 def test_args_cnc(): A = symbols('A', commutative=False) assert (x + A).args_cnc() == \ [[], [x + A]] assert (x + a).args_cnc() == \ [[a + x], []] assert (x*a).args_cnc() == \ [[a, x], []] assert (x*y*A*(A + 1)).args_cnc(cset=True) == \ [{x, y}, [A, 1 + A]] assert Mul(x, x, evaluate=False).args_cnc(cset=True, warn=False) == \ [{x}, []] assert Mul(x, x**2, evaluate=False).args_cnc(cset=True, warn=False) == \ [{x, x**2}, []] raises(ValueError, lambda: Mul(x, x, evaluate=False).args_cnc(cset=True)) assert Mul(x, y, x, evaluate=False).args_cnc() == \ [[x, y, x], []] # always split -1 from leading number assert (-1.*x).args_cnc() == [[-1, 1.0, x], []] def test_new_rawargs(): n = Symbol('n', commutative=False) a = x + n assert a.is_commutative is False assert a._new_rawargs(x).is_commutative assert a._new_rawargs(x, y).is_commutative assert a._new_rawargs(x, n).is_commutative is False assert a._new_rawargs(x, y, n).is_commutative is False m = x*n assert m.is_commutative is False assert m._new_rawargs(x).is_commutative assert m._new_rawargs(n).is_commutative is False assert m._new_rawargs(x, y).is_commutative assert m._new_rawargs(x, n).is_commutative is False assert m._new_rawargs(x, y, n).is_commutative is False assert m._new_rawargs(x, n, reeval=False).is_commutative is False assert m._new_rawargs(S.One) is S.One def test_issue_5226(): assert Add(evaluate=False) == 0 assert Mul(evaluate=False) == 1 assert Mul(x + y, evaluate=False).is_Add def test_free_symbols(): # free_symbols should return the free symbols of an object assert S.One.free_symbols == set() assert x.free_symbols == {x} assert Integral(x, (x, 1, y)).free_symbols == {y} assert (-Integral(x, (x, 1, y))).free_symbols == {y} assert meter.free_symbols == set() assert (meter**x).free_symbols == {x} def test_issue_5300(): x = Symbol('x', commutative=False) assert x*sqrt(2)/sqrt(6) == x*sqrt(3)/3 def test_floordiv(): from sympy.functions.elementary.integers import floor assert x // y == floor(x / y) def test_as_coeff_Mul(): assert S.Zero.as_coeff_Mul() == (S.One, S.Zero) assert Integer(3).as_coeff_Mul() == (Integer(3), Integer(1)) assert Rational(3, 4).as_coeff_Mul() == (Rational(3, 4), Integer(1)) assert Float(5.0).as_coeff_Mul() == (Float(5.0), Integer(1)) assert (Integer(3)*x).as_coeff_Mul() == (Integer(3), x) assert (Rational(3, 4)*x).as_coeff_Mul() == (Rational(3, 4), x) assert (Float(5.0)*x).as_coeff_Mul() == (Float(5.0), x) assert (Integer(3)*x*y).as_coeff_Mul() == (Integer(3), x*y) assert (Rational(3, 4)*x*y).as_coeff_Mul() == (Rational(3, 4), x*y) assert (Float(5.0)*x*y).as_coeff_Mul() == (Float(5.0), x*y) assert (x).as_coeff_Mul() == (S.One, x) assert (x*y).as_coeff_Mul() == (S.One, x*y) assert (-oo*x).as_coeff_Mul(rational=True) == (-1, oo*x) def test_as_coeff_Add(): assert Integer(3).as_coeff_Add() == (Integer(3), Integer(0)) assert Rational(3, 4).as_coeff_Add() == (Rational(3, 4), Integer(0)) assert Float(5.0).as_coeff_Add() == (Float(5.0), Integer(0)) assert (Integer(3) + x).as_coeff_Add() == (Integer(3), x) assert (Rational(3, 4) + x).as_coeff_Add() == (Rational(3, 4), x) assert (Float(5.0) + x).as_coeff_Add() == (Float(5.0), x) assert (Float(5.0) + x).as_coeff_Add(rational=True) == (0, Float(5.0) + x) assert (Integer(3) + x + y).as_coeff_Add() == (Integer(3), x + y) assert (Rational(3, 4) + x + y).as_coeff_Add() == (Rational(3, 4), x + y) assert (Float(5.0) + x + y).as_coeff_Add() == (Float(5.0), x + y) assert (x).as_coeff_Add() == (S.Zero, x) assert (x*y).as_coeff_Add() == (S.Zero, x*y) def test_expr_sorting(): f, g = symbols('f,g', cls=Function) exprs = [1/x**2, 1/x, sqrt(sqrt(x)), sqrt(x), x, sqrt(x)**3, x**2] assert sorted(exprs, key=default_sort_key) == exprs exprs = [x, 2*x, 2*x**2, 2*x**3, x**n, 2*x**n, sin(x), sin(x)**n, sin(x**2), cos(x), cos(x**2), tan(x)] assert sorted(exprs, key=default_sort_key) == exprs exprs = [x + 1, x**2 + x + 1, x**3 + x**2 + x + 1] assert sorted(exprs, key=default_sort_key) == exprs exprs = [S(4), x - 3*I/2, x + 3*I/2, x - 4*I + 1, x + 4*I + 1] assert sorted(exprs, key=default_sort_key) == exprs exprs = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] assert sorted(exprs, key=default_sort_key) == exprs exprs = [f(x), g(x), exp(x), sin(x), cos(x), factorial(x)] assert sorted(exprs, key=default_sort_key) == exprs exprs = [Tuple(x, y), Tuple(x, z), Tuple(x, y, z)] assert sorted(exprs, key=default_sort_key) == exprs exprs = [[3], [1, 2]] assert sorted(exprs, key=default_sort_key) == exprs exprs = [[1, 2], [2, 3]] assert sorted(exprs, key=default_sort_key) == exprs exprs = [[1, 2], [1, 2, 3]] assert sorted(exprs, key=default_sort_key) == exprs exprs = [{x: -y}, {x: y}] assert sorted(exprs, key=default_sort_key) == exprs exprs = [{1}, {1, 2}] assert sorted(exprs, key=default_sort_key) == exprs a, b = exprs = [Dummy('x'), Dummy('x')] assert sorted([b, a], key=default_sort_key) == exprs def test_as_ordered_factors(): f, g = symbols('f,g', cls=Function) assert x.as_ordered_factors() == [x] assert (2*x*x**n*sin(x)*cos(x)).as_ordered_factors() \ == [Integer(2), x, x**n, sin(x), cos(x)] args = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] expr = Mul(*args) assert expr.as_ordered_factors() == args A, B = symbols('A,B', commutative=False) assert (A*B).as_ordered_factors() == [A, B] assert (B*A).as_ordered_factors() == [B, A] def test_as_ordered_terms(): f, g = symbols('f,g', cls=Function) assert x.as_ordered_terms() == [x] assert (sin(x)**2*cos(x) + sin(x)*cos(x)**2 + 1).as_ordered_terms() \ == [sin(x)**2*cos(x), sin(x)*cos(x)**2, 1] args = [f(1), f(2), f(3), f(1, 2, 3), g(1), g(2), g(3), g(1, 2, 3)] expr = Add(*args) assert expr.as_ordered_terms() == args assert (1 + 4*sqrt(3)*pi*x).as_ordered_terms() == [4*pi*x*sqrt(3), 1] assert ( 2 + 3*I).as_ordered_terms() == [2, 3*I] assert (-2 + 3*I).as_ordered_terms() == [-2, 3*I] assert ( 2 - 3*I).as_ordered_terms() == [2, -3*I] assert (-2 - 3*I).as_ordered_terms() == [-2, -3*I] assert ( 4 + 3*I).as_ordered_terms() == [4, 3*I] assert (-4 + 3*I).as_ordered_terms() == [-4, 3*I] assert ( 4 - 3*I).as_ordered_terms() == [4, -3*I] assert (-4 - 3*I).as_ordered_terms() == [-4, -3*I] f = x**2*y**2 + x*y**4 + y + 2 assert f.as_ordered_terms(order="lex") == [x**2*y**2, x*y**4, y, 2] assert f.as_ordered_terms(order="grlex") == [x*y**4, x**2*y**2, y, 2] assert f.as_ordered_terms(order="rev-lex") == [2, y, x*y**4, x**2*y**2] assert f.as_ordered_terms(order="rev-grlex") == [2, y, x**2*y**2, x*y**4] k = symbols('k') assert k.as_ordered_terms(data=True) == ([(k, ((1.0, 0.0), (1,), ()))], [k]) def test_sort_key_atomic_expr(): from sympy.physics.units import m, s assert sorted([-m, s], key=lambda arg: arg.sort_key()) == [-m, s] def test_eval_interval(): assert exp(x)._eval_interval(*Tuple(x, 0, 1)) == exp(1) - exp(0) # issue 4199 a = x/y raises(NotImplementedError, lambda: a._eval_interval(x, S.Zero, oo)._eval_interval(y, oo, S.Zero)) raises(NotImplementedError, lambda: a._eval_interval(x, S.Zero, oo)._eval_interval(y, S.Zero, oo)) a = x - y raises(NotImplementedError, lambda: a._eval_interval(x, S.One, oo)._eval_interval(y, oo, S.One)) raises(ValueError, lambda: x._eval_interval(x, None, None)) a = -y*Heaviside(x - y) assert a._eval_interval(x, -oo, oo) == -y assert a._eval_interval(x, oo, -oo) == y def test_eval_interval_zoo(): # Test that limit is used when zoo is returned assert Si(1/x)._eval_interval(x, S.Zero, S.One) == -pi/2 + Si(1) def test_primitive(): assert (3*(x + 1)**2).primitive() == (3, (x + 1)**2) assert (6*x + 2).primitive() == (2, 3*x + 1) assert (x/2 + 3).primitive() == (S.Half, x + 6) eq = (6*x + 2)*(x/2 + 3) assert eq.primitive()[0] == 1 eq = (2 + 2*x)**2 assert eq.primitive()[0] == 1 assert (4.0*x).primitive() == (1, 4.0*x) assert (4.0*x + y/2).primitive() == (S.Half, 8.0*x + y) assert (-2*x).primitive() == (2, -x) assert Add(5*z/7, 0.5*x, 3*y/2, evaluate=False).primitive() == \ (S.One/14, 7.0*x + 21*y + 10*z) for i in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: assert (i + x/3).primitive() == \ (S.One/3, i + x) assert (S.Infinity + 2*x/3 + 4*y/7).primitive() == \ (S.One/21, 14*x + 12*y + oo) assert S.Zero.primitive() == (S.One, S.Zero) def test_issue_5843(): a = 1 + x assert (2*a).extract_multiplicatively(a) == 2 assert (4*a).extract_multiplicatively(2*a) == 2 assert ((3*a)*(2*a)).extract_multiplicatively(a) == 6*a def test_is_constant(): from sympy.solvers.solvers import checksol Sum(x, (x, 1, 10)).is_constant() is True Sum(x, (x, 1, n)).is_constant() is False Sum(x, (x, 1, n)).is_constant(y) is True Sum(x, (x, 1, n)).is_constant(n) is False Sum(x, (x, 1, n)).is_constant(x) is True eq = a*cos(x)**2 + a*sin(x)**2 - a eq.is_constant() is True assert eq.subs({x: pi, a: 2}) == eq.subs({x: pi, a: 3}) == 0 assert x.is_constant() is False assert x.is_constant(y) is True assert checksol(x, x, Sum(x, (x, 1, n))) is False assert checksol(x, x, Sum(x, (x, 1, n))) is False f = Function('f') assert f(1).is_constant assert checksol(x, x, f(x)) is False assert Pow(x, S.Zero, evaluate=False).is_constant() is True # == 1 assert Pow(S.Zero, x, evaluate=False).is_constant() is False # == 0 or 1 assert (2**x).is_constant() is False assert Pow(S(2), S(3), evaluate=False).is_constant() is True z1, z2 = symbols('z1 z2', zero=True) assert (z1 + 2*z2).is_constant() is True assert meter.is_constant() is True assert (3*meter).is_constant() is True assert (x*meter).is_constant() is False def test_equals(): assert (-3 - sqrt(5) + (-sqrt(10)/2 - sqrt(2)/2)**2).equals(0) assert (x**2 - 1).equals((x + 1)*(x - 1)) assert (cos(x)**2 + sin(x)**2).equals(1) assert (a*cos(x)**2 + a*sin(x)**2).equals(a) r = sqrt(2) assert (-1/(r + r*x) + 1/r/(1 + x)).equals(0) assert factorial(x + 1).equals((x + 1)*factorial(x)) assert sqrt(3).equals(2*sqrt(3)) is False assert (sqrt(5)*sqrt(3)).equals(sqrt(3)) is False assert (sqrt(5) + sqrt(3)).equals(0) is False assert (sqrt(5) + pi).equals(0) is False assert meter.equals(0) is False assert (3*meter**2).equals(0) is False eq = -(-1)**(S(3)/4)*6**(S.One/4) + (-6)**(S.One/4)*I if eq != 0: # if canonicalization makes this zero, skip the test assert eq.equals(0) assert sqrt(x).equals(0) is False # from integrate(x*sqrt(1 + 2*x), x); # diff is zero only when assumptions allow i = 2*sqrt(2)*x**(S(5)/2)*(1 + 1/(2*x))**(S(5)/2)/5 + \ 2*sqrt(2)*x**(S(3)/2)*(1 + 1/(2*x))**(S(5)/2)/(-6 - 3/x) ans = sqrt(2*x + 1)*(6*x**2 + x - 1)/15 diff = i - ans assert diff.equals(0) is False assert diff.subs(x, Rational(-1, 2)/2) == 7*sqrt(2)/120 # there are regions for x for which the expression is True, for # example, when x < -1/2 or x > 0 the expression is zero p = Symbol('p', positive=True) assert diff.subs(x, p).equals(0) is True assert diff.subs(x, -1).equals(0) is True # prove via minimal_polynomial or self-consistency eq = sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) - sqrt(10 + 6*sqrt(3)) assert eq.equals(0) q = 3**Rational(1, 3) + 3 p = expand(q**3)**Rational(1, 3) assert (p - q).equals(0) # issue 6829 # eq = q*x + q/4 + x**4 + x**3 + 2*x**2 - S.One/3 # z = eq.subs(x, solve(eq, x)[0]) q = symbols('q') z = (q*(-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12)/2 - sqrt((2*q - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/6)/2 - S.One/4) + q/4 + (-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12)/2 - sqrt((2*q - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/6)/2 - S.One/4)**4 + (-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12)/2 - sqrt((2*q - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/6)/2 - S.One/4)**3 + 2*(-sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12)/2 - sqrt((2*q - S(7)/4)/sqrt(-2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/12) + 2*(-(q - S(7)/8)**S(2)/8 - S(2197)/13824)**(S.One/3) - S(13)/6)/2 - S.One/4)**2 - Rational(1, 3)) assert z.equals(0) def test_random(): from sympy import posify, lucas assert posify(x)[0]._random() is not None assert lucas(n)._random(2, -2, 0, -1, 1) is None # issue 8662 assert Piecewise((Max(x, y), z))._random() is None def test_round(): from sympy.abc import x assert str(Float('0.1249999').round(2)) == '0.12' d20 = 12345678901234567890 ans = S(d20).round(2) assert ans.is_Integer and ans == d20 ans = S(d20).round(-2) assert ans.is_Integer and ans == 12345678901234567900 assert str(S('1/7').round(4)) == '0.1429' assert str(S('.[12345]').round(4)) == '0.1235' assert str(S('.1349').round(2)) == '0.13' n = S(12345) ans = n.round() assert ans.is_Integer assert ans == n ans = n.round(1) assert ans.is_Integer assert ans == n ans = n.round(4) assert ans.is_Integer assert ans == n assert n.round(-1) == 12340 r = Float(str(n)).round(-4) assert r == 10000 assert n.round(-5) == 0 assert str((pi + sqrt(2)).round(2)) == '4.56' assert (10*(pi + sqrt(2))).round(-1) == 50 raises(TypeError, lambda: round(x + 2, 2)) assert str(S(2.3).round(1)) == '2.3' # rounding in SymPy (as in Decimal) should be # exact for the given precision; we check here # that when a 5 follows the last digit that # the rounded digit will be even. for i in range(-99, 100): # construct a decimal that ends in 5, e.g. 123 -> 0.1235 s = str(abs(i)) p = len(s) # we are going to round to the last digit of i n = '0.%s5' % s # put a 5 after i's digits j = p + 2 # 2 for '0.' if i < 0: # 1 for '-' j += 1 n = '-' + n v = str(Float(n).round(p))[:j] # pertinent digits if v.endswith('.'): continue # it ends with 0 which is even L = int(v[-1]) # last digit assert L % 2 == 0, (n, '->', v) assert (Float(.3, 3) + 2*pi).round() == 7 assert (Float(.3, 3) + 2*pi*100).round() == 629 assert (pi + 2*E*I).round() == 3 + 5*I # don't let request for extra precision give more than # what is known (in this case, only 3 digits) assert str((Float(.03, 3) + 2*pi/100).round(5)) == '0.0928' assert str((Float(.03, 3) + 2*pi/100).round(4)) == '0.0928' assert S.Zero.round() == 0 a = (Add(1, Float('1.' + '9'*27, ''), evaluate=0)) assert a.round(10) == Float('3.0000000000', '') assert a.round(25) == Float('3.0000000000000000000000000', '') assert a.round(26) == Float('3.00000000000000000000000000', '') assert a.round(27) == Float('2.999999999999999999999999999', '') assert a.round(30) == Float('2.999999999999999999999999999', '') raises(TypeError, lambda: x.round()) f = Function('f') raises(TypeError, lambda: f(1).round()) # exact magnitude of 10 assert str(S.One.round()) == '1' assert str(S(100).round()) == '100' # applied to real and imaginary portions assert (2*pi + E*I).round() == 6 + 3*I assert (2*pi + I/10).round() == 6 assert (pi/10 + 2*I).round() == 2*I # the lhs re and im parts are Float with dps of 2 # and those on the right have dps of 15 so they won't compare # equal unless we use string or compare components (which will # then coerce the floats to the same precision) or re-create # the floats assert str((pi/10 + E*I).round(2)) == '0.31 + 2.72*I' assert str((pi/10 + E*I).round(2).as_real_imag()) == '(0.31, 2.72)' assert str((pi/10 + E*I).round(2)) == '0.31 + 2.72*I' # issue 6914 assert (I**(I + 3)).round(3) == Float('-0.208', '')*I # issue 8720 assert S(-123.6).round() == -124 assert S(-1.5).round() == -2 assert S(-100.5).round() == -100 assert S(-1.5 - 10.5*I).round() == -2 - 10*I # issue 7961 assert str(S(0.006).round(2)) == '0.01' assert str(S(0.00106).round(4)) == '0.0011' # issue 8147 assert S.NaN.round() is S.NaN assert S.Infinity.round() is S.Infinity assert S.NegativeInfinity.round() is S.NegativeInfinity assert S.ComplexInfinity.round() is S.ComplexInfinity # check that types match for i in range(2): f = float(i) # 2 args assert all(type(round(i, p)) is int for p in (-1, 0, 1)) assert all(S(i).round(p).is_Integer for p in (-1, 0, 1)) assert all(type(round(f, p)) is float for p in (-1, 0, 1)) assert all(S(f).round(p).is_Float for p in (-1, 0, 1)) # 1 arg (p is None) assert type(round(i)) is int assert S(i).round().is_Integer assert type(round(f)) is int assert S(f).round().is_Integer def test_held_expression_UnevaluatedExpr(): x = symbols("x") he = UnevaluatedExpr(1/x) e1 = x*he assert isinstance(e1, Mul) assert e1.args == (x, he) assert e1.doit() == 1 assert UnevaluatedExpr(Derivative(x, x)).doit(deep=False ) == Derivative(x, x) assert UnevaluatedExpr(Derivative(x, x)).doit() == 1 xx = Mul(x, x, evaluate=False) assert xx != x**2 ue2 = UnevaluatedExpr(xx) assert isinstance(ue2, UnevaluatedExpr) assert ue2.args == (xx,) assert ue2.doit() == x**2 assert ue2.doit(deep=False) == xx x2 = UnevaluatedExpr(2)*2 assert type(x2) is Mul assert x2.args == (2, UnevaluatedExpr(2)) def test_round_exception_nostr(): # Don't use the string form of the expression in the round exception, as # it's too slow s = Symbol('bad') try: s.round() except TypeError as e: assert 'bad' not in str(e) else: # Did not raise raise AssertionError("Did not raise") def test_extract_branch_factor(): assert exp_polar(2.0*I*pi).extract_branch_factor() == (1, 1) def test_identity_removal(): assert Add.make_args(x + 0) == (x,) assert Mul.make_args(x*1) == (x,) def test_float_0(): assert Float(0.0) + 1 == Float(1.0) @XFAIL def test_float_0_fail(): assert Float(0.0)*x == Float(0.0) assert (x + Float(0.0)).is_Add def test_issue_6325(): ans = (b**2 + z**2 - (b*(a + b*t) + z*(c + t*z))**2/( (a + b*t)**2 + (c + t*z)**2))/sqrt((a + b*t)**2 + (c + t*z)**2) e = sqrt((a + b*t)**2 + (c + z*t)**2) assert diff(e, t, 2) == ans e.diff(t, 2) == ans assert diff(e, t, 2, simplify=False) != ans def test_issue_7426(): f1 = a % c f2 = x % z assert f1.equals(f2) is None def test_issue_11122(): x = Symbol('x', extended_positive=False) assert unchanged(Gt, x, 0) # (x > 0) # (x > 0) should remain unevaluated after PR #16956 x = Symbol('x', positive=False, real=True) assert (x > 0) is S.false def test_issue_10651(): x = Symbol('x', real=True) e1 = (-1 + x)/(1 - x) e3 = (4*x**2 - 4)/((1 - x)*(1 + x)) e4 = 1/(cos(x)**2) - (tan(x))**2 x = Symbol('x', positive=True) e5 = (1 + x)/x assert e1.is_constant() is None assert e3.is_constant() is None assert e4.is_constant() is None assert e5.is_constant() is False def test_issue_10161(): x = symbols('x', real=True) assert x*abs(x)*abs(x) == x**3 def test_issue_10755(): x = symbols('x') raises(TypeError, lambda: int(log(x))) raises(TypeError, lambda: log(x).round(2)) def test_issue_11877(): x = symbols('x') assert integrate(log(S.Half - x), (x, 0, S.Half)) == Rational(-1, 2) -log(2)/2 def test_normal(): x = symbols('x') e = Mul(S.Half, 1 + x, evaluate=False) assert e.normal() == e def test_expr(): x = symbols('x') raises(TypeError, lambda: tan(x).series(x, 2, oo, "+")) def test_ExprBuilder(): eb = ExprBuilder(Mul) eb.args.extend([x, x]) assert eb.build() == x**2 def test_non_string_equality(): # Expressions should not compare equal to strings x = symbols('x') one = sympify(1) assert (x == 'x') is False assert (x != 'x') is True assert (one == '1') is False assert (one != '1') is True assert (x + 1 == 'x + 1') is False assert (x + 1 != 'x + 1') is True # Make sure == doesn't try to convert the resulting expression to a string # (e.g., by calling sympify() instead of _sympify()) class BadRepr: def __repr__(self): raise RuntimeError assert (x == BadRepr()) is False assert (x != BadRepr()) is True def test_21494(): from sympy.testing.pytest import warns_deprecated_sympy with warns_deprecated_sympy(): assert x.expr_free_symbols == {x} sympy-sympy-1.9/sympy/core/tests/test_exprtools.py000066400000000000000000000432051412543434000226520ustar00rootroot00000000000000"""Tests for tools for manipulating of large commutative expressions. """ from sympy import (S, Add, sin, Mul, Symbol, oo, Integral, sqrt, Tuple, I, Function, Interval, O, symbols, simplify, collect, Sum, Basic, Dict, root, exp, cos, Dummy, log, Rational) from sympy.core.exprtools import (decompose_power, Factors, Term, _gcd_terms, gcd_terms, factor_terms, factor_nc, _mask_nc, _monotonic_sign) from sympy.core.mul import _keep_coeff as _keep_coeff from sympy.simplify.cse_opts import sub_pre from sympy.testing.pytest import raises from sympy.abc import a, b, t, x, y, z def test_decompose_power(): assert decompose_power(x) == (x, 1) assert decompose_power(x**2) == (x, 2) assert decompose_power(x**(2*y)) == (x**y, 2) assert decompose_power(x**(2*y/3)) == (x**(y/3), 2) assert decompose_power(x**(y*Rational(2, 3))) == (x**(y/3), 2) def test_Factors(): assert Factors() == Factors({}) == Factors(S.One) assert Factors().as_expr() is S.One assert Factors({x: 2, y: 3, sin(x): 4}).as_expr() == x**2*y**3*sin(x)**4 assert Factors(S.Infinity) == Factors({oo: 1}) assert Factors(S.NegativeInfinity) == Factors({oo: 1, -1: 1}) # issue #18059: assert Factors((x**2)**S.Half).as_expr() == (x**2)**S.Half a = Factors({x: 5, y: 3, z: 7}) b = Factors({ y: 4, z: 3, t: 10}) assert a.mul(b) == a*b == Factors({x: 5, y: 7, z: 10, t: 10}) assert a.div(b) == divmod(a, b) == \ (Factors({x: 5, z: 4}), Factors({y: 1, t: 10})) assert a.quo(b) == a/b == Factors({x: 5, z: 4}) assert a.rem(b) == a % b == Factors({y: 1, t: 10}) assert a.pow(3) == a**3 == Factors({x: 15, y: 9, z: 21}) assert b.pow(3) == b**3 == Factors({y: 12, z: 9, t: 30}) assert a.gcd(b) == Factors({y: 3, z: 3}) assert a.lcm(b) == Factors({x: 5, y: 4, z: 7, t: 10}) a = Factors({x: 4, y: 7, t: 7}) b = Factors({z: 1, t: 3}) assert a.normal(b) == (Factors({x: 4, y: 7, t: 4}), Factors({z: 1})) assert Factors(sqrt(2)*x).as_expr() == sqrt(2)*x assert Factors(-I)*I == Factors() assert Factors({S.NegativeOne: S(3)})*Factors({S.NegativeOne: S.One, I: S(5)}) == \ Factors(I) assert Factors(sqrt(I)*I) == Factors(I**(S(3)/2)) == Factors({I: S(3)/2}) assert Factors({I: S(3)/2}).as_expr() == I**(S(3)/2) assert Factors(S(2)**x).div(S(3)**x) == \ (Factors({S(2): x}), Factors({S(3): x})) assert Factors(2**(2*x + 2)).div(S(8)) == \ (Factors({S(2): 2*x + 2}), Factors({S(8): S.One})) # coverage # /!\ things break if this is not True assert Factors({S.NegativeOne: Rational(3, 2)}) == Factors({I: S.One, S.NegativeOne: S.One}) assert Factors({I: S.One, S.NegativeOne: Rational(1, 3)}).as_expr() == I*(-1)**Rational(1, 3) assert Factors(-1.) == Factors({S.NegativeOne: S.One, S(1.): 1}) assert Factors(-2.) == Factors({S.NegativeOne: S.One, S(2.): 1}) assert Factors((-2.)**x) == Factors({S(-2.): x}) assert Factors(S(-2)) == Factors({S.NegativeOne: S.One, S(2): 1}) assert Factors(S.Half) == Factors({S(2): -S.One}) assert Factors(Rational(3, 2)) == Factors({S(3): S.One, S(2): S.NegativeOne}) assert Factors({I: S.One}) == Factors(I) assert Factors({-1.0: 2, I: 1}) == Factors({S(1.0): 1, I: 1}) assert Factors({S.NegativeOne: Rational(-3, 2)}).as_expr() == I A = symbols('A', commutative=False) assert Factors(2*A**2) == Factors({S(2): 1, A**2: 1}) assert Factors(I) == Factors({I: S.One}) assert Factors(x).normal(S(2)) == (Factors(x), Factors(S(2))) assert Factors(x).normal(S.Zero) == (Factors(), Factors(S.Zero)) raises(ZeroDivisionError, lambda: Factors(x).div(S.Zero)) assert Factors(x).mul(S(2)) == Factors(2*x) assert Factors(x).mul(S.Zero).is_zero assert Factors(x).mul(1/x).is_one assert Factors(x**sqrt(2)**3).as_expr() == x**(2*sqrt(2)) assert Factors(x)**Factors(S(2)) == Factors(x**2) assert Factors(x).gcd(S.Zero) == Factors(x) assert Factors(x).lcm(S.Zero).is_zero assert Factors(S.Zero).div(x) == (Factors(S.Zero), Factors()) assert Factors(x).div(x) == (Factors(), Factors()) assert Factors({x: .2})/Factors({x: .2}) == Factors() assert Factors(x) != Factors() assert Factors(S.Zero).normal(x) == (Factors(S.Zero), Factors()) n, d = x**(2 + y), x**2 f = Factors(n) assert f.div(d) == f.normal(d) == (Factors(x**y), Factors()) assert f.gcd(d) == Factors() d = x**y assert f.div(d) == f.normal(d) == (Factors(x**2), Factors()) assert f.gcd(d) == Factors(d) n = d = 2**x f = Factors(n) assert f.div(d) == f.normal(d) == (Factors(), Factors()) assert f.gcd(d) == Factors(d) n, d = 2**x, 2**y f = Factors(n) assert f.div(d) == f.normal(d) == (Factors({S(2): x}), Factors({S(2): y})) assert f.gcd(d) == Factors() # extraction of constant only n = x**(x + 3) assert Factors(n).normal(x**-3) == (Factors({x: x + 6}), Factors({})) assert Factors(n).normal(x**3) == (Factors({x: x}), Factors({})) assert Factors(n).normal(x**4) == (Factors({x: x}), Factors({x: 1})) assert Factors(n).normal(x**(y - 3)) == \ (Factors({x: x + 6}), Factors({x: y})) assert Factors(n).normal(x**(y + 3)) == (Factors({x: x}), Factors({x: y})) assert Factors(n).normal(x**(y + 4)) == \ (Factors({x: x}), Factors({x: y + 1})) assert Factors(n).div(x**-3) == (Factors({x: x + 6}), Factors({})) assert Factors(n).div(x**3) == (Factors({x: x}), Factors({})) assert Factors(n).div(x**4) == (Factors({x: x}), Factors({x: 1})) assert Factors(n).div(x**(y - 3)) == \ (Factors({x: x + 6}), Factors({x: y})) assert Factors(n).div(x**(y + 3)) == (Factors({x: x}), Factors({x: y})) assert Factors(n).div(x**(y + 4)) == \ (Factors({x: x}), Factors({x: y + 1})) assert Factors(3 * x / 2) == Factors({3: 1, 2: -1, x: 1}) assert Factors(x * x / y) == Factors({x: 2, y: -1}) assert Factors(27 * x / y**9) == Factors({27: 1, x: 1, y: -9}) def test_Term(): a = Term(4*x*y**2/z/t**3) b = Term(2*x**3*y**5/t**3) assert a == Term(4, Factors({x: 1, y: 2}), Factors({z: 1, t: 3})) assert b == Term(2, Factors({x: 3, y: 5}), Factors({t: 3})) assert a.as_expr() == 4*x*y**2/z/t**3 assert b.as_expr() == 2*x**3*y**5/t**3 assert a.inv() == \ Term(S.One/4, Factors({z: 1, t: 3}), Factors({x: 1, y: 2})) assert b.inv() == Term(S.Half, Factors({t: 3}), Factors({x: 3, y: 5})) assert a.mul(b) == a*b == \ Term(8, Factors({x: 4, y: 7}), Factors({z: 1, t: 6})) assert a.quo(b) == a/b == Term(2, Factors({}), Factors({x: 2, y: 3, z: 1})) assert a.pow(3) == a**3 == \ Term(64, Factors({x: 3, y: 6}), Factors({z: 3, t: 9})) assert b.pow(3) == b**3 == Term(8, Factors({x: 9, y: 15}), Factors({t: 9})) assert a.pow(-3) == a**(-3) == \ Term(S.One/64, Factors({z: 3, t: 9}), Factors({x: 3, y: 6})) assert b.pow(-3) == b**(-3) == \ Term(S.One/8, Factors({t: 9}), Factors({x: 9, y: 15})) assert a.gcd(b) == Term(2, Factors({x: 1, y: 2}), Factors({t: 3})) assert a.lcm(b) == Term(4, Factors({x: 3, y: 5}), Factors({z: 1, t: 3})) a = Term(4*x*y**2/z/t**3) b = Term(2*x**3*y**5*t**7) assert a.mul(b) == Term(8, Factors({x: 4, y: 7, t: 4}), Factors({z: 1})) assert Term((2*x + 2)**3) == Term(8, Factors({x + 1: 3}), Factors({})) assert Term((2*x + 2)*(3*x + 6)**2) == \ Term(18, Factors({x + 1: 1, x + 2: 2}), Factors({})) def test_gcd_terms(): f = 2*(x + 1)*(x + 4)/(5*x**2 + 5) + (2*x + 2)*(x + 5)/(x**2 + 1)/5 + \ (2*x + 2)*(x + 6)/(5*x**2 + 5) assert _gcd_terms(f) == ((Rational(6, 5))*((1 + x)/(1 + x**2)), 5 + x, 1) assert _gcd_terms(Add.make_args(f)) == \ ((Rational(6, 5))*((1 + x)/(1 + x**2)), 5 + x, 1) newf = (Rational(6, 5))*((1 + x)*(5 + x)/(1 + x**2)) assert gcd_terms(f) == newf args = Add.make_args(f) # non-Basic sequences of terms treated as terms of Add assert gcd_terms(list(args)) == newf assert gcd_terms(tuple(args)) == newf assert gcd_terms(set(args)) == newf # but a Basic sequence is treated as a container assert gcd_terms(Tuple(*args)) != newf assert gcd_terms(Basic(Tuple(1, 3*y + 3*x*y), Tuple(1, 3))) == \ Basic((1, 3*y*(x + 1)), (1, 3)) # but we shouldn't change keys of a dictionary or some may be lost assert gcd_terms(Dict((x*(1 + y), 2), (x + x*y, y + x*y))) == \ Dict({x*(y + 1): 2, x + x*y: y*(1 + x)}) assert gcd_terms((2*x + 2)**3 + (2*x + 2)**2) == 4*(x + 1)**2*(2*x + 3) assert gcd_terms(0) == 0 assert gcd_terms(1) == 1 assert gcd_terms(x) == x assert gcd_terms(2 + 2*x) == Mul(2, 1 + x, evaluate=False) arg = x*(2*x + 4*y) garg = 2*x*(x + 2*y) assert gcd_terms(arg) == garg assert gcd_terms(sin(arg)) == sin(garg) # issue 6139-like alpha, alpha1, alpha2, alpha3 = symbols('alpha:4') a = alpha**2 - alpha*x**2 + alpha + x**3 - x*(alpha + 1) rep = (alpha, (1 + sqrt(5))/2 + alpha1*x + alpha2*x**2 + alpha3*x**3) s = (a/(x - alpha)).subs(*rep).series(x, 0, 1) assert simplify(collect(s, x)) == -sqrt(5)/2 - Rational(3, 2) + O(x) # issue 5917 assert _gcd_terms([S.Zero, S.Zero]) == (0, 0, 1) assert _gcd_terms([2*x + 4]) == (2, x + 2, 1) eq = x/(x + 1/x) assert gcd_terms(eq, fraction=False) == eq eq = x/2/y + 1/x/y assert gcd_terms(eq, fraction=True, clear=True) == \ (x**2 + 2)/(2*x*y) assert gcd_terms(eq, fraction=True, clear=False) == \ (x**2/2 + 1)/(x*y) assert gcd_terms(eq, fraction=False, clear=True) == \ (x + 2/x)/(2*y) assert gcd_terms(eq, fraction=False, clear=False) == \ (x/2 + 1/x)/y def test_factor_terms(): A = Symbol('A', commutative=False) assert factor_terms(9*(x + x*y + 1) + (3*x + 3)**(2 + 2*x)) == \ 9*x*y + 9*x + _keep_coeff(S(3), x + 1)**_keep_coeff(S(2), x + 1) + 9 assert factor_terms(9*(x + x*y + 1) + (3)**(2 + 2*x)) == \ _keep_coeff(S(9), 3**(2*x) + x*y + x + 1) assert factor_terms(3**(2 + 2*x) + a*3**(2 + 2*x)) == \ 9*3**(2*x)*(a + 1) assert factor_terms(x + x*A) == \ x*(1 + A) assert factor_terms(sin(x + x*A)) == \ sin(x*(1 + A)) assert factor_terms((3*x + 3)**((2 + 2*x)/3)) == \ _keep_coeff(S(3), x + 1)**_keep_coeff(Rational(2, 3), x + 1) assert factor_terms(x + (x*y + x)**(3*x + 3)) == \ x + (x*(y + 1))**_keep_coeff(S(3), x + 1) assert factor_terms(a*(x + x*y) + b*(x*2 + y*x*2)) == \ x*(a + 2*b)*(y + 1) i = Integral(x, (x, 0, oo)) assert factor_terms(i) == i assert factor_terms(x/2 + y) == x/2 + y # fraction doesn't apply to integer denominators assert factor_terms(x/2 + y, fraction=True) == x/2 + y # clear *does* apply to the integer denominators assert factor_terms(x/2 + y, clear=True) == Mul(S.Half, x + 2*y, evaluate=False) # check radical extraction eq = sqrt(2) + sqrt(10) assert factor_terms(eq) == eq assert factor_terms(eq, radical=True) == sqrt(2)*(1 + sqrt(5)) eq = root(-6, 3) + root(6, 3) assert factor_terms(eq, radical=True) == 6**(S.One/3)*(1 + (-1)**(S.One/3)) eq = [x + x*y] ans = [x*(y + 1)] for c in [list, tuple, set]: assert factor_terms(c(eq)) == c(ans) assert factor_terms(Tuple(x + x*y)) == Tuple(x*(y + 1)) assert factor_terms(Interval(0, 1)) == Interval(0, 1) e = 1/sqrt(a/2 + 1) assert factor_terms(e, clear=False) == 1/sqrt(a/2 + 1) assert factor_terms(e, clear=True) == sqrt(2)/sqrt(a + 2) eq = x/(x + 1/x) + 1/(x**2 + 1) assert factor_terms(eq, fraction=False) == eq assert factor_terms(eq, fraction=True) == 1 assert factor_terms((1/(x**3 + x**2) + 2/x**2)*y) == \ y*(2 + 1/(x + 1))/x**2 # if not True, then processesing for this in factor_terms is not necessary assert gcd_terms(-x - y) == -x - y assert factor_terms(-x - y) == Mul(-1, x + y, evaluate=False) # if not True, then "special" processesing in factor_terms is not necessary assert gcd_terms(exp(Mul(-1, x + 1))) == exp(-x - 1) e = exp(-x - 2) + x assert factor_terms(e) == exp(Mul(-1, x + 2, evaluate=False)) + x assert factor_terms(e, sign=False) == e assert factor_terms(exp(-4*x - 2) - x) == -x + exp(Mul(-2, 2*x + 1, evaluate=False)) # sum/integral tests for F in (Sum, Integral): assert factor_terms(F(x, (y, 1, 10))) == x * F(1, (y, 1, 10)) assert factor_terms(F(x, (y, 1, 10)) + x) == x * (1 + F(1, (y, 1, 10))) assert factor_terms(F(x*y + x*y**2, (y, 1, 10))) == x*F(y*(y + 1), (y, 1, 10)) def test_xreplace(): e = Mul(2, 1 + x, evaluate=False) assert e.xreplace({}) == e assert e.xreplace({y: x}) == e def test_factor_nc(): x, y = symbols('x,y') k = symbols('k', integer=True) n, m, o = symbols('n,m,o', commutative=False) # mul and multinomial expansion is needed from sympy.core.function import _mexpand e = x*(1 + y)**2 assert _mexpand(e) == x + x*2*y + x*y**2 def factor_nc_test(e): ex = _mexpand(e) assert ex.is_Add f = factor_nc(ex) assert not f.is_Add and _mexpand(f) == ex factor_nc_test(x*(1 + y)) factor_nc_test(n*(x + 1)) factor_nc_test(n*(x + m)) factor_nc_test((x + m)*n) factor_nc_test(n*m*(x*o + n*o*m)*n) s = Sum(x, (x, 1, 2)) factor_nc_test(x*(1 + s)) factor_nc_test(x*(1 + s)*s) factor_nc_test(x*(1 + sin(s))) factor_nc_test((1 + n)**2) factor_nc_test((x + n)*(x + m)*(x + y)) factor_nc_test(x*(n*m + 1)) factor_nc_test(x*(n*m + x)) factor_nc_test(x*(x*n*m + 1)) factor_nc_test(x*n*(x*m + 1)) factor_nc_test(x*(m*n + x*n*m)) factor_nc_test(n*(1 - m)*n**2) factor_nc_test((n + m)**2) factor_nc_test((n - m)*(n + m)**2) factor_nc_test((n + m)**2*(n - m)) factor_nc_test((m - n)*(n + m)**2*(n - m)) assert factor_nc(n*(n + n*m)) == n**2*(1 + m) assert factor_nc(m*(m*n + n*m*n**2)) == m*(m + n*m*n)*n eq = m*sin(n) - sin(n)*m assert factor_nc(eq) == eq # for coverage: from sympy.physics.secondquant import Commutator from sympy import factor eq = 1 + x*Commutator(m, n) assert factor_nc(eq) == eq eq = x*Commutator(m, n) + x*Commutator(m, o)*Commutator(m, n) assert factor(eq) == x*(1 + Commutator(m, o))*Commutator(m, n) # issue 6534 assert (2*n + 2*m).factor() == 2*(n + m) # issue 6701 assert factor_nc(n**k + n**(k + 1)) == n**k*(1 + n) assert factor_nc((m*n)**k + (m*n)**(k + 1)) == (1 + m*n)*(m*n)**k # issue 6918 assert factor_nc(-n*(2*x**2 + 2*x)) == -2*n*x*(x + 1) def test_issue_6360(): a, b = symbols("a b") apb = a + b eq = apb + apb**2*(-2*a - 2*b) assert factor_terms(sub_pre(eq)) == a + b - 2*(a + b)**3 def test_issue_7903(): a = symbols(r'a', real=True) t = exp(I*cos(a)) + exp(-I*sin(a)) assert t.simplify() def test_issue_8263(): F, G = symbols('F, G', commutative=False, cls=Function) x, y = symbols('x, y') expr, dummies, _ = _mask_nc(F(x)*G(y) - G(y)*F(x)) for v in dummies.values(): assert not v.is_commutative assert not expr.is_zero def test_monotonic_sign(): F = _monotonic_sign x = symbols('x') assert F(x) is None assert F(-x) is None assert F(Dummy(prime=True)) == 2 assert F(Dummy(prime=True, odd=True)) == 3 assert F(Dummy(composite=True)) == 4 assert F(Dummy(composite=True, odd=True)) == 9 assert F(Dummy(positive=True, integer=True)) == 1 assert F(Dummy(positive=True, even=True)) == 2 assert F(Dummy(positive=True, even=True, prime=False)) == 4 assert F(Dummy(negative=True, integer=True)) == -1 assert F(Dummy(negative=True, even=True)) == -2 assert F(Dummy(zero=True)) == 0 assert F(Dummy(nonnegative=True)) == 0 assert F(Dummy(nonpositive=True)) == 0 assert F(Dummy(positive=True) + 1).is_positive assert F(Dummy(positive=True, integer=True) - 1).is_nonnegative assert F(Dummy(positive=True) - 1) is None assert F(Dummy(negative=True) + 1) is None assert F(Dummy(negative=True, integer=True) - 1).is_nonpositive assert F(Dummy(negative=True) - 1).is_negative assert F(-Dummy(positive=True) + 1) is None assert F(-Dummy(positive=True, integer=True) - 1).is_negative assert F(-Dummy(positive=True) - 1).is_negative assert F(-Dummy(negative=True) + 1).is_positive assert F(-Dummy(negative=True, integer=True) - 1).is_nonnegative assert F(-Dummy(negative=True) - 1) is None x = Dummy(negative=True) assert F(x**3).is_nonpositive assert F(x**3 + log(2)*x - 1).is_negative x = Dummy(positive=True) assert F(-x**3).is_nonpositive p = Dummy(positive=True) assert F(1/p).is_positive assert F(p/(p + 1)).is_positive p = Dummy(nonnegative=True) assert F(p/(p + 1)).is_nonnegative p = Dummy(positive=True) assert F(-1/p).is_negative p = Dummy(nonpositive=True) assert F(p/(-p + 1)).is_nonpositive p = Dummy(positive=True, integer=True) q = Dummy(positive=True, integer=True) assert F(-2/p/q).is_negative assert F(-2/(p - 1)/q) is None assert F((p - 1)*q + 1).is_positive assert F(-(p - 1)*q - 1).is_negative def test_issue_17256(): from sympy import Symbol, Range, Sum x = Symbol('x') s1 = Sum(x + 1, (x, 1, 9)) s2 = Sum(x + 1, (x, Range(1, 10))) a = Symbol('a') r1 = s1.xreplace({x:a}) r2 = s2.xreplace({x:a}) r1.doit() == r2.doit() s1 = Sum(x + 1, (x, 0, 9)) s2 = Sum(x + 1, (x, Range(10))) a = Symbol('a') r1 = s1.xreplace({x:a}) r2 = s2.xreplace({x:a}) assert r1 == r2 def test_issue_21623(): from sympy import MatrixSymbol, gcd_terms M = MatrixSymbol('X', 2, 2) assert gcd_terms(M[0,0], 1) == M[0,0] sympy-sympy-1.9/sympy/core/tests/test_facts.py000066400000000000000000000264731412543434000217230ustar00rootroot00000000000000from sympy.core.facts import (deduce_alpha_implications, apply_beta_to_alpha_route, rules_2prereq, FactRules, FactKB) from sympy.core.logic import And, Not from sympy.testing.pytest import raises T = True F = False U = None def test_deduce_alpha_implications(): def D(i): I = deduce_alpha_implications(i) P = rules_2prereq({ (k, True): {(v, True) for v in S} for k, S in I.items()}) return I, P # transitivity I, P = D([('a', 'b'), ('b', 'c')]) assert I == {'a': {'b', 'c'}, 'b': {'c'}, Not('b'): {Not('a')}, Not('c'): {Not('a'), Not('b')}} assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} # Duplicate entry I, P = D([('a', 'b'), ('b', 'c'), ('b', 'c')]) assert I == {'a': {'b', 'c'}, 'b': {'c'}, Not('b'): {Not('a')}, Not('c'): {Not('a'), Not('b')}} assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} # see if it is tolerant to cycles assert D([('a', 'a'), ('a', 'a')]) == ({}, {}) assert D([('a', 'b'), ('b', 'a')]) == ( {'a': {'b'}, 'b': {'a'}, Not('a'): {Not('b')}, Not('b'): {Not('a')}}, {'a': {'b'}, 'b': {'a'}}) # see if it catches inconsistency raises(ValueError, lambda: D([('a', Not('a'))])) raises(ValueError, lambda: D([('a', 'b'), ('b', Not('a'))])) raises(ValueError, lambda: D([('a', 'b'), ('b', 'c'), ('b', 'na'), ('na', Not('a'))])) # see if it handles implications with negations I, P = D([('a', Not('b')), ('c', 'b')]) assert I == {'a': {Not('b'), Not('c')}, 'b': {Not('a')}, 'c': {'b', Not('a')}, Not('b'): {Not('c')}} assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} I, P = D([(Not('a'), 'b'), ('a', 'c')]) assert I == {'a': {'c'}, Not('a'): {'b'}, Not('b'): {'a', 'c'}, Not('c'): {Not('a'), 'b'},} assert P == {'a': {'b', 'c'}, 'b': {'a', 'c'}, 'c': {'a', 'b'}} # Long deductions I, P = D([('a', 'b'), ('b', 'c'), ('c', 'd'), ('d', 'e')]) assert I == {'a': {'b', 'c', 'd', 'e'}, 'b': {'c', 'd', 'e'}, 'c': {'d', 'e'}, 'd': {'e'}, Not('b'): {Not('a')}, Not('c'): {Not('a'), Not('b')}, Not('d'): {Not('a'), Not('b'), Not('c')}, Not('e'): {Not('a'), Not('b'), Not('c'), Not('d')}} assert P == {'a': {'b', 'c', 'd', 'e'}, 'b': {'a', 'c', 'd', 'e'}, 'c': {'a', 'b', 'd', 'e'}, 'd': {'a', 'b', 'c', 'e'}, 'e': {'a', 'b', 'c', 'd'}} # something related to real-world I, P = D([('rat', 'real'), ('int', 'rat')]) assert I == {'int': {'rat', 'real'}, 'rat': {'real'}, Not('real'): {Not('rat'), Not('int')}, Not('rat'): {Not('int')}} assert P == {'rat': {'int', 'real'}, 'real': {'int', 'rat'}, 'int': {'rat', 'real'}} # TODO move me to appropriate place def test_apply_beta_to_alpha_route(): APPLY = apply_beta_to_alpha_route # indicates empty alpha-chain with attached beta-rule #bidx def Q(bidx): return (set(), [bidx]) # x -> a &(a,b) -> x -- x -> a A = {'x': {'a'}} B = [(And('a', 'b'), 'x')] assert APPLY(A, B) == {'x': ({'a'}, []), 'a': Q(0), 'b': Q(0)} # x -> a &(a,!x) -> b -- x -> a A = {'x': {'a'}} B = [(And('a', Not('x')), 'b')] assert APPLY(A, B) == {'x': ({'a'}, []), Not('x'): Q(0), 'a': Q(0)} # x -> a b &(a,b) -> c -- x -> a b c A = {'x': {'a', 'b'}} B = [(And('a', 'b'), 'c')] assert APPLY(A, B) == \ {'x': ({'a', 'b', 'c'}, []), 'a': Q(0), 'b': Q(0)} # x -> a &(a,b) -> y -- x -> a [#0] A = {'x': {'a'}} B = [(And('a', 'b'), 'y')] assert APPLY(A, B) == {'x': ({'a'}, [0]), 'a': Q(0), 'b': Q(0)} # x -> a b c &(a,b) -> c -- x -> a b c A = {'x': {'a', 'b', 'c'}} B = [(And('a', 'b'), 'c')] assert APPLY(A, B) == \ {'x': ({'a', 'b', 'c'}, []), 'a': Q(0), 'b': Q(0)} # x -> a b &(a,b,c) -> y -- x -> a b [#0] A = {'x': {'a', 'b'}} B = [(And('a', 'b', 'c'), 'y')] assert APPLY(A, B) == \ {'x': ({'a', 'b'}, [0]), 'a': Q(0), 'b': Q(0), 'c': Q(0)} # x -> a b &(a,b) -> c -- x -> a b c d # c -> d c -> d A = {'x': {'a', 'b'}, 'c': {'d'}} B = [(And('a', 'b'), 'c')] assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'd'}, []), 'c': ({'d'}, []), 'a': Q(0), 'b': Q(0)} # x -> a b &(a,b) -> c -- x -> a b c d e # c -> d &(c,d) -> e c -> d e A = {'x': {'a', 'b'}, 'c': {'d'}} B = [(And('a', 'b'), 'c'), (And('c', 'd'), 'e')] assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'd', 'e'}, []), 'c': ({'d', 'e'}, []), 'a': Q(0), 'b': Q(0), 'd': Q(1)} # x -> a b &(a,y) -> z -- x -> a b y z # &(a,b) -> y A = {'x': {'a', 'b'}} B = [(And('a', 'y'), 'z'), (And('a', 'b'), 'y')] assert APPLY(A, B) == {'x': ({'a', 'b', 'y', 'z'}, []), 'a': (set(), [0, 1]), 'y': Q(0), 'b': Q(1)} # x -> a b &(a,!b) -> c -- x -> a b A = {'x': {'a', 'b'}} B = [(And('a', Not('b')), 'c')] assert APPLY(A, B) == \ {'x': ({'a', 'b'}, []), 'a': Q(0), Not('b'): Q(0)} # !x -> !a !b &(!a,b) -> c -- !x -> !a !b A = {Not('x'): {Not('a'), Not('b')}} B = [(And(Not('a'), 'b'), 'c')] assert APPLY(A, B) == \ {Not('x'): ({Not('a'), Not('b')}, []), Not('a'): Q(0), 'b': Q(0)} # x -> a b &(b,c) -> !a -- x -> a b A = {'x': {'a', 'b'}} B = [(And('b', 'c'), Not('a'))] assert APPLY(A, B) == {'x': ({'a', 'b'}, []), 'b': Q(0), 'c': Q(0)} # x -> a b &(a, b) -> c -- x -> a b c p # c -> p a A = {'x': {'a', 'b'}, 'c': {'p', 'a'}} B = [(And('a', 'b'), 'c')] assert APPLY(A, B) == {'x': ({'a', 'b', 'c', 'p'}, []), 'c': ({'p', 'a'}, []), 'a': Q(0), 'b': Q(0)} def test_FactRules_parse(): f = FactRules('a -> b') assert f.prereq == {'b': {'a'}, 'a': {'b'}} f = FactRules('a -> !b') assert f.prereq == {'b': {'a'}, 'a': {'b'}} f = FactRules('!a -> b') assert f.prereq == {'b': {'a'}, 'a': {'b'}} f = FactRules('!a -> !b') assert f.prereq == {'b': {'a'}, 'a': {'b'}} f = FactRules('!z == nz') assert f.prereq == {'z': {'nz'}, 'nz': {'z'}} def test_FactRules_parse2(): raises(ValueError, lambda: FactRules('a -> !a')) def test_FactRules_deduce(): f = FactRules(['a -> b', 'b -> c', 'b -> d', 'c -> e']) def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb assert D({'a': T}) == {'a': T, 'b': T, 'c': T, 'd': T, 'e': T} assert D({'b': T}) == { 'b': T, 'c': T, 'd': T, 'e': T} assert D({'c': T}) == { 'c': T, 'e': T} assert D({'d': T}) == { 'd': T } assert D({'e': T}) == { 'e': T} assert D({'a': F}) == {'a': F } assert D({'b': F}) == {'a': F, 'b': F } assert D({'c': F}) == {'a': F, 'b': F, 'c': F } assert D({'d': F}) == {'a': F, 'b': F, 'd': F } assert D({'a': U}) == {'a': U} # XXX ok? def test_FactRules_deduce2(): # pos/neg/zero, but the rules are not sufficient to derive all relations f = FactRules(['pos -> !neg', 'pos -> !z']) def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb assert D({'pos': T}) == {'pos': T, 'neg': F, 'z': F} assert D({'pos': F}) == {'pos': F } assert D({'neg': T}) == {'pos': F, 'neg': T } assert D({'neg': F}) == { 'neg': F } assert D({'z': T}) == {'pos': F, 'z': T} assert D({'z': F}) == { 'z': F} # pos/neg/zero. rules are sufficient to derive all relations f = FactRules(['pos -> !neg', 'neg -> !pos', 'pos -> !z', 'neg -> !z']) assert D({'pos': T}) == {'pos': T, 'neg': F, 'z': F} assert D({'pos': F}) == {'pos': F } assert D({'neg': T}) == {'pos': F, 'neg': T, 'z': F} assert D({'neg': F}) == { 'neg': F } assert D({'z': T}) == {'pos': F, 'neg': F, 'z': T} assert D({'z': F}) == { 'z': F} def test_FactRules_deduce_multiple(): # deduction that involves _several_ starting points f = FactRules(['real == pos | npos']) def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb assert D({'real': T}) == {'real': T} assert D({'real': F}) == {'real': F, 'pos': F, 'npos': F} assert D({'pos': T}) == {'real': T, 'pos': T} assert D({'npos': T}) == {'real': T, 'npos': T} # --- key tests below --- assert D({'pos': F, 'npos': F}) == {'real': F, 'pos': F, 'npos': F} assert D({'real': T, 'pos': F}) == {'real': T, 'pos': F, 'npos': T} assert D({'real': T, 'npos': F}) == {'real': T, 'pos': T, 'npos': F} assert D({'pos': T, 'npos': F}) == {'real': T, 'pos': T, 'npos': F} assert D({'pos': F, 'npos': T}) == {'real': T, 'pos': F, 'npos': T} def test_FactRules_deduce_multiple2(): f = FactRules(['real == neg | zero | pos']) def D(facts): kb = FactKB(f) kb.deduce_all_facts(facts) return kb assert D({'real': T}) == {'real': T} assert D({'real': F}) == {'real': F, 'neg': F, 'zero': F, 'pos': F} assert D({'neg': T}) == {'real': T, 'neg': T} assert D({'zero': T}) == {'real': T, 'zero': T} assert D({'pos': T}) == {'real': T, 'pos': T} # --- key tests below --- assert D({'neg': F, 'zero': F, 'pos': F}) == {'real': F, 'neg': F, 'zero': F, 'pos': F} assert D({'real': T, 'neg': F}) == {'real': T, 'neg': F} assert D({'real': T, 'zero': F}) == {'real': T, 'zero': F} assert D({'real': T, 'pos': F}) == {'real': T, 'pos': F} assert D({'real': T, 'zero': F, 'pos': F}) == {'real': T, 'neg': T, 'zero': F, 'pos': F} assert D({'real': T, 'neg': F, 'pos': F}) == {'real': T, 'neg': F, 'zero': T, 'pos': F} assert D({'real': T, 'neg': F, 'zero': F }) == {'real': T, 'neg': F, 'zero': F, 'pos': T} assert D({'neg': T, 'zero': F, 'pos': F}) == {'real': T, 'neg': T, 'zero': F, 'pos': F} assert D({'neg': F, 'zero': T, 'pos': F}) == {'real': T, 'neg': F, 'zero': T, 'pos': F} assert D({'neg': F, 'zero': F, 'pos': T}) == {'real': T, 'neg': F, 'zero': F, 'pos': T} def test_FactRules_deduce_base(): # deduction that starts from base f = FactRules(['real == neg | zero | pos', 'neg -> real & !zero & !pos', 'pos -> real & !zero & !neg']) base = FactKB(f) base.deduce_all_facts({'real': T, 'neg': F}) assert base == {'real': T, 'neg': F} base.deduce_all_facts({'zero': F}) assert base == {'real': T, 'neg': F, 'zero': F, 'pos': T} def test_FactRules_deduce_staticext(): # verify that static beta-extensions deduction takes place f = FactRules(['real == neg | zero | pos', 'neg -> real & !zero & !pos', 'pos -> real & !zero & !neg', 'nneg == real & !neg', 'npos == real & !pos']) assert ('npos', True) in f.full_implications[('neg', True)] assert ('nneg', True) in f.full_implications[('pos', True)] assert ('nneg', True) in f.full_implications[('zero', True)] assert ('npos', True) in f.full_implications[('zero', True)] sympy-sympy-1.9/sympy/core/tests/test_function.py000066400000000000000000001417261412543434000224470ustar00rootroot00000000000000from sympy import (Lambda, Symbol, Function, Derivative, Subs, sqrt, log, exp, Rational, Float, sin, cos, acos, diff, I, re, im, E, expand, pi, O, Sum, S, polygamma, loggamma, expint, Tuple, Dummy, Eq, Expr, symbols, nfloat, Piecewise, Indexed, Matrix, Basic, Dict, oo, zoo, nan, Pow, sstr) from sympy.core.basic import _aresame from sympy.core.cache import clear_cache from sympy.core.expr import unchanged from sympy.core.function import (PoleError, _mexpand, arity, BadSignatureError, BadArgumentsError) from sympy.core.parameters import _exp_is_pow from sympy.core.sympify import sympify from sympy.matrices import MutableMatrix, ImmutableMatrix from sympy.sets.sets import FiniteSet from sympy.solvers.solveset import solveset from sympy.tensor.array import NDimArray from sympy.utilities.iterables import subsets, variations from sympy.testing.pytest import XFAIL, raises, warns_deprecated_sympy, _both_exp_pow from sympy.abc import t, w, x, y, z f, g, h = symbols('f g h', cls=Function) _xi_1, _xi_2, _xi_3 = [Dummy() for i in range(3)] def test_f_expand_complex(): x = Symbol('x', real=True) assert f(x).expand(complex=True) == I*im(f(x)) + re(f(x)) assert exp(x).expand(complex=True) == exp(x) assert exp(I*x).expand(complex=True) == cos(x) + I*sin(x) assert exp(z).expand(complex=True) == cos(im(z))*exp(re(z)) + \ I*sin(im(z))*exp(re(z)) def test_bug1(): e = sqrt(-log(w)) assert e.subs(log(w), -x) == sqrt(x) e = sqrt(-5*log(w)) assert e.subs(log(w), -x) == sqrt(5*x) def test_general_function(): nu = Function('nu') e = nu(x) edx = e.diff(x) edy = e.diff(y) edxdx = e.diff(x).diff(x) edxdy = e.diff(x).diff(y) assert e == nu(x) assert edx != nu(x) assert edx == diff(nu(x), x) assert edy == 0 assert edxdx == diff(diff(nu(x), x), x) assert edxdy == 0 def test_general_function_nullary(): nu = Function('nu') e = nu() edx = e.diff(x) edxdx = e.diff(x).diff(x) assert e == nu() assert edx != nu() assert edx == 0 assert edxdx == 0 def test_derivative_subs_bug(): e = diff(g(x), x) assert e.subs(g(x), f(x)) != e assert e.subs(g(x), f(x)) == Derivative(f(x), x) assert e.subs(g(x), -f(x)) == Derivative(-f(x), x) assert e.subs(x, y) == Derivative(g(y), y) def test_derivative_subs_self_bug(): d = diff(f(x), x) assert d.subs(d, y) == y def test_derivative_linearity(): assert diff(-f(x), x) == -diff(f(x), x) assert diff(8*f(x), x) == 8*diff(f(x), x) assert diff(8*f(x), x) != 7*diff(f(x), x) assert diff(8*f(x)*x, x) == 8*f(x) + 8*x*diff(f(x), x) assert diff(8*f(x)*y*x, x).expand() == 8*y*f(x) + 8*y*x*diff(f(x), x) def test_derivative_evaluate(): assert Derivative(sin(x), x) != diff(sin(x), x) assert Derivative(sin(x), x).doit() == diff(sin(x), x) assert Derivative(Derivative(f(x), x), x) == diff(f(x), x, x) assert Derivative(sin(x), x, 0) == sin(x) assert Derivative(sin(x), (x, y), (x, -y)) == sin(x) def test_diff_symbols(): assert diff(f(x, y, z), x, y, z) == Derivative(f(x, y, z), x, y, z) assert diff(f(x, y, z), x, x, x) == Derivative(f(x, y, z), x, x, x) == Derivative(f(x, y, z), (x, 3)) assert diff(f(x, y, z), x, 3) == Derivative(f(x, y, z), x, 3) # issue 5028 assert [diff(-z + x/y, sym) for sym in (z, x, y)] == [-1, 1/y, -x/y**2] assert diff(f(x, y, z), x, y, z, 2) == Derivative(f(x, y, z), x, y, z, z) assert diff(f(x, y, z), x, y, z, 2, evaluate=False) == \ Derivative(f(x, y, z), x, y, z, z) assert Derivative(f(x, y, z), x, y, z)._eval_derivative(z) == \ Derivative(f(x, y, z), x, y, z, z) assert Derivative(Derivative(f(x, y, z), x), y)._eval_derivative(z) == \ Derivative(f(x, y, z), x, y, z) raises(TypeError, lambda: cos(x).diff((x, y)).variables) assert cos(x).diff((x, y))._wrt_variables == [x] def test_Function(): class myfunc(Function): @classmethod def eval(cls): # zero args return assert myfunc.nargs == FiniteSet(0) assert myfunc().nargs == FiniteSet(0) raises(TypeError, lambda: myfunc(x).nargs) class myfunc(Function): @classmethod def eval(cls, x): # one arg return assert myfunc.nargs == FiniteSet(1) assert myfunc(x).nargs == FiniteSet(1) raises(TypeError, lambda: myfunc(x, y).nargs) class myfunc(Function): @classmethod def eval(cls, *x): # star args return assert myfunc.nargs == S.Naturals0 assert myfunc(x).nargs == S.Naturals0 def test_nargs(): f = Function('f') assert f.nargs == S.Naturals0 assert f(1).nargs == S.Naturals0 assert Function('f', nargs=2)(1, 2).nargs == FiniteSet(2) assert sin.nargs == FiniteSet(1) assert sin(2).nargs == FiniteSet(1) assert log.nargs == FiniteSet(1, 2) assert log(2).nargs == FiniteSet(1, 2) assert Function('f', nargs=2).nargs == FiniteSet(2) assert Function('f', nargs=0).nargs == FiniteSet(0) assert Function('f', nargs=(0, 1)).nargs == FiniteSet(0, 1) assert Function('f', nargs=None).nargs == S.Naturals0 raises(ValueError, lambda: Function('f', nargs=())) def test_nargs_inheritance(): class f1(Function): nargs = 2 class f2(f1): pass class f3(f2): pass class f4(f3): nargs = 1,2 class f5(f4): pass class f6(f5): pass class f7(f6): nargs=None class f8(f7): pass class f9(f8): pass class f10(f9): nargs = 1 class f11(f10): pass assert f1.nargs == FiniteSet(2) assert f2.nargs == FiniteSet(2) assert f3.nargs == FiniteSet(2) assert f4.nargs == FiniteSet(1, 2) assert f5.nargs == FiniteSet(1, 2) assert f6.nargs == FiniteSet(1, 2) assert f7.nargs == S.Naturals0 assert f8.nargs == S.Naturals0 assert f9.nargs == S.Naturals0 assert f10.nargs == FiniteSet(1) assert f11.nargs == FiniteSet(1) def test_arity(): f = lambda x, y: 1 assert arity(f) == 2 def f(x, y, z=None): pass assert arity(f) == (2, 3) assert arity(lambda *x: x) is None assert arity(log) == (1, 2) def test_Lambda(): e = Lambda(x, x**2) assert e(4) == 16 assert e(x) == x**2 assert e(y) == y**2 assert Lambda((), 42)() == 42 assert unchanged(Lambda, (), 42) assert Lambda((), 42) != Lambda((), 43) assert Lambda((), f(x))() == f(x) assert Lambda((), 42).nargs == FiniteSet(0) assert unchanged(Lambda, (x,), x**2) assert Lambda(x, x**2) == Lambda((x,), x**2) assert Lambda(x, x**2) != Lambda(x, x**2 + 1) assert Lambda((x, y), x**y) != Lambda((y, x), y**x) assert Lambda((x, y), x**y) != Lambda((x, y), y**x) assert Lambda((x, y), x**y)(x, y) == x**y assert Lambda((x, y), x**y)(3, 3) == 3**3 assert Lambda((x, y), x**y)(x, 3) == x**3 assert Lambda((x, y), x**y)(3, y) == 3**y assert Lambda(x, f(x))(x) == f(x) assert Lambda(x, x**2)(e(x)) == x**4 assert e(e(x)) == x**4 x1, x2 = (Indexed('x', i) for i in (1, 2)) assert Lambda((x1, x2), x1 + x2)(x, y) == x + y assert Lambda((x, y), x + y).nargs == FiniteSet(2) p = x, y, z, t assert Lambda(p, t*(x + y + z))(*p) == t * (x + y + z) eq = Lambda(x, 2*x) + Lambda(y, 2*y) assert eq != 2*Lambda(x, 2*x) assert eq.as_dummy() == 2*Lambda(x, 2*x).as_dummy() assert Lambda(x, 2*x) not in [ Lambda(x, x) ] raises(BadSignatureError, lambda: Lambda(1, x)) assert Lambda(x, 1)(1) is S.One raises(BadSignatureError, lambda: Lambda((x, x), x + 2)) raises(BadSignatureError, lambda: Lambda(((x, x), y), x)) raises(BadSignatureError, lambda: Lambda(((y, x), x), x)) raises(BadSignatureError, lambda: Lambda(((y, 1), 2), x)) with warns_deprecated_sympy(): assert Lambda([x, y], x+y) == Lambda((x, y), x+y) flam = Lambda( ((x, y),) , x + y) assert flam((2, 3)) == 5 flam = Lambda( ((x, y), z) , x + y + z) assert flam((2, 3), 1) == 6 flam = Lambda( (((x,y),z),) , x+y+z) assert flam( ((2,3),1) ) == 6 raises(BadArgumentsError, lambda: flam(1, 2, 3)) flam = Lambda( (x,), (x, x)) assert flam(1,) == (1, 1) assert flam((1,)) == ((1,), (1,)) flam = Lambda( ((x,),) , (x, x)) raises(BadArgumentsError, lambda: flam(1)) assert flam((1,)) == (1, 1) # Previously TypeError was raised so this is potentially needed for # backwards compatibility. assert issubclass(BadSignatureError, TypeError) assert issubclass(BadArgumentsError, TypeError) # These are tested to see they don't raise: hash(Lambda(x, 2*x)) hash(Lambda(x, x)) # IdentityFunction subclass def test_IdentityFunction(): assert Lambda(x, x) is Lambda(y, y) is S.IdentityFunction assert Lambda(x, 2*x) is not S.IdentityFunction assert Lambda((x, y), x) is not S.IdentityFunction def test_Lambda_symbols(): assert Lambda(x, 2*x).free_symbols == set() assert Lambda(x, x*y).free_symbols == {y} assert Lambda((), 42).free_symbols == set() assert Lambda((), x*y).free_symbols == {x,y} def test_functionclas_symbols(): assert f.free_symbols == set() def test_Lambda_arguments(): raises(TypeError, lambda: Lambda(x, 2*x)(x, y)) raises(TypeError, lambda: Lambda((x, y), x + y)(x)) raises(TypeError, lambda: Lambda((), 42)(x)) def test_Lambda_equality(): assert Lambda((x, y), 2*x) == Lambda((x, y), 2*x) # these, of course, should never be equal assert Lambda(x, 2*x) != Lambda((x, y), 2*x) assert Lambda(x, 2*x) != 2*x # But it is tempting to want expressions that differ only # in bound symbols to compare the same. But this is not what # Python's `==` is intended to do; two objects that compare # as equal means that they are indistibguishable and cache to the # same value. We wouldn't want to expression that are # mathematically the same but written in different variables to be # interchanged else what is the point of allowing for different # variable names? assert Lambda(x, 2*x) != Lambda(y, 2*y) def test_Subs(): assert Subs(1, (), ()) is S.One # check null subs influence on hashing assert Subs(x, y, z) != Subs(x, y, 1) # neutral subs works assert Subs(x, x, 1).subs(x, y).has(y) # self mapping var/point assert Subs(Derivative(f(x), (x, 2)), x, x).doit() == f(x).diff(x, x) assert Subs(x, x, 0).has(x) # it's a structural answer assert not Subs(x, x, 0).free_symbols assert Subs(Subs(x + y, x, 2), y, 1) == Subs(x + y, (x, y), (2, 1)) assert Subs(x, (x,), (0,)) == Subs(x, x, 0) assert Subs(x, x, 0) == Subs(y, y, 0) assert Subs(x, x, 0).subs(x, 1) == Subs(x, x, 0) assert Subs(y, x, 0).subs(y, 1) == Subs(1, x, 0) assert Subs(f(x), x, 0).doit() == f(0) assert Subs(f(x**2), x**2, 0).doit() == f(0) assert Subs(f(x, y, z), (x, y, z), (0, 1, 1)) != \ Subs(f(x, y, z), (x, y, z), (0, 0, 1)) assert Subs(x, y, 2).subs(x, y).doit() == 2 assert Subs(f(x, y), (x, y, z), (0, 1, 1)) != \ Subs(f(x, y) + z, (x, y, z), (0, 1, 0)) assert Subs(f(x, y), (x, y), (0, 1)).doit() == f(0, 1) assert Subs(Subs(f(x, y), x, 0), y, 1).doit() == f(0, 1) raises(ValueError, lambda: Subs(f(x, y), (x, y), (0, 0, 1))) raises(ValueError, lambda: Subs(f(x, y), (x, x, y), (0, 0, 1))) assert len(Subs(f(x, y), (x, y), (0, 1)).variables) == 2 assert Subs(f(x, y), (x, y), (0, 1)).point == Tuple(0, 1) assert Subs(f(x), x, 0) == Subs(f(y), y, 0) assert Subs(f(x, y), (x, y), (0, 1)) == Subs(f(x, y), (y, x), (1, 0)) assert Subs(f(x)*y, (x, y), (0, 1)) == Subs(f(y)*x, (y, x), (0, 1)) assert Subs(f(x)*y, (x, y), (1, 1)) == Subs(f(y)*x, (x, y), (1, 1)) assert Subs(f(x), x, 0).subs(x, 1).doit() == f(0) assert Subs(f(x), x, y).subs(y, 0) == Subs(f(x), x, 0) assert Subs(y*f(x), x, y).subs(y, 2) == Subs(2*f(x), x, 2) assert (2 * Subs(f(x), x, 0)).subs(Subs(f(x), x, 0), y) == 2*y assert Subs(f(x), x, 0).free_symbols == set() assert Subs(f(x, y), x, z).free_symbols == {y, z} assert Subs(f(x).diff(x), x, 0).doit(), Subs(f(x).diff(x), x, 0) assert Subs(1 + f(x).diff(x), x, 0).doit(), 1 + Subs(f(x).diff(x), x, 0) assert Subs(y*f(x, y).diff(x), (x, y), (0, 2)).doit() == \ 2*Subs(Derivative(f(x, 2), x), x, 0) assert Subs(y**2*f(x), x, 0).diff(y) == 2*y*f(0) e = Subs(y**2*f(x), x, y) assert e.diff(y) == e.doit().diff(y) == y**2*Derivative(f(y), y) + 2*y*f(y) assert Subs(f(x), x, 0) + Subs(f(x), x, 0) == 2*Subs(f(x), x, 0) e1 = Subs(z*f(x), x, 1) e2 = Subs(z*f(y), y, 1) assert e1 + e2 == 2*e1 assert e1.__hash__() == e2.__hash__() assert Subs(z*f(x + 1), x, 1) not in [ e1, e2 ] assert Derivative(f(x), x).subs(x, g(x)) == Derivative(f(g(x)), g(x)) assert Derivative(f(x), x).subs(x, x + y) == Subs(Derivative(f(x), x), x, x + y) assert Subs(f(x)*cos(y) + z, (x, y), (0, pi/3)).n(2) == \ Subs(f(x)*cos(y) + z, (x, y), (0, pi/3)).evalf(2) == \ z + Rational('1/2').n(2)*f(0) assert f(x).diff(x).subs(x, 0).subs(x, y) == f(x).diff(x).subs(x, 0) assert (x*f(x).diff(x).subs(x, 0)).subs(x, y) == y*f(x).diff(x).subs(x, 0) assert Subs(Derivative(g(x)**2, g(x), x), g(x), exp(x) ).doit() == 2*exp(x) assert Subs(Derivative(g(x)**2, g(x), x), g(x), exp(x) ).doit(deep=False) == 2*Derivative(exp(x), x) assert Derivative(f(x, g(x)), x).doit() == Derivative( f(x, g(x)), g(x))*Derivative(g(x), x) + Subs(Derivative( f(y, g(x)), y), y, x) def test_doitdoit(): done = Derivative(f(x, g(x)), x, g(x)).doit() assert done == done.doit() @XFAIL def test_Subs2(): # this reflects a limitation of subs(), probably won't fix assert Subs(f(x), x**2, x).doit() == f(sqrt(x)) def test_expand_function(): assert expand(x + y) == x + y assert expand(x + y, complex=True) == I*im(x) + I*im(y) + re(x) + re(y) assert expand((x + y)**11, modulus=11) == x**11 + y**11 def test_function_comparable(): assert sin(x).is_comparable is False assert cos(x).is_comparable is False assert sin(Float('0.1')).is_comparable is True assert cos(Float('0.1')).is_comparable is True assert sin(E).is_comparable is True assert cos(E).is_comparable is True assert sin(Rational(1, 3)).is_comparable is True assert cos(Rational(1, 3)).is_comparable is True def test_function_comparable_infinities(): assert sin(oo).is_comparable is False assert sin(-oo).is_comparable is False assert sin(zoo).is_comparable is False assert sin(nan).is_comparable is False def test_deriv1(): # These all require derivatives evaluated at a point (issue 4719) to work. # See issue 4624 assert f(2*x).diff(x) == 2*Subs(Derivative(f(x), x), x, 2*x) assert (f(x)**3).diff(x) == 3*f(x)**2*f(x).diff(x) assert (f(2*x)**3).diff(x) == 6*f(2*x)**2*Subs( Derivative(f(x), x), x, 2*x) assert f(2 + x).diff(x) == Subs(Derivative(f(x), x), x, x + 2) assert f(2 + 3*x).diff(x) == 3*Subs( Derivative(f(x), x), x, 3*x + 2) assert f(3*sin(x)).diff(x) == 3*cos(x)*Subs( Derivative(f(x), x), x, 3*sin(x)) # See issue 8510 assert f(x, x + z).diff(x) == ( Subs(Derivative(f(y, x + z), y), y, x) + Subs(Derivative(f(x, y), y), y, x + z)) assert f(x, x**2).diff(x) == ( 2*x*Subs(Derivative(f(x, y), y), y, x**2) + Subs(Derivative(f(y, x**2), y), y, x)) # but Subs is not always necessary assert f(x, g(y)).diff(g(y)) == Derivative(f(x, g(y)), g(y)) def test_deriv2(): assert (x**3).diff(x) == 3*x**2 assert (x**3).diff(x, evaluate=False) != 3*x**2 assert (x**3).diff(x, evaluate=False) == Derivative(x**3, x) assert diff(x**3, x) == 3*x**2 assert diff(x**3, x, evaluate=False) != 3*x**2 assert diff(x**3, x, evaluate=False) == Derivative(x**3, x) def test_func_deriv(): assert f(x).diff(x) == Derivative(f(x), x) # issue 4534 assert f(x, y).diff(x, y) - f(x, y).diff(y, x) == 0 assert Derivative(f(x, y), x, y).args[1:] == ((x, 1), (y, 1)) assert Derivative(f(x, y), y, x).args[1:] == ((y, 1), (x, 1)) assert (Derivative(f(x, y), x, y) - Derivative(f(x, y), y, x)).doit() == 0 def test_suppressed_evaluation(): a = sin(0, evaluate=False) assert a != 0 assert a.func is sin assert a.args == (0,) def test_function_evalf(): def eq(a, b, eps): return abs(a - b) < eps assert eq(sin(1).evalf(15), Float("0.841470984807897"), 1e-13) assert eq( sin(2).evalf(25), Float("0.9092974268256816953960199", 25), 1e-23) assert eq(sin(1 + I).evalf( 15), Float("1.29845758141598") + Float("0.634963914784736")*I, 1e-13) assert eq(exp(1 + I).evalf(15), Float( "1.46869393991588") + Float("2.28735528717884239")*I, 1e-13) assert eq(exp(-0.5 + 1.5*I).evalf(15), Float( "0.0429042815937374") + Float("0.605011292285002")*I, 1e-13) assert eq(log(pi + sqrt(2)*I).evalf( 15), Float("1.23699044022052") + Float("0.422985442737893")*I, 1e-13) assert eq(cos(100).evalf(15), Float("0.86231887228768"), 1e-13) def test_extensibility_eval(): class MyFunc(Function): @classmethod def eval(cls, *args): return (0, 0, 0) assert MyFunc(0) == (0, 0, 0) @_both_exp_pow def test_function_non_commutative(): x = Symbol('x', commutative=False) assert f(x).is_commutative is False assert sin(x).is_commutative is False assert exp(x).is_commutative is False assert log(x).is_commutative is False assert f(x).is_complex is False assert sin(x).is_complex is False assert exp(x).is_complex is False assert log(x).is_complex is False def test_function_complex(): x = Symbol('x', complex=True) xzf = Symbol('x', complex=True, zero=False) assert f(x).is_commutative is True assert sin(x).is_commutative is True assert exp(x).is_commutative is True assert log(x).is_commutative is True assert f(x).is_complex is None assert sin(x).is_complex is True assert exp(x).is_complex is True assert log(x).is_complex is None assert log(xzf).is_complex is True def test_function__eval_nseries(): n = Symbol('n') assert sin(x)._eval_nseries(x, 2, None) == x + O(x**2) assert sin(x + 1)._eval_nseries(x, 2, None) == x*cos(1) + sin(1) + O(x**2) assert sin(pi*(1 - x))._eval_nseries(x, 2, None) == pi*x + O(x**2) assert acos(1 - x**2)._eval_nseries(x, 2, None) == sqrt(2)*sqrt(x**2) + O(x**2) assert polygamma(n, x + 1)._eval_nseries(x, 2, None) == \ polygamma(n, 1) + polygamma(n + 1, 1)*x + O(x**2) raises(PoleError, lambda: sin(1/x)._eval_nseries(x, 2, None)) assert acos(1 - x)._eval_nseries(x, 2, None) == sqrt(2)*sqrt(x) + sqrt(2)*x**(S(3)/2)/12 + O(x**2) assert acos(1 + x)._eval_nseries(x, 2, None) == sqrt(2)*sqrt(-x) + sqrt(2)*(-x)**(S(3)/2)/12 + O(x**2) assert loggamma(1/x)._eval_nseries(x, 0, None) == \ log(x)/2 - log(x)/x - 1/x + O(1, x) assert loggamma(log(1/x)).nseries(x, n=1, logx=y) == loggamma(-y) # issue 6725: assert expint(Rational(3, 2), -x)._eval_nseries(x, 5, None) == \ 2 - 2*sqrt(pi)*sqrt(-x) - 2*x + x**2 + x**3/3 + x**4/12 + 4*I*x**(S(3)/2)*sqrt(-x)/3 + \ 2*I*x**(S(5)/2)*sqrt(-x)/5 + 2*I*x**(S(7)/2)*sqrt(-x)/21 + O(x**5) assert sin(sqrt(x))._eval_nseries(x, 3, None) == \ sqrt(x) - x**Rational(3, 2)/6 + x**Rational(5, 2)/120 + O(x**3) # issue 19065: s1 = f(x,y).series(y, n=2) assert {i.name for i in s1.atoms(Symbol)} == {'x', 'xi', 'y'} xi = Symbol('xi') s2 = f(xi, y).series(y, n=2) assert {i.name for i in s2.atoms(Symbol)} == {'xi', 'xi0', 'y'} def test_doit(): n = Symbol('n', integer=True) f = Sum(2 * n * x, (n, 1, 3)) d = Derivative(f, x) assert d.doit() == 12 assert d.doit(deep=False) == Sum(2*n, (n, 1, 3)) def test_evalf_default(): from sympy.functions.special.gamma_functions import polygamma assert type(sin(4.0)) == Float assert type(re(sin(I + 1.0))) == Float assert type(im(sin(I + 1.0))) == Float assert type(sin(4)) == sin assert type(polygamma(2.0, 4.0)) == Float assert type(sin(Rational(1, 4))) == sin def test_issue_5399(): args = [x, y, S(2), S.Half] def ok(a): """Return True if the input args for diff are ok""" if not a: return False if a[0].is_Symbol is False: return False s_at = [i for i in range(len(a)) if a[i].is_Symbol] n_at = [i for i in range(len(a)) if not a[i].is_Symbol] # every symbol is followed by symbol or int # every number is followed by a symbol return (all(a[i + 1].is_Symbol or a[i + 1].is_Integer for i in s_at if i + 1 < len(a)) and all(a[i + 1].is_Symbol for i in n_at if i + 1 < len(a))) eq = x**10*y**8 for a in subsets(args): for v in variations(a, len(a)): if ok(v): eq.diff(*v) # does not raise else: raises(ValueError, lambda: eq.diff(*v)) def test_derivative_numerically(): from random import random z0 = random() + I*random() assert abs(Derivative(sin(x), x).doit_numerically(z0) - cos(z0)) < 1e-15 def test_fdiff_argument_index_error(): from sympy.core.function import ArgumentIndexError class myfunc(Function): nargs = 1 # define since there is no eval routine def fdiff(self, idx): raise ArgumentIndexError mf = myfunc(x) assert mf.diff(x) == Derivative(mf, x) raises(TypeError, lambda: myfunc(x, x)) def test_deriv_wrt_function(): x = f(t) xd = diff(x, t) xdd = diff(xd, t) y = g(t) yd = diff(y, t) assert diff(x, t) == xd assert diff(2 * x + 4, t) == 2 * xd assert diff(2 * x + 4 + y, t) == 2 * xd + yd assert diff(2 * x + 4 + y * x, t) == 2 * xd + x * yd + xd * y assert diff(2 * x + 4 + y * x, x) == 2 + y assert (diff(4 * x**2 + 3 * x + x * y, t) == 3 * xd + x * yd + xd * y + 8 * x * xd) assert (diff(4 * x**2 + 3 * xd + x * y, t) == 3 * xdd + x * yd + xd * y + 8 * x * xd) assert diff(4 * x**2 + 3 * xd + x * y, xd) == 3 assert diff(4 * x**2 + 3 * xd + x * y, xdd) == 0 assert diff(sin(x), t) == xd * cos(x) assert diff(exp(x), t) == xd * exp(x) assert diff(sqrt(x), t) == xd / (2 * sqrt(x)) def test_diff_wrt_value(): assert Expr()._diff_wrt is False assert x._diff_wrt is True assert f(x)._diff_wrt is True assert Derivative(f(x), x)._diff_wrt is True assert Derivative(x**2, x)._diff_wrt is False def test_diff_wrt(): fx = f(x) dfx = diff(f(x), x) ddfx = diff(f(x), x, x) assert diff(sin(fx) + fx**2, fx) == cos(fx) + 2*fx assert diff(sin(dfx) + dfx**2, dfx) == cos(dfx) + 2*dfx assert diff(sin(ddfx) + ddfx**2, ddfx) == cos(ddfx) + 2*ddfx assert diff(fx**2, dfx) == 0 assert diff(fx**2, ddfx) == 0 assert diff(dfx**2, fx) == 0 assert diff(dfx**2, ddfx) == 0 assert diff(ddfx**2, dfx) == 0 assert diff(fx*dfx*ddfx, fx) == dfx*ddfx assert diff(fx*dfx*ddfx, dfx) == fx*ddfx assert diff(fx*dfx*ddfx, ddfx) == fx*dfx assert diff(f(x), x).diff(f(x)) == 0 assert (sin(f(x)) - cos(diff(f(x), x))).diff(f(x)) == cos(f(x)) assert diff(sin(fx), fx, x) == diff(sin(fx), x, fx) # Chain rule cases assert f(g(x)).diff(x) == \ Derivative(g(x), x)*Derivative(f(g(x)), g(x)) assert diff(f(g(x), h(y)), x) == \ Derivative(g(x), x)*Derivative(f(g(x), h(y)), g(x)) assert diff(f(g(x), h(x)), x) == ( Derivative(f(g(x), h(x)), g(x))*Derivative(g(x), x) + Derivative(f(g(x), h(x)), h(x))*Derivative(h(x), x)) assert f( sin(x)).diff(x) == cos(x)*Subs(Derivative(f(x), x), x, sin(x)) assert diff(f(g(x)), g(x)) == Derivative(f(g(x)), g(x)) def test_diff_wrt_func_subs(): assert f(g(x)).diff(x).subs(g, Lambda(x, 2*x)).doit() == f(2*x).diff(x) def test_subs_in_derivative(): expr = sin(x*exp(y)) u = Function('u') v = Function('v') assert Derivative(expr, y).subs(expr, y) == Derivative(y, y) assert Derivative(expr, y).subs(y, x).doit() == \ Derivative(expr, y).doit().subs(y, x) assert Derivative(f(x, y), y).subs(y, x) == Subs(Derivative(f(x, y), y), y, x) assert Derivative(f(x, y), y).subs(x, y) == Subs(Derivative(f(x, y), y), x, y) assert Derivative(f(x, y), y).subs(y, g(x, y)) == Subs(Derivative(f(x, y), y), y, g(x, y)).doit() assert Derivative(f(x, y), y).subs(x, g(x, y)) == Subs(Derivative(f(x, y), y), x, g(x, y)) assert Derivative(f(x, y), g(y)).subs(x, g(x, y)) == Derivative(f(g(x, y), y), g(y)) assert Derivative(f(u(x), h(y)), h(y)).subs(h(y), g(x, y)) == \ Subs(Derivative(f(u(x), h(y)), h(y)), h(y), g(x, y)).doit() assert Derivative(f(x, y), y).subs(y, z) == Derivative(f(x, z), z) assert Derivative(f(x, y), y).subs(y, g(y)) == Derivative(f(x, g(y)), g(y)) assert Derivative(f(g(x), h(y)), h(y)).subs(h(y), u(y)) == \ Derivative(f(g(x), u(y)), u(y)) assert Derivative(f(x, f(x, x)), f(x, x)).subs( f, Lambda((x, y), x + y)) == Subs( Derivative(z + x, z), z, 2*x) assert Subs(Derivative(f(f(x)), x), f, cos).doit() == sin(x)*sin(cos(x)) assert Subs(Derivative(f(f(x)), f(x)), f, cos).doit() == -sin(cos(x)) # Issue 13791. No comparison (it's a long formula) but this used to raise an exception. assert isinstance(v(x, y, u(x, y)).diff(y).diff(x).diff(y), Expr) # This is also related to issues 13791 and 13795; issue 15190 F = Lambda((x, y), exp(2*x + 3*y)) abstract = f(x, f(x, x)).diff(x, 2) concrete = F(x, F(x, x)).diff(x, 2) assert (abstract.subs(f, F).doit() - concrete).simplify() == 0 # don't introduce a new symbol if not necessary assert x in f(x).diff(x).subs(x, 0).atoms() # case (4) assert Derivative(f(x,f(x,y)), x, y).subs(x, g(y) ) == Subs(Derivative(f(x, f(x, y)), x, y), x, g(y)) assert Derivative(f(x, x), x).subs(x, 0 ) == Subs(Derivative(f(x, x), x), x, 0) # issue 15194 assert Derivative(f(y, g(x)), (x, z)).subs(z, x ) == Derivative(f(y, g(x)), (x, x)) df = f(x).diff(x) assert df.subs(df, 1) is S.One assert df.diff(df) is S.One dxy = Derivative(f(x, y), x, y) dyx = Derivative(f(x, y), y, x) assert dxy.subs(Derivative(f(x, y), y, x), 1) is S.One assert dxy.diff(dyx) is S.One assert Derivative(f(x, y), x, 2, y, 3).subs( dyx, g(x, y)) == Derivative(g(x, y), x, 1, y, 2) assert Derivative(f(x, x - y), y).subs(x, x + y) == Subs( Derivative(f(x, x - y), y), x, x + y) def test_diff_wrt_not_allowed(): # issue 7027 included for wrt in ( cos(x), re(x), x**2, x*y, 1 + x, Derivative(cos(x), x), Derivative(f(f(x)), x)): raises(ValueError, lambda: diff(f(x), wrt)) # if we don't differentiate wrt then don't raise error assert diff(exp(x*y), x*y, 0) == exp(x*y) def test_klein_gordon_lagrangian(): m = Symbol('m') phi = f(x, t) L = -(diff(phi, t)**2 - diff(phi, x)**2 - m**2*phi**2)/2 eqna = Eq( diff(L, phi) - diff(L, diff(phi, x), x) - diff(L, diff(phi, t), t), 0) eqnb = Eq(diff(phi, t, t) - diff(phi, x, x) + m**2*phi, 0) assert eqna == eqnb def test_sho_lagrangian(): m = Symbol('m') k = Symbol('k') x = f(t) L = m*diff(x, t)**2/2 - k*x**2/2 eqna = Eq(diff(L, x), diff(L, diff(x, t), t)) eqnb = Eq(-k*x, m*diff(x, t, t)) assert eqna == eqnb assert diff(L, x, t) == diff(L, t, x) assert diff(L, diff(x, t), t) == m*diff(x, t, 2) assert diff(L, t, diff(x, t)) == -k*x + m*diff(x, t, 2) def test_straight_line(): F = f(x) Fd = F.diff(x) L = sqrt(1 + Fd**2) assert diff(L, F) == 0 assert diff(L, Fd) == Fd/sqrt(1 + Fd**2) def test_sort_variable(): vsort = Derivative._sort_variable_count def vsort0(*v, reverse=False): return [i[0] for i in vsort([(i, 0) for i in ( reversed(v) if reverse else v)])] for R in range(2): assert vsort0(y, x, reverse=R) == [x, y] assert vsort0(f(x), x, reverse=R) == [x, f(x)] assert vsort0(f(y), f(x), reverse=R) == [f(x), f(y)] assert vsort0(g(x), f(y), reverse=R) == [f(y), g(x)] assert vsort0(f(x, y), f(x), reverse=R) == [f(x), f(x, y)] fx = f(x).diff(x) assert vsort0(fx, y, reverse=R) == [y, fx] fy = f(y).diff(y) assert vsort0(fy, fx, reverse=R) == [fx, fy] fxx = fx.diff(x) assert vsort0(fxx, fx, reverse=R) == [fx, fxx] assert vsort0(Basic(x), f(x), reverse=R) == [f(x), Basic(x)] assert vsort0(Basic(y), Basic(x), reverse=R) == [Basic(x), Basic(y)] assert vsort0(Basic(y, z), Basic(x), reverse=R) == [ Basic(x), Basic(y, z)] assert vsort0(fx, x, reverse=R) == [ x, fx] if R else [fx, x] assert vsort0(Basic(x), x, reverse=R) == [ x, Basic(x)] if R else [Basic(x), x] assert vsort0(Basic(f(x)), f(x), reverse=R) == [ f(x), Basic(f(x))] if R else [Basic(f(x)), f(x)] assert vsort0(Basic(x, z), Basic(x), reverse=R) == [ Basic(x), Basic(x, z)] if R else [Basic(x, z), Basic(x)] assert vsort([]) == [] assert _aresame(vsort([(x, 1)]), [Tuple(x, 1)]) assert vsort([(x, y), (x, z)]) == [(x, y + z)] assert vsort([(y, 1), (x, 1 + y)]) == [(x, 1 + y), (y, 1)] # coverage complete; legacy tests below assert vsort([(x, 3), (y, 2), (z, 1)]) == [(x, 3), (y, 2), (z, 1)] assert vsort([(h(x), 1), (g(x), 1), (f(x), 1)]) == [ (f(x), 1), (g(x), 1), (h(x), 1)] assert vsort([(z, 1), (y, 2), (x, 3), (h(x), 1), (g(x), 1), (f(x), 1)]) == [(x, 3), (y, 2), (z, 1), (f(x), 1), (g(x), 1), (h(x), 1)] assert vsort([(x, 1), (f(x), 1), (y, 1), (f(y), 1)]) == [(x, 1), (y, 1), (f(x), 1), (f(y), 1)] assert vsort([(y, 1), (x, 2), (g(x), 1), (f(x), 1), (z, 1), (h(x), 1), (y, 2), (x, 1)]) == [(x, 3), (y, 3), (z, 1), (f(x), 1), (g(x), 1), (h(x), 1)] assert vsort([(z, 1), (y, 1), (f(x), 1), (x, 1), (f(x), 1), (g(x), 1)]) == [(x, 1), (y, 1), (z, 1), (f(x), 2), (g(x), 1)] assert vsort([(z, 1), (y, 2), (f(x), 1), (x, 2), (f(x), 2), (g(x), 1), (z, 2), (z, 1), (y, 1), (x, 1)]) == [(x, 3), (y, 3), (z, 4), (f(x), 3), (g(x), 1)] assert vsort(((y, 2), (x, 1), (y, 1), (x, 1))) == [(x, 2), (y, 3)] assert isinstance(vsort([(x, 3), (y, 2), (z, 1)])[0], Tuple) assert vsort([(x, 1), (f(x), 1), (x, 1)]) == [(x, 2), (f(x), 1)] assert vsort([(y, 2), (x, 3), (z, 1)]) == [(x, 3), (y, 2), (z, 1)] assert vsort([(h(y), 1), (g(x), 1), (f(x), 1)]) == [ (f(x), 1), (g(x), 1), (h(y), 1)] assert vsort([(x, 1), (y, 1), (x, 1)]) == [(x, 2), (y, 1)] assert vsort([(f(x), 1), (f(y), 1), (f(x), 1)]) == [ (f(x), 2), (f(y), 1)] dfx = f(x).diff(x) self = [(dfx, 1), (x, 1)] assert vsort(self) == self assert vsort([ (dfx, 1), (y, 1), (f(x), 1), (x, 1), (f(y), 1), (x, 1)]) == [ (y, 1), (f(x), 1), (f(y), 1), (dfx, 1), (x, 2)] dfy = f(y).diff(y) assert vsort([(dfy, 1), (dfx, 1)]) == [(dfx, 1), (dfy, 1)] d2fx = dfx.diff(x) assert vsort([(d2fx, 1), (dfx, 1)]) == [(dfx, 1), (d2fx, 1)] def test_multiple_derivative(): # Issue #15007 assert f(x, y).diff(y, y, x, y, x ) == Derivative(f(x, y), (x, 2), (y, 3)) def test_unhandled(): class MyExpr(Expr): def _eval_derivative(self, s): if not s.name.startswith('xi'): return self else: return None eq = MyExpr(f(x), y, z) assert diff(eq, x, y, f(x), z) == Derivative(eq, f(x)) assert diff(eq, f(x), x) == Derivative(eq, f(x)) assert f(x, y).diff(x,(y, z)) == Derivative(f(x, y), x, (y, z)) assert f(x, y).diff(x,(y, 0)) == Derivative(f(x, y), x) def test_nfloat(): from sympy.core.basic import _aresame from sympy.polys.rootoftools import rootof x = Symbol("x") eq = x**Rational(4, 3) + 4*x**(S.One/3)/3 assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0/3)*x**(S.One/3)) assert _aresame(nfloat(eq, exponent=True), x**(4.0/3) + (4.0/3)*x**(1.0/3)) eq = x**Rational(4, 3) + 4*x**(x/3)/3 assert _aresame(nfloat(eq), x**Rational(4, 3) + (4.0/3)*x**(x/3)) big = 12345678901234567890 # specify precision to match value used in nfloat Float_big = Float(big, 15) assert _aresame(nfloat(big), Float_big) assert _aresame(nfloat(big*x), Float_big*x) assert _aresame(nfloat(x**big, exponent=True), x**Float_big) assert nfloat(cos(x + sqrt(2))) == cos(x + nfloat(sqrt(2))) # issue 6342 f = S('x*lamda + lamda**3*(x/2 + 1/2) + lamda**2 + 1/4') assert not any(a.free_symbols for a in solveset(f.subs(x, -0.139))) # issue 6632 assert nfloat(-100000*sqrt(2500000001) + 5000000001) == \ 9.99999999800000e-11 # issue 7122 eq = cos(3*x**4 + y)*rootof(x**5 + 3*x**3 + 1, 0) assert str(nfloat(eq, exponent=False, n=1)) == '-0.7*cos(3.0*x**4 + y)' # issue 10933 for ti in (dict, Dict): d = ti({S.Half: S.Half}) n = nfloat(d) assert isinstance(n, ti) assert _aresame(list(n.items()).pop(), (S.Half, Float(.5))) for ti in (dict, Dict): d = ti({S.Half: S.Half}) n = nfloat(d, dkeys=True) assert isinstance(n, ti) assert _aresame(list(n.items()).pop(), (Float(.5), Float(.5))) d = [S.Half] n = nfloat(d) assert type(n) is list assert _aresame(n[0], Float(.5)) assert _aresame(nfloat(Eq(x, S.Half)).rhs, Float(.5)) assert _aresame(nfloat(S(True)), S(True)) assert _aresame(nfloat(Tuple(S.Half))[0], Float(.5)) assert nfloat(Eq((3 - I)**2/2 + I, 0)) == S.false # pass along kwargs assert nfloat([{S.Half: x}], dkeys=True) == [{Float(0.5): x}] # Issue 17706 A = MutableMatrix([[1, 2], [3, 4]]) B = MutableMatrix( [[Float('1.0', precision=53), Float('2.0', precision=53)], [Float('3.0', precision=53), Float('4.0', precision=53)]]) assert _aresame(nfloat(A), B) A = ImmutableMatrix([[1, 2], [3, 4]]) B = ImmutableMatrix( [[Float('1.0', precision=53), Float('2.0', precision=53)], [Float('3.0', precision=53), Float('4.0', precision=53)]]) assert _aresame(nfloat(A), B) def test_issue_7068(): from sympy.abc import a, b f = Function('f') y1 = Dummy('y') y2 = Dummy('y') func1 = f(a + y1 * b) func2 = f(a + y2 * b) func1_y = func1.diff(y1) func2_y = func2.diff(y2) assert func1_y != func2_y z1 = Subs(f(a), a, y1) z2 = Subs(f(a), a, y2) assert z1 != z2 def test_issue_7231(): from sympy.abc import a ans1 = f(x).series(x, a) res = (f(a) + (-a + x)*Subs(Derivative(f(y), y), y, a) + (-a + x)**2*Subs(Derivative(f(y), y, y), y, a)/2 + (-a + x)**3*Subs(Derivative(f(y), y, y, y), y, a)/6 + (-a + x)**4*Subs(Derivative(f(y), y, y, y, y), y, a)/24 + (-a + x)**5*Subs(Derivative(f(y), y, y, y, y, y), y, a)/120 + O((-a + x)**6, (x, a))) assert res == ans1 ans2 = f(x).series(x, a) assert res == ans2 def test_issue_7687(): from sympy.core.function import Function from sympy.abc import x f = Function('f')(x) ff = Function('f')(x) match_with_cache = ff.matches(f) assert isinstance(f, type(ff)) clear_cache() ff = Function('f')(x) assert isinstance(f, type(ff)) assert match_with_cache == ff.matches(f) def test_issue_7688(): from sympy.core.function import Function, UndefinedFunction f = Function('f') # actually an UndefinedFunction clear_cache() class A(UndefinedFunction): pass a = A('f') assert isinstance(a, type(f)) def test_mexpand(): from sympy.abc import x assert _mexpand(None) is None assert _mexpand(1) is S.One assert _mexpand(x*(x + 1)**2) == (x*(x + 1)**2).expand() def test_issue_8469(): # This should not take forever to run N = 40 def g(w, theta): return 1/(1+exp(w-theta)) ws = symbols(['w%i'%i for i in range(N)]) import functools expr = functools.reduce(g, ws) assert isinstance(expr, Pow) def test_issue_12996(): # foo=True imitates the sort of arguments that Derivative can get # from Integral when it passes doit to the expression assert Derivative(im(x), x).doit(foo=True) == Derivative(im(x), x) def test_should_evalf(): # This should not take forever to run (see #8506) assert isinstance(sin((1.0 + 1.0*I)**10000 + 1), sin) def test_Derivative_as_finite_difference(): # Central 1st derivative at gridpoint x, h = symbols('x h', real=True) dfdx = f(x).diff(x) assert (dfdx.as_finite_difference([x-2, x-1, x, x+1, x+2]) - (S.One/12*(f(x-2)-f(x+2)) + Rational(2, 3)*(f(x+1)-f(x-1)))).simplify() == 0 # Central 1st derivative "half-way" assert (dfdx.as_finite_difference() - (f(x + S.Half)-f(x - S.Half))).simplify() == 0 assert (dfdx.as_finite_difference(h) - (f(x + h/S(2))-f(x - h/S(2)))/h).simplify() == 0 assert (dfdx.as_finite_difference([x - 3*h, x-h, x+h, x + 3*h]) - (S(9)/(8*2*h)*(f(x+h) - f(x-h)) + S.One/(24*2*h)*(f(x - 3*h) - f(x + 3*h)))).simplify() == 0 # One sided 1st derivative at gridpoint assert (dfdx.as_finite_difference([0, 1, 2], 0) - (Rational(-3, 2)*f(0) + 2*f(1) - f(2)/2)).simplify() == 0 assert (dfdx.as_finite_difference([x, x+h], x) - (f(x+h) - f(x))/h).simplify() == 0 assert (dfdx.as_finite_difference([x-h, x, x+h], x-h) - (-S(3)/(2*h)*f(x-h) + 2/h*f(x) - S.One/(2*h)*f(x+h))).simplify() == 0 # One sided 1st derivative "half-way" assert (dfdx.as_finite_difference([x-h, x+h, x + 3*h, x + 5*h, x + 7*h]) - 1/(2*h)*(-S(11)/(12)*f(x-h) + S(17)/(24)*f(x+h) + Rational(3, 8)*f(x + 3*h) - Rational(5, 24)*f(x + 5*h) + S.One/24*f(x + 7*h))).simplify() == 0 d2fdx2 = f(x).diff(x, 2) # Central 2nd derivative at gridpoint assert (d2fdx2.as_finite_difference([x-h, x, x+h]) - h**-2 * (f(x-h) + f(x+h) - 2*f(x))).simplify() == 0 assert (d2fdx2.as_finite_difference([x - 2*h, x-h, x, x+h, x + 2*h]) - h**-2 * (Rational(-1, 12)*(f(x - 2*h) + f(x + 2*h)) + Rational(4, 3)*(f(x+h) + f(x-h)) - Rational(5, 2)*f(x))).simplify() == 0 # Central 2nd derivative "half-way" assert (d2fdx2.as_finite_difference([x - 3*h, x-h, x+h, x + 3*h]) - (2*h)**-2 * (S.Half*(f(x - 3*h) + f(x + 3*h)) - S.Half*(f(x+h) + f(x-h)))).simplify() == 0 # One sided 2nd derivative at gridpoint assert (d2fdx2.as_finite_difference([x, x+h, x + 2*h, x + 3*h]) - h**-2 * (2*f(x) - 5*f(x+h) + 4*f(x+2*h) - f(x+3*h))).simplify() == 0 # One sided 2nd derivative at "half-way" assert (d2fdx2.as_finite_difference([x-h, x+h, x + 3*h, x + 5*h]) - (2*h)**-2 * (Rational(3, 2)*f(x-h) - Rational(7, 2)*f(x+h) + Rational(5, 2)*f(x + 3*h) - S.Half*f(x + 5*h))).simplify() == 0 d3fdx3 = f(x).diff(x, 3) # Central 3rd derivative at gridpoint assert (d3fdx3.as_finite_difference() - (-f(x - Rational(3, 2)) + 3*f(x - S.Half) - 3*f(x + S.Half) + f(x + Rational(3, 2)))).simplify() == 0 assert (d3fdx3.as_finite_difference( [x - 3*h, x - 2*h, x-h, x, x+h, x + 2*h, x + 3*h]) - h**-3 * (S.One/8*(f(x - 3*h) - f(x + 3*h)) - f(x - 2*h) + f(x + 2*h) + Rational(13, 8)*(f(x-h) - f(x+h)))).simplify() == 0 # Central 3rd derivative at "half-way" assert (d3fdx3.as_finite_difference([x - 3*h, x-h, x+h, x + 3*h]) - (2*h)**-3 * (f(x + 3*h)-f(x - 3*h) + 3*(f(x-h)-f(x+h)))).simplify() == 0 # One sided 3rd derivative at gridpoint assert (d3fdx3.as_finite_difference([x, x+h, x + 2*h, x + 3*h]) - h**-3 * (f(x + 3*h)-f(x) + 3*(f(x+h)-f(x + 2*h)))).simplify() == 0 # One sided 3rd derivative at "half-way" assert (d3fdx3.as_finite_difference([x-h, x+h, x + 3*h, x + 5*h]) - (2*h)**-3 * (f(x + 5*h)-f(x-h) + 3*(f(x+h)-f(x + 3*h)))).simplify() == 0 # issue 11007 y = Symbol('y', real=True) d2fdxdy = f(x, y).diff(x, y) ref0 = Derivative(f(x + S.Half, y), y) - Derivative(f(x - S.Half, y), y) assert (d2fdxdy.as_finite_difference(wrt=x) - ref0).simplify() == 0 half = S.Half xm, xp, ym, yp = x-half, x+half, y-half, y+half ref2 = f(xm, ym) + f(xp, yp) - f(xp, ym) - f(xm, yp) assert (d2fdxdy.as_finite_difference() - ref2).simplify() == 0 def test_issue_11159(): # Tests Application._eval_subs with _exp_is_pow(False): expr1 = E expr0 = expr1 * expr1 expr1 = expr0.subs(expr1,expr0) assert expr0 == expr1 with _exp_is_pow(True): expr1 = E expr0 = expr1 * expr1 expr2 = expr0.subs(expr1, expr0) assert expr2 == E ** 4 def test_issue_12005(): e1 = Subs(Derivative(f(x), x), x, x) assert e1.diff(x) == Derivative(f(x), x, x) e2 = Subs(Derivative(f(x), x), x, x**2 + 1) assert e2.diff(x) == 2*x*Subs(Derivative(f(x), x, x), x, x**2 + 1) e3 = Subs(Derivative(f(x) + y**2 - y, y), y, y**2) assert e3.diff(y) == 4*y e4 = Subs(Derivative(f(x + y), y), y, (x**2)) assert e4.diff(y) is S.Zero e5 = Subs(Derivative(f(x), x), (y, z), (y, z)) assert e5.diff(x) == Derivative(f(x), x, x) assert f(g(x)).diff(g(x), g(x)) == Derivative(f(g(x)), g(x), g(x)) def test_issue_13843(): x = symbols('x') f = Function('f') m, n = symbols('m n', integer=True) assert Derivative(Derivative(f(x), (x, m)), (x, n)) == Derivative(f(x), (x, m + n)) assert Derivative(Derivative(f(x), (x, m+5)), (x, n+3)) == Derivative(f(x), (x, m + n + 8)) assert Derivative(f(x), (x, n)).doit() == Derivative(f(x), (x, n)) def test_order_could_be_zero(): x, y = symbols('x, y') n = symbols('n', integer=True, nonnegative=True) m = symbols('m', integer=True, positive=True) assert diff(y, (x, n)) == Piecewise((y, Eq(n, 0)), (0, True)) assert diff(y, (x, n + 1)) is S.Zero assert diff(y, (x, m)) is S.Zero def test_undefined_function_eq(): f = Function('f') f2 = Function('f') g = Function('g') f_real = Function('f', is_real=True) # This test may only be meaningful if the cache is turned off assert f == f2 assert hash(f) == hash(f2) assert f == f assert f != g assert f != f_real def test_function_assumptions(): x = Symbol('x') f = Function('f') f_real = Function('f', real=True) f_real1 = Function('f', real=1) f_real_inherit = Function(Symbol('f', real=True)) assert f_real == f_real1 # assumptions are sanitized assert f != f_real assert f(x) != f_real(x) assert f(x).is_real is None assert f_real(x).is_real is True assert f_real_inherit(x).is_real is True and f_real_inherit.name == 'f' # Can also do it this way, but it won't be equal to f_real because of the # way UndefinedFunction.__new__ works. Any non-recognized assumptions # are just added literally as something which is used in the hash f_real2 = Function('f', is_real=True) assert f_real2(x).is_real is True def test_undef_fcn_float_issue_6938(): f = Function('ceil') assert not f(0.3).is_number f = Function('sin') assert not f(0.3).is_number assert not f(pi).evalf().is_number x = Symbol('x') assert not f(x).evalf(subs={x:1.2}).is_number def test_undefined_function_eval(): # Issue 15170. Make sure UndefinedFunction with eval defined works # properly. The issue there was that the hash was determined before _nargs # was set, which is included in the hash, hence changing the hash. The # class is added to sympy.core.core.all_classes before the hash is # changed, meaning "temp in all_classes" would fail, causing sympify(temp(t)) # to give a new class. We will eventually remove all_classes, but make # sure this continues to work. fdiff = lambda self, argindex=1: cos(self.args[argindex - 1]) eval = classmethod(lambda cls, t: None) _imp_ = classmethod(lambda cls, t: sin(t)) temp = Function('temp', fdiff=fdiff, eval=eval, _imp_=_imp_) expr = temp(t) assert sympify(expr) == expr assert type(sympify(expr)).fdiff.__name__ == "" assert expr.diff(t) == cos(t) def test_issue_15241(): F = f(x) Fx = F.diff(x) assert (F + x*Fx).diff(x, Fx) == 2 assert (F + x*Fx).diff(Fx, x) == 1 assert (x*F + x*Fx*F).diff(F, x) == x*Fx.diff(x) + Fx + 1 assert (x*F + x*Fx*F).diff(x, F) == x*Fx.diff(x) + Fx + 1 y = f(x) G = f(y) Gy = G.diff(y) assert (G + y*Gy).diff(y, Gy) == 2 assert (G + y*Gy).diff(Gy, y) == 1 assert (y*G + y*Gy*G).diff(G, y) == y*Gy.diff(y) + Gy + 1 assert (y*G + y*Gy*G).diff(y, G) == y*Gy.diff(y) + Gy + 1 def test_issue_15226(): assert Subs(Derivative(f(y), x, y), y, g(x)).doit() != 0 def test_issue_7027(): for wrt in (cos(x), re(x), Derivative(cos(x), x)): raises(ValueError, lambda: diff(f(x), wrt)) def test_derivative_quick_exit(): assert f(x).diff(y) == 0 assert f(x).diff(y, f(x)) == 0 assert f(x).diff(x, f(y)) == 0 assert f(f(x)).diff(x, f(x), f(y)) == 0 assert f(f(x)).diff(x, f(x), y) == 0 assert f(x).diff(g(x)) == 0 assert f(x).diff(x, f(x).diff(x)) == 1 df = f(x).diff(x) assert f(x).diff(df) == 0 dg = g(x).diff(x) assert dg.diff(df).doit() == 0 def test_issue_15084_13166(): eq = f(x, g(x)) assert eq.diff((g(x), y)) == Derivative(f(x, g(x)), (g(x), y)) # issue 13166 assert eq.diff(x, 2).doit() == ( (Derivative(f(x, g(x)), (g(x), 2))*Derivative(g(x), x) + Subs(Derivative(f(x, _xi_2), _xi_2, x), _xi_2, g(x)))*Derivative(g(x), x) + Derivative(f(x, g(x)), g(x))*Derivative(g(x), (x, 2)) + Derivative(g(x), x)*Subs(Derivative(f(_xi_1, g(x)), _xi_1, g(x)), _xi_1, x) + Subs(Derivative(f(_xi_1, g(x)), (_xi_1, 2)), _xi_1, x)) # issue 6681 assert diff(f(x, t, g(x, t)), x).doit() == ( Derivative(f(x, t, g(x, t)), g(x, t))*Derivative(g(x, t), x) + Subs(Derivative(f(_xi_1, t, g(x, t)), _xi_1), _xi_1, x)) # make sure the order doesn't matter when using diff assert eq.diff(x, g(x)) == eq.diff(g(x), x) def test_negative_counts(): # issue 13873 raises(ValueError, lambda: sin(x).diff(x, -1)) def test_Derivative__new__(): raises(TypeError, lambda: f(x).diff((x, 2), 0)) assert f(x, y).diff([(x, y), 0]) == f(x, y) assert f(x, y).diff([(x, y), 1]) == NDimArray([ Derivative(f(x, y), x), Derivative(f(x, y), y)]) assert f(x,y).diff(y, (x, z), y, x) == Derivative( f(x, y), (x, z + 1), (y, 2)) assert Matrix([x]).diff(x, 2) == Matrix([0]) # is_zero exit def test_issue_14719_10150(): class V(Expr): _diff_wrt = True is_scalar = False assert V().diff(V()) == Derivative(V(), V()) assert (2*V()).diff(V()) == 2*Derivative(V(), V()) class X(Expr): _diff_wrt = True assert X().diff(X()) == 1 assert (2*X()).diff(X()) == 2 def test_noncommutative_issue_15131(): x = Symbol('x', commutative=False) t = Symbol('t', commutative=False) fx = Function('Fx', commutative=False)(x) ft = Function('Ft', commutative=False)(t) A = Symbol('A', commutative=False) eq = fx * A * ft eqdt = eq.diff(t) assert eqdt.args[-1] == ft.diff(t) def test_Subs_Derivative(): a = Derivative(f(g(x), h(x)), g(x), h(x),x) b = Derivative(Derivative(f(g(x), h(x)), g(x), h(x)),x) c = f(g(x), h(x)).diff(g(x), h(x), x) d = f(g(x), h(x)).diff(g(x), h(x)).diff(x) e = Derivative(f(g(x), h(x)), x) eqs = (a, b, c, d, e) subs = lambda arg: arg.subs(f, Lambda((x, y), exp(x + y)) ).subs(g(x), 1/x).subs(h(x), x**3) ans = 3*x**2*exp(1/x)*exp(x**3) - exp(1/x)*exp(x**3)/x**2 assert all(subs(i).doit().expand() == ans for i in eqs) assert all(subs(i.doit()).doit().expand() == ans for i in eqs) def test_issue_15360(): f = Function('f') assert f.name == 'f' def test_issue_15947(): assert f._diff_wrt is False raises(TypeError, lambda: f(f)) raises(TypeError, lambda: f(x).diff(f)) def test_Derivative_free_symbols(): f = Function('f') n = Symbol('n', integer=True, positive=True) assert diff(f(x), (x, n)).free_symbols == {n, x} def test_issue_20683(): x = Symbol('x') y = Symbol('y') z = Symbol('z') y = Derivative(z, x).subs(x,0) assert y.doit() == 0 y = Derivative(8, x).subs(x,0) assert y.doit() == 0 def test_issue_10503(): f = exp(x**3)*cos(x**6) assert f.series(x, 0, 14) == 1 + x**3 + x**6/2 + x**9/6 - 11*x**12/24 + O(x**14) def test_issue_17382(): # copied from sympy/core/tests/test_evalf.py def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) x = Symbol('x') expr = solveset(2 * cos(x) * cos(2 * x) - 1, x, S.Reals) expected = "Union(" \ "ImageSet(Lambda(_n, 6.28318530717959*_n + 5.79812359592087), Integers), " \ "ImageSet(Lambda(_n, 6.28318530717959*_n + 0.485061711258717), Integers))" assert NS(expr) == expected sympy-sympy-1.9/sympy/core/tests/test_kind.py000066400000000000000000000040001412543434000215260ustar00rootroot00000000000000from sympy.core.add import Add from sympy.core.kind import NumberKind, UndefinedKind from sympy.core.mul import Mul from sympy.core.numbers import pi, zoo, I, AlgebraicNumber from sympy.core.singleton import S from sympy.core.symbol import Symbol from sympy.integrals.integrals import Integral from sympy.core.function import Derivative from sympy.matrices import (Matrix, SparseMatrix, ImmutableMatrix, ImmutableSparseMatrix, MatrixSymbol, MatrixKind, MatMul) comm_x = Symbol('x') noncomm_x = Symbol('x', commutative=False) def test_NumberKind(): assert S.One.kind is NumberKind assert pi.kind is NumberKind assert S.NaN.kind is NumberKind assert zoo.kind is NumberKind assert I.kind is NumberKind assert AlgebraicNumber(1).kind is NumberKind def test_Add_kind(): assert Add(2, 3, evaluate=False).kind is NumberKind assert Add(2,comm_x).kind is NumberKind assert Add(2,noncomm_x).kind is UndefinedKind def test_mul_kind(): assert Mul(2,comm_x, evaluate=False).kind is NumberKind assert Mul(2,3, evaluate=False).kind is NumberKind assert Mul(noncomm_x,2, evaluate=False).kind is UndefinedKind assert Mul(2,noncomm_x, evaluate=False).kind is UndefinedKind def test_Symbol_kind(): assert comm_x.kind is NumberKind assert noncomm_x.kind is UndefinedKind def test_Integral_kind(): A = MatrixSymbol('A', 2,2) assert Integral(comm_x, comm_x).kind is NumberKind assert Integral(A, comm_x).kind is MatrixKind(NumberKind) def test_Derivative_kind(): A = MatrixSymbol('A', 2,2) assert Derivative(comm_x, comm_x).kind is NumberKind assert Derivative(A, comm_x).kind is MatrixKind(NumberKind) def test_Matrix_kind(): classes = (Matrix, SparseMatrix, ImmutableMatrix, ImmutableSparseMatrix) for cls in classes: m = cls.zeros(3, 2) assert m.kind is MatrixKind(NumberKind) def test_MatMul_kind(): M = Matrix([[1,2],[3,4]]) assert MatMul(2, M).kind is MatrixKind(NumberKind) assert MatMul(comm_x, M).kind is MatrixKind(NumberKind) sympy-sympy-1.9/sympy/core/tests/test_logic.py000066400000000000000000000131021412543434000217010ustar00rootroot00000000000000from sympy.core.logic import (fuzzy_not, Logic, And, Or, Not, fuzzy_and, fuzzy_or, _fuzzy_group, _torf, fuzzy_nand, fuzzy_xor) from sympy.testing.pytest import raises T = True F = False U = None def test_torf(): from sympy.utilities.iterables import cartes v = [T, F, U] for i in cartes(*[v]*3): assert _torf(i) is (True if all(j for j in i) else (False if all(j is False for j in i) else None)) def test_fuzzy_group(): from sympy.utilities.iterables import cartes v = [T, F, U] for i in cartes(*[v]*3): assert _fuzzy_group(i) is (None if None in i else (True if all(j for j in i) else False)) assert _fuzzy_group(i, quick_exit=True) is \ (None if (i.count(False) > 1) else (None if None in i else (True if all(j for j in i) else False))) it = (True if (i == 0) else None for i in range(2)) assert _torf(it) is None it = (True if (i == 1) else None for i in range(2)) assert _torf(it) is None def test_fuzzy_not(): assert fuzzy_not(T) == F assert fuzzy_not(F) == T assert fuzzy_not(U) == U def test_fuzzy_and(): assert fuzzy_and([T, T]) == T assert fuzzy_and([T, F]) == F assert fuzzy_and([T, U]) == U assert fuzzy_and([F, F]) == F assert fuzzy_and([F, U]) == F assert fuzzy_and([U, U]) == U assert [fuzzy_and([w]) for w in [U, T, F]] == [U, T, F] assert fuzzy_and([T, F, U]) == F assert fuzzy_and([]) == T raises(TypeError, lambda: fuzzy_and()) def test_fuzzy_or(): assert fuzzy_or([T, T]) == T assert fuzzy_or([T, F]) == T assert fuzzy_or([T, U]) == T assert fuzzy_or([F, F]) == F assert fuzzy_or([F, U]) == U assert fuzzy_or([U, U]) == U assert [fuzzy_or([w]) for w in [U, T, F]] == [U, T, F] assert fuzzy_or([T, F, U]) == T assert fuzzy_or([]) == F raises(TypeError, lambda: fuzzy_or()) def test_logic_cmp(): l1 = And('a', Not('b')) l2 = And('a', Not('b')) assert hash(l1) == hash(l2) assert (l1 == l2) == T assert (l1 != l2) == F assert And('a', 'b', 'c') == And('b', 'a', 'c') assert And('a', 'b', 'c') == And('c', 'b', 'a') assert And('a', 'b', 'c') == And('c', 'a', 'b') assert Not('a') < Not('b') assert (Not('b') < Not('a')) is False assert (Not('a') < 2) is False def test_logic_onearg(): assert And() is True assert Or() is False assert And(T) == T assert And(F) == F assert Or(T) == T assert Or(F) == F assert And('a') == 'a' assert Or('a') == 'a' def test_logic_xnotx(): assert And('a', Not('a')) == F assert Or('a', Not('a')) == T def test_logic_eval_TF(): assert And(F, F) == F assert And(F, T) == F assert And(T, F) == F assert And(T, T) == T assert Or(F, F) == F assert Or(F, T) == T assert Or(T, F) == T assert Or(T, T) == T assert And('a', T) == 'a' assert And('a', F) == F assert Or('a', T) == T assert Or('a', F) == 'a' def test_logic_combine_args(): assert And('a', 'b', 'a') == And('a', 'b') assert Or('a', 'b', 'a') == Or('a', 'b') assert And(And('a', 'b'), And('c', 'd')) == And('a', 'b', 'c', 'd') assert Or(Or('a', 'b'), Or('c', 'd')) == Or('a', 'b', 'c', 'd') assert Or('t', And('n', 'p', 'r'), And('n', 'r'), And('n', 'p', 'r'), 't', And('n', 'r')) == Or('t', And('n', 'p', 'r'), And('n', 'r')) def test_logic_expand(): t = And(Or('a', 'b'), 'c') assert t.expand() == Or(And('a', 'c'), And('b', 'c')) t = And(Or('a', Not('b')), 'b') assert t.expand() == And('a', 'b') t = And(Or('a', 'b'), Or('c', 'd')) assert t.expand() == \ Or(And('a', 'c'), And('a', 'd'), And('b', 'c'), And('b', 'd')) def test_logic_fromstring(): S = Logic.fromstring assert S('a') == 'a' assert S('!a') == Not('a') assert S('a & b') == And('a', 'b') assert S('a | b') == Or('a', 'b') assert S('a | b & c') == And(Or('a', 'b'), 'c') assert S('a & b | c') == Or(And('a', 'b'), 'c') assert S('a & b & c') == And('a', 'b', 'c') assert S('a | b | c') == Or('a', 'b', 'c') raises(ValueError, lambda: S('| a')) raises(ValueError, lambda: S('& a')) raises(ValueError, lambda: S('a | | b')) raises(ValueError, lambda: S('a | & b')) raises(ValueError, lambda: S('a & & b')) raises(ValueError, lambda: S('a |')) raises(ValueError, lambda: S('a|b')) raises(ValueError, lambda: S('!')) raises(ValueError, lambda: S('! a')) raises(ValueError, lambda: S('!(a + 1)')) raises(ValueError, lambda: S('')) def test_logic_not(): assert Not('a') != '!a' assert Not('!a') != 'a' assert Not(True) == False assert Not(False) == True # NOTE: we may want to change default Not behaviour and put this # functionality into some method. assert Not(And('a', 'b')) == Or(Not('a'), Not('b')) assert Not(Or('a', 'b')) == And(Not('a'), Not('b')) raises(ValueError, lambda: Not(1)) def test_formatting(): S = Logic.fromstring raises(ValueError, lambda: S('a&b')) raises(ValueError, lambda: S('a|b')) raises(ValueError, lambda: S('! a')) def test_fuzzy_xor(): assert fuzzy_xor((None,)) is None assert fuzzy_xor((None, True)) is None assert fuzzy_xor((None, False)) is None assert fuzzy_xor((True, False)) is True assert fuzzy_xor((True, True)) is False assert fuzzy_xor((True, True, False)) is False assert fuzzy_xor((True, True, False, True)) is True def test_fuzzy_nand(): for args in [(1, 0), (1, 1), (0, 0)]: assert fuzzy_nand(args) == fuzzy_not(fuzzy_and(args)) sympy-sympy-1.9/sympy/core/tests/test_match.py000066400000000000000000000524331412543434000217120ustar00rootroot00000000000000from sympy import (abc, Add, cos, collect, Derivative, diff, exp, Float, Function, I, Integer, log, Mul, oo, Poly, Rational, S, signsimp, sin, sqrt, Symbol, symbols, Wild, pi, meijerg, Sum ) from sympy.testing.pytest import XFAIL def test_symbol(): x = Symbol('x') a, b, c, p, q = map(Wild, 'abcpq') e = x assert e.match(x) == {} assert e.matches(x) == {} assert e.match(a) == {a: x} e = Rational(5) assert e.match(c) == {c: 5} assert e.match(e) == {} assert e.match(e + 1) is None def test_add(): x, y, a, b, c = map(Symbol, 'xyabc') p, q, r = map(Wild, 'pqr') e = a + b assert e.match(p + b) == {p: a} assert e.match(p + a) == {p: b} e = 1 + b assert e.match(p + b) == {p: 1} e = a + b + c assert e.match(a + p + c) == {p: b} assert e.match(b + p + c) == {p: a} e = a + b + c + x assert e.match(a + p + x + c) == {p: b} assert e.match(b + p + c + x) == {p: a} assert e.match(b) is None assert e.match(b + p) == {p: a + c + x} assert e.match(a + p + c) == {p: b + x} assert e.match(b + p + c) == {p: a + x} e = 4*x + 5 assert e.match(4*x + p) == {p: 5} assert e.match(3*x + p) == {p: x + 5} assert e.match(p*x + 5) == {p: 4} def test_power(): x, y, a, b, c = map(Symbol, 'xyabc') p, q, r = map(Wild, 'pqr') e = (x + y)**a assert e.match(p**q) == {p: x + y, q: a} assert e.match(p**p) is None e = (x + y)**(x + y) assert e.match(p**p) == {p: x + y} assert e.match(p**q) == {p: x + y, q: x + y} e = (2*x)**2 assert e.match(p*q**r) == {p: 4, q: x, r: 2} e = Integer(1) assert e.match(x**p) == {p: 0} def test_match_exclude(): x = Symbol('x') y = Symbol('y') p = Wild("p") q = Wild("q") r = Wild("r") e = Rational(6) assert e.match(2*p) == {p: 3} e = 3/(4*x + 5) assert e.match(3/(p*x + q)) == {p: 4, q: 5} e = 3/(4*x + 5) assert e.match(p/(q*x + r)) == {p: 3, q: 4, r: 5} e = 2/(x + 1) assert e.match(p/(q*x + r)) == {p: 2, q: 1, r: 1} e = 1/(x + 1) assert e.match(p/(q*x + r)) == {p: 1, q: 1, r: 1} e = 4*x + 5 assert e.match(p*x + q) == {p: 4, q: 5} e = 4*x + 5*y + 6 assert e.match(p*x + q*y + r) == {p: 4, q: 5, r: 6} a = Wild('a', exclude=[x]) e = 3*x assert e.match(p*x) == {p: 3} assert e.match(a*x) == {a: 3} e = 3*x**2 assert e.match(p*x) == {p: 3*x} assert e.match(a*x) is None e = 3*x + 3 + 6/x assert e.match(p*x**2 + p*x + 2*p) == {p: 3/x} assert e.match(a*x**2 + a*x + 2*a) is None def test_mul(): x, y, a, b, c = map(Symbol, 'xyabc') p, q = map(Wild, 'pq') e = 4*x assert e.match(p*x) == {p: 4} assert e.match(p*y) is None assert e.match(e + p*y) == {p: 0} e = a*x*b*c assert e.match(p*x) == {p: a*b*c} assert e.match(c*p*x) == {p: a*b} e = (a + b)*(a + c) assert e.match((p + b)*(p + c)) == {p: a} e = x assert e.match(p*x) == {p: 1} e = exp(x) assert e.match(x**p*exp(x*q)) == {p: 0, q: 1} e = I*Poly(x, x) assert e.match(I*p) == {p: x} def test_mul_noncommutative(): x, y = symbols('x y') A, B, C = symbols('A B C', commutative=False) u, v = symbols('u v', cls=Wild) w, z = symbols('w z', cls=Wild, commutative=False) assert (u*v).matches(x) in ({v: x, u: 1}, {u: x, v: 1}) assert (u*v).matches(x*y) in ({v: y, u: x}, {u: y, v: x}) assert (u*v).matches(A) is None assert (u*v).matches(A*B) is None assert (u*v).matches(x*A) is None assert (u*v).matches(x*y*A) is None assert (u*v).matches(x*A*B) is None assert (u*v).matches(x*y*A*B) is None assert (v*w).matches(x) is None assert (v*w).matches(x*y) is None assert (v*w).matches(A) == {w: A, v: 1} assert (v*w).matches(A*B) == {w: A*B, v: 1} assert (v*w).matches(x*A) == {w: A, v: x} assert (v*w).matches(x*y*A) == {w: A, v: x*y} assert (v*w).matches(x*A*B) == {w: A*B, v: x} assert (v*w).matches(x*y*A*B) == {w: A*B, v: x*y} assert (v*w).matches(-x) is None assert (v*w).matches(-x*y) is None assert (v*w).matches(-A) == {w: A, v: -1} assert (v*w).matches(-A*B) == {w: A*B, v: -1} assert (v*w).matches(-x*A) == {w: A, v: -x} assert (v*w).matches(-x*y*A) == {w: A, v: -x*y} assert (v*w).matches(-x*A*B) == {w: A*B, v: -x} assert (v*w).matches(-x*y*A*B) == {w: A*B, v: -x*y} assert (w*z).matches(x) is None assert (w*z).matches(x*y) is None assert (w*z).matches(A) is None assert (w*z).matches(A*B) == {w: A, z: B} assert (w*z).matches(B*A) == {w: B, z: A} assert (w*z).matches(A*B*C) in [{w: A, z: B*C}, {w: A*B, z: C}] assert (w*z).matches(x*A) is None assert (w*z).matches(x*y*A) is None assert (w*z).matches(x*A*B) is None assert (w*z).matches(x*y*A*B) is None assert (w*A).matches(A) is None assert (A*w*B).matches(A*B) is None assert (u*w*z).matches(x) is None assert (u*w*z).matches(x*y) is None assert (u*w*z).matches(A) is None assert (u*w*z).matches(A*B) == {u: 1, w: A, z: B} assert (u*w*z).matches(B*A) == {u: 1, w: B, z: A} assert (u*w*z).matches(x*A) is None assert (u*w*z).matches(x*y*A) is None assert (u*w*z).matches(x*A*B) == {u: x, w: A, z: B} assert (u*w*z).matches(x*B*A) == {u: x, w: B, z: A} assert (u*w*z).matches(x*y*A*B) == {u: x*y, w: A, z: B} assert (u*w*z).matches(x*y*B*A) == {u: x*y, w: B, z: A} assert (u*A).matches(x*A) == {u: x} assert (u*A).matches(x*A*B) is None assert (u*B).matches(x*A) is None assert (u*A*B).matches(x*A*B) == {u: x} assert (u*A*B).matches(x*B*A) is None assert (u*A*B).matches(x*A) is None assert (u*w*A).matches(x*A*B) is None assert (u*w*B).matches(x*A*B) == {u: x, w: A} assert (u*v*A*B).matches(x*A*B) in [{u: x, v: 1}, {v: x, u: 1}] assert (u*v*A*B).matches(x*B*A) is None assert (u*v*A*B).matches(u*v*A*C) is None def test_mul_noncommutative_mismatch(): A, B, C = symbols('A B C', commutative=False) w = symbols('w', cls=Wild, commutative=False) assert (w*B*w).matches(A*B*A) == {w: A} assert (w*B*w).matches(A*C*B*A*C) == {w: A*C} assert (w*B*w).matches(A*C*B*A*B) is None assert (w*B*w).matches(A*B*C) is None assert (w*w*C).matches(A*B*C) is None def test_mul_noncommutative_pow(): A, B, C = symbols('A B C', commutative=False) w = symbols('w', cls=Wild, commutative=False) assert (A*B*w).matches(A*B**2) == {w: B} assert (A*(B**2)*w*(B**3)).matches(A*B**8) == {w: B**3} assert (A*B*w*C).matches(A*(B**4)*C) == {w: B**3} assert (A*B*(w**(-1))).matches(A*B*(C**(-1))) == {w: C} assert (A*(B*w)**(-1)*C).matches(A*(B*C)**(-1)*C) == {w: C} assert ((w**2)*B*C).matches((A**2)*B*C) == {w: A} assert ((w**2)*B*(w**3)).matches((A**2)*B*(A**3)) == {w: A} assert ((w**2)*B*(w**4)).matches((A**2)*B*(A**2)) is None def test_complex(): a, b, c = map(Symbol, 'abc') x, y = map(Wild, 'xy') assert (1 + I).match(x + I) == {x: 1} assert (a + I).match(x + I) == {x: a} assert (2*I).match(x*I) == {x: 2} assert (a*I).match(x*I) == {x: a} assert (a*I).match(x*y) == {x: I, y: a} assert (2*I).match(x*y) == {x: 2, y: I} assert (a + b*I).match(x + y*I) == {x: a, y: b} def test_functions(): from sympy.core.function import WildFunction x = Symbol('x') g = WildFunction('g') p = Wild('p') q = Wild('q') f = cos(5*x) notf = x assert f.match(p*cos(q*x)) == {p: 1, q: 5} assert f.match(p*g) == {p: 1, g: cos(5*x)} assert notf.match(g) is None @XFAIL def test_functions_X1(): from sympy.core.function import WildFunction x = Symbol('x') g = WildFunction('g') p = Wild('p') q = Wild('q') f = cos(5*x) assert f.match(p*g(q*x)) == {p: 1, g: cos, q: 5} def test_interface(): x, y = map(Symbol, 'xy') p, q = map(Wild, 'pq') assert (x + 1).match(p + 1) == {p: x} assert (x*3).match(p*3) == {p: x} assert (x**3).match(p**3) == {p: x} assert (x*cos(y)).match(p*cos(q)) == {p: x, q: y} assert (x*y).match(p*q) in [{p:x, q:y}, {p:y, q:x}] assert (x + y).match(p + q) in [{p:x, q:y}, {p:y, q:x}] assert (x*y + 1).match(p*q) in [{p:1, q:1 + x*y}, {p:1 + x*y, q:1}] def test_derivative1(): x, y = map(Symbol, 'xy') p, q = map(Wild, 'pq') f = Function('f', nargs=1) fd = Derivative(f(x), x) assert fd.match(p) == {p: fd} assert (fd + 1).match(p + 1) == {p: fd} assert (fd).match(fd) == {} assert (3*fd).match(p*fd) is not None assert (3*fd - 1).match(p*fd + q) == {p: 3, q: -1} def test_derivative_bug1(): f = Function("f") x = Symbol("x") a = Wild("a", exclude=[f, x]) b = Wild("b", exclude=[f]) pattern = a * Derivative(f(x), x, x) + b expr = Derivative(f(x), x) + x**2 d1 = {b: x**2} d2 = pattern.xreplace(d1).matches(expr, d1) assert d2 is None def test_derivative2(): f = Function("f") x = Symbol("x") a = Wild("a", exclude=[f, x]) b = Wild("b", exclude=[f]) e = Derivative(f(x), x) assert e.match(Derivative(f(x), x)) == {} assert e.match(Derivative(f(x), x, x)) is None e = Derivative(f(x), x, x) assert e.match(Derivative(f(x), x)) is None assert e.match(Derivative(f(x), x, x)) == {} e = Derivative(f(x), x) + x**2 assert e.match(a*Derivative(f(x), x) + b) == {a: 1, b: x**2} assert e.match(a*Derivative(f(x), x, x) + b) is None e = Derivative(f(x), x, x) + x**2 assert e.match(a*Derivative(f(x), x) + b) is None assert e.match(a*Derivative(f(x), x, x) + b) == {a: 1, b: x**2} def test_match_deriv_bug1(): n = Function('n') l = Function('l') x = Symbol('x') p = Wild('p') e = diff(l(x), x)/x - diff(diff(n(x), x), x)/2 - \ diff(n(x), x)**2/4 + diff(n(x), x)*diff(l(x), x)/4 e = e.subs(n(x), -l(x)).doit() t = x*exp(-l(x)) t2 = t.diff(x, x)/t assert e.match( (p*t2).expand() ) == {p: Rational(-1, 2)} def test_match_bug2(): x, y = map(Symbol, 'xy') p, q, r = map(Wild, 'pqr') res = (x + y).match(p + q + r) assert (p + q + r).subs(res) == x + y def test_match_bug3(): x, a, b = map(Symbol, 'xab') p = Wild('p') assert (b*x*exp(a*x)).match(x*exp(p*x)) is None def test_match_bug4(): x = Symbol('x') p = Wild('p') e = x assert e.match(-p*x) == {p: -1} def test_match_bug5(): x = Symbol('x') p = Wild('p') e = -x assert e.match(-p*x) == {p: 1} def test_match_bug6(): x = Symbol('x') p = Wild('p') e = x assert e.match(3*p*x) == {p: Rational(1)/3} def test_match_polynomial(): x = Symbol('x') a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) c = Wild('c', exclude=[x]) d = Wild('d', exclude=[x]) eq = 4*x**3 + 3*x**2 + 2*x + 1 pattern = a*x**3 + b*x**2 + c*x + d assert eq.match(pattern) == {a: 4, b: 3, c: 2, d: 1} assert (eq - 3*x**2).match(pattern) == {a: 4, b: 0, c: 2, d: 1} assert (x + sqrt(2) + 3).match(a + b*x + c*x**2) == \ {b: 1, a: sqrt(2) + 3, c: 0} def test_exclude(): x, y, a = map(Symbol, 'xya') p = Wild('p', exclude=[1, x]) q = Wild('q') r = Wild('r', exclude=[sin, y]) assert sin(x).match(r) is None assert cos(y).match(r) is None e = 3*x**2 + y*x + a assert e.match(p*x**2 + q*x + r) == {p: 3, q: y, r: a} e = x + 1 assert e.match(x + p) is None assert e.match(p + 1) is None assert e.match(x + 1 + p) == {p: 0} e = cos(x) + 5*sin(y) assert e.match(r) is None assert e.match(cos(y) + r) is None assert e.match(r + p*sin(q)) == {r: cos(x), p: 5, q: y} def test_floats(): a, b = map(Wild, 'ab') e = cos(0.12345, evaluate=False)**2 r = e.match(a*cos(b)**2) assert r == {a: 1, b: Float(0.12345)} def test_Derivative_bug1(): f = Function("f") x = abc.x a = Wild("a", exclude=[f(x)]) b = Wild("b", exclude=[f(x)]) eq = f(x).diff(x) assert eq.match(a*Derivative(f(x), x) + b) == {a: 1, b: 0} def test_match_wild_wild(): p = Wild('p') q = Wild('q') r = Wild('r') assert p.match(q + r) in [ {q: p, r: 0}, {q: 0, r: p} ] assert p.match(q*r) in [ {q: p, r: 1}, {q: 1, r: p} ] p = Wild('p') q = Wild('q', exclude=[p]) r = Wild('r') assert p.match(q + r) == {q: 0, r: p} assert p.match(q*r) == {q: 1, r: p} p = Wild('p') q = Wild('q', exclude=[p]) r = Wild('r', exclude=[p]) assert p.match(q + r) is None assert p.match(q*r) is None def test__combine_inverse(): x, y = symbols("x y") assert Mul._combine_inverse(x*I*y, x*I) == y assert Mul._combine_inverse(x*x**(1 + y), x**(1 + y)) == x assert Mul._combine_inverse(x*I*y, y*I) == x assert Mul._combine_inverse(oo*I*y, y*I) is oo assert Mul._combine_inverse(oo*I*y, oo*I) == y assert Mul._combine_inverse(oo*I*y, oo*I) == y assert Mul._combine_inverse(oo*y, -oo) == -y assert Mul._combine_inverse(-oo*y, oo) == -y assert Mul._combine_inverse((1-exp(x/y)),(exp(x/y)-1)) == -1 assert Add._combine_inverse(oo, oo) is S.Zero assert Add._combine_inverse(oo*I, oo*I) is S.Zero assert Add._combine_inverse(x*oo, x*oo) is S.Zero assert Add._combine_inverse(-x*oo, -x*oo) is S.Zero assert Add._combine_inverse((x - oo)*(x + oo), -oo) def test_issue_3773(): x = symbols('x') z, phi, r = symbols('z phi r') c, A, B, N = symbols('c A B N', cls=Wild) l = Wild('l', exclude=(0,)) eq = z * sin(2*phi) * r**7 matcher = c * sin(phi*N)**l * r**A * log(r)**B assert eq.match(matcher) == {c: z, l: 1, N: 2, A: 7, B: 0} assert (-eq).match(matcher) == {c: -z, l: 1, N: 2, A: 7, B: 0} assert (x*eq).match(matcher) == {c: x*z, l: 1, N: 2, A: 7, B: 0} assert (-7*x*eq).match(matcher) == {c: -7*x*z, l: 1, N: 2, A: 7, B: 0} matcher = c*sin(phi*N)**l * r**A assert eq.match(matcher) == {c: z, l: 1, N: 2, A: 7} assert (-eq).match(matcher) == {c: -z, l: 1, N: 2, A: 7} assert (x*eq).match(matcher) == {c: x*z, l: 1, N: 2, A: 7} assert (-7*x*eq).match(matcher) == {c: -7*x*z, l: 1, N: 2, A: 7} def test_issue_3883(): from sympy.abc import gamma, mu, x f = (-gamma * (x - mu)**2 - log(gamma) + log(2*pi))/2 a, b, c = symbols('a b c', cls=Wild, exclude=(gamma,)) assert f.match(a * log(gamma) + b * gamma + c) == \ {a: Rational(-1, 2), b: -(-mu + x)**2/2, c: log(2*pi)/2} assert f.expand().collect(gamma).match(a * log(gamma) + b * gamma + c) == \ {a: Rational(-1, 2), b: (-(x - mu)**2/2).expand(), c: (log(2*pi)/2).expand()} g1 = Wild('g1', exclude=[gamma]) g2 = Wild('g2', exclude=[gamma]) g3 = Wild('g3', exclude=[gamma]) assert f.expand().match(g1 * log(gamma) + g2 * gamma + g3) == \ {g3: log(2)/2 + log(pi)/2, g1: Rational(-1, 2), g2: -mu**2/2 + mu*x - x**2/2} def test_issue_4418(): x = Symbol('x') a, b, c = symbols('a b c', cls=Wild, exclude=(x,)) f, g = symbols('f g', cls=Function) eq = diff(g(x)*f(x).diff(x), x) assert eq.match( g(x).diff(x)*f(x).diff(x) + g(x)*f(x).diff(x, x) + c) == {c: 0} assert eq.match(a*g(x).diff( x)*f(x).diff(x) + b*g(x)*f(x).diff(x, x) + c) == {a: 1, b: 1, c: 0} def test_issue_4700(): f = Function('f') x = Symbol('x') a, b = symbols('a b', cls=Wild, exclude=(f(x),)) p = a*f(x) + b eq1 = sin(x) eq2 = f(x) + sin(x) eq3 = f(x) + x + sin(x) eq4 = x + sin(x) assert eq1.match(p) == {a: 0, b: sin(x)} assert eq2.match(p) == {a: 1, b: sin(x)} assert eq3.match(p) == {a: 1, b: x + sin(x)} assert eq4.match(p) == {a: 0, b: x + sin(x)} def test_issue_5168(): a, b, c = symbols('a b c', cls=Wild) x = Symbol('x') f = Function('f') assert x.match(a) == {a: x} assert x.match(a*f(x)**c) == {a: x, c: 0} assert x.match(a*b) == {a: 1, b: x} assert x.match(a*b*f(x)**c) == {a: 1, b: x, c: 0} assert (-x).match(a) == {a: -x} assert (-x).match(a*f(x)**c) == {a: -x, c: 0} assert (-x).match(a*b) == {a: -1, b: x} assert (-x).match(a*b*f(x)**c) == {a: -1, b: x, c: 0} assert (2*x).match(a) == {a: 2*x} assert (2*x).match(a*f(x)**c) == {a: 2*x, c: 0} assert (2*x).match(a*b) == {a: 2, b: x} assert (2*x).match(a*b*f(x)**c) == {a: 2, b: x, c: 0} assert (-2*x).match(a) == {a: -2*x} assert (-2*x).match(a*f(x)**c) == {a: -2*x, c: 0} assert (-2*x).match(a*b) == {a: -2, b: x} assert (-2*x).match(a*b*f(x)**c) == {a: -2, b: x, c: 0} def test_issue_4559(): x = Symbol('x') e = Symbol('e') w = Wild('w', exclude=[x]) y = Wild('y') # this is as it should be assert (3/x).match(w/y) == {w: 3, y: x} assert (3*x).match(w*y) == {w: 3, y: x} assert (x/3).match(y/w) == {w: 3, y: x} assert (3*x).match(y/w) == {w: S.One/3, y: x} assert (3*x).match(y/w) == {w: Rational(1, 3), y: x} # these could be allowed to fail assert (x/3).match(w/y) == {w: S.One/3, y: 1/x} assert (3*x).match(w/y) == {w: 3, y: 1/x} assert (3/x).match(w*y) == {w: 3, y: 1/x} # Note that solve will give # multiple roots but match only gives one: # # >>> solve(x**r-y**2,y) # [-x**(r/2), x**(r/2)] r = Symbol('r', rational=True) assert (x**r).match(y**2) == {y: x**(r/2)} assert (x**e).match(y**2) == {y: sqrt(x**e)} # since (x**i = y) -> x = y**(1/i) where i is an integer # the following should also be valid as long as y is not # zero when i is negative. a = Wild('a') e = S.Zero assert e.match(a) == {a: e} assert e.match(1/a) is None assert e.match(a**.3) is None e = S(3) assert e.match(1/a) == {a: 1/e} assert e.match(1/a**2) == {a: 1/sqrt(e)} e = pi assert e.match(1/a) == {a: 1/e} assert e.match(1/a**2) == {a: 1/sqrt(e)} assert (-e).match(sqrt(a)) is None assert (-e).match(a**2) == {a: I*sqrt(pi)} # The pattern matcher doesn't know how to handle (x - a)**2 == (a - x)**2. To # avoid ambiguity in actual applications, don't put a coefficient (including a # minus sign) in front of a wild. @XFAIL def test_issue_4883(): a = Wild('a') x = Symbol('x') e = [i**2 for i in (x - 2, 2 - x)] p = [i**2 for i in (x - a, a- x)] for eq in e: for pat in p: assert eq.match(pat) == {a: 2} def test_issue_4319(): x, y = symbols('x y') p = -x*(S.One/8 - y) ans = {S.Zero, y - S.One/8} def ok(pat): assert set(p.match(pat).values()) == ans ok(Wild("coeff", exclude=[x])*x + Wild("rest")) ok(Wild("w", exclude=[x])*x + Wild("rest")) ok(Wild("coeff", exclude=[x])*x + Wild("rest")) ok(Wild("w", exclude=[x])*x + Wild("rest")) ok(Wild("e", exclude=[x])*x + Wild("rest")) ok(Wild("ress", exclude=[x])*x + Wild("rest")) ok(Wild("resu", exclude=[x])*x + Wild("rest")) def test_issue_3778(): p, c, q = symbols('p c q', cls=Wild) x = Symbol('x') assert (sin(x)**2).match(sin(p)*sin(q)*c) == {q: x, c: 1, p: x} assert (2*sin(x)).match(sin(p) + sin(q) + c) == {q: x, c: 0, p: x} def test_issue_6103(): x = Symbol('x') a = Wild('a') assert (-I*x*oo).match(I*a*oo) == {a: -x} def test_issue_3539(): a = Wild('a') x = Symbol('x') assert (x - 2).match(a - x) is None assert (6/x).match(a*x) is None assert (6/x**2).match(a/x) == {a: 6/x} def test_gh_issue_2711(): x = Symbol('x') f = meijerg(((), ()), ((0,), ()), x) a = Wild('a') b = Wild('b') assert f.find(a) == {(S.Zero,), ((), ()), ((S.Zero,), ()), x, S.Zero, (), meijerg(((), ()), ((S.Zero,), ()), x)} assert f.find(a + b) == \ {meijerg(((), ()), ((S.Zero,), ()), x), x, S.Zero} assert f.find(a**2) == {meijerg(((), ()), ((S.Zero,), ()), x), x} def test_match_issue_17397(): f = Function("f") x = Symbol("x") a3 = Wild('a3', exclude=[f(x), f(x).diff(x), f(x).diff(x, 2)]) b3 = Wild('b3', exclude=[f(x), f(x).diff(x), f(x).diff(x, 2)]) c3 = Wild('c3', exclude=[f(x), f(x).diff(x), f(x).diff(x, 2)]) deq = a3*(f(x).diff(x, 2)) + b3*f(x).diff(x) + c3*f(x) eq = (x-2)**2*(f(x).diff(x, 2)) + (x-2)*(f(x).diff(x)) + ((x-2)**2 - 4)*f(x) r = collect(eq, [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) assert r == {a3: (x - 2)**2, c3: (x - 2)**2 - 4, b3: x - 2} eq =x*f(x) + x*Derivative(f(x), (x, 2)) - 4*f(x) + Derivative(f(x), x) \ - 4*Derivative(f(x), (x, 2)) - 2*Derivative(f(x), x)/x + 4*Derivative(f(x), (x, 2))/x r = collect(eq, [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) assert r == {a3: x - 4 + 4/x, b3: 1 - 2/x, c3: x - 4} def test_match_issue_21942(): a, r, w = symbols('a, r, w', nonnegative=True) p = symbols('p', positive=True) g_ = Wild('g') pattern = g_ ** (1 / (1 - p)) eq = (a * r ** (1 - p) + w ** (1 - p) * (1 - a)) ** (1 / (1 - p)) m = {g_: a * r ** (1 - p) + w ** (1 - p) * (1 - a)} assert pattern.matches(eq) == m assert (-pattern).matches(-eq) == m assert pattern.matches(signsimp(eq)) is None def test_match_terms(): X, Y = map(Wild, "XY") x, y, z = symbols('x y z') assert (5*y - x).match(5*X - Y) == {X: y, Y: x} # 15907 assert (x + (y - 1)*z).match(x + X*z) == {X: y - 1} # 20747 assert (x - log(x/y)*(1-exp(x/y))).match(x - log(X/y)*(1-exp(x/y))) == {X: x} def test_match_bound(): V, W = map(Wild, "VW") x, y = symbols('x y') assert Sum(x, (x, 1, 2)).match(Sum(y, (y, 1, W))) == {W: 2} assert Sum(x, (x, 1, 2)).match(Sum(V, (V, 1, W))) == {W: 2, V:x} assert Sum(x, (x, 1, 2)).match(Sum(V, (V, 1, 2))) == {V:x} sympy-sympy-1.9/sympy/core/tests/test_multidimensional.py000066400000000000000000000013571412543434000241720ustar00rootroot00000000000000from sympy import diff, sin, symbols, Function, Derivative from sympy.core.multidimensional import vectorize x, y, z = symbols('x y z') f, g, h = list(map(Function, 'fgh')) def test_vectorize(): @vectorize(0) def vsin(x): return sin(x) assert vsin([1, x, y]) == [sin(1), sin(x), sin(y)] @vectorize(0, 1) def vdiff(f, y): return diff(f, y) assert vdiff([f(x, y, z), g(x, y, z), h(x, y, z)], [x, y, z]) == \ [[Derivative(f(x, y, z), x), Derivative(f(x, y, z), y), Derivative(f(x, y, z), z)], [Derivative(g(x, y, z), x), Derivative(g(x, y, z), y), Derivative(g(x, y, z), z)], [Derivative(h(x, y, z), x), Derivative(h(x, y, z), y), Derivative(h(x, y, z), z)]] sympy-sympy-1.9/sympy/core/tests/test_noncommutative.py000066400000000000000000000077741412543434000236760ustar00rootroot00000000000000"""Tests for noncommutative symbols and expressions.""" from sympy import ( adjoint, cancel, collect, combsimp, conjugate, cos, expand, factor, gammasimp, posify, radsimp, ratsimp, rcollect, sin, simplify, symbols, transpose, trigsimp, I, ) from sympy.abc import x, y, z from sympy.testing.pytest import XFAIL A, B, C = symbols("A B C", commutative=False) X = symbols("X", commutative=False, hermitian=True) Y = symbols("Y", commutative=False, antihermitian=True) def test_adjoint(): assert adjoint(A).is_commutative is False assert adjoint(A*A) == adjoint(A)**2 assert adjoint(A*B) == adjoint(B)*adjoint(A) assert adjoint(A*B**2) == adjoint(B)**2*adjoint(A) assert adjoint(A*B - B*A) == adjoint(B)*adjoint(A) - adjoint(A)*adjoint(B) assert adjoint(A + I*B) == adjoint(A) - I*adjoint(B) assert adjoint(X) == X assert adjoint(-I*X) == I*X assert adjoint(Y) == -Y assert adjoint(-I*Y) == -I*Y assert adjoint(X) == conjugate(transpose(X)) assert adjoint(Y) == conjugate(transpose(Y)) assert adjoint(X) == transpose(conjugate(X)) assert adjoint(Y) == transpose(conjugate(Y)) def test_cancel(): assert cancel(A*B - B*A) == A*B - B*A assert cancel(A*B*(x - 1)) == A*B*(x - 1) assert cancel(A*B*(x**2 - 1)/(x + 1)) == A*B*(x - 1) assert cancel(A*B*(x**2 - 1)/(x + 1) - B*A*(x - 1)) == A*B*(x - 1) + (1 - x)*B*A @XFAIL def test_collect(): assert collect(A*B - B*A, A) == A*B - B*A assert collect(A*B - B*A, B) == A*B - B*A assert collect(A*B - B*A, x) == A*B - B*A def test_combsimp(): assert combsimp(A*B - B*A) == A*B - B*A def test_gammasimp(): assert gammasimp(A*B - B*A) == A*B - B*A def test_conjugate(): assert conjugate(A).is_commutative is False assert (A*A).conjugate() == conjugate(A)**2 assert (A*B).conjugate() == conjugate(A)*conjugate(B) assert (A*B**2).conjugate() == conjugate(A)*conjugate(B)**2 assert (A*B - B*A).conjugate() == \ conjugate(A)*conjugate(B) - conjugate(B)*conjugate(A) assert (A*B).conjugate() - (B*A).conjugate() == \ conjugate(A)*conjugate(B) - conjugate(B)*conjugate(A) assert (A + I*B).conjugate() == conjugate(A) - I*conjugate(B) def test_expand(): assert expand((A*B)**2) == A*B*A*B assert expand(A*B - B*A) == A*B - B*A assert expand((A*B/A)**2) == A*B*B/A assert expand(B*A*(A + B)*B) == B*A**2*B + B*A*B**2 assert expand(B*A*(A + C)*B) == B*A**2*B + B*A*C*B def test_factor(): assert factor(A*B - B*A) == A*B - B*A def test_posify(): assert posify(A)[0].is_commutative is False for q in (A*B/A, (A*B/A)**2, (A*B)**2, A*B - B*A): p = posify(q) assert p[0].subs(p[1]) == q def test_radsimp(): assert radsimp(A*B - B*A) == A*B - B*A @XFAIL def test_ratsimp(): assert ratsimp(A*B - B*A) == A*B - B*A @XFAIL def test_rcollect(): assert rcollect(A*B - B*A, A) == A*B - B*A assert rcollect(A*B - B*A, B) == A*B - B*A assert rcollect(A*B - B*A, x) == A*B - B*A def test_simplify(): assert simplify(A*B - B*A) == A*B - B*A def test_subs(): assert (x*y*A).subs(x*y, z) == A*z assert (x*A*B).subs(x*A, C) == C*B assert (x*A*x*x).subs(x**2*A, C) == x*C assert (x*A*x*B).subs(x**2*A, C) == C*B assert (A**2*B**2).subs(A*B**2, C) == A*C assert (A*A*A + A*B*A).subs(A*A*A, C) == C + A*B*A def test_transpose(): assert transpose(A).is_commutative is False assert transpose(A*A) == transpose(A)**2 assert transpose(A*B) == transpose(B)*transpose(A) assert transpose(A*B**2) == transpose(B)**2*transpose(A) assert transpose(A*B - B*A) == \ transpose(B)*transpose(A) - transpose(A)*transpose(B) assert transpose(A + I*B) == transpose(A) + I*transpose(B) assert transpose(X) == conjugate(X) assert transpose(-I*X) == -I*conjugate(X) assert transpose(Y) == -conjugate(Y) assert transpose(-I*Y) == I*conjugate(Y) def test_trigsimp(): assert trigsimp(A*sin(x)**2 + A*cos(x)**2) == A sympy-sympy-1.9/sympy/core/tests/test_numbers.py000066400000000000000000002166301412543434000222720ustar00rootroot00000000000000import numbers as nums import decimal from sympy import (Rational, Symbol, Float, I, sqrt, cbrt, oo, nan, pi, E, Integer, S, factorial, Catalan, EulerGamma, GoldenRatio, TribonacciConstant, cos, exp, Number, zoo, log, Mul, Pow, Tuple, latex, Gt, Lt, Ge, Le, AlgebraicNumber, simplify, sin, fibonacci, RealField, sympify, srepr, Dummy, Sum) from sympy.core.logic import fuzzy_not from sympy.core.numbers import (igcd, ilcm, igcdex, seterr, igcd2, igcd_lehmer, mpf_norm, comp, mod_inverse) from sympy.core.power import integer_nthroot, isqrt, integer_log from sympy.polys.domains.groundtypes import PythonRational from sympy.utilities.decorator import conserve_mpmath_dps from sympy.utilities.iterables import permutations from sympy.testing.pytest import XFAIL, raises, _both_exp_pow from mpmath import mpf from mpmath.rational import mpq import mpmath from sympy.core import numbers t = Symbol('t', real=False) _ninf = float(-oo) _inf = float(oo) def same_and_same_prec(a, b): # stricter matching for Floats return a == b and a._prec == b._prec def test_seterr(): seterr(divide=True) raises(ValueError, lambda: S.Zero/S.Zero) seterr(divide=False) assert S.Zero / S.Zero is S.NaN def test_mod(): x = S.Half y = Rational(3, 4) z = Rational(5, 18043) assert x % x == 0 assert x % y == S.Half assert x % z == Rational(3, 36086) assert y % x == Rational(1, 4) assert y % y == 0 assert y % z == Rational(9, 72172) assert z % x == Rational(5, 18043) assert z % y == Rational(5, 18043) assert z % z == 0 a = Float(2.6) assert (a % .2) == 0.0 assert (a % 2).round(15) == 0.6 assert (a % 0.5).round(15) == 0.1 p = Symbol('p', infinite=True) assert oo % oo is nan assert zoo % oo is nan assert 5 % oo is nan assert p % 5 is nan # In these two tests, if the precision of m does # not match the precision of the ans, then it is # likely that the change made now gives an answer # with degraded accuracy. r = Rational(500, 41) f = Float('.36', 3) m = r % f ans = Float(r % Rational(f), 3) assert m == ans and m._prec == ans._prec f = Float('8.36', 3) m = f % r ans = Float(Rational(f) % r, 3) assert m == ans and m._prec == ans._prec s = S.Zero assert s % float(1) == 0.0 # No rounding required since these numbers can be represented # exactly. assert Rational(3, 4) % Float(1.1) == 0.75 assert Float(1.5) % Rational(5, 4) == 0.25 assert Rational(5, 4).__rmod__(Float('1.5')) == 0.25 assert Float('1.5').__rmod__(Float('2.75')) == Float('1.25') assert 2.75 % Float('1.5') == Float('1.25') a = Integer(7) b = Integer(4) assert type(a % b) == Integer assert a % b == Integer(3) assert Integer(1) % Rational(2, 3) == Rational(1, 3) assert Rational(7, 5) % Integer(1) == Rational(2, 5) assert Integer(2) % 1.5 == 0.5 assert Integer(3).__rmod__(Integer(10)) == Integer(1) assert Integer(10) % 4 == Integer(2) assert 15 % Integer(4) == Integer(3) def test_divmod(): assert divmod(S(12), S(8)) == Tuple(1, 4) assert divmod(-S(12), S(8)) == Tuple(-2, 4) assert divmod(S.Zero, S.One) == Tuple(0, 0) raises(ZeroDivisionError, lambda: divmod(S.Zero, S.Zero)) raises(ZeroDivisionError, lambda: divmod(S.One, S.Zero)) assert divmod(S(12), 8) == Tuple(1, 4) assert divmod(12, S(8)) == Tuple(1, 4) assert divmod(S("2"), S("3/2")) == Tuple(S("1"), S("1/2")) assert divmod(S("3/2"), S("2")) == Tuple(S("0"), S("3/2")) assert divmod(S("2"), S("3.5")) == Tuple(S("0"), S("2")) assert divmod(S("3.5"), S("2")) == Tuple(S("1"), S("1.5")) assert divmod(S("2"), S("1/3")) == Tuple(S("6"), S("0")) assert divmod(S("1/3"), S("2")) == Tuple(S("0"), S("1/3")) assert divmod(S("2"), S("1/10")) == Tuple(S("20"), S("0")) assert divmod(S("2"), S(".1"))[0] == 19 assert divmod(S("0.1"), S("2")) == Tuple(S("0"), S("0.1")) assert divmod(S("2"), 2) == Tuple(S("1"), S("0")) assert divmod(2, S("2")) == Tuple(S("1"), S("0")) assert divmod(S("2"), 1.5) == Tuple(S("1"), S("0.5")) assert divmod(1.5, S("2")) == Tuple(S("0"), S("1.5")) assert divmod(0.3, S("2")) == Tuple(S("0"), S("0.3")) assert divmod(S("3/2"), S("3.5")) == Tuple(S("0"), S("3/2")) assert divmod(S("3.5"), S("3/2")) == Tuple(S("2"), S("0.5")) assert divmod(S("3/2"), S("1/3")) == Tuple(S("4"), S("1/6")) assert divmod(S("1/3"), S("3/2")) == Tuple(S("0"), S("1/3")) assert divmod(S("3/2"), S("0.1"))[0] == 14 assert divmod(S("0.1"), S("3/2")) == Tuple(S("0"), S("0.1")) assert divmod(S("3/2"), 2) == Tuple(S("0"), S("3/2")) assert divmod(2, S("3/2")) == Tuple(S("1"), S("1/2")) assert divmod(S("3/2"), 1.5) == Tuple(S("1"), S("0")) assert divmod(1.5, S("3/2")) == Tuple(S("1"), S("0")) assert divmod(S("3/2"), 0.3) == Tuple(S("5"), S("0")) assert divmod(0.3, S("3/2")) == Tuple(S("0"), S("0.3")) assert divmod(S("1/3"), S("3.5")) == Tuple(S("0"), S("1/3")) assert divmod(S("3.5"), S("0.1")) == Tuple(S("35"), S("0")) assert divmod(S("0.1"), S("3.5")) == Tuple(S("0"), S("0.1")) assert divmod(S("3.5"), 2) == Tuple(S("1"), S("1.5")) assert divmod(2, S("3.5")) == Tuple(S("0"), S("2")) assert divmod(S("3.5"), 1.5) == Tuple(S("2"), S("0.5")) assert divmod(1.5, S("3.5")) == Tuple(S("0"), S("1.5")) assert divmod(0.3, S("3.5")) == Tuple(S("0"), S("0.3")) assert divmod(S("0.1"), S("1/3")) == Tuple(S("0"), S("0.1")) assert divmod(S("1/3"), 2) == Tuple(S("0"), S("1/3")) assert divmod(2, S("1/3")) == Tuple(S("6"), S("0")) assert divmod(S("1/3"), 1.5) == Tuple(S("0"), S("1/3")) assert divmod(0.3, S("1/3")) == Tuple(S("0"), S("0.3")) assert divmod(S("0.1"), 2) == Tuple(S("0"), S("0.1")) assert divmod(2, S("0.1"))[0] == 19 assert divmod(S("0.1"), 1.5) == Tuple(S("0"), S("0.1")) assert divmod(1.5, S("0.1")) == Tuple(S("15"), S("0")) assert divmod(S("0.1"), 0.3) == Tuple(S("0"), S("0.1")) assert str(divmod(S("2"), 0.3)) == '(6, 0.2)' assert str(divmod(S("3.5"), S("1/3"))) == '(10, 0.166666666666667)' assert str(divmod(S("3.5"), 0.3)) == '(11, 0.2)' assert str(divmod(S("1/3"), S("0.1"))) == '(3, 0.0333333333333333)' assert str(divmod(1.5, S("1/3"))) == '(4, 0.166666666666667)' assert str(divmod(S("1/3"), 0.3)) == '(1, 0.0333333333333333)' assert str(divmod(0.3, S("0.1"))) == '(2, 0.1)' assert divmod(-3, S(2)) == (-2, 1) assert divmod(S(-3), S(2)) == (-2, 1) assert divmod(S(-3), 2) == (-2, 1) assert divmod(S(4), S(-3.1)) == Tuple(-2, -2.2) assert divmod(S(4), S(-2.1)) == divmod(4, -2.1) assert divmod(S(-8), S(-2.5) ) == Tuple(3 , -0.5) assert divmod(oo, 1) == (S.NaN, S.NaN) assert divmod(S.NaN, 1) == (S.NaN, S.NaN) assert divmod(1, S.NaN) == (S.NaN, S.NaN) ans = [(-1, oo), (-1, oo), (0, 0), (0, 1), (0, 2)] OO = float('inf') ANS = [tuple(map(float, i)) for i in ans] assert [divmod(i, oo) for i in range(-2, 3)] == ans ans = [(0, -2), (0, -1), (0, 0), (-1, -oo), (-1, -oo)] ANS = [tuple(map(float, i)) for i in ans] assert [divmod(i, -oo) for i in range(-2, 3)] == ans assert [divmod(i, -OO) for i in range(-2, 3)] == ANS assert divmod(S(3.5), S(-2)) == divmod(3.5, -2) assert divmod(-S(3.5), S(-2)) == divmod(-3.5, -2) assert divmod(S(0.0), S(9)) == divmod(0.0, 9) assert divmod(S(0), S(9.0)) == divmod(0, 9.0) def test_igcd(): assert igcd(0, 0) == 0 assert igcd(0, 1) == 1 assert igcd(1, 0) == 1 assert igcd(0, 7) == 7 assert igcd(7, 0) == 7 assert igcd(7, 1) == 1 assert igcd(1, 7) == 1 assert igcd(-1, 0) == 1 assert igcd(0, -1) == 1 assert igcd(-1, -1) == 1 assert igcd(-1, 7) == 1 assert igcd(7, -1) == 1 assert igcd(8, 2) == 2 assert igcd(4, 8) == 4 assert igcd(8, 16) == 8 assert igcd(7, -3) == 1 assert igcd(-7, 3) == 1 assert igcd(-7, -3) == 1 assert igcd(*[10, 20, 30]) == 10 raises(TypeError, lambda: igcd()) raises(TypeError, lambda: igcd(2)) raises(ValueError, lambda: igcd(0, None)) raises(ValueError, lambda: igcd(1, 2.2)) for args in permutations((45.1, 1, 30)): raises(ValueError, lambda: igcd(*args)) for args in permutations((1, 2, None)): raises(ValueError, lambda: igcd(*args)) def test_igcd_lehmer(): a, b = fibonacci(10001), fibonacci(10000) # len(str(a)) == 2090 # small divisors, long Euclidean sequence assert igcd_lehmer(a, b) == 1 c = fibonacci(100) assert igcd_lehmer(a*c, b*c) == c # big divisor assert igcd_lehmer(a, 10**1000) == 1 # swapping argmument assert igcd_lehmer(1, 2) == igcd_lehmer(2, 1) def test_igcd2(): # short loop assert igcd2(2**100 - 1, 2**99 - 1) == 1 # Lehmer's algorithm a, b = int(fibonacci(10001)), int(fibonacci(10000)) assert igcd2(a, b) == 1 def test_ilcm(): assert ilcm(0, 0) == 0 assert ilcm(1, 0) == 0 assert ilcm(0, 1) == 0 assert ilcm(1, 1) == 1 assert ilcm(2, 1) == 2 assert ilcm(8, 2) == 8 assert ilcm(8, 6) == 24 assert ilcm(8, 7) == 56 assert ilcm(*[10, 20, 30]) == 60 raises(ValueError, lambda: ilcm(8.1, 7)) raises(ValueError, lambda: ilcm(8, 7.1)) raises(TypeError, lambda: ilcm(8)) def test_igcdex(): assert igcdex(2, 3) == (-1, 1, 1) assert igcdex(10, 12) == (-1, 1, 2) assert igcdex(100, 2004) == (-20, 1, 4) assert igcdex(0, 0) == (0, 1, 0) assert igcdex(1, 0) == (1, 0, 1) def _strictly_equal(a, b): return (a.p, a.q, type(a.p), type(a.q)) == \ (b.p, b.q, type(b.p), type(b.q)) def _test_rational_new(cls): """ Tests that are common between Integer and Rational. """ assert cls(0) is S.Zero assert cls(1) is S.One assert cls(-1) is S.NegativeOne # These look odd, but are similar to int(): assert cls('1') is S.One assert cls('-1') is S.NegativeOne i = Integer(10) assert _strictly_equal(i, cls('10')) assert _strictly_equal(i, cls('10')) assert _strictly_equal(i, cls(int(10))) assert _strictly_equal(i, cls(i)) raises(TypeError, lambda: cls(Symbol('x'))) def test_Integer_new(): """ Test for Integer constructor """ _test_rational_new(Integer) assert _strictly_equal(Integer(0.9), S.Zero) assert _strictly_equal(Integer(10.5), Integer(10)) raises(ValueError, lambda: Integer("10.5")) assert Integer(Rational('1.' + '9'*20)) == 1 def test_Rational_new(): """" Test for Rational constructor """ _test_rational_new(Rational) n1 = S.Half assert n1 == Rational(Integer(1), 2) assert n1 == Rational(Integer(1), Integer(2)) assert n1 == Rational(1, Integer(2)) assert n1 == Rational(S.Half) assert 1 == Rational(n1, n1) assert Rational(3, 2) == Rational(S.Half, Rational(1, 3)) assert Rational(3, 1) == Rational(1, Rational(1, 3)) n3_4 = Rational(3, 4) assert Rational('3/4') == n3_4 assert -Rational('-3/4') == n3_4 assert Rational('.76').limit_denominator(4) == n3_4 assert Rational(19, 25).limit_denominator(4) == n3_4 assert Rational('19/25').limit_denominator(4) == n3_4 assert Rational(1.0, 3) == Rational(1, 3) assert Rational(1, 3.0) == Rational(1, 3) assert Rational(Float(0.5)) == S.Half assert Rational('1e2/1e-2') == Rational(10000) assert Rational('1 234') == Rational(1234) assert Rational('1/1 234') == Rational(1, 1234) assert Rational(-1, 0) is S.ComplexInfinity assert Rational(1, 0) is S.ComplexInfinity # Make sure Rational doesn't lose precision on Floats assert Rational(pi.evalf(100)).evalf(100) == pi.evalf(100) raises(TypeError, lambda: Rational('3**3')) raises(TypeError, lambda: Rational('1/2 + 2/3')) # handle fractions.Fraction instances try: import fractions assert Rational(fractions.Fraction(1, 2)) == S.Half except ImportError: pass assert Rational(mpq(2, 6)) == Rational(1, 3) assert Rational(PythonRational(2, 6)) == Rational(1, 3) assert Rational(2, 4, gcd=1).q == 4 n = Rational(2, -4, gcd=1) assert n.q == 4 assert n.p == -2 def test_Number_new(): """" Test for Number constructor """ # Expected behavior on numbers and strings assert Number(1) is S.One assert Number(2).__class__ is Integer assert Number(-622).__class__ is Integer assert Number(5, 3).__class__ is Rational assert Number(5.3).__class__ is Float assert Number('1') is S.One assert Number('2').__class__ is Integer assert Number('-622').__class__ is Integer assert Number('5/3').__class__ is Rational assert Number('5.3').__class__ is Float raises(ValueError, lambda: Number('cos')) raises(TypeError, lambda: Number(cos)) a = Rational(3, 5) assert Number(a) is a # Check idempotence on Numbers u = ['inf', '-inf', 'nan', 'iNF', '+inf'] v = [oo, -oo, nan, oo, oo] for i, a in zip(u, v): assert Number(i) is a, (i, Number(i), a) def test_Number_cmp(): n1 = Number(1) n2 = Number(2) n3 = Number(-3) assert n1 < n2 assert n1 <= n2 assert n3 < n1 assert n2 > n3 assert n2 >= n3 raises(TypeError, lambda: n1 < S.NaN) raises(TypeError, lambda: n1 <= S.NaN) raises(TypeError, lambda: n1 > S.NaN) raises(TypeError, lambda: n1 >= S.NaN) def test_Rational_cmp(): n1 = Rational(1, 4) n2 = Rational(1, 3) n3 = Rational(2, 4) n4 = Rational(2, -4) n5 = Rational(0) n6 = Rational(1) n7 = Rational(3) n8 = Rational(-3) assert n8 < n5 assert n5 < n6 assert n6 < n7 assert n8 < n7 assert n7 > n8 assert (n1 + 1)**n2 < 2 assert ((n1 + n6)/n7) < 1 assert n4 < n3 assert n2 < n3 assert n1 < n2 assert n3 > n1 assert not n3 < n1 assert not (Rational(-1) > 0) assert Rational(-1) < 0 raises(TypeError, lambda: n1 < S.NaN) raises(TypeError, lambda: n1 <= S.NaN) raises(TypeError, lambda: n1 > S.NaN) raises(TypeError, lambda: n1 >= S.NaN) def test_Float(): def eq(a, b): t = Float("1.0E-15") return (-t < a - b < t) zeros = (0, S.Zero, 0., Float(0)) for i, j in permutations(zeros, 2): assert i == j for z in zeros: assert z in zeros assert S.Zero.is_zero a = Float(2) ** Float(3) assert eq(a.evalf(), Float(8)) assert eq((pi ** -1).evalf(), Float("0.31830988618379067")) a = Float(2) ** Float(4) assert eq(a.evalf(), Float(16)) assert (S(.3) == S(.5)) is False mpf = (0, 5404319552844595, -52, 53) x_str = Float((0, '13333333333333', -52, 53)) x2_str = Float((0, '26666666666666', -53, 54)) x_hex = Float((0, int(0x13333333333333), -52, 53)) x_dec = Float(mpf) assert x_str == x_hex == x_dec == Float(1.2) # x2_str was entered slightly malformed in that the mantissa # was even -- it should be odd and the even part should be # included with the exponent, but this is resolved by normalization # ONLY IF REQUIREMENTS of mpf_norm are met: the bitcount must # be exact: double the mantissa ==> increase bc by 1 assert Float(1.2)._mpf_ == mpf assert x2_str._mpf_ == mpf assert Float((0, int(0), -123, -1)) is S.NaN assert Float((0, int(0), -456, -2)) is S.Infinity assert Float((1, int(0), -789, -3)) is S.NegativeInfinity # if you don't give the full signature, it's not special assert Float((0, int(0), -123)) == Float(0) assert Float((0, int(0), -456)) == Float(0) assert Float((1, int(0), -789)) == Float(0) raises(ValueError, lambda: Float((0, 7, 1, 3), '')) assert Float('0.0').is_finite is True assert Float('0.0').is_negative is False assert Float('0.0').is_positive is False assert Float('0.0').is_infinite is False assert Float('0.0').is_zero is True # rationality properties # if the integer test fails then the use of intlike # should be removed from gamma_functions.py assert Float(1).is_integer is False assert Float(1).is_rational is None assert Float(1).is_irrational is None assert sqrt(2).n(15).is_rational is None assert sqrt(2).n(15).is_irrational is None # do not automatically evalf def teq(a): assert (a.evalf() == a) is False assert (a.evalf() != a) is True assert (a == a.evalf()) is False assert (a != a.evalf()) is True teq(pi) teq(2*pi) teq(cos(0.1, evaluate=False)) # long integer i = 12345678901234567890 assert same_and_same_prec(Float(12, ''), Float('12', '')) assert same_and_same_prec(Float(Integer(i), ''), Float(i, '')) assert same_and_same_prec(Float(i, ''), Float(str(i), 20)) assert same_and_same_prec(Float(str(i)), Float(i, '')) assert same_and_same_prec(Float(i), Float(i, '')) # inexact floats (repeating binary = denom not multiple of 2) # cannot have precision greater than 15 assert Float(.125, 22) == .125 assert Float(2.0, 22) == 2 assert float(Float('.12500000000000001', '')) == .125 raises(ValueError, lambda: Float(.12500000000000001, '')) # allow spaces Float('123 456.123 456') == Float('123456.123456') Integer('123 456') == Integer('123456') Rational('123 456.123 456') == Rational('123456.123456') assert Float(' .3e2') == Float('0.3e2') # allow underscore assert Float('1_23.4_56') == Float('123.456') assert Float('1_23.4_5_6', 12) == Float('123.456', 12) # ...but not in all cases (per Py 3.6) raises(ValueError, lambda: Float('_1')) raises(ValueError, lambda: Float('1_')) raises(ValueError, lambda: Float('1_.')) raises(ValueError, lambda: Float('1._')) raises(ValueError, lambda: Float('1__2')) raises(ValueError, lambda: Float('_inf')) # allow auto precision detection assert Float('.1', '') == Float(.1, 1) assert Float('.125', '') == Float(.125, 3) assert Float('.100', '') == Float(.1, 3) assert Float('2.0', '') == Float('2', 2) raises(ValueError, lambda: Float("12.3d-4", "")) raises(ValueError, lambda: Float(12.3, "")) raises(ValueError, lambda: Float('.')) raises(ValueError, lambda: Float('-.')) zero = Float('0.0') assert Float('-0') == zero assert Float('.0') == zero assert Float('-.0') == zero assert Float('-0.0') == zero assert Float(0.0) == zero assert Float(0) == zero assert Float(0, '') == Float('0', '') assert Float(1) == Float(1.0) assert Float(S.Zero) == zero assert Float(S.One) == Float(1.0) assert Float(decimal.Decimal('0.1'), 3) == Float('.1', 3) assert Float(decimal.Decimal('nan')) is S.NaN assert Float(decimal.Decimal('Infinity')) is S.Infinity assert Float(decimal.Decimal('-Infinity')) is S.NegativeInfinity assert '{:.3f}'.format(Float(4.236622)) == '4.237' assert '{:.35f}'.format(Float(pi.n(40), 40)) == \ '3.14159265358979323846264338327950288' # unicode assert Float('0.73908513321516064100000000') == \ Float('0.73908513321516064100000000') assert Float('0.73908513321516064100000000', 28) == \ Float('0.73908513321516064100000000', 28) # binary precision # Decimal value 0.1 cannot be expressed precisely as a base 2 fraction a = Float(S.One/10, dps=15) b = Float(S.One/10, dps=16) p = Float(S.One/10, precision=53) q = Float(S.One/10, precision=54) assert a._mpf_ == p._mpf_ assert not a._mpf_ == q._mpf_ assert not b._mpf_ == q._mpf_ # Precision specifying errors raises(ValueError, lambda: Float("1.23", dps=3, precision=10)) raises(ValueError, lambda: Float("1.23", dps="", precision=10)) raises(ValueError, lambda: Float("1.23", dps=3, precision="")) raises(ValueError, lambda: Float("1.23", dps="", precision="")) # from NumberSymbol assert same_and_same_prec(Float(pi, 32), pi.evalf(32)) assert same_and_same_prec(Float(Catalan), Catalan.evalf()) # oo and nan u = ['inf', '-inf', 'nan', 'iNF', '+inf'] v = [oo, -oo, nan, oo, oo] for i, a in zip(u, v): assert Float(i) is a def test_zero_not_false(): # https://github.com/sympy/sympy/issues/20796 assert (S(0.0) == S.false) is False assert (S.false == S(0.0)) is False assert (S(0) == S.false) is False assert (S.false == S(0)) is False @conserve_mpmath_dps def test_float_mpf(): import mpmath mpmath.mp.dps = 100 mp_pi = mpmath.pi() assert Float(mp_pi, 100) == Float(mp_pi._mpf_, 100) == pi.evalf(100) mpmath.mp.dps = 15 assert Float(mp_pi, 100) == Float(mp_pi._mpf_, 100) == pi.evalf(100) def test_Float_RealElement(): repi = RealField(dps=100)(pi.evalf(100)) # We still have to pass the precision because Float doesn't know what # RealElement is, but make sure it keeps full precision from the result. assert Float(repi, 100) == pi.evalf(100) def test_Float_default_to_highprec_from_str(): s = str(pi.evalf(128)) assert same_and_same_prec(Float(s), Float(s, '')) def test_Float_eval(): a = Float(3.2) assert (a**2).is_Float def test_Float_issue_2107(): a = Float(0.1, 10) b = Float("0.1", 10) assert a - a == 0 assert a + (-a) == 0 assert S.Zero + a - a == 0 assert S.Zero + a + (-a) == 0 assert b - b == 0 assert b + (-b) == 0 assert S.Zero + b - b == 0 assert S.Zero + b + (-b) == 0 def test_issue_14289(): from sympy.polys.numberfields import to_number_field a = 1 - sqrt(2) b = to_number_field(a) assert b.as_expr() == a assert b.minpoly(a).expand() == 0 def test_Float_from_tuple(): a = Float((0, '1L', 0, 1)) b = Float((0, '1', 0, 1)) assert a == b def test_Infinity(): assert oo != 1 assert 1*oo is oo assert 1 != oo assert oo != -oo assert oo != Symbol("x")**3 assert oo + 1 is oo assert 2 + oo is oo assert 3*oo + 2 is oo assert S.Half**oo == 0 assert S.Half**(-oo) is oo assert -oo*3 is -oo assert oo + oo is oo assert -oo + oo*(-5) is -oo assert 1/oo == 0 assert 1/(-oo) == 0 assert 8/oo == 0 assert oo % 2 is nan assert 2 % oo is nan assert oo/oo is nan assert oo/-oo is nan assert -oo/oo is nan assert -oo/-oo is nan assert oo - oo is nan assert oo - -oo is oo assert -oo - oo is -oo assert -oo - -oo is nan assert oo + -oo is nan assert -oo + oo is nan assert oo + oo is oo assert -oo + oo is nan assert oo + -oo is nan assert -oo + -oo is -oo assert oo*oo is oo assert -oo*oo is -oo assert oo*-oo is -oo assert -oo*-oo is oo assert oo/0 is oo assert -oo/0 is -oo assert 0/oo == 0 assert 0/-oo == 0 assert oo*0 is nan assert -oo*0 is nan assert 0*oo is nan assert 0*-oo is nan assert oo + 0 is oo assert -oo + 0 is -oo assert 0 + oo is oo assert 0 + -oo is -oo assert oo - 0 is oo assert -oo - 0 is -oo assert 0 - oo is -oo assert 0 - -oo is oo assert oo/2 is oo assert -oo/2 is -oo assert oo/-2 is -oo assert -oo/-2 is oo assert oo*2 is oo assert -oo*2 is -oo assert oo*-2 is -oo assert 2/oo == 0 assert 2/-oo == 0 assert -2/oo == 0 assert -2/-oo == 0 assert 2*oo is oo assert 2*-oo is -oo assert -2*oo is -oo assert -2*-oo is oo assert 2 + oo is oo assert 2 - oo is -oo assert -2 + oo is oo assert -2 - oo is -oo assert 2 + -oo is -oo assert 2 - -oo is oo assert -2 + -oo is -oo assert -2 - -oo is oo assert S(2) + oo is oo assert S(2) - oo is -oo assert oo/I == -oo*I assert -oo/I == oo*I assert oo*float(1) == _inf and (oo*float(1)) is oo assert -oo*float(1) == _ninf and (-oo*float(1)) is -oo assert oo/float(1) == _inf and (oo/float(1)) is oo assert -oo/float(1) == _ninf and (-oo/float(1)) is -oo assert oo*float(-1) == _ninf and (oo*float(-1)) is -oo assert -oo*float(-1) == _inf and (-oo*float(-1)) is oo assert oo/float(-1) == _ninf and (oo/float(-1)) is -oo assert -oo/float(-1) == _inf and (-oo/float(-1)) is oo assert oo + float(1) == _inf and (oo + float(1)) is oo assert -oo + float(1) == _ninf and (-oo + float(1)) is -oo assert oo - float(1) == _inf and (oo - float(1)) is oo assert -oo - float(1) == _ninf and (-oo - float(1)) is -oo assert float(1)*oo == _inf and (float(1)*oo) is oo assert float(1)*-oo == _ninf and (float(1)*-oo) is -oo assert float(1)/oo == 0 assert float(1)/-oo == 0 assert float(-1)*oo == _ninf and (float(-1)*oo) is -oo assert float(-1)*-oo == _inf and (float(-1)*-oo) is oo assert float(-1)/oo == 0 assert float(-1)/-oo == 0 assert float(1) + oo is oo assert float(1) + -oo is -oo assert float(1) - oo is -oo assert float(1) - -oo is oo assert oo == float(oo) assert (oo != float(oo)) is False assert type(float(oo)) is float assert -oo == float(-oo) assert (-oo != float(-oo)) is False assert type(float(-oo)) is float assert Float('nan') is nan assert nan*1.0 is nan assert -1.0*nan is nan assert nan*oo is nan assert nan*-oo is nan assert nan/oo is nan assert nan/-oo is nan assert nan + oo is nan assert nan + -oo is nan assert nan - oo is nan assert nan - -oo is nan assert -oo * S.Zero is nan assert oo*nan is nan assert -oo*nan is nan assert oo/nan is nan assert -oo/nan is nan assert oo + nan is nan assert -oo + nan is nan assert oo - nan is nan assert -oo - nan is nan assert S.Zero * oo is nan assert oo.is_Rational is False assert isinstance(oo, Rational) is False assert S.One/oo == 0 assert -S.One/oo == 0 assert S.One/-oo == 0 assert -S.One/-oo == 0 assert S.One*oo is oo assert -S.One*oo is -oo assert S.One*-oo is -oo assert -S.One*-oo is oo assert S.One/nan is nan assert S.One - -oo is oo assert S.One + nan is nan assert S.One - nan is nan assert nan - S.One is nan assert nan/S.One is nan assert -oo - S.One is -oo def test_Infinity_2(): x = Symbol('x') assert oo*x != oo assert oo*(pi - 1) is oo assert oo*(1 - pi) is -oo assert (-oo)*x != -oo assert (-oo)*(pi - 1) is -oo assert (-oo)*(1 - pi) is oo assert (-1)**S.NaN is S.NaN assert oo - _inf is S.NaN assert oo + _ninf is S.NaN assert oo*0 is S.NaN assert oo/_inf is S.NaN assert oo/_ninf is S.NaN assert oo**S.NaN is S.NaN assert -oo + _inf is S.NaN assert -oo - _ninf is S.NaN assert -oo*S.NaN is S.NaN assert -oo*0 is S.NaN assert -oo/_inf is S.NaN assert -oo/_ninf is S.NaN assert -oo/S.NaN is S.NaN assert abs(-oo) is oo assert all((-oo)**i is S.NaN for i in (oo, -oo, S.NaN)) assert (-oo)**3 is -oo assert (-oo)**2 is oo assert abs(S.ComplexInfinity) is oo def test_Mul_Infinity_Zero(): assert Float(0)*_inf is nan assert Float(0)*_ninf is nan assert Float(0)*_inf is nan assert Float(0)*_ninf is nan assert _inf*Float(0) is nan assert _ninf*Float(0) is nan assert _inf*Float(0) is nan assert _ninf*Float(0) is nan def test_Div_By_Zero(): assert 1/S.Zero is zoo assert 1/Float(0) is zoo assert 0/S.Zero is nan assert 0/Float(0) is nan assert S.Zero/0 is nan assert Float(0)/0 is nan assert -1/S.Zero is zoo assert -1/Float(0) is zoo @_both_exp_pow def test_Infinity_inequations(): assert oo > pi assert not (oo < pi) assert exp(-3) < oo assert _inf > pi assert not (_inf < pi) assert exp(-3) < _inf raises(TypeError, lambda: oo < I) raises(TypeError, lambda: oo <= I) raises(TypeError, lambda: oo > I) raises(TypeError, lambda: oo >= I) raises(TypeError, lambda: -oo < I) raises(TypeError, lambda: -oo <= I) raises(TypeError, lambda: -oo > I) raises(TypeError, lambda: -oo >= I) raises(TypeError, lambda: I < oo) raises(TypeError, lambda: I <= oo) raises(TypeError, lambda: I > oo) raises(TypeError, lambda: I >= oo) raises(TypeError, lambda: I < -oo) raises(TypeError, lambda: I <= -oo) raises(TypeError, lambda: I > -oo) raises(TypeError, lambda: I >= -oo) assert oo > -oo and oo >= -oo assert (oo < -oo) == False and (oo <= -oo) == False assert -oo < oo and -oo <= oo assert (-oo > oo) == False and (-oo >= oo) == False assert (oo < oo) == False # issue 7775 assert (oo > oo) == False assert (-oo > -oo) == False and (-oo < -oo) == False assert oo >= oo and oo <= oo and -oo >= -oo and -oo <= -oo assert (-oo < -_inf) == False assert (oo > _inf) == False assert -oo >= -_inf assert oo <= _inf x = Symbol('x') b = Symbol('b', finite=True, real=True) assert (x < oo) == Lt(x, oo) # issue 7775 assert b < oo and b > -oo and b <= oo and b >= -oo assert oo > b and oo >= b and (oo < b) == False and (oo <= b) == False assert (-oo > b) == False and (-oo >= b) == False and -oo < b and -oo <= b assert (oo < x) == Lt(oo, x) and (oo > x) == Gt(oo, x) assert (oo <= x) == Le(oo, x) and (oo >= x) == Ge(oo, x) assert (-oo < x) == Lt(-oo, x) and (-oo > x) == Gt(-oo, x) assert (-oo <= x) == Le(-oo, x) and (-oo >= x) == Ge(-oo, x) def test_NaN(): assert nan is nan assert nan != 1 assert 1*nan is nan assert 1 != nan assert -nan is nan assert oo != Symbol("x")**3 assert 2 + nan is nan assert 3*nan + 2 is nan assert -nan*3 is nan assert nan + nan is nan assert -nan + nan*(-5) is nan assert 8/nan is nan raises(TypeError, lambda: nan > 0) raises(TypeError, lambda: nan < 0) raises(TypeError, lambda: nan >= 0) raises(TypeError, lambda: nan <= 0) raises(TypeError, lambda: 0 < nan) raises(TypeError, lambda: 0 > nan) raises(TypeError, lambda: 0 <= nan) raises(TypeError, lambda: 0 >= nan) assert nan**0 == 1 # as per IEEE 754 assert 1**nan is nan # IEEE 754 is not the best choice for symbolic work # test Pow._eval_power's handling of NaN assert Pow(nan, 0, evaluate=False)**2 == 1 for n in (1, 1., S.One, S.NegativeOne, Float(1)): assert n + nan is nan assert n - nan is nan assert nan + n is nan assert nan - n is nan assert n/nan is nan assert nan/n is nan def test_special_numbers(): assert isinstance(S.NaN, Number) is True assert isinstance(S.Infinity, Number) is True assert isinstance(S.NegativeInfinity, Number) is True assert S.NaN.is_number is True assert S.Infinity.is_number is True assert S.NegativeInfinity.is_number is True assert S.ComplexInfinity.is_number is True assert isinstance(S.NaN, Rational) is False assert isinstance(S.Infinity, Rational) is False assert isinstance(S.NegativeInfinity, Rational) is False assert S.NaN.is_rational is not True assert S.Infinity.is_rational is not True assert S.NegativeInfinity.is_rational is not True def test_powers(): assert integer_nthroot(1, 2) == (1, True) assert integer_nthroot(1, 5) == (1, True) assert integer_nthroot(2, 1) == (2, True) assert integer_nthroot(2, 2) == (1, False) assert integer_nthroot(2, 5) == (1, False) assert integer_nthroot(4, 2) == (2, True) assert integer_nthroot(123**25, 25) == (123, True) assert integer_nthroot(123**25 + 1, 25) == (123, False) assert integer_nthroot(123**25 - 1, 25) == (122, False) assert integer_nthroot(1, 1) == (1, True) assert integer_nthroot(0, 1) == (0, True) assert integer_nthroot(0, 3) == (0, True) assert integer_nthroot(10000, 1) == (10000, True) assert integer_nthroot(4, 2) == (2, True) assert integer_nthroot(16, 2) == (4, True) assert integer_nthroot(26, 2) == (5, False) assert integer_nthroot(1234567**7, 7) == (1234567, True) assert integer_nthroot(1234567**7 + 1, 7) == (1234567, False) assert integer_nthroot(1234567**7 - 1, 7) == (1234566, False) b = 25**1000 assert integer_nthroot(b, 1000) == (25, True) assert integer_nthroot(b + 1, 1000) == (25, False) assert integer_nthroot(b - 1, 1000) == (24, False) c = 10**400 c2 = c**2 assert integer_nthroot(c2, 2) == (c, True) assert integer_nthroot(c2 + 1, 2) == (c, False) assert integer_nthroot(c2 - 1, 2) == (c - 1, False) assert integer_nthroot(2, 10**10) == (1, False) p, r = integer_nthroot(int(factorial(10000)), 100) assert p % (10**10) == 5322420655 assert not r # Test that this is fast assert integer_nthroot(2, 10**10) == (1, False) # output should be int if possible assert type(integer_nthroot(2**61, 2)[0]) is int def test_integer_nthroot_overflow(): assert integer_nthroot(10**(50*50), 50) == (10**50, True) assert integer_nthroot(10**100000, 10000) == (10**10, True) def test_integer_log(): raises(ValueError, lambda: integer_log(2, 1)) raises(ValueError, lambda: integer_log(0, 2)) raises(ValueError, lambda: integer_log(1.1, 2)) raises(ValueError, lambda: integer_log(1, 2.2)) assert integer_log(1, 2) == (0, True) assert integer_log(1, 3) == (0, True) assert integer_log(2, 3) == (0, False) assert integer_log(3, 3) == (1, True) assert integer_log(3*2, 3) == (1, False) assert integer_log(3**2, 3) == (2, True) assert integer_log(3*4, 3) == (2, False) assert integer_log(3**3, 3) == (3, True) assert integer_log(27, 5) == (2, False) assert integer_log(2, 3) == (0, False) assert integer_log(-4, -2) == (2, False) assert integer_log(27, -3) == (3, False) assert integer_log(-49, 7) == (0, False) assert integer_log(-49, -7) == (2, False) def test_isqrt(): from math import sqrt as _sqrt limit = 4503599761588223 assert int(_sqrt(limit)) == integer_nthroot(limit, 2)[0] assert int(_sqrt(limit + 1)) != integer_nthroot(limit + 1, 2)[0] assert isqrt(limit + 1) == integer_nthroot(limit + 1, 2)[0] assert isqrt(limit + S.Half) == integer_nthroot(limit, 2)[0] assert isqrt(limit + 1 + S.Half) == integer_nthroot(limit + 1, 2)[0] assert isqrt(limit + 2 + S.Half) == integer_nthroot(limit + 2, 2)[0] # Regression tests for https://github.com/sympy/sympy/issues/17034 assert isqrt(4503599761588224) == 67108864 assert isqrt(9999999999999999) == 99999999 # Other corner cases, especially involving non-integers. raises(ValueError, lambda: isqrt(-1)) raises(ValueError, lambda: isqrt(-10**1000)) raises(ValueError, lambda: isqrt(Rational(-1, 2))) tiny = Rational(1, 10**1000) raises(ValueError, lambda: isqrt(-tiny)) assert isqrt(1-tiny) == 0 assert isqrt(4503599761588224-tiny) == 67108864 assert isqrt(10**100 - tiny) == 10**50 - 1 # Check that using an inaccurate math.sqrt doesn't affect the results. from sympy.core import power old_sqrt = power._sqrt power._sqrt = lambda x: 2.999999999 try: assert isqrt(9) == 3 assert isqrt(10000) == 100 finally: power._sqrt = old_sqrt def test_powers_Integer(): """Test Integer._eval_power""" # check infinity assert S.One ** S.Infinity is S.NaN assert S.NegativeOne** S.Infinity is S.NaN assert S(2) ** S.Infinity is S.Infinity assert S(-2)** S.Infinity == S.Infinity + S.Infinity * S.ImaginaryUnit assert S(0) ** S.Infinity is S.Zero # check Nan assert S.One ** S.NaN is S.NaN assert S.NegativeOne ** S.NaN is S.NaN # check for exact roots assert S.NegativeOne ** Rational(6, 5) == - (-1)**(S.One/5) assert sqrt(S(4)) == 2 assert sqrt(S(-4)) == I * 2 assert S(16) ** Rational(1, 4) == 2 assert S(-16) ** Rational(1, 4) == 2 * (-1)**Rational(1, 4) assert S(9) ** Rational(3, 2) == 27 assert S(-9) ** Rational(3, 2) == -27*I assert S(27) ** Rational(2, 3) == 9 assert S(-27) ** Rational(2, 3) == 9 * (S.NegativeOne ** Rational(2, 3)) assert (-2) ** Rational(-2, 1) == Rational(1, 4) # not exact roots assert sqrt(-3) == I*sqrt(3) assert (3) ** (Rational(3, 2)) == 3 * sqrt(3) assert (-3) ** (Rational(3, 2)) == - 3 * sqrt(-3) assert (-3) ** (Rational(5, 2)) == 9 * I * sqrt(3) assert (-3) ** (Rational(7, 2)) == - I * 27 * sqrt(3) assert (2) ** (Rational(3, 2)) == 2 * sqrt(2) assert (2) ** (Rational(-3, 2)) == sqrt(2) / 4 assert (81) ** (Rational(2, 3)) == 9 * (S(3) ** (Rational(2, 3))) assert (-81) ** (Rational(2, 3)) == 9 * (S(-3) ** (Rational(2, 3))) assert (-3) ** Rational(-7, 3) == \ -(-1)**Rational(2, 3)*3**Rational(2, 3)/27 assert (-3) ** Rational(-2, 3) == \ -(-1)**Rational(1, 3)*3**Rational(1, 3)/3 # join roots assert sqrt(6) + sqrt(24) == 3*sqrt(6) assert sqrt(2) * sqrt(3) == sqrt(6) # separate symbols & constansts x = Symbol("x") assert sqrt(49 * x) == 7 * sqrt(x) assert sqrt((3 - sqrt(pi)) ** 2) == 3 - sqrt(pi) # check that it is fast for big numbers assert (2**64 + 1) ** Rational(4, 3) assert (2**64 + 1) ** Rational(17, 25) # negative rational power and negative base assert (-3) ** Rational(-7, 3) == \ -(-1)**Rational(2, 3)*3**Rational(2, 3)/27 assert (-3) ** Rational(-2, 3) == \ -(-1)**Rational(1, 3)*3**Rational(1, 3)/3 assert (-2) ** Rational(-10, 3) == \ (-1)**Rational(2, 3)*2**Rational(2, 3)/16 assert abs(Pow(-2, Rational(-10, 3)).n() - Pow(-2, Rational(-10, 3), evaluate=False).n()) < 1e-16 # negative base and rational power with some simplification assert (-8) ** Rational(2, 5) == \ 2*(-1)**Rational(2, 5)*2**Rational(1, 5) assert (-4) ** Rational(9, 5) == \ -8*(-1)**Rational(4, 5)*2**Rational(3, 5) assert S(1234).factors() == {617: 1, 2: 1} assert Rational(2*3, 3*5*7).factors() == {2: 1, 5: -1, 7: -1} # test that eval_power factors numbers bigger than # the current limit in factor_trial_division (2**15) from sympy import nextprime n = nextprime(2**15) assert sqrt(n**2) == n assert sqrt(n**3) == n*sqrt(n) assert sqrt(4*n) == 2*sqrt(n) # check that factors of base with powers sharing gcd with power are removed assert (2**4*3)**Rational(1, 6) == 2**Rational(2, 3)*3**Rational(1, 6) assert (2**4*3)**Rational(5, 6) == 8*2**Rational(1, 3)*3**Rational(5, 6) # check that bases sharing a gcd are exptracted assert 2**Rational(1, 3)*3**Rational(1, 4)*6**Rational(1, 5) == \ 2**Rational(8, 15)*3**Rational(9, 20) assert sqrt(8)*24**Rational(1, 3)*6**Rational(1, 5) == \ 4*2**Rational(7, 10)*3**Rational(8, 15) assert sqrt(8)*(-24)**Rational(1, 3)*(-6)**Rational(1, 5) == \ 4*(-3)**Rational(8, 15)*2**Rational(7, 10) assert 2**Rational(1, 3)*2**Rational(8, 9) == 2*2**Rational(2, 9) assert 2**Rational(2, 3)*6**Rational(1, 3) == 2*3**Rational(1, 3) assert 2**Rational(2, 3)*6**Rational(8, 9) == \ 2*2**Rational(5, 9)*3**Rational(8, 9) assert (-2)**Rational(2, S(3))*(-4)**Rational(1, S(3)) == -2*2**Rational(1, 3) assert 3*Pow(3, 2, evaluate=False) == 3**3 assert 3*Pow(3, Rational(-1, 3), evaluate=False) == 3**Rational(2, 3) assert (-2)**Rational(1, 3)*(-3)**Rational(1, 4)*(-5)**Rational(5, 6) == \ -(-1)**Rational(5, 12)*2**Rational(1, 3)*3**Rational(1, 4) * \ 5**Rational(5, 6) assert Integer(-2)**Symbol('', even=True) == \ Integer(2)**Symbol('', even=True) assert (-1)**Float(.5) == 1.0*I def test_powers_Rational(): """Test Rational._eval_power""" # check infinity assert S.Half ** S.Infinity == 0 assert Rational(3, 2) ** S.Infinity is S.Infinity assert Rational(-1, 2) ** S.Infinity == 0 assert Rational(-3, 2) ** S.Infinity == \ S.Infinity + S.Infinity * S.ImaginaryUnit # check Nan assert Rational(3, 4) ** S.NaN is S.NaN assert Rational(-2, 3) ** S.NaN is S.NaN # exact roots on numerator assert sqrt(Rational(4, 3)) == 2 * sqrt(3) / 3 assert Rational(4, 3) ** Rational(3, 2) == 8 * sqrt(3) / 9 assert sqrt(Rational(-4, 3)) == I * 2 * sqrt(3) / 3 assert Rational(-4, 3) ** Rational(3, 2) == - I * 8 * sqrt(3) / 9 assert Rational(27, 2) ** Rational(1, 3) == 3 * (2 ** Rational(2, 3)) / 2 assert Rational(5**3, 8**3) ** Rational(4, 3) == Rational(5**4, 8**4) # exact root on denominator assert sqrt(Rational(1, 4)) == S.Half assert sqrt(Rational(1, -4)) == I * S.Half assert sqrt(Rational(3, 4)) == sqrt(3) / 2 assert sqrt(Rational(3, -4)) == I * sqrt(3) / 2 assert Rational(5, 27) ** Rational(1, 3) == (5 ** Rational(1, 3)) / 3 # not exact roots assert sqrt(S.Half) == sqrt(2) / 2 assert sqrt(Rational(-4, 7)) == I * sqrt(Rational(4, 7)) assert Rational(-3, 2)**Rational(-7, 3) == \ -4*(-1)**Rational(2, 3)*2**Rational(1, 3)*3**Rational(2, 3)/27 assert Rational(-3, 2)**Rational(-2, 3) == \ -(-1)**Rational(1, 3)*2**Rational(2, 3)*3**Rational(1, 3)/3 assert Rational(-3, 2)**Rational(-10, 3) == \ 8*(-1)**Rational(2, 3)*2**Rational(1, 3)*3**Rational(2, 3)/81 assert abs(Pow(Rational(-2, 3), Rational(-7, 4)).n() - Pow(Rational(-2, 3), Rational(-7, 4), evaluate=False).n()) < 1e-16 # negative integer power and negative rational base assert Rational(-2, 3) ** Rational(-2, 1) == Rational(9, 4) a = Rational(1, 10) assert a**Float(a, 2) == Float(a, 2)**Float(a, 2) assert Rational(-2, 3)**Symbol('', even=True) == \ Rational(2, 3)**Symbol('', even=True) def test_powers_Float(): assert str((S('-1/10')**S('3/10')).n()) == str(Float(-.1)**(.3)) def test_lshift_Integer(): assert Integer(0) << Integer(2) == Integer(0) assert Integer(0) << 2 == Integer(0) assert 0 << Integer(2) == Integer(0) assert Integer(0b11) << Integer(0) == Integer(0b11) assert Integer(0b11) << 0 == Integer(0b11) assert 0b11 << Integer(0) == Integer(0b11) assert Integer(0b11) << Integer(2) == Integer(0b11 << 2) assert Integer(0b11) << 2 == Integer(0b11 << 2) assert 0b11 << Integer(2) == Integer(0b11 << 2) assert Integer(-0b11) << Integer(2) == Integer(-0b11 << 2) assert Integer(-0b11) << 2 == Integer(-0b11 << 2) assert -0b11 << Integer(2) == Integer(-0b11 << 2) raises(TypeError, lambda: Integer(2) << 0.0) raises(TypeError, lambda: 0.0 << Integer(2)) raises(ValueError, lambda: Integer(1) << Integer(-1)) def test_rshift_Integer(): assert Integer(0) >> Integer(2) == Integer(0) assert Integer(0) >> 2 == Integer(0) assert 0 >> Integer(2) == Integer(0) assert Integer(0b11) >> Integer(0) == Integer(0b11) assert Integer(0b11) >> 0 == Integer(0b11) assert 0b11 >> Integer(0) == Integer(0b11) assert Integer(0b11) >> Integer(2) == Integer(0) assert Integer(0b11) >> 2 == Integer(0) assert 0b11 >> Integer(2) == Integer(0) assert Integer(-0b11) >> Integer(2) == Integer(-1) assert Integer(-0b11) >> 2 == Integer(-1) assert -0b11 >> Integer(2) == Integer(-1) assert Integer(0b1100) >> Integer(2) == Integer(0b1100 >> 2) assert Integer(0b1100) >> 2 == Integer(0b1100 >> 2) assert 0b1100 >> Integer(2) == Integer(0b1100 >> 2) assert Integer(-0b1100) >> Integer(2) == Integer(-0b1100 >> 2) assert Integer(-0b1100) >> 2 == Integer(-0b1100 >> 2) assert -0b1100 >> Integer(2) == Integer(-0b1100 >> 2) raises(TypeError, lambda: Integer(0b10) >> 0.0) raises(TypeError, lambda: 0.0 >> Integer(2)) raises(ValueError, lambda: Integer(1) >> Integer(-1)) def test_and_Integer(): assert Integer(0b01010101) & Integer(0b10101010) == Integer(0) assert Integer(0b01010101) & 0b10101010 == Integer(0) assert 0b01010101 & Integer(0b10101010) == Integer(0) assert Integer(0b01010101) & Integer(0b11011011) == Integer(0b01010001) assert Integer(0b01010101) & 0b11011011 == Integer(0b01010001) assert 0b01010101 & Integer(0b11011011) == Integer(0b01010001) assert -Integer(0b01010101) & Integer(0b11011011) == Integer(-0b01010101 & 0b11011011) assert Integer(-0b01010101) & 0b11011011 == Integer(-0b01010101 & 0b11011011) assert -0b01010101 & Integer(0b11011011) == Integer(-0b01010101 & 0b11011011) assert Integer(0b01010101) & -Integer(0b11011011) == Integer(0b01010101 & -0b11011011) assert Integer(0b01010101) & -0b11011011 == Integer(0b01010101 & -0b11011011) assert 0b01010101 & Integer(-0b11011011) == Integer(0b01010101 & -0b11011011) raises(TypeError, lambda: Integer(2) & 0.0) raises(TypeError, lambda: 0.0 & Integer(2)) def test_xor_Integer(): assert Integer(0b01010101) ^ Integer(0b11111111) == Integer(0b10101010) assert Integer(0b01010101) ^ 0b11111111 == Integer(0b10101010) assert 0b01010101 ^ Integer(0b11111111) == Integer(0b10101010) assert Integer(0b01010101) ^ Integer(0b11011011) == Integer(0b10001110) assert Integer(0b01010101) ^ 0b11011011 == Integer(0b10001110) assert 0b01010101 ^ Integer(0b11011011) == Integer(0b10001110) assert -Integer(0b01010101) ^ Integer(0b11011011) == Integer(-0b01010101 ^ 0b11011011) assert Integer(-0b01010101) ^ 0b11011011 == Integer(-0b01010101 ^ 0b11011011) assert -0b01010101 ^ Integer(0b11011011) == Integer(-0b01010101 ^ 0b11011011) assert Integer(0b01010101) ^ -Integer(0b11011011) == Integer(0b01010101 ^ -0b11011011) assert Integer(0b01010101) ^ -0b11011011 == Integer(0b01010101 ^ -0b11011011) assert 0b01010101 ^ Integer(-0b11011011) == Integer(0b01010101 ^ -0b11011011) raises(TypeError, lambda: Integer(2) ^ 0.0) raises(TypeError, lambda: 0.0 ^ Integer(2)) def test_or_Integer(): assert Integer(0b01010101) | Integer(0b10101010) == Integer(0b11111111) assert Integer(0b01010101) | 0b10101010 == Integer(0b11111111) assert 0b01010101 | Integer(0b10101010) == Integer(0b11111111) assert Integer(0b01010101) | Integer(0b11011011) == Integer(0b11011111) assert Integer(0b01010101) | 0b11011011 == Integer(0b11011111) assert 0b01010101 | Integer(0b11011011) == Integer(0b11011111) assert -Integer(0b01010101) | Integer(0b11011011) == Integer(-0b01010101 | 0b11011011) assert Integer(-0b01010101) | 0b11011011 == Integer(-0b01010101 | 0b11011011) assert -0b01010101 | Integer(0b11011011) == Integer(-0b01010101 | 0b11011011) assert Integer(0b01010101) | -Integer(0b11011011) == Integer(0b01010101 | -0b11011011) assert Integer(0b01010101) | -0b11011011 == Integer(0b01010101 | -0b11011011) assert 0b01010101 | Integer(-0b11011011) == Integer(0b01010101 | -0b11011011) raises(TypeError, lambda: Integer(2) | 0.0) raises(TypeError, lambda: 0.0 | Integer(2)) def test_invert_Integer(): assert ~Integer(0b01010101) == Integer(-0b01010110) assert ~Integer(0b01010101) == Integer(~0b01010101) assert ~(~Integer(0b01010101)) == Integer(0b01010101) def test_abs1(): assert Rational(1, 6) != Rational(-1, 6) assert abs(Rational(1, 6)) == abs(Rational(-1, 6)) def test_accept_int(): assert Float(4) == 4 def test_dont_accept_str(): assert Float("0.2") != "0.2" assert not (Float("0.2") == "0.2") def test_int(): a = Rational(5) assert int(a) == 5 a = Rational(9, 10) assert int(a) == int(-a) == 0 assert 1/(-1)**Rational(2, 3) == -(-1)**Rational(1, 3) # issue 10368 a = Rational(32442016954, 78058255275) assert type(int(a)) is type(int(-a)) is int def test_int_NumberSymbols(): assert int(Catalan) == 0 assert int(EulerGamma) == 0 assert int(pi) == 3 assert int(E) == 2 assert int(GoldenRatio) == 1 assert int(TribonacciConstant) == 1 for i in [Catalan, E, EulerGamma, GoldenRatio, TribonacciConstant, pi]: a, b = i.approximation_interval(Integer) ia = int(i) assert ia == a assert isinstance(ia, int) assert b == a + 1 assert a.is_Integer and b.is_Integer def test_real_bug(): x = Symbol("x") assert str(2.0*x*x) in ["(2.0*x)*x", "2.0*x**2", "2.00000000000000*x**2"] assert str(2.1*x*x) != "(2.0*x)*x" def test_bug_sqrt(): assert ((sqrt(Rational(2)) + 1)*(sqrt(Rational(2)) - 1)).expand() == 1 def test_pi_Pi(): "Test that pi (instance) is imported, but Pi (class) is not" from sympy import pi # noqa with raises(ImportError): from sympy import Pi # noqa def test_no_len(): # there should be no len for numbers raises(TypeError, lambda: len(Rational(2))) raises(TypeError, lambda: len(Rational(2, 3))) raises(TypeError, lambda: len(Integer(2))) def test_issue_3321(): assert sqrt(Rational(1, 5)) == Rational(1, 5)**S.Half assert 5 * sqrt(Rational(1, 5)) == sqrt(5) def test_issue_3692(): assert ((-1)**Rational(1, 6)).expand(complex=True) == I/2 + sqrt(3)/2 assert ((-5)**Rational(1, 6)).expand(complex=True) == \ 5**Rational(1, 6)*I/2 + 5**Rational(1, 6)*sqrt(3)/2 assert ((-64)**Rational(1, 6)).expand(complex=True) == I + sqrt(3) def test_issue_3423(): x = Symbol("x") assert sqrt(x - 1).as_base_exp() == (x - 1, S.Half) assert sqrt(x - 1) != I*sqrt(1 - x) def test_issue_3449(): x = Symbol("x") assert sqrt(x - 1).subs(x, 5) == 2 def test_issue_13890(): x = Symbol("x") e = (-x/4 - S.One/12)**x - 1 f = simplify(e) a = Rational(9, 5) assert abs(e.subs(x,a).evalf() - f.subs(x,a).evalf()) < 1e-15 def test_Integer_factors(): def F(i): return Integer(i).factors() assert F(1) == {} assert F(2) == {2: 1} assert F(3) == {3: 1} assert F(4) == {2: 2} assert F(5) == {5: 1} assert F(6) == {2: 1, 3: 1} assert F(7) == {7: 1} assert F(8) == {2: 3} assert F(9) == {3: 2} assert F(10) == {2: 1, 5: 1} assert F(11) == {11: 1} assert F(12) == {2: 2, 3: 1} assert F(13) == {13: 1} assert F(14) == {2: 1, 7: 1} assert F(15) == {3: 1, 5: 1} assert F(16) == {2: 4} assert F(17) == {17: 1} assert F(18) == {2: 1, 3: 2} assert F(19) == {19: 1} assert F(20) == {2: 2, 5: 1} assert F(21) == {3: 1, 7: 1} assert F(22) == {2: 1, 11: 1} assert F(23) == {23: 1} assert F(24) == {2: 3, 3: 1} assert F(25) == {5: 2} assert F(26) == {2: 1, 13: 1} assert F(27) == {3: 3} assert F(28) == {2: 2, 7: 1} assert F(29) == {29: 1} assert F(30) == {2: 1, 3: 1, 5: 1} assert F(31) == {31: 1} assert F(32) == {2: 5} assert F(33) == {3: 1, 11: 1} assert F(34) == {2: 1, 17: 1} assert F(35) == {5: 1, 7: 1} assert F(36) == {2: 2, 3: 2} assert F(37) == {37: 1} assert F(38) == {2: 1, 19: 1} assert F(39) == {3: 1, 13: 1} assert F(40) == {2: 3, 5: 1} assert F(41) == {41: 1} assert F(42) == {2: 1, 3: 1, 7: 1} assert F(43) == {43: 1} assert F(44) == {2: 2, 11: 1} assert F(45) == {3: 2, 5: 1} assert F(46) == {2: 1, 23: 1} assert F(47) == {47: 1} assert F(48) == {2: 4, 3: 1} assert F(49) == {7: 2} assert F(50) == {2: 1, 5: 2} assert F(51) == {3: 1, 17: 1} def test_Rational_factors(): def F(p, q, visual=None): return Rational(p, q).factors(visual=visual) assert F(2, 3) == {2: 1, 3: -1} assert F(2, 9) == {2: 1, 3: -2} assert F(2, 15) == {2: 1, 3: -1, 5: -1} assert F(6, 10) == {3: 1, 5: -1} def test_issue_4107(): assert pi*(E + 10) + pi*(-E - 10) != 0 assert pi*(E + 10**10) + pi*(-E - 10**10) != 0 assert pi*(E + 10**20) + pi*(-E - 10**20) != 0 assert pi*(E + 10**80) + pi*(-E - 10**80) != 0 assert (pi*(E + 10) + pi*(-E - 10)).expand() == 0 assert (pi*(E + 10**10) + pi*(-E - 10**10)).expand() == 0 assert (pi*(E + 10**20) + pi*(-E - 10**20)).expand() == 0 assert (pi*(E + 10**80) + pi*(-E - 10**80)).expand() == 0 def test_IntegerInteger(): a = Integer(4) b = Integer(a) assert a == b def test_Rational_gcd_lcm_cofactors(): assert Integer(4).gcd(2) == Integer(2) assert Integer(4).lcm(2) == Integer(4) assert Integer(4).gcd(Integer(2)) == Integer(2) assert Integer(4).lcm(Integer(2)) == Integer(4) a, b = 720**99911, 480**12342 assert Integer(a).lcm(b) == a*b/Integer(a).gcd(b) assert Integer(4).gcd(3) == Integer(1) assert Integer(4).lcm(3) == Integer(12) assert Integer(4).gcd(Integer(3)) == Integer(1) assert Integer(4).lcm(Integer(3)) == Integer(12) assert Rational(4, 3).gcd(2) == Rational(2, 3) assert Rational(4, 3).lcm(2) == Integer(4) assert Rational(4, 3).gcd(Integer(2)) == Rational(2, 3) assert Rational(4, 3).lcm(Integer(2)) == Integer(4) assert Integer(4).gcd(Rational(2, 9)) == Rational(2, 9) assert Integer(4).lcm(Rational(2, 9)) == Integer(4) assert Rational(4, 3).gcd(Rational(2, 9)) == Rational(2, 9) assert Rational(4, 3).lcm(Rational(2, 9)) == Rational(4, 3) assert Rational(4, 5).gcd(Rational(2, 9)) == Rational(2, 45) assert Rational(4, 5).lcm(Rational(2, 9)) == Integer(4) assert Rational(5, 9).lcm(Rational(3, 7)) == Rational(Integer(5).lcm(3),Integer(9).gcd(7)) assert Integer(4).cofactors(2) == (Integer(2), Integer(2), Integer(1)) assert Integer(4).cofactors(Integer(2)) == \ (Integer(2), Integer(2), Integer(1)) assert Integer(4).gcd(Float(2.0)) == S.One assert Integer(4).lcm(Float(2.0)) == Float(8.0) assert Integer(4).cofactors(Float(2.0)) == (S.One, Integer(4), Float(2.0)) assert S.Half.gcd(Float(2.0)) == S.One assert S.Half.lcm(Float(2.0)) == Float(1.0) assert S.Half.cofactors(Float(2.0)) == \ (S.One, S.Half, Float(2.0)) def test_Float_gcd_lcm_cofactors(): assert Float(2.0).gcd(Integer(4)) == S.One assert Float(2.0).lcm(Integer(4)) == Float(8.0) assert Float(2.0).cofactors(Integer(4)) == (S.One, Float(2.0), Integer(4)) assert Float(2.0).gcd(S.Half) == S.One assert Float(2.0).lcm(S.Half) == Float(1.0) assert Float(2.0).cofactors(S.Half) == \ (S.One, Float(2.0), S.Half) def test_issue_4611(): assert abs(pi._evalf(50) - 3.14159265358979) < 1e-10 assert abs(E._evalf(50) - 2.71828182845905) < 1e-10 assert abs(Catalan._evalf(50) - 0.915965594177219) < 1e-10 assert abs(EulerGamma._evalf(50) - 0.577215664901533) < 1e-10 assert abs(GoldenRatio._evalf(50) - 1.61803398874989) < 1e-10 assert abs(TribonacciConstant._evalf(50) - 1.83928675521416) < 1e-10 x = Symbol("x") assert (pi + x).evalf() == pi.evalf() + x assert (E + x).evalf() == E.evalf() + x assert (Catalan + x).evalf() == Catalan.evalf() + x assert (EulerGamma + x).evalf() == EulerGamma.evalf() + x assert (GoldenRatio + x).evalf() == GoldenRatio.evalf() + x assert (TribonacciConstant + x).evalf() == TribonacciConstant.evalf() + x @conserve_mpmath_dps def test_conversion_to_mpmath(): assert mpmath.mpmathify(Integer(1)) == mpmath.mpf(1) assert mpmath.mpmathify(S.Half) == mpmath.mpf(0.5) assert mpmath.mpmathify(Float('1.23', 15)) == mpmath.mpf('1.23') assert mpmath.mpmathify(I) == mpmath.mpc(1j) assert mpmath.mpmathify(1 + 2*I) == mpmath.mpc(1 + 2j) assert mpmath.mpmathify(1.0 + 2*I) == mpmath.mpc(1 + 2j) assert mpmath.mpmathify(1 + 2.0*I) == mpmath.mpc(1 + 2j) assert mpmath.mpmathify(1.0 + 2.0*I) == mpmath.mpc(1 + 2j) assert mpmath.mpmathify(S.Half + S.Half*I) == mpmath.mpc(0.5 + 0.5j) assert mpmath.mpmathify(2*I) == mpmath.mpc(2j) assert mpmath.mpmathify(2.0*I) == mpmath.mpc(2j) assert mpmath.mpmathify(S.Half*I) == mpmath.mpc(0.5j) mpmath.mp.dps = 100 assert mpmath.mpmathify(pi.evalf(100) + pi.evalf(100)*I) == mpmath.pi + mpmath.pi*mpmath.j assert mpmath.mpmathify(pi.evalf(100)*I) == mpmath.pi*mpmath.j def test_relational(): # real x = S(.1) assert (x != cos) is True assert (x == cos) is False # rational x = Rational(1, 3) assert (x != cos) is True assert (x == cos) is False # integer defers to rational so these tests are omitted # number symbol x = pi assert (x != cos) is True assert (x == cos) is False def test_Integer_as_index(): assert 'hello'[Integer(2):] == 'llo' def test_Rational_int(): assert int( Rational(7, 5)) == 1 assert int( S.Half) == 0 assert int(Rational(-1, 2)) == 0 assert int(-Rational(7, 5)) == -1 def test_zoo(): b = Symbol('b', finite=True) nz = Symbol('nz', nonzero=True) p = Symbol('p', positive=True) n = Symbol('n', negative=True) im = Symbol('i', imaginary=True) c = Symbol('c', complex=True) pb = Symbol('pb', positive=True, finite=True) nb = Symbol('nb', negative=True, finite=True) imb = Symbol('ib', imaginary=True, finite=True) for i in [I, S.Infinity, S.NegativeInfinity, S.Zero, S.One, S.Pi, S.Half, S(3), log(3), b, nz, p, n, im, pb, nb, imb, c]: if i.is_finite and (i.is_real or i.is_imaginary): assert i + zoo is zoo assert i - zoo is zoo assert zoo + i is zoo assert zoo - i is zoo elif i.is_finite is not False: assert (i + zoo).is_Add assert (i - zoo).is_Add assert (zoo + i).is_Add assert (zoo - i).is_Add else: assert (i + zoo) is S.NaN assert (i - zoo) is S.NaN assert (zoo + i) is S.NaN assert (zoo - i) is S.NaN if fuzzy_not(i.is_zero) and (i.is_extended_real or i.is_imaginary): assert i*zoo is zoo assert zoo*i is zoo elif i.is_zero: assert i*zoo is S.NaN assert zoo*i is S.NaN else: assert (i*zoo).is_Mul assert (zoo*i).is_Mul if fuzzy_not((1/i).is_zero) and (i.is_real or i.is_imaginary): assert zoo/i is zoo elif (1/i).is_zero: assert zoo/i is S.NaN elif i.is_zero: assert zoo/i is zoo else: assert (zoo/i).is_Mul assert (I*oo).is_Mul # allow directed infinity assert zoo + zoo is S.NaN assert zoo * zoo is zoo assert zoo - zoo is S.NaN assert zoo/zoo is S.NaN assert zoo**zoo is S.NaN assert zoo**0 is S.One assert zoo**2 is zoo assert 1/zoo is S.Zero assert Mul.flatten([S.NegativeOne, oo, S(0)]) == ([S.NaN], [], None) def test_issue_4122(): x = Symbol('x', nonpositive=True) assert oo + x is oo x = Symbol('x', extended_nonpositive=True) assert (oo + x).is_Add x = Symbol('x', finite=True) assert (oo + x).is_Add # x could be imaginary x = Symbol('x', nonnegative=True) assert oo + x is oo x = Symbol('x', extended_nonnegative=True) assert oo + x is oo x = Symbol('x', finite=True, real=True) assert oo + x is oo # similarly for negative infinity x = Symbol('x', nonnegative=True) assert -oo + x is -oo x = Symbol('x', extended_nonnegative=True) assert (-oo + x).is_Add x = Symbol('x', finite=True) assert (-oo + x).is_Add x = Symbol('x', nonpositive=True) assert -oo + x is -oo x = Symbol('x', extended_nonpositive=True) assert -oo + x is -oo x = Symbol('x', finite=True, real=True) assert -oo + x is -oo def test_GoldenRatio_expand(): assert GoldenRatio.expand(func=True) == S.Half + sqrt(5)/2 def test_TribonacciConstant_expand(): assert TribonacciConstant.expand(func=True) == \ (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 def test_as_content_primitive(): assert S.Zero.as_content_primitive() == (1, 0) assert S.Half.as_content_primitive() == (S.Half, 1) assert (Rational(-1, 2)).as_content_primitive() == (S.Half, -1) assert S(3).as_content_primitive() == (3, 1) assert S(3.1).as_content_primitive() == (1, 3.1) def test_hashing_sympy_integers(): # Test for issue 5072 assert {Integer(3)} == {int(3)} assert hash(Integer(4)) == hash(int(4)) def test_rounding_issue_4172(): assert int((E**100).round()) == \ 26881171418161354484126255515800135873611119 assert int((pi**100).round()) == \ 51878483143196131920862615246303013562686760680406 assert int((Rational(1)/EulerGamma**100).round()) == \ 734833795660954410469466 @XFAIL def test_mpmath_issues(): from mpmath.libmp.libmpf import _normalize import mpmath.libmp as mlib rnd = mlib.round_nearest mpf = (0, int(0), -123, -1, 53, rnd) # nan assert _normalize(mpf, 53) != (0, int(0), 0, 0) mpf = (0, int(0), -456, -2, 53, rnd) # +inf assert _normalize(mpf, 53) != (0, int(0), 0, 0) mpf = (1, int(0), -789, -3, 53, rnd) # -inf assert _normalize(mpf, 53) != (0, int(0), 0, 0) from mpmath.libmp.libmpf import fnan assert mlib.mpf_eq(fnan, fnan) def test_Catalan_EulerGamma_prec(): n = GoldenRatio f = Float(n.n(), 5) assert f._mpf_ == (0, int(212079), -17, 18) assert f._prec == 20 assert n._as_mpf_val(20) == f._mpf_ n = EulerGamma f = Float(n.n(), 5) assert f._mpf_ == (0, int(302627), -19, 19) assert f._prec == 20 assert n._as_mpf_val(20) == f._mpf_ def test_Catalan_rewrite(): k = Dummy('k', integer=True, nonnegative=True) assert Catalan.rewrite(Sum).dummy_eq( Sum((-1)**k/(2*k + 1)**2, (k, 0, oo))) assert Catalan.rewrite() == Catalan def test_bool_eq(): assert 0 == False assert S(0) == False assert S(0) != S.false assert 1 == True assert S.One == True assert S.One != S.true def test_Float_eq(): # all .5 values are the same assert Float(.5, 10) == Float(.5, 11) == Float(.5, 1) # but floats that aren't exact in base-2 still # don't compare the same because they have different # underlying mpf values assert Float(.12, 3) != Float(.12, 4) assert Float(.12, 3) != .12 assert 0.12 != Float(.12, 3) assert Float('.12', 22) != .12 # issue 11707 # but Float/Rational -- except for 0 -- # are exact so Rational(x) = Float(y) only if # Rational(x) == Rational(Float(y)) assert Float('1.1') != Rational(11, 10) assert Rational(11, 10) != Float('1.1') # coverage assert not Float(3) == 2 assert not Float(2**2) == S.Half assert Float(2**2) == 4 assert not Float(2**-2) == 1 assert Float(2**-1) == S.Half assert not Float(2*3) == 3 assert not Float(2*3) == S.Half assert Float(2*3) == 6 assert not Float(2*3) == 8 assert Float(.75) == Rational(3, 4) assert Float(5/18) == 5/18 # 4473 assert Float(2.) != 3 assert Float((0,1,-3)) == S.One/8 assert Float((0,1,-3)) != S.One/9 # 16196 assert 2 == Float(2) # as per Python # but in a computation... assert t**2 != t**2.0 def test_issue_6640(): from mpmath.libmp.libmpf import finf, fninf # fnan is not included because Float no longer returns fnan, # but otherwise, the same sort of test could apply assert Float(finf).is_zero is False assert Float(fninf).is_zero is False assert bool(Float(0)) is False def test_issue_6349(): assert Float('23.e3', '')._prec == 10 assert Float('23e3', '')._prec == 20 assert Float('23000', '')._prec == 20 assert Float('-23000', '')._prec == 20 def test_mpf_norm(): assert mpf_norm((1, 0, 1, 0), 10) == mpf('0')._mpf_ assert Float._new((1, 0, 1, 0), 10)._mpf_ == mpf('0')._mpf_ def test_latex(): assert latex(pi) == r"\pi" assert latex(E) == r"e" assert latex(GoldenRatio) == r"\phi" assert latex(TribonacciConstant) == r"\text{TribonacciConstant}" assert latex(EulerGamma) == r"\gamma" assert latex(oo) == r"\infty" assert latex(-oo) == r"-\infty" assert latex(zoo) == r"\tilde{\infty}" assert latex(nan) == r"\text{NaN}" assert latex(I) == r"i" def test_issue_7742(): assert -oo % 1 is nan def test_simplify_AlgebraicNumber(): A = AlgebraicNumber e = 3**(S.One/6)*(3 + (135 + 78*sqrt(3))**Rational(2, 3))/(45 + 26*sqrt(3))**(S.One/3) assert simplify(A(e)) == A(12) # wester test_C20 e = (41 + 29*sqrt(2))**(S.One/5) assert simplify(A(e)) == A(1 + sqrt(2)) # wester test_C21 e = (3 + 4*I)**Rational(3, 2) assert simplify(A(e)) == A(2 + 11*I) # issue 4401 def test_Float_idempotence(): x = Float('1.23', '') y = Float(x) z = Float(x, 15) assert same_and_same_prec(y, x) assert not same_and_same_prec(z, x) x = Float(10**20) y = Float(x) z = Float(x, 15) assert same_and_same_prec(y, x) assert not same_and_same_prec(z, x) def test_comp1(): # sqrt(2) = 1.414213 5623730950... a = sqrt(2).n(7) assert comp(a, 1.4142129) is False assert comp(a, 1.4142130) # ... assert comp(a, 1.4142141) assert comp(a, 1.4142142) is False assert comp(sqrt(2).n(2), '1.4') assert comp(sqrt(2).n(2), Float(1.4, 2), '') assert comp(sqrt(2).n(2), 1.4, '') assert comp(sqrt(2).n(2), Float(1.4, 3), '') is False assert comp(sqrt(2) + sqrt(3)*I, 1.4 + 1.7*I, .1) assert not comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*0.89, .1) assert comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*0.90, .1) assert comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*1.07, .1) assert not comp(sqrt(2) + sqrt(3)*I, (1.5 + 1.7*I)*1.08, .1) assert [(i, j) for i in range(130, 150) for j in range(170, 180) if comp((sqrt(2)+ I*sqrt(3)).n(3), i/100. + I*j/100.)] == [ (141, 173), (142, 173)] raises(ValueError, lambda: comp(t, '1')) raises(ValueError, lambda: comp(t, 1)) assert comp(0, 0.0) assert comp(.5, S.Half) assert comp(2 + sqrt(2), 2.0 + sqrt(2)) assert not comp(0, 1) assert not comp(2, sqrt(2)) assert not comp(2 + I, 2.0 + sqrt(2)) assert not comp(2.0 + sqrt(2), 2 + I) assert not comp(2.0 + sqrt(2), sqrt(3)) assert comp(1/pi.n(4), 0.3183, 1e-5) assert not comp(1/pi.n(4), 0.3183, 8e-6) def test_issue_9491(): assert oo**zoo is nan def test_issue_10063(): assert 2**Float(3) == Float(8) def test_issue_10020(): assert oo**I is S.NaN assert oo**(1 + I) is S.ComplexInfinity assert oo**(-1 + I) is S.Zero assert (-oo)**I is S.NaN assert (-oo)**(-1 + I) is S.Zero assert oo**t == Pow(oo, t, evaluate=False) assert (-oo)**t == Pow(-oo, t, evaluate=False) def test_invert_numbers(): assert S(2).invert(5) == 3 assert S(2).invert(Rational(5, 2)) == S.Half assert S(2).invert(5.) == 0.5 assert S(2).invert(S(5)) == 3 assert S(2.).invert(5) == 0.5 assert S(sqrt(2)).invert(5) == 1/sqrt(2) assert S(sqrt(2)).invert(sqrt(3)) == 1/sqrt(2) def test_mod_inverse(): assert mod_inverse(3, 11) == 4 assert mod_inverse(5, 11) == 9 assert mod_inverse(21124921, 521512) == 7713 assert mod_inverse(124215421, 5125) == 2981 assert mod_inverse(214, 12515) == 1579 assert mod_inverse(5823991, 3299) == 1442 assert mod_inverse(123, 44) == 39 assert mod_inverse(2, 5) == 3 assert mod_inverse(-2, 5) == 2 assert mod_inverse(2, -5) == -2 assert mod_inverse(-2, -5) == -3 assert mod_inverse(-3, -7) == -5 x = Symbol('x') assert S(2).invert(x) == S.Half raises(TypeError, lambda: mod_inverse(2, x)) raises(ValueError, lambda: mod_inverse(2, S.Half)) raises(ValueError, lambda: mod_inverse(2, cos(1)**2 + sin(1)**2)) def test_golden_ratio_rewrite_as_sqrt(): assert GoldenRatio.rewrite(sqrt) == S.Half + sqrt(5)*S.Half def test_tribonacci_constant_rewrite_as_sqrt(): assert TribonacciConstant.rewrite(sqrt) == \ (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 def test_comparisons_with_unknown_type(): class Foo: """ Class that is unaware of Basic, and relies on both classes returning the NotImplemented singleton for equivalence to evaluate to False. """ ni, nf, nr = Integer(3), Float(1.0), Rational(1, 3) foo = Foo() for n in ni, nf, nr, oo, -oo, zoo, nan: assert n != foo assert foo != n assert not n == foo assert not foo == n raises(TypeError, lambda: n < foo) raises(TypeError, lambda: foo > n) raises(TypeError, lambda: n > foo) raises(TypeError, lambda: foo < n) raises(TypeError, lambda: n <= foo) raises(TypeError, lambda: foo >= n) raises(TypeError, lambda: n >= foo) raises(TypeError, lambda: foo <= n) class Bar: """ Class that considers itself equal to any instance of Number except infinities and nans, and relies on sympy types returning the NotImplemented singleton for symmetric equality relations. """ def __eq__(self, other): if other in (oo, -oo, zoo, nan): return False if isinstance(other, Number): return True return NotImplemented def __ne__(self, other): return not self == other bar = Bar() for n in ni, nf, nr: assert n == bar assert bar == n assert not n != bar assert not bar != n for n in oo, -oo, zoo, nan: assert n != bar assert bar != n assert not n == bar assert not bar == n for n in ni, nf, nr, oo, -oo, zoo, nan: raises(TypeError, lambda: n < bar) raises(TypeError, lambda: bar > n) raises(TypeError, lambda: n > bar) raises(TypeError, lambda: bar < n) raises(TypeError, lambda: n <= bar) raises(TypeError, lambda: bar >= n) raises(TypeError, lambda: n >= bar) raises(TypeError, lambda: bar <= n) def test_NumberSymbol_comparison(): from sympy.core.tests.test_relational import rel_check rpi = Rational('905502432259640373/288230376151711744') fpi = Float(float(pi)) assert rel_check(rpi, fpi) def test_Integer_precision(): # Make sure Integer inputs for keyword args work assert Float('1.0', dps=Integer(15))._prec == 53 assert Float('1.0', precision=Integer(15))._prec == 15 assert type(Float('1.0', precision=Integer(15))._prec) == int assert sympify(srepr(Float('1.0', precision=15))) == Float('1.0', precision=15) def test_numpy_to_float(): from sympy.testing.pytest import skip from sympy.external import import_module np = import_module('numpy') if not np: skip('numpy not installed. Abort numpy tests.') def check_prec_and_relerr(npval, ratval): prec = np.finfo(npval).nmant + 1 x = Float(npval) assert x._prec == prec y = Float(ratval, precision=prec) assert abs((x - y)/y) < 2**(-(prec + 1)) check_prec_and_relerr(np.float16(2.0/3), Rational(2, 3)) check_prec_and_relerr(np.float32(2.0/3), Rational(2, 3)) check_prec_and_relerr(np.float64(2.0/3), Rational(2, 3)) # extended precision, on some arch/compilers: x = np.longdouble(2)/3 check_prec_and_relerr(x, Rational(2, 3)) y = Float(x, precision=10) assert same_and_same_prec(y, Float(Rational(2, 3), precision=10)) raises(TypeError, lambda: Float(np.complex64(1+2j))) raises(TypeError, lambda: Float(np.complex128(1+2j))) def test_Integer_ceiling_floor(): a = Integer(4) assert a.floor() == a assert a.ceiling() == a def test_ComplexInfinity(): assert zoo.floor() is zoo assert zoo.ceiling() is zoo assert zoo**zoo is S.NaN def test_Infinity_floor_ceiling_power(): assert oo.floor() is oo assert oo.ceiling() is oo assert oo**S.NaN is S.NaN assert oo**zoo is S.NaN def test_One_power(): assert S.One**12 is S.One assert S.NegativeOne**S.NaN is S.NaN def test_NegativeInfinity(): assert (-oo).floor() is -oo assert (-oo).ceiling() is -oo assert (-oo)**11 is -oo assert (-oo)**12 is oo def test_issue_6133(): raises(TypeError, lambda: (-oo < None)) raises(TypeError, lambda: (S(-2) < None)) raises(TypeError, lambda: (oo < None)) raises(TypeError, lambda: (oo > None)) raises(TypeError, lambda: (S(2) < None)) def test_abc(): x = numbers.Float(5) assert(isinstance(x, nums.Number)) assert(isinstance(x, numbers.Number)) assert(isinstance(x, nums.Real)) y = numbers.Rational(1, 3) assert(isinstance(y, nums.Number)) assert(y.numerator == 1) assert(y.denominator == 3) assert(isinstance(y, nums.Rational)) z = numbers.Integer(3) assert(isinstance(z, nums.Number)) assert(isinstance(z, numbers.Number)) assert(isinstance(z, nums.Rational)) assert(isinstance(z, numbers.Rational)) assert(isinstance(z, nums.Integral)) def test_floordiv(): assert S(2)//S.Half == 4 sympy-sympy-1.9/sympy/core/tests/test_operations.py000066400000000000000000000053041412543434000227740ustar00rootroot00000000000000from sympy import Integer, S, Symbol, symbols, Expr from sympy.core.operations import AssocOp, LatticeOp from sympy.testing.pytest import raises from sympy.core.sympify import SympifyError from sympy.core.add import Add, add from sympy.core.mul import Mul, mul # create the simplest possible Lattice class class join(LatticeOp): zero = Integer(0) identity = Integer(1) def test_lattice_simple(): assert join(join(2, 3), 4) == join(2, join(3, 4)) assert join(2, 3) == join(3, 2) assert join(0, 2) == 0 assert join(1, 2) == 2 assert join(2, 2) == 2 assert join(join(2, 3), 4) == join(2, 3, 4) assert join() == 1 assert join(4) == 4 assert join(1, 4, 2, 3, 1, 3, 2) == join(2, 3, 4) def test_lattice_shortcircuit(): raises(SympifyError, lambda: join(object)) assert join(0, object) == 0 def test_lattice_print(): assert str(join(5, 4, 3, 2)) == 'join(2, 3, 4, 5)' def test_lattice_make_args(): assert join.make_args(join(2, 3, 4)) == {S(2), S(3), S(4)} assert join.make_args(0) == {0} assert list(join.make_args(0))[0] is S.Zero assert Add.make_args(0)[0] is S.Zero def test_issue_14025(): a, b, c, d = symbols('a,b,c,d', commutative=False) assert Mul(a, b, c).has(c*b) == False assert Mul(a, b, c).has(b*c) == True assert Mul(a, b, c, d).has(b*c*d) == True def test_AssocOp_flatten(): a, b, c, d = symbols('a,b,c,d') class MyAssoc(AssocOp): identity = S.One assert MyAssoc(a, MyAssoc(b, c)).args == \ MyAssoc(MyAssoc(a, b), c).args == \ MyAssoc(MyAssoc(a, b, c)).args == \ MyAssoc(a, b, c).args == \ (a, b, c) u = MyAssoc(b, c) v = MyAssoc(u, d, evaluate=False) assert v.args == (u, d) # like Add, any unevaluated outer call will flatten inner args assert MyAssoc(a, v).args == (a, b, c, d) def test_add_dispatcher(): class NewBase(Expr): @property def _add_handler(self): return NewAdd class NewAdd(NewBase, Add): pass add.register_handlerclass((Add, NewAdd), NewAdd) a, b = Symbol('a'), NewBase() # Add called as fallback assert add(1, 2) == Add(1, 2) assert add(a, a) == Add(a, a) # selection by registered priority assert add(a,b,a) == NewAdd(2*a, b) def test_mul_dispatcher(): class NewBase(Expr): @property def _mul_handler(self): return NewMul class NewMul(NewBase, Mul): pass mul.register_handlerclass((Mul, NewMul), NewMul) a, b = Symbol('a'), NewBase() # Mul called as fallback assert mul(1, 2) == Mul(1, 2) assert mul(a, a) == Mul(a, a) # selection by registered priority assert mul(a,b,a) == NewMul(a**2, b) sympy-sympy-1.9/sympy/core/tests/test_parameters.py000066400000000000000000000052561412543434000227620ustar00rootroot00000000000000from sympy.abc import x, y from sympy.core.parameters import evaluate from sympy.core import Mul, Add, Pow, S from sympy import sqrt, oo def test_add(): with evaluate(False): p = oo - oo assert isinstance(p, Add) and p.args == (oo, -oo) p = 5 - oo assert isinstance(p, Add) and p.args == (-oo, 5) p = oo - 5 assert isinstance(p, Add) and p.args == (oo, -5) p = oo + 5 assert isinstance(p, Add) and p.args == (oo, 5) p = 5 + oo assert isinstance(p, Add) and p.args == (oo, 5) p = -oo + 5 assert isinstance(p, Add) and p.args == (-oo, 5) p = -5 - oo assert isinstance(p, Add) and p.args == (-oo, -5) with evaluate(False): expr = x + x assert isinstance(expr, Add) assert expr.args == (x, x) with evaluate(True): assert (x + x).args == (2, x) assert (x + x).args == (x, x) assert isinstance(x + x, Mul) with evaluate(False): assert S.One + 1 == Add(1, 1) assert 1 + S.One == Add(1, 1) assert S(4) - 3 == Add(4, -3) assert -3 + S(4) == Add(4, -3) assert S(2) * 4 == Mul(2, 4) assert 4 * S(2) == Mul(2, 4) assert S(6) / 3 == Mul(6, Pow(3, -1)) assert S.One / 3 * 6 == Mul(S.One / 3, 6) assert 9 ** S(2) == Pow(9, 2) assert S(2) ** 9 == Pow(2, 9) assert S(2) / 2 == Mul(2, Pow(2, -1)) assert S.One / 2 * 2 == Mul(S.One / 2, 2) assert S(2) / 3 + 1 == Add(S(2) / 3, 1) assert 1 + S(2) / 3 == Add(1, S(2) / 3) assert S(4) / 7 - 3 == Add(S(4) / 7, -3) assert -3 + S(4) / 7 == Add(-3, S(4) / 7) assert S(2) / 4 * 4 == Mul(S(2) / 4, 4) assert 4 * (S(2) / 4) == Mul(4, S(2) / 4) assert S(6) / 3 == Mul(6, Pow(3, -1)) assert S.One / 3 * 6 == Mul(S.One / 3, 6) assert S.One / 3 + sqrt(3) == Add(S.One / 3, sqrt(3)) assert sqrt(3) + S.One / 3 == Add(sqrt(3), S.One / 3) assert S.One / 2 * 10.333 == Mul(S.One / 2, 10.333) assert 10.333 * (S.One / 2) == Mul(10.333, S.One / 2) assert sqrt(2) * sqrt(2) == Mul(sqrt(2), sqrt(2)) assert S.One / 2 + x == Add(S.One / 2, x) assert x + S.One / 2 == Add(x, S.One / 2) assert S.One / x * x == Mul(S.One / x, x) assert x * (S.One / x) == Mul(x, Pow(x, -1)) assert S.One / 3 == Pow(3, -1) assert S.One / x == Pow(x, -1) assert 1 / S(3) == Pow(3, -1) assert 1 / x == Pow(x, -1) def test_nested(): with evaluate(False): expr = (x + x) + (y + y) assert expr.args == ((x + x), (y + y)) assert expr.args[0].args == (x, x) sympy-sympy-1.9/sympy/core/tests/test_power.py000066400000000000000000000551141412543434000217510ustar00rootroot00000000000000from sympy.core import ( Basic, Rational, Symbol, S, Float, Integer, Mul, Number, Pow, Expr, I, nan, pi, symbols, oo, zoo, N) from sympy.core.parameters import global_parameters from sympy.core.tests.test_evalf import NS from sympy.core.function import expand_multinomial from sympy.functions.elementary.miscellaneous import sqrt, cbrt from sympy.functions.elementary.exponential import exp, log from sympy.functions.special.error_functions import erf from sympy.functions.elementary.trigonometric import ( sin, cos, tan, sec, csc, sinh, cosh, tanh, atan) from sympy.polys import Poly from sympy.series.order import O from sympy.sets import FiniteSet from sympy.core.expr import unchanged from sympy.core.power import power from sympy.testing.pytest import warns_deprecated_sympy, _both_exp_pow def test_rational(): a = Rational(1, 5) r = sqrt(5)/5 assert sqrt(a) == r assert 2*sqrt(a) == 2*r r = a*a**S.Half assert a**Rational(3, 2) == r assert 2*a**Rational(3, 2) == 2*r r = a**5*a**Rational(2, 3) assert a**Rational(17, 3) == r assert 2 * a**Rational(17, 3) == 2*r def test_large_rational(): e = (Rational(123712**12 - 1, 7) + Rational(1, 7))**Rational(1, 3) assert e == 234232585392159195136 * (Rational(1, 7)**Rational(1, 3)) def test_negative_real(): def feq(a, b): return abs(a - b) < 1E-10 assert feq(S.One / Float(-0.5), -Integer(2)) def test_expand(): x = Symbol('x') assert (2**(-1 - x)).expand() == S.Half*2**(-x) def test_issue_3449(): #test if powers are simplified correctly #see also issue 3995 x = Symbol('x') assert ((x**Rational(1, 3))**Rational(2)) == x**Rational(2, 3) assert ( (x**Rational(3))**Rational(2, 5)) == (x**Rational(3))**Rational(2, 5) a = Symbol('a', real=True) b = Symbol('b', real=True) assert (a**2)**b == (abs(a)**b)**2 assert sqrt(1/a) != 1/sqrt(a) # e.g. for a = -1 assert (a**3)**Rational(1, 3) != a assert (x**a)**b != x**(a*b) # e.g. x = -1, a=2, b=1/2 assert (x**.5)**b == x**(.5*b) assert (x**.5)**.5 == x**.25 assert (x**2.5)**.5 != x**1.25 # e.g. for x = 5*I k = Symbol('k', integer=True) m = Symbol('m', integer=True) assert (x**k)**m == x**(k*m) assert Number(5)**Rational(2, 3) == Number(25)**Rational(1, 3) assert (x**.5)**2 == x**1.0 assert (x**2)**k == (x**k)**2 == x**(2*k) a = Symbol('a', positive=True) assert (a**3)**Rational(2, 5) == a**Rational(6, 5) assert (a**2)**b == (a**b)**2 assert (a**Rational(2, 3))**x == a**(x*Rational(2, 3)) != (a**x)**Rational(2, 3) def test_issue_3866(): assert --sqrt(sqrt(5) - 1) == sqrt(sqrt(5) - 1) def test_negative_one(): x = Symbol('x', complex=True) y = Symbol('y', complex=True) assert 1/x**y == x**(-y) def test_issue_4362(): neg = Symbol('neg', negative=True) nonneg = Symbol('nonneg', nonnegative=True) any = Symbol('any') num, den = sqrt(1/neg).as_numer_denom() assert num == sqrt(-1) assert den == sqrt(-neg) num, den = sqrt(1/nonneg).as_numer_denom() assert num == 1 assert den == sqrt(nonneg) num, den = sqrt(1/any).as_numer_denom() assert num == sqrt(1/any) assert den == 1 def eqn(num, den, pow): return (num/den)**pow npos = 1 nneg = -1 dpos = 2 - sqrt(3) dneg = 1 - sqrt(3) assert dpos > 0 and dneg < 0 and npos > 0 and nneg < 0 # pos or neg integer eq = eqn(npos, dpos, 2) assert eq.is_Pow and eq.as_numer_denom() == (1, dpos**2) eq = eqn(npos, dneg, 2) assert eq.is_Pow and eq.as_numer_denom() == (1, dneg**2) eq = eqn(nneg, dpos, 2) assert eq.is_Pow and eq.as_numer_denom() == (1, dpos**2) eq = eqn(nneg, dneg, 2) assert eq.is_Pow and eq.as_numer_denom() == (1, dneg**2) eq = eqn(npos, dpos, -2) assert eq.is_Pow and eq.as_numer_denom() == (dpos**2, 1) eq = eqn(npos, dneg, -2) assert eq.is_Pow and eq.as_numer_denom() == (dneg**2, 1) eq = eqn(nneg, dpos, -2) assert eq.is_Pow and eq.as_numer_denom() == (dpos**2, 1) eq = eqn(nneg, dneg, -2) assert eq.is_Pow and eq.as_numer_denom() == (dneg**2, 1) # pos or neg rational pow = S.Half eq = eqn(npos, dpos, pow) assert eq.is_Pow and eq.as_numer_denom() == (npos**pow, dpos**pow) eq = eqn(npos, dneg, pow) assert eq.is_Pow is False and eq.as_numer_denom() == ((-npos)**pow, (-dneg)**pow) eq = eqn(nneg, dpos, pow) assert not eq.is_Pow or eq.as_numer_denom() == (nneg**pow, dpos**pow) eq = eqn(nneg, dneg, pow) assert eq.is_Pow and eq.as_numer_denom() == ((-nneg)**pow, (-dneg)**pow) eq = eqn(npos, dpos, -pow) assert eq.is_Pow and eq.as_numer_denom() == (dpos**pow, npos**pow) eq = eqn(npos, dneg, -pow) assert eq.is_Pow is False and eq.as_numer_denom() == (-(-npos)**pow*(-dneg)**pow, npos) eq = eqn(nneg, dpos, -pow) assert not eq.is_Pow or eq.as_numer_denom() == (dpos**pow, nneg**pow) eq = eqn(nneg, dneg, -pow) assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-nneg)**pow) # unknown exponent pow = 2*any eq = eqn(npos, dpos, pow) assert eq.is_Pow and eq.as_numer_denom() == (npos**pow, dpos**pow) eq = eqn(npos, dneg, pow) assert eq.is_Pow and eq.as_numer_denom() == ((-npos)**pow, (-dneg)**pow) eq = eqn(nneg, dpos, pow) assert eq.is_Pow and eq.as_numer_denom() == (nneg**pow, dpos**pow) eq = eqn(nneg, dneg, pow) assert eq.is_Pow and eq.as_numer_denom() == ((-nneg)**pow, (-dneg)**pow) eq = eqn(npos, dpos, -pow) assert eq.as_numer_denom() == (dpos**pow, npos**pow) eq = eqn(npos, dneg, -pow) assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-npos)**pow) eq = eqn(nneg, dpos, -pow) assert eq.is_Pow and eq.as_numer_denom() == (dpos**pow, nneg**pow) eq = eqn(nneg, dneg, -pow) assert eq.is_Pow and eq.as_numer_denom() == ((-dneg)**pow, (-nneg)**pow) x = Symbol('x') y = Symbol('y') assert ((1/(1 + x/3))**(-S.One)).as_numer_denom() == (3 + x, 3) notp = Symbol('notp', positive=False) # not positive does not imply real b = ((1 + x/notp)**-2) assert (b**(-y)).as_numer_denom() == (1, b**y) assert (b**(-S.One)).as_numer_denom() == ((notp + x)**2, notp**2) nonp = Symbol('nonp', nonpositive=True) assert (((1 + x/nonp)**-2)**(-S.One)).as_numer_denom() == ((-nonp - x)**2, nonp**2) n = Symbol('n', negative=True) assert (x**n).as_numer_denom() == (1, x**-n) assert sqrt(1/n).as_numer_denom() == (S.ImaginaryUnit, sqrt(-n)) n = Symbol('0 or neg', nonpositive=True) # if x and n are split up without negating each term and n is negative # then the answer might be wrong; if n is 0 it won't matter since # 1/oo and 1/zoo are both zero as is sqrt(0)/sqrt(-x) unless x is also # zero (in which case the negative sign doesn't matter): # 1/sqrt(1/-1) = -I but sqrt(-1)/sqrt(1) = I assert (1/sqrt(x/n)).as_numer_denom() == (sqrt(-n), sqrt(-x)) c = Symbol('c', complex=True) e = sqrt(1/c) assert e.as_numer_denom() == (e, 1) i = Symbol('i', integer=True) assert ((1 + x/y)**i).as_numer_denom() == ((x + y)**i, y**i) def test_Pow_Expr_args(): x = Symbol('x') bases = [Basic(), Poly(x, x), FiniteSet(x)] for base in bases: with warns_deprecated_sympy(): Pow(base, S.One) def test_Pow_signs(): """Cf. issues 4595 and 5250""" x = Symbol('x') y = Symbol('y') n = Symbol('n', even=True) assert (3 - y)**2 != (y - 3)**2 assert (3 - y)**n != (y - 3)**n assert (-3 + y - x)**2 != (3 - y + x)**2 assert (y - 3)**3 != -(3 - y)**3 def test_power_with_noncommutative_mul_as_base(): x = Symbol('x', commutative=False) y = Symbol('y', commutative=False) assert not (x*y)**3 == x**3*y**3 assert (2*x*y)**3 == 8*(x*y)**3 @_both_exp_pow def test_power_rewrite_exp(): assert (I**I).rewrite(exp) == exp(-pi/2) expr = (2 + 3*I)**(4 + 5*I) assert expr.rewrite(exp) == exp((4 + 5*I)*(log(sqrt(13)) + I*atan(Rational(3, 2)))) assert expr.rewrite(exp).expand() == \ 169*exp(5*I*log(13)/2)*exp(4*I*atan(Rational(3, 2)))*exp(-5*atan(Rational(3, 2))) assert ((6 + 7*I)**5).rewrite(exp) == 7225*sqrt(85)*exp(5*I*atan(Rational(7, 6))) expr = 5**(6 + 7*I) assert expr.rewrite(exp) == exp((6 + 7*I)*log(5)) assert expr.rewrite(exp).expand() == 15625*exp(7*I*log(5)) assert Pow(123, 789, evaluate=False).rewrite(exp) == 123**789 assert (1**I).rewrite(exp) == 1**I assert (0**I).rewrite(exp) == 0**I expr = (-2)**(2 + 5*I) assert expr.rewrite(exp) == exp((2 + 5*I)*(log(2) + I*pi)) assert expr.rewrite(exp).expand() == 4*exp(-5*pi)*exp(5*I*log(2)) assert ((-2)**S(-5)).rewrite(exp) == (-2)**S(-5) x, y = symbols('x y') assert (x**y).rewrite(exp) == exp(y*log(x)) if global_parameters.exp_is_pow: assert (7**x).rewrite(exp) == Pow(S.Exp1, x*log(7), evaluate=False) else: assert (7**x).rewrite(exp) == exp(x*log(7), evaluate=False) assert ((2 + 3*I)**x).rewrite(exp) == exp(x*(log(sqrt(13)) + I*atan(Rational(3, 2)))) assert (y**(5 + 6*I)).rewrite(exp) == exp(log(y)*(5 + 6*I)) assert all((1/func(x)).rewrite(exp) == 1/(func(x).rewrite(exp)) for func in (sin, cos, tan, sec, csc, sinh, cosh, tanh)) def test_zero(): x = Symbol('x') y = Symbol('y') assert 0**x != 0 assert 0**(2*x) == 0**x assert 0**(1.0*x) == 0**x assert 0**(2.0*x) == 0**x assert (0**(2 - x)).as_base_exp() == (0, 2 - x) assert 0**(x - 2) != S.Infinity**(2 - x) assert 0**(2*x*y) == 0**(x*y) assert 0**(-2*x*y) == S.ComplexInfinity**(x*y) #Test issue 19572 assert 0 ** -oo is zoo assert power(0, -oo) is zoo def test_pow_as_base_exp(): x = Symbol('x') assert (S.Infinity**(2 - x)).as_base_exp() == (S.Infinity, 2 - x) assert (S.Infinity**(x - 2)).as_base_exp() == (S.Infinity, x - 2) p = S.Half**x assert p.base, p.exp == p.as_base_exp() == (S(2), -x) # issue 8344: assert Pow(1, 2, evaluate=False).as_base_exp() == (S.One, S(2)) def test_nseries(): x = Symbol('x') assert sqrt(I*x - 1)._eval_nseries(x, 4, None, 1) == I + x/2 + I*x**2/8 - x**3/16 + O(x**4) assert sqrt(I*x - 1)._eval_nseries(x, 4, None, -1) == -I - x/2 - I*x**2/8 + x**3/16 + O(x**4) assert cbrt(I*x - 1)._eval_nseries(x, 4, None, 1) == (-1)**(S(1)/3) - (-1)**(S(5)/6)*x/3 + \ (-1)**(S(1)/3)*x**2/9 + 5*(-1)**(S(5)/6)*x**3/81 + O(x**4) assert cbrt(I*x - 1)._eval_nseries(x, 4, None, -1) == (-1)**(S(1)/3)*exp(-2*I*pi/3) - \ (-1)**(S(5)/6)*x*exp(-2*I*pi/3)/3 + (-1)**(S(1)/3)*x**2*exp(-2*I*pi/3)/9 + \ 5*(-1)**(S(5)/6)*x**3*exp(-2*I*pi/3)/81 + O(x**4) assert (1 / (exp(-1/x) + 1/x))._eval_nseries(x, 2, None) == x + O(x**2) def test_issue_6100_12942_4473(): x = Symbol('x') y = Symbol('y') assert x**1.0 != x assert x != x**1.0 assert True != x**1.0 assert x**1.0 is not True assert x is not True assert x*y != (x*y)**1.0 # Pow != Symbol assert (x**1.0)**1.0 != x assert (x**1.0)**2.0 != x**2 b = Expr() assert Pow(b, 1.0, evaluate=False) != b # if the following gets distributed as a Mul (x**1.0*y**1.0 then # __eq__ methods could be added to Symbol and Pow to detect the # power-of-1.0 case. assert ((x*y)**1.0).func is Pow def test_issue_6208(): from sympy import root assert sqrt(33**(I*Rational(9, 10))) == -33**(I*Rational(9, 20)) assert root((6*I)**(2*I), 3).as_base_exp()[1] == Rational(1, 3) # != 2*I/3 assert root((6*I)**(I/3), 3).as_base_exp()[1] == I/9 assert sqrt(exp(3*I)) == exp(I*Rational(3, 2)) assert sqrt(-sqrt(3)*(1 + 2*I)) == sqrt(sqrt(3))*sqrt(-1 - 2*I) assert sqrt(exp(5*I)) == -exp(I*Rational(5, 2)) assert root(exp(5*I), 3).exp == Rational(1, 3) def test_issue_6990(): x = Symbol('x') a = Symbol('a') b = Symbol('b') assert (sqrt(a + b*x + x**2)).series(x, 0, 3).removeO() == \ sqrt(a)*x**2*(1/(2*a) - b**2/(8*a**2)) + sqrt(a) + b*x/(2*sqrt(a)) def test_issue_6068(): x = Symbol('x') assert sqrt(sin(x)).series(x, 0, 7) == \ sqrt(x) - x**Rational(5, 2)/12 + x**Rational(9, 2)/1440 - \ x**Rational(13, 2)/24192 + O(x**7) assert sqrt(sin(x)).series(x, 0, 9) == \ sqrt(x) - x**Rational(5, 2)/12 + x**Rational(9, 2)/1440 - \ x**Rational(13, 2)/24192 - 67*x**Rational(17, 2)/29030400 + O(x**9) assert sqrt(sin(x**3)).series(x, 0, 19) == \ x**Rational(3, 2) - x**Rational(15, 2)/12 + x**Rational(27, 2)/1440 + O(x**19) assert sqrt(sin(x**3)).series(x, 0, 20) == \ x**Rational(3, 2) - x**Rational(15, 2)/12 + x**Rational(27, 2)/1440 - \ x**Rational(39, 2)/24192 + O(x**20) def test_issue_6782(): x = Symbol('x') assert sqrt(sin(x**3)).series(x, 0, 7) == x**Rational(3, 2) + O(x**7) assert sqrt(sin(x**4)).series(x, 0, 3) == x**2 + O(x**3) def test_issue_6653(): x = Symbol('x') assert (1 / sqrt(1 + sin(x**2))).series(x, 0, 3) == 1 - x**2/2 + O(x**3) def test_issue_6429(): x = Symbol('x') c = Symbol('c') f = (c**2 + x)**(0.5) assert f.series(x, x0=0, n=1) == (c**2)**0.5 + O(x) assert f.taylor_term(0, x) == (c**2)**0.5 assert f.taylor_term(1, x) == 0.5*x*(c**2)**(-0.5) assert f.taylor_term(2, x) == -0.125*x**2*(c**2)**(-1.5) def test_issue_7638(): f = pi/log(sqrt(2)) assert ((1 + I)**(I*f/2))**0.3 == (1 + I)**(0.15*I*f) # if 1/3 -> 1.0/3 this should fail since it cannot be shown that the # sign will be +/-1; for the previous "small arg" case, it didn't matter # that this could not be proved assert (1 + I)**(4*I*f) == ((1 + I)**(12*I*f))**Rational(1, 3) assert (((1 + I)**(I*(1 + 7*f)))**Rational(1, 3)).exp == Rational(1, 3) r = symbols('r', real=True) assert sqrt(r**2) == abs(r) assert cbrt(r**3) != r assert sqrt(Pow(2*I, 5*S.Half)) != (2*I)**Rational(5, 4) p = symbols('p', positive=True) assert cbrt(p**2) == p**Rational(2, 3) assert NS(((0.2 + 0.7*I)**(0.7 + 1.0*I))**(0.5 - 0.1*I), 1) == '0.4 + 0.2*I' assert sqrt(1/(1 + I)) == sqrt(1 - I)/sqrt(2) # or 1/sqrt(1 + I) e = 1/(1 - sqrt(2)) assert sqrt(e) == I/sqrt(-1 + sqrt(2)) assert e**Rational(-1, 2) == -I*sqrt(-1 + sqrt(2)) assert sqrt((cos(1)**2 + sin(1)**2 - 1)**(3 + I)).exp in [S.Half, Rational(3, 2) + I/2] assert sqrt(r**Rational(4, 3)) != r**Rational(2, 3) assert sqrt((p + I)**Rational(4, 3)) == (p + I)**Rational(2, 3) assert sqrt((p - p**2*I)**2) == p - p**2*I assert sqrt((p + r*I)**2) != p + r*I e = (1 + I/5) assert sqrt(e**5) == e**(5*S.Half) assert sqrt(e**6) == e**3 assert sqrt((1 + I*r)**6) != (1 + I*r)**3 def test_issue_8582(): assert 1**oo is nan assert 1**(-oo) is nan assert 1**zoo is nan assert 1**(oo + I) is nan assert 1**(1 + I*oo) is nan assert 1**(oo + I*oo) is nan def test_issue_8650(): n = Symbol('n', integer=True, nonnegative=True) assert (n**n).is_positive is True x = 5*n + 5 assert (x**(5*(n + 1))).is_positive is True def test_issue_13914(): b = Symbol('b') assert (-1)**zoo is nan assert 2**zoo is nan assert (S.Half)**(1 + zoo) is nan assert I**(zoo + I) is nan assert b**(I + zoo) is nan def test_better_sqrt(): n = Symbol('n', integer=True, nonnegative=True) assert sqrt(3 + 4*I) == 2 + I assert sqrt(3 - 4*I) == 2 - I assert sqrt(-3 - 4*I) == 1 - 2*I assert sqrt(-3 + 4*I) == 1 + 2*I assert sqrt(32 + 24*I) == 6 + 2*I assert sqrt(32 - 24*I) == 6 - 2*I assert sqrt(-32 - 24*I) == 2 - 6*I assert sqrt(-32 + 24*I) == 2 + 6*I # triple (3, 4, 5): # parity of 3 matches parity of 5 and # den, 4, is a square assert sqrt((3 + 4*I)/4) == 1 + I/2 # triple (8, 15, 17) # parity of 8 doesn't match parity of 17 but # den/2, 8/2, is a square assert sqrt((8 + 15*I)/8) == (5 + 3*I)/4 # handle the denominator assert sqrt((3 - 4*I)/25) == (2 - I)/5 assert sqrt((3 - 4*I)/26) == (2 - I)/sqrt(26) # mul # issue #12739 assert sqrt((3 + 4*I)/(3 - 4*I)) == (3 + 4*I)/5 assert sqrt(2/(3 + 4*I)) == sqrt(2)/5*(2 - I) assert sqrt(n/(3 + 4*I)).subs(n, 2) == sqrt(2)/5*(2 - I) assert sqrt(-2/(3 + 4*I)) == sqrt(2)/5*(1 + 2*I) assert sqrt(-n/(3 + 4*I)).subs(n, 2) == sqrt(2)/5*(1 + 2*I) # power assert sqrt(1/(3 + I*4)) == (2 - I)/5 assert sqrt(1/(3 - I)) == sqrt(10)*sqrt(3 + I)/10 # symbolic i = symbols('i', imaginary=True) assert sqrt(3/i) == Mul(sqrt(3), 1/sqrt(i), evaluate=False) # multiples of 1/2; don't make this too automatic assert sqrt(3 + 4*I)**3 == (2 + I)**3 assert Pow(3 + 4*I, Rational(3, 2)) == 2 + 11*I assert Pow(6 + 8*I, Rational(3, 2)) == 2*sqrt(2)*(2 + 11*I) n, d = (3 + 4*I), (3 - 4*I)**3 a = n/d assert a.args == (1/d, n) eq = sqrt(a) assert eq.args == (a, S.Half) assert expand_multinomial(eq) == sqrt((-117 + 44*I)*(3 + 4*I))/125 assert eq.expand() == (7 - 24*I)/125 # issue 12775 # pos im part assert sqrt(2*I) == (1 + I) assert sqrt(2*9*I) == Mul(3, 1 + I, evaluate=False) assert Pow(2*I, 3*S.Half) == (1 + I)**3 # neg im part assert sqrt(-I/2) == Mul(S.Half, 1 - I, evaluate=False) # fractional im part assert Pow(Rational(-9, 2)*I, Rational(3, 2)) == 27*(1 - I)**3/8 def test_issue_2993(): x = Symbol('x') assert str((2.3*x - 4)**0.3) == '1.5157165665104*(0.575*x - 1)**0.3' assert str((2.3*x + 4)**0.3) == '1.5157165665104*(0.575*x + 1)**0.3' assert str((-2.3*x + 4)**0.3) == '1.5157165665104*(1 - 0.575*x)**0.3' assert str((-2.3*x - 4)**0.3) == '1.5157165665104*(-0.575*x - 1)**0.3' assert str((2.3*x - 2)**0.3) == '1.28386201800527*(x - 0.869565217391304)**0.3' assert str((-2.3*x - 2)**0.3) == '1.28386201800527*(-x - 0.869565217391304)**0.3' assert str((-2.3*x + 2)**0.3) == '1.28386201800527*(0.869565217391304 - x)**0.3' assert str((2.3*x + 2)**0.3) == '1.28386201800527*(x + 0.869565217391304)**0.3' assert str((2.3*x - 4)**Rational(1, 3)) == '2**(2/3)*(0.575*x - 1)**(1/3)' eq = (2.3*x + 4) assert eq**2 == 16*(0.575*x + 1)**2 assert (1/eq).args == (eq, -1) # don't change trivial power # issue 17735 q=.5*exp(x) - .5*exp(-x) + 0.1 assert int((q**2).subs(x, 1)) == 1 # issue 17756 y = Symbol('y') assert len(sqrt(x/(x + y)**2 + Float('0.008', 30)).subs(y, pi.n(25)).atoms(Float)) == 2 # issue 17756 a, b, c, d, e, f, g = symbols('a:g') expr = sqrt(1 + a*(c**4 + g*d - 2*g*e - f*(-g + d))**2/ (c**3*b**2*(d - 3*e + 2*f)**2))/2 r = [ (a, N('0.0170992456333788667034850458615', 30)), (b, N('0.0966594956075474769169134801223', 30)), (c, N('0.390911862903463913632151616184', 30)), (d, N('0.152812084558656566271750185933', 30)), (e, N('0.137562344465103337106561623432', 30)), (f, N('0.174259178881496659302933610355', 30)), (g, N('0.220745448491223779615401870086', 30))] tru = expr.n(30, subs=dict(r)) seq = expr.subs(r) # although `tru` is the right way to evaluate # expr with numerical values, `seq` will have # significant loss of precision if extraction of # the largest coefficient of a power's base's terms # is done improperly assert seq == tru def test_issue_17450(): assert (erf(cosh(1)**7)**I).is_real is None assert (erf(cosh(1)**7)**I).is_imaginary is False assert (Pow(exp(1+sqrt(2)), ((1-sqrt(2))*I*pi), evaluate=False)).is_real is None assert ((-10)**(10*I*pi/3)).is_real is False assert ((-5)**(4*I*pi)).is_real is False def test_issue_18190(): assert sqrt(1 / tan(1 + I)) == 1 / sqrt(tan(1 + I)) def test_issue_14815(): x = Symbol('x', real=True) assert sqrt(x).is_extended_negative is False x = Symbol('x', real=False) assert sqrt(x).is_extended_negative is None x = Symbol('x', complex=True) assert sqrt(x).is_extended_negative is False x = Symbol('x', extended_real=True) assert sqrt(x).is_extended_negative is False assert sqrt(zoo, evaluate=False).is_extended_negative is None assert sqrt(nan, evaluate=False).is_extended_negative is None def test_issue_18509(): assert unchanged(Mul, oo, 1/pi**oo) assert (1/pi**oo).is_extended_positive == False def test_issue_18762(): e, p = symbols('e p') g0 = sqrt(1 + e**2 - 2*e*cos(p)) assert len(g0.series(e, 1, 3).args) == 4 def test_issue_21860(): x = Symbol('x') e = 3*2**Rational(66666666667,200000000000)*3**Rational(16666666667,50000000000)*x**Rational(66666666667, 200000000000) ans = Mul(Rational(3, 2), Pow(Integer(2), Rational(33333333333, 100000000000)), Pow(Integer(3), Rational(26666666667, 40000000000))) assert e.xreplace({x: Rational(3,8)}) == ans def test_issue_21647(): x = Symbol('x') e = log((Integer(567)/500)**(811*(Integer(567)/500)**x/100)) ans = log(Mul(Rational(64701150190720499096094005280169087619821081527, 76293945312500000000000000000000000000000000000), Pow(Integer(2), Rational(396204892125479941, 781250000000000000)), Pow(Integer(3), Rational(385045107874520059, 390625000000000000)), Pow(Integer(5), Rational(407364676376439823, 1562500000000000000)), Pow(Integer(7), Rational(385045107874520059, 1562500000000000000)))) assert e.xreplace({x: 6}) == ans def test_issue_21762(): x = Symbol('x') e = (x**2 + 6)**(Integer(33333333333333333)/50000000000000000) ans = Mul(Rational(5, 4), Pow(Integer(2), Rational(16666666666666667, 25000000000000000)), Pow(Integer(5), Rational(8333333333333333, 25000000000000000))) assert e.xreplace({x: S.Half}) == ans def test_rational_powers_larger_than_one(): assert Rational(2, 3)**Rational(3, 2) == 2*sqrt(6)/9 assert Rational(1, 6)**Rational(9, 4) == 6**Rational(3, 4)/216 assert Rational(3, 7)**Rational(7, 3) == 9*3**Rational(1, 3)*7**Rational(2, 3)/343 def test_power_dispatcher(): class NewBase(Expr): pass class NewPow(NewBase, Pow): pass a, b = Symbol('a'), NewBase() @power.register(Expr, NewBase) @power.register(NewBase, Expr) @power.register(NewBase, NewBase) def _(a, b): return NewPow(a, b) # Pow called as fallback assert power(2, 3) == 8*S.One assert power(a, 2) == Pow(a, 2) assert power(a, a) == Pow(a, a) # NewPow called by dispatch assert power(a, b) == NewPow(a, b) assert power(b, a) == NewPow(b, a) assert power(b, b) == NewPow(b, b) def test_powers_of_I(): assert [sqrt(I)**i for i in range(13)] == [ 1, sqrt(I), I, sqrt(I)**3, -1, -sqrt(I), -I, -sqrt(I)**3, 1, sqrt(I), I, sqrt(I)**3, -1] assert sqrt(I)**(S(9)/2) == -I**(S(1)/4) sympy-sympy-1.9/sympy/core/tests/test_priority.py000066400000000000000000000061661412543434000225010ustar00rootroot00000000000000from sympy.core.decorators import call_highest_priority from sympy.core.expr import Expr from sympy.core.mod import Mod from sympy.core.numbers import Integer from sympy.core.symbol import Symbol from sympy.functions.elementary.integers import floor class Higher(Integer): ''' Integer of value 1 and _op_priority 20 Operations handled by this class return 1 and reverse operations return 2 ''' _op_priority = 20.0 result = 1 def __new__(cls): obj = Expr.__new__(cls) obj.p = 1 return obj @call_highest_priority('__rmul__') def __mul__(self, other): return self.result @call_highest_priority('__mul__') def __rmul__(self, other): return 2*self.result @call_highest_priority('__radd__') def __add__(self, other): return self.result @call_highest_priority('__add__') def __radd__(self, other): return 2*self.result @call_highest_priority('__rsub__') def __sub__(self, other): return self.result @call_highest_priority('__sub__') def __rsub__(self, other): return 2*self.result @call_highest_priority('__rpow__') def __pow__(self, other): return self.result @call_highest_priority('__pow__') def __rpow__(self, other): return 2*self.result @call_highest_priority('__rtruediv__') def __truediv__(self, other): return self.result @call_highest_priority('__truediv__') def __rtruediv__(self, other): return 2*self.result @call_highest_priority('__rmod__') def __mod__(self, other): return self.result @call_highest_priority('__mod__') def __rmod__(self, other): return 2*self.result @call_highest_priority('__rfloordiv__') def __floordiv__(self, other): return self.result @call_highest_priority('__floordiv__') def __rfloordiv__(self, other): return 2*self.result class Lower(Higher): ''' Integer of value -1 and _op_priority 5 Operations handled by this class return -1 and reverse operations return -2 ''' _op_priority = 5.0 result = -1 def __new__(cls): obj = Expr.__new__(cls) obj.p = -1 return obj x = Symbol('x') h = Higher() l = Lower() def test_mul(): assert h*l == h*x == 1 assert l*h == x*h == 2 assert x*l == l*x == -x def test_add(): assert h + l == h + x == 1 assert l + h == x + h == 2 assert x + l == l + x == x - 1 def test_sub(): assert h - l == h - x == 1 assert l - h == x - h == 2 assert x - l == -(l - x) == x + 1 def test_pow(): assert h**l == h**x == 1 assert l**h == x**h == 2 assert (x**l).args == (1/x).args and (x**l).is_Pow assert (l**x).args == ((-1)**x).args and (l**x).is_Pow def test_div(): assert h/l == h/x == 1 assert l/h == x/h == 2 assert x/l == 1/(l/x) == -x def test_mod(): assert h%l == h%x == 1 assert l%h == x%h == 2 assert x%l == Mod(x, -1) assert l%x == Mod(-1, x) def test_floordiv(): assert h//l == h//x == 1 assert l//h == x//h == 2 assert x//l == floor(-x) assert l//x == floor(-1/x) sympy-sympy-1.9/sympy/core/tests/test_relational.py000066400000000000000000001216161412543434000227500ustar00rootroot00000000000000from sympy.core.logic import fuzzy_and from sympy.core.sympify import _sympify from sympy.multipledispatch import dispatch from sympy.testing.pytest import XFAIL, raises, warns_deprecated_sympy from sympy import (S, Symbol, symbols, nan, oo, I, pi, Float, And, Or, Not, Implies, Xor, zoo, sqrt, Rational, simplify, Function, log, cos, sin, Add, Mul, Pow, floor, ceiling, trigsimp, Reals, Basic, Expr, Q, exp, exp_polar) from sympy.core.relational import (Relational, Equality, Unequality, GreaterThan, LessThan, StrictGreaterThan, StrictLessThan, Rel, Eq, Lt, Le, Gt, Ge, Ne, is_le, is_gt, is_ge, is_lt, is_eq, is_neq) from sympy.sets.sets import Interval, FiniteSet from itertools import combinations x, y, z, t = symbols('x,y,z,t') def rel_check(a, b): from sympy.testing.pytest import raises assert a.is_number and b.is_number for do in range(len({type(a), type(b)})): if S.NaN in (a, b): v = [(a == b), (a != b)] assert len(set(v)) == 1 and v[0] == False assert not (a != b) and not (a == b) assert raises(TypeError, lambda: a < b) assert raises(TypeError, lambda: a <= b) assert raises(TypeError, lambda: a > b) assert raises(TypeError, lambda: a >= b) else: E = [(a == b), (a != b)] assert len(set(E)) == 2 v = [ (a < b), (a <= b), (a > b), (a >= b)] i = [ [True, True, False, False], [False, True, False, True], # <-- i == 1 [False, False, True, True]].index(v) if i == 1: assert E[0] or (a.is_Float != b.is_Float) # ugh else: assert E[1] a, b = b, a return True def test_rel_ne(): assert Relational(x, y, '!=') == Ne(x, y) # issue 6116 p = Symbol('p', positive=True) assert Ne(p, 0) is S.true def test_rel_subs(): e = Relational(x, y, '==') e = e.subs(x, z) assert isinstance(e, Equality) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '>=') e = e.subs(x, z) assert isinstance(e, GreaterThan) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '<=') e = e.subs(x, z) assert isinstance(e, LessThan) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '>') e = e.subs(x, z) assert isinstance(e, StrictGreaterThan) assert e.lhs == z assert e.rhs == y e = Relational(x, y, '<') e = e.subs(x, z) assert isinstance(e, StrictLessThan) assert e.lhs == z assert e.rhs == y e = Eq(x, 0) assert e.subs(x, 0) is S.true assert e.subs(x, 1) is S.false def test_wrappers(): e = x + x**2 res = Relational(y, e, '==') assert Rel(y, x + x**2, '==') == res assert Eq(y, x + x**2) == res res = Relational(y, e, '<') assert Lt(y, x + x**2) == res res = Relational(y, e, '<=') assert Le(y, x + x**2) == res res = Relational(y, e, '>') assert Gt(y, x + x**2) == res res = Relational(y, e, '>=') assert Ge(y, x + x**2) == res res = Relational(y, e, '!=') assert Ne(y, x + x**2) == res def test_Eq_Ne(): assert Eq(x, x) # issue 5719 with warns_deprecated_sympy(): assert Eq(x) == Eq(x, 0) # issue 6116 p = Symbol('p', positive=True) assert Eq(p, 0) is S.false # issue 13348; 19048 # SymPy is strict about 0 and 1 not being # interpreted as Booleans assert Eq(True, 1) is S.false assert Eq(False, 0) is S.false assert Eq(~x, 0) is S.false assert Eq(~x, 1) is S.false assert Ne(True, 1) is S.true assert Ne(False, 0) is S.true assert Ne(~x, 0) is S.true assert Ne(~x, 1) is S.true assert Eq((), 1) is S.false assert Ne((), 1) is S.true def test_as_poly(): from sympy.polys.polytools import Poly # Only Eq should have an as_poly method: assert Eq(x, 1).as_poly() == Poly(x - 1, x, domain='ZZ') raises(AttributeError, lambda: Ne(x, 1).as_poly()) raises(AttributeError, lambda: Ge(x, 1).as_poly()) raises(AttributeError, lambda: Gt(x, 1).as_poly()) raises(AttributeError, lambda: Le(x, 1).as_poly()) raises(AttributeError, lambda: Lt(x, 1).as_poly()) def test_rel_Infinity(): # NOTE: All of these are actually handled by sympy.core.Number, and do # not create Relational objects. assert (oo > oo) is S.false assert (oo > -oo) is S.true assert (oo > 1) is S.true assert (oo < oo) is S.false assert (oo < -oo) is S.false assert (oo < 1) is S.false assert (oo >= oo) is S.true assert (oo >= -oo) is S.true assert (oo >= 1) is S.true assert (oo <= oo) is S.true assert (oo <= -oo) is S.false assert (oo <= 1) is S.false assert (-oo > oo) is S.false assert (-oo > -oo) is S.false assert (-oo > 1) is S.false assert (-oo < oo) is S.true assert (-oo < -oo) is S.false assert (-oo < 1) is S.true assert (-oo >= oo) is S.false assert (-oo >= -oo) is S.true assert (-oo >= 1) is S.false assert (-oo <= oo) is S.true assert (-oo <= -oo) is S.true assert (-oo <= 1) is S.true def test_infinite_symbol_inequalities(): x = Symbol('x', extended_positive=True, infinite=True) y = Symbol('y', extended_positive=True, infinite=True) z = Symbol('z', extended_negative=True, infinite=True) w = Symbol('w', extended_negative=True, infinite=True) inf_set = (x, y, oo) ninf_set = (z, w, -oo) for inf1 in inf_set: assert (inf1 < 1) is S.false assert (inf1 > 1) is S.true assert (inf1 <= 1) is S.false assert (inf1 >= 1) is S.true for inf2 in inf_set: assert (inf1 < inf2) is S.false assert (inf1 > inf2) is S.false assert (inf1 <= inf2) is S.true assert (inf1 >= inf2) is S.true for ninf1 in ninf_set: assert (inf1 < ninf1) is S.false assert (inf1 > ninf1) is S.true assert (inf1 <= ninf1) is S.false assert (inf1 >= ninf1) is S.true assert (ninf1 < inf1) is S.true assert (ninf1 > inf1) is S.false assert (ninf1 <= inf1) is S.true assert (ninf1 >= inf1) is S.false for ninf1 in ninf_set: assert (ninf1 < 1) is S.true assert (ninf1 > 1) is S.false assert (ninf1 <= 1) is S.true assert (ninf1 >= 1) is S.false for ninf2 in ninf_set: assert (ninf1 < ninf2) is S.false assert (ninf1 > ninf2) is S.false assert (ninf1 <= ninf2) is S.true assert (ninf1 >= ninf2) is S.true def test_bool(): assert Eq(0, 0) is S.true assert Eq(1, 0) is S.false assert Ne(0, 0) is S.false assert Ne(1, 0) is S.true assert Lt(0, 1) is S.true assert Lt(1, 0) is S.false assert Le(0, 1) is S.true assert Le(1, 0) is S.false assert Le(0, 0) is S.true assert Gt(1, 0) is S.true assert Gt(0, 1) is S.false assert Ge(1, 0) is S.true assert Ge(0, 1) is S.false assert Ge(1, 1) is S.true assert Eq(I, 2) is S.false assert Ne(I, 2) is S.true raises(TypeError, lambda: Gt(I, 2)) raises(TypeError, lambda: Ge(I, 2)) raises(TypeError, lambda: Lt(I, 2)) raises(TypeError, lambda: Le(I, 2)) a = Float('.000000000000000000001', '') b = Float('.0000000000000000000001', '') assert Eq(pi + a, pi + b) is S.false def test_rich_cmp(): assert (x < y) == Lt(x, y) assert (x <= y) == Le(x, y) assert (x > y) == Gt(x, y) assert (x >= y) == Ge(x, y) def test_doit(): from sympy import Symbol p = Symbol('p', positive=True) n = Symbol('n', negative=True) np = Symbol('np', nonpositive=True) nn = Symbol('nn', nonnegative=True) assert Gt(p, 0).doit() is S.true assert Gt(p, 1).doit() == Gt(p, 1) assert Ge(p, 0).doit() is S.true assert Le(p, 0).doit() is S.false assert Lt(n, 0).doit() is S.true assert Le(np, 0).doit() is S.true assert Gt(nn, 0).doit() == Gt(nn, 0) assert Lt(nn, 0).doit() is S.false assert Eq(x, 0).doit() == Eq(x, 0) def test_new_relational(): x = Symbol('x') assert Eq(x, 0) == Relational(x, 0) # None ==> Equality assert Eq(x, 0) == Relational(x, 0, '==') assert Eq(x, 0) == Relational(x, 0, 'eq') assert Eq(x, 0) == Equality(x, 0) assert Eq(x, 0) != Relational(x, 1) # None ==> Equality assert Eq(x, 0) != Relational(x, 1, '==') assert Eq(x, 0) != Relational(x, 1, 'eq') assert Eq(x, 0) != Equality(x, 1) assert Eq(x, -1) == Relational(x, -1) # None ==> Equality assert Eq(x, -1) == Relational(x, -1, '==') assert Eq(x, -1) == Relational(x, -1, 'eq') assert Eq(x, -1) == Equality(x, -1) assert Eq(x, -1) != Relational(x, 1) # None ==> Equality assert Eq(x, -1) != Relational(x, 1, '==') assert Eq(x, -1) != Relational(x, 1, 'eq') assert Eq(x, -1) != Equality(x, 1) assert Ne(x, 0) == Relational(x, 0, '!=') assert Ne(x, 0) == Relational(x, 0, '<>') assert Ne(x, 0) == Relational(x, 0, 'ne') assert Ne(x, 0) == Unequality(x, 0) assert Ne(x, 0) != Relational(x, 1, '!=') assert Ne(x, 0) != Relational(x, 1, '<>') assert Ne(x, 0) != Relational(x, 1, 'ne') assert Ne(x, 0) != Unequality(x, 1) assert Ge(x, 0) == Relational(x, 0, '>=') assert Ge(x, 0) == Relational(x, 0, 'ge') assert Ge(x, 0) == GreaterThan(x, 0) assert Ge(x, 1) != Relational(x, 0, '>=') assert Ge(x, 1) != Relational(x, 0, 'ge') assert Ge(x, 1) != GreaterThan(x, 0) assert (x >= 1) == Relational(x, 1, '>=') assert (x >= 1) == Relational(x, 1, 'ge') assert (x >= 1) == GreaterThan(x, 1) assert (x >= 0) != Relational(x, 1, '>=') assert (x >= 0) != Relational(x, 1, 'ge') assert (x >= 0) != GreaterThan(x, 1) assert Le(x, 0) == Relational(x, 0, '<=') assert Le(x, 0) == Relational(x, 0, 'le') assert Le(x, 0) == LessThan(x, 0) assert Le(x, 1) != Relational(x, 0, '<=') assert Le(x, 1) != Relational(x, 0, 'le') assert Le(x, 1) != LessThan(x, 0) assert (x <= 1) == Relational(x, 1, '<=') assert (x <= 1) == Relational(x, 1, 'le') assert (x <= 1) == LessThan(x, 1) assert (x <= 0) != Relational(x, 1, '<=') assert (x <= 0) != Relational(x, 1, 'le') assert (x <= 0) != LessThan(x, 1) assert Gt(x, 0) == Relational(x, 0, '>') assert Gt(x, 0) == Relational(x, 0, 'gt') assert Gt(x, 0) == StrictGreaterThan(x, 0) assert Gt(x, 1) != Relational(x, 0, '>') assert Gt(x, 1) != Relational(x, 0, 'gt') assert Gt(x, 1) != StrictGreaterThan(x, 0) assert (x > 1) == Relational(x, 1, '>') assert (x > 1) == Relational(x, 1, 'gt') assert (x > 1) == StrictGreaterThan(x, 1) assert (x > 0) != Relational(x, 1, '>') assert (x > 0) != Relational(x, 1, 'gt') assert (x > 0) != StrictGreaterThan(x, 1) assert Lt(x, 0) == Relational(x, 0, '<') assert Lt(x, 0) == Relational(x, 0, 'lt') assert Lt(x, 0) == StrictLessThan(x, 0) assert Lt(x, 1) != Relational(x, 0, '<') assert Lt(x, 1) != Relational(x, 0, 'lt') assert Lt(x, 1) != StrictLessThan(x, 0) assert (x < 1) == Relational(x, 1, '<') assert (x < 1) == Relational(x, 1, 'lt') assert (x < 1) == StrictLessThan(x, 1) assert (x < 0) != Relational(x, 1, '<') assert (x < 0) != Relational(x, 1, 'lt') assert (x < 0) != StrictLessThan(x, 1) # finally, some fuzz testing from random import randint for i in range(100): while 1: strtype, length = (chr, 65535) if randint(0, 1) else (chr, 255) relation_type = strtype(randint(0, length)) if randint(0, 1): relation_type += strtype(randint(0, length)) if relation_type not in ('==', 'eq', '!=', '<>', 'ne', '>=', 'ge', '<=', 'le', '>', 'gt', '<', 'lt', ':=', '+=', '-=', '*=', '/=', '%='): break raises(ValueError, lambda: Relational(x, 1, relation_type)) assert all(Relational(x, 0, op).rel_op == '==' for op in ('eq', '==')) assert all(Relational(x, 0, op).rel_op == '!=' for op in ('ne', '<>', '!=')) assert all(Relational(x, 0, op).rel_op == '>' for op in ('gt', '>')) assert all(Relational(x, 0, op).rel_op == '<' for op in ('lt', '<')) assert all(Relational(x, 0, op).rel_op == '>=' for op in ('ge', '>=')) assert all(Relational(x, 0, op).rel_op == '<=' for op in ('le', '<=')) def test_relational_arithmetic(): for cls in [Eq, Ne, Le, Lt, Ge, Gt]: rel = cls(x, y) raises(TypeError, lambda: 0+rel) raises(TypeError, lambda: 1*rel) raises(TypeError, lambda: 1**rel) raises(TypeError, lambda: rel**1) raises(TypeError, lambda: Add(0, rel)) raises(TypeError, lambda: Mul(1, rel)) raises(TypeError, lambda: Pow(1, rel)) raises(TypeError, lambda: Pow(rel, 1)) def test_relational_bool_output(): # https://github.com/sympy/sympy/issues/5931 raises(TypeError, lambda: bool(x > 3)) raises(TypeError, lambda: bool(x >= 3)) raises(TypeError, lambda: bool(x < 3)) raises(TypeError, lambda: bool(x <= 3)) raises(TypeError, lambda: bool(Eq(x, 3))) raises(TypeError, lambda: bool(Ne(x, 3))) def test_relational_logic_symbols(): # See issue 6204 assert (x < y) & (z < t) == And(x < y, z < t) assert (x < y) | (z < t) == Or(x < y, z < t) assert ~(x < y) == Not(x < y) assert (x < y) >> (z < t) == Implies(x < y, z < t) assert (x < y) << (z < t) == Implies(z < t, x < y) assert (x < y) ^ (z < t) == Xor(x < y, z < t) assert isinstance((x < y) & (z < t), And) assert isinstance((x < y) | (z < t), Or) assert isinstance(~(x < y), GreaterThan) assert isinstance((x < y) >> (z < t), Implies) assert isinstance((x < y) << (z < t), Implies) assert isinstance((x < y) ^ (z < t), (Or, Xor)) def test_univariate_relational_as_set(): assert (x > 0).as_set() == Interval(0, oo, True, True) assert (x >= 0).as_set() == Interval(0, oo) assert (x < 0).as_set() == Interval(-oo, 0, True, True) assert (x <= 0).as_set() == Interval(-oo, 0) assert Eq(x, 0).as_set() == FiniteSet(0) assert Ne(x, 0).as_set() == Interval(-oo, 0, True, True) + \ Interval(0, oo, True, True) assert (x**2 >= 4).as_set() == Interval(-oo, -2) + Interval(2, oo) @XFAIL def test_multivariate_relational_as_set(): assert (x*y >= 0).as_set() == Interval(0, oo)*Interval(0, oo) + \ Interval(-oo, 0)*Interval(-oo, 0) def test_Not(): assert Not(Equality(x, y)) == Unequality(x, y) assert Not(Unequality(x, y)) == Equality(x, y) assert Not(StrictGreaterThan(x, y)) == LessThan(x, y) assert Not(StrictLessThan(x, y)) == GreaterThan(x, y) assert Not(GreaterThan(x, y)) == StrictLessThan(x, y) assert Not(LessThan(x, y)) == StrictGreaterThan(x, y) def test_evaluate(): assert str(Eq(x, x, evaluate=False)) == 'Eq(x, x)' assert Eq(x, x, evaluate=False).doit() == S.true assert str(Ne(x, x, evaluate=False)) == 'Ne(x, x)' assert Ne(x, x, evaluate=False).doit() == S.false assert str(Ge(x, x, evaluate=False)) == 'x >= x' assert str(Le(x, x, evaluate=False)) == 'x <= x' assert str(Gt(x, x, evaluate=False)) == 'x > x' assert str(Lt(x, x, evaluate=False)) == 'x < x' def assert_all_ineq_raise_TypeError(a, b): raises(TypeError, lambda: a > b) raises(TypeError, lambda: a >= b) raises(TypeError, lambda: a < b) raises(TypeError, lambda: a <= b) raises(TypeError, lambda: b > a) raises(TypeError, lambda: b >= a) raises(TypeError, lambda: b < a) raises(TypeError, lambda: b <= a) def assert_all_ineq_give_class_Inequality(a, b): """All inequality operations on `a` and `b` result in class Inequality.""" from sympy.core.relational import _Inequality as Inequality assert isinstance(a > b, Inequality) assert isinstance(a >= b, Inequality) assert isinstance(a < b, Inequality) assert isinstance(a <= b, Inequality) assert isinstance(b > a, Inequality) assert isinstance(b >= a, Inequality) assert isinstance(b < a, Inequality) assert isinstance(b <= a, Inequality) def test_imaginary_compare_raises_TypeError(): # See issue #5724 assert_all_ineq_raise_TypeError(I, x) def test_complex_compare_not_real(): # two cases which are not real y = Symbol('y', imaginary=True) z = Symbol('z', complex=True, extended_real=False) for w in (y, z): assert_all_ineq_raise_TypeError(2, w) # some cases which should remain un-evaluated t = Symbol('t') x = Symbol('x', real=True) z = Symbol('z', complex=True) for w in (x, z, t): assert_all_ineq_give_class_Inequality(2, w) def test_imaginary_and_inf_compare_raises_TypeError(): # See pull request #7835 y = Symbol('y', imaginary=True) assert_all_ineq_raise_TypeError(oo, y) assert_all_ineq_raise_TypeError(-oo, y) def test_complex_pure_imag_not_ordered(): raises(TypeError, lambda: 2*I < 3*I) # more generally x = Symbol('x', real=True, nonzero=True) y = Symbol('y', imaginary=True) z = Symbol('z', complex=True) assert_all_ineq_raise_TypeError(I, y) t = I*x # an imaginary number, should raise errors assert_all_ineq_raise_TypeError(2, t) t = -I*y # a real number, so no errors assert_all_ineq_give_class_Inequality(2, t) t = I*z # unknown, should be unevaluated assert_all_ineq_give_class_Inequality(2, t) def test_x_minus_y_not_same_as_x_lt_y(): """ A consequence of pull request #7792 is that `x - y < 0` and `x < y` are not synonymous. """ x = I + 2 y = I + 3 raises(TypeError, lambda: x < y) assert x - y < 0 ineq = Lt(x, y, evaluate=False) raises(TypeError, lambda: ineq.doit()) assert ineq.lhs - ineq.rhs < 0 t = Symbol('t', imaginary=True) x = 2 + t y = 3 + t ineq = Lt(x, y, evaluate=False) raises(TypeError, lambda: ineq.doit()) assert ineq.lhs - ineq.rhs < 0 # this one should give error either way x = I + 2 y = 2*I + 3 raises(TypeError, lambda: x < y) raises(TypeError, lambda: x - y < 0) def test_nan_equality_exceptions(): # See issue #7774 import random assert Equality(nan, nan) is S.false assert Unequality(nan, nan) is S.true # See issue #7773 A = (x, S.Zero, S.One/3, pi, oo, -oo) assert Equality(nan, random.choice(A)) is S.false assert Equality(random.choice(A), nan) is S.false assert Unequality(nan, random.choice(A)) is S.true assert Unequality(random.choice(A), nan) is S.true def test_nan_inequality_raise_errors(): # See discussion in pull request #7776. We test inequalities with # a set including examples of various classes. for q in (x, S.Zero, S(10), S.One/3, pi, S(1.3), oo, -oo, nan): assert_all_ineq_raise_TypeError(q, nan) def test_nan_complex_inequalities(): # Comparisons of NaN with non-real raise errors, we're not too # fussy whether its the NaN error or complex error. for r in (I, zoo, Symbol('z', imaginary=True)): assert_all_ineq_raise_TypeError(r, nan) def test_complex_infinity_inequalities(): raises(TypeError, lambda: zoo > 0) raises(TypeError, lambda: zoo >= 0) raises(TypeError, lambda: zoo < 0) raises(TypeError, lambda: zoo <= 0) def test_inequalities_symbol_name_same(): """Using the operator and functional forms should give same results.""" # We test all combinations from a set # FIXME: could replace with random selection after test passes A = (x, y, S.Zero, S.One/3, pi, oo, -oo) for a in A: for b in A: assert Gt(a, b) == (a > b) assert Lt(a, b) == (a < b) assert Ge(a, b) == (a >= b) assert Le(a, b) == (a <= b) for b in (y, S.Zero, S.One/3, pi, oo, -oo): assert Gt(x, b, evaluate=False) == (x > b) assert Lt(x, b, evaluate=False) == (x < b) assert Ge(x, b, evaluate=False) == (x >= b) assert Le(x, b, evaluate=False) == (x <= b) for b in (y, S.Zero, S.One/3, pi, oo, -oo): assert Gt(b, x, evaluate=False) == (b > x) assert Lt(b, x, evaluate=False) == (b < x) assert Ge(b, x, evaluate=False) == (b >= x) assert Le(b, x, evaluate=False) == (b <= x) def test_inequalities_symbol_name_same_complex(): """Using the operator and functional forms should give same results. With complex non-real numbers, both should raise errors. """ # FIXME: could replace with random selection after test passes for a in (x, S.Zero, S.One/3, pi, oo, Rational(1, 3)): raises(TypeError, lambda: Gt(a, I)) raises(TypeError, lambda: a > I) raises(TypeError, lambda: Lt(a, I)) raises(TypeError, lambda: a < I) raises(TypeError, lambda: Ge(a, I)) raises(TypeError, lambda: a >= I) raises(TypeError, lambda: Le(a, I)) raises(TypeError, lambda: a <= I) def test_inequalities_cant_sympify_other(): # see issue 7833 from operator import gt, lt, ge, le bar = "foo" for a in (x, S.Zero, S.One/3, pi, I, zoo, oo, -oo, nan, Rational(1, 3)): for op in (lt, gt, le, ge): raises(TypeError, lambda: op(a, bar)) def test_ineq_avoid_wild_symbol_flip(): # see issue #7951, we try to avoid this internally, e.g., by using # __lt__ instead of "<". from sympy.core.symbol import Wild p = symbols('p', cls=Wild) # x > p might flip, but Gt should not: assert Gt(x, p) == Gt(x, p, evaluate=False) # Previously failed as 'p > x': e = Lt(x, y).subs({y: p}) assert e == Lt(x, p, evaluate=False) # Previously failed as 'p <= x': e = Ge(x, p).doit() assert e == Ge(x, p, evaluate=False) def test_issue_8245(): a = S("6506833320952669167898688709329/5070602400912917605986812821504") assert rel_check(a, a.n(10)) assert rel_check(a, a.n(20)) assert rel_check(a, a.n()) # prec of 30 is enough to fully capture a as mpf assert Float(a, 30) == Float(str(a.p), '')/Float(str(a.q), '') for i in range(31): r = Rational(Float(a, i)) f = Float(r) assert (f < a) == (Rational(f) < a) # test sign handling assert (-f < -a) == (Rational(-f) < -a) # test equivalence handling isa = Float(a.p,'')/Float(a.q,'') assert isa <= a assert not isa < a assert isa >= a assert not isa > a assert isa > 0 a = sqrt(2) r = Rational(str(a.n(30))) assert rel_check(a, r) a = sqrt(2) r = Rational(str(a.n(29))) assert rel_check(a, r) assert Eq(log(cos(2)**2 + sin(2)**2), 0) is S.true def test_issue_8449(): p = Symbol('p', nonnegative=True) assert Lt(-oo, p) assert Ge(-oo, p) is S.false assert Gt(oo, -p) assert Le(oo, -p) is S.false def test_simplify_relational(): assert simplify(x*(y + 1) - x*y - x + 1 < x) == (x > 1) assert simplify(x*(y + 1) - x*y - x - 1 < x) == (x > -1) assert simplify(x < x*(y + 1) - x*y - x + 1) == (x < 1) q, r = symbols("q r") assert (((-q + r) - (q - r)) <= 0).simplify() == (q >= r) root2 = sqrt(2) equation = ((root2 * (-q + r) - root2 * (q - r)) <= 0).simplify() assert equation == (q >= r) r = S.One < x # canonical operations are not the same as simplification, # so if there is no simplification, canonicalization will # be done unless the measure forbids it assert simplify(r) == r.canonical assert simplify(r, ratio=0) != r.canonical # this is not a random test; in _eval_simplify # this will simplify to S.false and that is the # reason for the 'if r.is_Relational' in Relational's # _eval_simplify routine assert simplify(-(2**(pi*Rational(3, 2)) + 6**pi)**(1/pi) + 2*(2**(pi/2) + 3**pi)**(1/pi) < 0) is S.false # canonical at least assert Eq(y, x).simplify() == Eq(x, y) assert Eq(x - 1, 0).simplify() == Eq(x, 1) assert Eq(x - 1, x).simplify() == S.false assert Eq(2*x - 1, x).simplify() == Eq(x, 1) assert Eq(2*x, 4).simplify() == Eq(x, 2) z = cos(1)**2 + sin(1)**2 - 1 # z.is_zero is None assert Eq(z*x, 0).simplify() == S.true assert Ne(y, x).simplify() == Ne(x, y) assert Ne(x - 1, 0).simplify() == Ne(x, 1) assert Ne(x - 1, x).simplify() == S.true assert Ne(2*x - 1, x).simplify() == Ne(x, 1) assert Ne(2*x, 4).simplify() == Ne(x, 2) assert Ne(z*x, 0).simplify() == S.false # No real-valued assumptions assert Ge(y, x).simplify() == Le(x, y) assert Ge(x - 1, 0).simplify() == Ge(x, 1) assert Ge(x - 1, x).simplify() == S.false assert Ge(2*x - 1, x).simplify() == Ge(x, 1) assert Ge(2*x, 4).simplify() == Ge(x, 2) assert Ge(z*x, 0).simplify() == S.true assert Ge(x, -2).simplify() == Ge(x, -2) assert Ge(-x, -2).simplify() == Le(x, 2) assert Ge(x, 2).simplify() == Ge(x, 2) assert Ge(-x, 2).simplify() == Le(x, -2) assert Le(y, x).simplify() == Ge(x, y) assert Le(x - 1, 0).simplify() == Le(x, 1) assert Le(x - 1, x).simplify() == S.true assert Le(2*x - 1, x).simplify() == Le(x, 1) assert Le(2*x, 4).simplify() == Le(x, 2) assert Le(z*x, 0).simplify() == S.true assert Le(x, -2).simplify() == Le(x, -2) assert Le(-x, -2).simplify() == Ge(x, 2) assert Le(x, 2).simplify() == Le(x, 2) assert Le(-x, 2).simplify() == Ge(x, -2) assert Gt(y, x).simplify() == Lt(x, y) assert Gt(x - 1, 0).simplify() == Gt(x, 1) assert Gt(x - 1, x).simplify() == S.false assert Gt(2*x - 1, x).simplify() == Gt(x, 1) assert Gt(2*x, 4).simplify() == Gt(x, 2) assert Gt(z*x, 0).simplify() == S.false assert Gt(x, -2).simplify() == Gt(x, -2) assert Gt(-x, -2).simplify() == Lt(x, 2) assert Gt(x, 2).simplify() == Gt(x, 2) assert Gt(-x, 2).simplify() == Lt(x, -2) assert Lt(y, x).simplify() == Gt(x, y) assert Lt(x - 1, 0).simplify() == Lt(x, 1) assert Lt(x - 1, x).simplify() == S.true assert Lt(2*x - 1, x).simplify() == Lt(x, 1) assert Lt(2*x, 4).simplify() == Lt(x, 2) assert Lt(z*x, 0).simplify() == S.false assert Lt(x, -2).simplify() == Lt(x, -2) assert Lt(-x, -2).simplify() == Gt(x, 2) assert Lt(x, 2).simplify() == Lt(x, 2) assert Lt(-x, 2).simplify() == Gt(x, -2) # Test particulat branches of _eval_simplify m = exp(1) - exp_polar(1) assert simplify(m*x > 1) is S.false # These two tests the same branch assert simplify(m*x + 2*m*y > 1) is S.false assert simplify(m*x + y > 1 + y) is S.false def test_equals(): w, x, y, z = symbols('w:z') f = Function('f') assert Eq(x, 1).equals(Eq(x*(y + 1) - x*y - x + 1, x)) assert Eq(x, y).equals(x < y, True) == False assert Eq(x, f(1)).equals(Eq(x, f(2)), True) == f(1) - f(2) assert Eq(f(1), y).equals(Eq(f(2), y), True) == f(1) - f(2) assert Eq(x, f(1)).equals(Eq(f(2), x), True) == f(1) - f(2) assert Eq(f(1), x).equals(Eq(x, f(2)), True) == f(1) - f(2) assert Eq(w, x).equals(Eq(y, z), True) == False assert Eq(f(1), f(2)).equals(Eq(f(3), f(4)), True) == f(1) - f(3) assert (x < y).equals(y > x, True) == True assert (x < y).equals(y >= x, True) == False assert (x < y).equals(z < y, True) == False assert (x < y).equals(x < z, True) == False assert (x < f(1)).equals(x < f(2), True) == f(1) - f(2) assert (f(1) < x).equals(f(2) < x, True) == f(1) - f(2) def test_reversed(): assert (x < y).reversed == (y > x) assert (x <= y).reversed == (y >= x) assert Eq(x, y, evaluate=False).reversed == Eq(y, x, evaluate=False) assert Ne(x, y, evaluate=False).reversed == Ne(y, x, evaluate=False) assert (x >= y).reversed == (y <= x) assert (x > y).reversed == (y < x) def test_canonical(): c = [i.canonical for i in ( x + y < z, x + 2 > 3, x < 2, S(2) > x, x**2 > -x/y, Gt(3, 2, evaluate=False) )] assert [i.canonical for i in c] == c assert [i.reversed.canonical for i in c] == c assert not any(i.lhs.is_Number and not i.rhs.is_Number for i in c) c = [i.reversed.func(i.rhs, i.lhs, evaluate=False).canonical for i in c] assert [i.canonical for i in c] == c assert [i.reversed.canonical for i in c] == c assert not any(i.lhs.is_Number and not i.rhs.is_Number for i in c) @XFAIL def test_issue_8444_nonworkingtests(): x = symbols('x', real=True) assert (x <= oo) == (x >= -oo) == True x = symbols('x') assert x >= floor(x) assert (x < floor(x)) == False assert x <= ceiling(x) assert (x > ceiling(x)) == False def test_issue_8444_workingtests(): x = symbols('x') assert Gt(x, floor(x)) == Gt(x, floor(x), evaluate=False) assert Ge(x, floor(x)) == Ge(x, floor(x), evaluate=False) assert Lt(x, ceiling(x)) == Lt(x, ceiling(x), evaluate=False) assert Le(x, ceiling(x)) == Le(x, ceiling(x), evaluate=False) i = symbols('i', integer=True) assert (i > floor(i)) == False assert (i < ceiling(i)) == False def test_issue_10304(): d = cos(1)**2 + sin(1)**2 - 1 assert d.is_comparable is False # if this fails, find a new d e = 1 + d*I assert simplify(Eq(e, 0)) is S.false def test_issue_18412(): d = (Rational(1, 6) + z / 4 / y) assert Eq(x, pi * y**3 * d).replace(y**3, z) == Eq(x, pi * z * d) def test_issue_10401(): x = symbols('x') fin = symbols('inf', finite=True) inf = symbols('inf', infinite=True) inf2 = symbols('inf2', infinite=True) infx = symbols('infx', infinite=True, extended_real=True) # Used in the commented tests below: #infx2 = symbols('infx2', infinite=True, extended_real=True) infnx = symbols('inf~x', infinite=True, extended_real=False) infnx2 = symbols('inf~x2', infinite=True, extended_real=False) infp = symbols('infp', infinite=True, extended_positive=True) infp1 = symbols('infp1', infinite=True, extended_positive=True) infn = symbols('infn', infinite=True, extended_negative=True) zero = symbols('z', zero=True) nonzero = symbols('nz', zero=False, finite=True) assert Eq(1/(1/x + 1), 1).func is Eq assert Eq(1/(1/x + 1), 1).subs(x, S.ComplexInfinity) is S.true assert Eq(1/(1/fin + 1), 1) is S.false T, F = S.true, S.false assert Eq(fin, inf) is F assert Eq(inf, inf2) not in (T, F) and inf != inf2 assert Eq(1 + inf, 2 + inf2) not in (T, F) and inf != inf2 assert Eq(infp, infp1) is T assert Eq(infp, infn) is F assert Eq(1 + I*oo, I*oo) is F assert Eq(I*oo, 1 + I*oo) is F assert Eq(1 + I*oo, 2 + I*oo) is F assert Eq(1 + I*oo, 2 + I*infx) is F assert Eq(1 + I*oo, 2 + infx) is F # FIXME: The test below fails because (-infx).is_extended_positive is True # (should be None) #assert Eq(1 + I*infx, 1 + I*infx2) not in (T, F) and infx != infx2 # assert Eq(zoo, sqrt(2) + I*oo) is F assert Eq(zoo, oo) is F r = Symbol('r', real=True) i = Symbol('i', imaginary=True) assert Eq(i*I, r) not in (T, F) assert Eq(infx, infnx) is F assert Eq(infnx, infnx2) not in (T, F) and infnx != infnx2 assert Eq(zoo, oo) is F assert Eq(inf/inf2, 0) is F assert Eq(inf/fin, 0) is F assert Eq(fin/inf, 0) is T assert Eq(zero/nonzero, 0) is T and ((zero/nonzero) != 0) # The commented out test below is incorrect because: assert zoo == -zoo assert Eq(zoo, -zoo) is T assert Eq(oo, -oo) is F assert Eq(inf, -inf) not in (T, F) assert Eq(fin/(fin + 1), 1) is S.false o = symbols('o', odd=True) assert Eq(o, 2*o) is S.false p = symbols('p', positive=True) assert Eq(p/(p - 1), 1) is F def test_issue_10633(): assert Eq(True, False) == False assert Eq(False, True) == False assert Eq(True, True) == True assert Eq(False, False) == True def test_issue_10927(): x = symbols('x') assert str(Eq(x, oo)) == 'Eq(x, oo)' assert str(Eq(x, -oo)) == 'Eq(x, -oo)' def test_issues_13081_12583_12534(): # 13081 r = Rational('905502432259640373/288230376151711744') assert (r < pi) is S.false assert (r > pi) is S.true # 12583 v = sqrt(2) u = sqrt(v) + 2/sqrt(10 - 8/sqrt(2 - v) + 4*v*(1/sqrt(2 - v) - 1)) assert (u >= 0) is S.true # 12534; Rational vs NumberSymbol # here are some precisions for which Rational forms # at a lower and higher precision bracket the value of pi # e.g. for p = 20: # Rational(pi.n(p + 1)).n(25) = 3.14159265358979323846 2834 # pi.n(25) = 3.14159265358979323846 2643 # Rational(pi.n(p )).n(25) = 3.14159265358979323846 1987 assert [p for p in range(20, 50) if (Rational(pi.n(p)) < pi) and (pi < Rational(pi.n(p + 1)))] == [20, 24, 27, 33, 37, 43, 48] # pick one such precision and affirm that the reversed operation # gives the opposite result, i.e. if x < y is true then x > y # must be false for i in (20, 21): v = pi.n(i) assert rel_check(Rational(v), pi) assert rel_check(v, pi) assert rel_check(pi.n(20), pi.n(21)) # Float vs Rational # the rational form is less than the floating representation # at the same precision assert [i for i in range(15, 50) if Rational(pi.n(i)) > pi.n(i)] == [] # this should be the same if we reverse the relational assert [i for i in range(15, 50) if pi.n(i) < Rational(pi.n(i))] == [] def test_issue_18188(): from sympy.sets.conditionset import ConditionSet result1 = Eq(x*cos(x) - 3*sin(x), 0) assert result1.as_set() == ConditionSet(x, Eq(x*cos(x) - 3*sin(x), 0), Reals) result2 = Eq(x**2 + sqrt(x*2) + sin(x), 0) assert result2.as_set() == ConditionSet(x, Eq(sqrt(2)*sqrt(x) + x**2 + sin(x), 0), Reals) def test_binary_symbols(): ans = {x} for f in Eq, Ne: for t in S.true, S.false: eq = f(x, S.true) assert eq.binary_symbols == ans assert eq.reversed.binary_symbols == ans assert f(x, 1).binary_symbols == set() def test_rel_args(): # can't have Boolean args; this is automatic for True/False # with Python 3 and we confirm that SymPy does the same # for true/false for op in ['<', '<=', '>', '>=']: for b in (S.true, x < 1, And(x, y)): for v in (0.1, 1, 2**32, t, S.One): raises(TypeError, lambda: Relational(b, v, op)) def test_Equality_rewrite_as_Add(): eq = Eq(x + y, y - x) assert eq.rewrite(Add) == 2*x assert eq.rewrite(Add, evaluate=None).args == (x, x, y, -y) assert eq.rewrite(Add, evaluate=False).args == (x, y, x, -y) def test_issue_15847(): a = Ne(x*(x+y), x**2 + x*y) assert simplify(a) == False def test_negated_property(): eq = Eq(x, y) assert eq.negated == Ne(x, y) eq = Ne(x, y) assert eq.negated == Eq(x, y) eq = Ge(x + y, y - x) assert eq.negated == Lt(x + y, y - x) for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(x, y).negated.negated == f(x, y) def test_reversedsign_property(): eq = Eq(x, y) assert eq.reversedsign == Eq(-x, -y) eq = Ne(x, y) assert eq.reversedsign == Ne(-x, -y) eq = Ge(x + y, y - x) assert eq.reversedsign == Le(-x - y, x - y) for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(x, y).reversedsign.reversedsign == f(x, y) for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(-x, y).reversedsign.reversedsign == f(-x, y) for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(x, -y).reversedsign.reversedsign == f(x, -y) for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(-x, -y).reversedsign.reversedsign == f(-x, -y) def test_reversed_reversedsign_property(): for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(x, y).reversed.reversedsign == f(x, y).reversedsign.reversed for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(-x, y).reversed.reversedsign == f(-x, y).reversedsign.reversed for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(x, -y).reversed.reversedsign == f(x, -y).reversedsign.reversed for f in (Eq, Ne, Ge, Gt, Le, Lt): assert f(-x, -y).reversed.reversedsign == \ f(-x, -y).reversedsign.reversed def test_improved_canonical(): def test_different_forms(listofforms): for form1, form2 in combinations(listofforms, 2): assert form1.canonical == form2.canonical def generate_forms(expr): return [expr, expr.reversed, expr.reversedsign, expr.reversed.reversedsign] test_different_forms(generate_forms(x > -y)) test_different_forms(generate_forms(x >= -y)) test_different_forms(generate_forms(Eq(x, -y))) test_different_forms(generate_forms(Ne(x, -y))) test_different_forms(generate_forms(pi < x)) test_different_forms(generate_forms(pi - 5*y < -x + 2*y**2 - 7)) assert (pi >= x).canonical == (x <= pi) def test_set_equality_canonical(): a, b, c = symbols('a b c') A = Eq(FiniteSet(a, b, c), FiniteSet(1, 2, 3)) B = Ne(FiniteSet(a, b, c), FiniteSet(4, 5, 6)) assert A.canonical == A.reversed assert B.canonical == B.reversed def test_trigsimp(): # issue 16736 s, c = sin(2*x), cos(2*x) eq = Eq(s, c) assert trigsimp(eq) == eq # no rearrangement of sides # simplification of sides might result in # an unevaluated Eq changed = trigsimp(Eq(s + c, sqrt(2))) assert isinstance(changed, Eq) assert changed.subs(x, pi/8) is S.true # or an evaluated one assert trigsimp(Eq(cos(x)**2 + sin(x)**2, 1)) is S.true def test_polynomial_relation_simplification(): assert Ge(3*x*(x + 1) + 4, 3*x).simplify() in [Ge(x**2, -Rational(4,3)), Le(-x**2, Rational(4, 3))] assert Le(-(3*x*(x + 1) + 4), -3*x).simplify() in [Ge(x**2, -Rational(4,3)), Le(-x**2, Rational(4, 3))] assert ((x**2+3)*(x**2-1)+3*x >= 2*x**2).simplify() in [(x**4 + 3*x >= 3), (-x**4 - 3*x <= -3)] def test_multivariate_linear_function_simplification(): assert Ge(x + y, x - y).simplify() == Ge(y, 0) assert Le(-x + y, -x - y).simplify() == Le(y, 0) assert Eq(2*x + y, 2*x + y - 3).simplify() == False assert (2*x + y > 2*x + y - 3).simplify() == True assert (2*x + y < 2*x + y - 3).simplify() == False assert (2*x + y < 2*x + y + 3).simplify() == True a, b, c, d, e, f, g = symbols('a b c d e f g') assert Lt(a + b + c + 2*d, 3*d - f + g). simplify() == Lt(a, -b - c + d - f + g) def test_nonpolymonial_relations(): assert Eq(cos(x), 0).simplify() == Eq(cos(x), 0) def test_18778(): raises(TypeError, lambda: is_le(Basic(), Basic())) raises(TypeError, lambda: is_gt(Basic(), Basic())) raises(TypeError, lambda: is_ge(Basic(), Basic())) raises(TypeError, lambda: is_lt(Basic(), Basic())) def test_EvalEq(): """ This test exists to ensure backwards compatibility. The method to use is _eval_is_eq """ from sympy import Expr class PowTest(Expr): def __new__(cls, base, exp): return Basic.__new__(PowTest, _sympify(base), _sympify(exp)) def _eval_Eq(lhs, rhs): if type(lhs) == PowTest and type(rhs) == PowTest: return lhs.args[0] == rhs.args[0] and lhs.args[1] == rhs.args[1] assert is_eq(PowTest(3, 4), PowTest(3,4)) assert is_eq(PowTest(3, 4), _sympify(4)) is None assert is_neq(PowTest(3, 4), PowTest(3,7)) def test_is_eq(): # test assumptions assert is_eq(x, y, Q.infinite(x) & Q.finite(y)) is False assert is_eq(x, y, Q.infinite(x) & Q.infinite(y) & Q.extended_real(x) & ~Q.extended_real(y)) is False assert is_eq(x, y, Q.infinite(x) & Q.infinite(y) & Q.extended_positive(x) & Q.extended_negative(y)) is False assert is_eq(x+I, y+I, Q.infinite(x) & Q.finite(y)) is False assert is_eq(1+x*I, 1+y*I, Q.infinite(x) & Q.finite(y)) is False assert is_eq(x, S(0), assumptions=Q.zero(x)) assert is_eq(x, S(0), assumptions=~Q.zero(x)) is False assert is_eq(x, S(0), assumptions=Q.nonzero(x)) is False assert is_neq(x, S(0), assumptions=Q.zero(x)) is False assert is_neq(x, S(0), assumptions=~Q.zero(x)) assert is_neq(x, S(0), assumptions=Q.nonzero(x)) # test registration class PowTest(Expr): def __new__(cls, base, exp): return Basic.__new__(cls, _sympify(base), _sympify(exp)) @dispatch(PowTest, PowTest) def _eval_is_eq(lhs, rhs): if type(lhs) == PowTest and type(rhs) == PowTest: return fuzzy_and([is_eq(lhs.args[0], rhs.args[0]), is_eq(lhs.args[1], rhs.args[1])]) assert is_eq(PowTest(3, 4), PowTest(3,4)) assert is_eq(PowTest(3, 4), _sympify(4)) is None assert is_neq(PowTest(3, 4), PowTest(3,7)) def test_is_ge_le(): # test assumptions assert is_ge(x, S(0), Q.nonnegative(x)) is True assert is_ge(x, S(0), Q.negative(x)) is False # test registration class PowTest(Expr): def __new__(cls, base, exp): return Basic.__new__(cls, _sympify(base), _sympify(exp)) @dispatch(PowTest, PowTest) def _eval_is_ge(lhs, rhs): if type(lhs) == PowTest and type(rhs) == PowTest: return fuzzy_and([is_ge(lhs.args[0], rhs.args[0]), is_ge(lhs.args[1], rhs.args[1])]) assert is_ge(PowTest(3, 9), PowTest(3,2)) assert is_gt(PowTest(3, 9), PowTest(3,2)) assert is_le(PowTest(3, 2), PowTest(3,9)) assert is_lt(PowTest(3, 2), PowTest(3,9)) sympy-sympy-1.9/sympy/core/tests/test_rules.py000066400000000000000000000005351412543434000217440ustar00rootroot00000000000000from sympy.core.rules import Transform from sympy.testing.pytest import raises def test_Transform(): add1 = Transform(lambda x: x + 1, lambda x: x % 2 == 1) assert add1[1] == 2 assert (1 in add1) is True assert add1.get(1) == 2 raises(KeyError, lambda: add1[2]) assert (2 in add1) is False assert add1.get(2) is None sympy-sympy-1.9/sympy/core/tests/test_singleton.py000066400000000000000000000057341412543434000226220ustar00rootroot00000000000000from sympy.core.basic import Basic from sympy.core.numbers import Rational from sympy.core.singleton import S, Singleton def test_Singleton(): class MySingleton(Basic, metaclass=Singleton): pass MySingleton() # force instantiation assert MySingleton() is not Basic() assert MySingleton() is MySingleton() assert S.MySingleton is MySingleton() class MySingleton_sub(MySingleton): pass MySingleton_sub() assert MySingleton_sub() is not MySingleton() assert MySingleton_sub() is MySingleton_sub() def test_singleton_redefinition(): class TestSingleton(Basic, metaclass=Singleton): pass assert TestSingleton() is S.TestSingleton class TestSingleton(Basic, metaclass=Singleton): pass assert TestSingleton() is S.TestSingleton def test_names_in_namespace(): # Every singleton name should be accessible from the 'from sympy import *' # namespace in addition to the S object. However, it does not need to be # by the same name (e.g., oo instead of S.Infinity). # As a general rule, things should only be added to the singleton registry # if they are used often enough that code can benefit either from the # performance benefit of being able to use 'is' (this only matters in very # tight loops), or from the memory savings of having exactly one instance # (this matters for the numbers singletons, but very little else). The # singleton registry is already a bit overpopulated, and things cannot be # removed from it without breaking backwards compatibility. So if you got # here by adding something new to the singletons, ask yourself if it # really needs to be singletonized. Note that SymPy classes compare to one # another just fine, so Class() == Class() will give True even if each # Class() returns a new instance. Having unique instances is only # necessary for the above noted performance gains. It should not be needed # for any behavioral purposes. # If you determine that something really should be a singleton, it must be # accessible to sympify() without using 'S' (hence this test). Also, its # str printer should print a form that does not use S. This is because # sympify() disables attribute lookups by default for safety purposes. d = {} exec('from sympy import *', d) for name in dir(S) + list(S._classes_to_install): if name.startswith('_'): continue if name == 'register': continue if isinstance(getattr(S, name), Rational): continue if getattr(S, name).__module__.startswith('sympy.physics'): continue if name in ['MySingleton', 'MySingleton_sub', 'TestSingleton']: # From the tests above continue if name == 'NegativeInfinity': # Accessible by -oo continue # Use is here to ensure it is the exact same object assert any(getattr(S, name) is i for i in d.values()), name sympy-sympy-1.9/sympy/core/tests/test_subs.py000066400000000000000000000704151412543434000215720ustar00rootroot00000000000000from sympy import ( Symbol, Wild, sin, cos, exp, sqrt, pi, Function, Derivative, Integer, Eq, symbols, Add, I, Float, log, Rational, Lambda, atan2, cse, cot, tan, S, Tuple, Basic, Dict, Piecewise, oo, Mul, factor, nsimplify, zoo, Subs, RootOf, AccumBounds, Matrix, zeros, ZeroMatrix) from sympy.core.basic import _aresame from sympy.testing.pytest import XFAIL from sympy.abc import a, x, y, z, t def test_subs(): n3 = Rational(3) e = x e = e.subs(x, n3) assert e == Rational(3) e = 2*x assert e == 2*x e = e.subs(x, n3) assert e == Rational(6) def test_subs_Matrix(): z = zeros(2) z1 = ZeroMatrix(2, 2) assert (x*y).subs({x:z, y:0}) in [z, z1] assert (x*y).subs({y:z, x:0}) == 0 assert (x*y).subs({y:z, x:0}, simultaneous=True) in [z, z1] assert (x + y).subs({x: z, y: z}, simultaneous=True) in [z, z1] assert (x + y).subs({x: z, y: z}) in [z, z1] # Issue #15528 assert Mul(Matrix([[3]]), x).subs(x, 2.0) == Matrix([[6.0]]) # Does not raise a TypeError, see comment on the MatAdd postprocessor assert Add(Matrix([[3]]), x).subs(x, 2.0) == Add(Matrix([[3]]), 2.0) def test_subs_AccumBounds(): e = x e = e.subs(x, AccumBounds(1, 3)) assert e == AccumBounds(1, 3) e = 2*x e = e.subs(x, AccumBounds(1, 3)) assert e == AccumBounds(2, 6) e = x + x**2 e = e.subs(x, AccumBounds(-1, 1)) assert e == AccumBounds(-1, 2) def test_trigonometric(): n3 = Rational(3) e = (sin(x)**2).diff(x) assert e == 2*sin(x)*cos(x) e = e.subs(x, n3) assert e == 2*cos(n3)*sin(n3) e = (sin(x)**2).diff(x) assert e == 2*sin(x)*cos(x) e = e.subs(sin(x), cos(x)) assert e == 2*cos(x)**2 assert exp(pi).subs(exp, sin) == 0 assert cos(exp(pi)).subs(exp, sin) == 1 i = Symbol('i', integer=True) zoo = S.ComplexInfinity assert tan(x).subs(x, pi/2) is zoo assert cot(x).subs(x, pi) is zoo assert cot(i*x).subs(x, pi) is zoo assert tan(i*x).subs(x, pi/2) == tan(i*pi/2) assert tan(i*x).subs(x, pi/2).subs(i, 1) is zoo o = Symbol('o', odd=True) assert tan(o*x).subs(x, pi/2) == tan(o*pi/2) def test_powers(): assert sqrt(1 - sqrt(x)).subs(x, 4) == I assert (sqrt(1 - x**2)**3).subs(x, 2) == - 3*I*sqrt(3) assert (x**Rational(1, 3)).subs(x, 27) == 3 assert (x**Rational(1, 3)).subs(x, -27) == 3*(-1)**Rational(1, 3) assert ((-x)**Rational(1, 3)).subs(x, 27) == 3*(-1)**Rational(1, 3) n = Symbol('n', negative=True) assert (x**n).subs(x, 0) is S.ComplexInfinity assert exp(-1).subs(S.Exp1, 0) is S.ComplexInfinity assert (x**(4.0*y)).subs(x**(2.0*y), n) == n**2.0 assert (2**(x + 2)).subs(2, 3) == 3**(x + 3) def test_logexppow(): # no eval() x = Symbol('x', real=True) w = Symbol('w') e = (3**(1 + x) + 2**(1 + x))/(3**x + 2**x) assert e.subs(2**x, w) != e assert e.subs(exp(x*log(Rational(2))), w) != e def test_bug(): x1 = Symbol('x1') x2 = Symbol('x2') y = x1*x2 assert y.subs(x1, Float(3.0)) == Float(3.0)*x2 def test_subbug1(): # see that they don't fail (x**x).subs(x, 1) (x**x).subs(x, 1.0) def test_subbug2(): # Ensure this does not cause infinite recursion assert Float(7.7).epsilon_eq(abs(x).subs(x, -7.7)) def test_dict_set(): a, b, c = map(Wild, 'abc') f = 3*cos(4*x) r = f.match(a*cos(b*x)) assert r == {a: 3, b: 4} e = a/b*sin(b*x) assert e.subs(r) == r[a]/r[b]*sin(r[b]*x) assert e.subs(r) == 3*sin(4*x) / 4 s = set(r.items()) assert e.subs(s) == r[a]/r[b]*sin(r[b]*x) assert e.subs(s) == 3*sin(4*x) / 4 assert e.subs(r) == r[a]/r[b]*sin(r[b]*x) assert e.subs(r) == 3*sin(4*x) / 4 assert x.subs(Dict((x, 1))) == 1 def test_dict_ambigous(): # see issue 3566 f = x*exp(x) g = z*exp(z) df = {x: y, exp(x): y} dg = {z: y, exp(z): y} assert f.subs(df) == y**2 assert g.subs(dg) == y**2 # and this is how order can affect the result assert f.subs(x, y).subs(exp(x), y) == y*exp(y) assert f.subs(exp(x), y).subs(x, y) == y**2 # length of args and count_ops are the same so # default_sort_key resolves ordering...if one # doesn't want this result then an unordered # sequence should not be used. e = 1 + x*y assert e.subs({x: y, y: 2}) == 5 # here, there are no obviously clashing keys or values # but the results depend on the order assert exp(x/2 + y).subs({exp(y + 1): 2, x: 2}) == exp(y + 1) def test_deriv_sub_bug3(): f = Function('f') pat = Derivative(f(x), x, x) assert pat.subs(y, y**2) == Derivative(f(x), x, x) assert pat.subs(y, y**2) != Derivative(f(x), x) def test_equality_subs1(): f = Function('f') eq = Eq(f(x)**2, x) res = Eq(Integer(16), x) assert eq.subs(f(x), 4) == res def test_equality_subs2(): f = Function('f') eq = Eq(f(x)**2, 16) assert bool(eq.subs(f(x), 3)) is False assert bool(eq.subs(f(x), 4)) is True def test_issue_3742(): e = sqrt(x)*exp(y) assert e.subs(sqrt(x), 1) == exp(y) def test_subs_dict1(): assert (1 + x*y).subs(x, pi) == 1 + pi*y assert (1 + x*y).subs({x: pi, y: 2}) == 1 + 2*pi c2, c3, q1p, q2p, c1, s1, s2, s3 = symbols('c2 c3 q1p q2p c1 s1 s2 s3') test = (c2**2*q2p*c3 + c1**2*s2**2*q2p*c3 + s1**2*s2**2*q2p*c3 - c1**2*q1p*c2*s3 - s1**2*q1p*c2*s3) assert (test.subs({c1**2: 1 - s1**2, c2**2: 1 - s2**2, c3**3: 1 - s3**2}) == c3*q2p*(1 - s2**2) + c3*q2p*s2**2*(1 - s1**2) - c2*q1p*s3*(1 - s1**2) + c3*q2p*s1**2*s2**2 - c2*q1p*s3*s1**2) def test_mul(): x, y, z, a, b, c = symbols('x y z a b c') A, B, C = symbols('A B C', commutative=0) assert (x*y*z).subs(z*x, y) == y**2 assert (z*x).subs(1/x, z) == 1 assert (x*y/z).subs(1/z, a) == a*x*y assert (x*y/z).subs(x/z, a) == a*y assert (x*y/z).subs(y/z, a) == a*x assert (x*y/z).subs(x/z, 1/a) == y/a assert (x*y/z).subs(x, 1/a) == y/(z*a) assert (2*x*y).subs(5*x*y, z) != z*Rational(2, 5) assert (x*y*A).subs(x*y, a) == a*A assert (x**2*y**(x*Rational(3, 2))).subs(x*y**(x/2), 2) == 4*y**(x/2) assert (x*exp(x*2)).subs(x*exp(x), 2) == 2*exp(x) assert ((x**(2*y))**3).subs(x**y, 2) == 64 assert (x*A*B).subs(x*A, y) == y*B assert (x*y*(1 + x)*(1 + x*y)).subs(x*y, 2) == 6*(1 + x) assert ((1 + A*B)*A*B).subs(A*B, x*A*B) assert (x*a/z).subs(x/z, A) == a*A assert (x**3*A).subs(x**2*A, a) == a*x assert (x**2*A*B).subs(x**2*B, a) == a*A assert (x**2*A*B).subs(x**2*A, a) == a*B assert (b*A**3/(a**3*c**3)).subs(a**4*c**3*A**3/b**4, z) == \ b*A**3/(a**3*c**3) assert (6*x).subs(2*x, y) == 3*y assert (y*exp(x*Rational(3, 2))).subs(y*exp(x), 2) == 2*exp(x/2) assert (y*exp(x*Rational(3, 2))).subs(y*exp(x), 2) == 2*exp(x/2) assert (A**2*B*A**2*B*A**2).subs(A*B*A, C) == A*C**2*A assert (x*A**3).subs(x*A, y) == y*A**2 assert (x**2*A**3).subs(x*A, y) == y**2*A assert (x*A**3).subs(x*A, B) == B*A**2 assert (x*A*B*A*exp(x*A*B)).subs(x*A, B) == B**2*A*exp(B*B) assert (x**2*A*B*A*exp(x*A*B)).subs(x*A, B) == B**3*exp(B**2) assert (x**3*A*exp(x*A*B)*A*exp(x*A*B)).subs(x*A, B) == \ x*B*exp(B**2)*B*exp(B**2) assert (x*A*B*C*A*B).subs(x*A*B, C) == C**2*A*B assert (-I*a*b).subs(a*b, 2) == -2*I # issue 6361 assert (-8*I*a).subs(-2*a, 1) == 4*I assert (-I*a).subs(-a, 1) == I # issue 6441 assert (4*x**2).subs(2*x, y) == y**2 assert (2*4*x**2).subs(2*x, y) == 2*y**2 assert (-x**3/9).subs(-x/3, z) == -z**2*x assert (-x**3/9).subs(x/3, z) == -z**2*x assert (-2*x**3/9).subs(x/3, z) == -2*x*z**2 assert (-2*x**3/9).subs(-x/3, z) == -2*x*z**2 assert (-2*x**3/9).subs(-2*x, z) == z*x**2/9 assert (-2*x**3/9).subs(2*x, z) == -z*x**2/9 assert (2*(3*x/5/7)**2).subs(3*x/5, z) == 2*(Rational(1, 7))**2*z**2 assert (4*x).subs(-2*x, z) == 4*x # try keep subs literal def test_subs_simple(): a = symbols('a', commutative=True) x = symbols('x', commutative=False) assert (2*a).subs(1, 3) == 2*a assert (2*a).subs(2, 3) == 3*a assert (2*a).subs(a, 3) == 6 assert sin(2).subs(1, 3) == sin(2) assert sin(2).subs(2, 3) == sin(3) assert sin(a).subs(a, 3) == sin(3) assert (2*x).subs(1, 3) == 2*x assert (2*x).subs(2, 3) == 3*x assert (2*x).subs(x, 3) == 6 assert sin(x).subs(x, 3) == sin(3) def test_subs_constants(): a, b = symbols('a b', commutative=True) x, y = symbols('x y', commutative=False) assert (a*b).subs(2*a, 1) == a*b assert (1.5*a*b).subs(a, 1) == 1.5*b assert (2*a*b).subs(2*a, 1) == b assert (2*a*b).subs(4*a, 1) == 2*a*b assert (x*y).subs(2*x, 1) == x*y assert (1.5*x*y).subs(x, 1) == 1.5*y assert (2*x*y).subs(2*x, 1) == y assert (2*x*y).subs(4*x, 1) == 2*x*y def test_subs_commutative(): a, b, c, d, K = symbols('a b c d K', commutative=True) assert (a*b).subs(a*b, K) == K assert (a*b*a*b).subs(a*b, K) == K**2 assert (a*a*b*b).subs(a*b, K) == K**2 assert (a*b*c*d).subs(a*b*c, K) == d*K assert (a*b**c).subs(a, K) == K*b**c assert (a*b**c).subs(b, K) == a*K**c assert (a*b**c).subs(c, K) == a*b**K assert (a*b*c*b*a).subs(a*b, K) == c*K**2 assert (a**3*b**2*a).subs(a*b, K) == a**2*K**2 def test_subs_noncommutative(): w, x, y, z, L = symbols('w x y z L', commutative=False) alpha = symbols('alpha', commutative=True) someint = symbols('someint', commutative=True, integer=True) assert (x*y).subs(x*y, L) == L assert (w*y*x).subs(x*y, L) == w*y*x assert (w*x*y*z).subs(x*y, L) == w*L*z assert (x*y*x*y).subs(x*y, L) == L**2 assert (x*x*y).subs(x*y, L) == x*L assert (x*x*y*y).subs(x*y, L) == x*L*y assert (w*x*y).subs(x*y*z, L) == w*x*y assert (x*y**z).subs(x, L) == L*y**z assert (x*y**z).subs(y, L) == x*L**z assert (x*y**z).subs(z, L) == x*y**L assert (w*x*y*z*x*y).subs(x*y*z, L) == w*L*x*y assert (w*x*y*y*w*x*x*y*x*y*y*x*y).subs(x*y, L) == w*L*y*w*x*L**2*y*L # Check fractional power substitutions. It should not do # substitutions that choose a value for noncommutative log, # or inverses that don't already appear in the expressions. assert (x*x*x).subs(x*x, L) == L*x assert (x*x*x*y*x*x*x*x).subs(x*x, L) == L*x*y*L**2 for p in range(1, 5): for k in range(10): assert (y * x**k).subs(x**p, L) == y * L**(k//p) * x**(k % p) assert (x**Rational(3, 2)).subs(x**S.Half, L) == x**Rational(3, 2) assert (x**S.Half).subs(x**S.Half, L) == L assert (x**Rational(-1, 2)).subs(x**S.Half, L) == x**Rational(-1, 2) assert (x**Rational(-1, 2)).subs(x**Rational(-1, 2), L) == L assert (x**(2*someint)).subs(x**someint, L) == L**2 assert (x**(2*someint + 3)).subs(x**someint, L) == L**2*x**3 assert (x**(3*someint + 3)).subs(x**someint, L) == L**3*x**3 assert (x**(3*someint)).subs(x**(2*someint), L) == L * x**someint assert (x**(4*someint)).subs(x**(2*someint), L) == L**2 assert (x**(4*someint + 1)).subs(x**(2*someint), L) == L**2 * x assert (x**(4*someint)).subs(x**(3*someint), L) == L * x**someint assert (x**(4*someint + 1)).subs(x**(3*someint), L) == L * x**(someint + 1) assert (x**(2*alpha)).subs(x**alpha, L) == x**(2*alpha) assert (x**(2*alpha + 2)).subs(x**2, L) == x**(2*alpha + 2) assert ((2*z)**alpha).subs(z**alpha, y) == (2*z)**alpha assert (x**(2*someint*alpha)).subs(x**someint, L) == x**(2*someint*alpha) assert (x**(2*someint + alpha)).subs(x**someint, L) == x**(2*someint + alpha) # This could in principle be substituted, but is not currently # because it requires recognizing that someint**2 is divisible by # someint. assert (x**(someint**2 + 3)).subs(x**someint, L) == x**(someint**2 + 3) # alpha**z := exp(log(alpha) z) is usually well-defined assert (4**z).subs(2**z, y) == y**2 # Negative powers assert (x**(-1)).subs(x**3, L) == x**(-1) assert (x**(-2)).subs(x**3, L) == x**(-2) assert (x**(-3)).subs(x**3, L) == L**(-1) assert (x**(-4)).subs(x**3, L) == L**(-1) * x**(-1) assert (x**(-5)).subs(x**3, L) == L**(-1) * x**(-2) assert (x**(-1)).subs(x**(-3), L) == x**(-1) assert (x**(-2)).subs(x**(-3), L) == x**(-2) assert (x**(-3)).subs(x**(-3), L) == L assert (x**(-4)).subs(x**(-3), L) == L * x**(-1) assert (x**(-5)).subs(x**(-3), L) == L * x**(-2) assert (x**1).subs(x**(-3), L) == x assert (x**2).subs(x**(-3), L) == x**2 assert (x**3).subs(x**(-3), L) == L**(-1) assert (x**4).subs(x**(-3), L) == L**(-1) * x assert (x**5).subs(x**(-3), L) == L**(-1) * x**2 def test_subs_basic_funcs(): a, b, c, d, K = symbols('a b c d K', commutative=True) w, x, y, z, L = symbols('w x y z L', commutative=False) assert (x + y).subs(x + y, L) == L assert (x - y).subs(x - y, L) == L assert (x/y).subs(x, L) == L/y assert (x**y).subs(x, L) == L**y assert (x**y).subs(y, L) == x**L assert ((a - c)/b).subs(b, K) == (a - c)/K assert (exp(x*y - z)).subs(x*y, L) == exp(L - z) assert (a*exp(x*y - w*z) + b*exp(x*y + w*z)).subs(z, 0) == \ a*exp(x*y) + b*exp(x*y) assert ((a - b)/(c*d - a*b)).subs(c*d - a*b, K) == (a - b)/K assert (w*exp(a*b - c)*x*y/4).subs(x*y, L) == w*exp(a*b - c)*L/4 def test_subs_wild(): R, S, T, U = symbols('R S T U', cls=Wild) assert (R*S).subs(R*S, T) == T assert (S*R).subs(R*S, T) == T assert (R + S).subs(R + S, T) == T assert (R**S).subs(R, T) == T**S assert (R**S).subs(S, T) == R**T assert (R*S**T).subs(R, U) == U*S**T assert (R*S**T).subs(S, U) == R*U**T assert (R*S**T).subs(T, U) == R*S**U def test_subs_mixed(): a, b, c, d, K = symbols('a b c d K', commutative=True) w, x, y, z, L = symbols('w x y z L', commutative=False) R, S, T, U = symbols('R S T U', cls=Wild) assert (a*x*y).subs(x*y, L) == a*L assert (a*b*x*y*x).subs(x*y, L) == a*b*L*x assert (R*x*y*exp(x*y)).subs(x*y, L) == R*L*exp(L) assert (a*x*y*y*x - x*y*z*exp(a*b)).subs(x*y, L) == a*L*y*x - L*z*exp(a*b) e = c*y*x*y*x**(R*S - a*b) - T*(a*R*b*S) assert e.subs(x*y, L).subs(a*b, K).subs(R*S, U) == \ c*y*L*x**(U - K) - T*(U*K) def test_division(): a, b, c = symbols('a b c', commutative=True) x, y, z = symbols('x y z', commutative=True) assert (1/a).subs(a, c) == 1/c assert (1/a**2).subs(a, c) == 1/c**2 assert (1/a**2).subs(a, -2) == Rational(1, 4) assert (-(1/a**2)).subs(a, -2) == Rational(-1, 4) assert (1/x).subs(x, z) == 1/z assert (1/x**2).subs(x, z) == 1/z**2 assert (1/x**2).subs(x, -2) == Rational(1, 4) assert (-(1/x**2)).subs(x, -2) == Rational(-1, 4) #issue 5360 assert (1/x).subs(x, 0) == 1/S.Zero def test_add(): a, b, c, d, x, y, t = symbols('a b c d x y t') assert (a**2 - b - c).subs(a**2 - b, d) in [d - c, a**2 - b - c] assert (a**2 - c).subs(a**2 - c, d) == d assert (a**2 - b - c).subs(a**2 - c, d) in [d - b, a**2 - b - c] assert (a**2 - x - c).subs(a**2 - c, d) in [d - x, a**2 - x - c] assert (a**2 - b - sqrt(a)).subs(a**2 - sqrt(a), c) == c - b assert (a + b + exp(a + b)).subs(a + b, c) == c + exp(c) assert (c + b + exp(c + b)).subs(c + b, a) == a + exp(a) assert (a + b + c + d).subs(b + c, x) == a + d + x assert (a + b + c + d).subs(-b - c, x) == a + d - x assert ((x + 1)*y).subs(x + 1, t) == t*y assert ((-x - 1)*y).subs(x + 1, t) == -t*y assert ((x - 1)*y).subs(x + 1, t) == y*(t - 2) assert ((-x + 1)*y).subs(x + 1, t) == y*(-t + 2) # this should work every time: e = a**2 - b - c assert e.subs(Add(*e.args[:2]), d) == d + e.args[2] assert e.subs(a**2 - c, d) == d - b # the fallback should recognize when a change has # been made; while .1 == Rational(1, 10) they are not the same # and the change should be made assert (0.1 + a).subs(0.1, Rational(1, 10)) == Rational(1, 10) + a e = (-x*(-y + 1) - y*(y - 1)) ans = (-x*(x) - y*(-x)).expand() assert e.subs(-y + 1, x) == ans #Test issue 18747 assert (exp(x) + cos(x)).subs(x, oo) == oo assert Add(*[AccumBounds(-1, 1), oo]) == oo assert Add(*[oo, AccumBounds(-1, 1)]) == oo def test_subs_issue_4009(): assert (I*Symbol('a')).subs(1, 2) == I*Symbol('a') def test_functions_subs(): f, g = symbols('f g', cls=Function) l = Lambda((x, y), sin(x) + y) assert (g(y, x) + cos(x)).subs(g, l) == sin(y) + x + cos(x) assert (f(x)**2).subs(f, sin) == sin(x)**2 assert (f(x, y)).subs(f, log) == log(x, y) assert (f(x, y)).subs(f, sin) == f(x, y) assert (sin(x) + atan2(x, y)).subs([[atan2, f], [sin, g]]) == \ f(x, y) + g(x) assert (g(f(x + y, x))).subs([[f, l], [g, exp]]) == exp(x + sin(x + y)) def test_derivative_subs(): f = Function('f') g = Function('g') assert Derivative(f(x), x).subs(f(x), y) != 0 # need xreplace to put the function back, see #13803 assert Derivative(f(x), x).subs(f(x), y).xreplace({y: f(x)}) == \ Derivative(f(x), x) # issues 5085, 5037 assert cse(Derivative(f(x), x) + f(x))[1][0].has(Derivative) assert cse(Derivative(f(x, y), x) + Derivative(f(x, y), y))[1][0].has(Derivative) eq = Derivative(g(x), g(x)) assert eq.subs(g, f) == Derivative(f(x), f(x)) assert eq.subs(g(x), f(x)) == Derivative(f(x), f(x)) assert eq.subs(g, cos) == Subs(Derivative(y, y), y, cos(x)) def test_derivative_subs2(): f_func, g_func = symbols('f g', cls=Function) f, g = f_func(x, y, z), g_func(x, y, z) assert Derivative(f, x, y).subs(Derivative(f, x, y), g) == g assert Derivative(f, y, x).subs(Derivative(f, x, y), g) == g assert Derivative(f, x, y).subs(Derivative(f, x), g) == Derivative(g, y) assert Derivative(f, x, y).subs(Derivative(f, y), g) == Derivative(g, x) assert (Derivative(f, x, y, z).subs( Derivative(f, x, z), g) == Derivative(g, y)) assert (Derivative(f, x, y, z).subs( Derivative(f, z, y), g) == Derivative(g, x)) assert (Derivative(f, x, y, z).subs( Derivative(f, z, y, x), g) == g) # Issue 9135 assert (Derivative(f, x, x, y).subs( Derivative(f, y, y), g) == Derivative(f, x, x, y)) assert (Derivative(f, x, y, y, z).subs( Derivative(f, x, y, y, y), g) == Derivative(f, x, y, y, z)) assert Derivative(f, x, y).subs(Derivative(f_func(x), x, y), g) == Derivative(f, x, y) def test_derivative_subs3(): dex = Derivative(exp(x), x) assert Derivative(dex, x).subs(dex, exp(x)) == dex assert dex.subs(exp(x), dex) == Derivative(exp(x), x, x) def test_issue_5284(): A, B = symbols('A B', commutative=False) assert (x*A).subs(x**2*A, B) == x*A assert (A**2).subs(A**3, B) == A**2 assert (A**6).subs(A**3, B) == B**2 def test_subs_iter(): assert x.subs(reversed([[x, y]])) == y it = iter([[x, y]]) assert x.subs(it) == y assert x.subs(Tuple((x, y))) == y def test_subs_dict(): a, b, c, d, e = symbols('a b c d e') assert (2*x + y + z).subs(dict(x=1, y=2)) == 4 + z l = [(sin(x), 2), (x, 1)] assert (sin(x)).subs(l) == \ (sin(x)).subs(dict(l)) == 2 assert sin(x).subs(reversed(l)) == sin(1) expr = sin(2*x) + sqrt(sin(2*x))*cos(2*x)*sin(exp(x)*x) reps = dict([ (sin(2*x), c), (sqrt(sin(2*x)), a), (cos(2*x), b), (exp(x), e), (x, d), ]) assert expr.subs(reps) == c + a*b*sin(d*e) l = [(x, 3), (y, x**2)] assert (x + y).subs(l) == 3 + x**2 assert (x + y).subs(reversed(l)) == 12 # If changes are made to convert lists into dictionaries and do # a dictionary-lookup replacement, these tests will help to catch # some logical errors that might occur l = [(y, z + 2), (1 + z, 5), (z, 2)] assert (y - 1 + 3*x).subs(l) == 5 + 3*x l = [(y, z + 2), (z, 3)] assert (y - 2).subs(l) == 3 def test_no_arith_subs_on_floats(): assert (x + 3).subs(x + 3, a) == a assert (x + 3).subs(x + 2, a) == a + 1 assert (x + y + 3).subs(x + 3, a) == a + y assert (x + y + 3).subs(x + 2, a) == a + y + 1 assert (x + 3.0).subs(x + 3.0, a) == a assert (x + 3.0).subs(x + 2.0, a) == x + 3.0 assert (x + y + 3.0).subs(x + 3.0, a) == a + y assert (x + y + 3.0).subs(x + 2.0, a) == x + y + 3.0 def test_issue_5651(): a, b, c, K = symbols('a b c K', commutative=True) assert (a/(b*c)).subs(b*c, K) == a/K assert (a/(b**2*c**3)).subs(b*c, K) == a/(c*K**2) assert (1/(x*y)).subs(x*y, 2) == S.Half assert ((1 + x*y)/(x*y)).subs(x*y, 1) == 2 assert (x*y*z).subs(x*y, 2) == 2*z assert ((1 + x*y)/(x*y)/z).subs(x*y, 1) == 2/z def test_issue_6075(): assert Tuple(1, True).subs(1, 2) == Tuple(2, True) def test_issue_6079(): # since x + 2.0 == x + 2 we can't do a simple equality test assert _aresame((x + 2.0).subs(2, 3), x + 2.0) assert _aresame((x + 2.0).subs(2.0, 3), x + 3) assert not _aresame(x + 2, x + 2.0) assert not _aresame(Basic(cos, 1), Basic(cos, 1.)) assert _aresame(cos, cos) assert not _aresame(1, S.One) assert not _aresame(x, symbols('x', positive=True)) def test_issue_4680(): N = Symbol('N') assert N.subs(dict(N=3)) == 3 def test_issue_6158(): assert (x - 1).subs(1, y) == x - y assert (x - 1).subs(-1, y) == x + y assert (x - oo).subs(oo, y) == x - y assert (x - oo).subs(-oo, y) == x + y def test_Function_subs(): f, g, h, i = symbols('f g h i', cls=Function) p = Piecewise((g(f(x, y)), x < -1), (g(x), x <= 1)) assert p.subs(g, h) == Piecewise((h(f(x, y)), x < -1), (h(x), x <= 1)) assert (f(y) + g(x)).subs({f: h, g: i}) == i(x) + h(y) def test_simultaneous_subs(): reps = {x: 0, y: 0} assert (x/y).subs(reps) != (y/x).subs(reps) assert (x/y).subs(reps, simultaneous=True) == \ (y/x).subs(reps, simultaneous=True) reps = reps.items() assert (x/y).subs(reps) != (y/x).subs(reps) assert (x/y).subs(reps, simultaneous=True) == \ (y/x).subs(reps, simultaneous=True) assert Derivative(x, y, z).subs(reps, simultaneous=True) == \ Subs(Derivative(0, y, z), y, 0) def test_issue_6419_6421(): assert (1/(1 + x/y)).subs(x/y, x) == 1/(1 + x) assert (-2*I).subs(2*I, x) == -x assert (-I*x).subs(I*x, x) == -x assert (-3*I*y**4).subs(3*I*y**2, x) == -x*y**2 def test_issue_6559(): assert (-12*x + y).subs(-x, 1) == 12 + y # though this involves cse it generated a failure in Mul._eval_subs x0, x1 = symbols('x0 x1') e = -log(-12*sqrt(2) + 17)/24 - log(-2*sqrt(2) + 3)/12 + sqrt(2)/3 # XXX modify cse so x1 is eliminated and x0 = -sqrt(2)? assert cse(e) == ( [(x0, sqrt(2))], [x0/3 - log(-12*x0 + 17)/24 - log(-2*x0 + 3)/12]) def test_issue_5261(): x = symbols('x', real=True) e = I*x assert exp(e).subs(exp(x), y) == y**I assert (2**e).subs(2**x, y) == y**I eq = (-2)**e assert eq.subs((-2)**x, y) == eq def test_issue_6923(): assert (-2*x*sqrt(2)).subs(2*x, y) == -sqrt(2)*y def test_2arg_hack(): N = Symbol('N', commutative=False) ans = Mul(2, y + 1, evaluate=False) assert (2*x*(y + 1)).subs(x, 1, hack2=True) == ans assert (2*(y + 1 + N)).subs(N, 0, hack2=True) == ans @XFAIL def test_mul2(): """When this fails, remove things labelled "2-arg hack" 1) remove special handling in the fallback of subs that was added in the same commit as this test 2) remove the special handling in Mul.flatten """ assert (2*(x + 1)).is_Mul def test_noncommutative_subs(): x,y = symbols('x,y', commutative=False) assert (x*y*x).subs([(x, x*y), (y, x)], simultaneous=True) == (x*y*x**2*y) def test_issue_2877(): f = Float(2.0) assert (x + f).subs({f: 2}) == x + 2 def r(a, b, c): return factor(a*x**2 + b*x + c) e = r(5.0/6, 10, 5) assert nsimplify(e) == 5*x**2/6 + 10*x + 5 def test_issue_5910(): t = Symbol('t') assert (1/(1 - t)).subs(t, 1) is zoo n = t d = t - 1 assert (n/d).subs(t, 1) is zoo assert (-n/-d).subs(t, 1) is zoo def test_issue_5217(): s = Symbol('s') z = (1 - 2*x*x) w = (1 + 2*x*x) q = 2*x*x*2*y*y sub = {2*x*x: s} assert w.subs(sub) == 1 + s assert z.subs(sub) == 1 - s assert q == 4*x**2*y**2 assert q.subs(sub) == 2*y**2*s def test_issue_10829(): assert (4**x).subs(2**x, y) == y**2 assert (9**x).subs(3**x, y) == y**2 def test_pow_eval_subs_no_cache(): # Tests pull request 9376 is working from sympy.core.cache import clear_cache s = 1/sqrt(x**2) # This bug only appeared when the cache was turned off. # We need to approximate running this test without the cache. # This creates approximately the same situation. clear_cache() # This used to fail with a wrong result. # It incorrectly returned 1/sqrt(x**2) before this pull request. result = s.subs(sqrt(x**2), y) assert result == 1/y def test_RootOf_issue_10092(): x = Symbol('x', real=True) eq = x**3 - 17*x**2 + 81*x - 118 r = RootOf(eq, 0) assert (x < r).subs(x, r) is S.false def test_issue_8886(): from sympy.physics.mechanics import ReferenceFrame as R # if something can't be sympified we assume that it # doesn't play well with SymPy and disallow the # substitution v = R('A').x assert x.subs(x, v) == x assert v.subs(v, x) == v assert v.__eq__(x) is False def test_issue_12657(): # treat -oo like the atom that it is reps = [(-oo, 1), (oo, 2)] assert (x < -oo).subs(reps) == (x < 1) assert (x < -oo).subs(list(reversed(reps))) == (x < 1) reps = [(-oo, 2), (oo, 1)] assert (x < oo).subs(reps) == (x < 1) assert (x < oo).subs(list(reversed(reps))) == (x < 1) def test_recurse_Application_args(): F = Lambda((x, y), exp(2*x + 3*y)) f = Function('f') A = f(x, f(x, x)) C = F(x, F(x, x)) assert A.subs(f, F) == A.replace(f, F) == C def test_Subs_subs(): assert Subs(x*y, x, x).subs(x, y) == Subs(x*y, x, y) assert Subs(x*y, x, x + 1).subs(x, y) == \ Subs(x*y, x, y + 1) assert Subs(x*y, y, x + 1).subs(x, y) == \ Subs(y**2, y, y + 1) a = Subs(x*y*z, (y, x, z), (x + 1, x + z, x)) b = Subs(x*y*z, (y, x, z), (x + 1, y + z, y)) assert a.subs(x, y) == b and \ a.doit().subs(x, y) == a.subs(x, y).doit() f = Function('f') g = Function('g') assert Subs(2*f(x, y) + g(x), f(x, y), 1).subs(y, 2) == Subs( 2*f(x, y) + g(x), (f(x, y), y), (1, 2)) def test_issue_13333(): eq = 1/x assert eq.subs(dict(x='1/2')) == 2 assert eq.subs(dict(x='(1/2)')) == 2 def test_issue_15234(): x, y = symbols('x y', real=True) p = 6*x**5 + x**4 - 4*x**3 + 4*x**2 - 2*x + 3 p_subbed = 6*x**5 - 4*x**3 - 2*x + y**4 + 4*y**2 + 3 assert p.subs([(x**i, y**i) for i in [2, 4]]) == p_subbed x, y = symbols('x y', complex=True) p = 6*x**5 + x**4 - 4*x**3 + 4*x**2 - 2*x + 3 p_subbed = 6*x**5 - 4*x**3 - 2*x + y**4 + 4*y**2 + 3 assert p.subs([(x**i, y**i) for i in [2, 4]]) == p_subbed def test_issue_6976(): x, y = symbols('x y') assert (sqrt(x)**3 + sqrt(x) + x + x**2).subs(sqrt(x), y) == \ y**4 + y**3 + y**2 + y assert (x**4 + x**3 + x**2 + x + sqrt(x)).subs(x**2, y) == \ sqrt(x) + x**3 + x + y**2 + y assert x.subs(x**3, y) == x assert x.subs(x**Rational(1, 3), y) == y**3 # More substitutions are possible with nonnegative symbols x, y = symbols('x y', nonnegative=True) assert (x**4 + x**3 + x**2 + x + sqrt(x)).subs(x**2, y) == \ y**Rational(1, 4) + y**Rational(3, 2) + sqrt(y) + y**2 + y assert x.subs(x**3, y) == y**Rational(1, 3) def test_issue_11746(): assert (1/x).subs(x**2, 1) == 1/x assert (1/(x**3)).subs(x**2, 1) == x**(-3) assert (1/(x**4)).subs(x**2, 1) == 1 assert (1/(x**3)).subs(x**4, 1) == x**(-3) assert (1/(y**5)).subs(x**5, 1) == y**(-5) def test_issue_17823(): from sympy.physics.mechanics import dynamicsymbols q1, q2 = dynamicsymbols('q1, q2') expr = q1.diff().diff()**2*q1 + q1.diff()*q2.diff() reps={q1: a, q1.diff(): a*x*y, q1.diff().diff(): z} assert expr.subs(reps) == a*x*y*Derivative(q2, t) + a*z**2 def test_issue_19326(): x, y = [i(t) for i in map(Function, 'xy')] assert (x*y).subs({x: 1 + x, y: x}) == (1 + x)*x def test_issue_19558(): e = (7*x*cos(x) - 12*log(x)**3)*(-log(x)**4 + 2*sin(x) + 1)**2/ \ (2*(x*cos(x) - 2*log(x)**3)*(3*log(x)**4 - 7*sin(x) + 3)**2) assert e.subs(x, oo) == AccumBounds(-oo, oo) assert (sin(x) + cos(x)).subs(x, oo) == AccumBounds(-2, 2) sympy-sympy-1.9/sympy/core/tests/test_symbol.py000066400000000000000000000274141412543434000221240ustar00rootroot00000000000000from sympy import (Symbol, Wild, GreaterThan, LessThan, StrictGreaterThan, StrictLessThan, pi, I, Rational, sympify, symbols, Dummy) from sympy.core.symbol import uniquely_named_symbol, _symbol, Str from sympy.testing.pytest import raises from sympy.core.symbol import disambiguate def test_Str(): a1 = Str('a') a2 = Str('a') b = Str('b') assert a1 == a2 != b raises(TypeError, lambda: Str()) def test_Symbol(): a = Symbol("a") x1 = Symbol("x") x2 = Symbol("x") xdummy1 = Dummy("x") xdummy2 = Dummy("x") assert a != x1 assert a != x2 assert x1 == x2 assert x1 != xdummy1 assert xdummy1 != xdummy2 assert Symbol("x") == Symbol("x") assert Dummy("x") != Dummy("x") d = symbols('d', cls=Dummy) assert isinstance(d, Dummy) c, d = symbols('c,d', cls=Dummy) assert isinstance(c, Dummy) assert isinstance(d, Dummy) raises(TypeError, lambda: Symbol()) def test_Dummy(): assert Dummy() != Dummy() def test_Dummy_force_dummy_index(): raises(AssertionError, lambda: Dummy(dummy_index=1)) assert Dummy('d', dummy_index=2) == Dummy('d', dummy_index=2) assert Dummy('d1', dummy_index=2) != Dummy('d2', dummy_index=2) d1 = Dummy('d', dummy_index=3) d2 = Dummy('d') # might fail if d1 were created with dummy_index >= 10**6 assert d1 != d2 d3 = Dummy('d', dummy_index=3) assert d1 == d3 assert Dummy()._count == Dummy('d', dummy_index=3)._count def test_lt_gt(): from sympy import sympify as S x, y = Symbol('x'), Symbol('y') assert (x >= y) == GreaterThan(x, y) assert (x >= 0) == GreaterThan(x, 0) assert (x <= y) == LessThan(x, y) assert (x <= 0) == LessThan(x, 0) assert (0 <= x) == GreaterThan(x, 0) assert (0 >= x) == LessThan(x, 0) assert (S(0) >= x) == GreaterThan(0, x) assert (S(0) <= x) == LessThan(0, x) assert (x > y) == StrictGreaterThan(x, y) assert (x > 0) == StrictGreaterThan(x, 0) assert (x < y) == StrictLessThan(x, y) assert (x < 0) == StrictLessThan(x, 0) assert (0 < x) == StrictGreaterThan(x, 0) assert (0 > x) == StrictLessThan(x, 0) assert (S(0) > x) == StrictGreaterThan(0, x) assert (S(0) < x) == StrictLessThan(0, x) e = x**2 + 4*x + 1 assert (e >= 0) == GreaterThan(e, 0) assert (0 <= e) == GreaterThan(e, 0) assert (e > 0) == StrictGreaterThan(e, 0) assert (0 < e) == StrictGreaterThan(e, 0) assert (e <= 0) == LessThan(e, 0) assert (0 >= e) == LessThan(e, 0) assert (e < 0) == StrictLessThan(e, 0) assert (0 > e) == StrictLessThan(e, 0) assert (S(0) >= e) == GreaterThan(0, e) assert (S(0) <= e) == LessThan(0, e) assert (S(0) < e) == StrictLessThan(0, e) assert (S(0) > e) == StrictGreaterThan(0, e) def test_no_len(): # there should be no len for numbers x = Symbol('x') raises(TypeError, lambda: len(x)) def test_ineq_unequal(): S = sympify x, y, z = symbols('x,y,z') e = ( S(-1) >= x, S(-1) >= y, S(-1) >= z, S(-1) > x, S(-1) > y, S(-1) > z, S(-1) <= x, S(-1) <= y, S(-1) <= z, S(-1) < x, S(-1) < y, S(-1) < z, S(0) >= x, S(0) >= y, S(0) >= z, S(0) > x, S(0) > y, S(0) > z, S(0) <= x, S(0) <= y, S(0) <= z, S(0) < x, S(0) < y, S(0) < z, S('3/7') >= x, S('3/7') >= y, S('3/7') >= z, S('3/7') > x, S('3/7') > y, S('3/7') > z, S('3/7') <= x, S('3/7') <= y, S('3/7') <= z, S('3/7') < x, S('3/7') < y, S('3/7') < z, S(1.5) >= x, S(1.5) >= y, S(1.5) >= z, S(1.5) > x, S(1.5) > y, S(1.5) > z, S(1.5) <= x, S(1.5) <= y, S(1.5) <= z, S(1.5) < x, S(1.5) < y, S(1.5) < z, S(2) >= x, S(2) >= y, S(2) >= z, S(2) > x, S(2) > y, S(2) > z, S(2) <= x, S(2) <= y, S(2) <= z, S(2) < x, S(2) < y, S(2) < z, x >= -1, y >= -1, z >= -1, x > -1, y > -1, z > -1, x <= -1, y <= -1, z <= -1, x < -1, y < -1, z < -1, x >= 0, y >= 0, z >= 0, x > 0, y > 0, z > 0, x <= 0, y <= 0, z <= 0, x < 0, y < 0, z < 0, x >= 1.5, y >= 1.5, z >= 1.5, x > 1.5, y > 1.5, z > 1.5, x <= 1.5, y <= 1.5, z <= 1.5, x < 1.5, y < 1.5, z < 1.5, x >= 2, y >= 2, z >= 2, x > 2, y > 2, z > 2, x <= 2, y <= 2, z <= 2, x < 2, y < 2, z < 2, x >= y, x >= z, y >= x, y >= z, z >= x, z >= y, x > y, x > z, y > x, y > z, z > x, z > y, x <= y, x <= z, y <= x, y <= z, z <= x, z <= y, x < y, x < z, y < x, y < z, z < x, z < y, x - pi >= y + z, y - pi >= x + z, z - pi >= x + y, x - pi > y + z, y - pi > x + z, z - pi > x + y, x - pi <= y + z, y - pi <= x + z, z - pi <= x + y, x - pi < y + z, y - pi < x + z, z - pi < x + y, True, False ) left_e = e[:-1] for i, e1 in enumerate( left_e ): for e2 in e[i + 1:]: assert e1 != e2 def test_Wild_properties(): # these tests only include Atoms x = Symbol("x") y = Symbol("y") p = Symbol("p", positive=True) k = Symbol("k", integer=True) n = Symbol("n", integer=True, positive=True) given_patterns = [ x, y, p, k, -k, n, -n, sympify(-3), sympify(3), pi, Rational(3, 2), I ] integerp = lambda k: k.is_integer positivep = lambda k: k.is_positive symbolp = lambda k: k.is_Symbol realp = lambda k: k.is_extended_real S = Wild("S", properties=[symbolp]) R = Wild("R", properties=[realp]) Y = Wild("Y", exclude=[x, p, k, n]) P = Wild("P", properties=[positivep]) K = Wild("K", properties=[integerp]) N = Wild("N", properties=[positivep, integerp]) given_wildcards = [ S, R, Y, P, K, N ] goodmatch = { S: (x, y, p, k, n), R: (p, k, -k, n, -n, -3, 3, pi, Rational(3, 2)), Y: (y, -3, 3, pi, Rational(3, 2), I ), P: (p, n, 3, pi, Rational(3, 2)), K: (k, -k, n, -n, -3, 3), N: (n, 3)} for A in given_wildcards: for pat in given_patterns: d = pat.match(A) if pat in goodmatch[A]: assert d[A] in goodmatch[A] else: assert d is None def test_symbols(): x = Symbol('x') y = Symbol('y') z = Symbol('z') assert symbols('x') == x assert symbols('x ') == x assert symbols(' x ') == x assert symbols('x,') == (x,) assert symbols('x, ') == (x,) assert symbols('x ,') == (x,) assert symbols('x , y') == (x, y) assert symbols('x,y,z') == (x, y, z) assert symbols('x y z') == (x, y, z) assert symbols('x,y,z,') == (x, y, z) assert symbols('x y z ') == (x, y, z) xyz = Symbol('xyz') abc = Symbol('abc') assert symbols('xyz') == xyz assert symbols('xyz,') == (xyz,) assert symbols('xyz,abc') == (xyz, abc) assert symbols(('xyz',)) == (xyz,) assert symbols(('xyz,',)) == ((xyz,),) assert symbols(('x,y,z,',)) == ((x, y, z),) assert symbols(('xyz', 'abc')) == (xyz, abc) assert symbols(('xyz,abc',)) == ((xyz, abc),) assert symbols(('xyz,abc', 'x,y,z')) == ((xyz, abc), (x, y, z)) assert symbols(('x', 'y', 'z')) == (x, y, z) assert symbols(['x', 'y', 'z']) == [x, y, z] assert symbols({'x', 'y', 'z'}) == {x, y, z} raises(ValueError, lambda: symbols('')) raises(ValueError, lambda: symbols(',')) raises(ValueError, lambda: symbols('x,,y,,z')) raises(ValueError, lambda: symbols(('x', '', 'y', '', 'z'))) a, b = symbols('x,y', real=True) assert a.is_real and b.is_real x0 = Symbol('x0') x1 = Symbol('x1') x2 = Symbol('x2') y0 = Symbol('y0') y1 = Symbol('y1') assert symbols('x0:0') == () assert symbols('x0:1') == (x0,) assert symbols('x0:2') == (x0, x1) assert symbols('x0:3') == (x0, x1, x2) assert symbols('x:0') == () assert symbols('x:1') == (x0,) assert symbols('x:2') == (x0, x1) assert symbols('x:3') == (x0, x1, x2) assert symbols('x1:1') == () assert symbols('x1:2') == (x1,) assert symbols('x1:3') == (x1, x2) assert symbols('x1:3,x,y,z') == (x1, x2, x, y, z) assert symbols('x:3,y:2') == (x0, x1, x2, y0, y1) assert symbols(('x:3', 'y:2')) == ((x0, x1, x2), (y0, y1)) a = Symbol('a') b = Symbol('b') c = Symbol('c') d = Symbol('d') assert symbols('x:z') == (x, y, z) assert symbols('a:d,x:z') == (a, b, c, d, x, y, z) assert symbols(('a:d', 'x:z')) == ((a, b, c, d), (x, y, z)) aa = Symbol('aa') ab = Symbol('ab') ac = Symbol('ac') ad = Symbol('ad') assert symbols('aa:d') == (aa, ab, ac, ad) assert symbols('aa:d,x:z') == (aa, ab, ac, ad, x, y, z) assert symbols(('aa:d','x:z')) == ((aa, ab, ac, ad), (x, y, z)) # issue 6675 def sym(s): return str(symbols(s)) assert sym('a0:4') == '(a0, a1, a2, a3)' assert sym('a2:4,b1:3') == '(a2, a3, b1, b2)' assert sym('a1(2:4)') == '(a12, a13)' assert sym('a0:2.0:2') == '(a0.0, a0.1, a1.0, a1.1)' assert sym('aa:cz') == '(aaz, abz, acz)' assert sym('aa:c0:2') == '(aa0, aa1, ab0, ab1, ac0, ac1)' assert sym('aa:ba:b') == '(aaa, aab, aba, abb)' assert sym('a:3b') == '(a0b, a1b, a2b)' assert sym('a-1:3b') == '(a-1b, a-2b)' assert sym(r'a:2\,:2' + chr(0)) == '(a0,0%s, a0,1%s, a1,0%s, a1,1%s)' % ( (chr(0),)*4) assert sym('x(:a:3)') == '(x(a0), x(a1), x(a2))' assert sym('x(:c):1') == '(xa0, xb0, xc0)' assert sym('x((:a)):3') == '(x(a)0, x(a)1, x(a)2)' assert sym('x(:a:3') == '(x(a0, x(a1, x(a2)' assert sym(':2') == '(0, 1)' assert sym(':b') == '(a, b)' assert sym(':b:2') == '(a0, a1, b0, b1)' assert sym(':2:2') == '(00, 01, 10, 11)' assert sym(':b:b') == '(aa, ab, ba, bb)' raises(ValueError, lambda: symbols(':')) raises(ValueError, lambda: symbols('a:')) raises(ValueError, lambda: symbols('::')) raises(ValueError, lambda: symbols('a::')) raises(ValueError, lambda: symbols(':a:')) raises(ValueError, lambda: symbols('::a')) def test_symbols_become_functions_issue_3539(): from sympy.abc import alpha, phi, beta, t raises(TypeError, lambda: beta(2)) raises(TypeError, lambda: beta(2.5)) raises(TypeError, lambda: phi(2.5)) raises(TypeError, lambda: alpha(2.5)) raises(TypeError, lambda: phi(t)) def test_unicode(): xu = Symbol('x') x = Symbol('x') assert x == xu raises(TypeError, lambda: Symbol(1)) def testuniquely_named_symbol_and__symbol(): F = uniquely_named_symbol x = Symbol('x') assert F(x) == x assert F('x') == x assert str(F('x', x)) == 'x0' assert str(F('x', (x + 1, 1/x))) == 'x0' _x = Symbol('x', real=True) assert F(('x', _x)) == _x assert F((x, _x)) == _x assert F('x', real=True).is_real y = Symbol('y') assert F(('x', y), real=True).is_real r = Symbol('x', real=True) assert F(('x', r)).is_real assert F(('x', r), real=False).is_real assert F('x1', Symbol('x1'), compare=lambda i: str(i).rstrip('1')).name == 'x1' assert F('x1', Symbol('x1'), modify=lambda i: i + '_').name == 'x1_' assert _symbol(x, _x) == x def test_disambiguate(): x, y, y_1, _x, x_1, x_2 = symbols('x y y_1 _x x_1 x_2') t1 = Dummy('y'), _x, Dummy('x'), Dummy('x') t2 = Dummy('x'), Dummy('x') t3 = Dummy('x'), Dummy('y') t4 = x, Dummy('x') t5 = Symbol('x', integer=True), x, Symbol('x_1') assert disambiguate(*t1) == (y, x_2, x, x_1) assert disambiguate(*t2) == (x, x_1) assert disambiguate(*t3) == (x, y) assert disambiguate(*t4) == (x_1, x) assert disambiguate(*t5) == (t5[0], x_2, x_1) assert disambiguate(*t5)[0] != x # assumptions are retained t6 = _x, Dummy('x')/y t7 = y*Dummy('y'), y assert disambiguate(*t6) == (x_1, x/y) assert disambiguate(*t7) == (y*y_1, y_1) assert disambiguate(Dummy('x_1'), Dummy('x_1') ) == (x_1, Symbol('x_1_1')) sympy-sympy-1.9/sympy/core/tests/test_sympify.py000066400000000000000000000613471412543434000223220ustar00rootroot00000000000000from sympy import (Symbol, exp, Integer, Float, sin, cos, Poly, Lambda, Function, I, S, sqrt, srepr, Rational, Tuple, Matrix, Interval, Add, Mul, Pow, Or, true, false, Abs, pi, Range, Xor) from sympy.abc import x, y from sympy.core.sympify import (sympify, _sympify, SympifyError, kernS, CantSympify) from sympy.core.decorators import _sympifyit from sympy.external import import_module from sympy.testing.pytest import raises, XFAIL, skip, warns_deprecated_sympy from sympy.utilities.decorator import conserve_mpmath_dps from sympy.geometry import Point, Line from sympy.functions.combinatorial.factorials import factorial, factorial2 from sympy.abc import _clash, _clash1, _clash2 from sympy.core.compatibility import HAS_GMPY from sympy.sets import FiniteSet, EmptySet from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray import mpmath from collections import defaultdict, OrderedDict from mpmath.rational import mpq numpy = import_module('numpy') def test_issue_3538(): v = sympify("exp(x)") assert v == exp(x) assert type(v) == type(exp(x)) assert str(type(v)) == str(type(exp(x))) def test_sympify1(): assert sympify("x") == Symbol("x") assert sympify(" x") == Symbol("x") assert sympify(" x ") == Symbol("x") # issue 4877 n1 = S.Half assert sympify('--.5') == n1 assert sympify('-1/2') == -n1 assert sympify('-+--.5') == -n1 assert sympify('-.[3]') == Rational(-1, 3) assert sympify('.[3]') == Rational(1, 3) assert sympify('+.[3]') == Rational(1, 3) assert sympify('+0.[3]*10**-2') == Rational(1, 300) assert sympify('.[052631578947368421]') == Rational(1, 19) assert sympify('.0[526315789473684210]') == Rational(1, 19) assert sympify('.034[56]') == Rational(1711, 49500) # options to make reals into rationals assert sympify('1.22[345]', rational=True) == \ 1 + Rational(22, 100) + Rational(345, 99900) assert sympify('2/2.6', rational=True) == Rational(10, 13) assert sympify('2.6/2', rational=True) == Rational(13, 10) assert sympify('2.6e2/17', rational=True) == Rational(260, 17) assert sympify('2.6e+2/17', rational=True) == Rational(260, 17) assert sympify('2.6e-2/17', rational=True) == Rational(26, 17000) assert sympify('2.1+3/4', rational=True) == \ Rational(21, 10) + Rational(3, 4) assert sympify('2.234456', rational=True) == Rational(279307, 125000) assert sympify('2.234456e23', rational=True) == 223445600000000000000000 assert sympify('2.234456e-23', rational=True) == \ Rational(279307, 12500000000000000000000000000) assert sympify('-2.234456e-23', rational=True) == \ Rational(-279307, 12500000000000000000000000000) assert sympify('12345678901/17', rational=True) == \ Rational(12345678901, 17) assert sympify('1/.3 + x', rational=True) == Rational(10, 3) + x # make sure longs in fractions work assert sympify('222222222222/11111111111') == \ Rational(222222222222, 11111111111) # ... even if they come from repetend notation assert sympify('1/.2[123456789012]') == Rational(333333333333, 70781892967) # ... or from high precision reals assert sympify('.1234567890123456', rational=True) == \ Rational(19290123283179, 156250000000000) def test_sympify_Fraction(): try: import fractions except ImportError: pass else: value = sympify(fractions.Fraction(101, 127)) assert value == Rational(101, 127) and type(value) is Rational def test_sympify_gmpy(): if HAS_GMPY: if HAS_GMPY == 2: import gmpy2 as gmpy elif HAS_GMPY == 1: import gmpy value = sympify(gmpy.mpz(1000001)) assert value == Integer(1000001) and type(value) is Integer value = sympify(gmpy.mpq(101, 127)) assert value == Rational(101, 127) and type(value) is Rational @conserve_mpmath_dps def test_sympify_mpmath(): value = sympify(mpmath.mpf(1.0)) assert value == Float(1.0) and type(value) is Float mpmath.mp.dps = 12 assert sympify( mpmath.pi).epsilon_eq(Float("3.14159265359"), Float("1e-12")) == True assert sympify( mpmath.pi).epsilon_eq(Float("3.14159265359"), Float("1e-13")) == False mpmath.mp.dps = 6 assert sympify( mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-5")) == True assert sympify( mpmath.pi).epsilon_eq(Float("3.14159"), Float("1e-6")) == False assert sympify(mpmath.mpc(1.0 + 2.0j)) == Float(1.0) + Float(2.0)*I assert sympify(mpq(1, 2)) == S.Half def test_sympify2(): class A: def _sympy_(self): return Symbol("x")**3 a = A() assert _sympify(a) == x**3 assert sympify(a) == x**3 assert a == x**3 def test_sympify3(): assert sympify("x**3") == x**3 assert sympify("x^3") == x**3 assert sympify("1/2") == Integer(1)/2 raises(SympifyError, lambda: _sympify('x**3')) raises(SympifyError, lambda: _sympify('1/2')) def test_sympify_keywords(): raises(SympifyError, lambda: sympify('if')) raises(SympifyError, lambda: sympify('for')) raises(SympifyError, lambda: sympify('while')) raises(SympifyError, lambda: sympify('lambda')) def test_sympify_float(): assert sympify("1e-64") != 0 assert sympify("1e-20000") != 0 def test_sympify_bool(): assert sympify(True) is true assert sympify(False) is false def test_sympyify_iterables(): ans = [Rational(3, 10), Rational(1, 5)] assert sympify(['.3', '.2'], rational=True) == ans assert sympify(dict(x=0, y=1)) == {x: 0, y: 1} assert sympify(['1', '2', ['3', '4']]) == [S(1), S(2), [S(3), S(4)]] @XFAIL def test_issue_16772(): # because there is a converter for tuple, the # args are only sympified without the flags being passed # along; list, on the other hand, is not converted # with a converter so its args are traversed later ans = [Rational(3, 10), Rational(1, 5)] assert sympify(tuple(['.3', '.2']), rational=True) == Tuple(*ans) def test_issue_16859(): class no(float, CantSympify): pass raises(SympifyError, lambda: sympify(no(1.2))) def test_sympify4(): class A: def _sympy_(self): return Symbol("x") a = A() assert _sympify(a)**3 == x**3 assert sympify(a)**3 == x**3 assert a == x def test_sympify_text(): assert sympify('some') == Symbol('some') assert sympify('core') == Symbol('core') assert sympify('True') is True assert sympify('False') is False assert sympify('Poly') == Poly assert sympify('sin') == sin def test_sympify_function(): assert sympify('factor(x**2-1, x)') == -(1 - x)*(x + 1) assert sympify('sin(pi/2)*cos(pi)') == -Integer(1) def test_sympify_poly(): p = Poly(x**2 + x + 1, x) assert _sympify(p) is p assert sympify(p) is p def test_sympify_factorial(): assert sympify('x!') == factorial(x) assert sympify('(x+1)!') == factorial(x + 1) assert sympify('(1 + y*(x + 1))!') == factorial(1 + y*(x + 1)) assert sympify('(1 + y*(x + 1)!)^2') == (1 + y*factorial(x + 1))**2 assert sympify('y*x!') == y*factorial(x) assert sympify('x!!') == factorial2(x) assert sympify('(x+1)!!') == factorial2(x + 1) assert sympify('(1 + y*(x + 1))!!') == factorial2(1 + y*(x + 1)) assert sympify('(1 + y*(x + 1)!!)^2') == (1 + y*factorial2(x + 1))**2 assert sympify('y*x!!') == y*factorial2(x) assert sympify('factorial2(x)!') == factorial(factorial2(x)) raises(SympifyError, lambda: sympify("+!!")) raises(SympifyError, lambda: sympify(")!!")) raises(SympifyError, lambda: sympify("!")) raises(SympifyError, lambda: sympify("(!)")) raises(SympifyError, lambda: sympify("x!!!")) def test_issue_3595(): assert sympify("a_") == Symbol("a_") assert sympify("_a") == Symbol("_a") def test_lambda(): x = Symbol('x') assert sympify('lambda: 1') == Lambda((), 1) assert sympify('lambda x: x') == Lambda(x, x) assert sympify('lambda x: 2*x') == Lambda(x, 2*x) assert sympify('lambda x, y: 2*x+y') == Lambda((x, y), 2*x + y) def test_lambda_raises(): raises(SympifyError, lambda: sympify("lambda *args: args")) # args argument error raises(SympifyError, lambda: sympify("lambda **kwargs: kwargs[0]")) # kwargs argument error raises(SympifyError, lambda: sympify("lambda x = 1: x")) # Keyword argument error with raises(SympifyError): _sympify('lambda: 1') def test_sympify_raises(): raises(SympifyError, lambda: sympify("fx)")) class A: def __str__(self): return 'x' with warns_deprecated_sympy(): assert sympify(A()) == Symbol('x') def test__sympify(): x = Symbol('x') f = Function('f') # positive _sympify assert _sympify(x) is x assert _sympify(1) == Integer(1) assert _sympify(0.5) == Float("0.5") assert _sympify(1 + 1j) == 1.0 + I*1.0 # Function f is not Basic and can't sympify to Basic. We allow it to pass # with sympify but not with _sympify. # https://github.com/sympy/sympy/issues/20124 assert sympify(f) is f raises(SympifyError, lambda: _sympify(f)) class A: def _sympy_(self): return Integer(5) a = A() assert _sympify(a) == Integer(5) # negative _sympify raises(SympifyError, lambda: _sympify('1')) raises(SympifyError, lambda: _sympify([1, 2, 3])) def test_sympifyit(): x = Symbol('x') y = Symbol('y') @_sympifyit('b', NotImplemented) def add(a, b): return a + b assert add(x, 1) == x + 1 assert add(x, 0.5) == x + Float('0.5') assert add(x, y) == x + y assert add(x, '1') == NotImplemented @_sympifyit('b') def add_raises(a, b): return a + b assert add_raises(x, 1) == x + 1 assert add_raises(x, 0.5) == x + Float('0.5') assert add_raises(x, y) == x + y raises(SympifyError, lambda: add_raises(x, '1')) def test_int_float(): class F1_1: def __float__(self): return 1.1 class F1_1b: """ This class is still a float, even though it also implements __int__(). """ def __float__(self): return 1.1 def __int__(self): return 1 class F1_1c: """ This class is still a float, because it implements _sympy_() """ def __float__(self): return 1.1 def __int__(self): return 1 def _sympy_(self): return Float(1.1) class I5: def __int__(self): return 5 class I5b: """ This class implements both __int__() and __float__(), so it will be treated as Float in SymPy. One could change this behavior, by using float(a) == int(a), but deciding that integer-valued floats represent exact numbers is arbitrary and often not correct, so we do not do it. If, in the future, we decide to do it anyway, the tests for I5b need to be changed. """ def __float__(self): return 5.0 def __int__(self): return 5 class I5c: """ This class implements both __int__() and __float__(), but also a _sympy_() method, so it will be Integer. """ def __float__(self): return 5.0 def __int__(self): return 5 def _sympy_(self): return Integer(5) i5 = I5() i5b = I5b() i5c = I5c() f1_1 = F1_1() f1_1b = F1_1b() f1_1c = F1_1c() assert sympify(i5) == 5 assert isinstance(sympify(i5), Integer) assert sympify(i5b) == 5 assert isinstance(sympify(i5b), Float) assert sympify(i5c) == 5 assert isinstance(sympify(i5c), Integer) assert abs(sympify(f1_1) - 1.1) < 1e-5 assert abs(sympify(f1_1b) - 1.1) < 1e-5 assert abs(sympify(f1_1c) - 1.1) < 1e-5 assert _sympify(i5) == 5 assert isinstance(_sympify(i5), Integer) assert _sympify(i5b) == 5 assert isinstance(_sympify(i5b), Float) assert _sympify(i5c) == 5 assert isinstance(_sympify(i5c), Integer) assert abs(_sympify(f1_1) - 1.1) < 1e-5 assert abs(_sympify(f1_1b) - 1.1) < 1e-5 assert abs(_sympify(f1_1c) - 1.1) < 1e-5 def test_evaluate_false(): cases = { '2 + 3': Add(2, 3, evaluate=False), '2**2 / 3': Mul(Pow(2, 2, evaluate=False), Pow(3, -1, evaluate=False), evaluate=False), '2 + 3 * 5': Add(2, Mul(3, 5, evaluate=False), evaluate=False), '2 - 3 * 5': Add(2, Mul(-1, Mul(3, 5,evaluate=False), evaluate=False), evaluate=False), '1 / 3': Mul(1, Pow(3, -1, evaluate=False), evaluate=False), 'True | False': Or(True, False, evaluate=False), '1 + 2 + 3 + 5*3 + integrate(x)': Add(1, 2, 3, Mul(5, 3, evaluate=False), x**2/2, evaluate=False), '2 * 4 * 6 + 8': Add(Mul(2, 4, 6, evaluate=False), 8, evaluate=False), '2 - 8 / 4': Add(2, Mul(-1, Mul(8, Pow(4, -1, evaluate=False), evaluate=False), evaluate=False), evaluate=False), '2 - 2**2': Add(2, Mul(-1, Pow(2, 2, evaluate=False), evaluate=False), evaluate=False), } for case, result in cases.items(): assert sympify(case, evaluate=False) == result def test_issue_4133(): a = sympify('Integer(4)') assert a == Integer(4) assert a.is_Integer def test_issue_3982(): a = [3, 2.0] assert sympify(a) == [Integer(3), Float(2.0)] assert sympify(tuple(a)) == Tuple(Integer(3), Float(2.0)) assert sympify(set(a)) == FiniteSet(Integer(3), Float(2.0)) def test_S_sympify(): assert S(1)/2 == sympify(1)/2 assert (-2)**(S(1)/2) == sqrt(2)*I def test_issue_4788(): assert srepr(S(1.0 + 0J)) == srepr(S(1.0)) == srepr(Float(1.0)) def test_issue_4798_None(): assert S(None) is None def test_issue_3218(): assert sympify("x+\ny") == x + y def test_issue_4988_builtins(): C = Symbol('C') vars = {'C': C} exp1 = sympify('C') assert exp1 == C # Make sure it did not get mixed up with sympy.C exp2 = sympify('C', vars) assert exp2 == C # Make sure it did not get mixed up with sympy.C def test_geometry(): p = sympify(Point(0, 1)) assert p == Point(0, 1) and isinstance(p, Point) L = sympify(Line(p, (1, 0))) assert L == Line((0, 1), (1, 0)) and isinstance(L, Line) def test_kernS(): s = '-1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x)))' # when 1497 is fixed, this no longer should pass: the expression # should be unchanged assert -1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x))) == -1 # sympification should not allow the constant to enter a Mul # or else the structure can change dramatically ss = kernS(s) assert ss != -1 and ss.simplify() == -1 s = '-1 - 2*(-(-x + 1/x)/(x*(x - 1/x)**2) - 1/(x*(x - 1/x)))'.replace( 'x', '_kern') ss = kernS(s) assert ss != -1 and ss.simplify() == -1 # issue 6687 assert (kernS('Interval(-1,-2 - 4*(-3))') == Interval(-1, Add(-2, Mul(12, 1, evaluate=False), evaluate=False))) assert kernS('_kern') == Symbol('_kern') assert kernS('E**-(x)') == exp(-x) e = 2*(x + y)*y assert kernS(['2*(x + y)*y', ('2*(x + y)*y',)]) == [e, (e,)] assert kernS('-(2*sin(x)**2 + 2*sin(x)*cos(x))*y/2') == \ -y*(2*sin(x)**2 + 2*sin(x)*cos(x))/2 # issue 15132 assert kernS('(1 - x)/(1 - x*(1-y))') == kernS('(1-x)/(1-(1-y)*x)') assert kernS('(1-2**-(4+1)*(1-y)*x)') == (1 - x*(1 - y)/32) assert kernS('(1-2**(4+1)*(1-y)*x)') == (1 - 32*x*(1 - y)) assert kernS('(1-2.*(1-y)*x)') == 1 - 2.*x*(1 - y) one = kernS('x - (x - 1)') assert one != 1 and one.expand() == 1 assert kernS("(2*x)/(x-1)") == 2*x/(x-1) def test_issue_6540_6552(): assert S('[[1/3,2], (2/5,)]') == [[Rational(1, 3), 2], (Rational(2, 5),)] assert S('[[2/6,2], (2/4,)]') == [[Rational(1, 3), 2], (S.Half,)] assert S('[[[2*(1)]]]') == [[[2]]] assert S('Matrix([2*(1)])') == Matrix([2]) def test_issue_6046(): assert str(S("Q & C", locals=_clash1)) == 'C & Q' assert str(S('pi(x)', locals=_clash2)) == 'pi(x)' locals = {} exec("from sympy.abc import Q, C", locals) assert str(S('C&Q', locals)) == 'C & Q' # clash can act as Symbol or Function assert str(S('pi(C, Q)', locals=_clash)) == 'pi(C, Q)' assert len(S('pi + x', locals=_clash2).free_symbols) == 2 # but not both raises(TypeError, lambda: S('pi + pi(x)', locals=_clash2)) assert all(set(i.values()) == {None} for i in ( _clash, _clash1, _clash2)) def test_issue_8821_highprec_from_str(): s = str(pi.evalf(128)) p = sympify(s) assert Abs(sin(p)) < 1e-127 def test_issue_10295(): if not numpy: skip("numpy not installed.") A = numpy.array([[1, 3, -1], [0, 1, 7]]) sA = S(A) assert sA.shape == (2, 3) for (ri, ci), val in numpy.ndenumerate(A): assert sA[ri, ci] == val B = numpy.array([-7, x, 3*y**2]) sB = S(B) assert sB.shape == (3,) assert B[0] == sB[0] == -7 assert B[1] == sB[1] == x assert B[2] == sB[2] == 3*y**2 C = numpy.arange(0, 24) C.resize(2,3,4) sC = S(C) assert sC[0, 0, 0].is_integer assert sC[0, 0, 0] == 0 a1 = numpy.array([1, 2, 3]) a2 = numpy.array([i for i in range(24)]) a2.resize(2, 4, 3) assert sympify(a1) == ImmutableDenseNDimArray([1, 2, 3]) assert sympify(a2) == ImmutableDenseNDimArray([i for i in range(24)], (2, 4, 3)) def test_Range(): # Only works in Python 3 where range returns a range type assert sympify(range(10)) == Range(10) assert _sympify(range(10)) == Range(10) def test_sympify_set(): n = Symbol('n') assert sympify({n}) == FiniteSet(n) assert sympify(set()) == EmptySet def test_sympify_numpy(): if not numpy: skip('numpy not installed. Abort numpy tests.') np = numpy def equal(x, y): return x == y and type(x) == type(y) assert sympify(np.bool_(1)) is S(True) try: assert equal( sympify(np.int_(1234567891234567891)), S(1234567891234567891)) assert equal( sympify(np.intp(1234567891234567891)), S(1234567891234567891)) except OverflowError: # May fail on 32-bit systems: Python int too large to convert to C long pass assert equal(sympify(np.intc(1234567891)), S(1234567891)) assert equal(sympify(np.int8(-123)), S(-123)) assert equal(sympify(np.int16(-12345)), S(-12345)) assert equal(sympify(np.int32(-1234567891)), S(-1234567891)) assert equal( sympify(np.int64(-1234567891234567891)), S(-1234567891234567891)) assert equal(sympify(np.uint8(123)), S(123)) assert equal(sympify(np.uint16(12345)), S(12345)) assert equal(sympify(np.uint32(1234567891)), S(1234567891)) assert equal( sympify(np.uint64(1234567891234567891)), S(1234567891234567891)) assert equal(sympify(np.float32(1.123456)), Float(1.123456, precision=24)) assert equal(sympify(np.float64(1.1234567891234)), Float(1.1234567891234, precision=53)) assert equal(sympify(np.longdouble(1.123456789)), Float(1.123456789, precision=80)) assert equal(sympify(np.complex64(1 + 2j)), S(1.0 + 2.0*I)) assert equal(sympify(np.complex128(1 + 2j)), S(1.0 + 2.0*I)) assert equal(sympify(np.longcomplex(1 + 2j)), S(1.0 + 2.0*I)) #float96 does not exist on all platforms if hasattr(np, 'float96'): assert equal(sympify(np.float96(1.123456789)), Float(1.123456789, precision=80)) #float128 does not exist on all platforms if hasattr(np, 'float128'): assert equal(sympify(np.float128(1.123456789123)), Float(1.123456789123, precision=80)) @XFAIL def test_sympify_rational_numbers_set(): ans = [Rational(3, 10), Rational(1, 5)] assert sympify({'.3', '.2'}, rational=True) == FiniteSet(*ans) def test_issue_13924(): if not numpy: skip("numpy not installed.") a = sympify(numpy.array([1])) assert isinstance(a, ImmutableDenseNDimArray) assert a[0] == 1 def test_numpy_sympify_args(): # Issue 15098. Make sure sympify args work with numpy types (like numpy.str_) if not numpy: skip("numpy not installed.") a = sympify(numpy.str_('a')) assert type(a) is Symbol assert a == Symbol('a') class CustomSymbol(Symbol): pass a = sympify(numpy.str_('a'), {"Symbol": CustomSymbol}) assert isinstance(a, CustomSymbol) a = sympify(numpy.str_('x^y')) assert a == x**y a = sympify(numpy.str_('x^y'), convert_xor=False) assert a == Xor(x, y) raises(SympifyError, lambda: sympify(numpy.str_('x'), strict=True)) a = sympify(numpy.str_('1.1')) assert isinstance(a, Float) assert a == 1.1 a = sympify(numpy.str_('1.1'), rational=True) assert isinstance(a, Rational) assert a == Rational(11, 10) a = sympify(numpy.str_('x + x')) assert isinstance(a, Mul) assert a == 2*x a = sympify(numpy.str_('x + x'), evaluate=False) assert isinstance(a, Add) assert a == Add(x, x, evaluate=False) def test_issue_5939(): a = Symbol('a') b = Symbol('b') assert sympify('''a+\nb''') == a + b def test_issue_16759(): d = sympify({.5: 1}) assert S.Half not in d assert Float(.5) in d assert d[.5] is S.One d = sympify(OrderedDict({.5: 1})) assert S.Half not in d assert Float(.5) in d assert d[.5] is S.One d = sympify(defaultdict(int, {.5: 1})) assert S.Half not in d assert Float(.5) in d assert d[.5] is S.One def test_issue_17811(): a = Function('a') assert sympify('a(x)*5', evaluate=False) == Mul(a(x), 5, evaluate=False) def test_issue_14706(): if not numpy: skip("numpy not installed.") z1 = numpy.zeros((1, 1), dtype=numpy.float64) z2 = numpy.zeros((2, 2), dtype=numpy.float64) z3 = numpy.zeros((), dtype=numpy.float64) y1 = numpy.ones((1, 1), dtype=numpy.float64) y2 = numpy.ones((2, 2), dtype=numpy.float64) y3 = numpy.ones((), dtype=numpy.float64) assert numpy.all(x + z1 == numpy.full((1, 1), x)) assert numpy.all(x + z2 == numpy.full((2, 2), x)) assert numpy.all(z1 + x == numpy.full((1, 1), x)) assert numpy.all(z2 + x == numpy.full((2, 2), x)) for z in [z3, numpy.int64(0), numpy.float64(0), numpy.complex64(0)]: assert x + z == x assert z + x == x assert isinstance(x + z, Symbol) assert isinstance(z + x, Symbol) # If these tests fail, then it means that numpy has finally # fixed the issue of scalar conversion for rank>0 arrays # which is mentioned in numpy/numpy#10404. In that case, # some changes have to be made in sympify.py. # Note: For future reference, for anyone who takes up this # issue when numpy has finally fixed their side of the problem, # the changes for this temporary fix were introduced in PR 18651 assert numpy.all(x + y1 == numpy.full((1, 1), x + 1.0)) assert numpy.all(x + y2 == numpy.full((2, 2), x + 1.0)) assert numpy.all(y1 + x == numpy.full((1, 1), x + 1.0)) assert numpy.all(y2 + x == numpy.full((2, 2), x + 1.0)) for y_ in [y3, numpy.int64(1), numpy.float64(1), numpy.complex64(1)]: assert x + y_ == y_ + x assert isinstance(x + y_, Add) assert isinstance(y_ + x, Add) assert x + numpy.array(x) == 2 * x assert x + numpy.array([x]) == numpy.array([2*x], dtype=object) assert sympify(numpy.array([1])) == ImmutableDenseNDimArray([1], 1) assert sympify(numpy.array([[[1]]])) == ImmutableDenseNDimArray([1], (1, 1, 1)) assert sympify(z1) == ImmutableDenseNDimArray([0], (1, 1)) assert sympify(z2) == ImmutableDenseNDimArray([0, 0, 0, 0], (2, 2)) assert sympify(z3) == ImmutableDenseNDimArray([0], ()) assert sympify(z3, strict=True) == 0.0 raises(SympifyError, lambda: sympify(numpy.array([1]), strict=True)) raises(SympifyError, lambda: sympify(z1, strict=True)) raises(SympifyError, lambda: sympify(z2, strict=True)) def test_issue_21536(): #test to check evaluate=False in case of iterable input u = sympify("x+3*x+2", evaluate=False) v = sympify("2*x+4*x+2+4", evaluate=False) assert u.is_Add and set(u.args) == {x, 3*x, 2} assert v.is_Add and set(v.args) == {2*x, 4*x, 2, 4} assert sympify(["x+3*x+2", "2*x+4*x+2+4"], evaluate=False) == [u, v] #test to check evaluate=True in case of iterable input u = sympify("x+3*x+2", evaluate=True) v = sympify("2*x+4*x+2+4", evaluate=True) assert u.is_Add and set(u.args) == {4*x, 2} assert v.is_Add and set(v.args) == {6*x, 6} assert sympify(["x+3*x+2", "2*x+4*x+2+4"], evaluate=True) == [u, v] #test to check evaluate with no input in case of iterable input u = sympify("x+3*x+2") v = sympify("2*x+4*x+2+4") assert u.is_Add and set(u.args) == {4*x, 2} assert v.is_Add and set(v.args) == {6*x, 6} assert sympify(["x+3*x+2", "2*x+4*x+2+4"]) == [u, v] sympy-sympy-1.9/sympy/core/tests/test_trace.py000066400000000000000000000054071412543434000217130ustar00rootroot00000000000000from sympy import symbols, Matrix, Tuple from sympy.core.trace import Tr from sympy.testing.pytest import raises def test_trace_new(): a, b, c, d, Y = symbols('a b c d Y') A, B, C, D = symbols('A B C D', commutative=False) assert Tr(a + b) == a + b assert Tr(A + B) == Tr(A) + Tr(B) #check trace args not implicitly permuted assert Tr(C*D*A*B).args[0].args == (C, D, A, B) # check for mul and adds assert Tr((a*b) + ( c*d)) == (a*b) + (c*d) # Tr(scalar*A) = scalar*Tr(A) assert Tr(a*A) == a*Tr(A) assert Tr(a*A*B*b) == a*b*Tr(A*B) # since A is symbol and not commutative assert isinstance(Tr(A), Tr) #POW assert Tr(pow(a, b)) == a**b assert isinstance(Tr(pow(A, a)), Tr) #Matrix M = Matrix([[1, 1], [2, 2]]) assert Tr(M) == 3 ##test indices in different forms #no index t = Tr(A) assert t.args[1] == Tuple() #single index t = Tr(A, 0) assert t.args[1] == Tuple(0) #index in a list t = Tr(A, [0]) assert t.args[1] == Tuple(0) t = Tr(A, [0, 1, 2]) assert t.args[1] == Tuple(0, 1, 2) #index is tuple t = Tr(A, (0)) assert t.args[1] == Tuple(0) t = Tr(A, (1, 2)) assert t.args[1] == Tuple(1, 2) #trace indices test t = Tr((A + B), [2]) assert t.args[0].args[1] == Tuple(2) and t.args[1].args[1] == Tuple(2) t = Tr(a*A, [2, 3]) assert t.args[1].args[1] == Tuple(2, 3) #class with trace method defined #to simulate numpy objects class Foo: def trace(self): return 1 assert Tr(Foo()) == 1 #argument test # check for value error, when either/both arguments are not provided raises(ValueError, lambda: Tr()) raises(ValueError, lambda: Tr(A, 1, 2)) def test_trace_doit(): a, b, c, d = symbols('a b c d') A, B, C, D = symbols('A B C D', commutative=False) #TODO: needed while testing reduced density operations, etc. def test_permute(): A, B, C, D, E, F, G = symbols('A B C D E F G', commutative=False) t = Tr(A*B*C*D*E*F*G) assert t.permute(0).args[0].args == (A, B, C, D, E, F, G) assert t.permute(2).args[0].args == (F, G, A, B, C, D, E) assert t.permute(4).args[0].args == (D, E, F, G, A, B, C) assert t.permute(6).args[0].args == (B, C, D, E, F, G, A) assert t.permute(8).args[0].args == t.permute(1).args[0].args assert t.permute(-1).args[0].args == (B, C, D, E, F, G, A) assert t.permute(-3).args[0].args == (D, E, F, G, A, B, C) assert t.permute(-5).args[0].args == (F, G, A, B, C, D, E) assert t.permute(-8).args[0].args == t.permute(-1).args[0].args t = Tr((A + B)*(B*B)*C*D) assert t.permute(2).args[0].args == (C, D, (A + B), (B**2)) t1 = Tr(A*B) t2 = t1.permute(1) assert id(t1) != id(t2) and t1 == t2 sympy-sympy-1.9/sympy/core/tests/test_truediv.py000066400000000000000000000014521412543434000222730ustar00rootroot00000000000000#this module tests that sympy works with true division turned on from sympy import Rational, Symbol, Float def test_truediv(): assert 1/2 != 0 assert Rational(1)/2 != 0 def dotest(s): x = Symbol("x") y = Symbol("y") l = [ Rational(2), Float("1.3"), x, y, pow(x, y)*y, 5, 5.5 ] for x in l: for y in l: s(x, y) return True def test_basic(): def s(a, b): x = a x = +a x = -a x = a + b x = a - b x = a*b x = a/b x = a**b del x assert dotest(s) def test_ibasic(): def s(a, b): x = a x += b x = a x -= b x = a x *= b x = a x /= b assert dotest(s) sympy-sympy-1.9/sympy/core/tests/test_var.py000066400000000000000000000030131412543434000213740ustar00rootroot00000000000000from sympy import Symbol, var, Function, FunctionClass from sympy.testing.pytest import raises def test_var(): ns = {"var": var, "raises": raises} eval("var('a')", ns) assert ns["a"] == Symbol("a") eval("var('b bb cc zz _x')", ns) assert ns["b"] == Symbol("b") assert ns["bb"] == Symbol("bb") assert ns["cc"] == Symbol("cc") assert ns["zz"] == Symbol("zz") assert ns["_x"] == Symbol("_x") v = eval("var(['d', 'e', 'fg'])", ns) assert ns['d'] == Symbol('d') assert ns['e'] == Symbol('e') assert ns['fg'] == Symbol('fg') # check return value assert v != ['d', 'e', 'fg'] assert v == [Symbol('d'), Symbol('e'), Symbol('fg')] def test_var_return(): ns = {"var": var, "raises": raises} "raises(ValueError, lambda: var(''))" v2 = eval("var('q')", ns) v3 = eval("var('q p')", ns) assert v2 == Symbol('q') assert v3 == (Symbol('q'), Symbol('p')) def test_var_accepts_comma(): ns = {"var": var} v1 = eval("var('x y z')", ns) v2 = eval("var('x,y,z')", ns) v3 = eval("var('x,y z')", ns) assert v1 == v2 assert v1 == v3 def test_var_keywords(): ns = {"var": var} eval("var('x y', real=True)", ns) assert ns['x'].is_real and ns['y'].is_real def test_var_cls(): ns = {"var": var, "Function": Function} eval("var('f', cls=Function)", ns) assert isinstance(ns['f'], FunctionClass) eval("var('g,h', cls=Function)", ns) assert isinstance(ns['g'], FunctionClass) assert isinstance(ns['h'], FunctionClass) sympy-sympy-1.9/sympy/core/trace.py000066400000000000000000000140471412543434000175120ustar00rootroot00000000000000from sympy import Expr, Add, Mul, Pow, sympify, Matrix, Tuple from sympy.utilities import default_sort_key def _is_scalar(e): """ Helper method used in Tr""" # sympify to set proper attributes e = sympify(e) if isinstance(e, Expr): if (e.is_Integer or e.is_Float or e.is_Rational or e.is_Number or (e.is_Symbol and e.is_commutative) ): return True return False def _cycle_permute(l): """ Cyclic permutations based on canonical ordering Explanation =========== This method does the sort based ascii values while a better approach would be to used lexicographic sort. TODO: Handle condition such as symbols have subscripts/superscripts in case of lexicographic sort """ if len(l) == 1: return l min_item = min(l, key=default_sort_key) indices = [i for i, x in enumerate(l) if x == min_item] le = list(l) le.extend(l) # duplicate and extend string for easy processing # adding the first min_item index back for easier looping indices.append(len(l) + indices[0]) # create sublist of items with first item as min_item and last_item # in each of the sublist is item just before the next occurrence of # minitem in the cycle formed. sublist = [[le[indices[i]:indices[i + 1]]] for i in range(len(indices) - 1)] # we do comparison of strings by comparing elements # in each sublist idx = sublist.index(min(sublist)) ordered_l = le[indices[idx]:indices[idx] + len(l)] return ordered_l def _rearrange_args(l): """ this just moves the last arg to first position to enable expansion of args A,B,A ==> A**2,B """ if len(l) == 1: return l x = list(l[-1:]) x.extend(l[0:-1]) return Mul(*x).args class Tr(Expr): """ Generic Trace operation than can trace over: a) sympy matrix b) operators c) outer products Parameters ========== o : operator, matrix, expr i : tuple/list indices (optional) Examples ======== # TODO: Need to handle printing a) Trace(A+B) = Tr(A) + Tr(B) b) Trace(scalar*Operator) = scalar*Trace(Operator) >>> from sympy.core.trace import Tr >>> from sympy import symbols, Matrix >>> a, b = symbols('a b', commutative=True) >>> A, B = symbols('A B', commutative=False) >>> Tr(a*A,[2]) a*Tr(A) >>> m = Matrix([[1,2],[1,1]]) >>> Tr(m) 2 """ def __new__(cls, *args): """ Construct a Trace object. Parameters ========== args = sympy expression indices = tuple/list if indices, optional """ # expect no indices,int or a tuple/list/Tuple if (len(args) == 2): if not isinstance(args[1], (list, Tuple, tuple)): indices = Tuple(args[1]) else: indices = Tuple(*args[1]) expr = args[0] elif (len(args) == 1): indices = Tuple() expr = args[0] else: raise ValueError("Arguments to Tr should be of form " "(expr[, [indices]])") if isinstance(expr, Matrix): return expr.trace() elif hasattr(expr, 'trace') and callable(expr.trace): #for any objects that have trace() defined e.g numpy return expr.trace() elif isinstance(expr, Add): return Add(*[Tr(arg, indices) for arg in expr.args]) elif isinstance(expr, Mul): c_part, nc_part = expr.args_cnc() if len(nc_part) == 0: return Mul(*c_part) else: obj = Expr.__new__(cls, Mul(*nc_part), indices ) #this check is needed to prevent cached instances #being returned even if len(c_part)==0 return Mul(*c_part)*obj if len(c_part) > 0 else obj elif isinstance(expr, Pow): if (_is_scalar(expr.args[0]) and _is_scalar(expr.args[1])): return expr else: return Expr.__new__(cls, expr, indices) else: if (_is_scalar(expr)): return expr return Expr.__new__(cls, expr, indices) @property def kind(self): expr = self.args[0] expr_kind = expr.kind return expr_kind.element_kind def doit(self, **kwargs): """ Perform the trace operation. #TODO: Current version ignores the indices set for partial trace. >>> from sympy.core.trace import Tr >>> from sympy.physics.quantum.operator import OuterProduct >>> from sympy.physics.quantum.spin import JzKet, JzBra >>> t = Tr(OuterProduct(JzKet(1,1), JzBra(1,1))) >>> t.doit() 1 """ if hasattr(self.args[0], '_eval_trace'): return self.args[0]._eval_trace(indices=self.args[1]) return self @property def is_number(self): # TODO : improve this implementation return True #TODO: Review if the permute method is needed # and if it needs to return a new instance def permute(self, pos): """ Permute the arguments cyclically. Parameters ========== pos : integer, if positive, shift-right, else shift-left Examples ======== >>> from sympy.core.trace import Tr >>> from sympy import symbols >>> A, B, C, D = symbols('A B C D', commutative=False) >>> t = Tr(A*B*C*D) >>> t.permute(2) Tr(C*D*A*B) >>> t.permute(-2) Tr(C*D*A*B) """ if pos > 0: pos = pos % len(self.args[0].args) else: pos = -(abs(pos) % len(self.args[0].args)) args = list(self.args[0].args[-pos:] + self.args[0].args[0:-pos]) return Tr(Mul(*(args))) def _hashable_content(self): if isinstance(self.args[0], Mul): args = _cycle_permute(_rearrange_args(self.args[0].args)) else: args = [self.args[0]] return tuple(args) + (self.args[1], ) sympy-sympy-1.9/sympy/crypto/000077500000000000000000000000001412543434000164245ustar00rootroot00000000000000sympy-sympy-1.9/sympy/crypto/__init__.py000066400000000000000000000041561412543434000205430ustar00rootroot00000000000000from sympy.crypto.crypto import (cycle_list, encipher_shift, encipher_affine, encipher_substitution, check_and_join, encipher_vigenere, decipher_vigenere, bifid5_square, bifid6_square, encipher_hill, decipher_hill, encipher_bifid5, encipher_bifid6, decipher_bifid5, decipher_bifid6, encipher_kid_rsa, decipher_kid_rsa, kid_rsa_private_key, kid_rsa_public_key, decipher_rsa, rsa_private_key, rsa_public_key, encipher_rsa, lfsr_connection_polynomial, lfsr_autocorrelation, lfsr_sequence, encode_morse, decode_morse, elgamal_private_key, elgamal_public_key, decipher_elgamal, encipher_elgamal, dh_private_key, dh_public_key, dh_shared_key, padded_key, encipher_bifid, decipher_bifid, bifid_square, bifid5, bifid6, bifid10, decipher_gm, encipher_gm, gm_public_key, gm_private_key, bg_private_key, bg_public_key, encipher_bg, decipher_bg, encipher_rot13, decipher_rot13, encipher_atbash, decipher_atbash, encipher_railfence, decipher_railfence) __all__ = [ 'cycle_list', 'encipher_shift', 'encipher_affine', 'encipher_substitution', 'check_and_join', 'encipher_vigenere', 'decipher_vigenere', 'bifid5_square', 'bifid6_square', 'encipher_hill', 'decipher_hill', 'encipher_bifid5', 'encipher_bifid6', 'decipher_bifid5', 'decipher_bifid6', 'encipher_kid_rsa', 'decipher_kid_rsa', 'kid_rsa_private_key', 'kid_rsa_public_key', 'decipher_rsa', 'rsa_private_key', 'rsa_public_key', 'encipher_rsa', 'lfsr_connection_polynomial', 'lfsr_autocorrelation', 'lfsr_sequence', 'encode_morse', 'decode_morse', 'elgamal_private_key', 'elgamal_public_key', 'decipher_elgamal', 'encipher_elgamal', 'dh_private_key', 'dh_public_key', 'dh_shared_key', 'padded_key', 'encipher_bifid', 'decipher_bifid', 'bifid_square', 'bifid5', 'bifid6', 'bifid10', 'decipher_gm', 'encipher_gm', 'gm_public_key', 'gm_private_key', 'bg_private_key', 'bg_public_key', 'encipher_bg', 'decipher_bg', 'encipher_rot13', 'decipher_rot13', 'encipher_atbash', 'decipher_atbash', 'encipher_railfence', 'decipher_railfence', ] sympy-sympy-1.9/sympy/crypto/crypto.py000066400000000000000000002564501412543434000203320ustar00rootroot00000000000000""" This file contains some classical ciphers and routines implementing a linear-feedback shift register (LFSR) and the Diffie-Hellman key exchange. .. warning:: This module is intended for educational purposes only. Do not use the functions in this module for real cryptographic applications. If you wish to encrypt real data, we recommend using something like the `cryptography `_ module. """ from string import whitespace, ascii_uppercase as uppercase, printable from functools import reduce import warnings from itertools import cycle from sympy import nextprime from sympy.core import Rational, Symbol from sympy.core.numbers import igcdex, mod_inverse, igcd from sympy.core.compatibility import as_int from sympy.matrices import Matrix from sympy.ntheory import isprime, primitive_root, factorint from sympy.polys.domains import FF from sympy.polys.polytools import gcd, Poly from sympy.utilities.misc import filldedent, translate from sympy.utilities.iterables import uniq, multiset from sympy.testing.randtest import _randrange, _randint class NonInvertibleCipherWarning(RuntimeWarning): """A warning raised if the cipher is not invertible.""" def __init__(self, msg): self.fullMessage = msg def __str__(self): return '\n\t' + self.fullMessage def warn(self, stacklevel=2): warnings.warn(self, stacklevel=stacklevel) def AZ(s=None): """Return the letters of ``s`` in uppercase. In case more than one string is passed, each of them will be processed and a list of upper case strings will be returned. Examples ======== >>> from sympy.crypto.crypto import AZ >>> AZ('Hello, world!') 'HELLOWORLD' >>> AZ('Hello, world!'.split()) ['HELLO', 'WORLD'] See Also ======== check_and_join """ if not s: return uppercase t = type(s) is str if t: s = [s] rv = [check_and_join(i.upper().split(), uppercase, filter=True) for i in s] if t: return rv[0] return rv bifid5 = AZ().replace('J', '') bifid6 = AZ() + '0123456789' bifid10 = printable def padded_key(key, symbols): """Return a string of the distinct characters of ``symbols`` with those of ``key`` appearing first. A ValueError is raised if a) there are duplicate characters in ``symbols`` or b) there are characters in ``key`` that are not in ``symbols``. Examples ======== >>> from sympy.crypto.crypto import padded_key >>> padded_key('PUPPY', 'OPQRSTUVWXY') 'PUYOQRSTVWX' >>> padded_key('RSA', 'ARTIST') Traceback (most recent call last): ... ValueError: duplicate characters in symbols: T """ syms = list(uniq(symbols)) if len(syms) != len(symbols): extra = ''.join(sorted({ i for i in symbols if symbols.count(i) > 1})) raise ValueError('duplicate characters in symbols: %s' % extra) extra = set(key) - set(syms) if extra: raise ValueError( 'characters in key but not symbols: %s' % ''.join( sorted(extra))) key0 = ''.join(list(uniq(key))) # remove from syms characters in key0 return key0 + translate(''.join(syms), None, key0) def check_and_join(phrase, symbols=None, filter=None): """ Joins characters of ``phrase`` and if ``symbols`` is given, raises an error if any character in ``phrase`` is not in ``symbols``. Parameters ========== phrase String or list of strings to be returned as a string. symbols Iterable of characters allowed in ``phrase``. If ``symbols`` is ``None``, no checking is performed. Examples ======== >>> from sympy.crypto.crypto import check_and_join >>> check_and_join('a phrase') 'a phrase' >>> check_and_join('a phrase'.upper().split()) 'APHRASE' >>> check_and_join('a phrase!'.upper().split(), 'ARE', filter=True) 'ARAE' >>> check_and_join('a phrase!'.upper().split(), 'ARE') Traceback (most recent call last): ... ValueError: characters in phrase but not symbols: "!HPS" """ rv = ''.join(''.join(phrase)) if symbols is not None: symbols = check_and_join(symbols) missing = ''.join(list(sorted(set(rv) - set(symbols)))) if missing: if not filter: raise ValueError( 'characters in phrase but not symbols: "%s"' % missing) rv = translate(rv, None, missing) return rv def _prep(msg, key, alp, default=None): if not alp: if not default: alp = AZ() msg = AZ(msg) key = AZ(key) else: alp = default else: alp = ''.join(alp) key = check_and_join(key, alp, filter=True) msg = check_and_join(msg, alp, filter=True) return msg, key, alp def cycle_list(k, n): """ Returns the elements of the list ``range(n)`` shifted to the left by ``k`` (so the list starts with ``k`` (mod ``n``)). Examples ======== >>> from sympy.crypto.crypto import cycle_list >>> cycle_list(3, 10) [3, 4, 5, 6, 7, 8, 9, 0, 1, 2] """ k = k % n return list(range(k, n)) + list(range(k)) ######## shift cipher examples ############ def encipher_shift(msg, key, symbols=None): """ Performs shift cipher encryption on plaintext msg, and returns the ciphertext. Parameters ========== key : int The secret key. msg : str Plaintext of upper-case letters. Returns ======= str Ciphertext of upper-case letters. Examples ======== >>> from sympy.crypto.crypto import encipher_shift, decipher_shift >>> msg = "GONAVYBEATARMY" >>> ct = encipher_shift(msg, 1); ct 'HPOBWZCFBUBSNZ' To decipher the shifted text, change the sign of the key: >>> encipher_shift(ct, -1) 'GONAVYBEATARMY' There is also a convenience function that does this with the original key: >>> decipher_shift(ct, 1) 'GONAVYBEATARMY' Notes ===== ALGORITHM: STEPS: 0. Number the letters of the alphabet from 0, ..., N 1. Compute from the string ``msg`` a list ``L1`` of corresponding integers. 2. Compute from the list ``L1`` a new list ``L2``, given by adding ``(k mod 26)`` to each element in ``L1``. 3. Compute from the list ``L2`` a string ``ct`` of corresponding letters. The shift cipher is also called the Caesar cipher, after Julius Caesar, who, according to Suetonius, used it with a shift of three to protect messages of military significance. Caesar's nephew Augustus reportedly used a similar cipher, but with a right shift of 1. References ========== .. [1] https://en.wikipedia.org/wiki/Caesar_cipher .. [2] http://mathworld.wolfram.com/CaesarsMethod.html See Also ======== decipher_shift """ msg, _, A = _prep(msg, '', symbols) shift = len(A) - key % len(A) key = A[shift:] + A[:shift] return translate(msg, key, A) def decipher_shift(msg, key, symbols=None): """ Return the text by shifting the characters of ``msg`` to the left by the amount given by ``key``. Examples ======== >>> from sympy.crypto.crypto import encipher_shift, decipher_shift >>> msg = "GONAVYBEATARMY" >>> ct = encipher_shift(msg, 1); ct 'HPOBWZCFBUBSNZ' To decipher the shifted text, change the sign of the key: >>> encipher_shift(ct, -1) 'GONAVYBEATARMY' Or use this function with the original key: >>> decipher_shift(ct, 1) 'GONAVYBEATARMY' """ return encipher_shift(msg, -key, symbols) def encipher_rot13(msg, symbols=None): """ Performs the ROT13 encryption on a given plaintext ``msg``. Explanation =========== ROT13 is a substitution cipher which substitutes each letter in the plaintext message for the letter furthest away from it in the English alphabet. Equivalently, it is just a Caeser (shift) cipher with a shift key of 13 (midway point of the alphabet). References ========== .. [1] https://en.wikipedia.org/wiki/ROT13 See Also ======== decipher_rot13 encipher_shift """ return encipher_shift(msg, 13, symbols) def decipher_rot13(msg, symbols=None): """ Performs the ROT13 decryption on a given plaintext ``msg``. Explanation ============ ``decipher_rot13`` is equivalent to ``encipher_rot13`` as both ``decipher_shift`` with a key of 13 and ``encipher_shift`` key with a key of 13 will return the same results. Nonetheless, ``decipher_rot13`` has nonetheless been explicitly defined here for consistency. Examples ======== >>> from sympy.crypto.crypto import encipher_rot13, decipher_rot13 >>> msg = 'GONAVYBEATARMY' >>> ciphertext = encipher_rot13(msg);ciphertext 'TBANILORNGNEZL' >>> decipher_rot13(ciphertext) 'GONAVYBEATARMY' >>> encipher_rot13(msg) == decipher_rot13(msg) True >>> msg == decipher_rot13(ciphertext) True """ return decipher_shift(msg, 13, symbols) ######## affine cipher examples ############ def encipher_affine(msg, key, symbols=None, _inverse=False): r""" Performs the affine cipher encryption on plaintext ``msg``, and returns the ciphertext. Explanation =========== Encryption is based on the map `x \rightarrow ax+b` (mod `N`) where ``N`` is the number of characters in the alphabet. Decryption is based on the map `x \rightarrow cx+d` (mod `N`), where `c = a^{-1}` (mod `N`) and `d = -a^{-1}b` (mod `N`). In particular, for the map to be invertible, we need `\mathrm{gcd}(a, N) = 1` and an error will be raised if this is not true. Parameters ========== msg : str Characters that appear in ``symbols``. a, b : int, int A pair integers, with ``gcd(a, N) = 1`` (the secret key). symbols String of characters (default = uppercase letters). When no symbols are given, ``msg`` is converted to upper case letters and all other characters are ignored. Returns ======= ct String of characters (the ciphertext message) Notes ===== ALGORITHM: STEPS: 0. Number the letters of the alphabet from 0, ..., N 1. Compute from the string ``msg`` a list ``L1`` of corresponding integers. 2. Compute from the list ``L1`` a new list ``L2``, given by replacing ``x`` by ``a*x + b (mod N)``, for each element ``x`` in ``L1``. 3. Compute from the list ``L2`` a string ``ct`` of corresponding letters. This is a straightforward generalization of the shift cipher with the added complexity of requiring 2 characters to be deciphered in order to recover the key. References ========== .. [1] https://en.wikipedia.org/wiki/Affine_cipher See Also ======== decipher_affine """ msg, _, A = _prep(msg, '', symbols) N = len(A) a, b = key assert gcd(a, N) == 1 if _inverse: c = mod_inverse(a, N) d = -b*c a, b = c, d B = ''.join([A[(a*i + b) % N] for i in range(N)]) return translate(msg, A, B) def decipher_affine(msg, key, symbols=None): r""" Return the deciphered text that was made from the mapping, `x \rightarrow ax+b` (mod `N`), where ``N`` is the number of characters in the alphabet. Deciphering is done by reciphering with a new key: `x \rightarrow cx+d` (mod `N`), where `c = a^{-1}` (mod `N`) and `d = -a^{-1}b` (mod `N`). Examples ======== >>> from sympy.crypto.crypto import encipher_affine, decipher_affine >>> msg = "GO NAVY BEAT ARMY" >>> key = (3, 1) >>> encipher_affine(msg, key) 'TROBMVENBGBALV' >>> decipher_affine(_, key) 'GONAVYBEATARMY' See Also ======== encipher_affine """ return encipher_affine(msg, key, symbols, _inverse=True) def encipher_atbash(msg, symbols=None): r""" Enciphers a given ``msg`` into its Atbash ciphertext and returns it. Explanation =========== Atbash is a substitution cipher originally used to encrypt the Hebrew alphabet. Atbash works on the principle of mapping each alphabet to its reverse / counterpart (i.e. a would map to z, b to y etc.) Atbash is functionally equivalent to the affine cipher with ``a = 25`` and ``b = 25`` See Also ======== decipher_atbash """ return encipher_affine(msg, (25, 25), symbols) def decipher_atbash(msg, symbols=None): r""" Deciphers a given ``msg`` using Atbash cipher and returns it. Explanation =========== ``decipher_atbash`` is functionally equivalent to ``encipher_atbash``. However, it has still been added as a separate function to maintain consistency. Examples ======== >>> from sympy.crypto.crypto import encipher_atbash, decipher_atbash >>> msg = 'GONAVYBEATARMY' >>> encipher_atbash(msg) 'TLMZEBYVZGZINB' >>> decipher_atbash(msg) 'TLMZEBYVZGZINB' >>> encipher_atbash(msg) == decipher_atbash(msg) True >>> msg == encipher_atbash(encipher_atbash(msg)) True References ========== .. [1] https://en.wikipedia.org/wiki/Atbash See Also ======== encipher_atbash """ return decipher_affine(msg, (25, 25), symbols) #################### substitution cipher ########################### def encipher_substitution(msg, old, new=None): r""" Returns the ciphertext obtained by replacing each character that appears in ``old`` with the corresponding character in ``new``. If ``old`` is a mapping, then new is ignored and the replacements defined by ``old`` are used. Explanation =========== This is a more general than the affine cipher in that the key can only be recovered by determining the mapping for each symbol. Though in practice, once a few symbols are recognized the mappings for other characters can be quickly guessed. Examples ======== >>> from sympy.crypto.crypto import encipher_substitution, AZ >>> old = 'OEYAG' >>> new = '034^6' >>> msg = AZ("go navy! beat army!") >>> ct = encipher_substitution(msg, old, new); ct '60N^V4B3^T^RM4' To decrypt a substitution, reverse the last two arguments: >>> encipher_substitution(ct, new, old) 'GONAVYBEATARMY' In the special case where ``old`` and ``new`` are a permutation of order 2 (representing a transposition of characters) their order is immaterial: >>> old = 'NAVY' >>> new = 'ANYV' >>> encipher = lambda x: encipher_substitution(x, old, new) >>> encipher('NAVY') 'ANYV' >>> encipher(_) 'NAVY' The substitution cipher, in general, is a method whereby "units" (not necessarily single characters) of plaintext are replaced with ciphertext according to a regular system. >>> ords = dict(zip('abc', ['\\%i' % ord(i) for i in 'abc'])) >>> print(encipher_substitution('abc', ords)) \97\98\99 References ========== .. [1] https://en.wikipedia.org/wiki/Substitution_cipher """ return translate(msg, old, new) ###################################################################### #################### Vigenere cipher examples ######################## ###################################################################### def encipher_vigenere(msg, key, symbols=None): """ Performs the Vigenere cipher encryption on plaintext ``msg``, and returns the ciphertext. Examples ======== >>> from sympy.crypto.crypto import encipher_vigenere, AZ >>> key = "encrypt" >>> msg = "meet me on monday" >>> encipher_vigenere(msg, key) 'QRGKKTHRZQEBPR' Section 1 of the Kryptos sculpture at the CIA headquarters uses this cipher and also changes the order of the the alphabet [2]_. Here is the first line of that section of the sculpture: >>> from sympy.crypto.crypto import decipher_vigenere, padded_key >>> alp = padded_key('KRYPTOS', AZ()) >>> key = 'PALIMPSEST' >>> msg = 'EMUFPHZLRFAXYUSDJKZLDKRNSHGNFIVJ' >>> decipher_vigenere(msg, key, alp) 'BETWEENSUBTLESHADINGANDTHEABSENC' Explanation =========== The Vigenere cipher is named after Blaise de Vigenere, a sixteenth century diplomat and cryptographer, by a historical accident. Vigenere actually invented a different and more complicated cipher. The so-called *Vigenere cipher* was actually invented by Giovan Batista Belaso in 1553. This cipher was used in the 1800's, for example, during the American Civil War. The Confederacy used a brass cipher disk to implement the Vigenere cipher (now on display in the NSA Museum in Fort Meade) [1]_. The Vigenere cipher is a generalization of the shift cipher. Whereas the shift cipher shifts each letter by the same amount (that amount being the key of the shift cipher) the Vigenere cipher shifts a letter by an amount determined by the key (which is a word or phrase known only to the sender and receiver). For example, if the key was a single letter, such as "C", then the so-called Vigenere cipher is actually a shift cipher with a shift of `2` (since "C" is the 2nd letter of the alphabet, if you start counting at `0`). If the key was a word with two letters, such as "CA", then the so-called Vigenere cipher will shift letters in even positions by `2` and letters in odd positions are left alone (shifted by `0`, since "A" is the 0th letter, if you start counting at `0`). ALGORITHM: INPUT: ``msg``: string of characters that appear in ``symbols`` (the plaintext) ``key``: a string of characters that appear in ``symbols`` (the secret key) ``symbols``: a string of letters defining the alphabet OUTPUT: ``ct``: string of characters (the ciphertext message) STEPS: 0. Number the letters of the alphabet from 0, ..., N 1. Compute from the string ``key`` a list ``L1`` of corresponding integers. Let ``n1 = len(L1)``. 2. Compute from the string ``msg`` a list ``L2`` of corresponding integers. Let ``n2 = len(L2)``. 3. Break ``L2`` up sequentially into sublists of size ``n1``; the last sublist may be smaller than ``n1`` 4. For each of these sublists ``L`` of ``L2``, compute a new list ``C`` given by ``C[i] = L[i] + L1[i] (mod N)`` to the ``i``-th element in the sublist, for each ``i``. 5. Assemble these lists ``C`` by concatenation into a new list of length ``n2``. 6. Compute from the new list a string ``ct`` of corresponding letters. Once it is known that the key is, say, `n` characters long, frequency analysis can be applied to every `n`-th letter of the ciphertext to determine the plaintext. This method is called *Kasiski examination* (although it was first discovered by Babbage). If they key is as long as the message and is comprised of randomly selected characters -- a one-time pad -- the message is theoretically unbreakable. The cipher Vigenere actually discovered is an "auto-key" cipher described as follows. ALGORITHM: INPUT: ``key``: a string of letters (the secret key) ``msg``: string of letters (the plaintext message) OUTPUT: ``ct``: string of upper-case letters (the ciphertext message) STEPS: 0. Number the letters of the alphabet from 0, ..., N 1. Compute from the string ``msg`` a list ``L2`` of corresponding integers. Let ``n2 = len(L2)``. 2. Let ``n1`` be the length of the key. Append to the string ``key`` the first ``n2 - n1`` characters of the plaintext message. Compute from this string (also of length ``n2``) a list ``L1`` of integers corresponding to the letter numbers in the first step. 3. Compute a new list ``C`` given by ``C[i] = L1[i] + L2[i] (mod N)``. 4. Compute from the new list a string ``ct`` of letters corresponding to the new integers. To decipher the auto-key ciphertext, the key is used to decipher the first ``n1`` characters and then those characters become the key to decipher the next ``n1`` characters, etc...: >>> m = AZ('go navy, beat army! yes you can'); m 'GONAVYBEATARMYYESYOUCAN' >>> key = AZ('gold bug'); n1 = len(key); n2 = len(m) >>> auto_key = key + m[:n2 - n1]; auto_key 'GOLDBUGGONAVYBEATARMYYE' >>> ct = encipher_vigenere(m, auto_key); ct 'MCYDWSHKOGAMKZCELYFGAYR' >>> n1 = len(key) >>> pt = [] >>> while ct: ... part, ct = ct[:n1], ct[n1:] ... pt.append(decipher_vigenere(part, key)) ... key = pt[-1] ... >>> ''.join(pt) == m True References ========== .. [1] https://en.wikipedia.org/wiki/Vigenere_cipher .. [2] http://web.archive.org/web/20071116100808/ .. [3] http://filebox.vt.edu/users/batman/kryptos.html (short URL: https://goo.gl/ijr22d) """ msg, key, A = _prep(msg, key, symbols) map = {c: i for i, c in enumerate(A)} key = [map[c] for c in key] N = len(map) k = len(key) rv = [] for i, m in enumerate(msg): rv.append(A[(map[m] + key[i % k]) % N]) rv = ''.join(rv) return rv def decipher_vigenere(msg, key, symbols=None): """ Decode using the Vigenere cipher. Examples ======== >>> from sympy.crypto.crypto import decipher_vigenere >>> key = "encrypt" >>> ct = "QRGK kt HRZQE BPR" >>> decipher_vigenere(ct, key) 'MEETMEONMONDAY' """ msg, key, A = _prep(msg, key, symbols) map = {c: i for i, c in enumerate(A)} N = len(A) # normally, 26 K = [map[c] for c in key] n = len(K) C = [map[c] for c in msg] rv = ''.join([A[(-K[i % n] + c) % N] for i, c in enumerate(C)]) return rv #################### Hill cipher ######################## def encipher_hill(msg, key, symbols=None, pad="Q"): r""" Return the Hill cipher encryption of ``msg``. Explanation =========== The Hill cipher [1]_, invented by Lester S. Hill in the 1920's [2]_, was the first polygraphic cipher in which it was practical (though barely) to operate on more than three symbols at once. The following discussion assumes an elementary knowledge of matrices. First, each letter is first encoded as a number starting with 0. Suppose your message `msg` consists of `n` capital letters, with no spaces. This may be regarded an `n`-tuple M of elements of `Z_{26}` (if the letters are those of the English alphabet). A key in the Hill cipher is a `k x k` matrix `K`, all of whose entries are in `Z_{26}`, such that the matrix `K` is invertible (i.e., the linear transformation `K: Z_{N}^k \rightarrow Z_{N}^k` is one-to-one). Parameters ========== msg Plaintext message of `n` upper-case letters. key A `k \times k` invertible matrix `K`, all of whose entries are in `Z_{26}` (or whatever number of symbols are being used). pad Character (default "Q") to use to make length of text be a multiple of ``k``. Returns ======= ct Ciphertext of upper-case letters. Notes ===== ALGORITHM: STEPS: 0. Number the letters of the alphabet from 0, ..., N 1. Compute from the string ``msg`` a list ``L`` of corresponding integers. Let ``n = len(L)``. 2. Break the list ``L`` up into ``t = ceiling(n/k)`` sublists ``L_1``, ..., ``L_t`` of size ``k`` (with the last list "padded" to ensure its size is ``k``). 3. Compute new list ``C_1``, ..., ``C_t`` given by ``C[i] = K*L_i`` (arithmetic is done mod N), for each ``i``. 4. Concatenate these into a list ``C = C_1 + ... + C_t``. 5. Compute from ``C`` a string ``ct`` of corresponding letters. This has length ``k*t``. References ========== .. [1] https://en.wikipedia.org/wiki/Hill_cipher .. [2] Lester S. Hill, Cryptography in an Algebraic Alphabet, The American Mathematical Monthly Vol.36, June-July 1929, pp.306-312. See Also ======== decipher_hill """ assert key.is_square assert len(pad) == 1 msg, pad, A = _prep(msg, pad, symbols) map = {c: i for i, c in enumerate(A)} P = [map[c] for c in msg] N = len(A) k = key.cols n = len(P) m, r = divmod(n, k) if r: P = P + [map[pad]]*(k - r) m += 1 rv = ''.join([A[c % N] for j in range(m) for c in list(key*Matrix(k, 1, [P[i] for i in range(k*j, k*(j + 1))]))]) return rv def decipher_hill(msg, key, symbols=None): """ Deciphering is the same as enciphering but using the inverse of the key matrix. Examples ======== >>> from sympy.crypto.crypto import encipher_hill, decipher_hill >>> from sympy import Matrix >>> key = Matrix([[1, 2], [3, 5]]) >>> encipher_hill("meet me on monday", key) 'UEQDUEODOCTCWQ' >>> decipher_hill(_, key) 'MEETMEONMONDAY' When the length of the plaintext (stripped of invalid characters) is not a multiple of the key dimension, extra characters will appear at the end of the enciphered and deciphered text. In order to decipher the text, those characters must be included in the text to be deciphered. In the following, the key has a dimension of 4 but the text is 2 short of being a multiple of 4 so two characters will be added. >>> key = Matrix([[1, 1, 1, 2], [0, 1, 1, 0], ... [2, 2, 3, 4], [1, 1, 0, 1]]) >>> msg = "ST" >>> encipher_hill(msg, key) 'HJEB' >>> decipher_hill(_, key) 'STQQ' >>> encipher_hill(msg, key, pad="Z") 'ISPK' >>> decipher_hill(_, key) 'STZZ' If the last two characters of the ciphertext were ignored in either case, the wrong plaintext would be recovered: >>> decipher_hill("HD", key) 'ORMV' >>> decipher_hill("IS", key) 'UIKY' See Also ======== encipher_hill """ assert key.is_square msg, _, A = _prep(msg, '', symbols) map = {c: i for i, c in enumerate(A)} C = [map[c] for c in msg] N = len(A) k = key.cols n = len(C) m, r = divmod(n, k) if r: C = C + [0]*(k - r) m += 1 key_inv = key.inv_mod(N) rv = ''.join([A[p % N] for j in range(m) for p in list(key_inv*Matrix( k, 1, [C[i] for i in range(k*j, k*(j + 1))]))]) return rv #################### Bifid cipher ######################## def encipher_bifid(msg, key, symbols=None): r""" Performs the Bifid cipher encryption on plaintext ``msg``, and returns the ciphertext. This is the version of the Bifid cipher that uses an `n \times n` Polybius square. Parameters ========== msg Plaintext string. key Short string for key. Duplicate characters are ignored and then it is padded with the characters in ``symbols`` that were not in the short key. symbols `n \times n` characters defining the alphabet. (default is string.printable) Returns ======= ciphertext Ciphertext using Bifid5 cipher without spaces. See Also ======== decipher_bifid, encipher_bifid5, encipher_bifid6 References ========== .. [1] https://en.wikipedia.org/wiki/Bifid_cipher """ msg, key, A = _prep(msg, key, symbols, bifid10) long_key = ''.join(uniq(key)) or A n = len(A)**.5 if n != int(n): raise ValueError( 'Length of alphabet (%s) is not a square number.' % len(A)) N = int(n) if len(long_key) < N**2: long_key = list(long_key) + [x for x in A if x not in long_key] # the fractionalization row_col = {ch: divmod(i, N) for i, ch in enumerate(long_key)} r, c = zip(*[row_col[x] for x in msg]) rc = r + c ch = {i: ch for ch, i in row_col.items()} rv = ''.join(ch[i] for i in zip(rc[::2], rc[1::2])) return rv def decipher_bifid(msg, key, symbols=None): r""" Performs the Bifid cipher decryption on ciphertext ``msg``, and returns the plaintext. This is the version of the Bifid cipher that uses the `n \times n` Polybius square. Parameters ========== msg Ciphertext string. key Short string for key. Duplicate characters are ignored and then it is padded with the characters in symbols that were not in the short key. symbols `n \times n` characters defining the alphabet. (default=string.printable, a `10 \times 10` matrix) Returns ======= deciphered Deciphered text. Examples ======== >>> from sympy.crypto.crypto import ( ... encipher_bifid, decipher_bifid, AZ) Do an encryption using the bifid5 alphabet: >>> alp = AZ().replace('J', '') >>> ct = AZ("meet me on monday!") >>> key = AZ("gold bug") >>> encipher_bifid(ct, key, alp) 'IEILHHFSTSFQYE' When entering the text or ciphertext, spaces are ignored so it can be formatted as desired. Re-entering the ciphertext from the preceding, putting 4 characters per line and padding with an extra J, does not cause problems for the deciphering: >>> decipher_bifid(''' ... IEILH ... HFSTS ... FQYEJ''', key, alp) 'MEETMEONMONDAY' When no alphabet is given, all 100 printable characters will be used: >>> key = '' >>> encipher_bifid('hello world!', key) 'bmtwmg-bIo*w' >>> decipher_bifid(_, key) 'hello world!' If the key is changed, a different encryption is obtained: >>> key = 'gold bug' >>> encipher_bifid('hello world!', 'gold_bug') 'hg2sfuei7t}w' And if the key used to decrypt the message is not exact, the original text will not be perfectly obtained: >>> decipher_bifid(_, 'gold pug') 'heldo~wor6d!' """ msg, _, A = _prep(msg, '', symbols, bifid10) long_key = ''.join(uniq(key)) or A n = len(A)**.5 if n != int(n): raise ValueError( 'Length of alphabet (%s) is not a square number.' % len(A)) N = int(n) if len(long_key) < N**2: long_key = list(long_key) + [x for x in A if x not in long_key] # the reverse fractionalization row_col = { ch: divmod(i, N) for i, ch in enumerate(long_key)} rc = [i for c in msg for i in row_col[c]] n = len(msg) rc = zip(*(rc[:n], rc[n:])) ch = {i: ch for ch, i in row_col.items()} rv = ''.join(ch[i] for i in rc) return rv def bifid_square(key): """Return characters of ``key`` arranged in a square. Examples ======== >>> from sympy.crypto.crypto import ( ... bifid_square, AZ, padded_key, bifid5) >>> bifid_square(AZ().replace('J', '')) Matrix([ [A, B, C, D, E], [F, G, H, I, K], [L, M, N, O, P], [Q, R, S, T, U], [V, W, X, Y, Z]]) >>> bifid_square(padded_key(AZ('gold bug!'), bifid5)) Matrix([ [G, O, L, D, B], [U, A, C, E, F], [H, I, K, M, N], [P, Q, R, S, T], [V, W, X, Y, Z]]) See Also ======== padded_key """ A = ''.join(uniq(''.join(key))) n = len(A)**.5 if n != int(n): raise ValueError( 'Length of alphabet (%s) is not a square number.' % len(A)) n = int(n) f = lambda i, j: Symbol(A[n*i + j]) rv = Matrix(n, n, f) return rv def encipher_bifid5(msg, key): r""" Performs the Bifid cipher encryption on plaintext ``msg``, and returns the ciphertext. Explanation =========== This is the version of the Bifid cipher that uses the `5 \times 5` Polybius square. The letter "J" is ignored so it must be replaced with something else (traditionally an "I") before encryption. ALGORITHM: (5x5 case) STEPS: 0. Create the `5 \times 5` Polybius square ``S`` associated to ``key`` as follows: a) moving from left-to-right, top-to-bottom, place the letters of the key into a `5 \times 5` matrix, b) if the key has less than 25 letters, add the letters of the alphabet not in the key until the `5 \times 5` square is filled. 1. Create a list ``P`` of pairs of numbers which are the coordinates in the Polybius square of the letters in ``msg``. 2. Let ``L1`` be the list of all first coordinates of ``P`` (length of ``L1 = n``), let ``L2`` be the list of all second coordinates of ``P`` (so the length of ``L2`` is also ``n``). 3. Let ``L`` be the concatenation of ``L1`` and ``L2`` (length ``L = 2*n``), except that consecutive numbers are paired ``(L[2*i], L[2*i + 1])``. You can regard ``L`` as a list of pairs of length ``n``. 4. Let ``C`` be the list of all letters which are of the form ``S[i, j]``, for all ``(i, j)`` in ``L``. As a string, this is the ciphertext of ``msg``. Parameters ========== msg : str Plaintext string. Converted to upper case and filtered of anything but all letters except J. key Short string for key; non-alphabetic letters, J and duplicated characters are ignored and then, if the length is less than 25 characters, it is padded with other letters of the alphabet (in alphabetical order). Returns ======= ct Ciphertext (all caps, no spaces). Examples ======== >>> from sympy.crypto.crypto import ( ... encipher_bifid5, decipher_bifid5) "J" will be omitted unless it is replaced with something else: >>> round_trip = lambda m, k: \ ... decipher_bifid5(encipher_bifid5(m, k), k) >>> key = 'a' >>> msg = "JOSIE" >>> round_trip(msg, key) 'OSIE' >>> round_trip(msg.replace("J", "I"), key) 'IOSIE' >>> j = "QIQ" >>> round_trip(msg.replace("J", j), key).replace(j, "J") 'JOSIE' Notes ===== The Bifid cipher was invented around 1901 by Felix Delastelle. It is a *fractional substitution* cipher, where letters are replaced by pairs of symbols from a smaller alphabet. The cipher uses a `5 \times 5` square filled with some ordering of the alphabet, except that "J" is replaced with "I" (this is a so-called Polybius square; there is a `6 \times 6` analog if you add back in "J" and also append onto the usual 26 letter alphabet, the digits 0, 1, ..., 9). According to Helen Gaines' book *Cryptanalysis*, this type of cipher was used in the field by the German Army during World War I. See Also ======== decipher_bifid5, encipher_bifid """ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid5) key = padded_key(key, bifid5) return encipher_bifid(msg, '', key) def decipher_bifid5(msg, key): r""" Return the Bifid cipher decryption of ``msg``. Explanation =========== This is the version of the Bifid cipher that uses the `5 \times 5` Polybius square; the letter "J" is ignored unless a ``key`` of length 25 is used. Parameters ========== msg Ciphertext string. key Short string for key; duplicated characters are ignored and if the length is less then 25 characters, it will be padded with other letters from the alphabet omitting "J". Non-alphabetic characters are ignored. Returns ======= plaintext Plaintext from Bifid5 cipher (all caps, no spaces). Examples ======== >>> from sympy.crypto.crypto import encipher_bifid5, decipher_bifid5 >>> key = "gold bug" >>> encipher_bifid5('meet me on friday', key) 'IEILEHFSTSFXEE' >>> encipher_bifid5('meet me on monday', key) 'IEILHHFSTSFQYE' >>> decipher_bifid5(_, key) 'MEETMEONMONDAY' """ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid5) key = padded_key(key, bifid5) return decipher_bifid(msg, '', key) def bifid5_square(key=None): r""" 5x5 Polybius square. Produce the Polybius square for the `5 \times 5` Bifid cipher. Examples ======== >>> from sympy.crypto.crypto import bifid5_square >>> bifid5_square("gold bug") Matrix([ [G, O, L, D, B], [U, A, C, E, F], [H, I, K, M, N], [P, Q, R, S, T], [V, W, X, Y, Z]]) """ if not key: key = bifid5 else: _, key, _ = _prep('', key.upper(), None, bifid5) key = padded_key(key, bifid5) return bifid_square(key) def encipher_bifid6(msg, key): r""" Performs the Bifid cipher encryption on plaintext ``msg``, and returns the ciphertext. This is the version of the Bifid cipher that uses the `6 \times 6` Polybius square. Parameters ========== msg Plaintext string (digits okay). key Short string for key (digits okay). If ``key`` is less than 36 characters long, the square will be filled with letters A through Z and digits 0 through 9. Returns ======= ciphertext Ciphertext from Bifid cipher (all caps, no spaces). See Also ======== decipher_bifid6, encipher_bifid """ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid6) key = padded_key(key, bifid6) return encipher_bifid(msg, '', key) def decipher_bifid6(msg, key): r""" Performs the Bifid cipher decryption on ciphertext ``msg``, and returns the plaintext. This is the version of the Bifid cipher that uses the `6 \times 6` Polybius square. Parameters ========== msg Ciphertext string (digits okay); converted to upper case key Short string for key (digits okay). If ``key`` is less than 36 characters long, the square will be filled with letters A through Z and digits 0 through 9. All letters are converted to uppercase. Returns ======= plaintext Plaintext from Bifid cipher (all caps, no spaces). Examples ======== >>> from sympy.crypto.crypto import encipher_bifid6, decipher_bifid6 >>> key = "gold bug" >>> encipher_bifid6('meet me on monday at 8am', key) 'KFKLJJHF5MMMKTFRGPL' >>> decipher_bifid6(_, key) 'MEETMEONMONDAYAT8AM' """ msg, key, _ = _prep(msg.upper(), key.upper(), None, bifid6) key = padded_key(key, bifid6) return decipher_bifid(msg, '', key) def bifid6_square(key=None): r""" 6x6 Polybius square. Produces the Polybius square for the `6 \times 6` Bifid cipher. Assumes alphabet of symbols is "A", ..., "Z", "0", ..., "9". Examples ======== >>> from sympy.crypto.crypto import bifid6_square >>> key = "gold bug" >>> bifid6_square(key) Matrix([ [G, O, L, D, B, U], [A, C, E, F, H, I], [J, K, M, N, P, Q], [R, S, T, V, W, X], [Y, Z, 0, 1, 2, 3], [4, 5, 6, 7, 8, 9]]) """ if not key: key = bifid6 else: _, key, _ = _prep('', key.upper(), None, bifid6) key = padded_key(key, bifid6) return bifid_square(key) #################### RSA ############################# def _decipher_rsa_crt(i, d, factors): """Decipher RSA using chinese remainder theorem from the information of the relatively-prime factors of the modulus. Parameters ========== i : integer Ciphertext d : integer The exponent component. factors : list of relatively-prime integers The integers given must be coprime and the product must equal the modulus component of the original RSA key. Examples ======== How to decrypt RSA with CRT: >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key >>> primes = [61, 53] >>> e = 17 >>> args = primes + [e] >>> puk = rsa_public_key(*args) >>> prk = rsa_private_key(*args) >>> from sympy.crypto.crypto import encipher_rsa, _decipher_rsa_crt >>> msg = 65 >>> crt_primes = primes >>> encrypted = encipher_rsa(msg, puk) >>> decrypted = _decipher_rsa_crt(encrypted, prk[1], primes) >>> decrypted 65 """ from sympy.ntheory.modular import crt moduluses = [pow(i, d, p) for p in factors] result = crt(factors, moduluses) if not result: raise ValueError("CRT failed") return result[0] def _rsa_key(*args, public=True, private=True, totient='Euler', index=None, multipower=None): r"""A private subroutine to generate RSA key Parameters ========== public, private : bool, optional Flag to generate either a public key, a private key. totient : 'Euler' or 'Carmichael' Different notation used for totient. multipower : bool, optional Flag to bypass warning for multipower RSA. """ from sympy.ntheory import totient as _euler from sympy.ntheory import reduced_totient as _carmichael if len(args) < 2: return False if totient not in ('Euler', 'Carmichael'): raise ValueError( "The argument totient={} should either be " \ "'Euler', 'Carmichalel'." \ .format(totient)) if totient == 'Euler': _totient = _euler else: _totient = _carmichael if index is not None: index = as_int(index) if totient != 'Carmichael': raise ValueError( "Setting the 'index' keyword argument requires totient" "notation to be specified as 'Carmichael'.") primes, e = args[:-1], args[-1] if any(not isprime(p) for p in primes): new_primes = [] for i in primes: new_primes.extend(factorint(i, multiple=True)) primes = new_primes n = reduce(lambda i, j: i*j, primes) tally = multiset(primes) if all(v == 1 for v in tally.values()): multiple = list(tally.keys()) phi = _totient._from_distinct_primes(*multiple) else: if not multipower: NonInvertibleCipherWarning( 'Non-distinctive primes found in the factors {}. ' 'The cipher may not be decryptable for some numbers ' 'in the complete residue system Z[{}], but the cipher ' 'can still be valid if you restrict the domain to be ' 'the reduced residue system Z*[{}]. You can pass ' 'the flag multipower=True if you want to suppress this ' 'warning.' .format(primes, n, n) ).warn() phi = _totient._from_factors(tally) if igcd(e, phi) == 1: if public and not private: if isinstance(index, int): e = e % phi e += index * phi return n, e if private and not public: d = mod_inverse(e, phi) if isinstance(index, int): d += index * phi return n, d return False def rsa_public_key(*args, **kwargs): r"""Return the RSA *public key* pair, `(n, e)` Parameters ========== args : naturals If specified as `p, q, e` where `p` and `q` are distinct primes and `e` is a desired public exponent of the RSA, `n = p q` and `e` will be verified against the totient `\phi(n)` (Euler totient) or `\lambda(n)` (Carmichael totient) to be `\gcd(e, \phi(n)) = 1` or `\gcd(e, \lambda(n)) = 1`. If specified as `p_1, p_2, ..., p_n, e` where `p_1, p_2, ..., p_n` are specified as primes, and `e` is specified as a desired public exponent of the RSA, it will be able to form a multi-prime RSA, which is a more generalized form of the popular 2-prime RSA. It can also be possible to form a single-prime RSA by specifying the argument as `p, e`, which can be considered a trivial case of a multiprime RSA. Furthermore, it can be possible to form a multi-power RSA by specifying two or more pairs of the primes to be same. However, unlike the two-distinct prime RSA or multi-prime RSA, not every numbers in the complete residue system (`\mathbb{Z}_n`) will be decryptable since the mapping `\mathbb{Z}_{n} \rightarrow \mathbb{Z}_{n}` will not be bijective. (Only except for the trivial case when `e = 1` or more generally, .. math:: e \in \left \{ 1 + k \lambda(n) \mid k \in \mathbb{Z} \land k \geq 0 \right \} when RSA reduces to the identity.) However, the RSA can still be decryptable for the numbers in the reduced residue system (`\mathbb{Z}_n^{\times}`), since the mapping `\mathbb{Z}_{n}^{\times} \rightarrow \mathbb{Z}_{n}^{\times}` can still be bijective. If you pass a non-prime integer to the arguments `p_1, p_2, ..., p_n`, the particular number will be prime-factored and it will become either a multi-prime RSA or a multi-power RSA in its canonical form, depending on whether the product equals its radical or not. `p_1 p_2 ... p_n = \text{rad}(p_1 p_2 ... p_n)` totient : bool, optional If ``'Euler'``, it uses Euler's totient `\phi(n)` which is :meth:`sympy.ntheory.factor_.totient` in SymPy. If ``'Carmichael'``, it uses Carmichael's totient `\lambda(n)` which is :meth:`sympy.ntheory.factor_.reduced_totient` in SymPy. Unlike private key generation, this is a trivial keyword for public key generation because `\gcd(e, \phi(n)) = 1 \iff \gcd(e, \lambda(n)) = 1`. index : nonnegative integer, optional Returns an arbitrary solution of a RSA public key at the index specified at `0, 1, 2, ...`. This parameter needs to be specified along with ``totient='Carmichael'``. Similarly to the non-uniquenss of a RSA private key as described in the ``index`` parameter documentation in :meth:`rsa_private_key`, RSA public key is also not unique and there is an infinite number of RSA public exponents which can behave in the same manner. From any given RSA public exponent `e`, there are can be an another RSA public exponent `e + k \lambda(n)` where `k` is an integer, `\lambda` is a Carmichael's totient function. However, considering only the positive cases, there can be a principal solution of a RSA public exponent `e_0` in `0 < e_0 < \lambda(n)`, and all the other solutions can be canonicalzed in a form of `e_0 + k \lambda(n)`. ``index`` specifies the `k` notation to yield any possible value an RSA public key can have. An example of computing any arbitrary RSA public key: >>> from sympy.crypto.crypto import rsa_public_key >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=0) (3233, 17) >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=1) (3233, 797) >>> rsa_public_key(61, 53, 17, totient='Carmichael', index=2) (3233, 1577) multipower : bool, optional Any pair of non-distinct primes found in the RSA specification will restrict the domain of the cryptosystem, as noted in the explaination of the parameter ``args``. SymPy RSA key generator may give a warning before dispatching it as a multi-power RSA, however, you can disable the warning if you pass ``True`` to this keyword. Returns ======= (n, e) : int, int `n` is a product of any arbitrary number of primes given as the argument. `e` is relatively prime (coprime) to the Euler totient `\phi(n)`. False Returned if less than two arguments are given, or `e` is not relatively prime to the modulus. Examples ======== >>> from sympy.crypto.crypto import rsa_public_key A public key of a two-prime RSA: >>> p, q, e = 3, 5, 7 >>> rsa_public_key(p, q, e) (15, 7) >>> rsa_public_key(p, q, 30) False A public key of a multiprime RSA: >>> primes = [2, 3, 5, 7, 11, 13] >>> e = 7 >>> args = primes + [e] >>> rsa_public_key(*args) (30030, 7) Notes ===== Although the RSA can be generalized over any modulus `n`, using two large primes had became the most popular specification because a product of two large primes is usually the hardest to factor relatively to the digits of `n` can have. However, it may need further understanding of the time complexities of each prime-factoring algorithms to verify the claim. See Also ======== rsa_private_key encipher_rsa decipher_rsa References ========== .. [1] https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29 .. [2] http://cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf .. [3] https://link.springer.com/content/pdf/10.1007%2FBFb0055738.pdf .. [4] http://www.itiis.org/digital-library/manuscript/1381 """ return _rsa_key(*args, public=True, private=False, **kwargs) def rsa_private_key(*args, **kwargs): r"""Return the RSA *private key* pair, `(n, d)` Parameters ========== args : naturals The keyword is identical to the ``args`` in :meth:`rsa_public_key`. totient : bool, optional If ``'Euler'``, it uses Euler's totient convention `\phi(n)` which is :meth:`sympy.ntheory.factor_.totient` in SymPy. If ``'Carmichael'``, it uses Carmichael's totient convention `\lambda(n)` which is :meth:`sympy.ntheory.factor_.reduced_totient` in SymPy. There can be some output differences for private key generation as examples below. Example using Euler's totient: >>> from sympy.crypto.crypto import rsa_private_key >>> rsa_private_key(61, 53, 17, totient='Euler') (3233, 2753) Example using Carmichael's totient: >>> from sympy.crypto.crypto import rsa_private_key >>> rsa_private_key(61, 53, 17, totient='Carmichael') (3233, 413) index : nonnegative integer, optional Returns an arbitrary solution of a RSA private key at the index specified at `0, 1, 2, ...`. This parameter needs to be specified along with ``totient='Carmichael'``. RSA private exponent is a non-unique solution of `e d \mod \lambda(n) = 1` and it is possible in any form of `d + k \lambda(n)`, where `d` is an another already-computed private exponent, and `\lambda` is a Carmichael's totient function, and `k` is any integer. However, considering only the positive cases, there can be a principal solution of a RSA private exponent `d_0` in `0 < d_0 < \lambda(n)`, and all the other solutions can be canonicalzed in a form of `d_0 + k \lambda(n)`. ``index`` specifies the `k` notation to yield any possible value an RSA private key can have. An example of computing any arbitrary RSA private key: >>> from sympy.crypto.crypto import rsa_private_key >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=0) (3233, 413) >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=1) (3233, 1193) >>> rsa_private_key(61, 53, 17, totient='Carmichael', index=2) (3233, 1973) multipower : bool, optional The keyword is identical to the ``multipower`` in :meth:`rsa_public_key`. Returns ======= (n, d) : int, int `n` is a product of any arbitrary number of primes given as the argument. `d` is the inverse of `e` (mod `\phi(n)`) where `e` is the exponent given, and `\phi` is a Euler totient. False Returned if less than two arguments are given, or `e` is not relatively prime to the totient of the modulus. Examples ======== >>> from sympy.crypto.crypto import rsa_private_key A private key of a two-prime RSA: >>> p, q, e = 3, 5, 7 >>> rsa_private_key(p, q, e) (15, 7) >>> rsa_private_key(p, q, 30) False A private key of a multiprime RSA: >>> primes = [2, 3, 5, 7, 11, 13] >>> e = 7 >>> args = primes + [e] >>> rsa_private_key(*args) (30030, 823) See Also ======== rsa_public_key encipher_rsa decipher_rsa References ========== .. [1] https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29 .. [2] http://cacr.uwaterloo.ca/techreports/2006/cacr2006-16.pdf .. [3] https://link.springer.com/content/pdf/10.1007%2FBFb0055738.pdf .. [4] http://www.itiis.org/digital-library/manuscript/1381 """ return _rsa_key(*args, public=False, private=True, **kwargs) def _encipher_decipher_rsa(i, key, factors=None): n, d = key if not factors: return pow(i, d, n) def _is_coprime_set(l): is_coprime_set = True for i in range(len(l)): for j in range(i+1, len(l)): if igcd(l[i], l[j]) != 1: is_coprime_set = False break return is_coprime_set prod = reduce(lambda i, j: i*j, factors) if prod == n and _is_coprime_set(factors): return _decipher_rsa_crt(i, d, factors) return _encipher_decipher_rsa(i, key, factors=None) def encipher_rsa(i, key, factors=None): r"""Encrypt the plaintext with RSA. Parameters ========== i : integer The plaintext to be encrypted for. key : (n, e) where n, e are integers `n` is the modulus of the key and `e` is the exponent of the key. The encryption is computed by `i^e \bmod n`. The key can either be a public key or a private key, however, the message encrypted by a public key can only be decrypted by a private key, and vice versa, as RSA is an asymmetric cryptography system. factors : list of coprime integers This is identical to the keyword ``factors`` in :meth:`decipher_rsa`. Notes ===== Some specifications may make the RSA not cryptographically meaningful. For example, `0`, `1` will remain always same after taking any number of exponentiation, thus, should be avoided. Furthermore, if `i^e < n`, `i` may easily be figured out by taking `e` th root. And also, specifying the exponent as `1` or in more generalized form as `1 + k \lambda(n)` where `k` is an nonnegative integer, `\lambda` is a carmichael totient, the RSA becomes an identity mapping. Examples ======== >>> from sympy.crypto.crypto import encipher_rsa >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key Public Key Encryption: >>> p, q, e = 3, 5, 7 >>> puk = rsa_public_key(p, q, e) >>> msg = 12 >>> encipher_rsa(msg, puk) 3 Private Key Encryption: >>> p, q, e = 3, 5, 7 >>> prk = rsa_private_key(p, q, e) >>> msg = 12 >>> encipher_rsa(msg, prk) 3 Encryption using chinese remainder theorem: >>> encipher_rsa(msg, prk, factors=[p, q]) 3 """ return _encipher_decipher_rsa(i, key, factors=factors) def decipher_rsa(i, key, factors=None): r"""Decrypt the ciphertext with RSA. Parameters ========== i : integer The ciphertext to be decrypted for. key : (n, d) where n, d are integers `n` is the modulus of the key and `d` is the exponent of the key. The decryption is computed by `i^d \bmod n`. The key can either be a public key or a private key, however, the message encrypted by a public key can only be decrypted by a private key, and vice versa, as RSA is an asymmetric cryptography system. factors : list of coprime integers As the modulus `n` created from RSA key generation is composed of arbitrary prime factors `n = {p_1}^{k_1}{p_2}^{k_2}...{p_n}^{k_n}` where `p_1, p_2, ..., p_n` are distinct primes and `k_1, k_2, ..., k_n` are positive integers, chinese remainder theorem can be used to compute `i^d \bmod n` from the fragmented modulo operations like .. math:: i^d \bmod {p_1}^{k_1}, i^d \bmod {p_2}^{k_2}, ... , i^d \bmod {p_n}^{k_n} or like .. math:: i^d \bmod {p_1}^{k_1}{p_2}^{k_2}, i^d \bmod {p_3}^{k_3}, ... , i^d \bmod {p_n}^{k_n} as long as every moduli does not share any common divisor each other. The raw primes used in generating the RSA key pair can be a good option. Note that the speed advantage of using this is only viable for very large cases (Like 2048-bit RSA keys) since the overhead of using pure python implementation of :meth:`sympy.ntheory.modular.crt` may overcompensate the theoritical speed advantage. Notes ===== See the ``Notes`` section in the documentation of :meth:`encipher_rsa` Examples ======== >>> from sympy.crypto.crypto import decipher_rsa, encipher_rsa >>> from sympy.crypto.crypto import rsa_public_key, rsa_private_key Public Key Encryption and Decryption: >>> p, q, e = 3, 5, 7 >>> prk = rsa_private_key(p, q, e) >>> puk = rsa_public_key(p, q, e) >>> msg = 12 >>> new_msg = encipher_rsa(msg, prk) >>> new_msg 3 >>> decipher_rsa(new_msg, puk) 12 Private Key Encryption and Decryption: >>> p, q, e = 3, 5, 7 >>> prk = rsa_private_key(p, q, e) >>> puk = rsa_public_key(p, q, e) >>> msg = 12 >>> new_msg = encipher_rsa(msg, puk) >>> new_msg 3 >>> decipher_rsa(new_msg, prk) 12 Decryption using chinese remainder theorem: >>> decipher_rsa(new_msg, prk, factors=[p, q]) 12 See Also ======== encipher_rsa """ return _encipher_decipher_rsa(i, key, factors=factors) #################### kid krypto (kid RSA) ############################# def kid_rsa_public_key(a, b, A, B): r""" Kid RSA is a version of RSA useful to teach grade school children since it does not involve exponentiation. Explanation =========== Alice wants to talk to Bob. Bob generates keys as follows. Key generation: * Select positive integers `a, b, A, B` at random. * Compute `M = a b - 1`, `e = A M + a`, `d = B M + b`, `n = (e d - 1)//M`. * The *public key* is `(n, e)`. Bob sends these to Alice. * The *private key* is `(n, d)`, which Bob keeps secret. Encryption: If `p` is the plaintext message then the ciphertext is `c = p e \pmod n`. Decryption: If `c` is the ciphertext message then the plaintext is `p = c d \pmod n`. Examples ======== >>> from sympy.crypto.crypto import kid_rsa_public_key >>> a, b, A, B = 3, 4, 5, 6 >>> kid_rsa_public_key(a, b, A, B) (369, 58) """ M = a*b - 1 e = A*M + a d = B*M + b n = (e*d - 1)//M return n, e def kid_rsa_private_key(a, b, A, B): """ Compute `M = a b - 1`, `e = A M + a`, `d = B M + b`, `n = (e d - 1) / M`. The *private key* is `d`, which Bob keeps secret. Examples ======== >>> from sympy.crypto.crypto import kid_rsa_private_key >>> a, b, A, B = 3, 4, 5, 6 >>> kid_rsa_private_key(a, b, A, B) (369, 70) """ M = a*b - 1 e = A*M + a d = B*M + b n = (e*d - 1)//M return n, d def encipher_kid_rsa(msg, key): """ Here ``msg`` is the plaintext and ``key`` is the public key. Examples ======== >>> from sympy.crypto.crypto import ( ... encipher_kid_rsa, kid_rsa_public_key) >>> msg = 200 >>> a, b, A, B = 3, 4, 5, 6 >>> key = kid_rsa_public_key(a, b, A, B) >>> encipher_kid_rsa(msg, key) 161 """ n, e = key return (msg*e) % n def decipher_kid_rsa(msg, key): """ Here ``msg`` is the plaintext and ``key`` is the private key. Examples ======== >>> from sympy.crypto.crypto import ( ... kid_rsa_public_key, kid_rsa_private_key, ... decipher_kid_rsa, encipher_kid_rsa) >>> a, b, A, B = 3, 4, 5, 6 >>> d = kid_rsa_private_key(a, b, A, B) >>> msg = 200 >>> pub = kid_rsa_public_key(a, b, A, B) >>> pri = kid_rsa_private_key(a, b, A, B) >>> ct = encipher_kid_rsa(msg, pub) >>> decipher_kid_rsa(ct, pri) 200 """ n, d = key return (msg*d) % n #################### Morse Code ###################################### morse_char = { ".-": "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", "-----": "0", ".----": "1", "..---": "2", "...--": "3", "....-": "4", ".....": "5", "-....": "6", "--...": "7", "---..": "8", "----.": "9", ".-.-.-": ".", "--..--": ",", "---...": ":", "-.-.-.": ";", "..--..": "?", "-....-": "-", "..--.-": "_", "-.--.": "(", "-.--.-": ")", ".----.": "'", "-...-": "=", ".-.-.": "+", "-..-.": "/", ".--.-.": "@", "...-..-": "$", "-.-.--": "!"} char_morse = {v: k for k, v in morse_char.items()} def encode_morse(msg, sep='|', mapping=None): """ Encodes a plaintext into popular Morse Code with letters separated by ``sep`` and words by a double ``sep``. Examples ======== >>> from sympy.crypto.crypto import encode_morse >>> msg = 'ATTACK RIGHT FLANK' >>> encode_morse(msg) '.-|-|-|.-|-.-.|-.-||.-.|..|--.|....|-||..-.|.-..|.-|-.|-.-' References ========== .. [1] https://en.wikipedia.org/wiki/Morse_code """ mapping = mapping or char_morse assert sep not in mapping word_sep = 2*sep mapping[" "] = word_sep suffix = msg and msg[-1] in whitespace # normalize whitespace msg = (' ' if word_sep else '').join(msg.split()) # omit unmapped chars chars = set(''.join(msg.split())) ok = set(mapping.keys()) msg = translate(msg, None, ''.join(chars - ok)) morsestring = [] words = msg.split() for word in words: morseword = [] for letter in word: morseletter = mapping[letter] morseword.append(morseletter) word = sep.join(morseword) morsestring.append(word) return word_sep.join(morsestring) + (word_sep if suffix else '') def decode_morse(msg, sep='|', mapping=None): """ Decodes a Morse Code with letters separated by ``sep`` (default is '|') and words by `word_sep` (default is '||) into plaintext. Examples ======== >>> from sympy.crypto.crypto import decode_morse >>> mc = '--|---|...-|.||.|.-|...|-' >>> decode_morse(mc) 'MOVE EAST' References ========== .. [1] https://en.wikipedia.org/wiki/Morse_code """ mapping = mapping or morse_char word_sep = 2*sep characterstring = [] words = msg.strip(word_sep).split(word_sep) for word in words: letters = word.split(sep) chars = [mapping[c] for c in letters] word = ''.join(chars) characterstring.append(word) rv = " ".join(characterstring) return rv #################### LFSRs ########################################## def lfsr_sequence(key, fill, n): r""" This function creates an LFSR sequence. Parameters ========== key : list A list of finite field elements, `[c_0, c_1, \ldots, c_k].` fill : list The list of the initial terms of the LFSR sequence, `[x_0, x_1, \ldots, x_k].` n Number of terms of the sequence that the function returns. Returns ======= L The LFSR sequence defined by `x_{n+1} = c_k x_n + \ldots + c_0 x_{n-k}`, for `n \leq k`. Notes ===== S. Golomb [G]_ gives a list of three statistical properties a sequence of numbers `a = \{a_n\}_{n=1}^\infty`, `a_n \in \{0,1\}`, should display to be considered "random". Define the autocorrelation of `a` to be .. math:: C(k) = C(k,a) = \lim_{N\rightarrow \infty} {1\over N}\sum_{n=1}^N (-1)^{a_n + a_{n+k}}. In the case where `a` is periodic with period `P` then this reduces to .. math:: C(k) = {1\over P}\sum_{n=1}^P (-1)^{a_n + a_{n+k}}. Assume `a` is periodic with period `P`. - balance: .. math:: \left|\sum_{n=1}^P(-1)^{a_n}\right| \leq 1. - low autocorrelation: .. math:: C(k) = \left\{ \begin{array}{cc} 1,& k = 0,\\ \epsilon, & k \ne 0. \end{array} \right. (For sequences satisfying these first two properties, it is known that `\epsilon = -1/P` must hold.) - proportional runs property: In each period, half the runs have length `1`, one-fourth have length `2`, etc. Moreover, there are as many runs of `1`'s as there are of `0`'s. Examples ======== >>> from sympy.crypto.crypto import lfsr_sequence >>> from sympy.polys.domains import FF >>> F = FF(2) >>> fill = [F(1), F(1), F(0), F(1)] >>> key = [F(1), F(0), F(0), F(1)] >>> lfsr_sequence(key, fill, 10) [1 mod 2, 1 mod 2, 0 mod 2, 1 mod 2, 0 mod 2, 1 mod 2, 1 mod 2, 0 mod 2, 0 mod 2, 1 mod 2] References ========== .. [G] Solomon Golomb, Shift register sequences, Aegean Park Press, Laguna Hills, Ca, 1967 """ if not isinstance(key, list): raise TypeError("key must be a list") if not isinstance(fill, list): raise TypeError("fill must be a list") p = key[0].mod F = FF(p) s = fill k = len(fill) L = [] for i in range(n): s0 = s[:] L.append(s[0]) s = s[1:k] x = sum([int(key[i]*s0[i]) for i in range(k)]) s.append(F(x)) return L # use [x.to_int() for x in L] for int version def lfsr_autocorrelation(L, P, k): """ This function computes the LFSR autocorrelation function. Parameters ========== L A periodic sequence of elements of `GF(2)`. L must have length larger than P. P The period of L. k : int An integer `k` (`0 < k < P`). Returns ======= autocorrelation The k-th value of the autocorrelation of the LFSR L. Examples ======== >>> from sympy.crypto.crypto import ( ... lfsr_sequence, lfsr_autocorrelation) >>> from sympy.polys.domains import FF >>> F = FF(2) >>> fill = [F(1), F(1), F(0), F(1)] >>> key = [F(1), F(0), F(0), F(1)] >>> s = lfsr_sequence(key, fill, 20) >>> lfsr_autocorrelation(s, 15, 7) -1/15 >>> lfsr_autocorrelation(s, 15, 0) 1 """ if not isinstance(L, list): raise TypeError("L (=%s) must be a list" % L) P = int(P) k = int(k) L0 = L[:P] # slices makes a copy L1 = L0 + L0[:k] L2 = [(-1)**(L1[i].to_int() + L1[i + k].to_int()) for i in range(P)] tot = sum(L2) return Rational(tot, P) def lfsr_connection_polynomial(s): """ This function computes the LFSR connection polynomial. Parameters ========== s A sequence of elements of even length, with entries in a finite field. Returns ======= C(x) The connection polynomial of a minimal LFSR yielding s. This implements the algorithm in section 3 of J. L. Massey's article [M]_. Examples ======== >>> from sympy.crypto.crypto import ( ... lfsr_sequence, lfsr_connection_polynomial) >>> from sympy.polys.domains import FF >>> F = FF(2) >>> fill = [F(1), F(1), F(0), F(1)] >>> key = [F(1), F(0), F(0), F(1)] >>> s = lfsr_sequence(key, fill, 20) >>> lfsr_connection_polynomial(s) x**4 + x + 1 >>> fill = [F(1), F(0), F(0), F(1)] >>> key = [F(1), F(1), F(0), F(1)] >>> s = lfsr_sequence(key, fill, 20) >>> lfsr_connection_polynomial(s) x**3 + 1 >>> fill = [F(1), F(0), F(1)] >>> key = [F(1), F(1), F(0)] >>> s = lfsr_sequence(key, fill, 20) >>> lfsr_connection_polynomial(s) x**3 + x**2 + 1 >>> fill = [F(1), F(0), F(1)] >>> key = [F(1), F(0), F(1)] >>> s = lfsr_sequence(key, fill, 20) >>> lfsr_connection_polynomial(s) x**3 + x + 1 References ========== .. [M] James L. Massey, "Shift-Register Synthesis and BCH Decoding." IEEE Trans. on Information Theory, vol. 15(1), pp. 122-127, Jan 1969. """ # Initialization: p = s[0].mod x = Symbol("x") C = 1*x**0 B = 1*x**0 m = 1 b = 1*x**0 L = 0 N = 0 while N < len(s): if L > 0: dC = Poly(C).degree() r = min(L + 1, dC + 1) coeffsC = [C.subs(x, 0)] + [C.coeff(x**i) for i in range(1, dC + 1)] d = (s[N].to_int() + sum([coeffsC[i]*s[N - i].to_int() for i in range(1, r)])) % p if L == 0: d = s[N].to_int()*x**0 if d == 0: m += 1 N += 1 if d > 0: if 2*L > N: C = (C - d*((b**(p - 2)) % p)*x**m*B).expand() m += 1 N += 1 else: T = C C = (C - d*((b**(p - 2)) % p)*x**m*B).expand() L = N + 1 - L m = 1 b = d B = T N += 1 dC = Poly(C).degree() coeffsC = [C.subs(x, 0)] + [C.coeff(x**i) for i in range(1, dC + 1)] return sum([coeffsC[i] % p*x**i for i in range(dC + 1) if coeffsC[i] is not None]) #################### ElGamal ############################# def elgamal_private_key(digit=10, seed=None): r""" Return three number tuple as private key. Explanation =========== Elgamal encryption is based on the mathmatical problem called the Discrete Logarithm Problem (DLP). For example, `a^{b} \equiv c \pmod p` In general, if ``a`` and ``b`` are known, ``ct`` is easily calculated. If ``b`` is unknown, it is hard to use ``a`` and ``ct`` to get ``b``. Parameters ========== digit : int Minimum number of binary digits for key. Returns ======= tuple : (p, r, d) p = prime number. r = primitive root. d = random number. Notes ===== For testing purposes, the ``seed`` parameter may be set to control the output of this routine. See sympy.testing.randtest._randrange. Examples ======== >>> from sympy.crypto.crypto import elgamal_private_key >>> from sympy.ntheory import is_primitive_root, isprime >>> a, b, _ = elgamal_private_key() >>> isprime(a) True >>> is_primitive_root(b, a) True """ randrange = _randrange(seed) p = nextprime(2**digit) return p, primitive_root(p), randrange(2, p) def elgamal_public_key(key): r""" Return three number tuple as public key. Parameters ========== key : (p, r, e) Tuple generated by ``elgamal_private_key``. Returns ======= tuple : (p, r, e) `e = r**d \bmod p` `d` is a random number in private key. Examples ======== >>> from sympy.crypto.crypto import elgamal_public_key >>> elgamal_public_key((1031, 14, 636)) (1031, 14, 212) """ p, r, e = key return p, r, pow(r, e, p) def encipher_elgamal(i, key, seed=None): r""" Encrypt message with public key. Explanation =========== ``i`` is a plaintext message expressed as an integer. ``key`` is public key (p, r, e). In order to encrypt a message, a random number ``a`` in ``range(2, p)`` is generated and the encryped message is returned as `c_{1}` and `c_{2}` where: `c_{1} \equiv r^{a} \pmod p` `c_{2} \equiv m e^{a} \pmod p` Parameters ========== msg int of encoded message. key Public key. Returns ======= tuple : (c1, c2) Encipher into two number. Notes ===== For testing purposes, the ``seed`` parameter may be set to control the output of this routine. See sympy.testing.randtest._randrange. Examples ======== >>> from sympy.crypto.crypto import encipher_elgamal, elgamal_private_key, elgamal_public_key >>> pri = elgamal_private_key(5, seed=[3]); pri (37, 2, 3) >>> pub = elgamal_public_key(pri); pub (37, 2, 8) >>> msg = 36 >>> encipher_elgamal(msg, pub, seed=[3]) (8, 6) """ p, r, e = key if i < 0 or i >= p: raise ValueError( 'Message (%s) should be in range(%s)' % (i, p)) randrange = _randrange(seed) a = randrange(2, p) return pow(r, a, p), i*pow(e, a, p) % p def decipher_elgamal(msg, key): r""" Decrypt message with private key. `msg = (c_{1}, c_{2})` `key = (p, r, d)` According to extended Eucliden theorem, `u c_{1}^{d} + p n = 1` `u \equiv 1/{{c_{1}}^d} \pmod p` `u c_{2} \equiv \frac{1}{c_{1}^d} c_{2} \equiv \frac{1}{r^{ad}} c_{2} \pmod p` `\frac{1}{r^{ad}} m e^a \equiv \frac{1}{r^{ad}} m {r^{d a}} \equiv m \pmod p` Examples ======== >>> from sympy.crypto.crypto import decipher_elgamal >>> from sympy.crypto.crypto import encipher_elgamal >>> from sympy.crypto.crypto import elgamal_private_key >>> from sympy.crypto.crypto import elgamal_public_key >>> pri = elgamal_private_key(5, seed=[3]) >>> pub = elgamal_public_key(pri); pub (37, 2, 8) >>> msg = 17 >>> decipher_elgamal(encipher_elgamal(msg, pub), pri) == msg True """ p, _, d = key c1, c2 = msg u = igcdex(c1**d, p)[0] return u * c2 % p ################ Diffie-Hellman Key Exchange ######################### def dh_private_key(digit=10, seed=None): r""" Return three integer tuple as private key. Explanation =========== Diffie-Hellman key exchange is based on the mathematical problem called the Discrete Logarithm Problem (see ElGamal). Diffie-Hellman key exchange is divided into the following steps: * Alice and Bob agree on a base that consist of a prime ``p`` and a primitive root of ``p`` called ``g`` * Alice choses a number ``a`` and Bob choses a number ``b`` where ``a`` and ``b`` are random numbers in range `[2, p)`. These are their private keys. * Alice then publicly sends Bob `g^{a} \pmod p` while Bob sends Alice `g^{b} \pmod p` * They both raise the received value to their secretly chosen number (``a`` or ``b``) and now have both as their shared key `g^{ab} \pmod p` Parameters ========== digit Minimum number of binary digits required in key. Returns ======= tuple : (p, g, a) p = prime number. g = primitive root of p. a = random number from 2 through p - 1. Notes ===== For testing purposes, the ``seed`` parameter may be set to control the output of this routine. See sympy.testing.randtest._randrange. Examples ======== >>> from sympy.crypto.crypto import dh_private_key >>> from sympy.ntheory import isprime, is_primitive_root >>> p, g, _ = dh_private_key() >>> isprime(p) True >>> is_primitive_root(g, p) True >>> p, g, _ = dh_private_key(5) >>> isprime(p) True >>> is_primitive_root(g, p) True """ p = nextprime(2**digit) g = primitive_root(p) randrange = _randrange(seed) a = randrange(2, p) return p, g, a def dh_public_key(key): r""" Return three number tuple as public key. This is the tuple that Alice sends to Bob. Parameters ========== key : (p, g, a) A tuple generated by ``dh_private_key``. Returns ======= tuple : int, int, int A tuple of `(p, g, g^a \mod p)` with `p`, `g` and `a` given as parameters.s Examples ======== >>> from sympy.crypto.crypto import dh_private_key, dh_public_key >>> p, g, a = dh_private_key(); >>> _p, _g, x = dh_public_key((p, g, a)) >>> p == _p and g == _g True >>> x == pow(g, a, p) True """ p, g, a = key return p, g, pow(g, a, p) def dh_shared_key(key, b): """ Return an integer that is the shared key. This is what Bob and Alice can both calculate using the public keys they received from each other and their private keys. Parameters ========== key : (p, g, x) Tuple `(p, g, x)` generated by ``dh_public_key``. b Random number in the range of `2` to `p - 1` (Chosen by second key exchange member (Bob)). Returns ======= int A shared key. Examples ======== >>> from sympy.crypto.crypto import ( ... dh_private_key, dh_public_key, dh_shared_key) >>> prk = dh_private_key(); >>> p, g, x = dh_public_key(prk); >>> sk = dh_shared_key((p, g, x), 1000) >>> sk == pow(x, 1000, p) True """ p, _, x = key if 1 >= b or b >= p: raise ValueError(filldedent(''' Value of b should be greater 1 and less than prime %s.''' % p)) return pow(x, b, p) ################ Goldwasser-Micali Encryption ######################### def _legendre(a, p): """ Returns the legendre symbol of a and p assuming that p is a prime. i.e. 1 if a is a quadratic residue mod p -1 if a is not a quadratic residue mod p 0 if a is divisible by p Parameters ========== a : int The number to test. p : prime The prime to test ``a`` against. Returns ======= int Legendre symbol (a / p). """ sig = pow(a, (p - 1)//2, p) if sig == 1: return 1 elif sig == 0: return 0 else: return -1 def _random_coprime_stream(n, seed=None): randrange = _randrange(seed) while True: y = randrange(n) if gcd(y, n) == 1: yield y def gm_private_key(p, q, a=None): """ Check if ``p`` and ``q`` can be used as private keys for the Goldwasser-Micali encryption. The method works roughly as follows. Explanation =========== $\\cdot$ Pick two large primes $p$ and $q$. $\\cdot$ Call their product $N$. $\\cdot$ Given a message as an integer $i$, write $i$ in its bit representation $b_0$ , $\\dotsc$ , $b_n$ . $\\cdot$ For each $k$ , if $b_k$ = 0: let $a_k$ be a random square (quadratic residue) modulo $p q$ such that $jacobi \\_symbol(a, p q) = 1$ if $b_k$ = 1: let $a_k$ be a random non-square (non-quadratic residue) modulo $p q$ such that $jacobi \\_ symbol(a, p q) = 1$ returns [$a_1$ , $a_2$ , $\\dotsc$ ] $b_k$ can be recovered by checking whether or not $a_k$ is a residue. And from the $b_k$ 's, the message can be reconstructed. The idea is that, while $jacobi \\_ symbol(a, p q)$ can be easily computed (and when it is equal to $-1$ will tell you that $a$ is not a square mod $p q$ ), quadratic residuosity modulo a composite number is hard to compute without knowing its factorization. Moreover, approximately half the numbers coprime to $p q$ have $jacobi \\_ symbol$ equal to $1$ . And among those, approximately half are residues and approximately half are not. This maximizes the entropy of the code. Parameters ========== p, q, a Initialization variables. Returns ======= tuple : (p, q) The input value ``p`` and ``q``. Raises ====== ValueError If ``p`` and ``q`` are not distinct odd primes. """ if p == q: raise ValueError("expected distinct primes, " "got two copies of %i" % p) elif not isprime(p) or not isprime(q): raise ValueError("first two arguments must be prime, " "got %i of %i" % (p, q)) elif p == 2 or q == 2: raise ValueError("first two arguments must not be even, " "got %i of %i" % (p, q)) return p, q def gm_public_key(p, q, a=None, seed=None): """ Compute public keys for ``p`` and ``q``. Note that in Goldwasser-Micali Encryption, public keys are randomly selected. Parameters ========== p, q, a : int, int, int Initialization variables. Returns ======= tuple : (a, N) ``a`` is the input ``a`` if it is not ``None`` otherwise some random integer coprime to ``p`` and ``q``. ``N`` is the product of ``p`` and ``q``. """ p, q = gm_private_key(p, q) N = p * q if a is None: randrange = _randrange(seed) while True: a = randrange(N) if _legendre(a, p) == _legendre(a, q) == -1: break else: if _legendre(a, p) != -1 or _legendre(a, q) != -1: return False return (a, N) def encipher_gm(i, key, seed=None): """ Encrypt integer 'i' using public_key 'key' Note that gm uses random encryption. Parameters ========== i : int The message to encrypt. key : (a, N) The public key. Returns ======= list : list of int The randomized encrypted message. """ if i < 0: raise ValueError( "message must be a non-negative " "integer: got %d instead" % i) a, N = key bits = [] while i > 0: bits.append(i % 2) i //= 2 gen = _random_coprime_stream(N, seed) rev = reversed(bits) encode = lambda b: next(gen)**2*pow(a, b) % N return [ encode(b) for b in rev ] def decipher_gm(message, key): """ Decrypt message 'message' using public_key 'key'. Parameters ========== message : list of int The randomized encrypted message. key : (p, q) The private key. Returns ======= int The encrypted message. """ p, q = key res = lambda m, p: _legendre(m, p) > 0 bits = [res(m, p) * res(m, q) for m in message] m = 0 for b in bits: m <<= 1 m += not b return m ########### RailFence Cipher ############# def encipher_railfence(message,rails): """ Performs Railfence Encryption on plaintext and returns ciphertext Examples ======== >>> from sympy.crypto.crypto import encipher_railfence >>> message = "hello world" >>> encipher_railfence(message,3) 'horel ollwd' Parameters ========== message : string, the message to encrypt. rails : int, the number of rails. Returns ======= The Encrypted string message. References ========== .. [1] https://en.wikipedia.org/wiki/Rail_fence_cipher """ r = list(range(rails)) p = cycle(r + r[-2:0:-1]) return ''.join(sorted(message, key=lambda i: next(p))) def decipher_railfence(ciphertext,rails): """ Decrypt the message using the given rails Examples ======== >>> from sympy.crypto.crypto import decipher_railfence >>> decipher_railfence("horel ollwd",3) 'hello world' Parameters ========== message : string, the message to encrypt. rails : int, the number of rails. Returns ======= The Decrypted string message. """ r = list(range(rails)) p = cycle(r + r[-2:0:-1]) idx = sorted(range(len(ciphertext)), key=lambda i: next(p)) res = [''] * len(ciphertext) for i, c in zip(idx, ciphertext): res[i] = c return ''.join(res) ################ Blum-Goldwasser cryptosystem ######################### def bg_private_key(p, q): """ Check if p and q can be used as private keys for the Blum-Goldwasser cryptosystem. Explanation =========== The three necessary checks for p and q to pass so that they can be used as private keys: 1. p and q must both be prime 2. p and q must be distinct 3. p and q must be congruent to 3 mod 4 Parameters ========== p, q The keys to be checked. Returns ======= p, q Input values. Raises ====== ValueError If p and q do not pass the above conditions. """ if not isprime(p) or not isprime(q): raise ValueError("the two arguments must be prime, " "got %i and %i" %(p, q)) elif p == q: raise ValueError("the two arguments must be distinct, " "got two copies of %i. " %p) elif (p - 3) % 4 != 0 or (q - 3) % 4 != 0: raise ValueError("the two arguments must be congruent to 3 mod 4, " "got %i and %i" %(p, q)) return p, q def bg_public_key(p, q): """ Calculates public keys from private keys. Explanation =========== The function first checks the validity of private keys passed as arguments and then returns their product. Parameters ========== p, q The private keys. Returns ======= N The public key. """ p, q = bg_private_key(p, q) N = p * q return N def encipher_bg(i, key, seed=None): """ Encrypts the message using public key and seed. Explanation =========== ALGORITHM: 1. Encodes i as a string of L bits, m. 2. Select a random element r, where 1 < r < key, and computes x = r^2 mod key. 3. Use BBS pseudo-random number generator to generate L random bits, b, using the initial seed as x. 4. Encrypted message, c_i = m_i XOR b_i, 1 <= i <= L. 5. x_L = x^(2^L) mod key. 6. Return (c, x_L) Parameters ========== i Message, a non-negative integer key The public key Returns ======= Tuple (encrypted_message, x_L) Raises ====== ValueError If i is negative. """ if i < 0: raise ValueError( "message must be a non-negative " "integer: got %d instead" % i) enc_msg = [] while i > 0: enc_msg.append(i % 2) i //= 2 enc_msg.reverse() L = len(enc_msg) r = _randint(seed)(2, key - 1) x = r**2 % key x_L = pow(int(x), int(2**L), int(key)) rand_bits = [] for _ in range(L): rand_bits.append(x % 2) x = x**2 % key encrypt_msg = [m ^ b for (m, b) in zip(enc_msg, rand_bits)] return (encrypt_msg, x_L) def decipher_bg(message, key): """ Decrypts the message using private keys. Explanation =========== ALGORITHM: 1. Let, c be the encrypted message, y the second number received, and p and q be the private keys. 2. Compute, r_p = y^((p+1)/4 ^ L) mod p and r_q = y^((q+1)/4 ^ L) mod q. 3. Compute x_0 = (q(q^-1 mod p)r_p + p(p^-1 mod q)r_q) mod N. 4. From, recompute the bits using the BBS generator, as in the encryption algorithm. 5. Compute original message by XORing c and b. Parameters ========== message Tuple of encrypted message and a non-negative integer. key Tuple of private keys. Returns ======= orig_msg The original message """ p, q = key encrypt_msg, y = message public_key = p * q L = len(encrypt_msg) p_t = ((p + 1)/4)**L q_t = ((q + 1)/4)**L r_p = pow(int(y), int(p_t), int(p)) r_q = pow(int(y), int(q_t), int(q)) x = (q * mod_inverse(q, p) * r_p + p * mod_inverse(p, q) * r_q) % public_key orig_bits = [] for _ in range(L): orig_bits.append(x % 2) x = x**2 % public_key orig_msg = 0 for (m, b) in zip(encrypt_msg, orig_bits): orig_msg = orig_msg * 2 orig_msg += (m ^ b) return orig_msg sympy-sympy-1.9/sympy/crypto/tests/000077500000000000000000000000001412543434000175665ustar00rootroot00000000000000sympy-sympy-1.9/sympy/crypto/tests/__init__.py000066400000000000000000000000001412543434000216650ustar00rootroot00000000000000sympy-sympy-1.9/sympy/crypto/tests/test_crypto.py000066400000000000000000000464501412543434000225300ustar00rootroot00000000000000from sympy.core import symbols from sympy.crypto.crypto import (cycle_list, encipher_shift, encipher_affine, encipher_substitution, check_and_join, encipher_vigenere, decipher_vigenere, encipher_hill, decipher_hill, encipher_bifid5, encipher_bifid6, bifid5_square, bifid6_square, bifid5, bifid6, decipher_bifid5, decipher_bifid6, encipher_kid_rsa, decipher_kid_rsa, kid_rsa_private_key, kid_rsa_public_key, decipher_rsa, rsa_private_key, rsa_public_key, encipher_rsa, lfsr_connection_polynomial, lfsr_autocorrelation, lfsr_sequence, encode_morse, decode_morse, elgamal_private_key, elgamal_public_key, encipher_elgamal, decipher_elgamal, dh_private_key, dh_public_key, dh_shared_key, decipher_shift, decipher_affine, encipher_bifid, decipher_bifid, bifid_square, padded_key, uniq, decipher_gm, encipher_gm, gm_public_key, gm_private_key, encipher_bg, decipher_bg, bg_private_key, bg_public_key, encipher_rot13, decipher_rot13, encipher_atbash, decipher_atbash, NonInvertibleCipherWarning, encipher_railfence, decipher_railfence) from sympy.matrices import Matrix from sympy.ntheory import isprime, is_primitive_root from sympy.polys.domains import FF from sympy.testing.pytest import raises, warns from random import randrange def test_encipher_railfence(): assert encipher_railfence("hello world",2) == "hlowrdel ol" assert encipher_railfence("hello world",3) == "horel ollwd" assert encipher_railfence("hello world",4) == "hwe olordll" def test_decipher_railfence(): assert decipher_railfence("hlowrdel ol",2) == "hello world" assert decipher_railfence("horel ollwd",3) == "hello world" assert decipher_railfence("hwe olordll",4) == "hello world" def test_cycle_list(): assert cycle_list(3, 4) == [3, 0, 1, 2] assert cycle_list(-1, 4) == [3, 0, 1, 2] assert cycle_list(1, 4) == [1, 2, 3, 0] def test_encipher_shift(): assert encipher_shift("ABC", 0) == "ABC" assert encipher_shift("ABC", 1) == "BCD" assert encipher_shift("ABC", -1) == "ZAB" assert decipher_shift("ZAB", -1) == "ABC" def test_encipher_rot13(): assert encipher_rot13("ABC") == "NOP" assert encipher_rot13("NOP") == "ABC" assert decipher_rot13("ABC") == "NOP" assert decipher_rot13("NOP") == "ABC" def test_encipher_affine(): assert encipher_affine("ABC", (1, 0)) == "ABC" assert encipher_affine("ABC", (1, 1)) == "BCD" assert encipher_affine("ABC", (-1, 0)) == "AZY" assert encipher_affine("ABC", (-1, 1), symbols="ABCD") == "BAD" assert encipher_affine("123", (-1, 1), symbols="1234") == "214" assert encipher_affine("ABC", (3, 16)) == "QTW" assert decipher_affine("QTW", (3, 16)) == "ABC" def test_encipher_atbash(): assert encipher_atbash("ABC") == "ZYX" assert encipher_atbash("ZYX") == "ABC" assert decipher_atbash("ABC") == "ZYX" assert decipher_atbash("ZYX") == "ABC" def test_encipher_substitution(): assert encipher_substitution("ABC", "BAC", "ABC") == "BAC" assert encipher_substitution("123", "1243", "1234") == "124" def test_check_and_join(): assert check_and_join("abc") == "abc" assert check_and_join(uniq("aaabc")) == "abc" assert check_and_join("ab c".split()) == "abc" assert check_and_join("abc", "a", filter=True) == "a" raises(ValueError, lambda: check_and_join('ab', 'a')) def test_encipher_vigenere(): assert encipher_vigenere("ABC", "ABC") == "ACE" assert encipher_vigenere("ABC", "ABC", symbols="ABCD") == "ACA" assert encipher_vigenere("ABC", "AB", symbols="ABCD") == "ACC" assert encipher_vigenere("AB", "ABC", symbols="ABCD") == "AC" assert encipher_vigenere("A", "ABC", symbols="ABCD") == "A" def test_decipher_vigenere(): assert decipher_vigenere("ABC", "ABC") == "AAA" assert decipher_vigenere("ABC", "ABC", symbols="ABCD") == "AAA" assert decipher_vigenere("ABC", "AB", symbols="ABCD") == "AAC" assert decipher_vigenere("AB", "ABC", symbols="ABCD") == "AA" assert decipher_vigenere("A", "ABC", symbols="ABCD") == "A" def test_encipher_hill(): A = Matrix(2, 2, [1, 2, 3, 5]) assert encipher_hill("ABCD", A) == "CFIV" A = Matrix(2, 2, [1, 0, 0, 1]) assert encipher_hill("ABCD", A) == "ABCD" assert encipher_hill("ABCD", A, symbols="ABCD") == "ABCD" A = Matrix(2, 2, [1, 2, 3, 5]) assert encipher_hill("ABCD", A, symbols="ABCD") == "CBAB" assert encipher_hill("AB", A, symbols="ABCD") == "CB" # message length, n, does not need to be a multiple of k; # it is padded assert encipher_hill("ABA", A) == "CFGC" assert encipher_hill("ABA", A, pad="Z") == "CFYV" def test_decipher_hill(): A = Matrix(2, 2, [1, 2, 3, 5]) assert decipher_hill("CFIV", A) == "ABCD" A = Matrix(2, 2, [1, 0, 0, 1]) assert decipher_hill("ABCD", A) == "ABCD" assert decipher_hill("ABCD", A, symbols="ABCD") == "ABCD" A = Matrix(2, 2, [1, 2, 3, 5]) assert decipher_hill("CBAB", A, symbols="ABCD") == "ABCD" assert decipher_hill("CB", A, symbols="ABCD") == "AB" # n does not need to be a multiple of k assert decipher_hill("CFA", A) == "ABAA" def test_encipher_bifid5(): assert encipher_bifid5("AB", "AB") == "AB" assert encipher_bifid5("AB", "CD") == "CO" assert encipher_bifid5("ab", "c") == "CH" assert encipher_bifid5("a bc", "b") == "BAC" def test_bifid5_square(): A = bifid5 f = lambda i, j: symbols(A[5*i + j]) M = Matrix(5, 5, f) assert bifid5_square("") == M def test_decipher_bifid5(): assert decipher_bifid5("AB", "AB") == "AB" assert decipher_bifid5("CO", "CD") == "AB" assert decipher_bifid5("ch", "c") == "AB" assert decipher_bifid5("b ac", "b") == "ABC" def test_encipher_bifid6(): assert encipher_bifid6("AB", "AB") == "AB" assert encipher_bifid6("AB", "CD") == "CP" assert encipher_bifid6("ab", "c") == "CI" assert encipher_bifid6("a bc", "b") == "BAC" def test_decipher_bifid6(): assert decipher_bifid6("AB", "AB") == "AB" assert decipher_bifid6("CP", "CD") == "AB" assert decipher_bifid6("ci", "c") == "AB" assert decipher_bifid6("b ac", "b") == "ABC" def test_bifid6_square(): A = bifid6 f = lambda i, j: symbols(A[6*i + j]) M = Matrix(6, 6, f) assert bifid6_square("") == M def test_rsa_public_key(): assert rsa_public_key(2, 3, 1) == (6, 1) assert rsa_public_key(5, 3, 3) == (15, 3) with warns(NonInvertibleCipherWarning): assert rsa_public_key(2, 2, 1) == (4, 1) assert rsa_public_key(8, 8, 8) is False def test_rsa_private_key(): assert rsa_private_key(2, 3, 1) == (6, 1) assert rsa_private_key(5, 3, 3) == (15, 3) assert rsa_private_key(23,29,5) == (667,493) with warns(NonInvertibleCipherWarning): assert rsa_private_key(2, 2, 1) == (4, 1) assert rsa_private_key(8, 8, 8) is False def test_rsa_large_key(): # Sample from # http://www.herongyang.com/Cryptography/JCE-Public-Key-RSA-Private-Public-Key-Pair-Sample.html p = int('101565610013301240713207239558950144682174355406589305284428666'\ '903702505233009') q = int('894687191887545488935455605955948413812376003053143521429242133'\ '12069293984003') e = int('65537') d = int('893650581832704239530398858744759129594796235440844479456143566'\ '6999402846577625762582824202269399672579058991442587406384754958587'\ '400493169361356902030209') assert rsa_public_key(p, q, e) == (p*q, e) assert rsa_private_key(p, q, e) == (p*q, d) def test_encipher_rsa(): puk = rsa_public_key(2, 3, 1) assert encipher_rsa(2, puk) == 2 puk = rsa_public_key(5, 3, 3) assert encipher_rsa(2, puk) == 8 with warns(NonInvertibleCipherWarning): puk = rsa_public_key(2, 2, 1) assert encipher_rsa(2, puk) == 2 def test_decipher_rsa(): prk = rsa_private_key(2, 3, 1) assert decipher_rsa(2, prk) == 2 prk = rsa_private_key(5, 3, 3) assert decipher_rsa(8, prk) == 2 with warns(NonInvertibleCipherWarning): prk = rsa_private_key(2, 2, 1) assert decipher_rsa(2, prk) == 2 def test_mutltiprime_rsa_full_example(): # Test example from # https://iopscience.iop.org/article/10.1088/1742-6596/995/1/012030 puk = rsa_public_key(2, 3, 5, 7, 11, 13, 7) prk = rsa_private_key(2, 3, 5, 7, 11, 13, 7) assert puk == (30030, 7) assert prk == (30030, 823) msg = 10 encrypted = encipher_rsa(2 * msg - 15, puk) assert encrypted == 18065 decrypted = (decipher_rsa(encrypted, prk) + 15) / 2 assert decrypted == msg # Test example from # https://www.scirp.org/pdf/JCC_2018032215502008.pdf puk1 = rsa_public_key(53, 41, 43, 47, 41) prk1 = rsa_private_key(53, 41, 43, 47, 41) puk2 = rsa_public_key(53, 41, 43, 47, 97) prk2 = rsa_private_key(53, 41, 43, 47, 97) assert puk1 == (4391633, 41) assert prk1 == (4391633, 294041) assert puk2 == (4391633, 97) assert prk2 == (4391633, 455713) msg = 12321 encrypted = encipher_rsa(encipher_rsa(msg, puk1), puk2) assert encrypted == 1081588 decrypted = decipher_rsa(decipher_rsa(encrypted, prk2), prk1) assert decrypted == msg def test_rsa_crt_extreme(): p = int( '10177157607154245068023861503693082120906487143725062283406501' \ '54082258226204046999838297167140821364638180697194879500245557' \ '65445186962893346463841419427008800341257468600224049986260471' \ '92257248163014468841725476918639415726709736077813632961290911' \ '0256421232977833028677441206049309220354796014376698325101693') q = int( '28752342353095132872290181526607275886182793241660805077850801' \ '75689512797754286972952273553128181861830576836289738668745250' \ '34028199691128870676414118458442900035778874482624765513861643' \ '27966696316822188398336199002306588703902894100476186823849595' \ '103239410527279605442148285816149368667083114802852804976893') r = int( '17698229259868825776879500736350186838850961935956310134378261' \ '89771862186717463067541369694816245225291921138038800171125596' \ '07315449521981157084370187887650624061033066022458512942411841' \ '18747893789972315277160085086164119879536041875335384844820566' \ '0287479617671726408053319619892052000850883994343378882717849') s = int( '68925428438585431029269182233502611027091755064643742383515623' \ '64321310582896893395529367074942808353187138794422745718419645' \ '28291231865157212604266903677599180789896916456120289112752835' \ '98502265889669730331688206825220074713977607415178738015831030' \ '364290585369150502819743827343552098197095520550865360159439' ) t = int( '69035483433453632820551311892368908779778144568711455301541094' \ '31487047642322695357696860925747923189635033183069823820910521' \ '71172909106797748883261493224162414050106920442445896819806600' \ '15448444826108008217972129130625571421904893252804729877353352' \ '739420480574842850202181462656251626522910618936534699566291' ) e = 65537 puk = rsa_public_key(p, q, r, s, t, e) prk = rsa_private_key(p, q, r, s, t, e) plaintext = 1000 ciphertext_1 = encipher_rsa(plaintext, puk) ciphertext_2 = encipher_rsa(plaintext, puk, [p, q, r, s, t]) assert ciphertext_1 == ciphertext_2 assert decipher_rsa(ciphertext_1, prk) == \ decipher_rsa(ciphertext_1, prk, [p, q, r, s, t]) def test_rsa_exhaustive(): p, q = 61, 53 e = 17 puk = rsa_public_key(p, q, e, totient='Carmichael') prk = rsa_private_key(p, q, e, totient='Carmichael') for msg in range(puk[0]): encrypted = encipher_rsa(msg, puk) decrypted = decipher_rsa(encrypted, prk) try: assert decrypted == msg except AssertionError: raise AssertionError( "The RSA is not correctly decrypted " \ "(Original : {}, Encrypted : {}, Decrypted : {})" \ .format(msg, encrypted, decrypted) ) def test_rsa_multiprime_exhanstive(): primes = [3, 5, 7, 11] e = 7 args = primes + [e] puk = rsa_public_key(*args, totient='Carmichael') prk = rsa_private_key(*args, totient='Carmichael') n = puk[0] for msg in range(n): encrypted = encipher_rsa(msg, puk) decrypted = decipher_rsa(encrypted, prk) try: assert decrypted == msg except AssertionError: raise AssertionError( "The RSA is not correctly decrypted " \ "(Original : {}, Encrypted : {}, Decrypted : {})" \ .format(msg, encrypted, decrypted) ) def test_rsa_multipower_exhanstive(): from sympy.core.numbers import igcd primes = [5, 5, 7] e = 7 args = primes + [e] puk = rsa_public_key(*args, multipower=True) prk = rsa_private_key(*args, multipower=True) n = puk[0] for msg in range(n): if igcd(msg, n) != 1: continue encrypted = encipher_rsa(msg, puk) decrypted = decipher_rsa(encrypted, prk) try: assert decrypted == msg except AssertionError: raise AssertionError( "The RSA is not correctly decrypted " \ "(Original : {}, Encrypted : {}, Decrypted : {})" \ .format(msg, encrypted, decrypted) ) def test_kid_rsa_public_key(): assert kid_rsa_public_key(1, 2, 1, 1) == (5, 2) assert kid_rsa_public_key(1, 2, 2, 1) == (8, 3) assert kid_rsa_public_key(1, 2, 1, 2) == (7, 2) def test_kid_rsa_private_key(): assert kid_rsa_private_key(1, 2, 1, 1) == (5, 3) assert kid_rsa_private_key(1, 2, 2, 1) == (8, 3) assert kid_rsa_private_key(1, 2, 1, 2) == (7, 4) def test_encipher_kid_rsa(): assert encipher_kid_rsa(1, (5, 2)) == 2 assert encipher_kid_rsa(1, (8, 3)) == 3 assert encipher_kid_rsa(1, (7, 2)) == 2 def test_decipher_kid_rsa(): assert decipher_kid_rsa(2, (5, 3)) == 1 assert decipher_kid_rsa(3, (8, 3)) == 1 assert decipher_kid_rsa(2, (7, 4)) == 1 def test_encode_morse(): assert encode_morse('ABC') == '.-|-...|-.-.' assert encode_morse('SMS ') == '...|--|...||' assert encode_morse('SMS\n') == '...|--|...||' assert encode_morse('') == '' assert encode_morse(' ') == '||' assert encode_morse(' ', sep='`') == '``' assert encode_morse(' ', sep='``') == '````' assert encode_morse('!@#$%^&*()_+') == '-.-.--|.--.-.|...-..-|-.--.|-.--.-|..--.-|.-.-.' assert encode_morse('12345') == '.----|..---|...--|....-|.....' assert encode_morse('67890') == '-....|--...|---..|----.|-----' def test_decode_morse(): assert decode_morse('-.-|.|-.--') == 'KEY' assert decode_morse('.-.|..-|-.||') == 'RUN' raises(KeyError, lambda: decode_morse('.....----')) def test_lfsr_sequence(): raises(TypeError, lambda: lfsr_sequence(1, [1], 1)) raises(TypeError, lambda: lfsr_sequence([1], 1, 1)) F = FF(2) assert lfsr_sequence([F(1)], [F(1)], 2) == [F(1), F(1)] assert lfsr_sequence([F(0)], [F(1)], 2) == [F(1), F(0)] F = FF(3) assert lfsr_sequence([F(1)], [F(1)], 2) == [F(1), F(1)] assert lfsr_sequence([F(0)], [F(2)], 2) == [F(2), F(0)] assert lfsr_sequence([F(1)], [F(2)], 2) == [F(2), F(2)] def test_lfsr_autocorrelation(): raises(TypeError, lambda: lfsr_autocorrelation(1, 2, 3)) F = FF(2) s = lfsr_sequence([F(1), F(0)], [F(0), F(1)], 5) assert lfsr_autocorrelation(s, 2, 0) == 1 assert lfsr_autocorrelation(s, 2, 1) == -1 def test_lfsr_connection_polynomial(): F = FF(2) x = symbols("x") s = lfsr_sequence([F(1), F(0)], [F(0), F(1)], 5) assert lfsr_connection_polynomial(s) == x**2 + 1 s = lfsr_sequence([F(1), F(1)], [F(0), F(1)], 5) assert lfsr_connection_polynomial(s) == x**2 + x + 1 def test_elgamal_private_key(): a, b, _ = elgamal_private_key(digit=100) assert isprime(a) assert is_primitive_root(b, a) assert len(bin(a)) >= 102 def test_elgamal(): dk = elgamal_private_key(5) ek = elgamal_public_key(dk) P = ek[0] assert P - 1 == decipher_elgamal(encipher_elgamal(P - 1, ek), dk) raises(ValueError, lambda: encipher_elgamal(P, dk)) raises(ValueError, lambda: encipher_elgamal(-1, dk)) def test_dh_private_key(): p, g, _ = dh_private_key(digit = 100) assert isprime(p) assert is_primitive_root(g, p) assert len(bin(p)) >= 102 def test_dh_public_key(): p1, g1, a = dh_private_key(digit = 100) p2, g2, ga = dh_public_key((p1, g1, a)) assert p1 == p2 assert g1 == g2 assert ga == pow(g1, a, p1) def test_dh_shared_key(): prk = dh_private_key(digit = 100) p, _, ga = dh_public_key(prk) b = randrange(2, p) sk = dh_shared_key((p, _, ga), b) assert sk == pow(ga, b, p) raises(ValueError, lambda: dh_shared_key((1031, 14, 565), 2000)) def test_padded_key(): assert padded_key('b', 'ab') == 'ba' raises(ValueError, lambda: padded_key('ab', 'ace')) raises(ValueError, lambda: padded_key('ab', 'abba')) def test_bifid(): raises(ValueError, lambda: encipher_bifid('abc', 'b', 'abcde')) assert encipher_bifid('abc', 'b', 'abcd') == 'bdb' raises(ValueError, lambda: decipher_bifid('bdb', 'b', 'abcde')) assert encipher_bifid('bdb', 'b', 'abcd') == 'abc' raises(ValueError, lambda: bifid_square('abcde')) assert bifid5_square("B") == \ bifid5_square('BACDEFGHIKLMNOPQRSTUVWXYZ') assert bifid6_square('B0') == \ bifid6_square('B0ACDEFGHIJKLMNOPQRSTUVWXYZ123456789') def test_encipher_decipher_gm(): ps = [131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199] qs = [89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 47] messages = [ 0, 32855, 34303, 14805, 1280, 75859, 38368, 724, 60356, 51675, 76697, 61854, 18661, ] for p, q in zip(ps, qs): pri = gm_private_key(p, q) for msg in messages: pub = gm_public_key(p, q) enc = encipher_gm(msg, pub) dec = decipher_gm(enc, pri) assert dec == msg def test_gm_private_key(): raises(ValueError, lambda: gm_public_key(13, 15)) raises(ValueError, lambda: gm_public_key(0, 0)) raises(ValueError, lambda: gm_public_key(0, 5)) assert 17, 19 == gm_public_key(17, 19) def test_gm_public_key(): assert 323 == gm_public_key(17, 19)[1] assert 15 == gm_public_key(3, 5)[1] raises(ValueError, lambda: gm_public_key(15, 19)) def test_encipher_decipher_bg(): ps = [67, 7, 71, 103, 11, 43, 107, 47, 79, 19, 83, 23, 59, 127, 31] qs = qs = [7, 71, 103, 11, 43, 107, 47, 79, 19, 83, 23, 59, 127, 31, 67] messages = [ 0, 328, 343, 148, 1280, 758, 383, 724, 603, 516, 766, 618, 186, ] for p, q in zip(ps, qs): pri = bg_private_key(p, q) for msg in messages: pub = bg_public_key(p, q) enc = encipher_bg(msg, pub) dec = decipher_bg(enc, pri) assert dec == msg def test_bg_private_key(): raises(ValueError, lambda: bg_private_key(8, 16)) raises(ValueError, lambda: bg_private_key(8, 8)) raises(ValueError, lambda: bg_private_key(13, 17)) assert 23, 31 == bg_private_key(23, 31) def test_bg_public_key(): assert 5293 == bg_public_key(67, 79) assert 713 == bg_public_key(23, 31) raises(ValueError, lambda: bg_private_key(13, 17)) sympy-sympy-1.9/sympy/diffgeom/000077500000000000000000000000001412543434000166645ustar00rootroot00000000000000sympy-sympy-1.9/sympy/diffgeom/__init__.py000066400000000000000000000017371412543434000210050ustar00rootroot00000000000000from .diffgeom import ( BaseCovarDerivativeOp, BaseScalarField, BaseVectorField, Commutator, contravariant_order, CoordSystem, CoordinateSymbol, CovarDerivativeOp, covariant_order, Differential, intcurve_diffequ, intcurve_series, LieDerivative, Manifold, metric_to_Christoffel_1st, metric_to_Christoffel_2nd, metric_to_Ricci_components, metric_to_Riemann_components, Patch, Point, TensorProduct, twoform_to_matrix, vectors_in_basis, WedgeProduct, ) __all__ = [ 'BaseCovarDerivativeOp', 'BaseScalarField', 'BaseVectorField', 'Commutator', 'contravariant_order', 'CoordSystem', 'CoordinateSymbol', 'CovarDerivativeOp', 'covariant_order', 'Differential', 'intcurve_diffequ', 'intcurve_series', 'LieDerivative', 'Manifold', 'metric_to_Christoffel_1st', 'metric_to_Christoffel_2nd', 'metric_to_Ricci_components', 'metric_to_Riemann_components', 'Patch', 'Point', 'TensorProduct', 'twoform_to_matrix', 'vectors_in_basis', 'WedgeProduct', ] sympy-sympy-1.9/sympy/diffgeom/diffgeom.py000066400000000000000000002134451412543434000210270ustar00rootroot00000000000000from typing import Any, Set from functools import reduce from itertools import permutations from sympy.combinatorics import Permutation from sympy.core import ( Basic, Expr, Function, diff, Pow, Mul, Add, Lambda, S, Tuple, Dict ) from sympy.core.cache import cacheit from sympy.core.symbol import Symbol, Dummy from sympy.core.symbol import Str from sympy.core.sympify import _sympify from sympy.functions import factorial from sympy.matrices import ImmutableDenseMatrix as Matrix from sympy.simplify import simplify from sympy.solvers import solve from sympy.utilities.exceptions import SymPyDeprecationWarning # TODO you are a bit excessive in the use of Dummies # TODO dummy point, literal field # TODO too often one needs to call doit or simplify on the output, check the # tests and find out why from sympy.tensor.array import ImmutableDenseNDimArray class Manifold(Basic): """ A mathematical manifold. Explanation =========== A manifold is a topological space that locally resembles Euclidean space near each point [1]. This class does not provide any means to study the topological characteristics of the manifold that it represents, though. Parameters ========== name : str The name of the manifold. dim : int The dimension of the manifold. Examples ======== >>> from sympy.diffgeom import Manifold >>> m = Manifold('M', 2) >>> m M >>> m.dim 2 References ========== .. [1] https://en.wikipedia.org/wiki/Manifold """ def __new__(cls, name, dim, **kwargs): if not isinstance(name, Str): name = Str(name) dim = _sympify(dim) obj = super().__new__(cls, name, dim) obj.patches = _deprecated_list( "Manifold.patches", "external container for registry", 19321, "1.7", [] ) return obj @property def name(self): return self.args[0] @property def dim(self): return self.args[1] class Patch(Basic): """ A patch on a manifold. Explanation =========== Coordinate patch, or patch in short, is a simply-connected open set around a point in the manifold [1]. On a manifold one can have many patches that do not always include the whole manifold. On these patches coordinate charts can be defined that permit the parameterization of any point on the patch in terms of a tuple of real numbers (the coordinates). This class does not provide any means to study the topological characteristics of the patch that it represents. Parameters ========== name : str The name of the patch. manifold : Manifold The manifold on which the patch is defined. Examples ======== >>> from sympy.diffgeom import Manifold, Patch >>> m = Manifold('M', 2) >>> p = Patch('P', m) >>> p P >>> p.dim 2 References ========== .. [1] G. Sussman, J. Wisdom, W. Farr, Functional Differential Geometry (2013) """ def __new__(cls, name, manifold, **kwargs): if not isinstance(name, Str): name = Str(name) obj = super().__new__(cls, name, manifold) obj.manifold.patches.append(obj) # deprecated obj.coord_systems = _deprecated_list( "Patch.coord_systems", "external container for registry", 19321, "1.7", [] ) return obj @property def name(self): return self.args[0] @property def manifold(self): return self.args[1] @property def dim(self): return self.manifold.dim class CoordSystem(Basic): """ A coordinate system defined on the patch. Explanation =========== Coordinate system is a system that uses one or more coordinates to uniquely determine the position of the points or other geometric elements on a manifold [1]. By passing ``Symbols`` to *symbols* parameter, user can define the name and assumptions of coordinate symbols of the coordinate system. If not passed, these symbols are generated automatically and are assumed to be real valued. By passing *relations* parameter, user can define the tranform relations of coordinate systems. Inverse transformation and indirect transformation can be found automatically. If this parameter is not passed, coordinate transformation cannot be done. Parameters ========== name : str The name of the coordinate system. patch : Patch The patch where the coordinate system is defined. symbols : list of Symbols, optional Defines the names and assumptions of coordinate symbols. relations : dict, optional Key is a tuple of two strings, who are the names of the systems where the coordinates transform from and transform to. Value is a tuple of the symbols before transformation and a tuple of the expressions after transformation. Examples ======== We define two-dimensional Cartesian coordinate system and polar coordinate system. >>> from sympy import symbols, pi, sqrt, atan2, cos, sin >>> from sympy.diffgeom import Manifold, Patch, CoordSystem >>> m = Manifold('M', 2) >>> p = Patch('P', m) >>> x, y = symbols('x y', real=True) >>> r, theta = symbols('r theta', nonnegative=True) >>> relation_dict = { ... ('Car2D', 'Pol'): [(x, y), (sqrt(x**2 + y**2), atan2(y, x))], ... ('Pol', 'Car2D'): [(r, theta), (r*cos(theta), r*sin(theta))] ... } >>> Car2D = CoordSystem('Car2D', p, (x, y), relation_dict) >>> Pol = CoordSystem('Pol', p, (r, theta), relation_dict) ``symbols`` property returns ``CoordinateSymbol`` instances. These symbols are not same with the symbols used to construct the coordinate system. >>> Car2D Car2D >>> Car2D.dim 2 >>> Car2D.symbols (x, y) >>> _[0].func ``transformation()`` method returns the transformation function from one coordinate system to another. ``transform()`` method returns the transformed coordinates. >>> Car2D.transformation(Pol) Lambda((x, y), Matrix([ [sqrt(x**2 + y**2)], [ atan2(y, x)]])) >>> Car2D.transform(Pol) Matrix([ [sqrt(x**2 + y**2)], [ atan2(y, x)]]) >>> Car2D.transform(Pol, [1, 2]) Matrix([ [sqrt(5)], [atan(2)]]) ``jacobian()`` method returns the Jacobian matrix of coordinate transformation between two systems. ``jacobian_determinant()`` method returns the Jacobian determinant of coordinate transformation between two systems. >>> Pol.jacobian(Car2D) Matrix([ [cos(theta), -r*sin(theta)], [sin(theta), r*cos(theta)]]) >>> Pol.jacobian(Car2D, [1, pi/2]) Matrix([ [0, -1], [1, 0]]) >>> Car2D.jacobian_determinant(Pol) 1/sqrt(x**2 + y**2) >>> Car2D.jacobian_determinant(Pol, [1,0]) 1 References ========== .. [1] https://en.wikipedia.org/wiki/Coordinate_system """ def __new__(cls, name, patch, symbols=None, relations={}, **kwargs): if not isinstance(name, Str): name = Str(name) # canonicallize the symbols if symbols is None: names = kwargs.get('names', None) if names is None: symbols = Tuple( *[Symbol('%s_%s' % (name.name, i), real=True) for i in range(patch.dim)] ) else: SymPyDeprecationWarning( feature="Class signature 'names' of CoordSystem", useinstead="class signature 'symbols'", issue=19321, deprecated_since_version="1.7" ).warn() symbols = Tuple( *[Symbol(n, real=True) for n in names] ) else: syms = [] for s in symbols: if isinstance(s, Symbol): syms.append(Symbol(s.name, **s._assumptions.generator)) elif isinstance(s, str): SymPyDeprecationWarning( feature="Passing str as coordinate symbol's name", useinstead="Symbol which contains the name and assumption for coordinate symbol", issue=19321, deprecated_since_version="1.7" ).warn() syms.append(Symbol(s, real=True)) symbols = Tuple(*syms) # canonicallize the relations rel_temp = {} for k,v in relations.items(): s1, s2 = k if not isinstance(s1, Str): s1 = Str(s1) if not isinstance(s2, Str): s2 = Str(s2) key = Tuple(s1, s2) # Old version used Lambda as a value. if isinstance(v, Lambda): v = (tuple(v.signature), tuple(v.expr)) else: v = (tuple(v[0]), tuple(v[1])) rel_temp[key] = v relations = Dict(rel_temp) # construct the object obj = super().__new__(cls, name, patch, symbols, relations) # Add deprecated attributes obj.transforms = _deprecated_dict( "Mutable CoordSystem.transforms", "'relations' parameter in class signature", 19321, "1.7", {} ) obj._names = [str(n) for n in symbols] obj.patch.coord_systems.append(obj) # deprecated obj._dummies = [Dummy(str(n)) for n in symbols] # deprecated obj._dummy = Dummy() return obj @property def name(self): return self.args[0] @property def patch(self): return self.args[1] @property def manifold(self): return self.patch.manifold @property def symbols(self): return tuple(CoordinateSymbol(self, i, **s._assumptions.generator) for i,s in enumerate(self.args[2])) @property def relations(self): return self.args[3] @property def dim(self): return self.patch.dim ########################################################################## # Finding transformation relation ########################################################################## def transformation(self, sys): """ Return coordinate transformation function from *self* to *sys*. Parameters ========== sys : CoordSystem Returns ======= sympy.Lambda Examples ======== >>> from sympy.diffgeom.rn import R2_r, R2_p >>> R2_r.transformation(R2_p) Lambda((x, y), Matrix([ [sqrt(x**2 + y**2)], [ atan2(y, x)]])) """ signature = self.args[2] key = Tuple(self.name, sys.name) if self == sys: expr = Matrix(self.symbols) elif key in self.relations: expr = Matrix(self.relations[key][1]) elif key[::-1] in self.relations: expr = Matrix(self._inverse_transformation(sys, self)) else: expr = Matrix(self._indirect_transformation(self, sys)) return Lambda(signature, expr) @staticmethod def _solve_inverse(sym1, sym2, exprs, sys1_name, sys2_name): ret = solve( [t[0] - t[1] for t in zip(sym2, exprs)], list(sym1), dict=True) if len(ret) == 0: temp = "Cannot solve inverse relation from {} to {}." raise NotImplementedError(temp.format(sys1_name, sys2_name)) elif len(ret) > 1: temp = "Obtained multiple inverse relation from {} to {}." raise ValueError(temp.format(sys1_name, sys2_name)) return ret[0] @classmethod def _inverse_transformation(cls, sys1, sys2): # Find the transformation relation from sys2 to sys1 forward = sys1.transform(sys2) inv_results = cls._solve_inverse(sys1.symbols, sys2.symbols, forward, sys1.name, sys2.name) signature = tuple(sys1.symbols) return [inv_results[s] for s in signature] @classmethod @cacheit def _indirect_transformation(cls, sys1, sys2): # Find the transformation relation between two indirectly connected # coordinate systems rel = sys1.relations path = cls._dijkstra(sys1, sys2) transforms = [] for s1, s2 in zip(path, path[1:]): if (s1, s2) in rel: transforms.append(rel[(s1, s2)]) else: sym2, inv_exprs = rel[(s2, s1)] sym1 = tuple(Dummy() for i in sym2) ret = cls._solve_inverse(sym2, sym1, inv_exprs, s2, s1) ret = tuple(ret[s] for s in sym2) transforms.append((sym1, ret)) syms = sys1.args[2] exprs = syms for newsyms, newexprs in transforms: exprs = tuple(e.subs(zip(newsyms, exprs)) for e in newexprs) return exprs @staticmethod def _dijkstra(sys1, sys2): # Use Dijkstra algorithm to find the shortest path between two indirectly-connected # coordinate systems # return value is the list of the names of the systems. relations = sys1.relations graph = {} for s1, s2 in relations.keys(): if s1 not in graph: graph[s1] = {s2} else: graph[s1].add(s2) if s2 not in graph: graph[s2] = {s1} else: graph[s2].add(s1) path_dict = {sys:[0, [], 0] for sys in graph} # minimum distance, path, times of visited def visit(sys): path_dict[sys][2] = 1 for newsys in graph[sys]: distance = path_dict[sys][0] + 1 if path_dict[newsys][0] >= distance or not path_dict[newsys][1]: path_dict[newsys][0] = distance path_dict[newsys][1] = [i for i in path_dict[sys][1]] path_dict[newsys][1].append(sys) visit(sys1.name) while True: min_distance = max(path_dict.values(), key=lambda x:x[0])[0] newsys = None for sys, lst in path_dict.items(): if 0 < lst[0] <= min_distance and not lst[2]: min_distance = lst[0] newsys = sys if newsys is None: break visit(newsys) result = path_dict[sys2.name][1] result.append(sys2.name) if result == [sys2.name]: raise KeyError("Two coordinate systems are not connected.") return result def connect_to(self, to_sys, from_coords, to_exprs, inverse=True, fill_in_gaps=False): SymPyDeprecationWarning( feature="CoordSystem.connect_to", useinstead="new instance generated with new 'transforms' parameter", issue=19321, deprecated_since_version="1.7" ).warn() from_coords, to_exprs = dummyfy(from_coords, to_exprs) self.transforms[to_sys] = Matrix(from_coords), Matrix(to_exprs) if inverse: to_sys.transforms[self] = self._inv_transf(from_coords, to_exprs) if fill_in_gaps: self._fill_gaps_in_transformations() @staticmethod def _inv_transf(from_coords, to_exprs): # Will be removed when connect_to is removed inv_from = [i.as_dummy() for i in from_coords] inv_to = solve( [t[0] - t[1] for t in zip(inv_from, to_exprs)], list(from_coords), dict=True)[0] inv_to = [inv_to[fc] for fc in from_coords] return Matrix(inv_from), Matrix(inv_to) @staticmethod def _fill_gaps_in_transformations(): # Will be removed when connect_to is removed raise NotImplementedError ########################################################################## # Coordinate transformations ########################################################################## def transform(self, sys, coordinates=None): """ Return the result of coordinate transformation from *self* to *sys*. If coordinates are not given, coordinate symbols of *self* are used. Parameters ========== sys : CoordSystem coordinates : Any iterable, optional. Returns ======= sympy.ImmutableDenseMatrix containing CoordinateSymbol Examples ======== >>> from sympy.diffgeom.rn import R2_r, R2_p >>> R2_r.transform(R2_p) Matrix([ [sqrt(x**2 + y**2)], [ atan2(y, x)]]) >>> R2_r.transform(R2_p, [0, 1]) Matrix([ [ 1], [pi/2]]) """ if coordinates is None: coordinates = self.symbols if self != sys: transf = self.transformation(sys) coordinates = transf(*coordinates) else: coordinates = Matrix(coordinates) return coordinates def coord_tuple_transform_to(self, to_sys, coords): """Transform ``coords`` to coord system ``to_sys``.""" SymPyDeprecationWarning( feature="CoordSystem.coord_tuple_transform_to", useinstead="CoordSystem.transform", issue=19321, deprecated_since_version="1.7" ).warn() coords = Matrix(coords) if self != to_sys: transf = self.transforms[to_sys] coords = transf[1].subs(list(zip(transf[0], coords))) return coords def jacobian(self, sys, coordinates=None): """ Return the jacobian matrix of a transformation on given coordinates. If coordinates are not given, coordinate symbols of *self* are used. Parameters ========== sys : CoordSystem coordinates : Any iterable, optional. Returns ======= sympy.ImmutableDenseMatrix Examples ======== >>> from sympy.diffgeom.rn import R2_r, R2_p >>> R2_p.jacobian(R2_r) Matrix([ [cos(theta), -rho*sin(theta)], [sin(theta), rho*cos(theta)]]) >>> R2_p.jacobian(R2_r, [1, 0]) Matrix([ [1, 0], [0, 1]]) """ result = self.transform(sys).jacobian(self.symbols) if coordinates is not None: result = result.subs(list(zip(self.symbols, coordinates))) return result jacobian_matrix = jacobian def jacobian_determinant(self, sys, coordinates=None): """ Return the jacobian determinant of a transformation on given coordinates. If coordinates are not given, coordinate symbols of *self* are used. Parameters ========== sys : CoordSystem coordinates : Any iterable, optional. Returns ======= sympy.Expr Examples ======== >>> from sympy.diffgeom.rn import R2_r, R2_p >>> R2_r.jacobian_determinant(R2_p) 1/sqrt(x**2 + y**2) >>> R2_r.jacobian_determinant(R2_p, [1, 0]) 1 """ return self.jacobian(sys, coordinates).det() ########################################################################## # Points ########################################################################## def point(self, coords): """Create a ``Point`` with coordinates given in this coord system.""" return Point(self, coords) def point_to_coords(self, point): """Calculate the coordinates of a point in this coord system.""" return point.coords(self) ########################################################################## # Base fields. ########################################################################## def base_scalar(self, coord_index): """Return ``BaseScalarField`` that takes a point and returns one of the coordinates.""" return BaseScalarField(self, coord_index) coord_function = base_scalar def base_scalars(self): """Returns a list of all coordinate functions. For more details see the ``base_scalar`` method of this class.""" return [self.base_scalar(i) for i in range(self.dim)] coord_functions = base_scalars def base_vector(self, coord_index): """Return a basis vector field. The basis vector field for this coordinate system. It is also an operator on scalar fields.""" return BaseVectorField(self, coord_index) def base_vectors(self): """Returns a list of all base vectors. For more details see the ``base_vector`` method of this class.""" return [self.base_vector(i) for i in range(self.dim)] def base_oneform(self, coord_index): """Return a basis 1-form field. The basis one-form field for this coordinate system. It is also an operator on vector fields.""" return Differential(self.coord_function(coord_index)) def base_oneforms(self): """Returns a list of all base oneforms. For more details see the ``base_oneform`` method of this class.""" return [self.base_oneform(i) for i in range(self.dim)] class CoordinateSymbol(Symbol): """A symbol which denotes an abstract value of i-th coordinate of the coordinate system with given context. Explanation =========== Each coordinates in coordinate system are represented by unique symbol, such as x, y, z in Cartesian coordinate system. You may not construct this class directly. Instead, use `symbols` method of CoordSystem. Parameters ========== coord_sys : CoordSystem index : integer Examples ======== >>> from sympy import symbols, Lambda, Matrix, sqrt, atan2, cos, sin >>> from sympy.diffgeom import Manifold, Patch, CoordSystem >>> m = Manifold('M', 2) >>> p = Patch('P', m) >>> x, y = symbols('x y', real=True) >>> r, theta = symbols('r theta', nonnegative=True) >>> relation_dict = { ... ('Car2D', 'Pol'): Lambda((x, y), Matrix([sqrt(x**2 + y**2), atan2(y, x)])), ... ('Pol', 'Car2D'): Lambda((r, theta), Matrix([r*cos(theta), r*sin(theta)])) ... } >>> Car2D = CoordSystem('Car2D', p, [x, y], relation_dict) >>> Pol = CoordSystem('Pol', p, [r, theta], relation_dict) >>> x, y = Car2D.symbols ``CoordinateSymbol`` contains its coordinate symbol and index. >>> x.name 'x' >>> x.coord_sys == Car2D True >>> x.index 0 >>> x.is_real True You can transform ``CoordinateSymbol`` into other coordinate system using ``rewrite()`` method. >>> x.rewrite(Pol) r*cos(theta) >>> sqrt(x**2 + y**2).rewrite(Pol).simplify() r """ def __new__(cls, coord_sys, index, **assumptions): name = coord_sys.args[2][index].name obj = super().__new__(cls, name, **assumptions) obj.coord_sys = coord_sys obj.index = index return obj def __getnewargs__(self): return (self.coord_sys, self.index) def _hashable_content(self): return ( self.coord_sys, self.index ) + tuple(sorted(self.assumptions0.items())) def _eval_rewrite(self, rule, args, **hints): if isinstance(rule, CoordSystem): return rule.transform(self.coord_sys)[self.index] return super()._eval_rewrite(rule, args, **hints) class Point(Basic): """Point defined in a coordinate system. Explanation =========== Mathematically, point is defined in the manifold and does not have any coordinates by itself. Coordinate system is what imbues the coordinates to the point by coordinate chart. However, due to the difficulty of realizing such logic, you must supply a coordinate system and coordinates to define a Point here. The usage of this object after its definition is independent of the coordinate system that was used in order to define it, however due to limitations in the simplification routines you can arrive at complicated expressions if you use inappropriate coordinate systems. Parameters ========== coord_sys : CoordSystem coords : list The coordinates of the point. Examples ======== >>> from sympy import pi >>> from sympy.diffgeom import Point >>> from sympy.diffgeom.rn import R2, R2_r, R2_p >>> rho, theta = R2_p.symbols >>> p = Point(R2_p, [rho, 3*pi/4]) >>> p.manifold == R2 True >>> p.coords() Matrix([ [ rho], [3*pi/4]]) >>> p.coords(R2_r) Matrix([ [-sqrt(2)*rho/2], [ sqrt(2)*rho/2]]) """ def __new__(cls, coord_sys, coords, **kwargs): coords = Matrix(coords) obj = super().__new__(cls, coord_sys, coords) obj._coord_sys = coord_sys obj._coords = coords return obj @property def patch(self): return self._coord_sys.patch @property def manifold(self): return self._coord_sys.manifold @property def dim(self): return self.manifold.dim def coords(self, sys=None): """ Coordinates of the point in given coordinate system. If coordinate system is not passed, it returns the coordinates in the coordinate system in which the poin was defined. """ if sys is None: return self._coords else: return self._coord_sys.transform(sys, self._coords) @property def free_symbols(self): return self._coords.free_symbols class BaseScalarField(Expr): """Base scalar field over a manifold for a given coordinate system. Explanation =========== A scalar field takes a point as an argument and returns a scalar. A base scalar field of a coordinate system takes a point and returns one of the coordinates of that point in the coordinate system in question. To define a scalar field you need to choose the coordinate system and the index of the coordinate. The use of the scalar field after its definition is independent of the coordinate system in which it was defined, however due to limitations in the simplification routines you may arrive at more complicated expression if you use unappropriate coordinate systems. You can build complicated scalar fields by just building up SymPy expressions containing ``BaseScalarField`` instances. Parameters ========== coord_sys : CoordSystem index : integer Examples ======== >>> from sympy import Function, pi >>> from sympy.diffgeom import BaseScalarField >>> from sympy.diffgeom.rn import R2_r, R2_p >>> rho, _ = R2_p.symbols >>> point = R2_p.point([rho, 0]) >>> fx, fy = R2_r.base_scalars() >>> ftheta = BaseScalarField(R2_r, 1) >>> fx(point) rho >>> fy(point) 0 >>> (fx**2+fy**2).rcall(point) rho**2 >>> g = Function('g') >>> fg = g(ftheta-pi) >>> fg.rcall(point) g(-pi) """ is_commutative = True def __new__(cls, coord_sys, index, **kwargs): index = _sympify(index) obj = super().__new__(cls, coord_sys, index) obj._coord_sys = coord_sys obj._index = index return obj @property def coord_sys(self): return self.args[0] @property def index(self): return self.args[1] @property def patch(self): return self.coord_sys.patch @property def manifold(self): return self.coord_sys.manifold @property def dim(self): return self.manifold.dim def __call__(self, *args): """Evaluating the field at a point or doing nothing. If the argument is a ``Point`` instance, the field is evaluated at that point. The field is returned itself if the argument is any other object. It is so in order to have working recursive calling mechanics for all fields (check the ``__call__`` method of ``Expr``). """ point = args[0] if len(args) != 1 or not isinstance(point, Point): return self coords = point.coords(self._coord_sys) # XXX Calling doit is necessary with all the Subs expressions # XXX Calling simplify is necessary with all the trig expressions return simplify(coords[self._index]).doit() # XXX Workaround for limitations on the content of args free_symbols = set() # type: Set[Any] def doit(self): return self class BaseVectorField(Expr): r"""Base vector field over a manifold for a given coordinate system. Explanation =========== A vector field is an operator taking a scalar field and returning a directional derivative (which is also a scalar field). A base vector field is the same type of operator, however the derivation is specifically done with respect to a chosen coordinate. To define a base vector field you need to choose the coordinate system and the index of the coordinate. The use of the vector field after its definition is independent of the coordinate system in which it was defined, however due to limitations in the simplification routines you may arrive at more complicated expression if you use unappropriate coordinate systems. Parameters ========== coord_sys : CoordSystem index : integer Examples ======== >>> from sympy import Function >>> from sympy.diffgeom.rn import R2_p, R2_r >>> from sympy.diffgeom import BaseVectorField >>> from sympy import pprint >>> x, y = R2_r.symbols >>> rho, theta = R2_p.symbols >>> fx, fy = R2_r.base_scalars() >>> point_p = R2_p.point([rho, theta]) >>> point_r = R2_r.point([x, y]) >>> g = Function('g') >>> s_field = g(fx, fy) >>> v = BaseVectorField(R2_r, 1) >>> pprint(v(s_field)) / d \| |---(g(x, xi))|| \dxi /|xi=y >>> pprint(v(s_field).rcall(point_r).doit()) d --(g(x, y)) dy >>> pprint(v(s_field).rcall(point_p)) / d \| |---(g(rho*cos(theta), xi))|| \dxi /|xi=rho*sin(theta) """ is_commutative = False def __new__(cls, coord_sys, index, **kwargs): index = _sympify(index) obj = super().__new__(cls, coord_sys, index) obj._coord_sys = coord_sys obj._index = index return obj @property def coord_sys(self): return self.args[0] @property def index(self): return self.args[1] @property def patch(self): return self.coord_sys.patch @property def manifold(self): return self.coord_sys.manifold @property def dim(self): return self.manifold.dim def __call__(self, scalar_field): """Apply on a scalar field. The action of a vector field on a scalar field is a directional differentiation. If the argument is not a scalar field an error is raised. """ if covariant_order(scalar_field) or contravariant_order(scalar_field): raise ValueError('Only scalar fields can be supplied as arguments to vector fields.') if scalar_field is None: return self base_scalars = list(scalar_field.atoms(BaseScalarField)) # First step: e_x(x+r**2) -> e_x(x) + 2*r*e_x(r) d_var = self._coord_sys._dummy # TODO: you need a real dummy function for the next line d_funcs = [Function('_#_%s' % i)(d_var) for i, b in enumerate(base_scalars)] d_result = scalar_field.subs(list(zip(base_scalars, d_funcs))) d_result = d_result.diff(d_var) # Second step: e_x(x) -> 1 and e_x(r) -> cos(atan2(x, y)) coords = self._coord_sys.symbols d_funcs_deriv = [f.diff(d_var) for f in d_funcs] d_funcs_deriv_sub = [] for b in base_scalars: jac = self._coord_sys.jacobian(b._coord_sys, coords) d_funcs_deriv_sub.append(jac[b._index, self._index]) d_result = d_result.subs(list(zip(d_funcs_deriv, d_funcs_deriv_sub))) # Remove the dummies result = d_result.subs(list(zip(d_funcs, base_scalars))) result = result.subs(list(zip(coords, self._coord_sys.coord_functions()))) return result.doit() def _find_coords(expr): # Finds CoordinateSystems existing in expr fields = expr.atoms(BaseScalarField, BaseVectorField) result = set() for f in fields: result.add(f._coord_sys) return result class Commutator(Expr): r"""Commutator of two vector fields. Explanation =========== The commutator of two vector fields `v_1` and `v_2` is defined as the vector field `[v_1, v_2]` that evaluated on each scalar field `f` is equal to `v_1(v_2(f)) - v_2(v_1(f))`. Examples ======== >>> from sympy.diffgeom.rn import R2_p, R2_r >>> from sympy.diffgeom import Commutator >>> from sympy.simplify import simplify >>> fx, fy = R2_r.base_scalars() >>> e_x, e_y = R2_r.base_vectors() >>> e_r = R2_p.base_vector(0) >>> c_xy = Commutator(e_x, e_y) >>> c_xr = Commutator(e_x, e_r) >>> c_xy 0 Unfortunately, the current code is not able to compute everything: >>> c_xr Commutator(e_x, e_rho) >>> simplify(c_xr(fy**2)) -2*cos(theta)*y**2/(x**2 + y**2) """ def __new__(cls, v1, v2): if (covariant_order(v1) or contravariant_order(v1) != 1 or covariant_order(v2) or contravariant_order(v2) != 1): raise ValueError( 'Only commutators of vector fields are supported.') if v1 == v2: return S.Zero coord_sys = set().union(*[_find_coords(v) for v in (v1, v2)]) if len(coord_sys) == 1: # Only one coordinate systems is used, hence it is easy enough to # actually evaluate the commutator. if all(isinstance(v, BaseVectorField) for v in (v1, v2)): return S.Zero bases_1, bases_2 = [list(v.atoms(BaseVectorField)) for v in (v1, v2)] coeffs_1 = [v1.expand().coeff(b) for b in bases_1] coeffs_2 = [v2.expand().coeff(b) for b in bases_2] res = 0 for c1, b1 in zip(coeffs_1, bases_1): for c2, b2 in zip(coeffs_2, bases_2): res += c1*b1(c2)*b2 - c2*b2(c1)*b1 return res else: obj = super().__new__(cls, v1, v2) obj._v1 = v1 # deprecated assignment obj._v2 = v2 # deprecated assignment return obj @property def v1(self): return self.args[0] @property def v2(self): return self.args[1] def __call__(self, scalar_field): """Apply on a scalar field. If the argument is not a scalar field an error is raised. """ return self.v1(self.v2(scalar_field)) - self.v2(self.v1(scalar_field)) class Differential(Expr): r"""Return the differential (exterior derivative) of a form field. Explanation =========== The differential of a form (i.e. the exterior derivative) has a complicated definition in the general case. The differential `df` of the 0-form `f` is defined for any vector field `v` as `df(v) = v(f)`. Examples ======== >>> from sympy import Function >>> from sympy.diffgeom.rn import R2_r >>> from sympy.diffgeom import Differential >>> from sympy import pprint >>> fx, fy = R2_r.base_scalars() >>> e_x, e_y = R2_r.base_vectors() >>> g = Function('g') >>> s_field = g(fx, fy) >>> dg = Differential(s_field) >>> dg d(g(x, y)) >>> pprint(dg(e_x)) / d \| |---(g(xi, y))|| \dxi /|xi=x >>> pprint(dg(e_y)) / d \| |---(g(x, xi))|| \dxi /|xi=y Applying the exterior derivative operator twice always results in: >>> Differential(dg) 0 """ is_commutative = False def __new__(cls, form_field): if contravariant_order(form_field): raise ValueError( 'A vector field was supplied as an argument to Differential.') if isinstance(form_field, Differential): return S.Zero else: obj = super().__new__(cls, form_field) obj._form_field = form_field # deprecated assignment return obj @property def form_field(self): return self.args[0] def __call__(self, *vector_fields): """Apply on a list of vector_fields. Explanation =========== If the number of vector fields supplied is not equal to 1 + the order of the form field inside the differential the result is undefined. For 1-forms (i.e. differentials of scalar fields) the evaluation is done as `df(v)=v(f)`. However if `v` is ``None`` instead of a vector field, the differential is returned unchanged. This is done in order to permit partial contractions for higher forms. In the general case the evaluation is done by applying the form field inside the differential on a list with one less elements than the number of elements in the original list. Lowering the number of vector fields is achieved through replacing each pair of fields by their commutator. If the arguments are not vectors or ``None``s an error is raised. """ if any((contravariant_order(a) != 1 or covariant_order(a)) and a is not None for a in vector_fields): raise ValueError('The arguments supplied to Differential should be vector fields or Nones.') k = len(vector_fields) if k == 1: if vector_fields[0]: return vector_fields[0].rcall(self._form_field) return self else: # For higher form it is more complicated: # Invariant formula: # https://en.wikipedia.org/wiki/Exterior_derivative#Invariant_formula # df(v1, ... vn) = +/- vi(f(v1..no i..vn)) # +/- f([vi,vj],v1..no i, no j..vn) f = self._form_field v = vector_fields ret = 0 for i in range(k): t = v[i].rcall(f.rcall(*v[:i] + v[i + 1:])) ret += (-1)**i*t for j in range(i + 1, k): c = Commutator(v[i], v[j]) if c: # TODO this is ugly - the Commutator can be Zero and # this causes the next line to fail t = f.rcall(*(c,) + v[:i] + v[i + 1:j] + v[j + 1:]) ret += (-1)**(i + j)*t return ret class TensorProduct(Expr): """Tensor product of forms. Explanation =========== The tensor product permits the creation of multilinear functionals (i.e. higher order tensors) out of lower order fields (e.g. 1-forms and vector fields). However, the higher tensors thus created lack the interesting features provided by the other type of product, the wedge product, namely they are not antisymmetric and hence are not form fields. Examples ======== >>> from sympy.diffgeom.rn import R2_r >>> from sympy.diffgeom import TensorProduct >>> fx, fy = R2_r.base_scalars() >>> e_x, e_y = R2_r.base_vectors() >>> dx, dy = R2_r.base_oneforms() >>> TensorProduct(dx, dy)(e_x, e_y) 1 >>> TensorProduct(dx, dy)(e_y, e_x) 0 >>> TensorProduct(dx, fx*dy)(fx*e_x, e_y) x**2 >>> TensorProduct(e_x, e_y)(fx**2, fy**2) 4*x*y >>> TensorProduct(e_y, dx)(fy) dx You can nest tensor products. >>> tp1 = TensorProduct(dx, dy) >>> TensorProduct(tp1, dx)(e_x, e_y, e_x) 1 You can make partial contraction for instance when 'raising an index'. Putting ``None`` in the second argument of ``rcall`` means that the respective position in the tensor product is left as it is. >>> TP = TensorProduct >>> metric = TP(dx, dx) + 3*TP(dy, dy) >>> metric.rcall(e_y, None) 3*dy Or automatically pad the args with ``None`` without specifying them. >>> metric.rcall(e_y) 3*dy """ def __new__(cls, *args): scalar = Mul(*[m for m in args if covariant_order(m) + contravariant_order(m) == 0]) multifields = [m for m in args if covariant_order(m) + contravariant_order(m)] if multifields: if len(multifields) == 1: return scalar*multifields[0] return scalar*super().__new__(cls, *multifields) else: return scalar def __call__(self, *fields): """Apply on a list of fields. If the number of input fields supplied is not equal to the order of the tensor product field, the list of arguments is padded with ``None``'s. The list of arguments is divided in sublists depending on the order of the forms inside the tensor product. The sublists are provided as arguments to these forms and the resulting expressions are given to the constructor of ``TensorProduct``. """ tot_order = covariant_order(self) + contravariant_order(self) tot_args = len(fields) if tot_args != tot_order: fields = list(fields) + [None]*(tot_order - tot_args) orders = [covariant_order(f) + contravariant_order(f) for f in self._args] indices = [sum(orders[:i + 1]) for i in range(len(orders) - 1)] fields = [fields[i:j] for i, j in zip([0] + indices, indices + [None])] multipliers = [t[0].rcall(*t[1]) for t in zip(self._args, fields)] return TensorProduct(*multipliers) class WedgeProduct(TensorProduct): """Wedge product of forms. Explanation =========== In the context of integration only completely antisymmetric forms make sense. The wedge product permits the creation of such forms. Examples ======== >>> from sympy.diffgeom.rn import R2_r >>> from sympy.diffgeom import WedgeProduct >>> fx, fy = R2_r.base_scalars() >>> e_x, e_y = R2_r.base_vectors() >>> dx, dy = R2_r.base_oneforms() >>> WedgeProduct(dx, dy)(e_x, e_y) 1 >>> WedgeProduct(dx, dy)(e_y, e_x) -1 >>> WedgeProduct(dx, fx*dy)(fx*e_x, e_y) x**2 >>> WedgeProduct(e_x, e_y)(fy, None) -e_x You can nest wedge products. >>> wp1 = WedgeProduct(dx, dy) >>> WedgeProduct(wp1, dx)(e_x, e_y, e_x) 0 """ # TODO the calculation of signatures is slow # TODO you do not need all these permutations (neither the prefactor) def __call__(self, *fields): """Apply on a list of vector_fields. The expression is rewritten internally in terms of tensor products and evaluated.""" orders = (covariant_order(e) + contravariant_order(e) for e in self.args) mul = 1/Mul(*(factorial(o) for o in orders)) perms = permutations(fields) perms_par = (Permutation( p).signature() for p in permutations(list(range(len(fields))))) tensor_prod = TensorProduct(*self.args) return mul*Add(*[tensor_prod(*p[0])*p[1] for p in zip(perms, perms_par)]) class LieDerivative(Expr): """Lie derivative with respect to a vector field. Explanation =========== The transport operator that defines the Lie derivative is the pushforward of the field to be derived along the integral curve of the field with respect to which one derives. Examples ======== >>> from sympy.diffgeom.rn import R2_r, R2_p >>> from sympy.diffgeom import (LieDerivative, TensorProduct) >>> fx, fy = R2_r.base_scalars() >>> e_x, e_y = R2_r.base_vectors() >>> e_rho, e_theta = R2_p.base_vectors() >>> dx, dy = R2_r.base_oneforms() >>> LieDerivative(e_x, fy) 0 >>> LieDerivative(e_x, fx) 1 >>> LieDerivative(e_x, e_x) 0 The Lie derivative of a tensor field by another tensor field is equal to their commutator: >>> LieDerivative(e_x, e_rho) Commutator(e_x, e_rho) >>> LieDerivative(e_x + e_y, fx) 1 >>> tp = TensorProduct(dx, dy) >>> LieDerivative(e_x, tp) LieDerivative(e_x, TensorProduct(dx, dy)) >>> LieDerivative(e_x, tp) LieDerivative(e_x, TensorProduct(dx, dy)) """ def __new__(cls, v_field, expr): expr_form_ord = covariant_order(expr) if contravariant_order(v_field) != 1 or covariant_order(v_field): raise ValueError('Lie derivatives are defined only with respect to' ' vector fields. The supplied argument was not a ' 'vector field.') if expr_form_ord > 0: obj = super().__new__(cls, v_field, expr) # deprecated assignments obj._v_field = v_field obj._expr = expr return obj if expr.atoms(BaseVectorField): return Commutator(v_field, expr) else: return v_field.rcall(expr) @property def v_field(self): return self.args[0] @property def expr(self): return self.args[1] def __call__(self, *args): v = self.v_field expr = self.expr lead_term = v(expr(*args)) rest = Add(*[Mul(*args[:i] + (Commutator(v, args[i]),) + args[i + 1:]) for i in range(len(args))]) return lead_term - rest class BaseCovarDerivativeOp(Expr): """Covariant derivative operator with respect to a base vector. Examples ======== >>> from sympy.diffgeom.rn import R2_r >>> from sympy.diffgeom import BaseCovarDerivativeOp >>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct >>> TP = TensorProduct >>> fx, fy = R2_r.base_scalars() >>> e_x, e_y = R2_r.base_vectors() >>> dx, dy = R2_r.base_oneforms() >>> ch = metric_to_Christoffel_2nd(TP(dx, dx) + TP(dy, dy)) >>> ch [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] >>> cvd = BaseCovarDerivativeOp(R2_r, 0, ch) >>> cvd(fx) 1 >>> cvd(fx*e_x) e_x """ def __new__(cls, coord_sys, index, christoffel): index = _sympify(index) christoffel = ImmutableDenseNDimArray(christoffel) obj = super().__new__(cls, coord_sys, index, christoffel) # deprecated assignments obj._coord_sys = coord_sys obj._index = index obj._christoffel = christoffel return obj @property def coord_sys(self): return self.args[0] @property def index(self): return self.args[1] @property def christoffel(self): return self.args[2] def __call__(self, field): """Apply on a scalar field. The action of a vector field on a scalar field is a directional differentiation. If the argument is not a scalar field the behaviour is undefined. """ if covariant_order(field) != 0: raise NotImplementedError() field = vectors_in_basis(field, self._coord_sys) wrt_vector = self._coord_sys.base_vector(self._index) wrt_scalar = self._coord_sys.coord_function(self._index) vectors = list(field.atoms(BaseVectorField)) # First step: replace all vectors with something susceptible to # derivation and do the derivation # TODO: you need a real dummy function for the next line d_funcs = [Function('_#_%s' % i)(wrt_scalar) for i, b in enumerate(vectors)] d_result = field.subs(list(zip(vectors, d_funcs))) d_result = wrt_vector(d_result) # Second step: backsubstitute the vectors in d_result = d_result.subs(list(zip(d_funcs, vectors))) # Third step: evaluate the derivatives of the vectors derivs = [] for v in vectors: d = Add(*[(self._christoffel[k, wrt_vector._index, v._index] *v._coord_sys.base_vector(k)) for k in range(v._coord_sys.dim)]) derivs.append(d) to_subs = [wrt_vector(d) for d in d_funcs] # XXX: This substitution can fail when there are Dummy symbols and the # cache is disabled: https://github.com/sympy/sympy/issues/17794 result = d_result.subs(list(zip(to_subs, derivs))) # Remove the dummies result = result.subs(list(zip(d_funcs, vectors))) return result.doit() class CovarDerivativeOp(Expr): """Covariant derivative operator. Examples ======== >>> from sympy.diffgeom.rn import R2_r >>> from sympy.diffgeom import CovarDerivativeOp >>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct >>> TP = TensorProduct >>> fx, fy = R2_r.base_scalars() >>> e_x, e_y = R2_r.base_vectors() >>> dx, dy = R2_r.base_oneforms() >>> ch = metric_to_Christoffel_2nd(TP(dx, dx) + TP(dy, dy)) >>> ch [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] >>> cvd = CovarDerivativeOp(fx*e_x, ch) >>> cvd(fx) x >>> cvd(fx*e_x) x*e_x """ def __new__(cls, wrt, christoffel): if len({v._coord_sys for v in wrt.atoms(BaseVectorField)}) > 1: raise NotImplementedError() if contravariant_order(wrt) != 1 or covariant_order(wrt): raise ValueError('Covariant derivatives are defined only with ' 'respect to vector fields. The supplied argument ' 'was not a vector field.') obj = super().__new__(cls, wrt, christoffel) # deprecated assigments obj._wrt = wrt obj._christoffel = christoffel return obj @property def wrt(self): return self.args[0] @property def christoffel(self): return self.args[1] def __call__(self, field): vectors = list(self._wrt.atoms(BaseVectorField)) base_ops = [BaseCovarDerivativeOp(v._coord_sys, v._index, self._christoffel) for v in vectors] return self._wrt.subs(list(zip(vectors, base_ops))).rcall(field) ############################################################################### # Integral curves on vector fields ############################################################################### def intcurve_series(vector_field, param, start_point, n=6, coord_sys=None, coeffs=False): r"""Return the series expansion for an integral curve of the field. Explanation =========== Integral curve is a function `\gamma` taking a parameter in `R` to a point in the manifold. It verifies the equation: `V(f)\big(\gamma(t)\big) = \frac{d}{dt}f\big(\gamma(t)\big)` where the given ``vector_field`` is denoted as `V`. This holds for any value `t` for the parameter and any scalar field `f`. This equation can also be decomposed of a basis of coordinate functions `V(f_i)\big(\gamma(t)\big) = \frac{d}{dt}f_i\big(\gamma(t)\big) \quad \forall i` This function returns a series expansion of `\gamma(t)` in terms of the coordinate system ``coord_sys``. The equations and expansions are necessarily done in coordinate-system-dependent way as there is no other way to represent movement between points on the manifold (i.e. there is no such thing as a difference of points for a general manifold). Parameters ========== vector_field the vector field for which an integral curve will be given param the argument of the function `\gamma` from R to the curve start_point the point which corresponds to `\gamma(0)` n the order to which to expand coord_sys the coordinate system in which to expand coeffs (default False) - if True return a list of elements of the expansion Examples ======== Use the predefined R2 manifold: >>> from sympy.abc import t, x, y >>> from sympy.diffgeom.rn import R2_p, R2_r >>> from sympy.diffgeom import intcurve_series Specify a starting point and a vector field: >>> start_point = R2_r.point([x, y]) >>> vector_field = R2_r.e_x Calculate the series: >>> intcurve_series(vector_field, t, start_point, n=3) Matrix([ [t + x], [ y]]) Or get the elements of the expansion in a list: >>> series = intcurve_series(vector_field, t, start_point, n=3, coeffs=True) >>> series[0] Matrix([ [x], [y]]) >>> series[1] Matrix([ [t], [0]]) >>> series[2] Matrix([ [0], [0]]) The series in the polar coordinate system: >>> series = intcurve_series(vector_field, t, start_point, ... n=3, coord_sys=R2_p, coeffs=True) >>> series[0] Matrix([ [sqrt(x**2 + y**2)], [ atan2(y, x)]]) >>> series[1] Matrix([ [t*x/sqrt(x**2 + y**2)], [ -t*y/(x**2 + y**2)]]) >>> series[2] Matrix([ [t**2*(-x**2/(x**2 + y**2)**(3/2) + 1/sqrt(x**2 + y**2))/2], [ t**2*x*y/(x**2 + y**2)**2]]) See Also ======== intcurve_diffequ """ if contravariant_order(vector_field) != 1 or covariant_order(vector_field): raise ValueError('The supplied field was not a vector field.') def iter_vfield(scalar_field, i): """Return ``vector_field`` called `i` times on ``scalar_field``.""" return reduce(lambda s, v: v.rcall(s), [vector_field, ]*i, scalar_field) def taylor_terms_per_coord(coord_function): """Return the series for one of the coordinates.""" return [param**i*iter_vfield(coord_function, i).rcall(start_point)/factorial(i) for i in range(n)] coord_sys = coord_sys if coord_sys else start_point._coord_sys coord_functions = coord_sys.coord_functions() taylor_terms = [taylor_terms_per_coord(f) for f in coord_functions] if coeffs: return [Matrix(t) for t in zip(*taylor_terms)] else: return Matrix([sum(c) for c in taylor_terms]) def intcurve_diffequ(vector_field, param, start_point, coord_sys=None): r"""Return the differential equation for an integral curve of the field. Explanation =========== Integral curve is a function `\gamma` taking a parameter in `R` to a point in the manifold. It verifies the equation: `V(f)\big(\gamma(t)\big) = \frac{d}{dt}f\big(\gamma(t)\big)` where the given ``vector_field`` is denoted as `V`. This holds for any value `t` for the parameter and any scalar field `f`. This function returns the differential equation of `\gamma(t)` in terms of the coordinate system ``coord_sys``. The equations and expansions are necessarily done in coordinate-system-dependent way as there is no other way to represent movement between points on the manifold (i.e. there is no such thing as a difference of points for a general manifold). Parameters ========== vector_field the vector field for which an integral curve will be given param the argument of the function `\gamma` from R to the curve start_point the point which corresponds to `\gamma(0)` coord_sys the coordinate system in which to give the equations Returns ======= a tuple of (equations, initial conditions) Examples ======== Use the predefined R2 manifold: >>> from sympy.abc import t >>> from sympy.diffgeom.rn import R2, R2_p, R2_r >>> from sympy.diffgeom import intcurve_diffequ Specify a starting point and a vector field: >>> start_point = R2_r.point([0, 1]) >>> vector_field = -R2.y*R2.e_x + R2.x*R2.e_y Get the equation: >>> equations, init_cond = intcurve_diffequ(vector_field, t, start_point) >>> equations [f_1(t) + Derivative(f_0(t), t), -f_0(t) + Derivative(f_1(t), t)] >>> init_cond [f_0(0), f_1(0) - 1] The series in the polar coordinate system: >>> equations, init_cond = intcurve_diffequ(vector_field, t, start_point, R2_p) >>> equations [Derivative(f_0(t), t), Derivative(f_1(t), t) - 1] >>> init_cond [f_0(0) - 1, f_1(0) - pi/2] See Also ======== intcurve_series """ if contravariant_order(vector_field) != 1 or covariant_order(vector_field): raise ValueError('The supplied field was not a vector field.') coord_sys = coord_sys if coord_sys else start_point._coord_sys gammas = [Function('f_%d' % i)(param) for i in range( start_point._coord_sys.dim)] arbitrary_p = Point(coord_sys, gammas) coord_functions = coord_sys.coord_functions() equations = [simplify(diff(cf.rcall(arbitrary_p), param) - vector_field.rcall(cf).rcall(arbitrary_p)) for cf in coord_functions] init_cond = [simplify(cf.rcall(arbitrary_p).subs(param, 0) - cf.rcall(start_point)) for cf in coord_functions] return equations, init_cond ############################################################################### # Helpers ############################################################################### def dummyfy(args, exprs): # TODO Is this a good idea? d_args = Matrix([s.as_dummy() for s in args]) reps = dict(zip(args, d_args)) d_exprs = Matrix([_sympify(expr).subs(reps) for expr in exprs]) return d_args, d_exprs ############################################################################### # Helpers ############################################################################### def contravariant_order(expr, _strict=False): """Return the contravariant order of an expression. Examples ======== >>> from sympy.diffgeom import contravariant_order >>> from sympy.diffgeom.rn import R2 >>> from sympy.abc import a >>> contravariant_order(a) 0 >>> contravariant_order(a*R2.x + 2) 0 >>> contravariant_order(a*R2.x*R2.e_y + R2.e_x) 1 """ # TODO move some of this to class methods. # TODO rewrite using the .as_blah_blah methods if isinstance(expr, Add): orders = [contravariant_order(e) for e in expr.args] if len(set(orders)) != 1: raise ValueError('Misformed expression containing contravariant fields of varying order.') return orders[0] elif isinstance(expr, Mul): orders = [contravariant_order(e) for e in expr.args] not_zero = [o for o in orders if o != 0] if len(not_zero) > 1: raise ValueError('Misformed expression containing multiplication between vectors.') return 0 if not not_zero else not_zero[0] elif isinstance(expr, Pow): if covariant_order(expr.base) or covariant_order(expr.exp): raise ValueError( 'Misformed expression containing a power of a vector.') return 0 elif isinstance(expr, BaseVectorField): return 1 elif isinstance(expr, TensorProduct): return sum(contravariant_order(a) for a in expr.args) elif not _strict or expr.atoms(BaseScalarField): return 0 else: # If it does not contain anything related to the diffgeom module and it is _strict return -1 def covariant_order(expr, _strict=False): """Return the covariant order of an expression. Examples ======== >>> from sympy.diffgeom import covariant_order >>> from sympy.diffgeom.rn import R2 >>> from sympy.abc import a >>> covariant_order(a) 0 >>> covariant_order(a*R2.x + 2) 0 >>> covariant_order(a*R2.x*R2.dy + R2.dx) 1 """ # TODO move some of this to class methods. # TODO rewrite using the .as_blah_blah methods if isinstance(expr, Add): orders = [covariant_order(e) for e in expr.args] if len(set(orders)) != 1: raise ValueError('Misformed expression containing form fields of varying order.') return orders[0] elif isinstance(expr, Mul): orders = [covariant_order(e) for e in expr.args] not_zero = [o for o in orders if o != 0] if len(not_zero) > 1: raise ValueError('Misformed expression containing multiplication between forms.') return 0 if not not_zero else not_zero[0] elif isinstance(expr, Pow): if covariant_order(expr.base) or covariant_order(expr.exp): raise ValueError( 'Misformed expression containing a power of a form.') return 0 elif isinstance(expr, Differential): return covariant_order(*expr.args) + 1 elif isinstance(expr, TensorProduct): return sum(covariant_order(a) for a in expr.args) elif not _strict or expr.atoms(BaseScalarField): return 0 else: # If it does not contain anything related to the diffgeom module and it is _strict return -1 ############################################################################### # Coordinate transformation functions ############################################################################### def vectors_in_basis(expr, to_sys): """Transform all base vectors in base vectors of a specified coord basis. While the new base vectors are in the new coordinate system basis, any coefficients are kept in the old system. Examples ======== >>> from sympy.diffgeom import vectors_in_basis >>> from sympy.diffgeom.rn import R2_r, R2_p >>> vectors_in_basis(R2_r.e_x, R2_p) -y*e_theta/(x**2 + y**2) + x*e_rho/sqrt(x**2 + y**2) >>> vectors_in_basis(R2_p.e_r, R2_r) sin(theta)*e_y + cos(theta)*e_x """ vectors = list(expr.atoms(BaseVectorField)) new_vectors = [] for v in vectors: cs = v._coord_sys jac = cs.jacobian(to_sys, cs.coord_functions()) new = (jac.T*Matrix(to_sys.base_vectors()))[v._index] new_vectors.append(new) return expr.subs(list(zip(vectors, new_vectors))) ############################################################################### # Coordinate-dependent functions ############################################################################### def twoform_to_matrix(expr): """Return the matrix representing the twoform. For the twoform `w` return the matrix `M` such that `M[i,j]=w(e_i, e_j)`, where `e_i` is the i-th base vector field for the coordinate system in which the expression of `w` is given. Examples ======== >>> from sympy.diffgeom.rn import R2 >>> from sympy.diffgeom import twoform_to_matrix, TensorProduct >>> TP = TensorProduct >>> twoform_to_matrix(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) Matrix([ [1, 0], [0, 1]]) >>> twoform_to_matrix(R2.x*TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) Matrix([ [x, 0], [0, 1]]) >>> twoform_to_matrix(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy) - TP(R2.dx, R2.dy)/2) Matrix([ [ 1, 0], [-1/2, 1]]) """ if covariant_order(expr) != 2 or contravariant_order(expr): raise ValueError('The input expression is not a two-form.') coord_sys = _find_coords(expr) if len(coord_sys) != 1: raise ValueError('The input expression concerns more than one ' 'coordinate systems, hence there is no unambiguous ' 'way to choose a coordinate system for the matrix.') coord_sys = coord_sys.pop() vectors = coord_sys.base_vectors() expr = expr.expand() matrix_content = [[expr.rcall(v1, v2) for v1 in vectors] for v2 in vectors] return Matrix(matrix_content) def metric_to_Christoffel_1st(expr): """Return the nested list of Christoffel symbols for the given metric. This returns the Christoffel symbol of first kind that represents the Levi-Civita connection for the given metric. Examples ======== >>> from sympy.diffgeom.rn import R2 >>> from sympy.diffgeom import metric_to_Christoffel_1st, TensorProduct >>> TP = TensorProduct >>> metric_to_Christoffel_1st(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] >>> metric_to_Christoffel_1st(R2.x*TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) [[[1/2, 0], [0, 0]], [[0, 0], [0, 0]]] """ matrix = twoform_to_matrix(expr) if not matrix.is_symmetric(): raise ValueError( 'The two-form representing the metric is not symmetric.') coord_sys = _find_coords(expr).pop() deriv_matrices = [matrix.applyfunc(lambda a: d(a)) for d in coord_sys.base_vectors()] indices = list(range(coord_sys.dim)) christoffel = [[[(deriv_matrices[k][i, j] + deriv_matrices[j][i, k] - deriv_matrices[i][j, k])/2 for k in indices] for j in indices] for i in indices] return ImmutableDenseNDimArray(christoffel) def metric_to_Christoffel_2nd(expr): """Return the nested list of Christoffel symbols for the given metric. This returns the Christoffel symbol of second kind that represents the Levi-Civita connection for the given metric. Examples ======== >>> from sympy.diffgeom.rn import R2 >>> from sympy.diffgeom import metric_to_Christoffel_2nd, TensorProduct >>> TP = TensorProduct >>> metric_to_Christoffel_2nd(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) [[[0, 0], [0, 0]], [[0, 0], [0, 0]]] >>> metric_to_Christoffel_2nd(R2.x*TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) [[[1/(2*x), 0], [0, 0]], [[0, 0], [0, 0]]] """ ch_1st = metric_to_Christoffel_1st(expr) coord_sys = _find_coords(expr).pop() indices = list(range(coord_sys.dim)) # XXX workaround, inverting a matrix does not work if it contains non # symbols #matrix = twoform_to_matrix(expr).inv() matrix = twoform_to_matrix(expr) s_fields = set() for e in matrix: s_fields.update(e.atoms(BaseScalarField)) s_fields = list(s_fields) dums = coord_sys.symbols matrix = matrix.subs(list(zip(s_fields, dums))).inv().subs(list(zip(dums, s_fields))) # XXX end of workaround christoffel = [[[Add(*[matrix[i, l]*ch_1st[l, j, k] for l in indices]) for k in indices] for j in indices] for i in indices] return ImmutableDenseNDimArray(christoffel) def metric_to_Riemann_components(expr): """Return the components of the Riemann tensor expressed in a given basis. Given a metric it calculates the components of the Riemann tensor in the canonical basis of the coordinate system in which the metric expression is given. Examples ======== >>> from sympy import exp >>> from sympy.diffgeom.rn import R2 >>> from sympy.diffgeom import metric_to_Riemann_components, TensorProduct >>> TP = TensorProduct >>> metric_to_Riemann_components(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) [[[[0, 0], [0, 0]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[0, 0], [0, 0]]]] >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + \ R2.r**2*TP(R2.dtheta, R2.dtheta) >>> non_trivial_metric exp(2*rho)*TensorProduct(drho, drho) + rho**2*TensorProduct(dtheta, dtheta) >>> riemann = metric_to_Riemann_components(non_trivial_metric) >>> riemann[0, :, :, :] [[[0, 0], [0, 0]], [[0, exp(-2*rho)*rho], [-exp(-2*rho)*rho, 0]]] >>> riemann[1, :, :, :] [[[0, -1/rho], [1/rho, 0]], [[0, 0], [0, 0]]] """ ch_2nd = metric_to_Christoffel_2nd(expr) coord_sys = _find_coords(expr).pop() indices = list(range(coord_sys.dim)) deriv_ch = [[[[d(ch_2nd[i, j, k]) for d in coord_sys.base_vectors()] for k in indices] for j in indices] for i in indices] riemann_a = [[[[deriv_ch[rho][sig][nu][mu] - deriv_ch[rho][sig][mu][nu] for nu in indices] for mu in indices] for sig in indices] for rho in indices] riemann_b = [[[[Add(*[ch_2nd[rho, l, mu]*ch_2nd[l, sig, nu] - ch_2nd[rho, l, nu]*ch_2nd[l, sig, mu] for l in indices]) for nu in indices] for mu in indices] for sig in indices] for rho in indices] riemann = [[[[riemann_a[rho][sig][mu][nu] + riemann_b[rho][sig][mu][nu] for nu in indices] for mu in indices] for sig in indices] for rho in indices] return ImmutableDenseNDimArray(riemann) def metric_to_Ricci_components(expr): """Return the components of the Ricci tensor expressed in a given basis. Given a metric it calculates the components of the Ricci tensor in the canonical basis of the coordinate system in which the metric expression is given. Examples ======== >>> from sympy import exp >>> from sympy.diffgeom.rn import R2 >>> from sympy.diffgeom import metric_to_Ricci_components, TensorProduct >>> TP = TensorProduct >>> metric_to_Ricci_components(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) [[0, 0], [0, 0]] >>> non_trivial_metric = exp(2*R2.r)*TP(R2.dr, R2.dr) + \ R2.r**2*TP(R2.dtheta, R2.dtheta) >>> non_trivial_metric exp(2*rho)*TensorProduct(drho, drho) + rho**2*TensorProduct(dtheta, dtheta) >>> metric_to_Ricci_components(non_trivial_metric) [[1/rho, 0], [0, exp(-2*rho)*rho]] """ riemann = metric_to_Riemann_components(expr) coord_sys = _find_coords(expr).pop() indices = list(range(coord_sys.dim)) ricci = [[Add(*[riemann[k, i, k, j] for k in indices]) for j in indices] for i in indices] return ImmutableDenseNDimArray(ricci) ############################################################################### # Classes for deprecation ############################################################################### class _deprecated_container: # This class gives deprecation warning. # When deprecated features are completely deleted, this should be removed as well. # See https://github.com/sympy/sympy/pull/19368 def __init__(self, feature, useinstead, issue, version, data): super().__init__(data) self.feature = feature self.useinstead = useinstead self.issue = issue self.version = version def warn(self): SymPyDeprecationWarning( feature=self.feature, useinstead=self.useinstead, issue=self.issue, deprecated_since_version=self.version).warn() def __iter__(self): self.warn() return super().__iter__() def __getitem__(self, key): self.warn() return super().__getitem__(key) def __contains__(self, key): self.warn() return super().__contains__(key) class _deprecated_list(_deprecated_container, list): pass class _deprecated_dict(_deprecated_container, dict): pass sympy-sympy-1.9/sympy/diffgeom/rn.py000066400000000000000000000141101412543434000176520ustar00rootroot00000000000000"""Predefined R^n manifolds together with common coord. systems. Coordinate systems are predefined as well as the transformation laws between them. Coordinate functions can be accessed as attributes of the manifold (eg `R2.x`), as attributes of the coordinate systems (eg `R2_r.x` and `R2_p.theta`), or by using the usual `coord_sys.coord_function(index, name)` interface. """ from typing import Any import warnings from sympy import sqrt, atan2, acos, sin, cos, symbols, Dummy from .diffgeom import Manifold, Patch, CoordSystem __all__ = [ 'R2', 'R2_origin', 'relations_2d', 'R2_r', 'R2_p', 'R3', 'R3_origin', 'relations_3d', 'R3_r', 'R3_c', 'R3_s' ] ############################################################################### # R2 ############################################################################### R2 = Manifold('R^2', 2) # type: Any R2_origin = Patch('origin', R2) # type: Any x, y = symbols('x y', real=True) r, theta = symbols('rho theta', nonnegative=True) relations_2d = { ('rectangular', 'polar'): [(x, y), (sqrt(x**2 + y**2), atan2(y, x))], ('polar', 'rectangular'): [(r, theta), (r*cos(theta), r*sin(theta))], } R2_r = CoordSystem('rectangular', R2_origin, (x, y), relations_2d) # type: Any R2_p = CoordSystem('polar', R2_origin, (r, theta), relations_2d) # type: Any # support deprecated feature with warnings.catch_warnings(): warnings.simplefilter("ignore") x, y, r, theta = symbols('x y r theta', cls=Dummy) R2_r.connect_to(R2_p, [x, y], [sqrt(x**2 + y**2), atan2(y, x)], inverse=False, fill_in_gaps=False) R2_p.connect_to(R2_r, [r, theta], [r*cos(theta), r*sin(theta)], inverse=False, fill_in_gaps=False) # Defining the basis coordinate functions and adding shortcuts for them to the # manifold and the patch. R2.x, R2.y = R2_origin.x, R2_origin.y = R2_r.x, R2_r.y = R2_r.coord_functions() R2.r, R2.theta = R2_origin.r, R2_origin.theta = R2_p.r, R2_p.theta = R2_p.coord_functions() # Defining the basis vector fields and adding shortcuts for them to the # manifold and the patch. R2.e_x, R2.e_y = R2_origin.e_x, R2_origin.e_y = R2_r.e_x, R2_r.e_y = R2_r.base_vectors() R2.e_r, R2.e_theta = R2_origin.e_r, R2_origin.e_theta = R2_p.e_r, R2_p.e_theta = R2_p.base_vectors() # Defining the basis oneform fields and adding shortcuts for them to the # manifold and the patch. R2.dx, R2.dy = R2_origin.dx, R2_origin.dy = R2_r.dx, R2_r.dy = R2_r.base_oneforms() R2.dr, R2.dtheta = R2_origin.dr, R2_origin.dtheta = R2_p.dr, R2_p.dtheta = R2_p.base_oneforms() ############################################################################### # R3 ############################################################################### R3 = Manifold('R^3', 3) # type: Any R3_origin = Patch('origin', R3) # type: Any x, y, z = symbols('x y z', real=True) rho, psi, r, theta, phi = symbols('rho psi r theta phi', nonnegative=True) relations_3d = { ('rectangular', 'cylindrical'): [(x, y, z), (sqrt(x**2 + y**2), atan2(y, x), z)], ('cylindrical', 'rectangular'): [(rho, psi, z), (rho*cos(psi), rho*sin(psi), z)], ('rectangular', 'spherical'): [(x, y, z), (sqrt(x**2 + y**2 + z**2), acos(z/sqrt(x**2 + y**2 + z**2)), atan2(y, x))], ('spherical', 'rectangular'): [(r, theta, phi), (r*sin(theta)*cos(phi), r*sin(theta)*sin(phi), r*cos(theta))], ('cylindrical', 'spherical'): [(rho, psi, z), (sqrt(rho**2 + z**2), acos(z/sqrt(rho**2 + z**2)), psi)], ('spherical', 'cylindrical'): [(r, theta, phi), (r*sin(theta), phi, r*cos(theta))], } R3_r = CoordSystem('rectangular', R3_origin, (x, y, z), relations_3d) # type: Any R3_c = CoordSystem('cylindrical', R3_origin, (rho, psi, z), relations_3d) # type: Any R3_s = CoordSystem('spherical', R3_origin, (r, theta, phi), relations_3d) # type: Any # support deprecated feature with warnings.catch_warnings(): warnings.simplefilter("ignore") x, y, z, rho, psi, r, theta, phi = symbols('x y z rho psi r theta phi', cls=Dummy) R3_r.connect_to(R3_c, [x, y, z], [sqrt(x**2 + y**2), atan2(y, x), z], inverse=False, fill_in_gaps=False) R3_c.connect_to(R3_r, [rho, psi, z], [rho*cos(psi), rho*sin(psi), z], inverse=False, fill_in_gaps=False) ## rectangular <-> spherical R3_r.connect_to(R3_s, [x, y, z], [sqrt(x**2 + y**2 + z**2), acos(z/ sqrt(x**2 + y**2 + z**2)), atan2(y, x)], inverse=False, fill_in_gaps=False) R3_s.connect_to(R3_r, [r, theta, phi], [r*sin(theta)*cos(phi), r*sin( theta)*sin(phi), r*cos(theta)], inverse=False, fill_in_gaps=False) ## cylindrical <-> spherical R3_c.connect_to(R3_s, [rho, psi, z], [sqrt(rho**2 + z**2), acos(z/sqrt(rho**2 + z**2)), psi], inverse=False, fill_in_gaps=False) R3_s.connect_to(R3_c, [r, theta, phi], [r*sin(theta), phi, r*cos(theta)], inverse=False, fill_in_gaps=False) # Defining the basis coordinate functions. R3_r.x, R3_r.y, R3_r.z = R3_r.coord_functions() R3_c.rho, R3_c.psi, R3_c.z = R3_c.coord_functions() R3_s.r, R3_s.theta, R3_s.phi = R3_s.coord_functions() # Defining the basis vector fields. R3_r.e_x, R3_r.e_y, R3_r.e_z = R3_r.base_vectors() R3_c.e_rho, R3_c.e_psi, R3_c.e_z = R3_c.base_vectors() R3_s.e_r, R3_s.e_theta, R3_s.e_phi = R3_s.base_vectors() # Defining the basis oneform fields. R3_r.dx, R3_r.dy, R3_r.dz = R3_r.base_oneforms() R3_c.drho, R3_c.dpsi, R3_c.dz = R3_c.base_oneforms() R3_s.dr, R3_s.dtheta, R3_s.dphi = R3_s.base_oneforms() sympy-sympy-1.9/sympy/diffgeom/tests/000077500000000000000000000000001412543434000200265ustar00rootroot00000000000000sympy-sympy-1.9/sympy/diffgeom/tests/__init__.py000066400000000000000000000000001412543434000221250ustar00rootroot00000000000000sympy-sympy-1.9/sympy/diffgeom/tests/test_class_structure.py000066400000000000000000000017551412543434000246740ustar00rootroot00000000000000from sympy.diffgeom import Manifold, Patch, CoordSystem, Point from sympy import symbols, Function from sympy.testing.pytest import warns_deprecated_sympy m = Manifold('m', 2) p = Patch('p', m) a, b = symbols('a b') cs = CoordSystem('cs', p, [a, b]) x, y = symbols('x y') f = Function('f') s1, s2 = cs.coord_functions() v1, v2 = cs.base_vectors() f1, f2 = cs.base_oneforms() def test_point(): point = Point(cs, [x, y]) assert point != Point(cs, [2, y]) #TODO assert point.subs(x, 2) == Point(cs, [2, y]) #TODO assert point.free_symbols == set([x, y]) def test_subs(): assert s1.subs(s1, s2) == s2 assert v1.subs(v1, v2) == v2 assert f1.subs(f1, f2) == f2 assert (x*f(s1) + y).subs(s1, s2) == x*f(s2) + y assert (f(s1)*v1).subs(v1, v2) == f(s1)*v2 assert (y*f(s1)*f1).subs(f1, f2) == y*f(s1)*f2 def test_deprecated(): with warns_deprecated_sympy(): cs_wname = CoordSystem('cs', p, ['a', 'b']) assert cs_wname == cs_wname.func(*cs_wname.args) sympy-sympy-1.9/sympy/diffgeom/tests/test_diffgeom.py000066400000000000000000000323461412543434000232270ustar00rootroot00000000000000from sympy.core import Lambda, Symbol, symbols from sympy.diffgeom.rn import R2, R2_p, R2_r, R3_r, R3_c, R3_s, R2_origin from sympy.diffgeom import (CoordSystem, Commutator, Differential, TensorProduct, WedgeProduct, BaseCovarDerivativeOp, CovarDerivativeOp, LieDerivative, covariant_order, contravariant_order, twoform_to_matrix, metric_to_Christoffel_1st, metric_to_Christoffel_2nd, metric_to_Riemann_components, metric_to_Ricci_components, intcurve_diffequ, intcurve_series) from sympy.simplify import trigsimp, simplify from sympy.functions import sqrt, atan2, sin from sympy.matrices import Matrix from sympy.testing.pytest import raises, nocache_fail from sympy.testing.pytest import warns_deprecated_sympy TP = TensorProduct def test_coordsys_transform(): # test inverse transforms p, q, r, s = symbols('p q r s') rel = {('first', 'second'): [(p, q), (q, -p)]} R2_pq = CoordSystem('first', R2_origin, [p, q], rel) R2_rs = CoordSystem('second', R2_origin, [r, s], rel) r, s = R2_rs.symbols assert R2_rs.transform(R2_pq) == Matrix([[-s], [r]]) # inverse transform impossible case a, b = symbols('a b', positive=True) rel = {('first', 'second'): [(a,), (-a,)]} R2_a = CoordSystem('first', R2_origin, [a], rel) R2_b = CoordSystem('second', R2_origin, [b], rel) # This transformation is uninvertible because there is no positive a, b satisfying a = -b with raises(NotImplementedError): R2_b.transform(R2_a) # inverse transform ambiguous case c, d = symbols('c d') rel = {('first', 'second'): [(c,), (c**2,)]} R2_c = CoordSystem('first', R2_origin, [c], rel) R2_d = CoordSystem('second', R2_origin, [d], rel) # The transform method should throw if it finds multiple inverses for a coordinate transformation. with raises(ValueError): R2_d.transform(R2_c) # test indirect transformation a, b, c, d, e, f = symbols('a, b, c, d, e, f') rel = {('C1', 'C2'): [(a, b), (2*a, 3*b)], ('C2', 'C3'): [(c, d), (3*c, 2*d)]} C1 = CoordSystem('C1', R2_origin, (a, b), rel) C2 = CoordSystem('C2', R2_origin, (c, d), rel) C3 = CoordSystem('C3', R2_origin, (e, f), rel) a, b = C1.symbols c, d = C2.symbols e, f = C3.symbols assert C2.transform(C1) == Matrix([c/2, d/3]) assert C1.transform(C3) == Matrix([6*a, 6*b]) assert C3.transform(C1) == Matrix([e/6, f/6]) assert C3.transform(C2) == Matrix([e/3, f/2]) a, b, c, d, e, f = symbols('a, b, c, d, e, f') rel = {('C1', 'C2'): [(a, b), (2*a, 3*b + 1)], ('C3', 'C2'): [(e, f), (-e - 2, 2*f)]} C1 = CoordSystem('C1', R2_origin, (a, b), rel) C2 = CoordSystem('C2', R2_origin, (c, d), rel) C3 = CoordSystem('C3', R2_origin, (e, f), rel) a, b = C1.symbols c, d = C2.symbols e, f = C3.symbols assert C2.transform(C1) == Matrix([c/2, (d - 1)/3]) assert C1.transform(C3) == Matrix([-2*a - 2, (3*b + 1)/2]) assert C3.transform(C1) == Matrix([-e/2 - 1, (2*f - 1)/3]) assert C3.transform(C2) == Matrix([-e - 2, 2*f]) # old signature uses Lambda a, b, c, d, e, f = symbols('a, b, c, d, e, f') rel = {('C1', 'C2'): Lambda((a, b), (2*a, 3*b + 1)), ('C3', 'C2'): Lambda((e, f), (-e - 2, 2*f))} C1 = CoordSystem('C1', R2_origin, (a, b), rel) C2 = CoordSystem('C2', R2_origin, (c, d), rel) C3 = CoordSystem('C3', R2_origin, (e, f), rel) a, b = C1.symbols c, d = C2.symbols e, f = C3.symbols assert C2.transform(C1) == Matrix([c/2, (d - 1)/3]) assert C1.transform(C3) == Matrix([-2*a - 2, (3*b + 1)/2]) assert C3.transform(C1) == Matrix([-e/2 - 1, (2*f - 1)/3]) assert C3.transform(C2) == Matrix([-e - 2, 2*f]) def test_R2(): x0, y0, r0, theta0 = symbols('x0, y0, r0, theta0', real=True) point_r = R2_r.point([x0, y0]) point_p = R2_p.point([r0, theta0]) # r**2 = x**2 + y**2 assert (R2.r**2 - R2.x**2 - R2.y**2).rcall(point_r) == 0 assert trigsimp( (R2.r**2 - R2.x**2 - R2.y**2).rcall(point_p) ) == 0 assert trigsimp(R2.e_r(R2.x**2 + R2.y**2).rcall(point_p).doit()) == 2*r0 # polar->rect->polar == Id a, b = symbols('a b', positive=True) m = Matrix([[a], [b]]) #TODO assert m == R2_r.transform(R2_p, R2_p.transform(R2_r, [a, b])).applyfunc(simplify) assert m == R2_p.transform(R2_r, R2_r.transform(R2_p, m)).applyfunc(simplify) # deprecated method with warns_deprecated_sympy(): assert m == R2_p.coord_tuple_transform_to( R2_r, R2_r.coord_tuple_transform_to(R2_p, m)).applyfunc(simplify) def test_R3(): a, b, c = symbols('a b c', positive=True) m = Matrix([[a], [b], [c]]) assert m == R3_c.transform(R3_r, R3_r.transform(R3_c, m)).applyfunc(simplify) #TODO assert m == R3_r.transform(R3_c, R3_c.transform(R3_r, m)).applyfunc(simplify) assert m == R3_s.transform( R3_r, R3_r.transform(R3_s, m)).applyfunc(simplify) #TODO assert m == R3_r.transform(R3_s, R3_s.transform(R3_r, m)).applyfunc(simplify) assert m == R3_s.transform( R3_c, R3_c.transform(R3_s, m)).applyfunc(simplify) #TODO assert m == R3_c.transform(R3_s, R3_s.transform(R3_c, m)).applyfunc(simplify) with warns_deprecated_sympy(): assert m == R3_c.coord_tuple_transform_to( R3_r, R3_r.coord_tuple_transform_to(R3_c, m)).applyfunc(simplify) #TODO assert m == R3_r.coord_tuple_transform_to(R3_c, R3_c.coord_tuple_transform_to(R3_r, m)).applyfunc(simplify) assert m == R3_s.coord_tuple_transform_to( R3_r, R3_r.coord_tuple_transform_to(R3_s, m)).applyfunc(simplify) #TODO assert m == R3_r.coord_tuple_transform_to(R3_s, R3_s.coord_tuple_transform_to(R3_r, m)).applyfunc(simplify) assert m == R3_s.coord_tuple_transform_to( R3_c, R3_c.coord_tuple_transform_to(R3_s, m)).applyfunc(simplify) #TODO assert m == R3_c.coord_tuple_transform_to(R3_s, R3_s.coord_tuple_transform_to(R3_c, m)).applyfunc(simplify) def test_CoordinateSymbol(): x, y = R2_r.symbols r, theta = R2_p.symbols assert y.rewrite(R2_p) == r*sin(theta) def test_point(): x, y = symbols('x, y') p = R2_r.point([x, y]) assert p.free_symbols == {x, y} assert p.coords(R2_r) == p.coords() == Matrix([x, y]) assert p.coords(R2_p) == Matrix([sqrt(x**2 + y**2), atan2(y, x)]) def test_commutator(): assert Commutator(R2.e_x, R2.e_y) == 0 assert Commutator(R2.x*R2.e_x, R2.x*R2.e_x) == 0 assert Commutator(R2.x*R2.e_x, R2.x*R2.e_y) == R2.x*R2.e_y c = Commutator(R2.e_x, R2.e_r) assert c(R2.x) == R2.y*(R2.x**2 + R2.y**2)**(-1)*sin(R2.theta) def test_differential(): xdy = R2.x*R2.dy dxdy = Differential(xdy) assert xdy.rcall(None) == xdy assert dxdy(R2.e_x, R2.e_y) == 1 assert dxdy(R2.e_x, R2.x*R2.e_y) == R2.x assert Differential(dxdy) == 0 def test_products(): assert TensorProduct( R2.dx, R2.dy)(R2.e_x, R2.e_y) == R2.dx(R2.e_x)*R2.dy(R2.e_y) == 1 assert TensorProduct(R2.dx, R2.dy)(None, R2.e_y) == R2.dx assert TensorProduct(R2.dx, R2.dy)(R2.e_x, None) == R2.dy assert TensorProduct(R2.dx, R2.dy)(R2.e_x) == R2.dy assert TensorProduct(R2.x, R2.dx) == R2.x*R2.dx assert TensorProduct( R2.e_x, R2.e_y)(R2.x, R2.y) == R2.e_x(R2.x) * R2.e_y(R2.y) == 1 assert TensorProduct(R2.e_x, R2.e_y)(None, R2.y) == R2.e_x assert TensorProduct(R2.e_x, R2.e_y)(R2.x, None) == R2.e_y assert TensorProduct(R2.e_x, R2.e_y)(R2.x) == R2.e_y assert TensorProduct(R2.x, R2.e_x) == R2.x * R2.e_x assert TensorProduct( R2.dx, R2.e_y)(R2.e_x, R2.y) == R2.dx(R2.e_x) * R2.e_y(R2.y) == 1 assert TensorProduct(R2.dx, R2.e_y)(None, R2.y) == R2.dx assert TensorProduct(R2.dx, R2.e_y)(R2.e_x, None) == R2.e_y assert TensorProduct(R2.dx, R2.e_y)(R2.e_x) == R2.e_y assert TensorProduct(R2.x, R2.e_x) == R2.x * R2.e_x assert TensorProduct( R2.e_x, R2.dy)(R2.x, R2.e_y) == R2.e_x(R2.x) * R2.dy(R2.e_y) == 1 assert TensorProduct(R2.e_x, R2.dy)(None, R2.e_y) == R2.e_x assert TensorProduct(R2.e_x, R2.dy)(R2.x, None) == R2.dy assert TensorProduct(R2.e_x, R2.dy)(R2.x) == R2.dy assert TensorProduct(R2.e_y,R2.e_x)(R2.x**2 + R2.y**2,R2.x**2 + R2.y**2) == 4*R2.x*R2.y assert WedgeProduct(R2.dx, R2.dy)(R2.e_x, R2.e_y) == 1 assert WedgeProduct(R2.e_x, R2.e_y)(R2.x, R2.y) == 1 def test_lie_derivative(): assert LieDerivative(R2.e_x, R2.y) == R2.e_x(R2.y) == 0 assert LieDerivative(R2.e_x, R2.x) == R2.e_x(R2.x) == 1 assert LieDerivative(R2.e_x, R2.e_x) == Commutator(R2.e_x, R2.e_x) == 0 assert LieDerivative(R2.e_x, R2.e_r) == Commutator(R2.e_x, R2.e_r) assert LieDerivative(R2.e_x + R2.e_y, R2.x) == 1 assert LieDerivative( R2.e_x, TensorProduct(R2.dx, R2.dy))(R2.e_x, R2.e_y) == 0 @nocache_fail def test_covar_deriv(): ch = metric_to_Christoffel_2nd(TP(R2.dx, R2.dx) + TP(R2.dy, R2.dy)) cvd = BaseCovarDerivativeOp(R2_r, 0, ch) assert cvd(R2.x) == 1 # This line fails if the cache is disabled: assert cvd(R2.x*R2.e_x) == R2.e_x cvd = CovarDerivativeOp(R2.x*R2.e_x, ch) assert cvd(R2.x) == R2.x assert cvd(R2.x*R2.e_x) == R2.x*R2.e_x def test_intcurve_diffequ(): t = symbols('t') start_point = R2_r.point([1, 0]) vector_field = -R2.y*R2.e_x + R2.x*R2.e_y equations, init_cond = intcurve_diffequ(vector_field, t, start_point) assert str(equations) == '[f_1(t) + Derivative(f_0(t), t), -f_0(t) + Derivative(f_1(t), t)]' assert str(init_cond) == '[f_0(0) - 1, f_1(0)]' equations, init_cond = intcurve_diffequ(vector_field, t, start_point, R2_p) assert str( equations) == '[Derivative(f_0(t), t), Derivative(f_1(t), t) - 1]' assert str(init_cond) == '[f_0(0) - 1, f_1(0)]' def test_helpers_and_coordinate_dependent(): one_form = R2.dr + R2.dx two_form = Differential(R2.x*R2.dr + R2.r*R2.dx) three_form = Differential( R2.y*two_form) + Differential(R2.x*Differential(R2.r*R2.dr)) metric = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dy, R2.dy) metric_ambig = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dr, R2.dr) misform_a = TensorProduct(R2.dr, R2.dr) + R2.dr misform_b = R2.dr**4 misform_c = R2.dx*R2.dy twoform_not_sym = TensorProduct(R2.dx, R2.dx) + TensorProduct(R2.dx, R2.dy) twoform_not_TP = WedgeProduct(R2.dx, R2.dy) one_vector = R2.e_x + R2.e_y two_vector = TensorProduct(R2.e_x, R2.e_y) three_vector = TensorProduct(R2.e_x, R2.e_y, R2.e_x) two_wp = WedgeProduct(R2.e_x,R2.e_y) assert covariant_order(one_form) == 1 assert covariant_order(two_form) == 2 assert covariant_order(three_form) == 3 assert covariant_order(two_form + metric) == 2 assert covariant_order(two_form + metric_ambig) == 2 assert covariant_order(two_form + twoform_not_sym) == 2 assert covariant_order(two_form + twoform_not_TP) == 2 assert contravariant_order(one_vector) == 1 assert contravariant_order(two_vector) == 2 assert contravariant_order(three_vector) == 3 assert contravariant_order(two_vector + two_wp) == 2 raises(ValueError, lambda: covariant_order(misform_a)) raises(ValueError, lambda: covariant_order(misform_b)) raises(ValueError, lambda: covariant_order(misform_c)) assert twoform_to_matrix(metric) == Matrix([[1, 0], [0, 1]]) assert twoform_to_matrix(twoform_not_sym) == Matrix([[1, 0], [1, 0]]) assert twoform_to_matrix(twoform_not_TP) == Matrix([[0, -1], [1, 0]]) raises(ValueError, lambda: twoform_to_matrix(one_form)) raises(ValueError, lambda: twoform_to_matrix(three_form)) raises(ValueError, lambda: twoform_to_matrix(metric_ambig)) raises(ValueError, lambda: metric_to_Christoffel_1st(twoform_not_sym)) raises(ValueError, lambda: metric_to_Christoffel_2nd(twoform_not_sym)) raises(ValueError, lambda: metric_to_Riemann_components(twoform_not_sym)) raises(ValueError, lambda: metric_to_Ricci_components(twoform_not_sym)) def test_correct_arguments(): raises(ValueError, lambda: R2.e_x(R2.e_x)) raises(ValueError, lambda: R2.e_x(R2.dx)) raises(ValueError, lambda: Commutator(R2.e_x, R2.x)) raises(ValueError, lambda: Commutator(R2.dx, R2.e_x)) raises(ValueError, lambda: Differential(Differential(R2.e_x))) raises(ValueError, lambda: R2.dx(R2.x)) raises(ValueError, lambda: LieDerivative(R2.dx, R2.dx)) raises(ValueError, lambda: LieDerivative(R2.x, R2.dx)) raises(ValueError, lambda: CovarDerivativeOp(R2.dx, [])) raises(ValueError, lambda: CovarDerivativeOp(R2.x, [])) a = Symbol('a') raises(ValueError, lambda: intcurve_series(R2.dx, a, R2_r.point([1, 2]))) raises(ValueError, lambda: intcurve_series(R2.x, a, R2_r.point([1, 2]))) raises(ValueError, lambda: intcurve_diffequ(R2.dx, a, R2_r.point([1, 2]))) raises(ValueError, lambda: intcurve_diffequ(R2.x, a, R2_r.point([1, 2]))) raises(ValueError, lambda: contravariant_order(R2.e_x + R2.dx)) raises(ValueError, lambda: covariant_order(R2.e_x + R2.dx)) raises(ValueError, lambda: contravariant_order(R2.e_x*R2.e_y)) raises(ValueError, lambda: covariant_order(R2.dx*R2.dy)) def test_simplify(): x, y = R2_r.coord_functions() dx, dy = R2_r.base_oneforms() ex, ey = R2_r.base_vectors() assert simplify(x) == x assert simplify(x*y) == x*y assert simplify(dx*dy) == dx*dy assert simplify(ex*ey) == ex*ey assert ((1-x)*dx)/(1-x)**2 == dx/(1-x) sympy-sympy-1.9/sympy/diffgeom/tests/test_function_diffgeom_book.py000066400000000000000000000122121412543434000261340ustar00rootroot00000000000000from sympy.diffgeom.rn import R2, R2_p, R2_r, R3_r from sympy.diffgeom import intcurve_series, Differential, WedgeProduct from sympy.core import symbols, Function, Derivative from sympy.simplify import trigsimp, simplify from sympy.functions import sqrt, atan2, sin, cos from sympy.matrices import Matrix # Most of the functionality is covered in the # test_functional_diffgeom_ch* tests which are based on the # example from the paper of Sussman and Wisdom. # If they do not cover something, additional tests are added in other test # functions. # From "Functional Differential Geometry" as of 2011 # by Sussman and Wisdom. def test_functional_diffgeom_ch2(): x0, y0, r0, theta0 = symbols('x0, y0, r0, theta0', real=True) x, y = symbols('x, y', real=True) f = Function('f') assert (R2_p.point_to_coords(R2_r.point([x0, y0])) == Matrix([sqrt(x0**2 + y0**2), atan2(y0, x0)])) assert (R2_r.point_to_coords(R2_p.point([r0, theta0])) == Matrix([r0*cos(theta0), r0*sin(theta0)])) assert R2_p.jacobian(R2_r, [r0, theta0]) == Matrix( [[cos(theta0), -r0*sin(theta0)], [sin(theta0), r0*cos(theta0)]]) field = f(R2.x, R2.y) p1_in_rect = R2_r.point([x0, y0]) p1_in_polar = R2_p.point([sqrt(x0**2 + y0**2), atan2(y0, x0)]) assert field.rcall(p1_in_rect) == f(x0, y0) assert field.rcall(p1_in_polar) == f(x0, y0) p_r = R2_r.point([x0, y0]) p_p = R2_p.point([r0, theta0]) assert R2.x(p_r) == x0 assert R2.x(p_p) == r0*cos(theta0) assert R2.r(p_p) == r0 assert R2.r(p_r) == sqrt(x0**2 + y0**2) assert R2.theta(p_r) == atan2(y0, x0) h = R2.x*R2.r**2 + R2.y**3 assert h.rcall(p_r) == x0*(x0**2 + y0**2) + y0**3 assert h.rcall(p_p) == r0**3*sin(theta0)**3 + r0**3*cos(theta0) def test_functional_diffgeom_ch3(): x0, y0 = symbols('x0, y0', real=True) x, y, t = symbols('x, y, t', real=True) f = Function('f') b1 = Function('b1') b2 = Function('b2') p_r = R2_r.point([x0, y0]) s_field = f(R2.x, R2.y) v_field = b1(R2.x)*R2.e_x + b2(R2.y)*R2.e_y assert v_field.rcall(s_field).rcall(p_r).doit() == b1( x0)*Derivative(f(x0, y0), x0) + b2(y0)*Derivative(f(x0, y0), y0) assert R2.e_x(R2.r**2).rcall(p_r) == 2*x0 v = R2.e_x + 2*R2.e_y s = R2.r**2 + 3*R2.x assert v.rcall(s).rcall(p_r).doit() == 2*x0 + 4*y0 + 3 circ = -R2.y*R2.e_x + R2.x*R2.e_y series = intcurve_series(circ, t, R2_r.point([1, 0]), coeffs=True) series_x, series_y = zip(*series) assert all( [term == cos(t).taylor_term(i, t) for i, term in enumerate(series_x)]) assert all( [term == sin(t).taylor_term(i, t) for i, term in enumerate(series_y)]) def test_functional_diffgeom_ch4(): x0, y0, theta0 = symbols('x0, y0, theta0', real=True) x, y, r, theta = symbols('x, y, r, theta', real=True) r0 = symbols('r0', positive=True) f = Function('f') b1 = Function('b1') b2 = Function('b2') p_r = R2_r.point([x0, y0]) p_p = R2_p.point([r0, theta0]) f_field = b1(R2.x, R2.y)*R2.dx + b2(R2.x, R2.y)*R2.dy assert f_field.rcall(R2.e_x).rcall(p_r) == b1(x0, y0) assert f_field.rcall(R2.e_y).rcall(p_r) == b2(x0, y0) s_field_r = f(R2.x, R2.y) df = Differential(s_field_r) assert df(R2.e_x).rcall(p_r).doit() == Derivative(f(x0, y0), x0) assert df(R2.e_y).rcall(p_r).doit() == Derivative(f(x0, y0), y0) s_field_p = f(R2.r, R2.theta) df = Differential(s_field_p) assert trigsimp(df(R2.e_x).rcall(p_p).doit()) == ( cos(theta0)*Derivative(f(r0, theta0), r0) - sin(theta0)*Derivative(f(r0, theta0), theta0)/r0) assert trigsimp(df(R2.e_y).rcall(p_p).doit()) == ( sin(theta0)*Derivative(f(r0, theta0), r0) + cos(theta0)*Derivative(f(r0, theta0), theta0)/r0) assert R2.dx(R2.e_x).rcall(p_r) == 1 assert R2.dx(R2.e_x) == 1 assert R2.dx(R2.e_y).rcall(p_r) == 0 assert R2.dx(R2.e_y) == 0 circ = -R2.y*R2.e_x + R2.x*R2.e_y assert R2.dx(circ).rcall(p_r).doit() == -y0 assert R2.dy(circ).rcall(p_r) == x0 assert R2.dr(circ).rcall(p_r) == 0 assert simplify(R2.dtheta(circ).rcall(p_r)) == 1 assert (circ - R2.e_theta).rcall(s_field_r).rcall(p_r) == 0 def test_functional_diffgeom_ch6(): u0, u1, u2, v0, v1, v2, w0, w1, w2 = symbols('u0:3, v0:3, w0:3', real=True) u = u0*R2.e_x + u1*R2.e_y v = v0*R2.e_x + v1*R2.e_y wp = WedgeProduct(R2.dx, R2.dy) assert wp(u, v) == u0*v1 - u1*v0 u = u0*R3_r.e_x + u1*R3_r.e_y + u2*R3_r.e_z v = v0*R3_r.e_x + v1*R3_r.e_y + v2*R3_r.e_z w = w0*R3_r.e_x + w1*R3_r.e_y + w2*R3_r.e_z wp = WedgeProduct(R3_r.dx, R3_r.dy, R3_r.dz) assert wp( u, v, w) == Matrix(3, 3, [u0, u1, u2, v0, v1, v2, w0, w1, w2]).det() a, b, c = symbols('a, b, c', cls=Function) a_f = a(R3_r.x, R3_r.y, R3_r.z) b_f = b(R3_r.x, R3_r.y, R3_r.z) c_f = c(R3_r.x, R3_r.y, R3_r.z) theta = a_f*R3_r.dx + b_f*R3_r.dy + c_f*R3_r.dz dtheta = Differential(theta) da = Differential(a_f) db = Differential(b_f) dc = Differential(c_f) expr = dtheta - WedgeProduct( da, R3_r.dx) - WedgeProduct(db, R3_r.dy) - WedgeProduct(dc, R3_r.dz) assert expr.rcall(R3_r.e_x, R3_r.e_y) == 0 sympy-sympy-1.9/sympy/diffgeom/tests/test_hyperbolic_space.py000066400000000000000000000050271412543434000247560ustar00rootroot00000000000000r''' unit test describing the hyperbolic half-plane with the Poincare metric. This is a basic model of hyperbolic geometry on the (positive) half-space {(x,y) \in R^2 | y > 0} with the Riemannian metric ds^2 = (dx^2 + dy^2)/y^2 It has constant negative scalar curvature = -2 https://en.wikipedia.org/wiki/Poincare_half-plane_model ''' from sympy import diag from sympy.diffgeom import (twoform_to_matrix, metric_to_Christoffel_1st, metric_to_Christoffel_2nd, metric_to_Riemann_components, metric_to_Ricci_components) import sympy.diffgeom.rn from sympy.tensor.array import ImmutableDenseNDimArray def test_H2(): TP = sympy.diffgeom.TensorProduct R2 = sympy.diffgeom.rn.R2 y = R2.y dy = R2.dy dx = R2.dx g = (TP(dx, dx) + TP(dy, dy))*y**(-2) automat = twoform_to_matrix(g) mat = diag(y**(-2), y**(-2)) assert mat == automat gamma1 = metric_to_Christoffel_1st(g) assert gamma1[0, 0, 0] == 0 assert gamma1[0, 0, 1] == -y**(-3) assert gamma1[0, 1, 0] == -y**(-3) assert gamma1[0, 1, 1] == 0 assert gamma1[1, 1, 1] == -y**(-3) assert gamma1[1, 1, 0] == 0 assert gamma1[1, 0, 1] == 0 assert gamma1[1, 0, 0] == y**(-3) gamma2 = metric_to_Christoffel_2nd(g) assert gamma2[0, 0, 0] == 0 assert gamma2[0, 0, 1] == -y**(-1) assert gamma2[0, 1, 0] == -y**(-1) assert gamma2[0, 1, 1] == 0 assert gamma2[1, 1, 1] == -y**(-1) assert gamma2[1, 1, 0] == 0 assert gamma2[1, 0, 1] == 0 assert gamma2[1, 0, 0] == y**(-1) Rm = metric_to_Riemann_components(g) assert Rm[0, 0, 0, 0] == 0 assert Rm[0, 0, 0, 1] == 0 assert Rm[0, 0, 1, 0] == 0 assert Rm[0, 0, 1, 1] == 0 assert Rm[0, 1, 0, 0] == 0 assert Rm[0, 1, 0, 1] == -y**(-2) assert Rm[0, 1, 1, 0] == y**(-2) assert Rm[0, 1, 1, 1] == 0 assert Rm[1, 0, 0, 0] == 0 assert Rm[1, 0, 0, 1] == y**(-2) assert Rm[1, 0, 1, 0] == -y**(-2) assert Rm[1, 0, 1, 1] == 0 assert Rm[1, 1, 0, 0] == 0 assert Rm[1, 1, 0, 1] == 0 assert Rm[1, 1, 1, 0] == 0 assert Rm[1, 1, 1, 1] == 0 Ric = metric_to_Ricci_components(g) assert Ric[0, 0] == -y**(-2) assert Ric[0, 1] == 0 assert Ric[1, 0] == 0 assert Ric[0, 0] == -y**(-2) assert Ric == ImmutableDenseNDimArray([-y**(-2), 0, 0, -y**(-2)], (2, 2)) ## scalar curvature is -2 #TODO - it would be nice to have index contraction built-in R = (Ric[0, 0] + Ric[1, 1])*y**2 assert R == -2 ## Gauss curvature is -1 assert R/2 == -1 sympy-sympy-1.9/sympy/discrete/000077500000000000000000000000001412543434000167065ustar00rootroot00000000000000sympy-sympy-1.9/sympy/discrete/__init__.py000066400000000000000000000014041412543434000210160ustar00rootroot00000000000000"""This module contains functions which operate on discrete sequences. Transforms - ``fft``, ``ifft``, ``ntt``, ``intt``, ``fwht``, ``ifwht``, ``mobius_transform``, ``inverse_mobius_transform`` Convolutions - ``convolution``, ``convolution_fft``, ``convolution_ntt``, ``convolution_fwht``, ``convolution_subset``, ``covering_product``, ``intersecting_product`` """ from .transforms import (fft, ifft, ntt, intt, fwht, ifwht, mobius_transform, inverse_mobius_transform) from .convolutions import convolution, covering_product, intersecting_product __all__ = [ 'fft', 'ifft', 'ntt', 'intt', 'fwht', 'ifwht', 'mobius_transform', 'inverse_mobius_transform', 'convolution', 'covering_product', 'intersecting_product', ] sympy-sympy-1.9/sympy/discrete/convolutions.py000066400000000000000000000342101412543434000220220ustar00rootroot00000000000000""" Convolution (using **FFT**, **NTT**, **FWHT**), Subset Convolution, Covering Product, Intersecting Product """ from sympy.core import S, sympify from sympy.core.compatibility import as_int, iterable from sympy.core.function import expand_mul from sympy.discrete.transforms import ( fft, ifft, ntt, intt, fwht, ifwht, mobius_transform, inverse_mobius_transform) def convolution(a, b, cycle=0, dps=None, prime=None, dyadic=None, subset=None): """ Performs convolution by determining the type of desired convolution using hints. Exactly one of ``dps``, ``prime``, ``dyadic``, ``subset`` arguments should be specified explicitly for identifying the type of convolution, and the argument ``cycle`` can be specified optionally. For the default arguments, linear convolution is performed using **FFT**. Parameters ========== a, b : iterables The sequences for which convolution is performed. cycle : Integer Specifies the length for doing cyclic convolution. dps : Integer Specifies the number of decimal digits for precision for performing **FFT** on the sequence. prime : Integer Prime modulus of the form `(m 2^k + 1)` to be used for performing **NTT** on the sequence. dyadic : bool Identifies the convolution type as dyadic (*bitwise-XOR*) convolution, which is performed using **FWHT**. subset : bool Identifies the convolution type as subset convolution. Examples ======== >>> from sympy import convolution, symbols, S, I >>> u, v, w, x, y, z = symbols('u v w x y z') >>> convolution([1 + 2*I, 4 + 3*I], [S(5)/4, 6], dps=3) [1.25 + 2.5*I, 11.0 + 15.8*I, 24.0 + 18.0*I] >>> convolution([1, 2, 3], [4, 5, 6], cycle=3) [31, 31, 28] >>> convolution([111, 777], [888, 444], prime=19*2**10 + 1) [1283, 19351, 14219] >>> convolution([111, 777], [888, 444], prime=19*2**10 + 1, cycle=2) [15502, 19351] >>> convolution([u, v], [x, y, z], dyadic=True) [u*x + v*y, u*y + v*x, u*z, v*z] >>> convolution([u, v], [x, y, z], dyadic=True, cycle=2) [u*x + u*z + v*y, u*y + v*x + v*z] >>> convolution([u, v, w], [x, y, z], subset=True) [u*x, u*y + v*x, u*z + w*x, v*z + w*y] >>> convolution([u, v, w], [x, y, z], subset=True, cycle=3) [u*x + v*z + w*y, u*y + v*x, u*z + w*x] """ c = as_int(cycle) if c < 0: raise ValueError("The length for cyclic convolution " "must be non-negative") dyadic = True if dyadic else None subset = True if subset else None if sum(x is not None for x in (prime, dps, dyadic, subset)) > 1: raise TypeError("Ambiguity in determining the type of convolution") if prime is not None: ls = convolution_ntt(a, b, prime=prime) return ls if not c else [sum(ls[i::c]) % prime for i in range(c)] if dyadic: ls = convolution_fwht(a, b) elif subset: ls = convolution_subset(a, b) else: ls = convolution_fft(a, b, dps=dps) return ls if not c else [sum(ls[i::c]) for i in range(c)] #----------------------------------------------------------------------------# # # # Convolution for Complex domain # # # #----------------------------------------------------------------------------# def convolution_fft(a, b, dps=None): """ Performs linear convolution using Fast Fourier Transform. Parameters ========== a, b : iterables The sequences for which convolution is performed. dps : Integer Specifies the number of decimal digits for precision. Examples ======== >>> from sympy import S, I >>> from sympy.discrete.convolutions import convolution_fft >>> convolution_fft([2, 3], [4, 5]) [8, 22, 15] >>> convolution_fft([2, 5], [6, 7, 3]) [12, 44, 41, 15] >>> convolution_fft([1 + 2*I, 4 + 3*I], [S(5)/4, 6]) [5/4 + 5*I/2, 11 + 63*I/4, 24 + 18*I] References ========== .. [1] https://en.wikipedia.org/wiki/Convolution_theorem .. [2] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29 """ a, b = a[:], b[:] n = m = len(a) + len(b) - 1 # convolution size if n > 0 and n&(n - 1): # not a power of 2 n = 2**n.bit_length() # padding with zeros a += [S.Zero]*(n - len(a)) b += [S.Zero]*(n - len(b)) a, b = fft(a, dps), fft(b, dps) a = [expand_mul(x*y) for x, y in zip(a, b)] a = ifft(a, dps)[:m] return a #----------------------------------------------------------------------------# # # # Convolution for GF(p) # # # #----------------------------------------------------------------------------# def convolution_ntt(a, b, prime): """ Performs linear convolution using Number Theoretic Transform. Parameters ========== a, b : iterables The sequences for which convolution is performed. prime : Integer Prime modulus of the form `(m 2^k + 1)` to be used for performing **NTT** on the sequence. Examples ======== >>> from sympy.discrete.convolutions import convolution_ntt >>> convolution_ntt([2, 3], [4, 5], prime=19*2**10 + 1) [8, 22, 15] >>> convolution_ntt([2, 5], [6, 7, 3], prime=19*2**10 + 1) [12, 44, 41, 15] >>> convolution_ntt([333, 555], [222, 666], prime=19*2**10 + 1) [15555, 14219, 19404] References ========== .. [1] https://en.wikipedia.org/wiki/Convolution_theorem .. [2] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29 """ a, b, p = a[:], b[:], as_int(prime) n = m = len(a) + len(b) - 1 # convolution size if n > 0 and n&(n - 1): # not a power of 2 n = 2**n.bit_length() # padding with zeros a += [0]*(n - len(a)) b += [0]*(n - len(b)) a, b = ntt(a, p), ntt(b, p) a = [x*y % p for x, y in zip(a, b)] a = intt(a, p)[:m] return a #----------------------------------------------------------------------------# # # # Convolution for 2**n-group # # # #----------------------------------------------------------------------------# def convolution_fwht(a, b): """ Performs dyadic (*bitwise-XOR*) convolution using Fast Walsh Hadamard Transform. The convolution is automatically padded to the right with zeros, as the *radix-2 FWHT* requires the number of sample points to be a power of 2. Parameters ========== a, b : iterables The sequences for which convolution is performed. Examples ======== >>> from sympy import symbols, S, I >>> from sympy.discrete.convolutions import convolution_fwht >>> u, v, x, y = symbols('u v x y') >>> convolution_fwht([u, v], [x, y]) [u*x + v*y, u*y + v*x] >>> convolution_fwht([2, 3], [4, 5]) [23, 22] >>> convolution_fwht([2, 5 + 4*I, 7], [6*I, 7, 3 + 4*I]) [56 + 68*I, -10 + 30*I, 6 + 50*I, 48 + 32*I] >>> convolution_fwht([S(33)/7, S(55)/6, S(7)/4], [S(2)/3, 5]) [2057/42, 1870/63, 7/6, 35/4] References ========== .. [1] https://www.radioeng.cz/fulltexts/2002/02_03_40_42.pdf .. [2] https://en.wikipedia.org/wiki/Hadamard_transform """ if not a or not b: return [] a, b = a[:], b[:] n = max(len(a), len(b)) if n&(n - 1): # not a power of 2 n = 2**n.bit_length() # padding with zeros a += [S.Zero]*(n - len(a)) b += [S.Zero]*(n - len(b)) a, b = fwht(a), fwht(b) a = [expand_mul(x*y) for x, y in zip(a, b)] a = ifwht(a) return a #----------------------------------------------------------------------------# # # # Subset Convolution # # # #----------------------------------------------------------------------------# def convolution_subset(a, b): """ Performs Subset Convolution of given sequences. The indices of each argument, considered as bit strings, correspond to subsets of a finite set. The sequence is automatically padded to the right with zeros, as the definition of subset based on bitmasks (indices) requires the size of sequence to be a power of 2. Parameters ========== a, b : iterables The sequences for which convolution is performed. Examples ======== >>> from sympy import symbols, S >>> from sympy.discrete.convolutions import convolution_subset >>> u, v, x, y, z = symbols('u v x y z') >>> convolution_subset([u, v], [x, y]) [u*x, u*y + v*x] >>> convolution_subset([u, v, x], [y, z]) [u*y, u*z + v*y, x*y, x*z] >>> convolution_subset([1, S(2)/3], [3, 4]) [3, 6] >>> convolution_subset([1, 3, S(5)/7], [7]) [7, 21, 5, 0] References ========== .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf """ if not a or not b: return [] if not iterable(a) or not iterable(b): raise TypeError("Expected a sequence of coefficients for convolution") a = [sympify(arg) for arg in a] b = [sympify(arg) for arg in b] n = max(len(a), len(b)) if n&(n - 1): # not a power of 2 n = 2**n.bit_length() # padding with zeros a += [S.Zero]*(n - len(a)) b += [S.Zero]*(n - len(b)) c = [S.Zero]*n for mask in range(n): smask = mask while smask > 0: c[mask] += expand_mul(a[smask] * b[mask^smask]) smask = (smask - 1)&mask c[mask] += expand_mul(a[smask] * b[mask^smask]) return c #----------------------------------------------------------------------------# # # # Covering Product # # # #----------------------------------------------------------------------------# def covering_product(a, b): """ Returns the covering product of given sequences. The indices of each argument, considered as bit strings, correspond to subsets of a finite set. The covering product of given sequences is a sequence which contains the sum of products of the elements of the given sequences grouped by the *bitwise-OR* of the corresponding indices. The sequence is automatically padded to the right with zeros, as the definition of subset based on bitmasks (indices) requires the size of sequence to be a power of 2. Parameters ========== a, b : iterables The sequences for which covering product is to be obtained. Examples ======== >>> from sympy import symbols, S, I, covering_product >>> u, v, x, y, z = symbols('u v x y z') >>> covering_product([u, v], [x, y]) [u*x, u*y + v*x + v*y] >>> covering_product([u, v, x], [y, z]) [u*y, u*z + v*y + v*z, x*y, x*z] >>> covering_product([1, S(2)/3], [3, 4 + 5*I]) [3, 26/3 + 25*I/3] >>> covering_product([1, 3, S(5)/7], [7, 8]) [7, 53, 5, 40/7] References ========== .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf """ if not a or not b: return [] a, b = a[:], b[:] n = max(len(a), len(b)) if n&(n - 1): # not a power of 2 n = 2**n.bit_length() # padding with zeros a += [S.Zero]*(n - len(a)) b += [S.Zero]*(n - len(b)) a, b = mobius_transform(a), mobius_transform(b) a = [expand_mul(x*y) for x, y in zip(a, b)] a = inverse_mobius_transform(a) return a #----------------------------------------------------------------------------# # # # Intersecting Product # # # #----------------------------------------------------------------------------# def intersecting_product(a, b): """ Returns the intersecting product of given sequences. The indices of each argument, considered as bit strings, correspond to subsets of a finite set. The intersecting product of given sequences is the sequence which contains the sum of products of the elements of the given sequences grouped by the *bitwise-AND* of the corresponding indices. The sequence is automatically padded to the right with zeros, as the definition of subset based on bitmasks (indices) requires the size of sequence to be a power of 2. Parameters ========== a, b : iterables The sequences for which intersecting product is to be obtained. Examples ======== >>> from sympy import symbols, S, I, intersecting_product >>> u, v, x, y, z = symbols('u v x y z') >>> intersecting_product([u, v], [x, y]) [u*x + u*y + v*x, v*y] >>> intersecting_product([u, v, x], [y, z]) [u*y + u*z + v*y + x*y + x*z, v*z, 0, 0] >>> intersecting_product([1, S(2)/3], [3, 4 + 5*I]) [9 + 5*I, 8/3 + 10*I/3] >>> intersecting_product([1, 3, S(5)/7], [7, 8]) [327/7, 24, 0, 0] References ========== .. [1] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf """ if not a or not b: return [] a, b = a[:], b[:] n = max(len(a), len(b)) if n&(n - 1): # not a power of 2 n = 2**n.bit_length() # padding with zeros a += [S.Zero]*(n - len(a)) b += [S.Zero]*(n - len(b)) a, b = mobius_transform(a, subset=False), mobius_transform(b, subset=False) a = [expand_mul(x*y) for x, y in zip(a, b)] a = inverse_mobius_transform(a, subset=False) return a sympy-sympy-1.9/sympy/discrete/recurrences.py000066400000000000000000000117421412543434000216050ustar00rootroot00000000000000""" Recurrences """ from sympy.core import S, sympify from sympy.core.compatibility import as_int, iterable def linrec(coeffs, init, n): r""" Evaluation of univariate linear recurrences of homogeneous type having coefficients independent of the recurrence variable. Parameters ========== coeffs : iterable Coefficients of the recurrence init : iterable Initial values of the recurrence n : Integer Point of evaluation for the recurrence Notes ===== Let `y(n)` be the recurrence of given type, ``c`` be the sequence of coefficients, ``b`` be the sequence of initial/base values of the recurrence and ``k`` (equal to ``len(c)``) be the order of recurrence. Then, .. math :: y(n) = \begin{cases} b_n & 0 \le n < k \\ c_0 y(n-1) + c_1 y(n-2) + \cdots + c_{k-1} y(n-k) & n \ge k \end{cases} Let `x_0, x_1, \ldots, x_n` be a sequence and consider the transformation that maps each polynomial `f(x)` to `T(f(x))` where each power `x^i` is replaced by the corresponding value `x_i`. The sequence is then a solution of the recurrence if and only if `T(x^i p(x)) = 0` for each `i \ge 0` where `p(x) = x^k - c_0 x^(k-1) - \cdots - c_{k-1}` is the characteristic polynomial. Then `T(f(x)p(x)) = 0` for each polynomial `f(x)` (as it is a linear combination of powers `x^i`). Now, if `x^n` is congruent to `g(x) = a_0 x^0 + a_1 x^1 + \cdots + a_{k-1} x^{k-1}` modulo `p(x)`, then `T(x^n) = x_n` is equal to `T(g(x)) = a_0 x_0 + a_1 x_1 + \cdots + a_{k-1} x_{k-1}`. Computation of `x^n`, given `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}` is performed using exponentiation by squaring (refer to [1]_) with an additional reduction step performed to retain only first `k` powers of `x` in the representation of `x^n`. Examples ======== >>> from sympy.discrete.recurrences import linrec >>> from sympy.abc import x, y, z >>> linrec(coeffs=[1, 1], init=[0, 1], n=10) 55 >>> linrec(coeffs=[1, 1], init=[x, y], n=10) 34*x + 55*y >>> linrec(coeffs=[x, y], init=[0, 1], n=5) x**2*y + x*(x**3 + 2*x*y) + y**2 >>> linrec(coeffs=[1, 2, 3, 0, 0, 4], init=[x, y, z], n=16) 13576*x + 5676*y + 2356*z References ========== .. [1] https://en.wikipedia.org/wiki/Exponentiation_by_squaring .. [2] https://en.wikipedia.org/w/index.php?title=Modular_exponentiation§ion=6#Matrices See Also ======== sympy.polys.agca.extensions.ExtensionElement.__pow__ """ if not coeffs: return S.Zero if not iterable(coeffs): raise TypeError("Expected a sequence of coefficients for" " the recurrence") if not iterable(init): raise TypeError("Expected a sequence of values for the initialization" " of the recurrence") n = as_int(n) if n < 0: raise ValueError("Point of evaluation of recurrence must be a " "non-negative integer") c = [sympify(arg) for arg in coeffs] b = [sympify(arg) for arg in init] k = len(c) if len(b) > k: raise TypeError("Count of initial values should not exceed the " "order of the recurrence") else: b += [S.Zero]*(k - len(b)) # remaining initial values default to zero if n < k: return b[n] terms = [u*v for u, v in zip(linrec_coeffs(c, n), b)] return sum(terms[:-1], terms[-1]) def linrec_coeffs(c, n): r""" Compute the coefficients of n'th term in linear recursion sequence defined by c. `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}`. It computes the coefficients by using binary exponentiation. This function is used by `linrec` and `_eval_pow_by_cayley`. Parameters ========== c = coefficients of the divisor polynomial n = exponent of x, so dividend is x^n """ k = len(c) def _square_and_reduce(u, offset): # squares `(u_0 + u_1 x + u_2 x^2 + \cdots + u_{k-1} x^k)` (and # multiplies by `x` if offset is 1) and reduces the above result of # length upto `2k` to `k` using the characteristic equation of the # recurrence given by, `x^k = c_0 x^{k-1} + c_1 x^{k-2} + \cdots + c_{k-1}` w = [S.Zero]*(2*len(u) - 1 + offset) for i, p in enumerate(u): for j, q in enumerate(u): w[offset + i + j] += p*q for j in range(len(w) - 1, k - 1, -1): for i in range(k): w[j - i - 1] += w[j]*c[i] return w[:k] def _final_coeffs(n): # computes the final coefficient list - `cf` corresponding to the # point at which recurrence is to be evalauted - `n`, such that, # `y(n) = cf_0 y(k-1) + cf_1 y(k-2) + \cdots + cf_{k-1} y(0)` if n < k: return [S.Zero]*n + [S.One] + [S.Zero]*(k - n - 1) else: return _square_and_reduce(_final_coeffs(n // 2), n % 2) return _final_coeffs(n) sympy-sympy-1.9/sympy/discrete/tests/000077500000000000000000000000001412543434000200505ustar00rootroot00000000000000sympy-sympy-1.9/sympy/discrete/tests/__init__.py000066400000000000000000000000001412543434000221470ustar00rootroot00000000000000sympy-sympy-1.9/sympy/discrete/tests/test_convolutions.py000066400000000000000000000410661412543434000242320ustar00rootroot00000000000000from sympy import sqrt, pi, E, exp, Rational from sympy.core import S, symbols, I from sympy.discrete.convolutions import ( convolution, convolution_fft, convolution_ntt, convolution_fwht, convolution_subset, covering_product, intersecting_product) from sympy.testing.pytest import raises from sympy.abc import x, y def test_convolution(): # fft a = [1, Rational(5, 3), sqrt(3), Rational(7, 5)] b = [9, 5, 5, 4, 3, 2] c = [3, 5, 3, 7, 8] d = [1422, 6572, 3213, 5552] assert convolution(a, b) == convolution_fft(a, b) assert convolution(a, b, dps=9) == convolution_fft(a, b, dps=9) assert convolution(a, d, dps=7) == convolution_fft(d, a, dps=7) assert convolution(a, d[1:], dps=3) == convolution_fft(d[1:], a, dps=3) # prime moduli of the form (m*2**k + 1), sequence length # should be a divisor of 2**k p = 7*17*2**23 + 1 q = 19*2**10 + 1 # ntt assert convolution(d, b, prime=q) == convolution_ntt(b, d, prime=q) assert convolution(c, b, prime=p) == convolution_ntt(b, c, prime=p) assert convolution(d, c, prime=p) == convolution_ntt(c, d, prime=p) raises(TypeError, lambda: convolution(b, d, dps=5, prime=q)) raises(TypeError, lambda: convolution(b, d, dps=6, prime=q)) # fwht assert convolution(a, b, dyadic=True) == convolution_fwht(a, b) assert convolution(a, b, dyadic=False) == convolution(a, b) raises(TypeError, lambda: convolution(b, d, dps=2, dyadic=True)) raises(TypeError, lambda: convolution(b, d, prime=p, dyadic=True)) raises(TypeError, lambda: convolution(a, b, dps=2, dyadic=True)) raises(TypeError, lambda: convolution(b, c, prime=p, dyadic=True)) # subset assert convolution(a, b, subset=True) == convolution_subset(a, b) == \ convolution(a, b, subset=True, dyadic=False) == \ convolution(a, b, subset=True) assert convolution(a, b, subset=False) == convolution(a, b) raises(TypeError, lambda: convolution(a, b, subset=True, dyadic=True)) raises(TypeError, lambda: convolution(c, d, subset=True, dps=6)) raises(TypeError, lambda: convolution(a, c, subset=True, prime=q)) def test_cyclic_convolution(): # fft a = [1, Rational(5, 3), sqrt(3), Rational(7, 5)] b = [9, 5, 5, 4, 3, 2] assert convolution([1, 2, 3], [4, 5, 6], cycle=0) == \ convolution([1, 2, 3], [4, 5, 6], cycle=5) == \ convolution([1, 2, 3], [4, 5, 6]) assert convolution([1, 2, 3], [4, 5, 6], cycle=3) == [31, 31, 28] a = [Rational(1, 3), Rational(7, 3), Rational(5, 9), Rational(2, 7), Rational(5, 8)] b = [Rational(3, 5), Rational(4, 7), Rational(7, 8), Rational(8, 9)] assert convolution(a, b, cycle=0) == \ convolution(a, b, cycle=len(a) + len(b) - 1) assert convolution(a, b, cycle=4) == [Rational(87277, 26460), Rational(30521, 11340), Rational(11125, 4032), Rational(3653, 1080)] assert convolution(a, b, cycle=6) == [Rational(20177, 20160), Rational(676, 315), Rational(47, 24), Rational(3053, 1080), Rational(16397, 5292), Rational(2497, 2268)] assert convolution(a, b, cycle=9) == \ convolution(a, b, cycle=0) + [S.Zero] # ntt a = [2313, 5323532, S(3232), 42142, 42242421] b = [S(33456), 56757, 45754, 432423] assert convolution(a, b, prime=19*2**10 + 1, cycle=0) == \ convolution(a, b, prime=19*2**10 + 1, cycle=8) == \ convolution(a, b, prime=19*2**10 + 1) assert convolution(a, b, prime=19*2**10 + 1, cycle=5) == [96, 17146, 2664, 15534, 3517] assert convolution(a, b, prime=19*2**10 + 1, cycle=7) == [4643, 3458, 1260, 15534, 3517, 16314, 13688] assert convolution(a, b, prime=19*2**10 + 1, cycle=9) == \ convolution(a, b, prime=19*2**10 + 1) + [0] # fwht u, v, w, x, y = symbols('u v w x y') p, q, r, s, t = symbols('p q r s t') c = [u, v, w, x, y] d = [p, q, r, s, t] assert convolution(a, b, dyadic=True, cycle=3) == \ [2499522285783, 19861417974796, 4702176579021] assert convolution(a, b, dyadic=True, cycle=5) == [2718149225143, 2114320852171, 20571217906407, 246166418903, 1413262436976] assert convolution(c, d, dyadic=True, cycle=4) == \ [p*u + p*y + q*v + r*w + s*x + t*u + t*y, p*v + q*u + q*y + r*x + s*w + t*v, p*w + q*x + r*u + r*y + s*v + t*w, p*x + q*w + r*v + s*u + s*y + t*x] assert convolution(c, d, dyadic=True, cycle=6) == \ [p*u + q*v + r*w + r*y + s*x + t*w + t*y, p*v + q*u + r*x + s*w + s*y + t*x, p*w + q*x + r*u + s*v, p*x + q*w + r*v + s*u, p*y + t*u, q*y + t*v] # subset assert convolution(a, b, subset=True, cycle=7) == [18266671799811, 178235365533, 213958794, 246166418903, 1413262436976, 2397553088697, 1932759730434] assert convolution(a[1:], b, subset=True, cycle=4) == \ [178104086592, 302255835516, 244982785880, 3717819845434] assert convolution(a, b[:-1], subset=True, cycle=6) == [1932837114162, 178235365533, 213958794, 245166224504, 1413262436976, 2397553088697] assert convolution(c, d, subset=True, cycle=3) == \ [p*u + p*x + q*w + r*v + r*y + s*u + t*w, p*v + p*y + q*u + s*y + t*u + t*x, p*w + q*y + r*u + t*v] assert convolution(c, d, subset=True, cycle=5) == \ [p*u + q*y + t*v, p*v + q*u + r*y + t*w, p*w + r*u + s*y + t*x, p*x + q*w + r*v + s*u, p*y + t*u] raises(ValueError, lambda: convolution([1, 2, 3], [4, 5, 6], cycle=-1)) def test_convolution_fft(): assert all(convolution_fft([], x, dps=y) == [] for x in ([], [1]) for y in (None, 3)) assert convolution_fft([1, 2, 3], [4, 5, 6]) == [4, 13, 28, 27, 18] assert convolution_fft([1], [5, 6, 7]) == [5, 6, 7] assert convolution_fft([1, 3], [5, 6, 7]) == [5, 21, 25, 21] assert convolution_fft([1 + 2*I], [2 + 3*I]) == [-4 + 7*I] assert convolution_fft([1 + 2*I, 3 + 4*I, 5 + Rational(3, 5)*I], [Rational(2, 5) + Rational(4, 7)*I]) == \ [Rational(-26, 35) + I*Rational(48, 35), Rational(-38, 35) + I*Rational(116, 35), Rational(58, 35) + I*Rational(542, 175)] assert convolution_fft([Rational(3, 4), Rational(5, 6)], [Rational(7, 8), Rational(1, 3), Rational(2, 5)]) == \ [Rational(21, 32), Rational(47, 48), Rational(26, 45), Rational(1, 3)] assert convolution_fft([Rational(1, 9), Rational(2, 3), Rational(3, 5)], [Rational(2, 5), Rational(3, 7), Rational(4, 9)]) == \ [Rational(2, 45), Rational(11, 35), Rational(8152, 14175), Rational(523, 945), Rational(4, 15)] assert convolution_fft([pi, E, sqrt(2)], [sqrt(3), 1/pi, 1/E]) == \ [sqrt(3)*pi, 1 + sqrt(3)*E, E/pi + pi*exp(-1) + sqrt(6), sqrt(2)/pi + 1, sqrt(2)*exp(-1)] assert convolution_fft([2321, 33123], [5321, 6321, 71323]) == \ [12350041, 190918524, 374911166, 2362431729] assert convolution_fft([312313, 31278232], [32139631, 319631]) == \ [10037624576503, 1005370659728895, 9997492572392] raises(TypeError, lambda: convolution_fft(x, y)) raises(ValueError, lambda: convolution_fft([x, y], [y, x])) def test_convolution_ntt(): # prime moduli of the form (m*2**k + 1), sequence length # should be a divisor of 2**k p = 7*17*2**23 + 1 q = 19*2**10 + 1 r = 2*500000003 + 1 # only for sequences of length 1 or 2 # s = 2*3*5*7 # composite modulus assert all(convolution_ntt([], x, prime=y) == [] for x in ([], [1]) for y in (p, q, r)) assert convolution_ntt([2], [3], r) == [6] assert convolution_ntt([2, 3], [4], r) == [8, 12] assert convolution_ntt([32121, 42144, 4214, 4241], [32132, 3232, 87242], p) == [33867619, 459741727, 79180879, 831885249, 381344700, 369993322] assert convolution_ntt([121913, 3171831, 31888131, 12], [17882, 21292, 29921, 312], q) == \ [8158, 3065, 3682, 7090, 1239, 2232, 3744] assert convolution_ntt([12, 19, 21, 98, 67], [2, 6, 7, 8, 9], p) == \ convolution_ntt([12, 19, 21, 98, 67], [2, 6, 7, 8, 9], q) assert convolution_ntt([12, 19, 21, 98, 67], [21, 76, 17, 78, 69], p) == \ convolution_ntt([12, 19, 21, 98, 67], [21, 76, 17, 78, 69], q) raises(ValueError, lambda: convolution_ntt([2, 3], [4, 5], r)) raises(ValueError, lambda: convolution_ntt([x, y], [y, x], q)) raises(TypeError, lambda: convolution_ntt(x, y, p)) def test_convolution_fwht(): assert convolution_fwht([], []) == [] assert convolution_fwht([], [1]) == [] assert convolution_fwht([1, 2, 3], [4, 5, 6]) == [32, 13, 18, 27] assert convolution_fwht([Rational(5, 7), Rational(6, 8), Rational(7, 3)], [2, 4, Rational(6, 7)]) == \ [Rational(45, 7), Rational(61, 14), Rational(776, 147), Rational(419, 42)] a = [1, Rational(5, 3), sqrt(3), Rational(7, 5), 4 + 5*I] b = [94, 51, 53, 45, 31, 27, 13] c = [3 + 4*I, 5 + 7*I, 3, Rational(7, 6), 8] assert convolution_fwht(a, b) == [53*sqrt(3) + 366 + 155*I, 45*sqrt(3) + Rational(5848, 15) + 135*I, 94*sqrt(3) + Rational(1257, 5) + 65*I, 51*sqrt(3) + Rational(3974, 15), 13*sqrt(3) + 452 + 470*I, Rational(4513, 15) + 255*I, 31*sqrt(3) + Rational(1314, 5) + 265*I, 27*sqrt(3) + Rational(3676, 15) + 225*I] assert convolution_fwht(b, c) == [Rational(1993, 2) + 733*I, Rational(6215, 6) + 862*I, Rational(1659, 2) + 527*I, Rational(1988, 3) + 551*I, 1019 + 313*I, Rational(3955, 6) + 325*I, Rational(1175, 2) + 52*I, Rational(3253, 6) + 91*I] assert convolution_fwht(a[3:], c) == [Rational(-54, 5) + I*Rational(293, 5), -1 + I*Rational(204, 5), Rational(133, 15) + I*Rational(35, 6), Rational(409, 30) + 15*I, Rational(56, 5), 32 + 40*I, 0, 0] u, v, w, x, y, z = symbols('u v w x y z') assert convolution_fwht([u, v], [x, y]) == [u*x + v*y, u*y + v*x] assert convolution_fwht([u, v, w], [x, y]) == \ [u*x + v*y, u*y + v*x, w*x, w*y] assert convolution_fwht([u, v, w], [x, y, z]) == \ [u*x + v*y + w*z, u*y + v*x, u*z + w*x, v*z + w*y] raises(TypeError, lambda: convolution_fwht(x, y)) raises(TypeError, lambda: convolution_fwht(x*y, u + v)) def test_convolution_subset(): assert convolution_subset([], []) == [] assert convolution_subset([], [Rational(1, 3)]) == [] assert convolution_subset([6 + I*Rational(3, 7)], [Rational(2, 3)]) == [4 + I*Rational(2, 7)] a = [1, Rational(5, 3), sqrt(3), 4 + 5*I] b = [64, 71, 55, 47, 33, 29, 15] c = [3 + I*Rational(2, 3), 5 + 7*I, 7, Rational(7, 5), 9] assert convolution_subset(a, b) == [64, Rational(533, 3), 55 + 64*sqrt(3), 71*sqrt(3) + Rational(1184, 3) + 320*I, 33, 84, 15 + 33*sqrt(3), 29*sqrt(3) + 157 + 165*I] assert convolution_subset(b, c) == [192 + I*Rational(128, 3), 533 + I*Rational(1486, 3), 613 + I*Rational(110, 3), Rational(5013, 5) + I*Rational(1249, 3), 675 + 22*I, 891 + I*Rational(751, 3), 771 + 10*I, Rational(3736, 5) + 105*I] assert convolution_subset(a, c) == convolution_subset(c, a) assert convolution_subset(a[:2], b) == \ [64, Rational(533, 3), 55, Rational(416, 3), 33, 84, 15, 25] assert convolution_subset(a[:2], c) == \ [3 + I*Rational(2, 3), 10 + I*Rational(73, 9), 7, Rational(196, 15), 9, 15, 0, 0] u, v, w, x, y, z = symbols('u v w x y z') assert convolution_subset([u, v, w], [x, y]) == [u*x, u*y + v*x, w*x, w*y] assert convolution_subset([u, v, w, x], [y, z]) == \ [u*y, u*z + v*y, w*y, w*z + x*y] assert convolution_subset([u, v], [x, y, z]) == \ convolution_subset([x, y, z], [u, v]) raises(TypeError, lambda: convolution_subset(x, z)) raises(TypeError, lambda: convolution_subset(Rational(7, 3), u)) def test_covering_product(): assert covering_product([], []) == [] assert covering_product([], [Rational(1, 3)]) == [] assert covering_product([6 + I*Rational(3, 7)], [Rational(2, 3)]) == [4 + I*Rational(2, 7)] a = [1, Rational(5, 8), sqrt(7), 4 + 9*I] b = [66, 81, 95, 49, 37, 89, 17] c = [3 + I*Rational(2, 3), 51 + 72*I, 7, Rational(7, 15), 91] assert covering_product(a, b) == [66, Rational(1383, 8), 95 + 161*sqrt(7), 130*sqrt(7) + 1303 + 2619*I, 37, Rational(671, 4), 17 + 54*sqrt(7), 89*sqrt(7) + Rational(4661, 8) + 1287*I] assert covering_product(b, c) == [198 + 44*I, 7740 + 10638*I, 1412 + I*Rational(190, 3), Rational(42684, 5) + I*Rational(31202, 3), 9484 + I*Rational(74, 3), 22163 + I*Rational(27394, 3), 10621 + I*Rational(34, 3), Rational(90236, 15) + 1224*I] assert covering_product(a, c) == covering_product(c, a) assert covering_product(b, c[:-1]) == [198 + 44*I, 7740 + 10638*I, 1412 + I*Rational(190, 3), Rational(42684, 5) + I*Rational(31202, 3), 111 + I*Rational(74, 3), 6693 + I*Rational(27394, 3), 429 + I*Rational(34, 3), Rational(23351, 15) + 1224*I] assert covering_product(a, c[:-1]) == [3 + I*Rational(2, 3), Rational(339, 4) + I*Rational(1409, 12), 7 + 10*sqrt(7) + 2*sqrt(7)*I/3, -403 + 772*sqrt(7)/15 + 72*sqrt(7)*I + I*Rational(12658, 15)] u, v, w, x, y, z = symbols('u v w x y z') assert covering_product([u, v, w], [x, y]) == \ [u*x, u*y + v*x + v*y, w*x, w*y] assert covering_product([u, v, w, x], [y, z]) == \ [u*y, u*z + v*y + v*z, w*y, w*z + x*y + x*z] assert covering_product([u, v], [x, y, z]) == \ covering_product([x, y, z], [u, v]) raises(TypeError, lambda: covering_product(x, z)) raises(TypeError, lambda: covering_product(Rational(7, 3), u)) def test_intersecting_product(): assert intersecting_product([], []) == [] assert intersecting_product([], [Rational(1, 3)]) == [] assert intersecting_product([6 + I*Rational(3, 7)], [Rational(2, 3)]) == [4 + I*Rational(2, 7)] a = [1, sqrt(5), Rational(3, 8) + 5*I, 4 + 7*I] b = [67, 51, 65, 48, 36, 79, 27] c = [3 + I*Rational(2, 5), 5 + 9*I, 7, Rational(7, 19), 13] assert intersecting_product(a, b) == [195*sqrt(5) + Rational(6979, 8) + 1886*I, 178*sqrt(5) + 520 + 910*I, Rational(841, 2) + 1344*I, 192 + 336*I, 0, 0, 0, 0] assert intersecting_product(b, c) == [Rational(128553, 19) + I*Rational(9521, 5), Rational(17820, 19) + 1602*I, Rational(19264, 19), Rational(336, 19), 1846, 0, 0, 0] assert intersecting_product(a, c) == intersecting_product(c, a) assert intersecting_product(b[1:], c[:-1]) == [Rational(64788, 19) + I*Rational(8622, 5), Rational(12804, 19) + 1152*I, Rational(11508, 19), Rational(252, 19), 0, 0, 0, 0] assert intersecting_product(a, c[:-2]) == \ [Rational(-99, 5) + 10*sqrt(5) + 2*sqrt(5)*I/5 + I*Rational(3021, 40), -43 + 5*sqrt(5) + 9*sqrt(5)*I + 71*I, Rational(245, 8) + 84*I, 0] u, v, w, x, y, z = symbols('u v w x y z') assert intersecting_product([u, v, w], [x, y]) == \ [u*x + u*y + v*x + w*x + w*y, v*y, 0, 0] assert intersecting_product([u, v, w, x], [y, z]) == \ [u*y + u*z + v*y + w*y + w*z + x*y, v*z + x*z, 0, 0] assert intersecting_product([u, v], [x, y, z]) == \ intersecting_product([x, y, z], [u, v]) raises(TypeError, lambda: intersecting_product(x, z)) raises(TypeError, lambda: intersecting_product(u, Rational(8, 3))) sympy-sympy-1.9/sympy/discrete/tests/test_recurrences.py000066400000000000000000000056151412543434000240100ustar00rootroot00000000000000from sympy import Rational, fibonacci from sympy.core import S, symbols from sympy.testing.pytest import raises from sympy.discrete.recurrences import linrec def test_linrec(): assert linrec(coeffs=[1, 1], init=[1, 1], n=20) == 10946 assert linrec(coeffs=[1, 2, 3, 4, 5], init=[1, 1, 0, 2], n=10) == 1040 assert linrec(coeffs=[0, 0, 11, 13], init=[23, 27], n=25) == 59628567384 assert linrec(coeffs=[0, 0, 1, 1, 2], init=[1, 5, 3], n=15) == 165 assert linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4], n=70) == \ 56889923441670659718376223533331214868804815612050381493741233489928913241 assert linrec(coeffs=[0]*55 + [1, 1, 2, 3], init=[0]*50 + [1, 2, 3], n=4000) == \ 702633573874937994980598979769135096432444135301118916539 assert linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4], n=10**4) assert linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4], n=10**5) assert all(linrec(coeffs=[1, 1], init=[0, 1], n=n) == fibonacci(n) for n in range(95, 115)) assert all(linrec(coeffs=[1, 1], init=[1, 1], n=n) == fibonacci(n + 1) for n in range(595, 615)) a = [S.Half, Rational(3, 4), Rational(5, 6), 7, Rational(8, 9), Rational(3, 5)] b = [1, 2, 8, Rational(5, 7), Rational(3, 7), Rational(2, 9), 6] x, y, z = symbols('x y z') assert linrec(coeffs=a[:5], init=b[:4], n=80) == \ Rational(1726244235456268979436592226626304376013002142588105090705187189, 1960143456748895967474334873705475211264) assert linrec(coeffs=a[:4], init=b[:4], n=50) == \ Rational(368949940033050147080268092104304441, 504857282956046106624) assert linrec(coeffs=a[3:], init=b[:3], n=35) == \ Rational(97409272177295731943657945116791049305244422833125109, 814315512679031689453125) assert linrec(coeffs=[0]*60 + [Rational(2, 3), Rational(4, 5)], init=b, n=3000) == \ Rational(26777668739896791448594650497024, 48084516708184142230517578125) raises(TypeError, lambda: linrec(coeffs=[11, 13, 15, 17], init=[1, 2, 3, 4, 5], n=1)) raises(TypeError, lambda: linrec(coeffs=a[:4], init=b[:5], n=10000)) raises(ValueError, lambda: linrec(coeffs=a[:4], init=b[:4], n=-10000)) raises(TypeError, lambda: linrec(x, b, n=10000)) raises(TypeError, lambda: linrec(a, y, n=10000)) assert linrec(coeffs=[x, y, z], init=[1, 1, 1], n=4) == \ x**2 + x*y + x*z + y + z assert linrec(coeffs=[1, 2, 1], init=[x, y, z], n=20) == \ 269542*x + 664575*y + 578949*z assert linrec(coeffs=[0, 3, 1, 2], init=[x, y], n=30) == \ 58516436*x + 56372788*y assert linrec(coeffs=[0]*50 + [1, 2, 3], init=[x, y, z], n=1000) == \ 11477135884896*x + 25999077948732*y + 41975630244216*z assert linrec(coeffs=[], init=[1, 1], n=20) == 0 assert linrec(coeffs=[x, y, z], init=[1, 2, 3], n=2) == 3 sympy-sympy-1.9/sympy/discrete/tests/test_transforms.py000066400000000000000000000126351412543434000236660ustar00rootroot00000000000000from sympy import sqrt from sympy.core import S, Symbol, symbols, I, Rational from sympy.discrete import (fft, ifft, ntt, intt, fwht, ifwht, mobius_transform, inverse_mobius_transform) from sympy.testing.pytest import raises def test_fft_ifft(): assert all(tf(ls) == ls for tf in (fft, ifft) for ls in ([], [Rational(5, 3)])) ls = list(range(6)) fls = [15, -7*sqrt(2)/2 - 4 - sqrt(2)*I/2 + 2*I, 2 + 3*I, -4 + 7*sqrt(2)/2 - 2*I - sqrt(2)*I/2, -3, -4 + 7*sqrt(2)/2 + sqrt(2)*I/2 + 2*I, 2 - 3*I, -7*sqrt(2)/2 - 4 - 2*I + sqrt(2)*I/2] assert fft(ls) == fls assert ifft(fls) == ls + [S.Zero]*2 ls = [1 + 2*I, 3 + 4*I, 5 + 6*I] ifls = [Rational(9, 4) + 3*I, I*Rational(-7, 4), Rational(3, 4) + I, -2 - I/4] assert ifft(ls) == ifls assert fft(ifls) == ls + [S.Zero] x = Symbol('x', real=True) raises(TypeError, lambda: fft(x)) raises(ValueError, lambda: ifft([x, 2*x, 3*x**2, 4*x**3])) def test_ntt_intt(): # prime moduli of the form (m*2**k + 1), sequence length # should be a divisor of 2**k p = 7*17*2**23 + 1 q = 2*500000003 + 1 # only for sequences of length 1 or 2 r = 2*3*5*7 # composite modulus assert all(tf(ls, p) == ls for tf in (ntt, intt) for ls in ([], [5])) ls = list(range(6)) nls = [15, 801133602, 738493201, 334102277, 998244350, 849020224, 259751156, 12232587] assert ntt(ls, p) == nls assert intt(nls, p) == ls + [0]*2 ls = [1 + 2*I, 3 + 4*I, 5 + 6*I] x = Symbol('x', integer=True) raises(TypeError, lambda: ntt(x, p)) raises(ValueError, lambda: intt([x, 2*x, 3*x**2, 4*x**3], p)) raises(ValueError, lambda: intt(ls, p)) raises(ValueError, lambda: ntt([1.2, 2.1, 3.5], p)) raises(ValueError, lambda: ntt([3, 5, 6], q)) raises(ValueError, lambda: ntt([4, 5, 7], r)) raises(ValueError, lambda: ntt([1.0, 2.0, 3.0], p)) def test_fwht_ifwht(): assert all(tf(ls) == ls for tf in (fwht, ifwht) \ for ls in ([], [Rational(7, 4)])) ls = [213, 321, 43235, 5325, 312, 53] fls = [49459, 38061, -47661, -37759, 48729, 37543, -48391, -38277] assert fwht(ls) == fls assert ifwht(fls) == ls + [S.Zero]*2 ls = [S.Half + 2*I, Rational(3, 7) + 4*I, Rational(5, 6) + 6*I, Rational(7, 3), Rational(9, 4)] ifls = [Rational(533, 672) + I*Rational(3, 2), Rational(23, 224) + I/2, Rational(1, 672), Rational(107, 224) - I, Rational(155, 672) + I*Rational(3, 2), Rational(-103, 224) + I/2, Rational(-377, 672), Rational(-19, 224) - I] assert ifwht(ls) == ifls assert fwht(ifls) == ls + [S.Zero]*3 x, y = symbols('x y') raises(TypeError, lambda: fwht(x)) ls = [x, 2*x, 3*x**2, 4*x**3] ifls = [x**3 + 3*x**2/4 + x*Rational(3, 4), -x**3 + 3*x**2/4 - x/4, -x**3 - 3*x**2/4 + x*Rational(3, 4), x**3 - 3*x**2/4 - x/4] assert ifwht(ls) == ifls assert fwht(ifls) == ls ls = [x, y, x**2, y**2, x*y] fls = [x**2 + x*y + x + y**2 + y, x**2 + x*y + x - y**2 - y, -x**2 + x*y + x - y**2 + y, -x**2 + x*y + x + y**2 - y, x**2 - x*y + x + y**2 + y, x**2 - x*y + x - y**2 - y, -x**2 - x*y + x - y**2 + y, -x**2 - x*y + x + y**2 - y] assert fwht(ls) == fls assert ifwht(fls) == ls + [S.Zero]*3 ls = list(range(6)) assert fwht(ls) == [x*8 for x in ifwht(ls)] def test_mobius_transform(): assert all(tf(ls, subset=subset) == ls for ls in ([], [Rational(7, 4)]) for subset in (True, False) for tf in (mobius_transform, inverse_mobius_transform)) w, x, y, z = symbols('w x y z') assert mobius_transform([x, y]) == [x, x + y] assert inverse_mobius_transform([x, x + y]) == [x, y] assert mobius_transform([x, y], subset=False) == [x + y, y] assert inverse_mobius_transform([x + y, y], subset=False) == [x, y] assert mobius_transform([w, x, y, z]) == [w, w + x, w + y, w + x + y + z] assert inverse_mobius_transform([w, w + x, w + y, w + x + y + z]) == \ [w, x, y, z] assert mobius_transform([w, x, y, z], subset=False) == \ [w + x + y + z, x + z, y + z, z] assert inverse_mobius_transform([w + x + y + z, x + z, y + z, z], subset=False) == \ [w, x, y, z] ls = [Rational(2, 3), Rational(6, 7), Rational(5, 8), 9, Rational(5, 3) + 7*I] mls = [Rational(2, 3), Rational(32, 21), Rational(31, 24), Rational(1873, 168), Rational(7, 3) + 7*I, Rational(67, 21) + 7*I, Rational(71, 24) + 7*I, Rational(2153, 168) + 7*I] assert mobius_transform(ls) == mls assert inverse_mobius_transform(mls) == ls + [S.Zero]*3 mls = [Rational(2153, 168) + 7*I, Rational(69, 7), Rational(77, 8), 9, Rational(5, 3) + 7*I, 0, 0, 0] assert mobius_transform(ls, subset=False) == mls assert inverse_mobius_transform(mls, subset=False) == ls + [S.Zero]*3 ls = ls[:-1] mls = [Rational(2, 3), Rational(32, 21), Rational(31, 24), Rational(1873, 168)] assert mobius_transform(ls) == mls assert inverse_mobius_transform(mls) == ls mls = [Rational(1873, 168), Rational(69, 7), Rational(77, 8), 9] assert mobius_transform(ls, subset=False) == mls assert inverse_mobius_transform(mls, subset=False) == ls raises(TypeError, lambda: mobius_transform(x, subset=True)) raises(TypeError, lambda: inverse_mobius_transform(y, subset=False)) sympy-sympy-1.9/sympy/discrete/transforms.py000066400000000000000000000266431412543434000214710ustar00rootroot00000000000000""" Discrete Fourier Transform, Number Theoretic Transform, Walsh Hadamard Transform, Mobius Transform """ from sympy.core import S, Symbol, sympify from sympy.core.compatibility import as_int, iterable from sympy.core.function import expand_mul from sympy.core.numbers import pi, I from sympy.functions.elementary.trigonometric import sin, cos from sympy.ntheory import isprime, primitive_root from sympy.utilities.iterables import ibin #----------------------------------------------------------------------------# # # # Discrete Fourier Transform # # # #----------------------------------------------------------------------------# def _fourier_transform(seq, dps, inverse=False): """Utility function for the Discrete Fourier Transform""" if not iterable(seq): raise TypeError("Expected a sequence of numeric coefficients " "for Fourier Transform") a = [sympify(arg) for arg in seq] if any(x.has(Symbol) for x in a): raise ValueError("Expected non-symbolic coefficients") n = len(a) if n < 2: return a b = n.bit_length() - 1 if n&(n - 1): # not a power of 2 b += 1 n = 2**b a += [S.Zero]*(n - len(a)) for i in range(1, n): j = int(ibin(i, b, str=True)[::-1], 2) if i < j: a[i], a[j] = a[j], a[i] ang = -2*pi/n if inverse else 2*pi/n if dps is not None: ang = ang.evalf(dps + 2) w = [cos(ang*i) + I*sin(ang*i) for i in range(n // 2)] h = 2 while h <= n: hf, ut = h // 2, n // h for i in range(0, n, h): for j in range(hf): u, v = a[i + j], expand_mul(a[i + j + hf]*w[ut * j]) a[i + j], a[i + j + hf] = u + v, u - v h *= 2 if inverse: a = [(x/n).evalf(dps) for x in a] if dps is not None \ else [x/n for x in a] return a def fft(seq, dps=None): r""" Performs the Discrete Fourier Transform (**DFT**) in the complex domain. The sequence is automatically padded to the right with zeros, as the *radix-2 FFT* requires the number of sample points to be a power of 2. This method should be used with default arguments only for short sequences as the complexity of expressions increases with the size of the sequence. Parameters ========== seq : iterable The sequence on which **DFT** is to be applied. dps : Integer Specifies the number of decimal digits for precision. Examples ======== >>> from sympy import fft, ifft >>> fft([1, 2, 3, 4]) [10, -2 - 2*I, -2, -2 + 2*I] >>> ifft(_) [1, 2, 3, 4] >>> ifft([1, 2, 3, 4]) [5/2, -1/2 + I/2, -1/2, -1/2 - I/2] >>> fft(_) [1, 2, 3, 4] >>> ifft([1, 7, 3, 4], dps=15) [3.75, -0.5 - 0.75*I, -1.75, -0.5 + 0.75*I] >>> fft(_) [1.0, 7.0, 3.0, 4.0] References ========== .. [1] https://en.wikipedia.org/wiki/Cooley%E2%80%93Tukey_FFT_algorithm .. [2] http://mathworld.wolfram.com/FastFourierTransform.html """ return _fourier_transform(seq, dps=dps) def ifft(seq, dps=None): return _fourier_transform(seq, dps=dps, inverse=True) ifft.__doc__ = fft.__doc__ #----------------------------------------------------------------------------# # # # Number Theoretic Transform # # # #----------------------------------------------------------------------------# def _number_theoretic_transform(seq, prime, inverse=False): """Utility function for the Number Theoretic Transform""" if not iterable(seq): raise TypeError("Expected a sequence of integer coefficients " "for Number Theoretic Transform") p = as_int(prime) if not isprime(p): raise ValueError("Expected prime modulus for " "Number Theoretic Transform") a = [as_int(x) % p for x in seq] n = len(a) if n < 1: return a b = n.bit_length() - 1 if n&(n - 1): b += 1 n = 2**b if (p - 1) % n: raise ValueError("Expected prime modulus of the form (m*2**k + 1)") a += [0]*(n - len(a)) for i in range(1, n): j = int(ibin(i, b, str=True)[::-1], 2) if i < j: a[i], a[j] = a[j], a[i] pr = primitive_root(p) rt = pow(pr, (p - 1) // n, p) if inverse: rt = pow(rt, p - 2, p) w = [1]*(n // 2) for i in range(1, n // 2): w[i] = w[i - 1]*rt % p h = 2 while h <= n: hf, ut = h // 2, n // h for i in range(0, n, h): for j in range(hf): u, v = a[i + j], a[i + j + hf]*w[ut * j] a[i + j], a[i + j + hf] = (u + v) % p, (u - v) % p h *= 2 if inverse: rv = pow(n, p - 2, p) a = [x*rv % p for x in a] return a def ntt(seq, prime): r""" Performs the Number Theoretic Transform (**NTT**), which specializes the Discrete Fourier Transform (**DFT**) over quotient ring `Z/pZ` for prime `p` instead of complex numbers `C`. The sequence is automatically padded to the right with zeros, as the *radix-2 NTT* requires the number of sample points to be a power of 2. Parameters ========== seq : iterable The sequence on which **DFT** is to be applied. prime : Integer Prime modulus of the form `(m 2^k + 1)` to be used for performing **NTT** on the sequence. Examples ======== >>> from sympy import ntt, intt >>> ntt([1, 2, 3, 4], prime=3*2**8 + 1) [10, 643, 767, 122] >>> intt(_, 3*2**8 + 1) [1, 2, 3, 4] >>> intt([1, 2, 3, 4], prime=3*2**8 + 1) [387, 415, 384, 353] >>> ntt(_, prime=3*2**8 + 1) [1, 2, 3, 4] References ========== .. [1] http://www.apfloat.org/ntt.html .. [2] http://mathworld.wolfram.com/NumberTheoreticTransform.html .. [3] https://en.wikipedia.org/wiki/Discrete_Fourier_transform_(general%29 """ return _number_theoretic_transform(seq, prime=prime) def intt(seq, prime): return _number_theoretic_transform(seq, prime=prime, inverse=True) intt.__doc__ = ntt.__doc__ #----------------------------------------------------------------------------# # # # Walsh Hadamard Transform # # # #----------------------------------------------------------------------------# def _walsh_hadamard_transform(seq, inverse=False): """Utility function for the Walsh Hadamard Transform""" if not iterable(seq): raise TypeError("Expected a sequence of coefficients " "for Walsh Hadamard Transform") a = [sympify(arg) for arg in seq] n = len(a) if n < 2: return a if n&(n - 1): n = 2**n.bit_length() a += [S.Zero]*(n - len(a)) h = 2 while h <= n: hf = h // 2 for i in range(0, n, h): for j in range(hf): u, v = a[i + j], a[i + j + hf] a[i + j], a[i + j + hf] = u + v, u - v h *= 2 if inverse: a = [x/n for x in a] return a def fwht(seq): r""" Performs the Walsh Hadamard Transform (**WHT**), and uses Hadamard ordering for the sequence. The sequence is automatically padded to the right with zeros, as the *radix-2 FWHT* requires the number of sample points to be a power of 2. Parameters ========== seq : iterable The sequence on which WHT is to be applied. Examples ======== >>> from sympy import fwht, ifwht >>> fwht([4, 2, 2, 0, 0, 2, -2, 0]) [8, 0, 8, 0, 8, 8, 0, 0] >>> ifwht(_) [4, 2, 2, 0, 0, 2, -2, 0] >>> ifwht([19, -1, 11, -9, -7, 13, -15, 5]) [2, 0, 4, 0, 3, 10, 0, 0] >>> fwht(_) [19, -1, 11, -9, -7, 13, -15, 5] References ========== .. [1] https://en.wikipedia.org/wiki/Hadamard_transform .. [2] https://en.wikipedia.org/wiki/Fast_Walsh%E2%80%93Hadamard_transform """ return _walsh_hadamard_transform(seq) def ifwht(seq): return _walsh_hadamard_transform(seq, inverse=True) ifwht.__doc__ = fwht.__doc__ #----------------------------------------------------------------------------# # # # Mobius Transform for Subset Lattice # # # #----------------------------------------------------------------------------# def _mobius_transform(seq, sgn, subset): r"""Utility function for performing Mobius Transform using Yate's Dynamic Programming method""" if not iterable(seq): raise TypeError("Expected a sequence of coefficients") a = [sympify(arg) for arg in seq] n = len(a) if n < 2: return a if n&(n - 1): n = 2**n.bit_length() a += [S.Zero]*(n - len(a)) if subset: i = 1 while i < n: for j in range(n): if j & i: a[j] += sgn*a[j ^ i] i *= 2 else: i = 1 while i < n: for j in range(n): if j & i: continue a[j] += sgn*a[j ^ i] i *= 2 return a def mobius_transform(seq, subset=True): r""" Performs the Mobius Transform for subset lattice with indices of sequence as bitmasks. The indices of each argument, considered as bit strings, correspond to subsets of a finite set. The sequence is automatically padded to the right with zeros, as the definition of subset/superset based on bitmasks (indices) requires the size of sequence to be a power of 2. Parameters ========== seq : iterable The sequence on which Mobius Transform is to be applied. subset : bool Specifies if Mobius Transform is applied by enumerating subsets or supersets of the given set. Examples ======== >>> from sympy import symbols >>> from sympy import mobius_transform, inverse_mobius_transform >>> x, y, z = symbols('x y z') >>> mobius_transform([x, y, z]) [x, x + y, x + z, x + y + z] >>> inverse_mobius_transform(_) [x, y, z, 0] >>> mobius_transform([x, y, z], subset=False) [x + y + z, y, z, 0] >>> inverse_mobius_transform(_, subset=False) [x, y, z, 0] >>> mobius_transform([1, 2, 3, 4]) [1, 3, 4, 10] >>> inverse_mobius_transform(_) [1, 2, 3, 4] >>> mobius_transform([1, 2, 3, 4], subset=False) [10, 6, 7, 4] >>> inverse_mobius_transform(_, subset=False) [1, 2, 3, 4] References ========== .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_inversion_formula .. [2] https://people.csail.mit.edu/rrw/presentations/subset-conv.pdf .. [3] https://arxiv.org/pdf/1211.0189.pdf """ return _mobius_transform(seq, sgn=+1, subset=subset) def inverse_mobius_transform(seq, subset=True): return _mobius_transform(seq, sgn=-1, subset=subset) inverse_mobius_transform.__doc__ = mobius_transform.__doc__ sympy-sympy-1.9/sympy/external/000077500000000000000000000000001412543434000167265ustar00rootroot00000000000000sympy-sympy-1.9/sympy/external/__init__.py000066400000000000000000000011021412543434000210310ustar00rootroot00000000000000""" Unified place for determining if external dependencies are installed or not. You should import all external modules using the import_module() function. For example >>> from sympy.external import import_module >>> numpy = import_module('numpy') If the resulting library is not installed, or if the installed version is less than a given minimum version, the function will return None. Otherwise, it will return the library. See the docstring of import_module() for more information. """ from sympy.external.importtools import import_module __all__ = ['import_module'] sympy-sympy-1.9/sympy/external/gmpy.py000066400000000000000000000055361412543434000202650ustar00rootroot00000000000000import os import mpmath.libmp as mlib from sympy.external import import_module __all__ = [ # GROUND_TYPES is either 'gmpy' or 'python' depending on which is used. If # gmpy is installed then it will be used unless the environment variable # SYMPY_GROUND_TYPES is set to something other than 'auto', 'gmpy', or # 'gmpy2'. 'GROUND_TYPES', # If HAS_GMPY is 0, no supported version of gmpy is available. Otherwise, # HAS_GMPY will be 2 for gmpy2 if GROUND_TYPES is 'gmpy'. It used to be # possible for HAS_GMPY to be 1 for gmpy but gmpy is no longer supported. 'HAS_GMPY', # SYMPY_INTS is a tuple containing the base types for valid integer types. # This is either (int,) or (int, type(mpz(0))) depending on GROUND_TYPES. 'SYMPY_INTS', # MPQ is either gmpy.mpq or the Python equivalent from # sympy.external.pythonmpq 'MPQ', # MPZ is either gmpy.mpz or int. 'MPZ', # Either the gmpy or the mpmath function 'factorial', # isqrt from gmpy or mpmath 'sqrt', ] # # SYMPY_GROUND_TYPES can be gmpy, gmpy2, python or auto # GROUND_TYPES = os.environ.get('SYMPY_GROUND_TYPES', 'auto').lower() # # Try to import gmpy2 by default. If gmpy or gmpy2 is specified in # SYMPY_GROUND_TYPES then warn if gmpy2 is not found. In all cases there is a # fallback based on pure Python int and PythonMPQ that should still work fine. # if GROUND_TYPES in ('auto', 'gmpy', 'gmpy2'): # Actually import gmpy2 gmpy = import_module('gmpy2', min_module_version='2.0.0', module_version_attr='version', module_version_attr_call_args=()) # Warn if user explicitly asked for gmpy but it isn't available. if gmpy is None and GROUND_TYPES in ('gmpy', 'gmpy2'): from warnings import warn warn("gmpy library is not installed, switching to 'python' ground types") elif GROUND_TYPES == 'python': # The user asked for python so ignore gmpy2 module. gmpy = None else: # Invalid value for SYMPY_GROUND_TYPES. Ignore the gmpy2 module. from warnings import warn warn("SYMPY_GROUND_TYPES environment variable unrecognised. " "Should be 'python', 'auto', 'gmpy', or 'gmpy2'") gmpy = None # # At this point gmpy will be None if gmpy2 was not successfully imported or if # the environment variable SYMPY_GROUND_TYPES was set to 'python' (or some # unrecognised value). The two blocks below define the values exported by this # module in each case. # if gmpy is not None: HAS_GMPY = 2 GROUND_TYPES = 'gmpy' SYMPY_INTS = (int, type(gmpy.mpz(0))) MPZ = gmpy.mpz MPQ = gmpy.mpq factorial = gmpy.fac sqrt = gmpy.isqrt else: from .pythonmpq import PythonMPQ HAS_GMPY = 0 GROUND_TYPES = 'python' SYMPY_INTS = (int,) MPZ = int MPQ = PythonMPQ factorial = lambda x: int(mlib.ifac(x)) sqrt = lambda x: int(mlib.isqrt(x)) sympy-sympy-1.9/sympy/external/importtools.py000066400000000000000000000172441412543434000217030ustar00rootroot00000000000000"""Tools to assist importing optional external modules.""" import sys import re # Override these in the module to change the default warning behavior. # For example, you might set both to False before running the tests so that # warnings are not printed to the console, or set both to True for debugging. WARN_NOT_INSTALLED = None # Default is False WARN_OLD_VERSION = None # Default is True def __sympy_debug(): # helper function from sympy/__init__.py # We don't just import SYMPY_DEBUG from that file because we don't want to # import all of sympy just to use this module. import os debug_str = os.getenv('SYMPY_DEBUG', 'False') if debug_str in ('True', 'False'): return eval(debug_str) else: raise RuntimeError("unrecognized value for SYMPY_DEBUG: %s" % debug_str) if __sympy_debug(): WARN_OLD_VERSION = True WARN_NOT_INSTALLED = True _component_re = re.compile(r'(\d+ | [a-z]+ | \.)', re.VERBOSE) def version_tuple(vstring): # Parse a version string to a tuple e.g. '1.2' -> (1, 2) # Simplified from distutils.version.LooseVersion which was deprecated in # Python 3.10. components = [] for x in _component_re.split(vstring): if x and x != '.': try: x = int(x) except ValueError: pass components.append(x) return components def import_module(module, min_module_version=None, min_python_version=None, warn_not_installed=None, warn_old_version=None, module_version_attr='__version__', module_version_attr_call_args=None, import_kwargs={}, catch=()): """ Import and return a module if it is installed. If the module is not installed, it returns None. A minimum version for the module can be given as the keyword argument min_module_version. This should be comparable against the module version. By default, module.__version__ is used to get the module version. To override this, set the module_version_attr keyword argument. If the attribute of the module to get the version should be called (e.g., module.version()), then set module_version_attr_call_args to the args such that module.module_version_attr(*module_version_attr_call_args) returns the module's version. If the module version is less than min_module_version using the Python < comparison, None will be returned, even if the module is installed. You can use this to keep from importing an incompatible older version of a module. You can also specify a minimum Python version by using the min_python_version keyword argument. This should be comparable against sys.version_info. If the keyword argument warn_not_installed is set to True, the function will emit a UserWarning when the module is not installed. If the keyword argument warn_old_version is set to True, the function will emit a UserWarning when the library is installed, but cannot be imported because of the min_module_version or min_python_version options. Note that because of the way warnings are handled, a warning will be emitted for each module only once. You can change the default warning behavior by overriding the values of WARN_NOT_INSTALLED and WARN_OLD_VERSION in sympy.external.importtools. By default, WARN_NOT_INSTALLED is False and WARN_OLD_VERSION is True. This function uses __import__() to import the module. To pass additional options to __import__(), use the import_kwargs keyword argument. For example, to import a submodule A.B, you must pass a nonempty fromlist option to __import__. See the docstring of __import__(). This catches ImportError to determine if the module is not installed. To catch additional errors, pass them as a tuple to the catch keyword argument. Examples ======== >>> from sympy.external import import_module >>> numpy = import_module('numpy') >>> numpy = import_module('numpy', min_python_version=(2, 7), ... warn_old_version=False) >>> numpy = import_module('numpy', min_module_version='1.5', ... warn_old_version=False) # numpy.__version__ is a string >>> # gmpy does not have __version__, but it does have gmpy.version() >>> gmpy = import_module('gmpy', min_module_version='1.14', ... module_version_attr='version', module_version_attr_call_args=(), ... warn_old_version=False) >>> # To import a submodule, you must pass a nonempty fromlist to >>> # __import__(). The values do not matter. >>> p3 = import_module('mpl_toolkits.mplot3d', ... import_kwargs={'fromlist':['something']}) >>> # matplotlib.pyplot can raise RuntimeError when the display cannot be opened >>> matplotlib = import_module('matplotlib', ... import_kwargs={'fromlist':['pyplot']}, catch=(RuntimeError,)) """ # keyword argument overrides default, and global variable overrides # keyword argument. warn_old_version = (WARN_OLD_VERSION if WARN_OLD_VERSION is not None else warn_old_version or True) warn_not_installed = (WARN_NOT_INSTALLED if WARN_NOT_INSTALLED is not None else warn_not_installed or False) import warnings # Check Python first so we don't waste time importing a module we can't use if min_python_version: if sys.version_info < min_python_version: if warn_old_version: warnings.warn("Python version is too old to use %s " "(%s or newer required)" % ( module, '.'.join(map(str, min_python_version))), UserWarning, stacklevel=2) return # PyPy 1.6 has rudimentary NumPy support and importing it produces errors, so skip it if module == 'numpy' and '__pypy__' in sys.builtin_module_names: return try: mod = __import__(module, **import_kwargs) ## there's something funny about imports with matplotlib and py3k. doing ## from matplotlib import collections ## gives python's stdlib collections module. explicitly re-importing ## the module fixes this. from_list = import_kwargs.get('fromlist', tuple()) for submod in from_list: if submod == 'collections' and mod.__name__ == 'matplotlib': __import__(module + '.' + submod) except ImportError: if warn_not_installed: warnings.warn("%s module is not installed" % module, UserWarning, stacklevel=2) return except catch as e: if warn_not_installed: warnings.warn( "%s module could not be used (%s)" % (module, repr(e)), stacklevel=2) return if min_module_version: modversion = getattr(mod, module_version_attr) if module_version_attr_call_args is not None: modversion = modversion(*module_version_attr_call_args) if version_tuple(modversion) < version_tuple(min_module_version): if warn_old_version: # Attempt to create a pretty string version of the version if isinstance(min_module_version, str): verstr = min_module_version elif isinstance(min_module_version, (tuple, list)): verstr = '.'.join(map(str, min_module_version)) else: # Either don't know what this is. Hopefully # it's something that has a nice str version, like an int. verstr = str(min_module_version) warnings.warn("%s version is too old to use " "(%s or newer required)" % (module, verstr), UserWarning, stacklevel=2) return return mod sympy-sympy-1.9/sympy/external/pythonmpq.py000066400000000000000000000271361412543434000213500ustar00rootroot00000000000000""" PythonMPQ: Rational number type based on Python integers. This class is intended as a pure Python fallback for when gmpy2 is not installed. If gmpy2 is installed then its mpq type will be used instead. The mpq type is around 20x faster. We could just use the stdlib Fraction class here but that is slower: from fractions import Fraction from sympy.external.pythonmpq import PythonMPQ nums = range(1000) dens = range(5, 1005) rats = [Fraction(n, d) for n, d in zip(nums, dens)] sum(rats) # <--- 24 milliseconds rats = [PythonMPQ(n, d) for n, d in zip(nums, dens)] sum(rats) # <--- 7 milliseconds Both mpq and Fraction have some awkward features like the behaviour of division with // and %: >>> from fractions import Fraction >>> Fraction(2, 3) % Fraction(1, 4) 1/6 For the QQ domain we don't want this behaviour because there should be no remainder when dividing rational numbers. SymPy doesn't make use of this aspect of mpq when gmpy2 is installed. Since this class is a fallback for that case we don't bother implementing e.g. __mod__ so that we can be sure we aren't using it when gmpy2 is installed either. """ import operator from math import gcd from decimal import Decimal from fractions import Fraction import sys # Used for __hash__ _PyHASH_MODULUS = sys.hash_info.modulus _PyHASH_INF = sys.hash_info.inf class PythonMPQ: """Rational number implementation that is intended to be compatible with gmpy2's mpq. Also slightly faster than fractions.Fraction. PythonMPQ should be treated as immutable although no effort is made to prevent mutation (since that might slow down calculations). """ __slots__ = ('numerator', 'denominator') def __new__(cls, numerator, denominator=None): """Construct PythonMPQ with gcd computation and checks""" if denominator is not None: # # PythonMPQ(n, d): require n and d to be int and d != 0 # if isinstance(numerator, int) and isinstance(denominator, int): # This is the slow part: divisor = gcd(numerator, denominator) numerator //= divisor denominator //= divisor return cls._new_check(numerator, denominator) else: # # PythonMPQ(q) # # Here q can be PythonMPQ, int, Decimal, float, Fraction or str # if isinstance(numerator, int): return cls._new(numerator, 1) elif isinstance(numerator, PythonMPQ): return cls._new(numerator.numerator, numerator.denominator) # Let Fraction handle Decimal/float conversion and str parsing if isinstance(numerator, (Decimal, float, str)): numerator = Fraction(numerator) if isinstance(numerator, Fraction): return cls._new(numerator.numerator, numerator.denominator) # # Reject everything else. This is more strict than mpq which allows # things like mpq(Fraction, Fraction) or mpq(Decimal, any). The mpq # behaviour is somewhat inconsistent so we choose to accept only a # more strict subset of what mpq allows. # raise TypeError("PythonMPQ() requires numeric or string argument") @classmethod def _new_check(cls, numerator, denominator): """Construct PythonMPQ, check divide by zero and canonicalize signs""" if not denominator: raise ZeroDivisionError(f'Zero divisor {numerator}/{denominator}') elif denominator < 0: numerator = -numerator denominator = -denominator return cls._new(numerator, denominator) @classmethod def _new(cls, numerator, denominator): """Construct PythonMPQ efficiently (no checks)""" obj = super().__new__(cls) obj.numerator = numerator obj.denominator = denominator return obj def __int__(self): """Convert to int (truncates towards zero)""" p, q = self.numerator, self.denominator if p < 0: return -(-p//q) return p//q def __float__(self): """Convert to float (approximately)""" return self.numerator / self.denominator def __bool__(self): """True/False if nonzero/zero""" return bool(self.numerator) def __eq__(self, other): """Compare equal with PythonMPQ, int, float, Decimal or Fraction""" if isinstance(other, PythonMPQ): return (self.numerator == other.numerator and self.denominator == other.denominator) elif isinstance(other, self._compatible_types): return self.__eq__(PythonMPQ(other)) else: return NotImplemented # The hashing algorithm for Fraction changed in Python 3.8 if sys.version_info >= (3, 8): # # Hash for Python 3.8 onwards # def __hash__(self): """hash - same as mpq/Fraction""" try: dinv = pow(self.denominator, -1, _PyHASH_MODULUS) except ValueError: hash_ = _PyHASH_INF else: hash_ = hash(hash(abs(self.numerator)) * dinv) result = hash_ if self.numerator >= 0 else -hash_ return -2 if result == -1 else result else: # # Hash for Python < 3.7 # def __hash__(self): """hash - same as mpq/Fraction""" # This is from fractions.py in the stdlib. dinv = pow(self.denominator, _PyHASH_MODULUS - 2, _PyHASH_MODULUS) if not dinv: hash_ = _PyHASH_INF else: hash_ = abs(self.numerator) * dinv % _PyHASH_MODULUS result = hash_ if self >= 0 else -hash_ return -2 if result == -1 else result def __reduce__(self): """Deconstruct for pickling""" return type(self), (self.numerator, self.denominator) def __str__(self): """Convert to string""" if self.denominator != 1: return f"{self.numerator}/{self.denominator}" else: return f"{self.numerator}" def __repr__(self): """Convert to string""" return f"MPQ({self.numerator},{self.denominator})" def _cmp(self, other, op): """Helper for lt/le/gt/ge""" if not isinstance(other, self._compatible_types): return NotImplemented lhs = self.numerator * other.denominator rhs = other.numerator * self.denominator return op(lhs, rhs) def __lt__(self, other): """self < other""" return self._cmp(other, operator.lt) def __le__(self, other): """self <= other""" return self._cmp(other, operator.le) def __gt__(self, other): """self > other""" return self._cmp(other, operator.gt) def __ge__(self, other): """self >= other""" return self._cmp(other, operator.ge) def __abs__(self): """abs(q)""" return self._new(abs(self.numerator), self.denominator) def __pos__(self): """+q""" return self def __neg__(self): """-q""" return self._new(-self.numerator, self.denominator) def __add__(self, other): """q1 + q2""" if isinstance(other, PythonMPQ): # # This is much faster than the naive method used in the stdlib # fractions module. Not sure where this method comes from # though... # # Compare timings for something like: # nums = range(1000) # rats = [PythonMPQ(n, d) for n, d in zip(nums[:-5], nums[5:])] # sum(rats) # <-- time this # ap, aq = self.numerator, self.denominator bp, bq = other.numerator, other.denominator g = gcd(aq, bq) if g == 1: p = ap*bq + aq*bp q = bq*aq else: q1, q2 = aq//g, bq//g p, q = ap*q2 + bp*q1, q1*q2 g2 = gcd(p, g) p, q = (p // g2), q * (g // g2) elif isinstance(other, int): p = self.numerator + self.denominator * other q = self.denominator else: return NotImplemented return self._new(p, q) def __radd__(self, other): """z1 + q2""" if isinstance(other, int): p = self.numerator + self.denominator * other q = self.denominator return self._new(p, q) else: return NotImplemented def __sub__(self ,other): """q1 - q2""" if isinstance(other, PythonMPQ): ap, aq = self.numerator, self.denominator bp, bq = other.numerator, other.denominator g = gcd(aq, bq) if g == 1: p = ap*bq - aq*bp q = bq*aq else: q1, q2 = aq//g, bq//g p, q = ap*q2 - bp*q1, q1*q2 g2 = gcd(p, g) p, q = (p // g2), q * (g // g2) elif isinstance(other, int): p = self.numerator - self.denominator*other q = self.denominator else: return NotImplemented return self._new(p, q) def __rsub__(self, other): """z1 - q2""" if isinstance(other, int): p = self.denominator * other - self.numerator q = self.denominator return self._new(p, q) else: return NotImplemented def __mul__(self, other): """q1 * q2""" if isinstance(other, PythonMPQ): ap, aq = self.numerator, self.denominator bp, bq = other.numerator, other.denominator x1 = gcd(ap, bq) x2 = gcd(bp, aq) p, q = ((ap//x1)*(bp//x2), (aq//x2)*(bq//x1)) elif isinstance(other, int): x = gcd(other, self.denominator) p = self.numerator*(other//x) q = self.denominator//x else: return NotImplemented return self._new(p, q) def __rmul__(self, other): """z1 * q2""" if isinstance(other, int): x = gcd(self.denominator, other) p = self.numerator*(other//x) q = self.denominator//x return self._new(p, q) else: return NotImplemented def __pow__(self, exp): """q ** z""" p, q = self.numerator, self.denominator if exp < 0: p, q, exp = q, p, -exp return self._new_check(p**exp, q**exp) def __truediv__(self, other): """q1 / q2""" if isinstance(other, PythonMPQ): ap, aq = self.numerator, self.denominator bp, bq = other.numerator, other.denominator x1 = gcd(ap, bp) x2 = gcd(bq, aq) p, q = ((ap//x1)*(bq//x2), (aq//x2)*(bp//x1)) elif isinstance(other, int): x = gcd(other, self.numerator) p = self.numerator//x q = self.denominator*(other//x) else: return NotImplemented return self._new_check(p, q) def __rtruediv__(self, other): """z / q""" if isinstance(other, int): x = gcd(self.numerator, other) p = self.denominator*(other//x) q = self.numerator//x return self._new_check(p, q) else: return NotImplemented # # These are the types that PythonMPQ will interoperate with for operations # and comparisons such as ==, + etc. We define this down here so that we can # include PythonMPQ in the list as well. # PythonMPQ._compatible_types = (PythonMPQ, int, Decimal, Fraction) sympy-sympy-1.9/sympy/external/tests/000077500000000000000000000000001412543434000200705ustar00rootroot00000000000000sympy-sympy-1.9/sympy/external/tests/__init__.py000066400000000000000000000000001412543434000221670ustar00rootroot00000000000000sympy-sympy-1.9/sympy/external/tests/test_autowrap.py000066400000000000000000000226231412543434000233500ustar00rootroot00000000000000import sympy import tempfile import os from sympy import symbols, Eq, Mod from sympy.external import import_module from sympy.tensor import IndexedBase, Idx from sympy.utilities.autowrap import autowrap, ufuncify, CodeWrapError from sympy.testing.pytest import skip numpy = import_module('numpy', min_module_version='1.6.1') Cython = import_module('Cython', min_module_version='0.15.1') f2py = import_module('numpy.f2py', import_kwargs={'fromlist': ['f2py']}) f2pyworks = False if f2py: try: autowrap(symbols('x'), 'f95', 'f2py') except (CodeWrapError, ImportError, OSError): f2pyworks = False else: f2pyworks = True a, b, c = symbols('a b c') n, m, d = symbols('n m d', integer=True) A, B, C = symbols('A B C', cls=IndexedBase) i = Idx('i', m) j = Idx('j', n) k = Idx('k', d) def has_module(module): """ Return True if module exists, otherwise run skip(). module should be a string. """ # To give a string of the module name to skip(), this function takes a # string. So we don't waste time running import_module() more than once, # just map the three modules tested here in this dict. modnames = {'numpy': numpy, 'Cython': Cython, 'f2py': f2py} if modnames[module]: if module == 'f2py' and not f2pyworks: skip("Couldn't run f2py.") return True skip("Couldn't import %s." % module) # # test runners used by several language-backend combinations # def runtest_autowrap_twice(language, backend): f = autowrap((((a + b)/c)**5).expand(), language, backend) g = autowrap((((a + b)/c)**4).expand(), language, backend) # check that autowrap updates the module name. Else, g gives the same as f assert f(1, -2, 1) == -1.0 assert g(1, -2, 1) == 1.0 def runtest_autowrap_trace(language, backend): has_module('numpy') trace = autowrap(A[i, i], language, backend) assert trace(numpy.eye(100)) == 100 def runtest_autowrap_matrix_vector(language, backend): has_module('numpy') x, y = symbols('x y', cls=IndexedBase) expr = Eq(y[i], A[i, j]*x[j]) mv = autowrap(expr, language, backend) # compare with numpy's dot product M = numpy.random.rand(10, 20) x = numpy.random.rand(20) y = numpy.dot(M, x) assert numpy.sum(numpy.abs(y - mv(M, x))) < 1e-13 def runtest_autowrap_matrix_matrix(language, backend): has_module('numpy') expr = Eq(C[i, j], A[i, k]*B[k, j]) matmat = autowrap(expr, language, backend) # compare with numpy's dot product M1 = numpy.random.rand(10, 20) M2 = numpy.random.rand(20, 15) M3 = numpy.dot(M1, M2) assert numpy.sum(numpy.abs(M3 - matmat(M1, M2))) < 1e-13 def runtest_ufuncify(language, backend): has_module('numpy') a, b, c = symbols('a b c') fabc = ufuncify([a, b, c], a*b + c, backend=backend) facb = ufuncify([a, c, b], a*b + c, backend=backend) grid = numpy.linspace(-2, 2, 50) b = numpy.linspace(-5, 4, 50) c = numpy.linspace(-1, 1, 50) expected = grid*b + c numpy.testing.assert_allclose(fabc(grid, b, c), expected) numpy.testing.assert_allclose(facb(grid, c, b), expected) def runtest_issue_10274(language, backend): expr = (a - b + c)**(13) tmp = tempfile.mkdtemp() f = autowrap(expr, language, backend, tempdir=tmp, helpers=('helper', a - b + c, (a, b, c))) assert f(1, 1, 1) == 1 for file in os.listdir(tmp): if file.startswith("wrapped_code_") and file.endswith(".c"): fil = open(tmp + '/' + file) lines = fil.readlines() assert lines[0] == "/******************************************************************************\n" assert "Code generated with sympy " + sympy.__version__ in lines[1] assert lines[2:] == [ " * *\n", " * See http://www.sympy.org/ for more information. *\n", " * *\n", " * This file is part of 'autowrap' *\n", " ******************************************************************************/\n", "#include " + '"' + file[:-1]+ 'h"' + "\n", "#include \n", "\n", "double helper(double a, double b, double c) {\n", "\n", " double helper_result;\n", " helper_result = a - b + c;\n", " return helper_result;\n", "\n", "}\n", "\n", "double autofunc(double a, double b, double c) {\n", "\n", " double autofunc_result;\n", " autofunc_result = pow(helper(a, b, c), 13);\n", " return autofunc_result;\n", "\n", "}\n", ] def runtest_issue_15337(language, backend): has_module('numpy') # NOTE : autowrap was originally designed to only accept an iterable for # the kwarg "helpers", but in issue 10274 the user mistakenly thought that # if there was only a single helper it did not need to be passed via an # iterable that wrapped the helper tuple. There were no tests for this # behavior so when the code was changed to accept a single tuple it broke # the original behavior. These tests below ensure that both now work. a, b, c, d, e = symbols('a, b, c, d, e') expr = (a - b + c - d + e)**13 exp_res = (1. - 2. + 3. - 4. + 5.)**13 f = autowrap(expr, language, backend, args=(a, b, c, d, e), helpers=('f1', a - b + c, (a, b, c))) numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res) f = autowrap(expr, language, backend, args=(a, b, c, d, e), helpers=(('f1', a - b, (a, b)), ('f2', c - d, (c, d)))) numpy.testing.assert_allclose(f(1, 2, 3, 4, 5), exp_res) def test_issue_15230(): has_module('f2py') x, y = symbols('x, y') expr = Mod(x, 3.0) - Mod(y, -2.0) f = autowrap(expr, args=[x, y], language='F95') exp_res = float(expr.xreplace({x: 3.5, y: 2.7}).evalf()) assert abs(f(3.5, 2.7) - exp_res) < 1e-14 x, y = symbols('x, y', integer=True) expr = Mod(x, 3) - Mod(y, -2) f = autowrap(expr, args=[x, y], language='F95') assert f(3, 2) == expr.xreplace({x: 3, y: 2}) # # tests of language-backend combinations # # f2py def test_wrap_twice_f95_f2py(): has_module('f2py') runtest_autowrap_twice('f95', 'f2py') def test_autowrap_trace_f95_f2py(): has_module('f2py') runtest_autowrap_trace('f95', 'f2py') def test_autowrap_matrix_vector_f95_f2py(): has_module('f2py') runtest_autowrap_matrix_vector('f95', 'f2py') def test_autowrap_matrix_matrix_f95_f2py(): has_module('f2py') runtest_autowrap_matrix_matrix('f95', 'f2py') def test_ufuncify_f95_f2py(): has_module('f2py') runtest_ufuncify('f95', 'f2py') def test_issue_15337_f95_f2py(): has_module('f2py') runtest_issue_15337('f95', 'f2py') # Cython def test_wrap_twice_c_cython(): has_module('Cython') runtest_autowrap_twice('C', 'cython') def test_autowrap_trace_C_Cython(): has_module('Cython') runtest_autowrap_trace('C99', 'cython') def test_autowrap_matrix_vector_C_cython(): has_module('Cython') runtest_autowrap_matrix_vector('C99', 'cython') def test_autowrap_matrix_matrix_C_cython(): has_module('Cython') runtest_autowrap_matrix_matrix('C99', 'cython') def test_ufuncify_C_Cython(): has_module('Cython') runtest_ufuncify('C99', 'cython') def test_issue_10274_C_cython(): has_module('Cython') runtest_issue_10274('C89', 'cython') def test_issue_15337_C_cython(): has_module('Cython') runtest_issue_15337('C89', 'cython') def test_autowrap_custom_printer(): has_module('Cython') from sympy import pi from sympy.utilities.codegen import C99CodeGen from sympy.printing.c import C99CodePrinter class PiPrinter(C99CodePrinter): def _print_Pi(self, expr): return "S_PI" printer = PiPrinter() gen = C99CodeGen(printer=printer) gen.preprocessor_statements.append('#include "shortpi.h"') expr = pi * a expected = ( '#include "%s"\n' '#include \n' '#include "shortpi.h"\n' '\n' 'double autofunc(double a) {\n' '\n' ' double autofunc_result;\n' ' autofunc_result = S_PI*a;\n' ' return autofunc_result;\n' '\n' '}\n' ) tmpdir = tempfile.mkdtemp() # write a trivial header file to use in the generated code open(os.path.join(tmpdir, 'shortpi.h'), 'w').write('#define S_PI 3.14') func = autowrap(expr, backend='cython', tempdir=tmpdir, code_gen=gen) assert func(4.2) == 3.14 * 4.2 # check that the generated code is correct for filename in os.listdir(tmpdir): if filename.startswith('wrapped_code') and filename.endswith('.c'): with open(os.path.join(tmpdir, filename)) as f: lines = f.readlines() expected = expected % filename.replace('.c', '.h') assert ''.join(lines[7:]) == expected # Numpy def test_ufuncify_numpy(): # This test doesn't use Cython, but if Cython works, then there is a valid # C compiler, which is needed. has_module('Cython') runtest_ufuncify('C99', 'numpy') sympy-sympy-1.9/sympy/external/tests/test_codegen.py000066400000000000000000000274621412543434000231200ustar00rootroot00000000000000# This tests the compilation and execution of the source code generated with # utilities.codegen. The compilation takes place in a temporary directory that # is removed after the test. By default the test directory is always removed, # but this behavior can be changed by setting the environment variable # SYMPY_TEST_CLEAN_TEMP to: # export SYMPY_TEST_CLEAN_TEMP=always : the default behavior. # export SYMPY_TEST_CLEAN_TEMP=success : only remove the directories of working tests. # export SYMPY_TEST_CLEAN_TEMP=never : never remove the directories with the test code. # When a directory is not removed, the necessary information is printed on # screen to find the files that belong to the (failed) tests. If a test does # not fail, py.test captures all the output and you will not see the directories # corresponding to the successful tests. Use the --nocapture option to see all # the output. # All tests below have a counterpart in utilities/test/test_codegen.py. In the # latter file, the resulting code is compared with predefined strings, without # compilation or execution. # All the generated Fortran code should conform with the Fortran 95 standard, # and all the generated C code should be ANSI C, which facilitates the # incorporation in various projects. The tests below assume that the binary cc # is somewhere in the path and that it can compile ANSI C code. from sympy.abc import x, y, z from sympy.testing.pytest import skip from sympy.utilities.codegen import codegen, make_routine, get_code_generator import sys import os import tempfile import subprocess # templates for the main program that will test the generated code. main_template = {} main_template['F95'] = """ program main include "codegen.h" integer :: result; result = 0 %(statements)s call exit(result) end program """ main_template['C89'] = """ #include "codegen.h" #include #include int main() { int result = 0; %(statements)s return result; } """ main_template['C99'] = main_template['C89'] # templates for the numerical tests numerical_test_template = {} numerical_test_template['C89'] = """ if (fabs(%(call)s)>%(threshold)s) { printf("Numerical validation failed: %(call)s=%%e threshold=%(threshold)s\\n", %(call)s); result = -1; } """ numerical_test_template['C99'] = numerical_test_template['C89'] numerical_test_template['F95'] = """ if (abs(%(call)s)>%(threshold)s) then write(6,"('Numerical validation failed:')") write(6,"('%(call)s=',e15.5,'threshold=',e15.5)") %(call)s, %(threshold)s result = -1; end if """ # command sequences for supported compilers compile_commands = {} compile_commands['cc'] = [ "cc -c codegen.c -o codegen.o", "cc -c main.c -o main.o", "cc main.o codegen.o -lm -o test.exe" ] compile_commands['gfortran'] = [ "gfortran -c codegen.f90 -o codegen.o", "gfortran -ffree-line-length-none -c main.f90 -o main.o", "gfortran main.o codegen.o -o test.exe" ] compile_commands['g95'] = [ "g95 -c codegen.f90 -o codegen.o", "g95 -ffree-line-length-huge -c main.f90 -o main.o", "g95 main.o codegen.o -o test.exe" ] compile_commands['ifort'] = [ "ifort -c codegen.f90 -o codegen.o", "ifort -c main.f90 -o main.o", "ifort main.o codegen.o -o test.exe" ] combinations_lang_compiler = [ ('C89', 'cc'), ('C99', 'cc'), ('F95', 'ifort'), ('F95', 'gfortran'), ('F95', 'g95') ] def try_run(commands): """Run a series of commands and only return True if all ran fine.""" null = open(os.devnull, 'w') for command in commands: retcode = subprocess.call(command, stdout=null, shell=True, stderr=subprocess.STDOUT) if retcode != 0: return False return True def run_test(label, routines, numerical_tests, language, commands, friendly=True): """A driver for the codegen tests. This driver assumes that a compiler ifort is present in the PATH and that ifort is (at least) a Fortran 90 compiler. The generated code is written in a temporary directory, together with a main program that validates the generated code. The test passes when the compilation and the validation run correctly. """ # Check input arguments before touching the file system language = language.upper() assert language in main_template assert language in numerical_test_template # Check that environment variable makes sense clean = os.getenv('SYMPY_TEST_CLEAN_TEMP', 'always').lower() if clean not in ('always', 'success', 'never'): raise ValueError("SYMPY_TEST_CLEAN_TEMP must be one of the following: 'always', 'success' or 'never'.") # Do all the magic to compile, run and validate the test code # 1) prepare the temporary working directory, switch to that dir work = tempfile.mkdtemp("_sympy_%s_test" % language, "%s_" % label) oldwork = os.getcwd() os.chdir(work) # 2) write the generated code if friendly: # interpret the routines as a name_expr list and call the friendly # function codegen codegen(routines, language, "codegen", to_files=True) else: code_gen = get_code_generator(language, "codegen") code_gen.write(routines, "codegen", to_files=True) # 3) write a simple main program that links to the generated code, and that # includes the numerical tests test_strings = [] for fn_name, args, expected, threshold in numerical_tests: call_string = "%s(%s)-(%s)" % ( fn_name, ",".join(str(arg) for arg in args), expected) if language == "F95": call_string = fortranize_double_constants(call_string) threshold = fortranize_double_constants(str(threshold)) test_strings.append(numerical_test_template[language] % { "call": call_string, "threshold": threshold, }) if language == "F95": f_name = "main.f90" elif language.startswith("C"): f_name = "main.c" else: raise NotImplementedError( "FIXME: filename extension unknown for language: %s" % language) with open(f_name, "w") as f: f.write( main_template[language] % {'statements': "".join(test_strings)}) # 4) Compile and link compiled = try_run(commands) # 5) Run if compiled if compiled: executed = try_run(["./test.exe"]) else: executed = False # 6) Clean up stuff if clean == 'always' or (clean == 'success' and compiled and executed): def safe_remove(filename): if os.path.isfile(filename): os.remove(filename) safe_remove("codegen.f90") safe_remove("codegen.c") safe_remove("codegen.h") safe_remove("codegen.o") safe_remove("main.f90") safe_remove("main.c") safe_remove("main.o") safe_remove("test.exe") os.chdir(oldwork) os.rmdir(work) else: print("TEST NOT REMOVED: %s" % work, file=sys.stderr) os.chdir(oldwork) # 7) Do the assertions in the end assert compiled, "failed to compile %s code with:\n%s" % ( language, "\n".join(commands)) assert executed, "failed to execute %s code from:\n%s" % ( language, "\n".join(commands)) def fortranize_double_constants(code_string): """ Replaces every literal float with literal doubles """ import re pattern_exp = re.compile(r'\d+(\.)?\d*[eE]-?\d+') pattern_float = re.compile(r'\d+\.\d*(?!\d*d)') def subs_exp(matchobj): return re.sub('[eE]', 'd', matchobj.group(0)) def subs_float(matchobj): return "%sd0" % matchobj.group(0) code_string = pattern_exp.sub(subs_exp, code_string) code_string = pattern_float.sub(subs_float, code_string) return code_string def is_feasible(language, commands): # This test should always work, otherwise the compiler is not present. routine = make_routine("test", x) numerical_tests = [ ("test", ( 1.0,), 1.0, 1e-15), ("test", (-1.0,), -1.0, 1e-15), ] try: run_test("is_feasible", [routine], numerical_tests, language, commands, friendly=False) return True except AssertionError: return False valid_lang_commands = [] invalid_lang_compilers = [] for lang, compiler in combinations_lang_compiler: commands = compile_commands[compiler] if is_feasible(lang, commands): valid_lang_commands.append((lang, commands)) else: invalid_lang_compilers.append((lang, compiler)) # We test all language-compiler combinations, just to report what is skipped def test_C89_cc(): if ("C89", 'cc') in invalid_lang_compilers: skip("`cc' command didn't work as expected (C89)") def test_C99_cc(): if ("C99", 'cc') in invalid_lang_compilers: skip("`cc' command didn't work as expected (C99)") def test_F95_ifort(): if ("F95", 'ifort') in invalid_lang_compilers: skip("`ifort' command didn't work as expected") def test_F95_gfortran(): if ("F95", 'gfortran') in invalid_lang_compilers: skip("`gfortran' command didn't work as expected") def test_F95_g95(): if ("F95", 'g95') in invalid_lang_compilers: skip("`g95' command didn't work as expected") # Here comes the actual tests def test_basic_codegen(): numerical_tests = [ ("test", (1.0, 6.0, 3.0), 21.0, 1e-15), ("test", (-1.0, 2.0, -2.5), -2.5, 1e-15), ] name_expr = [("test", (x + y)*z)] for lang, commands in valid_lang_commands: run_test("basic_codegen", name_expr, numerical_tests, lang, commands) def test_intrinsic_math1_codegen(): # not included: log10 from sympy import acos, asin, atan, ceiling, cos, cosh, floor, log, ln, \ sin, sinh, sqrt, tan, tanh, N name_expr = [ ("test_fabs", abs(x)), ("test_acos", acos(x)), ("test_asin", asin(x)), ("test_atan", atan(x)), ("test_cos", cos(x)), ("test_cosh", cosh(x)), ("test_log", log(x)), ("test_ln", ln(x)), ("test_sin", sin(x)), ("test_sinh", sinh(x)), ("test_sqrt", sqrt(x)), ("test_tan", tan(x)), ("test_tanh", tanh(x)), ] numerical_tests = [] for name, expr in name_expr: for xval in 0.2, 0.5, 0.8: expected = N(expr.subs(x, xval)) numerical_tests.append((name, (xval,), expected, 1e-14)) for lang, commands in valid_lang_commands: if lang.startswith("C"): name_expr_C = [("test_floor", floor(x)), ("test_ceil", ceiling(x))] else: name_expr_C = [] run_test("intrinsic_math1", name_expr + name_expr_C, numerical_tests, lang, commands) def test_instrinsic_math2_codegen(): # not included: frexp, ldexp, modf, fmod from sympy import atan2, N name_expr = [ ("test_atan2", atan2(x, y)), ("test_pow", x**y), ] numerical_tests = [] for name, expr in name_expr: for xval, yval in (0.2, 1.3), (0.5, -0.2), (0.8, 0.8): expected = N(expr.subs(x, xval).subs(y, yval)) numerical_tests.append((name, (xval, yval), expected, 1e-14)) for lang, commands in valid_lang_commands: run_test("intrinsic_math2", name_expr, numerical_tests, lang, commands) def test_complicated_codegen(): from sympy import sin, cos, tan, N name_expr = [ ("test1", ((sin(x) + cos(y) + tan(z))**7).expand()), ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))), ] numerical_tests = [] for name, expr in name_expr: for xval, yval, zval in (0.2, 1.3, -0.3), (0.5, -0.2, 0.0), (0.8, 2.1, 0.8): expected = N(expr.subs(x, xval).subs(y, yval).subs(z, zval)) numerical_tests.append((name, (xval, yval, zval), expected, 1e-12)) for lang, commands in valid_lang_commands: run_test( "complicated_codegen", name_expr, numerical_tests, lang, commands) sympy-sympy-1.9/sympy/external/tests/test_importtools.py000066400000000000000000000025621412543434000241010ustar00rootroot00000000000000from sympy.external import import_module from sympy.testing.pytest import warns # fixes issue that arose in addressing issue 6533 def test_no_stdlib_collections(): ''' make sure we get the right collections when it is not part of a larger list ''' import collections matplotlib = import_module('matplotlib', import_kwargs={'fromlist': ['cm', 'collections']}, min_module_version='1.1.0', catch=(RuntimeError,)) if matplotlib: assert collections != matplotlib.collections def test_no_stdlib_collections2(): ''' make sure we get the right collections when it is not part of a larger list ''' import collections matplotlib = import_module('matplotlib', import_kwargs={'fromlist': ['collections']}, min_module_version='1.1.0', catch=(RuntimeError,)) if matplotlib: assert collections != matplotlib.collections def test_no_stdlib_collections3(): '''make sure we get the right collections with no catch''' import collections matplotlib = import_module('matplotlib', import_kwargs={'fromlist': ['cm', 'collections']}, min_module_version='1.1.0') if matplotlib: assert collections != matplotlib.collections def test_min_module_version_python3_basestring_error(): with warns(UserWarning): import_module('mpmath', min_module_version='1000.0.1') sympy-sympy-1.9/sympy/external/tests/test_numpy.py000066400000000000000000000225211412543434000226530ustar00rootroot00000000000000# This testfile tests SymPy <-> NumPy compatibility # Don't test any SymPy features here. Just pure interaction with NumPy. # Always write regular SymPy tests for anything, that can be tested in pure # Python (without numpy). Here we test everything, that a user may need when # using SymPy with NumPy from sympy.external.importtools import version_tuple from sympy.external import import_module numpy = import_module('numpy') if numpy: array, matrix, ndarray = numpy.array, numpy.matrix, numpy.ndarray else: #bin/test will not execute any tests now disabled = True from sympy import (Rational, Symbol, list2numpy, matrix2numpy, sin, Float, Matrix, lambdify, symarray, symbols, Integer) import sympy import mpmath from sympy.abc import x, y, z from sympy.utilities.decorator import conserve_mpmath_dps from sympy.testing.pytest import raises # first, systematically check, that all operations are implemented and don't # raise an exception def test_systematic_basic(): def s(sympy_object, numpy_array): sympy_object + numpy_array numpy_array + sympy_object sympy_object - numpy_array numpy_array - sympy_object sympy_object * numpy_array numpy_array * sympy_object sympy_object / numpy_array numpy_array / sympy_object sympy_object ** numpy_array numpy_array ** sympy_object x = Symbol("x") y = Symbol("y") sympy_objs = [ Rational(2, 3), Float("1.3"), x, y, pow(x, y)*y, Integer(5), Float(5.5), ] numpy_objs = [ array([1]), array([3, 8, -1]), array([x, x**2, Rational(5)]), array([x/y*sin(y), 5, Rational(5)]), ] for x in sympy_objs: for y in numpy_objs: s(x, y) # now some random tests, that test particular problems and that also # check that the results of the operations are correct def test_basics(): one = Rational(1) zero = Rational(0) assert array(1) == array(one) assert array([one]) == array([one]) assert array([x]) == array([x]) assert array(x) == array(Symbol("x")) assert array(one + x) == array(1 + x) X = array([one, zero, zero]) assert (X == array([one, zero, zero])).all() assert (X == array([one, 0, 0])).all() def test_arrays(): one = Rational(1) zero = Rational(0) X = array([one, zero, zero]) Y = one*X X = array([Symbol("a") + Rational(1, 2)]) Y = X + X assert Y == array([1 + 2*Symbol("a")]) Y = Y + 1 assert Y == array([2 + 2*Symbol("a")]) Y = X - X assert Y == array([0]) def test_conversion1(): a = list2numpy([x**2, x]) #looks like an array? assert isinstance(a, ndarray) assert a[0] == x**2 assert a[1] == x assert len(a) == 2 #yes, it's the array def test_conversion2(): a = 2*list2numpy([x**2, x]) b = list2numpy([2*x**2, 2*x]) assert (a == b).all() one = Rational(1) zero = Rational(0) X = list2numpy([one, zero, zero]) Y = one*X X = list2numpy([Symbol("a") + Rational(1, 2)]) Y = X + X assert Y == array([1 + 2*Symbol("a")]) Y = Y + 1 assert Y == array([2 + 2*Symbol("a")]) Y = X - X assert Y == array([0]) def test_list2numpy(): assert (array([x**2, x]) == list2numpy([x**2, x])).all() def test_Matrix1(): m = Matrix([[x, x**2], [5, 2/x]]) assert (array(m.subs(x, 2)) == array([[2, 4], [5, 1]])).all() m = Matrix([[sin(x), x**2], [5, 2/x]]) assert (array(m.subs(x, 2)) == array([[sin(2), 4], [5, 1]])).all() def test_Matrix2(): m = Matrix([[x, x**2], [5, 2/x]]) assert (matrix(m.subs(x, 2)) == matrix([[2, 4], [5, 1]])).all() m = Matrix([[sin(x), x**2], [5, 2/x]]) assert (matrix(m.subs(x, 2)) == matrix([[sin(2), 4], [5, 1]])).all() def test_Matrix3(): a = array([[2, 4], [5, 1]]) assert Matrix(a) == Matrix([[2, 4], [5, 1]]) assert Matrix(a) != Matrix([[2, 4], [5, 2]]) a = array([[sin(2), 4], [5, 1]]) assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]]) assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]]) def test_Matrix4(): a = matrix([[2, 4], [5, 1]]) assert Matrix(a) == Matrix([[2, 4], [5, 1]]) assert Matrix(a) != Matrix([[2, 4], [5, 2]]) a = matrix([[sin(2), 4], [5, 1]]) assert Matrix(a) == Matrix([[sin(2), 4], [5, 1]]) assert Matrix(a) != Matrix([[sin(0), 4], [5, 1]]) def test_Matrix_sum(): M = Matrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]]) m = matrix([[2, 3, 4], [x, 5, 6], [x, y, z**2]]) assert M + m == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]]) assert m + M == Matrix([[3, 5, 7], [2*x, y + 5, x + 6], [2*y + x, y - 50, z*x + z**2]]) assert M + m == M.add(m) def test_Matrix_mul(): M = Matrix([[1, 2, 3], [x, y, x]]) m = matrix([[2, 4], [x, 6], [x, z**2]]) assert M*m == Matrix([ [ 2 + 5*x, 16 + 3*z**2], [2*x + x*y + x**2, 4*x + 6*y + x*z**2], ]) assert m*M == Matrix([ [ 2 + 4*x, 4 + 4*y, 6 + 4*x], [ 7*x, 2*x + 6*y, 9*x], [x + x*z**2, 2*x + y*z**2, 3*x + x*z**2], ]) a = array([2]) assert a[0] * M == 2 * M assert M * a[0] == 2 * M def test_Matrix_array(): class matarray: def __array__(self): from numpy import array return array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) matarr = matarray() assert Matrix(matarr) == Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) def test_matrix2numpy(): a = matrix2numpy(Matrix([[1, x**2], [3*sin(x), 0]])) assert isinstance(a, ndarray) assert a.shape == (2, 2) assert a[0, 0] == 1 assert a[0, 1] == x**2 assert a[1, 0] == 3*sin(x) assert a[1, 1] == 0 def test_matrix2numpy_conversion(): a = Matrix([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]]) b = array([[1, 2, sin(x)], [x**2, x, Rational(1, 2)]]) assert (matrix2numpy(a) == b).all() assert matrix2numpy(a).dtype == numpy.dtype('object') c = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='int8') d = matrix2numpy(Matrix([[1, 2], [10, 20]]), dtype='float64') assert c.dtype == numpy.dtype('int8') assert d.dtype == numpy.dtype('float64') def test_issue_3728(): assert (Rational(1, 2)*array([2*x, 0]) == array([x, 0])).all() assert (Rational(1, 2) + array( [2*x, 0]) == array([2*x + Rational(1, 2), Rational(1, 2)])).all() assert (Float("0.5")*array([2*x, 0]) == array([Float("1.0")*x, 0])).all() assert (Float("0.5") + array( [2*x, 0]) == array([2*x + Float("0.5"), Float("0.5")])).all() @conserve_mpmath_dps def test_lambdify(): mpmath.mp.dps = 16 sin02 = mpmath.mpf("0.198669330795061215459412627") f = lambdify(x, sin(x), "numpy") prec = 1e-15 assert -prec < f(0.2) - sin02 < prec # if this succeeds, it can't be a numpy function if version_tuple(numpy.__version__) >= version_tuple('1.17'): with raises(TypeError): f(x) else: with raises(AttributeError): f(x) def test_lambdify_matrix(): f = lambdify(x, Matrix([[x, 2*x], [1, 2]]), [{'ImmutableMatrix': numpy.array}, "numpy"]) assert (f(1) == array([[1, 2], [1, 2]])).all() def test_lambdify_matrix_multi_input(): M = sympy.Matrix([[x**2, x*y, x*z], [y*x, y**2, y*z], [z*x, z*y, z**2]]) f = lambdify((x, y, z), M, [{'ImmutableMatrix': numpy.array}, "numpy"]) xh, yh, zh = 1.0, 2.0, 3.0 expected = array([[xh**2, xh*yh, xh*zh], [yh*xh, yh**2, yh*zh], [zh*xh, zh*yh, zh**2]]) actual = f(xh, yh, zh) assert numpy.allclose(actual, expected) def test_lambdify_matrix_vec_input(): X = sympy.DeferredVector('X') M = Matrix([ [X[0]**2, X[0]*X[1], X[0]*X[2]], [X[1]*X[0], X[1]**2, X[1]*X[2]], [X[2]*X[0], X[2]*X[1], X[2]**2]]) f = lambdify(X, M, [{'ImmutableMatrix': numpy.array}, "numpy"]) Xh = array([1.0, 2.0, 3.0]) expected = array([[Xh[0]**2, Xh[0]*Xh[1], Xh[0]*Xh[2]], [Xh[1]*Xh[0], Xh[1]**2, Xh[1]*Xh[2]], [Xh[2]*Xh[0], Xh[2]*Xh[1], Xh[2]**2]]) actual = f(Xh) assert numpy.allclose(actual, expected) def test_lambdify_transl(): from sympy.utilities.lambdify import NUMPY_TRANSLATIONS for sym, mat in NUMPY_TRANSLATIONS.items(): assert sym in sympy.__dict__ assert mat in numpy.__dict__ def test_symarray(): """Test creation of numpy arrays of sympy symbols.""" import numpy as np import numpy.testing as npt syms = symbols('_0,_1,_2') s1 = symarray("", 3) s2 = symarray("", 3) npt.assert_array_equal(s1, np.array(syms, dtype=object)) assert s1[0] == s2[0] a = symarray('a', 3) b = symarray('b', 3) assert not(a[0] == b[0]) asyms = symbols('a_0,a_1,a_2') npt.assert_array_equal(a, np.array(asyms, dtype=object)) # Multidimensional checks a2d = symarray('a', (2, 3)) assert a2d.shape == (2, 3) a00, a12 = symbols('a_0_0,a_1_2') assert a2d[0, 0] == a00 assert a2d[1, 2] == a12 a3d = symarray('a', (2, 3, 2)) assert a3d.shape == (2, 3, 2) a000, a120, a121 = symbols('a_0_0_0,a_1_2_0,a_1_2_1') assert a3d[0, 0, 0] == a000 assert a3d[1, 2, 0] == a120 assert a3d[1, 2, 1] == a121 def test_vectorize(): assert (numpy.vectorize( sin)([1, 2, 3]) == numpy.array([sin(1), sin(2), sin(3)])).all() sympy-sympy-1.9/sympy/external/tests/test_pythonmpq.py000066400000000000000000000127451412543434000235510ustar00rootroot00000000000000""" test_pythonmpq.py Test the PythonMPQ class for consistency with gmpy2's mpq type. If gmpy2 is installed run the same tests for both. """ from fractions import Fraction from decimal import Decimal import pickle from sympy.testing.pytest import raises from sympy.external.pythonmpq import PythonMPQ # # If gmpy2 is installed then run the tests for both mpq and PythonMPQ. # That should ensure consistency between the implementation here and mpq. # rational_types = [(PythonMPQ, PythonMPQ, int, int)] try: from gmpy2 import mpq, mpz rational_types.append((mpq, type(mpq(1)), mpz, type(mpz(1)))) except ImportError: pass def test_PythonMPQ(): # # Test PythonMPQ and also mpq if gmpy/gmpy2 is installed. # for Q, TQ, Z, TZ in rational_types: def check_Q(q): assert isinstance(q, TQ) assert isinstance(q.numerator, TZ) assert isinstance(q.denominator, TZ) return q.numerator, q.denominator # Check construction from different types assert check_Q(Q(3)) == (3, 1) assert check_Q(Q(3, 5)) == (3, 5) assert check_Q(Q(Q(3, 5))) == (3, 5) assert check_Q(Q(0.5)) == (1, 2) assert check_Q(Q('0.5')) == (1, 2) assert check_Q(Q(Decimal('0.6'))) == (3, 5) assert check_Q(Q(Fraction(3, 5))) == (3, 5) # Invalid types raises(TypeError, lambda: Q([])) raises(TypeError, lambda: Q([], [])) # Check normalisation of signs assert check_Q(Q(2, 3)) == (2, 3) assert check_Q(Q(-2, 3)) == (-2, 3) assert check_Q(Q(2, -3)) == (-2, 3) assert check_Q(Q(-2, -3)) == (2, 3) # Check gcd calculation assert check_Q(Q(12, 8)) == (3, 2) # __int__/__float__ assert int(Q(5, 3)) == 1 assert int(Q(-5, 3)) == -1 assert float(Q(5, 2)) == 2.5 assert float(Q(-5, 2)) == -2.5 # __str__/__repr__ assert str(Q(2, 1)) == "2" assert str(Q(1, 2)) == "1/2" if Q is PythonMPQ: assert repr(Q(2, 1)) == "MPQ(2,1)" assert repr(Q(1, 2)) == "MPQ(1,2)" else: assert repr(Q(2, 1)) == "mpq(2,1)" assert repr(Q(1, 2)) == "mpq(1,2)" # __bool__ assert bool(Q(1, 2)) is True assert bool(Q(0)) is False # __eq__/__ne__ assert (Q(2, 3) == Q(2, 3)) is True assert (Q(2, 3) == Q(2, 5)) is False assert (Q(2, 3) != Q(2, 3)) is False assert (Q(2, 3) != Q(2, 5)) is True # __hash__ assert hash(Q(3, 5)) == hash(Fraction(3, 5)) # __reduce__ q = Q(2, 3) assert pickle.loads(pickle.dumps(q)) == q # __ge__/__gt__/__le__/__lt__ assert (Q(1, 3) < Q(2, 3)) is True assert (Q(2, 3) < Q(2, 3)) is False assert (Q(2, 3) < Q(1, 3)) is False assert (Q(-2, 3) < Q(1, 3)) is True assert (Q(1, 3) < Q(-2, 3)) is False assert (Q(1, 3) <= Q(2, 3)) is True assert (Q(2, 3) <= Q(2, 3)) is True assert (Q(2, 3) <= Q(1, 3)) is False assert (Q(-2, 3) <= Q(1, 3)) is True assert (Q(1, 3) <= Q(-2, 3)) is False assert (Q(1, 3) > Q(2, 3)) is False assert (Q(2, 3) > Q(2, 3)) is False assert (Q(2, 3) > Q(1, 3)) is True assert (Q(-2, 3) > Q(1, 3)) is False assert (Q(1, 3) > Q(-2, 3)) is True assert (Q(1, 3) >= Q(2, 3)) is False assert (Q(2, 3) >= Q(2, 3)) is True assert (Q(2, 3) >= Q(1, 3)) is True assert (Q(-2, 3) >= Q(1, 3)) is False assert (Q(1, 3) >= Q(-2, 3)) is True # __abs__/__pos__/__neg__ assert abs(Q(2, 3)) == abs(Q(-2, 3)) == Q(2, 3) assert +Q(2, 3) == Q(2, 3) assert -Q(2, 3) == Q(-2, 3) # __add__/__radd__ assert Q(2, 3) + Q(5, 7) == Q(29, 21) assert Q(2, 3) + 1 == Q(5, 3) assert 1 + Q(2, 3) == Q(5, 3) raises(TypeError, lambda: [] + Q(1)) raises(TypeError, lambda: Q(1) + []) # __sub__/__rsub__ assert Q(2, 3) - Q(5, 7) == Q(-1, 21) assert Q(2, 3) - 1 == Q(-1, 3) assert 1 - Q(2, 3) == Q(1, 3) raises(TypeError, lambda: [] - Q(1)) raises(TypeError, lambda: Q(1) - []) # __mul__/__rmul__ assert Q(2, 3) * Q(5, 7) == Q(10, 21) assert Q(2, 3) * 1 == Q(2, 3) assert 1 * Q(2, 3) == Q(2, 3) raises(TypeError, lambda: [] * Q(1)) raises(TypeError, lambda: Q(1) * []) # __pow__/__rpow__ assert Q(2, 3) ** 2 == Q(4, 9) assert Q(2, 3) ** 1 == Q(2, 3) assert Q(-2, 3) ** 2 == Q(4, 9) assert Q(-2, 3) ** -1 == Q(-3, 2) if Q is PythonMPQ: raises(TypeError, lambda: 1 ** Q(2, 3)) raises(TypeError, lambda: Q(1, 4) ** Q(1, 2)) raises(TypeError, lambda: [] ** Q(1)) raises(TypeError, lambda: Q(1) ** []) # __div__/__rdiv__ assert Q(2, 3) / Q(5, 7) == Q(14, 15) assert Q(2, 3) / 1 == Q(2, 3) assert 1 / Q(2, 3) == Q(3, 2) raises(TypeError, lambda: [] / Q(1)) raises(TypeError, lambda: Q(1) / []) raises(ZeroDivisionError, lambda: Q(1, 2) / Q(0)) # __divmod__ if Q is PythonMPQ: raises(TypeError, lambda: Q(2, 3) // Q(1, 3)) raises(TypeError, lambda: Q(2, 3) % Q(1, 3)) raises(TypeError, lambda: 1 // Q(1, 3)) raises(TypeError, lambda: 1 % Q(1, 3)) raises(TypeError, lambda: Q(2, 3) // 1) raises(TypeError, lambda: Q(2, 3) % 1) sympy-sympy-1.9/sympy/external/tests/test_scipy.py000066400000000000000000000021731412543434000226330ustar00rootroot00000000000000# This testfile tests SymPy <-> SciPy compatibility # Don't test any SymPy features here. Just pure interaction with SciPy. # Always write regular SymPy tests for anything, that can be tested in pure # Python (without scipy). Here we test everything, that a user may need when # using SymPy with SciPy from sympy.external import import_module scipy = import_module('scipy') if not scipy: #bin/test will not execute any tests now disabled = True from sympy import jn_zeros def eq(a, b, tol=1e-6): for x, y in zip(a, b): if not (abs(x - y) < tol): return False return True def test_jn_zeros(): assert eq(jn_zeros(0, 4, method="scipy"), [3.141592, 6.283185, 9.424777, 12.566370]) assert eq(jn_zeros(1, 4, method="scipy"), [4.493409, 7.725251, 10.904121, 14.066193]) assert eq(jn_zeros(2, 4, method="scipy"), [5.763459, 9.095011, 12.322940, 15.514603]) assert eq(jn_zeros(3, 4, method="scipy"), [6.987932, 10.417118, 13.698023, 16.923621]) assert eq(jn_zeros(4, 4, method="scipy"), [8.182561, 11.704907, 15.039664, 18.301255]) sympy-sympy-1.9/sympy/functions/000077500000000000000000000000001412543434000171145ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/__init__.py000066400000000000000000000117231412543434000212310ustar00rootroot00000000000000"""A functions module, includes all the standard functions. Combinatorial - factorial, fibonacci, harmonic, bernoulli... Elementary - hyperbolic, trigonometric, exponential, floor and ceiling, sqrt... Special - gamma, zeta,spherical harmonics... """ from sympy.functions.combinatorial.factorials import (factorial, factorial2, rf, ff, binomial, RisingFactorial, FallingFactorial, subfactorial) from sympy.functions.combinatorial.numbers import (carmichael, fibonacci, lucas, tribonacci, harmonic, bernoulli, bell, euler, catalan, genocchi, partition, motzkin) from sympy.functions.elementary.miscellaneous import (sqrt, root, Min, Max, Id, real_root, cbrt) from sympy.functions.elementary.complexes import (re, im, sign, Abs, conjugate, arg, polar_lift, periodic_argument, unbranched_argument, principal_branch, transpose, adjoint, polarify, unpolarify) from sympy.functions.elementary.trigonometric import (sin, cos, tan, sec, csc, cot, sinc, asin, acos, atan, asec, acsc, acot, atan2) from sympy.functions.elementary.exponential import (exp_polar, exp, log, LambertW) from sympy.functions.elementary.hyperbolic import (sinh, cosh, tanh, coth, sech, csch, asinh, acosh, atanh, acoth, asech, acsch) from sympy.functions.elementary.integers import floor, ceiling, frac from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold from sympy.functions.special.error_functions import (erf, erfc, erfi, erf2, erfinv, erfcinv, erf2inv, Ei, expint, E1, li, Li, Si, Ci, Shi, Chi, fresnels, fresnelc) from sympy.functions.special.gamma_functions import (gamma, lowergamma, uppergamma, polygamma, loggamma, digamma, trigamma, multigamma) from sympy.functions.special.zeta_functions import (dirichlet_eta, zeta, lerchphi, polylog, stieltjes, riemann_xi) from sympy.functions.special.tensor_functions import (Eijk, LeviCivita, KroneckerDelta) from sympy.functions.special.singularity_functions import SingularityFunction from sympy.functions.special.delta_functions import DiracDelta, Heaviside from sympy.functions.special.bsplines import bspline_basis, bspline_basis_set, interpolating_spline from sympy.functions.special.bessel import (besselj, bessely, besseli, besselk, hankel1, hankel2, jn, yn, jn_zeros, hn1, hn2, airyai, airybi, airyaiprime, airybiprime, marcumq) from sympy.functions.special.hyper import hyper, meijerg, appellf1 from sympy.functions.special.polynomials import (legendre, assoc_legendre, hermite, chebyshevt, chebyshevu, chebyshevu_root, chebyshevt_root, laguerre, assoc_laguerre, gegenbauer, jacobi, jacobi_normalized) from sympy.functions.special.spherical_harmonics import Ynm, Ynm_c, Znm from sympy.functions.special.elliptic_integrals import (elliptic_k, elliptic_f, elliptic_e, elliptic_pi) from sympy.functions.special.beta_functions import beta, betainc, betainc_regularized from sympy.functions.special.mathieu_functions import (mathieus, mathieuc, mathieusprime, mathieucprime) ln = log __all__ = [ 'factorial', 'factorial2', 'rf', 'ff', 'binomial', 'RisingFactorial', 'FallingFactorial', 'subfactorial', 'carmichael', 'fibonacci', 'lucas', 'motzkin', 'tribonacci', 'harmonic', 'bernoulli', 'bell', 'euler', 'catalan', 'genocchi', 'partition', 'sqrt', 'root', 'Min', 'Max', 'Id', 'real_root', 'cbrt', 're', 'im', 'sign', 'Abs', 'conjugate', 'arg', 'polar_lift', 'periodic_argument', 'unbranched_argument', 'principal_branch', 'transpose', 'adjoint', 'polarify', 'unpolarify', 'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinc', 'asin', 'acos', 'atan', 'asec', 'acsc', 'acot', 'atan2', 'exp_polar', 'exp', 'ln', 'log', 'LambertW', 'sinh', 'cosh', 'tanh', 'coth', 'sech', 'csch', 'asinh', 'acosh', 'atanh', 'acoth', 'asech', 'acsch', 'floor', 'ceiling', 'frac', 'Piecewise', 'piecewise_fold', 'erf', 'erfc', 'erfi', 'erf2', 'erfinv', 'erfcinv', 'erf2inv', 'Ei', 'expint', 'E1', 'li', 'Li', 'Si', 'Ci', 'Shi', 'Chi', 'fresnels', 'fresnelc', 'gamma', 'lowergamma', 'uppergamma', 'polygamma', 'loggamma', 'digamma', 'trigamma', 'multigamma', 'dirichlet_eta', 'zeta', 'lerchphi', 'polylog', 'stieltjes', 'riemann_xi', 'Eijk', 'LeviCivita', 'KroneckerDelta', 'SingularityFunction', 'DiracDelta', 'Heaviside', 'bspline_basis', 'bspline_basis_set', 'interpolating_spline', 'besselj', 'bessely', 'besseli', 'besselk', 'hankel1', 'hankel2', 'jn', 'yn', 'jn_zeros', 'hn1', 'hn2', 'airyai', 'airybi', 'airyaiprime', 'airybiprime', 'marcumq', 'hyper', 'meijerg', 'appellf1', 'legendre', 'assoc_legendre', 'hermite', 'chebyshevt', 'chebyshevu', 'chebyshevu_root', 'chebyshevt_root', 'laguerre', 'assoc_laguerre', 'gegenbauer', 'jacobi', 'jacobi_normalized', 'Ynm', 'Ynm_c', 'Znm', 'elliptic_k', 'elliptic_f', 'elliptic_e', 'elliptic_pi', 'beta', 'betainc', 'betainc_regularized', 'mathieus', 'mathieuc', 'mathieusprime', 'mathieucprime', ] sympy-sympy-1.9/sympy/functions/combinatorial/000077500000000000000000000000001412543434000217375ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/combinatorial/__init__.py000066400000000000000000000000651412543434000240510ustar00rootroot00000000000000# Stub __init__.py for sympy.functions.combinatorial sympy-sympy-1.9/sympy/functions/combinatorial/factorials.py000066400000000000000000001100611412543434000244370ustar00rootroot00000000000000from typing import List from functools import reduce from sympy.core import S, sympify, Dummy, Mod from sympy.core.cache import cacheit from sympy.core.compatibility import HAS_GMPY from sympy.core.function import Function, ArgumentIndexError, PoleError from sympy.core.logic import fuzzy_and from sympy.core.numbers import Integer, pi from sympy.core.relational import Eq from sympy.ntheory import sieve from sympy.polys.polytools import Poly from math import sqrt as _sqrt class CombinatorialFunction(Function): """Base class for combinatorial functions. """ def _eval_simplify(self, **kwargs): from sympy.simplify.combsimp import combsimp # combinatorial function with non-integer arguments is # automatically passed to gammasimp expr = combsimp(self) measure = kwargs['measure'] if measure(expr) <= kwargs['ratio']*measure(self): return expr return self ############################################################################### ######################## FACTORIAL and MULTI-FACTORIAL ######################## ############################################################################### class factorial(CombinatorialFunction): r"""Implementation of factorial function over nonnegative integers. By convention (consistent with the gamma function and the binomial coefficients), factorial of a negative integer is complex infinity. The factorial is very important in combinatorics where it gives the number of ways in which `n` objects can be permuted. It also arises in calculus, probability, number theory, etc. There is strict relation of factorial with gamma function. In fact `n! = gamma(n+1)` for nonnegative integers. Rewrite of this kind is very useful in case of combinatorial simplification. Computation of the factorial is done using two algorithms. For small arguments a precomputed look up table is used. However for bigger input algorithm Prime-Swing is used. It is the fastest algorithm known and computes `n!` via prime factorization of special class of numbers, called here the 'Swing Numbers'. Examples ======== >>> from sympy import Symbol, factorial, S >>> n = Symbol('n', integer=True) >>> factorial(0) 1 >>> factorial(7) 5040 >>> factorial(-2) zoo >>> factorial(n) factorial(n) >>> factorial(2*n) factorial(2*n) >>> factorial(S(1)/2) factorial(1/2) See Also ======== factorial2, RisingFactorial, FallingFactorial """ def fdiff(self, argindex=1): from sympy import gamma, polygamma if argindex == 1: return gamma(self.args[0] + 1)*polygamma(0, self.args[0] + 1) else: raise ArgumentIndexError(self, argindex) _small_swing = [ 1, 1, 1, 3, 3, 15, 5, 35, 35, 315, 63, 693, 231, 3003, 429, 6435, 6435, 109395, 12155, 230945, 46189, 969969, 88179, 2028117, 676039, 16900975, 1300075, 35102025, 5014575, 145422675, 9694845, 300540195, 300540195 ] _small_factorials = [] # type: List[int] @classmethod def _swing(cls, n): if n < 33: return cls._small_swing[n] else: N, primes = int(_sqrt(n)), [] for prime in sieve.primerange(3, N + 1): p, q = 1, n while True: q //= prime if q > 0: if q & 1 == 1: p *= prime else: break if p > 1: primes.append(p) for prime in sieve.primerange(N + 1, n//3 + 1): if (n // prime) & 1 == 1: primes.append(prime) L_product = R_product = 1 for prime in sieve.primerange(n//2 + 1, n + 1): L_product *= prime for prime in primes: R_product *= prime return L_product*R_product @classmethod def _recursive(cls, n): if n < 2: return 1 else: return (cls._recursive(n//2)**2)*cls._swing(n) @classmethod def eval(cls, n): n = sympify(n) if n.is_Number: if n.is_zero: return S.One elif n is S.Infinity: return S.Infinity elif n.is_Integer: if n.is_negative: return S.ComplexInfinity else: n = n.p if n < 20: if not cls._small_factorials: result = 1 for i in range(1, 20): result *= i cls._small_factorials.append(result) result = cls._small_factorials[n-1] # GMPY factorial is faster, use it when available elif HAS_GMPY: from sympy.core.compatibility import gmpy result = gmpy.fac(n) else: bits = bin(n).count('1') result = cls._recursive(n)*2**(n - bits) return Integer(result) def _facmod(self, n, q): res, N = 1, int(_sqrt(n)) # Exponent of prime p in n! is e_p(n) = [n/p] + [n/p**2] + ... # for p > sqrt(n), e_p(n) < sqrt(n), the primes with [n/p] = m, # occur consecutively and are grouped together in pw[m] for # simultaneous exponentiation at a later stage pw = [1]*N m = 2 # to initialize the if condition below for prime in sieve.primerange(2, n + 1): if m > 1: m, y = 0, n // prime while y: m += y y //= prime if m < N: pw[m] = pw[m]*prime % q else: res = res*pow(prime, m, q) % q for ex, bs in enumerate(pw): if ex == 0 or bs == 1: continue if bs == 0: return 0 res = res*pow(bs, ex, q) % q return res def _eval_Mod(self, q): n = self.args[0] if n.is_integer and n.is_nonnegative and q.is_integer: aq = abs(q) d = aq - n if d.is_nonpositive: return S.Zero else: isprime = aq.is_prime if d == 1: # Apply Wilson's theorem (if a natural number n > 1 # is a prime number, then (n-1)! = -1 mod n) and # its inverse (if n > 4 is a composite number, then # (n-1)! = 0 mod n) if isprime: return S(-1 % q) elif isprime is False and (aq - 6).is_nonnegative: return S.Zero elif n.is_Integer and q.is_Integer: n, d, aq = map(int, (n, d, aq)) if isprime and (d - 1 < n): fc = self._facmod(d - 1, aq) fc = pow(fc, aq - 2, aq) if d%2: fc = -fc else: fc = self._facmod(n, aq) return S(fc % q) def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs): from sympy import gamma return gamma(n + 1) def _eval_rewrite_as_Product(self, n, **kwargs): from sympy import Product if n.is_nonnegative and n.is_integer: i = Dummy('i', integer=True) return Product(i, (i, 1, n)) def _eval_is_integer(self): if self.args[0].is_integer and self.args[0].is_nonnegative: return True def _eval_is_positive(self): if self.args[0].is_integer and self.args[0].is_nonnegative: return True def _eval_is_even(self): x = self.args[0] if x.is_integer and x.is_nonnegative: return (x - 2).is_nonnegative def _eval_is_composite(self): x = self.args[0] if x.is_integer and x.is_nonnegative: return (x - 3).is_nonnegative def _eval_is_real(self): x = self.args[0] if x.is_nonnegative or x.is_noninteger: return True def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x) arg0 = arg.subs(x, 0) if arg0.is_zero: return S.One elif not arg0.is_infinite: return self.func(arg) raise PoleError("Cannot expand %s around 0" % (self)) class MultiFactorial(CombinatorialFunction): pass class subfactorial(CombinatorialFunction): r"""The subfactorial counts the derangements of n items and is defined for non-negative integers as: .. math:: !n = \begin{cases} 1 & n = 0 \\ 0 & n = 1 \\ (n-1)(!(n-1) + !(n-2)) & n > 1 \end{cases} It can also be written as ``int(round(n!/exp(1)))`` but the recursive definition with caching is implemented for this function. An interesting analytic expression is the following [2]_ .. math:: !x = \Gamma(x + 1, -1)/e which is valid for non-negative integers `x`. The above formula is not very useful incase of non-integers. :math:`\Gamma(x + 1, -1)` is single-valued only for integral arguments `x`, elsewhere on the positive real axis it has an infinite number of branches none of which are real. References ========== .. [1] https://en.wikipedia.org/wiki/Subfactorial .. [2] http://mathworld.wolfram.com/Subfactorial.html Examples ======== >>> from sympy import subfactorial >>> from sympy.abc import n >>> subfactorial(n + 1) subfactorial(n + 1) >>> subfactorial(5) 44 See Also ======== sympy.functions.combinatorial.factorials.factorial, sympy.utilities.iterables.generate_derangements, sympy.functions.special.gamma_functions.uppergamma """ @classmethod @cacheit def _eval(self, n): if not n: return S.One elif n == 1: return S.Zero else: z1, z2 = 1, 0 for i in range(2, n + 1): z1, z2 = z2, (i - 1)*(z2 + z1) return z2 @classmethod def eval(cls, arg): if arg.is_Number: if arg.is_Integer and arg.is_nonnegative: return cls._eval(arg) elif arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity def _eval_is_even(self): if self.args[0].is_odd and self.args[0].is_nonnegative: return True def _eval_is_integer(self): if self.args[0].is_integer and self.args[0].is_nonnegative: return True def _eval_rewrite_as_factorial(self, arg, **kwargs): from sympy import summation i = Dummy('i') f = S.NegativeOne**i / factorial(i) return factorial(arg) * summation(f, (i, 0, arg)) def _eval_rewrite_as_gamma(self, arg, piecewise=True, **kwargs): from sympy import exp, gamma, I, lowergamma return ((-1)**(arg + 1)*exp(-I*pi*arg)*lowergamma(arg + 1, -1) + gamma(arg + 1))*exp(-1) def _eval_rewrite_as_uppergamma(self, arg, **kwargs): from sympy import uppergamma return uppergamma(arg + 1, -1)/S.Exp1 def _eval_is_nonnegative(self): if self.args[0].is_integer and self.args[0].is_nonnegative: return True def _eval_is_odd(self): if self.args[0].is_even and self.args[0].is_nonnegative: return True class factorial2(CombinatorialFunction): r"""The double factorial `n!!`, not to be confused with `(n!)!` The double factorial is defined for nonnegative integers and for odd negative integers as: .. math:: n!! = \begin{cases} 1 & n = 0 \\ n(n-2)(n-4) \cdots 1 & n\ \text{positive odd} \\ n(n-2)(n-4) \cdots 2 & n\ \text{positive even} \\ (n+2)!!/(n+2) & n\ \text{negative odd} \end{cases} References ========== .. [1] https://en.wikipedia.org/wiki/Double_factorial Examples ======== >>> from sympy import factorial2, var >>> n = var('n') >>> n n >>> factorial2(n + 1) factorial2(n + 1) >>> factorial2(5) 15 >>> factorial2(-1) 1 >>> factorial2(-5) 1/3 See Also ======== factorial, RisingFactorial, FallingFactorial """ @classmethod def eval(cls, arg): # TODO: extend this to complex numbers? if arg.is_Number: if not arg.is_Integer: raise ValueError("argument must be nonnegative integer " "or negative odd integer") # This implementation is faster than the recursive one # It also avoids "maximum recursion depth exceeded" runtime error if arg.is_nonnegative: if arg.is_even: k = arg / 2 return 2**k * factorial(k) return factorial(arg) / factorial2(arg - 1) if arg.is_odd: return arg*(S.NegativeOne)**((1 - arg)/2) / factorial2(-arg) raise ValueError("argument must be nonnegative integer " "or negative odd integer") def _eval_is_even(self): # Double factorial is even for every positive even input n = self.args[0] if n.is_integer: if n.is_odd: return False if n.is_even: if n.is_positive: return True if n.is_zero: return False def _eval_is_integer(self): # Double factorial is an integer for every nonnegative input, and for # -1 and -3 n = self.args[0] if n.is_integer: if (n + 1).is_nonnegative: return True if n.is_odd: return (n + 3).is_nonnegative def _eval_is_odd(self): # Double factorial is odd for every odd input not smaller than -3, and # for 0 n = self.args[0] if n.is_odd: return (n + 3).is_nonnegative if n.is_even: if n.is_positive: return False if n.is_zero: return True def _eval_is_positive(self): # Double factorial is positive for every nonnegative input, and for # every odd negative input which is of the form -1-4k for an # nonnegative integer k n = self.args[0] if n.is_integer: if (n + 1).is_nonnegative: return True if n.is_odd: return ((n + 1) / 2).is_even def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs): from sympy import gamma, Piecewise, sqrt return 2**(n/2)*gamma(n/2 + 1) * Piecewise((1, Eq(Mod(n, 2), 0)), (sqrt(2/pi), Eq(Mod(n, 2), 1))) ############################################################################### ######################## RISING and FALLING FACTORIALS ######################## ############################################################################### class RisingFactorial(CombinatorialFunction): r""" Rising factorial (also called Pochhammer symbol) is a double valued function arising in concrete mathematics, hypergeometric functions and series expansions. It is defined by: .. math:: rf(x,k) = x \cdot (x+1) \cdots (x+k-1) where `x` can be arbitrary expression and `k` is an integer. For more information check "Concrete mathematics" by Graham, pp. 66 or visit http://mathworld.wolfram.com/RisingFactorial.html page. When `x` is a Poly instance of degree >= 1 with a single variable, `rf(x,k) = x(y) \cdot x(y+1) \cdots x(y+k-1)`, where `y` is the variable of `x`. This is as described in Peter Paule, "Greatest Factorial Factorization and Symbolic Summation", Journal of Symbolic Computation, vol. 20, pp. 235-268, 1995. Examples ======== >>> from sympy import rf, Poly >>> from sympy.abc import x >>> rf(x, 0) 1 >>> rf(1, 5) 120 >>> rf(x, 5) == x*(1 + x)*(2 + x)*(3 + x)*(4 + x) True >>> rf(Poly(x**3, x), 2) Poly(x**6 + 3*x**5 + 3*x**4 + x**3, x, domain='ZZ') Rewriting is complicated unless the relationship between the arguments is known, but rising factorial can be rewritten in terms of gamma, factorial and binomial and falling factorial. >>> from sympy import Symbol, factorial, ff, binomial, gamma >>> n = Symbol('n', integer=True, positive=True) >>> R = rf(n, n + 2) >>> for i in (rf, ff, factorial, binomial, gamma): ... R.rewrite(i) ... RisingFactorial(n, n + 2) FallingFactorial(2*n + 1, n + 2) factorial(2*n + 1)/factorial(n - 1) binomial(2*n + 1, n + 2)*factorial(n + 2) gamma(2*n + 2)/gamma(n) See Also ======== factorial, factorial2, FallingFactorial References ========== .. [1] https://en.wikipedia.org/wiki/Pochhammer_symbol """ @classmethod def eval(cls, x, k): x = sympify(x) k = sympify(k) if x is S.NaN or k is S.NaN: return S.NaN elif x is S.One: return factorial(k) elif k.is_Integer: if k.is_zero: return S.One else: if k.is_positive: if x is S.Infinity: return S.Infinity elif x is S.NegativeInfinity: if k.is_odd: return S.NegativeInfinity else: return S.Infinity else: if isinstance(x, Poly): gens = x.gens if len(gens)!= 1: raise ValueError("rf only defined for " "polynomials on one generator") else: return reduce(lambda r, i: r*(x.shift(i)), range(0, int(k)), 1) else: return reduce(lambda r, i: r*(x + i), range(0, int(k)), 1) else: if x is S.Infinity: return S.Infinity elif x is S.NegativeInfinity: return S.Infinity else: if isinstance(x, Poly): gens = x.gens if len(gens)!= 1: raise ValueError("rf only defined for " "polynomials on one generator") else: return 1/reduce(lambda r, i: r*(x.shift(-i)), range(1, abs(int(k)) + 1), 1) else: return 1/reduce(lambda r, i: r*(x - i), range(1, abs(int(k)) + 1), 1) if k.is_integer == False: if x.is_integer and x.is_negative: return S.Zero def _eval_rewrite_as_gamma(self, x, k, piecewise=True, **kwargs): from sympy import gamma, Piecewise if not piecewise: if (x <= 0) == True: return (-1)**k*gamma(1 - x) / gamma(-k - x + 1) return gamma(x + k) / gamma(x) return Piecewise( (gamma(x + k) / gamma(x), x > 0), ((-1)**k*gamma(1 - x) / gamma(-k - x + 1), True)) def _eval_rewrite_as_FallingFactorial(self, x, k, **kwargs): return FallingFactorial(x + k - 1, k) def _eval_rewrite_as_factorial(self, x, k, **kwargs): from sympy import Piecewise if x.is_integer and k.is_integer: return Piecewise( (factorial(k + x - 1)/factorial(x - 1), x > 0), ((-1)**k*factorial(-x)/factorial(-k - x), True)) def _eval_rewrite_as_binomial(self, x, k, **kwargs): if k.is_integer: return factorial(k) * binomial(x + k - 1, k) def _eval_rewrite_as_tractable(self, x, k, limitvar=None, **kwargs): from sympy import gamma if limitvar: k_lim = k.subs(limitvar, S.Infinity) if k_lim is S.Infinity: return (gamma(x + k).rewrite('tractable', deep=True) / gamma(x)) elif k_lim is S.NegativeInfinity: return ((-1)**k*gamma(1 - x) / gamma(-k - x + 1).rewrite('tractable', deep=True)) return self.rewrite(gamma).rewrite('tractable', deep=True) def _eval_is_integer(self): return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer, self.args[1].is_nonnegative)) class FallingFactorial(CombinatorialFunction): r""" Falling factorial (related to rising factorial) is a double valued function arising in concrete mathematics, hypergeometric functions and series expansions. It is defined by .. math:: ff(x,k) = x \cdot (x-1) \cdots (x-k+1) where `x` can be arbitrary expression and `k` is an integer. For more information check "Concrete mathematics" by Graham, pp. 66 or visit http://mathworld.wolfram.com/FallingFactorial.html page. When `x` is a Poly instance of degree >= 1 with single variable, `ff(x,k) = x(y) \cdot x(y-1) \cdots x(y-k+1)`, where `y` is the variable of `x`. This is as described in Peter Paule, "Greatest Factorial Factorization and Symbolic Summation", Journal of Symbolic Computation, vol. 20, pp. 235-268, 1995. >>> from sympy import ff, Poly, Symbol >>> from sympy.abc import x >>> n = Symbol('n', integer=True) >>> ff(x, 0) 1 >>> ff(5, 5) 120 >>> ff(x, 5) == x*(x - 1)*(x - 2)*(x - 3)*(x - 4) True >>> ff(Poly(x**2, x), 2) Poly(x**4 - 2*x**3 + x**2, x, domain='ZZ') >>> ff(n, n) factorial(n) Rewriting is complicated unless the relationship between the arguments is known, but falling factorial can be rewritten in terms of gamma, factorial and binomial and rising factorial. >>> from sympy import factorial, rf, gamma, binomial, Symbol >>> n = Symbol('n', integer=True, positive=True) >>> F = ff(n, n - 2) >>> for i in (rf, ff, factorial, binomial, gamma): ... F.rewrite(i) ... RisingFactorial(3, n - 2) FallingFactorial(n, n - 2) factorial(n)/2 binomial(n, n - 2)*factorial(n - 2) gamma(n + 1)/2 See Also ======== factorial, factorial2, RisingFactorial References ========== .. [1] http://mathworld.wolfram.com/FallingFactorial.html """ @classmethod def eval(cls, x, k): x = sympify(x) k = sympify(k) if x is S.NaN or k is S.NaN: return S.NaN elif k.is_integer and x == k: return factorial(x) elif k.is_Integer: if k.is_zero: return S.One else: if k.is_positive: if x is S.Infinity: return S.Infinity elif x is S.NegativeInfinity: if k.is_odd: return S.NegativeInfinity else: return S.Infinity else: if isinstance(x, Poly): gens = x.gens if len(gens)!= 1: raise ValueError("ff only defined for " "polynomials on one generator") else: return reduce(lambda r, i: r*(x.shift(-i)), range(0, int(k)), 1) else: return reduce(lambda r, i: r*(x - i), range(0, int(k)), 1) else: if x is S.Infinity: return S.Infinity elif x is S.NegativeInfinity: return S.Infinity else: if isinstance(x, Poly): gens = x.gens if len(gens)!= 1: raise ValueError("rf only defined for " "polynomials on one generator") else: return 1/reduce(lambda r, i: r*(x.shift(i)), range(1, abs(int(k)) + 1), 1) else: return 1/reduce(lambda r, i: r*(x + i), range(1, abs(int(k)) + 1), 1) def _eval_rewrite_as_gamma(self, x, k, piecewise=True, **kwargs): from sympy import gamma, Piecewise if not piecewise: if (x < 0) == True: return (-1)**k*gamma(k - x) / gamma(-x) return gamma(x + 1) / gamma(x - k + 1) return Piecewise( (gamma(x + 1) / gamma(x - k + 1), x >= 0), ((-1)**k*gamma(k - x) / gamma(-x), True)) def _eval_rewrite_as_RisingFactorial(self, x, k, **kwargs): return rf(x - k + 1, k) def _eval_rewrite_as_binomial(self, x, k, **kwargs): if k.is_integer: return factorial(k) * binomial(x, k) def _eval_rewrite_as_factorial(self, x, k, **kwargs): from sympy import Piecewise if x.is_integer and k.is_integer: return Piecewise( (factorial(x)/factorial(-k + x), x >= 0), ((-1)**k*factorial(k - x - 1)/factorial(-x - 1), True)) def _eval_rewrite_as_tractable(self, x, k, limitvar=None, **kwargs): from sympy import gamma if limitvar: k_lim = k.subs(limitvar, S.Infinity) if k_lim is S.Infinity: return ((-1)**k*gamma(k - x).rewrite('tractable', deep=True) / gamma(-x)) elif k_lim is S.NegativeInfinity: return (gamma(x + 1) / gamma(x - k + 1).rewrite('tractable', deep=True)) return self.rewrite(gamma).rewrite('tractable', deep=True) def _eval_is_integer(self): return fuzzy_and((self.args[0].is_integer, self.args[1].is_integer, self.args[1].is_nonnegative)) rf = RisingFactorial ff = FallingFactorial ############################################################################### ########################### BINOMIAL COEFFICIENTS ############################# ############################################################################### class binomial(CombinatorialFunction): r"""Implementation of the binomial coefficient. It can be defined in two ways depending on its desired interpretation: .. math:: \binom{n}{k} = \frac{n!}{k!(n-k)!}\ \text{or}\ \binom{n}{k} = \frac{ff(n, k)}{k!} First, in a strict combinatorial sense it defines the number of ways we can choose `k` elements from a set of `n` elements. In this case both arguments are nonnegative integers and binomial is computed using an efficient algorithm based on prime factorization. The other definition is generalization for arbitrary `n`, however `k` must also be nonnegative. This case is very useful when evaluating summations. For the sake of convenience for negative integer `k` this function will return zero no matter what valued is the other argument. To expand the binomial when `n` is a symbol, use either ``expand_func()`` or ``expand(func=True)``. The former will keep the polynomial in factored form while the latter will expand the polynomial itself. See examples for details. Examples ======== >>> from sympy import Symbol, Rational, binomial, expand_func >>> n = Symbol('n', integer=True, positive=True) >>> binomial(15, 8) 6435 >>> binomial(n, -1) 0 Rows of Pascal's triangle can be generated with the binomial function: >>> for N in range(8): ... print([binomial(N, i) for i in range(N + 1)]) ... [1] [1, 1] [1, 2, 1] [1, 3, 3, 1] [1, 4, 6, 4, 1] [1, 5, 10, 10, 5, 1] [1, 6, 15, 20, 15, 6, 1] [1, 7, 21, 35, 35, 21, 7, 1] As can a given diagonal, e.g. the 4th diagonal: >>> N = -4 >>> [binomial(N, i) for i in range(1 - N)] [1, -4, 10, -20, 35] >>> binomial(Rational(5, 4), 3) -5/128 >>> binomial(Rational(-5, 4), 3) -195/128 >>> binomial(n, 3) binomial(n, 3) >>> binomial(n, 3).expand(func=True) n**3/6 - n**2/2 + n/3 >>> expand_func(binomial(n, 3)) n*(n - 2)*(n - 1)/6 References ========== .. [1] https://www.johndcook.com/blog/binomial_coefficients/ """ def fdiff(self, argindex=1): from sympy import polygamma if argindex == 1: # http://functions.wolfram.com/GammaBetaErf/Binomial/20/01/01/ n, k = self.args return binomial(n, k)*(polygamma(0, n + 1) - \ polygamma(0, n - k + 1)) elif argindex == 2: # http://functions.wolfram.com/GammaBetaErf/Binomial/20/01/02/ n, k = self.args return binomial(n, k)*(polygamma(0, n - k + 1) - \ polygamma(0, k + 1)) else: raise ArgumentIndexError(self, argindex) @classmethod def _eval(self, n, k): # n.is_Number and k.is_Integer and k != 1 and n != k if k.is_Integer: if n.is_Integer and n >= 0: n, k = int(n), int(k) if k > n: return S.Zero elif k > n // 2: k = n - k if HAS_GMPY: from sympy.core.compatibility import gmpy return Integer(gmpy.bincoef(n, k)) d, result = n - k, 1 for i in range(1, k + 1): d += 1 result = result * d // i return Integer(result) else: d, result = n - k, 1 for i in range(1, k + 1): d += 1 result *= d result /= i return result @classmethod def eval(cls, n, k): n, k = map(sympify, (n, k)) d = n - k n_nonneg, n_isint = n.is_nonnegative, n.is_integer if k.is_zero or ((n_nonneg or n_isint is False) and d.is_zero): return S.One if (k - 1).is_zero or ((n_nonneg or n_isint is False) and (d - 1).is_zero): return n if k.is_integer: if k.is_negative or (n_nonneg and n_isint and d.is_negative): return S.Zero elif n.is_number: res = cls._eval(n, k) return res.expand(basic=True) if res else res elif n_nonneg is False and n_isint: # a special case when binomial evaluates to complex infinity return S.ComplexInfinity elif k.is_number: from sympy import gamma return gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1)) def _eval_Mod(self, q): n, k = self.args if any(x.is_integer is False for x in (n, k, q)): raise ValueError("Integers expected for binomial Mod") if all(x.is_Integer for x in (n, k, q)): n, k = map(int, (n, k)) aq, res = abs(q), 1 # handle negative integers k or n if k < 0: return S.Zero if n < 0: n = -n + k - 1 res = -1 if k%2 else 1 # non negative integers k and n if k > n: return S.Zero isprime = aq.is_prime aq = int(aq) if isprime: if aq < n: # use Lucas Theorem N, K = n, k while N or K: res = res*binomial(N % aq, K % aq) % aq N, K = N // aq, K // aq else: # use Factorial Modulo d = n - k if k > d: k, d = d, k kf = 1 for i in range(2, k + 1): kf = kf*i % aq df = kf for i in range(k + 1, d + 1): df = df*i % aq res *= df for i in range(d + 1, n + 1): res = res*i % aq res *= pow(kf*df % aq, aq - 2, aq) res %= aq else: # Binomial Factorization is performed by calculating the # exponents of primes <= n in `n! /(k! (n - k)!)`, # for non-negative integers n and k. As the exponent of # prime in n! is e_p(n) = [n/p] + [n/p**2] + ... # the exponent of prime in binomial(n, k) would be # e_p(n) - e_p(k) - e_p(n - k) M = int(_sqrt(n)) for prime in sieve.primerange(2, n + 1): if prime > n - k: res = res*prime % aq elif prime > n // 2: continue elif prime > M: if n % prime < k % prime: res = res*prime % aq else: N, K = n, k exp = a = 0 while N > 0: a = int((N % prime) < (K % prime + a)) N, K = N // prime, K // prime exp += a if exp > 0: res *= pow(prime, exp, aq) res %= aq return S(res % q) def _eval_expand_func(self, **hints): """ Function to expand binomial(n, k) when m is positive integer Also, n is self.args[0] and k is self.args[1] while using binomial(n, k) """ n = self.args[0] if n.is_Number: return binomial(*self.args) k = self.args[1] if (n-k).is_Integer: k = n - k if k.is_Integer: if k.is_zero: return S.One elif k.is_negative: return S.Zero else: n, result = self.args[0], 1 for i in range(1, k + 1): result *= n - k + i result /= i return result else: return binomial(*self.args) def _eval_rewrite_as_factorial(self, n, k, **kwargs): return factorial(n)/(factorial(k)*factorial(n - k)) def _eval_rewrite_as_gamma(self, n, k, piecewise=True, **kwargs): from sympy import gamma return gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1)) def _eval_rewrite_as_tractable(self, n, k, limitvar=None, **kwargs): return self._eval_rewrite_as_gamma(n, k).rewrite('tractable') def _eval_rewrite_as_FallingFactorial(self, n, k, **kwargs): if k.is_integer: return ff(n, k) / factorial(k) def _eval_is_integer(self): n, k = self.args if n.is_integer and k.is_integer: return True elif k.is_integer is False: return False def _eval_is_nonnegative(self): n, k = self.args if n.is_integer and k.is_integer: if n.is_nonnegative or k.is_negative or k.is_even: return True elif k.is_even is False: return False def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import gamma return self.rewrite(gamma)._eval_as_leading_term(x, logx=logx, cdir=cdir) sympy-sympy-1.9/sympy/functions/combinatorial/numbers.py000066400000000000000000002047761412543434000240040ustar00rootroot00000000000000""" This module implements some special functions that commonly appear in combinatorial contexts (e.g. in power series); in particular, sequences of rational numbers such as Bernoulli and Fibonacci numbers. Factorials, binomial coefficients and related functions are located in the separate 'factorials' module. """ from typing import Callable, Dict from sympy.core import S, Symbol, Rational, Integer, Add, Dummy from sympy.core.cache import cacheit from sympy.core.compatibility import as_int, SYMPY_INTS from sympy.core.function import Function, expand_mul from sympy.core.logic import fuzzy_not from sympy.core.numbers import E, pi from sympy.core.relational import LessThan, StrictGreaterThan from sympy.functions.combinatorial.factorials import binomial, factorial from sympy.functions.elementary.exponential import log from sympy.functions.elementary.integers import floor from sympy.functions.elementary.miscellaneous import sqrt, cbrt from sympy.functions.elementary.trigonometric import sin, cos, cot from sympy.ntheory import isprime from sympy.ntheory.primetest import is_square from sympy.utilities.memoization import recurrence_memo from mpmath import bernfrac, workprec from mpmath.libmp import ifib as _ifib def _product(a, b): p = 1 for k in range(a, b + 1): p *= k return p # Dummy symbol used for computing polynomial sequences _sym = Symbol('x') #----------------------------------------------------------------------------# # # # Carmichael numbers # # # #----------------------------------------------------------------------------# class carmichael(Function): """ Carmichael Numbers: Certain cryptographic algorithms make use of big prime numbers. However, checking whether a big number is prime is not so easy. Randomized prime number checking tests exist that offer a high degree of confidence of accurate determination at low cost, such as the Fermat test. Let 'a' be a random number between 2 and n - 1, where n is the number whose primality we are testing. Then, n is probably prime if it satisfies the modular arithmetic congruence relation : a^(n-1) = 1(mod n). (where mod refers to the modulo operation) If a number passes the Fermat test several times, then it is prime with a high probability. Unfortunately, certain composite numbers (non-primes) still pass the Fermat test with every number smaller than themselves. These numbers are called Carmichael numbers. A Carmichael number will pass a Fermat primality test to every base b relatively prime to the number, even though it is not actually prime. This makes tests based on Fermat's Little Theorem less effective than strong probable prime tests such as the Baillie-PSW primality test and the Miller-Rabin primality test. mr functions given in sympy/sympy/ntheory/primetest.py will produce wrong results for each and every carmichael number. Examples ======== >>> from sympy import carmichael >>> carmichael.find_first_n_carmichaels(5) [561, 1105, 1729, 2465, 2821] >>> carmichael.is_prime(2465) False >>> carmichael.is_prime(1729) False >>> carmichael.find_carmichael_numbers_in_range(0, 562) [561] >>> carmichael.find_carmichael_numbers_in_range(0,1000) [561] >>> carmichael.find_carmichael_numbers_in_range(0,2000) [561, 1105, 1729] References ========== .. [1] https://en.wikipedia.org/wiki/Carmichael_number .. [2] https://en.wikipedia.org/wiki/Fermat_primality_test .. [3] https://www.jstor.org/stable/23248683?seq=1#metadata_info_tab_contents """ @staticmethod def is_perfect_square(n): return is_square(n) @staticmethod def divides(p, n): return n % p == 0 @staticmethod def is_prime(n): return isprime(n) @staticmethod def is_carmichael(n): if n >= 0: if (n == 1) or (carmichael.is_prime(n)) or (n % 2 == 0): return False divisors = list([1, n]) # get divisors for i in range(3, n // 2 + 1, 2): if n % i == 0: divisors.append(i) for i in divisors: if carmichael.is_perfect_square(i) and i != 1: return False if carmichael.is_prime(i): if not carmichael.divides(i - 1, n - 1): return False return True else: raise ValueError('The provided number must be greater than or equal to 0') @staticmethod def find_carmichael_numbers_in_range(x, y): if 0 <= x <= y: if x % 2 == 0: return list([i for i in range(x + 1, y, 2) if carmichael.is_carmichael(i)]) else: return list([i for i in range(x, y, 2) if carmichael.is_carmichael(i)]) else: raise ValueError('The provided range is not valid. x and y must be non-negative integers and x <= y') @staticmethod def find_first_n_carmichaels(n): i = 1 carmichaels = list() while len(carmichaels) < n: if carmichael.is_carmichael(i): carmichaels.append(i) i += 2 return carmichaels #----------------------------------------------------------------------------# # # # Fibonacci numbers # # # #----------------------------------------------------------------------------# class fibonacci(Function): r""" Fibonacci numbers / Fibonacci polynomials The Fibonacci numbers are the integer sequence defined by the initial terms `F_0 = 0`, `F_1 = 1` and the two-term recurrence relation `F_n = F_{n-1} + F_{n-2}`. This definition extended to arbitrary real and complex arguments using the formula .. math :: F_z = \frac{\phi^z - \cos(\pi z) \phi^{-z}}{\sqrt 5} The Fibonacci polynomials are defined by `F_1(x) = 1`, `F_2(x) = x`, and `F_n(x) = x*F_{n-1}(x) + F_{n-2}(x)` for `n > 2`. For all positive integers `n`, `F_n(1) = F_n`. * ``fibonacci(n)`` gives the `n^{th}` Fibonacci number, `F_n` * ``fibonacci(n, x)`` gives the `n^{th}` Fibonacci polynomial in `x`, `F_n(x)` Examples ======== >>> from sympy import fibonacci, Symbol >>> [fibonacci(x) for x in range(11)] [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55] >>> fibonacci(5, Symbol('t')) t**4 + 3*t**2 + 1 See Also ======== bell, bernoulli, catalan, euler, harmonic, lucas, genocchi, partition, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Fibonacci_number .. [2] http://mathworld.wolfram.com/FibonacciNumber.html """ @staticmethod def _fib(n): return _ifib(n) @staticmethod @recurrence_memo([None, S.One, _sym]) def _fibpoly(n, prev): return (prev[-2] + _sym*prev[-1]).expand() @classmethod def eval(cls, n, sym=None): if n is S.Infinity: return S.Infinity if n.is_Integer: if sym is None: n = int(n) if n < 0: return S.NegativeOne**(n + 1) * fibonacci(-n) else: return Integer(cls._fib(n)) else: if n < 1: raise ValueError("Fibonacci polynomials are defined " "only for positive integer indices.") return cls._fibpoly(n).subs(_sym, sym) def _eval_rewrite_as_sqrt(self, n, **kwargs): return 2**(-n)*sqrt(5)*((1 + sqrt(5))**n - (-sqrt(5) + 1)**n) / 5 def _eval_rewrite_as_GoldenRatio(self,n, **kwargs): return (S.GoldenRatio**n - 1/(-S.GoldenRatio)**n)/(2*S.GoldenRatio-1) #----------------------------------------------------------------------------# # # # Lucas numbers # # # #----------------------------------------------------------------------------# class lucas(Function): """ Lucas numbers Lucas numbers satisfy a recurrence relation similar to that of the Fibonacci sequence, in which each term is the sum of the preceding two. They are generated by choosing the initial values `L_0 = 2` and `L_1 = 1`. * ``lucas(n)`` gives the `n^{th}` Lucas number Examples ======== >>> from sympy import lucas >>> [lucas(x) for x in range(11)] [2, 1, 3, 4, 7, 11, 18, 29, 47, 76, 123] See Also ======== bell, bernoulli, catalan, euler, fibonacci, harmonic, genocchi, partition, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Lucas_number .. [2] http://mathworld.wolfram.com/LucasNumber.html """ @classmethod def eval(cls, n): if n is S.Infinity: return S.Infinity if n.is_Integer: return fibonacci(n + 1) + fibonacci(n - 1) def _eval_rewrite_as_sqrt(self, n, **kwargs): return 2**(-n)*((1 + sqrt(5))**n + (-sqrt(5) + 1)**n) #----------------------------------------------------------------------------# # # # Tribonacci numbers # # # #----------------------------------------------------------------------------# class tribonacci(Function): r""" Tribonacci numbers / Tribonacci polynomials The Tribonacci numbers are the integer sequence defined by the initial terms `T_0 = 0`, `T_1 = 1`, `T_2 = 1` and the three-term recurrence relation `T_n = T_{n-1} + T_{n-2} + T_{n-3}`. The Tribonacci polynomials are defined by `T_0(x) = 0`, `T_1(x) = 1`, `T_2(x) = x^2`, and `T_n(x) = x^2 T_{n-1}(x) + x T_{n-2}(x) + T_{n-3}(x)` for `n > 2`. For all positive integers `n`, `T_n(1) = T_n`. * ``tribonacci(n)`` gives the `n^{th}` Tribonacci number, `T_n` * ``tribonacci(n, x)`` gives the `n^{th}` Tribonacci polynomial in `x`, `T_n(x)` Examples ======== >>> from sympy import tribonacci, Symbol >>> [tribonacci(x) for x in range(11)] [0, 1, 1, 2, 4, 7, 13, 24, 44, 81, 149] >>> tribonacci(5, Symbol('t')) t**8 + 3*t**5 + 3*t**2 See Also ======== bell, bernoulli, catalan, euler, fibonacci, harmonic, lucas, genocchi, partition References ========== .. [1] https://en.wikipedia.org/wiki/Generalizations_of_Fibonacci_numbers#Tribonacci_numbers .. [2] http://mathworld.wolfram.com/TribonacciNumber.html .. [3] https://oeis.org/A000073 """ @staticmethod @recurrence_memo([S.Zero, S.One, S.One]) def _trib(n, prev): return (prev[-3] + prev[-2] + prev[-1]) @staticmethod @recurrence_memo([S.Zero, S.One, _sym**2]) def _tribpoly(n, prev): return (prev[-3] + _sym*prev[-2] + _sym**2*prev[-1]).expand() @classmethod def eval(cls, n, sym=None): if n is S.Infinity: return S.Infinity if n.is_Integer: n = int(n) if n < 0: raise ValueError("Tribonacci polynomials are defined " "only for non-negative integer indices.") if sym is None: return Integer(cls._trib(n)) else: return cls._tribpoly(n).subs(_sym, sym) def _eval_rewrite_as_sqrt(self, n, **kwargs): w = (-1 + S.ImaginaryUnit * sqrt(3)) / 2 a = (1 + cbrt(19 + 3*sqrt(33)) + cbrt(19 - 3*sqrt(33))) / 3 b = (1 + w*cbrt(19 + 3*sqrt(33)) + w**2*cbrt(19 - 3*sqrt(33))) / 3 c = (1 + w**2*cbrt(19 + 3*sqrt(33)) + w*cbrt(19 - 3*sqrt(33))) / 3 Tn = (a**(n + 1)/((a - b)*(a - c)) + b**(n + 1)/((b - a)*(b - c)) + c**(n + 1)/((c - a)*(c - b))) return Tn def _eval_rewrite_as_TribonacciConstant(self, n, **kwargs): b = cbrt(586 + 102*sqrt(33)) Tn = 3 * b * S.TribonacciConstant**n / (b**2 - 2*b + 4) return floor(Tn + S.Half) #----------------------------------------------------------------------------# # # # Bernoulli numbers # # # #----------------------------------------------------------------------------# class bernoulli(Function): r""" Bernoulli numbers / Bernoulli polynomials The Bernoulli numbers are a sequence of rational numbers defined by `B_0 = 1` and the recursive relation (`n > 0`): .. math :: 0 = \sum_{k=0}^n \binom{n+1}{k} B_k They are also commonly defined by their exponential generating function, which is `\frac{x}{e^x - 1}`. For odd indices > 1, the Bernoulli numbers are zero. The Bernoulli polynomials satisfy the analogous formula: .. math :: B_n(x) = \sum_{k=0}^n \binom{n}{k} B_k x^{n-k} Bernoulli numbers and Bernoulli polynomials are related as `B_n(0) = B_n`. We compute Bernoulli numbers using Ramanujan's formula: .. math :: B_n = \frac{A(n) - S(n)}{\binom{n+3}{n}} where: .. math :: A(n) = \begin{cases} \frac{n+3}{3} & n \equiv 0\ \text{or}\ 2 \pmod{6} \\ -\frac{n+3}{6} & n \equiv 4 \pmod{6} \end{cases} and: .. math :: S(n) = \sum_{k=1}^{[n/6]} \binom{n+3}{n-6k} B_{n-6k} This formula is similar to the sum given in the definition, but cuts 2/3 of the terms. For Bernoulli polynomials, we use the formula in the definition. * ``bernoulli(n)`` gives the nth Bernoulli number, `B_n` * ``bernoulli(n, x)`` gives the nth Bernoulli polynomial in `x`, `B_n(x)` Examples ======== >>> from sympy import bernoulli >>> [bernoulli(n) for n in range(11)] [1, -1/2, 1/6, 0, -1/30, 0, 1/42, 0, -1/30, 0, 5/66] >>> bernoulli(1000001) 0 See Also ======== bell, catalan, euler, fibonacci, harmonic, lucas, genocchi, partition, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Bernoulli_number .. [2] https://en.wikipedia.org/wiki/Bernoulli_polynomial .. [3] http://mathworld.wolfram.com/BernoulliNumber.html .. [4] http://mathworld.wolfram.com/BernoulliPolynomial.html """ # Calculates B_n for positive even n @staticmethod def _calc_bernoulli(n): s = 0 a = int(binomial(n + 3, n - 6)) for j in range(1, n//6 + 1): s += a * bernoulli(n - 6*j) # Avoid computing each binomial coefficient from scratch a *= _product(n - 6 - 6*j + 1, n - 6*j) a //= _product(6*j + 4, 6*j + 9) if n % 6 == 4: s = -Rational(n + 3, 6) - s else: s = Rational(n + 3, 3) - s return s / binomial(n + 3, n) # We implement a specialized memoization scheme to handle each # case modulo 6 separately _cache = {0: S.One, 2: Rational(1, 6), 4: Rational(-1, 30)} _highest = {0: 0, 2: 2, 4: 4} @classmethod def eval(cls, n, sym=None): if n.is_Number: if n.is_Integer and n.is_nonnegative: if n.is_zero: return S.One elif n is S.One: if sym is None: return Rational(-1, 2) else: return sym - S.Half # Bernoulli numbers elif sym is None: if n.is_odd: return S.Zero n = int(n) # Use mpmath for enormous Bernoulli numbers if n > 500: p, q = bernfrac(n) return Rational(int(p), int(q)) case = n % 6 highest_cached = cls._highest[case] if n <= highest_cached: return cls._cache[n] # To avoid excessive recursion when, say, bernoulli(1000) is # requested, calculate and cache the entire sequence ... B_988, # B_994, B_1000 in increasing order for i in range(highest_cached + 6, n + 6, 6): b = cls._calc_bernoulli(i) cls._cache[i] = b cls._highest[case] = i return b # Bernoulli polynomials else: n, result = int(n), [] for k in range(n + 1): result.append(binomial(n, k)*cls(k)*sym**(n - k)) return Add(*result) else: raise ValueError("Bernoulli numbers are defined only" " for nonnegative integer indices.") if sym is None: if n.is_odd and (n - 1).is_positive: return S.Zero #----------------------------------------------------------------------------# # # # Bell numbers # # # #----------------------------------------------------------------------------# class bell(Function): r""" Bell numbers / Bell polynomials The Bell numbers satisfy `B_0 = 1` and .. math:: B_n = \sum_{k=0}^{n-1} \binom{n-1}{k} B_k. They are also given by: .. math:: B_n = \frac{1}{e} \sum_{k=0}^{\infty} \frac{k^n}{k!}. The Bell polynomials are given by `B_0(x) = 1` and .. math:: B_n(x) = x \sum_{k=1}^{n-1} \binom{n-1}{k-1} B_{k-1}(x). The second kind of Bell polynomials (are sometimes called "partial" Bell polynomials or incomplete Bell polynomials) are defined as .. math:: B_{n,k}(x_1, x_2,\dotsc x_{n-k+1}) = \sum_{j_1+j_2+j_2+\dotsb=k \atop j_1+2j_2+3j_2+\dotsb=n} \frac{n!}{j_1!j_2!\dotsb j_{n-k+1}!} \left(\frac{x_1}{1!} \right)^{j_1} \left(\frac{x_2}{2!} \right)^{j_2} \dotsb \left(\frac{x_{n-k+1}}{(n-k+1)!} \right) ^{j_{n-k+1}}. * ``bell(n)`` gives the `n^{th}` Bell number, `B_n`. * ``bell(n, x)`` gives the `n^{th}` Bell polynomial, `B_n(x)`. * ``bell(n, k, (x1, x2, ...))`` gives Bell polynomials of the second kind, `B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})`. Notes ===== Not to be confused with Bernoulli numbers and Bernoulli polynomials, which use the same notation. Examples ======== >>> from sympy import bell, Symbol, symbols >>> [bell(n) for n in range(11)] [1, 1, 2, 5, 15, 52, 203, 877, 4140, 21147, 115975] >>> bell(30) 846749014511809332450147 >>> bell(4, Symbol('t')) t**4 + 6*t**3 + 7*t**2 + t >>> bell(6, 2, symbols('x:6')[1:]) 6*x1*x5 + 15*x2*x4 + 10*x3**2 See Also ======== bernoulli, catalan, euler, fibonacci, harmonic, lucas, genocchi, partition, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Bell_number .. [2] http://mathworld.wolfram.com/BellNumber.html .. [3] http://mathworld.wolfram.com/BellPolynomial.html """ @staticmethod @recurrence_memo([1, 1]) def _bell(n, prev): s = 1 a = 1 for k in range(1, n): a = a * (n - k) // k s += a * prev[k] return s @staticmethod @recurrence_memo([S.One, _sym]) def _bell_poly(n, prev): s = 1 a = 1 for k in range(2, n + 1): a = a * (n - k + 1) // (k - 1) s += a * prev[k - 1] return expand_mul(_sym * s) @staticmethod def _bell_incomplete_poly(n, k, symbols): r""" The second kind of Bell polynomials (incomplete Bell polynomials). Calculated by recurrence formula: .. math:: B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1}) = \sum_{m=1}^{n-k+1} \x_m \binom{n-1}{m-1} B_{n-m,k-1}(x_1, x_2, \dotsc, x_{n-m-k}) where `B_{0,0} = 1;` `B_{n,0} = 0; for n \ge 1` `B_{0,k} = 0; for k \ge 1` """ if (n == 0) and (k == 0): return S.One elif (n == 0) or (k == 0): return S.Zero s = S.Zero a = S.One for m in range(1, n - k + 2): s += a * bell._bell_incomplete_poly( n - m, k - 1, symbols) * symbols[m - 1] a = a * (n - m) / m return expand_mul(s) @classmethod def eval(cls, n, k_sym=None, symbols=None): if n is S.Infinity: if k_sym is None: return S.Infinity else: raise ValueError("Bell polynomial is not defined") if n.is_negative or n.is_integer is False: raise ValueError("a non-negative integer expected") if n.is_Integer and n.is_nonnegative: if k_sym is None: return Integer(cls._bell(int(n))) elif symbols is None: return cls._bell_poly(int(n)).subs(_sym, k_sym) else: r = cls._bell_incomplete_poly(int(n), int(k_sym), symbols) return r def _eval_rewrite_as_Sum(self, n, k_sym=None, symbols=None, **kwargs): from sympy import Sum if (k_sym is not None) or (symbols is not None): return self # Dobinski's formula if not n.is_nonnegative: return self k = Dummy('k', integer=True, nonnegative=True) return 1 / E * Sum(k**n / factorial(k), (k, 0, S.Infinity)) #----------------------------------------------------------------------------# # # # Harmonic numbers # # # #----------------------------------------------------------------------------# class harmonic(Function): r""" Harmonic numbers The nth harmonic number is given by `\operatorname{H}_{n} = 1 + \frac{1}{2} + \frac{1}{3} + \ldots + \frac{1}{n}`. More generally: .. math:: \operatorname{H}_{n,m} = \sum_{k=1}^{n} \frac{1}{k^m} As `n \rightarrow \infty`, `\operatorname{H}_{n,m} \rightarrow \zeta(m)`, the Riemann zeta function. * ``harmonic(n)`` gives the nth harmonic number, `\operatorname{H}_n` * ``harmonic(n, m)`` gives the nth generalized harmonic number of order `m`, `\operatorname{H}_{n,m}`, where ``harmonic(n) == harmonic(n, 1)`` Examples ======== >>> from sympy import harmonic, oo >>> [harmonic(n) for n in range(6)] [0, 1, 3/2, 11/6, 25/12, 137/60] >>> [harmonic(n, 2) for n in range(6)] [0, 1, 5/4, 49/36, 205/144, 5269/3600] >>> harmonic(oo, 2) pi**2/6 >>> from sympy import Symbol, Sum >>> n = Symbol("n") >>> harmonic(n).rewrite(Sum) Sum(1/_k, (_k, 1, n)) We can evaluate harmonic numbers for all integral and positive rational arguments: >>> from sympy import S, expand_func, simplify >>> harmonic(8) 761/280 >>> harmonic(11) 83711/27720 >>> H = harmonic(1/S(3)) >>> H harmonic(1/3) >>> He = expand_func(H) >>> He -log(6) - sqrt(3)*pi/6 + 2*Sum(log(sin(_k*pi/3))*cos(2*_k*pi/3), (_k, 1, 1)) + 3*Sum(1/(3*_k + 1), (_k, 0, 0)) >>> He.doit() -log(6) - sqrt(3)*pi/6 - log(sqrt(3)/2) + 3 >>> H = harmonic(25/S(7)) >>> He = simplify(expand_func(H).doit()) >>> He log(sin(2*pi/7)**(2*cos(16*pi/7))/(14*sin(pi/7)**(2*cos(pi/7))*cos(pi/14)**(2*sin(pi/14)))) + pi*tan(pi/14)/2 + 30247/9900 >>> He.n(40) 1.983697455232980674869851942390639915940 >>> harmonic(25/S(7)).n(40) 1.983697455232980674869851942390639915940 We can rewrite harmonic numbers in terms of polygamma functions: >>> from sympy import digamma, polygamma >>> m = Symbol("m") >>> harmonic(n).rewrite(digamma) polygamma(0, n + 1) + EulerGamma >>> harmonic(n).rewrite(polygamma) polygamma(0, n + 1) + EulerGamma >>> harmonic(n,3).rewrite(polygamma) polygamma(2, n + 1)/2 - polygamma(2, 1)/2 >>> harmonic(n,m).rewrite(polygamma) (-1)**m*(polygamma(m - 1, 1) - polygamma(m - 1, n + 1))/factorial(m - 1) Integer offsets in the argument can be pulled out: >>> from sympy import expand_func >>> expand_func(harmonic(n+4)) harmonic(n) + 1/(n + 4) + 1/(n + 3) + 1/(n + 2) + 1/(n + 1) >>> expand_func(harmonic(n-4)) harmonic(n) - 1/(n - 1) - 1/(n - 2) - 1/(n - 3) - 1/n Some limits can be computed as well: >>> from sympy import limit, oo >>> limit(harmonic(n), n, oo) oo >>> limit(harmonic(n, 2), n, oo) pi**2/6 >>> limit(harmonic(n, 3), n, oo) -polygamma(2, 1)/2 However we can not compute the general relation yet: >>> limit(harmonic(n, m), n, oo) harmonic(oo, m) which equals ``zeta(m)`` for ``m > 1``. See Also ======== bell, bernoulli, catalan, euler, fibonacci, lucas, genocchi, partition, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Harmonic_number .. [2] http://functions.wolfram.com/GammaBetaErf/HarmonicNumber/ .. [3] http://functions.wolfram.com/GammaBetaErf/HarmonicNumber2/ """ # Generate one memoized Harmonic number-generating function for each # order and store it in a dictionary _functions = {} # type: Dict[Integer, Callable[[int], Rational]] @classmethod def eval(cls, n, m=None): from sympy import zeta if m is S.One: return cls(n) if m is None: m = S.One if m.is_zero: return n if n is S.Infinity and m.is_Number: # TODO: Fix for symbolic values of m if m.is_negative: return S.NaN elif LessThan(m, S.One): return S.Infinity elif StrictGreaterThan(m, S.One): return zeta(m) else: return cls if n == 0: return S.Zero if n.is_Integer and n.is_nonnegative and m.is_Integer: if not m in cls._functions: @recurrence_memo([0]) def f(n, prev): return prev[-1] + S.One / n**m cls._functions[m] = f return cls._functions[m](int(n)) def _eval_rewrite_as_polygamma(self, n, m=1, **kwargs): from sympy.functions.special.gamma_functions import polygamma return S.NegativeOne**m/factorial(m - 1) * (polygamma(m - 1, 1) - polygamma(m - 1, n + 1)) def _eval_rewrite_as_digamma(self, n, m=1, **kwargs): from sympy.functions.special.gamma_functions import polygamma return self.rewrite(polygamma) def _eval_rewrite_as_trigamma(self, n, m=1, **kwargs): from sympy.functions.special.gamma_functions import polygamma return self.rewrite(polygamma) def _eval_rewrite_as_Sum(self, n, m=None, **kwargs): from sympy import Sum k = Dummy("k", integer=True) if m is None: m = S.One return Sum(k**(-m), (k, 1, n)) def _eval_expand_func(self, **hints): from sympy import Sum n = self.args[0] m = self.args[1] if len(self.args) == 2 else 1 if m == S.One: if n.is_Add: off = n.args[0] nnew = n - off if off.is_Integer and off.is_positive: result = [S.One/(nnew + i) for i in range(off, 0, -1)] + [harmonic(nnew)] return Add(*result) elif off.is_Integer and off.is_negative: result = [-S.One/(nnew + i) for i in range(0, off, -1)] + [harmonic(nnew)] return Add(*result) if n.is_Rational: # Expansions for harmonic numbers at general rational arguments (u + p/q) # Split n as u + p/q with p < q p, q = n.as_numer_denom() u = p // q p = p - u * q if u.is_nonnegative and p.is_positive and q.is_positive and p < q: k = Dummy("k") t1 = q * Sum(1 / (q * k + p), (k, 0, u)) t2 = 2 * Sum(cos((2 * pi * p * k) / S(q)) * log(sin((pi * k) / S(q))), (k, 1, floor((q - 1) / S(2)))) t3 = (pi / 2) * cot((pi * p) / q) + log(2 * q) return t1 + t2 - t3 return self def _eval_rewrite_as_tractable(self, n, m=1, limitvar=None, **kwargs): from sympy import polygamma return self.rewrite(polygamma).rewrite("tractable", deep=True) def _eval_evalf(self, prec): from sympy import polygamma if all(i.is_number for i in self.args): return self.rewrite(polygamma)._eval_evalf(prec) #----------------------------------------------------------------------------# # # # Euler numbers # # # #----------------------------------------------------------------------------# class euler(Function): r""" Euler numbers / Euler polynomials The Euler numbers are given by: .. math:: E_{2n} = I \sum_{k=1}^{2n+1} \sum_{j=0}^k \binom{k}{j} \frac{(-1)^j (k-2j)^{2n+1}}{2^k I^k k} .. math:: E_{2n+1} = 0 Euler numbers and Euler polynomials are related by .. math:: E_n = 2^n E_n\left(\frac{1}{2}\right). We compute symbolic Euler polynomials using [5]_ .. math:: E_n(x) = \sum_{k=0}^n \binom{n}{k} \frac{E_k}{2^k} \left(x - \frac{1}{2}\right)^{n-k}. However, numerical evaluation of the Euler polynomial is computed more efficiently (and more accurately) using the mpmath library. * ``euler(n)`` gives the `n^{th}` Euler number, `E_n`. * ``euler(n, x)`` gives the `n^{th}` Euler polynomial, `E_n(x)`. Examples ======== >>> from sympy import Symbol, S >>> from sympy.functions import euler >>> [euler(n) for n in range(10)] [1, 0, -1, 0, 5, 0, -61, 0, 1385, 0] >>> n = Symbol("n") >>> euler(n + 2*n) euler(3*n) >>> x = Symbol("x") >>> euler(n, x) euler(n, x) >>> euler(0, x) 1 >>> euler(1, x) x - 1/2 >>> euler(2, x) x**2 - x >>> euler(3, x) x**3 - 3*x**2/2 + 1/4 >>> euler(4, x) x**4 - 2*x**3 + x >>> euler(12, S.Half) 2702765/4096 >>> euler(12) 2702765 See Also ======== bell, bernoulli, catalan, fibonacci, harmonic, lucas, genocchi, partition, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Euler_numbers .. [2] http://mathworld.wolfram.com/EulerNumber.html .. [3] https://en.wikipedia.org/wiki/Alternating_permutation .. [4] http://mathworld.wolfram.com/AlternatingPermutation.html .. [5] http://dlmf.nist.gov/24.2#ii """ @classmethod def eval(cls, m, sym=None): if m.is_Number: if m.is_Integer and m.is_nonnegative: # Euler numbers if sym is None: if m.is_odd: return S.Zero from mpmath import mp m = m._to_mpmath(mp.prec) res = mp.eulernum(m, exact=True) return Integer(res) # Euler polynomial else: from sympy.core.evalf import pure_complex reim = pure_complex(sym, or_real=True) # Evaluate polynomial numerically using mpmath if reim and all(a.is_Float or a.is_Integer for a in reim) \ and any(a.is_Float for a in reim): from mpmath import mp from sympy import Expr m = int(m) # XXX ComplexFloat (#12192) would be nice here, above prec = min([a._prec for a in reim if a.is_Float]) with workprec(prec): res = mp.eulerpoly(m, sym) return Expr._from_mpmath(res, prec) # Construct polynomial symbolically from definition m, result = int(m), [] for k in range(m + 1): result.append(binomial(m, k)*cls(k)/(2**k)*(sym - S.Half)**(m - k)) return Add(*result).expand() else: raise ValueError("Euler numbers are defined only" " for nonnegative integer indices.") if sym is None: if m.is_odd and m.is_positive: return S.Zero def _eval_rewrite_as_Sum(self, n, x=None, **kwargs): from sympy import Sum if x is None and n.is_even: k = Dummy("k", integer=True) j = Dummy("j", integer=True) n = n / 2 Em = (S.ImaginaryUnit * Sum(Sum(binomial(k, j) * ((-1)**j * (k - 2*j)**(2*n + 1)) / (2**k*S.ImaginaryUnit**k * k), (j, 0, k)), (k, 1, 2*n + 1))) return Em if x: k = Dummy("k", integer=True) return Sum(binomial(n, k)*euler(k)/2**k*(x - S.Half)**(n - k), (k, 0, n)) def _eval_evalf(self, prec): m, x = (self.args[0], None) if len(self.args) == 1 else self.args if x is None and m.is_Integer and m.is_nonnegative: from mpmath import mp from sympy import Expr m = m._to_mpmath(prec) with workprec(prec): res = mp.eulernum(m) return Expr._from_mpmath(res, prec) if x and x.is_number and m.is_Integer and m.is_nonnegative: from mpmath import mp from sympy import Expr m = int(m) x = x._to_mpmath(prec) with workprec(prec): res = mp.eulerpoly(m, x) return Expr._from_mpmath(res, prec) #----------------------------------------------------------------------------# # # # Catalan numbers # # # #----------------------------------------------------------------------------# class catalan(Function): r""" Catalan numbers The `n^{th}` catalan number is given by: .. math :: C_n = \frac{1}{n+1} \binom{2n}{n} * ``catalan(n)`` gives the `n^{th}` Catalan number, `C_n` Examples ======== >>> from sympy import (Symbol, binomial, gamma, hyper, catalan, ... diff, combsimp, Rational, I) >>> [catalan(i) for i in range(1,10)] [1, 2, 5, 14, 42, 132, 429, 1430, 4862] >>> n = Symbol("n", integer=True) >>> catalan(n) catalan(n) Catalan numbers can be transformed into several other, identical expressions involving other mathematical functions >>> catalan(n).rewrite(binomial) binomial(2*n, n)/(n + 1) >>> catalan(n).rewrite(gamma) 4**n*gamma(n + 1/2)/(sqrt(pi)*gamma(n + 2)) >>> catalan(n).rewrite(hyper) hyper((1 - n, -n), (2,), 1) For some non-integer values of n we can get closed form expressions by rewriting in terms of gamma functions: >>> catalan(Rational(1, 2)).rewrite(gamma) 8/(3*pi) We can differentiate the Catalan numbers C(n) interpreted as a continuous real function in n: >>> diff(catalan(n), n) (polygamma(0, n + 1/2) - polygamma(0, n + 2) + log(4))*catalan(n) As a more advanced example consider the following ratio between consecutive numbers: >>> combsimp((catalan(n + 1)/catalan(n)).rewrite(binomial)) 2*(2*n + 1)/(n + 2) The Catalan numbers can be generalized to complex numbers: >>> catalan(I).rewrite(gamma) 4**I*gamma(1/2 + I)/(sqrt(pi)*gamma(2 + I)) and evaluated with arbitrary precision: >>> catalan(I).evalf(20) 0.39764993382373624267 - 0.020884341620842555705*I See Also ======== bell, bernoulli, euler, fibonacci, harmonic, lucas, genocchi, partition, tribonacci sympy.functions.combinatorial.factorials.binomial References ========== .. [1] https://en.wikipedia.org/wiki/Catalan_number .. [2] http://mathworld.wolfram.com/CatalanNumber.html .. [3] http://functions.wolfram.com/GammaBetaErf/CatalanNumber/ .. [4] http://geometer.org/mathcircles/catalan.pdf """ @classmethod def eval(cls, n): from sympy import gamma if (n.is_Integer and n.is_nonnegative) or \ (n.is_noninteger and n.is_negative): return 4**n*gamma(n + S.Half)/(gamma(S.Half)*gamma(n + 2)) if (n.is_integer and n.is_negative): if (n + 1).is_negative: return S.Zero if (n + 1).is_zero: return Rational(-1, 2) def fdiff(self, argindex=1): from sympy import polygamma, log n = self.args[0] return catalan(n)*(polygamma(0, n + S.Half) - polygamma(0, n + 2) + log(4)) def _eval_rewrite_as_binomial(self, n, **kwargs): return binomial(2*n, n)/(n + 1) def _eval_rewrite_as_factorial(self, n, **kwargs): return factorial(2*n) / (factorial(n+1) * factorial(n)) def _eval_rewrite_as_gamma(self, n, piecewise=True, **kwargs): from sympy import gamma # The gamma function allows to generalize Catalan numbers to complex n return 4**n*gamma(n + S.Half)/(gamma(S.Half)*gamma(n + 2)) def _eval_rewrite_as_hyper(self, n, **kwargs): from sympy import hyper return hyper([1 - n, -n], [2], 1) def _eval_rewrite_as_Product(self, n, **kwargs): from sympy import Product if not (n.is_integer and n.is_nonnegative): return self k = Dummy('k', integer=True, positive=True) return Product((n + k) / k, (k, 2, n)) def _eval_is_integer(self): if self.args[0].is_integer and self.args[0].is_nonnegative: return True def _eval_is_positive(self): if self.args[0].is_nonnegative: return True def _eval_is_composite(self): if self.args[0].is_integer and (self.args[0] - 3).is_positive: return True def _eval_evalf(self, prec): from sympy import gamma if self.args[0].is_number: return self.rewrite(gamma)._eval_evalf(prec) #----------------------------------------------------------------------------# # # # Genocchi numbers # # # #----------------------------------------------------------------------------# class genocchi(Function): r""" Genocchi numbers The Genocchi numbers are a sequence of integers `G_n` that satisfy the relation: .. math:: \frac{2t}{e^t + 1} = \sum_{n=1}^\infty \frac{G_n t^n}{n!} Examples ======== >>> from sympy import Symbol >>> from sympy.functions import genocchi >>> [genocchi(n) for n in range(1, 9)] [1, -1, 0, 1, 0, -3, 0, 17] >>> n = Symbol('n', integer=True, positive=True) >>> genocchi(2*n + 1) 0 See Also ======== bell, bernoulli, catalan, euler, fibonacci, harmonic, lucas, partition, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Genocchi_number .. [2] http://mathworld.wolfram.com/GenocchiNumber.html """ @classmethod def eval(cls, n): if n.is_Number: if (not n.is_Integer) or n.is_nonpositive: raise ValueError("Genocchi numbers are defined only for " + "positive integers") return 2 * (1 - S(2) ** n) * bernoulli(n) if n.is_odd and (n - 1).is_positive: return S.Zero if (n - 1).is_zero: return S.One def _eval_rewrite_as_bernoulli(self, n, **kwargs): if n.is_integer and n.is_nonnegative: return (1 - S(2) ** n) * bernoulli(n) * 2 def _eval_is_integer(self): if self.args[0].is_integer and self.args[0].is_positive: return True def _eval_is_negative(self): n = self.args[0] if n.is_integer and n.is_positive: if n.is_odd: return False return (n / 2).is_odd def _eval_is_positive(self): n = self.args[0] if n.is_integer and n.is_positive: if n.is_odd: return fuzzy_not((n - 1).is_positive) return (n / 2).is_even def _eval_is_even(self): n = self.args[0] if n.is_integer and n.is_positive: if n.is_even: return False return (n - 1).is_positive def _eval_is_odd(self): n = self.args[0] if n.is_integer and n.is_positive: if n.is_even: return True return fuzzy_not((n - 1).is_positive) def _eval_is_prime(self): n = self.args[0] # only G_6 = -3 and G_8 = 17 are prime, # but SymPy does not consider negatives as prime # so only n=8 is tested return (n - 8).is_zero #----------------------------------------------------------------------------# # # # Partition numbers # # # #----------------------------------------------------------------------------# _npartition = [1, 1] class partition(Function): r""" Partition numbers The Partition numbers are a sequence of integers `p_n` that represent the number of distinct ways of representing `n` as a sum of natural numbers (with order irrelevant). The generating function for `p_n` is given by: .. math:: \sum_{n=0}^\infty p_n x^n = \prod_{k=1}^\infty (1 - x^k)^{-1} Examples ======== >>> from sympy import Symbol >>> from sympy.functions import partition >>> [partition(n) for n in range(9)] [1, 1, 2, 3, 5, 7, 11, 15, 22] >>> n = Symbol('n', integer=True, negative=True) >>> partition(n) 0 See Also ======== bell, bernoulli, catalan, euler, fibonacci, harmonic, lucas, genocchi, tribonacci References ========== .. [1] https://en.wikipedia.org/wiki/Partition_(number_theory%29 .. [2] https://en.wikipedia.org/wiki/Pentagonal_number_theorem """ @staticmethod def _partition(n): L = len(_npartition) if n < L: return _npartition[n] # lengthen cache for _n in range(L, n + 1): v, p, i = 0, 0, 0 while 1: s = 0 p += 3*i + 1 # p = pentagonal number: 1, 5, 12, ... if _n >= p: s += _npartition[_n - p] i += 1 gp = p + i # gp = generalized pentagonal: 2, 7, 15, ... if _n >= gp: s += _npartition[_n - gp] if s == 0: break else: v += s if i%2 == 1 else -s _npartition.append(v) return v @classmethod def eval(cls, n): is_int = n.is_integer if is_int == False: raise ValueError("Partition numbers are defined only for " "integers") elif is_int: if n.is_negative: return S.Zero if n.is_zero or (n - 1).is_zero: return S.One if n.is_Integer: return Integer(cls._partition(n)) def _eval_is_integer(self): if self.args[0].is_integer: return True def _eval_is_negative(self): if self.args[0].is_integer: return False def _eval_is_positive(self): n = self.args[0] if n.is_nonnegative and n.is_integer: return True ####################################################################### ### ### Functions for enumerating partitions, permutations and combinations ### ####################################################################### class _MultisetHistogram(tuple): pass _N = -1 _ITEMS = -2 _M = slice(None, _ITEMS) def _multiset_histogram(n): """Return tuple used in permutation and combination counting. Input is a dictionary giving items with counts as values or a sequence of items (which need not be sorted). The data is stored in a class deriving from tuple so it is easily recognized and so it can be converted easily to a list. """ if isinstance(n, dict): # item: count if not all(isinstance(v, int) and v >= 0 for v in n.values()): raise ValueError tot = sum(n.values()) items = sum(1 for k in n if n[k] > 0) return _MultisetHistogram([n[k] for k in n if n[k] > 0] + [items, tot]) else: n = list(n) s = set(n) if len(s) == len(n): n = [1]*len(n) n.extend([len(n), len(n)]) return _MultisetHistogram(n) m = dict(zip(s, range(len(s)))) d = dict(zip(range(len(s)), [0]*len(s))) for i in n: d[m[i]] += 1 return _multiset_histogram(d) def nP(n, k=None, replacement=False): """Return the number of permutations of ``n`` items taken ``k`` at a time. Possible values for ``n``: integer - set of length ``n`` sequence - converted to a multiset internally multiset - {element: multiplicity} If ``k`` is None then the total of all permutations of length 0 through the number of items represented by ``n`` will be returned. If ``replacement`` is True then a given item can appear more than once in the ``k`` items. (For example, for 'ab' permutations of 2 would include 'aa', 'ab', 'ba' and 'bb'.) The multiplicity of elements in ``n`` is ignored when ``replacement`` is True but the total number of elements is considered since no element can appear more times than the number of elements in ``n``. Examples ======== >>> from sympy.functions.combinatorial.numbers import nP >>> from sympy.utilities.iterables import multiset_permutations, multiset >>> nP(3, 2) 6 >>> nP('abc', 2) == nP(multiset('abc'), 2) == 6 True >>> nP('aab', 2) 3 >>> nP([1, 2, 2], 2) 3 >>> [nP(3, i) for i in range(4)] [1, 3, 6, 6] >>> nP(3) == sum(_) True When ``replacement`` is True, each item can have multiplicity equal to the length represented by ``n``: >>> nP('aabc', replacement=True) 121 >>> [len(list(multiset_permutations('aaaabbbbcccc', i))) for i in range(5)] [1, 3, 9, 27, 81] >>> sum(_) 121 See Also ======== sympy.utilities.iterables.multiset_permutations References ========== .. [1] https://en.wikipedia.org/wiki/Permutation """ try: n = as_int(n) except ValueError: return Integer(_nP(_multiset_histogram(n), k, replacement)) return Integer(_nP(n, k, replacement)) @cacheit def _nP(n, k=None, replacement=False): from sympy.functions.combinatorial.factorials import factorial from sympy.core.mul import prod if k == 0: return 1 if isinstance(n, SYMPY_INTS): # n different items # assert n >= 0 if k is None: return sum(_nP(n, i, replacement) for i in range(n + 1)) elif replacement: return n**k elif k > n: return 0 elif k == n: return factorial(k) elif k == 1: return n else: # assert k >= 0 return _product(n - k + 1, n) elif isinstance(n, _MultisetHistogram): if k is None: return sum(_nP(n, i, replacement) for i in range(n[_N] + 1)) elif replacement: return n[_ITEMS]**k elif k == n[_N]: return factorial(k)/prod([factorial(i) for i in n[_M] if i > 1]) elif k > n[_N]: return 0 elif k == 1: return n[_ITEMS] else: # assert k >= 0 tot = 0 n = list(n) for i in range(len(n[_M])): if not n[i]: continue n[_N] -= 1 if n[i] == 1: n[i] = 0 n[_ITEMS] -= 1 tot += _nP(_MultisetHistogram(n), k - 1) n[_ITEMS] += 1 n[i] = 1 else: n[i] -= 1 tot += _nP(_MultisetHistogram(n), k - 1) n[i] += 1 n[_N] += 1 return tot @cacheit def _AOP_product(n): """for n = (m1, m2, .., mk) return the coefficients of the polynomial, prod(sum(x**i for i in range(nj + 1)) for nj in n); i.e. the coefficients of the product of AOPs (all-one polynomials) or order given in n. The resulting coefficient corresponding to x**r is the number of r-length combinations of sum(n) elements with multiplicities given in n. The coefficients are given as a default dictionary (so if a query is made for a key that is not present, 0 will be returned). Examples ======== >>> from sympy.functions.combinatorial.numbers import _AOP_product >>> from sympy.abc import x >>> n = (2, 2, 3) # e.g. aabbccc >>> prod = ((x**2 + x + 1)*(x**2 + x + 1)*(x**3 + x**2 + x + 1)).expand() >>> c = _AOP_product(n); dict(c) {0: 1, 1: 3, 2: 6, 3: 8, 4: 8, 5: 6, 6: 3, 7: 1} >>> [c[i] for i in range(8)] == [prod.coeff(x, i) for i in range(8)] True The generating poly used here is the same as that listed in http://tinyurl.com/cep849r, but in a refactored form. """ from collections import defaultdict n = list(n) ord = sum(n) need = (ord + 2)//2 rv = [1]*(n.pop() + 1) rv.extend([0]*(need - len(rv))) rv = rv[:need] while n: ni = n.pop() N = ni + 1 was = rv[:] for i in range(1, min(N, len(rv))): rv[i] += rv[i - 1] for i in range(N, need): rv[i] += rv[i - 1] - was[i - N] rev = list(reversed(rv)) if ord % 2: rv = rv + rev else: rv[-1:] = rev d = defaultdict(int) for i in range(len(rv)): d[i] = rv[i] return d def nC(n, k=None, replacement=False): """Return the number of combinations of ``n`` items taken ``k`` at a time. Possible values for ``n``: integer - set of length ``n`` sequence - converted to a multiset internally multiset - {element: multiplicity} If ``k`` is None then the total of all combinations of length 0 through the number of items represented in ``n`` will be returned. If ``replacement`` is True then a given item can appear more than once in the ``k`` items. (For example, for 'ab' sets of 2 would include 'aa', 'ab', and 'bb'.) The multiplicity of elements in ``n`` is ignored when ``replacement`` is True but the total number of elements is considered since no element can appear more times than the number of elements in ``n``. Examples ======== >>> from sympy.functions.combinatorial.numbers import nC >>> from sympy.utilities.iterables import multiset_combinations >>> nC(3, 2) 3 >>> nC('abc', 2) 3 >>> nC('aab', 2) 2 When ``replacement`` is True, each item can have multiplicity equal to the length represented by ``n``: >>> nC('aabc', replacement=True) 35 >>> [len(list(multiset_combinations('aaaabbbbcccc', i))) for i in range(5)] [1, 3, 6, 10, 15] >>> sum(_) 35 If there are ``k`` items with multiplicities ``m_1, m_2, ..., m_k`` then the total of all combinations of length 0 through ``k`` is the product, ``(m_1 + 1)*(m_2 + 1)*...*(m_k + 1)``. When the multiplicity of each item is 1 (i.e., k unique items) then there are 2**k combinations. For example, if there are 4 unique items, the total number of combinations is 16: >>> sum(nC(4, i) for i in range(5)) 16 See Also ======== sympy.utilities.iterables.multiset_combinations References ========== .. [1] https://en.wikipedia.org/wiki/Combination .. [2] http://tinyurl.com/cep849r """ from sympy.functions.combinatorial.factorials import binomial from sympy.core.mul import prod if isinstance(n, SYMPY_INTS): if k is None: if not replacement: return 2**n return sum(nC(n, i, replacement) for i in range(n + 1)) if k < 0: raise ValueError("k cannot be negative") if replacement: return binomial(n + k - 1, k) return binomial(n, k) if isinstance(n, _MultisetHistogram): N = n[_N] if k is None: if not replacement: return prod(m + 1 for m in n[_M]) return sum(nC(n, i, replacement) for i in range(N + 1)) elif replacement: return nC(n[_ITEMS], k, replacement) # assert k >= 0 elif k in (1, N - 1): return n[_ITEMS] elif k in (0, N): return 1 return _AOP_product(tuple(n[_M]))[k] else: return nC(_multiset_histogram(n), k, replacement) def _eval_stirling1(n, k): if n == k == 0: return S.One if 0 in (n, k): return S.Zero # some special values if n == k: return S.One elif k == n - 1: return binomial(n, 2) elif k == n - 2: return (3*n - 1)*binomial(n, 3)/4 elif k == n - 3: return binomial(n, 2)*binomial(n, 4) return _stirling1(n, k) @cacheit def _stirling1(n, k): row = [0, 1]+[0]*(k-1) # for n = 1 for i in range(2, n+1): for j in range(min(k,i), 0, -1): row[j] = (i-1) * row[j] + row[j-1] return Integer(row[k]) def _eval_stirling2(n, k): if n == k == 0: return S.One if 0 in (n, k): return S.Zero # some special values if n == k: return S.One elif k == n - 1: return binomial(n, 2) elif k == 1: return S.One elif k == 2: return Integer(2**(n - 1) - 1) return _stirling2(n, k) @cacheit def _stirling2(n, k): row = [0, 1]+[0]*(k-1) # for n = 1 for i in range(2, n+1): for j in range(min(k,i), 0, -1): row[j] = j * row[j] + row[j-1] return Integer(row[k]) def stirling(n, k, d=None, kind=2, signed=False): r"""Return Stirling number $S(n, k)$ of the first or second (default) kind. The sum of all Stirling numbers of the second kind for $k = 1$ through $n$ is ``bell(n)``. The recurrence relationship for these numbers is: .. math :: {0 \brace 0} = 1; {n \brace 0} = {0 \brace k} = 0; .. math :: {{n+1} \brace k} = j {n \brace k} + {n \brace {k-1}} where $j$ is: $n$ for Stirling numbers of the first kind, $-n$ for signed Stirling numbers of the first kind, $k$ for Stirling numbers of the second kind. The first kind of Stirling number counts the number of permutations of ``n`` distinct items that have ``k`` cycles; the second kind counts the ways in which ``n`` distinct items can be partitioned into ``k`` parts. If ``d`` is given, the "reduced Stirling number of the second kind" is returned: $S^{d}(n, k) = S(n - d + 1, k - d + 1)$ with $n \ge k \ge d$. (This counts the ways to partition $n$ consecutive integers into $k$ groups with no pairwise difference less than $d$. See example below.) To obtain the signed Stirling numbers of the first kind, use keyword ``signed=True``. Using this keyword automatically sets ``kind`` to 1. Examples ======== >>> from sympy.functions.combinatorial.numbers import stirling, bell >>> from sympy.combinatorics import Permutation >>> from sympy.utilities.iterables import multiset_partitions, permutations First kind (unsigned by default): >>> [stirling(6, i, kind=1) for i in range(7)] [0, 120, 274, 225, 85, 15, 1] >>> perms = list(permutations(range(4))) >>> [sum(Permutation(p).cycles == i for p in perms) for i in range(5)] [0, 6, 11, 6, 1] >>> [stirling(4, i, kind=1) for i in range(5)] [0, 6, 11, 6, 1] First kind (signed): >>> [stirling(4, i, signed=True) for i in range(5)] [0, -6, 11, -6, 1] Second kind: >>> [stirling(10, i) for i in range(12)] [0, 1, 511, 9330, 34105, 42525, 22827, 5880, 750, 45, 1, 0] >>> sum(_) == bell(10) True >>> len(list(multiset_partitions(range(4), 2))) == stirling(4, 2) True Reduced second kind: >>> from sympy import subsets, oo >>> def delta(p): ... if len(p) == 1: ... return oo ... return min(abs(i[0] - i[1]) for i in subsets(p, 2)) >>> parts = multiset_partitions(range(5), 3) >>> d = 2 >>> sum(1 for p in parts if all(delta(i) >= d for i in p)) 7 >>> stirling(5, 3, 2) 7 See Also ======== sympy.utilities.iterables.multiset_partitions References ========== .. [1] https://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind .. [2] https://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind """ # TODO: make this a class like bell() n = as_int(n) k = as_int(k) if n < 0: raise ValueError('n must be nonnegative') if k > n: return S.Zero if d: # assert k >= d # kind is ignored -- only kind=2 is supported return _eval_stirling2(n - d + 1, k - d + 1) elif signed: # kind is ignored -- only kind=1 is supported return (-1)**(n - k)*_eval_stirling1(n, k) if kind == 1: return _eval_stirling1(n, k) elif kind == 2: return _eval_stirling2(n, k) else: raise ValueError('kind must be 1 or 2, not %s' % k) @cacheit def _nT(n, k): """Return the partitions of ``n`` items into ``k`` parts. This is used by ``nT`` for the case when ``n`` is an integer.""" # really quick exits if k > n or k < 0: return 0 if k == n or k == 1: return 1 if k == 0: return 0 # exits that could be done below but this is quicker if k == 2: return n//2 d = n - k if d <= 3: return d # quick exit if 3*k >= n: # or, equivalently, 2*k >= d # all the information needed in this case # will be in the cache needed to calculate # partition(d), so... # update cache tot = partition._partition(d) # and correct for values not needed if d - k > 0: tot -= sum(_npartition[:d - k]) return tot # regular exit # nT(n, k) = Sum(nT(n - k, m), (m, 1, k)); # calculate needed nT(i, j) values p = [1]*d for i in range(2, k + 1): for m in range(i + 1, d): p[m] += p[m - i] d -= 1 # if p[0] were appended to the end of p then the last # k values of p are the nT(n, j) values for 0 < j < k in reverse # order p[-1] = nT(n, 1), p[-2] = nT(n, 2), etc.... Instead of # putting the 1 from p[0] there, however, it is simply added to # the sum below which is valid for 1 < k <= n//2 return (1 + sum(p[1 - k:])) def nT(n, k=None): """Return the number of ``k``-sized partitions of ``n`` items. Possible values for ``n``: integer - ``n`` identical items sequence - converted to a multiset internally multiset - {element: multiplicity} Note: the convention for ``nT`` is different than that of ``nC`` and ``nP`` in that here an integer indicates ``n`` *identical* items instead of a set of length ``n``; this is in keeping with the ``partitions`` function which treats its integer-``n`` input like a list of ``n`` 1s. One can use ``range(n)`` for ``n`` to indicate ``n`` distinct items. If ``k`` is None then the total number of ways to partition the elements represented in ``n`` will be returned. Examples ======== >>> from sympy.functions.combinatorial.numbers import nT Partitions of the given multiset: >>> [nT('aabbc', i) for i in range(1, 7)] [1, 8, 11, 5, 1, 0] >>> nT('aabbc') == sum(_) True >>> [nT("mississippi", i) for i in range(1, 12)] [1, 74, 609, 1521, 1768, 1224, 579, 197, 50, 9, 1] Partitions when all items are identical: >>> [nT(5, i) for i in range(1, 6)] [1, 2, 2, 1, 1] >>> nT('1'*5) == sum(_) True When all items are different: >>> [nT(range(5), i) for i in range(1, 6)] [1, 15, 25, 10, 1] >>> nT(range(5)) == sum(_) True Partitions of an integer expressed as a sum of positive integers: >>> from sympy.functions.combinatorial.numbers import partition >>> partition(4) 5 >>> nT(4, 1) + nT(4, 2) + nT(4, 3) + nT(4, 4) 5 >>> nT('1'*4) 5 See Also ======== sympy.utilities.iterables.partitions sympy.utilities.iterables.multiset_partitions sympy.functions.combinatorial.numbers.partition References ========== .. [1] http://undergraduate.csse.uwa.edu.au/units/CITS7209/partition.pdf """ from sympy.utilities.enumerative import MultisetPartitionTraverser if isinstance(n, SYMPY_INTS): # n identical items if k is None: return partition(n) if isinstance(k, SYMPY_INTS): n = as_int(n) k = as_int(k) return Integer(_nT(n, k)) if not isinstance(n, _MultisetHistogram): try: # if n contains hashable items there is some # quick handling that can be done u = len(set(n)) if u <= 1: return nT(len(n), k) elif u == len(n): n = range(u) raise TypeError except TypeError: n = _multiset_histogram(n) N = n[_N] if k is None and N == 1: return 1 if k in (1, N): return 1 if k == 2 or N == 2 and k is None: m, r = divmod(N, 2) rv = sum(nC(n, i) for i in range(1, m + 1)) if not r: rv -= nC(n, m)//2 if k is None: rv += 1 # for k == 1 return rv if N == n[_ITEMS]: # all distinct if k is None: return bell(N) return stirling(N, k) m = MultisetPartitionTraverser() if k is None: return m.count_partitions(n[_M]) # MultisetPartitionTraverser does not have a range-limited count # method, so need to enumerate and count tot = 0 for discard in m.enum_range(n[_M], k-1, k): tot += 1 return tot #-----------------------------------------------------------------------------# # # # Motzkin numbers # # # #-----------------------------------------------------------------------------# class motzkin(Function): """ The nth Motzkin number is the number of ways of drawing non-intersecting chords between n points on a circle (not necessarily touching every point by a chord). The Motzkin numbers are named after Theodore Motzkin and have diverse applications in geometry, combinatorics and number theory. Motzkin numbers are the integer sequence defined by the initial terms `M_0 = 1`, `M_1 = 1` and the two-term recurrence relation `M_n = \frac{2*n + 1}{n + 2} * M_{n-1} + \frac{3n - 3}{n + 2} * M_{n-2}`. Examples ======== >>> from sympy import motzkin >>> motzkin.is_motzkin(5) False >>> motzkin.find_motzkin_numbers_in_range(2,300) [2, 4, 9, 21, 51, 127] >>> motzkin.find_motzkin_numbers_in_range(2,900) [2, 4, 9, 21, 51, 127, 323, 835] >>> motzkin.find_first_n_motzkins(10) [1, 1, 2, 4, 9, 21, 51, 127, 323, 835] References ========== .. [1] https://en.wikipedia.org/wiki/Motzkin_number .. [2] https://mathworld.wolfram.com/MotzkinNumber.html """ @staticmethod def is_motzkin(n): try: n = as_int(n) except ValueError: return False if n > 0: if n == 1 or n == 2: return True tn1 = 1 tn = 2 i = 3 while tn < n: a = ((2*i + 1)*tn + (3*i - 3)*tn1)/(i + 2) i += 1 tn1 = tn tn = a if tn == n: return True else: return False else: return False @staticmethod def find_motzkin_numbers_in_range(x, y): if 0 <= x <= y: motzkins = list() if x <= 1 <= y: motzkins.append(1) tn1 = 1 tn = 2 i = 3 while tn <= y: if tn >= x: motzkins.append(tn) a = ((2*i + 1)*tn + (3*i - 3)*tn1)/(i + 2) i += 1 tn1 = tn tn = int(a) return motzkins else: raise ValueError('The provided range is not valid. This condition should satisfy x <= y') @staticmethod def find_first_n_motzkins(n): try: n = as_int(n) except ValueError: raise ValueError('The provided number must be a positive integer') if n < 0: raise ValueError('The provided number must be a positive integer') motzkins = [1] if n >= 1: motzkins.append(1) tn1 = 1 tn = 2 i = 3 while i <= n: motzkins.append(tn) a = ((2*i + 1)*tn + (3*i - 3)*tn1)/(i + 2) i += 1 tn1 = tn tn = int(a) return motzkins @staticmethod @recurrence_memo([S.One, S.One]) def _motzkin(n, prev): return ((2*n + 1)*prev[-1] + (3*n - 3)*prev[-2]) // (n + 2) @classmethod def eval(cls, n): try: n = as_int(n) except ValueError: raise ValueError('The provided number must be a positive integer') if n < 0: raise ValueError('The provided number must be a positive integer') return Integer(cls._motzkin(n - 1)) sympy-sympy-1.9/sympy/functions/combinatorial/tests/000077500000000000000000000000001412543434000231015ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/combinatorial/tests/__init__.py000066400000000000000000000000001412543434000252000ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/combinatorial/tests/test_comb_factorials.py000066400000000000000000000621251412543434000276470ustar00rootroot00000000000000from sympy import (S, Symbol, symbols, factorial, factorial2, Float, binomial, rf, ff, gamma, polygamma, EulerGamma, O, pi, nan, oo, zoo, simplify, expand_func, Product, Mul, Piecewise, Mod, Eq, sqrt, Poly, Dummy, I, Rational) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.functions.combinatorial.factorials import subfactorial from sympy.functions.special.gamma_functions import uppergamma from sympy.testing.pytest import XFAIL, raises, slow #Solves and Fixes Issue #10388 - This is the updated test for the same solved issue def test_rf_eval_apply(): x, y = symbols('x,y') n, k = symbols('n k', integer=True) m = Symbol('m', integer=True, nonnegative=True) assert rf(nan, y) is nan assert rf(x, nan) is nan assert unchanged(rf, x, y) assert rf(oo, 0) == 1 assert rf(-oo, 0) == 1 assert rf(oo, 6) is oo assert rf(-oo, 7) is -oo assert rf(-oo, 6) is oo assert rf(oo, -6) is oo assert rf(-oo, -7) is oo assert rf(-1, pi) == 0 assert rf(-5, 1 + I) == 0 assert unchanged(rf, -3, k) assert unchanged(rf, x, Symbol('k', integer=False)) assert rf(-3, Symbol('k', integer=False)) == 0 assert rf(Symbol('x', negative=True, integer=True), Symbol('k', integer=False)) == 0 assert rf(x, 0) == 1 assert rf(x, 1) == x assert rf(x, 2) == x*(x + 1) assert rf(x, 3) == x*(x + 1)*(x + 2) assert rf(x, 5) == x*(x + 1)*(x + 2)*(x + 3)*(x + 4) assert rf(x, -1) == 1/(x - 1) assert rf(x, -2) == 1/((x - 1)*(x - 2)) assert rf(x, -3) == 1/((x - 1)*(x - 2)*(x - 3)) assert rf(1, 100) == factorial(100) assert rf(x**2 + 3*x, 2) == (x**2 + 3*x)*(x**2 + 3*x + 1) assert isinstance(rf(x**2 + 3*x, 2), Mul) assert rf(x**3 + x, -2) == 1/((x**3 + x - 1)*(x**3 + x - 2)) assert rf(Poly(x**2 + 3*x, x), 2) == Poly(x**4 + 8*x**3 + 19*x**2 + 12*x, x) assert isinstance(rf(Poly(x**2 + 3*x, x), 2), Poly) raises(ValueError, lambda: rf(Poly(x**2 + 3*x, x, y), 2)) assert rf(Poly(x**3 + x, x), -2) == 1/(x**6 - 9*x**5 + 35*x**4 - 75*x**3 + 94*x**2 - 66*x + 20) raises(ValueError, lambda: rf(Poly(x**3 + x, x, y), -2)) assert rf(x, m).is_integer is None assert rf(n, k).is_integer is None assert rf(n, m).is_integer is True assert rf(n, k + pi).is_integer is False assert rf(n, m + pi).is_integer is False assert rf(pi, m).is_integer is False def check(x, k, o, n): a, b = Dummy(), Dummy() r = lambda x, k: o(a, b).rewrite(n).subs({a:x,b:k}) for i in range(-5,5): for j in range(-5,5): assert o(i, j) == r(i, j), (o, n, i, j) check(x, k, rf, ff) check(x, k, rf, binomial) check(n, k, rf, factorial) check(x, y, rf, factorial) check(x, y, rf, binomial) assert rf(x, k).rewrite(ff) == ff(x + k - 1, k) assert rf(x, k).rewrite(gamma) == Piecewise( (gamma(k + x)/gamma(x), x > 0), ((-1)**k*gamma(1 - x)/gamma(-k - x + 1), True)) assert rf(5, k).rewrite(gamma) == gamma(k + 5)/24 assert rf(x, k).rewrite(binomial) == factorial(k)*binomial(x + k - 1, k) assert rf(n, k).rewrite(factorial) == Piecewise( (factorial(k + n - 1)/factorial(n - 1), n > 0), ((-1)**k*factorial(-n)/factorial(-k - n), True)) assert rf(5, k).rewrite(factorial) == factorial(k + 4)/24 assert rf(x, y).rewrite(factorial) == rf(x, y) assert rf(x, y).rewrite(binomial) == rf(x, y) import random from mpmath import rf as mpmath_rf for i in range(100): x = -500 + 500 * random.random() k = -500 + 500 * random.random() assert (abs(mpmath_rf(x, k) - rf(x, k)) < 10**(-15)) def test_ff_eval_apply(): x, y = symbols('x,y') n, k = symbols('n k', integer=True) m = Symbol('m', integer=True, nonnegative=True) assert ff(nan, y) is nan assert ff(x, nan) is nan assert unchanged(ff, x, y) assert ff(oo, 0) == 1 assert ff(-oo, 0) == 1 assert ff(oo, 6) is oo assert ff(-oo, 7) is -oo assert ff(-oo, 6) is oo assert ff(oo, -6) is oo assert ff(-oo, -7) is oo assert ff(x, 0) == 1 assert ff(x, 1) == x assert ff(x, 2) == x*(x - 1) assert ff(x, 3) == x*(x - 1)*(x - 2) assert ff(x, 5) == x*(x - 1)*(x - 2)*(x - 3)*(x - 4) assert ff(x, -1) == 1/(x + 1) assert ff(x, -2) == 1/((x + 1)*(x + 2)) assert ff(x, -3) == 1/((x + 1)*(x + 2)*(x + 3)) assert ff(100, 100) == factorial(100) assert ff(2*x**2 - 5*x, 2) == (2*x**2 - 5*x)*(2*x**2 - 5*x - 1) assert isinstance(ff(2*x**2 - 5*x, 2), Mul) assert ff(x**2 + 3*x, -2) == 1/((x**2 + 3*x + 1)*(x**2 + 3*x + 2)) assert ff(Poly(2*x**2 - 5*x, x), 2) == Poly(4*x**4 - 28*x**3 + 59*x**2 - 35*x, x) assert isinstance(ff(Poly(2*x**2 - 5*x, x), 2), Poly) raises(ValueError, lambda: ff(Poly(2*x**2 - 5*x, x, y), 2)) assert ff(Poly(x**2 + 3*x, x), -2) == 1/(x**4 + 12*x**3 + 49*x**2 + 78*x + 40) raises(ValueError, lambda: ff(Poly(x**2 + 3*x, x, y), -2)) assert ff(x, m).is_integer is None assert ff(n, k).is_integer is None assert ff(n, m).is_integer is True assert ff(n, k + pi).is_integer is False assert ff(n, m + pi).is_integer is False assert ff(pi, m).is_integer is False assert isinstance(ff(x, x), ff) assert ff(n, n) == factorial(n) def check(x, k, o, n): a, b = Dummy(), Dummy() r = lambda x, k: o(a, b).rewrite(n).subs({a:x,b:k}) for i in range(-5,5): for j in range(-5,5): assert o(i, j) == r(i, j), (o, n) check(x, k, ff, rf) check(x, k, ff, gamma) check(n, k, ff, factorial) check(x, k, ff, binomial) check(x, y, ff, factorial) check(x, y, ff, binomial) assert ff(x, k).rewrite(rf) == rf(x - k + 1, k) assert ff(x, k).rewrite(gamma) == Piecewise( (gamma(x + 1)/gamma(-k + x + 1), x >= 0), ((-1)**k*gamma(k - x)/gamma(-x), True)) assert ff(5, k).rewrite(gamma) == 120/gamma(6 - k) assert ff(n, k).rewrite(factorial) == Piecewise( (factorial(n)/factorial(-k + n), n >= 0), ((-1)**k*factorial(k - n - 1)/factorial(-n - 1), True)) assert ff(5, k).rewrite(factorial) == 120/factorial(5 - k) assert ff(x, k).rewrite(binomial) == factorial(k) * binomial(x, k) assert ff(x, y).rewrite(factorial) == ff(x, y) assert ff(x, y).rewrite(binomial) == ff(x, y) import random from mpmath import ff as mpmath_ff for i in range(100): x = -500 + 500 * random.random() k = -500 + 500 * random.random() a = mpmath_ff(x, k) b = ff(x, k) assert (abs(a - b) < abs(a) * 10**(-15)) def test_rf_ff_eval_hiprec(): maple = Float('6.9109401292234329956525265438452') us = ff(18, Rational(2, 3)).evalf(32) assert abs(us - maple)/us < 1e-31 maple = Float('6.8261540131125511557924466355367') us = rf(18, Rational(2, 3)).evalf(32) assert abs(us - maple)/us < 1e-31 maple = Float('34.007346127440197150854651814225') us = rf(Float('4.4', 32), Float('2.2', 32)); assert abs(us - maple)/us < 1e-31 def test_rf_lambdify_mpmath(): from sympy import lambdify x, y = symbols('x,y') f = lambdify((x,y), rf(x, y), 'mpmath') maple = Float('34.007346127440197') us = f(4.4, 2.2) assert abs(us - maple)/us < 1e-15 def test_factorial(): x = Symbol('x') n = Symbol('n', integer=True) k = Symbol('k', integer=True, nonnegative=True) r = Symbol('r', integer=False) s = Symbol('s', integer=False, negative=True) t = Symbol('t', nonnegative=True) u = Symbol('u', noninteger=True) assert factorial(-2) is zoo assert factorial(0) == 1 assert factorial(7) == 5040 assert factorial(19) == 121645100408832000 assert factorial(31) == 8222838654177922817725562880000000 assert factorial(n).func == factorial assert factorial(2*n).func == factorial assert factorial(x).is_integer is None assert factorial(n).is_integer is None assert factorial(k).is_integer assert factorial(r).is_integer is None assert factorial(n).is_positive is None assert factorial(k).is_positive assert factorial(x).is_real is None assert factorial(n).is_real is None assert factorial(k).is_real is True assert factorial(r).is_real is None assert factorial(s).is_real is True assert factorial(t).is_real is True assert factorial(u).is_real is True assert factorial(x).is_composite is None assert factorial(n).is_composite is None assert factorial(k).is_composite is None assert factorial(k + 3).is_composite is True assert factorial(r).is_composite is None assert factorial(s).is_composite is None assert factorial(t).is_composite is None assert factorial(u).is_composite is None assert factorial(oo) is oo def test_factorial_Mod(): pr = Symbol('pr', prime=True) p, q = 10**9 + 9, 10**9 + 33 # prime modulo r, s = 10**7 + 5, 33333333 # composite modulo assert Mod(factorial(pr - 1), pr) == pr - 1 assert Mod(factorial(pr - 1), -pr) == -1 assert Mod(factorial(r - 1, evaluate=False), r) == 0 assert Mod(factorial(s - 1, evaluate=False), s) == 0 assert Mod(factorial(p - 1, evaluate=False), p) == p - 1 assert Mod(factorial(q - 1, evaluate=False), q) == q - 1 assert Mod(factorial(p - 50, evaluate=False), p) == 854928834 assert Mod(factorial(q - 1800, evaluate=False), q) == 905504050 assert Mod(factorial(153, evaluate=False), r) == Mod(factorial(153), r) assert Mod(factorial(255, evaluate=False), s) == Mod(factorial(255), s) assert Mod(factorial(4, evaluate=False), 3) == S.Zero assert Mod(factorial(5, evaluate=False), 6) == S.Zero def test_factorial_diff(): n = Symbol('n', integer=True) assert factorial(n).diff(n) == \ gamma(1 + n)*polygamma(0, 1 + n) assert factorial(n**2).diff(n) == \ 2*n*gamma(1 + n**2)*polygamma(0, 1 + n**2) raises(ArgumentIndexError, lambda: factorial(n**2).fdiff(2)) def test_factorial_series(): n = Symbol('n', integer=True) assert factorial(n).series(n, 0, 3) == \ 1 - n*EulerGamma + n**2*(EulerGamma**2/2 + pi**2/12) + O(n**3) def test_factorial_rewrite(): n = Symbol('n', integer=True) k = Symbol('k', integer=True, nonnegative=True) assert factorial(n).rewrite(gamma) == gamma(n + 1) _i = Dummy('i') assert factorial(k).rewrite(Product).dummy_eq(Product(_i, (_i, 1, k))) assert factorial(n).rewrite(Product) == factorial(n) def test_factorial2(): n = Symbol('n', integer=True) assert factorial2(-1) == 1 assert factorial2(0) == 1 assert factorial2(7) == 105 assert factorial2(8) == 384 # The following is exhaustive tt = Symbol('tt', integer=True, nonnegative=True) tte = Symbol('tte', even=True, nonnegative=True) tpe = Symbol('tpe', even=True, positive=True) tto = Symbol('tto', odd=True, nonnegative=True) tf = Symbol('tf', integer=True, nonnegative=False) tfe = Symbol('tfe', even=True, nonnegative=False) tfo = Symbol('tfo', odd=True, nonnegative=False) ft = Symbol('ft', integer=False, nonnegative=True) ff = Symbol('ff', integer=False, nonnegative=False) fn = Symbol('fn', integer=False) nt = Symbol('nt', nonnegative=True) nf = Symbol('nf', nonnegative=False) nn = Symbol('nn') z = Symbol('z', zero=True) #Solves and Fixes Issue #10388 - This is the updated test for the same solved issue raises(ValueError, lambda: factorial2(oo)) raises(ValueError, lambda: factorial2(Rational(5, 2))) raises(ValueError, lambda: factorial2(-4)) assert factorial2(n).is_integer is None assert factorial2(tt - 1).is_integer assert factorial2(tte - 1).is_integer assert factorial2(tpe - 3).is_integer assert factorial2(tto - 4).is_integer assert factorial2(tto - 2).is_integer assert factorial2(tf).is_integer is None assert factorial2(tfe).is_integer is None assert factorial2(tfo).is_integer is None assert factorial2(ft).is_integer is None assert factorial2(ff).is_integer is None assert factorial2(fn).is_integer is None assert factorial2(nt).is_integer is None assert factorial2(nf).is_integer is None assert factorial2(nn).is_integer is None assert factorial2(n).is_positive is None assert factorial2(tt - 1).is_positive is True assert factorial2(tte - 1).is_positive is True assert factorial2(tpe - 3).is_positive is True assert factorial2(tpe - 1).is_positive is True assert factorial2(tto - 2).is_positive is True assert factorial2(tto - 1).is_positive is True assert factorial2(tf).is_positive is None assert factorial2(tfe).is_positive is None assert factorial2(tfo).is_positive is None assert factorial2(ft).is_positive is None assert factorial2(ff).is_positive is None assert factorial2(fn).is_positive is None assert factorial2(nt).is_positive is None assert factorial2(nf).is_positive is None assert factorial2(nn).is_positive is None assert factorial2(tt).is_even is None assert factorial2(tt).is_odd is None assert factorial2(tte).is_even is None assert factorial2(tte).is_odd is None assert factorial2(tte + 2).is_even is True assert factorial2(tpe).is_even is True assert factorial2(tpe).is_odd is False assert factorial2(tto).is_odd is True assert factorial2(tf).is_even is None assert factorial2(tf).is_odd is None assert factorial2(tfe).is_even is None assert factorial2(tfe).is_odd is None assert factorial2(tfo).is_even is False assert factorial2(tfo).is_odd is None assert factorial2(z).is_even is False assert factorial2(z).is_odd is True def test_factorial2_rewrite(): n = Symbol('n', integer=True) assert factorial2(n).rewrite(gamma) == \ 2**(n/2)*Piecewise((1, Eq(Mod(n, 2), 0)), (sqrt(2)/sqrt(pi), Eq(Mod(n, 2), 1)))*gamma(n/2 + 1) assert factorial2(2*n).rewrite(gamma) == 2**n*gamma(n + 1) assert factorial2(2*n + 1).rewrite(gamma) == \ sqrt(2)*2**(n + S.Half)*gamma(n + Rational(3, 2))/sqrt(pi) def test_binomial(): x = Symbol('x') n = Symbol('n', integer=True) nz = Symbol('nz', integer=True, nonzero=True) k = Symbol('k', integer=True) kp = Symbol('kp', integer=True, positive=True) kn = Symbol('kn', integer=True, negative=True) u = Symbol('u', negative=True) v = Symbol('v', nonnegative=True) p = Symbol('p', positive=True) z = Symbol('z', zero=True) nt = Symbol('nt', integer=False) kt = Symbol('kt', integer=False) a = Symbol('a', integer=True, nonnegative=True) b = Symbol('b', integer=True, nonnegative=True) assert binomial(0, 0) == 1 assert binomial(1, 1) == 1 assert binomial(10, 10) == 1 assert binomial(n, z) == 1 assert binomial(1, 2) == 0 assert binomial(-1, 2) == 1 assert binomial(1, -1) == 0 assert binomial(-1, 1) == -1 assert binomial(-1, -1) == 0 assert binomial(S.Half, S.Half) == 1 assert binomial(-10, 1) == -10 assert binomial(-10, 7) == -11440 assert binomial(n, -1) == 0 # holds for all integers (negative, zero, positive) assert binomial(kp, -1) == 0 assert binomial(nz, 0) == 1 assert expand_func(binomial(n, 1)) == n assert expand_func(binomial(n, 2)) == n*(n - 1)/2 assert expand_func(binomial(n, n - 2)) == n*(n - 1)/2 assert expand_func(binomial(n, n - 1)) == n assert binomial(n, 3).func == binomial assert binomial(n, 3).expand(func=True) == n**3/6 - n**2/2 + n/3 assert expand_func(binomial(n, 3)) == n*(n - 2)*(n - 1)/6 assert binomial(n, n).func == binomial # e.g. (-1, -1) == 0, (2, 2) == 1 assert binomial(n, n + 1).func == binomial # e.g. (-1, 0) == 1 assert binomial(kp, kp + 1) == 0 assert binomial(kn, kn) == 0 # issue #14529 assert binomial(n, u).func == binomial assert binomial(kp, u).func == binomial assert binomial(n, p).func == binomial assert binomial(n, k).func == binomial assert binomial(n, n + p).func == binomial assert binomial(kp, kp + p).func == binomial assert expand_func(binomial(n, n - 3)) == n*(n - 2)*(n - 1)/6 assert binomial(n, k).is_integer assert binomial(nt, k).is_integer is None assert binomial(x, nt).is_integer is False assert binomial(gamma(25), 6) == 79232165267303928292058750056084441948572511312165380965440075720159859792344339983120618959044048198214221915637090855535036339620413440000 assert binomial(1324, 47) == 906266255662694632984994480774946083064699457235920708992926525848438478406790323869952 assert binomial(1735, 43) == 190910140420204130794758005450919715396159959034348676124678207874195064798202216379800 assert binomial(2512, 53) == 213894469313832631145798303740098720367984955243020898718979538096223399813295457822575338958939834177325304000 assert binomial(3383, 52) == 27922807788818096863529701501764372757272890613101645521813434902890007725667814813832027795881839396839287659777235 assert binomial(4321, 51) == 124595639629264868916081001263541480185227731958274383287107643816863897851139048158022599533438936036467601690983780576 assert binomial(a, b).is_nonnegative is True assert binomial(-1, 2, evaluate=False).is_nonnegative is True assert binomial(10, 5, evaluate=False).is_nonnegative is True assert binomial(10, -3, evaluate=False).is_nonnegative is True assert binomial(-10, -3, evaluate=False).is_nonnegative is True assert binomial(-10, 2, evaluate=False).is_nonnegative is True assert binomial(-10, 1, evaluate=False).is_nonnegative is False assert binomial(-10, 7, evaluate=False).is_nonnegative is False # issue #14625 for _ in (pi, -pi, nt, v, a): assert binomial(_, _) == 1 assert binomial(_, _ - 1) == _ assert isinstance(binomial(u, u), binomial) assert isinstance(binomial(u, u - 1), binomial) assert isinstance(binomial(x, x), binomial) assert isinstance(binomial(x, x - 1), binomial) #issue #18802 assert expand_func(binomial(x + 1, x)) == x + 1 assert expand_func(binomial(x, x - 1)) == x assert expand_func(binomial(x + 1, x - 1)) == x*(x + 1)/2 assert expand_func(binomial(x**2 + 1, x**2)) == x**2 + 1 # issue #13980 and #13981 assert binomial(-7, -5) == 0 assert binomial(-23, -12) == 0 assert binomial(Rational(13, 2), -10) == 0 assert binomial(-49, -51) == 0 assert binomial(19, Rational(-7, 2)) == S(-68719476736)/(911337863661225*pi) assert binomial(0, Rational(3, 2)) == S(-2)/(3*pi) assert binomial(-3, Rational(-7, 2)) is zoo assert binomial(kn, kt) is zoo assert binomial(nt, kt).func == binomial assert binomial(nt, Rational(15, 6)) == 8*gamma(nt + 1)/(15*sqrt(pi)*gamma(nt - Rational(3, 2))) assert binomial(Rational(20, 3), Rational(-10, 8)) == gamma(Rational(23, 3))/(gamma(Rational(-1, 4))*gamma(Rational(107, 12))) assert binomial(Rational(19, 2), Rational(-7, 2)) == Rational(-1615, 8388608) assert binomial(Rational(-13, 5), Rational(-7, 8)) == gamma(Rational(-8, 5))/(gamma(Rational(-29, 40))*gamma(Rational(1, 8))) assert binomial(Rational(-19, 8), Rational(-13, 5)) == gamma(Rational(-11, 8))/(gamma(Rational(-8, 5))*gamma(Rational(49, 40))) # binomial for complexes from sympy import I assert binomial(I, Rational(-89, 8)) == gamma(1 + I)/(gamma(Rational(-81, 8))*gamma(Rational(97, 8) + I)) assert binomial(I, 2*I) == gamma(1 + I)/(gamma(1 - I)*gamma(1 + 2*I)) assert binomial(-7, I) is zoo assert binomial(Rational(-7, 6), I) == gamma(Rational(-1, 6))/(gamma(Rational(-1, 6) - I)*gamma(1 + I)) assert binomial((1+2*I), (1+3*I)) == gamma(2 + 2*I)/(gamma(1 - I)*gamma(2 + 3*I)) assert binomial(I, 5) == Rational(1, 3) - I/S(12) assert binomial((2*I + 3), 7) == -13*I/S(63) assert isinstance(binomial(I, n), binomial) assert expand_func(binomial(3, 2, evaluate=False)) == 3 assert expand_func(binomial(n, 0, evaluate=False)) == 1 assert expand_func(binomial(n, -2, evaluate=False)) == 0 assert expand_func(binomial(n, k)) == binomial(n, k) def test_binomial_Mod(): p, q = 10**5 + 3, 10**9 + 33 # prime modulo r = 10**7 + 5 # composite modulo # A few tests to get coverage # Lucas Theorem assert Mod(binomial(156675, 4433, evaluate=False), p) == Mod(binomial(156675, 4433), p) # factorial Mod assert Mod(binomial(1234, 432, evaluate=False), q) == Mod(binomial(1234, 432), q) # binomial factorize assert Mod(binomial(253, 113, evaluate=False), r) == Mod(binomial(253, 113), r) @slow def test_binomial_Mod_slow(): p, q = 10**5 + 3, 10**9 + 33 # prime modulo r, s = 10**7 + 5, 33333333 # composite modulo n, k, m = symbols('n k m') assert (binomial(n, k) % q).subs({n: s, k: p}) == Mod(binomial(s, p), q) assert (binomial(n, k) % m).subs({n: 8, k: 5, m: 13}) == 4 assert (binomial(9, k) % 7).subs(k, 2) == 1 # Lucas Theorem assert Mod(binomial(123456, 43253, evaluate=False), p) == Mod(binomial(123456, 43253), p) assert Mod(binomial(-178911, 237, evaluate=False), p) == Mod(-binomial(178911 + 237 - 1, 237), p) assert Mod(binomial(-178911, 238, evaluate=False), p) == Mod(binomial(178911 + 238 - 1, 238), p) # factorial Mod assert Mod(binomial(9734, 451, evaluate=False), q) == Mod(binomial(9734, 451), q) assert Mod(binomial(-10733, 4459, evaluate=False), q) == Mod(binomial(-10733, 4459), q) assert Mod(binomial(-15733, 4458, evaluate=False), q) == Mod(binomial(-15733, 4458), q) assert Mod(binomial(23, -38, evaluate=False), q) is S.Zero assert Mod(binomial(23, 38, evaluate=False), q) is S.Zero # binomial factorize assert Mod(binomial(753, 119, evaluate=False), r) == Mod(binomial(753, 119), r) assert Mod(binomial(3781, 948, evaluate=False), s) == Mod(binomial(3781, 948), s) assert Mod(binomial(25773, 1793, evaluate=False), s) == Mod(binomial(25773, 1793), s) assert Mod(binomial(-753, 118, evaluate=False), r) == Mod(binomial(-753, 118), r) assert Mod(binomial(-25773, 1793, evaluate=False), s) == Mod(binomial(-25773, 1793), s) def test_binomial_diff(): n = Symbol('n', integer=True) k = Symbol('k', integer=True) assert binomial(n, k).diff(n) == \ (-polygamma(0, 1 + n - k) + polygamma(0, 1 + n))*binomial(n, k) assert binomial(n**2, k**3).diff(n) == \ 2*n*(-polygamma( 0, 1 + n**2 - k**3) + polygamma(0, 1 + n**2))*binomial(n**2, k**3) assert binomial(n, k).diff(k) == \ (-polygamma(0, 1 + k) + polygamma(0, 1 + n - k))*binomial(n, k) assert binomial(n**2, k**3).diff(k) == \ 3*k**2*(-polygamma( 0, 1 + k**3) + polygamma(0, 1 + n**2 - k**3))*binomial(n**2, k**3) raises(ArgumentIndexError, lambda: binomial(n, k).fdiff(3)) def test_binomial_rewrite(): n = Symbol('n', integer=True) k = Symbol('k', integer=True) x = Symbol('x') assert binomial(n, k).rewrite( factorial) == factorial(n)/(factorial(k)*factorial(n - k)) assert binomial( n, k).rewrite(gamma) == gamma(n + 1)/(gamma(k + 1)*gamma(n - k + 1)) assert binomial(n, k).rewrite(ff) == ff(n, k) / factorial(k) assert binomial(n, x).rewrite(ff) == binomial(n, x) @XFAIL def test_factorial_simplify_fail(): # simplify(factorial(x + 1).diff(x) - ((x + 1)*factorial(x)).diff(x))) == 0 from sympy.abc import x assert simplify(x*polygamma(0, x + 1) - x*polygamma(0, x + 2) + polygamma(0, x + 1) - polygamma(0, x + 2) + 1) == 0 def test_subfactorial(): assert all(subfactorial(i) == ans for i, ans in enumerate( [1, 0, 1, 2, 9, 44, 265, 1854, 14833, 133496])) assert subfactorial(oo) is oo assert subfactorial(nan) is nan assert subfactorial(23) == 9510425471055777937262 assert unchanged(subfactorial, 2.2) x = Symbol('x') assert subfactorial(x).rewrite(uppergamma) == uppergamma(x + 1, -1)/S.Exp1 tt = Symbol('tt', integer=True, nonnegative=True) tf = Symbol('tf', integer=True, nonnegative=False) tn = Symbol('tf', integer=True) ft = Symbol('ft', integer=False, nonnegative=True) ff = Symbol('ff', integer=False, nonnegative=False) fn = Symbol('ff', integer=False) nt = Symbol('nt', nonnegative=True) nf = Symbol('nf', nonnegative=False) nn = Symbol('nf') te = Symbol('te', even=True, nonnegative=True) to = Symbol('to', odd=True, nonnegative=True) assert subfactorial(tt).is_integer assert subfactorial(tf).is_integer is None assert subfactorial(tn).is_integer is None assert subfactorial(ft).is_integer is None assert subfactorial(ff).is_integer is None assert subfactorial(fn).is_integer is None assert subfactorial(nt).is_integer is None assert subfactorial(nf).is_integer is None assert subfactorial(nn).is_integer is None assert subfactorial(tt).is_nonnegative assert subfactorial(tf).is_nonnegative is None assert subfactorial(tn).is_nonnegative is None assert subfactorial(ft).is_nonnegative is None assert subfactorial(ff).is_nonnegative is None assert subfactorial(fn).is_nonnegative is None assert subfactorial(nt).is_nonnegative is None assert subfactorial(nf).is_nonnegative is None assert subfactorial(nn).is_nonnegative is None assert subfactorial(tt).is_even is None assert subfactorial(tt).is_odd is None assert subfactorial(te).is_odd is True assert subfactorial(to).is_even is True sympy-sympy-1.9/sympy/functions/combinatorial/tests/test_comb_numbers.py000066400000000000000000000633221412543434000271730ustar00rootroot00000000000000import string from sympy import ( Symbol, symbols, Dummy, S, Sum, Rational, oo, pi, I, floor, limit, expand_func, diff, EulerGamma, cancel, re, im, Product, carmichael, TribonacciConstant) from sympy.functions import ( bernoulli, harmonic, bell, fibonacci, tribonacci, lucas, euler, catalan, genocchi, partition, motzkin, binomial, gamma, sqrt, cbrt, hyper, log, digamma, trigamma, polygamma, factorial, sin, cos, cot, zeta) from sympy.functions.combinatorial.numbers import _nT from sympy.core.expr import unchanged from sympy.core.numbers import GoldenRatio, Integer from sympy.testing.pytest import XFAIL, raises, nocache_fail x = Symbol('x') def test_carmichael(): assert carmichael.find_carmichael_numbers_in_range(0, 561) == [] assert carmichael.find_carmichael_numbers_in_range(561, 562) == [561] assert carmichael.find_carmichael_numbers_in_range(561, 1105) == carmichael.find_carmichael_numbers_in_range(561, 562) assert carmichael.find_first_n_carmichaels(5) == [561, 1105, 1729, 2465, 2821] assert carmichael.is_prime(2821) == False assert carmichael.is_prime(2465) == False assert carmichael.is_prime(1729) == False assert carmichael.is_prime(1105) == False assert carmichael.is_prime(561) == False raises(ValueError, lambda: carmichael.is_carmichael(-2)) raises(ValueError, lambda: carmichael.find_carmichael_numbers_in_range(-2, 2)) raises(ValueError, lambda: carmichael.find_carmichael_numbers_in_range(22, 2)) def test_bernoulli(): assert bernoulli(0) == 1 assert bernoulli(1) == Rational(-1, 2) assert bernoulli(2) == Rational(1, 6) assert bernoulli(3) == 0 assert bernoulli(4) == Rational(-1, 30) assert bernoulli(5) == 0 assert bernoulli(6) == Rational(1, 42) assert bernoulli(7) == 0 assert bernoulli(8) == Rational(-1, 30) assert bernoulli(10) == Rational(5, 66) assert bernoulli(1000001) == 0 assert bernoulli(0, x) == 1 assert bernoulli(1, x) == x - S.Half assert bernoulli(2, x) == x**2 - x + Rational(1, 6) assert bernoulli(3, x) == x**3 - (3*x**2)/2 + x/2 # Should be fast; computed with mpmath b = bernoulli(1000) assert b.p % 10**10 == 7950421099 assert b.q == 342999030 b = bernoulli(10**6, evaluate=False).evalf() assert str(b) == '-2.23799235765713e+4767529' # Issue #8527 l = Symbol('l', integer=True) m = Symbol('m', integer=True, nonnegative=True) n = Symbol('n', integer=True, positive=True) assert isinstance(bernoulli(2 * l + 1), bernoulli) assert isinstance(bernoulli(2 * m + 1), bernoulli) assert bernoulli(2 * n + 1) == 0 raises(ValueError, lambda: bernoulli(-2)) def test_fibonacci(): assert [fibonacci(n) for n in range(-3, 5)] == [2, -1, 1, 0, 1, 1, 2, 3] assert fibonacci(100) == 354224848179261915075 assert [lucas(n) for n in range(-3, 5)] == [-4, 3, -1, 2, 1, 3, 4, 7] assert lucas(100) == 792070839848372253127 assert fibonacci(1, x) == 1 assert fibonacci(2, x) == x assert fibonacci(3, x) == x**2 + 1 assert fibonacci(4, x) == x**3 + 2*x # issue #8800 n = Dummy('n') assert fibonacci(n).limit(n, S.Infinity) is S.Infinity assert lucas(n).limit(n, S.Infinity) is S.Infinity assert fibonacci(n).rewrite(sqrt) == \ 2**(-n)*sqrt(5)*((1 + sqrt(5))**n - (-sqrt(5) + 1)**n) / 5 assert fibonacci(n).rewrite(sqrt).subs(n, 10).expand() == fibonacci(10) assert fibonacci(n).rewrite(GoldenRatio).subs(n,10).evalf() == \ fibonacci(10) assert lucas(n).rewrite(sqrt) == \ (fibonacci(n-1).rewrite(sqrt) + fibonacci(n+1).rewrite(sqrt)).simplify() assert lucas(n).rewrite(sqrt).subs(n, 10).expand() == lucas(10) raises(ValueError, lambda: fibonacci(-3, x)) def test_tribonacci(): assert [tribonacci(n) for n in range(8)] == [0, 1, 1, 2, 4, 7, 13, 24] assert tribonacci(100) == 98079530178586034536500564 assert tribonacci(0, x) == 0 assert tribonacci(1, x) == 1 assert tribonacci(2, x) == x**2 assert tribonacci(3, x) == x**4 + x assert tribonacci(4, x) == x**6 + 2*x**3 + 1 assert tribonacci(5, x) == x**8 + 3*x**5 + 3*x**2 n = Dummy('n') assert tribonacci(n).limit(n, S.Infinity) is S.Infinity w = (-1 + S.ImaginaryUnit * sqrt(3)) / 2 a = (1 + cbrt(19 + 3*sqrt(33)) + cbrt(19 - 3*sqrt(33))) / 3 b = (1 + w*cbrt(19 + 3*sqrt(33)) + w**2*cbrt(19 - 3*sqrt(33))) / 3 c = (1 + w**2*cbrt(19 + 3*sqrt(33)) + w*cbrt(19 - 3*sqrt(33))) / 3 assert tribonacci(n).rewrite(sqrt) == \ (a**(n + 1)/((a - b)*(a - c)) + b**(n + 1)/((b - a)*(b - c)) + c**(n + 1)/((c - a)*(c - b))) assert tribonacci(n).rewrite(sqrt).subs(n, 4).simplify() == tribonacci(4) assert tribonacci(n).rewrite(GoldenRatio).subs(n,10).evalf() == \ tribonacci(10) assert tribonacci(n).rewrite(TribonacciConstant) == floor( 3*TribonacciConstant**n*(102*sqrt(33) + 586)**Rational(1, 3)/ (-2*(102*sqrt(33) + 586)**Rational(1, 3) + 4 + (102*sqrt(33) + 586)**Rational(2, 3)) + S.Half) raises(ValueError, lambda: tribonacci(-1, x)) @nocache_fail def test_bell(): assert [bell(n) for n in range(8)] == [1, 1, 2, 5, 15, 52, 203, 877] assert bell(0, x) == 1 assert bell(1, x) == x assert bell(2, x) == x**2 + x assert bell(5, x) == x**5 + 10*x**4 + 25*x**3 + 15*x**2 + x assert bell(oo) is S.Infinity raises(ValueError, lambda: bell(oo, x)) raises(ValueError, lambda: bell(-1)) raises(ValueError, lambda: bell(S.Half)) X = symbols('x:6') # X = (x0, x1, .. x5) # at the same time: X[1] = x1, X[2] = x2 for standard readablity. # but we must supply zero-based indexed object X[1:] = (x1, .. x5) assert bell(6, 2, X[1:]) == 6*X[5]*X[1] + 15*X[4]*X[2] + 10*X[3]**2 assert bell( 6, 3, X[1:]) == 15*X[4]*X[1]**2 + 60*X[3]*X[2]*X[1] + 15*X[2]**3 X = (1, 10, 100, 1000, 10000) assert bell(6, 2, X) == (6 + 15 + 10)*10000 X = (1, 2, 3, 3, 5) assert bell(6, 2, X) == 6*5 + 15*3*2 + 10*3**2 X = (1, 2, 3, 5) assert bell(6, 3, X) == 15*5 + 60*3*2 + 15*2**3 # Dobinski's formula n = Symbol('n', integer=True, nonnegative=True) # For large numbers, this is too slow # For nonintegers, there are significant precision errors for i in [0, 2, 3, 7, 13, 42, 55]: # Running without the cache this is either very slow or goes into an # infinite loop. assert bell(i).evalf() == bell(n).rewrite(Sum).evalf(subs={n: i}) m = Symbol("m") assert bell(m).rewrite(Sum) == bell(m) assert bell(n, m).rewrite(Sum) == bell(n, m) # issue 9184 n = Dummy('n') assert bell(n).limit(n, S.Infinity) is S.Infinity def test_harmonic(): n = Symbol("n") m = Symbol("m") assert harmonic(n, 0) == n assert harmonic(n).evalf() == harmonic(n) assert harmonic(n, 1) == harmonic(n) assert harmonic(1, n).evalf() == harmonic(1, n) assert harmonic(0, 1) == 0 assert harmonic(1, 1) == 1 assert harmonic(2, 1) == Rational(3, 2) assert harmonic(3, 1) == Rational(11, 6) assert harmonic(4, 1) == Rational(25, 12) assert harmonic(0, 2) == 0 assert harmonic(1, 2) == 1 assert harmonic(2, 2) == Rational(5, 4) assert harmonic(3, 2) == Rational(49, 36) assert harmonic(4, 2) == Rational(205, 144) assert harmonic(0, 3) == 0 assert harmonic(1, 3) == 1 assert harmonic(2, 3) == Rational(9, 8) assert harmonic(3, 3) == Rational(251, 216) assert harmonic(4, 3) == Rational(2035, 1728) assert harmonic(oo, -1) is S.NaN assert harmonic(oo, 0) is oo assert harmonic(oo, S.Half) is oo assert harmonic(oo, 1) is oo assert harmonic(oo, 2) == (pi**2)/6 assert harmonic(oo, 3) == zeta(3) assert harmonic(0, m) == 0 def test_harmonic_rational(): ne = S(6) no = S(5) pe = S(8) po = S(9) qe = S(10) qo = S(13) Heee = harmonic(ne + pe/qe) Aeee = (-log(10) + 2*(Rational(-1, 4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + Rational(5, 8))) + 2*(-sqrt(5)/4 - Rational(1, 4))*log(sqrt(sqrt(5)/8 + Rational(5, 8))) + pi*sqrt(2*sqrt(5)/5 + 1)/2 + Rational(13944145, 4720968)) Heeo = harmonic(ne + pe/qo) Aeeo = (-log(26) + 2*log(sin(pi*Rational(3, 13)))*cos(pi*Rational(4, 13)) + 2*log(sin(pi*Rational(2, 13)))*cos(pi*Rational(32, 13)) + 2*log(sin(pi*Rational(5, 13)))*cos(pi*Rational(80, 13)) - 2*log(sin(pi*Rational(6, 13)))*cos(pi*Rational(5, 13)) - 2*log(sin(pi*Rational(4, 13)))*cos(pi/13) + pi*cot(pi*Rational(5, 13))/2 - 2*log(sin(pi/13))*cos(pi*Rational(3, 13)) + Rational(2422020029, 702257080)) Heoe = harmonic(ne + po/qe) Aeoe = (-log(20) + 2*(Rational(1, 4) + sqrt(5)/4)*log(Rational(-1, 4) + sqrt(5)/4) + 2*(Rational(-1, 4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + Rational(5, 8))) + 2*(-sqrt(5)/4 - Rational(1, 4))*log(sqrt(sqrt(5)/8 + Rational(5, 8))) + 2*(-sqrt(5)/4 + Rational(1, 4))*log(Rational(1, 4) + sqrt(5)/4) + Rational(11818877030, 4286604231) + pi*sqrt(2*sqrt(5) + 5)/2) Heoo = harmonic(ne + po/qo) Aeoo = (-log(26) + 2*log(sin(pi*Rational(3, 13)))*cos(pi*Rational(54, 13)) + 2*log(sin(pi*Rational(4, 13)))*cos(pi*Rational(6, 13)) + 2*log(sin(pi*Rational(6, 13)))*cos(pi*Rational(108, 13)) - 2*log(sin(pi*Rational(5, 13)))*cos(pi/13) - 2*log(sin(pi/13))*cos(pi*Rational(5, 13)) + pi*cot(pi*Rational(4, 13))/2 - 2*log(sin(pi*Rational(2, 13)))*cos(pi*Rational(3, 13)) + Rational(11669332571, 3628714320)) Hoee = harmonic(no + pe/qe) Aoee = (-log(10) + 2*(Rational(-1, 4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + Rational(5, 8))) + 2*(-sqrt(5)/4 - Rational(1, 4))*log(sqrt(sqrt(5)/8 + Rational(5, 8))) + pi*sqrt(2*sqrt(5)/5 + 1)/2 + Rational(779405, 277704)) Hoeo = harmonic(no + pe/qo) Aoeo = (-log(26) + 2*log(sin(pi*Rational(3, 13)))*cos(pi*Rational(4, 13)) + 2*log(sin(pi*Rational(2, 13)))*cos(pi*Rational(32, 13)) + 2*log(sin(pi*Rational(5, 13)))*cos(pi*Rational(80, 13)) - 2*log(sin(pi*Rational(6, 13)))*cos(pi*Rational(5, 13)) - 2*log(sin(pi*Rational(4, 13)))*cos(pi/13) + pi*cot(pi*Rational(5, 13))/2 - 2*log(sin(pi/13))*cos(pi*Rational(3, 13)) + Rational(53857323, 16331560)) Hooe = harmonic(no + po/qe) Aooe = (-log(20) + 2*(Rational(1, 4) + sqrt(5)/4)*log(Rational(-1, 4) + sqrt(5)/4) + 2*(Rational(-1, 4) + sqrt(5)/4)*log(sqrt(-sqrt(5)/8 + Rational(5, 8))) + 2*(-sqrt(5)/4 - Rational(1, 4))*log(sqrt(sqrt(5)/8 + Rational(5, 8))) + 2*(-sqrt(5)/4 + Rational(1, 4))*log(Rational(1, 4) + sqrt(5)/4) + Rational(486853480, 186374097) + pi*sqrt(2*sqrt(5) + 5)/2) Hooo = harmonic(no + po/qo) Aooo = (-log(26) + 2*log(sin(pi*Rational(3, 13)))*cos(pi*Rational(54, 13)) + 2*log(sin(pi*Rational(4, 13)))*cos(pi*Rational(6, 13)) + 2*log(sin(pi*Rational(6, 13)))*cos(pi*Rational(108, 13)) - 2*log(sin(pi*Rational(5, 13)))*cos(pi/13) - 2*log(sin(pi/13))*cos(pi*Rational(5, 13)) + pi*cot(pi*Rational(4, 13))/2 - 2*log(sin(pi*Rational(2, 13)))*cos(3*pi/13) + Rational(383693479, 125128080)) H = [Heee, Heeo, Heoe, Heoo, Hoee, Hoeo, Hooe, Hooo] A = [Aeee, Aeeo, Aeoe, Aeoo, Aoee, Aoeo, Aooe, Aooo] for h, a in zip(H, A): e = expand_func(h).doit() assert cancel(e/a) == 1 assert abs(h.n() - a.n()) < 1e-12 def test_harmonic_evalf(): assert str(harmonic(1.5).evalf(n=10)) == '1.280372306' assert str(harmonic(1.5, 2).evalf(n=10)) == '1.154576311' # issue 7443 def test_harmonic_rewrite(): n = Symbol("n") m = Symbol("m") assert harmonic(n).rewrite(digamma) == polygamma(0, n + 1) + EulerGamma assert harmonic(n).rewrite(trigamma) == polygamma(0, n + 1) + EulerGamma assert harmonic(n).rewrite(polygamma) == polygamma(0, n + 1) + EulerGamma assert harmonic(n,3).rewrite(polygamma) == polygamma(2, n + 1)/2 - polygamma(2, 1)/2 assert harmonic(n,m).rewrite(polygamma) == (-1)**m*(polygamma(m - 1, 1) - polygamma(m - 1, n + 1))/factorial(m - 1) assert expand_func(harmonic(n+4)) == harmonic(n) + 1/(n + 4) + 1/(n + 3) + 1/(n + 2) + 1/(n + 1) assert expand_func(harmonic(n-4)) == harmonic(n) - 1/(n - 1) - 1/(n - 2) - 1/(n - 3) - 1/n assert harmonic(n, m).rewrite("tractable") == harmonic(n, m).rewrite(polygamma) _k = Dummy("k") assert harmonic(n).rewrite(Sum).dummy_eq(Sum(1/_k, (_k, 1, n))) assert harmonic(n, m).rewrite(Sum).dummy_eq(Sum(_k**(-m), (_k, 1, n))) @XFAIL def test_harmonic_limit_fail(): n = Symbol("n") m = Symbol("m") # For m > 1: assert limit(harmonic(n, m), n, oo) == zeta(m) def test_euler(): assert euler(0) == 1 assert euler(1) == 0 assert euler(2) == -1 assert euler(3) == 0 assert euler(4) == 5 assert euler(6) == -61 assert euler(8) == 1385 assert euler(20, evaluate=False) != 370371188237525 n = Symbol('n', integer=True) assert euler(n) != -1 assert euler(n).subs(n, 2) == -1 raises(ValueError, lambda: euler(-2)) raises(ValueError, lambda: euler(-3)) raises(ValueError, lambda: euler(2.3)) assert euler(20).evalf() == 370371188237525.0 assert euler(20, evaluate=False).evalf() == 370371188237525.0 assert euler(n).rewrite(Sum) == euler(n) n = Symbol('n', integer=True, nonnegative=True) assert euler(2*n + 1).rewrite(Sum) == 0 _j = Dummy('j') _k = Dummy('k') assert euler(2*n).rewrite(Sum).dummy_eq( I*Sum((-1)**_j*2**(-_k)*I**(-_k)*(-2*_j + _k)**(2*n + 1)* binomial(_k, _j)/_k, (_j, 0, _k), (_k, 1, 2*n + 1))) def test_euler_odd(): n = Symbol('n', odd=True, positive=True) assert euler(n) == 0 n = Symbol('n', odd=True) assert euler(n) != 0 def test_euler_polynomials(): assert euler(0, x) == 1 assert euler(1, x) == x - S.Half assert euler(2, x) == x**2 - x assert euler(3, x) == x**3 - (3*x**2)/2 + Rational(1, 4) m = Symbol('m') assert isinstance(euler(m, x), euler) from sympy import Float A = Float('-0.46237208575048694923364757452876131e8') # from Maple B = euler(19, S.Pi.evalf(32)) assert abs((A - B)/A) < 1e-31 # expect low relative error C = euler(19, S.Pi, evaluate=False).evalf(32) assert abs((A - C)/A) < 1e-31 def test_euler_polynomial_rewrite(): m = Symbol('m') A = euler(m, x).rewrite('Sum'); assert A.subs({m:3, x:5}).doit() == euler(3, 5) def test_catalan(): n = Symbol('n', integer=True) m = Symbol('m', integer=True, positive=True) k = Symbol('k', integer=True, nonnegative=True) p = Symbol('p', nonnegative=True) catalans = [1, 1, 2, 5, 14, 42, 132, 429, 1430, 4862, 16796, 58786] for i, c in enumerate(catalans): assert catalan(i) == c assert catalan(n).rewrite(factorial).subs(n, i) == c assert catalan(n).rewrite(Product).subs(n, i).doit() == c assert unchanged(catalan, x) assert catalan(2*x).rewrite(binomial) == binomial(4*x, 2*x)/(2*x + 1) assert catalan(S.Half).rewrite(gamma) == 8/(3*pi) assert catalan(S.Half).rewrite(factorial).rewrite(gamma) ==\ 8 / (3 * pi) assert catalan(3*x).rewrite(gamma) == 4**( 3*x)*gamma(3*x + S.Half)/(sqrt(pi)*gamma(3*x + 2)) assert catalan(x).rewrite(hyper) == hyper((-x + 1, -x), (2,), 1) assert catalan(n).rewrite(factorial) == factorial(2*n) / (factorial(n + 1) * factorial(n)) assert isinstance(catalan(n).rewrite(Product), catalan) assert isinstance(catalan(m).rewrite(Product), Product) assert diff(catalan(x), x) == (polygamma( 0, x + S.Half) - polygamma(0, x + 2) + log(4))*catalan(x) assert catalan(x).evalf() == catalan(x) c = catalan(S.Half).evalf() assert str(c) == '0.848826363156775' c = catalan(I).evalf(3) assert str((re(c), im(c))) == '(0.398, -0.0209)' # Assumptions assert catalan(p).is_positive is True assert catalan(k).is_integer is True assert catalan(m+3).is_composite is True def test_genocchi(): genocchis = [1, -1, 0, 1, 0, -3, 0, 17] for n, g in enumerate(genocchis): assert genocchi(n + 1) == g m = Symbol('m', integer=True) n = Symbol('n', integer=True, positive=True) assert unchanged(genocchi, m) assert genocchi(2*n + 1) == 0 assert genocchi(n).rewrite(bernoulli) == (1 - 2 ** n) * bernoulli(n) * 2 assert genocchi(2 * n).is_odd assert genocchi(2 * n).is_even is False assert genocchi(2 * n + 1).is_even assert genocchi(n).is_integer assert genocchi(4 * n).is_positive # these are the only 2 prime Genocchi numbers assert genocchi(6, evaluate=False).is_prime == S(-3).is_prime assert genocchi(8, evaluate=False).is_prime assert genocchi(4 * n + 2).is_negative assert genocchi(4 * n + 1).is_negative is False assert genocchi(4 * n - 2).is_negative raises(ValueError, lambda: genocchi(Rational(5, 4))) raises(ValueError, lambda: genocchi(-2)) @nocache_fail def test_partition(): partition_nums = [1, 1, 2, 3, 5, 7, 11, 15, 22] for n, p in enumerate(partition_nums): assert partition(n) == p x = Symbol('x') y = Symbol('y', real=True) m = Symbol('m', integer=True) n = Symbol('n', integer=True, negative=True) p = Symbol('p', integer=True, nonnegative=True) assert partition(m).is_integer assert not partition(m).is_negative assert partition(m).is_nonnegative assert partition(n).is_zero assert partition(p).is_positive assert partition(x).subs(x, 7) == 15 assert partition(y).subs(y, 8) == 22 raises(ValueError, lambda: partition(Rational(5, 4))) def test__nT(): assert [_nT(i, j) for i in range(5) for j in range(i + 2)] == [ 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 2, 1, 1, 0] check = [_nT(10, i) for i in range(11)] assert check == [0, 1, 5, 8, 9, 7, 5, 3, 2, 1, 1] assert all(type(i) is int for i in check) assert _nT(10, 5) == 7 assert _nT(100, 98) == 2 assert _nT(100, 100) == 1 assert _nT(10, 3) == 8 def test_nC_nP_nT(): from sympy.utilities.iterables import ( multiset_permutations, multiset_combinations, multiset_partitions, partitions, subsets, permutations) from sympy.functions.combinatorial.numbers import ( nP, nC, nT, stirling, _stirling1, _stirling2, _multiset_histogram, _AOP_product) from sympy.combinatorics.permutations import Permutation from sympy.core.numbers import oo from random import choice c = string.ascii_lowercase for i in range(100): s = ''.join(choice(c) for i in range(7)) u = len(s) == len(set(s)) try: tot = 0 for i in range(8): check = nP(s, i) tot += check assert len(list(multiset_permutations(s, i))) == check if u: assert nP(len(s), i) == check assert nP(s) == tot except AssertionError: print(s, i, 'failed perm test') raise ValueError() for i in range(100): s = ''.join(choice(c) for i in range(7)) u = len(s) == len(set(s)) try: tot = 0 for i in range(8): check = nC(s, i) tot += check assert len(list(multiset_combinations(s, i))) == check if u: assert nC(len(s), i) == check assert nC(s) == tot if u: assert nC(len(s)) == tot except AssertionError: print(s, i, 'failed combo test') raise ValueError() for i in range(1, 10): tot = 0 for j in range(1, i + 2): check = nT(i, j) assert check.is_Integer tot += check assert sum(1 for p in partitions(i, j, size=True) if p[0] == j) == check assert nT(i) == tot for i in range(1, 10): tot = 0 for j in range(1, i + 2): check = nT(range(i), j) tot += check assert len(list(multiset_partitions(list(range(i)), j))) == check assert nT(range(i)) == tot for i in range(100): s = ''.join(choice(c) for i in range(7)) u = len(s) == len(set(s)) try: tot = 0 for i in range(1, 8): check = nT(s, i) tot += check assert len(list(multiset_partitions(s, i))) == check if u: assert nT(range(len(s)), i) == check if u: assert nT(range(len(s))) == tot assert nT(s) == tot except AssertionError: print(s, i, 'failed partition test') raise ValueError() # tests for Stirling numbers of the first kind that are not tested in the # above assert [stirling(9, i, kind=1) for i in range(11)] == [ 0, 40320, 109584, 118124, 67284, 22449, 4536, 546, 36, 1, 0] perms = list(permutations(range(4))) assert [sum(1 for p in perms if Permutation(p).cycles == i) for i in range(5)] == [0, 6, 11, 6, 1] == [ stirling(4, i, kind=1) for i in range(5)] # http://oeis.org/A008275 assert [stirling(n, k, signed=1) for n in range(10) for k in range(1, n + 1)] == [ 1, -1, 1, 2, -3, 1, -6, 11, -6, 1, 24, -50, 35, -10, 1, -120, 274, -225, 85, -15, 1, 720, -1764, 1624, -735, 175, -21, 1, -5040, 13068, -13132, 6769, -1960, 322, -28, 1, 40320, -109584, 118124, -67284, 22449, -4536, 546, -36, 1] # https://en.wikipedia.org/wiki/Stirling_numbers_of_the_first_kind assert [stirling(n, k, kind=1) for n in range(10) for k in range(n+1)] == [ 1, 0, 1, 0, 1, 1, 0, 2, 3, 1, 0, 6, 11, 6, 1, 0, 24, 50, 35, 10, 1, 0, 120, 274, 225, 85, 15, 1, 0, 720, 1764, 1624, 735, 175, 21, 1, 0, 5040, 13068, 13132, 6769, 1960, 322, 28, 1, 0, 40320, 109584, 118124, 67284, 22449, 4536, 546, 36, 1] # https://en.wikipedia.org/wiki/Stirling_numbers_of_the_second_kind assert [stirling(n, k, kind=2) for n in range(10) for k in range(n+1)] == [ 1, 0, 1, 0, 1, 1, 0, 1, 3, 1, 0, 1, 7, 6, 1, 0, 1, 15, 25, 10, 1, 0, 1, 31, 90, 65, 15, 1, 0, 1, 63, 301, 350, 140, 21, 1, 0, 1, 127, 966, 1701, 1050, 266, 28, 1, 0, 1, 255, 3025, 7770, 6951, 2646, 462, 36, 1] assert stirling(3, 4, kind=1) == stirling(3, 4, kind=1) == 0 raises(ValueError, lambda: stirling(-2, 2)) # Assertion that the return type is SymPy Integer. assert isinstance(_stirling1(6, 3), Integer) assert isinstance(_stirling2(6, 3), Integer) def delta(p): if len(p) == 1: return oo return min(abs(i[0] - i[1]) for i in subsets(p, 2)) parts = multiset_partitions(range(5), 3) d = 2 assert (sum(1 for p in parts if all(delta(i) >= d for i in p)) == stirling(5, 3, d=d) == 7) # other coverage tests assert nC('abb', 2) == nC('aab', 2) == 2 assert nP(3, 3, replacement=True) == nP('aabc', 3, replacement=True) == 27 assert nP(3, 4) == 0 assert nP('aabc', 5) == 0 assert nC(4, 2, replacement=True) == nC('abcdd', 2, replacement=True) == \ len(list(multiset_combinations('aabbccdd', 2))) == 10 assert nC('abcdd') == sum(nC('abcdd', i) for i in range(6)) == 24 assert nC(list('abcdd'), 4) == 4 assert nT('aaaa') == nT(4) == len(list(partitions(4))) == 5 assert nT('aaab') == len(list(multiset_partitions('aaab'))) == 7 assert nC('aabb'*3, 3) == 4 # aaa, bbb, abb, baa assert dict(_AOP_product((4,1,1,1))) == { 0: 1, 1: 4, 2: 7, 3: 8, 4: 8, 5: 7, 6: 4, 7: 1} # the following was the first t that showed a problem in a previous form of # the function, so it's not as random as it may appear t = (3, 9, 4, 6, 6, 5, 5, 2, 10, 4) assert sum(_AOP_product(t)[i] for i in range(55)) == 58212000 raises(ValueError, lambda: _multiset_histogram({1:'a'})) def test_PR_14617(): from sympy.functions.combinatorial.numbers import nT for n in (0, []): for k in (-1, 0, 1): if k == 0: assert nT(n, k) == 1 else: assert nT(n, k) == 0 def test_issue_8496(): n = Symbol("n") k = Symbol("k") raises(TypeError, lambda: catalan(n, k)) def test_issue_8601(): n = Symbol('n', integer=True, negative=True) assert catalan(n - 1) is S.Zero assert catalan(Rational(-1, 2)) is S.ComplexInfinity assert catalan(-S.One) == Rational(-1, 2) c1 = catalan(-5.6).evalf() assert str(c1) == '6.93334070531408e-5' c2 = catalan(-35.4).evalf() assert str(c2) == '-4.14189164517449e-24' def test_motzkin(): assert motzkin.is_motzkin(4) == True assert motzkin.is_motzkin(9) == True assert motzkin.is_motzkin(10) == False assert motzkin.find_motzkin_numbers_in_range(10,200) == [21, 51, 127] assert motzkin.find_motzkin_numbers_in_range(10,400) == [21, 51, 127, 323] assert motzkin.find_motzkin_numbers_in_range(10,1600) == [21, 51, 127, 323, 835] assert motzkin.find_first_n_motzkins(5) == [1, 1, 2, 4, 9] assert motzkin.find_first_n_motzkins(7) == [1, 1, 2, 4, 9, 21, 51] assert motzkin.find_first_n_motzkins(10) == [1, 1, 2, 4, 9, 21, 51, 127, 323, 835] raises(ValueError, lambda: motzkin.eval(77.58)) raises(ValueError, lambda: motzkin.eval(-8)) raises(ValueError, lambda: motzkin.find_motzkin_numbers_in_range(-2,7)) raises(ValueError, lambda: motzkin.find_motzkin_numbers_in_range(13,7)) raises(ValueError, lambda: motzkin.find_first_n_motzkins(112.8)) sympy-sympy-1.9/sympy/functions/elementary/000077500000000000000000000000001412543434000212615ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/elementary/__init__.py000066400000000000000000000000621412543434000233700ustar00rootroot00000000000000# Stub __init__.py for sympy.functions.elementary sympy-sympy-1.9/sympy/functions/elementary/benchmarks/000077500000000000000000000000001412543434000233765ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/elementary/benchmarks/__init__.py000066400000000000000000000000001412543434000254750ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/elementary/benchmarks/bench_exp.py000066400000000000000000000001731412543434000257040ustar00rootroot00000000000000from sympy import exp, symbols x, y = symbols('x,y') e = exp(2*x) q = exp(3*x) def timeit_exp_subs(): e.subs(q, y) sympy-sympy-1.9/sympy/functions/elementary/complexes.py000066400000000000000000001221411412543434000236330ustar00rootroot00000000000000from sympy.core import S, Add, Mul, sympify, Symbol, Dummy, Basic from sympy.core.expr import Expr from sympy.core.exprtools import factor_terms from sympy.core.function import (Function, Derivative, ArgumentIndexError, AppliedUndef) from sympy.core.logic import fuzzy_not, fuzzy_or from sympy.core.numbers import pi, I, oo from sympy.core.relational import Eq from sympy.functions.elementary.exponential import exp, exp_polar, log from sympy.functions.elementary.integers import ceiling from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import atan, atan2 ############################################################################### ######################### REAL and IMAGINARY PARTS ############################ ############################################################################### class re(Function): """ Returns real part of expression. This function performs only elementary analysis and so it will fail to decompose properly more complicated expressions. If completely simplified result is needed then use Basic.as_real_imag() or perform complex expansion on instance of this function. Examples ======== >>> from sympy import re, im, I, E, symbols >>> x, y = symbols('x y', real=True) >>> re(2*E) 2*E >>> re(2*I + 17) 17 >>> re(2*I) 0 >>> re(im(x) + x*I + 2) 2 >>> re(5 + I + 2) 7 Parameters ========== arg : Expr Real or complex expression. Returns ======= expr : Expr Real part of expression. See Also ======== im """ is_extended_real = True unbranched = True # implicitly works on the projection to C _singularities = True # non-holomorphic @classmethod def eval(cls, arg): if arg is S.NaN: return S.NaN elif arg is S.ComplexInfinity: return S.NaN elif arg.is_extended_real: return arg elif arg.is_imaginary or (S.ImaginaryUnit*arg).is_extended_real: return S.Zero elif arg.is_Matrix: return arg.as_real_imag()[0] elif arg.is_Function and isinstance(arg, conjugate): return re(arg.args[0]) else: included, reverted, excluded = [], [], [] args = Add.make_args(arg) for term in args: coeff = term.as_coefficient(S.ImaginaryUnit) if coeff is not None: if not coeff.is_extended_real: reverted.append(coeff) elif not term.has(S.ImaginaryUnit) and term.is_extended_real: excluded.append(term) else: # Try to do some advanced expansion. If # impossible, don't try to do re(arg) again # (because this is what we are trying to do now). real_imag = term.as_real_imag(ignore=arg) if real_imag: excluded.append(real_imag[0]) else: included.append(term) if len(args) != len(included): a, b, c = (Add(*xs) for xs in [included, reverted, excluded]) return cls(a) - im(b) + c def as_real_imag(self, deep=True, **hints): """ Returns the real number with a zero imaginary part. """ return (self, S.Zero) def _eval_derivative(self, x): if x.is_extended_real or self.args[0].is_extended_real: return re(Derivative(self.args[0], x, evaluate=True)) if x.is_imaginary or self.args[0].is_imaginary: return -S.ImaginaryUnit \ * im(Derivative(self.args[0], x, evaluate=True)) def _eval_rewrite_as_im(self, arg, **kwargs): return self.args[0] - S.ImaginaryUnit*im(self.args[0]) def _eval_is_algebraic(self): return self.args[0].is_algebraic def _eval_is_zero(self): # is_imaginary implies nonzero return fuzzy_or([self.args[0].is_imaginary, self.args[0].is_zero]) def _eval_is_finite(self): if self.args[0].is_finite: return True def _eval_is_complex(self): if self.args[0].is_finite: return True class im(Function): """ Returns imaginary part of expression. This function performs only elementary analysis and so it will fail to decompose properly more complicated expressions. If completely simplified result is needed then use Basic.as_real_imag() or perform complex expansion on instance of this function. Examples ======== >>> from sympy import re, im, E, I >>> from sympy.abc import x, y >>> im(2*E) 0 >>> im(2*I + 17) 2 >>> im(x*I) re(x) >>> im(re(x) + y) im(y) >>> im(2 + 3*I) 3 Parameters ========== arg : Expr Real or complex expression. Returns ======= expr : Expr Imaginary part of expression. See Also ======== re """ is_extended_real = True unbranched = True # implicitly works on the projection to C _singularities = True # non-holomorphic @classmethod def eval(cls, arg): if arg is S.NaN: return S.NaN elif arg is S.ComplexInfinity: return S.NaN elif arg.is_extended_real: return S.Zero elif arg.is_imaginary or (S.ImaginaryUnit*arg).is_extended_real: return -S.ImaginaryUnit * arg elif arg.is_Matrix: return arg.as_real_imag()[1] elif arg.is_Function and isinstance(arg, conjugate): return -im(arg.args[0]) else: included, reverted, excluded = [], [], [] args = Add.make_args(arg) for term in args: coeff = term.as_coefficient(S.ImaginaryUnit) if coeff is not None: if not coeff.is_extended_real: reverted.append(coeff) else: excluded.append(coeff) elif term.has(S.ImaginaryUnit) or not term.is_extended_real: # Try to do some advanced expansion. If # impossible, don't try to do im(arg) again # (because this is what we are trying to do now). real_imag = term.as_real_imag(ignore=arg) if real_imag: excluded.append(real_imag[1]) else: included.append(term) if len(args) != len(included): a, b, c = (Add(*xs) for xs in [included, reverted, excluded]) return cls(a) + re(b) + c def as_real_imag(self, deep=True, **hints): """ Return the imaginary part with a zero real part. """ return (self, S.Zero) def _eval_derivative(self, x): if x.is_extended_real or self.args[0].is_extended_real: return im(Derivative(self.args[0], x, evaluate=True)) if x.is_imaginary or self.args[0].is_imaginary: return -S.ImaginaryUnit \ * re(Derivative(self.args[0], x, evaluate=True)) def _eval_rewrite_as_re(self, arg, **kwargs): return -S.ImaginaryUnit*(self.args[0] - re(self.args[0])) def _eval_is_algebraic(self): return self.args[0].is_algebraic def _eval_is_zero(self): return self.args[0].is_extended_real def _eval_is_finite(self): if self.args[0].is_finite: return True def _eval_is_complex(self): if self.args[0].is_finite: return True ############################################################################### ############### SIGN, ABSOLUTE VALUE, ARGUMENT and CONJUGATION ################ ############################################################################### class sign(Function): """ Returns the complex sign of an expression: Explanation =========== If the expression is real the sign will be: * 1 if expression is positive * 0 if expression is equal to zero * -1 if expression is negative If the expression is imaginary the sign will be: * I if im(expression) is positive * -I if im(expression) is negative Otherwise an unevaluated expression will be returned. When evaluated, the result (in general) will be ``cos(arg(expr)) + I*sin(arg(expr))``. Examples ======== >>> from sympy.functions import sign >>> from sympy.core.numbers import I >>> sign(-1) -1 >>> sign(0) 0 >>> sign(-3*I) -I >>> sign(1 + I) sign(1 + I) >>> _.evalf() 0.707106781186548 + 0.707106781186548*I Parameters ========== arg : Expr Real or imaginary expression. Returns ======= expr : Expr Complex sign of expression. See Also ======== Abs, conjugate """ is_complex = True _singularities = True def doit(self, **hints): s = super().doit() if s == self and self.args[0].is_zero is False: return self.args[0] / Abs(self.args[0]) return s @classmethod def eval(cls, arg): # handle what we can if arg.is_Mul: c, args = arg.as_coeff_mul() unk = [] s = sign(c) for a in args: if a.is_extended_negative: s = -s elif a.is_extended_positive: pass else: if a.is_imaginary: ai = im(a) if ai.is_comparable: # i.e. a = I*real s *= S.ImaginaryUnit if ai.is_extended_negative: # can't use sign(ai) here since ai might not be # a Number s = -s else: unk.append(a) else: unk.append(a) if c is S.One and len(unk) == len(args): return None return s * cls(arg._new_rawargs(*unk)) if arg is S.NaN: return S.NaN if arg.is_zero: # it may be an Expr that is zero return S.Zero if arg.is_extended_positive: return S.One if arg.is_extended_negative: return S.NegativeOne if arg.is_Function: if isinstance(arg, sign): return arg if arg.is_imaginary: if arg.is_Pow and arg.exp is S.Half: # we catch this because non-trivial sqrt args are not expanded # e.g. sqrt(1-sqrt(2)) --x--> to I*sqrt(sqrt(2) - 1) return S.ImaginaryUnit arg2 = -S.ImaginaryUnit * arg if arg2.is_extended_positive: return S.ImaginaryUnit if arg2.is_extended_negative: return -S.ImaginaryUnit def _eval_Abs(self): if fuzzy_not(self.args[0].is_zero): return S.One def _eval_conjugate(self): return sign(conjugate(self.args[0])) def _eval_derivative(self, x): if self.args[0].is_extended_real: from sympy.functions.special.delta_functions import DiracDelta return 2 * Derivative(self.args[0], x, evaluate=True) \ * DiracDelta(self.args[0]) elif self.args[0].is_imaginary: from sympy.functions.special.delta_functions import DiracDelta return 2 * Derivative(self.args[0], x, evaluate=True) \ * DiracDelta(-S.ImaginaryUnit * self.args[0]) def _eval_is_nonnegative(self): if self.args[0].is_nonnegative: return True def _eval_is_nonpositive(self): if self.args[0].is_nonpositive: return True def _eval_is_imaginary(self): return self.args[0].is_imaginary def _eval_is_integer(self): return self.args[0].is_extended_real def _eval_is_zero(self): return self.args[0].is_zero def _eval_power(self, other): if ( fuzzy_not(self.args[0].is_zero) and other.is_integer and other.is_even ): return S.One def _eval_nseries(self, x, n, logx, cdir=0): arg0 = self.args[0] x0 = arg0.subs(x, 0) if x0 != 0: return self.func(x0) if cdir != 0: cdir = arg0.dir(x, cdir) return -S.One if re(cdir) < 0 else S.One def _eval_rewrite_as_Piecewise(self, arg, **kwargs): if arg.is_extended_real: return Piecewise((1, arg > 0), (-1, arg < 0), (0, True)) def _eval_rewrite_as_Heaviside(self, arg, **kwargs): from sympy.functions.special.delta_functions import Heaviside if arg.is_extended_real: return Heaviside(arg) * 2 - 1 def _eval_rewrite_as_Abs(self, arg, **kwargs): return Piecewise((0, Eq(arg, 0)), (arg / Abs(arg), True)) def _eval_simplify(self, **kwargs): return self.func(factor_terms(self.args[0])) # XXX include doit? class Abs(Function): """ Return the absolute value of the argument. Explanation =========== This is an extension of the built-in function abs() to accept symbolic values. If you pass a SymPy expression to the built-in abs(), it will pass it automatically to Abs(). Examples ======== >>> from sympy import Abs, Symbol, S, I >>> Abs(-1) 1 >>> x = Symbol('x', real=True) >>> Abs(-x) Abs(x) >>> Abs(x**2) x**2 >>> abs(-x) # The Python built-in Abs(x) >>> Abs(3*x + 2*I) sqrt(9*x**2 + 4) >>> Abs(8*I) 8 Note that the Python built-in will return either an Expr or int depending on the argument:: >>> type(abs(-1)) <... 'int'> >>> type(abs(S.NegativeOne)) Abs will always return a sympy object. Parameters ========== arg : Expr Real or complex expression. Returns ======= expr : Expr Absolute value returned can be an expression or integer depending on input arg. See Also ======== sign, conjugate """ is_extended_real = True is_extended_negative = False is_extended_nonnegative = True unbranched = True _singularities = True # non-holomorphic def fdiff(self, argindex=1): """ Get the first derivative of the argument to Abs(). """ if argindex == 1: return sign(self.args[0]) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): from sympy.simplify.simplify import signsimp from sympy.core.function import expand_mul from sympy.core.power import Pow if hasattr(arg, '_eval_Abs'): obj = arg._eval_Abs() if obj is not None: return obj if not isinstance(arg, Expr): raise TypeError("Bad argument type for Abs(): %s" % type(arg)) # handle what we can arg = signsimp(arg, evaluate=False) n, d = arg.as_numer_denom() if d.free_symbols and not n.free_symbols: return cls(n)/cls(d) if arg.is_Mul: known = [] unk = [] for t in arg.args: if t.is_Pow and t.exp.is_integer and t.exp.is_negative: bnew = cls(t.base) if isinstance(bnew, cls): unk.append(t) else: known.append(Pow(bnew, t.exp)) else: tnew = cls(t) if isinstance(tnew, cls): unk.append(t) else: known.append(tnew) known = Mul(*known) unk = cls(Mul(*unk), evaluate=False) if unk else S.One return known*unk if arg is S.NaN: return S.NaN if arg is S.ComplexInfinity: return S.Infinity if arg.is_Pow: base, exponent = arg.as_base_exp() if base.is_extended_real: if exponent.is_integer: if exponent.is_even: return arg if base is S.NegativeOne: return S.One return Abs(base)**exponent if base.is_extended_nonnegative: return base**re(exponent) if base.is_extended_negative: return (-base)**re(exponent)*exp(-S.Pi*im(exponent)) return elif not base.has(Symbol): # complex base # express base**exponent as exp(exponent*log(base)) a, b = log(base).as_real_imag() z = a + I*b return exp(re(exponent*z)) if isinstance(arg, exp): return exp(re(arg.args[0])) if isinstance(arg, AppliedUndef): if arg.is_positive: return arg elif arg.is_negative: return -arg return if arg.is_Add and arg.has(S.Infinity, S.NegativeInfinity): if any(a.is_infinite for a in arg.as_real_imag()): return S.Infinity if arg.is_zero: return S.Zero if arg.is_extended_nonnegative: return arg if arg.is_extended_nonpositive: return -arg if arg.is_imaginary: arg2 = -S.ImaginaryUnit * arg if arg2.is_extended_nonnegative: return arg2 if arg.is_extended_real: return # reject result if all new conjugates are just wrappers around # an expression that was already in the arg conj = signsimp(arg.conjugate(), evaluate=False) new_conj = conj.atoms(conjugate) - arg.atoms(conjugate) if new_conj and all(arg.has(i.args[0]) for i in new_conj): return if arg != conj and arg != -conj: ignore = arg.atoms(Abs) abs_free_arg = arg.xreplace({i: Dummy(real=True) for i in ignore}) unk = [a for a in abs_free_arg.free_symbols if a.is_extended_real is None] if not unk or not all(conj.has(conjugate(u)) for u in unk): return sqrt(expand_mul(arg*conj)) def _eval_is_real(self): if self.args[0].is_finite: return True def _eval_is_integer(self): if self.args[0].is_extended_real: return self.args[0].is_integer def _eval_is_extended_nonzero(self): return fuzzy_not(self._args[0].is_zero) def _eval_is_zero(self): return self._args[0].is_zero def _eval_is_extended_positive(self): is_z = self.is_zero if is_z is not None: return not is_z def _eval_is_rational(self): if self.args[0].is_extended_real: return self.args[0].is_rational def _eval_is_even(self): if self.args[0].is_extended_real: return self.args[0].is_even def _eval_is_odd(self): if self.args[0].is_extended_real: return self.args[0].is_odd def _eval_is_algebraic(self): return self.args[0].is_algebraic def _eval_power(self, exponent): if self.args[0].is_extended_real and exponent.is_integer: if exponent.is_even: return self.args[0]**exponent elif exponent is not S.NegativeOne and exponent.is_Integer: return self.args[0]**(exponent - 1)*self return def _eval_nseries(self, x, n, logx, cdir=0): direction = self.args[0].leadterm(x)[0] if direction.has(log(x)): direction = direction.subs(log(x), logx) s = self.args[0]._eval_nseries(x, n=n, logx=logx) return (sign(direction)*s).expand() def _eval_derivative(self, x): if self.args[0].is_extended_real or self.args[0].is_imaginary: return Derivative(self.args[0], x, evaluate=True) \ * sign(conjugate(self.args[0])) rv = (re(self.args[0]) * Derivative(re(self.args[0]), x, evaluate=True) + im(self.args[0]) * Derivative(im(self.args[0]), x, evaluate=True)) / Abs(self.args[0]) return rv.rewrite(sign) def _eval_rewrite_as_Heaviside(self, arg, **kwargs): # Note this only holds for real arg (since Heaviside is not defined # for complex arguments). from sympy.functions.special.delta_functions import Heaviside if arg.is_extended_real: return arg*(Heaviside(arg) - Heaviside(-arg)) def _eval_rewrite_as_Piecewise(self, arg, **kwargs): if arg.is_extended_real: return Piecewise((arg, arg >= 0), (-arg, True)) elif arg.is_imaginary: return Piecewise((I*arg, I*arg >= 0), (-I*arg, True)) def _eval_rewrite_as_sign(self, arg, **kwargs): return arg/sign(arg) def _eval_rewrite_as_conjugate(self, arg, **kwargs): return (arg*conjugate(arg))**S.Half class arg(Function): """ returns the argument (in radians) of a complex number. The argument is evaluated in consistent convention with atan2 where the branch-cut is taken along the negative real axis and arg(z) is in the interval (-pi,pi]. For a positive number, the argument is always 0. Examples ======== >>> from sympy.functions import arg >>> from sympy import I, sqrt >>> arg(2.0) 0 >>> arg(I) pi/2 >>> arg(sqrt(2) + I*sqrt(2)) pi/4 >>> arg(sqrt(3)/2 + I/2) pi/6 >>> arg(4 + 3*I) atan(3/4) >>> arg(0.8 + 0.6*I) 0.643501108793284 Parameters ========== arg : Expr Real or complex expression. Returns ======= value : Expr Returns arc tangent of arg measured in radians. """ is_extended_real = True is_real = True is_finite = True _singularities = True # non-holomorphic @classmethod def eval(cls, arg): if isinstance(arg, exp_polar): return periodic_argument(arg, oo) if not arg.is_Atom: c, arg_ = factor_terms(arg).as_coeff_Mul() if arg_.is_Mul: arg_ = Mul(*[a if (sign(a) not in (-1, 1)) else sign(a) for a in arg_.args]) arg_ = sign(c)*arg_ else: arg_ = arg if any(i.is_extended_positive is None for i in arg_.atoms(AppliedUndef)): return x, y = arg_.as_real_imag() rv = atan2(y, x) if rv.is_number: return rv if arg_ != arg: return cls(arg_, evaluate=False) def _eval_derivative(self, t): x, y = self.args[0].as_real_imag() return (x * Derivative(y, t, evaluate=True) - y * Derivative(x, t, evaluate=True)) / (x**2 + y**2) def _eval_rewrite_as_atan2(self, arg, **kwargs): x, y = self.args[0].as_real_imag() return atan2(y, x) class conjugate(Function): """ Returns the `complex conjugate` Ref[1] of an argument. In mathematics, the complex conjugate of a complex number is given by changing the sign of the imaginary part. Thus, the conjugate of the complex number :math:`a + ib` (where a and b are real numbers) is :math:`a - ib` Examples ======== >>> from sympy import conjugate, I >>> conjugate(2) 2 >>> conjugate(I) -I >>> conjugate(3 + 2*I) 3 - 2*I >>> conjugate(5 - I) 5 + I Parameters ========== arg : Expr Real or complex expression. Returns ======= arg : Expr Complex conjugate of arg as real, imaginary or mixed expression. See Also ======== sign, Abs References ========== .. [1] https://en.wikipedia.org/wiki/Complex_conjugation """ _singularities = True # non-holomorphic @classmethod def eval(cls, arg): obj = arg._eval_conjugate() if obj is not None: return obj def _eval_Abs(self): return Abs(self.args[0], evaluate=True) def _eval_adjoint(self): return transpose(self.args[0]) def _eval_conjugate(self): return self.args[0] def _eval_derivative(self, x): if x.is_real: return conjugate(Derivative(self.args[0], x, evaluate=True)) elif x.is_imaginary: return -conjugate(Derivative(self.args[0], x, evaluate=True)) def _eval_transpose(self): return adjoint(self.args[0]) def _eval_is_algebraic(self): return self.args[0].is_algebraic class transpose(Function): """ Linear map transposition. Examples ======== >>> from sympy.functions import transpose >>> from sympy.matrices import MatrixSymbol >>> from sympy import Matrix >>> A = MatrixSymbol('A', 25, 9) >>> transpose(A) A.T >>> B = MatrixSymbol('B', 9, 22) >>> transpose(B) B.T >>> transpose(A*B) B.T*A.T >>> M = Matrix([[4, 5], [2, 1], [90, 12]]) >>> M Matrix([ [ 4, 5], [ 2, 1], [90, 12]]) >>> transpose(M) Matrix([ [4, 2, 90], [5, 1, 12]]) Parameters ========== arg : Matrix Matrix or matrix expression to take the transpose of. Returns ======= value : Matrix Transpose of arg. """ @classmethod def eval(cls, arg): obj = arg._eval_transpose() if obj is not None: return obj def _eval_adjoint(self): return conjugate(self.args[0]) def _eval_conjugate(self): return adjoint(self.args[0]) def _eval_transpose(self): return self.args[0] class adjoint(Function): """ Conjugate transpose or Hermite conjugation. Examples ======== >>> from sympy import adjoint >>> from sympy.matrices import MatrixSymbol >>> A = MatrixSymbol('A', 10, 5) >>> adjoint(A) Adjoint(A) Parameters ========== arg : Matrix Matrix or matrix expression to take the adjoint of. Returns ======= value : Matrix Represents the conjugate transpose or Hermite conjugation of arg. """ @classmethod def eval(cls, arg): obj = arg._eval_adjoint() if obj is not None: return obj obj = arg._eval_transpose() if obj is not None: return conjugate(obj) def _eval_adjoint(self): return self.args[0] def _eval_conjugate(self): return transpose(self.args[0]) def _eval_transpose(self): return conjugate(self.args[0]) def _latex(self, printer, exp=None, *args): arg = printer._print(self.args[0]) tex = r'%s^{\dagger}' % arg if exp: tex = r'\left(%s\right)^{%s}' % (tex, exp) return tex def _pretty(self, printer, *args): from sympy.printing.pretty.stringpict import prettyForm pform = printer._print(self.args[0], *args) if printer._use_unicode: pform = pform**prettyForm('\N{DAGGER}') else: pform = pform**prettyForm('+') return pform ############################################################################### ############### HANDLING OF POLAR NUMBERS ##################################### ############################################################################### class polar_lift(Function): """ Lift argument to the Riemann surface of the logarithm, using the standard branch. Examples ======== >>> from sympy import Symbol, polar_lift, I >>> p = Symbol('p', polar=True) >>> x = Symbol('x') >>> polar_lift(4) 4*exp_polar(0) >>> polar_lift(-4) 4*exp_polar(I*pi) >>> polar_lift(-I) exp_polar(-I*pi/2) >>> polar_lift(I + 2) polar_lift(2 + I) >>> polar_lift(4*x) 4*polar_lift(x) >>> polar_lift(4*p) 4*p Parameters ========== arg : Expr Real or complex expression. See Also ======== sympy.functions.elementary.exponential.exp_polar periodic_argument """ is_polar = True is_comparable = False # Cannot be evalf'd. @classmethod def eval(cls, arg): from sympy.functions.elementary.complexes import arg as argument if arg.is_number: ar = argument(arg) # In general we want to affirm that something is known, # e.g. `not ar.has(argument) and not ar.has(atan)` # but for now we will just be more restrictive and # see that it has evaluated to one of the known values. if ar in (0, pi/2, -pi/2, pi): return exp_polar(I*ar)*abs(arg) if arg.is_Mul: args = arg.args else: args = [arg] included = [] excluded = [] positive = [] for arg in args: if arg.is_polar: included += [arg] elif arg.is_positive: positive += [arg] else: excluded += [arg] if len(excluded) < len(args): if excluded: return Mul(*(included + positive))*polar_lift(Mul(*excluded)) elif included: return Mul(*(included + positive)) else: return Mul(*positive)*exp_polar(0) def _eval_evalf(self, prec): """ Careful! any evalf of polar numbers is flaky """ return self.args[0]._eval_evalf(prec) def _eval_Abs(self): return Abs(self.args[0], evaluate=True) class periodic_argument(Function): """ Represent the argument on a quotient of the Riemann surface of the logarithm. That is, given a period $P$, always return a value in (-P/2, P/2], by using exp(P*I) == 1. Examples ======== >>> from sympy import exp_polar, periodic_argument >>> from sympy import I, pi >>> periodic_argument(exp_polar(10*I*pi), 2*pi) 0 >>> periodic_argument(exp_polar(5*I*pi), 4*pi) pi >>> from sympy import exp_polar, periodic_argument >>> from sympy import I, pi >>> periodic_argument(exp_polar(5*I*pi), 2*pi) pi >>> periodic_argument(exp_polar(5*I*pi), 3*pi) -pi >>> periodic_argument(exp_polar(5*I*pi), pi) 0 Parameters ========== ar : Expr A polar number. period : ExprT The period $P$. See Also ======== sympy.functions.elementary.exponential.exp_polar polar_lift : Lift argument to the Riemann surface of the logarithm principal_branch """ @classmethod def _getunbranched(cls, ar): if ar.is_Mul: args = ar.args else: args = [ar] unbranched = 0 for a in args: if not a.is_polar: unbranched += arg(a) elif isinstance(a, exp_polar): unbranched += a.exp.as_real_imag()[1] elif a.is_Pow: re, im = a.exp.as_real_imag() unbranched += re*unbranched_argument( a.base) + im*log(abs(a.base)) elif isinstance(a, polar_lift): unbranched += arg(a.args[0]) else: return None return unbranched @classmethod def eval(cls, ar, period): # Our strategy is to evaluate the argument on the Riemann surface of the # logarithm, and then reduce. # NOTE evidently this means it is a rather bad idea to use this with # period != 2*pi and non-polar numbers. if not period.is_extended_positive: return None if period == oo and isinstance(ar, principal_branch): return periodic_argument(*ar.args) if isinstance(ar, polar_lift) and period >= 2*pi: return periodic_argument(ar.args[0], period) if ar.is_Mul: newargs = [x for x in ar.args if not x.is_positive] if len(newargs) != len(ar.args): return periodic_argument(Mul(*newargs), period) unbranched = cls._getunbranched(ar) if unbranched is None: return None if unbranched.has(periodic_argument, atan2, atan): return None if period == oo: return unbranched if period != oo: n = ceiling(unbranched/period - S.Half)*period if not n.has(ceiling): return unbranched - n def _eval_evalf(self, prec): z, period = self.args if period == oo: unbranched = periodic_argument._getunbranched(z) if unbranched is None: return self return unbranched._eval_evalf(prec) ub = periodic_argument(z, oo)._eval_evalf(prec) return (ub - ceiling(ub/period - S.Half)*period)._eval_evalf(prec) def unbranched_argument(arg): ''' Returns periodic argument of arg with period as infinity. Examples ======== >>> from sympy import exp_polar, unbranched_argument >>> from sympy import I, pi >>> unbranched_argument(exp_polar(15*I*pi)) 15*pi >>> unbranched_argument(exp_polar(7*I*pi)) 7*pi See also ======== periodic_argument ''' return periodic_argument(arg, oo) class principal_branch(Function): """ Represent a polar number reduced to its principal branch on a quotient of the Riemann surface of the logarithm. Explanation =========== This is a function of two arguments. The first argument is a polar number `z`, and the second one a positive real number or infinity, `p`. The result is "z mod exp_polar(I*p)". Examples ======== >>> from sympy import exp_polar, principal_branch, oo, I, pi >>> from sympy.abc import z >>> principal_branch(z, oo) z >>> principal_branch(exp_polar(2*pi*I)*3, 2*pi) 3*exp_polar(0) >>> principal_branch(exp_polar(2*pi*I)*3*z, 2*pi) 3*principal_branch(z, 2*pi) Parameters ========== x : Expr A polar number. period : Expr Positive real number or infinity. See Also ======== sympy.functions.elementary.exponential.exp_polar polar_lift : Lift argument to the Riemann surface of the logarithm periodic_argument """ is_polar = True is_comparable = False # cannot always be evalf'd @classmethod def eval(self, x, period): from sympy import oo, exp_polar, I, Mul, polar_lift, Symbol if isinstance(x, polar_lift): return principal_branch(x.args[0], period) if period == oo: return x ub = periodic_argument(x, oo) barg = periodic_argument(x, period) if ub != barg and not ub.has(periodic_argument) \ and not barg.has(periodic_argument): pl = polar_lift(x) def mr(expr): if not isinstance(expr, Symbol): return polar_lift(expr) return expr pl = pl.replace(polar_lift, mr) # Recompute unbranched argument ub = periodic_argument(pl, oo) if not pl.has(polar_lift): if ub != barg: res = exp_polar(I*(barg - ub))*pl else: res = pl if not res.is_polar and not res.has(exp_polar): res *= exp_polar(0) return res if not x.free_symbols: c, m = x, () else: c, m = x.as_coeff_mul(*x.free_symbols) others = [] for y in m: if y.is_positive: c *= y else: others += [y] m = tuple(others) arg = periodic_argument(c, period) if arg.has(periodic_argument): return None if arg.is_number and (unbranched_argument(c) != arg or (arg == 0 and m != () and c != 1)): if arg == 0: return abs(c)*principal_branch(Mul(*m), period) return principal_branch(exp_polar(I*arg)*Mul(*m), period)*abs(c) if arg.is_number and ((abs(arg) < period/2) == True or arg == period/2) \ and m == (): return exp_polar(arg*I)*abs(c) def _eval_evalf(self, prec): from sympy import exp, pi, I z, period = self.args p = periodic_argument(z, period)._eval_evalf(prec) if abs(p) > pi or p == -pi: return self # Cannot evalf for this argument. return (abs(z)*exp(I*p))._eval_evalf(prec) def _polarify(eq, lift, pause=False): from sympy import Integral if eq.is_polar: return eq if eq.is_number and not pause: return polar_lift(eq) if isinstance(eq, Symbol) and not pause and lift: return polar_lift(eq) elif eq.is_Atom: return eq elif eq.is_Add: r = eq.func(*[_polarify(arg, lift, pause=True) for arg in eq.args]) if lift: return polar_lift(r) return r elif eq.is_Pow and eq.base == S.Exp1: return eq.func(S.Exp1, _polarify(eq.exp, lift, pause=False)) elif eq.is_Function: return eq.func(*[_polarify(arg, lift, pause=False) for arg in eq.args]) elif isinstance(eq, Integral): # Don't lift the integration variable func = _polarify(eq.function, lift, pause=pause) limits = [] for limit in eq.args[1:]: var = _polarify(limit[0], lift=False, pause=pause) rest = _polarify(limit[1:], lift=lift, pause=pause) limits.append((var,) + rest) return Integral(*((func,) + tuple(limits))) else: return eq.func(*[_polarify(arg, lift, pause=pause) if isinstance(arg, Expr) else arg for arg in eq.args]) def polarify(eq, subs=True, lift=False): """ Turn all numbers in eq into their polar equivalents (under the standard choice of argument). Note that no attempt is made to guess a formal convention of adding polar numbers, expressions like 1 + x will generally not be altered. Note also that this function does not promote exp(x) to exp_polar(x). If ``subs`` is True, all symbols which are not already polar will be substituted for polar dummies; in this case the function behaves much like posify. If ``lift`` is True, both addition statements and non-polar symbols are changed to their polar_lift()ed versions. Note that lift=True implies subs=False. Examples ======== >>> from sympy import polarify, sin, I >>> from sympy.abc import x, y >>> expr = (-x)**y >>> expr.expand() (-x)**y >>> polarify(expr) ((_x*exp_polar(I*pi))**_y, {_x: x, _y: y}) >>> polarify(expr)[0].expand() _x**_y*exp_polar(_y*I*pi) >>> polarify(x, lift=True) polar_lift(x) >>> polarify(x*(1+y), lift=True) polar_lift(x)*polar_lift(y + 1) Adds are treated carefully: >>> polarify(1 + sin((1 + I)*x)) (sin(_x*polar_lift(1 + I)) + 1, {_x: x}) """ if lift: subs = False eq = _polarify(sympify(eq), lift) if not subs: return eq reps = {s: Dummy(s.name, polar=True) for s in eq.free_symbols} eq = eq.subs(reps) return eq, {r: s for s, r in reps.items()} def _unpolarify(eq, exponents_only, pause=False): if not isinstance(eq, Basic) or eq.is_Atom: return eq if not pause: if isinstance(eq, exp_polar): return exp(_unpolarify(eq.exp, exponents_only)) if isinstance(eq, principal_branch) and eq.args[1] == 2*pi: return _unpolarify(eq.args[0], exponents_only) if ( eq.is_Add or eq.is_Mul or eq.is_Boolean or eq.is_Relational and ( eq.rel_op in ('==', '!=') and 0 in eq.args or eq.rel_op not in ('==', '!=')) ): return eq.func(*[_unpolarify(x, exponents_only) for x in eq.args]) if isinstance(eq, polar_lift): return _unpolarify(eq.args[0], exponents_only) if eq.is_Pow: expo = _unpolarify(eq.exp, exponents_only) base = _unpolarify(eq.base, exponents_only, not (expo.is_integer and not pause)) return base**expo if eq.is_Function and getattr(eq.func, 'unbranched', False): return eq.func(*[_unpolarify(x, exponents_only, exponents_only) for x in eq.args]) return eq.func(*[_unpolarify(x, exponents_only, True) for x in eq.args]) def unpolarify(eq, subs={}, exponents_only=False): """ If p denotes the projection from the Riemann surface of the logarithm to the complex line, return a simplified version eq' of `eq` such that p(eq') == p(eq). Also apply the substitution subs in the end. (This is a convenience, since ``unpolarify``, in a certain sense, undoes polarify.) Examples ======== >>> from sympy import unpolarify, polar_lift, sin, I >>> unpolarify(polar_lift(I + 2)) 2 + I >>> unpolarify(sin(polar_lift(I + 7))) sin(7 + I) """ if isinstance(eq, bool): return eq eq = sympify(eq) if subs != {}: return unpolarify(eq.subs(subs)) changed = True pause = False if exponents_only: pause = True while changed: changed = False res = _unpolarify(eq, exponents_only, pause) if res != eq: changed = True eq = res if isinstance(res, bool): return res # Finally, replacing Exp(0) by 1 is always correct. # So is polar_lift(0) -> 0. return res.subs({exp_polar(0): 1, polar_lift(0): 0}) sympy-sympy-1.9/sympy/functions/elementary/exponential.py000066400000000000000000001157551412543434000241770ustar00rootroot00000000000000from sympy.core import sympify from sympy.core.add import Add from sympy.core.cache import cacheit from sympy.core.function import ( Function, ArgumentIndexError, _coeff_isneg, expand_mul, FunctionClass, PoleError) from sympy.core.logic import fuzzy_and, fuzzy_not, fuzzy_or from sympy.core.mul import Mul from sympy.core.numbers import Integer, Rational from sympy.core.parameters import global_parameters from sympy.core.power import Pow from sympy.core.singleton import S from sympy.core.symbol import Wild, Dummy from sympy.functions.combinatorial.factorials import factorial from sympy.functions.elementary.miscellaneous import sqrt from sympy.ntheory import multiplicity, perfect_power # NOTE IMPORTANT # The series expansion code in this file is an important part of the gruntz # algorithm for determining limits. _eval_nseries has to return a generalized # power series with coefficients in C(log(x), log). # In more detail, the result of _eval_nseries(self, x, n) must be # c_0*x**e_0 + ... (finitely many terms) # where e_i are numbers (not necessarily integers) and c_i involve only # numbers, the function log, and log(x). [This also means it must not contain # log(x(1+p)), this *has* to be expanded to log(x)+log(1+p) if x.is_positive and # p.is_positive.] class ExpBase(Function): unbranched = True _singularities = (S.ComplexInfinity,) @property def kind(self): return self.exp.kind def inverse(self, argindex=1): """ Returns the inverse function of ``exp(x)``. """ return log def as_numer_denom(self): """ Returns this with a positive exponent as a 2-tuple (a fraction). Examples ======== >>> from sympy.functions import exp >>> from sympy.abc import x >>> exp(-x).as_numer_denom() (1, exp(x)) >>> exp(x).as_numer_denom() (exp(x), 1) """ # this should be the same as Pow.as_numer_denom wrt # exponent handling exp = self.exp neg_exp = exp.is_negative if not neg_exp and not (-exp).is_negative: neg_exp = _coeff_isneg(exp) if neg_exp: return S.One, self.func(-exp) return self, S.One @property def exp(self): """ Returns the exponent of the function. """ return self.args[0] def as_base_exp(self): """ Returns the 2-tuple (base, exponent). """ return self.func(1), Mul(*self.args) def _eval_adjoint(self): return self.func(self.exp.adjoint()) def _eval_conjugate(self): return self.func(self.exp.conjugate()) def _eval_transpose(self): return self.func(self.exp.transpose()) def _eval_is_finite(self): arg = self.exp if arg.is_infinite: if arg.is_extended_negative: return True if arg.is_extended_positive: return False if arg.is_finite: return True def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: z = s.exp.is_zero if z: return True elif s.exp.is_rational and fuzzy_not(z): return False else: return s.is_rational def _eval_is_zero(self): return self.exp is S.NegativeInfinity def _eval_power(self, other): """exp(arg)**e -> exp(arg*e) if assumptions allow it. """ b, e = self.as_base_exp() return Pow._eval_power(Pow(b, e, evaluate=False), other) def _eval_expand_power_exp(self, **hints): from sympy import Sum, Product arg = self.args[0] if arg.is_Add and arg.is_commutative: return Mul.fromiter(self.func(x) for x in arg.args) elif isinstance(arg, Sum) and arg.is_commutative: return Product(self.func(arg.function), *arg.limits) return self.func(arg) class exp_polar(ExpBase): r""" Represent a 'polar number' (see g-function Sphinx documentation). Explanation =========== ``exp_polar`` represents the function `Exp: \mathbb{C} \rightarrow \mathcal{S}`, sending the complex number `z = a + bi` to the polar number `r = exp(a), \theta = b`. It is one of the main functions to construct polar numbers. Examples ======== >>> from sympy import exp_polar, pi, I, exp The main difference is that polar numbers don't "wrap around" at `2 \pi`: >>> exp(2*pi*I) 1 >>> exp_polar(2*pi*I) exp_polar(2*I*pi) apart from that they behave mostly like classical complex numbers: >>> exp_polar(2)*exp_polar(3) exp_polar(5) See Also ======== sympy.simplify.powsimp.powsimp polar_lift periodic_argument principal_branch """ is_polar = True is_comparable = False # cannot be evalf'd def _eval_Abs(self): # Abs is never a polar number from sympy.functions.elementary.complexes import re return exp(re(self.args[0])) def _eval_evalf(self, prec): """ Careful! any evalf of polar numbers is flaky """ from sympy import im, pi, re i = im(self.args[0]) try: bad = (i <= -pi or i > pi) except TypeError: bad = True if bad: return self # cannot evalf for this argument res = exp(self.args[0])._eval_evalf(prec) if i > 0 and im(res) < 0: # i ~ pi, but exp(I*i) evaluated to argument slightly bigger than pi return re(res) return res def _eval_power(self, other): return self.func(self.args[0]*other) def _eval_is_extended_real(self): if self.args[0].is_extended_real: return True def as_base_exp(self): # XXX exp_polar(0) is special! if self.args[0] == 0: return self, S.One return ExpBase.as_base_exp(self) class ExpMeta(FunctionClass): def __instancecheck__(cls, instance): if exp in instance.__class__.__mro__: return True return isinstance(instance, Pow) and instance.base is S.Exp1 class exp(ExpBase, metaclass=ExpMeta): """ The exponential function, :math:`e^x`. Examples ======== >>> from sympy.functions import exp >>> from sympy.abc import x >>> from sympy import I, pi >>> exp(x) exp(x) >>> exp(x).diff(x) exp(x) >>> exp(I*pi) -1 Parameters ========== arg : Expr See Also ======== log """ def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return self else: raise ArgumentIndexError(self, argindex) def _eval_refine(self, assumptions): from sympy.assumptions import ask, Q arg = self.args[0] if arg.is_Mul: Ioo = S.ImaginaryUnit*S.Infinity if arg in [Ioo, -Ioo]: return S.NaN coeff = arg.as_coefficient(S.Pi*S.ImaginaryUnit) if coeff: if ask(Q.integer(2*coeff)): if ask(Q.even(coeff)): return S.One elif ask(Q.odd(coeff)): return S.NegativeOne elif ask(Q.even(coeff + S.Half)): return -S.ImaginaryUnit elif ask(Q.odd(coeff + S.Half)): return S.ImaginaryUnit @classmethod def eval(cls, arg): from sympy.calculus import AccumBounds from sympy.sets.setexpr import SetExpr from sympy.matrices.matrices import MatrixBase from sympy import im, logcombine, re if isinstance(arg, MatrixBase): return arg.exp() elif global_parameters.exp_is_pow: return Pow(S.Exp1, arg) elif arg.is_Number: if arg is S.NaN: return S.NaN elif arg.is_zero: return S.One elif arg is S.One: return S.Exp1 elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Zero elif arg is S.ComplexInfinity: return S.NaN elif isinstance(arg, log): return arg.args[0] elif isinstance(arg, AccumBounds): return AccumBounds(exp(arg.min), exp(arg.max)) elif isinstance(arg, SetExpr): return arg._eval_func(cls) elif arg.is_Mul: coeff = arg.as_coefficient(S.Pi*S.ImaginaryUnit) if coeff: if (2*coeff).is_integer: if coeff.is_even: return S.One elif coeff.is_odd: return S.NegativeOne elif (coeff + S.Half).is_even: return -S.ImaginaryUnit elif (coeff + S.Half).is_odd: return S.ImaginaryUnit elif coeff.is_Rational: ncoeff = coeff % 2 # restrict to [0, 2pi) if ncoeff > 1: # restrict to (-pi, pi] ncoeff -= 2 if ncoeff != coeff: return cls(ncoeff*S.Pi*S.ImaginaryUnit) # Warning: code in risch.py will be very sensitive to changes # in this (see DifferentialExtension). # look for a single log factor coeff, terms = arg.as_coeff_Mul() # but it can't be multiplied by oo if coeff in [S.NegativeInfinity, S.Infinity]: if terms.is_number: if coeff is S.NegativeInfinity: terms = -terms if re(terms).is_zero and terms is not S.Zero: return S.NaN if re(terms).is_positive and im(terms) is not S.Zero: return S.ComplexInfinity if re(terms).is_negative: return S.Zero return None coeffs, log_term = [coeff], None for term in Mul.make_args(terms): term_ = logcombine(term) if isinstance(term_, log): if log_term is None: log_term = term_.args[0] else: return None elif term.is_comparable: coeffs.append(term) else: return None return log_term**Mul(*coeffs) if log_term else None elif arg.is_Add: out = [] add = [] argchanged = False for a in arg.args: if a is S.One: add.append(a) continue newa = cls(a) if isinstance(newa, cls): if newa.args[0] != a: add.append(newa.args[0]) argchanged = True else: add.append(a) else: out.append(newa) if out or argchanged: return Mul(*out)*cls(Add(*add), evaluate=False) if arg.is_zero: return S.One @property def base(self): """ Returns the base of the exponential function. """ return S.Exp1 @staticmethod @cacheit def taylor_term(n, x, *previous_terms): """ Calculates the next term in the Taylor series expansion. """ if n < 0: return S.Zero if n == 0: return S.One x = sympify(x) if previous_terms: p = previous_terms[-1] if p is not None: return p * x / n return x**n/factorial(n) def as_real_imag(self, deep=True, **hints): """ Returns this function as a 2-tuple representing a complex number. Examples ======== >>> from sympy import I >>> from sympy.abc import x >>> from sympy.functions import exp >>> exp(x).as_real_imag() (exp(re(x))*cos(im(x)), exp(re(x))*sin(im(x))) >>> exp(1).as_real_imag() (E, 0) >>> exp(I).as_real_imag() (cos(1), sin(1)) >>> exp(1+I).as_real_imag() (E*cos(1), E*sin(1)) See Also ======== sympy.functions.elementary.complexes.re sympy.functions.elementary.complexes.im """ from sympy.functions.elementary.trigonometric import cos, sin re, im = self.args[0].as_real_imag() if deep: re = re.expand(deep, **hints) im = im.expand(deep, **hints) cos, sin = cos(im), sin(im) return (exp(re)*cos, exp(re)*sin) def _eval_subs(self, old, new): # keep processing of power-like args centralized in Pow if old.is_Pow: # handle (exp(3*log(x))).subs(x**2, z) -> z**(3/2) old = exp(old.exp*log(old.base)) elif old is S.Exp1 and new.is_Function: old = exp if isinstance(old, exp) or old is S.Exp1: f = lambda a: Pow(*a.as_base_exp(), evaluate=False) if ( a.is_Pow or isinstance(a, exp)) else a return Pow._eval_subs(f(self), f(old), new) if old is exp and not new.is_Function: return new**self.exp._subs(old, new) return Function._eval_subs(self, old, new) def _eval_is_extended_real(self): if self.args[0].is_extended_real: return True elif self.args[0].is_imaginary: arg2 = -S(2) * S.ImaginaryUnit * self.args[0] / S.Pi return arg2.is_even def _eval_is_complex(self): def complex_extended_negative(arg): yield arg.is_complex yield arg.is_extended_negative return fuzzy_or(complex_extended_negative(self.args[0])) def _eval_is_algebraic(self): if (self.exp / S.Pi / S.ImaginaryUnit).is_rational: return True if fuzzy_not(self.exp.is_zero): if self.exp.is_algebraic: return False elif (self.exp / S.Pi).is_rational: return False def _eval_is_extended_positive(self): if self.exp.is_extended_real: return not self.args[0] is S.NegativeInfinity elif self.exp.is_imaginary: arg2 = -S.ImaginaryUnit * self.args[0] / S.Pi return arg2.is_even def _eval_nseries(self, x, n, logx, cdir=0): # NOTE Please see the comment at the beginning of this file, labelled # IMPORTANT. from sympy import ceiling, limit, Order, powsimp, Wild, expand_complex arg = self.exp arg_series = arg._eval_nseries(x, n=n, logx=logx) if arg_series.is_Order: return 1 + arg_series arg0 = limit(arg_series.removeO(), x, 0) if arg0 is S.NegativeInfinity: return Order(x**n, x) if arg0 is S.Infinity: return self t = Dummy("t") nterms = n try: cf = Order(arg.as_leading_term(x, logx=logx), x).getn() except (NotImplementedError, PoleError): cf = 0 if cf and cf > 0: nterms = ceiling(n/cf) exp_series = exp(t)._taylor(t, nterms) r = exp(arg0)*exp_series.subs(t, arg_series - arg0) if cf and cf > 1: r += Order((arg_series - arg0)**n, x)/x**((cf-1)*n) else: r += Order((arg_series - arg0)**n, x) r = r.expand() r = powsimp(r, deep=True, combine='exp') # powsimp may introduce unexpanded (-1)**Rational; see PR #17201 simplerat = lambda x: x.is_Rational and x.q in [3, 4, 6] w = Wild('w', properties=[simplerat]) r = r.replace((-1)**w, expand_complex((-1)**w)) return r def _taylor(self, x, n): l = [] g = None for i in range(n): g = self.taylor_term(i, self.args[0], g) g = g.nseries(x, n=n) l.append(g.removeO()) return Add(*l) def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].cancel().as_leading_term(x, logx=logx) arg0 = arg.subs(x, 0) if arg0 is S.NaN: arg0 = arg.limit(x, 0) if arg0.is_infinite is False: return exp(arg0) raise PoleError("Cannot expand %s around 0" % (self)) def _eval_rewrite_as_sin(self, arg, **kwargs): from sympy import sin I = S.ImaginaryUnit return sin(I*arg + S.Pi/2) - I*sin(I*arg) def _eval_rewrite_as_cos(self, arg, **kwargs): from sympy import cos I = S.ImaginaryUnit return cos(I*arg) + I*cos(I*arg + S.Pi/2) def _eval_rewrite_as_tanh(self, arg, **kwargs): from sympy import tanh return (1 + tanh(arg/2))/(1 - tanh(arg/2)) def _eval_rewrite_as_sqrt(self, arg, **kwargs): from sympy.functions.elementary.trigonometric import sin, cos if arg.is_Mul: coeff = arg.coeff(S.Pi*S.ImaginaryUnit) if coeff and coeff.is_number: cosine, sine = cos(S.Pi*coeff), sin(S.Pi*coeff) if not isinstance(cosine, cos) and not isinstance (sine, sin): return cosine + S.ImaginaryUnit*sine def _eval_rewrite_as_Pow(self, arg, **kwargs): if arg.is_Mul: logs = [a for a in arg.args if isinstance(a, log) and len(a.args) == 1] if logs: return Pow(logs[0].args[0], arg.coeff(logs[0])) def match_real_imag(expr): """ Try to match expr with a + b*I for real a and b. ``match_real_imag`` returns a tuple containing the real and imaginary parts of expr or (None, None) if direct matching is not possible. Contrary to ``re()``, ``im()``, ``as_real_imag()``, this helper won't force things by returning expressions themselves containing ``re()`` or ``im()`` and it doesn't expand its argument either. """ r_, i_ = expr.as_independent(S.ImaginaryUnit, as_Add=True) if i_ == 0 and r_.is_real: return (r_, i_) i_ = i_.as_coefficient(S.ImaginaryUnit) if i_ and i_.is_real and r_.is_real: return (r_, i_) else: return (None, None) # simpler to check for than None class log(Function): r""" The natural logarithm function `\ln(x)` or `\log(x)`. Explanation =========== Logarithms are taken with the natural base, `e`. To get a logarithm of a different base ``b``, use ``log(x, b)``, which is essentially short-hand for ``log(x)/log(b)``. ``log`` represents the principal branch of the natural logarithm. As such it has a branch cut along the negative real axis and returns values having a complex argument in `(-\pi, \pi]`. Examples ======== >>> from sympy import log, sqrt, S, I >>> log(8, 2) 3 >>> log(S(8)/3, 2) -log(3)/log(2) + 3 >>> log(-1 + I*sqrt(3)) log(2) + 2*I*pi/3 See Also ======== exp """ _singularities = (S.Zero, S.ComplexInfinity) def fdiff(self, argindex=1): """ Returns the first derivative of the function. """ if argindex == 1: return 1/self.args[0] else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): r""" Returns `e^x`, the inverse function of `\log(x)`. """ return exp @classmethod def eval(cls, arg, base=None): from sympy import unpolarify from sympy.calculus import AccumBounds from sympy.sets.setexpr import SetExpr from sympy.functions.elementary.complexes import Abs arg = sympify(arg) if base is not None: base = sympify(base) if base == 1: if arg == 1: return S.NaN else: return S.ComplexInfinity try: # handle extraction of powers of the base now # or else expand_log in Mul would have to handle this n = multiplicity(base, arg) if n: return n + log(arg / base**n) / log(base) else: return log(arg)/log(base) except ValueError: pass if base is not S.Exp1: return cls(arg)/cls(base) else: return cls(arg) if arg.is_Number: if arg.is_zero: return S.ComplexInfinity elif arg is S.One: return S.Zero elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg is S.NaN: return S.NaN elif arg.is_Rational and arg.p == 1: return -cls(arg.q) if arg.is_Pow and arg.base is S.Exp1 and arg.exp.is_extended_real: return arg.exp I = S.ImaginaryUnit if isinstance(arg, exp) and arg.exp.is_extended_real: return arg.exp elif isinstance(arg, exp) and arg.exp.is_number: r_, i_ = match_real_imag(arg.exp) if i_ and i_.is_comparable: i_ %= 2*S.Pi if i_ > S.Pi: i_ -= 2*S.Pi return r_ + expand_mul(i_ * I, deep=False) elif isinstance(arg, exp_polar): return unpolarify(arg.exp) elif isinstance(arg, AccumBounds): if arg.min.is_positive: return AccumBounds(log(arg.min), log(arg.max)) else: return elif isinstance(arg, SetExpr): return arg._eval_func(cls) if arg.is_number: if arg.is_negative: return S.Pi * I + cls(-arg) elif arg is S.ComplexInfinity: return S.ComplexInfinity elif arg is S.Exp1: return S.One if arg.is_zero: return S.ComplexInfinity # don't autoexpand Pow or Mul (see the issue 3351): if not arg.is_Add: coeff = arg.as_coefficient(I) if coeff is not None: if coeff is S.Infinity: return S.Infinity elif coeff is S.NegativeInfinity: return S.Infinity elif coeff.is_Rational: if coeff.is_nonnegative: return S.Pi * I * S.Half + cls(coeff) else: return -S.Pi * I * S.Half + cls(-coeff) if arg.is_number and arg.is_algebraic: # Match arg = coeff*(r_ + i_*I) with coeff>0, r_ and i_ real. coeff, arg_ = arg.as_independent(I, as_Add=False) if coeff.is_negative: coeff *= -1 arg_ *= -1 arg_ = expand_mul(arg_, deep=False) r_, i_ = arg_.as_independent(I, as_Add=True) i_ = i_.as_coefficient(I) if coeff.is_real and i_ and i_.is_real and r_.is_real: if r_.is_zero: if i_.is_positive: return S.Pi * I * S.Half + cls(coeff * i_) elif i_.is_negative: return -S.Pi * I * S.Half + cls(coeff * -i_) else: from sympy.simplify import ratsimp # Check for arguments involving rational multiples of pi t = (i_/r_).cancel() t1 = (-t).cancel() atan_table = { # first quadrant only sqrt(3): S.Pi/3, 1: S.Pi/4, sqrt(5 - 2*sqrt(5)): S.Pi/5, sqrt(2)*sqrt(5 - sqrt(5))/(1 + sqrt(5)): S.Pi/5, sqrt(5 + 2*sqrt(5)): S.Pi*Rational(2, 5), sqrt(2)*sqrt(sqrt(5) + 5)/(-1 + sqrt(5)): S.Pi*Rational(2, 5), sqrt(3)/3: S.Pi/6, sqrt(2) - 1: S.Pi/8, sqrt(2 - sqrt(2))/sqrt(sqrt(2) + 2): S.Pi/8, sqrt(2) + 1: S.Pi*Rational(3, 8), sqrt(sqrt(2) + 2)/sqrt(2 - sqrt(2)): S.Pi*Rational(3, 8), sqrt(1 - 2*sqrt(5)/5): S.Pi/10, (-sqrt(2) + sqrt(10))/(2*sqrt(sqrt(5) + 5)): S.Pi/10, sqrt(1 + 2*sqrt(5)/5): S.Pi*Rational(3, 10), (sqrt(2) + sqrt(10))/(2*sqrt(5 - sqrt(5))): S.Pi*Rational(3, 10), 2 - sqrt(3): S.Pi/12, (-1 + sqrt(3))/(1 + sqrt(3)): S.Pi/12, 2 + sqrt(3): S.Pi*Rational(5, 12), (1 + sqrt(3))/(-1 + sqrt(3)): S.Pi*Rational(5, 12) } if t in atan_table: modulus = ratsimp(coeff * Abs(arg_)) if r_.is_positive: return cls(modulus) + I * atan_table[t] else: return cls(modulus) + I * (atan_table[t] - S.Pi) elif t1 in atan_table: modulus = ratsimp(coeff * Abs(arg_)) if r_.is_positive: return cls(modulus) + I * (-atan_table[t1]) else: return cls(modulus) + I * (S.Pi - atan_table[t1]) def as_base_exp(self): """ Returns this function in the form (base, exponent). """ return self, S.One @staticmethod @cacheit def taylor_term(n, x, *previous_terms): # of log(1+x) r""" Returns the next term in the Taylor series expansion of `\log(1+x)`. """ from sympy import powsimp if n < 0: return S.Zero x = sympify(x) if n == 0: return x if previous_terms: p = previous_terms[-1] if p is not None: return powsimp((-n) * p * x / (n + 1), deep=True, combine='exp') return (1 - 2*(n % 2)) * x**(n + 1)/(n + 1) def _eval_expand_log(self, deep=True, **hints): from sympy import unpolarify, expand_log, factorint from sympy.concrete import Sum, Product force = hints.get('force', False) factor = hints.get('factor', False) if (len(self.args) == 2): return expand_log(self.func(*self.args), deep=deep, force=force) arg = self.args[0] if arg.is_Integer: # remove perfect powers p = perfect_power(arg) logarg = None coeff = 1 if p is not False: arg, coeff = p logarg = self.func(arg) # expand as product of its prime factors if factor=True if factor: p = factorint(arg) if arg not in p.keys(): logarg = sum(n*log(val) for val, n in p.items()) if logarg is not None: return coeff*logarg elif arg.is_Rational: return log(arg.p) - log(arg.q) elif arg.is_Mul: expr = [] nonpos = [] for x in arg.args: if force or x.is_positive or x.is_polar: a = self.func(x) if isinstance(a, log): expr.append(self.func(x)._eval_expand_log(**hints)) else: expr.append(a) elif x.is_negative: a = self.func(-x) expr.append(a) nonpos.append(S.NegativeOne) else: nonpos.append(x) return Add(*expr) + log(Mul(*nonpos)) elif arg.is_Pow or isinstance(arg, exp): if force or (arg.exp.is_extended_real and (arg.base.is_positive or ((arg.exp+1) .is_positive and (arg.exp-1).is_nonpositive))) or arg.base.is_polar: b = arg.base e = arg.exp a = self.func(b) if isinstance(a, log): return unpolarify(e) * a._eval_expand_log(**hints) else: return unpolarify(e) * a elif isinstance(arg, Product): if force or arg.function.is_positive: return Sum(log(arg.function), *arg.limits) return self.func(arg) def _eval_simplify(self, **kwargs): from sympy.simplify.simplify import expand_log, simplify, inversecombine if len(self.args) == 2: # it's unevaluated return simplify(self.func(*self.args), **kwargs) expr = self.func(simplify(self.args[0], **kwargs)) if kwargs['inverse']: expr = inversecombine(expr) expr = expand_log(expr, deep=True) return min([expr, self], key=kwargs['measure']) def as_real_imag(self, deep=True, **hints): """ Returns this function as a complex coordinate. Examples ======== >>> from sympy import I >>> from sympy.abc import x >>> from sympy.functions import log >>> log(x).as_real_imag() (log(Abs(x)), arg(x)) >>> log(I).as_real_imag() (0, pi/2) >>> log(1 + I).as_real_imag() (log(sqrt(2)), pi/4) >>> log(I*x).as_real_imag() (log(Abs(x)), arg(I*x)) """ from sympy import Abs, arg sarg = self.args[0] if deep: sarg = self.args[0].expand(deep, **hints) abs = Abs(sarg) if abs == sarg: return self, S.Zero arg = arg(sarg) if hints.get('log', False): # Expand the log hints['complex'] = False return (log(abs).expand(deep, **hints), arg) else: return log(abs), arg def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if (self.args[0] - 1).is_zero: return True if s.args[0].is_rational and fuzzy_not((self.args[0] - 1).is_zero): return False else: return s.is_rational def _eval_is_algebraic(self): s = self.func(*self.args) if s.func == self.func: if (self.args[0] - 1).is_zero: return True elif fuzzy_not((self.args[0] - 1).is_zero): if self.args[0].is_algebraic: return False else: return s.is_algebraic def _eval_is_extended_real(self): return self.args[0].is_extended_positive def _eval_is_complex(self): z = self.args[0] return fuzzy_and([z.is_complex, fuzzy_not(z.is_zero)]) def _eval_is_finite(self): arg = self.args[0] if arg.is_zero: return False return arg.is_finite def _eval_is_extended_positive(self): return (self.args[0] - 1).is_extended_positive def _eval_is_zero(self): return (self.args[0] - 1).is_zero def _eval_is_extended_nonnegative(self): return (self.args[0] - 1).is_extended_nonnegative def _eval_nseries(self, x, n, logx, cdir=0): # NOTE Please see the comment at the beginning of this file, labelled # IMPORTANT. from sympy import im, cancel, I, Order, logcombine from itertools import product if not logx: logx = log(x) if self.args[0] == x: return logx arg = self.args[0] k, l = Wild("k"), Wild("l") r = arg.match(k*x**l) if r is not None: k, l = r[k], r[l] if l != 0 and not l.has(x) and not k.has(x): r = log(k) + l*logx # XXX true regardless of assumptions? return r def coeff_exp(term, x): coeff, exp = S.One, S.Zero for factor in Mul.make_args(term): if factor.has(x): base, exp = factor.as_base_exp() if base != x: try: return term.leadterm(x) except ValueError: return term, S.Zero else: coeff *= factor return coeff, exp # TODO new and probably slow try: a, b = arg.leadterm(x) s = arg.nseries(x, n=n+b, logx=logx) except (ValueError, NotImplementedError, PoleError): s = arg.nseries(x, n=n, logx=logx) while s.is_Order: n += 1 s = arg.nseries(x, n=n, logx=logx) a, b = s.removeO().leadterm(x) p = cancel(s/(a*x**b) - 1).expand().powsimp() if p.has(exp): p = logcombine(p) if isinstance(p, Order): n = p.getn() _, d = coeff_exp(p, x) if not d.is_positive: return log(a) + b*logx + Order(x**n, x) def mul(d1, d2): res = {} for e1, e2 in product(d1, d2): ex = e1 + e2 if ex < n: res[ex] = res.get(ex, S.Zero) + d1[e1]*d2[e2] return res pterms = {} for term in Add.make_args(p): co1, e1 = coeff_exp(term, x) pterms[e1] = pterms.get(e1, S.Zero) + co1.removeO() k = S.One terms = {} pk = pterms while k*d < n: coeff = -(-1)**k/k for ex in pk: terms[ex] = terms.get(ex, S.Zero) + coeff*pk[ex] pk = mul(pk, pterms) k += S.One res = log(a) + b*logx for ex in terms: res += terms[ex]*x**(ex) if cdir != 0: cdir = self.args[0].dir(x, cdir) if a.is_real and a.is_negative and im(cdir) < 0: res -= 2*I*S.Pi return res + Order(x**n, x) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import I, im, re arg0 = self.args[0].together() arg = arg0.as_leading_term(x, cdir=cdir) x0 = arg0.subs(x, 0) if (x0 is S.NaN and logx is None): x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if x0 in (S.NegativeInfinity, S.Infinity): raise PoleError("Cannot expand %s around 0" % (self)) if x0 == 1: return (arg0 - S.One).as_leading_term(x) if cdir != 0: cdir = arg0.dir(x, cdir) if x0.is_real and x0.is_negative and im(cdir).is_negative: return self.func(x0) - 2*I*S.Pi return self.func(arg) class LambertW(Function): r""" The Lambert W function `W(z)` is defined as the inverse function of `w \exp(w)` [1]_. Explanation =========== In other words, the value of `W(z)` is such that `z = W(z) \exp(W(z))` for any complex number `z`. The Lambert W function is a multivalued function with infinitely many branches `W_k(z)`, indexed by `k \in \mathbb{Z}`. Each branch gives a different solution `w` of the equation `z = w \exp(w)`. The Lambert W function has two partially real branches: the principal branch (`k = 0`) is real for real `z > -1/e`, and the `k = -1` branch is real for `-1/e < z < 0`. All branches except `k = 0` have a logarithmic singularity at `z = 0`. Examples ======== >>> from sympy import LambertW >>> LambertW(1.2) 0.635564016364870 >>> LambertW(1.2, -1).n() -1.34747534407696 - 4.41624341514535*I >>> LambertW(-1).is_real False References ========== .. [1] https://en.wikipedia.org/wiki/Lambert_W_function """ _singularities = (-Pow(S.Exp1, -1, evaluate=False), S.ComplexInfinity) @classmethod def eval(cls, x, k=None): if k == S.Zero: return cls(x) elif k is None: k = S.Zero if k.is_zero: if x.is_zero: return S.Zero if x is S.Exp1: return S.One if x == -1/S.Exp1: return S.NegativeOne if x == -log(2)/2: return -log(2) if x == 2*log(2): return log(2) if x == -S.Pi/2: return S.ImaginaryUnit*S.Pi/2 if x == exp(1 + S.Exp1): return S.Exp1 if x is S.Infinity: return S.Infinity if x.is_zero: return S.Zero if fuzzy_not(k.is_zero): if x.is_zero: return S.NegativeInfinity if k is S.NegativeOne: if x == -S.Pi/2: return -S.ImaginaryUnit*S.Pi/2 elif x == -1/S.Exp1: return S.NegativeOne elif x == -2*exp(-2): return -Integer(2) def fdiff(self, argindex=1): """ Return the first derivative of this function. """ x = self.args[0] if len(self.args) == 1: if argindex == 1: return LambertW(x)/(x*(1 + LambertW(x))) else: k = self.args[1] if argindex == 1: return LambertW(x, k)/(x*(1 + LambertW(x, k))) raise ArgumentIndexError(self, argindex) def _eval_is_extended_real(self): x = self.args[0] if len(self.args) == 1: k = S.Zero else: k = self.args[1] if k.is_zero: if (x + 1/S.Exp1).is_positive: return True elif (x + 1/S.Exp1).is_nonpositive: return False elif (k + 1).is_zero: if x.is_negative and (x + 1/S.Exp1).is_positive: return True elif x.is_nonpositive or (x + 1/S.Exp1).is_nonnegative: return False elif fuzzy_not(k.is_zero) and fuzzy_not((k + 1).is_zero): if x.is_extended_real: return False def _eval_is_finite(self): return self.args[0].is_finite def _eval_is_algebraic(self): s = self.func(*self.args) if s.func == self.func: if fuzzy_not(self.args[0].is_zero) and self.args[0].is_algebraic: return False else: return s.is_algebraic def _eval_as_leading_term(self, x, logx=None, cdir=0): if len(self.args) == 1: arg = self.args[0] arg0 = arg.subs(x, 0).cancel() if not arg0.is_zero: return self.func(arg0) return arg.as_leading_term(x) def _eval_nseries(self, x, n, logx, cdir=0): if len(self.args) == 1: from sympy import Order, ceiling, expand_multinomial arg = self.args[0].nseries(x, n=n, logx=logx) lt = arg.compute_leading_term(x, logx=logx) lte = 1 if lt.is_Pow: lte = lt.exp if ceiling(n/lte) >= 1: s = Add(*[(-S.One)**(k - 1)*Integer(k)**(k - 2)/ factorial(k - 1)*arg**k for k in range(1, ceiling(n/lte))]) s = expand_multinomial(s) else: s = S.Zero return s + Order(x**n, x) return super()._eval_nseries(x, n, logx) def _eval_is_zero(self): x = self.args[0] if len(self.args) == 1: k = S.Zero else: k = self.args[1] if x.is_zero and k.is_zero: return True sympy-sympy-1.9/sympy/functions/elementary/hyperbolic.py000066400000000000000000001445721412543434000240100ustar00rootroot00000000000000from sympy.core.logic import FuzzyBool from sympy.core import S, sympify, cacheit, pi, I, Rational from sympy.core.add import Add from sympy.core.function import Function, ArgumentIndexError, _coeff_isneg from sympy.functions.combinatorial.factorials import factorial, RisingFactorial from sympy.functions.elementary.exponential import exp, log, match_real_imag from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.integers import floor from sympy.core.logic import fuzzy_or, fuzzy_and def _rewrite_hyperbolics_as_exp(expr): expr = sympify(expr) return expr.xreplace({h: h.rewrite(exp) for h in expr.atoms(HyperbolicFunction)}) ############################################################################### ########################### HYPERBOLIC FUNCTIONS ############################## ############################################################################### class HyperbolicFunction(Function): """ Base class for hyperbolic functions. See Also ======== sinh, cosh, tanh, coth """ unbranched = True def _peeloff_ipi(arg): """ Split ARG into two parts, a "rest" and a multiple of I*pi/2. This assumes ARG to be an Add. The multiple of I*pi returned in the second position is always a Rational. Examples ======== >>> from sympy.functions.elementary.hyperbolic import _peeloff_ipi as peel >>> from sympy import pi, I >>> from sympy.abc import x, y >>> peel(x + I*pi/2) (x, I*pi/2) >>> peel(x + I*2*pi/3 + I*pi*y) (x + I*pi*y + I*pi/6, I*pi/2) """ for a in Add.make_args(arg): if a == S.Pi*S.ImaginaryUnit: K = S.One break elif a.is_Mul: K, p = a.as_two_terms() if p == S.Pi*S.ImaginaryUnit and K.is_Rational: break else: return arg, S.Zero m1 = (K % S.Half)*S.Pi*S.ImaginaryUnit m2 = K*S.Pi*S.ImaginaryUnit - m1 return arg - m2, m2 class sinh(HyperbolicFunction): r""" sinh(x) is the hyperbolic sine of x. The hyperbolic sine function is $\frac{e^x - e^{-x}}{2}$. Examples ======== >>> from sympy import sinh >>> from sympy.abc import x >>> sinh(x) sinh(x) See Also ======== cosh, tanh, asinh """ def fdiff(self, argindex=1): """ Returns the first derivative of this function. """ if argindex == 1: return cosh(self.args[0]) else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return asinh @classmethod def eval(cls, arg): from sympy import sin arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.NegativeInfinity elif arg.is_zero: return S.Zero elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit * sin(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.is_Add: x, m = _peeloff_ipi(arg) if m: return sinh(m)*cosh(x) + cosh(m)*sinh(x) if arg.is_zero: return S.Zero if arg.func == asinh: return arg.args[0] if arg.func == acosh: x = arg.args[0] return sqrt(x - 1) * sqrt(x + 1) if arg.func == atanh: x = arg.args[0] return x/sqrt(1 - x**2) if arg.func == acoth: x = arg.args[0] return 1/(sqrt(x - 1) * sqrt(x + 1)) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): """ Returns the next term in the Taylor series expansion. """ if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) > 2: p = previous_terms[-2] return p * x**2 / (n*(n - 1)) else: return x**(n) / factorial(n) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): """ Returns this function as a complex coordinate. """ from sympy import cos, sin if self.args[0].is_extended_real: if deep: hints['complex'] = False return (self.expand(deep, **hints), S.Zero) else: return (self, S.Zero) if deep: re, im = self.args[0].expand(deep, **hints).as_real_imag() else: re, im = self.args[0].as_real_imag() return (sinh(re)*cos(im), cosh(re)*sin(im)) def _eval_expand_complex(self, deep=True, **hints): re_part, im_part = self.as_real_imag(deep=deep, **hints) return re_part + im_part*S.ImaginaryUnit def _eval_expand_trig(self, deep=True, **hints): if deep: arg = self.args[0].expand(deep, **hints) else: arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here x, y = arg.as_two_terms() else: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff is not S.One and coeff.is_Integer and terms is not S.One: x = terms y = (coeff - 1)*x if x is not None: return (sinh(x)*cosh(y) + sinh(y)*cosh(x)).expand(trig=True) return sinh(arg) def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): return (exp(arg) - exp(-arg)) / 2 def _eval_rewrite_as_exp(self, arg, **kwargs): return (exp(arg) - exp(-arg)) / 2 def _eval_rewrite_as_cosh(self, arg, **kwargs): return -S.ImaginaryUnit*cosh(arg + S.Pi*S.ImaginaryUnit/2) def _eval_rewrite_as_tanh(self, arg, **kwargs): tanh_half = tanh(S.Half*arg) return 2*tanh_half/(1 - tanh_half**2) def _eval_rewrite_as_coth(self, arg, **kwargs): coth_half = coth(S.Half*arg) return 2*coth_half/(coth_half**2 - 1) def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.NaN: arg0 = arg.limit(x, 0, dir='-' if cdir.is_negative else '+') if arg0.is_zero: return arg elif arg0.is_finite: return self.func(arg0) else: return self def _eval_is_real(self): arg = self.args[0] if arg.is_real: return True # if `im` is of the form n*pi # else, check if it is a number re, im = arg.as_real_imag() return (im%pi).is_zero def _eval_is_extended_real(self): if self.args[0].is_extended_real: return True def _eval_is_positive(self): if self.args[0].is_extended_real: return self.args[0].is_positive def _eval_is_negative(self): if self.args[0].is_extended_real: return self.args[0].is_negative def _eval_is_finite(self): arg = self.args[0] return arg.is_finite def _eval_is_zero(self): arg = self.args[0] if arg.is_zero: return True class cosh(HyperbolicFunction): r""" cosh(x) is the hyperbolic cosine of x. The hyperbolic cosine function is $\frac{e^x + e^{-x}}{2}$. Examples ======== >>> from sympy import cosh >>> from sympy.abc import x >>> cosh(x) cosh(x) See Also ======== sinh, tanh, acosh """ def fdiff(self, argindex=1): if argindex == 1: return sinh(self.args[0]) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): from sympy import cos arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg.is_zero: return S.One elif arg.is_negative: return cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return cos(i_coeff) else: if _coeff_isneg(arg): return cls(-arg) if arg.is_Add: x, m = _peeloff_ipi(arg) if m: return cosh(m)*cosh(x) + sinh(m)*sinh(x) if arg.is_zero: return S.One if arg.func == asinh: return sqrt(1 + arg.args[0]**2) if arg.func == acosh: return arg.args[0] if arg.func == atanh: return 1/sqrt(1 - arg.args[0]**2) if arg.func == acoth: x = arg.args[0] return x/(sqrt(x - 1) * sqrt(x + 1)) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 1: return S.Zero else: x = sympify(x) if len(previous_terms) > 2: p = previous_terms[-2] return p * x**2 / (n*(n - 1)) else: return x**(n)/factorial(n) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): from sympy import cos, sin if self.args[0].is_extended_real: if deep: hints['complex'] = False return (self.expand(deep, **hints), S.Zero) else: return (self, S.Zero) if deep: re, im = self.args[0].expand(deep, **hints).as_real_imag() else: re, im = self.args[0].as_real_imag() return (cosh(re)*cos(im), sinh(re)*sin(im)) def _eval_expand_complex(self, deep=True, **hints): re_part, im_part = self.as_real_imag(deep=deep, **hints) return re_part + im_part*S.ImaginaryUnit def _eval_expand_trig(self, deep=True, **hints): if deep: arg = self.args[0].expand(deep, **hints) else: arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here x, y = arg.as_two_terms() else: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff is not S.One and coeff.is_Integer and terms is not S.One: x = terms y = (coeff - 1)*x if x is not None: return (cosh(x)*cosh(y) + sinh(x)*sinh(y)).expand(trig=True) return cosh(arg) def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): return (exp(arg) + exp(-arg)) / 2 def _eval_rewrite_as_exp(self, arg, **kwargs): return (exp(arg) + exp(-arg)) / 2 def _eval_rewrite_as_sinh(self, arg, **kwargs): return -S.ImaginaryUnit*sinh(arg + S.Pi*S.ImaginaryUnit/2) def _eval_rewrite_as_tanh(self, arg, **kwargs): tanh_half = tanh(S.Half*arg)**2 return (1 + tanh_half)/(1 - tanh_half) def _eval_rewrite_as_coth(self, arg, **kwargs): coth_half = coth(S.Half*arg)**2 return (coth_half + 1)/(coth_half - 1) def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.NaN: arg0 = arg.limit(x, 0, dir='-' if cdir.is_negative else '+') if arg0.is_zero: return S.One elif arg0.is_finite: return self.func(arg0) else: return self def _eval_is_real(self): arg = self.args[0] # `cosh(x)` is real for real OR purely imaginary `x` if arg.is_real or arg.is_imaginary: return True # cosh(a+ib) = cos(b)*cosh(a) + i*sin(b)*sinh(a) # the imaginary part can be an expression like n*pi # if not, check if the imaginary part is a number re, im = arg.as_real_imag() return (im%pi).is_zero def _eval_is_positive(self): # cosh(x+I*y) = cos(y)*cosh(x) + I*sin(y)*sinh(x) # cosh(z) is positive iff it is real and the real part is positive. # So we need sin(y)*sinh(x) = 0 which gives x=0 or y=n*pi # Case 1 (y=n*pi): cosh(z) = (-1)**n * cosh(x) -> positive for n even # Case 2 (x=0): cosh(z) = cos(y) -> positive when cos(y) is positive z = self.args[0] x, y = z.as_real_imag() ymod = y % (2*pi) yzero = ymod.is_zero # shortcut if ymod is zero if yzero: return True xzero = x.is_zero # shortcut x is not zero if xzero is False: return yzero return fuzzy_or([ # Case 1: yzero, # Case 2: fuzzy_and([ xzero, fuzzy_or([ymod < pi/2, ymod > 3*pi/2]) ]) ]) def _eval_is_nonnegative(self): z = self.args[0] x, y = z.as_real_imag() ymod = y % (2*pi) yzero = ymod.is_zero # shortcut if ymod is zero if yzero: return True xzero = x.is_zero # shortcut x is not zero if xzero is False: return yzero return fuzzy_or([ # Case 1: yzero, # Case 2: fuzzy_and([ xzero, fuzzy_or([ymod <= pi/2, ymod >= 3*pi/2]) ]) ]) def _eval_is_finite(self): arg = self.args[0] return arg.is_finite class tanh(HyperbolicFunction): r""" tanh(x) is the hyperbolic tangent of x. The hyperbolic tangent function is $\frac{\sinh(x)}{\cosh(x)}$. Examples ======== >>> from sympy import tanh >>> from sympy.abc import x >>> tanh(x) tanh(x) See Also ======== sinh, cosh, atanh """ def fdiff(self, argindex=1): if argindex == 1: return S.One - tanh(self.args[0])**2 else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return atanh @classmethod def eval(cls, arg): from sympy import tan arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.One elif arg is S.NegativeInfinity: return S.NegativeOne elif arg.is_zero: return S.Zero elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: if _coeff_isneg(i_coeff): return -S.ImaginaryUnit * tan(-i_coeff) return S.ImaginaryUnit * tan(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.is_Add: x, m = _peeloff_ipi(arg) if m: tanhm = tanh(m) if tanhm is S.ComplexInfinity: return coth(x) else: # tanhm == 0 return tanh(x) if arg.is_zero: return S.Zero if arg.func == asinh: x = arg.args[0] return x/sqrt(1 + x**2) if arg.func == acosh: x = arg.args[0] return sqrt(x - 1) * sqrt(x + 1) / x if arg.func == atanh: return arg.args[0] if arg.func == acoth: return 1/arg.args[0] @staticmethod @cacheit def taylor_term(n, x, *previous_terms): from sympy import bernoulli if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) a = 2**(n + 1) B = bernoulli(n + 1) F = factorial(n + 1) return a*(a - 1) * B/F * x**n def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): from sympy import cos, sin if self.args[0].is_extended_real: if deep: hints['complex'] = False return (self.expand(deep, **hints), S.Zero) else: return (self, S.Zero) if deep: re, im = self.args[0].expand(deep, **hints).as_real_imag() else: re, im = self.args[0].as_real_imag() denom = sinh(re)**2 + cos(im)**2 return (sinh(re)*cosh(re)/denom, sin(im)*cos(im)/denom) def _eval_expand_trig(self, **hints): arg = self.args[0] if arg.is_Add: from sympy import symmetric_poly n = len(arg.args) TX = [tanh(x, evaluate=False)._eval_expand_trig() for x in arg.args] p = [0, 0] # [den, num] for i in range(n + 1): p[i % 2] += symmetric_poly(i, TX) return p[1]/p[0] elif arg.is_Mul: from sympy.functions.combinatorial.numbers import nC coeff, terms = arg.as_coeff_Mul() if coeff.is_Integer and coeff > 1: n = [] d = [] T = tanh(terms) for k in range(1, coeff + 1, 2): n.append(nC(range(coeff), k)*T**k) for k in range(0, coeff + 1, 2): d.append(nC(range(coeff), k)*T**k) return Add(*n)/Add(*d) return tanh(arg) def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): neg_exp, pos_exp = exp(-arg), exp(arg) return (pos_exp - neg_exp)/(pos_exp + neg_exp) def _eval_rewrite_as_exp(self, arg, **kwargs): neg_exp, pos_exp = exp(-arg), exp(arg) return (pos_exp - neg_exp)/(pos_exp + neg_exp) def _eval_rewrite_as_sinh(self, arg, **kwargs): return S.ImaginaryUnit*sinh(arg)/sinh(S.Pi*S.ImaginaryUnit/2 - arg) def _eval_rewrite_as_cosh(self, arg, **kwargs): return S.ImaginaryUnit*cosh(S.Pi*S.ImaginaryUnit/2 - arg)/cosh(arg) def _eval_rewrite_as_coth(self, arg, **kwargs): return 1/coth(arg) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order arg = self.args[0].as_leading_term(x) if x in arg.free_symbols and Order(1, x).contains(arg): return arg else: return self.func(arg) def _eval_is_real(self): arg = self.args[0] if arg.is_real: return True re, im = arg.as_real_imag() # if denom = 0, tanh(arg) = zoo if re == 0 and im % pi == pi/2: return None # check if im is of the form n*pi/2 to make sin(2*im) = 0 # if not, im could be a number, return False in that case return (im % (pi/2)).is_zero def _eval_is_extended_real(self): if self.args[0].is_extended_real: return True def _eval_is_positive(self): if self.args[0].is_extended_real: return self.args[0].is_positive def _eval_is_negative(self): if self.args[0].is_extended_real: return self.args[0].is_negative def _eval_is_finite(self): from sympy import sinh, cos arg = self.args[0] re, im = arg.as_real_imag() denom = cos(im)**2 + sinh(re)**2 if denom == 0: return False elif denom.is_number: return True if arg.is_extended_real: return True def _eval_is_zero(self): arg = self.args[0] if arg.is_zero: return True class coth(HyperbolicFunction): r""" coth(x) is the hyperbolic cotangent of x. The hyperbolic cotangent function is $\frac{\cosh(x)}{\sinh(x)}$. Examples ======== >>> from sympy import coth >>> from sympy.abc import x >>> coth(x) coth(x) See Also ======== sinh, cosh, acoth """ def fdiff(self, argindex=1): if argindex == 1: return -1/sinh(self.args[0])**2 else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return acoth @classmethod def eval(cls, arg): from sympy import cot arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.One elif arg is S.NegativeInfinity: return S.NegativeOne elif arg.is_zero: return S.ComplexInfinity elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.NaN i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: if _coeff_isneg(i_coeff): return S.ImaginaryUnit * cot(-i_coeff) return -S.ImaginaryUnit * cot(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.is_Add: x, m = _peeloff_ipi(arg) if m: cothm = coth(m) if cothm is S.ComplexInfinity: return coth(x) else: # cothm == 0 return tanh(x) if arg.is_zero: return S.ComplexInfinity if arg.func == asinh: x = arg.args[0] return sqrt(1 + x**2)/x if arg.func == acosh: x = arg.args[0] return x/(sqrt(x - 1) * sqrt(x + 1)) if arg.func == atanh: return 1/arg.args[0] if arg.func == acoth: return arg.args[0] @staticmethod @cacheit def taylor_term(n, x, *previous_terms): from sympy import bernoulli if n == 0: return 1 / sympify(x) elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) B = bernoulli(n + 1) F = factorial(n + 1) return 2**(n + 1) * B/F * x**n def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): from sympy import cos, sin if self.args[0].is_extended_real: if deep: hints['complex'] = False return (self.expand(deep, **hints), S.Zero) else: return (self, S.Zero) if deep: re, im = self.args[0].expand(deep, **hints).as_real_imag() else: re, im = self.args[0].as_real_imag() denom = sinh(re)**2 + sin(im)**2 return (sinh(re)*cosh(re)/denom, -sin(im)*cos(im)/denom) def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): neg_exp, pos_exp = exp(-arg), exp(arg) return (pos_exp + neg_exp)/(pos_exp - neg_exp) def _eval_rewrite_as_exp(self, arg, **kwargs): neg_exp, pos_exp = exp(-arg), exp(arg) return (pos_exp + neg_exp)/(pos_exp - neg_exp) def _eval_rewrite_as_sinh(self, arg, **kwargs): return -S.ImaginaryUnit*sinh(S.Pi*S.ImaginaryUnit/2 - arg)/sinh(arg) def _eval_rewrite_as_cosh(self, arg, **kwargs): return -S.ImaginaryUnit*cosh(arg)/cosh(S.Pi*S.ImaginaryUnit/2 - arg) def _eval_rewrite_as_tanh(self, arg, **kwargs): return 1/tanh(arg) def _eval_is_positive(self): if self.args[0].is_extended_real: return self.args[0].is_positive def _eval_is_negative(self): if self.args[0].is_extended_real: return self.args[0].is_negative def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order arg = self.args[0].as_leading_term(x) if x in arg.free_symbols and Order(1, x).contains(arg): return 1/arg else: return self.func(arg) def _eval_expand_trig(self, **hints): arg = self.args[0] if arg.is_Add: from sympy import symmetric_poly CX = [coth(x, evaluate=False)._eval_expand_trig() for x in arg.args] p = [[], []] n = len(arg.args) for i in range(n, -1, -1): p[(n - i) % 2].append(symmetric_poly(i, CX)) return Add(*p[0])/Add(*p[1]) elif arg.is_Mul: from sympy import binomial coeff, x = arg.as_coeff_Mul(rational=True) if coeff.is_Integer and coeff > 1: c = coth(x, evaluate=False) p = [[], []] for i in range(coeff, -1, -1): p[(coeff - i) % 2].append(binomial(coeff, i)*c**i) return Add(*p[0])/Add(*p[1]) return coth(arg) class ReciprocalHyperbolicFunction(HyperbolicFunction): """Base class for reciprocal functions of hyperbolic functions. """ #To be defined in class _reciprocal_of = None _is_even = None # type: FuzzyBool _is_odd = None # type: FuzzyBool @classmethod def eval(cls, arg): if arg.could_extract_minus_sign(): if cls._is_even: return cls(-arg) if cls._is_odd: return -cls(-arg) t = cls._reciprocal_of.eval(arg) if hasattr(arg, 'inverse') and arg.inverse() == cls: return arg.args[0] return 1/t if t is not None else t def _call_reciprocal(self, method_name, *args, **kwargs): # Calls method_name on _reciprocal_of o = self._reciprocal_of(self.args[0]) return getattr(o, method_name)(*args, **kwargs) def _calculate_reciprocal(self, method_name, *args, **kwargs): # If calling method_name on _reciprocal_of returns a value != None # then return the reciprocal of that value t = self._call_reciprocal(method_name, *args, **kwargs) return 1/t if t is not None else t def _rewrite_reciprocal(self, method_name, arg): # Special handling for rewrite functions. If reciprocal rewrite returns # unmodified expression, then return None t = self._call_reciprocal(method_name, arg) if t is not None and t != self._reciprocal_of(arg): return 1/t def _eval_rewrite_as_exp(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_exp", arg) def _eval_rewrite_as_tractable(self, arg, limitvar=None, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_tractable", arg) def _eval_rewrite_as_tanh(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_tanh", arg) def _eval_rewrite_as_coth(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_coth", arg) def as_real_imag(self, deep = True, **hints): return (1 / self._reciprocal_of(self.args[0])).as_real_imag(deep, **hints) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def _eval_expand_complex(self, deep=True, **hints): re_part, im_part = self.as_real_imag(deep=True, **hints) return re_part + S.ImaginaryUnit*im_part def _eval_expand_trig(self, **hints): return self._calculate_reciprocal("_eval_expand_trig", **hints) def _eval_as_leading_term(self, x, logx=None, cdir=0): return (1/self._reciprocal_of(self.args[0]))._eval_as_leading_term(x) def _eval_is_extended_real(self): return self._reciprocal_of(self.args[0]).is_extended_real def _eval_is_finite(self): return (1/self._reciprocal_of(self.args[0])).is_finite class csch(ReciprocalHyperbolicFunction): r""" csch(x) is the hyperbolic cosecant of x. The hyperbolic cosecant function is $\frac{2}{e^x - e^{-x}}$ Examples ======== >>> from sympy import csch >>> from sympy.abc import x >>> csch(x) csch(x) See Also ======== sinh, cosh, tanh, sech, asinh, acosh """ _reciprocal_of = sinh _is_odd = True def fdiff(self, argindex=1): """ Returns the first derivative of this function """ if argindex == 1: return -coth(self.args[0]) * csch(self.args[0]) else: raise ArgumentIndexError(self, argindex) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): """ Returns the next term in the Taylor series expansion """ from sympy import bernoulli if n == 0: return 1/sympify(x) elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) B = bernoulli(n + 1) F = factorial(n + 1) return 2 * (1 - 2**n) * B/F * x**n def _eval_rewrite_as_cosh(self, arg, **kwargs): return S.ImaginaryUnit / cosh(arg + S.ImaginaryUnit * S.Pi / 2) def _eval_is_positive(self): if self.args[0].is_extended_real: return self.args[0].is_positive def _eval_is_negative(self): if self.args[0].is_extended_real: return self.args[0].is_negative class sech(ReciprocalHyperbolicFunction): r""" sech(x) is the hyperbolic secant of x. The hyperbolic secant function is $\frac{2}{e^x + e^{-x}}$ Examples ======== >>> from sympy import sech >>> from sympy.abc import x >>> sech(x) sech(x) See Also ======== sinh, cosh, tanh, coth, csch, asinh, acosh """ _reciprocal_of = cosh _is_even = True def fdiff(self, argindex=1): if argindex == 1: return - tanh(self.args[0])*sech(self.args[0]) else: raise ArgumentIndexError(self, argindex) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): from sympy.functions.combinatorial.numbers import euler if n < 0 or n % 2 == 1: return S.Zero else: x = sympify(x) return euler(n) / factorial(n) * x**(n) def _eval_rewrite_as_sinh(self, arg, **kwargs): return S.ImaginaryUnit / sinh(arg + S.ImaginaryUnit * S.Pi /2) def _eval_is_positive(self): if self.args[0].is_extended_real: return True ############################################################################### ############################# HYPERBOLIC INVERSES ############################# ############################################################################### class InverseHyperbolicFunction(Function): """Base class for inverse hyperbolic functions.""" pass class asinh(InverseHyperbolicFunction): """ asinh(x) is the inverse hyperbolic sine of x. The inverse hyperbolic sine function. Examples ======== >>> from sympy import asinh >>> from sympy.abc import x >>> asinh(x).diff(x) 1/sqrt(x**2 + 1) >>> asinh(1) log(1 + sqrt(2)) See Also ======== acosh, atanh, sinh """ def fdiff(self, argindex=1): if argindex == 1: return 1/sqrt(self.args[0]**2 + 1) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): from sympy import asin arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.NegativeInfinity elif arg.is_zero: return S.Zero elif arg is S.One: return log(sqrt(2) + 1) elif arg is S.NegativeOne: return log(sqrt(2) - 1) elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.ComplexInfinity if arg.is_zero: return S.Zero i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit * asin(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if isinstance(arg, sinh) and arg.args[0].is_number: z = arg.args[0] if z.is_real: return z r, i = match_real_imag(z) if r is not None and i is not None: f = floor((i + pi/2)/pi) m = z - I*pi*f even = f.is_even if even is True: return m elif even is False: return -m @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] return -p * (n - 2)**2/(n*(n - 1)) * x**2 else: k = (n - 1) // 2 R = RisingFactorial(S.Half, k) F = factorial(k) return (-1)**k * R / F * x**n / n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order arg = self.args[0].as_leading_term(x) if x in arg.free_symbols and Order(1, x).contains(arg): return arg else: return self.func(arg) def _eval_rewrite_as_log(self, x, **kwargs): return log(x + sqrt(x**2 + 1)) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return sinh def _eval_is_zero(self): arg = self.args[0] if arg.is_zero: return True class acosh(InverseHyperbolicFunction): """ acosh(x) is the inverse hyperbolic cosine of x. The inverse hyperbolic cosine function. Examples ======== >>> from sympy import acosh >>> from sympy.abc import x >>> acosh(x).diff(x) 1/sqrt(x**2 - 1) >>> acosh(1) 0 See Also ======== asinh, atanh, cosh """ def fdiff(self, argindex=1): if argindex == 1: return 1/sqrt(self.args[0]**2 - 1) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Infinity elif arg.is_zero: return S.Pi*S.ImaginaryUnit / 2 elif arg is S.One: return S.Zero elif arg is S.NegativeOne: return S.Pi*S.ImaginaryUnit if arg.is_number: cst_table = { S.ImaginaryUnit: log(S.ImaginaryUnit*(1 + sqrt(2))), -S.ImaginaryUnit: log(-S.ImaginaryUnit*(1 + sqrt(2))), S.Half: S.Pi/3, Rational(-1, 2): S.Pi*Rational(2, 3), sqrt(2)/2: S.Pi/4, -sqrt(2)/2: S.Pi*Rational(3, 4), 1/sqrt(2): S.Pi/4, -1/sqrt(2): S.Pi*Rational(3, 4), sqrt(3)/2: S.Pi/6, -sqrt(3)/2: S.Pi*Rational(5, 6), (sqrt(3) - 1)/sqrt(2**3): S.Pi*Rational(5, 12), -(sqrt(3) - 1)/sqrt(2**3): S.Pi*Rational(7, 12), sqrt(2 + sqrt(2))/2: S.Pi/8, -sqrt(2 + sqrt(2))/2: S.Pi*Rational(7, 8), sqrt(2 - sqrt(2))/2: S.Pi*Rational(3, 8), -sqrt(2 - sqrt(2))/2: S.Pi*Rational(5, 8), (1 + sqrt(3))/(2*sqrt(2)): S.Pi/12, -(1 + sqrt(3))/(2*sqrt(2)): S.Pi*Rational(11, 12), (sqrt(5) + 1)/4: S.Pi/5, -(sqrt(5) + 1)/4: S.Pi*Rational(4, 5) } if arg in cst_table: if arg.is_extended_real: return cst_table[arg]*S.ImaginaryUnit return cst_table[arg] if arg is S.ComplexInfinity: return S.ComplexInfinity if arg == S.ImaginaryUnit*S.Infinity: return S.Infinity + S.ImaginaryUnit*S.Pi/2 if arg == -S.ImaginaryUnit*S.Infinity: return S.Infinity - S.ImaginaryUnit*S.Pi/2 if arg.is_zero: return S.Pi*S.ImaginaryUnit*S.Half if isinstance(arg, cosh) and arg.args[0].is_number: z = arg.args[0] if z.is_real: from sympy.functions.elementary.complexes import Abs return Abs(z) r, i = match_real_imag(z) if r is not None and i is not None: f = floor(i/pi) m = z - I*pi*f even = f.is_even if even is True: if r.is_nonnegative: return m elif r.is_negative: return -m elif even is False: m -= I*pi if r.is_nonpositive: return -m elif r.is_positive: return m @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n == 0: return S.Pi*S.ImaginaryUnit / 2 elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] return p * (n - 2)**2/(n*(n - 1)) * x**2 else: k = (n - 1) // 2 R = RisingFactorial(S.Half, k) F = factorial(k) return -R / F * S.ImaginaryUnit * x**n / n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order arg = self.args[0].as_leading_term(x) if x in arg.free_symbols and Order(1, x).contains(arg): return S.ImaginaryUnit*S.Pi/2 else: return self.func(arg) def _eval_rewrite_as_log(self, x, **kwargs): return log(x + sqrt(x + 1) * sqrt(x - 1)) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return cosh class atanh(InverseHyperbolicFunction): """ atanh(x) is the inverse hyperbolic tangent of x. The inverse hyperbolic tangent function. Examples ======== >>> from sympy import atanh >>> from sympy.abc import x >>> atanh(x).diff(x) 1/(1 - x**2) See Also ======== asinh, acosh, tanh """ def fdiff(self, argindex=1): if argindex == 1: return 1/(1 - self.args[0]**2) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): from sympy import atan arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg.is_zero: return S.Zero elif arg is S.One: return S.Infinity elif arg is S.NegativeOne: return S.NegativeInfinity elif arg is S.Infinity: return -S.ImaginaryUnit * atan(arg) elif arg is S.NegativeInfinity: return S.ImaginaryUnit * atan(-arg) elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: from sympy.calculus.util import AccumBounds return S.ImaginaryUnit*AccumBounds(-S.Pi/2, S.Pi/2) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit * atan(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.is_zero: return S.Zero if isinstance(arg, tanh) and arg.args[0].is_number: z = arg.args[0] if z.is_real: return z r, i = match_real_imag(z) if r is not None and i is not None: f = floor(2*i/pi) even = f.is_even m = z - I*f*pi/2 if even is True: return m elif even is False: return m - I*pi/2 @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) return x**n / n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order arg = self.args[0].as_leading_term(x) if x in arg.free_symbols and Order(1, x).contains(arg): return arg else: return self.func(arg) def _eval_rewrite_as_log(self, x, **kwargs): return (log(1 + x) - log(1 - x)) / 2 def _eval_is_zero(self): arg = self.args[0] if arg.is_zero: return True def inverse(self, argindex=1): """ Returns the inverse of this function. """ return tanh class acoth(InverseHyperbolicFunction): """ acoth(x) is the inverse hyperbolic cotangent of x. The inverse hyperbolic cotangent function. Examples ======== >>> from sympy import acoth >>> from sympy.abc import x >>> acoth(x).diff(x) 1/(1 - x**2) See Also ======== asinh, acosh, coth """ def fdiff(self, argindex=1): if argindex == 1: return 1/(1 - self.args[0]**2) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): from sympy import acot arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero elif arg is S.NegativeInfinity: return S.Zero elif arg.is_zero: return S.Pi*S.ImaginaryUnit / 2 elif arg is S.One: return S.Infinity elif arg is S.NegativeOne: return S.NegativeInfinity elif arg.is_negative: return -cls(-arg) else: if arg is S.ComplexInfinity: return S.Zero i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return -S.ImaginaryUnit * acot(i_coeff) else: if _coeff_isneg(arg): return -cls(-arg) if arg.is_zero: return S.Pi*S.ImaginaryUnit*S.Half @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n == 0: return S.Pi*S.ImaginaryUnit / 2 elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) return x**n / n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order arg = self.args[0].as_leading_term(x) if x in arg.free_symbols and Order(1, x).contains(arg): return S.ImaginaryUnit*S.Pi/2 else: return self.func(arg) def _eval_rewrite_as_log(self, x, **kwargs): return (log(1 + 1/x) - log(1 - 1/x)) / 2 def inverse(self, argindex=1): """ Returns the inverse of this function. """ return coth class asech(InverseHyperbolicFunction): """ asech(x) is the inverse hyperbolic secant of x. The inverse hyperbolic secant function. Examples ======== >>> from sympy import asech, sqrt, S >>> from sympy.abc import x >>> asech(x).diff(x) -1/(x*sqrt(1 - x**2)) >>> asech(1).diff(x) 0 >>> asech(1) 0 >>> asech(S(2)) I*pi/3 >>> asech(-sqrt(2)) 3*I*pi/4 >>> asech((sqrt(6) - sqrt(2))) I*pi/12 See Also ======== asinh, atanh, cosh, acoth References ========== .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function .. [2] http://dlmf.nist.gov/4.37 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcSech/ """ def fdiff(self, argindex=1): if argindex == 1: z = self.args[0] return -1/(z*sqrt(1 - z**2)) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Pi*S.ImaginaryUnit / 2 elif arg is S.NegativeInfinity: return S.Pi*S.ImaginaryUnit / 2 elif arg.is_zero: return S.Infinity elif arg is S.One: return S.Zero elif arg is S.NegativeOne: return S.Pi*S.ImaginaryUnit if arg.is_number: cst_table = { S.ImaginaryUnit: - (S.Pi*S.ImaginaryUnit / 2) + log(1 + sqrt(2)), -S.ImaginaryUnit: (S.Pi*S.ImaginaryUnit / 2) + log(1 + sqrt(2)), (sqrt(6) - sqrt(2)): S.Pi / 12, (sqrt(2) - sqrt(6)): 11*S.Pi / 12, sqrt(2 - 2/sqrt(5)): S.Pi / 10, -sqrt(2 - 2/sqrt(5)): 9*S.Pi / 10, 2 / sqrt(2 + sqrt(2)): S.Pi / 8, -2 / sqrt(2 + sqrt(2)): 7*S.Pi / 8, 2 / sqrt(3): S.Pi / 6, -2 / sqrt(3): 5*S.Pi / 6, (sqrt(5) - 1): S.Pi / 5, (1 - sqrt(5)): 4*S.Pi / 5, sqrt(2): S.Pi / 4, -sqrt(2): 3*S.Pi / 4, sqrt(2 + 2/sqrt(5)): 3*S.Pi / 10, -sqrt(2 + 2/sqrt(5)): 7*S.Pi / 10, S(2): S.Pi / 3, -S(2): 2*S.Pi / 3, sqrt(2*(2 + sqrt(2))): 3*S.Pi / 8, -sqrt(2*(2 + sqrt(2))): 5*S.Pi / 8, (1 + sqrt(5)): 2*S.Pi / 5, (-1 - sqrt(5)): 3*S.Pi / 5, (sqrt(6) + sqrt(2)): 5*S.Pi / 12, (-sqrt(6) - sqrt(2)): 7*S.Pi / 12, } if arg in cst_table: if arg.is_extended_real: return cst_table[arg]*S.ImaginaryUnit return cst_table[arg] if arg is S.ComplexInfinity: from sympy.calculus.util import AccumBounds return S.ImaginaryUnit*AccumBounds(-S.Pi/2, S.Pi/2) if arg.is_zero: return S.Infinity @staticmethod @cacheit def expansion_term(n, x, *previous_terms): if n == 0: return log(2 / x) elif n < 0 or n % 2 == 1: return S.Zero else: x = sympify(x) if len(previous_terms) > 2 and n > 2: p = previous_terms[-2] return p * (n - 1)**2 // (n // 2)**2 * x**2 / 4 else: k = n // 2 R = RisingFactorial(S.Half , k) * n F = factorial(k) * n // 2 * n // 2 return -1 * R / F * x**n / 4 def inverse(self, argindex=1): """ Returns the inverse of this function. """ return sech def _eval_rewrite_as_log(self, arg, **kwargs): return log(1/arg + sqrt(1/arg - 1) * sqrt(1/arg + 1)) class acsch(InverseHyperbolicFunction): """ acsch(x) is the inverse hyperbolic cosecant of x. The inverse hyperbolic cosecant function. Examples ======== >>> from sympy import acsch, sqrt, S >>> from sympy.abc import x >>> acsch(x).diff(x) -1/(x**2*sqrt(1 + x**(-2))) >>> acsch(1).diff(x) 0 >>> acsch(1) log(1 + sqrt(2)) >>> acsch(S.ImaginaryUnit) -I*pi/2 >>> acsch(-2*S.ImaginaryUnit) I*pi/6 >>> acsch(S.ImaginaryUnit*(sqrt(6) - sqrt(2))) -5*I*pi/12 See Also ======== asinh References ========== .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function .. [2] http://dlmf.nist.gov/4.37 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcCsch/ """ def fdiff(self, argindex=1): if argindex == 1: z = self.args[0] return -1/(z**2*sqrt(1 + 1/z**2)) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): arg = sympify(arg) if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero elif arg is S.NegativeInfinity: return S.Zero elif arg.is_zero: return S.ComplexInfinity elif arg is S.One: return log(1 + sqrt(2)) elif arg is S.NegativeOne: return - log(1 + sqrt(2)) if arg.is_number: cst_table = { S.ImaginaryUnit: -S.Pi / 2, S.ImaginaryUnit*(sqrt(2) + sqrt(6)): -S.Pi / 12, S.ImaginaryUnit*(1 + sqrt(5)): -S.Pi / 10, S.ImaginaryUnit*2 / sqrt(2 - sqrt(2)): -S.Pi / 8, S.ImaginaryUnit*2: -S.Pi / 6, S.ImaginaryUnit*sqrt(2 + 2/sqrt(5)): -S.Pi / 5, S.ImaginaryUnit*sqrt(2): -S.Pi / 4, S.ImaginaryUnit*(sqrt(5)-1): -3*S.Pi / 10, S.ImaginaryUnit*2 / sqrt(3): -S.Pi / 3, S.ImaginaryUnit*2 / sqrt(2 + sqrt(2)): -3*S.Pi / 8, S.ImaginaryUnit*sqrt(2 - 2/sqrt(5)): -2*S.Pi / 5, S.ImaginaryUnit*(sqrt(6) - sqrt(2)): -5*S.Pi / 12, S(2): -S.ImaginaryUnit*log((1+sqrt(5))/2), } if arg in cst_table: return cst_table[arg]*S.ImaginaryUnit if arg is S.ComplexInfinity: return S.Zero if arg.is_zero: return S.ComplexInfinity if _coeff_isneg(arg): return -cls(-arg) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return csch def _eval_rewrite_as_log(self, arg, **kwargs): return log(1/arg + sqrt(1/arg**2 + 1)) sympy-sympy-1.9/sympy/functions/elementary/integers.py000066400000000000000000000417511412543434000234630ustar00rootroot00000000000000from sympy import Basic, Expr from sympy.core import Add, S from sympy.core.evalf import get_integer_part, PrecisionExhausted from sympy.core.function import Function from sympy.core.logic import fuzzy_or from sympy.core.numbers import Integer from sympy.core.relational import Gt, Lt, Ge, Le, Relational, is_eq from sympy.core.symbol import Symbol from sympy.core.sympify import _sympify from sympy.multipledispatch import dispatch ############################################################################### ######################### FLOOR and CEILING FUNCTIONS ######################### ############################################################################### class RoundFunction(Function): """The base class for rounding functions.""" @classmethod def eval(cls, arg): from sympy import im v = cls._eval_number(arg) if v is not None: return v if arg.is_integer or arg.is_finite is False: return arg if arg.is_imaginary or (S.ImaginaryUnit*arg).is_real: i = im(arg) if not i.has(S.ImaginaryUnit): return cls(i)*S.ImaginaryUnit return cls(arg, evaluate=False) # Integral, numerical, symbolic part ipart = npart = spart = S.Zero # Extract integral (or complex integral) terms terms = Add.make_args(arg) for t in terms: if t.is_integer or (t.is_imaginary and im(t).is_integer): ipart += t elif t.has(Symbol): spart += t else: npart += t if not (npart or spart): return ipart # Evaluate npart numerically if independent of spart if npart and ( not spart or npart.is_real and (spart.is_imaginary or (S.ImaginaryUnit*spart).is_real) or npart.is_imaginary and spart.is_real): try: r, i = get_integer_part( npart, cls._dir, {}, return_ints=True) ipart += Integer(r) + Integer(i)*S.ImaginaryUnit npart = S.Zero except (PrecisionExhausted, NotImplementedError): pass spart += npart if not spart: return ipart elif spart.is_imaginary or (S.ImaginaryUnit*spart).is_real: return ipart + cls(im(spart), evaluate=False)*S.ImaginaryUnit elif isinstance(spart, (floor, ceiling)): return ipart + spart else: return ipart + cls(spart, evaluate=False) def _eval_is_finite(self): return self.args[0].is_finite def _eval_is_real(self): return self.args[0].is_real def _eval_is_integer(self): return self.args[0].is_real class floor(RoundFunction): """ Floor is a univariate function which returns the largest integer value not greater than its argument. This implementation generalizes floor to complex numbers by taking the floor of the real and imaginary parts separately. Examples ======== >>> from sympy import floor, E, I, S, Float, Rational >>> floor(17) 17 >>> floor(Rational(23, 10)) 2 >>> floor(2*E) 5 >>> floor(-Float(0.567)) -1 >>> floor(-I/2) -I >>> floor(S(5)/2 + 5*I/2) 2 + 2*I See Also ======== sympy.functions.elementary.integers.ceiling References ========== .. [1] "Concrete mathematics" by Graham, pp. 87 .. [2] http://mathworld.wolfram.com/FloorFunction.html """ _dir = -1 @classmethod def _eval_number(cls, arg): if arg.is_Number: return arg.floor() elif any(isinstance(i, j) for i in (arg, -arg) for j in (floor, ceiling)): return arg if arg.is_NumberSymbol: return arg.approximation_interval(Integer)[0] def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0] arg0 = arg.subs(x, 0) r = self.subs(x, 0) if arg0.is_finite: if arg0 == r: if cdir == 0: ndirl = arg.dir(x, cdir=-1) ndir = arg.dir(x, cdir=1) if ndir != ndirl: raise ValueError("Two sided limit of %s around 0" "does not exist" % self) else: ndir = arg.dir(x, cdir=cdir) return r - 1 if ndir.is_negative else r else: return r return arg.as_leading_term(x, logx=logx, cdir=cdir) def _eval_nseries(self, x, n, logx, cdir=0): arg = self.args[0] arg0 = arg.subs(x, 0) if arg0.is_infinite: from sympy.calculus.util import AccumBounds from sympy.series.order import Order s = arg._eval_nseries(x, n, logx, cdir) o = Order(1, (x, 0)) if n <= 0 else AccumBounds(-1, 0) return s + o r = self.subs(x, 0) if arg0 == r: ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1) return r - 1 if ndir.is_negative else r else: return r def _eval_is_negative(self): return self.args[0].is_negative def _eval_is_nonnegative(self): return self.args[0].is_nonnegative def _eval_rewrite_as_ceiling(self, arg, **kwargs): return -ceiling(-arg) def _eval_rewrite_as_frac(self, arg, **kwargs): return arg - frac(arg) def __le__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] < other + 1 if other.is_number and other.is_real: return self.args[0] < ceiling(other) if self.args[0] == other and other.is_real: return S.true if other is S.Infinity and self.is_finite: return S.true return Le(self, other, evaluate=False) def __ge__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] >= other if other.is_number and other.is_real: return self.args[0] >= ceiling(other) if self.args[0] == other and other.is_real: return S.false if other is S.NegativeInfinity and self.is_finite: return S.true return Ge(self, other, evaluate=False) def __gt__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] >= other + 1 if other.is_number and other.is_real: return self.args[0] >= ceiling(other) if self.args[0] == other and other.is_real: return S.false if other is S.NegativeInfinity and self.is_finite: return S.true return Gt(self, other, evaluate=False) def __lt__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] < other if other.is_number and other.is_real: return self.args[0] < ceiling(other) if self.args[0] == other and other.is_real: return S.false if other is S.Infinity and self.is_finite: return S.true return Lt(self, other, evaluate=False) @dispatch(floor, Expr) def _eval_is_eq(lhs, rhs): # noqa:F811 return is_eq(lhs.rewrite(ceiling), rhs) or \ is_eq(lhs.rewrite(frac),rhs) class ceiling(RoundFunction): """ Ceiling is a univariate function which returns the smallest integer value not less than its argument. This implementation generalizes ceiling to complex numbers by taking the ceiling of the real and imaginary parts separately. Examples ======== >>> from sympy import ceiling, E, I, S, Float, Rational >>> ceiling(17) 17 >>> ceiling(Rational(23, 10)) 3 >>> ceiling(2*E) 6 >>> ceiling(-Float(0.567)) 0 >>> ceiling(I/2) I >>> ceiling(S(5)/2 + 5*I/2) 3 + 3*I See Also ======== sympy.functions.elementary.integers.floor References ========== .. [1] "Concrete mathematics" by Graham, pp. 87 .. [2] http://mathworld.wolfram.com/CeilingFunction.html """ _dir = 1 @classmethod def _eval_number(cls, arg): if arg.is_Number: return arg.ceiling() elif any(isinstance(i, j) for i in (arg, -arg) for j in (floor, ceiling)): return arg if arg.is_NumberSymbol: return arg.approximation_interval(Integer)[1] def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0] arg0 = arg.subs(x, 0) r = self.subs(x, 0) if arg0.is_finite: if arg0 == r: if cdir == 0: ndirl = arg.dir(x, cdir=-1) ndir = arg.dir(x, cdir=1) if ndir != ndirl: raise ValueError("Two sided limit of %s around 0" "does not exist" % self) else: ndir = arg.dir(x, cdir=cdir) return r if ndir.is_negative else r + 1 else: return r return arg.as_leading_term(x, logx=logx, cdir=cdir) def _eval_nseries(self, x, n, logx, cdir=0): arg = self.args[0] arg0 = arg.subs(x, 0) if arg0.is_infinite: from sympy.calculus.util import AccumBounds from sympy.series.order import Order s = arg._eval_nseries(x, n, logx, cdir) o = Order(1, (x, 0)) if n <= 0 else AccumBounds(0, 1) return s + o r = self.subs(x, 0) if arg0 == r: ndir = arg.dir(x, cdir=cdir if cdir != 0 else 1) return r if ndir.is_negative else r + 1 else: return r def _eval_rewrite_as_floor(self, arg, **kwargs): return -floor(-arg) def _eval_rewrite_as_frac(self, arg, **kwargs): return arg + frac(-arg) def _eval_is_positive(self): return self.args[0].is_positive def _eval_is_nonpositive(self): return self.args[0].is_nonpositive def __lt__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] <= other - 1 if other.is_number and other.is_real: return self.args[0] <= floor(other) if self.args[0] == other and other.is_real: return S.false if other is S.Infinity and self.is_finite: return S.true return Lt(self, other, evaluate=False) def __gt__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] > other if other.is_number and other.is_real: return self.args[0] > floor(other) if self.args[0] == other and other.is_real: return S.false if other is S.NegativeInfinity and self.is_finite: return S.true return Gt(self, other, evaluate=False) def __ge__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] > other - 1 if other.is_number and other.is_real: return self.args[0] > floor(other) if self.args[0] == other and other.is_real: return S.true if other is S.NegativeInfinity and self.is_finite: return S.true return Ge(self, other, evaluate=False) def __le__(self, other): other = S(other) if self.args[0].is_real: if other.is_integer: return self.args[0] <= other if other.is_number and other.is_real: return self.args[0] <= floor(other) if self.args[0] == other and other.is_real: return S.false if other is S.Infinity and self.is_finite: return S.true return Le(self, other, evaluate=False) @dispatch(ceiling, Basic) # type:ignore def _eval_is_eq(lhs, rhs): # noqa:F811 return is_eq(lhs.rewrite(floor), rhs) or is_eq(lhs.rewrite(frac),rhs) class frac(Function): r"""Represents the fractional part of x For real numbers it is defined [1]_ as .. math:: x - \left\lfloor{x}\right\rfloor Examples ======== >>> from sympy import Symbol, frac, Rational, floor, I >>> frac(Rational(4, 3)) 1/3 >>> frac(-Rational(4, 3)) 2/3 returns zero for integer arguments >>> n = Symbol('n', integer=True) >>> frac(n) 0 rewrite as floor >>> x = Symbol('x') >>> frac(x).rewrite(floor) x - floor(x) for complex arguments >>> r = Symbol('r', real=True) >>> t = Symbol('t', real=True) >>> frac(t + I*r) I*frac(r) + frac(t) See Also ======== sympy.functions.elementary.integers.floor sympy.functions.elementary.integers.ceiling References =========== .. [1] https://en.wikipedia.org/wiki/Fractional_part .. [2] http://mathworld.wolfram.com/FractionalPart.html """ @classmethod def eval(cls, arg): from sympy import AccumBounds, im def _eval(arg): if arg is S.Infinity or arg is S.NegativeInfinity: return AccumBounds(0, 1) if arg.is_integer: return S.Zero if arg.is_number: if arg is S.NaN: return S.NaN elif arg is S.ComplexInfinity: return S.NaN else: return arg - floor(arg) return cls(arg, evaluate=False) terms = Add.make_args(arg) real, imag = S.Zero, S.Zero for t in terms: # Two checks are needed for complex arguments # see issue-7649 for details if t.is_imaginary or (S.ImaginaryUnit*t).is_real: i = im(t) if not i.has(S.ImaginaryUnit): imag += i else: real += t else: real += t real = _eval(real) imag = _eval(imag) return real + S.ImaginaryUnit*imag def _eval_rewrite_as_floor(self, arg, **kwargs): return arg - floor(arg) def _eval_rewrite_as_ceiling(self, arg, **kwargs): return arg + ceiling(-arg) def _eval_is_finite(self): return True def _eval_is_real(self): return self.args[0].is_extended_real def _eval_is_imaginary(self): return self.args[0].is_imaginary def _eval_is_integer(self): return self.args[0].is_integer def _eval_is_zero(self): return fuzzy_or([self.args[0].is_zero, self.args[0].is_integer]) def _eval_is_negative(self): return False def __ge__(self, other): if self.is_extended_real: other = _sympify(other) # Check if other <= 0 if other.is_extended_nonpositive: return S.true # Check if other >= 1 res = self._value_one_or_more(other) if res is not None: return not(res) return Ge(self, other, evaluate=False) def __gt__(self, other): if self.is_extended_real: other = _sympify(other) # Check if other < 0 res = self._value_one_or_more(other) if res is not None: return not(res) # Check if other >= 1 if other.is_extended_negative: return S.true return Gt(self, other, evaluate=False) def __le__(self, other): if self.is_extended_real: other = _sympify(other) # Check if other < 0 if other.is_extended_negative: return S.false # Check if other >= 1 res = self._value_one_or_more(other) if res is not None: return res return Le(self, other, evaluate=False) def __lt__(self, other): if self.is_extended_real: other = _sympify(other) # Check if other <= 0 if other.is_extended_nonpositive: return S.false # Check if other >= 1 res = self._value_one_or_more(other) if res is not None: return res return Lt(self, other, evaluate=False) def _value_one_or_more(self, other): if other.is_extended_real: if other.is_number: res = other >= 1 if res and not isinstance(res, Relational): return S.true if other.is_integer and other.is_positive: return S.true @dispatch(frac, Basic) # type:ignore def _eval_is_eq(lhs, rhs): # noqa:F811 if (lhs.rewrite(floor) == rhs) or \ (lhs.rewrite(ceiling) == rhs): return True # Check if other < 0 if rhs.is_extended_negative: return False # Check if other >= 1 res = lhs._value_one_or_more(rhs) if res is not None: return False sympy-sympy-1.9/sympy/functions/elementary/miscellaneous.py000066400000000000000000000640601412543434000245040ustar00rootroot00000000000000from sympy.core import Function, S, sympify from sympy.utilities.iterables import sift from sympy.core.add import Add from sympy.core.containers import Tuple from sympy.core.compatibility import ordered from sympy.core.operations import LatticeOp, ShortCircuit from sympy.core.function import (Application, Lambda, ArgumentIndexError) from sympy.core.expr import Expr from sympy.core.mod import Mod from sympy.core.mul import Mul from sympy.core.numbers import Rational from sympy.core.power import Pow from sympy.core.relational import Eq, Relational from sympy.core.singleton import Singleton from sympy.core.symbol import Dummy from sympy.core.rules import Transform from sympy.core.logic import fuzzy_and, fuzzy_or, _torf from sympy.logic.boolalg import And, Or def _minmax_as_Piecewise(op, *args): # helper for Min/Max rewrite as Piecewise from sympy.functions.elementary.piecewise import Piecewise ec = [] for i, a in enumerate(args): c = [] for j in range(i + 1, len(args)): c.append(Relational(a, args[j], op)) ec.append((a, And(*c))) return Piecewise(*ec) class IdentityFunction(Lambda, metaclass=Singleton): """ The identity function Examples ======== >>> from sympy import Id, Symbol >>> x = Symbol('x') >>> Id(x) x """ _symbol = Dummy('x') @property def signature(self): return Tuple(self._symbol) @property def expr(self): return self._symbol Id = S.IdentityFunction ############################################################################### ############################# ROOT and SQUARE ROOT FUNCTION ################### ############################################################################### def sqrt(arg, evaluate=None): """Returns the principal square root. Parameters ========== evaluate : bool, optional The parameter determines if the expression should be evaluated. If ``None``, its value is taken from ``global_parameters.evaluate``. Examples ======== >>> from sympy import sqrt, Symbol, S >>> x = Symbol('x') >>> sqrt(x) sqrt(x) >>> sqrt(x)**2 x Note that sqrt(x**2) does not simplify to x. >>> sqrt(x**2) sqrt(x**2) This is because the two are not equal to each other in general. For example, consider x == -1: >>> from sympy import Eq >>> Eq(sqrt(x**2), x).subs(x, -1) False This is because sqrt computes the principal square root, so the square may put the argument in a different branch. This identity does hold if x is positive: >>> y = Symbol('y', positive=True) >>> sqrt(y**2) y You can force this simplification by using the powdenest() function with the force option set to True: >>> from sympy import powdenest >>> sqrt(x**2) sqrt(x**2) >>> powdenest(sqrt(x**2), force=True) x To get both branches of the square root you can use the rootof function: >>> from sympy import rootof >>> [rootof(x**2-3,i) for i in (0,1)] [-sqrt(3), sqrt(3)] Although ``sqrt`` is printed, there is no ``sqrt`` function so looking for ``sqrt`` in an expression will fail: >>> from sympy.utilities.misc import func_name >>> func_name(sqrt(x)) 'Pow' >>> sqrt(x).has(sqrt) Traceback (most recent call last): ... sympy.core.sympify.SympifyError: SympifyError: To find ``sqrt`` look for ``Pow`` with an exponent of ``1/2``: >>> (x + 1/sqrt(x)).find(lambda i: i.is_Pow and abs(i.exp) is S.Half) {1/sqrt(x)} See Also ======== sympy.polys.rootoftools.rootof, root, real_root References ========== .. [1] https://en.wikipedia.org/wiki/Square_root .. [2] https://en.wikipedia.org/wiki/Principal_value """ # arg = sympify(arg) is handled by Pow return Pow(arg, S.Half, evaluate=evaluate) def cbrt(arg, evaluate=None): """Returns the principal cube root. Parameters ========== evaluate : bool, optional The parameter determines if the expression should be evaluated. If ``None``, its value is taken from ``global_parameters.evaluate``. Examples ======== >>> from sympy import cbrt, Symbol >>> x = Symbol('x') >>> cbrt(x) x**(1/3) >>> cbrt(x)**3 x Note that cbrt(x**3) does not simplify to x. >>> cbrt(x**3) (x**3)**(1/3) This is because the two are not equal to each other in general. For example, consider `x == -1`: >>> from sympy import Eq >>> Eq(cbrt(x**3), x).subs(x, -1) False This is because cbrt computes the principal cube root, this identity does hold if `x` is positive: >>> y = Symbol('y', positive=True) >>> cbrt(y**3) y See Also ======== sympy.polys.rootoftools.rootof, root, real_root References ========== * https://en.wikipedia.org/wiki/Cube_root * https://en.wikipedia.org/wiki/Principal_value """ return Pow(arg, Rational(1, 3), evaluate=evaluate) def root(arg, n, k=0, evaluate=None): r"""Returns the *k*-th *n*-th root of ``arg``. Parameters ========== k : int, optional Should be an integer in $\{0, 1, ..., n-1\}$. Defaults to the principal root if $0$. evaluate : bool, optional The parameter determines if the expression should be evaluated. If ``None``, its value is taken from ``global_parameters.evaluate``. Examples ======== >>> from sympy import root, Rational >>> from sympy.abc import x, n >>> root(x, 2) sqrt(x) >>> root(x, 3) x**(1/3) >>> root(x, n) x**(1/n) >>> root(x, -Rational(2, 3)) x**(-3/2) To get the k-th n-th root, specify k: >>> root(-2, 3, 2) -(-1)**(2/3)*2**(1/3) To get all n n-th roots you can use the rootof function. The following examples show the roots of unity for n equal 2, 3 and 4: >>> from sympy import rootof >>> [rootof(x**2 - 1, i) for i in range(2)] [-1, 1] >>> [rootof(x**3 - 1,i) for i in range(3)] [1, -1/2 - sqrt(3)*I/2, -1/2 + sqrt(3)*I/2] >>> [rootof(x**4 - 1,i) for i in range(4)] [-1, 1, -I, I] SymPy, like other symbolic algebra systems, returns the complex root of negative numbers. This is the principal root and differs from the text-book result that one might be expecting. For example, the cube root of -8 does not come back as -2: >>> root(-8, 3) 2*(-1)**(1/3) The real_root function can be used to either make the principal result real (or simply to return the real root directly): >>> from sympy import real_root >>> real_root(_) -2 >>> real_root(-32, 5) -2 Alternatively, the n//2-th n-th root of a negative number can be computed with root: >>> root(-32, 5, 5//2) -2 See Also ======== sympy.polys.rootoftools.rootof sympy.core.power.integer_nthroot sqrt, real_root References ========== * https://en.wikipedia.org/wiki/Square_root * https://en.wikipedia.org/wiki/Real_root * https://en.wikipedia.org/wiki/Root_of_unity * https://en.wikipedia.org/wiki/Principal_value * http://mathworld.wolfram.com/CubeRoot.html """ n = sympify(n) if k: return Mul(Pow(arg, S.One/n, evaluate=evaluate), S.NegativeOne**(2*k/n), evaluate=evaluate) return Pow(arg, 1/n, evaluate=evaluate) def real_root(arg, n=None, evaluate=None): """Return the real *n*'th-root of *arg* if possible. Parameters ========== n : int or None, optional If *n* is ``None``, then all instances of ``(-n)**(1/odd)`` will be changed to ``-n**(1/odd)``. This will only create a real root of a principal root. The presence of other factors may cause the result to not be real. evaluate : bool, optional The parameter determines if the expression should be evaluated. If ``None``, its value is taken from ``global_parameters.evaluate``. Examples ======== >>> from sympy import root, real_root >>> real_root(-8, 3) -2 >>> root(-8, 3) 2*(-1)**(1/3) >>> real_root(_) -2 If one creates a non-principal root and applies real_root, the result will not be real (so use with caution): >>> root(-8, 3, 2) -2*(-1)**(2/3) >>> real_root(_) -2*(-1)**(2/3) See Also ======== sympy.polys.rootoftools.rootof sympy.core.power.integer_nthroot root, sqrt """ from sympy.functions.elementary.complexes import Abs, im, sign from sympy.functions.elementary.piecewise import Piecewise if n is not None: return Piecewise( (root(arg, n, evaluate=evaluate), Or(Eq(n, S.One), Eq(n, S.NegativeOne))), (Mul(sign(arg), root(Abs(arg), n, evaluate=evaluate), evaluate=evaluate), And(Eq(im(arg), S.Zero), Eq(Mod(n, 2), S.One))), (root(arg, n, evaluate=evaluate), True)) rv = sympify(arg) n1pow = Transform(lambda x: -(-x.base)**x.exp, lambda x: x.is_Pow and x.base.is_negative and x.exp.is_Rational and x.exp.p == 1 and x.exp.q % 2) return rv.xreplace(n1pow) ############################################################################### ############################# MINIMUM and MAXIMUM ############################# ############################################################################### class MinMaxBase(Expr, LatticeOp): def __new__(cls, *args, **assumptions): evaluate = assumptions.pop('evaluate', True) args = (sympify(arg) for arg in args) # first standard filter, for cls.zero and cls.identity # also reshape Max(a, Max(b, c)) to Max(a, b, c) if evaluate: try: args = frozenset(cls._new_args_filter(args)) except ShortCircuit: return cls.zero else: args = frozenset(args) if evaluate: # remove redundant args that are easily identified args = cls._collapse_arguments(args, **assumptions) # find local zeros args = cls._find_localzeros(args, **assumptions) if not args: return cls.identity if len(args) == 1: return list(args).pop() # base creation _args = frozenset(args) obj = Expr.__new__(cls, *ordered(_args), **assumptions) obj._argset = _args return obj @classmethod def _collapse_arguments(cls, args, **assumptions): """Remove redundant args. Examples ======== >>> from sympy import Min, Max >>> from sympy.abc import a, b, c, d, e Any arg in parent that appears in any parent-like function in any of the flat args of parent can be removed from that sub-arg: >>> Min(a, Max(b, Min(a, c, d))) Min(a, Max(b, Min(c, d))) If the arg of parent appears in an opposite-than parent function in any of the flat args of parent that function can be replaced with the arg: >>> Min(a, Max(b, Min(c, d, Max(a, e)))) Min(a, Max(b, Min(a, c, d))) """ from sympy.utilities.iterables import ordered from sympy.simplify.simplify import walk if not args: return args args = list(ordered(args)) if cls == Min: other = Max else: other = Min # find global comparable max of Max and min of Min if a new # value is being introduced in these args at position 0 of # the ordered args if args[0].is_number: sifted = mins, maxs = [], [] for i in args: for v in walk(i, Min, Max): if v.args[0].is_comparable: sifted[isinstance(v, Max)].append(v) small = Min.identity for i in mins: v = i.args[0] if v.is_number and (v < small) == True: small = v big = Max.identity for i in maxs: v = i.args[0] if v.is_number and (v > big) == True: big = v # at the point when this function is called from __new__, # there may be more than one numeric arg present since # local zeros have not been handled yet, so look through # more than the first arg if cls == Min: for i in range(len(args)): if not args[i].is_number: break if (args[i] < small) == True: small = args[i] elif cls == Max: for i in range(len(args)): if not args[i].is_number: break if (args[i] > big) == True: big = args[i] T = None if cls == Min: if small != Min.identity: other = Max T = small elif big != Max.identity: other = Min T = big if T is not None: # remove numerical redundancy for i in range(len(args)): a = args[i] if isinstance(a, other): a0 = a.args[0] if ((a0 > T) if other == Max else (a0 < T)) == True: args[i] = cls.identity # remove redundant symbolic args def do(ai, a): if not isinstance(ai, (Min, Max)): return ai cond = a in ai.args if not cond: return ai.func(*[do(i, a) for i in ai.args], evaluate=False) if isinstance(ai, cls): return ai.func(*[do(i, a) for i in ai.args if i != a], evaluate=False) return a for i, a in enumerate(args): args[i + 1:] = [do(ai, a) for ai in args[i + 1:]] # factor out common elements as for # Min(Max(x, y), Max(x, z)) -> Max(x, Min(y, z)) # and vice versa when swapping Min/Max -- do this only for the # easy case where all functions contain something in common; # trying to find some optimal subset of args to modify takes # too long def factor_minmax(args): is_other = lambda arg: isinstance(arg, other) other_args, remaining_args = sift(args, is_other, binary=True) if not other_args: return args # Min(Max(x, y, z), Max(x, y, u, v)) -> {x,y}, ({z}, {u,v}) arg_sets = [set(arg.args) for arg in other_args] common = set.intersection(*arg_sets) if not common: return args new_other_args = list(common) arg_sets_diff = [arg_set - common for arg_set in arg_sets] # If any set is empty after removing common then all can be # discarded e.g. Min(Max(a, b, c), Max(a, b)) -> Max(a, b) if all(arg_sets_diff): other_args_diff = [other(*s, evaluate=False) for s in arg_sets_diff] new_other_args.append(cls(*other_args_diff, evaluate=False)) other_args_factored = other(*new_other_args, evaluate=False) return remaining_args + [other_args_factored] if len(args) > 1: args = factor_minmax(args) return args @classmethod def _new_args_filter(cls, arg_sequence): """ Generator filtering args. first standard filter, for cls.zero and cls.identity. Also reshape Max(a, Max(b, c)) to Max(a, b, c), and check arguments for comparability """ for arg in arg_sequence: # pre-filter, checking comparability of arguments if not isinstance(arg, Expr) or arg.is_extended_real is False or ( arg.is_number and not arg.is_comparable): raise ValueError("The argument '%s' is not comparable." % arg) if arg == cls.zero: raise ShortCircuit(arg) elif arg == cls.identity: continue elif arg.func == cls: yield from arg.args else: yield arg @classmethod def _find_localzeros(cls, values, **options): """ Sequentially allocate values to localzeros. When a value is identified as being more extreme than another member it replaces that member; if this is never true, then the value is simply appended to the localzeros. """ localzeros = set() for v in values: is_newzero = True localzeros_ = list(localzeros) for z in localzeros_: if id(v) == id(z): is_newzero = False else: con = cls._is_connected(v, z) if con: is_newzero = False if con is True or con == cls: localzeros.remove(z) localzeros.update([v]) if is_newzero: localzeros.update([v]) return localzeros @classmethod def _is_connected(cls, x, y): """ Check if x and y are connected somehow. """ from sympy.core.exprtools import factor_terms def hit(v, t, f): if not v.is_Relational: return t if v else f for i in range(2): if x == y: return True r = hit(x >= y, Max, Min) if r is not None: return r r = hit(y <= x, Max, Min) if r is not None: return r r = hit(x <= y, Min, Max) if r is not None: return r r = hit(y >= x, Min, Max) if r is not None: return r # simplification can be expensive, so be conservative # in what is attempted x = factor_terms(x - y) y = S.Zero return False def _eval_derivative(self, s): # f(x).diff(s) -> x.diff(s) * f.fdiff(1)(s) i = 0 l = [] for a in self.args: i += 1 da = a.diff(s) if da.is_zero: continue try: df = self.fdiff(i) except ArgumentIndexError: df = Function.fdiff(self, i) l.append(df * da) return Add(*l) def _eval_rewrite_as_Abs(self, *args, **kwargs): from sympy.functions.elementary.complexes import Abs s = (args[0] + self.func(*args[1:]))/2 d = abs(args[0] - self.func(*args[1:]))/2 return (s + d if isinstance(self, Max) else s - d).rewrite(Abs) def evalf(self, n=15, **options): return self.func(*[a.evalf(n, **options) for a in self.args]) def n(self, *args, **kwargs): return self.evalf(*args, **kwargs) _eval_is_algebraic = lambda s: _torf(i.is_algebraic for i in s.args) _eval_is_antihermitian = lambda s: _torf(i.is_antihermitian for i in s.args) _eval_is_commutative = lambda s: _torf(i.is_commutative for i in s.args) _eval_is_complex = lambda s: _torf(i.is_complex for i in s.args) _eval_is_composite = lambda s: _torf(i.is_composite for i in s.args) _eval_is_even = lambda s: _torf(i.is_even for i in s.args) _eval_is_finite = lambda s: _torf(i.is_finite for i in s.args) _eval_is_hermitian = lambda s: _torf(i.is_hermitian for i in s.args) _eval_is_imaginary = lambda s: _torf(i.is_imaginary for i in s.args) _eval_is_infinite = lambda s: _torf(i.is_infinite for i in s.args) _eval_is_integer = lambda s: _torf(i.is_integer for i in s.args) _eval_is_irrational = lambda s: _torf(i.is_irrational for i in s.args) _eval_is_negative = lambda s: _torf(i.is_negative for i in s.args) _eval_is_noninteger = lambda s: _torf(i.is_noninteger for i in s.args) _eval_is_nonnegative = lambda s: _torf(i.is_nonnegative for i in s.args) _eval_is_nonpositive = lambda s: _torf(i.is_nonpositive for i in s.args) _eval_is_nonzero = lambda s: _torf(i.is_nonzero for i in s.args) _eval_is_odd = lambda s: _torf(i.is_odd for i in s.args) _eval_is_polar = lambda s: _torf(i.is_polar for i in s.args) _eval_is_positive = lambda s: _torf(i.is_positive for i in s.args) _eval_is_prime = lambda s: _torf(i.is_prime for i in s.args) _eval_is_rational = lambda s: _torf(i.is_rational for i in s.args) _eval_is_real = lambda s: _torf(i.is_real for i in s.args) _eval_is_extended_real = lambda s: _torf(i.is_extended_real for i in s.args) _eval_is_transcendental = lambda s: _torf(i.is_transcendental for i in s.args) _eval_is_zero = lambda s: _torf(i.is_zero for i in s.args) class Max(MinMaxBase, Application): """ Return, if possible, the maximum value of the list. When number of arguments is equal one, then return this argument. When number of arguments is equal two, then return, if possible, the value from (a, b) that is >= the other. In common case, when the length of list greater than 2, the task is more complicated. Return only the arguments, which are greater than others, if it is possible to determine directional relation. If is not possible to determine such a relation, return a partially evaluated result. Assumptions are used to make the decision too. Also, only comparable arguments are permitted. It is named ``Max`` and not ``max`` to avoid conflicts with the built-in function ``max``. Examples ======== >>> from sympy import Max, Symbol, oo >>> from sympy.abc import x, y, z >>> p = Symbol('p', positive=True) >>> n = Symbol('n', negative=True) >>> Max(x, -2) Max(-2, x) >>> Max(x, -2).subs(x, 3) 3 >>> Max(p, -2) p >>> Max(x, y) Max(x, y) >>> Max(x, y) == Max(y, x) True >>> Max(x, Max(y, z)) Max(x, y, z) >>> Max(n, 8, p, 7, -oo) Max(8, p) >>> Max (1, x, oo) oo * Algorithm The task can be considered as searching of supremums in the directed complete partial orders [1]_. The source values are sequentially allocated by the isolated subsets in which supremums are searched and result as Max arguments. If the resulted supremum is single, then it is returned. The isolated subsets are the sets of values which are only the comparable with each other in the current set. E.g. natural numbers are comparable with each other, but not comparable with the `x` symbol. Another example: the symbol `x` with negative assumption is comparable with a natural number. Also there are "least" elements, which are comparable with all others, and have a zero property (maximum or minimum for all elements). E.g. `oo`. In case of it the allocation operation is terminated and only this value is returned. Assumption: - if A > B > C then A > C - if A == B then B can be removed References ========== .. [1] https://en.wikipedia.org/wiki/Directed_complete_partial_order .. [2] https://en.wikipedia.org/wiki/Lattice_%28order%29 See Also ======== Min : find minimum values """ zero = S.Infinity identity = S.NegativeInfinity def fdiff( self, argindex ): from sympy import Heaviside n = len(self.args) if 0 < argindex and argindex <= n: argindex -= 1 if n == 2: return Heaviside(self.args[argindex] - self.args[1 - argindex]) newargs = tuple([self.args[i] for i in range(n) if i != argindex]) return Heaviside(self.args[argindex] - Max(*newargs)) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_Heaviside(self, *args, **kwargs): from sympy import Heaviside return Add(*[j*Mul(*[Heaviside(j - i) for i in args if i!=j]) \ for j in args]) def _eval_rewrite_as_Piecewise(self, *args, **kwargs): return _minmax_as_Piecewise('>=', *args) def _eval_is_positive(self): return fuzzy_or(a.is_positive for a in self.args) def _eval_is_nonnegative(self): return fuzzy_or(a.is_nonnegative for a in self.args) def _eval_is_negative(self): return fuzzy_and(a.is_negative for a in self.args) class Min(MinMaxBase, Application): """ Return, if possible, the minimum value of the list. It is named ``Min`` and not ``min`` to avoid conflicts with the built-in function ``min``. Examples ======== >>> from sympy import Min, Symbol, oo >>> from sympy.abc import x, y >>> p = Symbol('p', positive=True) >>> n = Symbol('n', negative=True) >>> Min(x, -2) Min(-2, x) >>> Min(x, -2).subs(x, 3) -2 >>> Min(p, -3) -3 >>> Min(x, y) Min(x, y) >>> Min(n, 8, p, -7, p, oo) Min(-7, n) See Also ======== Max : find maximum values """ zero = S.NegativeInfinity identity = S.Infinity def fdiff( self, argindex ): from sympy import Heaviside n = len(self.args) if 0 < argindex and argindex <= n: argindex -= 1 if n == 2: return Heaviside( self.args[1-argindex] - self.args[argindex] ) newargs = tuple([ self.args[i] for i in range(n) if i != argindex]) return Heaviside( Min(*newargs) - self.args[argindex] ) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_Heaviside(self, *args, **kwargs): from sympy import Heaviside return Add(*[j*Mul(*[Heaviside(i-j) for i in args if i!=j]) \ for j in args]) def _eval_rewrite_as_Piecewise(self, *args, **kwargs): return _minmax_as_Piecewise('<=', *args) def _eval_is_positive(self): return fuzzy_and(a.is_positive for a in self.args) def _eval_is_nonnegative(self): return fuzzy_and(a.is_nonnegative for a in self.args) def _eval_is_negative(self): return fuzzy_or(a.is_negative for a in self.args) sympy-sympy-1.9/sympy/functions/elementary/piecewise.py000066400000000000000000001416711412543434000236220ustar00rootroot00000000000000from sympy.core import Basic, S, Function, diff, Tuple, Dummy from sympy.core.basic import as_Basic from sympy.core.numbers import Rational, NumberSymbol from sympy.core.relational import (Equality, Unequality, Relational, _canonical) from sympy.functions.elementary.miscellaneous import Max, Min from sympy.logic.boolalg import (And, Boolean, distribute_and_over_or, true, false, Or, ITE, simplify_logic) from sympy.utilities.iterables import uniq, ordered, product, sift from sympy.utilities.misc import filldedent, func_name Undefined = S.NaN # Piecewise() class ExprCondPair(Tuple): """Represents an expression, condition pair.""" def __new__(cls, expr, cond): expr = as_Basic(expr) if cond == True: return Tuple.__new__(cls, expr, true) elif cond == False: return Tuple.__new__(cls, expr, false) elif isinstance(cond, Basic) and cond.has(Piecewise): cond = piecewise_fold(cond) if isinstance(cond, Piecewise): cond = cond.rewrite(ITE) if not isinstance(cond, Boolean): raise TypeError(filldedent(''' Second argument must be a Boolean, not `%s`''' % func_name(cond))) return Tuple.__new__(cls, expr, cond) @property def expr(self): """ Returns the expression of this pair. """ return self.args[0] @property def cond(self): """ Returns the condition of this pair. """ return self.args[1] @property def is_commutative(self): return self.expr.is_commutative def __iter__(self): yield self.expr yield self.cond def _eval_simplify(self, **kwargs): return self.func(*[a.simplify(**kwargs) for a in self.args]) class Piecewise(Function): """ Represents a piecewise function. Usage: Piecewise( (expr,cond), (expr,cond), ... ) - Each argument is a 2-tuple defining an expression and condition - The conds are evaluated in turn returning the first that is True. If any of the evaluated conds are not determined explicitly False, e.g. x < 1, the function is returned in symbolic form. - If the function is evaluated at a place where all conditions are False, nan will be returned. - Pairs where the cond is explicitly False, will be removed. Examples ======== >>> from sympy import Piecewise, log, piecewise_fold >>> from sympy.abc import x, y >>> f = x**2 >>> g = log(x) >>> p = Piecewise((0, x < -1), (f, x <= 1), (g, True)) >>> p.subs(x,1) 1 >>> p.subs(x,5) log(5) Booleans can contain Piecewise elements: >>> cond = (x < y).subs(x, Piecewise((2, x < 0), (3, True))); cond Piecewise((2, x < 0), (3, True)) < y The folded version of this results in a Piecewise whose expressions are Booleans: >>> folded_cond = piecewise_fold(cond); folded_cond Piecewise((2 < y, x < 0), (3 < y, True)) When a Boolean containing Piecewise (like cond) or a Piecewise with Boolean expressions (like folded_cond) is used as a condition, it is converted to an equivalent ITE object: >>> Piecewise((1, folded_cond)) Piecewise((1, ITE(x < 0, y > 2, y > 3))) When a condition is an ITE, it will be converted to a simplified Boolean expression: >>> piecewise_fold(_) Piecewise((1, ((x >= 0) | (y > 2)) & ((y > 3) | (x < 0)))) See Also ======== piecewise_fold, ITE """ nargs = None is_Piecewise = True def __new__(cls, *args, **options): if len(args) == 0: raise TypeError("At least one (expr, cond) pair expected.") # (Try to) sympify args first newargs = [] for ec in args: # ec could be a ExprCondPair or a tuple pair = ExprCondPair(*getattr(ec, 'args', ec)) cond = pair.cond if cond is false: continue newargs.append(pair) if cond is true: break if options.pop('evaluate', True): r = cls.eval(*newargs) else: r = None if r is None: return Basic.__new__(cls, *newargs, **options) else: return r @classmethod def eval(cls, *_args): """Either return a modified version of the args or, if no modifications were made, return None. Modifications that are made here: 1) relationals are made canonical 2) any False conditions are dropped 3) any repeat of a previous condition is ignored 3) any args past one with a true condition are dropped If there are no args left, nan will be returned. If there is a single arg with a True condition, its corresponding expression will be returned. """ from sympy.functions.elementary.complexes import im, re if not _args: return Undefined if len(_args) == 1 and _args[0][-1] == True: return _args[0][0] newargs = [] # the unevaluated conditions current_cond = set() # the conditions up to a given e, c pair # make conditions canonical args = [] for e, c in _args: if (not c.is_Atom and not isinstance(c, Relational) and not c.has(im, re)): free = c.free_symbols if len(free) == 1: funcs = [i for i in c.atoms(Function) if not isinstance(i, Boolean)] if len(funcs) == 1 and len( c.xreplace({list(funcs)[0]: Dummy()} ).free_symbols) == 1: # we can treat function like a symbol free = funcs _c = c x = free.pop() try: c = c.as_set().as_relational(x) except NotImplementedError: pass else: reps = {} for i in c.atoms(Relational): ic = i.canonical if ic.rhs in (S.Infinity, S.NegativeInfinity): if not _c.has(ic.rhs): # don't accept introduction of # new Relationals with +/-oo reps[i] = S.true elif ('=' not in ic.rel_op and c.xreplace({x: i.rhs}) != _c.xreplace({x: i.rhs})): reps[i] = Relational( i.lhs, i.rhs, i.rel_op + '=') c = c.xreplace(reps) args.append((e, _canonical(c))) for expr, cond in args: # Check here if expr is a Piecewise and collapse if one of # the conds in expr matches cond. This allows the collapsing # of Piecewise((Piecewise((x,x<0)),x<0)) to Piecewise((x,x<0)). # This is important when using piecewise_fold to simplify # multiple Piecewise instances having the same conds. # Eventually, this code should be able to collapse Piecewise's # having different intervals, but this will probably require # using the new assumptions. if isinstance(expr, Piecewise): unmatching = [] for i, (e, c) in enumerate(expr.args): if c in current_cond: # this would already have triggered continue if c == cond: if c != True: # nothing past this condition will ever # trigger and only those args before this # that didn't match a previous condition # could possibly trigger if unmatching: expr = Piecewise(*( unmatching + [(e, c)])) else: expr = e break else: unmatching.append((e, c)) # check for condition repeats got = False # -- if an And contains a condition that was # already encountered, then the And will be # False: if the previous condition was False # then the And will be False and if the previous # condition is True then then we wouldn't get to # this point. In either case, we can skip this condition. for i in ([cond] + (list(cond.args) if isinstance(cond, And) else [])): if i in current_cond: got = True break if got: continue # -- if not(c) is already in current_cond then c is # a redundant condition in an And. This does not # apply to Or, however: (e1, c), (e2, Or(~c, d)) # is not (e1, c), (e2, d) because if c and d are # both False this would give no results when the # true answer should be (e2, True) if isinstance(cond, And): nonredundant = [] for c in cond.args: if (isinstance(c, Relational) and c.negated.canonical in current_cond): continue nonredundant.append(c) cond = cond.func(*nonredundant) elif isinstance(cond, Relational): if cond.negated.canonical in current_cond: cond = S.true current_cond.add(cond) # collect successive e,c pairs when exprs or cond match if newargs: if newargs[-1].expr == expr: orcond = Or(cond, newargs[-1].cond) if isinstance(orcond, (And, Or)): orcond = distribute_and_over_or(orcond) newargs[-1] = ExprCondPair(expr, orcond) continue elif newargs[-1].cond == cond: newargs[-1] = ExprCondPair(expr, cond) continue newargs.append(ExprCondPair(expr, cond)) # some conditions may have been redundant missing = len(newargs) != len(_args) # some conditions may have changed same = all(a == b for a, b in zip(newargs, _args)) # if either change happened we return the expr with the # updated args if not newargs: raise ValueError(filldedent(''' There are no conditions (or none that are not trivially false) to define an expression.''')) if missing or not same: return cls(*newargs) def doit(self, **hints): """ Evaluate this piecewise function. """ newargs = [] for e, c in self.args: if hints.get('deep', True): if isinstance(e, Basic): newe = e.doit(**hints) if newe != self: e = newe if isinstance(c, Basic): c = c.doit(**hints) newargs.append((e, c)) return self.func(*newargs) def _eval_simplify(self, **kwargs): return piecewise_simplify(self, **kwargs) def _eval_as_leading_term(self, x, logx=None, cdir=0): for e, c in self.args: if c == True or c.subs(x, 0) == True: return e.as_leading_term(x) def _eval_adjoint(self): return self.func(*[(e.adjoint(), c) for e, c in self.args]) def _eval_conjugate(self): return self.func(*[(e.conjugate(), c) for e, c in self.args]) def _eval_derivative(self, x): return self.func(*[(diff(e, x), c) for e, c in self.args]) def _eval_evalf(self, prec): return self.func(*[(e._evalf(prec), c) for e, c in self.args]) def piecewise_integrate(self, x, **kwargs): """Return the Piecewise with each expression being replaced with its antiderivative. To obtain a continuous antiderivative, use the `integrate` function or method. Examples ======== >>> from sympy import Piecewise >>> from sympy.abc import x >>> p = Piecewise((0, x < 0), (1, x < 1), (2, True)) >>> p.piecewise_integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x, True)) Note that this does not give a continuous function, e.g. at x = 1 the 3rd condition applies and the antiderivative there is 2*x so the value of the antiderivative is 2: >>> anti = _ >>> anti.subs(x, 1) 2 The continuous derivative accounts for the integral *up to* the point of interest, however: >>> p.integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x - 1, True)) >>> _.subs(x, 1) 1 See Also ======== Piecewise._eval_integral """ from sympy.integrals import integrate return self.func(*[(integrate(e, x, **kwargs), c) for e, c in self.args]) def _handle_irel(self, x, handler): """Return either None (if the conditions of self depend only on x) else a Piecewise expression whose expressions (handled by the handler that was passed) are paired with the governing x-independent relationals, e.g. Piecewise((A, a(x) & b(y)), (B, c(x) | c(y)) -> Piecewise( (handler(Piecewise((A, a(x) & True), (B, c(x) | True)), b(y) & c(y)), (handler(Piecewise((A, a(x) & True), (B, c(x) | False)), b(y)), (handler(Piecewise((A, a(x) & False), (B, c(x) | True)), c(y)), (handler(Piecewise((A, a(x) & False), (B, c(x) | False)), True)) """ # identify governing relationals rel = self.atoms(Relational) irel = list(ordered([r for r in rel if x not in r.free_symbols and r not in (S.true, S.false)])) if irel: args = {} exprinorder = [] for truth in product((1, 0), repeat=len(irel)): reps = dict(zip(irel, truth)) # only store the true conditions since the false are implied # when they appear lower in the Piecewise args if 1 not in truth: cond = None # flag this one so it doesn't get combined else: andargs = Tuple(*[i for i in reps if reps[i]]) free = list(andargs.free_symbols) if len(free) == 1: from sympy.solvers.inequalities import ( reduce_inequalities, _solve_inequality) try: t = reduce_inequalities(andargs, free[0]) # ValueError when there are potentially # nonvanishing imaginary parts except (ValueError, NotImplementedError): # at least isolate free symbol on left t = And(*[_solve_inequality( a, free[0], linear=True) for a in andargs]) else: t = And(*andargs) if t is S.false: continue # an impossible combination cond = t expr = handler(self.xreplace(reps)) if isinstance(expr, self.func) and len(expr.args) == 1: expr, econd = expr.args[0] cond = And(econd, True if cond is None else cond) # the ec pairs are being collected since all possibilities # are being enumerated, but don't put the last one in since # its expr might match a previous expression and it # must appear last in the args if cond is not None: args.setdefault(expr, []).append(cond) # but since we only store the true conditions we must maintain # the order so that the expression with the most true values # comes first exprinorder.append(expr) # convert collected conditions as args of Or for k in args: args[k] = Or(*args[k]) # take them in the order obtained args = [(e, args[e]) for e in uniq(exprinorder)] # add in the last arg args.append((expr, True)) return Piecewise(*args) def _eval_integral(self, x, _first=True, **kwargs): """Return the indefinite integral of the Piecewise such that subsequent substitution of x with a value will give the value of the integral (not including the constant of integration) up to that point. To only integrate the individual parts of Piecewise, use the `piecewise_integrate` method. Examples ======== >>> from sympy import Piecewise >>> from sympy.abc import x >>> p = Piecewise((0, x < 0), (1, x < 1), (2, True)) >>> p.integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x - 1, True)) >>> p.piecewise_integrate(x) Piecewise((0, x < 0), (x, x < 1), (2*x, True)) See Also ======== Piecewise.piecewise_integrate """ from sympy.integrals.integrals import integrate if _first: def handler(ipw): if isinstance(ipw, self.func): return ipw._eval_integral(x, _first=False, **kwargs) else: return ipw.integrate(x, **kwargs) irv = self._handle_irel(x, handler) if irv is not None: return irv # handle a Piecewise from -oo to oo with and no x-independent relationals # ----------------------------------------------------------------------- try: abei = self._intervals(x) except NotImplementedError: from sympy import Integral return Integral(self, x) # unevaluated pieces = [(a, b) for a, b, _, _ in abei] oo = S.Infinity done = [(-oo, oo, -1)] for k, p in enumerate(pieces): if p == (-oo, oo): # all undone intervals will get this key for j, (a, b, i) in enumerate(done): if i == -1: done[j] = a, b, k break # nothing else to consider N = len(done) - 1 for j, (a, b, i) in enumerate(reversed(done)): if i == -1: j = N - j done[j: j + 1] = _clip(p, (a, b), k) done = [(a, b, i) for a, b, i in done if a != b] # append an arg if there is a hole so a reference to # argument -1 will give Undefined if any(i == -1 for (a, b, i) in done): abei.append((-oo, oo, Undefined, -1)) # return the sum of the intervals args = [] sum = None for a, b, i in done: anti = integrate(abei[i][-2], x, **kwargs) if sum is None: sum = anti else: sum = sum.subs(x, a) if sum == Undefined: sum = 0 sum += anti._eval_interval(x, a, x) # see if we know whether b is contained in original # condition if b is S.Infinity: cond = True elif self.args[abei[i][-1]].cond.subs(x, b) == False: cond = (x < b) else: cond = (x <= b) args.append((sum, cond)) return Piecewise(*args) def _eval_interval(self, sym, a, b, _first=True): """Evaluates the function along the sym in a given interval [a, b]""" # FIXME: Currently complex intervals are not supported. A possible # replacement algorithm, discussed in issue 5227, can be found in the # following papers; # http://portal.acm.org/citation.cfm?id=281649 # http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.70.4127&rep=rep1&type=pdf from sympy.core.symbol import Dummy if a is None or b is None: # In this case, it is just simple substitution return super()._eval_interval(sym, a, b) else: x, lo, hi = map(as_Basic, (sym, a, b)) if _first: # get only x-dependent relationals def handler(ipw): if isinstance(ipw, self.func): return ipw._eval_interval(x, lo, hi, _first=None) else: return ipw._eval_interval(x, lo, hi) irv = self._handle_irel(x, handler) if irv is not None: return irv if (lo < hi) is S.false or ( lo is S.Infinity or hi is S.NegativeInfinity): rv = self._eval_interval(x, hi, lo, _first=False) if isinstance(rv, Piecewise): rv = Piecewise(*[(-e, c) for e, c in rv.args]) else: rv = -rv return rv if (lo < hi) is S.true or ( hi is S.Infinity or lo is S.NegativeInfinity): pass else: _a = Dummy('lo') _b = Dummy('hi') a = lo if lo.is_comparable else _a b = hi if hi.is_comparable else _b pos = self._eval_interval(x, a, b, _first=False) if a == _a and b == _b: # it's purely symbolic so just swap lo and hi and # change the sign to get the value for when lo > hi neg, pos = (-pos.xreplace({_a: hi, _b: lo}), pos.xreplace({_a: lo, _b: hi})) else: # at least one of the bounds was comparable, so allow # _eval_interval to use that information when computing # the interval with lo and hi reversed neg, pos = (-self._eval_interval(x, hi, lo, _first=False), pos.xreplace({_a: lo, _b: hi})) # allow simplification based on ordering of lo and hi p = Dummy('', positive=True) if lo.is_Symbol: pos = pos.xreplace({lo: hi - p}).xreplace({p: hi - lo}) neg = neg.xreplace({lo: hi + p}).xreplace({p: lo - hi}) elif hi.is_Symbol: pos = pos.xreplace({hi: lo + p}).xreplace({p: hi - lo}) neg = neg.xreplace({hi: lo - p}).xreplace({p: lo - hi}) # evaluate limits that may have unevaluate Min/Max touch = lambda _: _.replace( lambda x: isinstance(x, (Min, Max)), lambda x: x.func(*x.args)) neg = touch(neg) pos = touch(pos) # assemble return expression; make the first condition be Lt # b/c then the first expression will look the same whether # the lo or hi limit is symbolic if a == _a: # the lower limit was symbolic rv = Piecewise( (pos, lo < hi), (neg, True)) else: rv = Piecewise( (neg, hi < lo), (pos, True)) if rv == Undefined: raise ValueError("Can't integrate across undefined region.") if any(isinstance(i, Piecewise) for i in (pos, neg)): rv = piecewise_fold(rv) return rv # handle a Piecewise with lo <= hi and no x-independent relationals # ----------------------------------------------------------------- try: abei = self._intervals(x) except NotImplementedError: from sympy import Integral # not being able to do the interval of f(x) can # be stated as not being able to do the integral # of f'(x) over the same range return Integral(self.diff(x), (x, lo, hi)) # unevaluated pieces = [(a, b) for a, b, _, _ in abei] done = [(lo, hi, -1)] oo = S.Infinity for k, p in enumerate(pieces): if p[:2] == (-oo, oo): # all undone intervals will get this key for j, (a, b, i) in enumerate(done): if i == -1: done[j] = a, b, k break # nothing else to consider N = len(done) - 1 for j, (a, b, i) in enumerate(reversed(done)): if i == -1: j = N - j done[j: j + 1] = _clip(p, (a, b), k) done = [(a, b, i) for a, b, i in done if a != b] # return the sum of the intervals sum = S.Zero upto = None for a, b, i in done: if i == -1: if upto is None: return Undefined # TODO simplify hi <= upto return Piecewise((sum, hi <= upto), (Undefined, True)) sum += abei[i][-2]._eval_interval(x, a, b) upto = b return sum def _intervals(self, sym): """Return a list of unique tuples, (a, b, e, i), where a and b are the lower and upper bounds in which the expression e of argument i in self is defined and a < b (when involving numbers) or a <= b when involving symbols. If there are any relationals not involving sym, or any relational cannot be solved for sym, NotImplementedError is raised. The calling routine should have removed such relationals before calling this routine. The evaluated conditions will be returned as ranges. Discontinuous ranges will be returned separately with identical expressions. The first condition that evaluates to True will be returned as the last tuple with a, b = -oo, oo. """ from sympy.solvers.inequalities import _solve_inequality from sympy.logic.boolalg import to_cnf, distribute_or_over_and assert isinstance(self, Piecewise) def _solve_relational(r): if sym not in r.free_symbols: nonsymfail(r) rv = _solve_inequality(r, sym) if isinstance(rv, Relational): free = rv.args[1].free_symbols if rv.args[0] != sym or sym in free: raise NotImplementedError(filldedent(''' Unable to solve relational %s for %s.''' % (r, sym))) if rv.rel_op == '==': # this equality has been affirmed to have the form # Eq(sym, rhs) where rhs is sym-free; it represents # a zero-width interval which will be ignored # whether it is an isolated condition or contained # within an And or an Or rv = S.false elif rv.rel_op == '!=': try: rv = Or(sym < rv.rhs, sym > rv.rhs) except TypeError: # e.g. x != I ==> all real x satisfy rv = S.true elif rv == (S.NegativeInfinity < sym) & (sym < S.Infinity): rv = S.true return rv def nonsymfail(cond): raise NotImplementedError(filldedent(''' A condition not involving %s appeared: %s''' % (sym, cond))) # make self canonical wrt Relationals reps = { r: _solve_relational(r) for r in self.atoms(Relational)} # process args individually so if any evaluate, their position # in the original Piecewise will be known args = [i.xreplace(reps) for i in self.args] # precondition args expr_cond = [] default = idefault = None for i, (expr, cond) in enumerate(args): if cond is S.false: continue elif cond is S.true: default = expr idefault = i break cond = to_cnf(cond) if isinstance(cond, And): cond = distribute_or_over_and(cond) if isinstance(cond, Or): expr_cond.extend( [(i, expr, o) for o in cond.args if not isinstance(o, Equality)]) elif cond is not S.false: expr_cond.append((i, expr, cond)) # determine intervals represented by conditions int_expr = [] for iarg, expr, cond in expr_cond: if isinstance(cond, And): lower = S.NegativeInfinity upper = S.Infinity exclude = [] for cond2 in cond.args: if isinstance(cond2, Equality): lower = upper # ignore break elif isinstance(cond2, Unequality): l, r = cond2.args if l == sym: exclude.append(r) elif r == sym: exclude.append(l) else: nonsymfail(cond2) continue elif cond2.lts == sym: upper = Min(cond2.gts, upper) elif cond2.gts == sym: lower = Max(cond2.lts, lower) else: nonsymfail(cond2) # should never get here if exclude: exclude = list(ordered(exclude)) newcond = [] for i, e in enumerate(exclude): if e < lower == True or e > upper == True: continue if not newcond: newcond.append((None, lower)) # add a primer newcond.append((newcond[-1][1], e)) newcond.append((newcond[-1][1], upper)) newcond.pop(0) # remove the primer expr_cond.extend([(iarg, expr, And(i[0] < sym, sym < i[1])) for i in newcond]) continue elif isinstance(cond, Relational): lower, upper = cond.lts, cond.gts # part 1: initialize with givens if cond.lts == sym: # part 1a: expand the side ... lower = S.NegativeInfinity # e.g. x <= 0 ---> -oo <= 0 elif cond.gts == sym: # part 1a: ... that can be expanded upper = S.Infinity # e.g. x >= 0 ---> oo >= 0 else: nonsymfail(cond) else: raise NotImplementedError( 'unrecognized condition: %s' % cond) lower, upper = lower, Max(lower, upper) if (lower >= upper) is not S.true: int_expr.append((lower, upper, expr, iarg)) if default is not None: int_expr.append( (S.NegativeInfinity, S.Infinity, default, idefault)) return list(uniq(int_expr)) def _eval_nseries(self, x, n, logx, cdir=0): args = [(ec.expr._eval_nseries(x, n, logx), ec.cond) for ec in self.args] return self.func(*args) def _eval_power(self, s): return self.func(*[(e**s, c) for e, c in self.args]) def _eval_subs(self, old, new): # this is strictly not necessary, but we can keep track # of whether True or False conditions arise and be # somewhat more efficient by avoiding other substitutions # and avoiding invalid conditions that appear after a # True condition args = list(self.args) args_exist = False for i, (e, c) in enumerate(args): c = c._subs(old, new) if c != False: args_exist = True e = e._subs(old, new) args[i] = (e, c) if c == True: break if not args_exist: args = ((Undefined, True),) return self.func(*args) def _eval_transpose(self): return self.func(*[(e.transpose(), c) for e, c in self.args]) def _eval_template_is_attr(self, is_attr): b = None for expr, _ in self.args: a = getattr(expr, is_attr) if a is None: return if b is None: b = a elif b is not a: return return b _eval_is_finite = lambda self: self._eval_template_is_attr( 'is_finite') _eval_is_complex = lambda self: self._eval_template_is_attr('is_complex') _eval_is_even = lambda self: self._eval_template_is_attr('is_even') _eval_is_imaginary = lambda self: self._eval_template_is_attr( 'is_imaginary') _eval_is_integer = lambda self: self._eval_template_is_attr('is_integer') _eval_is_irrational = lambda self: self._eval_template_is_attr( 'is_irrational') _eval_is_negative = lambda self: self._eval_template_is_attr('is_negative') _eval_is_nonnegative = lambda self: self._eval_template_is_attr( 'is_nonnegative') _eval_is_nonpositive = lambda self: self._eval_template_is_attr( 'is_nonpositive') _eval_is_nonzero = lambda self: self._eval_template_is_attr( 'is_nonzero') _eval_is_odd = lambda self: self._eval_template_is_attr('is_odd') _eval_is_polar = lambda self: self._eval_template_is_attr('is_polar') _eval_is_positive = lambda self: self._eval_template_is_attr('is_positive') _eval_is_extended_real = lambda self: self._eval_template_is_attr( 'is_extended_real') _eval_is_extended_positive = lambda self: self._eval_template_is_attr( 'is_extended_positive') _eval_is_extended_negative = lambda self: self._eval_template_is_attr( 'is_extended_negative') _eval_is_extended_nonzero = lambda self: self._eval_template_is_attr( 'is_extended_nonzero') _eval_is_extended_nonpositive = lambda self: self._eval_template_is_attr( 'is_extended_nonpositive') _eval_is_extended_nonnegative = lambda self: self._eval_template_is_attr( 'is_extended_nonnegative') _eval_is_real = lambda self: self._eval_template_is_attr('is_real') _eval_is_zero = lambda self: self._eval_template_is_attr( 'is_zero') @classmethod def __eval_cond(cls, cond): """Return the truth value of the condition.""" if cond == True: return True if isinstance(cond, Equality): try: diff = cond.lhs - cond.rhs if diff.is_commutative: return diff.is_zero except TypeError: pass def as_expr_set_pairs(self, domain=None): """Return tuples for each argument of self that give the expression and the interval in which it is valid which is contained within the given domain. If a condition cannot be converted to a set, an error will be raised. The variable of the conditions is assumed to be real; sets of real values are returned. Examples ======== >>> from sympy import Piecewise, Interval >>> from sympy.abc import x >>> p = Piecewise( ... (1, x < 2), ... (2,(x > 0) & (x < 4)), ... (3, True)) >>> p.as_expr_set_pairs() [(1, Interval.open(-oo, 2)), (2, Interval.Ropen(2, 4)), (3, Interval(4, oo))] >>> p.as_expr_set_pairs(Interval(0, 3)) [(1, Interval.Ropen(0, 2)), (2, Interval(2, 3))] """ if domain is None: domain = S.Reals exp_sets = [] U = domain complex = not domain.is_subset(S.Reals) cond_free = set() for expr, cond in self.args: cond_free |= cond.free_symbols if len(cond_free) > 1: raise NotImplementedError(filldedent(''' multivariate conditions are not handled.''')) if complex: for i in cond.atoms(Relational): if not isinstance(i, (Equality, Unequality)): raise ValueError(filldedent(''' Inequalities in the complex domain are not supported. Try the real domain by setting domain=S.Reals''')) cond_int = U.intersect(cond.as_set()) U = U - cond_int if cond_int != S.EmptySet: exp_sets.append((expr, cond_int)) return exp_sets def _eval_rewrite_as_ITE(self, *args, **kwargs): byfree = {} args = list(args) default = any(c == True for b, c in args) for i, (b, c) in enumerate(args): if not isinstance(b, Boolean) and b != True: raise TypeError(filldedent(''' Expecting Boolean or bool but got `%s` ''' % func_name(b))) if c == True: break # loop over independent conditions for this b for c in c.args if isinstance(c, Or) else [c]: free = c.free_symbols x = free.pop() try: byfree[x] = byfree.setdefault( x, S.EmptySet).union(c.as_set()) except NotImplementedError: if not default: raise NotImplementedError(filldedent(''' A method to determine whether a multivariate conditional is consistent with a complete coverage of all variables has not been implemented so the rewrite is being stopped after encountering `%s`. This error would not occur if a default expression like `(foo, True)` were given. ''' % c)) if byfree[x] in (S.UniversalSet, S.Reals): # collapse the ith condition to True and break args[i] = list(args[i]) c = args[i][1] = True break if c == True: break if c != True: raise ValueError(filldedent(''' Conditions must cover all reals or a final default condition `(foo, True)` must be given. ''')) last, _ = args[i] # ignore all past ith arg for a, c in reversed(args[:i]): last = ITE(c, a, last) return _canonical(last) def _eval_rewrite_as_KroneckerDelta(self, *args): from sympy import Ne, Eq, Not, KroneckerDelta rules = { And: [False, False], Or: [True, True], Not: [True, False], Eq: [None, None], Ne: [None, None] } class UnrecognizedCondition(Exception): pass def rewrite(cond): if isinstance(cond, Eq): return KroneckerDelta(*cond.args) if isinstance(cond, Ne): return 1 - KroneckerDelta(*cond.args) cls, args = type(cond), cond.args if cls not in rules: raise UnrecognizedCondition(cls) b1, b2 = rules[cls] k = 1 for c in args: if b1: k *= 1 - rewrite(c) else: k *= rewrite(c) if b2: return 1 - k return k conditions = [] true_value = None for value, cond in args: if type(cond) in rules: conditions.append((value, cond)) elif cond is S.true: if true_value is None: true_value = value else: return if true_value is not None: result = true_value for value, cond in conditions[::-1]: try: k = rewrite(cond) result = k * value + (1 - k) * result except UnrecognizedCondition: return return result def piecewise_fold(expr): """ Takes an expression containing a piecewise function and returns the expression in piecewise form. In addition, any ITE conditions are rewritten in negation normal form and simplified. Examples ======== >>> from sympy import Piecewise, piecewise_fold, sympify as S >>> from sympy.abc import x >>> p = Piecewise((x, x < 1), (1, S(1) <= x)) >>> piecewise_fold(x*p) Piecewise((x**2, x < 1), (x, True)) See Also ======== Piecewise """ if not isinstance(expr, Basic) or not expr.has(Piecewise): return expr new_args = [] if isinstance(expr, (ExprCondPair, Piecewise)): for e, c in expr.args: if not isinstance(e, Piecewise): e = piecewise_fold(e) # we don't keep Piecewise in condition because # it has to be checked to see that it's complete # and we convert it to ITE at that time assert not c.has(Piecewise) # pragma: no cover if isinstance(c, ITE): c = c.to_nnf() c = simplify_logic(c, form='cnf') if isinstance(e, Piecewise): new_args.extend([(piecewise_fold(ei), And(ci, c)) for ei, ci in e.args]) else: new_args.append((e, c)) else: from sympy.utilities.iterables import cartes, sift, common_prefix # Given # P1 = Piecewise((e11, c1), (e12, c2), A) # P2 = Piecewise((e21, c1), (e22, c2), B) # ... # the folding of f(P1, P2) is trivially # Piecewise( # (f(e11, e21), c1), # (f(e12, e22), c2), # (f(Piecewise(A), Piecewise(B)), True)) # Certain objects end up rewriting themselves as thus, so # we do that grouping before the more generic folding. # The following applies this idea when f = Add or f = Mul # (and the expression is commutative). if expr.is_Add or expr.is_Mul and expr.is_commutative: p, args = sift(expr.args, lambda x: x.is_Piecewise, binary=True) pc = sift(p, lambda x: tuple([c for e,c in x.args])) for c in list(ordered(pc)): if len(pc[c]) > 1: pargs = [list(i.args) for i in pc[c]] # the first one is the same; there may be more com = common_prefix(*[ [i.cond for i in j] for j in pargs]) n = len(com) collected = [] for i in range(n): collected.append(( expr.func(*[ai[i].expr for ai in pargs]), com[i])) remains = [] for a in pargs: if n == len(a): # no more args continue if a[n].cond == True: # no longer Piecewise remains.append(a[n].expr) else: # restore the remaining Piecewise remains.append( Piecewise(*a[n:], evaluate=False)) if remains: collected.append((expr.func(*remains), True)) args.append(Piecewise(*collected, evaluate=False)) continue args.extend(pc[c]) else: args = expr.args # fold folded = list(map(piecewise_fold, args)) for ec in cartes(*[ (i.args if isinstance(i, Piecewise) else [(i, true)]) for i in folded]): e, c = zip(*ec) new_args.append((expr.func(*e), And(*c))) return Piecewise(*new_args) def _clip(A, B, k): """Return interval B as intervals that are covered by A (keyed to k) and all other intervals of B not covered by A keyed to -1. The reference point of each interval is the rhs; if the lhs is greater than the rhs then an interval of zero width interval will result, e.g. (4, 1) is treated like (1, 1). Examples ======== >>> from sympy.functions.elementary.piecewise import _clip >>> from sympy import Tuple >>> A = Tuple(1, 3) >>> B = Tuple(2, 4) >>> _clip(A, B, 0) [(2, 3, 0), (3, 4, -1)] Interpretation: interval portion (2, 3) of interval (2, 4) is covered by interval (1, 3) and is keyed to 0 as requested; interval (3, 4) was not covered by (1, 3) and is keyed to -1. """ a, b = B c, d = A c, d = Min(Max(c, a), b), Min(Max(d, a), b) a, b = Min(a, b), b p = [] if a != c: p.append((a, c, -1)) else: pass if c != d: p.append((c, d, k)) else: pass if b != d: if d == c and p and p[-1][-1] == -1: p[-1] = p[-1][0], b, -1 else: p.append((d, b, -1)) else: pass return p def piecewise_simplify_arguments(expr, **kwargs): from sympy import simplify args = [] for e, c in expr.args: if isinstance(e, Basic): doit = kwargs.pop('doit', None) # Skip doit to avoid growth at every call for some integrals # and sums, see sympy/sympy#17165 newe = simplify(e, doit=False, **kwargs) if newe != expr: e = newe if isinstance(c, Basic): c = simplify(c, doit=doit, **kwargs) args.append((e, c)) return Piecewise(*args) def piecewise_simplify(expr, **kwargs): expr = piecewise_simplify_arguments(expr, **kwargs) if not isinstance(expr, Piecewise): return expr args = list(expr.args) _blessed = lambda e: getattr(e.lhs, '_diff_wrt', False) and ( getattr(e.rhs, '_diff_wrt', None) or isinstance(e.rhs, (Rational, NumberSymbol))) for i, (expr, cond) in enumerate(args): # try to simplify conditions and the expression for # equalities that are part of the condition, e.g. # Piecewise((n, And(Eq(n,0), Eq(n + m, 0))), (1, True)) # -> Piecewise((0, And(Eq(n, 0), Eq(m, 0))), (1, True)) if isinstance(cond, And): eqs, other = sift(cond.args, lambda i: isinstance(i, Equality), binary=True) elif isinstance(cond, Equality): eqs, other = [cond], [] else: eqs = other = [] if eqs: eqs = list(ordered(eqs)) for j, e in enumerate(eqs): # these blessed lhs objects behave like Symbols # and the rhs are simple replacements for the "symbols" if _blessed(e): expr = expr.subs(*e.args) eqs[j + 1:] = [ei.subs(*e.args) for ei in eqs[j + 1:]] other = [ei.subs(*e.args) for ei in other] cond = And(*(eqs + other)) args[i] = args[i].func(expr, cond) # See if expressions valid for an Equal expression happens to evaluate # to the same function as in the next piecewise segment, see: # https://github.com/sympy/sympy/issues/8458 prevexpr = None for i, (expr, cond) in reversed(list(enumerate(args))): if prevexpr is not None: if isinstance(cond, And): eqs, other = sift(cond.args, lambda i: isinstance(i, Equality), binary=True) elif isinstance(cond, Equality): eqs, other = [cond], [] else: eqs = other = [] _prevexpr = prevexpr _expr = expr if eqs and not other: eqs = list(ordered(eqs)) for e in eqs: # allow 2 args to collapse into 1 for any e # otherwise limit simplification to only simple-arg # Eq instances if len(args) == 2 or _blessed(e): _prevexpr = _prevexpr.subs(*e.args) _expr = _expr.subs(*e.args) # Did it evaluate to the same? if _prevexpr == _expr: # Set the expression for the Not equal section to the same # as the next. These will be merged when creating the new # Piecewise args[i] = args[i].func(args[i+1][0], cond) else: # Update the expression that we compare against prevexpr = expr else: prevexpr = expr return Piecewise(*args) sympy-sympy-1.9/sympy/functions/elementary/tests/000077500000000000000000000000001412543434000224235ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/elementary/tests/__init__.py000066400000000000000000000000001412543434000245220ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/elementary/tests/test_complexes.py000066400000000000000000000765241412543434000260510ustar00rootroot00000000000000from sympy import ( Abs, acos, adjoint, arg, atan, atan2, conjugate, cos, DiracDelta, E, exp, expand, Expr, Function, Heaviside, I, im, log, nan, oo, pi, Rational, re, S, sign, sin, sqrt, Symbol, symbols, transpose, zoo, exp_polar, Piecewise, Interval, comp, Integral, Matrix, ImmutableMatrix, SparseMatrix, ImmutableSparseMatrix, MatrixSymbol, FunctionMatrix, Lambda, Derivative, Eq) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.testing.pytest import XFAIL, raises, _both_exp_pow def N_equals(a, b): """Check whether two complex numbers are numerically close""" return comp(a.n(), b.n(), 1.e-6) def test_re(): x, y = symbols('x,y') a, b = symbols('a,b', real=True) r = Symbol('r', real=True) i = Symbol('i', imaginary=True) assert re(nan) is nan assert re(oo) is oo assert re(-oo) is -oo assert re(0) == 0 assert re(1) == 1 assert re(-1) == -1 assert re(E) == E assert re(-E) == -E assert unchanged(re, x) assert re(x*I) == -im(x) assert re(r*I) == 0 assert re(r) == r assert re(i*I) == I * i assert re(i) == 0 assert re(x + y) == re(x) + re(y) assert re(x + r) == re(x) + r assert re(re(x)) == re(x) assert re(2 + I) == 2 assert re(x + I) == re(x) assert re(x + y*I) == re(x) - im(y) assert re(x + r*I) == re(x) assert re(log(2*I)) == log(2) assert re((2 + I)**2).expand(complex=True) == 3 assert re(conjugate(x)) == re(x) assert conjugate(re(x)) == re(x) assert re(x).as_real_imag() == (re(x), 0) assert re(i*r*x).diff(r) == re(i*x) assert re(i*r*x).diff(i) == I*r*im(x) assert re( sqrt(a + b*I)) == (a**2 + b**2)**Rational(1, 4)*cos(atan2(b, a)/2) assert re(a * (2 + b*I)) == 2*a assert re((1 + sqrt(a + b*I))/2) == \ (a**2 + b**2)**Rational(1, 4)*cos(atan2(b, a)/2)/2 + S.Half assert re(x).rewrite(im) == x - S.ImaginaryUnit*im(x) assert (x + re(y)).rewrite(re, im) == x + y - S.ImaginaryUnit*im(y) a = Symbol('a', algebraic=True) t = Symbol('t', transcendental=True) x = Symbol('x') assert re(a).is_algebraic assert re(x).is_algebraic is None assert re(t).is_algebraic is False assert re(S.ComplexInfinity) is S.NaN n, m, l = symbols('n m l') A = MatrixSymbol('A',n,m) assert re(A) == (S.Half) * (A + conjugate(A)) A = Matrix([[1 + 4*I,2],[0, -3*I]]) assert re(A) == Matrix([[1, 2],[0, 0]]) A = ImmutableMatrix([[1 + 3*I, 3-2*I],[0, 2*I]]) assert re(A) == ImmutableMatrix([[1, 3],[0, 0]]) X = SparseMatrix([[2*j + i*I for i in range(5)] for j in range(5)]) assert re(X) - Matrix([[0, 0, 0, 0, 0], [2, 2, 2, 2, 2], [4, 4, 4, 4, 4], [6, 6, 6, 6, 6], [8, 8, 8, 8, 8]]) == Matrix.zeros(5) assert im(X) - Matrix([[0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4], [0, 1, 2, 3, 4]]) == Matrix.zeros(5) X = FunctionMatrix(3, 3, Lambda((n, m), n + m*I)) assert re(X) == Matrix([[0, 0, 0], [1, 1, 1], [2, 2, 2]]) def test_im(): x, y = symbols('x,y') a, b = symbols('a,b', real=True) r = Symbol('r', real=True) i = Symbol('i', imaginary=True) assert im(nan) is nan assert im(oo*I) is oo assert im(-oo*I) is -oo assert im(0) == 0 assert im(1) == 0 assert im(-1) == 0 assert im(E*I) == E assert im(-E*I) == -E assert unchanged(im, x) assert im(x*I) == re(x) assert im(r*I) == r assert im(r) == 0 assert im(i*I) == 0 assert im(i) == -I * i assert im(x + y) == im(x) + im(y) assert im(x + r) == im(x) assert im(x + r*I) == im(x) + r assert im(im(x)*I) == im(x) assert im(2 + I) == 1 assert im(x + I) == im(x) + 1 assert im(x + y*I) == im(x) + re(y) assert im(x + r*I) == im(x) + r assert im(log(2*I)) == pi/2 assert im((2 + I)**2).expand(complex=True) == 4 assert im(conjugate(x)) == -im(x) assert conjugate(im(x)) == im(x) assert im(x).as_real_imag() == (im(x), 0) assert im(i*r*x).diff(r) == im(i*x) assert im(i*r*x).diff(i) == -I * re(r*x) assert im( sqrt(a + b*I)) == (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2) assert im(a * (2 + b*I)) == a*b assert im((1 + sqrt(a + b*I))/2) == \ (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2)/2 assert im(x).rewrite(re) == -S.ImaginaryUnit * (x - re(x)) assert (x + im(y)).rewrite(im, re) == x - S.ImaginaryUnit * (y - re(y)) a = Symbol('a', algebraic=True) t = Symbol('t', transcendental=True) x = Symbol('x') assert re(a).is_algebraic assert re(x).is_algebraic is None assert re(t).is_algebraic is False assert im(S.ComplexInfinity) is S.NaN n, m, l = symbols('n m l') A = MatrixSymbol('A',n,m) assert im(A) == (S.One/(2*I)) * (A - conjugate(A)) A = Matrix([[1 + 4*I, 2],[0, -3*I]]) assert im(A) == Matrix([[4, 0],[0, -3]]) A = ImmutableMatrix([[1 + 3*I, 3-2*I],[0, 2*I]]) assert im(A) == ImmutableMatrix([[3, -2],[0, 2]]) X = ImmutableSparseMatrix( [[i*I + i for i in range(5)] for i in range(5)]) Y = SparseMatrix([[i for i in range(5)] for i in range(5)]) assert im(X).as_immutable() == Y X = FunctionMatrix(3, 3, Lambda((n, m), n + m*I)) assert im(X) == Matrix([[0, 1, 2], [0, 1, 2], [0, 1, 2]]) def test_sign(): assert sign(1.2) == 1 assert sign(-1.2) == -1 assert sign(3*I) == I assert sign(-3*I) == -I assert sign(0) == 0 assert sign(0, evaluate=False).doit() == 0 assert sign(oo, evaluate=False).doit() == 1 assert sign(nan) is nan assert sign(2 + 2*I).doit() == sqrt(2)*(2 + 2*I)/4 assert sign(2 + 3*I).simplify() == sign(2 + 3*I) assert sign(2 + 2*I).simplify() == sign(1 + I) assert sign(im(sqrt(1 - sqrt(3)))) == 1 assert sign(sqrt(1 - sqrt(3))) == I x = Symbol('x') assert sign(x).is_finite is True assert sign(x).is_complex is True assert sign(x).is_imaginary is None assert sign(x).is_integer is None assert sign(x).is_real is None assert sign(x).is_zero is None assert sign(x).doit() == sign(x) assert sign(1.2*x) == sign(x) assert sign(2*x) == sign(x) assert sign(I*x) == I*sign(x) assert sign(-2*I*x) == -I*sign(x) assert sign(conjugate(x)) == conjugate(sign(x)) p = Symbol('p', positive=True) n = Symbol('n', negative=True) m = Symbol('m', negative=True) assert sign(2*p*x) == sign(x) assert sign(n*x) == -sign(x) assert sign(n*m*x) == sign(x) x = Symbol('x', imaginary=True) assert sign(x).is_imaginary is True assert sign(x).is_integer is False assert sign(x).is_real is False assert sign(x).is_zero is False assert sign(x).diff(x) == 2*DiracDelta(-I*x) assert sign(x).doit() == x / Abs(x) assert conjugate(sign(x)) == -sign(x) x = Symbol('x', real=True) assert sign(x).is_imaginary is False assert sign(x).is_integer is True assert sign(x).is_real is True assert sign(x).is_zero is None assert sign(x).diff(x) == 2*DiracDelta(x) assert sign(x).doit() == sign(x) assert conjugate(sign(x)) == sign(x) x = Symbol('x', nonzero=True) assert sign(x).is_imaginary is False assert sign(x).is_integer is True assert sign(x).is_real is True assert sign(x).is_zero is False assert sign(x).doit() == x / Abs(x) assert sign(Abs(x)) == 1 assert Abs(sign(x)) == 1 x = Symbol('x', positive=True) assert sign(x).is_imaginary is False assert sign(x).is_integer is True assert sign(x).is_real is True assert sign(x).is_zero is False assert sign(x).doit() == x / Abs(x) assert sign(Abs(x)) == 1 assert Abs(sign(x)) == 1 x = 0 assert sign(x).is_imaginary is False assert sign(x).is_integer is True assert sign(x).is_real is True assert sign(x).is_zero is True assert sign(x).doit() == 0 assert sign(Abs(x)) == 0 assert Abs(sign(x)) == 0 nz = Symbol('nz', nonzero=True, integer=True) assert sign(nz).is_imaginary is False assert sign(nz).is_integer is True assert sign(nz).is_real is True assert sign(nz).is_zero is False assert sign(nz)**2 == 1 assert (sign(nz)**3).args == (sign(nz), 3) assert sign(Symbol('x', nonnegative=True)).is_nonnegative assert sign(Symbol('x', nonnegative=True)).is_nonpositive is None assert sign(Symbol('x', nonpositive=True)).is_nonnegative is None assert sign(Symbol('x', nonpositive=True)).is_nonpositive assert sign(Symbol('x', real=True)).is_nonnegative is None assert sign(Symbol('x', real=True)).is_nonpositive is None assert sign(Symbol('x', real=True, zero=False)).is_nonpositive is None x, y = Symbol('x', real=True), Symbol('y') f = Function('f') assert sign(x).rewrite(Piecewise) == \ Piecewise((1, x > 0), (-1, x < 0), (0, True)) assert sign(y).rewrite(Piecewise) == sign(y) assert sign(x).rewrite(Heaviside) == 2*Heaviside(x, H0=S(1)/2) - 1 assert sign(y).rewrite(Heaviside) == sign(y) assert sign(y).rewrite(Abs) == Piecewise((0, Eq(y, 0)), (y/Abs(y), True)) assert sign(f(y)).rewrite(Abs) == Piecewise((0, Eq(f(y), 0)), (f(y)/Abs(f(y)), True)) # evaluate what can be evaluated assert sign(exp_polar(I*pi)*pi) is S.NegativeOne eq = -sqrt(10 + 6*sqrt(3)) + sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) # if there is a fast way to know when and when you cannot prove an # expression like this is zero then the equality to zero is ok assert sign(eq).func is sign or sign(eq) == 0 # but sometimes it's hard to do this so it's better not to load # abs down with tests that will be very slow q = 1 + sqrt(2) - 2*sqrt(3) + 1331*sqrt(6) p = expand(q**3)**Rational(1, 3) d = p - q assert sign(d).func is sign or sign(d) == 0 def test_as_real_imag(): n = pi**1000 # the special code for working out the real # and complex parts of a power with Integer exponent # should not run if there is no imaginary part, hence # this should not hang assert n.as_real_imag() == (n, 0) # issue 6261 x = Symbol('x') assert sqrt(x).as_real_imag() == \ ((re(x)**2 + im(x)**2)**Rational(1, 4)*cos(atan2(im(x), re(x))/2), (re(x)**2 + im(x)**2)**Rational(1, 4)*sin(atan2(im(x), re(x))/2)) # issue 3853 a, b = symbols('a,b', real=True) assert ((1 + sqrt(a + b*I))/2).as_real_imag() == \ ( (a**2 + b**2)**Rational( 1, 4)*cos(atan2(b, a)/2)/2 + S.Half, (a**2 + b**2)**Rational(1, 4)*sin(atan2(b, a)/2)/2) assert sqrt(a**2).as_real_imag() == (sqrt(a**2), 0) i = symbols('i', imaginary=True) assert sqrt(i**2).as_real_imag() == (0, abs(i)) assert ((1 + I)/(1 - I)).as_real_imag() == (0, 1) assert ((1 + I)**3/(1 - I)).as_real_imag() == (-2, 0) @XFAIL def test_sign_issue_3068(): n = pi**1000 i = int(n) x = Symbol('x') assert (n - i).round() == 1 # doesn't hang assert sign(n - i) == 1 # perhaps it's not possible to get the sign right when # only 1 digit is being requested for this situation; # 2 digits works assert (n - x).n(1, subs={x: i}) > 0 assert (n - x).n(2, subs={x: i}) > 0 def test_Abs(): raises(TypeError, lambda: Abs(Interval(2, 3))) # issue 8717 x, y = symbols('x,y') assert sign(sign(x)) == sign(x) assert sign(x*y).func is sign assert Abs(0) == 0 assert Abs(1) == 1 assert Abs(-1) == 1 assert Abs(I) == 1 assert Abs(-I) == 1 assert Abs(nan) is nan assert Abs(zoo) is oo assert Abs(I * pi) == pi assert Abs(-I * pi) == pi assert Abs(I * x) == Abs(x) assert Abs(-I * x) == Abs(x) assert Abs(-2*x) == 2*Abs(x) assert Abs(-2.0*x) == 2.0*Abs(x) assert Abs(2*pi*x*y) == 2*pi*Abs(x*y) assert Abs(conjugate(x)) == Abs(x) assert conjugate(Abs(x)) == Abs(x) assert Abs(x).expand(complex=True) == sqrt(re(x)**2 + im(x)**2) a = Symbol('a', positive=True) assert Abs(2*pi*x*a) == 2*pi*a*Abs(x) assert Abs(2*pi*I*x*a) == 2*pi*a*Abs(x) x = Symbol('x', real=True) n = Symbol('n', integer=True) assert Abs((-1)**n) == 1 assert x**(2*n) == Abs(x)**(2*n) assert Abs(x).diff(x) == sign(x) assert abs(x) == Abs(x) # Python built-in assert Abs(x)**3 == x**2*Abs(x) assert Abs(x)**4 == x**4 assert ( Abs(x)**(3*n)).args == (Abs(x), 3*n) # leave symbolic odd unchanged assert (1/Abs(x)).args == (Abs(x), -1) assert 1/Abs(x)**3 == 1/(x**2*Abs(x)) assert Abs(x)**-3 == Abs(x)/(x**4) assert Abs(x**3) == x**2*Abs(x) assert Abs(I**I) == exp(-pi/2) assert Abs((4 + 5*I)**(6 + 7*I)) == 68921*exp(-7*atan(Rational(5, 4))) y = Symbol('y', real=True) assert Abs(I**y) == 1 y = Symbol('y') assert Abs(I**y) == exp(-pi*im(y)/2) x = Symbol('x', imaginary=True) assert Abs(x).diff(x) == -sign(x) eq = -sqrt(10 + 6*sqrt(3)) + sqrt(1 + sqrt(3)) + sqrt(3 + 3*sqrt(3)) # if there is a fast way to know when you can and when you cannot prove an # expression like this is zero then the equality to zero is ok assert abs(eq).func is Abs or abs(eq) == 0 # but sometimes it's hard to do this so it's better not to load # abs down with tests that will be very slow q = 1 + sqrt(2) - 2*sqrt(3) + 1331*sqrt(6) p = expand(q**3)**Rational(1, 3) d = p - q assert abs(d).func is Abs or abs(d) == 0 assert Abs(4*exp(pi*I/4)) == 4 assert Abs(3**(2 + I)) == 9 assert Abs((-3)**(1 - I)) == 3*exp(pi) assert Abs(oo) is oo assert Abs(-oo) is oo assert Abs(oo + I) is oo assert Abs(oo + I*oo) is oo a = Symbol('a', algebraic=True) t = Symbol('t', transcendental=True) x = Symbol('x') assert re(a).is_algebraic assert re(x).is_algebraic is None assert re(t).is_algebraic is False assert Abs(x).fdiff() == sign(x) raises(ArgumentIndexError, lambda: Abs(x).fdiff(2)) # doesn't have recursion error arg = sqrt(acos(1 - I)*acos(1 + I)) assert abs(arg) == arg # special handling to put Abs in denom assert abs(1/x) == 1/Abs(x) e = abs(2/x**2) assert e.is_Mul and e == 2/Abs(x**2) assert unchanged(Abs, y/x) assert unchanged(Abs, x/(x + 1)) assert unchanged(Abs, x*y) p = Symbol('p', positive=True) assert abs(x/p) == abs(x)/p # coverage assert unchanged(Abs, Symbol('x', real=True)**y) # issue 19627 f = Function('f', positive=True) assert sqrt(f(x)**2) == f(x) # issue 21625 assert unchanged(Abs, S("im(acos(-i + acosh(-g + i)))")) def test_Abs_rewrite(): x = Symbol('x', real=True) a = Abs(x).rewrite(Heaviside).expand() assert a == x*Heaviside(x) - x*Heaviside(-x) for i in [-2, -1, 0, 1, 2]: assert a.subs(x, i) == abs(i) y = Symbol('y') assert Abs(y).rewrite(Heaviside) == Abs(y) x, y = Symbol('x', real=True), Symbol('y') assert Abs(x).rewrite(Piecewise) == Piecewise((x, x >= 0), (-x, True)) assert Abs(y).rewrite(Piecewise) == Abs(y) assert Abs(y).rewrite(sign) == y/sign(y) i = Symbol('i', imaginary=True) assert abs(i).rewrite(Piecewise) == Piecewise((I*i, I*i >= 0), (-I*i, True)) assert Abs(y).rewrite(conjugate) == sqrt(y*conjugate(y)) assert Abs(i).rewrite(conjugate) == sqrt(-i**2) # == -I*i y = Symbol('y', extended_real=True) assert (Abs(exp(-I*x)-exp(-I*y))**2).rewrite(conjugate) == \ -exp(I*x)*exp(-I*y) + 2 - exp(-I*x)*exp(I*y) def test_Abs_real(): # test some properties of abs that only apply # to real numbers x = Symbol('x', complex=True) assert sqrt(x**2) != Abs(x) assert Abs(x**2) != x**2 x = Symbol('x', real=True) assert sqrt(x**2) == Abs(x) assert Abs(x**2) == x**2 # if the symbol is zero, the following will still apply nn = Symbol('nn', nonnegative=True, real=True) np = Symbol('np', nonpositive=True, real=True) assert Abs(nn) == nn assert Abs(np) == -np def test_Abs_properties(): x = Symbol('x') assert Abs(x).is_real is None assert Abs(x).is_extended_real is True assert Abs(x).is_rational is None assert Abs(x).is_positive is None assert Abs(x).is_nonnegative is None assert Abs(x).is_extended_positive is None assert Abs(x).is_extended_nonnegative is True f = Symbol('x', finite=True) assert Abs(f).is_real is True assert Abs(f).is_extended_real is True assert Abs(f).is_rational is None assert Abs(f).is_positive is None assert Abs(f).is_nonnegative is True assert Abs(f).is_extended_positive is None assert Abs(f).is_extended_nonnegative is True z = Symbol('z', complex=True, zero=False) assert Abs(z).is_real is True # since complex implies finite assert Abs(z).is_extended_real is True assert Abs(z).is_rational is None assert Abs(z).is_positive is True assert Abs(z).is_extended_positive is True assert Abs(z).is_zero is False p = Symbol('p', positive=True) assert Abs(p).is_real is True assert Abs(p).is_extended_real is True assert Abs(p).is_rational is None assert Abs(p).is_positive is True assert Abs(p).is_zero is False q = Symbol('q', rational=True) assert Abs(q).is_real is True assert Abs(q).is_rational is True assert Abs(q).is_integer is None assert Abs(q).is_positive is None assert Abs(q).is_nonnegative is True i = Symbol('i', integer=True) assert Abs(i).is_real is True assert Abs(i).is_integer is True assert Abs(i).is_positive is None assert Abs(i).is_nonnegative is True e = Symbol('n', even=True) ne = Symbol('ne', real=True, even=False) assert Abs(e).is_even is True assert Abs(ne).is_even is False assert Abs(i).is_even is None o = Symbol('n', odd=True) no = Symbol('no', real=True, odd=False) assert Abs(o).is_odd is True assert Abs(no).is_odd is False assert Abs(i).is_odd is None def test_abs(): # this tests that abs calls Abs; don't rename to # test_Abs since that test is already above a = Symbol('a', positive=True) assert abs(I*(1 + a)**2) == (1 + a)**2 def test_arg(): assert arg(0) is nan assert arg(1) == 0 assert arg(-1) == pi assert arg(I) == pi/2 assert arg(-I) == -pi/2 assert arg(1 + I) == pi/4 assert arg(-1 + I) == pi*Rational(3, 4) assert arg(1 - I) == -pi/4 assert arg(exp_polar(4*pi*I)) == 4*pi assert arg(exp_polar(-7*pi*I)) == -7*pi assert arg(exp_polar(5 - 3*pi*I/4)) == pi*Rational(-3, 4) f = Function('f') assert not arg(f(0) + I*f(1)).atoms(re) x = Symbol('x') p = Function('p', extended_positive=True) assert arg(p(x)) == 0 assert arg((3 + I)*p(x)) == arg(3 + I) p = Symbol('p', positive=True) assert arg(p) == 0 n = Symbol('n', negative=True) assert arg(n) == pi x = Symbol('x') assert conjugate(arg(x)) == arg(x) e = p + I*p**2 assert arg(e) == arg(1 + p*I) # make sure sign doesn't swap e = -2*p + 4*I*p**2 assert arg(e) == arg(-1 + 2*p*I) # make sure sign isn't lost x = symbols('x', real=True) # could be zero e = x + I*x assert arg(e) == arg(x*(1 + I)) assert arg(e/p) == arg(x*(1 + I)) e = p*cos(p) + I*log(p)*exp(p) assert arg(e).args[0] == e # keep it simple -- let the user do more advanced cancellation e = (p + 1) + I*(p**2 - 1) assert arg(e).args[0] == e f = Function('f') e = 2*x*(f(0) - 1) - 2*x*f(0) assert arg(e) == arg(-2*x) assert arg(f(0)).func == arg and arg(f(0)).args == (f(0),) def test_arg_rewrite(): assert arg(1 + I) == atan2(1, 1) x = Symbol('x', real=True) y = Symbol('y', real=True) assert arg(x + I*y).rewrite(atan2) == atan2(y, x) def test_adjoint(): a = Symbol('a', antihermitian=True) b = Symbol('b', hermitian=True) assert adjoint(a) == -a assert adjoint(I*a) == I*a assert adjoint(b) == b assert adjoint(I*b) == -I*b assert adjoint(a*b) == -b*a assert adjoint(I*a*b) == I*b*a x, y = symbols('x y') assert adjoint(adjoint(x)) == x assert adjoint(x + y) == adjoint(x) + adjoint(y) assert adjoint(x - y) == adjoint(x) - adjoint(y) assert adjoint(x * y) == adjoint(x) * adjoint(y) assert adjoint(x / y) == adjoint(x) / adjoint(y) assert adjoint(-x) == -adjoint(x) x, y = symbols('x y', commutative=False) assert adjoint(adjoint(x)) == x assert adjoint(x + y) == adjoint(x) + adjoint(y) assert adjoint(x - y) == adjoint(x) - adjoint(y) assert adjoint(x * y) == adjoint(y) * adjoint(x) assert adjoint(x / y) == 1 / adjoint(y) * adjoint(x) assert adjoint(-x) == -adjoint(x) def test_conjugate(): a = Symbol('a', real=True) b = Symbol('b', imaginary=True) assert conjugate(a) == a assert conjugate(I*a) == -I*a assert conjugate(b) == -b assert conjugate(I*b) == I*b assert conjugate(a*b) == -a*b assert conjugate(I*a*b) == I*a*b x, y = symbols('x y') assert conjugate(conjugate(x)) == x assert conjugate(x + y) == conjugate(x) + conjugate(y) assert conjugate(x - y) == conjugate(x) - conjugate(y) assert conjugate(x * y) == conjugate(x) * conjugate(y) assert conjugate(x / y) == conjugate(x) / conjugate(y) assert conjugate(-x) == -conjugate(x) a = Symbol('a', algebraic=True) t = Symbol('t', transcendental=True) assert re(a).is_algebraic assert re(x).is_algebraic is None assert re(t).is_algebraic is False def test_conjugate_transpose(): x = Symbol('x') assert conjugate(transpose(x)) == adjoint(x) assert transpose(conjugate(x)) == adjoint(x) assert adjoint(transpose(x)) == conjugate(x) assert transpose(adjoint(x)) == conjugate(x) assert adjoint(conjugate(x)) == transpose(x) assert conjugate(adjoint(x)) == transpose(x) class Symmetric(Expr): def _eval_adjoint(self): return None def _eval_conjugate(self): return None def _eval_transpose(self): return self x = Symmetric() assert conjugate(x) == adjoint(x) assert transpose(x) == x def test_transpose(): a = Symbol('a', complex=True) assert transpose(a) == a assert transpose(I*a) == I*a x, y = symbols('x y') assert transpose(transpose(x)) == x assert transpose(x + y) == transpose(x) + transpose(y) assert transpose(x - y) == transpose(x) - transpose(y) assert transpose(x * y) == transpose(x) * transpose(y) assert transpose(x / y) == transpose(x) / transpose(y) assert transpose(-x) == -transpose(x) x, y = symbols('x y', commutative=False) assert transpose(transpose(x)) == x assert transpose(x + y) == transpose(x) + transpose(y) assert transpose(x - y) == transpose(x) - transpose(y) assert transpose(x * y) == transpose(y) * transpose(x) assert transpose(x / y) == 1 / transpose(y) * transpose(x) assert transpose(-x) == -transpose(x) @_both_exp_pow def test_polarify(): from sympy import polar_lift, polarify x = Symbol('x') z = Symbol('z', polar=True) f = Function('f') ES = {} assert polarify(-1) == (polar_lift(-1), ES) assert polarify(1 + I) == (polar_lift(1 + I), ES) assert polarify(exp(x), subs=False) == exp(x) assert polarify(1 + x, subs=False) == 1 + x assert polarify(f(I) + x, subs=False) == f(polar_lift(I)) + x assert polarify(x, lift=True) == polar_lift(x) assert polarify(z, lift=True) == z assert polarify(f(x), lift=True) == f(polar_lift(x)) assert polarify(1 + x, lift=True) == polar_lift(1 + x) assert polarify(1 + f(x), lift=True) == polar_lift(1 + f(polar_lift(x))) newex, subs = polarify(f(x) + z) assert newex.subs(subs) == f(x) + z mu = Symbol("mu") sigma = Symbol("sigma", positive=True) # Make sure polarify(lift=True) doesn't try to lift the integration # variable assert polarify( Integral(sqrt(2)*x*exp(-(-mu + x)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (x, -oo, oo)), lift=True) == Integral(sqrt(2)*(sigma*exp_polar(0))**exp_polar(I*pi)* exp((sigma*exp_polar(0))**(2*exp_polar(I*pi))*exp_polar(I*pi)*polar_lift(-mu + x)** (2*exp_polar(0))/2)*exp_polar(0)*polar_lift(x)/(2*sqrt(pi)), (x, -oo, oo)) def test_unpolarify(): from sympy import (exp_polar, polar_lift, exp, unpolarify, principal_branch) from sympy import gamma, erf, sin, tanh, uppergamma, Eq, Ne from sympy.abc import x p = exp_polar(7*I) + 1 u = exp(7*I) + 1 assert unpolarify(1) == 1 assert unpolarify(p) == u assert unpolarify(p**2) == u**2 assert unpolarify(p**x) == p**x assert unpolarify(p*x) == u*x assert unpolarify(p + x) == u + x assert unpolarify(sqrt(sin(p))) == sqrt(sin(u)) # Test reduction to principal branch 2*pi. t = principal_branch(x, 2*pi) assert unpolarify(t) == x assert unpolarify(sqrt(t)) == sqrt(t) # Test exponents_only. assert unpolarify(p**p, exponents_only=True) == p**u assert unpolarify(uppergamma(x, p**p)) == uppergamma(x, p**u) # Test functions. assert unpolarify(sin(p)) == sin(u) assert unpolarify(tanh(p)) == tanh(u) assert unpolarify(gamma(p)) == gamma(u) assert unpolarify(erf(p)) == erf(u) assert unpolarify(uppergamma(x, p)) == uppergamma(x, p) assert unpolarify(uppergamma(sin(p), sin(p + exp_polar(0)))) == \ uppergamma(sin(u), sin(u + 1)) assert unpolarify(uppergamma(polar_lift(0), 2*exp_polar(0))) == \ uppergamma(0, 2) assert unpolarify(Eq(p, 0)) == Eq(u, 0) assert unpolarify(Ne(p, 0)) == Ne(u, 0) assert unpolarify(polar_lift(x) > 0) == (x > 0) # Test bools assert unpolarify(True) is True def test_issue_4035(): x = Symbol('x') assert Abs(x).expand(trig=True) == Abs(x) assert sign(x).expand(trig=True) == sign(x) assert arg(x).expand(trig=True) == arg(x) def test_issue_3206(): x = Symbol('x') assert Abs(Abs(x)) == Abs(x) def test_issue_4754_derivative_conjugate(): x = Symbol('x', real=True) y = Symbol('y', imaginary=True) f = Function('f') assert (f(x).conjugate()).diff(x) == (f(x).diff(x)).conjugate() assert (f(y).conjugate()).diff(y) == -(f(y).diff(y)).conjugate() def test_derivatives_issue_4757(): x = Symbol('x', real=True) y = Symbol('y', imaginary=True) f = Function('f') assert re(f(x)).diff(x) == re(f(x).diff(x)) assert im(f(x)).diff(x) == im(f(x).diff(x)) assert re(f(y)).diff(y) == -I*im(f(y).diff(y)) assert im(f(y)).diff(y) == -I*re(f(y).diff(y)) assert Abs(f(x)).diff(x).subs(f(x), 1 + I*x).doit() == x/sqrt(1 + x**2) assert arg(f(x)).diff(x).subs(f(x), 1 + I*x**2).doit() == 2*x/(1 + x**4) assert Abs(f(y)).diff(y).subs(f(y), 1 + y).doit() == -y/sqrt(1 - y**2) assert arg(f(y)).diff(y).subs(f(y), I + y**2).doit() == 2*y/(1 + y**4) def test_issue_11413(): from sympy import Matrix, simplify v0 = Symbol('v0') v1 = Symbol('v1') v2 = Symbol('v2') V = Matrix([[v0],[v1],[v2]]) U = V.normalized() assert U == Matrix([ [v0/sqrt(Abs(v0)**2 + Abs(v1)**2 + Abs(v2)**2)], [v1/sqrt(Abs(v0)**2 + Abs(v1)**2 + Abs(v2)**2)], [v2/sqrt(Abs(v0)**2 + Abs(v1)**2 + Abs(v2)**2)]]) U.norm = sqrt(v0**2/(v0**2 + v1**2 + v2**2) + v1**2/(v0**2 + v1**2 + v2**2) + v2**2/(v0**2 + v1**2 + v2**2)) assert simplify(U.norm) == 1 def test_periodic_argument(): from sympy import (periodic_argument, unbranched_argument, oo, principal_branch, polar_lift, pi) x = Symbol('x') p = Symbol('p', positive=True) assert unbranched_argument(2 + I) == periodic_argument(2 + I, oo) assert unbranched_argument(1 + x) == periodic_argument(1 + x, oo) assert N_equals(unbranched_argument((1 + I)**2), pi/2) assert N_equals(unbranched_argument((1 - I)**2), -pi/2) assert N_equals(periodic_argument((1 + I)**2, 3*pi), pi/2) assert N_equals(periodic_argument((1 - I)**2, 3*pi), -pi/2) assert unbranched_argument(principal_branch(x, pi)) == \ periodic_argument(x, pi) assert unbranched_argument(polar_lift(2 + I)) == unbranched_argument(2 + I) assert periodic_argument(polar_lift(2 + I), 2*pi) == \ periodic_argument(2 + I, 2*pi) assert periodic_argument(polar_lift(2 + I), 3*pi) == \ periodic_argument(2 + I, 3*pi) assert periodic_argument(polar_lift(2 + I), pi) == \ periodic_argument(polar_lift(2 + I), pi) assert unbranched_argument(polar_lift(1 + I)) == pi/4 assert periodic_argument(2*p, p) == periodic_argument(p, p) assert periodic_argument(pi*p, p) == periodic_argument(p, p) assert Abs(polar_lift(1 + I)) == Abs(1 + I) @XFAIL def test_principal_branch_fail(): # TODO XXX why does abs(x)._eval_evalf() not fall back to global evalf? from sympy import principal_branch assert N_equals(principal_branch((1 + I)**2, pi/2), 0) def test_principal_branch(): from sympy import principal_branch, polar_lift, exp_polar p = Symbol('p', positive=True) x = Symbol('x') neg = Symbol('x', negative=True) assert principal_branch(polar_lift(x), p) == principal_branch(x, p) assert principal_branch(polar_lift(2 + I), p) == principal_branch(2 + I, p) assert principal_branch(2*x, p) == 2*principal_branch(x, p) assert principal_branch(1, pi) == exp_polar(0) assert principal_branch(-1, 2*pi) == exp_polar(I*pi) assert principal_branch(-1, pi) == exp_polar(0) assert principal_branch(exp_polar(3*pi*I)*x, 2*pi) == \ principal_branch(exp_polar(I*pi)*x, 2*pi) assert principal_branch(neg*exp_polar(pi*I), 2*pi) == neg*exp_polar(-I*pi) # related to issue #14692 assert principal_branch(exp_polar(-I*pi/2)/polar_lift(neg), 2*pi) == \ exp_polar(-I*pi/2)/neg assert N_equals(principal_branch((1 + I)**2, 2*pi), 2*I) assert N_equals(principal_branch((1 + I)**2, 3*pi), 2*I) assert N_equals(principal_branch((1 + I)**2, 1*pi), 2*I) # test argument sanitization assert principal_branch(x, I).func is principal_branch assert principal_branch(x, -4).func is principal_branch assert principal_branch(x, -oo).func is principal_branch assert principal_branch(x, zoo).func is principal_branch @XFAIL def test_issue_6167_6151(): n = pi**1000 i = int(n) assert sign(n - i) == 1 assert abs(n - i) == n - i x = Symbol('x') eps = pi**-1500 big = pi**1000 one = cos(x)**2 + sin(x)**2 e = big*one - big + eps from sympy import simplify assert sign(simplify(e)) == 1 for xi in (111, 11, 1, Rational(1, 10)): assert sign(e.subs(x, xi)) == 1 def test_issue_14216(): from sympy.functions.elementary.complexes import unpolarify A = MatrixSymbol("A", 2, 2) assert unpolarify(A[0, 0]) == A[0, 0] assert unpolarify(A[0, 0]*A[1, 0]) == A[0, 0]*A[1, 0] def test_issue_14238(): # doesn't cause recursion error r = Symbol('r', real=True) assert Abs(r + Piecewise((0, r > 0), (1 - r, True))) def test_zero_assumptions(): nr = Symbol('nonreal', real=False, finite=True) ni = Symbol('nonimaginary', imaginary=False) # imaginary implies not zero nzni = Symbol('nonzerononimaginary', zero=False, imaginary=False) assert re(nr).is_zero is None assert im(nr).is_zero is False assert re(ni).is_zero is None assert im(ni).is_zero is None assert re(nzni).is_zero is False assert im(nzni).is_zero is None @_both_exp_pow def test_issue_15893(): f = Function('f', real=True) x = Symbol('x', real=True) eq = Derivative(Abs(f(x)), f(x)) assert eq.doit() == sign(f(x)) sympy-sympy-1.9/sympy/functions/elementary/tests/test_exponential.py000066400000000000000000000604061412543434000263700ustar00rootroot00000000000000from sympy import ( symbols, log, ln, Float, nan, oo, zoo, I, pi, E, exp, Symbol, LambertW, sqrt, Rational, expand_log, S, sign, adjoint, conjugate, transpose, O, refine, sin, cos, sinh, cosh, tanh, exp_polar, re, simplify, AccumBounds, MatrixSymbol, Pow, gcd, Sum, Product) from sympy.core.parameters import global_parameters from sympy.functions.elementary.exponential import match_real_imag from sympy.abc import x, y, z from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.testing.pytest import raises, XFAIL, _both_exp_pow @_both_exp_pow def test_exp_values(): if global_parameters.exp_is_pow: assert type(exp(x)) is Pow else: assert type(exp(x)) is exp k = Symbol('k', integer=True) assert exp(nan) is nan assert exp(oo) is oo assert exp(-oo) == 0 assert exp(0) == 1 assert exp(1) == E assert exp(-1 + x).as_base_exp() == (S.Exp1, x - 1) assert exp(1 + x).as_base_exp() == (S.Exp1, x + 1) assert exp(pi*I/2) == I assert exp(pi*I) == -1 assert exp(pi*I*Rational(3, 2)) == -I assert exp(2*pi*I) == 1 assert refine(exp(pi*I*2*k)) == 1 assert refine(exp(pi*I*2*(k + S.Half))) == -1 assert refine(exp(pi*I*2*(k + Rational(1, 4)))) == I assert refine(exp(pi*I*2*(k + Rational(3, 4)))) == -I assert exp(log(x)) == x assert exp(2*log(x)) == x**2 assert exp(pi*log(x)) == x**pi assert exp(17*log(x) + E*log(y)) == x**17 * y**E assert exp(x*log(x)) != x**x assert exp(sin(x)*log(x)) != x assert exp(3*log(x) + oo*x) == exp(oo*x) * x**3 assert exp(4*log(x)*log(y) + 3*log(x)) == x**3 * exp(4*log(x)*log(y)) assert exp(-oo, evaluate=False).is_finite is True assert exp(oo, evaluate=False).is_finite is False @_both_exp_pow def test_exp_period(): assert exp(I*pi*Rational(9, 4)) == exp(I*pi/4) assert exp(I*pi*Rational(46, 18)) == exp(I*pi*Rational(5, 9)) assert exp(I*pi*Rational(25, 7)) == exp(I*pi*Rational(-3, 7)) assert exp(I*pi*Rational(-19, 3)) == exp(-I*pi/3) assert exp(I*pi*Rational(37, 8)) - exp(I*pi*Rational(-11, 8)) == 0 assert exp(I*pi*Rational(-5, 3)) / exp(I*pi*Rational(11, 5)) * exp(I*pi*Rational(148, 15)) == 1 assert exp(2 - I*pi*Rational(17, 5)) == exp(2 + I*pi*Rational(3, 5)) assert exp(log(3) + I*pi*Rational(29, 9)) == 3 * exp(I*pi*Rational(-7, 9)) n = Symbol('n', integer=True) e = Symbol('e', even=True) assert exp(e*I*pi) == 1 assert exp((e + 1)*I*pi) == -1 assert exp((1 + 4*n)*I*pi/2) == I assert exp((-1 + 4*n)*I*pi/2) == -I @_both_exp_pow def test_exp_log(): x = Symbol("x", real=True) assert log(exp(x)) == x assert exp(log(x)) == x if not global_parameters.exp_is_pow: assert log(x).inverse() == exp assert exp(x).inverse() == log y = Symbol("y", polar=True) assert log(exp_polar(z)) == z assert exp(log(y)) == y @_both_exp_pow def test_exp_expand(): e = exp(log(Rational(2))*(1 + x) - log(Rational(2))*x) assert e.expand() == 2 assert exp(x + y) != exp(x)*exp(y) assert exp(x + y).expand() == exp(x)*exp(y) @_both_exp_pow def test_exp__as_base_exp(): assert exp(x).as_base_exp() == (E, x) assert exp(2*x).as_base_exp() == (E, 2*x) assert exp(x*y).as_base_exp() == (E, x*y) assert exp(-x).as_base_exp() == (E, -x) # Pow( *expr.as_base_exp() ) == expr invariant should hold assert E**x == exp(x) assert E**(2*x) == exp(2*x) assert E**(x*y) == exp(x*y) assert exp(x).base is S.Exp1 assert exp(x).exp == x @_both_exp_pow def test_exp_infinity(): assert exp(I*y) != nan assert refine(exp(I*oo)) is nan assert refine(exp(-I*oo)) is nan assert exp(y*I*oo) != nan assert exp(zoo) is nan x = Symbol('x', extended_real=True, finite=False) assert exp(x).is_complex is None @_both_exp_pow def test_exp_subs(): x = Symbol('x') e = (exp(3*log(x), evaluate=False)) # evaluates to x**3 assert e.subs(x**3, y**3) == e assert e.subs(x**2, 5) == e assert (x**3).subs(x**2, y) != y**Rational(3, 2) assert exp(exp(x) + exp(x**2)).subs(exp(exp(x)), y) == y * exp(exp(x**2)) assert exp(x).subs(E, y) == y**x x = symbols('x', real=True) assert exp(5*x).subs(exp(7*x), y) == y**Rational(5, 7) assert exp(2*x + 7).subs(exp(3*x), y) == y**Rational(2, 3) * exp(7) x = symbols('x', positive=True) assert exp(3*log(x)).subs(x**2, y) == y**Rational(3, 2) # differentiate between E and exp assert exp(exp(x + E)).subs(exp, 3) == 3**(3**(x + E)) assert exp(exp(x + E)).subs(exp, sin) == sin(sin(x + E)) assert exp(exp(x + E)).subs(E, 3) == 3**(3**(x + 3)) assert exp(3).subs(E, sin) == sin(3) def test_exp_adjoint(): assert adjoint(exp(x)) == exp(adjoint(x)) def test_exp_conjugate(): assert conjugate(exp(x)) == exp(conjugate(x)) @_both_exp_pow def test_exp_transpose(): assert transpose(exp(x)) == exp(transpose(x)) @_both_exp_pow def test_exp_rewrite(): from sympy.concrete.summations import Sum assert exp(x).rewrite(sin) == sinh(x) + cosh(x) assert exp(x*I).rewrite(cos) == cos(x) + I*sin(x) assert exp(1).rewrite(cos) == sinh(1) + cosh(1) assert exp(1).rewrite(sin) == sinh(1) + cosh(1) assert exp(1).rewrite(sin) == sinh(1) + cosh(1) assert exp(x).rewrite(tanh) == (1 + tanh(x/2))/(1 - tanh(x/2)) assert exp(pi*I/4).rewrite(sqrt) == sqrt(2)/2 + sqrt(2)*I/2 assert exp(pi*I/3).rewrite(sqrt) == S.Half + sqrt(3)*I/2 if not global_parameters.exp_is_pow: assert exp(x*log(y)).rewrite(Pow) == y**x assert exp(log(x)*log(y)).rewrite(Pow) in [x**log(y), y**log(x)] assert exp(log(log(x))*y).rewrite(Pow) == log(x)**y n = Symbol('n', integer=True) assert Sum((exp(pi*I/2)/2)**n, (n, 0, oo)).rewrite(sqrt).doit() == Rational(4, 5) + I*Rational(2, 5) assert Sum((exp(pi*I/4)/2)**n, (n, 0, oo)).rewrite(sqrt).doit() == 1/(1 - sqrt(2)*(1 + I)/4) assert (Sum((exp(pi*I/3)/2)**n, (n, 0, oo)).rewrite(sqrt).doit().cancel() == 4*I/(sqrt(3) + 3*I)) @_both_exp_pow def test_exp_leading_term(): assert exp(x).as_leading_term(x) == 1 assert exp(2 + x).as_leading_term(x) == exp(2) assert exp((2*x + 3) / (x+1)).as_leading_term(x) == exp(3) # The following tests are commented, since now SymPy returns the # original function when the leading term in the series expansion does # not exist. # raises(NotImplementedError, lambda: exp(1/x).as_leading_term(x)) # raises(NotImplementedError, lambda: exp((x + 1) / x**2).as_leading_term(x)) # raises(NotImplementedError, lambda: exp(x + 1/x).as_leading_term(x)) @_both_exp_pow def test_exp_taylor_term(): x = symbols('x') assert exp(x).taylor_term(1, x) == x assert exp(x).taylor_term(3, x) == x**3/6 assert exp(x).taylor_term(4, x) == x**4/24 assert exp(x).taylor_term(-1, x) is S.Zero def test_exp_MatrixSymbol(): A = MatrixSymbol("A", 2, 2) assert exp(A).has(exp) def test_exp_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: exp(x).fdiff(2)) def test_log_values(): assert log(nan) is nan assert log(oo) is oo assert log(-oo) is oo assert log(zoo) is zoo assert log(-zoo) is zoo assert log(0) is zoo assert log(1) == 0 assert log(-1) == I*pi assert log(E) == 1 assert log(-E).expand() == 1 + I*pi assert unchanged(log, pi) assert log(-pi).expand() == log(pi) + I*pi assert unchanged(log, 17) assert log(-17) == log(17) + I*pi assert log(I) == I*pi/2 assert log(-I) == -I*pi/2 assert log(17*I) == I*pi/2 + log(17) assert log(-17*I).expand() == -I*pi/2 + log(17) assert log(oo*I) is oo assert log(-oo*I) is oo assert log(0, 2) is zoo assert log(0, 5) is zoo assert exp(-log(3))**(-1) == 3 assert log(S.Half) == -log(2) assert log(2*3).func is log assert log(2*3**2).func is log def test_match_real_imag(): x, y = symbols('x,y', real=True) i = Symbol('i', imaginary=True) assert match_real_imag(S.One) == (1, 0) assert match_real_imag(I) == (0, 1) assert match_real_imag(3 - 5*I) == (3, -5) assert match_real_imag(-sqrt(3) + S.Half*I) == (-sqrt(3), S.Half) assert match_real_imag(x + y*I) == (x, y) assert match_real_imag(x*I + y*I) == (0, x + y) assert match_real_imag((x + y)*I) == (0, x + y) assert match_real_imag(Rational(-2, 3)*i*I) == (None, None) assert match_real_imag(1 - 2*i) == (None, None) assert match_real_imag(sqrt(2)*(3 - 5*I)) == (None, None) def test_log_exact(): # check for pi/2, pi/3, pi/4, pi/6, pi/8, pi/12; pi/5, pi/10: for n in range(-23, 24): if gcd(n, 24) != 1: assert log(exp(n*I*pi/24).rewrite(sqrt)) == n*I*pi/24 for n in range(-9, 10): assert log(exp(n*I*pi/10).rewrite(sqrt)) == n*I*pi/10 assert log(S.Half - I*sqrt(3)/2) == -I*pi/3 assert log(Rational(-1, 2) + I*sqrt(3)/2) == I*pi*Rational(2, 3) assert log(-sqrt(2)/2 - I*sqrt(2)/2) == -I*pi*Rational(3, 4) assert log(-sqrt(3)/2 - I*S.Half) == -I*pi*Rational(5, 6) assert log(Rational(-1, 4) + sqrt(5)/4 - I*sqrt(sqrt(5)/8 + Rational(5, 8))) == -I*pi*Rational(2, 5) assert log(sqrt(Rational(5, 8) - sqrt(5)/8) + I*(Rational(1, 4) + sqrt(5)/4)) == I*pi*Rational(3, 10) assert log(-sqrt(sqrt(2)/4 + S.Half) + I*sqrt(S.Half - sqrt(2)/4)) == I*pi*Rational(7, 8) assert log(-sqrt(6)/4 - sqrt(2)/4 + I*(-sqrt(6)/4 + sqrt(2)/4)) == -I*pi*Rational(11, 12) assert log(-1 + I*sqrt(3)) == log(2) + I*pi*Rational(2, 3) assert log(5 + 5*I) == log(5*sqrt(2)) + I*pi/4 assert log(sqrt(-12)) == log(2*sqrt(3)) + I*pi/2 assert log(-sqrt(6) + sqrt(2) - I*sqrt(6) - I*sqrt(2)) == log(4) - I*pi*Rational(7, 12) assert log(-sqrt(6-3*sqrt(2)) - I*sqrt(6+3*sqrt(2))) == log(2*sqrt(3)) - I*pi*Rational(5, 8) assert log(1 + I*sqrt(2-sqrt(2))/sqrt(2+sqrt(2))) == log(2/sqrt(sqrt(2) + 2)) + I*pi/8 assert log(cos(pi*Rational(7, 12)) + I*sin(pi*Rational(7, 12))) == I*pi*Rational(7, 12) assert log(cos(pi*Rational(6, 5)) + I*sin(pi*Rational(6, 5))) == I*pi*Rational(-4, 5) assert log(5*(1 + I)/sqrt(2)) == log(5) + I*pi/4 assert log(sqrt(2)*(-sqrt(3) + 1 - sqrt(3)*I - I)) == log(4) - I*pi*Rational(7, 12) assert log(-sqrt(2)*(1 - I*sqrt(3))) == log(2*sqrt(2)) + I*pi*Rational(2, 3) assert log(sqrt(3)*I*(-sqrt(6 - 3*sqrt(2)) - I*sqrt(3*sqrt(2) + 6))) == log(6) - I*pi/8 zero = (1 + sqrt(2))**2 - 3 - 2*sqrt(2) assert log(zero - I*sqrt(3)) == log(sqrt(3)) - I*pi/2 assert unchanged(log, zero + I*zero) or log(zero + zero*I) is zoo # bail quickly if no obvious simplification is possible: assert unchanged(log, (sqrt(2)-1/sqrt(sqrt(3)+I))**1000) # beware of non-real coefficients assert unchanged(log, sqrt(2-sqrt(5))*(1 + I)) def test_log_base(): assert log(1, 2) == 0 assert log(2, 2) == 1 assert log(3, 2) == log(3)/log(2) assert log(6, 2) == 1 + log(3)/log(2) assert log(6, 3) == 1 + log(2)/log(3) assert log(2**3, 2) == 3 assert log(3**3, 3) == 3 assert log(5, 1) is zoo assert log(1, 1) is nan assert log(Rational(2, 3), 10) == log(Rational(2, 3))/log(10) assert log(Rational(2, 3), Rational(1, 3)) == -log(2)/log(3) + 1 assert log(Rational(2, 3), Rational(2, 5)) == \ log(Rational(2, 3))/log(Rational(2, 5)) # issue 17148 assert log(Rational(8, 3), 2) == -log(3)/log(2) + 3 def test_log_symbolic(): assert log(x, exp(1)) == log(x) assert log(exp(x)) != x assert log(x, exp(1)) == log(x) assert log(x*y) != log(x) + log(y) assert log(x/y).expand() != log(x) - log(y) assert log(x/y).expand(force=True) == log(x) - log(y) assert log(x**y).expand() != y*log(x) assert log(x**y).expand(force=True) == y*log(x) assert log(x, 2) == log(x)/log(2) assert log(E, 2) == 1/log(2) p, q = symbols('p,q', positive=True) r = Symbol('r', real=True) assert log(p**2) != 2*log(p) assert log(p**2).expand() == 2*log(p) assert log(x**2).expand() != 2*log(x) assert log(p**q) != q*log(p) assert log(exp(p)) == p assert log(p*q) != log(p) + log(q) assert log(p*q).expand() == log(p) + log(q) assert log(-sqrt(3)) == log(sqrt(3)) + I*pi assert log(-exp(p)) != p + I*pi assert log(-exp(x)).expand() != x + I*pi assert log(-exp(r)).expand() == r + I*pi assert log(x**y) != y*log(x) assert (log(x**-5)**-1).expand() != -1/log(x)/5 assert (log(p**-5)**-1).expand() == -1/log(p)/5 assert log(-x).func is log and log(-x).args[0] == -x assert log(-p).func is log and log(-p).args[0] == -p def test_log_exp(): assert log(exp(4*I*pi)) == 0 # exp evaluates assert log(exp(-5*I*pi)) == I*pi # exp evaluates assert log(exp(I*pi*Rational(19, 4))) == I*pi*Rational(3, 4) assert log(exp(I*pi*Rational(25, 7))) == I*pi*Rational(-3, 7) assert log(exp(-5*I)) == -5*I + 2*I*pi @_both_exp_pow def test_exp_assumptions(): r = Symbol('r', real=True) i = Symbol('i', imaginary=True) for e in exp, exp_polar: assert e(x).is_real is None assert e(x).is_imaginary is None assert e(i).is_real is None assert e(i).is_imaginary is None assert e(r).is_real is True assert e(r).is_imaginary is False assert e(re(x)).is_extended_real is True assert e(re(x)).is_imaginary is False assert Pow(E, I*pi, evaluate=False).is_imaginary == False assert Pow(E, 2*I*pi, evaluate=False).is_imaginary == False assert Pow(E, I*pi/2, evaluate=False).is_imaginary == True assert Pow(E, I*pi/3, evaluate=False).is_imaginary is None assert exp(0, evaluate=False).is_algebraic a = Symbol('a', algebraic=True) an = Symbol('an', algebraic=True, nonzero=True) r = Symbol('r', rational=True) rn = Symbol('rn', rational=True, nonzero=True) assert exp(a).is_algebraic is None assert exp(an).is_algebraic is False assert exp(pi*r).is_algebraic is None assert exp(pi*rn).is_algebraic is False assert exp(0, evaluate=False).is_algebraic is True assert exp(I*pi/3, evaluate=False).is_algebraic is True assert exp(I*pi*r, evaluate=False).is_algebraic is True @_both_exp_pow def test_exp_AccumBounds(): assert exp(AccumBounds(1, 2)) == AccumBounds(E, E**2) def test_log_assumptions(): p = symbols('p', positive=True) n = symbols('n', negative=True) z = symbols('z', zero=True) x = symbols('x', infinite=True, extended_positive=True) assert log(z).is_positive is False assert log(x).is_extended_positive is True assert log(2) > 0 assert log(1, evaluate=False).is_zero assert log(1 + z).is_zero assert log(p).is_zero is None assert log(n).is_zero is False assert log(0.5).is_negative is True assert log(exp(p) + 1).is_positive assert log(1, evaluate=False).is_algebraic assert log(42, evaluate=False).is_algebraic is False assert log(1 + z).is_rational def test_log_hashing(): assert x != log(log(x)) assert hash(x) != hash(log(log(x))) assert log(x) != log(log(log(x))) e = 1/log(log(x) + log(log(x))) assert e.base.func is log e = 1/log(log(x) + log(log(log(x)))) assert e.base.func is log e = log(log(x)) assert e.func is log assert not x.func is log assert hash(log(log(x))) != hash(x) assert e != x def test_log_sign(): assert sign(log(2)) == 1 def test_log_expand_complex(): assert log(1 + I).expand(complex=True) == log(2)/2 + I*pi/4 assert log(1 - sqrt(2)).expand(complex=True) == log(sqrt(2) - 1) + I*pi def test_log_apply_evalf(): value = (log(3)/log(2) - 1).evalf() assert value.epsilon_eq(Float("0.58496250072115618145373")) def test_log_nseries(): assert log(x - 1)._eval_nseries(x, 4, None, I) == I*pi - x - x**2/2 - x**3/3 + O(x**4) assert log(x - 1)._eval_nseries(x, 4, None, -I) == -I*pi - x - x**2/2 - x**3/3 + O(x**4) assert log(I*x + I*x**3 - 1)._eval_nseries(x, 3, None, 1) == I*pi - I*x + x**2/2 + O(x**3) assert log(I*x + I*x**3 - 1)._eval_nseries(x, 3, None, -1) == -I*pi - I*x + x**2/2 + O(x**3) assert log(I*x**2 + I*x**3 - 1)._eval_nseries(x, 3, None, 1) == I*pi - I*x**2 + O(x**3) assert log(I*x**2 + I*x**3 - 1)._eval_nseries(x, 3, None, -1) == I*pi - I*x**2 + O(x**3) def test_log_expand(): w = Symbol("w", positive=True) e = log(w**(log(5)/log(3))) assert e.expand() == log(5)/log(3) * log(w) x, y, z = symbols('x,y,z', positive=True) assert log(x*(y + z)).expand(mul=False) == log(x) + log(y + z) assert log(log(x**2)*log(y*z)).expand() in [log(2*log(x)*log(y) + 2*log(x)*log(z)), log(log(x)*log(z) + log(y)*log(x)) + log(2), log((log(y) + log(z))*log(x)) + log(2)] assert log(x**log(x**2)).expand(deep=False) == log(x)*log(x**2) assert log(x**log(x**2)).expand() == 2*log(x)**2 x, y = symbols('x,y') assert log(x*y).expand(force=True) == log(x) + log(y) assert log(x**y).expand(force=True) == y*log(x) assert log(exp(x)).expand(force=True) == x # there's generally no need to expand out logs since this requires # factoring and if simplification is sought, it's cheaper to put # logs together than it is to take them apart. assert log(2*3**2).expand() != 2*log(3) + log(2) @XFAIL def test_log_expand_fail(): x, y, z = symbols('x,y,z', positive=True) assert (log(x*(y + z))*(x + y)).expand(mul=True, log=True) == y*log( x) + y*log(y + z) + z*log(x) + z*log(y + z) def test_log_simplify(): x = Symbol("x", positive=True) assert log(x**2).expand() == 2*log(x) assert expand_log(log(x**(2 + log(2)))) == (2 + log(2))*log(x) z = Symbol('z') assert log(sqrt(z)).expand() == log(z)/2 assert expand_log(log(z**(log(2) - 1))) == (log(2) - 1)*log(z) assert log(z**(-1)).expand() != -log(z) assert log(z**(x/(x+1))).expand() == x*log(z)/(x + 1) def test_log_AccumBounds(): assert log(AccumBounds(1, E)) == AccumBounds(0, 1) @_both_exp_pow def test_lambertw(): k = Symbol('k') assert LambertW(x, 0) == LambertW(x) assert LambertW(x, 0, evaluate=False) != LambertW(x) assert LambertW(0) == 0 assert LambertW(E) == 1 assert LambertW(-1/E) == -1 assert LambertW(-log(2)/2) == -log(2) assert LambertW(oo) is oo assert LambertW(0, 1) is -oo assert LambertW(0, 42) is -oo assert LambertW(-pi/2, -1) == -I*pi/2 assert LambertW(-1/E, -1) == -1 assert LambertW(-2*exp(-2), -1) == -2 assert LambertW(2*log(2)) == log(2) assert LambertW(-pi/2) == I*pi/2 assert LambertW(exp(1 + E)) == E assert LambertW(x**2).diff(x) == 2*LambertW(x**2)/x/(1 + LambertW(x**2)) assert LambertW(x, k).diff(x) == LambertW(x, k)/x/(1 + LambertW(x, k)) assert LambertW(sqrt(2)).evalf(30).epsilon_eq( Float("0.701338383413663009202120278965", 30), 1e-29) assert re(LambertW(2, -1)).evalf().epsilon_eq(Float("-0.834310366631110")) assert LambertW(-1).is_real is False # issue 5215 assert LambertW(2, evaluate=False).is_real p = Symbol('p', positive=True) assert LambertW(p, evaluate=False).is_real assert LambertW(p - 1, evaluate=False).is_real is None assert LambertW(-p - 2/S.Exp1, evaluate=False).is_real is False assert LambertW(S.Half, -1, evaluate=False).is_real is False assert LambertW(Rational(-1, 10), -1, evaluate=False).is_real assert LambertW(-10, -1, evaluate=False).is_real is False assert LambertW(-2, 2, evaluate=False).is_real is False assert LambertW(0, evaluate=False).is_algebraic na = Symbol('na', nonzero=True, algebraic=True) assert LambertW(na).is_algebraic is False def test_issue_5673(): e = LambertW(-1) assert e.is_comparable is False assert e.is_positive is not True e2 = 1 - 1/(1 - exp(-1000)) assert e2.is_positive is not True e3 = -2 + exp(exp(LambertW(log(2)))*LambertW(log(2))) assert e3.is_nonzero is not True def test_log_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: log(x).fdiff(2)) def test_log_taylor_term(): x = symbols('x') assert log(x).taylor_term(0, x) == x assert log(x).taylor_term(1, x) == -x**2/2 assert log(x).taylor_term(4, x) == x**5/5 assert log(x).taylor_term(-1, x) is S.Zero def test_exp_expand_NC(): A, B, C = symbols('A,B,C', commutative=False) assert exp(A + B).expand() == exp(A + B) assert exp(A + B + C).expand() == exp(A + B + C) assert exp(x + y).expand() == exp(x)*exp(y) assert exp(x + y + z).expand() == exp(x)*exp(y)*exp(z) @_both_exp_pow def test_as_numer_denom(): n = symbols('n', negative=True) assert exp(x).as_numer_denom() == (exp(x), 1) assert exp(-x).as_numer_denom() == (1, exp(x)) assert exp(-2*x).as_numer_denom() == (1, exp(2*x)) assert exp(-2).as_numer_denom() == (1, exp(2)) assert exp(n).as_numer_denom() == (1, exp(-n)) assert exp(-n).as_numer_denom() == (exp(-n), 1) assert exp(-I*x).as_numer_denom() == (1, exp(I*x)) assert exp(-I*n).as_numer_denom() == (1, exp(I*n)) assert exp(-n).as_numer_denom() == (exp(-n), 1) @_both_exp_pow def test_polar(): x, y = symbols('x y', polar=True) assert abs(exp_polar(I*4)) == 1 assert abs(exp_polar(0)) == 1 assert abs(exp_polar(2 + 3*I)) == exp(2) assert exp_polar(I*10).n() == exp_polar(I*10) assert log(exp_polar(z)) == z assert log(x*y).expand() == log(x) + log(y) assert log(x**z).expand() == z*log(x) assert exp_polar(3).exp == 3 # Compare exp(1.0*pi*I). assert (exp_polar(1.0*pi*I).n(n=5)).as_real_imag()[1] >= 0 assert exp_polar(0).is_rational is True # issue 8008 def test_exp_summation(): w = symbols("w") m, n, i, j = symbols("m n i j") expr = exp(Sum(w*i, (i, 0, n), (j, 0, m))) assert expr.expand() == Product(exp(w*i), (i, 0, n), (j, 0, m)) def test_log_product(): from sympy.abc import n, m from sympy.concrete import Product i, j = symbols('i,j', positive=True, integer=True) x, y = symbols('x,y', positive=True) z = symbols('z', real=True) w = symbols('w') expr = log(Product(x**i, (i, 1, n))) assert simplify(expr) == expr assert expr.expand() == Sum(i*log(x), (i, 1, n)) expr = log(Product(x**i*y**j, (i, 1, n), (j, 1, m))) assert simplify(expr) == expr assert expr.expand() == Sum(i*log(x) + j*log(y), (i, 1, n), (j, 1, m)) expr = log(Product(-2, (n, 0, 4))) assert simplify(expr) == expr assert expr.expand() == expr assert expr.expand(force=True) == Sum(log(-2), (n, 0, 4)) expr = log(Product(exp(z*i), (i, 0, n))) assert expr.expand() == Sum(z*i, (i, 0, n)) expr = log(Product(exp(w*i), (i, 0, n))) assert expr.expand() == expr assert expr.expand(force=True) == Sum(w*i, (i, 0, n)) expr = log(Product(i**2*abs(j), (i, 1, n), (j, 1, m))) assert expr.expand() == Sum(2*log(i) + log(j), (i, 1, n), (j, 1, m)) @XFAIL def test_log_product_simplify_to_sum(): from sympy.abc import n, m i, j = symbols('i,j', positive=True, integer=True) x, y = symbols('x,y', positive=True) from sympy.concrete import Product, Sum assert simplify(log(Product(x**i, (i, 1, n)))) == Sum(i*log(x), (i, 1, n)) assert simplify(log(Product(x**i*y**j, (i, 1, n), (j, 1, m)))) == \ Sum(i*log(x) + j*log(y), (i, 1, n), (j, 1, m)) def test_issue_8866(): assert simplify(log(x, 10, evaluate=False)) == simplify(log(x, 10)) assert expand_log(log(x, 10, evaluate=False)) == expand_log(log(x, 10)) y = Symbol('y', positive=True) l1 = log(exp(y), exp(10)) b1 = log(exp(y), exp(5)) l2 = log(exp(y), exp(10), evaluate=False) b2 = log(exp(y), exp(5), evaluate=False) assert simplify(log(l1, b1)) == simplify(log(l2, b2)) assert expand_log(log(l1, b1)) == expand_log(log(l2, b2)) def test_log_expand_factor(): assert (log(18)/log(3) - 2).expand(factor=True) == log(2)/log(3) assert (log(12)/log(2)).expand(factor=True) == log(3)/log(2) + 2 assert (log(15)/log(3)).expand(factor=True) == 1 + log(5)/log(3) assert (log(2)/(-log(12) + log(24))).expand(factor=True) == 1 assert expand_log(log(12), factor=True) == log(3) + 2*log(2) assert expand_log(log(21)/log(7), factor=False) == log(3)/log(7) + 1 assert expand_log(log(45)/log(5) + log(20), factor=False) == \ 1 + 2*log(3)/log(5) + log(20) assert expand_log(log(45)/log(5) + log(26), factor=True) == \ log(2) + log(13) + (log(5) + 2*log(3))/log(5) def test_issue_9116(): n = Symbol('n', positive=True, integer=True) assert ln(n).is_nonnegative is True assert log(n).is_nonnegative is True sympy-sympy-1.9/sympy/functions/elementary/tests/test_hyperbolic.py000066400000000000000000001060311412543434000261750ustar00rootroot00000000000000from sympy import (symbols, Symbol, sinh, nan, oo, zoo, pi, asinh, acosh, log, sqrt, coth, I, cot, E, tanh, tan, cosh, cos, S, sin, Rational, atanh, acoth, Integer, O, exp, sech, sec, csch, asech, acsch, acos, asin, expand_mul, AccumBounds, im, re, expand_trig) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.testing.pytest import raises def test_sinh(): x, y = symbols('x,y') k = Symbol('k', integer=True) assert sinh(nan) is nan assert sinh(zoo) is nan assert sinh(oo) is oo assert sinh(-oo) is -oo assert sinh(0) == 0 assert unchanged(sinh, 1) assert sinh(-1) == -sinh(1) assert unchanged(sinh, x) assert sinh(-x) == -sinh(x) assert unchanged(sinh, pi) assert sinh(-pi) == -sinh(pi) assert unchanged(sinh, 2**1024 * E) assert sinh(-2**1024 * E) == -sinh(2**1024 * E) assert sinh(pi*I) == 0 assert sinh(-pi*I) == 0 assert sinh(2*pi*I) == 0 assert sinh(-2*pi*I) == 0 assert sinh(-3*10**73*pi*I) == 0 assert sinh(7*10**103*pi*I) == 0 assert sinh(pi*I/2) == I assert sinh(-pi*I/2) == -I assert sinh(pi*I*Rational(5, 2)) == I assert sinh(pi*I*Rational(7, 2)) == -I assert sinh(pi*I/3) == S.Half*sqrt(3)*I assert sinh(pi*I*Rational(-2, 3)) == Rational(-1, 2)*sqrt(3)*I assert sinh(pi*I/4) == S.Half*sqrt(2)*I assert sinh(-pi*I/4) == Rational(-1, 2)*sqrt(2)*I assert sinh(pi*I*Rational(17, 4)) == S.Half*sqrt(2)*I assert sinh(pi*I*Rational(-3, 4)) == Rational(-1, 2)*sqrt(2)*I assert sinh(pi*I/6) == S.Half*I assert sinh(-pi*I/6) == Rational(-1, 2)*I assert sinh(pi*I*Rational(7, 6)) == Rational(-1, 2)*I assert sinh(pi*I*Rational(-5, 6)) == Rational(-1, 2)*I assert sinh(pi*I/105) == sin(pi/105)*I assert sinh(-pi*I/105) == -sin(pi/105)*I assert unchanged(sinh, 2 + 3*I) assert sinh(x*I) == sin(x)*I assert sinh(k*pi*I) == 0 assert sinh(17*k*pi*I) == 0 assert sinh(k*pi*I/2) == sin(k*pi/2)*I assert sinh(x).as_real_imag(deep=False) == (cos(im(x))*sinh(re(x)), sin(im(x))*cosh(re(x))) x = Symbol('x', extended_real=True) assert sinh(x).as_real_imag(deep=False) == (sinh(x), 0) x = Symbol('x', real=True) assert sinh(I*x).is_finite is True assert sinh(x).is_real is True assert sinh(I).is_real is False def test_sinh_series(): x = Symbol('x') assert sinh(x).series(x, 0, 10) == \ x + x**3/6 + x**5/120 + x**7/5040 + x**9/362880 + O(x**10) def test_sinh_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: sinh(x).fdiff(2)) def test_cosh(): x, y = symbols('x,y') k = Symbol('k', integer=True) assert cosh(nan) is nan assert cosh(zoo) is nan assert cosh(oo) is oo assert cosh(-oo) is oo assert cosh(0) == 1 assert unchanged(cosh, 1) assert cosh(-1) == cosh(1) assert unchanged(cosh, x) assert cosh(-x) == cosh(x) assert cosh(pi*I) == cos(pi) assert cosh(-pi*I) == cos(pi) assert unchanged(cosh, 2**1024 * E) assert cosh(-2**1024 * E) == cosh(2**1024 * E) assert cosh(pi*I/2) == 0 assert cosh(-pi*I/2) == 0 assert cosh((-3*10**73 + 1)*pi*I/2) == 0 assert cosh((7*10**103 + 1)*pi*I/2) == 0 assert cosh(pi*I) == -1 assert cosh(-pi*I) == -1 assert cosh(5*pi*I) == -1 assert cosh(8*pi*I) == 1 assert cosh(pi*I/3) == S.Half assert cosh(pi*I*Rational(-2, 3)) == Rational(-1, 2) assert cosh(pi*I/4) == S.Half*sqrt(2) assert cosh(-pi*I/4) == S.Half*sqrt(2) assert cosh(pi*I*Rational(11, 4)) == Rational(-1, 2)*sqrt(2) assert cosh(pi*I*Rational(-3, 4)) == Rational(-1, 2)*sqrt(2) assert cosh(pi*I/6) == S.Half*sqrt(3) assert cosh(-pi*I/6) == S.Half*sqrt(3) assert cosh(pi*I*Rational(7, 6)) == Rational(-1, 2)*sqrt(3) assert cosh(pi*I*Rational(-5, 6)) == Rational(-1, 2)*sqrt(3) assert cosh(pi*I/105) == cos(pi/105) assert cosh(-pi*I/105) == cos(pi/105) assert unchanged(cosh, 2 + 3*I) assert cosh(x*I) == cos(x) assert cosh(k*pi*I) == cos(k*pi) assert cosh(17*k*pi*I) == cos(17*k*pi) assert unchanged(cosh, k*pi) assert cosh(x).as_real_imag(deep=False) == (cos(im(x))*cosh(re(x)), sin(im(x))*sinh(re(x))) x = Symbol('x', extended_real=True) assert cosh(x).as_real_imag(deep=False) == (cosh(x), 0) x = Symbol('x', real=True) assert cosh(I*x).is_finite is True assert cosh(I*x).is_real is True assert cosh(I*2 + 1).is_real is False def test_cosh_series(): x = Symbol('x') assert cosh(x).series(x, 0, 10) == \ 1 + x**2/2 + x**4/24 + x**6/720 + x**8/40320 + O(x**10) def test_cosh_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: cosh(x).fdiff(2)) def test_tanh(): x, y = symbols('x,y') k = Symbol('k', integer=True) assert tanh(nan) is nan assert tanh(zoo) is nan assert tanh(oo) == 1 assert tanh(-oo) == -1 assert tanh(0) == 0 assert unchanged(tanh, 1) assert tanh(-1) == -tanh(1) assert unchanged(tanh, x) assert tanh(-x) == -tanh(x) assert unchanged(tanh, pi) assert tanh(-pi) == -tanh(pi) assert unchanged(tanh, 2**1024 * E) assert tanh(-2**1024 * E) == -tanh(2**1024 * E) assert tanh(pi*I) == 0 assert tanh(-pi*I) == 0 assert tanh(2*pi*I) == 0 assert tanh(-2*pi*I) == 0 assert tanh(-3*10**73*pi*I) == 0 assert tanh(7*10**103*pi*I) == 0 assert tanh(pi*I/2) is zoo assert tanh(-pi*I/2) is zoo assert tanh(pi*I*Rational(5, 2)) is zoo assert tanh(pi*I*Rational(7, 2)) is zoo assert tanh(pi*I/3) == sqrt(3)*I assert tanh(pi*I*Rational(-2, 3)) == sqrt(3)*I assert tanh(pi*I/4) == I assert tanh(-pi*I/4) == -I assert tanh(pi*I*Rational(17, 4)) == I assert tanh(pi*I*Rational(-3, 4)) == I assert tanh(pi*I/6) == I/sqrt(3) assert tanh(-pi*I/6) == -I/sqrt(3) assert tanh(pi*I*Rational(7, 6)) == I/sqrt(3) assert tanh(pi*I*Rational(-5, 6)) == I/sqrt(3) assert tanh(pi*I/105) == tan(pi/105)*I assert tanh(-pi*I/105) == -tan(pi/105)*I assert unchanged(tanh, 2 + 3*I) assert tanh(x*I) == tan(x)*I assert tanh(k*pi*I) == 0 assert tanh(17*k*pi*I) == 0 assert tanh(k*pi*I/2) == tan(k*pi/2)*I assert tanh(x).as_real_imag(deep=False) == (sinh(re(x))*cosh(re(x))/(cos(im(x))**2 + sinh(re(x))**2), sin(im(x))*cos(im(x))/(cos(im(x))**2 + sinh(re(x))**2)) x = Symbol('x', extended_real=True) assert tanh(x).as_real_imag(deep=False) == (tanh(x), 0) assert tanh(I*pi/3 + 1).is_real is False assert tanh(x).is_real is True assert tanh(I*pi*x/2).is_real is None def test_tanh_series(): x = Symbol('x') assert tanh(x).series(x, 0, 10) == \ x - x**3/3 + 2*x**5/15 - 17*x**7/315 + 62*x**9/2835 + O(x**10) def test_tanh_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: tanh(x).fdiff(2)) def test_coth(): x, y = symbols('x,y') k = Symbol('k', integer=True) assert coth(nan) is nan assert coth(zoo) is nan assert coth(oo) == 1 assert coth(-oo) == -1 assert coth(0) is zoo assert unchanged(coth, 1) assert coth(-1) == -coth(1) assert unchanged(coth, x) assert coth(-x) == -coth(x) assert coth(pi*I) == -I*cot(pi) assert coth(-pi*I) == cot(pi)*I assert unchanged(coth, 2**1024 * E) assert coth(-2**1024 * E) == -coth(2**1024 * E) assert coth(pi*I) == -I*cot(pi) assert coth(-pi*I) == I*cot(pi) assert coth(2*pi*I) == -I*cot(2*pi) assert coth(-2*pi*I) == I*cot(2*pi) assert coth(-3*10**73*pi*I) == I*cot(3*10**73*pi) assert coth(7*10**103*pi*I) == -I*cot(7*10**103*pi) assert coth(pi*I/2) == 0 assert coth(-pi*I/2) == 0 assert coth(pi*I*Rational(5, 2)) == 0 assert coth(pi*I*Rational(7, 2)) == 0 assert coth(pi*I/3) == -I/sqrt(3) assert coth(pi*I*Rational(-2, 3)) == -I/sqrt(3) assert coth(pi*I/4) == -I assert coth(-pi*I/4) == I assert coth(pi*I*Rational(17, 4)) == -I assert coth(pi*I*Rational(-3, 4)) == -I assert coth(pi*I/6) == -sqrt(3)*I assert coth(-pi*I/6) == sqrt(3)*I assert coth(pi*I*Rational(7, 6)) == -sqrt(3)*I assert coth(pi*I*Rational(-5, 6)) == -sqrt(3)*I assert coth(pi*I/105) == -cot(pi/105)*I assert coth(-pi*I/105) == cot(pi/105)*I assert unchanged(coth, 2 + 3*I) assert coth(x*I) == -cot(x)*I assert coth(k*pi*I) == -cot(k*pi)*I assert coth(17*k*pi*I) == -cot(17*k*pi)*I assert coth(k*pi*I) == -cot(k*pi)*I assert coth(log(tan(2))) == coth(log(-tan(2))) assert coth(1 + I*pi/2) == tanh(1) assert coth(x).as_real_imag(deep=False) == (sinh(re(x))*cosh(re(x))/(sin(im(x))**2 + sinh(re(x))**2), -sin(im(x))*cos(im(x))/(sin(im(x))**2 + sinh(re(x))**2)) x = Symbol('x', extended_real=True) assert coth(x).as_real_imag(deep=False) == (coth(x), 0) assert expand_trig(coth(2*x)) == (coth(x)**2 + 1)/(2*coth(x)) assert expand_trig(coth(3*x)) == (coth(x)**3 + 3*coth(x))/(1 + 3*coth(x)**2) assert expand_trig(coth(x + y)) == (1 + coth(x)*coth(y))/(coth(x) + coth(y)) def test_coth_series(): x = Symbol('x') assert coth(x).series(x, 0, 8) == \ 1/x + x/3 - x**3/45 + 2*x**5/945 - x**7/4725 + O(x**8) def test_coth_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: coth(x).fdiff(2)) def test_csch(): x, y = symbols('x,y') k = Symbol('k', integer=True) n = Symbol('n', positive=True) assert csch(nan) is nan assert csch(zoo) is nan assert csch(oo) == 0 assert csch(-oo) == 0 assert csch(0) is zoo assert csch(-1) == -csch(1) assert csch(-x) == -csch(x) assert csch(-pi) == -csch(pi) assert csch(-2**1024 * E) == -csch(2**1024 * E) assert csch(pi*I) is zoo assert csch(-pi*I) is zoo assert csch(2*pi*I) is zoo assert csch(-2*pi*I) is zoo assert csch(-3*10**73*pi*I) is zoo assert csch(7*10**103*pi*I) is zoo assert csch(pi*I/2) == -I assert csch(-pi*I/2) == I assert csch(pi*I*Rational(5, 2)) == -I assert csch(pi*I*Rational(7, 2)) == I assert csch(pi*I/3) == -2/sqrt(3)*I assert csch(pi*I*Rational(-2, 3)) == 2/sqrt(3)*I assert csch(pi*I/4) == -sqrt(2)*I assert csch(-pi*I/4) == sqrt(2)*I assert csch(pi*I*Rational(7, 4)) == sqrt(2)*I assert csch(pi*I*Rational(-3, 4)) == sqrt(2)*I assert csch(pi*I/6) == -2*I assert csch(-pi*I/6) == 2*I assert csch(pi*I*Rational(7, 6)) == 2*I assert csch(pi*I*Rational(-7, 6)) == -2*I assert csch(pi*I*Rational(-5, 6)) == 2*I assert csch(pi*I/105) == -1/sin(pi/105)*I assert csch(-pi*I/105) == 1/sin(pi/105)*I assert csch(x*I) == -1/sin(x)*I assert csch(k*pi*I) is zoo assert csch(17*k*pi*I) is zoo assert csch(k*pi*I/2) == -1/sin(k*pi/2)*I assert csch(n).is_real is True assert expand_trig(csch(x + y)) == 1/(sinh(x)*cosh(y) + cosh(x)*sinh(y)) def test_csch_series(): x = Symbol('x') assert csch(x).series(x, 0, 10) == \ 1/ x - x/6 + 7*x**3/360 - 31*x**5/15120 + 127*x**7/604800 \ - 73*x**9/3421440 + O(x**10) def test_csch_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: csch(x).fdiff(2)) def test_sech(): x, y = symbols('x, y') k = Symbol('k', integer=True) n = Symbol('n', positive=True) assert sech(nan) is nan assert sech(zoo) is nan assert sech(oo) == 0 assert sech(-oo) == 0 assert sech(0) == 1 assert sech(-1) == sech(1) assert sech(-x) == sech(x) assert sech(pi*I) == sec(pi) assert sech(-pi*I) == sec(pi) assert sech(-2**1024 * E) == sech(2**1024 * E) assert sech(pi*I/2) is zoo assert sech(-pi*I/2) is zoo assert sech((-3*10**73 + 1)*pi*I/2) is zoo assert sech((7*10**103 + 1)*pi*I/2) is zoo assert sech(pi*I) == -1 assert sech(-pi*I) == -1 assert sech(5*pi*I) == -1 assert sech(8*pi*I) == 1 assert sech(pi*I/3) == 2 assert sech(pi*I*Rational(-2, 3)) == -2 assert sech(pi*I/4) == sqrt(2) assert sech(-pi*I/4) == sqrt(2) assert sech(pi*I*Rational(5, 4)) == -sqrt(2) assert sech(pi*I*Rational(-5, 4)) == -sqrt(2) assert sech(pi*I/6) == 2/sqrt(3) assert sech(-pi*I/6) == 2/sqrt(3) assert sech(pi*I*Rational(7, 6)) == -2/sqrt(3) assert sech(pi*I*Rational(-5, 6)) == -2/sqrt(3) assert sech(pi*I/105) == 1/cos(pi/105) assert sech(-pi*I/105) == 1/cos(pi/105) assert sech(x*I) == 1/cos(x) assert sech(k*pi*I) == 1/cos(k*pi) assert sech(17*k*pi*I) == 1/cos(17*k*pi) assert sech(n).is_real is True assert expand_trig(sech(x + y)) == 1/(cosh(x)*cosh(y) + sinh(x)*sinh(y)) def test_sech_series(): x = Symbol('x') assert sech(x).series(x, 0, 10) == \ 1 - x**2/2 + 5*x**4/24 - 61*x**6/720 + 277*x**8/8064 + O(x**10) def test_sech_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: sech(x).fdiff(2)) def test_asinh(): x, y = symbols('x,y') assert unchanged(asinh, x) assert asinh(-x) == -asinh(x) #at specific points assert asinh(nan) is nan assert asinh( 0) == 0 assert asinh(+1) == log(sqrt(2) + 1) assert asinh(-1) == log(sqrt(2) - 1) assert asinh(I) == pi*I/2 assert asinh(-I) == -pi*I/2 assert asinh(I/2) == pi*I/6 assert asinh(-I/2) == -pi*I/6 # at infinites assert asinh(oo) is oo assert asinh(-oo) is -oo assert asinh(I*oo) is oo assert asinh(-I *oo) is -oo assert asinh(zoo) is zoo #properties assert asinh(I *(sqrt(3) - 1)/(2**Rational(3, 2))) == pi*I/12 assert asinh(-I *(sqrt(3) - 1)/(2**Rational(3, 2))) == -pi*I/12 assert asinh(I*(sqrt(5) - 1)/4) == pi*I/10 assert asinh(-I*(sqrt(5) - 1)/4) == -pi*I/10 assert asinh(I*(sqrt(5) + 1)/4) == pi*I*Rational(3, 10) assert asinh(-I*(sqrt(5) + 1)/4) == pi*I*Rational(-3, 10) # Symmetry assert asinh(Rational(-1, 2)) == -asinh(S.Half) # inverse composition assert unchanged(asinh, sinh(Symbol('v1'))) assert asinh(sinh(0, evaluate=False)) == 0 assert asinh(sinh(-3, evaluate=False)) == -3 assert asinh(sinh(2, evaluate=False)) == 2 assert asinh(sinh(I, evaluate=False)) == I assert asinh(sinh(-I, evaluate=False)) == -I assert asinh(sinh(5*I, evaluate=False)) == -2*I*pi + 5*I assert asinh(sinh(15 + 11*I)) == 15 - 4*I*pi + 11*I assert asinh(sinh(-73 + 97*I)) == 73 - 97*I + 31*I*pi assert asinh(sinh(-7 - 23*I)) == 7 - 7*I*pi + 23*I assert asinh(sinh(13 - 3*I)) == -13 - I*pi + 3*I def test_asinh_rewrite(): x = Symbol('x') assert asinh(x).rewrite(log) == log(x + sqrt(x**2 + 1)) def test_asinh_series(): x = Symbol('x') assert asinh(x).series(x, 0, 8) == \ x - x**3/6 + 3*x**5/40 - 5*x**7/112 + O(x**8) t5 = asinh(x).taylor_term(5, x) assert t5 == 3*x**5/40 assert asinh(x).taylor_term(7, x, t5, 0) == -5*x**7/112 def test_asinh_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: asinh(x).fdiff(2)) def test_acosh(): x = Symbol('x') assert unchanged(acosh, -x) #at specific points assert acosh(1) == 0 assert acosh(-1) == pi*I assert acosh(0) == I*pi/2 assert acosh(S.Half) == I*pi/3 assert acosh(Rational(-1, 2)) == pi*I*Rational(2, 3) assert acosh(nan) is nan # at infinites assert acosh(oo) is oo assert acosh(-oo) is oo assert acosh(I*oo) == oo + I*pi/2 assert acosh(-I*oo) == oo - I*pi/2 assert acosh(zoo) is zoo assert acosh(I) == log(I*(1 + sqrt(2))) assert acosh(-I) == log(-I*(1 + sqrt(2))) assert acosh((sqrt(3) - 1)/(2*sqrt(2))) == pi*I*Rational(5, 12) assert acosh(-(sqrt(3) - 1)/(2*sqrt(2))) == pi*I*Rational(7, 12) assert acosh(sqrt(2)/2) == I*pi/4 assert acosh(-sqrt(2)/2) == I*pi*Rational(3, 4) assert acosh(sqrt(3)/2) == I*pi/6 assert acosh(-sqrt(3)/2) == I*pi*Rational(5, 6) assert acosh(sqrt(2 + sqrt(2))/2) == I*pi/8 assert acosh(-sqrt(2 + sqrt(2))/2) == I*pi*Rational(7, 8) assert acosh(sqrt(2 - sqrt(2))/2) == I*pi*Rational(3, 8) assert acosh(-sqrt(2 - sqrt(2))/2) == I*pi*Rational(5, 8) assert acosh((1 + sqrt(3))/(2*sqrt(2))) == I*pi/12 assert acosh(-(1 + sqrt(3))/(2*sqrt(2))) == I*pi*Rational(11, 12) assert acosh((sqrt(5) + 1)/4) == I*pi/5 assert acosh(-(sqrt(5) + 1)/4) == I*pi*Rational(4, 5) assert str(acosh(5*I).n(6)) == '2.31244 + 1.5708*I' assert str(acosh(-5*I).n(6)) == '2.31244 - 1.5708*I' # inverse composition assert unchanged(acosh, Symbol('v1')) assert acosh(cosh(-3, evaluate=False)) == 3 assert acosh(cosh(3, evaluate=False)) == 3 assert acosh(cosh(0, evaluate=False)) == 0 assert acosh(cosh(I, evaluate=False)) == I assert acosh(cosh(-I, evaluate=False)) == I assert acosh(cosh(7*I, evaluate=False)) == -2*I*pi + 7*I assert acosh(cosh(1 + I)) == 1 + I assert acosh(cosh(3 - 3*I)) == 3 - 3*I assert acosh(cosh(-3 + 2*I)) == 3 - 2*I assert acosh(cosh(-5 - 17*I)) == 5 - 6*I*pi + 17*I assert acosh(cosh(-21 + 11*I)) == 21 - 11*I + 4*I*pi assert acosh(cosh(cosh(1) + I)) == cosh(1) + I def test_acosh_rewrite(): x = Symbol('x') assert acosh(x).rewrite(log) == log(x + sqrt(x - 1)*sqrt(x + 1)) def test_acosh_series(): x = Symbol('x') assert acosh(x).series(x, 0, 8) == \ -I*x + pi*I/2 - I*x**3/6 - 3*I*x**5/40 - 5*I*x**7/112 + O(x**8) t5 = acosh(x).taylor_term(5, x) assert t5 == - 3*I*x**5/40 assert acosh(x).taylor_term(7, x, t5, 0) == - 5*I*x**7/112 def test_acosh_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: acosh(x).fdiff(2)) def test_asech(): x = Symbol('x') assert unchanged(asech, -x) # values at fixed points assert asech(1) == 0 assert asech(-1) == pi*I assert asech(0) is oo assert asech(2) == I*pi/3 assert asech(-2) == 2*I*pi / 3 assert asech(nan) is nan # at infinites assert asech(oo) == I*pi/2 assert asech(-oo) == I*pi/2 assert asech(zoo) == I*AccumBounds(-pi/2, pi/2) assert asech(I) == log(1 + sqrt(2)) - I*pi/2 assert asech(-I) == log(1 + sqrt(2)) + I*pi/2 assert asech(sqrt(2) - sqrt(6)) == 11*I*pi / 12 assert asech(sqrt(2 - 2/sqrt(5))) == I*pi / 10 assert asech(-sqrt(2 - 2/sqrt(5))) == 9*I*pi / 10 assert asech(2 / sqrt(2 + sqrt(2))) == I*pi / 8 assert asech(-2 / sqrt(2 + sqrt(2))) == 7*I*pi / 8 assert asech(sqrt(5) - 1) == I*pi / 5 assert asech(1 - sqrt(5)) == 4*I*pi / 5 assert asech(-sqrt(2*(2 + sqrt(2)))) == 5*I*pi / 8 # properties # asech(x) == acosh(1/x) assert asech(sqrt(2)) == acosh(1/sqrt(2)) assert asech(2/sqrt(3)) == acosh(sqrt(3)/2) assert asech(2/sqrt(2 + sqrt(2))) == acosh(sqrt(2 + sqrt(2))/2) assert asech(2) == acosh(S.Half) # asech(x) == I*acos(1/x) # (Note: the exact formula is asech(x) == +/- I*acos(1/x)) assert asech(-sqrt(2)) == I*acos(-1/sqrt(2)) assert asech(-2/sqrt(3)) == I*acos(-sqrt(3)/2) assert asech(-S(2)) == I*acos(Rational(-1, 2)) assert asech(-2/sqrt(2)) == I*acos(-sqrt(2)/2) # sech(asech(x)) / x == 1 assert expand_mul(sech(asech(sqrt(6) - sqrt(2))) / (sqrt(6) - sqrt(2))) == 1 assert expand_mul(sech(asech(sqrt(6) + sqrt(2))) / (sqrt(6) + sqrt(2))) == 1 assert (sech(asech(sqrt(2 + 2/sqrt(5)))) / (sqrt(2 + 2/sqrt(5)))).simplify() == 1 assert (sech(asech(-sqrt(2 + 2/sqrt(5)))) / (-sqrt(2 + 2/sqrt(5)))).simplify() == 1 assert (sech(asech(sqrt(2*(2 + sqrt(2))))) / (sqrt(2*(2 + sqrt(2))))).simplify() == 1 assert expand_mul(sech(asech(1 + sqrt(5))) / (1 + sqrt(5))) == 1 assert expand_mul(sech(asech(-1 - sqrt(5))) / (-1 - sqrt(5))) == 1 assert expand_mul(sech(asech(-sqrt(6) - sqrt(2))) / (-sqrt(6) - sqrt(2))) == 1 # numerical evaluation assert str(asech(5*I).n(6)) == '0.19869 - 1.5708*I' assert str(asech(-5*I).n(6)) == '0.19869 + 1.5708*I' def test_asech_series(): x = Symbol('x') t6 = asech(x).expansion_term(6, x) assert t6 == -5*x**6/96 assert asech(x).expansion_term(8, x, t6, 0) == -35*x**8/1024 def test_asech_rewrite(): x = Symbol('x') assert asech(x).rewrite(log) == log(1/x + sqrt(1/x - 1) * sqrt(1/x + 1)) def test_asech_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: asech(x).fdiff(2)) def test_acsch(): x = Symbol('x') assert unchanged(acsch, x) assert acsch(-x) == -acsch(x) # values at fixed points assert acsch(1) == log(1 + sqrt(2)) assert acsch(-1) == - log(1 + sqrt(2)) assert acsch(0) is zoo assert acsch(2) == log((1+sqrt(5))/2) assert acsch(-2) == - log((1+sqrt(5))/2) assert acsch(I) == - I*pi/2 assert acsch(-I) == I*pi/2 assert acsch(-I*(sqrt(6) + sqrt(2))) == I*pi / 12 assert acsch(I*(sqrt(2) + sqrt(6))) == -I*pi / 12 assert acsch(-I*(1 + sqrt(5))) == I*pi / 10 assert acsch(I*(1 + sqrt(5))) == -I*pi / 10 assert acsch(-I*2 / sqrt(2 - sqrt(2))) == I*pi / 8 assert acsch(I*2 / sqrt(2 - sqrt(2))) == -I*pi / 8 assert acsch(-I*2) == I*pi / 6 assert acsch(I*2) == -I*pi / 6 assert acsch(-I*sqrt(2 + 2/sqrt(5))) == I*pi / 5 assert acsch(I*sqrt(2 + 2/sqrt(5))) == -I*pi / 5 assert acsch(-I*sqrt(2)) == I*pi / 4 assert acsch(I*sqrt(2)) == -I*pi / 4 assert acsch(-I*(sqrt(5)-1)) == 3*I*pi / 10 assert acsch(I*(sqrt(5)-1)) == -3*I*pi / 10 assert acsch(-I*2 / sqrt(3)) == I*pi / 3 assert acsch(I*2 / sqrt(3)) == -I*pi / 3 assert acsch(-I*2 / sqrt(2 + sqrt(2))) == 3*I*pi / 8 assert acsch(I*2 / sqrt(2 + sqrt(2))) == -3*I*pi / 8 assert acsch(-I*sqrt(2 - 2/sqrt(5))) == 2*I*pi / 5 assert acsch(I*sqrt(2 - 2/sqrt(5))) == -2*I*pi / 5 assert acsch(-I*(sqrt(6) - sqrt(2))) == 5*I*pi / 12 assert acsch(I*(sqrt(6) - sqrt(2))) == -5*I*pi / 12 assert acsch(nan) is nan # properties # acsch(x) == asinh(1/x) assert acsch(-I*sqrt(2)) == asinh(I/sqrt(2)) assert acsch(-I*2 / sqrt(3)) == asinh(I*sqrt(3) / 2) # acsch(x) == -I*asin(I/x) assert acsch(-I*sqrt(2)) == -I*asin(-1/sqrt(2)) assert acsch(-I*2 / sqrt(3)) == -I*asin(-sqrt(3)/2) # csch(acsch(x)) / x == 1 assert expand_mul(csch(acsch(-I*(sqrt(6) + sqrt(2)))) / (-I*(sqrt(6) + sqrt(2)))) == 1 assert expand_mul(csch(acsch(I*(1 + sqrt(5)))) / (I*(1 + sqrt(5)))) == 1 assert (csch(acsch(I*sqrt(2 - 2/sqrt(5)))) / (I*sqrt(2 - 2/sqrt(5)))).simplify() == 1 assert (csch(acsch(-I*sqrt(2 - 2/sqrt(5)))) / (-I*sqrt(2 - 2/sqrt(5)))).simplify() == 1 # numerical evaluation assert str(acsch(5*I+1).n(6)) == '0.0391819 - 0.193363*I' assert str(acsch(-5*I+1).n(6)) == '0.0391819 + 0.193363*I' def test_acsch_infinities(): assert acsch(oo) == 0 assert acsch(-oo) == 0 assert acsch(zoo) == 0 def test_acsch_rewrite(): x = Symbol('x') assert acsch(x).rewrite(log) == log(1/x + sqrt(1/x**2 + 1)) def test_acsch_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: acsch(x).fdiff(2)) def test_atanh(): x = Symbol('x') #at specific points assert atanh(0) == 0 assert atanh(I) == I*pi/4 assert atanh(-I) == -I*pi/4 assert atanh(1) is oo assert atanh(-1) is -oo assert atanh(nan) is nan # at infinites assert atanh(oo) == -I*pi/2 assert atanh(-oo) == I*pi/2 assert atanh(I*oo) == I*pi/2 assert atanh(-I*oo) == -I*pi/2 assert atanh(zoo) == I*AccumBounds(-pi/2, pi/2) #properties assert atanh(-x) == -atanh(x) assert atanh(I/sqrt(3)) == I*pi/6 assert atanh(-I/sqrt(3)) == -I*pi/6 assert atanh(I*sqrt(3)) == I*pi/3 assert atanh(-I*sqrt(3)) == -I*pi/3 assert atanh(I*(1 + sqrt(2))) == pi*I*Rational(3, 8) assert atanh(I*(sqrt(2) - 1)) == pi*I/8 assert atanh(I*(1 - sqrt(2))) == -pi*I/8 assert atanh(-I*(1 + sqrt(2))) == pi*I*Rational(-3, 8) assert atanh(I*sqrt(5 + 2*sqrt(5))) == I*pi*Rational(2, 5) assert atanh(-I*sqrt(5 + 2*sqrt(5))) == I*pi*Rational(-2, 5) assert atanh(I*(2 - sqrt(3))) == pi*I/12 assert atanh(I*(sqrt(3) - 2)) == -pi*I/12 assert atanh(oo) == -I*pi/2 # Symmetry assert atanh(Rational(-1, 2)) == -atanh(S.Half) # inverse composition assert unchanged(atanh, tanh(Symbol('v1'))) assert atanh(tanh(-5, evaluate=False)) == -5 assert atanh(tanh(0, evaluate=False)) == 0 assert atanh(tanh(7, evaluate=False)) == 7 assert atanh(tanh(I, evaluate=False)) == I assert atanh(tanh(-I, evaluate=False)) == -I assert atanh(tanh(-11*I, evaluate=False)) == -11*I + 4*I*pi assert atanh(tanh(3 + I)) == 3 + I assert atanh(tanh(4 + 5*I)) == 4 - 2*I*pi + 5*I assert atanh(tanh(pi/2)) == pi/2 assert atanh(tanh(pi)) == pi assert atanh(tanh(-3 + 7*I)) == -3 - 2*I*pi + 7*I assert atanh(tanh(9 - I*Rational(2, 3))) == 9 - I*Rational(2, 3) assert atanh(tanh(-32 - 123*I)) == -32 - 123*I + 39*I*pi def test_atanh_rewrite(): x = Symbol('x') assert atanh(x).rewrite(log) == (log(1 + x) - log(1 - x)) / 2 def test_atanh_series(): x = Symbol('x') assert atanh(x).series(x, 0, 10) == \ x + x**3/3 + x**5/5 + x**7/7 + x**9/9 + O(x**10) def test_atanh_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: atanh(x).fdiff(2)) def test_acoth(): x = Symbol('x') #at specific points assert acoth(0) == I*pi/2 assert acoth(I) == -I*pi/4 assert acoth(-I) == I*pi/4 assert acoth(1) is oo assert acoth(-1) is -oo assert acoth(nan) is nan # at infinites assert acoth(oo) == 0 assert acoth(-oo) == 0 assert acoth(I*oo) == 0 assert acoth(-I*oo) == 0 assert acoth(zoo) == 0 #properties assert acoth(-x) == -acoth(x) assert acoth(I/sqrt(3)) == -I*pi/3 assert acoth(-I/sqrt(3)) == I*pi/3 assert acoth(I*sqrt(3)) == -I*pi/6 assert acoth(-I*sqrt(3)) == I*pi/6 assert acoth(I*(1 + sqrt(2))) == -pi*I/8 assert acoth(-I*(sqrt(2) + 1)) == pi*I/8 assert acoth(I*(1 - sqrt(2))) == pi*I*Rational(3, 8) assert acoth(I*(sqrt(2) - 1)) == pi*I*Rational(-3, 8) assert acoth(I*sqrt(5 + 2*sqrt(5))) == -I*pi/10 assert acoth(-I*sqrt(5 + 2*sqrt(5))) == I*pi/10 assert acoth(I*(2 + sqrt(3))) == -pi*I/12 assert acoth(-I*(2 + sqrt(3))) == pi*I/12 assert acoth(I*(2 - sqrt(3))) == pi*I*Rational(-5, 12) assert acoth(I*(sqrt(3) - 2)) == pi*I*Rational(5, 12) # Symmetry assert acoth(Rational(-1, 2)) == -acoth(S.Half) def test_acoth_rewrite(): x = Symbol('x') assert acoth(x).rewrite(log) == (log(1 + 1/x) - log(1 - 1/x)) / 2 def test_acoth_series(): x = Symbol('x') assert acoth(x).series(x, 0, 10) == \ I*pi/2 + x + x**3/3 + x**5/5 + x**7/7 + x**9/9 + O(x**10) def test_acoth_fdiff(): x = Symbol('x') raises(ArgumentIndexError, lambda: acoth(x).fdiff(2)) def test_inverses(): x = Symbol('x') assert sinh(x).inverse() == asinh raises(AttributeError, lambda: cosh(x).inverse()) assert tanh(x).inverse() == atanh assert coth(x).inverse() == acoth assert asinh(x).inverse() == sinh assert acosh(x).inverse() == cosh assert atanh(x).inverse() == tanh assert acoth(x).inverse() == coth assert asech(x).inverse() == sech assert acsch(x).inverse() == csch def test_leading_term(): x = Symbol('x') assert cosh(x).as_leading_term(x) == 1 assert coth(x).as_leading_term(x) == 1/x assert acosh(x).as_leading_term(x) == I*pi/2 assert acoth(x).as_leading_term(x) == I*pi/2 for func in [sinh, tanh, asinh, atanh]: assert func(x).as_leading_term(x) == x for func in [sinh, cosh, tanh, coth, asinh, acosh, atanh, acoth]: for arg in (1/x, S.Half): eq = func(arg) assert eq.as_leading_term(x) == eq for func in [csch, sech]: eq = func(S.Half) assert eq.as_leading_term(x) == eq def test_complex(): a, b = symbols('a,b', real=True) z = a + b*I for func in [sinh, cosh, tanh, coth, sech, csch]: assert func(z).conjugate() == func(a - b*I) for deep in [True, False]: assert sinh(z).expand( complex=True, deep=deep) == sinh(a)*cos(b) + I*cosh(a)*sin(b) assert cosh(z).expand( complex=True, deep=deep) == cosh(a)*cos(b) + I*sinh(a)*sin(b) assert tanh(z).expand(complex=True, deep=deep) == sinh(a)*cosh( a)/(cos(b)**2 + sinh(a)**2) + I*sin(b)*cos(b)/(cos(b)**2 + sinh(a)**2) assert coth(z).expand(complex=True, deep=deep) == sinh(a)*cosh( a)/(sin(b)**2 + sinh(a)**2) - I*sin(b)*cos(b)/(sin(b)**2 + sinh(a)**2) assert csch(z).expand(complex=True, deep=deep) == cos(b) * sinh(a) / (sin(b)**2\ *cosh(a)**2 + cos(b)**2 * sinh(a)**2) - I*sin(b) * cosh(a) / (sin(b)**2\ *cosh(a)**2 + cos(b)**2 * sinh(a)**2) assert sech(z).expand(complex=True, deep=deep) == cos(b) * cosh(a) / (sin(b)**2\ *sinh(a)**2 + cos(b)**2 * cosh(a)**2) - I*sin(b) * sinh(a) / (sin(b)**2\ *sinh(a)**2 + cos(b)**2 * cosh(a)**2) def test_complex_2899(): a, b = symbols('a,b', real=True) for deep in [True, False]: for func in [sinh, cosh, tanh, coth]: assert func(a).expand(complex=True, deep=deep) == func(a) def test_simplifications(): x = Symbol('x') assert sinh(asinh(x)) == x assert sinh(acosh(x)) == sqrt(x - 1) * sqrt(x + 1) assert sinh(atanh(x)) == x/sqrt(1 - x**2) assert sinh(acoth(x)) == 1/(sqrt(x - 1) * sqrt(x + 1)) assert cosh(asinh(x)) == sqrt(1 + x**2) assert cosh(acosh(x)) == x assert cosh(atanh(x)) == 1/sqrt(1 - x**2) assert cosh(acoth(x)) == x/(sqrt(x - 1) * sqrt(x + 1)) assert tanh(asinh(x)) == x/sqrt(1 + x**2) assert tanh(acosh(x)) == sqrt(x - 1) * sqrt(x + 1) / x assert tanh(atanh(x)) == x assert tanh(acoth(x)) == 1/x assert coth(asinh(x)) == sqrt(1 + x**2)/x assert coth(acosh(x)) == x/(sqrt(x - 1) * sqrt(x + 1)) assert coth(atanh(x)) == 1/x assert coth(acoth(x)) == x assert csch(asinh(x)) == 1/x assert csch(acosh(x)) == 1/(sqrt(x - 1) * sqrt(x + 1)) assert csch(atanh(x)) == sqrt(1 - x**2)/x assert csch(acoth(x)) == sqrt(x - 1) * sqrt(x + 1) assert sech(asinh(x)) == 1/sqrt(1 + x**2) assert sech(acosh(x)) == 1/x assert sech(atanh(x)) == sqrt(1 - x**2) assert sech(acoth(x)) == sqrt(x - 1) * sqrt(x + 1)/x def test_issue_4136(): assert cosh(asinh(Integer(3)/2)) == sqrt(Integer(13)/4) def test_sinh_rewrite(): x = Symbol('x') assert sinh(x).rewrite(exp) == (exp(x) - exp(-x))/2 \ == sinh(x).rewrite('tractable') assert sinh(x).rewrite(cosh) == -I*cosh(x + I*pi/2) tanh_half = tanh(S.Half*x) assert sinh(x).rewrite(tanh) == 2*tanh_half/(1 - tanh_half**2) coth_half = coth(S.Half*x) assert sinh(x).rewrite(coth) == 2*coth_half/(coth_half**2 - 1) def test_cosh_rewrite(): x = Symbol('x') assert cosh(x).rewrite(exp) == (exp(x) + exp(-x))/2 \ == cosh(x).rewrite('tractable') assert cosh(x).rewrite(sinh) == -I*sinh(x + I*pi/2) tanh_half = tanh(S.Half*x)**2 assert cosh(x).rewrite(tanh) == (1 + tanh_half)/(1 - tanh_half) coth_half = coth(S.Half*x)**2 assert cosh(x).rewrite(coth) == (coth_half + 1)/(coth_half - 1) def test_tanh_rewrite(): x = Symbol('x') assert tanh(x).rewrite(exp) == (exp(x) - exp(-x))/(exp(x) + exp(-x)) \ == tanh(x).rewrite('tractable') assert tanh(x).rewrite(sinh) == I*sinh(x)/sinh(I*pi/2 - x) assert tanh(x).rewrite(cosh) == I*cosh(I*pi/2 - x)/cosh(x) assert tanh(x).rewrite(coth) == 1/coth(x) def test_coth_rewrite(): x = Symbol('x') assert coth(x).rewrite(exp) == (exp(x) + exp(-x))/(exp(x) - exp(-x)) \ == coth(x).rewrite('tractable') assert coth(x).rewrite(sinh) == -I*sinh(I*pi/2 - x)/sinh(x) assert coth(x).rewrite(cosh) == -I*cosh(x)/cosh(I*pi/2 - x) assert coth(x).rewrite(tanh) == 1/tanh(x) def test_csch_rewrite(): x = Symbol('x') assert csch(x).rewrite(exp) == 1 / (exp(x)/2 - exp(-x)/2) \ == csch(x).rewrite('tractable') assert csch(x).rewrite(cosh) == I/cosh(x + I*pi/2) tanh_half = tanh(S.Half*x) assert csch(x).rewrite(tanh) == (1 - tanh_half**2)/(2*tanh_half) coth_half = coth(S.Half*x) assert csch(x).rewrite(coth) == (coth_half**2 - 1)/(2*coth_half) def test_sech_rewrite(): x = Symbol('x') assert sech(x).rewrite(exp) == 1 / (exp(x)/2 + exp(-x)/2) \ == sech(x).rewrite('tractable') assert sech(x).rewrite(sinh) == I/sinh(x + I*pi/2) tanh_half = tanh(S.Half*x)**2 assert sech(x).rewrite(tanh) == (1 - tanh_half)/(1 + tanh_half) coth_half = coth(S.Half*x)**2 assert sech(x).rewrite(coth) == (coth_half - 1)/(coth_half + 1) def test_derivs(): x = Symbol('x') assert coth(x).diff(x) == -sinh(x)**(-2) assert sinh(x).diff(x) == cosh(x) assert cosh(x).diff(x) == sinh(x) assert tanh(x).diff(x) == -tanh(x)**2 + 1 assert csch(x).diff(x) == -coth(x)*csch(x) assert sech(x).diff(x) == -tanh(x)*sech(x) assert acoth(x).diff(x) == 1/(-x**2 + 1) assert asinh(x).diff(x) == 1/sqrt(x**2 + 1) assert acosh(x).diff(x) == 1/sqrt(x**2 - 1) assert atanh(x).diff(x) == 1/(-x**2 + 1) assert asech(x).diff(x) == -1/(x*sqrt(1 - x**2)) assert acsch(x).diff(x) == -1/(x**2*sqrt(1 + x**(-2))) def test_sinh_expansion(): x, y = symbols('x,y') assert sinh(x+y).expand(trig=True) == sinh(x)*cosh(y) + cosh(x)*sinh(y) assert sinh(2*x).expand(trig=True) == 2*sinh(x)*cosh(x) assert sinh(3*x).expand(trig=True).expand() == \ sinh(x)**3 + 3*sinh(x)*cosh(x)**2 def test_cosh_expansion(): x, y = symbols('x,y') assert cosh(x+y).expand(trig=True) == cosh(x)*cosh(y) + sinh(x)*sinh(y) assert cosh(2*x).expand(trig=True) == cosh(x)**2 + sinh(x)**2 assert cosh(3*x).expand(trig=True).expand() == \ 3*sinh(x)**2*cosh(x) + cosh(x)**3 def test_cosh_positive(): # See issue 11721 # cosh(x) is positive for real values of x k = symbols('k', real=True) n = symbols('n', integer=True) assert cosh(k, evaluate=False).is_positive is True assert cosh(k + 2*n*pi*I, evaluate=False).is_positive is True assert cosh(I*pi/4, evaluate=False).is_positive is True assert cosh(3*I*pi/4, evaluate=False).is_positive is False def test_cosh_nonnegative(): k = symbols('k', real=True) n = symbols('n', integer=True) assert cosh(k, evaluate=False).is_nonnegative is True assert cosh(k + 2*n*pi*I, evaluate=False).is_nonnegative is True assert cosh(I*pi/4, evaluate=False).is_nonnegative is True assert cosh(3*I*pi/4, evaluate=False).is_nonnegative is False assert cosh(S.Zero, evaluate=False).is_nonnegative is True def test_real_assumptions(): z = Symbol('z', real=False) assert sinh(z).is_real is None assert cosh(z).is_real is None assert tanh(z).is_real is None assert sech(z).is_real is None assert csch(z).is_real is None assert coth(z).is_real is None def test_sign_assumptions(): p = Symbol('p', positive=True) n = Symbol('n', negative=True) assert sinh(n).is_negative is True assert sinh(p).is_positive is True assert cosh(n).is_positive is True assert cosh(p).is_positive is True assert tanh(n).is_negative is True assert tanh(p).is_positive is True assert csch(n).is_negative is True assert csch(p).is_positive is True assert sech(n).is_positive is True assert sech(p).is_positive is True assert coth(n).is_negative is True assert coth(p).is_positive is True sympy-sympy-1.9/sympy/functions/elementary/tests/test_integers.py000066400000000000000000000425621412543434000256650ustar00rootroot00000000000000from sympy import AccumBounds, Symbol, floor, nan, oo, zoo, E, symbols, \ ceiling, pi, Rational, Float, I, sin, exp, log, factorial, frac, Eq, \ Le, Ge, Gt, Lt, Ne, sqrt, S from sympy.core.expr import unchanged from sympy.testing.pytest import XFAIL x = Symbol('x') i = Symbol('i', imaginary=True) y = Symbol('y', real=True) k, n = symbols('k,n', integer=True) def test_floor(): assert floor(nan) is nan assert floor(oo) is oo assert floor(-oo) is -oo assert floor(zoo) is zoo assert floor(0) == 0 assert floor(1) == 1 assert floor(-1) == -1 assert floor(E) == 2 assert floor(-E) == -3 assert floor(2*E) == 5 assert floor(-2*E) == -6 assert floor(pi) == 3 assert floor(-pi) == -4 assert floor(S.Half) == 0 assert floor(Rational(-1, 2)) == -1 assert floor(Rational(7, 3)) == 2 assert floor(Rational(-7, 3)) == -3 assert floor(-Rational(7, 3)) == -3 assert floor(Float(17.0)) == 17 assert floor(-Float(17.0)) == -17 assert floor(Float(7.69)) == 7 assert floor(-Float(7.69)) == -8 assert floor(I) == I assert floor(-I) == -I e = floor(i) assert e.func is floor and e.args[0] == i assert floor(oo*I) == oo*I assert floor(-oo*I) == -oo*I assert floor(exp(I*pi/4)*oo) == exp(I*pi/4)*oo assert floor(2*I) == 2*I assert floor(-2*I) == -2*I assert floor(I/2) == 0 assert floor(-I/2) == -I assert floor(E + 17) == 19 assert floor(pi + 2) == 5 assert floor(E + pi) == 5 assert floor(I + pi) == 3 + I assert floor(floor(pi)) == 3 assert floor(floor(y)) == floor(y) assert floor(floor(x)) == floor(x) assert unchanged(floor, x) assert unchanged(floor, 2*x) assert unchanged(floor, k*x) assert floor(k) == k assert floor(2*k) == 2*k assert floor(k*n) == k*n assert unchanged(floor, k/2) assert unchanged(floor, x + y) assert floor(x + 3) == floor(x) + 3 assert floor(x + k) == floor(x) + k assert floor(y + 3) == floor(y) + 3 assert floor(y + k) == floor(y) + k assert floor(3 + I*y + pi) == 6 + floor(y)*I assert floor(k + n) == k + n assert unchanged(floor, x*I) assert floor(k*I) == k*I assert floor(Rational(23, 10) - E*I) == 2 - 3*I assert floor(sin(1)) == 0 assert floor(sin(-1)) == -1 assert floor(exp(2)) == 7 assert floor(log(8)/log(2)) != 2 assert int(floor(log(8)/log(2)).evalf(chop=True)) == 3 assert floor(factorial(50)/exp(1)) == \ 11188719610782480504630258070757734324011354208865721592720336800 assert (floor(y) < y) == False assert (floor(y) <= y) == True assert (floor(y) > y) == False assert (floor(y) >= y) == False assert (floor(x) <= x).is_Relational # x could be non-real assert (floor(x) > x).is_Relational assert (floor(x) <= y).is_Relational # arg is not same as rhs assert (floor(x) > y).is_Relational assert (floor(y) <= oo) == True assert (floor(y) < oo) == True assert (floor(y) >= -oo) == True assert (floor(y) > -oo) == True assert floor(y).rewrite(frac) == y - frac(y) assert floor(y).rewrite(ceiling) == -ceiling(-y) assert floor(y).rewrite(frac).subs(y, -pi) == floor(-pi) assert floor(y).rewrite(frac).subs(y, E) == floor(E) assert floor(y).rewrite(ceiling).subs(y, E) == -ceiling(-E) assert floor(y).rewrite(ceiling).subs(y, -pi) == -ceiling(pi) assert Eq(floor(y), y - frac(y)) assert Eq(floor(y), -ceiling(-y)) neg = Symbol('neg', negative=True) nn = Symbol('nn', nonnegative=True) pos = Symbol('pos', positive=True) np = Symbol('np', nonpositive=True) assert (floor(neg) < 0) == True assert (floor(neg) <= 0) == True assert (floor(neg) > 0) == False assert (floor(neg) >= 0) == False assert (floor(neg) <= -1) == True assert (floor(neg) >= -3) == (neg >= -3) assert (floor(neg) < 5) == (neg < 5) assert (floor(nn) < 0) == False assert (floor(nn) >= 0) == True assert (floor(pos) < 0) == False assert (floor(pos) <= 0) == (pos < 1) assert (floor(pos) > 0) == (pos >= 1) assert (floor(pos) >= 0) == True assert (floor(pos) >= 3) == (pos >= 3) assert (floor(np) <= 0) == True assert (floor(np) > 0) == False assert floor(neg).is_negative == True assert floor(neg).is_nonnegative == False assert floor(nn).is_negative == False assert floor(nn).is_nonnegative == True assert floor(pos).is_negative == False assert floor(pos).is_nonnegative == True assert floor(np).is_negative is None assert floor(np).is_nonnegative is None assert (floor(7, evaluate=False) >= 7) == True assert (floor(7, evaluate=False) > 7) == False assert (floor(7, evaluate=False) <= 7) == True assert (floor(7, evaluate=False) < 7) == False assert (floor(7, evaluate=False) >= 6) == True assert (floor(7, evaluate=False) > 6) == True assert (floor(7, evaluate=False) <= 6) == False assert (floor(7, evaluate=False) < 6) == False assert (floor(7, evaluate=False) >= 8) == False assert (floor(7, evaluate=False) > 8) == False assert (floor(7, evaluate=False) <= 8) == True assert (floor(7, evaluate=False) < 8) == True assert (floor(x) <= 5.5) == Le(floor(x), 5.5, evaluate=False) assert (floor(x) >= -3.2) == Ge(floor(x), -3.2, evaluate=False) assert (floor(x) < 2.9) == Lt(floor(x), 2.9, evaluate=False) assert (floor(x) > -1.7) == Gt(floor(x), -1.7, evaluate=False) assert (floor(y) <= 5.5) == (y < 6) assert (floor(y) >= -3.2) == (y >= -3) assert (floor(y) < 2.9) == (y < 3) assert (floor(y) > -1.7) == (y >= -1) assert (floor(y) <= n) == (y < n + 1) assert (floor(y) >= n) == (y >= n) assert (floor(y) < n) == (y < n) assert (floor(y) > n) == (y >= n + 1) def test_ceiling(): assert ceiling(nan) is nan assert ceiling(oo) is oo assert ceiling(-oo) is -oo assert ceiling(zoo) is zoo assert ceiling(0) == 0 assert ceiling(1) == 1 assert ceiling(-1) == -1 assert ceiling(E) == 3 assert ceiling(-E) == -2 assert ceiling(2*E) == 6 assert ceiling(-2*E) == -5 assert ceiling(pi) == 4 assert ceiling(-pi) == -3 assert ceiling(S.Half) == 1 assert ceiling(Rational(-1, 2)) == 0 assert ceiling(Rational(7, 3)) == 3 assert ceiling(-Rational(7, 3)) == -2 assert ceiling(Float(17.0)) == 17 assert ceiling(-Float(17.0)) == -17 assert ceiling(Float(7.69)) == 8 assert ceiling(-Float(7.69)) == -7 assert ceiling(I) == I assert ceiling(-I) == -I e = ceiling(i) assert e.func is ceiling and e.args[0] == i assert ceiling(oo*I) == oo*I assert ceiling(-oo*I) == -oo*I assert ceiling(exp(I*pi/4)*oo) == exp(I*pi/4)*oo assert ceiling(2*I) == 2*I assert ceiling(-2*I) == -2*I assert ceiling(I/2) == I assert ceiling(-I/2) == 0 assert ceiling(E + 17) == 20 assert ceiling(pi + 2) == 6 assert ceiling(E + pi) == 6 assert ceiling(I + pi) == I + 4 assert ceiling(ceiling(pi)) == 4 assert ceiling(ceiling(y)) == ceiling(y) assert ceiling(ceiling(x)) == ceiling(x) assert unchanged(ceiling, x) assert unchanged(ceiling, 2*x) assert unchanged(ceiling, k*x) assert ceiling(k) == k assert ceiling(2*k) == 2*k assert ceiling(k*n) == k*n assert unchanged(ceiling, k/2) assert unchanged(ceiling, x + y) assert ceiling(x + 3) == ceiling(x) + 3 assert ceiling(x + k) == ceiling(x) + k assert ceiling(y + 3) == ceiling(y) + 3 assert ceiling(y + k) == ceiling(y) + k assert ceiling(3 + pi + y*I) == 7 + ceiling(y)*I assert ceiling(k + n) == k + n assert unchanged(ceiling, x*I) assert ceiling(k*I) == k*I assert ceiling(Rational(23, 10) - E*I) == 3 - 2*I assert ceiling(sin(1)) == 1 assert ceiling(sin(-1)) == 0 assert ceiling(exp(2)) == 8 assert ceiling(-log(8)/log(2)) != -2 assert int(ceiling(-log(8)/log(2)).evalf(chop=True)) == -3 assert ceiling(factorial(50)/exp(1)) == \ 11188719610782480504630258070757734324011354208865721592720336801 assert (ceiling(y) >= y) == True assert (ceiling(y) > y) == False assert (ceiling(y) < y) == False assert (ceiling(y) <= y) == False assert (ceiling(x) >= x).is_Relational # x could be non-real assert (ceiling(x) < x).is_Relational assert (ceiling(x) >= y).is_Relational # arg is not same as rhs assert (ceiling(x) < y).is_Relational assert (ceiling(y) >= -oo) == True assert (ceiling(y) > -oo) == True assert (ceiling(y) <= oo) == True assert (ceiling(y) < oo) == True assert ceiling(y).rewrite(floor) == -floor(-y) assert ceiling(y).rewrite(frac) == y + frac(-y) assert ceiling(y).rewrite(floor).subs(y, -pi) == -floor(pi) assert ceiling(y).rewrite(floor).subs(y, E) == -floor(-E) assert ceiling(y).rewrite(frac).subs(y, pi) == ceiling(pi) assert ceiling(y).rewrite(frac).subs(y, -E) == ceiling(-E) assert Eq(ceiling(y), y + frac(-y)) assert Eq(ceiling(y), -floor(-y)) neg = Symbol('neg', negative=True) nn = Symbol('nn', nonnegative=True) pos = Symbol('pos', positive=True) np = Symbol('np', nonpositive=True) assert (ceiling(neg) <= 0) == True assert (ceiling(neg) < 0) == (neg <= -1) assert (ceiling(neg) > 0) == False assert (ceiling(neg) >= 0) == (neg > -1) assert (ceiling(neg) > -3) == (neg > -3) assert (ceiling(neg) <= 10) == (neg <= 10) assert (ceiling(nn) < 0) == False assert (ceiling(nn) >= 0) == True assert (ceiling(pos) < 0) == False assert (ceiling(pos) <= 0) == False assert (ceiling(pos) > 0) == True assert (ceiling(pos) >= 0) == True assert (ceiling(pos) >= 1) == True assert (ceiling(pos) > 5) == (pos > 5) assert (ceiling(np) <= 0) == True assert (ceiling(np) > 0) == False assert ceiling(neg).is_positive == False assert ceiling(neg).is_nonpositive == True assert ceiling(nn).is_positive is None assert ceiling(nn).is_nonpositive is None assert ceiling(pos).is_positive == True assert ceiling(pos).is_nonpositive == False assert ceiling(np).is_positive == False assert ceiling(np).is_nonpositive == True assert (ceiling(7, evaluate=False) >= 7) == True assert (ceiling(7, evaluate=False) > 7) == False assert (ceiling(7, evaluate=False) <= 7) == True assert (ceiling(7, evaluate=False) < 7) == False assert (ceiling(7, evaluate=False) >= 6) == True assert (ceiling(7, evaluate=False) > 6) == True assert (ceiling(7, evaluate=False) <= 6) == False assert (ceiling(7, evaluate=False) < 6) == False assert (ceiling(7, evaluate=False) >= 8) == False assert (ceiling(7, evaluate=False) > 8) == False assert (ceiling(7, evaluate=False) <= 8) == True assert (ceiling(7, evaluate=False) < 8) == True assert (ceiling(x) <= 5.5) == Le(ceiling(x), 5.5, evaluate=False) assert (ceiling(x) >= -3.2) == Ge(ceiling(x), -3.2, evaluate=False) assert (ceiling(x) < 2.9) == Lt(ceiling(x), 2.9, evaluate=False) assert (ceiling(x) > -1.7) == Gt(ceiling(x), -1.7, evaluate=False) assert (ceiling(y) <= 5.5) == (y <= 5) assert (ceiling(y) >= -3.2) == (y > -4) assert (ceiling(y) < 2.9) == (y <= 2) assert (ceiling(y) > -1.7) == (y > -2) assert (ceiling(y) <= n) == (y <= n) assert (ceiling(y) >= n) == (y > n - 1) assert (ceiling(y) < n) == (y <= n - 1) assert (ceiling(y) > n) == (y > n) def test_frac(): assert isinstance(frac(x), frac) assert frac(oo) == AccumBounds(0, 1) assert frac(-oo) == AccumBounds(0, 1) assert frac(zoo) is nan assert frac(n) == 0 assert frac(nan) is nan assert frac(Rational(4, 3)) == Rational(1, 3) assert frac(-Rational(4, 3)) == Rational(2, 3) assert frac(Rational(-4, 3)) == Rational(2, 3) r = Symbol('r', real=True) assert frac(I*r) == I*frac(r) assert frac(1 + I*r) == I*frac(r) assert frac(0.5 + I*r) == 0.5 + I*frac(r) assert frac(n + I*r) == I*frac(r) assert frac(n + I*k) == 0 assert unchanged(frac, x + I*x) assert frac(x + I*n) == frac(x) assert frac(x).rewrite(floor) == x - floor(x) assert frac(x).rewrite(ceiling) == x + ceiling(-x) assert frac(y).rewrite(floor).subs(y, pi) == frac(pi) assert frac(y).rewrite(floor).subs(y, -E) == frac(-E) assert frac(y).rewrite(ceiling).subs(y, -pi) == frac(-pi) assert frac(y).rewrite(ceiling).subs(y, E) == frac(E) assert Eq(frac(y), y - floor(y)) assert Eq(frac(y), y + ceiling(-y)) r = Symbol('r', real=True) p_i = Symbol('p_i', integer=True, positive=True) n_i = Symbol('p_i', integer=True, negative=True) np_i = Symbol('np_i', integer=True, nonpositive=True) nn_i = Symbol('nn_i', integer=True, nonnegative=True) p_r = Symbol('p_r', real=True, positive=True) n_r = Symbol('n_r', real=True, negative=True) np_r = Symbol('np_r', real=True, nonpositive=True) nn_r = Symbol('nn_r', real=True, nonnegative=True) # Real frac argument, integer rhs assert frac(r) <= p_i assert not frac(r) <= n_i assert (frac(r) <= np_i).has(Le) assert (frac(r) <= nn_i).has(Le) assert frac(r) < p_i assert not frac(r) < n_i assert not frac(r) < np_i assert (frac(r) < nn_i).has(Lt) assert not frac(r) >= p_i assert frac(r) >= n_i assert frac(r) >= np_i assert (frac(r) >= nn_i).has(Ge) assert not frac(r) > p_i assert frac(r) > n_i assert (frac(r) > np_i).has(Gt) assert (frac(r) > nn_i).has(Gt) assert not Eq(frac(r), p_i) assert not Eq(frac(r), n_i) assert Eq(frac(r), np_i).has(Eq) assert Eq(frac(r), nn_i).has(Eq) assert Ne(frac(r), p_i) assert Ne(frac(r), n_i) assert Ne(frac(r), np_i).has(Ne) assert Ne(frac(r), nn_i).has(Ne) # Real frac argument, real rhs assert (frac(r) <= p_r).has(Le) assert not frac(r) <= n_r assert (frac(r) <= np_r).has(Le) assert (frac(r) <= nn_r).has(Le) assert (frac(r) < p_r).has(Lt) assert not frac(r) < n_r assert not frac(r) < np_r assert (frac(r) < nn_r).has(Lt) assert (frac(r) >= p_r).has(Ge) assert frac(r) >= n_r assert frac(r) >= np_r assert (frac(r) >= nn_r).has(Ge) assert (frac(r) > p_r).has(Gt) assert frac(r) > n_r assert (frac(r) > np_r).has(Gt) assert (frac(r) > nn_r).has(Gt) assert not Eq(frac(r), n_r) assert Eq(frac(r), p_r).has(Eq) assert Eq(frac(r), np_r).has(Eq) assert Eq(frac(r), nn_r).has(Eq) assert Ne(frac(r), p_r).has(Ne) assert Ne(frac(r), n_r) assert Ne(frac(r), np_r).has(Ne) assert Ne(frac(r), nn_r).has(Ne) # Real frac argument, +/- oo rhs assert frac(r) < oo assert frac(r) <= oo assert not frac(r) > oo assert not frac(r) >= oo assert not frac(r) < -oo assert not frac(r) <= -oo assert frac(r) > -oo assert frac(r) >= -oo assert frac(r) < 1 assert frac(r) <= 1 assert not frac(r) > 1 assert not frac(r) >= 1 assert not frac(r) < 0 assert (frac(r) <= 0).has(Le) assert (frac(r) > 0).has(Gt) assert frac(r) >= 0 # Some test for numbers assert frac(r) <= sqrt(2) assert (frac(r) <= sqrt(3) - sqrt(2)).has(Le) assert not frac(r) <= sqrt(2) - sqrt(3) assert not frac(r) >= sqrt(2) assert (frac(r) >= sqrt(3) - sqrt(2)).has(Ge) assert frac(r) >= sqrt(2) - sqrt(3) assert not Eq(frac(r), sqrt(2)) assert Eq(frac(r), sqrt(3) - sqrt(2)).has(Eq) assert not Eq(frac(r), sqrt(2) - sqrt(3)) assert Ne(frac(r), sqrt(2)) assert Ne(frac(r), sqrt(3) - sqrt(2)).has(Ne) assert Ne(frac(r), sqrt(2) - sqrt(3)) assert frac(p_i, evaluate=False).is_zero assert frac(p_i, evaluate=False).is_finite assert frac(p_i, evaluate=False).is_integer assert frac(p_i, evaluate=False).is_real assert frac(r).is_finite assert frac(r).is_real assert frac(r).is_zero is None assert frac(r).is_integer is None assert frac(oo).is_finite assert frac(oo).is_real def test_series(): x, y = symbols('x,y') assert floor(x).nseries(x, y, 100) == floor(y) assert ceiling(x).nseries(x, y, 100) == ceiling(y) assert floor(x).nseries(x, pi, 100) == 3 assert ceiling(x).nseries(x, pi, 100) == 4 assert floor(x).nseries(x, 0, 100) == 0 assert ceiling(x).nseries(x, 0, 100) == 1 assert floor(-x).nseries(x, 0, 100) == -1 assert ceiling(-x).nseries(x, 0, 100) == 0 @XFAIL def test_issue_4149(): assert floor(3 + pi*I + y*I) == 3 + floor(pi + y)*I assert floor(3*I + pi*I + y*I) == floor(3 + pi + y)*I assert floor(3 + E + pi*I + y*I) == 5 + floor(pi + y)*I def test_issue_21651(): k = Symbol('k', positive=True, integer=True) exp = 2*2**(-k) assert isinstance(floor(exp), floor) def test_issue_11207(): assert floor(floor(x)) == floor(x) assert floor(ceiling(x)) == ceiling(x) assert ceiling(floor(x)) == floor(x) assert ceiling(ceiling(x)) == ceiling(x) def test_nested_floor_ceiling(): assert floor(-floor(ceiling(x**3)/y)) == -floor(ceiling(x**3)/y) assert ceiling(-floor(ceiling(x**3)/y)) == -floor(ceiling(x**3)/y) assert floor(ceiling(-floor(x**Rational(7, 2)/y))) == -floor(x**Rational(7, 2)/y) assert -ceiling(-ceiling(floor(x)/y)) == ceiling(floor(x)/y) def test_issue_18689(): assert floor(floor(floor(x)) + 3) == floor(x) + 3 assert ceiling(ceiling(ceiling(x)) + 1) == ceiling(x) + 1 assert ceiling(ceiling(floor(x)) + 3) == floor(x) + 3 def test_issue_18421(): assert floor(float(0)) is S.Zero assert ceiling(float(0)) is S.Zero sympy-sympy-1.9/sympy/functions/elementary/tests/test_interface.py000066400000000000000000000035241412543434000260000ustar00rootroot00000000000000# This test file tests the SymPy function interface, that people use to create # their own new functions. It should be as easy as possible. from sympy import Function, sympify, sin, cos, limit, tanh from sympy.abc import x def test_function_series1(): """Create our new "sin" function.""" class my_function(Function): def fdiff(self, argindex=1): return cos(self.args[0]) @classmethod def eval(cls, arg): arg = sympify(arg) if arg == 0: return sympify(0) #Test that the taylor series is correct assert my_function(x).series(x, 0, 10) == sin(x).series(x, 0, 10) assert limit(my_function(x)/x, x, 0) == 1 def test_function_series2(): """Create our new "cos" function.""" class my_function2(Function): def fdiff(self, argindex=1): return -sin(self.args[0]) @classmethod def eval(cls, arg): arg = sympify(arg) if arg == 0: return sympify(1) #Test that the taylor series is correct assert my_function2(x).series(x, 0, 10) == cos(x).series(x, 0, 10) def test_function_series3(): """ Test our easy "tanh" function. This test tests two things: * that the Function interface works as expected and it's easy to use * that the general algorithm for the series expansion works even when the derivative is defined recursively in terms of the original function, since tanh(x).diff(x) == 1-tanh(x)**2 """ class mytanh(Function): def fdiff(self, argindex=1): return 1 - mytanh(self.args[0])**2 @classmethod def eval(cls, arg): arg = sympify(arg) if arg == 0: return sympify(0) e = tanh(x) f = mytanh(x) assert e.series(x, 0, 6) == f.series(x, 0, 6) sympy-sympy-1.9/sympy/functions/elementary/tests/test_miscellaneous.py000066400000000000000000000372131412543434000267050ustar00rootroot00000000000000import itertools as it from sympy.core.expr import unchanged from sympy.core.function import Function from sympy.core.numbers import I, oo, Rational from sympy.core.power import Pow from sympy.core.singleton import S from sympy.core.symbol import Symbol from sympy.external import import_module from sympy.functions.elementary.exponential import log from sympy.functions.elementary.integers import floor, ceiling from sympy.functions.elementary.miscellaneous import (sqrt, cbrt, root, Min, Max, real_root) from sympy.functions.elementary.trigonometric import cos, sin from sympy.functions.special.delta_functions import Heaviside from sympy.utilities.lambdify import lambdify from sympy.testing.pytest import raises, skip, ignore_warnings def test_Min(): from sympy.abc import x, y, z n = Symbol('n', negative=True) n_ = Symbol('n_', negative=True) nn = Symbol('nn', nonnegative=True) nn_ = Symbol('nn_', nonnegative=True) p = Symbol('p', positive=True) p_ = Symbol('p_', positive=True) np = Symbol('np', nonpositive=True) np_ = Symbol('np_', nonpositive=True) r = Symbol('r', real=True) assert Min(5, 4) == 4 assert Min(-oo, -oo) is -oo assert Min(-oo, n) is -oo assert Min(n, -oo) is -oo assert Min(-oo, np) is -oo assert Min(np, -oo) is -oo assert Min(-oo, 0) is -oo assert Min(0, -oo) is -oo assert Min(-oo, nn) is -oo assert Min(nn, -oo) is -oo assert Min(-oo, p) is -oo assert Min(p, -oo) is -oo assert Min(-oo, oo) is -oo assert Min(oo, -oo) is -oo assert Min(n, n) == n assert unchanged(Min, n, np) assert Min(np, n) == Min(n, np) assert Min(n, 0) == n assert Min(0, n) == n assert Min(n, nn) == n assert Min(nn, n) == n assert Min(n, p) == n assert Min(p, n) == n assert Min(n, oo) == n assert Min(oo, n) == n assert Min(np, np) == np assert Min(np, 0) == np assert Min(0, np) == np assert Min(np, nn) == np assert Min(nn, np) == np assert Min(np, p) == np assert Min(p, np) == np assert Min(np, oo) == np assert Min(oo, np) == np assert Min(0, 0) == 0 assert Min(0, nn) == 0 assert Min(nn, 0) == 0 assert Min(0, p) == 0 assert Min(p, 0) == 0 assert Min(0, oo) == 0 assert Min(oo, 0) == 0 assert Min(nn, nn) == nn assert unchanged(Min, nn, p) assert Min(p, nn) == Min(nn, p) assert Min(nn, oo) == nn assert Min(oo, nn) == nn assert Min(p, p) == p assert Min(p, oo) == p assert Min(oo, p) == p assert Min(oo, oo) is oo assert Min(n, n_).func is Min assert Min(nn, nn_).func is Min assert Min(np, np_).func is Min assert Min(p, p_).func is Min # lists assert Min() is S.Infinity assert Min(x) == x assert Min(x, y) == Min(y, x) assert Min(x, y, z) == Min(z, y, x) assert Min(x, Min(y, z)) == Min(z, y, x) assert Min(x, Max(y, -oo)) == Min(x, y) assert Min(p, oo, n, p, p, p_) == n assert Min(p_, n_, p) == n_ assert Min(n, oo, -7, p, p, 2) == Min(n, -7) assert Min(2, x, p, n, oo, n_, p, 2, -2, -2) == Min(-2, x, n, n_) assert Min(0, x, 1, y) == Min(0, x, y) assert Min(1000, 100, -100, x, p, n) == Min(n, x, -100) assert unchanged(Min, sin(x), cos(x)) assert Min(sin(x), cos(x)) == Min(cos(x), sin(x)) assert Min(cos(x), sin(x)).subs(x, 1) == cos(1) assert Min(cos(x), sin(x)).subs(x, S.Half) == sin(S.Half) raises(ValueError, lambda: Min(cos(x), sin(x)).subs(x, I)) raises(ValueError, lambda: Min(I)) raises(ValueError, lambda: Min(I, x)) raises(ValueError, lambda: Min(S.ComplexInfinity, x)) assert Min(1, x).diff(x) == Heaviside(1 - x) assert Min(x, 1).diff(x) == Heaviside(1 - x) assert Min(0, -x, 1 - 2*x).diff(x) == -Heaviside(x + Min(0, -2*x + 1)) \ - 2*Heaviside(2*x + Min(0, -x) - 1) # issue 7619 f = Function('f') assert Min(1, 2*Min(f(1), 2)) # doesn't fail # issue 7233 e = Min(0, x) assert e.n().args == (0, x) # issue 8643 m = Min(n, p_, n_, r) assert m.is_positive is False assert m.is_nonnegative is False assert m.is_negative is True m = Min(p, p_) assert m.is_positive is True assert m.is_nonnegative is True assert m.is_negative is False m = Min(p, nn_, p_) assert m.is_positive is None assert m.is_nonnegative is True assert m.is_negative is False m = Min(nn, p, r) assert m.is_positive is None assert m.is_nonnegative is None assert m.is_negative is None def test_Max(): from sympy.abc import x, y, z n = Symbol('n', negative=True) n_ = Symbol('n_', negative=True) nn = Symbol('nn', nonnegative=True) p = Symbol('p', positive=True) p_ = Symbol('p_', positive=True) r = Symbol('r', real=True) assert Max(5, 4) == 5 # lists assert Max() is S.NegativeInfinity assert Max(x) == x assert Max(x, y) == Max(y, x) assert Max(x, y, z) == Max(z, y, x) assert Max(x, Max(y, z)) == Max(z, y, x) assert Max(x, Min(y, oo)) == Max(x, y) assert Max(n, -oo, n_, p, 2) == Max(p, 2) assert Max(n, -oo, n_, p) == p assert Max(2, x, p, n, -oo, S.NegativeInfinity, n_, p, 2) == Max(2, x, p) assert Max(0, x, 1, y) == Max(1, x, y) assert Max(r, r + 1, r - 1) == 1 + r assert Max(1000, 100, -100, x, p, n) == Max(p, x, 1000) assert Max(cos(x), sin(x)) == Max(sin(x), cos(x)) assert Max(cos(x), sin(x)).subs(x, 1) == sin(1) assert Max(cos(x), sin(x)).subs(x, S.Half) == cos(S.Half) raises(ValueError, lambda: Max(cos(x), sin(x)).subs(x, I)) raises(ValueError, lambda: Max(I)) raises(ValueError, lambda: Max(I, x)) raises(ValueError, lambda: Max(S.ComplexInfinity, 1)) assert Max(n, -oo, n_, p, 2) == Max(p, 2) assert Max(n, -oo, n_, p, 1000) == Max(p, 1000) assert Max(1, x).diff(x) == Heaviside(x - 1) assert Max(x, 1).diff(x) == Heaviside(x - 1) assert Max(x**2, 1 + x, 1).diff(x) == \ 2*x*Heaviside(x**2 - Max(1, x + 1)) \ + Heaviside(x - Max(1, x**2) + 1) e = Max(0, x) assert e.n().args == (0, x) # issue 8643 m = Max(p, p_, n, r) assert m.is_positive is True assert m.is_nonnegative is True assert m.is_negative is False m = Max(n, n_) assert m.is_positive is False assert m.is_nonnegative is False assert m.is_negative is True m = Max(n, n_, r) assert m.is_positive is None assert m.is_nonnegative is None assert m.is_negative is None m = Max(n, nn, r) assert m.is_positive is None assert m.is_nonnegative is True assert m.is_negative is False def test_minmax_assumptions(): r = Symbol('r', real=True) a = Symbol('a', real=True, algebraic=True) t = Symbol('t', real=True, transcendental=True) q = Symbol('q', rational=True) p = Symbol('p', irrational=True) n = Symbol('n', rational=True, integer=False) i = Symbol('i', integer=True) o = Symbol('o', odd=True) e = Symbol('e', even=True) k = Symbol('k', prime=True) reals = [r, a, t, q, p, n, i, o, e, k] for ext in (Max, Min): for x, y in it.product(reals, repeat=2): # Must be real assert ext(x, y).is_real # Algebraic? if x.is_algebraic and y.is_algebraic: assert ext(x, y).is_algebraic elif x.is_transcendental and y.is_transcendental: assert ext(x, y).is_transcendental else: assert ext(x, y).is_algebraic is None # Rational? if x.is_rational and y.is_rational: assert ext(x, y).is_rational elif x.is_irrational and y.is_irrational: assert ext(x, y).is_irrational else: assert ext(x, y).is_rational is None # Integer? if x.is_integer and y.is_integer: assert ext(x, y).is_integer elif x.is_noninteger and y.is_noninteger: assert ext(x, y).is_noninteger else: assert ext(x, y).is_integer is None # Odd? if x.is_odd and y.is_odd: assert ext(x, y).is_odd elif x.is_odd is False and y.is_odd is False: assert ext(x, y).is_odd is False else: assert ext(x, y).is_odd is None # Even? if x.is_even and y.is_even: assert ext(x, y).is_even elif x.is_even is False and y.is_even is False: assert ext(x, y).is_even is False else: assert ext(x, y).is_even is None # Prime? if x.is_prime and y.is_prime: assert ext(x, y).is_prime elif x.is_prime is False and y.is_prime is False: assert ext(x, y).is_prime is False else: assert ext(x, y).is_prime is None def test_issue_8413(): x = Symbol('x', real=True) # we can't evaluate in general because non-reals are not # comparable: Min(floor(3.2 + I), 3.2 + I) -> ValueError assert Min(floor(x), x) == floor(x) assert Min(ceiling(x), x) == x assert Max(floor(x), x) == x assert Max(ceiling(x), x) == ceiling(x) def test_root(): from sympy.abc import x n = Symbol('n', integer=True) k = Symbol('k', integer=True) assert root(2, 2) == sqrt(2) assert root(2, 1) == 2 assert root(2, 3) == 2**Rational(1, 3) assert root(2, 3) == cbrt(2) assert root(2, -5) == 2**Rational(4, 5)/2 assert root(-2, 1) == -2 assert root(-2, 2) == sqrt(2)*I assert root(-2, 1) == -2 assert root(x, 2) == sqrt(x) assert root(x, 1) == x assert root(x, 3) == x**Rational(1, 3) assert root(x, 3) == cbrt(x) assert root(x, -5) == x**Rational(-1, 5) assert root(x, n) == x**(1/n) assert root(x, -n) == x**(-1/n) assert root(x, n, k) == (-1)**(2*k/n)*x**(1/n) def test_real_root(): assert real_root(-8, 3) == -2 assert real_root(-16, 4) == root(-16, 4) r = root(-7, 4) assert real_root(r) == r r1 = root(-1, 3) r2 = r1**2 r3 = root(-1, 4) assert real_root(r1 + r2 + r3) == -1 + r2 + r3 assert real_root(root(-2, 3)) == -root(2, 3) assert real_root(-8., 3) == -2 x = Symbol('x') n = Symbol('n') g = real_root(x, n) assert g.subs(dict(x=-8, n=3)) == -2 assert g.subs(dict(x=8, n=3)) == 2 # give principle root if there is no real root -- if this is not desired # then maybe a Root class is needed to raise an error instead assert g.subs(dict(x=I, n=3)) == cbrt(I) assert g.subs(dict(x=-8, n=2)) == sqrt(-8) assert g.subs(dict(x=I, n=2)) == sqrt(I) def test_issue_11463(): numpy = import_module('numpy') if not numpy: skip("numpy not installed.") x = Symbol('x') f = lambdify(x, real_root((log(x/(x-2))), 3), 'numpy') # numpy.select evaluates all options before considering conditions, # so it raises a warning about root of negative number which does # not affect the outcome. This warning is suppressed here with ignore_warnings(RuntimeWarning): assert f(numpy.array(-1)) < -1 def test_rewrite_MaxMin_as_Heaviside(): from sympy.abc import x assert Max(0, x).rewrite(Heaviside) == x*Heaviside(x) assert Max(3, x).rewrite(Heaviside) == x*Heaviside(x - 3) + \ 3*Heaviside(-x + 3) assert Max(0, x+2, 2*x).rewrite(Heaviside) == \ 2*x*Heaviside(2*x)*Heaviside(x - 2) + \ (x + 2)*Heaviside(-x + 2)*Heaviside(x + 2) assert Min(0, x).rewrite(Heaviside) == x*Heaviside(-x) assert Min(3, x).rewrite(Heaviside) == x*Heaviside(-x + 3) + \ 3*Heaviside(x - 3) assert Min(x, -x, -2).rewrite(Heaviside) == \ x*Heaviside(-2*x)*Heaviside(-x - 2) - \ x*Heaviside(2*x)*Heaviside(x - 2) \ - 2*Heaviside(-x + 2)*Heaviside(x + 2) def test_rewrite_MaxMin_as_Piecewise(): from sympy import symbols, Piecewise x, y, z, a, b = symbols('x y z a b', real=True) vx, vy, va = symbols('vx vy va') assert Max(a, b).rewrite(Piecewise) == Piecewise((a, a >= b), (b, True)) assert Max(x, y, z).rewrite(Piecewise) == Piecewise((x, (x >= y) & (x >= z)), (y, y >= z), (z, True)) assert Max(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a >= b) & (a >= x) & (a >= y)), (b, (b >= x) & (b >= y)), (x, x >= y), (y, True)) assert Min(a, b).rewrite(Piecewise) == Piecewise((a, a <= b), (b, True)) assert Min(x, y, z).rewrite(Piecewise) == Piecewise((x, (x <= y) & (x <= z)), (y, y <= z), (z, True)) assert Min(x, y, a, b).rewrite(Piecewise) == Piecewise((a, (a <= b) & (a <= x) & (a <= y)), (b, (b <= x) & (b <= y)), (x, x <= y), (y, True)) # Piecewise rewriting of Min/Max does also takes place for not explicitly real arguments assert Max(vx, vy).rewrite(Piecewise) == Piecewise((vx, vx >= vy), (vy, True)) assert Min(va, vx, vy).rewrite(Piecewise) == Piecewise((va, (va <= vx) & (va <= vy)), (vx, vx <= vy), (vy, True)) def test_issue_11099(): from sympy.abc import x, y # some fixed value tests fixed_test_data = {x: -2, y: 3} assert Min(x, y).evalf(subs=fixed_test_data) == \ Min(x, y).subs(fixed_test_data).evalf() assert Max(x, y).evalf(subs=fixed_test_data) == \ Max(x, y).subs(fixed_test_data).evalf() # randomly generate some test data from random import randint for i in range(20): random_test_data = {x: randint(-100, 100), y: randint(-100, 100)} assert Min(x, y).evalf(subs=random_test_data) == \ Min(x, y).subs(random_test_data).evalf() assert Max(x, y).evalf(subs=random_test_data) == \ Max(x, y).subs(random_test_data).evalf() def test_issue_12638(): from sympy.abc import a, b, c assert Min(a, b, c, Max(a, b)) == Min(a, b, c) assert Min(a, b, Max(a, b, c)) == Min(a, b) assert Min(a, b, Max(a, c)) == Min(a, b) def test_issue_21399(): from sympy.abc import a, b, c assert Max(Min(a, b), Min(a, b, c)) == Min(a, b) def test_instantiation_evaluation(): from sympy.abc import v, w, x, y, z assert Min(1, Max(2, x)) == 1 assert Max(3, Min(2, x)) == 3 assert Min(Max(x, y), Max(x, z)) == Max(x, Min(y, z)) assert set(Min(Max(w, x), Max(y, z)).args) == { Max(w, x), Max(y, z)} assert Min(Max(x, y), Max(x, z), w) == Min( w, Max(x, Min(y, z))) A, B = Min, Max for i in range(2): assert A(x, B(x, y)) == x assert A(x, B(y, A(x, w, z))) == A(x, B(y, A(w, z))) A, B = B, A assert Min(w, Max(x, y), Max(v, x, z)) == Min( w, Max(x, Min(y, Max(v, z)))) def test_rewrite_as_Abs(): from itertools import permutations from sympy.functions.elementary.complexes import Abs from sympy.abc import x, y, z, w def test(e): free = e.free_symbols a = e.rewrite(Abs) assert not a.has(Min, Max) for i in permutations(range(len(free))): reps = dict(zip(free, i)) assert a.xreplace(reps) == e.xreplace(reps) test(Min(x, y)) test(Max(x, y)) test(Min(x, y, z)) test(Min(Max(w, x), Max(y, z))) def test_issue_14000(): assert isinstance(sqrt(4, evaluate=False), Pow) == True assert isinstance(cbrt(3.5, evaluate=False), Pow) == True assert isinstance(root(16, 4, evaluate=False), Pow) == True assert sqrt(4, evaluate=False) == Pow(4, S.Half, evaluate=False) assert cbrt(3.5, evaluate=False) == Pow(3.5, Rational(1, 3), evaluate=False) assert root(4, 2, evaluate=False) == Pow(4, S.Half, evaluate=False) assert root(16, 4, 2, evaluate=False).has(Pow) == True assert real_root(-8, 3, evaluate=False).has(Pow) == True def test_issue_6899(): from sympy import Lambda x = Symbol('x') eqn = Lambda(x, x) assert eqn.func(*eqn.args) == eqn sympy-sympy-1.9/sympy/functions/elementary/tests/test_piecewise.py000066400000000000000000001425721412543434000260240ustar00rootroot00000000000000from sympy import ( adjoint, And, Basic, conjugate, diff, expand, Eq, Function, I, ITE, Integral, integrate, Interval, KroneckerDelta, lambdify, log, Max, Min, oo, Or, pi, Piecewise, piecewise_fold, Rational, solve, symbols, transpose, cos, sin, exp, Abs, Ne, Not, Symbol, S, sqrt, Sum, Tuple, zoo, Float, DiracDelta, Heaviside, Add, Mul, factorial, Ge, Contains) from sympy.core.expr import unchanged from sympy.functions.elementary.piecewise import Undefined, ExprCondPair from sympy.printing import srepr from sympy.testing.pytest import raises, slow from sympy.simplify import simplify a, b, c, d, x, y = symbols('a:d, x, y') z = symbols('z', nonzero=True) def test_piecewise1(): # Test canonicalization assert unchanged(Piecewise, ExprCondPair(x, x < 1), ExprCondPair(0, True)) assert Piecewise((x, x < 1), (0, True)) == Piecewise(ExprCondPair(x, x < 1), ExprCondPair(0, True)) assert Piecewise((x, x < 1), (0, True), (1, True)) == \ Piecewise((x, x < 1), (0, True)) assert Piecewise((x, x < 1), (0, False), (-1, 1 > 2)) == \ Piecewise((x, x < 1)) assert Piecewise((x, x < 1), (0, x < 1), (0, True)) == \ Piecewise((x, x < 1), (0, True)) assert Piecewise((x, x < 1), (0, x < 2), (0, True)) == \ Piecewise((x, x < 1), (0, True)) assert Piecewise((x, x < 1), (x, x < 2), (0, True)) == \ Piecewise((x, Or(x < 1, x < 2)), (0, True)) assert Piecewise((x, x < 1), (x, x < 2), (x, True)) == x assert Piecewise((x, True)) == x # Explicitly constructed empty Piecewise not accepted raises(TypeError, lambda: Piecewise()) # False condition is never retained assert Piecewise((2*x, x < 0), (x, False)) == \ Piecewise((2*x, x < 0), (x, False), evaluate=False) == \ Piecewise((2*x, x < 0)) assert Piecewise((x, False)) == Undefined raises(TypeError, lambda: Piecewise(x)) assert Piecewise((x, 1)) == x # 1 and 0 are accepted as True/False raises(TypeError, lambda: Piecewise((x, 2))) raises(TypeError, lambda: Piecewise((x, x**2))) raises(TypeError, lambda: Piecewise(([1], True))) assert Piecewise(((1, 2), True)) == Tuple(1, 2) cond = (Piecewise((1, x < 0), (2, True)) < y) assert Piecewise((1, cond) ) == Piecewise((1, ITE(x < 0, y > 1, y > 2))) assert Piecewise((1, x > 0), (2, And(x <= 0, x > -1)) ) == Piecewise((1, x > 0), (2, x > -1)) # test for supporting Contains in Piecewise pwise = Piecewise( (1, And(x <= 6, x > 1, Contains(x, S.Integers))), (0, True)) assert pwise.subs(x, pi) == 0 assert pwise.subs(x, 2) == 1 assert pwise.subs(x, 7) == 0 # Test subs p = Piecewise((-1, x < -1), (x**2, x < 0), (log(x), x >= 0)) p_x2 = Piecewise((-1, x**2 < -1), (x**4, x**2 < 0), (log(x**2), x**2 >= 0)) assert p.subs(x, x**2) == p_x2 assert p.subs(x, -5) == -1 assert p.subs(x, -1) == 1 assert p.subs(x, 1) == log(1) # More subs tests p2 = Piecewise((1, x < pi), (-1, x < 2*pi), (0, x > 2*pi)) p3 = Piecewise((1, Eq(x, 0)), (1/x, True)) p4 = Piecewise((1, Eq(x, 0)), (2, 1/x>2)) assert p2.subs(x, 2) == 1 assert p2.subs(x, 4) == -1 assert p2.subs(x, 10) == 0 assert p3.subs(x, 0.0) == 1 assert p4.subs(x, 0.0) == 1 f, g, h = symbols('f,g,h', cls=Function) pf = Piecewise((f(x), x < -1), (f(x) + h(x) + 2, x <= 1)) pg = Piecewise((g(x), x < -1), (g(x) + h(x) + 2, x <= 1)) assert pg.subs(g, f) == pf assert Piecewise((1, Eq(x, 0)), (0, True)).subs(x, 0) == 1 assert Piecewise((1, Eq(x, 0)), (0, True)).subs(x, 1) == 0 assert Piecewise((1, Eq(x, y)), (0, True)).subs(x, y) == 1 assert Piecewise((1, Eq(x, z)), (0, True)).subs(x, z) == 1 assert Piecewise((1, Eq(exp(x), cos(z))), (0, True)).subs(x, z) == \ Piecewise((1, Eq(exp(z), cos(z))), (0, True)) p5 = Piecewise( (0, Eq(cos(x) + y, 0)), (1, True)) assert p5.subs(y, 0) == Piecewise( (0, Eq(cos(x), 0)), (1, True)) assert Piecewise((-1, y < 1), (0, x < 0), (1, Eq(x, 0)), (2, True) ).subs(x, 1) == Piecewise((-1, y < 1), (2, True)) assert Piecewise((1, Eq(x**2, -1)), (2, x < 0)).subs(x, I) == 1 p6 = Piecewise((x, x > 0)) n = symbols('n', negative=True) assert p6.subs(x, n) == Undefined # Test evalf assert p.evalf() == p assert p.evalf(subs={x: -2}) == -1 assert p.evalf(subs={x: -1}) == 1 assert p.evalf(subs={x: 1}) == log(1) assert p6.evalf(subs={x: -5}) == Undefined # Test doit f_int = Piecewise((Integral(x, (x, 0, 1)), x < 1)) assert f_int.doit() == Piecewise( (S.Half, x < 1) ) # Test differentiation f = x fp = x*p dp = Piecewise((0, x < -1), (2*x, x < 0), (1/x, x >= 0)) fp_dx = x*dp + p assert diff(p, x) == dp assert diff(f*p, x) == fp_dx # Test simple arithmetic assert x*p == fp assert x*p + p == p + x*p assert p + f == f + p assert p + dp == dp + p assert p - dp == -(dp - p) # Test power dp2 = Piecewise((0, x < -1), (4*x**2, x < 0), (1/x**2, x >= 0)) assert dp**2 == dp2 # Test _eval_interval f1 = x*y + 2 f2 = x*y**2 + 3 peval = Piecewise((f1, x < 0), (f2, x > 0)) peval_interval = f1.subs( x, 0) - f1.subs(x, -1) + f2.subs(x, 1) - f2.subs(x, 0) assert peval._eval_interval(x, 0, 0) == 0 assert peval._eval_interval(x, -1, 1) == peval_interval peval2 = Piecewise((f1, x < 0), (f2, True)) assert peval2._eval_interval(x, 0, 0) == 0 assert peval2._eval_interval(x, 1, -1) == -peval_interval assert peval2._eval_interval(x, -1, -2) == f1.subs(x, -2) - f1.subs(x, -1) assert peval2._eval_interval(x, -1, 1) == peval_interval assert peval2._eval_interval(x, None, 0) == peval2.subs(x, 0) assert peval2._eval_interval(x, -1, None) == -peval2.subs(x, -1) # Test integration assert p.integrate() == Piecewise( (-x, x < -1), (x**3/3 + Rational(4, 3), x < 0), (x*log(x) - x + Rational(4, 3), True)) p = Piecewise((x, x < 1), (x**2, -1 <= x), (x, 3 < x)) assert integrate(p, (x, -2, 2)) == Rational(5, 6) assert integrate(p, (x, 2, -2)) == Rational(-5, 6) p = Piecewise((0, x < 0), (1, x < 1), (0, x < 2), (1, x < 3), (0, True)) assert integrate(p, (x, -oo, oo)) == 2 p = Piecewise((x, x < -10), (x**2, x <= -1), (x, 1 < x)) assert integrate(p, (x, -2, 2)) == Undefined # Test commutativity assert isinstance(p, Piecewise) and p.is_commutative is True def test_piecewise_free_symbols(): f = Piecewise((x, a < 0), (y, True)) assert f.free_symbols == {x, y, a} def test_piecewise_integrate1(): x, y = symbols('x y', real=True, finite=True) f = Piecewise(((x - 2)**2, x >= 0), (1, True)) assert integrate(f, (x, -2, 2)) == Rational(14, 3) g = Piecewise(((x - 5)**5, x >= 4), (f, True)) assert integrate(g, (x, -2, 2)) == Rational(14, 3) assert integrate(g, (x, -2, 5)) == Rational(43, 6) assert g == Piecewise(((x - 5)**5, x >= 4), (f, x < 4)) g = Piecewise(((x - 5)**5, 2 <= x), (f, x < 2)) assert integrate(g, (x, -2, 2)) == Rational(14, 3) assert integrate(g, (x, -2, 5)) == Rational(-701, 6) assert g == Piecewise(((x - 5)**5, 2 <= x), (f, True)) g = Piecewise(((x - 5)**5, 2 <= x), (2*f, True)) assert integrate(g, (x, -2, 2)) == Rational(28, 3) assert integrate(g, (x, -2, 5)) == Rational(-673, 6) def test_piecewise_integrate1b(): g = Piecewise((1, x > 0), (0, Eq(x, 0)), (-1, x < 0)) assert integrate(g, (x, -1, 1)) == 0 g = Piecewise((1, x - y < 0), (0, True)) assert integrate(g, (y, -oo, 0)) == -Min(0, x) assert g.subs(x, -3).integrate((y, -oo, 0)) == 3 assert integrate(g, (y, 0, -oo)) == Min(0, x) assert integrate(g, (y, 0, oo)) == -Max(0, x) + oo assert integrate(g, (y, -oo, 42)) == -Min(42, x) + 42 assert integrate(g, (y, -oo, oo)) == -x + oo g = Piecewise((0, x < 0), (x, x <= 1), (1, True)) gy1 = g.integrate((x, y, 1)) g1y = g.integrate((x, 1, y)) for yy in (-1, S.Half, 2): assert g.integrate((x, yy, 1)) == gy1.subs(y, yy) assert g.integrate((x, 1, yy)) == g1y.subs(y, yy) assert gy1 == Piecewise( (-Min(1, Max(0, y))**2/2 + S.Half, y < 1), (-y + 1, True)) assert g1y == Piecewise( (Min(1, Max(0, y))**2/2 - S.Half, y < 1), (y - 1, True)) @slow def test_piecewise_integrate1ca(): y = symbols('y', real=True) g = Piecewise( (1 - x, Interval(0, 1).contains(x)), (1 + x, Interval(-1, 0).contains(x)), (0, True) ) gy1 = g.integrate((x, y, 1)) g1y = g.integrate((x, 1, y)) assert g.integrate((x, -2, 1)) == gy1.subs(y, -2) assert g.integrate((x, 1, -2)) == g1y.subs(y, -2) assert g.integrate((x, 0, 1)) == gy1.subs(y, 0) assert g.integrate((x, 1, 0)) == g1y.subs(y, 0) assert g.integrate((x, 2, 1)) == gy1.subs(y, 2) assert g.integrate((x, 1, 2)) == g1y.subs(y, 2) assert piecewise_fold(gy1.rewrite(Piecewise)) == \ Piecewise( (1, y <= -1), (-y**2/2 - y + S.Half, y <= 0), (y**2/2 - y + S.Half, y < 1), (0, True)) assert piecewise_fold(g1y.rewrite(Piecewise)) == \ Piecewise( (-1, y <= -1), (y**2/2 + y - S.Half, y <= 0), (-y**2/2 + y - S.Half, y < 1), (0, True)) assert gy1 == Piecewise( ( -Min(1, Max(-1, y))**2/2 - Min(1, Max(-1, y)) + Min(1, Max(0, y))**2 + S.Half, y < 1), (0, True) ) assert g1y == Piecewise( ( Min(1, Max(-1, y))**2/2 + Min(1, Max(-1, y)) - Min(1, Max(0, y))**2 - S.Half, y < 1), (0, True)) @slow def test_piecewise_integrate1cb(): y = symbols('y', real=True) g = Piecewise( (0, Or(x <= -1, x >= 1)), (1 - x, x > 0), (1 + x, True) ) gy1 = g.integrate((x, y, 1)) g1y = g.integrate((x, 1, y)) assert g.integrate((x, -2, 1)) == gy1.subs(y, -2) assert g.integrate((x, 1, -2)) == g1y.subs(y, -2) assert g.integrate((x, 0, 1)) == gy1.subs(y, 0) assert g.integrate((x, 1, 0)) == g1y.subs(y, 0) assert g.integrate((x, 2, 1)) == gy1.subs(y, 2) assert g.integrate((x, 1, 2)) == g1y.subs(y, 2) assert piecewise_fold(gy1.rewrite(Piecewise)) == \ Piecewise( (1, y <= -1), (-y**2/2 - y + S.Half, y <= 0), (y**2/2 - y + S.Half, y < 1), (0, True)) assert piecewise_fold(g1y.rewrite(Piecewise)) == \ Piecewise( (-1, y <= -1), (y**2/2 + y - S.Half, y <= 0), (-y**2/2 + y - S.Half, y < 1), (0, True)) # g1y and gy1 should simplify if the condition that y < 1 # is applied, e.g. Min(1, Max(-1, y)) --> Max(-1, y) assert gy1 == Piecewise( ( -Min(1, Max(-1, y))**2/2 - Min(1, Max(-1, y)) + Min(1, Max(0, y))**2 + S.Half, y < 1), (0, True) ) assert g1y == Piecewise( ( Min(1, Max(-1, y))**2/2 + Min(1, Max(-1, y)) - Min(1, Max(0, y))**2 - S.Half, y < 1), (0, True)) def test_piecewise_integrate2(): from itertools import permutations lim = Tuple(x, c, d) p = Piecewise((1, x < a), (2, x > b), (3, True)) q = p.integrate(lim) assert q == Piecewise( (-c + 2*d - 2*Min(d, Max(a, c)) + Min(d, Max(a, b, c)), c < d), (-2*c + d + 2*Min(c, Max(a, d)) - Min(c, Max(a, b, d)), True)) for v in permutations((1, 2, 3, 4)): r = dict(zip((a, b, c, d), v)) assert p.subs(r).integrate(lim.subs(r)) == q.subs(r) def test_meijer_bypass(): # totally bypass meijerg machinery when dealing # with Piecewise in integrate assert Piecewise((1, x < 4), (0, True)).integrate((x, oo, 1)) == -3 def test_piecewise_integrate3_inequality_conditions(): from sympy.utilities.iterables import cartes lim = (x, 0, 5) # set below includes two pts below range, 2 pts in range, # 2 pts above range, and the boundaries N = (-2, -1, 0, 1, 2, 5, 6, 7) p = Piecewise((1, x > a), (2, x > b), (0, True)) ans = p.integrate(lim) for i, j in cartes(N, repeat=2): reps = dict(zip((a, b), (i, j))) assert ans.subs(reps) == p.subs(reps).integrate(lim) assert ans.subs(a, 4).subs(b, 1) == 0 + 2*3 + 1 p = Piecewise((1, x > a), (2, x < b), (0, True)) ans = p.integrate(lim) for i, j in cartes(N, repeat=2): reps = dict(zip((a, b), (i, j))) assert ans.subs(reps) == p.subs(reps).integrate(lim) # delete old tests that involved c1 and c2 since those # reduce to the above except that a value of 0 was used # for two expressions whereas the above uses 3 different # values @slow def test_piecewise_integrate4_symbolic_conditions(): a = Symbol('a', real=True, finite=True) b = Symbol('b', real=True, finite=True) x = Symbol('x', real=True, finite=True) y = Symbol('y', real=True, finite=True) p0 = Piecewise((0, Or(x < a, x > b)), (1, True)) p1 = Piecewise((0, x < a), (0, x > b), (1, True)) p2 = Piecewise((0, x > b), (0, x < a), (1, True)) p3 = Piecewise((0, x < a), (1, x < b), (0, True)) p4 = Piecewise((0, x > b), (1, x > a), (0, True)) p5 = Piecewise((1, And(a < x, x < b)), (0, True)) # check values of a=1, b=3 (and reversed) with values # of y of 0, 1, 2, 3, 4 lim = Tuple(x, -oo, y) for p in (p0, p1, p2, p3, p4, p5): ans = p.integrate(lim) for i in range(5): reps = {a:1, b:3, y:i} assert ans.subs(reps) == p.subs(reps).integrate(lim.subs(reps)) reps = {a: 3, b:1, y:i} assert ans.subs(reps) == p.subs(reps).integrate(lim.subs(reps)) lim = Tuple(x, y, oo) for p in (p0, p1, p2, p3, p4, p5): ans = p.integrate(lim) for i in range(5): reps = {a:1, b:3, y:i} assert ans.subs(reps) == p.subs(reps).integrate(lim.subs(reps)) reps = {a:3, b:1, y:i} assert ans.subs(reps) == p.subs(reps).integrate(lim.subs(reps)) ans = Piecewise( (0, x <= Min(a, b)), (x - Min(a, b), x <= b), (b - Min(a, b), True)) for i in (p0, p1, p2, p4): assert i.integrate(x) == ans assert p3.integrate(x) == Piecewise( (0, x < a), (-a + x, x <= Max(a, b)), (-a + Max(a, b), True)) assert p5.integrate(x) == Piecewise( (0, x <= a), (-a + x, x <= Max(a, b)), (-a + Max(a, b), True)) p1 = Piecewise((0, x < a), (0.5, x > b), (1, True)) p2 = Piecewise((0.5, x > b), (0, x < a), (1, True)) p3 = Piecewise((0, x < a), (1, x < b), (0.5, True)) p4 = Piecewise((0.5, x > b), (1, x > a), (0, True)) p5 = Piecewise((1, And(a < x, x < b)), (0.5, x > b), (0, True)) # check values of a=1, b=3 (and reversed) with values # of y of 0, 1, 2, 3, 4 lim = Tuple(x, -oo, y) for p in (p1, p2, p3, p4, p5): ans = p.integrate(lim) for i in range(5): reps = {a:1, b:3, y:i} assert ans.subs(reps) == p.subs(reps).integrate(lim.subs(reps)) reps = {a: 3, b:1, y:i} assert ans.subs(reps) == p.subs(reps).integrate(lim.subs(reps)) def test_piecewise_integrate5_independent_conditions(): p = Piecewise((0, Eq(y, 0)), (x*y, True)) assert integrate(p, (x, 1, 3)) == Piecewise((0, Eq(y, 0)), (4*y, True)) def test_piecewise_simplify(): p = Piecewise(((x**2 + 1)/x**2, Eq(x*(1 + x) - x**2, 0)), ((-1)**x*(-1), True)) assert p.simplify() == \ Piecewise((zoo, Eq(x, 0)), ((-1)**(x + 1), True)) # simplify when there are Eq in conditions assert Piecewise( (a, And(Eq(a, 0), Eq(a + b, 0))), (1, True)).simplify( ) == Piecewise( (0, And(Eq(a, 0), Eq(b, 0))), (1, True)) assert Piecewise((2*x*factorial(a)/(factorial(y)*factorial(-y + a)), Eq(y, 0) & Eq(-y + a, 0)), (2*factorial(a)/(factorial(y)*factorial(-y + a)), Eq(y, 0) & Eq(-y + a, 1)), (0, True)).simplify( ) == Piecewise( (2*x, And(Eq(a, 0), Eq(y, 0))), (2, And(Eq(a, 1), Eq(y, 0))), (0, True)) args = (2, And(Eq(x, 2), Ge(y ,0))), (x, True) assert Piecewise(*args).simplify() == Piecewise(*args) args = (1, Eq(x, 0)), (sin(x)/x, True) assert Piecewise(*args).simplify() == Piecewise(*args) assert Piecewise((2 + y, And(Eq(x, 2), Eq(y, 0))), (x, True) ).simplify() == x # check that x or f(x) are recognized as being Symbol-like for lhs args = Tuple((1, Eq(x, 0)), (sin(x) + 1 + x, True)) ans = x + sin(x) + 1 f = Function('f') assert Piecewise(*args).simplify() == ans assert Piecewise(*args.subs(x, f(x))).simplify() == ans.subs(x, f(x)) # issue 18634 d = Symbol("d", integer=True) n = Symbol("n", integer=True) t = Symbol("t", real=True, positive=True) expr = Piecewise((-d + 2*n, Eq(1/t, 1)), (t**(1 - 4*n)*t**(4*n - 1)*(-d + 2*n), True)) assert expr.simplify() == -d + 2*n def test_piecewise_solve(): abs2 = Piecewise((-x, x <= 0), (x, x > 0)) f = abs2.subs(x, x - 2) assert solve(f, x) == [2] assert solve(f - 1, x) == [1, 3] f = Piecewise(((x - 2)**2, x >= 0), (1, True)) assert solve(f, x) == [2] g = Piecewise(((x - 5)**5, x >= 4), (f, True)) assert solve(g, x) == [2, 5] g = Piecewise(((x - 5)**5, x >= 4), (f, x < 4)) assert solve(g, x) == [2, 5] g = Piecewise(((x - 5)**5, x >= 2), (f, x < 2)) assert solve(g, x) == [5] g = Piecewise(((x - 5)**5, x >= 2), (f, True)) assert solve(g, x) == [5] g = Piecewise(((x - 5)**5, x >= 2), (f, True), (10, False)) assert solve(g, x) == [5] g = Piecewise(((x - 5)**5, x >= 2), (-x + 2, x - 2 <= 0), (x - 2, x - 2 > 0)) assert solve(g, x) == [5] # if no symbol is given the piecewise detection must still work assert solve(Piecewise((x - 2, x > 2), (2 - x, True)) - 3) == [-1, 5] f = Piecewise(((x - 2)**2, x >= 0), (0, True)) raises(NotImplementedError, lambda: solve(f, x)) def nona(ans): return list(filter(lambda x: x is not S.NaN, ans)) p = Piecewise((x**2 - 4, x < y), (x - 2, True)) ans = solve(p, x) assert nona([i.subs(y, -2) for i in ans]) == [2] assert nona([i.subs(y, 2) for i in ans]) == [-2, 2] assert nona([i.subs(y, 3) for i in ans]) == [-2, 2] assert ans == [ Piecewise((-2, y > -2), (S.NaN, True)), Piecewise((2, y <= 2), (S.NaN, True)), Piecewise((2, y > 2), (S.NaN, True))] # issue 6060 absxm3 = Piecewise( (x - 3, 0 <= x - 3), (3 - x, 0 > x - 3) ) assert solve(absxm3 - y, x) == [ Piecewise((-y + 3, -y < 0), (S.NaN, True)), Piecewise((y + 3, y >= 0), (S.NaN, True))] p = Symbol('p', positive=True) assert solve(absxm3 - p, x) == [-p + 3, p + 3] # issue 6989 f = Function('f') assert solve(Eq(-f(x), Piecewise((1, x > 0), (0, True))), f(x)) == \ [Piecewise((-1, x > 0), (0, True))] # issue 8587 f = Piecewise((2*x**2, And(0 < x, x < 1)), (2, True)) assert solve(f - 1) == [1/sqrt(2)] def test_piecewise_fold(): p = Piecewise((x, x < 1), (1, 1 <= x)) assert piecewise_fold(x*p) == Piecewise((x**2, x < 1), (x, 1 <= x)) assert piecewise_fold(p + p) == Piecewise((2*x, x < 1), (2, 1 <= x)) assert piecewise_fold(Piecewise((1, x < 0), (2, True)) + Piecewise((10, x < 0), (-10, True))) == \ Piecewise((11, x < 0), (-8, True)) p1 = Piecewise((0, x < 0), (x, x <= 1), (0, True)) p2 = Piecewise((0, x < 0), (1 - x, x <= 1), (0, True)) p = 4*p1 + 2*p2 assert integrate( piecewise_fold(p), (x, -oo, oo)) == integrate(2*x + 2, (x, 0, 1)) assert piecewise_fold( Piecewise((1, y <= 0), (-Piecewise((2, y >= 0)), True) )) == Piecewise((1, y <= 0), (-2, y >= 0)) assert piecewise_fold(Piecewise((x, ITE(x > 0, y < 1, y > 1))) ) == Piecewise((x, ((x <= 0) | (y < 1)) & ((x > 0) | (y > 1)))) a, b = (Piecewise((2, Eq(x, 0)), (0, True)), Piecewise((x, Eq(-x + y, 0)), (1, Eq(-x + y, 1)), (0, True))) assert piecewise_fold(Mul(a, b, evaluate=False) ) == piecewise_fold(Mul(b, a, evaluate=False)) def test_piecewise_fold_piecewise_in_cond(): p1 = Piecewise((cos(x), x < 0), (0, True)) p2 = Piecewise((0, Eq(p1, 0)), (p1 / Abs(p1), True)) assert p2.subs(x, -pi/2) == 0 assert p2.subs(x, 1) == 0 assert p2.subs(x, -pi/4) == 1 p4 = Piecewise((0, Eq(p1, 0)), (1,True)) ans = piecewise_fold(p4) for i in range(-1, 1): assert ans.subs(x, i) == p4.subs(x, i) r1 = 1 < Piecewise((1, x < 1), (3, True)) ans = piecewise_fold(r1) for i in range(2): assert ans.subs(x, i) == r1.subs(x, i) p5 = Piecewise((1, x < 0), (3, True)) p6 = Piecewise((1, x < 1), (3, True)) p7 = Piecewise((1, p5 < p6), (0, True)) ans = piecewise_fold(p7) for i in range(-1, 2): assert ans.subs(x, i) == p7.subs(x, i) def test_piecewise_fold_piecewise_in_cond_2(): p1 = Piecewise((cos(x), x < 0), (0, True)) p2 = Piecewise((0, Eq(p1, 0)), (1 / p1, True)) p3 = Piecewise( (0, (x >= 0) | Eq(cos(x), 0)), (1/cos(x), x < 0), (zoo, True)) # redundant b/c all x are already covered assert(piecewise_fold(p2) == p3) def test_piecewise_fold_expand(): p1 = Piecewise((1, Interval(0, 1, False, True).contains(x)), (0, True)) p2 = piecewise_fold(expand((1 - x)*p1)) assert p2 == Piecewise((1 - x, (x >= 0) & (x < 1)), (0, True)) assert p2 == expand(piecewise_fold((1 - x)*p1)) def test_piecewise_duplicate(): p = Piecewise((x, x < -10), (x**2, x <= -1), (x, 1 < x)) assert p == Piecewise(*p.args) def test_doit(): p1 = Piecewise((x, x < 1), (x**2, -1 <= x), (x, 3 < x)) p2 = Piecewise((x, x < 1), (Integral(2 * x), -1 <= x), (x, 3 < x)) assert p2.doit() == p1 assert p2.doit(deep=False) == p2 # issue 17165 p1 = Sum(y**x, (x, -1, oo)).doit() assert p1.doit() == p1 def test_piecewise_interval(): p1 = Piecewise((x, Interval(0, 1).contains(x)), (0, True)) assert p1.subs(x, -0.5) == 0 assert p1.subs(x, 0.5) == 0.5 assert p1.diff(x) == Piecewise((1, Interval(0, 1).contains(x)), (0, True)) assert integrate(p1, x) == Piecewise( (0, x <= 0), (x**2/2, x <= 1), (S.Half, True)) def test_piecewise_collapse(): assert Piecewise((x, True)) == x a = x < 1 assert Piecewise((x, a), (x + 1, a)) == Piecewise((x, a)) assert Piecewise((x, a), (x + 1, a.reversed)) == Piecewise((x, a)) b = x < 5 def canonical(i): if isinstance(i, Piecewise): return Piecewise(*i.args) return i for args in [ ((1, a), (Piecewise((2, a), (3, b)), b)), ((1, a), (Piecewise((2, a), (3, b.reversed)), b)), ((1, a), (Piecewise((2, a), (3, b)), b), (4, True)), ((1, a), (Piecewise((2, a), (3, b), (4, True)), b)), ((1, a), (Piecewise((2, a), (3, b), (4, True)), b), (5, True))]: for i in (0, 2, 10): assert canonical( Piecewise(*args, evaluate=False).subs(x, i) ) == canonical(Piecewise(*args).subs(x, i)) r1, r2, r3, r4 = symbols('r1:5') a = x < r1 b = x < r2 c = x < r3 d = x < r4 assert Piecewise((1, a), (Piecewise( (2, a), (3, b), (4, c)), b), (5, c) ) == Piecewise((1, a), (3, b), (5, c)) assert Piecewise((1, a), (Piecewise( (2, a), (3, b), (4, c), (6, True)), c), (5, d) ) == Piecewise((1, a), (Piecewise( (3, b), (4, c)), c), (5, d)) assert Piecewise((1, Or(a, d)), (Piecewise( (2, d), (3, b), (4, c)), b), (5, c) ) == Piecewise((1, Or(a, d)), (Piecewise( (2, d), (3, b)), b), (5, c)) assert Piecewise((1, c), (2, ~c), (3, S.true) ) == Piecewise((1, c), (2, S.true)) assert Piecewise((1, c), (2, And(~c, b)), (3,True) ) == Piecewise((1, c), (2, b), (3, True)) assert Piecewise((1, c), (2, Or(~c, b)), (3,True) ).subs(dict(zip((r1, r2, r3, r4, x), (1, 2, 3, 4, 3.5)))) == 2 assert Piecewise((1, c), (2, ~c)) == Piecewise((1, c), (2, True)) def test_piecewise_lambdify(): p = Piecewise( (x**2, x < 0), (x, Interval(0, 1, False, True).contains(x)), (2 - x, x >= 1), (0, True) ) f = lambdify(x, p) assert f(-2.0) == 4.0 assert f(0.0) == 0.0 assert f(0.5) == 0.5 assert f(2.0) == 0.0 def test_piecewise_series(): from sympy import sin, cos, O p1 = Piecewise((sin(x), x < 0), (cos(x), x > 0)) p2 = Piecewise((x + O(x**2), x < 0), (1 + O(x**2), x > 0)) assert p1.nseries(x, n=2) == p2 def test_piecewise_as_leading_term(): p1 = Piecewise((1/x, x > 1), (0, True)) p2 = Piecewise((x, x > 1), (0, True)) p3 = Piecewise((1/x, x > 1), (x, True)) p4 = Piecewise((x, x > 1), (1/x, True)) p5 = Piecewise((1/x, x > 1), (x, True)) p6 = Piecewise((1/x, x < 1), (x, True)) p7 = Piecewise((x, x < 1), (1/x, True)) p8 = Piecewise((x, x > 1), (1/x, True)) assert p1.as_leading_term(x) == 0 assert p2.as_leading_term(x) == 0 assert p3.as_leading_term(x) == x assert p4.as_leading_term(x) == 1/x assert p5.as_leading_term(x) == x assert p6.as_leading_term(x) == 1/x assert p7.as_leading_term(x) == x assert p8.as_leading_term(x) == 1/x def test_piecewise_complex(): p1 = Piecewise((2, x < 0), (1, 0 <= x)) p2 = Piecewise((2*I, x < 0), (I, 0 <= x)) p3 = Piecewise((I*x, x > 1), (1 + I, True)) p4 = Piecewise((-I*conjugate(x), x > 1), (1 - I, True)) assert conjugate(p1) == p1 assert conjugate(p2) == piecewise_fold(-p2) assert conjugate(p3) == p4 assert p1.is_imaginary is False assert p1.is_real is True assert p2.is_imaginary is True assert p2.is_real is False assert p3.is_imaginary is None assert p3.is_real is None assert p1.as_real_imag() == (p1, 0) assert p2.as_real_imag() == (0, -I*p2) def test_conjugate_transpose(): A, B = symbols("A B", commutative=False) p = Piecewise((A*B**2, x > 0), (A**2*B, True)) assert p.adjoint() == \ Piecewise((adjoint(A*B**2), x > 0), (adjoint(A**2*B), True)) assert p.conjugate() == \ Piecewise((conjugate(A*B**2), x > 0), (conjugate(A**2*B), True)) assert p.transpose() == \ Piecewise((transpose(A*B**2), x > 0), (transpose(A**2*B), True)) def test_piecewise_evaluate(): assert Piecewise((x, True)) == x assert Piecewise((x, True), evaluate=True) == x p = Piecewise((x, True), evaluate=False) assert p != x assert p.is_Piecewise assert all(isinstance(i, Basic) for i in p.args) assert Piecewise((1, Eq(1, x))).args == ((1, Eq(x, 1)),) assert Piecewise((1, Eq(1, x)), evaluate=False).args == ( (1, Eq(1, x)),) def test_as_expr_set_pairs(): assert Piecewise((x, x > 0), (-x, x <= 0)).as_expr_set_pairs() == \ [(x, Interval(0, oo, True, True)), (-x, Interval(-oo, 0))] assert Piecewise(((x - 2)**2, x >= 0), (0, True)).as_expr_set_pairs() == \ [((x - 2)**2, Interval(0, oo)), (0, Interval(-oo, 0, True, True))] def test_S_srepr_is_identity(): p = Piecewise((10, Eq(x, 0)), (12, True)) q = S(srepr(p)) assert p == q def test_issue_12587(): # sort holes into intervals p = Piecewise((1, x > 4), (2, Not((x <= 3) & (x > -1))), (3, True)) assert p.integrate((x, -5, 5)) == 23 p = Piecewise((1, x > 1), (2, x < y), (3, True)) lim = x, -3, 3 ans = p.integrate(lim) for i in range(-1, 3): assert ans.subs(y, i) == p.subs(y, i).integrate(lim) def test_issue_11045(): assert integrate(1/(x*sqrt(x**2 - 1)), (x, 1, 2)) == pi/3 # handle And with Or arguments assert Piecewise((1, And(Or(x < 1, x > 3), x < 2)), (0, True) ).integrate((x, 0, 3)) == 1 # hidden false assert Piecewise((1, x > 1), (2, x > x + 1), (3, True) ).integrate((x, 0, 3)) == 5 # targetcond is Eq assert Piecewise((1, x > 1), (2, Eq(1, x)), (3, True) ).integrate((x, 0, 4)) == 6 # And has Relational needing to be solved assert Piecewise((1, And(2*x > x + 1, x < 2)), (0, True) ).integrate((x, 0, 3)) == 1 # Or has Relational needing to be solved assert Piecewise((1, Or(2*x > x + 2, x < 1)), (0, True) ).integrate((x, 0, 3)) == 2 # ignore hidden false (handled in canonicalization) assert Piecewise((1, x > 1), (2, x > x + 1), (3, True) ).integrate((x, 0, 3)) == 5 # watch for hidden True Piecewise assert Piecewise((2, Eq(1 - x, x*(1/x - 1))), (0, True) ).integrate((x, 0, 3)) == 6 # overlapping conditions of targetcond are recognized and ignored; # the condition x > 3 will be pre-empted by the first condition assert Piecewise((1, Or(x < 1, x > 2)), (2, x > 3), (3, True) ).integrate((x, 0, 4)) == 6 # convert Ne to Or assert Piecewise((1, Ne(x, 0)), (2, True) ).integrate((x, -1, 1)) == 2 # no default but well defined assert Piecewise((x, (x > 1) & (x < 3)), (1, (x < 4)) ).integrate((x, 1, 4)) == 5 p = Piecewise((x, (x > 1) & (x < 3)), (1, (x < 4))) nan = Undefined i = p.integrate((x, 1, y)) assert i == Piecewise( (y - 1, y < 1), (Min(3, y)**2/2 - Min(3, y) + Min(4, y) - S.Half, y <= Min(4, y)), (nan, True)) assert p.integrate((x, 1, -1)) == i.subs(y, -1) assert p.integrate((x, 1, 4)) == 5 assert p.integrate((x, 1, 5)) is nan # handle Not p = Piecewise((1, x > 1), (2, Not(And(x > 1, x< 3))), (3, True)) assert p.integrate((x, 0, 3)) == 4 # handle updating of int_expr when there is overlap p = Piecewise( (1, And(5 > x, x > 1)), (2, Or(x < 3, x > 7)), (4, x < 8)) assert p.integrate((x, 0, 10)) == 20 # And with Eq arg handling assert Piecewise((1, x < 1), (2, And(Eq(x, 3), x > 1)) ).integrate((x, 0, 3)) is S.NaN assert Piecewise((1, x < 1), (2, And(Eq(x, 3), x > 1)), (3, True) ).integrate((x, 0, 3)) == 7 assert Piecewise((1, x < 0), (2, And(Eq(x, 3), x < 1)), (3, True) ).integrate((x, -1, 1)) == 4 # middle condition doesn't matter: it's a zero width interval assert Piecewise((1, x < 1), (2, Eq(x, 3) & (y < x)), (3, True) ).integrate((x, 0, 3)) == 7 def test_holes(): nan = Undefined assert Piecewise((1, x < 2)).integrate(x) == Piecewise( (x, x < 2), (nan, True)) assert Piecewise((1, And(x > 1, x < 2))).integrate(x) == Piecewise( (nan, x < 1), (x - 1, x < 2), (nan, True)) assert Piecewise((1, And(x > 1, x < 2))).integrate((x, 0, 3)) is nan assert Piecewise((1, And(x > 0, x < 4))).integrate((x, 1, 3)) == 2 # this also tests that the integrate method is used on non-Piecwise # arguments in _eval_integral A, B = symbols("A B") a, b = symbols('a b', real=True) assert Piecewise((A, And(x < 0, a < 1)), (B, Or(x < 1, a > 2)) ).integrate(x) == Piecewise( (B*x, (a > 2)), (Piecewise((A*x, x < 0), (B*x, x < 1), (nan, True)), a < 1), (Piecewise((B*x, x < 1), (nan, True)), True)) def test_issue_11922(): def f(x): return Piecewise((0, x < -1), (1 - x**2, x < 1), (0, True)) autocorr = lambda k: ( f(x) * f(x + k)).integrate((x, -1, 1)) assert autocorr(1.9) > 0 k = symbols('k') good_autocorr = lambda k: ( (1 - x**2) * f(x + k)).integrate((x, -1, 1)) a = good_autocorr(k) assert a.subs(k, 3) == 0 k = symbols('k', positive=True) a = good_autocorr(k) assert a.subs(k, 3) == 0 assert Piecewise((0, x < 1), (10, (x >= 1)) ).integrate() == Piecewise((0, x < 1), (10*x - 10, True)) def test_issue_5227(): f = 0.0032513612725229*Piecewise((0, x < -80.8461538461539), (-0.0160799238820171*x + 1.33215984776403, x < 2), (Piecewise((0.3, x > 123), (0.7, True)) + Piecewise((0.4, x > 2), (0.6, True)), x <= 123), (-0.00817409766454352*x + 2.10541401273885, x < 380.571428571429), (0, True)) i = integrate(f, (x, -oo, oo)) assert i == Integral(f, (x, -oo, oo)).doit() assert str(i) == '1.00195081676351' assert Piecewise((1, x - y < 0), (0, True) ).integrate(y) == Piecewise((0, y <= x), (-x + y, True)) def test_issue_10137(): a = Symbol('a', real=True, finite=True) b = Symbol('b', real=True, finite=True) x = Symbol('x', real=True, finite=True) y = Symbol('y', real=True, finite=True) p0 = Piecewise((0, Or(x < a, x > b)), (1, True)) p1 = Piecewise((0, Or(a > x, b < x)), (1, True)) assert integrate(p0, (x, y, oo)) == integrate(p1, (x, y, oo)) p3 = Piecewise((1, And(0 < x, x < a)), (0, True)) p4 = Piecewise((1, And(a > x, x > 0)), (0, True)) ip3 = integrate(p3, x) assert ip3 == Piecewise( (0, x <= 0), (x, x <= Max(0, a)), (Max(0, a), True)) ip4 = integrate(p4, x) assert ip4 == ip3 assert p3.integrate((x, 2, 4)) == Min(4, Max(2, a)) - 2 assert p4.integrate((x, 2, 4)) == Min(4, Max(2, a)) - 2 def test_stackoverflow_43852159(): f = lambda x: Piecewise((1 , (x >= -1) & (x <= 1)) , (0, True)) Conv = lambda x: integrate(f(x - y)*f(y), (y, -oo, +oo)) cx = Conv(x) assert cx.subs(x, -1.5) == cx.subs(x, 1.5) assert cx.subs(x, 3) == 0 assert piecewise_fold(f(x - y)*f(y)) == Piecewise( (1, (y >= -1) & (y <= 1) & (x - y >= -1) & (x - y <= 1)), (0, True)) def test_issue_12557(): ''' # 3200 seconds to compute the fourier part of issue import sympy as sym x,y,z,t = sym.symbols('x y z t') k = sym.symbols("k", integer=True) fourier = sym.fourier_series(sym.cos(k*x)*sym.sqrt(x**2), (x, -sym.pi, sym.pi)) assert fourier == FourierSeries( sqrt(x**2)*cos(k*x), (x, -pi, pi), (Piecewise((pi**2, Eq(k, 0)), (2*(-1)**k/k**2 - 2/k**2, True))/(2*pi), SeqFormula(Piecewise((pi**2, (Eq(_n, 0) & Eq(k, 0)) | (Eq(_n, 0) & Eq(_n, k) & Eq(k, 0)) | (Eq(_n, 0) & Eq(k, 0) & Eq(_n, -k)) | (Eq(_n, 0) & Eq(_n, k) & Eq(k, 0) & Eq(_n, -k))), (pi**2/2, Eq(_n, k) | Eq(_n, -k) | (Eq(_n, 0) & Eq(_n, k)) | (Eq(_n, k) & Eq(k, 0)) | (Eq(_n, 0) & Eq(_n, -k)) | (Eq(_n, k) & Eq(_n, -k)) | (Eq(k, 0) & Eq(_n, -k)) | (Eq(_n, 0) & Eq(_n, k) & Eq(_n, -k)) | (Eq(_n, k) & Eq(k, 0) & Eq(_n, -k))), ((-1)**k*pi**2*_n**3*sin(pi*_n)/(pi*_n**4 - 2*pi*_n**2*k**2 + pi*k**4) - (-1)**k*pi**2*_n**3*sin(pi*_n)/(-pi*_n**4 + 2*pi*_n**2*k**2 - pi*k**4) + (-1)**k*pi*_n**2*cos(pi*_n)/(pi*_n**4 - 2*pi*_n**2*k**2 + pi*k**4) - (-1)**k*pi*_n**2*cos(pi*_n)/(-pi*_n**4 + 2*pi*_n**2*k**2 - pi*k**4) - (-1)**k*pi**2*_n*k**2*sin(pi*_n)/(pi*_n**4 - 2*pi*_n**2*k**2 + pi*k**4) + (-1)**k*pi**2*_n*k**2*sin(pi*_n)/(-pi*_n**4 + 2*pi*_n**2*k**2 - pi*k**4) + (-1)**k*pi*k**2*cos(pi*_n)/(pi*_n**4 - 2*pi*_n**2*k**2 + pi*k**4) - (-1)**k*pi*k**2*cos(pi*_n)/(-pi*_n**4 + 2*pi*_n**2*k**2 - pi*k**4) - (2*_n**2 + 2*k**2)/(_n**4 - 2*_n**2*k**2 + k**4), True))*cos(_n*x)/pi, (_n, 1, oo)), SeqFormula(0, (_k, 1, oo)))) ''' x = symbols("x", real=True) k = symbols('k', integer=True, finite=True) abs2 = lambda x: Piecewise((-x, x <= 0), (x, x > 0)) assert integrate(abs2(x), (x, -pi, pi)) == pi**2 func = cos(k*x)*sqrt(x**2) assert integrate(func, (x, -pi, pi)) == Piecewise( (2*(-1)**k/k**2 - 2/k**2, Ne(k, 0)), (pi**2, True)) def test_issue_6900(): from itertools import permutations t0, t1, T, t = symbols('t0, t1 T t') f = Piecewise((0, t < t0), (x, And(t0 <= t, t < t1)), (0, t >= t1)) g = f.integrate(t) assert g == Piecewise( (0, t <= t0), (t*x - t0*x, t <= Max(t0, t1)), (-t0*x + x*Max(t0, t1), True)) for i in permutations(range(2)): reps = dict(zip((t0,t1), i)) for tt in range(-1,3): assert (g.xreplace(reps).subs(t,tt) == f.xreplace(reps).integrate(t).subs(t,tt)) lim = Tuple(t, t0, T) g = f.integrate(lim) ans = Piecewise( (-t0*x + x*Min(T, Max(t0, t1)), T > t0), (0, True)) for i in permutations(range(3)): reps = dict(zip((t0,t1,T), i)) tru = f.xreplace(reps).integrate(lim.xreplace(reps)) assert tru == ans.xreplace(reps) assert g == ans def test_issue_10122(): assert solve(abs(x) + abs(x - 1) - 1 > 0, x ) == Or(And(-oo < x, x < S.Zero), And(S.One < x, x < oo)) def test_issue_4313(): u = Piecewise((0, x <= 0), (1, x >= a), (x/a, True)) e = (u - u.subs(x, y))**2/(x - y)**2 M = Max(0, a) assert integrate(e, x).expand() == Piecewise( (Piecewise( (0, x <= 0), (-y**2/(a**2*x - a**2*y) + x/a**2 - 2*y*log(-y)/a**2 + 2*y*log(x - y)/a**2 - y/a**2, x <= M), (-y**2/(-a**2*y + a**2*M) + 1/(-y + M) - 1/(x - y) - 2*y*log(-y)/a**2 + 2*y*log(-y + M)/a**2 - y/a**2 + M/a**2, True)), ((a <= y) & (y <= 0)) | ((y <= 0) & (y > -oo))), (Piecewise( (-1/(x - y), x <= 0), (-a**2/(a**2*x - a**2*y) + 2*a*y/(a**2*x - a**2*y) - y**2/(a**2*x - a**2*y) + 2*log(-y)/a - 2*log(x - y)/a + 2/a + x/a**2 - 2*y*log(-y)/a**2 + 2*y*log(x - y)/a**2 - y/a**2, x <= M), (-a**2/(-a**2*y + a**2*M) + 2*a*y/(-a**2*y + a**2*M) - y**2/(-a**2*y + a**2*M) + 2*log(-y)/a - 2*log(-y + M)/a + 2/a - 2*y*log(-y)/a**2 + 2*y*log(-y + M)/a**2 - y/a**2 + M/a**2, True)), a <= y), (Piecewise( (-y**2/(a**2*x - a**2*y), x <= 0), (x/a**2 + y/a**2, x <= M), (a**2/(-a**2*y + a**2*M) - a**2/(a**2*x - a**2*y) - 2*a*y/(-a**2*y + a**2*M) + 2*a*y/(a**2*x - a**2*y) + y**2/(-a**2*y + a**2*M) - y**2/(a**2*x - a**2*y) + y/a**2 + M/a**2, True)), True)) def test__intervals(): assert Piecewise((x + 2, Eq(x, 3)))._intervals(x) == [] assert Piecewise( (1, x > x + 1), (Piecewise((1, x < x + 1)), 2*x < 2*x + 1), (1, True))._intervals(x) == [(-oo, oo, 1, 1)] assert Piecewise((1, Ne(x, I)), (0, True))._intervals(x) == [ (-oo, oo, 1, 0)] assert Piecewise((-cos(x), sin(x) >= 0), (cos(x), True) )._intervals(x) == [(0, pi, -cos(x), 0), (-oo, oo, cos(x), 1)] # the following tests that duplicates are removed and that non-Eq # generated zero-width intervals are removed assert Piecewise((1, Abs(x**(-2)) > 1), (0, True) )._intervals(x) == [(-1, 0, 1, 0), (0, 1, 1, 0), (-oo, oo, 0, 1)] def test_containment(): a, b, c, d, e = [1, 2, 3, 4, 5] p = (Piecewise((d, x > 1), (e, True))* Piecewise((a, Abs(x - 1) < 1), (b, Abs(x - 2) < 2), (c, True))) assert p.integrate(x).diff(x) == Piecewise( (c*e, x <= 0), (a*e, x <= 1), (a*d, x < 2), # this is what we want to get right (b*d, x < 4), (c*d, True)) def test_piecewise_with_DiracDelta(): d1 = DiracDelta(x - 1) assert integrate(d1, (x, -oo, oo)) == 1 assert integrate(d1, (x, 0, 2)) == 1 assert Piecewise((d1, Eq(x, 2)), (0, True)).integrate(x) == 0 assert Piecewise((d1, x < 2), (0, True)).integrate(x) == Piecewise( (Heaviside(x - 1), x < 2), (1, True)) # TODO raise error if function is discontinuous at limit of # integration, e.g. integrate(d1, (x, -2, 1)) or Piecewise( # (d1, Eq(x ,1) def test_issue_10258(): assert Piecewise((0, x < 1), (1, True)).is_zero is None assert Piecewise((-1, x < 1), (1, True)).is_zero is False a = Symbol('a', zero=True) assert Piecewise((0, x < 1), (a, True)).is_zero assert Piecewise((1, x < 1), (a, x < 3)).is_zero is None a = Symbol('a') assert Piecewise((0, x < 1), (a, True)).is_zero is None assert Piecewise((0, x < 1), (1, True)).is_nonzero is None assert Piecewise((1, x < 1), (2, True)).is_nonzero assert Piecewise((0, x < 1), (oo, True)).is_finite is None assert Piecewise((0, x < 1), (1, True)).is_finite b = Basic() assert Piecewise((b, x < 1)).is_finite is None # 10258 c = Piecewise((1, x < 0), (2, True)) < 3 assert c != True assert piecewise_fold(c) == True def test_issue_10087(): a, b = Piecewise((x, x > 1), (2, True)), Piecewise((x, x > 3), (3, True)) m = a*b f = piecewise_fold(m) for i in (0, 2, 4): assert m.subs(x, i) == f.subs(x, i) m = a + b f = piecewise_fold(m) for i in (0, 2, 4): assert m.subs(x, i) == f.subs(x, i) def test_issue_8919(): c = symbols('c:5') x = symbols("x") f1 = Piecewise((c[1], x < 1), (c[2], True)) f2 = Piecewise((c[3], x < Rational(1, 3)), (c[4], True)) assert integrate(f1*f2, (x, 0, 2) ) == c[1]*c[3]/3 + 2*c[1]*c[4]/3 + c[2]*c[4] f1 = Piecewise((0, x < 1), (2, True)) f2 = Piecewise((3, x < 2), (0, True)) assert integrate(f1*f2, (x, 0, 3)) == 6 y = symbols("y", positive=True) a, b, c, x, z = symbols("a,b,c,x,z", real=True) I = Integral(Piecewise( (0, (x >= y) | (x < 0) | (b > c)), (a, True)), (x, 0, z)) ans = I.doit() assert ans == Piecewise((0, b > c), (a*Min(y, z) - a*Min(0, z), True)) for cond in (True, False): for yy in range(1, 3): for zz in range(-yy, 0, yy): reps = [(b > c, cond), (y, yy), (z, zz)] assert ans.subs(reps) == I.subs(reps).doit() def test_unevaluated_integrals(): f = Function('f') p = Piecewise((1, Eq(f(x) - 1, 0)), (2, x - 10 < 0), (0, True)) assert p.integrate(x) == Integral(p, x) assert p.integrate((x, 0, 5)) == Integral(p, (x, 0, 5)) # test it by replacing f(x) with x%2 which will not # affect the answer: the integrand is essentially 2 over # the domain of integration assert Integral(p, (x, 0, 5)).subs(f(x), x%2).n() == 10 # this is a test of using _solve_inequality when # solve_univariate_inequality fails assert p.integrate(y) == Piecewise( (y, Eq(f(x), 1) | ((x < 10) & Eq(f(x), 1))), (2*y, (x >= -oo) & (x < 10)), (0, True)) def test_conditions_as_alternate_booleans(): a, b, c = symbols('a:c') assert Piecewise((x, Piecewise((y < 1, x > 0), (y > 1, True))) ) == Piecewise((x, ITE(x > 0, y < 1, y > 1))) def test_Piecewise_rewrite_as_ITE(): a, b, c, d = symbols('a:d') def _ITE(*args): return Piecewise(*args).rewrite(ITE) assert _ITE((a, x < 1), (b, x >= 1)) == ITE(x < 1, a, b) assert _ITE((a, x < 1), (b, x < oo)) == ITE(x < 1, a, b) assert _ITE((a, x < 1), (b, Or(y < 1, x < oo)), (c, y > 0) ) == ITE(x < 1, a, b) assert _ITE((a, x < 1), (b, True)) == ITE(x < 1, a, b) assert _ITE((a, x < 1), (b, x < 2), (c, True) ) == ITE(x < 1, a, ITE(x < 2, b, c)) assert _ITE((a, x < 1), (b, y < 2), (c, True) ) == ITE(x < 1, a, ITE(y < 2, b, c)) assert _ITE((a, x < 1), (b, x < oo), (c, y < 1) ) == ITE(x < 1, a, b) assert _ITE((a, x < 1), (c, y < 1), (b, x < oo), (d, True) ) == ITE(x < 1, a, ITE(y < 1, c, b)) assert _ITE((a, x < 0), (b, Or(x < oo, y < 1)) ) == ITE(x < 0, a, b) raises(TypeError, lambda: _ITE((x + 1, x < 1), (x, True))) # if `a` in the following were replaced with y then the coverage # is complete but something other than as_set would need to be # used to detect this raises(NotImplementedError, lambda: _ITE((x, x < y), (y, x >= a))) raises(ValueError, lambda: _ITE((a, x < 2), (b, x > 3))) def test_issue_14052(): assert integrate(abs(sin(x)), (x, 0, 2*pi)) == 4 def test_issue_14240(): assert piecewise_fold( Piecewise((1, a), (2, b), (4, True)) + Piecewise((8, a), (16, True)) ) == Piecewise((9, a), (18, b), (20, True)) assert piecewise_fold( Piecewise((2, a), (3, b), (5, True)) * Piecewise((7, a), (11, True)) ) == Piecewise((14, a), (33, b), (55, True)) # these will hang if naive folding is used assert piecewise_fold(Add(*[ Piecewise((i, a), (0, True)) for i in range(40)]) ) == Piecewise((780, a), (0, True)) assert piecewise_fold(Mul(*[ Piecewise((i, a), (0, True)) for i in range(1, 41)]) ) == Piecewise((factorial(40), a), (0, True)) def test_issue_14787(): x = Symbol('x') f = Piecewise((x, x < 1), ((S(58) / 7), True)) assert str(f.evalf()) == "Piecewise((x, x < 1), (8.28571428571429, True))" def test_issue_8458(): x, y = symbols('x y') # Original issue p1 = Piecewise((0, Eq(x, 0)), (sin(x), True)) assert p1.simplify() == sin(x) # Slightly larger variant p2 = Piecewise((x, Eq(x, 0)), (4*x + (y-2)**4, Eq(x, 0) & Eq(x+y, 2)), (sin(x), True)) assert p2.simplify() == sin(x) # Test for problem highlighted during review p3 = Piecewise((x+1, Eq(x, -1)), (4*x + (y-2)**4, Eq(x, 0) & Eq(x+y, 2)), (sin(x), True)) assert p3.simplify() == Piecewise((0, Eq(x, -1)), (sin(x), True)) def test_issue_16417(): from sympy import im, re, Gt z = Symbol('z') assert unchanged(Piecewise, (1, Or(Eq(im(z), 0), Gt(re(z), 0))), (2, True)) x = Symbol('x') assert unchanged(Piecewise, (S.Pi, re(x) < 0), (0, Or(re(x) > 0, Ne(im(x), 0))), (S.NaN, True)) r = Symbol('r', real=True) p = Piecewise((S.Pi, re(r) < 0), (0, Or(re(r) > 0, Ne(im(r), 0))), (S.NaN, True)) assert p == Piecewise((S.Pi, r < 0), (0, r > 0), (S.NaN, True), evaluate=False) # Does not work since imaginary != 0... #i = Symbol('i', imaginary=True) #p = Piecewise((S.Pi, re(i) < 0), # (0, Or(re(i) > 0, Ne(im(i), 0))), # (S.NaN, True)) #assert p == Piecewise((0, Ne(im(i), 0)), # (S.NaN, True), evaluate=False) i = I*r p = Piecewise((S.Pi, re(i) < 0), (0, Or(re(i) > 0, Ne(im(i), 0))), (S.NaN, True)) assert p == Piecewise((0, Ne(im(i), 0)), (S.NaN, True), evaluate=False) assert p == Piecewise((0, Ne(r, 0)), (S.NaN, True), evaluate=False) def test_eval_rewrite_as_KroneckerDelta(): x, y, z, n, t, m = symbols('x y z n t m') K = KroneckerDelta f = lambda p: expand(p.rewrite(K)) p1 = Piecewise((0, Eq(x, y)), (1, True)) assert f(p1) == 1 - K(x, y) p2 = Piecewise((x, Eq(y,0)), (z, Eq(t,0)), (n, True)) assert f(p2) == n*K(0, t)*K(0, y) - n*K(0, t) - n*K(0, y) + n + \ x*K(0, y) - z*K(0, t)*K(0, y) + z*K(0, t) p3 = Piecewise((1, Ne(x, y)), (0, True)) assert f(p3) == 1 - K(x, y) p4 = Piecewise((1, Eq(x, 3)), (4, True), (5, True)) assert f(p4) == 4 - 3*K(3, x) p5 = Piecewise((3, Ne(x, 2)), (4, Eq(y, 2)), (5, True)) assert f(p5) == -K(2, x)*K(2, y) + 2*K(2, x) + 3 p6 = Piecewise((0, Ne(x, 1) & Ne(y, 4)), (1, True)) assert f(p6) == -K(1, x)*K(4, y) + K(1, x) + K(4, y) p7 = Piecewise((2, Eq(y, 3) & Ne(x, 2)), (1, True)) assert f(p7) == -K(2, x)*K(3, y) + K(3, y) + 1 p8 = Piecewise((4, Eq(x, 3) & Ne(y, 2)), (1, True)) assert f(p8) == -3*K(2, y)*K(3, x) + 3*K(3, x) + 1 p9 = Piecewise((6, Eq(x, 4) & Eq(y, 1)), (1, True)) assert f(p9) == 5 * K(1, y) * K(4, x) + 1 p10 = Piecewise((4, Ne(x, -4) | Ne(y, 1)), (1, True)) assert f(p10) == -3 * K(-4, x) * K(1, y) + 4 p11 = Piecewise((1, Eq(y, 2) | Ne(x, -3)), (2, True)) assert f(p11) == -K(-3, x)*K(2, y) + K(-3, x) + 1 p12 = Piecewise((-1, Eq(x, 1) | Ne(y, 3)), (1, True)) assert f(p12) == -2*K(1, x)*K(3, y) + 2*K(3, y) - 1 p13 = Piecewise((3, Eq(x, 2) | Eq(y, 4)), (1, True)) assert f(p13) == -2*K(2, x)*K(4, y) + 2*K(2, x) + 2*K(4, y) + 1 p14 = Piecewise((1, Ne(x, 0) | Ne(y, 1)), (3, True)) assert f(p14) == 2 * K(0, x) * K(1, y) + 1 p15 = Piecewise((2, Eq(x, 3) | Ne(y, 2)), (3, Eq(x, 4) & Eq(y, 5)), (1, True)) assert f(p15) == -2*K(2, y)*K(3, x)*K(4, x)*K(5, y) + K(2, y)*K(3, x) + \ 2*K(2, y)*K(4, x)*K(5, y) - K(2, y) + 2 p16 = Piecewise((0, Ne(m, n)), (1, True))*Piecewise((0, Ne(n, t)), (1, True))\ *Piecewise((0, Ne(n, x)), (1, True)) - Piecewise((0, Ne(t, x)), (1, True)) assert f(p16) == K(m, n)*K(n, t)*K(n, x) - K(t, x) p17 = Piecewise((0, Ne(t, x) & (Ne(m, n) | Ne(n, t) | Ne(n, x))), (1, Ne(t, x)), (-1, Ne(m, n) | Ne(n, t) | Ne(n, x)), (0, True)) assert f(p17) == K(m, n)*K(n, t)*K(n, x) - K(t, x) p18 = Piecewise((-4, Eq(y, 1) | (Eq(x, -5) & Eq(x, z))), (4, True)) assert f(p18) == 8*K(-5, x)*K(1, y)*K(x, z) - 8*K(-5, x)*K(x, z) - 8*K(1, y) + 4 p19 = Piecewise((0, x > 2), (1, True)) assert f(p19) == p19 p20 = Piecewise((0, And(x < 2, x > -5)), (1, True)) assert f(p20) == p20 p21 = Piecewise((0, Or(x > 1, x < 0)), (1, True)) assert f(p21) == p21 p22 = Piecewise((0, ~((Eq(y, -1) | Ne(x, 0)) & (Ne(x, 1) | Ne(y, -1)))), (1, True)) assert f(p22) == K(-1, y)*K(0, x) - K(-1, y)*K(1, x) - K(0, x) + 1 @slow def test_identical_conds_issue(): from sympy.stats import Uniform, density u1 = Uniform('u1', 0, 1) u2 = Uniform('u2', 0, 1) # Result is quite big, so not really important here (and should ideally be # simpler). Should not give an exception though. density(u1 + u2) def test_issue_7370(): f = Piecewise((1, x <= 2400)) v = integrate(f, (x, 0, Float("252.4", 30))) assert str(v) == '252.400000000000000000000000000' def test_issue_16715(): raises(NotImplementedError, lambda: Piecewise((x, x<0), (0, y>1)).as_expr_set_pairs()) def test_issue_20360(): t, tau = symbols("t tau", real=True) n = symbols("n", integer=True) lam = pi * (n - S.Half) eq = integrate(exp(lam * tau), (tau, 0, t)) assert simplify(eq) == (2*exp(pi*t*(2*n - 1)/2) - 2)/(pi*(2*n - 1)) sympy-sympy-1.9/sympy/functions/elementary/tests/test_trigonometric.py000066400000000000000000002410201412543434000267200ustar00rootroot00000000000000from sympy import (symbols, Symbol, nan, oo, zoo, I, sinh, sin, pi, atan, acos, Rational, sqrt, asin, acot, coth, E, S, tan, tanh, cos, cosh, atan2, exp, log, asinh, acoth, atanh, O, cancel, Matrix, re, im, Float, Pow, gcd, sec, csc, cot, diff, simplify, Heaviside, arg, conjugate, series, FiniteSet, asec, acsc, Mul, sinc, jn, AccumBounds, Interval, ImageSet, Lambda, besselj, Add, limit) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.core.relational import Ne, Eq from sympy.functions.elementary.piecewise import Piecewise from sympy.sets.setexpr import SetExpr from sympy.testing.pytest import XFAIL, slow, raises x, y, z = symbols('x y z') r = Symbol('r', real=True) k, m = symbols('k m', integer=True) p = Symbol('p', positive=True) n = Symbol('n', negative=True) np = Symbol('p', nonpositive=True) nn = Symbol('n', nonnegative=True) nz = Symbol('nz', nonzero=True) ep = Symbol('ep', extended_positive=True) en = Symbol('en', extended_negative=True) enp = Symbol('ep', extended_nonpositive=True) enn = Symbol('en', extended_nonnegative=True) enz = Symbol('enz', extended_nonzero=True) a = Symbol('a', algebraic=True) na = Symbol('na', nonzero=True, algebraic=True) def test_sin(): x, y = symbols('x y') assert sin.nargs == FiniteSet(1) assert sin(nan) is nan assert sin(zoo) is nan assert sin(oo) == AccumBounds(-1, 1) assert sin(oo) - sin(oo) == AccumBounds(-2, 2) assert sin(oo*I) == oo*I assert sin(-oo*I) == -oo*I assert 0*sin(oo) is S.Zero assert 0/sin(oo) is S.Zero assert 0 + sin(oo) == AccumBounds(-1, 1) assert 5 + sin(oo) == AccumBounds(4, 6) assert sin(0) == 0 assert sin(asin(x)) == x assert sin(atan(x)) == x / sqrt(1 + x**2) assert sin(acos(x)) == sqrt(1 - x**2) assert sin(acot(x)) == 1 / (sqrt(1 + 1 / x**2) * x) assert sin(acsc(x)) == 1 / x assert sin(asec(x)) == sqrt(1 - 1 / x**2) assert sin(atan2(y, x)) == y / sqrt(x**2 + y**2) assert sin(pi*I) == sinh(pi)*I assert sin(-pi*I) == -sinh(pi)*I assert sin(-2*I) == -sinh(2)*I assert sin(pi) == 0 assert sin(-pi) == 0 assert sin(2*pi) == 0 assert sin(-2*pi) == 0 assert sin(-3*10**73*pi) == 0 assert sin(7*10**103*pi) == 0 assert sin(pi/2) == 1 assert sin(-pi/2) == -1 assert sin(pi*Rational(5, 2)) == 1 assert sin(pi*Rational(7, 2)) == -1 ne = symbols('ne', integer=True, even=False) e = symbols('e', even=True) assert sin(pi*ne/2) == (-1)**(ne/2 - S.Half) assert sin(pi*k/2).func == sin assert sin(pi*e/2) == 0 assert sin(pi*k) == 0 assert sin(pi*k).subs(k, 3) == sin(pi*k/2).subs(k, 6) # issue 8298 assert sin(pi/3) == S.Half*sqrt(3) assert sin(pi*Rational(-2, 3)) == Rational(-1, 2)*sqrt(3) assert sin(pi/4) == S.Half*sqrt(2) assert sin(-pi/4) == Rational(-1, 2)*sqrt(2) assert sin(pi*Rational(17, 4)) == S.Half*sqrt(2) assert sin(pi*Rational(-3, 4)) == Rational(-1, 2)*sqrt(2) assert sin(pi/6) == S.Half assert sin(-pi/6) == Rational(-1, 2) assert sin(pi*Rational(7, 6)) == Rational(-1, 2) assert sin(pi*Rational(-5, 6)) == Rational(-1, 2) assert sin(pi*Rational(1, 5)) == sqrt((5 - sqrt(5)) / 8) assert sin(pi*Rational(2, 5)) == sqrt((5 + sqrt(5)) / 8) assert sin(pi*Rational(3, 5)) == sin(pi*Rational(2, 5)) assert sin(pi*Rational(4, 5)) == sin(pi*Rational(1, 5)) assert sin(pi*Rational(6, 5)) == -sin(pi*Rational(1, 5)) assert sin(pi*Rational(8, 5)) == -sin(pi*Rational(2, 5)) assert sin(pi*Rational(-1273, 5)) == -sin(pi*Rational(2, 5)) assert sin(pi/8) == sqrt((2 - sqrt(2))/4) assert sin(pi/10) == Rational(-1, 4) + sqrt(5)/4 assert sin(pi/12) == -sqrt(2)/4 + sqrt(6)/4 assert sin(pi*Rational(5, 12)) == sqrt(2)/4 + sqrt(6)/4 assert sin(pi*Rational(-7, 12)) == -sqrt(2)/4 - sqrt(6)/4 assert sin(pi*Rational(-11, 12)) == sqrt(2)/4 - sqrt(6)/4 assert sin(pi*Rational(104, 105)) == sin(pi/105) assert sin(pi*Rational(106, 105)) == -sin(pi/105) assert sin(pi*Rational(-104, 105)) == -sin(pi/105) assert sin(pi*Rational(-106, 105)) == sin(pi/105) assert sin(x*I) == sinh(x)*I assert sin(k*pi) == 0 assert sin(17*k*pi) == 0 assert sin(2*k*pi + 4) == sin(4) assert sin(2*k*pi + m*pi + 1) == (-1)**(m + 2*k)*sin(1) assert sin(k*pi*I) == sinh(k*pi)*I assert sin(r).is_real is True assert sin(0, evaluate=False).is_algebraic assert sin(a).is_algebraic is None assert sin(na).is_algebraic is False q = Symbol('q', rational=True) assert sin(pi*q).is_algebraic qn = Symbol('qn', rational=True, nonzero=True) assert sin(qn).is_rational is False assert sin(q).is_rational is None # issue 8653 assert isinstance(sin( re(x) - im(y)), sin) is True assert isinstance(sin(-re(x) + im(y)), sin) is False assert sin(SetExpr(Interval(0, 1))) == SetExpr(ImageSet(Lambda(x, sin(x)), Interval(0, 1))) for d in list(range(1, 22)) + [60, 85]: for n in range(0, d*2 + 1): x = n*pi/d e = abs( float(sin(x)) - sin(float(x)) ) assert e < 1e-12 assert sin(0, evaluate=False).is_zero is True assert sin(k*pi, evaluate=False).is_zero is None assert sin(Add(1, -1, evaluate=False), evaluate=False).is_zero is True def test_sin_cos(): for d in [1, 2, 3, 4, 5, 6, 10, 12, 15, 20, 24, 30, 40, 60, 120]: # list is not exhaustive... for n in range(-2*d, d*2): x = n*pi/d assert sin(x + pi/2) == cos(x), "fails for %d*pi/%d" % (n, d) assert sin(x - pi/2) == -cos(x), "fails for %d*pi/%d" % (n, d) assert sin(x) == cos(x - pi/2), "fails for %d*pi/%d" % (n, d) assert -sin(x) == cos(x + pi/2), "fails for %d*pi/%d" % (n, d) def test_sin_series(): assert sin(x).series(x, 0, 9) == \ x - x**3/6 + x**5/120 - x**7/5040 + O(x**9) def test_sin_rewrite(): assert sin(x).rewrite(exp) == -I*(exp(I*x) - exp(-I*x))/2 assert sin(x).rewrite(tan) == 2*tan(x/2)/(1 + tan(x/2)**2) assert sin(x).rewrite(cot) == 2*cot(x/2)/(1 + cot(x/2)**2) assert sin(sinh(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, sinh(3)).n() assert sin(cosh(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cosh(3)).n() assert sin(tanh(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, tanh(3)).n() assert sin(coth(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, coth(3)).n() assert sin(sin(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, sin(3)).n() assert sin(cos(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cos(3)).n() assert sin(tan(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, tan(3)).n() assert sin(cot(x)).rewrite( exp).subs(x, 3).n() == sin(x).rewrite(exp).subs(x, cot(3)).n() assert sin(log(x)).rewrite(Pow) == I*x**-I / 2 - I*x**I /2 assert sin(x).rewrite(csc) == 1/csc(x) assert sin(x).rewrite(cos) == cos(x - pi / 2, evaluate=False) assert sin(x).rewrite(sec) == 1 / sec(x - pi / 2, evaluate=False) assert sin(cos(x)).rewrite(Pow) == sin(cos(x)) def _test_extrig(f, i, e): from sympy.core.expr import unchanged from sympy.core.function import expand_trig assert unchanged(f, i) assert expand_trig(f(i)) == f(i) # testing directly instead of with .expand(trig=True) # because the other expansions undo the unevaluated Mul assert expand_trig(f(Mul(i, 1, evaluate=False))) == e assert abs(f(i) - e).n() < 1e-10 def test_sin_expansion(): # Note: these formulas are not unique. The ones here come from the # Chebyshev formulas. assert sin(x + y).expand(trig=True) == sin(x)*cos(y) + cos(x)*sin(y) assert sin(x - y).expand(trig=True) == sin(x)*cos(y) - cos(x)*sin(y) assert sin(y - x).expand(trig=True) == cos(x)*sin(y) - sin(x)*cos(y) assert sin(2*x).expand(trig=True) == 2*sin(x)*cos(x) assert sin(3*x).expand(trig=True) == -4*sin(x)**3 + 3*sin(x) assert sin(4*x).expand(trig=True) == -8*sin(x)**3*cos(x) + 4*sin(x)*cos(x) _test_extrig(sin, 2, 2*sin(1)*cos(1)) _test_extrig(sin, 3, -4*sin(1)**3 + 3*sin(1)) def test_sin_AccumBounds(): assert sin(AccumBounds(-oo, oo)) == AccumBounds(-1, 1) assert sin(AccumBounds(0, oo)) == AccumBounds(-1, 1) assert sin(AccumBounds(-oo, 0)) == AccumBounds(-1, 1) assert sin(AccumBounds(0, 2*S.Pi)) == AccumBounds(-1, 1) assert sin(AccumBounds(0, S.Pi*Rational(3, 4))) == AccumBounds(0, 1) assert sin(AccumBounds(S.Pi*Rational(3, 4), S.Pi*Rational(7, 4))) == AccumBounds(-1, sin(S.Pi*Rational(3, 4))) assert sin(AccumBounds(S.Pi/4, S.Pi/3)) == AccumBounds(sin(S.Pi/4), sin(S.Pi/3)) assert sin(AccumBounds(S.Pi*Rational(3, 4), S.Pi*Rational(5, 6))) == AccumBounds(sin(S.Pi*Rational(5, 6)), sin(S.Pi*Rational(3, 4))) def test_sin_fdiff(): assert sin(x).fdiff() == cos(x) raises(ArgumentIndexError, lambda: sin(x).fdiff(2)) def test_trig_symmetry(): assert sin(-x) == -sin(x) assert cos(-x) == cos(x) assert tan(-x) == -tan(x) assert cot(-x) == -cot(x) assert sin(x + pi) == -sin(x) assert sin(x + 2*pi) == sin(x) assert sin(x + 3*pi) == -sin(x) assert sin(x + 4*pi) == sin(x) assert sin(x - 5*pi) == -sin(x) assert cos(x + pi) == -cos(x) assert cos(x + 2*pi) == cos(x) assert cos(x + 3*pi) == -cos(x) assert cos(x + 4*pi) == cos(x) assert cos(x - 5*pi) == -cos(x) assert tan(x + pi) == tan(x) assert tan(x - 3*pi) == tan(x) assert cot(x + pi) == cot(x) assert cot(x - 3*pi) == cot(x) assert sin(pi/2 - x) == cos(x) assert sin(pi*Rational(3, 2) - x) == -cos(x) assert sin(pi*Rational(5, 2) - x) == cos(x) assert cos(pi/2 - x) == sin(x) assert cos(pi*Rational(3, 2) - x) == -sin(x) assert cos(pi*Rational(5, 2) - x) == sin(x) assert tan(pi/2 - x) == cot(x) assert tan(pi*Rational(3, 2) - x) == cot(x) assert tan(pi*Rational(5, 2) - x) == cot(x) assert cot(pi/2 - x) == tan(x) assert cot(pi*Rational(3, 2) - x) == tan(x) assert cot(pi*Rational(5, 2) - x) == tan(x) assert sin(pi/2 + x) == cos(x) assert cos(pi/2 + x) == -sin(x) assert tan(pi/2 + x) == -cot(x) assert cot(pi/2 + x) == -tan(x) def test_cos(): x, y = symbols('x y') assert cos.nargs == FiniteSet(1) assert cos(nan) is nan assert cos(oo) == AccumBounds(-1, 1) assert cos(oo) - cos(oo) == AccumBounds(-2, 2) assert cos(oo*I) is oo assert cos(-oo*I) is oo assert cos(zoo) is nan assert cos(0) == 1 assert cos(acos(x)) == x assert cos(atan(x)) == 1 / sqrt(1 + x**2) assert cos(asin(x)) == sqrt(1 - x**2) assert cos(acot(x)) == 1 / sqrt(1 + 1 / x**2) assert cos(acsc(x)) == sqrt(1 - 1 / x**2) assert cos(asec(x)) == 1 / x assert cos(atan2(y, x)) == x / sqrt(x**2 + y**2) assert cos(pi*I) == cosh(pi) assert cos(-pi*I) == cosh(pi) assert cos(-2*I) == cosh(2) assert cos(pi/2) == 0 assert cos(-pi/2) == 0 assert cos(pi/2) == 0 assert cos(-pi/2) == 0 assert cos((-3*10**73 + 1)*pi/2) == 0 assert cos((7*10**103 + 1)*pi/2) == 0 n = symbols('n', integer=True, even=False) e = symbols('e', even=True) assert cos(pi*n/2) == 0 assert cos(pi*e/2) == (-1)**(e/2) assert cos(pi) == -1 assert cos(-pi) == -1 assert cos(2*pi) == 1 assert cos(5*pi) == -1 assert cos(8*pi) == 1 assert cos(pi/3) == S.Half assert cos(pi*Rational(-2, 3)) == Rational(-1, 2) assert cos(pi/4) == S.Half*sqrt(2) assert cos(-pi/4) == S.Half*sqrt(2) assert cos(pi*Rational(11, 4)) == Rational(-1, 2)*sqrt(2) assert cos(pi*Rational(-3, 4)) == Rational(-1, 2)*sqrt(2) assert cos(pi/6) == S.Half*sqrt(3) assert cos(-pi/6) == S.Half*sqrt(3) assert cos(pi*Rational(7, 6)) == Rational(-1, 2)*sqrt(3) assert cos(pi*Rational(-5, 6)) == Rational(-1, 2)*sqrt(3) assert cos(pi*Rational(1, 5)) == (sqrt(5) + 1)/4 assert cos(pi*Rational(2, 5)) == (sqrt(5) - 1)/4 assert cos(pi*Rational(3, 5)) == -cos(pi*Rational(2, 5)) assert cos(pi*Rational(4, 5)) == -cos(pi*Rational(1, 5)) assert cos(pi*Rational(6, 5)) == -cos(pi*Rational(1, 5)) assert cos(pi*Rational(8, 5)) == cos(pi*Rational(2, 5)) assert cos(pi*Rational(-1273, 5)) == -cos(pi*Rational(2, 5)) assert cos(pi/8) == sqrt((2 + sqrt(2))/4) assert cos(pi/12) == sqrt(2)/4 + sqrt(6)/4 assert cos(pi*Rational(5, 12)) == -sqrt(2)/4 + sqrt(6)/4 assert cos(pi*Rational(7, 12)) == sqrt(2)/4 - sqrt(6)/4 assert cos(pi*Rational(11, 12)) == -sqrt(2)/4 - sqrt(6)/4 assert cos(pi*Rational(104, 105)) == -cos(pi/105) assert cos(pi*Rational(106, 105)) == -cos(pi/105) assert cos(pi*Rational(-104, 105)) == -cos(pi/105) assert cos(pi*Rational(-106, 105)) == -cos(pi/105) assert cos(x*I) == cosh(x) assert cos(k*pi*I) == cosh(k*pi) assert cos(r).is_real is True assert cos(0, evaluate=False).is_algebraic assert cos(a).is_algebraic is None assert cos(na).is_algebraic is False q = Symbol('q', rational=True) assert cos(pi*q).is_algebraic assert cos(pi*Rational(2, 7)).is_algebraic assert cos(k*pi) == (-1)**k assert cos(2*k*pi) == 1 for d in list(range(1, 22)) + [60, 85]: for n in range(0, 2*d + 1): x = n*pi/d e = abs( float(cos(x)) - cos(float(x)) ) assert e < 1e-12 def test_issue_6190(): c = Float('123456789012345678901234567890.25', '') for cls in [sin, cos, tan, cot]: assert cls(c*pi) == cls(pi/4) assert cls(4.125*pi) == cls(pi/8) assert cls(4.7*pi) == cls((4.7 % 2)*pi) def test_cos_series(): assert cos(x).series(x, 0, 9) == \ 1 - x**2/2 + x**4/24 - x**6/720 + x**8/40320 + O(x**9) def test_cos_rewrite(): assert cos(x).rewrite(exp) == exp(I*x)/2 + exp(-I*x)/2 assert cos(x).rewrite(tan) == (1 - tan(x/2)**2)/(1 + tan(x/2)**2) assert cos(x).rewrite(cot) == -(1 - cot(x/2)**2)/(1 + cot(x/2)**2) assert cos(sinh(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, sinh(3)).n() assert cos(cosh(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cosh(3)).n() assert cos(tanh(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, tanh(3)).n() assert cos(coth(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, coth(3)).n() assert cos(sin(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, sin(3)).n() assert cos(cos(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cos(3)).n() assert cos(tan(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, tan(3)).n() assert cos(cot(x)).rewrite( exp).subs(x, 3).n() == cos(x).rewrite(exp).subs(x, cot(3)).n() assert cos(log(x)).rewrite(Pow) == x**I/2 + x**-I/2 assert cos(x).rewrite(sec) == 1/sec(x) assert cos(x).rewrite(sin) == sin(x + pi/2, evaluate=False) assert cos(x).rewrite(csc) == 1/csc(-x + pi/2, evaluate=False) assert cos(sin(x)).rewrite(Pow) == cos(sin(x)) def test_cos_expansion(): assert cos(x + y).expand(trig=True) == cos(x)*cos(y) - sin(x)*sin(y) assert cos(x - y).expand(trig=True) == cos(x)*cos(y) + sin(x)*sin(y) assert cos(y - x).expand(trig=True) == cos(x)*cos(y) + sin(x)*sin(y) assert cos(2*x).expand(trig=True) == 2*cos(x)**2 - 1 assert cos(3*x).expand(trig=True) == 4*cos(x)**3 - 3*cos(x) assert cos(4*x).expand(trig=True) == 8*cos(x)**4 - 8*cos(x)**2 + 1 _test_extrig(cos, 2, 2*cos(1)**2 - 1) _test_extrig(cos, 3, 4*cos(1)**3 - 3*cos(1)) def test_cos_AccumBounds(): assert cos(AccumBounds(-oo, oo)) == AccumBounds(-1, 1) assert cos(AccumBounds(0, oo)) == AccumBounds(-1, 1) assert cos(AccumBounds(-oo, 0)) == AccumBounds(-1, 1) assert cos(AccumBounds(0, 2*S.Pi)) == AccumBounds(-1, 1) assert cos(AccumBounds(-S.Pi/3, S.Pi/4)) == AccumBounds(cos(-S.Pi/3), 1) assert cos(AccumBounds(S.Pi*Rational(3, 4), S.Pi*Rational(5, 4))) == AccumBounds(-1, cos(S.Pi*Rational(3, 4))) assert cos(AccumBounds(S.Pi*Rational(5, 4), S.Pi*Rational(4, 3))) == AccumBounds(cos(S.Pi*Rational(5, 4)), cos(S.Pi*Rational(4, 3))) assert cos(AccumBounds(S.Pi/4, S.Pi/3)) == AccumBounds(cos(S.Pi/3), cos(S.Pi/4)) def test_cos_fdiff(): assert cos(x).fdiff() == -sin(x) raises(ArgumentIndexError, lambda: cos(x).fdiff(2)) def test_tan(): assert tan(nan) is nan assert tan(zoo) is nan assert tan(oo) == AccumBounds(-oo, oo) assert tan(oo) - tan(oo) == AccumBounds(-oo, oo) assert tan.nargs == FiniteSet(1) assert tan(oo*I) == I assert tan(-oo*I) == -I assert tan(0) == 0 assert tan(atan(x)) == x assert tan(asin(x)) == x / sqrt(1 - x**2) assert tan(acos(x)) == sqrt(1 - x**2) / x assert tan(acot(x)) == 1 / x assert tan(acsc(x)) == 1 / (sqrt(1 - 1 / x**2) * x) assert tan(asec(x)) == sqrt(1 - 1 / x**2) * x assert tan(atan2(y, x)) == y/x assert tan(pi*I) == tanh(pi)*I assert tan(-pi*I) == -tanh(pi)*I assert tan(-2*I) == -tanh(2)*I assert tan(pi) == 0 assert tan(-pi) == 0 assert tan(2*pi) == 0 assert tan(-2*pi) == 0 assert tan(-3*10**73*pi) == 0 assert tan(pi/2) is zoo assert tan(pi*Rational(3, 2)) is zoo assert tan(pi/3) == sqrt(3) assert tan(pi*Rational(-2, 3)) == sqrt(3) assert tan(pi/4) is S.One assert tan(-pi/4) is S.NegativeOne assert tan(pi*Rational(17, 4)) is S.One assert tan(pi*Rational(-3, 4)) is S.One assert tan(pi/5) == sqrt(5 - 2*sqrt(5)) assert tan(pi*Rational(2, 5)) == sqrt(5 + 2*sqrt(5)) assert tan(pi*Rational(18, 5)) == -sqrt(5 + 2*sqrt(5)) assert tan(pi*Rational(-16, 5)) == -sqrt(5 - 2*sqrt(5)) assert tan(pi/6) == 1/sqrt(3) assert tan(-pi/6) == -1/sqrt(3) assert tan(pi*Rational(7, 6)) == 1/sqrt(3) assert tan(pi*Rational(-5, 6)) == 1/sqrt(3) assert tan(pi/8) == -1 + sqrt(2) assert tan(pi*Rational(3, 8)) == 1 + sqrt(2) # issue 15959 assert tan(pi*Rational(5, 8)) == -1 - sqrt(2) assert tan(pi*Rational(7, 8)) == 1 - sqrt(2) assert tan(pi/10) == sqrt(1 - 2*sqrt(5)/5) assert tan(pi*Rational(3, 10)) == sqrt(1 + 2*sqrt(5)/5) assert tan(pi*Rational(17, 10)) == -sqrt(1 + 2*sqrt(5)/5) assert tan(pi*Rational(-31, 10)) == -sqrt(1 - 2*sqrt(5)/5) assert tan(pi/12) == -sqrt(3) + 2 assert tan(pi*Rational(5, 12)) == sqrt(3) + 2 assert tan(pi*Rational(7, 12)) == -sqrt(3) - 2 assert tan(pi*Rational(11, 12)) == sqrt(3) - 2 assert tan(pi/24).radsimp() == -2 - sqrt(3) + sqrt(2) + sqrt(6) assert tan(pi*Rational(5, 24)).radsimp() == -2 + sqrt(3) - sqrt(2) + sqrt(6) assert tan(pi*Rational(7, 24)).radsimp() == 2 - sqrt(3) - sqrt(2) + sqrt(6) assert tan(pi*Rational(11, 24)).radsimp() == 2 + sqrt(3) + sqrt(2) + sqrt(6) assert tan(pi*Rational(13, 24)).radsimp() == -2 - sqrt(3) - sqrt(2) - sqrt(6) assert tan(pi*Rational(17, 24)).radsimp() == -2 + sqrt(3) + sqrt(2) - sqrt(6) assert tan(pi*Rational(19, 24)).radsimp() == 2 - sqrt(3) + sqrt(2) - sqrt(6) assert tan(pi*Rational(23, 24)).radsimp() == 2 + sqrt(3) - sqrt(2) - sqrt(6) assert tan(x*I) == tanh(x)*I assert tan(k*pi) == 0 assert tan(17*k*pi) == 0 assert tan(k*pi*I) == tanh(k*pi)*I assert tan(r).is_real is None assert tan(r).is_extended_real is True assert tan(0, evaluate=False).is_algebraic assert tan(a).is_algebraic is None assert tan(na).is_algebraic is False assert tan(pi*Rational(10, 7)) == tan(pi*Rational(3, 7)) assert tan(pi*Rational(11, 7)) == -tan(pi*Rational(3, 7)) assert tan(pi*Rational(-11, 7)) == tan(pi*Rational(3, 7)) assert tan(pi*Rational(15, 14)) == tan(pi/14) assert tan(pi*Rational(-15, 14)) == -tan(pi/14) assert tan(r).is_finite is None assert tan(I*r).is_finite is True # https://github.com/sympy/sympy/issues/21177 f = tan(pi*(x + S(3)/2))/(3*x) assert f.as_leading_term(x) == -1/(3*pi*x**2) def test_tan_series(): assert tan(x).series(x, 0, 9) == \ x + x**3/3 + 2*x**5/15 + 17*x**7/315 + O(x**9) def test_tan_rewrite(): neg_exp, pos_exp = exp(-x*I), exp(x*I) assert tan(x).rewrite(exp) == I*(neg_exp - pos_exp)/(neg_exp + pos_exp) assert tan(x).rewrite(sin) == 2*sin(x)**2/sin(2*x) assert tan(x).rewrite(cos) == cos(x - S.Pi/2, evaluate=False)/cos(x) assert tan(x).rewrite(cot) == 1/cot(x) assert tan(sinh(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, sinh(3)).n() assert tan(cosh(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cosh(3)).n() assert tan(tanh(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, tanh(3)).n() assert tan(coth(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, coth(3)).n() assert tan(sin(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, sin(3)).n() assert tan(cos(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cos(3)).n() assert tan(tan(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, tan(3)).n() assert tan(cot(x)).rewrite( exp).subs(x, 3).n() == tan(x).rewrite(exp).subs(x, cot(3)).n() assert tan(log(x)).rewrite(Pow) == I*(x**-I - x**I)/(x**-I + x**I) assert 0 == (cos(pi/34)*tan(pi/34) - sin(pi/34)).rewrite(pow) assert 0 == (cos(pi/17)*tan(pi/17) - sin(pi/17)).rewrite(pow) assert tan(pi/19).rewrite(pow) == tan(pi/19) assert tan(pi*Rational(8, 19)).rewrite(sqrt) == tan(pi*Rational(8, 19)) assert tan(x).rewrite(sec) == sec(x)/sec(x - pi/2, evaluate=False) assert tan(x).rewrite(csc) == csc(-x + pi/2, evaluate=False)/csc(x) assert tan(sin(x)).rewrite(Pow) == tan(sin(x)) assert tan(pi*Rational(2, 5), evaluate=False).rewrite(sqrt) == sqrt(sqrt(5)/8 + Rational(5, 8))/(Rational(-1, 4) + sqrt(5)/4) def test_tan_subs(): assert tan(x).subs(tan(x), y) == y assert tan(x).subs(x, y) == tan(y) assert tan(x).subs(x, S.Pi/2) is zoo assert tan(x).subs(x, S.Pi*Rational(3, 2)) is zoo def test_tan_expansion(): assert tan(x + y).expand(trig=True) == ((tan(x) + tan(y))/(1 - tan(x)*tan(y))).expand() assert tan(x - y).expand(trig=True) == ((tan(x) - tan(y))/(1 + tan(x)*tan(y))).expand() assert tan(x + y + z).expand(trig=True) == ( (tan(x) + tan(y) + tan(z) - tan(x)*tan(y)*tan(z))/ (1 - tan(x)*tan(y) - tan(x)*tan(z) - tan(y)*tan(z))).expand() assert 0 == tan(2*x).expand(trig=True).rewrite(tan).subs([(tan(x), Rational(1, 7))])*24 - 7 assert 0 == tan(3*x).expand(trig=True).rewrite(tan).subs([(tan(x), Rational(1, 5))])*55 - 37 assert 0 == tan(4*x - pi/4).expand(trig=True).rewrite(tan).subs([(tan(x), Rational(1, 5))])*239 - 1 _test_extrig(tan, 2, 2*tan(1)/(1 - tan(1)**2)) _test_extrig(tan, 3, (-tan(1)**3 + 3*tan(1))/(1 - 3*tan(1)**2)) def test_tan_AccumBounds(): assert tan(AccumBounds(-oo, oo)) == AccumBounds(-oo, oo) assert tan(AccumBounds(S.Pi/3, S.Pi*Rational(2, 3))) == AccumBounds(-oo, oo) assert tan(AccumBounds(S.Pi/6, S.Pi/3)) == AccumBounds(tan(S.Pi/6), tan(S.Pi/3)) def test_tan_fdiff(): assert tan(x).fdiff() == tan(x)**2 + 1 raises(ArgumentIndexError, lambda: tan(x).fdiff(2)) def test_cot(): assert cot(nan) is nan assert cot.nargs == FiniteSet(1) assert cot(oo*I) == -I assert cot(-oo*I) == I assert cot(zoo) is nan assert cot(0) is zoo assert cot(2*pi) is zoo assert cot(acot(x)) == x assert cot(atan(x)) == 1 / x assert cot(asin(x)) == sqrt(1 - x**2) / x assert cot(acos(x)) == x / sqrt(1 - x**2) assert cot(acsc(x)) == sqrt(1 - 1 / x**2) * x assert cot(asec(x)) == 1 / (sqrt(1 - 1 / x**2) * x) assert cot(atan2(y, x)) == x/y assert cot(pi*I) == -coth(pi)*I assert cot(-pi*I) == coth(pi)*I assert cot(-2*I) == coth(2)*I assert cot(pi) == cot(2*pi) == cot(3*pi) assert cot(-pi) == cot(-2*pi) == cot(-3*pi) assert cot(pi/2) == 0 assert cot(-pi/2) == 0 assert cot(pi*Rational(5, 2)) == 0 assert cot(pi*Rational(7, 2)) == 0 assert cot(pi/3) == 1/sqrt(3) assert cot(pi*Rational(-2, 3)) == 1/sqrt(3) assert cot(pi/4) is S.One assert cot(-pi/4) is S.NegativeOne assert cot(pi*Rational(17, 4)) is S.One assert cot(pi*Rational(-3, 4)) is S.One assert cot(pi/6) == sqrt(3) assert cot(-pi/6) == -sqrt(3) assert cot(pi*Rational(7, 6)) == sqrt(3) assert cot(pi*Rational(-5, 6)) == sqrt(3) assert cot(pi/8) == 1 + sqrt(2) assert cot(pi*Rational(3, 8)) == -1 + sqrt(2) assert cot(pi*Rational(5, 8)) == 1 - sqrt(2) assert cot(pi*Rational(7, 8)) == -1 - sqrt(2) assert cot(pi/12) == sqrt(3) + 2 assert cot(pi*Rational(5, 12)) == -sqrt(3) + 2 assert cot(pi*Rational(7, 12)) == sqrt(3) - 2 assert cot(pi*Rational(11, 12)) == -sqrt(3) - 2 assert cot(pi/24).radsimp() == sqrt(2) + sqrt(3) + 2 + sqrt(6) assert cot(pi*Rational(5, 24)).radsimp() == -sqrt(2) - sqrt(3) + 2 + sqrt(6) assert cot(pi*Rational(7, 24)).radsimp() == -sqrt(2) + sqrt(3) - 2 + sqrt(6) assert cot(pi*Rational(11, 24)).radsimp() == sqrt(2) - sqrt(3) - 2 + sqrt(6) assert cot(pi*Rational(13, 24)).radsimp() == -sqrt(2) + sqrt(3) + 2 - sqrt(6) assert cot(pi*Rational(17, 24)).radsimp() == sqrt(2) - sqrt(3) + 2 - sqrt(6) assert cot(pi*Rational(19, 24)).radsimp() == sqrt(2) + sqrt(3) - 2 - sqrt(6) assert cot(pi*Rational(23, 24)).radsimp() == -sqrt(2) - sqrt(3) - 2 - sqrt(6) assert cot(x*I) == -coth(x)*I assert cot(k*pi*I) == -coth(k*pi)*I assert cot(r).is_real is None assert cot(r).is_extended_real is True assert cot(a).is_algebraic is None assert cot(na).is_algebraic is False assert cot(pi*Rational(10, 7)) == cot(pi*Rational(3, 7)) assert cot(pi*Rational(11, 7)) == -cot(pi*Rational(3, 7)) assert cot(pi*Rational(-11, 7)) == cot(pi*Rational(3, 7)) assert cot(pi*Rational(39, 34)) == cot(pi*Rational(5, 34)) assert cot(pi*Rational(-41, 34)) == -cot(pi*Rational(7, 34)) assert cot(x).is_finite is None assert cot(r).is_finite is None i = Symbol('i', imaginary=True) assert cot(i).is_finite is True assert cot(x).subs(x, 3*pi) is zoo # https://github.com/sympy/sympy/issues/21177 f = cot(pi*(x + 4))/(3*x) assert f.as_leading_term(x) == 1/(3*pi*x**2) def test_tan_cot_sin_cos_evalf(): assert abs((tan(pi*Rational(8, 15))*cos(pi*Rational(8, 15))/sin(pi*Rational(8, 15)) - 1).evalf()) < 1e-14 assert abs((cot(pi*Rational(4, 15))*sin(pi*Rational(4, 15))/cos(pi*Rational(4, 15)) - 1).evalf()) < 1e-14 @XFAIL def test_tan_cot_sin_cos_ratsimp(): assert 1 == (tan(pi*Rational(8, 15))*cos(pi*Rational(8, 15))/sin(pi*Rational(8, 15))).ratsimp() assert 1 == (cot(pi*Rational(4, 15))*sin(pi*Rational(4, 15))/cos(pi*Rational(4, 15))).ratsimp() def test_cot_series(): assert cot(x).series(x, 0, 9) == \ 1/x - x/3 - x**3/45 - 2*x**5/945 - x**7/4725 + O(x**9) # issue 6210 assert cot(x**4 + x**5).series(x, 0, 1) == \ x**(-4) - 1/x**3 + x**(-2) - 1/x + 1 + O(x) assert cot(pi*(1-x)).series(x, 0, 3) == -1/(pi*x) + pi*x/3 + O(x**3) assert cot(x).taylor_term(0, x) == 1/x assert cot(x).taylor_term(2, x) is S.Zero assert cot(x).taylor_term(3, x) == -x**3/45 def test_cot_rewrite(): neg_exp, pos_exp = exp(-x*I), exp(x*I) assert cot(x).rewrite(exp) == I*(pos_exp + neg_exp)/(pos_exp - neg_exp) assert cot(x).rewrite(sin) == sin(2*x)/(2*(sin(x)**2)) assert cot(x).rewrite(cos) == cos(x)/cos(x - pi/2, evaluate=False) assert cot(x).rewrite(tan) == 1/tan(x) assert cot(sinh(x)).rewrite( exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, sinh(3)).n() assert cot(cosh(x)).rewrite( exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, cosh(3)).n() assert cot(tanh(x)).rewrite( exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, tanh(3)).n() assert cot(coth(x)).rewrite( exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, coth(3)).n() assert cot(sin(x)).rewrite( exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, sin(3)).n() assert cot(tan(x)).rewrite( exp).subs(x, 3).n() == cot(x).rewrite(exp).subs(x, tan(3)).n() assert cot(log(x)).rewrite(Pow) == -I*(x**-I + x**I)/(x**-I - x**I) assert cot(pi*Rational(4, 34)).rewrite(pow).ratsimp() == (cos(pi*Rational(4, 34))/sin(pi*Rational(4, 34))).rewrite(pow).ratsimp() assert cot(pi*Rational(4, 17)).rewrite(pow) == (cos(pi*Rational(4, 17))/sin(pi*Rational(4, 17))).rewrite(pow) assert cot(pi/19).rewrite(pow) == cot(pi/19) assert cot(pi/19).rewrite(sqrt) == cot(pi/19) assert cot(x).rewrite(sec) == sec(x - pi / 2, evaluate=False) / sec(x) assert cot(x).rewrite(csc) == csc(x) / csc(- x + pi / 2, evaluate=False) assert cot(sin(x)).rewrite(Pow) == cot(sin(x)) assert cot(pi*Rational(2, 5), evaluate=False).rewrite(sqrt) == (Rational(-1, 4) + sqrt(5)/4)/\ sqrt(sqrt(5)/8 + Rational(5, 8)) def test_cot_subs(): assert cot(x).subs(cot(x), y) == y assert cot(x).subs(x, y) == cot(y) assert cot(x).subs(x, 0) is zoo assert cot(x).subs(x, S.Pi) is zoo def test_cot_expansion(): assert cot(x + y).expand(trig=True).together() == ( (cot(x)*cot(y) - 1)/(cot(x) + cot(y))) assert cot(x - y).expand(trig=True).together() == ( cot(x)*cot(-y) - 1)/(cot(x) + cot(-y)) assert cot(x + y + z).expand(trig=True).together() == ( (cot(x)*cot(y)*cot(z) - cot(x) - cot(y) - cot(z))/ (-1 + cot(x)*cot(y) + cot(x)*cot(z) + cot(y)*cot(z))) assert cot(3*x).expand(trig=True).together() == ( (cot(x)**2 - 3)*cot(x)/(3*cot(x)**2 - 1)) assert cot(2*x).expand(trig=True) == cot(x)/2 - 1/(2*cot(x)) assert cot(3*x).expand(trig=True).together() == ( cot(x)**2 - 3)*cot(x)/(3*cot(x)**2 - 1) assert cot(4*x - pi/4).expand(trig=True).cancel() == ( -tan(x)**4 + 4*tan(x)**3 + 6*tan(x)**2 - 4*tan(x) - 1 )/(tan(x)**4 + 4*tan(x)**3 - 6*tan(x)**2 - 4*tan(x) + 1) _test_extrig(cot, 2, (-1 + cot(1)**2)/(2*cot(1))) _test_extrig(cot, 3, (-3*cot(1) + cot(1)**3)/(-1 + 3*cot(1)**2)) def test_cot_AccumBounds(): assert cot(AccumBounds(-oo, oo)) == AccumBounds(-oo, oo) assert cot(AccumBounds(-S.Pi/3, S.Pi/3)) == AccumBounds(-oo, oo) assert cot(AccumBounds(S.Pi/6, S.Pi/3)) == AccumBounds(cot(S.Pi/3), cot(S.Pi/6)) def test_cot_fdiff(): assert cot(x).fdiff() == -cot(x)**2 - 1 raises(ArgumentIndexError, lambda: cot(x).fdiff(2)) def test_sinc(): assert isinstance(sinc(x), sinc) s = Symbol('s', zero=True) assert sinc(s) is S.One assert sinc(S.Infinity) is S.Zero assert sinc(S.NegativeInfinity) is S.Zero assert sinc(S.NaN) is S.NaN assert sinc(S.ComplexInfinity) is S.NaN n = Symbol('n', integer=True, nonzero=True) assert sinc(n*pi) is S.Zero assert sinc(-n*pi) is S.Zero assert sinc(pi/2) == 2 / pi assert sinc(-pi/2) == 2 / pi assert sinc(pi*Rational(5, 2)) == 2 / (5*pi) assert sinc(pi*Rational(7, 2)) == -2 / (7*pi) assert sinc(-x) == sinc(x) assert sinc(x).diff(x) == cos(x)/x - sin(x)/x**2 assert sinc(x).diff(x) == (sin(x)/x).diff(x) assert sinc(x).diff(x, x) == (-sin(x) - 2*cos(x)/x + 2*sin(x)/x**2)/x assert sinc(x).diff(x, x) == (sin(x)/x).diff(x, x) assert limit(sinc(x).diff(x), x, 0) == 0 assert limit(sinc(x).diff(x, x), x, 0) == -S(1)/3 # https://github.com/sympy/sympy/issues/11402 # # assert sinc(x).diff(x) == Piecewise(((x*cos(x) - sin(x)) / x**2, Ne(x, 0)), (0, True)) # # assert sinc(x).diff(x).equals(sinc(x).rewrite(sin).diff(x)) # # assert sinc(x).diff(x).subs(x, 0) is S.Zero assert sinc(x).series() == 1 - x**2/6 + x**4/120 + O(x**6) assert sinc(x).rewrite(jn) == jn(0, x) assert sinc(x).rewrite(sin) == Piecewise((sin(x)/x, Ne(x, 0)), (1, True)) def test_asin(): assert asin(nan) is nan assert asin.nargs == FiniteSet(1) assert asin(oo) == -I*oo assert asin(-oo) == I*oo assert asin(zoo) is zoo # Note: asin(-x) = - asin(x) assert asin(0) == 0 assert asin(1) == pi/2 assert asin(-1) == -pi/2 assert asin(sqrt(3)/2) == pi/3 assert asin(-sqrt(3)/2) == -pi/3 assert asin(sqrt(2)/2) == pi/4 assert asin(-sqrt(2)/2) == -pi/4 assert asin(sqrt((5 - sqrt(5))/8)) == pi/5 assert asin(-sqrt((5 - sqrt(5))/8)) == -pi/5 assert asin(S.Half) == pi/6 assert asin(Rational(-1, 2)) == -pi/6 assert asin((sqrt(2 - sqrt(2)))/2) == pi/8 assert asin(-(sqrt(2 - sqrt(2)))/2) == -pi/8 assert asin((sqrt(5) - 1)/4) == pi/10 assert asin(-(sqrt(5) - 1)/4) == -pi/10 assert asin((sqrt(3) - 1)/sqrt(2**3)) == pi/12 assert asin(-(sqrt(3) - 1)/sqrt(2**3)) == -pi/12 # check round-trip for exact values: for d in [5, 6, 8, 10, 12]: for n in range(-(d//2), d//2 + 1): if gcd(n, d) == 1: assert asin(sin(n*pi/d)) == n*pi/d assert asin(x).diff(x) == 1/sqrt(1 - x**2) assert asin(1/x).as_leading_term(x) == I*log(1/x) assert asin(0.2).is_real is True assert asin(-2).is_real is False assert asin(r).is_real is None assert asin(-2*I) == -I*asinh(2) assert asin(Rational(1, 7), evaluate=False).is_positive is True assert asin(Rational(-1, 7), evaluate=False).is_positive is False assert asin(p).is_positive is None assert asin(sin(Rational(7, 2))) == Rational(-7, 2) + pi assert asin(sin(Rational(-7, 4))) == Rational(7, 4) - pi assert unchanged(asin, cos(x)) def test_asin_series(): assert asin(x).series(x, 0, 9) == \ x + x**3/6 + 3*x**5/40 + 5*x**7/112 + O(x**9) t5 = asin(x).taylor_term(5, x) assert t5 == 3*x**5/40 assert asin(x).taylor_term(7, x, t5, 0) == 5*x**7/112 def test_asin_rewrite(): assert asin(x).rewrite(log) == -I*log(I*x + sqrt(1 - x**2)) assert asin(x).rewrite(atan) == 2*atan(x/(1 + sqrt(1 - x**2))) assert asin(x).rewrite(acos) == S.Pi/2 - acos(x) assert asin(x).rewrite(acot) == 2*acot((sqrt(-x**2 + 1) + 1)/x) assert asin(x).rewrite(asec) == -asec(1/x) + pi/2 assert asin(x).rewrite(acsc) == acsc(1/x) def test_asin_fdiff(): assert asin(x).fdiff() == 1/sqrt(1 - x**2) raises(ArgumentIndexError, lambda: asin(x).fdiff(2)) def test_acos(): assert acos(nan) is nan assert acos(zoo) is zoo assert acos.nargs == FiniteSet(1) assert acos(oo) == I*oo assert acos(-oo) == -I*oo # Note: acos(-x) = pi - acos(x) assert acos(0) == pi/2 assert acos(S.Half) == pi/3 assert acos(Rational(-1, 2)) == pi*Rational(2, 3) assert acos(1) == 0 assert acos(-1) == pi assert acos(sqrt(2)/2) == pi/4 assert acos(-sqrt(2)/2) == pi*Rational(3, 4) # check round-trip for exact values: for d in [5, 6, 8, 10, 12]: for num in range(d): if gcd(num, d) == 1: assert acos(cos(num*pi/d)) == num*pi/d assert acos(2*I) == pi/2 - asin(2*I) assert acos(x).diff(x) == -1/sqrt(1 - x**2) assert acos(1/x).as_leading_term(x) == I*log(1/x) assert acos(0.2).is_real is True assert acos(-2).is_real is False assert acos(r).is_real is None assert acos(Rational(1, 7), evaluate=False).is_positive is True assert acos(Rational(-1, 7), evaluate=False).is_positive is True assert acos(Rational(3, 2), evaluate=False).is_positive is False assert acos(p).is_positive is None assert acos(2 + p).conjugate() != acos(10 + p) assert acos(-3 + n).conjugate() != acos(-3 + n) assert acos(Rational(1, 3)).conjugate() == acos(Rational(1, 3)) assert acos(Rational(-1, 3)).conjugate() == acos(Rational(-1, 3)) assert acos(p + n*I).conjugate() == acos(p - n*I) assert acos(z).conjugate() != acos(conjugate(z)) def test_acos_series(): assert acos(x).series(x, 0, 8) == \ pi/2 - x - x**3/6 - 3*x**5/40 - 5*x**7/112 + O(x**8) assert acos(x).series(x, 0, 8) == pi/2 - asin(x).series(x, 0, 8) t5 = acos(x).taylor_term(5, x) assert t5 == -3*x**5/40 assert acos(x).taylor_term(7, x, t5, 0) == -5*x**7/112 assert acos(x).taylor_term(0, x) == pi/2 assert acos(x).taylor_term(2, x) is S.Zero def test_acos_rewrite(): assert acos(x).rewrite(log) == pi/2 + I*log(I*x + sqrt(1 - x**2)) assert acos(x).rewrite(atan) == \ atan(sqrt(1 - x**2)/x) + (pi/2)*(1 - x*sqrt(1/x**2)) assert acos(0).rewrite(atan) == S.Pi/2 assert acos(0.5).rewrite(atan) == acos(0.5).rewrite(log) assert acos(x).rewrite(asin) == S.Pi/2 - asin(x) assert acos(x).rewrite(acot) == -2*acot((sqrt(-x**2 + 1) + 1)/x) + pi/2 assert acos(x).rewrite(asec) == asec(1/x) assert acos(x).rewrite(acsc) == -acsc(1/x) + pi/2 def test_acos_fdiff(): assert acos(x).fdiff() == -1/sqrt(1 - x**2) raises(ArgumentIndexError, lambda: acos(x).fdiff(2)) def test_atan(): assert atan(nan) is nan assert atan.nargs == FiniteSet(1) assert atan(oo) == pi/2 assert atan(-oo) == -pi/2 assert atan(zoo) == AccumBounds(-pi/2, pi/2) assert atan(0) == 0 assert atan(1) == pi/4 assert atan(sqrt(3)) == pi/3 assert atan(-(1 + sqrt(2))) == pi*Rational(-3, 8) assert atan(sqrt(5 - 2 * sqrt(5))) == pi/5 assert atan(-sqrt(1 - 2 * sqrt(5)/ 5)) == -pi/10 assert atan(sqrt(1 + 2 * sqrt(5) / 5)) == pi*Rational(3, 10) assert atan(-2 + sqrt(3)) == -pi/12 assert atan(2 + sqrt(3)) == pi*Rational(5, 12) assert atan(-2 - sqrt(3)) == pi*Rational(-5, 12) # check round-trip for exact values: for d in [5, 6, 8, 10, 12]: for num in range(-(d//2), d//2 + 1): if gcd(num, d) == 1: assert atan(tan(num*pi/d)) == num*pi/d assert atan(oo) == pi/2 assert atan(x).diff(x) == 1/(1 + x**2) assert atan(1/x).as_leading_term(x) == pi/2 assert atan(r).is_real is True assert atan(-2*I) == -I*atanh(2) assert unchanged(atan, cot(x)) assert atan(cot(Rational(1, 4))) == Rational(-1, 4) + pi/2 assert acot(Rational(1, 4)).is_rational is False for s in (x, p, n, np, nn, nz, ep, en, enp, enn, enz): if s.is_real or s.is_extended_real is None: assert s.is_nonzero is atan(s).is_nonzero assert s.is_positive is atan(s).is_positive assert s.is_negative is atan(s).is_negative assert s.is_nonpositive is atan(s).is_nonpositive assert s.is_nonnegative is atan(s).is_nonnegative else: assert s.is_extended_nonzero is atan(s).is_nonzero assert s.is_extended_positive is atan(s).is_positive assert s.is_extended_negative is atan(s).is_negative assert s.is_extended_nonpositive is atan(s).is_nonpositive assert s.is_extended_nonnegative is atan(s).is_nonnegative assert s.is_extended_nonzero is atan(s).is_extended_nonzero assert s.is_extended_positive is atan(s).is_extended_positive assert s.is_extended_negative is atan(s).is_extended_negative assert s.is_extended_nonpositive is atan(s).is_extended_nonpositive assert s.is_extended_nonnegative is atan(s).is_extended_nonnegative def test_atan_rewrite(): assert atan(x).rewrite(log) == I*(log(1 - I*x)-log(1 + I*x))/2 assert atan(x).rewrite(asin) == (-asin(1/sqrt(x**2 + 1)) + pi/2)*sqrt(x**2)/x assert atan(x).rewrite(acos) == sqrt(x**2)*acos(1/sqrt(x**2 + 1))/x assert atan(x).rewrite(acot) == acot(1/x) assert atan(x).rewrite(asec) == sqrt(x**2)*asec(sqrt(x**2 + 1))/x assert atan(x).rewrite(acsc) == (-acsc(sqrt(x**2 + 1)) + pi/2)*sqrt(x**2)/x assert atan(-5*I).evalf() == atan(x).rewrite(log).evalf(subs={x:-5*I}) assert atan(5*I).evalf() == atan(x).rewrite(log).evalf(subs={x:5*I}) def test_atan_fdiff(): assert atan(x).fdiff() == 1/(x**2 + 1) raises(ArgumentIndexError, lambda: atan(x).fdiff(2)) def test_atan2(): assert atan2.nargs == FiniteSet(2) assert atan2(0, 0) is S.NaN assert atan2(0, 1) == 0 assert atan2(1, 1) == pi/4 assert atan2(1, 0) == pi/2 assert atan2(1, -1) == pi*Rational(3, 4) assert atan2(0, -1) == pi assert atan2(-1, -1) == pi*Rational(-3, 4) assert atan2(-1, 0) == -pi/2 assert atan2(-1, 1) == -pi/4 i = symbols('i', imaginary=True) r = symbols('r', real=True) eq = atan2(r, i) ans = -I*log((i + I*r)/sqrt(i**2 + r**2)) reps = ((r, 2), (i, I)) assert eq.subs(reps) == ans.subs(reps) x = Symbol('x', negative=True) y = Symbol('y', negative=True) assert atan2(y, x) == atan(y/x) - pi y = Symbol('y', nonnegative=True) assert atan2(y, x) == atan(y/x) + pi y = Symbol('y') assert atan2(y, x) == atan2(y, x, evaluate=False) u = Symbol("u", positive=True) assert atan2(0, u) == 0 u = Symbol("u", negative=True) assert atan2(0, u) == pi assert atan2(y, oo) == 0 assert atan2(y, -oo)== 2*pi*Heaviside(re(y), S.Half) - pi assert atan2(y, x).rewrite(log) == -I*log((x + I*y)/sqrt(x**2 + y**2)) assert atan2(0, 0) is S.NaN ex = atan2(y, x) - arg(x + I*y) assert ex.subs({x:2, y:3}).rewrite(arg) == 0 assert ex.subs({x:2, y:3*I}).rewrite(arg) == -pi - I*log(sqrt(5)*I/5) assert ex.subs({x:2*I, y:3}).rewrite(arg) == -pi/2 - I*log(sqrt(5)*I) assert ex.subs({x:2*I, y:3*I}).rewrite(arg) == -pi + atan(Rational(2, 3)) + atan(Rational(3, 2)) i = symbols('i', imaginary=True) r = symbols('r', real=True) e = atan2(i, r) rewrite = e.rewrite(arg) reps = {i: I, r: -2} assert rewrite == -I*log(abs(I*i + r)/sqrt(abs(i**2 + r**2))) + arg((I*i + r)/sqrt(i**2 + r**2)) assert (e - rewrite).subs(reps).equals(0) assert atan2(0, x).rewrite(atan) == Piecewise((pi, re(x) < 0), (0, Ne(x, 0)), (nan, True)) assert atan2(0, r).rewrite(atan) == Piecewise((pi, r < 0), (0, Ne(r, 0)), (S.NaN, True)) assert atan2(0, i),rewrite(atan) == 0 assert atan2(0, r + i).rewrite(atan) == Piecewise((pi, r < 0), (0, True)) assert atan2(y, x).rewrite(atan) == Piecewise( (2*atan(y/(x + sqrt(x**2 + y**2))), Ne(y, 0)), (pi, re(x) < 0), (0, (re(x) > 0) | Ne(im(x), 0)), (nan, True)) assert conjugate(atan2(x, y)) == atan2(conjugate(x), conjugate(y)) assert diff(atan2(y, x), x) == -y/(x**2 + y**2) assert diff(atan2(y, x), y) == x/(x**2 + y**2) assert simplify(diff(atan2(y, x).rewrite(log), x)) == -y/(x**2 + y**2) assert simplify(diff(atan2(y, x).rewrite(log), y)) == x/(x**2 + y**2) assert str(atan2(1, 2).evalf(5)) == '0.46365' raises(ArgumentIndexError, lambda: atan2(x, y).fdiff(3)) def test_issue_17461(): class A(Symbol): is_extended_real = True def _eval_evalf(self, prec): return Float(5.0) x = A('X') y = A('Y') assert abs(atan2(x, y).evalf() - 0.785398163397448) <= 1e-10 def test_acot(): assert acot(nan) is nan assert acot.nargs == FiniteSet(1) assert acot(-oo) == 0 assert acot(oo) == 0 assert acot(zoo) == 0 assert acot(1) == pi/4 assert acot(0) == pi/2 assert acot(sqrt(3)/3) == pi/3 assert acot(1/sqrt(3)) == pi/3 assert acot(-1/sqrt(3)) == -pi/3 assert acot(x).diff(x) == -1/(1 + x**2) assert acot(1/x).as_leading_term(x) == x assert acot(r).is_extended_real is True assert acot(I*pi) == -I*acoth(pi) assert acot(-2*I) == I*acoth(2) assert acot(x).is_positive is None assert acot(n).is_positive is False assert acot(p).is_positive is True assert acot(I).is_positive is False assert acot(Rational(1, 4)).is_rational is False assert unchanged(acot, cot(x)) assert unchanged(acot, tan(x)) assert acot(cot(Rational(1, 4))) == Rational(1, 4) assert acot(tan(Rational(-1, 4))) == Rational(1, 4) - pi/2 def test_acot_rewrite(): assert acot(x).rewrite(log) == I*(log(1 - I/x)-log(1 + I/x))/2 assert acot(x).rewrite(asin) == x*(-asin(sqrt(-x**2)/sqrt(-x**2 - 1)) + pi/2)*sqrt(x**(-2)) assert acot(x).rewrite(acos) == x*sqrt(x**(-2))*acos(sqrt(-x**2)/sqrt(-x**2 - 1)) assert acot(x).rewrite(atan) == atan(1/x) assert acot(x).rewrite(asec) == x*sqrt(x**(-2))*asec(sqrt((x**2 + 1)/x**2)) assert acot(x).rewrite(acsc) == x*(-acsc(sqrt((x**2 + 1)/x**2)) + pi/2)*sqrt(x**(-2)) assert acot(-I/5).evalf() == acot(x).rewrite(log).evalf(subs={x:-I/5}) assert acot(I/5).evalf() == acot(x).rewrite(log).evalf(subs={x:I/5}) def test_acot_fdiff(): assert acot(x).fdiff() == -1/(x**2 + 1) raises(ArgumentIndexError, lambda: acot(x).fdiff(2)) def test_attributes(): assert sin(x).args == (x,) def test_sincos_rewrite(): assert sin(pi/2 - x) == cos(x) assert sin(pi - x) == sin(x) assert cos(pi/2 - x) == sin(x) assert cos(pi - x) == -cos(x) def _check_even_rewrite(func, arg): """Checks that the expr has been rewritten using f(-x) -> f(x) arg : -x """ return func(arg).args[0] == -arg def _check_odd_rewrite(func, arg): """Checks that the expr has been rewritten using f(-x) -> -f(x) arg : -x """ return func(arg).func.is_Mul def _check_no_rewrite(func, arg): """Checks that the expr is not rewritten""" return func(arg).args[0] == arg def test_evenodd_rewrite(): a = cos(2) # negative b = sin(1) # positive even = [cos] odd = [sin, tan, cot, asin, atan, acot] with_minus = [-1, -2**1024 * E, -pi/105, -x*y, -x - y] for func in even: for expr in with_minus: assert _check_even_rewrite(func, expr) assert _check_no_rewrite(func, a*b) assert func( x - y) == func(y - x) # it doesn't matter which form is canonical for func in odd: for expr in with_minus: assert _check_odd_rewrite(func, expr) assert _check_no_rewrite(func, a*b) assert func( x - y) == -func(y - x) # it doesn't matter which form is canonical def test_issue_4547(): assert sin(x).rewrite(cot) == 2*cot(x/2)/(1 + cot(x/2)**2) assert cos(x).rewrite(cot) == -(1 - cot(x/2)**2)/(1 + cot(x/2)**2) assert tan(x).rewrite(cot) == 1/cot(x) assert cot(x).fdiff() == -1 - cot(x)**2 def test_as_leading_term_issue_5272(): assert sin(x).as_leading_term(x) == x assert cos(x).as_leading_term(x) == 1 assert tan(x).as_leading_term(x) == x assert cot(x).as_leading_term(x) == 1/x assert asin(x).as_leading_term(x) == x assert acos(x).as_leading_term(x) == pi/2 assert atan(x).as_leading_term(x) == x assert acot(x).as_leading_term(x) == pi/2 def test_leading_terms(): assert sin(1/x).as_leading_term(x) == AccumBounds(-1 , 1) assert sin(S.Half).as_leading_term(x) == sin(S.Half) assert cos(1/x).as_leading_term(x) == AccumBounds(-1 , 1) assert cos(S.Half).as_leading_term(x) == cos(S.Half) for func in [tan, cot]: for a in (1/x, S.Half): eq = func(a) assert eq.as_leading_term(x) == eq # https://github.com/sympy/sympy/issues/21038 f = sin(pi*(x + 4))/(3*x) assert f.as_leading_term(x) == pi/3 def test_atan2_expansion(): assert cancel(atan2(x**2, x + 1).diff(x) - atan(x**2/(x + 1)).diff(x)) == 0 assert cancel(atan(y/x).series(y, 0, 5) - atan2(y, x).series(y, 0, 5) + atan2(0, x) - atan(0)) == O(y**5) assert cancel(atan(y/x).series(x, 1, 4) - atan2(y, x).series(x, 1, 4) + atan2(y, 1) - atan(y)) == O((x - 1)**4, (x, 1)) assert cancel(atan((y + x)/x).series(x, 1, 3) - atan2(y + x, x).series(x, 1, 3) + atan2(1 + y, 1) - atan(1 + y)) == O((x - 1)**3, (x, 1)) assert Matrix([atan2(y, x)]).jacobian([y, x]) == \ Matrix([[x/(y**2 + x**2), -y/(y**2 + x**2)]]) def test_aseries(): def t(n, v, d, e): assert abs( n(1/v).evalf() - n(1/x).series(x, dir=d).removeO().subs(x, v)) < e t(atan, 0.1, '+', 1e-5) t(atan, -0.1, '-', 1e-5) t(acot, 0.1, '+', 1e-5) t(acot, -0.1, '-', 1e-5) def test_issue_4420(): i = Symbol('i', integer=True) e = Symbol('e', even=True) o = Symbol('o', odd=True) # unknown parity for variable assert cos(4*i*pi) == 1 assert sin(4*i*pi) == 0 assert tan(4*i*pi) == 0 assert cot(4*i*pi) is zoo assert cos(3*i*pi) == cos(pi*i) # +/-1 assert sin(3*i*pi) == 0 assert tan(3*i*pi) == 0 assert cot(3*i*pi) is zoo assert cos(4.0*i*pi) == 1 assert sin(4.0*i*pi) == 0 assert tan(4.0*i*pi) == 0 assert cot(4.0*i*pi) is zoo assert cos(3.0*i*pi) == cos(pi*i) # +/-1 assert sin(3.0*i*pi) == 0 assert tan(3.0*i*pi) == 0 assert cot(3.0*i*pi) is zoo assert cos(4.5*i*pi) == cos(0.5*pi*i) assert sin(4.5*i*pi) == sin(0.5*pi*i) assert tan(4.5*i*pi) == tan(0.5*pi*i) assert cot(4.5*i*pi) == cot(0.5*pi*i) # parity of variable is known assert cos(4*e*pi) == 1 assert sin(4*e*pi) == 0 assert tan(4*e*pi) == 0 assert cot(4*e*pi) is zoo assert cos(3*e*pi) == 1 assert sin(3*e*pi) == 0 assert tan(3*e*pi) == 0 assert cot(3*e*pi) is zoo assert cos(4.0*e*pi) == 1 assert sin(4.0*e*pi) == 0 assert tan(4.0*e*pi) == 0 assert cot(4.0*e*pi) is zoo assert cos(3.0*e*pi) == 1 assert sin(3.0*e*pi) == 0 assert tan(3.0*e*pi) == 0 assert cot(3.0*e*pi) is zoo assert cos(4.5*e*pi) == cos(0.5*pi*e) assert sin(4.5*e*pi) == sin(0.5*pi*e) assert tan(4.5*e*pi) == tan(0.5*pi*e) assert cot(4.5*e*pi) == cot(0.5*pi*e) assert cos(4*o*pi) == 1 assert sin(4*o*pi) == 0 assert tan(4*o*pi) == 0 assert cot(4*o*pi) is zoo assert cos(3*o*pi) == -1 assert sin(3*o*pi) == 0 assert tan(3*o*pi) == 0 assert cot(3*o*pi) is zoo assert cos(4.0*o*pi) == 1 assert sin(4.0*o*pi) == 0 assert tan(4.0*o*pi) == 0 assert cot(4.0*o*pi) is zoo assert cos(3.0*o*pi) == -1 assert sin(3.0*o*pi) == 0 assert tan(3.0*o*pi) == 0 assert cot(3.0*o*pi) is zoo assert cos(4.5*o*pi) == cos(0.5*pi*o) assert sin(4.5*o*pi) == sin(0.5*pi*o) assert tan(4.5*o*pi) == tan(0.5*pi*o) assert cot(4.5*o*pi) == cot(0.5*pi*o) # x could be imaginary assert cos(4*x*pi) == cos(4*pi*x) assert sin(4*x*pi) == sin(4*pi*x) assert tan(4*x*pi) == tan(4*pi*x) assert cot(4*x*pi) == cot(4*pi*x) assert cos(3*x*pi) == cos(3*pi*x) assert sin(3*x*pi) == sin(3*pi*x) assert tan(3*x*pi) == tan(3*pi*x) assert cot(3*x*pi) == cot(3*pi*x) assert cos(4.0*x*pi) == cos(4.0*pi*x) assert sin(4.0*x*pi) == sin(4.0*pi*x) assert tan(4.0*x*pi) == tan(4.0*pi*x) assert cot(4.0*x*pi) == cot(4.0*pi*x) assert cos(3.0*x*pi) == cos(3.0*pi*x) assert sin(3.0*x*pi) == sin(3.0*pi*x) assert tan(3.0*x*pi) == tan(3.0*pi*x) assert cot(3.0*x*pi) == cot(3.0*pi*x) assert cos(4.5*x*pi) == cos(4.5*pi*x) assert sin(4.5*x*pi) == sin(4.5*pi*x) assert tan(4.5*x*pi) == tan(4.5*pi*x) assert cot(4.5*x*pi) == cot(4.5*pi*x) def test_inverses(): raises(AttributeError, lambda: sin(x).inverse()) raises(AttributeError, lambda: cos(x).inverse()) assert tan(x).inverse() == atan assert cot(x).inverse() == acot raises(AttributeError, lambda: csc(x).inverse()) raises(AttributeError, lambda: sec(x).inverse()) assert asin(x).inverse() == sin assert acos(x).inverse() == cos assert atan(x).inverse() == tan assert acot(x).inverse() == cot def test_real_imag(): a, b = symbols('a b', real=True) z = a + b*I for deep in [True, False]: assert sin( z).as_real_imag(deep=deep) == (sin(a)*cosh(b), cos(a)*sinh(b)) assert cos( z).as_real_imag(deep=deep) == (cos(a)*cosh(b), -sin(a)*sinh(b)) assert tan(z).as_real_imag(deep=deep) == (sin(2*a)/(cos(2*a) + cosh(2*b)), sinh(2*b)/(cos(2*a) + cosh(2*b))) assert cot(z).as_real_imag(deep=deep) == (-sin(2*a)/(cos(2*a) - cosh(2*b)), sinh(2*b)/(cos(2*a) - cosh(2*b))) assert sin(a).as_real_imag(deep=deep) == (sin(a), 0) assert cos(a).as_real_imag(deep=deep) == (cos(a), 0) assert tan(a).as_real_imag(deep=deep) == (tan(a), 0) assert cot(a).as_real_imag(deep=deep) == (cot(a), 0) @XFAIL def test_sin_cos_with_infinity(): # Test for issue 5196 # https://github.com/sympy/sympy/issues/5196 assert sin(oo) is S.NaN assert cos(oo) is S.NaN @slow def test_sincos_rewrite_sqrt(): # equivalent to testing rewrite(pow) for p in [1, 3, 5, 17]: for t in [1, 8]: n = t*p # The vertices `exp(i*pi/n)` of a regular `n`-gon can # be expressed by means of nested square roots if and # only if `n` is a product of Fermat primes, `p`, and # powers of 2, `t'. The code aims to check all vertices # not belonging to an `m`-gon for `m < n`(`gcd(i, n) == 1`). # For large `n` this makes the test too slow, therefore # the vertices are limited to those of index `i < 10`. for i in range(1, min((n + 1)//2 + 1, 10)): if 1 == gcd(i, n): x = i*pi/n s1 = sin(x).rewrite(sqrt) c1 = cos(x).rewrite(sqrt) assert not s1.has(cos, sin), "fails for %d*pi/%d" % (i, n) assert not c1.has(cos, sin), "fails for %d*pi/%d" % (i, n) assert 1e-3 > abs(sin(x.evalf(5)) - s1.evalf(2)), "fails for %d*pi/%d" % (i, n) assert 1e-3 > abs(cos(x.evalf(5)) - c1.evalf(2)), "fails for %d*pi/%d" % (i, n) assert cos(pi/14).rewrite(sqrt) == sqrt(cos(pi/7)/2 + S.Half) assert cos(pi/257).rewrite(sqrt).evalf(64) == cos(pi/257).evalf(64) assert cos(pi*Rational(-15, 2)/11, evaluate=False).rewrite( sqrt) == -sqrt(-cos(pi*Rational(4, 11))/2 + S.Half) assert cos(Mul(2, pi, S.Half, evaluate=False), evaluate=False).rewrite( sqrt) == -1 e = cos(pi/3/17) # don't use pi/15 since that is caught at instantiation a = ( -3*sqrt(-sqrt(17) + 17)*sqrt(sqrt(17) + 17)/64 - 3*sqrt(34)*sqrt(sqrt(17) + 17)/128 - sqrt(sqrt(17) + 17)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/64 - sqrt(-sqrt(17) + 17)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/128 - Rational(1, 32) + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/64 + 3*sqrt(2)*sqrt(sqrt(17) + 17)/128 + sqrt(34)*sqrt(-sqrt(17) + 17)/128 + 13*sqrt(2)*sqrt(-sqrt(17) + 17)/128 + sqrt(17)*sqrt(-sqrt(17) + 17)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/128 + 5*sqrt(17)/32 + sqrt(3)*sqrt(-sqrt(2)*sqrt(sqrt(17) + 17)*sqrt(sqrt(17)/32 + sqrt(2)*sqrt(-sqrt(17) + 17)/32 + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + Rational(15, 32))/8 - 5*sqrt(2)*sqrt(sqrt(17)/32 + sqrt(2)*sqrt(-sqrt(17) + 17)/32 + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + Rational(15, 32))*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/64 - 3*sqrt(2)*sqrt(-sqrt(17) + 17)*sqrt(sqrt(17)/32 + sqrt(2)*sqrt(-sqrt(17) + 17)/32 + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + Rational(15, 32))/32 + sqrt(34)*sqrt(sqrt(17)/32 + sqrt(2)*sqrt(-sqrt(17) + 17)/32 + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + Rational(15, 32))*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/64 + sqrt(sqrt(17)/32 + sqrt(2)*sqrt(-sqrt(17) + 17)/32 + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + Rational(15, 32))/2 + S.Half + sqrt(-sqrt(17) + 17)*sqrt(sqrt(17)/32 + sqrt(2)*sqrt(-sqrt(17) + 17)/32 + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + Rational(15, 32))*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + sqrt(34)*sqrt(-sqrt(17) + 17)*sqrt(sqrt(17)/32 + sqrt(2)*sqrt(-sqrt(17) + 17)/32 + sqrt(2)*sqrt(-8*sqrt(2)*sqrt(sqrt(17) + 17) - sqrt(2)*sqrt(-sqrt(17) + 17) + sqrt(34)*sqrt(-sqrt(17) + 17) + 6*sqrt(17) + 34)/32 + Rational(15, 32))/32)/2) assert e.rewrite(sqrt) == a assert e.n() == a.n() # coverage of fermatCoords: multiplicity > 1; the following could be # different but that portion of the code should be tested in some way assert cos(pi/9/17).rewrite(sqrt) == \ sin(pi/9)*sin(pi*Rational(2, 17)) + cos(pi/9)*cos(pi*Rational(2, 17)) @slow def test_tancot_rewrite_sqrt(): # equivalent to testing rewrite(pow) for p in [1, 3, 5, 17]: for t in [1, 8]: n = t*p for i in range(1, min((n + 1)//2 + 1, 10)): if 1 == gcd(i, n): x = i*pi/n if 2*i != n and 3*i != 2*n: t1 = tan(x).rewrite(sqrt) assert not t1.has(cot, tan), "fails for %d*pi/%d" % (i, n) assert 1e-3 > abs( tan(x.evalf(7)) - t1.evalf(4) ), "fails for %d*pi/%d" % (i, n) if i != 0 and i != n: c1 = cot(x).rewrite(sqrt) assert not c1.has(cot, tan), "fails for %d*pi/%d" % (i, n) assert 1e-3 > abs( cot(x.evalf(7)) - c1.evalf(4) ), "fails for %d*pi/%d" % (i, n) def test_sec(): x = symbols('x', real=True) z = symbols('z') assert sec.nargs == FiniteSet(1) assert sec(zoo) is nan assert sec(0) == 1 assert sec(pi) == -1 assert sec(pi/2) is zoo assert sec(-pi/2) is zoo assert sec(pi/6) == 2*sqrt(3)/3 assert sec(pi/3) == 2 assert sec(pi*Rational(5, 2)) is zoo assert sec(pi*Rational(9, 7)) == -sec(pi*Rational(2, 7)) assert sec(pi*Rational(3, 4)) == -sqrt(2) # issue 8421 assert sec(I) == 1/cosh(1) assert sec(x*I) == 1/cosh(x) assert sec(-x) == sec(x) assert sec(asec(x)) == x assert sec(z).conjugate() == sec(conjugate(z)) assert (sec(z).as_real_imag() == (cos(re(z))*cosh(im(z))/(sin(re(z))**2*sinh(im(z))**2 + cos(re(z))**2*cosh(im(z))**2), sin(re(z))*sinh(im(z))/(sin(re(z))**2*sinh(im(z))**2 + cos(re(z))**2*cosh(im(z))**2))) assert sec(x).expand(trig=True) == 1/cos(x) assert sec(2*x).expand(trig=True) == 1/(2*cos(x)**2 - 1) assert sec(x).is_extended_real == True assert sec(z).is_real == None assert sec(a).is_algebraic is None assert sec(na).is_algebraic is False assert sec(x).as_leading_term() == sec(x) assert sec(0).is_finite == True assert sec(x).is_finite == None assert sec(pi/2).is_finite == False assert series(sec(x), x, x0=0, n=6) == 1 + x**2/2 + 5*x**4/24 + O(x**6) # https://github.com/sympy/sympy/issues/7166 assert series(sqrt(sec(x))) == 1 + x**2/4 + 7*x**4/96 + O(x**6) # https://github.com/sympy/sympy/issues/7167 assert (series(sqrt(sec(x)), x, x0=pi*3/2, n=4) == 1/sqrt(x - pi*Rational(3, 2)) + (x - pi*Rational(3, 2))**Rational(3, 2)/12 + (x - pi*Rational(3, 2))**Rational(7, 2)/160 + O((x - pi*Rational(3, 2))**4, (x, pi*Rational(3, 2)))) assert sec(x).diff(x) == tan(x)*sec(x) # Taylor Term checks assert sec(z).taylor_term(4, z) == 5*z**4/24 assert sec(z).taylor_term(6, z) == 61*z**6/720 assert sec(z).taylor_term(5, z) == 0 def test_sec_rewrite(): assert sec(x).rewrite(exp) == 1/(exp(I*x)/2 + exp(-I*x)/2) assert sec(x).rewrite(cos) == 1/cos(x) assert sec(x).rewrite(tan) == (tan(x/2)**2 + 1)/(-tan(x/2)**2 + 1) assert sec(x).rewrite(pow) == sec(x) assert sec(x).rewrite(sqrt) == sec(x) assert sec(z).rewrite(cot) == (cot(z/2)**2 + 1)/(cot(z/2)**2 - 1) assert sec(x).rewrite(sin) == 1 / sin(x + pi / 2, evaluate=False) assert sec(x).rewrite(tan) == (tan(x / 2)**2 + 1) / (-tan(x / 2)**2 + 1) assert sec(x).rewrite(csc) == csc(-x + pi/2, evaluate=False) def test_sec_fdiff(): assert sec(x).fdiff() == tan(x)*sec(x) raises(ArgumentIndexError, lambda: sec(x).fdiff(2)) def test_csc(): x = symbols('x', real=True) z = symbols('z') # https://github.com/sympy/sympy/issues/6707 cosecant = csc('x') alternate = 1/sin('x') assert cosecant.equals(alternate) == True assert alternate.equals(cosecant) == True assert csc.nargs == FiniteSet(1) assert csc(0) is zoo assert csc(pi) is zoo assert csc(zoo) is nan assert csc(pi/2) == 1 assert csc(-pi/2) == -1 assert csc(pi/6) == 2 assert csc(pi/3) == 2*sqrt(3)/3 assert csc(pi*Rational(5, 2)) == 1 assert csc(pi*Rational(9, 7)) == -csc(pi*Rational(2, 7)) assert csc(pi*Rational(3, 4)) == sqrt(2) # issue 8421 assert csc(I) == -I/sinh(1) assert csc(x*I) == -I/sinh(x) assert csc(-x) == -csc(x) assert csc(acsc(x)) == x assert csc(z).conjugate() == csc(conjugate(z)) assert (csc(z).as_real_imag() == (sin(re(z))*cosh(im(z))/(sin(re(z))**2*cosh(im(z))**2 + cos(re(z))**2*sinh(im(z))**2), -cos(re(z))*sinh(im(z))/(sin(re(z))**2*cosh(im(z))**2 + cos(re(z))**2*sinh(im(z))**2))) assert csc(x).expand(trig=True) == 1/sin(x) assert csc(2*x).expand(trig=True) == 1/(2*sin(x)*cos(x)) assert csc(x).is_extended_real == True assert csc(z).is_real == None assert csc(a).is_algebraic is None assert csc(na).is_algebraic is False assert csc(x).as_leading_term() == csc(x) assert csc(0).is_finite == False assert csc(x).is_finite == None assert csc(pi/2).is_finite == True assert series(csc(x), x, x0=pi/2, n=6) == \ 1 + (x - pi/2)**2/2 + 5*(x - pi/2)**4/24 + O((x - pi/2)**6, (x, pi/2)) assert series(csc(x), x, x0=0, n=6) == \ 1/x + x/6 + 7*x**3/360 + 31*x**5/15120 + O(x**6) assert csc(x).diff(x) == -cot(x)*csc(x) assert csc(x).taylor_term(2, x) == 0 assert csc(x).taylor_term(3, x) == 7*x**3/360 assert csc(x).taylor_term(5, x) == 31*x**5/15120 raises(ArgumentIndexError, lambda: csc(x).fdiff(2)) def test_asec(): z = Symbol('z', zero=True) assert asec(z) is zoo assert asec(nan) is nan assert asec(1) == 0 assert asec(-1) == pi assert asec(oo) == pi/2 assert asec(-oo) == pi/2 assert asec(zoo) == pi/2 assert asec(sec(pi*Rational(13, 4))) == pi*Rational(3, 4) assert asec(1 + sqrt(5)) == pi*Rational(2, 5) assert asec(2/sqrt(3)) == pi/6 assert asec(sqrt(4 - 2*sqrt(2))) == pi/8 assert asec(-sqrt(4 + 2*sqrt(2))) == pi*Rational(5, 8) assert asec(sqrt(2 + 2*sqrt(5)/5)) == pi*Rational(3, 10) assert asec(-sqrt(2 + 2*sqrt(5)/5)) == pi*Rational(7, 10) assert asec(sqrt(2) - sqrt(6)) == pi*Rational(11, 12) assert asec(x).diff(x) == 1/(x**2*sqrt(1 - 1/x**2)) assert asec(x).as_leading_term(x) == I*log(x) assert asec(x).rewrite(log) == I*log(sqrt(1 - 1/x**2) + I/x) + pi/2 assert asec(x).rewrite(asin) == -asin(1/x) + pi/2 assert asec(x).rewrite(acos) == acos(1/x) assert asec(x).rewrite(atan) == (2*atan(x + sqrt(x**2 - 1)) - pi/2)*sqrt(x**2)/x assert asec(x).rewrite(acot) == (2*acot(x - sqrt(x**2 - 1)) - pi/2)*sqrt(x**2)/x assert asec(x).rewrite(acsc) == -acsc(x) + pi/2 raises(ArgumentIndexError, lambda: asec(x).fdiff(2)) def test_asec_is_real(): assert asec(S.Half).is_real is False n = Symbol('n', positive=True, integer=True) assert asec(n).is_extended_real is True assert asec(x).is_real is None assert asec(r).is_real is None t = Symbol('t', real=False, finite=True) assert asec(t).is_real is False def test_acsc(): assert acsc(nan) is nan assert acsc(1) == pi/2 assert acsc(-1) == -pi/2 assert acsc(oo) == 0 assert acsc(-oo) == 0 assert acsc(zoo) == 0 assert acsc(0) is zoo assert acsc(csc(3)) == -3 + pi assert acsc(csc(4)) == -4 + pi assert acsc(csc(6)) == 6 - 2*pi assert unchanged(acsc, csc(x)) assert unchanged(acsc, sec(x)) assert acsc(2/sqrt(3)) == pi/3 assert acsc(csc(pi*Rational(13, 4))) == -pi/4 assert acsc(sqrt(2 + 2*sqrt(5)/5)) == pi/5 assert acsc(-sqrt(2 + 2*sqrt(5)/5)) == -pi/5 assert acsc(-2) == -pi/6 assert acsc(-sqrt(4 + 2*sqrt(2))) == -pi/8 assert acsc(sqrt(4 - 2*sqrt(2))) == pi*Rational(3, 8) assert acsc(1 + sqrt(5)) == pi/10 assert acsc(sqrt(2) - sqrt(6)) == pi*Rational(-5, 12) assert acsc(x).diff(x) == -1/(x**2*sqrt(1 - 1/x**2)) assert acsc(x).as_leading_term(x) == I*log(x) assert acsc(x).rewrite(log) == -I*log(sqrt(1 - 1/x**2) + I/x) assert acsc(x).rewrite(asin) == asin(1/x) assert acsc(x).rewrite(acos) == -acos(1/x) + pi/2 assert acsc(x).rewrite(atan) == (-atan(sqrt(x**2 - 1)) + pi/2)*sqrt(x**2)/x assert acsc(x).rewrite(acot) == (-acot(1/sqrt(x**2 - 1)) + pi/2)*sqrt(x**2)/x assert acsc(x).rewrite(asec) == -asec(x) + pi/2 raises(ArgumentIndexError, lambda: acsc(x).fdiff(2)) def test_csc_rewrite(): assert csc(x).rewrite(pow) == csc(x) assert csc(x).rewrite(sqrt) == csc(x) assert csc(x).rewrite(exp) == 2*I/(exp(I*x) - exp(-I*x)) assert csc(x).rewrite(sin) == 1/sin(x) assert csc(x).rewrite(tan) == (tan(x/2)**2 + 1)/(2*tan(x/2)) assert csc(x).rewrite(cot) == (cot(x/2)**2 + 1)/(2*cot(x/2)) assert csc(x).rewrite(cos) == 1/cos(x - pi/2, evaluate=False) assert csc(x).rewrite(sec) == sec(-x + pi/2, evaluate=False) # issue 17349 assert csc(1 - exp(-besselj(I, I))).rewrite(cos) == \ -1/cos(-pi/2 - 1 + cos(I*besselj(I, I)) + I*cos(-pi/2 + I*besselj(I, I), evaluate=False), evaluate=False) def test_inverses_nseries(): assert asin(x + 2)._eval_nseries(x, 4, None, I) == -asin(2) + pi + sqrt(3)*I*x/3 - sqrt(3)*I*x**2/9 + \ sqrt(3)*I*x**3/18 + O(x**4) assert asin(x + 2)._eval_nseries(x, 4, None, -I) == asin(2) - sqrt(3)*I*x/3 + sqrt(3)*I*x**2/9 - sqrt(3)*I*x**3/18 + O(x**4) assert asin(x - 2)._eval_nseries(x, 4, None, I) == -asin(2) - sqrt(3)*I*x/3 - sqrt(3)*I*x**2/9 - sqrt(3)*I*x**3/18 + O(x**4) assert asin(x - 2)._eval_nseries(x, 4, None, -I) == asin(2) - pi + sqrt(3)*I*x/3 + sqrt(3)*I*x**2/9 + \ sqrt(3)*I*x**3/18 + O(x**4) assert asin(I*x + I*x**3 + 2)._eval_nseries(x, 3, None, 1) == -asin(2) + pi - sqrt(3)*x/3 + sqrt(3)*I*x**2/9 + O(x**3) assert asin(I*x + I*x**3 + 2)._eval_nseries(x, 3, None, -1) == asin(2) + sqrt(3)*x/3 - sqrt(3)*I*x**2/9 + O(x**3) assert asin(I*x + I*x**3 - 2)._eval_nseries(x, 3, None, 1) == -asin(2) + sqrt(3)*x/3 + sqrt(3)*I*x**2/9 + O(x**3) assert asin(I*x + I*x**3 - 2)._eval_nseries(x, 3, None, -1) == asin(2) - pi - sqrt(3)*x/3 - sqrt(3)*I*x**2/9 + O(x**3) assert asin(I*x**2 + I*x**3 + 2)._eval_nseries(x, 3, None, 1) == -asin(2) + pi - sqrt(3)*x**2/3 + O(x**3) assert asin(I*x**2 + I*x**3 + 2)._eval_nseries(x, 3, None, -1) == -asin(2) + pi - sqrt(3)*x**2/3 + O(x**3) assert asin(I*x**2 + I*x**3 - 2)._eval_nseries(x, 3, None, 1) == -asin(2) + sqrt(3)*x**2/3 + O(x**3) assert asin(I*x**2 + I*x**3 - 2)._eval_nseries(x, 3, None, -1) == -asin(2) + sqrt(3)*x**2/3 + O(x**3) assert asin(1 + x)._eval_nseries(x, 3, None) == pi/2 - sqrt(2)*sqrt(-x) - \ sqrt(2)*(-x)**(S(3)/2)/12 - 3*sqrt(2)*(-x)**(S(5)/2)/160 + O(x**3) assert asin(-1 + x)._eval_nseries(x, 3, None) == -pi/2 + sqrt(2)*sqrt(x) + \ sqrt(2)*x**(S(3)/2)/12 + 3*sqrt(2)*x**(S(5)/2)/160 + O(x**3) assert asin(exp(x))._eval_nseries(x, 3, None) == pi/2 - sqrt(2)*sqrt(-x) + \ sqrt(2)*(-x)**(S(3)/2)/6 - sqrt(2)*(-x)**(S(5)/2)/120 + O(x**3) assert asin(-exp(x))._eval_nseries(x, 3, None) == -pi/2 + sqrt(2)*sqrt(-x) - \ sqrt(2)*(-x)**(S(3)/2)/6 + sqrt(2)*(-x)**(S(5)/2)/120 + O(x**3) assert acos(x + 2)._eval_nseries(x, 4, None, I) == -acos(2) - sqrt(3)*I*x/3 + sqrt(3)*I*x**2/9 - sqrt(3)*I*x**3/18 + O(x**4) assert acos(x + 2)._eval_nseries(x, 4, None, -I) == acos(2) + sqrt(3)*I*x/3 - sqrt(3)*I*x**2/9 + sqrt(3)*I*x**3/18 + O(x**4) assert acos(x - 2)._eval_nseries(x, 4, None, I) == acos(-2) + sqrt(3)*I*x/3 + sqrt(3)*I*x**2/9 + sqrt(3)*I*x**3/18 + O(x**4) assert acos(x - 2)._eval_nseries(x, 4, None, -I) == -acos(-2) + 2*pi - sqrt(3)*I*x/3 - \ sqrt(3)*I*x**2/9 - sqrt(3)*I*x**3/18 + O(x**4) # assert acos(I*x + I*x**3 + 2)._eval_nseries(x, 3, None, 1) == -acos(2) + sqrt(3)*x/3 - sqrt(3)*I*x**2/9 + O(x**3) # assert acos(I*x + I*x**3 + 2)._eval_nseries(x, 3, None, -1) == acos(2) - sqrt(3)*x/3 + sqrt(3)*I*x**2/9 + O(x**3) # assert acos(I*x + I*x**3 - 2)._eval_nseries(x, 3, None, 1) == acos(-2) - sqrt(3)*x/3 - sqrt(3)*I*x**2/9 + O(x**3) # assert acos(I*x + I*x**3 - 2)._eval_nseries(x, 3, None, -1) == -acos(-2) + 2*pi + sqrt(3)*x/3 + sqrt(3)*I*x**2/9 + O(x**3) # assert acos(I*x**2 + I*x**3 + 2)._eval_nseries(x, 3, None, 1) == -acos(2) + sqrt(3)*x**2/3 + O(x**3) # assert acos(I*x**2 + I*x**3 + 2)._eval_nseries(x, 3, None, -1) == -acos(2) + sqrt(3)*x**2/3 + O(x**3) # assert acos(I*x**2 + I*x**3 - 2)._eval_nseries(x, 3, None, 1) == acos(-2) - sqrt(3)*x**2/3 + O(x**3) # assert acos(I*x**2 + I*x**3 - 2)._eval_nseries(x, 3, None, -1) == acos(-2) - sqrt(3)*x**2/3 + O(x**3) # assert acos(1 + x)._eval_nseries(x, 3, None) == sqrt(2)*sqrt(-x) + sqrt(2)*(-x)**(S(3)/2)/12 + 3*sqrt(2)*(-x)**(S(5)/2)/160 + O(x**3) # assert acos(-1 + x)._eval_nseries(x, 3, None) == pi - sqrt(2)*sqrt(x) - sqrt(2)*x**(S(3)/2)/12 - 3*sqrt(2)*x**(S(5)/2)/160 + O(x**3) # assert acos(exp(x))._eval_nseries(x, 3, None) == sqrt(2)*sqrt(-x) - sqrt(2)*(-x)**(S(3)/2)/6 + sqrt(2)*(-x)**(S(5)/2)/120 + O(x**3) # assert acos(-exp(x))._eval_nseries(x, 3, None) == pi - sqrt(2)*sqrt(-x) + sqrt(2)*(-x)**(S(3)/2)/6 - sqrt(2)*(-x)**(S(5)/2)/120 + O(x**3) assert atan(x + 2*I)._eval_nseries(x, 4, None, 1) == I*atanh(2) - x/3 - 2*I*x**2/9 + 13*x**3/81 + O(x**4) assert atan(x + 2*I)._eval_nseries(x, 4, None, -1) == I*atanh(2) - pi - x/3 - 2*I*x**2/9 + 13*x**3/81 + O(x**4) assert atan(x - 2*I)._eval_nseries(x, 4, None, 1) == -I*atanh(2) + pi - x/3 + 2*I*x**2/9 + 13*x**3/81 + O(x**4) assert atan(x - 2*I)._eval_nseries(x, 4, None, -1) == -I*atanh(2) - x/3 + 2*I*x**2/9 + 13*x**3/81 + O(x**4) # assert atan(x**2 + 2*I)._eval_nseries(x, 3, None, 1) == I*atanh(2) - x**2/3 + O(x**3) # assert atan(x**2 + 2*I)._eval_nseries(x, 3, None, -1) == I*atanh(2) - x**2/3 + O(x**3) # assert atan(x**2 - 2*I)._eval_nseries(x, 3, None, 1) == -I*atanh(2) + pi - x**2/3 + O(x**3) # assert atan(x**2 - 2*I)._eval_nseries(x, 3, None, -1) == -I*atanh(2) + pi - x**2/3 + O(x**3) assert atan(1/x)._eval_nseries(x, 2, None, 1) == pi/2 - x + O(x**2) assert atan(1/x)._eval_nseries(x, 2, None, -1) == -pi/2 - x + O(x**2) assert acot(x + S(1)/2*I)._eval_nseries(x, 4, None, 1) == -I*acoth(S(1)/2) + pi - 4*x/3 + 8*I*x**2/9 + 112*x**3/81 + O(x**4) assert acot(x + S(1)/2*I)._eval_nseries(x, 4, None, -1) == -I*acoth(S(1)/2) - 4*x/3 + 8*I*x**2/9 + 112*x**3/81 + O(x**4) assert acot(x - S(1)/2*I)._eval_nseries(x, 4, None, 1) == I*acoth(S(1)/2) - 4*x/3 - 8*I*x**2/9 + 112*x**3/81 + O(x**4) assert acot(x - S(1)/2*I)._eval_nseries(x, 4, None, -1) == I*acoth(S(1)/2) - pi - 4*x/3 - 8*I*x**2/9 + 112*x**3/81 + O(x**4) # assert acot(x**2 + S(1)/2*I)._eval_nseries(x, 3, None, 1) == -I*acoth(S(1)/2) + pi - 4*x**2/3 + O(x**3) # assert acot(x**2 + S(1)/2*I)._eval_nseries(x, 3, None, -1) == -I*acoth(S(1)/2) + pi - 4*x**2/3 + O(x**3) # assert acot(x**2 - S(1)/2*I)._eval_nseries(x, 3, None, 1) == I*acoth(S(1)/2) - 4*x**2/3 + O(x**3) # assert acot(x**2 - S(1)/2*I)._eval_nseries(x, 3, None, -1) == I*acoth(S(1)/2) - 4*x**2/3 + O(x**3) # assert acot(x)._eval_nseries(x, 2, None, 1) == pi/2 - x + O(x**2) # assert acot(x)._eval_nseries(x, 2, None, -1) == -pi/2 - x + O(x**2) assert asec(x + S(1)/2)._eval_nseries(x, 4, None, I) == asec(S(1)/2) - 4*sqrt(3)*I*x/3 + \ 8*sqrt(3)*I*x**2/9 - 16*sqrt(3)*I*x**3/9 + O(x**4) assert asec(x + S(1)/2)._eval_nseries(x, 4, None, -I) == -asec(S(1)/2) + 4*sqrt(3)*I*x/3 - \ 8*sqrt(3)*I*x**2/9 + 16*sqrt(3)*I*x**3/9 + O(x**4) assert asec(x - S(1)/2)._eval_nseries(x, 4, None, I) == -asec(-S(1)/2) + 2*pi + 4*sqrt(3)*I*x/3 + \ 8*sqrt(3)*I*x**2/9 + 16*sqrt(3)*I*x**3/9 + O(x**4) assert asec(x - S(1)/2)._eval_nseries(x, 4, None, -I) == asec(-S(1)/2) - 4*sqrt(3)*I*x/3 - \ 8*sqrt(3)*I*x**2/9 - 16*sqrt(3)*I*x**3/9 + O(x**4) # assert asec(I*x + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, 1) == asec(S(1)/2) + 4*sqrt(3)*x/3 - 8*sqrt(3)*I*x**2/9 + O(x**3) # assert asec(I*x + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, -1) == -asec(S(1)/2) - 4*sqrt(3)*x/3 + 8*sqrt(3)*I*x**2/9 + O(x**3) # assert asec(I*x + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, 1) == -asec(-S(1)/2) + 2*pi - 4*sqrt(3)*x/3 - 8*sqrt(3)*I*x**2/9 + O(x**3) # assert asec(I*x + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, -1) == asec(-S(1)/2) + 4*sqrt(3)*x/3 + 8*sqrt(3)*I*x**2/9 + O(x**3) # assert asec(I*x**2 + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, 1) == asec(S(1)/2) + 4*sqrt(3)*x**2/3 + O(x**3) # assert asec(I*x**2 + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, -1) == asec(S(1)/2) + 4*sqrt(3)*x**2/3 + O(x**3) # assert asec(I*x**2 + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, 1) == -asec(-S(1)/2) + 2*pi - 4*sqrt(3)*x**2/3 + O(x**3) # assert asec(I*x**2 + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, -1) == -asec(-S(1)/2) + 2*pi - 4*sqrt(3)*x**2/3 + O(x**3) # assert asec(1 + x)._eval_nseries(x, 3, None) == sqrt(2)*sqrt(x) - 5*sqrt(2)*x**(S(3)/2)/12 + 43*sqrt(2)*x**(S(5)/2)/160 + O(x**3) # assert asec(-1 + x)._eval_nseries(x, 3, None) == pi - sqrt(2)*sqrt(-x) + 5*sqrt(2)*(-x)**(S(3)/2)/12 - 43*sqrt(2)*(-x)**(S(5)/2)/160 + O(x**3) # assert asec(exp(x))._eval_nseries(x, 3, None) == sqrt(2)*sqrt(x) - sqrt(2)*x**(S(3)/2)/6 + sqrt(2)*x**(S(5)/2)/120 + O(x**3) # assert asec(-exp(x))._eval_nseries(x, 3, None) == pi - sqrt(2)*sqrt(x) + sqrt(2)*x**(S(3)/2)/6 - sqrt(2)*x**(S(5)/2)/120 + O(x**3) assert acsc(x + S(1)/2)._eval_nseries(x, 4, None, I) == acsc(S(1)/2) + 4*sqrt(3)*I*x/3 - \ 8*sqrt(3)*I*x**2/9 + 16*sqrt(3)*I*x**3/9 + O(x**4) assert acsc(x + S(1)/2)._eval_nseries(x, 4, None, -I) == -acsc(S(1)/2) + pi - 4*sqrt(3)*I*x/3 + \ 8*sqrt(3)*I*x**2/9 - 16*sqrt(3)*I*x**3/9 + O(x**4) assert acsc(x - S(1)/2)._eval_nseries(x, 4, None, I) == acsc(S(1)/2) - pi - 4*sqrt(3)*I*x/3 - \ 8*sqrt(3)*I*x**2/9 - 16*sqrt(3)*I*x**3/9 + O(x**4) assert acsc(x - S(1)/2)._eval_nseries(x, 4, None, -I) == -acsc(S(1)/2) + 4*sqrt(3)*I*x/3 + \ 8*sqrt(3)*I*x**2/9 + 16*sqrt(3)*I*x**3/9 + O(x**4) # assert acsc(I*x + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, 1) == acsc(S(1)/2) - 4*sqrt(3)*x/3 + 8*sqrt(3)*I*x**2/9 + O(x**3) # assert acsc(I*x + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, -1) == -acsc(S(1)/2) + pi + 4*sqrt(3)*x/3 - 8*sqrt(3)*I*x**2/9 + O(x**3) # assert acsc(I*x + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, 1) == acsc(S(1)/2) - pi + 4*sqrt(3)*x/3 + 8*sqrt(3)*I*x**2/9 + O(x**3) # assert acsc(I*x + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, -1) == -acsc(S(1)/2) - 4*sqrt(3)*x/3 - 8*sqrt(3)*I*x**2/9 + O(x**3) # assert acsc(I*x**2 + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, 1) == acsc(S(1)/2) - 4*sqrt(3)*x**2/3 + O(x**3) # assert acsc(I*x**2 + I*x**3 + S(1)/2)._eval_nseries(x, 3, None, -1) == acsc(S(1)/2) - 4*sqrt(3)*x**2/3 + O(x**3) # assert acsc(I*x**2 + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, 1) == acsc(S(1)/2) - pi + 4*sqrt(3)*x**2/3 + O(x**3) # assert acsc(I*x**2 + I*x**3 - S(1)/2)._eval_nseries(x, 3, None, -1) == acsc(S(1)/2) - pi + 4*sqrt(3)*x**2/3 + O(x**3) # assert acsc(1 + x)._eval_nseries(x, 3, None) == pi/2 - sqrt(2)*sqrt(x) + 5*sqrt(2)*x**(S(3)/2)/12 - 43*sqrt(2)*x**(S(5)/2)/160 + O(x**3) # assert acsc(-1 + x)._eval_nseries(x, 3, None) == -pi/2 + sqrt(2)*sqrt(-x) - 5*sqrt(2)*(-x)**(S(3)/2)/12 + 43*sqrt(2)*(-x)**(S(5)/2)/160 + O(x**3) # assert acsc(exp(x))._eval_nseries(x, 3, None) == pi/2 - sqrt(2)*sqrt(x) + sqrt(2)*x**(S(3)/2)/6 - sqrt(2)*x**(S(5)/2)/120 + O(x**3) # assert acsc(-exp(x))._eval_nseries(x, 3, None) == -pi/2 + sqrt(2)*sqrt(x) - sqrt(2)*x**(S(3)/2)/6 + sqrt(2)*x**(S(5)/2)/120 + O(x**3) def test_issue_8653(): n = Symbol('n', integer=True) assert sin(n).is_irrational is None assert cos(n).is_irrational is None assert tan(n).is_irrational is None def test_issue_9157(): n = Symbol('n', integer=True, positive=True) assert atan(n - 1).is_nonnegative is True def test_trig_period(): x, y = symbols('x, y') assert sin(x).period() == 2*pi assert cos(x).period() == 2*pi assert tan(x).period() == pi assert cot(x).period() == pi assert sec(x).period() == 2*pi assert csc(x).period() == 2*pi assert sin(2*x).period() == pi assert cot(4*x - 6).period() == pi/4 assert cos((-3)*x).period() == pi*Rational(2, 3) assert cos(x*y).period(x) == 2*pi/abs(y) assert sin(3*x*y + 2*pi).period(y) == 2*pi/abs(3*x) assert tan(3*x).period(y) is S.Zero raises(NotImplementedError, lambda: sin(x**2).period(x)) def test_issue_7171(): assert sin(x).rewrite(sqrt) == sin(x) assert sin(x).rewrite(pow) == sin(x) def test_issue_11864(): w, k = symbols('w, k', real=True) F = Piecewise((1, Eq(2*pi*k, 0)), (sin(pi*k)/(pi*k), True)) soln = Piecewise((1, Eq(2*pi*k, 0)), (sinc(pi*k), True)) assert F.rewrite(sinc) == soln def test_real_assumptions(): z = Symbol('z', real=False, finite=True) assert sin(z).is_real is None assert cos(z).is_real is None assert tan(z).is_real is False assert sec(z).is_real is None assert csc(z).is_real is None assert cot(z).is_real is False assert asin(p).is_real is None assert asin(n).is_real is None assert asec(p).is_real is None assert asec(n).is_real is None assert acos(p).is_real is None assert acos(n).is_real is None assert acsc(p).is_real is None assert acsc(n).is_real is None assert atan(p).is_positive is True assert atan(n).is_negative is True assert acot(p).is_positive is True assert acot(n).is_negative is True def test_issue_14320(): assert asin(sin(2)) == -2 + pi and (-pi/2 <= -2 + pi <= pi/2) and sin(2) == sin(-2 + pi) assert asin(cos(2)) == -2 + pi/2 and (-pi/2 <= -2 + pi/2 <= pi/2) and cos(2) == sin(-2 + pi/2) assert acos(sin(2)) == -pi/2 + 2 and (0 <= -pi/2 + 2 <= pi) and sin(2) == cos(-pi/2 + 2) assert acos(cos(20)) == -6*pi + 20 and (0 <= -6*pi + 20 <= pi) and cos(20) == cos(-6*pi + 20) assert acos(cos(30)) == -30 + 10*pi and (0 <= -30 + 10*pi <= pi) and cos(30) == cos(-30 + 10*pi) assert atan(tan(17)) == -5*pi + 17 and (-pi/2 < -5*pi + 17 < pi/2) and tan(17) == tan(-5*pi + 17) assert atan(tan(15)) == -5*pi + 15 and (-pi/2 < -5*pi + 15 < pi/2) and tan(15) == tan(-5*pi + 15) assert atan(cot(12)) == -12 + pi*Rational(7, 2) and (-pi/2 < -12 + pi*Rational(7, 2) < pi/2) and cot(12) == tan(-12 + pi*Rational(7, 2)) assert acot(cot(15)) == -5*pi + 15 and (-pi/2 < -5*pi + 15 <= pi/2) and cot(15) == cot(-5*pi + 15) assert acot(tan(19)) == -19 + pi*Rational(13, 2) and (-pi/2 < -19 + pi*Rational(13, 2) <= pi/2) and tan(19) == cot(-19 + pi*Rational(13, 2)) assert asec(sec(11)) == -11 + 4*pi and (0 <= -11 + 4*pi <= pi) and cos(11) == cos(-11 + 4*pi) assert asec(csc(13)) == -13 + pi*Rational(9, 2) and (0 <= -13 + pi*Rational(9, 2) <= pi) and sin(13) == cos(-13 + pi*Rational(9, 2)) assert acsc(csc(14)) == -4*pi + 14 and (-pi/2 <= -4*pi + 14 <= pi/2) and sin(14) == sin(-4*pi + 14) assert acsc(sec(10)) == pi*Rational(-7, 2) + 10 and (-pi/2 <= pi*Rational(-7, 2) + 10 <= pi/2) and cos(10) == sin(pi*Rational(-7, 2) + 10) def test_issue_14543(): assert sec(2*pi + 11) == sec(11) assert sec(2*pi - 11) == sec(11) assert sec(pi + 11) == -sec(11) assert sec(pi - 11) == -sec(11) assert csc(2*pi + 17) == csc(17) assert csc(2*pi - 17) == -csc(17) assert csc(pi + 17) == -csc(17) assert csc(pi - 17) == csc(17) x = Symbol('x') assert csc(pi/2 + x) == sec(x) assert csc(pi/2 - x) == sec(x) assert csc(pi*Rational(3, 2) + x) == -sec(x) assert csc(pi*Rational(3, 2) - x) == -sec(x) assert sec(pi/2 - x) == csc(x) assert sec(pi/2 + x) == -csc(x) assert sec(pi*Rational(3, 2) + x) == csc(x) assert sec(pi*Rational(3, 2) - x) == -csc(x) def test_as_real_imag(): # This is for https://github.com/sympy/sympy/issues/17142 # If it start failing again in irrelevant builds or in the master # please open up the issue again. expr = atan(I/(I + I*tan(1))) assert expr.as_real_imag() == (expr, 0) def test_issue_18746(): e3 = cos(S.Pi*(x/4 + 1/4)) assert e3.period() == 8 sympy-sympy-1.9/sympy/functions/elementary/trigonometric.py000066400000000000000000003243631412543434000245330ustar00rootroot00000000000000from typing import Tuple from sympy.core.add import Add from sympy.core.basic import sympify, cacheit from sympy.core.expr import Expr from sympy.core.function import Function, ArgumentIndexError, PoleError, expand_mul from sympy.core.logic import fuzzy_not, fuzzy_or, FuzzyBool from sympy.core.numbers import igcdex, Rational, pi from sympy.core.relational import Ne from sympy.core.singleton import S from sympy.core.symbol import Symbol from sympy.functions.combinatorial.factorials import factorial, RisingFactorial from sympy.functions.elementary.exponential import log, exp from sympy.functions.elementary.integers import floor from sympy.functions.elementary.hyperbolic import (acoth, asinh, atanh, cosh, coth, HyperbolicFunction, sinh, tanh) from sympy.functions.elementary.miscellaneous import sqrt, Min, Max from sympy.functions.elementary.piecewise import Piecewise from sympy.sets.sets import FiniteSet from sympy.utilities.iterables import numbered_symbols ############################################################################### ########################## TRIGONOMETRIC FUNCTIONS ############################ ############################################################################### class TrigonometricFunction(Function): """Base class for trigonometric functions. """ unbranched = True _singularities = (S.ComplexInfinity,) def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if s.args[0].is_rational and fuzzy_not(s.args[0].is_zero): return False else: return s.is_rational def _eval_is_algebraic(self): s = self.func(*self.args) if s.func == self.func: if fuzzy_not(self.args[0].is_zero) and self.args[0].is_algebraic: return False pi_coeff = _pi_coeff(self.args[0]) if pi_coeff is not None and pi_coeff.is_rational: return True else: return s.is_algebraic def _eval_expand_complex(self, deep=True, **hints): re_part, im_part = self.as_real_imag(deep=deep, **hints) return re_part + im_part*S.ImaginaryUnit def _as_real_imag(self, deep=True, **hints): if self.args[0].is_extended_real: if deep: hints['complex'] = False return (self.args[0].expand(deep, **hints), S.Zero) else: return (self.args[0], S.Zero) if deep: re, im = self.args[0].expand(deep, **hints).as_real_imag() else: re, im = self.args[0].as_real_imag() return (re, im) def _period(self, general_period, symbol=None): f = expand_mul(self.args[0]) if symbol is None: symbol = tuple(f.free_symbols)[0] if not f.has(symbol): return S.Zero if f == symbol: return general_period if symbol in f.free_symbols: if f.is_Mul: g, h = f.as_independent(symbol) if h == symbol: return general_period/abs(g) if f.is_Add: a, h = f.as_independent(symbol) g, h = h.as_independent(symbol, as_Add=False) if h == symbol: return general_period/abs(g) raise NotImplementedError("Use the periodicity function instead.") def _peeloff_pi(arg): """ Split ARG into two parts, a "rest" and a multiple of pi/2. This assumes ARG to be an Add. The multiple of pi returned in the second position is always a Rational. Examples ======== >>> from sympy.functions.elementary.trigonometric import _peeloff_pi as peel >>> from sympy import pi >>> from sympy.abc import x, y >>> peel(x + pi/2) (x, pi/2) >>> peel(x + 2*pi/3 + pi*y) (x + pi*y + pi/6, pi/2) """ pi_coeff = S.Zero rest_terms = [] for a in Add.make_args(arg): K = a.coeff(S.Pi) if K and K.is_rational: pi_coeff += K else: rest_terms.append(a) if pi_coeff is S.Zero: return arg, S.Zero m1 = (pi_coeff % S.Half)*S.Pi m2 = pi_coeff*S.Pi - m1 final_coeff = m2 / S.Pi if final_coeff.is_integer or ((2*final_coeff).is_integer and final_coeff.is_even is False): return Add(*(rest_terms + [m1])), m2 return arg, S.Zero def _pi_coeff(arg, cycles=1): """ When arg is a Number times pi (e.g. 3*pi/2) then return the Number normalized to be in the range [0, 2], else None. When an even multiple of pi is encountered, if it is multiplying something with known parity then the multiple is returned as 0 otherwise as 2. Examples ======== >>> from sympy.functions.elementary.trigonometric import _pi_coeff as coeff >>> from sympy import pi, Dummy >>> from sympy.abc import x >>> coeff(3*x*pi) 3*x >>> coeff(11*pi/7) 11/7 >>> coeff(-11*pi/7) 3/7 >>> coeff(4*pi) 0 >>> coeff(5*pi) 1 >>> coeff(5.0*pi) 1 >>> coeff(5.5*pi) 3/2 >>> coeff(2 + pi) >>> coeff(2*Dummy(integer=True)*pi) 2 >>> coeff(2*Dummy(even=True)*pi) 0 """ arg = sympify(arg) if arg is S.Pi: return S.One elif not arg: return S.Zero elif arg.is_Mul: cx = arg.coeff(S.Pi) if cx: c, x = cx.as_coeff_Mul() # pi is not included as coeff if c.is_Float: # recast exact binary fractions to Rationals f = abs(c) % 1 if f != 0: p = -int(round(log(f, 2).evalf())) m = 2**p cm = c*m i = int(cm) if i == cm: c = Rational(i, m) cx = c*x else: c = Rational(int(c)) cx = c*x if x.is_integer: c2 = c % 2 if c2 == 1: return x elif not c2: if x.is_even is not None: # known parity return S.Zero return S(2) else: return c2*x return cx elif arg.is_zero: return S.Zero class sin(TrigonometricFunction): """ The sine function. Returns the sine of x (measured in radians). Explanation =========== This function will evaluate automatically in the case x/pi is some rational number [4]_. For example, if x is a multiple of pi, pi/2, pi/3, pi/4 and pi/6. Examples ======== >>> from sympy import sin, pi >>> from sympy.abc import x >>> sin(x**2).diff(x) 2*x*cos(x**2) >>> sin(1).diff(x) 0 >>> sin(pi) 0 >>> sin(pi/2) 1 >>> sin(pi/6) 1/2 >>> sin(pi/12) -sqrt(2)/4 + sqrt(6)/4 See Also ======== csc, cos, sec, tan, cot asin, acsc, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions .. [2] http://dlmf.nist.gov/4.14 .. [3] http://functions.wolfram.com/ElementaryFunctions/Sin .. [4] http://mathworld.wolfram.com/TrigonometryAngles.html """ def period(self, symbol=None): return self._period(2*pi, symbol) def fdiff(self, argindex=1): if argindex == 1: return cos(self.args[0]) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): from sympy.calculus import AccumBounds from sympy.sets.setexpr import SetExpr if arg.is_Number: if arg is S.NaN: return S.NaN elif arg.is_zero: return S.Zero elif arg is S.Infinity or arg is S.NegativeInfinity: return AccumBounds(-1, 1) if arg is S.ComplexInfinity: return S.NaN if isinstance(arg, AccumBounds): min, max = arg.min, arg.max d = floor(min/(2*S.Pi)) if min is not S.NegativeInfinity: min = min - d*2*S.Pi if max is not S.Infinity: max = max - d*2*S.Pi if AccumBounds(min, max).intersection(FiniteSet(S.Pi/2, S.Pi*Rational(5, 2))) \ is not S.EmptySet and \ AccumBounds(min, max).intersection(FiniteSet(S.Pi*Rational(3, 2), S.Pi*Rational(7, 2))) is not S.EmptySet: return AccumBounds(-1, 1) elif AccumBounds(min, max).intersection(FiniteSet(S.Pi/2, S.Pi*Rational(5, 2))) \ is not S.EmptySet: return AccumBounds(Min(sin(min), sin(max)), 1) elif AccumBounds(min, max).intersection(FiniteSet(S.Pi*Rational(3, 2), S.Pi*Rational(8, 2))) \ is not S.EmptySet: return AccumBounds(-1, Max(sin(min), sin(max))) else: return AccumBounds(Min(sin(min), sin(max)), Max(sin(min), sin(max))) elif isinstance(arg, SetExpr): return arg._eval_func(cls) if arg.could_extract_minus_sign(): return -cls(-arg) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit*sinh(i_coeff) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_integer: return S.Zero if (2*pi_coeff).is_integer: # is_even-case handled above as then pi_coeff.is_integer, # so check if known to be not even if pi_coeff.is_even is False: return S.NegativeOne**(pi_coeff - S.Half) if not pi_coeff.is_Rational: narg = pi_coeff*S.Pi if narg != arg: return cls(narg) return None # https://github.com/sympy/sympy/issues/6048 # transform a sine to a cosine, to avoid redundant code if pi_coeff.is_Rational: x = pi_coeff % 2 if x > 1: return -cls((x % 1)*S.Pi) if 2*x > 1: return cls((1 - x)*S.Pi) narg = ((pi_coeff + Rational(3, 2)) % 2)*S.Pi result = cos(narg) if not isinstance(result, cos): return result if pi_coeff*S.Pi != arg: return cls(pi_coeff*S.Pi) return None if arg.is_Add: x, m = _peeloff_pi(arg) if m: return sin(m)*cos(x) + cos(m)*sin(x) if arg.is_zero: return S.Zero if isinstance(arg, asin): return arg.args[0] if isinstance(arg, atan): x = arg.args[0] return x/sqrt(1 + x**2) if isinstance(arg, atan2): y, x = arg.args return y/sqrt(x**2 + y**2) if isinstance(arg, acos): x = arg.args[0] return sqrt(1 - x**2) if isinstance(arg, acot): x = arg.args[0] return 1/(sqrt(1 + 1/x**2)*x) if isinstance(arg, acsc): x = arg.args[0] return 1/x if isinstance(arg, asec): x = arg.args[0] return sqrt(1 - 1/x**2) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) > 2: p = previous_terms[-2] return -p*x**2/(n*(n - 1)) else: return (-1)**(n//2)*x**(n)/factorial(n) def _eval_nseries(self, x, n, logx, cdir=0): arg = self.args[0] if logx is not None: arg = arg.subs(log(x), logx) if arg.subs(x, 0).has(S.NaN, S.ComplexInfinity): raise PoleError("Cannot expand %s around 0" % (self)) return Function._eval_nseries(self, x, n=n, logx=logx, cdir=cdir) def _eval_rewrite_as_exp(self, arg, **kwargs): I = S.ImaginaryUnit if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) return (exp(arg*I) - exp(-arg*I))/(2*I) def _eval_rewrite_as_Pow(self, arg, **kwargs): if isinstance(arg, log): I = S.ImaginaryUnit x = arg.args[0] return I*x**-I/2 - I*x**I /2 def _eval_rewrite_as_cos(self, arg, **kwargs): return cos(arg - S.Pi/2, evaluate=False) def _eval_rewrite_as_tan(self, arg, **kwargs): tan_half = tan(S.Half*arg) return 2*tan_half/(1 + tan_half**2) def _eval_rewrite_as_sincos(self, arg, **kwargs): return sin(arg)*cos(arg)/cos(arg) def _eval_rewrite_as_cot(self, arg, **kwargs): cot_half = cot(S.Half*arg) return 2*cot_half/(1 + cot_half**2) def _eval_rewrite_as_pow(self, arg, **kwargs): return self.rewrite(cos).rewrite(pow) def _eval_rewrite_as_sqrt(self, arg, **kwargs): return self.rewrite(cos).rewrite(sqrt) def _eval_rewrite_as_csc(self, arg, **kwargs): return 1/csc(arg) def _eval_rewrite_as_sec(self, arg, **kwargs): return 1/sec(arg - S.Pi/2, evaluate=False) def _eval_rewrite_as_sinc(self, arg, **kwargs): return arg*sinc(arg) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): re, im = self._as_real_imag(deep=deep, **hints) return (sin(re)*cosh(im), cos(re)*sinh(im)) def _eval_expand_trig(self, **hints): from sympy import expand_mul from sympy.functions.special.polynomials import chebyshevt, chebyshevu arg = self.args[0] x = None if arg.is_Add: # TODO, implement more if deep stuff here # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() sy = sin(y, evaluate=False)._eval_expand_trig() cx = cos(x, evaluate=False)._eval_expand_trig() cy = cos(y, evaluate=False)._eval_expand_trig() return sx*cy + sy*cx elif arg.is_Mul: n, x = arg.as_coeff_Mul(rational=True) if n.is_Integer: # n will be positive because of .eval # canonicalization # See http://mathworld.wolfram.com/Multiple-AngleFormulas.html if n.is_odd: return (-1)**((n - 1)/2)*chebyshevt(n, sin(x)) else: return expand_mul((-1)**(n/2 - 1)*cos(x)*chebyshevu(n - 1, sin(x)), deep=False) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_Rational: return self.rewrite(sqrt) return sin(arg) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import re from sympy.calculus.util import AccumBounds arg = self.args[0] x0 = arg.subs(x, 0).cancel() n = x0/S.Pi if n.is_integer: lt = (arg - n*S.Pi).as_leading_term(x) return ((-1)**n)*lt if x0 is S.ComplexInfinity: x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if x0 in [S.Infinity, S.NegativeInfinity]: return AccumBounds(-1, 1) return self.func(x0) if x0.is_finite else self def _eval_is_extended_real(self): if self.args[0].is_extended_real: return True def _eval_is_finite(self): arg = self.args[0] if arg.is_extended_real: return True def _eval_is_zero(self): arg = self.args[0] if arg.is_zero: return True def _eval_is_complex(self): if self.args[0].is_extended_real \ or self.args[0].is_complex: return True class cos(TrigonometricFunction): """ The cosine function. Returns the cosine of x (measured in radians). Explanation =========== See :func:`sin` for notes about automatic evaluation. Examples ======== >>> from sympy import cos, pi >>> from sympy.abc import x >>> cos(x**2).diff(x) -2*x*sin(x**2) >>> cos(1).diff(x) 0 >>> cos(pi) -1 >>> cos(pi/2) 0 >>> cos(2*pi/3) -1/2 >>> cos(pi/12) sqrt(2)/4 + sqrt(6)/4 See Also ======== sin, csc, sec, tan, cot asin, acsc, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions .. [2] http://dlmf.nist.gov/4.14 .. [3] http://functions.wolfram.com/ElementaryFunctions/Cos """ def period(self, symbol=None): return self._period(2*pi, symbol) def fdiff(self, argindex=1): if argindex == 1: return -sin(self.args[0]) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): from sympy.functions.special.polynomials import chebyshevt from sympy.calculus.util import AccumBounds from sympy.sets.setexpr import SetExpr if arg.is_Number: if arg is S.NaN: return S.NaN elif arg.is_zero: return S.One elif arg is S.Infinity or arg is S.NegativeInfinity: # In this case it is better to return AccumBounds(-1, 1) # rather than returning S.NaN, since AccumBounds(-1, 1) # preserves the information that sin(oo) is between # -1 and 1, where S.NaN does not do that. return AccumBounds(-1, 1) if arg is S.ComplexInfinity: return S.NaN if isinstance(arg, AccumBounds): return sin(arg + S.Pi/2) elif isinstance(arg, SetExpr): return arg._eval_func(cls) if arg.is_extended_real and arg.is_finite is False: return AccumBounds(-1, 1) if arg.could_extract_minus_sign(): return cls(-arg) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return cosh(i_coeff) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_integer: return (S.NegativeOne)**pi_coeff if (2*pi_coeff).is_integer: # is_even-case handled above as then pi_coeff.is_integer, # so check if known to be not even if pi_coeff.is_even is False: return S.Zero if not pi_coeff.is_Rational: narg = pi_coeff*S.Pi if narg != arg: return cls(narg) return None # cosine formula ##################### # https://github.com/sympy/sympy/issues/6048 # explicit calculations are performed for # cos(k pi/n) for n = 8,10,12,15,20,24,30,40,60,120 # Some other exact values like cos(k pi/240) can be # calculated using a partial-fraction decomposition # by calling cos( X ).rewrite(sqrt) cst_table_some = { 3: S.Half, 5: (sqrt(5) + 1)/4, } if pi_coeff.is_Rational: q = pi_coeff.q p = pi_coeff.p % (2*q) if p > q: narg = (pi_coeff - 1)*S.Pi return -cls(narg) if 2*p > q: narg = (1 - pi_coeff)*S.Pi return -cls(narg) # If nested sqrt's are worse than un-evaluation # you can require q to be in (1, 2, 3, 4, 6, 12) # q <= 12, q=15, q=20, q=24, q=30, q=40, q=60, q=120 return # expressions with 2 or fewer sqrt nestings. table2 = { 12: (3, 4), 20: (4, 5), 30: (5, 6), 15: (6, 10), 24: (6, 8), 40: (8, 10), 60: (20, 30), 120: (40, 60) } if q in table2: a, b = p*S.Pi/table2[q][0], p*S.Pi/table2[q][1] nvala, nvalb = cls(a), cls(b) if None == nvala or None == nvalb: return None return nvala*nvalb + cls(S.Pi/2 - a)*cls(S.Pi/2 - b) if q > 12: return None if q in cst_table_some: cts = cst_table_some[pi_coeff.q] return chebyshevt(pi_coeff.p, cts).expand() if 0 == q % 2: narg = (pi_coeff*2)*S.Pi nval = cls(narg) if None == nval: return None x = (2*pi_coeff + 1)/2 sign_cos = (-1)**((-1 if x < 0 else 1)*int(abs(x))) return sign_cos*sqrt( (1 + nval)/2 ) return None if arg.is_Add: x, m = _peeloff_pi(arg) if m: return cos(m)*cos(x) - sin(m)*sin(x) if arg.is_zero: return S.One if isinstance(arg, acos): return arg.args[0] if isinstance(arg, atan): x = arg.args[0] return 1/sqrt(1 + x**2) if isinstance(arg, atan2): y, x = arg.args return x/sqrt(x**2 + y**2) if isinstance(arg, asin): x = arg.args[0] return sqrt(1 - x ** 2) if isinstance(arg, acot): x = arg.args[0] return 1/sqrt(1 + 1/x**2) if isinstance(arg, acsc): x = arg.args[0] return sqrt(1 - 1/x**2) if isinstance(arg, asec): x = arg.args[0] return 1/x @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 1: return S.Zero else: x = sympify(x) if len(previous_terms) > 2: p = previous_terms[-2] return -p*x**2/(n*(n - 1)) else: return (-1)**(n//2)*x**(n)/factorial(n) def _eval_nseries(self, x, n, logx, cdir=0): arg = self.args[0] if logx is not None: arg = arg.subs(log(x), logx) if arg.subs(x, 0).has(S.NaN, S.ComplexInfinity): raise PoleError("Cannot expand %s around 0" % (self)) return Function._eval_nseries(self, x, n=n, logx=logx, cdir=cdir) def _eval_rewrite_as_exp(self, arg, **kwargs): I = S.ImaginaryUnit if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) return (exp(arg*I) + exp(-arg*I))/2 def _eval_rewrite_as_Pow(self, arg, **kwargs): if isinstance(arg, log): I = S.ImaginaryUnit x = arg.args[0] return x**I/2 + x**-I/2 def _eval_rewrite_as_sin(self, arg, **kwargs): return sin(arg + S.Pi/2, evaluate=False) def _eval_rewrite_as_tan(self, arg, **kwargs): tan_half = tan(S.Half*arg)**2 return (1 - tan_half)/(1 + tan_half) def _eval_rewrite_as_sincos(self, arg, **kwargs): return sin(arg)*cos(arg)/sin(arg) def _eval_rewrite_as_cot(self, arg, **kwargs): cot_half = cot(S.Half*arg)**2 return (cot_half - 1)/(cot_half + 1) def _eval_rewrite_as_pow(self, arg, **kwargs): return self._eval_rewrite_as_sqrt(arg) def _eval_rewrite_as_sqrt(self, arg, **kwargs): from sympy.functions.special.polynomials import chebyshevt def migcdex(x): # recursive calcuation of gcd and linear combination # for a sequence of integers. # Given (x1, x2, x3) # Returns (y1, y1, y3, g) # such that g is the gcd and x1*y1+x2*y2+x3*y3 - g = 0 # Note, that this is only one such linear combination. if len(x) == 1: return (1, x[0]) if len(x) == 2: return igcdex(x[0], x[-1]) g = migcdex(x[1:]) u, v, h = igcdex(x[0], g[-1]) return tuple([u] + [v*i for i in g[0:-1] ] + [h]) def ipartfrac(r, factors=None): from sympy.ntheory import factorint if isinstance(r, int): return r if not isinstance(r, Rational): raise TypeError("r is not rational") n = r.q if 2 > r.q*r.q: return r.q if None == factors: a = [n//x**y for x, y in factorint(r.q).items()] else: a = [n//x for x in factors] if len(a) == 1: return [ r ] h = migcdex(a) ans = [ r.p*Rational(i*j, r.q) for i, j in zip(h[:-1], a) ] assert r == sum(ans) return ans pi_coeff = _pi_coeff(arg) if pi_coeff is None: return None if pi_coeff.is_integer: # it was unevaluated return self.func(pi_coeff*S.Pi) if not pi_coeff.is_Rational: return None def _cospi257(): """ Express cos(pi/257) explicitly as a function of radicals Based upon the equations in http://math.stackexchange.com/questions/516142/how-does-cos2-pi-257-look-like-in-real-radicals See also http://www.susqu.edu/brakke/constructions/257-gon.m.txt """ def f1(a, b): return (a + sqrt(a**2 + b))/2, (a - sqrt(a**2 + b))/2 def f2(a, b): return (a - sqrt(a**2 + b))/2 t1, t2 = f1(-1, 256) z1, z3 = f1(t1, 64) z2, z4 = f1(t2, 64) y1, y5 = f1(z1, 4*(5 + t1 + 2*z1)) y6, y2 = f1(z2, 4*(5 + t2 + 2*z2)) y3, y7 = f1(z3, 4*(5 + t1 + 2*z3)) y8, y4 = f1(z4, 4*(5 + t2 + 2*z4)) x1, x9 = f1(y1, -4*(t1 + y1 + y3 + 2*y6)) x2, x10 = f1(y2, -4*(t2 + y2 + y4 + 2*y7)) x3, x11 = f1(y3, -4*(t1 + y3 + y5 + 2*y8)) x4, x12 = f1(y4, -4*(t2 + y4 + y6 + 2*y1)) x5, x13 = f1(y5, -4*(t1 + y5 + y7 + 2*y2)) x6, x14 = f1(y6, -4*(t2 + y6 + y8 + 2*y3)) x15, x7 = f1(y7, -4*(t1 + y7 + y1 + 2*y4)) x8, x16 = f1(y8, -4*(t2 + y8 + y2 + 2*y5)) v1 = f2(x1, -4*(x1 + x2 + x3 + x6)) v2 = f2(x2, -4*(x2 + x3 + x4 + x7)) v3 = f2(x8, -4*(x8 + x9 + x10 + x13)) v4 = f2(x9, -4*(x9 + x10 + x11 + x14)) v5 = f2(x10, -4*(x10 + x11 + x12 + x15)) v6 = f2(x16, -4*(x16 + x1 + x2 + x5)) u1 = -f2(-v1, -4*(v2 + v3)) u2 = -f2(-v4, -4*(v5 + v6)) w1 = -2*f2(-u1, -4*u2) return sqrt(sqrt(2)*sqrt(w1 + 4)/8 + S.Half) cst_table_some = { 3: S.Half, 5: (sqrt(5) + 1)/4, 17: sqrt((15 + sqrt(17))/32 + sqrt(2)*(sqrt(17 - sqrt(17)) + sqrt(sqrt(2)*(-8*sqrt(17 + sqrt(17)) - (1 - sqrt(17)) *sqrt(17 - sqrt(17))) + 6*sqrt(17) + 34))/32), 257: _cospi257() # 65537 is the only other known Fermat prime and the very # large expression is intentionally omitted from SymPy; see # http://www.susqu.edu/brakke/constructions/65537-gon.m.txt } def _fermatCoords(n): # if n can be factored in terms of Fermat primes with # multiplicity of each being 1, return those primes, else # False primes = [] for p_i in cst_table_some: quotient, remainder = divmod(n, p_i) if remainder == 0: n = quotient primes.append(p_i) if n == 1: return tuple(primes) return False if pi_coeff.q in cst_table_some: rv = chebyshevt(pi_coeff.p, cst_table_some[pi_coeff.q]) if pi_coeff.q < 257: rv = rv.expand() return rv if not pi_coeff.q % 2: # recursively remove factors of 2 pico2 = pi_coeff*2 nval = cos(pico2*S.Pi).rewrite(sqrt) x = (pico2 + 1)/2 sign_cos = -1 if int(x) % 2 else 1 return sign_cos*sqrt( (1 + nval)/2 ) FC = _fermatCoords(pi_coeff.q) if FC: decomp = ipartfrac(pi_coeff, FC) X = [(x[1], x[0]*S.Pi) for x in zip(decomp, numbered_symbols('z'))] pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) return pcls.rewrite(sqrt) else: decomp = ipartfrac(pi_coeff) X = [(x[1], x[0]*S.Pi) for x in zip(decomp, numbered_symbols('z'))] pcls = cos(sum([x[0] for x in X]))._eval_expand_trig().subs(X) return pcls def _eval_rewrite_as_sec(self, arg, **kwargs): return 1/sec(arg) def _eval_rewrite_as_csc(self, arg, **kwargs): return 1/sec(arg).rewrite(csc) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): re, im = self._as_real_imag(deep=deep, **hints) return (cos(re)*cosh(im), -sin(re)*sinh(im)) def _eval_expand_trig(self, **hints): from sympy.functions.special.polynomials import chebyshevt arg = self.args[0] x = None if arg.is_Add: # TODO: Do this more efficiently for more than two terms x, y = arg.as_two_terms() sx = sin(x, evaluate=False)._eval_expand_trig() sy = sin(y, evaluate=False)._eval_expand_trig() cx = cos(x, evaluate=False)._eval_expand_trig() cy = cos(y, evaluate=False)._eval_expand_trig() return cx*cy - sx*sy elif arg.is_Mul: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer: return chebyshevt(coeff, cos(terms)) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_Rational: return self.rewrite(sqrt) return cos(arg) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import re from sympy.calculus.util import AccumBounds arg = self.args[0] x0 = arg.subs(x, 0).cancel() n = (x0 + S.Pi/2)/S.Pi if n.is_integer: lt = (arg - n*S.Pi + S.Pi/2).as_leading_term(x) return ((-1)**n)*lt if x0 is S.ComplexInfinity: x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if x0 in [S.Infinity, S.NegativeInfinity]: return AccumBounds(-1, 1) return self.func(x0) if x0.is_finite else self def _eval_is_extended_real(self): if self.args[0].is_extended_real: return True def _eval_is_finite(self): arg = self.args[0] if arg.is_extended_real: return True def _eval_is_complex(self): if self.args[0].is_extended_real \ or self.args[0].is_complex: return True class tan(TrigonometricFunction): """ The tangent function. Returns the tangent of x (measured in radians). Explanation =========== See :func:`sin` for notes about automatic evaluation. Examples ======== >>> from sympy import tan, pi >>> from sympy.abc import x >>> tan(x**2).diff(x) 2*x*(tan(x**2)**2 + 1) >>> tan(1).diff(x) 0 >>> tan(pi/8).expand() -1 + sqrt(2) See Also ======== sin, csc, cos, sec, cot asin, acsc, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions .. [2] http://dlmf.nist.gov/4.14 .. [3] http://functions.wolfram.com/ElementaryFunctions/Tan """ def period(self, symbol=None): return self._period(pi, symbol) def fdiff(self, argindex=1): if argindex == 1: return S.One + self**2 else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return atan @classmethod def eval(cls, arg): from sympy.calculus.util import AccumBounds if arg.is_Number: if arg is S.NaN: return S.NaN elif arg.is_zero: return S.Zero elif arg is S.Infinity or arg is S.NegativeInfinity: return AccumBounds(S.NegativeInfinity, S.Infinity) if arg is S.ComplexInfinity: return S.NaN if isinstance(arg, AccumBounds): min, max = arg.min, arg.max d = floor(min/S.Pi) if min is not S.NegativeInfinity: min = min - d*S.Pi if max is not S.Infinity: max = max - d*S.Pi if AccumBounds(min, max).intersection(FiniteSet(S.Pi/2, S.Pi*Rational(3, 2))): return AccumBounds(S.NegativeInfinity, S.Infinity) else: return AccumBounds(tan(min), tan(max)) if arg.could_extract_minus_sign(): return -cls(-arg) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit*tanh(i_coeff) pi_coeff = _pi_coeff(arg, 2) if pi_coeff is not None: if pi_coeff.is_integer: return S.Zero if not pi_coeff.is_Rational: narg = pi_coeff*S.Pi if narg != arg: return cls(narg) return None if pi_coeff.is_Rational: q = pi_coeff.q p = pi_coeff.p % q # ensure simplified results are returned for n*pi/5, n*pi/10 table10 = { 1: sqrt(1 - 2*sqrt(5)/5), 2: sqrt(5 - 2*sqrt(5)), 3: sqrt(1 + 2*sqrt(5)/5), 4: sqrt(5 + 2*sqrt(5)) } if q == 5 or q == 10: n = 10*p/q if n > 5: n = 10 - n return -table10[n] else: return table10[n] if not pi_coeff.q % 2: narg = pi_coeff*S.Pi*2 cresult, sresult = cos(narg), cos(narg - S.Pi/2) if not isinstance(cresult, cos) \ and not isinstance(sresult, cos): if sresult == 0: return S.ComplexInfinity return 1/sresult - cresult/sresult table2 = { 12: (3, 4), 20: (4, 5), 30: (5, 6), 15: (6, 10), 24: (6, 8), 40: (8, 10), 60: (20, 30), 120: (40, 60) } if q in table2: nvala, nvalb = cls(p*S.Pi/table2[q][0]), cls(p*S.Pi/table2[q][1]) if None == nvala or None == nvalb: return None return (nvala - nvalb)/(1 + nvala*nvalb) narg = ((pi_coeff + S.Half) % 1 - S.Half)*S.Pi # see cos() to specify which expressions should be # expanded automatically in terms of radicals cresult, sresult = cos(narg), cos(narg - S.Pi/2) if not isinstance(cresult, cos) \ and not isinstance(sresult, cos): if cresult == 0: return S.ComplexInfinity return (sresult/cresult) if narg != arg: return cls(narg) if arg.is_Add: x, m = _peeloff_pi(arg) if m: tanm = tan(m) if tanm is S.ComplexInfinity: return -cot(x) else: # tanm == 0 return tan(x) if arg.is_zero: return S.Zero if isinstance(arg, atan): return arg.args[0] if isinstance(arg, atan2): y, x = arg.args return y/x if isinstance(arg, asin): x = arg.args[0] return x/sqrt(1 - x**2) if isinstance(arg, acos): x = arg.args[0] return sqrt(1 - x**2)/x if isinstance(arg, acot): x = arg.args[0] return 1/x if isinstance(arg, acsc): x = arg.args[0] return 1/(sqrt(1 - 1/x**2)*x) if isinstance(arg, asec): x = arg.args[0] return sqrt(1 - 1/x**2)*x @staticmethod @cacheit def taylor_term(n, x, *previous_terms): from sympy import bernoulli if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) a, b = ((n - 1)//2), 2**(n + 1) B = bernoulli(n + 1) F = factorial(n + 1) return (-1)**a*b*(b - 1)*B/F*x**n def _eval_nseries(self, x, n, logx, cdir=0): i = self.args[0].limit(x, 0)*2/S.Pi if i and i.is_Integer: return self.rewrite(cos)._eval_nseries(x, n=n, logx=logx) return Function._eval_nseries(self, x, n=n, logx=logx) def _eval_rewrite_as_Pow(self, arg, **kwargs): if isinstance(arg, log): I = S.ImaginaryUnit x = arg.args[0] return I*(x**-I - x**I)/(x**-I + x**I) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): re, im = self._as_real_imag(deep=deep, **hints) if im: denom = cos(2*re) + cosh(2*im) return (sin(2*re)/denom, sinh(2*im)/denom) else: return (self.func(re), S.Zero) def _eval_expand_trig(self, **hints): from sympy import im, re arg = self.args[0] x = None if arg.is_Add: from sympy import symmetric_poly n = len(arg.args) TX = [] for x in arg.args: tx = tan(x, evaluate=False)._eval_expand_trig() TX.append(tx) Yg = numbered_symbols('Y') Y = [ next(Yg) for i in range(n) ] p = [0, 0] for i in range(n + 1): p[1 - i % 2] += symmetric_poly(i, Y)*(-1)**((i % 4)//2) return (p[0]/p[1]).subs(list(zip(Y, TX))) elif arg.is_Mul: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer and coeff > 1: I = S.ImaginaryUnit z = Symbol('dummy', real=True) P = ((1 + I*z)**coeff).expand() return (im(P)/re(P)).subs([(z, tan(terms))]) return tan(arg) def _eval_rewrite_as_exp(self, arg, **kwargs): I = S.ImaginaryUnit if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) neg_exp, pos_exp = exp(-arg*I), exp(arg*I) return I*(neg_exp - pos_exp)/(neg_exp + pos_exp) def _eval_rewrite_as_sin(self, x, **kwargs): return 2*sin(x)**2/sin(2*x) def _eval_rewrite_as_cos(self, x, **kwargs): return cos(x - S.Pi/2, evaluate=False)/cos(x) def _eval_rewrite_as_sincos(self, arg, **kwargs): return sin(arg)/cos(arg) def _eval_rewrite_as_cot(self, arg, **kwargs): return 1/cot(arg) def _eval_rewrite_as_sec(self, arg, **kwargs): sin_in_sec_form = sin(arg).rewrite(sec) cos_in_sec_form = cos(arg).rewrite(sec) return sin_in_sec_form/cos_in_sec_form def _eval_rewrite_as_csc(self, arg, **kwargs): sin_in_csc_form = sin(arg).rewrite(csc) cos_in_csc_form = cos(arg).rewrite(csc) return sin_in_csc_form/cos_in_csc_form def _eval_rewrite_as_pow(self, arg, **kwargs): y = self.rewrite(cos).rewrite(pow) if y.has(cos): return None return y def _eval_rewrite_as_sqrt(self, arg, **kwargs): y = self.rewrite(cos).rewrite(sqrt) if y.has(cos): return None return y def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0] x0 = arg.subs(x, 0).cancel() n = 2*x0/S.Pi if n.is_integer: lt = (arg - n*S.Pi/2).as_leading_term(x) return lt if n.is_even else -1/lt return self.func(x0) if x0.is_finite else self def _eval_is_extended_real(self): # FIXME: currently tan(pi/2) return zoo return self.args[0].is_extended_real def _eval_is_real(self): arg = self.args[0] if arg.is_real and (arg/pi - S.Half).is_integer is False: return True def _eval_is_finite(self): arg = self.args[0] if arg.is_real and (arg/pi - S.Half).is_integer is False: return True if arg.is_imaginary: return True def _eval_is_zero(self): arg = self.args[0] if arg.is_zero: return True def _eval_is_complex(self): arg = self.args[0] if arg.is_real and (arg/pi - S.Half).is_integer is False: return True class cot(TrigonometricFunction): """ The cotangent function. Returns the cotangent of x (measured in radians). Explanation =========== See :func:`sin` for notes about automatic evaluation. Examples ======== >>> from sympy import cot, pi >>> from sympy.abc import x >>> cot(x**2).diff(x) 2*x*(-cot(x**2)**2 - 1) >>> cot(1).diff(x) 0 >>> cot(pi/12) sqrt(3) + 2 See Also ======== sin, csc, cos, sec, tan asin, acsc, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions .. [2] http://dlmf.nist.gov/4.14 .. [3] http://functions.wolfram.com/ElementaryFunctions/Cot """ def period(self, symbol=None): return self._period(pi, symbol) def fdiff(self, argindex=1): if argindex == 1: return S.NegativeOne - self**2 else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return acot @classmethod def eval(cls, arg): from sympy.calculus.util import AccumBounds if arg.is_Number: if arg is S.NaN: return S.NaN if arg.is_zero: return S.ComplexInfinity if arg is S.ComplexInfinity: return S.NaN if isinstance(arg, AccumBounds): return -tan(arg + S.Pi/2) if arg.could_extract_minus_sign(): return -cls(-arg) i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return -S.ImaginaryUnit*coth(i_coeff) pi_coeff = _pi_coeff(arg, 2) if pi_coeff is not None: if pi_coeff.is_integer: return S.ComplexInfinity if not pi_coeff.is_Rational: narg = pi_coeff*S.Pi if narg != arg: return cls(narg) return None if pi_coeff.is_Rational: if pi_coeff.q == 5 or pi_coeff.q == 10: return tan(S.Pi/2 - arg) if pi_coeff.q > 2 and not pi_coeff.q % 2: narg = pi_coeff*S.Pi*2 cresult, sresult = cos(narg), cos(narg - S.Pi/2) if not isinstance(cresult, cos) \ and not isinstance(sresult, cos): return 1/sresult + cresult/sresult table2 = { 12: (3, 4), 20: (4, 5), 30: (5, 6), 15: (6, 10), 24: (6, 8), 40: (8, 10), 60: (20, 30), 120: (40, 60) } q = pi_coeff.q p = pi_coeff.p % q if q in table2: nvala, nvalb = cls(p*S.Pi/table2[q][0]), cls(p*S.Pi/table2[q][1]) if None == nvala or None == nvalb: return None return (1 + nvala*nvalb)/(nvalb - nvala) narg = (((pi_coeff + S.Half) % 1) - S.Half)*S.Pi # see cos() to specify which expressions should be # expanded automatically in terms of radicals cresult, sresult = cos(narg), cos(narg - S.Pi/2) if not isinstance(cresult, cos) \ and not isinstance(sresult, cos): if sresult == 0: return S.ComplexInfinity return cresult/sresult if narg != arg: return cls(narg) if arg.is_Add: x, m = _peeloff_pi(arg) if m: cotm = cot(m) if cotm is S.ComplexInfinity: return cot(x) else: # cotm == 0 return -tan(x) if arg.is_zero: return S.ComplexInfinity if isinstance(arg, acot): return arg.args[0] if isinstance(arg, atan): x = arg.args[0] return 1/x if isinstance(arg, atan2): y, x = arg.args return x/y if isinstance(arg, asin): x = arg.args[0] return sqrt(1 - x**2)/x if isinstance(arg, acos): x = arg.args[0] return x/sqrt(1 - x**2) if isinstance(arg, acsc): x = arg.args[0] return sqrt(1 - 1/x**2)*x if isinstance(arg, asec): x = arg.args[0] return 1/(sqrt(1 - 1/x**2)*x) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): from sympy import bernoulli if n == 0: return 1/sympify(x) elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) B = bernoulli(n + 1) F = factorial(n + 1) return (-1)**((n + 1)//2)*2**(n + 1)*B/F*x**n def _eval_nseries(self, x, n, logx, cdir=0): i = self.args[0].limit(x, 0)/S.Pi if i and i.is_Integer: return self.rewrite(cos)._eval_nseries(x, n=n, logx=logx) return self.rewrite(tan)._eval_nseries(x, n=n, logx=logx) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): re, im = self._as_real_imag(deep=deep, **hints) if im: denom = cos(2*re) - cosh(2*im) return (-sin(2*re)/denom, sinh(2*im)/denom) else: return (self.func(re), S.Zero) def _eval_rewrite_as_exp(self, arg, **kwargs): I = S.ImaginaryUnit if isinstance(arg, TrigonometricFunction) or isinstance(arg, HyperbolicFunction): arg = arg.func(arg.args[0]).rewrite(exp) neg_exp, pos_exp = exp(-arg*I), exp(arg*I) return I*(pos_exp + neg_exp)/(pos_exp - neg_exp) def _eval_rewrite_as_Pow(self, arg, **kwargs): if isinstance(arg, log): I = S.ImaginaryUnit x = arg.args[0] return -I*(x**-I + x**I)/(x**-I - x**I) def _eval_rewrite_as_sin(self, x, **kwargs): return sin(2*x)/(2*(sin(x)**2)) def _eval_rewrite_as_cos(self, x, **kwargs): return cos(x)/cos(x - S.Pi/2, evaluate=False) def _eval_rewrite_as_sincos(self, arg, **kwargs): return cos(arg)/sin(arg) def _eval_rewrite_as_tan(self, arg, **kwargs): return 1/tan(arg) def _eval_rewrite_as_sec(self, arg, **kwargs): cos_in_sec_form = cos(arg).rewrite(sec) sin_in_sec_form = sin(arg).rewrite(sec) return cos_in_sec_form/sin_in_sec_form def _eval_rewrite_as_csc(self, arg, **kwargs): cos_in_csc_form = cos(arg).rewrite(csc) sin_in_csc_form = sin(arg).rewrite(csc) return cos_in_csc_form/sin_in_csc_form def _eval_rewrite_as_pow(self, arg, **kwargs): y = self.rewrite(cos).rewrite(pow) if y.has(cos): return None return y def _eval_rewrite_as_sqrt(self, arg, **kwargs): y = self.rewrite(cos).rewrite(sqrt) if y.has(cos): return None return y def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0] x0 = arg.subs(x, 0).cancel() n = 2*x0/S.Pi if n.is_integer: lt = (arg - n*S.Pi/2).as_leading_term(x) return 1/lt if n.is_even else -lt return self.func(x0) if x0.is_finite else self def _eval_is_extended_real(self): return self.args[0].is_extended_real def _eval_expand_trig(self, **hints): from sympy import im, re arg = self.args[0] x = None if arg.is_Add: from sympy import symmetric_poly n = len(arg.args) CX = [] for x in arg.args: cx = cot(x, evaluate=False)._eval_expand_trig() CX.append(cx) Yg = numbered_symbols('Y') Y = [ next(Yg) for i in range(n) ] p = [0, 0] for i in range(n, -1, -1): p[(n - i) % 2] += symmetric_poly(i, Y)*(-1)**(((n - i) % 4)//2) return (p[0]/p[1]).subs(list(zip(Y, CX))) elif arg.is_Mul: coeff, terms = arg.as_coeff_Mul(rational=True) if coeff.is_Integer and coeff > 1: I = S.ImaginaryUnit z = Symbol('dummy', real=True) P = ((z + I)**coeff).expand() return (re(P)/im(P)).subs([(z, cot(terms))]) return cot(arg) # XXX sec and csc return 1/cos and 1/sin def _eval_is_finite(self): arg = self.args[0] if arg.is_real and (arg/pi).is_integer is False: return True if arg.is_imaginary: return True def _eval_is_real(self): arg = self.args[0] if arg.is_real and (arg/pi).is_integer is False: return True def _eval_is_complex(self): arg = self.args[0] if arg.is_real and (arg/pi).is_integer is False: return True def _eval_subs(self, old, new): arg = self.args[0] argnew = arg.subs(old, new) if arg != argnew and (argnew/S.Pi).is_integer: return S.ComplexInfinity return cot(argnew) class ReciprocalTrigonometricFunction(TrigonometricFunction): """Base class for reciprocal functions of trigonometric functions. """ _reciprocal_of = None # mandatory, to be defined in subclass _singularities = (S.ComplexInfinity,) # _is_even and _is_odd are used for correct evaluation of csc(-x), sec(-x) # TODO refactor into TrigonometricFunction common parts of # trigonometric functions eval() like even/odd, func(x+2*k*pi), etc. # optional, to be defined in subclasses: _is_even = None # type: FuzzyBool _is_odd = None # type: FuzzyBool @classmethod def eval(cls, arg): if arg.could_extract_minus_sign(): if cls._is_even: return cls(-arg) if cls._is_odd: return -cls(-arg) pi_coeff = _pi_coeff(arg) if (pi_coeff is not None and not (2*pi_coeff).is_integer and pi_coeff.is_Rational): q = pi_coeff.q p = pi_coeff.p % (2*q) if p > q: narg = (pi_coeff - 1)*S.Pi return -cls(narg) if 2*p > q: narg = (1 - pi_coeff)*S.Pi if cls._is_odd: return cls(narg) elif cls._is_even: return -cls(narg) if hasattr(arg, 'inverse') and arg.inverse() == cls: return arg.args[0] t = cls._reciprocal_of.eval(arg) if t is None: return t elif any(isinstance(i, cos) for i in (t, -t)): return (1/t).rewrite(sec) elif any(isinstance(i, sin) for i in (t, -t)): return (1/t).rewrite(csc) else: return 1/t def _call_reciprocal(self, method_name, *args, **kwargs): # Calls method_name on _reciprocal_of o = self._reciprocal_of(self.args[0]) return getattr(o, method_name)(*args, **kwargs) def _calculate_reciprocal(self, method_name, *args, **kwargs): # If calling method_name on _reciprocal_of returns a value != None # then return the reciprocal of that value t = self._call_reciprocal(method_name, *args, **kwargs) return 1/t if t is not None else t def _rewrite_reciprocal(self, method_name, arg): # Special handling for rewrite functions. If reciprocal rewrite returns # unmodified expression, then return None t = self._call_reciprocal(method_name, arg) if t is not None and t != self._reciprocal_of(arg): return 1/t def _period(self, symbol): f = expand_mul(self.args[0]) return self._reciprocal_of(f).period(symbol) def fdiff(self, argindex=1): return -self._calculate_reciprocal("fdiff", argindex)/self**2 def _eval_rewrite_as_exp(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_exp", arg) def _eval_rewrite_as_Pow(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_Pow", arg) def _eval_rewrite_as_sin(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_sin", arg) def _eval_rewrite_as_cos(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_cos", arg) def _eval_rewrite_as_tan(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_tan", arg) def _eval_rewrite_as_pow(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_pow", arg) def _eval_rewrite_as_sqrt(self, arg, **kwargs): return self._rewrite_reciprocal("_eval_rewrite_as_sqrt", arg) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def as_real_imag(self, deep=True, **hints): return (1/self._reciprocal_of(self.args[0])).as_real_imag(deep, **hints) def _eval_expand_trig(self, **hints): return self._calculate_reciprocal("_eval_expand_trig", **hints) def _eval_is_extended_real(self): return self._reciprocal_of(self.args[0])._eval_is_extended_real() def _eval_as_leading_term(self, x, logx=None, cdir=0): return (1/self._reciprocal_of(self.args[0]))._eval_as_leading_term(x) def _eval_is_finite(self): return (1/self._reciprocal_of(self.args[0])).is_finite def _eval_nseries(self, x, n, logx, cdir=0): return (1/self._reciprocal_of(self.args[0]))._eval_nseries(x, n, logx) class sec(ReciprocalTrigonometricFunction): """ The secant function. Returns the secant of x (measured in radians). Explanation =========== See :func:`sin` for notes about automatic evaluation. Examples ======== >>> from sympy import sec >>> from sympy.abc import x >>> sec(x**2).diff(x) 2*x*tan(x**2)*sec(x**2) >>> sec(1).diff(x) 0 See Also ======== sin, csc, cos, tan, cot asin, acsc, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions .. [2] http://dlmf.nist.gov/4.14 .. [3] http://functions.wolfram.com/ElementaryFunctions/Sec """ _reciprocal_of = cos _is_even = True def period(self, symbol=None): return self._period(symbol) def _eval_rewrite_as_cot(self, arg, **kwargs): cot_half_sq = cot(arg/2)**2 return (cot_half_sq + 1)/(cot_half_sq - 1) def _eval_rewrite_as_cos(self, arg, **kwargs): return (1/cos(arg)) def _eval_rewrite_as_sincos(self, arg, **kwargs): return sin(arg)/(cos(arg)*sin(arg)) def _eval_rewrite_as_sin(self, arg, **kwargs): return (1/cos(arg).rewrite(sin)) def _eval_rewrite_as_tan(self, arg, **kwargs): return (1/cos(arg).rewrite(tan)) def _eval_rewrite_as_csc(self, arg, **kwargs): return csc(pi/2 - arg, evaluate=False) def fdiff(self, argindex=1): if argindex == 1: return tan(self.args[0])*sec(self.args[0]) else: raise ArgumentIndexError(self, argindex) def _eval_is_complex(self): arg = self.args[0] if arg.is_complex and (arg/pi - S.Half).is_integer is False: return True @staticmethod @cacheit def taylor_term(n, x, *previous_terms): # Reference Formula: # http://functions.wolfram.com/ElementaryFunctions/Sec/06/01/02/01/ from sympy.functions.combinatorial.numbers import euler if n < 0 or n % 2 == 1: return S.Zero else: x = sympify(x) k = n//2 return (-1)**k*euler(2*k)/factorial(2*k)*x**(2*k) def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0] x0 = arg.subs(x, 0).cancel() n = (x0 + S.Pi/2)/S.Pi if n.is_integer: lt = (arg - n*S.Pi + S.Pi/2).as_leading_term(x) return ((-1)**n)/lt return self.func(x0) class csc(ReciprocalTrigonometricFunction): """ The cosecant function. Returns the cosecant of x (measured in radians). Explanation =========== See :func:`sin` for notes about automatic evaluation. Examples ======== >>> from sympy import csc >>> from sympy.abc import x >>> csc(x**2).diff(x) -2*x*cot(x**2)*csc(x**2) >>> csc(1).diff(x) 0 See Also ======== sin, cos, sec, tan, cot asin, acsc, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_functions .. [2] http://dlmf.nist.gov/4.14 .. [3] http://functions.wolfram.com/ElementaryFunctions/Csc """ _reciprocal_of = sin _is_odd = True def period(self, symbol=None): return self._period(symbol) def _eval_rewrite_as_sin(self, arg, **kwargs): return (1/sin(arg)) def _eval_rewrite_as_sincos(self, arg, **kwargs): return cos(arg)/(sin(arg)*cos(arg)) def _eval_rewrite_as_cot(self, arg, **kwargs): cot_half = cot(arg/2) return (1 + cot_half**2)/(2*cot_half) def _eval_rewrite_as_cos(self, arg, **kwargs): return 1/sin(arg).rewrite(cos) def _eval_rewrite_as_sec(self, arg, **kwargs): return sec(pi/2 - arg, evaluate=False) def _eval_rewrite_as_tan(self, arg, **kwargs): return (1/sin(arg).rewrite(tan)) def fdiff(self, argindex=1): if argindex == 1: return -cot(self.args[0])*csc(self.args[0]) else: raise ArgumentIndexError(self, argindex) def _eval_is_complex(self): arg = self.args[0] if arg.is_real and (arg/pi).is_integer is False: return True @staticmethod @cacheit def taylor_term(n, x, *previous_terms): from sympy import bernoulli if n == 0: return 1/sympify(x) elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) k = n//2 + 1 return ((-1)**(k - 1)*2*(2**(2*k - 1) - 1)* bernoulli(2*k)*x**(2*k - 1)/factorial(2*k)) class sinc(Function): r""" Represents an unnormalized sinc function: .. math:: \operatorname{sinc}(x) = \begin{cases} \frac{\sin x}{x} & \qquad x \neq 0 \\ 1 & \qquad x = 0 \end{cases} Examples ======== >>> from sympy import sinc, oo, jn >>> from sympy.abc import x >>> sinc(x) sinc(x) * Automated Evaluation >>> sinc(0) 1 >>> sinc(oo) 0 * Differentiation >>> sinc(x).diff() cos(x)/x - sin(x)/x**2 * Series Expansion >>> sinc(x).series() 1 - x**2/6 + x**4/120 + O(x**6) * As zero'th order spherical Bessel Function >>> sinc(x).rewrite(jn) jn(0, x) See also ======== sin References ========== .. [1] https://en.wikipedia.org/wiki/Sinc_function """ _singularities = (S.ComplexInfinity,) def fdiff(self, argindex=1): x = self.args[0] if argindex == 1: # We would like to return the Piecewise here, but Piecewise.diff # currently can't handle removable singularities, meaning things # like sinc(x).diff(x, 2) give the wrong answer at x = 0. See # https://github.com/sympy/sympy/issues/11402. # # return Piecewise(((x*cos(x) - sin(x))/x**2, Ne(x, S.Zero)), (S.Zero, S.true)) return cos(x)/x - sin(x)/x**2 else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): if arg.is_zero: return S.One if arg.is_Number: if arg in [S.Infinity, S.NegativeInfinity]: return S.Zero elif arg is S.NaN: return S.NaN if arg is S.ComplexInfinity: return S.NaN if arg.could_extract_minus_sign(): return cls(-arg) pi_coeff = _pi_coeff(arg) if pi_coeff is not None: if pi_coeff.is_integer: if fuzzy_not(arg.is_zero): return S.Zero elif (2*pi_coeff).is_integer: return S.NegativeOne**(pi_coeff - S.Half)/arg def _eval_nseries(self, x, n, logx, cdir=0): x = self.args[0] return (sin(x)/x)._eval_nseries(x, n, logx) def _eval_rewrite_as_jn(self, arg, **kwargs): from sympy.functions.special.bessel import jn return jn(0, arg) def _eval_rewrite_as_sin(self, arg, **kwargs): return Piecewise((sin(arg)/arg, Ne(arg, S.Zero)), (S.One, S.true)) ############################################################################### ########################### TRIGONOMETRIC INVERSES ############################ ############################################################################### class InverseTrigonometricFunction(Function): """Base class for inverse trigonometric functions.""" _singularities = (S.One, S.NegativeOne, S.Zero, S.ComplexInfinity) # type: Tuple[Expr, ...] @staticmethod def _asin_table(): # Only keys with could_extract_minus_sign() == False # are actually needed. return { sqrt(3)/2: S.Pi/3, sqrt(2)/2: S.Pi/4, 1/sqrt(2): S.Pi/4, sqrt((5 - sqrt(5))/8): S.Pi/5, sqrt(2)*sqrt(5 - sqrt(5))/4: S.Pi/5, sqrt((5 + sqrt(5))/8): S.Pi*Rational(2, 5), sqrt(2)*sqrt(5 + sqrt(5))/4: S.Pi*Rational(2, 5), S.Half: S.Pi/6, sqrt(2 - sqrt(2))/2: S.Pi/8, sqrt(S.Half - sqrt(2)/4): S.Pi/8, sqrt(2 + sqrt(2))/2: S.Pi*Rational(3, 8), sqrt(S.Half + sqrt(2)/4): S.Pi*Rational(3, 8), (sqrt(5) - 1)/4: S.Pi/10, (1 - sqrt(5))/4: -S.Pi/10, (sqrt(5) + 1)/4: S.Pi*Rational(3, 10), sqrt(6)/4 - sqrt(2)/4: S.Pi/12, -sqrt(6)/4 + sqrt(2)/4: -S.Pi/12, (sqrt(3) - 1)/sqrt(8): S.Pi/12, (1 - sqrt(3))/sqrt(8): -S.Pi/12, sqrt(6)/4 + sqrt(2)/4: S.Pi*Rational(5, 12), (1 + sqrt(3))/sqrt(8): S.Pi*Rational(5, 12) } @staticmethod def _atan_table(): # Only keys with could_extract_minus_sign() == False # are actually needed. return { sqrt(3)/3: S.Pi/6, 1/sqrt(3): S.Pi/6, sqrt(3): S.Pi/3, sqrt(2) - 1: S.Pi/8, 1 - sqrt(2): -S.Pi/8, 1 + sqrt(2): S.Pi*Rational(3, 8), sqrt(5 - 2*sqrt(5)): S.Pi/5, sqrt(5 + 2*sqrt(5)): S.Pi*Rational(2, 5), sqrt(1 - 2*sqrt(5)/5): S.Pi/10, sqrt(1 + 2*sqrt(5)/5): S.Pi*Rational(3, 10), 2 - sqrt(3): S.Pi/12, -2 + sqrt(3): -S.Pi/12, 2 + sqrt(3): S.Pi*Rational(5, 12) } @staticmethod def _acsc_table(): # Keys for which could_extract_minus_sign() # will obviously return True are omitted. return { 2*sqrt(3)/3: S.Pi/3, sqrt(2): S.Pi/4, sqrt(2 + 2*sqrt(5)/5): S.Pi/5, 1/sqrt(Rational(5, 8) - sqrt(5)/8): S.Pi/5, sqrt(2 - 2*sqrt(5)/5): S.Pi*Rational(2, 5), 1/sqrt(Rational(5, 8) + sqrt(5)/8): S.Pi*Rational(2, 5), 2: S.Pi/6, sqrt(4 + 2*sqrt(2)): S.Pi/8, 2/sqrt(2 - sqrt(2)): S.Pi/8, sqrt(4 - 2*sqrt(2)): S.Pi*Rational(3, 8), 2/sqrt(2 + sqrt(2)): S.Pi*Rational(3, 8), 1 + sqrt(5): S.Pi/10, sqrt(5) - 1: S.Pi*Rational(3, 10), -(sqrt(5) - 1): S.Pi*Rational(-3, 10), sqrt(6) + sqrt(2): S.Pi/12, sqrt(6) - sqrt(2): S.Pi*Rational(5, 12), -(sqrt(6) - sqrt(2)): S.Pi*Rational(-5, 12) } class asin(InverseTrigonometricFunction): """ The inverse sine function. Returns the arcsine of x in radians. Explanation =========== ``asin(x)`` will evaluate automatically in the cases ``oo``, ``-oo``, ``0``, ``1``, ``-1`` and for some instances when the result is a rational multiple of pi (see the eval class method). A purely imaginary argument will lead to an asinh expression. Examples ======== >>> from sympy import asin, oo >>> asin(1) pi/2 >>> asin(-1) -pi/2 >>> asin(-oo) oo*I >>> asin(oo) -oo*I See Also ======== sin, csc, cos, sec, tan, cot acsc, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions .. [2] http://dlmf.nist.gov/4.23 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcSin """ def fdiff(self, argindex=1): if argindex == 1: return 1/sqrt(1 - self.args[0]**2) else: raise ArgumentIndexError(self, argindex) def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if s.args[0].is_rational: return False else: return s.is_rational def _eval_is_positive(self): return self._eval_is_extended_real() and self.args[0].is_positive def _eval_is_negative(self): return self._eval_is_extended_real() and self.args[0].is_negative @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.NegativeInfinity*S.ImaginaryUnit elif arg is S.NegativeInfinity: return S.Infinity*S.ImaginaryUnit elif arg.is_zero: return S.Zero elif arg is S.One: return S.Pi/2 elif arg is S.NegativeOne: return -S.Pi/2 if arg is S.ComplexInfinity: return S.ComplexInfinity if arg.could_extract_minus_sign(): return -cls(-arg) if arg.is_number: asin_table = cls._asin_table() if arg in asin_table: return asin_table[arg] i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit*asinh(i_coeff) if arg.is_zero: return S.Zero if isinstance(arg, sin): ang = arg.args[0] if ang.is_comparable: ang %= 2*pi # restrict to [0,2*pi) if ang > pi: # restrict to (-pi,pi] ang = pi - ang # restrict to [-pi/2,pi/2] if ang > pi/2: ang = pi - ang if ang < -pi/2: ang = -pi - ang return ang if isinstance(arg, cos): # acos(x) + asin(x) = pi/2 ang = arg.args[0] if ang.is_comparable: return pi/2 - acos(arg) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] return p*(n - 2)**2/(n*(n - 1))*x**2 else: k = (n - 1) // 2 R = RisingFactorial(S.Half, k) F = factorial(k) return R/F*x**n/n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import I, im, log arg = self.args[0] x0 = arg.subs(x, 0).cancel() if x0.is_zero: return arg.as_leading_term(x) if x0 is S.ComplexInfinity: return I*log(arg.as_leading_term(x)) if cdir != 0: cdir = arg.dir(x, cdir) if im(cdir) < 0 and x0.is_real and x0 < S.NegativeOne: return -S.Pi - self.func(x0) elif im(cdir) > 0 and x0.is_real and x0 > S.One: return S.Pi - self.func(x0) return self.func(x0) def _eval_nseries(self, x, n, logx, cdir=0): #asin from sympy import Dummy, im, O arg0 = self.args[0].subs(x, 0) if arg0 is S.One: t = Dummy('t', positive=True) ser = asin(S.One - t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.One - self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f if not g.is_meromorphic(x, 0): # cannot be expanded return O(1) if n == 0 else S.Pi/2 + O(sqrt(x)) res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) if arg0 is S.NegativeOne: t = Dummy('t', positive=True) ser = asin(S.NegativeOne + t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.One + self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f if not g.is_meromorphic(x, 0): # cannot be expanded return O(1) if n == 0 else -S.Pi/2 + O(sqrt(x)) res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) res = Function._eval_nseries(self, x, n=n, logx=logx) if arg0 is S.ComplexInfinity: return res if cdir != 0: cdir = self.args[0].dir(x, cdir) if im(cdir) < 0 and arg0.is_real and arg0 < S.NegativeOne: return -S.Pi - res elif im(cdir) > 0 and arg0.is_real and arg0 > S.One: return S.Pi - res return res def _eval_rewrite_as_acos(self, x, **kwargs): return S.Pi/2 - acos(x) def _eval_rewrite_as_atan(self, x, **kwargs): return 2*atan(x/(1 + sqrt(1 - x**2))) def _eval_rewrite_as_log(self, x, **kwargs): return -S.ImaginaryUnit*log(S.ImaginaryUnit*x + sqrt(1 - x**2)) def _eval_rewrite_as_acot(self, arg, **kwargs): return 2*acot((1 + sqrt(1 - arg**2))/arg) def _eval_rewrite_as_asec(self, arg, **kwargs): return S.Pi/2 - asec(1/arg) def _eval_rewrite_as_acsc(self, arg, **kwargs): return acsc(1/arg) def _eval_is_extended_real(self): x = self.args[0] return x.is_extended_real and (1 - abs(x)).is_nonnegative def inverse(self, argindex=1): """ Returns the inverse of this function. """ return sin class acos(InverseTrigonometricFunction): """ The inverse cosine function. Returns the arc cosine of x (measured in radians). Examples ======== ``acos(x)`` will evaluate automatically in the cases ``oo``, ``-oo``, ``0``, ``1``, ``-1`` and for some instances when the result is a rational multiple of pi (see the eval class method). ``acos(zoo)`` evaluates to ``zoo`` (see note in :class:`sympy.functions.elementary.trigonometric.asec`) A purely imaginary argument will be rewritten to asinh. Examples ======== >>> from sympy import acos, oo >>> acos(1) 0 >>> acos(0) pi/2 >>> acos(oo) oo*I See Also ======== sin, csc, cos, sec, tan, cot asin, acsc, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions .. [2] http://dlmf.nist.gov/4.23 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcCos """ def fdiff(self, argindex=1): if argindex == 1: return -1/sqrt(1 - self.args[0]**2) else: raise ArgumentIndexError(self, argindex) def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if s.args[0].is_rational: return False else: return s.is_rational @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity*S.ImaginaryUnit elif arg is S.NegativeInfinity: return S.NegativeInfinity*S.ImaginaryUnit elif arg.is_zero: return S.Pi/2 elif arg is S.One: return S.Zero elif arg is S.NegativeOne: return S.Pi if arg is S.ComplexInfinity: return S.ComplexInfinity if arg.is_number: asin_table = cls._asin_table() if arg in asin_table: return pi/2 - asin_table[arg] elif -arg in asin_table: return pi/2 + asin_table[-arg] i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return pi/2 - asin(arg) if isinstance(arg, cos): ang = arg.args[0] if ang.is_comparable: ang %= 2*pi # restrict to [0,2*pi) if ang > pi: # restrict to [0,pi] ang = 2*pi - ang return ang if isinstance(arg, sin): # acos(x) + asin(x) = pi/2 ang = arg.args[0] if ang.is_comparable: return pi/2 - asin(arg) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n == 0: return S.Pi/2 elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) if len(previous_terms) >= 2 and n > 2: p = previous_terms[-2] return p*(n - 2)**2/(n*(n - 1))*x**2 else: k = (n - 1) // 2 R = RisingFactorial(S.Half, k) F = factorial(k) return -R/F*x**n/n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import I, im, log arg = self.args[0] x0 = arg.subs(x, 0).cancel() if x0 == 1: return sqrt(2)*sqrt((S.One - arg).as_leading_term(x)) if x0 is S.ComplexInfinity: return I*log(arg.as_leading_term(x)) if cdir != 0: cdir = arg.dir(x, cdir) if im(cdir) < 0 and x0.is_real and x0 < S.NegativeOne: return 2*S.Pi - self.func(x0) elif im(cdir) > 0 and x0.is_real and x0 > S.One: return -self.func(x0) return self.func(x0) def _eval_is_extended_real(self): x = self.args[0] return x.is_extended_real and (1 - abs(x)).is_nonnegative def _eval_is_nonnegative(self): return self._eval_is_extended_real() def _eval_nseries(self, x, n, logx, cdir=0): #acos from sympy import Dummy, im, O arg0 = self.args[0].subs(x, 0) if arg0 is S.One: t = Dummy('t', positive=True) ser = acos(S.One - t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.One - self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f if not g.is_meromorphic(x, 0): # cannot be expanded return O(1) if n == 0 else O(sqrt(x)) res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) if arg0 is S.NegativeOne: t = Dummy('t', positive=True) ser = acos(S.NegativeOne + t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.One + self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f if not g.is_meromorphic(x, 0): # cannot be expanded return O(1) if n == 0 else S.Pi + O(sqrt(x)) res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) res = Function._eval_nseries(self, x, n=n, logx=logx) if arg0 is S.ComplexInfinity: return res if cdir != 0: cdir = self.args[0].dir(x, cdir) if im(cdir) < 0 and arg0.is_real and arg0 < S.NegativeOne: return 2*S.Pi - res elif im(cdir) > 0 and arg0.is_real and arg0 > S.One: return -res return res def _eval_rewrite_as_log(self, x, **kwargs): return S.Pi/2 + S.ImaginaryUnit*\ log(S.ImaginaryUnit*x + sqrt(1 - x**2)) def _eval_rewrite_as_asin(self, x, **kwargs): return S.Pi/2 - asin(x) def _eval_rewrite_as_atan(self, x, **kwargs): return atan(sqrt(1 - x**2)/x) + (S.Pi/2)*(1 - x*sqrt(1/x**2)) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return cos def _eval_rewrite_as_acot(self, arg, **kwargs): return S.Pi/2 - 2*acot((1 + sqrt(1 - arg**2))/arg) def _eval_rewrite_as_asec(self, arg, **kwargs): return asec(1/arg) def _eval_rewrite_as_acsc(self, arg, **kwargs): return S.Pi/2 - acsc(1/arg) def _eval_conjugate(self): z = self.args[0] r = self.func(self.args[0].conjugate()) if z.is_extended_real is False: return r elif z.is_extended_real and (z + 1).is_nonnegative and (z - 1).is_nonpositive: return r class atan(InverseTrigonometricFunction): """ The inverse tangent function. Returns the arc tangent of x (measured in radians). Explanation =========== ``atan(x)`` will evaluate automatically in the cases ``oo``, ``-oo``, ``0``, ``1``, ``-1`` and for some instances when the result is a rational multiple of pi (see the eval class method). Examples ======== >>> from sympy import atan, oo >>> atan(0) 0 >>> atan(1) pi/4 >>> atan(oo) pi/2 See Also ======== sin, csc, cos, sec, tan, cot asin, acsc, acos, asec, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions .. [2] http://dlmf.nist.gov/4.23 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcTan """ _singularities = (S.ImaginaryUnit, -S.ImaginaryUnit) def fdiff(self, argindex=1): if argindex == 1: return 1/(1 + self.args[0]**2) else: raise ArgumentIndexError(self, argindex) def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if s.args[0].is_rational: return False else: return s.is_rational def _eval_is_positive(self): return self.args[0].is_extended_positive def _eval_is_nonnegative(self): return self.args[0].is_extended_nonnegative def _eval_is_zero(self): return self.args[0].is_zero def _eval_is_real(self): return self.args[0].is_extended_real @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Pi/2 elif arg is S.NegativeInfinity: return -S.Pi/2 elif arg.is_zero: return S.Zero elif arg is S.One: return S.Pi/4 elif arg is S.NegativeOne: return -S.Pi/4 if arg is S.ComplexInfinity: from sympy.calculus.util import AccumBounds return AccumBounds(-S.Pi/2, S.Pi/2) if arg.could_extract_minus_sign(): return -cls(-arg) if arg.is_number: atan_table = cls._atan_table() if arg in atan_table: return atan_table[arg] i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return S.ImaginaryUnit*atanh(i_coeff) if arg.is_zero: return S.Zero if isinstance(arg, tan): ang = arg.args[0] if ang.is_comparable: ang %= pi # restrict to [0,pi) if ang > pi/2: # restrict to [-pi/2,pi/2] ang -= pi return ang if isinstance(arg, cot): # atan(x) + acot(x) = pi/2 ang = arg.args[0] if ang.is_comparable: ang = pi/2 - acot(arg) if ang > pi/2: # restrict to [-pi/2,pi/2] ang -= pi return ang @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) return (-1)**((n - 1)//2)*x**n/n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import im, re arg = self.args[0] x0 = arg.subs(x, 0).cancel() if x0.is_zero: return arg.as_leading_term(x) if x0 is S.ComplexInfinity: return acot(1/arg)._eval_as_leading_term(x, cdir=cdir) if cdir != 0: cdir = arg.dir(x, cdir) if re(cdir) < 0 and re(x0).is_zero and im(x0) > S.One: return self.func(x0) - S.Pi elif re(cdir) > 0 and re(x0).is_zero and im(x0) < S.NegativeOne: return self.func(x0) + S.Pi return self.func(x0) def _eval_nseries(self, x, n, logx, cdir=0): #atan from sympy import im, re arg0 = self.args[0].subs(x, 0) res = Function._eval_nseries(self, x, n=n, logx=logx) if cdir != 0: cdir = self.args[0].dir(x, cdir) if arg0 is S.ComplexInfinity: if re(cdir) > 0: return res - S.Pi return res if re(cdir) < 0 and re(arg0).is_zero and im(arg0) > S.One: return res - S.Pi elif re(cdir) > 0 and re(arg0).is_zero and im(arg0) < S.NegativeOne: return res + S.Pi return res def _eval_rewrite_as_log(self, x, **kwargs): return S.ImaginaryUnit/2*(log(S.One - S.ImaginaryUnit*x) - log(S.One + S.ImaginaryUnit*x)) def _eval_aseries(self, n, args0, x, logx): if args0[0] is S.Infinity: return (S.Pi/2 - atan(1/self.args[0]))._eval_nseries(x, n, logx) elif args0[0] is S.NegativeInfinity: return (-S.Pi/2 - atan(1/self.args[0]))._eval_nseries(x, n, logx) else: return super()._eval_aseries(n, args0, x, logx) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return tan def _eval_rewrite_as_asin(self, arg, **kwargs): return sqrt(arg**2)/arg*(S.Pi/2 - asin(1/sqrt(1 + arg**2))) def _eval_rewrite_as_acos(self, arg, **kwargs): return sqrt(arg**2)/arg*acos(1/sqrt(1 + arg**2)) def _eval_rewrite_as_acot(self, arg, **kwargs): return acot(1/arg) def _eval_rewrite_as_asec(self, arg, **kwargs): return sqrt(arg**2)/arg*asec(sqrt(1 + arg**2)) def _eval_rewrite_as_acsc(self, arg, **kwargs): return sqrt(arg**2)/arg*(S.Pi/2 - acsc(sqrt(1 + arg**2))) class acot(InverseTrigonometricFunction): r""" The inverse cotangent function. Returns the arc cotangent of x (measured in radians). Explanation =========== ``acot(x)`` will evaluate automatically in the cases ``oo``, ``-oo``, ``zoo``, ``0``, ``1``, ``-1`` and for some instances when the result is a rational multiple of pi (see the eval class method). A purely imaginary argument will lead to an ``acoth`` expression. ``acot(x)`` has a branch cut along `(-i, i)`, hence it is discontinuous at 0. Its range for real ``x`` is `(-\frac{\pi}{2}, \frac{\pi}{2}]`. Examples ======== >>> from sympy import acot, sqrt >>> acot(0) pi/2 >>> acot(1) pi/4 >>> acot(sqrt(3) - 2) -5*pi/12 See Also ======== sin, csc, cos, sec, tan, cot asin, acsc, acos, asec, atan, atan2 References ========== .. [1] http://dlmf.nist.gov/4.23 .. [2] http://functions.wolfram.com/ElementaryFunctions/ArcCot """ _singularities = (S.ImaginaryUnit, -S.ImaginaryUnit) def fdiff(self, argindex=1): if argindex == 1: return -1/(1 + self.args[0]**2) else: raise ArgumentIndexError(self, argindex) def _eval_is_rational(self): s = self.func(*self.args) if s.func == self.func: if s.args[0].is_rational: return False else: return s.is_rational def _eval_is_positive(self): return self.args[0].is_nonnegative def _eval_is_negative(self): return self.args[0].is_negative def _eval_is_extended_real(self): return self.args[0].is_extended_real @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero elif arg is S.NegativeInfinity: return S.Zero elif arg.is_zero: return S.Pi/ 2 elif arg is S.One: return S.Pi/4 elif arg is S.NegativeOne: return -S.Pi/4 if arg is S.ComplexInfinity: return S.Zero if arg.could_extract_minus_sign(): return -cls(-arg) if arg.is_number: atan_table = cls._atan_table() if arg in atan_table: ang = pi/2 - atan_table[arg] if ang > pi/2: # restrict to (-pi/2,pi/2] ang -= pi return ang i_coeff = arg.as_coefficient(S.ImaginaryUnit) if i_coeff is not None: return -S.ImaginaryUnit*acoth(i_coeff) if arg.is_zero: return S.Pi*S.Half if isinstance(arg, cot): ang = arg.args[0] if ang.is_comparable: ang %= pi # restrict to [0,pi) if ang > pi/2: # restrict to (-pi/2,pi/2] ang -= pi; return ang if isinstance(arg, tan): # atan(x) + acot(x) = pi/2 ang = arg.args[0] if ang.is_comparable: ang = pi/2 - atan(arg) if ang > pi/2: # restrict to (-pi/2,pi/2] ang -= pi return ang @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n == 0: return S.Pi/2 # FIX THIS elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) return (-1)**((n + 1)//2)*x**n/n def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import im, re arg = self.args[0] x0 = arg.subs(x, 0).cancel() if x0 is S.ComplexInfinity: return (1/arg).as_leading_term(x) if cdir != 0: cdir = arg.dir(x, cdir) if x0.is_zero: if re(cdir) < 0: return self.func(x0) - S.Pi return self.func(x0) if re(cdir) > 0 and re(x0).is_zero and im(x0) > S.Zero and im(x0) < S.One: return self.func(x0) + S.Pi if re(cdir) < 0 and re(x0).is_zero and im(x0) < S.Zero and im(x0) > S.NegativeOne: return self.func(x0) - S.Pi return self.func(x0) def _eval_nseries(self, x, n, logx, cdir=0): #acot from sympy import im, re arg0 = self.args[0].subs(x, 0) res = Function._eval_nseries(self, x, n=n, logx=logx) if arg0 is S.ComplexInfinity: return res if cdir != 0: cdir = self.args[0].dir(x, cdir) if arg0.is_zero: if re(cdir) < 0: return res - S.Pi return res if re(cdir) > 0 and re(arg0).is_zero and im(arg0) > S.Zero and im(arg0) < S.One: return res + S.Pi if re(cdir) < 0 and re(arg0).is_zero and im(arg0) < S.Zero and im(arg0) > S.NegativeOne: return res - S.Pi return res def _eval_aseries(self, n, args0, x, logx): if args0[0] is S.Infinity: return (S.Pi/2 - acot(1/self.args[0]))._eval_nseries(x, n, logx) elif args0[0] is S.NegativeInfinity: return (S.Pi*Rational(3, 2) - acot(1/self.args[0]))._eval_nseries(x, n, logx) else: return super(atan, self)._eval_aseries(n, args0, x, logx) def _eval_rewrite_as_log(self, x, **kwargs): return S.ImaginaryUnit/2*(log(1 - S.ImaginaryUnit/x) - log(1 + S.ImaginaryUnit/x)) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return cot def _eval_rewrite_as_asin(self, arg, **kwargs): return (arg*sqrt(1/arg**2)* (S.Pi/2 - asin(sqrt(-arg**2)/sqrt(-arg**2 - 1)))) def _eval_rewrite_as_acos(self, arg, **kwargs): return arg*sqrt(1/arg**2)*acos(sqrt(-arg**2)/sqrt(-arg**2 - 1)) def _eval_rewrite_as_atan(self, arg, **kwargs): return atan(1/arg) def _eval_rewrite_as_asec(self, arg, **kwargs): return arg*sqrt(1/arg**2)*asec(sqrt((1 + arg**2)/arg**2)) def _eval_rewrite_as_acsc(self, arg, **kwargs): return arg*sqrt(1/arg**2)*(S.Pi/2 - acsc(sqrt((1 + arg**2)/arg**2))) class asec(InverseTrigonometricFunction): r""" The inverse secant function. Returns the arc secant of x (measured in radians). Explanation =========== ``asec(x)`` will evaluate automatically in the cases ``oo``, ``-oo``, ``0``, ``1``, ``-1`` and for some instances when the result is a rational multiple of pi (see the eval class method). ``asec(x)`` has branch cut in the interval [-1, 1]. For complex arguments, it can be defined [4]_ as .. math:: \operatorname{sec^{-1}}(z) = -i\frac{\log\left(\sqrt{1 - z^2} + 1\right)}{z} At ``x = 0``, for positive branch cut, the limit evaluates to ``zoo``. For negative branch cut, the limit .. math:: \lim_{z \to 0}-i\frac{\log\left(-\sqrt{1 - z^2} + 1\right)}{z} simplifies to :math:`-i\log\left(z/2 + O\left(z^3\right)\right)` which ultimately evaluates to ``zoo``. As ``acos(x)`` = ``asec(1/x)``, a similar argument can be given for ``acos(x)``. Examples ======== >>> from sympy import asec, oo >>> asec(1) 0 >>> asec(-1) pi >>> asec(0) zoo >>> asec(-oo) pi/2 See Also ======== sin, csc, cos, sec, tan, cot asin, acsc, acos, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions .. [2] http://dlmf.nist.gov/4.23 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcSec .. [4] http://reference.wolfram.com/language/ref/ArcSec.html """ @classmethod def eval(cls, arg): if arg.is_zero: return S.ComplexInfinity if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.One: return S.Zero elif arg is S.NegativeOne: return S.Pi if arg in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: return S.Pi/2 if arg.is_number: acsc_table = cls._acsc_table() if arg in acsc_table: return pi/2 - acsc_table[arg] elif -arg in acsc_table: return pi/2 + acsc_table[-arg] if isinstance(arg, sec): ang = arg.args[0] if ang.is_comparable: ang %= 2*pi # restrict to [0,2*pi) if ang > pi: # restrict to [0,pi] ang = 2*pi - ang return ang if isinstance(arg, csc): # asec(x) + acsc(x) = pi/2 ang = arg.args[0] if ang.is_comparable: return pi/2 - acsc(arg) def fdiff(self, argindex=1): if argindex == 1: return 1/(self.args[0]**2*sqrt(1 - 1/self.args[0]**2)) else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return sec def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import I, im, log arg = self.args[0] x0 = arg.subs(x, 0).cancel() if x0 == 1: return sqrt(2)*sqrt((arg - S.One).as_leading_term(x)) if x0.is_zero: return I*log(arg.as_leading_term(x)) if cdir != 0: cdir = arg.dir(x, cdir) if im(cdir) < 0 and x0.is_real and x0 > S.Zero and x0 < S.One: return -self.func(x0) elif im(cdir) > 0 and x0.is_real and x0 < S.Zero and x0 > S.NegativeOne: return 2*S.Pi - self.func(x0) return self.func(x0) def _eval_nseries(self, x, n, logx, cdir=0): #asec from sympy import Dummy, im, O arg0 = self.args[0].subs(x, 0) if arg0 is S.One: t = Dummy('t', positive=True) ser = asec(S.One + t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.NegativeOne + self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) if arg0 is S.NegativeOne: t = Dummy('t', positive=True) ser = asec(S.NegativeOne - t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.NegativeOne - self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) res = Function._eval_nseries(self, x, n=n, logx=logx) if arg0 is S.ComplexInfinity: return res if cdir != 0: cdir = self.args[0].dir(x, cdir) if im(cdir) < 0 and arg0.is_real and arg0 > S.Zero and arg0 < S.One: return -res elif im(cdir) > 0 and arg0.is_real and arg0 < S.Zero and arg0 > S.NegativeOne: return 2*S.Pi - res return res def _eval_is_extended_real(self): x = self.args[0] if x.is_extended_real is False: return False return fuzzy_or(((x - 1).is_nonnegative, (-x - 1).is_nonnegative)) def _eval_rewrite_as_log(self, arg, **kwargs): return S.Pi/2 + S.ImaginaryUnit*log(S.ImaginaryUnit/arg + sqrt(1 - 1/arg**2)) def _eval_rewrite_as_asin(self, arg, **kwargs): return S.Pi/2 - asin(1/arg) def _eval_rewrite_as_acos(self, arg, **kwargs): return acos(1/arg) def _eval_rewrite_as_atan(self, arg, **kwargs): return sqrt(arg**2)/arg*(-S.Pi/2 + 2*atan(arg + sqrt(arg**2 - 1))) def _eval_rewrite_as_acot(self, arg, **kwargs): return sqrt(arg**2)/arg*(-S.Pi/2 + 2*acot(arg - sqrt(arg**2 - 1))) def _eval_rewrite_as_acsc(self, arg, **kwargs): return S.Pi/2 - acsc(arg) class acsc(InverseTrigonometricFunction): """ The inverse cosecant function. Returns the arc cosecant of x (measured in radians). Explanation =========== ``acsc(x)`` will evaluate automatically in the cases ``oo``, ``-oo``, ``0``, ``1``, ``-1`` and for some instances when the result is a rational multiple of pi (see the eval class method). Examples ======== >>> from sympy import acsc, oo >>> acsc(1) pi/2 >>> acsc(-1) -pi/2 >>> acsc(oo) 0 >>> acsc(-oo) == acsc(oo) True >>> acsc(0) zoo See Also ======== sin, csc, cos, sec, tan, cot asin, acos, asec, atan, acot, atan2 References ========== .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions .. [2] http://dlmf.nist.gov/4.23 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcCsc """ @classmethod def eval(cls, arg): if arg.is_zero: return S.ComplexInfinity if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.One: return S.Pi/2 elif arg is S.NegativeOne: return -S.Pi/2 if arg in [S.Infinity, S.NegativeInfinity, S.ComplexInfinity]: return S.Zero if arg.could_extract_minus_sign(): return -cls(-arg) if arg.is_number: acsc_table = cls._acsc_table() if arg in acsc_table: return acsc_table[arg] if isinstance(arg, csc): ang = arg.args[0] if ang.is_comparable: ang %= 2*pi # restrict to [0,2*pi) if ang > pi: # restrict to (-pi,pi] ang = pi - ang # restrict to [-pi/2,pi/2] if ang > pi/2: ang = pi - ang if ang < -pi/2: ang = -pi - ang return ang if isinstance(arg, sec): # asec(x) + acsc(x) = pi/2 ang = arg.args[0] if ang.is_comparable: return pi/2 - asec(arg) def fdiff(self, argindex=1): if argindex == 1: return -1/(self.args[0]**2*sqrt(1 - 1/self.args[0]**2)) else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return csc def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import I, im, log arg = self.args[0] x0 = arg.subs(x, 0).cancel() if x0.is_zero: return I*log(arg.as_leading_term(x)) if x0 is S.ComplexInfinity: return arg.as_leading_term(x) if cdir != 0: cdir = arg.dir(x, cdir) if im(cdir) < 0 and x0.is_real and x0 > S.Zero and x0 < S.One: return S.Pi - self.func(x0) elif im(cdir) > 0 and x0.is_real and x0 < S.Zero and x0 > S.NegativeOne: return -S.Pi - self.func(x0) return self.func(x0) def _eval_nseries(self, x, n, logx, cdir=0): #acsc from sympy import Dummy, im, O arg0 = self.args[0].subs(x, 0) if arg0 is S.One: t = Dummy('t', positive=True) ser = acsc(S.One + t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.NegativeOne + self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) if arg0 is S.NegativeOne: t = Dummy('t', positive=True) ser = acsc(S.NegativeOne - t**2).rewrite(log).nseries(t, 0, 2*n) arg1 = S.NegativeOne - self.args[0] f = arg1.as_leading_term(x) g = (arg1 - f)/ f res1 = sqrt(S.One + g)._eval_nseries(x, n=n, logx=logx) res = (res1.removeO()*sqrt(f)).expand() return ser.removeO().subs(t, res).expand().powsimp() + O(x**n, x) res = Function._eval_nseries(self, x, n=n, logx=logx) if arg0 is S.ComplexInfinity: return res if cdir != 0: cdir = self.args[0].dir(x, cdir) if im(cdir) < 0 and arg0.is_real and arg0 > S.Zero and arg0 < S.One: return S.Pi - res elif im(cdir) > 0 and arg0.is_real and arg0 < S.Zero and arg0 > S.NegativeOne: return -S.Pi - res return res def _eval_rewrite_as_log(self, arg, **kwargs): return -S.ImaginaryUnit*log(S.ImaginaryUnit/arg + sqrt(1 - 1/arg**2)) def _eval_rewrite_as_asin(self, arg, **kwargs): return asin(1/arg) def _eval_rewrite_as_acos(self, arg, **kwargs): return S.Pi/2 - acos(1/arg) def _eval_rewrite_as_atan(self, arg, **kwargs): return sqrt(arg**2)/arg*(S.Pi/2 - atan(sqrt(arg**2 - 1))) def _eval_rewrite_as_acot(self, arg, **kwargs): return sqrt(arg**2)/arg*(S.Pi/2 - acot(1/sqrt(arg**2 - 1))) def _eval_rewrite_as_asec(self, arg, **kwargs): return S.Pi/2 - asec(arg) class atan2(InverseTrigonometricFunction): r""" The function ``atan2(y, x)`` computes `\operatorname{atan}(y/x)` taking two arguments `y` and `x`. Signs of both `y` and `x` are considered to determine the appropriate quadrant of `\operatorname{atan}(y/x)`. The range is `(-\pi, \pi]`. The complete definition reads as follows: .. math:: \operatorname{atan2}(y, x) = \begin{cases} \arctan\left(\frac y x\right) & \qquad x > 0 \\ \arctan\left(\frac y x\right) + \pi& \qquad y \ge 0 , x < 0 \\ \arctan\left(\frac y x\right) - \pi& \qquad y < 0 , x < 0 \\ +\frac{\pi}{2} & \qquad y > 0 , x = 0 \\ -\frac{\pi}{2} & \qquad y < 0 , x = 0 \\ \text{undefined} & \qquad y = 0, x = 0 \end{cases} Attention: Note the role reversal of both arguments. The `y`-coordinate is the first argument and the `x`-coordinate the second. If either `x` or `y` is complex: .. math:: \operatorname{atan2}(y, x) = -i\log\left(\frac{x + iy}{\sqrt{x**2 + y**2}}\right) Examples ======== Going counter-clock wise around the origin we find the following angles: >>> from sympy import atan2 >>> atan2(0, 1) 0 >>> atan2(1, 1) pi/4 >>> atan2(1, 0) pi/2 >>> atan2(1, -1) 3*pi/4 >>> atan2(0, -1) pi >>> atan2(-1, -1) -3*pi/4 >>> atan2(-1, 0) -pi/2 >>> atan2(-1, 1) -pi/4 which are all correct. Compare this to the results of the ordinary `\operatorname{atan}` function for the point `(x, y) = (-1, 1)` >>> from sympy import atan, S >>> atan(S(1)/-1) -pi/4 >>> atan2(1, -1) 3*pi/4 where only the `\operatorname{atan2}` function reurns what we expect. We can differentiate the function with respect to both arguments: >>> from sympy import diff >>> from sympy.abc import x, y >>> diff(atan2(y, x), x) -y/(x**2 + y**2) >>> diff(atan2(y, x), y) x/(x**2 + y**2) We can express the `\operatorname{atan2}` function in terms of complex logarithms: >>> from sympy import log >>> atan2(y, x).rewrite(log) -I*log((x + I*y)/sqrt(x**2 + y**2)) and in terms of `\operatorname(atan)`: >>> from sympy import atan >>> atan2(y, x).rewrite(atan) Piecewise((2*atan(y/(x + sqrt(x**2 + y**2))), Ne(y, 0)), (pi, re(x) < 0), (0, Ne(x, 0)), (nan, True)) but note that this form is undefined on the negative real axis. See Also ======== sin, csc, cos, sec, tan, cot asin, acsc, acos, asec, atan, acot References ========== .. [1] https://en.wikipedia.org/wiki/Inverse_trigonometric_functions .. [2] https://en.wikipedia.org/wiki/Atan2 .. [3] http://functions.wolfram.com/ElementaryFunctions/ArcTan2 """ @classmethod def eval(cls, y, x): from sympy import Heaviside, im, re if x is S.NegativeInfinity: if y.is_zero: # Special case y = 0 because we define Heaviside(0) = 1/2 return S.Pi return 2*S.Pi*(Heaviside(re(y))) - S.Pi elif x is S.Infinity: return S.Zero elif x.is_imaginary and y.is_imaginary and x.is_number and y.is_number: x = im(x) y = im(y) if x.is_extended_real and y.is_extended_real: if x.is_positive: return atan(y/x) elif x.is_negative: if y.is_negative: return atan(y/x) - S.Pi elif y.is_nonnegative: return atan(y/x) + S.Pi elif x.is_zero: if y.is_positive: return S.Pi/2 elif y.is_negative: return -S.Pi/2 elif y.is_zero: return S.NaN if y.is_zero: if x.is_extended_nonzero: return S.Pi*(S.One - Heaviside(x)) if x.is_number: return Piecewise((S.Pi, re(x) < 0), (0, Ne(x, 0)), (S.NaN, True)) if x.is_number and y.is_number: return -S.ImaginaryUnit*log( (x + S.ImaginaryUnit*y)/sqrt(x**2 + y**2)) def _eval_rewrite_as_log(self, y, x, **kwargs): return -S.ImaginaryUnit*log((x + S.ImaginaryUnit*y)/sqrt(x**2 + y**2)) def _eval_rewrite_as_atan(self, y, x, **kwargs): from sympy import re return Piecewise((2*atan(y/(x + sqrt(x**2 + y**2))), Ne(y, 0)), (pi, re(x) < 0), (0, Ne(x, 0)), (S.NaN, True)) def _eval_rewrite_as_arg(self, y, x, **kwargs): from sympy import arg if x.is_extended_real and y.is_extended_real: return arg(x + y*S.ImaginaryUnit) n = x + S.ImaginaryUnit*y d = x**2 + y**2 return arg(n/sqrt(d)) - S.ImaginaryUnit*log(abs(n)/sqrt(abs(d))) def _eval_is_extended_real(self): return self.args[0].is_extended_real and self.args[1].is_extended_real def _eval_conjugate(self): return self.func(self.args[0].conjugate(), self.args[1].conjugate()) def fdiff(self, argindex): y, x = self.args if argindex == 1: # Diff wrt y return x/(x**2 + y**2) elif argindex == 2: # Diff wrt x return -y/(x**2 + y**2) else: raise ArgumentIndexError(self, argindex) def _eval_evalf(self, prec): y, x = self.args if x.is_extended_real and y.is_extended_real: return super()._eval_evalf(prec) sympy-sympy-1.9/sympy/functions/special/000077500000000000000000000000001412543434000205345ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/special/__init__.py000066400000000000000000000000731412543434000226450ustar00rootroot00000000000000# Stub __init__.py for the sympy.functions.special package sympy-sympy-1.9/sympy/functions/special/benchmarks/000077500000000000000000000000001412543434000226515ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/special/benchmarks/__init__.py000066400000000000000000000000001412543434000247500ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/special/benchmarks/bench_special.py000066400000000000000000000002301412543434000257750ustar00rootroot00000000000000from sympy import symbols from sympy.functions.special.spherical_harmonics import Ynm x, y = symbols('x,y') def timeit_Ynm_xy(): Ynm(1, 1, x, y) sympy-sympy-1.9/sympy/functions/special/bessel.py000066400000000000000000001570671412543434000224030ustar00rootroot00000000000000from functools import wraps from sympy import Add, S, pi, I, Rational, Wild, cacheit, sympify from sympy.core.function import Function, ArgumentIndexError, _mexpand from sympy.core.logic import fuzzy_or, fuzzy_not from sympy.core.power import Pow from sympy.functions.combinatorial.factorials import factorial from sympy.functions.elementary.trigonometric import sin, cos, csc, cot from sympy.functions.elementary.integers import ceiling from sympy.functions.elementary.complexes import Abs from sympy.functions.elementary.exponential import exp, log from sympy.functions.elementary.miscellaneous import sqrt, root from sympy.functions.elementary.complexes import re, im from sympy.functions.special.gamma_functions import gamma, digamma from sympy.functions.special.hyper import hyper from sympy.polys.orthopolys import spherical_bessel_fn as fn # TODO # o Scorer functions G1 and G2 # o Asymptotic expansions # These are possible, e.g. for fixed order, but since the bessel type # functions are oscillatory they are not actually tractable at # infinity, so this is not particularly useful right now. # o Nicer series expansions. # o More rewriting. # o Add solvers to ode.py (or rather add solvers for the hypergeometric equation). class BesselBase(Function): """ Abstract base class for Bessel-type functions. This class is meant to reduce code duplication. All Bessel-type functions can 1) be differentiated, with the derivatives expressed in terms of similar functions, and 2) be rewritten in terms of other Bessel-type functions. Here, Bessel-type functions are assumed to have one complex parameter. To use this base class, define class attributes ``_a`` and ``_b`` such that ``2*F_n' = -_a*F_{n+1} + b*F_{n-1}``. """ @property def order(self): """ The order of the Bessel-type function. """ return self.args[0] @property def argument(self): """ The argument of the Bessel-type function. """ return self.args[1] @classmethod def eval(cls, nu, z): return def fdiff(self, argindex=2): if argindex != 2: raise ArgumentIndexError(self, argindex) return (self._b/2 * self.__class__(self.order - 1, self.argument) - self._a/2 * self.__class__(self.order + 1, self.argument)) def _eval_conjugate(self): z = self.argument if z.is_extended_negative is False: return self.__class__(self.order.conjugate(), z.conjugate()) def _eval_is_meromorphic(self, x, a): nu, z = self.order, self.argument if nu.has(x): return False if not z._eval_is_meromorphic(x, a): return None z0 = z.subs(x, a) if nu.is_integer: if isinstance(self, (besselj, besseli, hn1, hn2, jn, yn)) or not nu.is_zero: return fuzzy_not(z0.is_infinite) return fuzzy_not(fuzzy_or([z0.is_zero, z0.is_infinite])) def _eval_expand_func(self, **hints): nu, z, f = self.order, self.argument, self.__class__ if nu.is_real: if (nu - 1).is_positive: return (-self._a*self._b*f(nu - 2, z)._eval_expand_func() + 2*self._a*(nu - 1)*f(nu - 1, z)._eval_expand_func()/z) elif (nu + 1).is_negative: return (2*self._b*(nu + 1)*f(nu + 1, z)._eval_expand_func()/z - self._a*self._b*f(nu + 2, z)._eval_expand_func()) return self def _eval_simplify(self, **kwargs): from sympy.simplify.simplify import besselsimp return besselsimp(self) class besselj(BesselBase): r""" Bessel function of the first kind. Explanation =========== The Bessel $J$ function of order $\nu$ is defined to be the function satisfying Bessel's differential equation .. math :: z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2} + z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 - \nu^2) w = 0, with Laurent expansion .. math :: J_\nu(z) = z^\nu \left(\frac{1}{\Gamma(\nu + 1) 2^\nu} + O(z^2) \right), if $\nu$ is not a negative integer. If $\nu=-n \in \mathbb{Z}_{<0}$ *is* a negative integer, then the definition is .. math :: J_{-n}(z) = (-1)^n J_n(z). Examples ======== Create a Bessel function object: >>> from sympy import besselj, jn >>> from sympy.abc import z, n >>> b = besselj(n, z) Differentiate it: >>> b.diff(z) besselj(n - 1, z)/2 - besselj(n + 1, z)/2 Rewrite in terms of spherical Bessel functions: >>> b.rewrite(jn) sqrt(2)*sqrt(z)*jn(n - 1/2, z)/sqrt(pi) Access the parameter and argument: >>> b.order n >>> b.argument z See Also ======== bessely, besseli, besselk References ========== .. [1] Abramowitz, Milton; Stegun, Irene A., eds. (1965), "Chapter 9", Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables .. [2] Luke, Y. L. (1969), The Special Functions and Their Approximations, Volume 1 .. [3] https://en.wikipedia.org/wiki/Bessel_function .. [4] http://functions.wolfram.com/Bessel-TypeFunctions/BesselJ/ """ _a = S.One _b = S.One @classmethod def eval(cls, nu, z): if z.is_zero: if nu.is_zero: return S.One elif (nu.is_integer and nu.is_zero is False) or re(nu).is_positive: return S.Zero elif re(nu).is_negative and not (nu.is_integer is True): return S.ComplexInfinity elif nu.is_imaginary: return S.NaN if z is S.Infinity or (z is S.NegativeInfinity): return S.Zero if z.could_extract_minus_sign(): return (z)**nu*(-z)**(-nu)*besselj(nu, -z) if nu.is_integer: if nu.could_extract_minus_sign(): return S.NegativeOne**(-nu)*besselj(-nu, z) newz = z.extract_multiplicatively(I) if newz: # NOTE we don't want to change the function if z==0 return I**(nu)*besseli(nu, newz) # branch handling: from sympy import unpolarify if nu.is_integer: newz = unpolarify(z) if newz != z: return besselj(nu, newz) else: newz, n = z.extract_branch_factor() if n != 0: return exp(2*n*pi*nu*I)*besselj(nu, newz) nnu = unpolarify(nu) if nu != nnu: return besselj(nnu, z) def _eval_rewrite_as_besseli(self, nu, z, **kwargs): from sympy import polar_lift return exp(I*pi*nu/2)*besseli(nu, polar_lift(-I)*z) def _eval_rewrite_as_bessely(self, nu, z, **kwargs): if nu.is_integer is False: return csc(pi*nu)*bessely(-nu, z) - cot(pi*nu)*bessely(nu, z) def _eval_rewrite_as_jn(self, nu, z, **kwargs): return sqrt(2*z/pi)*jn(nu - S.Half, self.argument) def _eval_as_leading_term(self, x, logx=None, cdir=0): nu, z = self.args arg = z.as_leading_term(x) if x in arg.free_symbols: return arg**nu/(2**nu*gamma(nu + 1)) else: return self.func(nu, z.subs(x, 0)) def _eval_is_extended_real(self): nu, z = self.args if nu.is_integer and z.is_extended_real: return True def _eval_nseries(self, x, n, logx, cdir=0): from sympy.series.order import Order nu, z = self.args # In case of powers less than 1, number of terms need to be computed # separately to avoid repeated callings of _eval_nseries with wrong n try: _, exp = z.leadterm(x) except (ValueError, NotImplementedError): return self if exp.is_positive: newn = ceiling(n/exp) o = Order(x**n, x) r = (z/2)._eval_nseries(x, n, logx, cdir).removeO() if r is S.Zero: return o t = (_mexpand(r**2) + o).removeO() term = r**nu/gamma(nu + 1) s = [term] for k in range(1, (newn + 1)//2): term *= -t/(k*(nu + k)) term = (_mexpand(term) + o).removeO() s.append(term) return Add(*s) + o return super(besselj, self)._eval_nseries(x, n, logx, cdir) class bessely(BesselBase): r""" Bessel function of the second kind. Explanation =========== The Bessel $Y$ function of order $\nu$ is defined as .. math :: Y_\nu(z) = \lim_{\mu \to \nu} \frac{J_\mu(z) \cos(\pi \mu) - J_{-\mu}(z)}{\sin(\pi \mu)}, where $J_\mu(z)$ is the Bessel function of the first kind. It is a solution to Bessel's equation, and linearly independent from $J_\nu$. Examples ======== >>> from sympy import bessely, yn >>> from sympy.abc import z, n >>> b = bessely(n, z) >>> b.diff(z) bessely(n - 1, z)/2 - bessely(n + 1, z)/2 >>> b.rewrite(yn) sqrt(2)*sqrt(z)*yn(n - 1/2, z)/sqrt(pi) See Also ======== besselj, besseli, besselk References ========== .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/BesselY/ """ _a = S.One _b = S.One @classmethod def eval(cls, nu, z): if z.is_zero: if nu.is_zero: return S.NegativeInfinity elif re(nu).is_zero is False: return S.ComplexInfinity elif re(nu).is_zero: return S.NaN if z is S.Infinity or z is S.NegativeInfinity: return S.Zero if nu.is_integer: if nu.could_extract_minus_sign(): return S.NegativeOne**(-nu)*bessely(-nu, z) def _eval_rewrite_as_besselj(self, nu, z, **kwargs): if nu.is_integer is False: return csc(pi*nu)*(cos(pi*nu)*besselj(nu, z) - besselj(-nu, z)) def _eval_rewrite_as_besseli(self, nu, z, **kwargs): aj = self._eval_rewrite_as_besselj(*self.args) if aj: return aj.rewrite(besseli) def _eval_rewrite_as_yn(self, nu, z, **kwargs): return sqrt(2*z/pi) * yn(nu - S.Half, self.argument) def _eval_as_leading_term(self, x, logx=None, cdir=0): nu, z = self.args term_one = ((2/pi)*log(z/2)*besselj(nu, z)) term_two = (z/2)**(-nu)*factorial(nu - 1)/pi if (nu - 1).is_positive else S.Zero term_three = (z/2)**nu/(pi*factorial(nu))*(digamma(nu + 1) - S.EulerGamma) arg = Add(*[term_one, term_two, term_three]).as_leading_term(x) if x in arg.free_symbols: return arg else: return self.func(nu, z.subs(x, 0).cancel()) def _eval_is_extended_real(self): nu, z = self.args if nu.is_integer and z.is_positive: return True def _eval_nseries(self, x, n, logx, cdir=0): from sympy.series.order import Order nu, z = self.args # In case of powers less than 1, number of terms need to be computed # separately to avoid repeated callings of _eval_nseries with wrong n try: _, exp = z.leadterm(x) except (ValueError, NotImplementedError): return self if exp.is_positive and nu.is_integer: newn = ceiling(n/exp) bn = besselj(nu, z) a = ((2/pi)*log(z/2)*bn)._eval_nseries(x, n, logx, cdir) b, c = [], [] o = Order(x**n, x) r = (z/2)._eval_nseries(x, n, logx, cdir).removeO() if r is S.Zero: return o t = (_mexpand(r**2) + o).removeO() if nu > S.One: term = r**(-nu)*factorial(nu - 1)/pi b.append(term) for k in range(1, nu - 1): term *= t*(nu - k - 1)/k term = (_mexpand(term) + o).removeO() b.append(term) p = r**nu/(pi*factorial(nu)) term = p*(digamma(nu + 1) - S.EulerGamma) c.append(term) for k in range(1, (newn + 1)//2): p *= -t/(k*(k + nu)) p = (_mexpand(p) + o).removeO() term = p*(digamma(k + nu + 1) + digamma(k + 1)) c.append(term) return a - Add(*b) - Add(*c) # Order term comes from a return super(bessely, self)._eval_nseries(x, n, logx, cdir) class besseli(BesselBase): r""" Modified Bessel function of the first kind. Explanation =========== The Bessel $I$ function is a solution to the modified Bessel equation .. math :: z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2} + z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 + \nu^2)^2 w = 0. It can be defined as .. math :: I_\nu(z) = i^{-\nu} J_\nu(iz), where $J_\nu(z)$ is the Bessel function of the first kind. Examples ======== >>> from sympy import besseli >>> from sympy.abc import z, n >>> besseli(n, z).diff(z) besseli(n - 1, z)/2 + besseli(n + 1, z)/2 See Also ======== besselj, bessely, besselk References ========== .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/BesselI/ """ _a = -S.One _b = S.One @classmethod def eval(cls, nu, z): if z.is_zero: if nu.is_zero: return S.One elif (nu.is_integer and nu.is_zero is False) or re(nu).is_positive: return S.Zero elif re(nu).is_negative and not (nu.is_integer is True): return S.ComplexInfinity elif nu.is_imaginary: return S.NaN if im(z) is S.Infinity or im(z) is S.NegativeInfinity: return S.Zero if z.could_extract_minus_sign(): return (z)**nu*(-z)**(-nu)*besseli(nu, -z) if nu.is_integer: if nu.could_extract_minus_sign(): return besseli(-nu, z) newz = z.extract_multiplicatively(I) if newz: # NOTE we don't want to change the function if z==0 return I**(-nu)*besselj(nu, -newz) # branch handling: from sympy import unpolarify if nu.is_integer: newz = unpolarify(z) if newz != z: return besseli(nu, newz) else: newz, n = z.extract_branch_factor() if n != 0: return exp(2*n*pi*nu*I)*besseli(nu, newz) nnu = unpolarify(nu) if nu != nnu: return besseli(nnu, z) def _eval_rewrite_as_besselj(self, nu, z, **kwargs): from sympy import polar_lift return exp(-I*pi*nu/2)*besselj(nu, polar_lift(I)*z) def _eval_rewrite_as_bessely(self, nu, z, **kwargs): aj = self._eval_rewrite_as_besselj(*self.args) if aj: return aj.rewrite(bessely) def _eval_rewrite_as_jn(self, nu, z, **kwargs): return self._eval_rewrite_as_besselj(*self.args).rewrite(jn) def _eval_is_extended_real(self): nu, z = self.args if nu.is_integer and z.is_extended_real: return True class besselk(BesselBase): r""" Modified Bessel function of the second kind. Explanation =========== The Bessel $K$ function of order $\nu$ is defined as .. math :: K_\nu(z) = \lim_{\mu \to \nu} \frac{\pi}{2} \frac{I_{-\mu}(z) -I_\mu(z)}{\sin(\pi \mu)}, where $I_\mu(z)$ is the modified Bessel function of the first kind. It is a solution of the modified Bessel equation, and linearly independent from $Y_\nu$. Examples ======== >>> from sympy import besselk >>> from sympy.abc import z, n >>> besselk(n, z).diff(z) -besselk(n - 1, z)/2 - besselk(n + 1, z)/2 See Also ======== besselj, besseli, bessely References ========== .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/BesselK/ """ _a = S.One _b = -S.One @classmethod def eval(cls, nu, z): if z.is_zero: if nu.is_zero: return S.Infinity elif re(nu).is_zero is False: return S.ComplexInfinity elif re(nu).is_zero: return S.NaN if z in (S.Infinity, I*S.Infinity, I*S.NegativeInfinity): return S.Zero if nu.is_integer: if nu.could_extract_minus_sign(): return besselk(-nu, z) def _eval_rewrite_as_besseli(self, nu, z, **kwargs): if nu.is_integer is False: return pi*csc(pi*nu)*(besseli(-nu, z) - besseli(nu, z))/2 def _eval_rewrite_as_besselj(self, nu, z, **kwargs): ai = self._eval_rewrite_as_besseli(*self.args) if ai: return ai.rewrite(besselj) def _eval_rewrite_as_bessely(self, nu, z, **kwargs): aj = self._eval_rewrite_as_besselj(*self.args) if aj: return aj.rewrite(bessely) def _eval_rewrite_as_yn(self, nu, z, **kwargs): ay = self._eval_rewrite_as_bessely(*self.args) if ay: return ay.rewrite(yn) def _eval_is_extended_real(self): nu, z = self.args if nu.is_integer and z.is_positive: return True class hankel1(BesselBase): r""" Hankel function of the first kind. Explanation =========== This function is defined as .. math :: H_\nu^{(1)} = J_\nu(z) + iY_\nu(z), where $J_\nu(z)$ is the Bessel function of the first kind, and $Y_\nu(z)$ is the Bessel function of the second kind. It is a solution to Bessel's equation. Examples ======== >>> from sympy import hankel1 >>> from sympy.abc import z, n >>> hankel1(n, z).diff(z) hankel1(n - 1, z)/2 - hankel1(n + 1, z)/2 See Also ======== hankel2, besselj, bessely References ========== .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/HankelH1/ """ _a = S.One _b = S.One def _eval_conjugate(self): z = self.argument if z.is_extended_negative is False: return hankel2(self.order.conjugate(), z.conjugate()) class hankel2(BesselBase): r""" Hankel function of the second kind. Explanation =========== This function is defined as .. math :: H_\nu^{(2)} = J_\nu(z) - iY_\nu(z), where $J_\nu(z)$ is the Bessel function of the first kind, and $Y_\nu(z)$ is the Bessel function of the second kind. It is a solution to Bessel's equation, and linearly independent from $H_\nu^{(1)}$. Examples ======== >>> from sympy import hankel2 >>> from sympy.abc import z, n >>> hankel2(n, z).diff(z) hankel2(n - 1, z)/2 - hankel2(n + 1, z)/2 See Also ======== hankel1, besselj, bessely References ========== .. [1] http://functions.wolfram.com/Bessel-TypeFunctions/HankelH2/ """ _a = S.One _b = S.One def _eval_conjugate(self): z = self.argument if z.is_extended_negative is False: return hankel1(self.order.conjugate(), z.conjugate()) def assume_integer_order(fn): @wraps(fn) def g(self, nu, z): if nu.is_integer: return fn(self, nu, z) return g class SphericalBesselBase(BesselBase): """ Base class for spherical Bessel functions. These are thin wrappers around ordinary Bessel functions, since spherical Bessel functions differ from the ordinary ones just by a slight change in order. To use this class, define the ``_eval_evalf()`` and ``_expand()`` methods. """ def _expand(self, **hints): """ Expand self into a polynomial. Nu is guaranteed to be Integer. """ raise NotImplementedError('expansion') def _eval_expand_func(self, **hints): if self.order.is_Integer: return self._expand(**hints) return self def fdiff(self, argindex=2): if argindex != 2: raise ArgumentIndexError(self, argindex) return self.__class__(self.order - 1, self.argument) - \ self * (self.order + 1)/self.argument def _jn(n, z): return fn(n, z)*sin(z) + (-1)**(n + 1)*fn(-n - 1, z)*cos(z) def _yn(n, z): # (-1)**(n + 1) * _jn(-n - 1, z) return (-1)**(n + 1) * fn(-n - 1, z)*sin(z) - fn(n, z)*cos(z) class jn(SphericalBesselBase): r""" Spherical Bessel function of the first kind. Explanation =========== This function is a solution to the spherical Bessel equation .. math :: z^2 \frac{\mathrm{d}^2 w}{\mathrm{d}z^2} + 2z \frac{\mathrm{d}w}{\mathrm{d}z} + (z^2 - \nu(\nu + 1)) w = 0. It can be defined as .. math :: j_\nu(z) = \sqrt{\frac{\pi}{2z}} J_{\nu + \frac{1}{2}}(z), where $J_\nu(z)$ is the Bessel function of the first kind. The spherical Bessel functions of integral order are calculated using the formula: .. math:: j_n(z) = f_n(z) \sin{z} + (-1)^{n+1} f_{-n-1}(z) \cos{z}, where the coefficients $f_n(z)$ are available as :func:`sympy.polys.orthopolys.spherical_bessel_fn`. Examples ======== >>> from sympy import Symbol, jn, sin, cos, expand_func, besselj, bessely >>> z = Symbol("z") >>> nu = Symbol("nu", integer=True) >>> print(expand_func(jn(0, z))) sin(z)/z >>> expand_func(jn(1, z)) == sin(z)/z**2 - cos(z)/z True >>> expand_func(jn(3, z)) (-6/z**2 + 15/z**4)*sin(z) + (1/z - 15/z**3)*cos(z) >>> jn(nu, z).rewrite(besselj) sqrt(2)*sqrt(pi)*sqrt(1/z)*besselj(nu + 1/2, z)/2 >>> jn(nu, z).rewrite(bessely) (-1)**nu*sqrt(2)*sqrt(pi)*sqrt(1/z)*bessely(-nu - 1/2, z)/2 >>> jn(2, 5.2+0.3j).evalf(20) 0.099419756723640344491 - 0.054525080242173562897*I See Also ======== besselj, bessely, besselk, yn References ========== .. [1] http://dlmf.nist.gov/10.47 """ @classmethod def eval(cls, nu, z): if z.is_zero: if nu.is_zero: return S.One elif nu.is_integer: if nu.is_positive: return S.Zero else: return S.ComplexInfinity if z in (S.NegativeInfinity, S.Infinity): return S.Zero def _eval_rewrite_as_besselj(self, nu, z, **kwargs): return sqrt(pi/(2*z)) * besselj(nu + S.Half, z) def _eval_rewrite_as_bessely(self, nu, z, **kwargs): return (-1)**nu * sqrt(pi/(2*z)) * bessely(-nu - S.Half, z) def _eval_rewrite_as_yn(self, nu, z, **kwargs): return (-1)**(nu) * yn(-nu - 1, z) def _expand(self, **hints): return _jn(self.order, self.argument) def _eval_evalf(self, prec): if self.order.is_Integer: return self.rewrite(besselj)._eval_evalf(prec) class yn(SphericalBesselBase): r""" Spherical Bessel function of the second kind. Explanation =========== This function is another solution to the spherical Bessel equation, and linearly independent from $j_n$. It can be defined as .. math :: y_\nu(z) = \sqrt{\frac{\pi}{2z}} Y_{\nu + \frac{1}{2}}(z), where $Y_\nu(z)$ is the Bessel function of the second kind. For integral orders $n$, $y_n$ is calculated using the formula: .. math:: y_n(z) = (-1)^{n+1} j_{-n-1}(z) Examples ======== >>> from sympy import Symbol, yn, sin, cos, expand_func, besselj, bessely >>> z = Symbol("z") >>> nu = Symbol("nu", integer=True) >>> print(expand_func(yn(0, z))) -cos(z)/z >>> expand_func(yn(1, z)) == -cos(z)/z**2-sin(z)/z True >>> yn(nu, z).rewrite(besselj) (-1)**(nu + 1)*sqrt(2)*sqrt(pi)*sqrt(1/z)*besselj(-nu - 1/2, z)/2 >>> yn(nu, z).rewrite(bessely) sqrt(2)*sqrt(pi)*sqrt(1/z)*bessely(nu + 1/2, z)/2 >>> yn(2, 5.2+0.3j).evalf(20) 0.18525034196069722536 + 0.014895573969924817587*I See Also ======== besselj, bessely, besselk, jn References ========== .. [1] http://dlmf.nist.gov/10.47 """ @assume_integer_order def _eval_rewrite_as_besselj(self, nu, z, **kwargs): return (-1)**(nu+1) * sqrt(pi/(2*z)) * besselj(-nu - S.Half, z) @assume_integer_order def _eval_rewrite_as_bessely(self, nu, z, **kwargs): return sqrt(pi/(2*z)) * bessely(nu + S.Half, z) def _eval_rewrite_as_jn(self, nu, z, **kwargs): return (-1)**(nu + 1) * jn(-nu - 1, z) def _expand(self, **hints): return _yn(self.order, self.argument) def _eval_evalf(self, prec): if self.order.is_Integer: return self.rewrite(bessely)._eval_evalf(prec) class SphericalHankelBase(SphericalBesselBase): @assume_integer_order def _eval_rewrite_as_besselj(self, nu, z, **kwargs): # jn +- I*yn # jn as beeselj: sqrt(pi/(2*z)) * besselj(nu + S.Half, z) # yn as besselj: (-1)**(nu+1) * sqrt(pi/(2*z)) * besselj(-nu - S.Half, z) hks = self._hankel_kind_sign return sqrt(pi/(2*z))*(besselj(nu + S.Half, z) + hks*I*(-1)**(nu+1)*besselj(-nu - S.Half, z)) @assume_integer_order def _eval_rewrite_as_bessely(self, nu, z, **kwargs): # jn +- I*yn # jn as bessely: (-1)**nu * sqrt(pi/(2*z)) * bessely(-nu - S.Half, z) # yn as bessely: sqrt(pi/(2*z)) * bessely(nu + S.Half, z) hks = self._hankel_kind_sign return sqrt(pi/(2*z))*((-1)**nu*bessely(-nu - S.Half, z) + hks*I*bessely(nu + S.Half, z)) def _eval_rewrite_as_yn(self, nu, z, **kwargs): hks = self._hankel_kind_sign return jn(nu, z).rewrite(yn) + hks*I*yn(nu, z) def _eval_rewrite_as_jn(self, nu, z, **kwargs): hks = self._hankel_kind_sign return jn(nu, z) + hks*I*yn(nu, z).rewrite(jn) def _eval_expand_func(self, **hints): if self.order.is_Integer: return self._expand(**hints) else: nu = self.order z = self.argument hks = self._hankel_kind_sign return jn(nu, z) + hks*I*yn(nu, z) def _expand(self, **hints): n = self.order z = self.argument hks = self._hankel_kind_sign # fully expanded version # return ((fn(n, z) * sin(z) + # (-1)**(n + 1) * fn(-n - 1, z) * cos(z)) + # jn # (hks * I * (-1)**(n + 1) * # (fn(-n - 1, z) * hk * I * sin(z) + # (-1)**(-n) * fn(n, z) * I * cos(z))) # +-I*yn # ) return (_jn(n, z) + hks*I*_yn(n, z)).expand() def _eval_evalf(self, prec): if self.order.is_Integer: return self.rewrite(besselj)._eval_evalf(prec) class hn1(SphericalHankelBase): r""" Spherical Hankel function of the first kind. Explanation =========== This function is defined as .. math:: h_\nu^(1)(z) = j_\nu(z) + i y_\nu(z), where $j_\nu(z)$ and $y_\nu(z)$ are the spherical Bessel function of the first and second kinds. For integral orders $n$, $h_n^(1)$ is calculated using the formula: .. math:: h_n^(1)(z) = j_{n}(z) + i (-1)^{n+1} j_{-n-1}(z) Examples ======== >>> from sympy import Symbol, hn1, hankel1, expand_func, yn, jn >>> z = Symbol("z") >>> nu = Symbol("nu", integer=True) >>> print(expand_func(hn1(nu, z))) jn(nu, z) + I*yn(nu, z) >>> print(expand_func(hn1(0, z))) sin(z)/z - I*cos(z)/z >>> print(expand_func(hn1(1, z))) -I*sin(z)/z - cos(z)/z + sin(z)/z**2 - I*cos(z)/z**2 >>> hn1(nu, z).rewrite(jn) (-1)**(nu + 1)*I*jn(-nu - 1, z) + jn(nu, z) >>> hn1(nu, z).rewrite(yn) (-1)**nu*yn(-nu - 1, z) + I*yn(nu, z) >>> hn1(nu, z).rewrite(hankel1) sqrt(2)*sqrt(pi)*sqrt(1/z)*hankel1(nu, z)/2 See Also ======== hn2, jn, yn, hankel1, hankel2 References ========== .. [1] http://dlmf.nist.gov/10.47 """ _hankel_kind_sign = S.One @assume_integer_order def _eval_rewrite_as_hankel1(self, nu, z, **kwargs): return sqrt(pi/(2*z))*hankel1(nu, z) class hn2(SphericalHankelBase): r""" Spherical Hankel function of the second kind. Explanation =========== This function is defined as .. math:: h_\nu^(2)(z) = j_\nu(z) - i y_\nu(z), where $j_\nu(z)$ and $y_\nu(z)$ are the spherical Bessel function of the first and second kinds. For integral orders $n$, $h_n^(2)$ is calculated using the formula: .. math:: h_n^(2)(z) = j_{n} - i (-1)^{n+1} j_{-n-1}(z) Examples ======== >>> from sympy import Symbol, hn2, hankel2, expand_func, jn, yn >>> z = Symbol("z") >>> nu = Symbol("nu", integer=True) >>> print(expand_func(hn2(nu, z))) jn(nu, z) - I*yn(nu, z) >>> print(expand_func(hn2(0, z))) sin(z)/z + I*cos(z)/z >>> print(expand_func(hn2(1, z))) I*sin(z)/z - cos(z)/z + sin(z)/z**2 + I*cos(z)/z**2 >>> hn2(nu, z).rewrite(hankel2) sqrt(2)*sqrt(pi)*sqrt(1/z)*hankel2(nu, z)/2 >>> hn2(nu, z).rewrite(jn) -(-1)**(nu + 1)*I*jn(-nu - 1, z) + jn(nu, z) >>> hn2(nu, z).rewrite(yn) (-1)**nu*yn(-nu - 1, z) - I*yn(nu, z) See Also ======== hn1, jn, yn, hankel1, hankel2 References ========== .. [1] http://dlmf.nist.gov/10.47 """ _hankel_kind_sign = -S.One @assume_integer_order def _eval_rewrite_as_hankel2(self, nu, z, **kwargs): return sqrt(pi/(2*z))*hankel2(nu, z) def jn_zeros(n, k, method="sympy", dps=15): """ Zeros of the spherical Bessel function of the first kind. Explanation =========== This returns an array of zeros of $jn$ up to the $k$-th zero. * method = "sympy": uses `mpmath.besseljzero `_ * method = "scipy": uses the `SciPy's sph_jn `_ and `newton `_ to find all roots, which is faster than computing the zeros using a general numerical solver, but it requires SciPy and only works with low precision floating point numbers. (The function used with method="sympy" is a recent addition to mpmath; before that a general solver was used.) Examples ======== >>> from sympy import jn_zeros >>> jn_zeros(2, 4, dps=5) [5.7635, 9.095, 12.323, 15.515] See Also ======== jn, yn, besselj, besselk, bessely Parameters ========== n : integer order of Bessel function k : integer number of zeros to return """ from math import pi if method == "sympy": from mpmath import besseljzero from mpmath.libmp.libmpf import dps_to_prec from sympy import Expr prec = dps_to_prec(dps) return [Expr._from_mpmath(besseljzero(S(n + 0.5)._to_mpmath(prec), int(l)), prec) for l in range(1, k + 1)] elif method == "scipy": from scipy.optimize import newton try: from scipy.special import spherical_jn f = lambda x: spherical_jn(n, x) except ImportError: from scipy.special import sph_jn f = lambda x: sph_jn(n, x)[0][-1] else: raise NotImplementedError("Unknown method.") def solver(f, x): if method == "scipy": root = newton(f, x) else: raise NotImplementedError("Unknown method.") return root # we need to approximate the position of the first root: root = n + pi # determine the first root exactly: root = solver(f, root) roots = [root] for i in range(k - 1): # estimate the position of the next root using the last root + pi: root = solver(f, root + pi) roots.append(root) return roots class AiryBase(Function): """ Abstract base class for Airy functions. This class is meant to reduce code duplication. """ def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def _eval_is_extended_real(self): return self.args[0].is_extended_real def as_real_imag(self, deep=True, **hints): z = self.args[0] zc = z.conjugate() f = self.func u = (f(z)+f(zc))/2 v = I*(f(zc)-f(z))/2 return u, v def _eval_expand_complex(self, deep=True, **hints): re_part, im_part = self.as_real_imag(deep=deep, **hints) return re_part + im_part*S.ImaginaryUnit class airyai(AiryBase): r""" The Airy function $\operatorname{Ai}$ of the first kind. Explanation =========== The Airy function $\operatorname{Ai}(z)$ is defined to be the function satisfying Airy's differential equation .. math:: \frac{\mathrm{d}^2 w(z)}{\mathrm{d}z^2} - z w(z) = 0. Equivalently, for real $z$ .. math:: \operatorname{Ai}(z) := \frac{1}{\pi} \int_0^\infty \cos\left(\frac{t^3}{3} + z t\right) \mathrm{d}t. Examples ======== Create an Airy function object: >>> from sympy import airyai >>> from sympy.abc import z >>> airyai(z) airyai(z) Several special values are known: >>> airyai(0) 3**(1/3)/(3*gamma(2/3)) >>> from sympy import oo >>> airyai(oo) 0 >>> airyai(-oo) 0 The Airy function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(airyai(z)) airyai(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(airyai(z), z) airyaiprime(z) >>> diff(airyai(z), z, 2) z*airyai(z) Series expansion is also supported: >>> from sympy import series >>> series(airyai(z), z, 0, 3) 3**(5/6)*gamma(1/3)/(6*pi) - 3**(1/6)*z*gamma(2/3)/(2*pi) + O(z**3) We can numerically evaluate the Airy function to arbitrary precision on the whole complex plane: >>> airyai(-2).evalf(50) 0.22740742820168557599192443603787379946077222541710 Rewrite $\operatorname{Ai}(z)$ in terms of hypergeometric functions: >>> from sympy import hyper >>> airyai(z).rewrite(hyper) -3**(2/3)*z*hyper((), (4/3,), z**3/9)/(3*gamma(1/3)) + 3**(1/3)*hyper((), (2/3,), z**3/9)/(3*gamma(2/3)) See Also ======== airybi: Airy function of the second kind. airyaiprime: Derivative of the Airy function of the first kind. airybiprime: Derivative of the Airy function of the second kind. References ========== .. [1] https://en.wikipedia.org/wiki/Airy_function .. [2] http://dlmf.nist.gov/9 .. [3] http://www.encyclopediaofmath.org/index.php/Airy_functions .. [4] http://mathworld.wolfram.com/AiryFunctions.html """ nargs = 1 unbranched = True @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero elif arg is S.NegativeInfinity: return S.Zero elif arg.is_zero: return S.One / (3**Rational(2, 3) * gamma(Rational(2, 3))) if arg.is_zero: return S.One / (3**Rational(2, 3) * gamma(Rational(2, 3))) def fdiff(self, argindex=1): if argindex == 1: return airyaiprime(self.args[0]) else: raise ArgumentIndexError(self, argindex) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0: return S.Zero else: x = sympify(x) if len(previous_terms) > 1: p = previous_terms[-1] return ((3**Rational(1, 3)*x)**(-n)*(3**Rational(1, 3)*x)**(n + 1)*sin(pi*(n*Rational(2, 3) + Rational(4, 3)))*factorial(n) * gamma(n/3 + Rational(2, 3))/(sin(pi*(n*Rational(2, 3) + Rational(2, 3)))*factorial(n + 1)*gamma(n/3 + Rational(1, 3))) * p) else: return (S.One/(3**Rational(2, 3)*pi) * gamma((n+S.One)/S(3)) * sin(2*pi*(n+S.One)/S(3)) / factorial(n) * (root(3, 3)*x)**n) def _eval_rewrite_as_besselj(self, z, **kwargs): ot = Rational(1, 3) tt = Rational(2, 3) a = Pow(-z, Rational(3, 2)) if re(z).is_negative: return ot*sqrt(-z) * (besselj(-ot, tt*a) + besselj(ot, tt*a)) def _eval_rewrite_as_besseli(self, z, **kwargs): ot = Rational(1, 3) tt = Rational(2, 3) a = Pow(z, Rational(3, 2)) if re(z).is_positive: return ot*sqrt(z) * (besseli(-ot, tt*a) - besseli(ot, tt*a)) else: return ot*(Pow(a, ot)*besseli(-ot, tt*a) - z*Pow(a, -ot)*besseli(ot, tt*a)) def _eval_rewrite_as_hyper(self, z, **kwargs): pf1 = S.One / (3**Rational(2, 3)*gamma(Rational(2, 3))) pf2 = z / (root(3, 3)*gamma(Rational(1, 3))) return pf1 * hyper([], [Rational(2, 3)], z**3/9) - pf2 * hyper([], [Rational(4, 3)], z**3/9) def _eval_expand_func(self, **hints): arg = self.args[0] symbs = arg.free_symbols if len(symbs) == 1: z = symbs.pop() c = Wild("c", exclude=[z]) d = Wild("d", exclude=[z]) m = Wild("m", exclude=[z]) n = Wild("n", exclude=[z]) M = arg.match(c*(d*z**n)**m) if M is not None: m = M[m] # The transformation is given by 03.05.16.0001.01 # http://functions.wolfram.com/Bessel-TypeFunctions/AiryAi/16/01/01/0001/ if (3*m).is_integer: c = M[c] d = M[d] n = M[n] pf = (d * z**n)**m / (d**m * z**(m*n)) newarg = c * d**m * z**(m*n) return S.Half * ((pf + S.One)*airyai(newarg) - (pf - S.One)/sqrt(3)*airybi(newarg)) class airybi(AiryBase): r""" The Airy function $\operatorname{Bi}$ of the second kind. Explanation =========== The Airy function $\operatorname{Bi}(z)$ is defined to be the function satisfying Airy's differential equation .. math:: \frac{\mathrm{d}^2 w(z)}{\mathrm{d}z^2} - z w(z) = 0. Equivalently, for real $z$ .. math:: \operatorname{Bi}(z) := \frac{1}{\pi} \int_0^\infty \exp\left(-\frac{t^3}{3} + z t\right) + \sin\left(\frac{t^3}{3} + z t\right) \mathrm{d}t. Examples ======== Create an Airy function object: >>> from sympy import airybi >>> from sympy.abc import z >>> airybi(z) airybi(z) Several special values are known: >>> airybi(0) 3**(5/6)/(3*gamma(2/3)) >>> from sympy import oo >>> airybi(oo) oo >>> airybi(-oo) 0 The Airy function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(airybi(z)) airybi(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(airybi(z), z) airybiprime(z) >>> diff(airybi(z), z, 2) z*airybi(z) Series expansion is also supported: >>> from sympy import series >>> series(airybi(z), z, 0, 3) 3**(1/3)*gamma(1/3)/(2*pi) + 3**(2/3)*z*gamma(2/3)/(2*pi) + O(z**3) We can numerically evaluate the Airy function to arbitrary precision on the whole complex plane: >>> airybi(-2).evalf(50) -0.41230258795639848808323405461146104203453483447240 Rewrite $\operatorname{Bi}(z)$ in terms of hypergeometric functions: >>> from sympy import hyper >>> airybi(z).rewrite(hyper) 3**(1/6)*z*hyper((), (4/3,), z**3/9)/gamma(1/3) + 3**(5/6)*hyper((), (2/3,), z**3/9)/(3*gamma(2/3)) See Also ======== airyai: Airy function of the first kind. airyaiprime: Derivative of the Airy function of the first kind. airybiprime: Derivative of the Airy function of the second kind. References ========== .. [1] https://en.wikipedia.org/wiki/Airy_function .. [2] http://dlmf.nist.gov/9 .. [3] http://www.encyclopediaofmath.org/index.php/Airy_functions .. [4] http://mathworld.wolfram.com/AiryFunctions.html """ nargs = 1 unbranched = True @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Zero elif arg.is_zero: return S.One / (3**Rational(1, 6) * gamma(Rational(2, 3))) if arg.is_zero: return S.One / (3**Rational(1, 6) * gamma(Rational(2, 3))) def fdiff(self, argindex=1): if argindex == 1: return airybiprime(self.args[0]) else: raise ArgumentIndexError(self, argindex) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0: return S.Zero else: x = sympify(x) if len(previous_terms) > 1: p = previous_terms[-1] return (3**Rational(1, 3)*x * Abs(sin(2*pi*(n + S.One)/S(3))) * factorial((n - S.One)/S(3)) / ((n + S.One) * Abs(cos(2*pi*(n + S.Half)/S(3))) * factorial((n - 2)/S(3))) * p) else: return (S.One/(root(3, 6)*pi) * gamma((n + S.One)/S(3)) * Abs(sin(2*pi*(n + S.One)/S(3))) / factorial(n) * (root(3, 3)*x)**n) def _eval_rewrite_as_besselj(self, z, **kwargs): ot = Rational(1, 3) tt = Rational(2, 3) a = Pow(-z, Rational(3, 2)) if re(z).is_negative: return sqrt(-z/3) * (besselj(-ot, tt*a) - besselj(ot, tt*a)) def _eval_rewrite_as_besseli(self, z, **kwargs): ot = Rational(1, 3) tt = Rational(2, 3) a = Pow(z, Rational(3, 2)) if re(z).is_positive: return sqrt(z)/sqrt(3) * (besseli(-ot, tt*a) + besseli(ot, tt*a)) else: b = Pow(a, ot) c = Pow(a, -ot) return sqrt(ot)*(b*besseli(-ot, tt*a) + z*c*besseli(ot, tt*a)) def _eval_rewrite_as_hyper(self, z, **kwargs): pf1 = S.One / (root(3, 6)*gamma(Rational(2, 3))) pf2 = z*root(3, 6) / gamma(Rational(1, 3)) return pf1 * hyper([], [Rational(2, 3)], z**3/9) + pf2 * hyper([], [Rational(4, 3)], z**3/9) def _eval_expand_func(self, **hints): arg = self.args[0] symbs = arg.free_symbols if len(symbs) == 1: z = symbs.pop() c = Wild("c", exclude=[z]) d = Wild("d", exclude=[z]) m = Wild("m", exclude=[z]) n = Wild("n", exclude=[z]) M = arg.match(c*(d*z**n)**m) if M is not None: m = M[m] # The transformation is given by 03.06.16.0001.01 # http://functions.wolfram.com/Bessel-TypeFunctions/AiryBi/16/01/01/0001/ if (3*m).is_integer: c = M[c] d = M[d] n = M[n] pf = (d * z**n)**m / (d**m * z**(m*n)) newarg = c * d**m * z**(m*n) return S.Half * (sqrt(3)*(S.One - pf)*airyai(newarg) + (S.One + pf)*airybi(newarg)) class airyaiprime(AiryBase): r""" The derivative $\operatorname{Ai}^\prime$ of the Airy function of the first kind. Explanation =========== The Airy function $\operatorname{Ai}^\prime(z)$ is defined to be the function .. math:: \operatorname{Ai}^\prime(z) := \frac{\mathrm{d} \operatorname{Ai}(z)}{\mathrm{d} z}. Examples ======== Create an Airy function object: >>> from sympy import airyaiprime >>> from sympy.abc import z >>> airyaiprime(z) airyaiprime(z) Several special values are known: >>> airyaiprime(0) -3**(2/3)/(3*gamma(1/3)) >>> from sympy import oo >>> airyaiprime(oo) 0 The Airy function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(airyaiprime(z)) airyaiprime(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(airyaiprime(z), z) z*airyai(z) >>> diff(airyaiprime(z), z, 2) z*airyaiprime(z) + airyai(z) Series expansion is also supported: >>> from sympy import series >>> series(airyaiprime(z), z, 0, 3) -3**(2/3)/(3*gamma(1/3)) + 3**(1/3)*z**2/(6*gamma(2/3)) + O(z**3) We can numerically evaluate the Airy function to arbitrary precision on the whole complex plane: >>> airyaiprime(-2).evalf(50) 0.61825902074169104140626429133247528291577794512415 Rewrite $\operatorname{Ai}^\prime(z)$ in terms of hypergeometric functions: >>> from sympy import hyper >>> airyaiprime(z).rewrite(hyper) 3**(1/3)*z**2*hyper((), (5/3,), z**3/9)/(6*gamma(2/3)) - 3**(2/3)*hyper((), (1/3,), z**3/9)/(3*gamma(1/3)) See Also ======== airyai: Airy function of the first kind. airybi: Airy function of the second kind. airybiprime: Derivative of the Airy function of the second kind. References ========== .. [1] https://en.wikipedia.org/wiki/Airy_function .. [2] http://dlmf.nist.gov/9 .. [3] http://www.encyclopediaofmath.org/index.php/Airy_functions .. [4] http://mathworld.wolfram.com/AiryFunctions.html """ nargs = 1 unbranched = True @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero if arg.is_zero: return S.NegativeOne / (3**Rational(1, 3) * gamma(Rational(1, 3))) def fdiff(self, argindex=1): if argindex == 1: return self.args[0]*airyai(self.args[0]) else: raise ArgumentIndexError(self, argindex) def _eval_evalf(self, prec): from mpmath import mp, workprec from sympy import Expr z = self.args[0]._to_mpmath(prec) with workprec(prec): res = mp.airyai(z, derivative=1) return Expr._from_mpmath(res, prec) def _eval_rewrite_as_besselj(self, z, **kwargs): tt = Rational(2, 3) a = Pow(-z, Rational(3, 2)) if re(z).is_negative: return z/3 * (besselj(-tt, tt*a) - besselj(tt, tt*a)) def _eval_rewrite_as_besseli(self, z, **kwargs): ot = Rational(1, 3) tt = Rational(2, 3) a = tt * Pow(z, Rational(3, 2)) if re(z).is_positive: return z/3 * (besseli(tt, a) - besseli(-tt, a)) else: a = Pow(z, Rational(3, 2)) b = Pow(a, tt) c = Pow(a, -tt) return ot * (z**2*c*besseli(tt, tt*a) - b*besseli(-ot, tt*a)) def _eval_rewrite_as_hyper(self, z, **kwargs): pf1 = z**2 / (2*3**Rational(2, 3)*gamma(Rational(2, 3))) pf2 = 1 / (root(3, 3)*gamma(Rational(1, 3))) return pf1 * hyper([], [Rational(5, 3)], z**3/9) - pf2 * hyper([], [Rational(1, 3)], z**3/9) def _eval_expand_func(self, **hints): arg = self.args[0] symbs = arg.free_symbols if len(symbs) == 1: z = symbs.pop() c = Wild("c", exclude=[z]) d = Wild("d", exclude=[z]) m = Wild("m", exclude=[z]) n = Wild("n", exclude=[z]) M = arg.match(c*(d*z**n)**m) if M is not None: m = M[m] # The transformation is in principle # given by 03.07.16.0001.01 but note # that there is an error in this formula. # http://functions.wolfram.com/Bessel-TypeFunctions/AiryAiPrime/16/01/01/0001/ if (3*m).is_integer: c = M[c] d = M[d] n = M[n] pf = (d**m * z**(n*m)) / (d * z**n)**m newarg = c * d**m * z**(n*m) return S.Half * ((pf + S.One)*airyaiprime(newarg) + (pf - S.One)/sqrt(3)*airybiprime(newarg)) class airybiprime(AiryBase): r""" The derivative $\operatorname{Bi}^\prime$ of the Airy function of the first kind. Explanation =========== The Airy function $\operatorname{Bi}^\prime(z)$ is defined to be the function .. math:: \operatorname{Bi}^\prime(z) := \frac{\mathrm{d} \operatorname{Bi}(z)}{\mathrm{d} z}. Examples ======== Create an Airy function object: >>> from sympy import airybiprime >>> from sympy.abc import z >>> airybiprime(z) airybiprime(z) Several special values are known: >>> airybiprime(0) 3**(1/6)/gamma(1/3) >>> from sympy import oo >>> airybiprime(oo) oo >>> airybiprime(-oo) 0 The Airy function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(airybiprime(z)) airybiprime(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(airybiprime(z), z) z*airybi(z) >>> diff(airybiprime(z), z, 2) z*airybiprime(z) + airybi(z) Series expansion is also supported: >>> from sympy import series >>> series(airybiprime(z), z, 0, 3) 3**(1/6)/gamma(1/3) + 3**(5/6)*z**2/(6*gamma(2/3)) + O(z**3) We can numerically evaluate the Airy function to arbitrary precision on the whole complex plane: >>> airybiprime(-2).evalf(50) 0.27879516692116952268509756941098324140300059345163 Rewrite $\operatorname{Bi}^\prime(z)$ in terms of hypergeometric functions: >>> from sympy import hyper >>> airybiprime(z).rewrite(hyper) 3**(5/6)*z**2*hyper((), (5/3,), z**3/9)/(6*gamma(2/3)) + 3**(1/6)*hyper((), (1/3,), z**3/9)/gamma(1/3) See Also ======== airyai: Airy function of the first kind. airybi: Airy function of the second kind. airyaiprime: Derivative of the Airy function of the first kind. References ========== .. [1] https://en.wikipedia.org/wiki/Airy_function .. [2] http://dlmf.nist.gov/9 .. [3] http://www.encyclopediaofmath.org/index.php/Airy_functions .. [4] http://mathworld.wolfram.com/AiryFunctions.html """ nargs = 1 unbranched = True @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif arg is S.NegativeInfinity: return S.Zero elif arg.is_zero: return 3**Rational(1, 6) / gamma(Rational(1, 3)) if arg.is_zero: return 3**Rational(1, 6) / gamma(Rational(1, 3)) def fdiff(self, argindex=1): if argindex == 1: return self.args[0]*airybi(self.args[0]) else: raise ArgumentIndexError(self, argindex) def _eval_evalf(self, prec): from mpmath import mp, workprec from sympy import Expr z = self.args[0]._to_mpmath(prec) with workprec(prec): res = mp.airybi(z, derivative=1) return Expr._from_mpmath(res, prec) def _eval_rewrite_as_besselj(self, z, **kwargs): tt = Rational(2, 3) a = tt * Pow(-z, Rational(3, 2)) if re(z).is_negative: return -z/sqrt(3) * (besselj(-tt, a) + besselj(tt, a)) def _eval_rewrite_as_besseli(self, z, **kwargs): ot = Rational(1, 3) tt = Rational(2, 3) a = tt * Pow(z, Rational(3, 2)) if re(z).is_positive: return z/sqrt(3) * (besseli(-tt, a) + besseli(tt, a)) else: a = Pow(z, Rational(3, 2)) b = Pow(a, tt) c = Pow(a, -tt) return sqrt(ot) * (b*besseli(-tt, tt*a) + z**2*c*besseli(tt, tt*a)) def _eval_rewrite_as_hyper(self, z, **kwargs): pf1 = z**2 / (2*root(3, 6)*gamma(Rational(2, 3))) pf2 = root(3, 6) / gamma(Rational(1, 3)) return pf1 * hyper([], [Rational(5, 3)], z**3/9) + pf2 * hyper([], [Rational(1, 3)], z**3/9) def _eval_expand_func(self, **hints): arg = self.args[0] symbs = arg.free_symbols if len(symbs) == 1: z = symbs.pop() c = Wild("c", exclude=[z]) d = Wild("d", exclude=[z]) m = Wild("m", exclude=[z]) n = Wild("n", exclude=[z]) M = arg.match(c*(d*z**n)**m) if M is not None: m = M[m] # The transformation is in principle # given by 03.08.16.0001.01 but note # that there is an error in this formula. # http://functions.wolfram.com/Bessel-TypeFunctions/AiryBiPrime/16/01/01/0001/ if (3*m).is_integer: c = M[c] d = M[d] n = M[n] pf = (d**m * z**(n*m)) / (d * z**n)**m newarg = c * d**m * z**(n*m) return S.Half * (sqrt(3)*(pf - S.One)*airyaiprime(newarg) + (pf + S.One)*airybiprime(newarg)) class marcumq(Function): r""" The Marcum Q-function. Explanation =========== The Marcum Q-function is defined by the meromorphic continuation of .. math:: Q_m(a, b) = a^{- m + 1} \int_{b}^{\infty} x^{m} e^{- \frac{a^{2}}{2} - \frac{x^{2}}{2}} I_{m - 1}\left(a x\right)\, dx Examples ======== >>> from sympy import marcumq >>> from sympy.abc import m, a, b >>> marcumq(m, a, b) marcumq(m, a, b) Special values: >>> marcumq(m, 0, b) uppergamma(m, b**2/2)/gamma(m) >>> marcumq(0, 0, 0) 0 >>> marcumq(0, a, 0) 1 - exp(-a**2/2) >>> marcumq(1, a, a) 1/2 + exp(-a**2)*besseli(0, a**2)/2 >>> marcumq(2, a, a) 1/2 + exp(-a**2)*besseli(0, a**2)/2 + exp(-a**2)*besseli(1, a**2) Differentiation with respect to $a$ and $b$ is supported: >>> from sympy import diff >>> diff(marcumq(m, a, b), a) a*(-marcumq(m, a, b) + marcumq(m + 1, a, b)) >>> diff(marcumq(m, a, b), b) -a**(1 - m)*b**m*exp(-a**2/2 - b**2/2)*besseli(m - 1, a*b) References ========== .. [1] https://en.wikipedia.org/wiki/Marcum_Q-function .. [2] http://mathworld.wolfram.com/MarcumQ-Function.html """ @classmethod def eval(cls, m, a, b): from sympy import exp, uppergamma if a is S.Zero: if m is S.Zero and b is S.Zero: return S.Zero return uppergamma(m, b**2 * S.Half) / gamma(m) if m is S.Zero and b is S.Zero: return 1 - 1 / exp(a**2 * S.Half) if a == b: if m is S.One: return (1 + exp(-a**2) * besseli(0, a**2))*S.Half if m == 2: return S.Half + S.Half * exp(-a**2) * besseli(0, a**2) + exp(-a**2) * besseli(1, a**2) if a.is_zero: if m.is_zero and b.is_zero: return S.Zero return uppergamma(m, b**2*S.Half) / gamma(m) if m.is_zero and b.is_zero: return 1 - 1 / exp(a**2*S.Half) def fdiff(self, argindex=2): from sympy import exp m, a, b = self.args if argindex == 2: return a * (-marcumq(m, a, b) + marcumq(1+m, a, b)) elif argindex == 3: return (-b**m / a**(m-1)) * exp(-(a**2 + b**2)/2) * besseli(m-1, a*b) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_Integral(self, m, a, b, **kwargs): from sympy import Integral, exp, Dummy, oo x = kwargs.get('x', Dummy('x')) return a ** (1 - m) * \ Integral(x**m * exp(-(x**2 + a**2)/2) * besseli(m-1, a*x), [x, b, oo]) def _eval_rewrite_as_Sum(self, m, a, b, **kwargs): from sympy import Sum, exp, Dummy, oo k = kwargs.get('k', Dummy('k')) return exp(-(a**2 + b**2) / 2) * Sum((a/b)**k * besseli(k, a*b), [k, 1-m, oo]) def _eval_rewrite_as_besseli(self, m, a, b, **kwargs): if a == b: from sympy import exp if m == 1: return (1 + exp(-a**2) * besseli(0, a**2)) / 2 if m.is_Integer and m >= 2: s = sum([besseli(i, a**2) for i in range(1, m)]) return S.Half + exp(-a**2) * besseli(0, a**2) / 2 + exp(-a**2) * s def _eval_is_zero(self): if all(arg.is_zero for arg in self.args): return True sympy-sympy-1.9/sympy/functions/special/beta_functions.py000066400000000000000000000267141412543434000241230ustar00rootroot00000000000000from sympy.core import S from sympy.core.function import Function, ArgumentIndexError from sympy.core.symbol import Dummy from sympy.functions.special.gamma_functions import gamma, digamma from sympy.functions.elementary.complexes import conjugate # See mpmath #569 and SymPy #20569 def betainc_mpmath_fix(a, b, x1, x2, reg=0): from mpmath import betainc, mpf if x1 == x2: return mpf(0) else: return betainc(a, b, x1, x2, reg) ############################################################################### ############################ COMPLETE BETA FUNCTION ########################## ############################################################################### class beta(Function): r""" The beta integral is called the Eulerian integral of the first kind by Legendre: .. math:: \mathrm{B}(x,y) \int^{1}_{0} t^{x-1} (1-t)^{y-1} \mathrm{d}t. Explanation =========== The Beta function or Euler's first integral is closely associated with the gamma function. The Beta function is often used in probability theory and mathematical statistics. It satisfies properties like: .. math:: \mathrm{B}(a,1) = \frac{1}{a} \\ \mathrm{B}(a,b) = \mathrm{B}(b,a) \\ \mathrm{B}(a,b) = \frac{\Gamma(a) \Gamma(b)}{\Gamma(a+b)} Therefore for integral values of $a$ and $b$: .. math:: \mathrm{B} = \frac{(a-1)! (b-1)!}{(a+b-1)!} A special case of the Beta function when `x = y` is the Central Beta function. It satisfies properties like: .. math:: \mathrm{B}(x) = 2^{1 - 2x}\mathrm{B}(x, \frac{1}{2}) \mathrm{B}(x) = 2^{1 - 2x} cos(\pi x) \mathrm{B}(\frac{1}{2} - x, x) \mathrm{B}(x) = \int_{0}^{1} \frac{t^x}{(1 + t)^{2x}} dt \mathrm{B}(x) = \frac{2}{x} \prod_{n = 1}^{\infty} \frac{n(n + 2x)}{(n + x)^2} Examples ======== >>> from sympy import I, pi >>> from sympy.abc import x, y The Beta function obeys the mirror symmetry: >>> from sympy import beta, conjugate >>> conjugate(beta(x, y)) beta(conjugate(x), conjugate(y)) Differentiation with respect to both $x$ and $y$ is supported: >>> from sympy import beta, diff >>> diff(beta(x, y), x) (polygamma(0, x) - polygamma(0, x + y))*beta(x, y) >>> diff(beta(x, y), y) (polygamma(0, y) - polygamma(0, x + y))*beta(x, y) >>> diff(beta(x), x) 2*(polygamma(0, x) - polygamma(0, 2*x))*beta(x, x) We can numerically evaluate the Beta function to arbitrary precision for any complex numbers x and y: >>> from sympy import beta >>> beta(pi).evalf(40) 0.02671848900111377452242355235388489324562 >>> beta(1 + I).evalf(20) -0.2112723729365330143 - 0.7655283165378005676*I See Also ======== gamma: Gamma function. uppergamma: Upper incomplete gamma function. lowergamma: Lower incomplete gamma function. polygamma: Polygamma function. loggamma: Log Gamma function. digamma: Digamma function. trigamma: Trigamma function. References ========== .. [1] https://en.wikipedia.org/wiki/Beta_function .. [2] http://mathworld.wolfram.com/BetaFunction.html .. [3] http://dlmf.nist.gov/5.12 """ unbranched = True def fdiff(self, argindex): x, y = self.args if argindex == 1: # Diff wrt x return beta(x, y)*(digamma(x) - digamma(x + y)) elif argindex == 2: # Diff wrt y return beta(x, y)*(digamma(y) - digamma(x + y)) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, x, y=None): if y is None: return beta(x, x) if y is S.One: return 1/x if x is S.One: return 1/y def _eval_expand_func(self, **hints): x, y = self.args return gamma(x)*gamma(y) / gamma(x + y) def _eval_is_real(self): return self.args[0].is_real and self.args[1].is_real def _eval_conjugate(self): return self.func(self.args[0].conjugate(), self.args[1].conjugate()) def _eval_rewrite_as_gamma(self, x, y, piecewise=True, **kwargs): return self._eval_expand_func(**kwargs) def _eval_rewrite_as_Integral(self, x, y, **kwargs): from sympy.integrals.integrals import Integral t = Dummy('t') return Integral(t**(x - 1)*(1 - t)**(y - 1), (t, 0, 1)) ############################################################################### ########################## INCOMPLETE BETA FUNCTION ########################### ############################################################################### class betainc(Function): r""" The Generalized Incomplete Beta function is defined as .. math:: \mathrm{B}_{(x_1, x_2)}(a, b) = \int_{x_1}^{x_2} t^{a - 1} (1 - t)^{b - 1} dt The Incomplete Beta function is a special case of the Generalized Incomplete Beta function : .. math:: \mathrm{B}_z (a, b) = \mathrm{B}_{(0, z)}(a, b) The Incomplete Beta function satisfies : .. math:: \mathrm{B}_z (a, b) = (-1)^a \mathrm{B}_{\frac{z}{z - 1}} (a, 1 - a - b) The Beta function is a special case of the Incomplete Beta function : .. math:: \mathrm{B}(a, b) = \mathrm{B}_{1}(a, b) Examples ======== >>> from sympy import betainc, symbols, conjugate >>> a, b, x, x1, x2 = symbols('a b x x1 x2') The Generalized Incomplete Beta function is given by: >>> betainc(a, b, x1, x2) betainc(a, b, x1, x2) The Incomplete Beta function can be obtained as follows: >>> betainc(a, b, 0, x) betainc(a, b, 0, x) The Incomplete Beta function obeys the mirror symmetry: >>> conjugate(betainc(a, b, x1, x2)) betainc(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2)) We can numerically evaluate the Incomplete Beta function to arbitrary precision for any complex numbers a, b, x1 and x2: >>> from sympy import betainc, I >>> betainc(2, 3, 4, 5).evalf(10) 56.08333333 >>> betainc(0.75, 1 - 4*I, 0, 2 + 3*I).evalf(25) 0.2241657956955709603655887 + 0.3619619242700451992411724*I The Generalized Incomplete Beta function can be expressed in terms of the Generalized Hypergeometric function. >>> from sympy import hyper >>> betainc(a, b, x1, x2).rewrite(hyper) (-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/a See Also ======== beta: Beta function hyper: Generalized Hypergeometric function References ========== .. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function .. [2] https://dlmf.nist.gov/8.17 .. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/ .. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/ """ nargs = 4 unbranched = True def fdiff(self, argindex): a, b, x1, x2 = self.args if argindex == 3: # Diff wrt x1 return -(1 - x1)**(b - 1)*x1**(a - 1) elif argindex == 4: # Diff wrt x2 return (1 - x2)**(b - 1)*x2**(a - 1) else: raise ArgumentIndexError(self, argindex) def _eval_mpmath(self): return betainc_mpmath_fix, self.args def _eval_is_real(self): if all(arg.is_real for arg in self.args): return True def _eval_conjugate(self): return self.func(*map(conjugate, self.args)) def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs): from sympy.integrals.integrals import Integral t = Dummy('t') return Integral(t**(a - 1)*(1 - t)**(b - 1), (t, x1, x2)) def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs): from sympy.functions.special.hyper import hyper return (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a ############################################################################### #################### REGULARIZED INCOMPLETE BETA FUNCTION ##################### ############################################################################### class betainc_regularized(Function): r""" The Generalized Regularized Incomplete Beta function is given by .. math:: \mathrm{I}_{(x_1, x_2)}(a, b) = \frac{\mathrm{B}_{(x_1, x_2)}(a, b)}{\mathrm{B}(a, b)} The Regularized Incomplete Beta function is a special case of the Generalized Regularized Incomplete Beta function : .. math:: \mathrm{I}_z (a, b) = \mathrm{I}_{(0, z)}(a, b) The Regularized Incomplete Beta function is the cumulative distribution function of the beta distribution. Examples ======== >>> from sympy import betainc_regularized, symbols, conjugate >>> a, b, x, x1, x2 = symbols('a b x x1 x2') The Generalized Regularized Incomplete Beta function is given by: >>> betainc_regularized(a, b, x1, x2) betainc_regularized(a, b, x1, x2) The Regularized Incomplete Beta function can be obtained as follows: >>> betainc_regularized(a, b, 0, x) betainc_regularized(a, b, 0, x) The Regularized Incomplete Beta function obeys the mirror symmetry: >>> conjugate(betainc_regularized(a, b, x1, x2)) betainc_regularized(conjugate(a), conjugate(b), conjugate(x1), conjugate(x2)) We can numerically evaluate the Regularized Incomplete Beta function to arbitrary precision for any complex numbers a, b, x1 and x2: >>> from sympy import betainc_regularized, pi, E >>> betainc_regularized(1, 2, 0, 0.25).evalf(10) 0.4375000000 >>> betainc_regularized(pi, E, 0, 1).evalf(5) 1.00000 The Generalized Regularized Incomplete Beta function can be expressed in terms of the Generalized Hypergeometric function. >>> from sympy import hyper >>> betainc_regularized(a, b, x1, x2).rewrite(hyper) (-x1**a*hyper((a, 1 - b), (a + 1,), x1) + x2**a*hyper((a, 1 - b), (a + 1,), x2))/(a*beta(a, b)) See Also ======== beta: Beta function hyper: Generalized Hypergeometric function References ========== .. [1] https://en.wikipedia.org/wiki/Beta_function#Incomplete_beta_function .. [2] https://dlmf.nist.gov/8.17 .. [3] https://functions.wolfram.com/GammaBetaErf/Beta4/ .. [4] https://functions.wolfram.com/GammaBetaErf/BetaRegularized4/02/ """ nargs = 4 unbranched = True def __new__(cls, a, b, x1, x2): return Function.__new__(cls, a, b, x1, x2) def _eval_mpmath(self): return betainc_mpmath_fix, (*self.args, S(1)) def fdiff(self, argindex): a, b, x1, x2 = self.args if argindex == 3: # Diff wrt x1 return -(1 - x1)**(b - 1)*x1**(a - 1) / beta(a, b) elif argindex == 4: # Diff wrt x2 return (1 - x2)**(b - 1)*x2**(a - 1) / beta(a, b) else: raise ArgumentIndexError(self, argindex) def _eval_is_real(self): if all(arg.is_real for arg in self.args): return True def _eval_conjugate(self): return self.func(*map(conjugate, self.args)) def _eval_rewrite_as_Integral(self, a, b, x1, x2, **kwargs): from sympy.integrals.integrals import Integral t = Dummy('t') integrand = t**(a - 1)*(1 - t)**(b - 1) expr = Integral(integrand, (t, x1, x2)) return expr / Integral(integrand, (t, 0, 1)) def _eval_rewrite_as_hyper(self, a, b, x1, x2, **kwargs): from sympy.functions.special.hyper import hyper expr = (x2**a * hyper((a, 1 - b), (a + 1,), x2) - x1**a * hyper((a, 1 - b), (a + 1,), x1)) / a return expr / beta(a, b) sympy-sympy-1.9/sympy/functions/special/bsplines.py000066400000000000000000000237611412543434000227360ustar00rootroot00000000000000from sympy.core import S, sympify from sympy.functions import Piecewise, piecewise_fold from sympy.sets.sets import Interval from sympy.core.cache import lru_cache def _ivl(cond, x): """return the interval corresponding to the condition Conditions in spline's Piecewise give the range over which an expression is valid like (lo <= x) & (x <= hi). This function returns (lo, hi). """ from sympy.logic.boolalg import And if isinstance(cond, And) and len(cond.args) == 2: a, b = cond.args if a.lts == x: a, b = b, a return a.lts, b.gts raise TypeError('unexpected cond type: %s' % cond) def _add_splines(c, b1, d, b2, x): """Construct c*b1 + d*b2.""" if b1 == S.Zero or c == S.Zero: rv = piecewise_fold(d * b2) elif b2 == S.Zero or d == S.Zero: rv = piecewise_fold(c * b1) else: new_args = [] # Just combining the Piecewise without any fancy optimization p1 = piecewise_fold(c * b1) p2 = piecewise_fold(d * b2) # Search all Piecewise arguments except (0, True) p2args = list(p2.args[:-1]) # This merging algorithm assumes the conditions in # p1 and p2 are sorted for arg in p1.args[:-1]: expr = arg.expr cond = arg.cond lower = _ivl(cond, x)[0] # Check p2 for matching conditions that can be merged for i, arg2 in enumerate(p2args): expr2 = arg2.expr cond2 = arg2.cond lower_2, upper_2 = _ivl(cond2, x) if cond2 == cond: # Conditions match, join expressions expr += expr2 # Remove matching element del p2args[i] # No need to check the rest break elif lower_2 < lower and upper_2 <= lower: # Check if arg2 condition smaller than arg1, # add to new_args by itself (no match expected # in p1) new_args.append(arg2) del p2args[i] break # Checked all, add expr and cond new_args.append((expr, cond)) # Add remaining items from p2args new_args.extend(p2args) # Add final (0, True) new_args.append((0, True)) rv = Piecewise(*new_args, evaluate=False) return rv.expand() @lru_cache(maxsize=128) def bspline_basis(d, knots, n, x): """ The $n$-th B-spline at $x$ of degree $d$ with knots. Explanation =========== B-Splines are piecewise polynomials of degree $d$. They are defined on a set of knots, which is a sequence of integers or floats. Examples ======== The 0th degree splines have a value of 1 on a single interval: >>> from sympy import bspline_basis >>> from sympy.abc import x >>> d = 0 >>> knots = tuple(range(5)) >>> bspline_basis(d, knots, 0, x) Piecewise((1, (x >= 0) & (x <= 1)), (0, True)) For a given ``(d, knots)`` there are ``len(knots)-d-1`` B-splines defined, that are indexed by ``n`` (starting at 0). Here is an example of a cubic B-spline: >>> bspline_basis(3, tuple(range(5)), 0, x) Piecewise((x**3/6, (x >= 0) & (x <= 1)), (-x**3/2 + 2*x**2 - 2*x + 2/3, (x >= 1) & (x <= 2)), (x**3/2 - 4*x**2 + 10*x - 22/3, (x >= 2) & (x <= 3)), (-x**3/6 + 2*x**2 - 8*x + 32/3, (x >= 3) & (x <= 4)), (0, True)) By repeating knot points, you can introduce discontinuities in the B-splines and their derivatives: >>> d = 1 >>> knots = (0, 0, 2, 3, 4) >>> bspline_basis(d, knots, 0, x) Piecewise((1 - x/2, (x >= 0) & (x <= 2)), (0, True)) It is quite time consuming to construct and evaluate B-splines. If you need to evaluate a B-spline many times, it is best to lambdify them first: >>> from sympy import lambdify >>> d = 3 >>> knots = tuple(range(10)) >>> b0 = bspline_basis(d, knots, 0, x) >>> f = lambdify(x, b0) >>> y = f(0.5) Parameters ========== d : integer degree of bspline knots : list of integer values list of knots points of bspline n : integer $n$-th B-spline x : symbol See Also ======== bspline_basis_set References ========== .. [1] https://en.wikipedia.org/wiki/B-spline """ from sympy.core.symbol import Dummy # make sure x has no assumptions so conditions don't evaluate xvar = x x = Dummy() knots = tuple(sympify(k) for k in knots) d = int(d) n = int(n) n_knots = len(knots) n_intervals = n_knots - 1 if n + d + 1 > n_intervals: raise ValueError("n + d + 1 must not exceed len(knots) - 1") if d == 0: result = Piecewise( (S.One, Interval(knots[n], knots[n + 1]).contains(x)), (0, True) ) elif d > 0: denom = knots[n + d + 1] - knots[n + 1] if denom != S.Zero: B = (knots[n + d + 1] - x) / denom b2 = bspline_basis(d - 1, knots, n + 1, x) else: b2 = B = S.Zero denom = knots[n + d] - knots[n] if denom != S.Zero: A = (x - knots[n]) / denom b1 = bspline_basis(d - 1, knots, n, x) else: b1 = A = S.Zero result = _add_splines(A, b1, B, b2, x) else: raise ValueError("degree must be non-negative: %r" % n) # return result with user-given x return result.xreplace({x: xvar}) def bspline_basis_set(d, knots, x): """ Return the ``len(knots)-d-1`` B-splines at *x* of degree *d* with *knots*. Explanation =========== This function returns a list of piecewise polynomials that are the ``len(knots)-d-1`` B-splines of degree *d* for the given knots. This function calls ``bspline_basis(d, knots, n, x)`` for different values of *n*. Examples ======== >>> from sympy import bspline_basis_set >>> from sympy.abc import x >>> d = 2 >>> knots = range(5) >>> splines = bspline_basis_set(d, knots, x) >>> splines [Piecewise((x**2/2, (x >= 0) & (x <= 1)), (-x**2 + 3*x - 3/2, (x >= 1) & (x <= 2)), (x**2/2 - 3*x + 9/2, (x >= 2) & (x <= 3)), (0, True)), Piecewise((x**2/2 - x + 1/2, (x >= 1) & (x <= 2)), (-x**2 + 5*x - 11/2, (x >= 2) & (x <= 3)), (x**2/2 - 4*x + 8, (x >= 3) & (x <= 4)), (0, True))] Parameters ========== d : integer degree of bspline knots : list of integers list of knots points of bspline x : symbol See Also ======== bspline_basis """ n_splines = len(knots) - d - 1 return [bspline_basis(d, tuple(knots), i, x) for i in range(n_splines)] def interpolating_spline(d, x, X, Y): """ Return spline of degree *d*, passing through the given *X* and *Y* values. Explanation =========== This function returns a piecewise function such that each part is a polynomial of degree not greater than *d*. The value of *d* must be 1 or greater and the values of *X* must be strictly increasing. Examples ======== >>> from sympy import interpolating_spline >>> from sympy.abc import x >>> interpolating_spline(1, x, [1, 2, 4, 7], [3, 6, 5, 7]) Piecewise((3*x, (x >= 1) & (x <= 2)), (7 - x/2, (x >= 2) & (x <= 4)), (2*x/3 + 7/3, (x >= 4) & (x <= 7))) >>> interpolating_spline(3, x, [-2, 0, 1, 3, 4], [4, 2, 1, 1, 3]) Piecewise((7*x**3/117 + 7*x**2/117 - 131*x/117 + 2, (x >= -2) & (x <= 1)), (10*x**3/117 - 2*x**2/117 - 122*x/117 + 77/39, (x >= 1) & (x <= 4))) Parameters ========== d : integer Degree of Bspline strictly greater than equal to one x : symbol X : list of strictly increasing integer values list of X coordinates through which the spline passes Y : list of strictly increasing integer values list of Y coordinates through which the spline passes See Also ======== bspline_basis_set, interpolating_poly """ from sympy import symbols, Dummy from sympy.solvers.solveset import linsolve from sympy.matrices.dense import Matrix # Input sanitization d = sympify(d) if not (d.is_Integer and d.is_positive): raise ValueError("Spline degree must be a positive integer, not %s." % d) if len(X) != len(Y): raise ValueError("Number of X and Y coordinates must be the same.") if len(X) < d + 1: raise ValueError("Degree must be less than the number of control points.") if not all(a < b for a, b in zip(X, X[1:])): raise ValueError("The x-coordinates must be strictly increasing.") X = [sympify(i) for i in X] # Evaluating knots value if d.is_odd: j = (d + 1) // 2 interior_knots = X[j:-j] else: j = d // 2 interior_knots = [ (a + b)/2 for a, b in zip(X[j : -j - 1], X[j + 1 : -j]) ] knots = [X[0]] * (d + 1) + list(interior_knots) + [X[-1]] * (d + 1) basis = bspline_basis_set(d, knots, x) A = [[b.subs(x, v) for b in basis] for v in X] coeff = linsolve((Matrix(A), Matrix(Y)), symbols("c0:{}".format(len(X)), cls=Dummy)) coeff = list(coeff)[0] intervals = {c for b in basis for (e, c) in b.args if c != True} # Sorting the intervals # ival contains the end-points of each interval ival = [_ivl(c, x) for c in intervals] com = zip(ival, intervals) com = sorted(com, key=lambda x: x[0]) intervals = [y for x, y in com] basis_dicts = [{c: e for (e, c) in b.args} for b in basis] spline = [] for i in intervals: piece = sum( [c * d.get(i, S.Zero) for (c, d) in zip(coeff, basis_dicts)], S.Zero ) spline.append((piece, i)) return Piecewise(*spline) sympy-sympy-1.9/sympy/functions/special/delta_functions.py000066400000000000000000000473671412543434000243100ustar00rootroot00000000000000from sympy.core import S, sympify, diff from sympy.core.decorators import deprecated from sympy.core.function import Function, ArgumentIndexError from sympy.core.logic import fuzzy_not from sympy.core.relational import Eq, Ne from sympy.functions.elementary.complexes import im, sign from sympy.functions.elementary.piecewise import Piecewise from sympy.polys.polyerrors import PolynomialError from sympy.utilities import filldedent ############################################################################### ################################ DELTA FUNCTION ############################### ############################################################################### class DiracDelta(Function): r""" The DiracDelta function and its derivatives. Explanation =========== DiracDelta is not an ordinary function. It can be rigorously defined either as a distribution or as a measure. DiracDelta only makes sense in definite integrals, and in particular, integrals of the form ``Integral(f(x)*DiracDelta(x - x0), (x, a, b))``, where it equals ``f(x0)`` if ``a <= x0 <= b`` and ``0`` otherwise. Formally, DiracDelta acts in some ways like a function that is ``0`` everywhere except at ``0``, but in many ways it also does not. It can often be useful to treat DiracDelta in formal ways, building up and manipulating expressions with delta functions (which may eventually be integrated), but care must be taken to not treat it as a real function. SymPy's ``oo`` is similar. It only truly makes sense formally in certain contexts (such as integration limits), but SymPy allows its use everywhere, and it tries to be consistent with operations on it (like ``1/oo``), but it is easy to get into trouble and get wrong results if ``oo`` is treated too much like a number. Similarly, if DiracDelta is treated too much like a function, it is easy to get wrong or nonsensical results. DiracDelta function has the following properties: 1) $\frac{d}{d x} \theta(x) = \delta(x)$ 2) $\int_{-\infty}^\infty \delta(x - a)f(x)\, dx = f(a)$ and $\int_{a- \epsilon}^{a+\epsilon} \delta(x - a)f(x)\, dx = f(a)$ 3) $\delta(x) = 0$ for all $x \neq 0$ 4) $\delta(g(x)) = \sum_i \frac{\delta(x - x_i)}{\|g'(x_i)\|}$ where $x_i$ are the roots of $g$ 5) $\delta(-x) = \delta(x)$ Derivatives of ``k``-th order of DiracDelta have the following properties: 6) $\delta(x, k) = 0$ for all $x \neq 0$ 7) $\delta(-x, k) = -\delta(x, k)$ for odd $k$ 8) $\delta(-x, k) = \delta(x, k)$ for even $k$ Examples ======== >>> from sympy import DiracDelta, diff, pi >>> from sympy.abc import x, y >>> DiracDelta(x) DiracDelta(x) >>> DiracDelta(1) 0 >>> DiracDelta(-1) 0 >>> DiracDelta(pi) 0 >>> DiracDelta(x - 4).subs(x, 4) DiracDelta(0) >>> diff(DiracDelta(x)) DiracDelta(x, 1) >>> diff(DiracDelta(x - 1),x,2) DiracDelta(x - 1, 2) >>> diff(DiracDelta(x**2 - 1),x,2) 2*(2*x**2*DiracDelta(x**2 - 1, 2) + DiracDelta(x**2 - 1, 1)) >>> DiracDelta(3*x).is_simple(x) True >>> DiracDelta(x**2).is_simple(x) False >>> DiracDelta((x**2 - 1)*y).expand(diracdelta=True, wrt=x) DiracDelta(x - 1)/(2*Abs(y)) + DiracDelta(x + 1)/(2*Abs(y)) See Also ======== Heaviside sympy.simplify.simplify.simplify, is_simple sympy.functions.special.tensor_functions.KroneckerDelta References ========== .. [1] http://mathworld.wolfram.com/DeltaFunction.html """ is_real = True def fdiff(self, argindex=1): """ Returns the first derivative of a DiracDelta Function. Explanation =========== The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the user-level function and ``fdiff()`` is an object method. ``fdiff()`` is a convenience method available in the ``Function`` class. It returns the derivative of the function without considering the chain rule. ``diff(function, x)`` calls ``Function._eval_derivative`` which in turn calls ``fdiff()`` internally to compute the derivative of the function. Examples ======== >>> from sympy import DiracDelta, diff >>> from sympy.abc import x >>> DiracDelta(x).fdiff() DiracDelta(x, 1) >>> DiracDelta(x, 1).fdiff() DiracDelta(x, 2) >>> DiracDelta(x**2 - 1).fdiff() DiracDelta(x**2 - 1, 1) >>> diff(DiracDelta(x, 1)).fdiff() DiracDelta(x, 3) Parameters ========== argindex : integer degree of derivative """ if argindex == 1: #I didn't know if there is a better way to handle default arguments k = 0 if len(self.args) > 1: k = self.args[1] return self.func(self.args[0], k + 1) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg, k=0): """ Returns a simplified form or a value of DiracDelta depending on the argument passed by the DiracDelta object. Explanation =========== The ``eval()`` method is automatically called when the ``DiracDelta`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import DiracDelta, S >>> from sympy.abc import x >>> DiracDelta(x) DiracDelta(x) >>> DiracDelta(-x, 1) -DiracDelta(x, 1) >>> DiracDelta(1) 0 >>> DiracDelta(5, 1) 0 >>> DiracDelta(0) DiracDelta(0) >>> DiracDelta(-1) 0 >>> DiracDelta(S.NaN) nan >>> DiracDelta(x).eval(1) 0 >>> DiracDelta(x - 100).subs(x, 5) 0 >>> DiracDelta(x - 100).subs(x, 100) DiracDelta(0) Parameters ========== k : integer order of derivative arg : argument passed to DiracDelta """ k = sympify(k) if not k.is_Integer or k.is_negative: raise ValueError("Error: the second argument of DiracDelta must be \ a non-negative integer, %s given instead." % (k,)) arg = sympify(arg) if arg is S.NaN: return S.NaN if arg.is_nonzero: return S.Zero if fuzzy_not(im(arg).is_zero): raise ValueError(filldedent(''' Function defined only for Real Values. Complex part: %s found in %s .''' % ( repr(im(arg)), repr(arg)))) c, nc = arg.args_cnc() if c and c[0] is S.NegativeOne: # keep this fast and simple instead of using # could_extract_minus_sign if k.is_odd: return -cls(-arg, k) elif k.is_even: return cls(-arg, k) if k else cls(-arg) @deprecated(useinstead="expand(diracdelta=True, wrt=x)", issue=12859, deprecated_since_version="1.1") def simplify(self, x, **kwargs): return self.expand(diracdelta=True, wrt=x) def _eval_expand_diracdelta(self, **hints): """ Compute a simplified representation of the function using property number 4. Pass ``wrt`` as a hint to expand the expression with respect to a particular variable. Explanation =========== ``wrt`` is: - a variable with respect to which a DiracDelta expression will get expanded. Examples ======== >>> from sympy import DiracDelta >>> from sympy.abc import x, y >>> DiracDelta(x*y).expand(diracdelta=True, wrt=x) DiracDelta(x)/Abs(y) >>> DiracDelta(x*y).expand(diracdelta=True, wrt=y) DiracDelta(y)/Abs(x) >>> DiracDelta(x**2 + x - 2).expand(diracdelta=True, wrt=x) DiracDelta(x - 1)/3 + DiracDelta(x + 2)/3 See Also ======== is_simple, Diracdelta """ from sympy.polys.polyroots import roots wrt = hints.get('wrt', None) if wrt is None: free = self.free_symbols if len(free) == 1: wrt = free.pop() else: raise TypeError(filldedent(''' When there is more than 1 free symbol or variable in the expression, the 'wrt' keyword is required as a hint to expand when using the DiracDelta hint.''')) if not self.args[0].has(wrt) or (len(self.args) > 1 and self.args[1] != 0 ): return self try: argroots = roots(self.args[0], wrt) result = 0 valid = True darg = abs(diff(self.args[0], wrt)) for r, m in argroots.items(): if r.is_real is not False and m == 1: result += self.func(wrt - r)/darg.subs(wrt, r) else: # don't handle non-real and if m != 1 then # a polynomial will have a zero in the derivative (darg) # at r valid = False break if valid: return result except PolynomialError: pass return self def is_simple(self, x): """ Tells whether the argument(args[0]) of DiracDelta is a linear expression in *x*. Examples ======== >>> from sympy import DiracDelta, cos >>> from sympy.abc import x, y >>> DiracDelta(x*y).is_simple(x) True >>> DiracDelta(x*y).is_simple(y) True >>> DiracDelta(x**2 + x - 2).is_simple(x) False >>> DiracDelta(cos(x)).is_simple(x) False Parameters ========== x : can be a symbol See Also ======== sympy.simplify.simplify.simplify, DiracDelta """ p = self.args[0].as_poly(x) if p: return p.degree() == 1 return False def _eval_rewrite_as_Piecewise(self, *args, **kwargs): """ Represents DiracDelta in a piecewise form. Examples ======== >>> from sympy import DiracDelta, Piecewise, Symbol >>> x = Symbol('x') >>> DiracDelta(x).rewrite(Piecewise) Piecewise((DiracDelta(0), Eq(x, 0)), (0, True)) >>> DiracDelta(x - 5).rewrite(Piecewise) Piecewise((DiracDelta(0), Eq(x - 5, 0)), (0, True)) >>> DiracDelta(x**2 - 5).rewrite(Piecewise) Piecewise((DiracDelta(0), Eq(x**2 - 5, 0)), (0, True)) >>> DiracDelta(x - 5, 4).rewrite(Piecewise) DiracDelta(x - 5, 4) """ if len(args) == 1: return Piecewise((DiracDelta(0), Eq(args[0], 0)), (0, True)) def _eval_rewrite_as_SingularityFunction(self, *args, **kwargs): """ Returns the DiracDelta expression written in the form of Singularity Functions. """ from sympy.solvers import solve from sympy.functions import SingularityFunction if self == DiracDelta(0): return SingularityFunction(0, 0, -1) if self == DiracDelta(0, 1): return SingularityFunction(0, 0, -2) free = self.free_symbols if len(free) == 1: x = (free.pop()) if len(args) == 1: return SingularityFunction(x, solve(args[0], x)[0], -1) return SingularityFunction(x, solve(args[0], x)[0], -args[1] - 1) else: # I don't know how to handle the case for DiracDelta expressions # having arguments with more than one variable. raise TypeError(filldedent(''' rewrite(SingularityFunction) doesn't support arguments with more that 1 variable.''')) ############################################################################### ############################## HEAVISIDE FUNCTION ############################# ############################################################################### class Heaviside(Function): r""" Heaviside step function. Explanation =========== The Heaviside step function has the following properties: 1) $\frac{d}{d x} \theta(x) = \delta(x)$ 2) $\theta(x) = \begin{cases} 0 & \text{for}\: x < 0 \\ \frac{1}{2} & \text{for}\: x = 0 \\1 & \text{for}\: x > 0 \end{cases}$ 3) $\frac{d}{d x} \max(x, 0) = \theta(x)$ Heaviside(x) is printed as $\theta(x)$ with the SymPy LaTeX printer. The value at 0 is set differently in different fields. SymPy uses 1/2, which is a convention from electronics and signal processing, and is consistent with solving improper integrals by Fourier transform and convolution. To specify a different value of Heaviside at ``x=0``, a second argument can be given. Using ``Heaviside(x, nan)`` gives an expression that will evaluate to nan for x=0. .. versionchanged:: 1.9 ``Heaviside(0)`` now returns 1/2 (before: undefined) Examples ======== >>> from sympy import Heaviside, nan >>> from sympy.abc import x >>> Heaviside(9) 1 >>> Heaviside(-9) 0 >>> Heaviside(0) 1/2 >>> Heaviside(0, nan) nan >>> (Heaviside(x) + 1).replace(Heaviside(x), Heaviside(x, 1)) Heaviside(x, 1) + 1 See Also ======== DiracDelta References ========== .. [1] http://mathworld.wolfram.com/HeavisideStepFunction.html .. [2] http://dlmf.nist.gov/1.16#iv """ is_real = True def fdiff(self, argindex=1): """ Returns the first derivative of a Heaviside Function. Examples ======== >>> from sympy import Heaviside, diff >>> from sympy.abc import x >>> Heaviside(x).fdiff() DiracDelta(x) >>> Heaviside(x**2 - 1).fdiff() DiracDelta(x**2 - 1) >>> diff(Heaviside(x)).fdiff() DiracDelta(x, 1) Parameters ========== argindex : integer order of derivative """ if argindex == 1: return DiracDelta(self.args[0]) else: raise ArgumentIndexError(self, argindex) def __new__(cls, arg, H0=S.Half, **options): if isinstance(H0, Heaviside) and len(H0.args) == 1: H0 = S.Half return super(cls, cls).__new__(cls, arg, H0, **options) @property def pargs(self): """Args without default S.Half""" args = self.args if args[1] is S.Half: args = args[:1] return args @classmethod def eval(cls, arg, H0=S.Half): """ Returns a simplified form or a value of Heaviside depending on the argument passed by the Heaviside object. Explanation =========== The ``eval()`` method is automatically called when the ``Heaviside`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import Heaviside, S >>> from sympy.abc import x >>> Heaviside(x) Heaviside(x) >>> Heaviside(19) 1 >>> Heaviside(0) 1/2 >>> Heaviside(0, 1) 1 >>> Heaviside(-5) 0 >>> Heaviside(S.NaN) nan >>> Heaviside(x).eval(42) 1 >>> Heaviside(x - 100).subs(x, 5) 0 >>> Heaviside(x - 100).subs(x, 105) 1 Parameters ========== arg : argument passed by Heaviside object H0 : value of Heaviside(0) """ H0 = sympify(H0) arg = sympify(arg) if arg.is_extended_negative: return S.Zero elif arg.is_extended_positive: return S.One elif arg.is_zero: return H0 elif arg is S.NaN: return S.NaN elif fuzzy_not(im(arg).is_zero): raise ValueError("Function defined only for Real Values. Complex part: %s found in %s ." % (repr(im(arg)), repr(arg)) ) def _eval_rewrite_as_Piecewise(self, arg, H0=None, **kwargs): """ Represents Heaviside in a Piecewise form. Examples ======== >>> from sympy import Heaviside, Piecewise, Symbol, nan >>> x = Symbol('x') >>> Heaviside(x).rewrite(Piecewise) Piecewise((0, x < 0), (1/2, Eq(x, 0)), (1, x > 0)) >>> Heaviside(x,nan).rewrite(Piecewise) Piecewise((0, x < 0), (nan, Eq(x, 0)), (1, x > 0)) >>> Heaviside(x - 5).rewrite(Piecewise) Piecewise((0, x - 5 < 0), (1/2, Eq(x - 5, 0)), (1, x - 5 > 0)) >>> Heaviside(x**2 - 1).rewrite(Piecewise) Piecewise((0, x**2 - 1 < 0), (1/2, Eq(x**2 - 1, 0)), (1, x**2 - 1 > 0)) """ if H0 == 0: return Piecewise((0, arg <= 0), (1, arg > 0)) if H0 == 1: return Piecewise((0, arg < 0), (1, arg >= 0)) return Piecewise((0, arg < 0), (H0, Eq(arg, 0)), (1, arg > 0)) def _eval_rewrite_as_sign(self, arg, H0=S.Half, **kwargs): """ Represents the Heaviside function in the form of sign function. Explanation =========== The value of Heaviside(0) must be 1/2 for rewritting as sign to be strictly equivalent. For easier usage, we also allow this rewriting when Heaviside(0) is undefined. Examples ======== >>> from sympy import Heaviside, Symbol, sign, nan >>> x = Symbol('x', real=True) >>> y = Symbol('y') >>> Heaviside(x).rewrite(sign) sign(x)/2 + 1/2 >>> Heaviside(x, 0).rewrite(sign) Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (0, True)) >>> Heaviside(x, nan).rewrite(sign) Piecewise((sign(x)/2 + 1/2, Ne(x, 0)), (nan, True)) >>> Heaviside(x - 2).rewrite(sign) sign(x - 2)/2 + 1/2 >>> Heaviside(x**2 - 2*x + 1).rewrite(sign) sign(x**2 - 2*x + 1)/2 + 1/2 >>> Heaviside(y).rewrite(sign) Heaviside(y) >>> Heaviside(y**2 - 2*y + 1).rewrite(sign) Heaviside(y**2 - 2*y + 1) See Also ======== sign """ if arg.is_extended_real: pw1 = Piecewise( ((sign(arg) + 1)/2, Ne(arg, 0)), (Heaviside(0, H0=H0), True)) pw2 = Piecewise( ((sign(arg) + 1)/2, Eq(Heaviside(0, H0=H0), S(1)/2)), (pw1, True)) return pw2 def _eval_rewrite_as_SingularityFunction(self, args, H0=S.Half, **kwargs): """ Returns the Heaviside expression written in the form of Singularity Functions. """ from sympy.solvers import solve from sympy.functions import SingularityFunction if self == Heaviside(0): return SingularityFunction(0, 0, 0) free = self.free_symbols if len(free) == 1: x = (free.pop()) return SingularityFunction(x, solve(args, x)[0], 0) # TODO # ((x - 5)**3*Heaviside(x - 5)).rewrite(SingularityFunction) should output # SingularityFunction(x, 5, 0) instead of (x - 5)**3*SingularityFunction(x, 5, 0) else: # I don't know how to handle the case for Heaviside expressions # having arguments with more than one variable. raise TypeError(filldedent(''' rewrite(SingularityFunction) doesn't support arguments with more that 1 variable.''')) sympy-sympy-1.9/sympy/functions/special/elliptic_integrals.py000066400000000000000000000344101412543434000247650ustar00rootroot00000000000000""" Elliptic Integrals. """ from sympy.core import S, pi, I, Rational from sympy.core.function import Function, ArgumentIndexError from sympy.functions.elementary.complexes import sign from sympy.functions.elementary.hyperbolic import atanh from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import sin, tan from sympy.functions.special.gamma_functions import gamma from sympy.functions.special.hyper import hyper, meijerg class elliptic_k(Function): r""" The complete elliptic integral of the first kind, defined by .. math:: K(m) = F\left(\tfrac{\pi}{2}\middle| m\right) where $F\left(z\middle| m\right)$ is the Legendre incomplete elliptic integral of the first kind. Explanation =========== The function $K(m)$ is a single-valued function on the complex plane with branch cut along the interval $(1, \infty)$. Note that our notation defines the incomplete elliptic integral in terms of the parameter $m$ instead of the elliptic modulus (eccentricity) $k$. In this case, the parameter $m$ is defined as $m=k^2$. Examples ======== >>> from sympy import elliptic_k, I >>> from sympy.abc import m >>> elliptic_k(0) pi/2 >>> elliptic_k(1.0 + I) 1.50923695405127 + 0.625146415202697*I >>> elliptic_k(m).series(n=3) pi/2 + pi*m/8 + 9*pi*m**2/128 + O(m**3) See Also ======== elliptic_f References ========== .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticK """ @classmethod def eval(cls, m): if m.is_zero: return pi*S.Half elif m is S.Half: return 8*pi**Rational(3, 2)/gamma(Rational(-1, 4))**2 elif m is S.One: return S.ComplexInfinity elif m is S.NegativeOne: return gamma(Rational(1, 4))**2/(4*sqrt(2*pi)) elif m in (S.Infinity, S.NegativeInfinity, I*S.Infinity, I*S.NegativeInfinity, S.ComplexInfinity): return S.Zero def fdiff(self, argindex=1): m = self.args[0] return (elliptic_e(m) - (1 - m)*elliptic_k(m))/(2*m*(1 - m)) def _eval_conjugate(self): m = self.args[0] if (m.is_real and (m - 1).is_positive) is False: return self.func(m.conjugate()) def _eval_nseries(self, x, n, logx, cdir=0): from sympy.simplify import hyperexpand return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx)) def _eval_rewrite_as_hyper(self, m, **kwargs): return pi*S.Half*hyper((S.Half, S.Half), (S.One,), m) def _eval_rewrite_as_meijerg(self, m, **kwargs): return meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -m)/2 def _eval_is_zero(self): m = self.args[0] if m.is_infinite: return True def _eval_rewrite_as_Integral(self, *args): from sympy import Integral, Dummy t = Dummy('t') m = self.args[0] return Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2)) class elliptic_f(Function): r""" The Legendre incomplete elliptic integral of the first kind, defined by .. math:: F\left(z\middle| m\right) = \int_0^z \frac{dt}{\sqrt{1 - m \sin^2 t}} Explanation =========== This function reduces to a complete elliptic integral of the first kind, $K(m)$, when $z = \pi/2$. Note that our notation defines the incomplete elliptic integral in terms of the parameter $m$ instead of the elliptic modulus (eccentricity) $k$. In this case, the parameter $m$ is defined as $m=k^2$. Examples ======== >>> from sympy import elliptic_f, I >>> from sympy.abc import z, m >>> elliptic_f(z, m).series(z) z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6) >>> elliptic_f(3.0 + I/2, 1.0 + I) 2.909449841483 + 1.74720545502474*I See Also ======== elliptic_k References ========== .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticF """ @classmethod def eval(cls, z, m): if z.is_zero: return S.Zero if m.is_zero: return z k = 2*z/pi if k.is_integer: return k*elliptic_k(m) elif m in (S.Infinity, S.NegativeInfinity): return S.Zero elif z.could_extract_minus_sign(): return -elliptic_f(-z, m) def fdiff(self, argindex=1): z, m = self.args fm = sqrt(1 - m*sin(z)**2) if argindex == 1: return 1/fm elif argindex == 2: return (elliptic_e(z, m)/(2*m*(1 - m)) - elliptic_f(z, m)/(2*m) - sin(2*z)/(4*(1 - m)*fm)) raise ArgumentIndexError(self, argindex) def _eval_conjugate(self): z, m = self.args if (m.is_real and (m - 1).is_positive) is False: return self.func(z.conjugate(), m.conjugate()) def _eval_rewrite_as_Integral(self, *args): from sympy import Integral, Dummy t = Dummy('t') z, m = self.args[0], self.args[1] return Integral(1/(sqrt(1 - m*sin(t)**2)), (t, 0, z)) def _eval_is_zero(self): z, m = self.args if z.is_zero: return True if m.is_extended_real and m.is_infinite: return True class elliptic_e(Function): r""" Called with two arguments $z$ and $m$, evaluates the incomplete elliptic integral of the second kind, defined by .. math:: E\left(z\middle| m\right) = \int_0^z \sqrt{1 - m \sin^2 t} dt Called with a single argument $m$, evaluates the Legendre complete elliptic integral of the second kind .. math:: E(m) = E\left(\tfrac{\pi}{2}\middle| m\right) Explanation =========== The function $E(m)$ is a single-valued function on the complex plane with branch cut along the interval $(1, \infty)$. Note that our notation defines the incomplete elliptic integral in terms of the parameter $m$ instead of the elliptic modulus (eccentricity) $k$. In this case, the parameter $m$ is defined as $m=k^2$. Examples ======== >>> from sympy import elliptic_e, I >>> from sympy.abc import z, m >>> elliptic_e(z, m).series(z) z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6) >>> elliptic_e(m).series(n=4) pi/2 - pi*m/8 - 3*pi*m**2/128 - 5*pi*m**3/512 + O(m**4) >>> elliptic_e(1 + I, 2 - I/2).n() 1.55203744279187 + 0.290764986058437*I >>> elliptic_e(0) pi/2 >>> elliptic_e(2.0 - I) 0.991052601328069 + 0.81879421395609*I References ========== .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticE2 .. [3] http://functions.wolfram.com/EllipticIntegrals/EllipticE """ @classmethod def eval(cls, m, z=None): if z is not None: z, m = m, z k = 2*z/pi if m.is_zero: return z if z.is_zero: return S.Zero elif k.is_integer: return k*elliptic_e(m) elif m in (S.Infinity, S.NegativeInfinity): return S.ComplexInfinity elif z.could_extract_minus_sign(): return -elliptic_e(-z, m) else: if m.is_zero: return pi/2 elif m is S.One: return S.One elif m is S.Infinity: return I*S.Infinity elif m is S.NegativeInfinity: return S.Infinity elif m is S.ComplexInfinity: return S.ComplexInfinity def fdiff(self, argindex=1): if len(self.args) == 2: z, m = self.args if argindex == 1: return sqrt(1 - m*sin(z)**2) elif argindex == 2: return (elliptic_e(z, m) - elliptic_f(z, m))/(2*m) else: m = self.args[0] if argindex == 1: return (elliptic_e(m) - elliptic_k(m))/(2*m) raise ArgumentIndexError(self, argindex) def _eval_conjugate(self): if len(self.args) == 2: z, m = self.args if (m.is_real and (m - 1).is_positive) is False: return self.func(z.conjugate(), m.conjugate()) else: m = self.args[0] if (m.is_real and (m - 1).is_positive) is False: return self.func(m.conjugate()) def _eval_nseries(self, x, n, logx, cdir=0): from sympy.simplify import hyperexpand if len(self.args) == 1: return hyperexpand(self.rewrite(hyper)._eval_nseries(x, n=n, logx=logx)) return super()._eval_nseries(x, n=n, logx=logx) def _eval_rewrite_as_hyper(self, *args, **kwargs): if len(args) == 1: m = args[0] return (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), m) def _eval_rewrite_as_meijerg(self, *args, **kwargs): if len(args) == 1: m = args[0] return -meijerg(((S.Half, Rational(3, 2)), []), \ ((S.Zero,), (S.Zero,)), -m)/4 def _eval_rewrite_as_Integral(self, *args): from sympy import Integral, Dummy z, m = (pi/2, self.args[0]) if len(self.args) == 1 else self.args t = Dummy('t') return Integral(sqrt(1 - m*sin(t)**2), (t, 0, z)) class elliptic_pi(Function): r""" Called with three arguments $n$, $z$ and $m$, evaluates the Legendre incomplete elliptic integral of the third kind, defined by .. math:: \Pi\left(n; z\middle| m\right) = \int_0^z \frac{dt} {\left(1 - n \sin^2 t\right) \sqrt{1 - m \sin^2 t}} Called with two arguments $n$ and $m$, evaluates the complete elliptic integral of the third kind: .. math:: \Pi\left(n\middle| m\right) = \Pi\left(n; \tfrac{\pi}{2}\middle| m\right) Explanation =========== Note that our notation defines the incomplete elliptic integral in terms of the parameter $m$ instead of the elliptic modulus (eccentricity) $k$. In this case, the parameter $m$ is defined as $m=k^2$. Examples ======== >>> from sympy import elliptic_pi, I >>> from sympy.abc import z, n, m >>> elliptic_pi(n, z, m).series(z, n=4) z + z**3*(m/6 + n/3) + O(z**4) >>> elliptic_pi(0.5 + I, 1.0 - I, 1.2) 2.50232379629182 - 0.760939574180767*I >>> elliptic_pi(0, 0) pi/2 >>> elliptic_pi(1.0 - I/3, 2.0 + I) 3.29136443417283 + 0.32555634906645*I References ========== .. [1] https://en.wikipedia.org/wiki/Elliptic_integrals .. [2] http://functions.wolfram.com/EllipticIntegrals/EllipticPi3 .. [3] http://functions.wolfram.com/EllipticIntegrals/EllipticPi """ @classmethod def eval(cls, n, m, z=None): if z is not None: n, z, m = n, m, z if n.is_zero: return elliptic_f(z, m) elif n is S.One: return (elliptic_f(z, m) + (sqrt(1 - m*sin(z)**2)*tan(z) - elliptic_e(z, m))/(1 - m)) k = 2*z/pi if k.is_integer: return k*elliptic_pi(n, m) elif m.is_zero: return atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1) elif n == m: return (elliptic_f(z, n) - elliptic_pi(1, z, n) + tan(z)/sqrt(1 - n*sin(z)**2)) elif n in (S.Infinity, S.NegativeInfinity): return S.Zero elif m in (S.Infinity, S.NegativeInfinity): return S.Zero elif z.could_extract_minus_sign(): return -elliptic_pi(n, -z, m) if n.is_zero: return elliptic_f(z, m) if m.is_extended_real and m.is_infinite or \ n.is_extended_real and n.is_infinite: return S.Zero else: if n.is_zero: return elliptic_k(m) elif n is S.One: return S.ComplexInfinity elif m.is_zero: return pi/(2*sqrt(1 - n)) elif m == S.One: return S.NegativeInfinity/sign(n - 1) elif n == m: return elliptic_e(n)/(1 - n) elif n in (S.Infinity, S.NegativeInfinity): return S.Zero elif m in (S.Infinity, S.NegativeInfinity): return S.Zero if n.is_zero: return elliptic_k(m) if m.is_extended_real and m.is_infinite or \ n.is_extended_real and n.is_infinite: return S.Zero def _eval_conjugate(self): if len(self.args) == 3: n, z, m = self.args if (n.is_real and (n - 1).is_positive) is False and \ (m.is_real and (m - 1).is_positive) is False: return self.func(n.conjugate(), z.conjugate(), m.conjugate()) else: n, m = self.args return self.func(n.conjugate(), m.conjugate()) def fdiff(self, argindex=1): if len(self.args) == 3: n, z, m = self.args fm, fn = sqrt(1 - m*sin(z)**2), 1 - n*sin(z)**2 if argindex == 1: return (elliptic_e(z, m) + (m - n)*elliptic_f(z, m)/n + (n**2 - m)*elliptic_pi(n, z, m)/n - n*fm*sin(2*z)/(2*fn))/(2*(m - n)*(n - 1)) elif argindex == 2: return 1/(fm*fn) elif argindex == 3: return (elliptic_e(z, m)/(m - 1) + elliptic_pi(n, z, m) - m*sin(2*z)/(2*(m - 1)*fm))/(2*(n - m)) else: n, m = self.args if argindex == 1: return (elliptic_e(m) + (m - n)*elliptic_k(m)/n + (n**2 - m)*elliptic_pi(n, m)/n)/(2*(m - n)*(n - 1)) elif argindex == 2: return (elliptic_e(m)/(m - 1) + elliptic_pi(n, m))/(2*(n - m)) raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_Integral(self, *args): from sympy import Integral, Dummy if len(self.args) == 2: n, m, z = self.args[0], self.args[1], pi/2 else: n, z, m = self.args t = Dummy('t') return Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z)) sympy-sympy-1.9/sympy/functions/special/error_functions.py000066400000000000000000002254011412543434000243330ustar00rootroot00000000000000""" This module contains various functions that are special cases of incomplete gamma functions. It should probably be renamed. """ from sympy.core import Add, S, sympify, cacheit, pi, I, Rational from sympy.core.function import Function, ArgumentIndexError from sympy.core.symbol import Symbol from sympy.functions.combinatorial.factorials import factorial, factorial2, RisingFactorial from sympy.functions.elementary.complexes import re from sympy.functions.elementary.integers import floor from sympy.functions.elementary.miscellaneous import sqrt, root from sympy.functions.elementary.exponential import exp, log from sympy.functions.elementary.complexes import polar_lift from sympy.functions.elementary.hyperbolic import cosh, sinh from sympy.functions.elementary.trigonometric import cos, sin, sinc from sympy.functions.special.hyper import hyper, meijerg # TODO series expansions # TODO see the "Note:" in Ei # Helper function def real_to_real_as_real_imag(self, deep=True, **hints): if self.args[0].is_extended_real: if deep: hints['complex'] = False return (self.expand(deep, **hints), S.Zero) else: return (self, S.Zero) if deep: x, y = self.args[0].expand(deep, **hints).as_real_imag() else: x, y = self.args[0].as_real_imag() re = (self.func(x + I*y) + self.func(x - I*y))/2 im = (self.func(x + I*y) - self.func(x - I*y))/(2*I) return (re, im) ############################################################################### ################################ ERROR FUNCTION ############################### ############################################################################### class erf(Function): r""" The Gauss error function. Explanation =========== This function is defined as: .. math :: \mathrm{erf}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{-t^2} \mathrm{d}t. Examples ======== >>> from sympy import I, oo, erf >>> from sympy.abc import z Several special values are known: >>> erf(0) 0 >>> erf(oo) 1 >>> erf(-oo) -1 >>> erf(I*oo) oo*I >>> erf(-I*oo) -oo*I In general one can pull out factors of -1 and $I$ from the argument: >>> erf(-z) -erf(z) The error function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(erf(z)) erf(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(erf(z), z) 2*exp(-z**2)/sqrt(pi) We can numerically evaluate the error function to arbitrary precision on the whole complex plane: >>> erf(4).evalf(30) 0.999999984582742099719981147840 >>> erf(-4*I).evalf(30) -1296959.73071763923152794095062*I See Also ======== erfc: Complementary error function. erfi: Imaginary error function. erf2: Two-argument error function. erfinv: Inverse error function. erfcinv: Inverse Complementary error function. erf2inv: Inverse two-argument error function. References ========== .. [1] https://en.wikipedia.org/wiki/Error_function .. [2] http://dlmf.nist.gov/7 .. [3] http://mathworld.wolfram.com/Erf.html .. [4] http://functions.wolfram.com/GammaBetaErf/Erf """ unbranched = True def fdiff(self, argindex=1): if argindex == 1: return 2*exp(-self.args[0]**2)/sqrt(S.Pi) else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return erfinv @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.One elif arg is S.NegativeInfinity: return S.NegativeOne elif arg.is_zero: return S.Zero if isinstance(arg, erfinv): return arg.args[0] if isinstance(arg, erfcinv): return S.One - arg.args[0] if arg.is_zero: return S.Zero # Only happens with unevaluated erf2inv if isinstance(arg, erf2inv) and arg.args[0].is_zero: return arg.args[1] # Try to pull out factors of I t = arg.extract_multiplicatively(S.ImaginaryUnit) if t is S.Infinity or t is S.NegativeInfinity: return arg # Try to pull out factors of -1 if arg.could_extract_minus_sign(): return -cls(-arg) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) k = floor((n - 1)/S(2)) if len(previous_terms) > 2: return -previous_terms[-2] * x**2 * (n - 2)/(n*k) else: return 2*(-1)**k * x**n/(n*factorial(k)*sqrt(S.Pi)) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def _eval_is_real(self): return self.args[0].is_extended_real def _eval_is_finite(self): if self.args[0].is_finite: return True else: return self.args[0].is_extended_real def _eval_is_zero(self): if self.args[0].is_zero: return True def _eval_rewrite_as_uppergamma(self, z, **kwargs): from sympy import uppergamma return sqrt(z**2)/z*(S.One - uppergamma(S.Half, z**2)/sqrt(S.Pi)) def _eval_rewrite_as_fresnels(self, z, **kwargs): arg = (S.One - S.ImaginaryUnit)*z/sqrt(pi) return (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) def _eval_rewrite_as_fresnelc(self, z, **kwargs): arg = (S.One - S.ImaginaryUnit)*z/sqrt(pi) return (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) def _eval_rewrite_as_meijerg(self, z, **kwargs): return z/sqrt(pi)*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2) def _eval_rewrite_as_hyper(self, z, **kwargs): return 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], -z**2) def _eval_rewrite_as_expint(self, z, **kwargs): return sqrt(z**2)/z - z*expint(S.Half, z**2)/sqrt(S.Pi) def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs): from sympy.series.limits import limit if limitvar: lim = limit(z, limitvar, S.Infinity) if lim is S.NegativeInfinity: return S.NegativeOne + _erfs(-z)*exp(-z**2) return S.One - _erfs(z)*exp(-z**2) def _eval_rewrite_as_erfc(self, z, **kwargs): return S.One - erfc(z) def _eval_rewrite_as_erfi(self, z, **kwargs): return -I*erfi(I*z) def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.ComplexInfinity: arg0 = arg.limit(x, 0, dir='-' if cdir == -1 else '+') if x in arg.free_symbols and arg0.is_zero: return 2*arg/sqrt(pi) else: return self.func(arg0) def _eval_aseries(self, n, args0, x, logx): from sympy.series.order import Order from sympy import ceiling point = args0[0] if point in [S.Infinity, S.NegativeInfinity]: z = self.args[0] try: _, ex = z.leadterm(x) except (ValueError, NotImplementedError): return self ex = -ex # as x->1/x for aseries if ex.is_positive: newn = ceiling(n/ex) s = [(-1)**k * factorial2(2*k - 1) / (z**(2*k + 1) * 2**k) for k in range(0, newn)] + [Order(1/z**newn, x)] return S.One - (exp(-z**2)/sqrt(pi)) * Add(*s) return super(erf, self)._eval_aseries(n, args0, x, logx) as_real_imag = real_to_real_as_real_imag class erfc(Function): r""" Complementary Error Function. Explanation =========== The function is defined as: .. math :: \mathrm{erfc}(x) = \frac{2}{\sqrt{\pi}} \int_x^\infty e^{-t^2} \mathrm{d}t Examples ======== >>> from sympy import I, oo, erfc >>> from sympy.abc import z Several special values are known: >>> erfc(0) 1 >>> erfc(oo) 0 >>> erfc(-oo) 2 >>> erfc(I*oo) -oo*I >>> erfc(-I*oo) oo*I The error function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(erfc(z)) erfc(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(erfc(z), z) -2*exp(-z**2)/sqrt(pi) It also follows >>> erfc(-z) 2 - erfc(z) We can numerically evaluate the complementary error function to arbitrary precision on the whole complex plane: >>> erfc(4).evalf(30) 0.0000000154172579002800188521596734869 >>> erfc(4*I).evalf(30) 1.0 - 1296959.73071763923152794095062*I See Also ======== erf: Gaussian error function. erfi: Imaginary error function. erf2: Two-argument error function. erfinv: Inverse error function. erfcinv: Inverse Complementary error function. erf2inv: Inverse two-argument error function. References ========== .. [1] https://en.wikipedia.org/wiki/Error_function .. [2] http://dlmf.nist.gov/7 .. [3] http://mathworld.wolfram.com/Erfc.html .. [4] http://functions.wolfram.com/GammaBetaErf/Erfc """ unbranched = True def fdiff(self, argindex=1): if argindex == 1: return -2*exp(-self.args[0]**2)/sqrt(S.Pi) else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return erfcinv @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Zero elif arg.is_zero: return S.One if isinstance(arg, erfinv): return S.One - arg.args[0] if isinstance(arg, erfcinv): return arg.args[0] if arg.is_zero: return S.One # Try to pull out factors of I t = arg.extract_multiplicatively(S.ImaginaryUnit) if t is S.Infinity or t is S.NegativeInfinity: return -arg # Try to pull out factors of -1 if arg.could_extract_minus_sign(): return S(2) - cls(-arg) @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n == 0: return S.One elif n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) k = floor((n - 1)/S(2)) if len(previous_terms) > 2: return -previous_terms[-2] * x**2 * (n - 2)/(n*k) else: return -2*(-1)**k * x**n/(n*factorial(k)*sqrt(S.Pi)) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def _eval_is_real(self): return self.args[0].is_extended_real def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs): return self.rewrite(erf).rewrite("tractable", deep=True, limitvar=limitvar) def _eval_rewrite_as_erf(self, z, **kwargs): return S.One - erf(z) def _eval_rewrite_as_erfi(self, z, **kwargs): return S.One + I*erfi(I*z) def _eval_rewrite_as_fresnels(self, z, **kwargs): arg = (S.One - S.ImaginaryUnit)*z/sqrt(pi) return S.One - (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) def _eval_rewrite_as_fresnelc(self, z, **kwargs): arg = (S.One-S.ImaginaryUnit)*z/sqrt(pi) return S.One - (S.One + S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) def _eval_rewrite_as_meijerg(self, z, **kwargs): return S.One - z/sqrt(pi)*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2) def _eval_rewrite_as_hyper(self, z, **kwargs): return S.One - 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], -z**2) def _eval_rewrite_as_uppergamma(self, z, **kwargs): from sympy import uppergamma return S.One - sqrt(z**2)/z*(S.One - uppergamma(S.Half, z**2)/sqrt(S.Pi)) def _eval_rewrite_as_expint(self, z, **kwargs): return S.One - sqrt(z**2)/z + z*expint(S.Half, z**2)/sqrt(S.Pi) def _eval_expand_func(self, **hints): return self.rewrite(erf) def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.ComplexInfinity: arg0 = arg.limit(x, 0, dir='-' if cdir == -1 else '+') if arg0.is_zero: return S.One else: return self.func(arg0) as_real_imag = real_to_real_as_real_imag def _eval_aseries(self, n, args0, x, logx): return S.One - erf(*self.args)._eval_aseries(n, args0, x, logx) class erfi(Function): r""" Imaginary error function. Explanation =========== The function erfi is defined as: .. math :: \mathrm{erfi}(x) = \frac{2}{\sqrt{\pi}} \int_0^x e^{t^2} \mathrm{d}t Examples ======== >>> from sympy import I, oo, erfi >>> from sympy.abc import z Several special values are known: >>> erfi(0) 0 >>> erfi(oo) oo >>> erfi(-oo) -oo >>> erfi(I*oo) I >>> erfi(-I*oo) -I In general one can pull out factors of -1 and $I$ from the argument: >>> erfi(-z) -erfi(z) >>> from sympy import conjugate >>> conjugate(erfi(z)) erfi(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(erfi(z), z) 2*exp(z**2)/sqrt(pi) We can numerically evaluate the imaginary error function to arbitrary precision on the whole complex plane: >>> erfi(2).evalf(30) 18.5648024145755525987042919132 >>> erfi(-2*I).evalf(30) -0.995322265018952734162069256367*I See Also ======== erf: Gaussian error function. erfc: Complementary error function. erf2: Two-argument error function. erfinv: Inverse error function. erfcinv: Inverse Complementary error function. erf2inv: Inverse two-argument error function. References ========== .. [1] https://en.wikipedia.org/wiki/Error_function .. [2] http://mathworld.wolfram.com/Erfi.html .. [3] http://functions.wolfram.com/GammaBetaErf/Erfi """ unbranched = True def fdiff(self, argindex=1): if argindex == 1: return 2*exp(self.args[0]**2)/sqrt(S.Pi) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, z): if z.is_Number: if z is S.NaN: return S.NaN elif z.is_zero: return S.Zero elif z is S.Infinity: return S.Infinity if z.is_zero: return S.Zero # Try to pull out factors of -1 if z.could_extract_minus_sign(): return -cls(-z) # Try to pull out factors of I nz = z.extract_multiplicatively(I) if nz is not None: if nz is S.Infinity: return I if isinstance(nz, erfinv): return I*nz.args[0] if isinstance(nz, erfcinv): return I*(S.One - nz.args[0]) # Only happens with unevaluated erf2inv if isinstance(nz, erf2inv) and nz.args[0].is_zero: return I*nz.args[1] @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0 or n % 2 == 0: return S.Zero else: x = sympify(x) k = floor((n - 1)/S(2)) if len(previous_terms) > 2: return previous_terms[-2] * x**2 * (n - 2)/(n*k) else: return 2 * x**n/(n*factorial(k)*sqrt(S.Pi)) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def _eval_is_extended_real(self): return self.args[0].is_extended_real def _eval_is_zero(self): if self.args[0].is_zero: return True def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs): return self.rewrite(erf).rewrite("tractable", deep=True, limitvar=limitvar) def _eval_rewrite_as_erf(self, z, **kwargs): return -I*erf(I*z) def _eval_rewrite_as_erfc(self, z, **kwargs): return I*erfc(I*z) - I def _eval_rewrite_as_fresnels(self, z, **kwargs): arg = (S.One + S.ImaginaryUnit)*z/sqrt(pi) return (S.One - S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) def _eval_rewrite_as_fresnelc(self, z, **kwargs): arg = (S.One + S.ImaginaryUnit)*z/sqrt(pi) return (S.One - S.ImaginaryUnit)*(fresnelc(arg) - I*fresnels(arg)) def _eval_rewrite_as_meijerg(self, z, **kwargs): return z/sqrt(pi)*meijerg([S.Half], [], [0], [Rational(-1, 2)], -z**2) def _eval_rewrite_as_hyper(self, z, **kwargs): return 2*z/sqrt(pi)*hyper([S.Half], [3*S.Half], z**2) def _eval_rewrite_as_uppergamma(self, z, **kwargs): from sympy import uppergamma return sqrt(-z**2)/z*(uppergamma(S.Half, -z**2)/sqrt(S.Pi) - S.One) def _eval_rewrite_as_expint(self, z, **kwargs): return sqrt(-z**2)/z - z*expint(S.Half, -z**2)/sqrt(S.Pi) def _eval_expand_func(self, **hints): return self.rewrite(erf) as_real_imag = real_to_real_as_real_imag def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if x in arg.free_symbols and arg0.is_zero: return 2*arg/sqrt(pi) elif arg0.is_finite: return self.func(arg0) return self.func(arg) def _eval_aseries(self, n, args0, x, logx): from sympy.series.order import Order point = args0[0] if point is S.Infinity: z = self.args[0] s = [factorial2(2*k - 1) / (2**k * z**(2*k + 1)) for k in range(0, n)] + [Order(1/z**n, x)] return -S.ImaginaryUnit + (exp(z**2)/sqrt(pi)) * Add(*s) return super(erfi, self)._eval_aseries(n, args0, x, logx) class erf2(Function): r""" Two-argument error function. Explanation =========== This function is defined as: .. math :: \mathrm{erf2}(x, y) = \frac{2}{\sqrt{\pi}} \int_x^y e^{-t^2} \mathrm{d}t Examples ======== >>> from sympy import oo, erf2 >>> from sympy.abc import x, y Several special values are known: >>> erf2(0, 0) 0 >>> erf2(x, x) 0 >>> erf2(x, oo) 1 - erf(x) >>> erf2(x, -oo) -erf(x) - 1 >>> erf2(oo, y) erf(y) - 1 >>> erf2(-oo, y) erf(y) + 1 In general one can pull out factors of -1: >>> erf2(-x, -y) -erf2(x, y) The error function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(erf2(x, y)) erf2(conjugate(x), conjugate(y)) Differentiation with respect to $x$, $y$ is supported: >>> from sympy import diff >>> diff(erf2(x, y), x) -2*exp(-x**2)/sqrt(pi) >>> diff(erf2(x, y), y) 2*exp(-y**2)/sqrt(pi) See Also ======== erf: Gaussian error function. erfc: Complementary error function. erfi: Imaginary error function. erfinv: Inverse error function. erfcinv: Inverse Complementary error function. erf2inv: Inverse two-argument error function. References ========== .. [1] http://functions.wolfram.com/GammaBetaErf/Erf2/ """ def fdiff(self, argindex): x, y = self.args if argindex == 1: return -2*exp(-x**2)/sqrt(S.Pi) elif argindex == 2: return 2*exp(-y**2)/sqrt(S.Pi) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, x, y): I = S.Infinity N = S.NegativeInfinity O = S.Zero if x is S.NaN or y is S.NaN: return S.NaN elif x == y: return S.Zero elif (x is I or x is N or x is O) or (y is I or y is N or y is O): return erf(y) - erf(x) if isinstance(y, erf2inv) and y.args[0] == x: return y.args[1] if x.is_zero or y.is_zero or x.is_extended_real and x.is_infinite or \ y.is_extended_real and y.is_infinite: return erf(y) - erf(x) #Try to pull out -1 factor sign_x = x.could_extract_minus_sign() sign_y = y.could_extract_minus_sign() if (sign_x and sign_y): return -cls(-x, -y) elif (sign_x or sign_y): return erf(y)-erf(x) def _eval_conjugate(self): return self.func(self.args[0].conjugate(), self.args[1].conjugate()) def _eval_is_extended_real(self): return self.args[0].is_extended_real and self.args[1].is_extended_real def _eval_rewrite_as_erf(self, x, y, **kwargs): return erf(y) - erf(x) def _eval_rewrite_as_erfc(self, x, y, **kwargs): return erfc(x) - erfc(y) def _eval_rewrite_as_erfi(self, x, y, **kwargs): return I*(erfi(I*x)-erfi(I*y)) def _eval_rewrite_as_fresnels(self, x, y, **kwargs): return erf(y).rewrite(fresnels) - erf(x).rewrite(fresnels) def _eval_rewrite_as_fresnelc(self, x, y, **kwargs): return erf(y).rewrite(fresnelc) - erf(x).rewrite(fresnelc) def _eval_rewrite_as_meijerg(self, x, y, **kwargs): return erf(y).rewrite(meijerg) - erf(x).rewrite(meijerg) def _eval_rewrite_as_hyper(self, x, y, **kwargs): return erf(y).rewrite(hyper) - erf(x).rewrite(hyper) def _eval_rewrite_as_uppergamma(self, x, y, **kwargs): from sympy import uppergamma return (sqrt(y**2)/y*(S.One - uppergamma(S.Half, y**2)/sqrt(S.Pi)) - sqrt(x**2)/x*(S.One - uppergamma(S.Half, x**2)/sqrt(S.Pi))) def _eval_rewrite_as_expint(self, x, y, **kwargs): return erf(y).rewrite(expint) - erf(x).rewrite(expint) def _eval_expand_func(self, **hints): return self.rewrite(erf) class erfinv(Function): r""" Inverse Error Function. The erfinv function is defined as: .. math :: \mathrm{erf}(x) = y \quad \Rightarrow \quad \mathrm{erfinv}(y) = x Examples ======== >>> from sympy import erfinv >>> from sympy.abc import x Several special values are known: >>> erfinv(0) 0 >>> erfinv(1) oo Differentiation with respect to $x$ is supported: >>> from sympy import diff >>> diff(erfinv(x), x) sqrt(pi)*exp(erfinv(x)**2)/2 We can numerically evaluate the inverse error function to arbitrary precision on [-1, 1]: >>> erfinv(0.2).evalf(30) 0.179143454621291692285822705344 See Also ======== erf: Gaussian error function. erfc: Complementary error function. erfi: Imaginary error function. erf2: Two-argument error function. erfcinv: Inverse Complementary error function. erf2inv: Inverse two-argument error function. References ========== .. [1] https://en.wikipedia.org/wiki/Error_function#Inverse_functions .. [2] http://functions.wolfram.com/GammaBetaErf/InverseErf/ """ def fdiff(self, argindex =1): if argindex == 1: return sqrt(S.Pi)*exp(self.func(self.args[0])**2)*S.Half else : raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return erf @classmethod def eval(cls, z): if z is S.NaN: return S.NaN elif z is S.NegativeOne: return S.NegativeInfinity elif z.is_zero: return S.Zero elif z is S.One: return S.Infinity if isinstance(z, erf) and z.args[0].is_extended_real: return z.args[0] if z.is_zero: return S.Zero # Try to pull out factors of -1 nz = z.extract_multiplicatively(-1) if nz is not None and (isinstance(nz, erf) and (nz.args[0]).is_extended_real): return -nz.args[0] def _eval_rewrite_as_erfcinv(self, z, **kwargs): return erfcinv(1-z) def _eval_is_zero(self): if self.args[0].is_zero: return True class erfcinv (Function): r""" Inverse Complementary Error Function. The erfcinv function is defined as: .. math :: \mathrm{erfc}(x) = y \quad \Rightarrow \quad \mathrm{erfcinv}(y) = x Examples ======== >>> from sympy import erfcinv >>> from sympy.abc import x Several special values are known: >>> erfcinv(1) 0 >>> erfcinv(0) oo Differentiation with respect to $x$ is supported: >>> from sympy import diff >>> diff(erfcinv(x), x) -sqrt(pi)*exp(erfcinv(x)**2)/2 See Also ======== erf: Gaussian error function. erfc: Complementary error function. erfi: Imaginary error function. erf2: Two-argument error function. erfinv: Inverse error function. erf2inv: Inverse two-argument error function. References ========== .. [1] https://en.wikipedia.org/wiki/Error_function#Inverse_functions .. [2] http://functions.wolfram.com/GammaBetaErf/InverseErfc/ """ def fdiff(self, argindex =1): if argindex == 1: return -sqrt(S.Pi)*exp(self.func(self.args[0])**2)*S.Half else: raise ArgumentIndexError(self, argindex) def inverse(self, argindex=1): """ Returns the inverse of this function. """ return erfc @classmethod def eval(cls, z): if z is S.NaN: return S.NaN elif z.is_zero: return S.Infinity elif z is S.One: return S.Zero elif z == 2: return S.NegativeInfinity if z.is_zero: return S.Infinity def _eval_rewrite_as_erfinv(self, z, **kwargs): return erfinv(1-z) class erf2inv(Function): r""" Two-argument Inverse error function. The erf2inv function is defined as: .. math :: \mathrm{erf2}(x, w) = y \quad \Rightarrow \quad \mathrm{erf2inv}(x, y) = w Examples ======== >>> from sympy import erf2inv, oo >>> from sympy.abc import x, y Several special values are known: >>> erf2inv(0, 0) 0 >>> erf2inv(1, 0) 1 >>> erf2inv(0, 1) oo >>> erf2inv(0, y) erfinv(y) >>> erf2inv(oo, y) erfcinv(-y) Differentiation with respect to $x$ and $y$ is supported: >>> from sympy import diff >>> diff(erf2inv(x, y), x) exp(-x**2 + erf2inv(x, y)**2) >>> diff(erf2inv(x, y), y) sqrt(pi)*exp(erf2inv(x, y)**2)/2 See Also ======== erf: Gaussian error function. erfc: Complementary error function. erfi: Imaginary error function. erf2: Two-argument error function. erfinv: Inverse error function. erfcinv: Inverse complementary error function. References ========== .. [1] http://functions.wolfram.com/GammaBetaErf/InverseErf2/ """ def fdiff(self, argindex): x, y = self.args if argindex == 1: return exp(self.func(x,y)**2-x**2) elif argindex == 2: return sqrt(S.Pi)*S.Half*exp(self.func(x,y)**2) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, x, y): if x is S.NaN or y is S.NaN: return S.NaN elif x.is_zero and y.is_zero: return S.Zero elif x.is_zero and y is S.One: return S.Infinity elif x is S.One and y.is_zero: return S.One elif x.is_zero: return erfinv(y) elif x is S.Infinity: return erfcinv(-y) elif y.is_zero: return x elif y is S.Infinity: return erfinv(x) if x.is_zero: if y.is_zero: return S.Zero else: return erfinv(y) if y.is_zero: return x def _eval_is_zero(self): x, y = self.args if x.is_zero and y.is_zero: return True ############################################################################### #################### EXPONENTIAL INTEGRALS #################################### ############################################################################### class Ei(Function): r""" The classical exponential integral. Explanation =========== For use in SymPy, this function is defined as .. math:: \operatorname{Ei}(x) = \sum_{n=1}^\infty \frac{x^n}{n\, n!} + \log(x) + \gamma, where $\gamma$ is the Euler-Mascheroni constant. If $x$ is a polar number, this defines an analytic function on the Riemann surface of the logarithm. Otherwise this defines an analytic function in the cut plane $\mathbb{C} \setminus (-\infty, 0]$. **Background** The name exponential integral comes from the following statement: .. math:: \operatorname{Ei}(x) = \int_{-\infty}^x \frac{e^t}{t} \mathrm{d}t If the integral is interpreted as a Cauchy principal value, this statement holds for $x > 0$ and $\operatorname{Ei}(x)$ as defined above. Examples ======== >>> from sympy import Ei, polar_lift, exp_polar, I, pi >>> from sympy.abc import x >>> Ei(-1) Ei(-1) This yields a real value: >>> Ei(-1).n(chop=True) -0.219383934395520 On the other hand the analytic continuation is not real: >>> Ei(polar_lift(-1)).n(chop=True) -0.21938393439552 + 3.14159265358979*I The exponential integral has a logarithmic branch point at the origin: >>> Ei(x*exp_polar(2*I*pi)) Ei(x) + 2*I*pi Differentiation is supported: >>> Ei(x).diff(x) exp(x)/x The exponential integral is related to many other special functions. For example: >>> from sympy import expint, Shi >>> Ei(x).rewrite(expint) -expint(1, x*exp_polar(I*pi)) - I*pi >>> Ei(x).rewrite(Shi) Chi(x) + Shi(x) See Also ======== expint: Generalised exponential integral. E1: Special case of the generalised exponential integral. li: Logarithmic integral. Li: Offset logarithmic integral. Si: Sine integral. Ci: Cosine integral. Shi: Hyperbolic sine integral. Chi: Hyperbolic cosine integral. uppergamma: Upper incomplete gamma function. References ========== .. [1] http://dlmf.nist.gov/6.6 .. [2] https://en.wikipedia.org/wiki/Exponential_integral .. [3] Abramowitz & Stegun, section 5: http://people.math.sfu.ca/~cbm/aands/page_228.htm """ @classmethod def eval(cls, z): if z.is_zero: return S.NegativeInfinity elif z is S.Infinity: return S.Infinity elif z is S.NegativeInfinity: return S.Zero if z.is_zero: return S.NegativeInfinity nz, n = z.extract_branch_factor() if n: return Ei(nz) + 2*I*pi*n def fdiff(self, argindex=1): from sympy import unpolarify arg = unpolarify(self.args[0]) if argindex == 1: return exp(arg)/arg else: raise ArgumentIndexError(self, argindex) def _eval_evalf(self, prec): if (self.args[0]/polar_lift(-1)).is_positive: return Function._eval_evalf(self, prec) + (I*pi)._eval_evalf(prec) return Function._eval_evalf(self, prec) def _eval_rewrite_as_uppergamma(self, z, **kwargs): from sympy import uppergamma # XXX this does not currently work usefully because uppergamma # immediately turns into expint return -uppergamma(0, polar_lift(-1)*z) - I*pi def _eval_rewrite_as_expint(self, z, **kwargs): return -expint(1, polar_lift(-1)*z) - I*pi def _eval_rewrite_as_li(self, z, **kwargs): if isinstance(z, log): return li(z.args[0]) # TODO: # Actually it only holds that: # Ei(z) = li(exp(z)) # for -pi < imag(z) <= pi return li(exp(z)) def _eval_rewrite_as_Si(self, z, **kwargs): if z.is_negative: return Shi(z) + Chi(z) - I*pi else: return Shi(z) + Chi(z) _eval_rewrite_as_Ci = _eval_rewrite_as_Si _eval_rewrite_as_Chi = _eval_rewrite_as_Si _eval_rewrite_as_Shi = _eval_rewrite_as_Si def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs): return exp(z) * _eis(z) def _eval_as_leading_term(self, x, logx=None, cdir=0): x0 = self.args[0].limit(x, 0) if x0.is_zero: f = self._eval_rewrite_as_Si(*self.args) return f._eval_as_leading_term(x, logx=logx, cdir=cdir) return super()._eval_as_leading_term(x, logx=logx, cdir=cdir) def _eval_nseries(self, x, n, logx, cdir=0): x0 = self.args[0].limit(x, 0) if x0.is_zero: f = self._eval_rewrite_as_Si(*self.args) return f._eval_nseries(x, n, logx) return super()._eval_nseries(x, n, logx) def _eval_aseries(self, n, args0, x, logx): from sympy.series.order import Order point = args0[0] if point is S.Infinity: z = self.args[0] s = [factorial(k) / (z)**k for k in range(0, n)] + \ [Order(1/z**n, x)] return (exp(z)/z) * Add(*s) return super(Ei, self)._eval_aseries(n, args0, x, logx) class expint(Function): r""" Generalized exponential integral. Explanation =========== This function is defined as .. math:: \operatorname{E}_\nu(z) = z^{\nu - 1} \Gamma(1 - \nu, z), where $\Gamma(1 - \nu, z)$ is the upper incomplete gamma function (``uppergamma``). Hence for $z$ with positive real part we have .. math:: \operatorname{E}_\nu(z) = \int_1^\infty \frac{e^{-zt}}{t^\nu} \mathrm{d}t, which explains the name. The representation as an incomplete gamma function provides an analytic continuation for $\operatorname{E}_\nu(z)$. If $\nu$ is a non-positive integer, the exponential integral is thus an unbranched function of $z$, otherwise there is a branch point at the origin. Refer to the incomplete gamma function documentation for details of the branching behavior. Examples ======== >>> from sympy import expint, S >>> from sympy.abc import nu, z Differentiation is supported. Differentiation with respect to $z$ further explains the name: for integral orders, the exponential integral is an iterated integral of the exponential function. >>> expint(nu, z).diff(z) -expint(nu - 1, z) Differentiation with respect to $\nu$ has no classical expression: >>> expint(nu, z).diff(nu) -z**(nu - 1)*meijerg(((), (1, 1)), ((0, 0, 1 - nu), ()), z) At non-postive integer orders, the exponential integral reduces to the exponential function: >>> expint(0, z) exp(-z)/z >>> expint(-1, z) exp(-z)/z + exp(-z)/z**2 At half-integers it reduces to error functions: >>> expint(S(1)/2, z) sqrt(pi)*erfc(sqrt(z))/sqrt(z) At positive integer orders it can be rewritten in terms of exponentials and ``expint(1, z)``. Use ``expand_func()`` to do this: >>> from sympy import expand_func >>> expand_func(expint(5, z)) z**4*expint(1, z)/24 + (-z**3 + z**2 - 2*z + 6)*exp(-z)/24 The generalised exponential integral is essentially equivalent to the incomplete gamma function: >>> from sympy import uppergamma >>> expint(nu, z).rewrite(uppergamma) z**(nu - 1)*uppergamma(1 - nu, z) As such it is branched at the origin: >>> from sympy import exp_polar, pi, I >>> expint(4, z*exp_polar(2*pi*I)) I*pi*z**3/3 + expint(4, z) >>> expint(nu, z*exp_polar(2*pi*I)) z**(nu - 1)*(exp(2*I*pi*nu) - 1)*gamma(1 - nu) + expint(nu, z) See Also ======== Ei: Another related function called exponential integral. E1: The classical case, returns expint(1, z). li: Logarithmic integral. Li: Offset logarithmic integral. Si: Sine integral. Ci: Cosine integral. Shi: Hyperbolic sine integral. Chi: Hyperbolic cosine integral. uppergamma References ========== .. [1] http://dlmf.nist.gov/8.19 .. [2] http://functions.wolfram.com/GammaBetaErf/ExpIntegralE/ .. [3] https://en.wikipedia.org/wiki/Exponential_integral """ @classmethod def eval(cls, nu, z): from sympy import (unpolarify, expand_mul, uppergamma, exp, gamma, factorial) nu2 = unpolarify(nu) if nu != nu2: return expint(nu2, z) if nu.is_Integer and nu <= 0 or (not nu.is_Integer and (2*nu).is_Integer): return unpolarify(expand_mul(z**(nu - 1)*uppergamma(1 - nu, z))) # Extract branching information. This can be deduced from what is # explained in lowergamma.eval(). z, n = z.extract_branch_factor() if n is S.Zero: return if nu.is_integer: if not nu > 0: return return expint(nu, z) \ - 2*pi*I*n*(-1)**(nu - 1)/factorial(nu - 1)*unpolarify(z)**(nu - 1) else: return (exp(2*I*pi*nu*n) - 1)*z**(nu - 1)*gamma(1 - nu) + expint(nu, z) def fdiff(self, argindex): from sympy import meijerg nu, z = self.args if argindex == 1: return -z**(nu - 1)*meijerg([], [1, 1], [0, 0, 1 - nu], [], z) elif argindex == 2: return -expint(nu - 1, z) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_uppergamma(self, nu, z, **kwargs): from sympy import uppergamma return z**(nu - 1)*uppergamma(1 - nu, z) def _eval_rewrite_as_Ei(self, nu, z, **kwargs): from sympy import exp_polar, unpolarify, exp, factorial if nu == 1: return -Ei(z*exp_polar(-I*pi)) - I*pi elif nu.is_Integer and nu > 1: # DLMF, 8.19.7 x = -unpolarify(z) return x**(nu - 1)/factorial(nu - 1)*E1(z).rewrite(Ei) + \ exp(x)/factorial(nu - 1) * \ Add(*[factorial(nu - k - 2)*x**k for k in range(nu - 1)]) else: return self def _eval_expand_func(self, **hints): return self.rewrite(Ei).rewrite(expint, **hints) def _eval_rewrite_as_Si(self, nu, z, **kwargs): if nu != 1: return self return Shi(z) - Chi(z) _eval_rewrite_as_Ci = _eval_rewrite_as_Si _eval_rewrite_as_Chi = _eval_rewrite_as_Si _eval_rewrite_as_Shi = _eval_rewrite_as_Si def _eval_nseries(self, x, n, logx, cdir=0): if not self.args[0].has(x): nu = self.args[0] if nu == 1: f = self._eval_rewrite_as_Si(*self.args) return f._eval_nseries(x, n, logx) elif nu.is_Integer and nu > 1: f = self._eval_rewrite_as_Ei(*self.args) return f._eval_nseries(x, n, logx) return super()._eval_nseries(x, n, logx) def _eval_aseries(self, n, args0, x, logx): from sympy.series.order import Order point = args0[1] nu = self.args[0] if point is S.Infinity: z = self.args[1] s = [(-1)**k * RisingFactorial(nu, k) / z**k for k in range(0, n)] + [Order(1/z**n, x)] return (exp(-z)/z) * Add(*s) return super(expint, self)._eval_aseries(n, args0, x, logx) def E1(z): """ Classical case of the generalized exponential integral. Explanation =========== This is equivalent to ``expint(1, z)``. Examples ======== >>> from sympy import E1 >>> E1(0) expint(1, 0) >>> E1(5) expint(1, 5) See Also ======== Ei: Exponential integral. expint: Generalised exponential integral. li: Logarithmic integral. Li: Offset logarithmic integral. Si: Sine integral. Ci: Cosine integral. Shi: Hyperbolic sine integral. Chi: Hyperbolic cosine integral. """ return expint(1, z) class li(Function): r""" The classical logarithmic integral. Explanation =========== For use in SymPy, this function is defined as .. math:: \operatorname{li}(x) = \int_0^x \frac{1}{\log(t)} \mathrm{d}t \,. Examples ======== >>> from sympy import I, oo, li >>> from sympy.abc import z Several special values are known: >>> li(0) 0 >>> li(1) -oo >>> li(oo) oo Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(li(z), z) 1/log(z) Defining the ``li`` function via an integral: >>> from sympy import integrate >>> integrate(li(z)) z*li(z) - Ei(2*log(z)) >>> integrate(li(z),z) z*li(z) - Ei(2*log(z)) The logarithmic integral can also be defined in terms of ``Ei``: >>> from sympy import Ei >>> li(z).rewrite(Ei) Ei(log(z)) >>> diff(li(z).rewrite(Ei), z) 1/log(z) We can numerically evaluate the logarithmic integral to arbitrary precision on the whole complex plane (except the singular points): >>> li(2).evalf(30) 1.04516378011749278484458888919 >>> li(2*I).evalf(30) 1.0652795784357498247001125598 + 3.08346052231061726610939702133*I We can even compute Soldner's constant by the help of mpmath: >>> from mpmath import findroot >>> findroot(li, 2) 1.45136923488338 Further transformations include rewriting ``li`` in terms of the trigonometric integrals ``Si``, ``Ci``, ``Shi`` and ``Chi``: >>> from sympy import Si, Ci, Shi, Chi >>> li(z).rewrite(Si) -log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)) >>> li(z).rewrite(Ci) -log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z)) >>> li(z).rewrite(Shi) -log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z)) >>> li(z).rewrite(Chi) -log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z)) See Also ======== Li: Offset logarithmic integral. Ei: Exponential integral. expint: Generalised exponential integral. E1: Special case of the generalised exponential integral. Si: Sine integral. Ci: Cosine integral. Shi: Hyperbolic sine integral. Chi: Hyperbolic cosine integral. References ========== .. [1] https://en.wikipedia.org/wiki/Logarithmic_integral .. [2] http://mathworld.wolfram.com/LogarithmicIntegral.html .. [3] http://dlmf.nist.gov/6 .. [4] http://mathworld.wolfram.com/SoldnersConstant.html """ @classmethod def eval(cls, z): if z.is_zero: return S.Zero elif z is S.One: return S.NegativeInfinity elif z is S.Infinity: return S.Infinity if z.is_zero: return S.Zero def fdiff(self, argindex=1): arg = self.args[0] if argindex == 1: return S.One / log(arg) else: raise ArgumentIndexError(self, argindex) def _eval_conjugate(self): z = self.args[0] # Exclude values on the branch cut (-oo, 0) if not z.is_extended_negative: return self.func(z.conjugate()) def _eval_rewrite_as_Li(self, z, **kwargs): return Li(z) + li(2) def _eval_rewrite_as_Ei(self, z, **kwargs): return Ei(log(z)) def _eval_rewrite_as_uppergamma(self, z, **kwargs): from sympy import uppergamma return (-uppergamma(0, -log(z)) + S.Half*(log(log(z)) - log(S.One/log(z))) - log(-log(z))) def _eval_rewrite_as_Si(self, z, **kwargs): return (Ci(I*log(z)) - I*Si(I*log(z)) - S.Half*(log(S.One/log(z)) - log(log(z))) - log(I*log(z))) _eval_rewrite_as_Ci = _eval_rewrite_as_Si def _eval_rewrite_as_Shi(self, z, **kwargs): return (Chi(log(z)) - Shi(log(z)) - S.Half*(log(S.One/log(z)) - log(log(z)))) _eval_rewrite_as_Chi = _eval_rewrite_as_Shi def _eval_rewrite_as_hyper(self, z, **kwargs): return (log(z)*hyper((1, 1), (2, 2), log(z)) + S.Half*(log(log(z)) - log(S.One/log(z))) + S.EulerGamma) def _eval_rewrite_as_meijerg(self, z, **kwargs): return (-log(-log(z)) - S.Half*(log(S.One/log(z)) - log(log(z))) - meijerg(((), (1,)), ((0, 0), ()), -log(z))) def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs): return z * _eis(log(z)) def _eval_nseries(self, x, n, logx, cdir=0): z = self.args[0] s = [(log(z))**k / (factorial(k) * k) for k in range(1, n)] return S.EulerGamma + log(log(z)) + Add(*s) def _eval_is_zero(self): z = self.args[0] if z.is_zero: return True class Li(Function): r""" The offset logarithmic integral. Explanation =========== For use in SymPy, this function is defined as .. math:: \operatorname{Li}(x) = \operatorname{li}(x) - \operatorname{li}(2) Examples ======== >>> from sympy import Li >>> from sympy.abc import z The following special value is known: >>> Li(2) 0 Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(Li(z), z) 1/log(z) The shifted logarithmic integral can be written in terms of $li(z)$: >>> from sympy import li >>> Li(z).rewrite(li) li(z) - li(2) We can numerically evaluate the logarithmic integral to arbitrary precision on the whole complex plane (except the singular points): >>> Li(2).evalf(30) 0 >>> Li(4).evalf(30) 1.92242131492155809316615998938 See Also ======== li: Logarithmic integral. Ei: Exponential integral. expint: Generalised exponential integral. E1: Special case of the generalised exponential integral. Si: Sine integral. Ci: Cosine integral. Shi: Hyperbolic sine integral. Chi: Hyperbolic cosine integral. References ========== .. [1] https://en.wikipedia.org/wiki/Logarithmic_integral .. [2] http://mathworld.wolfram.com/LogarithmicIntegral.html .. [3] http://dlmf.nist.gov/6 """ @classmethod def eval(cls, z): if z is S.Infinity: return S.Infinity elif z == S(2): return S.Zero def fdiff(self, argindex=1): arg = self.args[0] if argindex == 1: return S.One / log(arg) else: raise ArgumentIndexError(self, argindex) def _eval_evalf(self, prec): return self.rewrite(li).evalf(prec) def _eval_rewrite_as_li(self, z, **kwargs): return li(z) - li(2) def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs): return self.rewrite(li).rewrite("tractable", deep=True) def _eval_nseries(self, x, n, logx, cdir=0): f = self._eval_rewrite_as_li(*self.args) return f._eval_nseries(x, n, logx) ############################################################################### #################### TRIGONOMETRIC INTEGRALS ################################## ############################################################################### class TrigonometricIntegral(Function): """ Base class for trigonometric integrals. """ @classmethod def eval(cls, z): if z is S.Zero: return cls._atzero elif z is S.Infinity: return cls._atinf() elif z is S.NegativeInfinity: return cls._atneginf() if z.is_zero: return cls._atzero nz = z.extract_multiplicatively(polar_lift(I)) if nz is None and cls._trigfunc(0) == 0: nz = z.extract_multiplicatively(I) if nz is not None: return cls._Ifactor(nz, 1) nz = z.extract_multiplicatively(polar_lift(-I)) if nz is not None: return cls._Ifactor(nz, -1) nz = z.extract_multiplicatively(polar_lift(-1)) if nz is None and cls._trigfunc(0) == 0: nz = z.extract_multiplicatively(-1) if nz is not None: return cls._minusfactor(nz) nz, n = z.extract_branch_factor() if n == 0 and nz == z: return return 2*pi*I*n*cls._trigfunc(0) + cls(nz) def fdiff(self, argindex=1): from sympy import unpolarify arg = unpolarify(self.args[0]) if argindex == 1: return self._trigfunc(arg)/arg else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_Ei(self, z, **kwargs): return self._eval_rewrite_as_expint(z).rewrite(Ei) def _eval_rewrite_as_uppergamma(self, z, **kwargs): from sympy import uppergamma return self._eval_rewrite_as_expint(z).rewrite(uppergamma) def _eval_nseries(self, x, n, logx, cdir=0): # NOTE this is fairly inefficient from sympy import log, EulerGamma, Pow n += 1 if self.args[0].subs(x, 0) != 0: return super()._eval_nseries(x, n, logx) baseseries = self._trigfunc(x)._eval_nseries(x, n, logx) if self._trigfunc(0) != 0: baseseries -= 1 baseseries = baseseries.replace(Pow, lambda t, n: t**n/n, simultaneous=False) if self._trigfunc(0) != 0: baseseries += EulerGamma + log(x) return baseseries.subs(x, self.args[0])._eval_nseries(x, n, logx) class Si(TrigonometricIntegral): r""" Sine integral. Explanation =========== This function is defined by .. math:: \operatorname{Si}(z) = \int_0^z \frac{\sin{t}}{t} \mathrm{d}t. It is an entire function. Examples ======== >>> from sympy import Si >>> from sympy.abc import z The sine integral is an antiderivative of $sin(z)/z$: >>> Si(z).diff(z) sin(z)/z It is unbranched: >>> from sympy import exp_polar, I, pi >>> Si(z*exp_polar(2*I*pi)) Si(z) Sine integral behaves much like ordinary sine under multiplication by ``I``: >>> Si(I*z) I*Shi(z) >>> Si(-z) -Si(z) It can also be expressed in terms of exponential integrals, but beware that the latter is branched: >>> from sympy import expint >>> Si(z).rewrite(expint) -I*(-expint(1, z*exp_polar(-I*pi/2))/2 + expint(1, z*exp_polar(I*pi/2))/2) + pi/2 It can be rewritten in the form of sinc function (by definition): >>> from sympy import sinc >>> Si(z).rewrite(sinc) Integral(sinc(t), (t, 0, z)) See Also ======== Ci: Cosine integral. Shi: Hyperbolic sine integral. Chi: Hyperbolic cosine integral. Ei: Exponential integral. expint: Generalised exponential integral. sinc: unnormalized sinc function E1: Special case of the generalised exponential integral. li: Logarithmic integral. Li: Offset logarithmic integral. References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral """ _trigfunc = sin _atzero = S.Zero @classmethod def _atinf(cls): return pi*S.Half @classmethod def _atneginf(cls): return -pi*S.Half @classmethod def _minusfactor(cls, z): return -Si(z) @classmethod def _Ifactor(cls, z, sign): return I*Shi(z)*sign def _eval_rewrite_as_expint(self, z, **kwargs): # XXX should we polarify z? return pi/2 + (E1(polar_lift(I)*z) - E1(polar_lift(-I)*z))/2/I def _eval_rewrite_as_sinc(self, z, **kwargs): from sympy import Integral t = Symbol('t', Dummy=True) return Integral(sinc(t), (t, 0, z)) def _eval_aseries(self, n, args0, x, logx): from sympy.series.order import Order point = args0[0] # Expansion at oo if point is S.Infinity: z = self.args[0] p = [(-1)**k * factorial(2*k) / z**(2*k) for k in range(0, int((n - 1)/2))] + [Order(1/z**n, x)] q = [(-1)**k * factorial(2*k + 1) / z**(2*k + 1) for k in range(0, int(n/2) - 1)] + [Order(1/z**n, x)] return pi/2 - (cos(z)/z)*Add(*p) - (sin(z)/z)*Add(*q) # All other points are not handled return super(Si, self)._eval_aseries(n, args0, x, logx) def _eval_is_zero(self): z = self.args[0] if z.is_zero: return True class Ci(TrigonometricIntegral): r""" Cosine integral. Explanation =========== This function is defined for positive $x$ by .. math:: \operatorname{Ci}(x) = \gamma + \log{x} + \int_0^x \frac{\cos{t} - 1}{t} \mathrm{d}t = -\int_x^\infty \frac{\cos{t}}{t} \mathrm{d}t, where $\gamma$ is the Euler-Mascheroni constant. We have .. math:: \operatorname{Ci}(z) = -\frac{\operatorname{E}_1\left(e^{i\pi/2} z\right) + \operatorname{E}_1\left(e^{-i \pi/2} z\right)}{2} which holds for all polar $z$ and thus provides an analytic continuation to the Riemann surface of the logarithm. The formula also holds as stated for $z \in \mathbb{C}$ with $\Re(z) > 0$. By lifting to the principal branch, we obtain an analytic function on the cut complex plane. Examples ======== >>> from sympy import Ci >>> from sympy.abc import z The cosine integral is a primitive of $\cos(z)/z$: >>> Ci(z).diff(z) cos(z)/z It has a logarithmic branch point at the origin: >>> from sympy import exp_polar, I, pi >>> Ci(z*exp_polar(2*I*pi)) Ci(z) + 2*I*pi The cosine integral behaves somewhat like ordinary $\cos$ under multiplication by $i$: >>> from sympy import polar_lift >>> Ci(polar_lift(I)*z) Chi(z) + I*pi/2 >>> Ci(polar_lift(-1)*z) Ci(z) + I*pi It can also be expressed in terms of exponential integrals: >>> from sympy import expint >>> Ci(z).rewrite(expint) -expint(1, z*exp_polar(-I*pi/2))/2 - expint(1, z*exp_polar(I*pi/2))/2 See Also ======== Si: Sine integral. Shi: Hyperbolic sine integral. Chi: Hyperbolic cosine integral. Ei: Exponential integral. expint: Generalised exponential integral. E1: Special case of the generalised exponential integral. li: Logarithmic integral. Li: Offset logarithmic integral. References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral """ _trigfunc = cos _atzero = S.ComplexInfinity @classmethod def _atinf(cls): return S.Zero @classmethod def _atneginf(cls): return I*pi @classmethod def _minusfactor(cls, z): return Ci(z) + I*pi @classmethod def _Ifactor(cls, z, sign): return Chi(z) + I*pi/2*sign def _eval_rewrite_as_expint(self, z, **kwargs): return -(E1(polar_lift(I)*z) + E1(polar_lift(-I)*z))/2 def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.NaN: arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if arg0.is_zero: return S.EulerGamma elif arg0.is_finite: return self.func(arg0) else: return self def _eval_aseries(self, n, args0, x, logx): from sympy.series.order import Order point = args0[0] # Expansion at oo if point is S.Infinity: z = self.args[0] p = [(-1)**k * factorial(2*k) / z**(2*k) for k in range(0, int((n - 1)/2))] + [Order(1/z**n, x)] q = [(-1)**k * factorial(2*k + 1) / z**(2*k + 1) for k in range(0, int(n/2) - 1)] + [Order(1/z**n, x)] return (sin(z)/z)*Add(*p) - (cos(z)/z)*Add(*q) # All other points are not handled return super(Ci, self)._eval_aseries(n, args0, x, logx) class Shi(TrigonometricIntegral): r""" Sinh integral. Explanation =========== This function is defined by .. math:: \operatorname{Shi}(z) = \int_0^z \frac{\sinh{t}}{t} \mathrm{d}t. It is an entire function. Examples ======== >>> from sympy import Shi >>> from sympy.abc import z The Sinh integral is a primitive of $\sinh(z)/z$: >>> Shi(z).diff(z) sinh(z)/z It is unbranched: >>> from sympy import exp_polar, I, pi >>> Shi(z*exp_polar(2*I*pi)) Shi(z) The $\sinh$ integral behaves much like ordinary $\sinh$ under multiplication by $i$: >>> Shi(I*z) I*Si(z) >>> Shi(-z) -Shi(z) It can also be expressed in terms of exponential integrals, but beware that the latter is branched: >>> from sympy import expint >>> Shi(z).rewrite(expint) expint(1, z)/2 - expint(1, z*exp_polar(I*pi))/2 - I*pi/2 See Also ======== Si: Sine integral. Ci: Cosine integral. Chi: Hyperbolic cosine integral. Ei: Exponential integral. expint: Generalised exponential integral. E1: Special case of the generalised exponential integral. li: Logarithmic integral. Li: Offset logarithmic integral. References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral """ _trigfunc = sinh _atzero = S.Zero @classmethod def _atinf(cls): return S.Infinity @classmethod def _atneginf(cls): return S.NegativeInfinity @classmethod def _minusfactor(cls, z): return -Shi(z) @classmethod def _Ifactor(cls, z, sign): return I*Si(z)*sign def _eval_rewrite_as_expint(self, z, **kwargs): from sympy import exp_polar # XXX should we polarify z? return (E1(z) - E1(exp_polar(I*pi)*z))/2 - I*pi/2 def _eval_is_zero(self): z = self.args[0] if z.is_zero: return True def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x) arg0 = arg.subs(x, 0) if arg0 is S.NaN: arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if arg0.is_zero: return arg elif not arg0.is_infinite: return self.func(arg0) elif arg0.is_infinite: return -pi*S.ImaginaryUnit/2 else: return self class Chi(TrigonometricIntegral): r""" Cosh integral. Explanation =========== This function is defined for positive $x$ by .. math:: \operatorname{Chi}(x) = \gamma + \log{x} + \int_0^x \frac{\cosh{t} - 1}{t} \mathrm{d}t, where $\gamma$ is the Euler-Mascheroni constant. We have .. math:: \operatorname{Chi}(z) = \operatorname{Ci}\left(e^{i \pi/2}z\right) - i\frac{\pi}{2}, which holds for all polar $z$ and thus provides an analytic continuation to the Riemann surface of the logarithm. By lifting to the principal branch we obtain an analytic function on the cut complex plane. Examples ======== >>> from sympy import Chi >>> from sympy.abc import z The $\cosh$ integral is a primitive of $\cosh(z)/z$: >>> Chi(z).diff(z) cosh(z)/z It has a logarithmic branch point at the origin: >>> from sympy import exp_polar, I, pi >>> Chi(z*exp_polar(2*I*pi)) Chi(z) + 2*I*pi The $\cosh$ integral behaves somewhat like ordinary $\cosh$ under multiplication by $i$: >>> from sympy import polar_lift >>> Chi(polar_lift(I)*z) Ci(z) + I*pi/2 >>> Chi(polar_lift(-1)*z) Chi(z) + I*pi It can also be expressed in terms of exponential integrals: >>> from sympy import expint >>> Chi(z).rewrite(expint) -expint(1, z)/2 - expint(1, z*exp_polar(I*pi))/2 - I*pi/2 See Also ======== Si: Sine integral. Ci: Cosine integral. Shi: Hyperbolic sine integral. Ei: Exponential integral. expint: Generalised exponential integral. E1: Special case of the generalised exponential integral. li: Logarithmic integral. Li: Offset logarithmic integral. References ========== .. [1] https://en.wikipedia.org/wiki/Trigonometric_integral """ _trigfunc = cosh _atzero = S.ComplexInfinity @classmethod def _atinf(cls): return S.Infinity @classmethod def _atneginf(cls): return S.Infinity @classmethod def _minusfactor(cls, z): return Chi(z) + I*pi @classmethod def _Ifactor(cls, z, sign): return Ci(z) + I*pi/2*sign def _eval_rewrite_as_expint(self, z, **kwargs): from sympy import exp_polar return -I*pi/2 - (E1(z) + E1(exp_polar(I*pi)*z))/2 def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.NaN: arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if arg0.is_zero: return S.EulerGamma elif arg0.is_finite: return self.func(arg0) else: return self ############################################################################### #################### FRESNEL INTEGRALS ######################################## ############################################################################### class FresnelIntegral(Function): """ Base class for the Fresnel integrals.""" unbranched = True @classmethod def eval(cls, z): # Values at positive infinities signs # if any were extracted automatically if z is S.Infinity: return S.Half # Value at zero if z.is_zero: return S.Zero # Try to pull out factors of -1 and I prefact = S.One newarg = z changed = False nz = newarg.extract_multiplicatively(-1) if nz is not None: prefact = -prefact newarg = nz changed = True nz = newarg.extract_multiplicatively(I) if nz is not None: prefact = cls._sign*I*prefact newarg = nz changed = True if changed: return prefact*cls(newarg) def fdiff(self, argindex=1): if argindex == 1: return self._trigfunc(S.Half*pi*self.args[0]**2) else: raise ArgumentIndexError(self, argindex) def _eval_is_extended_real(self): return self.args[0].is_extended_real _eval_is_finite = _eval_is_extended_real def _eval_is_zero(self): z = self.args[0] if z.is_zero: return True def _eval_conjugate(self): return self.func(self.args[0].conjugate()) as_real_imag = real_to_real_as_real_imag class fresnels(FresnelIntegral): r""" Fresnel integral S. Explanation =========== This function is defined by .. math:: \operatorname{S}(z) = \int_0^z \sin{\frac{\pi}{2} t^2} \mathrm{d}t. It is an entire function. Examples ======== >>> from sympy import I, oo, fresnels >>> from sympy.abc import z Several special values are known: >>> fresnels(0) 0 >>> fresnels(oo) 1/2 >>> fresnels(-oo) -1/2 >>> fresnels(I*oo) -I/2 >>> fresnels(-I*oo) I/2 In general one can pull out factors of -1 and $i$ from the argument: >>> fresnels(-z) -fresnels(z) >>> fresnels(I*z) -I*fresnels(z) The Fresnel S integral obeys the mirror symmetry $\overline{S(z)} = S(\bar{z})$: >>> from sympy import conjugate >>> conjugate(fresnels(z)) fresnels(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(fresnels(z), z) sin(pi*z**2/2) Defining the Fresnel functions via an integral: >>> from sympy import integrate, pi, sin, expand_func >>> integrate(sin(pi*z**2/2), z) 3*fresnels(z)*gamma(3/4)/(4*gamma(7/4)) >>> expand_func(integrate(sin(pi*z**2/2), z)) fresnels(z) We can numerically evaluate the Fresnel integral to arbitrary precision on the whole complex plane: >>> fresnels(2).evalf(30) 0.343415678363698242195300815958 >>> fresnels(-2*I).evalf(30) 0.343415678363698242195300815958*I See Also ======== fresnelc: Fresnel cosine integral. References ========== .. [1] https://en.wikipedia.org/wiki/Fresnel_integral .. [2] http://dlmf.nist.gov/7 .. [3] http://mathworld.wolfram.com/FresnelIntegrals.html .. [4] http://functions.wolfram.com/GammaBetaErf/FresnelS .. [5] The converging factors for the fresnel integrals by John W. Wrench Jr. and Vicki Alley """ _trigfunc = sin _sign = -S.One @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0: return S.Zero else: x = sympify(x) if len(previous_terms) > 1: p = previous_terms[-1] return (-pi**2*x**4*(4*n - 1)/(8*n*(2*n + 1)*(4*n + 3))) * p else: return x**3 * (-x**4)**n * (S(2)**(-2*n - 1)*pi**(2*n + 1)) / ((4*n + 3)*factorial(2*n + 1)) def _eval_rewrite_as_erf(self, z, **kwargs): return (S.One + I)/4 * (erf((S.One + I)/2*sqrt(pi)*z) - I*erf((S.One - I)/2*sqrt(pi)*z)) def _eval_rewrite_as_hyper(self, z, **kwargs): return pi*z**3/6 * hyper([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)], -pi**2*z**4/16) def _eval_rewrite_as_meijerg(self, z, **kwargs): return (pi*z**Rational(9, 4) / (sqrt(2)*(z**2)**Rational(3, 4)*(-z)**Rational(3, 4)) * meijerg([], [1], [Rational(3, 4)], [Rational(1, 4), 0], -pi**2*z**4/16)) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy.series.order import Order arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.ComplexInfinity: arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if arg0.is_zero: return pi*arg**3/6 elif arg0 in [S.Infinity, S.NegativeInfinity]: s = 1 if arg0 is S.Infinity else -1 return s*S.Half + Order(x, x) else: return self.func(arg0) def _eval_aseries(self, n, args0, x, logx): from sympy import Order point = args0[0] # Expansion at oo and -oo if point in [S.Infinity, -S.Infinity]: z = self.args[0] # expansion of S(x) = S1(x*sqrt(pi/2)), see reference[5] page 1-8 # as only real infinities are dealt with, sin and cos are O(1) p = [(-1)**k * factorial(4*k + 1) / (2**(2*k + 2) * z**(4*k + 3) * 2**(2*k)*factorial(2*k)) for k in range(0, n) if 4*k + 3 < n] q = [1/(2*z)] + [(-1)**k * factorial(4*k - 1) / (2**(2*k + 1) * z**(4*k + 1) * 2**(2*k - 1)*factorial(2*k - 1)) for k in range(1, n) if 4*k + 1 < n] p = [-sqrt(2/pi)*t for t in p] q = [-sqrt(2/pi)*t for t in q] s = 1 if point is S.Infinity else -1 # The expansion at oo is 1/2 + some odd powers of z # To get the expansion at -oo, replace z by -z and flip the sign # The result -1/2 + the same odd powers of z as before. return s*S.Half + (sin(z**2)*Add(*p) + cos(z**2)*Add(*q) ).subs(x, sqrt(2/pi)*x) + Order(1/z**n, x) # All other points are not handled return super()._eval_aseries(n, args0, x, logx) class fresnelc(FresnelIntegral): r""" Fresnel integral C. Explanation =========== This function is defined by .. math:: \operatorname{C}(z) = \int_0^z \cos{\frac{\pi}{2} t^2} \mathrm{d}t. It is an entire function. Examples ======== >>> from sympy import I, oo, fresnelc >>> from sympy.abc import z Several special values are known: >>> fresnelc(0) 0 >>> fresnelc(oo) 1/2 >>> fresnelc(-oo) -1/2 >>> fresnelc(I*oo) I/2 >>> fresnelc(-I*oo) -I/2 In general one can pull out factors of -1 and $i$ from the argument: >>> fresnelc(-z) -fresnelc(z) >>> fresnelc(I*z) I*fresnelc(z) The Fresnel C integral obeys the mirror symmetry $\overline{C(z)} = C(\bar{z})$: >>> from sympy import conjugate >>> conjugate(fresnelc(z)) fresnelc(conjugate(z)) Differentiation with respect to $z$ is supported: >>> from sympy import diff >>> diff(fresnelc(z), z) cos(pi*z**2/2) Defining the Fresnel functions via an integral: >>> from sympy import integrate, pi, cos, expand_func >>> integrate(cos(pi*z**2/2), z) fresnelc(z)*gamma(1/4)/(4*gamma(5/4)) >>> expand_func(integrate(cos(pi*z**2/2), z)) fresnelc(z) We can numerically evaluate the Fresnel integral to arbitrary precision on the whole complex plane: >>> fresnelc(2).evalf(30) 0.488253406075340754500223503357 >>> fresnelc(-2*I).evalf(30) -0.488253406075340754500223503357*I See Also ======== fresnels: Fresnel sine integral. References ========== .. [1] https://en.wikipedia.org/wiki/Fresnel_integral .. [2] http://dlmf.nist.gov/7 .. [3] http://mathworld.wolfram.com/FresnelIntegrals.html .. [4] http://functions.wolfram.com/GammaBetaErf/FresnelC .. [5] The converging factors for the fresnel integrals by John W. Wrench Jr. and Vicki Alley """ _trigfunc = cos _sign = S.One @staticmethod @cacheit def taylor_term(n, x, *previous_terms): if n < 0: return S.Zero else: x = sympify(x) if len(previous_terms) > 1: p = previous_terms[-1] return (-pi**2*x**4*(4*n - 3)/(8*n*(2*n - 1)*(4*n + 1))) * p else: return x * (-x**4)**n * (S(2)**(-2*n)*pi**(2*n)) / ((4*n + 1)*factorial(2*n)) def _eval_rewrite_as_erf(self, z, **kwargs): return (S.One - I)/4 * (erf((S.One + I)/2*sqrt(pi)*z) + I*erf((S.One - I)/2*sqrt(pi)*z)) def _eval_rewrite_as_hyper(self, z, **kwargs): return z * hyper([Rational(1, 4)], [S.Half, Rational(5, 4)], -pi**2*z**4/16) def _eval_rewrite_as_meijerg(self, z, **kwargs): return (pi*z**Rational(3, 4) / (sqrt(2)*root(z**2, 4)*root(-z, 4)) * meijerg([], [1], [Rational(1, 4)], [Rational(3, 4), 0], -pi**2*z**4/16)) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order arg = self.args[0].as_leading_term(x, logx=logx, cdir=cdir) arg0 = arg.subs(x, 0) if arg0 is S.ComplexInfinity: arg0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if arg0.is_zero: return arg elif arg0 in [S.Infinity, S.NegativeInfinity]: s = 1 if arg0 is S.Infinity else -1 return s*S.Half + Order(x, x) else: return self.func(arg0) def _eval_aseries(self, n, args0, x, logx): from sympy import Order point = args0[0] # Expansion at oo if point in [S.Infinity, -S.Infinity]: z = self.args[0] # expansion of C(x) = C1(x*sqrt(pi/2)), see reference[5] page 1-8 # as only real infinities are dealt with, sin and cos are O(1) p = [(-1)**k * factorial(4*k + 1) / (2**(2*k + 2) * z**(4*k + 3) * 2**(2*k)*factorial(2*k)) for k in range(0, n) if 4*k + 3 < n] q = [1/(2*z)] + [(-1)**k * factorial(4*k - 1) / (2**(2*k + 1) * z**(4*k + 1) * 2**(2*k - 1)*factorial(2*k - 1)) for k in range(1, n) if 4*k + 1 < n] p = [-sqrt(2/pi)*t for t in p] q = [ sqrt(2/pi)*t for t in q] s = 1 if point is S.Infinity else -1 # The expansion at oo is 1/2 + some odd powers of z # To get the expansion at -oo, replace z by -z and flip the sign # The result -1/2 + the same odd powers of z as before. return s*S.Half + (cos(z**2)*Add(*p) + sin(z**2)*Add(*q) ).subs(x, sqrt(2/pi)*x) + Order(1/z**n, x) # All other points are not handled return super()._eval_aseries(n, args0, x, logx) ############################################################################### #################### HELPER FUNCTIONS ######################################### ############################################################################### class _erfs(Function): """ Helper function to make the $\\mathrm{erf}(z)$ function tractable for the Gruntz algorithm. """ @classmethod def eval(cls, arg): if arg.is_zero: return S.One def _eval_aseries(self, n, args0, x, logx): from sympy import Order point = args0[0] # Expansion at oo if point is S.Infinity: z = self.args[0] l = [ 1/sqrt(S.Pi) * factorial(2*k)*(-S( 4))**(-k)/factorial(k) * (1/z)**(2*k + 1) for k in range(0, n) ] o = Order(1/z**(2*n + 1), x) # It is very inefficient to first add the order and then do the nseries return (Add(*l))._eval_nseries(x, n, logx) + o # Expansion at I*oo t = point.extract_multiplicatively(S.ImaginaryUnit) if t is S.Infinity: z = self.args[0] # TODO: is the series really correct? l = [ 1/sqrt(S.Pi) * factorial(2*k)*(-S( 4))**(-k)/factorial(k) * (1/z)**(2*k + 1) for k in range(0, n) ] o = Order(1/z**(2*n + 1), x) # It is very inefficient to first add the order and then do the nseries return (Add(*l))._eval_nseries(x, n, logx) + o # All other points are not handled return super()._eval_aseries(n, args0, x, logx) def fdiff(self, argindex=1): if argindex == 1: z = self.args[0] return -2/sqrt(S.Pi) + 2*z*_erfs(z) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_intractable(self, z, **kwargs): return (S.One - erf(z))*exp(z**2) class _eis(Function): """ Helper function to make the $\\mathrm{Ei}(z)$ and $\\mathrm{li}(z)$ functions tractable for the Gruntz algorithm. """ def _eval_aseries(self, n, args0, x, logx): from sympy import Order if args0[0] != S.Infinity: return super(_erfs, self)._eval_aseries(n, args0, x, logx) z = self.args[0] l = [ factorial(k) * (1/z)**(k + 1) for k in range(0, n) ] o = Order(1/z**(n + 1), x) # It is very inefficient to first add the order and then do the nseries return (Add(*l))._eval_nseries(x, n, logx) + o def fdiff(self, argindex=1): if argindex == 1: z = self.args[0] return S.One / z - _eis(z) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_intractable(self, z, **kwargs): return exp(-z)*Ei(z) def _eval_as_leading_term(self, x, logx=None, cdir=0): x0 = self.args[0].limit(x, 0) if x0.is_zero: f = self._eval_rewrite_as_intractable(*self.args) return f._eval_as_leading_term(x, logx=logx, cdir=cdir) return super()._eval_as_leading_term(x, logx=logx, cdir=cdir) def _eval_nseries(self, x, n, logx, cdir=0): x0 = self.args[0].limit(x, 0) if x0.is_zero: f = self._eval_rewrite_as_intractable(*self.args) return f._eval_nseries(x, n, logx) return super()._eval_nseries(x, n, logx) sympy-sympy-1.9/sympy/functions/special/gamma_functions.py000066400000000000000000001216551412543434000242720ustar00rootroot00000000000000from sympy.core import Add, S, sympify, oo, pi, Dummy, expand_func from sympy.core.compatibility import as_int from sympy.core.function import Function, ArgumentIndexError from sympy.core.logic import fuzzy_and, fuzzy_not from sympy.core.numbers import Rational from sympy.core.power import Pow from sympy.functions.special.zeta_functions import zeta from sympy.functions.special.error_functions import erf, erfc, Ei from sympy.functions.elementary.complexes import re from sympy.functions.elementary.exponential import exp, log from sympy.functions.elementary.integers import ceiling, floor from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import sin, cos, cot from sympy.functions.combinatorial.numbers import bernoulli, harmonic from sympy.functions.combinatorial.factorials import factorial, rf, RisingFactorial def intlike(n): try: as_int(n, strict=False) return True except ValueError: return False ############################################################################### ############################ COMPLETE GAMMA FUNCTION ########################## ############################################################################### class gamma(Function): r""" The gamma function .. math:: \Gamma(x) := \int^{\infty}_{0} t^{x-1} e^{-t} \mathrm{d}t. Explanation =========== The ``gamma`` function implements the function which passes through the values of the factorial function (i.e., $\Gamma(n) = (n - 1)!$ when n is an integer). More generally, $\Gamma(z)$ is defined in the whole complex plane except at the negative integers where there are simple poles. Examples ======== >>> from sympy import S, I, pi, gamma >>> from sympy.abc import x Several special values are known: >>> gamma(1) 1 >>> gamma(4) 6 >>> gamma(S(3)/2) sqrt(pi)/2 The ``gamma`` function obeys the mirror symmetry: >>> from sympy import conjugate >>> conjugate(gamma(x)) gamma(conjugate(x)) Differentiation with respect to $x$ is supported: >>> from sympy import diff >>> diff(gamma(x), x) gamma(x)*polygamma(0, x) Series expansion is also supported: >>> from sympy import series >>> series(gamma(x), x, 0, 3) 1/x - EulerGamma + x*(EulerGamma**2/2 + pi**2/12) + x**2*(-EulerGamma*pi**2/12 + polygamma(2, 1)/6 - EulerGamma**3/6) + O(x**3) We can numerically evaluate the ``gamma`` function to arbitrary precision on the whole complex plane: >>> gamma(pi).evalf(40) 2.288037795340032417959588909060233922890 >>> gamma(1+I).evalf(20) 0.49801566811835604271 - 0.15494982830181068512*I See Also ======== lowergamma: Lower incomplete gamma function. uppergamma: Upper incomplete gamma function. polygamma: Polygamma function. loggamma: Log Gamma function. digamma: Digamma function. trigamma: Trigamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Gamma_function .. [2] http://dlmf.nist.gov/5 .. [3] http://mathworld.wolfram.com/GammaFunction.html .. [4] http://functions.wolfram.com/GammaBetaErf/Gamma/ """ unbranched = True _singularities = (S.ComplexInfinity,) def fdiff(self, argindex=1): if argindex == 1: return self.func(self.args[0])*polygamma(0, self.args[0]) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, arg): if arg.is_Number: if arg is S.NaN: return S.NaN elif arg is S.Infinity: return S.Infinity elif intlike(arg): if arg.is_positive: return factorial(arg - 1) else: return S.ComplexInfinity elif arg.is_Rational: if arg.q == 2: n = abs(arg.p) // arg.q if arg.is_positive: k, coeff = n, S.One else: n = k = n + 1 if n & 1 == 0: coeff = S.One else: coeff = S.NegativeOne for i in range(3, 2*k, 2): coeff *= i if arg.is_positive: return coeff*sqrt(S.Pi) / 2**n else: return 2**n*sqrt(S.Pi) / coeff def _eval_expand_func(self, **hints): arg = self.args[0] if arg.is_Rational: if abs(arg.p) > arg.q: x = Dummy('x') n = arg.p // arg.q p = arg.p - n*arg.q return self.func(x + n)._eval_expand_func().subs(x, Rational(p, arg.q)) if arg.is_Add: coeff, tail = arg.as_coeff_add() if coeff and coeff.q != 1: intpart = floor(coeff) tail = (coeff - intpart,) + tail coeff = intpart tail = arg._new_rawargs(*tail, reeval=False) return self.func(tail)*RisingFactorial(tail, coeff) return self.func(*self.args) def _eval_conjugate(self): return self.func(self.args[0].conjugate()) def _eval_is_real(self): x = self.args[0] if x.is_nonpositive and x.is_integer: return False if intlike(x) and x <= 0: return False if x.is_positive or x.is_noninteger: return True def _eval_is_positive(self): x = self.args[0] if x.is_positive: return True elif x.is_noninteger: return floor(x).is_even def _eval_rewrite_as_tractable(self, z, limitvar=None, **kwargs): return exp(loggamma(z)) def _eval_rewrite_as_factorial(self, z, **kwargs): return factorial(z - 1) def _eval_nseries(self, x, n, logx, cdir=0): x0 = self.args[0].limit(x, 0) if not (x0.is_Integer and x0 <= 0): return super()._eval_nseries(x, n, logx) t = self.args[0] - x0 return (self.func(t + 1)/rf(self.args[0], -x0 + 1))._eval_nseries(x, n, logx) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import PoleError arg = self.args[0] x0 = arg.subs(x, 0) if x0.is_integer and x0.is_nonpositive: n = -x0 res = (-1)**n/self.func(n + 1) return res/(arg + n).as_leading_term(x) elif not x0.is_infinite: return self.func(x0) raise PoleError() ############################################################################### ################## LOWER and UPPER INCOMPLETE GAMMA FUNCTIONS ################# ############################################################################### class lowergamma(Function): r""" The lower incomplete gamma function. Explanation =========== It can be defined as the meromorphic continuation of .. math:: \gamma(s, x) := \int_0^x t^{s-1} e^{-t} \mathrm{d}t = \Gamma(s) - \Gamma(s, x). This can be shown to be the same as .. math:: \gamma(s, x) = \frac{x^s}{s} {}_1F_1\left({s \atop s+1} \middle| -x\right), where ${}_1F_1$ is the (confluent) hypergeometric function. Examples ======== >>> from sympy import lowergamma, S >>> from sympy.abc import s, x >>> lowergamma(s, x) lowergamma(s, x) >>> lowergamma(3, x) -2*(x**2/2 + x + 1)*exp(-x) + 2 >>> lowergamma(-S(1)/2, x) -2*sqrt(pi)*erf(sqrt(x)) - 2*exp(-x)/sqrt(x) See Also ======== gamma: Gamma function. uppergamma: Upper incomplete gamma function. polygamma: Polygamma function. loggamma: Log Gamma function. digamma: Digamma function. trigamma: Trigamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Incomplete_gamma_function#Lower_incomplete_Gamma_function .. [2] Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6, Section 5, Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables .. [3] http://dlmf.nist.gov/8 .. [4] http://functions.wolfram.com/GammaBetaErf/Gamma2/ .. [5] http://functions.wolfram.com/GammaBetaErf/Gamma3/ """ def fdiff(self, argindex=2): from sympy import meijerg, unpolarify if argindex == 2: a, z = self.args return exp(-unpolarify(z))*z**(a - 1) elif argindex == 1: a, z = self.args return gamma(a)*digamma(a) - log(z)*uppergamma(a, z) \ - meijerg([], [1, 1], [0, 0, a], [], z) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, a, x): # For lack of a better place, we use this one to extract branching # information. The following can be # found in the literature (c/f references given above), albeit scattered: # 1) For fixed x != 0, lowergamma(s, x) is an entire function of s # 2) For fixed positive integers s, lowergamma(s, x) is an entire # function of x. # 3) For fixed non-positive integers s, # lowergamma(s, exp(I*2*pi*n)*x) = # 2*pi*I*n*(-1)**(-s)/factorial(-s) + lowergamma(s, x) # (this follows from lowergamma(s, x).diff(x) = x**(s-1)*exp(-x)). # 4) For fixed non-integral s, # lowergamma(s, x) = x**s*gamma(s)*lowergamma_unbranched(s, x), # where lowergamma_unbranched(s, x) is an entire function (in fact # of both s and x), i.e. # lowergamma(s, exp(2*I*pi*n)*x) = exp(2*pi*I*n*a)*lowergamma(a, x) from sympy import unpolarify, I if x is S.Zero: return S.Zero nx, n = x.extract_branch_factor() if a.is_integer and a.is_positive: nx = unpolarify(x) if nx != x: return lowergamma(a, nx) elif a.is_integer and a.is_nonpositive: if n != 0: return 2*pi*I*n*(-1)**(-a)/factorial(-a) + lowergamma(a, nx) elif n != 0: return exp(2*pi*I*n*a)*lowergamma(a, nx) # Special values. if a.is_Number: if a is S.One: return S.One - exp(-x) elif a is S.Half: return sqrt(pi)*erf(sqrt(x)) elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: if a.is_integer: return factorial(b) - exp(-x) * factorial(b) * Add(*[x ** k / factorial(k) for k in range(a)]) else: return gamma(a)*(lowergamma(S.Half, x)/sqrt(pi) - exp(-x)*Add(*[x**(k - S.Half)/gamma(S.Half + k) for k in range(1, a + S.Half)])) if not a.is_Integer: return (-1)**(S.Half - a)*pi*erf(sqrt(x))/gamma(1 - a) + exp(-x)*Add(*[x**(k + a - 1)*gamma(a)/gamma(a + k) for k in range(1, Rational(3, 2) - a)]) if x.is_zero: return S.Zero def _eval_evalf(self, prec): from mpmath import mp, workprec from sympy import Expr if all(x.is_number for x in self.args): a = self.args[0]._to_mpmath(prec) z = self.args[1]._to_mpmath(prec) with workprec(prec): res = mp.gammainc(a, 0, z) return Expr._from_mpmath(res, prec) else: return self def _eval_conjugate(self): x = self.args[1] if x not in (S.Zero, S.NegativeInfinity): return self.func(self.args[0].conjugate(), x.conjugate()) def _eval_is_meromorphic(self, x, a): # By https://en.wikipedia.org/wiki/Incomplete_gamma_function#Holomorphic_extension, # lowergamma(s, z) = z**s*gamma(s)*gammastar(s, z), # where gammastar(s, z) is holomorphic for all s and z. # Hence the singularities of lowergamma are z = 0 (branch # point) and nonpositive integer values of s (poles of gamma(s)). s, z = self.args args_merom = fuzzy_and([z._eval_is_meromorphic(x, a), s._eval_is_meromorphic(x, a)]) if not args_merom: return args_merom z0 = z.subs(x, a) if s.is_integer: return fuzzy_and([s.is_positive, z0.is_finite]) s0 = s.subs(x, a) return fuzzy_and([s0.is_finite, z0.is_finite, fuzzy_not(z0.is_zero)]) def _eval_aseries(self, n, args0, x, logx): from sympy import O s, z = self.args if args0[0] is S.Infinity and not z.has(x): coeff = z**s*exp(-z) sum_expr = sum(z**k/rf(s, k + 1) for k in range(n - 1)) o = O(z**s*s**(-n)) return coeff*sum_expr + o return super()._eval_aseries(n, args0, x, logx) def _eval_rewrite_as_uppergamma(self, s, x, **kwargs): return gamma(s) - uppergamma(s, x) def _eval_rewrite_as_expint(self, s, x, **kwargs): from sympy import expint if s.is_integer and s.is_nonpositive: return self return self.rewrite(uppergamma).rewrite(expint) def _eval_is_zero(self): x = self.args[1] if x.is_zero: return True class uppergamma(Function): r""" The upper incomplete gamma function. Explanation =========== It can be defined as the meromorphic continuation of .. math:: \Gamma(s, x) := \int_x^\infty t^{s-1} e^{-t} \mathrm{d}t = \Gamma(s) - \gamma(s, x). where $\gamma(s, x)$ is the lower incomplete gamma function, :class:`lowergamma`. This can be shown to be the same as .. math:: \Gamma(s, x) = \Gamma(s) - \frac{x^s}{s} {}_1F_1\left({s \atop s+1} \middle| -x\right), where ${}_1F_1$ is the (confluent) hypergeometric function. The upper incomplete gamma function is also essentially equivalent to the generalized exponential integral: .. math:: \operatorname{E}_{n}(x) = \int_{1}^{\infty}{\frac{e^{-xt}}{t^n} \, dt} = x^{n-1}\Gamma(1-n,x). Examples ======== >>> from sympy import uppergamma, S >>> from sympy.abc import s, x >>> uppergamma(s, x) uppergamma(s, x) >>> uppergamma(3, x) 2*(x**2/2 + x + 1)*exp(-x) >>> uppergamma(-S(1)/2, x) -2*sqrt(pi)*erfc(sqrt(x)) + 2*exp(-x)/sqrt(x) >>> uppergamma(-2, x) expint(3, x)/x**2 See Also ======== gamma: Gamma function. lowergamma: Lower incomplete gamma function. polygamma: Polygamma function. loggamma: Log Gamma function. digamma: Digamma function. trigamma: Trigamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Incomplete_gamma_function#Upper_incomplete_Gamma_function .. [2] Abramowitz, Milton; Stegun, Irene A., eds. (1965), Chapter 6, Section 5, Handbook of Mathematical Functions with Formulas, Graphs, and Mathematical Tables .. [3] http://dlmf.nist.gov/8 .. [4] http://functions.wolfram.com/GammaBetaErf/Gamma2/ .. [5] http://functions.wolfram.com/GammaBetaErf/Gamma3/ .. [6] https://en.wikipedia.org/wiki/Exponential_integral#Relation_with_other_functions """ def fdiff(self, argindex=2): from sympy import meijerg, unpolarify if argindex == 2: a, z = self.args return -exp(-unpolarify(z))*z**(a - 1) elif argindex == 1: a, z = self.args return uppergamma(a, z)*log(z) + meijerg([], [1, 1], [0, 0, a], [], z) else: raise ArgumentIndexError(self, argindex) def _eval_evalf(self, prec): from mpmath import mp, workprec from sympy import Expr if all(x.is_number for x in self.args): a = self.args[0]._to_mpmath(prec) z = self.args[1]._to_mpmath(prec) with workprec(prec): res = mp.gammainc(a, z, mp.inf) return Expr._from_mpmath(res, prec) return self @classmethod def eval(cls, a, z): from sympy import unpolarify, I, expint if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: return S.Zero elif z.is_zero: if re(a).is_positive: return gamma(a) # We extract branching information here. C/f lowergamma. nx, n = z.extract_branch_factor() if a.is_integer and a.is_positive: nx = unpolarify(z) if z != nx: return uppergamma(a, nx) elif a.is_integer and a.is_nonpositive: if n != 0: return -2*pi*I*n*(-1)**(-a)/factorial(-a) + uppergamma(a, nx) elif n != 0: return gamma(a)*(1 - exp(2*pi*I*n*a)) + exp(2*pi*I*n*a)*uppergamma(a, nx) # Special values. if a.is_Number: if a is S.Zero and z.is_positive: return -Ei(-z) elif a is S.One: return exp(-z) elif a is S.Half: return sqrt(pi)*erfc(sqrt(z)) elif a.is_Integer or (2*a).is_Integer: b = a - 1 if b.is_positive: if a.is_integer: return exp(-z) * factorial(b) * Add(*[z**k / factorial(k) for k in range(a)]) else: return gamma(a) * erfc(sqrt(z)) + (-1)**(a - S(3)/2) * exp(-z) * sqrt(z) * Add(*[gamma(-S.Half - k) * (-z)**k / gamma(1-a) for k in range(a - S.Half)]) elif b.is_Integer: return expint(-b, z)*unpolarify(z)**(b + 1) if not a.is_Integer: return (-1)**(S.Half - a) * pi*erfc(sqrt(z))/gamma(1-a) - z**a * exp(-z) * Add(*[z**k * gamma(a) / gamma(a+k+1) for k in range(S.Half - a)]) if a.is_zero and z.is_positive: return -Ei(-z) if z.is_zero and re(a).is_positive: return gamma(a) def _eval_conjugate(self): z = self.args[1] if not z in (S.Zero, S.NegativeInfinity): return self.func(self.args[0].conjugate(), z.conjugate()) def _eval_is_meromorphic(self, x, a): return lowergamma._eval_is_meromorphic(self, x, a) def _eval_rewrite_as_lowergamma(self, s, x, **kwargs): return gamma(s) - lowergamma(s, x) def _eval_rewrite_as_tractable(self, s, x, **kwargs): return exp(loggamma(s)) - lowergamma(s, x) def _eval_rewrite_as_expint(self, s, x, **kwargs): from sympy import expint return expint(1 - s, x)*x**s ############################################################################### ###################### POLYGAMMA and LOGGAMMA FUNCTIONS ####################### ############################################################################### class polygamma(Function): r""" The function ``polygamma(n, z)`` returns ``log(gamma(z)).diff(n + 1)``. Explanation =========== It is a meromorphic function on $\mathbb{C}$ and defined as the $(n+1)$-th derivative of the logarithm of the gamma function: .. math:: \psi^{(n)} (z) := \frac{\mathrm{d}^{n+1}}{\mathrm{d} z^{n+1}} \log\Gamma(z). Examples ======== Several special values are known: >>> from sympy import S, polygamma >>> polygamma(0, 1) -EulerGamma >>> polygamma(0, 1/S(2)) -2*log(2) - EulerGamma >>> polygamma(0, 1/S(3)) -log(3) - sqrt(3)*pi/6 - EulerGamma - log(sqrt(3)) >>> polygamma(0, 1/S(4)) -pi/2 - log(4) - log(2) - EulerGamma >>> polygamma(0, 2) 1 - EulerGamma >>> polygamma(0, 23) 19093197/5173168 - EulerGamma >>> from sympy import oo, I >>> polygamma(0, oo) oo >>> polygamma(0, -oo) oo >>> polygamma(0, I*oo) oo >>> polygamma(0, -I*oo) oo Differentiation with respect to $x$ is supported: >>> from sympy import Symbol, diff >>> x = Symbol("x") >>> diff(polygamma(0, x), x) polygamma(1, x) >>> diff(polygamma(0, x), x, 2) polygamma(2, x) >>> diff(polygamma(0, x), x, 3) polygamma(3, x) >>> diff(polygamma(1, x), x) polygamma(2, x) >>> diff(polygamma(1, x), x, 2) polygamma(3, x) >>> diff(polygamma(2, x), x) polygamma(3, x) >>> diff(polygamma(2, x), x, 2) polygamma(4, x) >>> n = Symbol("n") >>> diff(polygamma(n, x), x) polygamma(n + 1, x) >>> diff(polygamma(n, x), x, 2) polygamma(n + 2, x) We can rewrite ``polygamma`` functions in terms of harmonic numbers: >>> from sympy import harmonic >>> polygamma(0, x).rewrite(harmonic) harmonic(x - 1) - EulerGamma >>> polygamma(2, x).rewrite(harmonic) 2*harmonic(x - 1, 3) - 2*zeta(3) >>> ni = Symbol("n", integer=True) >>> polygamma(ni, x).rewrite(harmonic) (-1)**(n + 1)*(-harmonic(x - 1, n + 1) + zeta(n + 1))*factorial(n) See Also ======== gamma: Gamma function. lowergamma: Lower incomplete gamma function. uppergamma: Upper incomplete gamma function. loggamma: Log Gamma function. digamma: Digamma function. trigamma: Trigamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Polygamma_function .. [2] http://mathworld.wolfram.com/PolygammaFunction.html .. [3] http://functions.wolfram.com/GammaBetaErf/PolyGamma/ .. [4] http://functions.wolfram.com/GammaBetaErf/PolyGamma2/ """ def _eval_evalf(self, prec): n = self.args[0] # the mpmath polygamma implementation valid only for nonnegative integers if n.is_number and n.is_real: if (n.is_integer or n == int(n)) and n.is_nonnegative: return super()._eval_evalf(prec) def fdiff(self, argindex=2): if argindex == 2: n, z = self.args[:2] return polygamma(n + 1, z) else: raise ArgumentIndexError(self, argindex) def _eval_is_real(self): if self.args[0].is_positive and self.args[1].is_positive: return True def _eval_is_complex(self): z = self.args[1] is_negative_integer = fuzzy_and([z.is_negative, z.is_integer]) return fuzzy_and([z.is_complex, fuzzy_not(is_negative_integer)]) def _eval_is_positive(self): if self.args[0].is_positive and self.args[1].is_positive: return self.args[0].is_odd def _eval_is_negative(self): if self.args[0].is_positive and self.args[1].is_positive: return self.args[0].is_even def _eval_aseries(self, n, args0, x, logx): from sympy import Order if args0[1] != oo or not \ (self.args[0].is_Integer and self.args[0].is_nonnegative): return super()._eval_aseries(n, args0, x, logx) z = self.args[1] N = self.args[0] if N == 0: # digamma function series # Abramowitz & Stegun, p. 259, 6.3.18 r = log(z) - 1/(2*z) o = None if n < 2: o = Order(1/z, x) else: m = ceiling((n + 1)//2) l = [bernoulli(2*k) / (2*k*z**(2*k)) for k in range(1, m)] r -= Add(*l) o = Order(1/z**n, x) return r._eval_nseries(x, n, logx) + o else: # proper polygamma function # Abramowitz & Stegun, p. 260, 6.4.10 # We return terms to order higher than O(x**n) on purpose # -- otherwise we would not be able to return any terms for # quite a long time! fac = gamma(N) e0 = fac + N*fac/(2*z) m = ceiling((n + 1)//2) for k in range(1, m): fac = fac*(2*k + N - 1)*(2*k + N - 2) / ((2*k)*(2*k - 1)) e0 += bernoulli(2*k)*fac/z**(2*k) o = Order(1/z**(2*m), x) if n == 0: o = Order(1/z, x) elif n == 1: o = Order(1/z**2, x) r = e0._eval_nseries(z, n, logx) + o return (-1 * (-1/z)**N * r)._eval_nseries(x, n, logx) @classmethod def eval(cls, n, z): n, z = map(sympify, (n, z)) from sympy import unpolarify if n.is_integer: if n.is_nonnegative: nz = unpolarify(z) if z != nz: return polygamma(n, nz) if n.is_positive: if z is S.Half: return (-1)**(n + 1)*factorial(n)*(2**(n + 1) - 1)*zeta(n + 1) if n is S.NegativeOne: return loggamma(z) else: if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: if n.is_Number: if n.is_zero: return S.Infinity else: return S.Zero if n.is_zero: return S.Infinity elif z.is_Integer: if z.is_nonpositive: return S.ComplexInfinity else: if n.is_zero: return -S.EulerGamma + harmonic(z - 1, 1) elif n.is_odd: return (-1)**(n + 1)*factorial(n)*zeta(n + 1, z) if n.is_zero: if z is S.NaN: return S.NaN elif z.is_Rational: p, q = z.as_numer_denom() # only expand for small denominators to avoid creating long expressions if q <= 5: return expand_func(polygamma(S.Zero, z, evaluate=False)) elif z in (S.Infinity, S.NegativeInfinity): return S.Infinity else: t = z.extract_multiplicatively(S.ImaginaryUnit) if t in (S.Infinity, S.NegativeInfinity): return S.Infinity # TODO n == 1 also can do some rational z def _eval_expand_func(self, **hints): n, z = self.args if n.is_Integer and n.is_nonnegative: if z.is_Add: coeff = z.args[0] if coeff.is_Integer: e = -(n + 1) if coeff > 0: tail = Add(*[Pow( z - i, e) for i in range(1, int(coeff) + 1)]) else: tail = -Add(*[Pow( z + i, e) for i in range(0, int(-coeff))]) return polygamma(n, z - coeff) + (-1)**n*factorial(n)*tail elif z.is_Mul: coeff, z = z.as_two_terms() if coeff.is_Integer and coeff.is_positive: tail = [ polygamma(n, z + Rational( i, coeff)) for i in range(0, int(coeff)) ] if n == 0: return Add(*tail)/coeff + log(coeff) else: return Add(*tail)/coeff**(n + 1) z *= coeff if n == 0 and z.is_Rational: p, q = z.as_numer_denom() # Reference: # Values of the polygamma functions at rational arguments, J. Choi, 2007 part_1 = -S.EulerGamma - pi * cot(p * pi / q) / 2 - log(q) + Add( *[cos(2 * k * pi * p / q) * log(2 * sin(k * pi / q)) for k in range(1, q)]) if z > 0: n = floor(z) z0 = z - n return part_1 + Add(*[1 / (z0 + k) for k in range(n)]) elif z < 0: n = floor(1 - z) z0 = z + n return part_1 - Add(*[1 / (z0 - 1 - k) for k in range(n)]) return polygamma(n, z) def _eval_rewrite_as_zeta(self, n, z, **kwargs): if n.is_integer: if (n - S.One).is_nonnegative: return (-1)**(n + 1)*factorial(n)*zeta(n + 1, z) def _eval_rewrite_as_harmonic(self, n, z, **kwargs): if n.is_integer: if n.is_zero: return harmonic(z - 1) - S.EulerGamma else: return S.NegativeOne**(n+1) * factorial(n) * (zeta(n+1) - harmonic(z-1, n+1)) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import Order n, z = [a.as_leading_term(x) for a in self.args] o = Order(z, x) if n == 0 and o.contains(1/x): return o.getn() * log(x) else: return self.func(n, z) class loggamma(Function): r""" The ``loggamma`` function implements the logarithm of the gamma function (i.e., $\log\Gamma(x)$). Examples ======== Several special values are known. For numerical integral arguments we have: >>> from sympy import loggamma >>> loggamma(-2) oo >>> loggamma(0) oo >>> loggamma(1) 0 >>> loggamma(2) 0 >>> loggamma(3) log(2) And for symbolic values: >>> from sympy import Symbol >>> n = Symbol("n", integer=True, positive=True) >>> loggamma(n) log(gamma(n)) >>> loggamma(-n) oo For half-integral values: >>> from sympy import S >>> loggamma(S(5)/2) log(3*sqrt(pi)/4) >>> loggamma(n/2) log(2**(1 - n)*sqrt(pi)*gamma(n)/gamma(n/2 + 1/2)) And general rational arguments: >>> from sympy import expand_func >>> L = loggamma(S(16)/3) >>> expand_func(L).doit() -5*log(3) + loggamma(1/3) + log(4) + log(7) + log(10) + log(13) >>> L = loggamma(S(19)/4) >>> expand_func(L).doit() -4*log(4) + loggamma(3/4) + log(3) + log(7) + log(11) + log(15) >>> L = loggamma(S(23)/7) >>> expand_func(L).doit() -3*log(7) + log(2) + loggamma(2/7) + log(9) + log(16) The ``loggamma`` function has the following limits towards infinity: >>> from sympy import oo >>> loggamma(oo) oo >>> loggamma(-oo) zoo The ``loggamma`` function obeys the mirror symmetry if $x \in \mathbb{C} \setminus \{-\infty, 0\}$: >>> from sympy.abc import x >>> from sympy import conjugate >>> conjugate(loggamma(x)) loggamma(conjugate(x)) Differentiation with respect to $x$ is supported: >>> from sympy import diff >>> diff(loggamma(x), x) polygamma(0, x) Series expansion is also supported: >>> from sympy import series >>> series(loggamma(x), x, 0, 4).cancel() -log(x) - EulerGamma*x + pi**2*x**2/12 + x**3*polygamma(2, 1)/6 + O(x**4) We can numerically evaluate the ``gamma`` function to arbitrary precision on the whole complex plane: >>> from sympy import I >>> loggamma(5).evalf(30) 3.17805383034794561964694160130 >>> loggamma(I).evalf(20) -0.65092319930185633889 - 1.8724366472624298171*I See Also ======== gamma: Gamma function. lowergamma: Lower incomplete gamma function. uppergamma: Upper incomplete gamma function. polygamma: Polygamma function. digamma: Digamma function. trigamma: Trigamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Gamma_function .. [2] http://dlmf.nist.gov/5 .. [3] http://mathworld.wolfram.com/LogGammaFunction.html .. [4] http://functions.wolfram.com/GammaBetaErf/LogGamma/ """ @classmethod def eval(cls, z): z = sympify(z) if z.is_integer: if z.is_nonpositive: return S.Infinity elif z.is_positive: return log(gamma(z)) elif z.is_rational: p, q = z.as_numer_denom() # Half-integral values: if p.is_positive and q == 2: return log(sqrt(S.Pi) * 2**(1 - p) * gamma(p) / gamma((p + 1)*S.Half)) if z is S.Infinity: return S.Infinity elif abs(z) is S.Infinity: return S.ComplexInfinity if z is S.NaN: return S.NaN def _eval_expand_func(self, **hints): from sympy import Sum z = self.args[0] if z.is_Rational: p, q = z.as_numer_denom() # General rational arguments (u + p/q) # Split z as n + p/q with p < q n = p // q p = p - n*q if p.is_positive and q.is_positive and p < q: k = Dummy("k") if n.is_positive: return loggamma(p / q) - n*log(q) + Sum(log((k - 1)*q + p), (k, 1, n)) elif n.is_negative: return loggamma(p / q) - n*log(q) + S.Pi*S.ImaginaryUnit*n - Sum(log(k*q - p), (k, 1, -n)) elif n.is_zero: return loggamma(p / q) return self def _eval_nseries(self, x, n, logx=None, cdir=0): x0 = self.args[0].limit(x, 0) if x0.is_zero: f = self._eval_rewrite_as_intractable(*self.args) return f._eval_nseries(x, n, logx) return super()._eval_nseries(x, n, logx) def _eval_aseries(self, n, args0, x, logx): from sympy import Order if args0[0] != oo: return super()._eval_aseries(n, args0, x, logx) z = self.args[0] r = log(z)*(z - S.Half) - z + log(2*pi)/2 l = [bernoulli(2*k) / (2*k*(2*k - 1)*z**(2*k - 1)) for k in range(1, n)] o = None if n == 0: o = Order(1, x) else: o = Order(1/z**n, x) # It is very inefficient to first add the order and then do the nseries return (r + Add(*l))._eval_nseries(x, n, logx) + o def _eval_rewrite_as_intractable(self, z, **kwargs): return log(gamma(z)) def _eval_is_real(self): z = self.args[0] if z.is_positive: return True elif z.is_nonpositive: return False def _eval_conjugate(self): z = self.args[0] if not z in (S.Zero, S.NegativeInfinity): return self.func(z.conjugate()) def fdiff(self, argindex=1): if argindex == 1: return polygamma(0, self.args[0]) else: raise ArgumentIndexError(self, argindex) class digamma(Function): r""" The ``digamma`` function is the first derivative of the ``loggamma`` function .. math:: \psi(x) := \frac{\mathrm{d}}{\mathrm{d} z} \log\Gamma(z) = \frac{\Gamma'(z)}{\Gamma(z) }. In this case, ``digamma(z) = polygamma(0, z)``. Examples ======== >>> from sympy import digamma >>> digamma(0) zoo >>> from sympy import Symbol >>> z = Symbol('z') >>> digamma(z) polygamma(0, z) To retain ``digamma`` as it is: >>> digamma(0, evaluate=False) digamma(0) >>> digamma(z, evaluate=False) digamma(z) See Also ======== gamma: Gamma function. lowergamma: Lower incomplete gamma function. uppergamma: Upper incomplete gamma function. polygamma: Polygamma function. loggamma: Log Gamma function. trigamma: Trigamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Digamma_function .. [2] http://mathworld.wolfram.com/DigammaFunction.html .. [3] http://functions.wolfram.com/GammaBetaErf/PolyGamma2/ """ def _eval_evalf(self, prec): z = self.args[0] return polygamma(0, z).evalf(prec) def fdiff(self, argindex=1): z = self.args[0] return polygamma(0, z).fdiff() def _eval_is_real(self): z = self.args[0] return polygamma(0, z).is_real def _eval_is_positive(self): z = self.args[0] return polygamma(0, z).is_positive def _eval_is_negative(self): z = self.args[0] return polygamma(0, z).is_negative def _eval_aseries(self, n, args0, x, logx): as_polygamma = self.rewrite(polygamma) args0 = [S.Zero,] + args0 return as_polygamma._eval_aseries(n, args0, x, logx) @classmethod def eval(cls, z): return polygamma(0, z) def _eval_expand_func(self, **hints): z = self.args[0] return polygamma(0, z).expand(func=True) def _eval_rewrite_as_harmonic(self, z, **kwargs): return harmonic(z - 1) - S.EulerGamma def _eval_rewrite_as_polygamma(self, z, **kwargs): return polygamma(0, z) def _eval_as_leading_term(self, x, logx=None, cdir=0): z = self.args[0] return polygamma(0, z).as_leading_term(x) class trigamma(Function): r""" The ``trigamma`` function is the second derivative of the ``loggamma`` function .. math:: \psi^{(1)}(z) := \frac{\mathrm{d}^{2}}{\mathrm{d} z^{2}} \log\Gamma(z). In this case, ``trigamma(z) = polygamma(1, z)``. Examples ======== >>> from sympy import trigamma >>> trigamma(0) zoo >>> from sympy import Symbol >>> z = Symbol('z') >>> trigamma(z) polygamma(1, z) To retain ``trigamma`` as it is: >>> trigamma(0, evaluate=False) trigamma(0) >>> trigamma(z, evaluate=False) trigamma(z) See Also ======== gamma: Gamma function. lowergamma: Lower incomplete gamma function. uppergamma: Upper incomplete gamma function. polygamma: Polygamma function. loggamma: Log Gamma function. digamma: Digamma function. beta: Euler Beta function. References ========== .. [1] https://en.wikipedia.org/wiki/Trigamma_function .. [2] http://mathworld.wolfram.com/TrigammaFunction.html .. [3] http://functions.wolfram.com/GammaBetaErf/PolyGamma2/ """ def _eval_evalf(self, prec): z = self.args[0] return polygamma(1, z).evalf(prec) def fdiff(self, argindex=1): z = self.args[0] return polygamma(1, z).fdiff() def _eval_is_real(self): z = self.args[0] return polygamma(1, z).is_real def _eval_is_positive(self): z = self.args[0] return polygamma(1, z).is_positive def _eval_is_negative(self): z = self.args[0] return polygamma(1, z).is_negative def _eval_aseries(self, n, args0, x, logx): as_polygamma = self.rewrite(polygamma) args0 = [S.One,] + args0 return as_polygamma._eval_aseries(n, args0, x, logx) @classmethod def eval(cls, z): return polygamma(1, z) def _eval_expand_func(self, **hints): z = self.args[0] return polygamma(1, z).expand(func=True) def _eval_rewrite_as_zeta(self, z, **kwargs): return zeta(2, z) def _eval_rewrite_as_polygamma(self, z, **kwargs): return polygamma(1, z) def _eval_rewrite_as_harmonic(self, z, **kwargs): return -harmonic(z - 1, 2) + S.Pi**2 / 6 def _eval_as_leading_term(self, x, logx=None, cdir=0): z = self.args[0] return polygamma(1, z).as_leading_term(x) ############################################################################### ##################### COMPLETE MULTIVARIATE GAMMA FUNCTION #################### ############################################################################### class multigamma(Function): r""" The multivariate gamma function is a generalization of the gamma function .. math:: \Gamma_p(z) = \pi^{p(p-1)/4}\prod_{k=1}^p \Gamma[z + (1 - k)/2]. In a special case, ``multigamma(x, 1) = gamma(x)``. Examples ======== >>> from sympy import S, multigamma >>> from sympy import Symbol >>> x = Symbol('x') >>> p = Symbol('p', positive=True, integer=True) >>> multigamma(x, p) pi**(p*(p - 1)/4)*Product(gamma(-_k/2 + x + 1/2), (_k, 1, p)) Several special values are known: >>> multigamma(1, 1) 1 >>> multigamma(4, 1) 6 >>> multigamma(S(3)/2, 1) sqrt(pi)/2 Writing ``multigamma`` in terms of the ``gamma`` function: >>> multigamma(x, 1) gamma(x) >>> multigamma(x, 2) sqrt(pi)*gamma(x)*gamma(x - 1/2) >>> multigamma(x, 3) pi**(3/2)*gamma(x)*gamma(x - 1)*gamma(x - 1/2) Parameters ========== p : order or dimension of the multivariate gamma function See Also ======== gamma, lowergamma, uppergamma, polygamma, loggamma, digamma, trigamma, beta References ========== .. [1] https://en.wikipedia.org/wiki/Multivariate_gamma_function """ unbranched = True def fdiff(self, argindex=2): from sympy import Sum if argindex == 2: x, p = self.args k = Dummy("k") return self.func(x, p)*Sum(polygamma(0, x + (1 - k)/2), (k, 1, p)) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, x, p): from sympy import Product x, p = map(sympify, (x, p)) if p.is_positive is False or p.is_integer is False: raise ValueError('Order parameter p must be positive integer.') k = Dummy("k") return (pi**(p*(p - 1)/4)*Product(gamma(x + (1 - k)/2), (k, 1, p))).doit() def _eval_conjugate(self): x, p = self.args return self.func(x.conjugate(), p) def _eval_is_real(self): x, p = self.args y = 2*x if y.is_integer and (y <= (p - 1)) is True: return False if intlike(y) and (y <= (p - 1)): return False if y > (p - 1) or y.is_noninteger: return True sympy-sympy-1.9/sympy/functions/special/hyper.py000066400000000000000000001107401412543434000222400ustar00rootroot00000000000000"""Hypergeometric and Meijer G-functions""" from functools import reduce from sympy.core import S, I, pi, oo, zoo, ilcm, Mod from sympy.core.function import Function, Derivative, ArgumentIndexError from sympy.core.containers import Tuple from sympy.core.mul import Mul from sympy.core.symbol import Dummy from sympy.functions import (sqrt, exp, log, sin, cos, asin, atan, sinh, cosh, asinh, acosh, atanh, acoth, Abs, re) from sympy.utilities.iterables import default_sort_key class TupleArg(Tuple): def limit(self, x, xlim, dir='+'): """ Compute limit x->xlim. """ from sympy.series.limits import limit return TupleArg(*[limit(f, x, xlim, dir) for f in self.args]) # TODO should __new__ accept **options? # TODO should constructors should check if parameters are sensible? def _prep_tuple(v): """ Turn an iterable argument *v* into a tuple and unpolarify, since both hypergeometric and meijer g-functions are unbranched in their parameters. Examples ======== >>> from sympy.functions.special.hyper import _prep_tuple >>> _prep_tuple([1, 2, 3]) (1, 2, 3) >>> _prep_tuple((4, 5)) (4, 5) >>> _prep_tuple((7, 8, 9)) (7, 8, 9) """ from sympy import unpolarify return TupleArg(*[unpolarify(x) for x in v]) class TupleParametersBase(Function): """ Base class that takes care of differentiation, when some of the arguments are actually tuples. """ # This is not deduced automatically since there are Tuples as arguments. is_commutative = True def _eval_derivative(self, s): try: res = 0 if self.args[0].has(s) or self.args[1].has(s): for i, p in enumerate(self._diffargs): m = self._diffargs[i].diff(s) if m != 0: res += self.fdiff((1, i))*m return res + self.fdiff(3)*self.args[2].diff(s) except (ArgumentIndexError, NotImplementedError): return Derivative(self, s) class hyper(TupleParametersBase): r""" The generalized hypergeometric function is defined by a series where the ratios of successive terms are a rational function of the summation index. When convergent, it is continued analytically to the largest possible domain. Explanation =========== The hypergeometric function depends on two vectors of parameters, called the numerator parameters $a_p$, and the denominator parameters $b_q$. It also has an argument $z$. The series definition is .. math :: {}_pF_q\left(\begin{matrix} a_1, \cdots, a_p \\ b_1, \cdots, b_q \end{matrix} \middle| z \right) = \sum_{n=0}^\infty \frac{(a_1)_n \cdots (a_p)_n}{(b_1)_n \cdots (b_q)_n} \frac{z^n}{n!}, where $(a)_n = (a)(a+1)\cdots(a+n-1)$ denotes the rising factorial. If one of the $b_q$ is a non-positive integer then the series is undefined unless one of the $a_p$ is a larger (i.e., smaller in magnitude) non-positive integer. If none of the $b_q$ is a non-positive integer and one of the $a_p$ is a non-positive integer, then the series reduces to a polynomial. To simplify the following discussion, we assume that none of the $a_p$ or $b_q$ is a non-positive integer. For more details, see the references. The series converges for all $z$ if $p \le q$, and thus defines an entire single-valued function in this case. If $p = q+1$ the series converges for $|z| < 1$, and can be continued analytically into a half-plane. If $p > q+1$ the series is divergent for all $z$. Please note the hypergeometric function constructor currently does *not* check if the parameters actually yield a well-defined function. Examples ======== The parameters $a_p$ and $b_q$ can be passed as arbitrary iterables, for example: >>> from sympy.functions import hyper >>> from sympy.abc import x, n, a >>> hyper((1, 2, 3), [3, 4], x) hyper((1, 2, 3), (3, 4), x) There is also pretty printing (it looks better using Unicode): >>> from sympy import pprint >>> pprint(hyper((1, 2, 3), [3, 4], x), use_unicode=False) _ |_ /1, 2, 3 | \ | | | x| 3 2 \ 3, 4 | / The parameters must always be iterables, even if they are vectors of length one or zero: >>> hyper((1, ), [], x) hyper((1,), (), x) But of course they may be variables (but if they depend on $x$ then you should not expect much implemented functionality): >>> hyper((n, a), (n**2,), x) hyper((n, a), (n**2,), x) The hypergeometric function generalizes many named special functions. The function ``hyperexpand()`` tries to express a hypergeometric function using named special functions. For example: >>> from sympy import hyperexpand >>> hyperexpand(hyper([], [], x)) exp(x) You can also use ``expand_func()``: >>> from sympy import expand_func >>> expand_func(x*hyper([1, 1], [2], -x)) log(x + 1) More examples: >>> from sympy import S >>> hyperexpand(hyper([], [S(1)/2], -x**2/4)) cos(x) >>> hyperexpand(x*hyper([S(1)/2, S(1)/2], [S(3)/2], x**2)) asin(x) We can also sometimes ``hyperexpand()`` parametric functions: >>> from sympy.abc import a >>> hyperexpand(hyper([-a], [], x)) (1 - x)**a See Also ======== sympy.simplify.hyperexpand gamma meijerg References ========== .. [1] Luke, Y. L. (1969), The Special Functions and Their Approximations, Volume 1 .. [2] https://en.wikipedia.org/wiki/Generalized_hypergeometric_function """ def __new__(cls, ap, bq, z, **kwargs): # TODO should we check convergence conditions? return Function.__new__(cls, _prep_tuple(ap), _prep_tuple(bq), z, **kwargs) @classmethod def eval(cls, ap, bq, z): from sympy import unpolarify if len(ap) <= len(bq) or (len(ap) == len(bq) + 1 and (Abs(z) <= 1) == True): nz = unpolarify(z) if z != nz: return hyper(ap, bq, nz) def fdiff(self, argindex=3): if argindex != 3: raise ArgumentIndexError(self, argindex) nap = Tuple(*[a + 1 for a in self.ap]) nbq = Tuple(*[b + 1 for b in self.bq]) fac = Mul(*self.ap)/Mul(*self.bq) return fac*hyper(nap, nbq, self.argument) def _eval_expand_func(self, **hints): from sympy import gamma, hyperexpand if len(self.ap) == 2 and len(self.bq) == 1 and self.argument == 1: a, b = self.ap c = self.bq[0] return gamma(c)*gamma(c - a - b)/gamma(c - a)/gamma(c - b) return hyperexpand(self) def _eval_rewrite_as_Sum(self, ap, bq, z, **kwargs): from sympy.functions import factorial, RisingFactorial, Piecewise from sympy import Sum n = Dummy("n", integer=True) rfap = Tuple(*[RisingFactorial(a, n) for a in ap]) rfbq = Tuple(*[RisingFactorial(b, n) for b in bq]) coeff = Mul(*rfap) / Mul(*rfbq) return Piecewise((Sum(coeff * z**n / factorial(n), (n, 0, oo)), self.convergence_statement), (self, True)) def _eval_as_leading_term(self, x, logx=None, cdir=0): arg = self.args[2] x0 = arg.subs(x, 0) if x0 is S.NaN: x0 = arg.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if x0 is S.Zero: return S.One return super()._eval_as_leading_term(x, logx=logx, cdir=cdir) def _eval_nseries(self, x, n, logx, cdir=0): from sympy.functions import factorial, RisingFactorial from sympy import Order, Add arg = self.args[2] x0 = arg.limit(x, 0) ap = self.args[0] bq = self.args[1] if x0 != 0: return super()._eval_nseries(x, n, logx) terms = [] for i in range(n): num = 1 den = 1 for a in ap: num *= RisingFactorial(a, i) for b in bq: den *= RisingFactorial(b, i) terms.append(((num/den) * (arg**i)) / factorial(i)) return (Add(*terms) + Order(x**n,x)) @property def argument(self): """ Argument of the hypergeometric function. """ return self.args[2] @property def ap(self): """ Numerator parameters of the hypergeometric function. """ return Tuple(*self.args[0]) @property def bq(self): """ Denominator parameters of the hypergeometric function. """ return Tuple(*self.args[1]) @property def _diffargs(self): return self.ap + self.bq @property def eta(self): """ A quantity related to the convergence of the series. """ return sum(self.ap) - sum(self.bq) @property def radius_of_convergence(self): """ Compute the radius of convergence of the defining series. Explanation =========== Note that even if this is not ``oo``, the function may still be evaluated outside of the radius of convergence by analytic continuation. But if this is zero, then the function is not actually defined anywhere else. Examples ======== >>> from sympy.functions import hyper >>> from sympy.abc import z >>> hyper((1, 2), [3], z).radius_of_convergence 1 >>> hyper((1, 2, 3), [4], z).radius_of_convergence 0 >>> hyper((1, 2), (3, 4), z).radius_of_convergence oo """ if any(a.is_integer and (a <= 0) == True for a in self.ap + self.bq): aints = [a for a in self.ap if a.is_Integer and (a <= 0) == True] bints = [a for a in self.bq if a.is_Integer and (a <= 0) == True] if len(aints) < len(bints): return S.Zero popped = False for b in bints: cancelled = False while aints: a = aints.pop() if a >= b: cancelled = True break popped = True if not cancelled: return S.Zero if aints or popped: # There are still non-positive numerator parameters. # This is a polynomial. return oo if len(self.ap) == len(self.bq) + 1: return S.One elif len(self.ap) <= len(self.bq): return oo else: return S.Zero @property def convergence_statement(self): """ Return a condition on z under which the series converges. """ from sympy import And, Or, re, Ne, oo R = self.radius_of_convergence if R == 0: return False if R == oo: return True # The special functions and their approximations, page 44 e = self.eta z = self.argument c1 = And(re(e) < 0, abs(z) <= 1) c2 = And(0 <= re(e), re(e) < 1, abs(z) <= 1, Ne(z, 1)) c3 = And(re(e) >= 1, abs(z) < 1) return Or(c1, c2, c3) def _eval_simplify(self, **kwargs): from sympy.simplify.hyperexpand import hyperexpand return hyperexpand(self) class meijerg(TupleParametersBase): r""" The Meijer G-function is defined by a Mellin-Barnes type integral that resembles an inverse Mellin transform. It generalizes the hypergeometric functions. Explanation =========== The Meijer G-function depends on four sets of parameters. There are "*numerator parameters*" $a_1, \ldots, a_n$ and $a_{n+1}, \ldots, a_p$, and there are "*denominator parameters*" $b_1, \ldots, b_m$ and $b_{m+1}, \ldots, b_q$. Confusingly, it is traditionally denoted as follows (note the position of $m$, $n$, $p$, $q$, and how they relate to the lengths of the four parameter vectors): .. math :: G_{p,q}^{m,n} \left(\begin{matrix}a_1, \cdots, a_n & a_{n+1}, \cdots, a_p \\ b_1, \cdots, b_m & b_{m+1}, \cdots, b_q \end{matrix} \middle| z \right). However, in SymPy the four parameter vectors are always available separately (see examples), so that there is no need to keep track of the decorating sub- and super-scripts on the G symbol. The G function is defined as the following integral: .. math :: \frac{1}{2 \pi i} \int_L \frac{\prod_{j=1}^m \Gamma(b_j - s) \prod_{j=1}^n \Gamma(1 - a_j + s)}{\prod_{j=m+1}^q \Gamma(1- b_j +s) \prod_{j=n+1}^p \Gamma(a_j - s)} z^s \mathrm{d}s, where $\Gamma(z)$ is the gamma function. There are three possible contours which we will not describe in detail here (see the references). If the integral converges along more than one of them, the definitions agree. The contours all separate the poles of $\Gamma(1-a_j+s)$ from the poles of $\Gamma(b_k-s)$, so in particular the G function is undefined if $a_j - b_k \in \mathbb{Z}_{>0}$ for some $j \le n$ and $k \le m$. The conditions under which one of the contours yields a convergent integral are complicated and we do not state them here, see the references. Please note currently the Meijer G-function constructor does *not* check any convergence conditions. Examples ======== You can pass the parameters either as four separate vectors: >>> from sympy.functions import meijerg >>> from sympy.abc import x, a >>> from sympy.core.containers import Tuple >>> from sympy import pprint >>> pprint(meijerg((1, 2), (a, 4), (5,), [], x), use_unicode=False) __1, 2 /1, 2 a, 4 | \ /__ | | x| \_|4, 1 \ 5 | / Or as two nested vectors: >>> pprint(meijerg([(1, 2), (3, 4)], ([5], Tuple()), x), use_unicode=False) __1, 2 /1, 2 3, 4 | \ /__ | | x| \_|4, 1 \ 5 | / As with the hypergeometric function, the parameters may be passed as arbitrary iterables. Vectors of length zero and one also have to be passed as iterables. The parameters need not be constants, but if they depend on the argument then not much implemented functionality should be expected. All the subvectors of parameters are available: >>> from sympy import pprint >>> g = meijerg([1], [2], [3], [4], x) >>> pprint(g, use_unicode=False) __1, 1 /1 2 | \ /__ | | x| \_|2, 2 \3 4 | / >>> g.an (1,) >>> g.ap (1, 2) >>> g.aother (2,) >>> g.bm (3,) >>> g.bq (3, 4) >>> g.bother (4,) The Meijer G-function generalizes the hypergeometric functions. In some cases it can be expressed in terms of hypergeometric functions, using Slater's theorem. For example: >>> from sympy import hyperexpand >>> from sympy.abc import a, b, c >>> hyperexpand(meijerg([a], [], [c], [b], x), allow_hyper=True) x**c*gamma(-a + c + 1)*hyper((-a + c + 1,), (-b + c + 1,), -x)/gamma(-b + c + 1) Thus the Meijer G-function also subsumes many named functions as special cases. You can use ``expand_func()`` or ``hyperexpand()`` to (try to) rewrite a Meijer G-function in terms of named special functions. For example: >>> from sympy import expand_func, S >>> expand_func(meijerg([[],[]], [[0],[]], -x)) exp(x) >>> hyperexpand(meijerg([[],[]], [[S(1)/2],[0]], (x/2)**2)) sin(x)/sqrt(pi) See Also ======== hyper sympy.simplify.hyperexpand References ========== .. [1] Luke, Y. L. (1969), The Special Functions and Their Approximations, Volume 1 .. [2] https://en.wikipedia.org/wiki/Meijer_G-function """ def __new__(cls, *args, **kwargs): if len(args) == 5: args = [(args[0], args[1]), (args[2], args[3]), args[4]] if len(args) != 3: raise TypeError("args must be either as, as', bs, bs', z or " "as, bs, z") def tr(p): if len(p) != 2: raise TypeError("wrong argument") return TupleArg(_prep_tuple(p[0]), _prep_tuple(p[1])) arg0, arg1 = tr(args[0]), tr(args[1]) if Tuple(arg0, arg1).has(oo, zoo, -oo): raise ValueError("G-function parameters must be finite") if any((a - b).is_Integer and a - b > 0 for a in arg0[0] for b in arg1[0]): raise ValueError("no parameter a1, ..., an may differ from " "any b1, ..., bm by a positive integer") # TODO should we check convergence conditions? return Function.__new__(cls, arg0, arg1, args[2], **kwargs) def fdiff(self, argindex=3): if argindex != 3: return self._diff_wrt_parameter(argindex[1]) if len(self.an) >= 1: a = list(self.an) a[0] -= 1 G = meijerg(a, self.aother, self.bm, self.bother, self.argument) return 1/self.argument * ((self.an[0] - 1)*self + G) elif len(self.bm) >= 1: b = list(self.bm) b[0] += 1 G = meijerg(self.an, self.aother, b, self.bother, self.argument) return 1/self.argument * (self.bm[0]*self - G) else: return S.Zero def _diff_wrt_parameter(self, idx): # Differentiation wrt a parameter can only be done in very special # cases. In particular, if we want to differentiate with respect to # `a`, all other gamma factors have to reduce to rational functions. # # Let MT denote mellin transform. Suppose T(-s) is the gamma factor # appearing in the definition of G. Then # # MT(log(z)G(z)) = d/ds T(s) = d/da T(s) + ... # # Thus d/da G(z) = log(z)G(z) - ... # The ... can be evaluated as a G function under the above conditions, # the formula being most easily derived by using # # d Gamma(s + n) Gamma(s + n) / 1 1 1 \ # -- ------------ = ------------ | - + ---- + ... + --------- | # ds Gamma(s) Gamma(s) \ s s + 1 s + n - 1 / # # which follows from the difference equation of the digamma function. # (There is a similar equation for -n instead of +n). # We first figure out how to pair the parameters. an = list(self.an) ap = list(self.aother) bm = list(self.bm) bq = list(self.bother) if idx < len(an): an.pop(idx) else: idx -= len(an) if idx < len(ap): ap.pop(idx) else: idx -= len(ap) if idx < len(bm): bm.pop(idx) else: bq.pop(idx - len(bm)) pairs1 = [] pairs2 = [] for l1, l2, pairs in [(an, bq, pairs1), (ap, bm, pairs2)]: while l1: x = l1.pop() found = None for i, y in enumerate(l2): if not Mod((x - y).simplify(), 1): found = i break if found is None: raise NotImplementedError('Derivative not expressible ' 'as G-function?') y = l2[i] l2.pop(i) pairs.append((x, y)) # Now build the result. res = log(self.argument)*self for a, b in pairs1: sign = 1 n = a - b base = b if n < 0: sign = -1 n = b - a base = a for k in range(n): res -= sign*meijerg(self.an + (base + k + 1,), self.aother, self.bm, self.bother + (base + k + 0,), self.argument) for a, b in pairs2: sign = 1 n = b - a base = a if n < 0: sign = -1 n = a - b base = b for k in range(n): res -= sign*meijerg(self.an, self.aother + (base + k + 1,), self.bm + (base + k + 0,), self.bother, self.argument) return res def get_period(self): """ Return a number $P$ such that $G(x*exp(I*P)) == G(x)$. Examples ======== >>> from sympy.functions.special.hyper import meijerg >>> from sympy.abc import z >>> from sympy import pi, S >>> meijerg([1], [], [], [], z).get_period() 2*pi >>> meijerg([pi], [], [], [], z).get_period() oo >>> meijerg([1, 2], [], [], [], z).get_period() oo >>> meijerg([1,1], [2], [1, S(1)/2, S(1)/3], [1], z).get_period() 12*pi """ # This follows from slater's theorem. def compute(l): # first check that no two differ by an integer for i, b in enumerate(l): if not b.is_Rational: return oo for j in range(i + 1, len(l)): if not Mod((b - l[j]).simplify(), 1): return oo return reduce(ilcm, (x.q for x in l), 1) beta = compute(self.bm) alpha = compute(self.an) p, q = len(self.ap), len(self.bq) if p == q: if beta == oo or alpha == oo: return oo return 2*pi*ilcm(alpha, beta) elif p < q: return 2*pi*beta else: return 2*pi*alpha def _eval_expand_func(self, **hints): from sympy import hyperexpand return hyperexpand(self) def _eval_evalf(self, prec): # The default code is insufficient for polar arguments. # mpmath provides an optional argument "r", which evaluates # G(z**(1/r)). I am not sure what its intended use is, but we hijack it # here in the following way: to evaluate at a number z of |argument| # less than (say) n*pi, we put r=1/n, compute z' = root(z, n) # (carefully so as not to loose the branch information), and evaluate # G(z'**(1/r)) = G(z'**n) = G(z). from sympy.functions import exp_polar, ceiling from sympy import Expr import mpmath znum = self.argument._eval_evalf(prec) if znum.has(exp_polar): znum, branch = znum.as_coeff_mul(exp_polar) if len(branch) != 1: return branch = branch[0].args[0]/I else: branch = S.Zero n = ceiling(abs(branch/S.Pi)) + 1 znum = znum**(S.One/n)*exp(I*branch / n) # Convert all args to mpf or mpc try: [z, r, ap, bq] = [arg._to_mpmath(prec) for arg in [znum, 1/n, self.args[0], self.args[1]]] except ValueError: return with mpmath.workprec(prec): v = mpmath.meijerg(ap, bq, z, r) return Expr._from_mpmath(v, prec) def _eval_as_leading_term(self, x, logx=None, cdir=0): from sympy import hyperexpand return hyperexpand(self).as_leading_term(x, logx=logx, cdir=cdir) def integrand(self, s): """ Get the defining integrand D(s). """ from sympy import gamma return self.argument**s \ * Mul(*(gamma(b - s) for b in self.bm)) \ * Mul(*(gamma(1 - a + s) for a in self.an)) \ / Mul(*(gamma(1 - b + s) for b in self.bother)) \ / Mul(*(gamma(a - s) for a in self.aother)) @property def argument(self): """ Argument of the Meijer G-function. """ return self.args[2] @property def an(self): """ First set of numerator parameters. """ return Tuple(*self.args[0][0]) @property def ap(self): """ Combined numerator parameters. """ return Tuple(*(self.args[0][0] + self.args[0][1])) @property def aother(self): """ Second set of numerator parameters. """ return Tuple(*self.args[0][1]) @property def bm(self): """ First set of denominator parameters. """ return Tuple(*self.args[1][0]) @property def bq(self): """ Combined denominator parameters. """ return Tuple(*(self.args[1][0] + self.args[1][1])) @property def bother(self): """ Second set of denominator parameters. """ return Tuple(*self.args[1][1]) @property def _diffargs(self): return self.ap + self.bq @property def nu(self): """ A quantity related to the convergence region of the integral, c.f. references. """ return sum(self.bq) - sum(self.ap) @property def delta(self): """ A quantity related to the convergence region of the integral, c.f. references. """ return len(self.bm) + len(self.an) - S(len(self.ap) + len(self.bq))/2 @property def is_number(self): """ Returns true if expression has numeric data only. """ return not self.free_symbols class HyperRep(Function): """ A base class for "hyper representation functions". This is used exclusively in ``hyperexpand()``, but fits more logically here. pFq is branched at 1 if p == q+1. For use with slater-expansion, we want define an "analytic continuation" to all polar numbers, which is continuous on circles and on the ray t*exp_polar(I*pi). Moreover, we want a "nice" expression for the various cases. This base class contains the core logic, concrete derived classes only supply the actual functions. """ @classmethod def eval(cls, *args): from sympy import unpolarify newargs = tuple(map(unpolarify, args[:-1])) + args[-1:] if args != newargs: return cls(*newargs) @classmethod def _expr_small(cls, x): """ An expression for F(x) which holds for |x| < 1. """ raise NotImplementedError @classmethod def _expr_small_minus(cls, x): """ An expression for F(-x) which holds for |x| < 1. """ raise NotImplementedError @classmethod def _expr_big(cls, x, n): """ An expression for F(exp_polar(2*I*pi*n)*x), |x| > 1. """ raise NotImplementedError @classmethod def _expr_big_minus(cls, x, n): """ An expression for F(exp_polar(2*I*pi*n + pi*I)*x), |x| > 1. """ raise NotImplementedError def _eval_rewrite_as_nonrep(self, *args, **kwargs): from sympy import Piecewise x, n = self.args[-1].extract_branch_factor(allow_half=True) minus = False newargs = self.args[:-1] + (x,) if not n.is_Integer: minus = True n -= S.Half newerargs = newargs + (n,) if minus: small = self._expr_small_minus(*newargs) big = self._expr_big_minus(*newerargs) else: small = self._expr_small(*newargs) big = self._expr_big(*newerargs) if big == small: return small return Piecewise((big, abs(x) > 1), (small, True)) def _eval_rewrite_as_nonrepsmall(self, *args, **kwargs): x, n = self.args[-1].extract_branch_factor(allow_half=True) args = self.args[:-1] + (x,) if not n.is_Integer: return self._expr_small_minus(*args) return self._expr_small(*args) class HyperRep_power1(HyperRep): """ Return a representative for hyper([-a], [], z) == (1 - z)**a. """ @classmethod def _expr_small(cls, a, x): return (1 - x)**a @classmethod def _expr_small_minus(cls, a, x): return (1 + x)**a @classmethod def _expr_big(cls, a, x, n): if a.is_integer: return cls._expr_small(a, x) return (x - 1)**a*exp((2*n - 1)*pi*I*a) @classmethod def _expr_big_minus(cls, a, x, n): if a.is_integer: return cls._expr_small_minus(a, x) return (1 + x)**a*exp(2*n*pi*I*a) class HyperRep_power2(HyperRep): """ Return a representative for hyper([a, a - 1/2], [2*a], z). """ @classmethod def _expr_small(cls, a, x): return 2**(2*a - 1)*(1 + sqrt(1 - x))**(1 - 2*a) @classmethod def _expr_small_minus(cls, a, x): return 2**(2*a - 1)*(1 + sqrt(1 + x))**(1 - 2*a) @classmethod def _expr_big(cls, a, x, n): sgn = -1 if n.is_odd: sgn = 1 n -= 1 return 2**(2*a - 1)*(1 + sgn*I*sqrt(x - 1))**(1 - 2*a) \ *exp(-2*n*pi*I*a) @classmethod def _expr_big_minus(cls, a, x, n): sgn = 1 if n.is_odd: sgn = -1 return sgn*2**(2*a - 1)*(sqrt(1 + x) + sgn)**(1 - 2*a)*exp(-2*pi*I*a*n) class HyperRep_log1(HyperRep): """ Represent -z*hyper([1, 1], [2], z) == log(1 - z). """ @classmethod def _expr_small(cls, x): return log(1 - x) @classmethod def _expr_small_minus(cls, x): return log(1 + x) @classmethod def _expr_big(cls, x, n): return log(x - 1) + (2*n - 1)*pi*I @classmethod def _expr_big_minus(cls, x, n): return log(1 + x) + 2*n*pi*I class HyperRep_atanh(HyperRep): """ Represent hyper([1/2, 1], [3/2], z) == atanh(sqrt(z))/sqrt(z). """ @classmethod def _expr_small(cls, x): return atanh(sqrt(x))/sqrt(x) def _expr_small_minus(cls, x): return atan(sqrt(x))/sqrt(x) def _expr_big(cls, x, n): if n.is_even: return (acoth(sqrt(x)) + I*pi/2)/sqrt(x) else: return (acoth(sqrt(x)) - I*pi/2)/sqrt(x) def _expr_big_minus(cls, x, n): if n.is_even: return atan(sqrt(x))/sqrt(x) else: return (atan(sqrt(x)) - pi)/sqrt(x) class HyperRep_asin1(HyperRep): """ Represent hyper([1/2, 1/2], [3/2], z) == asin(sqrt(z))/sqrt(z). """ @classmethod def _expr_small(cls, z): return asin(sqrt(z))/sqrt(z) @classmethod def _expr_small_minus(cls, z): return asinh(sqrt(z))/sqrt(z) @classmethod def _expr_big(cls, z, n): return S.NegativeOne**n*((S.Half - n)*pi/sqrt(z) + I*acosh(sqrt(z))/sqrt(z)) @classmethod def _expr_big_minus(cls, z, n): return S.NegativeOne**n*(asinh(sqrt(z))/sqrt(z) + n*pi*I/sqrt(z)) class HyperRep_asin2(HyperRep): """ Represent hyper([1, 1], [3/2], z) == asin(sqrt(z))/sqrt(z)/sqrt(1-z). """ # TODO this can be nicer @classmethod def _expr_small(cls, z): return HyperRep_asin1._expr_small(z) \ /HyperRep_power1._expr_small(S.Half, z) @classmethod def _expr_small_minus(cls, z): return HyperRep_asin1._expr_small_minus(z) \ /HyperRep_power1._expr_small_minus(S.Half, z) @classmethod def _expr_big(cls, z, n): return HyperRep_asin1._expr_big(z, n) \ /HyperRep_power1._expr_big(S.Half, z, n) @classmethod def _expr_big_minus(cls, z, n): return HyperRep_asin1._expr_big_minus(z, n) \ /HyperRep_power1._expr_big_minus(S.Half, z, n) class HyperRep_sqrts1(HyperRep): """ Return a representative for hyper([-a, 1/2 - a], [1/2], z). """ @classmethod def _expr_small(cls, a, z): return ((1 - sqrt(z))**(2*a) + (1 + sqrt(z))**(2*a))/2 @classmethod def _expr_small_minus(cls, a, z): return (1 + z)**a*cos(2*a*atan(sqrt(z))) @classmethod def _expr_big(cls, a, z, n): if n.is_even: return ((sqrt(z) + 1)**(2*a)*exp(2*pi*I*n*a) + (sqrt(z) - 1)**(2*a)*exp(2*pi*I*(n - 1)*a))/2 else: n -= 1 return ((sqrt(z) - 1)**(2*a)*exp(2*pi*I*a*(n + 1)) + (sqrt(z) + 1)**(2*a)*exp(2*pi*I*a*n))/2 @classmethod def _expr_big_minus(cls, a, z, n): if n.is_even: return (1 + z)**a*exp(2*pi*I*n*a)*cos(2*a*atan(sqrt(z))) else: return (1 + z)**a*exp(2*pi*I*n*a)*cos(2*a*atan(sqrt(z)) - 2*pi*a) class HyperRep_sqrts2(HyperRep): """ Return a representative for sqrt(z)/2*[(1-sqrt(z))**2a - (1 + sqrt(z))**2a] == -2*z/(2*a+1) d/dz hyper([-a - 1/2, -a], [1/2], z)""" @classmethod def _expr_small(cls, a, z): return sqrt(z)*((1 - sqrt(z))**(2*a) - (1 + sqrt(z))**(2*a))/2 @classmethod def _expr_small_minus(cls, a, z): return sqrt(z)*(1 + z)**a*sin(2*a*atan(sqrt(z))) @classmethod def _expr_big(cls, a, z, n): if n.is_even: return sqrt(z)/2*((sqrt(z) - 1)**(2*a)*exp(2*pi*I*a*(n - 1)) - (sqrt(z) + 1)**(2*a)*exp(2*pi*I*a*n)) else: n -= 1 return sqrt(z)/2*((sqrt(z) - 1)**(2*a)*exp(2*pi*I*a*(n + 1)) - (sqrt(z) + 1)**(2*a)*exp(2*pi*I*a*n)) def _expr_big_minus(cls, a, z, n): if n.is_even: return (1 + z)**a*exp(2*pi*I*n*a)*sqrt(z)*sin(2*a*atan(sqrt(z))) else: return (1 + z)**a*exp(2*pi*I*n*a)*sqrt(z) \ *sin(2*a*atan(sqrt(z)) - 2*pi*a) class HyperRep_log2(HyperRep): """ Represent log(1/2 + sqrt(1 - z)/2) == -z/4*hyper([3/2, 1, 1], [2, 2], z) """ @classmethod def _expr_small(cls, z): return log(S.Half + sqrt(1 - z)/2) @classmethod def _expr_small_minus(cls, z): return log(S.Half + sqrt(1 + z)/2) @classmethod def _expr_big(cls, z, n): if n.is_even: return (n - S.Half)*pi*I + log(sqrt(z)/2) + I*asin(1/sqrt(z)) else: return (n - S.Half)*pi*I + log(sqrt(z)/2) - I*asin(1/sqrt(z)) def _expr_big_minus(cls, z, n): if n.is_even: return pi*I*n + log(S.Half + sqrt(1 + z)/2) else: return pi*I*n + log(sqrt(1 + z)/2 - S.Half) class HyperRep_cosasin(HyperRep): """ Represent hyper([a, -a], [1/2], z) == cos(2*a*asin(sqrt(z))). """ # Note there are many alternative expressions, e.g. as powers of a sum of # square roots. @classmethod def _expr_small(cls, a, z): return cos(2*a*asin(sqrt(z))) @classmethod def _expr_small_minus(cls, a, z): return cosh(2*a*asinh(sqrt(z))) @classmethod def _expr_big(cls, a, z, n): return cosh(2*a*acosh(sqrt(z)) + a*pi*I*(2*n - 1)) @classmethod def _expr_big_minus(cls, a, z, n): return cosh(2*a*asinh(sqrt(z)) + 2*a*pi*I*n) class HyperRep_sinasin(HyperRep): """ Represent 2*a*z*hyper([1 - a, 1 + a], [3/2], z) == sqrt(z)/sqrt(1-z)*sin(2*a*asin(sqrt(z))) """ @classmethod def _expr_small(cls, a, z): return sqrt(z)/sqrt(1 - z)*sin(2*a*asin(sqrt(z))) @classmethod def _expr_small_minus(cls, a, z): return -sqrt(z)/sqrt(1 + z)*sinh(2*a*asinh(sqrt(z))) @classmethod def _expr_big(cls, a, z, n): return -1/sqrt(1 - 1/z)*sinh(2*a*acosh(sqrt(z)) + a*pi*I*(2*n - 1)) @classmethod def _expr_big_minus(cls, a, z, n): return -1/sqrt(1 + 1/z)*sinh(2*a*asinh(sqrt(z)) + 2*a*pi*I*n) class appellf1(Function): r""" This is the Appell hypergeometric function of two variables as: .. math :: F_1(a,b_1,b_2,c,x,y) = \sum_{m=0}^{\infty} \sum_{n=0}^{\infty} \frac{(a)_{m+n} (b_1)_m (b_2)_n}{(c)_{m+n}} \frac{x^m y^n}{m! n!}. Examples ======== >>> from sympy.functions.special.hyper import appellf1 >>> from sympy import symbols >>> x, y, a, b1, b2, c = symbols('x y a b1 b2 c') >>> appellf1(2., 1., 6., 4., 5., 6.) 0.0063339426292673 >>> appellf1(12., 12., 6., 4., 0.5, 0.12) 172870711.659936 >>> appellf1(40, 2, 6, 4, 15, 60) appellf1(40, 2, 6, 4, 15, 60) >>> appellf1(20., 12., 10., 3., 0.5, 0.12) 15605338197184.4 >>> appellf1(40, 2, 6, 4, x, y) appellf1(40, 2, 6, 4, x, y) >>> appellf1(a, b1, b2, c, x, y) appellf1(a, b1, b2, c, x, y) References ========== .. [1] https://en.wikipedia.org/wiki/Appell_series .. [2] http://functions.wolfram.com/HypergeometricFunctions/AppellF1/ """ @classmethod def eval(cls, a, b1, b2, c, x, y): if default_sort_key(b1) > default_sort_key(b2): b1, b2 = b2, b1 x, y = y, x return cls(a, b1, b2, c, x, y) elif b1 == b2 and default_sort_key(x) > default_sort_key(y): x, y = y, x return cls(a, b1, b2, c, x, y) if x == 0 and y == 0: return S.One def fdiff(self, argindex=5): a, b1, b2, c, x, y = self.args if argindex == 5: return (a*b1/c)*appellf1(a + 1, b1 + 1, b2, c + 1, x, y) elif argindex == 6: return (a*b2/c)*appellf1(a + 1, b1, b2 + 1, c + 1, x, y) elif argindex in (1, 2, 3, 4): return Derivative(self, self.args[argindex-1]) else: raise ArgumentIndexError(self, argindex) sympy-sympy-1.9/sympy/functions/special/mathieu_functions.py000066400000000000000000000146621412543434000246430ustar00rootroot00000000000000""" This module contains the Mathieu functions. """ from sympy.core.function import Function, ArgumentIndexError from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import sin, cos class MathieuBase(Function): """ Abstract base class for Mathieu functions. This class is meant to reduce code duplication. """ unbranched = True def _eval_conjugate(self): a, q, z = self.args return self.func(a.conjugate(), q.conjugate(), z.conjugate()) class mathieus(MathieuBase): r""" The Mathieu Sine function $S(a,q,z)$. Explanation =========== This function is one solution of the Mathieu differential equation: .. math :: y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0 The other solution is the Mathieu Cosine function. Examples ======== >>> from sympy import diff, mathieus >>> from sympy.abc import a, q, z >>> mathieus(a, q, z) mathieus(a, q, z) >>> mathieus(a, 0, z) sin(sqrt(a)*z) >>> diff(mathieus(a, q, z), z) mathieusprime(a, q, z) See Also ======== mathieuc: Mathieu cosine function. mathieusprime: Derivative of Mathieu sine function. mathieucprime: Derivative of Mathieu cosine function. References ========== .. [1] https://en.wikipedia.org/wiki/Mathieu_function .. [2] http://dlmf.nist.gov/28 .. [3] http://mathworld.wolfram.com/MathieuBase.html .. [4] http://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuS/ """ def fdiff(self, argindex=1): if argindex == 3: a, q, z = self.args return mathieusprime(a, q, z) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, a, q, z): if q.is_Number and q.is_zero: return sin(sqrt(a)*z) # Try to pull out factors of -1 if z.could_extract_minus_sign(): return -cls(a, q, -z) class mathieuc(MathieuBase): r""" The Mathieu Cosine function $C(a,q,z)$. Explanation =========== This function is one solution of the Mathieu differential equation: .. math :: y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0 The other solution is the Mathieu Sine function. Examples ======== >>> from sympy import diff, mathieuc >>> from sympy.abc import a, q, z >>> mathieuc(a, q, z) mathieuc(a, q, z) >>> mathieuc(a, 0, z) cos(sqrt(a)*z) >>> diff(mathieuc(a, q, z), z) mathieucprime(a, q, z) See Also ======== mathieus: Mathieu sine function mathieusprime: Derivative of Mathieu sine function mathieucprime: Derivative of Mathieu cosine function References ========== .. [1] https://en.wikipedia.org/wiki/Mathieu_function .. [2] http://dlmf.nist.gov/28 .. [3] http://mathworld.wolfram.com/MathieuBase.html .. [4] http://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuC/ """ def fdiff(self, argindex=1): if argindex == 3: a, q, z = self.args return mathieucprime(a, q, z) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, a, q, z): if q.is_Number and q.is_zero: return cos(sqrt(a)*z) # Try to pull out factors of -1 if z.could_extract_minus_sign(): return cls(a, q, -z) class mathieusprime(MathieuBase): r""" The derivative $S^{\prime}(a,q,z)$ of the Mathieu Sine function. Explanation =========== This function is one solution of the Mathieu differential equation: .. math :: y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0 The other solution is the Mathieu Cosine function. Examples ======== >>> from sympy import diff, mathieusprime >>> from sympy.abc import a, q, z >>> mathieusprime(a, q, z) mathieusprime(a, q, z) >>> mathieusprime(a, 0, z) sqrt(a)*cos(sqrt(a)*z) >>> diff(mathieusprime(a, q, z), z) (-a + 2*q*cos(2*z))*mathieus(a, q, z) See Also ======== mathieus: Mathieu sine function mathieuc: Mathieu cosine function mathieucprime: Derivative of Mathieu cosine function References ========== .. [1] https://en.wikipedia.org/wiki/Mathieu_function .. [2] http://dlmf.nist.gov/28 .. [3] http://mathworld.wolfram.com/MathieuBase.html .. [4] http://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuSPrime/ """ def fdiff(self, argindex=1): if argindex == 3: a, q, z = self.args return (2*q*cos(2*z) - a)*mathieus(a, q, z) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, a, q, z): if q.is_Number and q.is_zero: return sqrt(a)*cos(sqrt(a)*z) # Try to pull out factors of -1 if z.could_extract_minus_sign(): return cls(a, q, -z) class mathieucprime(MathieuBase): r""" The derivative $C^{\prime}(a,q,z)$ of the Mathieu Cosine function. Explanation =========== This function is one solution of the Mathieu differential equation: .. math :: y(x)^{\prime\prime} + (a - 2 q \cos(2 x)) y(x) = 0 The other solution is the Mathieu Sine function. Examples ======== >>> from sympy import diff, mathieucprime >>> from sympy.abc import a, q, z >>> mathieucprime(a, q, z) mathieucprime(a, q, z) >>> mathieucprime(a, 0, z) -sqrt(a)*sin(sqrt(a)*z) >>> diff(mathieucprime(a, q, z), z) (-a + 2*q*cos(2*z))*mathieuc(a, q, z) See Also ======== mathieus: Mathieu sine function mathieuc: Mathieu cosine function mathieusprime: Derivative of Mathieu sine function References ========== .. [1] https://en.wikipedia.org/wiki/Mathieu_function .. [2] http://dlmf.nist.gov/28 .. [3] http://mathworld.wolfram.com/MathieuBase.html .. [4] http://functions.wolfram.com/MathieuandSpheroidalFunctions/MathieuCPrime/ """ def fdiff(self, argindex=1): if argindex == 3: a, q, z = self.args return (2*q*cos(2*z) - a)*mathieuc(a, q, z) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, a, q, z): if q.is_Number and q.is_zero: return -sqrt(a)*sin(sqrt(a)*z) # Try to pull out factors of -1 if z.could_extract_minus_sign(): return -cls(a, q, -z) sympy-sympy-1.9/sympy/functions/special/polynomials.py000066400000000000000000001171221412543434000234600ustar00rootroot00000000000000""" This module mainly implements special orthogonal polynomials. See also functions.combinatorial.numbers which contains some combinatorial polynomials. """ from sympy.core import Rational from sympy.core.function import Function, ArgumentIndexError from sympy.core.singleton import S from sympy.core.symbol import Dummy from sympy.functions.combinatorial.factorials import binomial, factorial, RisingFactorial from sympy.functions.elementary.complexes import re from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.integers import floor from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import cos, sec from sympy.functions.special.gamma_functions import gamma from sympy.functions.special.hyper import hyper from sympy.polys.orthopolys import ( jacobi_poly, gegenbauer_poly, chebyshevt_poly, chebyshevu_poly, laguerre_poly, hermite_poly, legendre_poly ) _x = Dummy('x') class OrthogonalPolynomial(Function): """Base class for orthogonal polynomials. """ @classmethod def _eval_at_order(cls, n, x): if n.is_integer and n >= 0: return cls._ortho_poly(int(n), _x).subs(_x, x) def _eval_conjugate(self): return self.func(self.args[0], self.args[1].conjugate()) #---------------------------------------------------------------------------- # Jacobi polynomials # class jacobi(OrthogonalPolynomial): r""" Jacobi polynomial $P_n^{\left(\alpha, \beta\right)}(x)$. Explanation =========== ``jacobi(n, alpha, beta, x)`` gives the nth Jacobi polynomial in x, $P_n^{\left(\alpha, \beta\right)}(x)$. The Jacobi polynomials are orthogonal on $[-1, 1]$ with respect to the weight $\left(1-x\right)^\alpha \left(1+x\right)^\beta$. Examples ======== >>> from sympy import jacobi, S, conjugate, diff >>> from sympy.abc import a, b, n, x >>> jacobi(0, a, b, x) 1 >>> jacobi(1, a, b, x) a/2 - b/2 + x*(a/2 + b/2 + 1) >>> jacobi(2, a, b, x) a**2/8 - a*b/4 - a/8 + b**2/8 - b/8 + x**2*(a**2/8 + a*b/4 + 7*a/8 + b**2/8 + 7*b/8 + 3/2) + x*(a**2/4 + 3*a/4 - b**2/4 - 3*b/4) - 1/2 >>> jacobi(n, a, b, x) jacobi(n, a, b, x) >>> jacobi(n, a, a, x) RisingFactorial(a + 1, n)*gegenbauer(n, a + 1/2, x)/RisingFactorial(2*a + 1, n) >>> jacobi(n, 0, 0, x) legendre(n, x) >>> jacobi(n, S(1)/2, S(1)/2, x) RisingFactorial(3/2, n)*chebyshevu(n, x)/factorial(n + 1) >>> jacobi(n, -S(1)/2, -S(1)/2, x) RisingFactorial(1/2, n)*chebyshevt(n, x)/factorial(n) >>> jacobi(n, a, b, -x) (-1)**n*jacobi(n, b, a, x) >>> jacobi(n, a, b, 0) gamma(a + n + 1)*hyper((-b - n, -n), (a + 1,), -1)/(2**n*factorial(n)*gamma(a + 1)) >>> jacobi(n, a, b, 1) RisingFactorial(a + 1, n)/factorial(n) >>> conjugate(jacobi(n, a, b, x)) jacobi(n, conjugate(a), conjugate(b), conjugate(x)) >>> diff(jacobi(n,a,b,x), x) (a/2 + b/2 + n/2 + 1/2)*jacobi(n - 1, a + 1, b + 1, x) See Also ======== gegenbauer, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly, sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Jacobi_polynomials .. [2] http://mathworld.wolfram.com/JacobiPolynomial.html .. [3] http://functions.wolfram.com/Polynomials/JacobiP/ """ @classmethod def eval(cls, n, a, b, x): # Simplify to other polynomials # P^{a, a}_n(x) if a == b: if a == Rational(-1, 2): return RisingFactorial(S.Half, n) / factorial(n) * chebyshevt(n, x) elif a.is_zero: return legendre(n, x) elif a == S.Half: return RisingFactorial(3*S.Half, n) / factorial(n + 1) * chebyshevu(n, x) else: return RisingFactorial(a + 1, n) / RisingFactorial(2*a + 1, n) * gegenbauer(n, a + S.Half, x) elif b == -a: # P^{a, -a}_n(x) return gamma(n + a + 1) / gamma(n + 1) * (1 + x)**(a/2) / (1 - x)**(a/2) * assoc_legendre(n, -a, x) if not n.is_Number: # Symbolic result P^{a,b}_n(x) # P^{a,b}_n(-x) ---> (-1)**n * P^{b,a}_n(-x) if x.could_extract_minus_sign(): return S.NegativeOne**n * jacobi(n, b, a, -x) # We can evaluate for some special values of x if x.is_zero: return (2**(-n) * gamma(a + n + 1) / (gamma(a + 1) * factorial(n)) * hyper([-b - n, -n], [a + 1], -1)) if x == S.One: return RisingFactorial(a + 1, n) / factorial(n) elif x is S.Infinity: if n.is_positive: # Make sure a+b+2*n \notin Z if (a + b + 2*n).is_integer: raise ValueError("Error. a + b + 2*n should not be an integer.") return RisingFactorial(a + b + n + 1, n) * S.Infinity else: # n is a given fixed integer, evaluate into polynomial return jacobi_poly(n, a, b, x) def fdiff(self, argindex=4): from sympy import Sum if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt a n, a, b, x = self.args k = Dummy("k") f1 = 1 / (a + b + n + k + 1) f2 = ((a + b + 2*k + 1) * RisingFactorial(b + k + 1, n - k) / ((n - k) * RisingFactorial(a + b + k + 1, n - k))) return Sum(f1 * (jacobi(n, a, b, x) + f2*jacobi(k, a, b, x)), (k, 0, n - 1)) elif argindex == 3: # Diff wrt b n, a, b, x = self.args k = Dummy("k") f1 = 1 / (a + b + n + k + 1) f2 = (-1)**(n - k) * ((a + b + 2*k + 1) * RisingFactorial(a + k + 1, n - k) / ((n - k) * RisingFactorial(a + b + k + 1, n - k))) return Sum(f1 * (jacobi(n, a, b, x) + f2*jacobi(k, a, b, x)), (k, 0, n - 1)) elif argindex == 4: # Diff wrt x n, a, b, x = self.args return S.Half * (a + b + n + 1) * jacobi(n - 1, a + 1, b + 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, a, b, x, **kwargs): from sympy import Sum # Make sure n \in N if n.is_negative or n.is_integer is False: raise ValueError("Error: n should be a non-negative integer.") k = Dummy("k") kern = (RisingFactorial(-n, k) * RisingFactorial(a + b + n + 1, k) * RisingFactorial(a + k + 1, n - k) / factorial(k) * ((1 - x)/2)**k) return 1 / factorial(n) * Sum(kern, (k, 0, n)) def _eval_conjugate(self): n, a, b, x = self.args return self.func(n, a.conjugate(), b.conjugate(), x.conjugate()) def jacobi_normalized(n, a, b, x): r""" Jacobi polynomial $P_n^{\left(\alpha, \beta\right)}(x)$. Explanation =========== ``jacobi_normalized(n, alpha, beta, x)`` gives the nth Jacobi polynomial in *x*, $P_n^{\left(\alpha, \beta\right)}(x)$. The Jacobi polynomials are orthogonal on $[-1, 1]$ with respect to the weight $\left(1-x\right)^\alpha \left(1+x\right)^\beta$. This functions returns the polynomials normilzed: .. math:: \int_{-1}^{1} P_m^{\left(\alpha, \beta\right)}(x) P_n^{\left(\alpha, \beta\right)}(x) (1-x)^{\alpha} (1+x)^{\beta} \mathrm{d}x = \delta_{m,n} Examples ======== >>> from sympy import jacobi_normalized >>> from sympy.abc import n,a,b,x >>> jacobi_normalized(n, a, b, x) jacobi(n, a, b, x)/sqrt(2**(a + b + 1)*gamma(a + n + 1)*gamma(b + n + 1)/((a + b + 2*n + 1)*factorial(n)*gamma(a + b + n + 1))) Parameters ========== n : integer degree of polynomial a : alpha value b : beta value x : symbol See Also ======== gegenbauer, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly, sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Jacobi_polynomials .. [2] http://mathworld.wolfram.com/JacobiPolynomial.html .. [3] http://functions.wolfram.com/Polynomials/JacobiP/ """ nfactor = (S(2)**(a + b + 1) * (gamma(n + a + 1) * gamma(n + b + 1)) / (2*n + a + b + 1) / (factorial(n) * gamma(n + a + b + 1))) return jacobi(n, a, b, x) / sqrt(nfactor) #---------------------------------------------------------------------------- # Gegenbauer polynomials # class gegenbauer(OrthogonalPolynomial): r""" Gegenbauer polynomial $C_n^{\left(\alpha\right)}(x)$. Explanation =========== ``gegenbauer(n, alpha, x)`` gives the nth Gegenbauer polynomial in x, $C_n^{\left(\alpha\right)}(x)$. The Gegenbauer polynomials are orthogonal on $[-1, 1]$ with respect to the weight $\left(1-x^2\right)^{\alpha-\frac{1}{2}}$. Examples ======== >>> from sympy import gegenbauer, conjugate, diff >>> from sympy.abc import n,a,x >>> gegenbauer(0, a, x) 1 >>> gegenbauer(1, a, x) 2*a*x >>> gegenbauer(2, a, x) -a + x**2*(2*a**2 + 2*a) >>> gegenbauer(3, a, x) x**3*(4*a**3/3 + 4*a**2 + 8*a/3) + x*(-2*a**2 - 2*a) >>> gegenbauer(n, a, x) gegenbauer(n, a, x) >>> gegenbauer(n, a, -x) (-1)**n*gegenbauer(n, a, x) >>> gegenbauer(n, a, 0) 2**n*sqrt(pi)*gamma(a + n/2)/(gamma(a)*gamma(1/2 - n/2)*gamma(n + 1)) >>> gegenbauer(n, a, 1) gamma(2*a + n)/(gamma(2*a)*gamma(n + 1)) >>> conjugate(gegenbauer(n, a, x)) gegenbauer(n, conjugate(a), conjugate(x)) >>> diff(gegenbauer(n, a, x), x) 2*a*gegenbauer(n - 1, a + 1, x) See Also ======== jacobi, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Gegenbauer_polynomials .. [2] http://mathworld.wolfram.com/GegenbauerPolynomial.html .. [3] http://functions.wolfram.com/Polynomials/GegenbauerC3/ """ @classmethod def eval(cls, n, a, x): # For negative n the polynomials vanish # See http://functions.wolfram.com/Polynomials/GegenbauerC3/03/01/03/0012/ if n.is_negative: return S.Zero # Some special values for fixed a if a == S.Half: return legendre(n, x) elif a == S.One: return chebyshevu(n, x) elif a == S.NegativeOne: return S.Zero if not n.is_Number: # Handle this before the general sign extraction rule if x == S.NegativeOne: if (re(a) > S.Half) == True: return S.ComplexInfinity else: return (cos(S.Pi*(a+n)) * sec(S.Pi*a) * gamma(2*a+n) / (gamma(2*a) * gamma(n+1))) # Symbolic result C^a_n(x) # C^a_n(-x) ---> (-1)**n * C^a_n(x) if x.could_extract_minus_sign(): return S.NegativeOne**n * gegenbauer(n, a, -x) # We can evaluate for some special values of x if x.is_zero: return (2**n * sqrt(S.Pi) * gamma(a + S.Half*n) / (gamma((1 - n)/2) * gamma(n + 1) * gamma(a)) ) if x == S.One: return gamma(2*a + n) / (gamma(2*a) * gamma(n + 1)) elif x is S.Infinity: if n.is_positive: return RisingFactorial(a, n) * S.Infinity else: # n is a given fixed integer, evaluate into polynomial return gegenbauer_poly(n, a, x) def fdiff(self, argindex=3): from sympy import Sum if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt a n, a, x = self.args k = Dummy("k") factor1 = 2 * (1 + (-1)**(n - k)) * (k + a) / ((k + n + 2*a) * (n - k)) factor2 = 2*(k + 1) / ((k + 2*a) * (2*k + 2*a + 1)) + \ 2 / (k + n + 2*a) kern = factor1*gegenbauer(k, a, x) + factor2*gegenbauer(n, a, x) return Sum(kern, (k, 0, n - 1)) elif argindex == 3: # Diff wrt x n, a, x = self.args return 2*a*gegenbauer(n - 1, a + 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, a, x, **kwargs): from sympy import Sum k = Dummy("k") kern = ((-1)**k * RisingFactorial(a, n - k) * (2*x)**(n - 2*k) / (factorial(k) * factorial(n - 2*k))) return Sum(kern, (k, 0, floor(n/2))) def _eval_conjugate(self): n, a, x = self.args return self.func(n, a.conjugate(), x.conjugate()) #---------------------------------------------------------------------------- # Chebyshev polynomials of first and second kind # class chebyshevt(OrthogonalPolynomial): r""" Chebyshev polynomial of the first kind, $T_n(x)$. Explanation =========== ``chebyshevt(n, x)`` gives the nth Chebyshev polynomial (of the first kind) in x, $T_n(x)$. The Chebyshev polynomials of the first kind are orthogonal on $[-1, 1]$ with respect to the weight $\frac{1}{\sqrt{1-x^2}}$. Examples ======== >>> from sympy import chebyshevt, diff >>> from sympy.abc import n,x >>> chebyshevt(0, x) 1 >>> chebyshevt(1, x) x >>> chebyshevt(2, x) 2*x**2 - 1 >>> chebyshevt(n, x) chebyshevt(n, x) >>> chebyshevt(n, -x) (-1)**n*chebyshevt(n, x) >>> chebyshevt(-n, x) chebyshevt(n, x) >>> chebyshevt(n, 0) cos(pi*n/2) >>> chebyshevt(n, -1) (-1)**n >>> diff(chebyshevt(n, x), x) n*chebyshevu(n - 1, x) See Also ======== jacobi, gegenbauer, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Chebyshev_polynomial .. [2] http://mathworld.wolfram.com/ChebyshevPolynomialoftheFirstKind.html .. [3] http://mathworld.wolfram.com/ChebyshevPolynomialoftheSecondKind.html .. [4] http://functions.wolfram.com/Polynomials/ChebyshevT/ .. [5] http://functions.wolfram.com/Polynomials/ChebyshevU/ """ _ortho_poly = staticmethod(chebyshevt_poly) @classmethod def eval(cls, n, x): if not n.is_Number: # Symbolic result T_n(x) # T_n(-x) ---> (-1)**n * T_n(x) if x.could_extract_minus_sign(): return S.NegativeOne**n * chebyshevt(n, -x) # T_{-n}(x) ---> T_n(x) if n.could_extract_minus_sign(): return chebyshevt(-n, x) # We can evaluate for some special values of x if x.is_zero: return cos(S.Half * S.Pi * n) if x == S.One: return S.One elif x is S.Infinity: return S.Infinity else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: # T_{-n}(x) == T_n(x) return cls._eval_at_order(-n, x) else: return cls._eval_at_order(n, x) def fdiff(self, argindex=2): if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt x n, x = self.args return n * chebyshevu(n - 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x, **kwargs): from sympy import Sum k = Dummy("k") kern = binomial(n, 2*k) * (x**2 - 1)**k * x**(n - 2*k) return Sum(kern, (k, 0, floor(n/2))) class chebyshevu(OrthogonalPolynomial): r""" Chebyshev polynomial of the second kind, $U_n(x)$. Explanation =========== ``chebyshevu(n, x)`` gives the nth Chebyshev polynomial of the second kind in x, $U_n(x)$. The Chebyshev polynomials of the second kind are orthogonal on $[-1, 1]$ with respect to the weight $\sqrt{1-x^2}$. Examples ======== >>> from sympy import chebyshevu, diff >>> from sympy.abc import n,x >>> chebyshevu(0, x) 1 >>> chebyshevu(1, x) 2*x >>> chebyshevu(2, x) 4*x**2 - 1 >>> chebyshevu(n, x) chebyshevu(n, x) >>> chebyshevu(n, -x) (-1)**n*chebyshevu(n, x) >>> chebyshevu(-n, x) -chebyshevu(n - 2, x) >>> chebyshevu(n, 0) cos(pi*n/2) >>> chebyshevu(n, 1) n + 1 >>> diff(chebyshevu(n, x), x) (-x*chebyshevu(n, x) + (n + 1)*chebyshevt(n + 1, x))/(x**2 - 1) See Also ======== jacobi, gegenbauer, chebyshevt, chebyshevt_root, chebyshevu_root, legendre, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Chebyshev_polynomial .. [2] http://mathworld.wolfram.com/ChebyshevPolynomialoftheFirstKind.html .. [3] http://mathworld.wolfram.com/ChebyshevPolynomialoftheSecondKind.html .. [4] http://functions.wolfram.com/Polynomials/ChebyshevT/ .. [5] http://functions.wolfram.com/Polynomials/ChebyshevU/ """ _ortho_poly = staticmethod(chebyshevu_poly) @classmethod def eval(cls, n, x): if not n.is_Number: # Symbolic result U_n(x) # U_n(-x) ---> (-1)**n * U_n(x) if x.could_extract_minus_sign(): return S.NegativeOne**n * chebyshevu(n, -x) # U_{-n}(x) ---> -U_{n-2}(x) if n.could_extract_minus_sign(): if n == S.NegativeOne: # n can not be -1 here return S.Zero elif not (-n - 2).could_extract_minus_sign(): return -chebyshevu(-n - 2, x) # We can evaluate for some special values of x if x.is_zero: return cos(S.Half * S.Pi * n) if x == S.One: return S.One + n elif x is S.Infinity: return S.Infinity else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: # U_{-n}(x) ---> -U_{n-2}(x) if n == S.NegativeOne: return S.Zero else: return -cls._eval_at_order(-n - 2, x) else: return cls._eval_at_order(n, x) def fdiff(self, argindex=2): if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt x n, x = self.args return ((n + 1) * chebyshevt(n + 1, x) - x * chebyshevu(n, x)) / (x**2 - 1) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x, **kwargs): from sympy import Sum k = Dummy("k") kern = S.NegativeOne**k * factorial( n - k) * (2*x)**(n - 2*k) / (factorial(k) * factorial(n - 2*k)) return Sum(kern, (k, 0, floor(n/2))) class chebyshevt_root(Function): r""" ``chebyshev_root(n, k)`` returns the kth root (indexed from zero) of the nth Chebyshev polynomial of the first kind; that is, if 0 <= k < n, ``chebyshevt(n, chebyshevt_root(n, k)) == 0``. Examples ======== >>> from sympy import chebyshevt, chebyshevt_root >>> chebyshevt_root(3, 2) -sqrt(3)/2 >>> chebyshevt(3, chebyshevt_root(3, 2)) 0 See Also ======== jacobi, gegenbauer, chebyshevt, chebyshevu, chebyshevu_root, legendre, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly """ @classmethod def eval(cls, n, k): if not ((0 <= k) and (k < n)): raise ValueError("must have 0 <= k < n, " "got k = %s and n = %s" % (k, n)) return cos(S.Pi*(2*k + 1)/(2*n)) class chebyshevu_root(Function): r""" ``chebyshevu_root(n, k)`` returns the kth root (indexed from zero) of the nth Chebyshev polynomial of the second kind; that is, if 0 <= k < n, ``chebyshevu(n, chebyshevu_root(n, k)) == 0``. Examples ======== >>> from sympy import chebyshevu, chebyshevu_root >>> chebyshevu_root(3, 2) -sqrt(2)/2 >>> chebyshevu(3, chebyshevu_root(3, 2)) 0 See Also ======== chebyshevt, chebyshevt_root, chebyshevu, legendre, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly """ @classmethod def eval(cls, n, k): if not ((0 <= k) and (k < n)): raise ValueError("must have 0 <= k < n, " "got k = %s and n = %s" % (k, n)) return cos(S.Pi*(k + 1)/(n + 1)) #---------------------------------------------------------------------------- # Legendre polynomials and Associated Legendre polynomials # class legendre(OrthogonalPolynomial): r""" ``legendre(n, x)`` gives the nth Legendre polynomial of x, $P_n(x)$ Explanation =========== The Legendre polynomials are orthogonal on [-1, 1] with respect to the constant weight 1. They satisfy $P_n(1) = 1$ for all n; further, $P_n$ is odd for odd n and even for even n. Examples ======== >>> from sympy import legendre, diff >>> from sympy.abc import x, n >>> legendre(0, x) 1 >>> legendre(1, x) x >>> legendre(2, x) 3*x**2/2 - 1/2 >>> legendre(n, x) legendre(n, x) >>> diff(legendre(n,x), x) n*(x*legendre(n, x) - legendre(n - 1, x))/(x**2 - 1) See Also ======== jacobi, gegenbauer, chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root, assoc_legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Legendre_polynomial .. [2] http://mathworld.wolfram.com/LegendrePolynomial.html .. [3] http://functions.wolfram.com/Polynomials/LegendreP/ .. [4] http://functions.wolfram.com/Polynomials/LegendreP2/ """ _ortho_poly = staticmethod(legendre_poly) @classmethod def eval(cls, n, x): if not n.is_Number: # Symbolic result L_n(x) # L_n(-x) ---> (-1)**n * L_n(x) if x.could_extract_minus_sign(): return S.NegativeOne**n * legendre(n, -x) # L_{-n}(x) ---> L_{n-1}(x) if n.could_extract_minus_sign() and not(-n - 1).could_extract_minus_sign(): return legendre(-n - S.One, x) # We can evaluate for some special values of x if x.is_zero: return sqrt(S.Pi)/(gamma(S.Half - n/2)*gamma(S.One + n/2)) elif x == S.One: return S.One elif x is S.Infinity: return S.Infinity else: # n is a given fixed integer, evaluate into polynomial; # L_{-n}(x) ---> L_{n-1}(x) if n.is_negative: n = -n - S.One return cls._eval_at_order(n, x) def fdiff(self, argindex=2): if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt x # Find better formula, this is unsuitable for x = +/-1 # http://www.autodiff.org/ad16/Oral/Buecker_Legendre.pdf says # at x = 1: # n*(n + 1)/2 , m = 0 # oo , m = 1 # -(n-1)*n*(n+1)*(n+2)/4 , m = 2 # 0 , m = 3, 4, ..., n # # at x = -1 # (-1)**(n+1)*n*(n + 1)/2 , m = 0 # (-1)**n*oo , m = 1 # (-1)**n*(n-1)*n*(n+1)*(n+2)/4 , m = 2 # 0 , m = 3, 4, ..., n n, x = self.args return n/(x**2 - 1)*(x*legendre(n, x) - legendre(n - 1, x)) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x, **kwargs): from sympy import Sum k = Dummy("k") kern = (-1)**k*binomial(n, k)**2*((1 + x)/2)**(n - k)*((1 - x)/2)**k return Sum(kern, (k, 0, n)) class assoc_legendre(Function): r""" ``assoc_legendre(n, m, x)`` gives $P_n^m(x)$, where n and m are the degree and order or an expression which is related to the nth order Legendre polynomial, $P_n(x)$ in the following manner: .. math:: P_n^m(x) = (-1)^m (1 - x^2)^{\frac{m}{2}} \frac{\mathrm{d}^m P_n(x)}{\mathrm{d} x^m} Explanation =========== Associated Legendre polynomials are orthogonal on [-1, 1] with: - weight = 1 for the same m, and different n. - weight = 1/(1-x**2) for the same n, and different m. Examples ======== >>> from sympy import assoc_legendre >>> from sympy.abc import x, m, n >>> assoc_legendre(0,0, x) 1 >>> assoc_legendre(1,0, x) x >>> assoc_legendre(1,1, x) -sqrt(1 - x**2) >>> assoc_legendre(n,m,x) assoc_legendre(n, m, x) See Also ======== jacobi, gegenbauer, chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, hermite, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Associated_Legendre_polynomials .. [2] http://mathworld.wolfram.com/LegendrePolynomial.html .. [3] http://functions.wolfram.com/Polynomials/LegendreP/ .. [4] http://functions.wolfram.com/Polynomials/LegendreP2/ """ @classmethod def _eval_at_order(cls, n, m): P = legendre_poly(n, _x, polys=True).diff((_x, m)) return (-1)**m * (1 - _x**2)**Rational(m, 2) * P.as_expr() @classmethod def eval(cls, n, m, x): if m.could_extract_minus_sign(): # P^{-m}_n ---> F * P^m_n return S.NegativeOne**(-m) * (factorial(m + n)/factorial(n - m)) * assoc_legendre(n, -m, x) if m == 0: # P^0_n ---> L_n return legendre(n, x) if x == 0: return 2**m*sqrt(S.Pi) / (gamma((1 - m - n)/2)*gamma(1 - (m - n)/2)) if n.is_Number and m.is_Number and n.is_integer and m.is_integer: if n.is_negative: raise ValueError("%s : 1st index must be nonnegative integer (got %r)" % (cls, n)) if abs(m) > n: raise ValueError("%s : abs('2nd index') must be <= '1st index' (got %r, %r)" % (cls, n, m)) return cls._eval_at_order(int(n), abs(int(m))).subs(_x, x) def fdiff(self, argindex=3): if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt m raise ArgumentIndexError(self, argindex) elif argindex == 3: # Diff wrt x # Find better formula, this is unsuitable for x = 1 n, m, x = self.args return 1/(x**2 - 1)*(x*n*assoc_legendre(n, m, x) - (m + n)*assoc_legendre(n - 1, m, x)) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, m, x, **kwargs): from sympy import Sum k = Dummy("k") kern = factorial(2*n - 2*k)/(2**n*factorial(n - k)*factorial( k)*factorial(n - 2*k - m))*(-1)**k*x**(n - m - 2*k) return (1 - x**2)**(m/2) * Sum(kern, (k, 0, floor((n - m)*S.Half))) def _eval_conjugate(self): n, m, x = self.args return self.func(n, m.conjugate(), x.conjugate()) #---------------------------------------------------------------------------- # Hermite polynomials # class hermite(OrthogonalPolynomial): r""" ``hermite(n, x)`` gives the nth Hermite polynomial in x, $H_n(x)$ Explanation =========== The Hermite polynomials are orthogonal on $(-\infty, \infty)$ with respect to the weight $\exp\left(-x^2\right)$. Examples ======== >>> from sympy import hermite, diff >>> from sympy.abc import x, n >>> hermite(0, x) 1 >>> hermite(1, x) 2*x >>> hermite(2, x) 4*x**2 - 2 >>> hermite(n, x) hermite(n, x) >>> diff(hermite(n,x), x) 2*n*hermite(n - 1, x) >>> hermite(n, -x) (-1)**n*hermite(n, x) See Also ======== jacobi, gegenbauer, chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, assoc_legendre, laguerre, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Hermite_polynomial .. [2] http://mathworld.wolfram.com/HermitePolynomial.html .. [3] http://functions.wolfram.com/Polynomials/HermiteH/ """ _ortho_poly = staticmethod(hermite_poly) @classmethod def eval(cls, n, x): if not n.is_Number: # Symbolic result H_n(x) # H_n(-x) ---> (-1)**n * H_n(x) if x.could_extract_minus_sign(): return S.NegativeOne**n * hermite(n, -x) # We can evaluate for some special values of x if x.is_zero: return 2**n * sqrt(S.Pi) / gamma((S.One - n)/2) elif x is S.Infinity: return S.Infinity else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: raise ValueError( "The index n must be nonnegative integer (got %r)" % n) else: return cls._eval_at_order(n, x) def fdiff(self, argindex=2): if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt x n, x = self.args return 2*n*hermite(n - 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x, **kwargs): from sympy import Sum k = Dummy("k") kern = (-1)**k / (factorial(k)*factorial(n - 2*k)) * (2*x)**(n - 2*k) return factorial(n)*Sum(kern, (k, 0, floor(n/2))) #---------------------------------------------------------------------------- # Laguerre polynomials # class laguerre(OrthogonalPolynomial): r""" Returns the nth Laguerre polynomial in x, $L_n(x)$. Examples ======== >>> from sympy import laguerre, diff >>> from sympy.abc import x, n >>> laguerre(0, x) 1 >>> laguerre(1, x) 1 - x >>> laguerre(2, x) x**2/2 - 2*x + 1 >>> laguerre(3, x) -x**3/6 + 3*x**2/2 - 3*x + 1 >>> laguerre(n, x) laguerre(n, x) >>> diff(laguerre(n, x), x) -assoc_laguerre(n - 1, 1, x) Parameters ========== n : int Degree of Laguerre polynomial. Must be ``n >= 0``. See Also ======== jacobi, gegenbauer, chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, assoc_legendre, hermite, assoc_laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Laguerre_polynomial .. [2] http://mathworld.wolfram.com/LaguerrePolynomial.html .. [3] http://functions.wolfram.com/Polynomials/LaguerreL/ .. [4] http://functions.wolfram.com/Polynomials/LaguerreL3/ """ _ortho_poly = staticmethod(laguerre_poly) @classmethod def eval(cls, n, x): if n.is_integer is False: raise ValueError("Error: n should be an integer.") if not n.is_Number: # Symbolic result L_n(x) # L_{n}(-x) ---> exp(-x) * L_{-n-1}(x) # L_{-n}(x) ---> exp(x) * L_{n-1}(-x) if n.could_extract_minus_sign() and not(-n - 1).could_extract_minus_sign(): return exp(x)*laguerre(-n - 1, -x) # We can evaluate for some special values of x if x.is_zero: return S.One elif x is S.NegativeInfinity: return S.Infinity elif x is S.Infinity: return S.NegativeOne**n * S.Infinity else: if n.is_negative: return exp(x)*laguerre(-n - 1, -x) else: return cls._eval_at_order(n, x) def fdiff(self, argindex=2): if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt x n, x = self.args return -assoc_laguerre(n - 1, 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, x, **kwargs): from sympy import Sum # Make sure n \in N_0 if n.is_negative: return exp(x) * self._eval_rewrite_as_polynomial(-n - 1, -x, **kwargs) if n.is_integer is False: raise ValueError("Error: n should be an integer.") k = Dummy("k") kern = RisingFactorial(-n, k) / factorial(k)**2 * x**k return Sum(kern, (k, 0, n)) class assoc_laguerre(OrthogonalPolynomial): r""" Returns the nth generalized Laguerre polynomial in x, $L_n(x)$. Examples ======== >>> from sympy import assoc_laguerre, diff >>> from sympy.abc import x, n, a >>> assoc_laguerre(0, a, x) 1 >>> assoc_laguerre(1, a, x) a - x + 1 >>> assoc_laguerre(2, a, x) a**2/2 + 3*a/2 + x**2/2 + x*(-a - 2) + 1 >>> assoc_laguerre(3, a, x) a**3/6 + a**2 + 11*a/6 - x**3/6 + x**2*(a/2 + 3/2) + x*(-a**2/2 - 5*a/2 - 3) + 1 >>> assoc_laguerre(n, a, 0) binomial(a + n, a) >>> assoc_laguerre(n, a, x) assoc_laguerre(n, a, x) >>> assoc_laguerre(n, 0, x) laguerre(n, x) >>> diff(assoc_laguerre(n, a, x), x) -assoc_laguerre(n - 1, a + 1, x) >>> diff(assoc_laguerre(n, a, x), a) Sum(assoc_laguerre(_k, a, x)/(-a + n), (_k, 0, n - 1)) Parameters ========== n : int Degree of Laguerre polynomial. Must be ``n >= 0``. alpha : Expr Arbitrary expression. For ``alpha=0`` regular Laguerre polynomials will be generated. See Also ======== jacobi, gegenbauer, chebyshevt, chebyshevt_root, chebyshevu, chebyshevu_root, legendre, assoc_legendre, hermite, laguerre, sympy.polys.orthopolys.jacobi_poly sympy.polys.orthopolys.gegenbauer_poly sympy.polys.orthopolys.chebyshevt_poly sympy.polys.orthopolys.chebyshevu_poly sympy.polys.orthopolys.hermite_poly sympy.polys.orthopolys.legendre_poly sympy.polys.orthopolys.laguerre_poly References ========== .. [1] https://en.wikipedia.org/wiki/Laguerre_polynomial#Generalized_Laguerre_polynomials .. [2] http://mathworld.wolfram.com/AssociatedLaguerrePolynomial.html .. [3] http://functions.wolfram.com/Polynomials/LaguerreL/ .. [4] http://functions.wolfram.com/Polynomials/LaguerreL3/ """ @classmethod def eval(cls, n, alpha, x): # L_{n}^{0}(x) ---> L_{n}(x) if alpha.is_zero: return laguerre(n, x) if not n.is_Number: # We can evaluate for some special values of x if x.is_zero: return binomial(n + alpha, alpha) elif x is S.Infinity and n > 0: return S.NegativeOne**n * S.Infinity elif x is S.NegativeInfinity and n > 0: return S.Infinity else: # n is a given fixed integer, evaluate into polynomial if n.is_negative: raise ValueError( "The index n must be nonnegative integer (got %r)" % n) else: return laguerre_poly(n, x, alpha) def fdiff(self, argindex=3): from sympy import Sum if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt alpha n, alpha, x = self.args k = Dummy("k") return Sum(assoc_laguerre(k, alpha, x) / (n - alpha), (k, 0, n - 1)) elif argindex == 3: # Diff wrt x n, alpha, x = self.args return -assoc_laguerre(n - 1, alpha + 1, x) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, alpha, x, **kwargs): from sympy import Sum # Make sure n \in N_0 if n.is_negative or n.is_integer is False: raise ValueError("Error: n should be a non-negative integer.") k = Dummy("k") kern = RisingFactorial( -n, k) / (gamma(k + alpha + 1) * factorial(k)) * x**k return gamma(n + alpha + 1) / factorial(n) * Sum(kern, (k, 0, n)) def _eval_conjugate(self): n, alpha, x = self.args return self.func(n, alpha.conjugate(), x.conjugate()) sympy-sympy-1.9/sympy/functions/special/singularity_functions.py000066400000000000000000000201331412543434000255470ustar00rootroot00000000000000from sympy.core import S, sympify, oo, diff from sympy.core.function import Function, ArgumentIndexError from sympy.core.logic import fuzzy_not from sympy.core.relational import Eq from sympy.functions.elementary.complexes import im from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.special.delta_functions import Heaviside ############################################################################### ############################# SINGULARITY FUNCTION ############################ ############################################################################### class SingularityFunction(Function): r""" Singularity functions are a class of discontinuous functions. Explanation =========== Singularity functions take a variable, an offset, and an exponent as arguments. These functions are represented using Macaulay brackets as: SingularityFunction(x, a, n) := ^n The singularity function will automatically evaluate to ``Derivative(DiracDelta(x - a), x, -n - 1)`` if ``n < 0`` and ``(x - a)**n*Heaviside(x - a)`` if ``n >= 0``. Examples ======== >>> from sympy import SingularityFunction, diff, Piecewise, DiracDelta, Heaviside, Symbol >>> from sympy.abc import x, a, n >>> SingularityFunction(x, a, n) SingularityFunction(x, a, n) >>> y = Symbol('y', positive=True) >>> n = Symbol('n', nonnegative=True) >>> SingularityFunction(y, -10, n) (y + 10)**n >>> y = Symbol('y', negative=True) >>> SingularityFunction(y, 10, n) 0 >>> SingularityFunction(x, 4, -1).subs(x, 4) oo >>> SingularityFunction(x, 10, -2).subs(x, 10) oo >>> SingularityFunction(4, 1, 5) 243 >>> diff(SingularityFunction(x, 1, 5) + SingularityFunction(x, 1, 4), x) 4*SingularityFunction(x, 1, 3) + 5*SingularityFunction(x, 1, 4) >>> diff(SingularityFunction(x, 4, 0), x, 2) SingularityFunction(x, 4, -2) >>> SingularityFunction(x, 4, 5).rewrite(Piecewise) Piecewise(((x - 4)**5, x - 4 > 0), (0, True)) >>> expr = SingularityFunction(x, a, n) >>> y = Symbol('y', positive=True) >>> n = Symbol('n', nonnegative=True) >>> expr.subs({x: y, a: -10, n: n}) (y + 10)**n The methods ``rewrite(DiracDelta)``, ``rewrite(Heaviside)``, and ``rewrite('HeavisideDiracDelta')`` returns the same output. One can use any of these methods according to their choice. >>> expr = SingularityFunction(x, 4, 5) + SingularityFunction(x, -3, -1) - SingularityFunction(x, 0, -2) >>> expr.rewrite(Heaviside) (x - 4)**5*Heaviside(x - 4) + DiracDelta(x + 3) - DiracDelta(x, 1) >>> expr.rewrite(DiracDelta) (x - 4)**5*Heaviside(x - 4) + DiracDelta(x + 3) - DiracDelta(x, 1) >>> expr.rewrite('HeavisideDiracDelta') (x - 4)**5*Heaviside(x - 4) + DiracDelta(x + 3) - DiracDelta(x, 1) See Also ======== DiracDelta, Heaviside References ========== .. [1] https://en.wikipedia.org/wiki/Singularity_function """ is_real = True def fdiff(self, argindex=1): """ Returns the first derivative of a DiracDelta Function. Explanation =========== The difference between ``diff()`` and ``fdiff()`` is: ``diff()`` is the user-level function and ``fdiff()`` is an object method. ``fdiff()`` is a convenience method available in the ``Function`` class. It returns the derivative of the function without considering the chain rule. ``diff(function, x)`` calls ``Function._eval_derivative`` which in turn calls ``fdiff()`` internally to compute the derivative of the function. """ if argindex == 1: x = sympify(self.args[0]) a = sympify(self.args[1]) n = sympify(self.args[2]) if n == 0 or n == -1: return self.func(x, a, n-1) elif n.is_positive: return n*self.func(x, a, n-1) else: raise ArgumentIndexError(self, argindex) @classmethod def eval(cls, variable, offset, exponent): """ Returns a simplified form or a value of Singularity Function depending on the argument passed by the object. Explanation =========== The ``eval()`` method is automatically called when the ``SingularityFunction`` class is about to be instantiated and it returns either some simplified instance or the unevaluated instance depending on the argument passed. In other words, ``eval()`` method is not needed to be called explicitly, it is being called and evaluated once the object is called. Examples ======== >>> from sympy import SingularityFunction, Symbol, nan >>> from sympy.abc import x, a, n >>> SingularityFunction(x, a, n) SingularityFunction(x, a, n) >>> SingularityFunction(5, 3, 2) 4 >>> SingularityFunction(x, a, nan) nan >>> SingularityFunction(x, 3, 0).subs(x, 3) 1 >>> SingularityFunction(x, a, n).eval(3, 5, 1) 0 >>> SingularityFunction(x, a, n).eval(4, 1, 5) 243 >>> x = Symbol('x', positive = True) >>> a = Symbol('a', negative = True) >>> n = Symbol('n', nonnegative = True) >>> SingularityFunction(x, a, n) (-a + x)**n >>> x = Symbol('x', negative = True) >>> a = Symbol('a', positive = True) >>> SingularityFunction(x, a, n) 0 """ x = sympify(variable) a = sympify(offset) n = sympify(exponent) shift = (x - a) if fuzzy_not(im(shift).is_zero): raise ValueError("Singularity Functions are defined only for Real Numbers.") if fuzzy_not(im(n).is_zero): raise ValueError("Singularity Functions are not defined for imaginary exponents.") if shift is S.NaN or n is S.NaN: return S.NaN if (n + 2).is_negative: raise ValueError("Singularity Functions are not defined for exponents less than -2.") if shift.is_extended_negative: return S.Zero if n.is_nonnegative and shift.is_extended_nonnegative: return (x - a)**n if n == -1 or n == -2: if shift.is_negative or shift.is_extended_positive: return S.Zero if shift.is_zero: return S.Infinity def _eval_rewrite_as_Piecewise(self, *args, **kwargs): ''' Converts a Singularity Function expression into its Piecewise form. ''' x = self.args[0] a = self.args[1] n = sympify(self.args[2]) if n == -1 or n == -2: return Piecewise((oo, Eq((x - a), 0)), (0, True)) elif n.is_nonnegative: return Piecewise(((x - a)**n, (x - a) > 0), (0, True)) def _eval_rewrite_as_Heaviside(self, *args, **kwargs): ''' Rewrites a Singularity Function expression using Heavisides and DiracDeltas. ''' x = self.args[0] a = self.args[1] n = sympify(self.args[2]) if n == -2: return diff(Heaviside(x - a), x.free_symbols.pop(), 2) if n == -1: return diff(Heaviside(x - a), x.free_symbols.pop(), 1) if n.is_nonnegative: return (x - a)**n*Heaviside(x - a) def _eval_as_leading_term(self, x, logx=None, cdir=0): z, a, n = self.args shift = (z - a).subs(x, 0) if n < 0: return S.Zero elif n.is_zero and shift.is_zero: return S.Zero if cdir == -1 else S.One elif shift.is_positive: return shift**n return S.Zero def _eval_nseries(self, x, n, logx=None, cdir=0): z, a, n = self.args shift = (z - a).subs(x, 0) if n < 0: return S.Zero elif n.is_zero and shift.is_zero: return S.Zero if cdir == -1 else S.One elif shift.is_positive: return ((z - a)**n)._eval_nseries(x, n, logx=logx, cdir=cdir) return S.Zero _eval_rewrite_as_DiracDelta = _eval_rewrite_as_Heaviside _eval_rewrite_as_HeavisideDiracDelta = _eval_rewrite_as_Heaviside sympy-sympy-1.9/sympy/functions/special/spherical_harmonics.py000066400000000000000000000255501412543434000251320ustar00rootroot00000000000000from sympy import pi, I from sympy.core import Dummy, sympify from sympy.core.function import Function, ArgumentIndexError from sympy.core.singleton import S from sympy.functions import assoc_legendre from sympy.functions.combinatorial.factorials import factorial from sympy.functions.elementary.complexes import Abs from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import sin, cos, cot _x = Dummy("x") class Ynm(Function): r""" Spherical harmonics defined as .. math:: Y_n^m(\theta, \varphi) := \sqrt{\frac{(2n+1)(n-m)!}{4\pi(n+m)!}} \exp(i m \varphi) \mathrm{P}_n^m\left(\cos(\theta)\right) Explanation =========== ``Ynm()`` gives the spherical harmonic function of order $n$ and $m$ in $\theta$ and $\varphi$, $Y_n^m(\theta, \varphi)$. The four parameters are as follows: $n \geq 0$ an integer and $m$ an integer such that $-n \leq m \leq n$ holds. The two angles are real-valued with $\theta \in [0, \pi]$ and $\varphi \in [0, 2\pi]$. Examples ======== >>> from sympy import Ynm, Symbol, simplify >>> from sympy.abc import n,m >>> theta = Symbol("theta") >>> phi = Symbol("phi") >>> Ynm(n, m, theta, phi) Ynm(n, m, theta, phi) Several symmetries are known, for the order: >>> Ynm(n, -m, theta, phi) (-1)**m*exp(-2*I*m*phi)*Ynm(n, m, theta, phi) As well as for the angles: >>> Ynm(n, m, -theta, phi) Ynm(n, m, theta, phi) >>> Ynm(n, m, theta, -phi) exp(-2*I*m*phi)*Ynm(n, m, theta, phi) For specific integers $n$ and $m$ we can evaluate the harmonics to more useful expressions: >>> simplify(Ynm(0, 0, theta, phi).expand(func=True)) 1/(2*sqrt(pi)) >>> simplify(Ynm(1, -1, theta, phi).expand(func=True)) sqrt(6)*exp(-I*phi)*sin(theta)/(4*sqrt(pi)) >>> simplify(Ynm(1, 0, theta, phi).expand(func=True)) sqrt(3)*cos(theta)/(2*sqrt(pi)) >>> simplify(Ynm(1, 1, theta, phi).expand(func=True)) -sqrt(6)*exp(I*phi)*sin(theta)/(4*sqrt(pi)) >>> simplify(Ynm(2, -2, theta, phi).expand(func=True)) sqrt(30)*exp(-2*I*phi)*sin(theta)**2/(8*sqrt(pi)) >>> simplify(Ynm(2, -1, theta, phi).expand(func=True)) sqrt(30)*exp(-I*phi)*sin(2*theta)/(8*sqrt(pi)) >>> simplify(Ynm(2, 0, theta, phi).expand(func=True)) sqrt(5)*(3*cos(theta)**2 - 1)/(4*sqrt(pi)) >>> simplify(Ynm(2, 1, theta, phi).expand(func=True)) -sqrt(30)*exp(I*phi)*sin(2*theta)/(8*sqrt(pi)) >>> simplify(Ynm(2, 2, theta, phi).expand(func=True)) sqrt(30)*exp(2*I*phi)*sin(theta)**2/(8*sqrt(pi)) We can differentiate the functions with respect to both angles: >>> from sympy import Ynm, Symbol, diff >>> from sympy.abc import n,m >>> theta = Symbol("theta") >>> phi = Symbol("phi") >>> diff(Ynm(n, m, theta, phi), theta) m*cot(theta)*Ynm(n, m, theta, phi) + sqrt((-m + n)*(m + n + 1))*exp(-I*phi)*Ynm(n, m + 1, theta, phi) >>> diff(Ynm(n, m, theta, phi), phi) I*m*Ynm(n, m, theta, phi) Further we can compute the complex conjugation: >>> from sympy import Ynm, Symbol, conjugate >>> from sympy.abc import n,m >>> theta = Symbol("theta") >>> phi = Symbol("phi") >>> conjugate(Ynm(n, m, theta, phi)) (-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi) To get back the well known expressions in spherical coordinates, we use full expansion: >>> from sympy import Ynm, Symbol, expand_func >>> from sympy.abc import n,m >>> theta = Symbol("theta") >>> phi = Symbol("phi") >>> expand_func(Ynm(n, m, theta, phi)) sqrt((2*n + 1)*factorial(-m + n)/factorial(m + n))*exp(I*m*phi)*assoc_legendre(n, m, cos(theta))/(2*sqrt(pi)) See Also ======== Ynm_c, Znm References ========== .. [1] https://en.wikipedia.org/wiki/Spherical_harmonics .. [2] http://mathworld.wolfram.com/SphericalHarmonic.html .. [3] http://functions.wolfram.com/Polynomials/SphericalHarmonicY/ .. [4] http://dlmf.nist.gov/14.30 """ @classmethod def eval(cls, n, m, theta, phi): n, m, theta, phi = [sympify(x) for x in (n, m, theta, phi)] # Handle negative index m and arguments theta, phi if m.could_extract_minus_sign(): m = -m return S.NegativeOne**m * exp(-2*I*m*phi) * Ynm(n, m, theta, phi) if theta.could_extract_minus_sign(): theta = -theta return Ynm(n, m, theta, phi) if phi.could_extract_minus_sign(): phi = -phi return exp(-2*I*m*phi) * Ynm(n, m, theta, phi) # TODO Add more simplififcation here def _eval_expand_func(self, **hints): n, m, theta, phi = self.args rv = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) * exp(I*m*phi) * assoc_legendre(n, m, cos(theta))) # We can do this because of the range of theta return rv.subs(sqrt(-cos(theta)**2 + 1), sin(theta)) def fdiff(self, argindex=4): if argindex == 1: # Diff wrt n raise ArgumentIndexError(self, argindex) elif argindex == 2: # Diff wrt m raise ArgumentIndexError(self, argindex) elif argindex == 3: # Diff wrt theta n, m, theta, phi = self.args return (m * cot(theta) * Ynm(n, m, theta, phi) + sqrt((n - m)*(n + m + 1)) * exp(-I*phi) * Ynm(n, m + 1, theta, phi)) elif argindex == 4: # Diff wrt phi n, m, theta, phi = self.args return I * m * Ynm(n, m, theta, phi) else: raise ArgumentIndexError(self, argindex) def _eval_rewrite_as_polynomial(self, n, m, theta, phi, **kwargs): # TODO: Make sure n \in N # TODO: Assert |m| <= n ortherwise we should return 0 return self.expand(func=True) def _eval_rewrite_as_sin(self, n, m, theta, phi, **kwargs): return self.rewrite(cos) def _eval_rewrite_as_cos(self, n, m, theta, phi, **kwargs): # This method can be expensive due to extensive use of simplification! from sympy.simplify import simplify, trigsimp # TODO: Make sure n \in N # TODO: Assert |m| <= n ortherwise we should return 0 term = simplify(self.expand(func=True)) # We can do this because of the range of theta term = term.xreplace({Abs(sin(theta)):sin(theta)}) return simplify(trigsimp(term)) def _eval_conjugate(self): # TODO: Make sure theta \in R and phi \in R n, m, theta, phi = self.args return S.NegativeOne**m * self.func(n, -m, theta, phi) def as_real_imag(self, deep=True, **hints): # TODO: Handle deep and hints n, m, theta, phi = self.args re = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) * cos(m*phi) * assoc_legendre(n, m, cos(theta))) im = (sqrt((2*n + 1)/(4*pi) * factorial(n - m)/factorial(n + m)) * sin(m*phi) * assoc_legendre(n, m, cos(theta))) return (re, im) def _eval_evalf(self, prec): # Note: works without this function by just calling # mpmath for Legendre polynomials. But using # the dedicated function directly is cleaner. from mpmath import mp, workprec from sympy import Expr n = self.args[0]._to_mpmath(prec) m = self.args[1]._to_mpmath(prec) theta = self.args[2]._to_mpmath(prec) phi = self.args[3]._to_mpmath(prec) with workprec(prec): res = mp.spherharm(n, m, theta, phi) return Expr._from_mpmath(res, prec) def Ynm_c(n, m, theta, phi): r""" Conjugate spherical harmonics defined as .. math:: \overline{Y_n^m(\theta, \varphi)} := (-1)^m Y_n^{-m}(\theta, \varphi). Examples ======== >>> from sympy import Ynm_c, Symbol, simplify >>> from sympy.abc import n,m >>> theta = Symbol("theta") >>> phi = Symbol("phi") >>> Ynm_c(n, m, theta, phi) (-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi) >>> Ynm_c(n, m, -theta, phi) (-1)**(2*m)*exp(-2*I*m*phi)*Ynm(n, m, theta, phi) For specific integers $n$ and $m$ we can evaluate the harmonics to more useful expressions: >>> simplify(Ynm_c(0, 0, theta, phi).expand(func=True)) 1/(2*sqrt(pi)) >>> simplify(Ynm_c(1, -1, theta, phi).expand(func=True)) sqrt(6)*exp(I*(-phi + 2*conjugate(phi)))*sin(theta)/(4*sqrt(pi)) See Also ======== Ynm, Znm References ========== .. [1] https://en.wikipedia.org/wiki/Spherical_harmonics .. [2] http://mathworld.wolfram.com/SphericalHarmonic.html .. [3] http://functions.wolfram.com/Polynomials/SphericalHarmonicY/ """ from sympy import conjugate return conjugate(Ynm(n, m, theta, phi)) class Znm(Function): r""" Real spherical harmonics defined as .. math:: Z_n^m(\theta, \varphi) := \begin{cases} \frac{Y_n^m(\theta, \varphi) + \overline{Y_n^m(\theta, \varphi)}}{\sqrt{2}} &\quad m > 0 \\ Y_n^m(\theta, \varphi) &\quad m = 0 \\ \frac{Y_n^m(\theta, \varphi) - \overline{Y_n^m(\theta, \varphi)}}{i \sqrt{2}} &\quad m < 0 \\ \end{cases} which gives in simplified form .. math:: Z_n^m(\theta, \varphi) = \begin{cases} \frac{Y_n^m(\theta, \varphi) + (-1)^m Y_n^{-m}(\theta, \varphi)}{\sqrt{2}} &\quad m > 0 \\ Y_n^m(\theta, \varphi) &\quad m = 0 \\ \frac{Y_n^m(\theta, \varphi) - (-1)^m Y_n^{-m}(\theta, \varphi)}{i \sqrt{2}} &\quad m < 0 \\ \end{cases} Examples ======== >>> from sympy import Znm, Symbol, simplify >>> from sympy.abc import n, m >>> theta = Symbol("theta") >>> phi = Symbol("phi") >>> Znm(n, m, theta, phi) Znm(n, m, theta, phi) For specific integers n and m we can evaluate the harmonics to more useful expressions: >>> simplify(Znm(0, 0, theta, phi).expand(func=True)) 1/(2*sqrt(pi)) >>> simplify(Znm(1, 1, theta, phi).expand(func=True)) -sqrt(3)*sin(theta)*cos(phi)/(2*sqrt(pi)) >>> simplify(Znm(2, 1, theta, phi).expand(func=True)) -sqrt(15)*sin(2*theta)*cos(phi)/(4*sqrt(pi)) See Also ======== Ynm, Ynm_c References ========== .. [1] https://en.wikipedia.org/wiki/Spherical_harmonics .. [2] http://mathworld.wolfram.com/SphericalHarmonic.html .. [3] http://functions.wolfram.com/Polynomials/SphericalHarmonicY/ """ @classmethod def eval(cls, n, m, theta, phi): n, m, th, ph = [sympify(x) for x in (n, m, theta, phi)] if m.is_positive: zz = (Ynm(n, m, th, ph) + Ynm_c(n, m, th, ph)) / sqrt(2) return zz elif m.is_zero: return Ynm(n, m, th, ph) elif m.is_negative: zz = (Ynm(n, m, th, ph) - Ynm_c(n, m, th, ph)) / (sqrt(2)*I) return zz sympy-sympy-1.9/sympy/functions/special/tensor_functions.py000066400000000000000000000307161412543434000245170ustar00rootroot00000000000000from sympy.core import S, Integer from sympy.core.compatibility import SYMPY_INTS from sympy.core.function import Function from sympy.core.logic import fuzzy_not from sympy.core.mul import prod from sympy.utilities.iterables import (has_dups, default_sort_key) ############################################################################### ###################### Kronecker Delta, Levi-Civita etc. ###################### ############################################################################### def Eijk(*args, **kwargs): """ Represent the Levi-Civita symbol. This is a compatibility wrapper to ``LeviCivita()``. See Also ======== LeviCivita """ return LeviCivita(*args, **kwargs) def eval_levicivita(*args): """Evaluate Levi-Civita symbol.""" from sympy import factorial n = len(args) return prod( prod(args[j] - args[i] for j in range(i + 1, n)) / factorial(i) for i in range(n)) # converting factorial(i) to int is slightly faster class LeviCivita(Function): """ Represent the Levi-Civita symbol. Explanation =========== For even permutations of indices it returns 1, for odd permutations -1, and for everything else (a repeated index) it returns 0. Thus it represents an alternating pseudotensor. Examples ======== >>> from sympy import LeviCivita >>> from sympy.abc import i, j, k >>> LeviCivita(1, 2, 3) 1 >>> LeviCivita(1, 3, 2) -1 >>> LeviCivita(1, 2, 2) 0 >>> LeviCivita(i, j, k) LeviCivita(i, j, k) >>> LeviCivita(i, j, i) 0 See Also ======== Eijk """ is_integer = True @classmethod def eval(cls, *args): if all(isinstance(a, (SYMPY_INTS, Integer)) for a in args): return eval_levicivita(*args) if has_dups(args): return S.Zero def doit(self): return eval_levicivita(*self.args) class KroneckerDelta(Function): """ The discrete, or Kronecker, delta function. Explanation =========== A function that takes in two integers $i$ and $j$. It returns $0$ if $i$ and $j$ are not equal, or it returns $1$ if $i$ and $j$ are equal. Examples ======== An example with integer indices: >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> KroneckerDelta(1, 2) 0 >>> KroneckerDelta(3, 3) 1 Symbolic indices: >>> from sympy.abc import i, j, k >>> KroneckerDelta(i, j) KroneckerDelta(i, j) >>> KroneckerDelta(i, i) 1 >>> KroneckerDelta(i, i + 1) 0 >>> KroneckerDelta(i, i + 1 + k) KroneckerDelta(i, i + k + 1) Parameters ========== i : Number, Symbol The first index of the delta function. j : Number, Symbol The second index of the delta function. See Also ======== eval DiracDelta References ========== .. [1] https://en.wikipedia.org/wiki/Kronecker_delta """ is_integer = True @classmethod def eval(cls, i, j, delta_range=None): """ Evaluates the discrete delta function. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy.abc import i, j, k >>> KroneckerDelta(i, j) KroneckerDelta(i, j) >>> KroneckerDelta(i, i) 1 >>> KroneckerDelta(i, i + 1) 0 >>> KroneckerDelta(i, i + 1 + k) KroneckerDelta(i, i + k + 1) # indirect doctest """ if delta_range is not None: dinf, dsup = delta_range if (dinf - i > 0) == True: return S.Zero if (dinf - j > 0) == True: return S.Zero if (dsup - i < 0) == True: return S.Zero if (dsup - j < 0) == True: return S.Zero diff = i - j if diff.is_zero: return S.One elif fuzzy_not(diff.is_zero): return S.Zero if i.assumptions0.get("below_fermi") and \ j.assumptions0.get("above_fermi"): return S.Zero if j.assumptions0.get("below_fermi") and \ i.assumptions0.get("above_fermi"): return S.Zero # to make KroneckerDelta canonical # following lines will check if inputs are in order # if not, will return KroneckerDelta with correct order if i != min(i, j, key=default_sort_key): if delta_range: return cls(j, i, delta_range) else: return cls(j, i) @property def delta_range(self): if len(self.args) > 2: return self.args[2] def _eval_power(self, expt): if expt.is_positive: return self if expt.is_negative and not -expt is S.One: return 1/self @property def is_above_fermi(self): """ True if Delta can be non-zero above fermi. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy import Symbol >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> q = Symbol('q') >>> KroneckerDelta(p, a).is_above_fermi True >>> KroneckerDelta(p, i).is_above_fermi False >>> KroneckerDelta(p, q).is_above_fermi True See Also ======== is_below_fermi, is_only_below_fermi, is_only_above_fermi """ if self.args[0].assumptions0.get("below_fermi"): return False if self.args[1].assumptions0.get("below_fermi"): return False return True @property def is_below_fermi(self): """ True if Delta can be non-zero below fermi. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy import Symbol >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> q = Symbol('q') >>> KroneckerDelta(p, a).is_below_fermi False >>> KroneckerDelta(p, i).is_below_fermi True >>> KroneckerDelta(p, q).is_below_fermi True See Also ======== is_above_fermi, is_only_above_fermi, is_only_below_fermi """ if self.args[0].assumptions0.get("above_fermi"): return False if self.args[1].assumptions0.get("above_fermi"): return False return True @property def is_only_above_fermi(self): """ True if Delta is restricted to above fermi. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy import Symbol >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> q = Symbol('q') >>> KroneckerDelta(p, a).is_only_above_fermi True >>> KroneckerDelta(p, q).is_only_above_fermi False >>> KroneckerDelta(p, i).is_only_above_fermi False See Also ======== is_above_fermi, is_below_fermi, is_only_below_fermi """ return ( self.args[0].assumptions0.get("above_fermi") or self.args[1].assumptions0.get("above_fermi") ) or False @property def is_only_below_fermi(self): """ True if Delta is restricted to below fermi. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy import Symbol >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> q = Symbol('q') >>> KroneckerDelta(p, i).is_only_below_fermi True >>> KroneckerDelta(p, q).is_only_below_fermi False >>> KroneckerDelta(p, a).is_only_below_fermi False See Also ======== is_above_fermi, is_below_fermi, is_only_above_fermi """ return ( self.args[0].assumptions0.get("below_fermi") or self.args[1].assumptions0.get("below_fermi") ) or False @property def indices_contain_equal_information(self): """ Returns True if indices are either both above or below fermi. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy import Symbol >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> q = Symbol('q') >>> KroneckerDelta(p, q).indices_contain_equal_information True >>> KroneckerDelta(p, q+1).indices_contain_equal_information True >>> KroneckerDelta(i, p).indices_contain_equal_information False """ if (self.args[0].assumptions0.get("below_fermi") and self.args[1].assumptions0.get("below_fermi")): return True if (self.args[0].assumptions0.get("above_fermi") and self.args[1].assumptions0.get("above_fermi")): return True # if both indices are general we are True, else false return self.is_below_fermi and self.is_above_fermi @property def preferred_index(self): """ Returns the index which is preferred to keep in the final expression. Explanation =========== The preferred index is the index with more information regarding fermi level. If indices contain the same information, 'a' is preferred before 'b'. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy import Symbol >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> j = Symbol('j', below_fermi=True) >>> p = Symbol('p') >>> KroneckerDelta(p, i).preferred_index i >>> KroneckerDelta(p, a).preferred_index a >>> KroneckerDelta(i, j).preferred_index i See Also ======== killable_index """ if self._get_preferred_index(): return self.args[1] else: return self.args[0] @property def killable_index(self): """ Returns the index which is preferred to substitute in the final expression. Explanation =========== The index to substitute is the index with less information regarding fermi level. If indices contain the same information, 'a' is preferred before 'b'. Examples ======== >>> from sympy.functions.special.tensor_functions import KroneckerDelta >>> from sympy import Symbol >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> j = Symbol('j', below_fermi=True) >>> p = Symbol('p') >>> KroneckerDelta(p, i).killable_index p >>> KroneckerDelta(p, a).killable_index p >>> KroneckerDelta(i, j).killable_index j See Also ======== preferred_index """ if self._get_preferred_index(): return self.args[0] else: return self.args[1] def _get_preferred_index(self): """ Returns the index which is preferred to keep in the final expression. The preferred index is the index with more information regarding fermi level. If indices contain the same information, index 0 is returned. """ if not self.is_above_fermi: if self.args[0].assumptions0.get("below_fermi"): return 0 else: return 1 elif not self.is_below_fermi: if self.args[0].assumptions0.get("above_fermi"): return 0 else: return 1 else: return 0 @property def indices(self): return self.args[0:2] def _eval_rewrite_as_Piecewise(self, *args, **kwargs): from sympy.functions.elementary.piecewise import Piecewise from sympy.core.relational import Ne i, j = args return Piecewise((0, Ne(i, j)), (1, True)) sympy-sympy-1.9/sympy/functions/special/tests/000077500000000000000000000000001412543434000216765ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/special/tests/__init__.py000066400000000000000000000000001412543434000237750ustar00rootroot00000000000000sympy-sympy-1.9/sympy/functions/special/tests/test_bessel.py000066400000000000000000000730361412543434000245750ustar00rootroot00000000000000from itertools import product from sympy import (jn, yn, symbols, Symbol, sin, cos, pi, S, jn_zeros, besselj, bessely, besseli, besselk, hankel1, hankel2, hn1, hn2, expand_func, sqrt, sinh, cosh, diff, series, gamma, hyper, I, O, oo, conjugate, uppergamma, exp, Integral, Sum, Rational, log, polar_lift, exp_polar) from sympy.functions.special.bessel import fn from sympy.functions.special.bessel import (airyai, airybi, airyaiprime, airybiprime, marcumq) from sympy.testing.randtest import (random_complex_number as randcplx, verify_numerically as tn, test_derivative_numerically as td, _randint) from sympy.simplify import besselsimp from sympy.testing.pytest import raises, slow from sympy.abc import z, n, k, x randint = _randint() def test_bessel_rand(): for f in [besselj, bessely, besseli, besselk, hankel1, hankel2]: assert td(f(randcplx(), z), z) for f in [jn, yn, hn1, hn2]: assert td(f(randint(-10, 10), z), z) def test_bessel_twoinputs(): for f in [besselj, bessely, besseli, besselk, hankel1, hankel2, jn, yn]: raises(TypeError, lambda: f(1)) raises(TypeError, lambda: f(1, 2, 3)) def test_besselj_leading_term(): assert besselj(0, x).as_leading_term(x) == 1 assert besselj(1, sin(x)).as_leading_term(x) == x/2 assert besselj(1, 2*sqrt(x)).as_leading_term(x) == sqrt(x) # https://github.com/sympy/sympy/issues/21701 assert (besselj(z, x)/x**z).as_leading_term(x) == 1/(2**z*gamma(z + 1)) def test_bessely_leading_term(): assert bessely(0, x).as_leading_term(x) == (2*log(x) - 2*log(2))/pi assert bessely(1, sin(x)).as_leading_term(x) == (x*log(x) - x*log(2))/pi assert bessely(1, 2*sqrt(x)).as_leading_term(x) == sqrt(x)*log(x)/pi def test_besselj_series(): assert besselj(0, x).series(x) == 1 - x**2/4 + x**4/64 + O(x**6) assert besselj(0, x**(1.1)).series(x) == 1 + x**4.4/64 - x**2.2/4 + O(x**6) assert besselj(0, x**2 + x).series(x) == 1 - x**2/4 - x**3/2\ - 15*x**4/64 + x**5/16 + O(x**6) assert besselj(0, sqrt(x) + x).series(x, n=4) == 1 - x/4 - 15*x**2/64\ + 215*x**3/2304 - x**Rational(3, 2)/2 + x**Rational(5, 2)/16\ + 23*x**Rational(7, 2)/384 + O(x**4) assert besselj(0, x/(1 - x)).series(x) == 1 - x**2/4 - x**3/2 - 47*x**4/64\ - 15*x**5/16 + O(x**6) assert besselj(0, log(1 + x)).series(x) == 1 - x**2/4 + x**3/4\ - 41*x**4/192 + 17*x**5/96 + O(x**6) assert besselj(1, sin(x)).series(x) == x/2 - 7*x**3/48 + 73*x**5/1920 + O(x**6) assert besselj(1, 2*sqrt(x)).series(x) == sqrt(x) - x**Rational(3, 2)/2\ + x**Rational(5, 2)/12 - x**Rational(7, 2)/144 + x**Rational(9, 2)/2880\ - x**Rational(11, 2)/86400 + O(x**6) assert besselj(-2, sin(x)).series(x, n=4) == besselj(2, sin(x)).series(x, n=4) def test_bessely_series(): const = 2*S.EulerGamma/pi - 2*log(2)/pi + 2*log(x)/pi assert bessely(0, x).series(x, n=4) == const + x**2*(-log(x)/(2*pi)\ + (2 - 2*S.EulerGamma)/(4*pi) + log(2)/(2*pi)) + O(x**4*log(x)) assert bessely(0, x**(1.1)).series(x, n=4) == 2*S.EulerGamma/pi\ - 2*log(2)/pi + 2.2*log(x)/pi + x**2.2*(-0.55*log(x)/pi\ + (2 - 2*S.EulerGamma)/(4*pi) + log(2)/(2*pi)) + O(x**4*log(x)) assert bessely(0, x**2 + x).series(x, n=4) == \ const - (2 - 2*S.EulerGamma)*(-x**3/(2*pi) - x**2/(4*pi)) + 2*x/pi\ + x**2*(-log(x)/(2*pi) - 1/pi + log(2)/(2*pi))\ + x**3*(-log(x)/pi + 1/(6*pi) + log(2)/pi) + O(x**4*log(x)) assert bessely(0, x/(1 - x)).series(x, n=3) == const\ + 2*x/pi + x**2*(-log(x)/(2*pi) + (2 - 2*S.EulerGamma)/(4*pi)\ + log(2)/(2*pi) + 1/pi) + O(x**3*log(x)) assert bessely(0, log(1 + x)).series(x, n=3) == const\ - x/pi + x**2*(-log(x)/(2*pi) + (2 - 2*S.EulerGamma)/(4*pi)\ + log(2)/(2*pi) + 5/(12*pi)) + O(x**3*log(x)) assert bessely(1, sin(x)).series(x, n=4) == -(1/pi)*(1 - 2*S.EulerGamma)\ * (-x**3/12 + x/2) + x*(log(x)/pi - log(2)/pi) + x**3*(-7*log(x)\ / (24*pi) - 1/(6*pi) + (Rational(5, 2) - 2*S.EulerGamma)/(16*pi)\ + 7*log(2)/(24*pi)) + O(x**4*log(x)) assert bessely(1, 2*sqrt(x)).series(x, n=3) == sqrt(x)*(log(x)/pi \ - (1 - 2*S.EulerGamma)/pi) + x**Rational(3, 2)*(-log(x)/(2*pi)\ + (Rational(5, 2) - 2*S.EulerGamma)/(2*pi))\ + x**Rational(5, 2)*(log(x)/(12*pi)\ - (Rational(10, 3) - 2*S.EulerGamma)/(12*pi)) + O(x**3*log(x)) assert bessely(-2, sin(x)).series(x, n=4) == bessely(2, sin(x)).series(x, n=4) def test_diff(): assert besselj(n, z).diff(z) == besselj(n - 1, z)/2 - besselj(n + 1, z)/2 assert bessely(n, z).diff(z) == bessely(n - 1, z)/2 - bessely(n + 1, z)/2 assert besseli(n, z).diff(z) == besseli(n - 1, z)/2 + besseli(n + 1, z)/2 assert besselk(n, z).diff(z) == -besselk(n - 1, z)/2 - besselk(n + 1, z)/2 assert hankel1(n, z).diff(z) == hankel1(n - 1, z)/2 - hankel1(n + 1, z)/2 assert hankel2(n, z).diff(z) == hankel2(n - 1, z)/2 - hankel2(n + 1, z)/2 def test_rewrite(): assert besselj(n, z).rewrite(jn) == sqrt(2*z/pi)*jn(n - S.Half, z) assert bessely(n, z).rewrite(yn) == sqrt(2*z/pi)*yn(n - S.Half, z) assert besseli(n, z).rewrite(besselj) == \ exp(-I*n*pi/2)*besselj(n, polar_lift(I)*z) assert besselj(n, z).rewrite(besseli) == \ exp(I*n*pi/2)*besseli(n, polar_lift(-I)*z) nu = randcplx() assert tn(besselj(nu, z), besselj(nu, z).rewrite(besseli), z) assert tn(besselj(nu, z), besselj(nu, z).rewrite(bessely), z) assert tn(besseli(nu, z), besseli(nu, z).rewrite(besselj), z) assert tn(besseli(nu, z), besseli(nu, z).rewrite(bessely), z) assert tn(bessely(nu, z), bessely(nu, z).rewrite(besselj), z) assert tn(bessely(nu, z), bessely(nu, z).rewrite(besseli), z) assert tn(besselk(nu, z), besselk(nu, z).rewrite(besselj), z) assert tn(besselk(nu, z), besselk(nu, z).rewrite(besseli), z) assert tn(besselk(nu, z), besselk(nu, z).rewrite(bessely), z) # check that a rewrite was triggered, when the order is set to a generic # symbol 'nu' assert yn(nu, z) != yn(nu, z).rewrite(jn) assert hn1(nu, z) != hn1(nu, z).rewrite(jn) assert hn2(nu, z) != hn2(nu, z).rewrite(jn) assert jn(nu, z) != jn(nu, z).rewrite(yn) assert hn1(nu, z) != hn1(nu, z).rewrite(yn) assert hn2(nu, z) != hn2(nu, z).rewrite(yn) # rewriting spherical bessel functions (SBFs) w.r.t. besselj, bessely is # not allowed if a generic symbol 'nu' is used as the order of the SBFs # to avoid inconsistencies (the order of bessel[jy] is allowed to be # complex-valued, whereas SBFs are defined only for integer orders) order = nu for f in (besselj, bessely): assert hn1(order, z) == hn1(order, z).rewrite(f) assert hn2(order, z) == hn2(order, z).rewrite(f) assert jn(order, z).rewrite(besselj) == sqrt(2)*sqrt(pi)*sqrt(1/z)*besselj(order + S.Half, z)/2 assert jn(order, z).rewrite(bessely) == (-1)**nu*sqrt(2)*sqrt(pi)*sqrt(1/z)*bessely(-order - S.Half, z)/2 # for integral orders rewriting SBFs w.r.t bessel[jy] is allowed N = Symbol('n', integer=True) ri = randint(-11, 10) for order in (ri, N): for f in (besselj, bessely): assert yn(order, z) != yn(order, z).rewrite(f) assert jn(order, z) != jn(order, z).rewrite(f) assert hn1(order, z) != hn1(order, z).rewrite(f) assert hn2(order, z) != hn2(order, z).rewrite(f) for func, refunc in product((yn, jn, hn1, hn2), (jn, yn, besselj, bessely)): assert tn(func(ri, z), func(ri, z).rewrite(refunc), z) def test_expand(): assert expand_func(besselj(S.Half, z).rewrite(jn)) == \ sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z)) assert expand_func(bessely(S.Half, z).rewrite(yn)) == \ -sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z)) # XXX: teach sin/cos to work around arguments like # x*exp_polar(I*pi*n/2). Then change besselsimp -> expand_func assert besselsimp(besselj(S.Half, z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z)) assert besselsimp(besselj(Rational(-1, 2), z)) == sqrt(2)*cos(z)/(sqrt(pi)*sqrt(z)) assert besselsimp(besselj(Rational(5, 2), z)) == \ -sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**Rational(5, 2)) assert besselsimp(besselj(Rational(-5, 2), z)) == \ -sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**Rational(5, 2)) assert besselsimp(bessely(S.Half, z)) == \ -(sqrt(2)*cos(z))/(sqrt(pi)*sqrt(z)) assert besselsimp(bessely(Rational(-1, 2), z)) == sqrt(2)*sin(z)/(sqrt(pi)*sqrt(z)) assert besselsimp(bessely(Rational(5, 2), z)) == \ sqrt(2)*(z**2*cos(z) - 3*z*sin(z) - 3*cos(z))/(sqrt(pi)*z**Rational(5, 2)) assert besselsimp(bessely(Rational(-5, 2), z)) == \ -sqrt(2)*(z**2*sin(z) + 3*z*cos(z) - 3*sin(z))/(sqrt(pi)*z**Rational(5, 2)) assert besselsimp(besseli(S.Half, z)) == sqrt(2)*sinh(z)/(sqrt(pi)*sqrt(z)) assert besselsimp(besseli(Rational(-1, 2), z)) == \ sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) assert besselsimp(besseli(Rational(5, 2), z)) == \ sqrt(2)*(z**2*sinh(z) - 3*z*cosh(z) + 3*sinh(z))/(sqrt(pi)*z**Rational(5, 2)) assert besselsimp(besseli(Rational(-5, 2), z)) == \ sqrt(2)*(z**2*cosh(z) - 3*z*sinh(z) + 3*cosh(z))/(sqrt(pi)*z**Rational(5, 2)) assert besselsimp(besselk(S.Half, z)) == \ besselsimp(besselk(Rational(-1, 2), z)) == sqrt(pi)*exp(-z)/(sqrt(2)*sqrt(z)) assert besselsimp(besselk(Rational(5, 2), z)) == \ besselsimp(besselk(Rational(-5, 2), z)) == \ sqrt(2)*sqrt(pi)*(z**2 + 3*z + 3)*exp(-z)/(2*z**Rational(5, 2)) n = Symbol('n', integer=True, positive=True) assert expand_func(besseli(n + 2, z)) == \ besseli(n, z) + (-2*n - 2)*(-2*n*besseli(n, z)/z + besseli(n - 1, z))/z assert expand_func(besselj(n + 2, z)) == \ -besselj(n, z) + (2*n + 2)*(2*n*besselj(n, z)/z - besselj(n - 1, z))/z assert expand_func(besselk(n + 2, z)) == \ besselk(n, z) + (2*n + 2)*(2*n*besselk(n, z)/z + besselk(n - 1, z))/z assert expand_func(bessely(n + 2, z)) == \ -bessely(n, z) + (2*n + 2)*(2*n*bessely(n, z)/z - bessely(n - 1, z))/z assert expand_func(besseli(n + S.Half, z).rewrite(jn)) == \ (sqrt(2)*sqrt(z)*exp(-I*pi*(n + S.Half)/2) * exp_polar(I*pi/4)*jn(n, z*exp_polar(I*pi/2))/sqrt(pi)) assert expand_func(besselj(n + S.Half, z).rewrite(jn)) == \ sqrt(2)*sqrt(z)*jn(n, z)/sqrt(pi) r = Symbol('r', real=True) p = Symbol('p', positive=True) i = Symbol('i', integer=True) for besselx in [besselj, bessely, besseli, besselk]: assert besselx(i, p).is_extended_real is True assert besselx(i, x).is_extended_real is None assert besselx(x, z).is_extended_real is None for besselx in [besselj, besseli]: assert besselx(i, r).is_extended_real is True for besselx in [bessely, besselk]: assert besselx(i, r).is_extended_real is None for besselx in [besselj, bessely, besseli, besselk]: assert expand_func(besselx(oo, x)) == besselx(oo, x, evaluate=False) assert expand_func(besselx(-oo, x)) == besselx(-oo, x, evaluate=False) @slow def test_slow_expand(): def check(eq, ans): return tn(eq, ans) and eq == ans rn = randcplx(a=1, b=0, d=0, c=2) for besselx in [besselj, bessely, besseli, besselk]: ri = S(2*randint(-11, 10) + 1) / 2 # half integer in [-21/2, 21/2] assert tn(besselsimp(besselx(ri, z)), besselx(ri, z)) assert check(expand_func(besseli(rn, x)), besseli(rn - 2, x) - 2*(rn - 1)*besseli(rn - 1, x)/x) assert check(expand_func(besseli(-rn, x)), besseli(-rn + 2, x) + 2*(-rn + 1)*besseli(-rn + 1, x)/x) assert check(expand_func(besselj(rn, x)), -besselj(rn - 2, x) + 2*(rn - 1)*besselj(rn - 1, x)/x) assert check(expand_func(besselj(-rn, x)), -besselj(-rn + 2, x) + 2*(-rn + 1)*besselj(-rn + 1, x)/x) assert check(expand_func(besselk(rn, x)), besselk(rn - 2, x) + 2*(rn - 1)*besselk(rn - 1, x)/x) assert check(expand_func(besselk(-rn, x)), besselk(-rn + 2, x) - 2*(-rn + 1)*besselk(-rn + 1, x)/x) assert check(expand_func(bessely(rn, x)), -bessely(rn - 2, x) + 2*(rn - 1)*bessely(rn - 1, x)/x) assert check(expand_func(bessely(-rn, x)), -bessely(-rn + 2, x) + 2*(-rn + 1)*bessely(-rn + 1, x)/x) def test_fn(): x, z = symbols("x z") assert fn(1, z) == 1/z**2 assert fn(2, z) == -1/z + 3/z**3 assert fn(3, z) == -6/z**2 + 15/z**4 assert fn(4, z) == 1/z - 45/z**3 + 105/z**5 def mjn(n, z): return expand_func(jn(n, z)) def myn(n, z): return expand_func(yn(n, z)) def test_jn(): z = symbols("z") assert jn(0, 0) == 1 assert jn(1, 0) == 0 assert jn(-1, 0) == S.ComplexInfinity assert jn(z, 0) == jn(z, 0, evaluate=False) assert jn(0, oo) == 0 assert jn(0, -oo) == 0 assert mjn(0, z) == sin(z)/z assert mjn(1, z) == sin(z)/z**2 - cos(z)/z assert mjn(2, z) == (3/z**3 - 1/z)*sin(z) - (3/z**2) * cos(z) assert mjn(3, z) == (15/z**4 - 6/z**2)*sin(z) + (1/z - 15/z**3)*cos(z) assert mjn(4, z) == (1/z + 105/z**5 - 45/z**3)*sin(z) + \ (-105/z**4 + 10/z**2)*cos(z) assert mjn(5, z) == (945/z**6 - 420/z**4 + 15/z**2)*sin(z) + \ (-1/z - 945/z**5 + 105/z**3)*cos(z) assert mjn(6, z) == (-1/z + 10395/z**7 - 4725/z**5 + 210/z**3)*sin(z) + \ (-10395/z**6 + 1260/z**4 - 21/z**2)*cos(z) assert expand_func(jn(n, z)) == jn(n, z) # SBFs not defined for complex-valued orders assert jn(2+3j, 5.2+0.3j).evalf() == jn(2+3j, 5.2+0.3j) assert eq([jn(2, 5.2+0.3j).evalf(10)], [0.09941975672 - 0.05452508024*I]) def test_yn(): z = symbols("z") assert myn(0, z) == -cos(z)/z assert myn(1, z) == -cos(z)/z**2 - sin(z)/z assert myn(2, z) == -((3/z**3 - 1/z)*cos(z) + (3/z**2)*sin(z)) assert expand_func(yn(n, z)) == yn(n, z) # SBFs not defined for complex-valued orders assert yn(2+3j, 5.2+0.3j).evalf() == yn(2+3j, 5.2+0.3j) assert eq([yn(2, 5.2+0.3j).evalf(10)], [0.185250342 + 0.01489557397*I]) def test_sympify_yn(): assert S(15) in myn(3, pi).atoms() assert myn(3, pi) == 15/pi**4 - 6/pi**2 def eq(a, b, tol=1e-6): for u, v in zip(a, b): if not (abs(u - v) < tol): return False return True def test_jn_zeros(): assert eq(jn_zeros(0, 4), [3.141592, 6.283185, 9.424777, 12.566370]) assert eq(jn_zeros(1, 4), [4.493409, 7.725251, 10.904121, 14.066193]) assert eq(jn_zeros(2, 4), [5.763459, 9.095011, 12.322940, 15.514603]) assert eq(jn_zeros(3, 4), [6.987932, 10.417118, 13.698023, 16.923621]) assert eq(jn_zeros(4, 4), [8.182561, 11.704907, 15.039664, 18.301255]) def test_bessel_eval(): n, m, k = Symbol('n', integer=True), Symbol('m'), Symbol('k', integer=True, zero=False) for f in [besselj, besseli]: assert f(0, 0) is S.One assert f(2.1, 0) is S.Zero assert f(-3, 0) is S.Zero assert f(-10.2, 0) is S.ComplexInfinity assert f(1 + 3*I, 0) is S.Zero assert f(-3 + I, 0) is S.ComplexInfinity assert f(-2*I, 0) is S.NaN assert f(n, 0) != S.One and f(n, 0) != S.Zero assert f(m, 0) != S.One and f(m, 0) != S.Zero assert f(k, 0) is S.Zero assert bessely(0, 0) is S.NegativeInfinity assert besselk(0, 0) is S.Infinity for f in [bessely, besselk]: assert f(1 + I, 0) is S.ComplexInfinity assert f(I, 0) is S.NaN for f in [besselj, bessely]: assert f(m, S.Infinity) is S.Zero assert f(m, S.NegativeInfinity) is S.Zero for f in [besseli, besselk]: assert f(m, I*S.Infinity) is S.Zero assert f(m, I*S.NegativeInfinity) is S.Zero for f in [besseli, besselk]: assert f(-4, z) == f(4, z) assert f(-3, z) == f(3, z) assert f(-n, z) == f(n, z) assert f(-m, z) != f(m, z) for f in [besselj, bessely]: assert f(-4, z) == f(4, z) assert f(-3, z) == -f(3, z) assert f(-n, z) == (-1)**n*f(n, z) assert f(-m, z) != (-1)**m*f(m, z) for f in [besselj, besseli]: assert f(m, -z) == (-z)**m*z**(-m)*f(m, z) assert besseli(2, -z) == besseli(2, z) assert besseli(3, -z) == -besseli(3, z) assert besselj(0, -z) == besselj(0, z) assert besselj(1, -z) == -besselj(1, z) assert besseli(0, I*z) == besselj(0, z) assert besseli(1, I*z) == I*besselj(1, z) assert besselj(3, I*z) == -I*besseli(3, z) def test_bessel_nan(): # FIXME: could have these return NaN; for now just fix infinite recursion for f in [besselj, bessely, besseli, besselk, hankel1, hankel2, yn, jn]: assert f(1, S.NaN) == f(1, S.NaN, evaluate=False) def test_meromorphic(): assert besselj(2, x).is_meromorphic(x, 1) == True assert besselj(2, x).is_meromorphic(x, 0) == True assert besselj(2, x).is_meromorphic(x, oo) == False assert besselj(S(2)/3, x).is_meromorphic(x, 1) == True assert besselj(S(2)/3, x).is_meromorphic(x, 0) == False assert besselj(S(2)/3, x).is_meromorphic(x, oo) == False assert besselj(x, 2*x).is_meromorphic(x, 2) == False assert besselk(0, x).is_meromorphic(x, 1) == True assert besselk(2, x).is_meromorphic(x, 0) == True assert besseli(0, x).is_meromorphic(x, 1) == True assert besseli(2, x).is_meromorphic(x, 0) == True assert bessely(0, x).is_meromorphic(x, 1) == True assert bessely(0, x).is_meromorphic(x, 0) == False assert bessely(2, x).is_meromorphic(x, 0) == True assert hankel1(3, x**2 + 2*x).is_meromorphic(x, 1) == True assert hankel1(0, x).is_meromorphic(x, 0) == False assert hankel2(11, 4).is_meromorphic(x, 5) == True assert hn1(6, 7*x**3 + 4).is_meromorphic(x, 7) == True assert hn2(3, 2*x).is_meromorphic(x, 9) == True assert jn(5, 2*x + 7).is_meromorphic(x, 4) == True assert yn(8, x**2 + 11).is_meromorphic(x, 6) == True def test_conjugate(): n = Symbol('n') z = Symbol('z', extended_real=False) x = Symbol('x', extended_real=True) y = Symbol('y', real=True, positive=True) t = Symbol('t', negative=True) for f in [besseli, besselj, besselk, bessely, hankel1, hankel2]: assert f(n, -1).conjugate() != f(conjugate(n), -1) assert f(n, x).conjugate() != f(conjugate(n), x) assert f(n, t).conjugate() != f(conjugate(n), t) rz = randcplx(b=0.5) for f in [besseli, besselj, besselk, bessely]: assert f(n, 1 + I).conjugate() == f(conjugate(n), 1 - I) assert f(n, 0).conjugate() == f(conjugate(n), 0) assert f(n, 1).conjugate() == f(conjugate(n), 1) assert f(n, z).conjugate() == f(conjugate(n), conjugate(z)) assert f(n, y).conjugate() == f(conjugate(n), y) assert tn(f(n, rz).conjugate(), f(conjugate(n), conjugate(rz))) assert hankel1(n, 1 + I).conjugate() == hankel2(conjugate(n), 1 - I) assert hankel1(n, 0).conjugate() == hankel2(conjugate(n), 0) assert hankel1(n, 1).conjugate() == hankel2(conjugate(n), 1) assert hankel1(n, y).conjugate() == hankel2(conjugate(n), y) assert hankel1(n, z).conjugate() == hankel2(conjugate(n), conjugate(z)) assert tn(hankel1(n, rz).conjugate(), hankel2(conjugate(n), conjugate(rz))) assert hankel2(n, 1 + I).conjugate() == hankel1(conjugate(n), 1 - I) assert hankel2(n, 0).conjugate() == hankel1(conjugate(n), 0) assert hankel2(n, 1).conjugate() == hankel1(conjugate(n), 1) assert hankel2(n, y).conjugate() == hankel1(conjugate(n), y) assert hankel2(n, z).conjugate() == hankel1(conjugate(n), conjugate(z)) assert tn(hankel2(n, rz).conjugate(), hankel1(conjugate(n), conjugate(rz))) def test_branching(): assert besselj(polar_lift(k), x) == besselj(k, x) assert besseli(polar_lift(k), x) == besseli(k, x) n = Symbol('n', integer=True) assert besselj(n, exp_polar(2*pi*I)*x) == besselj(n, x) assert besselj(n, polar_lift(x)) == besselj(n, x) assert besseli(n, exp_polar(2*pi*I)*x) == besseli(n, x) assert besseli(n, polar_lift(x)) == besseli(n, x) def tn(func, s): from random import uniform c = uniform(1, 5) expr = func(s, c*exp_polar(I*pi)) - func(s, c*exp_polar(-I*pi)) eps = 1e-15 expr2 = func(s + eps, -c + eps*I) - func(s + eps, -c - eps*I) return abs(expr.n() - expr2.n()).n() < 1e-10 nu = Symbol('nu') assert besselj(nu, exp_polar(2*pi*I)*x) == exp(2*pi*I*nu)*besselj(nu, x) assert besseli(nu, exp_polar(2*pi*I)*x) == exp(2*pi*I*nu)*besseli(nu, x) assert tn(besselj, 2) assert tn(besselj, pi) assert tn(besselj, I) assert tn(besseli, 2) assert tn(besseli, pi) assert tn(besseli, I) def test_airy_base(): z = Symbol('z') x = Symbol('x', real=True) y = Symbol('y', real=True) assert conjugate(airyai(z)) == airyai(conjugate(z)) assert airyai(x).is_extended_real assert airyai(x+I*y).as_real_imag() == ( airyai(x - I*y)/2 + airyai(x + I*y)/2, I*(airyai(x - I*y) - airyai(x + I*y))/2) def test_airyai(): z = Symbol('z', real=False) t = Symbol('t', negative=True) p = Symbol('p', positive=True) assert isinstance(airyai(z), airyai) assert airyai(0) == 3**Rational(1, 3)/(3*gamma(Rational(2, 3))) assert airyai(oo) == 0 assert airyai(-oo) == 0 assert diff(airyai(z), z) == airyaiprime(z) assert series(airyai(z), z, 0, 3) == ( 3**Rational(5, 6)*gamma(Rational(1, 3))/(6*pi) - 3**Rational(1, 6)*z*gamma(Rational(2, 3))/(2*pi) + O(z**3)) assert airyai(z).rewrite(hyper) == ( -3**Rational(2, 3)*z*hyper((), (Rational(4, 3),), z**3/9)/(3*gamma(Rational(1, 3))) + 3**Rational(1, 3)*hyper((), (Rational(2, 3),), z**3/9)/(3*gamma(Rational(2, 3)))) assert isinstance(airyai(z).rewrite(besselj), airyai) assert airyai(t).rewrite(besselj) == ( sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) + besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3) assert airyai(z).rewrite(besseli) == ( -z*besseli(Rational(1, 3), 2*z**Rational(3, 2)/3)/(3*(z**Rational(3, 2))**Rational(1, 3)) + (z**Rational(3, 2))**Rational(1, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3)/3) assert airyai(p).rewrite(besseli) == ( sqrt(p)*(besseli(Rational(-1, 3), 2*p**Rational(3, 2)/3) - besseli(Rational(1, 3), 2*p**Rational(3, 2)/3))/3) assert expand_func(airyai(2*(3*z**5)**Rational(1, 3))) == ( -sqrt(3)*(-1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airybi(2*3**Rational(1, 3)*z**Rational(5, 3))/6 + (1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airyai(2*3**Rational(1, 3)*z**Rational(5, 3))/2) def test_airybi(): z = Symbol('z', real=False) t = Symbol('t', negative=True) p = Symbol('p', positive=True) assert isinstance(airybi(z), airybi) assert airybi(0) == 3**Rational(5, 6)/(3*gamma(Rational(2, 3))) assert airybi(oo) is oo assert airybi(-oo) == 0 assert diff(airybi(z), z) == airybiprime(z) assert series(airybi(z), z, 0, 3) == ( 3**Rational(1, 3)*gamma(Rational(1, 3))/(2*pi) + 3**Rational(2, 3)*z*gamma(Rational(2, 3))/(2*pi) + O(z**3)) assert airybi(z).rewrite(hyper) == ( 3**Rational(1, 6)*z*hyper((), (Rational(4, 3),), z**3/9)/gamma(Rational(1, 3)) + 3**Rational(5, 6)*hyper((), (Rational(2, 3),), z**3/9)/(3*gamma(Rational(2, 3)))) assert isinstance(airybi(z).rewrite(besselj), airybi) assert airyai(t).rewrite(besselj) == ( sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) + besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3) assert airybi(z).rewrite(besseli) == ( sqrt(3)*(z*besseli(Rational(1, 3), 2*z**Rational(3, 2)/3)/(z**Rational(3, 2))**Rational(1, 3) + (z**Rational(3, 2))**Rational(1, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3))/3) assert airybi(p).rewrite(besseli) == ( sqrt(3)*sqrt(p)*(besseli(Rational(-1, 3), 2*p**Rational(3, 2)/3) + besseli(Rational(1, 3), 2*p**Rational(3, 2)/3))/3) assert expand_func(airybi(2*(3*z**5)**Rational(1, 3))) == ( sqrt(3)*(1 - (z**5)**Rational(1, 3)/z**Rational(5, 3))*airyai(2*3**Rational(1, 3)*z**Rational(5, 3))/2 + (1 + (z**5)**Rational(1, 3)/z**Rational(5, 3))*airybi(2*3**Rational(1, 3)*z**Rational(5, 3))/2) def test_airyaiprime(): z = Symbol('z', real=False) t = Symbol('t', negative=True) p = Symbol('p', positive=True) assert isinstance(airyaiprime(z), airyaiprime) assert airyaiprime(0) == -3**Rational(2, 3)/(3*gamma(Rational(1, 3))) assert airyaiprime(oo) == 0 assert diff(airyaiprime(z), z) == z*airyai(z) assert series(airyaiprime(z), z, 0, 3) == ( -3**Rational(2, 3)/(3*gamma(Rational(1, 3))) + 3**Rational(1, 3)*z**2/(6*gamma(Rational(2, 3))) + O(z**3)) assert airyaiprime(z).rewrite(hyper) == ( 3**Rational(1, 3)*z**2*hyper((), (Rational(5, 3),), z**3/9)/(6*gamma(Rational(2, 3))) - 3**Rational(2, 3)*hyper((), (Rational(1, 3),), z**3/9)/(3*gamma(Rational(1, 3)))) assert isinstance(airyaiprime(z).rewrite(besselj), airyaiprime) assert airyai(t).rewrite(besselj) == ( sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) + besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3) assert airyaiprime(z).rewrite(besseli) == ( z**2*besseli(Rational(2, 3), 2*z**Rational(3, 2)/3)/(3*(z**Rational(3, 2))**Rational(2, 3)) - (z**Rational(3, 2))**Rational(2, 3)*besseli(Rational(-1, 3), 2*z**Rational(3, 2)/3)/3) assert airyaiprime(p).rewrite(besseli) == ( p*(-besseli(Rational(-2, 3), 2*p**Rational(3, 2)/3) + besseli(Rational(2, 3), 2*p**Rational(3, 2)/3))/3) assert expand_func(airyaiprime(2*(3*z**5)**Rational(1, 3))) == ( sqrt(3)*(z**Rational(5, 3)/(z**5)**Rational(1, 3) - 1)*airybiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/6 + (z**Rational(5, 3)/(z**5)**Rational(1, 3) + 1)*airyaiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2) def test_airybiprime(): z = Symbol('z', real=False) t = Symbol('t', negative=True) p = Symbol('p', positive=True) assert isinstance(airybiprime(z), airybiprime) assert airybiprime(0) == 3**Rational(1, 6)/gamma(Rational(1, 3)) assert airybiprime(oo) is oo assert airybiprime(-oo) == 0 assert diff(airybiprime(z), z) == z*airybi(z) assert series(airybiprime(z), z, 0, 3) == ( 3**Rational(1, 6)/gamma(Rational(1, 3)) + 3**Rational(5, 6)*z**2/(6*gamma(Rational(2, 3))) + O(z**3)) assert airybiprime(z).rewrite(hyper) == ( 3**Rational(5, 6)*z**2*hyper((), (Rational(5, 3),), z**3/9)/(6*gamma(Rational(2, 3))) + 3**Rational(1, 6)*hyper((), (Rational(1, 3),), z**3/9)/gamma(Rational(1, 3))) assert isinstance(airybiprime(z).rewrite(besselj), airybiprime) assert airyai(t).rewrite(besselj) == ( sqrt(-t)*(besselj(Rational(-1, 3), 2*(-t)**Rational(3, 2)/3) + besselj(Rational(1, 3), 2*(-t)**Rational(3, 2)/3))/3) assert airybiprime(z).rewrite(besseli) == ( sqrt(3)*(z**2*besseli(Rational(2, 3), 2*z**Rational(3, 2)/3)/(z**Rational(3, 2))**Rational(2, 3) + (z**Rational(3, 2))**Rational(2, 3)*besseli(Rational(-2, 3), 2*z**Rational(3, 2)/3))/3) assert airybiprime(p).rewrite(besseli) == ( sqrt(3)*p*(besseli(Rational(-2, 3), 2*p**Rational(3, 2)/3) + besseli(Rational(2, 3), 2*p**Rational(3, 2)/3))/3) assert expand_func(airybiprime(2*(3*z**5)**Rational(1, 3))) == ( sqrt(3)*(z**Rational(5, 3)/(z**5)**Rational(1, 3) - 1)*airyaiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2 + (z**Rational(5, 3)/(z**5)**Rational(1, 3) + 1)*airybiprime(2*3**Rational(1, 3)*z**Rational(5, 3))/2) def test_marcumq(): m = Symbol('m') a = Symbol('a') b = Symbol('b') assert marcumq(0, 0, 0) == 0 assert marcumq(m, 0, b) == uppergamma(m, b**2/2)/gamma(m) assert marcumq(2, 0, 5) == 27*exp(Rational(-25, 2))/2 assert marcumq(0, a, 0) == 1 - exp(-a**2/2) assert marcumq(0, pi, 0) == 1 - exp(-pi**2/2) assert marcumq(1, a, a) == S.Half + exp(-a**2)*besseli(0, a**2)/2 assert marcumq(2, a, a) == S.Half + exp(-a**2)*besseli(0, a**2)/2 + exp(-a**2)*besseli(1, a**2) assert diff(marcumq(1, a, 3), a) == a*(-marcumq(1, a, 3) + marcumq(2, a, 3)) assert diff(marcumq(2, 3, b), b) == -b**2*exp(-b**2/2 - Rational(9, 2))*besseli(1, 3*b)/3 x = Symbol('x') assert marcumq(2, 3, 4).rewrite(Integral, x=x) == \ Integral(x**2*exp(-x**2/2 - Rational(9, 2))*besseli(1, 3*x), (x, 4, oo))/3 assert eq([marcumq(5, -2, 3).rewrite(Integral).evalf(10)], [0.7905769565]) k = Symbol('k') assert marcumq(-3, -5, -7).rewrite(Sum, k=k) == \ exp(-37)*Sum((Rational(5, 7))**k*besseli(k, 35), (k, 4, oo)) assert eq([marcumq(1, 3, 1).rewrite(Sum).evalf(10)], [0.9891705502]) assert marcumq(1, a, a, evaluate=False).rewrite(besseli) == S.Half + exp(-a**2)*besseli(0, a**2)/2 assert marcumq(2, a, a, evaluate=False).rewrite(besseli) == S.Half + exp(-a**2)*besseli(0, a**2)/2 + \ exp(-a**2)*besseli(1, a**2) assert marcumq(3, a, a).rewrite(besseli) == (besseli(1, a**2) + besseli(2, a**2))*exp(-a**2) + \ S.Half + exp(-a**2)*besseli(0, a**2)/2 assert marcumq(5, 8, 8).rewrite(besseli) == exp(-64)*besseli(0, 64)/2 + \ (besseli(4, 64) + besseli(3, 64) + besseli(2, 64) + besseli(1, 64))*exp(-64) + S.Half assert marcumq(m, a, a).rewrite(besseli) == marcumq(m, a, a) x = Symbol('x', integer=True) assert marcumq(x, a, a).rewrite(besseli) == marcumq(x, a, a) sympy-sympy-1.9/sympy/functions/special/tests/test_beta_functions.py000066400000000000000000000046711412543434000263220ustar00rootroot00000000000000from sympy import (symbols, gamma, expand_func, beta, betainc, hyper, diff, conjugate, Integral, Dummy, I, betainc_regularized) from sympy.functions.special.gamma_functions import polygamma from sympy.core.function import ArgumentIndexError from sympy.core.expr import unchanged from sympy.testing.pytest import raises def test_beta(): x, y = symbols('x y') t = Dummy('t') assert unchanged(beta, x, y) assert beta(5, -3).is_real == True assert beta(3, y).is_real is None assert expand_func(beta(x, y)) == gamma(x)*gamma(y)/gamma(x + y) assert expand_func(beta(x, y) - beta(y, x)) == 0 # Symmetric assert expand_func(beta(x, y)) == expand_func(beta(x, y + 1) + beta(x + 1, y)).simplify() assert diff(beta(x, y), x) == beta(x, y)*(polygamma(0, x) - polygamma(0, x + y)) assert diff(beta(x, y), y) == beta(x, y)*(polygamma(0, y) - polygamma(0, x + y)) assert conjugate(beta(x, y)) == beta(conjugate(x), conjugate(y)) raises(ArgumentIndexError, lambda: beta(x, y).fdiff(3)) assert beta(x, y).rewrite(gamma) == gamma(x)*gamma(y)/gamma(x + y) assert beta(x).rewrite(gamma) == gamma(x)**2/gamma(2*x) assert beta(x, y).rewrite(Integral).dummy_eq(Integral(t**(x - 1) * (1 - t)**(y - 1), (t, 0, 1))) def test_betainc(): a, b, x1, x2 = symbols('a b x1 x2') assert unchanged(betainc, a, b, x1, x2) assert unchanged(betainc, a, b, 0, x1) assert betainc(1, 2, 0, -5).is_real == True assert betainc(1, 2, 0, x2).is_real is None assert conjugate(betainc(I, 2, 3 - I, 1 + 4*I)) == betainc(-I, 2, 3 + I, 1 - 4*I) assert betainc(a, b, 0, 1).rewrite(Integral).dummy_eq(beta(a, b).rewrite(Integral)) assert betainc(1, 2, 0, x2).rewrite(hyper) == x2*hyper((1, -1), (2,), x2) assert betainc(1, 2, 3, 3).evalf() == 0 def test_betainc_regularized(): a, b, x1, x2 = symbols('a b x1 x2') assert unchanged(betainc_regularized, a, b, x1, x2) assert unchanged(betainc_regularized, a, b, 0, x1) assert betainc_regularized(3, 5, 0, -1).is_real == True assert betainc_regularized(3, 5, 0, x2).is_real is None assert conjugate(betainc_regularized(3*I, 1, 2 + I, 1 + 2*I)) == betainc_regularized(-3*I, 1, 2 - I, 1 - 2*I) assert betainc_regularized(a, b, 0, 1).rewrite(Integral) == 1 assert betainc_regularized(1, 2, x1, x2).rewrite(hyper) == 2*x2*hyper((1, -1), (2,), x2) - 2*x1*hyper((1, -1), (2,), x1) assert betainc_regularized(4, 1, 5, 5).evalf() == 0 sympy-sympy-1.9/sympy/functions/special/tests/test_bsplines.py000066400000000000000000000154671412543434000251430ustar00rootroot00000000000000from sympy.functions import bspline_basis_set, interpolating_spline from sympy import (Piecewise, Interval, And, symbols, Rational, S) from sympy.testing.pytest import slow x, y = symbols('x,y') def test_basic_degree_0(): d = 0 knots = range(5) splines = bspline_basis_set(d, knots, x) for i in range(len(splines)): assert splines[i] == Piecewise((1, Interval(i, i + 1).contains(x)), (0, True)) def test_basic_degree_1(): d = 1 knots = range(5) splines = bspline_basis_set(d, knots, x) assert splines[0] == Piecewise((x, Interval(0, 1).contains(x)), (2 - x, Interval(1, 2).contains(x)), (0, True)) assert splines[1] == Piecewise((-1 + x, Interval(1, 2).contains(x)), (3 - x, Interval(2, 3).contains(x)), (0, True)) assert splines[2] == Piecewise((-2 + x, Interval(2, 3).contains(x)), (4 - x, Interval(3, 4).contains(x)), (0, True)) def test_basic_degree_2(): d = 2 knots = range(5) splines = bspline_basis_set(d, knots, x) b0 = Piecewise((x**2/2, Interval(0, 1).contains(x)), (Rational(-3, 2) + 3*x - x**2, Interval(1, 2).contains(x)), (Rational(9, 2) - 3*x + x**2/2, Interval(2, 3).contains(x)), (0, True)) b1 = Piecewise((S.Half - x + x**2/2, Interval(1, 2).contains(x)), (Rational(-11, 2) + 5*x - x**2, Interval(2, 3).contains(x)), (8 - 4*x + x**2/2, Interval(3, 4).contains(x)), (0, True)) assert splines[0] == b0 assert splines[1] == b1 def test_basic_degree_3(): d = 3 knots = range(5) splines = bspline_basis_set(d, knots, x) b0 = Piecewise( (x**3/6, Interval(0, 1).contains(x)), (Rational(2, 3) - 2*x + 2*x**2 - x**3/2, Interval(1, 2).contains(x)), (Rational(-22, 3) + 10*x - 4*x**2 + x**3/2, Interval(2, 3).contains(x)), (Rational(32, 3) - 8*x + 2*x**2 - x**3/6, Interval(3, 4).contains(x)), (0, True) ) assert splines[0] == b0 def test_repeated_degree_1(): d = 1 knots = [0, 0, 1, 2, 2, 3, 4, 4] splines = bspline_basis_set(d, knots, x) assert splines[0] == Piecewise((1 - x, Interval(0, 1).contains(x)), (0, True)) assert splines[1] == Piecewise((x, Interval(0, 1).contains(x)), (2 - x, Interval(1, 2).contains(x)), (0, True)) assert splines[2] == Piecewise((-1 + x, Interval(1, 2).contains(x)), (0, True)) assert splines[3] == Piecewise((3 - x, Interval(2, 3).contains(x)), (0, True)) assert splines[4] == Piecewise((-2 + x, Interval(2, 3).contains(x)), (4 - x, Interval(3, 4).contains(x)), (0, True)) assert splines[5] == Piecewise((-3 + x, Interval(3, 4).contains(x)), (0, True)) def test_repeated_degree_2(): d = 2 knots = [0, 0, 1, 2, 2, 3, 4, 4] splines = bspline_basis_set(d, knots, x) assert splines[0] == Piecewise(((-3*x**2/2 + 2*x), And(x <= 1, x >= 0)), (x**2/2 - 2*x + 2, And(x <= 2, x >= 1)), (0, True)) assert splines[1] == Piecewise((x**2/2, And(x <= 1, x >= 0)), (-3*x**2/2 + 4*x - 2, And(x <= 2, x >= 1)), (0, True)) assert splines[2] == Piecewise((x**2 - 2*x + 1, And(x <= 2, x >= 1)), (x**2 - 6*x + 9, And(x <= 3, x >= 2)), (0, True)) assert splines[3] == Piecewise((-3*x**2/2 + 8*x - 10, And(x <= 3, x >= 2)), (x**2/2 - 4*x + 8, And(x <= 4, x >= 3)), (0, True)) assert splines[4] == Piecewise((x**2/2 - 2*x + 2, And(x <= 3, x >= 2)), (-3*x**2/2 + 10*x - 16, And(x <= 4, x >= 3)), (0, True)) # Tests for interpolating_spline def test_10_points_degree_1(): d = 1 X = [-5, 2, 3, 4, 7, 9, 10, 30, 31, 34] Y = [-10, -2, 2, 4, 7, 6, 20, 45, 19, 25] spline = interpolating_spline(d, x, X, Y) assert spline == Piecewise((x*Rational(8, 7) - Rational(30, 7), (x >= -5) & (x <= 2)), (4*x - 10, (x >= 2) & (x <= 3)), (2*x - 4, (x >= 3) & (x <= 4)), (x, (x >= 4) & (x <= 7)), (-x/2 + Rational(21, 2), (x >= 7) & (x <= 9)), (14*x - 120, (x >= 9) & (x <= 10)), (x*Rational(5, 4) + Rational(15, 2), (x >= 10) & (x <= 30)), (-26*x + 825, (x >= 30) & (x <= 31)), (2*x - 43, (x >= 31) & (x <= 34))) def test_3_points_degree_2(): d = 2 X = [-3, 10, 19] Y = [3, -4, 30] spline = interpolating_spline(d, x, X, Y) assert spline == Piecewise((505*x**2/2574 - x*Rational(4921, 2574) - Rational(1931, 429), (x >= -3) & (x <= 19))) def test_5_points_degree_2(): d = 2 X = [-3, 2, 4, 5, 10] Y = [-1, 2, 5, 10, 14] spline = interpolating_spline(d, x, X, Y) assert spline == Piecewise((4*x**2/329 + x*Rational(1007, 1645) + Rational(1196, 1645), (x >= -3) & (x <= 3)), (2701*x**2/1645 - x*Rational(15079, 1645) + Rational(5065, 329), (x >= 3) & (x <= Rational(9, 2))), (-1319*x**2/1645 + x*Rational(21101, 1645) - Rational(11216, 329), (x >= Rational(9, 2)) & (x <= 10))) @slow def test_6_points_degree_3(): d = 3 X = [-1, 0, 2, 3, 9, 12] Y = [-4, 3, 3, 7, 9, 20] spline = interpolating_spline(d, x, X, Y) assert spline == Piecewise((6058*x**3/5301 - 18427*x**2/5301 + x*Rational(12622, 5301) + 3, (x >= -1) & (x <= 2)), (-8327*x**3/5301 + 67883*x**2/5301 - x*Rational(159998, 5301) + Rational(43661, 1767), (x >= 2) & (x <= 3)), (5414*x**3/47709 - 1386*x**2/589 + x*Rational(4267, 279) - Rational(12232, 589), (x >= 3) & (x <= 12))) def test_issue_19262(): Delta = symbols('Delta', positive=True) knots = [i*Delta for i in range(4)] basis = bspline_basis_set(1, knots, x) y = symbols('y', nonnegative=True) basis2 = bspline_basis_set(1, knots, y) assert basis[0].subs(x, y) == basis2[0] assert interpolating_spline(1, x, [Delta*i for i in [1, 2, 4, 7]], [3, 6, 5, 7] ) == Piecewise((3*x/Delta, (Delta <= x) & (x <= 2*Delta)), (7 - x/(2*Delta), (x >= 2*Delta) & (x <= 4*Delta)), (Rational(7, 3) + 2*x/(3*Delta), (x >= 4*Delta) & (x <= 7*Delta))) sympy-sympy-1.9/sympy/functions/special/tests/test_delta_functions.py000066400000000000000000000152661412543434000265020ustar00rootroot00000000000000from sympy import ( adjoint, conjugate, DiracDelta, Heaviside, nan, pi, sign, sqrt, symbols, transpose, Symbol, Piecewise, I, S, Eq, Ne, oo, SingularityFunction, signsimp ) from sympy.testing.pytest import raises, warns_deprecated_sympy from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError x, y = symbols('x y') i = symbols('t', nonzero=True) j = symbols('j', positive=True) k = symbols('k', negative=True) def test_DiracDelta(): assert DiracDelta(1) == 0 assert DiracDelta(5.1) == 0 assert DiracDelta(-pi) == 0 assert DiracDelta(5, 7) == 0 assert DiracDelta(i) == 0 assert DiracDelta(j) == 0 assert DiracDelta(k) == 0 assert DiracDelta(nan) is nan assert DiracDelta(0).func is DiracDelta assert DiracDelta(x).func is DiracDelta # FIXME: this is generally undefined @ x=0 # But then limit(Delta(c)*Heaviside(x),x,-oo) # need's to be implemented. # assert 0*DiracDelta(x) == 0 assert adjoint(DiracDelta(x)) == DiracDelta(x) assert adjoint(DiracDelta(x - y)) == DiracDelta(x - y) assert conjugate(DiracDelta(x)) == DiracDelta(x) assert conjugate(DiracDelta(x - y)) == DiracDelta(x - y) assert transpose(DiracDelta(x)) == DiracDelta(x) assert transpose(DiracDelta(x - y)) == DiracDelta(x - y) assert DiracDelta(x).diff(x) == DiracDelta(x, 1) assert DiracDelta(x, 1).diff(x) == DiracDelta(x, 2) assert DiracDelta(x).is_simple(x) is True assert DiracDelta(3*x).is_simple(x) is True assert DiracDelta(x**2).is_simple(x) is False assert DiracDelta(sqrt(x)).is_simple(x) is False assert DiracDelta(x).is_simple(y) is False assert DiracDelta(x*y).expand(diracdelta=True, wrt=x) == DiracDelta(x)/abs(y) assert DiracDelta(x*y).expand(diracdelta=True, wrt=y) == DiracDelta(y)/abs(x) assert DiracDelta(x**2*y).expand(diracdelta=True, wrt=x) == DiracDelta(x**2*y) assert DiracDelta(y).expand(diracdelta=True, wrt=x) == DiracDelta(y) assert DiracDelta((x - 1)*(x - 2)*(x - 3)).expand(diracdelta=True, wrt=x) == ( DiracDelta(x - 3)/2 + DiracDelta(x - 2) + DiracDelta(x - 1)/2) assert DiracDelta(2*x) != DiracDelta(x) # scaling property assert DiracDelta(x) == DiracDelta(-x) # even function assert DiracDelta(-x, 2) == DiracDelta(x, 2) assert DiracDelta(-x, 1) == -DiracDelta(x, 1) # odd deriv is odd assert DiracDelta(-oo*x) == DiracDelta(oo*x) assert DiracDelta(x - y) != DiracDelta(y - x) assert signsimp(DiracDelta(x - y) - DiracDelta(y - x)) == 0 with warns_deprecated_sympy(): assert DiracDelta(x*y).simplify(x) == DiracDelta(x)/abs(y) with warns_deprecated_sympy(): assert DiracDelta(x*y).simplify(y) == DiracDelta(y)/abs(x) with warns_deprecated_sympy(): assert DiracDelta(x**2*y).simplify(x) == DiracDelta(x**2*y) with warns_deprecated_sympy(): assert DiracDelta(y).simplify(x) == DiracDelta(y) with warns_deprecated_sympy(): assert DiracDelta((x - 1)*(x - 2)*(x - 3)).simplify(x) == ( DiracDelta(x - 3)/2 + DiracDelta(x - 2) + DiracDelta(x - 1)/2) raises(ArgumentIndexError, lambda: DiracDelta(x).fdiff(2)) raises(ValueError, lambda: DiracDelta(x, -1)) raises(ValueError, lambda: DiracDelta(I)) raises(ValueError, lambda: DiracDelta(2 + 3*I)) def test_heaviside(): assert Heaviside(-5) == 0 assert Heaviside(1) == 1 assert Heaviside(0) == S.Half assert Heaviside(0, x) == x assert unchanged(Heaviside,x, nan) assert Heaviside(0, nan) == nan h0 = Heaviside(x, 0) h12 = Heaviside(x, S.Half) h1 = Heaviside(x, 1) assert h0.args == h0.pargs == (x, 0) assert h1.args == h1.pargs == (x, 1) assert h12.args == (x, S.Half) assert h12.pargs == (x,) # default 1/2 suppressed assert adjoint(Heaviside(x)) == Heaviside(x) assert adjoint(Heaviside(x - y)) == Heaviside(x - y) assert conjugate(Heaviside(x)) == Heaviside(x) assert conjugate(Heaviside(x - y)) == Heaviside(x - y) assert transpose(Heaviside(x)) == Heaviside(x) assert transpose(Heaviside(x - y)) == Heaviside(x - y) assert Heaviside(x).diff(x) == DiracDelta(x) assert Heaviside(x + I).is_Function is True assert Heaviside(I*x).is_Function is True raises(ArgumentIndexError, lambda: Heaviside(x).fdiff(2)) raises(ValueError, lambda: Heaviside(I)) raises(ValueError, lambda: Heaviside(2 + 3*I)) def test_rewrite(): x, y = Symbol('x', real=True), Symbol('y') assert Heaviside(x).rewrite(Piecewise) == ( Piecewise((0, x < 0), (Heaviside(0), Eq(x, 0)), (1, x > 0))) assert Heaviside(y).rewrite(Piecewise) == ( Piecewise((0, y < 0), (Heaviside(0), Eq(y, 0)), (1, y > 0))) assert Heaviside(x, y).rewrite(Piecewise) == ( Piecewise((0, x < 0), (y, Eq(x, 0)), (1, x > 0))) assert Heaviside(x, 0).rewrite(Piecewise) == ( Piecewise((0, x <= 0), (1, x > 0))) assert Heaviside(x, 1).rewrite(Piecewise) == ( Piecewise((0, x < 0), (1, x >= 0))) assert Heaviside(x, nan).rewrite(Piecewise) == ( Piecewise((0, x < 0), (nan, Eq(x, 0)), (1, x > 0))) assert Heaviside(x).rewrite(sign) == \ Heaviside(x, H0=Heaviside(0)).rewrite(sign) == \ Piecewise( (sign(x)/2 + S(1)/2, Eq(Heaviside(0), S(1)/2)), (Piecewise( (sign(x)/2 + S(1)/2, Ne(x, 0)), (Heaviside(0), True)), True) ) assert Heaviside(y).rewrite(sign) == Heaviside(y) assert Heaviside(x, S.Half).rewrite(sign) == (sign(x)+1)/2 assert Heaviside(x, y).rewrite(sign) == \ Piecewise( (sign(x)/2 + S(1)/2, Eq(y, S(1)/2)), (Piecewise( (sign(x)/2 + S(1)/2, Ne(x, 0)), (y, True)), True) ) assert DiracDelta(y).rewrite(Piecewise) == Piecewise((DiracDelta(0), Eq(y, 0)), (0, True)) assert DiracDelta(y, 1).rewrite(Piecewise) == DiracDelta(y, 1) assert DiracDelta(x - 5).rewrite(Piecewise) == ( Piecewise((DiracDelta(0), Eq(x - 5, 0)), (0, True))) assert (x*DiracDelta(x - 10)).rewrite(SingularityFunction) == x*SingularityFunction(x, 10, -1) assert 5*x*y*DiracDelta(y, 1).rewrite(SingularityFunction) == 5*x*y*SingularityFunction(y, 0, -2) assert DiracDelta(0).rewrite(SingularityFunction) == SingularityFunction(0, 0, -1) assert DiracDelta(0, 1).rewrite(SingularityFunction) == SingularityFunction(0, 0, -2) assert Heaviside(x).rewrite(SingularityFunction) == SingularityFunction(x, 0, 0) assert 5*x*y*Heaviside(y + 1).rewrite(SingularityFunction) == 5*x*y*SingularityFunction(y, -1, 0) assert ((x - 3)**3*Heaviside(x - 3)).rewrite(SingularityFunction) == (x - 3)**3*SingularityFunction(x, 3, 0) assert Heaviside(0).rewrite(SingularityFunction) == S.Half sympy-sympy-1.9/sympy/functions/special/tests/test_elliptic_integrals.py000066400000000000000000000146041412543434000271710ustar00rootroot00000000000000from sympy import (S, Symbol, pi, I, oo, zoo, sin, sqrt, tan, gamma, atanh, hyper, meijerg, O, Dummy, Integral, Rational) from sympy.functions.special.elliptic_integrals import (elliptic_k as K, elliptic_f as F, elliptic_e as E, elliptic_pi as P) from sympy.testing.randtest import (test_derivative_numerically as td, random_complex_number as randcplx, verify_numerically as tn) from sympy.abc import z, m, n i = Symbol('i', integer=True) j = Symbol('k', integer=True, positive=True) t = Dummy('t') def test_K(): assert K(0) == pi/2 assert K(S.Half) == 8*pi**Rational(3, 2)/gamma(Rational(-1, 4))**2 assert K(1) is zoo assert K(-1) == gamma(Rational(1, 4))**2/(4*sqrt(2*pi)) assert K(oo) == 0 assert K(-oo) == 0 assert K(I*oo) == 0 assert K(-I*oo) == 0 assert K(zoo) == 0 assert K(z).diff(z) == (E(z) - (1 - z)*K(z))/(2*z*(1 - z)) assert td(K(z), z) zi = Symbol('z', real=False) assert K(zi).conjugate() == K(zi.conjugate()) zr = Symbol('z', real=True, negative=True) assert K(zr).conjugate() == K(zr) assert K(z).rewrite(hyper) == \ (pi/2)*hyper((S.Half, S.Half), (S.One,), z) assert tn(K(z), (pi/2)*hyper((S.Half, S.Half), (S.One,), z)) assert K(z).rewrite(meijerg) == \ meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -z)/2 assert tn(K(z), meijerg(((S.Half, S.Half), []), ((S.Zero,), (S.Zero,)), -z)/2) assert K(z).series(z) == pi/2 + pi*z/8 + 9*pi*z**2/128 + \ 25*pi*z**3/512 + 1225*pi*z**4/32768 + 3969*pi*z**5/131072 + O(z**6) assert K(m).rewrite(Integral).dummy_eq( Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, pi/2))) def test_F(): assert F(z, 0) == z assert F(0, m) == 0 assert F(pi*i/2, m) == i*K(m) assert F(z, oo) == 0 assert F(z, -oo) == 0 assert F(-z, m) == -F(z, m) assert F(z, m).diff(z) == 1/sqrt(1 - m*sin(z)**2) assert F(z, m).diff(m) == E(z, m)/(2*m*(1 - m)) - F(z, m)/(2*m) - \ sin(2*z)/(4*(1 - m)*sqrt(1 - m*sin(z)**2)) r = randcplx() assert td(F(z, r), z) assert td(F(r, m), m) mi = Symbol('m', real=False) assert F(z, mi).conjugate() == F(z.conjugate(), mi.conjugate()) mr = Symbol('m', real=True, negative=True) assert F(z, mr).conjugate() == F(z.conjugate(), mr) assert F(z, m).series(z) == \ z + z**5*(3*m**2/40 - m/30) + m*z**3/6 + O(z**6) assert F(z, m).rewrite(Integral).dummy_eq( Integral(1/sqrt(1 - m*sin(t)**2), (t, 0, z))) def test_E(): assert E(z, 0) == z assert E(0, m) == 0 assert E(i*pi/2, m) == i*E(m) assert E(z, oo) is zoo assert E(z, -oo) is zoo assert E(0) == pi/2 assert E(1) == 1 assert E(oo) == I*oo assert E(-oo) is oo assert E(zoo) is zoo assert E(-z, m) == -E(z, m) assert E(z, m).diff(z) == sqrt(1 - m*sin(z)**2) assert E(z, m).diff(m) == (E(z, m) - F(z, m))/(2*m) assert E(z).diff(z) == (E(z) - K(z))/(2*z) r = randcplx() assert td(E(r, m), m) assert td(E(z, r), z) assert td(E(z), z) mi = Symbol('m', real=False) assert E(z, mi).conjugate() == E(z.conjugate(), mi.conjugate()) assert E(mi).conjugate() == E(mi.conjugate()) mr = Symbol('m', real=True, negative=True) assert E(z, mr).conjugate() == E(z.conjugate(), mr) assert E(mr).conjugate() == E(mr) assert E(z).rewrite(hyper) == (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), z) assert tn(E(z), (pi/2)*hyper((Rational(-1, 2), S.Half), (S.One,), z)) assert E(z).rewrite(meijerg) == \ -meijerg(((S.Half, Rational(3, 2)), []), ((S.Zero,), (S.Zero,)), -z)/4 assert tn(E(z), -meijerg(((S.Half, Rational(3, 2)), []), ((S.Zero,), (S.Zero,)), -z)/4) assert E(z, m).series(z) == \ z + z**5*(-m**2/40 + m/30) - m*z**3/6 + O(z**6) assert E(z).series(z) == pi/2 - pi*z/8 - 3*pi*z**2/128 - \ 5*pi*z**3/512 - 175*pi*z**4/32768 - 441*pi*z**5/131072 + O(z**6) assert E(z, m).rewrite(Integral).dummy_eq( Integral(sqrt(1 - m*sin(t)**2), (t, 0, z))) assert E(m).rewrite(Integral).dummy_eq( Integral(sqrt(1 - m*sin(t)**2), (t, 0, pi/2))) def test_P(): assert P(0, z, m) == F(z, m) assert P(1, z, m) == F(z, m) + \ (sqrt(1 - m*sin(z)**2)*tan(z) - E(z, m))/(1 - m) assert P(n, i*pi/2, m) == i*P(n, m) assert P(n, z, 0) == atanh(sqrt(n - 1)*tan(z))/sqrt(n - 1) assert P(n, z, n) == F(z, n) - P(1, z, n) + tan(z)/sqrt(1 - n*sin(z)**2) assert P(oo, z, m) == 0 assert P(-oo, z, m) == 0 assert P(n, z, oo) == 0 assert P(n, z, -oo) == 0 assert P(0, m) == K(m) assert P(1, m) is zoo assert P(n, 0) == pi/(2*sqrt(1 - n)) assert P(2, 1) is -oo assert P(-1, 1) is oo assert P(n, n) == E(n)/(1 - n) assert P(n, -z, m) == -P(n, z, m) ni, mi = Symbol('n', real=False), Symbol('m', real=False) assert P(ni, z, mi).conjugate() == \ P(ni.conjugate(), z.conjugate(), mi.conjugate()) nr, mr = Symbol('n', real=True, negative=True), \ Symbol('m', real=True, negative=True) assert P(nr, z, mr).conjugate() == P(nr, z.conjugate(), mr) assert P(n, m).conjugate() == P(n.conjugate(), m.conjugate()) assert P(n, z, m).diff(n) == (E(z, m) + (m - n)*F(z, m)/n + (n**2 - m)*P(n, z, m)/n - n*sqrt(1 - m*sin(z)**2)*sin(2*z)/(2*(1 - n*sin(z)**2)))/(2*(m - n)*(n - 1)) assert P(n, z, m).diff(z) == 1/(sqrt(1 - m*sin(z)**2)*(1 - n*sin(z)**2)) assert P(n, z, m).diff(m) == (E(z, m)/(m - 1) + P(n, z, m) - m*sin(2*z)/(2*(m - 1)*sqrt(1 - m*sin(z)**2)))/(2*(n - m)) assert P(n, m).diff(n) == (E(m) + (m - n)*K(m)/n + (n**2 - m)*P(n, m)/n)/(2*(m - n)*(n - 1)) assert P(n, m).diff(m) == (E(m)/(m - 1) + P(n, m))/(2*(n - m)) # These tests fail due to # https://github.com/fredrik-johansson/mpmath/issues/571#issuecomment-777201962 # https://github.com/sympy/sympy/issues/20933#issuecomment-777080385 # # rx, ry = randcplx(), randcplx() # assert td(P(n, rx, ry), n) # assert td(P(rx, z, ry), z) # assert td(P(rx, ry, m), m) assert P(n, z, m).series(z) == z + z**3*(m/6 + n/3) + \ z**5*(3*m**2/40 + m*n/10 - m/30 + n**2/5 - n/15) + O(z**6) assert P(n, z, m).rewrite(Integral).dummy_eq( Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, z))) assert P(n, m).rewrite(Integral).dummy_eq( Integral(1/((1 - n*sin(t)**2)*sqrt(1 - m*sin(t)**2)), (t, 0, pi/2))) sympy-sympy-1.9/sympy/functions/special/tests/test_error_functions.py000066400000000000000000000727241412543434000265440ustar00rootroot00000000000000from sympy import ( symbols, expand, expand_func, nan, oo, Float, conjugate, diff, re, im, O, exp_polar, polar_lift, gruntz, limit, Symbol, I, integrate, Integral, S, sqrt, sin, cos, sinc, sinh, cosh, exp, log, pi, EulerGamma, erf, erfc, erfi, erf2, erfinv, erfcinv, erf2inv, gamma, uppergamma, Ei, expint, E1, li, Li, Si, Ci, Shi, Chi, fresnels, fresnelc, hyper, meijerg, E, Rational) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.functions.special.error_functions import _erfs, _eis from sympy.testing.pytest import raises x, y, z = symbols('x,y,z') w = Symbol("w", real=True) n = Symbol("n", integer=True) def test_erf(): assert erf(nan) is nan assert erf(oo) == 1 assert erf(-oo) == -1 assert erf(0) == 0 assert erf(I*oo) == oo*I assert erf(-I*oo) == -oo*I assert erf(-2) == -erf(2) assert erf(-x*y) == -erf(x*y) assert erf(-x - y) == -erf(x + y) assert erf(erfinv(x)) == x assert erf(erfcinv(x)) == 1 - x assert erf(erf2inv(0, x)) == x assert erf(erf2inv(0, x, evaluate=False)) == x # To cover code in erf assert erf(erf2inv(0, erf(erfcinv(1 - erf(erfinv(x)))))) == x assert erf(I).is_real is False assert erf(0).is_real is True assert conjugate(erf(z)) == erf(conjugate(z)) assert erf(x).as_leading_term(x) == 2*x/sqrt(pi) assert erf(x*y).as_leading_term(y) == 2*x*y/sqrt(pi) assert (erf(x*y)/erf(y)).as_leading_term(y) == x assert erf(1/x).as_leading_term(x) == S.One assert erf(z).rewrite('uppergamma') == sqrt(z**2)*(1 - erfc(sqrt(z**2)))/z assert erf(z).rewrite('erfc') == S.One - erfc(z) assert erf(z).rewrite('erfi') == -I*erfi(I*z) assert erf(z).rewrite('fresnels') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - I*fresnels(z*(1 - I)/sqrt(pi))) assert erf(z).rewrite('fresnelc') == (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - I*fresnels(z*(1 - I)/sqrt(pi))) assert erf(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi) assert erf(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)/sqrt(pi) assert erf(z).rewrite('expint') == sqrt(z**2)/z - z*expint(S.Half, z**2)/sqrt(S.Pi) assert limit(exp(x)*exp(x**2)*(erf(x + 1/exp(x)) - erf(x)), x, oo) == \ 2/sqrt(pi) assert limit((1 - erf(z))*exp(z**2)*z, z, oo) == 1/sqrt(pi) assert limit((1 - erf(x))*exp(x**2)*sqrt(pi)*x, x, oo) == 1 assert limit(((1 - erf(x))*exp(x**2)*sqrt(pi)*x - 1)*2*x**2, x, oo) == -1 assert limit(erf(x)/x, x, 0) == 2/sqrt(pi) assert limit(x**(-4) - sqrt(pi)*erf(x**2) / (2*x**6), x, 0) == S(1)/3 assert erf(x).as_real_imag() == \ (erf(re(x) - I*im(x))/2 + erf(re(x) + I*im(x))/2, -I*(-erf(re(x) - I*im(x)) + erf(re(x) + I*im(x)))/2) assert erf(x).as_real_imag(deep=False) == \ (erf(re(x) - I*im(x))/2 + erf(re(x) + I*im(x))/2, -I*(-erf(re(x) - I*im(x)) + erf(re(x) + I*im(x)))/2) assert erf(w).as_real_imag() == (erf(w), 0) assert erf(w).as_real_imag(deep=False) == (erf(w), 0) # issue 13575 assert erf(I).as_real_imag() == (0, -I*erf(I)) raises(ArgumentIndexError, lambda: erf(x).fdiff(2)) assert erf(x).inverse() == erfinv def test_erf_series(): assert erf(x).series(x, 0, 7) == 2*x/sqrt(pi) - \ 2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7) assert erf(x).series(x, oo) == \ -exp(-x**2)*(3/(4*x**5) - 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))/sqrt(pi) + 1 assert erf(x**2).series(x, oo, n=8) == \ (-1/(2*x**6) + x**(-2) + O(x**(-8), (x, oo)))*exp(-x**4)/sqrt(pi)*-1 + 1 assert erf(sqrt(x)).series(x, oo, n=3) == (sqrt(1/x) - (1/x)**(S(3)/2)/2\ + 3*(1/x)**(S(5)/2)/4 + O(x**(-3), (x, oo)))*exp(-x)/sqrt(pi)*-1 + 1 def test_erf_evalf(): assert abs( erf(Float(2.0)) - 0.995322265 ) < 1E-8 # XXX def test__erfs(): assert _erfs(z).diff(z) == -2/sqrt(S.Pi) + 2*z*_erfs(z) assert _erfs(1/z).series(z) == \ z/sqrt(pi) - z**3/(2*sqrt(pi)) + 3*z**5/(4*sqrt(pi)) + O(z**6) assert expand(erf(z).rewrite('tractable').diff(z).rewrite('intractable')) \ == erf(z).diff(z) assert _erfs(z).rewrite("intractable") == (-erf(z) + 1)*exp(z**2) raises(ArgumentIndexError, lambda: _erfs(z).fdiff(2)) def test_erfc(): assert erfc(nan) is nan assert erfc(oo) == 0 assert erfc(-oo) == 2 assert erfc(0) == 1 assert erfc(I*oo) == -oo*I assert erfc(-I*oo) == oo*I assert erfc(-x) == S(2) - erfc(x) assert erfc(erfcinv(x)) == x assert erfc(I).is_real is False assert erfc(0).is_real is True assert erfc(erfinv(x)) == 1 - x assert conjugate(erfc(z)) == erfc(conjugate(z)) assert erfc(x).as_leading_term(x) is S.One assert erfc(1/x).as_leading_term(x) == S.Zero assert erfc(z).rewrite('erf') == 1 - erf(z) assert erfc(z).rewrite('erfi') == 1 + I*erfi(I*z) assert erfc(z).rewrite('fresnels') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - I*fresnels(z*(1 - I)/sqrt(pi))) assert erfc(z).rewrite('fresnelc') == 1 - (1 + I)*(fresnelc(z*(1 - I)/sqrt(pi)) - I*fresnels(z*(1 - I)/sqrt(pi))) assert erfc(z).rewrite('hyper') == 1 - 2*z*hyper([S.Half], [3*S.Half], -z**2)/sqrt(pi) assert erfc(z).rewrite('meijerg') == 1 - z*meijerg([S.Half], [], [0], [Rational(-1, 2)], z**2)/sqrt(pi) assert erfc(z).rewrite('uppergamma') == 1 - sqrt(z**2)*(1 - erfc(sqrt(z**2)))/z assert erfc(z).rewrite('expint') == S.One - sqrt(z**2)/z + z*expint(S.Half, z**2)/sqrt(S.Pi) assert erfc(z).rewrite('tractable') == _erfs(z)*exp(-z**2) assert expand_func(erf(x) + erfc(x)) is S.One assert erfc(x).as_real_imag() == \ (erfc(re(x) - I*im(x))/2 + erfc(re(x) + I*im(x))/2, -I*(-erfc(re(x) - I*im(x)) + erfc(re(x) + I*im(x)))/2) assert erfc(x).as_real_imag(deep=False) == \ (erfc(re(x) - I*im(x))/2 + erfc(re(x) + I*im(x))/2, -I*(-erfc(re(x) - I*im(x)) + erfc(re(x) + I*im(x)))/2) assert erfc(w).as_real_imag() == (erfc(w), 0) assert erfc(w).as_real_imag(deep=False) == (erfc(w), 0) raises(ArgumentIndexError, lambda: erfc(x).fdiff(2)) assert erfc(x).inverse() == erfcinv def test_erfc_series(): assert erfc(x).series(x, 0, 7) == 1 - 2*x/sqrt(pi) + \ 2*x**3/3/sqrt(pi) - x**5/5/sqrt(pi) + O(x**7) assert erfc(x).series(x, oo) == \ (3/(4*x**5) - 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))*exp(-x**2)/sqrt(pi) def test_erfc_evalf(): assert abs( erfc(Float(2.0)) - 0.00467773 ) < 1E-8 # XXX def test_erfi(): assert erfi(nan) is nan assert erfi(oo) is S.Infinity assert erfi(-oo) is S.NegativeInfinity assert erfi(0) is S.Zero assert erfi(I*oo) == I assert erfi(-I*oo) == -I assert erfi(-x) == -erfi(x) assert erfi(I*erfinv(x)) == I*x assert erfi(I*erfcinv(x)) == I*(1 - x) assert erfi(I*erf2inv(0, x)) == I*x assert erfi(I*erf2inv(0, x, evaluate=False)) == I*x # To cover code in erfi assert erfi(I).is_real is False assert erfi(0).is_real is True assert conjugate(erfi(z)) == erfi(conjugate(z)) assert erfi(x).as_leading_term(x) == 2*x/sqrt(pi) assert erfi(x*y).as_leading_term(y) == 2*x*y/sqrt(pi) assert (erfi(x*y)/erfi(y)).as_leading_term(y) == x assert erfi(1/x).as_leading_term(x) == erfi(1/x) assert erfi(z).rewrite('erf') == -I*erf(I*z) assert erfi(z).rewrite('erfc') == I*erfc(I*z) - I assert erfi(z).rewrite('fresnels') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) - I*fresnels(z*(1 + I)/sqrt(pi))) assert erfi(z).rewrite('fresnelc') == (1 - I)*(fresnelc(z*(1 + I)/sqrt(pi)) - I*fresnels(z*(1 + I)/sqrt(pi))) assert erfi(z).rewrite('hyper') == 2*z*hyper([S.Half], [3*S.Half], z**2)/sqrt(pi) assert erfi(z).rewrite('meijerg') == z*meijerg([S.Half], [], [0], [Rational(-1, 2)], -z**2)/sqrt(pi) assert erfi(z).rewrite('uppergamma') == (sqrt(-z**2)/z*(uppergamma(S.Half, -z**2)/sqrt(S.Pi) - S.One)) assert erfi(z).rewrite('expint') == sqrt(-z**2)/z - z*expint(S.Half, -z**2)/sqrt(S.Pi) assert erfi(z).rewrite('tractable') == -I*(-_erfs(I*z)*exp(z**2) + 1) assert expand_func(erfi(I*z)) == I*erf(z) assert erfi(x).as_real_imag() == \ (erfi(re(x) - I*im(x))/2 + erfi(re(x) + I*im(x))/2, -I*(-erfi(re(x) - I*im(x)) + erfi(re(x) + I*im(x)))/2) assert erfi(x).as_real_imag(deep=False) == \ (erfi(re(x) - I*im(x))/2 + erfi(re(x) + I*im(x))/2, -I*(-erfi(re(x) - I*im(x)) + erfi(re(x) + I*im(x)))/2) assert erfi(w).as_real_imag() == (erfi(w), 0) assert erfi(w).as_real_imag(deep=False) == (erfi(w), 0) raises(ArgumentIndexError, lambda: erfi(x).fdiff(2)) def test_erfi_series(): assert erfi(x).series(x, 0, 7) == 2*x/sqrt(pi) + \ 2*x**3/3/sqrt(pi) + x**5/5/sqrt(pi) + O(x**7) assert erfi(x).series(x, oo) == \ (3/(4*x**5) + 1/(2*x**3) + 1/x + O(x**(-6), (x, oo)))*exp(x**2)/sqrt(pi) - I def test_erfi_evalf(): assert abs( erfi(Float(2.0)) - 18.5648024145756 ) < 1E-13 # XXX def test_erf2(): assert erf2(0, 0) is S.Zero assert erf2(x, x) is S.Zero assert erf2(nan, 0) is nan assert erf2(-oo, y) == erf(y) + 1 assert erf2( oo, y) == erf(y) - 1 assert erf2( x, oo) == 1 - erf(x) assert erf2( x,-oo) == -1 - erf(x) assert erf2(x, erf2inv(x, y)) == y assert erf2(-x, -y) == -erf2(x,y) assert erf2(-x, y) == erf(y) + erf(x) assert erf2( x, -y) == -erf(y) - erf(x) assert erf2(x, y).rewrite('fresnels') == erf(y).rewrite(fresnels)-erf(x).rewrite(fresnels) assert erf2(x, y).rewrite('fresnelc') == erf(y).rewrite(fresnelc)-erf(x).rewrite(fresnelc) assert erf2(x, y).rewrite('hyper') == erf(y).rewrite(hyper)-erf(x).rewrite(hyper) assert erf2(x, y).rewrite('meijerg') == erf(y).rewrite(meijerg)-erf(x).rewrite(meijerg) assert erf2(x, y).rewrite('uppergamma') == erf(y).rewrite(uppergamma) - erf(x).rewrite(uppergamma) assert erf2(x, y).rewrite('expint') == erf(y).rewrite(expint)-erf(x).rewrite(expint) assert erf2(I, 0).is_real is False assert erf2(0, 0).is_real is True assert expand_func(erf(x) + erf2(x, y)) == erf(y) assert conjugate(erf2(x, y)) == erf2(conjugate(x), conjugate(y)) assert erf2(x, y).rewrite('erf') == erf(y) - erf(x) assert erf2(x, y).rewrite('erfc') == erfc(x) - erfc(y) assert erf2(x, y).rewrite('erfi') == I*(erfi(I*x) - erfi(I*y)) assert erf2(x, y).diff(x) == erf2(x, y).fdiff(1) assert erf2(x, y).diff(y) == erf2(x, y).fdiff(2) assert erf2(x, y).diff(x) == -2*exp(-x**2)/sqrt(pi) assert erf2(x, y).diff(y) == 2*exp(-y**2)/sqrt(pi) raises(ArgumentIndexError, lambda: erf2(x, y).fdiff(3)) assert erf2(x, y).is_extended_real is None xr, yr = symbols('xr yr', extended_real=True) assert erf2(xr, yr).is_extended_real is True def test_erfinv(): assert erfinv(0) == 0 assert erfinv(1) is S.Infinity assert erfinv(nan) is S.NaN assert erfinv(-1) is S.NegativeInfinity assert erfinv(erf(w)) == w assert erfinv(erf(-w)) == -w assert erfinv(x).diff() == sqrt(pi)*exp(erfinv(x)**2)/2 raises(ArgumentIndexError, lambda: erfinv(x).fdiff(2)) assert erfinv(z).rewrite('erfcinv') == erfcinv(1-z) assert erfinv(z).inverse() == erf def test_erfinv_evalf(): assert abs( erfinv(Float(0.2)) - 0.179143454621292 ) < 1E-13 def test_erfcinv(): assert erfcinv(1) == 0 assert erfcinv(0) is S.Infinity assert erfcinv(nan) is S.NaN assert erfcinv(x).diff() == -sqrt(pi)*exp(erfcinv(x)**2)/2 raises(ArgumentIndexError, lambda: erfcinv(x).fdiff(2)) assert erfcinv(z).rewrite('erfinv') == erfinv(1-z) assert erfcinv(z).inverse() == erfc def test_erf2inv(): assert erf2inv(0, 0) is S.Zero assert erf2inv(0, 1) is S.Infinity assert erf2inv(1, 0) is S.One assert erf2inv(0, y) == erfinv(y) assert erf2inv(oo, y) == erfcinv(-y) assert erf2inv(x, 0) == x assert erf2inv(x, oo) == erfinv(x) assert erf2inv(nan, 0) is nan assert erf2inv(0, nan) is nan assert erf2inv(x, y).diff(x) == exp(-x**2 + erf2inv(x, y)**2) assert erf2inv(x, y).diff(y) == sqrt(pi)*exp(erf2inv(x, y)**2)/2 raises(ArgumentIndexError, lambda: erf2inv(x, y).fdiff(3)) # NOTE we multiply by exp_polar(I*pi) and need this to be on the principal # branch, hence take x in the lower half plane (d=0). def mytn(expr1, expr2, expr3, x, d=0): from sympy.testing.randtest import verify_numerically, random_complex_number subs = {} for a in expr1.free_symbols: if a != x: subs[a] = random_complex_number() return expr2 == expr3 and verify_numerically(expr1.subs(subs), expr2.subs(subs), x, d=d) def mytd(expr1, expr2, x): from sympy.testing.randtest import test_derivative_numerically, \ random_complex_number subs = {} for a in expr1.free_symbols: if a != x: subs[a] = random_complex_number() return expr1.diff(x) == expr2 and test_derivative_numerically(expr1.subs(subs), x) def tn_branch(func, s=None): from random import uniform def fn(x): if s is None: return func(x) return func(s, x) c = uniform(1, 5) expr = fn(c*exp_polar(I*pi)) - fn(c*exp_polar(-I*pi)) eps = 1e-15 expr2 = fn(-c + eps*I) - fn(-c - eps*I) return abs(expr.n() - expr2.n()).n() < 1e-10 def test_ei(): assert Ei(0) is S.NegativeInfinity assert Ei(oo) is S.Infinity assert Ei(-oo) is S.Zero assert tn_branch(Ei) assert mytd(Ei(x), exp(x)/x, x) assert mytn(Ei(x), Ei(x).rewrite(uppergamma), -uppergamma(0, x*polar_lift(-1)) - I*pi, x) assert mytn(Ei(x), Ei(x).rewrite(expint), -expint(1, x*polar_lift(-1)) - I*pi, x) assert Ei(x).rewrite(expint).rewrite(Ei) == Ei(x) assert Ei(x*exp_polar(2*I*pi)) == Ei(x) + 2*I*pi assert Ei(x*exp_polar(-2*I*pi)) == Ei(x) - 2*I*pi assert mytn(Ei(x), Ei(x).rewrite(Shi), Chi(x) + Shi(x), x) assert mytn(Ei(x*polar_lift(I)), Ei(x*polar_lift(I)).rewrite(Si), Ci(x) + I*Si(x) + I*pi/2, x) assert Ei(log(x)).rewrite(li) == li(x) assert Ei(2*log(x)).rewrite(li) == li(x**2) assert gruntz(Ei(x+exp(-x))*exp(-x)*x, x, oo) == 1 assert Ei(x).series(x) == EulerGamma + log(x) + x + x**2/4 + \ x**3/18 + x**4/96 + x**5/600 + O(x**6) assert Ei(x).series(x, 1, 3) == Ei(1) + E*(x - 1) + O((x - 1)**3, (x, 1)) assert Ei(x).series(x, oo) == \ (120/x**5 + 24/x**4 + 6/x**3 + 2/x**2 + 1/x + 1 + O(x**(-6), (x, oo)))*exp(x)/x assert str(Ei(cos(2)).evalf(n=10)) == '-0.6760647401' raises(ArgumentIndexError, lambda: Ei(x).fdiff(2)) def test_expint(): assert mytn(expint(x, y), expint(x, y).rewrite(uppergamma), y**(x - 1)*uppergamma(1 - x, y), x) assert mytd( expint(x, y), -y**(x - 1)*meijerg([], [1, 1], [0, 0, 1 - x], [], y), x) assert mytd(expint(x, y), -expint(x - 1, y), y) assert mytn(expint(1, x), expint(1, x).rewrite(Ei), -Ei(x*polar_lift(-1)) + I*pi, x) assert expint(-4, x) == exp(-x)/x + 4*exp(-x)/x**2 + 12*exp(-x)/x**3 \ + 24*exp(-x)/x**4 + 24*exp(-x)/x**5 assert expint(Rational(-3, 2), x) == \ exp(-x)/x + 3*exp(-x)/(2*x**2) + 3*sqrt(pi)*erfc(sqrt(x))/(4*x**S('5/2')) assert tn_branch(expint, 1) assert tn_branch(expint, 2) assert tn_branch(expint, 3) assert tn_branch(expint, 1.7) assert tn_branch(expint, pi) assert expint(y, x*exp_polar(2*I*pi)) == \ x**(y - 1)*(exp(2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x) assert expint(y, x*exp_polar(-2*I*pi)) == \ x**(y - 1)*(exp(-2*I*pi*y) - 1)*gamma(-y + 1) + expint(y, x) assert expint(2, x*exp_polar(2*I*pi)) == 2*I*pi*x + expint(2, x) assert expint(2, x*exp_polar(-2*I*pi)) == -2*I*pi*x + expint(2, x) assert expint(1, x).rewrite(Ei).rewrite(expint) == expint(1, x) assert expint(x, y).rewrite(Ei) == expint(x, y) assert expint(x, y).rewrite(Ci) == expint(x, y) assert mytn(E1(x), E1(x).rewrite(Shi), Shi(x) - Chi(x), x) assert mytn(E1(polar_lift(I)*x), E1(polar_lift(I)*x).rewrite(Si), -Ci(x) + I*Si(x) - I*pi/2, x) assert mytn(expint(2, x), expint(2, x).rewrite(Ei).rewrite(expint), -x*E1(x) + exp(-x), x) assert mytn(expint(3, x), expint(3, x).rewrite(Ei).rewrite(expint), x**2*E1(x)/2 + (1 - x)*exp(-x)/2, x) assert expint(Rational(3, 2), z).nseries(z) == \ 2 + 2*z - z**2/3 + z**3/15 - z**4/84 + z**5/540 - \ 2*sqrt(pi)*sqrt(z) + O(z**6) assert E1(z).series(z) == -EulerGamma - log(z) + z - \ z**2/4 + z**3/18 - z**4/96 + z**5/600 + O(z**6) assert expint(4, z).series(z) == Rational(1, 3) - z/2 + z**2/2 + \ z**3*(log(z)/6 - Rational(11, 36) + EulerGamma/6 - I*pi/6) - z**4/24 + \ z**5/240 + O(z**6) assert expint(n, x).series(x, oo, n=3) == \ (n*(n + 1)/x**2 - n/x + 1 + O(x**(-3), (x, oo)))*exp(-x)/x assert expint(z, y).series(z, 0, 2) == exp(-y)/y - z*meijerg(((), (1, 1)), ((0, 0, 1), ()), y)/y + O(z**2) raises(ArgumentIndexError, lambda: expint(x, y).fdiff(3)) neg = Symbol('neg', negative=True) assert Ei(neg).rewrite(Si) == Shi(neg) + Chi(neg) - I*pi def test__eis(): assert _eis(z).diff(z) == -_eis(z) + 1/z assert _eis(1/z).series(z) == \ z + z**2 + 2*z**3 + 6*z**4 + 24*z**5 + O(z**6) assert Ei(z).rewrite('tractable') == exp(z)*_eis(z) assert li(z).rewrite('tractable') == z*_eis(log(z)) assert _eis(z).rewrite('intractable') == exp(-z)*Ei(z) assert expand(li(z).rewrite('tractable').diff(z).rewrite('intractable')) \ == li(z).diff(z) assert expand(Ei(z).rewrite('tractable').diff(z).rewrite('intractable')) \ == Ei(z).diff(z) assert _eis(z).series(z, n=3) == EulerGamma + log(z) + z*(-log(z) - \ EulerGamma + 1) + z**2*(log(z)/2 - Rational(3, 4) + EulerGamma/2)\ + O(z**3*log(z)) raises(ArgumentIndexError, lambda: _eis(z).fdiff(2)) def tn_arg(func): def test(arg, e1, e2): from random import uniform v = uniform(1, 5) v1 = func(arg*x).subs(x, v).n() v2 = func(e1*v + e2*1e-15).n() return abs(v1 - v2).n() < 1e-10 return test(exp_polar(I*pi/2), I, 1) and \ test(exp_polar(-I*pi/2), -I, 1) and \ test(exp_polar(I*pi), -1, I) and \ test(exp_polar(-I*pi), -1, -I) def test_li(): z = Symbol("z") zr = Symbol("z", real=True) zp = Symbol("z", positive=True) zn = Symbol("z", negative=True) assert li(0) == 0 assert li(1) is -oo assert li(oo) is oo assert isinstance(li(z), li) assert unchanged(li, -zp) assert unchanged(li, zn) assert diff(li(z), z) == 1/log(z) assert conjugate(li(z)) == li(conjugate(z)) assert conjugate(li(-zr)) == li(-zr) assert unchanged(conjugate, li(-zp)) assert unchanged(conjugate, li(zn)) assert li(z).rewrite(Li) == Li(z) + li(2) assert li(z).rewrite(Ei) == Ei(log(z)) assert li(z).rewrite(uppergamma) == (-log(1/log(z))/2 - log(-log(z)) + log(log(z))/2 - expint(1, -log(z))) assert li(z).rewrite(Si) == (-log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z))) assert li(z).rewrite(Ci) == (-log(I*log(z)) - log(1/log(z))/2 + log(log(z))/2 + Ci(I*log(z)) + Shi(log(z))) assert li(z).rewrite(Shi) == (-log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z))) assert li(z).rewrite(Chi) == (-log(1/log(z))/2 + log(log(z))/2 + Chi(log(z)) - Shi(log(z))) assert li(z).rewrite(hyper) ==(log(z)*hyper((1, 1), (2, 2), log(z)) - log(1/log(z))/2 + log(log(z))/2 + EulerGamma) assert li(z).rewrite(meijerg) == (-log(1/log(z))/2 - log(-log(z)) + log(log(z))/2 - meijerg(((), (1,)), ((0, 0), ()), -log(z))) assert gruntz(1/li(z), z, oo) == 0 assert li(z).series(z) == log(z)**5/600 + log(z)**4/96 + log(z)**3/18 + log(z)**2/4 + \ log(z) + log(log(z)) + EulerGamma raises(ArgumentIndexError, lambda: li(z).fdiff(2)) def test_Li(): assert Li(2) == 0 assert Li(oo) is oo assert isinstance(Li(z), Li) assert diff(Li(z), z) == 1/log(z) assert gruntz(1/Li(z), z, oo) == 0 assert Li(z).rewrite(li) == li(z) - li(2) assert Li(z).series(z) == \ log(z)**5/600 + log(z)**4/96 + log(z)**3/18 + log(z)**2/4 + log(z) + log(log(z)) - li(2) + EulerGamma raises(ArgumentIndexError, lambda: Li(z).fdiff(2)) def test_si(): assert Si(I*x) == I*Shi(x) assert Shi(I*x) == I*Si(x) assert Si(-I*x) == -I*Shi(x) assert Shi(-I*x) == -I*Si(x) assert Si(-x) == -Si(x) assert Shi(-x) == -Shi(x) assert Si(exp_polar(2*pi*I)*x) == Si(x) assert Si(exp_polar(-2*pi*I)*x) == Si(x) assert Shi(exp_polar(2*pi*I)*x) == Shi(x) assert Shi(exp_polar(-2*pi*I)*x) == Shi(x) assert Si(oo) == pi/2 assert Si(-oo) == -pi/2 assert Shi(oo) is oo assert Shi(-oo) is -oo assert mytd(Si(x), sin(x)/x, x) assert mytd(Shi(x), sinh(x)/x, x) assert mytn(Si(x), Si(x).rewrite(Ei), -I*(-Ei(x*exp_polar(-I*pi/2))/2 + Ei(x*exp_polar(I*pi/2))/2 - I*pi) + pi/2, x) assert mytn(Si(x), Si(x).rewrite(expint), -I*(-expint(1, x*exp_polar(-I*pi/2))/2 + expint(1, x*exp_polar(I*pi/2))/2) + pi/2, x) assert mytn(Shi(x), Shi(x).rewrite(Ei), Ei(x)/2 - Ei(x*exp_polar(I*pi))/2 + I*pi/2, x) assert mytn(Shi(x), Shi(x).rewrite(expint), expint(1, x)/2 - expint(1, x*exp_polar(I*pi))/2 - I*pi/2, x) assert tn_arg(Si) assert tn_arg(Shi) assert Si(x).nseries(x, n=8) == \ x - x**3/18 + x**5/600 - x**7/35280 + O(x**9) assert Shi(x).nseries(x, n=8) == \ x + x**3/18 + x**5/600 + x**7/35280 + O(x**9) assert Si(sin(x)).nseries(x, n=5) == x - 2*x**3/9 + 17*x**5/450 + O(x**6) assert Si(x).nseries(x, 1, n=3) == \ Si(1) + (x - 1)*sin(1) + (x - 1)**2*(-sin(1)/2 + cos(1)/2) + O((x - 1)**3, (x, 1)) assert Si(x).series(x, oo) == pi/2 - (- 6/x**3 + 1/x \ + O(x**(-7), (x, oo)))*sin(x)/x - (24/x**4 - 2/x**2 + 1 \ + O(x**(-7), (x, oo)))*cos(x)/x t = Symbol('t', Dummy=True) assert Si(x).rewrite(sinc) == Integral(sinc(t), (t, 0, x)) assert limit(Shi(x), x, S.NegativeInfinity) == -I*pi/2 def test_ci(): m1 = exp_polar(I*pi) m1_ = exp_polar(-I*pi) pI = exp_polar(I*pi/2) mI = exp_polar(-I*pi/2) assert Ci(m1*x) == Ci(x) + I*pi assert Ci(m1_*x) == Ci(x) - I*pi assert Ci(pI*x) == Chi(x) + I*pi/2 assert Ci(mI*x) == Chi(x) - I*pi/2 assert Chi(m1*x) == Chi(x) + I*pi assert Chi(m1_*x) == Chi(x) - I*pi assert Chi(pI*x) == Ci(x) + I*pi/2 assert Chi(mI*x) == Ci(x) - I*pi/2 assert Ci(exp_polar(2*I*pi)*x) == Ci(x) + 2*I*pi assert Chi(exp_polar(-2*I*pi)*x) == Chi(x) - 2*I*pi assert Chi(exp_polar(2*I*pi)*x) == Chi(x) + 2*I*pi assert Ci(exp_polar(-2*I*pi)*x) == Ci(x) - 2*I*pi assert Ci(oo) == 0 assert Ci(-oo) == I*pi assert Chi(oo) is oo assert Chi(-oo) is oo assert mytd(Ci(x), cos(x)/x, x) assert mytd(Chi(x), cosh(x)/x, x) assert mytn(Ci(x), Ci(x).rewrite(Ei), Ei(x*exp_polar(-I*pi/2))/2 + Ei(x*exp_polar(I*pi/2))/2, x) assert mytn(Chi(x), Chi(x).rewrite(Ei), Ei(x)/2 + Ei(x*exp_polar(I*pi))/2 - I*pi/2, x) assert tn_arg(Ci) assert tn_arg(Chi) assert Ci(x).nseries(x, n=4) == \ EulerGamma + log(x) - x**2/4 + x**4/96 + O(x**5) assert Chi(x).nseries(x, n=4) == \ EulerGamma + log(x) + x**2/4 + x**4/96 + O(x**5) assert Ci(x).series(x, oo) == -cos(x)*(-6/x**3 + 1/x \ + O(x**(-7), (x, oo)))/x + (24/x**4 - 2/x**2 + 1 \ + O(x**(-7), (x, oo)))*sin(x)/x assert limit(log(x) - Ci(2*x), x, 0) == -log(2) - EulerGamma assert Ci(x).rewrite(uppergamma) == -expint(1, x*exp_polar(-I*pi/2))/2 -\ expint(1, x*exp_polar(I*pi/2))/2 assert Ci(x).rewrite(expint) == -expint(1, x*exp_polar(-I*pi/2))/2 -\ expint(1, x*exp_polar(I*pi/2))/2 raises(ArgumentIndexError, lambda: Ci(x).fdiff(2)) def test_fresnel(): assert fresnels(0) == 0 assert fresnels(oo) == S.Half assert fresnels(-oo) == Rational(-1, 2) assert fresnels(I*oo) == -I*S.Half assert unchanged(fresnels, z) assert fresnels(-z) == -fresnels(z) assert fresnels(I*z) == -I*fresnels(z) assert fresnels(-I*z) == I*fresnels(z) assert conjugate(fresnels(z)) == fresnels(conjugate(z)) assert fresnels(z).diff(z) == sin(pi*z**2/2) assert fresnels(z).rewrite(erf) == (S.One + I)/4 * ( erf((S.One + I)/2*sqrt(pi)*z) - I*erf((S.One - I)/2*sqrt(pi)*z)) assert fresnels(z).rewrite(hyper) == \ pi*z**3/6 * hyper([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)], -pi**2*z**4/16) assert fresnels(z).series(z, n=15) == \ pi*z**3/6 - pi**3*z**7/336 + pi**5*z**11/42240 + O(z**15) assert fresnels(w).is_extended_real is True assert fresnels(w).is_finite is True assert fresnels(z).is_extended_real is None assert fresnels(z).is_finite is None assert fresnels(z).as_real_imag() == (fresnels(re(z) - I*im(z))/2 + fresnels(re(z) + I*im(z))/2, -I*(-fresnels(re(z) - I*im(z)) + fresnels(re(z) + I*im(z)))/2) assert fresnels(z).as_real_imag(deep=False) == (fresnels(re(z) - I*im(z))/2 + fresnels(re(z) + I*im(z))/2, -I*(-fresnels(re(z) - I*im(z)) + fresnels(re(z) + I*im(z)))/2) assert fresnels(w).as_real_imag() == (fresnels(w), 0) assert fresnels(w).as_real_imag(deep=True) == (fresnels(w), 0) assert fresnels(2 + 3*I).as_real_imag() == ( fresnels(2 + 3*I)/2 + fresnels(2 - 3*I)/2, -I*(fresnels(2 + 3*I) - fresnels(2 - 3*I))/2 ) assert expand_func(integrate(fresnels(z), z)) == \ z*fresnels(z) + cos(pi*z**2/2)/pi assert fresnels(z).rewrite(meijerg) == sqrt(2)*pi*z**Rational(9, 4) * \ meijerg(((), (1,)), ((Rational(3, 4),), (Rational(1, 4), 0)), -pi**2*z**4/16)/(2*(-z)**Rational(3, 4)*(z**2)**Rational(3, 4)) assert fresnelc(0) == 0 assert fresnelc(oo) == S.Half assert fresnelc(-oo) == Rational(-1, 2) assert fresnelc(I*oo) == I*S.Half assert unchanged(fresnelc, z) assert fresnelc(-z) == -fresnelc(z) assert fresnelc(I*z) == I*fresnelc(z) assert fresnelc(-I*z) == -I*fresnelc(z) assert conjugate(fresnelc(z)) == fresnelc(conjugate(z)) assert fresnelc(z).diff(z) == cos(pi*z**2/2) assert fresnelc(z).rewrite(erf) == (S.One - I)/4 * ( erf((S.One + I)/2*sqrt(pi)*z) + I*erf((S.One - I)/2*sqrt(pi)*z)) assert fresnelc(z).rewrite(hyper) == \ z * hyper([Rational(1, 4)], [S.Half, Rational(5, 4)], -pi**2*z**4/16) assert fresnelc(w).is_extended_real is True assert fresnelc(z).as_real_imag() == \ (fresnelc(re(z) - I*im(z))/2 + fresnelc(re(z) + I*im(z))/2, -I*(-fresnelc(re(z) - I*im(z)) + fresnelc(re(z) + I*im(z)))/2) assert fresnelc(z).as_real_imag(deep=False) == \ (fresnelc(re(z) - I*im(z))/2 + fresnelc(re(z) + I*im(z))/2, -I*(-fresnelc(re(z) - I*im(z)) + fresnelc(re(z) + I*im(z)))/2) assert fresnelc(2 + 3*I).as_real_imag() == ( fresnelc(2 - 3*I)/2 + fresnelc(2 + 3*I)/2, -I*(fresnelc(2 + 3*I) - fresnelc(2 - 3*I))/2 ) assert expand_func(integrate(fresnelc(z), z)) == \ z*fresnelc(z) - sin(pi*z**2/2)/pi assert fresnelc(z).rewrite(meijerg) == sqrt(2)*pi*z**Rational(3, 4) * \ meijerg(((), (1,)), ((Rational(1, 4),), (Rational(3, 4), 0)), -pi**2*z**4/16)/(2*(-z)**Rational(1, 4)*(z**2)**Rational(1, 4)) from sympy.testing.randtest import verify_numerically verify_numerically(re(fresnels(z)), fresnels(z).as_real_imag()[0], z) verify_numerically(im(fresnels(z)), fresnels(z).as_real_imag()[1], z) verify_numerically(fresnels(z), fresnels(z).rewrite(hyper), z) verify_numerically(fresnels(z), fresnels(z).rewrite(meijerg), z) verify_numerically(re(fresnelc(z)), fresnelc(z).as_real_imag()[0], z) verify_numerically(im(fresnelc(z)), fresnelc(z).as_real_imag()[1], z) verify_numerically(fresnelc(z), fresnelc(z).rewrite(hyper), z) verify_numerically(fresnelc(z), fresnelc(z).rewrite(meijerg), z) raises(ArgumentIndexError, lambda: fresnels(z).fdiff(2)) raises(ArgumentIndexError, lambda: fresnelc(z).fdiff(2)) assert fresnels(x).taylor_term(-1, x) is S.Zero assert fresnelc(x).taylor_term(-1, x) is S.Zero assert fresnelc(x).taylor_term(1, x) == -pi**2*x**5/40 def test_fresnel_series(): assert fresnelc(z).series(z, n=15) == \ z - pi**2*z**5/40 + pi**4*z**9/3456 - pi**6*z**13/599040 + O(z**15) # issues 6510, 10102 fs = (S.Half - sin(pi*z**2/2)/(pi**2*z**3) + (-1/(pi*z) + 3/(pi**3*z**5))*cos(pi*z**2/2)) fc = (S.Half - cos(pi*z**2/2)/(pi**2*z**3) + (1/(pi*z) - 3/(pi**3*z**5))*sin(pi*z**2/2)) assert fresnels(z).series(z, oo) == fs + O(z**(-6), (z, oo)) assert fresnelc(z).series(z, oo) == fc + O(z**(-6), (z, oo)) assert (fresnels(z).series(z, -oo) + fs.subs(z, -z)).expand().is_Order assert (fresnelc(z).series(z, -oo) + fc.subs(z, -z)).expand().is_Order assert (fresnels(1/z).series(z) - fs.subs(z, 1/z)).expand().is_Order assert (fresnelc(1/z).series(z) - fc.subs(z, 1/z)).expand().is_Order assert ((2*fresnels(3*z)).series(z, oo) - 2*fs.subs(z, 3*z)).expand().is_Order assert ((3*fresnelc(2*z)).series(z, oo) - 3*fc.subs(z, 2*z)).expand().is_Order sympy-sympy-1.9/sympy/functions/special/tests/test_gamma_functions.py000066400000000000000000000675111412543434000264730ustar00rootroot00000000000000from sympy import ( Symbol, Dummy, gamma, I, oo, nan, zoo, factorial, sqrt, Rational, multigamma, log, polygamma, digamma, trigamma, EulerGamma, pi, uppergamma, S, expand_func, loggamma, sin, cos, O, lowergamma, exp, erf, erfc, exp_polar, harmonic, zeta, conjugate, Ei, im, re, tanh, Abs) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.testing.pytest import raises from sympy.testing.randtest import (test_derivative_numerically as td, random_complex_number as randcplx, verify_numerically as tn) x = Symbol('x') y = Symbol('y') n = Symbol('n', integer=True) w = Symbol('w', real=True) def test_gamma(): assert gamma(nan) is nan assert gamma(oo) is oo assert gamma(-100) is zoo assert gamma(0) is zoo assert gamma(-100.0) is zoo assert gamma(1) == 1 assert gamma(2) == 1 assert gamma(3) == 2 assert gamma(102) == factorial(101) assert gamma(S.Half) == sqrt(pi) assert gamma(Rational(3, 2)) == sqrt(pi)*S.Half assert gamma(Rational(5, 2)) == sqrt(pi)*Rational(3, 4) assert gamma(Rational(7, 2)) == sqrt(pi)*Rational(15, 8) assert gamma(Rational(-1, 2)) == -2*sqrt(pi) assert gamma(Rational(-3, 2)) == sqrt(pi)*Rational(4, 3) assert gamma(Rational(-5, 2)) == sqrt(pi)*Rational(-8, 15) assert gamma(Rational(-15, 2)) == sqrt(pi)*Rational(256, 2027025) assert gamma(Rational( -11, 8)).expand(func=True) == Rational(64, 33)*gamma(Rational(5, 8)) assert gamma(Rational( -10, 3)).expand(func=True) == Rational(81, 280)*gamma(Rational(2, 3)) assert gamma(Rational( 14, 3)).expand(func=True) == Rational(880, 81)*gamma(Rational(2, 3)) assert gamma(Rational( 17, 7)).expand(func=True) == Rational(30, 49)*gamma(Rational(3, 7)) assert gamma(Rational( 19, 8)).expand(func=True) == Rational(33, 64)*gamma(Rational(3, 8)) assert gamma(x).diff(x) == gamma(x)*polygamma(0, x) assert gamma(x - 1).expand(func=True) == gamma(x)/(x - 1) assert gamma(x + 2).expand(func=True, mul=False) == x*(x + 1)*gamma(x) assert conjugate(gamma(x)) == gamma(conjugate(x)) assert expand_func(gamma(x + Rational(3, 2))) == \ (x + S.Half)*gamma(x + S.Half) assert expand_func(gamma(x - S.Half)) == \ gamma(S.Half + x)/(x - S.Half) # Test a bug: assert expand_func(gamma(x + Rational(3, 4))) == gamma(x + Rational(3, 4)) # XXX: Not sure about these tests. I can fix them by defining e.g. # exp_polar.is_integer but I'm not sure if that makes sense. assert gamma(3*exp_polar(I*pi)/4).is_nonnegative is False assert gamma(3*exp_polar(I*pi)/4).is_extended_nonpositive is True y = Symbol('y', nonpositive=True, integer=True) assert gamma(y).is_real == False y = Symbol('y', positive=True, noninteger=True) assert gamma(y).is_real == True assert gamma(-1.0, evaluate=False).is_real == False assert gamma(0, evaluate=False).is_real == False assert gamma(-2, evaluate=False).is_real == False def test_gamma_rewrite(): assert gamma(n).rewrite(factorial) == factorial(n - 1) def test_gamma_series(): assert gamma(x + 1).series(x, 0, 3) == \ 1 - EulerGamma*x + x**2*(EulerGamma**2/2 + pi**2/12) + O(x**3) assert gamma(x).series(x, -1, 3) == \ -1/(x + 1) + EulerGamma - 1 + (x + 1)*(-1 - pi**2/12 - EulerGamma**2/2 + \ EulerGamma) + (x + 1)**2*(-1 - pi**2/12 - EulerGamma**2/2 + EulerGamma**3/6 - \ polygamma(2, 1)/6 + EulerGamma*pi**2/12 + EulerGamma) + O((x + 1)**3, (x, -1)) def tn_branch(s, func): from sympy import I, pi, exp_polar from random import uniform c = uniform(1, 5) expr = func(s, c*exp_polar(I*pi)) - func(s, c*exp_polar(-I*pi)) eps = 1e-15 expr2 = func(s + eps, -c + eps*I) - func(s + eps, -c - eps*I) return abs(expr.n() - expr2.n()).n() < 1e-10 def test_lowergamma(): from sympy import meijerg, exp_polar, I, expint assert lowergamma(x, 0) == 0 assert lowergamma(x, y).diff(y) == y**(x - 1)*exp(-y) assert td(lowergamma(randcplx(), y), y) assert td(lowergamma(x, randcplx()), x) assert lowergamma(x, y).diff(x) == \ gamma(x)*digamma(x) - uppergamma(x, y)*log(y) \ - meijerg([], [1, 1], [0, 0, x], [], y) assert lowergamma(S.Half, x) == sqrt(pi)*erf(sqrt(x)) assert not lowergamma(S.Half - 3, x).has(lowergamma) assert not lowergamma(S.Half + 3, x).has(lowergamma) assert lowergamma(S.Half, x, evaluate=False).has(lowergamma) assert tn(lowergamma(S.Half + 3, x, evaluate=False), lowergamma(S.Half + 3, x), x) assert tn(lowergamma(S.Half - 3, x, evaluate=False), lowergamma(S.Half - 3, x), x) assert tn_branch(-3, lowergamma) assert tn_branch(-4, lowergamma) assert tn_branch(Rational(1, 3), lowergamma) assert tn_branch(pi, lowergamma) assert lowergamma(3, exp_polar(4*pi*I)*x) == lowergamma(3, x) assert lowergamma(y, exp_polar(5*pi*I)*x) == \ exp(4*I*pi*y)*lowergamma(y, x*exp_polar(pi*I)) assert lowergamma(-2, exp_polar(5*pi*I)*x) == \ lowergamma(-2, x*exp_polar(I*pi)) + 2*pi*I assert conjugate(lowergamma(x, y)) == lowergamma(conjugate(x), conjugate(y)) assert conjugate(lowergamma(x, 0)) == 0 assert unchanged(conjugate, lowergamma(x, -oo)) assert lowergamma(0, x)._eval_is_meromorphic(x, 0) == False assert lowergamma(S(1)/3, x)._eval_is_meromorphic(x, 0) == False assert lowergamma(1, x, evaluate=False)._eval_is_meromorphic(x, 0) == True assert lowergamma(x, x)._eval_is_meromorphic(x, 0) == False assert lowergamma(x + 1, x)._eval_is_meromorphic(x, 0) == False assert lowergamma(1/x, x)._eval_is_meromorphic(x, 0) == False assert lowergamma(0, x + 1)._eval_is_meromorphic(x, 0) == False assert lowergamma(S(1)/3, x + 1)._eval_is_meromorphic(x, 0) == True assert lowergamma(1, x + 1, evaluate=False)._eval_is_meromorphic(x, 0) == True assert lowergamma(x, x + 1)._eval_is_meromorphic(x, 0) == True assert lowergamma(x + 1, x + 1)._eval_is_meromorphic(x, 0) == True assert lowergamma(1/x, x + 1)._eval_is_meromorphic(x, 0) == False assert lowergamma(0, 1/x)._eval_is_meromorphic(x, 0) == False assert lowergamma(S(1)/3, 1/x)._eval_is_meromorphic(x, 0) == False assert lowergamma(1, 1/x, evaluate=False)._eval_is_meromorphic(x, 0) == False assert lowergamma(x, 1/x)._eval_is_meromorphic(x, 0) == False assert lowergamma(x + 1, 1/x)._eval_is_meromorphic(x, 0) == False assert lowergamma(1/x, 1/x)._eval_is_meromorphic(x, 0) == False assert lowergamma(x, 2).series(x, oo, 3) == \ 2**x*(1 + 2/(x + 1))*exp(-2)/x + O(exp(x*log(2))/x**3, (x, oo)) assert lowergamma( x, y).rewrite(expint) == -y**x*expint(-x + 1, y) + gamma(x) k = Symbol('k', integer=True) assert lowergamma( k, y).rewrite(expint) == -y**k*expint(-k + 1, y) + gamma(k) k = Symbol('k', integer=True, positive=False) assert lowergamma(k, y).rewrite(expint) == lowergamma(k, y) assert lowergamma(x, y).rewrite(uppergamma) == gamma(x) - uppergamma(x, y) assert lowergamma(70, 6) == factorial(69) - 69035724522603011058660187038367026272747334489677105069435923032634389419656200387949342530805432320 * exp(-6) assert (lowergamma(S(77) / 2, 6) - lowergamma(S(77) / 2, 6, evaluate=False)).evalf() < 1e-16 assert (lowergamma(-S(77) / 2, 6) - lowergamma(-S(77) / 2, 6, evaluate=False)).evalf() < 1e-16 def test_uppergamma(): from sympy import meijerg, exp_polar, I, expint assert uppergamma(4, 0) == 6 assert uppergamma(x, y).diff(y) == -y**(x - 1)*exp(-y) assert td(uppergamma(randcplx(), y), y) assert uppergamma(x, y).diff(x) == \ uppergamma(x, y)*log(y) + meijerg([], [1, 1], [0, 0, x], [], y) assert td(uppergamma(x, randcplx()), x) p = Symbol('p', positive=True) assert uppergamma(0, p) == -Ei(-p) assert uppergamma(p, 0) == gamma(p) assert uppergamma(S.Half, x) == sqrt(pi)*erfc(sqrt(x)) assert not uppergamma(S.Half - 3, x).has(uppergamma) assert not uppergamma(S.Half + 3, x).has(uppergamma) assert uppergamma(S.Half, x, evaluate=False).has(uppergamma) assert tn(uppergamma(S.Half + 3, x, evaluate=False), uppergamma(S.Half + 3, x), x) assert tn(uppergamma(S.Half - 3, x, evaluate=False), uppergamma(S.Half - 3, x), x) assert unchanged(uppergamma, x, -oo) assert unchanged(uppergamma, x, 0) assert tn_branch(-3, uppergamma) assert tn_branch(-4, uppergamma) assert tn_branch(Rational(1, 3), uppergamma) assert tn_branch(pi, uppergamma) assert uppergamma(3, exp_polar(4*pi*I)*x) == uppergamma(3, x) assert uppergamma(y, exp_polar(5*pi*I)*x) == \ exp(4*I*pi*y)*uppergamma(y, x*exp_polar(pi*I)) + \ gamma(y)*(1 - exp(4*pi*I*y)) assert uppergamma(-2, exp_polar(5*pi*I)*x) == \ uppergamma(-2, x*exp_polar(I*pi)) - 2*pi*I assert uppergamma(-2, x) == expint(3, x)/x**2 assert conjugate(uppergamma(x, y)) == uppergamma(conjugate(x), conjugate(y)) assert unchanged(conjugate, uppergamma(x, -oo)) assert uppergamma(x, y).rewrite(expint) == y**x*expint(-x + 1, y) assert uppergamma(x, y).rewrite(lowergamma) == gamma(x) - lowergamma(x, y) assert uppergamma(70, 6) == 69035724522603011058660187038367026272747334489677105069435923032634389419656200387949342530805432320*exp(-6) assert (uppergamma(S(77) / 2, 6) - uppergamma(S(77) / 2, 6, evaluate=False)).evalf() < 1e-16 assert (uppergamma(-S(77) / 2, 6) - uppergamma(-S(77) / 2, 6, evaluate=False)).evalf() < 1e-16 def test_polygamma(): from sympy import I assert polygamma(n, nan) is nan assert polygamma(0, oo) is oo assert polygamma(0, -oo) is oo assert polygamma(0, I*oo) is oo assert polygamma(0, -I*oo) is oo assert polygamma(1, oo) == 0 assert polygamma(5, oo) == 0 assert polygamma(0, -9) is zoo assert polygamma(0, -9) is zoo assert polygamma(0, -1) is zoo assert polygamma(0, 0) is zoo assert polygamma(0, 1) == -EulerGamma assert polygamma(0, 7) == Rational(49, 20) - EulerGamma assert polygamma(1, 1) == pi**2/6 assert polygamma(1, 2) == pi**2/6 - 1 assert polygamma(1, 3) == pi**2/6 - Rational(5, 4) assert polygamma(3, 1) == pi**4 / 15 assert polygamma(3, 5) == 6*(Rational(-22369, 20736) + pi**4/90) assert polygamma(5, 1) == 8 * pi**6 / 63 assert polygamma(1, S.Half) == pi**2 / 2 assert polygamma(2, S.Half) == -14*zeta(3) assert polygamma(11, S.Half) == 176896*pi**12 def t(m, n): x = S(m)/n r = polygamma(0, x) if r.has(polygamma): return False return abs(polygamma(0, x.n()).n() - r.n()).n() < 1e-10 assert t(1, 2) assert t(3, 2) assert t(-1, 2) assert t(1, 4) assert t(-3, 4) assert t(1, 3) assert t(4, 3) assert t(3, 4) assert t(2, 3) assert t(123, 5) assert polygamma(0, x).rewrite(zeta) == polygamma(0, x) assert polygamma(1, x).rewrite(zeta) == zeta(2, x) assert polygamma(2, x).rewrite(zeta) == -2*zeta(3, x) assert polygamma(I, 2).rewrite(zeta) == polygamma(I, 2) n1 = Symbol('n1') n2 = Symbol('n2', real=True) n3 = Symbol('n3', integer=True) n4 = Symbol('n4', positive=True) n5 = Symbol('n5', positive=True, integer=True) assert polygamma(n1, x).rewrite(zeta) == polygamma(n1, x) assert polygamma(n2, x).rewrite(zeta) == polygamma(n2, x) assert polygamma(n3, x).rewrite(zeta) == polygamma(n3, x) assert polygamma(n4, x).rewrite(zeta) == polygamma(n4, x) assert polygamma(n5, x).rewrite(zeta) == (-1)**(n5 + 1) * factorial(n5) * zeta(n5 + 1, x) assert polygamma(3, 7*x).diff(x) == 7*polygamma(4, 7*x) assert polygamma(0, x).rewrite(harmonic) == harmonic(x - 1) - EulerGamma assert polygamma(2, x).rewrite(harmonic) == 2*harmonic(x - 1, 3) - 2*zeta(3) ni = Symbol("n", integer=True) assert polygamma(ni, x).rewrite(harmonic) == (-1)**(ni + 1)*(-harmonic(x - 1, ni + 1) + zeta(ni + 1))*factorial(ni) # Polygamma of non-negative integer order is unbranched: from sympy import exp_polar k = Symbol('n', integer=True, nonnegative=True) assert polygamma(k, exp_polar(2*I*pi)*x) == polygamma(k, x) # but negative integers are branched! k = Symbol('n', integer=True) assert polygamma(k, exp_polar(2*I*pi)*x).args == (k, exp_polar(2*I*pi)*x) # Polygamma of order -1 is loggamma: assert polygamma(-1, x) == loggamma(x) # But smaller orders are iterated integrals and don't have a special name assert polygamma(-2, x).func is polygamma # Test a bug assert polygamma(0, -x).expand(func=True) == polygamma(0, -x) assert polygamma(2, 2.5).is_positive == False assert polygamma(2, -2.5).is_positive == False assert polygamma(3, 2.5).is_positive == True assert polygamma(3, -2.5).is_positive is True assert polygamma(-2, -2.5).is_positive is None assert polygamma(-3, -2.5).is_positive is None assert polygamma(2, 2.5).is_negative == True assert polygamma(3, 2.5).is_negative == False assert polygamma(3, -2.5).is_negative == False assert polygamma(2, -2.5).is_negative is True assert polygamma(-2, -2.5).is_negative is None assert polygamma(-3, -2.5).is_negative is None assert polygamma(I, 2).is_positive is None assert polygamma(I, 3).is_negative is None # issue 17350 assert polygamma(pi, 3).evalf() == polygamma(pi, 3) assert (I*polygamma(I, pi)).as_real_imag() == \ (-im(polygamma(I, pi)), re(polygamma(I, pi))) assert (tanh(polygamma(I, 1))).rewrite(exp) == \ (exp(polygamma(I, 1)) - exp(-polygamma(I, 1)))/(exp(polygamma(I, 1)) + exp(-polygamma(I, 1))) assert (I / polygamma(I, 4)).rewrite(exp) == \ I*sqrt(re(polygamma(I, 4))**2 + im(polygamma(I, 4))**2)\ /((re(polygamma(I, 4)) + I*im(polygamma(I, 4)))*Abs(polygamma(I, 4))) assert unchanged(polygamma, 2.3, 1.0) # issue 12569 assert unchanged(im, polygamma(0, I)) assert polygamma(Symbol('a', positive=True), Symbol('b', positive=True)).is_real is True assert polygamma(0, I).is_real is None def test_polygamma_expand_func(): assert polygamma(0, x).expand(func=True) == polygamma(0, x) assert polygamma(0, 2*x).expand(func=True) == \ polygamma(0, x)/2 + polygamma(0, S.Half + x)/2 + log(2) assert polygamma(1, 2*x).expand(func=True) == \ polygamma(1, x)/4 + polygamma(1, S.Half + x)/4 assert polygamma(2, x).expand(func=True) == \ polygamma(2, x) assert polygamma(0, -1 + x).expand(func=True) == \ polygamma(0, x) - 1/(x - 1) assert polygamma(0, 1 + x).expand(func=True) == \ 1/x + polygamma(0, x ) assert polygamma(0, 2 + x).expand(func=True) == \ 1/x + 1/(1 + x) + polygamma(0, x) assert polygamma(0, 3 + x).expand(func=True) == \ polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) assert polygamma(0, 4 + x).expand(func=True) == \ polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x) assert polygamma(1, 1 + x).expand(func=True) == \ polygamma(1, x) - 1/x**2 assert polygamma(1, 2 + x).expand(func=True, multinomial=False) == \ polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 assert polygamma(1, 3 + x).expand(func=True, multinomial=False) == \ polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2 assert polygamma(1, 4 + x).expand(func=True, multinomial=False) == \ polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \ 1/(2 + x)**2 - 1/(3 + x)**2 assert polygamma(0, x + y).expand(func=True) == \ polygamma(0, x + y) assert polygamma(1, x + y).expand(func=True) == \ polygamma(1, x + y) assert polygamma(1, 3 + 4*x + y).expand(func=True, multinomial=False) == \ polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \ 1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2 assert polygamma(3, 3 + 4*x + y).expand(func=True, multinomial=False) == \ polygamma(3, y + 4*x) - 6/(y + 4*x)**4 - \ 6/(1 + y + 4*x)**4 - 6/(2 + y + 4*x)**4 assert polygamma(3, 4*x + y + 1).expand(func=True, multinomial=False) == \ polygamma(3, y + 4*x) - 6/(y + 4*x)**4 e = polygamma(3, 4*x + y + Rational(3, 2)) assert e.expand(func=True) == e e = polygamma(3, x + y + Rational(3, 4)) assert e.expand(func=True, basic=False) == e def test_digamma(): from sympy import I assert digamma(nan) == nan assert digamma(oo) == oo assert digamma(-oo) == oo assert digamma(I*oo) == oo assert digamma(-I*oo) == oo assert digamma(-9) == zoo assert digamma(-9) == zoo assert digamma(-1) == zoo assert digamma(0) == zoo assert digamma(1) == -EulerGamma assert digamma(7) == Rational(49, 20) - EulerGamma def t(m, n): x = S(m)/n r = digamma(x) if r.has(digamma): return False return abs(digamma(x.n()).n() - r.n()).n() < 1e-10 assert t(1, 2) assert t(3, 2) assert t(-1, 2) assert t(1, 4) assert t(-3, 4) assert t(1, 3) assert t(4, 3) assert t(3, 4) assert t(2, 3) assert t(123, 5) assert digamma(x).rewrite(zeta) == polygamma(0, x) assert digamma(x).rewrite(harmonic) == harmonic(x - 1) - EulerGamma assert digamma(I).is_real is None assert digamma(x,evaluate=False).fdiff() == polygamma(1, x) assert digamma(x,evaluate=False).is_real is None assert digamma(x,evaluate=False).is_positive is None assert digamma(x,evaluate=False).is_negative is None assert digamma(x,evaluate=False).rewrite(polygamma) == polygamma(0, x) def test_digamma_expand_func(): assert digamma(x).expand(func=True) == polygamma(0, x) assert digamma(2*x).expand(func=True) == \ polygamma(0, x)/2 + polygamma(0, Rational(1, 2) + x)/2 + log(2) assert digamma(-1 + x).expand(func=True) == \ polygamma(0, x) - 1/(x - 1) assert digamma(1 + x).expand(func=True) == \ 1/x + polygamma(0, x ) assert digamma(2 + x).expand(func=True) == \ 1/x + 1/(1 + x) + polygamma(0, x) assert digamma(3 + x).expand(func=True) == \ polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) assert digamma(4 + x).expand(func=True) == \ polygamma(0, x) + 1/x + 1/(1 + x) + 1/(2 + x) + 1/(3 + x) assert digamma(x + y).expand(func=True) == \ polygamma(0, x + y) def test_trigamma(): assert trigamma(nan) == nan assert trigamma(oo) == 0 assert trigamma(1) == pi**2/6 assert trigamma(2) == pi**2/6 - 1 assert trigamma(3) == pi**2/6 - Rational(5, 4) assert trigamma(x, evaluate=False).rewrite(zeta) == zeta(2, x) assert trigamma(x, evaluate=False).rewrite(harmonic) == \ trigamma(x).rewrite(polygamma).rewrite(harmonic) assert trigamma(x,evaluate=False).fdiff() == polygamma(2, x) assert trigamma(x,evaluate=False).is_real is None assert trigamma(x,evaluate=False).is_positive is None assert trigamma(x,evaluate=False).is_negative is None assert trigamma(x,evaluate=False).rewrite(polygamma) == polygamma(1, x) def test_trigamma_expand_func(): assert trigamma(2*x).expand(func=True) == \ polygamma(1, x)/4 + polygamma(1, Rational(1, 2) + x)/4 assert trigamma(1 + x).expand(func=True) == \ polygamma(1, x) - 1/x**2 assert trigamma(2 + x).expand(func=True, multinomial=False) == \ polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 assert trigamma(3 + x).expand(func=True, multinomial=False) == \ polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - 1/(2 + x)**2 assert trigamma(4 + x).expand(func=True, multinomial=False) == \ polygamma(1, x) - 1/x**2 - 1/(1 + x)**2 - \ 1/(2 + x)**2 - 1/(3 + x)**2 assert trigamma(x + y).expand(func=True) == \ polygamma(1, x + y) assert trigamma(3 + 4*x + y).expand(func=True, multinomial=False) == \ polygamma(1, y + 4*x) - 1/(y + 4*x)**2 - \ 1/(1 + y + 4*x)**2 - 1/(2 + y + 4*x)**2 def test_loggamma(): raises(TypeError, lambda: loggamma(2, 3)) raises(ArgumentIndexError, lambda: loggamma(x).fdiff(2)) assert loggamma(-1) is oo assert loggamma(-2) is oo assert loggamma(0) is oo assert loggamma(1) == 0 assert loggamma(2) == 0 assert loggamma(3) == log(2) assert loggamma(4) == log(6) n = Symbol("n", integer=True, positive=True) assert loggamma(n) == log(gamma(n)) assert loggamma(-n) is oo assert loggamma(n/2) == log(2**(-n + 1)*sqrt(pi)*gamma(n)/gamma(n/2 + S.Half)) from sympy import I assert loggamma(oo) is oo assert loggamma(-oo) is zoo assert loggamma(I*oo) is zoo assert loggamma(-I*oo) is zoo assert loggamma(zoo) is zoo assert loggamma(nan) is nan L = loggamma(Rational(16, 3)) E = -5*log(3) + loggamma(Rational(1, 3)) + log(4) + log(7) + log(10) + log(13) assert expand_func(L).doit() == E assert L.n() == E.n() L = loggamma(Rational(19, 4)) E = -4*log(4) + loggamma(Rational(3, 4)) + log(3) + log(7) + log(11) + log(15) assert expand_func(L).doit() == E assert L.n() == E.n() L = loggamma(Rational(23, 7)) E = -3*log(7) + log(2) + loggamma(Rational(2, 7)) + log(9) + log(16) assert expand_func(L).doit() == E assert L.n() == E.n() L = loggamma(Rational(19, 4) - 7) E = -log(9) - log(5) + loggamma(Rational(3, 4)) + 3*log(4) - 3*I*pi assert expand_func(L).doit() == E assert L.n() == E.n() L = loggamma(Rational(23, 7) - 6) E = -log(19) - log(12) - log(5) + loggamma(Rational(2, 7)) + 3*log(7) - 3*I*pi assert expand_func(L).doit() == E assert L.n() == E.n() assert loggamma(x).diff(x) == polygamma(0, x) s1 = loggamma(1/(x + sin(x)) + cos(x)).nseries(x, n=4) s2 = (-log(2*x) - 1)/(2*x) - log(x/pi)/2 + (4 - log(2*x))*x/24 + O(x**2) + \ log(x)*x**2/2 assert (s1 - s2).expand(force=True).removeO() == 0 s1 = loggamma(1/x).series(x) s2 = (1/x - S.Half)*log(1/x) - 1/x + log(2*pi)/2 + \ x/12 - x**3/360 + x**5/1260 + O(x**7) assert ((s1 - s2).expand(force=True)).removeO() == 0 assert loggamma(x).rewrite('intractable') == log(gamma(x)) s1 = loggamma(x).series(x).cancel() assert s1 == -log(x) - EulerGamma*x + pi**2*x**2/12 + x**3*polygamma(2, 1)/6 + \ pi**4*x**4/360 + x**5*polygamma(4, 1)/120 + O(x**6) assert s1 == loggamma(x).rewrite('intractable').series(x).cancel() assert conjugate(loggamma(x)) == loggamma(conjugate(x)) assert conjugate(loggamma(0)) is oo assert conjugate(loggamma(1)) == loggamma(conjugate(1)) assert conjugate(loggamma(-oo)) == conjugate(zoo) assert loggamma(Symbol('v', positive=True)).is_real is True assert loggamma(Symbol('v', zero=True)).is_real is False assert loggamma(Symbol('v', negative=True)).is_real is False assert loggamma(Symbol('v', nonpositive=True)).is_real is False assert loggamma(Symbol('v', nonnegative=True)).is_real is None assert loggamma(Symbol('v', imaginary=True)).is_real is None assert loggamma(Symbol('v', real=True)).is_real is None assert loggamma(Symbol('v')).is_real is None assert loggamma(S.Half).is_real is True assert loggamma(0).is_real is False assert loggamma(Rational(-1, 2)).is_real is False assert loggamma(I).is_real is None assert loggamma(2 + 3*I).is_real is None def tN(N, M): assert loggamma(1/x)._eval_nseries(x, n=N).getn() == M tN(0, 0) tN(1, 1) tN(2, 2) tN(3, 3) tN(4, 4) tN(5, 5) def test_polygamma_expansion(): # A. & S., pa. 259 and 260 assert polygamma(0, 1/x).nseries(x, n=3) == \ -log(x) - x/2 - x**2/12 + O(x**3) assert polygamma(1, 1/x).series(x, n=5) == \ x + x**2/2 + x**3/6 + O(x**5) assert polygamma(3, 1/x).nseries(x, n=11) == \ 2*x**3 + 3*x**4 + 2*x**5 - x**7 + 4*x**9/3 + O(x**11) def test_issue_8657(): n = Symbol('n', negative=True, integer=True) m = Symbol('m', integer=True) o = Symbol('o', positive=True) p = Symbol('p', negative=True, integer=False) assert gamma(n).is_real is False assert gamma(m).is_real is None assert gamma(o).is_real is True assert gamma(p).is_real is True assert gamma(w).is_real is None def test_issue_8524(): x = Symbol('x', positive=True) y = Symbol('y', negative=True) z = Symbol('z', positive=False) p = Symbol('p', negative=False) q = Symbol('q', integer=True) r = Symbol('r', integer=False) e = Symbol('e', even=True, negative=True) assert gamma(x).is_positive is True assert gamma(y).is_positive is None assert gamma(z).is_positive is None assert gamma(p).is_positive is None assert gamma(q).is_positive is None assert gamma(r).is_positive is None assert gamma(e + S.Half).is_positive is True assert gamma(e - S.Half).is_positive is False def test_issue_14450(): assert uppergamma(Rational(3, 8), x).evalf() == uppergamma(Rational(3, 8), x) assert lowergamma(x, Rational(3, 8)).evalf() == lowergamma(x, Rational(3, 8)) # some values from Wolfram Alpha for comparison assert abs(uppergamma(Rational(3, 8), 2).evalf() - 0.07105675881) < 1e-9 assert abs(lowergamma(Rational(3, 8), 2).evalf() - 2.2993794256) < 1e-9 def test_issue_14528(): k = Symbol('k', integer=True, nonpositive=True) assert isinstance(gamma(k), gamma) def test_multigamma(): from sympy import Product p = Symbol('p') _k = Dummy('_k') assert multigamma(x, p).dummy_eq(pi**(p*(p - 1)/4)*\ Product(gamma(x + (1 - _k)/2), (_k, 1, p))) assert conjugate(multigamma(x, p)).dummy_eq(pi**((conjugate(p) - 1)*\ conjugate(p)/4)*Product(gamma(conjugate(x) + (1-conjugate(_k))/2), (_k, 1, p))) assert conjugate(multigamma(x, 1)) == gamma(conjugate(x)) p = Symbol('p', positive=True) assert conjugate(multigamma(x, p)).dummy_eq(pi**((p - 1)*p/4)*\ Product(gamma(conjugate(x) + (1-conjugate(_k))/2), (_k, 1, p))) assert multigamma(nan, 1) is nan assert multigamma(oo, 1).doit() is oo assert multigamma(1, 1) == 1 assert multigamma(2, 1) == 1 assert multigamma(3, 1) == 2 assert multigamma(102, 1) == factorial(101) assert multigamma(S.Half, 1) == sqrt(pi) assert multigamma(1, 2) == pi assert multigamma(2, 2) == pi/2 assert multigamma(1, 3) is zoo assert multigamma(2, 3) == pi**2/2 assert multigamma(3, 3) == 3*pi**2/2 assert multigamma(x, 1).diff(x) == gamma(x)*polygamma(0, x) assert multigamma(x, 2).diff(x) == sqrt(pi)*gamma(x)*gamma(x - S.Half)*\ polygamma(0, x) + sqrt(pi)*gamma(x)*gamma(x - S.Half)*polygamma(0, x - S.Half) assert multigamma(x - 1, 1).expand(func=True) == gamma(x)/(x - 1) assert multigamma(x + 2, 1).expand(func=True, mul=False) == x*(x + 1)*\ gamma(x) assert multigamma(x - 1, 2).expand(func=True) == sqrt(pi)*gamma(x)*\ gamma(x + S.Half)/(x**3 - 3*x**2 + x*Rational(11, 4) - Rational(3, 4)) assert multigamma(x - 1, 3).expand(func=True) == pi**Rational(3, 2)*gamma(x)**2*\ gamma(x + S.Half)/(x**5 - 6*x**4 + 55*x**3/4 - 15*x**2 + x*Rational(31, 4) - Rational(3, 2)) assert multigamma(n, 1).rewrite(factorial) == factorial(n - 1) assert multigamma(n, 2).rewrite(factorial) == sqrt(pi)*\ factorial(n - Rational(3, 2))*factorial(n - 1) assert multigamma(n, 3).rewrite(factorial) == pi**Rational(3, 2)*\ factorial(n - 2)*factorial(n - Rational(3, 2))*factorial(n - 1) assert multigamma(Rational(-1, 2), 3, evaluate=False).is_real == False assert multigamma(S.Half, 3, evaluate=False).is_real == False assert multigamma(0, 1, evaluate=False).is_real == False assert multigamma(1, 3, evaluate=False).is_real == False assert multigamma(-1.0, 3, evaluate=False).is_real == False assert multigamma(0.7, 3, evaluate=False).is_real == True assert multigamma(3, 3, evaluate=False).is_real == True def test_gamma_as_leading_term(): assert gamma(x).as_leading_term(x) == 1/x assert gamma(2 + x).as_leading_term(x) == S(1) assert gamma(cos(x)).as_leading_term(x) == S(1) assert gamma(sin(x)).as_leading_term(x) == 1/x sympy-sympy-1.9/sympy/functions/special/tests/test_hyper.py000066400000000000000000000357221412543434000244470ustar00rootroot00000000000000from sympy import (hyper, meijerg, S, Tuple, pi, I, exp, log, Rational, cos, sqrt, symbols, oo, Derivative, gamma, O, appellf1) from sympy.abc import x, z, k from sympy.series.limits import limit from sympy.testing.pytest import raises, slow from sympy.testing.randtest import ( random_complex_number as randcplx, verify_numerically as tn, test_derivative_numerically as td) def test_TupleParametersBase(): # test that our implementation of the chain rule works p = hyper((), (), z**2) assert p.diff(z) == p*2*z def test_hyper(): raises(TypeError, lambda: hyper(1, 2, z)) assert hyper((1, 2), (1,), z) == hyper(Tuple(1, 2), Tuple(1), z) h = hyper((1, 2), (3, 4, 5), z) assert h.ap == Tuple(1, 2) assert h.bq == Tuple(3, 4, 5) assert h.argument == z assert h.is_commutative is True # just a few checks to make sure that all arguments go where they should assert tn(hyper(Tuple(), Tuple(), z), exp(z), z) assert tn(z*hyper((1, 1), Tuple(2), -z), log(1 + z), z) # differentiation h = hyper( (randcplx(), randcplx(), randcplx()), (randcplx(), randcplx()), z) assert td(h, z) a1, a2, b1, b2, b3 = symbols('a1:3, b1:4') assert hyper((a1, a2), (b1, b2, b3), z).diff(z) == \ a1*a2/(b1*b2*b3) * hyper((a1 + 1, a2 + 1), (b1 + 1, b2 + 1, b3 + 1), z) # differentiation wrt parameters is not supported assert hyper([z], [], z).diff(z) == Derivative(hyper([z], [], z), z) # hyper is unbranched wrt parameters from sympy import polar_lift assert hyper([polar_lift(z)], [polar_lift(k)], polar_lift(x)) == \ hyper([z], [k], polar_lift(x)) # hyper does not automatically evaluate anyway, but the test is to make # sure that the evaluate keyword is accepted assert hyper((1, 2), (1,), z, evaluate=False).func is hyper def test_expand_func(): # evaluation at 1 of Gauss' hypergeometric function: from sympy.abc import a, b, c from sympy import gamma, expand_func a1, b1, c1 = randcplx(), randcplx(), randcplx() + 5 assert expand_func(hyper([a, b], [c], 1)) == \ gamma(c)*gamma(-a - b + c)/(gamma(-a + c)*gamma(-b + c)) assert abs(expand_func(hyper([a1, b1], [c1], 1)).n() - hyper([a1, b1], [c1], 1).n()) < 1e-10 # hyperexpand wrapper for hyper: assert expand_func(hyper([], [], z)) == exp(z) assert expand_func(hyper([1, 2, 3], [], z)) == hyper([1, 2, 3], [], z) assert expand_func(meijerg([[1, 1], []], [[1], [0]], z)) == log(z + 1) assert expand_func(meijerg([[1, 1], []], [[], []], z)) == \ meijerg([[1, 1], []], [[], []], z) def replace_dummy(expr, sym): from sympy import Dummy dum = expr.atoms(Dummy) if not dum: return expr assert len(dum) == 1 return expr.xreplace({dum.pop(): sym}) def test_hyper_rewrite_sum(): from sympy import RisingFactorial, factorial, Dummy, Sum _k = Dummy("k") assert replace_dummy(hyper((1, 2), (1, 3), x).rewrite(Sum), _k) == \ Sum(x**_k / factorial(_k) * RisingFactorial(2, _k) / RisingFactorial(3, _k), (_k, 0, oo)) assert hyper((1, 2, 3), (-1, 3), z).rewrite(Sum) == \ hyper((1, 2, 3), (-1, 3), z) def test_radius_of_convergence(): assert hyper((1, 2), [3], z).radius_of_convergence == 1 assert hyper((1, 2), [3, 4], z).radius_of_convergence is oo assert hyper((1, 2, 3), [4], z).radius_of_convergence == 0 assert hyper((0, 1, 2), [4], z).radius_of_convergence is oo assert hyper((-1, 1, 2), [-4], z).radius_of_convergence == 0 assert hyper((-1, -2, 2), [-1], z).radius_of_convergence is oo assert hyper((-1, 2), [-1, -2], z).radius_of_convergence == 0 assert hyper([-1, 1, 3], [-2, 2], z).radius_of_convergence == 1 assert hyper([-1, 1], [-2, 2], z).radius_of_convergence is oo assert hyper([-1, 1, 3], [-2], z).radius_of_convergence == 0 assert hyper((-1, 2, 3, 4), [], z).radius_of_convergence is oo assert hyper([1, 1], [3], 1).convergence_statement == True assert hyper([1, 1], [2], 1).convergence_statement == False assert hyper([1, 1], [2], -1).convergence_statement == True assert hyper([1, 1], [1], -1).convergence_statement == False def test_meijer(): raises(TypeError, lambda: meijerg(1, z)) raises(TypeError, lambda: meijerg(((1,), (2,)), (3,), (4,), z)) assert meijerg(((1, 2), (3,)), ((4,), (5,)), z) == \ meijerg(Tuple(1, 2), Tuple(3), Tuple(4), Tuple(5), z) g = meijerg((1, 2), (3, 4, 5), (6, 7, 8, 9), (10, 11, 12, 13, 14), z) assert g.an == Tuple(1, 2) assert g.ap == Tuple(1, 2, 3, 4, 5) assert g.aother == Tuple(3, 4, 5) assert g.bm == Tuple(6, 7, 8, 9) assert g.bq == Tuple(6, 7, 8, 9, 10, 11, 12, 13, 14) assert g.bother == Tuple(10, 11, 12, 13, 14) assert g.argument == z assert g.nu == 75 assert g.delta == -1 assert g.is_commutative is True assert g.is_number is False #issue 13071 assert meijerg([[],[]], [[S.Half],[0]], 1).is_number is True assert meijerg([1, 2], [3], [4], [5], z).delta == S.Half # just a few checks to make sure that all arguments go where they should assert tn(meijerg(Tuple(), Tuple(), Tuple(0), Tuple(), -z), exp(z), z) assert tn(sqrt(pi)*meijerg(Tuple(), Tuple(), Tuple(0), Tuple(S.Half), z**2/4), cos(z), z) assert tn(meijerg(Tuple(1, 1), Tuple(), Tuple(1), Tuple(0), z), log(1 + z), z) # test exceptions raises(ValueError, lambda: meijerg(((3, 1), (2,)), ((oo,), (2, 0)), x)) raises(ValueError, lambda: meijerg(((3, 1), (2,)), ((1,), (2, 0)), x)) # differentiation g = meijerg((randcplx(),), (randcplx() + 2*I,), Tuple(), (randcplx(), randcplx()), z) assert td(g, z) g = meijerg(Tuple(), (randcplx(),), Tuple(), (randcplx(), randcplx()), z) assert td(g, z) g = meijerg(Tuple(), Tuple(), Tuple(randcplx()), Tuple(randcplx(), randcplx()), z) assert td(g, z) a1, a2, b1, b2, c1, c2, d1, d2 = symbols('a1:3, b1:3, c1:3, d1:3') assert meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z).diff(z) == \ (meijerg((a1 - 1, a2), (b1, b2), (c1, c2), (d1, d2), z) + (a1 - 1)*meijerg((a1, a2), (b1, b2), (c1, c2), (d1, d2), z))/z assert meijerg([z, z], [], [], [], z).diff(z) == \ Derivative(meijerg([z, z], [], [], [], z), z) # meijerg is unbranched wrt parameters from sympy import polar_lift as pl assert meijerg([pl(a1)], [pl(a2)], [pl(b1)], [pl(b2)], pl(z)) == \ meijerg([a1], [a2], [b1], [b2], pl(z)) # integrand from sympy.abc import a, b, c, d, s assert meijerg([a], [b], [c], [d], z).integrand(s) == \ z**s*gamma(c - s)*gamma(-a + s + 1)/(gamma(b - s)*gamma(-d + s + 1)) def test_meijerg_derivative(): assert meijerg([], [1, 1], [0, 0, x], [], z).diff(x) == \ log(z)*meijerg([], [1, 1], [0, 0, x], [], z) \ + 2*meijerg([], [1, 1, 1], [0, 0, x, 0], [], z) y = randcplx() a = 5 # mpmath chokes with non-real numbers, and Mod1 with floats assert td(meijerg([x], [], [], [], y), x) assert td(meijerg([x**2], [], [], [], y), x) assert td(meijerg([], [x], [], [], y), x) assert td(meijerg([], [], [x], [], y), x) assert td(meijerg([], [], [], [x], y), x) assert td(meijerg([x], [a], [a + 1], [], y), x) assert td(meijerg([x], [a + 1], [a], [], y), x) assert td(meijerg([x, a], [], [], [a + 1], y), x) assert td(meijerg([x, a + 1], [], [], [a], y), x) b = Rational(3, 2) assert td(meijerg([a + 2], [b], [b - 3, x], [a], y), x) def test_meijerg_period(): assert meijerg([], [1], [0], [], x).get_period() == 2*pi assert meijerg([1], [], [], [0], x).get_period() == 2*pi assert meijerg([], [], [0], [], x).get_period() == 2*pi # exp(x) assert meijerg( [], [], [0], [S.Half], x).get_period() == 2*pi # cos(sqrt(x)) assert meijerg( [], [], [S.Half], [0], x).get_period() == 4*pi # sin(sqrt(x)) assert meijerg([1, 1], [], [1], [0], x).get_period() is oo # log(1 + x) def test_hyper_unpolarify(): from sympy import exp_polar a = exp_polar(2*pi*I)*x b = x assert hyper([], [], a).argument == b assert hyper([0], [], a).argument == a assert hyper([0], [0], a).argument == b assert hyper([0, 1], [0], a).argument == a assert hyper([0, 1], [0], exp_polar(2*pi*I)).argument == 1 @slow def test_hyperrep(): from sympy.functions.special.hyper import (HyperRep, HyperRep_atanh, HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1, HyperRep_asin2, HyperRep_sqrts1, HyperRep_sqrts2, HyperRep_log2, HyperRep_cosasin, HyperRep_sinasin) # First test the base class works. from sympy import Piecewise, exp_polar a, b, c, d, z = symbols('a b c d z') class myrep(HyperRep): @classmethod def _expr_small(cls, x): return a @classmethod def _expr_small_minus(cls, x): return b @classmethod def _expr_big(cls, x, n): return c*n @classmethod def _expr_big_minus(cls, x, n): return d*n assert myrep(z).rewrite('nonrep') == Piecewise((0, abs(z) > 1), (a, True)) assert myrep(exp_polar(I*pi)*z).rewrite('nonrep') == \ Piecewise((0, abs(z) > 1), (b, True)) assert myrep(exp_polar(2*I*pi)*z).rewrite('nonrep') == \ Piecewise((c, abs(z) > 1), (a, True)) assert myrep(exp_polar(3*I*pi)*z).rewrite('nonrep') == \ Piecewise((d, abs(z) > 1), (b, True)) assert myrep(exp_polar(4*I*pi)*z).rewrite('nonrep') == \ Piecewise((2*c, abs(z) > 1), (a, True)) assert myrep(exp_polar(5*I*pi)*z).rewrite('nonrep') == \ Piecewise((2*d, abs(z) > 1), (b, True)) assert myrep(z).rewrite('nonrepsmall') == a assert myrep(exp_polar(I*pi)*z).rewrite('nonrepsmall') == b def t(func, hyp, z): """ Test that func is a valid representation of hyp. """ # First test that func agrees with hyp for small z if not tn(func.rewrite('nonrepsmall'), hyp, z, a=Rational(-1, 2), b=Rational(-1, 2), c=S.Half, d=S.Half): return False # Next check that the two small representations agree. if not tn( func.rewrite('nonrepsmall').subs( z, exp_polar(I*pi)*z).replace(exp_polar, exp), func.subs(z, exp_polar(I*pi)*z).rewrite('nonrepsmall'), z, a=Rational(-1, 2), b=Rational(-1, 2), c=S.Half, d=S.Half): return False # Next check continuity along exp_polar(I*pi)*t expr = func.subs(z, exp_polar(I*pi)*z).rewrite('nonrep') if abs(expr.subs(z, 1 + 1e-15).n() - expr.subs(z, 1 - 1e-15).n()) > 1e-10: return False # Finally check continuity of the big reps. def dosubs(func, a, b): rv = func.subs(z, exp_polar(a)*z).rewrite('nonrep') return rv.subs(z, exp_polar(b)*z).replace(exp_polar, exp) for n in [0, 1, 2, 3, 4, -1, -2, -3, -4]: expr1 = dosubs(func, 2*I*pi*n, I*pi/2) expr2 = dosubs(func, 2*I*pi*n + I*pi, -I*pi/2) if not tn(expr1, expr2, z): return False expr1 = dosubs(func, 2*I*pi*(n + 1), -I*pi/2) expr2 = dosubs(func, 2*I*pi*n + I*pi, I*pi/2) if not tn(expr1, expr2, z): return False return True # Now test the various representatives. a = Rational(1, 3) assert t(HyperRep_atanh(z), hyper([S.Half, 1], [Rational(3, 2)], z), z) assert t(HyperRep_power1(a, z), hyper([-a], [], z), z) assert t(HyperRep_power2(a, z), hyper([a, a - S.Half], [2*a], z), z) assert t(HyperRep_log1(z), -z*hyper([1, 1], [2], z), z) assert t(HyperRep_asin1(z), hyper([S.Half, S.Half], [Rational(3, 2)], z), z) assert t(HyperRep_asin2(z), hyper([1, 1], [Rational(3, 2)], z), z) assert t(HyperRep_sqrts1(a, z), hyper([-a, S.Half - a], [S.Half], z), z) assert t(HyperRep_sqrts2(a, z), -2*z/(2*a + 1)*hyper([-a - S.Half, -a], [S.Half], z).diff(z), z) assert t(HyperRep_log2(z), -z/4*hyper([Rational(3, 2), 1, 1], [2, 2], z), z) assert t(HyperRep_cosasin(a, z), hyper([-a, a], [S.Half], z), z) assert t(HyperRep_sinasin(a, z), 2*a*z*hyper([1 - a, 1 + a], [Rational(3, 2)], z), z) @slow def test_meijerg_eval(): from sympy import besseli, exp_polar from sympy.abc import l a = randcplx() arg = x*exp_polar(k*pi*I) expr1 = pi*meijerg([[], [(a + 1)/2]], [[a/2], [-a/2, (a + 1)/2]], arg**2/4) expr2 = besseli(a, arg) # Test that the two expressions agree for all arguments. for x_ in [0.5, 1.5]: for k_ in [0.0, 0.1, 0.3, 0.5, 0.8, 1, 5.751, 15.3]: assert abs((expr1 - expr2).n(subs={x: x_, k: k_})) < 1e-10 assert abs((expr1 - expr2).n(subs={x: x_, k: -k_})) < 1e-10 # Test continuity independently eps = 1e-13 expr2 = expr1.subs(k, l) for x_ in [0.5, 1.5]: for k_ in [0.5, Rational(1, 3), 0.25, 0.75, Rational(2, 3), 1.0, 1.5]: assert abs((expr1 - expr2).n( subs={x: x_, k: k_ + eps, l: k_ - eps})) < 1e-10 assert abs((expr1 - expr2).n( subs={x: x_, k: -k_ + eps, l: -k_ - eps})) < 1e-10 expr = (meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(-I*pi)/4) + meijerg(((0.5,), ()), ((0.5, 0, 0.5), ()), exp_polar(I*pi)/4)) \ /(2*sqrt(pi)) assert (expr - pi/exp(1)).n(chop=True) == 0 def test_limits(): k, x = symbols('k, x') assert hyper((1,), (Rational(4, 3), Rational(5, 3)), k**2).series(k) == \ 1 + 9*k**2/20 + 81*k**4/1120 + O(k**6) # issue 6350 assert limit(meijerg((), (), (1,), (0,), -x), x, 0) == \ meijerg(((), ()), ((1,), (0,)), 0) # issue 6052 # https://github.com/sympy/sympy/issues/11465 assert limit(1/hyper((1, ), (1, ), x), x, 0) == 1 def test_appellf1(): a, b1, b2, c, x, y = symbols('a b1 b2 c x y') assert appellf1(a, b2, b1, c, y, x) == appellf1(a, b1, b2, c, x, y) assert appellf1(a, b1, b1, c, y, x) == appellf1(a, b1, b1, c, x, y) assert appellf1(a, b1, b2, c, S.Zero, S.Zero) is S.One f = appellf1(a, b1, b2, c, S.Zero, S.Zero, evaluate=False) assert f.func is appellf1 assert f.doit() is S.One def test_derivative_appellf1(): from sympy import diff a, b1, b2, c, x, y, z = symbols('a b1 b2 c x y z') assert diff(appellf1(a, b1, b2, c, x, y), x) == a*b1*appellf1(a + 1, b2, b1 + 1, c + 1, y, x)/c assert diff(appellf1(a, b1, b2, c, x, y), y) == a*b2*appellf1(a + 1, b1, b2 + 1, c + 1, x, y)/c assert diff(appellf1(a, b1, b2, c, x, y), z) == 0 assert diff(appellf1(a, b1, b2, c, x, y), a) == Derivative(appellf1(a, b1, b2, c, x, y), a) def test_eval_nseries(): a1, b1, a2, b2 = symbols('a1 b1 a2 b2') assert hyper((1,2), (1,2,3), x**2)._eval_nseries(x, 7, None) == 1 + x**2/3 + x**4/24 + x**6/360 + O(x**7) assert exp(x)._eval_nseries(x,7,None) == hyper((a1, b1), (a1, b1), x)._eval_nseries(x, 7, None) assert hyper((a1, a2), (b1, b2), x)._eval_nseries(z, 7, None) == hyper((a1, a2), (b1, b2), x) + O(z**7) sympy-sympy-1.9/sympy/functions/special/tests/test_mathieu.py000066400000000000000000000020701412543434000247420ustar00rootroot00000000000000from sympy import (sqrt, sin, cos, diff, conjugate, mathieus, mathieuc, mathieusprime, mathieucprime) from sympy.abc import a, q, z def test_mathieus(): assert isinstance(mathieus(a, q, z), mathieus) assert mathieus(a, 0, z) == sin(sqrt(a)*z) assert conjugate(mathieus(a, q, z)) == mathieus(conjugate(a), conjugate(q), conjugate(z)) assert diff(mathieus(a, q, z), z) == mathieusprime(a, q, z) def test_mathieuc(): assert isinstance(mathieuc(a, q, z), mathieuc) assert mathieuc(a, 0, z) == cos(sqrt(a)*z) assert diff(mathieuc(a, q, z), z) == mathieucprime(a, q, z) def test_mathieusprime(): assert isinstance(mathieusprime(a, q, z), mathieusprime) assert mathieusprime(a, 0, z) == sqrt(a)*cos(sqrt(a)*z) assert diff(mathieusprime(a, q, z), z) == (-a + 2*q*cos(2*z))*mathieus(a, q, z) def test_mathieucprime(): assert isinstance(mathieucprime(a, q, z), mathieucprime) assert mathieucprime(a, 0, z) == -sqrt(a)*sin(sqrt(a)*z) assert diff(mathieucprime(a, q, z), z) == (-a + 2*q*cos(2*z))*mathieuc(a, q, z) sympy-sympy-1.9/sympy/functions/special/tests/test_singularity_functions.py000066400000000000000000000120761412543434000277570ustar00rootroot00000000000000from sympy import ( nan, pi, symbols, DiracDelta, Symbol, diff, Piecewise, I, Eq, Derivative, oo, SingularityFunction, Heaviside, Float, O ) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.testing.pytest import raises x, y, a, n = symbols('x y a n') def test_fdiff(): assert SingularityFunction(x, 4, 5).fdiff() == 5*SingularityFunction(x, 4, 4) assert SingularityFunction(x, 4, -1).fdiff() == SingularityFunction(x, 4, -2) assert SingularityFunction(x, 4, 0).fdiff() == SingularityFunction(x, 4, -1) assert SingularityFunction(y, 6, 2).diff(y) == 2*SingularityFunction(y, 6, 1) assert SingularityFunction(y, -4, -1).diff(y) == SingularityFunction(y, -4, -2) assert SingularityFunction(y, 4, 0).diff(y) == SingularityFunction(y, 4, -1) assert SingularityFunction(y, 4, 0).diff(y, 2) == SingularityFunction(y, 4, -2) n = Symbol('n', positive=True) assert SingularityFunction(x, a, n).fdiff() == n*SingularityFunction(x, a, n - 1) assert SingularityFunction(y, a, n).diff(y) == n*SingularityFunction(y, a, n - 1) expr_in = 4*SingularityFunction(x, a, n) + 3*SingularityFunction(x, a, -1) + -10*SingularityFunction(x, a, 0) expr_out = n*4*SingularityFunction(x, a, n - 1) + 3*SingularityFunction(x, a, -2) - 10*SingularityFunction(x, a, -1) assert diff(expr_in, x) == expr_out assert SingularityFunction(x, -10, 5).diff(evaluate=False) == ( Derivative(SingularityFunction(x, -10, 5), x)) raises(ArgumentIndexError, lambda: SingularityFunction(x, 4, 5).fdiff(2)) def test_eval(): assert SingularityFunction(x, a, n).func == SingularityFunction assert unchanged(SingularityFunction, x, 5, n) assert SingularityFunction(5, 3, 2) == 4 assert SingularityFunction(3, 5, 1) == 0 assert SingularityFunction(3, 3, 0) == 1 assert SingularityFunction(4, 4, -1) is oo assert SingularityFunction(4, 2, -1) == 0 assert SingularityFunction(4, 7, -1) == 0 assert SingularityFunction(5, 6, -2) == 0 assert SingularityFunction(4, 2, -2) == 0 assert SingularityFunction(4, 4, -2) is oo assert (SingularityFunction(6.1, 4, 5)).evalf(5) == Float('40.841', '5') assert SingularityFunction(6.1, pi, 2) == (-pi + 6.1)**2 assert SingularityFunction(x, a, nan) is nan assert SingularityFunction(x, nan, 1) is nan assert SingularityFunction(nan, a, n) is nan raises(ValueError, lambda: SingularityFunction(x, a, I)) raises(ValueError, lambda: SingularityFunction(2*I, I, n)) raises(ValueError, lambda: SingularityFunction(x, a, -3)) def test_leading_term(): l = Symbol('l', positive=True) assert SingularityFunction(x, 3, 2).as_leading_term(x) == 0 assert SingularityFunction(x, -2, 1).as_leading_term(x) == 2 assert SingularityFunction(x, 0, 0).as_leading_term(x) == 1 assert SingularityFunction(x, 0, 0).as_leading_term(x, cdir=-1) == 0 assert SingularityFunction(x, 0, -1).as_leading_term(x) == 0 assert SingularityFunction(x, 0, -2).as_leading_term(x) == 0 assert (SingularityFunction(x + l, 0, 1)/2\ - SingularityFunction(x + l, l/2, 1)\ + SingularityFunction(x + l, l, 1)/2).as_leading_term(x) == -x/2 def test_series(): l = Symbol('l', positive=True) assert SingularityFunction(x, -3, 2).series(x) == x**2 + 6*x + 9 assert SingularityFunction(x, -2, 1).series(x) == x + 2 assert SingularityFunction(x, 0, 0).series(x) == 1 assert SingularityFunction(x, 0, 0).series(x, dir='-') == 0 assert SingularityFunction(x, 0, -1).series(x) == 0 assert SingularityFunction(x, 0, -2).series(x) == 0 assert (SingularityFunction(x + l, 0, 1)/2\ - SingularityFunction(x + l, l/2, 1)\ + SingularityFunction(x + l, l, 1)/2).nseries(x) == -x/2 + O(x**6) def test_rewrite(): assert SingularityFunction(x, 4, 5).rewrite(Piecewise) == ( Piecewise(((x - 4)**5, x - 4 > 0), (0, True))) assert SingularityFunction(x, -10, 0).rewrite(Piecewise) == ( Piecewise((1, x + 10 > 0), (0, True))) assert SingularityFunction(x, 2, -1).rewrite(Piecewise) == ( Piecewise((oo, Eq(x - 2, 0)), (0, True))) assert SingularityFunction(x, 0, -2).rewrite(Piecewise) == ( Piecewise((oo, Eq(x, 0)), (0, True))) n = Symbol('n', nonnegative=True) assert SingularityFunction(x, a, n).rewrite(Piecewise) == ( Piecewise(((x - a)**n, x - a > 0), (0, True))) expr_in = SingularityFunction(x, 4, 5) + SingularityFunction(x, -3, -1) - SingularityFunction(x, 0, -2) expr_out = (x - 4)**5*Heaviside(x - 4) + DiracDelta(x + 3) - DiracDelta(x, 1) assert expr_in.rewrite(Heaviside) == expr_out assert expr_in.rewrite(DiracDelta) == expr_out assert expr_in.rewrite('HeavisideDiracDelta') == expr_out expr_in = SingularityFunction(x, a, n) + SingularityFunction(x, a, -1) - SingularityFunction(x, a, -2) expr_out = (x - a)**n*Heaviside(x - a) + DiracDelta(x - a) + DiracDelta(a - x, 1) assert expr_in.rewrite(Heaviside) == expr_out assert expr_in.rewrite(DiracDelta) == expr_out assert expr_in.rewrite('HeavisideDiracDelta') == expr_out sympy-sympy-1.9/sympy/functions/special/tests/test_spec_polynomials.py000066400000000000000000000364341412543434000267010ustar00rootroot00000000000000from sympy import ( Symbol, Dummy, diff, Derivative, Rational, roots, S, sqrt, hyper, cos, gamma, conjugate, factorial, pi, oo, zoo, binomial, RisingFactorial, legendre, assoc_legendre, chebyshevu, chebyshevt, chebyshevt_root, chebyshevu_root, laguerre, assoc_laguerre, laguerre_poly, hermite, gegenbauer, jacobi, jacobi_normalized, Sum, floor, exp) from sympy.core.expr import unchanged from sympy.core.function import ArgumentIndexError from sympy.testing.pytest import raises x = Symbol('x') def test_jacobi(): n = Symbol("n") a = Symbol("a") b = Symbol("b") assert jacobi(0, a, b, x) == 1 assert jacobi(1, a, b, x) == a/2 - b/2 + x*(a/2 + b/2 + 1) assert jacobi(n, a, a, x) == RisingFactorial( a + 1, n)*gegenbauer(n, a + S.Half, x)/RisingFactorial(2*a + 1, n) assert jacobi(n, a, -a, x) == ((-1)**a*(-x + 1)**(-a/2)*(x + 1)**(a/2)*assoc_legendre(n, a, x)* factorial(-a + n)*gamma(a + n + 1)/(factorial(a + n)*gamma(n + 1))) assert jacobi(n, -b, b, x) == ((-x + 1)**(b/2)*(x + 1)**(-b/2)*assoc_legendre(n, b, x)* gamma(-b + n + 1)/gamma(n + 1)) assert jacobi(n, 0, 0, x) == legendre(n, x) assert jacobi(n, S.Half, S.Half, x) == RisingFactorial( Rational(3, 2), n)*chebyshevu(n, x)/factorial(n + 1) assert jacobi(n, Rational(-1, 2), Rational(-1, 2), x) == RisingFactorial( S.Half, n)*chebyshevt(n, x)/factorial(n) X = jacobi(n, a, b, x) assert isinstance(X, jacobi) assert jacobi(n, a, b, -x) == (-1)**n*jacobi(n, b, a, x) assert jacobi(n, a, b, 0) == 2**(-n)*gamma(a + n + 1)*hyper( (-b - n, -n), (a + 1,), -1)/(factorial(n)*gamma(a + 1)) assert jacobi(n, a, b, 1) == RisingFactorial(a + 1, n)/factorial(n) m = Symbol("m", positive=True) assert jacobi(m, a, b, oo) == oo*RisingFactorial(a + b + m + 1, m) assert unchanged(jacobi, n, a, b, oo) assert conjugate(jacobi(m, a, b, x)) == \ jacobi(m, conjugate(a), conjugate(b), conjugate(x)) _k = Dummy('k') assert diff(jacobi(n, a, b, x), n) == Derivative(jacobi(n, a, b, x), n) assert diff(jacobi(n, a, b, x), a).dummy_eq(Sum((jacobi(n, a, b, x) + (2*_k + a + b + 1)*RisingFactorial(_k + b + 1, -_k + n)*jacobi(_k, a, b, x)/((-_k + n)*RisingFactorial(_k + a + b + 1, -_k + n)))/(_k + a + b + n + 1), (_k, 0, n - 1))) assert diff(jacobi(n, a, b, x), b).dummy_eq(Sum(((-1)**(-_k + n)*(2*_k + a + b + 1)*RisingFactorial(_k + a + 1, -_k + n)*jacobi(_k, a, b, x)/ ((-_k + n)*RisingFactorial(_k + a + b + 1, -_k + n)) + jacobi(n, a, b, x))/(_k + a + b + n + 1), (_k, 0, n - 1))) assert diff(jacobi(n, a, b, x), x) == \ (a/2 + b/2 + n/2 + S.Half)*jacobi(n - 1, a + 1, b + 1, x) assert jacobi_normalized(n, a, b, x) == \ (jacobi(n, a, b, x)/sqrt(2**(a + b + 1)*gamma(a + n + 1)*gamma(b + n + 1) /((a + b + 2*n + 1)*factorial(n)*gamma(a + b + n + 1)))) raises(ValueError, lambda: jacobi(-2.1, a, b, x)) raises(ValueError, lambda: jacobi(Dummy(positive=True, integer=True), 1, 2, oo)) assert jacobi(n, a, b, x).rewrite("polynomial").dummy_eq(Sum((S.Half - x/2) **_k*RisingFactorial(-n, _k)*RisingFactorial(_k + a + 1, -_k + n)* RisingFactorial(a + b + n + 1, _k)/factorial(_k), (_k, 0, n))/factorial(n)) raises(ArgumentIndexError, lambda: jacobi(n, a, b, x).fdiff(5)) def test_gegenbauer(): n = Symbol("n") a = Symbol("a") assert gegenbauer(0, a, x) == 1 assert gegenbauer(1, a, x) == 2*a*x assert gegenbauer(2, a, x) == -a + x**2*(2*a**2 + 2*a) assert gegenbauer(3, a, x) == \ x**3*(4*a**3/3 + 4*a**2 + a*Rational(8, 3)) + x*(-2*a**2 - 2*a) assert gegenbauer(-1, a, x) == 0 assert gegenbauer(n, S.Half, x) == legendre(n, x) assert gegenbauer(n, 1, x) == chebyshevu(n, x) assert gegenbauer(n, -1, x) == 0 X = gegenbauer(n, a, x) assert isinstance(X, gegenbauer) assert gegenbauer(n, a, -x) == (-1)**n*gegenbauer(n, a, x) assert gegenbauer(n, a, 0) == 2**n*sqrt(pi) * \ gamma(a + n/2)/(gamma(a)*gamma(-n/2 + S.Half)*gamma(n + 1)) assert gegenbauer(n, a, 1) == gamma(2*a + n)/(gamma(2*a)*gamma(n + 1)) assert gegenbauer(n, Rational(3, 4), -1) is zoo assert gegenbauer(n, Rational(1, 4), -1) == (sqrt(2)*cos(pi*(n + S.One/4))* gamma(n + S.Half)/(sqrt(pi)*gamma(n + 1))) m = Symbol("m", positive=True) assert gegenbauer(m, a, oo) == oo*RisingFactorial(a, m) assert unchanged(gegenbauer, n, a, oo) assert conjugate(gegenbauer(n, a, x)) == gegenbauer(n, conjugate(a), conjugate(x)) _k = Dummy('k') assert diff(gegenbauer(n, a, x), n) == Derivative(gegenbauer(n, a, x), n) assert diff(gegenbauer(n, a, x), a).dummy_eq(Sum((2*(-1)**(-_k + n) + 2)* (_k + a)*gegenbauer(_k, a, x)/((-_k + n)*(_k + 2*a + n)) + ((2*_k + 2)/((_k + 2*a)*(2*_k + 2*a + 1)) + 2/(_k + 2*a + n))*gegenbauer(n, a , x), (_k, 0, n - 1))) assert diff(gegenbauer(n, a, x), x) == 2*a*gegenbauer(n - 1, a + 1, x) assert gegenbauer(n, a, x).rewrite('polynomial').dummy_eq( Sum((-1)**_k*(2*x)**(-2*_k + n)*RisingFactorial(a, -_k + n) /(factorial(_k)*factorial(-2*_k + n)), (_k, 0, floor(n/2)))) raises(ArgumentIndexError, lambda: gegenbauer(n, a, x).fdiff(4)) def test_legendre(): assert legendre(0, x) == 1 assert legendre(1, x) == x assert legendre(2, x) == ((3*x**2 - 1)/2).expand() assert legendre(3, x) == ((5*x**3 - 3*x)/2).expand() assert legendre(4, x) == ((35*x**4 - 30*x**2 + 3)/8).expand() assert legendre(5, x) == ((63*x**5 - 70*x**3 + 15*x)/8).expand() assert legendre(6, x) == ((231*x**6 - 315*x**4 + 105*x**2 - 5)/16).expand() assert legendre(10, -1) == 1 assert legendre(11, -1) == -1 assert legendre(10, 1) == 1 assert legendre(11, 1) == 1 assert legendre(10, 0) != 0 assert legendre(11, 0) == 0 assert legendre(-1, x) == 1 k = Symbol('k') assert legendre(5 - k, x).subs(k, 2) == ((5*x**3 - 3*x)/2).expand() assert roots(legendre(4, x), x) == { sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) - Rational(2, 35)*sqrt(30)): 1, sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, -sqrt(Rational(3, 7) + Rational(2, 35)*sqrt(30)): 1, } n = Symbol("n") X = legendre(n, x) assert isinstance(X, legendre) assert unchanged(legendre, n, x) assert legendre(n, 0) == sqrt(pi)/(gamma(S.Half - n/2)*gamma(n/2 + 1)) assert legendre(n, 1) == 1 assert legendre(n, oo) is oo assert legendre(-n, x) == legendre(n - 1, x) assert legendre(n, -x) == (-1)**n*legendre(n, x) assert unchanged(legendre, -n + k, x) assert conjugate(legendre(n, x)) == legendre(n, conjugate(x)) assert diff(legendre(n, x), x) == \ n*(x*legendre(n, x) - legendre(n - 1, x))/(x**2 - 1) assert diff(legendre(n, x), n) == Derivative(legendre(n, x), n) _k = Dummy('k') assert legendre(n, x).rewrite("polynomial").dummy_eq(Sum((-1)**_k*(S.Half - x/2)**_k*(x/2 + S.Half)**(-_k + n)*binomial(n, _k)**2, (_k, 0, n))) raises(ArgumentIndexError, lambda: legendre(n, x).fdiff(1)) raises(ArgumentIndexError, lambda: legendre(n, x).fdiff(3)) def test_assoc_legendre(): Plm = assoc_legendre Q = sqrt(1 - x**2) assert Plm(0, 0, x) == 1 assert Plm(1, 0, x) == x assert Plm(1, 1, x) == -Q assert Plm(2, 0, x) == (3*x**2 - 1)/2 assert Plm(2, 1, x) == -3*x*Q assert Plm(2, 2, x) == 3*Q**2 assert Plm(3, 0, x) == (5*x**3 - 3*x)/2 assert Plm(3, 1, x).expand() == (( 3*(1 - 5*x**2)/2 ).expand() * Q).expand() assert Plm(3, 2, x) == 15*x * Q**2 assert Plm(3, 3, x) == -15 * Q**3 # negative m assert Plm(1, -1, x) == -Plm(1, 1, x)/2 assert Plm(2, -2, x) == Plm(2, 2, x)/24 assert Plm(2, -1, x) == -Plm(2, 1, x)/6 assert Plm(3, -3, x) == -Plm(3, 3, x)/720 assert Plm(3, -2, x) == Plm(3, 2, x)/120 assert Plm(3, -1, x) == -Plm(3, 1, x)/12 n = Symbol("n") m = Symbol("m") X = Plm(n, m, x) assert isinstance(X, assoc_legendre) assert Plm(n, 0, x) == legendre(n, x) assert Plm(n, m, 0) == 2**m*sqrt(pi)/(gamma(-m/2 - n/2 + S.Half)*gamma(-m/2 + n/2 + 1)) assert diff(Plm(m, n, x), x) == (m*x*assoc_legendre(m, n, x) - (m + n)*assoc_legendre(m - 1, n, x))/(x**2 - 1) _k = Dummy('k') assert Plm(m, n, x).rewrite("polynomial").dummy_eq( (1 - x**2)**(n/2)*Sum((-1)**_k*2**(-m)*x**(-2*_k + m - n)*factorial (-2*_k + 2*m)/(factorial(_k)*factorial(-_k + m)*factorial(-2*_k + m - n)), (_k, 0, floor(m/2 - n/2)))) assert conjugate(assoc_legendre(n, m, x)) == \ assoc_legendre(n, conjugate(m), conjugate(x)) raises(ValueError, lambda: Plm(0, 1, x)) raises(ValueError, lambda: Plm(-1, 1, x)) raises(ArgumentIndexError, lambda: Plm(n, m, x).fdiff(1)) raises(ArgumentIndexError, lambda: Plm(n, m, x).fdiff(2)) raises(ArgumentIndexError, lambda: Plm(n, m, x).fdiff(4)) def test_chebyshev(): assert chebyshevt(0, x) == 1 assert chebyshevt(1, x) == x assert chebyshevt(2, x) == 2*x**2 - 1 assert chebyshevt(3, x) == 4*x**3 - 3*x for n in range(1, 4): for k in range(n): z = chebyshevt_root(n, k) assert chebyshevt(n, z) == 0 raises(ValueError, lambda: chebyshevt_root(n, n)) for n in range(1, 4): for k in range(n): z = chebyshevu_root(n, k) assert chebyshevu(n, z) == 0 raises(ValueError, lambda: chebyshevu_root(n, n)) n = Symbol("n") X = chebyshevt(n, x) assert isinstance(X, chebyshevt) assert unchanged(chebyshevt, n, x) assert chebyshevt(n, -x) == (-1)**n*chebyshevt(n, x) assert chebyshevt(-n, x) == chebyshevt(n, x) assert chebyshevt(n, 0) == cos(pi*n/2) assert chebyshevt(n, 1) == 1 assert chebyshevt(n, oo) is oo assert conjugate(chebyshevt(n, x)) == chebyshevt(n, conjugate(x)) assert diff(chebyshevt(n, x), x) == n*chebyshevu(n - 1, x) X = chebyshevu(n, x) assert isinstance(X, chebyshevu) y = Symbol('y') assert chebyshevu(n, -x) == (-1)**n*chebyshevu(n, x) assert chebyshevu(-n, x) == -chebyshevu(n - 2, x) assert unchanged(chebyshevu, -n + y, x) assert chebyshevu(n, 0) == cos(pi*n/2) assert chebyshevu(n, 1) == n + 1 assert chebyshevu(n, oo) is oo assert conjugate(chebyshevu(n, x)) == chebyshevu(n, conjugate(x)) assert diff(chebyshevu(n, x), x) == \ (-x*chebyshevu(n, x) + (n + 1)*chebyshevt(n + 1, x))/(x**2 - 1) _k = Dummy('k') assert chebyshevt(n, x).rewrite("polynomial").dummy_eq(Sum(x**(-2*_k + n) *(x**2 - 1)**_k*binomial(n, 2*_k), (_k, 0, floor(n/2)))) assert chebyshevu(n, x).rewrite("polynomial").dummy_eq(Sum((-1)**_k*(2*x) **(-2*_k + n)*factorial(-_k + n)/(factorial(_k)* factorial(-2*_k + n)), (_k, 0, floor(n/2)))) raises(ArgumentIndexError, lambda: chebyshevt(n, x).fdiff(1)) raises(ArgumentIndexError, lambda: chebyshevt(n, x).fdiff(3)) raises(ArgumentIndexError, lambda: chebyshevu(n, x).fdiff(1)) raises(ArgumentIndexError, lambda: chebyshevu(n, x).fdiff(3)) def test_hermite(): assert hermite(0, x) == 1 assert hermite(1, x) == 2*x assert hermite(2, x) == 4*x**2 - 2 assert hermite(3, x) == 8*x**3 - 12*x assert hermite(4, x) == 16*x**4 - 48*x**2 + 12 assert hermite(6, x) == 64*x**6 - 480*x**4 + 720*x**2 - 120 n = Symbol("n") assert unchanged(hermite, n, x) assert hermite(n, -x) == (-1)**n*hermite(n, x) assert unchanged(hermite, -n, x) assert hermite(n, 0) == 2**n*sqrt(pi)/gamma(S.Half - n/2) assert hermite(n, oo) is oo assert conjugate(hermite(n, x)) == hermite(n, conjugate(x)) _k = Dummy('k') assert hermite(n, x).rewrite("polynomial").dummy_eq(factorial(n)*Sum((-1) **_k*(2*x)**(-2*_k + n)/(factorial(_k)*factorial(-2*_k + n)), (_k, 0, floor(n/2)))) assert diff(hermite(n, x), x) == 2*n*hermite(n - 1, x) assert diff(hermite(n, x), n) == Derivative(hermite(n, x), n) raises(ArgumentIndexError, lambda: hermite(n, x).fdiff(3)) def test_laguerre(): n = Symbol("n") m = Symbol("m", negative=True) # Laguerre polynomials: assert laguerre(0, x) == 1 assert laguerre(1, x) == -x + 1 assert laguerre(2, x) == x**2/2 - 2*x + 1 assert laguerre(3, x) == -x**3/6 + 3*x**2/2 - 3*x + 1 assert laguerre(-2, x) == (x + 1)*exp(x) X = laguerre(n, x) assert isinstance(X, laguerre) assert laguerre(n, 0) == 1 assert laguerre(n, oo) == (-1)**n*oo assert laguerre(n, -oo) is oo assert conjugate(laguerre(n, x)) == laguerre(n, conjugate(x)) _k = Dummy('k') assert laguerre(n, x).rewrite("polynomial").dummy_eq( Sum(x**_k*RisingFactorial(-n, _k)/factorial(_k)**2, (_k, 0, n))) assert laguerre(m, x).rewrite("polynomial").dummy_eq( exp(x)*Sum((-x)**_k*RisingFactorial(m + 1, _k)/factorial(_k)**2, (_k, 0, -m - 1))) assert diff(laguerre(n, x), x) == -assoc_laguerre(n - 1, 1, x) k = Symbol('k') assert laguerre(-n, x) == exp(x)*laguerre(n - 1, -x) assert laguerre(-3, x) == exp(x)*laguerre(2, -x) assert unchanged(laguerre, -n + k, x) raises(ValueError, lambda: laguerre(-2.1, x)) raises(ValueError, lambda: laguerre(Rational(5, 2), x)) raises(ArgumentIndexError, lambda: laguerre(n, x).fdiff(1)) raises(ArgumentIndexError, lambda: laguerre(n, x).fdiff(3)) def test_assoc_laguerre(): n = Symbol("n") m = Symbol("m") alpha = Symbol("alpha") # generalized Laguerre polynomials: assert assoc_laguerre(0, alpha, x) == 1 assert assoc_laguerre(1, alpha, x) == -x + alpha + 1 assert assoc_laguerre(2, alpha, x).expand() == \ (x**2/2 - (alpha + 2)*x + (alpha + 2)*(alpha + 1)/2).expand() assert assoc_laguerre(3, alpha, x).expand() == \ (-x**3/6 + (alpha + 3)*x**2/2 - (alpha + 2)*(alpha + 3)*x/2 + (alpha + 1)*(alpha + 2)*(alpha + 3)/6).expand() # Test the lowest 10 polynomials with laguerre_poly, to make sure it works: for i in range(10): assert assoc_laguerre(i, 0, x).expand() == laguerre_poly(i, x) X = assoc_laguerre(n, m, x) assert isinstance(X, assoc_laguerre) assert assoc_laguerre(n, 0, x) == laguerre(n, x) assert assoc_laguerre(n, alpha, 0) == binomial(alpha + n, alpha) p = Symbol("p", positive=True) assert assoc_laguerre(p, alpha, oo) == (-1)**p*oo assert assoc_laguerre(p, alpha, -oo) is oo assert diff(assoc_laguerre(n, alpha, x), x) == \ -assoc_laguerre(n - 1, alpha + 1, x) _k = Dummy('k') assert diff(assoc_laguerre(n, alpha, x), alpha).dummy_eq( Sum(assoc_laguerre(_k, alpha, x)/(-alpha + n), (_k, 0, n - 1))) assert conjugate(assoc_laguerre(n, alpha, x)) == \ assoc_laguerre(n, conjugate(alpha), conjugate(x)) assert assoc_laguerre(n, alpha, x).rewrite('polynomial').dummy_eq( gamma(alpha + n + 1)*Sum(x**_k*RisingFactorial(-n, _k)/ (factorial(_k)*gamma(_k + alpha + 1)), (_k, 0, n))/factorial(n)) raises(ValueError, lambda: assoc_laguerre(-2.1, alpha, x)) raises(ArgumentIndexError, lambda: assoc_laguerre(n, alpha, x).fdiff(1)) raises(ArgumentIndexError, lambda: assoc_laguerre(n, alpha, x).fdiff(4)) sympy-sympy-1.9/sympy/functions/special/tests/test_spherical_harmonics.py000066400000000000000000000067631412543434000273400ustar00rootroot00000000000000from sympy import Symbol, sqrt, pi, sin, cos, cot, exp, I, diff, conjugate from sympy.functions.special.spherical_harmonics import Ynm, Znm, Ynm_c def test_Ynm(): # https://en.wikipedia.org/wiki/Spherical_harmonics th, ph = Symbol("theta", real=True), Symbol("phi", real=True) from sympy.abc import n,m assert Ynm(0, 0, th, ph).expand(func=True) == 1/(2*sqrt(pi)) assert Ynm(1, -1, th, ph) == -exp(-2*I*ph)*Ynm(1, 1, th, ph) assert Ynm(1, -1, th, ph).expand(func=True) == sqrt(6)*sin(th)*exp(-I*ph)/(4*sqrt(pi)) assert Ynm(1, 0, th, ph).expand(func=True) == sqrt(3)*cos(th)/(2*sqrt(pi)) assert Ynm(1, 1, th, ph).expand(func=True) == -sqrt(6)*sin(th)*exp(I*ph)/(4*sqrt(pi)) assert Ynm(2, 0, th, ph).expand(func=True) == 3*sqrt(5)*cos(th)**2/(4*sqrt(pi)) - sqrt(5)/(4*sqrt(pi)) assert Ynm(2, 1, th, ph).expand(func=True) == -sqrt(30)*sin(th)*exp(I*ph)*cos(th)/(4*sqrt(pi)) assert Ynm(2, -2, th, ph).expand(func=True) == (-sqrt(30)*exp(-2*I*ph)*cos(th)**2/(8*sqrt(pi)) + sqrt(30)*exp(-2*I*ph)/(8*sqrt(pi))) assert Ynm(2, 2, th, ph).expand(func=True) == (-sqrt(30)*exp(2*I*ph)*cos(th)**2/(8*sqrt(pi)) + sqrt(30)*exp(2*I*ph)/(8*sqrt(pi))) assert diff(Ynm(n, m, th, ph), th) == (m*cot(th)*Ynm(n, m, th, ph) + sqrt((-m + n)*(m + n + 1))*exp(-I*ph)*Ynm(n, m + 1, th, ph)) assert diff(Ynm(n, m, th, ph), ph) == I*m*Ynm(n, m, th, ph) assert conjugate(Ynm(n, m, th, ph)) == (-1)**(2*m)*exp(-2*I*m*ph)*Ynm(n, m, th, ph) assert Ynm(n, m, -th, ph) == Ynm(n, m, th, ph) assert Ynm(n, m, th, -ph) == exp(-2*I*m*ph)*Ynm(n, m, th, ph) assert Ynm(n, -m, th, ph) == (-1)**m*exp(-2*I*m*ph)*Ynm(n, m, th, ph) def test_Ynm_c(): th, ph = Symbol("theta", real=True), Symbol("phi", real=True) from sympy.abc import n,m assert Ynm_c(n, m, th, ph) == (-1)**(2*m)*exp(-2*I*m*ph)*Ynm(n, m, th, ph) def test_Znm(): # https://en.wikipedia.org/wiki/Solid_harmonics#List_of_lowest_functions th, ph = Symbol("theta", real=True), Symbol("phi", real=True) assert Znm(0, 0, th, ph) == Ynm(0, 0, th, ph) assert Znm(1, -1, th, ph) == (-sqrt(2)*I*(Ynm(1, 1, th, ph) - exp(-2*I*ph)*Ynm(1, 1, th, ph))/2) assert Znm(1, 0, th, ph) == Ynm(1, 0, th, ph) assert Znm(1, 1, th, ph) == (sqrt(2)*(Ynm(1, 1, th, ph) + exp(-2*I*ph)*Ynm(1, 1, th, ph))/2) assert Znm(0, 0, th, ph).expand(func=True) == 1/(2*sqrt(pi)) assert Znm(1, -1, th, ph).expand(func=True) == (sqrt(3)*I*sin(th)*exp(I*ph)/(4*sqrt(pi)) - sqrt(3)*I*sin(th)*exp(-I*ph)/(4*sqrt(pi))) assert Znm(1, 0, th, ph).expand(func=True) == sqrt(3)*cos(th)/(2*sqrt(pi)) assert Znm(1, 1, th, ph).expand(func=True) == (-sqrt(3)*sin(th)*exp(I*ph)/(4*sqrt(pi)) - sqrt(3)*sin(th)*exp(-I*ph)/(4*sqrt(pi))) assert Znm(2, -1, th, ph).expand(func=True) == (sqrt(15)*I*sin(th)*exp(I*ph)*cos(th)/(4*sqrt(pi)) - sqrt(15)*I*sin(th)*exp(-I*ph)*cos(th)/(4*sqrt(pi))) assert Znm(2, 0, th, ph).expand(func=True) == 3*sqrt(5)*cos(th)**2/(4*sqrt(pi)) - sqrt(5)/(4*sqrt(pi)) assert Znm(2, 1, th, ph).expand(func=True) == (-sqrt(15)*sin(th)*exp(I*ph)*cos(th)/(4*sqrt(pi)) - sqrt(15)*sin(th)*exp(-I*ph)*cos(th)/(4*sqrt(pi))) sympy-sympy-1.9/sympy/functions/special/tests/test_tensor_functions.py000066400000000000000000000123521412543434000267140ustar00rootroot00000000000000from sympy import ( adjoint, conjugate, Dummy, Eijk, KroneckerDelta, LeviCivita, Symbol, symbols, transpose, Piecewise, Ne ) from sympy.physics.secondquant import evaluate_deltas, F x, y = symbols('x y') def test_levicivita(): assert Eijk(1, 2, 3) == LeviCivita(1, 2, 3) assert LeviCivita(1, 2, 3) == 1 assert LeviCivita(int(1), int(2), int(3)) == 1 assert LeviCivita(1, 3, 2) == -1 assert LeviCivita(1, 2, 2) == 0 i, j, k = symbols('i j k') assert LeviCivita(i, j, k) == LeviCivita(i, j, k, evaluate=False) assert LeviCivita(i, j, i) == 0 assert LeviCivita(1, i, i) == 0 assert LeviCivita(i, j, k).doit() == (j - i)*(k - i)*(k - j)/2 assert LeviCivita(1, 2, 3, 1) == 0 assert LeviCivita(4, 5, 1, 2, 3) == 1 assert LeviCivita(4, 5, 2, 1, 3) == -1 assert LeviCivita(i, j, k).is_integer is True assert adjoint(LeviCivita(i, j, k)) == LeviCivita(i, j, k) assert conjugate(LeviCivita(i, j, k)) == LeviCivita(i, j, k) assert transpose(LeviCivita(i, j, k)) == LeviCivita(i, j, k) def test_kronecker_delta(): i, j = symbols('i j') k = Symbol('k', nonzero=True) assert KroneckerDelta(1, 1) == 1 assert KroneckerDelta(1, 2) == 0 assert KroneckerDelta(k, 0) == 0 assert KroneckerDelta(x, x) == 1 assert KroneckerDelta(x**2 - y**2, x**2 - y**2) == 1 assert KroneckerDelta(i, i) == 1 assert KroneckerDelta(i, i + 1) == 0 assert KroneckerDelta(0, 0) == 1 assert KroneckerDelta(0, 1) == 0 assert KroneckerDelta(i + k, i) == 0 assert KroneckerDelta(i + k, i + k) == 1 assert KroneckerDelta(i + k, i + 1 + k) == 0 assert KroneckerDelta(i, j).subs(dict(i=1, j=0)) == 0 assert KroneckerDelta(i, j).subs(dict(i=3, j=3)) == 1 assert KroneckerDelta(i, j)**0 == 1 for n in range(1, 10): assert KroneckerDelta(i, j)**n == KroneckerDelta(i, j) assert KroneckerDelta(i, j)**-n == 1/KroneckerDelta(i, j) assert KroneckerDelta(i, j).is_integer is True assert adjoint(KroneckerDelta(i, j)) == KroneckerDelta(i, j) assert conjugate(KroneckerDelta(i, j)) == KroneckerDelta(i, j) assert transpose(KroneckerDelta(i, j)) == KroneckerDelta(i, j) # to test if canonical assert (KroneckerDelta(i, j) == KroneckerDelta(j, i)) == True assert KroneckerDelta(i, j).rewrite(Piecewise) == Piecewise((0, Ne(i, j)), (1, True)) # Tests with range: assert KroneckerDelta(i, j, (0, i)).args == (i, j, (0, i)) assert KroneckerDelta(i, j, (-j, i)).delta_range == (-j, i) # If index is out of range, return zero: assert KroneckerDelta(i, j, (0, i-1)) == 0 assert KroneckerDelta(-1, j, (0, i-1)) == 0 assert KroneckerDelta(j, -1, (0, i-1)) == 0 assert KroneckerDelta(j, i, (0, i-1)) == 0 def test_kronecker_delta_secondquant(): """secondquant-specific methods""" D = KroneckerDelta i, j, v, w = symbols('i j v w', below_fermi=True, cls=Dummy) a, b, t, u = symbols('a b t u', above_fermi=True, cls=Dummy) p, q, r, s = symbols('p q r s', cls=Dummy) assert D(i, a) == 0 assert D(i, t) == 0 assert D(i, j).is_above_fermi is False assert D(a, b).is_above_fermi is True assert D(p, q).is_above_fermi is True assert D(i, q).is_above_fermi is False assert D(q, i).is_above_fermi is False assert D(q, v).is_above_fermi is False assert D(a, q).is_above_fermi is True assert D(i, j).is_below_fermi is True assert D(a, b).is_below_fermi is False assert D(p, q).is_below_fermi is True assert D(p, j).is_below_fermi is True assert D(q, b).is_below_fermi is False assert D(i, j).is_only_above_fermi is False assert D(a, b).is_only_above_fermi is True assert D(p, q).is_only_above_fermi is False assert D(i, q).is_only_above_fermi is False assert D(q, i).is_only_above_fermi is False assert D(a, q).is_only_above_fermi is True assert D(i, j).is_only_below_fermi is True assert D(a, b).is_only_below_fermi is False assert D(p, q).is_only_below_fermi is False assert D(p, j).is_only_below_fermi is True assert D(q, b).is_only_below_fermi is False assert not D(i, q).indices_contain_equal_information assert not D(a, q).indices_contain_equal_information assert D(p, q).indices_contain_equal_information assert D(a, b).indices_contain_equal_information assert D(i, j).indices_contain_equal_information assert D(q, b).preferred_index == b assert D(q, b).killable_index == q assert D(q, t).preferred_index == t assert D(q, t).killable_index == q assert D(q, i).preferred_index == i assert D(q, i).killable_index == q assert D(q, v).preferred_index == v assert D(q, v).killable_index == q assert D(q, p).preferred_index == p assert D(q, p).killable_index == q EV = evaluate_deltas assert EV(D(a, q)*F(q)) == F(a) assert EV(D(i, q)*F(q)) == F(i) assert EV(D(a, q)*F(a)) == D(a, q)*F(a) assert EV(D(i, q)*F(i)) == D(i, q)*F(i) assert EV(D(a, b)*F(a)) == F(b) assert EV(D(a, b)*F(b)) == F(a) assert EV(D(i, j)*F(i)) == F(j) assert EV(D(i, j)*F(j)) == F(i) assert EV(D(p, q)*F(q)) == F(p) assert EV(D(p, q)*F(p)) == F(q) assert EV(D(p, j)*D(p, i)*F(i)) == F(j) assert EV(D(p, j)*D(p, i)*F(j)) == F(i) assert EV(D(p, q)*D(p, i))*F(i) == D(q, i)*F(i) sympy-sympy-1.9/sympy/functions/special/tests/test_zeta_functions.py000066400000000000000000000220021412543434000263360ustar00rootroot00000000000000from sympy import (Symbol, zeta, nan, Rational, Float, pi, dirichlet_eta, log, zoo, expand_func, polylog, lerchphi, S, exp, sqrt, I, exp_polar, polar_lift, O, stieltjes, Abs, Sum, oo, riemann_xi) from sympy.core.function import ArgumentIndexError from sympy.functions.combinatorial.numbers import bernoulli, factorial from sympy.testing.pytest import raises from sympy.testing.randtest import (test_derivative_numerically as td, random_complex_number as randcplx, verify_numerically as tn) x = Symbol('x') a = Symbol('a') b = Symbol('b', negative=True) z = Symbol('z') s = Symbol('s') def test_zeta_eval(): assert zeta(nan) is nan assert zeta(x, nan) is nan assert zeta(0) == Rational(-1, 2) assert zeta(0, x) == S.Half - x assert zeta(0, b) == S.Half - b assert zeta(1) is zoo assert zeta(1, 2) is zoo assert zeta(1, -7) is zoo assert zeta(1, x) is zoo assert zeta(2, 1) == pi**2/6 assert zeta(2) == pi**2/6 assert zeta(4) == pi**4/90 assert zeta(6) == pi**6/945 assert zeta(2, 2) == pi**2/6 - 1 assert zeta(4, 3) == pi**4/90 - Rational(17, 16) assert zeta(6, 4) == pi**6/945 - Rational(47449, 46656) assert zeta(2, -2) == pi**2/6 + Rational(5, 4) assert zeta(4, -3) == pi**4/90 + Rational(1393, 1296) assert zeta(6, -4) == pi**6/945 + Rational(3037465, 2985984) assert zeta(oo) == 1 assert zeta(-1) == Rational(-1, 12) assert zeta(-2) == 0 assert zeta(-3) == Rational(1, 120) assert zeta(-4) == 0 assert zeta(-5) == Rational(-1, 252) assert zeta(-1, 3) == Rational(-37, 12) assert zeta(-1, 7) == Rational(-253, 12) assert zeta(-1, -4) == Rational(119, 12) assert zeta(-1, -9) == Rational(539, 12) assert zeta(-4, 3) == -17 assert zeta(-4, -8) == 8772 assert zeta(0, 1) == Rational(-1, 2) assert zeta(0, -1) == Rational(3, 2) assert zeta(0, 2) == Rational(-3, 2) assert zeta(0, -2) == Rational(5, 2) assert zeta( 3).evalf(20).epsilon_eq(Float("1.2020569031595942854", 20), 1e-19) def test_zeta_series(): assert zeta(x, a).series(a, 0, 2) == \ zeta(x, 0) - x*a*zeta(x + 1, 0) + O(a**2) def test_dirichlet_eta_eval(): assert dirichlet_eta(0) == S.Half assert dirichlet_eta(-1) == Rational(1, 4) assert dirichlet_eta(1) == log(2) assert dirichlet_eta(2) == pi**2/12 assert dirichlet_eta(4) == pi**4*Rational(7, 720) def test_riemann_xi_eval(): assert riemann_xi(2) == pi/6 assert riemann_xi(0) == Rational(1, 2) assert riemann_xi(1) == Rational(1, 2) assert riemann_xi(3).rewrite(zeta) == 3*zeta(3)/(2*pi) assert riemann_xi(4) == pi**2/15 def test_rewriting(): assert dirichlet_eta(x).rewrite(zeta) == (1 - 2**(1 - x))*zeta(x) assert zeta(x).rewrite(dirichlet_eta) == dirichlet_eta(x)/(1 - 2**(1 - x)) assert zeta(x).rewrite(dirichlet_eta, a=2) == zeta(x) assert tn(dirichlet_eta(x), dirichlet_eta(x).rewrite(zeta), x) assert tn(zeta(x), zeta(x).rewrite(dirichlet_eta), x) assert zeta(x, a).rewrite(lerchphi) == lerchphi(1, x, a) assert polylog(s, z).rewrite(lerchphi) == lerchphi(z, s, 1)*z assert lerchphi(1, x, a).rewrite(zeta) == zeta(x, a) assert z*lerchphi(z, s, 1).rewrite(polylog) == polylog(s, z) def test_derivatives(): from sympy import Derivative assert zeta(x, a).diff(x) == Derivative(zeta(x, a), x) assert zeta(x, a).diff(a) == -x*zeta(x + 1, a) assert lerchphi( z, s, a).diff(z) == (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z assert lerchphi(z, s, a).diff(a) == -s*lerchphi(z, s + 1, a) assert polylog(s, z).diff(z) == polylog(s - 1, z)/z b = randcplx() c = randcplx() assert td(zeta(b, x), x) assert td(polylog(b, z), z) assert td(lerchphi(c, b, x), x) assert td(lerchphi(x, b, c), x) raises(ArgumentIndexError, lambda: lerchphi(c, b, x).fdiff(2)) raises(ArgumentIndexError, lambda: lerchphi(c, b, x).fdiff(4)) raises(ArgumentIndexError, lambda: polylog(b, z).fdiff(1)) raises(ArgumentIndexError, lambda: polylog(b, z).fdiff(3)) def myexpand(func, target): expanded = expand_func(func) if target is not None: return expanded == target if expanded == func: # it didn't expand return False # check to see that the expanded and original evaluate to the same value subs = {} for a in func.free_symbols: subs[a] = randcplx() return abs(func.subs(subs).n() - expanded.replace(exp_polar, exp).subs(subs).n()) < 1e-10 def test_polylog_expansion(): from sympy import log assert polylog(s, 0) == 0 assert polylog(s, 1) == zeta(s) assert polylog(s, -1) == -dirichlet_eta(s) assert polylog(s, exp_polar(I*pi*Rational(4, 3))) == polylog(s, exp(I*pi*Rational(4, 3))) assert polylog(s, exp_polar(I*pi)/3) == polylog(s, exp(I*pi)/3) assert myexpand(polylog(1, z), -log(1 - z)) assert myexpand(polylog(0, z), z/(1 - z)) assert myexpand(polylog(-1, z), z/(1 - z)**2) assert ((1-z)**3 * expand_func(polylog(-2, z))).simplify() == z*(1 + z) assert myexpand(polylog(-5, z), None) def test_polylog_series(): assert polylog(1, z).series(z, n=5) == z + z**2/2 + z**3/3 + z**4/4 + O(z**5) assert polylog(1, sqrt(z)).series(z, n=3) == z/2 + z**2/4 + sqrt(z)\ + z**(S(3)/2)/3 + z**(S(5)/2)/5 + O(z**3) # https://github.com/sympy/sympy/issues/9497 assert polylog(S(3)/2, -z).series(z, 0, 5) == -z + sqrt(2)*z**2/4\ - sqrt(3)*z**3/9 + z**4/8 + O(z**5) def test_issue_8404(): i = Symbol('i', integer=True) assert Abs(Sum(1/(3*i + 1)**2, (i, 0, S.Infinity)).doit().n(4) - 1.122) < 0.001 def test_polylog_values(): from sympy.testing.randtest import verify_numerically as tn assert polylog(2, 2) == pi**2/4 - I*pi*log(2) assert polylog(2, S.Half) == pi**2/12 - log(2)**2/2 for z in [S.Half, 2, (sqrt(5)-1)/2, -(sqrt(5)-1)/2, -(sqrt(5)+1)/2, (3-sqrt(5))/2]: assert Abs(polylog(2, z).evalf() - polylog(2, z, evaluate=False).evalf()) < 1e-15 z = Symbol("z") for s in [-1, 0]: for _ in range(10): assert tn(polylog(s, z), polylog(s, z, evaluate=False), z, a=-3, b=-2, c=S.Half, d=2) assert tn(polylog(s, z), polylog(s, z, evaluate=False), z, a=2, b=-2, c=5, d=2) from sympy import Integral assert polylog(0, Integral(1, (x, 0, 1))) == -S.Half def test_lerchphi_expansion(): assert myexpand(lerchphi(1, s, a), zeta(s, a)) assert myexpand(lerchphi(z, s, 1), polylog(s, z)/z) # direct summation assert myexpand(lerchphi(z, -1, a), a/(1 - z) + z/(1 - z)**2) assert myexpand(lerchphi(z, -3, a), None) # polylog reduction assert myexpand(lerchphi(z, s, S.Half), 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - polylog(s, polar_lift(-1)*sqrt(z))/sqrt(z))) assert myexpand(lerchphi(z, s, 2), -1/z + polylog(s, z)/z**2) assert myexpand(lerchphi(z, s, Rational(3, 2)), None) assert myexpand(lerchphi(z, s, Rational(7, 3)), None) assert myexpand(lerchphi(z, s, Rational(-1, 3)), None) assert myexpand(lerchphi(z, s, Rational(-5, 2)), None) # hurwitz zeta reduction assert myexpand(lerchphi(-1, s, a), 2**(-s)*zeta(s, a/2) - 2**(-s)*zeta(s, (a + 1)/2)) assert myexpand(lerchphi(I, s, a), None) assert myexpand(lerchphi(-I, s, a), None) assert myexpand(lerchphi(exp(I*pi*Rational(2, 5)), s, a), None) def test_stieltjes(): assert isinstance(stieltjes(x), stieltjes) assert isinstance(stieltjes(x, a), stieltjes) # Zero'th constant EulerGamma assert stieltjes(0) == S.EulerGamma assert stieltjes(0, 1) == S.EulerGamma # Not defined assert stieltjes(nan) is nan assert stieltjes(0, nan) is nan assert stieltjes(-1) is S.ComplexInfinity assert stieltjes(1.5) is S.ComplexInfinity assert stieltjes(z, 0) is S.ComplexInfinity assert stieltjes(z, -1) is S.ComplexInfinity def test_stieltjes_evalf(): assert abs(stieltjes(0).evalf() - 0.577215664) < 1E-9 assert abs(stieltjes(0, 0.5).evalf() - 1.963510026) < 1E-9 assert abs(stieltjes(1, 2).evalf() + 0.072815845 ) < 1E-9 def test_issue_10475(): a = Symbol('a', extended_real=True) b = Symbol('b', extended_positive=True) s = Symbol('s', zero=False) assert zeta(2 + I).is_finite assert zeta(1).is_finite is False assert zeta(x).is_finite is None assert zeta(x + I).is_finite is None assert zeta(a).is_finite is None assert zeta(b).is_finite is None assert zeta(-b).is_finite is True assert zeta(b**2 - 2*b + 1).is_finite is None assert zeta(a + I).is_finite is True assert zeta(b + 1).is_finite is True assert zeta(s + 1).is_finite is True def test_issue_14177(): n = Symbol('n', positive=True, integer=True) assert zeta(2*n) == (-1)**(n + 1)*2**(2*n - 1)*pi**(2*n)*bernoulli(2*n)/factorial(2*n) assert zeta(-n) == (-1)**(-n)*bernoulli(n + 1)/(n + 1) n = Symbol('n') assert zeta(2*n) == zeta(2*n) # As sign of z (= 2*n) is not determined sympy-sympy-1.9/sympy/functions/special/zeta_functions.py000066400000000000000000000516261412543434000241530ustar00rootroot00000000000000""" Riemann zeta and related function. """ from sympy import Add from sympy.core import Function, S, sympify, pi, I from sympy.core.function import ArgumentIndexError from sympy.functions.combinatorial.numbers import bernoulli, factorial, harmonic from sympy.functions.elementary.complexes import re from sympy.functions.elementary.exponential import log, exp_polar from sympy.functions.elementary.miscellaneous import sqrt ############################################################################### ###################### LERCH TRANSCENDENT ##################################### ############################################################################### class lerchphi(Function): r""" Lerch transcendent (Lerch phi function). Explanation =========== For $\operatorname{Re}(a) > 0$, $|z| < 1$ and $s \in \mathbb{C}$, the Lerch transcendent is defined as .. math :: \Phi(z, s, a) = \sum_{n=0}^\infty \frac{z^n}{(n + a)^s}, where the standard branch of the argument is used for $n + a$, and by analytic continuation for other values of the parameters. A commonly used related function is the Lerch zeta function, defined by .. math:: L(q, s, a) = \Phi(e^{2\pi i q}, s, a). **Analytic Continuation and Branching Behavior** It can be shown that .. math:: \Phi(z, s, a) = z\Phi(z, s, a+1) + a^{-s}. This provides the analytic continuation to $\operatorname{Re}(a) \le 0$. Assume now $\operatorname{Re}(a) > 0$. The integral representation .. math:: \Phi_0(z, s, a) = \int_0^\infty \frac{t^{s-1} e^{-at}}{1 - ze^{-t}} \frac{\mathrm{d}t}{\Gamma(s)} provides an analytic continuation to $\mathbb{C} - [1, \infty)$. Finally, for $x \in (1, \infty)$ we find .. math:: \lim_{\epsilon \to 0^+} \Phi_0(x + i\epsilon, s, a) -\lim_{\epsilon \to 0^+} \Phi_0(x - i\epsilon, s, a) = \frac{2\pi i \log^{s-1}{x}}{x^a \Gamma(s)}, using the standard branch for both $\log{x}$ and $\log{\log{x}}$ (a branch of $\log{\log{x}}$ is needed to evaluate $\log{x}^{s-1}$). This concludes the analytic continuation. The Lerch transcendent is thus branched at $z \in \{0, 1, \infty\}$ and $a \in \mathbb{Z}_{\le 0}$. For fixed $z, a$ outside these branch points, it is an entire function of $s$. Examples ======== The Lerch transcendent is a fairly general function, for this reason it does not automatically evaluate to simpler functions. Use ``expand_func()`` to achieve this. If $z=1$, the Lerch transcendent reduces to the Hurwitz zeta function: >>> from sympy import lerchphi, expand_func >>> from sympy.abc import z, s, a >>> expand_func(lerchphi(1, s, a)) zeta(s, a) More generally, if $z$ is a root of unity, the Lerch transcendent reduces to a sum of Hurwitz zeta functions: >>> expand_func(lerchphi(-1, s, a)) zeta(s, a/2)/2**s - zeta(s, a/2 + 1/2)/2**s If $a=1$, the Lerch transcendent reduces to the polylogarithm: >>> expand_func(lerchphi(z, s, 1)) polylog(s, z)/z More generally, if $a$ is rational, the Lerch transcendent reduces to a sum of polylogarithms: >>> from sympy import S >>> expand_func(lerchphi(z, s, S(1)/2)) 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z)) >>> expand_func(lerchphi(z, s, S(3)/2)) -2**s/z + 2**(s - 1)*(polylog(s, sqrt(z))/sqrt(z) - polylog(s, sqrt(z)*exp_polar(I*pi))/sqrt(z))/z The derivatives with respect to $z$ and $a$ can be computed in closed form: >>> lerchphi(z, s, a).diff(z) (-a*lerchphi(z, s, a) + lerchphi(z, s - 1, a))/z >>> lerchphi(z, s, a).diff(a) -s*lerchphi(z, s + 1, a) See Also ======== polylog, zeta References ========== .. [1] Bateman, H.; Erdelyi, A. (1953), Higher Transcendental Functions, Vol. I, New York: McGraw-Hill. Section 1.11. .. [2] http://dlmf.nist.gov/25.14 .. [3] https://en.wikipedia.org/wiki/Lerch_transcendent """ def _eval_expand_func(self, **hints): from sympy import exp, I, floor, Add, Poly, Dummy, exp_polar, unpolarify z, s, a = self.args if z == 1: return zeta(s, a) if s.is_Integer and s <= 0: t = Dummy('t') p = Poly((t + a)**(-s), t) start = 1/(1 - t) res = S.Zero for c in reversed(p.all_coeffs()): res += c*start start = t*start.diff(t) return res.subs(t, z) if a.is_Rational: # See section 18 of # Kelly B. Roach. Hypergeometric Function Representations. # In: Proceedings of the 1997 International Symposium on Symbolic and # Algebraic Computation, pages 205-211, New York, 1997. ACM. # TODO should something be polarified here? add = S.Zero mul = S.One # First reduce a to the interaval (0, 1] if a > 1: n = floor(a) if n == a: n -= 1 a -= n mul = z**(-n) add = Add(*[-z**(k - n)/(a + k)**s for k in range(n)]) elif a <= 0: n = floor(-a) + 1 a += n mul = z**n add = Add(*[z**(n - 1 - k)/(a - k - 1)**s for k in range(n)]) m, n = S([a.p, a.q]) zet = exp_polar(2*pi*I/n) root = z**(1/n) return add + mul*n**(s - 1)*Add( *[polylog(s, zet**k*root)._eval_expand_func(**hints) / (unpolarify(zet)**k*root)**m for k in range(n)]) # TODO use minpoly instead of ad-hoc methods when issue 5888 is fixed if isinstance(z, exp) and (z.args[0]/(pi*I)).is_Rational or z in [-1, I, -I]: # TODO reference? if z == -1: p, q = S([1, 2]) elif z == I: p, q = S([1, 4]) elif z == -I: p, q = S([-1, 4]) else: arg = z.args[0]/(2*pi*I) p, q = S([arg.p, arg.q]) return Add(*[exp(2*pi*I*k*p/q)/q**s*zeta(s, (k + a)/q) for k in range(q)]) return lerchphi(z, s, a) def fdiff(self, argindex=1): z, s, a = self.args if argindex == 3: return -s*lerchphi(z, s + 1, a) elif argindex == 1: return (lerchphi(z, s - 1, a) - a*lerchphi(z, s, a))/z else: raise ArgumentIndexError def _eval_rewrite_helper(self, z, s, a, target): res = self._eval_expand_func() if res.has(target): return res else: return self def _eval_rewrite_as_zeta(self, z, s, a, **kwargs): return self._eval_rewrite_helper(z, s, a, zeta) def _eval_rewrite_as_polylog(self, z, s, a, **kwargs): return self._eval_rewrite_helper(z, s, a, polylog) ############################################################################### ###################### POLYLOGARITHM ########################################## ############################################################################### class polylog(Function): r""" Polylogarithm function. Explanation =========== For $|z| < 1$ and $s \in \mathbb{C}$, the polylogarithm is defined by .. math:: \operatorname{Li}_s(z) = \sum_{n=1}^\infty \frac{z^n}{n^s}, where the standard branch of the argument is used for $n$. It admits an analytic continuation which is branched at $z=1$ (notably not on the sheet of initial definition), $z=0$ and $z=\infty$. The name polylogarithm comes from the fact that for $s=1$, the polylogarithm is related to the ordinary logarithm (see examples), and that .. math:: \operatorname{Li}_{s+1}(z) = \int_0^z \frac{\operatorname{Li}_s(t)}{t} \mathrm{d}t. The polylogarithm is a special case of the Lerch transcendent: .. math:: \operatorname{Li}_{s}(z) = z \Phi(z, s, 1). Examples ======== For $z \in \{0, 1, -1\}$, the polylogarithm is automatically expressed using other functions: >>> from sympy import polylog >>> from sympy.abc import s >>> polylog(s, 0) 0 >>> polylog(s, 1) zeta(s) >>> polylog(s, -1) -dirichlet_eta(s) If $s$ is a negative integer, $0$ or $1$, the polylogarithm can be expressed using elementary functions. This can be done using ``expand_func()``: >>> from sympy import expand_func >>> from sympy.abc import z >>> expand_func(polylog(1, z)) -log(1 - z) >>> expand_func(polylog(0, z)) z/(1 - z) The derivative with respect to $z$ can be computed in closed form: >>> polylog(s, z).diff(z) polylog(s - 1, z)/z The polylogarithm can be expressed in terms of the lerch transcendent: >>> from sympy import lerchphi >>> polylog(s, z).rewrite(lerchphi) z*lerchphi(z, s, 1) See Also ======== zeta, lerchphi """ @classmethod def eval(cls, s, z): s, z = sympify((s, z)) if z is S.One: return zeta(s) elif z is S.NegativeOne: return -dirichlet_eta(s) elif z is S.Zero: return S.Zero elif s == 2: if z == S.Half: return pi**2/12 - log(2)**2/2 elif z == 2: return pi**2/4 - I*pi*log(2) elif z == -(sqrt(5) - 1)/2: return -pi**2/15 + log((sqrt(5)-1)/2)**2/2 elif z == -(sqrt(5) + 1)/2: return -pi**2/10 - log((sqrt(5)+1)/2)**2 elif z == (3 - sqrt(5))/2: return pi**2/15 - log((sqrt(5)-1)/2)**2 elif z == (sqrt(5) - 1)/2: return pi**2/10 - log((sqrt(5)-1)/2)**2 if z.is_zero: return S.Zero # Make an effort to determine if z is 1 to avoid replacing into # expression with singularity zone = z.equals(S.One) if zone: return zeta(s) elif zone is False: # For s = 0 or -1 use explicit formulas to evaluate, but # automatically expanding polylog(1, z) to -log(1-z) seems # undesirable for summation methods based on hypergeometric # functions if s is S.Zero: return z/(1 - z) elif s is S.NegativeOne: return z/(1 - z)**2 if s.is_zero: return z/(1 - z) # polylog is branched, but not over the unit disk from sympy.functions.elementary.complexes import (Abs, unpolarify, polar_lift) if z.has(exp_polar, polar_lift) and (zone or (Abs(z) <= S.One) == True): return cls(s, unpolarify(z)) def fdiff(self, argindex=1): s, z = self.args if argindex == 2: return polylog(s - 1, z)/z raise ArgumentIndexError def _eval_rewrite_as_lerchphi(self, s, z, **kwargs): return z*lerchphi(z, s, 1) def _eval_expand_func(self, **hints): from sympy import log, expand_mul, Dummy s, z = self.args if s == 1: return -log(1 - z) if s.is_Integer and s <= 0: u = Dummy('u') start = u/(1 - u) for _ in range(-s): start = u*start.diff(u) return expand_mul(start).subs(u, z) return polylog(s, z) def _eval_is_zero(self): z = self.args[1] if z.is_zero: return True def _eval_nseries(self, x, n, logx, cdir=0): from sympy import ceiling, Order nu, z = self.args z0 = z.subs(x, 0) if z0 is S.NaN: z0 = z.limit(x, 0, dir='-' if re(cdir).is_negative else '+') if z0.is_zero: # In case of powers less than 1, number of terms need to be computed # separately to avoid repeated callings of _eval_nseries with wrong n try: _, exp = z.leadterm(x) except (ValueError, NotImplementedError): return self if exp.is_positive: newn = ceiling(n/exp) o = Order(x**n, x) r = z._eval_nseries(x, n, logx, cdir).removeO() if r is S.Zero: return o term = r s = [term] for k in range(2, newn): term *= r s.append(term/k**nu) return Add(*s) + o return super(polylog, self)._eval_nseries(x, n, logx, cdir) ############################################################################### ###################### HURWITZ GENERALIZED ZETA FUNCTION ###################### ############################################################################### class zeta(Function): r""" Hurwitz zeta function (or Riemann zeta function). Explanation =========== For $\operatorname{Re}(a) > 0$ and $\operatorname{Re}(s) > 1$, this function is defined as .. math:: \zeta(s, a) = \sum_{n=0}^\infty \frac{1}{(n + a)^s}, where the standard choice of argument for $n + a$ is used. For fixed $a$ with $\operatorname{Re}(a) > 0$ the Hurwitz zeta function admits a meromorphic continuation to all of $\mathbb{C}$, it is an unbranched function with a simple pole at $s = 1$. Analytic continuation to other $a$ is possible under some circumstances, but this is not typically done. The Hurwitz zeta function is a special case of the Lerch transcendent: .. math:: \zeta(s, a) = \Phi(1, s, a). This formula defines an analytic continuation for all possible values of $s$ and $a$ (also $\operatorname{Re}(a) < 0$), see the documentation of :class:`lerchphi` for a description of the branching behavior. If no value is passed for $a$, by this function assumes a default value of $a = 1$, yielding the Riemann zeta function. Examples ======== For $a = 1$ the Hurwitz zeta function reduces to the famous Riemann zeta function: .. math:: \zeta(s, 1) = \zeta(s) = \sum_{n=1}^\infty \frac{1}{n^s}. >>> from sympy import zeta >>> from sympy.abc import s >>> zeta(s, 1) zeta(s) >>> zeta(s) zeta(s) The Riemann zeta function can also be expressed using the Dirichlet eta function: >>> from sympy import dirichlet_eta >>> zeta(s).rewrite(dirichlet_eta) dirichlet_eta(s)/(1 - 2**(1 - s)) The Riemann zeta function at positive even integer and negative odd integer values is related to the Bernoulli numbers: >>> zeta(2) pi**2/6 >>> zeta(4) pi**4/90 >>> zeta(-1) -1/12 The specific formulae are: .. math:: \zeta(2n) = (-1)^{n+1} \frac{B_{2n} (2\pi)^{2n}}{2(2n)!} .. math:: \zeta(-n) = -\frac{B_{n+1}}{n+1} At negative even integers the Riemann zeta function is zero: >>> zeta(-4) 0 No closed-form expressions are known at positive odd integers, but numerical evaluation is possible: >>> zeta(3).n() 1.20205690315959 The derivative of $\zeta(s, a)$ with respect to $a$ can be computed: >>> from sympy.abc import a >>> zeta(s, a).diff(a) -s*zeta(s + 1, a) However the derivative with respect to $s$ has no useful closed form expression: >>> zeta(s, a).diff(s) Derivative(zeta(s, a), s) The Hurwitz zeta function can be expressed in terms of the Lerch transcendent, :class:`~.lerchphi`: >>> from sympy import lerchphi >>> zeta(s, a).rewrite(lerchphi) lerchphi(1, s, a) See Also ======== dirichlet_eta, lerchphi, polylog References ========== .. [1] http://dlmf.nist.gov/25.11 .. [2] https://en.wikipedia.org/wiki/Hurwitz_zeta_function """ @classmethod def eval(cls, z, a_=None): if a_ is None: z, a = list(map(sympify, (z, 1))) else: z, a = list(map(sympify, (z, a_))) if a.is_Number: if a is S.NaN: return S.NaN elif a is S.One and a_ is not None: return cls(z) # TODO Should a == 0 return S.NaN as well? if z.is_Number: if z is S.NaN: return S.NaN elif z is S.Infinity: return S.One elif z.is_zero: return S.Half - a elif z is S.One: return S.ComplexInfinity if z.is_integer: if a.is_Integer: if z.is_negative: zeta = (-1)**z * bernoulli(-z + 1)/(-z + 1) elif z.is_even and z.is_positive: B, F = bernoulli(z), factorial(z) zeta = ((-1)**(z/2+1) * 2**(z - 1) * B * pi**z) / F else: return if a.is_negative: return zeta + harmonic(abs(a), z) else: return zeta - harmonic(a - 1, z) if z.is_zero: return S.Half - a def _eval_rewrite_as_dirichlet_eta(self, s, a=1, **kwargs): if a != 1: return self s = self.args[0] return dirichlet_eta(s)/(1 - 2**(1 - s)) def _eval_rewrite_as_lerchphi(self, s, a=1, **kwargs): return lerchphi(1, s, a) def _eval_is_finite(self): arg_is_one = (self.args[0] - 1).is_zero if arg_is_one is not None: return not arg_is_one def fdiff(self, argindex=1): if len(self.args) == 2: s, a = self.args else: s, a = self.args + (1,) if argindex == 2: return -s*zeta(s + 1, a) else: raise ArgumentIndexError class dirichlet_eta(Function): r""" Dirichlet eta function. Explanation =========== For $\operatorname{Re}(s) > 0$, this function is defined as .. math:: \eta(s) = \sum_{n=1}^\infty \frac{(-1)^{n-1}}{n^s}. It admits a unique analytic continuation to all of $\mathbb{C}$. It is an entire, unbranched function. Examples ======== The Dirichlet eta function is closely related to the Riemann zeta function: >>> from sympy import dirichlet_eta, zeta >>> from sympy.abc import s >>> dirichlet_eta(s).rewrite(zeta) (1 - 2**(1 - s))*zeta(s) See Also ======== zeta References ========== .. [1] https://en.wikipedia.org/wiki/Dirichlet_eta_function """ @classmethod def eval(cls, s): if s == 1: return log(2) z = zeta(s) if not z.has(zeta): return (1 - 2**(1 - s))*z def _eval_rewrite_as_zeta(self, s, **kwargs): return (1 - 2**(1 - s)) * zeta(s) class riemann_xi(Function): r""" Riemann Xi function. Examples ======== The Riemann Xi function is closely related to the Riemann zeta function. The zeros of Riemann Xi function are precisely the non-trivial zeros of the zeta function. >>> from sympy import riemann_xi, zeta >>> from sympy.abc import s >>> riemann_xi(s).rewrite(zeta) s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2)) References ========== .. [1] https://en.wikipedia.org/wiki/Riemann_Xi_function """ @classmethod def eval(cls, s): from sympy import gamma z = zeta(s) if s is S.Zero or s is S.One: return S.Half if not isinstance(z, zeta): return s*(s - 1)*gamma(s/2)*z/(2*pi**(s/2)) def _eval_rewrite_as_zeta(self, s, **kwargs): from sympy import gamma return s*(s - 1)*gamma(s/2)*zeta(s)/(2*pi**(s/2)) class stieltjes(Function): r""" Represents Stieltjes constants, $\gamma_{k}$ that occur in Laurent Series expansion of the Riemann zeta function. Examples ======== >>> from sympy import stieltjes >>> from sympy.abc import n, m >>> stieltjes(n) stieltjes(n) The zero'th stieltjes constant: >>> stieltjes(0) EulerGamma >>> stieltjes(0, 1) EulerGamma For generalized stieltjes constants: >>> stieltjes(n, m) stieltjes(n, m) Constants are only defined for integers >= 0: >>> stieltjes(-1) zoo References ========== .. [1] https://en.wikipedia.org/wiki/Stieltjes_constants """ @classmethod def eval(cls, n, a=None): n = sympify(n) if a is not None: a = sympify(a) if a is S.NaN: return S.NaN if a.is_Integer and a.is_nonpositive: return S.ComplexInfinity if n.is_Number: if n is S.NaN: return S.NaN elif n < 0: return S.ComplexInfinity elif not n.is_Integer: return S.ComplexInfinity elif n is S.Zero and a in [None, 1]: return S.EulerGamma if n.is_extended_negative: return S.ComplexInfinity if n.is_zero and a in [None, 1]: return S.EulerGamma if n.is_integer == False: return S.ComplexInfinity sympy-sympy-1.9/sympy/galgebra.py000066400000000000000000000001731412543434000172230ustar00rootroot00000000000000raise ImportError("""As of SymPy 1.0 the galgebra module is maintained separately at https://github.com/pygae/galgebra""") sympy-sympy-1.9/sympy/geometry/000077500000000000000000000000001412543434000167375ustar00rootroot00000000000000sympy-sympy-1.9/sympy/geometry/__init__.py000066400000000000000000000023301412543434000210460ustar00rootroot00000000000000""" A geometry module for the SymPy library. This module contains all of the entities and functions needed to construct basic geometrical data and to perform simple informational queries. Usage: ====== Examples ======== """ from sympy.geometry.point import Point, Point2D, Point3D from sympy.geometry.line import Line, Ray, Segment, Line2D, Segment2D, Ray2D, \ Line3D, Segment3D, Ray3D from sympy.geometry.plane import Plane from sympy.geometry.ellipse import Ellipse, Circle from sympy.geometry.polygon import Polygon, RegularPolygon, Triangle, rad, deg from sympy.geometry.util import are_similar, centroid, convex_hull, idiff, \ intersection, closest_points, farthest_points from sympy.geometry.exceptions import GeometryError from sympy.geometry.curve import Curve from sympy.geometry.parabola import Parabola __all__ = [ 'Point', 'Point2D', 'Point3D', 'Line', 'Ray', 'Segment', 'Line2D', 'Segment2D', 'Ray2D', 'Line3D', 'Segment3D', 'Ray3D', 'Plane', 'Ellipse', 'Circle', 'Polygon', 'RegularPolygon', 'Triangle', 'rad', 'deg', 'are_similar', 'centroid', 'convex_hull', 'idiff', 'intersection', 'closest_points', 'farthest_points', 'GeometryError', 'Curve', 'Parabola', ] sympy-sympy-1.9/sympy/geometry/curve.py000066400000000000000000000235141412543434000204420ustar00rootroot00000000000000"""Curves in 2-dimensional Euclidean space. Contains ======== Curve """ from sympy import sqrt from sympy.core import sympify, diff from sympy.core.compatibility import is_sequence from sympy.core.containers import Tuple from sympy.core.symbol import _symbol from sympy.geometry.entity import GeometryEntity, GeometrySet from sympy.geometry.point import Point from sympy.integrals import integrate class Curve(GeometrySet): """A curve in space. A curve is defined by parametric functions for the coordinates, a parameter and the lower and upper bounds for the parameter value. Parameters ========== function : list of functions limits : 3-tuple Function parameter and lower and upper bounds. Attributes ========== functions parameter limits Raises ====== ValueError When `functions` are specified incorrectly. When `limits` are specified incorrectly. Examples ======== >>> from sympy import sin, cos, interpolate >>> from sympy.abc import t, a >>> from sympy.geometry import Curve >>> C = Curve((sin(t), cos(t)), (t, 0, 2)) >>> C.functions (sin(t), cos(t)) >>> C.limits (t, 0, 2) >>> C.parameter t >>> C = Curve((t, interpolate([1, 4, 9, 16], t)), (t, 0, 1)); C Curve((t, t**2), (t, 0, 1)) >>> C.subs(t, 4) Point2D(4, 16) >>> C.arbitrary_point(a) Point2D(a, a**2) See Also ======== sympy.core.function.Function sympy.polys.polyfuncs.interpolate """ def __new__(cls, function, limits): fun = sympify(function) if not is_sequence(fun) or len(fun) != 2: raise ValueError("Function argument should be (x(t), y(t)) " "but got %s" % str(function)) if not is_sequence(limits) or len(limits) != 3: raise ValueError("Limit argument should be (t, tmin, tmax) " "but got %s" % str(limits)) return GeometryEntity.__new__(cls, Tuple(*fun), Tuple(*limits)) def __call__(self, f): return self.subs(self.parameter, f) def _eval_subs(self, old, new): if old == self.parameter: return Point(*[f.subs(old, new) for f in self.functions]) def arbitrary_point(self, parameter='t'): """A parameterized point on the curve. Parameters ========== parameter : str or Symbol, optional Default value is 't'. The Curve's parameter is selected with None or self.parameter otherwise the provided symbol is used. Returns ======= Point : Returns a point in parametric form. Raises ====== ValueError When `parameter` already appears in the functions. Examples ======== >>> from sympy import Symbol >>> from sympy.abc import s >>> from sympy.geometry import Curve >>> C = Curve([2*s, s**2], (s, 0, 2)) >>> C.arbitrary_point() Point2D(2*t, t**2) >>> C.arbitrary_point(C.parameter) Point2D(2*s, s**2) >>> C.arbitrary_point(None) Point2D(2*s, s**2) >>> C.arbitrary_point(Symbol('a')) Point2D(2*a, a**2) See Also ======== sympy.geometry.point.Point """ if parameter is None: return Point(*self.functions) tnew = _symbol(parameter, self.parameter, real=True) t = self.parameter if (tnew.name != t.name and tnew.name in (f.name for f in self.free_symbols)): raise ValueError('Symbol %s already appears in object ' 'and cannot be used as a parameter.' % tnew.name) return Point(*[w.subs(t, tnew) for w in self.functions]) @property def free_symbols(self): """Return a set of symbols other than the bound symbols used to parametrically define the Curve. Returns ======= set : Set of all non-parameterized symbols. Examples ======== >>> from sympy.abc import t, a >>> from sympy.geometry import Curve >>> Curve((t, t**2), (t, 0, 2)).free_symbols set() >>> Curve((t, t**2), (t, a, 2)).free_symbols {a} """ free = set() for a in self.functions + self.limits[1:]: free |= a.free_symbols free = free.difference({self.parameter}) return free @property def ambient_dimension(self): """The dimension of the curve. Returns ======= int : the dimension of curve. Examples ======== >>> from sympy.abc import t >>> from sympy.geometry import Curve >>> C = Curve((t, t**2), (t, 0, 2)) >>> C.ambient_dimension 2 """ return len(self.args[0]) @property def functions(self): """The functions specifying the curve. Returns ======= functions : list of parameterized coordinate functions. Examples ======== >>> from sympy.abc import t >>> from sympy.geometry import Curve >>> C = Curve((t, t**2), (t, 0, 2)) >>> C.functions (t, t**2) See Also ======== parameter """ return self.args[0] @property def limits(self): """The limits for the curve. Returns ======= limits : tuple Contains parameter and lower and upper limits. Examples ======== >>> from sympy.abc import t >>> from sympy.geometry import Curve >>> C = Curve([t, t**3], (t, -2, 2)) >>> C.limits (t, -2, 2) See Also ======== plot_interval """ return self.args[1] @property def parameter(self): """The curve function variable. Returns ======= Symbol : returns a bound symbol. Examples ======== >>> from sympy.abc import t >>> from sympy.geometry import Curve >>> C = Curve([t, t**2], (t, 0, 2)) >>> C.parameter t See Also ======== functions """ return self.args[1][0] @property def length(self): """The curve length. Examples ======== >>> from sympy.geometry.curve import Curve >>> from sympy.abc import t >>> Curve((t, t), (t, 0, 1)).length sqrt(2) """ integrand = sqrt(sum(diff(func, self.limits[0])**2 for func in self.functions)) return integrate(integrand, self.limits) def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the curve. Parameters ========== parameter : str or Symbol, optional Default value is 't'; otherwise the provided symbol is used. Returns ======= List : the plot interval as below: [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Curve, sin >>> from sympy.abc import x, s >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval() [t, 1, 2] >>> Curve((x, sin(x)), (x, 1, 2)).plot_interval(s) [s, 1, 2] See Also ======== limits : Returns limits of the parameter interval """ t = _symbol(parameter, self.parameter, real=True) return [t] + list(self.limits[1:]) def rotate(self, angle=0, pt=None): """This function is used to rotate a curve along given point ``pt`` at given angle(in radian). Parameters ========== angle : the angle at which the curve will be rotated(in radian) in counterclockwise direction. default value of angle is 0. pt : Point the point along which the curve will be rotated. If no point given, the curve will be rotated around origin. Returns ======= Curve : returns a curve rotated at given angle along given point. Examples ======== >>> from sympy.geometry.curve import Curve >>> from sympy.abc import x >>> from sympy import pi >>> Curve((x, x), (x, 0, 1)).rotate(pi/2) Curve((-x, x), (x, 0, 1)) """ from sympy.matrices import Matrix, rot_axis3 if pt: pt = -Point(pt, dim=2) else: pt = Point(0,0) rv = self.translate(*pt.args) f = list(rv.functions) f.append(0) f = Matrix(1, 3, f) f *= rot_axis3(angle) rv = self.func(f[0, :2].tolist()[0], self.limits) pt = -pt return rv.translate(*pt.args) def scale(self, x=1, y=1, pt=None): """Override GeometryEntity.scale since Curve is not made up of Points. Returns ======= Curve : returns scaled curve. Examples ======== >>> from sympy.geometry.curve import Curve >>> from sympy.abc import x >>> Curve((x, x), (x, 0, 1)).scale(2) Curve((2*x, x), (x, 0, 1)) """ if pt: pt = Point(pt, dim=2) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) fx, fy = self.functions return self.func((fx*x, fy*y), self.limits) def translate(self, x=0, y=0): """Translate the Curve by (x, y). Returns ======= Curve : returns a translated curve. Examples ======== >>> from sympy.geometry.curve import Curve >>> from sympy.abc import x >>> Curve((x, x), (x, 0, 1)).translate(1, 2) Curve((x + 1, x + 2), (x, 0, 1)) """ fx, fy = self.functions return self.func((fx + x, fy + y), self.limits) sympy-sympy-1.9/sympy/geometry/ellipse.py000066400000000000000000001431451412543434000207560ustar00rootroot00000000000000"""Elliptical geometrical entities. Contains * Ellipse * Circle """ from sympy import Expr, Eq from sympy.core import S, pi, sympify from sympy.core.parameters import global_parameters from sympy.core.logic import fuzzy_bool from sympy.core.numbers import Rational, oo from sympy.core.compatibility import ordered from sympy.core.symbol import Dummy, uniquely_named_symbol, _symbol from sympy.simplify import simplify, trigsimp from sympy.functions.elementary.miscellaneous import sqrt, Max from sympy.functions.elementary.trigonometric import cos, sin from sympy.functions.special.elliptic_integrals import elliptic_e from sympy.geometry.exceptions import GeometryError from sympy.geometry.line import Ray2D, Segment2D, Line2D, LinearEntity3D from sympy.polys import DomainError, Poly, PolynomialError from sympy.polys.polyutils import _not_a_coeff, _nsort from sympy.solvers import solve from sympy.solvers.solveset import linear_coeffs from sympy.utilities.misc import filldedent, func_name from .entity import GeometryEntity, GeometrySet from .point import Point, Point2D, Point3D from .line import Line, Segment from .util import idiff import random class Ellipse(GeometrySet): """An elliptical GeometryEntity. Parameters ========== center : Point, optional Default value is Point(0, 0) hradius : number or SymPy expression, optional vradius : number or SymPy expression, optional eccentricity : number or SymPy expression, optional Two of `hradius`, `vradius` and `eccentricity` must be supplied to create an Ellipse. The third is derived from the two supplied. Attributes ========== center hradius vradius area circumference eccentricity periapsis apoapsis focus_distance foci Raises ====== GeometryError When `hradius`, `vradius` and `eccentricity` are incorrectly supplied as parameters. TypeError When `center` is not a Point. See Also ======== Circle Notes ----- Constructed from a center and two radii, the first being the horizontal radius (along the x-axis) and the second being the vertical radius (along the y-axis). When symbolic value for hradius and vradius are used, any calculation that refers to the foci or the major or minor axis will assume that the ellipse has its major radius on the x-axis. If this is not true then a manual rotation is necessary. Examples ======== >>> from sympy import Ellipse, Point, Rational >>> e1 = Ellipse(Point(0, 0), 5, 1) >>> e1.hradius, e1.vradius (5, 1) >>> e2 = Ellipse(Point(3, 1), hradius=3, eccentricity=Rational(4, 5)) >>> e2 Ellipse(Point2D(3, 1), 3, 9/5) """ def __contains__(self, o): if isinstance(o, Point): x = Dummy('x', real=True) y = Dummy('y', real=True) res = self.equation(x, y).subs({x: o.x, y: o.y}) return trigsimp(simplify(res)) is S.Zero elif isinstance(o, Ellipse): return self == o return False def __eq__(self, o): """Is the other GeometryEntity the same as this ellipse?""" return isinstance(o, Ellipse) and (self.center == o.center and self.hradius == o.hradius and self.vradius == o.vradius) def __hash__(self): return super().__hash__() def __new__( cls, center=None, hradius=None, vradius=None, eccentricity=None, **kwargs): hradius = sympify(hradius) vradius = sympify(vradius) eccentricity = sympify(eccentricity) if center is None: center = Point(0, 0) else: center = Point(center, dim=2) if len(center) != 2: raise ValueError('The center of "{}" must be a two dimensional point'.format(cls)) if len(list(filter(lambda x: x is not None, (hradius, vradius, eccentricity)))) != 2: raise ValueError(filldedent(''' Exactly two arguments of "hradius", "vradius", and "eccentricity" must not be None.''')) if eccentricity is not None: if eccentricity.is_negative: raise GeometryError("Eccentricity of ellipse/circle should lie between [0, 1)") elif hradius is None: hradius = vradius / sqrt(1 - eccentricity**2) elif vradius is None: vradius = hradius * sqrt(1 - eccentricity**2) if hradius == vradius: return Circle(center, hradius, **kwargs) if hradius == 0 or vradius == 0: return Segment(Point(center[0] - hradius, center[1] - vradius), Point(center[0] + hradius, center[1] + vradius)) if hradius.is_real is False or vradius.is_real is False: raise GeometryError("Invalid value encountered when computing hradius / vradius.") return GeometryEntity.__new__(cls, center, hradius, vradius, **kwargs) def _svg(self, scale_factor=1., fill_color="#66cc99"): """Returns SVG ellipse element for the Ellipse. Parameters ========== scale_factor : float Multiplication factor for the SVG stroke-width. Default is 1. fill_color : str, optional Hex string for fill color. Default is "#66cc99". """ from sympy.core.evalf import N c = N(self.center) h, v = N(self.hradius), N(self.vradius) return ( '' ).format(2. * scale_factor, fill_color, c.x, c.y, h, v) @property def ambient_dimension(self): return 2 @property def apoapsis(self): """The apoapsis of the ellipse. The greatest distance between the focus and the contour. Returns ======= apoapsis : number See Also ======== periapsis : Returns shortest distance between foci and contour Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.apoapsis 2*sqrt(2) + 3 """ return self.major * (1 + self.eccentricity) def arbitrary_point(self, parameter='t'): """A parameterized point on the ellipse. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= arbitrary_point : Point Raises ====== ValueError When `parameter` already appears in the functions. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.arbitrary_point() Point2D(3*cos(t), 2*sin(t)) """ t = _symbol(parameter, real=True) if t.name in (f.name for f in self.free_symbols): raise ValueError(filldedent('Symbol %s already appears in object ' 'and cannot be used as a parameter.' % t.name)) return Point(self.center.x + self.hradius*cos(t), self.center.y + self.vradius*sin(t)) @property def area(self): """The area of the ellipse. Returns ======= area : number Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.area 3*pi """ return simplify(S.Pi * self.hradius * self.vradius) @property def bounds(self): """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding rectangle for the geometric figure. """ h, v = self.hradius, self.vradius return (self.center.x - h, self.center.y - v, self.center.x + h, self.center.y + v) @property def center(self): """The center of the ellipse. Returns ======= center : number See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.center Point2D(0, 0) """ return self.args[0] @property def circumference(self): """The circumference of the ellipse. Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.circumference 12*elliptic_e(8/9) """ if self.eccentricity == 1: # degenerate return 4*self.major elif self.eccentricity == 0: # circle return 2*pi*self.hradius else: return 4*self.major*elliptic_e(self.eccentricity**2) @property def eccentricity(self): """The eccentricity of the ellipse. Returns ======= eccentricity : number Examples ======== >>> from sympy import Point, Ellipse, sqrt >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, sqrt(2)) >>> e1.eccentricity sqrt(7)/3 """ return self.focus_distance / self.major def encloses_point(self, p): """ Return True if p is enclosed by (is inside of) self. Notes ----- Being on the border of self is considered False. Parameters ========== p : Point Returns ======= encloses_point : True, False or None See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Ellipse, S >>> from sympy.abc import t >>> e = Ellipse((0, 0), 3, 2) >>> e.encloses_point((0, 0)) True >>> e.encloses_point(e.arbitrary_point(t).subs(t, S.Half)) False >>> e.encloses_point((4, 0)) False """ p = Point(p, dim=2) if p in self: return False if len(self.foci) == 2: # if the combined distance from the foci to p (h1 + h2) is less # than the combined distance from the foci to the minor axis # (which is the same as the major axis length) then p is inside # the ellipse h1, h2 = [f.distance(p) for f in self.foci] test = 2*self.major - (h1 + h2) else: test = self.radius - self.center.distance(p) return fuzzy_bool(test.is_positive) def equation(self, x='x', y='y', _slope=None): """ Returns the equation of an ellipse aligned with the x and y axes; when slope is given, the equation returned corresponds to an ellipse with a major axis having that slope. Parameters ========== x : str, optional Label for the x-axis. Default value is 'x'. y : str, optional Label for the y-axis. Default value is 'y'. _slope : Expr, optional The slope of the major axis. Ignored when 'None'. Returns ======= equation : sympy expression See Also ======== arbitrary_point : Returns parameterized point on ellipse Examples ======== >>> from sympy import Point, Ellipse, pi >>> from sympy.abc import x, y >>> e1 = Ellipse(Point(1, 0), 3, 2) >>> eq1 = e1.equation(x, y); eq1 y**2/4 + (x/3 - 1/3)**2 - 1 >>> eq2 = e1.equation(x, y, _slope=1); eq2 (-x + y + 1)**2/8 + (x + y - 1)**2/18 - 1 A point on e1 satisfies eq1. Let's use one on the x-axis: >>> p1 = e1.center + Point(e1.major, 0) >>> assert eq1.subs(x, p1.x).subs(y, p1.y) == 0 When rotated the same as the rotated ellipse, about the center point of the ellipse, it will satisfy the rotated ellipse's equation, too: >>> r1 = p1.rotate(pi/4, e1.center) >>> assert eq2.subs(x, r1.x).subs(y, r1.y) == 0 References ========== .. [1] https://math.stackexchange.com/questions/108270/what-is-the-equation-of-an-ellipse-that-is-not-aligned-with-the-axis .. [2] https://en.wikipedia.org/wiki/Ellipse#Equation_of_a_shifted_ellipse """ x = _symbol(x, real=True) y = _symbol(y, real=True) dx = x - self.center.x dy = y - self.center.y if _slope is not None: L = (dy - _slope*dx)**2 l = (_slope*dy + dx)**2 h = 1 + _slope**2 b = h*self.major**2 a = h*self.minor**2 return l/b + L/a - 1 else: t1 = (dx/self.hradius)**2 t2 = (dy/self.vradius)**2 return t1 + t2 - 1 def evolute(self, x='x', y='y'): """The equation of evolute of the ellipse. Parameters ========== x : str, optional Label for the x-axis. Default value is 'x'. y : str, optional Label for the y-axis. Default value is 'y'. Returns ======= equation : sympy expression Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(1, 0), 3, 2) >>> e1.evolute() 2**(2/3)*y**(2/3) + (3*x - 3)**(2/3) - 5**(2/3) """ if len(self.args) != 3: raise NotImplementedError('Evolute of arbitrary Ellipse is not supported.') x = _symbol(x, real=True) y = _symbol(y, real=True) t1 = (self.hradius*(x - self.center.x))**Rational(2, 3) t2 = (self.vradius*(y - self.center.y))**Rational(2, 3) return t1 + t2 - (self.hradius**2 - self.vradius**2)**Rational(2, 3) @property def foci(self): """The foci of the ellipse. Notes ----- The foci can only be calculated if the major/minor axes are known. Raises ====== ValueError When the major and minor axis cannot be determined. See Also ======== sympy.geometry.point.Point focus_distance : Returns the distance between focus and center Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.foci (Point2D(-2*sqrt(2), 0), Point2D(2*sqrt(2), 0)) """ c = self.center hr, vr = self.hradius, self.vradius if hr == vr: return (c, c) # calculate focus distance manually, since focus_distance calls this # routine fd = sqrt(self.major**2 - self.minor**2) if hr == self.minor: # foci on the y-axis return (c + Point(0, -fd), c + Point(0, fd)) elif hr == self.major: # foci on the x-axis return (c + Point(-fd, 0), c + Point(fd, 0)) @property def focus_distance(self): """The focal distance of the ellipse. The distance between the center and one focus. Returns ======= focus_distance : number See Also ======== foci Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.focus_distance 2*sqrt(2) """ return Point.distance(self.center, self.foci[0]) @property def hradius(self): """The horizontal radius of the ellipse. Returns ======= hradius : number See Also ======== vradius, major, minor Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.hradius 3 """ return self.args[1] def intersection(self, o): """The intersection of this ellipse and another geometrical entity `o`. Parameters ========== o : GeometryEntity Returns ======= intersection : list of GeometryEntity objects Notes ----- Currently supports intersections with Point, Line, Segment, Ray, Circle and Ellipse types. See Also ======== sympy.geometry.entity.GeometryEntity Examples ======== >>> from sympy import Ellipse, Point, Line >>> e = Ellipse(Point(0, 0), 5, 7) >>> e.intersection(Point(0, 0)) [] >>> e.intersection(Point(5, 0)) [Point2D(5, 0)] >>> e.intersection(Line(Point(0,0), Point(0, 1))) [Point2D(0, -7), Point2D(0, 7)] >>> e.intersection(Line(Point(5,0), Point(5, 1))) [Point2D(5, 0)] >>> e.intersection(Line(Point(6,0), Point(6, 1))) [] >>> e = Ellipse(Point(-1, 0), 4, 3) >>> e.intersection(Ellipse(Point(1, 0), 4, 3)) [Point2D(0, -3*sqrt(15)/4), Point2D(0, 3*sqrt(15)/4)] >>> e.intersection(Ellipse(Point(5, 0), 4, 3)) [Point2D(2, -3*sqrt(7)/4), Point2D(2, 3*sqrt(7)/4)] >>> e.intersection(Ellipse(Point(100500, 0), 4, 3)) [] >>> e.intersection(Ellipse(Point(0, 0), 3, 4)) [Point2D(3, 0), Point2D(-363/175, -48*sqrt(111)/175), Point2D(-363/175, 48*sqrt(111)/175)] >>> e.intersection(Ellipse(Point(-1, 0), 3, 4)) [Point2D(-17/5, -12/5), Point2D(-17/5, 12/5), Point2D(7/5, -12/5), Point2D(7/5, 12/5)] """ # TODO: Replace solve with nonlinsolve, when nonlinsolve will be able to solve in real domain x = Dummy('x', real=True) y = Dummy('y', real=True) if isinstance(o, Point): if o in self: return [o] else: return [] elif isinstance(o, (Segment2D, Ray2D)): ellipse_equation = self.equation(x, y) result = solve([ellipse_equation, Line(o.points[0], o.points[1]).equation(x, y)], [x, y]) return list(ordered([Point(i) for i in result if i in o])) elif isinstance(o, Polygon): return o.intersection(self) elif isinstance(o, (Ellipse, Line2D)): if o == self: return self else: ellipse_equation = self.equation(x, y) return list(ordered([Point(i) for i in solve([ellipse_equation, o.equation(x, y)], [x, y])])) elif isinstance(o, LinearEntity3D): raise TypeError('Entity must be two dimensional, not three dimensional') else: raise TypeError('Intersection not handled for %s' % func_name(o)) def is_tangent(self, o): """Is `o` tangent to the ellipse? Parameters ========== o : GeometryEntity An Ellipse, LinearEntity or Polygon Raises ====== NotImplementedError When the wrong type of argument is supplied. Returns ======= is_tangent: boolean True if o is tangent to the ellipse, False otherwise. See Also ======== tangent_lines Examples ======== >>> from sympy import Point, Ellipse, Line >>> p0, p1, p2 = Point(0, 0), Point(3, 0), Point(3, 3) >>> e1 = Ellipse(p0, 3, 2) >>> l1 = Line(p1, p2) >>> e1.is_tangent(l1) True """ if isinstance(o, Point2D): return False elif isinstance(o, Ellipse): intersect = self.intersection(o) if isinstance(intersect, Ellipse): return True elif intersect: return all((self.tangent_lines(i)[0]).equals(o.tangent_lines(i)[0]) for i in intersect) else: return False elif isinstance(o, Line2D): hit = self.intersection(o) if not hit: return False if len(hit) == 1: return True # might return None if it can't decide return hit[0].equals(hit[1]) elif isinstance(o, Ray2D): intersect = self.intersection(o) if len(intersect) == 1: return intersect[0] != o.source and not self.encloses_point(o.source) else: return False elif isinstance(o, (Segment2D, Polygon)): all_tangents = False segments = o.sides if isinstance(o, Polygon) else [o] for segment in segments: intersect = self.intersection(segment) if len(intersect) == 1: if not any(intersect[0] in i for i in segment.points) \ and all(not self.encloses_point(i) for i in segment.points): all_tangents = True continue else: return False else: return all_tangents return all_tangents elif isinstance(o, (LinearEntity3D, Point3D)): raise TypeError('Entity must be two dimensional, not three dimensional') else: raise TypeError('Is_tangent not handled for %s' % func_name(o)) @property def major(self): """Longer axis of the ellipse (if it can be determined) else hradius. Returns ======= major : number or expression See Also ======== hradius, vradius, minor Examples ======== >>> from sympy import Point, Ellipse, Symbol >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.major 3 >>> a = Symbol('a') >>> b = Symbol('b') >>> Ellipse(p1, a, b).major a >>> Ellipse(p1, b, a).major b >>> m = Symbol('m') >>> M = m + 1 >>> Ellipse(p1, m, M).major m + 1 """ ab = self.args[1:3] if len(ab) == 1: return ab[0] a, b = ab o = b - a < 0 if o == True: return a elif o == False: return b return self.hradius @property def minor(self): """Shorter axis of the ellipse (if it can be determined) else vradius. Returns ======= minor : number or expression See Also ======== hradius, vradius, major Examples ======== >>> from sympy import Point, Ellipse, Symbol >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.minor 1 >>> a = Symbol('a') >>> b = Symbol('b') >>> Ellipse(p1, a, b).minor b >>> Ellipse(p1, b, a).minor a >>> m = Symbol('m') >>> M = m + 1 >>> Ellipse(p1, m, M).minor m """ ab = self.args[1:3] if len(ab) == 1: return ab[0] a, b = ab o = a - b < 0 if o == True: return a elif o == False: return b return self.vradius def normal_lines(self, p, prec=None): """Normal lines between `p` and the ellipse. Parameters ========== p : Point Returns ======= normal_lines : list with 1, 2 or 4 Lines Examples ======== >>> from sympy import Point, Ellipse >>> e = Ellipse((0, 0), 2, 3) >>> c = e.center >>> e.normal_lines(c + Point(1, 0)) [Line2D(Point2D(0, 0), Point2D(1, 0))] >>> e.normal_lines(c) [Line2D(Point2D(0, 0), Point2D(0, 1)), Line2D(Point2D(0, 0), Point2D(1, 0))] Off-axis points require the solution of a quartic equation. This often leads to very large expressions that may be of little practical use. An approximate solution of `prec` digits can be obtained by passing in the desired value: >>> e.normal_lines((3, 3), prec=2) [Line2D(Point2D(-0.81, -2.7), Point2D(0.19, -1.2)), Line2D(Point2D(1.5, -2.0), Point2D(2.5, -2.7))] Whereas the above solution has an operation count of 12, the exact solution has an operation count of 2020. """ p = Point(p, dim=2) # XXX change True to something like self.angle == 0 if the arbitrarily # rotated ellipse is introduced. # https://github.com/sympy/sympy/issues/2815) if True: rv = [] if p.x == self.center.x: rv.append(Line(self.center, slope=oo)) if p.y == self.center.y: rv.append(Line(self.center, slope=0)) if rv: # at these special orientations of p either 1 or 2 normals # exist and we are done return rv # find the 4 normal points and construct lines through them with # the corresponding slope x, y = Dummy('x', real=True), Dummy('y', real=True) eq = self.equation(x, y) dydx = idiff(eq, y, x) norm = -1/dydx slope = Line(p, (x, y)).slope seq = slope - norm # TODO: Replace solve with solveset, when this line is tested yis = solve(seq, y)[0] xeq = eq.subs(y, yis).as_numer_denom()[0].expand() if len(xeq.free_symbols) == 1: try: # this is so much faster, it's worth a try xsol = Poly(xeq, x).real_roots() except (DomainError, PolynomialError, NotImplementedError): # TODO: Replace solve with solveset, when these lines are tested xsol = _nsort(solve(xeq, x), separated=True)[0] points = [Point(i, solve(eq.subs(x, i), y)[0]) for i in xsol] else: raise NotImplementedError( 'intersections for the general ellipse are not supported') slopes = [norm.subs(zip((x, y), pt.args)) for pt in points] if prec is not None: points = [pt.n(prec) for pt in points] slopes = [i if _not_a_coeff(i) else i.n(prec) for i in slopes] return [Line(pt, slope=s) for pt, s in zip(points, slopes)] @property def periapsis(self): """The periapsis of the ellipse. The shortest distance between the focus and the contour. Returns ======= periapsis : number See Also ======== apoapsis : Returns greatest distance between focus and contour Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.periapsis 3 - 2*sqrt(2) """ return self.major * (1 - self.eccentricity) @property def semilatus_rectum(self): """ Calculates the semi-latus rectum of the Ellipse. Semi-latus rectum is defined as one half of the the chord through a focus parallel to the conic section directrix of a conic section. Returns ======= semilatus_rectum : number See Also ======== apoapsis : Returns greatest distance between focus and contour periapsis : The shortest distance between the focus and the contour Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.semilatus_rectum 1/3 References ========== [1] http://mathworld.wolfram.com/SemilatusRectum.html [2] https://en.wikipedia.org/wiki/Ellipse#Semi-latus_rectum """ return self.major * (1 - self.eccentricity ** 2) def auxiliary_circle(self): """Returns a Circle whose diameter is the major axis of the ellipse. Examples ======== >>> from sympy import Ellipse, Point, symbols >>> c = Point(1, 2) >>> Ellipse(c, 8, 7).auxiliary_circle() Circle(Point2D(1, 2), 8) >>> a, b = symbols('a b') >>> Ellipse(c, a, b).auxiliary_circle() Circle(Point2D(1, 2), Max(a, b)) """ return Circle(self.center, Max(self.hradius, self.vradius)) def director_circle(self): """ Returns a Circle consisting of all points where two perpendicular tangent lines to the ellipse cross each other. Returns ======= Circle A director circle returned as a geometric object. Examples ======== >>> from sympy import Ellipse, Point, symbols >>> c = Point(3,8) >>> Ellipse(c, 7, 9).director_circle() Circle(Point2D(3, 8), sqrt(130)) >>> a, b = symbols('a b') >>> Ellipse(c, a, b).director_circle() Circle(Point2D(3, 8), sqrt(a**2 + b**2)) References ========== .. [1] https://en.wikipedia.org/wiki/Director_circle """ return Circle(self.center, sqrt(self.hradius**2 + self.vradius**2)) def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the Ellipse. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.plot_interval() [t, -pi, pi] """ t = _symbol(parameter, real=True) return [t, -S.Pi, S.Pi] def random_point(self, seed=None): """A random point on the ellipse. Returns ======= point : Point Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.random_point() # gives some random point Point2D(...) >>> p1 = e1.random_point(seed=0); p1.n(2) Point2D(2.1, 1.4) Notes ===== When creating a random point, one may simply replace the parameter with a random number. When doing so, however, the random number should be made a Rational or else the point may not test as being in the ellipse: >>> from sympy.abc import t >>> from sympy import Rational >>> arb = e1.arbitrary_point(t); arb Point2D(3*cos(t), 2*sin(t)) >>> arb.subs(t, .1) in e1 False >>> arb.subs(t, Rational(.1)) in e1 True >>> arb.subs(t, Rational('.1')) in e1 True See Also ======== sympy.geometry.point.Point arbitrary_point : Returns parameterized point on ellipse """ from sympy import sin, cos, Rational t = _symbol('t', real=True) x, y = self.arbitrary_point(t).args # get a random value in [-1, 1) corresponding to cos(t) # and confirm that it will test as being in the ellipse if seed is not None: rng = random.Random(seed) else: rng = random # simplify this now or else the Float will turn s into a Float r = Rational(rng.random()) c = 2*r - 1 s = sqrt(1 - c**2) return Point(x.subs(cos(t), c), y.subs(sin(t), s)) def reflect(self, line): """Override GeometryEntity.reflect since the radius is not a GeometryEntity. Examples ======== >>> from sympy import Circle, Line >>> Circle((0, 1), 1).reflect(Line((0, 0), (1, 1))) Circle(Point2D(1, 0), -1) >>> from sympy import Ellipse, Line, Point >>> Ellipse(Point(3, 4), 1, 3).reflect(Line(Point(0, -4), Point(5, 0))) Traceback (most recent call last): ... NotImplementedError: General Ellipse is not supported but the equation of the reflected Ellipse is given by the zeros of: f(x, y) = (9*x/41 + 40*y/41 + 37/41)**2 + (40*x/123 - 3*y/41 - 364/123)**2 - 1 Notes ===== Until the general ellipse (with no axis parallel to the x-axis) is supported a NotImplemented error is raised and the equation whose zeros define the rotated ellipse is given. """ if line.slope in (0, oo): c = self.center c = c.reflect(line) return self.func(c, -self.hradius, self.vradius) else: x, y = [uniquely_named_symbol( name, (self, line), modify=lambda s: '_' + s, real=True) for name in 'xy'] expr = self.equation(x, y) p = Point(x, y).reflect(line) result = expr.subs(zip((x, y), p.args ), simultaneous=True) raise NotImplementedError(filldedent( 'General Ellipse is not supported but the equation ' 'of the reflected Ellipse is given by the zeros of: ' + "f(%s, %s) = %s" % (str(x), str(y), str(result)))) def rotate(self, angle=0, pt=None): """Rotate ``angle`` radians counterclockwise about Point ``pt``. Note: since the general ellipse is not supported, only rotations that are integer multiples of pi/2 are allowed. Examples ======== >>> from sympy import Ellipse, pi >>> Ellipse((1, 0), 2, 1).rotate(pi/2) Ellipse(Point2D(0, 1), 1, 2) >>> Ellipse((1, 0), 2, 1).rotate(pi) Ellipse(Point2D(-1, 0), 2, 1) """ if self.hradius == self.vradius: return self.func(self.center.rotate(angle, pt), self.hradius) if (angle/S.Pi).is_integer: return super().rotate(angle, pt) if (2*angle/S.Pi).is_integer: return self.func(self.center.rotate(angle, pt), self.vradius, self.hradius) # XXX see https://github.com/sympy/sympy/issues/2815 for general ellipes raise NotImplementedError('Only rotations of pi/2 are currently supported for Ellipse.') def scale(self, x=1, y=1, pt=None): """Override GeometryEntity.scale since it is the major and minor axes which must be scaled and they are not GeometryEntities. Examples ======== >>> from sympy import Ellipse >>> Ellipse((0, 0), 2, 1).scale(2, 4) Circle(Point2D(0, 0), 4) >>> Ellipse((0, 0), 2, 1).scale(2) Ellipse(Point2D(0, 0), 4, 1) """ c = self.center if pt: pt = Point(pt, dim=2) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) h = self.hradius v = self.vradius return self.func(c.scale(x, y), hradius=h*x, vradius=v*y) def tangent_lines(self, p): """Tangent lines between `p` and the ellipse. If `p` is on the ellipse, returns the tangent line through point `p`. Otherwise, returns the tangent line(s) from `p` to the ellipse, or None if no tangent line is possible (e.g., `p` inside ellipse). Parameters ========== p : Point Returns ======= tangent_lines : list with 1 or 2 Lines Raises ====== NotImplementedError Can only find tangent lines for a point, `p`, on the ellipse. See Also ======== sympy.geometry.point.Point, sympy.geometry.line.Line Examples ======== >>> from sympy import Point, Ellipse >>> e1 = Ellipse(Point(0, 0), 3, 2) >>> e1.tangent_lines(Point(3, 0)) [Line2D(Point2D(3, 0), Point2D(3, -12))] """ p = Point(p, dim=2) if self.encloses_point(p): return [] if p in self: delta = self.center - p rise = (self.vradius**2)*delta.x run = -(self.hradius**2)*delta.y p2 = Point(simplify(p.x + run), simplify(p.y + rise)) return [Line(p, p2)] else: if len(self.foci) == 2: f1, f2 = self.foci maj = self.hradius test = (2*maj - Point.distance(f1, p) - Point.distance(f2, p)) else: test = self.radius - Point.distance(self.center, p) if test.is_number and test.is_positive: return [] # else p is outside the ellipse or we can't tell. In case of the # latter, the solutions returned will only be valid if # the point is not inside the ellipse; if it is, nan will result. x, y = Dummy('x'), Dummy('y') eq = self.equation(x, y) dydx = idiff(eq, y, x) slope = Line(p, Point(x, y)).slope # TODO: Replace solve with solveset, when this line is tested tangent_points = solve([slope - dydx, eq], [x, y]) # handle horizontal and vertical tangent lines if len(tangent_points) == 1: if tangent_points[0][ 0] == p.x or tangent_points[0][1] == p.y: return [Line(p, p + Point(1, 0)), Line(p, p + Point(0, 1))] else: return [Line(p, p + Point(0, 1)), Line(p, tangent_points[0])] # others return [Line(p, tangent_points[0]), Line(p, tangent_points[1])] @property def vradius(self): """The vertical radius of the ellipse. Returns ======= vradius : number See Also ======== hradius, major, minor Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.vradius 1 """ return self.args[2] def second_moment_of_area(self, point=None): """Returns the second moment and product moment area of an ellipse. Parameters ========== point : Point, two-tuple of sympifiable objects, or None(default=None) point is the point about which second moment of area is to be found. If "point=None" it will be calculated about the axis passing through the centroid of the ellipse. Returns ======= I_xx, I_yy, I_xy : number or sympy expression I_xx, I_yy are second moment of area of an ellise. I_xy is product moment of area of an ellipse. Examples ======== >>> from sympy import Point, Ellipse >>> p1 = Point(0, 0) >>> e1 = Ellipse(p1, 3, 1) >>> e1.second_moment_of_area() (3*pi/4, 27*pi/4, 0) References ========== https://en.wikipedia.org/wiki/List_of_second_moments_of_area """ I_xx = (S.Pi*(self.hradius)*(self.vradius**3))/4 I_yy = (S.Pi*(self.hradius**3)*(self.vradius))/4 I_xy = 0 if point is None: return I_xx, I_yy, I_xy # parallel axis theorem I_xx = I_xx + self.area*((point[1] - self.center.y)**2) I_yy = I_yy + self.area*((point[0] - self.center.x)**2) I_xy = I_xy + self.area*(point[0] - self.center.x)*(point[1] - self.center.y) return I_xx, I_yy, I_xy def polar_second_moment_of_area(self): """Returns the polar second moment of area of an Ellipse It is a constituent of the second moment of area, linked through the perpendicular axis theorem. While the planar second moment of area describes an object's resistance to deflection (bending) when subjected to a force applied to a plane parallel to the central axis, the polar second moment of area describes an object's resistance to deflection when subjected to a moment applied in a plane perpendicular to the object's central axis (i.e. parallel to the cross-section) References ========== https://en.wikipedia.org/wiki/Polar_moment_of_inertia Examples ======== >>> from sympy import symbols, Circle, Ellipse >>> c = Circle((5, 5), 4) >>> c.polar_second_moment_of_area() 128*pi >>> a, b = symbols('a, b') >>> e = Ellipse((0, 0), a, b) >>> e.polar_second_moment_of_area() pi*a**3*b/4 + pi*a*b**3/4 """ second_moment = self.second_moment_of_area() return second_moment[0] + second_moment[1] def section_modulus(self, point=None): """Returns a tuple with the section modulus of an ellipse Section modulus is a geometric property of an ellipse defined as the ratio of second moment of area to the distance of the extreme end of the ellipse from the centroidal axis. References ========== https://en.wikipedia.org/wiki/Section_modulus Parameters ========== point : Point, two-tuple of sympifyable objects, or None(default=None) point is the point at which section modulus is to be found. If "point=None" section modulus will be calculated for the point farthest from the centroidal axis of the ellipse. Returns ======= S_x, S_y: numbers or SymPy expressions S_x is the section modulus with respect to the x-axis S_y is the section modulus with respect to the y-axis A negative sign indicates that the section modulus is determined for a point below the centroidal axis. Examples ======== >>> from sympy import Symbol, Ellipse, Circle, Point2D >>> d = Symbol('d', positive=True) >>> c = Circle((0, 0), d/2) >>> c.section_modulus() (pi*d**3/32, pi*d**3/32) >>> e = Ellipse(Point2D(0, 0), 2, 4) >>> e.section_modulus() (8*pi, 4*pi) >>> e.section_modulus((2, 2)) (16*pi, 4*pi) """ x_c, y_c = self.center if point is None: # taking x and y as maximum distances from centroid x_min, y_min, x_max, y_max = self.bounds y = max(y_c - y_min, y_max - y_c) x = max(x_c - x_min, x_max - x_c) else: # taking x and y as distances of the given point from the center point = Point2D(point) y = point.y - y_c x = point.x - x_c second_moment = self.second_moment_of_area() S_x = second_moment[0]/y S_y = second_moment[1]/x return S_x, S_y class Circle(Ellipse): """A circle in space. Constructed simply from a center and a radius, from three non-collinear points, or the equation of a circle. Parameters ========== center : Point radius : number or sympy expression points : sequence of three Points equation : equation of a circle Attributes ========== radius (synonymous with hradius, vradius, major and minor) circumference equation Raises ====== GeometryError When the given equation is not that of a circle. When trying to construct circle from incorrect parameters. See Also ======== Ellipse, sympy.geometry.point.Point Examples ======== >>> from sympy import Eq >>> from sympy.geometry import Point, Circle >>> from sympy.abc import x, y, a, b A circle constructed from a center and radius: >>> c1 = Circle(Point(0, 0), 5) >>> c1.hradius, c1.vradius, c1.radius (5, 5, 5) A circle constructed from three points: >>> c2 = Circle(Point(0, 0), Point(1, 1), Point(1, 0)) >>> c2.hradius, c2.vradius, c2.radius, c2.center (sqrt(2)/2, sqrt(2)/2, sqrt(2)/2, Point2D(1/2, 1/2)) A circle can be constructed from an equation in the form `a*x**2 + by**2 + gx + hy + c = 0`, too: >>> Circle(x**2 + y**2 - 25) Circle(Point2D(0, 0), 5) If the variables corresponding to x and y are named something else, their name or symbol can be supplied: >>> Circle(Eq(a**2 + b**2, 25), x='a', y=b) Circle(Point2D(0, 0), 5) """ def __new__(cls, *args, **kwargs): from sympy.geometry.util import find from .polygon import Triangle evaluate = kwargs.get('evaluate', global_parameters.evaluate) if len(args) == 1 and isinstance(args[0], (Expr, Eq)): x = kwargs.get('x', 'x') y = kwargs.get('y', 'y') equation = args[0] if isinstance(equation, Eq): equation = equation.lhs - equation.rhs x = find(x, equation) y = find(y, equation) try: a, b, c, d, e = linear_coeffs(equation, x**2, y**2, x, y) except ValueError: raise GeometryError("The given equation is not that of a circle.") if a == 0 or b == 0 or a != b: raise GeometryError("The given equation is not that of a circle.") center_x = -c/a/2 center_y = -d/b/2 r2 = (center_x**2) + (center_y**2) - e return Circle((center_x, center_y), sqrt(r2), evaluate=evaluate) else: c, r = None, None if len(args) == 3: args = [Point(a, dim=2, evaluate=evaluate) for a in args] t = Triangle(*args) if not isinstance(t, Triangle): return t c = t.circumcenter r = t.circumradius elif len(args) == 2: # Assume (center, radius) pair c = Point(args[0], dim=2, evaluate=evaluate) r = args[1] # this will prohibit imaginary radius try: r = Point(r, 0, evaluate=evaluate).x except ValueError: raise GeometryError("Circle with imaginary radius is not permitted") if not (c is None or r is None): if r == 0: return c return GeometryEntity.__new__(cls, c, r, **kwargs) raise GeometryError("Circle.__new__ received unknown arguments") @property def circumference(self): """The circumference of the circle. Returns ======= circumference : number or SymPy expression Examples ======== >>> from sympy import Point, Circle >>> c1 = Circle(Point(3, 4), 6) >>> c1.circumference 12*pi """ return 2 * S.Pi * self.radius def equation(self, x='x', y='y'): """The equation of the circle. Parameters ========== x : str or Symbol, optional Default value is 'x'. y : str or Symbol, optional Default value is 'y'. Returns ======= equation : SymPy expression Examples ======== >>> from sympy import Point, Circle >>> c1 = Circle(Point(0, 0), 5) >>> c1.equation() x**2 + y**2 - 25 """ x = _symbol(x, real=True) y = _symbol(y, real=True) t1 = (x - self.center.x)**2 t2 = (y - self.center.y)**2 return t1 + t2 - self.major**2 def intersection(self, o): """The intersection of this circle with another geometrical entity. Parameters ========== o : GeometryEntity Returns ======= intersection : list of GeometryEntities Examples ======== >>> from sympy import Point, Circle, Line, Ray >>> p1, p2, p3 = Point(0, 0), Point(5, 5), Point(6, 0) >>> p4 = Point(5, 0) >>> c1 = Circle(p1, 5) >>> c1.intersection(p2) [] >>> c1.intersection(p4) [Point2D(5, 0)] >>> c1.intersection(Ray(p1, p2)) [Point2D(5*sqrt(2)/2, 5*sqrt(2)/2)] >>> c1.intersection(Line(p2, p3)) [] """ return Ellipse.intersection(self, o) @property def radius(self): """The radius of the circle. Returns ======= radius : number or sympy expression See Also ======== Ellipse.major, Ellipse.minor, Ellipse.hradius, Ellipse.vradius Examples ======== >>> from sympy import Point, Circle >>> c1 = Circle(Point(3, 4), 6) >>> c1.radius 6 """ return self.args[1] def reflect(self, line): """Override GeometryEntity.reflect since the radius is not a GeometryEntity. Examples ======== >>> from sympy import Circle, Line >>> Circle((0, 1), 1).reflect(Line((0, 0), (1, 1))) Circle(Point2D(1, 0), -1) """ c = self.center c = c.reflect(line) return self.func(c, -self.radius) def scale(self, x=1, y=1, pt=None): """Override GeometryEntity.scale since the radius is not a GeometryEntity. Examples ======== >>> from sympy import Circle >>> Circle((0, 0), 1).scale(2, 2) Circle(Point2D(0, 0), 2) >>> Circle((0, 0), 1).scale(2, 4) Ellipse(Point2D(0, 0), 2, 4) """ c = self.center if pt: pt = Point(pt, dim=2) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) c = c.scale(x, y) x, y = [abs(i) for i in (x, y)] if x == y: return self.func(c, x*self.radius) h = v = self.radius return Ellipse(c, hradius=h*x, vradius=v*y) @property def vradius(self): """ This Ellipse property is an alias for the Circle's radius. Whereas hradius, major and minor can use Ellipse's conventions, the vradius does not exist for a circle. It is always a positive value in order that the Circle, like Polygons, will have an area that can be positive or negative as determined by the sign of the hradius. Examples ======== >>> from sympy import Point, Circle >>> c1 = Circle(Point(3, 4), 6) >>> c1.vradius 6 """ return abs(self.radius) from .polygon import Polygon sympy-sympy-1.9/sympy/geometry/entity.py000066400000000000000000000501521412543434000206300ustar00rootroot00000000000000"""The definition of the base geometrical entity with attributes common to all derived geometrical entities. Contains ======== GeometryEntity GeometricSet Notes ===== A GeometryEntity is any object that has special geometric properties. A GeometrySet is a superclass of any GeometryEntity that can also be viewed as a sympy.sets.Set. In particular, points are the only GeometryEntity not considered a Set. Rn is a GeometrySet representing n-dimensional Euclidean space. R2 and R3 are currently the only ambient spaces implemented. """ from sympy.core.basic import Basic from sympy.core.compatibility import is_sequence from sympy.core.containers import Tuple from sympy.core.sympify import sympify from sympy.functions import cos, sin from sympy.matrices import eye from sympy.multipledispatch import dispatch from sympy.sets import Set from sympy.sets.handlers.intersection import intersection_sets from sympy.sets.handlers.union import union_sets from sympy.utilities.misc import func_name # How entities are ordered; used by __cmp__ in GeometryEntity ordering_of_classes = [ "Point2D", "Point3D", "Point", "Segment2D", "Ray2D", "Line2D", "Segment3D", "Line3D", "Ray3D", "Segment", "Ray", "Line", "Plane", "Triangle", "RegularPolygon", "Polygon", "Circle", "Ellipse", "Curve", "Parabola" ] class GeometryEntity(Basic): """The base class for all geometrical entities. This class doesn't represent any particular geometric entity, it only provides the implementation of some methods common to all subclasses. """ def __cmp__(self, other): """Comparison of two GeometryEntities.""" n1 = self.__class__.__name__ n2 = other.__class__.__name__ c = (n1 > n2) - (n1 < n2) if not c: return 0 i1 = -1 for cls in self.__class__.__mro__: try: i1 = ordering_of_classes.index(cls.__name__) break except ValueError: i1 = -1 if i1 == -1: return c i2 = -1 for cls in other.__class__.__mro__: try: i2 = ordering_of_classes.index(cls.__name__) break except ValueError: i2 = -1 if i2 == -1: return c return (i1 > i2) - (i1 < i2) def __contains__(self, other): """Subclasses should implement this method for anything more complex than equality.""" if type(self) == type(other): return self == other raise NotImplementedError() def __getnewargs__(self): """Returns a tuple that will be passed to __new__ on unpickling.""" return tuple(self.args) def __ne__(self, o): """Test inequality of two geometrical entities.""" return not self == o def __new__(cls, *args, **kwargs): # Points are sequences, but they should not # be converted to Tuples, so use this detection function instead. def is_seq_and_not_point(a): # we cannot use isinstance(a, Point) since we cannot import Point if hasattr(a, 'is_Point') and a.is_Point: return False return is_sequence(a) args = [Tuple(*a) if is_seq_and_not_point(a) else sympify(a) for a in args] return Basic.__new__(cls, *args) def __radd__(self, a): """Implementation of reverse add method.""" return a.__add__(self) def __rtruediv__(self, a): """Implementation of reverse division method.""" return a.__truediv__(self) def __repr__(self): """String representation of a GeometryEntity that can be evaluated by sympy.""" return type(self).__name__ + repr(self.args) def __rmul__(self, a): """Implementation of reverse multiplication method.""" return a.__mul__(self) def __rsub__(self, a): """Implementation of reverse subtraction method.""" return a.__sub__(self) def __str__(self): """String representation of a GeometryEntity.""" from sympy.printing import sstr return type(self).__name__ + sstr(self.args) def _eval_subs(self, old, new): from sympy.geometry.point import Point, Point3D if is_sequence(old) or is_sequence(new): if isinstance(self, Point3D): old = Point3D(old) new = Point3D(new) else: old = Point(old) new = Point(new) return self._subs(old, new) def _repr_svg_(self): """SVG representation of a GeometryEntity suitable for IPython""" from sympy.core.evalf import N try: bounds = self.bounds except (NotImplementedError, TypeError): # if we have no SVG representation, return None so IPython # will fall back to the next representation return None if any([not x.is_number or not x.is_finite for x in bounds]): return None svg_top = ''' ''' # Establish SVG canvas that will fit all the data + small space xmin, ymin, xmax, ymax = map(N, bounds) if xmin == xmax and ymin == ymax: # This is a point; buffer using an arbitrary size xmin, ymin, xmax, ymax = xmin - .5, ymin -.5, xmax + .5, ymax + .5 else: # Expand bounds by a fraction of the data ranges expand = 0.1 # or 10%; this keeps arrowheads in view (R plots use 4%) widest_part = max([xmax - xmin, ymax - ymin]) expand_amount = widest_part * expand xmin -= expand_amount ymin -= expand_amount xmax += expand_amount ymax += expand_amount dx = xmax - xmin dy = ymax - ymin width = min([max([100., dx]), 300]) height = min([max([100., dy]), 300]) scale_factor = 1. if max(width, height) == 0 else max(dx, dy) / max(width, height) try: svg = self._svg(scale_factor) except (NotImplementedError, TypeError): # if we have no SVG representation, return None so IPython # will fall back to the next representation return None view_box = "{} {} {} {}".format(xmin, ymin, dx, dy) transform = "matrix(1,0,0,-1,0,{})".format(ymax + ymin) svg_top = svg_top.format(view_box, width, height) return svg_top + ( '{}' ).format(transform, svg) def _svg(self, scale_factor=1., fill_color="#66cc99"): """Returns SVG path element for the GeometryEntity. Parameters ========== scale_factor : float Multiplication factor for the SVG stroke-width. Default is 1. fill_color : str, optional Hex string for fill color. Default is "#66cc99". """ raise NotImplementedError() def _sympy_(self): return self @property def ambient_dimension(self): """What is the dimension of the space that the object is contained in?""" raise NotImplementedError() @property def bounds(self): """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding rectangle for the geometric figure. """ raise NotImplementedError() def encloses(self, o): """ Return True if o is inside (not on or outside) the boundaries of self. The object will be decomposed into Points and individual Entities need only define an encloses_point method for their class. See Also ======== sympy.geometry.ellipse.Ellipse.encloses_point sympy.geometry.polygon.Polygon.encloses_point Examples ======== >>> from sympy import RegularPolygon, Point, Polygon >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) >>> t2 = Polygon(*RegularPolygon(Point(0, 0), 2, 3).vertices) >>> t2.encloses(t) True >>> t.encloses(t2) False """ from sympy.geometry.point import Point from sympy.geometry.line import Segment, Ray, Line from sympy.geometry.ellipse import Ellipse from sympy.geometry.polygon import Polygon, RegularPolygon if isinstance(o, Point): return self.encloses_point(o) elif isinstance(o, Segment): return all(self.encloses_point(x) for x in o.points) elif isinstance(o, Ray) or isinstance(o, Line): return False elif isinstance(o, Ellipse): return self.encloses_point(o.center) and \ self.encloses_point( Point(o.center.x + o.hradius, o.center.y)) and \ not self.intersection(o) elif isinstance(o, Polygon): if isinstance(o, RegularPolygon): if not self.encloses_point(o.center): return False return all(self.encloses_point(v) for v in o.vertices) raise NotImplementedError() def equals(self, o): return self == o def intersection(self, o): """ Returns a list of all of the intersections of self with o. Notes ===== An entity is not required to implement this method. If two different types of entities can intersect, the item with higher index in ordering_of_classes should implement intersections with anything having a lower index. See Also ======== sympy.geometry.util.intersection """ raise NotImplementedError() def is_similar(self, other): """Is this geometrical entity similar to another geometrical entity? Two entities are similar if a uniform scaling (enlarging or shrinking) of one of the entities will allow one to obtain the other. Notes ===== This method is not intended to be used directly but rather through the `are_similar` function found in util.py. An entity is not required to implement this method. If two different types of entities can be similar, it is only required that one of them be able to determine this. See Also ======== scale """ raise NotImplementedError() def reflect(self, line): """ Reflects an object across a line. Parameters ========== line: Line Examples ======== >>> from sympy import pi, sqrt, Line, RegularPolygon >>> l = Line((0, pi), slope=sqrt(2)) >>> pent = RegularPolygon((1, 2), 1, 5) >>> rpent = pent.reflect(l) >>> rpent RegularPolygon(Point2D(-2*sqrt(2)*pi/3 - 1/3 + 4*sqrt(2)/3, 2/3 + 2*sqrt(2)/3 + 2*pi/3), -1, 5, -atan(2*sqrt(2)) + 3*pi/5) >>> from sympy import pi, Line, Circle, Point >>> l = Line((0, pi), slope=1) >>> circ = Circle(Point(0, 0), 5) >>> rcirc = circ.reflect(l) >>> rcirc Circle(Point2D(-pi, pi), -5) """ from sympy import atan, Point, Dummy, oo g = self l = line o = Point(0, 0) if l.slope.is_zero: y = l.args[0].y if not y: # x-axis return g.scale(y=-1) reps = [(p, p.translate(y=2*(y - p.y))) for p in g.atoms(Point)] elif l.slope is oo: x = l.args[0].x if not x: # y-axis return g.scale(x=-1) reps = [(p, p.translate(x=2*(x - p.x))) for p in g.atoms(Point)] else: if not hasattr(g, 'reflect') and not all( isinstance(arg, Point) for arg in g.args): raise NotImplementedError( 'reflect undefined or non-Point args in %s' % g) a = atan(l.slope) c = l.coefficients d = -c[-1]/c[1] # y-intercept # apply the transform to a single point x, y = Dummy(), Dummy() xf = Point(x, y) xf = xf.translate(y=-d).rotate(-a, o).scale(y=-1 ).rotate(a, o).translate(y=d) # replace every point using that transform reps = [(p, xf.xreplace({x: p.x, y: p.y})) for p in g.atoms(Point)] return g.xreplace(dict(reps)) def rotate(self, angle, pt=None): """Rotate ``angle`` radians counterclockwise about Point ``pt``. The default pt is the origin, Point(0, 0) See Also ======== scale, translate Examples ======== >>> from sympy import Point, RegularPolygon, Polygon, pi >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) >>> t # vertex on x axis Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2)) >>> t.rotate(pi/2) # vertex on y axis now Triangle(Point2D(0, 1), Point2D(-sqrt(3)/2, -1/2), Point2D(sqrt(3)/2, -1/2)) """ newargs = [] for a in self.args: if isinstance(a, GeometryEntity): newargs.append(a.rotate(angle, pt)) else: newargs.append(a) return type(self)(*newargs) def scale(self, x=1, y=1, pt=None): """Scale the object by multiplying the x,y-coordinates by x and y. If pt is given, the scaling is done relative to that point; the object is shifted by -pt, scaled, and shifted by pt. See Also ======== rotate, translate Examples ======== >>> from sympy import RegularPolygon, Point, Polygon >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) >>> t Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2)) >>> t.scale(2) Triangle(Point2D(2, 0), Point2D(-1, sqrt(3)/2), Point2D(-1, -sqrt(3)/2)) >>> t.scale(2, 2) Triangle(Point2D(2, 0), Point2D(-1, sqrt(3)), Point2D(-1, -sqrt(3))) """ from sympy.geometry.point import Point if pt: pt = Point(pt, dim=2) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) return type(self)(*[a.scale(x, y) for a in self.args]) # if this fails, override this class def translate(self, x=0, y=0): """Shift the object by adding to the x,y-coordinates the values x and y. See Also ======== rotate, scale Examples ======== >>> from sympy import RegularPolygon, Point, Polygon >>> t = Polygon(*RegularPolygon(Point(0, 0), 1, 3).vertices) >>> t Triangle(Point2D(1, 0), Point2D(-1/2, sqrt(3)/2), Point2D(-1/2, -sqrt(3)/2)) >>> t.translate(2) Triangle(Point2D(3, 0), Point2D(3/2, sqrt(3)/2), Point2D(3/2, -sqrt(3)/2)) >>> t.translate(2, 2) Triangle(Point2D(3, 2), Point2D(3/2, sqrt(3)/2 + 2), Point2D(3/2, 2 - sqrt(3)/2)) """ newargs = [] for a in self.args: if isinstance(a, GeometryEntity): newargs.append(a.translate(x, y)) else: newargs.append(a) return self.func(*newargs) def parameter_value(self, other, t): """Return the parameter corresponding to the given point. Evaluating an arbitrary point of the entity at this parameter value will return the given point. Examples ======== >>> from sympy import Line, Point >>> from sympy.abc import t >>> a = Point(0, 0) >>> b = Point(2, 2) >>> Line(a, b).parameter_value((1, 1), t) {t: 1/2} >>> Line(a, b).arbitrary_point(t).subs(_) Point2D(1, 1) """ from sympy.geometry.point import Point from sympy.core.symbol import Dummy from sympy.solvers.solvers import solve if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if not isinstance(other, Point): raise ValueError("other must be a point") T = Dummy('t', real=True) sol = solve(self.arbitrary_point(T) - other, T, dict=True) if not sol: raise ValueError("Given point is not on %s" % func_name(self)) return {t: sol[0][T]} class GeometrySet(GeometryEntity, Set): """Parent class of all GeometryEntity that are also Sets (compatible with sympy.sets) """ def _contains(self, other): """sympy.sets uses the _contains method, so include it for compatibility.""" if isinstance(other, Set) and other.is_FiniteSet: return all(self.__contains__(i) for i in other) return self.__contains__(other) @dispatch(GeometrySet, Set) # type:ignore # noqa:F811 def union_sets(self, o): # noqa:F811 """ Returns the union of self and o for use with sympy.sets.Set, if possible. """ from sympy.sets import Union, FiniteSet # if its a FiniteSet, merge any points # we contain and return a union with the rest if o.is_FiniteSet: other_points = [p for p in o if not self._contains(p)] if len(other_points) == len(o): return None return Union(self, FiniteSet(*other_points)) if self._contains(o): return self return None @dispatch(GeometrySet, Set) # type: ignore # noqa:F811 def intersection_sets(self, o): # noqa:F811 """ Returns a sympy.sets.Set of intersection objects, if possible. """ from sympy.sets import FiniteSet, Union from sympy.geometry import Point try: # if o is a FiniteSet, find the intersection directly # to avoid infinite recursion if o.is_FiniteSet: inter = FiniteSet(*(p for p in o if self.contains(p))) else: inter = self.intersection(o) except NotImplementedError: # sympy.sets.Set.reduce expects None if an object # doesn't know how to simplify return None # put the points in a FiniteSet points = FiniteSet(*[p for p in inter if isinstance(p, Point)]) non_points = [p for p in inter if not isinstance(p, Point)] return Union(*(non_points + [points])) def translate(x, y): """Return the matrix to translate a 2-D point by x and y.""" rv = eye(3) rv[2, 0] = x rv[2, 1] = y return rv def scale(x, y, pt=None): """Return the matrix to multiply a 2-D point's coordinates by x and y. If pt is given, the scaling is done relative to that point.""" rv = eye(3) rv[0, 0] = x rv[1, 1] = y if pt: from sympy.geometry.point import Point pt = Point(pt, dim=2) tr1 = translate(*(-pt).args) tr2 = translate(*pt.args) return tr1*rv*tr2 return rv def rotate(th): """Return the matrix to rotate a 2-D point about the origin by ``angle``. The angle is measured in radians. To Point a point about a point other then the origin, translate the Point, do the rotation, and translate it back: >>> from sympy.geometry.entity import rotate, translate >>> from sympy import Point, pi >>> rot_about_11 = translate(-1, -1)*rotate(pi/2)*translate(1, 1) >>> Point(1, 1).transform(rot_about_11) Point2D(1, 1) >>> Point(0, 0).transform(rot_about_11) Point2D(2, 0) """ s = sin(th) rv = eye(3)*cos(th) rv[0, 1] = s rv[1, 0] = -s rv[2, 2] = 1 return rv sympy-sympy-1.9/sympy/geometry/exceptions.py000066400000000000000000000002031412543434000214650ustar00rootroot00000000000000"""Geometry Errors.""" class GeometryError(ValueError): """An exception raised by classes in the geometry module.""" pass sympy-sympy-1.9/sympy/geometry/line.py000066400000000000000000002264331412543434000202520ustar00rootroot00000000000000"""Line-like geometrical entities. Contains ======== LinearEntity Line Ray Segment LinearEntity2D Line2D Ray2D Segment2D LinearEntity3D Line3D Ray3D Segment3D """ from sympy import Expr from sympy.core import S, sympify from sympy.core.compatibility import ordered from sympy.core.containers import Tuple from sympy.core.decorators import deprecated from sympy.core.numbers import Rational, oo from sympy.core.relational import Eq from sympy.core.symbol import _symbol, Dummy from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import (_pi_coeff as pi_coeff, acos, tan, atan2) from sympy.geometry.exceptions import GeometryError from sympy.geometry.util import intersection from sympy.logic.boolalg import And from sympy.matrices import Matrix from sympy.sets import Intersection from sympy.simplify.simplify import simplify from sympy.solvers.solveset import linear_coeffs from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.misc import Undecidable, filldedent from .entity import GeometryEntity, GeometrySet from .point import Point, Point3D class LinearEntity(GeometrySet): """A base class for all linear entities (Line, Ray and Segment) in n-dimensional Euclidean space. Attributes ========== ambient_dimension direction length p1 p2 points Notes ===== This is an abstract class and is not meant to be instantiated. See Also ======== sympy.geometry.entity.GeometryEntity """ def __new__(cls, p1, p2=None, **kwargs): p1, p2 = Point._normalize_dimension(p1, p2) if p1 == p2: # sometimes we return a single point if we are not given two unique # points. This is done in the specific subclass raise ValueError( "%s.__new__ requires two unique Points." % cls.__name__) if len(p1) != len(p2): raise ValueError( "%s.__new__ requires two Points of equal dimension." % cls.__name__) return GeometryEntity.__new__(cls, p1, p2, **kwargs) def __contains__(self, other): """Return a definitive answer or else raise an error if it cannot be determined that other is on the boundaries of self.""" result = self.contains(other) if result is not None: return result else: raise Undecidable( "can't decide whether '%s' contains '%s'" % (self, other)) def _span_test(self, other): """Test whether the point `other` lies in the positive span of `self`. A point x is 'in front' of a point y if x.dot(y) >= 0. Return -1 if `other` is behind `self.p1`, 0 if `other` is `self.p1` and and 1 if `other` is in front of `self.p1`.""" if self.p1 == other: return 0 rel_pos = other - self.p1 d = self.direction if d.dot(rel_pos) > 0: return 1 return -1 @property def ambient_dimension(self): """A property method that returns the dimension of LinearEntity object. Parameters ========== p1 : LinearEntity Returns ======= dimension : integer Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(1, 1) >>> l1 = Line(p1, p2) >>> l1.ambient_dimension 2 >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0, 0), Point(1, 1, 1) >>> l1 = Line(p1, p2) >>> l1.ambient_dimension 3 """ return len(self.p1) def angle_between(l1, l2): """Return the non-reflex angle formed by rays emanating from the origin with directions the same as the direction vectors of the linear entities. Parameters ========== l1 : LinearEntity l2 : LinearEntity Returns ======= angle : angle in radians Notes ===== From the dot product of vectors v1 and v2 it is known that: ``dot(v1, v2) = |v1|*|v2|*cos(A)`` where A is the angle formed between the two vectors. We can get the directional vectors of the two lines and readily find the angle between the two using the above formula. See Also ======== is_perpendicular, Ray2D.closing_angle Examples ======== >>> from sympy import Line >>> e = Line((0, 0), (1, 0)) >>> ne = Line((0, 0), (1, 1)) >>> sw = Line((1, 1), (0, 0)) >>> ne.angle_between(e) pi/4 >>> sw.angle_between(e) 3*pi/4 To obtain the non-obtuse angle at the intersection of lines, use the ``smallest_angle_between`` method: >>> sw.smallest_angle_between(e) pi/4 >>> from sympy import Point3D, Line3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(-1, 2, 0) >>> l1, l2 = Line3D(p1, p2), Line3D(p2, p3) >>> l1.angle_between(l2) acos(-sqrt(2)/3) >>> l1.smallest_angle_between(l2) acos(sqrt(2)/3) """ if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): raise TypeError('Must pass only LinearEntity objects') v1, v2 = l1.direction, l2.direction return acos(v1.dot(v2)/(abs(v1)*abs(v2))) def smallest_angle_between(l1, l2): """Return the smallest angle formed at the intersection of the lines containing the linear entities. Parameters ========== l1 : LinearEntity l2 : LinearEntity Returns ======= angle : angle in radians See Also ======== angle_between, is_perpendicular, Ray2D.closing_angle Examples ======== >>> from sympy import Point, Line >>> p1, p2, p3 = Point(0, 0), Point(0, 4), Point(2, -2) >>> l1, l2 = Line(p1, p2), Line(p1, p3) >>> l1.smallest_angle_between(l2) pi/4 See Also ======== angle_between, Ray2D.closing_angle """ if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): raise TypeError('Must pass only LinearEntity objects') v1, v2 = l1.direction, l2.direction return acos(abs(v1.dot(v2))/(abs(v1)*abs(v2))) def arbitrary_point(self, parameter='t'): """A parameterized point on the Line. Parameters ========== parameter : str, optional The name of the parameter which will be used for the parametric point. The default value is 't'. When this parameter is 0, the first point used to define the line will be returned, and when it is 1 the second point will be returned. Returns ======= point : Point Raises ====== ValueError When ``parameter`` already appears in the Line's definition. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(1, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.arbitrary_point() Point2D(4*t + 1, 3*t) >>> from sympy import Point3D, Line3D >>> p1, p2 = Point3D(1, 0, 0), Point3D(5, 3, 1) >>> l1 = Line3D(p1, p2) >>> l1.arbitrary_point() Point3D(4*t + 1, 3*t, t) """ t = _symbol(parameter, real=True) if t.name in (f.name for f in self.free_symbols): raise ValueError(filldedent(''' Symbol %s already appears in object and cannot be used as a parameter. ''' % t.name)) # multiply on the right so the variable gets # combined with the coordinates of the point return self.p1 + (self.p2 - self.p1)*t @staticmethod def are_concurrent(*lines): """Is a sequence of linear entities concurrent? Two or more linear entities are concurrent if they all intersect at a single point. Parameters ========== lines : a sequence of linear entities. Returns ======= True : if the set of linear entities intersect in one point False : otherwise. See Also ======== sympy.geometry.util.intersection Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(3, 5) >>> p3, p4 = Point(-2, -2), Point(0, 2) >>> l1, l2, l3 = Line(p1, p2), Line(p1, p3), Line(p1, p4) >>> Line.are_concurrent(l1, l2, l3) True >>> l4 = Line(p2, p3) >>> Line.are_concurrent(l2, l3, l4) False >>> from sympy import Point3D, Line3D >>> p1, p2 = Point3D(0, 0, 0), Point3D(3, 5, 2) >>> p3, p4 = Point3D(-2, -2, -2), Point3D(0, 2, 1) >>> l1, l2, l3 = Line3D(p1, p2), Line3D(p1, p3), Line3D(p1, p4) >>> Line3D.are_concurrent(l1, l2, l3) True >>> l4 = Line3D(p2, p3) >>> Line3D.are_concurrent(l2, l3, l4) False """ common_points = Intersection(*lines) if common_points.is_FiniteSet and len(common_points) == 1: return True return False def contains(self, other): """Subclasses should implement this method and should return True if other is on the boundaries of self; False if not on the boundaries of self; None if a determination cannot be made.""" raise NotImplementedError() @property def direction(self): """The direction vector of the LinearEntity. Returns ======= p : a Point; the ray from the origin to this point is the direction of `self` Examples ======== >>> from sympy.geometry import Line >>> a, b = (1, 1), (1, 3) >>> Line(a, b).direction Point2D(0, 2) >>> Line(b, a).direction Point2D(0, -2) This can be reported so the distance from the origin is 1: >>> Line(b, a).direction.unit Point2D(0, -1) See Also ======== sympy.geometry.point.Point.unit """ return self.p2 - self.p1 def intersection(self, other): """The intersection with another geometrical entity. Parameters ========== o : Point or LinearEntity Returns ======= intersection : list of geometrical entities See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Line, Segment >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(7, 7) >>> l1 = Line(p1, p2) >>> l1.intersection(p3) [Point2D(7, 7)] >>> p4, p5 = Point(5, 0), Point(0, 3) >>> l2 = Line(p4, p5) >>> l1.intersection(l2) [Point2D(15/8, 15/8)] >>> p6, p7 = Point(0, 5), Point(2, 6) >>> s1 = Segment(p6, p7) >>> l1.intersection(s1) [] >>> from sympy import Point3D, Line3D, Segment3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(7, 7, 7) >>> l1 = Line3D(p1, p2) >>> l1.intersection(p3) [Point3D(7, 7, 7)] >>> l1 = Line3D(Point3D(4,19,12), Point3D(5,25,17)) >>> l2 = Line3D(Point3D(-3, -15, -19), direction_ratio=[2,8,8]) >>> l1.intersection(l2) [Point3D(1, 1, -3)] >>> p6, p7 = Point3D(0, 5, 2), Point3D(2, 6, 3) >>> s1 = Segment3D(p6, p7) >>> l1.intersection(s1) [] """ def intersect_parallel_rays(ray1, ray2): if ray1.direction.dot(ray2.direction) > 0: # rays point in the same direction # so return the one that is "in front" return [ray2] if ray1._span_test(ray2.p1) >= 0 else [ray1] else: # rays point in opposite directions st = ray1._span_test(ray2.p1) if st < 0: return [] elif st == 0: return [ray2.p1] return [Segment(ray1.p1, ray2.p1)] def intersect_parallel_ray_and_segment(ray, seg): st1, st2 = ray._span_test(seg.p1), ray._span_test(seg.p2) if st1 < 0 and st2 < 0: return [] elif st1 >= 0 and st2 >= 0: return [seg] elif st1 >= 0: # st2 < 0: return [Segment(ray.p1, seg.p1)] else: # st1 < 0 and st2 >= 0: return [Segment(ray.p1, seg.p2)] def intersect_parallel_segments(seg1, seg2): if seg1.contains(seg2): return [seg2] if seg2.contains(seg1): return [seg1] # direct the segments so they're oriented the same way if seg1.direction.dot(seg2.direction) < 0: seg2 = Segment(seg2.p2, seg2.p1) # order the segments so seg1 is "behind" seg2 if seg1._span_test(seg2.p1) < 0: seg1, seg2 = seg2, seg1 if seg2._span_test(seg1.p2) < 0: return [] return [Segment(seg2.p1, seg1.p2)] if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if other.is_Point: if self.contains(other): return [other] else: return [] elif isinstance(other, LinearEntity): # break into cases based on whether # the lines are parallel, non-parallel intersecting, or skew pts = Point._normalize_dimension(self.p1, self.p2, other.p1, other.p2) rank = Point.affine_rank(*pts) if rank == 1: # we're collinear if isinstance(self, Line): return [other] if isinstance(other, Line): return [self] if isinstance(self, Ray) and isinstance(other, Ray): return intersect_parallel_rays(self, other) if isinstance(self, Ray) and isinstance(other, Segment): return intersect_parallel_ray_and_segment(self, other) if isinstance(self, Segment) and isinstance(other, Ray): return intersect_parallel_ray_and_segment(other, self) if isinstance(self, Segment) and isinstance(other, Segment): return intersect_parallel_segments(self, other) elif rank == 2: # we're in the same plane l1 = Line(*pts[:2]) l2 = Line(*pts[2:]) # check to see if we're parallel. If we are, we can't # be intersecting, since the collinear case was already # handled if l1.direction.is_scalar_multiple(l2.direction): return [] # find the intersection as if everything were lines # by solving the equation t*d + p1 == s*d' + p1' m = Matrix([l1.direction, -l2.direction]).transpose() v = Matrix([l2.p1 - l1.p1]).transpose() # we cannot use m.solve(v) because that only works for square matrices m_rref, pivots = m.col_insert(2, v).rref(simplify=True) # rank == 2 ensures we have 2 pivots, but let's check anyway if len(pivots) != 2: raise GeometryError("Failed when solving Mx=b when M={} and b={}".format(m, v)) coeff = m_rref[0, 2] line_intersection = l1.direction*coeff + self.p1 # if we're both lines, we can skip a containment check if isinstance(self, Line) and isinstance(other, Line): return [line_intersection] if ((isinstance(self, Line) or self.contains(line_intersection)) and other.contains(line_intersection)): return [line_intersection] return [] else: # we're skew return [] return other.intersection(self) def is_parallel(l1, l2): """Are two linear entities parallel? Parameters ========== l1 : LinearEntity l2 : LinearEntity Returns ======= True : if l1 and l2 are parallel, False : otherwise. See Also ======== coefficients Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(1, 1) >>> p3, p4 = Point(3, 4), Point(6, 7) >>> l1, l2 = Line(p1, p2), Line(p3, p4) >>> Line.is_parallel(l1, l2) True >>> p5 = Point(6, 6) >>> l3 = Line(p3, p5) >>> Line.is_parallel(l1, l3) False >>> from sympy import Point3D, Line3D >>> p1, p2 = Point3D(0, 0, 0), Point3D(3, 4, 5) >>> p3, p4 = Point3D(2, 1, 1), Point3D(8, 9, 11) >>> l1, l2 = Line3D(p1, p2), Line3D(p3, p4) >>> Line3D.is_parallel(l1, l2) True >>> p5 = Point3D(6, 6, 6) >>> l3 = Line3D(p3, p5) >>> Line3D.is_parallel(l1, l3) False """ if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): raise TypeError('Must pass only LinearEntity objects') return l1.direction.is_scalar_multiple(l2.direction) def is_perpendicular(l1, l2): """Are two linear entities perpendicular? Parameters ========== l1 : LinearEntity l2 : LinearEntity Returns ======= True : if l1 and l2 are perpendicular, False : otherwise. See Also ======== coefficients Examples ======== >>> from sympy import Point, Line >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(-1, 1) >>> l1, l2 = Line(p1, p2), Line(p1, p3) >>> l1.is_perpendicular(l2) True >>> p4 = Point(5, 3) >>> l3 = Line(p1, p4) >>> l1.is_perpendicular(l3) False >>> from sympy import Point3D, Line3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(-1, 2, 0) >>> l1, l2 = Line3D(p1, p2), Line3D(p2, p3) >>> l1.is_perpendicular(l2) False >>> p4 = Point3D(5, 3, 7) >>> l3 = Line3D(p1, p4) >>> l1.is_perpendicular(l3) False """ if not isinstance(l1, LinearEntity) and not isinstance(l2, LinearEntity): raise TypeError('Must pass only LinearEntity objects') return S.Zero.equals(l1.direction.dot(l2.direction)) def is_similar(self, other): """ Return True if self and other are contained in the same line. Examples ======== >>> from sympy import Point, Line >>> p1, p2, p3 = Point(0, 1), Point(3, 4), Point(2, 3) >>> l1 = Line(p1, p2) >>> l2 = Line(p1, p3) >>> l1.is_similar(l2) True """ l = Line(self.p1, self.p2) return l.contains(other) @property def length(self): """ The length of the line. Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(3, 5) >>> l1 = Line(p1, p2) >>> l1.length oo """ return S.Infinity @property def p1(self): """The first defining point of a linear entity. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(5, 3) >>> l = Line(p1, p2) >>> l.p1 Point2D(0, 0) """ return self.args[0] @property def p2(self): """The second defining point of a linear entity. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(5, 3) >>> l = Line(p1, p2) >>> l.p2 Point2D(5, 3) """ return self.args[1] def parallel_line(self, p): """Create a new Line parallel to this linear entity which passes through the point `p`. Parameters ========== p : Point Returns ======= line : Line See Also ======== is_parallel Examples ======== >>> from sympy import Point, Line >>> p1, p2, p3 = Point(0, 0), Point(2, 3), Point(-2, 2) >>> l1 = Line(p1, p2) >>> l2 = l1.parallel_line(p3) >>> p3 in l2 True >>> l1.is_parallel(l2) True >>> from sympy import Point3D, Line3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(2, 3, 4), Point3D(-2, 2, 0) >>> l1 = Line3D(p1, p2) >>> l2 = l1.parallel_line(p3) >>> p3 in l2 True >>> l1.is_parallel(l2) True """ p = Point(p, dim=self.ambient_dimension) return Line(p, p + self.direction) def perpendicular_line(self, p): """Create a new Line perpendicular to this linear entity which passes through the point `p`. Parameters ========== p : Point Returns ======= line : Line See Also ======== sympy.geometry.line.LinearEntity.is_perpendicular, perpendicular_segment Examples ======== >>> from sympy import Point, Line >>> p1, p2, p3 = Point(0, 0), Point(2, 3), Point(-2, 2) >>> l1 = Line(p1, p2) >>> l2 = l1.perpendicular_line(p3) >>> p3 in l2 True >>> l1.is_perpendicular(l2) True >>> from sympy import Point3D, Line3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(2, 3, 4), Point3D(-2, 2, 0) >>> l1 = Line3D(p1, p2) >>> l2 = l1.perpendicular_line(p3) >>> p3 in l2 True >>> l1.is_perpendicular(l2) True """ p = Point(p, dim=self.ambient_dimension) if p in self: p = p + self.direction.orthogonal_direction return Line(p, self.projection(p)) def perpendicular_segment(self, p): """Create a perpendicular line segment from `p` to this line. The enpoints of the segment are ``p`` and the closest point in the line containing self. (If self is not a line, the point might not be in self.) Parameters ========== p : Point Returns ======= segment : Segment Notes ===== Returns `p` itself if `p` is on this linear entity. See Also ======== perpendicular_line Examples ======== >>> from sympy import Point, Line >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(0, 2) >>> l1 = Line(p1, p2) >>> s1 = l1.perpendicular_segment(p3) >>> l1.is_perpendicular(s1) True >>> p3 in s1 True >>> l1.perpendicular_segment(Point(4, 0)) Segment2D(Point2D(4, 0), Point2D(2, 2)) >>> from sympy import Point3D, Line3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(0, 2, 0) >>> l1 = Line3D(p1, p2) >>> s1 = l1.perpendicular_segment(p3) >>> l1.is_perpendicular(s1) True >>> p3 in s1 True >>> l1.perpendicular_segment(Point3D(4, 0, 0)) Segment3D(Point3D(4, 0, 0), Point3D(4/3, 4/3, 4/3)) """ p = Point(p, dim=self.ambient_dimension) if p in self: return p l = self.perpendicular_line(p) # The intersection should be unique, so unpack the singleton p2, = Intersection(Line(self.p1, self.p2), l) return Segment(p, p2) @property def points(self): """The two points used to define this linear entity. Returns ======= points : tuple of Points See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(5, 11) >>> l1 = Line(p1, p2) >>> l1.points (Point2D(0, 0), Point2D(5, 11)) """ return (self.p1, self.p2) def projection(self, other): """Project a point, line, ray, or segment onto this linear entity. Parameters ========== other : Point or LinearEntity (Line, Ray, Segment) Returns ======= projection : Point or LinearEntity (Line, Ray, Segment) The return type matches the type of the parameter ``other``. Raises ====== GeometryError When method is unable to perform projection. Notes ===== A projection involves taking the two points that define the linear entity and projecting those points onto a Line and then reforming the linear entity using these projections. A point P is projected onto a line L by finding the point on L that is closest to P. This point is the intersection of L and the line perpendicular to L that passes through P. See Also ======== sympy.geometry.point.Point, perpendicular_line Examples ======== >>> from sympy import Point, Line, Segment, Rational >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(Rational(1, 2), 0) >>> l1 = Line(p1, p2) >>> l1.projection(p3) Point2D(1/4, 1/4) >>> p4, p5 = Point(10, 0), Point(12, 1) >>> s1 = Segment(p4, p5) >>> l1.projection(s1) Segment2D(Point2D(5, 5), Point2D(13/2, 13/2)) >>> p1, p2, p3 = Point(0, 0, 1), Point(1, 1, 2), Point(2, 0, 1) >>> l1 = Line(p1, p2) >>> l1.projection(p3) Point3D(2/3, 2/3, 5/3) >>> p4, p5 = Point(10, 0, 1), Point(12, 1, 3) >>> s1 = Segment(p4, p5) >>> l1.projection(s1) Segment3D(Point3D(10/3, 10/3, 13/3), Point3D(5, 5, 6)) """ if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) def proj_point(p): return Point.project(p - self.p1, self.direction) + self.p1 if isinstance(other, Point): return proj_point(other) elif isinstance(other, LinearEntity): p1, p2 = proj_point(other.p1), proj_point(other.p2) # test to see if we're degenerate if p1 == p2: return p1 projected = other.__class__(p1, p2) projected = Intersection(self, projected) # if we happen to have intersected in only a point, return that if projected.is_FiniteSet and len(projected) == 1: # projected is a set of size 1, so unpack it in `a` a, = projected return a # order args so projection is in the same direction as self if self.direction.dot(projected.direction) < 0: p1, p2 = projected.args projected = projected.func(p2, p1) return projected raise GeometryError( "Do not know how to project %s onto %s" % (other, self)) def random_point(self, seed=None): """A random point on a LinearEntity. Returns ======= point : Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Line, Ray, Segment >>> p1, p2 = Point(0, 0), Point(5, 3) >>> line = Line(p1, p2) >>> r = line.random_point(seed=42) # seed value is optional >>> r.n(3) Point2D(-0.72, -0.432) >>> r in line True >>> Ray(p1, p2).random_point(seed=42).n(3) Point2D(0.72, 0.432) >>> Segment(p1, p2).random_point(seed=42).n(3) Point2D(3.2, 1.92) """ import random if seed is not None: rng = random.Random(seed) else: rng = random t = Dummy() pt = self.arbitrary_point(t) if isinstance(self, Ray): v = abs(rng.gauss(0, 1)) elif isinstance(self, Segment): v = rng.random() elif isinstance(self, Line): v = rng.gauss(0, 1) else: raise NotImplementedError('unhandled line type') return pt.subs(t, Rational(v)) def bisectors(self, other): """Returns the perpendicular lines which pass through the intersections of self and other that are in the same plane. Parameters ========== line : Line3D Returns ======= list: two Line instances Examples ======== >>> from sympy.geometry import Point3D, Line3D >>> r1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)) >>> r2 = Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0)) >>> r1.bisectors(r2) [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 0)), Line3D(Point3D(0, 0, 0), Point3D(1, -1, 0))] """ if not isinstance(other, LinearEntity): raise GeometryError("Expecting LinearEntity, not %s" % other) l1, l2 = self, other # make sure dimensions match or else a warning will rise from # intersection calculation if l1.p1.ambient_dimension != l2.p1.ambient_dimension: if isinstance(l1, Line2D): l1, l2 = l2, l1 _, p1 = Point._normalize_dimension(l1.p1, l2.p1, on_morph='ignore') _, p2 = Point._normalize_dimension(l1.p2, l2.p2, on_morph='ignore') l2 = Line(p1, p2) point = intersection(l1, l2) # Three cases: Lines may intersect in a point, may be equal or may not intersect. if not point: raise GeometryError("The lines do not intersect") else: pt = point[0] if isinstance(pt, Line): # Intersection is a line because both lines are coincident return [self] d1 = l1.direction.unit d2 = l2.direction.unit bis1 = Line(pt, pt + d1 + d2) bis2 = Line(pt, pt + d1 - d2) return [bis1, bis2] class Line(LinearEntity): """An infinite line in space. A 2D line is declared with two distinct points, point and slope, or an equation. A 3D line may be defined with a point and a direction ratio. Parameters ========== p1 : Point p2 : Point slope : sympy expression direction_ratio : list equation : equation of a line Notes ===== `Line` will automatically subclass to `Line2D` or `Line3D` based on the dimension of `p1`. The `slope` argument is only relevant for `Line2D` and the `direction_ratio` argument is only relevant for `Line3D`. See Also ======== sympy.geometry.point.Point sympy.geometry.line.Line2D sympy.geometry.line.Line3D Examples ======== >>> from sympy import Point, Eq >>> from sympy.geometry import Line, Segment >>> from sympy.abc import x, y, a, b >>> L = Line(Point(2,3), Point(3,5)) >>> L Line2D(Point2D(2, 3), Point2D(3, 5)) >>> L.points (Point2D(2, 3), Point2D(3, 5)) >>> L.equation() -2*x + y + 1 >>> L.coefficients (-2, 1, 1) Instantiate with keyword ``slope``: >>> Line(Point(0, 0), slope=0) Line2D(Point2D(0, 0), Point2D(1, 0)) Instantiate with another linear object >>> s = Segment((0, 0), (0, 1)) >>> Line(s).equation() x The line corresponding to an equation in the for `ax + by + c = 0`, can be entered: >>> Line(3*x + y + 18) Line2D(Point2D(0, -18), Point2D(1, -21)) If `x` or `y` has a different name, then they can be specified, too, as a string (to match the name) or symbol: >>> Line(Eq(3*a + b, -18), x='a', y=b) Line2D(Point2D(0, -18), Point2D(1, -21)) """ def __new__(cls, *args, **kwargs): from sympy.geometry.util import find if len(args) == 1 and isinstance(args[0], (Expr, Eq)): x = kwargs.get('x', 'x') y = kwargs.get('y', 'y') equation = args[0] if isinstance(equation, Eq): equation = equation.lhs - equation.rhs xin, yin = x, y x = find(x, equation) or Dummy() y = find(y, equation) or Dummy() a, b, c = linear_coeffs(equation, x, y) if b: return Line((0, -c/b), slope=-a/b) if a: return Line((-c/a, 0), slope=oo) raise ValueError('neither %s nor %s were found in the equation' % (xin, yin)) else: if len(args) > 0: p1 = args[0] if len(args) > 1: p2 = args[1] else: p2 = None if isinstance(p1, LinearEntity): if p2: raise ValueError('If p1 is a LinearEntity, p2 must be None.') dim = len(p1.p1) else: p1 = Point(p1) dim = len(p1) if p2 is not None or isinstance(p2, Point) and p2.ambient_dimension != dim: p2 = Point(p2) if dim == 2: return Line2D(p1, p2, **kwargs) elif dim == 3: return Line3D(p1, p2, **kwargs) return LinearEntity.__new__(cls, p1, p2, **kwargs) def contains(self, other): """ Return True if `other` is on this Line, or False otherwise. Examples ======== >>> from sympy import Line,Point >>> p1, p2 = Point(0, 1), Point(3, 4) >>> l = Line(p1, p2) >>> l.contains(p1) True >>> l.contains((0, 1)) True >>> l.contains((0, 0)) False >>> a = (0, 0, 0) >>> b = (1, 1, 1) >>> c = (2, 2, 2) >>> l1 = Line(a, b) >>> l2 = Line(b, a) >>> l1 == l2 False >>> l1 in l2 True """ if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if isinstance(other, Point): return Point.is_collinear(other, self.p1, self.p2) if isinstance(other, LinearEntity): return Point.is_collinear(self.p1, self.p2, other.p1, other.p2) return False def distance(self, other): """ Finds the shortest distance between a line and a point. Raises ====== NotImplementedError is raised if `other` is not a Point Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(1, 1) >>> s = Line(p1, p2) >>> s.distance(Point(-1, 1)) sqrt(2) >>> s.distance((-1, 2)) 3*sqrt(2)/2 >>> p1, p2 = Point(0, 0, 0), Point(1, 1, 1) >>> s = Line(p1, p2) >>> s.distance(Point(-1, 1, 1)) 2*sqrt(6)/3 >>> s.distance((-1, 1, 1)) 2*sqrt(6)/3 """ if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if self.contains(other): return S.Zero return self.perpendicular_segment(other).length @deprecated(useinstead="equals", issue=12860, deprecated_since_version="1.0") def equal(self, other): return self.equals(other) def equals(self, other): """Returns True if self and other are the same mathematical entities""" if not isinstance(other, Line): return False return Point.is_collinear(self.p1, other.p1, self.p2, other.p2) def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of line. Gives values that will produce a line that is +/- 5 units long (where a unit is the distance between the two points that define the line). Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list (plot interval) [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.plot_interval() [t, -5, 5] """ t = _symbol(parameter, real=True) return [t, -5, 5] class Ray(LinearEntity): """A Ray is a semi-line in the space with a source point and a direction. Parameters ========== p1 : Point The source of the Ray p2 : Point or radian value This point determines the direction in which the Ray propagates. If given as an angle it is interpreted in radians with the positive direction being ccw. Attributes ========== source See Also ======== sympy.geometry.line.Ray2D sympy.geometry.line.Ray3D sympy.geometry.point.Point sympy.geometry.line.Line Notes ===== `Ray` will automatically subclass to `Ray2D` or `Ray3D` based on the dimension of `p1`. Examples ======== >>> from sympy import Point, pi >>> from sympy.geometry import Ray >>> r = Ray(Point(2, 3), Point(3, 5)) >>> r Ray2D(Point2D(2, 3), Point2D(3, 5)) >>> r.points (Point2D(2, 3), Point2D(3, 5)) >>> r.source Point2D(2, 3) >>> r.xdirection oo >>> r.ydirection oo >>> r.slope 2 >>> Ray(Point(0, 0), angle=pi/4).slope 1 """ def __new__(cls, p1, p2=None, **kwargs): p1 = Point(p1) if p2 is not None: p1, p2 = Point._normalize_dimension(p1, Point(p2)) dim = len(p1) if dim == 2: return Ray2D(p1, p2, **kwargs) elif dim == 3: return Ray3D(p1, p2, **kwargs) return LinearEntity.__new__(cls, p1, p2, **kwargs) def _svg(self, scale_factor=1., fill_color="#66cc99"): """Returns SVG path element for the LinearEntity. Parameters ========== scale_factor : float Multiplication factor for the SVG stroke-width. Default is 1. fill_color : str, optional Hex string for fill color. Default is "#66cc99". """ from sympy.core.evalf import N verts = (N(self.p1), N(self.p2)) coords = ["{},{}".format(p.x, p.y) for p in verts] path = "M {} L {}".format(coords[0], " L ".join(coords[1:])) return ( '' ).format(2.*scale_factor, path, fill_color) def contains(self, other): """ Is other GeometryEntity contained in this Ray? Examples ======== >>> from sympy import Ray,Point,Segment >>> p1, p2 = Point(0, 0), Point(4, 4) >>> r = Ray(p1, p2) >>> r.contains(p1) True >>> r.contains((1, 1)) True >>> r.contains((1, 3)) False >>> s = Segment((1, 1), (2, 2)) >>> r.contains(s) True >>> s = Segment((1, 2), (2, 5)) >>> r.contains(s) False >>> r1 = Ray((2, 2), (3, 3)) >>> r.contains(r1) True >>> r1 = Ray((2, 2), (3, 5)) >>> r.contains(r1) False """ if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if isinstance(other, Point): if Point.is_collinear(self.p1, self.p2, other): # if we're in the direction of the ray, our # direction vector dot the ray's direction vector # should be non-negative return bool((self.p2 - self.p1).dot(other - self.p1) >= S.Zero) return False elif isinstance(other, Ray): if Point.is_collinear(self.p1, self.p2, other.p1, other.p2): return bool((self.p2 - self.p1).dot(other.p2 - other.p1) > S.Zero) return False elif isinstance(other, Segment): return other.p1 in self and other.p2 in self # No other known entity can be contained in a Ray return False def distance(self, other): """ Finds the shortest distance between the ray and a point. Raises ====== NotImplementedError is raised if `other` is not a Point Examples ======== >>> from sympy import Point, Ray >>> p1, p2 = Point(0, 0), Point(1, 1) >>> s = Ray(p1, p2) >>> s.distance(Point(-1, -1)) sqrt(2) >>> s.distance((-1, 2)) 3*sqrt(2)/2 >>> p1, p2 = Point(0, 0, 0), Point(1, 1, 2) >>> s = Ray(p1, p2) >>> s Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 2)) >>> s.distance(Point(-1, -1, 2)) 4*sqrt(3)/3 >>> s.distance((-1, -1, 2)) 4*sqrt(3)/3 """ if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if self.contains(other): return S.Zero proj = Line(self.p1, self.p2).projection(other) if self.contains(proj): return abs(other - proj) else: return abs(other - self.source) def equals(self, other): """Returns True if self and other are the same mathematical entities""" if not isinstance(other, Ray): return False return self.source == other.source and other.p2 in self def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the Ray. Gives values that will produce a ray that is 10 units long (where a unit is the distance between the two points that define the ray). Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Ray, pi >>> r = Ray((0, 0), angle=pi/4) >>> r.plot_interval() [t, 0, 10] """ t = _symbol(parameter, real=True) return [t, 0, 10] @property def source(self): """The point from which the ray emanates. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Ray >>> p1, p2 = Point(0, 0), Point(4, 1) >>> r1 = Ray(p1, p2) >>> r1.source Point2D(0, 0) >>> p1, p2 = Point(0, 0, 0), Point(4, 1, 5) >>> r1 = Ray(p2, p1) >>> r1.source Point3D(4, 1, 5) """ return self.p1 class Segment(LinearEntity): """A line segment in space. Parameters ========== p1 : Point p2 : Point Attributes ========== length : number or sympy expression midpoint : Point See Also ======== sympy.geometry.line.Segment2D sympy.geometry.line.Segment3D sympy.geometry.point.Point sympy.geometry.line.Line Notes ===== If 2D or 3D points are used to define `Segment`, it will be automatically subclassed to `Segment2D` or `Segment3D`. Examples ======== >>> from sympy import Point >>> from sympy.geometry import Segment >>> Segment((1, 0), (1, 1)) # tuples are interpreted as pts Segment2D(Point2D(1, 0), Point2D(1, 1)) >>> s = Segment(Point(4, 3), Point(1, 1)) >>> s.points (Point2D(4, 3), Point2D(1, 1)) >>> s.slope 2/3 >>> s.length sqrt(13) >>> s.midpoint Point2D(5/2, 2) >>> Segment((1, 0, 0), (1, 1, 1)) # tuples are interpreted as pts Segment3D(Point3D(1, 0, 0), Point3D(1, 1, 1)) >>> s = Segment(Point(4, 3, 9), Point(1, 1, 7)); s Segment3D(Point3D(4, 3, 9), Point3D(1, 1, 7)) >>> s.points (Point3D(4, 3, 9), Point3D(1, 1, 7)) >>> s.length sqrt(17) >>> s.midpoint Point3D(5/2, 2, 8) """ def __new__(cls, p1, p2, **kwargs): p1, p2 = Point._normalize_dimension(Point(p1), Point(p2)) dim = len(p1) if dim == 2: return Segment2D(p1, p2, **kwargs) elif dim == 3: return Segment3D(p1, p2, **kwargs) return LinearEntity.__new__(cls, p1, p2, **kwargs) def contains(self, other): """ Is the other GeometryEntity contained within this Segment? Examples ======== >>> from sympy import Point, Segment >>> p1, p2 = Point(0, 1), Point(3, 4) >>> s = Segment(p1, p2) >>> s2 = Segment(p2, p1) >>> s.contains(s2) True >>> from sympy import Point3D, Segment3D >>> p1, p2 = Point3D(0, 1, 1), Point3D(3, 4, 5) >>> s = Segment3D(p1, p2) >>> s2 = Segment3D(p2, p1) >>> s.contains(s2) True >>> s.contains((p1 + p2)/2) True """ if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if isinstance(other, Point): if Point.is_collinear(other, self.p1, self.p2): if isinstance(self, Segment2D): # if it is collinear and is in the bounding box of the # segment then it must be on the segment vert = (1/self.slope).equals(0) if vert is False: isin = (self.p1.x - other.x)*(self.p2.x - other.x) <= 0 if isin in (True, False): return isin if vert is True: isin = (self.p1.y - other.y)*(self.p2.y - other.y) <= 0 if isin in (True, False): return isin # use the triangle inequality d1, d2 = other - self.p1, other - self.p2 d = self.p2 - self.p1 # without the call to simplify, sympy cannot tell that an expression # like (a+b)*(a/2+b/2) is always non-negative. If it cannot be # determined, raise an Undecidable error try: # the triangle inequality says that |d1|+|d2| >= |d| and is strict # only if other lies in the line segment return bool(simplify(Eq(abs(d1) + abs(d2) - abs(d), 0))) except TypeError: raise Undecidable("Cannot determine if {} is in {}".format(other, self)) if isinstance(other, Segment): return other.p1 in self and other.p2 in self return False def equals(self, other): """Returns True if self and other are the same mathematical entities""" return isinstance(other, self.func) and list( ordered(self.args)) == list(ordered(other.args)) def distance(self, other): """ Finds the shortest distance between a line segment and a point. Raises ====== NotImplementedError is raised if `other` is not a Point Examples ======== >>> from sympy import Point, Segment >>> p1, p2 = Point(0, 1), Point(3, 4) >>> s = Segment(p1, p2) >>> s.distance(Point(10, 15)) sqrt(170) >>> s.distance((0, 12)) sqrt(73) >>> from sympy import Point3D, Segment3D >>> p1, p2 = Point3D(0, 0, 3), Point3D(1, 1, 4) >>> s = Segment3D(p1, p2) >>> s.distance(Point3D(10, 15, 12)) sqrt(341) >>> s.distance((10, 15, 12)) sqrt(341) """ if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if isinstance(other, Point): vp1 = other - self.p1 vp2 = other - self.p2 dot_prod_sign_1 = self.direction.dot(vp1) >= 0 dot_prod_sign_2 = self.direction.dot(vp2) <= 0 if dot_prod_sign_1 and dot_prod_sign_2: return Line(self.p1, self.p2).distance(other) if dot_prod_sign_1 and not dot_prod_sign_2: return abs(vp2) if not dot_prod_sign_1 and dot_prod_sign_2: return abs(vp1) raise NotImplementedError() @property def length(self): """The length of the line segment. See Also ======== sympy.geometry.point.Point.distance Examples ======== >>> from sympy import Point, Segment >>> p1, p2 = Point(0, 0), Point(4, 3) >>> s1 = Segment(p1, p2) >>> s1.length 5 >>> from sympy import Point3D, Segment3D >>> p1, p2 = Point3D(0, 0, 0), Point3D(4, 3, 3) >>> s1 = Segment3D(p1, p2) >>> s1.length sqrt(34) """ return Point.distance(self.p1, self.p2) @property def midpoint(self): """The midpoint of the line segment. See Also ======== sympy.geometry.point.Point.midpoint Examples ======== >>> from sympy import Point, Segment >>> p1, p2 = Point(0, 0), Point(4, 3) >>> s1 = Segment(p1, p2) >>> s1.midpoint Point2D(2, 3/2) >>> from sympy import Point3D, Segment3D >>> p1, p2 = Point3D(0, 0, 0), Point3D(4, 3, 3) >>> s1 = Segment3D(p1, p2) >>> s1.midpoint Point3D(2, 3/2, 3/2) """ return Point.midpoint(self.p1, self.p2) def perpendicular_bisector(self, p=None): """The perpendicular bisector of this segment. If no point is specified or the point specified is not on the bisector then the bisector is returned as a Line. Otherwise a Segment is returned that joins the point specified and the intersection of the bisector and the segment. Parameters ========== p : Point Returns ======= bisector : Line or Segment See Also ======== LinearEntity.perpendicular_segment Examples ======== >>> from sympy import Point, Segment >>> p1, p2, p3 = Point(0, 0), Point(6, 6), Point(5, 1) >>> s1 = Segment(p1, p2) >>> s1.perpendicular_bisector() Line2D(Point2D(3, 3), Point2D(-3, 9)) >>> s1.perpendicular_bisector(p3) Segment2D(Point2D(5, 1), Point2D(3, 3)) """ l = self.perpendicular_line(self.midpoint) if p is not None: p2 = Point(p, dim=self.ambient_dimension) if p2 in l: return Segment(p2, self.midpoint) return l def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the Segment gives values that will produce the full segment in a plot. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Point, Segment >>> p1, p2 = Point(0, 0), Point(5, 3) >>> s1 = Segment(p1, p2) >>> s1.plot_interval() [t, 0, 1] """ t = _symbol(parameter, real=True) return [t, 0, 1] class LinearEntity2D(LinearEntity): """A base class for all linear entities (line, ray and segment) in a 2-dimensional Euclidean space. Attributes ========== p1 p2 coefficients slope points Notes ===== This is an abstract class and is not meant to be instantiated. See Also ======== sympy.geometry.entity.GeometryEntity """ @property def bounds(self): """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding rectangle for the geometric figure. """ verts = self.points xs = [p.x for p in verts] ys = [p.y for p in verts] return (min(xs), min(ys), max(xs), max(ys)) def perpendicular_line(self, p): """Create a new Line perpendicular to this linear entity which passes through the point `p`. Parameters ========== p : Point Returns ======= line : Line See Also ======== sympy.geometry.line.LinearEntity.is_perpendicular, perpendicular_segment Examples ======== >>> from sympy import Point, Line >>> p1, p2, p3 = Point(0, 0), Point(2, 3), Point(-2, 2) >>> l1 = Line(p1, p2) >>> l2 = l1.perpendicular_line(p3) >>> p3 in l2 True >>> l1.is_perpendicular(l2) True """ p = Point(p, dim=self.ambient_dimension) # any two lines in R^2 intersect, so blindly making # a line through p in an orthogonal direction will work return Line(p, p + self.direction.orthogonal_direction) @property def slope(self): """The slope of this linear entity, or infinity if vertical. Returns ======= slope : number or sympy expression See Also ======== coefficients Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(0, 0), Point(3, 5) >>> l1 = Line(p1, p2) >>> l1.slope 5/3 >>> p3 = Point(0, 4) >>> l2 = Line(p1, p3) >>> l2.slope oo """ d1, d2 = (self.p1 - self.p2).args if d1 == 0: return S.Infinity return simplify(d2/d1) class Line2D(LinearEntity2D, Line): """An infinite line in space 2D. A line is declared with two distinct points or a point and slope as defined using keyword `slope`. Parameters ========== p1 : Point pt : Point slope : sympy expression See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point >>> from sympy.geometry import Line, Segment >>> L = Line(Point(2,3), Point(3,5)) >>> L Line2D(Point2D(2, 3), Point2D(3, 5)) >>> L.points (Point2D(2, 3), Point2D(3, 5)) >>> L.equation() -2*x + y + 1 >>> L.coefficients (-2, 1, 1) Instantiate with keyword ``slope``: >>> Line(Point(0, 0), slope=0) Line2D(Point2D(0, 0), Point2D(1, 0)) Instantiate with another linear object >>> s = Segment((0, 0), (0, 1)) >>> Line(s).equation() x """ def __new__(cls, p1, pt=None, slope=None, **kwargs): if isinstance(p1, LinearEntity): if pt is not None: raise ValueError('When p1 is a LinearEntity, pt should be None') p1, pt = Point._normalize_dimension(*p1.args, dim=2) else: p1 = Point(p1, dim=2) if pt is not None and slope is None: try: p2 = Point(pt, dim=2) except (NotImplementedError, TypeError, ValueError): raise ValueError(filldedent(''' The 2nd argument was not a valid Point. If it was a slope, enter it with keyword "slope". ''')) elif slope is not None and pt is None: slope = sympify(slope) if slope.is_finite is False: # when infinite slope, don't change x dx = 0 dy = 1 else: # go over 1 up slope dx = 1 dy = slope # XXX avoiding simplification by adding to coords directly p2 = Point(p1.x + dx, p1.y + dy, evaluate=False) else: raise ValueError('A 2nd Point or keyword "slope" must be used.') return LinearEntity2D.__new__(cls, p1, p2, **kwargs) def _svg(self, scale_factor=1., fill_color="#66cc99"): """Returns SVG path element for the LinearEntity. Parameters ========== scale_factor : float Multiplication factor for the SVG stroke-width. Default is 1. fill_color : str, optional Hex string for fill color. Default is "#66cc99". """ from sympy.core.evalf import N verts = (N(self.p1), N(self.p2)) coords = ["{},{}".format(p.x, p.y) for p in verts] path = "M {} L {}".format(coords[0], " L ".join(coords[1:])) return ( '' ).format(2.*scale_factor, path, fill_color) @property def coefficients(self): """The coefficients (`a`, `b`, `c`) for `ax + by + c = 0`. See Also ======== sympy.geometry.line.Line2D.equation Examples ======== >>> from sympy import Point, Line >>> from sympy.abc import x, y >>> p1, p2 = Point(0, 0), Point(5, 3) >>> l = Line(p1, p2) >>> l.coefficients (-3, 5, 0) >>> p3 = Point(x, y) >>> l2 = Line(p1, p3) >>> l2.coefficients (-y, x, 0) """ p1, p2 = self.points if p1.x == p2.x: return (S.One, S.Zero, -p1.x) elif p1.y == p2.y: return (S.Zero, S.One, -p1.y) return tuple([simplify(i) for i in (self.p1.y - self.p2.y, self.p2.x - self.p1.x, self.p1.x*self.p2.y - self.p1.y*self.p2.x)]) def equation(self, x='x', y='y'): """The equation of the line: ax + by + c. Parameters ========== x : str, optional The name to use for the x-axis, default value is 'x'. y : str, optional The name to use for the y-axis, default value is 'y'. Returns ======= equation : sympy expression See Also ======== sympy.geometry.line.Line2D.coefficients Examples ======== >>> from sympy import Point, Line >>> p1, p2 = Point(1, 0), Point(5, 3) >>> l1 = Line(p1, p2) >>> l1.equation() -3*x + 4*y + 3 """ x = _symbol(x, real=True) y = _symbol(y, real=True) p1, p2 = self.points if p1.x == p2.x: return x - p1.x elif p1.y == p2.y: return y - p1.y a, b, c = self.coefficients return a*x + b*y + c class Ray2D(LinearEntity2D, Ray): """ A Ray is a semi-line in the space with a source point and a direction. Parameters ========== p1 : Point The source of the Ray p2 : Point or radian value This point determines the direction in which the Ray propagates. If given as an angle it is interpreted in radians with the positive direction being ccw. Attributes ========== source xdirection ydirection See Also ======== sympy.geometry.point.Point, Line Examples ======== >>> from sympy import Point, pi >>> from sympy.geometry import Ray >>> r = Ray(Point(2, 3), Point(3, 5)) >>> r Ray2D(Point2D(2, 3), Point2D(3, 5)) >>> r.points (Point2D(2, 3), Point2D(3, 5)) >>> r.source Point2D(2, 3) >>> r.xdirection oo >>> r.ydirection oo >>> r.slope 2 >>> Ray(Point(0, 0), angle=pi/4).slope 1 """ def __new__(cls, p1, pt=None, angle=None, **kwargs): p1 = Point(p1, dim=2) if pt is not None and angle is None: try: p2 = Point(pt, dim=2) except (NotImplementedError, TypeError, ValueError): from sympy.utilities.misc import filldedent raise ValueError(filldedent(''' The 2nd argument was not a valid Point; if it was meant to be an angle it should be given with keyword "angle".''')) if p1 == p2: raise ValueError('A Ray requires two distinct points.') elif angle is not None and pt is None: # we need to know if the angle is an odd multiple of pi/2 c = pi_coeff(sympify(angle)) p2 = None if c is not None: if c.is_Rational: if c.q == 2: if c.p == 1: p2 = p1 + Point(0, 1) elif c.p == 3: p2 = p1 + Point(0, -1) elif c.q == 1: if c.p == 0: p2 = p1 + Point(1, 0) elif c.p == 1: p2 = p1 + Point(-1, 0) if p2 is None: c *= S.Pi else: c = angle % (2*S.Pi) if not p2: m = 2*c/S.Pi left = And(1 < m, m < 3) # is it in quadrant 2 or 3? x = Piecewise((-1, left), (Piecewise((0, Eq(m % 1, 0)), (1, True)), True)) y = Piecewise((-tan(c), left), (Piecewise((1, Eq(m, 1)), (-1, Eq(m, 3)), (tan(c), True)), True)) p2 = p1 + Point(x, y) else: raise ValueError('A 2nd point or keyword "angle" must be used.') return LinearEntity2D.__new__(cls, p1, p2, **kwargs) @property def xdirection(self): """The x direction of the ray. Positive infinity if the ray points in the positive x direction, negative infinity if the ray points in the negative x direction, or 0 if the ray is vertical. See Also ======== ydirection Examples ======== >>> from sympy import Point, Ray >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(0, -1) >>> r1, r2 = Ray(p1, p2), Ray(p1, p3) >>> r1.xdirection oo >>> r2.xdirection 0 """ if self.p1.x < self.p2.x: return S.Infinity elif self.p1.x == self.p2.x: return S.Zero else: return S.NegativeInfinity @property def ydirection(self): """The y direction of the ray. Positive infinity if the ray points in the positive y direction, negative infinity if the ray points in the negative y direction, or 0 if the ray is horizontal. See Also ======== xdirection Examples ======== >>> from sympy import Point, Ray >>> p1, p2, p3 = Point(0, 0), Point(-1, -1), Point(-1, 0) >>> r1, r2 = Ray(p1, p2), Ray(p1, p3) >>> r1.ydirection -oo >>> r2.ydirection 0 """ if self.p1.y < self.p2.y: return S.Infinity elif self.p1.y == self.p2.y: return S.Zero else: return S.NegativeInfinity def closing_angle(r1, r2): """Return the angle by which r2 must be rotated so it faces the same direction as r1. Parameters ========== r1 : Ray2D r2 : Ray2D Returns ======= angle : angle in radians (ccw angle is positive) See Also ======== LinearEntity.angle_between Examples ======== >>> from sympy import Ray, pi >>> r1 = Ray((0, 0), (1, 0)) >>> r2 = r1.rotate(-pi/2) >>> angle = r1.closing_angle(r2); angle pi/2 >>> r2.rotate(angle).direction.unit == r1.direction.unit True >>> r2.closing_angle(r1) -pi/2 """ if not all(isinstance(r, Ray2D) for r in (r1, r2)): # although the direction property is defined for # all linear entities, only the Ray is truly a # directed object raise TypeError('Both arguments must be Ray2D objects.') a1 = atan2(*list(reversed(r1.direction.args))) a2 = atan2(*list(reversed(r2.direction.args))) if a1*a2 < 0: a1 = 2*S.Pi + a1 if a1 < 0 else a1 a2 = 2*S.Pi + a2 if a2 < 0 else a2 return a1 - a2 class Segment2D(LinearEntity2D, Segment): """A line segment in 2D space. Parameters ========== p1 : Point p2 : Point Attributes ========== length : number or sympy expression midpoint : Point See Also ======== sympy.geometry.point.Point, Line Examples ======== >>> from sympy import Point >>> from sympy.geometry import Segment >>> Segment((1, 0), (1, 1)) # tuples are interpreted as pts Segment2D(Point2D(1, 0), Point2D(1, 1)) >>> s = Segment(Point(4, 3), Point(1, 1)); s Segment2D(Point2D(4, 3), Point2D(1, 1)) >>> s.points (Point2D(4, 3), Point2D(1, 1)) >>> s.slope 2/3 >>> s.length sqrt(13) >>> s.midpoint Point2D(5/2, 2) """ def __new__(cls, p1, p2, **kwargs): p1 = Point(p1, dim=2) p2 = Point(p2, dim=2) if p1 == p2: return p1 return LinearEntity2D.__new__(cls, p1, p2, **kwargs) def _svg(self, scale_factor=1., fill_color="#66cc99"): """Returns SVG path element for the LinearEntity. Parameters ========== scale_factor : float Multiplication factor for the SVG stroke-width. Default is 1. fill_color : str, optional Hex string for fill color. Default is "#66cc99". """ from sympy.core.evalf import N verts = (N(self.p1), N(self.p2)) coords = ["{},{}".format(p.x, p.y) for p in verts] path = "M {} L {}".format(coords[0], " L ".join(coords[1:])) return ( '' ).format(2.*scale_factor, path, fill_color) class LinearEntity3D(LinearEntity): """An base class for all linear entities (line, ray and segment) in a 3-dimensional Euclidean space. Attributes ========== p1 p2 direction_ratio direction_cosine points Notes ===== This is a base class and is not meant to be instantiated. """ def __new__(cls, p1, p2, **kwargs): p1 = Point3D(p1, dim=3) p2 = Point3D(p2, dim=3) if p1 == p2: # if it makes sense to return a Point, handle in subclass raise ValueError( "%s.__new__ requires two unique Points." % cls.__name__) return GeometryEntity.__new__(cls, p1, p2, **kwargs) ambient_dimension = 3 @property def direction_ratio(self): """The direction ratio of a given line in 3D. See Also ======== sympy.geometry.line.Line3D.equation Examples ======== >>> from sympy import Point3D, Line3D >>> p1, p2 = Point3D(0, 0, 0), Point3D(5, 3, 1) >>> l = Line3D(p1, p2) >>> l.direction_ratio [5, 3, 1] """ p1, p2 = self.points return p1.direction_ratio(p2) @property def direction_cosine(self): """The normalized direction ratio of a given line in 3D. See Also ======== sympy.geometry.line.Line3D.equation Examples ======== >>> from sympy import Point3D, Line3D >>> p1, p2 = Point3D(0, 0, 0), Point3D(5, 3, 1) >>> l = Line3D(p1, p2) >>> l.direction_cosine [sqrt(35)/7, 3*sqrt(35)/35, sqrt(35)/35] >>> sum(i**2 for i in _) 1 """ p1, p2 = self.points return p1.direction_cosine(p2) class Line3D(LinearEntity3D, Line): """An infinite 3D line in space. A line is declared with two distinct points or a point and direction_ratio as defined using keyword `direction_ratio`. Parameters ========== p1 : Point3D pt : Point3D direction_ratio : list See Also ======== sympy.geometry.point.Point3D sympy.geometry.line.Line sympy.geometry.line.Line2D Examples ======== >>> from sympy import Point3D >>> from sympy.geometry import Line3D >>> L = Line3D(Point3D(2, 3, 4), Point3D(3, 5, 1)) >>> L Line3D(Point3D(2, 3, 4), Point3D(3, 5, 1)) >>> L.points (Point3D(2, 3, 4), Point3D(3, 5, 1)) """ def __new__(cls, p1, pt=None, direction_ratio=[], **kwargs): if isinstance(p1, LinearEntity3D): if pt is not None: raise ValueError('if p1 is a LinearEntity, pt must be None.') p1, pt = p1.args else: p1 = Point(p1, dim=3) if pt is not None and len(direction_ratio) == 0: pt = Point(pt, dim=3) elif len(direction_ratio) == 3 and pt is None: pt = Point3D(p1.x + direction_ratio[0], p1.y + direction_ratio[1], p1.z + direction_ratio[2]) else: raise ValueError('A 2nd Point or keyword "direction_ratio" must ' 'be used.') return LinearEntity3D.__new__(cls, p1, pt, **kwargs) def equation(self, x='x', y='y', z='z', k=None): """Return the equations that define the line in 3D. Parameters ========== x : str, optional The name to use for the x-axis, default value is 'x'. y : str, optional The name to use for the y-axis, default value is 'y'. z : str, optional The name to use for the z-axis, default value is 'z'. Returns ======= equation : Tuple of simultaneous equations Examples ======== >>> from sympy import Point3D, Line3D, solve >>> from sympy.abc import x, y, z >>> p1, p2 = Point3D(1, 0, 0), Point3D(5, 3, 0) >>> l1 = Line3D(p1, p2) >>> eq = l1.equation(x, y, z); eq (-3*x + 4*y + 3, z) >>> solve(eq.subs(z, 0), (x, y, z)) {x: 4*y/3 + 1} """ if k is not None: SymPyDeprecationWarning( feature="equation() no longer needs 'k'", issue=13742, deprecated_since_version="1.2").warn() from sympy import solve x, y, z, k = [_symbol(i, real=True) for i in (x, y, z, 'k')] p1, p2 = self.points d1, d2, d3 = p1.direction_ratio(p2) x1, y1, z1 = p1 eqs = [-d1*k + x - x1, -d2*k + y - y1, -d3*k + z - z1] # eliminate k from equations by solving first eq with k for k for i, e in enumerate(eqs): if e.has(k): kk = solve(eqs[i], k)[0] eqs.pop(i) break return Tuple(*[i.subs(k, kk).as_numer_denom()[0] for i in eqs]) class Ray3D(LinearEntity3D, Ray): """ A Ray is a semi-line in the space with a source point and a direction. Parameters ========== p1 : Point3D The source of the Ray p2 : Point or a direction vector direction_ratio: Determines the direction in which the Ray propagates. Attributes ========== source xdirection ydirection zdirection See Also ======== sympy.geometry.point.Point3D, Line3D Examples ======== >>> from sympy import Point3D >>> from sympy.geometry import Ray3D >>> r = Ray3D(Point3D(2, 3, 4), Point3D(3, 5, 0)) >>> r Ray3D(Point3D(2, 3, 4), Point3D(3, 5, 0)) >>> r.points (Point3D(2, 3, 4), Point3D(3, 5, 0)) >>> r.source Point3D(2, 3, 4) >>> r.xdirection oo >>> r.ydirection oo >>> r.direction_ratio [1, 2, -4] """ def __new__(cls, p1, pt=None, direction_ratio=[], **kwargs): from sympy.utilities.misc import filldedent if isinstance(p1, LinearEntity3D): if pt is not None: raise ValueError('If p1 is a LinearEntity, pt must be None') p1, pt = p1.args else: p1 = Point(p1, dim=3) if pt is not None and len(direction_ratio) == 0: pt = Point(pt, dim=3) elif len(direction_ratio) == 3 and pt is None: pt = Point3D(p1.x + direction_ratio[0], p1.y + direction_ratio[1], p1.z + direction_ratio[2]) else: raise ValueError(filldedent(''' A 2nd Point or keyword "direction_ratio" must be used. ''')) return LinearEntity3D.__new__(cls, p1, pt, **kwargs) @property def xdirection(self): """The x direction of the ray. Positive infinity if the ray points in the positive x direction, negative infinity if the ray points in the negative x direction, or 0 if the ray is vertical. See Also ======== ydirection Examples ======== >>> from sympy import Point3D, Ray3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(0, -1, 0) >>> r1, r2 = Ray3D(p1, p2), Ray3D(p1, p3) >>> r1.xdirection oo >>> r2.xdirection 0 """ if self.p1.x < self.p2.x: return S.Infinity elif self.p1.x == self.p2.x: return S.Zero else: return S.NegativeInfinity @property def ydirection(self): """The y direction of the ray. Positive infinity if the ray points in the positive y direction, negative infinity if the ray points in the negative y direction, or 0 if the ray is horizontal. See Also ======== xdirection Examples ======== >>> from sympy import Point3D, Ray3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(-1, -1, -1), Point3D(-1, 0, 0) >>> r1, r2 = Ray3D(p1, p2), Ray3D(p1, p3) >>> r1.ydirection -oo >>> r2.ydirection 0 """ if self.p1.y < self.p2.y: return S.Infinity elif self.p1.y == self.p2.y: return S.Zero else: return S.NegativeInfinity @property def zdirection(self): """The z direction of the ray. Positive infinity if the ray points in the positive z direction, negative infinity if the ray points in the negative z direction, or 0 if the ray is horizontal. See Also ======== xdirection Examples ======== >>> from sympy import Point3D, Ray3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(-1, -1, -1), Point3D(-1, 0, 0) >>> r1, r2 = Ray3D(p1, p2), Ray3D(p1, p3) >>> r1.ydirection -oo >>> r2.ydirection 0 >>> r2.zdirection 0 """ if self.p1.z < self.p2.z: return S.Infinity elif self.p1.z == self.p2.z: return S.Zero else: return S.NegativeInfinity class Segment3D(LinearEntity3D, Segment): """A line segment in a 3D space. Parameters ========== p1 : Point3D p2 : Point3D Attributes ========== length : number or sympy expression midpoint : Point3D See Also ======== sympy.geometry.point.Point3D, Line3D Examples ======== >>> from sympy import Point3D >>> from sympy.geometry import Segment3D >>> Segment3D((1, 0, 0), (1, 1, 1)) # tuples are interpreted as pts Segment3D(Point3D(1, 0, 0), Point3D(1, 1, 1)) >>> s = Segment3D(Point3D(4, 3, 9), Point3D(1, 1, 7)); s Segment3D(Point3D(4, 3, 9), Point3D(1, 1, 7)) >>> s.points (Point3D(4, 3, 9), Point3D(1, 1, 7)) >>> s.length sqrt(17) >>> s.midpoint Point3D(5/2, 2, 8) """ def __new__(cls, p1, p2, **kwargs): p1 = Point(p1, dim=3) p2 = Point(p2, dim=3) if p1 == p2: return p1 return LinearEntity3D.__new__(cls, p1, p2, **kwargs) sympy-sympy-1.9/sympy/geometry/parabola.py000066400000000000000000000240171412543434000210760ustar00rootroot00000000000000"""Parabolic geometrical entity. Contains * Parabola """ from sympy.core import S from sympy.core.compatibility import ordered from sympy.core.symbol import _symbol from sympy import symbols, simplify, solve # type:ignore from sympy.geometry.entity import GeometryEntity, GeometrySet from sympy.geometry.point import Point, Point2D from sympy.geometry.line import Line, Line2D, Ray2D, Segment2D, LinearEntity3D from sympy.geometry.ellipse import Ellipse from sympy.functions import sign class Parabola(GeometrySet): """A parabolic GeometryEntity. A parabola is declared with a point, that is called 'focus', and a line, that is called 'directrix'. Only vertical or horizontal parabolas are currently supported. Parameters ========== focus : Point Default value is Point(0, 0) directrix : Line Attributes ========== focus directrix axis of symmetry focal length p parameter vertex eccentricity Raises ====== ValueError When `focus` is not a two dimensional point. When `focus` is a point of directrix. NotImplementedError When `directrix` is neither horizontal nor vertical. Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7,8))) >>> p1.focus Point2D(0, 0) >>> p1.directrix Line2D(Point2D(5, 8), Point2D(7, 8)) """ def __new__(cls, focus=None, directrix=None, **kwargs): if focus: focus = Point(focus, dim=2) else: focus = Point(0, 0) directrix = Line(directrix) if (directrix.slope != 0 and directrix.slope != S.Infinity): raise NotImplementedError('The directrix must be a horizontal' ' or vertical line') if directrix.contains(focus): raise ValueError('The focus must not be a point of directrix') return GeometryEntity.__new__(cls, focus, directrix, **kwargs) @property def ambient_dimension(self): """Returns the ambient dimension of parabola. Returns ======= ambient_dimension : integer Examples ======== >>> from sympy import Parabola, Point, Line >>> f1 = Point(0, 0) >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8))) >>> p1.ambient_dimension 2 """ return S(2) @property def axis_of_symmetry(self): """The axis of symmetry of the parabola. Returns ======= axis_of_symmetry : Line See Also ======== sympy.geometry.line.Line Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.axis_of_symmetry Line2D(Point2D(0, 0), Point2D(0, 1)) """ return self.directrix.perpendicular_line(self.focus) @property def directrix(self): """The directrix of the parabola. Returns ======= directrix : Line See Also ======== sympy.geometry.line.Line Examples ======== >>> from sympy import Parabola, Point, Line >>> l1 = Line(Point(5, 8), Point(7, 8)) >>> p1 = Parabola(Point(0, 0), l1) >>> p1.directrix Line2D(Point2D(5, 8), Point2D(7, 8)) """ return self.args[1] @property def eccentricity(self): """The eccentricity of the parabola. Returns ======= eccentricity : number A parabola may also be characterized as a conic section with an eccentricity of 1. As a consequence of this, all parabolas are similar, meaning that while they can be different sizes, they are all the same shape. See Also ======== https://en.wikipedia.org/wiki/Parabola Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.eccentricity 1 Notes ----- The eccentricity for every Parabola is 1 by definition. """ return S.One def equation(self, x='x', y='y'): """The equation of the parabola. Parameters ========== x : str, optional Label for the x-axis. Default value is 'x'. y : str, optional Label for the y-axis. Default value is 'y'. Returns ======= equation : sympy expression Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.equation() -x**2 - 16*y + 64 >>> p1.equation('f') -f**2 - 16*y + 64 >>> p1.equation(y='z') -x**2 - 16*z + 64 """ x = _symbol(x, real=True) y = _symbol(y, real=True) if (self.axis_of_symmetry.slope == 0): t1 = 4 * (self.p_parameter) * (x - self.vertex.x) t2 = (y - self.vertex.y)**2 else: t1 = 4 * (self.p_parameter) * (y - self.vertex.y) t2 = (x - self.vertex.x)**2 return t1 - t2 @property def focal_length(self): """The focal length of the parabola. Returns ======= focal_lenght : number or symbolic expression Notes ===== The distance between the vertex and the focus (or the vertex and directrix), measured along the axis of symmetry, is the "focal length". See Also ======== https://en.wikipedia.org/wiki/Parabola Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.focal_length 4 """ distance = self.directrix.distance(self.focus) focal_length = distance/2 return focal_length @property def focus(self): """The focus of the parabola. Returns ======= focus : Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Parabola, Point, Line >>> f1 = Point(0, 0) >>> p1 = Parabola(f1, Line(Point(5, 8), Point(7, 8))) >>> p1.focus Point2D(0, 0) """ return self.args[0] def intersection(self, o): """The intersection of the parabola and another geometrical entity `o`. Parameters ========== o : GeometryEntity, LinearEntity Returns ======= intersection : list of GeometryEntity objects Examples ======== >>> from sympy import Parabola, Point, Ellipse, Line, Segment >>> p1 = Point(0,0) >>> l1 = Line(Point(1, -2), Point(-1,-2)) >>> parabola1 = Parabola(p1, l1) >>> parabola1.intersection(Ellipse(Point(0, 0), 2, 5)) [Point2D(-2, 0), Point2D(2, 0)] >>> parabola1.intersection(Line(Point(-7, 3), Point(12, 3))) [Point2D(-4, 3), Point2D(4, 3)] >>> parabola1.intersection(Segment((-12, -65), (14, -68))) [] """ x, y = symbols('x y', real=True) parabola_eq = self.equation() if isinstance(o, Parabola): if o in self: return [o] else: return list(ordered([Point(i) for i in solve([parabola_eq, o.equation()], [x, y])])) elif isinstance(o, Point2D): if simplify(parabola_eq.subs([(x, o._args[0]), (y, o._args[1])])) == 0: return [o] else: return [] elif isinstance(o, (Segment2D, Ray2D)): result = solve([parabola_eq, Line2D(o.points[0], o.points[1]).equation()], [x, y]) return list(ordered([Point2D(i) for i in result if i in o])) elif isinstance(o, (Line2D, Ellipse)): return list(ordered([Point2D(i) for i in solve([parabola_eq, o.equation()], [x, y])])) elif isinstance(o, LinearEntity3D): raise TypeError('Entity must be two dimensional, not three dimensional') else: raise TypeError('Wrong type of argument were put') @property def p_parameter(self): """P is a parameter of parabola. Returns ======= p : number or symbolic expression Notes ===== The absolute value of p is the focal length. The sign on p tells which way the parabola faces. Vertical parabolas that open up and horizontal that open right, give a positive value for p. Vertical parabolas that open down and horizontal that open left, give a negative value for p. See Also ======== http://www.sparknotes.com/math/precalc/conicsections/section2.rhtml Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.p_parameter -4 """ if self.axis_of_symmetry.slope == 0: x = self.directrix.coefficients[2] p = sign(self.focus.args[0] + x) else: y = self.directrix.coefficients[2] p = sign(self.focus.args[1] + y) return p * self.focal_length @property def vertex(self): """The vertex of the parabola. Returns ======= vertex : Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Parabola, Point, Line >>> p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7, 8))) >>> p1.vertex Point2D(0, 4) """ focus = self.focus if (self.axis_of_symmetry.slope == 0): vertex = Point(focus.args[0] - self.p_parameter, focus.args[1]) else: vertex = Point(focus.args[0], focus.args[1] - self.p_parameter) return vertex sympy-sympy-1.9/sympy/geometry/plane.py000066400000000000000000000652011412543434000204140ustar00rootroot00000000000000"""Geometrical Planes. Contains ======== Plane """ from sympy import simplify # type:ignore from sympy.core import Dummy, Rational, S, Symbol from sympy.core.symbol import _symbol from sympy.core.compatibility import is_sequence from sympy.functions.elementary.trigonometric import cos, sin, acos, asin, sqrt from sympy.matrices import Matrix from sympy.polys.polytools import cancel from sympy.solvers import solve, linsolve from sympy.utilities.iterables import uniq from sympy.utilities.misc import filldedent, func_name, Undecidable from .entity import GeometryEntity from .point import Point, Point3D from .line import Line, Ray, Segment, Line3D, LinearEntity3D, Ray3D, Segment3D class Plane(GeometryEntity): """ A plane is a flat, two-dimensional surface. A plane is the two-dimensional analogue of a point (zero-dimensions), a line (one-dimension) and a solid (three-dimensions). A plane can generally be constructed by two types of inputs. They are three non-collinear points and a point and the plane's normal vector. Attributes ========== p1 normal_vector Examples ======== >>> from sympy import Plane, Point3D >>> Plane(Point3D(1, 1, 1), Point3D(2, 3, 4), Point3D(2, 2, 2)) Plane(Point3D(1, 1, 1), (-1, 2, -1)) >>> Plane((1, 1, 1), (2, 3, 4), (2, 2, 2)) Plane(Point3D(1, 1, 1), (-1, 2, -1)) >>> Plane(Point3D(1, 1, 1), normal_vector=(1,4,7)) Plane(Point3D(1, 1, 1), (1, 4, 7)) """ def __new__(cls, p1, a=None, b=None, **kwargs): p1 = Point3D(p1, dim=3) if a and b: p2 = Point(a, dim=3) p3 = Point(b, dim=3) if Point3D.are_collinear(p1, p2, p3): raise ValueError('Enter three non-collinear points') a = p1.direction_ratio(p2) b = p1.direction_ratio(p3) normal_vector = tuple(Matrix(a).cross(Matrix(b))) else: a = kwargs.pop('normal_vector', a) if is_sequence(a) and len(a) == 3: normal_vector = Point3D(a).args else: raise ValueError(filldedent(''' Either provide 3 3D points or a point with a normal vector expressed as a sequence of length 3''')) if all(coord.is_zero for coord in normal_vector): raise ValueError('Normal vector cannot be zero vector') return GeometryEntity.__new__(cls, p1, normal_vector, **kwargs) def __contains__(self, o): from sympy.geometry.line import LinearEntity, LinearEntity3D x, y, z = map(Dummy, 'xyz') k = self.equation(x, y, z) if isinstance(o, (LinearEntity, LinearEntity3D)): t = Dummy() d = Point3D(o.arbitrary_point(t)) e = k.subs([(x, d.x), (y, d.y), (z, d.z)]) return e.equals(0) try: o = Point(o, dim=3, strict=True) d = k.xreplace(dict(zip((x, y, z), o.args))) return d.equals(0) except TypeError: return False def angle_between(self, o): """Angle between the plane and other geometric entity. Parameters ========== LinearEntity3D, Plane. Returns ======= angle : angle in radians Notes ===== This method accepts only 3D entities as it's parameter, but if you want to calculate the angle between a 2D entity and a plane you should first convert to a 3D entity by projecting onto a desired plane and then proceed to calculate the angle. Examples ======== >>> from sympy import Point3D, Line3D, Plane >>> a = Plane(Point3D(1, 2, 2), normal_vector=(1, 2, 3)) >>> b = Line3D(Point3D(1, 3, 4), Point3D(2, 2, 2)) >>> a.angle_between(b) -asin(sqrt(21)/6) """ from sympy.geometry.line import LinearEntity3D if isinstance(o, LinearEntity3D): a = Matrix(self.normal_vector) b = Matrix(o.direction_ratio) c = a.dot(b) d = sqrt(sum([i**2 for i in self.normal_vector])) e = sqrt(sum([i**2 for i in o.direction_ratio])) return asin(c/(d*e)) if isinstance(o, Plane): a = Matrix(self.normal_vector) b = Matrix(o.normal_vector) c = a.dot(b) d = sqrt(sum([i**2 for i in self.normal_vector])) e = sqrt(sum([i**2 for i in o.normal_vector])) return acos(c/(d*e)) def arbitrary_point(self, u=None, v=None): """ Returns an arbitrary point on the Plane. If given two parameters, the point ranges over the entire plane. If given 1 or no parameters, returns a point with one parameter which, when varying from 0 to 2*pi, moves the point in a circle of radius 1 about p1 of the Plane. Examples ======== >>> from sympy.geometry import Plane, Ray >>> from sympy.abc import u, v, t, r >>> p = Plane((1, 1, 1), normal_vector=(1, 0, 0)) >>> p.arbitrary_point(u, v) Point3D(1, u + 1, v + 1) >>> p.arbitrary_point(t) Point3D(1, cos(t) + 1, sin(t) + 1) While arbitrary values of u and v can move the point anywhere in the plane, the single-parameter point can be used to construct a ray whose arbitrary point can be located at angle t and radius r from p.p1: >>> Ray(p.p1, _).arbitrary_point(r) Point3D(1, r*cos(t) + 1, r*sin(t) + 1) Returns ======= Point3D """ circle = v is None if circle: u = _symbol(u or 't', real=True) else: u = _symbol(u or 'u', real=True) v = _symbol(v or 'v', real=True) x, y, z = self.normal_vector a, b, c = self.p1.args # x1, y1, z1 is a nonzero vector parallel to the plane if x.is_zero and y.is_zero: x1, y1, z1 = S.One, S.Zero, S.Zero else: x1, y1, z1 = -y, x, S.Zero # x2, y2, z2 is also parallel to the plane, and orthogonal to x1, y1, z1 x2, y2, z2 = tuple(Matrix((x, y, z)).cross(Matrix((x1, y1, z1)))) if circle: x1, y1, z1 = (w/sqrt(x1**2 + y1**2 + z1**2) for w in (x1, y1, z1)) x2, y2, z2 = (w/sqrt(x2**2 + y2**2 + z2**2) for w in (x2, y2, z2)) p = Point3D(a + x1*cos(u) + x2*sin(u), \ b + y1*cos(u) + y2*sin(u), \ c + z1*cos(u) + z2*sin(u)) else: p = Point3D(a + x1*u + x2*v, b + y1*u + y2*v, c + z1*u + z2*v) return p @staticmethod def are_concurrent(*planes): """Is a sequence of Planes concurrent? Two or more Planes are concurrent if their intersections are a common line. Parameters ========== planes: list Returns ======= Boolean Examples ======== >>> from sympy import Plane, Point3D >>> a = Plane(Point3D(5, 0, 0), normal_vector=(1, -1, 1)) >>> b = Plane(Point3D(0, -2, 0), normal_vector=(3, 1, 1)) >>> c = Plane(Point3D(0, -1, 0), normal_vector=(5, -1, 9)) >>> Plane.are_concurrent(a, b) True >>> Plane.are_concurrent(a, b, c) False """ planes = list(uniq(planes)) for i in planes: if not isinstance(i, Plane): raise ValueError('All objects should be Planes but got %s' % i.func) if len(planes) < 2: return False planes = list(planes) first = planes.pop(0) sol = first.intersection(planes[0]) if sol == []: return False else: line = sol[0] for i in planes[1:]: l = first.intersection(i) if not l or not l[0] in line: return False return True def distance(self, o): """Distance between the plane and another geometric entity. Parameters ========== Point3D, LinearEntity3D, Plane. Returns ======= distance Notes ===== This method accepts only 3D entities as it's parameter, but if you want to calculate the distance between a 2D entity and a plane you should first convert to a 3D entity by projecting onto a desired plane and then proceed to calculate the distance. Examples ======== >>> from sympy import Point3D, Line3D, Plane >>> a = Plane(Point3D(1, 1, 1), normal_vector=(1, 1, 1)) >>> b = Point3D(1, 2, 3) >>> a.distance(b) sqrt(3) >>> c = Line3D(Point3D(2, 3, 1), Point3D(1, 2, 2)) >>> a.distance(c) 0 """ if self.intersection(o) != []: return S.Zero if isinstance(o, (Segment3D, Ray3D)): a, b = o.p1, o.p2 pi, = self.intersection(Line3D(a, b)) if pi in o: return self.distance(pi) elif a in Segment3D(pi, b): return self.distance(a) else: assert isinstance(o, Segment3D) is True return self.distance(b) # following code handles `Point3D`, `LinearEntity3D`, `Plane` a = o if isinstance(o, Point3D) else o.p1 n = Point3D(self.normal_vector).unit d = (a - self.p1).dot(n) return abs(d) def equals(self, o): """ Returns True if self and o are the same mathematical entities. Examples ======== >>> from sympy import Plane, Point3D >>> a = Plane(Point3D(1, 2, 3), normal_vector=(1, 1, 1)) >>> b = Plane(Point3D(1, 2, 3), normal_vector=(2, 2, 2)) >>> c = Plane(Point3D(1, 2, 3), normal_vector=(-1, 4, 6)) >>> a.equals(a) True >>> a.equals(b) True >>> a.equals(c) False """ if isinstance(o, Plane): a = self.equation() b = o.equation() return simplify(a / b).is_constant() else: return False def equation(self, x=None, y=None, z=None): """The equation of the Plane. Examples ======== >>> from sympy import Point3D, Plane >>> a = Plane(Point3D(1, 1, 2), Point3D(2, 4, 7), Point3D(3, 5, 1)) >>> a.equation() -23*x + 11*y - 2*z + 16 >>> a = Plane(Point3D(1, 4, 2), normal_vector=(6, 6, 6)) >>> a.equation() 6*x + 6*y + 6*z - 42 """ x, y, z = [i if i else Symbol(j, real=True) for i, j in zip((x, y, z), 'xyz')] a = Point3D(x, y, z) b = self.p1.direction_ratio(a) c = self.normal_vector return (sum(i*j for i, j in zip(b, c))) def intersection(self, o): """ The intersection with other geometrical entity. Parameters ========== Point, Point3D, LinearEntity, LinearEntity3D, Plane Returns ======= List Examples ======== >>> from sympy import Point3D, Line3D, Plane >>> a = Plane(Point3D(1, 2, 3), normal_vector=(1, 1, 1)) >>> b = Point3D(1, 2, 3) >>> a.intersection(b) [Point3D(1, 2, 3)] >>> c = Line3D(Point3D(1, 4, 7), Point3D(2, 2, 2)) >>> a.intersection(c) [Point3D(2, 2, 2)] >>> d = Plane(Point3D(6, 0, 0), normal_vector=(2, -5, 3)) >>> e = Plane(Point3D(2, 0, 0), normal_vector=(3, 4, -3)) >>> d.intersection(e) [Line3D(Point3D(78/23, -24/23, 0), Point3D(147/23, 321/23, 23))] """ from sympy.geometry.line import LinearEntity, LinearEntity3D if not isinstance(o, GeometryEntity): o = Point(o, dim=3) if isinstance(o, Point): if o in self: return [o] else: return [] if isinstance(o, (LinearEntity, LinearEntity3D)): # recast to 3D p1, p2 = o.p1, o.p2 if isinstance(o, Segment): o = Segment3D(p1, p2) elif isinstance(o, Ray): o = Ray3D(p1, p2) elif isinstance(o, Line): o = Line3D(p1, p2) else: raise ValueError('unhandled linear entity: %s' % o.func) if o in self: return [o] else: t = Dummy() # unnamed else it may clash with a symbol in o a = Point3D(o.arbitrary_point(t)) p1, n = self.p1, Point3D(self.normal_vector) # TODO: Replace solve with solveset, when this line is tested c = solve((a - p1).dot(n), t) if not c: return [] else: c = [i for i in c if i.is_real is not False] if len(c) > 1: c = [i for i in c if i.is_real] if len(c) != 1: raise Undecidable("not sure which point is real") p = a.subs(t, c[0]) if p not in o: return [] # e.g. a segment might not intersect a plane return [p] if isinstance(o, Plane): if self.equals(o): return [self] if self.is_parallel(o): return [] else: x, y, z = map(Dummy, 'xyz') a, b = Matrix([self.normal_vector]), Matrix([o.normal_vector]) c = list(a.cross(b)) d = self.equation(x, y, z) e = o.equation(x, y, z) result = list(linsolve([d, e], x, y, z))[0] for i in (x, y, z): result = result.subs(i, 0) return [Line3D(Point3D(result), direction_ratio=c)] def is_coplanar(self, o): """ Returns True if `o` is coplanar with self, else False. Examples ======== >>> from sympy import Plane >>> o = (0, 0, 0) >>> p = Plane(o, (1, 1, 1)) >>> p2 = Plane(o, (2, 2, 2)) >>> p == p2 False >>> p.is_coplanar(p2) True """ if isinstance(o, Plane): x, y, z = map(Dummy, 'xyz') return not cancel(self.equation(x, y, z)/o.equation(x, y, z)).has(x, y, z) if isinstance(o, Point3D): return o in self elif isinstance(o, LinearEntity3D): return all(i in self for i in self) elif isinstance(o, GeometryEntity): # XXX should only be handling 2D objects now return all(i == 0 for i in self.normal_vector[:2]) def is_parallel(self, l): """Is the given geometric entity parallel to the plane? Parameters ========== LinearEntity3D or Plane Returns ======= Boolean Examples ======== >>> from sympy import Plane, Point3D >>> a = Plane(Point3D(1,4,6), normal_vector=(2, 4, 6)) >>> b = Plane(Point3D(3,1,3), normal_vector=(4, 8, 12)) >>> a.is_parallel(b) True """ from sympy.geometry.line import LinearEntity3D if isinstance(l, LinearEntity3D): a = l.direction_ratio b = self.normal_vector c = sum([i*j for i, j in zip(a, b)]) if c == 0: return True else: return False elif isinstance(l, Plane): a = Matrix(l.normal_vector) b = Matrix(self.normal_vector) if a.cross(b).is_zero_matrix: return True else: return False def is_perpendicular(self, l): """is the given geometric entity perpendicualar to the given plane? Parameters ========== LinearEntity3D or Plane Returns ======= Boolean Examples ======== >>> from sympy import Plane, Point3D >>> a = Plane(Point3D(1,4,6), normal_vector=(2, 4, 6)) >>> b = Plane(Point3D(2, 2, 2), normal_vector=(-1, 2, -1)) >>> a.is_perpendicular(b) True """ from sympy.geometry.line import LinearEntity3D if isinstance(l, LinearEntity3D): a = Matrix(l.direction_ratio) b = Matrix(self.normal_vector) if a.cross(b).is_zero_matrix: return True else: return False elif isinstance(l, Plane): a = Matrix(l.normal_vector) b = Matrix(self.normal_vector) if a.dot(b) == 0: return True else: return False else: return False @property def normal_vector(self): """Normal vector of the given plane. Examples ======== >>> from sympy import Point3D, Plane >>> a = Plane(Point3D(1, 1, 1), Point3D(2, 3, 4), Point3D(2, 2, 2)) >>> a.normal_vector (-1, 2, -1) >>> a = Plane(Point3D(1, 1, 1), normal_vector=(1, 4, 7)) >>> a.normal_vector (1, 4, 7) """ return self.args[1] @property def p1(self): """The only defining point of the plane. Others can be obtained from the arbitrary_point method. See Also ======== sympy.geometry.point.Point3D Examples ======== >>> from sympy import Point3D, Plane >>> a = Plane(Point3D(1, 1, 1), Point3D(2, 3, 4), Point3D(2, 2, 2)) >>> a.p1 Point3D(1, 1, 1) """ return self.args[0] def parallel_plane(self, pt): """ Plane parallel to the given plane and passing through the point pt. Parameters ========== pt: Point3D Returns ======= Plane Examples ======== >>> from sympy import Plane, Point3D >>> a = Plane(Point3D(1, 4, 6), normal_vector=(2, 4, 6)) >>> a.parallel_plane(Point3D(2, 3, 5)) Plane(Point3D(2, 3, 5), (2, 4, 6)) """ a = self.normal_vector return Plane(pt, normal_vector=a) def perpendicular_line(self, pt): """A line perpendicular to the given plane. Parameters ========== pt: Point3D Returns ======= Line3D Examples ======== >>> from sympy import Plane, Point3D >>> a = Plane(Point3D(1,4,6), normal_vector=(2, 4, 6)) >>> a.perpendicular_line(Point3D(9, 8, 7)) Line3D(Point3D(9, 8, 7), Point3D(11, 12, 13)) """ a = self.normal_vector return Line3D(pt, direction_ratio=a) def perpendicular_plane(self, *pts): """ Return a perpendicular passing through the given points. If the direction ratio between the points is the same as the Plane's normal vector then, to select from the infinite number of possible planes, a third point will be chosen on the z-axis (or the y-axis if the normal vector is already parallel to the z-axis). If less than two points are given they will be supplied as follows: if no point is given then pt1 will be self.p1; if a second point is not given it will be a point through pt1 on a line parallel to the z-axis (if the normal is not already the z-axis, otherwise on the line parallel to the y-axis). Parameters ========== pts: 0, 1 or 2 Point3D Returns ======= Plane Examples ======== >>> from sympy import Plane, Point3D >>> a, b = Point3D(0, 0, 0), Point3D(0, 1, 0) >>> Z = (0, 0, 1) >>> p = Plane(a, normal_vector=Z) >>> p.perpendicular_plane(a, b) Plane(Point3D(0, 0, 0), (1, 0, 0)) """ if len(pts) > 2: raise ValueError('No more than 2 pts should be provided.') pts = list(pts) if len(pts) == 0: pts.append(self.p1) if len(pts) == 1: x, y, z = self.normal_vector if x == y == 0: dir = (0, 1, 0) else: dir = (0, 0, 1) pts.append(pts[0] + Point3D(*dir)) p1, p2 = [Point(i, dim=3) for i in pts] l = Line3D(p1, p2) n = Line3D(p1, direction_ratio=self.normal_vector) if l in n: # XXX should an error be raised instead? # there are infinitely many perpendicular planes; x, y, z = self.normal_vector if x == y == 0: # the z axis is the normal so pick a pt on the y-axis p3 = Point3D(0, 1, 0) # case 1 else: # else pick a pt on the z axis p3 = Point3D(0, 0, 1) # case 2 # in case that point is already given, move it a bit if p3 in l: p3 *= 2 # case 3 else: p3 = p1 + Point3D(*self.normal_vector) # case 4 return Plane(p1, p2, p3) def projection_line(self, line): """Project the given line onto the plane through the normal plane containing the line. Parameters ========== LinearEntity or LinearEntity3D Returns ======= Point3D, Line3D, Ray3D or Segment3D Notes ===== For the interaction between 2D and 3D lines(segments, rays), you should convert the line to 3D by using this method. For example for finding the intersection between a 2D and a 3D line, convert the 2D line to a 3D line by projecting it on a required plane and then proceed to find the intersection between those lines. Examples ======== >>> from sympy import Plane, Line, Line3D, Point3D >>> a = Plane(Point3D(1, 1, 1), normal_vector=(1, 1, 1)) >>> b = Line(Point3D(1, 1), Point3D(2, 2)) >>> a.projection_line(b) Line3D(Point3D(4/3, 4/3, 1/3), Point3D(5/3, 5/3, -1/3)) >>> c = Line3D(Point3D(1, 1, 1), Point3D(2, 2, 2)) >>> a.projection_line(c) Point3D(1, 1, 1) """ from sympy.geometry.line import LinearEntity, LinearEntity3D if not isinstance(line, (LinearEntity, LinearEntity3D)): raise NotImplementedError('Enter a linear entity only') a, b = self.projection(line.p1), self.projection(line.p2) if a == b: # projection does not imply intersection so for # this case (line parallel to plane's normal) we # return the projection point return a if isinstance(line, (Line, Line3D)): return Line3D(a, b) if isinstance(line, (Ray, Ray3D)): return Ray3D(a, b) if isinstance(line, (Segment, Segment3D)): return Segment3D(a, b) def projection(self, pt): """Project the given point onto the plane along the plane normal. Parameters ========== Point or Point3D Returns ======= Point3D Examples ======== >>> from sympy import Plane, Point3D >>> A = Plane(Point3D(1, 1, 2), normal_vector=(1, 1, 1)) The projection is along the normal vector direction, not the z axis, so (1, 1) does not project to (1, 1, 2) on the plane A: >>> b = Point3D(1, 1) >>> A.projection(b) Point3D(5/3, 5/3, 2/3) >>> _ in A True But the point (1, 1, 2) projects to (1, 1) on the XY-plane: >>> XY = Plane((0, 0, 0), (0, 0, 1)) >>> XY.projection((1, 1, 2)) Point3D(1, 1, 0) """ rv = Point(pt, dim=3) if rv in self: return rv return self.intersection(Line3D(rv, rv + Point3D(self.normal_vector)))[0] def random_point(self, seed=None): """ Returns a random point on the Plane. Returns ======= Point3D Examples ======== >>> from sympy import Plane >>> p = Plane((1, 0, 0), normal_vector=(0, 1, 0)) >>> r = p.random_point(seed=42) # seed value is optional >>> r.n(3) Point3D(2.29, 0, -1.35) The random point can be moved to lie on the circle of radius 1 centered on p1: >>> c = p.p1 + (r - p.p1).unit >>> c.distance(p.p1).equals(1) True """ import random if seed is not None: rng = random.Random(seed) else: rng = random u, v = Dummy('u'), Dummy('v') params = { u: 2*Rational(rng.gauss(0, 1)) - 1, v: 2*Rational(rng.gauss(0, 1)) - 1} return self.arbitrary_point(u, v).subs(params) def parameter_value(self, other, u, v=None): """Return the parameter(s) corresponding to the given point. Examples ======== >>> from sympy import pi >>> from sympy.geometry import Plane >>> from sympy.abc import t, u, v >>> p = Plane((2, 0, 0), (0, 0, 1), (0, 1, 0)) By default, the parameter value returned defines a point that is a distance of 1 from the Plane's p1 value and in line with the given point: >>> on_circle = p.arbitrary_point(t).subs(t, pi/4) >>> on_circle.distance(p.p1) 1 >>> p.parameter_value(on_circle, t) {t: pi/4} Moving the point twice as far from p1 does not change the parameter value: >>> off_circle = p.p1 + (on_circle - p.p1)*2 >>> off_circle.distance(p.p1) 2 >>> p.parameter_value(off_circle, t) {t: pi/4} If the 2-value parameter is desired, supply the two parameter symbols and a replacement dictionary will be returned: >>> p.parameter_value(on_circle, u, v) {u: sqrt(10)/10, v: sqrt(10)/30} >>> p.parameter_value(off_circle, u, v) {u: sqrt(10)/5, v: sqrt(10)/15} """ from sympy.geometry.point import Point from sympy.solvers.solvers import solve if not isinstance(other, GeometryEntity): other = Point(other, dim=self.ambient_dimension) if not isinstance(other, Point): raise ValueError("other must be a point") if other == self.p1: return other if isinstance(u, Symbol) and v is None: delta = self.arbitrary_point(u) - self.p1 eq = delta - (other - self.p1).unit sol = solve(eq, u, dict=True) elif isinstance(u, Symbol) and isinstance(v, Symbol): pt = self.arbitrary_point(u, v) sol = solve(pt - other, (u, v), dict=True) else: raise ValueError('expecting 1 or 2 symbols') if not sol: raise ValueError("Given point is not on %s" % func_name(self)) return sol[0] # {t: tval} or {u: uval, v: vval} @property def ambient_dimension(self): return self.p1.ambient_dimension sympy-sympy-1.9/sympy/geometry/point.py000066400000000000000000001075061412543434000204530ustar00rootroot00000000000000"""Geometrical Points. Contains ======== Point Point2D Point3D When methods of Point require 1 or more points as arguments, they can be passed as a sequence of coordinates or Points: >>> from sympy.geometry.point import Point >>> Point(1, 1).is_collinear((2, 2), (3, 4)) False >>> Point(1, 1).is_collinear(Point(2, 2), Point(3, 4)) False """ import warnings from sympy.core import S, sympify, Expr from sympy.core.compatibility import is_sequence from sympy.core.containers import Tuple from sympy.simplify import nsimplify, simplify from sympy.geometry.exceptions import GeometryError from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.complexes import im from sympy.matrices import Matrix from sympy.core.numbers import Float from sympy.core.parameters import global_parameters from sympy.core.add import Add from sympy.utilities.iterables import uniq from sympy.utilities.misc import filldedent, func_name, Undecidable from .entity import GeometryEntity class Point(GeometryEntity): """A point in a n-dimensional Euclidean space. Parameters ========== coords : sequence of n-coordinate values. In the special case where n=2 or 3, a Point2D or Point3D will be created as appropriate. evaluate : if `True` (default), all floats are turn into exact types. dim : number of coordinates the point should have. If coordinates are unspecified, they are padded with zeros. on_morph : indicates what should happen when the number of coordinates of a point need to be changed by adding or removing zeros. Possible values are `'warn'`, `'error'`, or `ignore` (default). No warning or error is given when `*args` is empty and `dim` is given. An error is always raised when trying to remove nonzero coordinates. Attributes ========== length origin: A `Point` representing the origin of the appropriately-dimensioned space. Raises ====== TypeError : When instantiating with anything but a Point or sequence ValueError : when instantiating with a sequence with length < 2 or when trying to reduce dimensions if keyword `on_morph='error'` is set. See Also ======== sympy.geometry.line.Segment : Connects two Points Examples ======== >>> from sympy.geometry import Point >>> from sympy.abc import x >>> Point(1, 2, 3) Point3D(1, 2, 3) >>> Point([1, 2]) Point2D(1, 2) >>> Point(0, x) Point2D(0, x) >>> Point(dim=4) Point(0, 0, 0, 0) Floats are automatically converted to Rational unless the evaluate flag is False: >>> Point(0.5, 0.25) Point2D(1/2, 1/4) >>> Point(0.5, 0.25, evaluate=False) Point2D(0.5, 0.25) """ is_Point = True def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_parameters.evaluate) on_morph = kwargs.get('on_morph', 'ignore') # unpack into coords coords = args[0] if len(args) == 1 else args # check args and handle quickly handle Point instances if isinstance(coords, Point): # even if we're mutating the dimension of a point, we # don't reevaluate its coordinates evaluate = False if len(coords) == kwargs.get('dim', len(coords)): return coords if not is_sequence(coords): raise TypeError(filldedent(''' Expecting sequence of coordinates, not `{}`''' .format(func_name(coords)))) # A point where only `dim` is specified is initialized # to zeros. if len(coords) == 0 and kwargs.get('dim', None): coords = (S.Zero,)*kwargs.get('dim') coords = Tuple(*coords) dim = kwargs.get('dim', len(coords)) if len(coords) < 2: raise ValueError(filldedent(''' Point requires 2 or more coordinates or keyword `dim` > 1.''')) if len(coords) != dim: message = ("Dimension of {} needs to be changed " "from {} to {}.").format(coords, len(coords), dim) if on_morph == 'ignore': pass elif on_morph == "error": raise ValueError(message) elif on_morph == 'warn': warnings.warn(message) else: raise ValueError(filldedent(''' on_morph value should be 'error', 'warn' or 'ignore'.''')) if any(coords[dim:]): raise ValueError('Nonzero coordinates cannot be removed.') if any(a.is_number and im(a) for a in coords): raise ValueError('Imaginary coordinates are not permitted.') if not all(isinstance(a, Expr) for a in coords): raise TypeError('Coordinates must be valid SymPy expressions.') # pad with zeros appropriately coords = coords[:dim] + (S.Zero,)*(dim - len(coords)) # Turn any Floats into rationals and simplify # any expressions before we instantiate if evaluate: coords = coords.xreplace({ f: simplify(nsimplify(f, rational=True)) for f in coords.atoms(Float)}) # return 2D or 3D instances if len(coords) == 2: kwargs['_nocheck'] = True return Point2D(*coords, **kwargs) elif len(coords) == 3: kwargs['_nocheck'] = True return Point3D(*coords, **kwargs) # the general Point return GeometryEntity.__new__(cls, *coords) def __abs__(self): """Returns the distance between this point and the origin.""" origin = Point([0]*len(self)) return Point.distance(origin, self) def __add__(self, other): """Add other to self by incrementing self's coordinates by those of other. Notes ===== >>> from sympy.geometry.point import Point When sequences of coordinates are passed to Point methods, they are converted to a Point internally. This __add__ method does not do that so if floating point values are used, a floating point result (in terms of SymPy Floats) will be returned. >>> Point(1, 2) + (.1, .2) Point2D(1.1, 2.2) If this is not desired, the `translate` method can be used or another Point can be added: >>> Point(1, 2).translate(.1, .2) Point2D(11/10, 11/5) >>> Point(1, 2) + Point(.1, .2) Point2D(11/10, 11/5) See Also ======== sympy.geometry.point.Point.translate """ try: s, o = Point._normalize_dimension(self, Point(other, evaluate=False)) except TypeError: raise GeometryError("Don't know how to add {} and a Point object".format(other)) coords = [simplify(a + b) for a, b in zip(s, o)] return Point(coords, evaluate=False) def __contains__(self, item): return item in self.args def __truediv__(self, divisor): """Divide point's coordinates by a factor.""" divisor = sympify(divisor) coords = [simplify(x/divisor) for x in self.args] return Point(coords, evaluate=False) def __eq__(self, other): if not isinstance(other, Point) or len(self.args) != len(other.args): return False return self.args == other.args def __getitem__(self, key): return self.args[key] def __hash__(self): return hash(self.args) def __iter__(self): return self.args.__iter__() def __len__(self): return len(self.args) def __mul__(self, factor): """Multiply point's coordinates by a factor. Notes ===== >>> from sympy.geometry.point import Point When multiplying a Point by a floating point number, the coordinates of the Point will be changed to Floats: >>> Point(1, 2)*0.1 Point2D(0.1, 0.2) If this is not desired, the `scale` method can be used or else only multiply or divide by integers: >>> Point(1, 2).scale(1.1, 1.1) Point2D(11/10, 11/5) >>> Point(1, 2)*11/10 Point2D(11/10, 11/5) See Also ======== sympy.geometry.point.Point.scale """ factor = sympify(factor) coords = [simplify(x*factor) for x in self.args] return Point(coords, evaluate=False) def __rmul__(self, factor): """Multiply a factor by point's coordinates.""" return self.__mul__(factor) def __neg__(self): """Negate the point.""" coords = [-x for x in self.args] return Point(coords, evaluate=False) def __sub__(self, other): """Subtract two points, or subtract a factor from this point's coordinates.""" return self + [-x for x in other] @classmethod def _normalize_dimension(cls, *points, **kwargs): """Ensure that points have the same dimension. By default `on_morph='warn'` is passed to the `Point` constructor.""" # if we have a built-in ambient dimension, use it dim = getattr(cls, '_ambient_dimension', None) # override if we specified it dim = kwargs.get('dim', dim) # if no dim was given, use the highest dimensional point if dim is None: dim = max(i.ambient_dimension for i in points) if all(i.ambient_dimension == dim for i in points): return list(points) kwargs['dim'] = dim kwargs['on_morph'] = kwargs.get('on_morph', 'warn') return [Point(i, **kwargs) for i in points] @staticmethod def affine_rank(*args): """The affine rank of a set of points is the dimension of the smallest affine space containing all the points. For example, if the points lie on a line (and are not all the same) their affine rank is 1. If the points lie on a plane but not a line, their affine rank is 2. By convention, the empty set has affine rank -1.""" if len(args) == 0: return -1 # make sure we're genuinely points # and translate every point to the origin points = Point._normalize_dimension(*[Point(i) for i in args]) origin = points[0] points = [i - origin for i in points[1:]] m = Matrix([i.args for i in points]) # XXX fragile -- what is a better way? return m.rank(iszerofunc = lambda x: abs(x.n(2)) < 1e-12 if x.is_number else x.is_zero) @property def ambient_dimension(self): """Number of components this point has.""" return getattr(self, '_ambient_dimension', len(self)) @classmethod def are_coplanar(cls, *points): """Return True if there exists a plane in which all the points lie. A trivial True value is returned if `len(points) < 3` or all Points are 2-dimensional. Parameters ========== A set of points Raises ====== ValueError : if less than 3 unique points are given Returns ======= boolean Examples ======== >>> from sympy import Point3D >>> p1 = Point3D(1, 2, 2) >>> p2 = Point3D(2, 7, 2) >>> p3 = Point3D(0, 0, 2) >>> p4 = Point3D(1, 1, 2) >>> Point3D.are_coplanar(p1, p2, p3, p4) True >>> p5 = Point3D(0, 1, 3) >>> Point3D.are_coplanar(p1, p2, p3, p5) False """ if len(points) <= 1: return True points = cls._normalize_dimension(*[Point(i) for i in points]) # quick exit if we are in 2D if points[0].ambient_dimension == 2: return True points = list(uniq(points)) return Point.affine_rank(*points) <= 2 def distance(self, other): """The Euclidean distance between self and another GeometricEntity. Returns ======= distance : number or symbolic expression. Raises ====== TypeError : if other is not recognized as a GeometricEntity or is a GeometricEntity for which distance is not defined. See Also ======== sympy.geometry.line.Segment.length sympy.geometry.point.Point.taxicab_distance Examples ======== >>> from sympy.geometry import Point, Line >>> p1, p2 = Point(1, 1), Point(4, 5) >>> l = Line((3, 1), (2, 2)) >>> p1.distance(p2) 5 >>> p1.distance(l) sqrt(2) The computed distance may be symbolic, too: >>> from sympy.abc import x, y >>> p3 = Point(x, y) >>> p3.distance((0, 0)) sqrt(x**2 + y**2) """ if not isinstance(other, GeometryEntity): try: other = Point(other, dim=self.ambient_dimension) except TypeError: raise TypeError("not recognized as a GeometricEntity: %s" % type(other)) if isinstance(other, Point): s, p = Point._normalize_dimension(self, Point(other)) return sqrt(Add(*((a - b)**2 for a, b in zip(s, p)))) distance = getattr(other, 'distance', None) if distance is None: raise TypeError("distance between Point and %s is not defined" % type(other)) return distance(self) def dot(self, p): """Return dot product of self with another Point.""" if not is_sequence(p): p = Point(p) # raise the error via Point return Add(*(a*b for a, b in zip(self, p))) def equals(self, other): """Returns whether the coordinates of self and other agree.""" # a point is equal to another point if all its components are equal if not isinstance(other, Point) or len(self) != len(other): return False return all(a.equals(b) for a, b in zip(self, other)) def evalf(self, prec=None, **options): """Evaluate the coordinates of the point. This method will, where possible, create and return a new Point where the coordinates are evaluated as floating point numbers to the precision indicated (default=15). Parameters ========== prec : int Returns ======= point : Point Examples ======== >>> from sympy import Point, Rational >>> p1 = Point(Rational(1, 2), Rational(3, 2)) >>> p1 Point2D(1/2, 3/2) >>> p1.evalf() Point2D(0.5, 1.5) """ coords = [x.evalf(prec, **options) for x in self.args] return Point(*coords, evaluate=False) def intersection(self, other): """The intersection between this point and another GeometryEntity. Parameters ========== other : GeometryEntity or sequence of coordinates Returns ======= intersection : list of Points Notes ===== The return value will either be an empty list if there is no intersection, otherwise it will contain this point. Examples ======== >>> from sympy import Point >>> p1, p2, p3 = Point(0, 0), Point(1, 1), Point(0, 0) >>> p1.intersection(p2) [] >>> p1.intersection(p3) [Point2D(0, 0)] """ if not isinstance(other, GeometryEntity): other = Point(other) if isinstance(other, Point): if self == other: return [self] p1, p2 = Point._normalize_dimension(self, other) if p1 == self and p1 == p2: return [self] return [] return other.intersection(self) def is_collinear(self, *args): """Returns `True` if there exists a line that contains `self` and `points`. Returns `False` otherwise. A trivially True value is returned if no points are given. Parameters ========== args : sequence of Points Returns ======= is_collinear : boolean See Also ======== sympy.geometry.line.Line Examples ======== >>> from sympy import Point >>> from sympy.abc import x >>> p1, p2 = Point(0, 0), Point(1, 1) >>> p3, p4, p5 = Point(2, 2), Point(x, x), Point(1, 2) >>> Point.is_collinear(p1, p2, p3, p4) True >>> Point.is_collinear(p1, p2, p3, p5) False """ points = (self,) + args points = Point._normalize_dimension(*[Point(i) for i in points]) points = list(uniq(points)) return Point.affine_rank(*points) <= 1 def is_concyclic(self, *args): """Do `self` and the given sequence of points lie in a circle? Returns True if the set of points are concyclic and False otherwise. A trivial value of True is returned if there are fewer than 2 other points. Parameters ========== args : sequence of Points Returns ======= is_concyclic : boolean Examples ======== >>> from sympy import Point Define 4 points that are on the unit circle: >>> p1, p2, p3, p4 = Point(1, 0), (0, 1), (-1, 0), (0, -1) >>> p1.is_concyclic() == p1.is_concyclic(p2, p3, p4) == True True Define a point not on that circle: >>> p = Point(1, 1) >>> p.is_concyclic(p1, p2, p3) False """ points = (self,) + args points = Point._normalize_dimension(*[Point(i) for i in points]) points = list(uniq(points)) if not Point.affine_rank(*points) <= 2: return False origin = points[0] points = [p - origin for p in points] # points are concyclic if they are coplanar and # there is a point c so that ||p_i-c|| == ||p_j-c|| for all # i and j. Rearranging this equation gives us the following # condition: the matrix `mat` must not a pivot in the last # column. mat = Matrix([list(i) + [i.dot(i)] for i in points]) rref, pivots = mat.rref() if len(origin) not in pivots: return True return False @property def is_nonzero(self): """True if any coordinate is nonzero, False if every coordinate is zero, and None if it cannot be determined.""" is_zero = self.is_zero if is_zero is None: return None return not is_zero def is_scalar_multiple(self, p): """Returns whether each coordinate of `self` is a scalar multiple of the corresponding coordinate in point p. """ s, o = Point._normalize_dimension(self, Point(p)) # 2d points happen a lot, so optimize this function call if s.ambient_dimension == 2: (x1, y1), (x2, y2) = s.args, o.args rv = (x1*y2 - x2*y1).equals(0) if rv is None: raise Undecidable(filldedent( '''can't determine if %s is a scalar multiple of %s''' % (s, o))) # if the vectors p1 and p2 are linearly dependent, then they must # be scalar multiples of each other m = Matrix([s.args, o.args]) return m.rank() < 2 @property def is_zero(self): """True if every coordinate is zero, False if any coordinate is not zero, and None if it cannot be determined.""" nonzero = [x.is_nonzero for x in self.args] if any(nonzero): return False if any(x is None for x in nonzero): return None return True @property def length(self): """ Treating a Point as a Line, this returns 0 for the length of a Point. Examples ======== >>> from sympy import Point >>> p = Point(0, 1) >>> p.length 0 """ return S.Zero def midpoint(self, p): """The midpoint between self and point p. Parameters ========== p : Point Returns ======= midpoint : Point See Also ======== sympy.geometry.line.Segment.midpoint Examples ======== >>> from sympy.geometry import Point >>> p1, p2 = Point(1, 1), Point(13, 5) >>> p1.midpoint(p2) Point2D(7, 3) """ s, p = Point._normalize_dimension(self, Point(p)) return Point([simplify((a + b)*S.Half) for a, b in zip(s, p)]) @property def origin(self): """A point of all zeros of the same ambient dimension as the current point""" return Point([0]*len(self), evaluate=False) @property def orthogonal_direction(self): """Returns a non-zero point that is orthogonal to the line containing `self` and the origin. Examples ======== >>> from sympy.geometry import Line, Point >>> a = Point(1, 2, 3) >>> a.orthogonal_direction Point3D(-2, 1, 0) >>> b = _ >>> Line(b, b.origin).is_perpendicular(Line(a, a.origin)) True """ dim = self.ambient_dimension # if a coordinate is zero, we can put a 1 there and zeros elsewhere if self[0].is_zero: return Point([1] + (dim - 1)*[0]) if self[1].is_zero: return Point([0,1] + (dim - 2)*[0]) # if the first two coordinates aren't zero, we can create a non-zero # orthogonal vector by swapping them, negating one, and padding with zeros return Point([-self[1], self[0]] + (dim - 2)*[0]) @staticmethod def project(a, b): """Project the point `a` onto the line between the origin and point `b` along the normal direction. Parameters ========== a : Point b : Point Returns ======= p : Point See Also ======== sympy.geometry.line.LinearEntity.projection Examples ======== >>> from sympy.geometry import Line, Point >>> a = Point(1, 2) >>> b = Point(2, 5) >>> z = a.origin >>> p = Point.project(a, b) >>> Line(p, a).is_perpendicular(Line(p, b)) True >>> Point.is_collinear(z, p, b) True """ a, b = Point._normalize_dimension(Point(a), Point(b)) if b.is_zero: raise ValueError("Cannot project to the zero vector.") return b*(a.dot(b) / b.dot(b)) def taxicab_distance(self, p): """The Taxicab Distance from self to point p. Returns the sum of the horizontal and vertical distances to point p. Parameters ========== p : Point Returns ======= taxicab_distance : The sum of the horizontal and vertical distances to point p. See Also ======== sympy.geometry.point.Point.distance Examples ======== >>> from sympy.geometry import Point >>> p1, p2 = Point(1, 1), Point(4, 5) >>> p1.taxicab_distance(p2) 7 """ s, p = Point._normalize_dimension(self, Point(p)) return Add(*(abs(a - b) for a, b in zip(s, p))) def canberra_distance(self, p): """The Canberra Distance from self to point p. Returns the weighted sum of horizontal and vertical distances to point p. Parameters ========== p : Point Returns ======= canberra_distance : The weighted sum of horizontal and vertical distances to point p. The weight used is the sum of absolute values of the coordinates. Examples ======== >>> from sympy.geometry import Point >>> p1, p2 = Point(1, 1), Point(3, 3) >>> p1.canberra_distance(p2) 1 >>> p1, p2 = Point(0, 0), Point(3, 3) >>> p1.canberra_distance(p2) 2 Raises ====== ValueError when both vectors are zero. See Also ======== sympy.geometry.point.Point.distance """ s, p = Point._normalize_dimension(self, Point(p)) if self.is_zero and p.is_zero: raise ValueError("Cannot project to the zero vector.") return Add(*((abs(a - b)/(abs(a) + abs(b))) for a, b in zip(s, p))) @property def unit(self): """Return the Point that is in the same direction as `self` and a distance of 1 from the origin""" return self / abs(self) n = evalf class Point2D(Point): """A point in a 2-dimensional Euclidean space. Parameters ========== coords : sequence of 2 coordinate values. Attributes ========== x y length Raises ====== TypeError When trying to add or subtract points with different dimensions. When trying to create a point with more than two dimensions. When `intersection` is called with object other than a Point. See Also ======== sympy.geometry.line.Segment : Connects two Points Examples ======== >>> from sympy.geometry import Point2D >>> from sympy.abc import x >>> Point2D(1, 2) Point2D(1, 2) >>> Point2D([1, 2]) Point2D(1, 2) >>> Point2D(0, x) Point2D(0, x) Floats are automatically converted to Rational unless the evaluate flag is False: >>> Point2D(0.5, 0.25) Point2D(1/2, 1/4) >>> Point2D(0.5, 0.25, evaluate=False) Point2D(0.5, 0.25) """ _ambient_dimension = 2 def __new__(cls, *args, _nocheck=False, **kwargs): if not _nocheck: kwargs['dim'] = 2 args = Point(*args, **kwargs) return GeometryEntity.__new__(cls, *args) def __contains__(self, item): return item == self @property def bounds(self): """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding rectangle for the geometric figure. """ return (self.x, self.y, self.x, self.y) def rotate(self, angle, pt=None): """Rotate ``angle`` radians counterclockwise about Point ``pt``. See Also ======== translate, scale Examples ======== >>> from sympy import Point2D, pi >>> t = Point2D(1, 0) >>> t.rotate(pi/2) Point2D(0, 1) >>> t.rotate(pi/2, (2, 0)) Point2D(2, -1) """ from sympy import cos, sin, Point c = cos(angle) s = sin(angle) rv = self if pt is not None: pt = Point(pt, dim=2) rv -= pt x, y = rv.args rv = Point(c*x - s*y, s*x + c*y) if pt is not None: rv += pt return rv def scale(self, x=1, y=1, pt=None): """Scale the coordinates of the Point by multiplying by ``x`` and ``y`` after subtracting ``pt`` -- default is (0, 0) -- and then adding ``pt`` back again (i.e. ``pt`` is the point of reference for the scaling). See Also ======== rotate, translate Examples ======== >>> from sympy import Point2D >>> t = Point2D(1, 1) >>> t.scale(2) Point2D(2, 1) >>> t.scale(2, 2) Point2D(2, 2) """ if pt: pt = Point(pt, dim=2) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) return Point(self.x*x, self.y*y) def transform(self, matrix): """Return the point after applying the transformation described by the 3x3 Matrix, ``matrix``. See Also ======== sympy.geometry.point.Point2D.rotate sympy.geometry.point.Point2D.scale sympy.geometry.point.Point2D.translate """ if not (matrix.is_Matrix and matrix.shape == (3, 3)): raise ValueError("matrix must be a 3x3 matrix") x, y = self.args return Point(*(Matrix(1, 3, [x, y, 1])*matrix).tolist()[0][:2]) def translate(self, x=0, y=0): """Shift the Point by adding x and y to the coordinates of the Point. See Also ======== sympy.geometry.point.Point2D.rotate, scale Examples ======== >>> from sympy import Point2D >>> t = Point2D(0, 1) >>> t.translate(2) Point2D(2, 1) >>> t.translate(2, 2) Point2D(2, 3) >>> t + Point2D(2, 2) Point2D(2, 3) """ return Point(self.x + x, self.y + y) @property def coordinates(self): """ Returns the two coordinates of the Point. Examples ======== >>> from sympy import Point2D >>> p = Point2D(0, 1) >>> p.coordinates (0, 1) """ return self.args @property def x(self): """ Returns the X coordinate of the Point. Examples ======== >>> from sympy import Point2D >>> p = Point2D(0, 1) >>> p.x 0 """ return self.args[0] @property def y(self): """ Returns the Y coordinate of the Point. Examples ======== >>> from sympy import Point2D >>> p = Point2D(0, 1) >>> p.y 1 """ return self.args[1] class Point3D(Point): """A point in a 3-dimensional Euclidean space. Parameters ========== coords : sequence of 3 coordinate values. Attributes ========== x y z length Raises ====== TypeError When trying to add or subtract points with different dimensions. When `intersection` is called with object other than a Point. Examples ======== >>> from sympy import Point3D >>> from sympy.abc import x >>> Point3D(1, 2, 3) Point3D(1, 2, 3) >>> Point3D([1, 2, 3]) Point3D(1, 2, 3) >>> Point3D(0, x, 3) Point3D(0, x, 3) Floats are automatically converted to Rational unless the evaluate flag is False: >>> Point3D(0.5, 0.25, 2) Point3D(1/2, 1/4, 2) >>> Point3D(0.5, 0.25, 3, evaluate=False) Point3D(0.5, 0.25, 3) """ _ambient_dimension = 3 def __new__(cls, *args, _nocheck=False, **kwargs): if not _nocheck: kwargs['dim'] = 3 args = Point(*args, **kwargs) return GeometryEntity.__new__(cls, *args) def __contains__(self, item): return item == self @staticmethod def are_collinear(*points): """Is a sequence of points collinear? Test whether or not a set of points are collinear. Returns True if the set of points are collinear, or False otherwise. Parameters ========== points : sequence of Point Returns ======= are_collinear : boolean See Also ======== sympy.geometry.line.Line3D Examples ======== >>> from sympy import Point3D >>> from sympy.abc import x >>> p1, p2 = Point3D(0, 0, 0), Point3D(1, 1, 1) >>> p3, p4, p5 = Point3D(2, 2, 2), Point3D(x, x, x), Point3D(1, 2, 6) >>> Point3D.are_collinear(p1, p2, p3, p4) True >>> Point3D.are_collinear(p1, p2, p3, p5) False """ return Point.is_collinear(*points) def direction_cosine(self, point): """ Gives the direction cosine between 2 points Parameters ========== p : Point3D Returns ======= list Examples ======== >>> from sympy import Point3D >>> p1 = Point3D(1, 2, 3) >>> p1.direction_cosine(Point3D(2, 3, 5)) [sqrt(6)/6, sqrt(6)/6, sqrt(6)/3] """ a = self.direction_ratio(point) b = sqrt(Add(*(i**2 for i in a))) return [(point.x - self.x) / b,(point.y - self.y) / b, (point.z - self.z) / b] def direction_ratio(self, point): """ Gives the direction ratio between 2 points Parameters ========== p : Point3D Returns ======= list Examples ======== >>> from sympy import Point3D >>> p1 = Point3D(1, 2, 3) >>> p1.direction_ratio(Point3D(2, 3, 5)) [1, 1, 2] """ return [(point.x - self.x),(point.y - self.y),(point.z - self.z)] def intersection(self, other): """The intersection between this point and another GeometryEntity. Parameters ========== other : GeometryEntity or sequence of coordinates Returns ======= intersection : list of Points Notes ===== The return value will either be an empty list if there is no intersection, otherwise it will contain this point. Examples ======== >>> from sympy import Point3D >>> p1, p2, p3 = Point3D(0, 0, 0), Point3D(1, 1, 1), Point3D(0, 0, 0) >>> p1.intersection(p2) [] >>> p1.intersection(p3) [Point3D(0, 0, 0)] """ if not isinstance(other, GeometryEntity): other = Point(other, dim=3) if isinstance(other, Point3D): if self == other: return [self] return [] return other.intersection(self) def scale(self, x=1, y=1, z=1, pt=None): """Scale the coordinates of the Point by multiplying by ``x`` and ``y`` after subtracting ``pt`` -- default is (0, 0) -- and then adding ``pt`` back again (i.e. ``pt`` is the point of reference for the scaling). See Also ======== translate Examples ======== >>> from sympy import Point3D >>> t = Point3D(1, 1, 1) >>> t.scale(2) Point3D(2, 1, 1) >>> t.scale(2, 2) Point3D(2, 2, 1) """ if pt: pt = Point3D(pt) return self.translate(*(-pt).args).scale(x, y, z).translate(*pt.args) return Point3D(self.x*x, self.y*y, self.z*z) def transform(self, matrix): """Return the point after applying the transformation described by the 4x4 Matrix, ``matrix``. See Also ======== sympy.geometry.point.Point3D.scale sympy.geometry.point.Point3D.translate """ if not (matrix.is_Matrix and matrix.shape == (4, 4)): raise ValueError("matrix must be a 4x4 matrix") from sympy.matrices.expressions import Transpose x, y, z = self.args m = Transpose(matrix) return Point3D(*(Matrix(1, 4, [x, y, z, 1])*m).tolist()[0][:3]) def translate(self, x=0, y=0, z=0): """Shift the Point by adding x and y to the coordinates of the Point. See Also ======== scale Examples ======== >>> from sympy import Point3D >>> t = Point3D(0, 1, 1) >>> t.translate(2) Point3D(2, 1, 1) >>> t.translate(2, 2) Point3D(2, 3, 1) >>> t + Point3D(2, 2, 2) Point3D(2, 3, 3) """ return Point3D(self.x + x, self.y + y, self.z + z) @property def coordinates(self): """ Returns the three coordinates of the Point. Examples ======== >>> from sympy import Point3D >>> p = Point3D(0, 1, 2) >>> p.coordinates (0, 1, 2) """ return self.args @property def x(self): """ Returns the X coordinate of the Point. Examples ======== >>> from sympy import Point3D >>> p = Point3D(0, 1, 3) >>> p.x 0 """ return self.args[0] @property def y(self): """ Returns the Y coordinate of the Point. Examples ======== >>> from sympy import Point3D >>> p = Point3D(0, 1, 2) >>> p.y 1 """ return self.args[1] @property def z(self): """ Returns the Z coordinate of the Point. Examples ======== >>> from sympy import Point3D >>> p = Point3D(0, 1, 1) >>> p.z 1 """ return self.args[2] sympy-sympy-1.9/sympy/geometry/polygon.py000066400000000000000000002375521412543434000210160ustar00rootroot00000000000000from sympy.core import Expr, S, Symbol, oo, pi, sympify from sympy.core.compatibility import as_int, ordered from sympy.core.symbol import _symbol, Dummy, symbols from sympy.functions.elementary.complexes import sign from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import cos, sin, tan from sympy.geometry.exceptions import GeometryError from sympy.logic import And from sympy.matrices import Matrix from sympy.simplify import simplify from sympy.utilities import default_sort_key from sympy.utilities.iterables import has_dups, has_variety, uniq, rotate_left, least_rotation from sympy.utilities.misc import func_name from .entity import GeometryEntity, GeometrySet from .point import Point from .ellipse import Circle from .line import Line, Segment, Ray import warnings class Polygon(GeometrySet): """A two-dimensional polygon. A simple polygon in space. Can be constructed from a sequence of points or from a center, radius, number of sides and rotation angle. Parameters ========== vertices : sequence of Points Optional parameters ========== n : If > 0, an n-sided RegularPolygon is created. See below. Default value is 0. Attributes ========== area angles perimeter vertices centroid sides Raises ====== GeometryError If all parameters are not Points. See Also ======== sympy.geometry.point.Point, sympy.geometry.line.Segment, Triangle Notes ===== Polygons are treated as closed paths rather than 2D areas so some calculations can be be negative or positive (e.g., area) based on the orientation of the points. Any consecutive identical points are reduced to a single point and any points collinear and between two points will be removed unless they are needed to define an explicit intersection (see examples). A Triangle, Segment or Point will be returned when there are 3 or fewer points provided. Examples ======== >>> from sympy import Polygon, pi >>> p1, p2, p3, p4, p5 = [(0, 0), (1, 0), (5, 1), (0, 1), (3, 0)] >>> Polygon(p1, p2, p3, p4) Polygon(Point2D(0, 0), Point2D(1, 0), Point2D(5, 1), Point2D(0, 1)) >>> Polygon(p1, p2) Segment2D(Point2D(0, 0), Point2D(1, 0)) >>> Polygon(p1, p2, p5) Segment2D(Point2D(0, 0), Point2D(3, 0)) The area of a polygon is calculated as positive when vertices are traversed in a ccw direction. When the sides of a polygon cross the area will have positive and negative contributions. The following defines a Z shape where the bottom right connects back to the top left. >>> Polygon((0, 2), (2, 2), (0, 0), (2, 0)).area 0 When the the keyword `n` is used to define the number of sides of the Polygon then a RegularPolygon is created and the other arguments are interpreted as center, radius and rotation. The unrotated RegularPolygon will always have a vertex at Point(r, 0) where `r` is the radius of the circle that circumscribes the RegularPolygon. Its method `spin` can be used to increment that angle. >>> p = Polygon((0,0), 1, n=3) >>> p RegularPolygon(Point2D(0, 0), 1, 3, 0) >>> p.vertices[0] Point2D(1, 0) >>> p.args[0] Point2D(0, 0) >>> p.spin(pi/2) >>> p.vertices[0] Point2D(0, 1) """ def __new__(cls, *args, n = 0, **kwargs): if n: args = list(args) # return a virtual polygon with n sides if len(args) == 2: # center, radius args.append(n) elif len(args) == 3: # center, radius, rotation args.insert(2, n) return RegularPolygon(*args, **kwargs) vertices = [Point(a, dim=2, **kwargs) for a in args] # remove consecutive duplicates nodup = [] for p in vertices: if nodup and p == nodup[-1]: continue nodup.append(p) if len(nodup) > 1 and nodup[-1] == nodup[0]: nodup.pop() # last point was same as first # remove collinear points i = -3 while i < len(nodup) - 3 and len(nodup) > 2: a, b, c = nodup[i], nodup[i + 1], nodup[i + 2] if Point.is_collinear(a, b, c): nodup.pop(i + 1) if a == c: nodup.pop(i) else: i += 1 vertices = list(nodup) if len(vertices) > 3: return GeometryEntity.__new__(cls, *vertices, **kwargs) elif len(vertices) == 3: return Triangle(*vertices, **kwargs) elif len(vertices) == 2: return Segment(*vertices, **kwargs) else: return Point(*vertices, **kwargs) @property def area(self): """ The area of the polygon. Notes ===== The area calculation can be positive or negative based on the orientation of the points. If any side of the polygon crosses any other side, there will be areas having opposite signs. See Also ======== sympy.geometry.ellipse.Ellipse.area Examples ======== >>> from sympy import Point, Polygon >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly = Polygon(p1, p2, p3, p4) >>> poly.area 3 In the Z shaped polygon (with the lower right connecting back to the upper left) the areas cancel out: >>> Z = Polygon((0, 1), (1, 1), (0, 0), (1, 0)) >>> Z.area 0 In the M shaped polygon, areas do not cancel because no side crosses any other (though there is a point of contact). >>> M = Polygon((0, 0), (0, 1), (2, 0), (3, 1), (3, 0)) >>> M.area -3/2 """ area = 0 args = self.args for i in range(len(args)): x1, y1 = args[i - 1].args x2, y2 = args[i].args area += x1*y2 - x2*y1 return simplify(area) / 2 @staticmethod def _isright(a, b, c): """Return True/False for cw/ccw orientation. Examples ======== >>> from sympy import Point, Polygon >>> a, b, c = [Point(i) for i in [(0, 0), (1, 1), (1, 0)]] >>> Polygon._isright(a, b, c) True >>> Polygon._isright(a, c, b) False """ ba = b - a ca = c - a t_area = simplify(ba.x*ca.y - ca.x*ba.y) res = t_area.is_nonpositive if res is None: raise ValueError("Can't determine orientation") return res @property def angles(self): """The internal angle at each vertex. Returns ======= angles : dict A dictionary where each key is a vertex and each value is the internal angle at that vertex. The vertices are represented as Points. See Also ======== sympy.geometry.point.Point, sympy.geometry.line.LinearEntity.angle_between Examples ======== >>> from sympy import Point, Polygon >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly = Polygon(p1, p2, p3, p4) >>> poly.angles[p1] pi/2 >>> poly.angles[p2] acos(-4*sqrt(17)/17) """ # Determine orientation of points args = self.vertices cw = self._isright(args[-1], args[0], args[1]) ret = {} for i in range(len(args)): a, b, c = args[i - 2], args[i - 1], args[i] ang = Ray(b, a).angle_between(Ray(b, c)) if cw ^ self._isright(a, b, c): ret[b] = 2*S.Pi - ang else: ret[b] = ang return ret @property def ambient_dimension(self): return self.vertices[0].ambient_dimension @property def perimeter(self): """The perimeter of the polygon. Returns ======= perimeter : number or Basic instance See Also ======== sympy.geometry.line.Segment.length Examples ======== >>> from sympy import Point, Polygon >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly = Polygon(p1, p2, p3, p4) >>> poly.perimeter sqrt(17) + 7 """ p = 0 args = self.vertices for i in range(len(args)): p += args[i - 1].distance(args[i]) return simplify(p) @property def vertices(self): """The vertices of the polygon. Returns ======= vertices : list of Points Notes ===== When iterating over the vertices, it is more efficient to index self rather than to request the vertices and index them. Only use the vertices when you want to process all of them at once. This is even more important with RegularPolygons that calculate each vertex. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Point, Polygon >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly = Polygon(p1, p2, p3, p4) >>> poly.vertices [Point2D(0, 0), Point2D(1, 0), Point2D(5, 1), Point2D(0, 1)] >>> poly.vertices[0] Point2D(0, 0) """ return list(self.args) @property def centroid(self): """The centroid of the polygon. Returns ======= centroid : Point See Also ======== sympy.geometry.point.Point, sympy.geometry.util.centroid Examples ======== >>> from sympy import Point, Polygon >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly = Polygon(p1, p2, p3, p4) >>> poly.centroid Point2D(31/18, 11/18) """ A = 1/(6*self.area) cx, cy = 0, 0 args = self.args for i in range(len(args)): x1, y1 = args[i - 1].args x2, y2 = args[i].args v = x1*y2 - x2*y1 cx += v*(x1 + x2) cy += v*(y1 + y2) return Point(simplify(A*cx), simplify(A*cy)) def second_moment_of_area(self, point=None): """Returns the second moment and product moment of area of a two dimensional polygon. Parameters ========== point : Point, two-tuple of sympifyable objects, or None(default=None) point is the point about which second moment of area is to be found. If "point=None" it will be calculated about the axis passing through the centroid of the polygon. Returns ======= I_xx, I_yy, I_xy : number or sympy expression I_xx, I_yy are second moment of area of a two dimensional polygon. I_xy is product moment of area of a two dimensional polygon. Examples ======== >>> from sympy import Polygon, symbols >>> a, b = symbols('a, b') >>> p1, p2, p3, p4, p5 = [(0, 0), (a, 0), (a, b), (0, b), (a/3, b/3)] >>> rectangle = Polygon(p1, p2, p3, p4) >>> rectangle.second_moment_of_area() (a*b**3/12, a**3*b/12, 0) >>> rectangle.second_moment_of_area(p5) (a*b**3/9, a**3*b/9, a**2*b**2/36) References ========== https://en.wikipedia.org/wiki/Second_moment_of_area """ I_xx, I_yy, I_xy = 0, 0, 0 args = self.vertices for i in range(len(args)): x1, y1 = args[i-1].args x2, y2 = args[i].args v = x1*y2 - x2*y1 I_xx += (y1**2 + y1*y2 + y2**2)*v I_yy += (x1**2 + x1*x2 + x2**2)*v I_xy += (x1*y2 + 2*x1*y1 + 2*x2*y2 + x2*y1)*v A = self.area c_x = self.centroid[0] c_y = self.centroid[1] # parallel axis theorem I_xx_c = (I_xx/12) - (A*(c_y**2)) I_yy_c = (I_yy/12) - (A*(c_x**2)) I_xy_c = (I_xy/24) - (A*(c_x*c_y)) if point is None: return I_xx_c, I_yy_c, I_xy_c I_xx = (I_xx_c + A*((point[1]-c_y)**2)) I_yy = (I_yy_c + A*((point[0]-c_x)**2)) I_xy = (I_xy_c + A*((point[0]-c_x)*(point[1]-c_y))) return I_xx, I_yy, I_xy def first_moment_of_area(self, point=None): """ Returns the first moment of area of a two-dimensional polygon with respect to a certain point of interest. First moment of area is a measure of the distribution of the area of a polygon in relation to an axis. The first moment of area of the entire polygon about its own centroid is always zero. Therefore, here it is calculated for an area, above or below a certain point of interest, that makes up a smaller portion of the polygon. This area is bounded by the point of interest and the extreme end (top or bottom) of the polygon. The first moment for this area is is then determined about the centroidal axis of the initial polygon. References ========== https://skyciv.com/docs/tutorials/section-tutorials/calculating-the-statical-or-first-moment-of-area-of-beam-sections/?cc=BMD https://mechanicalc.com/reference/cross-sections Parameters ========== point: Point, two-tuple of sympifyable objects, or None (default=None) point is the point above or below which the area of interest lies If ``point=None`` then the centroid acts as the point of interest. Returns ======= Q_x, Q_y: number or sympy expressions Q_x is the first moment of area about the x-axis Q_y is the first moment of area about the y-axis A negative sign indicates that the section modulus is determined for a section below (or left of) the centroidal axis Examples ======== >>> from sympy import Point, Polygon >>> a, b = 50, 10 >>> p1, p2, p3, p4 = [(0, b), (0, 0), (a, 0), (a, b)] >>> p = Polygon(p1, p2, p3, p4) >>> p.first_moment_of_area() (625, 3125) >>> p.first_moment_of_area(point=Point(30, 7)) (525, 3000) """ if point: xc, yc = self.centroid else: point = self.centroid xc, yc = point h_line = Line(point, slope=0) v_line = Line(point, slope=S.Infinity) h_poly = self.cut_section(h_line) v_poly = self.cut_section(v_line) poly_1 = h_poly[0] if h_poly[0].area <= h_poly[1].area else h_poly[1] poly_2 = v_poly[0] if v_poly[0].area <= v_poly[1].area else v_poly[1] Q_x = (poly_1.centroid.y - yc)*poly_1.area Q_y = (poly_2.centroid.x - xc)*poly_2.area return Q_x, Q_y def polar_second_moment_of_area(self): """Returns the polar modulus of a two-dimensional polygon It is a constituent of the second moment of area, linked through the perpendicular axis theorem. While the planar second moment of area describes an object's resistance to deflection (bending) when subjected to a force applied to a plane parallel to the central axis, the polar second moment of area describes an object's resistance to deflection when subjected to a moment applied in a plane perpendicular to the object's central axis (i.e. parallel to the cross-section) References ========== https://en.wikipedia.org/wiki/Polar_moment_of_inertia Examples ======== >>> from sympy import Polygon, symbols >>> a, b = symbols('a, b') >>> rectangle = Polygon((0, 0), (a, 0), (a, b), (0, b)) >>> rectangle.polar_second_moment_of_area() a**3*b/12 + a*b**3/12 """ second_moment = self.second_moment_of_area() return second_moment[0] + second_moment[1] def section_modulus(self, point=None): """Returns a tuple with the section modulus of a two-dimensional polygon. Section modulus is a geometric property of a polygon defined as the ratio of second moment of area to the distance of the extreme end of the polygon from the centroidal axis. References ========== https://en.wikipedia.org/wiki/Section_modulus Parameters ========== point : Point, two-tuple of sympifyable objects, or None(default=None) point is the point at which section modulus is to be found. If "point=None" it will be calculated for the point farthest from the centroidal axis of the polygon. Returns ======= S_x, S_y: numbers or SymPy expressions S_x is the section modulus with respect to the x-axis S_y is the section modulus with respect to the y-axis A negative sign indicates that the section modulus is determined for a point below the centroidal axis Examples ======== >>> from sympy import symbols, Polygon, Point >>> a, b = symbols('a, b', positive=True) >>> rectangle = Polygon((0, 0), (a, 0), (a, b), (0, b)) >>> rectangle.section_modulus() (a*b**2/6, a**2*b/6) >>> rectangle.section_modulus(Point(a/4, b/4)) (-a*b**2/3, -a**2*b/3) """ x_c, y_c = self.centroid if point is None: # taking x and y as maximum distances from centroid x_min, y_min, x_max, y_max = self.bounds y = max(y_c - y_min, y_max - y_c) x = max(x_c - x_min, x_max - x_c) else: # taking x and y as distances of the given point from the centroid y = point.y - y_c x = point.x - x_c second_moment= self.second_moment_of_area() S_x = second_moment[0]/y S_y = second_moment[1]/x return S_x, S_y @property def sides(self): """The directed line segments that form the sides of the polygon. Returns ======= sides : list of sides Each side is a directed Segment. See Also ======== sympy.geometry.point.Point, sympy.geometry.line.Segment Examples ======== >>> from sympy import Point, Polygon >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly = Polygon(p1, p2, p3, p4) >>> poly.sides [Segment2D(Point2D(0, 0), Point2D(1, 0)), Segment2D(Point2D(1, 0), Point2D(5, 1)), Segment2D(Point2D(5, 1), Point2D(0, 1)), Segment2D(Point2D(0, 1), Point2D(0, 0))] """ res = [] args = self.vertices for i in range(-len(args), 0): res.append(Segment(args[i], args[i + 1])) return res @property def bounds(self): """Return a tuple (xmin, ymin, xmax, ymax) representing the bounding rectangle for the geometric figure. """ verts = self.vertices xs = [p.x for p in verts] ys = [p.y for p in verts] return (min(xs), min(ys), max(xs), max(ys)) def is_convex(self): """Is the polygon convex? A polygon is convex if all its interior angles are less than 180 degrees and there are no intersections between sides. Returns ======= is_convex : boolean True if this polygon is convex, False otherwise. See Also ======== sympy.geometry.util.convex_hull Examples ======== >>> from sympy import Point, Polygon >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly = Polygon(p1, p2, p3, p4) >>> poly.is_convex() True """ # Determine orientation of points args = self.vertices cw = self._isright(args[-2], args[-1], args[0]) for i in range(1, len(args)): if cw ^ self._isright(args[i - 2], args[i - 1], args[i]): return False # check for intersecting sides sides = self.sides for i, si in enumerate(sides): pts = si.args # exclude the sides connected to si for j in range(1 if i == len(sides) - 1 else 0, i - 1): sj = sides[j] if sj.p1 not in pts and sj.p2 not in pts: hit = si.intersection(sj) if hit: return False return True def encloses_point(self, p): """ Return True if p is enclosed by (is inside of) self. Notes ===== Being on the border of self is considered False. Parameters ========== p : Point Returns ======= encloses_point : True, False or None See Also ======== sympy.geometry.point.Point, sympy.geometry.ellipse.Ellipse.encloses_point Examples ======== >>> from sympy import Polygon, Point >>> p = Polygon((0, 0), (4, 0), (4, 4)) >>> p.encloses_point(Point(2, 1)) True >>> p.encloses_point(Point(2, 2)) False >>> p.encloses_point(Point(5, 5)) False References ========== [1] http://paulbourke.net/geometry/polygonmesh/#insidepoly """ p = Point(p, dim=2) if p in self.vertices or any(p in s for s in self.sides): return False # move to p, checking that the result is numeric lit = [] for v in self.vertices: lit.append(v - p) # the difference is simplified if lit[-1].free_symbols: return None poly = Polygon(*lit) # polygon closure is assumed in the following test but Polygon removes duplicate pts so # the last point has to be added so all sides are computed. Using Polygon.sides is # not good since Segments are unordered. args = poly.args indices = list(range(-len(args), 1)) if poly.is_convex(): orientation = None for i in indices: a = args[i] b = args[i + 1] test = ((-a.y)*(b.x - a.x) - (-a.x)*(b.y - a.y)).is_negative if orientation is None: orientation = test elif test is not orientation: return False return True hit_odd = False p1x, p1y = args[0].args for i in indices[1:]: p2x, p2y = args[i].args if 0 > min(p1y, p2y): if 0 <= max(p1y, p2y): if 0 <= max(p1x, p2x): if p1y != p2y: xinters = (-p1y)*(p2x - p1x)/(p2y - p1y) + p1x if p1x == p2x or 0 <= xinters: hit_odd = not hit_odd p1x, p1y = p2x, p2y return hit_odd def arbitrary_point(self, parameter='t'): """A parameterized point on the polygon. The parameter, varying from 0 to 1, assigns points to the position on the perimeter that is that fraction of the total perimeter. So the point evaluated at t=1/2 would return the point from the first vertex that is 1/2 way around the polygon. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= arbitrary_point : Point Raises ====== ValueError When `parameter` already appears in the Polygon's definition. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy import Polygon, Symbol >>> t = Symbol('t', real=True) >>> tri = Polygon((0, 0), (1, 0), (1, 1)) >>> p = tri.arbitrary_point('t') >>> perimeter = tri.perimeter >>> s1, s2 = [s.length for s in tri.sides[:2]] >>> p.subs(t, (s1 + s2/2)/perimeter) Point2D(1, 1/2) """ t = _symbol(parameter, real=True) if t.name in (f.name for f in self.free_symbols): raise ValueError('Symbol %s already appears in object and cannot be used as a parameter.' % t.name) sides = [] perimeter = self.perimeter perim_fraction_start = 0 for s in self.sides: side_perim_fraction = s.length/perimeter perim_fraction_end = perim_fraction_start + side_perim_fraction pt = s.arbitrary_point(parameter).subs( t, (t - perim_fraction_start)/side_perim_fraction) sides.append( (pt, (And(perim_fraction_start <= t, t < perim_fraction_end)))) perim_fraction_start = perim_fraction_end return Piecewise(*sides) def parameter_value(self, other, t): from sympy.solvers.solvers import solve if not isinstance(other,GeometryEntity): other = Point(other, dim=self.ambient_dimension) if not isinstance(other,Point): raise ValueError("other must be a point") if other.free_symbols: raise NotImplementedError('non-numeric coordinates') unknown = False T = Dummy('t', real=True) p = self.arbitrary_point(T) for pt, cond in p.args: sol = solve(pt - other, T, dict=True) if not sol: continue value = sol[0][T] if simplify(cond.subs(T, value)) == True: return {t: value} unknown = True if unknown: raise ValueError("Given point may not be on %s" % func_name(self)) raise ValueError("Given point is not on %s" % func_name(self)) def plot_interval(self, parameter='t'): """The plot interval for the default geometric plot of the polygon. Parameters ========== parameter : str, optional Default value is 't'. Returns ======= plot_interval : list (plot interval) [parameter, lower_bound, upper_bound] Examples ======== >>> from sympy import Polygon >>> p = Polygon((0, 0), (1, 0), (1, 1)) >>> p.plot_interval() [t, 0, 1] """ t = Symbol(parameter, real=True) return [t, 0, 1] def intersection(self, o): """The intersection of polygon and geometry entity. The intersection may be empty and can contain individual Points and complete Line Segments. Parameters ========== other: GeometryEntity Returns ======= intersection : list The list of Segments and Points See Also ======== sympy.geometry.point.Point, sympy.geometry.line.Segment Examples ======== >>> from sympy import Point, Polygon, Line >>> p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) >>> poly1 = Polygon(p1, p2, p3, p4) >>> p5, p6, p7 = map(Point, [(3, 2), (1, -1), (0, 2)]) >>> poly2 = Polygon(p5, p6, p7) >>> poly1.intersection(poly2) [Point2D(1/3, 1), Point2D(2/3, 0), Point2D(9/5, 1/5), Point2D(7/3, 1)] >>> poly1.intersection(Line(p1, p2)) [Segment2D(Point2D(0, 0), Point2D(1, 0))] >>> poly1.intersection(p1) [Point2D(0, 0)] """ intersection_result = [] k = o.sides if isinstance(o, Polygon) else [o] for side in self.sides: for side1 in k: intersection_result.extend(side.intersection(side1)) intersection_result = list(uniq(intersection_result)) points = [entity for entity in intersection_result if isinstance(entity, Point)] segments = [entity for entity in intersection_result if isinstance(entity, Segment)] if points and segments: points_in_segments = list(uniq([point for point in points for segment in segments if point in segment])) if points_in_segments: for i in points_in_segments: points.remove(i) return list(ordered(segments + points)) else: return list(ordered(intersection_result)) def cut_section(self, line): """ Returns a tuple of two polygon segments that lie above and below the intersecting line respectively. Parameters ========== line: Line object of geometry module line which cuts the Polygon. The part of the Polygon that lies above and below this line is returned. Returns ======= upper_polygon, lower_polygon: Polygon objects or None upper_polygon is the polygon that lies above the given line. lower_polygon is the polygon that lies below the given line. upper_polygon and lower polygon are ``None`` when no polygon exists above the line or below the line. Raises ====== ValueError: When the line does not intersect the polygon References ========== https://github.com/sympy/sympy/wiki/A-method-to-return-a-cut-section-of-any-polygon-geometry Examples ======== >>> from sympy import Polygon, Line >>> a, b = 20, 10 >>> p1, p2, p3, p4 = [(0, b), (0, 0), (a, 0), (a, b)] >>> rectangle = Polygon(p1, p2, p3, p4) >>> t = rectangle.cut_section(Line((0, 5), slope=0)) >>> t (Polygon(Point2D(0, 10), Point2D(0, 5), Point2D(20, 5), Point2D(20, 10)), Polygon(Point2D(0, 5), Point2D(0, 0), Point2D(20, 0), Point2D(20, 5))) >>> upper_segment, lower_segment = t >>> upper_segment.area 100 >>> upper_segment.centroid Point2D(10, 15/2) >>> lower_segment.centroid Point2D(10, 5/2) """ intersection_points = self.intersection(line) if not intersection_points: raise ValueError("This line does not intersect the polygon") points = list(self.vertices) points.append(points[0]) x, y = symbols('x, y', real=True, cls=Dummy) eq = line.equation(x, y) # considering equation of line to be `ax +by + c` a = eq.coeff(x) b = eq.coeff(y) upper_vertices = [] lower_vertices = [] # prev is true when previous point is above the line prev = True prev_point = None for point in points: # when coefficient of y is 0, right side of the line is # considered compare = eq.subs({x: point.x, y: point.y})/b if b \ else eq.subs(x, point.x)/a # if point lies above line if compare > 0: if not prev: # if previous point lies below the line, the intersection # point of the polygon egde and the line has to be included edge = Line(point, prev_point) new_point = edge.intersection(line) upper_vertices.append(new_point[0]) lower_vertices.append(new_point[0]) upper_vertices.append(point) prev = True else: if prev and prev_point: edge = Line(point, prev_point) new_point = edge.intersection(line) upper_vertices.append(new_point[0]) lower_vertices.append(new_point[0]) lower_vertices.append(point) prev = False prev_point = point upper_polygon, lower_polygon = None, None if upper_vertices and isinstance(Polygon(*upper_vertices), Polygon): upper_polygon = Polygon(*upper_vertices) if lower_vertices and isinstance(Polygon(*lower_vertices), Polygon): lower_polygon = Polygon(*lower_vertices) return upper_polygon, lower_polygon def distance(self, o): """ Returns the shortest distance between self and o. If o is a point, then self does not need to be convex. If o is another polygon self and o must be convex. Examples ======== >>> from sympy import Point, Polygon, RegularPolygon >>> p1, p2 = map(Point, [(0, 0), (7, 5)]) >>> poly = Polygon(*RegularPolygon(p1, 1, 3).vertices) >>> poly.distance(p2) sqrt(61) """ if isinstance(o, Point): dist = oo for side in self.sides: current = side.distance(o) if current == 0: return S.Zero elif current < dist: dist = current return dist elif isinstance(o, Polygon) and self.is_convex() and o.is_convex(): return self._do_poly_distance(o) raise NotImplementedError() def _do_poly_distance(self, e2): """ Calculates the least distance between the exteriors of two convex polygons e1 and e2. Does not check for the convexity of the polygons as this is checked by Polygon.distance. Notes ===== - Prints a warning if the two polygons possibly intersect as the return value will not be valid in such a case. For a more through test of intersection use intersection(). See Also ======== sympy.geometry.point.Point.distance Examples ======== >>> from sympy.geometry import Point, Polygon >>> square = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) >>> triangle = Polygon(Point(1, 2), Point(2, 2), Point(2, 1)) >>> square._do_poly_distance(triangle) sqrt(2)/2 Description of method used ========================== Method: [1] http://cgm.cs.mcgill.ca/~orm/mind2p.html Uses rotating calipers: [2] https://en.wikipedia.org/wiki/Rotating_calipers and antipodal points: [3] https://en.wikipedia.org/wiki/Antipodal_point """ e1 = self '''Tests for a possible intersection between the polygons and outputs a warning''' e1_center = e1.centroid e2_center = e2.centroid e1_max_radius = S.Zero e2_max_radius = S.Zero for vertex in e1.vertices: r = Point.distance(e1_center, vertex) if e1_max_radius < r: e1_max_radius = r for vertex in e2.vertices: r = Point.distance(e2_center, vertex) if e2_max_radius < r: e2_max_radius = r center_dist = Point.distance(e1_center, e2_center) if center_dist <= e1_max_radius + e2_max_radius: warnings.warn("Polygons may intersect producing erroneous output") ''' Find the upper rightmost vertex of e1 and the lowest leftmost vertex of e2 ''' e1_ymax = Point(0, -oo) e2_ymin = Point(0, oo) for vertex in e1.vertices: if vertex.y > e1_ymax.y or (vertex.y == e1_ymax.y and vertex.x > e1_ymax.x): e1_ymax = vertex for vertex in e2.vertices: if vertex.y < e2_ymin.y or (vertex.y == e2_ymin.y and vertex.x < e2_ymin.x): e2_ymin = vertex min_dist = Point.distance(e1_ymax, e2_ymin) ''' Produce a dictionary with vertices of e1 as the keys and, for each vertex, the points to which the vertex is connected as its value. The same is then done for e2. ''' e1_connections = {} e2_connections = {} for side in e1.sides: if side.p1 in e1_connections: e1_connections[side.p1].append(side.p2) else: e1_connections[side.p1] = [side.p2] if side.p2 in e1_connections: e1_connections[side.p2].append(side.p1) else: e1_connections[side.p2] = [side.p1] for side in e2.sides: if side.p1 in e2_connections: e2_connections[side.p1].append(side.p2) else: e2_connections[side.p1] = [side.p2] if side.p2 in e2_connections: e2_connections[side.p2].append(side.p1) else: e2_connections[side.p2] = [side.p1] e1_current = e1_ymax e2_current = e2_ymin support_line = Line(Point(S.Zero, S.Zero), Point(S.One, S.Zero)) ''' Determine which point in e1 and e2 will be selected after e2_ymin and e1_ymax, this information combined with the above produced dictionaries determines the path that will be taken around the polygons ''' point1 = e1_connections[e1_ymax][0] point2 = e1_connections[e1_ymax][1] angle1 = support_line.angle_between(Line(e1_ymax, point1)) angle2 = support_line.angle_between(Line(e1_ymax, point2)) if angle1 < angle2: e1_next = point1 elif angle2 < angle1: e1_next = point2 elif Point.distance(e1_ymax, point1) > Point.distance(e1_ymax, point2): e1_next = point2 else: e1_next = point1 point1 = e2_connections[e2_ymin][0] point2 = e2_connections[e2_ymin][1] angle1 = support_line.angle_between(Line(e2_ymin, point1)) angle2 = support_line.angle_between(Line(e2_ymin, point2)) if angle1 > angle2: e2_next = point1 elif angle2 > angle1: e2_next = point2 elif Point.distance(e2_ymin, point1) > Point.distance(e2_ymin, point2): e2_next = point2 else: e2_next = point1 ''' Loop which determines the distance between anti-podal pairs and updates the minimum distance accordingly. It repeats until it reaches the starting position. ''' while True: e1_angle = support_line.angle_between(Line(e1_current, e1_next)) e2_angle = pi - support_line.angle_between(Line( e2_current, e2_next)) if (e1_angle < e2_angle) is True: support_line = Line(e1_current, e1_next) e1_segment = Segment(e1_current, e1_next) min_dist_current = e1_segment.distance(e2_current) if min_dist_current.evalf() < min_dist.evalf(): min_dist = min_dist_current if e1_connections[e1_next][0] != e1_current: e1_current = e1_next e1_next = e1_connections[e1_next][0] else: e1_current = e1_next e1_next = e1_connections[e1_next][1] elif (e1_angle > e2_angle) is True: support_line = Line(e2_next, e2_current) e2_segment = Segment(e2_current, e2_next) min_dist_current = e2_segment.distance(e1_current) if min_dist_current.evalf() < min_dist.evalf(): min_dist = min_dist_current if e2_connections[e2_next][0] != e2_current: e2_current = e2_next e2_next = e2_connections[e2_next][0] else: e2_current = e2_next e2_next = e2_connections[e2_next][1] else: support_line = Line(e1_current, e1_next) e1_segment = Segment(e1_current, e1_next) e2_segment = Segment(e2_current, e2_next) min1 = e1_segment.distance(e2_next) min2 = e2_segment.distance(e1_next) min_dist_current = min(min1, min2) if min_dist_current.evalf() < min_dist.evalf(): min_dist = min_dist_current if e1_connections[e1_next][0] != e1_current: e1_current = e1_next e1_next = e1_connections[e1_next][0] else: e1_current = e1_next e1_next = e1_connections[e1_next][1] if e2_connections[e2_next][0] != e2_current: e2_current = e2_next e2_next = e2_connections[e2_next][0] else: e2_current = e2_next e2_next = e2_connections[e2_next][1] if e1_current == e1_ymax and e2_current == e2_ymin: break return min_dist def _svg(self, scale_factor=1., fill_color="#66cc99"): """Returns SVG path element for the Polygon. Parameters ========== scale_factor : float Multiplication factor for the SVG stroke-width. Default is 1. fill_color : str, optional Hex string for fill color. Default is "#66cc99". """ from sympy.core.evalf import N verts = map(N, self.vertices) coords = ["{},{}".format(p.x, p.y) for p in verts] path = "M {} L {} z".format(coords[0], " L ".join(coords[1:])) return ( '' ).format(2. * scale_factor, path, fill_color) def _hashable_content(self): D = {} def ref_list(point_list): kee = {} for i, p in enumerate(ordered(set(point_list))): kee[p] = i D[i] = p return [kee[p] for p in point_list] S1 = ref_list(self.args) r_nor = rotate_left(S1, least_rotation(S1)) S2 = ref_list(list(reversed(self.args))) r_rev = rotate_left(S2, least_rotation(S2)) if r_nor < r_rev: r = r_nor else: r = r_rev canonical_args = [ D[order] for order in r ] return tuple(canonical_args) def __contains__(self, o): """ Return True if o is contained within the boundary lines of self.altitudes Parameters ========== other : GeometryEntity Returns ======= contained in : bool The points (and sides, if applicable) are contained in self. See Also ======== sympy.geometry.entity.GeometryEntity.encloses Examples ======== >>> from sympy import Line, Segment, Point >>> p = Point(0, 0) >>> q = Point(1, 1) >>> s = Segment(p, q*2) >>> l = Line(p, q) >>> p in q False >>> p in s True >>> q*3 in s False >>> s in l True """ if isinstance(o, Polygon): return self == o elif isinstance(o, Segment): return any(o in s for s in self.sides) elif isinstance(o, Point): if o in self.vertices: return True for side in self.sides: if o in side: return True return False def bisectors(p, prec=None): """Returns angle bisectors of a polygon. If prec is given then approximate the point defining the ray to that precision. The distance between the points defining the bisector ray is 1. Examples ======== >>> from sympy import Polygon, Point >>> p = Polygon(Point(0, 0), Point(2, 0), Point(1, 1), Point(0, 3)) >>> p.bisectors(2) {Point2D(0, 0): Ray2D(Point2D(0, 0), Point2D(0.71, 0.71)), Point2D(0, 3): Ray2D(Point2D(0, 3), Point2D(0.23, 2.0)), Point2D(1, 1): Ray2D(Point2D(1, 1), Point2D(0.19, 0.42)), Point2D(2, 0): Ray2D(Point2D(2, 0), Point2D(1.1, 0.38))} """ b = {} pts = list(p.args) pts.append(pts[0]) # close it cw = Polygon._isright(*pts[:3]) if cw: pts = list(reversed(pts)) for v, a in p.angles.items(): i = pts.index(v) p1, p2 = Point._normalize_dimension(pts[i], pts[i + 1]) ray = Ray(p1, p2).rotate(a/2, v) dir = ray.direction ray = Ray(ray.p1, ray.p1 + dir/dir.distance((0, 0))) if prec is not None: ray = Ray(ray.p1, ray.p2.n(prec)) b[v] = ray return b class RegularPolygon(Polygon): """ A regular polygon. Such a polygon has all internal angles equal and all sides the same length. Parameters ========== center : Point radius : number or Basic instance The distance from the center to a vertex n : int The number of sides Attributes ========== vertices center radius rotation apothem interior_angle exterior_angle circumcircle incircle angles Raises ====== GeometryError If the `center` is not a Point, or the `radius` is not a number or Basic instance, or the number of sides, `n`, is less than three. Notes ===== A RegularPolygon can be instantiated with Polygon with the kwarg n. Regular polygons are instantiated with a center, radius, number of sides and a rotation angle. Whereas the arguments of a Polygon are vertices, the vertices of the RegularPolygon must be obtained with the vertices method. See Also ======== sympy.geometry.point.Point, Polygon Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> r = RegularPolygon(Point(0, 0), 5, 3) >>> r RegularPolygon(Point2D(0, 0), 5, 3, 0) >>> r.vertices[0] Point2D(5, 0) """ __slots__ = ('_n', '_center', '_radius', '_rot') def __new__(self, c, r, n, rot=0, **kwargs): r, n, rot = map(sympify, (r, n, rot)) c = Point(c, dim=2, **kwargs) if not isinstance(r, Expr): raise GeometryError("r must be an Expr object, not %s" % r) if n.is_Number: as_int(n) # let an error raise if necessary if n < 3: raise GeometryError("n must be a >= 3, not %s" % n) obj = GeometryEntity.__new__(self, c, r, n, **kwargs) obj._n = n obj._center = c obj._radius = r obj._rot = rot % (2*S.Pi/n) if rot.is_number else rot return obj @property def args(self): """ Returns the center point, the radius, the number of sides, and the orientation angle. Examples ======== >>> from sympy import RegularPolygon, Point >>> r = RegularPolygon(Point(0, 0), 5, 3) >>> r.args (Point2D(0, 0), 5, 3, 0) """ return self._center, self._radius, self._n, self._rot def __str__(self): return 'RegularPolygon(%s, %s, %s, %s)' % tuple(self.args) def __repr__(self): return 'RegularPolygon(%s, %s, %s, %s)' % tuple(self.args) @property def area(self): """Returns the area. Examples ======== >>> from sympy.geometry import RegularPolygon >>> square = RegularPolygon((0, 0), 1, 4) >>> square.area 2 >>> _ == square.length**2 True """ c, r, n, rot = self.args return sign(r)*n*self.length**2/(4*tan(pi/n)) @property def length(self): """Returns the length of the sides. The half-length of the side and the apothem form two legs of a right triangle whose hypotenuse is the radius of the regular polygon. Examples ======== >>> from sympy.geometry import RegularPolygon >>> from sympy import sqrt >>> s = square_in_unit_circle = RegularPolygon((0, 0), 1, 4) >>> s.length sqrt(2) >>> sqrt((_/2)**2 + s.apothem**2) == s.radius True """ return self.radius*2*sin(pi/self._n) @property def center(self): """The center of the RegularPolygon This is also the center of the circumscribing circle. Returns ======= center : Point See Also ======== sympy.geometry.point.Point, sympy.geometry.ellipse.Ellipse.center Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> rp = RegularPolygon(Point(0, 0), 5, 4) >>> rp.center Point2D(0, 0) """ return self._center centroid = center @property def circumcenter(self): """ Alias for center. Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> rp = RegularPolygon(Point(0, 0), 5, 4) >>> rp.circumcenter Point2D(0, 0) """ return self.center @property def radius(self): """Radius of the RegularPolygon This is also the radius of the circumscribing circle. Returns ======= radius : number or instance of Basic See Also ======== sympy.geometry.line.Segment.length, sympy.geometry.ellipse.Circle.radius Examples ======== >>> from sympy import Symbol >>> from sympy.geometry import RegularPolygon, Point >>> radius = Symbol('r') >>> rp = RegularPolygon(Point(0, 0), radius, 4) >>> rp.radius r """ return self._radius @property def circumradius(self): """ Alias for radius. Examples ======== >>> from sympy import Symbol >>> from sympy.geometry import RegularPolygon, Point >>> radius = Symbol('r') >>> rp = RegularPolygon(Point(0, 0), radius, 4) >>> rp.circumradius r """ return self.radius @property def rotation(self): """CCW angle by which the RegularPolygon is rotated Returns ======= rotation : number or instance of Basic Examples ======== >>> from sympy import pi >>> from sympy.abc import a >>> from sympy.geometry import RegularPolygon, Point >>> RegularPolygon(Point(0, 0), 3, 4, pi/4).rotation pi/4 Numerical rotation angles are made canonical: >>> RegularPolygon(Point(0, 0), 3, 4, a).rotation a >>> RegularPolygon(Point(0, 0), 3, 4, pi).rotation 0 """ return self._rot @property def apothem(self): """The inradius of the RegularPolygon. The apothem/inradius is the radius of the inscribed circle. Returns ======= apothem : number or instance of Basic See Also ======== sympy.geometry.line.Segment.length, sympy.geometry.ellipse.Circle.radius Examples ======== >>> from sympy import Symbol >>> from sympy.geometry import RegularPolygon, Point >>> radius = Symbol('r') >>> rp = RegularPolygon(Point(0, 0), radius, 4) >>> rp.apothem sqrt(2)*r/2 """ return self.radius * cos(S.Pi/self._n) @property def inradius(self): """ Alias for apothem. Examples ======== >>> from sympy import Symbol >>> from sympy.geometry import RegularPolygon, Point >>> radius = Symbol('r') >>> rp = RegularPolygon(Point(0, 0), radius, 4) >>> rp.inradius sqrt(2)*r/2 """ return self.apothem @property def interior_angle(self): """Measure of the interior angles. Returns ======= interior_angle : number See Also ======== sympy.geometry.line.LinearEntity.angle_between Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> rp = RegularPolygon(Point(0, 0), 4, 8) >>> rp.interior_angle 3*pi/4 """ return (self._n - 2)*S.Pi/self._n @property def exterior_angle(self): """Measure of the exterior angles. Returns ======= exterior_angle : number See Also ======== sympy.geometry.line.LinearEntity.angle_between Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> rp = RegularPolygon(Point(0, 0), 4, 8) >>> rp.exterior_angle pi/4 """ return 2*S.Pi/self._n @property def circumcircle(self): """The circumcircle of the RegularPolygon. Returns ======= circumcircle : Circle See Also ======== circumcenter, sympy.geometry.ellipse.Circle Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> rp = RegularPolygon(Point(0, 0), 4, 8) >>> rp.circumcircle Circle(Point2D(0, 0), 4) """ return Circle(self.center, self.radius) @property def incircle(self): """The incircle of the RegularPolygon. Returns ======= incircle : Circle See Also ======== inradius, sympy.geometry.ellipse.Circle Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> rp = RegularPolygon(Point(0, 0), 4, 7) >>> rp.incircle Circle(Point2D(0, 0), 4*cos(pi/7)) """ return Circle(self.center, self.apothem) @property def angles(self): """ Returns a dictionary with keys, the vertices of the Polygon, and values, the interior angle at each vertex. Examples ======== >>> from sympy import RegularPolygon, Point >>> r = RegularPolygon(Point(0, 0), 5, 3) >>> r.angles {Point2D(-5/2, -5*sqrt(3)/2): pi/3, Point2D(-5/2, 5*sqrt(3)/2): pi/3, Point2D(5, 0): pi/3} """ ret = {} ang = self.interior_angle for v in self.vertices: ret[v] = ang return ret def encloses_point(self, p): """ Return True if p is enclosed by (is inside of) self. Notes ===== Being on the border of self is considered False. The general Polygon.encloses_point method is called only if a point is not within or beyond the incircle or circumcircle, respectively. Parameters ========== p : Point Returns ======= encloses_point : True, False or None See Also ======== sympy.geometry.ellipse.Ellipse.encloses_point Examples ======== >>> from sympy import RegularPolygon, S, Point, Symbol >>> p = RegularPolygon((0, 0), 3, 4) >>> p.encloses_point(Point(0, 0)) True >>> r, R = p.inradius, p.circumradius >>> p.encloses_point(Point((r + R)/2, 0)) True >>> p.encloses_point(Point(R/2, R/2 + (R - r)/10)) False >>> t = Symbol('t', real=True) >>> p.encloses_point(p.arbitrary_point().subs(t, S.Half)) False >>> p.encloses_point(Point(5, 5)) False """ c = self.center d = Segment(c, p).length if d >= self.radius: return False elif d < self.inradius: return True else: # now enumerate the RegularPolygon like a general polygon. return Polygon.encloses_point(self, p) def spin(self, angle): """Increment *in place* the virtual Polygon's rotation by ccw angle. See also: rotate method which moves the center. >>> from sympy import Polygon, Point, pi >>> r = Polygon(Point(0,0), 1, n=3) >>> r.vertices[0] Point2D(1, 0) >>> r.spin(pi/6) >>> r.vertices[0] Point2D(sqrt(3)/2, 1/2) See Also ======== rotation rotate : Creates a copy of the RegularPolygon rotated about a Point """ self._rot += angle def rotate(self, angle, pt=None): """Override GeometryEntity.rotate to first rotate the RegularPolygon about its center. >>> from sympy import Point, RegularPolygon, pi >>> t = RegularPolygon(Point(1, 0), 1, 3) >>> t.vertices[0] # vertex on x-axis Point2D(2, 0) >>> t.rotate(pi/2).vertices[0] # vertex on y axis now Point2D(0, 2) See Also ======== rotation spin : Rotates a RegularPolygon in place """ r = type(self)(*self.args) # need a copy or else changes are in-place r._rot += angle return GeometryEntity.rotate(r, angle, pt) def scale(self, x=1, y=1, pt=None): """Override GeometryEntity.scale since it is the radius that must be scaled (if x == y) or else a new Polygon must be returned. >>> from sympy import RegularPolygon Symmetric scaling returns a RegularPolygon: >>> RegularPolygon((0, 0), 1, 4).scale(2, 2) RegularPolygon(Point2D(0, 0), 2, 4, 0) Asymmetric scaling returns a kite as a Polygon: >>> RegularPolygon((0, 0), 1, 4).scale(2, 1) Polygon(Point2D(2, 0), Point2D(0, 1), Point2D(-2, 0), Point2D(0, -1)) """ if pt: pt = Point(pt, dim=2) return self.translate(*(-pt).args).scale(x, y).translate(*pt.args) if x != y: return Polygon(*self.vertices).scale(x, y) c, r, n, rot = self.args r *= x return self.func(c, r, n, rot) def reflect(self, line): """Override GeometryEntity.reflect since this is not made of only points. Examples ======== >>> from sympy import RegularPolygon, Line >>> RegularPolygon((0, 0), 1, 4).reflect(Line((0, 1), slope=-2)) RegularPolygon(Point2D(4/5, 2/5), -1, 4, atan(4/3)) """ c, r, n, rot = self.args v = self.vertices[0] d = v - c cc = c.reflect(line) vv = v.reflect(line) dd = vv - cc # calculate rotation about the new center # which will align the vertices l1 = Ray((0, 0), dd) l2 = Ray((0, 0), d) ang = l1.closing_angle(l2) rot += ang # change sign of radius as point traversal is reversed return self.func(cc, -r, n, rot) @property def vertices(self): """The vertices of the RegularPolygon. Returns ======= vertices : list Each vertex is a Point. See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy.geometry import RegularPolygon, Point >>> rp = RegularPolygon(Point(0, 0), 5, 4) >>> rp.vertices [Point2D(5, 0), Point2D(0, 5), Point2D(-5, 0), Point2D(0, -5)] """ c = self._center r = abs(self._radius) rot = self._rot v = 2*S.Pi/self._n return [Point(c.x + r*cos(k*v + rot), c.y + r*sin(k*v + rot)) for k in range(self._n)] def __eq__(self, o): if not isinstance(o, Polygon): return False elif not isinstance(o, RegularPolygon): return Polygon.__eq__(o, self) return self.args == o.args def __hash__(self): return super().__hash__() class Triangle(Polygon): """ A polygon with three vertices and three sides. Parameters ========== points : sequence of Points keyword: asa, sas, or sss to specify sides/angles of the triangle Attributes ========== vertices altitudes orthocenter circumcenter circumradius circumcircle inradius incircle exradii medians medial nine_point_circle Raises ====== GeometryError If the number of vertices is not equal to three, or one of the vertices is not a Point, or a valid keyword is not given. See Also ======== sympy.geometry.point.Point, Polygon Examples ======== >>> from sympy.geometry import Triangle, Point >>> Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) Triangle(Point2D(0, 0), Point2D(4, 0), Point2D(4, 3)) Keywords sss, sas, or asa can be used to give the desired side lengths (in order) and interior angles (in degrees) that define the triangle: >>> Triangle(sss=(3, 4, 5)) Triangle(Point2D(0, 0), Point2D(3, 0), Point2D(3, 4)) >>> Triangle(asa=(30, 1, 30)) Triangle(Point2D(0, 0), Point2D(1, 0), Point2D(1/2, sqrt(3)/6)) >>> Triangle(sas=(1, 45, 2)) Triangle(Point2D(0, 0), Point2D(2, 0), Point2D(sqrt(2)/2, sqrt(2)/2)) """ def __new__(cls, *args, **kwargs): if len(args) != 3: if 'sss' in kwargs: return _sss(*[simplify(a) for a in kwargs['sss']]) if 'asa' in kwargs: return _asa(*[simplify(a) for a in kwargs['asa']]) if 'sas' in kwargs: return _sas(*[simplify(a) for a in kwargs['sas']]) msg = "Triangle instantiates with three points or a valid keyword." raise GeometryError(msg) vertices = [Point(a, dim=2, **kwargs) for a in args] # remove consecutive duplicates nodup = [] for p in vertices: if nodup and p == nodup[-1]: continue nodup.append(p) if len(nodup) > 1 and nodup[-1] == nodup[0]: nodup.pop() # last point was same as first # remove collinear points i = -3 while i < len(nodup) - 3 and len(nodup) > 2: a, b, c = sorted( [nodup[i], nodup[i + 1], nodup[i + 2]], key=default_sort_key) if Point.is_collinear(a, b, c): nodup[i] = a nodup[i + 1] = None nodup.pop(i + 1) i += 1 vertices = list(filter(lambda x: x is not None, nodup)) if len(vertices) == 3: return GeometryEntity.__new__(cls, *vertices, **kwargs) elif len(vertices) == 2: return Segment(*vertices, **kwargs) else: return Point(*vertices, **kwargs) @property def vertices(self): """The triangle's vertices Returns ======= vertices : tuple Each element in the tuple is a Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy.geometry import Triangle, Point >>> t = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) >>> t.vertices (Point2D(0, 0), Point2D(4, 0), Point2D(4, 3)) """ return self.args def is_similar(t1, t2): """Is another triangle similar to this one. Two triangles are similar if one can be uniformly scaled to the other. Parameters ========== other: Triangle Returns ======= is_similar : boolean See Also ======== sympy.geometry.entity.GeometryEntity.is_similar Examples ======== >>> from sympy.geometry import Triangle, Point >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) >>> t2 = Triangle(Point(0, 0), Point(-4, 0), Point(-4, -3)) >>> t1.is_similar(t2) True >>> t2 = Triangle(Point(0, 0), Point(-4, 0), Point(-4, -4)) >>> t1.is_similar(t2) False """ if not isinstance(t2, Polygon): return False s1_1, s1_2, s1_3 = [side.length for side in t1.sides] s2 = [side.length for side in t2.sides] def _are_similar(u1, u2, u3, v1, v2, v3): e1 = simplify(u1/v1) e2 = simplify(u2/v2) e3 = simplify(u3/v3) return bool(e1 == e2) and bool(e2 == e3) # There's only 6 permutations, so write them out return _are_similar(s1_1, s1_2, s1_3, *s2) or \ _are_similar(s1_1, s1_3, s1_2, *s2) or \ _are_similar(s1_2, s1_1, s1_3, *s2) or \ _are_similar(s1_2, s1_3, s1_1, *s2) or \ _are_similar(s1_3, s1_1, s1_2, *s2) or \ _are_similar(s1_3, s1_2, s1_1, *s2) def is_equilateral(self): """Are all the sides the same length? Returns ======= is_equilateral : boolean See Also ======== sympy.geometry.entity.GeometryEntity.is_similar, RegularPolygon is_isosceles, is_right, is_scalene Examples ======== >>> from sympy.geometry import Triangle, Point >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) >>> t1.is_equilateral() False >>> from sympy import sqrt >>> t2 = Triangle(Point(0, 0), Point(10, 0), Point(5, 5*sqrt(3))) >>> t2.is_equilateral() True """ return not has_variety(s.length for s in self.sides) def is_isosceles(self): """Are two or more of the sides the same length? Returns ======= is_isosceles : boolean See Also ======== is_equilateral, is_right, is_scalene Examples ======== >>> from sympy.geometry import Triangle, Point >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(2, 4)) >>> t1.is_isosceles() True """ return has_dups(s.length for s in self.sides) def is_scalene(self): """Are all the sides of the triangle of different lengths? Returns ======= is_scalene : boolean See Also ======== is_equilateral, is_isosceles, is_right Examples ======== >>> from sympy.geometry import Triangle, Point >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(1, 4)) >>> t1.is_scalene() True """ return not has_dups(s.length for s in self.sides) def is_right(self): """Is the triangle right-angled. Returns ======= is_right : boolean See Also ======== sympy.geometry.line.LinearEntity.is_perpendicular is_equilateral, is_isosceles, is_scalene Examples ======== >>> from sympy.geometry import Triangle, Point >>> t1 = Triangle(Point(0, 0), Point(4, 0), Point(4, 3)) >>> t1.is_right() True """ s = self.sides return Segment.is_perpendicular(s[0], s[1]) or \ Segment.is_perpendicular(s[1], s[2]) or \ Segment.is_perpendicular(s[0], s[2]) @property def altitudes(self): """The altitudes of the triangle. An altitude of a triangle is a segment through a vertex, perpendicular to the opposite side, with length being the height of the vertex measured from the line containing the side. Returns ======= altitudes : dict The dictionary consists of keys which are vertices and values which are Segments. See Also ======== sympy.geometry.point.Point, sympy.geometry.line.Segment.length Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.altitudes[p1] Segment2D(Point2D(0, 0), Point2D(1/2, 1/2)) """ s = self.sides v = self.vertices return {v[0]: s[1].perpendicular_segment(v[0]), v[1]: s[2].perpendicular_segment(v[1]), v[2]: s[0].perpendicular_segment(v[2])} @property def orthocenter(self): """The orthocenter of the triangle. The orthocenter is the intersection of the altitudes of a triangle. It may lie inside, outside or on the triangle. Returns ======= orthocenter : Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.orthocenter Point2D(0, 0) """ a = self.altitudes v = self.vertices return Line(a[v[0]]).intersection(Line(a[v[1]]))[0] @property def circumcenter(self): """The circumcenter of the triangle The circumcenter is the center of the circumcircle. Returns ======= circumcenter : Point See Also ======== sympy.geometry.point.Point Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.circumcenter Point2D(1/2, 1/2) """ a, b, c = [x.perpendicular_bisector() for x in self.sides] if not a.intersection(b): print(a,b,a.intersection(b)) return a.intersection(b)[0] @property def circumradius(self): """The radius of the circumcircle of the triangle. Returns ======= circumradius : number of Basic instance See Also ======== sympy.geometry.ellipse.Circle.radius Examples ======== >>> from sympy import Symbol >>> from sympy.geometry import Point, Triangle >>> a = Symbol('a') >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, a) >>> t = Triangle(p1, p2, p3) >>> t.circumradius sqrt(a**2/4 + 1/4) """ return Point.distance(self.circumcenter, self.vertices[0]) @property def circumcircle(self): """The circle which passes through the three vertices of the triangle. Returns ======= circumcircle : Circle See Also ======== sympy.geometry.ellipse.Circle Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.circumcircle Circle(Point2D(1/2, 1/2), sqrt(2)/2) """ return Circle(self.circumcenter, self.circumradius) def bisectors(self): """The angle bisectors of the triangle. An angle bisector of a triangle is a straight line through a vertex which cuts the corresponding angle in half. Returns ======= bisectors : dict Each key is a vertex (Point) and each value is the corresponding bisector (Segment). See Also ======== sympy.geometry.point.Point, sympy.geometry.line.Segment Examples ======== >>> from sympy.geometry import Point, Triangle, Segment >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> from sympy import sqrt >>> t.bisectors()[p2] == Segment(Point(1, 0), Point(0, sqrt(2) - 1)) True """ # use lines containing sides so containment check during # intersection calculation can be avoided, thus reducing # the processing time for calculating the bisectors s = [Line(l) for l in self.sides] v = self.vertices c = self.incenter l1 = Segment(v[0], Line(v[0], c).intersection(s[1])[0]) l2 = Segment(v[1], Line(v[1], c).intersection(s[2])[0]) l3 = Segment(v[2], Line(v[2], c).intersection(s[0])[0]) return {v[0]: l1, v[1]: l2, v[2]: l3} @property def incenter(self): """The center of the incircle. The incircle is the circle which lies inside the triangle and touches all three sides. Returns ======= incenter : Point See Also ======== incircle, sympy.geometry.point.Point Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.incenter Point2D(1 - sqrt(2)/2, 1 - sqrt(2)/2) """ s = self.sides l = Matrix([s[i].length for i in [1, 2, 0]]) p = sum(l) v = self.vertices x = simplify(l.dot(Matrix([vi.x for vi in v]))/p) y = simplify(l.dot(Matrix([vi.y for vi in v]))/p) return Point(x, y) @property def inradius(self): """The radius of the incircle. Returns ======= inradius : number of Basic instance See Also ======== incircle, sympy.geometry.ellipse.Circle.radius Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(4, 0), Point(0, 3) >>> t = Triangle(p1, p2, p3) >>> t.inradius 1 """ return simplify(2 * self.area / self.perimeter) @property def incircle(self): """The incircle of the triangle. The incircle is the circle which lies inside the triangle and touches all three sides. Returns ======= incircle : Circle See Also ======== sympy.geometry.ellipse.Circle Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(2, 0), Point(0, 2) >>> t = Triangle(p1, p2, p3) >>> t.incircle Circle(Point2D(2 - sqrt(2), 2 - sqrt(2)), 2 - sqrt(2)) """ return Circle(self.incenter, self.inradius) @property def exradii(self): """The radius of excircles of a triangle. An excircle of the triangle is a circle lying outside the triangle, tangent to one of its sides and tangent to the extensions of the other two. Returns ======= exradii : dict See Also ======== sympy.geometry.polygon.Triangle.inradius Examples ======== The exradius touches the side of the triangle to which it is keyed, e.g. the exradius touching side 2 is: >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(6, 0), Point(0, 2) >>> t = Triangle(p1, p2, p3) >>> t.exradii[t.sides[2]] -2 + sqrt(10) References ========== [1] http://mathworld.wolfram.com/Exradius.html [2] http://mathworld.wolfram.com/Excircles.html """ side = self.sides a = side[0].length b = side[1].length c = side[2].length s = (a+b+c)/2 area = self.area exradii = {self.sides[0]: simplify(area/(s-a)), self.sides[1]: simplify(area/(s-b)), self.sides[2]: simplify(area/(s-c))} return exradii @property def excenters(self): """Excenters of the triangle. An excenter is the center of a circle that is tangent to a side of the triangle and the extensions of the other two sides. Returns ======= excenters : dict Examples ======== The excenters are keyed to the side of the triangle to which their corresponding excircle is tangent: The center is keyed, e.g. the excenter of a circle touching side 0 is: >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(6, 0), Point(0, 2) >>> t = Triangle(p1, p2, p3) >>> t.excenters[t.sides[0]] Point2D(12*sqrt(10), 2/3 + sqrt(10)/3) See Also ======== sympy.geometry.polygon.Triangle.exradii References ========== .. [1] http://mathworld.wolfram.com/Excircles.html """ s = self.sides v = self.vertices a = s[0].length b = s[1].length c = s[2].length x = [v[0].x, v[1].x, v[2].x] y = [v[0].y, v[1].y, v[2].y] exc_coords = { "x1": simplify(-a*x[0]+b*x[1]+c*x[2]/(-a+b+c)), "x2": simplify(a*x[0]-b*x[1]+c*x[2]/(a-b+c)), "x3": simplify(a*x[0]+b*x[1]-c*x[2]/(a+b-c)), "y1": simplify(-a*y[0]+b*y[1]+c*y[2]/(-a+b+c)), "y2": simplify(a*y[0]-b*y[1]+c*y[2]/(a-b+c)), "y3": simplify(a*y[0]+b*y[1]-c*y[2]/(a+b-c)) } excenters = { s[0]: Point(exc_coords["x1"], exc_coords["y1"]), s[1]: Point(exc_coords["x2"], exc_coords["y2"]), s[2]: Point(exc_coords["x3"], exc_coords["y3"]) } return excenters @property def medians(self): """The medians of the triangle. A median of a triangle is a straight line through a vertex and the midpoint of the opposite side, and divides the triangle into two equal areas. Returns ======= medians : dict Each key is a vertex (Point) and each value is the median (Segment) at that point. See Also ======== sympy.geometry.point.Point.midpoint, sympy.geometry.line.Segment.midpoint Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.medians[p1] Segment2D(Point2D(0, 0), Point2D(1/2, 1/2)) """ s = self.sides v = self.vertices return {v[0]: Segment(v[0], s[1].midpoint), v[1]: Segment(v[1], s[2].midpoint), v[2]: Segment(v[2], s[0].midpoint)} @property def medial(self): """The medial triangle of the triangle. The triangle which is formed from the midpoints of the three sides. Returns ======= medial : Triangle See Also ======== sympy.geometry.line.Segment.midpoint Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.medial Triangle(Point2D(1/2, 0), Point2D(1/2, 1/2), Point2D(0, 1/2)) """ s = self.sides return Triangle(s[0].midpoint, s[1].midpoint, s[2].midpoint) @property def nine_point_circle(self): """The nine-point circle of the triangle. Nine-point circle is the circumcircle of the medial triangle, which passes through the feet of altitudes and the middle points of segments connecting the vertices and the orthocenter. Returns ======= nine_point_circle : Circle See also ======== sympy.geometry.line.Segment.midpoint sympy.geometry.polygon.Triangle.medial sympy.geometry.polygon.Triangle.orthocenter Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.nine_point_circle Circle(Point2D(1/4, 1/4), sqrt(2)/4) """ return Circle(*self.medial.vertices) @property def eulerline(self): """The Euler line of the triangle. The line which passes through circumcenter, centroid and orthocenter. Returns ======= eulerline : Line (or Point for equilateral triangles in which case all centers coincide) Examples ======== >>> from sympy.geometry import Point, Triangle >>> p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) >>> t = Triangle(p1, p2, p3) >>> t.eulerline Line2D(Point2D(0, 0), Point2D(1/2, 1/2)) """ if self.is_equilateral(): return self.orthocenter return Line(self.orthocenter, self.circumcenter) def rad(d): """Return the radian value for the given degrees (pi = 180 degrees).""" return d*pi/180 def deg(r): """Return the degree value for the given radians (pi = 180 degrees).""" return r/pi*180 def _slope(d): rv = tan(rad(d)) return rv def _asa(d1, l, d2): """Return triangle having side with length l on the x-axis.""" xy = Line((0, 0), slope=_slope(d1)).intersection( Line((l, 0), slope=_slope(180 - d2)))[0] return Triangle((0, 0), (l, 0), xy) def _sss(l1, l2, l3): """Return triangle having side of length l1 on the x-axis.""" c1 = Circle((0, 0), l3) c2 = Circle((l1, 0), l2) inter = [a for a in c1.intersection(c2) if a.y.is_nonnegative] if not inter: return None pt = inter[0] return Triangle((0, 0), (l1, 0), pt) def _sas(l1, d, l2): """Return triangle having side with length l2 on the x-axis.""" p1 = Point(0, 0) p2 = Point(l2, 0) p3 = Point(cos(rad(d))*l1, sin(rad(d))*l1) return Triangle(p1, p2, p3) sympy-sympy-1.9/sympy/geometry/tests/000077500000000000000000000000001412543434000201015ustar00rootroot00000000000000sympy-sympy-1.9/sympy/geometry/tests/__init__.py000066400000000000000000000000001412543434000222000ustar00rootroot00000000000000sympy-sympy-1.9/sympy/geometry/tests/test_curve.py000066400000000000000000000102531412543434000226370ustar00rootroot00000000000000from sympy import Symbol, pi, symbols, Tuple, S, sqrt, asinh, Rational from sympy.geometry import Curve, Line, Point, Ellipse, Ray, Segment, Circle, Polygon, RegularPolygon from sympy.testing.pytest import raises, slow def test_curve(): x = Symbol('x', real=True) s = Symbol('s') z = Symbol('z') # this curve is independent of the indicated parameter c = Curve([2*s, s**2], (z, 0, 2)) assert c.parameter == z assert c.functions == (2*s, s**2) assert c.arbitrary_point() == Point(2*s, s**2) assert c.arbitrary_point(z) == Point(2*s, s**2) # this is how it is normally used c = Curve([2*s, s**2], (s, 0, 2)) assert c.parameter == s assert c.functions == (2*s, s**2) t = Symbol('t') # the t returned as assumptions assert c.arbitrary_point() != Point(2*t, t**2) t = Symbol('t', real=True) # now t has the same assumptions so the test passes assert c.arbitrary_point() == Point(2*t, t**2) assert c.arbitrary_point(z) == Point(2*z, z**2) assert c.arbitrary_point(c.parameter) == Point(2*s, s**2) assert c.arbitrary_point(None) == Point(2*s, s**2) assert c.plot_interval() == [t, 0, 2] assert c.plot_interval(z) == [z, 0, 2] assert Curve([x, x], (x, 0, 1)).rotate(pi/2) == Curve([-x, x], (x, 0, 1)) assert Curve([x, x], (x, 0, 1)).rotate(pi/2, (1, 2)).scale(2, 3).translate( 1, 3).arbitrary_point(s) == \ Line((0, 0), (1, 1)).rotate(pi/2, (1, 2)).scale(2, 3).translate( 1, 3).arbitrary_point(s) == \ Point(-2*s + 7, 3*s + 6) raises(ValueError, lambda: Curve((s), (s, 1, 2))) raises(ValueError, lambda: Curve((x, x * 2), (1, x))) raises(ValueError, lambda: Curve((s, s + t), (s, 1, 2)).arbitrary_point()) raises(ValueError, lambda: Curve((s, s + t), (t, 1, 2)).arbitrary_point(s)) @slow def test_free_symbols(): a, b, c, d, e, f, s = symbols('a:f,s') assert Point(a, b).free_symbols == {a, b} assert Line((a, b), (c, d)).free_symbols == {a, b, c, d} assert Ray((a, b), (c, d)).free_symbols == {a, b, c, d} assert Ray((a, b), angle=c).free_symbols == {a, b, c} assert Segment((a, b), (c, d)).free_symbols == {a, b, c, d} assert Line((a, b), slope=c).free_symbols == {a, b, c} assert Curve((a*s, b*s), (s, c, d)).free_symbols == {a, b, c, d} assert Ellipse((a, b), c, d).free_symbols == {a, b, c, d} assert Ellipse((a, b), c, eccentricity=d).free_symbols == \ {a, b, c, d} assert Ellipse((a, b), vradius=c, eccentricity=d).free_symbols == \ {a, b, c, d} assert Circle((a, b), c).free_symbols == {a, b, c} assert Circle((a, b), (c, d), (e, f)).free_symbols == \ {e, d, c, b, f, a} assert Polygon((a, b), (c, d), (e, f)).free_symbols == \ {e, b, d, f, a, c} assert RegularPolygon((a, b), c, d, e).free_symbols == {e, a, b, c, d} def test_transform(): x = Symbol('x', real=True) y = Symbol('y', real=True) c = Curve((x, x**2), (x, 0, 1)) cout = Curve((2*x - 4, 3*x**2 - 10), (x, 0, 1)) pts = [Point(0, 0), Point(S.Half, Rational(1, 4)), Point(1, 1)] pts_out = [Point(-4, -10), Point(-3, Rational(-37, 4)), Point(-2, -7)] assert c.scale(2, 3, (4, 5)) == cout assert [c.subs(x, xi/2) for xi in Tuple(0, 1, 2)] == pts assert [cout.subs(x, xi/2) for xi in Tuple(0, 1, 2)] == pts_out assert Curve((x + y, 3*x), (x, 0, 1)).subs(y, S.Half) == \ Curve((x + S.Half, 3*x), (x, 0, 1)) assert Curve((x, 3*x), (x, 0, 1)).translate(4, 5) == \ Curve((x + 4, 3*x + 5), (x, 0, 1)) def test_length(): t = Symbol('t', real=True) c1 = Curve((t, 0), (t, 0, 1)) assert c1.length == 1 c2 = Curve((t, t), (t, 0, 1)) assert c2.length == sqrt(2) c3 = Curve((t ** 2, t), (t, 2, 5)) assert c3.length == -sqrt(17) - asinh(4) / 4 + asinh(10) / 4 + 5 * sqrt(101) / 2 def test_parameter_value(): t = Symbol('t') C = Curve([2*t, t**2], (t, 0, 2)) assert C.parameter_value((2, 1), t) == {t: 1} raises(ValueError, lambda: C.parameter_value((2, 0), t)) def test_issue_17997(): t, s = symbols('t s') c = Curve((t, t**2), (t, 0, 10)) p = Curve([2*s, s**2], (s, 0, 2)) assert c(2) == Point(2, 4) assert p(1) == Point(2, 1) sympy-sympy-1.9/sympy/geometry/tests/test_ellipse.py000066400000000000000000000611021412543434000231470ustar00rootroot00000000000000from sympy import Eq, Rational, S, Symbol, symbols, pi, sqrt, oo, Point2D, Segment2D, Abs, sec from sympy.geometry import (Circle, Ellipse, GeometryError, Line, Point, Polygon, Ray, RegularPolygon, Segment, Triangle, intersection) from sympy.testing.pytest import raises, slow from sympy import integrate from sympy.functions.special.elliptic_integrals import elliptic_e from sympy.functions.elementary.miscellaneous import Max def test_ellipse_equation_using_slope(): from sympy.abc import x, y e1 = Ellipse(Point(1, 0), 3, 2) assert str(e1.equation(_slope=1)) == str((-x + y + 1)**2/8 + (x + y - 1)**2/18 - 1) e2 = Ellipse(Point(0, 0), 4, 1) assert str(e2.equation(_slope=1)) == str((-x + y)**2/2 + (x + y)**2/32 - 1) e3 = Ellipse(Point(1, 5), 6, 2) assert str(e3.equation(_slope=2)) == str((-2*x + y - 3)**2/20 + (x + 2*y - 11)**2/180 - 1) def test_object_from_equation(): from sympy.abc import x, y, a, b assert Circle(x**2 + y**2 + 3*x + 4*y - 8) == Circle(Point2D(S(-3) / 2, -2), sqrt(57) / 2) assert Circle(x**2 + y**2 + 6*x + 8*y + 25) == Circle(Point2D(-3, -4), 0) assert Circle(a**2 + b**2 + 6*a + 8*b + 25, x='a', y='b') == Circle(Point2D(-3, -4), 0) assert Circle(x**2 + y**2 - 25) == Circle(Point2D(0, 0), 5) assert Circle(x**2 + y**2) == Circle(Point2D(0, 0), 0) assert Circle(a**2 + b**2, x='a', y='b') == Circle(Point2D(0, 0), 0) assert Circle(x**2 + y**2 + 6*x + 8) == Circle(Point2D(-3, 0), 1) assert Circle(x**2 + y**2 + 6*y + 8) == Circle(Point2D(0, -3), 1) assert Circle(6*(x**2) + 6*(y**2) + 6*x + 8*y - 25) == Circle(Point2D(Rational(-1, 2), Rational(-2, 3)), 5*sqrt(37)/6) assert Circle(Eq(a**2 + b**2, 25), x='a', y=b) == Circle(Point2D(0, 0), 5) raises(GeometryError, lambda: Circle(x**2 + y**2 + 3*x + 4*y + 26)) raises(GeometryError, lambda: Circle(x**2 + y**2 + 25)) raises(GeometryError, lambda: Circle(a**2 + b**2 + 25, x='a', y='b')) raises(GeometryError, lambda: Circle(x**2 + 6*y + 8)) raises(GeometryError, lambda: Circle(6*(x ** 2) + 4*(y**2) + 6*x + 8*y + 25)) raises(ValueError, lambda: Circle(a**2 + b**2 + 3*a + 4*b - 8)) @slow def test_ellipse_geom(): x = Symbol('x', real=True) y = Symbol('y', real=True) t = Symbol('t', real=True) y1 = Symbol('y1', real=True) half = S.Half p1 = Point(0, 0) p2 = Point(1, 1) p4 = Point(0, 1) e1 = Ellipse(p1, 1, 1) e2 = Ellipse(p2, half, 1) e3 = Ellipse(p1, y1, y1) c1 = Circle(p1, 1) c2 = Circle(p2, 1) c3 = Circle(Point(sqrt(2), sqrt(2)), 1) l1 = Line(p1, p2) # Test creation with three points cen, rad = Point(3*half, 2), 5*half assert Circle(Point(0, 0), Point(3, 0), Point(0, 4)) == Circle(cen, rad) assert Circle(Point(0, 0), Point(1, 1), Point(2, 2)) == Segment2D(Point2D(0, 0), Point2D(2, 2)) raises(ValueError, lambda: Ellipse(None, None, None, 1)) raises(ValueError, lambda: Ellipse()) raises(GeometryError, lambda: Circle(Point(0, 0))) raises(GeometryError, lambda: Circle(Symbol('x')*Symbol('y'))) # Basic Stuff assert Ellipse(None, 1, 1).center == Point(0, 0) assert e1 == c1 assert e1 != e2 assert e1 != l1 assert p4 in e1 assert e1 in e1 assert e2 in e2 assert 1 not in e2 assert p2 not in e2 assert e1.area == pi assert e2.area == pi/2 assert e3.area == pi*y1*abs(y1) assert c1.area == e1.area assert c1.circumference == e1.circumference assert e3.circumference == 2*pi*y1 assert e1.plot_interval() == e2.plot_interval() == [t, -pi, pi] assert e1.plot_interval(x) == e2.plot_interval(x) == [x, -pi, pi] assert c1.minor == 1 assert c1.major == 1 assert c1.hradius == 1 assert c1.vradius == 1 assert Ellipse((1, 1), 0, 0) == Point(1, 1) assert Ellipse((1, 1), 1, 0) == Segment(Point(0, 1), Point(2, 1)) assert Ellipse((1, 1), 0, 1) == Segment(Point(1, 0), Point(1, 2)) # Private Functions assert hash(c1) == hash(Circle(Point(1, 0), Point(0, 1), Point(0, -1))) assert c1 in e1 assert (Line(p1, p2) in e1) is False assert e1.__cmp__(e1) == 0 assert e1.__cmp__(Point(0, 0)) > 0 # Encloses assert e1.encloses(Segment(Point(-0.5, -0.5), Point(0.5, 0.5))) is True assert e1.encloses(Line(p1, p2)) is False assert e1.encloses(Ray(p1, p2)) is False assert e1.encloses(e1) is False assert e1.encloses( Polygon(Point(-0.5, -0.5), Point(-0.5, 0.5), Point(0.5, 0.5))) is True assert e1.encloses(RegularPolygon(p1, 0.5, 3)) is True assert e1.encloses(RegularPolygon(p1, 5, 3)) is False assert e1.encloses(RegularPolygon(p2, 5, 3)) is False assert e2.arbitrary_point() in e2 raises(ValueError, lambda: Ellipse(Point(x, y), 1, 1).arbitrary_point(parameter='x')) # Foci f1, f2 = Point(sqrt(12), 0), Point(-sqrt(12), 0) ef = Ellipse(Point(0, 0), 4, 2) assert ef.foci in [(f1, f2), (f2, f1)] # Tangents v = sqrt(2) / 2 p1_1 = Point(v, v) p1_2 = p2 + Point(half, 0) p1_3 = p2 + Point(0, 1) assert e1.tangent_lines(p4) == c1.tangent_lines(p4) assert e2.tangent_lines(p1_2) == [Line(Point(Rational(3, 2), 1), Point(Rational(3, 2), S.Half))] assert e2.tangent_lines(p1_3) == [Line(Point(1, 2), Point(Rational(5, 4), 2))] assert c1.tangent_lines(p1_1) != [Line(p1_1, Point(0, sqrt(2)))] assert c1.tangent_lines(p1) == [] assert e2.is_tangent(Line(p1_2, p2 + Point(half, 1))) assert e2.is_tangent(Line(p1_3, p2 + Point(half, 1))) assert c1.is_tangent(Line(p1_1, Point(0, sqrt(2)))) assert e1.is_tangent(Line(Point(0, 0), Point(1, 1))) is False assert c1.is_tangent(e1) is True assert c1.is_tangent(Ellipse(Point(2, 0), 1, 1)) is True assert c1.is_tangent( Polygon(Point(1, 1), Point(1, -1), Point(2, 0))) is True assert c1.is_tangent( Polygon(Point(1, 1), Point(1, 0), Point(2, 0))) is False assert Circle(Point(5, 5), 3).is_tangent(Circle(Point(0, 5), 1)) is False assert Ellipse(Point(5, 5), 2, 1).tangent_lines(Point(0, 0)) == \ [Line(Point(0, 0), Point(Rational(77, 25), Rational(132, 25))), Line(Point(0, 0), Point(Rational(33, 5), Rational(22, 5)))] assert Ellipse(Point(5, 5), 2, 1).tangent_lines(Point(3, 4)) == \ [Line(Point(3, 4), Point(4, 4)), Line(Point(3, 4), Point(3, 5))] assert Circle(Point(5, 5), 2).tangent_lines(Point(3, 3)) == \ [Line(Point(3, 3), Point(4, 3)), Line(Point(3, 3), Point(3, 4))] assert Circle(Point(5, 5), 2).tangent_lines(Point(5 - 2*sqrt(2), 5)) == \ [Line(Point(5 - 2*sqrt(2), 5), Point(5 - sqrt(2), 5 - sqrt(2))), Line(Point(5 - 2*sqrt(2), 5), Point(5 - sqrt(2), 5 + sqrt(2))), ] assert Circle(Point(5, 5), 5).tangent_lines(Point(4, 0)) == \ [Line(Point(4, 0), Point(Rational(40, 13), Rational(5, 13))), Line(Point(4, 0), Point(5, 0))] assert Circle(Point(5, 5), 5).tangent_lines(Point(0, 6)) == \ [Line(Point(0, 6), Point(0, 7)), Line(Point(0, 6), Point(Rational(5, 13), Rational(90, 13)))] # for numerical calculations, we shouldn't demand exact equality, # so only test up to the desired precision def lines_close(l1, l2, prec): """ tests whether l1 and 12 are within 10**(-prec) of each other """ return abs(l1.p1 - l2.p1) < 10**(-prec) and abs(l1.p2 - l2.p2) < 10**(-prec) def line_list_close(ll1, ll2, prec): return all(lines_close(l1, l2, prec) for l1, l2 in zip(ll1, ll2)) e = Ellipse(Point(0, 0), 2, 1) assert e.normal_lines(Point(0, 0)) == \ [Line(Point(0, 0), Point(0, 1)), Line(Point(0, 0), Point(1, 0))] assert e.normal_lines(Point(1, 0)) == \ [Line(Point(0, 0), Point(1, 0))] assert e.normal_lines((0, 1)) == \ [Line(Point(0, 0), Point(0, 1))] assert line_list_close(e.normal_lines(Point(1, 1), 2), [ Line(Point(Rational(-51, 26), Rational(-1, 5)), Point(Rational(-25, 26), Rational(17, 83))), Line(Point(Rational(28, 29), Rational(-7, 8)), Point(Rational(57, 29), Rational(-9, 2)))], 2) # test the failure of Poly.intervals and checks a point on the boundary p = Point(sqrt(3), S.Half) assert p in e assert line_list_close(e.normal_lines(p, 2), [ Line(Point(Rational(-341, 171), Rational(-1, 13)), Point(Rational(-170, 171), Rational(5, 64))), Line(Point(Rational(26, 15), Rational(-1, 2)), Point(Rational(41, 15), Rational(-43, 26)))], 2) # be sure to use the slope that isn't undefined on boundary e = Ellipse((0, 0), 2, 2*sqrt(3)/3) assert line_list_close(e.normal_lines((1, 1), 2), [ Line(Point(Rational(-64, 33), Rational(-20, 71)), Point(Rational(-31, 33), Rational(2, 13))), Line(Point(1, -1), Point(2, -4))], 2) # general ellipse fails except under certain conditions e = Ellipse((0, 0), x, 1) assert e.normal_lines((x + 1, 0)) == [Line(Point(0, 0), Point(1, 0))] raises(NotImplementedError, lambda: e.normal_lines((x + 1, 1))) # Properties major = 3 minor = 1 e4 = Ellipse(p2, minor, major) assert e4.focus_distance == sqrt(major**2 - minor**2) ecc = e4.focus_distance / major assert e4.eccentricity == ecc assert e4.periapsis == major*(1 - ecc) assert e4.apoapsis == major*(1 + ecc) assert e4.semilatus_rectum == major*(1 - ecc ** 2) # independent of orientation e4 = Ellipse(p2, major, minor) assert e4.focus_distance == sqrt(major**2 - minor**2) ecc = e4.focus_distance / major assert e4.eccentricity == ecc assert e4.periapsis == major*(1 - ecc) assert e4.apoapsis == major*(1 + ecc) # Intersection l1 = Line(Point(1, -5), Point(1, 5)) l2 = Line(Point(-5, -1), Point(5, -1)) l3 = Line(Point(-1, -1), Point(1, 1)) l4 = Line(Point(-10, 0), Point(0, 10)) pts_c1_l3 = [Point(sqrt(2)/2, sqrt(2)/2), Point(-sqrt(2)/2, -sqrt(2)/2)] assert intersection(e2, l4) == [] assert intersection(c1, Point(1, 0)) == [Point(1, 0)] assert intersection(c1, l1) == [Point(1, 0)] assert intersection(c1, l2) == [Point(0, -1)] assert intersection(c1, l3) in [pts_c1_l3, [pts_c1_l3[1], pts_c1_l3[0]]] assert intersection(c1, c2) == [Point(0, 1), Point(1, 0)] assert intersection(c1, c3) == [Point(sqrt(2)/2, sqrt(2)/2)] assert e1.intersection(l1) == [Point(1, 0)] assert e2.intersection(l4) == [] assert e1.intersection(Circle(Point(0, 2), 1)) == [Point(0, 1)] assert e1.intersection(Circle(Point(5, 0), 1)) == [] assert e1.intersection(Ellipse(Point(2, 0), 1, 1)) == [Point(1, 0)] assert e1.intersection(Ellipse(Point(5, 0), 1, 1)) == [] assert e1.intersection(Point(2, 0)) == [] assert e1.intersection(e1) == e1 assert intersection(Ellipse(Point(0, 0), 2, 1), Ellipse(Point(3, 0), 1, 2)) == [Point(2, 0)] assert intersection(Circle(Point(0, 0), 2), Circle(Point(3, 0), 1)) == [Point(2, 0)] assert intersection(Circle(Point(0, 0), 2), Circle(Point(7, 0), 1)) == [] assert intersection(Ellipse(Point(0, 0), 5, 17), Ellipse(Point(4, 0), 1, 0.2)) == [Point(5, 0)] assert intersection(Ellipse(Point(0, 0), 5, 17), Ellipse(Point(4, 0), 0.999, 0.2)) == [] assert Circle((0, 0), S.Half).intersection( Triangle((-1, 0), (1, 0), (0, 1))) == [ Point(Rational(-1, 2), 0), Point(S.Half, 0)] raises(TypeError, lambda: intersection(e2, Line((0, 0, 0), (0, 0, 1)))) raises(TypeError, lambda: intersection(e2, Rational(12))) raises(TypeError, lambda: Ellipse.intersection(e2, 1)) # some special case intersections csmall = Circle(p1, 3) cbig = Circle(p1, 5) cout = Circle(Point(5, 5), 1) # one circle inside of another assert csmall.intersection(cbig) == [] # separate circles assert csmall.intersection(cout) == [] # coincident circles assert csmall.intersection(csmall) == csmall v = sqrt(2) t1 = Triangle(Point(0, v), Point(0, -v), Point(v, 0)) points = intersection(t1, c1) assert len(points) == 4 assert Point(0, 1) in points assert Point(0, -1) in points assert Point(v/2, v/2) in points assert Point(v/2, -v/2) in points circ = Circle(Point(0, 0), 5) elip = Ellipse(Point(0, 0), 5, 20) assert intersection(circ, elip) in \ [[Point(5, 0), Point(-5, 0)], [Point(-5, 0), Point(5, 0)]] assert elip.tangent_lines(Point(0, 0)) == [] elip = Ellipse(Point(0, 0), 3, 2) assert elip.tangent_lines(Point(3, 0)) == \ [Line(Point(3, 0), Point(3, -12))] e1 = Ellipse(Point(0, 0), 5, 10) e2 = Ellipse(Point(2, 1), 4, 8) a = Rational(53, 17) c = 2*sqrt(3991)/17 ans = [Point(a - c/8, a/2 + c), Point(a + c/8, a/2 - c)] assert e1.intersection(e2) == ans e2 = Ellipse(Point(x, y), 4, 8) c = sqrt(3991) ans = [Point(-c/68 + a, c*Rational(2, 17) + a/2), Point(c/68 + a, c*Rational(-2, 17) + a/2)] assert [p.subs({x: 2, y:1}) for p in e1.intersection(e2)] == ans # Combinations of above assert e3.is_tangent(e3.tangent_lines(p1 + Point(y1, 0))[0]) e = Ellipse((1, 2), 3, 2) assert e.tangent_lines(Point(10, 0)) == \ [Line(Point(10, 0), Point(1, 0)), Line(Point(10, 0), Point(Rational(14, 5), Rational(18, 5)))] # encloses_point e = Ellipse((0, 0), 1, 2) assert e.encloses_point(e.center) assert e.encloses_point(e.center + Point(0, e.vradius - Rational(1, 10))) assert e.encloses_point(e.center + Point(e.hradius - Rational(1, 10), 0)) assert e.encloses_point(e.center + Point(e.hradius, 0)) is False assert e.encloses_point( e.center + Point(e.hradius + Rational(1, 10), 0)) is False e = Ellipse((0, 0), 2, 1) assert e.encloses_point(e.center) assert e.encloses_point(e.center + Point(0, e.vradius - Rational(1, 10))) assert e.encloses_point(e.center + Point(e.hradius - Rational(1, 10), 0)) assert e.encloses_point(e.center + Point(e.hradius, 0)) is False assert e.encloses_point( e.center + Point(e.hradius + Rational(1, 10), 0)) is False assert c1.encloses_point(Point(1, 0)) is False assert c1.encloses_point(Point(0.3, 0.4)) is True assert e.scale(2, 3) == Ellipse((0, 0), 4, 3) assert e.scale(3, 6) == Ellipse((0, 0), 6, 6) assert e.rotate(pi) == e assert e.rotate(pi, (1, 2)) == Ellipse(Point(2, 4), 2, 1) raises(NotImplementedError, lambda: e.rotate(pi/3)) # Circle rotation tests (Issue #11743) # Link - https://github.com/sympy/sympy/issues/11743 cir = Circle(Point(1, 0), 1) assert cir.rotate(pi/2) == Circle(Point(0, 1), 1) assert cir.rotate(pi/3) == Circle(Point(S.Half, sqrt(3)/2), 1) assert cir.rotate(pi/3, Point(1, 0)) == Circle(Point(1, 0), 1) assert cir.rotate(pi/3, Point(0, 1)) == Circle(Point(S.Half + sqrt(3)/2, S.Half + sqrt(3)/2), 1) def test_construction(): e1 = Ellipse(hradius=2, vradius=1, eccentricity=None) assert e1.eccentricity == sqrt(3)/2 e2 = Ellipse(hradius=2, vradius=None, eccentricity=sqrt(3)/2) assert e2.vradius == 1 e3 = Ellipse(hradius=None, vradius=1, eccentricity=sqrt(3)/2) assert e3.hradius == 2 # filter(None, iterator) filters out anything falsey, including 0 # eccentricity would be filtered out in this case and the constructor would throw an error e4 = Ellipse(Point(0, 0), hradius=1, eccentricity=0) assert e4.vradius == 1 #tests for eccentricity > 1 raises(GeometryError, lambda: Ellipse(Point(3, 1), hradius=3, eccentricity = S(3)/2)) raises(GeometryError, lambda: Ellipse(Point(3, 1), hradius=3, eccentricity=sec(5))) raises(GeometryError, lambda: Ellipse(Point(3, 1), hradius=3, eccentricity=S.Pi-S(2))) #tests for eccentricity = 1 #if vradius is not defined assert Ellipse(None, 1, None, 1).length == 2 #if hradius is not defined raises(GeometryError, lambda: Ellipse(None, None, 1, eccentricity = 1)) #tests for eccentricity < 0 raises(GeometryError, lambda: Ellipse(Point(3, 1), hradius=3, eccentricity = -3)) raises(GeometryError, lambda: Ellipse(Point(3, 1), hradius=3, eccentricity = -0.5)) def test_ellipse_random_point(): y1 = Symbol('y1', real=True) e3 = Ellipse(Point(0, 0), y1, y1) rx, ry = Symbol('rx'), Symbol('ry') for ind in range(0, 5): r = e3.random_point() # substitution should give zero*y1**2 assert e3.equation(rx, ry).subs(zip((rx, ry), r.args)).equals(0) # test for the case with seed r = e3.random_point(seed=1) assert e3.equation(rx, ry).subs(zip((rx, ry), r.args)).equals(0) def test_repr(): assert repr(Circle((0, 1), 2)) == 'Circle(Point2D(0, 1), 2)' def test_transform(): c = Circle((1, 1), 2) assert c.scale(-1) == Circle((-1, 1), 2) assert c.scale(y=-1) == Circle((1, -1), 2) assert c.scale(2) == Ellipse((2, 1), 4, 2) assert Ellipse((0, 0), 2, 3).scale(2, 3, (4, 5)) == \ Ellipse(Point(-4, -10), 4, 9) assert Circle((0, 0), 2).scale(2, 3, (4, 5)) == \ Ellipse(Point(-4, -10), 4, 6) assert Ellipse((0, 0), 2, 3).scale(3, 3, (4, 5)) == \ Ellipse(Point(-8, -10), 6, 9) assert Circle((0, 0), 2).scale(3, 3, (4, 5)) == \ Circle(Point(-8, -10), 6) assert Circle(Point(-8, -10), 6).scale(Rational(1, 3), Rational(1, 3), (4, 5)) == \ Circle((0, 0), 2) assert Circle((0, 0), 2).translate(4, 5) == \ Circle((4, 5), 2) assert Circle((0, 0), 2).scale(3, 3) == \ Circle((0, 0), 6) def test_bounds(): e1 = Ellipse(Point(0, 0), 3, 5) e2 = Ellipse(Point(2, -2), 7, 7) c1 = Circle(Point(2, -2), 7) c2 = Circle(Point(-2, 0), Point(0, 2), Point(2, 0)) assert e1.bounds == (-3, -5, 3, 5) assert e2.bounds == (-5, -9, 9, 5) assert c1.bounds == (-5, -9, 9, 5) assert c2.bounds == (-2, -2, 2, 2) def test_reflect(): b = Symbol('b') m = Symbol('m') l = Line((0, b), slope=m) t1 = Triangle((0, 0), (1, 0), (2, 3)) assert t1.area == -t1.reflect(l).area e = Ellipse((1, 0), 1, 2) assert e.area == -e.reflect(Line((1, 0), slope=0)).area assert e.area == -e.reflect(Line((1, 0), slope=oo)).area raises(NotImplementedError, lambda: e.reflect(Line((1, 0), slope=m))) assert Circle((0, 1), 1).reflect(Line((0, 0), (1, 1))) == Circle(Point2D(1, 0), -1) def test_is_tangent(): e1 = Ellipse(Point(0, 0), 3, 5) c1 = Circle(Point(2, -2), 7) assert e1.is_tangent(Point(0, 0)) is False assert e1.is_tangent(Point(3, 0)) is False assert e1.is_tangent(e1) is True assert e1.is_tangent(Ellipse((0, 0), 1, 2)) is False assert e1.is_tangent(Ellipse((0, 0), 3, 2)) is True assert c1.is_tangent(Ellipse((2, -2), 7, 1)) is True assert c1.is_tangent(Circle((11, -2), 2)) is True assert c1.is_tangent(Circle((7, -2), 2)) is True assert c1.is_tangent(Ray((-5, -2), (-15, -20))) is False assert c1.is_tangent(Ray((-3, -2), (-15, -20))) is False assert c1.is_tangent(Ray((-3, -22), (15, 20))) is False assert c1.is_tangent(Ray((9, 20), (9, -20))) is True assert e1.is_tangent(Segment((2, 2), (-7, 7))) is False assert e1.is_tangent(Segment((0, 0), (1, 2))) is False assert c1.is_tangent(Segment((0, 0), (-5, -2))) is False assert e1.is_tangent(Segment((3, 0), (12, 12))) is False assert e1.is_tangent(Segment((12, 12), (3, 0))) is False assert e1.is_tangent(Segment((-3, 0), (3, 0))) is False assert e1.is_tangent(Segment((-3, 5), (3, 5))) is True assert e1.is_tangent(Line((10, 0), (10, 10))) is False assert e1.is_tangent(Line((0, 0), (1, 1))) is False assert e1.is_tangent(Line((-3, 0), (-2.99, -0.001))) is False assert e1.is_tangent(Line((-3, 0), (-3, 1))) is True assert e1.is_tangent(Polygon((0, 0), (5, 5), (5, -5))) is False assert e1.is_tangent(Polygon((-100, -50), (-40, -334), (-70, -52))) is False assert e1.is_tangent(Polygon((-3, 0), (3, 0), (0, 1))) is False assert e1.is_tangent(Polygon((-3, 0), (3, 0), (0, 5))) is False assert e1.is_tangent(Polygon((-3, 0), (0, -5), (3, 0), (0, 5))) is False assert e1.is_tangent(Polygon((-3, -5), (-3, 5), (3, 5), (3, -5))) is True assert c1.is_tangent(Polygon((-3, -5), (-3, 5), (3, 5), (3, -5))) is False assert e1.is_tangent(Polygon((0, 0), (3, 0), (7, 7), (0, 5))) is False assert e1.is_tangent(Polygon((3, 12), (3, -12), (6, 5))) is True assert e1.is_tangent(Polygon((3, 12), (3, -12), (0, -5), (0, 5))) is False assert e1.is_tangent(Polygon((3, 0), (5, 7), (6, -5))) is False raises(TypeError, lambda: e1.is_tangent(Point(0, 0, 0))) raises(TypeError, lambda: e1.is_tangent(Rational(5))) def test_parameter_value(): t = Symbol('t') e = Ellipse(Point(0, 0), 3, 5) assert e.parameter_value((3, 0), t) == {t: 0} raises(ValueError, lambda: e.parameter_value((4, 0), t)) @slow def test_second_moment_of_area(): x, y = symbols('x, y') e = Ellipse(Point(0, 0), 5, 4) I_yy = 2*4*integrate(sqrt(25 - x**2)*x**2, (x, -5, 5))/5 I_xx = 2*5*integrate(sqrt(16 - y**2)*y**2, (y, -4, 4))/4 Y = 3*sqrt(1 - x**2/5**2) I_xy = integrate(integrate(y, (y, -Y, Y))*x, (x, -5, 5)) assert I_yy == e.second_moment_of_area()[1] assert I_xx == e.second_moment_of_area()[0] assert I_xy == e.second_moment_of_area()[2] #checking for other point t1 = e.second_moment_of_area(Point(6,5)) t2 = (580*pi, 845*pi, 600*pi) assert t1==t2 def test_section_modulus_and_polar_second_moment_of_area(): d = Symbol('d', positive=True) c = Circle((3, 7), 8) assert c.polar_second_moment_of_area() == 2048*pi assert c.section_modulus() == (128*pi, 128*pi) c = Circle((2, 9), d/2) assert c.polar_second_moment_of_area() == pi*d**3*Abs(d)/64 + pi*d*Abs(d)**3/64 assert c.section_modulus() == (pi*d**3/S(32), pi*d**3/S(32)) a, b = symbols('a, b', positive=True) e = Ellipse((4, 6), a, b) assert e.section_modulus() == (pi*a*b**2/S(4), pi*a**2*b/S(4)) assert e.polar_second_moment_of_area() == pi*a**3*b/S(4) + pi*a*b**3/S(4) e = e.rotate(pi/2) # no change in polar and section modulus assert e.section_modulus() == (pi*a**2*b/S(4), pi*a*b**2/S(4)) assert e.polar_second_moment_of_area() == pi*a**3*b/S(4) + pi*a*b**3/S(4) e = Ellipse((a, b), 2, 6) assert e.section_modulus() == (18*pi, 6*pi) assert e.polar_second_moment_of_area() == 120*pi e = Ellipse(Point(0, 0), 2, 2) assert e.section_modulus() == (2*pi, 2*pi) assert e.section_modulus(Point(2, 2)) == (2*pi, 2*pi) assert e.section_modulus((2, 2)) == (2*pi, 2*pi) def test_circumference(): M = Symbol('M') m = Symbol('m') assert Ellipse(Point(0, 0), M, m).circumference == 4 * M * elliptic_e((M ** 2 - m ** 2) / M**2) assert Ellipse(Point(0, 0), 5, 4).circumference == 20 * elliptic_e(S(9) / 25) # circle assert Ellipse(None, 1, None, 0).circumference == 2*pi # test numerically assert abs(Ellipse(None, hradius=5, vradius=3).circumference.evalf(16) - 25.52699886339813) < 1e-10 def test_issue_15259(): assert Circle((1, 2), 0) == Point(1, 2) def test_issue_15797_equals(): Ri = 0.024127189424130748 Ci = (0.0864931002830291, 0.0819863295239654) A = Point(0, 0.0578591400998346) c = Circle(Ci, Ri) # evaluated assert c.is_tangent(c.tangent_lines(A)[0]) == True assert c.center.x.is_Rational assert c.center.y.is_Rational assert c.radius.is_Rational u = Circle(Ci, Ri, evaluate=False) # unevaluated assert u.center.x.is_Float assert u.center.y.is_Float assert u.radius.is_Float def test_auxiliary_circle(): x, y, a, b = symbols('x y a b') e = Ellipse((x, y), a, b) # the general result assert e.auxiliary_circle() == Circle((x, y), Max(a, b)) # a special case where Ellipse is a Circle assert Circle((3, 4), 8).auxiliary_circle() == Circle((3, 4), 8) def test_director_circle(): x, y, a, b = symbols('x y a b') e = Ellipse((x, y), a, b) # the general result assert e.director_circle() == Circle((x, y), sqrt(a**2 + b**2)) # a special case where Ellipse is a Circle assert Circle((3, 4), 8).director_circle() == Circle((3, 4), 8*sqrt(2)) def test_evolute(): #ellipse centered at h,k x, y, h, k = symbols('x y h k',real = True) a, b = symbols('a b') e = Ellipse(Point(h, k), a, b) t1 = (e.hradius*(x - e.center.x))**Rational(2, 3) t2 = (e.vradius*(y - e.center.y))**Rational(2, 3) E = t1 + t2 - (e.hradius**2 - e.vradius**2)**Rational(2, 3) assert e.evolute() == E #Numerical Example e = Ellipse(Point(1, 1), 6, 3) t1 = (6*(x - 1))**Rational(2, 3) t2 = (3*(y - 1))**Rational(2, 3) E = t1 + t2 - (27)**Rational(2, 3) assert e.evolute() == E def test_svg(): e1 = Ellipse(Point(1, 0), 3, 2) assert e1._svg(2, "#FFAAFF") == '' sympy-sympy-1.9/sympy/geometry/tests/test_entity.py000066400000000000000000000060311412543434000230260ustar00rootroot00000000000000from sympy import Symbol, Rational, S from sympy.geometry import Circle, Ellipse, Line, Point, Polygon, Ray, RegularPolygon, Segment, Triangle from sympy.geometry.entity import scale, GeometryEntity from sympy.testing.pytest import raises from random import random def test_entity(): x = Symbol('x', real=True) y = Symbol('y', real=True) assert GeometryEntity(x, y) in GeometryEntity(x, y) raises(NotImplementedError, lambda: Point(0, 0) in GeometryEntity(x, y)) assert GeometryEntity(x, y) == GeometryEntity(x, y) assert GeometryEntity(x, y).equals(GeometryEntity(x, y)) c = Circle((0, 0), 5) assert GeometryEntity.encloses(c, Point(0, 0)) assert GeometryEntity.encloses(c, Segment((0, 0), (1, 1))) assert GeometryEntity.encloses(c, Line((0, 0), (1, 1))) is False assert GeometryEntity.encloses(c, Circle((0, 0), 4)) assert GeometryEntity.encloses(c, Polygon(Point(0, 0), Point(1, 0), Point(0, 1))) assert GeometryEntity.encloses(c, RegularPolygon(Point(8, 8), 1, 3)) is False def test_svg(): a = Symbol('a') b = Symbol('b') d = Symbol('d') entity = Circle(Point(a, b), d) assert entity._repr_svg_() is None entity = Circle(Point(0, 0), S.Infinity) assert entity._repr_svg_() is None def test_subs(): x = Symbol('x', real=True) y = Symbol('y', real=True) p = Point(x, 2) q = Point(1, 1) r = Point(3, 4) for o in [p, Segment(p, q), Ray(p, q), Line(p, q), Triangle(p, q, r), RegularPolygon(p, 3, 6), Polygon(p, q, r, Point(5, 4)), Circle(p, 3), Ellipse(p, 3, 4)]: assert 'y' in str(o.subs(x, y)) assert p.subs({x: 1}) == Point(1, 2) assert Point(1, 2).subs(Point(1, 2), Point(3, 4)) == Point(3, 4) assert Point(1, 2).subs((1, 2), Point(3, 4)) == Point(3, 4) assert Point(1, 2).subs(Point(1, 2), Point(3, 4)) == Point(3, 4) assert Point(1, 2).subs({(1, 2)}) == Point(2, 2) raises(ValueError, lambda: Point(1, 2).subs(1)) raises(ValueError, lambda: Point(1, 1).subs((Point(1, 1), Point(1, 2)), 1, 2)) def test_transform(): assert scale(1, 2, (3, 4)).tolist() == \ [[1, 0, 0], [0, 2, 0], [0, -4, 1]] def test_reflect_entity_overrides(): x = Symbol('x', real=True) y = Symbol('y', real=True) b = Symbol('b') m = Symbol('m') l = Line((0, b), slope=m) p = Point(x, y) r = p.reflect(l) c = Circle((x, y), 3) cr = c.reflect(l) assert cr == Circle(r, -3) assert c.area == -cr.area pent = RegularPolygon((1, 2), 1, 5) l = Line(pent.vertices[1], slope=Rational(random() - .5, random() - .5)) rpent = pent.reflect(l) assert rpent.center == pent.center.reflect(l) rvert = [i.reflect(l) for i in pent.vertices] for v in rpent.vertices: for i in range(len(rvert)): ri = rvert[i] if ri.equals(v): rvert.remove(ri) break assert not rvert assert pent.area.equals(-rpent.area) sympy-sympy-1.9/sympy/geometry/tests/test_geometrysets.py000066400000000000000000000035121412543434000242450ustar00rootroot00000000000000from sympy import Rational, S from sympy.geometry import Circle, Line, Point, Polygon, Segment from sympy.sets import FiniteSet, Union, Intersection, EmptySet def test_booleans(): """ test basic unions and intersections """ half = S.Half p1, p2, p3, p4 = map(Point, [(0, 0), (1, 0), (5, 1), (0, 1)]) p5, p6, p7 = map(Point, [(3, 2), (1, -1), (0, 2)]) l1 = Line(Point(0,0), Point(1,1)) l2 = Line(Point(half, half), Point(5,5)) l3 = Line(p2, p3) l4 = Line(p3, p4) poly1 = Polygon(p1, p2, p3, p4) poly2 = Polygon(p5, p6, p7) poly3 = Polygon(p1, p2, p5) assert Union(l1, l2).equals(l1) assert Intersection(l1, l2).equals(l1) assert Intersection(l1, l4) == FiniteSet(Point(1,1)) assert Intersection(Union(l1, l4), l3) == FiniteSet(Point(Rational(-1, 3), Rational(-1, 3)), Point(5, 1)) assert Intersection(l1, FiniteSet(Point(7,-7))) == EmptySet assert Intersection(Circle(Point(0,0), 3), Line(p1,p2)) == FiniteSet(Point(-3,0), Point(3,0)) assert Intersection(l1, FiniteSet(p1)) == FiniteSet(p1) assert Union(l1, FiniteSet(p1)) == l1 fs = FiniteSet(Point(Rational(1, 3), 1), Point(Rational(2, 3), 0), Point(Rational(9, 5), Rational(1, 5)), Point(Rational(7, 3), 1)) # test the intersection of polygons assert Intersection(poly1, poly2) == fs # make sure if we union polygons with subsets, the subsets go away assert Union(poly1, poly2, fs) == Union(poly1, poly2) # make sure that if we union with a FiniteSet that isn't a subset, # that the points in the intersection stop being listed assert Union(poly1, FiniteSet(Point(0,0), Point(3,5))) == Union(poly1, FiniteSet(Point(3,5))) # intersect two polygons that share an edge assert Intersection(poly1, poly3) == Union(FiniteSet(Point(Rational(3, 2), 1), Point(2, 1)), Segment(Point(0, 0), Point(1, 0))) sympy-sympy-1.9/sympy/geometry/tests/test_line.py000066400000000000000000001053141412543434000224450ustar00rootroot00000000000000from sympy import (Eq, Rational, Float, S, Symbol, cos, oo, pi, simplify, sin, sqrt, symbols, acos) from sympy.functions.elementary.trigonometric import tan from sympy.geometry import (Circle, GeometryError, Line, Point, Ray, Segment, Triangle, intersection, Point3D, Line3D, Ray3D, Segment3D, Point2D, Line2D) from sympy.geometry.line import Undecidable from sympy.geometry.polygon import _asa as asa from sympy.utilities.iterables import cartes from sympy.testing.pytest import raises, warns x = Symbol('x', real=True) y = Symbol('y', real=True) z = Symbol('z', real=True) k = Symbol('k', real=True) x1 = Symbol('x1', real=True) y1 = Symbol('y1', real=True) t = Symbol('t', real=True) a, b = symbols('a,b', real=True) m = symbols('m', real=True) def test_object_from_equation(): from sympy.abc import x, y, a, b assert Line(3*x + y + 18) == Line2D(Point2D(0, -18), Point2D(1, -21)) assert Line(3*x + 5 * y + 1) == Line2D(Point2D(0, Rational(-1, 5)), Point2D(1, Rational(-4, 5))) assert Line(3*a + b + 18, x='a', y='b') == Line2D(Point2D(0, -18), Point2D(1, -21)) assert Line(3*x + y) == Line2D(Point2D(0, 0), Point2D(1, -3)) assert Line(x + y) == Line2D(Point2D(0, 0), Point2D(1, -1)) assert Line(Eq(3*a + b, -18), x='a', y=b) == Line2D(Point2D(0, -18), Point2D(1, -21)) raises(ValueError, lambda: Line(x)) raises(ValueError, lambda: Line(y)) raises(ValueError, lambda: Line(x/y)) raises(ValueError, lambda: Line(a/b, x='a', y='b')) raises(ValueError, lambda: Line(y/x)) raises(ValueError, lambda: Line(b/a, x='a', y='b')) raises(ValueError, lambda: Line((x + 1)**2 + y)) def feq(a, b): """Test if two floating point values are 'equal'.""" t_float = Float("1.0E-10") return -t_float < a - b < t_float def test_angle_between(): a = Point(1, 2, 3, 4) b = a.orthogonal_direction o = a.origin assert feq(Line.angle_between(Line(Point(0, 0), Point(1, 1)), Line(Point(0, 0), Point(5, 0))).evalf(), pi.evalf() / 4) assert Line(a, o).angle_between(Line(b, o)) == pi / 2 assert Line3D.angle_between(Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)), Line3D(Point3D(0, 0, 0), Point3D(5, 0, 0))) == acos(sqrt(3) / 3) def test_closing_angle(): a = Ray((0, 0), angle=0) b = Ray((1, 2), angle=pi/2) assert a.closing_angle(b) == -pi/2 assert b.closing_angle(a) == pi/2 assert a.closing_angle(a) == 0 def test_smallest_angle(): a = Line(Point(1, 1), Point(1, 2)) b = Line(Point(1, 1),Point(2, 3)) assert a.smallest_angle_between(b) == acos(2*sqrt(5)/5) def test_svg(): a = Line(Point(1, 1),Point(1, 2)) assert a._svg() == '' a = Segment(Point(1, 0),Point(1, 1)) assert a._svg() == '' a = Ray(Point(2, 3), Point(3, 5)) assert a._svg() == '' def test_arbitrary_point(): l1 = Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)) l2 = Line(Point(x1, x1), Point(y1, y1)) assert l2.arbitrary_point() in l2 assert Ray((1, 1), angle=pi / 4).arbitrary_point() == \ Point(t + 1, t + 1) assert Segment((1, 1), (2, 3)).arbitrary_point() == Point(1 + t, 1 + 2 * t) assert l1.perpendicular_segment(l1.arbitrary_point()) == l1.arbitrary_point() assert Ray3D((1, 1, 1), direction_ratio=[1, 2, 3]).arbitrary_point() == \ Point3D(t + 1, 2 * t + 1, 3 * t + 1) assert Segment3D(Point3D(0, 0, 0), Point3D(1, 1, 1)).midpoint == \ Point3D(S.Half, S.Half, S.Half) assert Segment3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1)).length == sqrt(3) * sqrt((x1 - y1) ** 2) assert Segment3D((1, 1, 1), (2, 3, 4)).arbitrary_point() == \ Point3D(t + 1, 2 * t + 1, 3 * t + 1) raises(ValueError, (lambda: Line((x, 1), (2, 3)).arbitrary_point(x))) def test_are_concurrent_2d(): l1 = Line(Point(0, 0), Point(1, 1)) l2 = Line(Point(x1, x1), Point(x1, 1 + x1)) assert Line.are_concurrent(l1) is False assert Line.are_concurrent(l1, l2) assert Line.are_concurrent(l1, l1, l1, l2) assert Line.are_concurrent(l1, l2, Line(Point(5, x1), Point(Rational(-3, 5), x1))) assert Line.are_concurrent(l1, Line(Point(0, 0), Point(-x1, x1)), l2) is False def test_are_concurrent_3d(): p1 = Point3D(0, 0, 0) l1 = Line(p1, Point3D(1, 1, 1)) parallel_1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)) parallel_2 = Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0)) assert Line3D.are_concurrent(l1) is False assert Line3D.are_concurrent(l1, Line(Point3D(x1, x1, x1), Point3D(y1, y1, y1))) is False assert Line3D.are_concurrent(l1, Line3D(p1, Point3D(x1, x1, x1)), Line(Point3D(x1, x1, x1), Point3D(x1, 1 + x1, 1))) is True assert Line3D.are_concurrent(parallel_1, parallel_2) is False def test_arguments(): """Functions accepting `Point` objects in `geometry` should also accept tuples, lists, and generators and automatically convert them to points.""" from sympy import subsets singles2d = ((1, 2), [1, 3], Point(1, 5)) doubles2d = subsets(singles2d, 2) l2d = Line(Point2D(1, 2), Point2D(2, 3)) singles3d = ((1, 2, 3), [1, 2, 4], Point(1, 2, 6)) doubles3d = subsets(singles3d, 2) l3d = Line(Point3D(1, 2, 3), Point3D(1, 1, 2)) singles4d = ((1, 2, 3, 4), [1, 2, 3, 5], Point(1, 2, 3, 7)) doubles4d = subsets(singles4d, 2) l4d = Line(Point(1, 2, 3, 4), Point(2, 2, 2, 2)) # test 2D test_single = ['contains', 'distance', 'equals', 'parallel_line', 'perpendicular_line', 'perpendicular_segment', 'projection', 'intersection'] for p in doubles2d: Line2D(*p) for func in test_single: for p in singles2d: getattr(l2d, func)(p) # test 3D for p in doubles3d: Line3D(*p) for func in test_single: for p in singles3d: getattr(l3d, func)(p) # test 4D for p in doubles4d: Line(*p) for func in test_single: for p in singles4d: getattr(l4d, func)(p) def test_basic_properties_2d(): p1 = Point(0, 0) p2 = Point(1, 1) p10 = Point(2000, 2000) p_r3 = Ray(p1, p2).random_point() p_r4 = Ray(p2, p1).random_point() l1 = Line(p1, p2) l3 = Line(Point(x1, x1), Point(x1, 1 + x1)) l4 = Line(p1, Point(1, 0)) r1 = Ray(p1, Point(0, 1)) r2 = Ray(Point(0, 1), p1) s1 = Segment(p1, p10) p_s1 = s1.random_point() assert Line((1, 1), slope=1) == Line((1, 1), (2, 2)) assert Line((1, 1), slope=oo) == Line((1, 1), (1, 2)) assert Line((1, 1), slope=oo).bounds == (1, 1, 1, 2) assert Line((1, 1), slope=-oo) == Line((1, 1), (1, 2)) assert Line(p1, p2).scale(2, 1) == Line(p1, Point(2, 1)) assert Line(p1, p2) == Line(p1, p2) assert Line(p1, p2) != Line(p2, p1) assert l1 != Line(Point(x1, x1), Point(y1, y1)) assert l1 != l3 assert Line(p1, p10) != Line(p10, p1) assert Line(p1, p10) != p1 assert p1 in l1 # is p1 on the line l1? assert p1 not in l3 assert s1 in Line(p1, p10) assert Ray(Point(0, 0), Point(0, 1)) in Ray(Point(0, 0), Point(0, 2)) assert Ray(Point(0, 0), Point(0, 2)) in Ray(Point(0, 0), Point(0, 1)) assert Ray(Point(0, 0), Point(0, 2)).xdirection == S.Zero assert Ray(Point(0, 0), Point(1, 2)).xdirection == S.Infinity assert Ray(Point(0, 0), Point(-1, 2)).xdirection == S.NegativeInfinity assert Ray(Point(0, 0), Point(2, 0)).ydirection == S.Zero assert Ray(Point(0, 0), Point(2, 2)).ydirection == S.Infinity assert Ray(Point(0, 0), Point(2, -2)).ydirection == S.NegativeInfinity assert (r1 in s1) is False assert Segment(p1, p2) in s1 assert Ray(Point(x1, x1), Point(x1, 1 + x1)) != Ray(p1, Point(-1, 5)) assert Segment(p1, p2).midpoint == Point(S.Half, S.Half) assert Segment(p1, Point(-x1, x1)).length == sqrt(2 * (x1 ** 2)) assert l1.slope == 1 assert l3.slope is oo assert l4.slope == 0 assert Line(p1, Point(0, 1)).slope is oo assert Line(r1.source, r1.random_point()).slope == r1.slope assert Line(r2.source, r2.random_point()).slope == r2.slope assert Segment(Point(0, -1), Segment(p1, Point(0, 1)).random_point()).slope == Segment(p1, Point(0, 1)).slope assert l4.coefficients == (0, 1, 0) assert Line((-x, x), (-x + 1, x - 1)).coefficients == (1, 1, 0) assert Line(p1, Point(0, 1)).coefficients == (1, 0, 0) # issue 7963 r = Ray((0, 0), angle=x) assert r.subs(x, 3 * pi / 4) == Ray((0, 0), (-1, 1)) assert r.subs(x, 5 * pi / 4) == Ray((0, 0), (-1, -1)) assert r.subs(x, -pi / 4) == Ray((0, 0), (1, -1)) assert r.subs(x, pi / 2) == Ray((0, 0), (0, 1)) assert r.subs(x, -pi / 2) == Ray((0, 0), (0, -1)) for ind in range(0, 5): assert l3.random_point() in l3 assert p_r3.x >= p1.x and p_r3.y >= p1.y assert p_r4.x <= p2.x and p_r4.y <= p2.y assert p1.x <= p_s1.x <= p10.x and p1.y <= p_s1.y <= p10.y assert hash(s1) != hash(Segment(p10, p1)) assert s1.plot_interval() == [t, 0, 1] assert Line(p1, p10).plot_interval() == [t, -5, 5] assert Ray((0, 0), angle=pi / 4).plot_interval() == [t, 0, 10] def test_basic_properties_3d(): p1 = Point3D(0, 0, 0) p2 = Point3D(1, 1, 1) p3 = Point3D(x1, x1, x1) p5 = Point3D(x1, 1 + x1, 1) l1 = Line3D(p1, p2) l3 = Line3D(p3, p5) r1 = Ray3D(p1, Point3D(-1, 5, 0)) r3 = Ray3D(p1, p2) s1 = Segment3D(p1, p2) assert Line3D((1, 1, 1), direction_ratio=[2, 3, 4]) == Line3D(Point3D(1, 1, 1), Point3D(3, 4, 5)) assert Line3D((1, 1, 1), direction_ratio=[1, 5, 7]) == Line3D(Point3D(1, 1, 1), Point3D(2, 6, 8)) assert Line3D((1, 1, 1), direction_ratio=[1, 2, 3]) == Line3D(Point3D(1, 1, 1), Point3D(2, 3, 4)) assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).direction_cosine == [1, 0, 0] assert Line3D(Line3D(p1, Point3D(0, 1, 0))) == Line3D(p1, Point3D(0, 1, 0)) assert Ray3D(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0))) == Ray3D(p1, Point3D(1, 0, 0)) assert Line3D(p1, p2) != Line3D(p2, p1) assert l1 != l3 assert l1 != Line3D(p3, Point3D(y1, y1, y1)) assert r3 != r1 assert Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 1)) in Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)) assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)) in Ray3D(Point3D(0, 0, 0), Point3D(1, 1, 1)) assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).xdirection == S.Infinity assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).ydirection == S.Infinity assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 2)).zdirection == S.Infinity assert Ray3D(Point3D(0, 0, 0), Point3D(-2, 2, 2)).xdirection == S.NegativeInfinity assert Ray3D(Point3D(0, 0, 0), Point3D(2, -2, 2)).ydirection == S.NegativeInfinity assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, -2)).zdirection == S.NegativeInfinity assert Ray3D(Point3D(0, 0, 0), Point3D(0, 2, 2)).xdirection == S.Zero assert Ray3D(Point3D(0, 0, 0), Point3D(2, 0, 2)).ydirection == S.Zero assert Ray3D(Point3D(0, 0, 0), Point3D(2, 2, 0)).zdirection == S.Zero assert p1 in l1 assert p1 not in l3 assert l1.direction_ratio == [1, 1, 1] assert s1.midpoint == Point3D(S.Half, S.Half, S.Half) # Test zdirection assert Ray3D(p1, Point3D(0, 0, -1)).zdirection is S.NegativeInfinity def test_contains(): p1 = Point(0, 0) r = Ray(p1, Point(4, 4)) r1 = Ray3D(p1, Point3D(0, 0, -1)) r2 = Ray3D(p1, Point3D(0, 1, 0)) r3 = Ray3D(p1, Point3D(0, 0, 1)) l = Line(Point(0, 1), Point(3, 4)) # Segment contains assert Point(0, (a + b) / 2) in Segment((0, a), (0, b)) assert Point((a + b) / 2, 0) in Segment((a, 0), (b, 0)) assert Point3D(0, 1, 0) in Segment3D((0, 1, 0), (0, 1, 0)) assert Point3D(1, 0, 0) in Segment3D((1, 0, 0), (1, 0, 0)) assert Segment3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).contains([]) is True assert Segment3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).contains( Segment3D(Point3D(2, 2, 2), Point3D(3, 2, 2))) is False # Line contains assert l.contains(Point(0, 1)) is True assert l.contains((0, 1)) is True assert l.contains((0, 0)) is False # Ray contains assert r.contains(p1) is True assert r.contains((1, 1)) is True assert r.contains((1, 3)) is False assert r.contains(Segment((1, 1), (2, 2))) is True assert r.contains(Segment((1, 2), (2, 5))) is False assert r.contains(Ray((2, 2), (3, 3))) is True assert r.contains(Ray((2, 2), (3, 5))) is False assert r1.contains(Segment3D(p1, Point3D(0, 0, -10))) is True assert r1.contains(Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))) is False assert r2.contains(Point3D(0, 0, 0)) is True assert r3.contains(Point3D(0, 0, 0)) is True assert Ray3D(Point3D(1, 1, 1), Point3D(1, 0, 0)).contains([]) is False assert Line3D((0, 0, 0), (x, y, z)).contains((2 * x, 2 * y, 2 * z)) with warns(UserWarning): assert Line3D(p1, Point3D(0, 1, 0)).contains(Point(1.0, 1.0)) is False with warns(UserWarning): assert r3.contains(Point(1.0, 1.0)) is False def test_contains_nonreal_symbols(): u, v, w, z = symbols('u, v, w, z') l = Segment(Point(u, w), Point(v, z)) p = Point(u*Rational(2, 3) + v/3, w*Rational(2, 3) + z/3) assert l.contains(p) def test_distance_2d(): p1 = Point(0, 0) p2 = Point(1, 1) half = S.Half s1 = Segment(Point(0, 0), Point(1, 1)) s2 = Segment(Point(half, half), Point(1, 0)) r = Ray(p1, p2) assert s1.distance(Point(0, 0)) == 0 assert s1.distance((0, 0)) == 0 assert s2.distance(Point(0, 0)) == 2 ** half / 2 assert s2.distance(Point(Rational(3) / 2, Rational(3) / 2)) == 2 ** half assert Line(p1, p2).distance(Point(-1, 1)) == sqrt(2) assert Line(p1, p2).distance(Point(1, -1)) == sqrt(2) assert Line(p1, p2).distance(Point(2, 2)) == 0 assert Line(p1, p2).distance((-1, 1)) == sqrt(2) assert Line((0, 0), (0, 1)).distance(p1) == 0 assert Line((0, 0), (0, 1)).distance(p2) == 1 assert Line((0, 0), (1, 0)).distance(p1) == 0 assert Line((0, 0), (1, 0)).distance(p2) == 1 assert r.distance(Point(-1, -1)) == sqrt(2) assert r.distance(Point(1, 1)) == 0 assert r.distance(Point(-1, 1)) == sqrt(2) assert Ray((1, 1), (2, 2)).distance(Point(1.5, 3)) == 3 * sqrt(2) / 4 assert r.distance((1, 1)) == 0 def test_dimension_normalization(): with warns(UserWarning): assert Ray((1, 1), (2, 1, 2)) == Ray((1, 1, 0), (2, 1, 2)) def test_distance_3d(): p1, p2 = Point3D(0, 0, 0), Point3D(1, 1, 1) p3 = Point3D(Rational(3) / 2, Rational(3) / 2, Rational(3) / 2) s1 = Segment3D(Point3D(0, 0, 0), Point3D(1, 1, 1)) s2 = Segment3D(Point3D(S.Half, S.Half, S.Half), Point3D(1, 0, 1)) r = Ray3D(p1, p2) assert s1.distance(p1) == 0 assert s2.distance(p1) == sqrt(3) / 2 assert s2.distance(p3) == 2 * sqrt(6) / 3 assert s1.distance((0, 0, 0)) == 0 assert s2.distance((0, 0, 0)) == sqrt(3) / 2 assert s1.distance(p1) == 0 assert s2.distance(p1) == sqrt(3) / 2 assert s2.distance(p3) == 2 * sqrt(6) / 3 assert s1.distance((0, 0, 0)) == 0 assert s2.distance((0, 0, 0)) == sqrt(3) / 2 # Line to point assert Line3D(p1, p2).distance(Point3D(-1, 1, 1)) == 2 * sqrt(6) / 3 assert Line3D(p1, p2).distance(Point3D(1, -1, 1)) == 2 * sqrt(6) / 3 assert Line3D(p1, p2).distance(Point3D(2, 2, 2)) == 0 assert Line3D(p1, p2).distance((2, 2, 2)) == 0 assert Line3D(p1, p2).distance((1, -1, 1)) == 2 * sqrt(6) / 3 assert Line3D((0, 0, 0), (0, 1, 0)).distance(p1) == 0 assert Line3D((0, 0, 0), (0, 1, 0)).distance(p2) == sqrt(2) assert Line3D((0, 0, 0), (1, 0, 0)).distance(p1) == 0 assert Line3D((0, 0, 0), (1, 0, 0)).distance(p2) == sqrt(2) # Ray to point assert r.distance(Point3D(-1, -1, -1)) == sqrt(3) assert r.distance(Point3D(1, 1, 1)) == 0 assert r.distance((-1, -1, -1)) == sqrt(3) assert r.distance((1, 1, 1)) == 0 assert Ray3D((0, 0, 0), (1, 1, 2)).distance((-1, -1, 2)) == 4 * sqrt(3) / 3 assert Ray3D((1, 1, 1), (2, 2, 2)).distance(Point3D(1.5, -3, -1)) == Rational(9) / 2 assert Ray3D((1, 1, 1), (2, 2, 2)).distance(Point3D(1.5, 3, 1)) == sqrt(78) / 6 def test_equals(): p1 = Point(0, 0) p2 = Point(1, 1) l1 = Line(p1, p2) l2 = Line((0, 5), slope=m) l3 = Line(Point(x1, x1), Point(x1, 1 + x1)) assert l1.perpendicular_line(p1.args).equals(Line(Point(0, 0), Point(1, -1))) assert l1.perpendicular_line(p1).equals(Line(Point(0, 0), Point(1, -1))) assert Line(Point(x1, x1), Point(y1, y1)).parallel_line(Point(-x1, x1)). \ equals(Line(Point(-x1, x1), Point(-y1, 2 * x1 - y1))) assert l3.parallel_line(p1.args).equals(Line(Point(0, 0), Point(0, -1))) assert l3.parallel_line(p1).equals(Line(Point(0, 0), Point(0, -1))) assert (l2.distance(Point(2, 3)) - 2 * abs(m + 1) / sqrt(m ** 2 + 1)).equals(0) assert Line3D(p1, Point3D(0, 1, 0)).equals(Point(1.0, 1.0)) is False assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).equals(Line3D(Point3D(-5, 0, 0), Point3D(-1, 0, 0))) is True assert Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)).equals(Line3D(p1, Point3D(0, 1, 0))) is False assert Ray3D(p1, Point3D(0, 0, -1)).equals(Point(1.0, 1.0)) is False assert Ray3D(p1, Point3D(0, 0, -1)).equals(Ray3D(p1, Point3D(0, 0, -1))) is True assert Line3D((0, 0), (t, t)).perpendicular_line(Point(0, 1, 0)).equals( Line3D(Point3D(0, 1, 0), Point3D(S.Half, S.Half, 0))) assert Line3D((0, 0), (t, t)).perpendicular_segment(Point(0, 1, 0)).equals(Segment3D((0, 1), (S.Half, S.Half))) assert Line3D(p1, Point3D(0, 1, 0)).equals(Point(1.0, 1.0)) is False def test_equation(): p1 = Point(0, 0) p2 = Point(1, 1) l1 = Line(p1, p2) l3 = Line(Point(x1, x1), Point(x1, 1 + x1)) assert simplify(l1.equation()) in (x - y, y - x) assert simplify(l3.equation()) in (x - x1, x1 - x) assert simplify(l1.equation()) in (x - y, y - x) assert simplify(l3.equation()) in (x - x1, x1 - x) assert Line(p1, Point(1, 0)).equation(x=x, y=y) == y assert Line(p1, Point(0, 1)).equation() == x assert Line(Point(2, 0), Point(2, 1)).equation() == x - 2 assert Line(p2, Point(2, 1)).equation() == y - 1 assert Line3D(Point(x1, x1, x1), Point(y1, y1, y1) ).equation() == (-x + y, -x + z) assert Line3D(Point(1, 2, 3), Point(2, 3, 4) ).equation() == (-x + y - 1, -x + z - 2) assert Line3D(Point(1, 2, 3), Point(1, 3, 4) ).equation() == (x - 1, -y + z - 1) assert Line3D(Point(1, 2, 3), Point(2, 2, 4) ).equation() == (y - 2, -x + z - 2) assert Line3D(Point(1, 2, 3), Point(2, 3, 3) ).equation() == (-x + y - 1, z - 3) assert Line3D(Point(1, 2, 3), Point(1, 2, 4) ).equation() == (x - 1, y - 2) assert Line3D(Point(1, 2, 3), Point(1, 3, 3) ).equation() == (x - 1, z - 3) assert Line3D(Point(1, 2, 3), Point(2, 2, 3) ).equation() == (y - 2, z - 3) def test_intersection_2d(): p1 = Point(0, 0) p2 = Point(1, 1) p3 = Point(x1, x1) p4 = Point(y1, y1) l1 = Line(p1, p2) l3 = Line(Point(0, 0), Point(3, 4)) r1 = Ray(Point(1, 1), Point(2, 2)) r2 = Ray(Point(0, 0), Point(3, 4)) r4 = Ray(p1, p2) r6 = Ray(Point(0, 1), Point(1, 2)) r7 = Ray(Point(0.5, 0.5), Point(1, 1)) s1 = Segment(p1, p2) s2 = Segment(Point(0.25, 0.25), Point(0.5, 0.5)) s3 = Segment(Point(0, 0), Point(3, 4)) assert intersection(l1, p1) == [p1] assert intersection(l1, Point(x1, 1 + x1)) == [] assert intersection(l1, Line(p3, p4)) in [[l1], [Line(p3, p4)]] assert intersection(l1, l1.parallel_line(Point(x1, 1 + x1))) == [] assert intersection(l3, l3) == [l3] assert intersection(l3, r2) == [r2] assert intersection(l3, s3) == [s3] assert intersection(s3, l3) == [s3] assert intersection(Segment(Point(-10, 10), Point(10, 10)), Segment(Point(-5, -5), Point(-5, 5))) == [] assert intersection(r2, l3) == [r2] assert intersection(r1, Ray(Point(2, 2), Point(0, 0))) == [Segment(Point(1, 1), Point(2, 2))] assert intersection(r1, Ray(Point(1, 1), Point(-1, -1))) == [Point(1, 1)] assert intersection(r1, Segment(Point(0, 0), Point(2, 2))) == [Segment(Point(1, 1), Point(2, 2))] assert r4.intersection(s2) == [s2] assert r4.intersection(Segment(Point(2, 3), Point(3, 4))) == [] assert r4.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))] assert r4.intersection(Ray(p2, p1)) == [s1] assert Ray(p2, p1).intersection(r6) == [] assert r4.intersection(r7) == r7.intersection(r4) == [r7] assert Ray3D((0, 0), (3, 0)).intersection(Ray3D((1, 0), (3, 0))) == [Ray3D((1, 0), (3, 0))] assert Ray3D((1, 0), (3, 0)).intersection(Ray3D((0, 0), (3, 0))) == [Ray3D((1, 0), (3, 0))] assert Ray(Point(0, 0), Point(0, 4)).intersection(Ray(Point(0, 1), Point(0, -1))) == \ [Segment(Point(0, 0), Point(0, 1))] assert Segment3D((0, 0), (3, 0)).intersection( Segment3D((1, 0), (2, 0))) == [Segment3D((1, 0), (2, 0))] assert Segment3D((1, 0), (2, 0)).intersection( Segment3D((0, 0), (3, 0))) == [Segment3D((1, 0), (2, 0))] assert Segment3D((0, 0), (3, 0)).intersection( Segment3D((3, 0), (4, 0))) == [Point3D((3, 0))] assert Segment3D((0, 0), (3, 0)).intersection( Segment3D((2, 0), (5, 0))) == [Segment3D((2, 0), (3, 0))] assert Segment3D((0, 0), (3, 0)).intersection( Segment3D((-2, 0), (1, 0))) == [Segment3D((0, 0), (1, 0))] assert Segment3D((0, 0), (3, 0)).intersection( Segment3D((-2, 0), (0, 0))) == [Point3D(0, 0)] assert s1.intersection(Segment(Point(1, 1), Point(2, 2))) == [Point(1, 1)] assert s1.intersection(Segment(Point(0.5, 0.5), Point(1.5, 1.5))) == [Segment(Point(0.5, 0.5), p2)] assert s1.intersection(Segment(Point(4, 4), Point(5, 5))) == [] assert s1.intersection(Segment(Point(-1, -1), p1)) == [p1] assert s1.intersection(Segment(Point(-1, -1), Point(0.5, 0.5))) == [Segment(p1, Point(0.5, 0.5))] assert s1.intersection(Line(Point(1, 0), Point(2, 1))) == [] assert s1.intersection(s2) == [s2] assert s2.intersection(s1) == [s2] assert asa(120, 8, 52) == \ Triangle( Point(0, 0), Point(8, 0), Point(-4 * cos(19 * pi / 90) / sin(2 * pi / 45), 4 * sqrt(3) * cos(19 * pi / 90) / sin(2 * pi / 45))) assert Line((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == [Point(1, 1)] assert Line((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == [Point(1, 1)] assert Ray((0, 0), (1, 1)).intersection(Ray((1, 0), (1, 2))) == [Point(1, 1)] assert Ray((0, 0), (1, 1)).intersection(Segment((1, 0), (1, 2))) == [Point(1, 1)] assert Ray((0, 0), (10, 10)).contains(Segment((1, 1), (2, 2))) is True assert Segment((1, 1), (2, 2)) in Line((0, 0), (10, 10)) assert s1.intersection(Ray((1, 1), (4, 4))) == [Point(1, 1)] # This test is disabled because it hangs after rref changes which simplify # intermediate results and return a different representation from when the # test was written. # # 16628 - this should be fast # p0 = Point2D(Rational(249, 5), Rational(497999, 10000)) # p1 = Point2D((-58977084786*sqrt(405639795226) + 2030690077184193 + # 20112207807*sqrt(630547164901) + 99600*sqrt(255775022850776494562626)) # /(2000*sqrt(255775022850776494562626) + 1991998000*sqrt(405639795226) # + 1991998000*sqrt(630547164901) + 1622561172902000), # (-498000*sqrt(255775022850776494562626) - 995999*sqrt(630547164901) + # 90004251917891999 + # 496005510002*sqrt(405639795226))/(10000*sqrt(255775022850776494562626) # + 9959990000*sqrt(405639795226) + 9959990000*sqrt(630547164901) + # 8112805864510000)) # p2 = Point2D(Rational(497, 10), Rational(-497, 10)) # p3 = Point2D(Rational(-497, 10), Rational(-497, 10)) # l = Line(p0, p1) # s = Segment(p2, p3) # n = (-52673223862*sqrt(405639795226) - 15764156209307469 - # 9803028531*sqrt(630547164901) + # 33200*sqrt(255775022850776494562626)) # d = sqrt(405639795226) + 315274080450 + 498000*sqrt( # 630547164901) + sqrt(255775022850776494562626) # assert intersection(l, s) == [ # Point2D(n/d*Rational(3, 2000), Rational(-497, 10))] def test_line_intersection(): # see also test_issue_11238 in test_matrices.py x0 = tan(pi*Rational(13, 45)) x1 = sqrt(3) x2 = x0**2 x, y = [8*x0/(x0 + x1), (24*x0 - 8*x1*x2)/(x2 - 3)] assert Line(Point(0, 0), Point(1, -sqrt(3))).contains(Point(x, y)) is True def test_intersection_3d(): p1 = Point3D(0, 0, 0) p2 = Point3D(1, 1, 1) l1 = Line3D(p1, p2) l2 = Line3D(Point3D(0, 0, 0), Point3D(3, 4, 0)) r1 = Ray3D(Point3D(1, 1, 1), Point3D(2, 2, 2)) r2 = Ray3D(Point3D(0, 0, 0), Point3D(3, 4, 0)) s1 = Segment3D(Point3D(0, 0, 0), Point3D(3, 4, 0)) assert intersection(l1, p1) == [p1] assert intersection(l1, Point3D(x1, 1 + x1, 1)) == [] assert intersection(l1, l1.parallel_line(p1)) == [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1))] assert intersection(l2, r2) == [r2] assert intersection(l2, s1) == [s1] assert intersection(r2, l2) == [r2] assert intersection(r1, Ray3D(Point3D(1, 1, 1), Point3D(-1, -1, -1))) == [Point3D(1, 1, 1)] assert intersection(r1, Segment3D(Point3D(0, 0, 0), Point3D(2, 2, 2))) == [ Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))] assert intersection(Ray3D(Point3D(1, 0, 0), Point3D(-1, 0, 0)), Ray3D(Point3D(0, 1, 0), Point3D(0, -1, 0))) \ == [Point3D(0, 0, 0)] assert intersection(r1, Ray3D(Point3D(2, 2, 2), Point3D(0, 0, 0))) == \ [Segment3D(Point3D(1, 1, 1), Point3D(2, 2, 2))] assert intersection(s1, r2) == [s1] assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).intersection(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) == \ [Point3D(2, 2, 1)] assert Line3D((0, 1, 2), (0, 2, 3)).intersection(Line3D((0, 1, 2), (0, 1, 1))) == [Point3D(0, 1, 2)] assert Line3D((0, 0), (t, t)).intersection(Line3D((0, 1), (t, t))) == \ [Point3D(t, t)] assert Ray3D(Point3D(0, 0, 0), Point3D(0, 4, 0)).intersection(Ray3D(Point3D(0, 1, 1), Point3D(0, -1, 1))) == [] def test_is_parallel(): p1 = Point3D(0, 0, 0) p2 = Point3D(1, 1, 1) p3 = Point3D(x1, x1, x1) l2 = Line(Point(x1, x1), Point(y1, y1)) l2_1 = Line(Point(x1, x1), Point(x1, 1 + x1)) assert Line.is_parallel(Line(Point(0, 0), Point(1, 1)), l2) assert Line.is_parallel(l2, Line(Point(x1, x1), Point(x1, 1 + x1))) is False assert Line.is_parallel(l2, l2.parallel_line(Point(-x1, x1))) assert Line.is_parallel(l2_1, l2_1.parallel_line(Point(0, 0))) assert Line3D(p1, p2).is_parallel(Line3D(p1, p2)) # same as in 2D assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).is_parallel(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) is False assert Line3D(p1, p2).parallel_line(p3) == Line3D(Point3D(x1, x1, x1), Point3D(x1 + 1, x1 + 1, x1 + 1)) assert Line3D(p1, p2).parallel_line(p3.args) == \ Line3D(Point3D(x1, x1, x1), Point3D(x1 + 1, x1 + 1, x1 + 1)) assert Line3D(Point3D(4, 0, 1), Point3D(0, 4, 1)).is_parallel(Line3D(Point3D(0, 0, 1), Point3D(4, 4, 1))) is False def test_is_perpendicular(): p1 = Point(0, 0) p2 = Point(1, 1) l1 = Line(p1, p2) l2 = Line(Point(x1, x1), Point(y1, y1)) l1_1 = Line(p1, Point(-x1, x1)) # 2D assert Line.is_perpendicular(l1, l1_1) assert Line.is_perpendicular(l1, l2) is False p = l1.random_point() assert l1.perpendicular_segment(p) == p # 3D assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)), Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))) is True assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)), Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))) is False assert Line3D.is_perpendicular(Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)), Line3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1))) is False def test_is_similar(): p1 = Point(2000, 2000) p2 = p1.scale(2, 2) r1 = Ray3D(Point3D(1, 1, 1), Point3D(1, 0, 0)) r2 = Ray(Point(0, 0), Point(0, 1)) s1 = Segment(Point(0, 0), p1) assert s1.is_similar(Segment(p1, p2)) assert s1.is_similar(r2) is False assert r1.is_similar(Line3D(Point3D(1, 1, 1), Point3D(1, 0, 0))) is True assert r1.is_similar(Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0))) is False def test_length(): s2 = Segment3D(Point3D(x1, x1, x1), Point3D(y1, y1, y1)) assert Line(Point(0, 0), Point(1, 1)).length is oo assert s2.length == sqrt(3) * sqrt((x1 - y1) ** 2) assert Line3D(Point3D(0, 0, 0), Point3D(1, 1, 1)).length is oo def test_projection(): p1 = Point(0, 0) p2 = Point3D(0, 0, 0) p3 = Point(-x1, x1) l1 = Line(p1, Point(1, 1)) l2 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)) l3 = Line3D(p2, Point3D(1, 1, 1)) r1 = Ray(Point(1, 1), Point(2, 2)) assert Line(Point(x1, x1), Point(y1, y1)).projection(Point(y1, y1)) == Point(y1, y1) assert Line(Point(x1, x1), Point(x1, 1 + x1)).projection(Point(1, 1)) == Point(x1, 1) assert Segment(Point(-2, 2), Point(0, 4)).projection(r1) == Segment(Point(-1, 3), Point(0, 4)) assert Segment(Point(0, 4), Point(-2, 2)).projection(r1) == Segment(Point(0, 4), Point(-1, 3)) assert l1.projection(p3) == p1 assert l1.projection(Ray(p1, Point(-1, 5))) == Ray(Point(0, 0), Point(2, 2)) assert l1.projection(Ray(p1, Point(-1, 1))) == p1 assert r1.projection(Ray(Point(1, 1), Point(-1, -1))) == Point(1, 1) assert r1.projection(Ray(Point(0, 4), Point(-1, -5))) == Segment(Point(1, 1), Point(2, 2)) assert r1.projection(Segment(Point(-1, 5), Point(-5, -10))) == Segment(Point(1, 1), Point(2, 2)) assert r1.projection(Ray(Point(1, 1), Point(-1, -1))) == Point(1, 1) assert r1.projection(Ray(Point(0, 4), Point(-1, -5))) == Segment(Point(1, 1), Point(2, 2)) assert r1.projection(Segment(Point(-1, 5), Point(-5, -10))) == Segment(Point(1, 1), Point(2, 2)) assert l3.projection(Ray3D(p2, Point3D(-1, 5, 0))) == Ray3D(Point3D(0, 0, 0), Point3D(Rational(4, 3), Rational(4, 3), Rational(4, 3))) assert l3.projection(Ray3D(p2, Point3D(-1, 1, 1))) == Ray3D(Point3D(0, 0, 0), Point3D(Rational(1, 3), Rational(1, 3), Rational(1, 3))) assert l2.projection(Point3D(5, 5, 0)) == Point3D(5, 0) assert l2.projection(Line3D(Point3D(0, 1, 0), Point3D(1, 1, 0))).equals(l2) def test_perpendicular_bisector(): s1 = Segment(Point(0, 0), Point(1, 1)) aline = Line(Point(S.Half, S.Half), Point(Rational(3, 2), Rational(-1, 2))) on_line = Segment(Point(S.Half, S.Half), Point(Rational(3, 2), Rational(-1, 2))).midpoint assert s1.perpendicular_bisector().equals(aline) assert s1.perpendicular_bisector(on_line).equals(Segment(s1.midpoint, on_line)) assert s1.perpendicular_bisector(on_line + (1, 0)).equals(aline) def test_raises(): d, e = symbols('a,b', real=True) s = Segment((d, 0), (e, 0)) raises(TypeError, lambda: Line((1, 1), 1)) raises(ValueError, lambda: Line(Point(0, 0), Point(0, 0))) raises(Undecidable, lambda: Point(2 * d, 0) in s) raises(ValueError, lambda: Ray3D(Point(1.0, 1.0))) raises(ValueError, lambda: Line3D(Point3D(0, 0, 0), Point3D(0, 0, 0))) raises(TypeError, lambda: Line3D((1, 1), 1)) raises(ValueError, lambda: Line3D(Point3D(0, 0, 0))) raises(TypeError, lambda: Ray((1, 1), 1)) raises(GeometryError, lambda: Line(Point(0, 0), Point(1, 0)) .projection(Circle(Point(0, 0), 1))) def test_ray_generation(): assert Ray((1, 1), angle=pi / 4) == Ray((1, 1), (2, 2)) assert Ray((1, 1), angle=pi / 2) == Ray((1, 1), (1, 2)) assert Ray((1, 1), angle=-pi / 2) == Ray((1, 1), (1, 0)) assert Ray((1, 1), angle=-3 * pi / 2) == Ray((1, 1), (1, 2)) assert Ray((1, 1), angle=5 * pi / 2) == Ray((1, 1), (1, 2)) assert Ray((1, 1), angle=5.0 * pi / 2) == Ray((1, 1), (1, 2)) assert Ray((1, 1), angle=pi) == Ray((1, 1), (0, 1)) assert Ray((1, 1), angle=3.0 * pi) == Ray((1, 1), (0, 1)) assert Ray((1, 1), angle=4.0 * pi) == Ray((1, 1), (2, 1)) assert Ray((1, 1), angle=0) == Ray((1, 1), (2, 1)) assert Ray((1, 1), angle=4.05 * pi) == Ray(Point(1, 1), Point(2, -sqrt(5) * sqrt(2 * sqrt(5) + 10) / 4 - sqrt( 2 * sqrt(5) + 10) / 4 + 2 + sqrt(5))) assert Ray((1, 1), angle=4.02 * pi) == Ray(Point(1, 1), Point(2, 1 + tan(4.02 * pi))) assert Ray((1, 1), angle=5) == Ray((1, 1), (2, 1 + tan(5))) assert Ray3D((1, 1, 1), direction_ratio=[4, 4, 4]) == Ray3D(Point3D(1, 1, 1), Point3D(5, 5, 5)) assert Ray3D((1, 1, 1), direction_ratio=[1, 2, 3]) == Ray3D(Point3D(1, 1, 1), Point3D(2, 3, 4)) assert Ray3D((1, 1, 1), direction_ratio=[1, 1, 1]) == Ray3D(Point3D(1, 1, 1), Point3D(2, 2, 2)) def test_symbolic_intersect(): # Issue 7814. circle = Circle(Point(x, 0), y) line = Line(Point(k, z), slope=0) assert line.intersection(circle) == [Point(x + sqrt((y - z) * (y + z)), z), Point(x - sqrt((y - z) * (y + z)), z)] def test_issue_2941(): def _check(): for f, g in cartes(*[(Line, Ray, Segment)] * 2): l1 = f(a, b) l2 = g(c, d) assert l1.intersection(l2) == l2.intersection(l1) # intersect at end point c, d = (-2, -2), (-2, 0) a, b = (0, 0), (1, 1) _check() # midline intersection c, d = (-2, -3), (-2, 0) _check() def test_parameter_value(): t = Symbol('t') p1, p2 = Point(0, 1), Point(5, 6) l = Line(p1, p2) assert l.parameter_value((5, 6), t) == {t: 1} raises(ValueError, lambda: l.parameter_value((0, 0), t)) def test_bisectors(): r1 = Line3D(Point3D(0, 0, 0), Point3D(1, 0, 0)) r2 = Line3D(Point3D(0, 0, 0), Point3D(0, 1, 0)) bisections = r1.bisectors(r2) assert bisections == [Line3D(Point3D(0, 0, 0), Point3D(1, 1, 0)), Line3D(Point3D(0, 0, 0), Point3D(1, -1, 0))] ans = [Line3D(Point3D(0, 0, 0), Point3D(1, 0, 1)), Line3D(Point3D(0, 0, 0), Point3D(-1, 0, 1))] l1 = (0, 0, 0), (0, 0, 1) l2 = (0, 0), (1, 0) for a, b in cartes((Line, Segment, Ray), repeat=2): assert a(*l1).bisectors(b(*l2)) == ans def test_issue_8615(): a = Line3D(Point3D(6, 5, 0), Point3D(6, -6, 0)) b = Line3D(Point3D(6, -1, 19/10), Point3D(6, -1, 0)) assert a.intersection(b) == [Point3D(6, -1, 0)] sympy-sympy-1.9/sympy/geometry/tests/test_parabola.py000066400000000000000000000120621412543434000232740ustar00rootroot00000000000000from sympy import Rational, oo, sqrt, S from sympy import Line, Point, Point2D, Parabola, Segment2D, Ray2D from sympy import Circle, Ellipse, symbols, sign from sympy.testing.pytest import raises def test_parabola_geom(): a, b = symbols('a b') p1 = Point(0, 0) p2 = Point(3, 7) p3 = Point(0, 4) p4 = Point(6, 0) p5 = Point(a, a) d1 = Line(Point(4, 0), Point(4, 9)) d2 = Line(Point(7, 6), Point(3, 6)) d3 = Line(Point(4, 0), slope=oo) d4 = Line(Point(7, 6), slope=0) d5 = Line(Point(b, a), slope=oo) d6 = Line(Point(a, b), slope=0) half = S.Half pa1 = Parabola(None, d2) pa2 = Parabola(directrix=d1) pa3 = Parabola(p1, d1) pa4 = Parabola(p2, d2) pa5 = Parabola(p2, d4) pa6 = Parabola(p3, d2) pa7 = Parabola(p2, d1) pa8 = Parabola(p4, d1) pa9 = Parabola(p4, d3) pa10 = Parabola(p5, d5) pa11 = Parabola(p5, d6) raises(ValueError, lambda: Parabola(Point(7, 8, 9), Line(Point(6, 7), Point(7, 7)))) raises(NotImplementedError, lambda: Parabola(Point(7, 8), Line(Point(3, 7), Point(2, 9)))) raises(ValueError, lambda: Parabola(Point(0, 2), Line(Point(7, 2), Point(6, 2)))) raises(ValueError, lambda: Parabola(Point(7, 8), Point(3, 8))) # Basic Stuff assert pa1.focus == Point(0, 0) assert pa1.ambient_dimension == S(2) assert pa2 == pa3 assert pa4 != pa7 assert pa6 != pa7 assert pa6.focus == Point2D(0, 4) assert pa6.focal_length == 1 assert pa6.p_parameter == -1 assert pa6.vertex == Point2D(0, 5) assert pa6.eccentricity == 1 assert pa7.focus == Point2D(3, 7) assert pa7.focal_length == half assert pa7.p_parameter == -half assert pa7.vertex == Point2D(7*half, 7) assert pa4.focal_length == half assert pa4.p_parameter == half assert pa4.vertex == Point2D(3, 13*half) assert pa8.focal_length == 1 assert pa8.p_parameter == 1 assert pa8.vertex == Point2D(5, 0) assert pa4.focal_length == pa5.focal_length assert pa4.p_parameter == pa5.p_parameter assert pa4.vertex == pa5.vertex assert pa4.equation() == pa5.equation() assert pa8.focal_length == pa9.focal_length assert pa8.p_parameter == pa9.p_parameter assert pa8.vertex == pa9.vertex assert pa8.equation() == pa9.equation() assert pa10.focal_length == pa11.focal_length == sqrt((a - b) ** 2) / 2 # if a, b real == abs(a - b)/2 assert pa11.vertex == Point(*pa10.vertex[::-1]) == Point(a, a - sqrt((a - b)**2)*sign(a - b)/2) # change axis x->y, y->x on pa10 def test_parabola_intersection(): l1 = Line(Point(1, -2), Point(-1,-2)) l2 = Line(Point(1, 2), Point(-1,2)) l3 = Line(Point(1, 0), Point(-1,0)) p1 = Point(0,0) p2 = Point(0, -2) p3 = Point(120, -12) parabola1 = Parabola(p1, l1) # parabola with parabola assert parabola1.intersection(parabola1) == [parabola1] assert parabola1.intersection(Parabola(p1, l2)) == [Point2D(-2, 0), Point2D(2, 0)] assert parabola1.intersection(Parabola(p2, l3)) == [Point2D(0, -1)] assert parabola1.intersection(Parabola(Point(16, 0), l1)) == [Point2D(8, 15)] assert parabola1.intersection(Parabola(Point(0, 16), l1)) == [Point2D(-6, 8), Point2D(6, 8)] assert parabola1.intersection(Parabola(p3, l3)) == [] # parabola with point assert parabola1.intersection(p1) == [] assert parabola1.intersection(Point2D(0, -1)) == [Point2D(0, -1)] assert parabola1.intersection(Point2D(4, 3)) == [Point2D(4, 3)] # parabola with line assert parabola1.intersection(Line(Point2D(-7, 3), Point(12, 3))) == [Point2D(-4, 3), Point2D(4, 3)] assert parabola1.intersection(Line(Point(-4, -1), Point(4, -1))) == [Point(0, -1)] assert parabola1.intersection(Line(Point(2, 0), Point(0, -2))) == [Point2D(2, 0)] raises(TypeError, lambda: parabola1.intersection(Line(Point(0, 0, 0), Point(1, 1, 1)))) # parabola with segment assert parabola1.intersection(Segment2D((-4, -5), (4, 3))) == [Point2D(0, -1), Point2D(4, 3)] assert parabola1.intersection(Segment2D((0, -5), (0, 6))) == [Point2D(0, -1)] assert parabola1.intersection(Segment2D((-12, -65), (14, -68))) == [] # parabola with ray assert parabola1.intersection(Ray2D((-4, -5), (4, 3))) == [Point2D(0, -1), Point2D(4, 3)] assert parabola1.intersection(Ray2D((0, 7), (1, 14))) == [Point2D(14 + 2*sqrt(57), 105 + 14*sqrt(57))] assert parabola1.intersection(Ray2D((0, 7), (0, 14))) == [] # parabola with ellipse/circle assert parabola1.intersection(Circle(p1, 2)) == [Point2D(-2, 0), Point2D(2, 0)] assert parabola1.intersection(Circle(p2, 1)) == [Point2D(0, -1), Point2D(0, -1)] assert parabola1.intersection(Ellipse(p2, 2, 1)) == [Point2D(0, -1), Point2D(0, -1)] assert parabola1.intersection(Ellipse(Point(0, 19), 5, 7)) == [] assert parabola1.intersection(Ellipse((0, 3), 12, 4)) == \ [Point2D(0, -1), Point2D(0, -1), Point2D(-4*sqrt(17)/3, Rational(59, 9)), Point2D(4*sqrt(17)/3, Rational(59, 9))] # parabola with unsupported type raises(TypeError, lambda: parabola1.intersection(2)) sympy-sympy-1.9/sympy/geometry/tests/test_plane.py000066400000000000000000000300651412543434000226150ustar00rootroot00000000000000from sympy import Dummy, S, symbols, pi, sqrt, asin, sin, cos, Rational from sympy.geometry import Line, Point, Ray, Segment, Point3D, Line3D, Ray3D, Segment3D, Plane, Circle from sympy.geometry.util import are_coplanar from sympy.testing.pytest import raises def test_plane(): x, y, z, u, v = symbols('x y z u v', real=True) p1 = Point3D(0, 0, 0) p2 = Point3D(1, 1, 1) p3 = Point3D(1, 2, 3) pl3 = Plane(p1, p2, p3) pl4 = Plane(p1, normal_vector=(1, 1, 1)) pl4b = Plane(p1, p2) pl5 = Plane(p3, normal_vector=(1, 2, 3)) pl6 = Plane(Point3D(2, 3, 7), normal_vector=(2, 2, 2)) pl7 = Plane(Point3D(1, -5, -6), normal_vector=(1, -2, 1)) pl8 = Plane(p1, normal_vector=(0, 0, 1)) pl9 = Plane(p1, normal_vector=(0, 12, 0)) pl10 = Plane(p1, normal_vector=(-2, 0, 0)) pl11 = Plane(p2, normal_vector=(0, 0, 1)) l1 = Line3D(Point3D(5, 0, 0), Point3D(1, -1, 1)) l2 = Line3D(Point3D(0, -2, 0), Point3D(3, 1, 1)) l3 = Line3D(Point3D(0, -1, 0), Point3D(5, -1, 9)) raises(ValueError, lambda: Plane(p1, p1, p1)) assert Plane(p1, p2, p3) != Plane(p1, p3, p2) assert Plane(p1, p2, p3).is_coplanar(Plane(p1, p3, p2)) assert Plane(p1, p2, p3).is_coplanar(p1) assert Plane(p1, p2, p3).is_coplanar(Circle(p1, 1)) is False assert Plane(p1, normal_vector=(0, 0, 1)).is_coplanar(Circle(p1, 1)) assert pl3 == Plane(Point3D(0, 0, 0), normal_vector=(1, -2, 1)) assert pl3 != pl4 assert pl4 == pl4b assert pl5 == Plane(Point3D(1, 2, 3), normal_vector=(1, 2, 3)) assert pl5.equation(x, y, z) == x + 2*y + 3*z - 14 assert pl3.equation(x, y, z) == x - 2*y + z assert pl3.p1 == p1 assert pl4.p1 == p1 assert pl5.p1 == p3 assert pl4.normal_vector == (1, 1, 1) assert pl5.normal_vector == (1, 2, 3) assert p1 in pl3 assert p1 in pl4 assert p3 in pl5 assert pl3.projection(Point(0, 0)) == p1 p = pl3.projection(Point3D(1, 1, 0)) assert p == Point3D(Rational(7, 6), Rational(2, 3), Rational(1, 6)) assert p in pl3 l = pl3.projection_line(Line(Point(0, 0), Point(1, 1))) assert l == Line3D(Point3D(0, 0, 0), Point3D(Rational(7, 6), Rational(2, 3), Rational(1, 6))) assert l in pl3 # get a segment that does not intersect the plane which is also # parallel to pl3's normal veector t = Dummy() r = pl3.random_point() a = pl3.perpendicular_line(r).arbitrary_point(t) s = Segment3D(a.subs(t, 1), a.subs(t, 2)) assert s.p1 not in pl3 and s.p2 not in pl3 assert pl3.projection_line(s).equals(r) assert pl3.projection_line(Segment(Point(1, 0), Point(1, 1))) == \ Segment3D(Point3D(Rational(5, 6), Rational(1, 3), Rational(-1, 6)), Point3D(Rational(7, 6), Rational(2, 3), Rational(1, 6))) assert pl6.projection_line(Ray(Point(1, 0), Point(1, 1))) == \ Ray3D(Point3D(Rational(14, 3), Rational(11, 3), Rational(11, 3)), Point3D(Rational(13, 3), Rational(13, 3), Rational(10, 3))) assert pl3.perpendicular_line(r.args) == pl3.perpendicular_line(r) assert pl3.is_parallel(pl6) is False assert pl4.is_parallel(pl6) assert pl3.is_parallel(Line(p1, p2)) assert pl6.is_parallel(l1) is False assert pl3.is_perpendicular(pl6) assert pl4.is_perpendicular(pl7) assert pl6.is_perpendicular(pl7) assert pl6.is_perpendicular(pl4) is False assert pl6.is_perpendicular(l1) is False assert pl6.is_perpendicular(Line((0, 0, 0), (1, 1, 1))) assert pl6.is_perpendicular((1, 1)) is False assert pl6.distance(pl6.arbitrary_point(u, v)) == 0 assert pl7.distance(pl7.arbitrary_point(u, v)) == 0 assert pl6.distance(pl6.arbitrary_point(t)) == 0 assert pl7.distance(pl7.arbitrary_point(t)) == 0 assert pl6.p1.distance(pl6.arbitrary_point(t)).simplify() == 1 assert pl7.p1.distance(pl7.arbitrary_point(t)).simplify() == 1 assert pl3.arbitrary_point(t) == Point3D(-sqrt(30)*sin(t)/30 + \ 2*sqrt(5)*cos(t)/5, sqrt(30)*sin(t)/15 + sqrt(5)*cos(t)/5, sqrt(30)*sin(t)/6) assert pl3.arbitrary_point(u, v) == Point3D(2*u - v, u + 2*v, 5*v) assert pl7.distance(Point3D(1, 3, 5)) == 5*sqrt(6)/6 assert pl6.distance(Point3D(0, 0, 0)) == 4*sqrt(3) assert pl6.distance(pl6.p1) == 0 assert pl7.distance(pl6) == 0 assert pl7.distance(l1) == 0 assert pl6.distance(Segment3D(Point3D(2, 3, 1), Point3D(1, 3, 4))) == \ pl6.distance(Point3D(1, 3, 4)) == 4*sqrt(3)/3 assert pl6.distance(Segment3D(Point3D(1, 3, 4), Point3D(0, 3, 7))) == \ pl6.distance(Point3D(0, 3, 7)) == 2*sqrt(3)/3 assert pl6.distance(Segment3D(Point3D(0, 3, 7), Point3D(-1, 3, 10))) == 0 assert pl6.distance(Segment3D(Point3D(-1, 3, 10), Point3D(-2, 3, 13))) == 0 assert pl6.distance(Segment3D(Point3D(-2, 3, 13), Point3D(-3, 3, 16))) == \ pl6.distance(Point3D(-2, 3, 13)) == 2*sqrt(3)/3 assert pl6.distance(Plane(Point3D(5, 5, 5), normal_vector=(8, 8, 8))) == sqrt(3) assert pl6.distance(Ray3D(Point3D(1, 3, 4), direction_ratio=[1, 0, -3])) == 4*sqrt(3)/3 assert pl6.distance(Ray3D(Point3D(2, 3, 1), direction_ratio=[-1, 0, 3])) == 0 assert pl6.angle_between(pl3) == pi/2 assert pl6.angle_between(pl6) == 0 assert pl6.angle_between(pl4) == 0 assert pl7.angle_between(Line3D(Point3D(2, 3, 5), Point3D(2, 4, 6))) == \ -asin(sqrt(3)/6) assert pl6.angle_between(Ray3D(Point3D(2, 4, 1), Point3D(6, 5, 3))) == \ asin(sqrt(7)/3) assert pl7.angle_between(Segment3D(Point3D(5, 6, 1), Point3D(1, 2, 4))) == \ asin(7*sqrt(246)/246) assert are_coplanar(l1, l2, l3) is False assert are_coplanar(l1) is False assert are_coplanar(Point3D(2, 7, 2), Point3D(0, 0, 2), Point3D(1, 1, 2), Point3D(1, 2, 2)) assert are_coplanar(Plane(p1, p2, p3), Plane(p1, p3, p2)) assert Plane.are_concurrent(pl3, pl4, pl5) is False assert Plane.are_concurrent(pl6) is False raises(ValueError, lambda: Plane.are_concurrent(Point3D(0, 0, 0))) raises(ValueError, lambda: Plane((1, 2, 3), normal_vector=(0, 0, 0))) assert pl3.parallel_plane(Point3D(1, 2, 5)) == Plane(Point3D(1, 2, 5), \ normal_vector=(1, -2, 1)) # perpendicular_plane p = Plane((0, 0, 0), (1, 0, 0)) # default assert p.perpendicular_plane() == Plane(Point3D(0, 0, 0), (0, 1, 0)) # 1 pt assert p.perpendicular_plane(Point3D(1, 0, 1)) == \ Plane(Point3D(1, 0, 1), (0, 1, 0)) # pts as tuples assert p.perpendicular_plane((1, 0, 1), (1, 1, 1)) == \ Plane(Point3D(1, 0, 1), (0, 0, -1)) # more than two planes raises(ValueError, lambda: p.perpendicular_plane((1, 0, 1), (1, 1, 1), (1, 1, 0))) a, b = Point3D(0, 0, 0), Point3D(0, 1, 0) Z = (0, 0, 1) p = Plane(a, normal_vector=Z) # case 4 assert p.perpendicular_plane(a, b) == Plane(a, (1, 0, 0)) n = Point3D(*Z) # case 1 assert p.perpendicular_plane(a, n) == Plane(a, (-1, 0, 0)) # case 2 assert Plane(a, normal_vector=b.args).perpendicular_plane(a, a + b) == \ Plane(Point3D(0, 0, 0), (1, 0, 0)) # case 1&3 assert Plane(b, normal_vector=Z).perpendicular_plane(b, b + n) == \ Plane(Point3D(0, 1, 0), (-1, 0, 0)) # case 2&3 assert Plane(b, normal_vector=b.args).perpendicular_plane(n, n + b) == \ Plane(Point3D(0, 0, 1), (1, 0, 0)) p = Plane(a, normal_vector=(0, 0, 1)) assert p.perpendicular_plane() == Plane(a, normal_vector=(1, 0, 0)) assert pl6.intersection(pl6) == [pl6] assert pl4.intersection(pl4.p1) == [pl4.p1] assert pl3.intersection(pl6) == [ Line3D(Point3D(8, 4, 0), Point3D(2, 4, 6))] assert pl3.intersection(Line3D(Point3D(1,2,4), Point3D(4,4,2))) == [ Point3D(2, Rational(8, 3), Rational(10, 3))] assert pl3.intersection(Plane(Point3D(6, 0, 0), normal_vector=(2, -5, 3)) ) == [Line3D(Point3D(-24, -12, 0), Point3D(-25, -13, -1))] assert pl6.intersection(Ray3D(Point3D(2, 3, 1), Point3D(1, 3, 4))) == [ Point3D(-1, 3, 10)] assert pl6.intersection(Segment3D(Point3D(2, 3, 1), Point3D(1, 3, 4))) == [] assert pl7.intersection(Line(Point(2, 3), Point(4, 2))) == [ Point3D(Rational(13, 2), Rational(3, 4), 0)] r = Ray(Point(2, 3), Point(4, 2)) assert Plane((1,2,0), normal_vector=(0,0,1)).intersection(r) == [ Ray3D(Point(2, 3), Point(4, 2))] assert pl9.intersection(pl8) == [Line3D(Point3D(0, 0, 0), Point3D(12, 0, 0))] assert pl10.intersection(pl11) == [Line3D(Point3D(0, 0, 1), Point3D(0, 2, 1))] assert pl4.intersection(pl8) == [Line3D(Point3D(0, 0, 0), Point3D(1, -1, 0))] assert pl11.intersection(pl8) == [] assert pl9.intersection(pl11) == [Line3D(Point3D(0, 0, 1), Point3D(12, 0, 1))] assert pl9.intersection(pl4) == [Line3D(Point3D(0, 0, 0), Point3D(12, 0, -12))] assert pl3.random_point() in pl3 assert pl3.random_point(seed=1) in pl3 # test geometrical entity using equals assert pl4.intersection(pl4.p1)[0].equals(pl4.p1) assert pl3.intersection(pl6)[0].equals(Line3D(Point3D(8, 4, 0), Point3D(2, 4, 6))) pl8 = Plane((1, 2, 0), normal_vector=(0, 0, 1)) assert pl8.intersection(Line3D(p1, (1, 12, 0)))[0].equals(Line((0, 0, 0), (0.1, 1.2, 0))) assert pl8.intersection(Ray3D(p1, (1, 12, 0)))[0].equals(Ray((0, 0, 0), (1, 12, 0))) assert pl8.intersection(Segment3D(p1, (21, 1, 0)))[0].equals(Segment3D(p1, (21, 1, 0))) assert pl8.intersection(Plane(p1, normal_vector=(0, 0, 112)))[0].equals(pl8) assert pl8.intersection(Plane(p1, normal_vector=(0, 12, 0)))[0].equals( Line3D(p1, direction_ratio=(112 * pi, 0, 0))) assert pl8.intersection(Plane(p1, normal_vector=(11, 0, 1)))[0].equals( Line3D(p1, direction_ratio=(0, -11, 0))) assert pl8.intersection(Plane(p1, normal_vector=(1, 0, 11)))[0].equals( Line3D(p1, direction_ratio=(0, 11, 0))) assert pl8.intersection(Plane(p1, normal_vector=(-1, -1, -11)))[0].equals( Line3D(p1, direction_ratio=(1, -1, 0))) assert pl3.random_point() in pl3 assert len(pl8.intersection(Ray3D(Point3D(0, 2, 3), Point3D(1, 0, 3)))) == 0 # check if two plane are equals assert pl6.intersection(pl6)[0].equals(pl6) assert pl8.equals(Plane(p1, normal_vector=(0, 12, 0))) is False assert pl8.equals(pl8) assert pl8.equals(Plane(p1, normal_vector=(0, 0, -12))) assert pl8.equals(Plane(p1, normal_vector=(0, 0, -12*sqrt(3)))) assert pl8.equals(p1) is False # issue 8570 l2 = Line3D(Point3D(Rational(50000004459633, 5000000000000), Rational(-891926590718643, 1000000000000000), Rational(231800966893633, 100000000000000)), Point3D(Rational(50000004459633, 50000000000000), Rational(-222981647679771, 250000000000000), Rational(231800966893633, 100000000000000))) p2 = Plane(Point3D(Rational(402775636372767, 100000000000000), Rational(-97224357654973, 100000000000000), Rational(216793600814789, 100000000000000)), (-S('9.00000087501922'), -S('4.81170658872543e-13'), S('0.0'))) assert str([i.n(2) for i in p2.intersection(l2)]) == \ '[Point3D(4.0, -0.89, 2.3)]' def test_dimension_normalization(): A = Plane(Point3D(1, 1, 2), normal_vector=(1, 1, 1)) b = Point(1, 1) assert A.projection(b) == Point(Rational(5, 3), Rational(5, 3), Rational(2, 3)) a, b = Point(0, 0), Point3D(0, 1) Z = (0, 0, 1) p = Plane(a, normal_vector=Z) assert p.perpendicular_plane(a, b) == Plane(Point3D(0, 0, 0), (1, 0, 0)) assert Plane((1, 2, 1), (2, 1, 0), (3, 1, 2) ).intersection((2, 1)) == [Point(2, 1, 0)] def test_parameter_value(): t, u, v = symbols("t, u v") p1, p2, p3 = Point(0, 0, 0), Point(0, 0, 1), Point(0, 1, 0) p = Plane(p1, p2, p3) assert p.parameter_value((0, -3, 2), t) == {t: asin(2*sqrt(13)/13)} assert p.parameter_value((0, -3, 2), u, v) == {u: 3, v: 2} assert p.parameter_value(p1, t) == p1 raises(ValueError, lambda: p.parameter_value((1, 0, 0), t)) raises(ValueError, lambda: p.parameter_value(Line(Point(0, 0), Point(1, 1)), t)) raises(ValueError, lambda: p.parameter_value((0, -3, 2), t, 1)) sympy-sympy-1.9/sympy/geometry/tests/test_point.py000066400000000000000000000370561412543434000226560ustar00rootroot00000000000000from sympy import I, Rational, Symbol, pi, sqrt, sympify, S, Basic from sympy.geometry import Line, Point, Point2D, Point3D, Line3D, Plane from sympy.geometry.entity import rotate, scale, translate, GeometryEntity from sympy.matrices import Matrix from sympy.utilities.iterables import subsets, permutations, cartes from sympy.utilities.misc import Undecidable from sympy.testing.pytest import raises, warns def test_point(): x = Symbol('x', real=True) y = Symbol('y', real=True) x1 = Symbol('x1', real=True) x2 = Symbol('x2', real=True) y1 = Symbol('y1', real=True) y2 = Symbol('y2', real=True) half = S.Half p1 = Point(x1, x2) p2 = Point(y1, y2) p3 = Point(0, 0) p4 = Point(1, 1) p5 = Point(0, 1) line = Line(Point(1, 0), slope=1) assert p1 in p1 assert p1 not in p2 assert p2.y == y2 assert (p3 + p4) == p4 assert (p2 - p1) == Point(y1 - x1, y2 - x2) assert -p2 == Point(-y1, -y2) raises(TypeError, lambda: Point(1)) raises(ValueError, lambda: Point([1])) raises(ValueError, lambda: Point(3, I)) raises(ValueError, lambda: Point(2*I, I)) raises(ValueError, lambda: Point(3 + I, I)) assert Point(34.05, sqrt(3)) == Point(Rational(681, 20), sqrt(3)) assert Point.midpoint(p3, p4) == Point(half, half) assert Point.midpoint(p1, p4) == Point(half + half*x1, half + half*x2) assert Point.midpoint(p2, p2) == p2 assert p2.midpoint(p2) == p2 assert p1.origin == Point(0, 0) assert Point.distance(p3, p4) == sqrt(2) assert Point.distance(p1, p1) == 0 assert Point.distance(p3, p2) == sqrt(p2.x**2 + p2.y**2) raises(TypeError, lambda: Point.distance(p1, 0)) raises(TypeError, lambda: Point.distance(p1, GeometryEntity())) # distance should be symmetric assert p1.distance(line) == line.distance(p1) assert p4.distance(line) == line.distance(p4) assert Point.taxicab_distance(p4, p3) == 2 assert Point.canberra_distance(p4, p5) == 1 raises(ValueError, lambda: Point.canberra_distance(p3, p3)) p1_1 = Point(x1, x1) p1_2 = Point(y2, y2) p1_3 = Point(x1 + 1, x1) assert Point.is_collinear(p3) with warns(UserWarning): assert Point.is_collinear(p3, Point(p3, dim=4)) assert p3.is_collinear() assert Point.is_collinear(p3, p4) assert Point.is_collinear(p3, p4, p1_1, p1_2) assert Point.is_collinear(p3, p4, p1_1, p1_3) is False assert Point.is_collinear(p3, p3, p4, p5) is False raises(TypeError, lambda: Point.is_collinear(line)) raises(TypeError, lambda: p1_1.is_collinear(line)) assert p3.intersection(Point(0, 0)) == [p3] assert p3.intersection(p4) == [] assert p3.intersection(line) == [] assert Point.intersection(Point(0, 0, 0), Point(0, 0)) == [Point(0, 0, 0)] x_pos = Symbol('x', real=True, positive=True) p2_1 = Point(x_pos, 0) p2_2 = Point(0, x_pos) p2_3 = Point(-x_pos, 0) p2_4 = Point(0, -x_pos) p2_5 = Point(x_pos, 5) assert Point.is_concyclic(p2_1) assert Point.is_concyclic(p2_1, p2_2) assert Point.is_concyclic(p2_1, p2_2, p2_3, p2_4) for pts in permutations((p2_1, p2_2, p2_3, p2_5)): assert Point.is_concyclic(*pts) is False assert Point.is_concyclic(p4, p4 * 2, p4 * 3) is False assert Point(0, 0).is_concyclic((1, 1), (2, 2), (2, 1)) is False assert Point.is_concyclic(Point(0, 0, 0, 0), Point(1, 0, 0, 0), Point(1, 1, 0, 0), Point(1, 1, 1, 0)) is False assert p1.is_scalar_multiple(p1) assert p1.is_scalar_multiple(2*p1) assert not p1.is_scalar_multiple(p2) assert Point.is_scalar_multiple(Point(1, 1), (-1, -1)) assert Point.is_scalar_multiple(Point(0, 0), (0, -1)) # test when is_scalar_multiple can't be determined raises(Undecidable, lambda: Point.is_scalar_multiple(Point(sympify("x1%y1"), sympify("x2%y2")), Point(0, 1))) assert Point(0, 1).orthogonal_direction == Point(1, 0) assert Point(1, 0).orthogonal_direction == Point(0, 1) assert p1.is_zero is None assert p3.is_zero assert p4.is_zero is False assert p1.is_nonzero is None assert p3.is_nonzero is False assert p4.is_nonzero assert p4.scale(2, 3) == Point(2, 3) assert p3.scale(2, 3) == p3 assert p4.rotate(pi, Point(0.5, 0.5)) == p3 assert p1.__radd__(p2) == p1.midpoint(p2).scale(2, 2) assert (-p3).__rsub__(p4) == p3.midpoint(p4).scale(2, 2) assert p4 * 5 == Point(5, 5) assert p4 / 5 == Point(0.2, 0.2) assert 5 * p4 == Point(5, 5) raises(ValueError, lambda: Point(0, 0) + 10) # Point differences should be simplified assert Point(x*(x - 1), y) - Point(x**2 - x, y + 1) == Point(0, -1) a, b = S.Half, Rational(1, 3) assert Point(a, b).evalf(2) == \ Point(a.n(2), b.n(2), evaluate=False) raises(ValueError, lambda: Point(1, 2) + 1) # test project assert Point.project((0, 1), (1, 0)) == Point(0, 0) assert Point.project((1, 1), (1, 0)) == Point(1, 0) raises(ValueError, lambda: Point.project(p1, Point(0, 0))) # test transformations p = Point(1, 0) assert p.rotate(pi/2) == Point(0, 1) assert p.rotate(pi/2, p) == p p = Point(1, 1) assert p.scale(2, 3) == Point(2, 3) assert p.translate(1, 2) == Point(2, 3) assert p.translate(1) == Point(2, 1) assert p.translate(y=1) == Point(1, 2) assert p.translate(*p.args) == Point(2, 2) # Check invalid input for transform raises(ValueError, lambda: p3.transform(p3)) raises(ValueError, lambda: p.transform(Matrix([[1, 0], [0, 1]]))) # test __contains__ assert 0 in Point(0, 0, 0, 0) assert 1 not in Point(0, 0, 0, 0) # test affine_rank assert Point.affine_rank() == -1 def test_point3D(): x = Symbol('x', real=True) y = Symbol('y', real=True) x1 = Symbol('x1', real=True) x2 = Symbol('x2', real=True) x3 = Symbol('x3', real=True) y1 = Symbol('y1', real=True) y2 = Symbol('y2', real=True) y3 = Symbol('y3', real=True) half = S.Half p1 = Point3D(x1, x2, x3) p2 = Point3D(y1, y2, y3) p3 = Point3D(0, 0, 0) p4 = Point3D(1, 1, 1) p5 = Point3D(0, 1, 2) assert p1 in p1 assert p1 not in p2 assert p2.y == y2 assert (p3 + p4) == p4 assert (p2 - p1) == Point3D(y1 - x1, y2 - x2, y3 - x3) assert -p2 == Point3D(-y1, -y2, -y3) assert Point(34.05, sqrt(3)) == Point(Rational(681, 20), sqrt(3)) assert Point3D.midpoint(p3, p4) == Point3D(half, half, half) assert Point3D.midpoint(p1, p4) == Point3D(half + half*x1, half + half*x2, half + half*x3) assert Point3D.midpoint(p2, p2) == p2 assert p2.midpoint(p2) == p2 assert Point3D.distance(p3, p4) == sqrt(3) assert Point3D.distance(p1, p1) == 0 assert Point3D.distance(p3, p2) == sqrt(p2.x**2 + p2.y**2 + p2.z**2) p1_1 = Point3D(x1, x1, x1) p1_2 = Point3D(y2, y2, y2) p1_3 = Point3D(x1 + 1, x1, x1) Point3D.are_collinear(p3) assert Point3D.are_collinear(p3, p4) assert Point3D.are_collinear(p3, p4, p1_1, p1_2) assert Point3D.are_collinear(p3, p4, p1_1, p1_3) is False assert Point3D.are_collinear(p3, p3, p4, p5) is False assert p3.intersection(Point3D(0, 0, 0)) == [p3] assert p3.intersection(p4) == [] assert p4 * 5 == Point3D(5, 5, 5) assert p4 / 5 == Point3D(0.2, 0.2, 0.2) assert 5 * p4 == Point3D(5, 5, 5) raises(ValueError, lambda: Point3D(0, 0, 0) + 10) # Test coordinate properties assert p1.coordinates == (x1, x2, x3) assert p2.coordinates == (y1, y2, y3) assert p3.coordinates == (0, 0, 0) assert p4.coordinates == (1, 1, 1) assert p5.coordinates == (0, 1, 2) assert p5.x == 0 assert p5.y == 1 assert p5.z == 2 # Point differences should be simplified assert Point3D(x*(x - 1), y, 2) - Point3D(x**2 - x, y + 1, 1) == \ Point3D(0, -1, 1) a, b, c = S.Half, Rational(1, 3), Rational(1, 4) assert Point3D(a, b, c).evalf(2) == \ Point(a.n(2), b.n(2), c.n(2), evaluate=False) raises(ValueError, lambda: Point3D(1, 2, 3) + 1) # test transformations p = Point3D(1, 1, 1) assert p.scale(2, 3) == Point3D(2, 3, 1) assert p.translate(1, 2) == Point3D(2, 3, 1) assert p.translate(1) == Point3D(2, 1, 1) assert p.translate(z=1) == Point3D(1, 1, 2) assert p.translate(*p.args) == Point3D(2, 2, 2) # Test __new__ assert Point3D(0.1, 0.2, evaluate=False, on_morph='ignore').args[0].is_Float # Test length property returns correctly assert p.length == 0 assert p1_1.length == 0 assert p1_2.length == 0 # Test are_colinear type error raises(TypeError, lambda: Point3D.are_collinear(p, x)) # Test are_coplanar assert Point.are_coplanar() assert Point.are_coplanar((1, 2, 0), (1, 2, 0), (1, 3, 0)) assert Point.are_coplanar((1, 2, 0), (1, 2, 3)) with warns(UserWarning): raises(ValueError, lambda: Point2D.are_coplanar((1, 2), (1, 2, 3))) assert Point3D.are_coplanar((1, 2, 0), (1, 2, 3)) assert Point.are_coplanar((0, 0, 0), (1, 1, 0), (1, 1, 1), (1, 2, 1)) is False planar2 = Point3D(1, -1, 1) planar3 = Point3D(-1, 1, 1) assert Point3D.are_coplanar(p, planar2, planar3) == True assert Point3D.are_coplanar(p, planar2, planar3, p3) == False assert Point.are_coplanar(p, planar2) planar2 = Point3D(1, 1, 2) planar3 = Point3D(1, 1, 3) assert Point3D.are_coplanar(p, planar2, planar3) # line, not plane plane = Plane((1, 2, 1), (2, 1, 0), (3, 1, 2)) assert Point.are_coplanar(*[plane.projection(((-1)**i, i)) for i in range(4)]) # all 2D points are coplanar assert Point.are_coplanar(Point(x, y), Point(x, x + y), Point(y, x + 2)) is True # Test Intersection assert planar2.intersection(Line3D(p, planar3)) == [Point3D(1, 1, 2)] # Test Scale assert planar2.scale(1, 1, 1) == planar2 assert planar2.scale(2, 2, 2, planar3) == Point3D(1, 1, 1) assert planar2.scale(1, 1, 1, p3) == planar2 # Test Transform identity = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) assert p.transform(identity) == p trans = Matrix([[1, 0, 0, 1], [0, 1, 0, 1], [0, 0, 1, 1], [0, 0, 0, 1]]) assert p.transform(trans) == Point3D(2, 2, 2) raises(ValueError, lambda: p.transform(p)) raises(ValueError, lambda: p.transform(Matrix([[1, 0], [0, 1]]))) # Test Equals assert p.equals(x1) == False # Test __sub__ p_4d = Point(0, 0, 0, 1) with warns(UserWarning): assert p - p_4d == Point(1, 1, 1, -1) p_4d3d = Point(0, 0, 1, 0) with warns(UserWarning): assert p - p_4d3d == Point(1, 1, 0, 0) def test_Point2D(): # Test Distance p1 = Point2D(1, 5) p2 = Point2D(4, 2.5) p3 = (6, 3) assert p1.distance(p2) == sqrt(61)/2 assert p2.distance(p3) == sqrt(17)/2 # Test coordinates assert p1.x == 1 assert p1.y == 5 assert p2.x == 4 assert p2.y == 2.5 assert p1.coordinates == (1, 5) assert p2.coordinates == (4, 2.5) # test bounds assert p1.bounds == (1, 5, 1, 5) def test_issue_9214(): p1 = Point3D(4, -2, 6) p2 = Point3D(1, 2, 3) p3 = Point3D(7, 2, 3) assert Point3D.are_collinear(p1, p2, p3) is False def test_issue_11617(): p1 = Point3D(1,0,2) p2 = Point2D(2,0) with warns(UserWarning): assert p1.distance(p2) == sqrt(5) def test_transform(): p = Point(1, 1) assert p.transform(rotate(pi/2)) == Point(-1, 1) assert p.transform(scale(3, 2)) == Point(3, 2) assert p.transform(translate(1, 2)) == Point(2, 3) assert Point(1, 1).scale(2, 3, (4, 5)) == \ Point(-2, -7) assert Point(1, 1).translate(4, 5) == \ Point(5, 6) def test_concyclic_doctest_bug(): p1, p2 = Point(-1, 0), Point(1, 0) p3, p4 = Point(0, 1), Point(-1, 2) assert Point.is_concyclic(p1, p2, p3) assert not Point.is_concyclic(p1, p2, p3, p4) def test_arguments(): """Functions accepting `Point` objects in `geometry` should also accept tuples and lists and automatically convert them to points.""" singles2d = ((1,2), [1,2], Point(1,2)) singles2d2 = ((1,3), [1,3], Point(1,3)) doubles2d = cartes(singles2d, singles2d2) p2d = Point2D(1,2) singles3d = ((1,2,3), [1,2,3], Point(1,2,3)) doubles3d = subsets(singles3d, 2) p3d = Point3D(1,2,3) singles4d = ((1,2,3,4), [1,2,3,4], Point(1,2,3,4)) doubles4d = subsets(singles4d, 2) p4d = Point(1,2,3,4) # test 2D test_single = ['distance', 'is_scalar_multiple', 'taxicab_distance', 'midpoint', 'intersection', 'dot', 'equals', '__add__', '__sub__'] test_double = ['is_concyclic', 'is_collinear'] for p in singles2d: Point2D(p) for func in test_single: for p in singles2d: getattr(p2d, func)(p) for func in test_double: for p in doubles2d: getattr(p2d, func)(*p) # test 3D test_double = ['is_collinear'] for p in singles3d: Point3D(p) for func in test_single: for p in singles3d: getattr(p3d, func)(p) for func in test_double: for p in doubles3d: getattr(p3d, func)(*p) # test 4D test_double = ['is_collinear'] for p in singles4d: Point(p) for func in test_single: for p in singles4d: getattr(p4d, func)(p) for func in test_double: for p in doubles4d: getattr(p4d, func)(*p) # test evaluate=False for ops x = Symbol('x') a = Point(0, 1) assert a + (0.1, x) == Point(0.1, 1 + x, evaluate=False) a = Point(0, 1) assert a/10.0 == Point(0, 0.1, evaluate=False) a = Point(0, 1) assert a*10.0 == Point(0.0, 10.0, evaluate=False) # test evaluate=False when changing dimensions u = Point(.1, .2, evaluate=False) u4 = Point(u, dim=4, on_morph='ignore') assert u4.args == (.1, .2, 0, 0) assert all(i.is_Float for i in u4.args[:2]) # and even when *not* changing dimensions assert all(i.is_Float for i in Point(u).args) # never raise error if creating an origin assert Point(dim=3, on_morph='error') # raise error with unmatched dimension raises(ValueError, lambda: Point(1, 1, dim=3, on_morph='error')) # test unknown on_morph raises(ValueError, lambda: Point(1, 1, dim=3, on_morph='unknown')) # test invalid expressions raises(TypeError, lambda: Point(Basic(), Basic())) def test_unit(): assert Point(1, 1).unit == Point(sqrt(2)/2, sqrt(2)/2) def test_dot(): raises(TypeError, lambda: Point(1, 2).dot(Line((0, 0), (1, 1)))) def test__normalize_dimension(): assert Point._normalize_dimension(Point(1, 2), Point(3, 4)) == [ Point(1, 2), Point(3, 4)] assert Point._normalize_dimension( Point(1, 2), Point(3, 4, 0), on_morph='ignore') == [ Point(1, 2, 0), Point(3, 4, 0)] def test_direction_cosine(): p1 = Point3D(0, 0, 0) p2 = Point3D(1, 1, 1) assert p1.direction_cosine(Point3D(1, 0, 0)) == [1, 0, 0] assert p1.direction_cosine(Point3D(0, 1, 0)) == [0, 1, 0] assert p1.direction_cosine(Point3D(0, 0, pi)) == [0, 0, 1] assert p1.direction_cosine(Point3D(5, 0, 0)) == [1, 0, 0] assert p1.direction_cosine(Point3D(0, sqrt(3), 0)) == [0, 1, 0] assert p1.direction_cosine(Point3D(0, 0, 5)) == [0, 0, 1] assert p1.direction_cosine(Point3D(2.4, 2.4, 0)) == [sqrt(2)/2, sqrt(2)/2, 0] assert p1.direction_cosine(Point3D(1, 1, 1)) == [sqrt(3) / 3, sqrt(3) / 3, sqrt(3) / 3] assert p1.direction_cosine(Point3D(-12, 0 -15)) == [-4*sqrt(41)/41, -5*sqrt(41)/41, 0] assert p2.direction_cosine(Point3D(0, 0, 0)) == [-sqrt(3) / 3, -sqrt(3) / 3, -sqrt(3) / 3] assert p2.direction_cosine(Point3D(1, 1, 12)) == [0, 0, 1] assert p2.direction_cosine(Point3D(12, 1, 12)) == [sqrt(2) / 2, 0, sqrt(2) / 2] sympy-sympy-1.9/sympy/geometry/tests/test_polygon.py000066400000000000000000000643651412543434000232170ustar00rootroot00000000000000from sympy import (Abs, Rational, Float, S, Symbol, symbols, cos, sin, pi, sqrt, \ oo, acos) from sympy.functions.elementary.trigonometric import tan from sympy.geometry import (Circle, Ellipse, GeometryError, Point, Point2D, \ Polygon, Ray, RegularPolygon, Segment, Triangle, \ are_similar, convex_hull, intersection, Line, Ray2D) from sympy.testing.pytest import raises, slow, warns from sympy.testing.randtest import verify_numerically from sympy.geometry.polygon import rad, deg from sympy import integrate def feq(a, b): """Test if two floating point values are 'equal'.""" t_float = Float("1.0E-10") return -t_float < a - b < t_float @slow def test_polygon(): x = Symbol('x', real=True) y = Symbol('y', real=True) q = Symbol('q', real=True) u = Symbol('u', real=True) v = Symbol('v', real=True) w = Symbol('w', real=True) x1 = Symbol('x1', real=True) half = S.Half a, b, c = Point(0, 0), Point(2, 0), Point(3, 3) t = Triangle(a, b, c) assert Polygon(Point(0, 0)) == Point(0, 0) assert Polygon(a, Point(1, 0), b, c) == t assert Polygon(Point(1, 0), b, c, a) == t assert Polygon(b, c, a, Point(1, 0)) == t # 2 "remove folded" tests assert Polygon(a, Point(3, 0), b, c) == t assert Polygon(a, b, Point(3, -1), b, c) == t # remove multiple collinear points assert Polygon(Point(-4, 15), Point(-11, 15), Point(-15, 15), Point(-15, 33/5), Point(-15, -87/10), Point(-15, -15), Point(-42/5, -15), Point(-2, -15), Point(7, -15), Point(15, -15), Point(15, -3), Point(15, 10), Point(15, 15)) == \ Polygon(Point(-15, -15), Point(15, -15), Point(15, 15), Point(-15, 15)) p1 = Polygon( Point(0, 0), Point(3, -1), Point(6, 0), Point(4, 5), Point(2, 3), Point(0, 3)) p2 = Polygon( Point(6, 0), Point(3, -1), Point(0, 0), Point(0, 3), Point(2, 3), Point(4, 5)) p3 = Polygon( Point(0, 0), Point(3, 0), Point(5, 2), Point(4, 4)) p4 = Polygon( Point(0, 0), Point(4, 4), Point(5, 2), Point(3, 0)) p5 = Polygon( Point(0, 0), Point(4, 4), Point(0, 4)) p6 = Polygon( Point(-11, 1), Point(-9, 6.6), Point(-4, -3), Point(-8.4, -8.7)) p7 = Polygon( Point(x, y), Point(q, u), Point(v, w)) p8 = Polygon( Point(x, y), Point(v, w), Point(q, u)) p9 = Polygon( Point(0, 0), Point(4, 4), Point(3, 0), Point(5, 2)) p10 = Polygon( Point(0, 2), Point(2, 2), Point(0, 0), Point(2, 0)) p11 = Polygon(Point(0, 0), 1, n=3) p12 = Polygon(Point(0, 0), 1, 0, n=3) r = Ray(Point(-9, 6.6), Point(-9, 5.5)) # # General polygon # assert p1 == p2 assert len(p1.args) == 6 assert len(p1.sides) == 6 assert p1.perimeter == 5 + 2*sqrt(10) + sqrt(29) + sqrt(8) assert p1.area == 22 assert not p1.is_convex() assert Polygon((-1, 1), (2, -1), (2, 1), (-1, -1), (3, 0) ).is_convex() is False # ensure convex for both CW and CCW point specification assert p3.is_convex() assert p4.is_convex() dict5 = p5.angles assert dict5[Point(0, 0)] == pi / 4 assert dict5[Point(0, 4)] == pi / 2 assert p5.encloses_point(Point(x, y)) is None assert p5.encloses_point(Point(1, 3)) assert p5.encloses_point(Point(0, 0)) is False assert p5.encloses_point(Point(4, 0)) is False assert p1.encloses(Circle(Point(2.5, 2.5), 5)) is False assert p1.encloses(Ellipse(Point(2.5, 2), 5, 6)) is False p5.plot_interval('x') == [x, 0, 1] assert p5.distance( Polygon(Point(10, 10), Point(14, 14), Point(10, 14))) == 6 * sqrt(2) assert p5.distance( Polygon(Point(1, 8), Point(5, 8), Point(8, 12), Point(1, 12))) == 4 with warns(UserWarning, \ match="Polygons may intersect producing erroneous output"): Polygon(Point(0, 0), Point(1, 0), Point(1, 1)).distance( Polygon(Point(0, 0), Point(0, 1), Point(1, 1))) assert hash(p5) == hash(Polygon(Point(0, 0), Point(4, 4), Point(0, 4))) assert hash(p1) == hash(p2) assert hash(p7) == hash(p8) assert hash(p3) != hash(p9) assert p5 == Polygon(Point(4, 4), Point(0, 4), Point(0, 0)) assert Polygon(Point(4, 4), Point(0, 4), Point(0, 0)) in p5 assert p5 != Point(0, 4) assert Point(0, 1) in p5 assert p5.arbitrary_point('t').subs(Symbol('t', real=True), 0) == \ Point(0, 0) raises(ValueError, lambda: Polygon( Point(x, 0), Point(0, y), Point(x, y)).arbitrary_point('x')) assert p6.intersection(r) == [Point(-9, Rational(-84, 13)), Point(-9, Rational(33, 5))] assert p10.area == 0 assert p11 == RegularPolygon(Point(0, 0), 1, 3, 0) assert p11 == p12 assert p11.vertices[0] == Point(1, 0) assert p11.args[0] == Point(0, 0) p11.spin(pi/2) assert p11.vertices[0] == Point(0, 1) # # Regular polygon # p1 = RegularPolygon(Point(0, 0), 10, 5) p2 = RegularPolygon(Point(0, 0), 5, 5) raises(GeometryError, lambda: RegularPolygon(Point(0, 0), Point(0, 1), Point(1, 1))) raises(GeometryError, lambda: RegularPolygon(Point(0, 0), 1, 2)) raises(ValueError, lambda: RegularPolygon(Point(0, 0), 1, 2.5)) assert p1 != p2 assert p1.interior_angle == pi*Rational(3, 5) assert p1.exterior_angle == pi*Rational(2, 5) assert p2.apothem == 5*cos(pi/5) assert p2.circumcenter == p1.circumcenter == Point(0, 0) assert p1.circumradius == p1.radius == 10 assert p2.circumcircle == Circle(Point(0, 0), 5) assert p2.incircle == Circle(Point(0, 0), p2.apothem) assert p2.inradius == p2.apothem == (5 * (1 + sqrt(5)) / 4) p2.spin(pi / 10) dict1 = p2.angles assert dict1[Point(0, 5)] == 3 * pi / 5 assert p1.is_convex() assert p1.rotation == 0 assert p1.encloses_point(Point(0, 0)) assert p1.encloses_point(Point(11, 0)) is False assert p2.encloses_point(Point(0, 4.9)) p1.spin(pi/3) assert p1.rotation == pi/3 assert p1.vertices[0] == Point(5, 5*sqrt(3)) for var in p1.args: if isinstance(var, Point): assert var == Point(0, 0) else: assert var == 5 or var == 10 or var == pi / 3 assert p1 != Point(0, 0) assert p1 != p5 # while spin works in place (notice that rotation is 2pi/3 below) # rotate returns a new object p1_old = p1 assert p1.rotate(pi/3) == RegularPolygon(Point(0, 0), 10, 5, pi*Rational(2, 3)) assert p1 == p1_old assert p1.area == (-250*sqrt(5) + 1250)/(4*tan(pi/5)) assert p1.length == 20*sqrt(-sqrt(5)/8 + Rational(5, 8)) assert p1.scale(2, 2) == \ RegularPolygon(p1.center, p1.radius*2, p1._n, p1.rotation) assert RegularPolygon((0, 0), 1, 4).scale(2, 3) == \ Polygon(Point(2, 0), Point(0, 3), Point(-2, 0), Point(0, -3)) assert repr(p1) == str(p1) # # Angles # angles = p4.angles assert feq(angles[Point(0, 0)].evalf(), Float("0.7853981633974483")) assert feq(angles[Point(4, 4)].evalf(), Float("1.2490457723982544")) assert feq(angles[Point(5, 2)].evalf(), Float("1.8925468811915388")) assert feq(angles[Point(3, 0)].evalf(), Float("2.3561944901923449")) angles = p3.angles assert feq(angles[Point(0, 0)].evalf(), Float("0.7853981633974483")) assert feq(angles[Point(4, 4)].evalf(), Float("1.2490457723982544")) assert feq(angles[Point(5, 2)].evalf(), Float("1.8925468811915388")) assert feq(angles[Point(3, 0)].evalf(), Float("2.3561944901923449")) # # Triangle # p1 = Point(0, 0) p2 = Point(5, 0) p3 = Point(0, 5) t1 = Triangle(p1, p2, p3) t2 = Triangle(p1, p2, Point(Rational(5, 2), sqrt(Rational(75, 4)))) t3 = Triangle(p1, Point(x1, 0), Point(0, x1)) s1 = t1.sides assert Triangle(p1, p2, p1) == Polygon(p1, p2, p1) == Segment(p1, p2) raises(GeometryError, lambda: Triangle(Point(0, 0))) # Basic stuff assert Triangle(p1, p1, p1) == p1 assert Triangle(p2, p2*2, p2*3) == Segment(p2, p2*3) assert t1.area == Rational(25, 2) assert t1.is_right() assert t2.is_right() is False assert t3.is_right() assert p1 in t1 assert t1.sides[0] in t1 assert Segment((0, 0), (1, 0)) in t1 assert Point(5, 5) not in t2 assert t1.is_convex() assert feq(t1.angles[p1].evalf(), pi.evalf()/2) assert t1.is_equilateral() is False assert t2.is_equilateral() assert t3.is_equilateral() is False assert are_similar(t1, t2) is False assert are_similar(t1, t3) assert are_similar(t2, t3) is False assert t1.is_similar(Point(0, 0)) is False assert t1.is_similar(t2) is False # Bisectors bisectors = t1.bisectors() assert bisectors[p1] == Segment( p1, Point(Rational(5, 2), Rational(5, 2))) assert t2.bisectors()[p2] == Segment( Point(5, 0), Point(Rational(5, 4), 5*sqrt(3)/4)) p4 = Point(0, x1) assert t3.bisectors()[p4] == Segment(p4, Point(x1*(sqrt(2) - 1), 0)) ic = (250 - 125*sqrt(2))/50 assert t1.incenter == Point(ic, ic) # Inradius assert t1.inradius == t1.incircle.radius == 5 - 5*sqrt(2)/2 assert t2.inradius == t2.incircle.radius == 5*sqrt(3)/6 assert t3.inradius == t3.incircle.radius == x1**2/((2 + sqrt(2))*Abs(x1)) # Exradius assert t1.exradii[t1.sides[2]] == 5*sqrt(2)/2 # Excenters assert t1.excenters[t1.sides[2]] == Point2D(25*sqrt(2), -5*sqrt(2)/2) # Circumcircle assert t1.circumcircle.center == Point(2.5, 2.5) # Medians + Centroid m = t1.medians assert t1.centroid == Point(Rational(5, 3), Rational(5, 3)) assert m[p1] == Segment(p1, Point(Rational(5, 2), Rational(5, 2))) assert t3.medians[p1] == Segment(p1, Point(x1/2, x1/2)) assert intersection(m[p1], m[p2], m[p3]) == [t1.centroid] assert t1.medial == Triangle(Point(2.5, 0), Point(0, 2.5), Point(2.5, 2.5)) # Nine-point circle assert t1.nine_point_circle == Circle(Point(2.5, 0), Point(0, 2.5), Point(2.5, 2.5)) assert t1.nine_point_circle == Circle(Point(0, 0), Point(0, 2.5), Point(2.5, 2.5)) # Perpendicular altitudes = t1.altitudes assert altitudes[p1] == Segment(p1, Point(Rational(5, 2), Rational(5, 2))) assert altitudes[p2].equals(s1[0]) assert altitudes[p3] == s1[2] assert t1.orthocenter == p1 t = S('''Triangle( Point(100080156402737/5000000000000, 79782624633431/500000000000), Point(39223884078253/2000000000000, 156345163124289/1000000000000), Point(31241359188437/1250000000000, 338338270939941/1000000000000000))''') assert t.orthocenter == S('''Point(-780660869050599840216997''' '''79471538701955848721853/80368430960602242240789074233100000000000000,''' '''20151573611150265741278060334545897615974257/16073686192120448448157''' '''8148466200000000000)''') # Ensure assert len(intersection(*bisectors.values())) == 1 assert len(intersection(*altitudes.values())) == 1 assert len(intersection(*m.values())) == 1 # Distance p1 = Polygon( Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1)) p2 = Polygon( Point(0, Rational(5)/4), Point(1, Rational(5)/4), Point(1, Rational(9)/4), Point(0, Rational(9)/4)) p3 = Polygon( Point(1, 2), Point(2, 2), Point(2, 1)) p4 = Polygon( Point(1, 1), Point(Rational(6)/5, 1), Point(1, Rational(6)/5)) pt1 = Point(half, half) pt2 = Point(1, 1) '''Polygon to Point''' assert p1.distance(pt1) == half assert p1.distance(pt2) == 0 assert p2.distance(pt1) == Rational(3)/4 assert p3.distance(pt2) == sqrt(2)/2 '''Polygon to Polygon''' # p1.distance(p2) emits a warning with warns(UserWarning, \ match="Polygons may intersect producing erroneous output"): assert p1.distance(p2) == half/2 assert p1.distance(p3) == sqrt(2)/2 # p3.distance(p4) emits a warning with warns(UserWarning, \ match="Polygons may intersect producing erroneous output"): assert p3.distance(p4) == (sqrt(2)/2 - sqrt(Rational(2)/25)/2) def test_convex_hull(): p = [Point(-5, -1), Point(-2, 1), Point(-2, -1), Point(-1, -3), \ Point(0, 0), Point(1, 1), Point(2, 2), Point(2, -1), Point(3, 1), \ Point(4, -1), Point(6, 2)] ch = Polygon(p[0], p[3], p[9], p[10], p[6], p[1]) #test handling of duplicate points p.append(p[3]) #more than 3 collinear points another_p = [Point(-45, -85), Point(-45, 85), Point(-45, 26), \ Point(-45, -24)] ch2 = Segment(another_p[0], another_p[1]) assert convex_hull(*another_p) == ch2 assert convex_hull(*p) == ch assert convex_hull(p[0]) == p[0] assert convex_hull(p[0], p[1]) == Segment(p[0], p[1]) # no unique points assert convex_hull(*[p[-1]]*3) == p[-1] # collection of items assert convex_hull(*[Point(0, 0), \ Segment(Point(1, 0), Point(1, 1)), \ RegularPolygon(Point(2, 0), 2, 4)]) == \ Polygon(Point(0, 0), Point(2, -2), Point(4, 0), Point(2, 2)) def test_encloses(): # square with a dimpled left side s = Polygon(Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1), \ Point(S.Half, S.Half)) # the following is True if the polygon isn't treated as closing on itself assert s.encloses(Point(0, S.Half)) is False assert s.encloses(Point(S.Half, S.Half)) is False # it's a vertex assert s.encloses(Point(Rational(3, 4), S.Half)) is True def test_triangle_kwargs(): assert Triangle(sss=(3, 4, 5)) == \ Triangle(Point(0, 0), Point(3, 0), Point(3, 4)) assert Triangle(asa=(30, 2, 30)) == \ Triangle(Point(0, 0), Point(2, 0), Point(1, sqrt(3)/3)) assert Triangle(sas=(1, 45, 2)) == \ Triangle(Point(0, 0), Point(2, 0), Point(sqrt(2)/2, sqrt(2)/2)) assert Triangle(sss=(1, 2, 5)) is None assert deg(rad(180)) == 180 def test_transform(): pts = [Point(0, 0), Point(S.Half, Rational(1, 4)), Point(1, 1)] pts_out = [Point(-4, -10), Point(-3, Rational(-37, 4)), Point(-2, -7)] assert Triangle(*pts).scale(2, 3, (4, 5)) == Triangle(*pts_out) assert RegularPolygon((0, 0), 1, 4).scale(2, 3, (4, 5)) == \ Polygon(Point(-2, -10), Point(-4, -7), Point(-6, -10), Point(-4, -13)) # Checks for symmetric scaling assert RegularPolygon((0, 0), 1, 4).scale(2, 2) == \ RegularPolygon(Point2D(0, 0), 2, 4, 0) def test_reflect(): x = Symbol('x', real=True) y = Symbol('y', real=True) b = Symbol('b') m = Symbol('m') l = Line((0, b), slope=m) p = Point(x, y) r = p.reflect(l) dp = l.perpendicular_segment(p).length dr = l.perpendicular_segment(r).length assert verify_numerically(dp, dr) assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((3, 0), slope=oo)) \ == Triangle(Point(5, 0), Point(4, 0), Point(4, 2)) assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((0, 3), slope=oo)) \ == Triangle(Point(-1, 0), Point(-2, 0), Point(-2, 2)) assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((0, 3), slope=0)) \ == Triangle(Point(1, 6), Point(2, 6), Point(2, 4)) assert Polygon((1, 0), (2, 0), (2, 2)).reflect(Line((3, 0), slope=0)) \ == Triangle(Point(1, 0), Point(2, 0), Point(2, -2)) def test_bisectors(): p1, p2, p3 = Point(0, 0), Point(1, 0), Point(0, 1) p = Polygon(Point(0, 0), Point(2, 0), Point(1, 1), Point(0, 3)) q = Polygon(Point(1, 0), Point(2, 0), Point(3, 3), Point(-1, 5)) poly = Polygon(Point(3, 4), Point(0, 0), Point(8, 7), Point(-1, 1), Point(19, -19)) t = Triangle(p1, p2, p3) assert t.bisectors()[p2] == Segment(Point(1, 0), Point(0, sqrt(2) - 1)) assert p.bisectors()[Point2D(0, 3)] == Ray2D(Point2D(0, 3), \ Point2D(sin(acos(2*sqrt(5)/5)/2), 3 - cos(acos(2*sqrt(5)/5)/2))) assert q.bisectors()[Point2D(-1, 5)] == \ Ray2D(Point2D(-1, 5), Point2D(-1 + sqrt(29)*(5*sin(acos(9*sqrt(145)/145)/2) + \ 2*cos(acos(9*sqrt(145)/145)/2))/29, sqrt(29)*(-5*cos(acos(9*sqrt(145)/145)/2) + \ 2*sin(acos(9*sqrt(145)/145)/2))/29 + 5)) assert poly.bisectors()[Point2D(-1, 1)] == Ray2D(Point2D(-1, 1), \ Point2D(-1 + sin(acos(sqrt(26)/26)/2 + pi/4), 1 - sin(-acos(sqrt(26)/26)/2 + pi/4))) def test_incenter(): assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).incenter \ == Point(1 - sqrt(2)/2, 1 - sqrt(2)/2) def test_inradius(): assert Triangle(Point(0, 0), Point(4, 0), Point(0, 3)).inradius == 1 def test_incircle(): assert Triangle(Point(0, 0), Point(2, 0), Point(0, 2)).incircle \ == Circle(Point(2 - sqrt(2), 2 - sqrt(2)), 2 - sqrt(2)) def test_exradii(): t = Triangle(Point(0, 0), Point(6, 0), Point(0, 2)) assert t.exradii[t.sides[2]] == (-2 + sqrt(10)) def test_medians(): t = Triangle(Point(0, 0), Point(1, 0), Point(0, 1)) assert t.medians[Point(0, 0)] == Segment(Point(0, 0), Point(S.Half, S.Half)) def test_medial(): assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).medial \ == Triangle(Point(S.Half, 0), Point(S.Half, S.Half), Point(0, S.Half)) def test_nine_point_circle(): assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).nine_point_circle \ == Circle(Point2D(Rational(1, 4), Rational(1, 4)), sqrt(2)/4) def test_eulerline(): assert Triangle(Point(0, 0), Point(1, 0), Point(0, 1)).eulerline \ == Line(Point2D(0, 0), Point2D(S.Half, S.Half)) assert Triangle(Point(0, 0), Point(10, 0), Point(5, 5*sqrt(3))).eulerline \ == Point2D(5, 5*sqrt(3)/3) assert Triangle(Point(4, -6), Point(4, -1), Point(-3, 3)).eulerline \ == Line(Point2D(Rational(64, 7), 3), Point2D(Rational(-29, 14), Rational(-7, 2))) def test_intersection(): poly1 = Triangle(Point(0, 0), Point(1, 0), Point(0, 1)) poly2 = Polygon(Point(0, 1), Point(-5, 0), Point(0, -4), Point(0, Rational(1, 5)), Point(S.Half, -0.1), Point(1, 0), Point(0, 1)) assert poly1.intersection(poly2) == [Point2D(Rational(1, 3), 0), Segment(Point(0, Rational(1, 5)), Point(0, 0)), Segment(Point(1, 0), Point(0, 1))] assert poly2.intersection(poly1) == [Point(Rational(1, 3), 0), Segment(Point(0, 0), Point(0, Rational(1, 5))), Segment(Point(1, 0), Point(0, 1))] assert poly1.intersection(Point(0, 0)) == [Point(0, 0)] assert poly1.intersection(Point(-12, -43)) == [] assert poly2.intersection(Line((-12, 0), (12, 0))) == [Point(-5, 0), Point(0, 0), Point(Rational(1, 3), 0), Point(1, 0)] assert poly2.intersection(Line((-12, 12), (12, 12))) == [] assert poly2.intersection(Ray((-3, 4), (1, 0))) == [Segment(Point(1, 0), Point(0, 1))] assert poly2.intersection(Circle((0, -1), 1)) == [Point(0, -2), Point(0, 0)] assert poly1.intersection(poly1) == [Segment(Point(0, 0), Point(1, 0)), Segment(Point(0, 1), Point(0, 0)), Segment(Point(1, 0), Point(0, 1))] assert poly2.intersection(poly2) == [Segment(Point(-5, 0), Point(0, -4)), Segment(Point(0, -4), Point(0, Rational(1, 5))), Segment(Point(0, Rational(1, 5)), Point(S.Half, Rational(-1, 10))), Segment(Point(0, 1), Point(-5, 0)), Segment(Point(S.Half, Rational(-1, 10)), Point(1, 0)), Segment(Point(1, 0), Point(0, 1))] assert poly2.intersection(Triangle(Point(0, 1), Point(1, 0), Point(-1, 1))) \ == [Point(Rational(-5, 7), Rational(6, 7)), Segment(Point2D(0, 1), Point(1, 0))] assert poly1.intersection(RegularPolygon((-12, -15), 3, 3)) == [] def test_parameter_value(): t = Symbol('t') sq = Polygon((0, 0), (0, 1), (1, 1), (1, 0)) assert sq.parameter_value((0.5, 1), t) == {t: Rational(3, 8)} q = Polygon((0, 0), (2, 1), (2, 4), (4, 0)) assert q.parameter_value((4, 0), t) == {t: -6 + 3*sqrt(5)} # ~= 0.708 raises(ValueError, lambda: sq.parameter_value((5, 6), t)) raises(ValueError, lambda: sq.parameter_value(Circle(Point(0, 0), 1), t)) def test_issue_12966(): poly = Polygon(Point(0, 0), Point(0, 10), Point(5, 10), Point(5, 5), Point(10, 5), Point(10, 0)) t = Symbol('t') pt = poly.arbitrary_point(t) DELTA = 5/poly.perimeter assert [pt.subs(t, DELTA*i) for i in range(int(1/DELTA))] == [ Point(0, 0), Point(0, 5), Point(0, 10), Point(5, 10), Point(5, 5), Point(10, 5), Point(10, 0), Point(5, 0)] def test_second_moment_of_area(): x, y = symbols('x, y') # triangle p1, p2, p3 = [(0, 0), (4, 0), (0, 2)] p = (0, 0) # equation of hypotenuse eq_y = (1-x/4)*2 I_yy = integrate((x**2) * (integrate(1, (y, 0, eq_y))), (x, 0, 4)) I_xx = integrate(1 * (integrate(y**2, (y, 0, eq_y))), (x, 0, 4)) I_xy = integrate(x * (integrate(y, (y, 0, eq_y))), (x, 0, 4)) triangle = Polygon(p1, p2, p3) assert (I_xx - triangle.second_moment_of_area(p)[0]) == 0 assert (I_yy - triangle.second_moment_of_area(p)[1]) == 0 assert (I_xy - triangle.second_moment_of_area(p)[2]) == 0 # rectangle p1, p2, p3, p4=[(0, 0), (4, 0), (4, 2), (0, 2)] I_yy = integrate((x**2) * integrate(1, (y, 0, 2)), (x, 0, 4)) I_xx = integrate(1 * integrate(y**2, (y, 0, 2)), (x, 0, 4)) I_xy = integrate(x * integrate(y, (y, 0, 2)), (x, 0, 4)) rectangle = Polygon(p1, p2, p3, p4) assert (I_xx - rectangle.second_moment_of_area(p)[0]) == 0 assert (I_yy - rectangle.second_moment_of_area(p)[1]) == 0 assert (I_xy - rectangle.second_moment_of_area(p)[2]) == 0 r = RegularPolygon(Point(0, 0), 5, 3) assert r.second_moment_of_area() == (1875*sqrt(3)/S(32), 1875*sqrt(3)/S(32), 0) def test_first_moment(): a, b = symbols('a, b', positive=True) # rectangle p1 = Polygon((0, 0), (a, 0), (a, b), (0, b)) assert p1.first_moment_of_area() == (a*b**2/8, a**2*b/8) assert p1.first_moment_of_area((a/3, b/4)) == (-3*a*b**2/32, -a**2*b/9) p1 = Polygon((0, 0), (40, 0), (40, 30), (0, 30)) assert p1.first_moment_of_area() == (4500, 6000) # triangle p2 = Polygon((0, 0), (a, 0), (a/2, b)) assert p2.first_moment_of_area() == (4*a*b**2/81, a**2*b/24) assert p2.first_moment_of_area((a/8, b/6)) == (-25*a*b**2/648, -5*a**2*b/768) p2 = Polygon((0, 0), (12, 0), (12, 30)) p2.first_moment_of_area() == (1600/3, -640/3) def test_section_modulus_and_polar_second_moment_of_area(): a, b = symbols('a, b', positive=True) x, y = symbols('x, y') rectangle = Polygon((0, b), (0, 0), (a, 0), (a, b)) assert rectangle.section_modulus(Point(x, y)) == (a*b**3/12/(-b/2 + y), a**3*b/12/(-a/2 + x)) assert rectangle.polar_second_moment_of_area() == a**3*b/12 + a*b**3/12 convex = RegularPolygon((0, 0), 1, 6) assert convex.section_modulus() == (Rational(5, 8), sqrt(3)*Rational(5, 16)) assert convex.polar_second_moment_of_area() == 5*sqrt(3)/S(8) concave = Polygon((0, 0), (1, 8), (3, 4), (4, 6), (7, 1)) assert concave.section_modulus() == (Rational(-6371, 429), Rational(-9778, 519)) assert concave.polar_second_moment_of_area() == Rational(-38669, 252) def test_cut_section(): # concave polygon p = Polygon((-1, -1), (1, Rational(5, 2)), (2, 1), (3, Rational(5, 2)), (4, 2), (5, 3), (-1, 3)) l = Line((0, 0), (Rational(9, 2), 3)) p1 = p.cut_section(l)[0] p2 = p.cut_section(l)[1] assert p1 == Polygon( Point2D(Rational(-9, 13), Rational(-6, 13)), Point2D(1, Rational(5, 2)), Point2D(Rational(24, 13), Rational(16, 13)), Point2D(Rational(12, 5), Rational(8, 5)), Point2D(3, Rational(5, 2)), Point2D(Rational(24, 7), Rational(16, 7)), Point2D(Rational(9, 2), 3), Point2D(-1, 3), Point2D(-1, Rational(-2, 3))) assert p2 == Polygon(Point2D(-1, -1), Point2D(Rational(-9, 13), Rational(-6, 13)), Point2D(Rational(24, 13), Rational(16, 13)), Point2D(2, 1), Point2D(Rational(12, 5), Rational(8, 5)), Point2D(Rational(24, 7), Rational(16, 7)), Point2D(4, 2), Point2D(5, 3), Point2D(Rational(9, 2), 3), Point2D(-1, Rational(-2, 3))) # convex polygon p = RegularPolygon(Point2D(0, 0), 6, 6) s = p.cut_section(Line((0, 0), slope=1)) assert s[0] == Polygon(Point2D(-3*sqrt(3) + 9, -3*sqrt(3) + 9), Point2D(3, 3*sqrt(3)), Point2D(-3, 3*sqrt(3)), Point2D(-6, 0), Point2D(-9 + 3*sqrt(3), -9 + 3*sqrt(3))) assert s[1] == Polygon(Point2D(6, 0), Point2D(-3*sqrt(3) + 9, -3*sqrt(3) + 9), Point2D(-9 + 3*sqrt(3), -9 + 3*sqrt(3)), Point2D(-3, -3*sqrt(3)), Point2D(3, -3*sqrt(3))) # case where line does not intersects but coincides with the edge of polygon a, b = 20, 10 t1, t2, t3, t4 = [(0, b), (0, 0), (a, 0), (a, b)] p = Polygon(t1, t2, t3, t4) p1, p2 = p.cut_section(Line((0, b), slope=0)) assert p1 == None assert p2 == Polygon(Point2D(0, 10), Point2D(0, 0), Point2D(20, 0), Point2D(20, 10)) p3, p4 = p.cut_section(Line((0, 0), slope=0)) assert p3 == Polygon(Point2D(0, 10), Point2D(0, 0), Point2D(20, 0), Point2D(20, 10)) assert p4 == None # case where the line does not intersect with a polygon at all raises(ValueError, lambda: p.cut_section(Line((0, a), slope=0))) def test_type_of_triangle(): # Isoceles triangle p1 = Polygon(Point(0, 0), Point(5, 0), Point(2, 4)) assert p1.is_isosceles() == True assert p1.is_scalene() == False assert p1.is_equilateral() == False # Scalene triangle p2 = Polygon (Point(0, 0), Point(0, 2), Point(4, 0)) assert p2.is_isosceles() == False assert p2.is_scalene() == True assert p2.is_equilateral() == False # Equilateral triagle p3 = Polygon(Point(0, 0), Point(6, 0), Point(3, sqrt(27))) assert p3.is_isosceles() == True assert p3.is_scalene() == False assert p3.is_equilateral() == True def test_do_poly_distance(): # Non-intersecting polygons square1 = Polygon (Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) triangle1 = Polygon(Point(1, 2), Point(2, 2), Point(2, 1)) assert square1._do_poly_distance(triangle1) == sqrt(2)/2 # Polygons which sides intersect square2 = Polygon(Point(1, 0), Point(2, 0), Point(2, 1), Point(1, 1)) with warns(UserWarning, \ match="Polygons may intersect producing erroneous output"): assert square1._do_poly_distance(square2) == 0 # Polygons which bodies intersect triangle2 = Polygon(Point(0, -1), Point(2, -1), Point(S.Half, S.Half)) with warns(UserWarning, \ match="Polygons may intersect producing erroneous output"): assert triangle2._do_poly_distance(square1) == 0 sympy-sympy-1.9/sympy/geometry/tests/test_util.py000066400000000000000000000132131412543434000224670ustar00rootroot00000000000000from sympy import Symbol, sqrt, Derivative, S, Function, exp from sympy.geometry import Point, Point2D, Line, Polygon, Segment, convex_hull,\ intersection, centroid, Point3D, Line3D from sympy.geometry.util import idiff, closest_points, farthest_points, _ordered_points, are_coplanar from sympy.solvers.solvers import solve from sympy.testing.pytest import raises def test_idiff(): x = Symbol('x', real=True) y = Symbol('y', real=True) t = Symbol('t', real=True) f = Function('f') g = Function('g') # the use of idiff in ellipse also provides coverage circ = x**2 + y**2 - 4 ans = -3*x*(x**2 + y**2)/y**5 assert ans == idiff(circ, y, x, 3).simplify() assert ans == idiff(circ, [y], x, 3).simplify() assert idiff(circ, y, x, 3).simplify() == ans explicit = 12*x/sqrt(-x**2 + 4)**5 assert ans.subs(y, solve(circ, y)[0]).equals(explicit) assert True in [sol.diff(x, 3).equals(explicit) for sol in solve(circ, y)] assert idiff(x + t + y, [y, t], x) == -Derivative(t, x) - 1 assert idiff(f(x) * exp(f(x)) - x * exp(x), f(x), x) == (x + 1) * exp(x - f(x))/(f(x) + 1) assert idiff(f(x) - y * exp(x), [f(x), y], x) == (y + Derivative(y, x)) * exp(x) assert idiff(f(x) - y * exp(x), [y, f(x)], x) == -y + exp(-x) * Derivative(f(x), x) assert idiff(f(x) - g(x), [f(x), g(x)], x) == Derivative(g(x), x) def test_intersection(): assert intersection(Point(0, 0)) == [] raises(TypeError, lambda: intersection(Point(0, 0), 3)) assert intersection( Segment((0, 0), (2, 0)), Segment((-1, 0), (1, 0)), Line((0, 0), (0, 1)), pairwise=True) == [ Point(0, 0), Segment((0, 0), (1, 0))] assert intersection( Line((0, 0), (0, 1)), Segment((0, 0), (2, 0)), Segment((-1, 0), (1, 0)), pairwise=True) == [ Point(0, 0), Segment((0, 0), (1, 0))] assert intersection( Line((0, 0), (0, 1)), Segment((0, 0), (2, 0)), Segment((-1, 0), (1, 0)), Line((0, 0), slope=1), pairwise=True) == [ Point(0, 0), Segment((0, 0), (1, 0))] def test_convex_hull(): raises(TypeError, lambda: convex_hull(Point(0, 0), 3)) points = [(1, -1), (1, -2), (3, -1), (-5, -2), (15, -4)] assert convex_hull(*points, **dict(polygon=False)) == ( [Point2D(-5, -2), Point2D(1, -1), Point2D(3, -1), Point2D(15, -4)], [Point2D(-5, -2), Point2D(15, -4)]) def test_centroid(): p = Polygon((0, 0), (10, 0), (10, 10)) q = p.translate(0, 20) assert centroid(p, q) == Point(20, 40)/3 p = Segment((0, 0), (2, 0)) q = Segment((0, 0), (2, 2)) assert centroid(p, q) == Point(1, -sqrt(2) + 2) assert centroid(Point(0, 0), Point(2, 0)) == Point(2, 0)/2 assert centroid(Point(0, 0), Point(0, 0), Point(2, 0)) == Point(2, 0)/3 def test_farthest_points_closest_points(): from random import randint from sympy.utilities.iterables import subsets for how in (min, max): if how is min: func = closest_points else: func = farthest_points raises(ValueError, lambda: func(Point2D(0, 0), Point2D(0, 0))) # 3rd pt dx is close and pt is closer to 1st pt p1 = [Point2D(0, 0), Point2D(3, 0), Point2D(1, 1)] # 3rd pt dx is close and pt is closer to 2nd pt p2 = [Point2D(0, 0), Point2D(3, 0), Point2D(2, 1)] # 3rd pt dx is close and but pt is not closer p3 = [Point2D(0, 0), Point2D(3, 0), Point2D(1, 10)] # 3rd pt dx is not closer and it's closer to 2nd pt p4 = [Point2D(0, 0), Point2D(3, 0), Point2D(4, 0)] # 3rd pt dx is not closer and it's closer to 1st pt p5 = [Point2D(0, 0), Point2D(3, 0), Point2D(-1, 0)] # duplicate point doesn't affect outcome dup = [Point2D(0, 0), Point2D(3, 0), Point2D(3, 0), Point2D(-1, 0)] # symbolic x = Symbol('x', positive=True) s = [Point2D(a) for a in ((x, 1), (x + 3, 2), (x + 2, 2))] for points in (p1, p2, p3, p4, p5, s, dup): d = how(i.distance(j) for i, j in subsets(points, 2)) ans = a, b = list(func(*points))[0] a.distance(b) == d assert ans == _ordered_points(ans) # if the following ever fails, the above tests were not sufficient # and the logical error in the routine should be fixed points = set() while len(points) != 7: points.add(Point2D(randint(1, 100), randint(1, 100))) points = list(points) d = how(i.distance(j) for i, j in subsets(points, 2)) ans = a, b = list(func(*points))[0] a.distance(b) == d assert ans == _ordered_points(ans) # equidistant points a, b, c = ( Point2D(0, 0), Point2D(1, 0), Point2D(S.Half, sqrt(3)/2)) ans = {_ordered_points((i, j)) for i, j in subsets((a, b, c), 2)} assert closest_points(b, c, a) == ans assert farthest_points(b, c, a) == ans # unique to farthest points = [(1, 1), (1, 2), (3, 1), (-5, 2), (15, 4)] assert farthest_points(*points) == { (Point2D(-5, 2), Point2D(15, 4))} points = [(1, -1), (1, -2), (3, -1), (-5, -2), (15, -4)] assert farthest_points(*points) == { (Point2D(-5, -2), Point2D(15, -4))} assert farthest_points((1, 1), (0, 0)) == { (Point2D(0, 0), Point2D(1, 1))} raises(ValueError, lambda: farthest_points((1, 1))) def test_are_coplanar(): a = Line3D(Point3D(5, 0, 0), Point3D(1, -1, 1)) b = Line3D(Point3D(0, -2, 0), Point3D(3, 1, 1)) c = Line3D(Point3D(0, -1, 0), Point3D(5, -1, 9)) d = Line(Point2D(0, 3), Point2D(1, 5)) assert are_coplanar(a, b, c) == False assert are_coplanar(a, d) == False sympy-sympy-1.9/sympy/geometry/util.py000066400000000000000000000460171412543434000202760ustar00rootroot00000000000000"""Utility functions for geometrical entities. Contains ======== intersection convex_hull closest_points farthest_points are_coplanar are_similar """ from sympy import Function, Symbol, solve, sqrt from sympy.core.compatibility import ( is_sequence, ordered) from sympy.core.containers import OrderedSet from .point import Point, Point2D def find(x, equation): """ Checks whether the parameter 'x' is present in 'equation' or not. If it is present then it returns the passed parameter 'x' as a free symbol, else, it returns a ValueError. """ free = equation.free_symbols xs = [i for i in free if (i.name if isinstance(x, str) else i) == x] if not xs: raise ValueError('could not find %s' % x) if len(xs) != 1: raise ValueError('ambiguous %s' % x) return xs[0] def _ordered_points(p): """Return the tuple of points sorted numerically according to args""" return tuple(sorted(p, key=lambda x: x.args)) def are_coplanar(*e): """ Returns True if the given entities are coplanar otherwise False Parameters ========== e: entities to be checked for being coplanar Returns ======= Boolean Examples ======== >>> from sympy import Point3D, Line3D >>> from sympy.geometry.util import are_coplanar >>> a = Line3D(Point3D(5, 0, 0), Point3D(1, -1, 1)) >>> b = Line3D(Point3D(0, -2, 0), Point3D(3, 1, 1)) >>> c = Line3D(Point3D(0, -1, 0), Point3D(5, -1, 9)) >>> are_coplanar(a, b, c) False """ from sympy.geometry.line import LinearEntity3D from sympy.geometry.entity import GeometryEntity from sympy.geometry.point import Point3D from sympy.geometry.plane import Plane # XXX update tests for coverage e = set(e) # first work with a Plane if present for i in list(e): if isinstance(i, Plane): e.remove(i) return all(p.is_coplanar(i) for p in e) if all(isinstance(i, Point3D) for i in e): if len(e) < 3: return False # remove pts that are collinear with 2 pts a, b = e.pop(), e.pop() for i in list(e): if Point3D.are_collinear(a, b, i): e.remove(i) if not e: return False else: # define a plane p = Plane(a, b, e.pop()) for i in e: if i not in p: return False return True else: pt3d = [] for i in e: if isinstance(i, Point3D): pt3d.append(i) elif isinstance(i, LinearEntity3D): pt3d.extend(i.args) elif isinstance(i, GeometryEntity): # XXX we should have a GeometryEntity3D class so we can tell the difference between 2D and 3D -- here we just want to deal with 2D objects; if new 3D objects are encountered that we didn't handle above, an error should be raised # all 2D objects have some Point that defines them; so convert those points to 3D pts by making z=0 for p in i.args: if isinstance(p, Point): pt3d.append(Point3D(*(p.args + (0,)))) return are_coplanar(*pt3d) def are_similar(e1, e2): """Are two geometrical entities similar. Can one geometrical entity be uniformly scaled to the other? Parameters ========== e1 : GeometryEntity e2 : GeometryEntity Returns ======= are_similar : boolean Raises ====== GeometryError When `e1` and `e2` cannot be compared. Notes ===== If the two objects are equal then they are similar. See Also ======== sympy.geometry.entity.GeometryEntity.is_similar Examples ======== >>> from sympy import Point, Circle, Triangle, are_similar >>> c1, c2 = Circle(Point(0, 0), 4), Circle(Point(1, 4), 3) >>> t1 = Triangle(Point(0, 0), Point(1, 0), Point(0, 1)) >>> t2 = Triangle(Point(0, 0), Point(2, 0), Point(0, 2)) >>> t3 = Triangle(Point(0, 0), Point(3, 0), Point(0, 1)) >>> are_similar(t1, t2) True >>> are_similar(t1, t3) False """ from .exceptions import GeometryError if e1 == e2: return True is_similar1 = getattr(e1, 'is_similar', None) if is_similar1: return is_similar1(e2) is_similar2 = getattr(e2, 'is_similar', None) if is_similar2: return is_similar2(e1) n1 = e1.__class__.__name__ n2 = e2.__class__.__name__ raise GeometryError( "Cannot test similarity between %s and %s" % (n1, n2)) def centroid(*args): """Find the centroid (center of mass) of the collection containing only Points, Segments or Polygons. The centroid is the weighted average of the individual centroid where the weights are the lengths (of segments) or areas (of polygons). Overlapping regions will add to the weight of that region. If there are no objects (or a mixture of objects) then None is returned. See Also ======== sympy.geometry.point.Point, sympy.geometry.line.Segment, sympy.geometry.polygon.Polygon Examples ======== >>> from sympy import Point, Segment, Polygon >>> from sympy.geometry.util import centroid >>> p = Polygon((0, 0), (10, 0), (10, 10)) >>> q = p.translate(0, 20) >>> p.centroid, q.centroid (Point2D(20/3, 10/3), Point2D(20/3, 70/3)) >>> centroid(p, q) Point2D(20/3, 40/3) >>> p, q = Segment((0, 0), (2, 0)), Segment((0, 0), (2, 2)) >>> centroid(p, q) Point2D(1, 2 - sqrt(2)) >>> centroid(Point(0, 0), Point(2, 0)) Point2D(1, 0) Stacking 3 polygons on top of each other effectively triples the weight of that polygon: >>> p = Polygon((0, 0), (1, 0), (1, 1), (0, 1)) >>> q = Polygon((1, 0), (3, 0), (3, 1), (1, 1)) >>> centroid(p, q) Point2D(3/2, 1/2) >>> centroid(p, p, p, q) # centroid x-coord shifts left Point2D(11/10, 1/2) Stacking the squares vertically above and below p has the same effect: >>> centroid(p, p.translate(0, 1), p.translate(0, -1), q) Point2D(11/10, 1/2) """ from sympy.geometry import Polygon, Segment, Point if args: if all(isinstance(g, Point) for g in args): c = Point(0, 0) for g in args: c += g den = len(args) elif all(isinstance(g, Segment) for g in args): c = Point(0, 0) L = 0 for g in args: l = g.length c += g.midpoint*l L += l den = L elif all(isinstance(g, Polygon) for g in args): c = Point(0, 0) A = 0 for g in args: a = g.area c += g.centroid*a A += a den = A c /= den return c.func(*[i.simplify() for i in c.args]) def closest_points(*args): """Return the subset of points from a set of points that were the closest to each other in the 2D plane. Parameters ========== args : a collection of Points on 2D plane. Notes ===== This can only be performed on a set of points whose coordinates can be ordered on the number line. If there are no ties then a single pair of Points will be in the set. References ========== [1] http://www.cs.mcgill.ca/~cs251/ClosestPair/ClosestPairPS.html [2] Sweep line algorithm https://en.wikipedia.org/wiki/Sweep_line_algorithm Examples ======== >>> from sympy.geometry import closest_points, Triangle >>> Triangle(sss=(3, 4, 5)).args (Point2D(0, 0), Point2D(3, 0), Point2D(3, 4)) >>> closest_points(*_) {(Point2D(0, 0), Point2D(3, 0))} """ from collections import deque from math import sqrt as _sqrt from sympy.functions.elementary.miscellaneous import sqrt p = [Point2D(i) for i in set(args)] if len(p) < 2: raise ValueError('At least 2 distinct points must be given.') try: p.sort(key=lambda x: x.args) except TypeError: raise ValueError("The points could not be sorted.") if any(not i.is_Rational for j in p for i in j.args): def hypot(x, y): arg = x*x + y*y if arg.is_Rational: return _sqrt(arg) return sqrt(arg) else: from math import hypot rv = [(0, 1)] best_dist = hypot(p[1].x - p[0].x, p[1].y - p[0].y) i = 2 left = 0 box = deque([0, 1]) while i < len(p): while left < i and p[i][0] - p[left][0] > best_dist: box.popleft() left += 1 for j in box: d = hypot(p[i].x - p[j].x, p[i].y - p[j].y) if d < best_dist: rv = [(j, i)] elif d == best_dist: rv.append((j, i)) else: continue best_dist = d box.append(i) i += 1 return {tuple([p[i] for i in pair]) for pair in rv} def convex_hull(*args, polygon=True): """The convex hull surrounding the Points contained in the list of entities. Parameters ========== args : a collection of Points, Segments and/or Polygons Optional parameters =================== polygon : Boolean. If True, returns a Polygon, if false a tuple, see below. Default is True. Returns ======= convex_hull : Polygon if ``polygon`` is True else as a tuple `(U, L)` where ``L`` and ``U`` are the lower and upper hulls, respectively. Notes ===== This can only be performed on a set of points whose coordinates can be ordered on the number line. References ========== [1] https://en.wikipedia.org/wiki/Graham_scan [2] Andrew's Monotone Chain Algorithm (A.M. Andrew, "Another Efficient Algorithm for Convex Hulls in Two Dimensions", 1979) http://geomalgorithms.com/a10-_hull-1.html See Also ======== sympy.geometry.point.Point, sympy.geometry.polygon.Polygon Examples ======== >>> from sympy.geometry import convex_hull >>> points = [(1, 1), (1, 2), (3, 1), (-5, 2), (15, 4)] >>> convex_hull(*points) Polygon(Point2D(-5, 2), Point2D(1, 1), Point2D(3, 1), Point2D(15, 4)) >>> convex_hull(*points, **dict(polygon=False)) ([Point2D(-5, 2), Point2D(15, 4)], [Point2D(-5, 2), Point2D(1, 1), Point2D(3, 1), Point2D(15, 4)]) """ from .entity import GeometryEntity from .point import Point from .line import Segment from .polygon import Polygon p = OrderedSet() for e in args: if not isinstance(e, GeometryEntity): try: e = Point(e) except NotImplementedError: raise ValueError('%s is not a GeometryEntity and cannot be made into Point' % str(e)) if isinstance(e, Point): p.add(e) elif isinstance(e, Segment): p.update(e.points) elif isinstance(e, Polygon): p.update(e.vertices) else: raise NotImplementedError( 'Convex hull for %s not implemented.' % type(e)) # make sure all our points are of the same dimension if any(len(x) != 2 for x in p): raise ValueError('Can only compute the convex hull in two dimensions') p = list(p) if len(p) == 1: return p[0] if polygon else (p[0], None) elif len(p) == 2: s = Segment(p[0], p[1]) return s if polygon else (s, None) def _orientation(p, q, r): '''Return positive if p-q-r are clockwise, neg if ccw, zero if collinear.''' return (q.y - p.y)*(r.x - p.x) - (q.x - p.x)*(r.y - p.y) # scan to find upper and lower convex hulls of a set of 2d points. U = [] L = [] try: p.sort(key=lambda x: x.args) except TypeError: raise ValueError("The points could not be sorted.") for p_i in p: while len(U) > 1 and _orientation(U[-2], U[-1], p_i) <= 0: U.pop() while len(L) > 1 and _orientation(L[-2], L[-1], p_i) >= 0: L.pop() U.append(p_i) L.append(p_i) U.reverse() convexHull = tuple(L + U[1:-1]) if len(convexHull) == 2: s = Segment(convexHull[0], convexHull[1]) return s if polygon else (s, None) if polygon: return Polygon(*convexHull) else: U.reverse() return (U, L) def farthest_points(*args): """Return the subset of points from a set of points that were the furthest apart from each other in the 2D plane. Parameters ========== args : a collection of Points on 2D plane. Notes ===== This can only be performed on a set of points whose coordinates can be ordered on the number line. If there are no ties then a single pair of Points will be in the set. References ========== [1] http://code.activestate.com/recipes/117225-convex-hull-and-diameter-of-2d-point-sets/ [2] Rotating Callipers Technique https://en.wikipedia.org/wiki/Rotating_calipers Examples ======== >>> from sympy.geometry import farthest_points, Triangle >>> Triangle(sss=(3, 4, 5)).args (Point2D(0, 0), Point2D(3, 0), Point2D(3, 4)) >>> farthest_points(*_) {(Point2D(0, 0), Point2D(3, 4))} """ from math import sqrt as _sqrt def rotatingCalipers(Points): U, L = convex_hull(*Points, **dict(polygon=False)) if L is None: if isinstance(U, Point): raise ValueError('At least two distinct points must be given.') yield U.args else: i = 0 j = len(L) - 1 while i < len(U) - 1 or j > 0: yield U[i], L[j] # if all the way through one side of hull, advance the other side if i == len(U) - 1: j -= 1 elif j == 0: i += 1 # still points left on both lists, compare slopes of next hull edges # being careful to avoid divide-by-zero in slope calculation elif (U[i+1].y - U[i].y) * (L[j].x - L[j-1].x) > \ (L[j].y - L[j-1].y) * (U[i+1].x - U[i].x): i += 1 else: j -= 1 p = [Point2D(i) for i in set(args)] if any(not i.is_Rational for j in p for i in j.args): def hypot(x, y): arg = x*x + y*y if arg.is_Rational: return _sqrt(arg) return sqrt(arg) else: from math import hypot rv = [] diam = 0 for pair in rotatingCalipers(args): h, q = _ordered_points(pair) d = hypot(h.x - q.x, h.y - q.y) if d > diam: rv = [(h, q)] elif d == diam: rv.append((h, q)) else: continue diam = d return set(rv) def idiff(eq, y, x, n=1): """Return ``dy/dx`` assuming that ``eq == 0``. Parameters ========== y : the dependent variable or a list of dependent variables (with y first) x : the variable that the derivative is being taken with respect to n : the order of the derivative (default is 1) Examples ======== >>> from sympy.abc import x, y, a >>> from sympy.geometry.util import idiff >>> circ = x**2 + y**2 - 4 >>> idiff(circ, y, x) -x/y >>> idiff(circ, y, x, 2).simplify() -(x**2 + y**2)/y**3 Here, ``a`` is assumed to be independent of ``x``: >>> idiff(x + a + y, y, x) -1 Now the x-dependence of ``a`` is made explicit by listing ``a`` after ``y`` in a list. >>> idiff(x + a + y, [y, a], x) -Derivative(a, x) - 1 See Also ======== sympy.core.function.Derivative: represents unevaluated derivatives sympy.core.function.diff: explicitly differentiates wrt symbols """ if is_sequence(y): dep = set(y) y = y[0] elif isinstance(y, Symbol): dep = {y} elif isinstance(y, Function): pass else: raise ValueError("expecting x-dependent symbol(s) or function(s) but got: %s" % y) f = {s: Function(s.name)(x) for s in eq.free_symbols if s != x and s in dep} if isinstance(y, Symbol): dydx = Function(y.name)(x).diff(x) else: dydx = y.diff(x) eq = eq.subs(f) derivs = {} for i in range(n): yp = solve(eq.diff(x), dydx)[0].subs(derivs) if i == n - 1: return yp.subs([(v, k) for k, v in f.items()]) derivs[dydx] = yp eq = dydx - yp dydx = dydx.diff(x) def intersection(*entities, pairwise=False, **kwargs): """The intersection of a collection of GeometryEntity instances. Parameters ========== entities : sequence of GeometryEntity pairwise (keyword argument) : Can be either True or False Returns ======= intersection : list of GeometryEntity Raises ====== NotImplementedError When unable to calculate intersection. Notes ===== The intersection of any geometrical entity with itself should return a list with one item: the entity in question. An intersection requires two or more entities. If only a single entity is given then the function will return an empty list. It is possible for `intersection` to miss intersections that one knows exists because the required quantities were not fully simplified internally. Reals should be converted to Rationals, e.g. Rational(str(real_num)) or else failures due to floating point issues may result. Case 1: When the keyword argument 'pairwise' is False (default value): In this case, the function returns a list of intersections common to all entities. Case 2: When the keyword argument 'pairwise' is True: In this case, the functions returns a list intersections that occur between any pair of entities. See Also ======== sympy.geometry.entity.GeometryEntity.intersection Examples ======== >>> from sympy.geometry import Ray, Circle, intersection >>> c = Circle((0, 1), 1) >>> intersection(c, c.center) [] >>> right = Ray((0, 0), (1, 0)) >>> up = Ray((0, 0), (0, 1)) >>> intersection(c, right, up) [Point2D(0, 0)] >>> intersection(c, right, up, pairwise=True) [Point2D(0, 0), Point2D(0, 2)] >>> left = Ray((1, 0), (0, 0)) >>> intersection(right, left) [Segment2D(Point2D(0, 0), Point2D(1, 0))] """ from .entity import GeometryEntity from .point import Point if len(entities) <= 1: return [] # entities may be an immutable tuple entities = list(entities) for i, e in enumerate(entities): if not isinstance(e, GeometryEntity): entities[i] = Point(e) if not pairwise: # find the intersection common to all objects res = entities[0].intersection(entities[1]) for entity in entities[2:]: newres = [] for x in res: newres.extend(x.intersection(entity)) res = newres return res # find all pairwise intersections ans = [] for j in range(0, len(entities)): for k in range(j + 1, len(entities)): ans.extend(intersection(entities[j], entities[k])) return list(ordered(set(ans))) sympy-sympy-1.9/sympy/holonomic/000077500000000000000000000000001412543434000170735ustar00rootroot00000000000000sympy-sympy-1.9/sympy/holonomic/__init__.py000066400000000000000000000014201412543434000212010ustar00rootroot00000000000000r""" The :py:mod:`~sympy.holonomic` module is intended to deal with holonomic functions along with various operations on them like addition, multiplication, composition, integration and differentiation. The module also implements various kinds of conversions such as converting holonomic functions to a different form and the other way around. """ from .holonomic import (DifferentialOperator, HolonomicFunction, DifferentialOperators, from_hyper, from_meijerg, expr_to_holonomic) from .recurrence import RecurrenceOperators, RecurrenceOperator, HolonomicSequence __all__ = [ 'DifferentialOperator', 'HolonomicFunction', 'DifferentialOperators', 'from_hyper', 'from_meijerg', 'expr_to_holonomic', 'RecurrenceOperators', 'RecurrenceOperator', 'HolonomicSequence', ] sympy-sympy-1.9/sympy/holonomic/holonomic.py000066400000000000000000002704221412543434000214430ustar00rootroot00000000000000""" This module implements Holonomic Functions and various operations on them. """ from sympy import (Symbol, S, Dummy, Order, rf, I, solve, limit, Float, nsimplify, gamma) from sympy.core.compatibility import ordered from sympy.core.numbers import NaN, Infinity, NegativeInfinity from sympy.core.sympify import sympify from sympy.functions.combinatorial.factorials import binomial, factorial from sympy.functions.elementary.exponential import exp_polar, exp from sympy.functions.special.hyper import hyper, meijerg from sympy.integrals import meijerint from sympy.matrices import Matrix from sympy.polys.rings import PolyElement from sympy.polys.fields import FracElement from sympy.polys.domains import QQ, RR from sympy.polys.polyclasses import DMF from sympy.polys.polyroots import roots from sympy.polys.polytools import Poly from sympy.polys.matrices import DomainMatrix from sympy.printing import sstr from sympy.simplify.hyperexpand import hyperexpand from .recurrence import HolonomicSequence, RecurrenceOperator, RecurrenceOperators from .holonomicerrors import (NotPowerSeriesError, NotHyperSeriesError, SingularityError, NotHolonomicError) def _find_nonzero_solution(r, homosys): ones = lambda shape: DomainMatrix.ones(shape, r.domain) particular, nullspace = r._solve(homosys) nullity = nullspace.shape[0] nullpart = ones((1, nullity)) * nullspace sol = (particular + nullpart).transpose() return sol def DifferentialOperators(base, generator): r""" This function is used to create annihilators using ``Dx``. Explanation =========== Returns an Algebra of Differential Operators also called Weyl Algebra and the operator for differentiation i.e. the ``Dx`` operator. Parameters ========== base: Base polynomial ring for the algebra. The base polynomial ring is the ring of polynomials in :math:`x` that will appear as coefficients in the operators. generator: Generator of the algebra which can be either a noncommutative ``Symbol`` or a string. e.g. "Dx" or "D". Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.abc import x >>> from sympy.holonomic.holonomic import DifferentialOperators >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') >>> R Univariate Differential Operator Algebra in intermediate Dx over the base ring ZZ[x] >>> Dx*x (1) + (x)*Dx """ ring = DifferentialOperatorAlgebra(base, generator) return (ring, ring.derivative_operator) class DifferentialOperatorAlgebra: r""" An Ore Algebra is a set of noncommutative polynomials in the intermediate ``Dx`` and coefficients in a base polynomial ring :math:`A`. It follows the commutation rule: .. math :: Dxa = \sigma(a)Dx + \delta(a) for :math:`a \subset A`. Where :math:`\sigma: A \Rightarrow A` is an endomorphism and :math:`\delta: A \rightarrow A` is a skew-derivation i.e. :math:`\delta(ab) = \delta(a) b + \sigma(a) \delta(b)`. If one takes the sigma as identity map and delta as the standard derivation then it becomes the algebra of Differential Operators also called a Weyl Algebra i.e. an algebra whose elements are Differential Operators. This class represents a Weyl Algebra and serves as the parent ring for Differential Operators. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy import symbols >>> from sympy.holonomic.holonomic import DifferentialOperators >>> x = symbols('x') >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') >>> R Univariate Differential Operator Algebra in intermediate Dx over the base ring ZZ[x] See Also ======== DifferentialOperator """ def __init__(self, base, generator): # the base polynomial ring for the algebra self.base = base # the operator representing differentiation i.e. `Dx` self.derivative_operator = DifferentialOperator( [base.zero, base.one], self) if generator is None: self.gen_symbol = Symbol('Dx', commutative=False) else: if isinstance(generator, str): self.gen_symbol = Symbol(generator, commutative=False) elif isinstance(generator, Symbol): self.gen_symbol = generator def __str__(self): string = 'Univariate Differential Operator Algebra in intermediate '\ + sstr(self.gen_symbol) + ' over the base ring ' + \ (self.base).__str__() return string __repr__ = __str__ def __eq__(self, other): if self.base == other.base and self.gen_symbol == other.gen_symbol: return True else: return False class DifferentialOperator: """ Differential Operators are elements of Weyl Algebra. The Operators are defined by a list of polynomials in the base ring and the parent ring of the Operator i.e. the algebra it belongs to. Explanation =========== Takes a list of polynomials for each power of ``Dx`` and the parent ring which must be an instance of DifferentialOperatorAlgebra. A Differential Operator can be created easily using the operator ``Dx``. See examples below. Examples ======== >>> from sympy.holonomic.holonomic import DifferentialOperator, DifferentialOperators >>> from sympy.polys.domains import ZZ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') >>> DifferentialOperator([0, 1, x**2], R) (1)*Dx + (x**2)*Dx**2 >>> (x*Dx*x + 1 - Dx**2)**2 (2*x**2 + 2*x + 1) + (4*x**3 + 2*x**2 - 4)*Dx + (x**4 - 6*x - 2)*Dx**2 + (-2*x**2)*Dx**3 + (1)*Dx**4 See Also ======== DifferentialOperatorAlgebra """ _op_priority = 20 def __init__(self, list_of_poly, parent): """ Parameters ========== list_of_poly: List of polynomials belonging to the base ring of the algebra. parent: Parent algebra of the operator. """ # the parent ring for this operator # must be an DifferentialOperatorAlgebra object self.parent = parent base = self.parent.base self.x = base.gens[0] if isinstance(base.gens[0], Symbol) else base.gens[0][0] # sequence of polynomials in x for each power of Dx # the list should not have trailing zeroes # represents the operator # convert the expressions into ring elements using from_sympy for i, j in enumerate(list_of_poly): if not isinstance(j, base.dtype): list_of_poly[i] = base.from_sympy(sympify(j)) else: list_of_poly[i] = base.from_sympy(base.to_sympy(j)) self.listofpoly = list_of_poly # highest power of `Dx` self.order = len(self.listofpoly) - 1 def __mul__(self, other): """ Multiplies two DifferentialOperator and returns another DifferentialOperator instance using the commutation rule Dx*a = a*Dx + a' """ listofself = self.listofpoly if not isinstance(other, DifferentialOperator): if not isinstance(other, self.parent.base.dtype): listofother = [self.parent.base.from_sympy(sympify(other))] else: listofother = [other] else: listofother = other.listofpoly # multiplies a polynomial `b` with a list of polynomials def _mul_dmp_diffop(b, listofother): if isinstance(listofother, list): sol = [] for i in listofother: sol.append(i * b) return sol else: return [b * listofother] sol = _mul_dmp_diffop(listofself[0], listofother) # compute Dx^i * b def _mul_Dxi_b(b): sol1 = [self.parent.base.zero] sol2 = [] if isinstance(b, list): for i in b: sol1.append(i) sol2.append(i.diff()) else: sol1.append(self.parent.base.from_sympy(b)) sol2.append(self.parent.base.from_sympy(b).diff()) return _add_lists(sol1, sol2) for i in range(1, len(listofself)): # find Dx^i * b in ith iteration listofother = _mul_Dxi_b(listofother) # solution = solution + listofself[i] * (Dx^i * b) sol = _add_lists(sol, _mul_dmp_diffop(listofself[i], listofother)) return DifferentialOperator(sol, self.parent) def __rmul__(self, other): if not isinstance(other, DifferentialOperator): if not isinstance(other, self.parent.base.dtype): other = (self.parent.base).from_sympy(sympify(other)) sol = [] for j in self.listofpoly: sol.append(other * j) return DifferentialOperator(sol, self.parent) def __add__(self, other): if isinstance(other, DifferentialOperator): sol = _add_lists(self.listofpoly, other.listofpoly) return DifferentialOperator(sol, self.parent) else: list_self = self.listofpoly if not isinstance(other, self.parent.base.dtype): list_other = [((self.parent).base).from_sympy(sympify(other))] else: list_other = [other] sol = [] sol.append(list_self[0] + list_other[0]) sol += list_self[1:] return DifferentialOperator(sol, self.parent) __radd__ = __add__ def __sub__(self, other): return self + (-1) * other def __rsub__(self, other): return (-1) * self + other def __neg__(self): return -1 * self def __truediv__(self, other): return self * (S.One / other) def __pow__(self, n): if n == 1: return self if n == 0: return DifferentialOperator([self.parent.base.one], self.parent) # if self is `Dx` if self.listofpoly == self.parent.derivative_operator.listofpoly: sol = [] for i in range(0, n): sol.append(self.parent.base.zero) sol.append(self.parent.base.one) return DifferentialOperator(sol, self.parent) # the general case else: if n % 2 == 1: powreduce = self**(n - 1) return powreduce * self elif n % 2 == 0: powreduce = self**(n / 2) return powreduce * powreduce def __str__(self): listofpoly = self.listofpoly print_str = '' for i, j in enumerate(listofpoly): if j == self.parent.base.zero: continue if i == 0: print_str += '(' + sstr(j) + ')' continue if print_str: print_str += ' + ' if i == 1: print_str += '(' + sstr(j) + ')*%s' %(self.parent.gen_symbol) continue print_str += '(' + sstr(j) + ')' + '*%s**' %(self.parent.gen_symbol) + sstr(i) return print_str __repr__ = __str__ def __eq__(self, other): if isinstance(other, DifferentialOperator): if self.listofpoly == other.listofpoly and self.parent == other.parent: return True else: return False else: if self.listofpoly[0] == other: for i in self.listofpoly[1:]: if i is not self.parent.base.zero: return False return True else: return False def is_singular(self, x0): """ Checks if the differential equation is singular at x0. """ base = self.parent.base return x0 in roots(base.to_sympy(self.listofpoly[-1]), self.x) class HolonomicFunction: r""" A Holonomic Function is a solution to a linear homogeneous ordinary differential equation with polynomial coefficients. This differential equation can also be represented by an annihilator i.e. a Differential Operator ``L`` such that :math:`L.f = 0`. For uniqueness of these functions, initial conditions can also be provided along with the annihilator. Explanation =========== Holonomic functions have closure properties and thus forms a ring. Given two Holonomic Functions f and g, their sum, product, integral and derivative is also a Holonomic Function. For ordinary points initial condition should be a vector of values of the derivatives i.e. :math:`[y(x_0), y'(x_0), y''(x_0) ... ]`. For regular singular points initial conditions can also be provided in this format: :math:`{s0: [C_0, C_1, ...], s1: [C^1_0, C^1_1, ...], ...}` where s0, s1, ... are the roots of indicial equation and vectors :math:`[C_0, C_1, ...], [C^0_0, C^0_1, ...], ...` are the corresponding initial terms of the associated power series. See Examples below. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import QQ >>> from sympy import symbols, S >>> x = symbols('x') >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') >>> p = HolonomicFunction(Dx - 1, x, 0, [1]) # e^x >>> q = HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]) # sin(x) >>> p + q # annihilator of e^x + sin(x) HolonomicFunction((-1) + (1)*Dx + (-1)*Dx**2 + (1)*Dx**3, x, 0, [1, 2, 1]) >>> p * q # annihilator of e^x * sin(x) HolonomicFunction((2) + (-2)*Dx + (1)*Dx**2, x, 0, [0, 1]) An example of initial conditions for regular singular points, the indicial equation has only one root `1/2`. >>> HolonomicFunction(-S(1)/2 + x*Dx, x, 0, {S(1)/2: [1]}) HolonomicFunction((-1/2) + (x)*Dx, x, 0, {1/2: [1]}) >>> HolonomicFunction(-S(1)/2 + x*Dx, x, 0, {S(1)/2: [1]}).to_expr() sqrt(x) To plot a Holonomic Function, one can use `.evalf()` for numerical computation. Here's an example on `sin(x)**2/x` using numpy and matplotlib. >>> import sympy.holonomic # doctest: +SKIP >>> from sympy import var, sin # doctest: +SKIP >>> import matplotlib.pyplot as plt # doctest: +SKIP >>> import numpy as np # doctest: +SKIP >>> var("x") # doctest: +SKIP >>> r = np.linspace(1, 5, 100) # doctest: +SKIP >>> y = sympy.holonomic.expr_to_holonomic(sin(x)**2/x, x0=1).evalf(r) # doctest: +SKIP >>> plt.plot(r, y, label="holonomic function") # doctest: +SKIP >>> plt.show() # doctest: +SKIP """ _op_priority = 20 def __init__(self, annihilator, x, x0=0, y0=None): """ Parameters ========== annihilator: Annihilator of the Holonomic Function, represented by a `DifferentialOperator` object. x: Variable of the function. x0: The point at which initial conditions are stored. Generally an integer. y0: The initial condition. The proper format for the initial condition is described in class docstring. To make the function unique, length of the vector `y0` should be equal to or greater than the order of differential equation. """ # initial condition self.y0 = y0 # the point for initial conditions, default is zero. self.x0 = x0 # differential operator L such that L.f = 0 self.annihilator = annihilator self.x = x def __str__(self): if self._have_init_cond(): str_sol = 'HolonomicFunction(%s, %s, %s, %s)' % (str(self.annihilator),\ sstr(self.x), sstr(self.x0), sstr(self.y0)) else: str_sol = 'HolonomicFunction(%s, %s)' % (str(self.annihilator),\ sstr(self.x)) return str_sol __repr__ = __str__ def unify(self, other): """ Unifies the base polynomial ring of a given two Holonomic Functions. """ R1 = self.annihilator.parent.base R2 = other.annihilator.parent.base dom1 = R1.dom dom2 = R2.dom if R1 == R2: return (self, other) R = (dom1.unify(dom2)).old_poly_ring(self.x) newparent, _ = DifferentialOperators(R, str(self.annihilator.parent.gen_symbol)) sol1 = [R1.to_sympy(i) for i in self.annihilator.listofpoly] sol2 = [R2.to_sympy(i) for i in other.annihilator.listofpoly] sol1 = DifferentialOperator(sol1, newparent) sol2 = DifferentialOperator(sol2, newparent) sol1 = HolonomicFunction(sol1, self.x, self.x0, self.y0) sol2 = HolonomicFunction(sol2, other.x, other.x0, other.y0) return (sol1, sol2) def is_singularics(self): """ Returns True if the function have singular initial condition in the dictionary format. Returns False if the function have ordinary initial condition in the list format. Returns None for all other cases. """ if isinstance(self.y0, dict): return True elif isinstance(self.y0, list): return False def _have_init_cond(self): """ Checks if the function have initial condition. """ return bool(self.y0) def _singularics_to_ord(self): """ Converts a singular initial condition to ordinary if possible. """ a = list(self.y0)[0] b = self.y0[a] if len(self.y0) == 1 and a == int(a) and a > 0: y0 = [] a = int(a) for i in range(a): y0.append(S.Zero) y0 += [j * factorial(a + i) for i, j in enumerate(b)] return HolonomicFunction(self.annihilator, self.x, self.x0, y0) def __add__(self, other): # if the ground domains are different if self.annihilator.parent.base != other.annihilator.parent.base: a, b = self.unify(other) return a + b deg1 = self.annihilator.order deg2 = other.annihilator.order dim = max(deg1, deg2) R = self.annihilator.parent.base K = R.get_field() rowsself = [self.annihilator] rowsother = [other.annihilator] gen = self.annihilator.parent.derivative_operator # constructing annihilators up to order dim for i in range(dim - deg1): diff1 = (gen * rowsself[-1]) rowsself.append(diff1) for i in range(dim - deg2): diff2 = (gen * rowsother[-1]) rowsother.append(diff2) row = rowsself + rowsother # constructing the matrix of the ansatz r = [] for expr in row: p = [] for i in range(dim + 1): if i >= len(expr.listofpoly): p.append(K.zero) else: p.append(K.new(expr.listofpoly[i].rep)) r.append(p) # solving the linear system using gauss jordan solver r = DomainMatrix(r, (len(row), dim+1), K).transpose() homosys = DomainMatrix.zeros((dim+1, 1), K) sol = _find_nonzero_solution(r, homosys) # if a solution is not obtained then increasing the order by 1 in each # iteration while sol.is_zero_matrix: dim += 1 diff1 = (gen * rowsself[-1]) rowsself.append(diff1) diff2 = (gen * rowsother[-1]) rowsother.append(diff2) row = rowsself + rowsother r = [] for expr in row: p = [] for i in range(dim + 1): if i >= len(expr.listofpoly): p.append(K.zero) else: p.append(K.new(expr.listofpoly[i].rep)) r.append(p) # solving the linear system using gauss jordan solver r = DomainMatrix(r, (len(row), dim+1), K).transpose() homosys = DomainMatrix.zeros((dim+1, 1), K) sol = _find_nonzero_solution(r, homosys) # taking only the coefficients needed to multiply with `self` # can be also be done the other way by taking R.H.S and multiplying with # `other` sol = sol.flat()[:dim + 1 - deg1] sol1 = _normalize(sol, self.annihilator.parent) # annihilator of the solution sol = sol1 * (self.annihilator) sol = _normalize(sol.listofpoly, self.annihilator.parent, negative=False) if not (self._have_init_cond() and other._have_init_cond()): return HolonomicFunction(sol, self.x) # both the functions have ordinary initial conditions if self.is_singularics() == False and other.is_singularics() == False: # directly add the corresponding value if self.x0 == other.x0: # try to extended the initial conditions # using the annihilator y1 = _extend_y0(self, sol.order) y2 = _extend_y0(other, sol.order) y0 = [a + b for a, b in zip(y1, y2)] return HolonomicFunction(sol, self.x, self.x0, y0) else: # change the intiial conditions to a same point selfat0 = self.annihilator.is_singular(0) otherat0 = other.annihilator.is_singular(0) if self.x0 == 0 and not selfat0 and not otherat0: return self + other.change_ics(0) elif other.x0 == 0 and not selfat0 and not otherat0: return self.change_ics(0) + other else: selfatx0 = self.annihilator.is_singular(self.x0) otheratx0 = other.annihilator.is_singular(self.x0) if not selfatx0 and not otheratx0: return self + other.change_ics(self.x0) else: return self.change_ics(other.x0) + other if self.x0 != other.x0: return HolonomicFunction(sol, self.x) # if the functions have singular_ics y1 = None y2 = None if self.is_singularics() == False and other.is_singularics() == True: # convert the ordinary initial condition to singular. _y0 = [j / factorial(i) for i, j in enumerate(self.y0)] y1 = {S.Zero: _y0} y2 = other.y0 elif self.is_singularics() == True and other.is_singularics() == False: _y0 = [j / factorial(i) for i, j in enumerate(other.y0)] y1 = self.y0 y2 = {S.Zero: _y0} elif self.is_singularics() == True and other.is_singularics() == True: y1 = self.y0 y2 = other.y0 # computing singular initial condition for the result # taking union of the series terms of both functions y0 = {} for i in y1: # add corresponding initial terms if the power # on `x` is same if i in y2: y0[i] = [a + b for a, b in zip(y1[i], y2[i])] else: y0[i] = y1[i] for i in y2: if not i in y1: y0[i] = y2[i] return HolonomicFunction(sol, self.x, self.x0, y0) def integrate(self, limits, initcond=False): """ Integrates the given holonomic function. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import QQ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') >>> HolonomicFunction(Dx - 1, x, 0, [1]).integrate((x, 0, x)) # e^x - 1 HolonomicFunction((-1)*Dx + (1)*Dx**2, x, 0, [0, 1]) >>> HolonomicFunction(Dx**2 + 1, x, 0, [1, 0]).integrate((x, 0, x)) HolonomicFunction((1)*Dx + (1)*Dx**3, x, 0, [0, 1, 0]) """ # to get the annihilator, just multiply by Dx from right D = self.annihilator.parent.derivative_operator # if the function have initial conditions of the series format if self.is_singularics() == True: r = self._singularics_to_ord() if r: return r.integrate(limits, initcond=initcond) # computing singular initial condition for the function # produced after integration. y0 = {} for i in self.y0: c = self.y0[i] c2 = [] for j in range(len(c)): if c[j] == 0: c2.append(S.Zero) # if power on `x` is -1, the integration becomes log(x) # TODO: Implement this case elif i + j + 1 == 0: raise NotImplementedError("logarithmic terms in the series are not supported") else: c2.append(c[j] / S(i + j + 1)) y0[i + 1] = c2 if hasattr(limits, "__iter__"): raise NotImplementedError("Definite integration for singular initial conditions") return HolonomicFunction(self.annihilator * D, self.x, self.x0, y0) # if no initial conditions are available for the function if not self._have_init_cond(): if initcond: return HolonomicFunction(self.annihilator * D, self.x, self.x0, [S.Zero]) return HolonomicFunction(self.annihilator * D, self.x) # definite integral # initial conditions for the answer will be stored at point `a`, # where `a` is the lower limit of the integrand if hasattr(limits, "__iter__"): if len(limits) == 3 and limits[0] == self.x: x0 = self.x0 a = limits[1] b = limits[2] definite = True else: definite = False y0 = [S.Zero] y0 += self.y0 indefinite_integral = HolonomicFunction(self.annihilator * D, self.x, self.x0, y0) if not definite: return indefinite_integral # use evalf to get the values at `a` if x0 != a: try: indefinite_expr = indefinite_integral.to_expr() except (NotHyperSeriesError, NotPowerSeriesError): indefinite_expr = None if indefinite_expr: lower = indefinite_expr.subs(self.x, a) if isinstance(lower, NaN): lower = indefinite_expr.limit(self.x, a) else: lower = indefinite_integral.evalf(a) if b == self.x: y0[0] = y0[0] - lower return HolonomicFunction(self.annihilator * D, self.x, x0, y0) elif S(b).is_Number: if indefinite_expr: upper = indefinite_expr.subs(self.x, b) if isinstance(upper, NaN): upper = indefinite_expr.limit(self.x, b) else: upper = indefinite_integral.evalf(b) return upper - lower # if the upper limit is `x`, the answer will be a function if b == self.x: return HolonomicFunction(self.annihilator * D, self.x, a, y0) # if the upper limits is a Number, a numerical value will be returned elif S(b).is_Number: try: s = HolonomicFunction(self.annihilator * D, self.x, a,\ y0).to_expr() indefinite = s.subs(self.x, b) if not isinstance(indefinite, NaN): return indefinite else: return s.limit(self.x, b) except (NotHyperSeriesError, NotPowerSeriesError): return HolonomicFunction(self.annihilator * D, self.x, a, y0).evalf(b) return HolonomicFunction(self.annihilator * D, self.x) def diff(self, *args, **kwargs): r""" Differentiation of the given Holonomic function. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import ZZ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') >>> HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]).diff().to_expr() cos(x) >>> HolonomicFunction(Dx - 2, x, 0, [1]).diff().to_expr() 2*exp(2*x) See Also ======== .integrate() """ kwargs.setdefault('evaluate', True) if args: if args[0] != self.x: return S.Zero elif len(args) == 2: sol = self for i in range(args[1]): sol = sol.diff(args[0]) return sol ann = self.annihilator # if the function is constant. if ann.listofpoly[0] == ann.parent.base.zero and ann.order == 1: return S.Zero # if the coefficient of y in the differential equation is zero. # a shifting is done to compute the answer in this case. elif ann.listofpoly[0] == ann.parent.base.zero: sol = DifferentialOperator(ann.listofpoly[1:], ann.parent) if self._have_init_cond(): # if ordinary initial condition if self.is_singularics() == False: return HolonomicFunction(sol, self.x, self.x0, self.y0[1:]) # TODO: support for singular initial condition return HolonomicFunction(sol, self.x) else: return HolonomicFunction(sol, self.x) # the general algorithm R = ann.parent.base K = R.get_field() seq_dmf = [K.new(i.rep) for i in ann.listofpoly] # -y = a1*y'/a0 + a2*y''/a0 ... + an*y^n/a0 rhs = [i / seq_dmf[0] for i in seq_dmf[1:]] rhs.insert(0, K.zero) # differentiate both lhs and rhs sol = _derivate_diff_eq(rhs) # add the term y' in lhs to rhs sol = _add_lists(sol, [K.zero, K.one]) sol = _normalize(sol[1:], self.annihilator.parent, negative=False) if not self._have_init_cond() or self.is_singularics() == True: return HolonomicFunction(sol, self.x) y0 = _extend_y0(self, sol.order + 1)[1:] return HolonomicFunction(sol, self.x, self.x0, y0) def __eq__(self, other): if self.annihilator == other.annihilator: if self.x == other.x: if self._have_init_cond() and other._have_init_cond(): if self.x0 == other.x0 and self.y0 == other.y0: return True else: return False else: return True else: return False else: return False def __mul__(self, other): ann_self = self.annihilator if not isinstance(other, HolonomicFunction): other = sympify(other) if other.has(self.x): raise NotImplementedError(" Can't multiply a HolonomicFunction and expressions/functions.") if not self._have_init_cond(): return self else: y0 = _extend_y0(self, ann_self.order) y1 = [] for j in y0: y1.append((Poly.new(j, self.x) * other).rep) return HolonomicFunction(ann_self, self.x, self.x0, y1) if self.annihilator.parent.base != other.annihilator.parent.base: a, b = self.unify(other) return a * b ann_other = other.annihilator list_self = [] list_other = [] a = ann_self.order b = ann_other.order R = ann_self.parent.base K = R.get_field() for j in ann_self.listofpoly: list_self.append(K.new(j.rep)) for j in ann_other.listofpoly: list_other.append(K.new(j.rep)) # will be used to reduce the degree self_red = [-list_self[i] / list_self[a] for i in range(a)] other_red = [-list_other[i] / list_other[b] for i in range(b)] # coeff_mull[i][j] is the coefficient of Dx^i(f).Dx^j(g) coeff_mul = [[K.zero for i in range(b + 1)] for j in range(a + 1)] coeff_mul[0][0] = K.one # making the ansatz lin_sys_elements = [[coeff_mul[i][j] for i in range(a) for j in range(b)]] lin_sys = DomainMatrix(lin_sys_elements, (1, a*b), K).transpose() homo_sys = DomainMatrix.zeros((a*b, 1), K) sol = _find_nonzero_solution(lin_sys, homo_sys) # until a non trivial solution is found while sol.is_zero_matrix: # updating the coefficients Dx^i(f).Dx^j(g) for next degree for i in range(a - 1, -1, -1): for j in range(b - 1, -1, -1): coeff_mul[i][j + 1] += coeff_mul[i][j] coeff_mul[i + 1][j] += coeff_mul[i][j] if isinstance(coeff_mul[i][j], K.dtype): coeff_mul[i][j] = DMFdiff(coeff_mul[i][j]) else: coeff_mul[i][j] = coeff_mul[i][j].diff(self.x) # reduce the terms to lower power using annihilators of f, g for i in range(a + 1): if not coeff_mul[i][b].is_zero: for j in range(b): coeff_mul[i][j] += other_red[j] * \ coeff_mul[i][b] coeff_mul[i][b] = K.zero # not d2 + 1, as that is already covered in previous loop for j in range(b): if not coeff_mul[a][j] == 0: for i in range(a): coeff_mul[i][j] += self_red[i] * \ coeff_mul[a][j] coeff_mul[a][j] = K.zero lin_sys_elements.append([coeff_mul[i][j] for i in range(a) for j in range(b)]) lin_sys = DomainMatrix(lin_sys_elements, (len(lin_sys_elements), a*b), K).transpose() sol = _find_nonzero_solution(lin_sys, homo_sys) sol_ann = _normalize(sol.flat(), self.annihilator.parent, negative=False) if not (self._have_init_cond() and other._have_init_cond()): return HolonomicFunction(sol_ann, self.x) if self.is_singularics() == False and other.is_singularics() == False: # if both the conditions are at same point if self.x0 == other.x0: # try to find more initial conditions y0_self = _extend_y0(self, sol_ann.order) y0_other = _extend_y0(other, sol_ann.order) # h(x0) = f(x0) * g(x0) y0 = [y0_self[0] * y0_other[0]] # coefficient of Dx^j(f)*Dx^i(g) in Dx^i(fg) for i in range(1, min(len(y0_self), len(y0_other))): coeff = [[0 for i in range(i + 1)] for j in range(i + 1)] for j in range(i + 1): for k in range(i + 1): if j + k == i: coeff[j][k] = binomial(i, j) sol = 0 for j in range(i + 1): for k in range(i + 1): sol += coeff[j][k]* y0_self[j] * y0_other[k] y0.append(sol) return HolonomicFunction(sol_ann, self.x, self.x0, y0) # if the points are different, consider one else: selfat0 = self.annihilator.is_singular(0) otherat0 = other.annihilator.is_singular(0) if self.x0 == 0 and not selfat0 and not otherat0: return self * other.change_ics(0) elif other.x0 == 0 and not selfat0 and not otherat0: return self.change_ics(0) * other else: selfatx0 = self.annihilator.is_singular(self.x0) otheratx0 = other.annihilator.is_singular(self.x0) if not selfatx0 and not otheratx0: return self * other.change_ics(self.x0) else: return self.change_ics(other.x0) * other if self.x0 != other.x0: return HolonomicFunction(sol_ann, self.x) # if the functions have singular_ics y1 = None y2 = None if self.is_singularics() == False and other.is_singularics() == True: _y0 = [j / factorial(i) for i, j in enumerate(self.y0)] y1 = {S.Zero: _y0} y2 = other.y0 elif self.is_singularics() == True and other.is_singularics() == False: _y0 = [j / factorial(i) for i, j in enumerate(other.y0)] y1 = self.y0 y2 = {S.Zero: _y0} elif self.is_singularics() == True and other.is_singularics() == True: y1 = self.y0 y2 = other.y0 y0 = {} # multiply every possible pair of the series terms for i in y1: for j in y2: k = min(len(y1[i]), len(y2[j])) c = [] for a in range(k): s = S.Zero for b in range(a + 1): s += y1[i][b] * y2[j][a - b] c.append(s) if not i + j in y0: y0[i + j] = c else: y0[i + j] = [a + b for a, b in zip(c, y0[i + j])] return HolonomicFunction(sol_ann, self.x, self.x0, y0) __rmul__ = __mul__ def __sub__(self, other): return self + other * -1 def __rsub__(self, other): return self * -1 + other def __neg__(self): return -1 * self def __truediv__(self, other): return self * (S.One / other) def __pow__(self, n): if self.annihilator.order <= 1: ann = self.annihilator parent = ann.parent if self.y0 is None: y0 = None else: y0 = [list(self.y0)[0] ** n] p0 = ann.listofpoly[0] p1 = ann.listofpoly[1] p0 = (Poly.new(p0, self.x) * n).rep sol = [parent.base.to_sympy(i) for i in [p0, p1]] dd = DifferentialOperator(sol, parent) return HolonomicFunction(dd, self.x, self.x0, y0) if n < 0: raise NotHolonomicError("Negative Power on a Holonomic Function") if n == 0: Dx = self.annihilator.parent.derivative_operator return HolonomicFunction(Dx, self.x, S.Zero, [S.One]) if n == 1: return self else: if n % 2 == 1: powreduce = self**(n - 1) return powreduce * self elif n % 2 == 0: powreduce = self**(n / 2) return powreduce * powreduce def degree(self): """ Returns the highest power of `x` in the annihilator. """ sol = [i.degree() for i in self.annihilator.listofpoly] return max(sol) def composition(self, expr, *args, **kwargs): """ Returns function after composition of a holonomic function with an algebraic function. The method can't compute initial conditions for the result by itself, so they can be also be provided. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import QQ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') >>> HolonomicFunction(Dx - 1, x).composition(x**2, 0, [1]) # e^(x**2) HolonomicFunction((-2*x) + (1)*Dx, x, 0, [1]) >>> HolonomicFunction(Dx**2 + 1, x).composition(x**2 - 1, 1, [1, 0]) HolonomicFunction((4*x**3) + (-1)*Dx + (x)*Dx**2, x, 1, [1, 0]) See Also ======== from_hyper() """ R = self.annihilator.parent a = self.annihilator.order diff = expr.diff(self.x) listofpoly = self.annihilator.listofpoly for i, j in enumerate(listofpoly): if isinstance(j, self.annihilator.parent.base.dtype): listofpoly[i] = self.annihilator.parent.base.to_sympy(j) r = listofpoly[a].subs({self.x:expr}) subs = [-listofpoly[i].subs({self.x:expr}) / r for i in range (a)] coeffs = [S.Zero for i in range(a)] # coeffs[i] == coeff of (D^i f)(a) in D^k (f(a)) coeffs[0] = S.One system = [coeffs] homogeneous = Matrix([[S.Zero for i in range(a)]]).transpose() while True: coeffs_next = [p.diff(self.x) for p in coeffs] for i in range(a - 1): coeffs_next[i + 1] += (coeffs[i] * diff) for i in range(a): coeffs_next[i] += (coeffs[-1] * subs[i] * diff) coeffs = coeffs_next # check for linear relations system.append(coeffs) sol, taus = (Matrix(system).transpose() ).gauss_jordan_solve(homogeneous) if sol.is_zero_matrix is not True: break tau = list(taus)[0] sol = sol.subs(tau, 1) sol = _normalize(sol[0:], R, negative=False) # if initial conditions are given for the resulting function if args: return HolonomicFunction(sol, self.x, args[0], args[1]) return HolonomicFunction(sol, self.x) def to_sequence(self, lb=True): r""" Finds recurrence relation for the coefficients in the series expansion of the function about :math:`x_0`, where :math:`x_0` is the point at which the initial condition is stored. Explanation =========== If the point :math:`x_0` is ordinary, solution of the form :math:`[(R, n_0)]` is returned. Where :math:`R` is the recurrence relation and :math:`n_0` is the smallest ``n`` for which the recurrence holds true. If the point :math:`x_0` is regular singular, a list of solutions in the format :math:`(R, p, n_0)` is returned, i.e. `[(R, p, n_0), ... ]`. Each tuple in this vector represents a recurrence relation :math:`R` associated with a root of the indicial equation ``p``. Conditions of a different format can also be provided in this case, see the docstring of HolonomicFunction class. If it's not possible to numerically compute a initial condition, it is returned as a symbol :math:`C_j`, denoting the coefficient of :math:`(x - x_0)^j` in the power series about :math:`x_0`. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import QQ >>> from sympy import symbols, S >>> x = symbols('x') >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') >>> HolonomicFunction(Dx - 1, x, 0, [1]).to_sequence() [(HolonomicSequence((-1) + (n + 1)Sn, n), u(0) = 1, 0)] >>> HolonomicFunction((1 + x)*Dx**2 + Dx, x, 0, [0, 1]).to_sequence() [(HolonomicSequence((n**2) + (n**2 + n)Sn, n), u(0) = 0, u(1) = 1, u(2) = -1/2, 2)] >>> HolonomicFunction(-S(1)/2 + x*Dx, x, 0, {S(1)/2: [1]}).to_sequence() [(HolonomicSequence((n), n), u(0) = 1, 1/2, 1)] See Also ======== HolonomicFunction.series() References ========== .. [1] https://hal.inria.fr/inria-00070025/document .. [2] http://www.risc.jku.at/publications/download/risc_2244/DIPLFORM.pdf """ if self.x0 != 0: return self.shift_x(self.x0).to_sequence() # check whether a power series exists if the point is singular if self.annihilator.is_singular(self.x0): return self._frobenius(lb=lb) dict1 = {} n = Symbol('n', integer=True) dom = self.annihilator.parent.base.dom R, _ = RecurrenceOperators(dom.old_poly_ring(n), 'Sn') # substituting each term of the form `x^k Dx^j` in the # annihilator, according to the formula below: # x^k Dx^j = Sum(rf(n + 1 - k, j) * a(n + j - k) * x^n, (n, k, oo)) # for explanation see [2]. for i, j in enumerate(self.annihilator.listofpoly): listofdmp = j.all_coeffs() degree = len(listofdmp) - 1 for k in range(degree + 1): coeff = listofdmp[degree - k] if coeff == 0: continue if (i - k, k) in dict1: dict1[(i - k, k)] += (dom.to_sympy(coeff) * rf(n - k + 1, i)) else: dict1[(i - k, k)] = (dom.to_sympy(coeff) * rf(n - k + 1, i)) sol = [] keylist = [i[0] for i in dict1] lower = min(keylist) upper = max(keylist) degree = self.degree() # the recurrence relation holds for all values of # n greater than smallest_n, i.e. n >= smallest_n smallest_n = lower + degree dummys = {} eqs = [] unknowns = [] # an appropriate shift of the recurrence for j in range(lower, upper + 1): if j in keylist: temp = S.Zero for k in dict1.keys(): if k[0] == j: temp += dict1[k].subs(n, n - lower) sol.append(temp) else: sol.append(S.Zero) # the recurrence relation sol = RecurrenceOperator(sol, R) # computing the initial conditions for recurrence order = sol.order all_roots = roots(R.base.to_sympy(sol.listofpoly[-1]), n, filter='Z') all_roots = all_roots.keys() if all_roots: max_root = max(all_roots) + 1 smallest_n = max(max_root, smallest_n) order += smallest_n y0 = _extend_y0(self, order) u0 = [] # u(n) = y^n(0)/factorial(n) for i, j in enumerate(y0): u0.append(j / factorial(i)) # if sufficient conditions can't be computed then # try to use the series method i.e. # equate the coefficients of x^k in the equation formed by # substituting the series in differential equation, to zero. if len(u0) < order: for i in range(degree): eq = S.Zero for j in dict1: if i + j[0] < 0: dummys[i + j[0]] = S.Zero elif i + j[0] < len(u0): dummys[i + j[0]] = u0[i + j[0]] elif not i + j[0] in dummys: dummys[i + j[0]] = Symbol('C_%s' %(i + j[0])) unknowns.append(dummys[i + j[0]]) if j[1] <= i: eq += dict1[j].subs(n, i) * dummys[i + j[0]] eqs.append(eq) # solve the system of equations formed soleqs = solve(eqs, *unknowns) if isinstance(soleqs, dict): for i in range(len(u0), order): if i not in dummys: dummys[i] = Symbol('C_%s' %i) if dummys[i] in soleqs: u0.append(soleqs[dummys[i]]) else: u0.append(dummys[i]) if lb: return [(HolonomicSequence(sol, u0), smallest_n)] return [HolonomicSequence(sol, u0)] for i in range(len(u0), order): if i not in dummys: dummys[i] = Symbol('C_%s' %i) s = False for j in soleqs: if dummys[i] in j: u0.append(j[dummys[i]]) s = True if not s: u0.append(dummys[i]) if lb: return [(HolonomicSequence(sol, u0), smallest_n)] return [HolonomicSequence(sol, u0)] def _frobenius(self, lb=True): # compute the roots of indicial equation indicialroots = self._indicial() reals = [] compl = [] for i in ordered(indicialroots.keys()): if i.is_real: reals.extend([i] * indicialroots[i]) else: a, b = i.as_real_imag() compl.extend([(i, a, b)] * indicialroots[i]) # sort the roots for a fixed ordering of solution compl.sort(key=lambda x : x[1]) compl.sort(key=lambda x : x[2]) reals.sort() # grouping the roots, roots differ by an integer are put in the same group. grp = [] for i in reals: intdiff = False if len(grp) == 0: grp.append([i]) continue for j in grp: if int(j[0] - i) == j[0] - i: j.append(i) intdiff = True break if not intdiff: grp.append([i]) # True if none of the roots differ by an integer i.e. # each element in group have only one member independent = True if all(len(i) == 1 for i in grp) else False allpos = all(i >= 0 for i in reals) allint = all(int(i) == i for i in reals) # if initial conditions are provided # then use them. if self.is_singularics() == True: rootstoconsider = [] for i in ordered(self.y0.keys()): for j in ordered(indicialroots.keys()): if j == i: rootstoconsider.append(i) elif allpos and allint: rootstoconsider = [min(reals)] elif independent: rootstoconsider = [i[0] for i in grp] + [j[0] for j in compl] elif not allint: rootstoconsider = [] for i in reals: if not int(i) == i: rootstoconsider.append(i) elif not allpos: if not self._have_init_cond() or S(self.y0[0]).is_finite == False: rootstoconsider = [min(reals)] else: posroots = [] for i in reals: if i >= 0: posroots.append(i) rootstoconsider = [min(posroots)] n = Symbol('n', integer=True) dom = self.annihilator.parent.base.dom R, _ = RecurrenceOperators(dom.old_poly_ring(n), 'Sn') finalsol = [] char = ord('C') for p in rootstoconsider: dict1 = {} for i, j in enumerate(self.annihilator.listofpoly): listofdmp = j.all_coeffs() degree = len(listofdmp) - 1 for k in range(degree + 1): coeff = listofdmp[degree - k] if coeff == 0: continue if (i - k, k - i) in dict1: dict1[(i - k, k - i)] += (dom.to_sympy(coeff) * rf(n - k + 1 + p, i)) else: dict1[(i - k, k - i)] = (dom.to_sympy(coeff) * rf(n - k + 1 + p, i)) sol = [] keylist = [i[0] for i in dict1] lower = min(keylist) upper = max(keylist) degree = max([i[1] for i in dict1]) degree2 = min([i[1] for i in dict1]) smallest_n = lower + degree dummys = {} eqs = [] unknowns = [] for j in range(lower, upper + 1): if j in keylist: temp = S.Zero for k in dict1.keys(): if k[0] == j: temp += dict1[k].subs(n, n - lower) sol.append(temp) else: sol.append(S.Zero) # the recurrence relation sol = RecurrenceOperator(sol, R) # computing the initial conditions for recurrence order = sol.order all_roots = roots(R.base.to_sympy(sol.listofpoly[-1]), n, filter='Z') all_roots = all_roots.keys() if all_roots: max_root = max(all_roots) + 1 smallest_n = max(max_root, smallest_n) order += smallest_n u0 = [] if self.is_singularics() == True: u0 = self.y0[p] elif self.is_singularics() == False and p >= 0 and int(p) == p and len(rootstoconsider) == 1: y0 = _extend_y0(self, order + int(p)) # u(n) = y^n(0)/factorial(n) if len(y0) > int(p): for i in range(int(p), len(y0)): u0.append(y0[i] / factorial(i)) if len(u0) < order: for i in range(degree2, degree): eq = S.Zero for j in dict1: if i + j[0] < 0: dummys[i + j[0]] = S.Zero elif i + j[0] < len(u0): dummys[i + j[0]] = u0[i + j[0]] elif not i + j[0] in dummys: letter = chr(char) + '_%s' %(i + j[0]) dummys[i + j[0]] = Symbol(letter) unknowns.append(dummys[i + j[0]]) if j[1] <= i: eq += dict1[j].subs(n, i) * dummys[i + j[0]] eqs.append(eq) # solve the system of equations formed soleqs = solve(eqs, *unknowns) if isinstance(soleqs, dict): for i in range(len(u0), order): if i not in dummys: letter = chr(char) + '_%s' %i dummys[i] = Symbol(letter) if dummys[i] in soleqs: u0.append(soleqs[dummys[i]]) else: u0.append(dummys[i]) if lb: finalsol.append((HolonomicSequence(sol, u0), p, smallest_n)) continue else: finalsol.append((HolonomicSequence(sol, u0), p)) continue for i in range(len(u0), order): if i not in dummys: letter = chr(char) + '_%s' %i dummys[i] = Symbol(letter) s = False for j in soleqs: if dummys[i] in j: u0.append(j[dummys[i]]) s = True if not s: u0.append(dummys[i]) if lb: finalsol.append((HolonomicSequence(sol, u0), p, smallest_n)) else: finalsol.append((HolonomicSequence(sol, u0), p)) char += 1 return finalsol def series(self, n=6, coefficient=False, order=True, _recur=None): r""" Finds the power series expansion of given holonomic function about :math:`x_0`. Explanation =========== A list of series might be returned if :math:`x_0` is a regular point with multiple roots of the indicial equation. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import QQ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') >>> HolonomicFunction(Dx - 1, x, 0, [1]).series() # e^x 1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + O(x**6) >>> HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]).series(n=8) # sin(x) x - x**3/6 + x**5/120 - x**7/5040 + O(x**8) See Also ======== HolonomicFunction.to_sequence() """ if _recur is None: recurrence = self.to_sequence() else: recurrence = _recur if isinstance(recurrence, tuple) and len(recurrence) == 2: recurrence = recurrence[0] constantpower = 0 elif isinstance(recurrence, tuple) and len(recurrence) == 3: constantpower = recurrence[1] recurrence = recurrence[0] elif len(recurrence) == 1 and len(recurrence[0]) == 2: recurrence = recurrence[0][0] constantpower = 0 elif len(recurrence) == 1 and len(recurrence[0]) == 3: constantpower = recurrence[0][1] recurrence = recurrence[0][0] else: sol = [] for i in recurrence: sol.append(self.series(_recur=i)) return sol n = n - int(constantpower) l = len(recurrence.u0) - 1 k = recurrence.recurrence.order x = self.x x0 = self.x0 seq_dmp = recurrence.recurrence.listofpoly R = recurrence.recurrence.parent.base K = R.get_field() seq = [] for i, j in enumerate(seq_dmp): seq.append(K.new(j.rep)) sub = [-seq[i] / seq[k] for i in range(k)] sol = [i for i in recurrence.u0] if l + 1 >= n: pass else: # use the initial conditions to find the next term for i in range(l + 1 - k, n - k): coeff = S.Zero for j in range(k): if i + j >= 0: coeff += DMFsubs(sub[j], i) * sol[i + j] sol.append(coeff) if coefficient: return sol ser = S.Zero for i, j in enumerate(sol): ser += x**(i + constantpower) * j if order: ser += Order(x**(n + int(constantpower)), x) if x0 != 0: return ser.subs(x, x - x0) return ser def _indicial(self): """ Computes roots of the Indicial equation. """ if self.x0 != 0: return self.shift_x(self.x0)._indicial() list_coeff = self.annihilator.listofpoly R = self.annihilator.parent.base x = self.x s = R.zero y = R.one def _pole_degree(poly): root_all = roots(R.to_sympy(poly), x, filter='Z') if 0 in root_all.keys(): return root_all[0] else: return 0 degree = [j.degree() for j in list_coeff] degree = max(degree) inf = 10 * (max(1, degree) + max(1, self.annihilator.order)) deg = lambda q: inf if q.is_zero else _pole_degree(q) b = deg(list_coeff[0]) for j in range(1, len(list_coeff)): b = min(b, deg(list_coeff[j]) - j) for i, j in enumerate(list_coeff): listofdmp = j.all_coeffs() degree = len(listofdmp) - 1 if - i - b <= 0 and degree - i - b >= 0: s = s + listofdmp[degree - i - b] * y y *= x - i return roots(R.to_sympy(s), x) def evalf(self, points, method='RK4', h=0.05, derivatives=False): r""" Finds numerical value of a holonomic function using numerical methods. (RK4 by default). A set of points (real or complex) must be provided which will be the path for the numerical integration. Explanation =========== The path should be given as a list :math:`[x_1, x_2, ... x_n]`. The numerical values will be computed at each point in this order :math:`x_1 --> x_2 --> x_3 ... --> x_n`. Returns values of the function at :math:`x_1, x_2, ... x_n` in a list. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import QQ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(QQ.old_poly_ring(x),'Dx') A straight line on the real axis from (0 to 1) >>> r = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1] Runge-Kutta 4th order on e^x from 0.1 to 1. Exact solution at 1 is 2.71828182845905 >>> HolonomicFunction(Dx - 1, x, 0, [1]).evalf(r) [1.10517083333333, 1.22140257085069, 1.34985849706254, 1.49182424008069, 1.64872063859684, 1.82211796209193, 2.01375162659678, 2.22553956329232, 2.45960141378007, 2.71827974413517] Euler's method for the same >>> HolonomicFunction(Dx - 1, x, 0, [1]).evalf(r, method='Euler') [1.1, 1.21, 1.331, 1.4641, 1.61051, 1.771561, 1.9487171, 2.14358881, 2.357947691, 2.5937424601] One can also observe that the value obtained using Runge-Kutta 4th order is much more accurate than Euler's method. """ from sympy.holonomic.numerical import _evalf lp = False # if a point `b` is given instead of a mesh if not hasattr(points, "__iter__"): lp = True b = S(points) if self.x0 == b: return _evalf(self, [b], method=method, derivatives=derivatives)[-1] if not b.is_Number: raise NotImplementedError a = self.x0 if a > b: h = -h n = int((b - a) / h) points = [a + h] for i in range(n - 1): points.append(points[-1] + h) for i in roots(self.annihilator.parent.base.to_sympy(self.annihilator.listofpoly[-1]), self.x): if i == self.x0 or i in points: raise SingularityError(self, i) if lp: return _evalf(self, points, method=method, derivatives=derivatives)[-1] return _evalf(self, points, method=method, derivatives=derivatives) def change_x(self, z): """ Changes only the variable of Holonomic Function, for internal purposes. For composition use HolonomicFunction.composition() """ dom = self.annihilator.parent.base.dom R = dom.old_poly_ring(z) parent, _ = DifferentialOperators(R, 'Dx') sol = [] for j in self.annihilator.listofpoly: sol.append(R(j.rep)) sol = DifferentialOperator(sol, parent) return HolonomicFunction(sol, z, self.x0, self.y0) def shift_x(self, a): """ Substitute `x + a` for `x`. """ x = self.x listaftershift = self.annihilator.listofpoly base = self.annihilator.parent.base sol = [base.from_sympy(base.to_sympy(i).subs(x, x + a)) for i in listaftershift] sol = DifferentialOperator(sol, self.annihilator.parent) x0 = self.x0 - a if not self._have_init_cond(): return HolonomicFunction(sol, x) return HolonomicFunction(sol, x, x0, self.y0) def to_hyper(self, as_list=False, _recur=None): r""" Returns a hypergeometric function (or linear combination of them) representing the given holonomic function. Explanation =========== Returns an answer of the form: `a_1 \cdot x^{b_1} \cdot{hyper()} + a_2 \cdot x^{b_2} \cdot{hyper()} ...` This is very useful as one can now use ``hyperexpand`` to find the symbolic expressions/functions. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import ZZ >>> from sympy import symbols >>> x = symbols('x') >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') >>> # sin(x) >>> HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]).to_hyper() x*hyper((), (3/2,), -x**2/4) >>> # exp(x) >>> HolonomicFunction(Dx - 1, x, 0, [1]).to_hyper() hyper((), (), x) See Also ======== from_hyper, from_meijerg """ if _recur is None: recurrence = self.to_sequence() else: recurrence = _recur if isinstance(recurrence, tuple) and len(recurrence) == 2: smallest_n = recurrence[1] recurrence = recurrence[0] constantpower = 0 elif isinstance(recurrence, tuple) and len(recurrence) == 3: smallest_n = recurrence[2] constantpower = recurrence[1] recurrence = recurrence[0] elif len(recurrence) == 1 and len(recurrence[0]) == 2: smallest_n = recurrence[0][1] recurrence = recurrence[0][0] constantpower = 0 elif len(recurrence) == 1 and len(recurrence[0]) == 3: smallest_n = recurrence[0][2] constantpower = recurrence[0][1] recurrence = recurrence[0][0] else: sol = self.to_hyper(as_list=as_list, _recur=recurrence[0]) for i in recurrence[1:]: sol += self.to_hyper(as_list=as_list, _recur=i) return sol u0 = recurrence.u0 r = recurrence.recurrence x = self.x x0 = self.x0 # order of the recurrence relation m = r.order # when no recurrence exists, and the power series have finite terms if m == 0: nonzeroterms = roots(r.parent.base.to_sympy(r.listofpoly[0]), recurrence.n, filter='R') sol = S.Zero for j, i in enumerate(nonzeroterms): if i < 0 or int(i) != i: continue i = int(i) if i < len(u0): if isinstance(u0[i], (PolyElement, FracElement)): u0[i] = u0[i].as_expr() sol += u0[i] * x**i else: sol += Symbol('C_%s' %j) * x**i if isinstance(sol, (PolyElement, FracElement)): sol = sol.as_expr() * x**constantpower else: sol = sol * x**constantpower if as_list: if x0 != 0: return [(sol.subs(x, x - x0), )] return [(sol, )] if x0 != 0: return sol.subs(x, x - x0) return sol if smallest_n + m > len(u0): raise NotImplementedError("Can't compute sufficient Initial Conditions") # check if the recurrence represents a hypergeometric series is_hyper = True for i in range(1, len(r.listofpoly)-1): if r.listofpoly[i] != r.parent.base.zero: is_hyper = False break if not is_hyper: raise NotHyperSeriesError(self, self.x0) a = r.listofpoly[0] b = r.listofpoly[-1] # the constant multiple of argument of hypergeometric function if isinstance(a.rep[0], (PolyElement, FracElement)): c = - (S(a.rep[0].as_expr()) * m**(a.degree())) / (S(b.rep[0].as_expr()) * m**(b.degree())) else: c = - (S(a.rep[0]) * m**(a.degree())) / (S(b.rep[0]) * m**(b.degree())) sol = 0 arg1 = roots(r.parent.base.to_sympy(a), recurrence.n) arg2 = roots(r.parent.base.to_sympy(b), recurrence.n) # iterate through the initial conditions to find # the hypergeometric representation of the given # function. # The answer will be a linear combination # of different hypergeometric series which satisfies # the recurrence. if as_list: listofsol = [] for i in range(smallest_n + m): # if the recurrence relation doesn't hold for `n = i`, # then a Hypergeometric representation doesn't exist. # add the algebraic term a * x**i to the solution, # where a is u0[i] if i < smallest_n: if as_list: listofsol.append(((S(u0[i]) * x**(i+constantpower)).subs(x, x-x0), )) else: sol += S(u0[i]) * x**i continue # if the coefficient u0[i] is zero, then the # independent hypergeomtric series starting with # x**i is not a part of the answer. if S(u0[i]) == 0: continue ap = [] bq = [] # substitute m * n + i for n for k in ordered(arg1.keys()): ap.extend([nsimplify((i - k) / m)] * arg1[k]) for k in ordered(arg2.keys()): bq.extend([nsimplify((i - k) / m)] * arg2[k]) # convention of (k + 1) in the denominator if 1 in bq: bq.remove(1) else: ap.append(1) if as_list: listofsol.append(((S(u0[i])*x**(i+constantpower)).subs(x, x-x0), (hyper(ap, bq, c*x**m)).subs(x, x-x0))) else: sol += S(u0[i]) * hyper(ap, bq, c * x**m) * x**i if as_list: return listofsol sol = sol * x**constantpower if x0 != 0: return sol.subs(x, x - x0) return sol def to_expr(self): """ Converts a Holonomic Function back to elementary functions. Examples ======== >>> from sympy.holonomic.holonomic import HolonomicFunction, DifferentialOperators >>> from sympy.polys.domains import ZZ >>> from sympy import symbols, S >>> x = symbols('x') >>> R, Dx = DifferentialOperators(ZZ.old_poly_ring(x),'Dx') >>> HolonomicFunction(x**2*Dx**2 + x*Dx + (x**2 - 1), x, 0, [0, S(1)/2]).to_expr() besselj(1, x) >>> HolonomicFunction((1 + x)*Dx**3 + Dx**2, x, 0, [1, 1, 1]).to_expr() x*log(x + 1) + log(x + 1) + 1 """ return hyperexpand(self.to_hyper()).simplify() def change_ics(self, b, lenics=None): """ Changes the point `x0` to ``b`` for initial conditions. Examples ======== >>> from sympy.holonomic import expr_to_holonomic >>> from sympy import symbols, sin, exp >>> x = symbols('x') >>> expr_to_holonomic(sin(x)).change_ics(1) HolonomicFunction((1) + (1)*Dx**2, x, 1, [sin(1), cos(1)]) >>> expr_to_holonomic(exp(x)).change_ics(2) HolonomicFunction((-1) + (1)*Dx, x, 2, [exp(2)]) """ symbolic = True if lenics is None and len(self.y0) > self.annihilator.order: lenics = len(self.y0) dom = self.annihilator.parent.base.domain try: sol = expr_to_holonomic(self.to_expr(), x=self.x, x0=b, lenics=lenics, domain=dom) except (NotPowerSeriesError, NotHyperSeriesError): symbolic = False if symbolic and sol.x0 == b: return sol y0 = self.evalf(b, derivatives=True) return HolonomicFunction(self.annihilator, self.x, b, y0) def to_meijerg(self): """ Returns a linear combination of Meijer G-functions. Examples ======== >>> from sympy.holonomic import expr_to_holonomic >>> from sympy import sin, cos, hyperexpand, log, symbols >>> x = symbols('x') >>> hyperexpand(expr_to_holonomic(cos(x) + sin(x)).to_meijerg()) sin(x) + cos(x) >>> hyperexpand(expr_to_holonomic(log(x)).to_meijerg()).simplify() log(x) See Also ======== to_hyper() """ # convert to hypergeometric first rep = self.to_hyper(as_list=True) sol = S.Zero for i in rep: if len(i) == 1: sol += i[0] elif len(i) == 2: sol += i[0] * _hyper_to_meijerg(i[1]) return sol def from_hyper(func, x0=0, evalf=False): r""" Converts a hypergeometric function to holonomic. ``func`` is the Hypergeometric Function and ``x0`` is the point at which initial conditions are required. Examples ======== >>> from sympy.holonomic.holonomic import from_hyper >>> from sympy import symbols, hyper, S >>> x = symbols('x') >>> from_hyper(hyper([], [S(3)/2], x**2/4)) HolonomicFunction((-x) + (2)*Dx + (x)*Dx**2, x, 1, [sinh(1), -sinh(1) + cosh(1)]) """ a = func.ap b = func.bq z = func.args[2] x = z.atoms(Symbol).pop() R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') # generalized hypergeometric differential equation r1 = 1 for i in range(len(a)): r1 = r1 * (x * Dx + a[i]) r2 = Dx for i in range(len(b)): r2 = r2 * (x * Dx + b[i] - 1) sol = r1 - r2 simp = hyperexpand(func) if isinstance(simp, Infinity) or isinstance(simp, NegativeInfinity): return HolonomicFunction(sol, x).composition(z) def _find_conditions(simp, x, x0, order, evalf=False): y0 = [] for i in range(order): if evalf: val = simp.subs(x, x0).evalf() else: val = simp.subs(x, x0) # return None if it is Infinite or NaN if val.is_finite is False or isinstance(val, NaN): return None y0.append(val) simp = simp.diff(x) return y0 # if the function is known symbolically if not isinstance(simp, hyper): y0 = _find_conditions(simp, x, x0, sol.order) while not y0: # if values don't exist at 0, then try to find initial # conditions at 1. If it doesn't exist at 1 too then # try 2 and so on. x0 += 1 y0 = _find_conditions(simp, x, x0, sol.order) return HolonomicFunction(sol, x).composition(z, x0, y0) if isinstance(simp, hyper): x0 = 1 # use evalf if the function can't be simplified y0 = _find_conditions(simp, x, x0, sol.order, evalf) while not y0: x0 += 1 y0 = _find_conditions(simp, x, x0, sol.order, evalf) return HolonomicFunction(sol, x).composition(z, x0, y0) return HolonomicFunction(sol, x).composition(z) def from_meijerg(func, x0=0, evalf=False, initcond=True, domain=QQ): """ Converts a Meijer G-function to Holonomic. ``func`` is the G-Function and ``x0`` is the point at which initial conditions are required. Examples ======== >>> from sympy.holonomic.holonomic import from_meijerg >>> from sympy import symbols, meijerg, S >>> x = symbols('x') >>> from_meijerg(meijerg(([], []), ([S(1)/2], [0]), x**2/4)) HolonomicFunction((1) + (1)*Dx**2, x, 0, [0, 1/sqrt(pi)]) """ a = func.ap b = func.bq n = len(func.an) m = len(func.bm) p = len(a) z = func.args[2] x = z.atoms(Symbol).pop() R, Dx = DifferentialOperators(domain.old_poly_ring(x), 'Dx') # compute the differential equation satisfied by the # Meijer G-function. mnp = (-1)**(m + n - p) r1 = x * mnp for i in range(len(a)): r1 *= x * Dx + 1 - a[i] r2 = 1 for i in range(len(b)): r2 *= x * Dx - b[i] sol = r1 - r2 if not initcond: return HolonomicFunction(sol, x).composition(z) simp = hyperexpand(func) if isinstance(simp, Infinity) or isinstance(simp, NegativeInfinity): return HolonomicFunction(sol, x).composition(z) def _find_conditions(simp, x, x0, order, evalf=False): y0 = [] for i in range(order): if evalf: val = simp.subs(x, x0).evalf() else: val = simp.subs(x, x0) if val.is_finite is False or isinstance(val, NaN): return None y0.append(val) simp = simp.diff(x) return y0 # computing initial conditions if not isinstance(simp, meijerg): y0 = _find_conditions(simp, x, x0, sol.order) while not y0: x0 += 1 y0 = _find_conditions(simp, x, x0, sol.order) return HolonomicFunction(sol, x).composition(z, x0, y0) if isinstance(simp, meijerg): x0 = 1 y0 = _find_conditions(simp, x, x0, sol.order, evalf) while not y0: x0 += 1 y0 = _find_conditions(simp, x, x0, sol.order, evalf) return HolonomicFunction(sol, x).composition(z, x0, y0) return HolonomicFunction(sol, x).composition(z) x_1 = Dummy('x_1') _lookup_table = None domain_for_table = None from sympy.integrals.meijerint import _mytype def expr_to_holonomic(func, x=None, x0=0, y0=None, lenics=None, domain=None, initcond=True): """ Converts a function or an expression to a holonomic function. Parameters ========== func: The expression to be converted. x: variable for the function. x0: point at which initial condition must be computed. y0: One can optionally provide initial condition if the method isn't able to do it automatically. lenics: Number of terms in the initial condition. By default it is equal to the order of the annihilator. domain: Ground domain for the polynomials in ``x`` appearing as coefficients in the annihilator. initcond: Set it false if you don't want the initial conditions to be computed. Examples ======== >>> from sympy.holonomic.holonomic import expr_to_holonomic >>> from sympy import sin, exp, symbols >>> x = symbols('x') >>> expr_to_holonomic(sin(x)) HolonomicFunction((1) + (1)*Dx**2, x, 0, [0, 1]) >>> expr_to_holonomic(exp(x)) HolonomicFunction((-1) + (1)*Dx, x, 0, [1]) See Also ======== sympy.integrals.meijerint._rewrite1, _convert_poly_rat_alg, _create_table """ func = sympify(func) syms = func.free_symbols if not x: if len(syms) == 1: x= syms.pop() else: raise ValueError("Specify the variable for the function") elif x in syms: syms.remove(x) extra_syms = list(syms) if domain is None: if func.has(Float): domain = RR else: domain = QQ if len(extra_syms) != 0: domain = domain[extra_syms].get_field() # try to convert if the function is polynomial or rational solpoly = _convert_poly_rat_alg(func, x, x0=x0, y0=y0, lenics=lenics, domain=domain, initcond=initcond) if solpoly: return solpoly # create the lookup table global _lookup_table, domain_for_table if not _lookup_table: domain_for_table = domain _lookup_table = {} _create_table(_lookup_table, domain=domain) elif domain != domain_for_table: domain_for_table = domain _lookup_table = {} _create_table(_lookup_table, domain=domain) # use the table directly to convert to Holonomic if func.is_Function: f = func.subs(x, x_1) t = _mytype(f, x_1) if t in _lookup_table: l = _lookup_table[t] sol = l[0][1].change_x(x) else: sol = _convert_meijerint(func, x, initcond=False, domain=domain) if not sol: raise NotImplementedError if y0: sol.y0 = y0 if y0 or not initcond: sol.x0 = x0 return sol if not lenics: lenics = sol.annihilator.order _y0 = _find_conditions(func, x, x0, lenics) while not _y0: x0 += 1 _y0 = _find_conditions(func, x, x0, lenics) return HolonomicFunction(sol.annihilator, x, x0, _y0) if y0 or not initcond: sol = sol.composition(func.args[0]) if y0: sol.y0 = y0 sol.x0 = x0 return sol if not lenics: lenics = sol.annihilator.order _y0 = _find_conditions(func, x, x0, lenics) while not _y0: x0 += 1 _y0 = _find_conditions(func, x, x0, lenics) return sol.composition(func.args[0], x0, _y0) # iterate through the expression recursively args = func.args f = func.func from sympy.core import Add, Mul, Pow sol = expr_to_holonomic(args[0], x=x, initcond=False, domain=domain) if f is Add: for i in range(1, len(args)): sol += expr_to_holonomic(args[i], x=x, initcond=False, domain=domain) elif f is Mul: for i in range(1, len(args)): sol *= expr_to_holonomic(args[i], x=x, initcond=False, domain=domain) elif f is Pow: sol = sol**args[1] sol.x0 = x0 if not sol: raise NotImplementedError if y0: sol.y0 = y0 if y0 or not initcond: return sol if sol.y0: return sol if not lenics: lenics = sol.annihilator.order if sol.annihilator.is_singular(x0): r = sol._indicial() l = list(r) if len(r) == 1 and r[l[0]] == S.One: r = l[0] g = func / (x - x0)**r singular_ics = _find_conditions(g, x, x0, lenics) singular_ics = [j / factorial(i) for i, j in enumerate(singular_ics)] y0 = {r:singular_ics} return HolonomicFunction(sol.annihilator, x, x0, y0) _y0 = _find_conditions(func, x, x0, lenics) while not _y0: x0 += 1 _y0 = _find_conditions(func, x, x0, lenics) return HolonomicFunction(sol.annihilator, x, x0, _y0) ## Some helper functions ## def _normalize(list_of, parent, negative=True): """ Normalize a given annihilator """ num = [] denom = [] base = parent.base K = base.get_field() lcm_denom = base.from_sympy(S.One) list_of_coeff = [] # convert polynomials to the elements of associated # fraction field for i, j in enumerate(list_of): if isinstance(j, base.dtype): list_of_coeff.append(K.new(j.rep)) elif not isinstance(j, K.dtype): list_of_coeff.append(K.from_sympy(sympify(j))) else: list_of_coeff.append(j) # corresponding numerators of the sequence of polynomials num.append(list_of_coeff[i].numer()) # corresponding denominators denom.append(list_of_coeff[i].denom()) # lcm of denominators in the coefficients for i in denom: lcm_denom = i.lcm(lcm_denom) if negative: lcm_denom = -lcm_denom lcm_denom = K.new(lcm_denom.rep) # multiply the coefficients with lcm for i, j in enumerate(list_of_coeff): list_of_coeff[i] = j * lcm_denom gcd_numer = base((list_of_coeff[-1].numer() / list_of_coeff[-1].denom()).rep) # gcd of numerators in the coefficients for i in num: gcd_numer = i.gcd(gcd_numer) gcd_numer = K.new(gcd_numer.rep) # divide all the coefficients by the gcd for i, j in enumerate(list_of_coeff): frac_ans = j / gcd_numer list_of_coeff[i] = base((frac_ans.numer() / frac_ans.denom()).rep) return DifferentialOperator(list_of_coeff, parent) def _derivate_diff_eq(listofpoly): """ Let a differential equation a0(x)y(x) + a1(x)y'(x) + ... = 0 where a0, a1,... are polynomials or rational functions. The function returns b0, b1, b2... such that the differential equation b0(x)y(x) + b1(x)y'(x) +... = 0 is formed after differentiating the former equation. """ sol = [] a = len(listofpoly) - 1 sol.append(DMFdiff(listofpoly[0])) for i, j in enumerate(listofpoly[1:]): sol.append(DMFdiff(j) + listofpoly[i]) sol.append(listofpoly[a]) return sol def _hyper_to_meijerg(func): """ Converts a `hyper` to meijerg. """ ap = func.ap bq = func.bq ispoly = any(i <= 0 and int(i) == i for i in ap) if ispoly: return hyperexpand(func) z = func.args[2] # parameters of the `meijerg` function. an = (1 - i for i in ap) anp = () bm = (S.Zero, ) bmq = (1 - i for i in bq) k = S.One for i in bq: k = k * gamma(i) for i in ap: k = k / gamma(i) return k * meijerg(an, anp, bm, bmq, -z) def _add_lists(list1, list2): """Takes polynomial sequences of two annihilators a and b and returns the list of polynomials of sum of a and b. """ if len(list1) <= len(list2): sol = [a + b for a, b in zip(list1, list2)] + list2[len(list1):] else: sol = [a + b for a, b in zip(list1, list2)] + list1[len(list2):] return sol def _extend_y0(Holonomic, n): """ Tries to find more initial conditions by substituting the initial value point in the differential equation. """ if Holonomic.annihilator.is_singular(Holonomic.x0) or Holonomic.is_singularics() == True: return Holonomic.y0 annihilator = Holonomic.annihilator a = annihilator.order listofpoly = [] y0 = Holonomic.y0 R = annihilator.parent.base K = R.get_field() for i, j in enumerate(annihilator.listofpoly): if isinstance(j, annihilator.parent.base.dtype): listofpoly.append(K.new(j.rep)) if len(y0) < a or n <= len(y0): return y0 else: list_red = [-listofpoly[i] / listofpoly[a] for i in range(a)] if len(y0) > a: y1 = [y0[i] for i in range(a)] else: y1 = [i for i in y0] for i in range(n - a): sol = 0 for a, b in zip(y1, list_red): r = DMFsubs(b, Holonomic.x0) if not getattr(r, 'is_finite', True): return y0 if isinstance(r, (PolyElement, FracElement)): r = r.as_expr() sol += a * r y1.append(sol) list_red = _derivate_diff_eq(list_red) return y0 + y1[len(y0):] def DMFdiff(frac): # differentiate a DMF object represented as p/q if not isinstance(frac, DMF): return frac.diff() K = frac.ring p = K.numer(frac) q = K.denom(frac) sol_num = - p * q.diff() + q * p.diff() sol_denom = q**2 return K((sol_num.rep, sol_denom.rep)) def DMFsubs(frac, x0, mpm=False): # substitute the point x0 in DMF object of the form p/q if not isinstance(frac, DMF): return frac p = frac.num q = frac.den sol_p = S.Zero sol_q = S.Zero if mpm: from mpmath import mp for i, j in enumerate(reversed(p)): if mpm: j = sympify(j)._to_mpmath(mp.prec) sol_p += j * x0**i for i, j in enumerate(reversed(q)): if mpm: j = sympify(j)._to_mpmath(mp.prec) sol_q += j * x0**i if isinstance(sol_p, (PolyElement, FracElement)): sol_p = sol_p.as_expr() if isinstance(sol_q, (PolyElement, FracElement)): sol_q = sol_q.as_expr() return sol_p / sol_q def _convert_poly_rat_alg(func, x, x0=0, y0=None, lenics=None, domain=QQ, initcond=True): """ Converts polynomials, rationals and algebraic functions to holonomic. """ ispoly = func.is_polynomial() if not ispoly: israt = func.is_rational_function() else: israt = True if not (ispoly or israt): basepoly, ratexp = func.as_base_exp() if basepoly.is_polynomial() and ratexp.is_Number: if isinstance(ratexp, Float): ratexp = nsimplify(ratexp) m, n = ratexp.p, ratexp.q is_alg = True else: is_alg = False else: is_alg = True if not (ispoly or israt or is_alg): return None R = domain.old_poly_ring(x) _, Dx = DifferentialOperators(R, 'Dx') # if the function is constant if not func.has(x): return HolonomicFunction(Dx, x, 0, [func]) if ispoly: # differential equation satisfied by polynomial sol = func * Dx - func.diff(x) sol = _normalize(sol.listofpoly, sol.parent, negative=False) is_singular = sol.is_singular(x0) # try to compute the conditions for singular points if y0 is None and x0 == 0 and is_singular: rep = R.from_sympy(func).rep for i, j in enumerate(reversed(rep)): if j == 0: continue else: coeff = list(reversed(rep))[i:] indicial = i break for i, j in enumerate(coeff): if isinstance(j, (PolyElement, FracElement)): coeff[i] = j.as_expr() y0 = {indicial: S(coeff)} elif israt: p, q = func.as_numer_denom() # differential equation satisfied by rational sol = p * q * Dx + p * q.diff(x) - q * p.diff(x) sol = _normalize(sol.listofpoly, sol.parent, negative=False) elif is_alg: sol = n * (x / m) * Dx - 1 sol = HolonomicFunction(sol, x).composition(basepoly).annihilator is_singular = sol.is_singular(x0) # try to compute the conditions for singular points if y0 is None and x0 == 0 and is_singular and \ (lenics is None or lenics <= 1): rep = R.from_sympy(basepoly).rep for i, j in enumerate(reversed(rep)): if j == 0: continue if isinstance(j, (PolyElement, FracElement)): j = j.as_expr() coeff = S(j)**ratexp indicial = S(i) * ratexp break if isinstance(coeff, (PolyElement, FracElement)): coeff = coeff.as_expr() y0 = {indicial: S([coeff])} if y0 or not initcond: return HolonomicFunction(sol, x, x0, y0) if not lenics: lenics = sol.order if sol.is_singular(x0): r = HolonomicFunction(sol, x, x0)._indicial() l = list(r) if len(r) == 1 and r[l[0]] == S.One: r = l[0] g = func / (x - x0)**r singular_ics = _find_conditions(g, x, x0, lenics) singular_ics = [j / factorial(i) for i, j in enumerate(singular_ics)] y0 = {r:singular_ics} return HolonomicFunction(sol, x, x0, y0) y0 = _find_conditions(func, x, x0, lenics) while not y0: x0 += 1 y0 = _find_conditions(func, x, x0, lenics) return HolonomicFunction(sol, x, x0, y0) def _convert_meijerint(func, x, initcond=True, domain=QQ): args = meijerint._rewrite1(func, x) if args: fac, po, g, _ = args else: return None # lists for sum of meijerg functions fac_list = [fac * i[0] for i in g] t = po.as_base_exp() s = t[1] if t[0] == x else S.Zero po_list = [s + i[1] for i in g] G_list = [i[2] for i in g] # finds meijerg representation of x**s * meijerg(a1 ... ap, b1 ... bq, z) def _shift(func, s): z = func.args[-1] if z.has(I): z = z.subs(exp_polar, exp) d = z.collect(x, evaluate=False) b = list(d)[0] a = d[b] t = b.as_base_exp() b = t[1] if t[0] == x else S.Zero r = s / b an = (i + r for i in func.args[0][0]) ap = (i + r for i in func.args[0][1]) bm = (i + r for i in func.args[1][0]) bq = (i + r for i in func.args[1][1]) return a**-r, meijerg((an, ap), (bm, bq), z) coeff, m = _shift(G_list[0], po_list[0]) sol = fac_list[0] * coeff * from_meijerg(m, initcond=initcond, domain=domain) # add all the meijerg functions after converting to holonomic for i in range(1, len(G_list)): coeff, m = _shift(G_list[i], po_list[i]) sol += fac_list[i] * coeff * from_meijerg(m, initcond=initcond, domain=domain) return sol def _create_table(table, domain=QQ): """ Creates the look-up table. For a similar implementation see meijerint._create_lookup_table. """ def add(formula, annihilator, arg, x0=0, y0=[]): """ Adds a formula in the dictionary """ table.setdefault(_mytype(formula, x_1), []).append((formula, HolonomicFunction(annihilator, arg, x0, y0))) R = domain.old_poly_ring(x_1) _, Dx = DifferentialOperators(R, 'Dx') from sympy import (sin, cos, exp, log, erf, sqrt, pi, sinh, cosh, sinc, erfc, Si, Ci, Shi, erfi) # add some basic functions add(sin(x_1), Dx**2 + 1, x_1, 0, [0, 1]) add(cos(x_1), Dx**2 + 1, x_1, 0, [1, 0]) add(exp(x_1), Dx - 1, x_1, 0, 1) add(log(x_1), Dx + x_1*Dx**2, x_1, 1, [0, 1]) add(erf(x_1), 2*x_1*Dx + Dx**2, x_1, 0, [0, 2/sqrt(pi)]) add(erfc(x_1), 2*x_1*Dx + Dx**2, x_1, 0, [1, -2/sqrt(pi)]) add(erfi(x_1), -2*x_1*Dx + Dx**2, x_1, 0, [0, 2/sqrt(pi)]) add(sinh(x_1), Dx**2 - 1, x_1, 0, [0, 1]) add(cosh(x_1), Dx**2 - 1, x_1, 0, [1, 0]) add(sinc(x_1), x_1 + 2*Dx + x_1*Dx**2, x_1) add(Si(x_1), x_1*Dx + 2*Dx**2 + x_1*Dx**3, x_1) add(Ci(x_1), x_1*Dx + 2*Dx**2 + x_1*Dx**3, x_1) add(Shi(x_1), -x_1*Dx + 2*Dx**2 + x_1*Dx**3, x_1) def _find_conditions(func, x, x0, order): y0 = [] for i in range(order): val = func.subs(x, x0) if isinstance(val, NaN): val = limit(func, x, x0) if val.is_finite is False or isinstance(val, NaN): return None y0.append(val) func = func.diff(x) return y0 sympy-sympy-1.9/sympy/holonomic/holonomicerrors.py000066400000000000000000000022511412543434000226710ustar00rootroot00000000000000""" Common Exceptions for `holonomic` module. """ class BaseHolonomicError(Exception): def new(self, *args): raise NotImplementedError("abstract base class") class NotPowerSeriesError(BaseHolonomicError): def __init__(self, holonomic, x0): self.holonomic = holonomic self.x0 = x0 def __str__(self): s = 'A Power Series does not exists for ' s += str(self.holonomic) s += ' about %s.' %self.x0 return s class NotHolonomicError(BaseHolonomicError): def __init__(self, m): self.m = m def __str__(self): return self.m class SingularityError(BaseHolonomicError): def __init__(self, holonomic, x0): self.holonomic = holonomic self.x0 = x0 def __str__(self): s = str(self.holonomic) s += ' has a singularity at %s.' %self.x0 return s class NotHyperSeriesError(BaseHolonomicError): def __init__(self, holonomic, x0): self.holonomic = holonomic self.x0 = x0 def __str__(self): s = 'Power series expansion of ' s += str(self.holonomic) s += ' about %s is not hypergeometric' %self.x0 return s sympy-sympy-1.9/sympy/holonomic/numerical.py000066400000000000000000000052521412543434000214300ustar00rootroot00000000000000"""Numerical Methods for Holonomic Functions""" from sympy.core.sympify import sympify from sympy.holonomic.holonomic import DMFsubs from mpmath import mp def _evalf(func, points, derivatives=False, method='RK4'): """ Numerical methods for numerical integration along a given set of points in the complex plane. """ ann = func.annihilator a = ann.order R = ann.parent.base K = R.get_field() if method == 'Euler': meth = _euler else: meth = _rk4 dmf = [] for j in ann.listofpoly: dmf.append(K.new(j.rep)) red = [-dmf[i] / dmf[a] for i in range(a)] y0 = func.y0 if len(y0) < a: raise TypeError("Not Enough Initial Conditions") x0 = func.x0 sol = [meth(red, x0, points[0], y0, a)] for i, j in enumerate(points[1:]): sol.append(meth(red, points[i], j, sol[-1], a)) if not derivatives: return [sympify(i[0]) for i in sol] else: return sympify(sol) def _euler(red, x0, x1, y0, a): """ Euler's method for numerical integration. From x0 to x1 with initial values given at x0 as vector y0. """ A = sympify(x0)._to_mpmath(mp.prec) B = sympify(x1)._to_mpmath(mp.prec) y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0] h = B - A f_0 = y_0[1:] f_0_n = 0 for i in range(a): f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i] f_0.append(f_0_n) sol = [] for i in range(a): sol.append(y_0[i] + h * f_0[i]) return sol def _rk4(red, x0, x1, y0, a): """ Runge-Kutta 4th order numerical method. """ A = sympify(x0)._to_mpmath(mp.prec) B = sympify(x1)._to_mpmath(mp.prec) y_0 = [sympify(i)._to_mpmath(mp.prec) for i in y0] h = B - A f_0_n = 0 f_1_n = 0 f_2_n = 0 f_3_n = 0 f_0 = y_0[1:] for i in range(a): f_0_n += sympify(DMFsubs(red[i], A, mpm=True))._to_mpmath(mp.prec) * y_0[i] f_0.append(f_0_n) f_1 = [y_0[i] + f_0[i]*h/2 for i in range(1, a)] for i in range(a): f_1_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_0[i]*h/2) f_1.append(f_1_n) f_2 = [y_0[i] + f_1[i]*h/2 for i in range(1, a)] for i in range(a): f_2_n += sympify(DMFsubs(red[i], A + h/2, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_1[i]*h/2) f_2.append(f_2_n) f_3 = [y_0[i] + f_2[i]*h for i in range(1, a)] for i in range(a): f_3_n += sympify(DMFsubs(red[i], A + h, mpm=True))._to_mpmath(mp.prec) * (y_0[i] + f_2[i]*h) f_3.append(f_3_n) sol = [] for i in range(a): sol.append(y_0[i] + h * (f_0[i]+2*f_1[i]+2*f_2[i]+f_3[i])/6) return sol sympy-sympy-1.9/sympy/holonomic/recurrence.py000066400000000000000000000253471412543434000216150ustar00rootroot00000000000000"""Recurrence Operators""" from sympy import symbols, Symbol, S from sympy.printing import sstr from sympy.core.sympify import sympify def RecurrenceOperators(base, generator): """ Returns an Algebra of Recurrence Operators and the operator for shifting i.e. the `Sn` operator. The first argument needs to be the base polynomial ring for the algebra and the second argument must be a generator which can be either a noncommutative Symbol or a string. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy import symbols >>> from sympy.holonomic.recurrence import RecurrenceOperators >>> n = symbols('n', integer=True) >>> R, Sn = RecurrenceOperators(ZZ.old_poly_ring(n), 'Sn') """ ring = RecurrenceOperatorAlgebra(base, generator) return (ring, ring.shift_operator) class RecurrenceOperatorAlgebra: """ A Recurrence Operator Algebra is a set of noncommutative polynomials in intermediate `Sn` and coefficients in a base ring A. It follows the commutation rule: Sn * a(n) = a(n + 1) * Sn This class represents a Recurrence Operator Algebra and serves as the parent ring for Recurrence Operators. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy import symbols >>> from sympy.holonomic.recurrence import RecurrenceOperators >>> n = symbols('n', integer=True) >>> R, Sn = RecurrenceOperators(ZZ.old_poly_ring(n), 'Sn') >>> R Univariate Recurrence Operator Algebra in intermediate Sn over the base ring ZZ[n] See Also ======== RecurrenceOperator """ def __init__(self, base, generator): # the base ring for the algebra self.base = base # the operator representing shift i.e. `Sn` self.shift_operator = RecurrenceOperator( [base.zero, base.one], self) if generator is None: self.gen_symbol = symbols('Sn', commutative=False) else: if isinstance(generator, str): self.gen_symbol = symbols(generator, commutative=False) elif isinstance(generator, Symbol): self.gen_symbol = generator def __str__(self): string = 'Univariate Recurrence Operator Algebra in intermediate '\ + sstr(self.gen_symbol) + ' over the base ring ' + \ (self.base).__str__() return string __repr__ = __str__ def __eq__(self, other): if self.base == other.base and self.gen_symbol == other.gen_symbol: return True else: return False def _add_lists(list1, list2): if len(list1) <= len(list2): sol = [a + b for a, b in zip(list1, list2)] + list2[len(list1):] else: sol = [a + b for a, b in zip(list1, list2)] + list1[len(list2):] return sol class RecurrenceOperator: """ The Recurrence Operators are defined by a list of polynomials in the base ring and the parent ring of the Operator. Explanation =========== Takes a list of polynomials for each power of Sn and the parent ring which must be an instance of RecurrenceOperatorAlgebra. A Recurrence Operator can be created easily using the operator `Sn`. See examples below. Examples ======== >>> from sympy.holonomic.recurrence import RecurrenceOperator, RecurrenceOperators >>> from sympy.polys.domains import ZZ >>> from sympy import symbols >>> n = symbols('n', integer=True) >>> R, Sn = RecurrenceOperators(ZZ.old_poly_ring(n),'Sn') >>> RecurrenceOperator([0, 1, n**2], R) (1)Sn + (n**2)Sn**2 >>> Sn*n (n + 1)Sn >>> n*Sn*n + 1 - Sn**2*n (1) + (n**2 + n)Sn + (-n - 2)Sn**2 See Also ======== DifferentialOperatorAlgebra """ _op_priority = 20 def __init__(self, list_of_poly, parent): # the parent ring for this operator # must be an RecurrenceOperatorAlgebra object self.parent = parent # sequence of polynomials in n for each power of Sn # represents the operator # convert the expressions into ring elements using from_sympy if isinstance(list_of_poly, list): for i, j in enumerate(list_of_poly): if isinstance(j, int): list_of_poly[i] = self.parent.base.from_sympy(S(j)) elif not isinstance(j, self.parent.base.dtype): list_of_poly[i] = self.parent.base.from_sympy(j) self.listofpoly = list_of_poly self.order = len(self.listofpoly) - 1 def __mul__(self, other): """ Multiplies two Operators and returns another RecurrenceOperator instance using the commutation rule Sn * a(n) = a(n + 1) * Sn """ listofself = self.listofpoly base = self.parent.base if not isinstance(other, RecurrenceOperator): if not isinstance(other, self.parent.base.dtype): listofother = [self.parent.base.from_sympy(sympify(other))] else: listofother = [other] else: listofother = other.listofpoly # multiply a polynomial `b` with a list of polynomials def _mul_dmp_diffop(b, listofother): if isinstance(listofother, list): sol = [] for i in listofother: sol.append(i * b) return sol else: return [b * listofother] sol = _mul_dmp_diffop(listofself[0], listofother) # compute Sn^i * b def _mul_Sni_b(b): sol = [base.zero] if isinstance(b, list): for i in b: j = base.to_sympy(i).subs(base.gens[0], base.gens[0] + S.One) sol.append(base.from_sympy(j)) else: j = b.subs(base.gens[0], base.gens[0] + S.One) sol.append(base.from_sympy(j)) return sol for i in range(1, len(listofself)): # find Sn^i * b in ith iteration listofother = _mul_Sni_b(listofother) # solution = solution + listofself[i] * (Sn^i * b) sol = _add_lists(sol, _mul_dmp_diffop(listofself[i], listofother)) return RecurrenceOperator(sol, self.parent) def __rmul__(self, other): if not isinstance(other, RecurrenceOperator): if isinstance(other, int): other = S(other) if not isinstance(other, self.parent.base.dtype): other = (self.parent.base).from_sympy(other) sol = [] for j in self.listofpoly: sol.append(other * j) return RecurrenceOperator(sol, self.parent) def __add__(self, other): if isinstance(other, RecurrenceOperator): sol = _add_lists(self.listofpoly, other.listofpoly) return RecurrenceOperator(sol, self.parent) else: if isinstance(other, int): other = S(other) list_self = self.listofpoly if not isinstance(other, self.parent.base.dtype): list_other = [((self.parent).base).from_sympy(other)] else: list_other = [other] sol = [] sol.append(list_self[0] + list_other[0]) sol += list_self[1:] return RecurrenceOperator(sol, self.parent) __radd__ = __add__ def __sub__(self, other): return self + (-1) * other def __rsub__(self, other): return (-1) * self + other def __pow__(self, n): if n == 1: return self if n == 0: return RecurrenceOperator([self.parent.base.one], self.parent) # if self is `Sn` if self.listofpoly == self.parent.shift_operator.listofpoly: sol = [] for i in range(0, n): sol.append(self.parent.base.zero) sol.append(self.parent.base.one) return RecurrenceOperator(sol, self.parent) else: if n % 2 == 1: powreduce = self**(n - 1) return powreduce * self elif n % 2 == 0: powreduce = self**(n / 2) return powreduce * powreduce def __str__(self): listofpoly = self.listofpoly print_str = '' for i, j in enumerate(listofpoly): if j == self.parent.base.zero: continue if i == 0: print_str += '(' + sstr(j) + ')' continue if print_str: print_str += ' + ' if i == 1: print_str += '(' + sstr(j) + ')Sn' continue print_str += '(' + sstr(j) + ')' + 'Sn**' + sstr(i) return print_str __repr__ = __str__ def __eq__(self, other): if isinstance(other, RecurrenceOperator): if self.listofpoly == other.listofpoly and self.parent == other.parent: return True else: return False else: if self.listofpoly[0] == other: for i in self.listofpoly[1:]: if i is not self.parent.base.zero: return False return True else: return False class HolonomicSequence: """ A Holonomic Sequence is a type of sequence satisfying a linear homogeneous recurrence relation with Polynomial coefficients. Alternatively, A sequence is Holonomic if and only if its generating function is a Holonomic Function. """ def __init__(self, recurrence, u0=[]): self.recurrence = recurrence if not isinstance(u0, list): self.u0 = [u0] else: self.u0 = u0 if len(self.u0) == 0: self._have_init_cond = False else: self._have_init_cond = True self.n = recurrence.parent.base.gens[0] def __repr__(self): str_sol = 'HolonomicSequence(%s, %s)' % ((self.recurrence).__repr__(), sstr(self.n)) if not self._have_init_cond: return str_sol else: cond_str = '' seq_str = 0 for i in self.u0: cond_str += ', u(%s) = %s' % (sstr(seq_str), sstr(i)) seq_str += 1 sol = str_sol + cond_str return sol __str__ = __repr__ def __eq__(self, other): if self.recurrence == other.recurrence: if self.n == other.n: if self._have_init_cond and other._have_init_cond: if self.u0 == other.u0: return True else: return False else: return True else: return False else: return False sympy-sympy-1.9/sympy/holonomic/tests/000077500000000000000000000000001412543434000202355ustar00rootroot00000000000000sympy-sympy-1.9/sympy/holonomic/tests/__init__.py000066400000000000000000000000001412543434000223340ustar00rootroot00000000000000sympy-sympy-1.9/sympy/holonomic/tests/test_holonomic.py000066400000000000000000001023721412543434000236420ustar00rootroot00000000000000from sympy.holonomic import (DifferentialOperator, HolonomicFunction, DifferentialOperators, from_hyper, from_meijerg, expr_to_holonomic) from sympy.holonomic.recurrence import RecurrenceOperators, HolonomicSequence from sympy import (symbols, hyper, S, sqrt, pi, exp, erf, erfc, sstr, Symbol, O, I, meijerg, sin, cos, log, cosh, besselj, hyperexpand, Ci, EulerGamma, Si, asinh, gamma, beta, Rational) from sympy import ZZ, QQ, RR def test_DifferentialOperator(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') assert Dx == R.derivative_operator assert Dx == DifferentialOperator([R.base.zero, R.base.one], R) assert x * Dx + x**2 * Dx**2 == DifferentialOperator([0, x, x**2], R) assert (x**2 + 1) + Dx + x * \ Dx**5 == DifferentialOperator([x**2 + 1, 1, 0, 0, 0, x], R) assert (x * Dx + x**2 + 1 - Dx * (x**3 + x))**3 == (-48 * x**6) + \ (-57 * x**7) * Dx + (-15 * x**8) * Dx**2 + (-x**9) * Dx**3 p = (x * Dx**2 + (x**2 + 3) * Dx**5) * (Dx + x**2) q = (2 * x) + (4 * x**2) * Dx + (x**3) * Dx**2 + \ (20 * x**2 + x + 60) * Dx**3 + (10 * x**3 + 30 * x) * Dx**4 + \ (x**4 + 3 * x**2) * Dx**5 + (x**2 + 3) * Dx**6 assert p == q def test_HolonomicFunction_addition(): x = symbols('x') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx**2 * x, x) q = HolonomicFunction((2) * Dx + (x) * Dx**2, x) assert p == q p = HolonomicFunction(x * Dx + 1, x) q = HolonomicFunction(Dx + 1, x) r = HolonomicFunction((x - 2) + (x**2 - 2) * Dx + (x**2 - x) * Dx**2, x) assert p + q == r p = HolonomicFunction(x * Dx + Dx**2 * (x**2 + 2), x) q = HolonomicFunction(Dx - 3, x) r = HolonomicFunction((-54 * x**2 - 126 * x - 150) + (-135 * x**3 - 252 * x**2 - 270 * x + 140) * Dx +\ (-27 * x**4 - 24 * x**2 + 14 * x - 150) * Dx**2 + \ (9 * x**4 + 15 * x**3 + 38 * x**2 + 30 * x +40) * Dx**3, x) assert p + q == r p = HolonomicFunction(Dx**5 - 1, x) q = HolonomicFunction(x**3 + Dx, x) r = HolonomicFunction((-x**18 + 45*x**14 - 525*x**10 + 1575*x**6 - x**3 - 630*x**2) + \ (-x**15 + 30*x**11 - 195*x**7 + 210*x**3 - 1)*Dx + (x**18 - 45*x**14 + 525*x**10 - \ 1575*x**6 + x**3 + 630*x**2)*Dx**5 + (x**15 - 30*x**11 + 195*x**7 - 210*x**3 + \ 1)*Dx**6, x) assert p+q == r p = x**2 + 3*x + 8 q = x**3 - 7*x + 5 p = p*Dx - p.diff() q = q*Dx - q.diff() r = HolonomicFunction(p, x) + HolonomicFunction(q, x) s = HolonomicFunction((6*x**2 + 18*x + 14) + (-4*x**3 - 18*x**2 - 62*x + 10)*Dx +\ (x**4 + 6*x**3 + 31*x**2 - 10*x - 71)*Dx**2, x) assert r == s def test_HolonomicFunction_multiplication(): x = symbols('x') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx+x+x*Dx**2, x) q = HolonomicFunction(x*Dx+Dx*x+Dx**2, x) r = HolonomicFunction((8*x**6 + 4*x**4 + 6*x**2 + 3) + (24*x**5 - 4*x**3 + 24*x)*Dx + \ (8*x**6 + 20*x**4 + 12*x**2 + 2)*Dx**2 + (8*x**5 + 4*x**3 + 4*x)*Dx**3 + \ (2*x**4 + x**2)*Dx**4, x) assert p*q == r p = HolonomicFunction(Dx**2+1, x) q = HolonomicFunction(Dx-1, x) r = HolonomicFunction((2) + (-2)*Dx + (1)*Dx**2, x) assert p*q == r p = HolonomicFunction(Dx**2+1+x+Dx, x) q = HolonomicFunction((Dx*x-1)**2, x) r = HolonomicFunction((4*x**7 + 11*x**6 + 16*x**5 + 4*x**4 - 6*x**3 - 7*x**2 - 8*x - 2) + \ (8*x**6 + 26*x**5 + 24*x**4 - 3*x**3 - 11*x**2 - 6*x - 2)*Dx + \ (8*x**6 + 18*x**5 + 15*x**4 - 3*x**3 - 6*x**2 - 6*x - 2)*Dx**2 + (8*x**5 + \ 10*x**4 + 6*x**3 - 2*x**2 - 4*x)*Dx**3 + (4*x**5 + 3*x**4 - x**2)*Dx**4, x) assert p*q == r p = HolonomicFunction(x*Dx**2-1, x) q = HolonomicFunction(Dx*x-x, x) r = HolonomicFunction((x - 3) + (-2*x + 2)*Dx + (x)*Dx**2, x) assert p*q == r def test_addition_initial_condition(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx-1, x, 0, [3]) q = HolonomicFunction(Dx**2+1, x, 0, [1, 0]) r = HolonomicFunction(-1 + Dx - Dx**2 + Dx**3, x, 0, [4, 3, 2]) assert p + q == r p = HolonomicFunction(Dx - x + Dx**2, x, 0, [1, 2]) q = HolonomicFunction(Dx**2 + x, x, 0, [1, 0]) r = HolonomicFunction((-x**4 - x**3/4 - x**2 + Rational(1, 4)) + (x**3 + x**2/4 + x*Rational(3, 4) + 1)*Dx + \ (x*Rational(-3, 2) + Rational(7, 4))*Dx**2 + (x**2 - x*Rational(7, 4) + Rational(1, 4))*Dx**3 + (x**2 + x/4 + S.Half)*Dx**4, x, 0, [2, 2, -2, 2]) assert p + q == r p = HolonomicFunction(Dx**2 + 4*x*Dx + x**2, x, 0, [3, 4]) q = HolonomicFunction(Dx**2 + 1, x, 0, [1, 1]) r = HolonomicFunction((x**6 + 2*x**4 - 5*x**2 - 6) + (4*x**5 + 36*x**3 - 32*x)*Dx + \ (x**6 + 3*x**4 + 5*x**2 - 9)*Dx**2 + (4*x**5 + 36*x**3 - 32*x)*Dx**3 + (x**4 + \ 10*x**2 - 3)*Dx**4, x, 0, [4, 5, -1, -17]) assert p + q == r q = HolonomicFunction(Dx**3 + x, x, 2, [3, 0, 1]) p = HolonomicFunction(Dx - 1, x, 2, [1]) r = HolonomicFunction((-x**2 - x + 1) + (x**2 + x)*Dx + (-x - 2)*Dx**3 + \ (x + 1)*Dx**4, x, 2, [4, 1, 2, -5 ]) assert p + q == r p = expr_to_holonomic(sin(x)) q = expr_to_holonomic(1/x, x0=1) r = HolonomicFunction((x**2 + 6) + (x**3 + 2*x)*Dx + (x**2 + 6)*Dx**2 + (x**3 + 2*x)*Dx**3, \ x, 1, [sin(1) + 1, -1 + cos(1), -sin(1) + 2]) assert p + q == r C_1 = symbols('C_1') p = expr_to_holonomic(sqrt(x)) q = expr_to_holonomic(sqrt(x**2-x)) r = (p + q).to_expr().subs(C_1, -I/2).expand() assert r == I*sqrt(x)*sqrt(-x + 1) + sqrt(x) def test_multiplication_initial_condition(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx**2 + x*Dx - 1, x, 0, [3, 1]) q = HolonomicFunction(Dx**2 + 1, x, 0, [1, 1]) r = HolonomicFunction((x**4 + 14*x**2 + 60) + 4*x*Dx + (x**4 + 9*x**2 + 20)*Dx**2 + \ (2*x**3 + 18*x)*Dx**3 + (x**2 + 10)*Dx**4, x, 0, [3, 4, 2, 3]) assert p * q == r p = HolonomicFunction(Dx**2 + x, x, 0, [1, 0]) q = HolonomicFunction(Dx**3 - x**2, x, 0, [3, 3, 3]) r = HolonomicFunction((x**8 - 37*x**7/27 - 10*x**6/27 - 164*x**5/9 - 184*x**4/9 + \ 160*x**3/27 + 404*x**2/9 + 8*x + Rational(40, 3)) + (6*x**7 - 128*x**6/9 - 98*x**5/9 - 28*x**4/9 + \ 8*x**3/9 + 28*x**2 + x*Rational(40, 9) - 40)*Dx + (3*x**6 - 82*x**5/9 + 76*x**4/9 + 4*x**3/3 + \ 220*x**2/9 - x*Rational(80, 3))*Dx**2 + (-2*x**6 + 128*x**5/27 - 2*x**4/3 -80*x**2/9 + Rational(200, 9))*Dx**3 + \ (3*x**5 - 64*x**4/9 - 28*x**3/9 + 6*x**2 - x*Rational(20, 9) - Rational(20, 3))*Dx**4 + (-4*x**3 + 64*x**2/9 + \ x*Rational(8, 3))*Dx**5 + (x**4 - 64*x**3/27 - 4*x**2/3 + Rational(20, 9))*Dx**6, x, 0, [3, 3, 3, -3, -12, -24]) assert p * q == r p = HolonomicFunction(Dx - 1, x, 0, [2]) q = HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]) r = HolonomicFunction(2 -2*Dx + Dx**2, x, 0, [0, 2]) assert p * q == r q = HolonomicFunction(x*Dx**2 + 1 + 2*Dx, x, 0,[0, 1]) r = HolonomicFunction((x - 1) + (-2*x + 2)*Dx + x*Dx**2, x, 0, [0, 2]) assert p * q == r p = HolonomicFunction(Dx**2 - 1, x, 0, [1, 3]) q = HolonomicFunction(Dx**3 + 1, x, 0, [1, 2, 1]) r = HolonomicFunction(6*Dx + 3*Dx**2 + 2*Dx**3 - 3*Dx**4 + Dx**6, x, 0, [1, 5, 14, 17, 17, 2]) assert p * q == r p = expr_to_holonomic(sin(x)) q = expr_to_holonomic(1/x, x0=1) r = HolonomicFunction(x + 2*Dx + x*Dx**2, x, 1, [sin(1), -sin(1) + cos(1)]) assert p * q == r p = expr_to_holonomic(sqrt(x)) q = expr_to_holonomic(sqrt(x**2-x)) r = (p * q).to_expr() assert r == I*x*sqrt(-x + 1) def test_HolonomicFunction_composition(): x = symbols('x') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx-1, x).composition(x**2+x) r = HolonomicFunction((-2*x - 1) + Dx, x) assert p == r p = HolonomicFunction(Dx**2+1, x).composition(x**5+x**2+1) r = HolonomicFunction((125*x**12 + 150*x**9 + 60*x**6 + 8*x**3) + (-20*x**3 - 2)*Dx + \ (5*x**4 + 2*x)*Dx**2, x) assert p == r p = HolonomicFunction(Dx**2*x+x, x).composition(2*x**3+x**2+1) r = HolonomicFunction((216*x**9 + 324*x**8 + 180*x**7 + 152*x**6 + 112*x**5 + \ 36*x**4 + 4*x**3) + (24*x**4 + 16*x**3 + 3*x**2 - 6*x - 1)*Dx + (6*x**5 + 5*x**4 + \ x**3 + 3*x**2 + x)*Dx**2, x) assert p == r p = HolonomicFunction(Dx**2+1, x).composition(1-x**2) r = HolonomicFunction((4*x**3) - Dx + x*Dx**2, x) assert p == r p = HolonomicFunction(Dx**2+1, x).composition(x - 2/(x**2 + 1)) r = HolonomicFunction((x**12 + 6*x**10 + 12*x**9 + 15*x**8 + 48*x**7 + 68*x**6 + \ 72*x**5 + 111*x**4 + 112*x**3 + 54*x**2 + 12*x + 1) + (12*x**8 + 32*x**6 + \ 24*x**4 - 4)*Dx + (x**12 + 6*x**10 + 4*x**9 + 15*x**8 + 16*x**7 + 20*x**6 + 24*x**5+ \ 15*x**4 + 16*x**3 + 6*x**2 + 4*x + 1)*Dx**2, x) assert p == r def test_from_hyper(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') p = hyper([1, 1], [Rational(3, 2)], x**2/4) q = HolonomicFunction((4*x) + (5*x**2 - 8)*Dx + (x**3 - 4*x)*Dx**2, x, 1, [2*sqrt(3)*pi/9, -4*sqrt(3)*pi/27 + Rational(4, 3)]) r = from_hyper(p) assert r == q p = from_hyper(hyper([1], [Rational(3, 2)], x**2/4)) q = HolonomicFunction(-x + (-x**2/2 + 2)*Dx + x*Dx**2, x) # x0 = 1 y0 = '[sqrt(pi)*exp(1/4)*erf(1/2), -sqrt(pi)*exp(1/4)*erf(1/2)/2 + 1]' assert sstr(p.y0) == y0 assert q.annihilator == p.annihilator def test_from_meijerg(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') p = from_meijerg(meijerg(([], [Rational(3, 2)]), ([S.Half], [S.Half, 1]), x)) q = HolonomicFunction(x/2 - Rational(1, 4) + (-x**2 + x/4)*Dx + x**2*Dx**2 + x**3*Dx**3, x, 1, \ [1/sqrt(pi), 1/(2*sqrt(pi)), -1/(4*sqrt(pi))]) assert p == q p = from_meijerg(meijerg(([], []), ([0], []), x)) q = HolonomicFunction(1 + Dx, x, 0, [1]) assert p == q p = from_meijerg(meijerg(([1], []), ([S.Half], [0]), x)) q = HolonomicFunction((x + S.Half)*Dx + x*Dx**2, x, 1, [sqrt(pi)*erf(1), exp(-1)]) assert p == q p = from_meijerg(meijerg(([0], [1]), ([0], []), 2*x**2)) q = HolonomicFunction((3*x**2 - 1)*Dx + x**3*Dx**2, x, 1, [-exp(Rational(-1, 2)) + 1, -exp(Rational(-1, 2))]) assert p == q def test_to_Sequence(): x = symbols('x') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') n = symbols('n', integer=True) _, Sn = RecurrenceOperators(ZZ.old_poly_ring(n), 'Sn') p = HolonomicFunction(x**2*Dx**4 + x + Dx, x).to_sequence() q = [(HolonomicSequence(1 + (n + 2)*Sn**2 + (n**4 + 6*n**3 + 11*n**2 + 6*n)*Sn**3), 0, 1)] assert p == q p = HolonomicFunction(x**2*Dx**4 + x**3 + Dx**2, x).to_sequence() q = [(HolonomicSequence(1 + (n**4 + 14*n**3 + 72*n**2 + 163*n + 140)*Sn**5), 0, 0)] assert p == q p = HolonomicFunction(x**3*Dx**4 + 1 + Dx**2, x).to_sequence() q = [(HolonomicSequence(1 + (n**4 - 2*n**3 - n**2 + 2*n)*Sn + (n**2 + 3*n + 2)*Sn**2), 0, 0)] assert p == q p = HolonomicFunction(3*x**3*Dx**4 + 2*x*Dx + x*Dx**3, x).to_sequence() q = [(HolonomicSequence(2*n + (3*n**4 - 6*n**3 - 3*n**2 + 6*n)*Sn + (n**3 + 3*n**2 + 2*n)*Sn**2), 0, 1)] assert p == q def test_to_Sequence_Initial_Coniditons(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') n = symbols('n', integer=True) _, Sn = RecurrenceOperators(QQ.old_poly_ring(n), 'Sn') p = HolonomicFunction(Dx - 1, x, 0, [1]).to_sequence() q = [(HolonomicSequence(-1 + (n + 1)*Sn, 1), 0)] assert p == q p = HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]).to_sequence() q = [(HolonomicSequence(1 + (n**2 + 3*n + 2)*Sn**2, [0, 1]), 0)] assert p == q p = HolonomicFunction(Dx**2 + 1 + x**3*Dx, x, 0, [2, 3]).to_sequence() q = [(HolonomicSequence(n + Sn**2 + (n**2 + 7*n + 12)*Sn**4, [2, 3, -1, Rational(-1, 2), Rational(1, 12)]), 1)] assert p == q p = HolonomicFunction(x**3*Dx**5 + 1 + Dx, x).to_sequence() q = [(HolonomicSequence(1 + (n + 1)*Sn + (n**5 - 5*n**3 + 4*n)*Sn**2), 0, 3)] assert p == q C_0, C_1, C_2, C_3 = symbols('C_0, C_1, C_2, C_3') p = expr_to_holonomic(log(1+x**2)) q = [(HolonomicSequence(n**2 + (n**2 + 2*n)*Sn**2, [0, 0, C_2]), 0, 1)] assert p.to_sequence() == q p = p.diff() q = [(HolonomicSequence((n + 2) + (n + 2)*Sn**2, [C_0, 0]), 1, 0)] assert p.to_sequence() == q p = expr_to_holonomic(erf(x) + x).to_sequence() q = [(HolonomicSequence((2*n**2 - 2*n) + (n**3 + 2*n**2 - n - 2)*Sn**2, [0, 1 + 2/sqrt(pi), 0, C_3]), 0, 2)] assert p == q def test_series(): x = symbols('x') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx**2 + 2*x*Dx, x, 0, [0, 1]).series(n=10) q = x - x**3/3 + x**5/10 - x**7/42 + x**9/216 + O(x**10) assert p == q p = HolonomicFunction(Dx - 1, x).composition(x**2, 0, [1]) # e^(x**2) q = HolonomicFunction(Dx**2 + 1, x, 0, [1, 0]) # cos(x) r = (p * q).series(n=10) # expansion of cos(x) * exp(x**2) s = 1 + x**2/2 + x**4/24 - 31*x**6/720 - 179*x**8/8064 + O(x**10) assert r == s t = HolonomicFunction((1 + x)*Dx**2 + Dx, x, 0, [0, 1]) # log(1 + x) r = (p * t + q).series(n=10) s = 1 + x - x**2 + 4*x**3/3 - 17*x**4/24 + 31*x**5/30 - 481*x**6/720 +\ 71*x**7/105 - 20159*x**8/40320 + 379*x**9/840 + O(x**10) assert r == s p = HolonomicFunction((6+6*x-3*x**2) - (10*x-3*x**2-3*x**3)*Dx + \ (4-6*x**3+2*x**4)*Dx**2, x, 0, [0, 1]).series(n=7) q = x + x**3/6 - 3*x**4/16 + x**5/20 - 23*x**6/960 + O(x**7) assert p == q p = HolonomicFunction((6+6*x-3*x**2) - (10*x-3*x**2-3*x**3)*Dx + \ (4-6*x**3+2*x**4)*Dx**2, x, 0, [1, 0]).series(n=7) q = 1 - 3*x**2/4 - x**3/4 - 5*x**4/32 - 3*x**5/40 - 17*x**6/384 + O(x**7) assert p == q p = expr_to_holonomic(erf(x) + x).series(n=10) C_3 = symbols('C_3') q = (erf(x) + x).series(n=10) assert p.subs(C_3, -2/(3*sqrt(pi))) == q assert expr_to_holonomic(sqrt(x**3 + x)).series(n=10) == sqrt(x**3 + x).series(n=10) assert expr_to_holonomic((2*x - 3*x**2)**Rational(1, 3)).series() == ((2*x - 3*x**2)**Rational(1, 3)).series() assert expr_to_holonomic(sqrt(x**2-x)).series() == (sqrt(x**2-x)).series() assert expr_to_holonomic(cos(x)**2/x**2, y0={-2: [1, 0, -1]}).series(n=10) == (cos(x)**2/x**2).series(n=10) assert expr_to_holonomic(cos(x)**2/x**2, x0=1).series(n=10).together() == (cos(x)**2/x**2).series(n=10, x0=1).together() assert expr_to_holonomic(cos(x-1)**2/(x-1)**2, x0=1, y0={-2: [1, 0, -1]}).series(n=10) \ == (cos(x-1)**2/(x-1)**2).series(x0=1, n=10) def test_evalf_euler(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') # log(1+x) p = HolonomicFunction((1 + x)*Dx**2 + Dx, x, 0, [0, 1]) # path taken is a straight line from 0 to 1, on the real axis r = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1] s = '0.699525841805253' # approx. equal to log(2) i.e. 0.693147180559945 assert sstr(p.evalf(r, method='Euler')[-1]) == s # path taken is a traingle 0-->1+i-->2 r = [0.1 + 0.1*I] for i in range(9): r.append(r[-1]+0.1+0.1*I) for i in range(10): r.append(r[-1]+0.1-0.1*I) # close to the exact solution 1.09861228866811 # imaginary part also close to zero s = '1.07530466271334 - 0.0251200594793912*I' assert sstr(p.evalf(r, method='Euler')[-1]) == s # sin(x) p = HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]) s = '0.905546532085401 - 6.93889390390723e-18*I' assert sstr(p.evalf(r, method='Euler')[-1]) == s # computing sin(pi/2) using this method # using a linear path from 0 to pi/2 r = [0.1] for i in range(14): r.append(r[-1] + 0.1) r.append(pi/2) s = '1.08016557252834' # close to 1.0 (exact solution) assert sstr(p.evalf(r, method='Euler')[-1]) == s # trying different path, a rectangle (0-->i-->pi/2 + i-->pi/2) # computing the same value sin(pi/2) using different path r = [0.1*I] for i in range(9): r.append(r[-1]+0.1*I) for i in range(15): r.append(r[-1]+0.1) r.append(pi/2+I) for i in range(10): r.append(r[-1]-0.1*I) # close to 1.0 s = '0.976882381836257 - 1.65557671738537e-16*I' assert sstr(p.evalf(r, method='Euler')[-1]) == s # cos(x) p = HolonomicFunction(Dx**2 + 1, x, 0, [1, 0]) # compute cos(pi) along 0-->pi r = [0.05] for i in range(61): r.append(r[-1]+0.05) r.append(pi) # close to -1 (exact answer) s = '-1.08140824719196' assert sstr(p.evalf(r, method='Euler')[-1]) == s # a rectangular path (0 -> i -> 2+i -> 2) r = [0.1*I] for i in range(9): r.append(r[-1]+0.1*I) for i in range(20): r.append(r[-1]+0.1) for i in range(10): r.append(r[-1]-0.1*I) p = HolonomicFunction(Dx**2 + 1, x, 0, [1,1]).evalf(r, method='Euler') s = '0.501421652861245 - 3.88578058618805e-16*I' assert sstr(p[-1]) == s def test_evalf_rk4(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') # log(1+x) p = HolonomicFunction((1 + x)*Dx**2 + Dx, x, 0, [0, 1]) # path taken is a straight line from 0 to 1, on the real axis r = [0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9, 1] s = '0.693146363174626' # approx. equal to log(2) i.e. 0.693147180559945 assert sstr(p.evalf(r)[-1]) == s # path taken is a traingle 0-->1+i-->2 r = [0.1 + 0.1*I] for i in range(9): r.append(r[-1]+0.1+0.1*I) for i in range(10): r.append(r[-1]+0.1-0.1*I) # close to the exact solution 1.09861228866811 # imaginary part also close to zero s = '1.098616 + 1.36083e-7*I' assert sstr(p.evalf(r)[-1].n(7)) == s # sin(x) p = HolonomicFunction(Dx**2 + 1, x, 0, [0, 1]) s = '0.90929463522785 + 1.52655665885959e-16*I' assert sstr(p.evalf(r)[-1]) == s # computing sin(pi/2) using this method # using a linear path from 0 to pi/2 r = [0.1] for i in range(14): r.append(r[-1] + 0.1) r.append(pi/2) s = '0.999999895088917' # close to 1.0 (exact solution) assert sstr(p.evalf(r)[-1]) == s # trying different path, a rectangle (0-->i-->pi/2 + i-->pi/2) # computing the same value sin(pi/2) using different path r = [0.1*I] for i in range(9): r.append(r[-1]+0.1*I) for i in range(15): r.append(r[-1]+0.1) r.append(pi/2+I) for i in range(10): r.append(r[-1]-0.1*I) # close to 1.0 s = '1.00000003415141 + 6.11940487991086e-16*I' assert sstr(p.evalf(r)[-1]) == s # cos(x) p = HolonomicFunction(Dx**2 + 1, x, 0, [1, 0]) # compute cos(pi) along 0-->pi r = [0.05] for i in range(61): r.append(r[-1]+0.05) r.append(pi) # close to -1 (exact answer) s = '-0.999999993238714' assert sstr(p.evalf(r)[-1]) == s # a rectangular path (0 -> i -> 2+i -> 2) r = [0.1*I] for i in range(9): r.append(r[-1]+0.1*I) for i in range(20): r.append(r[-1]+0.1) for i in range(10): r.append(r[-1]-0.1*I) p = HolonomicFunction(Dx**2 + 1, x, 0, [1,1]).evalf(r) s = '0.493152791638442 - 1.41553435639707e-15*I' assert sstr(p[-1]) == s def test_expr_to_holonomic(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') p = expr_to_holonomic((sin(x)/x)**2) q = HolonomicFunction(8*x + (4*x**2 + 6)*Dx + 6*x*Dx**2 + x**2*Dx**3, x, 0, \ [1, 0, Rational(-2, 3)]) assert p == q p = expr_to_holonomic(1/(1+x**2)**2) q = HolonomicFunction(4*x + (x**2 + 1)*Dx, x, 0, [1]) assert p == q p = expr_to_holonomic(exp(x)*sin(x)+x*log(1+x)) q = HolonomicFunction((2*x**3 + 10*x**2 + 20*x + 18) + (-2*x**4 - 10*x**3 - 20*x**2 \ - 18*x)*Dx + (2*x**5 + 6*x**4 + 7*x**3 + 8*x**2 + 10*x - 4)*Dx**2 + \ (-2*x**5 - 5*x**4 - 2*x**3 + 2*x**2 - x + 4)*Dx**3 + (x**5 + 2*x**4 - x**3 - \ 7*x**2/2 + x + Rational(5, 2))*Dx**4, x, 0, [0, 1, 4, -1]) assert p == q p = expr_to_holonomic(x*exp(x)+cos(x)+1) q = HolonomicFunction((-x - 3)*Dx + (x + 2)*Dx**2 + (-x - 3)*Dx**3 + (x + 2)*Dx**4, x, \ 0, [2, 1, 1, 3]) assert p == q assert (x*exp(x)+cos(x)+1).series(n=10) == p.series(n=10) p = expr_to_holonomic(log(1 + x)**2 + 1) q = HolonomicFunction(Dx + (3*x + 3)*Dx**2 + (x**2 + 2*x + 1)*Dx**3, x, 0, [1, 0, 2]) assert p == q p = expr_to_holonomic(erf(x)**2 + x) q = HolonomicFunction((8*x**4 - 2*x**2 + 2)*Dx**2 + (6*x**3 - x/2)*Dx**3 + \ (x**2+ Rational(1, 4))*Dx**4, x, 0, [0, 1, 8/pi, 0]) assert p == q p = expr_to_holonomic(cosh(x)*x) q = HolonomicFunction((-x**2 + 2) -2*x*Dx + x**2*Dx**2, x, 0, [0, 1]) assert p == q p = expr_to_holonomic(besselj(2, x)) q = HolonomicFunction((x**2 - 4) + x*Dx + x**2*Dx**2, x, 0, [0, 0]) assert p == q p = expr_to_holonomic(besselj(0, x) + exp(x)) q = HolonomicFunction((-x**2 - x/2 + S.Half) + (x**2 - x/2 - Rational(3, 2))*Dx + (-x**2 + x/2 + 1)*Dx**2 +\ (x**2 + x/2)*Dx**3, x, 0, [2, 1, S.Half]) assert p == q p = expr_to_holonomic(sin(x)**2/x) q = HolonomicFunction(4 + 4*x*Dx + 3*Dx**2 + x*Dx**3, x, 0, [0, 1, 0]) assert p == q p = expr_to_holonomic(sin(x)**2/x, x0=2) q = HolonomicFunction((4) + (4*x)*Dx + (3)*Dx**2 + (x)*Dx**3, x, 2, [sin(2)**2/2, sin(2)*cos(2) - sin(2)**2/4, -3*sin(2)**2/4 + cos(2)**2 - sin(2)*cos(2)]) assert p == q p = expr_to_holonomic(log(x)/2 - Ci(2*x)/2 + Ci(2)/2) q = HolonomicFunction(4*Dx + 4*x*Dx**2 + 3*Dx**3 + x*Dx**4, x, 0, \ [-log(2)/2 - EulerGamma/2 + Ci(2)/2, 0, 1, 0]) assert p == q p = p.to_expr() q = log(x)/2 - Ci(2*x)/2 + Ci(2)/2 assert p == q p = expr_to_holonomic(x**S.Half, x0=1) q = HolonomicFunction(x*Dx - S.Half, x, 1, [1]) assert p == q p = expr_to_holonomic(sqrt(1 + x**2)) q = HolonomicFunction((-x) + (x**2 + 1)*Dx, x, 0, [1]) assert p == q assert (expr_to_holonomic(sqrt(x) + sqrt(2*x)).to_expr()-\ (sqrt(x) + sqrt(2*x))).simplify() == 0 assert expr_to_holonomic(3*x+2*sqrt(x)).to_expr() == 3*x+2*sqrt(x) p = expr_to_holonomic((x**4+x**3+5*x**2+3*x+2)/x**2, lenics=3) q = HolonomicFunction((-2*x**4 - x**3 + 3*x + 4) + (x**5 + x**4 + 5*x**3 + 3*x**2 + \ 2*x)*Dx, x, 0, {-2: [2, 3, 5]}) assert p == q p = expr_to_holonomic(1/(x-1)**2, lenics=3, x0=1) q = HolonomicFunction((2) + (x - 1)*Dx, x, 1, {-2: [1, 0, 0]}) assert p == q a = symbols("a") p = expr_to_holonomic(sqrt(a*x), x=x) assert p.to_expr() == sqrt(a)*sqrt(x) def test_to_hyper(): x = symbols('x') R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx - 2, x, 0, [3]).to_hyper() q = 3 * hyper([], [], 2*x) assert p == q p = hyperexpand(HolonomicFunction((1 + x) * Dx - 3, x, 0, [2]).to_hyper()).expand() q = 2*x**3 + 6*x**2 + 6*x + 2 assert p == q p = HolonomicFunction((1 + x)*Dx**2 + Dx, x, 0, [0, 1]).to_hyper() q = -x**2*hyper((2, 2, 1), (3, 2), -x)/2 + x assert p == q p = HolonomicFunction(2*x*Dx + Dx**2, x, 0, [0, 2/sqrt(pi)]).to_hyper() q = 2*x*hyper((S.Half,), (Rational(3, 2),), -x**2)/sqrt(pi) assert p == q p = hyperexpand(HolonomicFunction(2*x*Dx + Dx**2, x, 0, [1, -2/sqrt(pi)]).to_hyper()) q = erfc(x) assert p.rewrite(erfc) == q p = hyperexpand(HolonomicFunction((x**2 - 1) + x*Dx + x**2*Dx**2, x, 0, [0, S.Half]).to_hyper()) q = besselj(1, x) assert p == q p = hyperexpand(HolonomicFunction(x*Dx**2 + Dx + x, x, 0, [1, 0]).to_hyper()) q = besselj(0, x) assert p == q def test_to_expr(): x = symbols('x') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') p = HolonomicFunction(Dx - 1, x, 0, [1]).to_expr() q = exp(x) assert p == q p = HolonomicFunction(Dx**2 + 1, x, 0, [1, 0]).to_expr() q = cos(x) assert p == q p = HolonomicFunction(Dx**2 - 1, x, 0, [1, 0]).to_expr() q = cosh(x) assert p == q p = HolonomicFunction(2 + (4*x - 1)*Dx + \ (x**2 - x)*Dx**2, x, 0, [1, 2]).to_expr().expand() q = 1/(x**2 - 2*x + 1) assert p == q p = expr_to_holonomic(sin(x)**2/x).integrate((x, 0, x)).to_expr() q = (sin(x)**2/x).integrate((x, 0, x)) assert p == q C_0, C_1, C_2, C_3 = symbols('C_0, C_1, C_2, C_3') p = expr_to_holonomic(log(1+x**2)).to_expr() q = C_2*log(x**2 + 1) assert p == q p = expr_to_holonomic(log(1+x**2)).diff().to_expr() q = C_0*x/(x**2 + 1) assert p == q p = expr_to_holonomic(erf(x) + x).to_expr() q = 3*C_3*x - 3*sqrt(pi)*C_3*erf(x)/2 + x + 2*x/sqrt(pi) assert p == q p = expr_to_holonomic(sqrt(x), x0=1).to_expr() assert p == sqrt(x) assert expr_to_holonomic(sqrt(x)).to_expr() == sqrt(x) p = expr_to_holonomic(sqrt(1 + x**2)).to_expr() assert p == sqrt(1+x**2) p = expr_to_holonomic((2*x**2 + 1)**Rational(2, 3)).to_expr() assert p == (2*x**2 + 1)**Rational(2, 3) p = expr_to_holonomic(sqrt(-x**2+2*x)).to_expr() assert p == sqrt(x)*sqrt(-x + 2) p = expr_to_holonomic((-2*x**3+7*x)**Rational(2, 3)).to_expr() q = x**Rational(2, 3)*(-2*x**2 + 7)**Rational(2, 3) assert p == q p = from_hyper(hyper((-2, -3), (S.Half, ), x)) s = hyperexpand(hyper((-2, -3), (S.Half, ), x)) D_0 = Symbol('D_0') C_0 = Symbol('C_0') assert (p.to_expr().subs({C_0:1, D_0:0}) - s).simplify() == 0 p.y0 = {0: [1], S.Half: [0]} assert p.to_expr() == s assert expr_to_holonomic(x**5).to_expr() == x**5 assert expr_to_holonomic(2*x**3-3*x**2).to_expr().expand() == \ 2*x**3-3*x**2 a = symbols("a") p = (expr_to_holonomic(1.4*x)*expr_to_holonomic(a*x, x)).to_expr() q = 1.4*a*x**2 assert p == q p = (expr_to_holonomic(1.4*x)+expr_to_holonomic(a*x, x)).to_expr() q = x*(a + 1.4) assert p == q p = (expr_to_holonomic(1.4*x)+expr_to_holonomic(x)).to_expr() assert p == 2.4*x def test_integrate(): x = symbols('x') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') p = expr_to_holonomic(sin(x)**2/x, x0=1).integrate((x, 2, 3)) q = '0.166270406994788' assert sstr(p) == q p = expr_to_holonomic(sin(x)).integrate((x, 0, x)).to_expr() q = 1 - cos(x) assert p == q p = expr_to_holonomic(sin(x)).integrate((x, 0, 3)) q = 1 - cos(3) assert p == q p = expr_to_holonomic(sin(x)/x, x0=1).integrate((x, 1, 2)) q = '0.659329913368450' assert sstr(p) == q p = expr_to_holonomic(sin(x)**2/x, x0=1).integrate((x, 1, 0)) q = '-0.423690480850035' assert sstr(p) == q p = expr_to_holonomic(sin(x)/x) assert p.integrate(x).to_expr() == Si(x) assert p.integrate((x, 0, 2)) == Si(2) p = expr_to_holonomic(sin(x)**2/x) q = p.to_expr() assert p.integrate(x).to_expr() == q.integrate((x, 0, x)) assert p.integrate((x, 0, 1)) == q.integrate((x, 0, 1)) assert expr_to_holonomic(1/x, x0=1).integrate(x).to_expr() == log(x) p = expr_to_holonomic((x + 1)**3*exp(-x), x0=-1).integrate(x).to_expr() q = (-x**3 - 6*x**2 - 15*x + 6*exp(x + 1) - 16)*exp(-x) assert p == q p = expr_to_holonomic(cos(x)**2/x**2, y0={-2: [1, 0, -1]}).integrate(x).to_expr() q = -Si(2*x) - cos(x)**2/x assert p == q p = expr_to_holonomic(sqrt(x**2+x)).integrate(x).to_expr() q = (x**Rational(3, 2)*(2*x**2 + 3*x + 1) - x*sqrt(x + 1)*asinh(sqrt(x)))/(4*x*sqrt(x + 1)) assert p == q p = expr_to_holonomic(sqrt(x**2+1)).integrate(x).to_expr() q = (sqrt(x**2+1)).integrate(x) assert (p-q).simplify() == 0 p = expr_to_holonomic(1/x**2, y0={-2:[1, 0, 0]}) r = expr_to_holonomic(1/x**2, lenics=3) assert p == r q = expr_to_holonomic(cos(x)**2) assert (r*q).integrate(x).to_expr() == -Si(2*x) - cos(x)**2/x def test_diff(): x, y = symbols('x, y') R, Dx = DifferentialOperators(ZZ.old_poly_ring(x), 'Dx') p = HolonomicFunction(x*Dx**2 + 1, x, 0, [0, 1]) assert p.diff().to_expr() == p.to_expr().diff().simplify() p = HolonomicFunction(Dx**2 - 1, x, 0, [1, 0]) assert p.diff(x, 2).to_expr() == p.to_expr() p = expr_to_holonomic(Si(x)) assert p.diff().to_expr() == sin(x)/x assert p.diff(y) == 0 C_0, C_1, C_2, C_3 = symbols('C_0, C_1, C_2, C_3') q = Si(x) assert p.diff(x).to_expr() == q.diff() assert p.diff(x, 2).to_expr().subs(C_0, Rational(-1, 3)).cancel() == q.diff(x, 2).cancel() assert p.diff(x, 3).series().subs({C_3: Rational(-1, 3), C_0: 0}) == q.diff(x, 3).series() def test_extended_domain_in_expr_to_holonomic(): x = symbols('x') p = expr_to_holonomic(1.2*cos(3.1*x)) assert p.to_expr() == 1.2*cos(3.1*x) assert sstr(p.integrate(x).to_expr()) == '0.387096774193548*sin(3.1*x)' _, Dx = DifferentialOperators(RR.old_poly_ring(x), 'Dx') p = expr_to_holonomic(1.1329138213*x) q = HolonomicFunction((-1.1329138213) + (1.1329138213*x)*Dx, x, 0, {1: [1.1329138213]}) assert p == q assert p.to_expr() == 1.1329138213*x assert sstr(p.integrate((x, 1, 2))) == sstr((1.1329138213*x).integrate((x, 1, 2))) y, z = symbols('y, z') p = expr_to_holonomic(sin(x*y*z), x=x) assert p.to_expr() == sin(x*y*z) assert p.integrate(x).to_expr() == (-cos(x*y*z) + 1)/(y*z) p = expr_to_holonomic(sin(x*y + z), x=x).integrate(x).to_expr() q = (cos(z) - cos(x*y + z))/y assert p == q a = symbols('a') p = expr_to_holonomic(a*x, x) assert p.to_expr() == a*x assert p.integrate(x).to_expr() == a*x**2/2 D_2, C_1 = symbols("D_2, C_1") p = expr_to_holonomic(x) + expr_to_holonomic(1.2*cos(x)) p = p.to_expr().subs(D_2, 0) assert p - x - 1.2*cos(1.0*x) == 0 p = expr_to_holonomic(x) * expr_to_holonomic(1.2*cos(x)) p = p.to_expr().subs(C_1, 0) assert p - 1.2*x*cos(1.0*x) == 0 def test_to_meijerg(): x = symbols('x') assert hyperexpand(expr_to_holonomic(sin(x)).to_meijerg()) == sin(x) assert hyperexpand(expr_to_holonomic(cos(x)).to_meijerg()) == cos(x) assert hyperexpand(expr_to_holonomic(exp(x)).to_meijerg()) == exp(x) assert hyperexpand(expr_to_holonomic(log(x)).to_meijerg()).simplify() == log(x) assert expr_to_holonomic(4*x**2/3 + 7).to_meijerg() == 4*x**2/3 + 7 assert hyperexpand(expr_to_holonomic(besselj(2, x), lenics=3).to_meijerg()) == besselj(2, x) p = hyper((Rational(-1, 2), -3), (), x) assert from_hyper(p).to_meijerg() == hyperexpand(p) p = hyper((S.One, S(3)), (S(2), ), x) assert (hyperexpand(from_hyper(p).to_meijerg()) - hyperexpand(p)).expand() == 0 p = from_hyper(hyper((-2, -3), (S.Half, ), x)) s = hyperexpand(hyper((-2, -3), (S.Half, ), x)) C_0 = Symbol('C_0') C_1 = Symbol('C_1') D_0 = Symbol('D_0') assert (hyperexpand(p.to_meijerg()).subs({C_0:1, D_0:0}) - s).simplify() == 0 p.y0 = {0: [1], S.Half: [0]} assert (hyperexpand(p.to_meijerg()) - s).simplify() == 0 p = expr_to_holonomic(besselj(S.Half, x), initcond=False) assert (p.to_expr() - (D_0*sin(x) + C_0*cos(x) + C_1*sin(x))/sqrt(x)).simplify() == 0 p = expr_to_holonomic(besselj(S.Half, x), y0={Rational(-1, 2): [sqrt(2)/sqrt(pi), sqrt(2)/sqrt(pi)]}) assert (p.to_expr() - besselj(S.Half, x) - besselj(Rational(-1, 2), x)).simplify() == 0 def test_gaussian(): mu, x = symbols("mu x") sd = symbols("sd", positive=True) Q = QQ[mu, sd].get_field() e = sqrt(2)*exp(-(-mu + x)**2/(2*sd**2))/(2*sqrt(pi)*sd) h1 = expr_to_holonomic(e, x, domain=Q) _, Dx = DifferentialOperators(Q.old_poly_ring(x), 'Dx') h2 = HolonomicFunction((-mu/sd**2 + x/sd**2) + (1)*Dx, x) assert h1 == h2 def test_beta(): a, b, x = symbols("a b x", positive=True) e = x**(a - 1)*(-x + 1)**(b - 1)/beta(a, b) Q = QQ[a, b].get_field() h1 = expr_to_holonomic(e, x, domain=Q) _, Dx = DifferentialOperators(Q.old_poly_ring(x), 'Dx') h2 = HolonomicFunction((a + x*(-a - b + 2) - 1) + (x**2 - x)*Dx, x) assert h1 == h2 def test_gamma(): a, b, x = symbols("a b x", positive=True) e = b**(-a)*x**(a - 1)*exp(-x/b)/gamma(a) Q = QQ[a, b].get_field() h1 = expr_to_holonomic(e, x, domain=Q) _, Dx = DifferentialOperators(Q.old_poly_ring(x), 'Dx') h2 = HolonomicFunction((-a + 1 + x/b) + (x)*Dx, x) assert h1 == h2 def test_symbolic_power(): x, n = symbols("x n") Q = QQ[n].get_field() _, Dx = DifferentialOperators(Q.old_poly_ring(x), 'Dx') h1 = HolonomicFunction((-1) + (x)*Dx, x) ** -n h2 = HolonomicFunction((n) + (x)*Dx, x) assert h1 == h2 def test_negative_power(): x = symbols("x") _, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') h1 = HolonomicFunction((-1) + (x)*Dx, x) ** -2 h2 = HolonomicFunction((2) + (x)*Dx, x) assert h1 == h2 def test_expr_in_power(): x, n = symbols("x n") Q = QQ[n].get_field() _, Dx = DifferentialOperators(Q.old_poly_ring(x), 'Dx') h1 = HolonomicFunction((-1) + (x)*Dx, x) ** (n - 3) h2 = HolonomicFunction((-n + 3) + (x)*Dx, x) assert h1 == h2 def test_DifferentialOperatorEqPoly(): x = symbols('x', integer=True) R, Dx = DifferentialOperators(QQ.old_poly_ring(x), 'Dx') do = DifferentialOperator([x**2, R.base.zero, R.base.zero], R) do2 = DifferentialOperator([x**2, 1, x], R) assert not do == do2 # polynomial comparison issue, see https://github.com/sympy/sympy/pull/15799 # should work once that is solved # p = do.listofpoly[0] # assert do == p p2 = do2.listofpoly[0] assert not do2 == p2 sympy-sympy-1.9/sympy/holonomic/tests/test_recurrence.py000066400000000000000000000017471412543434000240140ustar00rootroot00000000000000from sympy.holonomic.recurrence import RecurrenceOperators, RecurrenceOperator from sympy import symbols, QQ def test_RecurrenceOperator(): n = symbols('n', integer=True) R, Sn = RecurrenceOperators(QQ.old_poly_ring(n), 'Sn') assert Sn*n == (n + 1)*Sn assert Sn*n**2 == (n**2+1+2*n)*Sn assert Sn**2*n**2 == (n**2 + 4*n + 4)*Sn**2 p = (Sn**3*n**2 + Sn*n)**2 q = (n**2 + 3*n + 2)*Sn**2 + (2*n**3 + 19*n**2 + 57*n + 52)*Sn**4 + (n**4 + 18*n**3 + \ 117*n**2 + 324*n + 324)*Sn**6 assert p == q def test_RecurrenceOperatorEqPoly(): n = symbols('n', integer=True) R, Sn = RecurrenceOperators(QQ.old_poly_ring(n), 'Sn') rr = RecurrenceOperator([n**2, 0, 0], R) rr2 = RecurrenceOperator([n**2, 1, n], R) assert not rr == rr2 # polynomial comparison issue, see https://github.com/sympy/sympy/pull/15799 # should work once that is solved # d = rr.listofpoly[0] # assert rr == d d2 = rr2.listofpoly[0] assert not rr2 == d2 sympy-sympy-1.9/sympy/integrals/000077500000000000000000000000001412543434000170745ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/__init__.py000066400000000000000000000034641412543434000212140ustar00rootroot00000000000000"""Integration functions that integrate a sympy expression. Examples ======== >>> from sympy import integrate, sin >>> from sympy.abc import x >>> integrate(1/x,x) log(x) >>> integrate(sin(x),x) -cos(x) """ from .integrals import integrate, Integral, line_integrate from .transforms import (mellin_transform, inverse_mellin_transform, MellinTransform, InverseMellinTransform, laplace_transform, inverse_laplace_transform, LaplaceTransform, InverseLaplaceTransform, fourier_transform, inverse_fourier_transform, FourierTransform, InverseFourierTransform, sine_transform, inverse_sine_transform, SineTransform, InverseSineTransform, cosine_transform, inverse_cosine_transform, CosineTransform, InverseCosineTransform, hankel_transform, inverse_hankel_transform, HankelTransform, InverseHankelTransform) from .singularityfunctions import singularityintegrate __all__ = [ 'integrate', 'Integral', 'line_integrate', 'mellin_transform', 'inverse_mellin_transform', 'MellinTransform', 'InverseMellinTransform', 'laplace_transform', 'inverse_laplace_transform', 'LaplaceTransform', 'InverseLaplaceTransform', 'fourier_transform', 'inverse_fourier_transform', 'FourierTransform', 'InverseFourierTransform', 'sine_transform', 'inverse_sine_transform', 'SineTransform', 'InverseSineTransform', 'cosine_transform', 'inverse_cosine_transform', 'CosineTransform', 'InverseCosineTransform', 'hankel_transform', 'inverse_hankel_transform', 'HankelTransform', 'InverseHankelTransform', 'singularityintegrate', ] sympy-sympy-1.9/sympy/integrals/benchmarks/000077500000000000000000000000001412543434000212115ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/benchmarks/__init__.py000066400000000000000000000000001412543434000233100ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/benchmarks/bench_integrate.py000066400000000000000000000004471412543434000247110ustar00rootroot00000000000000from sympy import integrate, Symbol, sin x = Symbol('x') def bench_integrate_sin(): integrate(sin(x), x) def bench_integrate_x1sin(): integrate(x**1*sin(x), x) def bench_integrate_x2sin(): integrate(x**2*sin(x), x) def bench_integrate_x3sin(): integrate(x**3*sin(x), x) sympy-sympy-1.9/sympy/integrals/benchmarks/bench_trigintegrate.py000066400000000000000000000003611412543434000255720ustar00rootroot00000000000000from sympy import Symbol, sin from sympy.integrals.trigonometry import trigintegrate x = Symbol('x') def timeit_trigintegrate_sin3x(): trigintegrate(sin(x)**3, x) def timeit_trigintegrate_x2(): trigintegrate(x**2, x) # -> None sympy-sympy-1.9/sympy/integrals/deltafunctions.py000066400000000000000000000164021412543434000224730ustar00rootroot00000000000000from sympy.core import Mul from sympy.functions import DiracDelta, Heaviside from sympy.core.compatibility import default_sort_key from sympy.core.singleton import S def change_mul(node, x): """change_mul(node, x) Rearranges the operands of a product, bringing to front any simple DiracDelta expression. Explanation =========== If no simple DiracDelta expression was found, then all the DiracDelta expressions are simplified (using DiracDelta.expand(diracdelta=True, wrt=x)). Return: (dirac, new node) Where: o dirac is either a simple DiracDelta expression or None (if no simple expression was found); o new node is either a simplified DiracDelta expressions or None (if it could not be simplified). Examples ======== >>> from sympy import DiracDelta, cos >>> from sympy.integrals.deltafunctions import change_mul >>> from sympy.abc import x, y >>> change_mul(x*y*DiracDelta(x)*cos(x), x) (DiracDelta(x), x*y*cos(x)) >>> change_mul(x*y*DiracDelta(x**2 - 1)*cos(x), x) (None, x*y*cos(x)*DiracDelta(x - 1)/2 + x*y*cos(x)*DiracDelta(x + 1)/2) >>> change_mul(x*y*DiracDelta(cos(x))*cos(x), x) (None, None) See Also ======== sympy.functions.special.delta_functions.DiracDelta deltaintegrate """ new_args = [] dirac = None #Sorting is needed so that we consistently collapse the same delta; #However, we must preserve the ordering of non-commutative terms c, nc = node.args_cnc() sorted_args = sorted(c, key=default_sort_key) sorted_args.extend(nc) for arg in sorted_args: if arg.is_Pow and isinstance(arg.base, DiracDelta): new_args.append(arg.func(arg.base, arg.exp - 1)) arg = arg.base if dirac is None and (isinstance(arg, DiracDelta) and arg.is_simple(x)): dirac = arg else: new_args.append(arg) if not dirac: # there was no simple dirac new_args = [] for arg in sorted_args: if isinstance(arg, DiracDelta): new_args.append(arg.expand(diracdelta=True, wrt=x)) elif arg.is_Pow and isinstance(arg.base, DiracDelta): new_args.append(arg.func(arg.base.expand(diracdelta=True, wrt=x), arg.exp)) else: new_args.append(arg) if new_args != sorted_args: nnode = Mul(*new_args).expand() else: # if the node didn't change there is nothing to do nnode = None return (None, nnode) return (dirac, Mul(*new_args)) def deltaintegrate(f, x): """ deltaintegrate(f, x) Explanation =========== The idea for integration is the following: - If we are dealing with a DiracDelta expression, i.e. DiracDelta(g(x)), we try to simplify it. If we could simplify it, then we integrate the resulting expression. We already know we can integrate a simplified expression, because only simple DiracDelta expressions are involved. If we couldn't simplify it, there are two cases: 1) The expression is a simple expression: we return the integral, taking care if we are dealing with a Derivative or with a proper DiracDelta. 2) The expression is not simple (i.e. DiracDelta(cos(x))): we can do nothing at all. - If the node is a multiplication node having a DiracDelta term: First we expand it. If the expansion did work, then we try to integrate the expansion. If not, we try to extract a simple DiracDelta term, then we have two cases: 1) We have a simple DiracDelta term, so we return the integral. 2) We didn't have a simple term, but we do have an expression with simplified DiracDelta terms, so we integrate this expression. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.integrals.deltafunctions import deltaintegrate >>> from sympy import sin, cos, DiracDelta >>> deltaintegrate(x*sin(x)*cos(x)*DiracDelta(x - 1), x) sin(1)*cos(1)*Heaviside(x - 1) >>> deltaintegrate(y**2*DiracDelta(x - z)*DiracDelta(y - z), y) z**2*DiracDelta(x - z)*Heaviside(y - z) See Also ======== sympy.functions.special.delta_functions.DiracDelta sympy.integrals.integrals.Integral """ if not f.has(DiracDelta): return None from sympy.integrals import Integral, integrate from sympy.solvers import solve # g(x) = DiracDelta(h(x)) if f.func == DiracDelta: h = f.expand(diracdelta=True, wrt=x) if h == f: # can't simplify the expression #FIXME: the second term tells whether is DeltaDirac or Derivative #For integrating derivatives of DiracDelta we need the chain rule if f.is_simple(x): if (len(f.args) <= 1 or f.args[1] == 0): return Heaviside(f.args[0]) else: return (DiracDelta(f.args[0], f.args[1] - 1) / f.args[0].as_poly().LC()) else: # let's try to integrate the simplified expression fh = integrate(h, x) return fh elif f.is_Mul or f.is_Pow: # g(x) = a*b*c*f(DiracDelta(h(x)))*d*e g = f.expand() if f != g: # the expansion worked fh = integrate(g, x) if fh is not None and not isinstance(fh, Integral): return fh else: # no expansion performed, try to extract a simple DiracDelta term deltaterm, rest_mult = change_mul(f, x) if not deltaterm: if rest_mult: fh = integrate(rest_mult, x) return fh else: deltaterm = deltaterm.expand(diracdelta=True, wrt=x) if deltaterm.is_Mul: # Take out any extracted factors deltaterm, rest_mult_2 = change_mul(deltaterm, x) rest_mult = rest_mult*rest_mult_2 point = solve(deltaterm.args[0], x)[0] # Return the largest hyperreal term left after # repeated integration by parts. For example, # # integrate(y*DiracDelta(x, 1),x) == y*DiracDelta(x,0), not 0 # # This is so Integral(y*DiracDelta(x).diff(x),x).doit() # will return y*DiracDelta(x) instead of 0 or DiracDelta(x), # both of which are correct everywhere the value is defined # but give wrong answers for nested integration. n = (0 if len(deltaterm.args)==1 else deltaterm.args[1]) m = 0 while n >= 0: r = (-1)**n*rest_mult.diff(x, n).subs(x, point) if r.is_zero: n -= 1 m += 1 else: if m == 0: return r*Heaviside(x - point) else: return r*DiracDelta(x,m-1) # In some very weak sense, x=0 is still a singularity, # but we hope will not be of any practical consequence. return S.Zero return None sympy-sympy-1.9/sympy/integrals/heurisch.py000066400000000000000000000616171412543434000212730ustar00rootroot00000000000000from typing import Dict, List from itertools import permutations from functools import reduce from sympy.core.add import Add from sympy.core.basic import Basic from sympy.core.mul import Mul from sympy.core.symbol import Wild, Dummy from sympy.core.basic import sympify from sympy.core.numbers import Rational, pi, I from sympy.core.relational import Eq, Ne from sympy.core.singleton import S from sympy.functions import exp, sin, cos, tan, cot, asin, atan from sympy.functions import log, sinh, cosh, tanh, coth, asinh, acosh from sympy.functions import sqrt, erf, erfi, li, Ei from sympy.functions import besselj, bessely, besseli, besselk from sympy.functions import hankel1, hankel2, jn, yn from sympy.functions.elementary.complexes import Abs, re, im, sign, arg from sympy.functions.elementary.exponential import LambertW from sympy.functions.elementary.integers import floor, ceiling from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.special.delta_functions import Heaviside, DiracDelta from sympy.simplify.radsimp import collect from sympy.logic.boolalg import And, Or from sympy.utilities.iterables import uniq from sympy.polys import quo, gcd, lcm, factor, cancel, PolynomialError from sympy.polys.monomials import itermonomials from sympy.polys.polyroots import root_factors from sympy.polys.rings import PolyRing from sympy.polys.solvers import solve_lin_sys from sympy.polys.constructor import construct_domain from sympy.core.compatibility import ordered from sympy.integrals.integrals import integrate def components(f, x): """ Returns a set of all functional components of the given expression which includes symbols, function applications and compositions and non-integer powers. Fractional powers are collected with minimal, positive exponents. Examples ======== >>> from sympy import cos, sin >>> from sympy.abc import x >>> from sympy.integrals.heurisch import components >>> components(sin(x)*cos(x)**2, x) {x, sin(x), cos(x)} See Also ======== heurisch """ result = set() if x in f.free_symbols: if f.is_symbol and f.is_commutative: result.add(f) elif f.is_Function or f.is_Derivative: for g in f.args: result |= components(g, x) result.add(f) elif f.is_Pow: result |= components(f.base, x) if not f.exp.is_Integer: if f.exp.is_Rational: result.add(f.base**Rational(1, f.exp.q)) else: result |= components(f.exp, x) | {f} else: for g in f.args: result |= components(g, x) return result # name -> [] of symbols _symbols_cache = {} # type: Dict[str, List[Dummy]] # NB @cacheit is not convenient here def _symbols(name, n): """get vector of symbols local to this module""" try: lsyms = _symbols_cache[name] except KeyError: lsyms = [] _symbols_cache[name] = lsyms while len(lsyms) < n: lsyms.append( Dummy('%s%i' % (name, len(lsyms))) ) return lsyms[:n] def heurisch_wrapper(f, x, rewrite=False, hints=None, mappings=None, retries=3, degree_offset=0, unnecessary_permutations=None, _try_heurisch=None): """ A wrapper around the heurisch integration algorithm. Explanation =========== This method takes the result from heurisch and checks for poles in the denominator. For each of these poles, the integral is reevaluated, and the final integration result is given in terms of a Piecewise. Examples ======== >>> from sympy.core import symbols >>> from sympy.functions import cos >>> from sympy.integrals.heurisch import heurisch, heurisch_wrapper >>> n, x = symbols('n x') >>> heurisch(cos(n*x), x) sin(n*x)/n >>> heurisch_wrapper(cos(n*x), x) Piecewise((sin(n*x)/n, Ne(n, 0)), (x, True)) See Also ======== heurisch """ from sympy.solvers.solvers import solve, denoms f = sympify(f) if x not in f.free_symbols: return f*x res = heurisch(f, x, rewrite, hints, mappings, retries, degree_offset, unnecessary_permutations, _try_heurisch) if not isinstance(res, Basic): return res # We consider each denominator in the expression, and try to find # cases where one or more symbolic denominator might be zero. The # conditions for these cases are stored in the list slns. slns = [] for d in denoms(res): try: slns += solve(d, dict=True, exclude=(x,)) except NotImplementedError: pass if not slns: return res slns = list(uniq(slns)) # Remove the solutions corresponding to poles in the original expression. slns0 = [] for d in denoms(f): try: slns0 += solve(d, dict=True, exclude=(x,)) except NotImplementedError: pass slns = [s for s in slns if s not in slns0] if not slns: return res if len(slns) > 1: eqs = [] for sub_dict in slns: eqs.extend([Eq(key, value) for key, value in sub_dict.items()]) slns = solve(eqs, dict=True, exclude=(x,)) + slns # For each case listed in the list slns, we reevaluate the integral. pairs = [] for sub_dict in slns: expr = heurisch(f.subs(sub_dict), x, rewrite, hints, mappings, retries, degree_offset, unnecessary_permutations, _try_heurisch) cond = And(*[Eq(key, value) for key, value in sub_dict.items()]) generic = Or(*[Ne(key, value) for key, value in sub_dict.items()]) if expr is None: expr = integrate(f.subs(sub_dict),x) pairs.append((expr, cond)) # If there is one condition, put the generic case first. Otherwise, # doing so may lead to longer Piecewise formulas if len(pairs) == 1: pairs = [(heurisch(f, x, rewrite, hints, mappings, retries, degree_offset, unnecessary_permutations, _try_heurisch), generic), (pairs[0][0], True)] else: pairs.append((heurisch(f, x, rewrite, hints, mappings, retries, degree_offset, unnecessary_permutations, _try_heurisch), True)) return Piecewise(*pairs) class BesselTable: """ Derivatives of Bessel functions of orders n and n-1 in terms of each other. See the docstring of DiffCache. """ def __init__(self): self.table = {} self.n = Dummy('n') self.z = Dummy('z') self._create_table() def _create_table(t): table, n, z = t.table, t.n, t.z for f in (besselj, bessely, hankel1, hankel2): table[f] = (f(n-1, z) - n*f(n, z)/z, (n-1)*f(n-1, z)/z - f(n, z)) f = besseli table[f] = (f(n-1, z) - n*f(n, z)/z, (n-1)*f(n-1, z)/z + f(n, z)) f = besselk table[f] = (-f(n-1, z) - n*f(n, z)/z, (n-1)*f(n-1, z)/z - f(n, z)) for f in (jn, yn): table[f] = (f(n-1, z) - (n+1)*f(n, z)/z, (n-1)*f(n-1, z)/z - f(n, z)) def diffs(t, f, n, z): if f in t.table: diff0, diff1 = t.table[f] repl = [(t.n, n), (t.z, z)] return (diff0.subs(repl), diff1.subs(repl)) def has(t, f): return f in t.table _bessel_table = None class DiffCache: """ Store for derivatives of expressions. Explanation =========== The standard form of the derivative of a Bessel function of order n contains two Bessel functions of orders n-1 and n+1, respectively. Such forms cannot be used in parallel Risch algorithm, because there is a linear recurrence relation between the three functions while the algorithm expects that functions and derivatives are represented in terms of algebraically independent transcendentals. The solution is to take two of the functions, e.g., those of orders n and n-1, and to express the derivatives in terms of the pair. To guarantee that the proper form is used the two derivatives are cached as soon as one is encountered. Derivatives of other functions are also cached at no extra cost. All derivatives are with respect to the same variable `x`. """ def __init__(self, x): self.cache = {} self.x = x global _bessel_table if not _bessel_table: _bessel_table = BesselTable() def get_diff(self, f): cache = self.cache if f in cache: pass elif (not hasattr(f, 'func') or not _bessel_table.has(f.func)): cache[f] = cancel(f.diff(self.x)) else: n, z = f.args d0, d1 = _bessel_table.diffs(f.func, n, z) dz = self.get_diff(z) cache[f] = d0*dz cache[f.func(n-1, z)] = d1*dz return cache[f] def heurisch(f, x, rewrite=False, hints=None, mappings=None, retries=3, degree_offset=0, unnecessary_permutations=None, _try_heurisch=None): """ Compute indefinite integral using heuristic Risch algorithm. Explanation =========== This is a heuristic approach to indefinite integration in finite terms using the extended heuristic (parallel) Risch algorithm, based on Manuel Bronstein's "Poor Man's Integrator". The algorithm supports various classes of functions including transcendental elementary or special functions like Airy, Bessel, Whittaker and Lambert. Note that this algorithm is not a decision procedure. If it isn't able to compute the antiderivative for a given function, then this is not a proof that such a functions does not exist. One should use recursive Risch algorithm in such case. It's an open question if this algorithm can be made a full decision procedure. This is an internal integrator procedure. You should use toplevel 'integrate' function in most cases, as this procedure needs some preprocessing steps and otherwise may fail. Specification ============= heurisch(f, x, rewrite=False, hints=None) where f : expression x : symbol rewrite -> force rewrite 'f' in terms of 'tan' and 'tanh' hints -> a list of functions that may appear in anti-derivate - hints = None --> no suggestions at all - hints = [ ] --> try to figure out - hints = [f1, ..., fn] --> we know better Examples ======== >>> from sympy import tan >>> from sympy.integrals.heurisch import heurisch >>> from sympy.abc import x, y >>> heurisch(y*tan(x), x) y*log(tan(x)**2 + 1)/2 See Manuel Bronstein's "Poor Man's Integrator": References ========== .. [1] http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/index.html For more information on the implemented algorithm refer to: .. [2] K. Geddes, L. Stefanus, On the Risch-Norman Integration Method and its Implementation in Maple, Proceedings of ISSAC'89, ACM Press, 212-217. .. [3] J. H. Davenport, On the Parallel Risch Algorithm (I), Proceedings of EUROCAM'82, LNCS 144, Springer, 144-157. .. [4] J. H. Davenport, On the Parallel Risch Algorithm (III): Use of Tangents, SIGSAM Bulletin 16 (1982), 3-6. .. [5] J. H. Davenport, B. M. Trager, On the Parallel Risch Algorithm (II), ACM Transactions on Mathematical Software 11 (1985), 356-362. See Also ======== sympy.integrals.integrals.Integral.doit sympy.integrals.integrals.Integral sympy.integrals.heurisch.components """ f = sympify(f) # There are some functions that Heurisch cannot currently handle, # so do not even try. # Set _try_heurisch=True to skip this check if _try_heurisch is not True: if f.has(Abs, re, im, sign, Heaviside, DiracDelta, floor, ceiling, arg): return if x not in f.free_symbols: return f*x if not f.is_Add: indep, f = f.as_independent(x) else: indep = S.One rewritables = { (sin, cos, cot): tan, (sinh, cosh, coth): tanh, } if rewrite: for candidates, rule in rewritables.items(): f = f.rewrite(candidates, rule) else: for candidates in rewritables.keys(): if f.has(*candidates): break else: rewrite = True terms = components(f, x) if hints is not None: if not hints: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) c = Wild('c', exclude=[x]) for g in set(terms): # using copy of terms if g.is_Function: if isinstance(g, li): M = g.args[0].match(a*x**b) if M is not None: terms.add( x*(li(M[a]*x**M[b]) - (M[a]*x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) #terms.add( x*(li(M[a]*x**M[b]) - (x**M[b])**(-1/M[b])*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) #terms.add( x*(li(M[a]*x**M[b]) - x*Ei((M[b]+1)*log(M[a]*x**M[b])/M[b])) ) #terms.add( li(M[a]*x**M[b]) - Ei((M[b]+1)*log(M[a]*x**M[b])/M[b]) ) elif isinstance(g, exp): M = g.args[0].match(a*x**2) if M is not None: if M[a].is_positive: terms.add(erfi(sqrt(M[a])*x)) else: # M[a].is_negative or unknown terms.add(erf(sqrt(-M[a])*x)) M = g.args[0].match(a*x**2 + b*x + c) if M is not None: if M[a].is_positive: terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))* erfi(sqrt(M[a])*x + M[b]/(2*sqrt(M[a])))) elif M[a].is_negative: terms.add(sqrt(pi/4*(-M[a]))*exp(M[c] - M[b]**2/(4*M[a]))* erf(sqrt(-M[a])*x - M[b]/(2*sqrt(-M[a])))) M = g.args[0].match(a*log(x)**2) if M is not None: if M[a].is_positive: terms.add(erfi(sqrt(M[a])*log(x) + 1/(2*sqrt(M[a])))) if M[a].is_negative: terms.add(erf(sqrt(-M[a])*log(x) - 1/(2*sqrt(-M[a])))) elif g.is_Pow: if g.exp.is_Rational and g.exp.q == 2: M = g.base.match(a*x**2 + b) if M is not None and M[b].is_positive: if M[a].is_positive: terms.add(asinh(sqrt(M[a]/M[b])*x)) elif M[a].is_negative: terms.add(asin(sqrt(-M[a]/M[b])*x)) M = g.base.match(a*x**2 - b) if M is not None and M[b].is_positive: if M[a].is_positive: terms.add(acosh(sqrt(M[a]/M[b])*x)) elif M[a].is_negative: terms.add(-M[b]/2*sqrt(-M[a])* atan(sqrt(-M[a])*x/sqrt(M[a]*x**2 - M[b]))) else: terms |= set(hints) dcache = DiffCache(x) for g in set(terms): # using copy of terms terms |= components(dcache.get_diff(g), x) # TODO: caching is significant factor for why permutations work at all. Change this. V = _symbols('x', len(terms)) # sort mapping expressions from largest to smallest (last is always x). mapping = list(reversed(list(zip(*ordered( # [(a[0].as_independent(x)[1], a) for a in zip(terms, V)])))[1])) # rev_mapping = {v: k for k, v in mapping} # if mappings is None: # # optimizing the number of permutations of mapping # assert mapping[-1][0] == x # if not, find it and correct this comment unnecessary_permutations = [mapping.pop(-1)] mappings = permutations(mapping) else: unnecessary_permutations = unnecessary_permutations or [] def _substitute(expr): return expr.subs(mapping) for mapping in mappings: mapping = list(mapping) mapping = mapping + unnecessary_permutations diffs = [ _substitute(dcache.get_diff(g)) for g in terms ] denoms = [ g.as_numer_denom()[1] for g in diffs ] if all(h.is_polynomial(*V) for h in denoms) and _substitute(f).is_rational_function(*V): denom = reduce(lambda p, q: lcm(p, q, *V), denoms) break else: if not rewrite: result = heurisch(f, x, rewrite=True, hints=hints, unnecessary_permutations=unnecessary_permutations) if result is not None: return indep*result return None numers = [ cancel(denom*g) for g in diffs ] def _derivation(h): return Add(*[ d * h.diff(v) for d, v in zip(numers, V) ]) def _deflation(p): for y in V: if not p.has(y): continue if _derivation(p) is not S.Zero: c, q = p.as_poly(y).primitive() return _deflation(c)*gcd(q, q.diff(y)).as_expr() return p def _splitter(p): for y in V: if not p.has(y): continue if _derivation(y) is not S.Zero: c, q = p.as_poly(y).primitive() q = q.as_expr() h = gcd(q, _derivation(q), y) s = quo(h, gcd(q, q.diff(y), y), y) c_split = _splitter(c) if s.as_poly(y).degree() == 0: return (c_split[0], q * c_split[1]) q_split = _splitter(cancel(q / s)) return (c_split[0]*q_split[0]*s, c_split[1]*q_split[1]) return (S.One, p) special = {} for term in terms: if term.is_Function: if isinstance(term, tan): special[1 + _substitute(term)**2] = False elif isinstance(term, tanh): special[1 + _substitute(term)] = False special[1 - _substitute(term)] = False elif isinstance(term, LambertW): special[_substitute(term)] = True F = _substitute(f) P, Q = F.as_numer_denom() u_split = _splitter(denom) v_split = _splitter(Q) polys = set(list(v_split) + [ u_split[0] ] + list(special.keys())) s = u_split[0] * Mul(*[ k for k, v in special.items() if v ]) polified = [ p.as_poly(*V) for p in [s, P, Q] ] if None in polified: return None #--- definitions for _integrate a, b, c = [ p.total_degree() for p in polified ] poly_denom = (s * v_split[0] * _deflation(v_split[1])).as_expr() def _exponent(g): if g.is_Pow: if g.exp.is_Rational and g.exp.q != 1: if g.exp.p > 0: return g.exp.p + g.exp.q - 1 else: return abs(g.exp.p + g.exp.q) else: return 1 elif not g.is_Atom and g.args: return max([ _exponent(h) for h in g.args ]) else: return 1 A, B = _exponent(f), a + max(b, c) if A > 1 and B > 1: monoms = tuple(ordered(itermonomials(V, A + B - 1 + degree_offset))) else: monoms = tuple(ordered(itermonomials(V, A + B + degree_offset))) poly_coeffs = _symbols('A', len(monoms)) poly_part = Add(*[ poly_coeffs[i]*monomial for i, monomial in enumerate(monoms) ]) reducibles = set() for poly in polys: if poly.has(*V): try: factorization = factor(poly, greedy=True) except PolynomialError: factorization = poly if factorization.is_Mul: factors = factorization.args else: factors = (factorization, ) for fact in factors: if fact.is_Pow: reducibles.add(fact.base) else: reducibles.add(fact) def _integrate(field=None): irreducibles = set() atans = set() pairs = set() for poly in reducibles: for z in poly.free_symbols: if z in V: break # should this be: `irreducibles |= \ else: # set(root_factors(poly, z, filter=field))` continue # and the line below deleted? # | # V irreducibles |= set(root_factors(poly, z, filter=field)) log_part, atan_part = [], [] for poly in list(irreducibles): m = collect(poly, I, evaluate=False) y = m.get(I, S.Zero) if y: x = m.get(S.One, S.Zero) if x.has(I) or y.has(I): continue # nontrivial x + I*y pairs.add((x, y)) irreducibles.remove(poly) while pairs: x, y = pairs.pop() if (x, -y) in pairs: pairs.remove((x, -y)) # Choosing b with no minus sign if y.could_extract_minus_sign(): y = -y irreducibles.add(x*x + y*y) atans.add(atan(x/y)) else: irreducibles.add(x + I*y) B = _symbols('B', len(irreducibles)) C = _symbols('C', len(atans)) # Note: the ordering matters here for poly, b in reversed(list(zip(ordered(irreducibles), B))): if poly.has(*V): poly_coeffs.append(b) log_part.append(b * log(poly)) for poly, c in reversed(list(zip(ordered(atans), C))): if poly.has(*V): poly_coeffs.append(c) atan_part.append(c * poly) # TODO: Currently it's better to use symbolic expressions here instead # of rational functions, because it's simpler and FracElement doesn't # give big speed improvement yet. This is because cancellation is slow # due to slow polynomial GCD algorithms. If this gets improved then # revise this code. candidate = poly_part/poly_denom + Add(*log_part) + Add(*atan_part) h = F - _derivation(candidate) / denom raw_numer = h.as_numer_denom()[0] # Rewrite raw_numer as a polynomial in K[coeffs][V] where K is a field # that we have to determine. We can't use simply atoms() because log(3), # sqrt(y) and similar expressions can appear, leading to non-trivial # domains. syms = set(poly_coeffs) | set(V) non_syms = set() def find_non_syms(expr): if expr.is_Integer or expr.is_Rational: pass # ignore trivial numbers elif expr in syms: pass # ignore variables elif not expr.free_symbols & syms: non_syms.add(expr) elif expr.is_Add or expr.is_Mul or expr.is_Pow: list(map(find_non_syms, expr.args)) else: # TODO: Non-polynomial expression. This should have been # filtered out at an earlier stage. raise PolynomialError try: find_non_syms(raw_numer) except PolynomialError: return None else: ground, _ = construct_domain(non_syms, field=True) coeff_ring = PolyRing(poly_coeffs, ground) ring = PolyRing(V, coeff_ring) try: numer = ring.from_expr(raw_numer) except ValueError: raise PolynomialError solution = solve_lin_sys(numer.coeffs(), coeff_ring, _raw=False) if solution is None: return None else: return candidate.xreplace(solution).xreplace( dict(zip(poly_coeffs, [S.Zero]*len(poly_coeffs)))) if not (F.free_symbols - set(V)): solution = _integrate('Q') if solution is None: solution = _integrate() else: solution = _integrate() if solution is not None: antideriv = solution.subs(rev_mapping) antideriv = cancel(antideriv).expand() if antideriv.is_Add: antideriv = antideriv.as_independent(x)[1] return indep*antideriv else: if retries >= 0: result = heurisch(f, x, mappings=mappings, rewrite=rewrite, hints=hints, retries=retries - 1, unnecessary_permutations=unnecessary_permutations) if result is not None: return indep*result return None sympy-sympy-1.9/sympy/integrals/integrals.py000066400000000000000000001747071412543434000214560ustar00rootroot00000000000000from sympy.concrete.expr_with_limits import AddWithLimits from sympy.core.add import Add from sympy.core.basic import Basic from sympy.core.compatibility import is_sequence from sympy.core.containers import Tuple from sympy.core.expr import Expr from sympy.core.function import diff from sympy.core.logic import fuzzy_bool from sympy.core.mul import Mul from sympy.core.numbers import oo, pi from sympy.core.relational import Ne from sympy.core.singleton import S from sympy.core.symbol import (Dummy, Symbol, Wild) from sympy.core.sympify import sympify from sympy.functions import Piecewise, sqrt, piecewise_fold, tan, cot, atan from sympy.functions.elementary.exponential import log from sympy.functions.elementary.integers import floor from sympy.functions.elementary.complexes import Abs, sign from sympy.functions.elementary.miscellaneous import Min, Max from sympy.integrals.manualintegrate import manualintegrate from sympy.integrals.trigonometry import trigintegrate from sympy.integrals.meijerint import meijerint_definite, meijerint_indefinite from sympy.matrices import MatrixBase from sympy.polys import Poly, PolynomialError from sympy.series import limit from sympy.series.order import Order from sympy.series.formal import FormalPowerSeries from sympy.simplify.fu import sincos_to_sum from sympy.tensor.functions import shape from sympy.utilities.misc import filldedent from sympy.utilities.exceptions import SymPyDeprecationWarning class Integral(AddWithLimits): """Represents unevaluated integral.""" __slots__ = ('is_commutative',) def __new__(cls, function, *symbols, **assumptions): """Create an unevaluated integral. Explanation =========== Arguments are an integrand followed by one or more limits. If no limits are given and there is only one free symbol in the expression, that symbol will be used, otherwise an error will be raised. >>> from sympy import Integral >>> from sympy.abc import x, y >>> Integral(x) Integral(x, x) >>> Integral(y) Integral(y, y) When limits are provided, they are interpreted as follows (using ``x`` as though it were the variable of integration): (x,) or x - indefinite integral (x, a) - "evaluate at" integral is an abstract antiderivative (x, a, b) - definite integral The ``as_dummy`` method can be used to see which symbols cannot be targeted by subs: those with a prepended underscore cannot be changed with ``subs``. (Also, the integration variables themselves -- the first element of a limit -- can never be changed by subs.) >>> i = Integral(x, x) >>> at = Integral(x, (x, x)) >>> i.as_dummy() Integral(x, x) >>> at.as_dummy() Integral(_0, (_0, x)) """ #This will help other classes define their own definitions #of behaviour with Integral. if hasattr(function, '_eval_Integral'): return function._eval_Integral(*symbols, **assumptions) if isinstance(function, Poly): SymPyDeprecationWarning( feature="Using integrate/Integral with Poly", issue=18613, deprecated_since_version="1.6", useinstead="the as_expr or integrate methods of Poly").warn() obj = AddWithLimits.__new__(cls, function, *symbols, **assumptions) return obj def __getnewargs__(self): return (self.function,) + tuple([tuple(xab) for xab in self.limits]) @property def free_symbols(self): """ This method returns the symbols that will exist when the integral is evaluated. This is useful if one is trying to determine whether an integral depends on a certain symbol or not. Examples ======== >>> from sympy import Integral >>> from sympy.abc import x, y >>> Integral(x, (x, y, 1)).free_symbols {y} See Also ======== sympy.concrete.expr_with_limits.ExprWithLimits.function sympy.concrete.expr_with_limits.ExprWithLimits.limits sympy.concrete.expr_with_limits.ExprWithLimits.variables """ return AddWithLimits.free_symbols.fget(self) def _eval_is_zero(self): # This is a very naive and quick test, not intended to do the integral to # answer whether it is zero or not, e.g. Integral(sin(x), (x, 0, 2*pi)) # is zero but this routine should return None for that case. But, like # Mul, there are trivial situations for which the integral will be # zero so we check for those. if self.function.is_zero: return True got_none = False for l in self.limits: if len(l) == 3: z = (l[1] == l[2]) or (l[1] - l[2]).is_zero if z: return True elif z is None: got_none = True free = self.function.free_symbols for xab in self.limits: if len(xab) == 1: free.add(xab[0]) continue if len(xab) == 2 and xab[0] not in free: if xab[1].is_zero: return True elif xab[1].is_zero is None: got_none = True # take integration symbol out of free since it will be replaced # with the free symbols in the limits free.discard(xab[0]) # add in the new symbols for i in xab[1:]: free.update(i.free_symbols) if self.function.is_zero is False and got_none is False: return False def transform(self, x, u): r""" Performs a change of variables from `x` to `u` using the relationship given by `x` and `u` which will define the transformations `f` and `F` (which are inverses of each other) as follows: 1) If `x` is a Symbol (which is a variable of integration) then `u` will be interpreted as some function, f(u), with inverse F(u). This, in effect, just makes the substitution of x with f(x). 2) If `u` is a Symbol then `x` will be interpreted as some function, F(x), with inverse f(u). This is commonly referred to as u-substitution. Once f and F have been identified, the transformation is made as follows: .. math:: \int_a^b x \mathrm{d}x \rightarrow \int_{F(a)}^{F(b)} f(x) \frac{\mathrm{d}}{\mathrm{d}x} where `F(x)` is the inverse of `f(x)` and the limits and integrand have been corrected so as to retain the same value after integration. Notes ===== The mappings, F(x) or f(u), must lead to a unique integral. Linear or rational linear expression, ``2*x``, ``1/x`` and ``sqrt(x)``, will always work; quadratic expressions like ``x**2 - 1`` are acceptable as long as the resulting integrand does not depend on the sign of the solutions (see examples). The integral will be returned unchanged if ``x`` is not a variable of integration. ``x`` must be (or contain) only one of of the integration variables. If ``u`` has more than one free symbol then it should be sent as a tuple (``u``, ``uvar``) where ``uvar`` identifies which variable is replacing the integration variable. XXX can it contain another integration variable? Examples ======== >>> from sympy.abc import a, x, u >>> from sympy import Integral, cos, sqrt >>> i = Integral(x*cos(x**2 - 1), (x, 0, 1)) transform can change the variable of integration >>> i.transform(x, u) Integral(u*cos(u**2 - 1), (u, 0, 1)) transform can perform u-substitution as long as a unique integrand is obtained: >>> i.transform(x**2 - 1, u) Integral(cos(u)/2, (u, -1, 0)) This attempt fails because x = +/-sqrt(u + 1) and the sign does not cancel out of the integrand: >>> Integral(cos(x**2 - 1), (x, 0, 1)).transform(x**2 - 1, u) Traceback (most recent call last): ... ValueError: The mapping between F(x) and f(u) did not give a unique integrand. transform can do a substitution. Here, the previous result is transformed back into the original expression using "u-substitution": >>> ui = _ >>> _.transform(sqrt(u + 1), x) == i True We can accomplish the same with a regular substitution: >>> ui.transform(u, x**2 - 1) == i True If the `x` does not contain a symbol of integration then the integral will be returned unchanged. Integral `i` does not have an integration variable `a` so no change is made: >>> i.transform(a, x) == i True When `u` has more than one free symbol the symbol that is replacing `x` must be identified by passing `u` as a tuple: >>> Integral(x, (x, 0, 1)).transform(x, (u + a, u)) Integral(a + u, (u, -a, 1 - a)) >>> Integral(x, (x, 0, 1)).transform(x, (u + a, a)) Integral(a + u, (a, -u, 1 - u)) See Also ======== sympy.concrete.expr_with_limits.ExprWithLimits.variables : Lists the integration variables as_dummy : Replace integration variables with dummy ones """ from sympy.solvers.solvers import solve, posify d = Dummy('d') xfree = x.free_symbols.intersection(self.variables) if len(xfree) > 1: raise ValueError( 'F(x) can only contain one of: %s' % self.variables) xvar = xfree.pop() if xfree else d if xvar not in self.variables: return self u = sympify(u) if isinstance(u, Expr): ufree = u.free_symbols if len(ufree) == 0: raise ValueError(filldedent(''' f(u) cannot be a constant''')) if len(ufree) > 1: raise ValueError(filldedent(''' When f(u) has more than one free symbol, the one replacing x must be identified: pass f(u) as (f(u), u)''')) uvar = ufree.pop() else: u, uvar = u if uvar not in u.free_symbols: raise ValueError(filldedent(''' Expecting a tuple (expr, symbol) where symbol identified a free symbol in expr, but symbol is not in expr's free symbols.''')) if not isinstance(uvar, Symbol): # This probably never evaluates to True raise ValueError(filldedent(''' Expecting a tuple (expr, symbol) but didn't get a symbol; got %s''' % uvar)) if x.is_Symbol and u.is_Symbol: return self.xreplace({x: u}) if not x.is_Symbol and not u.is_Symbol: raise ValueError('either x or u must be a symbol') if uvar == xvar: return self.transform(x, (u.subs(uvar, d), d)).xreplace({d: uvar}) if uvar in self.limits: raise ValueError(filldedent(''' u must contain the same variable as in x or a variable that is not already an integration variable''')) if not x.is_Symbol: F = [x.subs(xvar, d)] soln = solve(u - x, xvar, check=False) if not soln: raise ValueError('no solution for solve(F(x) - f(u), x)') f = [fi.subs(uvar, d) for fi in soln] else: f = [u.subs(uvar, d)] pdiff, reps = posify(u - x) puvar = uvar.subs([(v, k) for k, v in reps.items()]) soln = [s.subs(reps) for s in solve(pdiff, puvar)] if not soln: raise ValueError('no solution for solve(F(x) - f(u), u)') F = [fi.subs(xvar, d) for fi in soln] newfuncs = {(self.function.subs(xvar, fi)*fi.diff(d) ).subs(d, uvar) for fi in f} if len(newfuncs) > 1: raise ValueError(filldedent(''' The mapping between F(x) and f(u) did not give a unique integrand.''')) newfunc = newfuncs.pop() def _calc_limit_1(F, a, b): """ replace d with a, using subs if possible, otherwise limit where sign of b is considered """ wok = F.subs(d, a) if wok is S.NaN or wok.is_finite is False and a.is_finite: return limit(sign(b)*F, d, a) return wok def _calc_limit(a, b): """ replace d with a, using subs if possible, otherwise limit where sign of b is considered """ avals = list({_calc_limit_1(Fi, a, b) for Fi in F}) if len(avals) > 1: raise ValueError(filldedent(''' The mapping between F(x) and f(u) did not give a unique limit.''')) return avals[0] newlimits = [] for xab in self.limits: sym = xab[0] if sym == xvar: if len(xab) == 3: a, b = xab[1:] a, b = _calc_limit(a, b), _calc_limit(b, a) if fuzzy_bool(a - b > 0): a, b = b, a newfunc = -newfunc newlimits.append((uvar, a, b)) elif len(xab) == 2: a = _calc_limit(xab[1], 1) newlimits.append((uvar, a)) else: newlimits.append(uvar) else: newlimits.append(xab) return self.func(newfunc, *newlimits) def doit(self, **hints): """ Perform the integration using any hints given. Examples ======== >>> from sympy import Piecewise, S >>> from sympy.abc import x, t >>> p = x**2 + Piecewise((0, x/t < 0), (1, True)) >>> p.integrate((t, S(4)/5, 1), (x, -1, 1)) 1/3 See Also ======== sympy.integrals.trigonometry.trigintegrate sympy.integrals.heurisch.heurisch sympy.integrals.rationaltools.ratint as_sum : Approximate the integral using a sum """ from sympy.concrete.summations import Sum if not hints.get('integrals', True): return self deep = hints.get('deep', True) meijerg = hints.get('meijerg', None) conds = hints.get('conds', 'piecewise') risch = hints.get('risch', None) heurisch = hints.get('heurisch', None) manual = hints.get('manual', None) if len(list(filter(None, (manual, meijerg, risch, heurisch)))) > 1: raise ValueError("At most one of manual, meijerg, risch, heurisch can be True") elif manual: meijerg = risch = heurisch = False elif meijerg: manual = risch = heurisch = False elif risch: manual = meijerg = heurisch = False elif heurisch: manual = meijerg = risch = False eval_kwargs = dict(meijerg=meijerg, risch=risch, manual=manual, heurisch=heurisch, conds=conds) if conds not in ['separate', 'piecewise', 'none']: raise ValueError('conds must be one of "separate", "piecewise", ' '"none", got: %s' % conds) if risch and any(len(xab) > 1 for xab in self.limits): raise ValueError('risch=True is only allowed for indefinite integrals.') # check for the trivial zero if self.is_zero: return S.Zero # hacks to handle integrals of # nested summations if isinstance(self.function, Sum): if any(v in self.function.limits[0] for v in self.variables): raise ValueError('Limit of the sum cannot be an integration variable.') if any(l.is_infinite for l in self.function.limits[0][1:]): return self _i = self _sum = self.function return _sum.func(_i.func(_sum.function, *_i.limits).doit(), *_sum.limits).doit() # now compute and check the function function = self.function if deep: function = function.doit(**hints) if function.is_zero: return S.Zero # hacks to handle special cases if isinstance(function, MatrixBase): return function.applyfunc( lambda f: self.func(f, self.limits).doit(**hints)) if isinstance(function, FormalPowerSeries): if len(self.limits) > 1: raise NotImplementedError xab = self.limits[0] if len(xab) > 1: return function.integrate(xab, **eval_kwargs) else: return function.integrate(xab[0], **eval_kwargs) # There is no trivial answer and special handling # is done so continue # first make sure any definite limits have integration # variables with matching assumptions reps = {} for xab in self.limits: if len(xab) != 3: continue x, a, b = xab l = (a, b) if all(i.is_nonnegative for i in l) and not x.is_nonnegative: d = Dummy(positive=True) elif all(i.is_nonpositive for i in l) and not x.is_nonpositive: d = Dummy(negative=True) elif all(i.is_real for i in l) and not x.is_real: d = Dummy(real=True) else: d = None if d: reps[x] = d if reps: undo = {v: k for k, v in reps.items()} did = self.xreplace(reps).doit(**hints) if type(did) is tuple: # when separate=True did = tuple([i.xreplace(undo) for i in did]) else: did = did.xreplace(undo) return did # continue with existing assumptions undone_limits = [] # ulj = free symbols of any undone limits' upper and lower limits ulj = set() for xab in self.limits: # compute uli, the free symbols in the # Upper and Lower limits of limit I if len(xab) == 1: uli = set(xab[:1]) elif len(xab) == 2: uli = xab[1].free_symbols elif len(xab) == 3: uli = xab[1].free_symbols.union(xab[2].free_symbols) # this integral can be done as long as there is no blocking # limit that has been undone. An undone limit is blocking if # it contains an integration variable that is in this limit's # upper or lower free symbols or vice versa if xab[0] in ulj or any(v[0] in uli for v in undone_limits): undone_limits.append(xab) ulj.update(uli) function = self.func(*([function] + [xab])) factored_function = function.factor() if not isinstance(factored_function, Integral): function = factored_function continue if function.has(Abs, sign) and ( (len(xab) < 3 and all(x.is_extended_real for x in xab)) or (len(xab) == 3 and all(x.is_extended_real and not x.is_infinite for x in xab[1:]))): # some improper integrals are better off with Abs xr = Dummy("xr", real=True) function = (function.xreplace({xab[0]: xr}) .rewrite(Piecewise).xreplace({xr: xab[0]})) elif function.has(Min, Max): function = function.rewrite(Piecewise) if (function.has(Piecewise) and not isinstance(function, Piecewise)): function = piecewise_fold(function) if isinstance(function, Piecewise): if len(xab) == 1: antideriv = function._eval_integral(xab[0], **eval_kwargs) else: antideriv = self._eval_integral( function, xab[0], **eval_kwargs) else: # There are a number of tradeoffs in using the # Meijer G method. It can sometimes be a lot faster # than other methods, and sometimes slower. And # there are certain types of integrals for which it # is more likely to work than others. These # heuristics are incorporated in deciding what # integration methods to try, in what order. See the # integrate() docstring for details. def try_meijerg(function, xab): ret = None if len(xab) == 3 and meijerg is not False: x, a, b = xab try: res = meijerint_definite(function, x, a, b) except NotImplementedError: from sympy.integrals.meijerint import _debug _debug('NotImplementedError ' 'from meijerint_definite') res = None if res is not None: f, cond = res if conds == 'piecewise': ret = Piecewise( (f, cond), (self.func( function, (x, a, b)), True)) elif conds == 'separate': if len(self.limits) != 1: raise ValueError(filldedent(''' conds=separate not supported in multiple integrals''')) ret = f, cond else: ret = f return ret meijerg1 = meijerg if (meijerg is not False and len(xab) == 3 and xab[1].is_extended_real and xab[2].is_extended_real and not function.is_Poly and (xab[1].has(oo, -oo) or xab[2].has(oo, -oo))): ret = try_meijerg(function, xab) if ret is not None: function = ret continue meijerg1 = False # If the special meijerg code did not succeed in # finding a definite integral, then the code using # meijerint_indefinite will not either (it might # find an antiderivative, but the answer is likely # to be nonsensical). Thus if we are requested to # only use Meijer G-function methods, we give up at # this stage. Otherwise we just disable G-function # methods. if meijerg1 is False and meijerg is True: antideriv = None else: antideriv = self._eval_integral( function, xab[0], **eval_kwargs) if antideriv is None and meijerg is True: ret = try_meijerg(function, xab) if ret is not None: function = ret continue final = hints.get('final', True) # dotit may be iterated but floor terms making atan and acot # continous should only be added in the final round if (final and not isinstance(antideriv, Integral) and antideriv is not None): for atan_term in antideriv.atoms(atan): atan_arg = atan_term.args[0] # Checking `atan_arg` to be linear combination of `tan` or `cot` for tan_part in atan_arg.atoms(tan): x1 = Dummy('x1') tan_exp1 = atan_arg.subs(tan_part, x1) # The coefficient of `tan` should be constant coeff = tan_exp1.diff(x1) if x1 not in coeff.free_symbols: a = tan_part.args[0] antideriv = antideriv.subs(atan_term, Add(atan_term, sign(coeff)*pi*floor((a-pi/2)/pi))) for cot_part in atan_arg.atoms(cot): x1 = Dummy('x1') cot_exp1 = atan_arg.subs(cot_part, x1) # The coefficient of `cot` should be constant coeff = cot_exp1.diff(x1) if x1 not in coeff.free_symbols: a = cot_part.args[0] antideriv = antideriv.subs(atan_term, Add(atan_term, sign(coeff)*pi*floor((a)/pi))) if antideriv is None: undone_limits.append(xab) function = self.func(*([function] + [xab])).factor() factored_function = function.factor() if not isinstance(factored_function, Integral): function = factored_function continue else: if len(xab) == 1: function = antideriv else: if len(xab) == 3: x, a, b = xab elif len(xab) == 2: x, b = xab a = None else: raise NotImplementedError if deep: if isinstance(a, Basic): a = a.doit(**hints) if isinstance(b, Basic): b = b.doit(**hints) if antideriv.is_Poly: gens = list(antideriv.gens) gens.remove(x) antideriv = antideriv.as_expr() function = antideriv._eval_interval(x, a, b) function = Poly(function, *gens) else: def is_indef_int(g, x): return (isinstance(g, Integral) and any(i == (x,) for i in g.limits)) def eval_factored(f, x, a, b): # _eval_interval for integrals with # (constant) factors # a single indefinite integral is assumed args = [] for g in Mul.make_args(f): if is_indef_int(g, x): args.append(g._eval_interval(x, a, b)) else: args.append(g) return Mul(*args) integrals, others, piecewises = [], [], [] for f in Add.make_args(antideriv): if any(is_indef_int(g, x) for g in Mul.make_args(f)): integrals.append(f) elif any(isinstance(g, Piecewise) for g in Mul.make_args(f)): piecewises.append(piecewise_fold(f)) else: others.append(f) uneval = Add(*[eval_factored(f, x, a, b) for f in integrals]) try: evalued = Add(*others)._eval_interval(x, a, b) evalued_pw = piecewise_fold(Add(*piecewises))._eval_interval(x, a, b) function = uneval + evalued + evalued_pw except NotImplementedError: # This can happen if _eval_interval depends in a # complicated way on limits that cannot be computed undone_limits.append(xab) function = self.func(*([function] + [xab])) factored_function = function.factor() if not isinstance(factored_function, Integral): function = factored_function return function def _eval_derivative(self, sym): """Evaluate the derivative of the current Integral object by differentiating under the integral sign [1], using the Fundamental Theorem of Calculus [2] when possible. Explanation =========== Whenever an Integral is encountered that is equivalent to zero or has an integrand that is independent of the variable of integration those integrals are performed. All others are returned as Integral instances which can be resolved with doit() (provided they are integrable). References ========== .. [1] https://en.wikipedia.org/wiki/Differentiation_under_the_integral_sign .. [2] https://en.wikipedia.org/wiki/Fundamental_theorem_of_calculus Examples ======== >>> from sympy import Integral >>> from sympy.abc import x, y >>> i = Integral(x + y, y, (y, 1, x)) >>> i.diff(x) Integral(x + y, (y, x)) + Integral(1, y, (y, 1, x)) >>> i.doit().diff(x) == i.diff(x).doit() True >>> i.diff(y) 0 The previous must be true since there is no y in the evaluated integral: >>> i.free_symbols {x} >>> i.doit() 2*x**3/3 - x/2 - 1/6 """ # differentiate under the integral sign; we do not # check for regularity conditions (TODO), see issue 4215 # get limits and the function f, limits = self.function, list(self.limits) # the order matters if variables of integration appear in the limits # so work our way in from the outside to the inside. limit = limits.pop(-1) if len(limit) == 3: x, a, b = limit elif len(limit) == 2: x, b = limit a = None else: a = b = None x = limit[0] if limits: # f is the argument to an integral f = self.func(f, *tuple(limits)) # assemble the pieces def _do(f, ab): dab_dsym = diff(ab, sym) if not dab_dsym: return S.Zero if isinstance(f, Integral): limits = [(x, x) if (len(l) == 1 and l[0] == x) else l for l in f.limits] f = self.func(f.function, *limits) return f.subs(x, ab)*dab_dsym rv = S.Zero if b is not None: rv += _do(f, b) if a is not None: rv -= _do(f, a) if len(limit) == 1 and sym == x: # the dummy variable *is* also the real-world variable arg = f rv += arg else: # the dummy variable might match sym but it's # only a dummy and the actual variable is determined # by the limits, so mask off the variable of integration # while differentiating u = Dummy('u') arg = f.subs(x, u).diff(sym).subs(u, x) if arg: rv += self.func(arg, Tuple(x, a, b)) return rv def _eval_integral(self, f, x, meijerg=None, risch=None, manual=None, heurisch=None, conds='piecewise',final=None): """ Calculate the anti-derivative to the function f(x). Explanation =========== The following algorithms are applied (roughly in this order): 1. Simple heuristics (based on pattern matching and integral table): - most frequently used functions (e.g. polynomials, products of trig functions) 2. Integration of rational functions: - A complete algorithm for integrating rational functions is implemented (the Lazard-Rioboo-Trager algorithm). The algorithm also uses the partial fraction decomposition algorithm implemented in apart() as a preprocessor to make this process faster. Note that the integral of a rational function is always elementary, but in general, it may include a RootSum. 3. Full Risch algorithm: - The Risch algorithm is a complete decision procedure for integrating elementary functions, which means that given any elementary function, it will either compute an elementary antiderivative, or else prove that none exists. Currently, part of transcendental case is implemented, meaning elementary integrals containing exponentials, logarithms, and (soon!) trigonometric functions can be computed. The algebraic case, e.g., functions containing roots, is much more difficult and is not implemented yet. - If the routine fails (because the integrand is not elementary, or because a case is not implemented yet), it continues on to the next algorithms below. If the routine proves that the integrals is nonelementary, it still moves on to the algorithms below, because we might be able to find a closed-form solution in terms of special functions. If risch=True, however, it will stop here. 4. The Meijer G-Function algorithm: - This algorithm works by first rewriting the integrand in terms of very general Meijer G-Function (meijerg in SymPy), integrating it, and then rewriting the result back, if possible. This algorithm is particularly powerful for definite integrals (which is actually part of a different method of Integral), since it can compute closed-form solutions of definite integrals even when no closed-form indefinite integral exists. But it also is capable of computing many indefinite integrals as well. - Another advantage of this method is that it can use some results about the Meijer G-Function to give a result in terms of a Piecewise expression, which allows to express conditionally convergent integrals. - Setting meijerg=True will cause integrate() to use only this method. 5. The "manual integration" algorithm: - This algorithm tries to mimic how a person would find an antiderivative by hand, for example by looking for a substitution or applying integration by parts. This algorithm does not handle as many integrands but can return results in a more familiar form. - Sometimes this algorithm can evaluate parts of an integral; in this case integrate() will try to evaluate the rest of the integrand using the other methods here. - Setting manual=True will cause integrate() to use only this method. 6. The Heuristic Risch algorithm: - This is a heuristic version of the Risch algorithm, meaning that it is not deterministic. This is tried as a last resort because it can be very slow. It is still used because not enough of the full Risch algorithm is implemented, so that there are still some integrals that can only be computed using this method. The goal is to implement enough of the Risch and Meijer G-function methods so that this can be deleted. Setting heurisch=True will cause integrate() to use only this method. Set heurisch=False to not use it. """ from sympy.integrals.deltafunctions import deltaintegrate from sympy.integrals.singularityfunctions import singularityintegrate from sympy.integrals.heurisch import heurisch as heurisch_, heurisch_wrapper from sympy.integrals.rationaltools import ratint from sympy.integrals.risch import risch_integrate if risch: try: return risch_integrate(f, x, conds=conds) except NotImplementedError: return None if manual: try: result = manualintegrate(f, x) if result is not None and result.func != Integral: return result except (ValueError, PolynomialError): pass eval_kwargs = dict(meijerg=meijerg, risch=risch, manual=manual, heurisch=heurisch, conds=conds) # if it is a poly(x) then let the polynomial integrate itself (fast) # # It is important to make this check first, otherwise the other code # will return a sympy expression instead of a Polynomial. # # see Polynomial for details. if isinstance(f, Poly) and not (manual or meijerg or risch): SymPyDeprecationWarning( feature="Using integrate/Integral with Poly", issue=18613, deprecated_since_version="1.6", useinstead="the as_expr or integrate methods of Poly").warn() return f.integrate(x) # Piecewise antiderivatives need to call special integrate. if isinstance(f, Piecewise): return f.piecewise_integrate(x, **eval_kwargs) # let's cut it short if `f` does not depend on `x`; if # x is only a dummy, that will be handled below if not f.has(x): return f*x # try to convert to poly(x) and then integrate if successful (fast) poly = f.as_poly(x) if poly is not None and not (manual or meijerg or risch): return poly.integrate().as_expr() if risch is not False: try: result, i = risch_integrate(f, x, separate_integral=True, conds=conds) except NotImplementedError: pass else: if i: # There was a nonelementary integral. Try integrating it. # if no part of the NonElementaryIntegral is integrated by # the Risch algorithm, then use the original function to # integrate, instead of re-written one if result == 0: from sympy.integrals.risch import NonElementaryIntegral return NonElementaryIntegral(f, x).doit(risch=False) else: return result + i.doit(risch=False) else: return result # since Integral(f=g1+g2+...) == Integral(g1) + Integral(g2) + ... # we are going to handle Add terms separately, # if `f` is not Add -- we only have one term # Note that in general, this is a bad idea, because Integral(g1) + # Integral(g2) might not be computable, even if Integral(g1 + g2) is. # For example, Integral(x**x + x**x*log(x)). But many heuristics only # work term-wise. So we compute this step last, after trying # risch_integrate. We also try risch_integrate again in this loop, # because maybe the integral is a sum of an elementary part and a # nonelementary part (like erf(x) + exp(x)). risch_integrate() is # quite fast, so this is acceptable. parts = [] args = Add.make_args(f) for g in args: coeff, g = g.as_independent(x) # g(x) = const if g is S.One and not meijerg: parts.append(coeff*x) continue # g(x) = expr + O(x**n) order_term = g.getO() if order_term is not None: h = self._eval_integral(g.removeO(), x, **eval_kwargs) if h is not None: h_order_expr = self._eval_integral(order_term.expr, x, **eval_kwargs) if h_order_expr is not None: h_order_term = order_term.func( h_order_expr, *order_term.variables) parts.append(coeff*(h + h_order_term)) continue # NOTE: if there is O(x**n) and we fail to integrate then # there is no point in trying other methods because they # will fail, too. return None # c # g(x) = (a*x+b) if g.is_Pow and not g.exp.has(x) and not meijerg: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) M = g.base.match(a*x + b) if M is not None: if g.exp == -1: h = log(g.base) elif conds != 'piecewise': h = g.base**(g.exp + 1) / (g.exp + 1) else: h1 = log(g.base) h2 = g.base**(g.exp + 1) / (g.exp + 1) h = Piecewise((h2, Ne(g.exp, -1)), (h1, True)) parts.append(coeff * h / M[a]) continue # poly(x) # g(x) = ------- # poly(x) if g.is_rational_function(x) and not (manual or meijerg or risch): parts.append(coeff * ratint(g, x)) continue if not (manual or meijerg or risch): # g(x) = Mul(trig) h = trigintegrate(g, x, conds=conds) if h is not None: parts.append(coeff * h) continue # g(x) has at least a DiracDelta term h = deltaintegrate(g, x) if h is not None: parts.append(coeff * h) continue # g(x) has at least a Singularity Function term h = singularityintegrate(g, x) if h is not None: parts.append(coeff * h) continue # Try risch again. if risch is not False: try: h, i = risch_integrate(g, x, separate_integral=True, conds=conds) except NotImplementedError: h = None else: if i: h = h + i.doit(risch=False) parts.append(coeff*h) continue # fall back to heurisch if heurisch is not False: try: if conds == 'piecewise': h = heurisch_wrapper(g, x, hints=[]) else: h = heurisch_(g, x, hints=[]) except PolynomialError: # XXX: this exception means there is a bug in the # implementation of heuristic Risch integration # algorithm. h = None else: h = None if meijerg is not False and h is None: # rewrite using G functions try: h = meijerint_indefinite(g, x) except NotImplementedError: from sympy.integrals.meijerint import _debug _debug('NotImplementedError from meijerint_definite') if h is not None: parts.append(coeff * h) continue if h is None and manual is not False: try: result = manualintegrate(g, x) if result is not None and not isinstance(result, Integral): if result.has(Integral) and not manual: # Try to have other algorithms do the integrals # manualintegrate can't handle, # unless we were asked to use manual only. # Keep the rest of eval_kwargs in case another # method was set to False already new_eval_kwargs = eval_kwargs new_eval_kwargs["manual"] = False new_eval_kwargs["final"] = False result = result.func(*[ arg.doit(**new_eval_kwargs) if arg.has(Integral) else arg for arg in result.args ]).expand(multinomial=False, log=False, power_exp=False, power_base=False) if not result.has(Integral): parts.append(coeff * result) continue except (ValueError, PolynomialError): # can't handle some SymPy expressions pass # if we failed maybe it was because we had # a product that could have been expanded, # so let's try an expansion of the whole # thing before giving up; we don't try this # at the outset because there are things # that cannot be solved unless they are # NOT expanded e.g., x**x*(1+log(x)). There # should probably be a checker somewhere in this # routine to look for such cases and try to do # collection on the expressions if they are already # in an expanded form if not h and len(args) == 1: f = sincos_to_sum(f).expand(mul=True, deep=False) if f.is_Add: # Note: risch will be identical on the expanded # expression, but maybe it will be able to pick out parts, # like x*(exp(x) + erf(x)). return self._eval_integral(f, x, **eval_kwargs) if h is not None: parts.append(coeff * h) else: return None return Add(*parts) def _eval_lseries(self, x, logx=None, cdir=0): expr = self.as_dummy() symb = x for l in expr.limits: if x in l[1:]: symb = l[0] break for term in expr.function.lseries(symb, logx): yield integrate(term, *expr.limits) def _eval_nseries(self, x, n, logx=None, cdir=0): expr = self.as_dummy() symb = x for l in expr.limits: if x in l[1:]: symb = l[0] break terms, order = expr.function.nseries( x=symb, n=n, logx=logx).as_coeff_add(Order) order = [o.subs(symb, x) for o in order] return integrate(terms, *expr.limits) + Add(*order)*x def _eval_as_leading_term(self, x, logx=None, cdir=0): series_gen = self.args[0].lseries(x) for leading_term in series_gen: if leading_term != 0: break return integrate(leading_term, *self.args[1:]) def _eval_simplify(self, **kwargs): from sympy.core.exprtools import factor_terms from sympy.simplify.simplify import simplify expr = factor_terms(self) if isinstance(expr, Integral): return expr.func(*[simplify(i, **kwargs) for i in expr.args]) return expr.simplify(**kwargs) def as_sum(self, n=None, method="midpoint", evaluate=True): """ Approximates a definite integral by a sum. Parameters ========== n : The number of subintervals to use, optional. method : One of: 'left', 'right', 'midpoint', 'trapezoid'. evaluate : bool If False, returns an unevaluated Sum expression. The default is True, evaluate the sum. Notes ===== These methods of approximate integration are described in [1]. Examples ======== >>> from sympy import sin, sqrt >>> from sympy.abc import x, n >>> from sympy.integrals import Integral >>> e = Integral(sin(x), (x, 3, 7)) >>> e Integral(sin(x), (x, 3, 7)) For demonstration purposes, this interval will only be split into 2 regions, bounded by [3, 5] and [5, 7]. The left-hand rule uses function evaluations at the left of each interval: >>> e.as_sum(2, 'left') 2*sin(5) + 2*sin(3) The midpoint rule uses evaluations at the center of each interval: >>> e.as_sum(2, 'midpoint') 2*sin(4) + 2*sin(6) The right-hand rule uses function evaluations at the right of each interval: >>> e.as_sum(2, 'right') 2*sin(5) + 2*sin(7) The trapezoid rule uses function evaluations on both sides of the intervals. This is equivalent to taking the average of the left and right hand rule results: >>> e.as_sum(2, 'trapezoid') 2*sin(5) + sin(3) + sin(7) >>> (e.as_sum(2, 'left') + e.as_sum(2, 'right'))/2 == _ True Here, the discontinuity at x = 0 can be avoided by using the midpoint or right-hand method: >>> e = Integral(1/sqrt(x), (x, 0, 1)) >>> e.as_sum(5).n(4) 1.730 >>> e.as_sum(10).n(4) 1.809 >>> e.doit().n(4) # the actual value is 2 2.000 The left- or trapezoid method will encounter the discontinuity and return infinity: >>> e.as_sum(5, 'left') zoo The number of intervals can be symbolic. If omitted, a dummy symbol will be used for it. >>> e = Integral(x**2, (x, 0, 2)) >>> e.as_sum(n, 'right').expand() 8/3 + 4/n + 4/(3*n**2) This shows that the midpoint rule is more accurate, as its error term decays as the square of n: >>> e.as_sum(method='midpoint').expand() 8/3 - 2/(3*_n**2) A symbolic sum is returned with evaluate=False: >>> e.as_sum(n, 'midpoint', evaluate=False) 2*Sum((2*_k/n - 1/n)**2, (_k, 1, n))/n See Also ======== Integral.doit : Perform the integration using any hints References ========== .. [1] https://en.wikipedia.org/wiki/Riemann_sum#Methods """ from sympy.concrete.summations import Sum limits = self.limits if len(limits) > 1: raise NotImplementedError( "Multidimensional midpoint rule not implemented yet") else: limit = limits[0] if (len(limit) != 3 or limit[1].is_finite is False or limit[2].is_finite is False): raise ValueError("Expecting a definite integral over " "a finite interval.") if n is None: n = Dummy('n', integer=True, positive=True) else: n = sympify(n) if (n.is_positive is False or n.is_integer is False or n.is_finite is False): raise ValueError("n must be a positive integer, got %s" % n) x, a, b = limit dx = (b - a)/n k = Dummy('k', integer=True, positive=True) f = self.function if method == "left": result = dx*Sum(f.subs(x, a + (k-1)*dx), (k, 1, n)) elif method == "right": result = dx*Sum(f.subs(x, a + k*dx), (k, 1, n)) elif method == "midpoint": result = dx*Sum(f.subs(x, a + k*dx - dx/2), (k, 1, n)) elif method == "trapezoid": result = dx*((f.subs(x, a) + f.subs(x, b))/2 + Sum(f.subs(x, a + k*dx), (k, 1, n - 1))) else: raise ValueError("Unknown method %s" % method) return result.doit() if evaluate else result def principal_value(self, **kwargs): """ Compute the Cauchy Principal Value of the definite integral of a real function in the given interval on the real axis. Explanation =========== In mathematics, the Cauchy principal value, is a method for assigning values to certain improper integrals which would otherwise be undefined. Examples ======== >>> from sympy import oo >>> from sympy.integrals.integrals import Integral >>> from sympy.abc import x >>> Integral(x+1, (x, -oo, oo)).principal_value() oo >>> f = 1 / (x**3) >>> Integral(f, (x, -oo, oo)).principal_value() 0 >>> Integral(f, (x, -10, 10)).principal_value() 0 >>> Integral(f, (x, -10, oo)).principal_value() + Integral(f, (x, -oo, 10)).principal_value() 0 References ========== .. [1] https://en.wikipedia.org/wiki/Cauchy_principal_value .. [2] http://mathworld.wolfram.com/CauchyPrincipalValue.html """ from sympy.calculus import singularities if len(self.limits) != 1 or len(list(self.limits[0])) != 3: raise ValueError("You need to insert a variable, lower_limit, and upper_limit correctly to calculate " "cauchy's principal value") x, a, b = self.limits[0] if not (a.is_comparable and b.is_comparable and a <= b): raise ValueError("The lower_limit must be smaller than or equal to the upper_limit to calculate " "cauchy's principal value. Also, a and b need to be comparable.") if a == b: return 0 r = Dummy('r') f = self.function singularities_list = [s for s in singularities(f, x) if s.is_comparable and a <= s <= b] for i in singularities_list: if (i == b) or (i == a): raise ValueError( 'The principal value is not defined in the given interval due to singularity at %d.' % (i)) F = integrate(f, x, **kwargs) if F.has(Integral): return self if a is -oo and b is oo: I = limit(F - F.subs(x, -x), x, oo) else: I = limit(F, x, b, '-') - limit(F, x, a, '+') for s in singularities_list: I += limit(((F.subs(x, s - r)) - F.subs(x, s + r)), r, 0, '+') return I def integrate(*args, meijerg=None, conds='piecewise', risch=None, heurisch=None, manual=None, **kwargs): """integrate(f, var, ...) Explanation =========== Compute definite or indefinite integral of one or more variables using Risch-Norman algorithm and table lookup. This procedure is able to handle elementary algebraic and transcendental functions and also a huge class of special functions, including Airy, Bessel, Whittaker and Lambert. var can be: - a symbol -- indefinite integration - a tuple (symbol, a) -- indefinite integration with result given with `a` replacing `symbol` - a tuple (symbol, a, b) -- definite integration Several variables can be specified, in which case the result is multiple integration. (If var is omitted and the integrand is univariate, the indefinite integral in that variable will be performed.) Indefinite integrals are returned without terms that are independent of the integration variables. (see examples) Definite improper integrals often entail delicate convergence conditions. Pass conds='piecewise', 'separate' or 'none' to have these returned, respectively, as a Piecewise function, as a separate result (i.e. result will be a tuple), or not at all (default is 'piecewise'). **Strategy** SymPy uses various approaches to definite integration. One method is to find an antiderivative for the integrand, and then use the fundamental theorem of calculus. Various functions are implemented to integrate polynomial, rational and trigonometric functions, and integrands containing DiracDelta terms. SymPy also implements the part of the Risch algorithm, which is a decision procedure for integrating elementary functions, i.e., the algorithm can either find an elementary antiderivative, or prove that one does not exist. There is also a (very successful, albeit somewhat slow) general implementation of the heuristic Risch algorithm. This algorithm will eventually be phased out as more of the full Risch algorithm is implemented. See the docstring of Integral._eval_integral() for more details on computing the antiderivative using algebraic methods. The option risch=True can be used to use only the (full) Risch algorithm. This is useful if you want to know if an elementary function has an elementary antiderivative. If the indefinite Integral returned by this function is an instance of NonElementaryIntegral, that means that the Risch algorithm has proven that integral to be non-elementary. Note that by default, additional methods (such as the Meijer G method outlined below) are tried on these integrals, as they may be expressible in terms of special functions, so if you only care about elementary answers, use risch=True. Also note that an unevaluated Integral returned by this function is not necessarily a NonElementaryIntegral, even with risch=True, as it may just be an indication that the particular part of the Risch algorithm needed to integrate that function is not yet implemented. Another family of strategies comes from re-writing the integrand in terms of so-called Meijer G-functions. Indefinite integrals of a single G-function can always be computed, and the definite integral of a product of two G-functions can be computed from zero to infinity. Various strategies are implemented to rewrite integrands as G-functions, and use this information to compute integrals (see the ``meijerint`` module). The option manual=True can be used to use only an algorithm that tries to mimic integration by hand. This algorithm does not handle as many integrands as the other algorithms implemented but may return results in a more familiar form. The ``manualintegrate`` module has functions that return the steps used (see the module docstring for more information). In general, the algebraic methods work best for computing antiderivatives of (possibly complicated) combinations of elementary functions. The G-function methods work best for computing definite integrals from zero to infinity of moderately complicated combinations of special functions, or indefinite integrals of very simple combinations of special functions. The strategy employed by the integration code is as follows: - If computing a definite integral, and both limits are real, and at least one limit is +- oo, try the G-function method of definite integration first. - Try to find an antiderivative, using all available methods, ordered by performance (that is try fastest method first, slowest last; in particular polynomial integration is tried first, Meijer G-functions second to last, and heuristic Risch last). - If still not successful, try G-functions irrespective of the limits. The option meijerg=True, False, None can be used to, respectively: always use G-function methods and no others, never use G-function methods, or use all available methods (in order as described above). It defaults to None. Examples ======== >>> from sympy import integrate, log, exp, oo >>> from sympy.abc import a, x, y >>> integrate(x*y, x) x**2*y/2 >>> integrate(log(x), x) x*log(x) - x >>> integrate(log(x), (x, 1, a)) a*log(a) - a + 1 >>> integrate(x) x**2/2 Terms that are independent of x are dropped by indefinite integration: >>> from sympy import sqrt >>> integrate(sqrt(1 + x), (x, 0, x)) 2*(x + 1)**(3/2)/3 - 2/3 >>> integrate(sqrt(1 + x), x) 2*(x + 1)**(3/2)/3 >>> integrate(x*y) Traceback (most recent call last): ... ValueError: specify integration variables to integrate x*y Note that ``integrate(x)`` syntax is meant only for convenience in interactive sessions and should be avoided in library code. >>> integrate(x**a*exp(-x), (x, 0, oo)) # same as conds='piecewise' Piecewise((gamma(a + 1), re(a) > -1), (Integral(x**a*exp(-x), (x, 0, oo)), True)) >>> integrate(x**a*exp(-x), (x, 0, oo), conds='none') gamma(a + 1) >>> integrate(x**a*exp(-x), (x, 0, oo), conds='separate') (gamma(a + 1), -re(a) < 1) See Also ======== Integral, Integral.doit """ doit_flags = { 'deep': False, 'meijerg': meijerg, 'conds': conds, 'risch': risch, 'heurisch': heurisch, 'manual': manual } integral = Integral(*args, **kwargs) if isinstance(integral, Integral): return integral.doit(**doit_flags) else: new_args = [a.doit(**doit_flags) if isinstance(a, Integral) else a for a in integral.args] return integral.func(*new_args) def line_integrate(field, curve, vars): """line_integrate(field, Curve, variables) Compute the line integral. Examples ======== >>> from sympy import Curve, line_integrate, E, ln >>> from sympy.abc import x, y, t >>> C = Curve([E**t + 1, E**t - 1], (t, 0, ln(2))) >>> line_integrate(x + y, C, [x, y]) 3*sqrt(2) See Also ======== sympy.integrals.integrals.integrate, Integral """ from sympy.geometry import Curve F = sympify(field) if not F: raise ValueError( "Expecting function specifying field as first argument.") if not isinstance(curve, Curve): raise ValueError("Expecting Curve entity as second argument.") if not is_sequence(vars): raise ValueError("Expecting ordered iterable for variables.") if len(curve.functions) != len(vars): raise ValueError("Field variable size does not match curve dimension.") if curve.parameter in vars: raise ValueError("Curve parameter clashes with field parameters.") # Calculate derivatives for line parameter functions # F(r) -> F(r(t)) and finally F(r(t)*r'(t)) Ft = F dldt = 0 for i, var in enumerate(vars): _f = curve.functions[i] _dn = diff(_f, curve.parameter) # ...arc length dldt = dldt + (_dn * _dn) Ft = Ft.subs(var, _f) Ft = Ft * sqrt(dldt) integral = Integral(Ft, curve.limits).doit(deep=False) return integral ### Property function dispatching ### @shape.register(Integral) def _(expr): return shape(expr.function) sympy-sympy-1.9/sympy/integrals/intpoly.py000066400000000000000000001243251412543434000211530ustar00rootroot00000000000000""" Module to implement integration of uni/bivariate polynomials over 2D Polytopes and uni/bi/trivariate polynomials over 3D Polytopes. Uses evaluation techniques as described in Chin et al. (2015) [1]. References =========== .. [1] Chin, Eric B., Jean B. Lasserre, and N. Sukumar. "Numerical integration of homogeneous functions on convex and nonconvex polygons and polyhedra." Computational Mechanics 56.6 (2015): 967-981 PDF link : http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf """ from functools import cmp_to_key from sympy.abc import x, y, z from sympy.core import S, diff, Expr, Symbol from sympy.core.sympify import _sympify from sympy.geometry import Segment2D, Polygon, Point, Point2D from sympy.polys.polytools import LC, gcd_list, degree_list from sympy.simplify.simplify import nsimplify def polytope_integrate(poly, expr=None, *, clockwise=False, max_degree=None): """Integrates polynomials over 2/3-Polytopes. Explanation =========== This function accepts the polytope in ``poly`` and the function in ``expr`` (uni/bi/trivariate polynomials are implemented) and returns the exact integral of ``expr`` over ``poly``. Parameters ========== poly : The input Polygon. expr : The input polynomial. clockwise : Binary value to sort input points of 2-Polytope clockwise.(Optional) max_degree : The maximum degree of any monomial of the input polynomial.(Optional) Examples ======== >>> from sympy.abc import x, y >>> from sympy.geometry.polygon import Polygon >>> from sympy.geometry.point import Point >>> from sympy.integrals.intpoly import polytope_integrate >>> polygon = Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)) >>> polys = [1, x, y, x*y, x**2*y, x*y**2] >>> expr = x*y >>> polytope_integrate(polygon, expr) 1/4 >>> polytope_integrate(polygon, polys, max_degree=3) {1: 1, x: 1/2, y: 1/2, x*y: 1/4, x*y**2: 1/6, x**2*y: 1/6} """ if clockwise: if isinstance(poly, Polygon): poly = Polygon(*point_sort(poly.vertices), evaluate=False) else: raise TypeError("clockwise=True works for only 2-Polytope" "V-representation input") if isinstance(poly, Polygon): # For Vertex Representation(2D case) hp_params = hyperplane_parameters(poly) facets = poly.sides elif len(poly[0]) == 2: # For Hyperplane Representation(2D case) plen = len(poly) if len(poly[0][0]) == 2: intersections = [intersection(poly[(i - 1) % plen], poly[i], "plane2D") for i in range(0, plen)] hp_params = poly lints = len(intersections) facets = [Segment2D(intersections[i], intersections[(i + 1) % lints]) for i in range(0, lints)] else: raise NotImplementedError("Integration for H-representation 3D" "case not implemented yet.") else: # For Vertex Representation(3D case) vertices = poly[0] facets = poly[1:] hp_params = hyperplane_parameters(facets, vertices) if max_degree is None: if expr is None: raise TypeError('Input expression be must' 'be a valid SymPy expression') return main_integrate3d(expr, facets, vertices, hp_params) if max_degree is not None: result = {} if not isinstance(expr, list) and expr is not None: raise TypeError('Input polynomials must be list of expressions') if len(hp_params[0][0]) == 3: result_dict = main_integrate3d(0, facets, vertices, hp_params, max_degree) else: result_dict = main_integrate(0, facets, hp_params, max_degree) if expr is None: return result_dict for poly in expr: poly = _sympify(poly) if poly not in result: if poly.is_zero: result[S.Zero] = S.Zero continue integral_value = S.Zero monoms = decompose(poly, separate=True) for monom in monoms: monom = nsimplify(monom) coeff, m = strip(monom) integral_value += result_dict[m] * coeff result[poly] = integral_value return result if expr is None: raise TypeError('Input expression be must' 'be a valid SymPy expression') return main_integrate(expr, facets, hp_params) def strip(monom): if monom.is_zero: return 0, 0 elif monom.is_number: return monom, 1 else: coeff = LC(monom) return coeff, S(monom) / coeff def main_integrate3d(expr, facets, vertices, hp_params, max_degree=None): """Function to translate the problem of integrating uni/bi/tri-variate polynomials over a 3-Polytope to integrating over its faces. This is done using Generalized Stokes' Theorem and Euler's Theorem. Parameters ========== expr : The input polynomial. facets : Faces of the 3-Polytope(expressed as indices of `vertices`). vertices : Vertices that constitute the Polytope. hp_params : Hyperplane Parameters of the facets. max_degree : optional Max degree of constituent monomial in given list of polynomial. Examples ======== >>> from sympy.integrals.intpoly import main_integrate3d, \ hyperplane_parameters >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ [3, 1, 0, 2], [0, 4, 6, 2]] >>> vertices = cube[0] >>> faces = cube[1:] >>> hp_params = hyperplane_parameters(faces, vertices) >>> main_integrate3d(1, faces, vertices, hp_params) -125 """ result = {} dims = (x, y, z) dim_length = len(dims) if max_degree: grad_terms = gradient_terms(max_degree, 3) flat_list = [term for z_terms in grad_terms for x_term in z_terms for term in x_term] for term in flat_list: result[term[0]] = 0 for facet_count, hp in enumerate(hp_params): a, b = hp[0], hp[1] x0 = vertices[facets[facet_count][0]] for i, monom in enumerate(flat_list): # Every monomial is a tuple : # (term, x_degree, y_degree, z_degree, value over boundary) expr, x_d, y_d, z_d, z_index, y_index, x_index, _ = monom degree = x_d + y_d + z_d if b.is_zero: value_over_face = S.Zero else: value_over_face = \ integration_reduction_dynamic(facets, facet_count, a, b, expr, degree, dims, x_index, y_index, z_index, x0, grad_terms, i, vertices, hp) monom[7] = value_over_face result[expr] += value_over_face * \ (b / norm(a)) / (dim_length + x_d + y_d + z_d) return result else: integral_value = S.Zero polynomials = decompose(expr) for deg in polynomials: poly_contribute = S.Zero facet_count = 0 for i, facet in enumerate(facets): hp = hp_params[i] if hp[1].is_zero: continue pi = polygon_integrate(facet, hp, i, facets, vertices, expr, deg) poly_contribute += pi *\ (hp[1] / norm(tuple(hp[0]))) facet_count += 1 poly_contribute /= (dim_length + deg) integral_value += poly_contribute return integral_value def main_integrate(expr, facets, hp_params, max_degree=None): """Function to translate the problem of integrating univariate/bivariate polynomials over a 2-Polytope to integrating over its boundary facets. This is done using Generalized Stokes's Theorem and Euler's Theorem. Parameters ========== expr : The input polynomial. facets : Facets(Line Segments) of the 2-Polytope. hp_params : Hyperplane Parameters of the facets. max_degree : optional The maximum degree of any monomial of the input polynomial. >>> from sympy.abc import x, y >>> from sympy.integrals.intpoly import main_integrate,\ hyperplane_parameters >>> from sympy.geometry.polygon import Polygon >>> from sympy.geometry.point import Point >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) >>> facets = triangle.sides >>> hp_params = hyperplane_parameters(triangle) >>> main_integrate(x**2 + y**2, facets, hp_params) 325/6 """ dims = (x, y) dim_length = len(dims) result = {} integral_value = S.Zero if max_degree: grad_terms = [[0, 0, 0, 0]] + gradient_terms(max_degree) for facet_count, hp in enumerate(hp_params): a, b = hp[0], hp[1] x0 = facets[facet_count].points[0] for i, monom in enumerate(grad_terms): # Every monomial is a tuple : # (term, x_degree, y_degree, value over boundary) m, x_d, y_d, _ = monom value = result.get(m, None) degree = S.Zero if b.is_zero: value_over_boundary = S.Zero else: degree = x_d + y_d value_over_boundary = \ integration_reduction_dynamic(facets, facet_count, a, b, m, degree, dims, x_d, y_d, max_degree, x0, grad_terms, i) monom[3] = value_over_boundary if value is not None: result[m] += value_over_boundary * \ (b / norm(a)) / (dim_length + degree) else: result[m] = value_over_boundary * \ (b / norm(a)) / (dim_length + degree) return result else: polynomials = decompose(expr) for deg in polynomials: poly_contribute = S.Zero facet_count = 0 for hp in hp_params: value_over_boundary = integration_reduction(facets, facet_count, hp[0], hp[1], polynomials[deg], dims, deg) poly_contribute += value_over_boundary * (hp[1] / norm(hp[0])) facet_count += 1 poly_contribute /= (dim_length + deg) integral_value += poly_contribute return integral_value def polygon_integrate(facet, hp_param, index, facets, vertices, expr, degree): """Helper function to integrate the input uni/bi/trivariate polynomial over a certain face of the 3-Polytope. Parameters ========== facet : Particular face of the 3-Polytope over which ``expr`` is integrated. index : The index of ``facet`` in ``facets``. facets : Faces of the 3-Polytope(expressed as indices of `vertices`). vertices : Vertices that constitute the facet. expr : The input polynomial. degree : Degree of ``expr``. Examples ======== >>> from sympy.integrals.intpoly import polygon_integrate >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ [3, 1, 0, 2], [0, 4, 6, 2]] >>> facet = cube[1] >>> facets = cube[1:] >>> vertices = cube[0] >>> polygon_integrate(facet, [(0, 1, 0), 5], 0, facets, vertices, 1, 0) -25 """ expr = S(expr) if expr.is_zero: return S.Zero result = S.Zero x0 = vertices[facet[0]] for i in range(len(facet)): side = (vertices[facet[i]], vertices[facet[(i + 1) % len(facet)]]) result += distance_to_side(x0, side, hp_param[0]) *\ lineseg_integrate(facet, i, side, expr, degree) if not expr.is_number: expr = diff(expr, x) * x0[0] + diff(expr, y) * x0[1] +\ diff(expr, z) * x0[2] result += polygon_integrate(facet, hp_param, index, facets, vertices, expr, degree - 1) result /= (degree + 2) return result def distance_to_side(point, line_seg, A): """Helper function to compute the signed distance between given 3D point and a line segment. Parameters ========== point : 3D Point line_seg : Line Segment Examples ======== >>> from sympy.integrals.intpoly import distance_to_side >>> point = (0, 0, 0) >>> distance_to_side(point, [(0, 0, 1), (0, 1, 0)], (1, 0, 0)) -sqrt(2)/2 """ x1, x2 = line_seg rev_normal = [-1 * S(i)/norm(A) for i in A] vector = [x2[i] - x1[i] for i in range(0, 3)] vector = [vector[i]/norm(vector) for i in range(0, 3)] n_side = cross_product((0, 0, 0), rev_normal, vector) vectorx0 = [line_seg[0][i] - point[i] for i in range(0, 3)] dot_product = sum([vectorx0[i] * n_side[i] for i in range(0, 3)]) return dot_product def lineseg_integrate(polygon, index, line_seg, expr, degree): """Helper function to compute the line integral of ``expr`` over ``line_seg``. Parameters =========== polygon : Face of a 3-Polytope. index : Index of line_seg in polygon. line_seg : Line Segment. Examples ======== >>> from sympy.integrals.intpoly import lineseg_integrate >>> polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)] >>> line_seg = [(0, 5, 0), (5, 5, 0)] >>> lineseg_integrate(polygon, 0, line_seg, 1, 0) 5 """ expr = _sympify(expr) if expr.is_zero: return S.Zero result = S.Zero x0 = line_seg[0] distance = norm(tuple([line_seg[1][i] - line_seg[0][i] for i in range(3)])) if isinstance(expr, Expr): expr_dict = {x: line_seg[1][0], y: line_seg[1][1], z: line_seg[1][2]} result += distance * expr.subs(expr_dict) else: result += distance * expr expr = diff(expr, x) * x0[0] + diff(expr, y) * x0[1] +\ diff(expr, z) * x0[2] result += lineseg_integrate(polygon, index, line_seg, expr, degree - 1) result /= (degree + 1) return result def integration_reduction(facets, index, a, b, expr, dims, degree): """Helper method for main_integrate. Returns the value of the input expression evaluated over the polytope facet referenced by a given index. Parameters =========== facets : List of facets of the polytope. index : Index referencing the facet to integrate the expression over. a : Hyperplane parameter denoting direction. b : Hyperplane parameter denoting distance. expr : The expression to integrate over the facet. dims : List of symbols denoting axes. degree : Degree of the homogeneous polynomial. Examples ======== >>> from sympy.abc import x, y >>> from sympy.integrals.intpoly import integration_reduction,\ hyperplane_parameters >>> from sympy.geometry.point import Point >>> from sympy.geometry.polygon import Polygon >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) >>> facets = triangle.sides >>> a, b = hyperplane_parameters(triangle)[0] >>> integration_reduction(facets, 0, a, b, 1, (x, y), 0) 5 """ expr = _sympify(expr) if expr.is_zero: return expr value = S.Zero x0 = facets[index].points[0] m = len(facets) gens = (x, y) inner_product = diff(expr, gens[0]) * x0[0] + diff(expr, gens[1]) * x0[1] if inner_product != 0: value += integration_reduction(facets, index, a, b, inner_product, dims, degree - 1) value += left_integral2D(m, index, facets, x0, expr, gens) return value/(len(dims) + degree - 1) def left_integral2D(m, index, facets, x0, expr, gens): """Computes the left integral of Eq 10 in Chin et al. For the 2D case, the integral is just an evaluation of the polynomial at the intersection of two facets which is multiplied by the distance between the first point of facet and that intersection. Parameters ========== m : No. of hyperplanes. index : Index of facet to find intersections with. facets : List of facets(Line Segments in 2D case). x0 : First point on facet referenced by index. expr : Input polynomial gens : Generators which generate the polynomial Examples ======== >>> from sympy.abc import x, y >>> from sympy.integrals.intpoly import left_integral2D >>> from sympy.geometry.point import Point >>> from sympy.geometry.polygon import Polygon >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) >>> facets = triangle.sides >>> left_integral2D(3, 0, facets, facets[0].points[0], 1, (x, y)) 5 """ value = S.Zero for j in range(0, m): intersect = () if j == (index - 1) % m or j == (index + 1) % m: intersect = intersection(facets[index], facets[j], "segment2D") if intersect: distance_origin = norm(tuple(map(lambda x, y: x - y, intersect, x0))) if is_vertex(intersect): if isinstance(expr, Expr): if len(gens) == 3: expr_dict = {gens[0]: intersect[0], gens[1]: intersect[1], gens[2]: intersect[2]} else: expr_dict = {gens[0]: intersect[0], gens[1]: intersect[1]} value += distance_origin * expr.subs(expr_dict) else: value += distance_origin * expr return value def integration_reduction_dynamic(facets, index, a, b, expr, degree, dims, x_index, y_index, max_index, x0, monomial_values, monom_index, vertices=None, hp_param=None): """The same integration_reduction function which uses a dynamic programming approach to compute terms by using the values of the integral of previously computed terms. Parameters ========== facets : Facets of the Polytope. index : Index of facet to find intersections with.(Used in left_integral()). a, b : Hyperplane parameters. expr : Input monomial. degree : Total degree of ``expr``. dims : Tuple denoting axes variables. x_index : Exponent of 'x' in ``expr``. y_index : Exponent of 'y' in ``expr``. max_index : Maximum exponent of any monomial in ``monomial_values``. x0 : First point on ``facets[index]``. monomial_values : List of monomial values constituting the polynomial. monom_index : Index of monomial whose integration is being found. vertices : optional Coordinates of vertices constituting the 3-Polytope. hp_param : optional Hyperplane Parameter of the face of the facets[index]. Examples ======== >>> from sympy.abc import x, y >>> from sympy.integrals.intpoly import (integration_reduction_dynamic, \ hyperplane_parameters) >>> from sympy.geometry.point import Point >>> from sympy.geometry.polygon import Polygon >>> triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) >>> facets = triangle.sides >>> a, b = hyperplane_parameters(triangle)[0] >>> x0 = facets[0].points[0] >>> monomial_values = [[0, 0, 0, 0], [1, 0, 0, 5],\ [y, 0, 1, 15], [x, 1, 0, None]] >>> integration_reduction_dynamic(facets, 0, a, b, x, 1, (x, y), 1, 0, 1,\ x0, monomial_values, 3) 25/2 """ value = S.Zero m = len(facets) if expr == S.Zero: return expr if len(dims) == 2: if not expr.is_number: _, x_degree, y_degree, _ = monomial_values[monom_index] x_index = monom_index - max_index + \ x_index - 2 if x_degree > 0 else 0 y_index = monom_index - 1 if y_degree > 0 else 0 x_value, y_value =\ monomial_values[x_index][3], monomial_values[y_index][3] value += x_degree * x_value * x0[0] + y_degree * y_value * x0[1] value += left_integral2D(m, index, facets, x0, expr, dims) else: # For 3D use case the max_index contains the z_degree of the term z_index = max_index if not expr.is_number: x_degree, y_degree, z_degree = y_index,\ z_index - x_index - y_index, x_index x_value = monomial_values[z_index - 1][y_index - 1][x_index][7]\ if x_degree > 0 else 0 y_value = monomial_values[z_index - 1][y_index][x_index][7]\ if y_degree > 0 else 0 z_value = monomial_values[z_index - 1][y_index][x_index - 1][7]\ if z_degree > 0 else 0 value += x_degree * x_value * x0[0] + y_degree * y_value * x0[1] \ + z_degree * z_value * x0[2] value += left_integral3D(facets, index, expr, vertices, hp_param, degree) return value / (len(dims) + degree - 1) def left_integral3D(facets, index, expr, vertices, hp_param, degree): """Computes the left integral of Eq 10 in Chin et al. Explanation =========== For the 3D case, this is the sum of the integral values over constituting line segments of the face (which is accessed by facets[index]) multiplied by the distance between the first point of facet and that line segment. Parameters ========== facets : List of faces of the 3-Polytope. index : Index of face over which integral is to be calculated. expr : Input polynomial. vertices : List of vertices that constitute the 3-Polytope. hp_param : The hyperplane parameters of the face. degree : Degree of the ``expr``. Examples ======== >>> from sympy.integrals.intpoly import left_integral3D >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ [3, 1, 0, 2], [0, 4, 6, 2]] >>> facets = cube[1:] >>> vertices = cube[0] >>> left_integral3D(facets, 3, 1, vertices, ([0, -1, 0], -5), 0) -50 """ value = S.Zero facet = facets[index] x0 = vertices[facet[0]] for i in range(len(facet)): side = (vertices[facet[i]], vertices[facet[(i + 1) % len(facet)]]) value += distance_to_side(x0, side, hp_param[0]) * \ lineseg_integrate(facet, i, side, expr, degree) return value def gradient_terms(binomial_power=0, no_of_gens=2): """Returns a list of all the possible monomials between 0 and y**binomial_power for 2D case and z**binomial_power for 3D case. Parameters ========== binomial_power : Power upto which terms are generated. no_of_gens : Denotes whether terms are being generated for 2D or 3D case. Examples ======== >>> from sympy.integrals.intpoly import gradient_terms >>> gradient_terms(2) [[1, 0, 0, 0], [y, 0, 1, 0], [y**2, 0, 2, 0], [x, 1, 0, 0], [x*y, 1, 1, 0], [x**2, 2, 0, 0]] >>> gradient_terms(2, 3) [[[[1, 0, 0, 0, 0, 0, 0, 0]]], [[[y, 0, 1, 0, 1, 0, 0, 0], [z, 0, 0, 1, 1, 0, 1, 0]], [[x, 1, 0, 0, 1, 1, 0, 0]]], [[[y**2, 0, 2, 0, 2, 0, 0, 0], [y*z, 0, 1, 1, 2, 0, 1, 0], [z**2, 0, 0, 2, 2, 0, 2, 0]], [[x*y, 1, 1, 0, 2, 1, 0, 0], [x*z, 1, 0, 1, 2, 1, 1, 0]], [[x**2, 2, 0, 0, 2, 2, 0, 0]]]] """ if no_of_gens == 2: count = 0 terms = [None] * int((binomial_power ** 2 + 3 * binomial_power + 2) / 2) for x_count in range(0, binomial_power + 1): for y_count in range(0, binomial_power - x_count + 1): terms[count] = [x**x_count*y**y_count, x_count, y_count, 0] count += 1 else: terms = [[[[x ** x_count * y ** y_count * z ** (z_count - y_count - x_count), x_count, y_count, z_count - y_count - x_count, z_count, x_count, z_count - y_count - x_count, 0] for y_count in range(z_count - x_count, -1, -1)] for x_count in range(0, z_count + 1)] for z_count in range(0, binomial_power + 1)] return terms def hyperplane_parameters(poly, vertices=None): """A helper function to return the hyperplane parameters of which the facets of the polytope are a part of. Parameters ========== poly : The input 2/3-Polytope. vertices : Vertex indices of 3-Polytope. Examples ======== >>> from sympy.geometry.point import Point >>> from sympy.geometry.polygon import Polygon >>> from sympy.integrals.intpoly import hyperplane_parameters >>> hyperplane_parameters(Polygon(Point(0, 3), Point(5, 3), Point(1, 1))) [((0, 1), 3), ((1, -2), -1), ((-2, -1), -3)] >>> cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ [3, 1, 0, 2], [0, 4, 6, 2]] >>> hyperplane_parameters(cube[1:], cube[0]) [([0, -1, 0], -5), ([0, 0, -1], -5), ([-1, 0, 0], -5), ([0, 1, 0], 0), ([1, 0, 0], 0), ([0, 0, 1], 0)] """ if isinstance(poly, Polygon): vertices = list(poly.vertices) + [poly.vertices[0]] # Close the polygon params = [None] * (len(vertices) - 1) for i in range(len(vertices) - 1): v1 = vertices[i] v2 = vertices[i + 1] a1 = v1[1] - v2[1] a2 = v2[0] - v1[0] b = v2[0] * v1[1] - v2[1] * v1[0] factor = gcd_list([a1, a2, b]) b = S(b) / factor a = (S(a1) / factor, S(a2) / factor) params[i] = (a, b) else: params = [None] * len(poly) for i, polygon in enumerate(poly): v1, v2, v3 = [vertices[vertex] for vertex in polygon[:3]] normal = cross_product(v1, v2, v3) b = sum([normal[j] * v1[j] for j in range(0, 3)]) fac = gcd_list(normal) if fac.is_zero: fac = 1 normal = [j / fac for j in normal] b = b / fac params[i] = (normal, b) return params def cross_product(v1, v2, v3): """Returns the cross-product of vectors (v2 - v1) and (v3 - v1) That is : (v2 - v1) X (v3 - v1) """ v2 = [v2[j] - v1[j] for j in range(0, 3)] v3 = [v3[j] - v1[j] for j in range(0, 3)] return [v3[2] * v2[1] - v3[1] * v2[2], v3[0] * v2[2] - v3[2] * v2[0], v3[1] * v2[0] - v3[0] * v2[1]] def best_origin(a, b, lineseg, expr): """Helper method for polytope_integrate. Currently not used in the main algorithm. Explanation =========== Returns a point on the lineseg whose vector inner product with the divergence of `expr` yields an expression with the least maximum total power. Parameters ========== a : Hyperplane parameter denoting direction. b : Hyperplane parameter denoting distance. lineseg : Line segment on which to find the origin. expr : The expression which determines the best point. Algorithm(currently works only for 2D use case) =============================================== 1 > Firstly, check for edge cases. Here that would refer to vertical or horizontal lines. 2 > If input expression is a polynomial containing more than one generator then find out the total power of each of the generators. x**2 + 3 + x*y + x**4*y**5 ---> {x: 7, y: 6} If expression is a constant value then pick the first boundary point of the line segment. 3 > First check if a point exists on the line segment where the value of the highest power generator becomes 0. If not check if the value of the next highest becomes 0. If none becomes 0 within line segment constraints then pick the first boundary point of the line segment. Actually, any point lying on the segment can be picked as best origin in the last case. Examples ======== >>> from sympy.integrals.intpoly import best_origin >>> from sympy.abc import x, y >>> from sympy.geometry.line import Segment2D >>> from sympy.geometry.point import Point >>> l = Segment2D(Point(0, 3), Point(1, 1)) >>> expr = x**3*y**7 >>> best_origin((2, 1), 3, l, expr) (0, 3.0) """ a1, b1 = lineseg.points[0] def x_axis_cut(ls): """Returns the point where the input line segment intersects the x-axis. Parameters ========== ls : Line segment """ p, q = ls.points if p.y.is_zero: return tuple(p) elif q.y.is_zero: return tuple(q) elif p.y/q.y < S.Zero: return p.y * (p.x - q.x)/(q.y - p.y) + p.x, S.Zero else: return () def y_axis_cut(ls): """Returns the point where the input line segment intersects the y-axis. Parameters ========== ls : Line segment """ p, q = ls.points if p.x.is_zero: return tuple(p) elif q.x.is_zero: return tuple(q) elif p.x/q.x < S.Zero: return S.Zero, p.x * (p.y - q.y)/(q.x - p.x) + p.y else: return () gens = (x, y) power_gens = {} for i in gens: power_gens[i] = S.Zero if len(gens) > 1: # Special case for vertical and horizontal lines if len(gens) == 2: if a[0] == 0: if y_axis_cut(lineseg): return S.Zero, b/a[1] else: return a1, b1 elif a[1] == 0: if x_axis_cut(lineseg): return b/a[0], S.Zero else: return a1, b1 if isinstance(expr, Expr): # Find the sum total of power of each if expr.is_Add: # generator and store in a dictionary. for monomial in expr.args: if monomial.is_Pow: if monomial.args[0] in gens: power_gens[monomial.args[0]] += monomial.args[1] else: for univariate in monomial.args: term_type = len(univariate.args) if term_type == 0 and univariate in gens: power_gens[univariate] += 1 elif term_type == 2 and univariate.args[0] in gens: power_gens[univariate.args[0]] +=\ univariate.args[1] elif expr.is_Mul: for term in expr.args: term_type = len(term.args) if term_type == 0 and term in gens: power_gens[term] += 1 elif term_type == 2 and term.args[0] in gens: power_gens[term.args[0]] += term.args[1] elif expr.is_Pow: power_gens[expr.args[0]] = expr.args[1] elif expr.is_Symbol: power_gens[expr] += 1 else: # If `expr` is a constant take first vertex of the line segment. return a1, b1 # TODO : This part is quite hacky. Should be made more robust with # TODO : respect to symbol names and scalable w.r.t higher dimensions. power_gens = sorted(power_gens.items(), key=lambda k: str(k[0])) if power_gens[0][1] >= power_gens[1][1]: if y_axis_cut(lineseg): x0 = (S.Zero, b / a[1]) elif x_axis_cut(lineseg): x0 = (b / a[0], S.Zero) else: x0 = (a1, b1) else: if x_axis_cut(lineseg): x0 = (b/a[0], S.Zero) elif y_axis_cut(lineseg): x0 = (S.Zero, b/a[1]) else: x0 = (a1, b1) else: x0 = (b/a[0]) return x0 def decompose(expr, separate=False): """Decomposes an input polynomial into homogeneous ones of smaller or equal degree. Explanation =========== Returns a dictionary with keys as the degree of the smaller constituting polynomials. Values are the constituting polynomials. Parameters ========== expr : Expr Polynomial(SymPy expression). separate : bool If True then simply return a list of the constituent monomials If not then break up the polynomial into constituent homogeneous polynomials. Examples ======== >>> from sympy.abc import x, y >>> from sympy.integrals.intpoly import decompose >>> decompose(x**2 + x*y + x + y + x**3*y**2 + y**5) {1: x + y, 2: x**2 + x*y, 5: x**3*y**2 + y**5} >>> decompose(x**2 + x*y + x + y + x**3*y**2 + y**5, True) {x, x**2, y, y**5, x*y, x**3*y**2} """ poly_dict = {} if isinstance(expr, Expr) and not expr.is_number: if expr.is_Symbol: poly_dict[1] = expr elif expr.is_Add: symbols = expr.atoms(Symbol) degrees = [(sum(degree_list(monom, *symbols)), monom) for monom in expr.args] if separate: return {monom[1] for monom in degrees} else: for monom in degrees: degree, term = monom if poly_dict.get(degree): poly_dict[degree] += term else: poly_dict[degree] = term elif expr.is_Pow: _, degree = expr.args poly_dict[degree] = expr else: # Now expr can only be of `Mul` type degree = 0 for term in expr.args: term_type = len(term.args) if term_type == 0 and term.is_Symbol: degree += 1 elif term_type == 2: degree += term.args[1] poly_dict[degree] = expr else: poly_dict[0] = expr if separate: return set(poly_dict.values()) return poly_dict def point_sort(poly, normal=None, clockwise=True): """Returns the same polygon with points sorted in clockwise or anti-clockwise order. Note that it's necessary for input points to be sorted in some order (clockwise or anti-clockwise) for the integration algorithm to work. As a convention algorithm has been implemented keeping clockwise orientation in mind. Parameters ========== poly: 2D or 3D Polygon. normal : optional The normal of the plane which the 3-Polytope is a part of. clockwise : bool, optional Returns points sorted in clockwise order if True and anti-clockwise if False. Examples ======== >>> from sympy.integrals.intpoly import point_sort >>> from sympy.geometry.point import Point >>> point_sort([Point(0, 0), Point(1, 0), Point(1, 1)]) [Point2D(1, 1), Point2D(1, 0), Point2D(0, 0)] """ pts = poly.vertices if isinstance(poly, Polygon) else poly n = len(pts) if n < 2: return list(pts) order = S.One if clockwise else S.NegativeOne dim = len(pts[0]) if dim == 2: center = Point(sum(map(lambda vertex: vertex.x, pts)) / n, sum(map(lambda vertex: vertex.y, pts)) / n) else: center = Point(sum(map(lambda vertex: vertex.x, pts)) / n, sum(map(lambda vertex: vertex.y, pts)) / n, sum(map(lambda vertex: vertex.z, pts)) / n) def compare(a, b): if a.x - center.x >= S.Zero and b.x - center.x < S.Zero: return -order elif a.x - center.x < 0 and b.x - center.x >= 0: return order elif a.x - center.x == 0 and b.x - center.x == 0: if a.y - center.y >= 0 or b.y - center.y >= 0: return -order if a.y > b.y else order return -order if b.y > a.y else order det = (a.x - center.x) * (b.y - center.y) -\ (b.x - center.x) * (a.y - center.y) if det < 0: return -order elif det > 0: return order first = (a.x - center.x) * (a.x - center.x) +\ (a.y - center.y) * (a.y - center.y) second = (b.x - center.x) * (b.x - center.x) +\ (b.y - center.y) * (b.y - center.y) return -order if first > second else order def compare3d(a, b): det = cross_product(center, a, b) dot_product = sum([det[i] * normal[i] for i in range(0, 3)]) if dot_product < 0: return -order elif dot_product > 0: return order return sorted(pts, key=cmp_to_key(compare if dim==2 else compare3d)) def norm(point): """Returns the Euclidean norm of a point from origin. Parameters ========== point: This denotes a point in the dimension_al spac_e. Examples ======== >>> from sympy.integrals.intpoly import norm >>> from sympy.geometry.point import Point >>> norm(Point(2, 7)) sqrt(53) """ half = S.Half if isinstance(point, (list, tuple)): return sum([coord ** 2 for coord in point]) ** half elif isinstance(point, Point): if isinstance(point, Point2D): return (point.x ** 2 + point.y ** 2) ** half else: return (point.x ** 2 + point.y ** 2 + point.z) ** half elif isinstance(point, dict): return sum(i**2 for i in point.values()) ** half def intersection(geom_1, geom_2, intersection_type): """Returns intersection between geometric objects. Explanation =========== Note that this function is meant for use in integration_reduction and at that point in the calling function the lines denoted by the segments surely intersect within segment boundaries. Coincident lines are taken to be non-intersecting. Also, the hyperplane intersection for 2D case is also implemented. Parameters ========== geom_1, geom_2: The input line segments. Examples ======== >>> from sympy.integrals.intpoly import intersection >>> from sympy.geometry.point import Point >>> from sympy.geometry.line import Segment2D >>> l1 = Segment2D(Point(1, 1), Point(3, 5)) >>> l2 = Segment2D(Point(2, 0), Point(2, 5)) >>> intersection(l1, l2, "segment2D") (2, 3) >>> p1 = ((-1, 0), 0) >>> p2 = ((0, 1), 1) >>> intersection(p1, p2, "plane2D") (0, 1) """ if intersection_type[:-2] == "segment": if intersection_type == "segment2D": x1, y1 = geom_1.points[0] x2, y2 = geom_1.points[1] x3, y3 = geom_2.points[0] x4, y4 = geom_2.points[1] elif intersection_type == "segment3D": x1, y1, z1 = geom_1.points[0] x2, y2, z2 = geom_1.points[1] x3, y3, z3 = geom_2.points[0] x4, y4, z4 = geom_2.points[1] denom = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4) if denom: t1 = x1 * y2 - y1 * x2 t2 = x3 * y4 - x4 * y3 return (S(t1 * (x3 - x4) - t2 * (x1 - x2)) / denom, S(t1 * (y3 - y4) - t2 * (y1 - y2)) / denom) if intersection_type[:-2] == "plane": if intersection_type == "plane2D": # Intersection of hyperplanes a1x, a1y = geom_1[0] a2x, a2y = geom_2[0] b1, b2 = geom_1[1], geom_2[1] denom = a1x * a2y - a2x * a1y if denom: return (S(b1 * a2y - b2 * a1y) / denom, S(b2 * a1x - b1 * a2x) / denom) def is_vertex(ent): """If the input entity is a vertex return True. Parameter ========= ent : Denotes a geometric entity representing a point. Examples ======== >>> from sympy.geometry.point import Point >>> from sympy.integrals.intpoly import is_vertex >>> is_vertex((2, 3)) True >>> is_vertex((2, 3, 6)) True >>> is_vertex(Point(2, 3)) True """ if isinstance(ent, tuple): if len(ent) in [2, 3]: return True elif isinstance(ent, Point): return True return False def plot_polytope(poly): """Plots the 2D polytope using the functions written in plotting module which in turn uses matplotlib backend. Parameter ========= poly: Denotes a 2-Polytope. """ from sympy.plotting.plot import Plot, List2DSeries xl = list(map(lambda vertex: vertex.x, poly.vertices)) yl = list(map(lambda vertex: vertex.y, poly.vertices)) xl.append(poly.vertices[0].x) # Closing the polygon yl.append(poly.vertices[0].y) l2ds = List2DSeries(xl, yl) p = Plot(l2ds, axes='label_axes=True') p.show() def plot_polynomial(expr): """Plots the polynomial using the functions written in plotting module which in turn uses matplotlib backend. Parameter ========= expr: Denotes a polynomial(SymPy expression). """ from sympy.plotting.plot import plot3d, plot gens = expr.free_symbols if len(gens) == 2: plot3d(expr) else: plot(expr) sympy-sympy-1.9/sympy/integrals/manualintegrate.py000066400000000000000000001735261412543434000226440ustar00rootroot00000000000000"""Integration method that emulates by-hand techniques. This module also provides functionality to get the steps used to evaluate a particular integral, in the ``integral_steps`` function. This will return nested namedtuples representing the integration rules used. The ``manualintegrate`` function computes the integral using those steps given an integrand; given the steps, ``_manualintegrate`` will evaluate them. The integrator can be extended with new heuristics and evaluation techniques. To do so, write a function that accepts an ``IntegralInfo`` object and returns either a namedtuple representing a rule or ``None``. Then, write another function that accepts the namedtuple's fields and returns the antiderivative, and decorate it with ``@evaluates(namedtuple_type)``. If the new technique requires a new match, add the key and call to the antiderivative function to integral_steps. To enable simple substitutions, add the match to find_substitutions. """ from typing import Dict as tDict, Optional from collections import namedtuple, defaultdict from collections.abc import Mapping from functools import reduce import sympy from sympy.core.compatibility import iterable from sympy.core.containers import Dict from sympy.core.expr import Expr from sympy.core.logic import fuzzy_not from sympy.functions.elementary.trigonometric import TrigonometricFunction from sympy.functions.special.polynomials import OrthogonalPolynomial from sympy.functions.elementary.piecewise import Piecewise from sympy.strategies.core import switch, do_one, null_safe, condition from sympy.core.relational import Eq, Ne from sympy.polys.polytools import degree from sympy.ntheory.factor_ import divisors from sympy.utilities.misc import debug ZERO = sympy.S.Zero def Rule(name, props=""): # GOTCHA: namedtuple class name not considered! def __eq__(self, other): return self.__class__ == other.__class__ and tuple.__eq__(self, other) __neq__ = lambda self, other: not __eq__(self, other) cls = namedtuple(name, props + " context symbol") cls.__eq__ = __eq__ cls.__ne__ = __neq__ return cls ConstantRule = Rule("ConstantRule", "constant") ConstantTimesRule = Rule("ConstantTimesRule", "constant other substep") PowerRule = Rule("PowerRule", "base exp") AddRule = Rule("AddRule", "substeps") URule = Rule("URule", "u_var u_func constant substep") PartsRule = Rule("PartsRule", "u dv v_step second_step") CyclicPartsRule = Rule("CyclicPartsRule", "parts_rules coefficient") TrigRule = Rule("TrigRule", "func arg") ExpRule = Rule("ExpRule", "base exp") ReciprocalRule = Rule("ReciprocalRule", "func") ArcsinRule = Rule("ArcsinRule") InverseHyperbolicRule = Rule("InverseHyperbolicRule", "func") AlternativeRule = Rule("AlternativeRule", "alternatives") DontKnowRule = Rule("DontKnowRule") DerivativeRule = Rule("DerivativeRule") RewriteRule = Rule("RewriteRule", "rewritten substep") PiecewiseRule = Rule("PiecewiseRule", "subfunctions") HeavisideRule = Rule("HeavisideRule", "harg ibnd substep") TrigSubstitutionRule = Rule("TrigSubstitutionRule", "theta func rewritten substep restriction") ArctanRule = Rule("ArctanRule", "a b c") ArccothRule = Rule("ArccothRule", "a b c") ArctanhRule = Rule("ArctanhRule", "a b c") JacobiRule = Rule("JacobiRule", "n a b") GegenbauerRule = Rule("GegenbauerRule", "n a") ChebyshevTRule = Rule("ChebyshevTRule", "n") ChebyshevURule = Rule("ChebyshevURule", "n") LegendreRule = Rule("LegendreRule", "n") HermiteRule = Rule("HermiteRule", "n") LaguerreRule = Rule("LaguerreRule", "n") AssocLaguerreRule = Rule("AssocLaguerreRule", "n a") CiRule = Rule("CiRule", "a b") ChiRule = Rule("ChiRule", "a b") EiRule = Rule("EiRule", "a b") SiRule = Rule("SiRule", "a b") ShiRule = Rule("ShiRule", "a b") ErfRule = Rule("ErfRule", "a b c") FresnelCRule = Rule("FresnelCRule", "a b c") FresnelSRule = Rule("FresnelSRule", "a b c") LiRule = Rule("LiRule", "a b") PolylogRule = Rule("PolylogRule", "a b") UpperGammaRule = Rule("UpperGammaRule", "a e") EllipticFRule = Rule("EllipticFRule", "a d") EllipticERule = Rule("EllipticERule", "a d") IntegralInfo = namedtuple('IntegralInfo', 'integrand symbol') evaluators = {} def evaluates(rule): def _evaluates(func): func.rule = rule evaluators[rule] = func return func return _evaluates def contains_dont_know(rule): if isinstance(rule, DontKnowRule): return True else: for val in rule: if isinstance(val, tuple): if contains_dont_know(val): return True elif isinstance(val, list): if any(contains_dont_know(i) for i in val): return True return False def manual_diff(f, symbol): """Derivative of f in form expected by find_substitutions SymPy's derivatives for some trig functions (like cot) aren't in a form that works well with finding substitutions; this replaces the derivatives for those particular forms with something that works better. """ if f.args: arg = f.args[0] if isinstance(f, sympy.tan): return arg.diff(symbol) * sympy.sec(arg)**2 elif isinstance(f, sympy.cot): return -arg.diff(symbol) * sympy.csc(arg)**2 elif isinstance(f, sympy.sec): return arg.diff(symbol) * sympy.sec(arg) * sympy.tan(arg) elif isinstance(f, sympy.csc): return -arg.diff(symbol) * sympy.csc(arg) * sympy.cot(arg) elif isinstance(f, sympy.Add): return sum([manual_diff(arg, symbol) for arg in f.args]) elif isinstance(f, sympy.Mul): if len(f.args) == 2 and isinstance(f.args[0], sympy.Number): return f.args[0] * manual_diff(f.args[1], symbol) return f.diff(symbol) def manual_subs(expr, *args): """ A wrapper for `expr.subs(*args)` with additional logic for substitution of invertible functions. """ if len(args) == 1: sequence = args[0] if isinstance(sequence, (Dict, Mapping)): sequence = sequence.items() elif not iterable(sequence): raise ValueError("Expected an iterable of (old, new) pairs") elif len(args) == 2: sequence = [args] else: raise ValueError("subs accepts either 1 or 2 arguments") new_subs = [] for old, new in sequence: if isinstance(old, sympy.log): # If log(x) = y, then exp(a*log(x)) = exp(a*y) # that is, x**a = exp(a*y). Replace nontrivial powers of x # before subs turns them into `exp(y)**a`, but # do not replace x itself yet, to avoid `log(exp(y))`. x0 = old.args[0] expr = expr.replace(lambda x: x.is_Pow and x.base == x0, lambda x: sympy.exp(x.exp*new)) new_subs.append((x0, sympy.exp(new))) return expr.subs(list(sequence) + new_subs) # Method based on that on SIN, described in "Symbolic Integration: The # Stormy Decade" inverse_trig_functions = (sympy.atan, sympy.asin, sympy.acos, sympy.acot, sympy.acsc, sympy.asec) def find_substitutions(integrand, symbol, u_var): results = [] def test_subterm(u, u_diff): if u_diff == 0: return False substituted = integrand / u_diff if symbol not in substituted.free_symbols: # replaced everything already return False debug("substituted: {}, u: {}, u_var: {}".format(substituted, u, u_var)) substituted = manual_subs(substituted, u, u_var).cancel() if symbol not in substituted.free_symbols: # avoid increasing the degree of a rational function if integrand.is_rational_function(symbol) and substituted.is_rational_function(u_var): deg_before = max([degree(t, symbol) for t in integrand.as_numer_denom()]) deg_after = max([degree(t, u_var) for t in substituted.as_numer_denom()]) if deg_after > deg_before: return False return substituted.as_independent(u_var, as_Add=False) # special treatment for substitutions u = (a*x+b)**(1/n) if (isinstance(u, sympy.Pow) and (1/u.exp).is_Integer and sympy.Abs(u.exp) < 1): a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) match = u.base.match(a*symbol + b) if match: a, b = [match.get(i, ZERO) for i in (a, b)] if a != 0 and b != 0: substituted = substituted.subs(symbol, (u_var**(1/u.exp) - b)/a) return substituted.as_independent(u_var, as_Add=False) return False def possible_subterms(term): if isinstance(term, (TrigonometricFunction, *inverse_trig_functions, sympy.exp, sympy.log, sympy.Heaviside)): return [term.args[0]] elif isinstance(term, (sympy.chebyshevt, sympy.chebyshevu, sympy.legendre, sympy.hermite, sympy.laguerre)): return [term.args[1]] elif isinstance(term, (sympy.gegenbauer, sympy.assoc_laguerre)): return [term.args[2]] elif isinstance(term, sympy.jacobi): return [term.args[3]] elif isinstance(term, sympy.Mul): r = [] for u in term.args: r.append(u) r.extend(possible_subterms(u)) return r elif isinstance(term, sympy.Pow): r = [] if term.args[1].is_constant(symbol): r.append(term.args[0]) elif term.args[0].is_constant(symbol): r.append(term.args[1]) if term.args[1].is_Integer: r.extend([term.args[0]**d for d in divisors(term.args[1]) if 1 < d < abs(term.args[1])]) if term.args[0].is_Add: r.extend([t for t in possible_subterms(term.args[0]) if t.is_Pow]) return r elif isinstance(term, sympy.Add): r = [] for arg in term.args: r.append(arg) r.extend(possible_subterms(arg)) return r return [] for u in possible_subterms(integrand): if u == symbol: continue u_diff = manual_diff(u, symbol) new_integrand = test_subterm(u, u_diff) if new_integrand is not False: constant, new_integrand = new_integrand if new_integrand == integrand.subs(symbol, u_var): continue substitution = (u, constant, new_integrand) if substitution not in results: results.append(substitution) return results def rewriter(condition, rewrite): """Strategy that rewrites an integrand.""" def _rewriter(integral): integrand, symbol = integral debug("Integral: {} is rewritten with {} on symbol: {}".format(integrand, rewrite, symbol)) if condition(*integral): rewritten = rewrite(*integral) if rewritten != integrand: substep = integral_steps(rewritten, symbol) if not isinstance(substep, DontKnowRule) and substep: return RewriteRule( rewritten, substep, integrand, symbol) return _rewriter def proxy_rewriter(condition, rewrite): """Strategy that rewrites an integrand based on some other criteria.""" def _proxy_rewriter(criteria): criteria, integral = criteria integrand, symbol = integral debug("Integral: {} is rewritten with {} on symbol: {} and criteria: {}".format(integrand, rewrite, symbol, criteria)) args = criteria + list(integral) if condition(*args): rewritten = rewrite(*args) if rewritten != integrand: return RewriteRule( rewritten, integral_steps(rewritten, symbol), integrand, symbol) return _proxy_rewriter def multiplexer(conditions): """Apply the rule that matches the condition, else None""" def multiplexer_rl(expr): for key, rule in conditions.items(): if key(expr): return rule(expr) return multiplexer_rl def alternatives(*rules): """Strategy that makes an AlternativeRule out of multiple possible results.""" def _alternatives(integral): alts = [] count = 0 debug("List of Alternative Rules") for rule in rules: count = count + 1 debug("Rule {}: {}".format(count, rule)) result = rule(integral) if (result and not isinstance(result, DontKnowRule) and result != integral and result not in alts): alts.append(result) if len(alts) == 1: return alts[0] elif alts: doable = [rule for rule in alts if not contains_dont_know(rule)] if doable: return AlternativeRule(doable, *integral) else: return AlternativeRule(alts, *integral) return _alternatives def constant_rule(integral): return ConstantRule(integral.integrand, *integral) def power_rule(integral): integrand, symbol = integral base, exp = integrand.as_base_exp() if symbol not in exp.free_symbols and isinstance(base, sympy.Symbol): if sympy.simplify(exp + 1) == 0: return ReciprocalRule(base, integrand, symbol) return PowerRule(base, exp, integrand, symbol) elif symbol not in base.free_symbols and isinstance(exp, sympy.Symbol): rule = ExpRule(base, exp, integrand, symbol) if fuzzy_not(sympy.log(base).is_zero): return rule elif sympy.log(base).is_zero: return ConstantRule(1, 1, symbol) return PiecewiseRule([ (rule, sympy.Ne(sympy.log(base), 0)), (ConstantRule(1, 1, symbol), True) ], integrand, symbol) def exp_rule(integral): integrand, symbol = integral if isinstance(integrand.args[0], sympy.Symbol): return ExpRule(sympy.E, integrand.args[0], integrand, symbol) def orthogonal_poly_rule(integral): orthogonal_poly_classes = { sympy.jacobi: JacobiRule, sympy.gegenbauer: GegenbauerRule, sympy.chebyshevt: ChebyshevTRule, sympy.chebyshevu: ChebyshevURule, sympy.legendre: LegendreRule, sympy.hermite: HermiteRule, sympy.laguerre: LaguerreRule, sympy.assoc_laguerre: AssocLaguerreRule } orthogonal_poly_var_index = { sympy.jacobi: 3, sympy.gegenbauer: 2, sympy.assoc_laguerre: 2 } integrand, symbol = integral for klass in orthogonal_poly_classes: if isinstance(integrand, klass): var_index = orthogonal_poly_var_index.get(klass, 1) if (integrand.args[var_index] is symbol and not any(v.has(symbol) for v in integrand.args[:var_index])): args = integrand.args[:var_index] + (integrand, symbol) return orthogonal_poly_classes[klass](*args) def special_function_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[symbol], properties=[lambda x: not x.is_zero]) b = sympy.Wild('b', exclude=[symbol]) c = sympy.Wild('c', exclude=[symbol]) d = sympy.Wild('d', exclude=[symbol], properties=[lambda x: not x.is_zero]) e = sympy.Wild('e', exclude=[symbol], properties=[ lambda x: not (x.is_nonnegative and x.is_integer)]) wilds = (a, b, c, d, e) # patterns consist of a SymPy class, a wildcard expr, an optional # condition coded as a lambda (when Wild properties are not enough), # followed by an applicable rule patterns = ( (sympy.Mul, sympy.exp(a*symbol + b)/symbol, None, EiRule), (sympy.Mul, sympy.cos(a*symbol + b)/symbol, None, CiRule), (sympy.Mul, sympy.cosh(a*symbol + b)/symbol, None, ChiRule), (sympy.Mul, sympy.sin(a*symbol + b)/symbol, None, SiRule), (sympy.Mul, sympy.sinh(a*symbol + b)/symbol, None, ShiRule), (sympy.Pow, 1/sympy.log(a*symbol + b), None, LiRule), (sympy.exp, sympy.exp(a*symbol**2 + b*symbol + c), None, ErfRule), (sympy.sin, sympy.sin(a*symbol**2 + b*symbol + c), None, FresnelSRule), (sympy.cos, sympy.cos(a*symbol**2 + b*symbol + c), None, FresnelCRule), (sympy.Mul, symbol**e*sympy.exp(a*symbol), None, UpperGammaRule), (sympy.Mul, sympy.polylog(b, a*symbol)/symbol, None, PolylogRule), (sympy.Pow, 1/sympy.sqrt(a - d*sympy.sin(symbol)**2), lambda a, d: a != d, EllipticFRule), (sympy.Pow, sympy.sqrt(a - d*sympy.sin(symbol)**2), lambda a, d: a != d, EllipticERule), ) for p in patterns: if isinstance(integrand, p[0]): match = integrand.match(p[1]) if match: wild_vals = tuple(match.get(w) for w in wilds if match.get(w) is not None) if p[2] is None or p[2](*wild_vals): args = wild_vals + (integrand, symbol) return p[3](*args) def inverse_trig_rule(integral): integrand, symbol = integral base, exp = integrand.as_base_exp() a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) match = base.match(a + b*symbol**2) if not match: return def negative(x): return x.is_negative or x.could_extract_minus_sign() def ArcsinhRule(integrand, symbol): return InverseHyperbolicRule(sympy.asinh, integrand, symbol) def ArccoshRule(integrand, symbol): return InverseHyperbolicRule(sympy.acosh, integrand, symbol) def make_inverse_trig(RuleClass, base_exp, a, sign_a, b, sign_b): u_var = sympy.Dummy("u") current_base = base current_symbol = symbol constant = u_func = u_constant = substep = None factored = integrand if a != 1: constant = a**base_exp current_base = sign_a + sign_b * (b/a) * current_symbol**2 factored = current_base ** base_exp if (b/a) != 1: u_func = sympy.sqrt(b/a) * symbol u_constant = sympy.sqrt(a/b) current_symbol = u_var current_base = sign_a + sign_b * current_symbol**2 substep = RuleClass(current_base ** base_exp, current_symbol) if u_func is not None: if u_constant != 1 and substep is not None: substep = ConstantTimesRule( u_constant, current_base ** base_exp, substep, u_constant * current_base ** base_exp, symbol) substep = URule(u_var, u_func, u_constant, substep, factored, symbol) if constant is not None and substep is not None: substep = ConstantTimesRule(constant, factored, substep, integrand, symbol) return substep a, b = [match.get(i, ZERO) for i in (a, b)] # list of (rule, base_exp, a, sign_a, b, sign_b, condition) possibilities = [] if sympy.simplify(2*exp + 1) == 0: possibilities.append((ArcsinRule, exp, a, 1, -b, -1, sympy.And(a > 0, b < 0))) possibilities.append((ArcsinhRule, exp, a, 1, b, 1, sympy.And(a > 0, b > 0))) possibilities.append((ArccoshRule, exp, -a, -1, b, 1, sympy.And(a < 0, b > 0))) possibilities = [p for p in possibilities if p[-1] is not sympy.false] if a.is_number and b.is_number: possibility = [p for p in possibilities if p[-1] is sympy.true] if len(possibility) == 1: return make_inverse_trig(*possibility[0][:-1]) elif possibilities: return PiecewiseRule( [(make_inverse_trig(*p[:-1]), p[-1]) for p in possibilities], integrand, symbol) def add_rule(integral): integrand, symbol = integral results = [integral_steps(g, symbol) for g in integrand.as_ordered_terms()] return None if None in results else AddRule(results, integrand, symbol) def mul_rule(integral): integrand, symbol = integral # Constant times function case coeff, f = integrand.as_independent(symbol) next_step = integral_steps(f, symbol) if coeff != 1 and next_step is not None: return ConstantTimesRule( coeff, f, next_step, integrand, symbol) def _parts_rule(integrand, symbol): # LIATE rule: # log, inverse trig, algebraic, trigonometric, exponential def pull_out_algebraic(integrand): integrand = integrand.cancel().together() # iterating over Piecewise args would not work here algebraic = ([] if isinstance(integrand, sympy.Piecewise) else [arg for arg in integrand.args if arg.is_algebraic_expr(symbol)]) if algebraic: u = sympy.Mul(*algebraic) dv = (integrand / u).cancel() return u, dv def pull_out_u(*functions): def pull_out_u_rl(integrand): if any([integrand.has(f) for f in functions]): args = [arg for arg in integrand.args if any(isinstance(arg, cls) for cls in functions)] if args: u = reduce(lambda a,b: a*b, args) dv = integrand / u return u, dv return pull_out_u_rl liate_rules = [pull_out_u(sympy.log), pull_out_u(*inverse_trig_functions), pull_out_algebraic, pull_out_u(sympy.sin, sympy.cos), pull_out_u(sympy.exp)] dummy = sympy.Dummy("temporary") # we can integrate log(x) and atan(x) by setting dv = 1 if isinstance(integrand, (sympy.log, *inverse_trig_functions)): integrand = dummy * integrand for index, rule in enumerate(liate_rules): result = rule(integrand) if result: u, dv = result # Don't pick u to be a constant if possible if symbol not in u.free_symbols and not u.has(dummy): return u = u.subs(dummy, 1) dv = dv.subs(dummy, 1) # Don't pick a non-polynomial algebraic to be differentiated if rule == pull_out_algebraic and not u.is_polynomial(symbol): return # Don't trade one logarithm for another if isinstance(u, sympy.log): rec_dv = 1/dv if (rec_dv.is_polynomial(symbol) and degree(rec_dv, symbol) == 1): return # Can integrate a polynomial times OrthogonalPolynomial if rule == pull_out_algebraic and isinstance(dv, OrthogonalPolynomial): v_step = integral_steps(dv, symbol) if contains_dont_know(v_step): return else: du = u.diff(symbol) v = _manualintegrate(v_step) return u, dv, v, du, v_step # make sure dv is amenable to integration accept = False if index < 2: # log and inverse trig are usually worth trying accept = True elif (rule == pull_out_algebraic and dv.args and all(isinstance(a, (sympy.sin, sympy.cos, sympy.exp)) for a in dv.args)): accept = True else: for rule in liate_rules[index + 1:]: r = rule(integrand) if r and r[0].subs(dummy, 1).equals(dv): accept = True break if accept: du = u.diff(symbol) v_step = integral_steps(sympy.simplify(dv), symbol) if not contains_dont_know(v_step): v = _manualintegrate(v_step) return u, dv, v, du, v_step def parts_rule(integral): integrand, symbol = integral constant, integrand = integrand.as_coeff_Mul() result = _parts_rule(integrand, symbol) steps = [] if result: u, dv, v, du, v_step = result debug("u : {}, dv : {}, v : {}, du : {}, v_step: {}".format(u, dv, v, du, v_step)) steps.append(result) if isinstance(v, sympy.Integral): return # Set a limit on the number of times u can be used if isinstance(u, (sympy.sin, sympy.cos, sympy.exp, sympy.sinh, sympy.cosh)): cachekey = u.xreplace({symbol: _cache_dummy}) if _parts_u_cache[cachekey] > 2: return _parts_u_cache[cachekey] += 1 # Try cyclic integration by parts a few times for _ in range(4): debug("Cyclic integration {} with v: {}, du: {}, integrand: {}".format(_, v, du, integrand)) coefficient = ((v * du) / integrand).cancel() if coefficient == 1: break if symbol not in coefficient.free_symbols: rule = CyclicPartsRule( [PartsRule(u, dv, v_step, None, None, None) for (u, dv, v, du, v_step) in steps], (-1) ** len(steps) * coefficient, integrand, symbol ) if (constant != 1) and rule: rule = ConstantTimesRule(constant, integrand, rule, constant * integrand, symbol) return rule # _parts_rule is sensitive to constants, factor it out next_constant, next_integrand = (v * du).as_coeff_Mul() result = _parts_rule(next_integrand, symbol) if result: u, dv, v, du, v_step = result u *= next_constant du *= next_constant steps.append((u, dv, v, du, v_step)) else: break def make_second_step(steps, integrand): if steps: u, dv, v, du, v_step = steps[0] return PartsRule(u, dv, v_step, make_second_step(steps[1:], v * du), integrand, symbol) else: steps = integral_steps(integrand, symbol) if steps: return steps else: return DontKnowRule(integrand, symbol) if steps: u, dv, v, du, v_step = steps[0] rule = PartsRule(u, dv, v_step, make_second_step(steps[1:], v * du), integrand, symbol) if (constant != 1) and rule: rule = ConstantTimesRule(constant, integrand, rule, constant * integrand, symbol) return rule def trig_rule(integral): integrand, symbol = integral if isinstance(integrand, sympy.sin) or isinstance(integrand, sympy.cos): arg = integrand.args[0] if not isinstance(arg, sympy.Symbol): return # perhaps a substitution can deal with it if isinstance(integrand, sympy.sin): func = 'sin' else: func = 'cos' return TrigRule(func, arg, integrand, symbol) if integrand == sympy.sec(symbol)**2: return TrigRule('sec**2', symbol, integrand, symbol) elif integrand == sympy.csc(symbol)**2: return TrigRule('csc**2', symbol, integrand, symbol) if isinstance(integrand, sympy.tan): rewritten = sympy.sin(*integrand.args) / sympy.cos(*integrand.args) elif isinstance(integrand, sympy.cot): rewritten = sympy.cos(*integrand.args) / sympy.sin(*integrand.args) elif isinstance(integrand, sympy.sec): arg = integrand.args[0] rewritten = ((sympy.sec(arg)**2 + sympy.tan(arg) * sympy.sec(arg)) / (sympy.sec(arg) + sympy.tan(arg))) elif isinstance(integrand, sympy.csc): arg = integrand.args[0] rewritten = ((sympy.csc(arg)**2 + sympy.cot(arg) * sympy.csc(arg)) / (sympy.csc(arg) + sympy.cot(arg))) else: return return RewriteRule( rewritten, integral_steps(rewritten, symbol), integrand, symbol ) def trig_product_rule(integral): integrand, symbol = integral sectan = sympy.sec(symbol) * sympy.tan(symbol) q = integrand / sectan if symbol not in q.free_symbols: rule = TrigRule('sec*tan', symbol, sectan, symbol) if q != 1 and rule: rule = ConstantTimesRule(q, sectan, rule, integrand, symbol) return rule csccot = -sympy.csc(symbol) * sympy.cot(symbol) q = integrand / csccot if symbol not in q.free_symbols: rule = TrigRule('csc*cot', symbol, csccot, symbol) if q != 1 and rule: rule = ConstantTimesRule(q, csccot, rule, integrand, symbol) return rule def quadratic_denom_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) c = sympy.Wild('c', exclude=[symbol]) match = integrand.match(a / (b * symbol ** 2 + c)) if match: a, b, c = match[a], match[b], match[c] if b.is_extended_real and c.is_extended_real: return PiecewiseRule([(ArctanRule(a, b, c, integrand, symbol), sympy.Gt(c / b, 0)), (ArccothRule(a, b, c, integrand, symbol), sympy.And(sympy.Gt(symbol ** 2, -c / b), sympy.Lt(c / b, 0))), (ArctanhRule(a, b, c, integrand, symbol), sympy.And(sympy.Lt(symbol ** 2, -c / b), sympy.Lt(c / b, 0))), ], integrand, symbol) else: return ArctanRule(a, b, c, integrand, symbol) d = sympy.Wild('d', exclude=[symbol]) match2 = integrand.match(a / (b * symbol ** 2 + c * symbol + d)) if match2: b, c = match2[b], match2[c] if b.is_zero: return u = sympy.Dummy('u') u_func = symbol + c/(2*b) integrand2 = integrand.subs(symbol, u - c / (2*b)) next_step = integral_steps(integrand2, u) if next_step: return URule(u, u_func, None, next_step, integrand2, symbol) else: return e = sympy.Wild('e', exclude=[symbol]) match3 = integrand.match((a* symbol + b) / (c * symbol ** 2 + d * symbol + e)) if match3: a, b, c, d, e = match3[a], match3[b], match3[c], match3[d], match3[e] if c.is_zero: return denominator = c * symbol**2 + d * symbol + e const = a/(2*c) numer1 = (2*c*symbol+d) numer2 = - const*d + b u = sympy.Dummy('u') step1 = URule(u, denominator, const, integral_steps(u**(-1), u), integrand, symbol) if const != 1: step1 = ConstantTimesRule(const, numer1/denominator, step1, const*numer1/denominator, symbol) if numer2.is_zero: return step1 step2 = integral_steps(numer2/denominator, symbol) substeps = AddRule([step1, step2], integrand, symbol) rewriten = const*numer1/denominator+numer2/denominator return RewriteRule(rewriten, substeps, integrand, symbol) return def root_mul_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) c = sympy.Wild('c') match = integrand.match(sympy.sqrt(a * symbol + b) * c) if not match: return a, b, c = match[a], match[b], match[c] d = sympy.Wild('d', exclude=[symbol]) e = sympy.Wild('e', exclude=[symbol]) f = sympy.Wild('f') recursion_test = c.match(sympy.sqrt(d * symbol + e) * f) if recursion_test: return u = sympy.Dummy('u') u_func = sympy.sqrt(a * symbol + b) integrand = integrand.subs(u_func, u) integrand = integrand.subs(symbol, (u**2 - b) / a) integrand = integrand * 2 * u / a next_step = integral_steps(integrand, u) if next_step: return URule(u, u_func, None, next_step, integrand, symbol) @sympy.cacheit def make_wilds(symbol): a = sympy.Wild('a', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) m = sympy.Wild('m', exclude=[symbol], properties=[lambda n: isinstance(n, sympy.Integer)]) n = sympy.Wild('n', exclude=[symbol], properties=[lambda n: isinstance(n, sympy.Integer)]) return a, b, m, n @sympy.cacheit def sincos_pattern(symbol): a, b, m, n = make_wilds(symbol) pattern = sympy.sin(a*symbol)**m * sympy.cos(b*symbol)**n return pattern, a, b, m, n @sympy.cacheit def tansec_pattern(symbol): a, b, m, n = make_wilds(symbol) pattern = sympy.tan(a*symbol)**m * sympy.sec(b*symbol)**n return pattern, a, b, m, n @sympy.cacheit def cotcsc_pattern(symbol): a, b, m, n = make_wilds(symbol) pattern = sympy.cot(a*symbol)**m * sympy.csc(b*symbol)**n return pattern, a, b, m, n @sympy.cacheit def heaviside_pattern(symbol): m = sympy.Wild('m', exclude=[symbol]) b = sympy.Wild('b', exclude=[symbol]) g = sympy.Wild('g') pattern = sympy.Heaviside(m*symbol + b) * g return pattern, m, b, g def uncurry(func): def uncurry_rl(args): return func(*args) return uncurry_rl def trig_rewriter(rewrite): def trig_rewriter_rl(args): a, b, m, n, integrand, symbol = args rewritten = rewrite(a, b, m, n, integrand, symbol) if rewritten != integrand: return RewriteRule( rewritten, integral_steps(rewritten, symbol), integrand, symbol) return trig_rewriter_rl sincos_botheven_condition = uncurry( lambda a, b, m, n, i, s: m.is_even and n.is_even and m.is_nonnegative and n.is_nonnegative) sincos_botheven = trig_rewriter( lambda a, b, m, n, i, symbol: ( (((1 - sympy.cos(2*a*symbol)) / 2) ** (m / 2)) * (((1 + sympy.cos(2*b*symbol)) / 2) ** (n / 2)) )) sincos_sinodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd and m >= 3) sincos_sinodd = trig_rewriter( lambda a, b, m, n, i, symbol: ( (1 - sympy.cos(a*symbol)**2)**((m - 1) / 2) * sympy.sin(a*symbol) * sympy.cos(b*symbol) ** n)) sincos_cosodd_condition = uncurry(lambda a, b, m, n, i, s: n.is_odd and n >= 3) sincos_cosodd = trig_rewriter( lambda a, b, m, n, i, symbol: ( (1 - sympy.sin(b*symbol)**2)**((n - 1) / 2) * sympy.cos(b*symbol) * sympy.sin(a*symbol) ** m)) tansec_seceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4) tansec_seceven = trig_rewriter( lambda a, b, m, n, i, symbol: ( (1 + sympy.tan(b*symbol)**2) ** (n/2 - 1) * sympy.sec(b*symbol)**2 * sympy.tan(a*symbol) ** m )) tansec_tanodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd) tansec_tanodd = trig_rewriter( lambda a, b, m, n, i, symbol: ( (sympy.sec(a*symbol)**2 - 1) ** ((m - 1) / 2) * sympy.tan(a*symbol) * sympy.sec(b*symbol) ** n )) tan_tansquared_condition = uncurry(lambda a, b, m, n, i, s: m == 2 and n == 0) tan_tansquared = trig_rewriter( lambda a, b, m, n, i, symbol: ( sympy.sec(a*symbol)**2 - 1)) cotcsc_csceven_condition = uncurry(lambda a, b, m, n, i, s: n.is_even and n >= 4) cotcsc_csceven = trig_rewriter( lambda a, b, m, n, i, symbol: ( (1 + sympy.cot(b*symbol)**2) ** (n/2 - 1) * sympy.csc(b*symbol)**2 * sympy.cot(a*symbol) ** m )) cotcsc_cotodd_condition = uncurry(lambda a, b, m, n, i, s: m.is_odd) cotcsc_cotodd = trig_rewriter( lambda a, b, m, n, i, symbol: ( (sympy.csc(a*symbol)**2 - 1) ** ((m - 1) / 2) * sympy.cot(a*symbol) * sympy.csc(b*symbol) ** n )) def trig_sincos_rule(integral): integrand, symbol = integral if any(integrand.has(f) for f in (sympy.sin, sympy.cos)): pattern, a, b, m, n = sincos_pattern(symbol) match = integrand.match(pattern) if not match: return return multiplexer({ sincos_botheven_condition: sincos_botheven, sincos_sinodd_condition: sincos_sinodd, sincos_cosodd_condition: sincos_cosodd })(tuple( [match.get(i, ZERO) for i in (a, b, m, n)] + [integrand, symbol])) def trig_tansec_rule(integral): integrand, symbol = integral integrand = integrand.subs({ 1 / sympy.cos(symbol): sympy.sec(symbol) }) if any(integrand.has(f) for f in (sympy.tan, sympy.sec)): pattern, a, b, m, n = tansec_pattern(symbol) match = integrand.match(pattern) if not match: return return multiplexer({ tansec_tanodd_condition: tansec_tanodd, tansec_seceven_condition: tansec_seceven, tan_tansquared_condition: tan_tansquared })(tuple( [match.get(i, ZERO) for i in (a, b, m, n)] + [integrand, symbol])) def trig_cotcsc_rule(integral): integrand, symbol = integral integrand = integrand.subs({ 1 / sympy.sin(symbol): sympy.csc(symbol), 1 / sympy.tan(symbol): sympy.cot(symbol), sympy.cos(symbol) / sympy.tan(symbol): sympy.cot(symbol) }) if any(integrand.has(f) for f in (sympy.cot, sympy.csc)): pattern, a, b, m, n = cotcsc_pattern(symbol) match = integrand.match(pattern) if not match: return return multiplexer({ cotcsc_cotodd_condition: cotcsc_cotodd, cotcsc_csceven_condition: cotcsc_csceven })(tuple( [match.get(i, ZERO) for i in (a, b, m, n)] + [integrand, symbol])) def trig_sindouble_rule(integral): integrand, symbol = integral a = sympy.Wild('a', exclude=[sympy.sin(2*symbol)]) match = integrand.match(sympy.sin(2*symbol)*a) if match: sin_double = 2*sympy.sin(symbol)*sympy.cos(symbol)/sympy.sin(2*symbol) return integral_steps(integrand * sin_double, symbol) def trig_powers_products_rule(integral): return do_one(null_safe(trig_sincos_rule), null_safe(trig_tansec_rule), null_safe(trig_cotcsc_rule), null_safe(trig_sindouble_rule))(integral) def trig_substitution_rule(integral): integrand, symbol = integral A = sympy.Wild('a', exclude=[0, symbol]) B = sympy.Wild('b', exclude=[0, symbol]) theta = sympy.Dummy("theta") target_pattern = A + B*symbol**2 matches = integrand.find(target_pattern) for expr in matches: match = expr.match(target_pattern) a = match.get(A, ZERO) b = match.get(B, ZERO) a_positive = ((a.is_number and a > 0) or a.is_positive) b_positive = ((b.is_number and b > 0) or b.is_positive) a_negative = ((a.is_number and a < 0) or a.is_negative) b_negative = ((b.is_number and b < 0) or b.is_negative) x_func = None if a_positive and b_positive: # a**2 + b*x**2. Assume sec(theta) > 0, -pi/2 < theta < pi/2 x_func = (sympy.sqrt(a)/sympy.sqrt(b)) * sympy.tan(theta) # Do not restrict the domain: tan(theta) takes on any real # value on the interval -pi/2 < theta < pi/2 so x takes on # any value restriction = True elif a_positive and b_negative: # a**2 - b*x**2. Assume cos(theta) > 0, -pi/2 < theta < pi/2 constant = sympy.sqrt(a)/sympy.sqrt(-b) x_func = constant * sympy.sin(theta) restriction = sympy.And(symbol > -constant, symbol < constant) elif a_negative and b_positive: # b*x**2 - a**2. Assume sin(theta) > 0, 0 < theta < pi constant = sympy.sqrt(-a)/sympy.sqrt(b) x_func = constant * sympy.sec(theta) restriction = sympy.And(symbol > -constant, symbol < constant) if x_func: # Manually simplify sqrt(trig(theta)**2) to trig(theta) # Valid due to assumed domain restriction substitutions = {} for f in [sympy.sin, sympy.cos, sympy.tan, sympy.sec, sympy.csc, sympy.cot]: substitutions[sympy.sqrt(f(theta)**2)] = f(theta) substitutions[sympy.sqrt(f(theta)**(-2))] = 1/f(theta) replaced = integrand.subs(symbol, x_func).trigsimp() replaced = manual_subs(replaced, substitutions) if not replaced.has(symbol): replaced *= manual_diff(x_func, theta) replaced = replaced.trigsimp() secants = replaced.find(1/sympy.cos(theta)) if secants: replaced = replaced.xreplace({ 1/sympy.cos(theta): sympy.sec(theta) }) substep = integral_steps(replaced, theta) if not contains_dont_know(substep): return TrigSubstitutionRule( theta, x_func, replaced, substep, restriction, integrand, symbol) def heaviside_rule(integral): integrand, symbol = integral pattern, m, b, g = heaviside_pattern(symbol) match = integrand.match(pattern) if match and 0 != match[g]: # f = Heaviside(m*x + b)*g v_step = integral_steps(match[g], symbol) result = _manualintegrate(v_step) m, b = match[m], match[b] return HeavisideRule(m*symbol + b, -b/m, result, integrand, symbol) def substitution_rule(integral): integrand, symbol = integral u_var = sympy.Dummy("u") substitutions = find_substitutions(integrand, symbol, u_var) count = 0 if substitutions: debug("List of Substitution Rules") ways = [] for u_func, c, substituted in substitutions: subrule = integral_steps(substituted, u_var) count = count + 1 debug("Rule {}: {}".format(count, subrule)) if contains_dont_know(subrule): continue if sympy.simplify(c - 1) != 0: _, denom = c.as_numer_denom() if subrule: subrule = ConstantTimesRule(c, substituted, subrule, substituted, u_var) if denom.free_symbols: piecewise = [] could_be_zero = [] if isinstance(denom, sympy.Mul): could_be_zero = denom.args else: could_be_zero.append(denom) for expr in could_be_zero: if not fuzzy_not(expr.is_zero): substep = integral_steps(manual_subs(integrand, expr, 0), symbol) if substep: piecewise.append(( substep, sympy.Eq(expr, 0) )) piecewise.append((subrule, True)) subrule = PiecewiseRule(piecewise, substituted, symbol) ways.append(URule(u_var, u_func, c, subrule, integrand, symbol)) if len(ways) > 1: return AlternativeRule(ways, integrand, symbol) elif ways: return ways[0] elif integrand.has(sympy.exp): u_func = sympy.exp(symbol) c = 1 substituted = integrand / u_func.diff(symbol) substituted = substituted.subs(u_func, u_var) if symbol not in substituted.free_symbols: return URule(u_var, u_func, c, integral_steps(substituted, u_var), integrand, symbol) partial_fractions_rule = rewriter( lambda integrand, symbol: integrand.is_rational_function(), lambda integrand, symbol: integrand.apart(symbol)) cancel_rule = rewriter( # lambda integrand, symbol: integrand.is_algebraic_expr(), # lambda integrand, symbol: isinstance(integrand, sympy.Mul), lambda integrand, symbol: True, lambda integrand, symbol: integrand.cancel()) distribute_expand_rule = rewriter( lambda integrand, symbol: ( all(arg.is_Pow or arg.is_polynomial(symbol) for arg in integrand.args) or isinstance(integrand, sympy.Pow) or isinstance(integrand, sympy.Mul)), lambda integrand, symbol: integrand.expand()) trig_expand_rule = rewriter( # If there are trig functions with different arguments, expand them lambda integrand, symbol: ( len({a.args[0] for a in integrand.atoms(TrigonometricFunction)}) > 1), lambda integrand, symbol: integrand.expand(trig=True)) def derivative_rule(integral): integrand = integral[0] diff_variables = integrand.variables undifferentiated_function = integrand.expr integrand_variables = undifferentiated_function.free_symbols if integral.symbol in integrand_variables: if integral.symbol in diff_variables: return DerivativeRule(*integral) else: return DontKnowRule(integrand, integral.symbol) else: return ConstantRule(integral.integrand, *integral) def rewrites_rule(integral): integrand, symbol = integral if integrand.match(1/sympy.cos(symbol)): rewritten = integrand.subs(1/sympy.cos(symbol), sympy.sec(symbol)) return RewriteRule(rewritten, integral_steps(rewritten, symbol), integrand, symbol) def fallback_rule(integral): return DontKnowRule(*integral) # Cache is used to break cyclic integrals. # Need to use the same dummy variable in cached expressions for them to match. # Also record "u" of integration by parts, to avoid infinite repetition. _integral_cache = {} # type: tDict[Expr, Optional[Expr]] _parts_u_cache = defaultdict(int) # type: tDict[Expr, int] _cache_dummy = sympy.Dummy("z") def integral_steps(integrand, symbol, **options): """Returns the steps needed to compute an integral. Explanation =========== This function attempts to mirror what a student would do by hand as closely as possible. SymPy Gamma uses this to provide a step-by-step explanation of an integral. The code it uses to format the results of this function can be found at https://github.com/sympy/sympy_gamma/blob/master/app/logic/intsteps.py. Examples ======== >>> from sympy import exp, sin >>> from sympy.integrals.manualintegrate import integral_steps >>> from sympy.abc import x >>> print(repr(integral_steps(exp(x) / (1 + exp(2 * x)), x))) \ # doctest: +NORMALIZE_WHITESPACE URule(u_var=_u, u_func=exp(x), constant=1, substep=PiecewiseRule(subfunctions=[(ArctanRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), True), (ArccothRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), False), (ArctanhRule(a=1, b=1, c=1, context=1/(_u**2 + 1), symbol=_u), False)], context=1/(_u**2 + 1), symbol=_u), context=exp(x)/(exp(2*x) + 1), symbol=x) >>> print(repr(integral_steps(sin(x), x))) \ # doctest: +NORMALIZE_WHITESPACE TrigRule(func='sin', arg=x, context=sin(x), symbol=x) >>> print(repr(integral_steps((x**2 + 3)**2 , x))) \ # doctest: +NORMALIZE_WHITESPACE RewriteRule(rewritten=x**4 + 6*x**2 + 9, substep=AddRule(substeps=[PowerRule(base=x, exp=4, context=x**4, symbol=x), ConstantTimesRule(constant=6, other=x**2, substep=PowerRule(base=x, exp=2, context=x**2, symbol=x), context=6*x**2, symbol=x), ConstantRule(constant=9, context=9, symbol=x)], context=x**4 + 6*x**2 + 9, symbol=x), context=(x**2 + 3)**2, symbol=x) Returns ======= rule : namedtuple The first step; most rules have substeps that must also be considered. These substeps can be evaluated using ``manualintegrate`` to obtain a result. """ cachekey = integrand.xreplace({symbol: _cache_dummy}) if cachekey in _integral_cache: if _integral_cache[cachekey] is None: # Stop this attempt, because it leads around in a loop return DontKnowRule(integrand, symbol) else: # TODO: This is for future development, as currently # _integral_cache gets no values other than None return (_integral_cache[cachekey].xreplace(_cache_dummy, symbol), symbol) else: _integral_cache[cachekey] = None integral = IntegralInfo(integrand, symbol) def key(integral): integrand = integral.integrand if isinstance(integrand, TrigonometricFunction): return TrigonometricFunction elif isinstance(integrand, sympy.Derivative): return sympy.Derivative elif symbol not in integrand.free_symbols: return sympy.Number else: for cls in (sympy.Pow, sympy.Symbol, sympy.exp, sympy.log, sympy.Add, sympy.Mul, *inverse_trig_functions, sympy.Heaviside, OrthogonalPolynomial): if isinstance(integrand, cls): return cls def integral_is_subclass(*klasses): def _integral_is_subclass(integral): k = key(integral) return k and issubclass(k, klasses) return _integral_is_subclass result = do_one( null_safe(special_function_rule), null_safe(switch(key, { sympy.Pow: do_one(null_safe(power_rule), null_safe(inverse_trig_rule), \ null_safe(quadratic_denom_rule)), sympy.Symbol: power_rule, sympy.exp: exp_rule, sympy.Add: add_rule, sympy.Mul: do_one(null_safe(mul_rule), null_safe(trig_product_rule), \ null_safe(heaviside_rule), null_safe(quadratic_denom_rule), \ null_safe(root_mul_rule)), sympy.Derivative: derivative_rule, TrigonometricFunction: trig_rule, sympy.Heaviside: heaviside_rule, OrthogonalPolynomial: orthogonal_poly_rule, sympy.Number: constant_rule })), do_one( null_safe(trig_rule), null_safe(alternatives( rewrites_rule, substitution_rule, condition( integral_is_subclass(sympy.Mul, sympy.Pow), partial_fractions_rule), condition( integral_is_subclass(sympy.Mul, sympy.Pow), cancel_rule), condition( integral_is_subclass(sympy.Mul, sympy.log, *inverse_trig_functions), parts_rule), condition( integral_is_subclass(sympy.Mul, sympy.Pow), distribute_expand_rule), trig_powers_products_rule, trig_expand_rule )), null_safe(trig_substitution_rule) ), fallback_rule)(integral) del _integral_cache[cachekey] return result @evaluates(ConstantRule) def eval_constant(constant, integrand, symbol): return constant * symbol @evaluates(ConstantTimesRule) def eval_constanttimes(constant, other, substep, integrand, symbol): return constant * _manualintegrate(substep) @evaluates(PowerRule) def eval_power(base, exp, integrand, symbol): return sympy.Piecewise( ((base**(exp + 1))/(exp + 1), sympy.Ne(exp, -1)), (sympy.log(base), True), ) @evaluates(ExpRule) def eval_exp(base, exp, integrand, symbol): return integrand / sympy.ln(base) @evaluates(AddRule) def eval_add(substeps, integrand, symbol): return sum(map(_manualintegrate, substeps)) @evaluates(URule) def eval_u(u_var, u_func, constant, substep, integrand, symbol): result = _manualintegrate(substep) if u_func.is_Pow and u_func.exp == -1: # avoid needless -log(1/x) from substitution result = result.subs(sympy.log(u_var), -sympy.log(u_func.base)) return result.subs(u_var, u_func) @evaluates(PartsRule) def eval_parts(u, dv, v_step, second_step, integrand, symbol): v = _manualintegrate(v_step) return u * v - _manualintegrate(second_step) @evaluates(CyclicPartsRule) def eval_cyclicparts(parts_rules, coefficient, integrand, symbol): coefficient = 1 - coefficient result = [] sign = 1 for rule in parts_rules: result.append(sign * rule.u * _manualintegrate(rule.v_step)) sign *= -1 return sympy.Add(*result) / coefficient @evaluates(TrigRule) def eval_trig(func, arg, integrand, symbol): if func == 'sin': return -sympy.cos(arg) elif func == 'cos': return sympy.sin(arg) elif func == 'sec*tan': return sympy.sec(arg) elif func == 'csc*cot': return sympy.csc(arg) elif func == 'sec**2': return sympy.tan(arg) elif func == 'csc**2': return -sympy.cot(arg) @evaluates(ArctanRule) def eval_arctan(a, b, c, integrand, symbol): return a / b * 1 / sympy.sqrt(c / b) * sympy.atan(symbol / sympy.sqrt(c / b)) @evaluates(ArccothRule) def eval_arccoth(a, b, c, integrand, symbol): return - a / b * 1 / sympy.sqrt(-c / b) * sympy.acoth(symbol / sympy.sqrt(-c / b)) @evaluates(ArctanhRule) def eval_arctanh(a, b, c, integrand, symbol): return - a / b * 1 / sympy.sqrt(-c / b) * sympy.atanh(symbol / sympy.sqrt(-c / b)) @evaluates(ReciprocalRule) def eval_reciprocal(func, integrand, symbol): return sympy.ln(func) @evaluates(ArcsinRule) def eval_arcsin(integrand, symbol): return sympy.asin(symbol) @evaluates(InverseHyperbolicRule) def eval_inversehyperbolic(func, integrand, symbol): return func(symbol) @evaluates(AlternativeRule) def eval_alternative(alternatives, integrand, symbol): return _manualintegrate(alternatives[0]) @evaluates(RewriteRule) def eval_rewrite(rewritten, substep, integrand, symbol): return _manualintegrate(substep) @evaluates(PiecewiseRule) def eval_piecewise(substeps, integrand, symbol): return sympy.Piecewise(*[(_manualintegrate(substep), cond) for substep, cond in substeps]) @evaluates(TrigSubstitutionRule) def eval_trigsubstitution(theta, func, rewritten, substep, restriction, integrand, symbol): func = func.subs(sympy.sec(theta), 1/sympy.cos(theta)) func = func.subs(sympy.csc(theta), 1/sympy.sin(theta)) func = func.subs(sympy.cot(theta), 1/sympy.tan(theta)) trig_function = list(func.find(TrigonometricFunction)) assert len(trig_function) == 1 trig_function = trig_function[0] relation = sympy.solve(symbol - func, trig_function) assert len(relation) == 1 numer, denom = sympy.fraction(relation[0]) if isinstance(trig_function, sympy.sin): opposite = numer hypotenuse = denom adjacent = sympy.sqrt(denom**2 - numer**2) inverse = sympy.asin(relation[0]) elif isinstance(trig_function, sympy.cos): adjacent = numer hypotenuse = denom opposite = sympy.sqrt(denom**2 - numer**2) inverse = sympy.acos(relation[0]) elif isinstance(trig_function, sympy.tan): opposite = numer adjacent = denom hypotenuse = sympy.sqrt(denom**2 + numer**2) inverse = sympy.atan(relation[0]) substitution = [ (sympy.sin(theta), opposite/hypotenuse), (sympy.cos(theta), adjacent/hypotenuse), (sympy.tan(theta), opposite/adjacent), (theta, inverse) ] return sympy.Piecewise( (_manualintegrate(substep).subs(substitution).trigsimp(), restriction) ) @evaluates(DerivativeRule) def eval_derivativerule(integrand, symbol): # isinstance(integrand, Derivative) should be True variable_count = list(integrand.variable_count) for i, (var, count) in enumerate(variable_count): if var == symbol: variable_count[i] = (var, count-1) break return sympy.Derivative(integrand.expr, *variable_count) @evaluates(HeavisideRule) def eval_heaviside(harg, ibnd, substep, integrand, symbol): # If we are integrating over x and the integrand has the form # Heaviside(m*x+b)*g(x) == Heaviside(harg)*g(symbol) # then there needs to be continuity at -b/m == ibnd, # so we subtract the appropriate term. return sympy.Heaviside(harg)*(substep - substep.subs(symbol, ibnd)) @evaluates(JacobiRule) def eval_jacobi(n, a, b, integrand, symbol): return Piecewise( (2*sympy.jacobi(n + 1, a - 1, b - 1, symbol)/(n + a + b), Ne(n + a + b, 0)), (symbol, Eq(n, 0)), ((a + b + 2)*symbol**2/4 + (a - b)*symbol/2, Eq(n, 1))) @evaluates(GegenbauerRule) def eval_gegenbauer(n, a, integrand, symbol): return Piecewise( (sympy.gegenbauer(n + 1, a - 1, symbol)/(2*(a - 1)), Ne(a, 1)), (sympy.chebyshevt(n + 1, symbol)/(n + 1), Ne(n, -1)), (sympy.S.Zero, True)) @evaluates(ChebyshevTRule) def eval_chebyshevt(n, integrand, symbol): return Piecewise(((sympy.chebyshevt(n + 1, symbol)/(n + 1) - sympy.chebyshevt(n - 1, symbol)/(n - 1))/2, Ne(sympy.Abs(n), 1)), (symbol**2/2, True)) @evaluates(ChebyshevURule) def eval_chebyshevu(n, integrand, symbol): return Piecewise( (sympy.chebyshevt(n + 1, symbol)/(n + 1), Ne(n, -1)), (sympy.S.Zero, True)) @evaluates(LegendreRule) def eval_legendre(n, integrand, symbol): return (sympy.legendre(n + 1, symbol) - sympy.legendre(n - 1, symbol))/(2*n + 1) @evaluates(HermiteRule) def eval_hermite(n, integrand, symbol): return sympy.hermite(n + 1, symbol)/(2*(n + 1)) @evaluates(LaguerreRule) def eval_laguerre(n, integrand, symbol): return sympy.laguerre(n, symbol) - sympy.laguerre(n + 1, symbol) @evaluates(AssocLaguerreRule) def eval_assoclaguerre(n, a, integrand, symbol): return -sympy.assoc_laguerre(n + 1, a - 1, symbol) @evaluates(CiRule) def eval_ci(a, b, integrand, symbol): return sympy.cos(b)*sympy.Ci(a*symbol) - sympy.sin(b)*sympy.Si(a*symbol) @evaluates(ChiRule) def eval_chi(a, b, integrand, symbol): return sympy.cosh(b)*sympy.Chi(a*symbol) + sympy.sinh(b)*sympy.Shi(a*symbol) @evaluates(EiRule) def eval_ei(a, b, integrand, symbol): return sympy.exp(b)*sympy.Ei(a*symbol) @evaluates(SiRule) def eval_si(a, b, integrand, symbol): return sympy.sin(b)*sympy.Ci(a*symbol) + sympy.cos(b)*sympy.Si(a*symbol) @evaluates(ShiRule) def eval_shi(a, b, integrand, symbol): return sympy.sinh(b)*sympy.Chi(a*symbol) + sympy.cosh(b)*sympy.Shi(a*symbol) @evaluates(ErfRule) def eval_erf(a, b, c, integrand, symbol): if a.is_extended_real: return Piecewise( (sympy.sqrt(sympy.pi/(-a))/2 * sympy.exp(c - b**2/(4*a)) * sympy.erf((-2*a*symbol - b)/(2*sympy.sqrt(-a))), a < 0), (sympy.sqrt(sympy.pi/a)/2 * sympy.exp(c - b**2/(4*a)) * sympy.erfi((2*a*symbol + b)/(2*sympy.sqrt(a))), True)) else: return sympy.sqrt(sympy.pi/a)/2 * sympy.exp(c - b**2/(4*a)) * \ sympy.erfi((2*a*symbol + b)/(2*sympy.sqrt(a))) @evaluates(FresnelCRule) def eval_fresnelc(a, b, c, integrand, symbol): return sympy.sqrt(sympy.pi/(2*a)) * ( sympy.cos(b**2/(4*a) - c)*sympy.fresnelc((2*a*symbol + b)/sympy.sqrt(2*a*sympy.pi)) + sympy.sin(b**2/(4*a) - c)*sympy.fresnels((2*a*symbol + b)/sympy.sqrt(2*a*sympy.pi))) @evaluates(FresnelSRule) def eval_fresnels(a, b, c, integrand, symbol): return sympy.sqrt(sympy.pi/(2*a)) * ( sympy.cos(b**2/(4*a) - c)*sympy.fresnels((2*a*symbol + b)/sympy.sqrt(2*a*sympy.pi)) - sympy.sin(b**2/(4*a) - c)*sympy.fresnelc((2*a*symbol + b)/sympy.sqrt(2*a*sympy.pi))) @evaluates(LiRule) def eval_li(a, b, integrand, symbol): return sympy.li(a*symbol + b)/a @evaluates(PolylogRule) def eval_polylog(a, b, integrand, symbol): return sympy.polylog(b + 1, a*symbol) @evaluates(UpperGammaRule) def eval_uppergamma(a, e, integrand, symbol): return symbol**e * (-a*symbol)**(-e) * sympy.uppergamma(e + 1, -a*symbol)/a @evaluates(EllipticFRule) def eval_elliptic_f(a, d, integrand, symbol): return sympy.elliptic_f(symbol, d/a)/sympy.sqrt(a) @evaluates(EllipticERule) def eval_elliptic_e(a, d, integrand, symbol): return sympy.elliptic_e(symbol, d/a)*sympy.sqrt(a) @evaluates(DontKnowRule) def eval_dontknowrule(integrand, symbol): return sympy.Integral(integrand, symbol) def _manualintegrate(rule): evaluator = evaluators.get(rule.__class__) if not evaluator: raise ValueError("Cannot evaluate rule %s" % repr(rule)) return evaluator(*rule) def manualintegrate(f, var): """manualintegrate(f, var) Explanation =========== Compute indefinite integral of a single variable using an algorithm that resembles what a student would do by hand. Unlike :func:`~.integrate`, var can only be a single symbol. Examples ======== >>> from sympy import sin, cos, tan, exp, log, integrate >>> from sympy.integrals.manualintegrate import manualintegrate >>> from sympy.abc import x >>> manualintegrate(1 / x, x) log(x) >>> integrate(1/x) log(x) >>> manualintegrate(log(x), x) x*log(x) - x >>> integrate(log(x)) x*log(x) - x >>> manualintegrate(exp(x) / (1 + exp(2 * x)), x) atan(exp(x)) >>> integrate(exp(x) / (1 + exp(2 * x))) RootSum(4*_z**2 + 1, Lambda(_i, _i*log(2*_i + exp(x)))) >>> manualintegrate(cos(x)**4 * sin(x), x) -cos(x)**5/5 >>> integrate(cos(x)**4 * sin(x), x) -cos(x)**5/5 >>> manualintegrate(cos(x)**4 * sin(x)**3, x) cos(x)**7/7 - cos(x)**5/5 >>> integrate(cos(x)**4 * sin(x)**3, x) cos(x)**7/7 - cos(x)**5/5 >>> manualintegrate(tan(x), x) -log(cos(x)) >>> integrate(tan(x), x) -log(cos(x)) See Also ======== sympy.integrals.integrals.integrate sympy.integrals.integrals.Integral.doit sympy.integrals.integrals.Integral """ result = _manualintegrate(integral_steps(f, var)) # Clear the cache of u-parts _parts_u_cache.clear() # If we got Piecewise with two parts, put generic first if isinstance(result, Piecewise) and len(result.args) == 2: cond = result.args[0][1] if isinstance(cond, Eq) and result.args[1][1] == True: result = result.func( (result.args[1][0], sympy.Ne(*cond.args)), (result.args[0][0], True)) return result sympy-sympy-1.9/sympy/integrals/meijerint.py000066400000000000000000002311431412543434000214400ustar00rootroot00000000000000""" Integrate functions by rewriting them as Meijer G-functions. There are three user-visible functions that can be used by other parts of the sympy library to solve various integration problems: - meijerint_indefinite - meijerint_definite - meijerint_inversion They can be used to compute, respectively, indefinite integrals, definite integrals over intervals of the real line, and inverse laplace-type integrals (from c-I*oo to c+I*oo). See the respective docstrings for details. The main references for this are: [L] Luke, Y. L. (1969), The Special Functions and Their Approximations, Volume 1 [R] Kelly B. Roach. Meijer G Function Representations. In: Proceedings of the 1997 International Symposium on Symbolic and Algebraic Computation, pages 205-211, New York, 1997. ACM. [P] A. P. Prudnikov, Yu. A. Brychkov and O. I. Marichev (1990). Integrals and Series: More Special Functions, Vol. 3,. Gordon and Breach Science Publisher """ from typing import Dict, Tuple from sympy.core import oo, S, pi, Expr from sympy.core.exprtools import factor_terms from sympy.core.function import expand, expand_mul, expand_power_base from sympy.core.add import Add from sympy.core.mul import Mul from sympy.core.numbers import Rational from sympy.core.cache import cacheit from sympy.core.symbol import Dummy, Wild from sympy.simplify import hyperexpand, powdenest, collect from sympy.simplify.fu import sincos_to_sum from sympy.logic.boolalg import And, Or, BooleanAtom from sympy.functions.special.delta_functions import DiracDelta, Heaviside from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold from sympy.functions.elementary.hyperbolic import \ _rewrite_hyperbolics_as_exp, HyperbolicFunction from sympy.functions.elementary.trigonometric import cos, sin from sympy.functions.special.hyper import meijerg from sympy.utilities.iterables import multiset_partitions, ordered from sympy.utilities.misc import debug as _debug from sympy.utilities import default_sort_key # keep this at top for easy reference z = Dummy('z') def _has(res, *f): # return True if res has f; in the case of Piecewise # only return True if *all* pieces have f res = piecewise_fold(res) if getattr(res, 'is_Piecewise', False): return all(_has(i, *f) for i in res.args) return res.has(*f) def _create_lookup_table(table): """ Add formulae for the function -> meijerg lookup table. """ def wild(n): return Wild(n, exclude=[z]) p, q, a, b, c = list(map(wild, 'pqabc')) n = Wild('n', properties=[lambda x: x.is_Integer and x > 0]) t = p*z**q def add(formula, an, ap, bm, bq, arg=t, fac=S.One, cond=True, hint=True): table.setdefault(_mytype(formula, z), []).append((formula, [(fac, meijerg(an, ap, bm, bq, arg))], cond, hint)) def addi(formula, inst, cond, hint=True): table.setdefault( _mytype(formula, z), []).append((formula, inst, cond, hint)) def constant(a): return [(a, meijerg([1], [], [], [0], z)), (a, meijerg([], [1], [0], [], z))] table[()] = [(a, constant(a), True, True)] # [P], Section 8. from sympy import unpolarify, Function, Not class IsNonPositiveInteger(Function): @classmethod def eval(cls, arg): arg = unpolarify(arg) if arg.is_Integer is True: return arg <= 0 # Section 8.4.2 from sympy import (gamma, pi, cos, exp, re, sin, sinc, sqrt, sinh, cosh, factorial, log, erf, erfc, erfi, polar_lift) # TODO this needs more polar_lift (c/f entry for exp) add(Heaviside(t - b)*(t - b)**(a - 1), [a], [], [], [0], t/b, gamma(a)*b**(a - 1), And(b > 0)) add(Heaviside(b - t)*(b - t)**(a - 1), [], [a], [0], [], t/b, gamma(a)*b**(a - 1), And(b > 0)) add(Heaviside(z - (b/p)**(1/q))*(t - b)**(a - 1), [a], [], [], [0], t/b, gamma(a)*b**(a - 1), And(b > 0)) add(Heaviside((b/p)**(1/q) - z)*(b - t)**(a - 1), [], [a], [0], [], t/b, gamma(a)*b**(a - 1), And(b > 0)) add((b + t)**(-a), [1 - a], [], [0], [], t/b, b**(-a)/gamma(a), hint=Not(IsNonPositiveInteger(a))) add(abs(b - t)**(-a), [1 - a], [(1 - a)/2], [0], [(1 - a)/2], t/b, 2*sin(pi*a/2)*gamma(1 - a)*abs(b)**(-a), re(a) < 1) add((t**a - b**a)/(t - b), [0, a], [], [0, a], [], t/b, b**(a - 1)*sin(a*pi)/pi) # 12 def A1(r, sign, nu): return pi**Rational(-1, 2)*(-sign*nu/2)**(1 - 2*r) def tmpadd(r, sgn): # XXX the a**2 is bad for matching add((sqrt(a**2 + t) + sgn*a)**b/(a**2 + t)**r, [(1 + b)/2, 1 - 2*r + b/2], [], [(b - sgn*b)/2], [(b + sgn*b)/2], t/a**2, a**(b - 2*r)*A1(r, sgn, b)) tmpadd(0, 1) tmpadd(0, -1) tmpadd(S.Half, 1) tmpadd(S.Half, -1) # 13 def tmpadd(r, sgn): add((sqrt(a + p*z**q) + sgn*sqrt(p)*z**(q/2))**b/(a + p*z**q)**r, [1 - r + sgn*b/2], [1 - r - sgn*b/2], [0, S.Half], [], p*z**q/a, a**(b/2 - r)*A1(r, sgn, b)) tmpadd(0, 1) tmpadd(0, -1) tmpadd(S.Half, 1) tmpadd(S.Half, -1) # (those after look obscure) # Section 8.4.3 add(exp(polar_lift(-1)*t), [], [], [0], []) # TODO can do sin^n, sinh^n by expansion ... where? # 8.4.4 (hyperbolic functions) add(sinh(t), [], [1], [S.Half], [1, 0], t**2/4, pi**Rational(3, 2)) add(cosh(t), [], [S.Half], [0], [S.Half, S.Half], t**2/4, pi**Rational(3, 2)) # Section 8.4.5 # TODO can do t + a. but can also do by expansion... (XXX not really) add(sin(t), [], [], [S.Half], [0], t**2/4, sqrt(pi)) add(cos(t), [], [], [0], [S.Half], t**2/4, sqrt(pi)) # Section 8.4.6 (sinc function) add(sinc(t), [], [], [0], [Rational(-1, 2)], t**2/4, sqrt(pi)/2) # Section 8.5.5 def make_log1(subs): N = subs[n] return [((-1)**N*factorial(N), meijerg([], [1]*(N + 1), [0]*(N + 1), [], t))] def make_log2(subs): N = subs[n] return [(factorial(N), meijerg([1]*(N + 1), [], [], [0]*(N + 1), t))] # TODO these only hold for positive p, and can be made more general # but who uses log(x)*Heaviside(a-x) anyway ... # TODO also it would be nice to derive them recursively ... addi(log(t)**n*Heaviside(1 - t), make_log1, True) addi(log(t)**n*Heaviside(t - 1), make_log2, True) def make_log3(subs): return make_log1(subs) + make_log2(subs) addi(log(t)**n, make_log3, True) addi(log(t + a), constant(log(a)) + [(S.One, meijerg([1, 1], [], [1], [0], t/a))], True) addi(log(abs(t - a)), constant(log(abs(a))) + [(pi, meijerg([1, 1], [S.Half], [1], [0, S.Half], t/a))], True) # TODO log(x)/(x+a) and log(x)/(x-1) can also be done. should they # be derivable? # TODO further formulae in this section seem obscure # Sections 8.4.9-10 # TODO # Section 8.4.11 from sympy import Ei, I, expint, Si, Ci, Shi, Chi, fresnels, fresnelc addi(Ei(t), constant(-I*pi) + [(S.NegativeOne, meijerg([], [1], [0, 0], [], t*polar_lift(-1)))], True) # Section 8.4.12 add(Si(t), [1], [], [S.Half], [0, 0], t**2/4, sqrt(pi)/2) add(Ci(t), [], [1], [0, 0], [S.Half], t**2/4, -sqrt(pi)/2) # Section 8.4.13 add(Shi(t), [S.Half], [], [0], [Rational(-1, 2), Rational(-1, 2)], polar_lift(-1)*t**2/4, t*sqrt(pi)/4) add(Chi(t), [], [S.Half, 1], [0, 0], [S.Half, S.Half], t**2/4, - pi**S('3/2')/2) # generalized exponential integral add(expint(a, t), [], [a], [a - 1, 0], [], t) # Section 8.4.14 add(erf(t), [1], [], [S.Half], [0], t**2, 1/sqrt(pi)) # TODO exp(-x)*erf(I*x) does not work add(erfc(t), [], [1], [0, S.Half], [], t**2, 1/sqrt(pi)) # This formula for erfi(z) yields a wrong(?) minus sign #add(erfi(t), [1], [], [S.Half], [0], -t**2, I/sqrt(pi)) add(erfi(t), [S.Half], [], [0], [Rational(-1, 2)], -t**2, t/sqrt(pi)) # Fresnel Integrals add(fresnels(t), [1], [], [Rational(3, 4)], [0, Rational(1, 4)], pi**2*t**4/16, S.Half) add(fresnelc(t), [1], [], [Rational(1, 4)], [0, Rational(3, 4)], pi**2*t**4/16, S.Half) ##### bessel-type functions ##### from sympy import besselj, bessely, besseli, besselk # Section 8.4.19 add(besselj(a, t), [], [], [a/2], [-a/2], t**2/4) # all of the following are derivable #add(sin(t)*besselj(a, t), [Rational(1, 4), Rational(3, 4)], [], [(1+a)/2], # [-a/2, a/2, (1-a)/2], t**2, 1/sqrt(2)) #add(cos(t)*besselj(a, t), [Rational(1, 4), Rational(3, 4)], [], [a/2], # [-a/2, (1+a)/2, (1-a)/2], t**2, 1/sqrt(2)) #add(besselj(a, t)**2, [S.Half], [], [a], [-a, 0], t**2, 1/sqrt(pi)) #add(besselj(a, t)*besselj(b, t), [0, S.Half], [], [(a + b)/2], # [-(a+b)/2, (a - b)/2, (b - a)/2], t**2, 1/sqrt(pi)) # Section 8.4.20 add(bessely(a, t), [], [-(a + 1)/2], [a/2, -a/2], [-(a + 1)/2], t**2/4) # TODO all of the following should be derivable #add(sin(t)*bessely(a, t), [Rational(1, 4), Rational(3, 4)], [(1 - a - 1)/2], # [(1 + a)/2, (1 - a)/2], [(1 - a - 1)/2, (1 - 1 - a)/2, (1 - 1 + a)/2], # t**2, 1/sqrt(2)) #add(cos(t)*bessely(a, t), [Rational(1, 4), Rational(3, 4)], [(0 - a - 1)/2], # [(0 + a)/2, (0 - a)/2], [(0 - a - 1)/2, (1 - 0 - a)/2, (1 - 0 + a)/2], # t**2, 1/sqrt(2)) #add(besselj(a, t)*bessely(b, t), [0, S.Half], [(a - b - 1)/2], # [(a + b)/2, (a - b)/2], [(a - b - 1)/2, -(a + b)/2, (b - a)/2], # t**2, 1/sqrt(pi)) #addi(bessely(a, t)**2, # [(2/sqrt(pi), meijerg([], [S.Half, S.Half - a], [0, a, -a], # [S.Half - a], t**2)), # (1/sqrt(pi), meijerg([S.Half], [], [a], [-a, 0], t**2))], # True) #addi(bessely(a, t)*bessely(b, t), # [(2/sqrt(pi), meijerg([], [0, S.Half, (1 - a - b)/2], # [(a + b)/2, (a - b)/2, (b - a)/2, -(a + b)/2], # [(1 - a - b)/2], t**2)), # (1/sqrt(pi), meijerg([0, S.Half], [], [(a + b)/2], # [-(a + b)/2, (a - b)/2, (b - a)/2], t**2))], # True) # Section 8.4.21 ? # Section 8.4.22 add(besseli(a, t), [], [(1 + a)/2], [a/2], [-a/2, (1 + a)/2], t**2/4, pi) # TODO many more formulas. should all be derivable # Section 8.4.23 add(besselk(a, t), [], [], [a/2, -a/2], [], t**2/4, S.Half) # TODO many more formulas. should all be derivable # Complete elliptic integrals K(z) and E(z) from sympy import elliptic_k, elliptic_e add(elliptic_k(t), [S.Half, S.Half], [], [0], [0], -t, S.Half) add(elliptic_e(t), [S.Half, 3*S.Half], [], [0], [0], -t, Rational(-1, 2)/2) #################################################################### # First some helper functions. #################################################################### from sympy.utilities.timeutils import timethis timeit = timethis('meijerg') def _mytype(f, x): """ Create a hashable entity describing the type of f. """ if x not in f.free_symbols: return () elif f.is_Function: return (type(f),) else: types = [_mytype(a, x) for a in f.args] res = [] for t in types: res += list(t) res.sort() return tuple(res) class _CoeffExpValueError(ValueError): """ Exception raised by _get_coeff_exp, for internal use only. """ pass def _get_coeff_exp(expr, x): """ When expr is known to be of the form c*x**b, with c and/or b possibly 1, return c, b. Examples ======== >>> from sympy.abc import x, a, b >>> from sympy.integrals.meijerint import _get_coeff_exp >>> _get_coeff_exp(a*x**b, x) (a, b) >>> _get_coeff_exp(x, x) (1, 1) >>> _get_coeff_exp(2*x, x) (2, 1) >>> _get_coeff_exp(x**3, x) (1, 3) """ from sympy import powsimp (c, m) = expand_power_base(powsimp(expr)).as_coeff_mul(x) if not m: return c, S.Zero [m] = m if m.is_Pow: if m.base != x: raise _CoeffExpValueError('expr not of form a*x**b') return c, m.exp elif m == x: return c, S.One else: raise _CoeffExpValueError('expr not of form a*x**b: %s' % expr) def _exponents(expr, x): """ Find the exponents of ``x`` (not including zero) in ``expr``. Examples ======== >>> from sympy.integrals.meijerint import _exponents >>> from sympy.abc import x, y >>> from sympy import sin >>> _exponents(x, x) {1} >>> _exponents(x**2, x) {2} >>> _exponents(x**2 + x, x) {1, 2} >>> _exponents(x**3*sin(x + x**y) + 1/x, x) {-1, 1, 3, y} """ def _exponents_(expr, x, res): if expr == x: res.update([1]) return if expr.is_Pow and expr.base == x: res.update([expr.exp]) return for arg in expr.args: _exponents_(arg, x, res) res = set() _exponents_(expr, x, res) return res def _functions(expr, x): """ Find the types of functions in expr, to estimate the complexity. """ from sympy import Function return {e.func for e in expr.atoms(Function) if x in e.free_symbols} def _find_splitting_points(expr, x): """ Find numbers a such that a linear substitution x -> x + a would (hopefully) simplify expr. Examples ======== >>> from sympy.integrals.meijerint import _find_splitting_points as fsp >>> from sympy import sin >>> from sympy.abc import x >>> fsp(x, x) {0} >>> fsp((x-1)**3, x) {1} >>> fsp(sin(x+3)*x, x) {-3, 0} """ p, q = [Wild(n, exclude=[x]) for n in 'pq'] def compute_innermost(expr, res): if not isinstance(expr, Expr): return m = expr.match(p*x + q) if m and m[p] != 0: res.add(-m[q]/m[p]) return if expr.is_Atom: return for arg in expr.args: compute_innermost(arg, res) innermost = set() compute_innermost(expr, innermost) return innermost def _split_mul(f, x): """ Split expression ``f`` into fac, po, g, where fac is a constant factor, po = x**s for some s independent of s, and g is "the rest". Examples ======== >>> from sympy.integrals.meijerint import _split_mul >>> from sympy import sin >>> from sympy.abc import s, x >>> _split_mul((3*x)**s*sin(x**2)*x, x) (3**s, x*x**s, sin(x**2)) """ from sympy import polarify, unpolarify fac = S.One po = S.One g = S.One f = expand_power_base(f) args = Mul.make_args(f) for a in args: if a == x: po *= x elif x not in a.free_symbols: fac *= a else: if a.is_Pow and x not in a.exp.free_symbols: c, t = a.base.as_coeff_mul(x) if t != (x,): c, t = expand_mul(a.base).as_coeff_mul(x) if t == (x,): po *= x**a.exp fac *= unpolarify(polarify(c**a.exp, subs=False)) continue g *= a return fac, po, g def _mul_args(f): """ Return a list ``L`` such that ``Mul(*L) == f``. If ``f`` is not a ``Mul`` or ``Pow``, ``L=[f]``. If ``f=g**n`` for an integer ``n``, ``L=[g]*n``. If ``f`` is a ``Mul``, ``L`` comes from applying ``_mul_args`` to all factors of ``f``. """ args = Mul.make_args(f) gs = [] for g in args: if g.is_Pow and g.exp.is_Integer: n = g.exp base = g.base if n < 0: n = -n base = 1/base gs += [base]*n else: gs.append(g) return gs def _mul_as_two_parts(f): """ Find all the ways to split ``f`` into a product of two terms. Return None on failure. Explanation =========== Although the order is canonical from multiset_partitions, this is not necessarily the best order to process the terms. For example, if the case of len(gs) == 2 is removed and multiset is allowed to sort the terms, some tests fail. Examples ======== >>> from sympy.integrals.meijerint import _mul_as_two_parts >>> from sympy import sin, exp, ordered >>> from sympy.abc import x >>> list(ordered(_mul_as_two_parts(x*sin(x)*exp(x)))) [(x, exp(x)*sin(x)), (x*exp(x), sin(x)), (x*sin(x), exp(x))] """ gs = _mul_args(f) if len(gs) < 2: return None if len(gs) == 2: return [tuple(gs)] return [(Mul(*x), Mul(*y)) for (x, y) in multiset_partitions(gs, 2)] def _inflate_g(g, n): """ Return C, h such that h is a G function of argument z**n and g = C*h. """ # TODO should this be a method of meijerg? # See: [L, page 150, equation (5)] def inflate(params, n): """ (a1, .., ak) -> (a1/n, (a1+1)/n, ..., (ak + n-1)/n) """ res = [] for a in params: for i in range(n): res.append((a + i)/n) return res v = S(len(g.ap) - len(g.bq)) C = n**(1 + g.nu + v/2) C /= (2*pi)**((n - 1)*g.delta) return C, meijerg(inflate(g.an, n), inflate(g.aother, n), inflate(g.bm, n), inflate(g.bother, n), g.argument**n * n**(n*v)) def _flip_g(g): """ Turn the G function into one of inverse argument (i.e. G(1/x) -> G'(x)) """ # See [L], section 5.2 def tr(l): return [1 - a for a in l] return meijerg(tr(g.bm), tr(g.bother), tr(g.an), tr(g.aother), 1/g.argument) def _inflate_fox_h(g, a): r""" Let d denote the integrand in the definition of the G function ``g``. Consider the function H which is defined in the same way, but with integrand d/Gamma(a*s) (contour conventions as usual). If ``a`` is rational, the function H can be written as C*G, for a constant C and a G-function G. This function returns C, G. """ if a < 0: return _inflate_fox_h(_flip_g(g), -a) p = S(a.p) q = S(a.q) # We use the substitution s->qs, i.e. inflate g by q. We are left with an # extra factor of Gamma(p*s), for which we use Gauss' multiplication # theorem. D, g = _inflate_g(g, q) z = g.argument D /= (2*pi)**((1 - p)/2)*p**Rational(-1, 2) z /= p**p bs = [(n + 1)/p for n in range(p)] return D, meijerg(g.an, g.aother, g.bm, list(g.bother) + bs, z) _dummies = {} # type: Dict[Tuple[str, str], Dummy] def _dummy(name, token, expr, **kwargs): """ Return a dummy. This will return the same dummy if the same token+name is requested more than once, and it is not already in expr. This is for being cache-friendly. """ d = _dummy_(name, token, **kwargs) if d in expr.free_symbols: return Dummy(name, **kwargs) return d def _dummy_(name, token, **kwargs): """ Return a dummy associated to name and token. Same effect as declaring it globally. """ global _dummies if not (name, token) in _dummies: _dummies[(name, token)] = Dummy(name, **kwargs) return _dummies[(name, token)] def _is_analytic(f, x): """ Check if f(x), when expressed using G functions on the positive reals, will in fact agree with the G functions almost everywhere """ from sympy import Heaviside, Abs return not any(x in expr.free_symbols for expr in f.atoms(Heaviside, Abs)) def _condsimp(cond): """ Do naive simplifications on ``cond``. Explanation =========== Note that this routine is completely ad-hoc, simplification rules being added as need arises rather than following any logical pattern. Examples ======== >>> from sympy.integrals.meijerint import _condsimp as simp >>> from sympy import Or, Eq, And >>> from sympy.abc import x, y, z >>> simp(Or(x < y, z, Eq(x, y))) z | (x <= y) >>> simp(Or(x <= y, And(x < y, z))) x <= y """ from sympy import ( symbols, Wild, Eq, unbranched_argument, exp_polar, pi, I, arg, periodic_argument, oo, polar_lift) from sympy.logic.boolalg import BooleanFunction if not isinstance(cond, BooleanFunction): return cond cond = cond.func(*list(map(_condsimp, cond.args))) change = True p, q, r = symbols('p q r', cls=Wild) rules = [ (Or(p < q, Eq(p, q)), p <= q), # The next two obviously are instances of a general pattern, but it is # easier to spell out the few cases we care about. (And(abs(arg(p)) <= pi, abs(arg(p) - 2*pi) <= pi), Eq(arg(p) - pi, 0)), (And(abs(2*arg(p) + pi) <= pi, abs(2*arg(p) - pi) <= pi), Eq(arg(p), 0)), (And(abs(unbranched_argument(p)) <= pi, abs(unbranched_argument(exp_polar(-2*pi*I)*p)) <= pi), Eq(unbranched_argument(exp_polar(-I*pi)*p), 0)), (And(abs(unbranched_argument(p)) <= pi/2, abs(unbranched_argument(exp_polar(-pi*I)*p)) <= pi/2), Eq(unbranched_argument(exp_polar(-I*pi/2)*p), 0)), (Or(p <= q, And(p < q, r)), p <= q) ] while change: change = False for fro, to in rules: if fro.func != cond.func: continue for n, arg1 in enumerate(cond.args): if r in fro.args[0].free_symbols: m = arg1.match(fro.args[1]) num = 1 else: num = 0 m = arg1.match(fro.args[0]) if not m: continue otherargs = [x.subs(m) for x in fro.args[:num] + fro.args[num + 1:]] otherlist = [n] for arg2 in otherargs: for k, arg3 in enumerate(cond.args): if k in otherlist: continue if arg2 == arg3: otherlist += [k] break if isinstance(arg3, And) and arg2.args[1] == r and \ isinstance(arg2, And) and arg2.args[0] in arg3.args: otherlist += [k] break if isinstance(arg3, And) and arg2.args[0] == r and \ isinstance(arg2, And) and arg2.args[1] in arg3.args: otherlist += [k] break if len(otherlist) != len(otherargs) + 1: continue newargs = [arg_ for (k, arg_) in enumerate(cond.args) if k not in otherlist] + [to.subs(m)] cond = cond.func(*newargs) change = True break # final tweak def repl_eq(orig): if orig.lhs == 0: expr = orig.rhs elif orig.rhs == 0: expr = orig.lhs else: return orig m = expr.match(arg(p)**q) if not m: m = expr.match(unbranched_argument(polar_lift(p)**q)) if not m: if isinstance(expr, periodic_argument) and not expr.args[0].is_polar \ and expr.args[1] is oo: return (expr.args[0] > 0) return orig return (m[p] > 0) return cond.replace( lambda expr: expr.is_Relational and expr.rel_op == '==', repl_eq) def _eval_cond(cond): """ Re-evaluate the conditions. """ if isinstance(cond, bool): return cond return _condsimp(cond.doit()) #################################################################### # Now the "backbone" functions to do actual integration. #################################################################### def _my_principal_branch(expr, period, full_pb=False): """ Bring expr nearer to its principal branch by removing superfluous factors. This function does *not* guarantee to yield the principal branch, to avoid introducing opaque principal_branch() objects, unless full_pb=True. """ from sympy import principal_branch res = principal_branch(expr, period) if not full_pb: res = res.replace(principal_branch, lambda x, y: x) return res def _rewrite_saxena_1(fac, po, g, x): """ Rewrite the integral fac*po*g dx, from zero to infinity, as integral fac*G, where G has argument a*x. Note po=x**s. Return fac, G. """ _, s = _get_coeff_exp(po, x) a, b = _get_coeff_exp(g.argument, x) period = g.get_period() a = _my_principal_branch(a, period) # We substitute t = x**b. C = fac/(abs(b)*a**((s + 1)/b - 1)) # Absorb a factor of (at)**((1 + s)/b - 1). def tr(l): return [a + (1 + s)/b - 1 for a in l] return C, meijerg(tr(g.an), tr(g.aother), tr(g.bm), tr(g.bother), a*x) def _check_antecedents_1(g, x, helper=False): r""" Return a condition under which the mellin transform of g exists. Any power of x has already been absorbed into the G function, so this is just $\int_0^\infty g\, dx$. See [L, section 5.6.1]. (Note that s=1.) If ``helper`` is True, only check if the MT exists at infinity, i.e. if $\int_1^\infty g\, dx$ exists. """ # NOTE if you update these conditions, please update the documentation as well from sympy import Eq, Not, ceiling, Ne, re, unbranched_argument as arg delta = g.delta eta, _ = _get_coeff_exp(g.argument, x) m, n, p, q = S([len(g.bm), len(g.an), len(g.ap), len(g.bq)]) if p > q: def tr(l): return [1 - x for x in l] return _check_antecedents_1(meijerg(tr(g.bm), tr(g.bother), tr(g.an), tr(g.aother), x/eta), x) tmp = [] for b in g.bm: tmp += [-re(b) < 1] for a in g.an: tmp += [1 < 1 - re(a)] cond_3 = And(*tmp) for b in g.bother: tmp += [-re(b) < 1] for a in g.aother: tmp += [1 < 1 - re(a)] cond_3_star = And(*tmp) cond_4 = (-re(g.nu) + (q + 1 - p)/2 > q - p) def debug(*msg): _debug(*msg) debug('Checking antecedents for 1 function:') debug(' delta=%s, eta=%s, m=%s, n=%s, p=%s, q=%s' % (delta, eta, m, n, p, q)) debug(' ap = %s, %s' % (list(g.an), list(g.aother))) debug(' bq = %s, %s' % (list(g.bm), list(g.bother))) debug(' cond_3=%s, cond_3*=%s, cond_4=%s' % (cond_3, cond_3_star, cond_4)) conds = [] # case 1 case1 = [] tmp1 = [1 <= n, p < q, 1 <= m] tmp2 = [1 <= p, 1 <= m, Eq(q, p + 1), Not(And(Eq(n, 0), Eq(m, p + 1)))] tmp3 = [1 <= p, Eq(q, p)] for k in range(ceiling(delta/2) + 1): tmp3 += [Ne(abs(arg(eta)), (delta - 2*k)*pi)] tmp = [delta > 0, abs(arg(eta)) < delta*pi] extra = [Ne(eta, 0), cond_3] if helper: extra = [] for t in [tmp1, tmp2, tmp3]: case1 += [And(*(t + tmp + extra))] conds += case1 debug(' case 1:', case1) # case 2 extra = [cond_3] if helper: extra = [] case2 = [And(Eq(n, 0), p + 1 <= m, m <= q, abs(arg(eta)) < delta*pi, *extra)] conds += case2 debug(' case 2:', case2) # case 3 extra = [cond_3, cond_4] if helper: extra = [] case3 = [And(p < q, 1 <= m, delta > 0, Eq(abs(arg(eta)), delta*pi), *extra)] case3 += [And(p <= q - 2, Eq(delta, 0), Eq(abs(arg(eta)), 0), *extra)] conds += case3 debug(' case 3:', case3) # TODO altered cases 4-7 # extra case from wofram functions site: # (reproduced verbatim from Prudnikov, section 2.24.2) # http://functions.wolfram.com/HypergeometricFunctions/MeijerG/21/02/01/ case_extra = [] case_extra += [Eq(p, q), Eq(delta, 0), Eq(arg(eta), 0), Ne(eta, 0)] if not helper: case_extra += [cond_3] s = [] for a, b in zip(g.ap, g.bq): s += [b - a] case_extra += [re(Add(*s)) < 0] case_extra = And(*case_extra) conds += [case_extra] debug(' extra case:', [case_extra]) case_extra_2 = [And(delta > 0, abs(arg(eta)) < delta*pi)] if not helper: case_extra_2 += [cond_3] case_extra_2 = And(*case_extra_2) conds += [case_extra_2] debug(' second extra case:', [case_extra_2]) # TODO This leaves only one case from the three listed by Prudnikov. # Investigate if these indeed cover everything; if so, remove the rest. return Or(*conds) def _int0oo_1(g, x): r""" Evaluate $\int_0^\infty g\, dx$ using G functions, assuming the necessary conditions are fulfilled. Examples ======== >>> from sympy.abc import a, b, c, d, x, y >>> from sympy import meijerg >>> from sympy.integrals.meijerint import _int0oo_1 >>> _int0oo_1(meijerg([a], [b], [c], [d], x*y), x) gamma(-a)*gamma(c + 1)/(y*gamma(-d)*gamma(b + 1)) """ # See [L, section 5.6.1]. Note that s=1. from sympy import gamma, gammasimp, unpolarify eta, _ = _get_coeff_exp(g.argument, x) res = 1/eta # XXX TODO we should reduce order first for b in g.bm: res *= gamma(b + 1) for a in g.an: res *= gamma(1 - a - 1) for b in g.bother: res /= gamma(1 - b - 1) for a in g.aother: res /= gamma(a + 1) return gammasimp(unpolarify(res)) def _rewrite_saxena(fac, po, g1, g2, x, full_pb=False): """ Rewrite the integral ``fac*po*g1*g2`` from 0 to oo in terms of G functions with argument ``c*x``. Explanation =========== Return C, f1, f2 such that integral C f1 f2 from 0 to infinity equals integral fac ``po``, ``g1``, ``g2`` from 0 to infinity. Examples ======== >>> from sympy.integrals.meijerint import _rewrite_saxena >>> from sympy.abc import s, t, m >>> from sympy import meijerg >>> g1 = meijerg([], [], [0], [], s*t) >>> g2 = meijerg([], [], [m/2], [-m/2], t**2/4) >>> r = _rewrite_saxena(1, t**0, g1, g2, t) >>> r[0] s/(4*sqrt(pi)) >>> r[1] meijerg(((), ()), ((-1/2, 0), ()), s**2*t/4) >>> r[2] meijerg(((), ()), ((m/2,), (-m/2,)), t/4) """ from sympy.core.numbers import ilcm def pb(g): a, b = _get_coeff_exp(g.argument, x) per = g.get_period() return meijerg(g.an, g.aother, g.bm, g.bother, _my_principal_branch(a, per, full_pb)*x**b) _, s = _get_coeff_exp(po, x) _, b1 = _get_coeff_exp(g1.argument, x) _, b2 = _get_coeff_exp(g2.argument, x) if (b1 < 0) == True: b1 = -b1 g1 = _flip_g(g1) if (b2 < 0) == True: b2 = -b2 g2 = _flip_g(g2) if not b1.is_Rational or not b2.is_Rational: return m1, n1 = b1.p, b1.q m2, n2 = b2.p, b2.q tau = ilcm(m1*n2, m2*n1) r1 = tau//(m1*n2) r2 = tau//(m2*n1) C1, g1 = _inflate_g(g1, r1) C2, g2 = _inflate_g(g2, r2) g1 = pb(g1) g2 = pb(g2) fac *= C1*C2 a1, b = _get_coeff_exp(g1.argument, x) a2, _ = _get_coeff_exp(g2.argument, x) # arbitrarily tack on the x**s part to g1 # TODO should we try both? exp = (s + 1)/b - 1 fac = fac/(abs(b) * a1**exp) def tr(l): return [a + exp for a in l] g1 = meijerg(tr(g1.an), tr(g1.aother), tr(g1.bm), tr(g1.bother), a1*x) g2 = meijerg(g2.an, g2.aother, g2.bm, g2.bother, a2*x) return powdenest(fac, polar=True), g1, g2 def _check_antecedents(g1, g2, x): """ Return a condition under which the integral theorem applies. """ from sympy import re, Eq, Ne, cos, I, exp, sin, sign, unpolarify from sympy import arg as arg_, unbranched_argument as arg # Yes, this is madness. # XXX TODO this is a testing *nightmare* # NOTE if you update these conditions, please update the documentation as well # The following conditions are found in # [P], Section 2.24.1 # # They are also reproduced (verbatim!) at # http://functions.wolfram.com/HypergeometricFunctions/MeijerG/21/02/03/ # # Note: k=l=r=alpha=1 sigma, _ = _get_coeff_exp(g1.argument, x) omega, _ = _get_coeff_exp(g2.argument, x) s, t, u, v = S([len(g1.bm), len(g1.an), len(g1.ap), len(g1.bq)]) m, n, p, q = S([len(g2.bm), len(g2.an), len(g2.ap), len(g2.bq)]) bstar = s + t - (u + v)/2 cstar = m + n - (p + q)/2 rho = g1.nu + (u - v)/2 + 1 mu = g2.nu + (p - q)/2 + 1 phi = q - p - (v - u) eta = 1 - (v - u) - mu - rho psi = (pi*(q - m - n) + abs(arg(omega)))/(q - p) theta = (pi*(v - s - t) + abs(arg(sigma)))/(v - u) _debug('Checking antecedents:') _debug(' sigma=%s, s=%s, t=%s, u=%s, v=%s, b*=%s, rho=%s' % (sigma, s, t, u, v, bstar, rho)) _debug(' omega=%s, m=%s, n=%s, p=%s, q=%s, c*=%s, mu=%s,' % (omega, m, n, p, q, cstar, mu)) _debug(' phi=%s, eta=%s, psi=%s, theta=%s' % (phi, eta, psi, theta)) def _c1(): for g in [g1, g2]: for i in g.an: for j in g.bm: diff = i - j if diff.is_integer and diff.is_positive: return False return True c1 = _c1() c2 = And(*[re(1 + i + j) > 0 for i in g1.bm for j in g2.bm]) c3 = And(*[re(1 + i + j) < 1 + 1 for i in g1.an for j in g2.an]) c4 = And(*[(p - q)*re(1 + i - 1) - re(mu) > Rational(-3, 2) for i in g1.an]) c5 = And(*[(p - q)*re(1 + i) - re(mu) > Rational(-3, 2) for i in g1.bm]) c6 = And(*[(u - v)*re(1 + i - 1) - re(rho) > Rational(-3, 2) for i in g2.an]) c7 = And(*[(u - v)*re(1 + i) - re(rho) > Rational(-3, 2) for i in g2.bm]) c8 = (abs(phi) + 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - 1)*(v - u)) > 0) c9 = (abs(phi) - 2*re((rho - 1)*(q - p) + (v - u)*(q - p) + (mu - 1)*(v - u)) > 0) c10 = (abs(arg(sigma)) < bstar*pi) c11 = Eq(abs(arg(sigma)), bstar*pi) c12 = (abs(arg(omega)) < cstar*pi) c13 = Eq(abs(arg(omega)), cstar*pi) # The following condition is *not* implemented as stated on the wolfram # function site. In the book of Prudnikov there is an additional part # (the And involving re()). However, I only have this book in russian, and # I don't read any russian. The following condition is what other people # have told me it means. # Worryingly, it is different from the condition implemented in REDUCE. # The REDUCE implementation: # https://reduce-algebra.svn.sourceforge.net/svnroot/reduce-algebra/trunk/packages/defint/definta.red # (search for tst14) # The Wolfram alpha version: # http://functions.wolfram.com/HypergeometricFunctions/MeijerG/21/02/03/03/0014/ z0 = exp(-(bstar + cstar)*pi*I) zos = unpolarify(z0*omega/sigma) zso = unpolarify(z0*sigma/omega) if zos == 1/zso: c14 = And(Eq(phi, 0), bstar + cstar <= 1, Or(Ne(zos, 1), re(mu + rho + v - u) < 1, re(mu + rho + q - p) < 1)) else: def _cond(z): '''Returns True if abs(arg(1-z)) < pi, avoiding arg(0). Explanation =========== If ``z`` is 1 then arg is NaN. This raises a TypeError on `NaN < pi`. Previously this gave `False` so this behavior has been hardcoded here but someone should check if this NaN is more serious! This NaN is triggered by test_meijerint() in test_meijerint.py: `meijerint_definite(exp(x), x, 0, I)` ''' return z != 1 and abs(arg_(1 - z)) < pi c14 = And(Eq(phi, 0), bstar - 1 + cstar <= 0, Or(And(Ne(zos, 1), _cond(zos)), And(re(mu + rho + v - u) < 1, Eq(zos, 1)))) c14_alt = And(Eq(phi, 0), cstar - 1 + bstar <= 0, Or(And(Ne(zso, 1), _cond(zso)), And(re(mu + rho + q - p) < 1, Eq(zso, 1)))) # Since r=k=l=1, in our case there is c14_alt which is the same as calling # us with (g1, g2) = (g2, g1). The conditions below enumerate all cases # (i.e. we don't have to try arguments reversed by hand), and indeed try # all symmetric cases. (i.e. whenever there is a condition involving c14, # there is also a dual condition which is exactly what we would get when g1, # g2 were interchanged, *but c14 was unaltered*). # Hence the following seems correct: c14 = Or(c14, c14_alt) ''' When `c15` is NaN (e.g. from `psi` being NaN as happens during 'test_issue_4992' and/or `theta` is NaN as in 'test_issue_6253', both in `test_integrals.py`) the comparison to 0 formerly gave False whereas now an error is raised. To keep the old behavior, the value of NaN is replaced with False but perhaps a closer look at this condition should be made: XXX how should conditions leading to c15=NaN be handled? ''' try: lambda_c = (q - p)*abs(omega)**(1/(q - p))*cos(psi) \ + (v - u)*abs(sigma)**(1/(v - u))*cos(theta) # the TypeError might be raised here, e.g. if lambda_c is NaN if _eval_cond(lambda_c > 0) != False: c15 = (lambda_c > 0) else: def lambda_s0(c1, c2): return c1*(q - p)*abs(omega)**(1/(q - p))*sin(psi) \ + c2*(v - u)*abs(sigma)**(1/(v - u))*sin(theta) lambda_s = Piecewise( ((lambda_s0(+1, +1)*lambda_s0(-1, -1)), And(Eq(arg(sigma), 0), Eq(arg(omega), 0))), (lambda_s0(sign(arg(omega)), +1)*lambda_s0(sign(arg(omega)), -1), And(Eq(arg(sigma), 0), Ne(arg(omega), 0))), (lambda_s0(+1, sign(arg(sigma)))*lambda_s0(-1, sign(arg(sigma))), And(Ne(arg(sigma), 0), Eq(arg(omega), 0))), (lambda_s0(sign(arg(omega)), sign(arg(sigma))), True)) tmp = [lambda_c > 0, And(Eq(lambda_c, 0), Ne(lambda_s, 0), re(eta) > -1), And(Eq(lambda_c, 0), Eq(lambda_s, 0), re(eta) > 0)] c15 = Or(*tmp) except TypeError: c15 = False for cond, i in [(c1, 1), (c2, 2), (c3, 3), (c4, 4), (c5, 5), (c6, 6), (c7, 7), (c8, 8), (c9, 9), (c10, 10), (c11, 11), (c12, 12), (c13, 13), (c14, 14), (c15, 15)]: _debug(' c%s:' % i, cond) # We will return Or(*conds) conds = [] def pr(count): _debug(' case %s:' % count, conds[-1]) conds += [And(m*n*s*t != 0, bstar.is_positive is True, cstar.is_positive is True, c1, c2, c3, c10, c12)] # 1 pr(1) conds += [And(Eq(u, v), Eq(bstar, 0), cstar.is_positive is True, sigma.is_positive is True, re(rho) < 1, c1, c2, c3, c12)] # 2 pr(2) conds += [And(Eq(p, q), Eq(cstar, 0), bstar.is_positive is True, omega.is_positive is True, re(mu) < 1, c1, c2, c3, c10)] # 3 pr(3) conds += [And(Eq(p, q), Eq(u, v), Eq(bstar, 0), Eq(cstar, 0), sigma.is_positive is True, omega.is_positive is True, re(mu) < 1, re(rho) < 1, Ne(sigma, omega), c1, c2, c3)] # 4 pr(4) conds += [And(Eq(p, q), Eq(u, v), Eq(bstar, 0), Eq(cstar, 0), sigma.is_positive is True, omega.is_positive is True, re(mu + rho) < 1, Ne(omega, sigma), c1, c2, c3)] # 5 pr(5) conds += [And(p > q, s.is_positive is True, bstar.is_positive is True, cstar >= 0, c1, c2, c3, c5, c10, c13)] # 6 pr(6) conds += [And(p < q, t.is_positive is True, bstar.is_positive is True, cstar >= 0, c1, c2, c3, c4, c10, c13)] # 7 pr(7) conds += [And(u > v, m.is_positive is True, cstar.is_positive is True, bstar >= 0, c1, c2, c3, c7, c11, c12)] # 8 pr(8) conds += [And(u < v, n.is_positive is True, cstar.is_positive is True, bstar >= 0, c1, c2, c3, c6, c11, c12)] # 9 pr(9) conds += [And(p > q, Eq(u, v), Eq(bstar, 0), cstar >= 0, sigma.is_positive is True, re(rho) < 1, c1, c2, c3, c5, c13)] # 10 pr(10) conds += [And(p < q, Eq(u, v), Eq(bstar, 0), cstar >= 0, sigma.is_positive is True, re(rho) < 1, c1, c2, c3, c4, c13)] # 11 pr(11) conds += [And(Eq(p, q), u > v, bstar >= 0, Eq(cstar, 0), omega.is_positive is True, re(mu) < 1, c1, c2, c3, c7, c11)] # 12 pr(12) conds += [And(Eq(p, q), u < v, bstar >= 0, Eq(cstar, 0), omega.is_positive is True, re(mu) < 1, c1, c2, c3, c6, c11)] # 13 pr(13) conds += [And(p < q, u > v, bstar >= 0, cstar >= 0, c1, c2, c3, c4, c7, c11, c13)] # 14 pr(14) conds += [And(p > q, u < v, bstar >= 0, cstar >= 0, c1, c2, c3, c5, c6, c11, c13)] # 15 pr(15) conds += [And(p > q, u > v, bstar >= 0, cstar >= 0, c1, c2, c3, c5, c7, c8, c11, c13, c14)] # 16 pr(16) conds += [And(p < q, u < v, bstar >= 0, cstar >= 0, c1, c2, c3, c4, c6, c9, c11, c13, c14)] # 17 pr(17) conds += [And(Eq(t, 0), s.is_positive is True, bstar.is_positive is True, phi.is_positive is True, c1, c2, c10)] # 18 pr(18) conds += [And(Eq(s, 0), t.is_positive is True, bstar.is_positive is True, phi.is_negative is True, c1, c3, c10)] # 19 pr(19) conds += [And(Eq(n, 0), m.is_positive is True, cstar.is_positive is True, phi.is_negative is True, c1, c2, c12)] # 20 pr(20) conds += [And(Eq(m, 0), n.is_positive is True, cstar.is_positive is True, phi.is_positive is True, c1, c3, c12)] # 21 pr(21) conds += [And(Eq(s*t, 0), bstar.is_positive is True, cstar.is_positive is True, c1, c2, c3, c10, c12)] # 22 pr(22) conds += [And(Eq(m*n, 0), bstar.is_positive is True, cstar.is_positive is True, c1, c2, c3, c10, c12)] # 23 pr(23) # The following case is from [Luke1969]. As far as I can tell, it is *not* # covered by Prudnikov's. # Let G1 and G2 be the two G-functions. Suppose the integral exists from # 0 to a > 0 (this is easy the easy part), that G1 is exponential decay at # infinity, and that the mellin transform of G2 exists. # Then the integral exists. mt1_exists = _check_antecedents_1(g1, x, helper=True) mt2_exists = _check_antecedents_1(g2, x, helper=True) conds += [And(mt2_exists, Eq(t, 0), u < s, bstar.is_positive is True, c10, c1, c2, c3)] pr('E1') conds += [And(mt2_exists, Eq(s, 0), v < t, bstar.is_positive is True, c10, c1, c2, c3)] pr('E2') conds += [And(mt1_exists, Eq(n, 0), p < m, cstar.is_positive is True, c12, c1, c2, c3)] pr('E3') conds += [And(mt1_exists, Eq(m, 0), q < n, cstar.is_positive is True, c12, c1, c2, c3)] pr('E4') # Let's short-circuit if this worked ... # the rest is corner-cases and terrible to read. r = Or(*conds) if _eval_cond(r) != False: return r conds += [And(m + n > p, Eq(t, 0), Eq(phi, 0), s.is_positive is True, bstar.is_positive is True, cstar.is_negative is True, abs(arg(omega)) < (m + n - p + 1)*pi, c1, c2, c10, c14, c15)] # 24 pr(24) conds += [And(m + n > q, Eq(s, 0), Eq(phi, 0), t.is_positive is True, bstar.is_positive is True, cstar.is_negative is True, abs(arg(omega)) < (m + n - q + 1)*pi, c1, c3, c10, c14, c15)] # 25 pr(25) conds += [And(Eq(p, q - 1), Eq(t, 0), Eq(phi, 0), s.is_positive is True, bstar.is_positive is True, cstar >= 0, cstar*pi < abs(arg(omega)), c1, c2, c10, c14, c15)] # 26 pr(26) conds += [And(Eq(p, q + 1), Eq(s, 0), Eq(phi, 0), t.is_positive is True, bstar.is_positive is True, cstar >= 0, cstar*pi < abs(arg(omega)), c1, c3, c10, c14, c15)] # 27 pr(27) conds += [And(p < q - 1, Eq(t, 0), Eq(phi, 0), s.is_positive is True, bstar.is_positive is True, cstar >= 0, cstar*pi < abs(arg(omega)), abs(arg(omega)) < (m + n - p + 1)*pi, c1, c2, c10, c14, c15)] # 28 pr(28) conds += [And( p > q + 1, Eq(s, 0), Eq(phi, 0), t.is_positive is True, bstar.is_positive is True, cstar >= 0, cstar*pi < abs(arg(omega)), abs(arg(omega)) < (m + n - q + 1)*pi, c1, c3, c10, c14, c15)] # 29 pr(29) conds += [And(Eq(n, 0), Eq(phi, 0), s + t > 0, m.is_positive is True, cstar.is_positive is True, bstar.is_negative is True, abs(arg(sigma)) < (s + t - u + 1)*pi, c1, c2, c12, c14, c15)] # 30 pr(30) conds += [And(Eq(m, 0), Eq(phi, 0), s + t > v, n.is_positive is True, cstar.is_positive is True, bstar.is_negative is True, abs(arg(sigma)) < (s + t - v + 1)*pi, c1, c3, c12, c14, c15)] # 31 pr(31) conds += [And(Eq(n, 0), Eq(phi, 0), Eq(u, v - 1), m.is_positive is True, cstar.is_positive is True, bstar >= 0, bstar*pi < abs(arg(sigma)), abs(arg(sigma)) < (bstar + 1)*pi, c1, c2, c12, c14, c15)] # 32 pr(32) conds += [And(Eq(m, 0), Eq(phi, 0), Eq(u, v + 1), n.is_positive is True, cstar.is_positive is True, bstar >= 0, bstar*pi < abs(arg(sigma)), abs(arg(sigma)) < (bstar + 1)*pi, c1, c3, c12, c14, c15)] # 33 pr(33) conds += [And( Eq(n, 0), Eq(phi, 0), u < v - 1, m.is_positive is True, cstar.is_positive is True, bstar >= 0, bstar*pi < abs(arg(sigma)), abs(arg(sigma)) < (s + t - u + 1)*pi, c1, c2, c12, c14, c15)] # 34 pr(34) conds += [And( Eq(m, 0), Eq(phi, 0), u > v + 1, n.is_positive is True, cstar.is_positive is True, bstar >= 0, bstar*pi < abs(arg(sigma)), abs(arg(sigma)) < (s + t - v + 1)*pi, c1, c3, c12, c14, c15)] # 35 pr(35) return Or(*conds) # NOTE An alternative, but as far as I can tell weaker, set of conditions # can be found in [L, section 5.6.2]. def _int0oo(g1, g2, x): """ Express integral from zero to infinity g1*g2 using a G function, assuming the necessary conditions are fulfilled. Examples ======== >>> from sympy.integrals.meijerint import _int0oo >>> from sympy.abc import s, t, m >>> from sympy import meijerg, S >>> g1 = meijerg([], [], [-S(1)/2, 0], [], s**2*t/4) >>> g2 = meijerg([], [], [m/2], [-m/2], t/4) >>> _int0oo(g1, g2, t) 4*meijerg(((1/2, 0), ()), ((m/2,), (-m/2,)), s**(-2))/s**2 """ # See: [L, section 5.6.2, equation (1)] eta, _ = _get_coeff_exp(g1.argument, x) omega, _ = _get_coeff_exp(g2.argument, x) def neg(l): return [-x for x in l] a1 = neg(g1.bm) + list(g2.an) a2 = list(g2.aother) + neg(g1.bother) b1 = neg(g1.an) + list(g2.bm) b2 = list(g2.bother) + neg(g1.aother) return meijerg(a1, a2, b1, b2, omega/eta)/eta def _rewrite_inversion(fac, po, g, x): """ Absorb ``po`` == x**s into g. """ _, s = _get_coeff_exp(po, x) a, b = _get_coeff_exp(g.argument, x) def tr(l): return [t + s/b for t in l] return (powdenest(fac/a**(s/b), polar=True), meijerg(tr(g.an), tr(g.aother), tr(g.bm), tr(g.bother), g.argument)) def _check_antecedents_inversion(g, x): """ Check antecedents for the laplace inversion integral. """ from sympy import re, im, Or, And, Eq, exp, I, Add, nan, Ne _debug('Checking antecedents for inversion:') z = g.argument _, e = _get_coeff_exp(z, x) if e < 0: _debug(' Flipping G.') # We want to assume that argument gets large as |x| -> oo return _check_antecedents_inversion(_flip_g(g), x) def statement_half(a, b, c, z, plus): coeff, exponent = _get_coeff_exp(z, x) a *= exponent b *= coeff**c c *= exponent conds = [] wp = b*exp(I*re(c)*pi/2) wm = b*exp(-I*re(c)*pi/2) if plus: w = wp else: w = wm conds += [And(Or(Eq(b, 0), re(c) <= 0), re(a) <= -1)] conds += [And(Ne(b, 0), Eq(im(c), 0), re(c) > 0, re(w) < 0)] conds += [And(Ne(b, 0), Eq(im(c), 0), re(c) > 0, re(w) <= 0, re(a) <= -1)] return Or(*conds) def statement(a, b, c, z): """ Provide a convergence statement for z**a * exp(b*z**c), c/f sphinx docs. """ return And(statement_half(a, b, c, z, True), statement_half(a, b, c, z, False)) # Notations from [L], section 5.7-10 m, n, p, q = S([len(g.bm), len(g.an), len(g.ap), len(g.bq)]) tau = m + n - p nu = q - m - n rho = (tau - nu)/2 sigma = q - p if sigma == 1: epsilon = S.Half elif sigma > 1: epsilon = 1 else: epsilon = nan theta = ((1 - sigma)/2 + Add(*g.bq) - Add(*g.ap))/sigma delta = g.delta _debug(' m=%s, n=%s, p=%s, q=%s, tau=%s, nu=%s, rho=%s, sigma=%s' % ( m, n, p, q, tau, nu, rho, sigma)) _debug(' epsilon=%s, theta=%s, delta=%s' % (epsilon, theta, delta)) # First check if the computation is valid. if not (g.delta >= e/2 or (p >= 1 and p >= q)): _debug(' Computation not valid for these parameters.') return False # Now check if the inversion integral exists. # Test "condition A" for a in g.an: for b in g.bm: if (a - b).is_integer and a > b: _debug(' Not a valid G function.') return False # There are two cases. If p >= q, we can directly use a slater expansion # like [L], 5.2 (11). Note in particular that the asymptotics of such an # expansion even hold when some of the parameters differ by integers, i.e. # the formula itself would not be valid! (b/c G functions are cts. in their # parameters) # When p < q, we need to use the theorems of [L], 5.10. if p >= q: _debug(' Using asymptotic Slater expansion.') return And(*[statement(a - 1, 0, 0, z) for a in g.an]) def E(z): return And(*[statement(a - 1, 0, 0, z) for a in g.an]) def H(z): return statement(theta, -sigma, 1/sigma, z) def Hp(z): return statement_half(theta, -sigma, 1/sigma, z, True) def Hm(z): return statement_half(theta, -sigma, 1/sigma, z, False) # [L], section 5.10 conds = [] # Theorem 1 -- p < q from test above conds += [And(1 <= n, 1 <= m, rho*pi - delta >= pi/2, delta > 0, E(z*exp(I*pi*(nu + 1))))] # Theorem 2, statements (2) and (3) conds += [And(p + 1 <= m, m + 1 <= q, delta > 0, delta < pi/2, n == 0, (m - p + 1)*pi - delta >= pi/2, Hp(z*exp(I*pi*(q - m))), Hm(z*exp(-I*pi*(q - m))))] # Theorem 2, statement (5) -- p < q from test above conds += [And(m == q, n == 0, delta > 0, (sigma + epsilon)*pi - delta >= pi/2, H(z))] # Theorem 3, statements (6) and (7) conds += [And(Or(And(p <= q - 2, 1 <= tau, tau <= sigma/2), And(p + 1 <= m + n, m + n <= (p + q)/2)), delta > 0, delta < pi/2, (tau + 1)*pi - delta >= pi/2, Hp(z*exp(I*pi*nu)), Hm(z*exp(-I*pi*nu)))] # Theorem 4, statements (10) and (11) -- p < q from test above conds += [And(1 <= m, rho > 0, delta > 0, delta + rho*pi < pi/2, (tau + epsilon)*pi - delta >= pi/2, Hp(z*exp(I*pi*nu)), Hm(z*exp(-I*pi*nu)))] # Trivial case conds += [m == 0] # TODO # Theorem 5 is quite general # Theorem 6 contains special cases for q=p+1 return Or(*conds) def _int_inversion(g, x, t): """ Compute the laplace inversion integral, assuming the formula applies. """ b, a = _get_coeff_exp(g.argument, x) C, g = _inflate_fox_h(meijerg(g.an, g.aother, g.bm, g.bother, b/t**a), -a) return C/t*g #################################################################### # Finally, the real meat. #################################################################### _lookup_table = None @cacheit @timeit def _rewrite_single(f, x, recursive=True): """ Try to rewrite f as a sum of single G functions of the form C*x**s*G(a*x**b), where b is a rational number and C is independent of x. We guarantee that result.argument.as_coeff_mul(x) returns (a, (x**b,)) or (a, ()). Returns a list of tuples (C, s, G) and a condition cond. Returns None on failure. """ from sympy import polarify, unpolarify, oo, zoo, Tuple global _lookup_table if not _lookup_table: _lookup_table = {} _create_lookup_table(_lookup_table) if isinstance(f, meijerg): from sympy import factor coeff, m = factor(f.argument, x).as_coeff_mul(x) if len(m) > 1: return None m = m[0] if m.is_Pow: if m.base != x or not m.exp.is_Rational: return None elif m != x: return None return [(1, 0, meijerg(f.an, f.aother, f.bm, f.bother, coeff*m))], True f_ = f f = f.subs(x, z) t = _mytype(f, z) if t in _lookup_table: l = _lookup_table[t] for formula, terms, cond, hint in l: subs = f.match(formula, old=True) if subs: subs_ = {} for fro, to in subs.items(): subs_[fro] = unpolarify(polarify(to, lift=True), exponents_only=True) subs = subs_ if not isinstance(hint, bool): hint = hint.subs(subs) if hint == False: continue if not isinstance(cond, (bool, BooleanAtom)): cond = unpolarify(cond.subs(subs)) if _eval_cond(cond) == False: continue if not isinstance(terms, list): terms = terms(subs) res = [] for fac, g in terms: r1 = _get_coeff_exp(unpolarify(fac.subs(subs).subs(z, x), exponents_only=True), x) try: g = g.subs(subs).subs(z, x) except ValueError: continue # NOTE these substitutions can in principle introduce oo, # zoo and other absurdities. It shouldn't matter, # but better be safe. if Tuple(*(r1 + (g,))).has(oo, zoo, -oo): continue g = meijerg(g.an, g.aother, g.bm, g.bother, unpolarify(g.argument, exponents_only=True)) res.append(r1 + (g,)) if res: return res, cond # try recursive mellin transform if not recursive: return None _debug('Trying recursive Mellin transform method.') from sympy.integrals.transforms import (mellin_transform, inverse_mellin_transform, IntegralTransformError, MellinTransformStripError) from sympy import oo, nan, zoo, simplify, cancel def my_imt(F, s, x, strip): """ Calling simplify() all the time is slow and not helpful, since most of the time it only factors things in a way that has to be un-done anyway. But sometimes it can remove apparent poles. """ # XXX should this be in inverse_mellin_transform? try: return inverse_mellin_transform(F, s, x, strip, as_meijerg=True, needeval=True) except MellinTransformStripError: return inverse_mellin_transform( simplify(cancel(expand(F))), s, x, strip, as_meijerg=True, needeval=True) f = f_ s = _dummy('s', 'rewrite-single', f) # to avoid infinite recursion, we have to force the two g functions case def my_integrator(f, x): from sympy import Integral, hyperexpand r = _meijerint_definite_4(f, x, only_double=True) if r is not None: res, cond = r res = _my_unpolarify(hyperexpand(res, rewrite='nonrepsmall')) return Piecewise((res, cond), (Integral(f, (x, 0, oo)), True)) return Integral(f, (x, 0, oo)) try: F, strip, _ = mellin_transform(f, x, s, integrator=my_integrator, simplify=False, needeval=True) g = my_imt(F, s, x, strip) except IntegralTransformError: g = None if g is None: # We try to find an expression by analytic continuation. # (also if the dummy is already in the expression, there is no point in # putting in another one) a = _dummy_('a', 'rewrite-single') if a not in f.free_symbols and _is_analytic(f, x): try: F, strip, _ = mellin_transform(f.subs(x, a*x), x, s, integrator=my_integrator, needeval=True, simplify=False) g = my_imt(F, s, x, strip).subs(a, 1) except IntegralTransformError: g = None if g is None or g.has(oo, nan, zoo): _debug('Recursive Mellin transform failed.') return None args = Add.make_args(g) res = [] for f in args: c, m = f.as_coeff_mul(x) if len(m) > 1: raise NotImplementedError('Unexpected form...') g = m[0] a, b = _get_coeff_exp(g.argument, x) res += [(c, 0, meijerg(g.an, g.aother, g.bm, g.bother, unpolarify(polarify( a, lift=True), exponents_only=True) *x**b))] _debug('Recursive Mellin transform worked:', g) return res, True def _rewrite1(f, x, recursive=True): """ Try to rewrite ``f`` using a (sum of) single G functions with argument a*x**b. Return fac, po, g such that f = fac*po*g, fac is independent of ``x``. and po = x**s. Here g is a result from _rewrite_single. Return None on failure. """ fac, po, g = _split_mul(f, x) g = _rewrite_single(g, x, recursive) if g: return fac, po, g[0], g[1] def _rewrite2(f, x): """ Try to rewrite ``f`` as a product of two G functions of arguments a*x**b. Return fac, po, g1, g2 such that f = fac*po*g1*g2, where fac is independent of x and po is x**s. Here g1 and g2 are results of _rewrite_single. Returns None on failure. """ fac, po, g = _split_mul(f, x) if any(_rewrite_single(expr, x, False) is None for expr in _mul_args(g)): return None l = _mul_as_two_parts(g) if not l: return None l = list(ordered(l, [ lambda p: max(len(_exponents(p[0], x)), len(_exponents(p[1], x))), lambda p: max(len(_functions(p[0], x)), len(_functions(p[1], x))), lambda p: max(len(_find_splitting_points(p[0], x)), len(_find_splitting_points(p[1], x)))])) for recursive in [False, True]: for fac1, fac2 in l: g1 = _rewrite_single(fac1, x, recursive) g2 = _rewrite_single(fac2, x, recursive) if g1 and g2: cond = And(g1[1], g2[1]) if cond != False: return fac, po, g1[0], g2[0], cond def meijerint_indefinite(f, x): """ Compute an indefinite integral of ``f`` by rewriting it as a G function. Examples ======== >>> from sympy.integrals.meijerint import meijerint_indefinite >>> from sympy import sin >>> from sympy.abc import x >>> meijerint_indefinite(sin(x), x) -cos(x) """ from sympy import hyper, meijerg results = [] for a in sorted(_find_splitting_points(f, x) | {S.Zero}, key=default_sort_key): res = _meijerint_indefinite_1(f.subs(x, x + a), x) if not res: continue res = res.subs(x, x - a) if _has(res, hyper, meijerg): results.append(res) else: return res if f.has(HyperbolicFunction): _debug('Try rewriting hyperbolics in terms of exp.') rv = meijerint_indefinite( _rewrite_hyperbolics_as_exp(f), x) if rv: if not type(rv) is list: return collect(factor_terms(rv), rv.atoms(exp)) results.extend(rv) if results: return next(ordered(results)) def _meijerint_indefinite_1(f, x): """ Helper that does not attempt any substitution. """ from sympy import Integral, piecewise_fold, nan, zoo _debug('Trying to compute the indefinite integral of', f, 'wrt', x) gs = _rewrite1(f, x) if gs is None: # Note: the code that calls us will do expand() and try again return None fac, po, gl, cond = gs _debug(' could rewrite:', gs) res = S.Zero for C, s, g in gl: a, b = _get_coeff_exp(g.argument, x) _, c = _get_coeff_exp(po, x) c += s # we do a substitution t=a*x**b, get integrand fac*t**rho*g fac_ = fac * C / (b*a**((1 + c)/b)) rho = (c + 1)/b - 1 # we now use t**rho*G(params, t) = G(params + rho, t) # [L, page 150, equation (4)] # and integral G(params, t) dt = G(1, params+1, 0, t) # (or a similar expression with 1 and 0 exchanged ... pick the one # which yields a well-defined function) # [R, section 5] # (Note that this dummy will immediately go away again, so we # can safely pass S.One for ``expr``.) t = _dummy('t', 'meijerint-indefinite', S.One) def tr(p): return [a + rho + 1 for a in p] if any(b.is_integer and (b <= 0) == True for b in tr(g.bm)): r = -meijerg( tr(g.an), tr(g.aother) + [1], tr(g.bm) + [0], tr(g.bother), t) else: r = meijerg( tr(g.an) + [1], tr(g.aother), tr(g.bm), tr(g.bother) + [0], t) # The antiderivative is most often expected to be defined # in the neighborhood of x = 0. if b.is_extended_nonnegative and not f.subs(x, 0).has(nan, zoo): place = 0 # Assume we can expand at zero else: place = None r = hyperexpand(r.subs(t, a*x**b), place=place) # now substitute back # Note: we really do want the powers of x to combine. res += powdenest(fac_*r, polar=True) def _clean(res): """This multiplies out superfluous powers of x we created, and chops off constants: >> _clean(x*(exp(x)/x - 1/x) + 3) exp(x) cancel is used before mul_expand since it is possible for an expression to have an additive constant that doesn't become isolated with simple expansion. Such a situation was identified in issue 6369: Examples ======== >>> from sympy import sqrt, cancel >>> from sympy.abc import x >>> a = sqrt(2*x + 1) >>> bad = (3*x*a**5 + 2*x - a**5 + 1)/a**2 >>> bad.expand().as_independent(x)[0] 0 >>> cancel(bad).expand().as_independent(x)[0] 1 """ from sympy import cancel res = expand_mul(cancel(res), deep=False) return Add._from_args(res.as_coeff_add(x)[1]) res = piecewise_fold(res) if res.is_Piecewise: newargs = [] for expr, cond in res.args: expr = _my_unpolarify(_clean(expr)) newargs += [(expr, cond)] res = Piecewise(*newargs) else: res = _my_unpolarify(_clean(res)) return Piecewise((res, _my_unpolarify(cond)), (Integral(f, x), True)) @timeit def meijerint_definite(f, x, a, b): """ Integrate ``f`` over the interval [``a``, ``b``], by rewriting it as a product of two G functions, or as a single G function. Return res, cond, where cond are convergence conditions. Examples ======== >>> from sympy.integrals.meijerint import meijerint_definite >>> from sympy import exp, oo >>> from sympy.abc import x >>> meijerint_definite(exp(-x**2), x, -oo, oo) (sqrt(pi), True) This function is implemented as a succession of functions meijerint_definite, _meijerint_definite_2, _meijerint_definite_3, _meijerint_definite_4. Each function in the list calls the next one (presumably) several times. This means that calling meijerint_definite can be very costly. """ # This consists of three steps: # 1) Change the integration limits to 0, oo # 2) Rewrite in terms of G functions # 3) Evaluate the integral # # There are usually several ways of doing this, and we want to try all. # This function does (1), calls _meijerint_definite_2 for step (2). from sympy import arg, exp, I, And, DiracDelta, SingularityFunction _debug('Integrating', f, 'wrt %s from %s to %s.' % (x, a, b)) if f.has(DiracDelta): _debug('Integrand has DiracDelta terms - giving up.') return None if f.has(SingularityFunction): _debug('Integrand has Singularity Function terms - giving up.') return None f_, x_, a_, b_ = f, x, a, b # Let's use a dummy in case any of the boundaries has x. d = Dummy('x') f = f.subs(x, d) x = d if a == b: return (S.Zero, True) results = [] if a is -oo and b is not oo: return meijerint_definite(f.subs(x, -x), x, -b, -a) elif a is -oo: # Integrating -oo to oo. We need to find a place to split the integral. _debug(' Integrating -oo to +oo.') innermost = _find_splitting_points(f, x) _debug(' Sensible splitting points:', innermost) for c in sorted(innermost, key=default_sort_key, reverse=True) + [S.Zero]: _debug(' Trying to split at', c) if not c.is_extended_real: _debug(' Non-real splitting point.') continue res1 = _meijerint_definite_2(f.subs(x, x + c), x) if res1 is None: _debug(' But could not compute first integral.') continue res2 = _meijerint_definite_2(f.subs(x, c - x), x) if res2 is None: _debug(' But could not compute second integral.') continue res1, cond1 = res1 res2, cond2 = res2 cond = _condsimp(And(cond1, cond2)) if cond == False: _debug(' But combined condition is always false.') continue res = res1 + res2 return res, cond elif a is oo: res = meijerint_definite(f, x, b, oo) return -res[0], res[1] elif (a, b) == (0, oo): # This is a common case - try it directly first. res = _meijerint_definite_2(f, x) if res: if _has(res[0], meijerg): results.append(res) else: return res else: if b is oo: for split in _find_splitting_points(f, x): if (a - split >= 0) == True: _debug('Trying x -> x + %s' % split) res = _meijerint_definite_2(f.subs(x, x + split) *Heaviside(x + split - a), x) if res: if _has(res[0], meijerg): results.append(res) else: return res f = f.subs(x, x + a) b = b - a a = 0 if b != oo: phi = exp(I*arg(b)) b = abs(b) f = f.subs(x, phi*x) f *= Heaviside(b - x)*phi b = oo _debug('Changed limits to', a, b) _debug('Changed function to', f) res = _meijerint_definite_2(f, x) if res: if _has(res[0], meijerg): results.append(res) else: return res if f_.has(HyperbolicFunction): _debug('Try rewriting hyperbolics in terms of exp.') rv = meijerint_definite( _rewrite_hyperbolics_as_exp(f_), x_, a_, b_) if rv: if not type(rv) is list: rv = (collect(factor_terms(rv[0]), rv[0].atoms(exp)),) + rv[1:] return rv results.extend(rv) if results: return next(ordered(results)) def _guess_expansion(f, x): """ Try to guess sensible rewritings for integrand f(x). """ from sympy import expand_trig from sympy.functions.elementary.trigonometric import TrigonometricFunction res = [(f, 'original integrand')] orig = res[-1][0] saw = {orig} expanded = expand_mul(orig) if expanded not in saw: res += [(expanded, 'expand_mul')] saw.add(expanded) expanded = expand(orig) if expanded not in saw: res += [(expanded, 'expand')] saw.add(expanded) if orig.has(TrigonometricFunction, HyperbolicFunction): expanded = expand_mul(expand_trig(orig)) if expanded not in saw: res += [(expanded, 'expand_trig, expand_mul')] saw.add(expanded) if orig.has(cos, sin): reduced = sincos_to_sum(orig) if reduced not in saw: res += [(reduced, 'trig power reduction')] saw.add(reduced) return res def _meijerint_definite_2(f, x): """ Try to integrate f dx from zero to infinity. The body of this function computes various 'simplifications' f1, f2, ... of f (e.g. by calling expand_mul(), trigexpand() - see _guess_expansion) and calls _meijerint_definite_3 with each of these in succession. If _meijerint_definite_3 succeeds with any of the simplified functions, returns this result. """ # This function does preparation for (2), calls # _meijerint_definite_3 for (2) and (3) combined. # use a positive dummy - we integrate from 0 to oo # XXX if a nonnegative symbol is used there will be test failures dummy = _dummy('x', 'meijerint-definite2', f, positive=True) f = f.subs(x, dummy) x = dummy if f == 0: return S.Zero, True for g, explanation in _guess_expansion(f, x): _debug('Trying', explanation) res = _meijerint_definite_3(g, x) if res: return res def _meijerint_definite_3(f, x): """ Try to integrate f dx from zero to infinity. This function calls _meijerint_definite_4 to try to compute the integral. If this fails, it tries using linearity. """ res = _meijerint_definite_4(f, x) if res and res[1] != False: return res if f.is_Add: _debug('Expanding and evaluating all terms.') ress = [_meijerint_definite_4(g, x) for g in f.args] if all(r is not None for r in ress): conds = [] res = S.Zero for r, c in ress: res += r conds += [c] c = And(*conds) if c != False: return res, c def _my_unpolarify(f): from sympy import unpolarify return _eval_cond(unpolarify(f)) @timeit def _meijerint_definite_4(f, x, only_double=False): """ Try to integrate f dx from zero to infinity. Explanation =========== This function tries to apply the integration theorems found in literature, i.e. it tries to rewrite f as either one or a product of two G-functions. The parameter ``only_double`` is used internally in the recursive algorithm to disable trying to rewrite f as a single G-function. """ # This function does (2) and (3) _debug('Integrating', f) # Try single G function. if not only_double: gs = _rewrite1(f, x, recursive=False) if gs is not None: fac, po, g, cond = gs _debug('Could rewrite as single G function:', fac, po, g) res = S.Zero for C, s, f in g: if C == 0: continue C, f = _rewrite_saxena_1(fac*C, po*x**s, f, x) res += C*_int0oo_1(f, x) cond = And(cond, _check_antecedents_1(f, x)) if cond == False: break cond = _my_unpolarify(cond) if cond == False: _debug('But cond is always False.') else: _debug('Result before branch substitutions is:', res) return _my_unpolarify(hyperexpand(res)), cond # Try two G functions. gs = _rewrite2(f, x) if gs is not None: for full_pb in [False, True]: fac, po, g1, g2, cond = gs _debug('Could rewrite as two G functions:', fac, po, g1, g2) res = S.Zero for C1, s1, f1 in g1: for C2, s2, f2 in g2: r = _rewrite_saxena(fac*C1*C2, po*x**(s1 + s2), f1, f2, x, full_pb) if r is None: _debug('Non-rational exponents.') return C, f1_, f2_ = r _debug('Saxena subst for yielded:', C, f1_, f2_) cond = And(cond, _check_antecedents(f1_, f2_, x)) if cond == False: break res += C*_int0oo(f1_, f2_, x) else: continue break cond = _my_unpolarify(cond) if cond == False: _debug('But cond is always False (full_pb=%s).' % full_pb) else: _debug('Result before branch substitutions is:', res) if only_double: return res, cond return _my_unpolarify(hyperexpand(res)), cond def meijerint_inversion(f, x, t): r""" Compute the inverse laplace transform $\int_{c+i\infty}^{c-i\infty} f(x) e^{tx}\, dx$, for real c larger than the real part of all singularities of ``f``. Note that ``t`` is always assumed real and positive. Return None if the integral does not exist or could not be evaluated. Examples ======== >>> from sympy.abc import x, t >>> from sympy.integrals.meijerint import meijerint_inversion >>> meijerint_inversion(1/x, x, t) Heaviside(t) """ from sympy import exp, expand, log, Add, Mul, Heaviside f_ = f t_ = t t = Dummy('t', polar=True) # We don't want sqrt(t**2) = abs(t) etc f = f.subs(t_, t) _debug('Laplace-inverting', f) if not _is_analytic(f, x): _debug('But expression is not analytic.') return None # Exponentials correspond to shifts; we filter them out and then # shift the result later. If we are given an Add this will not # work, but the calling code will take care of that. shift = S.Zero if f.is_Mul: args = list(f.args) elif isinstance(f, exp): args = [f] else: args = None if args: newargs = [] exponentials = [] while args: arg = args.pop() if isinstance(arg, exp): arg2 = expand(arg) if arg2.is_Mul: args += arg2.args continue try: a, b = _get_coeff_exp(arg.args[0], x) except _CoeffExpValueError: b = 0 if b == 1: exponentials.append(a) else: newargs.append(arg) elif arg.is_Pow: arg2 = expand(arg) if arg2.is_Mul: args += arg2.args continue if x not in arg.base.free_symbols: try: a, b = _get_coeff_exp(arg.exp, x) except _CoeffExpValueError: b = 0 if b == 1: exponentials.append(a*log(arg.base)) newargs.append(arg) else: newargs.append(arg) shift = Add(*exponentials) f = Mul(*newargs) if x not in f.free_symbols: _debug('Expression consists of constant and exp shift:', f, shift) from sympy import Eq, im cond = Eq(im(shift), 0) if cond == False: _debug('but shift is nonreal, cannot be a Laplace transform') return None res = f*DiracDelta(t + shift) _debug('Result is a delta function, possibly conditional:', res, cond) # cond is True or Eq return Piecewise((res.subs(t, t_), cond)) gs = _rewrite1(f, x) if gs is not None: fac, po, g, cond = gs _debug('Could rewrite as single G function:', fac, po, g) res = S.Zero for C, s, f in g: C, f = _rewrite_inversion(fac*C, po*x**s, f, x) res += C*_int_inversion(f, x, t) cond = And(cond, _check_antecedents_inversion(f, x)) if cond == False: break cond = _my_unpolarify(cond) if cond == False: _debug('But cond is always False.') else: _debug('Result before branch substitution:', res) res = _my_unpolarify(hyperexpand(res)) if not res.has(Heaviside): res *= Heaviside(t) res = res.subs(t, t + shift) if not isinstance(cond, bool): cond = cond.subs(t, t + shift) from sympy import InverseLaplaceTransform return Piecewise((res.subs(t, t_), cond), (InverseLaplaceTransform(f_.subs(t, t_), x, t_, None), True)) sympy-sympy-1.9/sympy/integrals/meijerint_doc.py000066400000000000000000000020031412543434000222540ustar00rootroot00000000000000""" This module cooks up a docstring when imported. Its only purpose is to be displayed in the sphinx documentation. """ from typing import Any, Dict, List, Tuple, Type from sympy.integrals.meijerint import _create_lookup_table from sympy import latex, Eq, Add, Symbol t = {} # type: Dict[Tuple[Type, ...], List[Any]] _create_lookup_table(t) doc = "" for about, category in sorted(t.items()): if about == (): doc += 'Elementary functions:\n\n' else: doc += 'Functions involving ' + ', '.join('`%s`' % latex( list(category[0][0].atoms(func))[0]) for func in about) + ':\n\n' for formula, gs, cond, hint in category: if not isinstance(gs, list): g = Symbol('\\text{generated}') else: g = Add(*[fac*f for (fac, f) in gs]) obj = Eq(formula, g) if cond is True: cond = "" else: cond = ',\\text{ if } %s' % latex(cond) doc += ".. math::\n %s%s\n\n" % (latex(obj), cond) __doc__ = doc sympy-sympy-1.9/sympy/integrals/prde.py000066400000000000000000001454331412543434000204120ustar00rootroot00000000000000""" Algorithms for solving Parametric Risch Differential Equations. The methods used for solving Parametric Risch Differential Equations parallel those for solving Risch Differential Equations. See the outline in the docstring of rde.py for more information. The Parametric Risch Differential Equation problem is, given f, g1, ..., gm in K(t), to determine if there exist y in K(t) and c1, ..., cm in Const(K) such that Dy + f*y == Sum(ci*gi, (i, 1, m)), and to find such y and ci if they exist. For the algorithms here G is a list of tuples of factions of the terms on the right hand side of the equation (i.e., gi in k(t)), and Q is a list of terms on the right hand side of the equation (i.e., qi in k[t]). See the docstring of each function for more information. """ from functools import reduce from sympy.core import Dummy, ilcm, Add, Mul, Pow, S from sympy.integrals.rde import (order_at, order_at_oo, weak_normalizer, bound_degree) from sympy.integrals.risch import (gcdex_diophantine, frac_in, derivation, residue_reduce, splitfactor, residue_reduce_derivation, DecrementLevel, recognize_log_derivative) from sympy.polys import Poly, lcm, cancel, sqf_list from sympy.polys.polymatrix import PolyMatrix as Matrix from sympy.solvers import solve zeros = Matrix.zeros eye = Matrix.eye def prde_normal_denom(fa, fd, G, DE): """ Parametric Risch Differential Equation - Normal part of the denominator. Explanation =========== Given a derivation D on k[t] and f, g1, ..., gm in k(t) with f weakly normalized with respect to t, return the tuple (a, b, G, h) such that a, h in k[t], b in k, G = [g1, ..., gm] in k(t)^m, and for any solution c1, ..., cm in Const(k) and y in k(t) of Dy + f*y == Sum(ci*gi, (i, 1, m)), q == y*h in k satisfies a*Dq + b*q == Sum(ci*Gi, (i, 1, m)). """ dn, ds = splitfactor(fd, DE) Gas, Gds = list(zip(*G)) gd = reduce(lambda i, j: i.lcm(j), Gds, Poly(1, DE.t)) en, es = splitfactor(gd, DE) p = dn.gcd(en) h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t))) a = dn*h c = a*h ba = a*fa - dn*derivation(h, DE)*fd ba, bd = ba.cancel(fd, include=True) G = [(c*A).cancel(D, include=True) for A, D in G] return (a, (ba, bd), G, h) def real_imag(ba, bd, gen): """ Helper function, to get the real and imaginary part of a rational function evaluated at sqrt(-1) without actually evaluating it at sqrt(-1). Explanation =========== Separates the even and odd power terms by checking the degree of terms wrt mod 4. Returns a tuple (ba[0], ba[1], bd) where ba[0] is real part of the numerator ba[1] is the imaginary part and bd is the denominator of the rational function. """ bd = bd.as_poly(gen).as_dict() ba = ba.as_poly(gen).as_dict() denom_real = [value if key[0] % 4 == 0 else -value if key[0] % 4 == 2 else 0 for key, value in bd.items()] denom_imag = [value if key[0] % 4 == 1 else -value if key[0] % 4 == 3 else 0 for key, value in bd.items()] bd_real = sum(r for r in denom_real) bd_imag = sum(r for r in denom_imag) num_real = [value if key[0] % 4 == 0 else -value if key[0] % 4 == 2 else 0 for key, value in ba.items()] num_imag = [value if key[0] % 4 == 1 else -value if key[0] % 4 == 3 else 0 for key, value in ba.items()] ba_real = sum(r for r in num_real) ba_imag = sum(r for r in num_imag) ba = ((ba_real*bd_real + ba_imag*bd_imag).as_poly(gen), (ba_imag*bd_real - ba_real*bd_imag).as_poly(gen)) bd = (bd_real*bd_real + bd_imag*bd_imag).as_poly(gen) return (ba[0], ba[1], bd) def prde_special_denom(a, ba, bd, G, DE, case='auto'): """ Parametric Risch Differential Equation - Special part of the denominator. Explanation =========== Case is one of {'exp', 'tan', 'primitive'} for the hyperexponential, hypertangent, and primitive cases, respectively. For the hyperexponential (resp. hypertangent) case, given a derivation D on k[t] and a in k[t], b in k, and g1, ..., gm in k(t) with Dt/t in k (resp. Dt/(t**2 + 1) in k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. gcd(a, t**2 + 1) == 1), return the tuple (A, B, GG, h) such that A, B, h in k[t], GG = [gg1, ..., ggm] in k(t)^m, and for any solution c1, ..., cm in Const(k) and q in k of a*Dq + b*q == Sum(ci*gi, (i, 1, m)), r == q*h in k[t] satisfies A*Dr + B*r == Sum(ci*ggi, (i, 1, m)). For case == 'primitive', k == k[t], so it returns (a, b, G, 1) in this case. """ # TODO: Merge this with the very similar special_denom() in rde.py if case == 'auto': case = DE.case if case == 'exp': p = Poly(DE.t, DE.t) elif case == 'tan': p = Poly(DE.t**2 + 1, DE.t) elif case in ['primitive', 'base']: B = ba.quo(bd) return (a, B, G, Poly(1, DE.t)) else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'base'}, not %s." % case) nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) nc = min([order_at(Ga, p, DE.t) - order_at(Gd, p, DE.t) for Ga, Gd in G]) n = min(0, nc - min(0, nb)) if not nb: # Possible cancellation. if case == 'exp': dcoeff = DE.d.quo(Poly(DE.t, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) etaa, etad = frac_in(dcoeff, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: Q, m, z = A if Q == 1: n = min(n, m) elif case == 'tan': dcoeff = DE.d.quo(Poly(DE.t**2 + 1, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. betaa, alphaa, alphad = real_imag(ba, bd*a, DE.t) betad = alphad etaa, etad = frac_in(dcoeff, DE.t) if recognize_log_derivative(Poly(2, DE.t)*betaa, betad, DE): A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) B = parametric_log_deriv(betaa, betad, etaa, etad, DE) if A is not None and B is not None: Q, s, z = A # TODO: Add test if Q == 1: n = min(n, s/2) N = max(0, -nb) pN = p**N pn = p**-n # This is 1/h A = a*pN B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN G = [(Ga*pN*pn).cancel(Gd, include=True) for Ga, Gd in G] h = pn # (a*p**N, (b + n*a*Dp/p)*p**N, g1*p**(N - n), ..., gm*p**(N - n), p**-n) return (A, B, G, h) def prde_linear_constraints(a, b, G, DE): """ Parametric Risch Differential Equation - Generate linear constraints on the constants. Explanation =========== Given a derivation D on k[t], a, b, in k[t] with gcd(a, b) == 1, and G = [g1, ..., gm] in k(t)^m, return Q = [q1, ..., qm] in k[t]^m and a matrix M with entries in k(t) such that for any solution c1, ..., cm in Const(k) and p in k[t] of a*Dp + b*p == Sum(ci*gi, (i, 1, m)), (c1, ..., cm) is a solution of Mx == 0, and p and the ci satisfy a*Dp + b*p == Sum(ci*qi, (i, 1, m)). Because M has entries in k(t), and because Matrix doesn't play well with Poly, M will be a Matrix of Basic expressions. """ m = len(G) Gns, Gds = list(zip(*G)) d = reduce(lambda i, j: i.lcm(j), Gds) d = Poly(d, field=True) Q = [(ga*(d).quo(gd)).div(d) for ga, gd in G] if not all([ri.is_zero for _, ri in Q]): N = max([ri.degree(DE.t) for _, ri in Q]) M = Matrix(N + 1, m, lambda i, j: Q[j][1].nth(i), DE.t) else: M = Matrix(0, m, [], DE.t) # No constraints, return the empty matrix. qs, _ = list(zip(*Q)) return (qs, M) def poly_linear_constraints(p, d): """ Given p = [p1, ..., pm] in k[t]^m and d in k[t], return q = [q1, ..., qm] in k[t]^m and a matrix M with entries in k such that Sum(ci*pi, (i, 1, m)), for c1, ..., cm in k, is divisible by d if and only if (c1, ..., cm) is a solution of Mx = 0, in which case the quotient is Sum(ci*qi, (i, 1, m)). """ m = len(p) q, r = zip(*[pi.div(d) for pi in p]) if not all([ri.is_zero for ri in r]): n = max([ri.degree() for ri in r]) M = Matrix(n + 1, m, lambda i, j: r[j].nth(i), d.gens) else: M = Matrix(0, m, [], d.gens) # No constraints. return q, M def constant_system(A, u, DE): """ Generate a system for the constant solutions. Explanation =========== Given a differential field (K, D) with constant field C = Const(K), a Matrix A, and a vector (Matrix) u with coefficients in K, returns the tuple (B, v, s), where B is a Matrix with coefficients in C and v is a vector (Matrix) such that either v has coefficients in C, in which case s is True and the solutions in C of Ax == u are exactly all the solutions of Bx == v, or v has a non-constant coefficient, in which case s is False Ax == u has no constant solution. This algorithm is used both in solving parametric problems and in determining if an element a of K is a derivative of an element of K or the logarithmic derivative of a K-radical using the structure theorem approach. Because Poly does not play well with Matrix yet, this algorithm assumes that all matrix entries are Basic expressions. """ if not A: return A, u Au = A.row_join(u) Au, _ = Au.rref() # Warning: This will NOT return correct results if cancel() cannot reduce # an identically zero expression to 0. The danger is that we might # incorrectly prove that an integral is nonelementary (such as # risch_integrate(exp((sin(x)**2 + cos(x)**2 - 1)*x**2), x). # But this is a limitation in computer algebra in general, and implicit # in the correctness of the Risch Algorithm is the computability of the # constant field (actually, this same correctness problem exists in any # algorithm that uses rref()). # # We therefore limit ourselves to constant fields that are computable # via the cancel() function, in order to prevent a speed bottleneck from # calling some more complex simplification function (rational function # coefficients will fall into this class). Furthermore, (I believe) this # problem will only crop up if the integral explicitly contains an # expression in the constant field that is identically zero, but cannot # be reduced to such by cancel(). Therefore, a careful user can avoid this # problem entirely by being careful with the sorts of expressions that # appear in his integrand in the variables other than the integration # variable (the structure theorems should be able to completely decide these # problems in the integration variable). A, u = Au[:, :-1], Au[:, -1] D = lambda x: derivation(x, DE, basic=True) for j in range(A.cols): for i in range(A.rows): if A[i, j].expr.has(*DE.T): # This assumes that const(F(t0, ..., tn) == const(K) == F Ri = A[i, :] # Rm+1; m = A.rows DAij = D(A[i, j]) Rm1 = Ri.applyfunc(lambda x: D(x) / DAij) um1 = D(u[i]) / DAij Aj = A[:, j] A = A - Aj * Rm1 u = u - Aj * um1 A = A.col_join(Rm1) u = u.col_join(Matrix([um1], u.gens)) return (A, u) def prde_spde(a, b, Q, n, DE): """ Special Polynomial Differential Equation algorithm: Parametric Version. Explanation =========== Given a derivation D on k[t], an integer n, and a, b, q1, ..., qm in k[t] with deg(a) > 0 and gcd(a, b) == 1, return (A, B, Q, R, n1), with Qq = [q1, ..., qm] and R = [r1, ..., rm], such that for any solution c1, ..., cm in Const(k) and q in k[t] of degree at most n of a*Dq + b*q == Sum(ci*gi, (i, 1, m)), p = (q - Sum(ci*ri, (i, 1, m)))/a has degree at most n1 and satisfies A*Dp + B*p == Sum(ci*qi, (i, 1, m)) """ R, Z = list(zip(*[gcdex_diophantine(b, a, qi) for qi in Q])) A = a B = b + derivation(a, DE) Qq = [zi - derivation(ri, DE) for ri, zi in zip(R, Z)] R = list(R) n1 = n - a.degree(DE.t) return (A, B, Qq, R, n1) def prde_no_cancel_b_large(b, Q, n, DE): """ Parametric Poly Risch Differential Equation - No cancellation: deg(b) large enough. Explanation =========== Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with b != 0 and either D == d/dt or deg(b) > max(0, deg(D) - 1), returns h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and Dq + b*q == Sum(ci*qi, (i, 1, m)), then q = Sum(dj*hj, (j, 1, r)), where d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. """ db = b.degree(DE.t) m = len(Q) H = [Poly(0, DE.t)]*m for N in range(n, -1, -1): # [n, ..., 0] for i in range(m): si = Q[i].nth(N + db)/b.LC() sitn = Poly(si*DE.t**N, DE.t) H[i] = H[i] + sitn Q[i] = Q[i] - derivation(sitn, DE) - b*sitn if all(qi.is_zero for qi in Q): dc = -1 M = zeros(0, 2, DE.t) else: dc = max([qi.degree(DE.t) for qi in Q]) M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i), DE.t) A, u = constant_system(M, zeros(dc + 1, 1, DE.t), DE) c = eye(m, DE.t) A = A.row_join(zeros(A.rows, m, DE.t)).col_join(c.row_join(-c)) return (H, A) def prde_no_cancel_b_small(b, Q, n, DE): """ Parametric Poly Risch Differential Equation - No cancellation: deg(b) small enough. Explanation =========== Given a derivation D on k[t], n in ZZ, and b, q1, ..., qm in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or deg(D) >= 2, returns h1, ..., hr in k[t] and a matrix A with coefficients in Const(k) such that if c1, ..., cm in Const(k) and q in k[t] satisfy deg(q) <= n and Dq + b*q == Sum(ci*qi, (i, 1, m)) then q = Sum(dj*hj, (j, 1, r)) where d1, ..., dr in Const(k) and A*Matrix([[c1, ..., cm, d1, ..., dr]]).T == 0. """ m = len(Q) H = [Poly(0, DE.t)]*m for N in range(n, 0, -1): # [n, ..., 1] for i in range(m): si = Q[i].nth(N + DE.d.degree(DE.t) - 1)/(N*DE.d.LC()) sitn = Poly(si*DE.t**N, DE.t) H[i] = H[i] + sitn Q[i] = Q[i] - derivation(sitn, DE) - b*sitn if b.degree(DE.t) > 0: for i in range(m): si = Poly(Q[i].nth(b.degree(DE.t))/b.LC(), DE.t) H[i] = H[i] + si Q[i] = Q[i] - derivation(si, DE) - b*si if all(qi.is_zero for qi in Q): dc = -1 M = Matrix() else: dc = max([qi.degree(DE.t) for qi in Q]) M = Matrix(dc + 1, m, lambda i, j: Q[j].nth(i), DE.t) A, u = constant_system(M, zeros(dc + 1, 1, DE.t), DE) c = eye(m, DE.t) A = A.row_join(zeros(A.rows, m, DE.t)).col_join(c.row_join(-c)) return (H, A) # else: b is in k, deg(qi) < deg(Dt) t = DE.t if DE.case != 'base': with DecrementLevel(DE): t0 = DE.t # k = k0(t0) ba, bd = frac_in(b, t0, field=True) Q0 = [frac_in(qi.TC(), t0, field=True) for qi in Q] f, B = param_rischDE(ba, bd, Q0, DE) # f = [f1, ..., fr] in k^r and B is a matrix with # m + r columns and entries in Const(k) = Const(k0) # such that Dy0 + b*y0 = Sum(ci*qi, (i, 1, m)) has # a solution y0 in k with c1, ..., cm in Const(k) # if and only y0 = Sum(dj*fj, (j, 1, r)) where # d1, ..., dr ar in Const(k) and # B*Matrix([c1, ..., cm, d1, ..., dr]) == 0. # Transform fractions (fa, fd) in f into constant # polynomials fa/fd in k[t]. # (Is there a better way?) f = [Poly(fa.as_expr()/fd.as_expr(), t, field=True) for fa, fd in f] B = Matrix.from_Matrix(B.to_Matrix(), t) else: # Base case. Dy == 0 for all y in k and b == 0. # Dy + b*y = Sum(ci*qi) is solvable if and only if # Sum(ci*qi) == 0 in which case the solutions are # y = d1*f1 for f1 = 1 and any d1 in Const(k) = k. f = [Poly(1, t, field=True)] # r = 1 B = Matrix([[qi.TC() for qi in Q] + [S.Zero]], DE.t) # The condition for solvability is # B*Matrix([c1, ..., cm, d1]) == 0 # There are no constraints on d1. # Coefficients of t^j (j > 0) in Sum(ci*qi) must be zero. d = max([qi.degree(DE.t) for qi in Q]) if d > 0: M = Matrix(d, m, lambda i, j: Q[j].nth(i + 1), DE.t) A, _ = constant_system(M, zeros(d, 1, DE.t), DE) else: # No constraints on the hj. A = Matrix(0, m, [], DE.t) # Solutions of the original equation are # y = Sum(dj*fj, (j, 1, r) + Sum(ei*hi, (i, 1, m)), # where ei == ci (i = 1, ..., m), when # A*Matrix([c1, ..., cm]) == 0 and # B*Matrix([c1, ..., cm, d1, ..., dr]) == 0 # Build combined constraint matrix with m + r + m columns. r = len(f) I = eye(m, DE.t) A = A.row_join(zeros(A.rows, r + m, DE.t)) B = B.row_join(zeros(B.rows, m, DE.t)) C = I.row_join(zeros(m, r, DE.t)).row_join(-I) return f + H, A.col_join(B).col_join(C) def prde_cancel_liouvillian(b, Q, n, DE): """ Pg, 237. """ H = [] # Why use DecrementLevel? Below line answers that: # Assuming that we can solve such problems over 'k' (not k[t]) if DE.case == 'primitive': with DecrementLevel(DE): ba, bd = frac_in(b, DE.t, field=True) for i in range(n, -1, -1): if DE.case == 'exp': # this re-checking can be avoided with DecrementLevel(DE): ba, bd = frac_in(b + (i*(derivation(DE.t, DE)/DE.t)).as_poly(b.gens), DE.t, field=True) with DecrementLevel(DE): Qy = [frac_in(q.nth(i), DE.t, field=True) for q in Q] fi, Ai = param_rischDE(ba, bd, Qy, DE) fi = [Poly(fa.as_expr()/fd.as_expr(), DE.t, field=True) for fa, fd in fi] Ai = Ai.set_gens(DE.t) ri = len(fi) if i == n: M = Ai else: M = Ai.col_join(M.row_join(zeros(M.rows, ri, DE.t))) Fi, hi = [None]*ri, [None]*ri # from eq. on top of p.238 (unnumbered) for j in range(ri): hji = fi[j] * (DE.t**i).as_poly(fi[j].gens) hi[j] = hji # building up Sum(djn*(D(fjn*t^n) - b*fjnt^n)) Fi[j] = -(derivation(hji, DE) - b*hji) H += hi # in the next loop instead of Q it has # to be Q + Fi taking its place Q = Q + Fi return (H, M) def param_poly_rischDE(a, b, q, n, DE): """Polynomial solutions of a parametric Risch differential equation. Explanation =========== Given a derivation D in k[t], a, b in k[t] relatively prime, and q = [q1, ..., qm] in k[t]^m, return h = [h1, ..., hr] in k[t]^r and a matrix A with m + r columns and entries in Const(k) such that a*Dp + b*p = Sum(ci*qi, (i, 1, m)) has a solution p of degree <= n in k[t] with c1, ..., cm in Const(k) if and only if p = Sum(dj*hj, (j, 1, r)) where d1, ..., dr are in Const(k) and (c1, ..., cm, d1, ..., dr) is a solution of Ax == 0. """ m = len(q) if n < 0: # Only the trivial zero solution is possible. # Find relations between the qi. if all([qi.is_zero for qi in q]): return [], zeros(1, m, DE.t) # No constraints. N = max([qi.degree(DE.t) for qi in q]) M = Matrix(N + 1, m, lambda i, j: q[j].nth(i), DE.t) A, _ = constant_system(M, zeros(M.rows, 1, DE.t), DE) return [], A if a.is_ground: # Normalization: a = 1. a = a.LC() b, q = b.quo_ground(a), [qi.quo_ground(a) for qi in q] if not b.is_zero and (DE.case == 'base' or b.degree() > max(0, DE.d.degree() - 1)): return prde_no_cancel_b_large(b, q, n, DE) elif ((b.is_zero or b.degree() < DE.d.degree() - 1) and (DE.case == 'base' or DE.d.degree() >= 2)): return prde_no_cancel_b_small(b, q, n, DE) elif (DE.d.degree() >= 2 and b.degree() == DE.d.degree() - 1 and n > -b.as_poly().LC()/DE.d.as_poly().LC()): raise NotImplementedError("prde_no_cancel_b_equal() is " "not yet implemented.") else: # Liouvillian cases if DE.case == 'primitive' or DE.case == 'exp': return prde_cancel_liouvillian(b, q, n, DE) else: raise NotImplementedError("non-linear and hypertangent " "cases have not yet been implemented") # else: deg(a) > 0 # Iterate SPDE as long as possible cumulating coefficient # and terms for the recovery of original solutions. alpha, beta = a.one, [a.zero]*m while n >= 0: # and a, b relatively prime a, b, q, r, n = prde_spde(a, b, q, n, DE) beta = [betai + alpha*ri for betai, ri in zip(beta, r)] alpha *= a # Solutions p of a*Dp + b*p = Sum(ci*qi) correspond to # solutions alpha*p + Sum(ci*betai) of the initial equation. d = a.gcd(b) if not d.is_ground: break # a*Dp + b*p = Sum(ci*qi) may have a polynomial solution # only if the sum is divisible by d. qq, M = poly_linear_constraints(q, d) # qq = [qq1, ..., qqm] where qqi = qi.quo(d). # M is a matrix with m columns an entries in k. # Sum(fi*qi, (i, 1, m)), where f1, ..., fm are elements of k, is # divisible by d if and only if M*Matrix([f1, ..., fm]) == 0, # in which case the quotient is Sum(fi*qqi). A, _ = constant_system(M, zeros(M.rows, 1, DE.t), DE) # A is a matrix with m columns and entries in Const(k). # Sum(ci*qqi) is Sum(ci*qi).quo(d), and the remainder is zero # for c1, ..., cm in Const(k) if and only if # A*Matrix([c1, ...,cm]) == 0. V = A.nullspace() # V = [v1, ..., vu] where each vj is a column matrix with # entries aj1, ..., ajm in Const(k). # Sum(aji*qi) is divisible by d with exact quotient Sum(aji*qqi). # Sum(ci*qi) is divisible by d if and only if ci = Sum(dj*aji) # (i = 1, ..., m) for some d1, ..., du in Const(k). # In that case, solutions of # a*Dp + b*p = Sum(ci*qi) = Sum(dj*Sum(aji*qi)) # are the same as those of # (a/d)*Dp + (b/d)*p = Sum(dj*rj) # where rj = Sum(aji*qqi). if not V: # No non-trivial solution. return [], eye(m, DE.t) # Could return A, but this has # the minimum number of rows. Mqq = Matrix([qq]) # A single row. r = [(Mqq*vj)[0] for vj in V] # [r1, ..., ru] # Solutions of (a/d)*Dp + (b/d)*p = Sum(dj*rj) correspond to # solutions alpha*p + Sum(Sum(dj*aji)*betai) of the initial # equation. These are equal to alpha*p + Sum(dj*fj) where # fj = Sum(aji*betai). Mbeta = Matrix([beta]) f = [(Mbeta*vj)[0] for vj in V] # [f1, ..., fu] # # Solve the reduced equation recursively. # g, B = param_poly_rischDE(a.quo(d), b.quo(d), r, n, DE) # g = [g1, ..., gv] in k[t]^v and and B is a matrix with u + v # columns and entries in Const(k) such that # (a/d)*Dp + (b/d)*p = Sum(dj*rj) has a solution p of degree <= n # in k[t] if and only if p = Sum(ek*gk) where e1, ..., ev are in # Const(k) and B*Matrix([d1, ..., du, e1, ..., ev]) == 0. # The solutions of the original equation are then # Sum(dj*fj, (j, 1, u)) + alpha*Sum(ek*gk, (k, 1, v)). # Collect solution components. h = f + [alpha*gk for gk in g] # Build combined relation matrix. A = -eye(m, DE.t) for vj in V: A = A.row_join(vj) A = A.row_join(zeros(m, len(g), DE.t)) A = A.col_join(zeros(B.rows, m, DE.t).row_join(B)) return h, A def param_rischDE(fa, fd, G, DE): """ Solve a Parametric Risch Differential Equation: Dy + f*y == Sum(ci*Gi, (i, 1, m)). Explanation =========== Given a derivation D in k(t), f in k(t), and G = [G1, ..., Gm] in k(t)^m, return h = [h1, ..., hr] in k(t)^r and a matrix A with m + r columns and entries in Const(k) such that Dy + f*y = Sum(ci*Gi, (i, 1, m)) has a solution y in k(t) with c1, ..., cm in Const(k) if and only if y = Sum(dj*hj, (j, 1, r)) where d1, ..., dr are in Const(k) and (c1, ..., cm, d1, ..., dr) is a solution of Ax == 0. Elements of k(t) are tuples (a, d) with a and d in k[t]. """ m = len(G) q, (fa, fd) = weak_normalizer(fa, fd, DE) # Solutions of the weakly normalized equation Dz + f*z = q*Sum(ci*Gi) # correspond to solutions y = z/q of the original equation. gamma = q G = [(q*ga).cancel(gd, include=True) for ga, gd in G] a, (ba, bd), G, hn = prde_normal_denom(fa, fd, G, DE) # Solutions q in k of a*Dq + b*q = Sum(ci*Gi) correspond # to solutions z = q/hn of the weakly normalized equation. gamma *= hn A, B, G, hs = prde_special_denom(a, ba, bd, G, DE) # Solutions p in k[t] of A*Dp + B*p = Sum(ci*Gi) correspond # to solutions q = p/hs of the previous equation. gamma *= hs g = A.gcd(B) a, b, g = A.quo(g), B.quo(g), [gia.cancel(gid*g, include=True) for gia, gid in G] # a*Dp + b*p = Sum(ci*gi) may have a polynomial solution # only if the sum is in k[t]. q, M = prde_linear_constraints(a, b, g, DE) # q = [q1, ..., qm] where qi in k[t] is the polynomial component # of the partial fraction expansion of gi. # M is a matrix with m columns and entries in k. # Sum(fi*gi, (i, 1, m)), where f1, ..., fm are elements of k, # is a polynomial if and only if M*Matrix([f1, ..., fm]) == 0, # in which case the sum is equal to Sum(fi*qi). M, _ = constant_system(M, zeros(M.rows, 1, DE.t), DE) # M is a matrix with m columns and entries in Const(k). # Sum(ci*gi) is in k[t] for c1, ..., cm in Const(k) # if and only if M*Matrix([c1, ..., cm]) == 0, # in which case the sum is Sum(ci*qi). ## Reduce number of constants at this point V = M.nullspace() # V = [v1, ..., vu] where each vj is a column matrix with # entries aj1, ..., ajm in Const(k). # Sum(aji*gi) is in k[t] and equal to Sum(aji*qi) (j = 1, ..., u). # Sum(ci*gi) is in k[t] if and only is ci = Sum(dj*aji) # (i = 1, ..., m) for some d1, ..., du in Const(k). # In that case, # Sum(ci*gi) = Sum(ci*qi) = Sum(dj*Sum(aji*qi)) = Sum(dj*rj) # where rj = Sum(aji*qi) (j = 1, ..., u) in k[t]. if not V: # No non-trivial solution return [], eye(m, DE.t) Mq = Matrix([q]) # A single row. r = [(Mq*vj)[0] for vj in V] # [r1, ..., ru] # Solutions of a*Dp + b*p = Sum(dj*rj) correspond to solutions # y = p/gamma of the initial equation with ci = Sum(dj*aji). try: # We try n=5. At least for prde_spde, it will always # terminate no matter what n is. n = bound_degree(a, b, r, DE, parametric=True) except NotImplementedError: # A temporary bound is set. Eventually, it will be removed. # the currently added test case takes large time # even with n=5, and much longer with large n's. n = 5 h, B = param_poly_rischDE(a, b, r, n, DE) # h = [h1, ..., hv] in k[t]^v and and B is a matrix with u + v # columns and entries in Const(k) such that # a*Dp + b*p = Sum(dj*rj) has a solution p of degree <= n # in k[t] if and only if p = Sum(ek*hk) where e1, ..., ev are in # Const(k) and B*Matrix([d1, ..., du, e1, ..., ev]) == 0. # The solutions of the original equation for ci = Sum(dj*aji) # (i = 1, ..., m) are then y = Sum(ek*hk, (k, 1, v))/gamma. ## Build combined relation matrix with m + u + v columns. A = -eye(m, DE.t) for vj in V: A = A.row_join(vj) A = A.row_join(zeros(m, len(h), DE.t)) A = A.col_join(zeros(B.rows, m, DE.t).row_join(B)) ## Eliminate d1, ..., du. W = A.nullspace() # W = [w1, ..., wt] where each wl is a column matrix with # entries blk (k = 1, ..., m + u + v) in Const(k). # The vectors (bl1, ..., blm) generate the space of those # constant families (c1, ..., cm) for which a solution of # the equation Dy + f*y == Sum(ci*Gi) exists. They generate # the space and form a basis except possibly when Dy + f*y == 0 # is solvable in k(t}. The corresponding solutions are # y = Sum(blk'*hk, (k, 1, v))/gamma, where k' = k + m + u. v = len(h) M = Matrix([wl[:m] + wl[-v:] for wl in W]) # excise dj's. N = M.nullspace() # N = [n1, ..., ns] where the ni in Const(k)^(m + v) are column # vectors generating the space of linear relations between # c1, ..., cm, e1, ..., ev. C = Matrix([ni[:] for ni in N], DE.t) # rows n1, ..., ns. return [hk.cancel(gamma, include=True) for hk in h], C def limited_integrate_reduce(fa, fd, G, DE): """ Simpler version of step 1 & 2 for the limited integration problem. Explanation =========== Given a derivation D on k(t) and f, g1, ..., gn in k(t), return (a, b, h, N, g, V) such that a, b, h in k[t], N is a non-negative integer, g in k(t), V == [v1, ..., vm] in k(t)^m, and for any solution v in k(t), c1, ..., cm in C of f == Dv + Sum(ci*wi, (i, 1, m)), p = v*h is in k, and p and the ci satisfy a*Dp + b*p == g + Sum(ci*vi, (i, 1, m)). Furthermore, if S1irr == Sirr, then p is in k[t], and if t is nonlinear or Liouvillian over k, then deg(p) <= N. So that the special part is always computed, this function calls the more general prde_special_denom() automatically if it cannot determine that S1irr == Sirr. Furthermore, it will automatically call bound_degree() when t is linear and non-Liouvillian, which for the transcendental case, implies that Dt == a*t + b with for some a, b in k*. """ dn, ds = splitfactor(fd, DE) E = [splitfactor(gd, DE) for _, gd in G] En, Es = list(zip(*E)) c = reduce(lambda i, j: i.lcm(j), (dn,) + En) # lcm(dn, en1, ..., enm) hn = c.gcd(c.diff(DE.t)) a = hn b = -derivation(hn, DE) N = 0 # These are the cases where we know that S1irr = Sirr, but there could be # others, and this algorithm will need to be extended to handle them. if DE.case in ['base', 'primitive', 'exp', 'tan']: hs = reduce(lambda i, j: i.lcm(j), (ds,) + Es) # lcm(ds, es1, ..., esm) a = hn*hs b -= (hn*derivation(hs, DE)).quo(hs) mu = min(order_at_oo(fa, fd, DE.t), min([order_at_oo(ga, gd, DE.t) for ga, gd in G])) # So far, all the above are also nonlinear or Liouvillian, but if this # changes, then this will need to be updated to call bound_degree() # as per the docstring of this function (DE.case == 'other_linear'). N = hn.degree(DE.t) + hs.degree(DE.t) + max(0, 1 - DE.d.degree(DE.t) - mu) else: # TODO: implement this raise NotImplementedError V = [(-a*hn*ga).cancel(gd, include=True) for ga, gd in G] return (a, b, a, N, (a*hn*fa).cancel(fd, include=True), V) def limited_integrate(fa, fd, G, DE): """ Solves the limited integration problem: f = Dv + Sum(ci*wi, (i, 1, n)) """ fa, fd = fa*Poly(1/fd.LC(), DE.t), fd.monic() # interpreting limited integration problem as a # parametric Risch DE problem Fa = Poly(0, DE.t) Fd = Poly(1, DE.t) G = [(fa, fd)] + G h, A = param_rischDE(Fa, Fd, G, DE) V = A.nullspace() V = [v for v in V if v[0] != 0] if not V: return None else: # we can take any vector from V, we take V[0] c0 = V[0][0] # v = [-1, c1, ..., cm, d1, ..., dr] v = V[0]/(-c0) r = len(h) m = len(v) - r - 1 C = list(v[1: m + 1]) y = -sum([v[m + 1 + i]*h[i][0].as_expr()/h[i][1].as_expr() \ for i in range(r)]) y_num, y_den = y.as_numer_denom() Ya, Yd = Poly(y_num, DE.t), Poly(y_den, DE.t) Y = Ya*Poly(1/Yd.LC(), DE.t), Yd.monic() return Y, C def parametric_log_deriv_heu(fa, fd, wa, wd, DE, c1=None): """ Parametric logarithmic derivative heuristic. Explanation =========== Given a derivation D on k[t], f in k(t), and a hyperexponential monomial theta over k(t), raises either NotImplementedError, in which case the heuristic failed, or returns None, in which case it has proven that no solution exists, or returns a solution (n, m, v) of the equation n*f == Dv/v + m*Dtheta/theta, with v in k(t)* and n, m in ZZ with n != 0. If this heuristic fails, the structure theorem approach will need to be used. The argument w == Dtheta/theta """ # TODO: finish writing this and write tests c1 = c1 or Dummy('c1') p, a = fa.div(fd) q, b = wa.div(wd) B = max(0, derivation(DE.t, DE).degree(DE.t) - 1) C = max(p.degree(DE.t), q.degree(DE.t)) if q.degree(DE.t) > B: eqs = [p.nth(i) - c1*q.nth(i) for i in range(B + 1, C + 1)] s = solve(eqs, c1) if not s or not s[c1].is_Rational: # deg(q) > B, no solution for c. return None M, N = s[c1].as_numer_denom() M_poly = M.as_poly(q.gens) N_poly = N.as_poly(q.gens) nfmwa = N_poly*fa*wd - M_poly*wa*fd nfmwd = fd*wd Qv = is_log_deriv_k_t_radical_in_field(nfmwa, nfmwd, DE, 'auto') if Qv is None: # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical. return None Q, v = Qv if Q.is_zero or v.is_zero: return None return (Q*N, Q*M, v) if p.degree(DE.t) > B: return None c = lcm(fd.as_poly(DE.t).LC(), wd.as_poly(DE.t).LC()) l = fd.monic().lcm(wd.monic())*Poly(c, DE.t) ln, ls = splitfactor(l, DE) z = ls*ln.gcd(ln.diff(DE.t)) if not z.has(DE.t): # TODO: We treat this as 'no solution', until the structure # theorem version of parametric_log_deriv is implemented. return None u1, r1 = (fa*l.quo(fd)).div(z) # (l*f).div(z) u2, r2 = (wa*l.quo(wd)).div(z) # (l*w).div(z) eqs = [r1.nth(i) - c1*r2.nth(i) for i in range(z.degree(DE.t))] s = solve(eqs, c1) if not s or not s[c1].is_Rational: # deg(q) <= B, no solution for c. return None M, N = s[c1].as_numer_denom() nfmwa = N.as_poly(DE.t)*fa*wd - M.as_poly(DE.t)*wa*fd nfmwd = fd*wd Qv = is_log_deriv_k_t_radical_in_field(nfmwa, nfmwd, DE) if Qv is None: # (N*f - M*w) is not the logarithmic derivative of a k(t)-radical. return None Q, v = Qv if Q.is_zero or v.is_zero: return None return (Q*N, Q*M, v) def parametric_log_deriv(fa, fd, wa, wd, DE): # TODO: Write the full algorithm using the structure theorems. # try: A = parametric_log_deriv_heu(fa, fd, wa, wd, DE) # except NotImplementedError: # Heuristic failed, we have to use the full method. # TODO: This could be implemented more efficiently. # It isn't too worrisome, because the heuristic handles most difficult # cases. return A def is_deriv_k(fa, fd, DE): r""" Checks if Df/f is the derivative of an element of k(t). Explanation =========== a in k(t) is the derivative of an element of k(t) if there exists b in k(t) such that a = Db. Either returns (ans, u), such that Df/f == Du, or None, which means that Df/f is not the derivative of an element of k(t). ans is a list of tuples such that Add(*[i*j for i, j in ans]) == u. This is useful for seeing exactly which elements of k(t) produce u. This function uses the structure theorem approach, which says that for any f in K, Df/f is the derivative of a element of K if and only if there are ri in QQ such that:: --- --- Dt \ r * Dt + \ r * i Df / i i / i --- = --. --- --- t f i in L i in E i K/C(x) K/C(x) Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of hyperexponential monomials of K over C(x)). If K is an elementary extension over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the transcendence degree of K over C(x). Furthermore, because Const_D(K) == Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) and L_K/C(x) are disjoint. The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed recursively using this same function. Therefore, it is required to pass them as indices to D (or T). E_args are the arguments of the hyperexponentials indexed by E_K (i.e., if i is in E_K, then T[i] == exp(E_args[i])). This is needed to compute the final answer u such that Df/f == Du. log(f) will be the same as u up to a additive constant. This is because they will both behave the same as monomials. For example, both log(x) and log(2*x) == log(x) + log(2) satisfy Dt == 1/x, because log(2) is constant. Therefore, the term const is returned. const is such that log(const) + f == u. This is calculated by dividing the arguments of one logarithm from the other. Therefore, it is necessary to pass the arguments of the logarithmic terms in L_args. To handle the case where we are given Df/f, not f, use is_deriv_k_in_field(). See also ======== is_log_deriv_k_t_radical_in_field, is_log_deriv_k_t_radical """ # Compute Df/f dfa, dfd = (fd*derivation(fa, DE) - fa*derivation(fd, DE)), fd*fa dfa, dfd = dfa.cancel(dfd, include=True) # Our assumption here is that each monomial is recursively transcendental if len(DE.exts) != len(DE.D): if [i for i in DE.cases if i == 'tan'] or \ ({i for i in DE.cases if i == 'primitive'} - set(DE.indices('log'))): raise NotImplementedError("Real version of the structure " "theorems with hypertangent support is not yet implemented.") # TODO: What should really be done in this case? raise NotImplementedError("Nonelementary extensions not supported " "in the structure theorems.") E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.indices('exp')] L_part = [DE.D[i].as_expr() for i in DE.indices('log')] # The expression dfa/dfd might not be polynomial in any of its symbols so we # use a Dummy as the generator for PolyMatrix. dum = Dummy() lhs = Matrix([E_part + L_part], dum) rhs = Matrix([dfa.as_expr()/dfd.as_expr()], dum) A, u = constant_system(lhs, rhs, DE) u = u.to_Matrix() # Poly to Expr if not all(derivation(i, DE, basic=True).is_zero for i in u) or not A: # If the elements of u are not all constant # Note: See comment in constant_system # Also note: derivation(basic=True) calls cancel() return None else: if not all(i.is_Rational for i in u): raise NotImplementedError("Cannot work with non-rational " "coefficients in this case.") else: terms = ([DE.extargs[i] for i in DE.indices('exp')] + [DE.T[i] for i in DE.indices('log')]) ans = list(zip(terms, u)) result = Add(*[Mul(i, j) for i, j in ans]) argterms = ([DE.T[i] for i in DE.indices('exp')] + [DE.extargs[i] for i in DE.indices('log')]) l = [] ld = [] for i, j in zip(argterms, u): # We need to get around things like sqrt(x**2) != x # and also sqrt(x**2 + 2*x + 1) != x + 1 # Issue 10798: i need not be a polynomial i, d = i.as_numer_denom() icoeff, iterms = sqf_list(i) l.append(Mul(*([Pow(icoeff, j)] + [Pow(b, e*j) for b, e in iterms]))) dcoeff, dterms = sqf_list(d) ld.append(Mul(*([Pow(dcoeff, j)] + [Pow(b, e*j) for b, e in dterms]))) const = cancel(fa.as_expr()/fd.as_expr()/Mul(*l)*Mul(*ld)) return (ans, result, const) def is_log_deriv_k_t_radical(fa, fd, DE, Df=True): r""" Checks if Df is the logarithmic derivative of a k(t)-radical. Explanation =========== b in k(t) can be written as the logarithmic derivative of a k(t) radical if there exist n in ZZ and u in k(t) with n, u != 0 such that n*b == Du/u. Either returns (ans, u, n, const) or None, which means that Df cannot be written as the logarithmic derivative of a k(t)-radical. ans is a list of tuples such that Mul(*[i**j for i, j in ans]) == u. This is useful for seeing exactly what elements of k(t) produce u. This function uses the structure theorem approach, which says that for any f in K, Df is the logarithmic derivative of a K-radical if and only if there are ri in QQ such that:: --- --- Dt \ r * Dt + \ r * i / i i / i --- = Df. --- --- t i in L i in E i K/C(x) K/C(x) Where C = Const(K), L_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i = Da_i/a_i, for some a_i in C(x)(t_1, ..., t_i-1)* } (i.e., the set of all indices of logarithmic monomials of K over C(x)), and E_K/C(x) = { i in {1, ..., n} such that t_i is transcendental over C(x)(t_1, ..., t_i-1) and Dt_i/t_i = Da_i, for some a_i in C(x)(t_1, ..., t_i-1) } (i.e., the set of all indices of hyperexponential monomials of K over C(x)). If K is an elementary extension over C(x), then the cardinality of L_K/C(x) U E_K/C(x) is exactly the transcendence degree of K over C(x). Furthermore, because Const_D(K) == Const_D(C(x)) == C, deg(Dt_i) == 1 when t_i is in E_K/C(x) and deg(Dt_i) == 0 when t_i is in L_K/C(x), implying in particular that E_K/C(x) and L_K/C(x) are disjoint. The sets L_K/C(x) and E_K/C(x) must, by their nature, be computed recursively using this same function. Therefore, it is required to pass them as indices to D (or T). L_args are the arguments of the logarithms indexed by L_K (i.e., if i is in L_K, then T[i] == log(L_args[i])). This is needed to compute the final answer u such that n*f == Du/u. exp(f) will be the same as u up to a multiplicative constant. This is because they will both behave the same as monomials. For example, both exp(x) and exp(x + 1) == E*exp(x) satisfy Dt == t. Therefore, the term const is returned. const is such that exp(const)*f == u. This is calculated by subtracting the arguments of one exponential from the other. Therefore, it is necessary to pass the arguments of the exponential terms in E_args. To handle the case where we are given Df, not f, use is_log_deriv_k_t_radical_in_field(). See also ======== is_log_deriv_k_t_radical_in_field, is_deriv_k """ if Df: dfa, dfd = (fd*derivation(fa, DE) - fa*derivation(fd, DE)).cancel(fd**2, include=True) else: dfa, dfd = fa, fd # Our assumption here is that each monomial is recursively transcendental if len(DE.exts) != len(DE.D): if [i for i in DE.cases if i == 'tan'] or \ ({i for i in DE.cases if i == 'primitive'} - set(DE.indices('log'))): raise NotImplementedError("Real version of the structure " "theorems with hypertangent support is not yet implemented.") # TODO: What should really be done in this case? raise NotImplementedError("Nonelementary extensions not supported " "in the structure theorems.") E_part = [DE.D[i].quo(Poly(DE.T[i], DE.T[i])).as_expr() for i in DE.indices('exp')] L_part = [DE.D[i].as_expr() for i in DE.indices('log')] # The expression dfa/dfd might not be polynomial in any of its symbols so we # use a Dummy as the generator for PolyMatrix. dum = Dummy() lhs = Matrix([E_part + L_part], dum) rhs = Matrix([dfa.as_expr()/dfd.as_expr()], dum) A, u = constant_system(lhs, rhs, DE) u = u.to_Matrix() # Poly to Expr if not all(derivation(i, DE, basic=True).is_zero for i in u) or not A: # If the elements of u are not all constant # Note: See comment in constant_system # Also note: derivation(basic=True) calls cancel() return None else: if not all(i.is_Rational for i in u): # TODO: But maybe we can tell if they're not rational, like # log(2)/log(3). Also, there should be an option to continue # anyway, even if the result might potentially be wrong. raise NotImplementedError("Cannot work with non-rational " "coefficients in this case.") else: n = reduce(ilcm, [i.as_numer_denom()[1] for i in u]) u *= n terms = ([DE.T[i] for i in DE.indices('exp')] + [DE.extargs[i] for i in DE.indices('log')]) ans = list(zip(terms, u)) result = Mul(*[Pow(i, j) for i, j in ans]) # exp(f) will be the same as result up to a multiplicative # constant. We now find the log of that constant. argterms = ([DE.extargs[i] for i in DE.indices('exp')] + [DE.T[i] for i in DE.indices('log')]) const = cancel(fa.as_expr()/fd.as_expr() - Add(*[Mul(i, j/n) for i, j in zip(argterms, u)])) return (ans, result, n, const) def is_log_deriv_k_t_radical_in_field(fa, fd, DE, case='auto', z=None): """ Checks if f can be written as the logarithmic derivative of a k(t)-radical. Explanation =========== It differs from is_log_deriv_k_t_radical(fa, fd, DE, Df=False) for any given fa, fd, DE in that it finds the solution in the given field not in some (possibly unspecified extension) and "in_field" with the function name is used to indicate that. f in k(t) can be written as the logarithmic derivative of a k(t) radical if there exist n in ZZ and u in k(t) with n, u != 0 such that n*f == Du/u. Either returns (n, u) or None, which means that f cannot be written as the logarithmic derivative of a k(t)-radical. case is one of {'primitive', 'exp', 'tan', 'auto'} for the primitive, hyperexponential, and hypertangent cases, respectively. If case is 'auto', it will attempt to determine the type of the derivation automatically. See also ======== is_log_deriv_k_t_radical, is_deriv_k """ fa, fd = fa.cancel(fd, include=True) # f must be simple n, s = splitfactor(fd, DE) if not s.is_one: pass z = z or Dummy('z') H, b = residue_reduce(fa, fd, DE, z=z) if not b: # I will have to verify, but I believe that the answer should be # None in this case. This should never happen for the # functions given when solving the parametric logarithmic # derivative problem when integration elementary functions (see # Bronstein's book, page 255), so most likely this indicates a bug. return None roots = [(i, i.real_roots()) for i, _ in H] if not all(len(j) == i.degree() and all(k.is_Rational for k in j) for i, j in roots): # If f is the logarithmic derivative of a k(t)-radical, then all the # roots of the resultant must be rational numbers. return None # [(a, i), ...], where i*log(a) is a term in the log-part of the integral # of f respolys, residues = list(zip(*roots)) or [[], []] # Note: this might be empty, but everything below should work find in that # case (it should be the same as if it were [[1, 1]]) residueterms = [(H[j][1].subs(z, i), i) for j in range(len(H)) for i in residues[j]] # TODO: finish writing this and write tests p = cancel(fa.as_expr()/fd.as_expr() - residue_reduce_derivation(H, DE, z)) p = p.as_poly(DE.t) if p is None: # f - Dg will be in k[t] if f is the logarithmic derivative of a k(t)-radical return None if p.degree(DE.t) >= max(1, DE.d.degree(DE.t)): return None if case == 'auto': case = DE.case if case == 'exp': wa, wd = derivation(DE.t, DE).cancel(Poly(DE.t, DE.t), include=True) with DecrementLevel(DE): pa, pd = frac_in(p, DE.t, cancel=True) wa, wd = frac_in((wa, wd), DE.t) A = parametric_log_deriv(pa, pd, wa, wd, DE) if A is None: return None n, e, u = A u *= DE.t**e elif case == 'primitive': with DecrementLevel(DE): pa, pd = frac_in(p, DE.t) A = is_log_deriv_k_t_radical_in_field(pa, pd, DE, case='auto') if A is None: return None n, u = A elif case == 'base': # TODO: we can use more efficient residue reduction from ratint() if not fd.is_sqf or fa.degree() >= fd.degree(): # f is the logarithmic derivative in the base case if and only if # f = fa/fd, fd is square-free, deg(fa) < deg(fd), and # gcd(fa, fd) == 1. The last condition is handled by cancel() above. return None # Note: if residueterms = [], returns (1, 1) # f had better be 0 in that case. n = reduce(ilcm, [i.as_numer_denom()[1] for _, i in residueterms], S.One) u = Mul(*[Pow(i, j*n) for i, j in residueterms]) return (n, u) elif case == 'tan': raise NotImplementedError("The hypertangent case is " "not yet implemented for is_log_deriv_k_t_radical_in_field()") elif case in ['other_linear', 'other_nonlinear']: # XXX: If these are supported by the structure theorems, change to NotImplementedError. raise ValueError("The %s case is not supported in this function." % case) else: raise ValueError("case must be one of {'primitive', 'exp', 'tan', " "'base', 'auto'}, not %s" % case) common_denom = reduce(ilcm, [i.as_numer_denom()[1] for i in [j for _, j in residueterms]] + [n], S.One) residueterms = [(i, j*common_denom) for i, j in residueterms] m = common_denom//n if common_denom != n*m: # Verify exact division raise ValueError("Inexact division") u = cancel(u**m*Mul(*[Pow(i, j) for i, j in residueterms])) return (common_denom, u) sympy-sympy-1.9/sympy/integrals/quadrature.py000066400000000000000000000411641412543434000216310ustar00rootroot00000000000000from sympy.core import S, Dummy, pi from sympy.functions.combinatorial.factorials import factorial from sympy.functions.elementary.trigonometric import sin, cos from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.special.gamma_functions import gamma from sympy.polys.orthopolys import (legendre_poly, laguerre_poly, hermite_poly, jacobi_poly) from sympy.polys.rootoftools import RootOf def gauss_legendre(n, n_digits): r""" Computes the Gauss-Legendre quadrature [1]_ points and weights. Explanation =========== The Gauss-Legendre quadrature approximates the integral: .. math:: \int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `P_n` and the weights `w_i` are given by: .. math:: w_i = \frac{2}{\left(1-x_i^2\right) \left(P'_n(x_i)\right)^2} Parameters ========== n : The order of quadrature. n_digits : Number of significant digits of the points and weights to return. Returns ======= (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy.integrals.quadrature import gauss_legendre >>> x, w = gauss_legendre(3, 5) >>> x [-0.7746, 0, 0.7746] >>> w [0.55556, 0.88889, 0.55556] >>> x, w = gauss_legendre(4, 5) >>> x [-0.86114, -0.33998, 0.33998, 0.86114] >>> w [0.34785, 0.65215, 0.65215, 0.34785] See Also ======== gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto References ========== .. [1] https://en.wikipedia.org/wiki/Gaussian_quadrature .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/legendre_rule/legendre_rule.html """ x = Dummy("x") p = legendre_poly(n, x, polys=True) pd = p.diff(x) xi = [] w = [] for r in p.real_roots(): if isinstance(r, RootOf): r = r.eval_rational(S.One/10**(n_digits+2)) xi.append(r.n(n_digits)) w.append((2/((1-r**2) * pd.subs(x, r)**2)).n(n_digits)) return xi, w def gauss_laguerre(n, n_digits): r""" Computes the Gauss-Laguerre quadrature [1]_ points and weights. Explanation =========== The Gauss-Laguerre quadrature approximates the integral: .. math:: \int_0^{\infty} e^{-x} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `L_n` and the weights `w_i` are given by: .. math:: w_i = \frac{x_i}{(n+1)^2 \left(L_{n+1}(x_i)\right)^2} Parameters ========== n : The order of quadrature. n_digits : Number of significant digits of the points and weights to return. Returns ======= (x, w) : The ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy.integrals.quadrature import gauss_laguerre >>> x, w = gauss_laguerre(3, 5) >>> x [0.41577, 2.2943, 6.2899] >>> w [0.71109, 0.27852, 0.010389] >>> x, w = gauss_laguerre(6, 5) >>> x [0.22285, 1.1889, 2.9927, 5.7751, 9.8375, 15.983] >>> w [0.45896, 0.417, 0.11337, 0.010399, 0.00026102, 8.9855e-7] See Also ======== gauss_legendre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto References ========== .. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/laguerre_rule/laguerre_rule.html """ x = Dummy("x") p = laguerre_poly(n, x, polys=True) p1 = laguerre_poly(n+1, x, polys=True) xi = [] w = [] for r in p.real_roots(): if isinstance(r, RootOf): r = r.eval_rational(S.One/10**(n_digits+2)) xi.append(r.n(n_digits)) w.append((r/((n+1)**2 * p1.subs(x, r)**2)).n(n_digits)) return xi, w def gauss_hermite(n, n_digits): r""" Computes the Gauss-Hermite quadrature [1]_ points and weights. Explanation =========== The Gauss-Hermite quadrature approximates the integral: .. math:: \int_{-\infty}^{\infty} e^{-x^2} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `H_n` and the weights `w_i` are given by: .. math:: w_i = \frac{2^{n-1} n! \sqrt{\pi}}{n^2 \left(H_{n-1}(x_i)\right)^2} Parameters ========== n : The order of quadrature. n_digits : Number of significant digits of the points and weights to return. Returns ======= (x, w) : The ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy.integrals.quadrature import gauss_hermite >>> x, w = gauss_hermite(3, 5) >>> x [-1.2247, 0, 1.2247] >>> w [0.29541, 1.1816, 0.29541] >>> x, w = gauss_hermite(6, 5) >>> x [-2.3506, -1.3358, -0.43608, 0.43608, 1.3358, 2.3506] >>> w [0.00453, 0.15707, 0.72463, 0.72463, 0.15707, 0.00453] See Also ======== gauss_legendre, gauss_laguerre, gauss_gen_laguerre, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto References ========== .. [1] https://en.wikipedia.org/wiki/Gauss-Hermite_Quadrature .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/hermite_rule/hermite_rule.html .. [3] http://people.sc.fsu.edu/~jburkardt/cpp_src/gen_hermite_rule/gen_hermite_rule.html """ x = Dummy("x") p = hermite_poly(n, x, polys=True) p1 = hermite_poly(n-1, x, polys=True) xi = [] w = [] for r in p.real_roots(): if isinstance(r, RootOf): r = r.eval_rational(S.One/10**(n_digits+2)) xi.append(r.n(n_digits)) w.append(((2**(n-1) * factorial(n) * sqrt(pi)) / (n**2 * p1.subs(x, r)**2)).n(n_digits)) return xi, w def gauss_gen_laguerre(n, alpha, n_digits): r""" Computes the generalized Gauss-Laguerre quadrature [1]_ points and weights. Explanation =========== The generalized Gauss-Laguerre quadrature approximates the integral: .. math:: \int_{0}^\infty x^{\alpha} e^{-x} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `L^{\alpha}_n` and the weights `w_i` are given by: .. math:: w_i = \frac{\Gamma(\alpha+n)} {n \Gamma(n) L^{\alpha}_{n-1}(x_i) L^{\alpha+1}_{n-1}(x_i)} Parameters ========== n : The order of quadrature. alpha : The exponent of the singularity, `\alpha > -1`. n_digits : Number of significant digits of the points and weights to return. Returns ======= (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy import S >>> from sympy.integrals.quadrature import gauss_gen_laguerre >>> x, w = gauss_gen_laguerre(3, -S.Half, 5) >>> x [0.19016, 1.7845, 5.5253] >>> w [1.4493, 0.31413, 0.00906] >>> x, w = gauss_gen_laguerre(4, 3*S.Half, 5) >>> x [0.97851, 2.9904, 6.3193, 11.712] >>> w [0.53087, 0.67721, 0.11895, 0.0023152] See Also ======== gauss_legendre, gauss_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto References ========== .. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Laguerre_quadrature .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/gen_laguerre_rule/gen_laguerre_rule.html """ x = Dummy("x") p = laguerre_poly(n, x, alpha=alpha, polys=True) p1 = laguerre_poly(n-1, x, alpha=alpha, polys=True) p2 = laguerre_poly(n-1, x, alpha=alpha+1, polys=True) xi = [] w = [] for r in p.real_roots(): if isinstance(r, RootOf): r = r.eval_rational(S.One/10**(n_digits+2)) xi.append(r.n(n_digits)) w.append((gamma(alpha+n) / (n*gamma(n)*p1.subs(x, r)*p2.subs(x, r))).n(n_digits)) return xi, w def gauss_chebyshev_t(n, n_digits): r""" Computes the Gauss-Chebyshev quadrature [1]_ points and weights of the first kind. Explanation =========== The Gauss-Chebyshev quadrature of the first kind approximates the integral: .. math:: \int_{-1}^{1} \frac{1}{\sqrt{1-x^2}} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `T_n` and the weights `w_i` are given by: .. math:: w_i = \frac{\pi}{n} Parameters ========== n : The order of quadrature. n_digits : Number of significant digits of the points and weights to return. Returns ======= (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy.integrals.quadrature import gauss_chebyshev_t >>> x, w = gauss_chebyshev_t(3, 5) >>> x [0.86602, 0, -0.86602] >>> w [1.0472, 1.0472, 1.0472] >>> x, w = gauss_chebyshev_t(6, 5) >>> x [0.96593, 0.70711, 0.25882, -0.25882, -0.70711, -0.96593] >>> w [0.5236, 0.5236, 0.5236, 0.5236, 0.5236, 0.5236] See Also ======== gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto References ========== .. [1] https://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev1_rule/chebyshev1_rule.html """ xi = [] w = [] for i in range(1, n+1): xi.append((cos((2*i-S.One)/(2*n)*S.Pi)).n(n_digits)) w.append((S.Pi/n).n(n_digits)) return xi, w def gauss_chebyshev_u(n, n_digits): r""" Computes the Gauss-Chebyshev quadrature [1]_ points and weights of the second kind. Explanation =========== The Gauss-Chebyshev quadrature of the second kind approximates the integral: .. math:: \int_{-1}^{1} \sqrt{1-x^2} f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `U_n` and the weights `w_i` are given by: .. math:: w_i = \frac{\pi}{n+1} \sin^2 \left(\frac{i}{n+1}\pi\right) Parameters ========== n : the order of quadrature n_digits : number of significant digits of the points and weights to return Returns ======= (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy.integrals.quadrature import gauss_chebyshev_u >>> x, w = gauss_chebyshev_u(3, 5) >>> x [0.70711, 0, -0.70711] >>> w [0.3927, 0.7854, 0.3927] >>> x, w = gauss_chebyshev_u(6, 5) >>> x [0.90097, 0.62349, 0.22252, -0.22252, -0.62349, -0.90097] >>> w [0.084489, 0.27433, 0.42658, 0.42658, 0.27433, 0.084489] See Also ======== gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_t, gauss_jacobi, gauss_lobatto References ========== .. [1] https://en.wikipedia.org/wiki/Chebyshev%E2%80%93Gauss_quadrature .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/chebyshev2_rule/chebyshev2_rule.html """ xi = [] w = [] for i in range(1, n+1): xi.append((cos(i/(n+S.One)*S.Pi)).n(n_digits)) w.append((S.Pi/(n+S.One)*sin(i*S.Pi/(n+S.One))**2).n(n_digits)) return xi, w def gauss_jacobi(n, alpha, beta, n_digits): r""" Computes the Gauss-Jacobi quadrature [1]_ points and weights. Explanation =========== The Gauss-Jacobi quadrature of the first kind approximates the integral: .. math:: \int_{-1}^1 (1-x)^\alpha (1+x)^\beta f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `P^{(\alpha,\beta)}_n` and the weights `w_i` are given by: .. math:: w_i = -\frac{2n+\alpha+\beta+2}{n+\alpha+\beta+1} \frac{\Gamma(n+\alpha+1)\Gamma(n+\beta+1)} {\Gamma(n+\alpha+\beta+1)(n+1)!} \frac{2^{\alpha+\beta}}{P'_n(x_i) P^{(\alpha,\beta)}_{n+1}(x_i)} Parameters ========== n : the order of quadrature alpha : the first parameter of the Jacobi Polynomial, `\alpha > -1` beta : the second parameter of the Jacobi Polynomial, `\beta > -1` n_digits : number of significant digits of the points and weights to return Returns ======= (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy import S >>> from sympy.integrals.quadrature import gauss_jacobi >>> x, w = gauss_jacobi(3, S.Half, -S.Half, 5) >>> x [-0.90097, -0.22252, 0.62349] >>> w [1.7063, 1.0973, 0.33795] >>> x, w = gauss_jacobi(6, 1, 1, 5) >>> x [-0.87174, -0.5917, -0.2093, 0.2093, 0.5917, 0.87174] >>> w [0.050584, 0.22169, 0.39439, 0.39439, 0.22169, 0.050584] See Also ======== gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_t, gauss_chebyshev_u, gauss_lobatto References ========== .. [1] https://en.wikipedia.org/wiki/Gauss%E2%80%93Jacobi_quadrature .. [2] http://people.sc.fsu.edu/~jburkardt/cpp_src/jacobi_rule/jacobi_rule.html .. [3] http://people.sc.fsu.edu/~jburkardt/cpp_src/gegenbauer_rule/gegenbauer_rule.html """ x = Dummy("x") p = jacobi_poly(n, alpha, beta, x, polys=True) pd = p.diff(x) pn = jacobi_poly(n+1, alpha, beta, x, polys=True) xi = [] w = [] for r in p.real_roots(): if isinstance(r, RootOf): r = r.eval_rational(S.One/10**(n_digits+2)) xi.append(r.n(n_digits)) w.append(( - (2*n+alpha+beta+2) / (n+alpha+beta+S.One) * (gamma(n+alpha+1)*gamma(n+beta+1)) / (gamma(n+alpha+beta+S.One)*gamma(n+2)) * 2**(alpha+beta) / (pd.subs(x, r) * pn.subs(x, r))).n(n_digits)) return xi, w def gauss_lobatto(n, n_digits): r""" Computes the Gauss-Lobatto quadrature [1]_ points and weights. Explanation =========== The Gauss-Lobatto quadrature approximates the integral: .. math:: \int_{-1}^1 f(x)\,dx \approx \sum_{i=1}^n w_i f(x_i) The nodes `x_i` of an order `n` quadrature rule are the roots of `P'_(n-1)` and the weights `w_i` are given by: .. math:: &w_i = \frac{2}{n(n-1) \left[P_{n-1}(x_i)\right]^2},\quad x\neq\pm 1\\ &w_i = \frac{2}{n(n-1)},\quad x=\pm 1 Parameters ========== n : the order of quadrature n_digits : number of significant digits of the points and weights to return Returns ======= (x, w) : the ``x`` and ``w`` are lists of points and weights as Floats. The points `x_i` and weights `w_i` are returned as ``(x, w)`` tuple of lists. Examples ======== >>> from sympy.integrals.quadrature import gauss_lobatto >>> x, w = gauss_lobatto(3, 5) >>> x [-1, 0, 1] >>> w [0.33333, 1.3333, 0.33333] >>> x, w = gauss_lobatto(4, 5) >>> x [-1, -0.44721, 0.44721, 1] >>> w [0.16667, 0.83333, 0.83333, 0.16667] See Also ======== gauss_legendre,gauss_laguerre, gauss_gen_laguerre, gauss_hermite, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi References ========== .. [1] https://en.wikipedia.org/wiki/Gaussian_quadrature#Gauss.E2.80.93Lobatto_rules .. [2] http://people.math.sfu.ca/~cbm/aands/page_888.htm """ x = Dummy("x") p = legendre_poly(n-1, x, polys=True) pd = p.diff(x) xi = [] w = [] for r in pd.real_roots(): if isinstance(r, RootOf): r = r.eval_rational(S.One/10**(n_digits+2)) xi.append(r.n(n_digits)) w.append((2/(n*(n-1) * p.subs(x, r)**2)).n(n_digits)) xi.insert(0, -1) xi.append(1) w.insert(0, (S(2)/(n*(n-1))).n(n_digits)) w.append((S(2)/(n*(n-1))).n(n_digits)) return xi, w sympy-sympy-1.9/sympy/integrals/rationaltools.py000066400000000000000000000245311412543434000223450ustar00rootroot00000000000000"""This module implements tools for integrating rational functions. """ from sympy import S, Symbol, symbols, I, log, atan, \ roots, RootSum, Lambda, cancel, Dummy from sympy.polys import Poly, resultant, ZZ def ratint(f, x, **flags): """ Performs indefinite integration of rational functions. Explanation =========== Given a field :math:`K` and a rational function :math:`f = p/q`, where :math:`p` and :math:`q` are polynomials in :math:`K[x]`, returns a function :math:`g` such that :math:`f = g'`. Examples ======== >>> from sympy.integrals.rationaltools import ratint >>> from sympy.abc import x >>> ratint(36/(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2), x) (12*x + 6)/(x**2 - 1) + 4*log(x - 2) - 4*log(x + 1) References ========== .. [1] M. Bronstein, Symbolic Integration I: Transcendental Functions, Second Edition, Springer-Verlag, 2005, pp. 35-70 See Also ======== sympy.integrals.integrals.Integral.doit sympy.integrals.rationaltools.ratint_logpart sympy.integrals.rationaltools.ratint_ratpart """ if type(f) is not tuple: p, q = f.as_numer_denom() else: p, q = f p, q = Poly(p, x, composite=False, field=True), Poly(q, x, composite=False, field=True) coeff, p, q = p.cancel(q) poly, p = p.div(q) result = poly.integrate(x).as_expr() if p.is_zero: return coeff*result g, h = ratint_ratpart(p, q, x) P, Q = h.as_numer_denom() P = Poly(P, x) Q = Poly(Q, x) q, r = P.div(Q) result += g + q.integrate(x).as_expr() if not r.is_zero: symbol = flags.get('symbol', 't') if not isinstance(symbol, Symbol): t = Dummy(symbol) else: t = symbol.as_dummy() L = ratint_logpart(r, Q, x, t) real = flags.get('real') if real is None: if type(f) is not tuple: atoms = f.atoms() else: p, q = f atoms = p.atoms() | q.atoms() for elt in atoms - {x}: if not elt.is_extended_real: real = False break else: real = True eps = S.Zero if not real: for h, q in L: _, h = h.primitive() eps += RootSum( q, Lambda(t, t*log(h.as_expr())), quadratic=True) else: for h, q in L: _, h = h.primitive() R = log_to_real(h, q, x, t) if R is not None: eps += R else: eps += RootSum( q, Lambda(t, t*log(h.as_expr())), quadratic=True) result += eps return coeff*result def ratint_ratpart(f, g, x): """ Horowitz-Ostrogradsky algorithm. Explanation =========== Given a field K and polynomials f and g in K[x], such that f and g are coprime and deg(f) < deg(g), returns fractions A and B in K(x), such that f/g = A' + B and B has square-free denominator. Examples ======== >>> from sympy.integrals.rationaltools import ratint_ratpart >>> from sympy.abc import x, y >>> from sympy import Poly >>> ratint_ratpart(Poly(1, x, domain='ZZ'), ... Poly(x + 1, x, domain='ZZ'), x) (0, 1/(x + 1)) >>> ratint_ratpart(Poly(1, x, domain='EX'), ... Poly(x**2 + y**2, x, domain='EX'), x) (0, 1/(x**2 + y**2)) >>> ratint_ratpart(Poly(36, x, domain='ZZ'), ... Poly(x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2, x, domain='ZZ'), x) ((12*x + 6)/(x**2 - 1), 12/(x**2 - x - 2)) See Also ======== ratint, ratint_logpart """ from sympy import solve f = Poly(f, x) g = Poly(g, x) u, v, _ = g.cofactors(g.diff()) n = u.degree() m = v.degree() A_coeffs = [ Dummy('a' + str(n - i)) for i in range(0, n) ] B_coeffs = [ Dummy('b' + str(m - i)) for i in range(0, m) ] C_coeffs = A_coeffs + B_coeffs A = Poly(A_coeffs, x, domain=ZZ[C_coeffs]) B = Poly(B_coeffs, x, domain=ZZ[C_coeffs]) H = f - A.diff()*v + A*(u.diff()*v).quo(u) - B*u result = solve(H.coeffs(), C_coeffs) A = A.as_expr().subs(result) B = B.as_expr().subs(result) rat_part = cancel(A/u.as_expr(), x) log_part = cancel(B/v.as_expr(), x) return rat_part, log_part def ratint_logpart(f, g, x, t=None): r""" Lazard-Rioboo-Trager algorithm. Explanation =========== Given a field K and polynomials f and g in K[x], such that f and g are coprime, deg(f) < deg(g) and g is square-free, returns a list of tuples (s_i, q_i) of polynomials, for i = 1..n, such that s_i in K[t, x] and q_i in K[t], and:: ___ ___ d f d \ ` \ ` -- - = -- ) ) a log(s_i(a, x)) dx g dx /__, /__, i=1..n a | q_i(a) = 0 Examples ======== >>> from sympy.integrals.rationaltools import ratint_logpart >>> from sympy.abc import x >>> from sympy import Poly >>> ratint_logpart(Poly(1, x, domain='ZZ'), ... Poly(x**2 + x + 1, x, domain='ZZ'), x) [(Poly(x + 3*_t/2 + 1/2, x, domain='QQ[_t]'), ...Poly(3*_t**2 + 1, _t, domain='ZZ'))] >>> ratint_logpart(Poly(12, x, domain='ZZ'), ... Poly(x**2 - x - 2, x, domain='ZZ'), x) [(Poly(x - 3*_t/8 - 1/2, x, domain='QQ[_t]'), ...Poly(-_t**2 + 16, _t, domain='ZZ'))] See Also ======== ratint, ratint_ratpart """ f, g = Poly(f, x), Poly(g, x) t = t or Dummy('t') a, b = g, f - g.diff()*Poly(t, x) res, R = resultant(a, b, includePRS=True) res = Poly(res, t, composite=False) assert res, "BUG: resultant(%s, %s) can't be zero" % (a, b) R_map, H = {}, [] for r in R: R_map[r.degree()] = r def _include_sign(c, sqf): if c.is_extended_real and (c < 0) == True: h, k = sqf[0] c_poly = c.as_poly(h.gens) sqf[0] = h*c_poly, k C, res_sqf = res.sqf_list() _include_sign(C, res_sqf) for q, i in res_sqf: _, q = q.primitive() if g.degree() == i: H.append((g, q)) else: h = R_map[i] h_lc = Poly(h.LC(), t, field=True) c, h_lc_sqf = h_lc.sqf_list(all=True) _include_sign(c, h_lc_sqf) for a, j in h_lc_sqf: h = h.quo(Poly(a.gcd(q)**j, x)) inv, coeffs = h_lc.invert(q), [S.One] for coeff in h.coeffs()[1:]: coeff = coeff.as_poly(inv.gens) T = (inv*coeff).rem(q) coeffs.append(T.as_expr()) h = Poly(dict(list(zip(h.monoms(), coeffs))), x) H.append((h, q)) return H def log_to_atan(f, g): """ Convert complex logarithms to real arctangents. Explanation =========== Given a real field K and polynomials f and g in K[x], with g != 0, returns a sum h of arctangents of polynomials in K[x], such that: dh d f + I g -- = -- I log( ------- ) dx dx f - I g Examples ======== >>> from sympy.integrals.rationaltools import log_to_atan >>> from sympy.abc import x >>> from sympy import Poly, sqrt, S >>> log_to_atan(Poly(x, x, domain='ZZ'), Poly(1, x, domain='ZZ')) 2*atan(x) >>> log_to_atan(Poly(x + S(1)/2, x, domain='QQ'), ... Poly(sqrt(3)/2, x, domain='EX')) 2*atan(2*sqrt(3)*x/3 + sqrt(3)/3) See Also ======== log_to_real """ if f.degree() < g.degree(): f, g = -g, f f = f.to_field() g = g.to_field() p, q = f.div(g) if q.is_zero: return 2*atan(p.as_expr()) else: s, t, h = g.gcdex(-f) u = (f*s + g*t).quo(h) A = 2*atan(u.as_expr()) return A + log_to_atan(s, t) def log_to_real(h, q, x, t): r""" Convert complex logarithms to real functions. Explanation =========== Given real field K and polynomials h in K[t,x] and q in K[t], returns real function f such that: ___ df d \ ` -- = -- ) a log(h(a, x)) dx dx /__, a | q(a) = 0 Examples ======== >>> from sympy.integrals.rationaltools import log_to_real >>> from sympy.abc import x, y >>> from sympy import Poly, S >>> log_to_real(Poly(x + 3*y/2 + S(1)/2, x, domain='QQ[y]'), ... Poly(3*y**2 + 1, y, domain='ZZ'), x, y) 2*sqrt(3)*atan(2*sqrt(3)*x/3 + sqrt(3)/3)/3 >>> log_to_real(Poly(x**2 - 1, x, domain='ZZ'), ... Poly(-2*y + 1, y, domain='ZZ'), x, y) log(x**2 - 1)/2 See Also ======== log_to_atan """ from sympy import collect u, v = symbols('u,v', cls=Dummy) H = h.as_expr().subs({t: u + I*v}).expand() Q = q.as_expr().subs({t: u + I*v}).expand() H_map = collect(H, I, evaluate=False) Q_map = collect(Q, I, evaluate=False) a, b = H_map.get(S.One, S.Zero), H_map.get(I, S.Zero) c, d = Q_map.get(S.One, S.Zero), Q_map.get(I, S.Zero) R = Poly(resultant(c, d, v), u) R_u = roots(R, filter='R') if len(R_u) != R.count_roots(): return None result = S.Zero for r_u in R_u.keys(): C = Poly(c.subs({u: r_u}), v) R_v = roots(C, filter='R') if len(R_v) != C.count_roots(): return None R_v_paired = [] # take one from each pair of conjugate roots for r_v in R_v: if r_v not in R_v_paired and -r_v not in R_v_paired: if r_v.is_negative or r_v.could_extract_minus_sign(): R_v_paired.append(-r_v) elif not r_v.is_zero: R_v_paired.append(r_v) for r_v in R_v_paired: D = d.subs({u: r_u, v: r_v}) if D.evalf(chop=True) != 0: continue A = Poly(a.subs({u: r_u, v: r_v}), x) B = Poly(b.subs({u: r_u, v: r_v}), x) AB = (A**2 + B**2).as_expr() result += r_u*log(AB) + r_v*log_to_atan(A, B) R_q = roots(q, filter='R') if len(R_q) != q.count_roots(): return None for r in R_q.keys(): result += r*log(h.as_expr().subs(t, r)) return result sympy-sympy-1.9/sympy/integrals/rde.py000066400000000000000000000650561412543434000202340ustar00rootroot00000000000000""" Algorithms for solving the Risch differential equation. Given a differential field K of characteristic 0 that is a simple monomial extension of a base field k and f, g in K, the Risch Differential Equation problem is to decide if there exist y in K such that Dy + f*y == g and to find one if there are some. If t is a monomial over k and the coefficients of f and g are in k(t), then y is in k(t), and the outline of the algorithm here is given as: 1. Compute the normal part n of the denominator of y. The problem is then reduced to finding y' in k, where y == y'/n. 2. Compute the special part s of the denominator of y. The problem is then reduced to finding y'' in k[t], where y == y''/(n*s) 3. Bound the degree of y''. 4. Reduce the equation Dy + f*y == g to a similar equation with f, g in k[t]. 5. Find the solutions in k[t] of bounded degree of the reduced equation. See Chapter 6 of "Symbolic Integration I: Transcendental Functions" by Manuel Bronstein. See also the docstring of risch.py. """ from operator import mul from functools import reduce from sympy.core import oo from sympy.core.symbol import Dummy from sympy.polys import Poly, gcd, ZZ, cancel from sympy import sqrt, re, im from sympy.integrals.risch import (gcdex_diophantine, frac_in, derivation, splitfactor, NonElementaryIntegralException, DecrementLevel, recognize_log_derivative) # TODO: Add messages to NonElementaryIntegralException errors def order_at(a, p, t): """ Computes the order of a at p, with respect to t. Explanation =========== For a, p in k[t], the order of a at p is defined as nu_p(a) = max({n in Z+ such that p**n|a}), where a != 0. If a == 0, nu_p(a) = +oo. To compute the order at a rational function, a/b, use the fact that nu_p(a/b) == nu_p(a) - nu_p(b). """ if a.is_zero: return oo if p == Poly(t, t): return a.as_poly(t).ET()[0][0] # Uses binary search for calculating the power. power_list collects the tuples # (p^k,k) where each k is some power of 2. After deciding the largest k # such that k is power of 2 and p^k|a the loop iteratively calculates # the actual power. power_list = [] p1 = p r = a.rem(p1) tracks_power = 1 while r.is_zero: power_list.append((p1,tracks_power)) p1 = p1*p1 tracks_power *= 2 r = a.rem(p1) n = 0 product = Poly(1, t) while len(power_list) != 0: final = power_list.pop() productf = product*final[0] r = a.rem(productf) if r.is_zero: n += final[1] product = productf return n def order_at_oo(a, d, t): """ Computes the order of a/d at oo (infinity), with respect to t. For f in k(t), the order or f at oo is defined as deg(d) - deg(a), where f == a/d. """ if a.is_zero: return oo return d.degree(t) - a.degree(t) def weak_normalizer(a, d, DE, z=None): """ Weak normalization. Explanation =========== Given a derivation D on k[t] and f == a/d in k(t), return q in k[t] such that f - Dq/q is weakly normalized with respect to t. f in k(t) is said to be "weakly normalized" with respect to t if residue_p(f) is not a positive integer for any normal irreducible p in k[t] such that f is in R_p (Definition 6.1.1). If f has an elementary integral, this is equivalent to no logarithm of integral(f) whose argument depends on t has a positive integer coefficient, where the arguments of the logarithms not in k(t) are in k[t]. Returns (q, f - Dq/q) """ z = z or Dummy('z') dn, ds = splitfactor(d, DE) # Compute d1, where dn == d1*d2**2*...*dn**n is a square-free # factorization of d. g = gcd(dn, dn.diff(DE.t)) d_sqf_part = dn.quo(g) d1 = d_sqf_part.quo(gcd(d_sqf_part, g)) a1, b = gcdex_diophantine(d.quo(d1).as_poly(DE.t), d1.as_poly(DE.t), a.as_poly(DE.t)) r = (a - Poly(z, DE.t)*derivation(d1, DE)).as_poly(DE.t).resultant( d1.as_poly(DE.t)) r = Poly(r, z) if not r.expr.has(z): return (Poly(1, DE.t), (a, d)) N = [i for i in r.real_roots() if i in ZZ and i > 0] q = reduce(mul, [gcd(a - Poly(n, DE.t)*derivation(d1, DE), d1) for n in N], Poly(1, DE.t)) dq = derivation(q, DE) sn = q*a - d*dq sd = q*d sn, sd = sn.cancel(sd, include=True) return (q, (sn, sd)) def normal_denom(fa, fd, ga, gd, DE): """ Normal part of the denominator. Explanation =========== Given a derivation D on k[t] and f, g in k(t) with f weakly normalized with respect to t, either raise NonElementaryIntegralException, in which case the equation Dy + f*y == g has no solution in k(t), or the quadruplet (a, b, c, h) such that a, h in k[t], b, c in k, and for any solution y in k(t) of Dy + f*y == g, q = y*h in k satisfies a*Dq + b*q == c. This constitutes step 1 in the outline given in the rde.py docstring. """ dn, ds = splitfactor(fd, DE) en, es = splitfactor(gd, DE) p = dn.gcd(en) h = en.gcd(en.diff(DE.t)).quo(p.gcd(p.diff(DE.t))) a = dn*h c = a*h if c.div(en)[1]: # en does not divide dn*h**2 raise NonElementaryIntegralException ca = c*ga ca, cd = ca.cancel(gd, include=True) ba = a*fa - dn*derivation(h, DE)*fd ba, bd = ba.cancel(fd, include=True) # (dn*h, dn*h*f - dn*Dh, dn*h**2*g, h) return (a, (ba, bd), (ca, cd), h) def special_denom(a, ba, bd, ca, cd, DE, case='auto'): """ Special part of the denominator. Explanation =========== case is one of {'exp', 'tan', 'primitive'} for the hyperexponential, hypertangent, and primitive cases, respectively. For the hyperexponential (resp. hypertangent) case, given a derivation D on k[t] and a in k[t], b, c, in k with Dt/t in k (resp. Dt/(t**2 + 1) in k, sqrt(-1) not in k), a != 0, and gcd(a, t) == 1 (resp. gcd(a, t**2 + 1) == 1), return the quadruplet (A, B, C, 1/h) such that A, B, C, h in k[t] and for any solution q in k of a*Dq + b*q == c, r = qh in k[t] satisfies A*Dr + B*r == C. For ``case == 'primitive'``, k == k[t], so it returns (a, b, c, 1) in this case. This constitutes step 2 of the outline given in the rde.py docstring. """ from sympy.integrals.prde import parametric_log_deriv # TODO: finish writing this and write tests if case == 'auto': case = DE.case if case == 'exp': p = Poly(DE.t, DE.t) elif case == 'tan': p = Poly(DE.t**2 + 1, DE.t) elif case in ['primitive', 'base']: B = ba.to_field().quo(bd) C = ca.to_field().quo(cd) return (a, B, C, Poly(1, DE.t)) else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'base'}, not %s." % case) nb = order_at(ba, p, DE.t) - order_at(bd, p, DE.t) nc = order_at(ca, p, DE.t) - order_at(cd, p, DE.t) n = min(0, nc - min(0, nb)) if not nb: # Possible cancellation. if case == 'exp': dcoeff = DE.d.quo(Poly(DE.t, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in(-ba.eval(0)/bd.eval(0)/a.eval(0), DE.t) etaa, etad = frac_in(dcoeff, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: Q, m, z = A if Q == 1: n = min(n, m) elif case == 'tan': dcoeff = DE.d.quo(Poly(DE.t**2+1, DE.t)) with DecrementLevel(DE): # We are guaranteed to not have problems, # because case != 'base'. alphaa, alphad = frac_in(im(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t) betaa, betad = frac_in(re(-ba.eval(sqrt(-1))/bd.eval(sqrt(-1))/a.eval(sqrt(-1))), DE.t) etaa, etad = frac_in(dcoeff, DE.t) if recognize_log_derivative(Poly(2, DE.t)*betaa, betad, DE): A = parametric_log_deriv(alphaa*Poly(sqrt(-1), DE.t)*betad+alphad*betaa, alphad*betad, etaa, etad, DE) if A is not None: Q, m, z = A if Q == 1: n = min(n, m) N = max(0, -nb, n - nc) pN = p**N pn = p**-n A = a*pN B = ba*pN.quo(bd) + Poly(n, DE.t)*a*derivation(p, DE).quo(p)*pN C = (ca*pN*pn).quo(cd) h = pn # (a*p**N, (b + n*a*Dp/p)*p**N, c*p**(N - n), p**-n) return (A, B, C, h) def bound_degree(a, b, cQ, DE, case='auto', parametric=False): """ Bound on polynomial solutions. Explanation =========== Given a derivation D on k[t] and ``a``, ``b``, ``c`` in k[t] with ``a != 0``, return n in ZZ such that deg(q) <= n for any solution q in k[t] of a*Dq + b*q == c, when parametric=False, or deg(q) <= n for any solution c1, ..., cm in Const(k) and q in k[t] of a*Dq + b*q == Sum(ci*gi, (i, 1, m)) when parametric=True. For ``parametric=False``, ``cQ`` is ``c``, a ``Poly``; for ``parametric=True``, ``cQ`` is Q == [q1, ..., qm], a list of Polys. This constitutes step 3 of the outline given in the rde.py docstring. """ from sympy.integrals.prde import (parametric_log_deriv, limited_integrate, is_log_deriv_k_t_radical_in_field) # TODO: finish writing this and write tests if case == 'auto': case = DE.case da = a.degree(DE.t) db = b.degree(DE.t) # The parametric and regular cases are identical, except for this part if parametric: dc = max([i.degree(DE.t) for i in cQ]) else: dc = cQ.degree(DE.t) alpha = cancel(-b.as_poly(DE.t).LC().as_expr()/ a.as_poly(DE.t).LC().as_expr()) if case == 'base': n = max(0, dc - max(db, da - 1)) if db == da - 1 and alpha.is_Integer: n = max(0, alpha, dc - db) elif case == 'primitive': if db > da: n = max(0, dc - db) else: n = max(0, dc - da + 1) etaa, etad = frac_in(DE.d, DE.T[DE.level - 1]) t1 = DE.t with DecrementLevel(DE): alphaa, alphad = frac_in(alpha, DE.t) if db == da - 1: # if alpha == m*Dt + Dz for z in k and m in ZZ: try: (za, zd), m = limited_integrate(alphaa, alphad, [(etaa, etad)], DE) except NonElementaryIntegralException: pass else: if len(m) != 1: raise ValueError("Length of m should be 1") n = max(n, m[0]) elif db == da: # if alpha == Dz/z for z in k*: # beta = -lc(a*Dz + b*z)/(z*lc(a)) # if beta == m*Dt + Dw for w in k and m in ZZ: # n = max(n, m) A = is_log_deriv_k_t_radical_in_field(alphaa, alphad, DE) if A is not None: aa, z = A if aa == 1: beta = -(a*derivation(z, DE).as_poly(t1) + b*z.as_poly(t1)).LC()/(z.as_expr()*a.LC()) betaa, betad = frac_in(beta, DE.t) try: (za, zd), m = limited_integrate(betaa, betad, [(etaa, etad)], DE) except NonElementaryIntegralException: pass else: if len(m) != 1: raise ValueError("Length of m should be 1") n = max(n, m[0].as_expr()) elif case == 'exp': n = max(0, dc - max(db, da)) if da == db: etaa, etad = frac_in(DE.d.quo(Poly(DE.t, DE.t)), DE.T[DE.level - 1]) with DecrementLevel(DE): alphaa, alphad = frac_in(alpha, DE.t) A = parametric_log_deriv(alphaa, alphad, etaa, etad, DE) if A is not None: # if alpha == m*Dt/t + Dz/z for z in k* and m in ZZ: # n = max(n, m) a, m, z = A if a == 1: n = max(n, m) elif case in ['tan', 'other_nonlinear']: delta = DE.d.degree(DE.t) lam = DE.d.LC() alpha = cancel(alpha/lam) n = max(0, dc - max(da + delta - 1, db)) if db == da + delta - 1 and alpha.is_Integer: n = max(0, alpha, dc - db) else: raise ValueError("case must be one of {'exp', 'tan', 'primitive', " "'other_nonlinear', 'base'}, not %s." % case) return n def spde(a, b, c, n, DE): """ Rothstein's Special Polynomial Differential Equation algorithm. Explanation =========== Given a derivation D on k[t], an integer n and ``a``,``b``,``c`` in k[t] with ``a != 0``, either raise NonElementaryIntegralException, in which case the equation a*Dq + b*q == c has no solution of degree at most ``n`` in k[t], or return the tuple (B, C, m, alpha, beta) such that B, C, alpha, beta in k[t], m in ZZ, and any solution q in k[t] of degree at most n of a*Dq + b*q == c must be of the form q == alpha*h + beta, where h in k[t], deg(h) <= m, and Dh + B*h == C. This constitutes step 4 of the outline given in the rde.py docstring. """ zero = Poly(0, DE.t) alpha = Poly(1, DE.t) beta = Poly(0, DE.t) while True: if c.is_zero: return (zero, zero, 0, zero, beta) # -1 is more to the point if (n < 0) is True: raise NonElementaryIntegralException g = a.gcd(b) if not c.rem(g).is_zero: # g does not divide c raise NonElementaryIntegralException a, b, c = a.quo(g), b.quo(g), c.quo(g) if a.degree(DE.t) == 0: b = b.to_field().quo(a) c = c.to_field().quo(a) return (b, c, n, alpha, beta) r, z = gcdex_diophantine(b, a, c) b += derivation(a, DE) c = z - derivation(r, DE) n -= a.degree(DE.t) beta += alpha * r alpha *= a def no_cancel_b_large(b, c, n, DE): """ Poly Risch Differential Equation - No cancellation: deg(b) large enough. Explanation =========== Given a derivation D on k[t], ``n`` either an integer or +oo, and ``b``,``c`` in k[t] with ``b != 0`` and either D == d/dt or deg(b) > max(0, deg(D) - 1), either raise NonElementaryIntegralException, in which case the equation ``Dq + b*q == c`` has no solution of degree at most n in k[t], or a solution q in k[t] of this equation with ``deg(q) < n``. """ q = Poly(0, DE.t) while not c.is_zero: m = c.degree(DE.t) - b.degree(DE.t) if not 0 <= m <= n: # n < 0 or m < 0 or m > n raise NonElementaryIntegralException p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC()*DE.t**m, DE.t, expand=False) q = q + p n = m - 1 c = c - derivation(p, DE) - b*p return q def no_cancel_b_small(b, c, n, DE): """ Poly Risch Differential Equation - No cancellation: deg(b) small enough. Explanation =========== Given a derivation D on k[t], ``n`` either an integer or +oo, and ``b``,``c`` in k[t] with deg(b) < deg(D) - 1 and either D == d/dt or deg(D) >= 2, either raise NonElementaryIntegralException, in which case the equation Dq + b*q == c has no solution of degree at most n in k[t], or a solution q in k[t] of this equation with deg(q) <= n, or the tuple (h, b0, c0) such that h in k[t], b0, c0, in k, and for any solution q in k[t] of degree at most n of Dq + bq == c, y == q - h is a solution in k of Dy + b0*y == c0. """ q = Poly(0, DE.t) while not c.is_zero: if n == 0: m = 0 else: m = c.degree(DE.t) - DE.d.degree(DE.t) + 1 if not 0 <= m <= n: # n < 0 or m < 0 or m > n raise NonElementaryIntegralException if m > 0: p = Poly(c.as_poly(DE.t).LC()/(m*DE.d.as_poly(DE.t).LC())*DE.t**m, DE.t, expand=False) else: if b.degree(DE.t) != c.degree(DE.t): raise NonElementaryIntegralException if b.degree(DE.t) == 0: return (q, b.as_poly(DE.T[DE.level - 1]), c.as_poly(DE.T[DE.level - 1])) p = Poly(c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC(), DE.t, expand=False) q = q + p n = m - 1 c = c - derivation(p, DE) - b*p return q # TODO: better name for this function def no_cancel_equal(b, c, n, DE): """ Poly Risch Differential Equation - No cancellation: deg(b) == deg(D) - 1 Explanation =========== Given a derivation D on k[t] with deg(D) >= 2, n either an integer or +oo, and b, c in k[t] with deg(b) == deg(D) - 1, either raise NonElementaryIntegralException, in which case the equation Dq + b*q == c has no solution of degree at most n in k[t], or a solution q in k[t] of this equation with deg(q) <= n, or the tuple (h, m, C) such that h in k[t], m in ZZ, and C in k[t], and for any solution q in k[t] of degree at most n of Dq + b*q == c, y == q - h is a solution in k[t] of degree at most m of Dy + b*y == C. """ q = Poly(0, DE.t) lc = cancel(-b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC()) if lc.is_Integer and lc.is_positive: M = lc else: M = -1 while not c.is_zero: m = max(M, c.degree(DE.t) - DE.d.degree(DE.t) + 1) if not 0 <= m <= n: # n < 0 or m < 0 or m > n raise NonElementaryIntegralException u = cancel(m*DE.d.as_poly(DE.t).LC() + b.as_poly(DE.t).LC()) if u.is_zero: return (q, m, c) if m > 0: p = Poly(c.as_poly(DE.t).LC()/u*DE.t**m, DE.t, expand=False) else: if c.degree(DE.t) != DE.d.degree(DE.t) - 1: raise NonElementaryIntegralException else: p = c.as_poly(DE.t).LC()/b.as_poly(DE.t).LC() q = q + p n = m - 1 c = c - derivation(p, DE) - b*p return q def cancel_primitive(b, c, n, DE): """ Poly Risch Differential Equation - Cancellation: Primitive case. Explanation =========== Given a derivation D on k[t], n either an integer or +oo, ``b`` in k, and ``c`` in k[t] with Dt in k and ``b != 0``, either raise NonElementaryIntegralException, in which case the equation Dq + b*q == c has no solution of degree at most n in k[t], or a solution q in k[t] of this equation with deg(q) <= n. """ from sympy.integrals.prde import is_log_deriv_k_t_radical_in_field with DecrementLevel(DE): ba, bd = frac_in(b, DE.t) A = is_log_deriv_k_t_radical_in_field(ba, bd, DE) if A is not None: n, z = A if n == 1: # b == Dz/z raise NotImplementedError("is_deriv_in_field() is required to " " solve this problem.") # if z*c == Dp for p in k[t] and deg(p) <= n: # return p/z # else: # raise NonElementaryIntegralException if c.is_zero: return c # return 0 if n < c.degree(DE.t): raise NonElementaryIntegralException q = Poly(0, DE.t) while not c.is_zero: m = c.degree(DE.t) if n < m: raise NonElementaryIntegralException with DecrementLevel(DE): a2a, a2d = frac_in(c.LC(), DE.t) sa, sd = rischDE(ba, bd, a2a, a2d, DE) stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) q += stm n = m - 1 c -= b*stm + derivation(stm, DE) return q def cancel_exp(b, c, n, DE): """ Poly Risch Differential Equation - Cancellation: Hyperexponential case. Explanation =========== Given a derivation D on k[t], n either an integer or +oo, ``b`` in k, and ``c`` in k[t] with Dt/t in k and ``b != 0``, either raise NonElementaryIntegralException, in which case the equation Dq + b*q == c has no solution of degree at most n in k[t], or a solution q in k[t] of this equation with deg(q) <= n. """ from sympy.integrals.prde import parametric_log_deriv eta = DE.d.quo(Poly(DE.t, DE.t)).as_expr() with DecrementLevel(DE): etaa, etad = frac_in(eta, DE.t) ba, bd = frac_in(b, DE.t) A = parametric_log_deriv(ba, bd, etaa, etad, DE) if A is not None: a, m, z = A if a == 1: raise NotImplementedError("is_deriv_in_field() is required to " "solve this problem.") # if c*z*t**m == Dp for p in k and q = p/(z*t**m) in k[t] and # deg(q) <= n: # return q # else: # raise NonElementaryIntegralException if c.is_zero: return c # return 0 if n < c.degree(DE.t): raise NonElementaryIntegralException q = Poly(0, DE.t) while not c.is_zero: m = c.degree(DE.t) if n < m: raise NonElementaryIntegralException # a1 = b + m*Dt/t a1 = b.as_expr() with DecrementLevel(DE): # TODO: Write a dummy function that does this idiom a1a, a1d = frac_in(a1, DE.t) a1a = a1a*etad + etaa*a1d*Poly(m, DE.t) a1d = a1d*etad a2a, a2d = frac_in(c.LC(), DE.t) sa, sd = rischDE(a1a, a1d, a2a, a2d, DE) stm = Poly(sa.as_expr()/sd.as_expr()*DE.t**m, DE.t, expand=False) q += stm n = m - 1 c -= b*stm + derivation(stm, DE) # deg(c) becomes smaller return q def solve_poly_rde(b, cQ, n, DE, parametric=False): """ Solve a Polynomial Risch Differential Equation with degree bound ``n``. This constitutes step 4 of the outline given in the rde.py docstring. For parametric=False, cQ is c, a Poly; for parametric=True, cQ is Q == [q1, ..., qm], a list of Polys. """ from sympy.integrals.prde import (prde_no_cancel_b_large, prde_no_cancel_b_small) # No cancellation if not b.is_zero and (DE.case == 'base' or b.degree(DE.t) > max(0, DE.d.degree(DE.t) - 1)): if parametric: return prde_no_cancel_b_large(b, cQ, n, DE) return no_cancel_b_large(b, cQ, n, DE) elif (b.is_zero or b.degree(DE.t) < DE.d.degree(DE.t) - 1) and \ (DE.case == 'base' or DE.d.degree(DE.t) >= 2): if parametric: return prde_no_cancel_b_small(b, cQ, n, DE) R = no_cancel_b_small(b, cQ, n, DE) if isinstance(R, Poly): return R else: # XXX: Might k be a field? (pg. 209) h, b0, c0 = R with DecrementLevel(DE): b0, c0 = b0.as_poly(DE.t), c0.as_poly(DE.t) if b0 is None: # See above comment raise ValueError("b0 should be a non-Null value") if c0 is None: raise ValueError("c0 should be a non-Null value") y = solve_poly_rde(b0, c0, n, DE).as_poly(DE.t) return h + y elif DE.d.degree(DE.t) >= 2 and b.degree(DE.t) == DE.d.degree(DE.t) - 1 and \ n > -b.as_poly(DE.t).LC()/DE.d.as_poly(DE.t).LC(): # TODO: Is this check necessary, and if so, what should it do if it fails? # b comes from the first element returned from spde() if not b.as_poly(DE.t).LC().is_number: raise TypeError("Result should be a number") if parametric: raise NotImplementedError("prde_no_cancel_b_equal() is not yet " "implemented.") R = no_cancel_equal(b, cQ, n, DE) if isinstance(R, Poly): return R else: h, m, C = R # XXX: Or should it be rischDE()? y = solve_poly_rde(b, C, m, DE) return h + y else: # Cancellation if b.is_zero: raise NotImplementedError("Remaining cases for Poly (P)RDE are " "not yet implemented (is_deriv_in_field() required).") else: if DE.case == 'exp': if parametric: raise NotImplementedError("Parametric RDE cancellation " "hyperexponential case is not yet implemented.") return cancel_exp(b, cQ, n, DE) elif DE.case == 'primitive': if parametric: raise NotImplementedError("Parametric RDE cancellation " "primitive case is not yet implemented.") return cancel_primitive(b, cQ, n, DE) else: raise NotImplementedError("Other Poly (P)RDE cancellation " "cases are not yet implemented (%s)." % DE.case) if parametric: raise NotImplementedError("Remaining cases for Poly PRDE not yet " "implemented.") raise NotImplementedError("Remaining cases for Poly RDE not yet " "implemented.") def rischDE(fa, fd, ga, gd, DE): """ Solve a Risch Differential Equation: Dy + f*y == g. Explanation =========== See the outline in the docstring of rde.py for more information about the procedure used. Either raise NonElementaryIntegralException, in which case there is no solution y in the given differential field, or return y in k(t) satisfying Dy + f*y == g, or raise NotImplementedError, in which case, the algorithms necessary to solve the given Risch Differential Equation have not yet been implemented. """ _, (fa, fd) = weak_normalizer(fa, fd, DE) a, (ba, bd), (ca, cd), hn = normal_denom(fa, fd, ga, gd, DE) A, B, C, hs = special_denom(a, ba, bd, ca, cd, DE) try: # Until this is fully implemented, use oo. Note that this will almost # certainly cause non-termination in spde() (unless A == 1), and # *might* lead to non-termination in the next step for a nonelementary # integral (I don't know for certain yet). Fortunately, spde() is # currently written recursively, so this will just give # RuntimeError: maximum recursion depth exceeded. n = bound_degree(A, B, C, DE) except NotImplementedError: # Useful for debugging: # import warnings # warnings.warn("rischDE: Proceeding with n = oo; may cause " # "non-termination.") n = oo B, C, m, alpha, beta = spde(A, B, C, n, DE) if C.is_zero: y = C else: y = solve_poly_rde(B, C, m, DE) return (alpha*y + beta, hn*hs) sympy-sympy-1.9/sympy/integrals/risch.py000066400000000000000000002037071412543434000205670ustar00rootroot00000000000000""" The Risch Algorithm for transcendental function integration. The core algorithms for the Risch algorithm are here. The subproblem algorithms are in the rde.py and prde.py files for the Risch Differential Equation solver and the parametric problems solvers, respectively. All important information concerning the differential extension for an integrand is stored in a DifferentialExtension object, which in the code is usually called DE. Throughout the code and Inside the DifferentialExtension object, the conventions/attribute names are that the base domain is QQ and each differential extension is x, t0, t1, ..., tn-1 = DE.t. DE.x is the variable of integration (Dx == 1), DE.D is a list of the derivatives of x, t1, t2, ..., tn-1 = t, DE.T is the list [x, t1, t2, ..., tn-1], DE.t is the outer-most variable of the differential extension at the given level (the level can be adjusted using DE.increment_level() and DE.decrement_level()), k is the field C(x, t0, ..., tn-2), where C is the constant field. The numerator of a fraction is denoted by a and the denominator by d. If the fraction is named f, fa == numer(f) and fd == denom(f). Fractions are returned as tuples (fa, fd). DE.d and DE.t are used to represent the topmost derivation and extension variable, respectively. The docstring of a function signifies whether an argument is in k[t], in which case it will just return a Poly in t, or in k(t), in which case it will return the fraction (fa, fd). Other variable names probably come from the names used in Bronstein's book. """ from sympy import real_roots, default_sort_key from sympy.abc import z from sympy.core.function import Lambda from sympy.core.numbers import ilcm, oo, I from sympy.core.mul import Mul from sympy.core.power import Pow from sympy.core.relational import Ne from sympy.core.singleton import S from sympy.core.symbol import Symbol, Dummy from sympy.core.compatibility import ordered from sympy.integrals.heurisch import _symbols from sympy.functions import (acos, acot, asin, atan, cos, cot, exp, log, Piecewise, sin, tan) from sympy.functions import sinh, cosh, tanh, coth from sympy.integrals import Integral, integrate from sympy.polys import gcd, cancel, PolynomialError, Poly, reduced, RootSum, DomainError from sympy.utilities.iterables import numbered_symbols from types import GeneratorType from functools import reduce def integer_powers(exprs): """ Rewrites a list of expressions as integer multiples of each other. Explanation =========== For example, if you have [x, x/2, x**2 + 1, 2*x/3], then you can rewrite this as [(x/6) * 6, (x/6) * 3, (x**2 + 1) * 1, (x/6) * 4]. This is useful in the Risch integration algorithm, where we must write exp(x) + exp(x/2) as (exp(x/2))**2 + exp(x/2), but not as exp(x) + sqrt(exp(x)) (this is because only the transcendental case is implemented and we therefore cannot integrate algebraic extensions). The integer multiples returned by this function for each term are the smallest possible (their content equals 1). Returns a list of tuples where the first element is the base term and the second element is a list of `(item, factor)` terms, where `factor` is the integer multiplicative factor that must multiply the base term to obtain the original item. The easiest way to understand this is to look at an example: >>> from sympy.abc import x >>> from sympy.integrals.risch import integer_powers >>> integer_powers([x, x/2, x**2 + 1, 2*x/3]) [(x/6, [(x, 6), (x/2, 3), (2*x/3, 4)]), (x**2 + 1, [(x**2 + 1, 1)])] We can see how this relates to the example at the beginning of the docstring. It chose x/6 as the first base term. Then, x can be written as (x/2) * 2, so we get (0, 2), and so on. Now only element (x**2 + 1) remains, and there are no other terms that can be written as a rational multiple of that, so we get that it can be written as (x**2 + 1) * 1. """ # Here is the strategy: # First, go through each term and determine if it can be rewritten as a # rational multiple of any of the terms gathered so far. # cancel(a/b).is_Rational is sufficient for this. If it is a multiple, we # add its multiple to the dictionary. terms = {} for term in exprs: for j in terms: a = cancel(term/j) if a.is_Rational: terms[j].append((term, a)) break else: terms[term] = [(term, S.One)] # After we have done this, we have all the like terms together, so we just # need to find a common denominator so that we can get the base term and # integer multiples such that each term can be written as an integer # multiple of the base term, and the content of the integers is 1. newterms = {} for term in terms: common_denom = reduce(ilcm, [i.as_numer_denom()[1] for _, i in terms[term]]) newterm = term/common_denom newmults = [(i, j*common_denom) for i, j in terms[term]] newterms[newterm] = newmults return sorted(iter(newterms.items()), key=lambda item: item[0].sort_key()) class DifferentialExtension: """ A container for all the information relating to a differential extension. Explanation =========== The attributes of this object are (see also the docstring of __init__): - f: The original (Expr) integrand. - x: The variable of integration. - T: List of variables in the extension. - D: List of derivations in the extension; corresponds to the elements of T. - fa: Poly of the numerator of the integrand. - fd: Poly of the denominator of the integrand. - Tfuncs: Lambda() representations of each element of T (except for x). For back-substitution after integration. - backsubs: A (possibly empty) list of further substitutions to be made on the final integral to make it look more like the integrand. - exts: - extargs: - cases: List of string representations of the cases of T. - t: The top level extension variable, as defined by the current level (see level below). - d: The top level extension derivation, as defined by the current derivation (see level below). - case: The string representation of the case of self.d. (Note that self.T and self.D will always contain the complete extension, regardless of the level. Therefore, you should ALWAYS use DE.t and DE.d instead of DE.T[-1] and DE.D[-1]. If you want to have a list of the derivations or variables only up to the current level, use DE.D[:len(DE.D) + DE.level + 1] and DE.T[:len(DE.T) + DE.level + 1]. Note that, in particular, the derivation() function does this.) The following are also attributes, but will probably not be useful other than in internal use: - newf: Expr form of fa/fd. - level: The number (between -1 and -len(self.T)) such that self.T[self.level] == self.t and self.D[self.level] == self.d. Use the methods self.increment_level() and self.decrement_level() to change the current level. """ # __slots__ is defined mainly so we can iterate over all the attributes # of the class easily (the memory use doesn't matter too much, since we # only create one DifferentialExtension per integration). Also, it's nice # to have a safeguard when debugging. __slots__ = ('f', 'x', 'T', 'D', 'fa', 'fd', 'Tfuncs', 'backsubs', 'exts', 'extargs', 'cases', 'case', 't', 'd', 'newf', 'level', 'ts', 'dummy') def __init__(self, f=None, x=None, handle_first='log', dummy=False, extension=None, rewrite_complex=None): """ Tries to build a transcendental extension tower from ``f`` with respect to ``x``. Explanation =========== If it is successful, creates a DifferentialExtension object with, among others, the attributes fa, fd, D, T, Tfuncs, and backsubs such that fa and fd are Polys in T[-1] with rational coefficients in T[:-1], fa/fd == f, and D[i] is a Poly in T[i] with rational coefficients in T[:i] representing the derivative of T[i] for each i from 1 to len(T). Tfuncs is a list of Lambda objects for back replacing the functions after integrating. Lambda() is only used (instead of lambda) to make them easier to test and debug. Note that Tfuncs corresponds to the elements of T, except for T[0] == x, but they should be back-substituted in reverse order. backsubs is a (possibly empty) back-substitution list that should be applied on the completed integral to make it look more like the original integrand. If it is unsuccessful, it raises NotImplementedError. You can also create an object by manually setting the attributes as a dictionary to the extension keyword argument. You must include at least D. Warning, any attribute that is not given will be set to None. The attributes T, t, d, cases, case, x, and level are set automatically and do not need to be given. The functions in the Risch Algorithm will NOT check to see if an attribute is None before using it. This also does not check to see if the extension is valid (non-algebraic) or even if it is self-consistent. Therefore, this should only be used for testing/debugging purposes. """ # XXX: If you need to debug this function, set the break point here if extension: if 'D' not in extension: raise ValueError("At least the key D must be included with " "the extension flag to DifferentialExtension.") for attr in extension: setattr(self, attr, extension[attr]) self._auto_attrs() return elif f is None or x is None: raise ValueError("Either both f and x or a manual extension must " "be given.") if handle_first not in ['log', 'exp']: raise ValueError("handle_first must be 'log' or 'exp', not %s." % str(handle_first)) # f will be the original function, self.f might change if we reset # (e.g., we pull out a constant from an exponential) self.f = f self.x = x # setting the default value 'dummy' self.dummy = dummy self.reset() exp_new_extension, log_new_extension = True, True # case of 'automatic' choosing if rewrite_complex is None: rewrite_complex = I in self.f.atoms() if rewrite_complex: rewritables = { (sin, cos, cot, tan, sinh, cosh, coth, tanh): exp, (asin, acos, acot, atan): log, } # rewrite the trigonometric components for candidates, rule in rewritables.items(): self.newf = self.newf.rewrite(candidates, rule) self.newf = cancel(self.newf) else: if any(i.has(x) for i in self.f.atoms(sin, cos, tan, atan, asin, acos)): raise NotImplementedError("Trigonometric extensions are not " "supported (yet!)") exps = set() pows = set() numpows = set() sympows = set() logs = set() symlogs = set() while True: if self.newf.is_rational_function(*self.T): break if not exp_new_extension and not log_new_extension: # We couldn't find a new extension on the last pass, so I guess # we can't do it. raise NotImplementedError("Couldn't find an elementary " "transcendental extension for %s. Try using a " % str(f) + "manual extension with the extension flag.") exps, pows, numpows, sympows, log_new_extension = \ self._rewrite_exps_pows(exps, pows, numpows, sympows, log_new_extension) logs, symlogs = self._rewrite_logs(logs, symlogs) if handle_first == 'exp' or not log_new_extension: exp_new_extension = self._exp_part(exps) if exp_new_extension is None: # reset and restart self.f = self.newf self.reset() exp_new_extension = True continue if handle_first == 'log' or not exp_new_extension: log_new_extension = self._log_part(logs) self.fa, self.fd = frac_in(self.newf, self.t) self._auto_attrs() return def __getattr__(self, attr): # Avoid AttributeErrors when debugging if attr not in self.__slots__: raise AttributeError("%s has no attribute %s" % (repr(self), repr(attr))) return None def _rewrite_exps_pows(self, exps, pows, numpows, sympows, log_new_extension): """ Rewrite exps/pows for better processing. """ # Pre-preparsing. ################# # Get all exp arguments, so we can avoid ahead of time doing # something like t1 = exp(x), t2 = exp(x/2) == sqrt(t1). # Things like sqrt(exp(x)) do not automatically simplify to # exp(x/2), so they will be viewed as algebraic. The easiest way # to handle this is to convert all instances of (a**b)**Rational # to a**(Rational*b) before doing anything else. Note that the # _exp_part code can generate terms of this form, so we do need to # do this at each pass (or else modify it to not do that). from sympy.integrals.prde import is_deriv_k ratpows = [i for i in self.newf.atoms(Pow).union(self.newf.atoms(exp)) if (i.base.is_Pow or isinstance(i.base, exp) and i.exp.is_Rational)] ratpows_repl = [ (i, i.base.base**(i.exp*i.base.exp)) for i in ratpows] self.backsubs += [(j, i) for i, j in ratpows_repl] self.newf = self.newf.xreplace(dict(ratpows_repl)) # To make the process deterministic, the args are sorted # so that functions with smaller op-counts are processed first. # Ties are broken with the default_sort_key. # XXX Although the method is deterministic no additional work # has been done to guarantee that the simplest solution is # returned and that it would be affected be using different # variables. Though it is possible that this is the case # one should know that it has not been done intentionally, so # further improvements may be possible. # TODO: This probably doesn't need to be completely recomputed at # each pass. exps = update_sets(exps, self.newf.atoms(exp), lambda i: i.exp.is_rational_function(*self.T) and i.exp.has(*self.T)) pows = update_sets(pows, self.newf.atoms(Pow), lambda i: i.exp.is_rational_function(*self.T) and i.exp.has(*self.T)) numpows = update_sets(numpows, set(pows), lambda i: not i.base.has(*self.T)) sympows = update_sets(sympows, set(pows) - set(numpows), lambda i: i.base.is_rational_function(*self.T) and not i.exp.is_Integer) # The easiest way to deal with non-base E powers is to convert them # into base E, integrate, and then convert back. for i in ordered(pows): old = i new = exp(i.exp*log(i.base)) # If exp is ever changed to automatically reduce exp(x*log(2)) # to 2**x, then this will break. The solution is to not change # exp to do that :) if i in sympows: if i.exp.is_Rational: raise NotImplementedError("Algebraic extensions are " "not supported (%s)." % str(i)) # We can add a**b only if log(a) in the extension, because # a**b == exp(b*log(a)). basea, based = frac_in(i.base, self.t) A = is_deriv_k(basea, based, self) if A is None: # Nonelementary monomial (so far) # TODO: Would there ever be any benefit from just # adding log(base) as a new monomial? # ANSWER: Yes, otherwise we can't integrate x**x (or # rather prove that it has no elementary integral) # without first manually rewriting it as exp(x*log(x)) self.newf = self.newf.xreplace({old: new}) self.backsubs += [(new, old)] log_new_extension = self._log_part([log(i.base)]) exps = update_sets(exps, self.newf.atoms(exp), lambda i: i.exp.is_rational_function(*self.T) and i.exp.has(*self.T)) continue ans, u, const = A newterm = exp(i.exp*(log(const) + u)) # Under the current implementation, exp kills terms # only if they are of the form a*log(x), where a is a # Number. This case should have already been killed by the # above tests. Again, if this changes to kill more than # that, this will break, which maybe is a sign that you # shouldn't be changing that. Actually, if anything, this # auto-simplification should be removed. See # http://groups.google.com/group/sympy/browse_thread/thread/a61d48235f16867f self.newf = self.newf.xreplace({i: newterm}) elif i not in numpows: continue else: # i in numpows newterm = new # TODO: Just put it in self.Tfuncs self.backsubs.append((new, old)) self.newf = self.newf.xreplace({old: newterm}) exps.append(newterm) return exps, pows, numpows, sympows, log_new_extension def _rewrite_logs(self, logs, symlogs): """ Rewrite logs for better processing. """ atoms = self.newf.atoms(log) logs = update_sets(logs, atoms, lambda i: i.args[0].is_rational_function(*self.T) and i.args[0].has(*self.T)) symlogs = update_sets(symlogs, atoms, lambda i: i.has(*self.T) and i.args[0].is_Pow and i.args[0].base.is_rational_function(*self.T) and not i.args[0].exp.is_Integer) # We can handle things like log(x**y) by converting it to y*log(x) # This will fix not only symbolic exponents of the argument, but any # non-Integer exponent, like log(sqrt(x)). The exponent can also # depend on x, like log(x**x). for i in ordered(symlogs): # Unlike in the exponential case above, we do not ever # potentially add new monomials (above we had to add log(a)). # Therefore, there is no need to run any is_deriv functions # here. Just convert log(a**b) to b*log(a) and let # log_new_extension() handle it from there. lbase = log(i.args[0].base) logs.append(lbase) new = i.args[0].exp*lbase self.newf = self.newf.xreplace({i: new}) self.backsubs.append((new, i)) # remove any duplicates logs = sorted(set(logs), key=default_sort_key) return logs, symlogs def _auto_attrs(self): """ Set attributes that are generated automatically. """ if not self.T: # i.e., when using the extension flag and T isn't given self.T = [i.gen for i in self.D] if not self.x: self.x = self.T[0] self.cases = [get_case(d, t) for d, t in zip(self.D, self.T)] self.level = -1 self.t = self.T[self.level] self.d = self.D[self.level] self.case = self.cases[self.level] def _exp_part(self, exps): """ Try to build an exponential extension. Returns ======= Returns True if there was a new extension, False if there was no new extension but it was able to rewrite the given exponentials in terms of the existing extension, and None if the entire extension building process should be restarted. If the process fails because there is no way around an algebraic extension (e.g., exp(log(x)/2)), it will raise NotImplementedError. """ from sympy.integrals.prde import is_log_deriv_k_t_radical new_extension = False restart = False expargs = [i.exp for i in exps] ip = integer_powers(expargs) for arg, others in ip: # Minimize potential problems with algebraic substitution others.sort(key=lambda i: i[1]) arga, argd = frac_in(arg, self.t) A = is_log_deriv_k_t_radical(arga, argd, self) if A is not None: ans, u, n, const = A # if n is 1 or -1, it's algebraic, but we can handle it if n == -1: # This probably will never happen, because # Rational.as_numer_denom() returns the negative term in # the numerator. But in case that changes, reduce it to # n == 1. n = 1 u **= -1 const *= -1 ans = [(i, -j) for i, j in ans] if n == 1: # Example: exp(x + x**2) over QQ(x, exp(x), exp(x**2)) self.newf = self.newf.xreplace({exp(arg): exp(const)*Mul(*[ u**power for u, power in ans])}) self.newf = self.newf.xreplace({exp(p*exparg): exp(const*p) * Mul(*[u**power for u, power in ans]) for exparg, p in others}) # TODO: Add something to backsubs to put exp(const*p) # back together. continue else: # Bad news: we have an algebraic radical. But maybe we # could still avoid it by choosing a different extension. # For example, integer_powers() won't handle exp(x/2 + 1) # over QQ(x, exp(x)), but if we pull out the exp(1), it # will. Or maybe we have exp(x + x**2/2), over # QQ(x, exp(x), exp(x**2)), which is exp(x)*sqrt(exp(x**2)), # but if we use QQ(x, exp(x), exp(x**2/2)), then they will # all work. # # So here is what we do: If there is a non-zero const, pull # it out and retry. Also, if len(ans) > 1, then rewrite # exp(arg) as the product of exponentials from ans, and # retry that. If const == 0 and len(ans) == 1, then we # assume that it would have been handled by either # integer_powers() or n == 1 above if it could be handled, # so we give up at that point. For example, you can never # handle exp(log(x)/2) because it equals sqrt(x). if const or len(ans) > 1: rad = Mul(*[term**(power/n) for term, power in ans]) self.newf = self.newf.xreplace({exp(p*exparg): exp(const*p)*rad for exparg, p in others}) self.newf = self.newf.xreplace(dict(list(zip(reversed(self.T), reversed([f(self.x) for f in self.Tfuncs]))))) restart = True break else: # TODO: give algebraic dependence in error string raise NotImplementedError("Cannot integrate over " "algebraic extensions.") else: arga, argd = frac_in(arg, self.t) darga = (argd*derivation(Poly(arga, self.t), self) - arga*derivation(Poly(argd, self.t), self)) dargd = argd**2 darga, dargd = darga.cancel(dargd, include=True) darg = darga.as_expr()/dargd.as_expr() self.t = next(self.ts) self.T.append(self.t) self.extargs.append(arg) self.exts.append('exp') self.D.append(darg.as_poly(self.t, expand=False)*Poly(self.t, self.t, expand=False)) if self.dummy: i = Dummy("i") else: i = Symbol('i') self.Tfuncs += [Lambda(i, exp(arg.subs(self.x, i)))] self.newf = self.newf.xreplace( {exp(exparg): self.t**p for exparg, p in others}) new_extension = True if restart: return None return new_extension def _log_part(self, logs): """ Try to build a logarithmic extension. Returns ======= Returns True if there was a new extension and False if there was no new extension but it was able to rewrite the given logarithms in terms of the existing extension. Unlike with exponential extensions, there is no way that a logarithm is not transcendental over and cannot be rewritten in terms of an already existing extension in a non-algebraic way, so this function does not ever return None or raise NotImplementedError. """ from sympy.integrals.prde import is_deriv_k new_extension = False logargs = [i.args[0] for i in logs] for arg in ordered(logargs): # The log case is easier, because whenever a logarithm is algebraic # over the base field, it is of the form a1*t1 + ... an*tn + c, # which is a polynomial, so we can just replace it with that. # In other words, we don't have to worry about radicals. arga, argd = frac_in(arg, self.t) A = is_deriv_k(arga, argd, self) if A is not None: ans, u, const = A newterm = log(const) + u self.newf = self.newf.xreplace({log(arg): newterm}) continue else: arga, argd = frac_in(arg, self.t) darga = (argd*derivation(Poly(arga, self.t), self) - arga*derivation(Poly(argd, self.t), self)) dargd = argd**2 darg = darga.as_expr()/dargd.as_expr() self.t = next(self.ts) self.T.append(self.t) self.extargs.append(arg) self.exts.append('log') self.D.append(cancel(darg.as_expr()/arg).as_poly(self.t, expand=False)) if self.dummy: i = Dummy("i") else: i = Symbol('i') self.Tfuncs += [Lambda(i, log(arg.subs(self.x, i)))] self.newf = self.newf.xreplace({log(arg): self.t}) new_extension = True return new_extension @property def _important_attrs(self): """ Returns some of the more important attributes of self. Explanation =========== Used for testing and debugging purposes. The attributes are (fa, fd, D, T, Tfuncs, backsubs, exts, extargs). """ return (self.fa, self.fd, self.D, self.T, self.Tfuncs, self.backsubs, self.exts, self.extargs) # NOTE: this printing doesn't follow the Python's standard # eval(repr(DE)) == DE, where DE is the DifferentialExtension object # , also this printing is supposed to contain all the important # attributes of a DifferentialExtension object def __repr__(self): # no need to have GeneratorType object printed in it r = [(attr, getattr(self, attr)) for attr in self.__slots__ if not isinstance(getattr(self, attr), GeneratorType)] return self.__class__.__name__ + '(dict(%r))' % (r) # fancy printing of DifferentialExtension object def __str__(self): return (self.__class__.__name__ + '({fa=%s, fd=%s, D=%s})' % (self.fa, self.fd, self.D)) # should only be used for debugging purposes, internally # f1 = f2 = log(x) at different places in code execution # may return D1 != D2 as True, since 'level' or other attribute # may differ def __eq__(self, other): for attr in self.__class__.__slots__: d1, d2 = getattr(self, attr), getattr(other, attr) if not (isinstance(d1, GeneratorType) or d1 == d2): return False return True def reset(self): """ Reset self to an initial state. Used by __init__. """ self.t = self.x self.T = [self.x] self.D = [Poly(1, self.x)] self.level = -1 self.exts = [None] self.extargs = [None] if self.dummy: self.ts = numbered_symbols('t', cls=Dummy) else: # For testing self.ts = numbered_symbols('t') # For various things that we change to make things work that we need to # change back when we are done. self.backsubs = [] self.Tfuncs = [] self.newf = self.f def indices(self, extension): """ Parameters ========== extension : str Represents a valid extension type. Returns ======= list: A list of indices of 'exts' where extension of type 'extension' is present. Examples ======== >>> from sympy.integrals.risch import DifferentialExtension >>> from sympy import log, exp >>> from sympy.abc import x >>> DE = DifferentialExtension(log(x) + exp(x), x, handle_first='exp') >>> DE.indices('log') [2] >>> DE.indices('exp') [1] """ return [i for i, ext in enumerate(self.exts) if ext == extension] def increment_level(self): """ Increment the level of self. Explanation =========== This makes the working differential extension larger. self.level is given relative to the end of the list (-1, -2, etc.), so we don't need do worry about it when building the extension. """ if self.level >= -1: raise ValueError("The level of the differential extension cannot " "be incremented any further.") self.level += 1 self.t = self.T[self.level] self.d = self.D[self.level] self.case = self.cases[self.level] return None def decrement_level(self): """ Decrease the level of self. Explanation =========== This makes the working differential extension smaller. self.level is given relative to the end of the list (-1, -2, etc.), so we don't need do worry about it when building the extension. """ if self.level <= -len(self.T): raise ValueError("The level of the differential extension cannot " "be decremented any further.") self.level -= 1 self.t = self.T[self.level] self.d = self.D[self.level] self.case = self.cases[self.level] return None def update_sets(seq, atoms, func): s = set(seq) s = atoms.intersection(s) new = atoms - s s.update(list(filter(func, new))) return list(s) class DecrementLevel: """ A context manager for decrementing the level of a DifferentialExtension. """ __slots__ = ('DE',) def __init__(self, DE): self.DE = DE return def __enter__(self): self.DE.decrement_level() def __exit__(self, exc_type, exc_value, traceback): self.DE.increment_level() class NonElementaryIntegralException(Exception): """ Exception used by subroutines within the Risch algorithm to indicate to one another that the function being integrated does not have an elementary integral in the given differential field. """ # TODO: Rewrite algorithms below to use this (?) # TODO: Pass through information about why the integral was nonelementary, # and store that in the resulting NonElementaryIntegral somehow. pass def gcdex_diophantine(a, b, c): """ Extended Euclidean Algorithm, Diophantine version. Explanation =========== Given ``a``, ``b`` in K[x] and ``c`` in (a, b), the ideal generated by ``a`` and ``b``, return (s, t) such that s*a + t*b == c and either s == 0 or s.degree() < b.degree(). """ # Extended Euclidean Algorithm (Diophantine Version) pg. 13 # TODO: This should go in densetools.py. # XXX: Bettter name? s, g = a.half_gcdex(b) s *= c.exquo(g) # Inexact division means c is not in (a, b) if s and s.degree() >= b.degree(): _, s = s.div(b) t = (c - s*a).exquo(b) return (s, t) def frac_in(f, t, *, cancel=False, **kwargs): """ Returns the tuple (fa, fd), where fa and fd are Polys in t. Explanation =========== This is a common idiom in the Risch Algorithm functions, so we abstract it out here. ``f`` should be a basic expression, a Poly, or a tuple (fa, fd), where fa and fd are either basic expressions or Polys, and f == fa/fd. **kwargs are applied to Poly. """ if type(f) is tuple: fa, fd = f f = fa.as_expr()/fd.as_expr() fa, fd = f.as_expr().as_numer_denom() fa, fd = fa.as_poly(t, **kwargs), fd.as_poly(t, **kwargs) if cancel: fa, fd = fa.cancel(fd, include=True) if fa is None or fd is None: raise ValueError("Could not turn %s into a fraction in %s." % (f, t)) return (fa, fd) def as_poly_1t(p, t, z): """ (Hackish) way to convert an element ``p`` of K[t, 1/t] to K[t, z]. In other words, ``z == 1/t`` will be a dummy variable that Poly can handle better. See issue 5131. Examples ======== >>> from sympy import random_poly >>> from sympy.integrals.risch import as_poly_1t >>> from sympy.abc import x, z >>> p1 = random_poly(x, 10, -10, 10) >>> p2 = random_poly(x, 10, -10, 10) >>> p = p1 + p2.subs(x, 1/x) >>> as_poly_1t(p, x, z).as_expr().subs(z, 1/x) == p True """ # TODO: Use this on the final result. That way, we can avoid answers like # (...)*exp(-x). pa, pd = frac_in(p, t, cancel=True) if not pd.is_monomial: # XXX: Is there a better Poly exception that we could raise here? # Either way, if you see this (from the Risch Algorithm) it indicates # a bug. raise PolynomialError("%s is not an element of K[%s, 1/%s]." % (p, t, t)) d = pd.degree(t) one_t_part = pa.slice(0, d + 1) r = pd.degree() - pa.degree() t_part = pa - one_t_part try: t_part = t_part.to_field().exquo(pd) except DomainError as e: # issue 4950 raise NotImplementedError(e) # Compute the negative degree parts. one_t_part = Poly.from_list(reversed(one_t_part.rep.rep), *one_t_part.gens, domain=one_t_part.domain) if 0 < r < oo: one_t_part *= Poly(t**r, t) one_t_part = one_t_part.replace(t, z) # z will be 1/t if pd.nth(d): one_t_part *= Poly(1/pd.nth(d), z, expand=False) ans = t_part.as_poly(t, z, expand=False) + one_t_part.as_poly(t, z, expand=False) return ans def derivation(p, DE, coefficientD=False, basic=False): """ Computes Dp. Explanation =========== Given the derivation D with D = d/dx and p is a polynomial in t over K(x), return Dp. If coefficientD is True, it computes the derivation kD (kappaD), which is defined as kD(sum(ai*Xi**i, (i, 0, n))) == sum(Dai*Xi**i, (i, 1, n)) (Definition 3.2.2, page 80). X in this case is T[-1], so coefficientD computes the derivative just with respect to T[:-1], with T[-1] treated as a constant. If ``basic=True``, the returns a Basic expression. Elements of D can still be instances of Poly. """ if basic: r = 0 else: r = Poly(0, DE.t) t = DE.t if coefficientD: if DE.level <= -len(DE.T): # 'base' case, the answer is 0. return r DE.decrement_level() D = DE.D[:len(DE.D) + DE.level + 1] T = DE.T[:len(DE.T) + DE.level + 1] for d, v in zip(D, T): pv = p.as_poly(v) if pv is None or basic: pv = p.as_expr() if basic: r += d.as_expr()*pv.diff(v) else: r += (d.as_expr()*pv.diff(v).as_expr()).as_poly(t) if basic: r = cancel(r) if coefficientD: DE.increment_level() return r def get_case(d, t): """ Returns the type of the derivation d. Returns one of {'exp', 'tan', 'base', 'primitive', 'other_linear', 'other_nonlinear'}. """ if not d.expr.has(t): if d.is_one: return 'base' return 'primitive' if d.rem(Poly(t, t)).is_zero: return 'exp' if d.rem(Poly(1 + t**2, t)).is_zero: return 'tan' if d.degree(t) > 1: return 'other_nonlinear' return 'other_linear' def splitfactor(p, DE, coefficientD=False, z=None): """ Splitting factorization. Explanation =========== Given a derivation D on k[t] and ``p`` in k[t], return (p_n, p_s) in k[t] x k[t] such that p = p_n*p_s, p_s is special, and each square factor of p_n is normal. Page. 100 """ kinv = [1/x for x in DE.T[:DE.level]] if z: kinv.append(z) One = Poly(1, DE.t, domain=p.get_domain()) Dp = derivation(p, DE, coefficientD=coefficientD) # XXX: Is this right? if p.is_zero: return (p, One) if not p.expr.has(DE.t): s = p.as_poly(*kinv).gcd(Dp.as_poly(*kinv)).as_poly(DE.t) n = p.exquo(s) return (n, s) if not Dp.is_zero: h = p.gcd(Dp).to_field() g = p.gcd(p.diff(DE.t)).to_field() s = h.exquo(g) if s.degree(DE.t) == 0: return (p, One) q_split = splitfactor(p.exquo(s), DE, coefficientD=coefficientD) return (q_split[0], q_split[1]*s) else: return (p, One) def splitfactor_sqf(p, DE, coefficientD=False, z=None, basic=False): """ Splitting Square-free Factorization. Explanation =========== Given a derivation D on k[t] and ``p`` in k[t], returns (N1, ..., Nm) and (S1, ..., Sm) in k[t]^m such that p = (N1*N2**2*...*Nm**m)*(S1*S2**2*...*Sm**m) is a splitting factorization of ``p`` and the Ni and Si are square-free and coprime. """ # TODO: This algorithm appears to be faster in every case # TODO: Verify this and splitfactor() for multiple extensions kkinv = [1/x for x in DE.T[:DE.level]] + DE.T[:DE.level] if z: kkinv = [z] S = [] N = [] p_sqf = p.sqf_list_include() if p.is_zero: return (((p, 1),), ()) for pi, i in p_sqf: Si = pi.as_poly(*kkinv).gcd(derivation(pi, DE, coefficientD=coefficientD,basic=basic).as_poly(*kkinv)).as_poly(DE.t) pi = Poly(pi, DE.t) Si = Poly(Si, DE.t) Ni = pi.exquo(Si) if not Si.is_one: S.append((Si, i)) if not Ni.is_one: N.append((Ni, i)) return (tuple(N), tuple(S)) def canonical_representation(a, d, DE): """ Canonical Representation. Explanation =========== Given a derivation D on k[t] and f = a/d in k(t), return (f_p, f_s, f_n) in k[t] x k(t) x k(t) such that f = f_p + f_s + f_n is the canonical representation of f (f_p is a polynomial, f_s is reduced (has a special denominator), and f_n is simple (has a normal denominator). """ # Make d monic l = Poly(1/d.LC(), DE.t) a, d = a.mul(l), d.mul(l) q, r = a.div(d) dn, ds = splitfactor(d, DE) b, c = gcdex_diophantine(dn.as_poly(DE.t), ds.as_poly(DE.t), r.as_poly(DE.t)) b, c = b.as_poly(DE.t), c.as_poly(DE.t) return (q, (b, ds), (c, dn)) def hermite_reduce(a, d, DE): """ Hermite Reduction - Mack's Linear Version. Given a derivation D on k(t) and f = a/d in k(t), returns g, h, r in k(t) such that f = Dg + h + r, h is simple, and r is reduced. """ # Make d monic l = Poly(1/d.LC(), DE.t) a, d = a.mul(l), d.mul(l) fp, fs, fn = canonical_representation(a, d, DE) a, d = fn l = Poly(1/d.LC(), DE.t) a, d = a.mul(l), d.mul(l) ga = Poly(0, DE.t) gd = Poly(1, DE.t) dd = derivation(d, DE) dm = gcd(d, dd).as_poly(DE.t) ds, r = d.div(dm) while dm.degree(DE.t)>0: ddm = derivation(dm, DE) dm2 = gcd(dm, ddm) dms, r = dm.div(dm2) ds_ddm = ds.mul(ddm) ds_ddm_dm, r = ds_ddm.div(dm) b, c = gcdex_diophantine(-ds_ddm_dm.as_poly(DE.t), dms.as_poly(DE.t), a.as_poly(DE.t)) b, c = b.as_poly(DE.t), c.as_poly(DE.t) db = derivation(b, DE).as_poly(DE.t) ds_dms, r = ds.div(dms) a = c.as_poly(DE.t) - db.mul(ds_dms).as_poly(DE.t) ga = ga*dm + b*gd gd = gd*dm ga, gd = ga.cancel(gd, include=True) dm = dm2 d = ds q, r = a.div(d) ga, gd = ga.cancel(gd, include=True) r, d = r.cancel(d, include=True) rra = q*fs[1] + fp*fs[1] + fs[0] rrd = fs[1] rra, rrd = rra.cancel(rrd, include=True) return ((ga, gd), (r, d), (rra, rrd)) def polynomial_reduce(p, DE): """ Polynomial Reduction. Explanation =========== Given a derivation D on k(t) and p in k[t] where t is a nonlinear monomial over k, return q, r in k[t] such that p = Dq + r, and deg(r) < deg_t(Dt). """ q = Poly(0, DE.t) while p.degree(DE.t) >= DE.d.degree(DE.t): m = p.degree(DE.t) - DE.d.degree(DE.t) + 1 q0 = Poly(DE.t**m, DE.t).mul(Poly(p.as_poly(DE.t).LC()/ (m*DE.d.LC()), DE.t)) q += q0 p = p - derivation(q0, DE) return (q, p) def laurent_series(a, d, F, n, DE): """ Contribution of ``F`` to the full partial fraction decomposition of A/D. Explanation =========== Given a field K of characteristic 0 and ``A``,``D``,``F`` in K[x] with D monic, nonzero, coprime with A, and ``F`` the factor of multiplicity n in the square- free factorization of D, return the principal parts of the Laurent series of A/D at all the zeros of ``F``. """ if F.degree()==0: return 0 Z = _symbols('z', n) Z.insert(0, z) delta_a = Poly(0, DE.t) delta_d = Poly(1, DE.t) E = d.quo(F**n) ha, hd = (a, E*Poly(z**n, DE.t)) dF = derivation(F,DE) B, G = gcdex_diophantine(E, F, Poly(1,DE.t)) C, G = gcdex_diophantine(dF, F, Poly(1,DE.t)) # initialization F_store = F V, DE_D_list, H_list= [], [], [] for j in range(0, n): # jth derivative of z would be substituted with dfnth/(j+1) where dfnth =(d^n)f/(dx)^n F_store = derivation(F_store, DE) v = (F_store.as_expr())/(j + 1) V.append(v) DE_D_list.append(Poly(Z[j + 1],Z[j])) DE_new = DifferentialExtension(extension = {'D': DE_D_list}) #a differential indeterminate for j in range(0, n): zEha = Poly(z**(n + j), DE.t)*E**(j + 1)*ha zEhd = hd Pa, Pd = cancel((zEha, zEhd))[1], cancel((zEha, zEhd))[2] Q = Pa.quo(Pd) for i in range(0, j + 1): Q = Q.subs(Z[i], V[i]) Dha = (hd*derivation(ha, DE, basic=True).as_poly(DE.t) + ha*derivation(hd, DE, basic=True).as_poly(DE.t) + hd*derivation(ha, DE_new, basic=True).as_poly(DE.t) + ha*derivation(hd, DE_new, basic=True).as_poly(DE.t)) Dhd = Poly(j + 1, DE.t)*hd**2 ha, hd = Dha, Dhd Ff, Fr = F.div(gcd(F, Q)) F_stara, F_stard = frac_in(Ff, DE.t) if F_stara.degree(DE.t) - F_stard.degree(DE.t) > 0: QBC = Poly(Q, DE.t)*B**(1 + j)*C**(n + j) H = QBC H_list.append(H) H = (QBC*F_stard).rem(F_stara) alphas = real_roots(F_stara) for alpha in list(alphas): delta_a = delta_a*Poly((DE.t - alpha)**(n - j), DE.t) + Poly(H.eval(alpha), DE.t) delta_d = delta_d*Poly((DE.t - alpha)**(n - j), DE.t) return (delta_a, delta_d, H_list) def recognize_derivative(a, d, DE, z=None): """ Compute the squarefree factorization of the denominator of f and for each Di the polynomial H in K[x] (see Theorem 2.7.1), using the LaurentSeries algorithm. Write Di = GiEi where Gj = gcd(Hn, Di) and gcd(Ei,Hn) = 1. Since the residues of f at the roots of Gj are all 0, and the residue of f at a root alpha of Ei is Hi(a) != 0, f is the derivative of a rational function if and only if Ei = 1 for each i, which is equivalent to Di | H[-1] for each i. """ flag =True a, d = a.cancel(d, include=True) q, r = a.div(d) Np, Sp = splitfactor_sqf(d, DE, coefficientD=True, z=z) j = 1 for (s, i) in Sp: delta_a, delta_d, H = laurent_series(r, d, s, j, DE) g = gcd(d, H[-1]).as_poly() if g is not d: flag = False break j = j + 1 return flag def recognize_log_derivative(a, d, DE, z=None): """ There exists a v in K(x)* such that f = dv/v where f a rational function if and only if f can be written as f = A/D where D is squarefree,deg(A) < deg(D), gcd(A, D) = 1, and all the roots of the Rothstein-Trager resultant are integers. In that case, any of the Rothstein-Trager, Lazard-Rioboo-Trager or Czichowski algorithm produces u in K(x) such that du/dx = uf. """ z = z or Dummy('z') a, d = a.cancel(d, include=True) p, a = a.div(d) pz = Poly(z, DE.t) Dd = derivation(d, DE) q = a - pz*Dd r, R = d.resultant(q, includePRS=True) r = Poly(r, z) Np, Sp = splitfactor_sqf(r, DE, coefficientD=True, z=z) for s, i in Sp: # TODO also consider the complex roots # incase we have complex roots it should turn the flag false a = real_roots(s.as_poly(z)) if any(not j.is_Integer for j in a): return False return True def residue_reduce(a, d, DE, z=None, invert=True): """ Lazard-Rioboo-Rothstein-Trager resultant reduction. Explanation =========== Given a derivation ``D`` on k(t) and f in k(t) simple, return g elementary over k(t) and a Boolean b in {True, False} such that f - Dg in k[t] if b == True or f + h and f + h - Dg do not have an elementary integral over k(t) for any h in k (reduced) if b == False. Returns (G, b), where G is a tuple of tuples of the form (s_i, S_i), such that g = Add(*[RootSum(s_i, lambda z: z*log(S_i(z, t))) for S_i, s_i in G]). f - Dg is the remaining integral, which is elementary only if b == True, and hence the integral of f is elementary only if b == True. f - Dg is not calculated in this function because that would require explicitly calculating the RootSum. Use residue_reduce_derivation(). """ # TODO: Use log_to_atan() from rationaltools.py # If r = residue_reduce(...), then the logarithmic part is given by: # sum([RootSum(a[0].as_poly(z), lambda i: i*log(a[1].as_expr()).subs(z, # i)).subs(t, log(x)) for a in r[0]]) z = z or Dummy('z') a, d = a.cancel(d, include=True) a, d = a.to_field().mul_ground(1/d.LC()), d.to_field().mul_ground(1/d.LC()) kkinv = [1/x for x in DE.T[:DE.level]] + DE.T[:DE.level] if a.is_zero: return ([], True) p, a = a.div(d) pz = Poly(z, DE.t) Dd = derivation(d, DE) q = a - pz*Dd if Dd.degree(DE.t) <= d.degree(DE.t): r, R = d.resultant(q, includePRS=True) else: r, R = q.resultant(d, includePRS=True) R_map, H = {}, [] for i in R: R_map[i.degree()] = i r = Poly(r, z) Np, Sp = splitfactor_sqf(r, DE, coefficientD=True, z=z) for s, i in Sp: if i == d.degree(DE.t): s = Poly(s, z).monic() H.append((s, d)) else: h = R_map.get(i) if h is None: continue h_lc = Poly(h.as_poly(DE.t).LC(), DE.t, field=True) h_lc_sqf = h_lc.sqf_list_include(all=True) for a, j in h_lc_sqf: h = Poly(h, DE.t, field=True).exquo(Poly(gcd(a, s**j, *kkinv), DE.t)) s = Poly(s, z).monic() if invert: h_lc = Poly(h.as_poly(DE.t).LC(), DE.t, field=True, expand=False) inv, coeffs = h_lc.as_poly(z, field=True).invert(s), [S.One] for coeff in h.coeffs()[1:]: L = reduced(inv*coeff.as_poly(inv.gens), [s])[1] coeffs.append(L.as_expr()) h = Poly(dict(list(zip(h.monoms(), coeffs))), DE.t) H.append((s, h)) b = all([not cancel(i.as_expr()).has(DE.t, z) for i, _ in Np]) return (H, b) def residue_reduce_to_basic(H, DE, z): """ Converts the tuple returned by residue_reduce() into a Basic expression. """ # TODO: check what Lambda does with RootOf i = Dummy('i') s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) return sum(RootSum(a[0].as_poly(z), Lambda(i, i*log(a[1].as_expr()).subs( {z: i}).subs(s))) for a in H) def residue_reduce_derivation(H, DE, z): """ Computes the derivation of an expression returned by residue_reduce(). In general, this is a rational function in t, so this returns an as_expr() result. """ # TODO: verify that this is correct for multiple extensions i = Dummy('i') return S(sum(RootSum(a[0].as_poly(z), Lambda(i, i*derivation(a[1], DE).as_expr().subs(z, i)/a[1].as_expr().subs(z, i))) for a in H)) def integrate_primitive_polynomial(p, DE): """ Integration of primitive polynomials. Explanation =========== Given a primitive monomial t over k, and ``p`` in k[t], return q in k[t], r in k, and a bool b in {True, False} such that r = p - Dq is in k if b is True, or r = p - Dq does not have an elementary integral over k(t) if b is False. """ from sympy.integrals.prde import limited_integrate Zero = Poly(0, DE.t) q = Poly(0, DE.t) if not p.expr.has(DE.t): return (Zero, p, True) while True: if not p.expr.has(DE.t): return (q, p, True) Dta, Dtb = frac_in(DE.d, DE.T[DE.level - 1]) with DecrementLevel(DE): # We had better be integrating the lowest extension (x) # with ratint(). a = p.LC() aa, ad = frac_in(a, DE.t) try: rv = limited_integrate(aa, ad, [(Dta, Dtb)], DE) if rv is None: raise NonElementaryIntegralException (ba, bd), c = rv except NonElementaryIntegralException: return (q, p, False) m = p.degree(DE.t) q0 = c[0].as_poly(DE.t)*Poly(DE.t**(m + 1)/(m + 1), DE.t) + \ (ba.as_expr()/bd.as_expr()).as_poly(DE.t)*Poly(DE.t**m, DE.t) p = p - derivation(q0, DE) q = q + q0 def integrate_primitive(a, d, DE, z=None): """ Integration of primitive functions. Explanation =========== Given a primitive monomial t over k and f in k(t), return g elementary over k(t), i in k(t), and b in {True, False} such that i = f - Dg is in k if b is True or i = f - Dg does not have an elementary integral over k(t) if b is False. This function returns a Basic expression for the first argument. If b is True, the second argument is Basic expression in k to recursively integrate. If b is False, the second argument is an unevaluated Integral, which has been proven to be nonelementary. """ # XXX: a and d must be canceled, or this might return incorrect results z = z or Dummy("z") s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) g1, h, r = hermite_reduce(a, d, DE) g2, b = residue_reduce(h[0], h[1], DE, z=z) if not b: i = cancel(a.as_expr()/d.as_expr() - (g1[1]*derivation(g1[0], DE) - g1[0]*derivation(g1[1], DE)).as_expr()/(g1[1]**2).as_expr() - residue_reduce_derivation(g2, DE, z)) i = NonElementaryIntegral(cancel(i).subs(s), DE.x) return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + residue_reduce_to_basic(g2, DE, z), i, b) # h - Dg2 + r p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, DE, z) + r[0].as_expr()/r[1].as_expr()) p = p.as_poly(DE.t) q, i, b = integrate_primitive_polynomial(p, DE) ret = ((g1[0].as_expr()/g1[1].as_expr() + q.as_expr()).subs(s) + residue_reduce_to_basic(g2, DE, z)) if not b: # TODO: This does not do the right thing when b is False i = NonElementaryIntegral(cancel(i.as_expr()).subs(s), DE.x) else: i = cancel(i.as_expr()) return (ret, i, b) def integrate_hyperexponential_polynomial(p, DE, z): """ Integration of hyperexponential polynomials. Explanation =========== Given a hyperexponential monomial t over k and ``p`` in k[t, 1/t], return q in k[t, 1/t] and a bool b in {True, False} such that p - Dq in k if b is True, or p - Dq does not have an elementary integral over k(t) if b is False. """ from sympy.integrals.rde import rischDE t1 = DE.t dtt = DE.d.exquo(Poly(DE.t, DE.t)) qa = Poly(0, DE.t) qd = Poly(1, DE.t) b = True if p.is_zero: return(qa, qd, b) with DecrementLevel(DE): for i in range(-p.degree(z), p.degree(t1) + 1): if not i: continue elif i < 0: # If you get AttributeError: 'NoneType' object has no attribute 'nth' # then this should really not have expand=False # But it shouldn't happen because p is already a Poly in t and z a = p.as_poly(z, expand=False).nth(-i) else: # If you get AttributeError: 'NoneType' object has no attribute 'nth' # then this should really not have expand=False a = p.as_poly(t1, expand=False).nth(i) aa, ad = frac_in(a, DE.t, field=True) aa, ad = aa.cancel(ad, include=True) iDt = Poly(i, t1)*dtt iDta, iDtd = frac_in(iDt, DE.t, field=True) try: va, vd = rischDE(iDta, iDtd, Poly(aa, DE.t), Poly(ad, DE.t), DE) va, vd = frac_in((va, vd), t1, cancel=True) except NonElementaryIntegralException: b = False else: qa = qa*vd + va*Poly(t1**i)*qd qd *= vd return (qa, qd, b) def integrate_hyperexponential(a, d, DE, z=None, conds='piecewise'): """ Integration of hyperexponential functions. Explanation =========== Given a hyperexponential monomial t over k and f in k(t), return g elementary over k(t), i in k(t), and a bool b in {True, False} such that i = f - Dg is in k if b is True or i = f - Dg does not have an elementary integral over k(t) if b is False. This function returns a Basic expression for the first argument. If b is True, the second argument is Basic expression in k to recursively integrate. If b is False, the second argument is an unevaluated Integral, which has been proven to be nonelementary. """ # XXX: a and d must be canceled, or this might return incorrect results z = z or Dummy("z") s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) g1, h, r = hermite_reduce(a, d, DE) g2, b = residue_reduce(h[0], h[1], DE, z=z) if not b: i = cancel(a.as_expr()/d.as_expr() - (g1[1]*derivation(g1[0], DE) - g1[0]*derivation(g1[1], DE)).as_expr()/(g1[1]**2).as_expr() - residue_reduce_derivation(g2, DE, z)) i = NonElementaryIntegral(cancel(i.subs(s)), DE.x) return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + residue_reduce_to_basic(g2, DE, z), i, b) # p should be a polynomial in t and 1/t, because Sirr == k[t, 1/t] # h - Dg2 + r p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, DE, z) + r[0].as_expr()/r[1].as_expr()) pp = as_poly_1t(p, DE.t, z) qa, qd, b = integrate_hyperexponential_polynomial(pp, DE, z) i = pp.nth(0, 0) ret = ((g1[0].as_expr()/g1[1].as_expr()).subs(s) \ + residue_reduce_to_basic(g2, DE, z)) qas = qa.as_expr().subs(s) qds = qd.as_expr().subs(s) if conds == 'piecewise' and DE.x not in qds.free_symbols: # We have to be careful if the exponent is S.Zero! # XXX: Does qd = 0 always necessarily correspond to the exponential # equaling 1? ret += Piecewise( (qas/qds, Ne(qds, 0)), (integrate((p - i).subs(DE.t, 1).subs(s), DE.x), True) ) else: ret += qas/qds if not b: i = p - (qd*derivation(qa, DE) - qa*derivation(qd, DE)).as_expr()/\ (qd**2).as_expr() i = NonElementaryIntegral(cancel(i).subs(s), DE.x) return (ret, i, b) def integrate_hypertangent_polynomial(p, DE): """ Integration of hypertangent polynomials. Explanation =========== Given a differential field k such that sqrt(-1) is not in k, a hypertangent monomial t over k, and p in k[t], return q in k[t] and c in k such that p - Dq - c*D(t**2 + 1)/(t**1 + 1) is in k and p - Dq does not have an elementary integral over k(t) if Dc != 0. """ # XXX: Make sure that sqrt(-1) is not in k. q, r = polynomial_reduce(p, DE) a = DE.d.exquo(Poly(DE.t**2 + 1, DE.t)) c = Poly(r.nth(1)/(2*a.as_expr()), DE.t) return (q, c) def integrate_nonlinear_no_specials(a, d, DE, z=None): """ Integration of nonlinear monomials with no specials. Explanation =========== Given a nonlinear monomial t over k such that Sirr ({p in k[t] | p is special, monic, and irreducible}) is empty, and f in k(t), returns g elementary over k(t) and a Boolean b in {True, False} such that f - Dg is in k if b == True, or f - Dg does not have an elementary integral over k(t) if b == False. This function is applicable to all nonlinear extensions, but in the case where it returns b == False, it will only have proven that the integral of f - Dg is nonelementary if Sirr is empty. This function returns a Basic expression. """ # TODO: Integral from k? # TODO: split out nonelementary integral # XXX: a and d must be canceled, or this might not return correct results z = z or Dummy("z") s = list(zip(reversed(DE.T), reversed([f(DE.x) for f in DE.Tfuncs]))) g1, h, r = hermite_reduce(a, d, DE) g2, b = residue_reduce(h[0], h[1], DE, z=z) if not b: return ((g1[0].as_expr()/g1[1].as_expr()).subs(s) + residue_reduce_to_basic(g2, DE, z), b) # Because f has no specials, this should be a polynomial in t, or else # there is a bug. p = cancel(h[0].as_expr()/h[1].as_expr() - residue_reduce_derivation(g2, DE, z).as_expr() + r[0].as_expr()/r[1].as_expr()).as_poly(DE.t) q1, q2 = polynomial_reduce(p, DE) if q2.expr.has(DE.t): b = False else: b = True ret = (cancel(g1[0].as_expr()/g1[1].as_expr() + q1.as_expr()).subs(s) + residue_reduce_to_basic(g2, DE, z)) return (ret, b) class NonElementaryIntegral(Integral): """ Represents a nonelementary Integral. Explanation =========== If the result of integrate() is an instance of this class, it is guaranteed to be nonelementary. Note that integrate() by default will try to find any closed-form solution, even in terms of special functions which may themselves not be elementary. To make integrate() only give elementary solutions, or, in the cases where it can prove the integral to be nonelementary, instances of this class, use integrate(risch=True). In this case, integrate() may raise NotImplementedError if it cannot make such a determination. integrate() uses the deterministic Risch algorithm to integrate elementary functions or prove that they have no elementary integral. In some cases, this algorithm can split an integral into an elementary and nonelementary part, so that the result of integrate will be the sum of an elementary expression and a NonElementaryIntegral. Examples ======== >>> from sympy import integrate, exp, log, Integral >>> from sympy.abc import x >>> a = integrate(exp(-x**2), x, risch=True) >>> print(a) Integral(exp(-x**2), x) >>> type(a) >>> expr = (2*log(x)**2 - log(x) - x**2)/(log(x)**3 - x**2*log(x)) >>> b = integrate(expr, x, risch=True) >>> print(b) -log(-x + log(x))/2 + log(x + log(x))/2 + Integral(1/log(x), x) >>> type(b.atoms(Integral).pop()) """ # TODO: This is useful in and of itself, because isinstance(result, # NonElementaryIntegral) will tell if the integral has been proven to be # elementary. But should we do more? Perhaps a no-op .doit() if # elementary=True? Or maybe some information on why the integral is # nonelementary. pass def risch_integrate(f, x, extension=None, handle_first='log', separate_integral=False, rewrite_complex=None, conds='piecewise'): r""" The Risch Integration Algorithm. Explanation =========== Only transcendental functions are supported. Currently, only exponentials and logarithms are supported, but support for trigonometric functions is forthcoming. If this function returns an unevaluated Integral in the result, it means that it has proven that integral to be nonelementary. Any errors will result in raising NotImplementedError. The unevaluated Integral will be an instance of NonElementaryIntegral, a subclass of Integral. handle_first may be either 'exp' or 'log'. This changes the order in which the extension is built, and may result in a different (but equivalent) solution (for an example of this, see issue 5109). It is also possible that the integral may be computed with one but not the other, because not all cases have been implemented yet. It defaults to 'log' so that the outer extension is exponential when possible, because more of the exponential case has been implemented. If ``separate_integral`` is ``True``, the result is returned as a tuple (ans, i), where the integral is ans + i, ans is elementary, and i is either a NonElementaryIntegral or 0. This useful if you want to try further integrating the NonElementaryIntegral part using other algorithms to possibly get a solution in terms of special functions. It is False by default. Examples ======== >>> from sympy.integrals.risch import risch_integrate >>> from sympy import exp, log, pprint >>> from sympy.abc import x First, we try integrating exp(-x**2). Except for a constant factor of 2/sqrt(pi), this is the famous error function. >>> pprint(risch_integrate(exp(-x**2), x)) / | | 2 | -x | e dx | / The unevaluated Integral in the result means that risch_integrate() has proven that exp(-x**2) does not have an elementary anti-derivative. In many cases, risch_integrate() can split out the elementary anti-derivative part from the nonelementary anti-derivative part. For example, >>> pprint(risch_integrate((2*log(x)**2 - log(x) - x**2)/(log(x)**3 - ... x**2*log(x)), x)) / | log(-x + log(x)) log(x + log(x)) | 1 - ---------------- + --------------- + | ------ dx 2 2 | log(x) | / This means that it has proven that the integral of 1/log(x) is nonelementary. This function is also known as the logarithmic integral, and is often denoted as Li(x). risch_integrate() currently only accepts purely transcendental functions with exponentials and logarithms, though note that this can include nested exponentials and logarithms, as well as exponentials with bases other than E. >>> pprint(risch_integrate(exp(x)*exp(exp(x)), x)) / x\ \e / e >>> pprint(risch_integrate(exp(exp(x)), x)) / | | / x\ | \e / | e dx | / >>> pprint(risch_integrate(x*x**x*log(x) + x**x + x*x**x, x)) x x*x >>> pprint(risch_integrate(x**x, x)) / | | x | x dx | / >>> pprint(risch_integrate(-1/(x*log(x)*log(log(x))**2), x)) 1 ----------- log(log(x)) """ f = S(f) DE = extension or DifferentialExtension(f, x, handle_first=handle_first, dummy=True, rewrite_complex=rewrite_complex) fa, fd = DE.fa, DE.fd result = S.Zero for case in reversed(DE.cases): if not fa.expr.has(DE.t) and not fd.expr.has(DE.t) and not case == 'base': DE.decrement_level() fa, fd = frac_in((fa, fd), DE.t) continue fa, fd = fa.cancel(fd, include=True) if case == 'exp': ans, i, b = integrate_hyperexponential(fa, fd, DE, conds=conds) elif case == 'primitive': ans, i, b = integrate_primitive(fa, fd, DE) elif case == 'base': # XXX: We can't call ratint() directly here because it doesn't # handle polynomials correctly. ans = integrate(fa.as_expr()/fd.as_expr(), DE.x, risch=False) b = False i = S.Zero else: raise NotImplementedError("Only exponential and logarithmic " "extensions are currently supported.") result += ans if b: DE.decrement_level() fa, fd = frac_in(i, DE.t) else: result = result.subs(DE.backsubs) if not i.is_zero: i = NonElementaryIntegral(i.function.subs(DE.backsubs),i.limits) if not separate_integral: result += i return result else: if isinstance(i, NonElementaryIntegral): return (result, i) else: return (result, 0) sympy-sympy-1.9/sympy/integrals/rubi/000077500000000000000000000000001412543434000200355ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/__init__.py000066400000000000000000000066101412543434000221510ustar00rootroot00000000000000''' Rule Based Integration(RUBI) module in sympy uses set of transformation rules to integrate an expression. All the transformation rules are compiled as a discrimination-net which helps in matching expression with the rule efficiently. Due to large number of rules, the module would normally take lot of time to load. Hence, it is better to use Rubi while doing multiple integrations. Rules are taken from Rubi version 4.10.8. Note: This module has dependency on MatchPy library. Basic Structure =============== All rules in matchpy format are in rules folder. They are in separate files. While matching a pattern, there are constraints that need to be checked. These constraints are placed in a single file `constraints.py`. A complete rule look like this: ``` def cons_f1(m, x): return FreeQ(m, x) cons1 = CustomConstraint(cons_f1) def cons_f2(m): return NonzeroQ(m + S(1)) cons2 = CustomConstraint(cons_f2) pattern1 = Pattern(Integral(x_**WC('m', S(1)), x_), cons1, cons2) def replacement1(m, x): rubi.append(1) return Simp(x**(m + S(1))/(m + S(1)), x) rule1 = ReplacementRule(pattern1, replacement1) ``` As seen in the above example, a rule has 3 parts 1. Pattern with constraints. Expression is matched against this pattern. 2. Replacement function, which gives the resulting expression with which the original expression has to be replaced with. There is also `rubi.append(1)`. This (rubi) is a list which keeps track of rules applied to an expression. This can be accessed by `rules_applied` in `rubi.py` 3. Rule, which combines pattern and replacement function. (For more details refer to matchpy documents) Note: The name of arguments of function for constraints and replacement should be taken care of. They need to be exactly same as wildcard in the `Pattern`. Like, in the above example, if `cons_f1` is written something like this: ``` def cons_f1(a, x): return FreeQ(a, x) ``` This is not going to work because in the Pattern, `m` has been used as a wildcard. So only thing is naming of arguments matters. TODO ==== * Use code generation to implement all rules. * Testing of all the tests from rubi test suit. See: http://www.apmaths.uwo.ca/~arich/IntegrationProblems/MathematicaSyntaxFiles/MathematicaSyntaxFiles.html * Add support for `Piecewise` functions. Debugging ========= When an integration is not successful. We can see which rule is matching the expression by using `get_matching_rule_definition()` function. We can cross-check if correct rule is being applied by evaluating the same expression in Mathematica. If the applied rule is same, then we need to check the `ReplacementRule` and the utility functions used in the `ReplacementRule`. Parsing Rules and Tests ======================= Code for parsing rule and tests are included in sympy. They have been properly explained with steps in `sympy/integrals/rubi/parsetools/rubi_parsing_guide.md`. Running Tests ============= The tests for rubi in `rubi_tests` have been blacklisted as it takes a very long time to run all the tests. To run a test run the following in a python terminal: ``` >>> import sympy >>> sympy.test("rubi_tests", blacklist = []) # doctest: +SKIP ``` For specific tests like `test_sine.py` use this `sympy.test("rubi_tests/tests/test_sine.py", blacklist = [])`. References ========== [1] http://www.apmaths.uwo.ca/~arich/ [2] https://github.com/sympy/sympy/issues/7749 [3] https://github.com/sympy/sympy/pull/12978 ''' sympy-sympy-1.9/sympy/integrals/rubi/constraints.py000066400000000000000000011003221412543434000227550ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def cons_f1(a): return ZeroQ(a) cons1 = CustomConstraint(cons_f1) def cons_f2(a, x): return FreeQ(a, x) cons2 = CustomConstraint(cons_f2) def cons_f3(b, x): return FreeQ(b, x) cons3 = CustomConstraint(cons_f3) def cons_f4(n, x): return FreeQ(n, x) cons4 = CustomConstraint(cons_f4) def cons_f5(p, x): return FreeQ(p, x) cons5 = CustomConstraint(cons_f5) def cons_f6(b): return ZeroQ(b) cons6 = CustomConstraint(cons_f6) def cons_f7(j, n): return ZeroQ(j - S(2)*n) cons7 = CustomConstraint(cons_f7) def cons_f8(c, x): return FreeQ(c, x) cons8 = CustomConstraint(cons_f8) def cons_f9(c): return ZeroQ(c) cons9 = CustomConstraint(cons_f9) def cons_f10(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(FreeQ(v, x)) cons10 = CustomConstraint(cons_f10) def cons_f11(Pm, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(Pm, x) cons11 = CustomConstraint(cons_f11) def cons_f12(p): return Not(RationalQ(p)) cons12 = CustomConstraint(cons_f12) def cons_f13(p): return RationalQ(p) cons13 = CustomConstraint(cons_f13) def cons_f14(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c), x) cons14 = CustomConstraint(cons_f14) def cons_f15(a): return EqQ(a**S(2), S(1)) cons15 = CustomConstraint(cons_f15) def cons_f16(u, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_15(b, v): return FreeQ(b, x) _cons_15 = CustomConstraint(_cons_f_15) pat = Pattern(UtilityOperator(b_*v_, x), _cons_15) result_matchq = is_match(UtilityOperator(u, x), pat) return Not(result_matchq) cons16 = CustomConstraint(cons_f16) def cons_f17(u): return SumQ(u) cons17 = CustomConstraint(cons_f17) def cons_f18(u, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_17(a, b, v): return And(FreeQ(List(a, b), x), InverseFunctionQ(v)) _cons_17 = CustomConstraint(_cons_f_17) pat = Pattern(UtilityOperator(a_ + v_*WC('b', S(1)), x), _cons_17) result_matchq = is_match(UtilityOperator(u, x), pat) return Not(result_matchq) cons18 = CustomConstraint(cons_f18) def cons_f19(m, x): return FreeQ(m, x) cons19 = CustomConstraint(cons_f19) def cons_f20(m): return IntegerQ(m) cons20 = CustomConstraint(cons_f20) def cons_f21(m): return Not(IntegerQ(m)) cons21 = CustomConstraint(cons_f21) def cons_f22(n): return PositiveIntegerQ(n + S(1)/2) cons22 = CustomConstraint(cons_f22) def cons_f23(m, n): return IntegerQ(m + n) cons23 = CustomConstraint(cons_f23) def cons_f24(n): return NegativeIntegerQ(n + S(-1)/2) cons24 = CustomConstraint(cons_f24) def cons_f25(n): return Not(IntegerQ(n)) cons25 = CustomConstraint(cons_f25) def cons_f26(m, n): return Not(IntegerQ(m + n)) cons26 = CustomConstraint(cons_f26) def cons_f27(a, b, c, d): return ZeroQ(-a*d + b*c) cons27 = CustomConstraint(cons_f27) def cons_f28(a, b, c, d, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(Not(IntegerQ(n)), SimplerQ(c + d*x, a + b*x)) cons28 = CustomConstraint(cons_f28) def cons_f29(d, x): return FreeQ(d, x) cons29 = CustomConstraint(cons_f29) def cons_f30(b, d): return PositiveQ(b/d) cons30 = CustomConstraint(cons_f30) def cons_f31(m, n): return Not(Or(IntegerQ(m), IntegerQ(n))) cons31 = CustomConstraint(cons_f31) def cons_f32(b, d, m, n): return Not(Or(IntegerQ(m), IntegerQ(n), PositiveQ(b/d))) cons32 = CustomConstraint(cons_f32) def cons_f33(m): return RationalQ(m) cons33 = CustomConstraint(cons_f33) def cons_f34(m): return LessEqual(m, S(-1)) cons34 = CustomConstraint(cons_f34) def cons_f35(A, B, C, a, b): return ZeroQ(A*b**S(2) - B*a*b + C*a**S(2)) cons35 = CustomConstraint(cons_f35) def cons_f36(A, x): return FreeQ(A, x) cons36 = CustomConstraint(cons_f36) def cons_f37(B, x): return FreeQ(B, x) cons37 = CustomConstraint(cons_f37) def cons_f38(C, x): return FreeQ(C, x) cons38 = CustomConstraint(cons_f38) def cons_f39(n, q): return ZeroQ(n + q) cons39 = CustomConstraint(cons_f39) def cons_f40(p): return IntegerQ(p) cons40 = CustomConstraint(cons_f40) def cons_f41(a, b, c, d): return ZeroQ(a*c - b*d) cons41 = CustomConstraint(cons_f41) def cons_f42(m, n): return Not(And(IntegerQ(m), NegQ(n))) cons42 = CustomConstraint(cons_f42) def cons_f43(m, p): return ZeroQ(m + p) cons43 = CustomConstraint(cons_f43) def cons_f44(a, b, c, d): return ZeroQ(a**S(2)*d + b**S(2)*c) cons44 = CustomConstraint(cons_f44) def cons_f45(a): return PositiveQ(a) cons45 = CustomConstraint(cons_f45) def cons_f46(d): return NegativeQ(d) cons46 = CustomConstraint(cons_f46) def cons_f47(a, b, c): return ZeroQ(-S(4)*a*c + b**S(2)) cons47 = CustomConstraint(cons_f47) def cons_f48(n, n2): return ZeroQ(-S(2)*n + n2) cons48 = CustomConstraint(cons_f48) def cons_f49(b, c, d, e): return ZeroQ(-b*e + S(2)*c*d) cons49 = CustomConstraint(cons_f49) def cons_f50(e, x): return FreeQ(e, x) cons50 = CustomConstraint(cons_f50) def cons_f51(p, q): return PosQ(-p + q) cons51 = CustomConstraint(cons_f51) def cons_f52(q, x): return FreeQ(q, x) cons52 = CustomConstraint(cons_f52) def cons_f53(p, r): return PosQ(-p + r) cons53 = CustomConstraint(cons_f53) def cons_f54(r, x): return FreeQ(r, x) cons54 = CustomConstraint(cons_f54) def cons_f55(m, n): return ZeroQ(m - n + S(1)) cons55 = CustomConstraint(cons_f55) def cons_f56(p): return NonzeroQ(p + S(1)) cons56 = CustomConstraint(cons_f56) def cons_f57(a1, a2, b1, b2): return ZeroQ(a1*b2 + a2*b1) cons57 = CustomConstraint(cons_f57) def cons_f58(m, n): return ZeroQ(m - S(2)*n + S(1)) cons58 = CustomConstraint(cons_f58) def cons_f59(a1, x): return FreeQ(a1, x) cons59 = CustomConstraint(cons_f59) def cons_f60(b1, x): return FreeQ(b1, x) cons60 = CustomConstraint(cons_f60) def cons_f61(a2, x): return FreeQ(a2, x) cons61 = CustomConstraint(cons_f61) def cons_f62(b2, x): return FreeQ(b2, x) cons62 = CustomConstraint(cons_f62) def cons_f63(Qm, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(Qm, x) cons63 = CustomConstraint(cons_f63) def cons_f64(m): return PositiveIntegerQ(m) cons64 = CustomConstraint(cons_f64) def cons_f65(p): return NegativeIntegerQ(p) cons65 = CustomConstraint(cons_f65) def cons_f66(Pq, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(Pq, x) cons66 = CustomConstraint(cons_f66) def cons_f67(Qr, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(Qr, x) cons67 = CustomConstraint(cons_f67) def cons_f68(m): return NonzeroQ(m + S(1)) cons68 = CustomConstraint(cons_f68) def cons_f69(a, b, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b), x) cons69 = CustomConstraint(cons_f69) def cons_f70(u, x): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(u, x) cons70 = CustomConstraint(cons_f70) def cons_f71(u, x): if isinstance(x, (int, Integer, float, Float)): return False return NonzeroQ(u - x) cons71 = CustomConstraint(cons_f71) def cons_f72(a, b, c, d): return ZeroQ(a*d + b*c) cons72 = CustomConstraint(cons_f72) def cons_f73(a, b, c, d): return NonzeroQ(-a*d + b*c) cons73 = CustomConstraint(cons_f73) def cons_f74(m, n): return ZeroQ(m + n + S(2)) cons74 = CustomConstraint(cons_f74) def cons_f75(m): return PositiveIntegerQ(m + S(1)/2) cons75 = CustomConstraint(cons_f75) def cons_f76(m): return NegativeIntegerQ(m + S(3)/2) cons76 = CustomConstraint(cons_f76) def cons_f77(a, c, m): return Or(IntegerQ(m), And(PositiveQ(a), PositiveQ(c))) cons77 = CustomConstraint(cons_f77) def cons_f78(a, c): return ZeroQ(a + c) cons78 = CustomConstraint(cons_f78) def cons_f79(m): return Not(IntegerQ(S(2)*m)) cons79 = CustomConstraint(cons_f79) def cons_f80(a, b, c, d): return PosQ(b*d/(a*c)) cons80 = CustomConstraint(cons_f80) def cons_f81(m): return IntegerQ(m + S(1)/2) cons81 = CustomConstraint(cons_f81) def cons_f82(n): return IntegerQ(n + S(1)/2) cons82 = CustomConstraint(cons_f82) def cons_f83(m, n): return Less(S(0), m, n) cons83 = CustomConstraint(cons_f83) def cons_f84(m, n): return Less(m, n, S(0)) cons84 = CustomConstraint(cons_f84) def cons_f85(c, m, n): return Or(Not(IntegerQ(n)), And(ZeroQ(c), LessEqual(S(7)*m + S(4)*n, S(0))), Less(S(9)*m + S(5)*n + S(5), S(0)), Greater(m + n + S(2), S(0))) cons85 = CustomConstraint(cons_f85) def cons_f86(m): return NegativeIntegerQ(m) cons86 = CustomConstraint(cons_f86) def cons_f87(n): return IntegerQ(n) cons87 = CustomConstraint(cons_f87) def cons_f88(m, n): return Not(And(PositiveIntegerQ(n), Less(m + n + S(2), S(0)))) cons88 = CustomConstraint(cons_f88) def cons_f89(n): return RationalQ(n) cons89 = CustomConstraint(cons_f89) def cons_f90(n): return Greater(n, S(0)) cons90 = CustomConstraint(cons_f90) def cons_f91(n): return Less(n, S(-1)) cons91 = CustomConstraint(cons_f91) def cons_f92(a, b, c, d): return PosQ((-a*d + b*c)/b) cons92 = CustomConstraint(cons_f92) def cons_f93(a, b, c, d): return NegQ((-a*d + b*c)/b) cons93 = CustomConstraint(cons_f93) def cons_f94(n): return Less(S(-1), n, S(0)) cons94 = CustomConstraint(cons_f94) def cons_f95(m, n): return RationalQ(m, n) cons95 = CustomConstraint(cons_f95) def cons_f96(m): return Less(m, S(-1)) cons96 = CustomConstraint(cons_f96) def cons_f97(m, n): return Not(And(IntegerQ(n), Not(IntegerQ(m)))) cons97 = CustomConstraint(cons_f97) def cons_f98(m, n): return Not(And(IntegerQ(m + n), LessEqual(m + n + S(2), S(0)), Or(FractionQ(m), GreaterEqual(m + S(2)*n + S(1), S(0))))) cons98 = CustomConstraint(cons_f98) def cons_f99(a, b, c, d, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return IntLinearcQ(a, b, c, d, m, n, x) cons99 = CustomConstraint(cons_f99) def cons_f100(a, c, m, n): return Not(And(Less(n, S(-1)), Or(ZeroQ(a), And(NonzeroQ(c), Less(m, n), IntegerQ(n))))) cons100 = CustomConstraint(cons_f100) def cons_f101(m, n): return Unequal(m + n + S(1), S(0)) cons101 = CustomConstraint(cons_f101) def cons_f102(m, n): return Not(And(PositiveIntegerQ(m), Or(Not(IntegerQ(n)), Less(S(0), m, n)))) cons102 = CustomConstraint(cons_f102) def cons_f103(m, n): return Not(And(IntegerQ(m + n), Less(m + n + S(2), S(0)))) cons103 = CustomConstraint(cons_f103) def cons_f104(b, d): return ZeroQ(b + d) cons104 = CustomConstraint(cons_f104) def cons_f105(a, c): return PositiveQ(a + c) cons105 = CustomConstraint(cons_f105) def cons_f106(a, b, c, d): return PositiveQ(-a*d + b*c) cons106 = CustomConstraint(cons_f106) def cons_f107(b): return PositiveQ(b) cons107 = CustomConstraint(cons_f107) def cons_f108(b, d): return ZeroQ(b - d) cons108 = CustomConstraint(cons_f108) def cons_f109(m): return Less(S(-1), m, S(0)) cons109 = CustomConstraint(cons_f109) def cons_f110(m): return LessEqual(S(3), Denominator(m), S(4)) cons110 = CustomConstraint(cons_f110) def cons_f111(b, d): return PosQ(d/b) cons111 = CustomConstraint(cons_f111) def cons_f112(b, d): return NegQ(d/b) cons112 = CustomConstraint(cons_f112) def cons_f113(m, n): return Equal(m + n + S(1), S(0)) cons113 = CustomConstraint(cons_f113) def cons_f114(m, n): return LessEqual(Denominator(n), Denominator(m)) cons114 = CustomConstraint(cons_f114) def cons_f115(m, n): return NegativeIntegerQ(m + n + S(2)) cons115 = CustomConstraint(cons_f115) def cons_f116(m, n): return Or(SumSimplerQ(m, S(1)), Not(SumSimplerQ(n, S(1)))) cons116 = CustomConstraint(cons_f116) def cons_f117(b, c, d, n): return Or(IntegerQ(n), And(PositiveQ(c), Not(And(ZeroQ(n + S(1)/2), ZeroQ(c**S(2) - d**S(2)), PositiveQ(-d/(b*c)))))) cons117 = CustomConstraint(cons_f117) def cons_f118(b, c, d, m): return Or(IntegerQ(m), PositiveQ(-d/(b*c))) cons118 = CustomConstraint(cons_f118) def cons_f119(c): return Not(PositiveQ(c)) cons119 = CustomConstraint(cons_f119) def cons_f120(b, c, d): return Not(PositiveQ(-d/(b*c))) cons120 = CustomConstraint(cons_f120) def cons_f121(c, d, m, n): return Or(And(RationalQ(m), Not(And(ZeroQ(n + S(1)/2), ZeroQ(c**S(2) - d**S(2))))), Not(RationalQ(n))) cons121 = CustomConstraint(cons_f121) def cons_f122(a, b, c, d): return PositiveQ(b/(-a*d + b*c)) cons122 = CustomConstraint(cons_f122) def cons_f123(a, b, c, d, m, n): return Or(RationalQ(m), Not(And(RationalQ(n), PositiveQ(-d/(-a*d + b*c))))) cons123 = CustomConstraint(cons_f123) def cons_f124(m, n): return Or(RationalQ(m), Not(SimplerQ(n + S(1), m + S(1)))) cons124 = CustomConstraint(cons_f124) def cons_f125(u, x): if isinstance(x, (int, Integer, float, Float)): return False return NonzeroQ(Coefficient(u, x, S(0))) cons125 = CustomConstraint(cons_f125) def cons_f126(m, n): return ZeroQ(m - n) cons126 = CustomConstraint(cons_f126) def cons_f127(f, x): return FreeQ(f, x) cons127 = CustomConstraint(cons_f127) def cons_f128(n, p): return NonzeroQ(n + p + S(2)) cons128 = CustomConstraint(cons_f128) def cons_f129(a, b, c, d, e, f, n, p): return ZeroQ(a*d*f*(n + p + S(2)) - b*(c*f*(p + S(1)) + d*e*(n + S(1)))) cons129 = CustomConstraint(cons_f129) def cons_f130(p): return PositiveIntegerQ(p) cons130 = CustomConstraint(cons_f130) def cons_f131(a, b, e, f): return ZeroQ(a*f + b*e) cons131 = CustomConstraint(cons_f131) def cons_f132(n, p): return Not(And(NegativeIntegerQ(n + p + S(2)), Greater(n + S(2)*p, S(0)))) cons132 = CustomConstraint(cons_f132) def cons_f133(n, p): return Or(NonzeroQ(n + S(1)), Equal(p, S(1))) cons133 = CustomConstraint(cons_f133) def cons_f134(a, b, e, f): return NonzeroQ(a*f + b*e) cons134 = CustomConstraint(cons_f134) def cons_f135(a, b, d, e, f, n, p): return Or(Not(IntegerQ(n)), Less(S(5)*n + S(9)*p, S(0)), GreaterEqual(n + p + S(1), S(0)), And(GreaterEqual(n + p + S(2), S(0)), RationalQ(a, b, d, e, f))) cons135 = CustomConstraint(cons_f135) def cons_f136(a, b, c, d, e, f, n, p): return Or(NegativeIntegerQ(n, p), ZeroQ(p + S(-1)), And(PositiveIntegerQ(p), Or(Not(IntegerQ(n)), LessEqual(S(5)*n + S(9)*p + S(10), S(0)), GreaterEqual(n + p + S(1), S(0)), And(GreaterEqual(n + p + S(2), S(0)), RationalQ(a, b, c, d, e, f))))) cons136 = CustomConstraint(cons_f136) def cons_f137(n, p): return ZeroQ(n + p + S(2)) cons137 = CustomConstraint(cons_f137) def cons_f138(n, p): return Not(And(SumSimplerQ(n, S(1)), Not(SumSimplerQ(p, S(1))))) cons138 = CustomConstraint(cons_f138) def cons_f139(p): return Less(p, S(-1)) cons139 = CustomConstraint(cons_f139) def cons_f140(c, e, n, p): return Or(Not(And(RationalQ(n), Less(n, S(-1)))), IntegerQ(p), Not(Or(IntegerQ(n), Not(Or(ZeroQ(e), Not(Or(ZeroQ(c), Less(p, n)))))))) cons140 = CustomConstraint(cons_f140) def cons_f141(p): return SumSimplerQ(p, S(1)) cons141 = CustomConstraint(cons_f141) def cons_f142(n, p): return NonzeroQ(n + p + S(3)) cons142 = CustomConstraint(cons_f142) def cons_f143(a, b, c, d, e, f, n, p): return ZeroQ(-b*(c*f*(p + S(1)) + d*e*(n + S(1)))*(a*d*f*(n + p + S(4)) - b*(c*f*(p + S(2)) + d*e*(n + S(2)))) + d*f*(a**S(2)*d*f*(n + p + S(3)) - b*(a*(c*f*(p + S(1)) + d*e*(n + S(1))) + b*c*e))*(n + p + S(2))) cons143 = CustomConstraint(cons_f143) def cons_f144(m, n): return ZeroQ(m - n + S(-1)) cons144 = CustomConstraint(cons_f144) def cons_f145(m): return Not(PositiveIntegerQ(m)) cons145 = CustomConstraint(cons_f145) def cons_f146(m, n, p): return NonzeroQ(m + n + p + S(2)) cons146 = CustomConstraint(cons_f146) def cons_f147(p): return Less(S(0), p, S(1)) cons147 = CustomConstraint(cons_f147) def cons_f148(p): return Greater(p, S(1)) cons148 = CustomConstraint(cons_f148) def cons_f149(p): return Not(IntegerQ(p)) cons149 = CustomConstraint(cons_f149) def cons_f150(n): return PositiveIntegerQ(n) cons150 = CustomConstraint(cons_f150) def cons_f151(p): return FractionQ(p) cons151 = CustomConstraint(cons_f151) def cons_f152(m, n): return IntegersQ(m, n) cons152 = CustomConstraint(cons_f152) def cons_f153(m, n, p): return Or(IntegerQ(p), And(Greater(m, S(0)), GreaterEqual(n, S(-1)))) cons153 = CustomConstraint(cons_f153) def cons_f154(n, p): return Or(And(RationalQ(n), Less(n, S(-1))), And(ZeroQ(n + p + S(3)), NonzeroQ(n + S(1)), Or(SumSimplerQ(n, S(1)), Not(SumSimplerQ(p, S(1)))))) cons154 = CustomConstraint(cons_f154) def cons_f155(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f), x) cons155 = CustomConstraint(cons_f155) def cons_f156(a, b, c, d, e, f): return ZeroQ(S(2)*b*d*e - f*(a*d + b*c)) cons156 = CustomConstraint(cons_f156) def cons_f157(m, n): return ZeroQ(m + n + S(1)) cons157 = CustomConstraint(cons_f157) def cons_f158(a, b, c, d, x): if isinstance(x, (int, Integer, float, Float)): return False return SimplerQ(a + b*x, c + d*x) cons158 = CustomConstraint(cons_f158) def cons_f159(m, n, p): return ZeroQ(m + n + p + S(2)) cons159 = CustomConstraint(cons_f159) def cons_f160(m, p): return Not(And(SumSimplerQ(p, S(1)), Not(SumSimplerQ(m, S(1))))) cons160 = CustomConstraint(cons_f160) def cons_f161(m, n, p): return ZeroQ(m + n + p + S(3)) cons161 = CustomConstraint(cons_f161) def cons_f162(a, b, c, d, e, f, m, n, p): return ZeroQ(a*d*f*(m + S(1)) + b*c*f*(n + S(1)) + b*d*e*(p + S(1))) cons162 = CustomConstraint(cons_f162) def cons_f163(m): return Or(And(RationalQ(m), Less(m, S(-1))), SumSimplerQ(m, S(1))) cons163 = CustomConstraint(cons_f163) def cons_f164(m, n, p): return RationalQ(m, n, p) cons164 = CustomConstraint(cons_f164) def cons_f165(p): return Greater(p, S(0)) cons165 = CustomConstraint(cons_f165) def cons_f166(m, n, p): return Or(IntegersQ(S(2)*m, S(2)*n, S(2)*p), IntegersQ(m, n + p), IntegersQ(p, m + n)) cons166 = CustomConstraint(cons_f166) def cons_f167(n): return Greater(n, S(1)) cons167 = CustomConstraint(cons_f167) def cons_f168(m): return Greater(m, S(1)) cons168 = CustomConstraint(cons_f168) def cons_f169(m, n, p): return NonzeroQ(m + n + p + S(1)) cons169 = CustomConstraint(cons_f169) def cons_f170(m): return Greater(m, S(0)) cons170 = CustomConstraint(cons_f170) def cons_f171(m, n, p): return Or(IntegersQ(S(2)*m, S(2)*n, S(2)*p), Or(IntegersQ(m, n + p), IntegersQ(p, m + n))) cons171 = CustomConstraint(cons_f171) def cons_f172(m, n, p): return IntegersQ(S(2)*m, S(2)*n, S(2)*p) cons172 = CustomConstraint(cons_f172) def cons_f173(n, p): return Or(IntegerQ(n), IntegersQ(S(2)*n, S(2)*p)) cons173 = CustomConstraint(cons_f173) def cons_f174(m, n): return PositiveIntegerQ(m + n + S(1)) cons174 = CustomConstraint(cons_f174) def cons_f175(m, n): return Or(And(RationalQ(m), Greater(m, S(0))), And(Not(RationalQ(m)), Or(SumSimplerQ(m, S(-1)), Not(SumSimplerQ(n, S(-1)))))) cons175 = CustomConstraint(cons_f175) def cons_f176(c, d, e, f): return PositiveQ(-f/(-c*f + d*e)) cons176 = CustomConstraint(cons_f176) def cons_f177(c, d, e, f): return Not(PositiveQ(-f/(-c*f + d*e))) cons177 = CustomConstraint(cons_f177) def cons_f178(c, d, e, f): return NonzeroQ(-c*f + d*e) cons178 = CustomConstraint(cons_f178) def cons_f179(c): return PositiveQ(c) cons179 = CustomConstraint(cons_f179) def cons_f180(e): return PositiveQ(e) cons180 = CustomConstraint(cons_f180) def cons_f181(b, d): return Not(NegativeQ(-b/d)) cons181 = CustomConstraint(cons_f181) def cons_f182(b, d): return NegativeQ(-b/d) cons182 = CustomConstraint(cons_f182) def cons_f183(c, e): return Not(And(PositiveQ(c), PositiveQ(e))) cons183 = CustomConstraint(cons_f183) def cons_f184(a, b, e, f): return PositiveQ(b/(-a*f + b*e)) cons184 = CustomConstraint(cons_f184) def cons_f185(a, b, c, d): return Not(NegativeQ(-(-a*d + b*c)/d)) cons185 = CustomConstraint(cons_f185) def cons_f186(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(SimplerQ(c + d*x, a + b*x), PositiveQ(-d/(-a*d + b*c)), PositiveQ(d/(-c*f + d*e)), Not(NegativeQ((-a*d + b*c)/b)))) cons186 = CustomConstraint(cons_f186) def cons_f187(a, b, c, d, e, f): return Not(And(PositiveQ(b/(-a*d + b*c)), PositiveQ(b/(-a*f + b*e)))) cons187 = CustomConstraint(cons_f187) def cons_f188(b, d, f): return Or(PositiveQ(-b/d), NegativeQ(-b/f)) cons188 = CustomConstraint(cons_f188) def cons_f189(b, d, f): return Or(PosQ(-b/d), NegQ(-b/f)) cons189 = CustomConstraint(cons_f189) def cons_f190(a, b, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return SimplerQ(a + b*x, e + f*x) cons190 = CustomConstraint(cons_f190) def cons_f191(a, b, c, d, e, f): return Or(PositiveQ(-(-a*d + b*c)/d), NegativeQ(-(-a*f + b*e)/f)) cons191 = CustomConstraint(cons_f191) def cons_f192(a, b, c, d, e, f): return Or(PosQ(-(-a*d + b*c)/d), NegQ(-(-a*f + b*e)/f)) cons192 = CustomConstraint(cons_f192) def cons_f193(a, b, c, d, e, f): return ZeroQ(-a*d*f - b*c*f + S(2)*b*d*e) cons193 = CustomConstraint(cons_f193) def cons_f194(m, n): return PositiveIntegerQ(m - n) cons194 = CustomConstraint(cons_f194) def cons_f195(m, n): return Or(PositiveIntegerQ(m), NegativeIntegerQ(m, n)) cons195 = CustomConstraint(cons_f195) def cons_f196(m, n, p): return NegativeIntegerQ(m + n + p + S(2)) cons196 = CustomConstraint(cons_f196) def cons_f197(m, n, p): return Or(SumSimplerQ(m, S(1)), And(Not(And(NonzeroQ(n + S(1)), SumSimplerQ(n, S(1)))), Not(And(NonzeroQ(p + S(1)), SumSimplerQ(p, S(1)))))) cons197 = CustomConstraint(cons_f197) def cons_f198(n): return NegativeIntegerQ(n) cons198 = CustomConstraint(cons_f198) def cons_f199(e, p): return Or(IntegerQ(p), PositiveQ(e)) cons199 = CustomConstraint(cons_f199) def cons_f200(b, c, d): return PositiveQ(-d/(b*c)) cons200 = CustomConstraint(cons_f200) def cons_f201(c, d, e, f, p): return Or(IntegerQ(p), PositiveQ(d/(-c*f + d*e))) cons201 = CustomConstraint(cons_f201) def cons_f202(a, b, c, d, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(PositiveQ(d/(a*d - b*c)), SimplerQ(c + d*x, a + b*x))) cons202 = CustomConstraint(cons_f202) def cons_f203(a, b, c, d): return Not(PositiveQ(b/(-a*d + b*c))) cons203 = CustomConstraint(cons_f203) def cons_f204(a, b, c, d, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(SimplerQ(c + d*x, a + b*x)) cons204 = CustomConstraint(cons_f204) def cons_f205(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(PositiveQ(d/(a*d - b*c)), PositiveQ(d/(-c*f + d*e)), SimplerQ(c + d*x, a + b*x))) cons205 = CustomConstraint(cons_f205) def cons_f206(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(PositiveQ(f/(a*f - b*e)), PositiveQ(f/(c*f - d*e)), SimplerQ(e + f*x, a + b*x))) cons206 = CustomConstraint(cons_f206) def cons_f207(a, b, e, f): return Not(PositiveQ(b/(-a*f + b*e))) cons207 = CustomConstraint(cons_f207) def cons_f208(a, b, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(SimplerQ(e + f*x, a + b*x)) cons208 = CustomConstraint(cons_f208) def cons_f209(m, n): return Or(PositiveIntegerQ(m), IntegersQ(m, n)) cons209 = CustomConstraint(cons_f209) def cons_f210(g, x): return FreeQ(g, x) cons210 = CustomConstraint(cons_f210) def cons_f211(h, x): return FreeQ(h, x) cons211 = CustomConstraint(cons_f211) def cons_f212(m, n): return Not(And(SumSimplerQ(n, S(1)), Not(SumSimplerQ(m, S(1))))) cons212 = CustomConstraint(cons_f212) def cons_f213(m, n): return Or(And(RationalQ(m), Less(m, S(-2))), And(ZeroQ(m + n + S(3)), Not(And(RationalQ(n), Less(n, S(-2)))))) cons213 = CustomConstraint(cons_f213) def cons_f214(m): return Or(And(RationalQ(m), Inequality(S(-2), LessEqual, m, Less, S(-1))), SumSimplerQ(m, S(1))) cons214 = CustomConstraint(cons_f214) def cons_f215(m, n): return NonzeroQ(m + n + S(3)) cons215 = CustomConstraint(cons_f215) def cons_f216(m, n): return NonzeroQ(m + n + S(2)) cons216 = CustomConstraint(cons_f216) def cons_f217(m, n, p): return Or(IntegersQ(m, n, p), PositiveIntegerQ(n, p)) cons217 = CustomConstraint(cons_f217) def cons_f218(a, b, c, d, e, f, g, h, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, h), x) cons218 = CustomConstraint(cons_f218) def cons_f219(a, b, c, d, e, f, g, h, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, h, n, p), x) cons219 = CustomConstraint(cons_f219) def cons_f220(c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return SimplerQ(c + d*x, e + f*x) cons220 = CustomConstraint(cons_f220) def cons_f221(m, n, p): return Or(SumSimplerQ(m, S(1)), And(Not(SumSimplerQ(n, S(1))), Not(SumSimplerQ(p, S(1))))) cons221 = CustomConstraint(cons_f221) def cons_f222(p, q): return IntegersQ(p, q) cons222 = CustomConstraint(cons_f222) def cons_f223(q): return PositiveIntegerQ(q) cons223 = CustomConstraint(cons_f223) def cons_f224(a, b, c, d, e, f, g, h, m, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, h, m, n, p, q), x) cons224 = CustomConstraint(cons_f224) def cons_f225(a, b, c, d, e, f, g, h, i, m, n, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, h, i, m, n, p, q, r), x) cons225 = CustomConstraint(cons_f225) def cons_f226(i, x): return FreeQ(i, x) cons226 = CustomConstraint(cons_f226) def cons_f227(p): return NonzeroQ(S(2)*p + S(1)) cons227 = CustomConstraint(cons_f227) def cons_f228(a, b, c): return NonzeroQ(-S(4)*a*c + b**S(2)) cons228 = CustomConstraint(cons_f228) def cons_f229(a, b, c): return PerfectSquareQ(-S(4)*a*c + b**S(2)) cons229 = CustomConstraint(cons_f229) def cons_f230(a, b, c): return Not(PerfectSquareQ(-S(4)*a*c + b**S(2))) cons230 = CustomConstraint(cons_f230) def cons_f231(p): return IntegerQ(S(4)*p) cons231 = CustomConstraint(cons_f231) def cons_f232(p): return Unequal(p, S(-3)/2) cons232 = CustomConstraint(cons_f232) def cons_f233(a, b, c): return PosQ(-S(4)*a*c + b**S(2)) cons233 = CustomConstraint(cons_f233) def cons_f234(a, b, c): return PositiveQ(S(4)*a - b**S(2)/c) cons234 = CustomConstraint(cons_f234) def cons_f235(b, c, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, c), x) cons235 = CustomConstraint(cons_f235) def cons_f236(p): return LessEqual(S(3), Denominator(p), S(4)) cons236 = CustomConstraint(cons_f236) def cons_f237(p): return Not(IntegerQ(S(4)*p)) cons237 = CustomConstraint(cons_f237) def cons_f238(m): return IntegerQ(m/S(2) + S(1)/2) cons238 = CustomConstraint(cons_f238) def cons_f239(m, p): return ZeroQ(m + S(2)*p + S(1)) cons239 = CustomConstraint(cons_f239) def cons_f240(m, p): return NonzeroQ(m + S(2)*p + S(1)) cons240 = CustomConstraint(cons_f240) def cons_f241(b, c, d, e): return NonzeroQ(-b*e + S(2)*c*d) cons241 = CustomConstraint(cons_f241) def cons_f242(m, p): return ZeroQ(m + S(2)*p + S(2)) cons242 = CustomConstraint(cons_f242) def cons_f243(m): return NonzeroQ(m + S(2)) cons243 = CustomConstraint(cons_f243) def cons_f244(m, p): return ZeroQ(m + S(2)*p + S(3)) cons244 = CustomConstraint(cons_f244) def cons_f245(p): return NonzeroQ(p + S(3)/2) cons245 = CustomConstraint(cons_f245) def cons_f246(m, p): return RationalQ(m, p) cons246 = CustomConstraint(cons_f246) def cons_f247(m): return Inequality(S(-2), LessEqual, m, Less, S(-1)) cons247 = CustomConstraint(cons_f247) def cons_f248(p): return IntegerQ(S(2)*p) cons248 = CustomConstraint(cons_f248) def cons_f249(m): return Less(m, S(-2)) cons249 = CustomConstraint(cons_f249) def cons_f250(m, p): return Not(And(NegativeIntegerQ(m + S(2)*p + S(3)), Greater(m + S(3)*p + S(3), S(0)))) cons250 = CustomConstraint(cons_f250) def cons_f251(m, p): return NonzeroQ(m + S(2)*p) cons251 = CustomConstraint(cons_f251) def cons_f252(m): return Not(And(RationalQ(m), Less(m, S(-2)))) cons252 = CustomConstraint(cons_f252) def cons_f253(m, p): return Not(And(IntegerQ(m), Less(S(0), m, S(2)*p))) cons253 = CustomConstraint(cons_f253) def cons_f254(m): return Inequality(S(0), Less, m, LessEqual, S(1)) cons254 = CustomConstraint(cons_f254) def cons_f255(m, p): return NonzeroQ(m + p + S(1)) cons255 = CustomConstraint(cons_f255) def cons_f256(m, p): return Or(Not(RationalQ(p)), Inequality(S(-1), LessEqual, p, Less, S(0)), And(IntegerQ(m), Less(S(0), m, S(2)*p)), And(Equal(m, S(1)/2), Less(p, S(0)))) cons256 = CustomConstraint(cons_f256) def cons_f257(m, p): return Or(IntegerQ(m), IntegerQ(S(2)*p)) cons257 = CustomConstraint(cons_f257) def cons_f258(a, b, c, d, e): return ZeroQ(a*e**S(2) - b*d*e + c*d**S(2)) cons258 = CustomConstraint(cons_f258) def cons_f259(a, c, d, e): return ZeroQ(a*e**S(2) + c*d**S(2)) cons259 = CustomConstraint(cons_f259) def cons_f260(a, d, m, p): return Or(IntegerQ(p), And(PositiveQ(a), PositiveQ(d), IntegerQ(m + p))) cons260 = CustomConstraint(cons_f260) def cons_f261(m, p): return Or(Less(S(0), -m, p), Less(p, -m, S(0))) cons261 = CustomConstraint(cons_f261) def cons_f262(m): return Unequal(m, S(2)) cons262 = CustomConstraint(cons_f262) def cons_f263(m): return Unequal(m, S(-1)) cons263 = CustomConstraint(cons_f263) def cons_f264(m, p): return PositiveIntegerQ(m + p) cons264 = CustomConstraint(cons_f264) def cons_f265(m, p): return NegativeIntegerQ(m + S(2)*p + S(2)) cons265 = CustomConstraint(cons_f265) def cons_f266(m, p): return Or(Less(m, S(-2)), ZeroQ(m + S(2)*p + S(1))) cons266 = CustomConstraint(cons_f266) def cons_f267(m, p): return Or(Inequality(S(-2), LessEqual, m, Less, S(0)), Equal(m + p + S(1), S(0))) cons267 = CustomConstraint(cons_f267) def cons_f268(m): return GreaterEqual(m, S(1)) cons268 = CustomConstraint(cons_f268) def cons_f269(m): return Less(m, S(0)) cons269 = CustomConstraint(cons_f269) def cons_f270(d): return PositiveQ(d) cons270 = CustomConstraint(cons_f270) def cons_f271(m, p): return Not(And(ZeroQ(m + S(-3)), Unequal(p, S(1)))) cons271 = CustomConstraint(cons_f271) def cons_f272(m, p): return NonzeroQ(m + S(2)*p + S(3)) cons272 = CustomConstraint(cons_f272) def cons_f273(m, p): return Not(And(EvenQ(m), Less(m + S(2)*p + S(3), S(0)))) cons273 = CustomConstraint(cons_f273) def cons_f274(m): return Not(And(RationalQ(m), Less(m, S(-1)))) cons274 = CustomConstraint(cons_f274) def cons_f275(m, p): return Not(And(PositiveIntegerQ(m/S(2) + S(-1)/2), Or(Not(IntegerQ(p)), Less(m, S(2)*p)))) cons275 = CustomConstraint(cons_f275) def cons_f276(m): return Not(And(RationalQ(m), Greater(m, S(1)))) cons276 = CustomConstraint(cons_f276) def cons_f277(a, b, c): return NegativeQ(c/(-S(4)*a*c + b**S(2))) cons277 = CustomConstraint(cons_f277) def cons_f278(m): return EqQ(m**S(2), S(1)/4) cons278 = CustomConstraint(cons_f278) def cons_f279(m, p): return Or(IntegerQ(S(2)*p), And(IntegerQ(m), RationalQ(p)), OddQ(m)) cons279 = CustomConstraint(cons_f279) def cons_f280(m, p): return Or(IntegerQ(S(2)*p), And(IntegerQ(m), RationalQ(p)), IntegerQ(m/S(2) + p + S(3)/2)) cons280 = CustomConstraint(cons_f280) def cons_f281(a, b, c, d, e): return NonzeroQ(a*e**S(2) - b*d*e + c*d**S(2)) cons281 = CustomConstraint(cons_f281) def cons_f282(a, c, d, e): return NonzeroQ(a*e**S(2) + c*d**S(2)) cons282 = CustomConstraint(cons_f282) def cons_f283(m, p): return Not(And(ZeroQ(m + S(-1)), Greater(p, S(1)))) cons283 = CustomConstraint(cons_f283) def cons_f284(a, b, c): return NiceSqrtQ(-S(4)*a*c + b**S(2)) cons284 = CustomConstraint(cons_f284) def cons_f285(a, c): return NiceSqrtQ(-a*c) cons285 = CustomConstraint(cons_f285) def cons_f286(a, b, c): return Not(NiceSqrtQ(-S(4)*a*c + b**S(2))) cons286 = CustomConstraint(cons_f286) def cons_f287(a, c): return Not(NiceSqrtQ(-a*c)) cons287 = CustomConstraint(cons_f287) def cons_f288(d, m): return Or(NonzeroQ(d), Greater(m, S(2))) cons288 = CustomConstraint(cons_f288) def cons_f289(p): return Not(And(RationalQ(p), LessEqual(p, S(-1)))) cons289 = CustomConstraint(cons_f289) def cons_f290(a, b, d, e): return ZeroQ(a*e + b*d) cons290 = CustomConstraint(cons_f290) def cons_f291(b, c, d, e): return ZeroQ(b*e + c*d) cons291 = CustomConstraint(cons_f291) def cons_f292(m, p): return PositiveIntegerQ(m - p + S(1)) cons292 = CustomConstraint(cons_f292) def cons_f293(b, c, d, e): return NonzeroQ(-b*e + c*d) cons293 = CustomConstraint(cons_f293) def cons_f294(m): return Equal(m**S(2), S(1)/4) cons294 = CustomConstraint(cons_f294) def cons_f295(c): return NegativeQ(c) cons295 = CustomConstraint(cons_f295) def cons_f296(b): return RationalQ(b) cons296 = CustomConstraint(cons_f296) def cons_f297(m): return ZeroQ(m**S(2) + S(-1)/4) cons297 = CustomConstraint(cons_f297) def cons_f298(m, p): return Equal(m + S(2)*p + S(2), S(0)) cons298 = CustomConstraint(cons_f298) def cons_f299(a, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, d, e), x) cons299 = CustomConstraint(cons_f299) def cons_f300(m, p): return Or(IntegerQ(p), And(RationalQ(m), Less(m, S(-1)))) cons300 = CustomConstraint(cons_f300) def cons_f301(m, p): return Not(NegativeIntegerQ(m + S(2)*p + S(1))) cons301 = CustomConstraint(cons_f301) def cons_f302(a, b, c, d, e, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return IntQuadraticQ(a, b, c, d, e, m, p, x) cons302 = CustomConstraint(cons_f302) def cons_f303(a, c, d, e, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return IntQuadraticQ(a, S(0), c, d, e, m, p, x) cons303 = CustomConstraint(cons_f303) def cons_f304(m): return Or(Not(RationalQ(m)), Less(m, S(1))) cons304 = CustomConstraint(cons_f304) def cons_f305(m, p): return Not(NegativeIntegerQ(m + S(2)*p)) cons305 = CustomConstraint(cons_f305) def cons_f306(m, p): return Or(Less(m, S(1)), And(NegativeIntegerQ(m + S(2)*p + S(3)), Unequal(m, S(2)))) cons306 = CustomConstraint(cons_f306) def cons_f307(m): return If(RationalQ(m), Greater(m, S(1)), SumSimplerQ(m, S(-2))) cons307 = CustomConstraint(cons_f307) def cons_f308(a, b, c, d, e, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(And(RationalQ(m), Less(m, S(-1)), IntQuadraticQ(a, b, c, d, e, m, p, x)), And(SumSimplerQ(m, S(1)), IntegerQ(p), NonzeroQ(m + S(1))), And(NegativeIntegerQ(m + S(2)*p + S(3)), NonzeroQ(m + S(1)))) cons308 = CustomConstraint(cons_f308) def cons_f309(a, c, d, e, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(And(RationalQ(m), Less(m, S(-1)), IntQuadraticQ(a, S(0), c, d, e, m, p, x)), And(SumSimplerQ(m, S(1)), IntegerQ(p), NonzeroQ(m + S(1))), And(NegativeIntegerQ(m + S(2)*p + S(3)), NonzeroQ(m + S(1)))) cons309 = CustomConstraint(cons_f309) def cons_f310(a, b, c, d, e): return ZeroQ(-S(3)*a*c*e**S(2) + b**S(2)*e**S(2) - b*c*d*e + c**S(2)*d**S(2)) cons310 = CustomConstraint(cons_f310) def cons_f311(b, c, d, e): return PosQ(c*e**S(2)*(-b*e + S(2)*c*d)) cons311 = CustomConstraint(cons_f311) def cons_f312(a, c, d, e): return ZeroQ(-S(3)*a*e**S(2) + c*d**S(2)) cons312 = CustomConstraint(cons_f312) def cons_f313(b, c, d, e): return NegQ(c*e**S(2)*(-b*e + S(2)*c*d)) cons313 = CustomConstraint(cons_f313) def cons_f314(a, b, c, d, e): return ZeroQ(S(9)*a*c*e**S(2) - S(2)*b**S(2)*e**S(2) - b*c*d*e + c**S(2)*d**S(2)) cons314 = CustomConstraint(cons_f314) def cons_f315(a, b, c): return Not(PositiveQ(S(4)*a - b**S(2)/c)) cons315 = CustomConstraint(cons_f315) def cons_f316(p): return Not(IntegerQ(S(2)*p)) cons316 = CustomConstraint(cons_f316) def cons_f317(d, e, f, g): return NonzeroQ(-d*g + e*f) cons317 = CustomConstraint(cons_f317) def cons_f318(b, c, f, g): return ZeroQ(-b*g + S(2)*c*f) cons318 = CustomConstraint(cons_f318) def cons_f319(m): return Not(And(RationalQ(m), Greater(m, S(0)))) cons319 = CustomConstraint(cons_f319) def cons_f320(m, p): return Or(Not(RationalQ(p)), And(Greater(p, S(0)), Or(Not(IntegerQ(m)), GreaterEqual(m, -S(2)*p + S(-2)), Less(m, -S(4)*p + S(-4))))) cons320 = CustomConstraint(cons_f320) def cons_f321(m, p): return NonzeroQ(m + S(2)*p + S(2)) cons321 = CustomConstraint(cons_f321) def cons_f322(m, p): return Or(Not(RationalQ(p)), Less(m, S(2)*p + S(2))) cons322 = CustomConstraint(cons_f322) def cons_f323(b, c, f, g): return NonzeroQ(-b*g + S(2)*c*f) cons323 = CustomConstraint(cons_f323) def cons_f324(p): return Less(p, S(0)) cons324 = CustomConstraint(cons_f324) def cons_f325(b, c, d, e, m, p): return Or(And(ZeroQ(m + S(2)*p + S(2)), NonzeroQ(m + S(1))), And(ZeroQ(-b*e + S(2)*c*d), NonzeroQ(m + S(-1)))) cons325 = CustomConstraint(cons_f325) def cons_f326(d, e, f, g, m, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(ZeroQ(m + S(-1)), SimplerQ(f + g*x, d + e*x))) cons326 = CustomConstraint(cons_f326) def cons_f327(a, d, m, p): return Or(IntegerQ(p), And(PositiveQ(a), PositiveQ(d), ZeroQ(m + p))) cons327 = CustomConstraint(cons_f327) def cons_f328(b, c, d, e, f, g, m, p): return ZeroQ(e*(p + S(1))*(-b*g + S(2)*c*f) + m*(c*e*f + g*(-b*e + c*d))) cons328 = CustomConstraint(cons_f328) def cons_f329(d, e, f, g, m, p): return ZeroQ(S(2)*e*f*(p + S(1)) + m*(d*g + e*f)) cons329 = CustomConstraint(cons_f329) def cons_f330(m): return SumSimplerQ(m, S(-1)) cons330 = CustomConstraint(cons_f330) def cons_f331(m, p): return Or(And(RationalQ(m), Less(m, S(-1)), Not(PositiveIntegerQ(m + p + S(1)))), And(RationalQ(m, p), Less(m, S(0)), Less(p, S(-1))), ZeroQ(m + S(2)*p + S(2))) cons331 = CustomConstraint(cons_f331) def cons_f332(a, c, f, g): return ZeroQ(a*g**S(2) + c*f**S(2)) cons332 = CustomConstraint(cons_f332) def cons_f333(p): return Less(p, S(-2)) cons333 = CustomConstraint(cons_f333) def cons_f334(m, p): return Or(Less(S(0), -m, p + S(1)), Less(p, -m, S(0))) cons334 = CustomConstraint(cons_f334) def cons_f335(n, p): return NegativeIntegerQ(n + S(2)*p) cons335 = CustomConstraint(cons_f335) def cons_f336(b, c, d, e, f, g): return ZeroQ(-b*e*g + c*d*g + c*e*f) cons336 = CustomConstraint(cons_f336) def cons_f337(m, n): return NonzeroQ(m - n + S(-1)) cons337 = CustomConstraint(cons_f337) def cons_f338(d, e, f, g): return ZeroQ(d*g + e*f) cons338 = CustomConstraint(cons_f338) def cons_f339(m, n): return ZeroQ(m - n + S(-2)) cons339 = CustomConstraint(cons_f339) def cons_f340(n, p): return RationalQ(n, p) cons340 = CustomConstraint(cons_f340) def cons_f341(n, p): return Not(And(IntegerQ(n + p), LessEqual(n + p + S(2), S(0)))) cons341 = CustomConstraint(cons_f341) def cons_f342(n): return Not(PositiveIntegerQ(n)) cons342 = CustomConstraint(cons_f342) def cons_f343(n, p): return Not(And(IntegerQ(n + p), Less(n + p + S(2), S(0)))) cons343 = CustomConstraint(cons_f343) def cons_f344(n, p): return Or(IntegerQ(S(2)*p), IntegerQ(n)) cons344 = CustomConstraint(cons_f344) def cons_f345(m, p): return ZeroQ(m + p + S(-1)) cons345 = CustomConstraint(cons_f345) def cons_f346(b, c, d, e, f, g, n, p): return ZeroQ(b*e*g*(n + S(1)) - c*d*g*(S(2)*n + p + S(3)) + c*e*f*(p + S(1))) cons346 = CustomConstraint(cons_f346) def cons_f347(d, e, f, g, n, p): return ZeroQ(-d*g*(S(2)*n + p + S(3)) + e*f*(p + S(1))) cons347 = CustomConstraint(cons_f347) def cons_f348(n): return Not(And(RationalQ(n), Less(n, S(-1)))) cons348 = CustomConstraint(cons_f348) def cons_f349(p): return IntegerQ(p + S(-1)/2) cons349 = CustomConstraint(cons_f349) def cons_f350(m, p): return Not(And(Less(m, S(0)), Less(p, S(0)))) cons350 = CustomConstraint(cons_f350) def cons_f351(p): return Unequal(p, S(1)/2) cons351 = CustomConstraint(cons_f351) def cons_f352(a, b, c, d, e, f, g): return ZeroQ(-S(2)*a*e*g + b*(d*g + e*f) - S(2)*c*d*f) cons352 = CustomConstraint(cons_f352) def cons_f353(a, c, d, e, f, g): return ZeroQ(a*e*g + c*d*f) cons353 = CustomConstraint(cons_f353) def cons_f354(b, c, d, e, m): return Not(And(Equal(m, S(1)), Or(ZeroQ(d), ZeroQ(-b*e + S(2)*c*d)))) cons354 = CustomConstraint(cons_f354) def cons_f355(d, m): return Not(And(Equal(m, S(1)), ZeroQ(d))) cons355 = CustomConstraint(cons_f355) def cons_f356(a, b, c, d, e, f, g, p): return ZeroQ(-S(2)*a*c*e*g + b**S(2)*e*g*(p + S(2)) + c*(S(2)*p + S(3))*(-b*(d*g + e*f) + S(2)*c*d*f)) cons356 = CustomConstraint(cons_f356) def cons_f357(a, c, d, e, f, g, p): return ZeroQ(a*e*g - c*d*f*(S(2)*p + S(3))) cons357 = CustomConstraint(cons_f357) def cons_f358(m): return Not(RationalQ(m)) cons358 = CustomConstraint(cons_f358) def cons_f359(p): return Not(PositiveIntegerQ(p)) cons359 = CustomConstraint(cons_f359) def cons_f360(m, p): return ZeroQ(m - p) cons360 = CustomConstraint(cons_f360) def cons_f361(m, p): return Less(m + S(2)*p, S(0)) cons361 = CustomConstraint(cons_f361) def cons_f362(m, p): return Not(NegativeIntegerQ(m + S(2)*p + S(3))) cons362 = CustomConstraint(cons_f362) def cons_f363(m, p): return Or(And(RationalQ(m), Less(m, S(-1))), Equal(p, S(1)), And(IntegerQ(p), Not(RationalQ(m)))) cons363 = CustomConstraint(cons_f363) def cons_f364(m, p): return Or(IntegerQ(m), IntegerQ(p), IntegersQ(S(2)*m, S(2)*p)) cons364 = CustomConstraint(cons_f364) def cons_f365(m, p): return Or(IntegerQ(p), Not(RationalQ(m)), Inequality(S(-1), LessEqual, m, Less, S(0))) cons365 = CustomConstraint(cons_f365) def cons_f366(a, b, c, d, e, f, g, m, p): return Or(And(Equal(m, S(2)), Equal(p, S(-3)), RationalQ(a, b, c, d, e, f, g)), Not(NegativeIntegerQ(m + S(2)*p + S(3)))) cons366 = CustomConstraint(cons_f366) def cons_f367(a, c, d, e, f, g, m, p): return Or(And(Equal(m, S(2)), Equal(p, S(-3)), RationalQ(a, c, d, e, f, g)), Not(NegativeIntegerQ(m + S(2)*p + S(3)))) cons367 = CustomConstraint(cons_f367) def cons_f368(d, e, f, g, m, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(Equal(m, S(1)), SimplerQ(d + e*x, f + g*x))) cons368 = CustomConstraint(cons_f368) def cons_f369(m): return FractionQ(m) cons369 = CustomConstraint(cons_f369) def cons_f370(d, e, f, g, m, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(Equal(m, S(1)), SimplerQ(f + g*x, d + e*x))) cons370 = CustomConstraint(cons_f370) def cons_f371(m, p): return NegativeIntegerQ(m + S(2)*p + S(3)) cons371 = CustomConstraint(cons_f371) def cons_f372(a, b, c, d, e): return ZeroQ(S(4)*c*(a - d) - (b - e)**S(2)) cons372 = CustomConstraint(cons_f372) def cons_f373(a, b, d, e, f, g): return ZeroQ(e*f*(b - e) - S(2)*g*(-a*e + b*d)) cons373 = CustomConstraint(cons_f373) def cons_f374(a, b, d, e): return NonzeroQ(-a*e + b*d) cons374 = CustomConstraint(cons_f374) def cons_f375(a, c, f, g, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, f, g), x) cons375 = CustomConstraint(cons_f375) def cons_f376(a, c, e, f, g, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, e, f, g), x) cons376 = CustomConstraint(cons_f376) def cons_f377(m, n, p): return IntegersQ(m, n, p) cons377 = CustomConstraint(cons_f377) def cons_f378(n, p): return IntegersQ(n, p) cons378 = CustomConstraint(cons_f378) def cons_f379(d, f, m): return Or(IntegerQ(m), And(PositiveQ(d), PositiveQ(f))) cons379 = CustomConstraint(cons_f379) def cons_f380(m, n, p): return Or(IntegerQ(p), IntegersQ(m, n)) cons380 = CustomConstraint(cons_f380) def cons_f381(a, c, e, f, g, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, e, f, g, m, p), x) cons381 = CustomConstraint(cons_f381) def cons_f382(a, b, c, d, e, f, g, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, m, n, p), x) cons382 = CustomConstraint(cons_f382) def cons_f383(a, c, d, e, f, g, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, d, e, f, g, m, n, p), x) cons383 = CustomConstraint(cons_f383) def cons_f384(a, c, d, f): return ZeroQ(-a*f + c*d) cons384 = CustomConstraint(cons_f384) def cons_f385(a, b, d, e): return ZeroQ(-a*e + b*d) cons385 = CustomConstraint(cons_f385) def cons_f386(c, f, p): return Or(IntegerQ(p), PositiveQ(c/f)) cons386 = CustomConstraint(cons_f386) def cons_f387(a, b, c, d, e, f, q, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(Not(IntegerQ(q)), LessEqual(LeafCount(d + e*x + f*x**S(2)), LeafCount(a + b*x + c*x**S(2)))) cons387 = CustomConstraint(cons_f387) def cons_f388(q): return Not(IntegerQ(q)) cons388 = CustomConstraint(cons_f388) def cons_f389(c, f): return Not(PositiveQ(c/f)) cons389 = CustomConstraint(cons_f389) def cons_f390(a, b, c, d, e, f, q): return ZeroQ(c*(-S(2)*d*f + e**S(2)*(q + S(2))) + f*(S(2)*q + S(3))*(S(2)*a*f - b*e)) cons390 = CustomConstraint(cons_f390) def cons_f391(q): return NonzeroQ(q + S(1)) cons391 = CustomConstraint(cons_f391) def cons_f392(q): return NonzeroQ(S(2)*q + S(3)) cons392 = CustomConstraint(cons_f392) def cons_f393(a, c, d, e, f, q): return ZeroQ(S(2)*a*f**S(2)*(S(2)*q + S(3)) + c*(-S(2)*d*f + e**S(2)*(q + S(2)))) cons393 = CustomConstraint(cons_f393) def cons_f394(a, c, d, f, q): return ZeroQ(S(2)*a*f*q + S(3)*a*f - c*d) cons394 = CustomConstraint(cons_f394) def cons_f395(q): return PositiveIntegerQ(q + S(2)) cons395 = CustomConstraint(cons_f395) def cons_f396(d, e, f): return NonzeroQ(-S(4)*d*f + e**S(2)) cons396 = CustomConstraint(cons_f396) def cons_f397(q): return RationalQ(q) cons397 = CustomConstraint(cons_f397) def cons_f398(q): return Less(q, S(-1)) cons398 = CustomConstraint(cons_f398) def cons_f399(a, b, c, d, e, f, q): return NonzeroQ(c*(-S(2)*d*f + e**S(2)*(q + S(2))) + f*(S(2)*q + S(3))*(S(2)*a*f - b*e)) cons399 = CustomConstraint(cons_f399) def cons_f400(a, c, d, e, f, q): return NonzeroQ(S(2)*a*f**S(2)*(S(2)*q + S(3)) + c*(-S(2)*d*f + e**S(2)*(q + S(2)))) cons400 = CustomConstraint(cons_f400) def cons_f401(a, c, d, f, q): return NonzeroQ(S(2)*a*f*q + S(3)*a*f - c*d) cons401 = CustomConstraint(cons_f401) def cons_f402(q): return Not(PositiveIntegerQ(q)) cons402 = CustomConstraint(cons_f402) def cons_f403(q): return Not(And(RationalQ(q), LessEqual(q, S(-1)))) cons403 = CustomConstraint(cons_f403) def cons_f404(p, q): return RationalQ(p, q) cons404 = CustomConstraint(cons_f404) def cons_f405(q): return Greater(q, S(0)) cons405 = CustomConstraint(cons_f405) def cons_f406(a, b, c, d, e, f): return NonzeroQ(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2)) cons406 = CustomConstraint(cons_f406) def cons_f407(p, q): return Not(And(Not(IntegerQ(p)), IntegerQ(q), Less(q, S(-1)))) cons407 = CustomConstraint(cons_f407) def cons_f408(a, b, c, d, f): return NonzeroQ(b**S(2)*d*f + (-a*f + c*d)**S(2)) cons408 = CustomConstraint(cons_f408) def cons_f409(a, c, d, e, f): return NonzeroQ(a*c*e**S(2) + (-a*f + c*d)**S(2)) cons409 = CustomConstraint(cons_f409) def cons_f410(p, q): return NonzeroQ(p + q) cons410 = CustomConstraint(cons_f410) def cons_f411(p, q): return NonzeroQ(S(2)*p + S(2)*q + S(1)) cons411 = CustomConstraint(cons_f411) def cons_f412(b, c, e, f): return ZeroQ(-b*f + c*e) cons412 = CustomConstraint(cons_f412) def cons_f413(b, c, e, f): return NonzeroQ(-b*f + c*e) cons413 = CustomConstraint(cons_f413) def cons_f414(a, c): return PosQ(-a*c) cons414 = CustomConstraint(cons_f414) def cons_f415(a, b, c): return NegQ(-S(4)*a*c + b**S(2)) cons415 = CustomConstraint(cons_f415) def cons_f416(a, c): return NegQ(-a*c) cons416 = CustomConstraint(cons_f416) def cons_f417(a, b, c, d, e, f, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, p, q), x) cons417 = CustomConstraint(cons_f417) def cons_f418(a, c, d, e, f, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, d, e, f, p, q), x) cons418 = CustomConstraint(cons_f418) def cons_f419(a, b, c, g, h): return ZeroQ(a*h**S(2) - b*g*h + c*g**S(2)) cons419 = CustomConstraint(cons_f419) def cons_f420(a, c, d, e, f, g, h): return ZeroQ(a**S(2)*f*h**S(2) - a*c*e*g*h + c**S(2)*d*g**S(2)) cons420 = CustomConstraint(cons_f420) def cons_f421(a, c, g, h): return ZeroQ(a*h**S(2) + c*g**S(2)) cons421 = CustomConstraint(cons_f421) def cons_f422(a, c, d, f, g, h): return ZeroQ(a**S(2)*f*h**S(2) + c**S(2)*d*g**S(2)) cons422 = CustomConstraint(cons_f422) def cons_f423(a, b, c, e, f): return ZeroQ(a*f**S(2) - b*e*f + c*e**S(2)) cons423 = CustomConstraint(cons_f423) def cons_f424(a, c, e, f): return ZeroQ(a*f**S(2) + c*e**S(2)) cons424 = CustomConstraint(cons_f424) def cons_f425(b, c, e, f, g, h, m, p): return ZeroQ(b*f*h*(m + p + S(2)) + c*(-e*h*(m + S(2)*p + S(3)) + S(2)*f*g*(p + S(1)))) cons425 = CustomConstraint(cons_f425) def cons_f426(a, b, c, d, f, g, h, m, p): return ZeroQ(b*f*g*(p + S(1)) + h*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3)))) cons426 = CustomConstraint(cons_f426) def cons_f427(c, e, f, g, h, m, p): return ZeroQ(c*(-e*h*(m + S(2)*p + S(3)) + S(2)*f*g*(p + S(1)))) cons427 = CustomConstraint(cons_f427) def cons_f428(a, c, d, f, h, m, p): return ZeroQ(h*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3)))) cons428 = CustomConstraint(cons_f428) def cons_f429(b, c, f, g, h, m, p): return ZeroQ(b*f*h*(m + p + S(2)) + S(2)*c*f*g*(p + S(1))) cons429 = CustomConstraint(cons_f429) def cons_f430(m, p): return Or(IntegersQ(m, p), PositiveIntegerQ(p)) cons430 = CustomConstraint(cons_f430) def cons_f431(a, b, c, g, h): return NonzeroQ(a*h**S(2) - b*g*h + c*g**S(2)) cons431 = CustomConstraint(cons_f431) def cons_f432(a, c, g, h): return NonzeroQ(a*h**S(2) + c*g**S(2)) cons432 = CustomConstraint(cons_f432) def cons_f433(a, b, c, g, h): return NonzeroQ(c*g**S(2) - h*(-a*h + b*g)) cons433 = CustomConstraint(cons_f433) def cons_f434(p, q): return Or(Greater(p, S(0)), Greater(q, S(0))) cons434 = CustomConstraint(cons_f434) def cons_f435(p, q): return NonzeroQ(p + q + S(1)) cons435 = CustomConstraint(cons_f435) def cons_f436(a, c): return PositiveQ(a*c) cons436 = CustomConstraint(cons_f436) def cons_f437(a, c): return Not(PositiveQ(a*c)) cons437 = CustomConstraint(cons_f437) def cons_f438(e, f, g, h): return ZeroQ(e*h - S(2)*f*g) cons438 = CustomConstraint(cons_f438) def cons_f439(e, f, g, h): return NonzeroQ(e*h - S(2)*f*g) cons439 = CustomConstraint(cons_f439) def cons_f440(d, e, g, h): return ZeroQ(S(2)*d*h - e*g) cons440 = CustomConstraint(cons_f440) def cons_f441(d, e, g, h): return NonzeroQ(S(2)*d*h - e*g) cons441 = CustomConstraint(cons_f441) def cons_f442(a, b, c, d, e, f, g, h): return ZeroQ(g**S(2)*(-b*f + c*e) - S(2)*g*h*(-a*f + c*d) + h**S(2)*(-a*e + b*d)) cons442 = CustomConstraint(cons_f442) def cons_f443(a, c, d, e, f, g, h): return ZeroQ(a*e*h**S(2) - c*e*g**S(2) + S(2)*g*h*(-a*f + c*d)) cons443 = CustomConstraint(cons_f443) def cons_f444(a, b, c, d, f, g, h): return ZeroQ(b*d*h**S(2) - b*f*g**S(2) - S(2)*g*h*(-a*f + c*d)) cons444 = CustomConstraint(cons_f444) def cons_f445(a, b, c, d, f): return ZeroQ(c**S(2)*d - f*(-S(3)*a*c + b**S(2))) cons445 = CustomConstraint(cons_f445) def cons_f446(a, b, c, g, h): return ZeroQ(S(9)*a*c*h**S(2) - S(2)*b**S(2)*h**S(2) - b*c*g*h + c**S(2)*g**S(2)) cons446 = CustomConstraint(cons_f446) def cons_f447(b, c, g, h): return PositiveQ(-S(9)*c*h**S(2)/(-b*h + S(2)*c*g)**S(2)) cons447 = CustomConstraint(cons_f447) def cons_f448(a, c, d, f): return ZeroQ(S(3)*a*f + c*d) cons448 = CustomConstraint(cons_f448) def cons_f449(a, c, g, h): return ZeroQ(S(9)*a*h**S(2) + c*g**S(2)) cons449 = CustomConstraint(cons_f449) def cons_f450(a): return Not(PositiveQ(a)) cons450 = CustomConstraint(cons_f450) def cons_f451(a, b, c, d, e, f, g, h, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, h, p, q), x) cons451 = CustomConstraint(cons_f451) def cons_f452(a, c, d, e, f, g, h, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, d, e, f, g, h, p, q), x) cons452 = CustomConstraint(cons_f452) def cons_f453(x, z): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(z, x) cons453 = CustomConstraint(cons_f453) def cons_f454(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return QuadraticQ(List(u, v), x) cons454 = CustomConstraint(cons_f454) def cons_f455(u, v, x, z): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(z, x), QuadraticMatchQ(List(u, v), x))) cons455 = CustomConstraint(cons_f455) def cons_f456(p, q): return NonzeroQ(S(2)*p + S(2)*q + S(3)) cons456 = CustomConstraint(cons_f456) def cons_f457(A, B, C, a, b, c, d, e, f, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, A, B, C, p, q), x) cons457 = CustomConstraint(cons_f457) def cons_f458(A, C, a, b, c, d, e, f, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, A, C, p, q), x) cons458 = CustomConstraint(cons_f458) def cons_f459(A, B, C, a, c, d, e, f, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, d, e, f, A, B, C, p, q), x) cons459 = CustomConstraint(cons_f459) def cons_f460(A, C, a, c, d, e, f, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, d, e, f, A, C, p, q), x) cons460 = CustomConstraint(cons_f460) def cons_f461(b, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, n, p), x) cons461 = CustomConstraint(cons_f461) def cons_f462(n, p): return ZeroQ(p + S(1) + S(1)/n) cons462 = CustomConstraint(cons_f462) def cons_f463(n, p): return NegativeIntegerQ(p + S(1) + S(1)/n) cons463 = CustomConstraint(cons_f463) def cons_f464(n): return NonzeroQ(S(3)*n + S(1)) cons464 = CustomConstraint(cons_f464) def cons_f465(n): return Less(n, S(0)) cons465 = CustomConstraint(cons_f465) def cons_f466(n, p): return PositiveIntegerQ(n, p) cons466 = CustomConstraint(cons_f466) def cons_f467(n, p): return Or(IntegerQ(S(2)*p), And(Equal(n, S(2)), IntegerQ(S(4)*p)), And(Equal(n, S(2)), IntegerQ(S(3)*p)), Less(Denominator(p + S(1)/n), Denominator(p))) cons467 = CustomConstraint(cons_f467) def cons_f468(a, b): return PosQ(b/a) cons468 = CustomConstraint(cons_f468) def cons_f469(n): return PositiveIntegerQ(n/S(2) + S(-3)/2) cons469 = CustomConstraint(cons_f469) def cons_f470(a, b): return PosQ(a/b) cons470 = CustomConstraint(cons_f470) def cons_f471(a, b): return NegQ(a/b) cons471 = CustomConstraint(cons_f471) def cons_f472(a, b): return Or(PositiveQ(a), PositiveQ(b)) cons472 = CustomConstraint(cons_f472) def cons_f473(a, b): return Or(NegativeQ(a), NegativeQ(b)) cons473 = CustomConstraint(cons_f473) def cons_f474(a, b): return Or(PositiveQ(a), NegativeQ(b)) cons474 = CustomConstraint(cons_f474) def cons_f475(a, b): return Or(NegativeQ(a), PositiveQ(b)) cons475 = CustomConstraint(cons_f475) def cons_f476(n): return PositiveIntegerQ(n/S(4) + S(-1)/2) cons476 = CustomConstraint(cons_f476) def cons_f477(a, b): try: return Or(PositiveQ(a/b), And(PosQ(a/b), AtomQ(SplitProduct(SumBaseQ, a)), AtomQ(SplitProduct(SumBaseQ, b)))) except (TypeError, AttributeError): return False cons477 = CustomConstraint(cons_f477) def cons_f478(a, b): return Not(PositiveQ(a/b)) cons478 = CustomConstraint(cons_f478) def cons_f479(n): return PositiveIntegerQ(n/S(4) + S(-1)) cons479 = CustomConstraint(cons_f479) def cons_f480(a, b): return PositiveQ(a/b) cons480 = CustomConstraint(cons_f480) def cons_f481(b): return PosQ(b) cons481 = CustomConstraint(cons_f481) def cons_f482(b): return NegQ(b) cons482 = CustomConstraint(cons_f482) def cons_f483(a): return PosQ(a) cons483 = CustomConstraint(cons_f483) def cons_f484(a): return NegQ(a) cons484 = CustomConstraint(cons_f484) def cons_f485(a, b): return NegQ(b/a) cons485 = CustomConstraint(cons_f485) def cons_f486(a): return NegativeQ(a) cons486 = CustomConstraint(cons_f486) def cons_f487(p): return Less(S(-1), p, S(0)) cons487 = CustomConstraint(cons_f487) def cons_f488(p): return Unequal(p, S(-1)/2) cons488 = CustomConstraint(cons_f488) def cons_f489(n, p): return IntegerQ(p + S(1)/n) cons489 = CustomConstraint(cons_f489) def cons_f490(n, p): return Less(Denominator(p + S(1)/n), Denominator(p)) cons490 = CustomConstraint(cons_f490) def cons_f491(n): return FractionQ(n) cons491 = CustomConstraint(cons_f491) def cons_f492(n): return Not(IntegerQ(S(1)/n)) cons492 = CustomConstraint(cons_f492) def cons_f493(n, p): return Not(NegativeIntegerQ(p + S(1)/n)) cons493 = CustomConstraint(cons_f493) def cons_f494(a, p): return Or(IntegerQ(p), PositiveQ(a)) cons494 = CustomConstraint(cons_f494) def cons_f495(a, p): return Not(Or(IntegerQ(p), PositiveQ(a))) cons495 = CustomConstraint(cons_f495) def cons_f496(a1, a2, p): return Or(IntegerQ(p), And(PositiveQ(a1), PositiveQ(a2))) cons496 = CustomConstraint(cons_f496) def cons_f497(n): return PositiveIntegerQ(S(2)*n) cons497 = CustomConstraint(cons_f497) def cons_f498(n, p): return Or(IntegerQ(S(2)*p), Less(Denominator(p + S(1)/n), Denominator(p))) cons498 = CustomConstraint(cons_f498) def cons_f499(n): return NegativeIntegerQ(S(2)*n) cons499 = CustomConstraint(cons_f499) def cons_f500(n): return FractionQ(S(2)*n) cons500 = CustomConstraint(cons_f500) def cons_f501(c, m): return Or(IntegerQ(m), PositiveQ(c)) cons501 = CustomConstraint(cons_f501) def cons_f502(m, n): return IntegerQ((m + S(1))/n) cons502 = CustomConstraint(cons_f502) def cons_f503(m, n): return Not(IntegerQ((m + S(1))/n)) cons503 = CustomConstraint(cons_f503) def cons_f504(n): return NegQ(n) cons504 = CustomConstraint(cons_f504) def cons_f505(m, n, p): return ZeroQ(p + S(1) + (m + S(1))/n) cons505 = CustomConstraint(cons_f505) def cons_f506(m, n, p): return ZeroQ(p + S(1) + (m + S(1))/(S(2)*n)) cons506 = CustomConstraint(cons_f506) def cons_f507(m, n): return IntegerQ((m + S(1))/(S(2)*n)) cons507 = CustomConstraint(cons_f507) def cons_f508(m, n, p): return NegativeIntegerQ((m + n*(p + S(1)) + S(1))/n) cons508 = CustomConstraint(cons_f508) def cons_f509(m, n, p): return NegativeIntegerQ((m + S(2)*n*(p + S(1)) + S(1))/(S(2)*n)) cons509 = CustomConstraint(cons_f509) def cons_f510(m, n, p): return Not(NegativeIntegerQ((m + n*p + n + S(1))/n)) cons510 = CustomConstraint(cons_f510) def cons_f511(a, b, c, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return IntBinomialQ(a, b, c, n, m, p, x) cons511 = CustomConstraint(cons_f511) def cons_f512(m, n, p): return NonzeroQ(m + S(2)*n*p + S(1)) cons512 = CustomConstraint(cons_f512) def cons_f513(a1, a2, b1, b2, c, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return IntBinomialQ(a1*a2, b1*b2, c, n, m, p, x) cons513 = CustomConstraint(cons_f513) def cons_f514(m, n, p): return NonzeroQ(m + n*p + S(1)) cons514 = CustomConstraint(cons_f514) def cons_f515(m): return PositiveIntegerQ(m/S(4) + S(-1)/2) cons515 = CustomConstraint(cons_f515) def cons_f516(m): return NegativeIntegerQ(m/S(4) + S(-1)/2) cons516 = CustomConstraint(cons_f516) def cons_f517(m): return IntegerQ(S(2)*m) cons517 = CustomConstraint(cons_f517) def cons_f518(m): return Greater(m, S(3)/2) cons518 = CustomConstraint(cons_f518) def cons_f519(m, n): return Greater(m + S(1), n) cons519 = CustomConstraint(cons_f519) def cons_f520(m, n, p): return Not(NegativeIntegerQ((m + n*(p + S(1)) + S(1))/n)) cons520 = CustomConstraint(cons_f520) def cons_f521(m, n): return Greater(m + S(1), S(2)*n) cons521 = CustomConstraint(cons_f521) def cons_f522(m, n, p): return Not(NegativeIntegerQ((m + S(2)*n*(p + S(1)) + S(1))/(S(2)*n))) cons522 = CustomConstraint(cons_f522) def cons_f523(n): return PositiveIntegerQ(n/S(2) + S(-1)/2) cons523 = CustomConstraint(cons_f523) def cons_f524(m, n): return Less(m, n + S(-1)) cons524 = CustomConstraint(cons_f524) def cons_f525(m, n): return PositiveIntegerQ(m, n/S(2) + S(-1)/2) cons525 = CustomConstraint(cons_f525) def cons_f526(m, n): return PositiveIntegerQ(m, n/S(4) + S(-1)/2) cons526 = CustomConstraint(cons_f526) def cons_f527(m, n): return PositiveIntegerQ(m, n/S(4)) cons527 = CustomConstraint(cons_f527) def cons_f528(m, n): return Less(m, n/S(2)) cons528 = CustomConstraint(cons_f528) def cons_f529(m, n): return Inequality(n/S(2), LessEqual, m, Less, n) cons529 = CustomConstraint(cons_f529) def cons_f530(m, n): return PositiveIntegerQ(m, n) cons530 = CustomConstraint(cons_f530) def cons_f531(m, n): return Greater(m, S(2)*n + S(-1)) cons531 = CustomConstraint(cons_f531) def cons_f532(m, n): return Greater(m, n + S(-1)) cons532 = CustomConstraint(cons_f532) def cons_f533(m, n): return SumSimplerQ(m, -n) cons533 = CustomConstraint(cons_f533) def cons_f534(m, n, p): return NegativeIntegerQ((m + n*p + S(1))/n) cons534 = CustomConstraint(cons_f534) def cons_f535(m, n): return SumSimplerQ(m, -S(2)*n) cons535 = CustomConstraint(cons_f535) def cons_f536(m, n, p): return NegativeIntegerQ((m + S(2)*n*p + S(1))/(S(2)*n)) cons536 = CustomConstraint(cons_f536) def cons_f537(m, n): return SumSimplerQ(m, n) cons537 = CustomConstraint(cons_f537) def cons_f538(m, n): return SumSimplerQ(m, S(2)*n) cons538 = CustomConstraint(cons_f538) def cons_f539(m, n, p): return IntegersQ(m, p + (m + S(1))/n) cons539 = CustomConstraint(cons_f539) def cons_f540(m, n, p): return IntegersQ(m, p + (m + S(1))/(S(2)*n)) cons540 = CustomConstraint(cons_f540) def cons_f541(m, n, p): return Less(Denominator(p + (m + S(1))/n), Denominator(p)) cons541 = CustomConstraint(cons_f541) def cons_f542(m, n, p): return Less(Denominator(p + (m + S(1))/(S(2)*n)), Denominator(p)) cons542 = CustomConstraint(cons_f542) def cons_f543(m, n): return IntegerQ(n/(m + S(1))) cons543 = CustomConstraint(cons_f543) def cons_f544(m, n): return IntegerQ(S(2)*n/(m + S(1))) cons544 = CustomConstraint(cons_f544) def cons_f545(n): return Not(IntegerQ(S(2)*n)) cons545 = CustomConstraint(cons_f545) def cons_f546(m, n, p): return ZeroQ(p + (m + S(1))/n) cons546 = CustomConstraint(cons_f546) def cons_f547(m, n, p): return ZeroQ(p + (m + S(1))/(S(2)*n)) cons547 = CustomConstraint(cons_f547) def cons_f548(m, n, p): return IntegerQ(p + (m + S(1))/n) cons548 = CustomConstraint(cons_f548) def cons_f549(m, n, p): return IntegerQ(p + (m + S(1))/(S(2)*n)) cons549 = CustomConstraint(cons_f549) def cons_f550(m, n): return FractionQ((m + S(1))/n) cons550 = CustomConstraint(cons_f550) def cons_f551(m, n): return Or(SumSimplerQ(m, n), SumSimplerQ(m, -n)) cons551 = CustomConstraint(cons_f551) def cons_f552(a, p): return Or(NegativeIntegerQ(p), PositiveQ(a)) cons552 = CustomConstraint(cons_f552) def cons_f553(a, p): return Not(Or(NegativeIntegerQ(p), PositiveQ(a))) cons553 = CustomConstraint(cons_f553) def cons_f554(v, x): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(v, x) cons554 = CustomConstraint(cons_f554) def cons_f555(v, x): if isinstance(x, (int, Integer, float, Float)): return False return NonzeroQ(v - x) cons555 = CustomConstraint(cons_f555) def cons_f556(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return LinearPairQ(u, v, x) cons556 = CustomConstraint(cons_f556) def cons_f557(p, q): return PositiveIntegerQ(p, q) cons557 = CustomConstraint(cons_f557) def cons_f558(n, p): return ZeroQ(n*p + S(1)) cons558 = CustomConstraint(cons_f558) def cons_f559(n, p, q): return ZeroQ(n*(p + q + S(1)) + S(1)) cons559 = CustomConstraint(cons_f559) def cons_f560(n, p, q): return ZeroQ(n*(p + q + S(2)) + S(1)) cons560 = CustomConstraint(cons_f560) def cons_f561(a, b, c, d, p, q): return ZeroQ(a*d*(p + S(1)) + b*c*(q + S(1))) cons561 = CustomConstraint(cons_f561) def cons_f562(p, q): return Or(And(RationalQ(p), Less(p, S(-1))), Not(And(RationalQ(q), Less(q, S(-1))))) cons562 = CustomConstraint(cons_f562) def cons_f563(a, b, c, d, n, p): return ZeroQ(a*d - b*c*(n*(p + S(1)) + S(1))) cons563 = CustomConstraint(cons_f563) def cons_f564(n, p): return Or(And(RationalQ(p), Less(p, S(-1))), NegativeIntegerQ(p + S(1)/n)) cons564 = CustomConstraint(cons_f564) def cons_f565(n, p): return NonzeroQ(n*(p + S(1)) + S(1)) cons565 = CustomConstraint(cons_f565) def cons_f566(q): return NegativeIntegerQ(q) cons566 = CustomConstraint(cons_f566) def cons_f567(p, q): return GreaterEqual(p, -q) cons567 = CustomConstraint(cons_f567) def cons_f568(a, b, c, d): return ZeroQ(S(3)*a*d + b*c) cons568 = CustomConstraint(cons_f568) def cons_f569(p): return Or(Equal(p, S(1)/2), Equal(Denominator(p), S(4))) cons569 = CustomConstraint(cons_f569) def cons_f570(p): return Equal(Denominator(p), S(4)) cons570 = CustomConstraint(cons_f570) def cons_f571(p): return Or(Equal(p, S(-5)/4), Equal(p, S(-7)/4)) cons571 = CustomConstraint(cons_f571) def cons_f572(a, b): return PosQ(a*b) cons572 = CustomConstraint(cons_f572) def cons_f573(a, b): return NegQ(a*b) cons573 = CustomConstraint(cons_f573) def cons_f574(p): return Or(Equal(p, S(3)/4), Equal(p, S(5)/4)) cons574 = CustomConstraint(cons_f574) def cons_f575(c, d): return PosQ(d/c) cons575 = CustomConstraint(cons_f575) def cons_f576(q): return Less(S(0), q, S(1)) cons576 = CustomConstraint(cons_f576) def cons_f577(a, b, c, d, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return IntBinomialQ(a, b, c, d, n, p, q, x) cons577 = CustomConstraint(cons_f577) def cons_f578(q): return Greater(q, S(1)) cons578 = CustomConstraint(cons_f578) def cons_f579(p, q): return Greater(p + q, S(0)) cons579 = CustomConstraint(cons_f579) def cons_f580(n, p, q): return NonzeroQ(n*(p + q) + S(1)) cons580 = CustomConstraint(cons_f580) def cons_f581(p): return Not(And(IntegerQ(p), Greater(p, S(1)))) cons581 = CustomConstraint(cons_f581) def cons_f582(a, b, c, d): return Not(SimplerSqrtQ(b/a, d/c)) cons582 = CustomConstraint(cons_f582) def cons_f583(c, d): return NegQ(d/c) cons583 = CustomConstraint(cons_f583) def cons_f584(a, b, c, d): return Not(And(NegQ(b/a), SimplerSqrtQ(-b/a, -d/c))) cons584 = CustomConstraint(cons_f584) def cons_f585(a, b, c, d): return PositiveQ(a - b*c/d) cons585 = CustomConstraint(cons_f585) def cons_f586(n): return NonzeroQ(n + S(1)) cons586 = CustomConstraint(cons_f586) def cons_f587(mn, n): return EqQ(mn, -n) cons587 = CustomConstraint(cons_f587) def cons_f588(q): return IntegerQ(q) cons588 = CustomConstraint(cons_f588) def cons_f589(n, p): return Or(PosQ(n), Not(IntegerQ(p))) cons589 = CustomConstraint(cons_f589) def cons_f590(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return PseudoBinomialPairQ(u, v, x) cons590 = CustomConstraint(cons_f590) def cons_f591(m, p): return IntegersQ(p, m/p) cons591 = CustomConstraint(cons_f591) def cons_f592(m, p, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return PseudoBinomialPairQ(u*x**(m/p), v, x) cons592 = CustomConstraint(cons_f592) def cons_f593(e, m): return Or(IntegerQ(m), PositiveQ(e)) cons593 = CustomConstraint(cons_f593) def cons_f594(a, b, c, d, m, n, p): return ZeroQ(a*d*(m + S(1)) - b*c*(m + n*(p + S(1)) + S(1))) cons594 = CustomConstraint(cons_f594) def cons_f595(n, non2): return ZeroQ(-n/S(2) + non2) cons595 = CustomConstraint(cons_f595) def cons_f596(a1, a2, b1, b2, c, d, m, n, p): return ZeroQ(a1*a2*d*(m + S(1)) - b1*b2*c*(m + n*(p + S(1)) + S(1))) cons596 = CustomConstraint(cons_f596) def cons_f597(m, n, p): return ZeroQ(m + n*(p + S(1)) + S(1)) cons597 = CustomConstraint(cons_f597) def cons_f598(e, n): return Or(IntegerQ(n), PositiveQ(e)) cons598 = CustomConstraint(cons_f598) def cons_f599(m, n): return Or(And(Greater(n, S(0)), Less(m, S(-1))), And(Less(n, S(0)), Greater(m + n, S(-1)))) cons599 = CustomConstraint(cons_f599) def cons_f600(p): return Not(And(IntegerQ(p), Less(p, S(-1)))) cons600 = CustomConstraint(cons_f600) def cons_f601(m): return PositiveIntegerQ(m/S(2)) cons601 = CustomConstraint(cons_f601) def cons_f602(m, p): return Or(IntegerQ(p), Equal(m + S(2)*p + S(1), S(0))) cons602 = CustomConstraint(cons_f602) def cons_f603(m): return NegativeIntegerQ(m/S(2)) cons603 = CustomConstraint(cons_f603) def cons_f604(m, n, p): return Or(IntegerQ(p), Not(RationalQ(m)), And(PositiveIntegerQ(n), NegativeIntegerQ(p + S(1)/2), LessEqual(S(-1), m, -n*(p + S(1))))) cons604 = CustomConstraint(cons_f604) def cons_f605(m, n, p): return NonzeroQ(m + n*(p + S(1)) + S(1)) cons605 = CustomConstraint(cons_f605) def cons_f606(m): return Or(IntegerQ(m), PositiveIntegerQ(S(2)*m + S(2)), Not(RationalQ(m))) cons606 = CustomConstraint(cons_f606) def cons_f607(m, n, p): return NonzeroQ(m + n*(p + S(2)) + S(1)) cons607 = CustomConstraint(cons_f607) def cons_f608(m, p, q): return RationalQ(m, p, q) cons608 = CustomConstraint(cons_f608) def cons_f609(m, n): return Greater(m - n + S(1), S(0)) cons609 = CustomConstraint(cons_f609) def cons_f610(a, b, c, d, e, m, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return IntBinomialQ(a, b, c, d, e, m, n, p, q, x) cons610 = CustomConstraint(cons_f610) def cons_f611(m, n): return Greater(m - n + S(1), n) cons611 = CustomConstraint(cons_f611) def cons_f612(m, n): return Inequality(n, GreaterEqual, m - n + S(1), Greater, S(0)) cons612 = CustomConstraint(cons_f612) def cons_f613(m, q): return RationalQ(m, q) cons613 = CustomConstraint(cons_f613) def cons_f614(m, n): return LessEqual(n, m, S(2)*n + S(-1)) cons614 = CustomConstraint(cons_f614) def cons_f615(m, n): return IntegersQ(m/S(2), n/S(2)) cons615 = CustomConstraint(cons_f615) def cons_f616(m, n): return Less(S(0), m - n + S(1), n) cons616 = CustomConstraint(cons_f616) def cons_f617(n): return LessEqual(n, S(4)) cons617 = CustomConstraint(cons_f617) def cons_f618(a, b, c, d): return ZeroQ(-a*d + S(4)*b*c) cons618 = CustomConstraint(cons_f618) def cons_f619(m): return PositiveIntegerQ(m/S(3) + S(-1)/3) cons619 = CustomConstraint(cons_f619) def cons_f620(m): return NegativeIntegerQ(m/S(3) + S(-1)/3) cons620 = CustomConstraint(cons_f620) def cons_f621(m): return IntegerQ(m/S(3) + S(-1)/3) cons621 = CustomConstraint(cons_f621) def cons_f622(n): return Or(EqQ(n, S(2)), EqQ(n, S(4))) cons622 = CustomConstraint(cons_f622) def cons_f623(a, b, c, d, n): return Not(And(EqQ(n, S(2)), SimplerSqrtQ(-b/a, -d/c))) cons623 = CustomConstraint(cons_f623) def cons_f624(m, n, p, q): return IntegersQ(p + (m + S(1))/n, q) cons624 = CustomConstraint(cons_f624) def cons_f625(m, n): return Or(ZeroQ(m - n), ZeroQ(m - S(2)*n + S(1))) cons625 = CustomConstraint(cons_f625) def cons_f626(m, p, q): return IntegersQ(m, p, q) cons626 = CustomConstraint(cons_f626) def cons_f627(p): return GreaterEqual(p, S(-2)) cons627 = CustomConstraint(cons_f627) def cons_f628(m, q): return Or(GreaterEqual(q, S(-2)), And(Equal(q, S(-3)), IntegerQ(m/S(2) + S(-1)/2))) cons628 = CustomConstraint(cons_f628) def cons_f629(m, n): return NonzeroQ(m - n + S(1)) cons629 = CustomConstraint(cons_f629) def cons_f630(p, q, r): return PositiveIntegerQ(p, q, r) cons630 = CustomConstraint(cons_f630) def cons_f631(a, b, c, d, e, f, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, n), x) cons631 = CustomConstraint(cons_f631) def cons_f632(a, b, c, d, n): return Not(And(ZeroQ(n + S(-2)), Or(And(PosQ(b/a), PosQ(d/c)), And(NegQ(b/a), Or(PosQ(d/c), And(PositiveQ(a), Or(Not(PositiveQ(c)), SimplerSqrtQ(-b/a, -d/c)))))))) cons632 = CustomConstraint(cons_f632) def cons_f633(n, p, q): return NonzeroQ(n*(p + q + S(1)) + S(1)) cons633 = CustomConstraint(cons_f633) def cons_f634(a, b, c, d, e, f, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, p, n), x) cons634 = CustomConstraint(cons_f634) def cons_f635(a, b, c, d, e, f, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, n, p, q), x) cons635 = CustomConstraint(cons_f635) def cons_f636(c, d): return PositiveQ(d/c) cons636 = CustomConstraint(cons_f636) def cons_f637(e, f): return PositiveQ(f/e) cons637 = CustomConstraint(cons_f637) def cons_f638(c, d, e, f): return Not(SimplerSqrtQ(d/c, f/e)) cons638 = CustomConstraint(cons_f638) def cons_f639(c, d, e, f): return Not(SimplerSqrtQ(-f/e, -d/c)) cons639 = CustomConstraint(cons_f639) def cons_f640(e, f): return PosQ(f/e) cons640 = CustomConstraint(cons_f640) def cons_f641(c, d, e, f): return Not(And(NegQ(f/e), SimplerSqrtQ(-f/e, -d/c))) cons641 = CustomConstraint(cons_f641) def cons_f642(q, r): return RationalQ(q, r) cons642 = CustomConstraint(cons_f642) def cons_f643(r): return Greater(r, S(1)) cons643 = CustomConstraint(cons_f643) def cons_f644(q): return LessEqual(q, S(-1)) cons644 = CustomConstraint(cons_f644) def cons_f645(c, d, e, f): return PosQ((-c*f + d*e)/c) cons645 = CustomConstraint(cons_f645) def cons_f646(c, d, e, f): return NegQ((-c*f + d*e)/c) cons646 = CustomConstraint(cons_f646) def cons_f647(a, b, c, d, e, f, n, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, n, p, q, r), x) cons647 = CustomConstraint(cons_f647) def cons_f648(u, v): return ZeroQ(u - v) cons648 = CustomConstraint(cons_f648) def cons_f649(u, w): return ZeroQ(u - w) cons649 = CustomConstraint(cons_f649) def cons_f650(r): return IntegerQ(r) cons650 = CustomConstraint(cons_f650) def cons_f651(n, n2): return ZeroQ(-n/S(2) + n2) cons651 = CustomConstraint(cons_f651) def cons_f652(e1, e2, f1, f2): return ZeroQ(e1*f2 + e2*f1) cons652 = CustomConstraint(cons_f652) def cons_f653(e1, e2, r): return Or(IntegerQ(r), And(PositiveQ(e1), PositiveQ(e2))) cons653 = CustomConstraint(cons_f653) def cons_f654(e1, x): return FreeQ(e1, x) cons654 = CustomConstraint(cons_f654) def cons_f655(f1, x): return FreeQ(f1, x) cons655 = CustomConstraint(cons_f655) def cons_f656(e2, x): return FreeQ(e2, x) cons656 = CustomConstraint(cons_f656) def cons_f657(f2, x): return FreeQ(f2, x) cons657 = CustomConstraint(cons_f657) def cons_f658(g, m): return Or(IntegerQ(m), PositiveQ(g)) cons658 = CustomConstraint(cons_f658) def cons_f659(p, q, r): return PositiveIntegerQ(p + S(2), q, r) cons659 = CustomConstraint(cons_f659) def cons_f660(p, q, r): return IntegersQ(p, q, r) cons660 = CustomConstraint(cons_f660) def cons_f661(a, b, c, d, e, f, q): return Not(And(Equal(q, S(1)), SimplerQ(-a*d + b*c, -a*f + b*e))) cons661 = CustomConstraint(cons_f661) def cons_f662(c, d, e, f, n, q, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(Equal(q, S(1)), SimplerQ(e + f*x**n, c + d*x**n))) cons662 = CustomConstraint(cons_f662) def cons_f663(r): return PositiveIntegerQ(r) cons663 = CustomConstraint(cons_f663) def cons_f664(a, b, c, d, e, f, g, m, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, m, n, p, q), x) cons664 = CustomConstraint(cons_f664) def cons_f665(a, b, c, d, e, f, g, m, n, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, m, n, p, q, r), x) cons665 = CustomConstraint(cons_f665) def cons_f666(n, p): return ZeroQ(n*(S(2)*p + S(1)) + S(1)) cons666 = CustomConstraint(cons_f666) def cons_f667(n, p): return ZeroQ(S(2)*n*(p + S(1)) + S(1)) cons667 = CustomConstraint(cons_f667) def cons_f668(n, p): return Or(ZeroQ(S(2)*n*p + S(1)), ZeroQ(n*(S(2)*p + S(-1)) + S(1))) cons668 = CustomConstraint(cons_f668) def cons_f669(p): return IntegerQ(p + S(1)/2) cons669 = CustomConstraint(cons_f669) def cons_f670(n): return NonzeroQ(S(2)*n + S(1)) cons670 = CustomConstraint(cons_f670) def cons_f671(n, p): return NonzeroQ(S(2)*n*p + S(1)) cons671 = CustomConstraint(cons_f671) def cons_f672(n, p): return NonzeroQ(n*(S(2)*p + S(-1)) + S(1)) cons672 = CustomConstraint(cons_f672) def cons_f673(n, p): return NonzeroQ(n*(S(2)*p + S(1)) + S(1)) cons673 = CustomConstraint(cons_f673) def cons_f674(n, p): return NonzeroQ(S(2)*n*(p + S(1)) + S(1)) cons674 = CustomConstraint(cons_f674) def cons_f675(n, p): return Or(IntegerQ(p), ZeroQ(n + S(-2))) cons675 = CustomConstraint(cons_f675) def cons_f676(n): return PositiveIntegerQ(n/S(2)) cons676 = CustomConstraint(cons_f676) def cons_f677(a, b, c): return PositiveQ(-S(4)*a*c + b**S(2)) cons677 = CustomConstraint(cons_f677) def cons_f678(a, c): return PositiveQ(c/a) cons678 = CustomConstraint(cons_f678) def cons_f679(a, b): return NegativeQ(b/a) cons679 = CustomConstraint(cons_f679) def cons_f680(a, c): return PosQ(c/a) cons680 = CustomConstraint(cons_f680) def cons_f681(a, c): return NegQ(c/a) cons681 = CustomConstraint(cons_f681) def cons_f682(n, n2): return EqQ(n2, S(2)*n) cons682 = CustomConstraint(cons_f682) def cons_f683(n): return PosQ(n) cons683 = CustomConstraint(cons_f683) def cons_f684(m, n, p): return ZeroQ(m + n*(S(2)*p + S(1)) + S(1)) cons684 = CustomConstraint(cons_f684) def cons_f685(m, n): return NonzeroQ(m + n + S(1)) cons685 = CustomConstraint(cons_f685) def cons_f686(m, n, p): return ZeroQ(m + S(2)*n*(p + S(1)) + S(1)) cons686 = CustomConstraint(cons_f686) def cons_f687(m, n): return Inequality(S(-1), LessEqual, m + n, Less, S(0)) cons687 = CustomConstraint(cons_f687) def cons_f688(m, n): return Less(m + n, S(-1)) cons688 = CustomConstraint(cons_f688) def cons_f689(m, n, p): return Not(And(NegativeIntegerQ((m + S(2)*n*(p + S(1)) + S(1))/n), Greater(p + (m + S(2)*n*(p + S(1)) + S(1))/n, S(0)))) cons689 = CustomConstraint(cons_f689) def cons_f690(m, n, p): return NonzeroQ(m + n*(S(2)*p + S(-1)) + S(1)) cons690 = CustomConstraint(cons_f690) def cons_f691(m, n, p): return Not(And(PositiveIntegerQ(m), IntegerQ((m + S(1))/n), Less(S(-1) + (m + S(1))/n, S(2)*p))) cons691 = CustomConstraint(cons_f691) def cons_f692(m, n): return Inequality(n + S(-1), Less, m, LessEqual, S(2)*n + S(-1)) cons692 = CustomConstraint(cons_f692) def cons_f693(m, n, p): return Or(IntegerQ(S(2)*p), PositiveIntegerQ((m + S(1))/n)) cons693 = CustomConstraint(cons_f693) def cons_f694(m, n, p): return Unequal(m + S(2)*n*p + S(1), S(0)) cons694 = CustomConstraint(cons_f694) def cons_f695(m, n, p): return Unequal(m + n*(S(2)*p + S(-1)) + S(1), S(0)) cons695 = CustomConstraint(cons_f695) def cons_f696(m, n, p): return Or(IntegerQ(p), And(IntegerQ(S(2)*p), IntegerQ(m), Equal(n, S(2)))) cons696 = CustomConstraint(cons_f696) def cons_f697(m, n): return Greater(m, S(3)*n + S(-1)) cons697 = CustomConstraint(cons_f697) def cons_f698(a, b, c): return NegativeQ(-S(4)*a*c + b**S(2)) cons698 = CustomConstraint(cons_f698) def cons_f699(a, c): return PosQ(a*c) cons699 = CustomConstraint(cons_f699) def cons_f700(m, n): return PositiveIntegerQ(n/S(2), m) cons700 = CustomConstraint(cons_f700) def cons_f701(m, n): return Inequality(S(3)*n/S(2), LessEqual, m, Less, S(2)*n) cons701 = CustomConstraint(cons_f701) def cons_f702(m, n): return Inequality(n/S(2), LessEqual, m, Less, S(3)*n/S(2)) cons702 = CustomConstraint(cons_f702) def cons_f703(m, n): return GreaterEqual(m, n) cons703 = CustomConstraint(cons_f703) def cons_f704(p): return NegativeIntegerQ(p + S(1)) cons704 = CustomConstraint(cons_f704) def cons_f705(b, c, d, e, n, p): return ZeroQ(b*e*(n*p + S(1)) - c*d*(n*(S(2)*p + S(1)) + S(1))) cons705 = CustomConstraint(cons_f705) def cons_f706(b, c, d, e, n, p): return NonzeroQ(b*e*(n*p + S(1)) - c*d*(n*(S(2)*p + S(1)) + S(1))) cons706 = CustomConstraint(cons_f706) def cons_f707(a, c, d, e): return ZeroQ(-a*e**S(2) + c*d**S(2)) cons707 = CustomConstraint(cons_f707) def cons_f708(d, e): return PosQ(d*e) cons708 = CustomConstraint(cons_f708) def cons_f709(d, e): return NegQ(d*e) cons709 = CustomConstraint(cons_f709) def cons_f710(a, c, d, e): return NonzeroQ(-a*e**S(2) + c*d**S(2)) cons710 = CustomConstraint(cons_f710) def cons_f711(a, c): return NegQ(a*c) cons711 = CustomConstraint(cons_f711) def cons_f712(a, c, n): return Or(PosQ(a*c), Not(IntegerQ(n))) cons712 = CustomConstraint(cons_f712) def cons_f713(a, b, c, d, e): return Or(PositiveQ(-b/c + S(2)*d/e), And(Not(NegativeQ(-b/c + S(2)*d/e)), ZeroQ(d - e*Rt(a/c, S(2))))) cons713 = CustomConstraint(cons_f713) def cons_f714(a, b, c): return Not(PositiveQ(-S(4)*a*c + b**S(2))) cons714 = CustomConstraint(cons_f714) def cons_f715(a, b, c, n): return Or(PosQ(-S(4)*a*c + b**S(2)), Not(PositiveIntegerQ(n/S(2)))) cons715 = CustomConstraint(cons_f715) def cons_f716(n, p): return NonzeroQ(S(2)*n*p + n + S(1)) cons716 = CustomConstraint(cons_f716) def cons_f717(a, c): return PositiveQ(-a*c) cons717 = CustomConstraint(cons_f717) def cons_f718(n, p, q): return NonzeroQ(S(2)*n*p + n*q + S(1)) cons718 = CustomConstraint(cons_f718) def cons_f719(p): return PositiveIntegerQ(p + S(-1)/2) cons719 = CustomConstraint(cons_f719) def cons_f720(c): return Not(NegativeQ(c)) cons720 = CustomConstraint(cons_f720) def cons_f721(p): return NegativeIntegerQ(p + S(1)/2) cons721 = CustomConstraint(cons_f721) def cons_f722(b, c, d, e): return ZeroQ(-b*e + c*d) cons722 = CustomConstraint(cons_f722) def cons_f723(a, d): return Not(And(PositiveQ(a), PositiveQ(d))) cons723 = CustomConstraint(cons_f723) def cons_f724(n, p, q): return Or(And(IntegersQ(p, q), Not(IntegerQ(n))), PositiveIntegerQ(p), And(PositiveIntegerQ(q), Not(IntegerQ(n)))) cons724 = CustomConstraint(cons_f724) def cons_f725(n, p): return Not(IntegersQ(n, S(2)*p)) cons725 = CustomConstraint(cons_f725) def cons_f726(n, q): return Not(IntegersQ(n, q)) cons726 = CustomConstraint(cons_f726) def cons_f727(mn, n2): return EqQ(n2, -S(2)*mn) cons727 = CustomConstraint(cons_f727) def cons_f728(mn, x): return FreeQ(mn, x) cons728 = CustomConstraint(cons_f728) def cons_f729(n2): return PosQ(n2) cons729 = CustomConstraint(cons_f729) def cons_f730(n2): return NegQ(n2) cons730 = CustomConstraint(cons_f730) def cons_f731(d1, d2, e1, e2): return ZeroQ(d1*e2 + d2*e1) cons731 = CustomConstraint(cons_f731) def cons_f732(d1, d2, q): return Or(IntegerQ(q), And(PositiveQ(d1), PositiveQ(d2))) cons732 = CustomConstraint(cons_f732) def cons_f733(d1, x): return FreeQ(d1, x) cons733 = CustomConstraint(cons_f733) def cons_f734(d2, x): return FreeQ(d2, x) cons734 = CustomConstraint(cons_f734) def cons_f735(f, m): return Or(IntegerQ(m), PositiveQ(f)) cons735 = CustomConstraint(cons_f735) def cons_f736(m, n): return PositiveIntegerQ(m, n, (m + S(1))/n) cons736 = CustomConstraint(cons_f736) def cons_f737(m, q): return IntegersQ(m, q) cons737 = CustomConstraint(cons_f737) def cons_f738(n, p): return Greater(S(2)*n*p, n + S(-1)) cons738 = CustomConstraint(cons_f738) def cons_f739(m, n, p, q): return NonzeroQ(m + S(2)*n*p + n*q + S(1)) cons739 = CustomConstraint(cons_f739) def cons_f740(m, n, p): return Unequal(m + n*(S(2)*p + S(1)) + S(1), S(0)) cons740 = CustomConstraint(cons_f740) def cons_f741(m, n, p): return NonzeroQ(m + n*(S(2)*p + S(1)) + S(1)) cons741 = CustomConstraint(cons_f741) def cons_f742(m, n): return IntegersQ(m, n/S(2)) cons742 = CustomConstraint(cons_f742) def cons_f743(d, e): return PositiveQ(d/e) cons743 = CustomConstraint(cons_f743) def cons_f744(b, c, d, e): return PosQ(c*(-b*e + S(2)*c*d)/e) cons744 = CustomConstraint(cons_f744) def cons_f745(n): return IntegerQ(n/S(2)) cons745 = CustomConstraint(cons_f745) def cons_f746(n): return Greater(n, S(2)) cons746 = CustomConstraint(cons_f746) def cons_f747(m, n): return Less(m, -n) cons747 = CustomConstraint(cons_f747) def cons_f748(m, n): return Greater(m, n) cons748 = CustomConstraint(cons_f748) def cons_f749(m, q): return Or(PositiveIntegerQ(q), IntegersQ(m, q)) cons749 = CustomConstraint(cons_f749) def cons_f750(p, q): return Or(PositiveIntegerQ(p), PositiveIntegerQ(q)) cons750 = CustomConstraint(cons_f750) def cons_f751(f, m): return Not(Or(IntegerQ(m), PositiveQ(f))) cons751 = CustomConstraint(cons_f751) def cons_f752(n, q): return ZeroQ(n - q) cons752 = CustomConstraint(cons_f752) def cons_f753(n, r): return ZeroQ(-n + r) cons753 = CustomConstraint(cons_f753) def cons_f754(n, q, r): return ZeroQ(-S(2)*n + q + r) cons754 = CustomConstraint(cons_f754) def cons_f755(n, q): return PosQ(n - q) cons755 = CustomConstraint(cons_f755) def cons_f756(n, p, q): return NonzeroQ(p*(S(2)*n - q) + S(1)) cons756 = CustomConstraint(cons_f756) def cons_f757(n, q): return ZeroQ(-n + q) cons757 = CustomConstraint(cons_f757) def cons_f758(m, n, q): return Or(And(ZeroQ(m + S(-1)), ZeroQ(n + S(-3)), ZeroQ(q + S(-2))), And(Or(ZeroQ(m + S(1)/2), ZeroQ(m + S(-3)/2), ZeroQ(m + S(-1)/2), ZeroQ(m + S(-5)/2)), ZeroQ(n + S(-3)), ZeroQ(q + S(-1)))) cons758 = CustomConstraint(cons_f758) def cons_f759(m, n): return ZeroQ(m - S(3)*n/S(2) + S(3)/2) cons759 = CustomConstraint(cons_f759) def cons_f760(n, q): return ZeroQ(-n + q + S(1)) cons760 = CustomConstraint(cons_f760) def cons_f761(n, r): return ZeroQ(-n + r + S(-1)) cons761 = CustomConstraint(cons_f761) def cons_f762(m, n): return ZeroQ(m - S(3)*n/S(2) + S(1)/2) cons762 = CustomConstraint(cons_f762) def cons_f763(m, n, p): return Equal(m + p*(n + S(-1)) + S(-1), S(0)) cons763 = CustomConstraint(cons_f763) def cons_f764(m, n, p, q): return Equal(m + p*q + S(1), n - q) cons764 = CustomConstraint(cons_f764) def cons_f765(m, n, p, q): return Greater(m + p*q + S(1), n - q) cons765 = CustomConstraint(cons_f765) def cons_f766(m, n, p, q): return Unequal(m + p*(S(2)*n - q) + S(1), S(0)) cons766 = CustomConstraint(cons_f766) def cons_f767(m, n, p, q): return Unequal(m + p*q + (n - q)*(S(2)*p + S(-1)) + S(1), S(0)) cons767 = CustomConstraint(cons_f767) def cons_f768(m, n, p, q): return LessEqual(m + p*q + S(1), -n + q + S(1)) cons768 = CustomConstraint(cons_f768) def cons_f769(m, p, q): return NonzeroQ(m + p*q + S(1)) cons769 = CustomConstraint(cons_f769) def cons_f770(m, n, p, q): return Greater(m + p*q + S(1), -n + q) cons770 = CustomConstraint(cons_f770) def cons_f771(m, n, p, q): return Equal(m + p*q + S(1), -(n - q)*(S(2)*p + S(3))) cons771 = CustomConstraint(cons_f771) def cons_f772(m, n, p, q): return Greater(m + p*q + S(1), S(2)*n - S(2)*q) cons772 = CustomConstraint(cons_f772) def cons_f773(m, n, p, q): return Less(m + p*q + S(1), n - q) cons773 = CustomConstraint(cons_f773) def cons_f774(m, n, p, q): return Less(n - q, m + p*q + S(1), S(2)*n - S(2)*q) cons774 = CustomConstraint(cons_f774) def cons_f775(p): return Inequality(S(-1), LessEqual, p, Less, S(0)) cons775 = CustomConstraint(cons_f775) def cons_f776(m, n, p, q): return Equal(m + p*q + S(1), S(2)*n - S(2)*q) cons776 = CustomConstraint(cons_f776) def cons_f777(m, n, p, q): return Equal(m + p*q + S(1), -S(2)*(n - q)*(p + S(1))) cons777 = CustomConstraint(cons_f777) def cons_f778(m, p, q): return Less(m + p*q + S(1), S(0)) cons778 = CustomConstraint(cons_f778) def cons_f779(n, q, r): return ZeroQ(-n + q + r) cons779 = CustomConstraint(cons_f779) def cons_f780(j, n, q): return ZeroQ(j - S(2)*n + q) cons780 = CustomConstraint(cons_f780) def cons_f781(j, n, q): return ZeroQ(j - n + q) cons781 = CustomConstraint(cons_f781) def cons_f782(n): return ZeroQ(n + S(-3)) cons782 = CustomConstraint(cons_f782) def cons_f783(q): return ZeroQ(q + S(-2)) cons783 = CustomConstraint(cons_f783) def cons_f784(n, p, q): return NonzeroQ(p*q + (n - q)*(S(2)*p + S(1)) + S(1)) cons784 = CustomConstraint(cons_f784) def cons_f785(m, n, p, q): return LessEqual(m + p*q, -n + q) cons785 = CustomConstraint(cons_f785) def cons_f786(m, p, q): return Unequal(m + p*q + S(1), S(0)) cons786 = CustomConstraint(cons_f786) def cons_f787(m, n, p, q): return Unequal(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1), S(0)) cons787 = CustomConstraint(cons_f787) def cons_f788(m, n, p, q): return Greater(m + p*q, n - q + S(-1)) cons788 = CustomConstraint(cons_f788) def cons_f789(m, n, p, q): return Greater(m + p*q, -n + q + S(-1)) cons789 = CustomConstraint(cons_f789) def cons_f790(m, n, p, q): return Less(m + p*q, n - q + S(-1)) cons790 = CustomConstraint(cons_f790) def cons_f791(m, n, p, q): return GreaterEqual(m + p*q, n - q + S(-1)) cons791 = CustomConstraint(cons_f791) def cons_f792(m, n, p, q): return Or(Inequality(S(-1), LessEqual, p, Less, S(0)), Equal(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1), S(0))) cons792 = CustomConstraint(cons_f792) def cons_f793(m): return Or(ZeroQ(m + S(-1)/2), ZeroQ(m + S(1)/2)) cons793 = CustomConstraint(cons_f793) def cons_f794(q): return ZeroQ(q + S(-1)) cons794 = CustomConstraint(cons_f794) def cons_f795(j, k, q): return ZeroQ(j - k + q) cons795 = CustomConstraint(cons_f795) def cons_f796(j, k, n): return ZeroQ(j - S(2)*k + n) cons796 = CustomConstraint(cons_f796) def cons_f797(j, k): return PosQ(-j + k) cons797 = CustomConstraint(cons_f797) def cons_f798(j, x): return FreeQ(j, x) cons798 = CustomConstraint(cons_f798) def cons_f799(k, x): return FreeQ(k, x) cons799 = CustomConstraint(cons_f799) def cons_f800(n, q): return IntegerQ(n*q) cons800 = CustomConstraint(cons_f800) def cons_f801(a, b, c, d, e, f, m, n, p, q, r, s, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, m, n, p, q, r, s), x) cons801 = CustomConstraint(cons_f801) def cons_f802(s, x): return FreeQ(s, x) cons802 = CustomConstraint(cons_f802) def cons_f803(b, d, e): return PositiveQ(b*d*e) cons803 = CustomConstraint(cons_f803) def cons_f804(a, b, c, d): return PositiveQ(-a*d/b + c) cons804 = CustomConstraint(cons_f804) def cons_f805(n): return IntegerQ(S(1)/n) cons805 = CustomConstraint(cons_f805) def cons_f806(u, x): if isinstance(x, (int, Integer, float, Float)): return False return PolynomialQ(u, x) cons806 = CustomConstraint(cons_f806) def cons_f807(m, r): return IntegersQ(m, r) cons807 = CustomConstraint(cons_f807) def cons_f808(a, b, c, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, n, p), x) cons808 = CustomConstraint(cons_f808) def cons_f809(n, n2): return ZeroQ(S(2)*n + n2) cons809 = CustomConstraint(cons_f809) def cons_f810(n): return IntegerQ(S(2)*n) cons810 = CustomConstraint(cons_f810) def cons_f811(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(LinearMatchQ(u, x)) cons811 = CustomConstraint(cons_f811) def cons_f812(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(List(u, v), x) cons812 = CustomConstraint(cons_f812) def cons_f813(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(LinearMatchQ(List(u, v), x)) cons813 = CustomConstraint(cons_f813) def cons_f814(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(List(u, v, w), x) cons814 = CustomConstraint(cons_f814) def cons_f815(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(LinearMatchQ(List(u, v, w), x)) cons815 = CustomConstraint(cons_f815) def cons_f816(u, v, w, x, z): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(List(u, v, w, z), x) cons816 = CustomConstraint(cons_f816) def cons_f817(u, v, w, x, z): if isinstance(x, (int, Integer, float, Float)): return False return Not(LinearMatchQ(List(u, v, w, z), x)) cons817 = CustomConstraint(cons_f817) def cons_f818(u, x): if isinstance(x, (int, Integer, float, Float)): return False return QuadraticQ(u, x) cons818 = CustomConstraint(cons_f818) def cons_f819(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(QuadraticMatchQ(u, x)) cons819 = CustomConstraint(cons_f819) def cons_f820(v, x): if isinstance(x, (int, Integer, float, Float)): return False return QuadraticQ(v, x) cons820 = CustomConstraint(cons_f820) def cons_f821(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(u, x), QuadraticMatchQ(v, x))) cons821 = CustomConstraint(cons_f821) def cons_f822(w, x): if isinstance(x, (int, Integer, float, Float)): return False return QuadraticQ(w, x) cons822 = CustomConstraint(cons_f822) def cons_f823(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(List(u, v), x), QuadraticMatchQ(w, x))) cons823 = CustomConstraint(cons_f823) def cons_f824(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(QuadraticMatchQ(List(u, v), x)) cons824 = CustomConstraint(cons_f824) def cons_f825(u, x): if isinstance(x, (int, Integer, float, Float)): return False return BinomialQ(u, x) cons825 = CustomConstraint(cons_f825) def cons_f826(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(BinomialMatchQ(u, x)) cons826 = CustomConstraint(cons_f826) def cons_f827(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return BinomialQ(List(u, v), x) cons827 = CustomConstraint(cons_f827) def cons_f828(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: return ZeroQ(BinomialDegree(u, x) - BinomialDegree(v, x)) except (TypeError, AttributeError): return False cons828 = CustomConstraint(cons_f828) def cons_f829(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(BinomialMatchQ(List(u, v), x)) cons829 = CustomConstraint(cons_f829) def cons_f830(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return BinomialQ(List(u, v, w), x) cons830 = CustomConstraint(cons_f830) def cons_f831(u, w, x): if isinstance(x, (int, Integer, float, Float)): return False try: return ZeroQ(BinomialDegree(u, x) - BinomialDegree(w, x)) except (TypeError, AttributeError): return False cons831 = CustomConstraint(cons_f831) def cons_f832(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(BinomialMatchQ(List(u, v, w), x)) cons832 = CustomConstraint(cons_f832) def cons_f833(u, v, x, z): if isinstance(x, (int, Integer, float, Float)): return False return BinomialQ(List(u, v, z), x) cons833 = CustomConstraint(cons_f833) def cons_f834(u, x, z): if isinstance(x, (int, Integer, float, Float)): return False try: return ZeroQ(BinomialDegree(u, x) - BinomialDegree(z, x)) except (TypeError, AttributeError): return False cons834 = CustomConstraint(cons_f834) def cons_f835(u, v, x, z): if isinstance(x, (int, Integer, float, Float)): return False return Not(BinomialMatchQ(List(u, v, z), x)) cons835 = CustomConstraint(cons_f835) def cons_f836(u, x): if isinstance(x, (int, Integer, float, Float)): return False return GeneralizedBinomialQ(u, x) cons836 = CustomConstraint(cons_f836) def cons_f837(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(GeneralizedBinomialMatchQ(u, x)) cons837 = CustomConstraint(cons_f837) def cons_f838(u, x): if isinstance(x, (int, Integer, float, Float)): return False return TrinomialQ(u, x) cons838 = CustomConstraint(cons_f838) def cons_f839(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(TrinomialMatchQ(u, x)) cons839 = CustomConstraint(cons_f839) def cons_f840(v, x): if isinstance(x, (int, Integer, float, Float)): return False return TrinomialQ(v, x) cons840 = CustomConstraint(cons_f840) def cons_f841(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(BinomialMatchQ(u, x), TrinomialMatchQ(v, x))) cons841 = CustomConstraint(cons_f841) def cons_f842(v, x): if isinstance(x, (int, Integer, float, Float)): return False return BinomialQ(v, x) cons842 = CustomConstraint(cons_f842) def cons_f843(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(BinomialMatchQ(u, x), BinomialMatchQ(v, x))) cons843 = CustomConstraint(cons_f843) def cons_f844(x, z): if isinstance(x, (int, Integer, float, Float)): return False return BinomialQ(z, x) cons844 = CustomConstraint(cons_f844) def cons_f845(u, x, z): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(BinomialMatchQ(z, x), TrinomialMatchQ(u, x))) cons845 = CustomConstraint(cons_f845) def cons_f846(u, x, z): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(BinomialMatchQ(z, x), BinomialMatchQ(u, x))) cons846 = CustomConstraint(cons_f846) def cons_f847(u, x): if isinstance(x, (int, Integer, float, Float)): return False return GeneralizedTrinomialQ(u, x) cons847 = CustomConstraint(cons_f847) def cons_f848(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(GeneralizedTrinomialMatchQ(u, x)) cons848 = CustomConstraint(cons_f848) def cons_f849(u, x, z): if isinstance(x, (int, Integer, float, Float)): return False try: return ZeroQ(BinomialDegree(z, x) - GeneralizedTrinomialDegree(u, x)) except (TypeError, AttributeError): return False cons849 = CustomConstraint(cons_f849) def cons_f850(u, x, z): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(BinomialMatchQ(z, x), GeneralizedTrinomialMatchQ(u, x))) cons850 = CustomConstraint(cons_f850) def cons_f851(n, q): return ZeroQ(-n/S(4) + q) cons851 = CustomConstraint(cons_f851) def cons_f852(n, r): return ZeroQ(-S(3)*n/S(4) + r) cons852 = CustomConstraint(cons_f852) def cons_f853(m, n): return ZeroQ(S(4)*m - n + S(4)) cons853 = CustomConstraint(cons_f853) def cons_f854(a, c, e, h): return ZeroQ(a*h + c*e) cons854 = CustomConstraint(cons_f854) def cons_f855(m): return NegativeIntegerQ(m + S(1)) cons855 = CustomConstraint(cons_f855) def cons_f856(m, n): return PositiveIntegerQ(n/(m + S(1))) cons856 = CustomConstraint(cons_f856) def cons_f857(Pq, m, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(Pq, x**(m + S(1))) cons857 = CustomConstraint(cons_f857) def cons_f858(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return NonzeroQ(Coeff(Pq, x, n + S(-1))) cons858 = CustomConstraint(cons_f858) def cons_f859(n, p): return Or(PositiveIntegerQ(p), ZeroQ(n + S(-1))) cons859 = CustomConstraint(cons_f859) def cons_f860(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(Pq, x**n) cons860 = CustomConstraint(cons_f860) def cons_f861(Pq, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(Coeff(Pq, x, S(0))) cons861 = CustomConstraint(cons_f861) def cons_f862(Pq): return SumQ(Pq) cons862 = CustomConstraint(cons_f862) def cons_f863(Pq, m, x): if isinstance(x, (int, Integer, float, Float)): return False return Less(m + Expon(Pq, x) + S(1), S(0)) cons863 = CustomConstraint(cons_f863) def cons_f864(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Less(Expon(Pq, x), n + S(-1)) cons864 = CustomConstraint(cons_f864) def cons_f865(a, b, d, g): return ZeroQ(a*g + b*d) cons865 = CustomConstraint(cons_f865) def cons_f866(a, b, e, h): return ZeroQ(-S(3)*a*h + b*e) cons866 = CustomConstraint(cons_f866) def cons_f867(A, B, a, b): return ZeroQ(-A**S(3)*b + B**S(3)*a) cons867 = CustomConstraint(cons_f867) def cons_f868(A, B, a, b): return NonzeroQ(-A**S(3)*b + B**S(3)*a) cons868 = CustomConstraint(cons_f868) def cons_f869(A, B, C): return ZeroQ(-A*C + B**S(2)) cons869 = CustomConstraint(cons_f869) def cons_f870(B, C, a, b): return ZeroQ(B**S(3)*b + C**S(3)*a) cons870 = CustomConstraint(cons_f870) def cons_f871(A, B, C, a, b): return ZeroQ(A*b**(S(2)/3) - B*a**(S(1)/3)*b**(S(1)/3) - S(2)*C*a**(S(2)/3)) cons871 = CustomConstraint(cons_f871) def cons_f872(B, C, a, b): return ZeroQ(B*a**(S(1)/3)*b**(S(1)/3) + S(2)*C*a**(S(2)/3)) cons872 = CustomConstraint(cons_f872) def cons_f873(A, C, a, b): return ZeroQ(A*b**(S(2)/3) - S(2)*C*a**(S(2)/3)) cons873 = CustomConstraint(cons_f873) def cons_f874(A, B, C, a, b): return ZeroQ(A*(-b)**(S(2)/3) - B*(-a)**(S(1)/3)*(-b)**(S(1)/3) - S(2)*C*(-a)**(S(2)/3)) cons874 = CustomConstraint(cons_f874) def cons_f875(B, C, a, b): return ZeroQ(B*(-a)**(S(1)/3)*(-b)**(S(1)/3) + S(2)*C*(-a)**(S(2)/3)) cons875 = CustomConstraint(cons_f875) def cons_f876(A, C, a, b): return ZeroQ(A*(-b)**(S(2)/3) - S(2)*C*(-a)**(S(2)/3)) cons876 = CustomConstraint(cons_f876) def cons_f877(A, B, C, a, b): return ZeroQ(A*b**(S(2)/3) + B*b**(S(1)/3)*(-a)**(S(1)/3) - S(2)*C*(-a)**(S(2)/3)) cons877 = CustomConstraint(cons_f877) def cons_f878(B, C, a, b): return ZeroQ(B*b**(S(1)/3)*(-a)**(S(1)/3) - S(2)*C*(-a)**(S(2)/3)) cons878 = CustomConstraint(cons_f878) def cons_f879(A, C, a, b): return ZeroQ(A*b**(S(2)/3) - S(2)*C*(-a)**(S(2)/3)) cons879 = CustomConstraint(cons_f879) def cons_f880(A, B, C, a, b): return ZeroQ(A*(-b)**(S(2)/3) + B*a**(S(1)/3)*(-b)**(S(1)/3) - S(2)*C*a**(S(2)/3)) cons880 = CustomConstraint(cons_f880) def cons_f881(B, C, a, b): return ZeroQ(B*a**(S(1)/3)*(-b)**(S(1)/3) - S(2)*C*a**(S(2)/3)) cons881 = CustomConstraint(cons_f881) def cons_f882(A, C, a, b): return ZeroQ(A*(-b)**(S(2)/3) - S(2)*C*a**(S(2)/3)) cons882 = CustomConstraint(cons_f882) def cons_f883(A, B, C, a, b): return ZeroQ(A - B*(a/b)**(S(1)/3) - S(2)*C*(a/b)**(S(2)/3)) cons883 = CustomConstraint(cons_f883) def cons_f884(B, C, a, b): return ZeroQ(B*(a/b)**(S(1)/3) + S(2)*C*(a/b)**(S(2)/3)) cons884 = CustomConstraint(cons_f884) def cons_f885(A, C, a, b): return ZeroQ(A - S(2)*C*(a/b)**(S(2)/3)) cons885 = CustomConstraint(cons_f885) def cons_f886(A, B, C, a, b): return ZeroQ(A - B*Rt(a/b, S(3)) - S(2)*C*Rt(a/b, S(3))**S(2)) cons886 = CustomConstraint(cons_f886) def cons_f887(B, C, a, b): return ZeroQ(B*Rt(a/b, S(3)) + S(2)*C*Rt(a/b, S(3))**S(2)) cons887 = CustomConstraint(cons_f887) def cons_f888(A, C, a, b): return ZeroQ(A - S(2)*C*Rt(a/b, S(3))**S(2)) cons888 = CustomConstraint(cons_f888) def cons_f889(A, B, C, a, b): return ZeroQ(A + B*(-a/b)**(S(1)/3) - S(2)*C*(-a/b)**(S(2)/3)) cons889 = CustomConstraint(cons_f889) def cons_f890(B, C, a, b): return ZeroQ(B*(-a/b)**(S(1)/3) - S(2)*C*(-a/b)**(S(2)/3)) cons890 = CustomConstraint(cons_f890) def cons_f891(A, C, a, b): return ZeroQ(A - S(2)*C*(-a/b)**(S(2)/3)) cons891 = CustomConstraint(cons_f891) def cons_f892(A, B, C, a, b): return ZeroQ(A + B*Rt(-a/b, S(3)) - S(2)*C*Rt(-a/b, S(3))**S(2)) cons892 = CustomConstraint(cons_f892) def cons_f893(B, C, a, b): return ZeroQ(B*Rt(-a/b, S(3)) - S(2)*C*Rt(-a/b, S(3))**S(2)) cons893 = CustomConstraint(cons_f893) def cons_f894(A, C, a, b): return ZeroQ(A - S(2)*C*Rt(-a/b, S(3))**S(2)) cons894 = CustomConstraint(cons_f894) def cons_f895(A, B, a, b): return Or(ZeroQ(-A**S(3)*b + B**S(3)*a), Not(RationalQ(a/b))) cons895 = CustomConstraint(cons_f895) def cons_f896(a, b): return Not(RationalQ(a/b)) cons896 = CustomConstraint(cons_f896) def cons_f897(A, C, a, b): return Not(RationalQ(a, b, A, C)) cons897 = CustomConstraint(cons_f897) def cons_f898(A, B, C, a, b): return ZeroQ(A - B*(a/b)**(S(1)/3) + C*(a/b)**(S(2)/3)) cons898 = CustomConstraint(cons_f898) def cons_f899(B, C, a, b): return ZeroQ(B*(a/b)**(S(1)/3) - C*(a/b)**(S(2)/3)) cons899 = CustomConstraint(cons_f899) def cons_f900(A, C, a, b): return ZeroQ(A + C*(a/b)**(S(2)/3)) cons900 = CustomConstraint(cons_f900) def cons_f901(A, B, C, a, b): return ZeroQ(A + B*(-a/b)**(S(1)/3) + C*(-a/b)**(S(2)/3)) cons901 = CustomConstraint(cons_f901) def cons_f902(B, C, a, b): return ZeroQ(B*(-a/b)**(S(1)/3) + C*(-a/b)**(S(2)/3)) cons902 = CustomConstraint(cons_f902) def cons_f903(A, C, a, b): return ZeroQ(A + C*(-a/b)**(S(2)/3)) cons903 = CustomConstraint(cons_f903) def cons_f904(a, b): return RationalQ(a/b) cons904 = CustomConstraint(cons_f904) def cons_f905(a, b): return Greater(a/b, S(0)) cons905 = CustomConstraint(cons_f905) def cons_f906(a, b): return Less(a/b, S(0)) cons906 = CustomConstraint(cons_f906) def cons_f907(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Less(Expon(Pq, x), n) cons907 = CustomConstraint(cons_f907) def cons_f908(a, b, c, d): return ZeroQ(c*Rt(b/a, S(3)) - d*(S(1) - sqrt(S(3)))) cons908 = CustomConstraint(cons_f908) def cons_f909(a, b, c, d): return NonzeroQ(c*Rt(b/a, S(3)) - d*(S(1) - sqrt(S(3)))) cons909 = CustomConstraint(cons_f909) def cons_f910(a, b, c, d): return ZeroQ(c*Rt(b/a, S(3)) - d*(S(1) + sqrt(S(3)))) cons910 = CustomConstraint(cons_f910) def cons_f911(a, b, c, d): return NonzeroQ(c*Rt(b/a, S(3)) - d*(S(1) + sqrt(S(3)))) cons911 = CustomConstraint(cons_f911) def cons_f912(a, b, c, d): return ZeroQ(S(2)*c*Rt(b/a, S(3))**S(2) - d*(S(1) - sqrt(S(3)))) cons912 = CustomConstraint(cons_f912) def cons_f913(a, b, c, d): return NonzeroQ(S(2)*c*Rt(b/a, S(3))**S(2) - d*(S(1) - sqrt(S(3)))) cons913 = CustomConstraint(cons_f913) def cons_f914(a, b, c, d): return ZeroQ(-a*d**S(4) + b*c**S(4)) cons914 = CustomConstraint(cons_f914) def cons_f915(a, b, c, d): return NonzeroQ(-a*d**S(4) + b*c**S(4)) cons915 = CustomConstraint(cons_f915) def cons_f916(Pq, x): if isinstance(x, (int, Integer, float, Float)): return False return NonzeroQ(Coeff(Pq, x, S(0))) cons916 = CustomConstraint(cons_f916) def cons_f917(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(PolyQ(Pq, x**(n/S(2)))) cons917 = CustomConstraint(cons_f917) def cons_f918(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Equal(Expon(Pq, x), n + S(-1)) cons918 = CustomConstraint(cons_f918) def cons_f919(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return LessEqual(n + S(-1), Expon(Pq, x)) cons919 = CustomConstraint(cons_f919) def cons_f920(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(PolyQ(Pq, x), PolyQ(Pq, x**n)) cons920 = CustomConstraint(cons_f920) def cons_f921(Pq, n, v): return PolyQ(Pq, v**n) cons921 = CustomConstraint(cons_f921) def cons_f922(a, b, c, d, e, f, n, p): return ZeroQ(a*c*f - e*(a*d + b*c)*(n*(p + S(1)) + S(1))) cons922 = CustomConstraint(cons_f922) def cons_f923(a, b, c, d, e, g, n, p): return ZeroQ(a*c*g - b*d*e*(S(2)*n*(p + S(1)) + S(1))) cons923 = CustomConstraint(cons_f923) def cons_f924(n, p): return ZeroQ(n*(p + S(1)) + S(1)) cons924 = CustomConstraint(cons_f924) def cons_f925(a, b, c, d, e, f, m, n, p): return ZeroQ(a*c*f*(m + S(1)) - e*(a*d + b*c)*(m + n*(p + S(1)) + S(1))) cons925 = CustomConstraint(cons_f925) def cons_f926(a, b, c, d, e, g, m, n, p): return ZeroQ(a*c*g*(m + S(1)) - b*d*e*(m + S(2)*n*(p + S(1)) + S(1))) cons926 = CustomConstraint(cons_f926) def cons_f927(Px, x): if isinstance(x, (int, Integer, float, Float)): return False return PolynomialQ(Px, x) cons927 = CustomConstraint(cons_f927) def cons_f928(a, b, d, e, n, p): return ZeroQ(a*e - b*d*(n*(p + S(1)) + S(1))) cons928 = CustomConstraint(cons_f928) def cons_f929(a, c, d, f, n, p): return ZeroQ(a*f - c*d*(S(2)*n*(p + S(1)) + S(1))) cons929 = CustomConstraint(cons_f929) def cons_f930(a, c, d, f): return ZeroQ(a*f + c*d) cons930 = CustomConstraint(cons_f930) def cons_f931(a, b, d, e, m, n, p): return ZeroQ(a*e*(m + S(1)) - b*d*(m + n*(p + S(1)) + S(1))) cons931 = CustomConstraint(cons_f931) def cons_f932(a, c, d, f, m, n, p): return ZeroQ(a*f*(m + S(1)) - c*d*(m + S(2)*n*(p + S(1)) + S(1))) cons932 = CustomConstraint(cons_f932) def cons_f933(n, n3): return ZeroQ(-S(3)*n + n3) cons933 = CustomConstraint(cons_f933) def cons_f934(a, b, c, d, e, g, n, p): return ZeroQ(a**S(2)*g*(n + S(1)) - c*(a*e - b*d*(n*(p + S(1)) + S(1)))*(n*(S(2)*p + S(3)) + S(1))) cons934 = CustomConstraint(cons_f934) def cons_f935(a, b, c, d, e, f, n, p): return ZeroQ(a**S(2)*f*(n + S(1)) - a*c*d*(n + S(1))*(S(2)*n*(p + S(1)) + S(1)) - b*(a*e - b*d*(n*(p + S(1)) + S(1)))*(n*(p + S(2)) + S(1))) cons935 = CustomConstraint(cons_f935) def cons_f936(a, b, c, d, g, n, p): return ZeroQ(a**S(2)*g*(n + S(1)) + b*c*d*(n*(p + S(1)) + S(1))*(n*(S(2)*p + S(3)) + S(1))) cons936 = CustomConstraint(cons_f936) def cons_f937(a, b, c, d, f, n, p): return ZeroQ(a**S(2)*f*(n + S(1)) - a*c*d*(n + S(1))*(S(2)*n*(p + S(1)) + S(1)) + b**S(2)*d*(n*(p + S(1)) + S(1))*(n*(p + S(2)) + S(1))) cons937 = CustomConstraint(cons_f937) def cons_f938(a, b, c, d, e, n, p): return ZeroQ(a*c*d*(n + S(1))*(S(2)*n*(p + S(1)) + S(1)) + b*(a*e - b*d*(n*(p + S(1)) + S(1)))*(n*(p + S(2)) + S(1))) cons938 = CustomConstraint(cons_f938) def cons_f939(a, b, c, d, n, p): return ZeroQ(a*c*d*(n + S(1))*(S(2)*n*(p + S(1)) + S(1)) - b**S(2)*d*(n*(p + S(1)) + S(1))*(n*(p + S(2)) + S(1))) cons939 = CustomConstraint(cons_f939) def cons_f940(n, q): return ZeroQ(-n/S(2) + q) cons940 = CustomConstraint(cons_f940) def cons_f941(n, r): return ZeroQ(-S(3)*n/S(2) + r) cons941 = CustomConstraint(cons_f941) def cons_f942(n, s): return ZeroQ(-S(2)*n + s) cons942 = CustomConstraint(cons_f942) def cons_f943(m, n): return ZeroQ(S(2)*m - n + S(2)) cons943 = CustomConstraint(cons_f943) def cons_f944(a, c, d, g): return ZeroQ(a*g + c*d) cons944 = CustomConstraint(cons_f944) def cons_f945(a, c, e, h): return ZeroQ(-S(3)*a*h + c*e) cons945 = CustomConstraint(cons_f945) def cons_f946(b, c, g, h): return ZeroQ(-S(2)*b*h + c*g) cons946 = CustomConstraint(cons_f946) def cons_f947(a, b, c, d, e, g): return ZeroQ(S(3)*a*g - S(2)*b*e + S(3)*c*d) cons947 = CustomConstraint(cons_f947) def cons_f948(b, c, d, e): return ZeroQ(-S(2)*b*e + S(3)*c*d) cons948 = CustomConstraint(cons_f948) def cons_f949(Pq, a, b, c, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(NiceSqrtQ(-S(4)*a*c + b**S(2)), Less(Expon(Pq, x), n)) cons949 = CustomConstraint(cons_f949) def cons_f950(c): return PosQ(c) cons950 = CustomConstraint(cons_f950) def cons_f951(c): return NegQ(c) cons951 = CustomConstraint(cons_f951) def cons_f952(Pq, n, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(PolyQ(Pq, x**n)) cons952 = CustomConstraint(cons_f952) def cons_f953(m): return NegativeIntegerQ(m + S(-1)/2) cons953 = CustomConstraint(cons_f953) def cons_f954(j, n): return NonzeroQ(-j + n) cons954 = CustomConstraint(cons_f954) def cons_f955(j, n, p): return ZeroQ(j*p + j - n + S(1)) cons955 = CustomConstraint(cons_f955) def cons_f956(j, n, p): return NegativeIntegerQ((j - n*p - n + S(-1))/(j - n)) cons956 = CustomConstraint(cons_f956) def cons_f957(j, p): return NonzeroQ(j*p + S(1)) cons957 = CustomConstraint(cons_f957) def cons_f958(j, n, p): return RationalQ(j, n, p) cons958 = CustomConstraint(cons_f958) def cons_f959(j, n): return Less(S(0), j, n) cons959 = CustomConstraint(cons_f959) def cons_f960(j, p): return Less(j*p + S(1), S(0)) cons960 = CustomConstraint(cons_f960) def cons_f961(n, p): return NonzeroQ(n*p + S(1)) cons961 = CustomConstraint(cons_f961) def cons_f962(j, n, p): return Greater(j*p + S(1), -j + n) cons962 = CustomConstraint(cons_f962) def cons_f963(p): return PositiveIntegerQ(p + S(1)/2) cons963 = CustomConstraint(cons_f963) def cons_f964(j, p): return ZeroQ(j*p + S(1)) cons964 = CustomConstraint(cons_f964) def cons_f965(n): return NonzeroQ(n + S(-2)) cons965 = CustomConstraint(cons_f965) def cons_f966(j, n): return RationalQ(j, n) cons966 = CustomConstraint(cons_f966) def cons_f967(j, n): return Less(S(2)*n + S(-2), j, n) cons967 = CustomConstraint(cons_f967) def cons_f968(j, n): return PosQ(-j + n) cons968 = CustomConstraint(cons_f968) def cons_f969(j, n): return IntegerQ(j/n) cons969 = CustomConstraint(cons_f969) def cons_f970(j, m, n, p): return ZeroQ(-j + m + n*p + n + S(1)) cons970 = CustomConstraint(cons_f970) def cons_f971(c, j): return Or(IntegerQ(j), PositiveQ(c)) cons971 = CustomConstraint(cons_f971) def cons_f972(j, m, n, p): return NegativeIntegerQ((j - m - n*p - n + S(-1))/(j - n)) cons972 = CustomConstraint(cons_f972) def cons_f973(j, m, p): return NonzeroQ(j*p + m + S(1)) cons973 = CustomConstraint(cons_f973) def cons_f974(c, j, n): return Or(IntegersQ(j, n), PositiveQ(c)) cons974 = CustomConstraint(cons_f974) def cons_f975(n): return NonzeroQ(n**S(2) + S(-1)) cons975 = CustomConstraint(cons_f975) def cons_f976(j, m, n, p): return RationalQ(j, m, n, p) cons976 = CustomConstraint(cons_f976) def cons_f977(j, m, p): return Less(j*p + m + S(1), S(0)) cons977 = CustomConstraint(cons_f977) def cons_f978(j, m, n, p): return Greater(j*p + m + S(1), -j + n) cons978 = CustomConstraint(cons_f978) def cons_f979(j, m, n, p): return PositiveQ(j*p + j + m - n + S(1)) cons979 = CustomConstraint(cons_f979) def cons_f980(j, m, p): return NegativeQ(j*p + m + S(1)) cons980 = CustomConstraint(cons_f980) def cons_f981(j, m, p): return ZeroQ(j*p + m + S(1)) cons981 = CustomConstraint(cons_f981) def cons_f982(j, m): return ZeroQ(-j/S(2) + m + S(1)) cons982 = CustomConstraint(cons_f982) def cons_f983(j, k): return NonzeroQ(-j + k) cons983 = CustomConstraint(cons_f983) def cons_f984(k, n): return IntegerQ(k/n) cons984 = CustomConstraint(cons_f984) def cons_f985(jn, j, n): return ZeroQ(jn - j - n) cons985 = CustomConstraint(cons_f985) def cons_f986(a, b, c, d, j, m, n, p): return ZeroQ(a*d*(j*p + m + S(1)) - b*c*(m + n + p*(j + n) + S(1))) cons986 = CustomConstraint(cons_f986) def cons_f987(e, j): return Or(PositiveQ(e), IntegersQ(j)) cons987 = CustomConstraint(cons_f987) def cons_f988(j, m, p): return RationalQ(j, m, p) cons988 = CustomConstraint(cons_f988) def cons_f989(j, m): return Inequality(S(0), Less, j, LessEqual, m) cons989 = CustomConstraint(cons_f989) def cons_f990(e, j): return Or(PositiveQ(e), IntegerQ(j)) cons990 = CustomConstraint(cons_f990) def cons_f991(j, m, n, p): return Or(Less(j*p + m, S(-1)), And(IntegersQ(m + S(-1)/2, p + S(-1)/2), Less(p, S(0)), Less(m, -n*p + S(-1)))) cons991 = CustomConstraint(cons_f991) def cons_f992(e, j, n): return Or(PositiveQ(e), IntegersQ(j, n)) cons992 = CustomConstraint(cons_f992) def cons_f993(j, m, n, p): return NonzeroQ(j*p + m - n + S(1)) cons993 = CustomConstraint(cons_f993) def cons_f994(j, m, n, p): return NonzeroQ(m + n + p*(j + n) + S(1)) cons994 = CustomConstraint(cons_f994) def cons_f995(j, n): return Not(And(ZeroQ(n + S(-1)), ZeroQ(j + S(-1)))) cons995 = CustomConstraint(cons_f995) def cons_f996(n): return Less(S(-1), n, S(1)) cons996 = CustomConstraint(cons_f996) def cons_f997(m): return Greater(m**S(2), S(1)) cons997 = CustomConstraint(cons_f997) def cons_f998(j, n): return PositiveIntegerQ(j, n, j/n) cons998 = CustomConstraint(cons_f998) def cons_f999(j, n): return PositiveIntegerQ(j, n) cons999 = CustomConstraint(cons_f999) def cons_f1000(j, n): return Less(j, n) cons1000 = CustomConstraint(cons_f1000) def cons_f1001(a, b, d): return ZeroQ(S(27)*a**S(2)*d + S(4)*b**S(3)) cons1001 = CustomConstraint(cons_f1001) def cons_f1002(a, b, d): return NonzeroQ(S(27)*a**S(2)*d + S(4)*b**S(3)) cons1002 = CustomConstraint(cons_f1002) def cons_f1003(a, c, d): return ZeroQ(S(27)*a*d**S(2) + S(4)*c**S(3)) cons1003 = CustomConstraint(cons_f1003) def cons_f1004(a, c, d): return NonzeroQ(S(27)*a*d**S(2) + S(4)*c**S(3)) cons1004 = CustomConstraint(cons_f1004) def cons_f1005(b, c, d): return ZeroQ(-S(3)*b*d + c**S(2)) cons1005 = CustomConstraint(cons_f1005) def cons_f1006(a, b, c): return ZeroQ(-S(3)*a*c + b**S(2)) cons1006 = CustomConstraint(cons_f1006) def cons_f1007(a, b, c): return NonzeroQ(-S(3)*a*c + b**S(2)) cons1007 = CustomConstraint(cons_f1007) def cons_f1008(b, c, d): return NonzeroQ(-S(3)*b*d + c**S(2)) cons1008 = CustomConstraint(cons_f1008) def cons_f1009(u, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(u, x, S(3)) cons1009 = CustomConstraint(cons_f1009) def cons_f1010(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(CubicMatchQ(u, x)) cons1010 = CustomConstraint(cons_f1010) def cons_f1011(v, x): if isinstance(x, (int, Integer, float, Float)): return False return PolyQ(v, x, S(3)) cons1011 = CustomConstraint(cons_f1011) def cons_f1012(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(u, x), CubicMatchQ(v, x))) cons1012 = CustomConstraint(cons_f1012) def cons_f1013(f, g): return ZeroQ(f + g) cons1013 = CustomConstraint(cons_f1013) def cons_f1014(a, c): return PosQ(a**S(2)*(S(2)*a - c)) cons1014 = CustomConstraint(cons_f1014) def cons_f1015(a, c): return NegQ(a**S(2)*(S(2)*a - c)) cons1015 = CustomConstraint(cons_f1015) def cons_f1016(b, c, d, e): return ZeroQ(S(8)*b*e**S(2) - S(4)*c*d*e + d**S(3)) cons1016 = CustomConstraint(cons_f1016) def cons_f1017(p): return UnsameQ(p, S(2)) cons1017 = CustomConstraint(cons_f1017) def cons_f1018(p): return UnsameQ(p, S(3)) cons1018 = CustomConstraint(cons_f1018) def cons_f1019(v, x): if isinstance(x, (int, Integer, float, Float)): return False return PolynomialQ(v, x) cons1019 = CustomConstraint(cons_f1019) def cons_f1020(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Equal(Exponent(v, x), S(4)) cons1020 = CustomConstraint(cons_f1020) def cons_f1021(a, b, c, d): return ZeroQ(S(8)*a**S(2)*d - S(4)*a*b*c + b**S(3)) cons1021 = CustomConstraint(cons_f1021) def cons_f1022(b, d): return ZeroQ(-b + d) cons1022 = CustomConstraint(cons_f1022) def cons_f1023(a, e): return ZeroQ(-a + e) cons1023 = CustomConstraint(cons_f1023) def cons_f1024(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False return SumQ(Factor(a*x**S(4) + a + b*x**S(3) + b*x + c*x**S(2))) cons1024 = CustomConstraint(cons_f1024) def cons_f1025(D, x): return FreeQ(D, x) cons1025 = CustomConstraint(cons_f1025) def cons_f1026(A, B, C, b, c, d, e): return ZeroQ(B**S(2)*d - S(2)*B*(S(2)*A*e + C*c) + S(2)*C*(A*d + C*b)) cons1026 = CustomConstraint(cons_f1026) def cons_f1027(A, B, C, a, c, d, e): return ZeroQ(-S(4)*A*B*C*d + S(4)*A*e*(S(2)*A*C + B**S(2)) - B**S(3)*d + S(2)*B**S(2)*C*c - S(8)*C**S(3)*a) cons1027 = CustomConstraint(cons_f1027) def cons_f1028(A, B, C, c, d, e): return PosQ(C*(C*(-S(4)*c*e + d**S(2)) + S(2)*e*(-S(4)*A*e + B*d))) cons1028 = CustomConstraint(cons_f1028) def cons_f1029(A, C, b, d): return ZeroQ(A*d + C*b) cons1029 = CustomConstraint(cons_f1029) def cons_f1030(A, C, a, e): return ZeroQ(-A**S(2)*e + C**S(2)*a) cons1030 = CustomConstraint(cons_f1030) def cons_f1031(A, C, c, d, e): return PosQ(C*(-S(8)*A*e**S(2) + C*(-S(4)*c*e + d**S(2)))) cons1031 = CustomConstraint(cons_f1031) def cons_f1032(A, B, C, c, d, e): return NegQ(C*(C*(-S(4)*c*e + d**S(2)) + S(2)*e*(-S(4)*A*e + B*d))) cons1032 = CustomConstraint(cons_f1032) def cons_f1033(A, C, c, d, e): return NegQ(C*(-S(8)*A*e**S(2) + C*(-S(4)*c*e + d**S(2)))) cons1033 = CustomConstraint(cons_f1033) def cons_f1034(A, B, C, D, b, c, d, e): return ZeroQ(S(4)*d*(-S(2)*B*e + D*c)**S(2) - S(4)*(-S(2)*B*e + D*c)*(-S(8)*A*e**S(2) - S(4)*C*c*e + S(2)*D*b*e + S(3)*D*c*d) + S(8)*(-S(4)*C*e + S(3)*D*d)*(-A*d*e - C*b*e + D*b*d)) cons1034 = CustomConstraint(cons_f1034) def cons_f1035(A, B, C, D, a, b, c, d, e): return ZeroQ(S(8)*a*(-S(4)*C*e + S(3)*D*d)**S(3) - S(8)*c*(-S(2)*B*e + D*c)**S(2)*(-S(4)*C*e + S(3)*D*d) + S(8)*d*(-S(4)*A*e + D*b)*(-S(2)*B*e + D*c)*(-S(4)*C*e + S(3)*D*d) + S(8)*d*(-S(2)*B*e + D*c)**S(3) - S(4)*e*(-S(4)*A*e + D*b)*(S(2)*(-S(4)*A*e + D*b)*(-S(4)*C*e + S(3)*D*d) + S(4)*(-S(2)*B*e + D*c)**S(2))) cons1035 = CustomConstraint(cons_f1035) def cons_f1036(A, D, b, c, d, e): return ZeroQ(D**S(2)*c**S(2)*d - D*c*(-S(8)*A*e**S(2) - S(4)*C*c*e + S(2)*D*b*e + S(3)*D*c*d) + S(2)*(-S(4)*C*e + S(3)*D*d)*(-A*d*e - C*b*e + D*b*d)) cons1036 = CustomConstraint(cons_f1036) def cons_f1037(A, B, D, a, b, c, d, e): return ZeroQ(S(54)*D**S(3)*a*d**S(3) - S(6)*D*c*d*(-S(2)*B*e + D*c)**S(2) + S(6)*D*d**S(2)*(-S(4)*A*e + D*b)*(-S(2)*B*e + D*c) + S(2)*d*(-S(2)*B*e + D*c)**S(3) - e*(-S(4)*A*e + D*b)*(S(6)*D*d*(-S(4)*A*e + D*b) + S(4)*(-S(2)*B*e + D*c)**S(2))) cons1037 = CustomConstraint(cons_f1037) def cons_f1038(a, c, e, f): return ZeroQ(a*e**S(2) - c*f**S(2)) cons1038 = CustomConstraint(cons_f1038) def cons_f1039(b, d, e, f): return ZeroQ(b*e**S(2) - d*f**S(2)) cons1039 = CustomConstraint(cons_f1039) def cons_f1040(a, c, e, f): return NonzeroQ(a*e**S(2) - c*f**S(2)) cons1040 = CustomConstraint(cons_f1040) def cons_f1041(b, d, e, f): return NonzeroQ(b*e**S(2) - d*f**S(2)) cons1041 = CustomConstraint(cons_f1041) def cons_f1042(n, p): return ZeroQ(-S(2)*n + p) cons1042 = CustomConstraint(cons_f1042) def cons_f1043(b, c, d): return ZeroQ(b*c**S(2) - d**S(2)) cons1043 = CustomConstraint(cons_f1043) def cons_f1044(b, c, d): return NonzeroQ(b*c**S(2) - d**S(2)) cons1044 = CustomConstraint(cons_f1044) def cons_f1045(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e), x) cons1045 = CustomConstraint(cons_f1045) def cons_f1046(a, b, c, d, e): return NonzeroQ(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4)) cons1046 = CustomConstraint(cons_f1046) def cons_f1047(b, c, d, e): return ZeroQ(b*d*e**S(2) + S(2)*c*d**S(3)) cons1047 = CustomConstraint(cons_f1047) def cons_f1048(b, c, d, e): return NonzeroQ(b*d*e**S(2) + S(2)*c*d**S(3)) cons1048 = CustomConstraint(cons_f1048) def cons_f1049(a, c, d, e): return NonzeroQ(a*e**S(4) + c*d**S(4)) cons1049 = CustomConstraint(cons_f1049) def cons_f1050(A, B, d, e): return ZeroQ(A*e + B*d) cons1050 = CustomConstraint(cons_f1050) def cons_f1051(A, B, a, c): return ZeroQ(A*c + B*a) cons1051 = CustomConstraint(cons_f1051) def cons_f1052(a, c, d, e): return ZeroQ(a*e + c*d) cons1052 = CustomConstraint(cons_f1052) def cons_f1053(a, b, c, d, e, f, g, h): return ZeroQ(-f**S(2)*(a*h**S(2) - b*g*h + c*g**S(2)) + (-d*h + e*g)**S(2)) cons1053 = CustomConstraint(cons_f1053) def cons_f1054(b, c, d, e, f, g, h): return ZeroQ(-S(2)*d*e*h + S(2)*e**S(2)*g - f**S(2)*(-b*h + S(2)*c*g)) cons1054 = CustomConstraint(cons_f1054) def cons_f1055(f, j, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(u, x), QuadraticMatchQ(v, x), Or(ZeroQ(j), ZeroQ(f + S(-1))))) cons1055 = CustomConstraint(cons_f1055) def cons_f1056(f, g, h, j, k, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(-f**S(2)*k**S(2)*(g**S(2)*Coefficient(v, x, S(2)) - g*h*Coefficient(v, x, S(1)) + h**S(2)*Coefficient(v, x, S(0))) + (g*Coefficient(u, x, S(1)) - h*(f*j + Coefficient(u, x, S(0))))**S(2)) cons1056 = CustomConstraint(cons_f1056) def cons_f1057(c, e, f): return ZeroQ(-c*f**S(2) + e**S(2)) cons1057 = CustomConstraint(cons_f1057) def cons_f1058(f, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(-f**S(2)*Coefficient(v, x, S(2)) + Coefficient(u, x, S(1))**S(2)) cons1058 = CustomConstraint(cons_f1058) def cons_f1059(a, c, g, i): return ZeroQ(-a*i + c*g) cons1059 = CustomConstraint(cons_f1059) def cons_f1060(m, p): return IntegersQ(p, S(2)*m) cons1060 = CustomConstraint(cons_f1060) def cons_f1061(c, i, m): return Or(IntegerQ(m), PositiveQ(i/c)) cons1061 = CustomConstraint(cons_f1061) def cons_f1062(b, c, h, i): return ZeroQ(-b*i + c*h) cons1062 = CustomConstraint(cons_f1062) def cons_f1063(c, i): return Not(PositiveQ(i/c)) cons1063 = CustomConstraint(cons_f1063) def cons_f1064(v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return QuadraticQ(List(v, w), x) cons1064 = CustomConstraint(cons_f1064) def cons_f1065(f, j, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(u, x), QuadraticMatchQ(List(v, w), x), Or(ZeroQ(j), ZeroQ(f + S(-1))))) cons1065 = CustomConstraint(cons_f1065) def cons_f1066(f, k, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(-f**S(2)*k**S(2)*Coefficient(v, x, S(2)) + Coefficient(u, x, S(1))**S(2)) cons1066 = CustomConstraint(cons_f1066) def cons_f1067(n, p): return ZeroQ(p - S(2)/n) cons1067 = CustomConstraint(cons_f1067) def cons_f1068(a, b, c): return ZeroQ(a**S(2) - b**S(2)*c) cons1068 = CustomConstraint(cons_f1068) def cons_f1069(a, b, d): return ZeroQ(a**S(2) - b**S(2)*d) cons1069 = CustomConstraint(cons_f1069) def cons_f1070(a, b, c): return ZeroQ(a + b**S(2)*c) cons1070 = CustomConstraint(cons_f1070) def cons_f1071(a, b, c, e): return ZeroQ(a + b**S(2)*c*e) cons1071 = CustomConstraint(cons_f1071) def cons_f1072(b, c, d): return ZeroQ(-b*d**S(2) + c**S(2)) cons1072 = CustomConstraint(cons_f1072) def cons_f1073(b, e): return ZeroQ(-b**S(2) + e) cons1073 = CustomConstraint(cons_f1073) def cons_f1074(a, b, c, d): return ZeroQ(-a*d + b*c, S(0)) cons1074 = CustomConstraint(cons_f1074) def cons_f1075(A, B, a, d, n): return ZeroQ(-A**S(2)*d*(n + S(-1))**S(2) + B**S(2)*a) cons1075 = CustomConstraint(cons_f1075) def cons_f1076(A, B, c, d, n): return ZeroQ(S(2)*A*d*(n + S(-1)) + B*c) cons1076 = CustomConstraint(cons_f1076) def cons_f1077(k, m): return ZeroQ(k - S(2)*m + S(-2)) cons1077 = CustomConstraint(cons_f1077) def cons_f1078(A, B, a, d, m, n): return ZeroQ(-A**S(2)*d*(m - n + S(1))**S(2) + B**S(2)*a*(m + S(1))**S(2)) cons1078 = CustomConstraint(cons_f1078) def cons_f1079(A, B, c, d, m, n): return ZeroQ(-S(2)*A*d*(m - n + S(1)) + B*c*(m + S(1))) cons1079 = CustomConstraint(cons_f1079) def cons_f1080(a, b, c, d, f, g): return ZeroQ(-S(12)*a**S(3)*g**S(2) + a**S(2)*c*f**S(2) + S(2)*a*b*g*(a*f + S(3)*c*d) + S(9)*c**S(3)*d**S(2) - c*d*f*(S(6)*a*c + b**S(2))) cons1080 = CustomConstraint(cons_f1080) def cons_f1081(a, b, c, d, e, f, g): return ZeroQ(a**S(3)*c*f**S(2)*g + S(2)*a**S(3)*g**S(2)*(-S(6)*a*g + b*f) - S(3)*a**S(2)*c**S(2)*d*f*g + S(3)*c**S(4)*d**S(2)*e - c**S(3)*d*(-S(12)*a*d*g + a*e*f + S(2)*b*d*f)) cons1081 = CustomConstraint(cons_f1081) def cons_f1082(a, c, d, f): return NonzeroQ(-a*f + S(3)*c*d) cons1082 = CustomConstraint(cons_f1082) def cons_f1083(a, b, c, d, g): return NonzeroQ(-S(2)*a**S(2)*g + b*c*d) cons1083 = CustomConstraint(cons_f1083) def cons_f1084(a, b, c, d, f, g): return NonzeroQ(S(4)*a**S(2)*g - a*b*f + b*c*d) cons1084 = CustomConstraint(cons_f1084) def cons_f1085(a, b, c, d, f, g): return PosQ((S(12)*a**S(2)*g**S(2) - a*c*f**S(2) + f*(-S(2)*a*b*g + S(3)*c**S(2)*d))/(c*g*(-a*f + S(3)*c*d))) cons1085 = CustomConstraint(cons_f1085) def cons_f1086(a, c, d, f, g): return ZeroQ(-S(12)*a**S(3)*g**S(2) + a**S(2)*c*f**S(2) - S(6)*a*c**S(2)*d*f + S(9)*c**S(3)*d**S(2)) cons1086 = CustomConstraint(cons_f1086) def cons_f1087(a, c, d, e, f, g): return ZeroQ(-S(12)*a**S(4)*g**S(3) + a**S(3)*c*f**S(2)*g - S(3)*a**S(2)*c**S(2)*d*f*g - a*c**S(3)*d*(-S(12)*d*g + e*f) + S(3)*c**S(4)*d**S(2)*e) cons1087 = CustomConstraint(cons_f1087) def cons_f1088(a, c, d, f, g): return PosQ((S(12)*a**S(2)*g**S(2) - a*c*f**S(2) + S(3)*c**S(2)*d*f)/(c*g*(-a*f + S(3)*c*d))) cons1088 = CustomConstraint(cons_f1088) def cons_f1089(v): return SumQ(v) cons1089 = CustomConstraint(cons_f1089) def cons_f1090(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(MonomialQ(u, x), BinomialQ(v, x))) cons1090 = CustomConstraint(cons_f1090) def cons_f1091(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(ZeroQ(Coefficient(u, x, S(0))), ZeroQ(Coefficient(v, x, S(0))))) cons1091 = CustomConstraint(cons_f1091) def cons_f1092(u, x): if isinstance(x, (int, Integer, float, Float)): return False return PiecewiseLinearQ(u, x) cons1092 = CustomConstraint(cons_f1092) def cons_f1093(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return PiecewiseLinearQ(u, v, x) cons1093 = CustomConstraint(cons_f1093) def cons_f1094(n): return Unequal(n, S(1)) cons1094 = CustomConstraint(cons_f1094) def cons_f1095(m, n): return Or(And(RationalQ(m, n), Less(m, S(-1)), Greater(n, S(0)), Not(And(IntegerQ(m + n), Less(m + n + S(2), S(0)), Or(FractionQ(m), GreaterEqual(m + S(2)*n + S(1), S(0)))))), And(PositiveIntegerQ(n, m), LessEqual(n, m)), And(PositiveIntegerQ(n), Not(IntegerQ(m))), And(NegativeIntegerQ(m), Not(IntegerQ(n)))) cons1095 = CustomConstraint(cons_f1095) def cons_f1096(n): return Not(RationalQ(n)) cons1096 = CustomConstraint(cons_f1096) def cons_f1097(n): return SumSimplerQ(n, S(-1)) cons1097 = CustomConstraint(cons_f1097) def cons_f1098(m): return SumSimplerQ(m, S(1)) cons1098 = CustomConstraint(cons_f1098) def cons_f1099(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(LinearQ(u, x)) cons1099 = CustomConstraint(cons_f1099) def cons_f1100(): return Not(SameQ(_UseGamma, True)) cons1100 = CustomConstraint(cons_f1100) def cons_f1101(F, x): return FreeQ(F, x) cons1101 = CustomConstraint(cons_f1101) def cons_f1102(F, b, c, d, e, f, g, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, b, c, d, e, f, g, m, n), x) cons1102 = CustomConstraint(cons_f1102) def cons_f1103(u, x): if isinstance(x, (int, Integer, float, Float)): return False return PowerOfLinearQ(u, x) cons1103 = CustomConstraint(cons_f1103) def cons_f1104(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(v, x), PowerOfLinearMatchQ(u, x))) cons1104 = CustomConstraint(cons_f1104) def cons_f1105(F, a, b, c, d, e, f, g, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b, c, d, e, f, g, m, n, p), x) cons1105 = CustomConstraint(cons_f1105) def cons_f1106(F, G, f, g, i, j, n, q): return ZeroQ(f*g*n*log(F) - i*j*q*log(G)) cons1106 = CustomConstraint(cons_f1106) def cons_f1107(F, G, e, f, g, h, i, j, k, n, q, x): if isinstance(x, (int, Integer, float, Float)): return False return NonzeroQ((G**(j*(h + i*x))*k)**q - (F**(g*(e + f*x)))**n) cons1107 = CustomConstraint(cons_f1107) def cons_f1108(F, a, b, c, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b, c, n), x) cons1108 = CustomConstraint(cons_f1108) def cons_f1109(): return SameQ(_UseGamma, True) cons1109 = CustomConstraint(cons_f1109) def cons_f1110(F, c, m, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(-c*(-Coefficient(u, x, S(0))*Coefficient(w, x, S(1)) + Coefficient(u, x, S(1))*Coefficient(w, x, S(0)))*Coefficient(v, x, S(1))*log(F) + (m + S(1))*Coefficient(u, x, S(1))*Coefficient(w, x, S(1))) cons1110 = CustomConstraint(cons_f1110) def cons_f1111(w, x): if isinstance(x, (int, Integer, float, Float)): return False return PolynomialQ(w, x) cons1111 = CustomConstraint(cons_f1111) def cons_f1112(e, f, h, n): return ZeroQ(e - f*h*(n + S(1))) cons1112 = CustomConstraint(cons_f1112) def cons_f1113(F, b, c, e, g, h, n): return ZeroQ(-b*c*e*log(F) + g*h*(n + S(1))) cons1113 = CustomConstraint(cons_f1113) def cons_f1114(e, f, h, m, n): return ZeroQ(e*(m + S(1)) - f*h*(n + S(1))) cons1114 = CustomConstraint(cons_f1114) def cons_f1115(F, a, b, c, d, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b, c, d), x) cons1115 = CustomConstraint(cons_f1115) def cons_f1116(n): return IntegerQ(S(2)/n) cons1116 = CustomConstraint(cons_f1116) def cons_f1117(n): return Not(IntegerQ(S(2)/n)) cons1117 = CustomConstraint(cons_f1117) def cons_f1118(c, d, e, f): return ZeroQ(-c*f + d*e) cons1118 = CustomConstraint(cons_f1118) def cons_f1119(m, n): return ZeroQ(-S(2)*m + n + S(-2)) cons1119 = CustomConstraint(cons_f1119) def cons_f1120(m, n): return IntegerQ(S(2)*(m + S(1))/n) cons1120 = CustomConstraint(cons_f1120) def cons_f1121(m, n): return Less(S(0), (m + S(1))/n, S(5)) cons1121 = CustomConstraint(cons_f1121) def cons_f1122(m, n): return Or(Less(S(0), n, m + S(1)), Less(m, n, S(0))) cons1122 = CustomConstraint(cons_f1122) def cons_f1123(m, n): return Less(S(-4), (m + S(1))/n, S(5)) cons1123 = CustomConstraint(cons_f1123) def cons_f1124(m, n): return Or(And(Greater(n, S(0)), Less(m, S(-1))), Inequality(S(0), Less, -n, LessEqual, m + S(1))) cons1124 = CustomConstraint(cons_f1124) def cons_f1125(d, f): return NonzeroQ(-d + f) cons1125 = CustomConstraint(cons_f1125) def cons_f1126(c, e): return NonzeroQ(c*e) cons1126 = CustomConstraint(cons_f1126) def cons_f1127(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(LinearMatchQ(u, x), BinomialMatchQ(v, x))) cons1127 = CustomConstraint(cons_f1127) def cons_f1128(v, x): if isinstance(x, (int, Integer, float, Float)): return False return PowerOfLinearQ(v, x) cons1128 = CustomConstraint(cons_f1128) def cons_f1129(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(PowerOfLinearMatchQ(v, x)) cons1129 = CustomConstraint(cons_f1129) def cons_f1130(c, d, g, h): return ZeroQ(-c*h + d*g) cons1130 = CustomConstraint(cons_f1130) def cons_f1131(c, d, g, h): return NonzeroQ(-c*h + d*g) cons1131 = CustomConstraint(cons_f1131) def cons_f1132(F, a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b, c), x) cons1132 = CustomConstraint(cons_f1132) def cons_f1133(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(QuadraticMatchQ(v, x)) cons1133 = CustomConstraint(cons_f1133) def cons_f1134(b, c, d, e): return ZeroQ(b*e - S(2)*c*d) cons1134 = CustomConstraint(cons_f1134) def cons_f1135(b, c, d, e): return NonzeroQ(b*e - S(2)*c*d) cons1135 = CustomConstraint(cons_f1135) def cons_f1136(F, a, b, c, d, e, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b, c, d, e, m), x) cons1136 = CustomConstraint(cons_f1136) def cons_f1137(c, d, e, v, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(S(2)*e*(c + d*x) - v) cons1137 = CustomConstraint(cons_f1137) def cons_f1138(F, G, a, b, c, d, e, f, g, h, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, G, a, b, c, d, e, f, g, h, n), x) cons1138 = CustomConstraint(cons_f1138) def cons_f1139(G, x): return FreeQ(G, x) cons1139 = CustomConstraint(cons_f1139) def cons_f1140(F, G, d, e, g, h): return Not(RationalQ(FullSimplify(g*h*log(G)/(d*e*log(F))))) cons1140 = CustomConstraint(cons_f1140) def cons_f1141(F, G, H, a, b, c, d, e, f, g, h, n, r, s, t, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, G, H, a, b, c, d, e, f, g, h, r, s, t, n), x) cons1141 = CustomConstraint(cons_f1141) def cons_f1142(H, x): return FreeQ(H, x) cons1142 = CustomConstraint(cons_f1142) def cons_f1143(t, x): return FreeQ(t, x) cons1143 = CustomConstraint(cons_f1143) def cons_f1144(F, G, d, e, g, h, n): return ZeroQ(d*e*n*log(F) + g*h*log(G)) cons1144 = CustomConstraint(cons_f1144) def cons_f1145(F, G, H, d, e, g, h, s, t): return Not(RationalQ(FullSimplify((g*h*log(G) + s*t*log(H))/(d*e*log(F))))) cons1145 = CustomConstraint(cons_f1145) def cons_f1146(u, v): return ZeroQ(-S(2)*u + v) cons1146 = CustomConstraint(cons_f1146) def cons_f1147(c, d, v, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(c + d*x + v) cons1147 = CustomConstraint(cons_f1147) def cons_f1148(w, x): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(w, x) cons1148 = CustomConstraint(cons_f1148) def cons_f1149(v, w): return ZeroQ(v + w) cons1149 = CustomConstraint(cons_f1149) def cons_f1150(v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return If(RationalQ(Coefficient(v, x, S(1))), Greater(Coefficient(v, x, S(1)), S(0)), Less(LeafCount(v), LeafCount(w))) cons1150 = CustomConstraint(cons_f1150) def cons_f1151(F, a, b, c, d, e, g, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b, c, d, e, g, n), x) cons1151 = CustomConstraint(cons_f1151) def cons_f1152(F, a, c, d, e, g, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, c, d, e, g, n), x) cons1152 = CustomConstraint(cons_f1152) def cons_f1153(F, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b), x) cons1153 = CustomConstraint(cons_f1153) def cons_f1154(n): return Unequal(n, S(-1)) cons1154 = CustomConstraint(cons_f1154) def cons_f1155(u, x): if isinstance(x, (int, Integer, float, Float)): return False return FunctionOfExponentialQ(u, x) cons1155 = CustomConstraint(cons_f1155) def cons_f1156(v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return LinearQ(List(v, w), x) cons1156 = CustomConstraint(cons_f1156) def cons_f1157(v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(BinomialQ(v + w, x), And(PolynomialQ(v + w, x), LessEqual(Exponent(v + w, x), S(2)))) cons1157 = CustomConstraint(cons_f1157) def cons_f1158(c, d, e, f, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, d, e, f, p, q), x) cons1158 = CustomConstraint(cons_f1158) def cons_f1159(d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(d, e, f), x) cons1159 = CustomConstraint(cons_f1159) def cons_f1160(b, p, q): return PosQ(b*p*q) cons1160 = CustomConstraint(cons_f1160) def cons_f1161(b, p, q): return NegQ(b*p*q) cons1161 = CustomConstraint(cons_f1161) def cons_f1162(e, f, g, h): return ZeroQ(-e*h + f*g) cons1162 = CustomConstraint(cons_f1162) def cons_f1163(m, p): return ZeroQ(m - p + S(1)) cons1163 = CustomConstraint(cons_f1163) def cons_f1164(f, h, p): return Or(IntegerQ(p), PositiveQ(h/f)) cons1164 = CustomConstraint(cons_f1164) def cons_f1165(f, h, p): return Not(Or(IntegerQ(p), PositiveQ(h/f))) cons1165 = CustomConstraint(cons_f1165) def cons_f1166(b, m, p, q): return PosQ((m + S(1))/(b*p*q)) cons1166 = CustomConstraint(cons_f1166) def cons_f1167(b, m, p, q): return NegQ((m + S(1))/(b*p*q)) cons1167 = CustomConstraint(cons_f1167) def cons_f1168(c, e, f, g, h): return ZeroQ(c*(-e*h + f*g) + h) cons1168 = CustomConstraint(cons_f1168) def cons_f1169(c, e, f, g, h): return NonzeroQ(c*(-e*h + f*g) + h) cons1169 = CustomConstraint(cons_f1169) def cons_f1170(c, e, f, g, h): return PositiveQ(c*(e - f*g/h)) cons1170 = CustomConstraint(cons_f1170) def cons_f1171(e, f, g, h): return NonzeroQ(-e*h + f*g) cons1171 = CustomConstraint(cons_f1171) def cons_f1172(m, n): return IntegersQ(S(2)*m, S(2)*n) cons1172 = CustomConstraint(cons_f1172) def cons_f1173(m, n): return Or(Equal(n, S(1)), Not(PositiveIntegerQ(m)), And(Equal(n, S(2)), NonzeroQ(m + S(-1)))) cons1173 = CustomConstraint(cons_f1173) def cons_f1174(c, e, f, i, j): return ZeroQ(f*i + j*(c - e)) cons1174 = CustomConstraint(cons_f1174) def cons_f1175(m, n): return Or(IntegerQ(n), Greater(m, S(0))) cons1175 = CustomConstraint(cons_f1175) def cons_f1176(a, b, c, d, e, f, g, h, i, j, m, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, h, i, j, m, n, p, q), x) cons1176 = CustomConstraint(cons_f1176) def cons_f1177(e, f, g, h): return ZeroQ(e**S(2)*h + f**S(2)*g) cons1177 = CustomConstraint(cons_f1177) def cons_f1178(c, e): return ZeroQ(c - S(2)*e) cons1178 = CustomConstraint(cons_f1178) def cons_f1179(c, e): return PositiveQ(c/(S(2)*e)) cons1179 = CustomConstraint(cons_f1179) def cons_f1180(a, c, e): return Or(NonzeroQ(c - S(2)*e), NonzeroQ(a)) cons1180 = CustomConstraint(cons_f1180) def cons_f1181(e, f, g, h, i): return ZeroQ(e**S(2)*i - e*f*h + f**S(2)*g) cons1181 = CustomConstraint(cons_f1181) def cons_f1182(e, f, g, i): return ZeroQ(e**S(2)*i + f**S(2)*g) cons1182 = CustomConstraint(cons_f1182) def cons_f1183(g): return PositiveQ(g) cons1183 = CustomConstraint(cons_f1183) def cons_f1184(g1, g2, h1, h2): return ZeroQ(g1*h2 + g2*h1) cons1184 = CustomConstraint(cons_f1184) def cons_f1185(g1): return PositiveQ(g1) cons1185 = CustomConstraint(cons_f1185) def cons_f1186(g2): return PositiveQ(g2) cons1186 = CustomConstraint(cons_f1186) def cons_f1187(g1, x): return FreeQ(g1, x) cons1187 = CustomConstraint(cons_f1187) def cons_f1188(h1, x): return FreeQ(h1, x) cons1188 = CustomConstraint(cons_f1188) def cons_f1189(g2, x): return FreeQ(g2, x) cons1189 = CustomConstraint(cons_f1189) def cons_f1190(h2, x): return FreeQ(h2, x) cons1190 = CustomConstraint(cons_f1190) def cons_f1191(g): return Not(PositiveQ(g)) cons1191 = CustomConstraint(cons_f1191) def cons_f1192(g, h, i, j, k): return ZeroQ(h - i*(-g*k + h*j)) cons1192 = CustomConstraint(cons_f1192) def cons_f1193(g, h, j, k): return ZeroQ(-g*k + h*j) cons1193 = CustomConstraint(cons_f1193) def cons_f1194(F): return MemberQ(List(Log, ArcSin, ArcCos, ArcTan, ArcCot, ArcSinh, ArcCosh, ArcTanh, ArcCoth), F) cons1194 = CustomConstraint(cons_f1194) def cons_f1195(m, r): return ZeroQ(m + r) cons1195 = CustomConstraint(cons_f1195) def cons_f1196(r, r1): return ZeroQ(-r + r1 + S(1)) cons1196 = CustomConstraint(cons_f1196) def cons_f1197(a, b, c, d, e, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, n), x) cons1197 = CustomConstraint(cons_f1197) def cons_f1198(mn, n): return ZeroQ(mn + n) cons1198 = CustomConstraint(cons_f1198) def cons_f1199(a, b, c, d, e): return ZeroQ(-a*c*d + b*c*e + d) cons1199 = CustomConstraint(cons_f1199) def cons_f1200(RFx, x): if isinstance(x, (int, Integer, float, Float)): return False return RationalFunctionQ(RFx, x) cons1200 = CustomConstraint(cons_f1200) def cons_f1201(e, f, g): return ZeroQ(-S(4)*e*g + f**S(2)) cons1201 = CustomConstraint(cons_f1201) def cons_f1202(c, d, p, q, v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1201(cc, dd, e, f, pp, qq): return FreeQ(List(cc, dd, e, f, pp, qq), x) _cons_1201 = CustomConstraint(_cons_f_1201) pat = Pattern(UtilityOperator(((x*WC('f', S(1)) + WC('e', S(0)))**WC('pp', S(1))*WC('dd', S(1)))**WC('qq', S(1))*WC('cc', S(1)), x), _cons_1201) result_matchq = is_match(UtilityOperator(c*(d*v**p)**q, x), pat) return Not(result_matchq) cons1202 = CustomConstraint(cons_f1202) def cons_f1203(a, b, c, n, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, n, p, q, r), x) cons1203 = CustomConstraint(cons_f1203) def cons_f1204(a, b, c, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(SameQ(x**(n*p*q), a*(b*(c*x**n)**p)**q)) cons1204 = CustomConstraint(cons_f1204) def cons_f1205(n1, n2): return ZeroQ(n1 + n2) cons1205 = CustomConstraint(cons_f1205) def cons_f1206(n1, x): return FreeQ(n1, x) cons1206 = CustomConstraint(cons_f1206) def cons_f1207(c, d, f, g): return ZeroQ(-c*g + d*f) cons1207 = CustomConstraint(cons_f1207) def cons_f1208(b, d, e): return ZeroQ(-b*e + d) cons1208 = CustomConstraint(cons_f1208) def cons_f1209(a, b, f, g): return ZeroQ(-a*g + b*f) cons1209 = CustomConstraint(cons_f1209) def cons_f1210(c, d, f, g): return NonzeroQ(-c*g + d*f) cons1210 = CustomConstraint(cons_f1210) def cons_f1211(a, b, f, g): return NonzeroQ(-a*g + b*f) cons1211 = CustomConstraint(cons_f1211) def cons_f1212(m, m2): return ZeroQ(m + m2 + S(2)) cons1212 = CustomConstraint(cons_f1212) def cons_f1213(a, b, c, d, u, x): return FreeQ(simplify(Mul(u, Add(c, Mul(d, x)), Pow(Add(a, Mul(b, x)), S(-1)))), x) cons1213 = CustomConstraint(cons_f1213) def cons_f1214(a, b, c, d, e, f, g): return ZeroQ(-c*g + d*f - e*(-a*g + b*f)) cons1214 = CustomConstraint(cons_f1214) def cons_f1215(c, d, f, g): return ZeroQ(c**S(2)*g + d**S(2)*f) cons1215 = CustomConstraint(cons_f1215) def cons_f1216(a, b, c, d, e): return ZeroQ(-a*d*e - b*c*e + S(2)*c*d) cons1216 = CustomConstraint(cons_f1216) def cons_f1217(c, d, f, g, h): return ZeroQ(c**S(2)*h - c*d*g + d**S(2)*f) cons1217 = CustomConstraint(cons_f1217) def cons_f1218(c, d, f, h): return ZeroQ(c**S(2)*h + d**S(2)*f) cons1218 = CustomConstraint(cons_f1218) def cons_f1219(u, v): return FreeQ(simplify(Mul(u, Pow(Add(S(1), Mul(S(-1), v)), S(-1)))), x) cons1219 = CustomConstraint(cons_f1219) def cons_f1220(u, v): return FreeQ(simplify(Mul(u, Add(S(1), Mul(S(-1), v)))), x) cons1220 = CustomConstraint(cons_f1220) def cons_f1221(u, v): return FreeQ(simplify(Mul(u, Pow(v, S(-1)))), x) cons1221 = CustomConstraint(cons_f1221) def cons_f1222(u, v): return FreeQ(simplify(Mul(u, v)), x) cons1222 = CustomConstraint(cons_f1222) def cons_f1223(a, b, c, d, f, h): return ZeroQ(-a*c*h + b*d*f) cons1223 = CustomConstraint(cons_f1223) def cons_f1224(a, b, c, d, g, h): return ZeroQ(-a*d*h - b*c*h + b*d*g) cons1224 = CustomConstraint(cons_f1224) def cons_f1225(v, x): if isinstance(x, (int, Integer, float, Float)): return False return QuotientOfLinearsQ(v, x) cons1225 = CustomConstraint(cons_f1225) def cons_f1226(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(QuotientOfLinearsMatchQ(v, x)) cons1226 = CustomConstraint(cons_f1226) def cons_f1227(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(BinomialMatchQ(v, x)) cons1227 = CustomConstraint(cons_f1227) def cons_f1228(a, b, c, d, e, f, g, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, n, p), x) cons1228 = CustomConstraint(cons_f1228) def cons_f1229(a, b, c, d, e, f, g, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g, p), x) cons1229 = CustomConstraint(cons_f1229) def cons_f1230(m): return IntegerQ(m/S(2) + S(-1)/2) cons1230 = CustomConstraint(cons_f1230) def cons_f1231(m): return Not(IntegerQ(m/S(2) + S(-1)/2)) cons1231 = CustomConstraint(cons_f1231) def cons_f1232(u, x): if isinstance(x, (int, Integer, float, Float)): return False return InverseFunctionFreeQ(u, x) cons1232 = CustomConstraint(cons_f1232) def cons_f1233(n): return Not(And(RationalQ(n), Less(n, S(0)))) cons1233 = CustomConstraint(cons_f1233) def cons_f1234(m, n): return Or(Equal(n, S(1)), IntegerQ(m)) cons1234 = CustomConstraint(cons_f1234) def cons_f1235(RFx, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(PolynomialQ(RFx, x)) cons1235 = CustomConstraint(cons_f1235) def cons_f1236(Px, Qx, x): if isinstance(x, (int, Integer, float, Float)): return False return QuadraticQ(List(Qx, Px), x) cons1236 = CustomConstraint(cons_f1236) def cons_f1237(Px, Qx, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(D(Px/Qx, x)) cons1237 = CustomConstraint(cons_f1237) def cons_f1238(RGx, x): if isinstance(x, (int, Integer, float, Float)): return False return RationalFunctionQ(RGx, x) cons1238 = CustomConstraint(cons_f1238) def cons_f1239(d): return NonzeroQ(d + S(-1)) cons1239 = CustomConstraint(cons_f1239) def cons_f1240(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1239(g, m): return FreeQ(List(g, m), x) _cons_1239 = CustomConstraint(_cons_f_1239) pat = Pattern(UtilityOperator((x*WC('g', S(1)))**WC('m', S(1)), x), _cons_1239) result_matchq = is_match(UtilityOperator(v, x), pat) return Or(ZeroQ(v + S(-1)), result_matchq) cons1240 = CustomConstraint(cons_f1240) def cons_f1241(u, x): if isinstance(x, (int, Integer, float, Float)): return False return RationalFunctionQ(D(u, x)/u, x) cons1241 = CustomConstraint(cons_f1241) def cons_f1242(a, u, x): if isinstance(x, (int, Integer, float, Float)): return False try: return Or(NonzeroQ(a), Not(And(BinomialQ(u, x), ZeroQ(BinomialDegree(u, x)**S(2) + S(-1))))) except (TypeError, AttributeError): return False cons1242 = CustomConstraint(cons_f1242) def cons_f1243(Qx, x): if isinstance(x, (int, Integer, float, Float)): return False return QuadraticQ(Qx, x) cons1243 = CustomConstraint(cons_f1243) def cons_f1244(v, x): if isinstance(x, (int, Integer, float, Float)): return False return InverseFunctionFreeQ(v, x) cons1244 = CustomConstraint(cons_f1244) def cons_f1245(w, x): if isinstance(x, (int, Integer, float, Float)): return False return InverseFunctionFreeQ(w, x) cons1245 = CustomConstraint(cons_f1245) def cons_f1246(a, b, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, n, p), x) cons1246 = CustomConstraint(cons_f1246) def cons_f1247(A, B, a, b): return NonzeroQ(A*b - B*a) cons1247 = CustomConstraint(cons_f1247) def cons_f1248(a, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, f), x) cons1248 = CustomConstraint(cons_f1248) def cons_f1249(u): return NonsumQ(u) cons1249 = CustomConstraint(cons_f1249) def cons_f1250(u, x): if isinstance(x, (int, Integer, float, Float)): return False return AlgebraicFunctionQ(u, x) cons1250 = CustomConstraint(cons_f1250) def cons_f1251(u, x): if isinstance(x, (int, Integer, float, Float)): return False return FunctionOfTrigOfLinearQ(u, x) cons1251 = CustomConstraint(cons_f1251) def cons_f1252(n): return IntegerQ(n/S(2) + S(-1)/2) cons1252 = CustomConstraint(cons_f1252) def cons_f1253(m, n): return Not(And(IntegerQ(m/S(2) + S(-1)/2), Less(S(0), m, n))) cons1253 = CustomConstraint(cons_f1253) def cons_f1254(m, n): return Not(And(IntegerQ(m/S(2) + S(-1)/2), Inequality(S(0), Less, m, LessEqual, n))) cons1254 = CustomConstraint(cons_f1254) def cons_f1255(m, n): return Or(IntegersQ(S(2)*m, S(2)*n), ZeroQ(m + n)) cons1255 = CustomConstraint(cons_f1255) def cons_f1256(a, b, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, e, f), x) cons1256 = CustomConstraint(cons_f1256) def cons_f1257(m, n): return ZeroQ(m + n) cons1257 = CustomConstraint(cons_f1257) def cons_f1258(m): return Less(S(0), m, S(1)) cons1258 = CustomConstraint(cons_f1258) def cons_f1259(a, b, m, n): return Or(RationalQ(n), And(Not(RationalQ(m)), Or(ZeroQ(b + S(-1)), NonzeroQ(a + S(-1))))) cons1259 = CustomConstraint(cons_f1259) def cons_f1260(a, b, e, f, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, e, f, m, n), x) cons1260 = CustomConstraint(cons_f1260) def cons_f1261(m, n): return ZeroQ(m - n + S(2)) cons1261 = CustomConstraint(cons_f1261) def cons_f1262(m, n): return NonzeroQ(m - n) cons1262 = CustomConstraint(cons_f1262) def cons_f1263(c, d, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, d), x) cons1263 = CustomConstraint(cons_f1263) def cons_f1264(c, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, c), x) cons1264 = CustomConstraint(cons_f1264) def cons_f1265(b, c, d, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, c, d), x) cons1265 = CustomConstraint(cons_f1265) def cons_f1266(a, b, c, d, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d), x) cons1266 = CustomConstraint(cons_f1266) def cons_f1267(a, b): return ZeroQ(a**S(2) - b**S(2)) cons1267 = CustomConstraint(cons_f1267) def cons_f1268(n): return PositiveIntegerQ(n + S(-1)/2) cons1268 = CustomConstraint(cons_f1268) def cons_f1269(a, b): return NonzeroQ(a**S(2) - b**S(2)) cons1269 = CustomConstraint(cons_f1269) def cons_f1270(a, b): return PositiveQ(a + b) cons1270 = CustomConstraint(cons_f1270) def cons_f1271(a, b): return PositiveQ(a - b) cons1271 = CustomConstraint(cons_f1271) def cons_f1272(a, b): return Not(PositiveQ(a + b)) cons1272 = CustomConstraint(cons_f1272) def cons_f1273(a, b): return PositiveQ(a**S(2) - b**S(2)) cons1273 = CustomConstraint(cons_f1273) def cons_f1274(c): return SimplerQ(-Pi/S(2) + c, c) cons1274 = CustomConstraint(cons_f1274) def cons_f1275(a, b, c, d, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, n), x) cons1275 = CustomConstraint(cons_f1275) def cons_f1276(p): return IntegerQ(p/S(2) + S(-1)/2) cons1276 = CustomConstraint(cons_f1276) def cons_f1277(a, b, m, p): return Or(GreaterEqual(p, S(-1)), Not(And(IntegerQ(m + S(1)/2), ZeroQ(a**S(2) - b**S(2))))) cons1277 = CustomConstraint(cons_f1277) def cons_f1278(a, b, p): return Or(IntegerQ(S(2)*p), NonzeroQ(a**S(2) - b**S(2))) cons1278 = CustomConstraint(cons_f1278) def cons_f1279(m, p): return GreaterEqual(S(2)*m + p, S(0)) cons1279 = CustomConstraint(cons_f1279) def cons_f1280(m, p): return ZeroQ(m + p + S(1)) cons1280 = CustomConstraint(cons_f1280) def cons_f1281(p): return Not(NegativeIntegerQ(p)) cons1281 = CustomConstraint(cons_f1281) def cons_f1282(m, p): return NegativeIntegerQ(m + p + S(1)) cons1282 = CustomConstraint(cons_f1282) def cons_f1283(m, p): return NonzeroQ(S(2)*m + p + S(1)) cons1283 = CustomConstraint(cons_f1283) def cons_f1284(m, p): return ZeroQ(S(2)*m + p + S(-1)) cons1284 = CustomConstraint(cons_f1284) def cons_f1285(m): return NonzeroQ(m + S(-1)) cons1285 = CustomConstraint(cons_f1285) def cons_f1286(m, p): return PositiveIntegerQ(m + p/S(2) + S(-1)/2) cons1286 = CustomConstraint(cons_f1286) def cons_f1287(m, p): return NonzeroQ(m + p) cons1287 = CustomConstraint(cons_f1287) def cons_f1288(m, p): return LessEqual(p, -S(2)*m) cons1288 = CustomConstraint(cons_f1288) def cons_f1289(m, p): return IntegersQ(m + S(1)/2, S(2)*p) cons1289 = CustomConstraint(cons_f1289) def cons_f1290(m, p): return IntegersQ(S(2)*m, S(2)*p) cons1290 = CustomConstraint(cons_f1290) def cons_f1291(m, p): return Or(Greater(m, S(-2)), ZeroQ(S(2)*m + p + S(1)), And(Equal(m, S(-2)), IntegerQ(p))) cons1291 = CustomConstraint(cons_f1291) def cons_f1292(m): return LessEqual(m, S(-2)) cons1292 = CustomConstraint(cons_f1292) def cons_f1293(m, p): return Not(NegativeIntegerQ(m + p + S(1))) cons1293 = CustomConstraint(cons_f1293) def cons_f1294(p): return Not(And(RationalQ(p), GreaterEqual(p, S(1)))) cons1294 = CustomConstraint(cons_f1294) def cons_f1295(p): return Greater(p, S(2)) cons1295 = CustomConstraint(cons_f1295) def cons_f1296(m, p): return Or(IntegersQ(S(2)*m, S(2)*p), IntegerQ(m)) cons1296 = CustomConstraint(cons_f1296) def cons_f1297(m, p): return ZeroQ(m + p + S(2)) cons1297 = CustomConstraint(cons_f1297) def cons_f1298(m, p): return NegativeIntegerQ(m + p + S(2)) cons1298 = CustomConstraint(cons_f1298) def cons_f1299(m, p): return Not(PositiveIntegerQ(m + p + S(1))) cons1299 = CustomConstraint(cons_f1299) def cons_f1300(p): return IntegerQ(p/S(2) + S(1)/2) cons1300 = CustomConstraint(cons_f1300) def cons_f1301(m, p): return IntegersQ(m, p) cons1301 = CustomConstraint(cons_f1301) def cons_f1302(m, p): return Equal(p, S(2)*m) cons1302 = CustomConstraint(cons_f1302) def cons_f1303(m, p): return IntegersQ(m, p/S(2)) cons1303 = CustomConstraint(cons_f1303) def cons_f1304(m, p): return Or(Less(p, S(0)), Greater(m - p/S(2), S(0))) cons1304 = CustomConstraint(cons_f1304) def cons_f1305(m): return Not(And(RationalQ(m), Less(m, S(0)))) cons1305 = CustomConstraint(cons_f1305) def cons_f1306(m): return IntegerQ(m + S(-1)/2) cons1306 = CustomConstraint(cons_f1306) def cons_f1307(m): return Not(Less(m, S(-1))) cons1307 = CustomConstraint(cons_f1307) def cons_f1308(p): return IntegerQ(p/S(2)) cons1308 = CustomConstraint(cons_f1308) def cons_f1309(p): return IntegersQ(S(2)*p) cons1309 = CustomConstraint(cons_f1309) def cons_f1310(a, b, e, f, g, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, e, f, g, m, p), x) cons1310 = CustomConstraint(cons_f1310) def cons_f1311(m, n): return Not(And(IntegerQ(n), Or(And(Less(m, S(0)), Greater(n, S(0))), Less(S(0), n, m), Less(m, n, S(0))))) cons1311 = CustomConstraint(cons_f1311) def cons_f1312(n): return NonzeroQ(n + S(1)/2) cons1312 = CustomConstraint(cons_f1312) def cons_f1313(m): return PositiveIntegerQ(m + S(-1)/2) cons1313 = CustomConstraint(cons_f1313) def cons_f1314(m, n): return Not(And(NegativeIntegerQ(m + n), Greater(S(2)*m + n + S(1), S(0)))) cons1314 = CustomConstraint(cons_f1314) def cons_f1315(m, n): return Not(And(PositiveIntegerQ(n + S(-1)/2), Less(n, m))) cons1315 = CustomConstraint(cons_f1315) def cons_f1316(m): return NonzeroQ(m + S(1)/2) cons1316 = CustomConstraint(cons_f1316) def cons_f1317(m, n): return NegativeIntegerQ(m + n + S(1)) cons1317 = CustomConstraint(cons_f1317) def cons_f1318(m, n): return Not(And(RationalQ(n), Less(m, n, S(-1)))) cons1318 = CustomConstraint(cons_f1318) def cons_f1319(m, n): return Or(FractionQ(m), Not(FractionQ(n))) cons1319 = CustomConstraint(cons_f1319) def cons_f1320(b, c, d, e, f, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, c, d, e, f, m), x) cons1320 = CustomConstraint(cons_f1320) def cons_f1321(a, b, c, d, m): return ZeroQ(a*d*m + b*c*(m + S(1))) cons1321 = CustomConstraint(cons_f1321) def cons_f1322(m): return Less(m, S(-1)/2) cons1322 = CustomConstraint(cons_f1322) def cons_f1323(m): return Not(And(RationalQ(m), Less(m, S(-1)/2))) cons1323 = CustomConstraint(cons_f1323) def cons_f1324(c, d): return ZeroQ(c**S(2) - d**S(2)) cons1324 = CustomConstraint(cons_f1324) def cons_f1325(c, d): return NonzeroQ(c**S(2) - d**S(2)) cons1325 = CustomConstraint(cons_f1325) def cons_f1326(c, m, n): return Or(IntegersQ(S(2)*m, S(2)*n), IntegerQ(m + S(1)/2), And(IntegerQ(m), ZeroQ(c))) cons1326 = CustomConstraint(cons_f1326) def cons_f1327(n): return Less(S(0), n, S(1)) cons1327 = CustomConstraint(cons_f1327) def cons_f1328(c, m, n): return Or(IntegersQ(S(2)*m, S(2)*n), And(IntegerQ(m), ZeroQ(c))) cons1328 = CustomConstraint(cons_f1328) def cons_f1329(n): return Not(And(RationalQ(n), Greater(n, S(0)))) cons1329 = CustomConstraint(cons_f1329) def cons_f1330(c, n): return Or(IntegerQ(S(2)*n), ZeroQ(c)) cons1330 = CustomConstraint(cons_f1330) def cons_f1331(n): return NonzeroQ(S(2)*n + S(3)) cons1331 = CustomConstraint(cons_f1331) def cons_f1332(a, b, d): return ZeroQ(-a/b + d) cons1332 = CustomConstraint(cons_f1332) def cons_f1333(b, d): return PositiveQ(d/b) cons1333 = CustomConstraint(cons_f1333) def cons_f1334(b, d): return Not(PositiveQ(d/b)) cons1334 = CustomConstraint(cons_f1334) def cons_f1335(m): return Greater(m, S(2)) cons1335 = CustomConstraint(cons_f1335) def cons_f1336(m, n): return Or(IntegerQ(m), IntegersQ(S(2)*m, S(2)*n)) cons1336 = CustomConstraint(cons_f1336) def cons_f1337(a, c, m, n): return Not(And(IntegerQ(n), Greater(n, S(2)), Or(Not(IntegerQ(m)), And(ZeroQ(a), NonzeroQ(c))))) cons1337 = CustomConstraint(cons_f1337) def cons_f1338(n): return Less(S(1), n, S(2)) cons1338 = CustomConstraint(cons_f1338) def cons_f1339(a, m, n): return Or(And(ZeroQ(a), IntegerQ(m), Not(IntegerQ(n))), Not(And(IntegerQ(S(2)*n), Less(n, S(-1)), Or(And(IntegerQ(n), Not(IntegerQ(m))), ZeroQ(a))))) cons1339 = CustomConstraint(cons_f1339) def cons_f1340(c, d): return PositiveQ(c + d) cons1340 = CustomConstraint(cons_f1340) def cons_f1341(c, d): return PositiveQ(c - d) cons1341 = CustomConstraint(cons_f1341) def cons_f1342(c, d): return Not(PositiveQ(c + d)) cons1342 = CustomConstraint(cons_f1342) def cons_f1343(c, d): return PositiveQ(c**S(2) - d**S(2)) cons1343 = CustomConstraint(cons_f1343) def cons_f1344(b, c, d): return PosQ((c + d)/b) cons1344 = CustomConstraint(cons_f1344) def cons_f1345(c): return PositiveQ(c**S(2)) cons1345 = CustomConstraint(cons_f1345) def cons_f1346(b, c, d): return NegQ((c + d)/b) cons1346 = CustomConstraint(cons_f1346) def cons_f1347(a, b, c, d): return PosQ((a + b)/(c + d)) cons1347 = CustomConstraint(cons_f1347) def cons_f1348(a, b, c, d): return NegQ((a + b)/(c + d)) cons1348 = CustomConstraint(cons_f1348) def cons_f1349(a, b): return NegativeQ(a**S(2) - b**S(2)) cons1349 = CustomConstraint(cons_f1349) def cons_f1350(d): return ZeroQ(d**S(2) + S(-1)) cons1350 = CustomConstraint(cons_f1350) def cons_f1351(b, d): return PositiveQ(b*d) cons1351 = CustomConstraint(cons_f1351) def cons_f1352(b): return PositiveQ(b**S(2)) cons1352 = CustomConstraint(cons_f1352) def cons_f1353(b, d): return Not(And(ZeroQ(d**S(2) + S(-1)), PositiveQ(b*d))) cons1353 = CustomConstraint(cons_f1353) def cons_f1354(a, b, d): return PosQ((a + b)/d) cons1354 = CustomConstraint(cons_f1354) def cons_f1355(a): return PositiveQ(a**S(2)) cons1355 = CustomConstraint(cons_f1355) def cons_f1356(a, b, d): return NegQ((a + b)/d) cons1356 = CustomConstraint(cons_f1356) def cons_f1357(a, b, c, d): return PosQ((c + d)/(a + b)) cons1357 = CustomConstraint(cons_f1357) def cons_f1358(a, b, c, d): return NegQ((c + d)/(a + b)) cons1358 = CustomConstraint(cons_f1358) def cons_f1359(m): return Less(S(0), m, S(2)) cons1359 = CustomConstraint(cons_f1359) def cons_f1360(n): return Less(S(-1), n, S(2)) cons1360 = CustomConstraint(cons_f1360) def cons_f1361(m, n): return NonzeroQ(m + n) cons1361 = CustomConstraint(cons_f1361) def cons_f1362(a, b, c, d, e, f, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, m, n), x) cons1362 = CustomConstraint(cons_f1362) def cons_f1363(a, b, n, p): return Or(And(Less(p, S(0)), NonzeroQ(a**S(2) - b**S(2))), Less(S(0), n, p + S(-1)), Less(p + S(1), -n, S(2)*p + S(1))) cons1363 = CustomConstraint(cons_f1363) def cons_f1364(n, p): return Or(Less(S(0), n, p/S(2) + S(1)/2), Inequality(p, LessEqual, -n, Less, S(2)*p + S(-3)), Inequality(S(0), Less, n, LessEqual, -p)) cons1364 = CustomConstraint(cons_f1364) def cons_f1365(a, b, d, e, f, g, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, d, e, f, g, n, p), x) cons1365 = CustomConstraint(cons_f1365) def cons_f1366(m, n): return Not(And(IntegerQ(n), Less(n**S(2), m**S(2)))) cons1366 = CustomConstraint(cons_f1366) def cons_f1367(n, p): return NonzeroQ(S(2)*n + p + S(1)) cons1367 = CustomConstraint(cons_f1367) def cons_f1368(m, n, p): return Not(And(NegativeIntegerQ(m + n + p), Greater(S(2)*m + n + S(3)*p/S(2) + S(1), S(0)))) cons1368 = CustomConstraint(cons_f1368) def cons_f1369(m, n, p): return Not(And(PositiveIntegerQ(n + p/S(2) + S(-1)/2), Greater(m - n, S(0)))) cons1369 = CustomConstraint(cons_f1369) def cons_f1370(m, p): return ZeroQ(S(2)*m + p + S(1)) cons1370 = CustomConstraint(cons_f1370) def cons_f1371(m, n, p): return ZeroQ(m + n + p + S(1)) cons1371 = CustomConstraint(cons_f1371) def cons_f1372(m, n, p): return NegativeIntegerQ(m + n + p + S(1)) cons1372 = CustomConstraint(cons_f1372) def cons_f1373(m, n, p): return NonzeroQ(m + n + p) cons1373 = CustomConstraint(cons_f1373) def cons_f1374(m, n): return Not(And(RationalQ(n), Less(S(0), n, m))) cons1374 = CustomConstraint(cons_f1374) def cons_f1375(a, b, c, d, m, p): return ZeroQ(a*d*m + b*c*(m + p + S(1))) cons1375 = CustomConstraint(cons_f1375) def cons_f1376(m): return Greater(m, S(-1)) cons1376 = CustomConstraint(cons_f1376) def cons_f1377(m, p): return PositiveIntegerQ(m + p/S(2) + S(1)/2) cons1377 = CustomConstraint(cons_f1377) def cons_f1378(m): return Less(m, S(-3)/2) cons1378 = CustomConstraint(cons_f1378) def cons_f1379(m): return Inequality(S(-3)/2, LessEqual, m, Less, S(0)) cons1379 = CustomConstraint(cons_f1379) def cons_f1380(m, p): return Or(And(RationalQ(m), Less(m, S(-1))), NegativeIntegerQ(m + p)) cons1380 = CustomConstraint(cons_f1380) def cons_f1381(p): return Not(And(RationalQ(p), Less(p, S(-1)))) cons1381 = CustomConstraint(cons_f1381) def cons_f1382(m, p): return Equal(S(2)*m + p, S(0)) cons1382 = CustomConstraint(cons_f1382) def cons_f1383(m, n, p): return IntegersQ(m, n, p/S(2)) cons1383 = CustomConstraint(cons_f1383) def cons_f1384(m, n, p): return Or(And(Greater(m, S(0)), Greater(p, S(0)), Less(-m - p, n, S(-1))), And(Greater(m, S(2)), Less(p, S(0)), Greater(m + p/S(2), S(0)))) cons1384 = CustomConstraint(cons_f1384) def cons_f1385(m, n): return Or(NegativeIntegerQ(m), Not(PositiveIntegerQ(n))) cons1385 = CustomConstraint(cons_f1385) def cons_f1386(m, p): return Or(Equal(S(2)*m + p, S(0)), And(Greater(S(2)*m + p, S(0)), Less(p, S(-1)))) cons1386 = CustomConstraint(cons_f1386) def cons_f1387(m): return LessEqual(m, S(-1)/2) cons1387 = CustomConstraint(cons_f1387) def cons_f1388(m, p): return NonzeroQ(m + p + S(2)) cons1388 = CustomConstraint(cons_f1388) def cons_f1389(n, p): return Or(IntegerQ(p), PositiveIntegerQ(n)) cons1389 = CustomConstraint(cons_f1389) def cons_f1390(m, p): return ZeroQ(m + p + S(1)/2) cons1390 = CustomConstraint(cons_f1390) def cons_f1391(m, p): return ZeroQ(m + p + S(3)/2) cons1391 = CustomConstraint(cons_f1391) def cons_f1392(m, n): return Or(PositiveIntegerQ(m), IntegersQ(S(2)*m, S(2)*n)) cons1392 = CustomConstraint(cons_f1392) def cons_f1393(n): return Not(Less(n, S(-1))) cons1393 = CustomConstraint(cons_f1393) def cons_f1394(m, n): return Or(Less(m, S(-2)), ZeroQ(m + n + S(4))) cons1394 = CustomConstraint(cons_f1394) def cons_f1395(m, n): return NonzeroQ(m + n + S(4)) cons1395 = CustomConstraint(cons_f1395) def cons_f1396(m, n): return Or(Less(n, S(-2)), ZeroQ(m + n + S(4))) cons1396 = CustomConstraint(cons_f1396) def cons_f1397(n): return NonzeroQ(n + S(2)) cons1397 = CustomConstraint(cons_f1397) def cons_f1398(m, n): return NonzeroQ(m + n + S(5)) cons1398 = CustomConstraint(cons_f1398) def cons_f1399(m, n): return NonzeroQ(m + n + S(6)) cons1399 = CustomConstraint(cons_f1399) def cons_f1400(m, n, p): return IntegersQ(m, S(2)*n, p/S(2)) cons1400 = CustomConstraint(cons_f1400) def cons_f1401(m, p): return Or(Less(m, S(-1)), And(Equal(m, S(-1)), Greater(p, S(0)))) cons1401 = CustomConstraint(cons_f1401) def cons_f1402(n, p): return Or(Less(n, S(0)), PositiveIntegerQ(p + S(1)/2)) cons1402 = CustomConstraint(cons_f1402) def cons_f1403(n, p): return IntegersQ(S(2)*n, S(2)*p) cons1403 = CustomConstraint(cons_f1403) def cons_f1404(n, p): return Or(LessEqual(n, S(-2)), And(Equal(n, S(-3)/2), Equal(p, S(3)/2))) cons1404 = CustomConstraint(cons_f1404) def cons_f1405(n, p): return Or(Less(n, S(-1)), And(Equal(p, S(3)/2), Equal(n, S(-1)/2))) cons1405 = CustomConstraint(cons_f1405) def cons_f1406(p): return Less(S(-1), p, S(1)) cons1406 = CustomConstraint(cons_f1406) def cons_f1407(m, n): return Or(Greater(m, S(0)), IntegerQ(n)) cons1407 = CustomConstraint(cons_f1407) def cons_f1408(m, n, p): return IntegersQ(m, S(2)*n, S(2)*p) cons1408 = CustomConstraint(cons_f1408) def cons_f1409(m, n, p): return Or(LessEqual(n, S(-2)), And(Equal(m, S(-1)), Equal(n, S(-3)/2), Equal(p, S(3)/2))) cons1409 = CustomConstraint(cons_f1409) def cons_f1410(p): return PositiveIntegerQ(p/S(2)) cons1410 = CustomConstraint(cons_f1410) def cons_f1411(a, b, c, d): return Or(ZeroQ(a**S(2) - b**S(2)), ZeroQ(c**S(2) - d**S(2))) cons1411 = CustomConstraint(cons_f1411) def cons_f1412(c, d): return ZeroQ(-c + d) cons1412 = CustomConstraint(cons_f1412) def cons_f1413(a, b): return PositiveQ(-a**S(2) + b**S(2)) cons1413 = CustomConstraint(cons_f1413) def cons_f1414(a, b, c, d): return NonzeroQ(a*d + b*c) cons1414 = CustomConstraint(cons_f1414) def cons_f1415(a, b, c, d): return Or(NonzeroQ(a**S(2) - b**S(2)), NonzeroQ(c**S(2) - d**S(2))) cons1415 = CustomConstraint(cons_f1415) def cons_f1416(n, p): return ZeroQ(S(2)*n + p) cons1416 = CustomConstraint(cons_f1416) def cons_f1417(m, n, p): return Or(IntegersQ(m, n), IntegersQ(m, p), IntegersQ(n, p)) cons1417 = CustomConstraint(cons_f1417) def cons_f1418(p): return NonzeroQ(p + S(-2)) cons1418 = CustomConstraint(cons_f1418) def cons_f1419(m, n): return Not(And(IntegerQ(m), IntegerQ(n))) cons1419 = CustomConstraint(cons_f1419) def cons_f1420(A, B, a, b): return ZeroQ(A*b + B*a) cons1420 = CustomConstraint(cons_f1420) def cons_f1421(A, B, a, b, m, n): return ZeroQ(A*b*(m + n + S(1)) + B*a*(m - n)) cons1421 = CustomConstraint(cons_f1421) def cons_f1422(m, n): return Or(And(RationalQ(m), Less(m, S(-1)/2)), And(NegativeIntegerQ(m + n), Not(SumSimplerQ(n, S(1))))) cons1422 = CustomConstraint(cons_f1422) def cons_f1423(m): return NonzeroQ(S(2)*m + S(1)) cons1423 = CustomConstraint(cons_f1423) def cons_f1424(A, B, a, b, c, d, m, n): return ZeroQ(A*(a*d*m + b*c*(n + S(1))) - B*(a*c*m + b*d*(n + S(1)))) cons1424 = CustomConstraint(cons_f1424) def cons_f1425(m): return Greater(m, S(1)/2) cons1425 = CustomConstraint(cons_f1425) def cons_f1426(A, B, a, b, c, d, n): return ZeroQ(A*b*d*(S(2)*n + S(3)) - B*(-S(2)*a*d*(n + S(1)) + b*c)) cons1426 = CustomConstraint(cons_f1426) def cons_f1427(m, n): return Or(IntegerQ(n), ZeroQ(m + S(1)/2)) cons1427 = CustomConstraint(cons_f1427) def cons_f1428(A, B, a, b): return NonzeroQ(A*b + B*a) cons1428 = CustomConstraint(cons_f1428) def cons_f1429(a, c, m, n): return Not(And(IntegerQ(n), Greater(n, S(1)), Or(Not(IntegerQ(m)), And(ZeroQ(a), NonzeroQ(c))))) cons1429 = CustomConstraint(cons_f1429) def cons_f1430(A, B): return ZeroQ(A - B) cons1430 = CustomConstraint(cons_f1430) def cons_f1431(A, B): return NonzeroQ(A - B) cons1431 = CustomConstraint(cons_f1431) def cons_f1432(n): return Equal(n**S(2), S(1)/4) cons1432 = CustomConstraint(cons_f1432) def cons_f1433(B, C, b, e, f, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, e, f, B, C, m), x) cons1433 = CustomConstraint(cons_f1433) def cons_f1434(A, C, m): return ZeroQ(A*(m + S(2)) + C*(m + S(1))) cons1434 = CustomConstraint(cons_f1434) def cons_f1435(A, C, a, b): return ZeroQ(A*b**S(2) + C*a**S(2)) cons1435 = CustomConstraint(cons_f1435) def cons_f1436(A, B, C): return ZeroQ(A - B + C) cons1436 = CustomConstraint(cons_f1436) def cons_f1437(A, C): return ZeroQ(A + C) cons1437 = CustomConstraint(cons_f1437) def cons_f1438(m, n): return Or(And(RationalQ(m), Less(m, S(-1)/2)), And(ZeroQ(m + n + S(2)), NonzeroQ(S(2)*m + S(1)))) cons1438 = CustomConstraint(cons_f1438) def cons_f1439(m, n): return Or(And(RationalQ(n), Less(n, S(-1))), ZeroQ(m + n + S(2))) cons1439 = CustomConstraint(cons_f1439) def cons_f1440(a, c, m, n): return Not(And(IntegerQ(n), Greater(n, S(0)), Or(Not(IntegerQ(m)), And(ZeroQ(a), NonzeroQ(c))))) cons1440 = CustomConstraint(cons_f1440) def cons_f1441(a, b): return ZeroQ(a**S(2) + b**S(2)) cons1441 = CustomConstraint(cons_f1441) def cons_f1442(a, b): return NonzeroQ(a**S(2) + b**S(2)) cons1442 = CustomConstraint(cons_f1442) def cons_f1443(n): return Not(OddQ(n)) cons1443 = CustomConstraint(cons_f1443) def cons_f1444(n): return Unequal(n, S(-2)) cons1444 = CustomConstraint(cons_f1444) def cons_f1445(n): return Not(And(RationalQ(n), Or(GreaterEqual(n, S(1)), LessEqual(n, S(-1))))) cons1445 = CustomConstraint(cons_f1445) def cons_f1446(a, b): return PositiveQ(a**S(2) + b**S(2)) cons1446 = CustomConstraint(cons_f1446) def cons_f1447(a, b): return Not(Or(PositiveQ(a**S(2) + b**S(2)), ZeroQ(a**S(2) + b**S(2)))) cons1447 = CustomConstraint(cons_f1447) def cons_f1448(m, n): return IntegerQ(m/S(2) + n/S(2)) cons1448 = CustomConstraint(cons_f1448) def cons_f1449(m, n): return Not(And(Greater(n, S(0)), Greater(m, S(1)))) cons1449 = CustomConstraint(cons_f1449) def cons_f1450(a, b, c): return ZeroQ(a**S(2) - b**S(2) - c**S(2)) cons1450 = CustomConstraint(cons_f1450) def cons_f1451(b, c): return ZeroQ(b**S(2) + c**S(2)) cons1451 = CustomConstraint(cons_f1451) def cons_f1452(b, c): return NonzeroQ(b**S(2) + c**S(2)) cons1452 = CustomConstraint(cons_f1452) def cons_f1453(a, b, c): return PositiveQ(a + sqrt(b**S(2) + c**S(2))) cons1453 = CustomConstraint(cons_f1453) def cons_f1454(a, b, c): return NonzeroQ(a**S(2) - b**S(2) - c**S(2)) cons1454 = CustomConstraint(cons_f1454) def cons_f1455(a, b, c): return Not(PositiveQ(a + sqrt(b**S(2) + c**S(2)))) cons1455 = CustomConstraint(cons_f1455) def cons_f1456(a, b): return ZeroQ(a + b) cons1456 = CustomConstraint(cons_f1456) def cons_f1457(a, c): return ZeroQ(a - c) cons1457 = CustomConstraint(cons_f1457) def cons_f1458(a, b): return NonzeroQ(a - b) cons1458 = CustomConstraint(cons_f1458) def cons_f1459(n): return Unequal(n, S(-3)/2) cons1459 = CustomConstraint(cons_f1459) def cons_f1460(A, B, C, a, b, c): return ZeroQ(A*(b**S(2) + c**S(2)) - a*(B*b + C*c)) cons1460 = CustomConstraint(cons_f1460) def cons_f1461(A, C, a, b, c): return ZeroQ(A*(b**S(2) + c**S(2)) - C*a*c) cons1461 = CustomConstraint(cons_f1461) def cons_f1462(A, B, a, b, c): return ZeroQ(A*(b**S(2) + c**S(2)) - B*a*b) cons1462 = CustomConstraint(cons_f1462) def cons_f1463(A, B, C, a, b, c): return NonzeroQ(A*(b**S(2) + c**S(2)) - a*(B*b + C*c)) cons1463 = CustomConstraint(cons_f1463) def cons_f1464(A, C, a, b, c): return NonzeroQ(A*(b**S(2) + c**S(2)) - C*a*c) cons1464 = CustomConstraint(cons_f1464) def cons_f1465(A, B, a, b, c): return NonzeroQ(A*(b**S(2) + c**S(2)) - B*a*b) cons1465 = CustomConstraint(cons_f1465) def cons_f1466(A, B, C, a, b, c, n): return ZeroQ(A*a*(n + S(1)) + n*(B*b + C*c)) cons1466 = CustomConstraint(cons_f1466) def cons_f1467(A, C, a, c, n): return ZeroQ(A*a*(n + S(1)) + C*c*n) cons1467 = CustomConstraint(cons_f1467) def cons_f1468(A, B, a, b, n): return ZeroQ(A*a*(n + S(1)) + B*b*n) cons1468 = CustomConstraint(cons_f1468) def cons_f1469(A, B, C, a, b, c, n): return NonzeroQ(A*a*(n + S(1)) + n*(B*b + C*c)) cons1469 = CustomConstraint(cons_f1469) def cons_f1470(A, C, a, c, n): return NonzeroQ(A*a*(n + S(1)) + C*c*n) cons1470 = CustomConstraint(cons_f1470) def cons_f1471(A, B, a, b, n): return NonzeroQ(A*a*(n + S(1)) + B*b*n) cons1471 = CustomConstraint(cons_f1471) def cons_f1472(B, C, b, c): return ZeroQ(B*b + C*c) cons1472 = CustomConstraint(cons_f1472) def cons_f1473(B, C, b, c): return ZeroQ(B*c - C*b) cons1473 = CustomConstraint(cons_f1473) def cons_f1474(A, B, C, a, b, c): return ZeroQ(A*a - B*b - C*c) cons1474 = CustomConstraint(cons_f1474) def cons_f1475(A, C, a, c): return ZeroQ(A*a - C*c) cons1475 = CustomConstraint(cons_f1475) def cons_f1476(A, B, a, b): return ZeroQ(A*a - B*b) cons1476 = CustomConstraint(cons_f1476) def cons_f1477(A, B, C, a, b, c): return NonzeroQ(A*a - B*b - C*c) cons1477 = CustomConstraint(cons_f1477) def cons_f1478(A, C, a, c): return NonzeroQ(A*a - C*c) cons1478 = CustomConstraint(cons_f1478) def cons_f1479(A, B, a, b): return NonzeroQ(A*a - B*b) cons1479 = CustomConstraint(cons_f1479) def cons_f1480(a, b): return NonzeroQ(a + b) cons1480 = CustomConstraint(cons_f1480) def cons_f1481(n): return EvenQ(n) cons1481 = CustomConstraint(cons_f1481) def cons_f1482(m): return EvenQ(m) cons1482 = CustomConstraint(cons_f1482) def cons_f1483(m): return OddQ(m) cons1483 = CustomConstraint(cons_f1483) def cons_f1484(n): return OddQ(n) cons1484 = CustomConstraint(cons_f1484) def cons_f1485(m): return Not(OddQ(m)) cons1485 = CustomConstraint(cons_f1485) def cons_f1486(p): return EvenQ(p) cons1486 = CustomConstraint(cons_f1486) def cons_f1487(q): return EvenQ(q) cons1487 = CustomConstraint(cons_f1487) def cons_f1488(p, q): return Inequality(S(0), Less, p, LessEqual, q) cons1488 = CustomConstraint(cons_f1488) def cons_f1489(p, q): return Less(S(0), q, p) cons1489 = CustomConstraint(cons_f1489) def cons_f1490(c, d, e, f, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, d, e, f, m), x) cons1490 = CustomConstraint(cons_f1490) def cons_f1491(m): return Or(Not(RationalQ(m)), Inequality(S(-1), LessEqual, m, Less, S(1))) cons1491 = CustomConstraint(cons_f1491) def cons_f1492(a, b, m, n): return Or(Equal(n, S(1)), PositiveIntegerQ(m), NonzeroQ(a**S(2) - b**S(2))) cons1492 = CustomConstraint(cons_f1492) def cons_f1493(m, n): return Or(Greater(n, S(0)), PositiveIntegerQ(m)) cons1493 = CustomConstraint(cons_f1493) def cons_f1494(a, b): return ZeroQ(a - b) cons1494 = CustomConstraint(cons_f1494) def cons_f1495(n): return NegativeIntegerQ(n + S(2)) cons1495 = CustomConstraint(cons_f1495) def cons_f1496(n, p): return Or(Equal(n, S(2)), Equal(p, S(-1))) cons1496 = CustomConstraint(cons_f1496) def cons_f1497(a, b, c, d, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, n, p), x) cons1497 = CustomConstraint(cons_f1497) def cons_f1498(m, n): return Or(Greater(m - n + S(1), S(0)), Greater(n, S(2))) cons1498 = CustomConstraint(cons_f1498) def cons_f1499(a, b, c, d, e, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, m, n, p), x) cons1499 = CustomConstraint(cons_f1499) def cons_f1500(c, d, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, d, n), x) cons1500 = CustomConstraint(cons_f1500) def cons_f1501(d, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(d, n), x) cons1501 = CustomConstraint(cons_f1501) def cons_f1502(m, n): return ZeroQ(m - n/S(2) + S(1)) cons1502 = CustomConstraint(cons_f1502) def cons_f1503(m, n): return Less(S(0), n, m + S(1)) cons1503 = CustomConstraint(cons_f1503) def cons_f1504(n): return NonzeroQ(n + S(-1)) cons1504 = CustomConstraint(cons_f1504) def cons_f1505(m, n): return Less(S(0), S(2)*n, m + S(1)) cons1505 = CustomConstraint(cons_f1505) def cons_f1506(m, n): return Less(S(0), S(2)*n, S(1) - m) cons1506 = CustomConstraint(cons_f1506) def cons_f1507(p): return Unequal(p, S(-2)) cons1507 = CustomConstraint(cons_f1507) def cons_f1508(c, d, e, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, d, e, m, n), x) cons1508 = CustomConstraint(cons_f1508) def cons_f1509(a, b, c, d, e, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, m), x) cons1509 = CustomConstraint(cons_f1509) def cons_f1510(m, n): return ZeroQ(m + n + S(-1)) cons1510 = CustomConstraint(cons_f1510) def cons_f1511(m, n): return IntegersQ(m, n, m/S(2) + n/S(2) + S(-1)/2) cons1511 = CustomConstraint(cons_f1511) def cons_f1512(m): return Unequal(m, S(-2)) cons1512 = CustomConstraint(cons_f1512) def cons_f1513(m): return Not(And(RationalQ(m), Greater(m, S(1)), Not(IntegerQ(m/S(2) + S(-1)/2)))) cons1513 = CustomConstraint(cons_f1513) def cons_f1514(n): return IntegerQ(n/S(2) + S(1)/2) cons1514 = CustomConstraint(cons_f1514) def cons_f1515(m, n): return Not(IntegersQ(S(2)*m, S(2)*n)) cons1515 = CustomConstraint(cons_f1515) def cons_f1516(m, n): return Not(And(IntegerQ(m/S(2)), Less(S(0), m, n + S(1)))) cons1516 = CustomConstraint(cons_f1516) def cons_f1517(m): return IntegerQ(m/S(2)) cons1517 = CustomConstraint(cons_f1517) def cons_f1518(m, n): return Not(And(IntegerQ(n/S(2) + S(-1)/2), Less(S(0), n, m + S(-1)))) cons1518 = CustomConstraint(cons_f1518) def cons_f1519(m, n): return Or(Greater(m, S(1)), And(Equal(m, S(1)), Equal(n, S(-3)/2))) cons1519 = CustomConstraint(cons_f1519) def cons_f1520(m, n): return Or(Less(m, S(-1)), And(Equal(m, S(-1)), Equal(n, S(3)/2))) cons1520 = CustomConstraint(cons_f1520) def cons_f1521(m, n): return NonzeroQ(m + n + S(-1)) cons1521 = CustomConstraint(cons_f1521) def cons_f1522(m, n): return Or(Less(m, S(-1)), And(Equal(m, S(-1)), RationalQ(n), Equal(n, S(-1)/2))) cons1522 = CustomConstraint(cons_f1522) def cons_f1523(m, n): return Or(Greater(m, S(1)), And(Equal(m, S(1)), RationalQ(n), Equal(n, S(1)/2))) cons1523 = CustomConstraint(cons_f1523) def cons_f1524(b, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, e, f), x) cons1524 = CustomConstraint(cons_f1524) def cons_f1525(n): return Not(IntegerQ(n/S(2) + S(-1)/2)) cons1525 = CustomConstraint(cons_f1525) def cons_f1526(m): return Not(IntegerQ(m/S(2))) cons1526 = CustomConstraint(cons_f1526) def cons_f1527(m, n, p): return NonzeroQ(m*p + n + S(-1)) cons1527 = CustomConstraint(cons_f1527) def cons_f1528(m, n, p): return IntegersQ(S(2)*m*p, S(2)*n) cons1528 = CustomConstraint(cons_f1528) def cons_f1529(m, n, p): return NonzeroQ(m*p + n + S(1)) cons1529 = CustomConstraint(cons_f1529) def cons_f1530(a, b, m): return Or(IntegerQ(S(2)*m), NonzeroQ(a**S(2) + b**S(2))) cons1530 = CustomConstraint(cons_f1530) def cons_f1531(m, n): return ZeroQ(m/S(2) + n) cons1531 = CustomConstraint(cons_f1531) def cons_f1532(m, n): return ZeroQ(m/S(2) + n + S(-1)) cons1532 = CustomConstraint(cons_f1532) def cons_f1533(m, n): return PositiveIntegerQ(m/S(2) + n + S(-1)) cons1533 = CustomConstraint(cons_f1533) def cons_f1534(m, n): return Or(And(PositiveIntegerQ(n/S(2)), NegativeIntegerQ(m + S(-1)/2)), And(Equal(n, S(2)), Less(m, S(0))), And(LessEqual(m, S(-1)), Greater(m + n, S(0))), And(NegativeIntegerQ(m), Less(m/S(2) + n + S(-1), S(0)), IntegerQ(n)), And(Equal(n, S(3)/2), Equal(m, S(-1)/2))) cons1534 = CustomConstraint(cons_f1534) def cons_f1535(m, n): return Or(And(PositiveIntegerQ(n/S(2)), NegativeIntegerQ(m + S(-1)/2)), And(Equal(n, S(2)), Less(m, S(0))), And(LessEqual(m, S(-1)), Greater(m + n, S(0))), And(NegativeIntegerQ(m), Less(m/S(2) + n + S(-1), S(0))), And(Equal(n, S(3)/2), Equal(m, S(-1)/2))) cons1535 = CustomConstraint(cons_f1535) def cons_f1536(m, n): return Or(And(NegativeIntegerQ(n/S(2)), PositiveIntegerQ(m + S(-1)/2)), Equal(n, S(-2)), PositiveIntegerQ(m + n), And(IntegersQ(n, m + S(1)/2), Greater(S(2)*m + n + S(1), S(0)))) cons1536 = CustomConstraint(cons_f1536) def cons_f1537(m, n): return Not(NegativeIntegerQ(m + n)) cons1537 = CustomConstraint(cons_f1537) def cons_f1538(m, n): return NonzeroQ(m + S(2)*n) cons1538 = CustomConstraint(cons_f1538) def cons_f1539(m, n): return PositiveIntegerQ(m + n + S(-1)) cons1539 = CustomConstraint(cons_f1539) def cons_f1540(m, n): return NegativeIntegerQ(m + n) cons1540 = CustomConstraint(cons_f1540) def cons_f1541(m): return PositiveIntegerQ(m + S(-1)) cons1541 = CustomConstraint(cons_f1541) def cons_f1542(m, n): return Or(And(Less(m, S(5)), Greater(n, S(-4))), And(Equal(m, S(5)), Equal(n, S(-1)))) cons1542 = CustomConstraint(cons_f1542) def cons_f1543(m, n): return Not(And(IntegerQ(n), Greater(n, S(0)), Or(Less(m, S(0)), Less(n, m)))) cons1543 = CustomConstraint(cons_f1543) def cons_f1544(a, b, c, d): return ZeroQ(a*c + b*d) cons1544 = CustomConstraint(cons_f1544) def cons_f1545(a, b, c, d): return NonzeroQ(a*c + b*d) cons1545 = CustomConstraint(cons_f1545) def cons_f1546(c, d): return ZeroQ(c**S(2) + d**S(2)) cons1546 = CustomConstraint(cons_f1546) def cons_f1547(c, d): return NonzeroQ(c**S(2) + d**S(2)) cons1547 = CustomConstraint(cons_f1547) def cons_f1548(a, b, c, d): return ZeroQ(S(2)*a*c*d - b*(c**S(2) - d**S(2))) cons1548 = CustomConstraint(cons_f1548) def cons_f1549(a, b, c, d): return NonzeroQ(S(2)*a*c*d - b*(c**S(2) - d**S(2))) cons1549 = CustomConstraint(cons_f1549) def cons_f1550(a, b, c, d): return Or(PerfectSquareQ(a**S(2) + b**S(2)), RationalQ(a, b, c, d)) cons1550 = CustomConstraint(cons_f1550) def cons_f1551(m): return Not(And(RationalQ(m), LessEqual(m, S(-1)))) cons1551 = CustomConstraint(cons_f1551) def cons_f1552(a, m): return Not(And(ZeroQ(m + S(-2)), ZeroQ(a))) cons1552 = CustomConstraint(cons_f1552) def cons_f1553(m, n): return Equal(m + n, S(0)) cons1553 = CustomConstraint(cons_f1553) def cons_f1554(m): return IntegersQ(S(2)*m) cons1554 = CustomConstraint(cons_f1554) def cons_f1555(m, n): return Or(IntegerQ(n), IntegersQ(S(2)*m, S(2)*n)) cons1555 = CustomConstraint(cons_f1555) def cons_f1556(m, n): return Or(And(RationalQ(n), GreaterEqual(n, S(-1))), IntegerQ(m)) cons1556 = CustomConstraint(cons_f1556) def cons_f1557(a, c, m, n): return Not(And(IntegerQ(n), Greater(n, S(2)), Or(Not(IntegerQ(m)), And(ZeroQ(c), NonzeroQ(a))))) cons1557 = CustomConstraint(cons_f1557) def cons_f1558(m, n): return Or(And(RationalQ(n), Less(n, S(0))), IntegerQ(m)) cons1558 = CustomConstraint(cons_f1558) def cons_f1559(a, c, m, n): return Not(And(IntegerQ(n), Less(n, S(-1)), Or(Not(IntegerQ(m)), And(ZeroQ(c), NonzeroQ(a))))) cons1559 = CustomConstraint(cons_f1559) def cons_f1560(A, B): return ZeroQ(A**S(2) + B**S(2)) cons1560 = CustomConstraint(cons_f1560) def cons_f1561(A, B): return NonzeroQ(A**S(2) + B**S(2)) cons1561 = CustomConstraint(cons_f1561) def cons_f1562(a, c, m, n): return Not(And(IntegerQ(n), Greater(n, S(1)), Or(Not(IntegerQ(m)), And(ZeroQ(c), NonzeroQ(a))))) cons1562 = CustomConstraint(cons_f1562) def cons_f1563(A, C): return ZeroQ(A - C) cons1563 = CustomConstraint(cons_f1563) def cons_f1564(A, B, C, a, b): return NonzeroQ(A*b**S(2) - B*a*b + C*a**S(2)) cons1564 = CustomConstraint(cons_f1564) def cons_f1565(A, C, a, b): return NonzeroQ(A*b**S(2) + C*a**S(2)) cons1565 = CustomConstraint(cons_f1565) def cons_f1566(A, B, C, a, b): return ZeroQ(A*b - B*a - C*b) cons1566 = CustomConstraint(cons_f1566) def cons_f1567(A, C): return NonzeroQ(A - C) cons1567 = CustomConstraint(cons_f1567) def cons_f1568(A, B, C, a, b): return NonzeroQ(A*b - B*a - C*b) cons1568 = CustomConstraint(cons_f1568) def cons_f1569(m, n): return Or(And(RationalQ(m), Less(m, S(0))), ZeroQ(m + n + S(1))) cons1569 = CustomConstraint(cons_f1569) def cons_f1570(a, c, m, n): return Not(And(IntegerQ(n), Greater(n, S(0)), Or(Not(IntegerQ(m)), And(ZeroQ(c), NonzeroQ(a))))) cons1570 = CustomConstraint(cons_f1570) def cons_f1571(n): return Not(And(RationalQ(n), LessEqual(n, S(-1)))) cons1571 = CustomConstraint(cons_f1571) def cons_f1572(a, b, c, d, e, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, n, p), x) cons1572 = CustomConstraint(cons_f1572) def cons_f1573(m, n): return NegativeIntegerQ(m, n) cons1573 = CustomConstraint(cons_f1573) def cons_f1574(n): return NegativeIntegerQ(n + S(1)) cons1574 = CustomConstraint(cons_f1574) def cons_f1575(n): return PositiveIntegerQ(S(1)/n) cons1575 = CustomConstraint(cons_f1575) def cons_f1576(m, n): return PositiveIntegerQ((m + S(1))/n) cons1576 = CustomConstraint(cons_f1576) def cons_f1577(c, d, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, d, m, n), x) cons1577 = CustomConstraint(cons_f1577) def cons_f1578(a, b, c, d, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, m, n, p), x) cons1578 = CustomConstraint(cons_f1578) def cons_f1579(m, n): return GreaterEqual(m - n, S(0)) cons1579 = CustomConstraint(cons_f1579) def cons_f1580(q): return SameQ(q, S(1)) cons1580 = CustomConstraint(cons_f1580) def cons_f1581(a, b, c, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, n), x) cons1581 = CustomConstraint(cons_f1581) def cons_f1582(a, b, c, d, e, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, m, n), x) cons1582 = CustomConstraint(cons_f1582) def cons_f1583(m, n): return ZeroQ(m + n + S(-2)) cons1583 = CustomConstraint(cons_f1583) def cons_f1584(m, n): return IntegersQ(m, n, m/S(2) + n/S(2)) cons1584 = CustomConstraint(cons_f1584) def cons_f1585(m, n): return Not(And(IntegerQ(m/S(2) + S(1)/2), Less(S(0), m, n))) cons1585 = CustomConstraint(cons_f1585) def cons_f1586(m, n): return Not(PositiveIntegerQ(m/S(2), n/S(2) + S(-1)/2)) cons1586 = CustomConstraint(cons_f1586) def cons_f1587(n): return ZeroQ(n**S(2) + S(-1)/4) cons1587 = CustomConstraint(cons_f1587) def cons_f1588(n): return LessEqual(n, S(-1)) cons1588 = CustomConstraint(cons_f1588) def cons_f1589(a, b, d, e, f, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, d, e, f, n), x) cons1589 = CustomConstraint(cons_f1589) def cons_f1590(a, b, d): return PositiveQ(a*d/b) cons1590 = CustomConstraint(cons_f1590) def cons_f1591(a, b, d): return Not(PositiveQ(a*d/b)) cons1591 = CustomConstraint(cons_f1591) def cons_f1592(n): return Less(n, S(-1)/2) cons1592 = CustomConstraint(cons_f1592) def cons_f1593(m, n): return Or(Less(n, S(-1)), And(Equal(m, S(3)/2), Equal(n, S(-1)/2))) cons1593 = CustomConstraint(cons_f1593) def cons_f1594(m, n): return Or(IntegersQ(S(2)*m, S(2)*n), IntegerQ(m)) cons1594 = CustomConstraint(cons_f1594) def cons_f1595(a, b, d): return NegativeQ(a*d/b) cons1595 = CustomConstraint(cons_f1595) def cons_f1596(m, n): return Or(And(IntegerQ(m), Less(n, S(-1))), And(IntegersQ(m + S(1)/2, S(2)*n), LessEqual(n, S(-1)))) cons1596 = CustomConstraint(cons_f1596) def cons_f1597(m, n): return Not(And(IntegerQ(n), Greater(n, S(2)), Not(IntegerQ(m)))) cons1597 = CustomConstraint(cons_f1597) def cons_f1598(m, n): return Or(And(IntegerQ(n), Greater(n, S(3))), And(IntegersQ(n + S(1)/2, S(2)*m), Greater(n, S(2)))) cons1598 = CustomConstraint(cons_f1598) def cons_f1599(m, n): return NegativeIntegerQ(m + S(1)/2, n) cons1599 = CustomConstraint(cons_f1599) def cons_f1600(n): return Greater(n, S(3)) cons1600 = CustomConstraint(cons_f1600) def cons_f1601(n): return IntegersQ(S(2)*n) cons1601 = CustomConstraint(cons_f1601) def cons_f1602(m): return Not(And(IntegerQ(m), Greater(m, S(2)))) cons1602 = CustomConstraint(cons_f1602) def cons_f1603(n): return Less(S(0), n, S(3)) cons1603 = CustomConstraint(cons_f1603) def cons_f1604(m): return Less(S(-1), m, S(2)) cons1604 = CustomConstraint(cons_f1604) def cons_f1605(n): return Less(S(1), n, S(3)) cons1605 = CustomConstraint(cons_f1605) def cons_f1606(a, b, d, e, f, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, d, e, f, m, n), x) cons1606 = CustomConstraint(cons_f1606) def cons_f1607(a, b, e, f, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, e, f, m), x) cons1607 = CustomConstraint(cons_f1607) def cons_f1608(a, b, m, p): return Or(ZeroQ(a**S(2) - b**S(2)), IntegersQ(S(2)*m, p)) cons1608 = CustomConstraint(cons_f1608) def cons_f1609(n): return IntegerQ(n + S(-1)/2) cons1609 = CustomConstraint(cons_f1609) def cons_f1610(m): return NegativeIntegerQ(m + S(1)/2) cons1610 = CustomConstraint(cons_f1610) def cons_f1611(m): return Or(IntegerQ(m/S(2)), LessEqual(m, S(1))) cons1611 = CustomConstraint(cons_f1611) def cons_f1612(m, n): return Less(m + n, S(2)) cons1612 = CustomConstraint(cons_f1612) def cons_f1613(m, n): return Not(And(IntegerQ(n), Greater(m - n, S(0)))) cons1613 = CustomConstraint(cons_f1613) def cons_f1614(n): return Greater(n, S(1)/2) cons1614 = CustomConstraint(cons_f1614) def cons_f1615(n): return Not(And(RationalQ(n), LessEqual(n, S(-1)/2))) cons1615 = CustomConstraint(cons_f1615) def cons_f1616(m, n): return MemberQ(List(S(0), S(-1), S(-2)), m + n) cons1616 = CustomConstraint(cons_f1616) def cons_f1617(m, n): return Not(And(PositiveIntegerQ(n + S(1)/2), Less(n + S(1)/2, -m - n))) cons1617 = CustomConstraint(cons_f1617) def cons_f1618(m, n): return Not(And(PositiveIntegerQ(m + S(-1)/2), Less(m, n))) cons1618 = CustomConstraint(cons_f1618) def cons_f1619(m, n): return GreaterEqual(-m + n, S(0)) cons1619 = CustomConstraint(cons_f1619) def cons_f1620(m, n): return Greater(m*n, S(0)) cons1620 = CustomConstraint(cons_f1620) def cons_f1621(m, n): return Or(NegativeIntegerQ(m, n + S(-1)/2), And(NegativeIntegerQ(m + S(-1)/2, n + S(-1)/2), Less(m, n))) cons1621 = CustomConstraint(cons_f1621) def cons_f1622(m, p): return Or(ZeroQ(p + S(-1)), IntegerQ(m + S(-1)/2)) cons1622 = CustomConstraint(cons_f1622) def cons_f1623(m, n, p): return ZeroQ(m + n + p) cons1623 = CustomConstraint(cons_f1623) def cons_f1624(m, n, p): return MemberQ(List(S(-1), S(-2)), m + n + p) cons1624 = CustomConstraint(cons_f1624) def cons_f1625(A, B, a, b, m): return ZeroQ(A*b*(m + S(1)) + B*a*m) cons1625 = CustomConstraint(cons_f1625) def cons_f1626(A, B, a, b, m): return NonzeroQ(A*b*(m + S(1)) + B*a*m) cons1626 = CustomConstraint(cons_f1626) def cons_f1627(A, B): return ZeroQ(A**S(2) - B**S(2)) cons1627 = CustomConstraint(cons_f1627) def cons_f1628(A, B): return NonzeroQ(A**S(2) - B**S(2)) cons1628 = CustomConstraint(cons_f1628) def cons_f1629(A, B, a, b, m, n): return ZeroQ(A*a*m - B*b*n) cons1629 = CustomConstraint(cons_f1629) def cons_f1630(A, B, a, b, n): return ZeroQ(A*b*(S(2)*n + S(1)) + S(2)*B*a*n) cons1630 = CustomConstraint(cons_f1630) def cons_f1631(A, B, a, b, n): return NonzeroQ(A*b*(S(2)*n + S(1)) + S(2)*B*a*n) cons1631 = CustomConstraint(cons_f1631) def cons_f1632(m, n): return Not(And(IntegerQ(n), Greater(n, S(1)), Not(IntegerQ(m)))) cons1632 = CustomConstraint(cons_f1632) def cons_f1633(m, n): return Not(NegativeIntegerQ(m + S(1)/2, n)) cons1633 = CustomConstraint(cons_f1633) def cons_f1634(m): return Not(And(IntegerQ(m), Greater(m, S(1)))) cons1634 = CustomConstraint(cons_f1634) def cons_f1635(A, C, m): return ZeroQ(A*(m + S(1)) + C*m) cons1635 = CustomConstraint(cons_f1635) def cons_f1636(A, C, m): return NonzeroQ(A*(m + S(1)) + C*m) cons1636 = CustomConstraint(cons_f1636) def cons_f1637(A, B, C, b, e, f, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, e, f, A, B, C, m), x) cons1637 = CustomConstraint(cons_f1637) def cons_f1638(A, B, C, a, b, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, e, f, A, B, C), x) cons1638 = CustomConstraint(cons_f1638) def cons_f1639(A, C, a, b, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, e, f, A, C), x) cons1639 = CustomConstraint(cons_f1639) def cons_f1640(m): return PositiveIntegerQ(S(2)*m) cons1640 = CustomConstraint(cons_f1640) def cons_f1641(m, n): return Or(And(RationalQ(n), Less(n, S(-1)/2)), ZeroQ(m + n + S(1))) cons1641 = CustomConstraint(cons_f1641) def cons_f1642(n): return Not(And(RationalQ(n), Less(n, S(-1)/2))) cons1642 = CustomConstraint(cons_f1642) def cons_f1643(A, B, C, a, b, d, e, f, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, d, e, f, A, B, C, m, n), x) cons1643 = CustomConstraint(cons_f1643) def cons_f1644(A, C, a, b, d, e, f, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, d, e, f, A, C, m, n), x) cons1644 = CustomConstraint(cons_f1644) def cons_f1645(b, c, d, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, c, d, n), x) cons1645 = CustomConstraint(cons_f1645) def cons_f1646(n): return Unequal(n, S(2)) cons1646 = CustomConstraint(cons_f1646) def cons_f1647(p): return NonzeroQ(p + S(-1)) cons1647 = CustomConstraint(cons_f1647) def cons_f1648(u, x): if isinstance(x, (int, Integer, float, Float)): return False return KnownSineIntegrandQ(u, x) cons1648 = CustomConstraint(cons_f1648) def cons_f1649(A, B, C, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, A, B, C), x) cons1649 = CustomConstraint(cons_f1649) def cons_f1650(n, n1): return ZeroQ(-n + n1 + S(-1)) cons1650 = CustomConstraint(cons_f1650) def cons_f1651(n, n2): return ZeroQ(-n + n2 + S(-2)) cons1651 = CustomConstraint(cons_f1651) def cons_f1652(u, x): if isinstance(x, (int, Integer, float, Float)): return False return KnownTangentIntegrandQ(u, x) cons1652 = CustomConstraint(cons_f1652) def cons_f1653(u, x): if isinstance(x, (int, Integer, float, Float)): return False return KnownCotangentIntegrandQ(u, x) cons1653 = CustomConstraint(cons_f1653) def cons_f1654(u, x): if isinstance(x, (int, Integer, float, Float)): return False return KnownSecantIntegrandQ(u, x) cons1654 = CustomConstraint(cons_f1654) def cons_f1655(b, d): return NonzeroQ(b**S(2) - d**S(2)) cons1655 = CustomConstraint(cons_f1655) def cons_f1656(b, d): return ZeroQ(S(-2) + d/b) cons1656 = CustomConstraint(cons_f1656) def cons_f1657(m, p): return Or(Greater(m, S(3)), Equal(p, S(-3)/2)) cons1657 = CustomConstraint(cons_f1657) def cons_f1658(m, p): return Or(Less(p, S(-2)), Equal(m, S(2))) cons1658 = CustomConstraint(cons_f1658) def cons_f1659(m, n, p): return ZeroQ(m + n + S(2)*p + S(2)) cons1659 = CustomConstraint(cons_f1659) def cons_f1660(m): return Greater(m, S(3)) cons1660 = CustomConstraint(cons_f1660) def cons_f1661(n, p): return NonzeroQ(n + p + S(1)) cons1661 = CustomConstraint(cons_f1661) def cons_f1662(m, n, p): return NonzeroQ(m + n + S(2)*p + S(2)) cons1662 = CustomConstraint(cons_f1662) def cons_f1663(m, p): return Or(Less(p, S(-2)), Equal(m, S(2)), Equal(m, S(3))) cons1663 = CustomConstraint(cons_f1663) def cons_f1664(m, n, p): return NonzeroQ(m + n + S(2)*p) cons1664 = CustomConstraint(cons_f1664) def cons_f1665(b, d, m): return ZeroQ(-Abs(m + S(2)) + d/b) cons1665 = CustomConstraint(cons_f1665) def cons_f1666(F): return InertTrigQ(F) cons1666 = CustomConstraint(cons_f1666) def cons_f1667(F, G): return InertTrigQ(F, G) cons1667 = CustomConstraint(cons_f1667) def cons_f1668(F): return Or(SameQ(F, Cos), SameQ(F, cos)) cons1668 = CustomConstraint(cons_f1668) def cons_f1669(F): return Or(SameQ(F, Sin), SameQ(F, sin)) cons1669 = CustomConstraint(cons_f1669) def cons_f1670(F): return Or(SameQ(F, Cot), SameQ(F, cot)) cons1670 = CustomConstraint(cons_f1670) def cons_f1671(F): return Or(SameQ(F, Tan), SameQ(F, tan)) cons1671 = CustomConstraint(cons_f1671) def cons_f1672(F): return Or(SameQ(F, Sec), SameQ(F, sec)) cons1672 = CustomConstraint(cons_f1672) def cons_f1673(F): return Or(SameQ(F, Csc), SameQ(F, csc)) cons1673 = CustomConstraint(cons_f1673) def cons_f1674(F): return Or(SameQ(F, sin), SameQ(F, cos)) cons1674 = CustomConstraint(cons_f1674) def cons_f1675(G): return Or(SameQ(G, sin), SameQ(G, cos)) cons1675 = CustomConstraint(cons_f1675) def cons_f1676(H): return Or(SameQ(H, sin), SameQ(H, cos)) cons1676 = CustomConstraint(cons_f1676) def cons_f1677(b, c): return ZeroQ(b - c) cons1677 = CustomConstraint(cons_f1677) def cons_f1678(b, c): return ZeroQ(b + c) cons1678 = CustomConstraint(cons_f1678) def cons_f1679(u): return Not(InertTrigFreeQ(u)) cons1679 = CustomConstraint(cons_f1679) def cons_f1680(p): return NegQ(p) cons1680 = CustomConstraint(cons_f1680) def cons_f1681(u): return TrigSimplifyQ(u) cons1681 = CustomConstraint(cons_f1681) def cons_f1682(v): return Not(InertTrigFreeQ(v)) cons1682 = CustomConstraint(cons_f1682) def cons_f1683(v, w): return Or(Not(InertTrigFreeQ(v)), Not(InertTrigFreeQ(w))) cons1683 = CustomConstraint(cons_f1683) def cons_f1684(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: return Not(FalseQ(FunctionOfTrig(u, x))) except (TypeError, AttributeError): return False cons1684 = CustomConstraint(cons_f1684) def cons_f1685(p): return SameQ(p, S(1)) cons1685 = CustomConstraint(cons_f1685) def cons_f1686(n, p): return Or(EvenQ(n), OddQ(p)) cons1686 = CustomConstraint(cons_f1686) def cons_f1687(n, p): return Unequal(n, p) cons1687 = CustomConstraint(cons_f1687) def cons_f1688(F): return TrigQ(F) cons1688 = CustomConstraint(cons_f1688) def cons_f1689(G): return TrigQ(G) cons1689 = CustomConstraint(cons_f1689) def cons_f1690(v, w): return ZeroQ(v - w) cons1690 = CustomConstraint(cons_f1690) def cons_f1691(F): return MemberQ(List(Sin, Cos), F) cons1691 = CustomConstraint(cons_f1691) def cons_f1692(G): return MemberQ(List(Sec, Csc), G) cons1692 = CustomConstraint(cons_f1692) def cons_f1693(b, d): return PositiveIntegerQ(b/d + S(-1)) cons1693 = CustomConstraint(cons_f1693) def cons_f1694(F, b, c, e): return NonzeroQ(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)) cons1694 = CustomConstraint(cons_f1694) def cons_f1695(F, b, c, e, n): return NonzeroQ(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)) cons1695 = CustomConstraint(cons_f1695) def cons_f1696(F, b, c, e, m): return NonzeroQ(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*m**S(2)) cons1696 = CustomConstraint(cons_f1696) def cons_f1697(F, b, c, e, n): return ZeroQ(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2)) cons1697 = CustomConstraint(cons_f1697) def cons_f1698(F, b, c, e, n): return NonzeroQ(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2)) cons1698 = CustomConstraint(cons_f1698) def cons_f1699(F, b, c, e, n): return ZeroQ(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2)) cons1699 = CustomConstraint(cons_f1699) def cons_f1700(F, b, c, e, n): return NonzeroQ(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2)) cons1700 = CustomConstraint(cons_f1700) def cons_f1701(f, g): return ZeroQ(f**S(2) - g**S(2)) cons1701 = CustomConstraint(cons_f1701) def cons_f1702(f, g): return ZeroQ(f - g) cons1702 = CustomConstraint(cons_f1702) def cons_f1703(h, i): return ZeroQ(h**S(2) - i**S(2)) cons1703 = CustomConstraint(cons_f1703) def cons_f1704(f, g, h, i): return ZeroQ(-f*i + g*h) cons1704 = CustomConstraint(cons_f1704) def cons_f1705(f, g, h, i): return ZeroQ(f*i + g*h) cons1705 = CustomConstraint(cons_f1705) def cons_f1706(m, n, p): return PositiveIntegerQ(m, n, p) cons1706 = CustomConstraint(cons_f1706) def cons_f1707(H): return TrigQ(H) cons1707 = CustomConstraint(cons_f1707) def cons_f1708(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(LinearQ(u, x), PolyQ(u, x, S(2))) cons1708 = CustomConstraint(cons_f1708) def cons_f1709(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(LinearQ(v, x), PolyQ(v, x, S(2))) cons1709 = CustomConstraint(cons_f1709) def cons_f1710(b, n, p): return ZeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) + S(1)) cons1710 = CustomConstraint(cons_f1710) def cons_f1711(b, n, p): return ZeroQ(b**S(2)*n**S(2)*p**S(2) + S(1)) cons1711 = CustomConstraint(cons_f1711) def cons_f1712(b, n): return NonzeroQ(b**S(2)*n**S(2) + S(1)) cons1712 = CustomConstraint(cons_f1712) def cons_f1713(b, n, p): return NonzeroQ(b**S(2)*n**S(2)*p**S(2) + S(1)) cons1713 = CustomConstraint(cons_f1713) def cons_f1714(b, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) + S(1)) cons1714 = CustomConstraint(cons_f1714) def cons_f1715(b, m, n, p): return ZeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) + (m + S(1))**S(2)) cons1715 = CustomConstraint(cons_f1715) def cons_f1716(b, m, n, p): return ZeroQ(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)) cons1716 = CustomConstraint(cons_f1716) def cons_f1717(b, m, n): return NonzeroQ(b**S(2)*n**S(2) + (m + S(1))**S(2)) cons1717 = CustomConstraint(cons_f1717) def cons_f1718(b, m, n, p): return NonzeroQ(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)) cons1718 = CustomConstraint(cons_f1718) def cons_f1719(b, m, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) + (m + S(1))**S(2)) cons1719 = CustomConstraint(cons_f1719) def cons_f1720(b, n): return ZeroQ(b**S(2)*n**S(2) + S(1)) cons1720 = CustomConstraint(cons_f1720) def cons_f1721(b, n, p): return ZeroQ(b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(1)) cons1721 = CustomConstraint(cons_f1721) def cons_f1722(p): return Unequal(p, S(2)) cons1722 = CustomConstraint(cons_f1722) def cons_f1723(b, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(1)) cons1723 = CustomConstraint(cons_f1723) def cons_f1724(b, m, n): return ZeroQ(b**S(2)*n**S(2) + (m + S(1))**S(2)) cons1724 = CustomConstraint(cons_f1724) def cons_f1725(b, m, n, p): return ZeroQ(b**S(2)*n**S(2)*(p + S(-2))**S(2) + (m + S(1))**S(2)) cons1725 = CustomConstraint(cons_f1725) def cons_f1726(b, m, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(-2))**S(2) + (m + S(1))**S(2)) cons1726 = CustomConstraint(cons_f1726) def cons_f1727(u, x): if isinstance(x, (int, Integer, float, Float)): return False return QuotientOfLinearsQ(u, x) cons1727 = CustomConstraint(cons_f1727) def cons_f1728(v, w, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(And(PolynomialQ(v, x), PolynomialQ(w, x)), And(BinomialQ(List(v, w), x), IndependentQ(v/w, x))) cons1728 = CustomConstraint(cons_f1728) def cons_f1729(m, p, q): return PositiveIntegerQ(m, p, q) cons1729 = CustomConstraint(cons_f1729) def cons_f1730(v, w): return NonzeroQ(v - w) cons1730 = CustomConstraint(cons_f1730) def cons_f1731(m, n): return Or(Equal(n, S(-1)), And(Equal(m, S(1)), Equal(n, S(-2)))) cons1731 = CustomConstraint(cons_f1731) def cons_f1732(a, c): return NonzeroQ(a + c) cons1732 = CustomConstraint(cons_f1732) def cons_f1733(a, b): return PosQ(a**S(2) - b**S(2)) cons1733 = CustomConstraint(cons_f1733) def cons_f1734(a, b): return NegQ(a**S(2) - b**S(2)) cons1734 = CustomConstraint(cons_f1734) def cons_f1735(b, d): return ZeroQ(b**S(2) - d**S(2)) cons1735 = CustomConstraint(cons_f1735) def cons_f1736(n): return Inequality(S(-2), LessEqual, n, Less, S(-1)) cons1736 = CustomConstraint(cons_f1736) def cons_f1737(n): return Less(n, S(-2)) cons1737 = CustomConstraint(cons_f1737) def cons_f1738(a, b, c, d, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, m, n), x) cons1738 = CustomConstraint(cons_f1738) def cons_f1739(c, d, e): return ZeroQ(c**S(2)*d + e) cons1739 = CustomConstraint(cons_f1739) def cons_f1740(d): return Not(PositiveQ(d)) cons1740 = CustomConstraint(cons_f1740) def cons_f1741(p): return PositiveIntegerQ(S(2)*p) cons1741 = CustomConstraint(cons_f1741) def cons_f1742(d, p): return Or(IntegerQ(p), PositiveQ(d)) cons1742 = CustomConstraint(cons_f1742) def cons_f1743(d, p): return Not(Or(IntegerQ(p), PositiveQ(d))) cons1743 = CustomConstraint(cons_f1743) def cons_f1744(c, d, e): return NonzeroQ(c**S(2)*d + e) cons1744 = CustomConstraint(cons_f1744) def cons_f1745(p): return Or(PositiveIntegerQ(p), NegativeIntegerQ(p + S(1)/2)) cons1745 = CustomConstraint(cons_f1745) def cons_f1746(n, p): return Or(Greater(p, S(0)), PositiveIntegerQ(n)) cons1746 = CustomConstraint(cons_f1746) def cons_f1747(c, f, g): return ZeroQ(c**S(2)*f**S(2) - g**S(2)) cons1747 = CustomConstraint(cons_f1747) def cons_f1748(m): return NegativeIntegerQ(m/S(2) + S(1)/2) cons1748 = CustomConstraint(cons_f1748) def cons_f1749(m, p): return Or(PositiveIntegerQ(m/S(2) + S(1)/2), NegativeIntegerQ(m/S(2) + p + S(3)/2)) cons1749 = CustomConstraint(cons_f1749) def cons_f1750(m, n): return Or(RationalQ(m), ZeroQ(n + S(-1))) cons1750 = CustomConstraint(cons_f1750) def cons_f1751(m, n, p): return Or(IntegerQ(m), IntegerQ(p), Equal(n, S(1))) cons1751 = CustomConstraint(cons_f1751) def cons_f1752(m, n): return Or(IntegerQ(m), Equal(n, S(1))) cons1752 = CustomConstraint(cons_f1752) def cons_f1753(m): return Greater(m, S(-3)) cons1753 = CustomConstraint(cons_f1753) def cons_f1754(p): return Greater(p, S(-1)) cons1754 = CustomConstraint(cons_f1754) def cons_f1755(m): return Not(PositiveIntegerQ(m/S(2) + S(1)/2)) cons1755 = CustomConstraint(cons_f1755) def cons_f1756(m): return Less(S(-3), m, S(0)) cons1756 = CustomConstraint(cons_f1756) def cons_f1757(m, p): return Or(Greater(p, S(0)), And(PositiveIntegerQ(m/S(2) + S(-1)/2), LessEqual(m + p, S(0)))) cons1757 = CustomConstraint(cons_f1757) def cons_f1758(a, b, c, d, e, f, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, m, n, p), x) cons1758 = CustomConstraint(cons_f1758) def cons_f1759(m, p): return Less(m + p + S(1), S(0)) cons1759 = CustomConstraint(cons_f1759) def cons_f1760(d, e, g, h): return ZeroQ(-S(2)*d*h + e*g) cons1760 = CustomConstraint(cons_f1760) def cons_f1761(m, p): return Or(Less(m, -S(2)*p + S(-1)), Greater(m, S(3))) cons1761 = CustomConstraint(cons_f1761) def cons_f1762(m, n, p): return Or(And(Equal(n, S(1)), Greater(p, S(-1))), Greater(p, S(0)), Equal(m, S(1)), And(Equal(m, S(2)), Less(p, S(-2)))) cons1762 = CustomConstraint(cons_f1762) def cons_f1763(m, n): return Or(Greater(m, S(0)), PositiveIntegerQ(n)) cons1763 = CustomConstraint(cons_f1763) def cons_f1764(A, B, c, d): return ZeroQ(S(2)*A*c*d + B*(S(1) - c**S(2))) cons1764 = CustomConstraint(cons_f1764) def cons_f1765(B, C, c, d): return ZeroQ(-B*d + S(2)*C*c) cons1765 = CustomConstraint(cons_f1765) def cons_f1766(c): return ZeroQ(c**S(2) + S(-1)) cons1766 = CustomConstraint(cons_f1766) def cons_f1767(a, b, d, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, d), x) cons1767 = CustomConstraint(cons_f1767) def cons_f1768(a, b, c, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, n, m), x) cons1768 = CustomConstraint(cons_f1768) def cons_f1769(b, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(b, n), x) cons1769 = CustomConstraint(cons_f1769) def cons_f1770(b, c): return EqQ(b**S(2)*c, S(1)) cons1770 = CustomConstraint(cons_f1770) def cons_f1771(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(FunctionOfExponentialQ(u, x)) cons1771 = CustomConstraint(cons_f1771) def cons_f1772(c, d, m, u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(FunctionOfQ((c + d*x)**(m + S(1)), u, x)) cons1772 = CustomConstraint(cons_f1772) def cons_f1773(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1772(c, d, m): return FreeQ(List(c, d, m), x) _cons_1772 = CustomConstraint(_cons_f_1772) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1772) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1773 = CustomConstraint(cons_f1773) def cons_f1774(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1773(c, d, m): return FreeQ(List(c, d, m), x) _cons_1773 = CustomConstraint(_cons_f_1773) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1773) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1774 = CustomConstraint(cons_f1774) def cons_f1775(c, d, e): return ZeroQ(c**S(2)*d**S(2) + e**S(2)) cons1775 = CustomConstraint(cons_f1775) def cons_f1776(c, d, e): return PositiveQ(I*c*d/e + S(1)) cons1776 = CustomConstraint(cons_f1776) def cons_f1777(c, d, e): return NegativeQ(I*c*d/e + S(-1)) cons1777 = CustomConstraint(cons_f1777) def cons_f1778(c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(c, d, e), x) cons1778 = CustomConstraint(cons_f1778) def cons_f1779(a, m, p): return Or(Greater(p, S(0)), NonzeroQ(a), IntegerQ(m)) cons1779 = CustomConstraint(cons_f1779) def cons_f1780(c, d, e): return ZeroQ(-c**S(2)*d + e) cons1780 = CustomConstraint(cons_f1780) def cons_f1781(p): return NegativeIntegerQ(S(2)*p + S(2)) cons1781 = CustomConstraint(cons_f1781) def cons_f1782(p): return Or(IntegerQ(p), NegativeIntegerQ(p + S(1)/2)) cons1782 = CustomConstraint(cons_f1782) def cons_f1783(a, m): return Not(And(Equal(m, S(1)), NonzeroQ(a))) cons1783 = CustomConstraint(cons_f1783) def cons_f1784(p): return Unequal(p, S(-5)/2) cons1784 = CustomConstraint(cons_f1784) def cons_f1785(m, n, p): return Or(RationalQ(m), And(EqQ(n, S(1)), IntegerQ(p))) cons1785 = CustomConstraint(cons_f1785) def cons_f1786(m, n, p): return IntegersQ(m, n, S(2)*p) cons1786 = CustomConstraint(cons_f1786) def cons_f1787(m, p): return NegativeIntegerQ(m + S(2)*p + S(1)) cons1787 = CustomConstraint(cons_f1787) def cons_f1788(m, p): return Or(And(PositiveIntegerQ(p), Not(And(NegativeIntegerQ(m/S(2) + S(-1)/2), Greater(m + S(2)*p + S(3), S(0))))), And(PositiveIntegerQ(m/S(2) + S(1)/2), Not(And(NegativeIntegerQ(p), Greater(m + S(2)*p + S(3), S(0))))), And(NegativeIntegerQ(m/S(2) + p + S(1)/2), Not(NegativeIntegerQ(m/S(2) + S(-1)/2)))) cons1788 = CustomConstraint(cons_f1788) def cons_f1789(m, p): return Or(Greater(p, S(0)), And(Less(p, S(-1)), IntegerQ(m), Unequal(m, S(1)))) cons1789 = CustomConstraint(cons_f1789) def cons_f1790(a, b, c, d, e, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, m, p), x) cons1790 = CustomConstraint(cons_f1790) def cons_f1791(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(u**S(2) - (S(1) - S(2)*I/(c*x + I))**S(2)) cons1791 = CustomConstraint(cons_f1791) def cons_f1792(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(u**S(2) - (S(1) - S(2)*I/(-c*x + I))**S(2)) cons1792 = CustomConstraint(cons_f1792) def cons_f1793(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ((S(1) - u)**S(2) - (S(1) - S(2)*I/(c*x + I))**S(2)) cons1793 = CustomConstraint(cons_f1793) def cons_f1794(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ((S(1) - u)**S(2) - (S(1) - S(2)*I/(-c*x + I))**S(2)) cons1794 = CustomConstraint(cons_f1794) def cons_f1795(m, n): return Inequality(S(0), Less, n, LessEqual, m) cons1795 = CustomConstraint(cons_f1795) def cons_f1796(m, n): return Less(S(0), n, m) cons1796 = CustomConstraint(cons_f1796) def cons_f1797(a, c, d, n): return Not(And(Equal(n, S(2)), ZeroQ(-a**S(2)*c + d))) cons1797 = CustomConstraint(cons_f1797) def cons_f1798(a, b, c, d, e, f, g, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, e, f, g), x) cons1798 = CustomConstraint(cons_f1798) def cons_f1799(m): return PositiveIntegerQ(m/S(2) + S(1)/2) cons1799 = CustomConstraint(cons_f1799) def cons_f1800(c, f, g): return ZeroQ(-c**S(2)*f + g) cons1800 = CustomConstraint(cons_f1800) def cons_f1801(n): return OddQ(I*n) cons1801 = CustomConstraint(cons_f1801) def cons_f1802(n): return Not(OddQ(I*n)) cons1802 = CustomConstraint(cons_f1802) def cons_f1803(a, c, d): return ZeroQ(a**S(2)*c**S(2) + d**S(2)) cons1803 = CustomConstraint(cons_f1803) def cons_f1804(c, p): return Or(IntegerQ(p), PositiveQ(c)) cons1804 = CustomConstraint(cons_f1804) def cons_f1805(c, p): return Not(Or(IntegerQ(p), PositiveQ(c))) cons1805 = CustomConstraint(cons_f1805) def cons_f1806(a, c, d): return ZeroQ(a**S(2)*d**S(2) + c**S(2)) cons1806 = CustomConstraint(cons_f1806) def cons_f1807(n): return IntegerQ(I*n/S(2)) cons1807 = CustomConstraint(cons_f1807) def cons_f1808(a, c, d): return ZeroQ(-a**S(2)*c + d) cons1808 = CustomConstraint(cons_f1808) def cons_f1809(n): return Not(IntegerQ(I*n)) cons1809 = CustomConstraint(cons_f1809) def cons_f1810(n, p): return NonzeroQ(n**S(2) + S(4)*(p + S(1))**S(2)) cons1810 = CustomConstraint(cons_f1810) def cons_f1811(n): return IntegerQ(I*n/S(2) + S(1)/2) cons1811 = CustomConstraint(cons_f1811) def cons_f1812(n, p): return Not(IntegerQ(-I*n/S(2) + p)) cons1812 = CustomConstraint(cons_f1812) def cons_f1813(n): return PositiveIntegerQ(I*n/S(2)) cons1813 = CustomConstraint(cons_f1813) def cons_f1814(n): return NegativeIntegerQ(I*n/S(2)) cons1814 = CustomConstraint(cons_f1814) def cons_f1815(n, p): return ZeroQ(n**S(2) - S(2)*p + S(-2)) cons1815 = CustomConstraint(cons_f1815) def cons_f1816(n): return Not(IntegerQ(I*n/S(2))) cons1816 = CustomConstraint(cons_f1816) def cons_f1817(a, c, d): return ZeroQ(-a**S(2)*d + c) cons1817 = CustomConstraint(cons_f1817) def cons_f1818(n): return RationalQ(I*n) cons1818 = CustomConstraint(cons_f1818) def cons_f1819(n): return Less(S(-1), I*n, S(1)) cons1819 = CustomConstraint(cons_f1819) def cons_f1820(a, b, d, e): return ZeroQ(-S(2)*a*e + b*d) cons1820 = CustomConstraint(cons_f1820) def cons_f1821(a, b, c, e): return ZeroQ(b**S(2)*c - e*(a**S(2) + S(1))) cons1821 = CustomConstraint(cons_f1821) def cons_f1822(a, c, p): return Or(IntegerQ(p), PositiveQ(c/(a**S(2) + S(1)))) cons1822 = CustomConstraint(cons_f1822) def cons_f1823(a, c, p): return Not(Or(IntegerQ(p), PositiveQ(c/(a**S(2) + S(1))))) cons1823 = CustomConstraint(cons_f1823) def cons_f1824(n, p): return Not(And(IntegerQ(p), EvenQ(I*n))) cons1824 = CustomConstraint(cons_f1824) def cons_f1825(n, p): return Not(And(Not(IntegerQ(p)), OddQ(I*n))) cons1825 = CustomConstraint(cons_f1825) def cons_f1826(p): return LessEqual(p, S(-1)) cons1826 = CustomConstraint(cons_f1826) def cons_f1827(n): return NonzeroQ(n**S(2) + S(1)) cons1827 = CustomConstraint(cons_f1827) def cons_f1828(n, p): return NonzeroQ(n**S(2) - S(2)*p + S(-2)) cons1828 = CustomConstraint(cons_f1828) def cons_f1829(m, p): return LessEqual(S(3), m, -S(2)*p + S(-2)) cons1829 = CustomConstraint(cons_f1829) def cons_f1830(n, p): return IntegersQ(S(2)*p, I*n/S(2) + p) cons1830 = CustomConstraint(cons_f1830) def cons_f1831(n, p): return Not(IntegersQ(S(2)*p, I*n/S(2) + p)) cons1831 = CustomConstraint(cons_f1831) def cons_f1832(A, B, c, d): return ZeroQ(-S(2)*A*c*d + B*(c**S(2) + S(1))) cons1832 = CustomConstraint(cons_f1832) def cons_f1833(a, b, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, n), x) cons1833 = CustomConstraint(cons_f1833) def cons_f1834(m): return Unequal(m + S(1), S(0)) cons1834 = CustomConstraint(cons_f1834) def cons_f1835(m, n): return Unequal(m + S(1), n) cons1835 = CustomConstraint(cons_f1835) def cons_f1836(a, b, c, d, f, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, f), x) cons1836 = CustomConstraint(cons_f1836) def cons_f1837(b, c): return ZeroQ(b + c**S(2)) cons1837 = CustomConstraint(cons_f1837) def cons_f1838(s): return ZeroQ(s**S(2) + S(-1)) cons1838 = CustomConstraint(cons_f1838) def cons_f1839(v, w): return ZeroQ(-v**S(2) + w + S(-1)) cons1839 = CustomConstraint(cons_f1839) def cons_f1840(v, x): if isinstance(x, (int, Integer, float, Float)): return False return NegQ(Discriminant(v, x)) cons1840 = CustomConstraint(cons_f1840) def cons_f1841(u, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1840(f, r, w): return FreeQ(f, x) _cons_1840 = CustomConstraint(_cons_f_1840) pat = Pattern(UtilityOperator(f_**w_*WC('r', S(1)), x), _cons_1840) result_matchq = is_match(UtilityOperator(u, x), pat) return result_matchq cons1841 = CustomConstraint(cons_f1841) def cons_f1842(u, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1841(f, r, w): return FreeQ(f, x) _cons_1841 = CustomConstraint(_cons_f_1841) pat = Pattern(UtilityOperator(f_**w_*WC('r', S(1)), x), _cons_1841) result_matchq = is_match(UtilityOperator(u, x), pat) return result_matchq cons1842 = CustomConstraint(cons_f1842) def cons_f1843(c, d): return ZeroQ((c + I*d)**S(2) + S(1)) cons1843 = CustomConstraint(cons_f1843) def cons_f1844(c, d): return ZeroQ((c - I*d)**S(2) + S(1)) cons1844 = CustomConstraint(cons_f1844) def cons_f1845(c, d): return NonzeroQ((c + I*d)**S(2) + S(1)) cons1845 = CustomConstraint(cons_f1845) def cons_f1846(c, d): return NonzeroQ((c - I*d)**S(2) + S(1)) cons1846 = CustomConstraint(cons_f1846) def cons_f1847(c, d): return ZeroQ((c - d)**S(2) + S(1)) cons1847 = CustomConstraint(cons_f1847) def cons_f1848(c, d): return NonzeroQ((c - d)**S(2) + S(1)) cons1848 = CustomConstraint(cons_f1848) def cons_f1849(m, u, x): if isinstance(x, (int, Integer, float, Float)): return False try: return FalseQ(PowerVariableExpn(u, m + S(1), x)) except (TypeError, AttributeError): return False cons1849 = CustomConstraint(cons_f1849) def cons_f1850(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1849(c, d, m): return FreeQ(List(c, d, m), x) _cons_1849 = CustomConstraint(_cons_f_1849) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1849) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1850 = CustomConstraint(cons_f1850) def cons_f1851(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: return FalseQ(FunctionOfLinear(v*(a + b*ArcTan(u)), x)) except (TypeError, AttributeError): return False cons1851 = CustomConstraint(cons_f1851) def cons_f1852(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1851(c, d, m): return FreeQ(List(c, d, m), x) _cons_1851 = CustomConstraint(_cons_f_1851) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1851) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1852 = CustomConstraint(cons_f1852) def cons_f1853(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: return FalseQ(FunctionOfLinear(v*(a + b*acot(u)), x)) except (TypeError, AttributeError): return False cons1853 = CustomConstraint(cons_f1853) def cons_f1854(a, b, v, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(D(v/(a + b*x), x)) cons1854 = CustomConstraint(cons_f1854) def cons_f1855(a, b, w, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(D(w/(a + b*x), x)) cons1855 = CustomConstraint(cons_f1855) def cons_f1856(a, b, c, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, m, n), x) cons1856 = CustomConstraint(cons_f1856) def cons_f1857(d): return Negative(d) cons1857 = CustomConstraint(cons_f1857) def cons_f1858(d, e): return Not(And(PositiveQ(e), Negative(d))) cons1858 = CustomConstraint(cons_f1858) def cons_f1859(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1858(c, d, m): return FreeQ(List(c, d, m), x) _cons_1858 = CustomConstraint(_cons_f_1858) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1858) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1859 = CustomConstraint(cons_f1859) def cons_f1860(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1859(c, d, m): return FreeQ(List(c, d, m), x) _cons_1859 = CustomConstraint(_cons_f_1859) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1859) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1860 = CustomConstraint(cons_f1860) def cons_f1861(a, b, m, n): return Or(Equal(n, S(1)), PositiveIntegerQ(m), NonzeroQ(a**S(2) + b**S(2))) cons1861 = CustomConstraint(cons_f1861) def cons_f1862(F): return HyperbolicQ(F) cons1862 = CustomConstraint(cons_f1862) def cons_f1863(G): return HyperbolicQ(G) cons1863 = CustomConstraint(cons_f1863) def cons_f1864(F): return MemberQ(List(Sinh, Cosh), F) cons1864 = CustomConstraint(cons_f1864) def cons_f1865(G): return MemberQ(List(Sech, Csch), G) cons1865 = CustomConstraint(cons_f1865) def cons_f1866(F, b, c, e): return NonzeroQ(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)) cons1866 = CustomConstraint(cons_f1866) def cons_f1867(F, b, c, e, n): return NonzeroQ(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)) cons1867 = CustomConstraint(cons_f1867) def cons_f1868(F, b, c, e, n): return ZeroQ(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2)) cons1868 = CustomConstraint(cons_f1868) def cons_f1869(F, b, c, e, n): return NonzeroQ(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2)) cons1869 = CustomConstraint(cons_f1869) def cons_f1870(F, b, c, e, n): return ZeroQ(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2)) cons1870 = CustomConstraint(cons_f1870) def cons_f1871(F, b, c, e, n): return NonzeroQ(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2)) cons1871 = CustomConstraint(cons_f1871) def cons_f1872(f, g): return ZeroQ(f**S(2) + g**S(2)) cons1872 = CustomConstraint(cons_f1872) def cons_f1873(h, i): return ZeroQ(h**S(2) + i**S(2)) cons1873 = CustomConstraint(cons_f1873) def cons_f1874(H): return HyperbolicQ(H) cons1874 = CustomConstraint(cons_f1874) def cons_f1875(b, n, p): return RationalQ(b, n, p) cons1875 = CustomConstraint(cons_f1875) def cons_f1876(b, n, p): return ZeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) + S(-1)) cons1876 = CustomConstraint(cons_f1876) def cons_f1877(b, n): return ZeroQ(b*n + S(-2)) cons1877 = CustomConstraint(cons_f1877) def cons_f1878(b, n, p): return ZeroQ(b**S(2)*n**S(2)*p**S(2) + S(-1)) cons1878 = CustomConstraint(cons_f1878) def cons_f1879(b, n): return NonzeroQ(b**S(2)*n**S(2) + S(-1)) cons1879 = CustomConstraint(cons_f1879) def cons_f1880(b, n, p): return NonzeroQ(b**S(2)*n**S(2)*p**S(2) + S(-1)) cons1880 = CustomConstraint(cons_f1880) def cons_f1881(b, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) + S(-1)) cons1881 = CustomConstraint(cons_f1881) def cons_f1882(b, m, n, p): return ZeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) - (m + S(1))**S(2)) cons1882 = CustomConstraint(cons_f1882) def cons_f1883(b, m, n, p): return ZeroQ(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)) cons1883 = CustomConstraint(cons_f1883) def cons_f1884(b, m, n): return NonzeroQ(b**S(2)*n**S(2) - (m + S(1))**S(2)) cons1884 = CustomConstraint(cons_f1884) def cons_f1885(b, m, n, p): return NonzeroQ(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)) cons1885 = CustomConstraint(cons_f1885) def cons_f1886(b, m, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(2))**S(2) - (m + S(1))**S(2)) cons1886 = CustomConstraint(cons_f1886) def cons_f1887(b, n): return ZeroQ(b**S(2)*n**S(2) + S(-1)) cons1887 = CustomConstraint(cons_f1887) def cons_f1888(b, n, p): return ZeroQ(b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(-1)) cons1888 = CustomConstraint(cons_f1888) def cons_f1889(b, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(-1)) cons1889 = CustomConstraint(cons_f1889) def cons_f1890(b, m, n, p): return RationalQ(b, m, n, p) cons1890 = CustomConstraint(cons_f1890) def cons_f1891(b, m, n): return ZeroQ(b**S(2)*n**S(2) - (m + S(1))**S(2)) cons1891 = CustomConstraint(cons_f1891) def cons_f1892(b, m, n, p): return NonzeroQ(b**S(2)*n**S(2)*(p + S(-2))**S(2) - (m + S(1))**S(2)) cons1892 = CustomConstraint(cons_f1892) def cons_f1893(A, B, a, b): return ZeroQ(A*a + B*b) cons1893 = CustomConstraint(cons_f1893) def cons_f1894(c, d1, e1): return ZeroQ(-c*d1 + e1) cons1894 = CustomConstraint(cons_f1894) def cons_f1895(c, d2, e2): return ZeroQ(c*d2 + e2) cons1895 = CustomConstraint(cons_f1895) def cons_f1896(d1): return PositiveQ(d1) cons1896 = CustomConstraint(cons_f1896) def cons_f1897(d2): return NegativeQ(d2) cons1897 = CustomConstraint(cons_f1897) def cons_f1898(d1, d2): return Not(And(PositiveQ(d1), NegativeQ(d2))) cons1898 = CustomConstraint(cons_f1898) def cons_f1899(d1, d2): return And(PositiveQ(d1), NegativeQ(d2)) cons1899 = CustomConstraint(cons_f1899) def cons_f1900(c, d, e): return NonzeroQ(-c**S(2)*d + e) cons1900 = CustomConstraint(cons_f1900) def cons_f1901(a, b, c, d1, d2, e1, e2, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d1, e1, d2, e2, n, p), x) cons1901 = CustomConstraint(cons_f1901) def cons_f1902(c, f, g): return ZeroQ(c**S(2)*f**S(2) + g**S(2)) cons1902 = CustomConstraint(cons_f1902) def cons_f1903(d1, d2, p): return Not(Or(IntegerQ(p), And(PositiveQ(d1), NegativeQ(d2)))) cons1903 = CustomConstraint(cons_f1903) def cons_f1904(m): return NonzeroQ(m + S(3)) cons1904 = CustomConstraint(cons_f1904) def cons_f1905(a, b, c, d1, d2, e1, e2, f, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d1, e1, d2, e2, f, m, n, p), x) cons1905 = CustomConstraint(cons_f1905) def cons_f1906(c): return ZeroQ(c**S(2) + S(1)) cons1906 = CustomConstraint(cons_f1906) def cons_f1907(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1906(c, d, m): return FreeQ(List(c, d, m), x) _cons_1906 = CustomConstraint(_cons_f_1906) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1906) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1907 = CustomConstraint(cons_f1907) def cons_f1908(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1907(c, d, m): return FreeQ(List(c, d, m), x) _cons_1907 = CustomConstraint(_cons_f_1907) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1907) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1908 = CustomConstraint(cons_f1908) def cons_f1909(c, d, e): return ZeroQ(c**S(2)*d**S(2) - e**S(2)) cons1909 = CustomConstraint(cons_f1909) def cons_f1910(c, d, e): return PositiveQ(c*d/e + S(1)) cons1910 = CustomConstraint(cons_f1910) def cons_f1911(c, d, e): return NegativeQ(c*d/e + S(-1)) cons1911 = CustomConstraint(cons_f1911) def cons_f1912(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(u**S(2) - (S(1) - S(2)/(c*x + S(1)))**S(2)) cons1912 = CustomConstraint(cons_f1912) def cons_f1913(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ(u**S(2) - (S(1) - S(2)/(-c*x + S(1)))**S(2)) cons1913 = CustomConstraint(cons_f1913) def cons_f1914(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ((S(1) - u)**S(2) - (S(1) - S(2)/(c*x + S(1)))**S(2)) cons1914 = CustomConstraint(cons_f1914) def cons_f1915(c, u, x): if isinstance(x, (int, Integer, float, Float)): return False return ZeroQ((S(1) - u)**S(2) - (S(1) - S(2)/(-c*x + S(1)))**S(2)) cons1915 = CustomConstraint(cons_f1915) def cons_f1916(a, c, d, n): return Not(And(Equal(n, S(2)), ZeroQ(a**S(2)*c + d))) cons1916 = CustomConstraint(cons_f1916) def cons_f1917(c, f, g): return ZeroQ(c**S(2)*f + g) cons1917 = CustomConstraint(cons_f1917) def cons_f1918(a, c, d): return ZeroQ(a*c + d) cons1918 = CustomConstraint(cons_f1918) def cons_f1919(n, p): return Or(IntegerQ(p), ZeroQ(-n/S(2) + p), ZeroQ(-n/S(2) + p + S(-1))) cons1919 = CustomConstraint(cons_f1919) def cons_f1920(a, c, d): return ZeroQ(a**S(2)*c**S(2) - d**S(2)) cons1920 = CustomConstraint(cons_f1920) def cons_f1921(a, c, d): return ZeroQ(-a**S(2)*d**S(2) + c**S(2)) cons1921 = CustomConstraint(cons_f1921) def cons_f1922(a, c, d): return ZeroQ(a**S(2)*c + d) cons1922 = CustomConstraint(cons_f1922) def cons_f1923(n, p): return NonzeroQ(n**S(2) - S(4)*(p + S(1))**S(2)) cons1923 = CustomConstraint(cons_f1923) def cons_f1924(n): return Not(IntegerQ(n/S(2))) cons1924 = CustomConstraint(cons_f1924) def cons_f1925(n): return PositiveIntegerQ(n/S(2) + S(1)/2) cons1925 = CustomConstraint(cons_f1925) def cons_f1926(n, p): return Not(IntegerQ(-n/S(2) + p)) cons1926 = CustomConstraint(cons_f1926) def cons_f1927(n): return NegativeIntegerQ(n/S(2) + S(-1)/2) cons1927 = CustomConstraint(cons_f1927) def cons_f1928(n): return NegativeIntegerQ(n/S(2)) cons1928 = CustomConstraint(cons_f1928) def cons_f1929(n, p): return ZeroQ(n**S(2) + S(2)*p + S(2)) cons1929 = CustomConstraint(cons_f1929) def cons_f1930(a, c, d): return ZeroQ(a**S(2)*d + c) cons1930 = CustomConstraint(cons_f1930) def cons_f1931(a, b, c, e): return ZeroQ(b**S(2)*c + e*(S(1) - a**S(2))) cons1931 = CustomConstraint(cons_f1931) def cons_f1932(a, c, p): return Or(IntegerQ(p), PositiveQ(c/(S(1) - a**S(2)))) cons1932 = CustomConstraint(cons_f1932) def cons_f1933(a, c, p): return Not(Or(IntegerQ(p), PositiveQ(c/(S(1) - a**S(2))))) cons1933 = CustomConstraint(cons_f1933) def cons_f1934(n, p): return ZeroQ(-n/S(2) + p) cons1934 = CustomConstraint(cons_f1934) def cons_f1935(a, c, d): return ZeroQ(a*d + c) cons1935 = CustomConstraint(cons_f1935) def cons_f1936(m, n, p): return Or(IntegerQ(p), ZeroQ(-n/S(2) + p), ZeroQ(-n/S(2) + p + S(-1)), Less(S(-5), m, S(-1))) cons1936 = CustomConstraint(cons_f1936) def cons_f1937(n, p): return Or(IntegerQ(p), Not(IntegerQ(n))) cons1937 = CustomConstraint(cons_f1937) def cons_f1938(n, p): return NonzeroQ(n**S(2) + S(2)*p + S(2)) cons1938 = CustomConstraint(cons_f1938) def cons_f1939(n, p): return IntegersQ(S(2)*p, n/S(2) + p) cons1939 = CustomConstraint(cons_f1939) def cons_f1940(n, p): return Not(IntegersQ(S(2)*p, n/S(2) + p)) cons1940 = CustomConstraint(cons_f1940) def cons_f1941(b, c): return ZeroQ(b - c**S(2)) cons1941 = CustomConstraint(cons_f1941) def cons_f1942(v, x): if isinstance(x, (int, Integer, float, Float)): return False return PosQ(Discriminant(v, x)) cons1942 = CustomConstraint(cons_f1942) def cons_f1943(u, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1942(f, r, w): return FreeQ(f, x) _cons_1942 = CustomConstraint(_cons_f_1942) pat = Pattern(UtilityOperator(f_**w_*WC('r', S(1)), x), _cons_1942) result_matchq = is_match(UtilityOperator(u, x), pat) return result_matchq cons1943 = CustomConstraint(cons_f1943) def cons_f1944(u, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1943(f, r, w): return FreeQ(f, x) _cons_1943 = CustomConstraint(_cons_f_1943) pat = Pattern(UtilityOperator(f_**w_*WC('r', S(1)), x), _cons_1943) result_matchq = is_match(UtilityOperator(u, x), pat) return result_matchq cons1944 = CustomConstraint(cons_f1944) def cons_f1945(c, d): return ZeroQ((c - d)**S(2) + S(-1)) cons1945 = CustomConstraint(cons_f1945) def cons_f1946(c, d): return NonzeroQ((c - d)**S(2) + S(-1)) cons1946 = CustomConstraint(cons_f1946) def cons_f1947(c, d): return ZeroQ((c + I*d)**S(2) + S(-1)) cons1947 = CustomConstraint(cons_f1947) def cons_f1948(c, d): return ZeroQ((c - I*d)**S(2) + S(-1)) cons1948 = CustomConstraint(cons_f1948) def cons_f1949(c, d): return NonzeroQ((c + I*d)**S(2) + S(-1)) cons1949 = CustomConstraint(cons_f1949) def cons_f1950(c, d): return NonzeroQ((c - I*d)**S(2) + S(-1)) cons1950 = CustomConstraint(cons_f1950) def cons_f1951(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1950(c, d, m): return FreeQ(List(c, d, m), x) _cons_1950 = CustomConstraint(_cons_f_1950) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1950) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1951 = CustomConstraint(cons_f1951) def cons_f1952(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: return FalseQ(FunctionOfLinear(v*(a + b*atanh(u)), x)) except (TypeError, AttributeError): return False cons1952 = CustomConstraint(cons_f1952) def cons_f1953(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1952(c, d, m): return FreeQ(List(c, d, m), x) _cons_1952 = CustomConstraint(_cons_f_1952) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1952) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1953 = CustomConstraint(cons_f1953) def cons_f1954(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: return FalseQ(FunctionOfLinear(v*(a + b*acoth(u)), x)) except (TypeError, AttributeError): return False cons1954 = CustomConstraint(cons_f1954) def cons_f1955(a, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, p), x) cons1955 = CustomConstraint(cons_f1955) def cons_f1956(a, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, m, p), x) cons1956 = CustomConstraint(cons_f1956) def cons_f1957(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1956(c, d, m): return FreeQ(List(c, d, m), x) _cons_1956 = CustomConstraint(_cons_f_1956) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1956) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1957 = CustomConstraint(cons_f1957) def cons_f1958(v, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_1957(c, d, m): return FreeQ(List(c, d, m), x) _cons_1957 = CustomConstraint(_cons_f_1957) pat = Pattern(UtilityOperator((x*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x), _cons_1957) result_matchq = is_match(UtilityOperator(v, x), pat) return Not(result_matchq) cons1958 = CustomConstraint(cons_f1958) def cons_f1959(b, d): return ZeroQ(-b**S(2) + d) cons1959 = CustomConstraint(cons_f1959) def cons_f1960(b, d): return ZeroQ(b**S(2) + d) cons1960 = CustomConstraint(cons_f1960) def cons_f1961(m): return Or(Greater(m, S(0)), OddQ(m)) cons1961 = CustomConstraint(cons_f1961) def cons_f1962(m): return Or(And(Greater(m, S(0)), EvenQ(m)), Equal(Mod(m, S(4)), S(3))) cons1962 = CustomConstraint(cons_f1962) def cons_f1963(b, c): return ZeroQ(-Pi*b**S(2)/S(2) + c) cons1963 = CustomConstraint(cons_f1963) def cons_f1964(m): return Not(Equal(Mod(m, S(4)), S(2))) cons1964 = CustomConstraint(cons_f1964) def cons_f1965(m): return Equal(Mod(m, S(4)), S(0)) cons1965 = CustomConstraint(cons_f1965) def cons_f1966(m): return Not(Equal(Mod(m, S(4)), S(0))) cons1966 = CustomConstraint(cons_f1966) def cons_f1967(m): return Equal(Mod(m, S(4)), S(2)) cons1967 = CustomConstraint(cons_f1967) def cons_f1968(m, n): return Or(PositiveIntegerQ(m), NegativeIntegerQ(n), And(RationalQ(m, n), Greater(m, S(0)), Less(n, S(-1)))) cons1968 = CustomConstraint(cons_f1968) def cons_f1969(m, n): return Or(PositiveIntegerQ(n), And(RationalQ(m, n), Less(m, S(-1)), Greater(n, S(0)))) cons1969 = CustomConstraint(cons_f1969) def cons_f1970(n): return Not(And(IntegerQ(n), LessEqual(n, S(0)))) cons1970 = CustomConstraint(cons_f1970) def cons_f1971(m, n): return Or(PositiveIntegerQ(m), PositiveIntegerQ(n), IntegersQ(m, n)) cons1971 = CustomConstraint(cons_f1971) def cons_f1972(a, c): return ZeroQ(a - c + S(1)) cons1972 = CustomConstraint(cons_f1972) def cons_f1973(s): return NonzeroQ(s + S(-1)) cons1973 = CustomConstraint(cons_f1973) def cons_f1974(s): return NonzeroQ(s + S(-2)) cons1974 = CustomConstraint(cons_f1974) def cons_f1975(a, b, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, n, p, q), x) cons1975 = CustomConstraint(cons_f1975) def cons_f1976(r): return RationalQ(r) cons1976 = CustomConstraint(cons_f1976) def cons_f1977(r): return Greater(r, S(0)) cons1977 = CustomConstraint(cons_f1977) def cons_f1978(F, a, b, c, d, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(F, a, b, c, d, n, p), x) cons1978 = CustomConstraint(cons_f1978) def cons_f1979(n, p): return Or(ZeroQ(n*(p + S(-1)) + S(1)), And(IntegerQ(p + S(-1)/2), ZeroQ(n*(p + S(-1)/2) + S(1)))) cons1979 = CustomConstraint(cons_f1979) def cons_f1980(n, p): return Or(And(IntegerQ(p), ZeroQ(n*(p + S(1)) + S(1))), And(IntegerQ(p + S(-1)/2), ZeroQ(n*(p + S(1)/2) + S(1)))) cons1980 = CustomConstraint(cons_f1980) def cons_f1981(m, n, p): return Or(And(IntegerQ(p + S(-1)/2), IntegerQ(S(2)*(m + n*p + S(1))/n), Greater((m + n*p + S(1))/n, S(0))), And(Not(IntegerQ(p + S(-1)/2)), IntegerQ((m + n*p + S(1))/n), GreaterEqual((m + n*p + S(1))/n, S(0)))) cons1981 = CustomConstraint(cons_f1981) def cons_f1982(m, n, p): return Or(ZeroQ(m + S(1)), And(IntegerQ(p + S(-1)/2), IntegerQ(S(-1)/2 + (m + n*p + S(1))/n), Less((m + n*p + S(1))/n, S(0))), And(Not(IntegerQ(p + S(-1)/2)), IntegerQ((m + n*p + S(1))/n), Less((m + n*p + S(1))/n, S(0)))) cons1982 = CustomConstraint(cons_f1982) def cons_f1983(a, c, m, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, m), x) cons1983 = CustomConstraint(cons_f1983) def cons_f1984(a, b, c, d, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, c, d, p), x) cons1984 = CustomConstraint(cons_f1984) def cons_f1985(n, p): return ZeroQ(n*(p + S(-1)) + S(1)) cons1985 = CustomConstraint(cons_f1985) def cons_f1986(n, p): return ZeroQ(p + S(1)/n) cons1986 = CustomConstraint(cons_f1986) def cons_f1987(n, p): return ZeroQ(p + S(-1)/2 + S(1)/n) cons1987 = CustomConstraint(cons_f1987) def cons_f1988(c, n): return PosQ(c*n) cons1988 = CustomConstraint(cons_f1988) def cons_f1989(c, n): return NegQ(c*n) cons1989 = CustomConstraint(cons_f1989) def cons_f1990(n, p): return Greater(n*(p + S(-1)) + S(1), S(0)) cons1990 = CustomConstraint(cons_f1990) def cons_f1991(n, p): return Less(n*p + S(1), S(0)) cons1991 = CustomConstraint(cons_f1991) def cons_f1992(a, d, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, d), x) cons1992 = CustomConstraint(cons_f1992) def cons_f1993(a, d, n, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, d, n), x) cons1993 = CustomConstraint(cons_f1993) def cons_f1994(a, c, d, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, c, d, n, p), x) cons1994 = CustomConstraint(cons_f1994) def cons_f1995(m, n, p): return ZeroQ(m + n*(p + S(-1)) + S(1)) cons1995 = CustomConstraint(cons_f1995) def cons_f1996(m, n, p): return ZeroQ(m + n*p + S(1)) cons1996 = CustomConstraint(cons_f1996) def cons_f1997(m, n, p): return ZeroQ(m + n*(p + S(-1)/2) + S(1)) cons1997 = CustomConstraint(cons_f1997) def cons_f1998(c, p): return PosQ(c/(p + S(-1)/2)) cons1998 = CustomConstraint(cons_f1998) def cons_f1999(c, p): return NegQ(c/(p + S(-1)/2)) cons1999 = CustomConstraint(cons_f1999) def cons_f2000(m, n, p): return RationalQ((m + n*p + S(1))/n) cons2000 = CustomConstraint(cons_f2000) def cons_f2001(m, n, p): return Greater((m + n*p + S(1))/n, S(1)) cons2001 = CustomConstraint(cons_f2001) def cons_f2002(m, n, p): return Less((m + n*p + S(1))/n, S(0)) cons2002 = CustomConstraint(cons_f2002) def cons_f2003(u, x): if isinstance(x, (int, Integer, float, Float)): return False return FunctionOfQ(ProductLog(x), u, x) cons2003 = CustomConstraint(cons_f2003) def cons_f2004(n, u, x): if isinstance(x, (int, Integer, float, Float)): return False def _cons_f_2003(n1, v): return ZeroQ(n - n1 - 1) _cons_2003 = CustomConstraint(_cons_f_2003) pat = Pattern(UtilityOperator(x**WC('n1', S(1))*WC('v', S(1)), x), _cons_2003) result_matchq = is_match(UtilityOperator(u, x), pat) return Not(result_matchq) cons2004 = CustomConstraint(cons_f2004) def cons_f2005(e, g): return ZeroQ(e + g) cons2005 = CustomConstraint(cons_f2005) def cons_f2006(d, f): return ZeroQ(d + f + S(-2)) cons2006 = CustomConstraint(cons_f2006) def cons_f2007(A, C, d, e, f): return ZeroQ(A*e**S(2) + C*d*f) cons2007 = CustomConstraint(cons_f2007) def cons_f2008(B, C, d, e): return ZeroQ(-B*e + S(2)*C*(d + S(-1))) cons2008 = CustomConstraint(cons_f2008) def cons_f2009(A, C, e): return ZeroQ(A*e**S(2) + C) cons2009 = CustomConstraint(cons_f2009) def cons_f2010(n): return Not(PositiveQ(n)) cons2010 = CustomConstraint(cons_f2010) def cons_f2011(v, y): return ZeroQ(-v + y) cons2011 = CustomConstraint(cons_f2011) def cons_f2012(w, y): return ZeroQ(-w + y) cons2012 = CustomConstraint(cons_f2012) def cons_f2013(y, z): return ZeroQ(y - z) cons2013 = CustomConstraint(cons_f2013) def cons_f2014(a, b, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False return FreeQ(List(a, b, m, n, p), x) cons2014 = CustomConstraint(cons_f2014) def cons_f2015(v, w): return ZeroQ(-v + w) cons2015 = CustomConstraint(cons_f2015) def cons_f2016(p, q, r): return ZeroQ(p - q*(r + S(1))) cons2016 = CustomConstraint(cons_f2016) def cons_f2017(r): return NonzeroQ(r + S(1)) cons2017 = CustomConstraint(cons_f2017) def cons_f2018(p, r): return IntegerQ(p/(r + S(1))) cons2018 = CustomConstraint(cons_f2018) def cons_f2019(p, q, r, s): return ZeroQ(p*(s + S(1)) - q*(r + S(1))) cons2019 = CustomConstraint(cons_f2019) def cons_f2020(m, p, q): return ZeroQ(p + q*(m*p + S(1))) cons2020 = CustomConstraint(cons_f2020) def cons_f2021(m, p, q, r): return ZeroQ(p + q*(m*p + r + S(1))) cons2021 = CustomConstraint(cons_f2021) def cons_f2022(m, p, q, s): return ZeroQ(p*(s + S(1)) + q*(m*p + S(1))) cons2022 = CustomConstraint(cons_f2022) def cons_f2023(s): return NonzeroQ(s + S(1)) cons2023 = CustomConstraint(cons_f2023) def cons_f2024(q, s): return IntegerQ(q/(s + S(1))) cons2024 = CustomConstraint(cons_f2024) def cons_f2025(m, p, q, r, s): return ZeroQ(p*(s + S(1)) + q*(m*p + r + S(1))) cons2025 = CustomConstraint(cons_f2025) def cons_f2026(m, u, x): if isinstance(x, (int, Integer, float, Float)): return False return FunctionOfQ(x**(m + S(1)), u, x) cons2026 = CustomConstraint(cons_f2026) def cons_f2027(w, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(FreeQ(w, x)) cons2027 = CustomConstraint(cons_f2027) def cons_f2028(x, z): if isinstance(x, (int, Integer, float, Float)): return False return Not(FreeQ(z, x)) cons2028 = CustomConstraint(cons_f2028) def cons_f2029(a, m): return Not(And(EqQ(a, S(1)), EqQ(m, S(1)))) cons2029 = CustomConstraint(cons_f2029) def cons_f2030(m, v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(And(EqQ(v, x), EqQ(m, S(1)))) cons2030 = CustomConstraint(cons_f2030) def cons_f2031(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(RationalFunctionQ(u, x)) cons2031 = CustomConstraint(cons_f2031) def cons_f2032(v, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(LinearQ(v, x)) cons2032 = CustomConstraint(cons_f2032) def cons_f2033(r, s): return PosQ(-r + s) cons2033 = CustomConstraint(cons_f2033) def cons_f2034(u, x): if isinstance(x, (int, Integer, float, Float)): return False return Not(AlgebraicFunctionQ(u, x)) cons2034 = CustomConstraint(cons_f2034) def cons_f2035(m, u, x): if isinstance(x, (int, Integer, float, Float)): return False return Or(Greater(m, S(0)), Not(AlgebraicFunctionQ(u, x))) cons2035 = CustomConstraint(cons_f2035) def cons_f2036(u, x): if isinstance(x, (int, Integer, float, Float)): return False return EulerIntegrandQ(u, x) cons2036 = CustomConstraint(cons_f2036) def cons_f2037(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False return PolynomialInQ(v, u, x) cons2037 = CustomConstraint(cons_f2037) def cons_f2038(a, d): return ZeroQ(a + d) cons2038 = CustomConstraint(cons_f2038) def cons_f2039(p, q): return ZeroQ(p + q) cons2039 = CustomConstraint(cons_f2039) sympy-sympy-1.9/sympy/integrals/rubi/parsetools/000077500000000000000000000000001412543434000222305ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/parsetools/__init__.py000066400000000000000000000000001412543434000243270ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/parsetools/generate_rules.py000066400000000000000000000054311412543434000256110ustar00rootroot00000000000000import os import inspect from sympy.integrals.rubi.parsetools.parse import (parse_full_form, downvalues_rules, temporary_variable_replacement, permanent_variable_replacement) def generate_rules_from_downvalues(): """ This function generate rules and saves in file. For more details, see `https://github.com/sympy/sympy/wiki/Rubi-parsing-guide` """ cons_dict = {} cons_index = 0 index = 0 cons = '' input = ["Integrand_simplification.txt", "Linear_products.txt", "Quadratic_products.txt", "Binomial_products.txt", "Trinomial_products.txt", "Miscellaneous_algebra.txt", "Piecewise_linear.txt", "Exponentials.txt", "Logarithms.txt", "Sine.txt", "Tangent.txt", "Secant.txt", "Miscellaneous_trig.txt", "Inverse_trig.txt", "Hyperbolic.txt", "Inverse_hyperbolic.txt", "Special_functions.txt", "Miscellaneous_integration.txt"] output = ['integrand_simplification.py', 'linear_products.py', 'quadratic_products.py', 'binomial_products.py', 'trinomial_products.py', 'miscellaneous_algebraic.py' ,'piecewise_linear.py', 'exponential.py', 'logarithms.py', 'sine.py', 'tangent.py', 'secant.py', 'miscellaneous_trig.py', 'inverse_trig.py', 'hyperbolic.py', 'inverse_hyperbolic.py', 'special_functions.py', 'miscellaneous_integration.py'] for k in range(0, 18): module_name = output[k][0:-3] path_header = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) header = open(os.path.join(path_header, "header.py.txt")).read() header = header.format(module_name) with open(input[k]) as myfile: fullform =myfile.read().replace('\n', '') for i in temporary_variable_replacement: fullform = fullform.replace(i, temporary_variable_replacement[i]) # Permanently rename these variables for i in permanent_variable_replacement: fullform = fullform.replace(i, permanent_variable_replacement[i]) rules = [] for i in parse_full_form(fullform): # separate all rules if i[0] == 'RuleDelayed': rules.append(i) parsed = downvalues_rules(rules, header, cons_dict, cons_index, index) result = parsed[0].strip() + '\n' cons_index = parsed[1] cons += parsed[2] index = parsed[3] # Replace temporary variables by actual values for i in temporary_variable_replacement: cons = cons.replace(temporary_variable_replacement[i], i) result = result.replace(temporary_variable_replacement[i], i) file = open(output[k],'w') file.write(str(result)) file.close() cons = "\n".join(header.split("\n")[:-2])+ '\n' + cons constraints = open('constraints.py', 'w') constraints.write(str(cons)) constraints.close() sympy-sympy-1.9/sympy/integrals/rubi/parsetools/generate_tests.py000066400000000000000000000052231412543434000256200ustar00rootroot00000000000000from sympy.integrals.rubi.parsetools.parse import generate_sympy_from_parsed, parse_full_form, rubi_printer from sympy import sympify from sympy.integrals.rubi.utility_function import List, If import os, inspect def rubi_sstr(a): return rubi_printer(a, sympy_integers=True) def generate_test_file(): ''' This function is assuming the name of file containing the fullform is test_1.m. It can be changes as per use. For more details, see `https://github.com/sympy/sympy/wiki/Rubi-parsing-guide#parsing-tests` ''' res =[] file_name = 'test_1.m' with open(file_name) as myfile: fullform =myfile.read().replace('\n', '') fullform = fullform.replace('$VersionNumber', 'version_number') fullform = fullform.replace('Defer[Int][', 'Integrate[') path_header = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) h = open(os.path.join(path_header, "header.py.txt")).read() header = "import sys\nfrom sympy.external import import_module\nmatchpy = import_module({})".format('\"matchpy\"') header += "\nif not matchpy:\n disabled = True\n" header += "if sys.version_info[:2] < (3, 6):\n disabled = True\n" header += "\n".join(h.split("\n")[8:-9]) header += "from sympy.integrals.rubi.rubi import rubi_integrate\n" header += "from sympy import Integral as Integrate, exp, log\n" header += "\na, 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 = symbols('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')" header += "\nA, B, C, F, G, H, J, K, L, M, N, O, P, Q, R, T, U, V, W, X, Y, Z = symbols('A B C F G H J K L M N O P Q R T U V W X Y Z')" header += "\n\ndef {}():\n".format(file_name[0:-2]) s = parse_full_form(fullform) tests = [] for i in s: res[:] = [] if i[0] == 'HoldComplete': ss = sympify(generate_sympy_from_parsed(i[1]), locals = { 'version_number' : 11, 'If' : If}) ss = List(*ss.args) tests.append(ss) t = '' for a in tests: if len(a) == 5: r = 'rubi_integrate({}, x)'.format(rubi_sstr(a[0])) t += '\n assert rubi_test({}, {}, {}, expand=True, _diff=True, _numerical=True) or rubi_test({}, {}, {}, expand=True, _diff=True, _numerical=True)'.format(r, rubi_sstr(a[1]), rubi_sstr(a[3]), r, rubi_sstr(a[1]),rubi_sstr(a[4])) else: r = 'rubi_integrate({}, x)'.format(rubi_sstr(a[0])) t += '\n assert rubi_test({}, {}, {}, expand=True, _diff=True, _numerical=True)'.format(r, rubi_sstr(a[1]), rubi_sstr(a[3])) t = header+t+'\n' test = open('parsed_tests.py', 'w') test.write(t) test.close() sympy-sympy-1.9/sympy/integrals/rubi/parsetools/header.py.txt000066400000000000000000000222361412543434000246550ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def {}(): sympy-sympy-1.9/sympy/integrals/rubi/parsetools/parse.py000066400000000000000000000656411412543434000237300ustar00rootroot00000000000000""" Parser for FullForm[Downvalues[]] of Mathematica rules. This parser is customised to parse the output in MatchPy rules format. Multiple `Constraints` are divided into individual `Constraints` because it helps the MatchPy's `ManyToOneReplacer` to backtrack earlier and improve the speed. Parsed output is formatted into readable format by using `sympify` and print the expression using `sstr`. This replaces `And`, `Mul`, 'Pow' by their respective symbols. Mathematica =========== To get the full form from Wolfram Mathematica, type: ``` ShowSteps = False Import["RubiLoader.m"] Export["output.txt", ToString@FullForm@DownValues@Int] ``` The file ``output.txt`` will then contain the rules in parseable format. References ========== [1] http://reference.wolfram.com/language/ref/FullForm.html [2] http://reference.wolfram.com/language/ref/DownValues.html [3] https://gist.github.com/Upabjojr/bc07c49262944f9c1eb0 """ import re import os import inspect from sympy import sympify, Function, Set, Symbol from sympy.printing import StrPrinter from sympy.utilities.misc import debug class RubiStrPrinter(StrPrinter): def _print_Not(self, expr): return "Not(%s)" % self._print(expr.args[0]) def rubi_printer(expr, **settings): return RubiStrPrinter(settings).doprint(expr) replacements = dict( # Mathematica equivalent functions in SymPy Times="Mul", Plus="Add", Power="Pow", Log='log', Exp='exp', Sqrt='sqrt', Cos='cos', Sin='sin', Tan='tan', Cot='1/tan', cot='1/tan', Sec='1/cos', sec='1/cos', Csc='1/sin', csc='1/sin', ArcSin='asin', ArcCos='acos', # ArcTan='atan', ArcCot='acot', ArcSec='asec', ArcCsc='acsc', Sinh='sinh', Cosh='cosh', Tanh='tanh', Coth='1/tanh', coth='1/tanh', Sech='1/cosh', sech='1/cosh', Csch='1/sinh', csch='1/sinh', ArcSinh='asinh', ArcCosh='acosh', ArcTanh='atanh', ArcCoth='acoth', ArcSech='asech', ArcCsch='acsch', Expand='expand', Im='im', Re='re', Flatten='flatten', Polylog='polylog', Cancel='cancel', #Gamma='gamma', TrigExpand='expand_trig', Sign='sign', Simplify='simplify', Defer='UnevaluatedExpr', Identity = 'S', Sum = 'Sum_doit', Module = 'With', Block = 'With', Null = 'None' ) temporary_variable_replacement = { # Temporarily rename because it can raise errors while sympifying 'gcd' : "_gcd", 'jn' : "_jn", } permanent_variable_replacement = { # Permamenely rename these variables r"\[ImaginaryI]" : 'ImaginaryI', "$UseGamma": '_UseGamma', } # These functions have different return type in different cases. So better to use a try and except in the constraints, when any of these appear f_diff_return_type = ['BinomialParts', 'BinomialDegree', 'TrinomialParts', 'GeneralizedBinomialParts', 'GeneralizedTrinomialParts', 'PseudoBinomialParts', 'PerfectPowerTest', 'SquareFreeFactorTest', 'SubstForFractionalPowerOfQuotientOfLinears', 'FractionalPowerOfQuotientOfLinears', 'InverseFunctionOfQuotientOfLinears', 'FractionalPowerOfSquareQ', 'FunctionOfLinear', 'FunctionOfInverseLinear', 'FunctionOfTrig', 'FindTrigFactor', 'FunctionOfLog', 'PowerVariableExpn', 'FunctionOfSquareRootOfQuadratic', 'SubstForFractionalPowerOfLinear', 'FractionalPowerOfLinear', 'InverseFunctionOfLinear', 'Divides', 'DerivativeDivides', 'TrigSquare', 'SplitProduct', 'SubstForFractionalPowerOfQuotientOfLinears', 'InverseFunctionOfQuotientOfLinears', 'FunctionOfHyperbolic', 'SplitSum'] def contains_diff_return_type(a): """ This function returns whether an expression contains functions which have different return types in diiferent cases. """ if isinstance(a, list): for i in a: if contains_diff_return_type(i): return True elif type(a) == Function('With') or type(a) == Function('Module'): for i in f_diff_return_type: if a.has(Function(i)): return True else: if a in f_diff_return_type: return True return False def parse_full_form(wmexpr): """ Parses FullForm[Downvalues[]] generated by Mathematica """ out = [] stack = [out] generator = re.finditer(r'[\[\],]', wmexpr) last_pos = 0 for match in generator: if match is None: break position = match.start() last_expr = wmexpr[last_pos:position].replace(',', '').replace(']', '').replace('[', '').strip() if match.group() == ',': if last_expr != '': stack[-1].append(last_expr) elif match.group() == ']': if last_expr != '': stack[-1].append(last_expr) stack.pop() elif match.group() == '[': stack[-1].append([last_expr]) stack.append(stack[-1][-1]) last_pos = match.end() return out[0] def get_default_values(parsed, default_values={}): """ Returns Optional variables and their values in the pattern """ if not isinstance(parsed, list): return default_values if parsed[0] == "Times": # find Default arguments for "Times" for i in parsed[1:]: if i[0] == "Optional": default_values[(i[1][1])] = 1 if parsed[0] == "Plus": # find Default arguments for "Plus" for i in parsed[1:]: if i[0] == "Optional": default_values[(i[1][1])] = 0 if parsed[0] == "Power": # find Default arguments for "Power" for i in parsed[1:]: if i[0] == "Optional": default_values[(i[1][1])] = 1 if len(parsed) == 1: return default_values for i in parsed: default_values = get_default_values(i, default_values) return default_values def add_wildcards(string, optional={}): """ Replaces `Pattern(variable)` by `variable` in `string`. Returns the free symbols present in the string. """ symbols = [] # stores symbols present in the expression p = r'(Optional\(Pattern\((\w+), Blank\)\))' matches = re.findall(p, string) for i in matches: string = string.replace(i[0], "WC('{}', S({}))".format(i[1], optional[i[1]])) symbols.append(i[1]) p = r'(Pattern\((\w+), Blank\))' matches = re.findall(p, string) for i in matches: string = string.replace(i[0], i[1] + '_') symbols.append(i[1]) p = r'(Pattern\((\w+), Blank\(Symbol\)\))' matches = re.findall(p, string) for i in matches: string = string.replace(i[0], i[1] + '_') symbols.append(i[1]) return string, symbols def seperate_freeq(s, variables=[], x=None): """ Returns list of symbols in FreeQ. """ if s[0] == 'FreeQ': if len(s[1]) == 1: variables = [s[1]] else: variables = s[1][1:] x = s[2] else: for i in s[1:]: variables, x = seperate_freeq(i, variables, x) return variables, x return variables, x def parse_freeq(l, x, cons_index, cons_dict, cons_import, symbols=None): """ Converts FreeQ constraints into MatchPy constraint """ res = [] cons = '' for i in l: if isinstance(i, str): r = ' return FreeQ({}, {})'.format(i, x) # First it checks if a constraint is already present in `cons_dict`, If yes, use it else create a new one. if r not in cons_dict.values(): cons_index += 1 c = '\n def cons_f{}({}, {}):\n'.format(cons_index, i, x) c += r c += '\n\n cons{} = CustomConstraint({})\n'.format(cons_index, 'cons_f{}'.format(cons_index)) cons_name = 'cons{}'.format(cons_index) cons_dict[cons_name] = r else: c = '' cons_name = next(key for key, value in sorted(cons_dict.items()) if value == r) elif isinstance(i, list): s = sorted(set(get_free_symbols(i, symbols))) s = ', '.join(s) r = ' return FreeQ({}, {})'.format(generate_sympy_from_parsed(i), x) if r not in cons_dict.values(): cons_index += 1 c = '\n def cons_f{}({}):\n'.format(cons_index, s) c += r c += '\n\n cons{} = CustomConstraint({})\n'.format(cons_index, 'cons_f{}'.format(cons_index)) cons_name = 'cons{}'.format(cons_index) cons_dict[cons_name] = r else: c = '' cons_name = next(key for key, value in cons_dict.items() if value == r) if cons_name not in cons_import: cons_import.append(cons_name) res.append(cons_name) cons += c if res != []: return ', ' + ', '.join(res), cons, cons_index return '', cons, cons_index def generate_sympy_from_parsed(parsed, wild=False, symbols=[], replace_Int=False): """ Parses list into Python syntax. Parameters ========== wild : When set to True, the symbols are replaced as wild symbols. symbols : Symbols already present in the pattern. replace_Int: when set to True, `Int` is replaced by `Integral`(used to parse pattern). """ out = "" if not isinstance(parsed, list): try: # return S(number) if parsed is Number float(parsed) return "S({})".format(parsed) except: pass if parsed in symbols: if wild: return parsed + '_' return parsed if parsed[0] == 'Rational': return 'S({})/S({})'.format(generate_sympy_from_parsed(parsed[1], wild=wild, symbols=symbols, replace_Int=replace_Int), generate_sympy_from_parsed(parsed[2], wild=wild, symbols=symbols, replace_Int=replace_Int)) if parsed[0] in replacements: out += replacements[parsed[0]] elif parsed[0] == 'Int' and replace_Int: out += 'Integral' else: out += parsed[0] if len(parsed) == 1: return out result = [generate_sympy_from_parsed(i, wild=wild, symbols=symbols, replace_Int=replace_Int) for i in parsed[1:]] if '' in result: result.remove('') out += "(" out += ", ".join(result) out += ")" return out def get_free_symbols(s, symbols, free_symbols=None): """ Returns free_symbols present in `s`. """ free_symbols = free_symbols or [] if not isinstance(s, list): if s in symbols: free_symbols.append(s) return free_symbols for i in s: free_symbols = get_free_symbols(i, symbols, free_symbols) return free_symbols def set_matchq_in_constraint(a, cons_index): """ Takes care of the case, when a pattern matching has to be done inside a constraint. """ lst = [] res = '' if isinstance(a, list): if a[0] == 'MatchQ': s = a optional = get_default_values(s, {}) r = generate_sympy_from_parsed(s, replace_Int=True) r, free_symbols = add_wildcards(r, optional=optional) free_symbols = sorted(set(free_symbols)) # remove common symbols r = sympify(r, locals={"Or": Function("Or"), "And": Function("And"), "Not":Function("Not")}) pattern = r.args[1].args[0] cons = r.args[1].args[1] pattern = rubi_printer(pattern, sympy_integers=True) pattern = setWC(pattern) res = ' def _cons_f_{}({}):\n return {}\n'.format(cons_index, ', '.join(free_symbols), cons) res += ' _cons_{} = CustomConstraint(_cons_f_{})\n'.format(cons_index, cons_index) res += ' pat = Pattern(UtilityOperator({}, x), _cons_{})\n'.format(pattern, cons_index) res += ' result_matchq = is_match(UtilityOperator({}, x), pat)'.format(r.args[0]) return "result_matchq", res else: for i in a: if isinstance(i, list): r = set_matchq_in_constraint(i, cons_index) lst.append(r[0]) res = r[1] else: lst.append(i) return lst, res def _divide_constriant(s, symbols, cons_index, cons_dict, cons_import): # Creates a CustomConstraint of the form `CustomConstraint(lambda a, x: FreeQ(a, x))` lambda_symbols = sorted(set(get_free_symbols(s, symbols, []))) r = generate_sympy_from_parsed(s) r = sympify(r, locals={"Or": Function("Or"), "And": Function("And"), "Not":Function("Not")}) if r.has(Function('MatchQ')): match_res = set_matchq_in_constraint(s, cons_index) res = match_res[1] res += '\n return {}'.format(rubi_printer(sympify(generate_sympy_from_parsed(match_res[0]), locals={"Or": Function("Or"), "And": Function("And"), "Not":Function("Not")}), sympy_integers = True)) elif contains_diff_return_type(s): res = ' try:\n return {}\n except (TypeError, AttributeError):\n return False'.format(rubi_printer(r, sympy_integers=True)) else: res = ' return {}'.format(rubi_printer(r, sympy_integers=True)) # First it checks if a constraint is already present in `cons_dict`, If yes, use it else create a new one. if not res in cons_dict.values(): cons_index += 1 cons = '\n def cons_f{}({}):\n'.format(cons_index, ', '.join(lambda_symbols)) if 'x' in lambda_symbols: cons += ' if isinstance(x, (int, Integer, float, Float)):\n return False\n' cons += res cons += '\n\n cons{} = CustomConstraint({})\n'.format(cons_index, 'cons_f{}'.format(cons_index)) cons_name = 'cons{}'.format(cons_index) cons_dict[cons_name] = res else: cons = '' cons_name = next(key for key, value in cons_dict.items() if value == res) if cons_name not in cons_import: cons_import.append(cons_name) return cons_name, cons, cons_index def divide_constraint(s, symbols, cons_index, cons_dict, cons_import): """ Divides multiple constraints into smaller constraints. Parameters ========== s : constraint as list symbols : all the symbols present in the expression """ result =[] cons = '' if s[0] == 'And': for i in s[1:]: if i[0]!= 'FreeQ': a = _divide_constriant(i, symbols, cons_index, cons_dict, cons_import) result.append(a[0]) cons += a[1] cons_index = a[2] else: a = _divide_constriant(s, symbols, cons_index, cons_dict, cons_import) result.append(a[0]) cons += a[1] cons_index = a[2] r = [''] for i in result: if i != '': r.append(i) return ', '.join(r),cons, cons_index def setWC(string): """ Replaces `WC(a, b)` by `WC('a', S(b))` """ p = r'(WC\((\w+), S\(([-+]?\d)\)\))' matches = re.findall(p, string) for i in matches: string = string.replace(i[0], "WC('{}', S({}))".format(i[1], i[2])) return string def process_return_type(a1, L): """ Functions like `Set`, `With` and `CompoundExpression` has to be taken special care. """ a = sympify(a1[1]) x = '' processed = False return_value = '' if type(a) == Function('With') or type(a) == Function('Module'): for i in a.args: for s in i.args: if isinstance(s, Set) and not s in L: x += '\n {} = {}'.format(s.args[0], rubi_printer(s.args[1], sympy_integers=True)) if not type(i) in (Function('List'), Function('CompoundExpression')) and not i.has(Function('CompoundExpression')): return_value = i processed = True elif type(i) == Function('CompoundExpression'): return_value = i.args[-1] processed = True elif type(i.args[0]) == Function('CompoundExpression'): C = i.args[0] return_value = '{}({}, {})'.format(i.func, C.args[-1], i.args[1]) processed = True return x, return_value, processed def extract_set(s, L): """ this function extracts all `Set` functions """ lst = [] if isinstance(s, Set) and not s in L: lst.append(s) else: try: for i in s.args: lst += extract_set(i, L) except: # when s has no attribute args (like `bool`) pass return lst def replaceWith(s, symbols, index): """ Replaces `With` and `Module by python functions` """ return_type = None with_value = '' if type(s) == Function('With') or type(s) == Function('Module'): constraints = ' ' result = '\n\n\ndef With{}({}):'.format(index, ', '.join(symbols)) if type(s.args[0]) == Function('List'): # get all local variables of With and Module L = list(s.args[0].args) else: L = [s.args[0]] lst = [] for i in s.args[1:]: lst += extract_set(i, L) L += lst for i in L: # define local variables if isinstance(i, Set): with_value += '\n {} = {}'.format(i.args[0], rubi_printer(i.args[1], sympy_integers=True)) elif isinstance(i, Symbol): with_value += "\n {} = Symbol('{}')".format(i, i) #result += with_value if type(s.args[1]) == Function('CompoundExpression'): # Expand CompoundExpression C = s.args[1] result += with_value if isinstance(C.args[0], Set): result += '\n {} = {}'.format(C.args[0].args[0], C.args[0].args[1]) result += '\n return {}'.format(rubi_printer(C.args[1], sympy_integers=True)) return result, constraints, return_type elif type(s.args[1]) == Function('Condition'): C = s.args[1] if len(C.args) == 2: if all(j in symbols for j in [str(i) for i in C.free_symbols]): result += with_value #constraints += 'CustomConstraint(lambda {}: {})'.format(', '.join([str(i) for i in C.free_symbols]), sstr(C.args[1], sympy_integers=True)) result += '\n return {}'.format(rubi_printer(C.args[0], sympy_integers=True)) else: if 'x' in symbols: result += '\n if isinstance(x, (int, Integer, float, Float)):\n return False' if contains_diff_return_type(s): n_with_value = with_value.replace('\n', '\n ') result += '\n try:{}\n res = {}'.format(n_with_value, rubi_printer(C.args[1], sympy_integers=True)) result += '\n except (TypeError, AttributeError):\n return False' result += '\n if res:' else: result+=with_value result += '\n if {}:'.format(rubi_printer(C.args[1], sympy_integers=True)) return_type = (with_value, rubi_printer(C.args[0], sympy_integers=True)) return_type1 = process_return_type(return_type, L) if return_type1[2]: return_type = (with_value+return_type1[0], rubi_printer(return_type1[1])) result += '\n return True' result += '\n return False' constraints = ', CustomConstraint(With{})'.format(index) return result, constraints, return_type elif type(s.args[1]) == Function('Module') or type(s.args[1]) == Function('With'): C = s.args[1] result += with_value return_type = (with_value, rubi_printer(C, sympy_integers=True)) return_type1 = process_return_type(return_type, L) if return_type1[2]: return_type = (with_value+return_type1[0], rubi_printer(return_type1[1])) result += return_type1[0] result += '\n return {}'.format(rubi_printer(return_type1[1])) return result, constraints, None elif s.args[1].has(Function("CompoundExpression")): C = s.args[1].args[0] result += with_value if isinstance(C.args[0], Set): result += '\n {} = {}'.format(C.args[0].args[0], C.args[0].args[1]) result += '\n return {}({}, {})'.format(s.args[1].func, C.args[-1], s.args[1].args[1]) return result, constraints, None result += with_value result += '\n return {}'.format(rubi_printer(s.args[1], sympy_integers=True)) return result, constraints, return_type else: return rubi_printer(s, sympy_integers=True), '', return_type def downvalues_rules(r, header, cons_dict, cons_index, index): """ Function which generates parsed rules by substituting all possible combinations of default values. """ rules = '[' parsed = '\n\n' repl_funcs = '\n\n' cons = '' cons_import = [] # it contains name of constraints that need to be imported for rules. for i in r: debug('parsing rule {}'.format(r.index(i) + 1)) # Parse Pattern if i[1][1][0] == 'Condition': p = i[1][1][1].copy() else: p = i[1][1].copy() optional = get_default_values(p, {}) pattern = generate_sympy_from_parsed(p.copy(), replace_Int=True) pattern, free_symbols = add_wildcards(pattern, optional=optional) free_symbols = sorted(set(free_symbols)) #remove common symbols # Parse Transformed Expression and Constraints if i[2][0] == 'Condition': # parse rules without constraints separately constriant, constraint_def, cons_index = divide_constraint(i[2][2], free_symbols, cons_index, cons_dict, cons_import) # separate And constraints into individual constraints FreeQ_vars, FreeQ_x = seperate_freeq(i[2][2].copy()) # separate FreeQ into individual constraints transformed = generate_sympy_from_parsed(i[2][1].copy(), symbols=free_symbols) else: constriant = '' constraint_def = '' FreeQ_vars, FreeQ_x = [], [] transformed = generate_sympy_from_parsed(i[2].copy(), symbols=free_symbols) FreeQ_constraint, free_cons_def, cons_index = parse_freeq(FreeQ_vars, FreeQ_x, cons_index, cons_dict, cons_import, free_symbols) pattern = sympify(pattern, locals={"Or": Function("Or"), "And": Function("And"), "Not":Function("Not") }) pattern = rubi_printer(pattern, sympy_integers=True) pattern = setWC(pattern) transformed = sympify(transformed, locals={"Or": Function("Or"), "And": Function("And"), "Not":Function("Not") }) constraint_def = constraint_def + free_cons_def cons += constraint_def index += 1 # below are certain if - else condition depending on various situation that may be encountered if type(transformed) == Function('With') or type(transformed) == Function('Module'): # define separate function when With appears transformed, With_constraints, return_type = replaceWith(transformed, free_symbols, index) if return_type is None: repl_funcs += '{}'.format(transformed) parsed += '\n pattern' + str(index) + ' = Pattern(' + pattern + '' + FreeQ_constraint + '' + constriant + ')' parsed += '\n ' + 'rule' + str(index) + ' = ReplacementRule(' + 'pattern' + rubi_printer(index, sympy_integers=True) + ', With{}'.format(index) + ')\n' else: repl_funcs += '{}'.format(transformed) parsed += '\n pattern' + str(index) + ' = Pattern(' + pattern + '' + FreeQ_constraint + '' + constriant + With_constraints + ')' repl_funcs += '\n\n\ndef replacement{}({}):\n'.format( index, ', '.join(free_symbols) ) + return_type[0] + '\n return '.format(index) + return_type[1] parsed += '\n ' + 'rule' + str(index) + ' = ReplacementRule(' + 'pattern' + rubi_printer(index, sympy_integers=True) + ', replacement{}'.format(index) + ')\n' else: transformed = rubi_printer(transformed, sympy_integers=True) parsed += '\n pattern' + str(index) + ' = Pattern(' + pattern + '' + FreeQ_constraint + '' + constriant + ')' repl_funcs += '\n\n\ndef replacement{}({}):\n return '.format(index, ', '.join(free_symbols), index) + transformed parsed += '\n ' + 'rule' + str(index) + ' = ReplacementRule(' + 'pattern' + rubi_printer(index, sympy_integers=True) + ', replacement{}'.format(index) + ')\n' rules += 'rule{}, '.format(index) rules += ']' parsed += ' return ' + rules +'\n' header += ' from sympy.integrals.rubi.constraints import ' + ', '.join(word for word in cons_import) parsed = header + parsed + repl_funcs return parsed, cons_index, cons, index def rubi_rule_parser(fullform, header=None, module_name='rubi_object'): """ Parses rules in MatchPy format. Parameters ========== fullform : FullForm of the rule as string. header : Header imports for the file. Uses default imports if None. module_name : name of RUBI module References ========== [1] http://reference.wolfram.com/language/ref/FullForm.html [2] http://reference.wolfram.com/language/ref/DownValues.html [3] https://gist.github.com/Upabjojr/bc07c49262944f9c1eb0 """ if header is None: # use default header values path_header = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) header = open(os.path.join(path_header, "header.py.txt")).read() header = header.format(module_name) cons_dict = {} # dict keeps track of constraints that has been encountered, thus avoids repetition of constraints. cons_index = 0 # for index of a constraint index = 0 # indicates the number of a rule. cons = '' # Temporarily rename these variables because it # can raise errors while sympifying for i in temporary_variable_replacement: fullform = fullform.replace(i, temporary_variable_replacement[i]) # Permanently rename these variables for i in permanent_variable_replacement: fullform = fullform.replace(i, permanent_variable_replacement[i]) rules = [] for i in parse_full_form(fullform): # separate all rules if i[0] == 'RuleDelayed': rules.append(i) parsed = downvalues_rules(rules, header, cons_dict, cons_index, index) result = parsed[0].strip() + '\n' cons += parsed[2] # Replace temporary variables by actual values for i in temporary_variable_replacement: cons = cons.replace(temporary_variable_replacement[i], i) result = result.replace(temporary_variable_replacement[i], i) cons = "\n".join(header.split("\n")[:-2]) + '\n' + cons return result, cons sympy-sympy-1.9/sympy/integrals/rubi/parsetools/tests/000077500000000000000000000000001412543434000233725ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/parsetools/tests/__init__.py000066400000000000000000000000001412543434000254710ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/parsetools/tests/test_parse.py000066400000000000000000000200231412543434000261120ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.parsetools.parse import (rubi_rule_parser, get_default_values, add_wildcards, parse_freeq, seperate_freeq, get_free_symbols, divide_constraint, generate_sympy_from_parsed, setWC, replaceWith, rubi_printer, set_matchq_in_constraint, contains_diff_return_type, process_return_type, extract_set) from sympy import Symbol, Not, symbols from sympy import sympify a, b, c, d, e, j, m, n, p, q, x, Pq, Pqq = symbols('a b c d e j m n p q x Pq Pqq') def test_rubi_rule_parser(): header = ''' from matchpy import Operation, CommutativeOperation rubi = ManyToOneReplacer() ''' fullform = 'List[RuleDelayed[HoldPattern[Int[Power[Pattern[x,Blank[]],Optional[Pattern[m,Blank[]]]],Pattern[x,Blank[Symbol]]]],Condition[Times[Power[x,Plus[m,1]],Power[Plus[m,1],-1]],NonzeroQ[Plus[m,1]]]]]' rules, constraint = rubi_rule_parser(fullform, header) result_rule = ''' from matchpy import Operation, CommutativeOperation rubi = ManyToOneReplacer() from sympy.integrals.rubi.constraints import cons1 pattern1 = Pattern(Integral(x_**WC('m', S(1)), x_), cons1) def replacement1(m, x): rubi.append(1) return x**(m + S(1))/(m + S(1)) rule1 = ReplacementRule(pattern1, replacement1) return [rule1, ] ''' result_constraint = ''' from matchpy import Operation, CommutativeOperation def cons_f1(m): return NonzeroQ(m + S(1)) cons1 = CustomConstraint(cons_f1) ''' assert len(result_rule.strip()) == len(rules.strip()) # failing randomly while using `result.strip() == rules` assert len(result_constraint.strip()) == len(constraint.strip()) def test_get_default_values(): s = ['Int', ['Power', ['Plus', ['Optional', ['Pattern', 'a', ['Blank']]], ['Times', ['Optional', ['Pattern', 'b', ['Blank']]], ['Pattern', 'x', ['Blank']]]], ['Pattern', 'm', ['Blank']]], ['Pattern', 'x', ['Blank', 'Symbol']]] assert get_default_values(s, {}) == {'a': 0, 'b': 1} s = ['Int', ['Power', ['Pattern', 'x', ['Blank']], ['Optional', ['Pattern', 'm', ['Blank']]]], ['Pattern', 'x', ['Blank', 'Symbol']]] assert get_default_values(s, {}) == {'m': 1} def test_add_wildcards(): s = 'Integral(Pow(Pattern(x, Blank), Optional(Pattern(m, Blank))), Pattern(x, Blank(Symbol)))' assert add_wildcards(s, {'m': 1}) == ("Integral(Pow(x_, WC('m', S(1))), x_)", ['m', 'x', 'x']) def test_seperate_freeq(): s = ['FreeQ', ['List', 'a', 'b'], 'x'] assert seperate_freeq(s) == (['a', 'b'], 'x') def test_parse_freeq(): l = ['a', 'b'] x = 'x' symbols = ['x', 'a', 'b'] assert parse_freeq(l, x, 0, {}, [], symbols) == (', cons1, cons2', '\n def cons_f1(a, x):\n return FreeQ(a, x)\n\n cons1 = CustomConstraint(cons_f1)\n\n def cons_f2(b, x):\n return FreeQ(b, x)\n\n cons2 = CustomConstraint(cons_f2)\n', 2) def test_get_free_symbols(): s = ['NonzeroQ', ['Plus', 'm', '1']] symbols = ['m', 'x'] assert get_free_symbols(s, symbols, []) == ['m'] def test_divide_constraint(): s = ['And', ['FreeQ', 'm', 'x'], ['NonzeroQ', ['Plus', 'm', '1']]] assert divide_constraint(s, ['m', 'x'], 0, {}, []) == (', cons1', '\n def cons_f1(m):\n return NonzeroQ(m + S(1))\n\n cons1 = CustomConstraint(cons_f1)\n', 1) def test_setWC(): assert setWC('Integral(x_**WC(m, S(1)), x_)') == "Integral(x_**WC('m', S(1)), x_)" def test_replaceWith(): s = sympify('Module(List(Set(r, Numerator(Rt(a/b, n))), Set(s, Denominator(Rt(a/b, n))), k, u), CompoundExpression(Set(u, Integral((r - s*x*cos(Pi*(2*k - 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x)), Dist(2*r/(a*n), _Sum(u, List(k, 1, n/2 - 1/2)), x) + r*Integral(1/(r + s*x), x)/(a*n)))') symbols = ['x', 'a', 'n', 'b'] assert replaceWith(s, symbols, 1) == (" def With1(x, a, n, b):\n r = Numerator(Rt(a/b, n))\n s = Denominator(Rt(a/b, n))\n k = Symbol('k')\n u = Symbol('u')\n u = Integral((r - s*x*cos(Pi*(S(2)*k + S(-1))/n))/(r**S(2) - S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x)\n u = Integral((r - s*x*cos(Pi*(2*k - 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x)\n rubi.append(1)\n return Dist(S(2)*r/(a*n), _Sum(u, List(k, S(1), n/S(2) + S(-1)/2)), x) + r*Integral(S(1)/(r + s*x), x)/(a*n)", ' ', None) def test_generate_sympy_from_parsed(): s = ['Int', ['Power', ['Plus', ['Pattern', 'a', ['Blank']], ['Times', ['Optional', ['Pattern', 'b', ['Blank']]], ['Power', ['Pattern', 'x', ['Blank']], ['Pattern', 'n', ['Blank']]]]], '-1'], ['Pattern', 'x', ['Blank', 'Symbol']]] assert generate_sympy_from_parsed(s, wild=True) == 'Int(Pow(Add(Pattern(a, Blank), Mul(Optional(Pattern(b, Blank)), Pow(Pattern(x, Blank), Pattern(n, Blank)))), S(-1)), Pattern(x, Blank(Symbol)))' assert generate_sympy_from_parsed(s ,replace_Int=True) == 'Integral(Pow(Add(Pattern(a, Blank), Mul(Optional(Pattern(b, Blank)), Pow(Pattern(x, Blank), Pattern(n, Blank)))), S(-1)), Pattern(x, Blank(Symbol)))' s = ['And', ['FreeQ', ['List', 'a', 'b'], 'x'], ['PositiveIntegerQ', ['Times', ['Plus', 'n', '-3'], ['Power', '2', '-1']]], ['PosQ', ['Times', 'a', ['Power', 'b', '-1']]]] assert generate_sympy_from_parsed(s) == 'And(FreeQ(List(a, b), x), PositiveIntegerQ(Mul(Add(n, S(-3)), Pow(S(2), S(-1)))), PosQ(Mul(a, Pow(b, S(-1)))))' def test_rubi_printer(): #14819 a = Symbol('a') assert rubi_printer(Not(a)) == 'Not(a)' def test_contains_diff_return_type(): assert contains_diff_return_type(['Plus', ['BinomialDegree', 'u', 'x'], ['Times', '-1', ['BinomialDegree', 'z', 'x']]]) def test_set_matchq_in_constraint(): expected = ('result_matchq', " def _cons_f_1229(g, m):\n return FreeQ(List(g, m), x)\n _cons_1229 = CustomConstraint(_cons_f_1229)\n pat = Pattern(UtilityOperator((x*WC('g', S(1)))**WC('m', S(1)), x), _cons_1229)\n result_matchq = is_match(UtilityOperator(v, x), pat)") expected1 = ('result_matchq', " def _cons_f_1229(m, g):\n return FreeQ(List(g, m), x)\n _cons_1229 = CustomConstraint(_cons_f_1229)\n pat = Pattern(UtilityOperator((x*WC('g', S(1)))**WC('m', S(1)), x), _cons_1229)\n result_matchq = is_match(UtilityOperator(v, x), pat)") result = set_matchq_in_constraint(['MatchQ', 'v', ['Condition', ['Power', ['Times', ['Optional',\ ['Pattern', 'g', ['Blank']]], 'x'], ['Optional', ['Pattern', 'm', ['Blank']]]], ['FreeQ', ['List', 'g', 'm'], 'x']]], 1229) assert result == expected1 or result == expected def test_process_return_type(): from sympy import Function Int = Function("Int") ExpandToSum = Function("ExpandToSum") s = ('\n q = Expon(Pq, x)\n Pqq = Coeff(Pq, x, q)', 'With(List(Set(Pqq, Coeff(Pq, x, q))), Pqq*c**(n - q + S(-1))*(c*x)**(m - n + q + S(1))*(a*x**j + b*x**n)**(p + S(1))/(b*(m + n*p + q + S(1))) + Int((c*x)**m*(a*x**j + b*x**n)**p*ExpandToSum(Pq - Pqq*a*x**(-n + q)*(m - n + q + S(1))/(b*(m + n*p + q + S(1))) - Pqq*x**q, x), x))') result = process_return_type(s, []) expected = ('\n Pqq = Coeff(Pq, x, q)',\ Pqq*c**(n - q - 1)*(c*x)**(m - n + q + 1)*(a*x**j + b*x**n)**(p + 1)/(b*(m + n*p + q + 1)) + Int((c*x)**m*(a*x**j + b*x**n)**p*ExpandToSum(Pq - Pqq*a*x**(-n + q)*(m - n + q + 1)/(b*(m + n*p + q + 1)) - Pqq*x**q, x), x),\ True) assert result == expected def test_extract_set(): s = sympify('Module(List(Set(r, Numerator(Rt(a/b, n))), Set(s, Denominator(Rt(a/b, n))), k, u), CompoundExpression(Set(u, Integral((r - s*x*cos(Pi*(2*k - 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x)), Dist(2*r/(a*n), _Sum(u, List(k, 1, n/2 - 1/2)), x) + r*Integral(1/(r + s*x), x)/(a*n)))') expected = list(sympify('Set(r, Numerator(Rt(a/b, n))), Set(s, Denominator(Rt(a/b, n))), Set(u, Integral((r - s*x*cos(Pi*(2*k - 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x))')) assert extract_set(s, []) == expected sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/000077500000000000000000000000001412543434000222205ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/__init__.py000066400000000000000000000004451412543434000243340ustar00rootroot00000000000000''' rubi_tests contain test cases parsed in sympy format. The complete test suite is here: http://www.apmaths.uwo.ca/~arich/IntegrationProblems/MathematicaSyntaxFiles/MathematicaSyntaxFiles.html The current version of test suite is 4.10.8 TODO ==== * Update test suite to latest version ''' sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/000077500000000000000000000000001412543434000233625ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/__init__.py000066400000000000000000000000001412543434000254610ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_1_2.py000066400000000000000000000733321412543434000253640ustar00rootroot00000000000000''' Tests for Rubi Algebraic 1.2 rules. Parsed from Maple syntax All tests: http://www.apmaths.uwo.ca/~arich/IntegrationProblems/MapleSyntaxFiles/MapleSyntaxFiles.html Note: Some tests are commented since they depend rules other than Algebraic1.2. ''' import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.rubi import rubi_integrate from sympy.functions import log, sqrt, exp, cos, sin, tan, sec, csc, cot from sympy.functions.elementary.hyperbolic import atanh as arctanh from sympy.functions.elementary.hyperbolic import asinh as arcsinh from sympy.functions.elementary.hyperbolic import acosh as arccosh from sympy.functions.elementary.trigonometric import atan as arctan from sympy.functions.elementary.trigonometric import asin as arcsin from sympy.functions.elementary.trigonometric import acos as arccos from sympy.integrals.rubi.utility_function import EllipticE, EllipticF, hypergeom, rubi_test from sympy import pi as Pi from sympy import S, hyper, I, simplify, exp_polar, symbols a, b, c, d, e, f, m, n, x, u = symbols('a b c d e f m n x u') def test_1(): test = [ [ - S(3)/S(2), x, S(1), - S(3)/S(2)*x], [Pi, x, S(1), Pi*x], [a, x, S(1), a*x], [x**m, x, S(1), x**(S(1) + m)/(S(1) + m)], [x**S(100), x, S(1), S(1)/S(101)*x**S(101)], [x**(S(5)/S(2)), x, S(1), S(2)/S(7)*x**(S(7)/S(2))], [x**(S(5)/S(3)), x, S(1), S(3)/S(8)*x**(S(8)/S(3))], [S(1)/x**(S(1)/S(3)), x, S(1), S(3)/S(2)*x**(S(2)/S(3))], [x**S(3)*(a + b*x), x, S(2), S(1)/S(4)*a*x**S(4) + S(1)/S(5)*b*x**S(5)], [(a + b*x)**S(2)/x**S(2), x, S(2), - a**S(2)/x + b**S(2)*x + S(2)*a*b*log(x)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) def test_2(): test = [ [(a + b*x)/x, x, S(2), b*x + a*log(x)], [x**S(5)/(a + b*x), x, S(2), a**S(4)*x/b**S(5) - S(1)/S(2)*a**S(3)*x**S(2)/b**S(4) + S(1)/S(3)*a**S(2)*x**S(3)/b**S(3) - S(1)/S(4)*a*x**S(4)/b**S(2) + S(1)/S(5)*x**S(5)/b - a**S(5)*log(a + b*x)/b**S(6)], [S(1)/(a + b*x)**S(2), x, S(1), ( - S(1))/(b*(a + b*x))], [S(1)/(x*(a + b*x)**S(3)), x, S(2), S(1)/S(2)/(a*(a + b*x)**S(2)) + S(1)/(a**S(2)*(a + b*x)) + log(x)/a**S(3) - log(a + b*x)/a**S(3)], [S(1)/(S(2) + S(2)*x), x, S(1), S(1)/S(2)*log(S(1) + x)], [S(1)/(x*(S(1) + b*x)), x, S(3), log(x) - log(S(1) + b*x)], [x**S(3)*sqrt(a + b*x), x, S(2), - S(2)/S(3)*a**S(3)*(a + b*x)**(S(3)/S(2))/b**S(4) + S(6)/S(5)*a**S(2)*(a + b*x)**(S(5)/S(2))/b**S(4) - S(6)/S(7)*a*(a + b*x)**(S(7)/S(2))/b**S(4) + S(2)/S(9)*(a + b*x)**(S(9)/S(2))/b**S(4)], [(a + b*x)**(S(3)/S(2)), x, S(1), S(2)/S(5)*(a + b*x)**(S(5)/S(2))/b], [x**S(4)/sqrt(a + b*x), x, S(2), - S(8)/S(3)*a**S(3)*(a + b*x)**(S(3)/S(2))/b**S(5) + S(12)/S(5)*a**S(2)*(a + b*x)**(S(5)/S(2))/b**S(5) - S(8)/S(7)*a*(a + b*x)**(S(7)/S(2))/b**S(5) + S(2)/S(9)*(a + b*x)**(S(9)/S(2))/b**S(5) + S(2)*a**S(4)*sqrt(a + b*x)/b**S(5)], [S(1)/sqrt(a + b*x), x, S(1), S(2)*sqrt(a + b*x)/b], [S(1)/(x*(a + b*x)**(S(3)/S(2))), x, S(3), - S(2)*arctanh(sqrt(a + b*x)/sqrt(a))/a**(S(3)/S(2)) + S(2)/(a*sqrt(a + b*x))], [S(1)/(x**S(2)*( - a + b*x)**(S(3)/S(2))), x, S(4), - S(3)*b*arctan(sqrt( - a + b*x)/sqrt(a))/a**(S(5)/S(2)) + ( - S(2))/(a*x*sqrt( - a + b*x)) - S(3)*sqrt( - a + b*x)/(a**S(2)*x)], [x**S(3)*(a + b*x)**(S(1)/S(3)), x, S(2), - S(3)/S(4)*a**S(3)*(a + b*x)**(S(4)/S(3))/b**S(4) + S(9)/S(7)*a**S(2)*(a + b*x)**(S(7)/S(3))/b**S(4) - S(9)/S(10)*a*(a + b*x)**(S(10)/S(3))/b**S(4) + S(3)/S(13)*(a + b*x)**(S(13)/S(3))/b**S(4)], [x**S(2)*(a + b*x)**(S(2)/S(3)), x, S(2), S(3)/S(5)*a**S(2)*(a + b*x)**(S(5)/S(3))/b**S(3) - S(3)/S(4)*a*(a + b*x)**(S(8)/S(3))/b**S(3) + S(3)/S(11)*(a + b*x)**(S(11)/S(3))/b**S(3)], [x**S(2)/(a + b*x)**(S(1)/S(3)), x, S(2), S(3)/S(2)*a**S(2)*(a + b*x)**(S(2)/S(3))/b**S(3) - S(6)/S(5)*a*(a + b*x)**(S(5)/S(3))/b**S(3) + S(3)/S(8)*(a + b*x)**(S(8)/S(3))/b**S(3)], [x**S(3)/( - a + b*x)**(S(1)/S(3)), x, S(2), S(3)/S(2)*a**S(3)*( - a + b*x)**(S(2)/S(3))/b**S(4) + S(9)/S(5)*a**S(2)*( - a + b*x)**(S(5)/S(3))/b**S(4) + S(9)/S(8)*a*( - a + b*x)**(S(8)/S(3))/b**S(4) + S(3)/S(11)*( - a + b*x)**(S(11)/S(3))/b**S(4)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) def test_3(): test = [ [x**m*(a + b*x), x, S(2), a*x**(S(1) + m)/(S(1) + m) + b*x**(S(2) + m)/(S(2) + m)], [x**(S(5)/S(2))*(a + b*x), x, S(2), S(2)/S(7)*a*x**(S(7)/S(2)) + S(2)/S(9)*b*x**(S(9)/S(2))], [x**(S(5)/S(2))/(a + b*x), x, S(5), - S(2)/S(3)*a*x**(S(3)/S(2))/b**S(2) + S(2)/S(5)*x**(S(5)/S(2))/b - S(2)*a**(S(5)/S(2))*arctan(sqrt(b)*sqrt(x)/sqrt(a))/b**(S(7)/S(2)) + S(2)*a**S(2)*sqrt(x)/b**S(3)], [x**(S(3)/S(2))/(a + b*x), x, S(4), S(2)/S(3)*x**(S(3)/S(2))/b + S(2)*a**(S(3)/S(2))*arctan(sqrt(b)*sqrt(x)/sqrt(a))/b**(S(5)/S(2)) - S(2)*a*sqrt(x)/b**S(2)], [x**(S(5)/S(2))/( - a + b*x), x, S(5), S(2)/S(3)*a*x**(S(3)/S(2))/b**S(2) + S(2)/S(5)*x**(S(5)/S(2))/b - S(2)*a**(S(5)/S(2))*arctanh(sqrt(b)*sqrt(x)/sqrt(a))/b**(S(7)/S(2)) + S(2)*a**S(2)*sqrt(x)/b**S(3)], [x**(S(5)/S(2))*sqrt(a + b*x), x, S(6), - S(5)/S(64)*a**S(4)*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(7)/S(2)) - S(5)/S(96)*a**S(2)*x**(S(3)/S(2))*sqrt(a + b*x)/b**S(2) + S(1)/S(24)*a*x**(S(5)/S(2))*sqrt(a + b*x)/b + S(1)/S(4)*x**(S(7)/S(2))*sqrt(a + b*x) + S(5)/S(64)*a**S(3)*sqrt(x)*sqrt(a + b*x)/b**S(3)], [x**(S(3)/S(2))*sqrt(a + b*x), x, S(5), S(1)/S(8)*a**S(3)*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(5)/S(2)) + S(1)/S(12)*a*x**(S(3)/S(2))*sqrt(a + b*x)/b + S(1)/S(3)*x**(S(5)/S(2))*sqrt(a + b*x) - S(1)/S(8)*a**S(2)*sqrt(x)*sqrt(a + b*x)/b**S(2)], [x**(S(5)/S(2))/sqrt(a + b*x), x, S(5), - S(5)/S(8)*a**S(3)*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(7)/S(2)) - S(5)/S(12)*a*x**(S(3)/S(2))*sqrt(a + b*x)/b**S(2) + S(1)/S(3)*x**(S(5)/S(2))*sqrt(a + b*x)/b + S(5)/S(8)*a**S(2)*sqrt(x)*sqrt(a + b*x)/b**S(3)], [sqrt(x)/sqrt(a + b*x), x, S(3), - a*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(3)/S(2)) + sqrt(x)*sqrt(a + b*x)/b], [x**(S(2)/S(3))*(a + b*x), x, S(2), S(3)/S(5)*a*x**(S(5)/S(3)) + S(3)/S(8)*b*x**(S(8)/S(3))], [x**(S(1)/S(3))*(a + b*x), x, S(2), S(3)/S(4)*a*x**(S(4)/S(3)) + S(3)/S(7)*b*x**(S(7)/S(3))], [x**(S(5)/S(3))/(a + b*x), x, S(6), - S(3)/S(2)*a*x**(S(2)/S(3))/b**S(2) + S(3)/S(5)*x**(S(5)/S(3))/b - S(3)/S(2)*a**(S(5)/S(3))*log(a**(S(1)/S(3)) + b**(S(1)/S(3))*x**(S(1)/S(3)))/b**(S(8)/S(3)) + S(1)/S(2)*a**(S(5)/S(3))*log(a + b*x)/b**(S(8)/S(3)) - a**(S(5)/S(3))*arctan((a**(S(1)/S(3)) - S(2)*b**(S(1)/S(3))*x**(S(1)/S(3)))/(a**(S(1)/S(3))*sqrt(S(3))))*sqrt(S(3))/b**(S(8)/S(3))], [x**(S(4)/S(3))/(a + b*x), x, S(6), - S(3)*a*x**(S(1)/S(3))/b**S(2) + S(3)/S(4)*x**(S(4)/S(3))/b + S(3)/S(2)*a**(S(4)/S(3))*log(a**(S(1)/S(3)) + b**(S(1)/S(3))*x**(S(1)/S(3)))/b**(S(7)/S(3)) - S(1)/S(2)*a**(S(4)/S(3))*log(a + b*x)/b**(S(7)/S(3)) - a**(S(4)/S(3))*arctan((a**(S(1)/S(3)) - S(2)*b**(S(1)/S(3))*x**(S(1)/S(3)))/(a**(S(1)/S(3))*sqrt(S(3))))*sqrt(S(3))/b**(S(7)/S(3))], [(S(1) - x)**(S(1)/S(4))/(S(1) + x), x, S(5), S(4)*(S(1) - x)**(S(1)/S(4)) - S(2)*S(2)**(S(1)/S(4))*arctan((S(1) - x)**(S(1)/S(4))/S(2)**(S(1)/S(4))) - S(2)*S(2)**(S(1)/S(4))*arctanh((S(1) - x)**(S(1)/S(4))/S(2)**(S(1)/S(4)))], [x**m*(a + b*x)**S(2), x, S(2), a**S(2)*x**(S(1) + m)/(S(1) + m) + S(2)*a*b*x**(S(2) + m)/(S(2) + m) + b**S(2)*x**(S(3) + m)/(S(3) + m)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) def test_4(): test = [ [x**m/(a + b*x)**S(2), x, S(1), x**(S(1) + m)*hypergeom([S(2), S(1) + m], [S(2) + m], - b*x/a)/(a**S(2)*(S(1) + m))], [x**m/sqrt(S(2) + S(3)*x), x, S(1), x**(S(1) + m)*hypergeom([S(1)/S(2), S(1) + m], [S(2) + m], - S(3)/S(2)*x)/((S(1) + m)*sqrt(S(2)))], [x**m*(a + b*x)**n, x, S(2), x**(S(1) + m)*(a + b*x)**n*hypergeom([S(1) + m, - n], [S(2) + m], - b*x/a)/((S(1) + m)*(S(1) + b*x/a)**n)], [x**( - S(1) + n)/(a + b*x)**n, x, S(2), x**n*(S(1) + b*x/a)**n*hypergeom([n, n], [S(1) + n], - b*x/a)/(n*(a + b*x)**n)], [(c + d*(a + b*x))**(S(5)/S(2)), x, S(2), S(2)/S(7)*(c + d*(a + b*x))**(S(7)/S(2))/(b*d)], [(c + d*(a + b*x))**(S(3)/S(2)), x, S(2), S(2)/S(5)*(c + d*(a + b*x))**(S(5)/S(2))/(b*d)], [(a + b*x)**S(3)/(a*d/b + d*x)**S(3), x, S(2), b**S(3)*x/d**S(3)], [(a + b*x)*(a*c - b*c*x)**S(3), x, S(2), - S(1)/S(2)*a*c**S(3)*(a - b*x)**S(4)/b + S(1)/S(5)*c**S(3)*(a - b*x)**S(5)/b], [(a*c - b*c*x)**S(3)/(a + b*x), x, S(2), - S(4)*a**S(2)*c**S(3)*x + a*c**S(3)*(a - b*x)**S(2)/b + S(1)/S(3)*c**S(3)*(a - b*x)**S(3)/b + S(8)*a**S(3)*c**S(3)*log(a + b*x)/b], [S(1)/((a + b*x)**S(2)*(a*c - b*c*x)), x, S(3), ( - S(1)/S(2))/(a*b*c*(a + b*x)) + S(1)/S(2)*arctanh(b*x/a)/(a**S(2)*b*c)], [(S(1) + x)**(S(1)/S(2))/(S(1) - x)**(S(9)/S(2)), x, S(3), S(1)/S(7)*(S(1) + x)**(S(3)/S(2))/(S(1) - x)**(S(7)/S(2)) + S(2)/S(35)*(S(1) + x)**(S(3)/S(2))/(S(1) - x)**(S(5)/S(2)) + S(2)/S(105)*(S(1) + x)**(S(3)/S(2))/(S(1) - x)**(S(3)/S(2))], [(S(1) + x)**(S(5)/S(2))/(S(1) - x)**(S(1)/S(2)), x, S(5), S(5)/S(2)*arcsin(x) - S(5)/S(6)*(S(1) + x)**(S(3)/S(2))*sqrt(S(1) - x) - S(1)/S(3)*(S(1) + x)**(S(5)/S(2))*sqrt(S(1) - x) - S(5)/S(2)*sqrt(S(1) - x)*sqrt(S(1) + x)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) def test_5(): test = [ [(S(1) + a*x)**(S(3)/S(2))/sqrt(S(1) - a*x), x, S(4), S(3)/S(2)*arcsin(a*x)/a - S(1)/S(2)*(S(1) + a*x)**(S(3)/S(2))*sqrt(S(1) - a*x)/a - S(3)/S(2)*sqrt(S(1) - a*x)*sqrt(S(1) + a*x)/a], [(S(1) - x)**(S(1)/S(2))/(S(1) + x)**(S(1)/S(2)), x, S(3), arcsin(x) + sqrt(S(1) - x)*sqrt(S(1) + x)], [S(1)/((S(1) - x)**(S(1)/S(2))*(S(1) + x)**(S(3)/S(2))), x, S(1), - sqrt(S(1) - x)/sqrt(S(1) + x)], [(a + a*x)**(S(5)/S(2))*(c - c*x)**(S(5)/S(2)), x, S(5), S(5)/S(24)*a*c*x*(a + a*x)**(S(3)/S(2))*(c - c*x)**(S(3)/S(2)) + S(1)/S(6)*x*(a + a*x)**(S(5)/S(2))*(c - c*x)**(S(5)/S(2)) + S(5)/S(8)*a**(S(5)/S(2))*c**(S(5)/S(2))*arctan(sqrt(c)*sqrt(a + a*x)/(sqrt(a)*sqrt(c - c*x))) + S(5)/S(16)*a**S(2)*c**S(2)*x*sqrt(a + a*x)*sqrt(c - c*x)], [S(1)/((a + a*x)**(S(5)/S(2))*(c - c*x)**(S(5)/S(2))), x, S(2), S(1)/S(3)*x/(a*c*(a + a*x)**(S(3)/S(2))*(c - c*x)**(S(3)/S(2))) + S(2)/S(3)*x/(a**S(2)*c**S(2)*sqrt(a + a*x)*sqrt(c - c*x))], [(S(3) - x)**(S(1)/S(2))*( - S(2) + x)**(S(1)/S(2)), x, S(5), - S(1)/S(8)*arcsin(S(5) - S(2)*x) - S(1)/S(2)*(S(3) - x)**(S(3)/S(2))*sqrt( - S(2) + x) + S(1)/S(4)*sqrt(S(3) - x)*sqrt( - S(2) + x)], [S(1)/(sqrt(a + b*x)*sqrt( - a*d + b*d*x)), x, S(2), S(2)*arctanh(sqrt(d)*sqrt(a + b*x)/sqrt( - a*d + b*d*x))/(b*sqrt(d))], [S(1)/((a - I*a*x)**(S(7)/S(4))*(a + I*a*x)**(S(1)/S(4))), x, S(1), - S(2)/S(3)*I*(a + I*a*x)**(S(3)/S(4))/(a**S(2)*(a - I*a*x)**(S(3)/S(4)))], [(a + b*x)**S(2)*(a*c - b*c*x)**n, x, S(2), - S(4)*a**S(2)*(a*c - b*c*x)**(S(1) + n)/(b*c*(S(1) + n)) + S(4)*a*(a*c - b*c*x)**(S(2) + n)/(b*c**S(2)*(S(2) + n)) - (a*c - b*c*x)**(S(3) + n)/(b*c**S(3)*(S(3) + n))], [(a + b*x)**S(4)*(c + d*x), x, S(2), S(1)/S(5)*(b*c - a*d)*(a + b*x)**S(5)/b**S(2) + S(1)/S(6)*d*(a + b*x)**S(6)/b**S(2)], [(a + b*x)*(c + d*x), x, S(2), a*c*x + S(1)/S(2)*(b*c + a*d)*x**S(2) + S(1)/S(3)*b*d*x**S(3)], [(a + b*x)**S(5)/(c + d*x), x, S(2), b*(b*c - a*d)**S(4)*x/d**S(5) - S(1)/S(2)*(b*c - a*d)**S(3)*(a + b*x)**S(2)/d**S(4) + S(1)/S(3)*(b*c - a*d)**S(2)*(a + b*x)**S(3)/d**S(3) - S(1)/S(4)*(b*c - a*d)*(a + b*x)**S(4)/d**S(2) + S(1)/S(5)*(a + b*x)**S(5)/d - (b*c - a*d)**S(5)*log(c + d*x)/d**S(6)], [(a + b*x)/(c + d*x)**S(3), x, S(1), S(1)/S(2)*(a + b*x)**S(2)/((b*c - a*d)*(c + d*x)**S(2))], [(a + b*x)**S(5)*(c + d*x)**(S(1)/S(2)), x, S(2), - S(2)/S(3)*(b*c - a*d)**S(5)*(c + d*x)**(S(3)/S(2))/d**S(6) + S(2)*b*(b*c - a*d)**S(4)*(c + d*x)**(S(5)/S(2))/d**S(6) - S(20)/S(7)*b**S(2)*(b*c - a*d)**S(3)*(c + d*x)**(S(7)/S(2))/d**S(6) + S(20)/S(9)*b**S(3)*(b*c - a*d)**S(2)*(c + d*x)**(S(9)/S(2))/d**S(6) - S(10)/S(11)*b**S(4)*(b*c - a*d)*(c + d*x)**(S(11)/S(2))/d**S(6) + S(2)/S(13)*b**S(5)*(c + d*x)**(S(13)/S(2))/d**S(6)], [(c + d*x)**(S(1)/S(2))/(a + b*x)**S(2), x, S(3), - d*arctanh(sqrt(b)*sqrt(c + d*x)/sqrt(b*c - a*d))/(b**(S(3)/S(2))*sqrt(b*c - a*d)) - sqrt(c + d*x)/(b*(a + b*x))], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) def test_6(): test = [ [(S(1) + a*x)**(S(3)/S(2))/sqrt(S(1) - a*x), x, S(4), S(3)/S(2)*arcsin(a*x)/a - S(1)/S(2)*(S(1) + a*x)**(S(3)/S(2))*sqrt(S(1) - a*x)/a - S(3)/S(2)*sqrt(S(1) - a*x)*sqrt(S(1) + a*x)/a], [(S(1) - x)**(S(1)/S(2))/(S(1) + x)**(S(1)/S(2)), x, S(3), arcsin(x) + sqrt(S(1) - x)*sqrt(S(1) + x)], [S(1)/((S(1) - x)**(S(1)/S(2))*(S(1) + x)**(S(3)/S(2))), x, S(1), - sqrt(S(1) - x)/sqrt(S(1) + x)], [(a + a*x)**(S(5)/S(2))*(c - c*x)**(S(5)/S(2)), x, S(5), S(5)/S(24)*a*c*x*(a + a*x)**(S(3)/S(2))*(c - c*x)**(S(3)/S(2)) + S(1)/S(6)*x*(a + a*x)**(S(5)/S(2))*(c - c*x)**(S(5)/S(2)) + S(5)/S(8)*a**(S(5)/S(2))*c**(S(5)/S(2))*arctan(sqrt(c)*sqrt(a + a*x)/(sqrt(a)*sqrt(c - c*x))) + S(5)/S(16)*a**S(2)*c**S(2)*x*sqrt(a + a*x)*sqrt(c - c*x)], [S(1)/((a + a*x)**(S(5)/S(2))*(c - c*x)**(S(5)/S(2))), x, S(2), S(1)/S(3)*x/(a*c*(a + a*x)**(S(3)/S(2))*(c - c*x)**(S(3)/S(2))) + S(2)/S(3)*x/(a**S(2)*c**S(2)*sqrt(a + a*x)*sqrt(c - c*x))], [(S(3) - x)**(S(1)/S(2))*( - S(2) + x)**(S(1)/S(2)), x, S(5), - S(1)/S(8)*arcsin(S(5) - S(2)*x) - S(1)/S(2)*(S(3) - x)**(S(3)/S(2))*sqrt( - S(2) + x) + S(1)/S(4)*sqrt(S(3) - x)*sqrt( - S(2) + x)], [S(1)/(sqrt(a + b*x)*sqrt( - a*d + b*d*x)), x, S(2), S(2)*arctanh(sqrt(d)*sqrt(a + b*x)/sqrt( - a*d + b*d*x))/(b*sqrt(d))], [S(1)/((a - I*a*x)**(S(7)/S(4))*(a + I*a*x)**(S(1)/S(4))), x, S(1), - S(2)/S(3)*I*(a + I*a*x)**(S(3)/S(4))/(a**S(2)*(a - I*a*x)**(S(3)/S(4)))], [(a + b*x)**S(2)*(a*c - b*c*x)**n, x, S(2), - S(4)*a**S(2)*(a*c - b*c*x)**(S(1) + n)/(b*c*(S(1) + n)) + S(4)*a*(a*c - b*c*x)**(S(2) + n)/(b*c**S(2)*(S(2) + n)) - (a*c - b*c*x)**(S(3) + n)/(b*c**S(3)*(S(3) + n))], [(a + b*x)**S(4)*(c + d*x), x, S(2), S(1)/S(5)*(b*c - a*d)*(a + b*x)**S(5)/b**S(2) + S(1)/S(6)*d*(a + b*x)**S(6)/b**S(2)], [(a + b*x)*(c + d*x), x, S(2), a*c*x + S(1)/S(2)*(b*c + a*d)*x**S(2) + S(1)/S(3)*b*d*x**S(3)], [(a + b*x)**S(5)/(c + d*x), x, S(2), b*(b*c - a*d)**S(4)*x/d**S(5) - S(1)/S(2)*(b*c - a*d)**S(3)*(a + b*x)**S(2)/d**S(4) + S(1)/S(3)*(b*c - a*d)**S(2)*(a + b*x)**S(3)/d**S(3) - S(1)/S(4)*(b*c - a*d)*(a + b*x)**S(4)/d**S(2) + S(1)/S(5)*(a + b*x)**S(5)/d - (b*c - a*d)**S(5)*log(c + d*x)/d**S(6)], [(a + b*x)/(c + d*x)**S(3), x, S(1), S(1)/S(2)*(a + b*x)**S(2)/((b*c - a*d)*(c + d*x)**S(2))], [(a + b*x)**S(5)*(c + d*x)**(S(1)/S(2)), x, S(2), - S(2)/S(3)*(b*c - a*d)**S(5)*(c + d*x)**(S(3)/S(2))/d**S(6) + S(2)*b*(b*c - a*d)**S(4)*(c + d*x)**(S(5)/S(2))/d**S(6) - S(20)/S(7)*b**S(2)*(b*c - a*d)**S(3)*(c + d*x)**(S(7)/S(2))/d**S(6) + S(20)/S(9)*b**S(3)*(b*c - a*d)**S(2)*(c + d*x)**(S(9)/S(2))/d**S(6) - S(10)/S(11)*b**S(4)*(b*c - a*d)*(c + d*x)**(S(11)/S(2))/d**S(6) + S(2)/S(13)*b**S(5)*(c + d*x)**(S(13)/S(2))/d**S(6)], [(c + d*x)**(S(1)/S(2))/(a + b*x)**S(2), x, S(3), - d*arctanh(sqrt(b)*sqrt(c + d*x)/sqrt(b*c - a*d))/(b**(S(3)/S(2))*sqrt(b*c - a*d)) - sqrt(c + d*x)/(b*(a + b*x))], [(a + b*x)**S(4)/(c + d*x)**(S(1)/S(2)), x, S(2), - S(8)/S(3)*b*(b*c - a*d)**S(3)*(c + d*x)**(S(3)/S(2))/d**S(5) + S(12)/S(5)*b**S(2)*(b*c - a*d)**S(2)*(c + d*x)**(S(5)/S(2))/d**S(5) - S(8)/S(7)*b**S(3)*(b*c - a*d)*(c + d*x)**(S(7)/S(2))/d**S(5) + S(2)/S(9)*b**S(4)*(c + d*x)**(S(9)/S(2))/d**S(5) + S(2)*(b*c - a*d)**S(4)*sqrt(c + d*x)/d**S(5)], [(a + b*x)**S(2)/(c + d*x)**(S(1)/S(2)), x, S(2), - S(4)/S(3)*b*(b*c - a*d)*(c + d*x)**(S(3)/S(2))/d**S(3) + S(2)/S(5)*b**S(2)*(c + d*x)**(S(5)/S(2))/d**S(3) + S(2)*(b*c - a*d)**S(2)*sqrt(c + d*x)/d**S(3)], [(S(1) - x)**(S(1)/S(3))/(S(1) + x), x, S(5), S(3)*(S(1) - x)**(S(1)/S(3)) + S(3)*log(S(2)**(S(1)/S(3)) - (S(1) - x)**(S(1)/S(3)))/S(2)**(S(2)/S(3)) - log(S(1) + x)/S(2)**(S(2)/S(3)) - S(2)**(S(1)/S(3))*arctan((S(1) + S(2)**(S(2)/S(3))*(S(1) - x)**(S(1)/S(3)))/sqrt(S(3)))*sqrt(S(3))], [(c + d*x)**(S(1)/S(2))/(a + b*x)**(S(1)/S(2)), x, S(3), (b*c - a*d)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(3)/S(2))*sqrt(d)) + sqrt(a + b*x)*sqrt(c + d*x)/b], [(a + b*x)**(S(1)/S(2))*(c + d*x)**(S(3)/S(2)), x, S(5), S(1)/S(3)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(2))/b - S(1)/S(8)*(b*c - a*d)**S(3)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(3)/S(2))) + S(1)/S(4)*(b*c - a*d)*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/b**S(2) + S(1)/S(8)*(b*c - a*d)**S(2)*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(2)*d)], [(a + b*x)**(S(1)/S(2))/(c + d*x)**(S(1)/S(2)), x, S(3), - (b*c - a*d)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(d**(S(3)/S(2))*sqrt(b)) + sqrt(a + b*x)*sqrt(c + d*x)/d], [S(1)/((a + b*x)**(S(1)/S(2))*(c + d*x)**(S(5)/S(2))), x, S(2), S(2)/S(3)*sqrt(a + b*x)/((b*c - a*d)*(c + d*x)**(S(3)/S(2))) + S(4)/S(3)*b*sqrt(a + b*x)/((b*c - a*d)**S(2)*sqrt(c + d*x))], [(a + b*x)**m*(c + d*x)**(S(1) + S(2)*n - S(2)*(S(1) + n)), x, S(2), (a + b*x)**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], - d*(a + b*x)/(b*c - a*d))/((b*c - a*d)*(S(1) + m))], [a + b*x + c*x**S(2) + d*x**S(3), x, S(1), a*x + S(1)/S(2)*b*x**S(2) + S(1)/S(3)*c*x**S(3) + S(1)/S(4)*d*x**S(4)], [a + d/x**S(3) + c/x**S(2) + b/x, x, S(1), - S(1)/S(2)*d/x**S(2) - c/x + a*x + b*log(x)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) def test_7(): test = [ #[(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(1)/S(3)), x, S(5), S(12)/S(187)*(b*c - a*d)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(1)/S(3))/(b*d) + S(6)/S(17)*(a + b*x)**(S(5)/S(2))*(c + d*x)**(S(1)/S(3))/b - S(108)/S(935)*(b*c - a*d)**S(2)*(c + d*x)**(S(1)/S(3))*sqrt(a + b*x)/(b*d**S(2)) - S(108)/S(935)*S(3)**(S(3)/S(4))*(b*c - a*d)**S(3)*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))*EllipticF(( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) + sqrt(S(3))))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3)))), sqrt( - S(7) + S(4)*sqrt(S(3))))*sqrt(((b*c - a*d)**(S(2)/S(3)) + b**(S(1)/S(3))*(b*c - a*d)**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + b**(S(2)/S(3))*(c + d*x)**(S(2)/S(3)))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3))))**S(2))*sqrt(S(2) - sqrt(S(3)))/(b**(S(4)/S(3))*d**S(3)*sqrt(a - b*c/d + b*(c + d*x)/d)*sqrt( - (b*c - a*d)**(S(1)/S(3))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3))))**S(2)))], #[(a + b*x)**(S(3)/S(2))/(c + d*x)**(S(1)/S(3)), x, S(6), S(6)/S(13)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(2)/S(3))/d - S(54)/S(91)*(b*c - a*d)*(c + d*x)**(S(2)/S(3))*sqrt(a + b*x)/d**S(2) - S(162)/S(91)*(b*c - a*d)**S(2)*sqrt(a - b*c/d + b*(c + d*x)/d)/(b**(S(2)/S(3))*d**S(2)*( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3))))) - S(54)/S(91)*S(3)**(S(3)/S(4))*(b*c - a*d)**(S(7)/S(3))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))*EllipticF(( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) + sqrt(S(3))))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3)))), sqrt( - S(7) + S(4)*sqrt(S(3))))*sqrt(S(2))*sqrt(((b*c - a*d)**(S(2)/S(3)) + b**(S(1)/S(3))*(b*c - a*d)**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + b**(S(2)/S(3))*(c + d*x)**(S(2)/S(3)))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3))))**S(2))/(b**(S(2)/S(3))*d**S(3)*sqrt(a - b*c/d + b*(c + d*x)/d)*sqrt( - (b*c - a*d)**(S(1)/S(3))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3))))**S(2))) + S(81)/S(91)*S(3)**(S(1)/S(4))*(b*c - a*d)**(S(7)/S(3))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))*EllipticE(( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) + sqrt(S(3))))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3)))), sqrt( - S(7) + S(4)*sqrt(S(3))))*sqrt(((b*c - a*d)**(S(2)/S(3)) + b**(S(1)/S(3))*(b*c - a*d)**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + b**(S(2)/S(3))*(c + d*x)**(S(2)/S(3)))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3))))**S(2))*sqrt(S(2) + sqrt(S(3)))/(b**(S(2)/S(3))*d**S(3)*sqrt(a - b*c/d + b*(c + d*x)/d)*sqrt( - (b*c - a*d)**(S(1)/S(3))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))/( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + (b*c - a*d)**(S(1)/S(3))*(S(1) - sqrt(S(3))))**S(2)))], [(a + b*x)**(S(2)/S(3))*(c + d*x)**(S(1)/S(3)), x, S(3), S(1)/S(6)*(b*c - a*d)*(a + b*x)**(S(2)/S(3))*(c + d*x)**(S(1)/S(3))/(b*d) + S(1)/S(2)*(a + b*x)**(S(5)/S(3))*(c + d*x)**(S(1)/S(3))/b + S(1)/S(18)*(b*c - a*d)**S(2)*log(c + d*x)/(b**(S(4)/S(3))*d**(S(5)/S(3))) + S(1)/S(6)*(b*c - a*d)**S(2)*log( - S(1) + d**(S(1)/S(3))*(a + b*x)**(S(1)/S(3))/(b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))))/(b**(S(4)/S(3))*d**(S(5)/S(3))) + S(1)/S(3)*(b*c - a*d)**S(2)*arctan(S(1)/sqrt(S(3)) + S(2)*d**(S(1)/S(3))*(a + b*x)**(S(1)/S(3))/(b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*sqrt(S(3))))/(b**(S(4)/S(3))*d**(S(5)/S(3))*sqrt(S(3)))], [(a + b*x)**(S(4)/S(3))/(c + d*x)**(S(1)/S(3)), x, S(3), - S(2)/S(3)*(b*c - a*d)*(a + b*x)**(S(1)/S(3))*(c + d*x)**(S(2)/S(3))/d**S(2) + S(1)/S(2)*(a + b*x)**(S(4)/S(3))*(c + d*x)**(S(2)/S(3))/d - S(1)/S(9)*(b*c - a*d)**S(2)*log(a + b*x)/(b**(S(2)/S(3))*d**(S(7)/S(3))) - S(1)/S(3)*(b*c - a*d)**S(2)*log( - S(1) + b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))/(d**(S(1)/S(3))*(a + b*x)**(S(1)/S(3))))/(b**(S(2)/S(3))*d**(S(7)/S(3))) - S(2)/S(3)*(b*c - a*d)**S(2)*arctan(S(1)/sqrt(S(3)) + S(2)*b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))/(d**(S(1)/S(3))*(a + b*x)**(S(1)/S(3))*sqrt(S(3))))/(b**(S(2)/S(3))*d**(S(7)/S(3))*sqrt(S(3)))], #[(a + b*x)**(S(5)/S(2))/(c + d*x)**(S(1)/S(4)), x, S(10), - S(40)/S(117)*(b*c - a*d)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(4))/d**S(2) + S(4)/S(13)*(a + b*x)**(S(5)/S(2))*(c + d*x)**(S(3)/S(4))/d + S(16)/S(39)*(b*c - a*d)**S(2)*(c + d*x)**(S(3)/S(4))*sqrt(a + b*x)/d**S(3) - S(32)/S(39)*(b*c - a*d)**(S(15)/S(4))*EllipticE(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))/(b*c - a*d)**(S(1)/S(4)), I)*sqrt(S(1) - b*(c + d*x)/(b*c - a*d))/(b**(S(3)/S(4))*d**S(4)*sqrt(a - b*c/d + b*(c + d*x)/d)) + S(32)/S(39)*(b*c - a*d)**(S(15)/S(4))*EllipticF(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))/(b*c - a*d)**(S(1)/S(4)), I)*sqrt(S(1) - b*(c + d*x)/(b*c - a*d))/(b**(S(3)/S(4))*d**S(4)*sqrt(a - b*c/d + b*(c + d*x)/d))], [(c + d*x)**(S(5)/S(4))/(a + b*x)**(S(25)/S(4)), x, S(4), - S(4)/S(21)*(c + d*x)**(S(9)/S(4))/((b*c - a*d)*(a + b*x)**(S(21)/S(4))) + S(16)/S(119)*d*(c + d*x)**(S(9)/S(4))/((b*c - a*d)**S(2)*(a + b*x)**(S(17)/S(4))) - S(128)/S(1547)*d**S(2)*(c + d*x)**(S(9)/S(4))/((b*c - a*d)**S(3)*(a + b*x)**(S(13)/S(4))) + S(512)/S(13923)*d**S(3)*(c + d*x)**(S(9)/S(4))/((b*c - a*d)**S(4)*(a + b*x)**(S(9)/S(4)))], [(a + b*x)**(S(5)/S(4))/(c + d*x)**(S(1)/S(4)), x, S(6), - S(5)/S(8)*(b*c - a*d)*(a + b*x)**(S(1)/S(4))*(c + d*x)**(S(3)/S(4))/d**S(2) + S(1)/S(2)*(a + b*x)**(S(5)/S(4))*(c + d*x)**(S(3)/S(4))/d + S(5)/S(16)*(b*c - a*d)**S(2)*arctan(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(3)/S(4))*d**(S(9)/S(4))) + S(5)/S(16)*(b*c - a*d)**S(2)*arctanh(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(3)/S(4))*d**(S(9)/S(4)))], [S(1)/((a + b*x)**(S(3)/S(4))*(c + d*x)**(S(1)/S(4))), x, S(4), S(2)*arctan(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(3)/S(4))*d**(S(1)/S(4))) + S(2)*arctanh(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(3)/S(4))*d**(S(1)/S(4)))], #[(a + b*x)**(S(3)/S(2))/(c + d*x)**(S(1)/S(5)), x, S(2), S(2)/S(5)*(a + b*x)**(S(5)/S(2))*(b*(c + d*x)/(b*c - a*d))**(S(1)/S(5))*hypergeom([S(1)/S(5), S(5)/S(2)], [S(7)/S(2)], - d*(a + b*x)/(b*c - a*d))/(b*(c + d*x)**(S(1)/S(5)))], #[(a + b*x)**(S(5)/S(2))/(c + d*x)**(S(1)/S(6)), x, S(7), - S(9)/S(28)*(b*c - a*d)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(5)/S(6))/d**S(2) + S(3)/S(10)*(a + b*x)**(S(5)/S(2))*(c + d*x)**(S(5)/S(6))/d + S(81)/S(224)*(b*c - a*d)**S(2)*(c + d*x)**(S(5)/S(6))*sqrt(a + b*x)/d**S(3) + S(243)/S(448)*(b*c - a*d)**S(3)*(c + d*x)**(S(1)/S(6))*(S(1) + sqrt(S(3)))*sqrt(a - b*c/d + b*(c + d*x)/d)/(b**(S(2)/S(3))*d**S(3)*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))) + S(243)/S(448)*S(3)**(S(1)/S(4))*(b*c - a*d)**(S(10)/S(3))*(c + d*x)**(S(1)/S(6))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))*sqrt(cos(arccos(((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) - sqrt(S(3))))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))))**S(2))/cos(arccos(((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) - sqrt(S(3))))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))))*EllipticE(sin(arccos(((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) - sqrt(S(3))))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3)))))), sqrt(S(1)/S(4)*(S(2) + sqrt(S(3)))))*sqrt(((b*c - a*d)**(S(2)/S(3)) + b**(S(1)/S(3))*(b*c - a*d)**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + b**(S(2)/S(3))*(c + d*x)**(S(2)/S(3)))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))**S(2))/(b**(S(2)/S(3))*d**S(4)*sqrt(a - b*c/d + b*(c + d*x)/d)*sqrt( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))**S(2))) + S(81)/S(896)*S(3)**(S(3)/S(4))*(b*c - a*d)**(S(10)/S(3))*(c + d*x)**(S(1)/S(6))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))*sqrt(cos(arccos(((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) - sqrt(S(3))))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))))**S(2))/cos(arccos(((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) - sqrt(S(3))))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))))*EllipticF(sin(arccos(((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) - sqrt(S(3))))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3)))))), sqrt(S(1)/S(4)*(S(2) + sqrt(S(3)))))*(S(1) - sqrt(S(3)))*sqrt(((b*c - a*d)**(S(2)/S(3)) + b**(S(1)/S(3))*(b*c - a*d)**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)) + b**(S(2)/S(3))*(c + d*x)**(S(2)/S(3)))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))**S(2))/(b**(S(2)/S(3))*d**S(4)*sqrt(a - b*c/d + b*(c + d*x)/d)*sqrt( - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3)))/((b*c - a*d)**(S(1)/S(3)) - b**(S(1)/S(3))*(c + d*x)**(S(1)/S(3))*(S(1) + sqrt(S(3))))**S(2)))], #[(a + b*x)**m*(c + d*x)**n, x, S(2), - (a + b*x)**(S(1) + m)*(c + d*x)**(S(1) + n)*hypergeom([S(1), S(2) + m + n], [S(2) + n], b*(c + d*x)/(b*c - a*d))/((b*c - a*d)*(S(1) + n)), (a + b*x)**(S(1) + m)*(c + d*x)**n*hypergeom([S(1) + m, - n], [S(2) + m], - d*(a + b*x)/(b*c - a*d))/(b*(S(1) + m)*(b*(c + d*x)/(b*c - a*d))**n)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) def test_numerical(): test = [ [(a + b*x)**(S(1)/S(2))*(c + d*x)**(S(1)/S(4)), x, S(5), S(4)/S(7)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(1)/S(4))/b + S(4)/S(21)*(b*c - a*d)*(c + d*x)**(S(1)/S(4))*sqrt(a + b*x)/(b*d) - S(8)/S(21)*(b*c - a*d)**(S(9)/S(4))*EllipticF(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))/(b*c - a*d)**(S(1)/S(4)), I)*sqrt(S(1) - b*(c + d*x)/(b*c - a*d))/(b**(S(5)/S(4))*d**S(2)*sqrt(a - b*c/d + b*(c + d*x)/d))], [S(1)/((a + b*x)*(a*d/b + d*x)**S(3)), x, S(2), - S(1)/S(3)*b**S(2)/(d**S(3)*(a + b*x)**S(3))], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True, _numerical=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True, _numerical=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_1_3.py000066400000000000000000001674011412543434000253660ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.rubi import rubi_integrate from sympy.functions import log, sqrt, exp, cos, sin, tan, sec, csc, cot from sympy.functions.elementary.hyperbolic import atanh as arctanh from sympy.functions.elementary.hyperbolic import asinh as arcsinh from sympy.functions.elementary.hyperbolic import acosh as arccosh from sympy.functions.elementary.trigonometric import atan as arctan from sympy.functions.elementary.trigonometric import asin as arcsin from sympy.functions.elementary.trigonometric import acos as arccos from sympy.integrals.rubi.utility_function import EllipticE, EllipticF, hypergeom, rubi_test from sympy import pi as Pi from sympy import S, hyper, I, simplify, exp_polar, symbols from sympy.testing.pytest import slow, skip, ON_TRAVIS A, B, C, D, a, b, c, d, e, f, m, n, p, x, u = symbols('A B C D a b c d e f m n p x u', real=True, imaginary=False) @slow def test_1(): if ON_TRAVIS: skip('Too slow for travis.') test = [ [x**S(2)*(a + b*x)*(a*c - b*c*x)**S(3), x, S(2), S(1)/S(3)*a**S(4)*c**S(3)*x**S(3) - S(1)/S(2)*a**S(3)*b*c**S(3)*x**S(4) + S(1)/S(3)*a*b**S(3)*c**S(3)*x**S(6) - S(1)/S(7)*b**S(4)*c**S(3)*x**S(7)], [x*(a + b*x)*(a*c - b*c*x)**S(3), x, S(2), S(1)/S(2)*a**S(4)*c**S(3)*x**S(2) - S(2)/S(3)*a**S(3)*b*c**S(3)*x**S(3) + S(2)/S(5)*a*b**S(3)*c**S(3)*x**S(5) - S(1)/S(6)*b**S(4)*c**S(3)*x**S(6)], [x**S(3)*(a + b*x)*(A + B*x), x, S(2), S(1)/S(4)*a*A*x**S(4) + S(1)/S(5)*(A*b + a*B)*x**S(5) + S(1)/S(6)*b*B*x**S(6)], [x**S(4)*(A + B*x)/(a + b*x), x, S(2), - a**S(3)*(A*b - a*B)*x/b**S(5) + S(1)/S(2)*a**S(2)*(A*b - a*B)*x**S(2)/b**S(4) - S(1)/S(3)*a*(A*b - a*B)*x**S(3)/b**S(3) + S(1)/S(4)*(A*b - a*B)*x**S(4)/b**S(2) + S(1)/S(5)*B*x**S(5)/b + a**S(4)*(A*b - a*B)*log(a + b*x)/b**S(6)], [x**S(2)*(c + d*x)/(a + b*x), x, S(2), - a*(b*c - a*d)*x/b**S(3) + S(1)/S(2)*(b*c - a*d)*x**S(2)/b**S(2) + S(1)/S(3)*d*x**S(3)/b + a**S(2)*(b*c - a*d)*log(a + b*x)/b**S(4)], [x**S(3)*(c + d*x)**S(2)/(a + b*x)**S(2), x, S(2), - S(2)*a*(b*c - S(2)*a*d)*(b*c - a*d)*x/b**S(5) + S(1)/S(2)*(b*c - S(3)*a*d)*(b*c - a*d)*x**S(2)/b**S(4) + S(2)/S(3)*d*(b*c - a*d)*x**S(3)/b**S(3) + S(1)/S(4)*d**S(2)*x**S(4)/b**S(2) + a**S(3)*(b*c - a*d)**S(2)/(b**S(6)*(a + b*x)) + a**S(2)*(S(3)*b*c - S(5)*a*d)*(b*c - a*d)*log(a + b*x)/b**S(6)], [x**S(2)*(c + d*x)**S(3)/(a + b*x)**S(3), x, S(2), S(3)*d*(b*c - S(2)*a*d)*(b*c - a*d)*x/b**S(5) + S(3)/S(2)*d**S(2)*(b*c - a*d)*x**S(2)/b**S(4) + S(1)/S(3)*d**S(3)*x**S(3)/b**S(3) - S(1)/S(2)*a**S(2)*(b*c - a*d)**S(3)/(b**S(6)*(a + b*x)**S(2)) + a*(S(2)*b*c - S(5)*a*d)*(b*c - a*d)**S(2)/(b**S(6)*(a + b*x)) + (b*c - a*d)*(b**S(2)*c**S(2) - S(8)*a*b*c*d + S(10)*a**S(2)*d**S(2))*log(a + b*x)/b**S(6)], [x**(S(5)/S(2))*(A + B*x)/(a + b*x), x, S(6), - S(2)/S(3)*a*(A*b - a*B)*x**(S(3)/S(2))/b**S(3) + S(2)/S(5)*(A*b - a*B)*x**(S(5)/S(2))/b**S(2) + S(2)/S(7)*B*x**(S(7)/S(2))/b - S(2)*a**(S(5)/S(2))*(A*b - a*B)*arctan(sqrt(b)*sqrt(x)/sqrt(a))/b**(S(9)/S(2)) + S(2)*a**S(2)*(A*b - a*B)*sqrt(x)/b**S(4)], [x**m*(a + b*x)**S(3)*(A + B*x), x, S(2), a**S(3)*A*x**(S(1) + m)/(S(1) + m) + a**S(2)*(S(3)*A*b + a*B)*x**(S(2) + m)/(S(2) + m) + S(3)*a*b*(A*b + a*B)*x**(S(3) + m)/(S(3) + m) + b**S(2)*(A*b + S(3)*a*B)*x**(S(4) + m)/(S(4) + m) + b**S(3)*B*x**(S(5) + m)/(S(5) + m)], [x**m*(c + d*x)**S(3)/(a + b*x), x, S(7), d*(S(3)*b**S(2)*c**S(2) - S(3)*a*b*c*d + a**S(2)*d**S(2))*x**(S(1) + m)/(b**S(3)*(S(1) + m)) + d**S(2)*(S(3)*b*c - a*d)*x**(S(2) + m)/(b**S(2)*(S(2) + m)) + d**S(3)*x**(S(3) + m)/(b*(S(3) + m)) + (b*c - a*d)**S(3)*x**(S(1) + m)*hypergeom([S(1), S(1)], [S(1) - m], a/(a + b*x))/(b**S(3)*m*(a + b*x)), c**S(2)*d*x**(S(1) + m)/(b*(S(1) + m)) + c*d*(b*c - a*d)*x**(S(1) + m)/(b**S(2)*(S(1) + m)) + d*(b*c - a*d)**S(2)*x**(S(1) + m)/(b**S(3)*(S(1) + m)) + S(2)*c*d**S(2)*x**(S(2) + m)/(b*(S(2) + m)) + d**S(2)*(b*c - a*d)*x**(S(2) + m)/(b**S(2)*(S(2) + m)) + d**S(3)*x**(S(3) + m)/(b*(S(3) + m)) + (b*c - a*d)**S(3)*x**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], - b*x/a)/(a*b**S(3)*(S(1) + m))], [x**m*(c + d*x)**S(2)/(a + b*x), x, S(5), c*d*x**(S(1) + m)/(b*(S(1) + m)) + d*(b*c - a*d)*x**(S(1) + m)/(b**S(2)*(S(1) + m)) + d**S(2)*x**(S(2) + m)/(b*(S(2) + m)) + (b*c - a*d)**S(2)*x**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], - b*x/a)/(a*b**S(2)*(S(1) + m))], [b**S(2)*x**m/(b + a*x**S(2))**S(2), x, S(2), x**(S(1) + m)*hypergeom([S(2), S(1)/S(2)*(S(1) + m)], [S(1)/S(2)*(S(3) + m)], - a*x**S(2)/b)/(S(1) + m)], [x**m/((S(1) - x*sqrt(a)/sqrt( - b))**S(2)*(S(1) + x*sqrt(a)/sqrt( - b))**S(2)), x, S(2), x**(S(1) + m)*hypergeom([S(2), S(1)/S(2)*(S(1) + m)], [S(1)/S(2)*(S(3) + m)], - a*x**S(2)/b)/(S(1) + m)], [x**S(3)*(A + B*x)*sqrt(a + b*x), x, S(2), - S(2)/S(3)*a**S(3)*(A*b - a*B)*(a + b*x)**(S(3)/S(2))/b**S(5) + S(2)/S(5)*a**S(2)*(S(3)*A*b - S(4)*a*B)*(a + b*x)**(S(5)/S(2))/b**S(5) - S(6)/S(7)*a*(A*b - S(2)*a*B)*(a + b*x)**(S(7)/S(2))/b**S(5) + S(2)/S(9)*(A*b - S(4)*a*B)*(a + b*x)**(S(9)/S(2))/b**S(5) + S(2)/S(11)*B*(a + b*x)**(S(11)/S(2))/b**S(5)], [x**S(3)*(A + B*x)/sqrt(a + b*x), x, S(2), S(2)/S(3)*a**S(2)*(S(3)*A*b - S(4)*a*B)*(a + b*x)**(S(3)/S(2))/b**S(5) - S(6)/S(5)*a*(A*b - S(2)*a*B)*(a + b*x)**(S(5)/S(2))/b**S(5) + S(2)/S(7)*(A*b - S(4)*a*B)*(a + b*x)**(S(7)/S(2))/b**S(5) + S(2)/S(9)*B*(a + b*x)**(S(9)/S(2))/b**S(5) - S(2)*a**S(3)*(A*b - a*B)*sqrt(a + b*x)/b**S(5)], [x**(S(5)/S(2))*(A + B*x)*sqrt(a + b*x), x, S(7), S(1)/S(5)*B*x**(S(7)/S(2))*(a + b*x)**(S(3)/S(2))/b - S(1)/S(128)*a**S(4)*(S(10)*A*b - S(7)*a*B)*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(9)/S(2)) - S(1)/S(192)*a**S(2)*(S(10)*A*b - S(7)*a*B)*x**(S(3)/S(2))*sqrt(a + b*x)/b**S(3) + S(1)/S(240)*a*(S(10)*A*b - S(7)*a*B)*x**(S(5)/S(2))*sqrt(a + b*x)/b**S(2) + S(1)/S(40)*(S(10)*A*b - S(7)*a*B)*x**(S(7)/S(2))*sqrt(a + b*x)/b + S(1)/S(128)*a**S(3)*(S(10)*A*b - S(7)*a*B)*sqrt(x)*sqrt(a + b*x)/b**S(4)], [x**(S(3)/S(2))*(A + B*x)*sqrt(a + b*x), x, S(6), S(1)/S(4)*B*x**(S(5)/S(2))*(a + b*x)**(S(3)/S(2))/b + S(1)/S(64)*a**S(3)*(S(8)*A*b - S(5)*a*B)*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(7)/S(2)) + S(1)/S(96)*a*(S(8)*A*b - S(5)*a*B)*x**(S(3)/S(2))*sqrt(a + b*x)/b**S(2) + S(1)/S(24)*(S(8)*A*b - S(5)*a*B)*x**(S(5)/S(2))*sqrt(a + b*x)/b - S(1)/S(64)*a**S(2)*(S(8)*A*b - S(5)*a*B)*sqrt(x)*sqrt(a + b*x)/b**S(3)], [x**(S(7)/S(2))*(A + B*x)/sqrt(a + b*x), x, S(7), S(7)/S(128)*a**S(4)*(S(10)*A*b - S(9)*a*B)*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(11)/S(2)) + S(7)/S(192)*a**S(2)*(S(10)*A*b - S(9)*a*B)*x**(S(3)/S(2))*sqrt(a + b*x)/b**S(4) - S(7)/S(240)*a*(S(10)*A*b - S(9)*a*B)*x**(S(5)/S(2))*sqrt(a + b*x)/b**S(3) + S(1)/S(40)*(S(10)*A*b - S(9)*a*B)*x**(S(7)/S(2))*sqrt(a + b*x)/b**S(2) + S(1)/S(5)*B*x**(S(9)/S(2))*sqrt(a + b*x)/b - S(7)/S(128)*a**S(3)*(S(10)*A*b - S(9)*a*B)*sqrt(x)*sqrt(a + b*x)/b**S(5)], [x**(S(5)/S(2))*(A + B*x)/sqrt(a + b*x), x, S(6), - S(5)/S(64)*a**S(3)*(S(8)*A*b - S(7)*a*B)*arctanh(sqrt(b)*sqrt(x)/sqrt(a + b*x))/b**(S(9)/S(2)) - S(5)/S(96)*a*(S(8)*A*b - S(7)*a*B)*x**(S(3)/S(2))*sqrt(a + b*x)/b**S(3) + S(1)/S(24)*(S(8)*A*b - S(7)*a*B)*x**(S(5)/S(2))*sqrt(a + b*x)/b**S(2) + S(1)/S(4)*B*x**(S(7)/S(2))*sqrt(a + b*x)/b + S(5)/S(64)*a**S(2)*(S(8)*A*b - S(7)*a*B)*sqrt(x)*sqrt(a + b*x)/b**S(4)], [x**S(3)*sqrt(a + b*x)*sqrt(c + d*x), x, S(6), S(1)/S(5)*x**S(2)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(2))/(b*d) + S(1)/S(240)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(2))*(S(35)*b**S(2)*c**S(2) + S(38)*a*b*c*d + S(35)*a**S(2)*d**S(2) - S(42)*b*d*(b*c + a*d)*x)/(b**S(3)*d**S(3)) + S(1)/S(128)*(b*c - a*d)**S(2)*(b*c + a*d)*(S(7)*b**S(2)*c**S(2) + S(2)*a*b*c*d + S(7)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(9)/S(2))*d**(S(9)/S(2))) - S(1)/S(64)*(b*c + a*d)*(S(7)*b**S(2)*c**S(2) + S(2)*a*b*c*d + S(7)*a**S(2)*d**S(2))*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(4)*d**S(3)) - S(1)/S(128)*(S(7)*b**S(4)*c**S(4) + S(2)*a*b**S(3)*c**S(3)*d - S(2)*a**S(3)*b*c*d**S(3) - S(7)*a**S(4)*d**S(4))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(4)*d**S(4))], [x**S(2)*sqrt(a + b*x)*sqrt(c + d*x), x, S(6), - S(5)/S(24)*(b*c + a*d)*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(2))/(b**S(2)*d**S(2)) + S(1)/S(4)*x*(a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(2))/(b*d) + S(1)/S(64)*(b*c - a*d)**S(2)*(S(4)*a*b*c*d - S(5)*(b*c + a*d)**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(7)/S(2))*d**(S(7)/S(2))) - S(1)/S(32)*(S(4)*a*b*c*d - S(5)*(b*c + a*d)**S(2))*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(3)*d**S(2)) - S(1)/S(64)*(b*c - a*d)*(S(4)*a*b*c*d - S(5)*(b*c + a*d)**S(2))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(3)*d**S(3))], [x**S(3)*sqrt(a + b*x)/sqrt(c + d*x), x, S(5), S(1)/S(64)*(b*c - a*d)*(S(35)*b**S(3)*c**S(3) + S(15)*a*b**S(2)*c**S(2)*d + S(9)*a**S(2)*b*c*d**S(2) + S(5)*a**S(3)*d**S(3))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(7)/S(2))*d**(S(9)/S(2))) + S(1)/S(4)*x**S(2)*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b*d) + S(1)/S(96)*(a + b*x)**(S(3)/S(2))*(S(35)*b**S(2)*c**S(2) + S(22)*a*b*c*d + S(15)*a**S(2)*d**S(2) - S(4)*b*d*(S(7)*b*c + S(5)*a*d)*x)*sqrt(c + d*x)/(b**S(3)*d**S(3)) - S(1)/S(64)*(S(35)*b**S(3)*c**S(3) + S(15)*a*b**S(2)*c**S(2)*d + S(9)*a**S(2)*b*c*d**S(2) + S(5)*a**S(3)*d**S(3))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(3)*d**S(4))], [x**S(2)*sqrt(a + b*x)/sqrt(c + d*x), x, S(5), - S(1)/S(8)*(b*c - a*d)*(S(5)*b**S(2)*c**S(2) + S(2)*a*b*c*d + a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(7)/S(2))) - S(1)/S(12)*(S(5)*b*c + S(3)*a*d)*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(2)*d**S(2)) + S(1)/S(3)*x*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b*d) + S(1)/S(8)*(S(5)*b**S(2)*c**S(2) + S(2)*a*b*c*d + a**S(2)*d**S(2))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(2)*d**S(3))], [x**S(2)*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x), x, S(7), - S(1)/S(40)*(S(7)*b*c + S(5)*a*d)*(a + b*x)**(S(5)/S(2))*(c + d*x)**(S(3)/S(2))/(b**S(2)*d**S(2)) + S(1)/S(5)*x*(a + b*x)**(S(5)/S(2))*(c + d*x)**(S(3)/S(2))/(b*d) + S(1)/S(128)*(b*c - a*d)**S(3)*(S(7)*b**S(2)*c**S(2) + S(6)*a*b*c*d + S(3)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(7)/S(2))*d**(S(9)/S(2))) + S(1)/S(192)*(b*c - a*d)*(S(7)*b**S(2)*c**S(2) + S(6)*a*b*c*d + S(3)*a**S(2)*d**S(2))*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(3)*d**S(3)) + S(1)/S(48)*(S(7)*b**S(2)*c**S(2) + S(6)*a*b*c*d + S(3)*a**S(2)*d**S(2))*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x)/(b**S(3)*d**S(2)) - S(1)/S(128)*(b*c - a*d)**S(2)*(S(7)*b**S(2)*c**S(2) + S(6)*a*b*c*d + S(3)*a**S(2)*d**S(2))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(3)*d**S(4))], [x*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x), x, S(6), S(1)/S(4)*(a + b*x)**(S(5)/S(2))*(c + d*x)**(S(3)/S(2))/(b*d) - S(1)/S(64)*(b*c - a*d)**S(3)*(S(5)*b*c + S(3)*a*d)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(7)/S(2))) - S(1)/S(96)*(b*c - a*d)*(S(5)*b*c + S(3)*a*d)*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(2)*d**S(2)) - S(1)/S(24)*(S(5)*b*c + S(3)*a*d)*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x)/(b**S(2)*d) + S(1)/S(64)*(b*c - a*d)**S(2)*(S(5)*b*c + S(3)*a*d)*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(2)*d**S(3))], [x**S(2)*(a + b*x)**(S(3)/S(2))/sqrt(c + d*x), x, S(6), S(1)/S(64)*(b*c - a*d)**S(2)*(S(35)*b**S(2)*c**S(2) + S(10)*a*b*c*d + S(3)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(9)/S(2))) + S(1)/S(96)*(S(35)*b**S(2)*c**S(2) + S(10)*a*b*c*d + S(3)*a**S(2)*d**S(2))*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(2)*d**S(3)) - S(1)/S(24)*(S(7)*b*c + S(3)*a*d)*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x)/(b**S(2)*d**S(2)) + S(1)/S(4)*x*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x)/(b*d) - S(1)/S(64)*(b*c - a*d)*(S(35)*b**S(2)*c**S(2) + S(10)*a*b*c*d + S(3)*a**S(2)*d**S(2))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(2)*d**S(4))], [x*(a + b*x)**(S(3)/S(2))/sqrt(c + d*x), x, S(5), - S(1)/S(8)*(b*c - a*d)**S(2)*(S(5)*b*c + a*d)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(3)/S(2))*d**(S(7)/S(2))) - S(1)/S(12)*(S(5)*b*c + a*d)*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b*d**S(2)) + S(1)/S(3)*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x)/(b*d) + S(1)/S(8)*(b*c - a*d)*(S(5)*b*c + a*d)*sqrt(a + b*x)*sqrt(c + d*x)/(b*d**S(3))], [x**S(2)*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x), x, S(8), - S(1)/S(60)*(S(9)*b*c + S(5)*a*d)*(a + b*x)**(S(7)/S(2))*(c + d*x)**(S(3)/S(2))/(b**S(2)*d**S(2)) + S(1)/S(6)*x*(a + b*x)**(S(7)/S(2))*(c + d*x)**(S(3)/S(2))/(b*d) - S(1)/S(512)*(b*c - a*d)**S(4)*(S(21)*b**S(2)*c**S(2) + S(14)*a*b*c*d + S(5)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(7)/S(2))*d**(S(11)/S(2))) - S(1)/S(768)*(b*c - a*d)**S(2)*(S(21)*b**S(2)*c**S(2) + S(14)*a*b*c*d + S(5)*a**S(2)*d**S(2))*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(3)*d**S(4)) + S(1)/S(960)*(b*c - a*d)*(S(21)*b**S(2)*c**S(2) + S(14)*a*b*c*d + S(5)*a**S(2)*d**S(2))*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x)/(b**S(3)*d**S(3)) + S(1)/S(160)*(S(21)*b**S(2)*c**S(2) + S(14)*a*b*c*d + S(5)*a**S(2)*d**S(2))*(a + b*x)**(S(7)/S(2))*sqrt(c + d*x)/(b**S(3)*d**S(2)) + S(1)/S(512)*(b*c - a*d)**S(3)*(S(21)*b**S(2)*c**S(2) + S(14)*a*b*c*d + S(5)*a**S(2)*d**S(2))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(3)*d**S(5))], [x*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x), x, S(7), S(1)/S(5)*(a + b*x)**(S(7)/S(2))*(c + d*x)**(S(3)/S(2))/(b*d) + S(1)/S(128)*(b*c - a*d)**S(4)*(S(7)*b*c + S(3)*a*d)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(9)/S(2))) + S(1)/S(192)*(b*c - a*d)**S(2)*(S(7)*b*c + S(3)*a*d)*(a + b*x)**(S(3)/S(2))*sqrt(c + d*x)/(b**S(2)*d**S(3)) - S(1)/S(240)*(b*c - a*d)*(S(7)*b*c + S(3)*a*d)*(a + b*x)**(S(5)/S(2))*sqrt(c + d*x)/(b**S(2)*d**S(2)) - S(1)/S(40)*(S(7)*b*c + S(3)*a*d)*(a + b*x)**(S(7)/S(2))*sqrt(c + d*x)/(b**S(2)*d) - S(1)/S(128)*(b*c - a*d)**S(3)*(S(7)*b*c + S(3)*a*d)*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(2)*d**S(4))], [x**S(2)*sqrt(c + d*x)/sqrt(a + b*x), x, S(5), S(1)/S(8)*(b*c - a*d)*(b**S(2)*c**S(2) + S(2)*a*b*c*d + S(5)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(7)/S(2))*d**(S(5)/S(2))) - S(1)/S(12)*(S(3)*b*c + S(5)*a*d)*(c + d*x)**(S(3)/S(2))*sqrt(a + b*x)/(b**S(2)*d**S(2)) + S(1)/S(3)*x*(c + d*x)**(S(3)/S(2))*sqrt(a + b*x)/(b*d) + S(1)/S(8)*(b**S(2)*c**S(2) + S(2)*a*b*c*d + S(5)*a**S(2)*d**S(2))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(3)*d**S(2))], [x*sqrt(c + d*x)/sqrt(a + b*x), x, S(4), - S(1)/S(4)*(b*c - a*d)*(b*c + S(3)*a*d)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(3)/S(2))) + S(1)/S(2)*(c + d*x)**(S(3)/S(2))*sqrt(a + b*x)/(b*d) - S(1)/S(4)*(b*c + S(3)*a*d)*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(2)*d)], [x**S(3)/(sqrt(a + b*x)*sqrt(c + d*x)), x, S(4), - S(1)/S(8)*(b*c + a*d)*(S(5)*b**S(2)*c**S(2) - S(2)*a*b*c*d + S(5)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(7)/S(2))*d**(S(7)/S(2))) + S(1)/S(3)*x**S(2)*sqrt(a + b*x)*sqrt(c + d*x)/(b*d) + S(1)/S(24)*(S(15)*b**S(2)*c**S(2) + S(14)*a*b*c*d + S(15)*a**S(2)*d**S(2) - S(10)*b*d*(b*c + a*d)*x)*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(3)*d**S(3))], [x**S(2)/(sqrt(a + b*x)*sqrt(c + d*x)), x, S(4), - S(1)/S(4)*(S(4)*a*b*c*d - S(3)*(b*c + a*d)**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(5)/S(2))) - S(3)/S(4)*(b*c + a*d)*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(2)*d**S(2)) + S(1)/S(2)*x*sqrt(a + b*x)*sqrt(c + d*x)/(b*d)], [x**S(4)/((a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(2))), x, S(5), S(3)/S(4)*(S(5)*b**S(2)*c**S(2) + S(6)*a*b*c*d + S(5)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(7)/S(2))*d**(S(7)/S(2))) + S(2)*a*x**S(3)/(b*(b*c - a*d)*sqrt(a + b*x)*sqrt(c + d*x)) - S(2)*c*(b*c + a*d)*x**S(2)*sqrt(a + b*x)/(b*d*(b*c - a*d)**S(2)*sqrt(c + d*x)) - S(1)/S(4)*((b*c + a*d)*(S(15)*b**S(2)*c**S(2) - S(22)*a*b*c*d + S(15)*a**S(2)*d**S(2)) - S(2)*b*d*(S(5)*b**S(2)*c**S(2) - S(2)*a*b*c*d + S(5)*a**S(2)*d**S(2))*x)*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(3)*d**S(3)*(b*c - a*d)**S(2))], [x**S(3)/((a + b*x)**(S(3)/S(2))*(c + d*x)**(S(3)/S(2))), x, S(4), - S(3)*(b*c + a*d)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*d**(S(5)/S(2))) + S(2)*a*x**S(2)/(b*(b*c - a*d)*sqrt(a + b*x)*sqrt(c + d*x)) + (c*(S(3)*b**S(2)*c**S(2) - S(2)*a*b*c*d + S(3)*a**S(2)*d**S(2)) + d*(b*c - S(3)*a*d)*(b*c - a*d)*x)*sqrt(a + b*x)/(b**S(2)*d**S(2)*(b*c - a*d)**S(2)*sqrt(c + d*x))], [x**S(3)*(a + b*x)**(S(1)/S(4))/(c + d*x)**(S(1)/S(4)), x, S(7), - S(1)/S(512)*(S(195)*b**S(3)*c**S(3) + S(135)*a*b**S(2)*c**S(2)*d + S(105)*a**S(2)*b*c*d**S(2) + S(77)*a**S(3)*d**S(3))*(a + b*x)**(S(1)/S(4))*(c + d*x)**(S(3)/S(4))/(b**S(3)*d**S(4)) + S(1)/S(4)*x**S(2)*(a + b*x)**(S(5)/S(4))*(c + d*x)**(S(3)/S(4))/(b*d) + S(1)/S(384)*(a + b*x)**(S(5)/S(4))*(c + d*x)**(S(3)/S(4))*(S(117)*b**S(2)*c**S(2) + S(94)*a*b*c*d + S(77)*a**S(2)*d**S(2) - S(8)*b*d*(S(13)*b*c + S(11)*a*d)*x)/(b**S(3)*d**S(3)) + S(1)/S(1024)*(b*c - a*d)*(S(195)*b**S(3)*c**S(3) + S(135)*a*b**S(2)*c**S(2)*d + S(105)*a**S(2)*b*c*d**S(2) + S(77)*a**S(3)*d**S(3))*arctan(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(15)/S(4))*d**(S(17)/S(4))) + S(1)/S(1024)*(b*c - a*d)*(S(195)*b**S(3)*c**S(3) + S(135)*a*b**S(2)*c**S(2)*d + S(105)*a**S(2)*b*c*d**S(2) + S(77)*a**S(3)*d**S(3))*arctanh(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(15)/S(4))*d**(S(17)/S(4)))], [x**S(2)*(a + b*x)**(S(1)/S(4))/(c + d*x)**(S(1)/S(4)), x, S(7), S(1)/S(32)*(S(15)*b**S(2)*c**S(2) + S(10)*a*b*c*d + S(7)*a**S(2)*d**S(2))*(a + b*x)**(S(1)/S(4))*(c + d*x)**(S(3)/S(4))/(b**S(2)*d**S(3)) - S(1)/S(24)*(S(9)*b*c + S(7)*a*d)*(a + b*x)**(S(5)/S(4))*(c + d*x)**(S(3)/S(4))/(b**S(2)*d**S(2)) + S(1)/S(3)*x*(a + b*x)**(S(5)/S(4))*(c + d*x)**(S(3)/S(4))/(b*d) - S(1)/S(64)*(b*c - a*d)*(S(15)*b**S(2)*c**S(2) + S(10)*a*b*c*d + S(7)*a**S(2)*d**S(2))*arctan(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(11)/S(4))*d**(S(13)/S(4))) - S(1)/S(64)*(b*c - a*d)*(S(15)*b**S(2)*c**S(2) + S(10)*a*b*c*d + S(7)*a**S(2)*d**S(2))*arctanh(d**(S(1)/S(4))*(a + b*x)**(S(1)/S(4))/(b**(S(1)/S(4))*(c + d*x)**(S(1)/S(4))))/(b**(S(11)/S(4))*d**(S(13)/S(4)))], [x*(a + b*x)**n*(c + d*x), x, S(2), - a*(b*c - a*d)*(a + b*x)**(S(1) + n)/(b**S(3)*(S(1) + n)) + (b*c - S(2)*a*d)*(a + b*x)**(S(2) + n)/(b**S(3)*(S(2) + n)) + d*(a + b*x)**(S(3) + n)/(b**S(3)*(S(3) + n))], [x**S(2)*(a + b*x)**n/(c + d*x), x, S(3), - (b*c + a*d)*(a + b*x)**(S(1) + n)/(b**S(2)*d**S(2)*(S(1) + n)) + (a + b*x)**(S(2) + n)/(b**S(2)*d*(S(2) + n)) + c**S(2)*(a + b*x)**(S(1) + n)*hypergeom([S(1), S(1) + n], [S(2) + n], - d*(a + b*x)/(b*c - a*d))/(d**S(2)*(b*c - a*d)*(S(1) + n))], [x*(a + b*x)**n/(c + d*x), x, S(2), (a + b*x)**(S(1) + n)/(b*d*(S(1) + n)) - c*(a + b*x)**(S(1) + n)*hypergeom([S(1), S(1) + n], [S(2) + n], - d*(a + b*x)/(b*c - a*d))/(d*(b*c - a*d)*(S(1) + n))], [x**m*(S(3) - S(2)*a*x)**(S(2) + n)*(S(6) + S(4)*a*x)**n, x, S(8), S(2)**n*S(9)**(S(1) + n)*x**(S(1) + m)*hypergeom([S(1)/S(2)*(S(1) + m), - n], [S(1)/S(2)*(S(3) + m)], S(4)/S(9)*a**S(2)*x**S(2))/(S(1) + m) - S(2)**(S(2) + n)*S(3)**(S(1) + S(2)*n)*a*x**(S(2) + m)*hypergeom([S(1)/S(2)*(S(2) + m), - n], [S(1)/S(2)*(S(4) + m)], S(4)/S(9)*a**S(2)*x**S(2))/(S(2) + m) + S(2)**(S(2) + n)*S(9)**n*a**S(2)*x**(S(3) + m)*hypergeom([S(1)/S(2)*(S(3) + m), - n], [S(1)/S(2)*(S(5) + m)], S(4)/S(9)*a**S(2)*x**S(2))/(S(3) + m)], [x**m*(S(3) - S(2)*a*x)**(S(1) + n)*(S(6) + S(4)*a*x)**n, x, S(5), S(2)**n*S(3)**(S(1) + S(2)*n)*x**(S(1) + m)*hypergeom([S(1)/S(2)*(S(1) + m), - n], [S(1)/S(2)*(S(3) + m)], S(4)/S(9)*a**S(2)*x**S(2))/(S(1) + m) - S(2)**(S(1) + n)*S(9)**n*a*x**(S(2) + m)*hypergeom([S(1)/S(2)*(S(2) + m), - n], [S(1)/S(2)*(S(4) + m)], S(4)/S(9)*a**S(2)*x**S(2))/(S(2) + m)], [(a + b*x)*(A + B*x)*(d + e*x)**m, x, S(2), (b*d - a*e)*(B*d - A*e)*(d + e*x)**(S(1) + m)/(e**S(3)*(S(1) + m)) - (S(2)*b*B*d - A*b*e - a*B*e)*(d + e*x)**(S(2) + m)/(e**S(3)*(S(2) + m)) + b*B*(d + e*x)**(S(3) + m)/(e**S(3)*(S(3) + m))], [(A + B*x)*(d + e*x)**S(5)/(a + b*x), x, S(2), (A*b - a*B)*e*(b*d - a*e)**S(4)*x/b**S(6) + S(1)/S(2)*(A*b - a*B)*(b*d - a*e)**S(3)*(d + e*x)**S(2)/b**S(5) + S(1)/S(3)*(A*b - a*B)*(b*d - a*e)**S(2)*(d + e*x)**S(3)/b**S(4) + S(1)/S(4)*(A*b - a*B)*(b*d - a*e)*(d + e*x)**S(4)/b**S(3) + S(1)/S(5)*(A*b - a*B)*(d + e*x)**S(5)/b**S(2) + S(1)/S(6)*B*(d + e*x)**S(6)/(b*e) + (A*b - a*B)*(b*d - a*e)**S(5)*log(a + b*x)/b**S(7)], [(S(1) - S(2)*x)*(S(2) + S(3)*x)**m*(S(3) + S(5)*x), x, S(2), - S(7)/S(27)*(S(2) + S(3)*x)**(S(1) + m)/(S(1) + m) + S(37)/S(27)*(S(2) + S(3)*x)**(S(2) + m)/(S(2) + m) - S(10)/S(27)*(S(2) + S(3)*x)**(S(3) + m)/(S(3) + m)], [(S(1) - S(2)*x)*(S(2) + S(3)*x)**S(8)*(S(3) + S(5)*x), x, S(2), - S(7)/S(243)*(S(2) + S(3)*x)**S(9) + S(37)/S(270)*(S(2) + S(3)*x)**S(10) - S(10)/S(297)*(S(2) + S(3)*x)**S(11)], [(S(1) - S(2)*x)*(S(2) + S(3)*x)**m/(S(3) + S(5)*x), x, S(2), - S(2)/S(15)*(S(2) + S(3)*x)**(S(1) + m)/(S(1) + m) - S(11)/S(5)*(S(2) + S(3)*x)**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], S(5)*(S(2) + S(3)*x))/(S(1) + m)], [(S(1) - S(2)*x)*(S(2) + S(3)*x)**S(6)/(S(3) + S(5)*x), x, S(2), S(1666663)/S(78125)*x + S(1777779)/S(31250)*x**S(2) + S(152469)/S(3125)*x**S(3) - S(152469)/S(2500)*x**S(4) - S(106677)/S(625)*x**S(5) - S(7047)/S(50)*x**S(6) - S(1458)/S(35)*x**S(7) + S(11)/S(390625)*log(S(3) + S(5)*x)], [(S(1) - S(2)*x)**S(2)*(S(2) + S(3)*x)**S(8)*(S(3) + S(5)*x), x, S(2), - S(49)/S(729)*(S(2) + S(3)*x)**S(9) + S(91)/S(270)*(S(2) + S(3)*x)**S(10) - S(16)/S(99)*(S(2) + S(3)*x)**S(11) + S(5)/S(243)*(S(2) + S(3)*x)**S(12)], [(S(1) - S(2)*x)**S(2)*(S(2) + S(3)*x)**S(7)*(S(3) + S(5)*x), x, S(2), - S(49)/S(648)*(S(2) + S(3)*x)**S(8) + S(91)/S(243)*(S(2) + S(3)*x)**S(9) - S(8)/S(45)*(S(2) + S(3)*x)**S(10) + S(20)/S(891)*(S(2) + S(3)*x)**S(11)], [(S(1) - S(2)*x)**S(2)*(S(2) + S(3)*x)**S(7)/(S(3) + S(5)*x), x, S(2), S(83333293)/S(1953125)*x + S(80555569)/S(781250)*x**S(2) + S(1327159)/S(78125)*x**S(3) - S(20577159)/S(62500)*x**S(4) - S(7315947)/S(15625)*x**S(5) + S(130383)/S(1250)*x**S(6) + S(672867)/S(875)*x**S(7) + S(16767)/S(25)*x**S(8) + S(972)/S(5)*x**S(9) + S(121)/S(9765625)*log(S(3) + S(5)*x)], [(S(1) - S(2)*x)**S(2)*(S(2) + S(3)*x)**S(6)/(S(3) + S(5)*x), x, S(2), S(8333293)/S(390625)*x + S(5555569)/S(156250)*x**S(2) - S(422841)/S(15625)*x**S(3) - S(1677159)/S(12500)*x**S(4) - S(228447)/S(3125)*x**S(5) + S(35883)/S(250)*x**S(6) + S(34992)/S(175)*x**S(7) + S(729)/S(10)*x**S(8) + S(121)/S(1953125)*log(S(3) + S(5)*x)], [(S(1) - S(2)*x)**S(3)*(S(2) + S(3)*x)**S(8)*(S(3) + S(5)*x), x, S(2), - S(343)/S(2187)*(S(2) + S(3)*x)**S(9) + S(2009)/S(2430)*(S(2) + S(3)*x)**S(10) - S(518)/S(891)*(S(2) + S(3)*x)**S(11) + S(107)/S(729)*(S(2) + S(3)*x)**S(12) - S(40)/S(3159)*(S(2) + S(3)*x)**S(13)], [(S(1) - S(2)*x)**S(3)*(S(2) + S(3)*x)**S(7)*(S(3) + S(5)*x), x, S(2), S(384)*x + S(1184)*x**S(2) + S(480)*x**S(3) - S(5148)*x**S(4) - S(48968)/S(5)*x**S(5) + S(3514)*x**S(6) + S(29106)*x**S(7) + S(208035)/S(8)*x**S(8) - S(15507)*x**S(9) - S(217971)/S(5)*x**S(10) - S(329508)/S(11)*x**S(11) - S(7290)*x**S(12)], [(S(1) - S(2)*x)**S(3)*(S(2) + S(3)*x)**S(6)/(S(3) + S(5)*x), x, S(2), S(41666223)/S(1953125)*x + S(11111259)/S(781250)*x**S(2) - S(17453753)/S(234375)*x**S(3) - S(5848749)/S(62500)*x**S(4) + S(2212083)/S(15625)*x**S(5) + S(331713)/S(1250)*x**S(6) - S(40338)/S(875)*x**S(7) - S(13851)/S(50)*x**S(8) - S(648)/S(5)*x**S(9) + S(1331)/S(9765625)*log(S(3) + S(5)*x)], [(S(1) - S(2)*x)**S(3)*(S(2) + S(3)*x)**S(5)/(S(3) + S(5)*x), x, S(2), S(4166223)/S(390625)*x - S(138741)/S(156250)*x**S(2) - S(1703753)/S(46875)*x**S(3) - S(73749)/S(12500)*x**S(4) + S(243333)/S(3125)*x**S(5) + S(4419)/S(125)*x**S(6) - S(11988)/S(175)*x**S(7) - S(243)/S(5)*x**S(8) + S(1331)/S(1953125)*log(S(3) + S(5)*x)], [(S(2) + S(3)*x)**m*(S(3) + S(5)*x)/(S(1) - S(2)*x), x, S(2), - S(5)/S(6)*(S(2) + S(3)*x)**(S(1) + m)/(S(1) + m) + S(11)/S(14)*(S(2) + S(3)*x)**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], S(2)/S(7)*(S(2) + S(3)*x))/(S(1) + m)], [(S(2) + S(3)*x)**S(8)*(S(3) + S(5)*x)/(S(1) - S(2)*x), x, S(2), - S(63019595)/S(512)*x - S(60332619)/S(512)*x**S(2) - S(17391129)/S(128)*x**S(3) - S(37722699)/S(256)*x**S(4) - S(21272139)/S(160)*x**S(5) - S(2929689)/S(32)*x**S(6) - S(353565)/S(8)*x**S(7) - S(422091)/S(32)*x**S(8) - S(3645)/S(2)*x**S(9) - S(63412811)/S(1024)*log(S(1) - S(2)*x)], [(S(2) + S(3)*x)**m/((S(1) - S(2)*x)*(S(3) + S(5)*x)), x, S(3), S(2)/S(77)*(S(2) + S(3)*x)**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], S(2)/S(7)*(S(2) + S(3)*x))/(S(1) + m) - S(5)/S(11)*(S(2) + S(3)*x)**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], S(5)*(S(2) + S(3)*x))/(S(1) + m)], [(S(2) + S(3)*x)**S(8)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**S(2), x, S(2), S(63412811)/S(1024)/(S(1) - S(2)*x) + S(91609881)/S(256)*x + S(122887143)/S(512)*x**S(2) + S(5892813)/S(32)*x**S(3) + S(32991057)/S(256)*x**S(4) + S(5859459)/S(80)*x**S(5) + S(976617)/S(32)*x**S(6) + S(56862)/S(7)*x**S(7) + S(32805)/S(32)*x**S(8) + S(246239357)/S(1024)*log(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(7)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**S(2), x, S(2), S(9058973)/S(512)/(S(1) - S(2)*x) + S(22333965)/S(256)*x + S(873207)/S(16)*x**S(2) + S(2399985)/S(64)*x**S(3) + S(1423899)/S(64)*x**S(4) + S(793881)/S(80)*x**S(5) + S(11421)/S(4)*x**S(6) + S(10935)/S(28)*x**S(7) + S(15647317)/S(256)*log(S(1) - S(2)*x)], [(a + b*x)**m/(e + f*x)**S(2), x, S(1), b*(a + b*x)**(S(1) + m)*hypergeom([S(2), S(1) + m], [S(2) + m], - f*(a + b*x)/(b*e - a*f))/((b*e - a*f)**S(2)*(S(1) + m))], [(a + b*x)**m/((c + d*x)*(e + f*x)**S(2)), x, S(4), - f*(a + b*x)**(S(1) + m)/((b*e - a*f)*(d*e - c*f)*(e + f*x)) + d**S(2)*(a + b*x)**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], - d*(a + b*x)/(b*c - a*d))/((b*c - a*d)*(d*e - c*f)**S(2)*(S(1) + m)) + f*(a*d*f - b*(d*e*(S(1) - m) + c*f*m))*(a + b*x)**(S(1) + m)*hypergeom([S(1), S(1) + m], [S(2) + m], - f*(a + b*x)/(b*e - a*f))/((b*e - a*f)**S(2)*(d*e - c*f)**S(2)*(S(1) + m))], [(S(2) + S(3)*x)**S(7)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**S(3), x, S(2), S(9058973)/S(1024)/(S(1) - S(2)*x)**S(2) + ( - S(15647317)/S(256))/(S(1) - S(2)*x) - S(24960933)/S(256)*x - S(10989621)/S(256)*x**S(2) - S(631611)/S(32)*x**S(3) - S(235467)/S(32)*x**S(4) - S(147987)/S(80)*x**S(5) - S(3645)/S(16)*x**S(6) - S(23647449)/S(256)*log(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(8)/((S(1) - S(2)*x)**S(3)*(S(3) + S(5)*x)), x, S(2), S(5764801)/S(5632)/(S(1) - S(2)*x)**S(2) + ( - S(188591347)/S(30976))/(S(1) - S(2)*x) - S(2941619571)/S(400000)*x - S(110180817)/S(40000)*x**S(2) - S(124416)/S(125)*x**S(3) - S(408969)/S(1600)*x**S(4) - S(6561)/S(200)*x**S(5) - S(2644396573)/S(340736)*log(S(1) - S(2)*x) + S(1)/S(20796875)*log(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(7)/((S(1) - S(2)*x)**S(3)*(S(3) + S(5)*x)), x, S(2), S(823543)/S(2816)/(S(1) - S(2)*x)**S(2) + ( - S(5764801)/S(3872))/(S(1) - S(2)*x) - S(26161299)/S(20000)*x - S(792423)/S(2000)*x**S(2) - S(40581)/S(400)*x**S(3) - S(2187)/S(160)*x**S(4) - S(269063263)/S(170368)*log(S(1) - S(2)*x) + S(1)/S(4159375)*log(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(6)*(S(3) + S(5)*x)*sqrt(S(1) - S(2)*x), x, S(2), - S(1294139)/S(384)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(3916031)/S(640)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(725445)/S(128)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(406455)/S(128)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(1580985)/S(1408)*(S(1) - S(2)*x)**(S(11)/S(2)) + S(409941)/S(1664)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(19683)/S(640)*(S(1) - S(2)*x)**(S(15)/S(2)) + S(3645)/S(2176)*(S(1) - S(2)*x)**(S(17)/S(2))], [(S(2) + S(3)*x)**S(5)*(S(3) + S(5)*x)*sqrt(S(1) - S(2)*x), x, S(2), - S(184877)/S(192)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(12005)/S(8)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(74235)/S(64)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(4165)/S(8)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(97335)/S(704)*(S(1) - S(2)*x)**(S(11)/S(2)) + S(81)/S(4)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(81)/S(64)*(S(1) - S(2)*x)**(S(15)/S(2))], [(S(2) + S(3)*x)**S(4)*sqrt(S(1) - S(2)*x)/(S(3) + S(5)*x), x, S(5), - S(45473)/S(5000)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(34371)/S(5000)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(2889)/S(1400)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(9)/S(40)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(2)/S(3125)*arctanh(sqrt(S(5)/S(11))*sqrt(S(1) - S(2)*x))*sqrt(S(11)/S(5)) + S(2)/S(3125)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(3)*sqrt(S(1) - S(2)*x)/(S(3) + S(5)*x), x, S(5), - S(1299)/S(500)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(162)/S(125)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(27)/S(140)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(2)/S(625)*arctanh(sqrt(S(5)/S(11))*sqrt(S(1) - S(2)*x))*sqrt(S(11)/S(5)) + S(2)/S(625)*sqrt(S(1) - S(2)*x)], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(6)*(S(3) + S(5)*x), x, S(2), - S(1294139)/S(640)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(559433)/S(128)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(564235)/S(128)*(S(1) - S(2)*x)**(S(9)/S(2)) + S(3658095)/S(1408)*(S(1) - S(2)*x)**(S(11)/S(2)) - S(1580985)/S(1664)*(S(1) - S(2)*x)**(S(13)/S(2)) + S(136647)/S(640)*(S(1) - S(2)*x)**(S(15)/S(2)) - S(59049)/S(2176)*(S(1) - S(2)*x)**(S(17)/S(2)) + S(3645)/S(2432)*(S(1) - S(2)*x)**(S(19)/S(2))], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(5)*(S(3) + S(5)*x), x, S(2), - S(184877)/S(320)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(8575)/S(8)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(173215)/S(192)*(S(1) - S(2)*x)**(S(9)/S(2)) + S(37485)/S(88)*(S(1) - S(2)*x)**(S(11)/S(2)) - S(97335)/S(832)*(S(1) - S(2)*x)**(S(13)/S(2)) + S(351)/S(20)*(S(1) - S(2)*x)**(S(15)/S(2)) - S(1215)/S(1088)*(S(1) - S(2)*x)**(S(17)/S(2))], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(6)/(S(3) + S(5)*x), x, S(6), S(2)/S(234375)*(S(1) - S(2)*x)**(S(3)/S(2)) - S(167115051)/S(2500000)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(70752609)/S(700000)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(665817)/S(10000)*(S(1) - S(2)*x)**(S(9)/S(2)) + S(507627)/S(22000)*(S(1) - S(2)*x)**(S(11)/S(2)) - S(43011)/S(10400)*(S(1) - S(2)*x)**(S(13)/S(2)) + S(243)/S(800)*(S(1) - S(2)*x)**(S(15)/S(2)) - S(22)/S(390625)*arctanh(sqrt(S(5)/S(11))*sqrt(S(1) - S(2)*x))*sqrt(S(11)/S(5)) + S(22)/S(390625)*sqrt(S(1) - S(2)*x)], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(5)/(S(3) + S(5)*x), x, S(6), S(2)/S(46875)*(S(1) - S(2)*x)**(S(3)/S(2)) - S(4774713)/S(250000)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(806121)/S(35000)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(5673)/S(500)*(S(1) - S(2)*x)**(S(9)/S(2)) + S(5751)/S(2200)*(S(1) - S(2)*x)**(S(11)/S(2)) - S(243)/S(1040)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(22)/S(78125)*arctanh(sqrt(S(5)/S(11))*sqrt(S(1) - S(2)*x))*sqrt(S(11)/S(5)) + S(22)/S(78125)*sqrt(S(1) - S(2)*x)], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(6)*(S(3) + S(5)*x), x, S(2), - S(184877)/S(128)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(3916031)/S(1152)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(5078115)/S(1408)*(S(1) - S(2)*x)**(S(11)/S(2)) + S(3658095)/S(1664)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(105399)/S(128)*(S(1) - S(2)*x)**(S(15)/S(2)) + S(409941)/S(2176)*(S(1) - S(2)*x)**(S(17)/S(2)) - S(59049)/S(2432)*(S(1) - S(2)*x)**(S(19)/S(2)) + S(1215)/S(896)*(S(1) - S(2)*x)**(S(21)/S(2))], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(5)*(S(3) + S(5)*x), x, S(2), - S(26411)/S(64)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(60025)/S(72)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(519645)/S(704)*(S(1) - S(2)*x)**(S(11)/S(2)) + S(37485)/S(104)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(6489)/S(64)*(S(1) - S(2)*x)**(S(15)/S(2)) + S(1053)/S(68)*(S(1) - S(2)*x)**(S(17)/S(2)) - S(1215)/S(1216)*(S(1) - S(2)*x)**(S(19)/S(2))], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(4)/(S(3) + S(5)*x), x, S(7), S(22)/S(46875)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(2)/S(15625)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(136419)/S(35000)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(3819)/S(1000)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(2889)/S(2200)*(S(1) - S(2)*x)**(S(11)/S(2)) + S(81)/S(520)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(242)/S(78125)*arctanh(sqrt(S(5)/S(11))*sqrt(S(1) - S(2)*x))*sqrt(S(11)/S(5)) + S(242)/S(78125)*sqrt(S(1) - S(2)*x)], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(3)/(S(3) + S(5)*x), x, S(7), S(22)/S(9375)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(2)/S(3125)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(3897)/S(3500)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(18)/S(25)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(27)/S(220)*(S(1) - S(2)*x)**(S(11)/S(2)) - S(242)/S(15625)*arctanh(sqrt(S(5)/S(11))*sqrt(S(1) - S(2)*x))*sqrt(S(11)/S(5)) + S(242)/S(15625)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(5)*(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x), x, S(2), S(60025)/S(24)*(S(1) - S(2)*x)**(S(3)/S(2)) - S(103929)/S(64)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(5355)/S(8)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(10815)/S(64)*(S(1) - S(2)*x)**(S(9)/S(2)) + S(1053)/S(44)*(S(1) - S(2)*x)**(S(11)/S(2)) - S(1215)/S(832)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(184877)/S(64)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(4)*(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x), x, S(2), S(57281)/S(96)*(S(1) - S(2)*x)**(S(3)/S(2)) - S(24843)/S(80)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(1539)/S(16)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(519)/S(32)*(S(1) - S(2)*x)**(S(9)/S(2)) + S(405)/S(352)*(S(1) - S(2)*x)**(S(11)/S(2)) - S(26411)/S(32)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(5)/((S(3) + S(5)*x)*sqrt(S(1) - S(2)*x)), x, S(4), S(268707)/S(5000)*(S(1) - S(2)*x)**(S(3)/S(2)) - S(51057)/S(2500)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(5751)/S(1400)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(27)/S(80)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(2)/S(3125)*arctanh(sqrt(S(5)/S(11))*sqrt(S(1) - S(2)*x))/sqrt(S(55)) - S(4774713)/S(50000)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(7)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)), x, S(2), - S(7882483)/S(128)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(4084101)/S(128)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(787185)/S(64)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(422919)/S(128)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(821583)/S(1408)*(S(1) - S(2)*x)**(S(11)/S(2)) + S(101331)/S(1664)*(S(1) - S(2)*x)**(S(13)/S(2)) - S(729)/S(256)*(S(1) - S(2)*x)**(S(15)/S(2)) + S(9058973)/S(256)/sqrt(S(1) - S(2)*x) + S(15647317)/S(128)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(6)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)), x, S(2), - S(1692705)/S(128)*(S(1) - S(2)*x)**(S(3)/S(2)) + S(731619)/S(128)*(S(1) - S(2)*x)**(S(5)/S(2)) - S(225855)/S(128)*(S(1) - S(2)*x)**(S(7)/S(2)) + S(45549)/S(128)*(S(1) - S(2)*x)**(S(9)/S(2)) - S(59049)/S(1408)*(S(1) - S(2)*x)**(S(11)/S(2)) + S(3645)/S(1664)*(S(1) - S(2)*x)**(S(13)/S(2)) + S(1294139)/S(128)/sqrt(S(1) - S(2)*x) + S(3916031)/S(128)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(5)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(5)/S(2)), x, S(2), S(184877)/S(192)/(S(1) - S(2)*x)**(S(3)/S(2)) + S(12495)/S(8)*(S(1) - S(2)*x)**(S(3)/S(2)) - S(19467)/S(64)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(1053)/S(28)*(S(1) - S(2)*x)**(S(7)/S(2)) - S(135)/S(64)*(S(1) - S(2)*x)**(S(9)/S(2)) + ( - S(60025)/S(8))/sqrt(S(1) - S(2)*x) - S(519645)/S(64)*sqrt(S(1) - S(2)*x)], [(S(2) + S(3)*x)**S(4)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(5)/S(2)), x, S(2), S(26411)/S(96)/(S(1) - S(2)*x)**(S(3)/S(2)) + S(3591)/S(16)*(S(1) - S(2)*x)**(S(3)/S(2)) - S(4671)/S(160)*(S(1) - S(2)*x)**(S(5)/S(2)) + S(405)/S(224)*(S(1) - S(2)*x)**(S(7)/S(2)) + ( - S(57281)/S(32))/sqrt(S(1) - S(2)*x) - S(24843)/S(16)*sqrt(S(1) - S(2)*x)], [(A + B*x)*(d + e*x)**(S(5)/S(2))*sqrt(a + b*x), x, S(7), - S(1)/S(48)*(b*d - a*e)*(S(3)*b*B*d - S(10)*A*b*e + S(7)*a*B*e)*(a + b*x)**(S(3)/S(2))*(d + e*x)**(S(3)/S(2))/(b**S(3)*e) - S(1)/S(40)*(S(3)*b*B*d - S(10)*A*b*e + S(7)*a*B*e)*(a + b*x)**(S(3)/S(2))*(d + e*x)**(S(5)/S(2))/(b**S(2)*e) + S(1)/S(5)*B*(a + b*x)**(S(3)/S(2))*(d + e*x)**(S(7)/S(2))/(b*e) + S(1)/S(128)*(b*d - a*e)**S(4)*(S(3)*b*B*d - S(10)*A*b*e + S(7)*a*B*e)*arctanh(sqrt(e)*sqrt(a + b*x)/(sqrt(b)*sqrt(d + e*x)))/(b**(S(9)/S(2))*e**(S(5)/S(2))) - S(1)/S(64)*(b*d - a*e)**S(2)*(S(3)*b*B*d - S(10)*A*b*e + S(7)*a*B*e)*(a + b*x)**(S(3)/S(2))*sqrt(d + e*x)/(b**S(4)*e) - S(1)/S(128)*(b*d - a*e)**S(3)*(S(3)*b*B*d - S(10)*A*b*e + S(7)*a*B*e)*sqrt(a + b*x)*sqrt(d + e*x)/(b**S(4)*e**S(2))], [(A + B*x)*(d + e*x)**(S(3)/S(2))*sqrt(a + b*x), x, S(6), - S(1)/S(24)*(S(3)*b*B*d - S(8)*A*b*e + S(5)*a*B*e)*(a + b*x)**(S(3)/S(2))*(d + e*x)**(S(3)/S(2))/(b**S(2)*e) + S(1)/S(4)*B*(a + b*x)**(S(3)/S(2))*(d + e*x)**(S(5)/S(2))/(b*e) + S(1)/S(64)*(b*d - a*e)**S(3)*(S(3)*b*B*d - S(8)*A*b*e + S(5)*a*B*e)*arctanh(sqrt(e)*sqrt(a + b*x)/(sqrt(b)*sqrt(d + e*x)))/(b**(S(7)/S(2))*e**(S(5)/S(2))) - S(1)/S(32)*(b*d - a*e)*(S(3)*b*B*d - S(8)*A*b*e + S(5)*a*B*e)*(a + b*x)**(S(3)/S(2))*sqrt(d + e*x)/(b**S(3)*e) - S(1)/S(64)*(b*d - a*e)**S(2)*(S(3)*b*B*d - S(8)*A*b*e + S(5)*a*B*e)*sqrt(a + b*x)*sqrt(d + e*x)/(b**S(3)*e**S(2))], [(A + B*x)*(d + e*x)**(S(5)/S(2))/sqrt(a + b*x), x, S(6), - S(5)/S(64)*(b*d - a*e)**S(3)*(b*B*d - S(8)*A*b*e + S(7)*a*B*e)*arctanh(sqrt(e)*sqrt(a + b*x)/(sqrt(b)*sqrt(d + e*x)))/(b**(S(9)/S(2))*e**(S(3)/S(2))) - S(5)/S(96)*(b*d - a*e)*(b*B*d - S(8)*A*b*e + S(7)*a*B*e)*(d + e*x)**(S(3)/S(2))*sqrt(a + b*x)/(b**S(3)*e) - S(1)/S(24)*(b*B*d - S(8)*A*b*e + S(7)*a*B*e)*(d + e*x)**(S(5)/S(2))*sqrt(a + b*x)/(b**S(2)*e) + S(1)/S(4)*B*(d + e*x)**(S(7)/S(2))*sqrt(a + b*x)/(b*e) - S(5)/S(64)*(b*d - a*e)**S(2)*(b*B*d - S(8)*A*b*e + S(7)*a*B*e)*sqrt(a + b*x)*sqrt(d + e*x)/(b**S(4)*e)], [(A + B*x)*(d + e*x)**(S(3)/S(2))/sqrt(a + b*x), x, S(5), - S(1)/S(8)*(b*d - a*e)**S(2)*(b*B*d - S(6)*A*b*e + S(5)*a*B*e)*arctanh(sqrt(e)*sqrt(a + b*x)/(sqrt(b)*sqrt(d + e*x)))/(b**(S(7)/S(2))*e**(S(3)/S(2))) - S(1)/S(12)*(b*B*d - S(6)*A*b*e + S(5)*a*B*e)*(d + e*x)**(S(3)/S(2))*sqrt(a + b*x)/(b**S(2)*e) + S(1)/S(3)*B*(d + e*x)**(S(5)/S(2))*sqrt(a + b*x)/(b*e) - S(1)/S(8)*(b*d - a*e)*(b*B*d - S(6)*A*b*e + S(5)*a*B*e)*sqrt(a + b*x)*sqrt(d + e*x)/(b**S(3)*e)], [(S(2) + S(3)*x)**S(4)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x), x, S(7), - S(333)/S(2000)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(2)*(S(3) + S(5)*x)**(S(3)/S(2)) - S(1)/S(20)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(3)*(S(3) + S(5)*x)**(S(3)/S(2)) - S(7)/S(640000)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(3) + S(5)*x)**(S(3)/S(2))*(S(231223) + S(140652)*x) + S(4122385421)/S(51200000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(34069301)/S(5120000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) + S(374762311)/S(51200000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(3)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x), x, S(6), - S(3)/S(50)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(2)*(S(3) + S(5)*x)**(S(3)/S(2)) - S(21)/S(16000)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(3) + S(5)*x)**(S(3)/S(2))*(S(731) + S(444)*x) + S(39142411)/S(1280000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(323491)/S(128000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) + S(3558401)/S(1280000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(3)*sqrt(S(1) - S(2)*x)/sqrt(S(3) + S(5)*x), x, S(5), S(525371)/S(64000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(3)/S(40)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x) - S(21)/S(6400)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(335) + S(216)*x)*sqrt(S(3) + S(5)*x) + S(47761)/S(64000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)/sqrt(S(3) + S(5)*x), x, S(5), S(3047)/S(800)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(23)/S(80)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) - S(1)/S(10)*(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)*sqrt(S(3) + S(5)*x) + S(277)/S(800)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x), x, S(7), - S(1)/S(20)*(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(2)*(S(3) + S(5)*x)**(S(3)/S(2)) - S(1)/S(160000)*(S(1) - S(2)*x)**(S(5)/S(2))*(S(3) + S(5)*x)**(S(3)/S(2))*(S(88987) + S(63120)*x) + S(452517373)/S(25600000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(3739813)/S(7680000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) - S(339983)/S(384000)*(S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x) + S(41137943)/S(25600000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x), x, S(7), - S(567)/S(4000)*(S(1) - S(2)*x)**(S(5)/S(2))*(S(3) + S(5)*x)**(S(3)/S(2)) - S(3)/S(50)*(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)*(S(3) + S(5)*x)**(S(3)/S(2)) + S(5487713)/S(640000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(45353)/S(192000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) - S(4123)/S(9600)*(S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x) + S(498883)/S(640000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(3)/sqrt(S(3) + S(5)*x), x, S(6), S(18648399)/S(3200000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(51373)/S(320000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) - S(3)/S(50)*(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x) - S(3)/S(80000)*(S(1) - S(2)*x)**(S(5)/S(2))*(S(14629) + S(11580)*x)*sqrt(S(3) + S(5)*x) + S(1695309)/S(3200000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(3)/S(2))*(S(2) + S(3)*x)**S(2)/sqrt(S(3) + S(5)*x), x, S(6), S(109263)/S(32000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(301)/S(3200)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) - S(119)/S(800)*(S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x) - S(3)/S(40)*(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)*sqrt(S(3) + S(5)*x) + S(9933)/S(32000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x), x, S(8), - S(3)/S(70)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(2) + S(3)*x)**S(2)*(S(3) + S(5)*x)**(S(3)/S(2)) - S(3)/S(280000)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(3) + S(5)*x)**(S(3)/S(2))*(S(33857) + S(26700)*x) + S(3735929329)/S(256000000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(30875449)/S(76800000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) + S(2806859)/S(19200000)*(S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x) - S(255169)/S(640000)*(S(1) - S(2)*x)**(S(7)/S(2))*sqrt(S(3) + S(5)*x) + S(339629939)/S(256000000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x), x, S(8), - S(193)/S(2000)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(3) + S(5)*x)**(S(3)/S(2)) - S(1)/S(20)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(2) + S(3)*x)*(S(3) + S(5)*x)**(S(3)/S(2)) + S(105254149)/S(12800000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(869869)/S(3840000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) + S(79079)/S(960000)*(S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x) - S(7189)/S(32000)*(S(1) - S(2)*x)**(S(7)/S(2))*sqrt(S(3) + S(5)*x) + S(9568559)/S(12800000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(4)/sqrt(S(3) + S(5)*x), x, S(8), S(12679836719)/S(1280000000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(104792039)/S(384000000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) + S(9526549)/S(96000000)*(S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x) - S(271)/S(2800)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x) - S(3)/S(70)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x) - S(1)/S(22400000)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(12923401) + S(11603280)*x)*sqrt(S(3) + S(5)*x) + S(1152712429)/S(1280000000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(1) - S(2)*x)**(S(5)/S(2))*(S(2) + S(3)*x)**S(3)/sqrt(S(3) + S(5)*x), x, S(7), S(368012183)/S(64000000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(3041423)/S(19200000)*(S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x) + S(276493)/S(4800000)*(S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x) - S(1)/S(20)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x) - S(1)/S(160000)*(S(1) - S(2)*x)**(S(7)/S(2))*(S(52951) + S(47280)*x)*sqrt(S(3) + S(5)*x) + S(33455653)/S(64000000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(4)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x), x, S(6), S(1067352517)/S(2560000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(987)/S(4000)*(S(2) + S(3)*x)**S(2)*(S(3) + S(5)*x)**(S(3)/S(2))*sqrt(S(1) - S(2)*x) - S(3)/S(50)*(S(2) + S(3)*x)**S(3)*(S(3) + S(5)*x)**(S(3)/S(2))*sqrt(S(1) - S(2)*x) - S(21)/S(640000)*(S(3) + S(5)*x)**(S(3)/S(2))*(S(194923) + S(92040)*x)*sqrt(S(1) - S(2)*x) - S(97032047)/S(2560000)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x), x, S(5), S(677017)/S(5120)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(3)/S(40)*(S(2) + S(3)*x)**S(2)*(S(3) + S(5)*x)**(S(3)/S(2))*sqrt(S(1) - S(2)*x) - S(3)/S(1280)*(S(3) + S(5)*x)**(S(3)/S(2))*(S(865) + S(408)*x)*sqrt(S(1) - S(2)*x) - S(61547)/S(5120)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(4)/(sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)), x, S(5), S(10866247)/S(128000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(259)/S(800)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) - S(3)/S(40)*(S(2) + S(3)*x)**S(3)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) - S(7)/S(128000)*(S(187559) + S(77820)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(3)/(sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)), x, S(4), S(44437)/S(1600)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) - S(1)/S(10)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) - S(1)/S(1600)*(S(5363) + S(2220)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(5)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)), x, S(7), - S(35439958001)/S(5120000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + (S(2) + S(3)*x)**S(5)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) + S(847637)/S(32000)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(10389)/S(1600)*(S(2) + S(3)*x)**S(3)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(33)/S(20)*(S(2) + S(3)*x)**S(4)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(49)/S(5120000)*(S(87394471) + S(36265980)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(4)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)), x, S(6), - S(92108287)/S(51200)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + (S(2) + S(3)*x)**S(4)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) + S(2203)/S(320)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(27)/S(16)*(S(2) + S(3)*x)**S(3)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(1)/S(51200)*(S(11129753) + S(4618500)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(5)/((S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x)), x, S(6), - S(291096141)/S(256000)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(7)/S(11)*(S(2) + S(3)*x)**S(4)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) + S(76587)/S(17600)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(939)/S(880)*(S(2) + S(3)*x)**S(3)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(21)/S(2816000)*(S(18424549) + S(7645620)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(4)/((S(1) - S(2)*x)**(S(3)/S(2))*sqrt(S(3) + S(5)*x)), x, S(5), - S(184641)/S(640)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(7)/S(11)*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) + S(243)/S(220)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) + S(9)/S(7040)*(S(27269) + S(11316)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(4)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(5)/S(2)), x, S(6), S(13246251)/S(6400)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(1)/S(3)*(S(2) + S(3)*x)**S(4)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)) - S(299)/S(66)*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) - S(697)/S(88)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) - S(1)/S(70400)*(S(17606479) + S(7306140)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(5)/S(2)), x, S(5), S(126513)/S(320)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(1)/S(3)*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)) - S(233)/S(66)*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) - S(1)/S(3520)*(S(168157) + S(69780)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(5)/((S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x)), x, S(6), S(8261577)/S(6400)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(7)/S(33)*(S(2) + S(3)*x)**S(4)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)) - S(2051)/S(726)*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) - S(23909)/S(4840)*(S(2) + S(3)*x)**S(2)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x) - S(1)/S(774400)*(S(120791143) + S(50124540)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(S(2) + S(3)*x)**S(4)/((S(1) - S(2)*x)**(S(5)/S(2))*sqrt(S(3) + S(5)*x)), x, S(5), S(392283)/S(1600)*arcsin(sqrt(S(2)/S(11))*sqrt(S(3) + S(5)*x))/sqrt(S(10)) + S(7)/S(33)*(S(2) + S(3)*x)**S(3)*sqrt(S(3) + S(5)*x)/(S(1) - S(2)*x)**(S(3)/S(2)) - S(1589)/S(726)*(S(2) + S(3)*x)**S(2)*sqrt(S(3) + S(5)*x)/sqrt(S(1) - S(2)*x) - S(1)/S(193600)*(S(5735477) + S(2380020)*x)*sqrt(S(1) - S(2)*x)*sqrt(S(3) + S(5)*x)], [(c + d*x)**(S(1)/S(2))/(x**S(2)*(a + b*x)**S(2)), x, S(7), (S(4)*b*c - a*d)*arctanh(sqrt(c + d*x)/sqrt(c))/(a**S(3)*sqrt(c)) - (S(4)*b*c - S(3)*a*d)*arctanh(sqrt(b)*sqrt(c + d*x)/sqrt(b*c - a*d))*sqrt(b)/(a**S(3)*sqrt(b*c - a*d)) - S(2)*b*sqrt(c + d*x)/(a**S(2)*(a + b*x)) - sqrt(c + d*x)/(a*x*(a + b*x))], [S(1)/(x**S(2)*(a + b*x)**S(2)*(c + d*x)**(S(1)/S(2))), x, S(7), (S(4)*b*c + a*d)*arctanh(sqrt(c + d*x)/sqrt(c))/(a**S(3)*c**(S(3)/S(2))) - b**(S(3)/S(2))*(S(4)*b*c - S(5)*a*d)*arctanh(sqrt(b)*sqrt(c + d*x)/sqrt(b*c - a*d))/(a**S(3)*(b*c - a*d)**(S(3)/S(2))) - b*(S(2)*b*c - a*d)*sqrt(c + d*x)/(a**S(2)*c*(b*c - a*d)*(a + b*x)) - sqrt(c + d*x)/(a*c*x*(a + b*x))], [S(1)/(x**S(2)*(a + b*x)**S(2)*(c + d*x)**(S(3)/S(2))), x, S(8), (S(4)*b*c + S(3)*a*d)*arctanh(sqrt(c + d*x)/sqrt(c))/(a**S(3)*c**(S(5)/S(2))) - b**(S(5)/S(2))*(S(4)*b*c - S(7)*a*d)*arctanh(sqrt(b)*sqrt(c + d*x)/sqrt(b*c - a*d))/(a**S(3)*(b*c - a*d)**(S(5)/S(2))) - d*(S(2)*b**S(2)*c**S(2) - S(2)*a*b*c*d + S(3)*a**S(2)*d**S(2))/(a**S(2)*c**S(2)*(b*c - a*d)**S(2)*sqrt(c + d*x)) - b*(S(2)*b*c - a*d)/(a**S(2)*c*(b*c - a*d)*(a + b*x)*sqrt(c + d*x)) + ( - S(1))/(a*c*x*(a + b*x)*sqrt(c + d*x))], [x**S(3)*(c + d*x)**(S(3)/S(2))/(a + b*x)**(S(3)/S(2)), x, S(6), S(3)/S(64)*(b*c - a*d)*(b**S(3)*c**S(3) + S(5)*a*b**S(2)*c**S(2)*d + S(35)*a**S(2)*b*c*d**S(2) - S(105)*a**S(3)*d**S(3))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(11)/S(2))*d**(S(5)/S(2))) - S(2)*x**S(3)*(c + d*x)**(S(3)/S(2))/(b*sqrt(a + b*x)) + S(9)/S(4)*x**S(2)*(c + d*x)**(S(3)/S(2))*sqrt(a + b*x)/b**S(2) - S(1)/S(32)*(c + d*x)**(S(3)/S(2))*(S(3)*b**S(2)*c**S(2) + S(14)*a*b*c*d - S(105)*a**S(2)*d**S(2) - S(4)*b*d*(b*c - S(21)*a*d)*x)*sqrt(a + b*x)/(b**S(4)*d**S(2)) + S(3)/S(64)*(b**S(3)*c**S(3) + S(5)*a*b**S(2)*c**S(2)*d + S(35)*a**S(2)*b*c*d**S(2) - S(105)*a**S(3)*d**S(3))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(5)*d**S(2))], [x**S(2)*(c + d*x)**(S(3)/S(2))/(a + b*x)**(S(3)/S(2)), x, S(6), - S(1)/S(8)*(b*c - a*d)*(b**S(2)*c**S(2) + S(10)*a*b*c*d - S(35)*a**S(2)*d**S(2))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(9)/S(2))*d**(S(3)/S(2))) - S(2)*a**S(2)*(c + d*x)**(S(5)/S(2))/(b**S(2)*(b*c - a*d)*sqrt(a + b*x)) - S(1)/S(12)*(S(10)*a*c + b*c**S(2)/d - S(35)*a**S(2)*d/b)*(c + d*x)**(S(3)/S(2))*sqrt(a + b*x)/(b**S(2)*(b*c - a*d)) + S(1)/S(3)*(c + d*x)**(S(5)/S(2))*sqrt(a + b*x)/(b**S(2)*d) - S(1)/S(8)*(b**S(2)*c**S(2) + S(10)*a*b*c*d - S(35)*a**S(2)*d**S(2))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(4)*d)], [x**S(3)*(c + d*x)**(S(5)/S(2))/(a + b*x)**(S(5)/S(2)), x, S(7), - S(2)/S(3)*x**S(3)*(c + d*x)**(S(5)/S(2))/(b*(a + b*x)**(S(3)/S(2))) - S(5)/S(64)*(b*c - a*d)*(b**S(3)*c**S(3) + S(21)*a*b**S(2)*c**S(2)*d - S(189)*a**S(2)*b*c*d**S(2) + S(231)*a**S(3)*d**S(3))*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(13)/S(2))*d**(S(3)/S(2))) - S(2)/S(3)*(S(6)*b*c - S(11)*a*d)*x**S(2)*(c + d*x)**(S(5)/S(2))/(b**S(2)*(b*c - a*d)*sqrt(a + b*x)) - S(5)/S(96)*(b**S(3)*c**S(3) + S(21)*a*b**S(2)*c**S(2)*d - S(189)*a**S(2)*b*c*d**S(2) + S(231)*a**S(3)*d**S(3))*(c + d*x)**(S(3)/S(2))*sqrt(a + b*x)/(b**S(5)*d*(b*c - a*d)) + S(1)/S(24)*(c + d*x)**(S(5)/S(2))*(S(5)*b**S(2)*c**S(2) - S(156)*a*b*c*d + S(231)*a**S(2)*d**S(2) + S(2)*b*d*(S(59)*b*c - S(99)*a*d)*x)*sqrt(a + b*x)/(b**S(4)*d*(b*c - a*d)) - S(5)/S(64)*(b**S(3)*c**S(3) + S(21)*a*b**S(2)*c**S(2)*d - S(189)*a**S(2)*b*c*d**S(2) + S(231)*a**S(3)*d**S(3))*sqrt(a + b*x)*sqrt(c + d*x)/(b**S(6)*d)], [x**S(2)/((a + b*x)**(S(5)/S(2))*(c + d*x)**(S(1)/S(2))), x, S(4), S(2)*arctanh(sqrt(d)*sqrt(a + b*x)/(sqrt(b)*sqrt(c + d*x)))/(b**(S(5)/S(2))*sqrt(d)) - S(2)/S(3)*a**S(2)*sqrt(c + d*x)/(b**S(2)*(b*c - a*d)*(a + b*x)**(S(3)/S(2))) + S(4)/S(3)*a*(S(3)*b*c - S(2)*a*d)*sqrt(c + d*x)/(b**S(2)*(b*c - a*d)**S(2)*sqrt(a + b*x))], [x*sqrt(a + b*x)/sqrt( - a - b*x), x, S(2), S(1)/S(2)*x**S(2)*sqrt(a + b*x)/sqrt( - a - b*x)], [(c + d*x)**(S(3)/S(2))/(x*(a + b*x)**S(2)), x, S(6), - S(2)*c**(S(3)/S(2))*arctanh(sqrt(c + d*x)/sqrt(c))/a**S(2) + (S(2)*b*c + a*d)*arctanh(sqrt(b)*sqrt(c + d*x)/sqrt(b*c - a*d))*sqrt(b*c - a*d)/(a**S(2)*b**(S(3)/S(2))) + (b*c - a*d)*sqrt(c + d*x)/(a*b*(a + b*x))], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True, _numerical=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True, _numerical=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True, _numerical=True) def test_simplify(): test = [ [x**S(3)*(a + b*x)**S(2)*(c + d*x)**S(16), x, S(2), - S(1)/S(17)*c**S(3)*(b*c - a*d)**S(2)*(c + d*x)**S(17)/d**S(6) + S(1)/S(18)*c**S(2)*(S(5)*b*c - S(3)*a*d)*(b*c - a*d)*(c + d*x)**S(18)/d**S(6) - S(1)/S(19)*c*(S(10)*b**S(2)*c**S(2) - S(12)*a*b*c*d + S(3)*a**S(2)*d**S(2))*(c + d*x)**S(19)/d**S(6) + S(1)/S(20)*(S(10)*b**S(2)*c**S(2) - S(8)*a*b*c*d + a**S(2)*d**S(2))*(c + d*x)**S(20)/d**S(6) - S(1)/S(21)*b*(S(5)*b*c - S(2)*a*d)*(c + d*x)**S(21)/d**S(6) + S(1)/S(22)*b**S(2)*(c + d*x)**S(22)/d**S(6)], [x**S(5)/((a + b*x)**S(2)*(c + d*x)**S(2)), x, S(2), - S(2)*(b*c + a*d)*x/(b**S(3)*d**S(3)) + S(1)/S(2)*x**S(2)/(b**S(2)*d**S(2)) + a**S(5)/(b**S(4)*(b*c - a*d)**S(2)*(a + b*x)) + c**S(5)/(d**S(4)*(b*c - a*d)**S(2)*(c + d*x)) + a**S(4)*(S(5)*b*c - S(3)*a*d)*log(a + b*x)/(b**S(4)*(b*c - a*d)**S(3)) + c**S(4)*(S(3)*b*c - S(5)*a*d)*log(c + d*x)/(d**S(4)*(b*c - a*d)**S(3))], [x**S(5)/((a + b*x)**S(2)*(c + d*x)**S(2)), x, S(2), - S(2)*(b*c + a*d)*x/(b**S(3)*d**S(3)) + S(1)/S(2)*x**S(2)/(b**S(2)*d**S(2)) + a**S(5)/(b**S(4)*(b*c - a*d)**S(2)*(a + b*x)) + c**S(5)/(d**S(4)*(b*c - a*d)**S(2)*(c + d*x)) + a**S(4)*(S(5)*b*c - S(3)*a*d)*log(a + b*x)/(b**S(4)*(b*c - a*d)**S(3)) + c**S(4)*(S(3)*b*c - S(5)*a*d)*log(c + d*x)/(d**S(4)*(b*c - a*d)**S(3))], [x**S(4)/((a + b*x)*(c + d*x)), x, S(2), (b**S(2)*c**S(2) + a*b*c*d + a**S(2)*d**S(2))*x/(b**S(3)*d**S(3)) - S(1)/S(2)*(b*c + a*d)*x**S(2)/(b**S(2)*d**S(2)) + S(1)/S(3)*x**S(3)/(b*d) + a**S(4)*log(a + b*x)/(b**S(4)*(b*c - a*d)) - c**S(4)*log(c + d*x)/(d**S(4)*(b*c - a*d))], [(a + b*x)*(A + B*x)*(d + e*x)**S(4), x, S(2), S(1)/S(5)*(b*d - a*e)*(B*d - A*e)*(d + e*x)**S(5)/e**S(3) - S(1)/S(6)*(S(2)*b*B*d - A*b*e - a*B*e)*(d + e*x)**S(6)/e**S(3) + S(1)/S(7)*b*B*(d + e*x)**S(7)/e**S(3)], [(a + b*x)**S(3)*(c + d*x)**S(3)*(e + f*x)**S(3), x, S(2), S(1)/S(4)*(b*c - a*d)**S(3)*(b*e - a*f)**S(3)*(a + b*x)**S(4)/b**S(7) + S(3)/S(5)*(b*c - a*d)**S(2)*(b*e - a*f)**S(2)*(b*d*e + b*c*f - S(2)*a*d*f)*(a + b*x)**S(5)/b**S(7) + S(1)/S(2)*(b*c - a*d)*(b*e - a*f)*(S(5)*a**S(2)*d**S(2)*f**S(2) - S(5)*a*b*d*f*(d*e + c*f) + b**S(2)*(d**S(2)*e**S(2) + S(3)*c*d*e*f + c**S(2)*f**S(2)))*(a + b*x)**S(6)/b**S(7) + S(1)/S(7)*(b*d*e + b*c*f - S(2)*a*d*f)*(S(10)*a**S(2)*d**S(2)*f**S(2) - S(10)*a*b*d*f*(d*e + c*f) + b**S(2)*(d**S(2)*e**S(2) + S(8)*c*d*e*f + c**S(2)*f**S(2)))*(a + b*x)**S(7)/b**S(7) + S(3)/S(8)*d*f*(S(5)*a**S(2)*d**S(2)*f**S(2) - S(5)*a*b*d*f*(d*e + c*f) + b**S(2)*(d**S(2)*e**S(2) + S(3)*c*d*e*f + c**S(2)*f**S(2)))*(a + b*x)**S(8)/b**S(7) + S(1)/S(3)*d**S(2)*f**S(2)*(b*d*e + b*c*f - S(2)*a*d*f)*(a + b*x)**S(9)/b**S(7) + S(1)/S(10)*d**S(3)*f**S(3)*(a + b*x)**S(10)/b**S(7)], [(a + b*x)*(A + B*x)*(d + e*x)**(S(5)/S(2)), x, S(2), S(2)/S(7)*(b*d - a*e)*(B*d - A*e)*(d + e*x)**(S(7)/S(2))/e**S(3) - S(2)/S(9)*(S(2)*b*B*d - A*b*e - a*B*e)*(d + e*x)**(S(9)/S(2))/e**S(3) + S(2)/S(11)*b*B*(d + e*x)**(S(11)/S(2))/e**S(3)], [(S(5) - S(4)*x)**S(4)*(S(2) + S(3)*x)**m/(S(1) + S(2)*x)**m, x, S(4), - S(1)/S(45)*(S(88) - m)*(S(5) - S(4)*x)**S(2)*(S(1) + S(2)*x)**(S(1) - m)*(S(2) + S(3)*x)**(S(1) + m) - S(2)/S(15)*(S(5) - S(4)*x)**S(3)*(S(1) + S(2)*x)**(S(1) - m)*(S(2) + S(3)*x)**(S(1) + m) - S(1)/S(1215)*(S(1) + S(2)*x)**(S(1) - m)*(S(2) + S(3)*x)**(S(1) + m)*(S(386850) - S(25441)*m + S(426)*m**S(2) - S(2)*m**S(3) - S(24)*(S(4359) - S(154)*m + m**S(2))*x) + S(1)/S(1215)*S(2)**( - S(1) - m)*(S(3528363) - S(639760)*m + S(29050)*m**S(2) - S(440)*m**S(3) + S(2)*m**S(4))*(S(1) + S(2)*x)**(S(1) - m)*hypergeom([S(1) - m, - m], [S(2) - m], - S(3)*(S(1) + S(2)*x))/(S(1) - m)], [(S(5) - S(4)*x)**S(3)*(S(1) + S(2)*x)**( - S(1) - m)*(S(2) + S(3)*x)**m, x, S(3), - S(2)/S(9)*(S(5) - S(4)*x)**S(2)*(S(2) + S(3)*x)**(S(1) + m)/(S(1) + S(2)*x)**m - S(1)/S(27)*(S(2) + S(3)*x)**(S(1) + m)*(S(9261) - S(512)*m + S(4)*m**S(2) - S(4)*(S(109) - S(2)*m)*m*x)/(m*(S(1) + S(2)*x)**m) + S(1)/S(27)*S(2)**( - S(1) - m)*(S(27783) - S(8324)*m + S(390)*m**S(2) - S(4)*m**S(3))*(S(1) + S(2)*x)**(S(1) - m)*hypergeom([S(1) - m, - m], [S(2) - m], - S(3)*(S(1) + S(2)*x))/((S(1) - m)*m)], [(a + b*x)**m*(c + d*x)**n*((b*c*f + a*d*f + a*d*f*m + b*c*f*n)/(b*d*(S(2) + m + n)) + f*x)**( - S(3) - m - n), x, S(1), b*d*(S(2) + m + n)*(a + b*x)**(S(1) + m)*(c + d*x)**(S(1) + n)*(f*(a*d*(S(1) + m) + b*c*(S(1) + n))/(b*d*(S(2) + m + n)) + f*x)**( - S(2) - m - n)/((b*c - a*d)**S(2)*f*(S(1) + m)*(S(1) + n))], [x**S(3)*(c + d*x)**S(3)/(a + b*x)**S(3), x, S(2), (b*c - a*d)*(b**S(2)*c**S(2) - S(8)*a*b*c*d + S(10)*a**S(2)*d**S(2))*x/b**S(6) + S(3)/S(2)*d*(b*c - S(2)*a*d)*(b*c - a*d)*x**S(2)/b**S(5) + d**S(2)*(b*c - a*d)*x**S(3)/b**S(4) + S(1)/S(4)*d**S(3)*x**S(4)/b**S(3) + S(1)/S(2)*a**S(3)*(b*c - a*d)**S(3)/(b**S(7)*(a + b*x)**S(2)) - S(3)*a**S(2)*(b*c - S(2)*a*d)*(b*c - a*d)**S(2)/(b**S(7)*(a + b*x)) - S(3)*a*(b*c - a*d)*(b**S(2)*c**S(2) - S(5)*a*b*c*d + S(5)*a**S(2)*d**S(2))*log(a + b*x)/b**S(7)], [(S(2) + S(3)*x)**S(8)*(S(3) + S(5)*x)/(S(1) - S(2)*x)**S(3), x, S(2), S(63412811)/S(2048)/(S(1) - S(2)*x)**S(2) + ( - S(246239357)/S(1024))/(S(1) - S(2)*x) - S(120864213)/S(256)*x - S(118841283)/S(512)*x**S(2) - S(16042509)/S(128)*x**S(3) - S(7568235)/S(128)*x**S(4) - S(213597)/S(10)*x**S(5) - S(162567)/S(32)*x**S(6) - S(32805)/S(56)*x**S(7) - S(106237047)/S(256)*log(S(1) - S(2)*x)], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True) or rubi_test(r, i[1], i[4], expand=True) else: assert rubi_test(r, i[1], i[3], expand=True) def test_diff(): test = [ [(a + b*x)*(e + f*x)**(S(3)/S(2))/(c + d*x), x, S(5), - S(2)/S(3)*(b*c - a*d)*(e + f*x)**(S(3)/S(2))/d**S(2) + S(2)/S(5)*b*(e + f*x)**(S(5)/S(2))/(d*f) + S(2)*(b*c - a*d)*(d*e - c*f)**(S(3)/S(2))*arctanh(sqrt(d)*sqrt(e + f*x)/sqrt(d*e - c*f))/d**(S(7)/S(2)) - S(2)*(b*c - a*d)*(d*e - c*f)*sqrt(e + f*x)/d**S(3)], [x**(S(5)/S(2))*(A + B*x)/(a + b*x), x, S(6), - S(2)/S(3)*a*(A*b - a*B)*x**(S(3)/S(2))/b**S(3) + S(2)/S(5)*(A*b - a*B)*x**(S(5)/S(2))/b**S(2) + S(2)/S(7)*B*x**(S(7)/S(2))/b - S(2)*a**(S(5)/S(2))*(A*b - a*B)*arctan(sqrt(b)*sqrt(x)/sqrt(a))/b**(S(9)/S(2)) + S(2)*a**S(2)*(A*b - a*B)*sqrt(x)/b**S(4)], [(a + b*x)**S(2)/((c + d*x)**S(2)*sqrt(e + f*x)), x, S(4), (b*c - a*d)*(S(4)*b*d*e - S(3)*b*c*f - a*d*f)*arctanh(sqrt(d)*sqrt(e + f*x)/sqrt(d*e - c*f))/(d**(S(5)/S(2))*(d*e - c*f)**(S(3)/S(2))) + S(2)*b**S(2)*sqrt(e + f*x)/(d**S(2)*f) - (b*c - a*d)**S(2)*sqrt(e + f*x)/(d**S(2)*(d*e - c*f)*(c + d*x))], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_1_4.py000066400000000000000000000242721412543434000253650ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.rubi import rubi_integrate from sympy.functions import log, sqrt, exp, cos, sin, tan, sec, csc, cot from sympy.functions.elementary.hyperbolic import atanh as arctanh from sympy.functions.elementary.hyperbolic import asinh as arcsinh from sympy.functions.elementary.hyperbolic import acosh as arccosh from sympy.functions.elementary.trigonometric import atan as arctan from sympy.functions.elementary.trigonometric import asin as arcsin from sympy.functions.elementary.trigonometric import acos as arccos from sympy.integrals.rubi.utility_function import EllipticE, EllipticF, EllipticPi, hypergeom, rubi_test, AppellF1 from sympy import pi as Pi from sympy import S, hyper, I, simplify, exp_polar, symbols, Integral from sympy.testing.pytest import XFAIL A, B, C, D, a, b, c, d, e, f, g, h, i, m, n, p, x, u = symbols('A B C D a b c d e f g h i m n p x u') def test_1(): ''' Tests for Rubi Algebraic 1.2 rules. Parsed from Maple syntax All tests: http://www.apmaths.uwo.ca/~arich/IntegrationProblems/MapleSyntaxFiles/MapleSyntaxFiles.html Note: Some tests are commented since they depend rules other than Algebraic1.2. ''' test = [ [(a + b*x)**S(2)*(e + f*x)*sqrt(c + d*x)/x, x, S(5), S(2)/S(7)*f*(a + b*x)**S(2)*(c + d*x)**(S(3)/S(2))/d + S(2)/S(105)*(c + d*x)**(S(3)/S(2))*(S(2)*(S(10)*a**S(2)*d**S(2)*f - b**S(2)*c*(S(7)*d*e - S(4)*c*f) + S(7)*a*b*d*(S(5)*d*e - S(2)*c*f)) + S(3)*b*d*(S(7)*b*d*e - S(4)*b*c*f + S(4)*a*d*f)*x)/d**S(3) - S(2)*a**S(2)*e*arctanh(sqrt(c + d*x)/sqrt(c))*sqrt(c) + S(2)*a**S(2)*e*sqrt(c + d*x)], [(a + b*x)*(e + f*x)*sqrt(c + d*x)/x, x, S(4), - S(2)/S(15)*(c + d*x)**(S(3)/S(2))*(S(2)*b*c*f - S(5)*d*(b*e + a*f) - S(3)*b*d*f*x)/d**S(2) - S(2)*a*e*arctanh(sqrt(c + d*x)/sqrt(c))*sqrt(c) + S(2)*a*e*sqrt(c + d*x)], [(c + d*x)**S(2)*(e + f*x)*sqrt(a + b*x)/x, x, S(5), S(2)/S(7)*f*(a + b*x)**(S(3)/S(2))*(c + d*x)**S(2)/b + S(2)/S(105)*(a + b*x)**(S(3)/S(2))*(S(2)*(S(4)*a**S(2)*d**S(2)*f - S(7)*a*b*d*(d*e + S(2)*c*f) + S(5)*b**S(2)*c*(S(7)*d*e + S(2)*c*f)) + S(3)*b*d*(S(7)*b*d*e + S(4)*b*c*f - S(4)*a*d*f)*x)/b**S(3) - S(2)*c**S(2)*e*arctanh(sqrt(a + b*x)/sqrt(a))*sqrt(a) + S(2)*c**S(2)*e*sqrt(a + b*x)], [(c + d*x)*(e + f*x)*sqrt(a + b*x)/x, x, S(4), - S(2)/S(15)*(a + b*x)**(S(3)/S(2))*(S(2)*a*d*f - S(5)*b*(d*e + c*f) - S(3)*b*d*f*x)/b**S(2) - S(2)*c*e*arctanh(sqrt(a + b*x)/sqrt(a))*sqrt(a) + S(2)*c*e*sqrt(a + b*x)], [x**S(4)*(e + f*x)**n/((a + b*x)*(c + d*x)), x, S(8), e**S(2)*(e + f*x)**(S(1) + n)/(b*d*f**S(3)*(S(1) + n)) + (b*c + a*d)*e*(e + f*x)**(S(1) + n)/(b**S(2)*d**S(2)*f**S(2)*(S(1) + n)) + (b**S(2)*c**S(2) + a*b*c*d + a**S(2)*d**S(2))*(e + f*x)**(S(1) + n)/(b**S(3)*d**S(3)*f*(S(1) + n)) - S(2)*e*(e + f*x)**(S(2) + n)/(b*d*f**S(3)*(S(2) + n)) - (b*c + a*d)*(e + f*x)**(S(2) + n)/(b**S(2)*d**S(2)*f**S(2)*(S(2) + n)) + (e + f*x)**(S(3) + n)/(b*d*f**S(3)*(S(3) + n)) - a**S(4)*(e + f*x)**(S(1) + n)*hypergeom([S(1), S(1) + n], [S(2) + n], b*(e + f*x)/(b*e - a*f))/(b**S(3)*(b*c - a*d)*(b*e - a*f)*(S(1) + n)) + c**S(4)*(e + f*x)**(S(1) + n)*hypergeom([S(1), S(1) + n], [S(2) + n], d*(e + f*x)/(d*e - c*f))/(d**S(3)*(b*c - a*d)*(d*e - c*f)*(S(1) + n))], [(a + b*x)*(c + d*x)*(e + f*x)*(g + h*x), x, S(2), a*c*e*g*x + S(1)/S(2)*(b*c*e*g + a*(d*e*g + c*f*g + c*e*h))*x**S(2) + S(1)/S(3)*(b*(d*e*g + c*f*g + c*e*h) + a*(d*f*g + d*e*h + c*f*h))*x**S(3) + S(1)/S(4)*(a*d*f*h + b*(d*f*g + d*e*h + c*f*h))*x**S(4) + S(1)/S(5)*b*d*f*h*x**S(5)], [(a + b*x)*(c + d*x)*(e + f*x)/(g + h*x), x, S(2), (b*(d*g - c*h)*(f*g - e*h) - a*h*(d*f*g - d*e*h - c*f*h))*x/h**S(3) + S(1)/S(2)*(a*d*f*h - b*(d*f*g - d*e*h - c*f*h))*x**S(2)/h**S(2) + S(1)/S(3)*b*d*f*x**S(3)/h - (b*g - a*h)*(d*g - c*h)*(f*g - e*h)*log(g + h*x)/h**S(4)], [(a + b*x)**m*(c + d*x)*(e + f*x)*(g + h*x), x, S(2), (b*c - a*d)*(b*e - a*f)*(b*g - a*h)*(a + b*x)**(S(1) + m)/(b**S(4)*(S(1) + m)) + (S(3)*a**S(2)*d*f*h + b**S(2)*(d*e*g + c*f*g + c*e*h) - S(2)*a*b*(d*f*g + d*e*h + c*f*h))*(a + b*x)**(S(2) + m)/(b**S(4)*(S(2) + m)) - (S(3)*a*d*f*h - b*(d*f*g + d*e*h + c*f*h))*(a + b*x)**(S(3) + m)/(b**S(4)*(S(3) + m)) + d*f*h*(a + b*x)**(S(4) + m)/(b**S(4)*(S(4) + m))], [(c + d*x)**( - S(4) - m)*(e + f*x)**m*(g + h*x), x, S(3), - (d*g - c*h)*(c + d*x)**( - S(3) - m)*(e + f*x)**(S(1) + m)/(d*(d*e - c*f)*(S(3) + m)) + (c*f*h*(S(1) + m) + d*(S(2)*f*g - e*h*(S(3) + m)))*(c + d*x)**( - S(2) - m)*(e + f*x)**(S(1) + m)/(d*(d*e - c*f)**S(2)*(S(2) + m)*(S(3) + m)) - f*(c*f*h*(S(1) + m) + d*(S(2)*f*g - e*h*(S(3) + m)))*(c + d*x)**( - S(1) - m)*(e + f*x)**(S(1) + m)/(d*(d*e - c*f)**S(3)*(S(1) + m)*(S(2) + m)*(S(3) + m))], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True) @XFAIL def test_2(): test = [ [x**m*(e + f*x)**n/((a + b*x)*(c + d*x)), x, S(6), b*x**(S(1) + m)*(e + f*x)**n*AppellF1(S(1) + m, - n, S(1), S(2) + m, - f*x/e, - b*x/a)/(a*(b*c - a*d)*(S(1) + m)*(S(1) + f*x/e)**n) - d*x**(S(1) + m)*(e + f*x)**n*AppellF1(S(1) + m, - n, S(1), S(2) + m, - f*x/e, - d*x/c)/(c*(b*c - a*d)*(S(1) + m)*(S(1) + f*x/e)**n)], [(a + b*x)**m*(c + d*x)**n*(e + f*x)*(g + h*x), x, S(3), - (a + b*x)**(S(1) + m)*(c + d*x)**(S(1) + n)*(b*c*f*h*(S(2) + m) + a*d*f*h*(S(2) + n) - b*d*(f*g + e*h)*(S(3) + m + n) - b*d*f*h*(S(2) + m + n)*x)/(b**S(2)*d**S(2)*(S(2) + m + n)*(S(3) + m + n)) + (a**S(2)*d**S(2)*f*h*(S(1) + n)*(S(2) + n) + a*b*d*(S(1) + n)*(S(2)*c*f*h*(S(1) + m) - d*(f*g + e*h)*(S(3) + m + n)) + b**S(2)*(c**S(2)*f*h*(S(1) + m)*(S(2) + m) - c*d*(f*g + e*h)*(S(1) + m)*(S(3) + m + n) + d**S(2)*e*g*(S(2) + m + n)*(S(3) + m + n)))*(a + b*x)**(S(1) + m)*(c + d*x)**n*hypergeom([S(1) + m, - n], [S(2) + m], - d*(a + b*x)/(b*c - a*d))/(b**S(3)*d**S(2)*(S(1) + m)*(S(2) + m + n)*(S(3) + m + n)*(b*(c + d*x)/(b*c - a*d))**n)], [(a + b*x)**m*(A + B*x)*(c + d*x)**n*(e + f*x)**p, x, S(7), (A*b - a*B)*(a + b*x)**(S(1) + m)*(c + d*x)**n*(e + f*x)**p*AppellF1(S(1) + m, - n, - p, S(2) + m, - d*(a + b*x)/(b*c - a*d), - f*(a + b*x)/(b*e - a*f))/(b**S(2)*(S(1) + m)*(b*(c + d*x)/(b*c - a*d))**n*(b*(e + f*x)/(b*e - a*f))**p) + B*(a + b*x)**(S(2) + m)*(c + d*x)**n*(e + f*x)**p*AppellF1(S(2) + m, - n, - p, S(3) + m, - d*(a + b*x)/(b*c - a*d), - f*(a + b*x)/(b*e - a*f))/(b**S(2)*(S(2) + m)*(b*(c + d*x)/(b*c - a*d))**n*(b*(e + f*x)/(b*e - a*f))**p)], [(A + B*x)*(c + d*x)**n*(e + f*x)**p/(a + b*x), x, S(5), - (A*b - a*B)*(c + d*x)**(S(1) + n)*(e + f*x)**p*AppellF1(S(1) + n, S(1), - p, S(2) + n, b*(c + d*x)/(b*c - a*d), - f*(c + d*x)/(d*e - c*f))/(b*(b*c - a*d)*(S(1) + n)*(d*(e + f*x)/(d*e - c*f))**p) - B*(c + d*x)**(S(1) + n)*(e + f*x)**(S(1) + p)*hypergeom([S(1), S(2) + n + p], [S(2) + p], d*(e + f*x)/(d*e - c*f))/(b*(d*e - c*f)*(S(1) + p)), - (A*b - a*B)*(c + d*x)**(S(1) + n)*(e + f*x)**p*AppellF1(S(1) + n, - p, S(1), S(2) + n, - f*(c + d*x)/(d*e - c*f), b*(c + d*x)/(b*c - a*d))/(b*(b*c - a*d)*(S(1) + n)*(d*(e + f*x)/(d*e - c*f))**p) + B*(c + d*x)**(S(1) + n)*(e + f*x)**p*hypergeom([S(1) + n, - p], [S(2) + n], - f*(c + d*x)/(d*e - c*f))/(b*d*(S(1) + n)*(d*(e + f*x)/(d*e - c*f))**p)], [(c*i + d*i*x)/(sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x, S(3), S(2)*i*EllipticE(sqrt(h)*sqrt(e + f*x)/sqrt( - f*g + e*h), sqrt( - d*(f*g - e*h)/((d*e - c*f)*h)))*sqrt( - f*g + e*h)*sqrt(c + d*x)*sqrt(f*(g + h*x)/(f*g - e*h))/(f*sqrt(h)*sqrt( - f*(c + d*x)/(d*e - c*f))*sqrt(g + h*x))], [(a + b*x)**m*(c + d*x)**n*(e + f*x)**p, x, S(3), (a + b*x)**(S(1) + m)*(c + d*x)**n*(e + f*x)**p*AppellF1(S(1) + m, - n, - p, S(2) + m, - d*(a + b*x)/(b*c - a*d), - f*(a + b*x)/(b*e - a*f))/(b*(S(1) + m)*(b*(c + d*x)/(b*c - a*d))**n*(b*(e + f*x)/(b*e - a*f))**p)], [(a + b*x)**m*(c + d*x)**n*(e + f*x)**p/(g + h*x), x, S(0), Integral((a + b*x)**m*(c + d*x)**n*(e + f*x)**p/(g + h*x), x)], [x**S(3)*(S(1) + a*x)/(sqrt(a*x)*sqrt(S(1) - a*x)), x, S(8), - S(75)/S(128)*arcsin(S(1) - S(2)*a*x)/a**S(4) - S(25)/S(32)*(a*x)**(S(3)/S(2))*sqrt(S(1) - a*x)/a**S(4) - S(5)/S(8)*(a*x)**(S(5)/S(2))*sqrt(S(1) - a*x)/a**S(4) - S(1)/S(4)*(a*x)**(S(7)/S(2))*sqrt(S(1) - a*x)/a**S(4) - S(75)/S(64)*sqrt(a*x)*sqrt(S(1) - a*x)/a**S(4)], ] for index in test: r = rubi_integrate(index[0], index[1]) if len(index) == 5: assert rubi_test(r, index[1], index[3], expand=True, _diff=True) or rubi_test(r, index[1], index[4], expand=True, _diff=True) else: assert rubi_test(r, index[1], index[3], expand=True, _diff=True) @XFAIL def test_numerical(): test = [ #[S(1)/((a + b*x)*sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x, S(1), - S(2)*EllipticPi(sqrt( - f/(d*e - c*f))*sqrt(c + d*x), - b*(d*e - c*f)/((b*c - a*d)*f), sqrt((d*e - c*f)*h/(f*(d*g - c*h))))*sqrt(d*(e + f*x)/(d*e - c*f))*sqrt(d*(g + h*x)/(d*g - c*h))/((b*c - a*d)*sqrt( - f/(d*e - c*f))*sqrt(e + f*x)*sqrt(g + h*x))], #[S(1)/(sqrt(a + b*x)*sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x, S(2), - S(2)*(a + b*x)*sqrt(cos(arctan(sqrt(b*e - a*f)*sqrt(g + h*x)/(sqrt(f*g - e*h)*sqrt(a + b*x))))**S(2))/cos(arctan(sqrt(b*e - a*f)*sqrt(g + h*x)/(sqrt(f*g - e*h)*sqrt(a + b*x))))*EllipticF(sin(arctan(sqrt(b*e - a*f)*sqrt(g + h*x)/(sqrt(f*g - e*h)*sqrt(a + b*x)))), sqrt((d*e - c*f)*(b*g - a*h)/((b*e - a*f)*(d*g - c*h))))*sqrt(f*g - e*h)*sqrt((b*g - a*h)*(c + d*x)/((d*g - c*h)*(a + b*x)))*sqrt((b*g - a*h)*(e + f*x)/((f*g - e*h)*(a + b*x)))*sqrt(S(1) + (b*c - a*d)*(g + h*x)/((d*g - c*h)*(a + b*x)))/((b*g - a*h)*sqrt(b*e - a*f)*sqrt(c + d*x)*sqrt(e + f*x)*sqrt((S(1) + (b*c - a*d)*(g + h*x)/((d*g - c*h)*(a + b*x)))/(S(1) + (b*e - a*f)*(g + h*x)/((f*g - e*h)*(a + b*x))))*sqrt(S(1) + (b*e - a*f)*(g + h*x)/((f*g - e*h)*(a + b*x))))], ] for i in test: r = rubi_integrate(i[0], i[1]) if len(i) == 5: assert rubi_test(r, i[1], i[3], expand=True, _diff=True, _numerical=True) or rubi_test(r, i[1], i[4], expand=True, _diff=True, _numerical=True) else: assert rubi_test(r, i[1], i[3], expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_exponential.py000066400000000000000000007521161412543434000273350ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.rubi import rubi_integrate from sympy.functions import log, sqrt, exp, cos, sin, tan, sec, csc, cot, sinh, sech, atan, asin, acos, atanh, asinh, acosh from sympy import acsch as arccsch, acsc as arccsc from sympy.integrals.rubi.utility_function import (EllipticE, EllipticF, Int, ArcCsch, ArcCsc, Gamma, hypergeom, rubi_test, AppellF1, EllipticPi, Log, Sqrt, ArcTan, ArcTanh, ArcSin, ArcSinh, ArcCosh, ArcTanh, ArcCos, Hypergeometric2F1) from sympy import pi from sympy import S, hyper, I, simplify, exp_polar, symbols, Ei,erf, erfi,gamma,uppergamma, polylog, Integral, exp from sympy.testing.pytest import SKIP a, b, c, d, e, f, m, n, x, u , k, p, r, s, t= symbols('a b c d e f m n x u k p r s t') A, B, C, D, a, b, c, d, e, f, g, h, i, y, z, m, n, p, q, u, v, w, E, F, G, H = symbols('A B C D a b c d e f g h i y z m n p q u v w E F G H') def test_1(): assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**m, x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(-m)*(d + e*x)**m*Gamma(m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**S(4), x), x, F**(c*(a + b*x))*(d + e*x)**S(4)/(b*c*log(F)) - S(4)*F**(c*(a + b*x))*e*(d + e*x)**S(3)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(12)*F**(c*(a + b*x))*e**S(2)*(d + e*x)**S(2)/(b**S(3)*c**S(3)*log(F)**S(3)) - S(24)*F**(c*(a + b*x))*e**S(3)*(d + e*x)/(b**S(4)*c**S(4)*log(F)**S(4)) + S(24)*F**(c*(a + b*x))*e**S(4)/(b**S(5)*c**S(5)*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**S(3), x), x, F**(c*(a + b*x))*(d + e*x)**S(3)/(b*c*log(F)) - S(3)*F**(c*(a + b*x))*e*(d + e*x)**S(2)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(6)*F**(c*(a + b*x))*e**S(2)*(d + e*x)/(b**S(3)*c**S(3)*log(F)**S(3)) - S(6)*F**(c*(a + b*x))*e**S(3)/(b**S(4)*c**S(4)*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**S(2), x), x, F**(c*(a + b*x))*(d + e*x)**S(2)/(b*c*log(F)) - S(2)*F**(c*(a + b*x))*e*(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(2)*F**(c*(a + b*x))*e**S(2)/(b**S(3)*c**S(3)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x), x), x, F**(c*(a + b*x))*(d + e*x)/(b*c*log(F)) - F**(c*(a + b*x))*e/(b**S(2)*c**S(2)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x)), x), x, F**(c*(a + b*x))/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x), x), x, F**(c*(a - b*d/e))*Ei(b*c*(d + e*x)*log(F)/e)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**S(2), x), x, -F**(c*(a + b*x))/(e*(d + e*x)) + F**(c*(a - b*d/e))*b*c*log(F)*Ei(b*c*(d + e*x)*log(F)/e)/e**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**S(3), x), x, -F**(c*(a + b*x))*b*c*log(F)/(S(2)*e**S(2)*(d + e*x)) - F**(c*(a + b*x))/(S(2)*e*(d + e*x)**S(2)) + F**(c*(a - b*d/e))*b**S(2)*c**S(2)*log(F)**S(2)*Ei(b*c*(d + e*x)*log(F)/e)/(S(2)*e**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**S(4), x), x, -F**(c*(a + b*x))*b**S(2)*c**S(2)*log(F)**S(2)/(S(6)*e**S(3)*(d + e*x)) - F**(c*(a + b*x))*b*c*log(F)/(S(6)*e**S(2)*(d + e*x)**S(2)) - F**(c*(a + b*x))/(S(3)*e*(d + e*x)**S(3)) + F**(c*(a - b*d/e))*b**S(3)*c**S(3)*log(F)**S(3)*Ei(b*c*(d + e*x)*log(F)/e)/(S(6)*e**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**S(5), x), x, -F**(c*(a + b*x))*b**S(3)*c**S(3)*log(F)**S(3)/(S(24)*e**S(4)*(d + e*x)) - F**(c*(a + b*x))*b**S(2)*c**S(2)*log(F)**S(2)/(S(24)*e**S(3)*(d + e*x)**S(2)) - F**(c*(a + b*x))*b*c*log(F)/(S(12)*e**S(2)*(d + e*x)**S(3)) - F**(c*(a + b*x))/(S(4)*e*(d + e*x)**S(4)) + F**(c*(a - b*d/e))*b**S(4)*c**S(4)*log(F)**S(4)*Ei(b*c*(d + e*x)*log(F)/e)/(S(24)*e**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(4) + S(4)*d**S(3)*e*x + S(6)*d**S(2)*e**S(2)*x**S(2) + S(4)*d*e**S(3)*x**S(3) + e**S(4)*x**S(4)), x), x, F**(c*(a + b*x))*(d + e*x)**S(4)/(b*c*log(F)) - S(4)*F**(c*(a + b*x))*e*(d + e*x)**S(3)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(12)*F**(c*(a + b*x))*e**S(2)*(d + e*x)**S(2)/(b**S(3)*c**S(3)*log(F)**S(3)) - S(24)*F**(c*(a + b*x))*e**S(3)*(d + e*x)/(b**S(4)*c**S(4)*log(F)**S(4)) + S(24)*F**(c*(a + b*x))*e**S(4)/(b**S(5)*c**S(5)*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(3) + S(3)*d**S(2)*e*x + S(3)*d*e**S(2)*x**S(2) + e**S(3)*x**S(3)), x), x, F**(c*(a + b*x))*(d + e*x)**S(3)/(b*c*log(F)) - S(3)*F**(c*(a + b*x))*e*(d + e*x)**S(2)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(6)*F**(c*(a + b*x))*e**S(2)*(d + e*x)/(b**S(3)*c**S(3)*log(F)**S(3)) - S(6)*F**(c*(a + b*x))*e**S(3)/(b**S(4)*c**S(4)*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(2) + S(2)*d*e*x + e**S(2)*x**S(2)), x), x, F**(c*(a + b*x))*(d + e*x)**S(2)/(b*c*log(F)) - S(2)*F**(c*(a + b*x))*e*(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(2)*F**(c*(a + b*x))*e**S(2)/(b**S(3)*c**S(3)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d**S(2) + S(2)*d*e*x + e**S(2)*x**S(2)), x), x, -F**(c*(a + b*x))/(e*(d + e*x)) + F**(c*(a - b*d/e))*b*c*log(F)*Ei(b*c*(d + e*x)*log(F)/e)/e**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d**S(3) + S(3)*d**S(2)*e*x + S(3)*d*e**S(2)*x**S(2) + e**S(3)*x**S(3)), x), x, -F**(c*(a + b*x))*b*c*log(F)/(S(2)*e**S(2)*(d + e*x)) - F**(c*(a + b*x))/(S(2)*e*(d + e*x)**S(2)) + F**(c*(a - b*d/e))*b**S(2)*c**S(2)*log(F)**S(2)*Ei(b*c*(d + e*x)*log(F)/e)/(S(2)*e**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d**S(4) + S(4)*d**S(3)*e*x + S(6)*d**S(2)*e**S(2)*x**S(2) + S(4)*d*e**S(3)*x**S(3) + e**S(4)*x**S(4)), x), x, -F**(c*(a + b*x))*b**S(2)*c**S(2)*log(F)**S(2)/(S(6)*e**S(3)*(d + e*x)) - F**(c*(a + b*x))*b*c*log(F)/(S(6)*e**S(2)*(d + e*x)**S(2)) - F**(c*(a + b*x))/(S(3)*e*(d + e*x)**S(3)) + F**(c*(a - b*d/e))*b**S(3)*c**S(3)*log(F)**S(3)*Ei(b*c*(d + e*x)*log(F)/e)/(S(6)*e**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d**S(5) + S(5)*d**S(4)*e*x + S(10)*d**S(3)*e**S(2)*x**S(2) + S(10)*d**S(2)*e**S(3)*x**S(3) + S(5)*d*e**S(4)*x**S(4) + e**S(5)*x**S(5)), x), x, -F**(c*(a + b*x))*b**S(3)*c**S(3)*log(F)**S(3)/(S(24)*e**S(4)*(d + e*x)) - F**(c*(a + b*x))*b**S(2)*c**S(2)*log(F)**S(2)/(S(24)*e**S(3)*(d + e*x)**S(2)) - F**(c*(a + b*x))*b*c*log(F)/(S(12)*e**S(2)*(d + e*x)**S(3)) - F**(c*(a + b*x))/(S(4)*e*(d + e*x)**S(4)) + F**(c*(a - b*d/e))*b**S(4)*c**S(4)*log(F)**S(4)*Ei(b*c*(d + e*x)*log(F)/e)/(S(24)*e**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*((d + e*x)**n)**m, x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(-m*n)*((d + e*x)**n)**m*Gamma(m*n + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(4) + S(4)*d**S(3)*e*x + S(6)*d**S(2)*e**S(2)*x**S(2) + S(4)*d*e**S(3)*x**S(3) + e**S(4)*x**S(4))**m, x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(-S(4)*m)*((d + e*x)**S(4))**m*Gamma(S(4)*m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(3) + S(3)*d**S(2)*e*x + S(3)*d*e**S(2)*x**S(2) + e**S(3)*x**S(3))**m, x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(-S(3)*m)*((d + e*x)**S(3))**m*Gamma(S(3)*m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(2) + S(2)*d*e*x + e**S(2)*x**S(2))**m, x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(-S(2)*m)*((d + e*x)**S(2))**m*Gamma(S(2)*m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**m, x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(-m)*(d + e*x)**m*Gamma(m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**(-m), x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**m*(d + e*x)**(-m)*Gamma(-m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(2) + S(2)*d*e*x + e**S(2)*x**S(2))**(-m), x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(S(2)*m)*((d + e*x)**S(2))**(-m)*Gamma(-S(2)*m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d**S(3) + S(3)*d**S(2)*e*x + S(3)*d*e**S(2)*x**S(2) + e**S(3)*x**S(3))**(-m), x), x, F**(c*(a - b*d/e))*(-b*c*(d + e*x)*log(F)/e)**(S(3)*m)*((d + e*x)**S(3))**(-m)*Gamma(-S(3)*m + S(1), -b*c*(d + e*x)*log(F)/e)/(b*c*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(S(5)*x + S(2)), x), x, F**(S(5)*x + S(2))/(S(5)*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x), x), x, F**(a + b*x)/(b*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(10)**(S(5)*x + S(2)), x), x, S(2)**(S(5)*x + S(2))*S(5)**(S(5)*x + S(1))/log(S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)*x**(S(7)/2), x), x, S(105)*sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/(S(16)*b**(S(9)/2)*log(F)**(S(9)/2)) + F**(a + b*x)*x**(S(7)/2)/(b*log(F)) - S(7)*F**(a + b*x)*x**(S(5)/2)/(S(2)*b**S(2)*log(F)**S(2)) + S(35)*F**(a + b*x)*x**(S(3)/2)/(S(4)*b**S(3)*log(F)**S(3)) - S(105)*F**(a + b*x)*sqrt(x)/(S(8)*b**S(4)*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)*x**(S(5)/2), x), x, -S(15)*sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/(S(8)*b**(S(7)/2)*log(F)**(S(7)/2)) + F**(a + b*x)*x**(S(5)/2)/(b*log(F)) - S(5)*F**(a + b*x)*x**(S(3)/2)/(S(2)*b**S(2)*log(F)**S(2)) + S(15)*F**(a + b*x)*sqrt(x)/(S(4)*b**S(3)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)*x**(S(3)/2), x), x, S(3)*sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/(S(4)*b**(S(5)/2)*log(F)**(S(5)/2)) + F**(a + b*x)*x**(S(3)/2)/(b*log(F)) - S(3)*F**(a + b*x)*sqrt(x)/(S(2)*b**S(2)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)*sqrt(x), x), x, -sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/(S(2)*b**(S(3)/2)*log(F)**(S(3)/2)) + F**(a + b*x)*sqrt(x)/(b*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)/sqrt(x), x), x, sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/(sqrt(b)*sqrt(log(F))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)/x**(S(3)/2), x), x, S(2)*sqrt(pi)*F**a*sqrt(b)*sqrt(log(F))*erfi(sqrt(b)*sqrt(x)*sqrt(log(F))) - S(2)*F**(a + b*x)/sqrt(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)/x**(S(5)/2), x), x, S(4)*sqrt(pi)*F**a*b**(S(3)/2)*log(F)**(S(3)/2)*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/S(3) - S(4)*F**(a + b*x)*b*log(F)/(S(3)*sqrt(x)) - S(2)*F**(a + b*x)/(S(3)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)/x**(S(7)/2), x), x, S(8)*sqrt(pi)*F**a*b**(S(5)/2)*log(F)**(S(5)/2)*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/S(15) - S(8)*F**(a + b*x)*b**S(2)*log(F)**S(2)/(S(15)*sqrt(x)) - S(4)*F**(a + b*x)*b*log(F)/(S(15)*x**(S(3)/2)) - S(2)*F**(a + b*x)/(S(5)*x**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x)/x**(S(9)/2), x), x, S(16)*sqrt(pi)*F**a*b**(S(7)/2)*log(F)**(S(7)/2)*erfi(sqrt(b)*sqrt(x)*sqrt(log(F)))/S(105) - S(16)*F**(a + b*x)*b**S(3)*log(F)**S(3)/(S(105)*sqrt(x)) - S(8)*F**(a + b*x)*b**S(2)*log(F)**S(2)/(S(105)*x**(S(3)/2)) - S(4)*F**(a + b*x)*b*log(F)/(S(35)*x**(S(5)/2)) - S(2)*F**(a + b*x)/(S(7)*x**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**(S(7)/2), x), x, F**(c*(a + b*x))*(d + e*x)**(S(7)/2)/(b*c*log(F)) - S(7)*F**(c*(a + b*x))*e*(d + e*x)**(S(5)/2)/(S(2)*b**S(2)*c**S(2)*log(F)**S(2)) + S(35)*F**(c*(a + b*x))*e**S(2)*(d + e*x)**(S(3)/2)/(S(4)*b**S(3)*c**S(3)*log(F)**S(3)) - S(105)*F**(c*(a + b*x))*e**S(3)*sqrt(d + e*x)/(S(8)*b**S(4)*c**S(4)*log(F)**S(4)) + S(105)*sqrt(pi)*F**(c*(a - b*d/e))*e**(S(7)/2)*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(S(16)*b**(S(9)/2)*c**(S(9)/2)*log(F)**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**(S(5)/2), x), x, F**(c*(a + b*x))*(d + e*x)**(S(5)/2)/(b*c*log(F)) - S(5)*F**(c*(a + b*x))*e*(d + e*x)**(S(3)/2)/(S(2)*b**S(2)*c**S(2)*log(F)**S(2)) + S(15)*F**(c*(a + b*x))*e**S(2)*sqrt(d + e*x)/(S(4)*b**S(3)*c**S(3)*log(F)**S(3)) - S(15)*sqrt(pi)*F**(c*(a - b*d/e))*e**(S(5)/2)*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(S(8)*b**(S(7)/2)*c**(S(7)/2)*log(F)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**(S(3)/2), x), x, F**(c*(a + b*x))*(d + e*x)**(S(3)/2)/(b*c*log(F)) - S(3)*F**(c*(a + b*x))*e*sqrt(d + e*x)/(S(2)*b**S(2)*c**S(2)*log(F)**S(2)) + S(3)*sqrt(pi)*F**(c*(a - b*d/e))*e**(S(3)/2)*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(S(4)*b**(S(5)/2)*c**(S(5)/2)*log(F)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*sqrt(d + e*x), x), x, F**(c*(a + b*x))*sqrt(d + e*x)/(b*c*log(F)) - sqrt(pi)*F**(c*(a - b*d/e))*sqrt(e)*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(S(2)*b**(S(3)/2)*c**(S(3)/2)*log(F)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/sqrt(d + e*x), x), x, sqrt(pi)*F**(c*(a - b*d/e))*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(sqrt(b)*sqrt(c)*sqrt(e)*sqrt(log(F))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**(S(3)/2), x), x, -S(2)*F**(c*(a + b*x))/(e*sqrt(d + e*x)) + S(2)*sqrt(pi)*F**(c*(a - b*d/e))*sqrt(b)*sqrt(c)*sqrt(log(F))*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/e**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**(S(5)/2), x), x, -S(4)*F**(c*(a + b*x))*b*c*log(F)/(S(3)*e**S(2)*sqrt(d + e*x)) - S(2)*F**(c*(a + b*x))/(S(3)*e*(d + e*x)**(S(3)/2)) + S(4)*sqrt(pi)*F**(c*(a - b*d/e))*b**(S(3)/2)*c**(S(3)/2)*log(F)**(S(3)/2)*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(S(3)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**(S(7)/2), x), x, -S(8)*F**(c*(a + b*x))*b**S(2)*c**S(2)*log(F)**S(2)/(S(15)*e**S(3)*sqrt(d + e*x)) - S(4)*F**(c*(a + b*x))*b*c*log(F)/(S(15)*e**S(2)*(d + e*x)**(S(3)/2)) - S(2)*F**(c*(a + b*x))/(S(5)*e*(d + e*x)**(S(5)/2)) + S(8)*sqrt(pi)*F**(c*(a - b*d/e))*b**(S(5)/2)*c**(S(5)/2)*log(F)**(S(5)/2)*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(S(15)*e**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))/(d + e*x)**(S(9)/2), x), x, -S(16)*F**(c*(a + b*x))*b**S(3)*c**S(3)*log(F)**S(3)/(S(105)*e**S(4)*sqrt(d + e*x)) - S(8)*F**(c*(a + b*x))*b**S(2)*c**S(2)*log(F)**S(2)/(S(105)*e**S(3)*(d + e*x)**(S(3)/2)) - S(4)*F**(c*(a + b*x))*b*c*log(F)/(S(35)*e**S(2)*(d + e*x)**(S(5)/2)) - S(2)*F**(c*(a + b*x))/(S(7)*e*(d + e*x)**(S(7)/2)) + S(16)*sqrt(pi)*F**(c*(a - b*d/e))*b**(S(7)/2)*c**(S(7)/2)*log(F)**(S(7)/2)*erfi(sqrt(b)*sqrt(c)*sqrt(d + e*x)*sqrt(log(F))/sqrt(e))/(S(105)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)*exp(-b*x), x), x, -x**(S(13)/2)*exp(-b*x)/b - S(13)*x**(S(11)/2)*exp(-b*x)/(S(2)*b**S(2)) - S(143)*x**(S(9)/2)*exp(-b*x)/(S(4)*b**S(3)) - S(1287)*x**(S(7)/2)*exp(-b*x)/(S(8)*b**S(4)) - S(9009)*x**(S(5)/2)*exp(-b*x)/(S(16)*b**S(5)) - S(45045)*x**(S(3)/2)*exp(-b*x)/(S(32)*b**S(6)) - S(135135)*sqrt(x)*exp(-b*x)/(S(64)*b**S(7)) + S(135135)*sqrt(pi)*erf(sqrt(b)*sqrt(x))/(S(128)*b**(S(15)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x)**(S(4)/3), x), x, -F**(c*(a - b*d/e))*e*(d + e*x)**(S(1)/3)*Gamma(S(7)/3, -b*c*(d + e*x)*log(F)/e)/(b**S(2)*c**S(2)*(-b*c*(d + e*x)*log(F)/e)**(S(1)/3)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**(S(4)/3)*(F**(c*(a + b*x)))**n, x), x, -F**(-c*n*(a + b*x) + c*n*(a - b*d/e))*e*(d + e*x)**(S(1)/3)*(F**(c*(a + b*x)))**n*Gamma(S(7)/3, -b*c*n*(d + e*x)*log(F)/e)/(b**S(2)*c**S(2)*n**S(2)*(-b*c*n*(d + e*x)*log(F)/e)**(S(1)/3)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x), x), x, F**(c*(a + b*x))*(d + e*x)/(b*c*log(F)) - F**(c*(a + b*x))*e/(b**S(2)*c**S(2)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x + f*x**S(2)), x), x, F**(c*(a + b*x))*d/(b*c*log(F)) + F**(c*(a + b*x))*e*x/(b*c*log(F)) + F**(c*(a + b*x))*f*x**S(2)/(b*c*log(F)) - F**(c*(a + b*x))*e/(b**S(2)*c**S(2)*log(F)**S(2)) - S(2)*F**(c*(a + b*x))*f*x/(b**S(2)*c**S(2)*log(F)**S(2)) + S(2)*F**(c*(a + b*x))*f/(b**S(3)*c**S(3)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x + f*x**S(2) + g*x**S(3)), x), x, F**(c*(a + b*x))*d/(b*c*log(F)) + F**(c*(a + b*x))*e*x/(b*c*log(F)) + F**(c*(a + b*x))*f*x**S(2)/(b*c*log(F)) + F**(c*(a + b*x))*g*x**S(3)/(b*c*log(F)) - F**(c*(a + b*x))*e/(b**S(2)*c**S(2)*log(F)**S(2)) - S(2)*F**(c*(a + b*x))*f*x/(b**S(2)*c**S(2)*log(F)**S(2)) - S(3)*F**(c*(a + b*x))*g*x**S(2)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(2)*F**(c*(a + b*x))*f/(b**S(3)*c**S(3)*log(F)**S(3)) + S(6)*F**(c*(a + b*x))*g*x/(b**S(3)*c**S(3)*log(F)**S(3)) - S(6)*F**(c*(a + b*x))*g/(b**S(4)*c**S(4)*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4)), x), x, F**(c*(a + b*x))*d/(b*c*log(F)) + F**(c*(a + b*x))*e*x/(b*c*log(F)) + F**(c*(a + b*x))*f*x**S(2)/(b*c*log(F)) + F**(c*(a + b*x))*g*x**S(3)/(b*c*log(F)) + F**(c*(a + b*x))*h*x**S(4)/(b*c*log(F)) - F**(c*(a + b*x))*e/(b**S(2)*c**S(2)*log(F)**S(2)) - S(2)*F**(c*(a + b*x))*f*x/(b**S(2)*c**S(2)*log(F)**S(2)) - S(3)*F**(c*(a + b*x))*g*x**S(2)/(b**S(2)*c**S(2)*log(F)**S(2)) - S(4)*F**(c*(a + b*x))*h*x**S(3)/(b**S(2)*c**S(2)*log(F)**S(2)) + S(2)*F**(c*(a + b*x))*f/(b**S(3)*c**S(3)*log(F)**S(3)) + S(6)*F**(c*(a + b*x))*g*x/(b**S(3)*c**S(3)*log(F)**S(3)) + S(12)*F**(c*(a + b*x))*h*x**S(2)/(b**S(3)*c**S(3)*log(F)**S(3)) - S(6)*F**(c*(a + b*x))*g/(b**S(4)*c**S(4)*log(F)**S(4)) - S(24)*F**(c*(a + b*x))*h*x/(b**S(4)*c**S(4)*log(F)**S(4)) + S(24)*F**(c*(a + b*x))*h/(b**S(5)*c**S(5)*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*x)**S(3)*exp(-a - b*x), x), x, -a**S(3)*x**m*(b*x)**(-m)*Gamma(m + S(1), b*x)*exp(-a)/b - S(3)*a**S(2)*x**m*(b*x)**(-m)*Gamma(m + S(2), b*x)*exp(-a)/b - S(3)*a*x**m*(b*x)**(-m)*Gamma(m + S(3), b*x)*exp(-a)/b - x**m*(b*x)**(-m)*Gamma(m + S(4), b*x)*exp(-a)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)**S(3)*exp(-a - b*x), x), x, -a**S(3)*x**S(3)*exp(-a - b*x)/b - S(3)*a**S(3)*x**S(2)*exp(-a - b*x)/b**S(2) - S(6)*a**S(3)*x*exp(-a - b*x)/b**S(3) - S(6)*a**S(3)*exp(-a - b*x)/b**S(4) - S(3)*a**S(2)*x**S(4)*exp(-a - b*x) - S(12)*a**S(2)*x**S(3)*exp(-a - b*x)/b - S(36)*a**S(2)*x**S(2)*exp(-a - b*x)/b**S(2) - S(72)*a**S(2)*x*exp(-a - b*x)/b**S(3) - S(72)*a**S(2)*exp(-a - b*x)/b**S(4) - S(3)*a*b*x**S(5)*exp(-a - b*x) - S(15)*a*x**S(4)*exp(-a - b*x) - S(60)*a*x**S(3)*exp(-a - b*x)/b - S(180)*a*x**S(2)*exp(-a - b*x)/b**S(2) - S(360)*a*x*exp(-a - b*x)/b**S(3) - S(360)*a*exp(-a - b*x)/b**S(4) - b**S(2)*x**S(6)*exp(-a - b*x) - S(6)*b*x**S(5)*exp(-a - b*x) - S(30)*x**S(4)*exp(-a - b*x) - S(120)*x**S(3)*exp(-a - b*x)/b - S(360)*x**S(2)*exp(-a - b*x)/b**S(2) - S(720)*x*exp(-a - b*x)/b**S(3) - S(720)*exp(-a - b*x)/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**S(3)*exp(-a - b*x), x), x, -a**S(3)*x**S(2)*exp(-a - b*x)/b - S(2)*a**S(3)*x*exp(-a - b*x)/b**S(2) - S(2)*a**S(3)*exp(-a - b*x)/b**S(3) - S(3)*a**S(2)*x**S(3)*exp(-a - b*x) - S(9)*a**S(2)*x**S(2)*exp(-a - b*x)/b - S(18)*a**S(2)*x*exp(-a - b*x)/b**S(2) - S(18)*a**S(2)*exp(-a - b*x)/b**S(3) - S(3)*a*b*x**S(4)*exp(-a - b*x) - S(12)*a*x**S(3)*exp(-a - b*x) - S(36)*a*x**S(2)*exp(-a - b*x)/b - S(72)*a*x*exp(-a - b*x)/b**S(2) - S(72)*a*exp(-a - b*x)/b**S(3) - b**S(2)*x**S(5)*exp(-a - b*x) - S(5)*b*x**S(4)*exp(-a - b*x) - S(20)*x**S(3)*exp(-a - b*x) - S(60)*x**S(2)*exp(-a - b*x)/b - S(120)*x*exp(-a - b*x)/b**S(2) - S(120)*exp(-a - b*x)/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**S(3)*exp(-a - b*x), x), x, a*(a + b*x)**S(3)*exp(-a - b*x)/b**S(2) + S(3)*a*(a + b*x)**S(2)*exp(-a - b*x)/b**S(2) + S(6)*a*(a + b*x)*exp(-a - b*x)/b**S(2) + S(6)*a*exp(-a - b*x)/b**S(2) - (a + b*x)**S(4)*exp(-a - b*x)/b**S(2) - S(4)*(a + b*x)**S(3)*exp(-a - b*x)/b**S(2) - S(12)*(a + b*x)**S(2)*exp(-a - b*x)/b**S(2) - S(24)*(a + b*x)*exp(-a - b*x)/b**S(2) - S(24)*exp(-a - b*x)/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(-a - b*x), x), x, -(a + b*x)**S(3)*exp(-a - b*x)/b - S(3)*(a + b*x)**S(2)*exp(-a - b*x)/b - S(6)*(a + b*x)*exp(-a - b*x)/b - S(6)*exp(-a - b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(-a - b*x)/x, x), x, a**S(3)*exp(-a)*Ei(-b*x) - S(3)*a**S(2)*exp(-a - b*x) - S(3)*a*b*x*exp(-a - b*x) - S(3)*a*exp(-a - b*x) - b**S(2)*x**S(2)*exp(-a - b*x) - S(2)*b*x*exp(-a - b*x) - S(2)*exp(-a - b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(-a - b*x)/x**S(2), x), x, -a**S(3)*b*exp(-a)*Ei(-b*x) - a**S(3)*exp(-a - b*x)/x + S(3)*a**S(2)*b*exp(-a)*Ei(-b*x) - S(3)*a*b*exp(-a - b*x) - b**S(2)*x*exp(-a - b*x) - b*exp(-a - b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(-a - b*x)/x**S(3), x), x, a**S(3)*b**S(2)*exp(-a)*Ei(-b*x)/S(2) + a**S(3)*b*exp(-a - b*x)/(S(2)*x) - a**S(3)*exp(-a - b*x)/(S(2)*x**S(2)) - S(3)*a**S(2)*b**S(2)*exp(-a)*Ei(-b*x) - S(3)*a**S(2)*b*exp(-a - b*x)/x + S(3)*a*b**S(2)*exp(-a)*Ei(-b*x) - b**S(2)*exp(-a - b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(-a - b*x)/x**S(4), x), x, -a**S(3)*b**S(3)*exp(-a)*Ei(-b*x)/S(6) - a**S(3)*b**S(2)*exp(-a - b*x)/(S(6)*x) + a**S(3)*b*exp(-a - b*x)/(S(6)*x**S(2)) - a**S(3)*exp(-a - b*x)/(S(3)*x**S(3)) + S(3)*a**S(2)*b**S(3)*exp(-a)*Ei(-b*x)/S(2) + S(3)*a**S(2)*b**S(2)*exp(-a - b*x)/(S(2)*x) - S(3)*a**S(2)*b*exp(-a - b*x)/(S(2)*x**S(2)) - S(3)*a*b**S(3)*exp(-a)*Ei(-b*x) - S(3)*a*b**S(2)*exp(-a - b*x)/x + b**S(3)*exp(-a)*Ei(-b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*x**m*(e + f*x)**S(2), x), x, F**(a + b*c)*e**S(2)*x**m*(-b*d*x*log(F))**(-m)*Gamma(m + S(1), -b*d*x*log(F))/(b*d*log(F)) - S(2)*F**(a + b*c)*e*f*x**m*(-b*d*x*log(F))**(-m)*Gamma(m + S(2), -b*d*x*log(F))/(b**S(2)*d**S(2)*log(F)**S(2)) + F**(a + b*c)*f**S(2)*x**m*(-b*d*x*log(F))**(-m)*Gamma(m + S(3), -b*d*x*log(F))/(b**S(3)*d**S(3)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*x**S(3)*(e + f*x)**S(2), x), x, F**(a + b*c + b*d*x)*e**S(2)*x**S(3)/(b*d*log(F)) + S(2)*F**(a + b*c + b*d*x)*e*f*x**S(4)/(b*d*log(F)) + F**(a + b*c + b*d*x)*f**S(2)*x**S(5)/(b*d*log(F)) - S(3)*F**(a + b*c + b*d*x)*e**S(2)*x**S(2)/(b**S(2)*d**S(2)*log(F)**S(2)) - S(8)*F**(a + b*c + b*d*x)*e*f*x**S(3)/(b**S(2)*d**S(2)*log(F)**S(2)) - S(5)*F**(a + b*c + b*d*x)*f**S(2)*x**S(4)/(b**S(2)*d**S(2)*log(F)**S(2)) + S(6)*F**(a + b*c + b*d*x)*e**S(2)*x/(b**S(3)*d**S(3)*log(F)**S(3)) + S(24)*F**(a + b*c + b*d*x)*e*f*x**S(2)/(b**S(3)*d**S(3)*log(F)**S(3)) + S(20)*F**(a + b*c + b*d*x)*f**S(2)*x**S(3)/(b**S(3)*d**S(3)*log(F)**S(3)) - S(6)*F**(a + b*c + b*d*x)*e**S(2)/(b**S(4)*d**S(4)*log(F)**S(4)) - S(48)*F**(a + b*c + b*d*x)*e*f*x/(b**S(4)*d**S(4)*log(F)**S(4)) - S(60)*F**(a + b*c + b*d*x)*f**S(2)*x**S(2)/(b**S(4)*d**S(4)*log(F)**S(4)) + S(48)*F**(a + b*c + b*d*x)*e*f/(b**S(5)*d**S(5)*log(F)**S(5)) + S(120)*F**(a + b*c + b*d*x)*f**S(2)*x/(b**S(5)*d**S(5)*log(F)**S(5)) - S(120)*F**(a + b*c + b*d*x)*f**S(2)/(b**S(6)*d**S(6)*log(F)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*x**S(2)*(e + f*x)**S(2), x), x, F**(a + b*c + b*d*x)*e**S(2)*x**S(2)/(b*d*log(F)) + S(2)*F**(a + b*c + b*d*x)*e*f*x**S(3)/(b*d*log(F)) + F**(a + b*c + b*d*x)*f**S(2)*x**S(4)/(b*d*log(F)) - S(2)*F**(a + b*c + b*d*x)*e**S(2)*x/(b**S(2)*d**S(2)*log(F)**S(2)) - S(6)*F**(a + b*c + b*d*x)*e*f*x**S(2)/(b**S(2)*d**S(2)*log(F)**S(2)) - S(4)*F**(a + b*c + b*d*x)*f**S(2)*x**S(3)/(b**S(2)*d**S(2)*log(F)**S(2)) + S(2)*F**(a + b*c + b*d*x)*e**S(2)/(b**S(3)*d**S(3)*log(F)**S(3)) + S(12)*F**(a + b*c + b*d*x)*e*f*x/(b**S(3)*d**S(3)*log(F)**S(3)) + S(12)*F**(a + b*c + b*d*x)*f**S(2)*x**S(2)/(b**S(3)*d**S(3)*log(F)**S(3)) - S(12)*F**(a + b*c + b*d*x)*e*f/(b**S(4)*d**S(4)*log(F)**S(4)) - S(24)*F**(a + b*c + b*d*x)*f**S(2)*x/(b**S(4)*d**S(4)*log(F)**S(4)) + S(24)*F**(a + b*c + b*d*x)*f**S(2)/(b**S(5)*d**S(5)*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*x*(e + f*x)**S(2), x), x, F**(a + b*c + b*d*x)*e**S(2)*x/(b*d*log(F)) + S(2)*F**(a + b*c + b*d*x)*e*f*x**S(2)/(b*d*log(F)) + F**(a + b*c + b*d*x)*f**S(2)*x**S(3)/(b*d*log(F)) - F**(a + b*c + b*d*x)*e**S(2)/(b**S(2)*d**S(2)*log(F)**S(2)) - S(4)*F**(a + b*c + b*d*x)*e*f*x/(b**S(2)*d**S(2)*log(F)**S(2)) - S(3)*F**(a + b*c + b*d*x)*f**S(2)*x**S(2)/(b**S(2)*d**S(2)*log(F)**S(2)) + S(4)*F**(a + b*c + b*d*x)*e*f/(b**S(3)*d**S(3)*log(F)**S(3)) + S(6)*F**(a + b*c + b*d*x)*f**S(2)*x/(b**S(3)*d**S(3)*log(F)**S(3)) - S(6)*F**(a + b*c + b*d*x)*f**S(2)/(b**S(4)*d**S(4)*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*(e + f*x)**S(2), x), x, F**(a + b*c + b*d*x)*(e + f*x)**S(2)/(b*d*log(F)) - S(2)*F**(a + b*c + b*d*x)*f*(e + f*x)/(b**S(2)*d**S(2)*log(F)**S(2)) + S(2)*F**(a + b*c + b*d*x)*f**S(2)/(b**S(3)*d**S(3)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*(e + f*x)**S(2)/x, x), x, F**(a + b*c)*e**S(2)*Ei(b*d*x*log(F)) + S(2)*F**(a + b*c + b*d*x)*e*f/(b*d*log(F)) + F**(a + b*c + b*d*x)*f**S(2)*x/(b*d*log(F)) - F**(a + b*c + b*d*x)*f**S(2)/(b**S(2)*d**S(2)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*(e + f*x)**S(2)/x**S(2), x), x, F**(a + b*c)*b*d*e**S(2)*log(F)*Ei(b*d*x*log(F)) + S(2)*F**(a + b*c)*e*f*Ei(b*d*x*log(F)) - F**(a + b*c + b*d*x)*e**S(2)/x + F**(a + b*c + b*d*x)*f**S(2)/(b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*(e + f*x)**S(2)/x**S(3), x), x, F**(a + b*c)*b**S(2)*d**S(2)*e**S(2)*log(F)**S(2)*Ei(b*d*x*log(F))/S(2) + S(2)*F**(a + b*c)*b*d*e*f*log(F)*Ei(b*d*x*log(F)) + F**(a + b*c)*f**S(2)*Ei(b*d*x*log(F)) - F**(a + b*c + b*d*x)*b*d*e**S(2)*log(F)/(S(2)*x) - F**(a + b*c + b*d*x)*e**S(2)/(S(2)*x**S(2)) - S(2)*F**(a + b*c + b*d*x)*e*f/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*(e + f*x)**S(2)/x**S(4), x), x, F**(a + b*c)*b**S(3)*d**S(3)*e**S(2)*log(F)**S(3)*Ei(b*d*x*log(F))/S(6) + F**(a + b*c)*b**S(2)*d**S(2)*e*f*log(F)**S(2)*Ei(b*d*x*log(F)) + F**(a + b*c)*b*d*f**S(2)*log(F)*Ei(b*d*x*log(F)) - F**(a + b*c + b*d*x)*b**S(2)*d**S(2)*e**S(2)*log(F)**S(2)/(S(6)*x) - F**(a + b*c + b*d*x)*b*d*e**S(2)*log(F)/(S(6)*x**S(2)) - F**(a + b*c + b*d*x)*b*d*e*f*log(F)/x - F**(a + b*c + b*d*x)*e**S(2)/(S(3)*x**S(3)) - F**(a + b*c + b*d*x)*e*f/x**S(2) - F**(a + b*c + b*d*x)*f**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x))*(e + f*x)**S(2)/x**S(5), x), x, F**(a + b*c)*b**S(4)*d**S(4)*e**S(2)*log(F)**S(4)*Ei(b*d*x*log(F))/S(24) + F**(a + b*c)*b**S(3)*d**S(3)*e*f*log(F)**S(3)*Ei(b*d*x*log(F))/S(3) + F**(a + b*c)*b**S(2)*d**S(2)*f**S(2)*log(F)**S(2)*Ei(b*d*x*log(F))/S(2) - F**(a + b*c + b*d*x)*b**S(3)*d**S(3)*e**S(2)*log(F)**S(3)/(S(24)*x) - F**(a + b*c + b*d*x)*b**S(2)*d**S(2)*e**S(2)*log(F)**S(2)/(S(24)*x**S(2)) - F**(a + b*c + b*d*x)*b**S(2)*d**S(2)*e*f*log(F)**S(2)/(S(3)*x) - F**(a + b*c + b*d*x)*b*d*e**S(2)*log(F)/(S(12)*x**S(3)) - F**(a + b*c + b*d*x)*b*d*e*f*log(F)/(S(3)*x**S(2)) - F**(a + b*c + b*d*x)*b*d*f**S(2)*log(F)/(S(2)*x) - F**(a + b*c + b*d*x)*e**S(2)/(S(4)*x**S(4)) - S(2)*F**(a + b*c + b*d*x)*e*f/(S(3)*x**S(3)) - F**(a + b*c + b*d*x)*f**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*(c + d*x)**S(3)*exp(-a - b*x), x), x, -d**S(3)*(a + b*x)**S(7)*exp(-a - b*x)/b**S(4) - S(7)*d**S(3)*(a + b*x)**S(6)*exp(-a - b*x)/b**S(4) - S(42)*d**S(3)*(a + b*x)**S(5)*exp(-a - b*x)/b**S(4) - S(210)*d**S(3)*(a + b*x)**S(4)*exp(-a - b*x)/b**S(4) - S(840)*d**S(3)*(a + b*x)**S(3)*exp(-a - b*x)/b**S(4) - S(2520)*d**S(3)*(a + b*x)**S(2)*exp(-a - b*x)/b**S(4) - S(5040)*d**S(3)*(a + b*x)*exp(-a - b*x)/b**S(4) - S(5040)*d**S(3)*exp(-a - b*x)/b**S(4) - S(3)*d**S(2)*(a + b*x)**S(6)*(-a*d + b*c)*exp(-a - b*x)/b**S(4) - S(18)*d**S(2)*(a + b*x)**S(5)*(-a*d + b*c)*exp(-a - b*x)/b**S(4) - S(90)*d**S(2)*(a + b*x)**S(4)*(-a*d + b*c)*exp(-a - b*x)/b**S(4) - S(360)*d**S(2)*(a + b*x)**S(3)*(-a*d + b*c)*exp(-a - b*x)/b**S(4) - S(1080)*d**S(2)*(a + b*x)**S(2)*(-a*d + b*c)*exp(-a - b*x)/b**S(4) - S(2160)*d**S(2)*(a + b*x)*(-a*d + b*c)*exp(-a - b*x)/b**S(4) - S(2160)*d**S(2)*(-a*d + b*c)*exp(-a - b*x)/b**S(4) - S(3)*d*(a + b*x)**S(5)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(4) - S(15)*d*(a + b*x)**S(4)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(4) - S(60)*d*(a + b*x)**S(3)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(4) - S(180)*d*(a + b*x)**S(2)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(4) - S(360)*d*(a + b*x)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(4) - S(360)*d*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(4) - (a + b*x)**S(4)*(-a*d + b*c)**S(3)*exp(-a - b*x)/b**S(4) - S(4)*(a + b*x)**S(3)*(-a*d + b*c)**S(3)*exp(-a - b*x)/b**S(4) - S(12)*(a + b*x)**S(2)*(-a*d + b*c)**S(3)*exp(-a - b*x)/b**S(4) - S(24)*(a + b*x)*(-a*d + b*c)**S(3)*exp(-a - b*x)/b**S(4) - S(24)*(-a*d + b*c)**S(3)*exp(-a - b*x)/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*(c + d*x)**S(2)*exp(-a - b*x), x), x, -d**S(2)*(a + b*x)**S(6)*exp(-a - b*x)/b**S(3) - S(6)*d**S(2)*(a + b*x)**S(5)*exp(-a - b*x)/b**S(3) - S(30)*d**S(2)*(a + b*x)**S(4)*exp(-a - b*x)/b**S(3) - S(120)*d**S(2)*(a + b*x)**S(3)*exp(-a - b*x)/b**S(3) - S(360)*d**S(2)*(a + b*x)**S(2)*exp(-a - b*x)/b**S(3) - S(720)*d**S(2)*(a + b*x)*exp(-a - b*x)/b**S(3) - S(720)*d**S(2)*exp(-a - b*x)/b**S(3) - S(2)*d*(a + b*x)**S(5)*(-a*d + b*c)*exp(-a - b*x)/b**S(3) - S(10)*d*(a + b*x)**S(4)*(-a*d + b*c)*exp(-a - b*x)/b**S(3) - S(40)*d*(a + b*x)**S(3)*(-a*d + b*c)*exp(-a - b*x)/b**S(3) - S(120)*d*(a + b*x)**S(2)*(-a*d + b*c)*exp(-a - b*x)/b**S(3) - S(240)*d*(a + b*x)*(-a*d + b*c)*exp(-a - b*x)/b**S(3) - S(240)*d*(-a*d + b*c)*exp(-a - b*x)/b**S(3) - (a + b*x)**S(4)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(3) - S(4)*(a + b*x)**S(3)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(3) - S(12)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(3) - S(24)*(a + b*x)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(3) - S(24)*(-a*d + b*c)**S(2)*exp(-a - b*x)/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*(c + d*x)*exp(-a - b*x), x), x, -d*(a + b*x)**S(5)*exp(-a - b*x)/b**S(2) - S(5)*d*(a + b*x)**S(4)*exp(-a - b*x)/b**S(2) - S(20)*d*(a + b*x)**S(3)*exp(-a - b*x)/b**S(2) - S(60)*d*(a + b*x)**S(2)*exp(-a - b*x)/b**S(2) - S(120)*d*(a + b*x)*exp(-a - b*x)/b**S(2) - S(120)*d*exp(-a - b*x)/b**S(2) - (a + b*x)**S(4)*(-a*d + b*c)*exp(-a - b*x)/b**S(2) - (a + b*x)**S(3)*(-S(4)*a*d + S(4)*b*c)*exp(-a - b*x)/b**S(2) - (a + b*x)**S(2)*(-S(12)*a*d + S(12)*b*c)*exp(-a - b*x)/b**S(2) - (a + b*x)*(-S(24)*a*d + S(24)*b*c)*exp(-a - b*x)/b**S(2) - (-S(24)*a*d + S(24)*b*c)*exp(-a - b*x)/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*exp(-a - b*x), x), x, -(a + b*x)**S(4)*exp(-a - b*x)/b - S(4)*(a + b*x)**S(3)*exp(-a - b*x)/b - S(12)*(a + b*x)**S(2)*exp(-a - b*x)/b - S(24)*(a + b*x)*exp(-a - b*x)/b - S(24)*exp(-a - b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*exp(-a - b*x)/(c + d*x), x), x, -(a + b*x)**S(3)*exp(-a - b*x)/d - S(3)*(a + b*x)**S(2)*exp(-a - b*x)/d - S(6)*(a + b*x)*exp(-a - b*x)/d - S(6)*exp(-a - b*x)/d + (a + b*x)**S(2)*(-a*d + b*c)*exp(-a - b*x)/d**S(2) + (a + b*x)*(-S(2)*a*d + S(2)*b*c)*exp(-a - b*x)/d**S(2) + (-S(2)*a*d + S(2)*b*c)*exp(-a - b*x)/d**S(2) - (a + b*x)*(-a*d + b*c)**S(2)*exp(-a - b*x)/d**S(3) - (-a*d + b*c)**S(2)*exp(-a - b*x)/d**S(3) + (-a*d + b*c)**S(3)*exp(-a - b*x)/d**S(4) + (-a*d + b*c)**S(4)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*exp(-a - b*x)/(c + d*x)**S(2), x), x, -b**S(3)*(c + d*x)**S(2)*exp(-a - b*x)/d**S(4) - S(2)*b**S(2)*(c + d*x)*exp(-a - b*x)/d**S(3) + S(4)*b**S(2)*(c + d*x)*(-a*d + b*c)*exp(-a - b*x)/d**S(4) - S(2)*b*exp(-a - b*x)/d**S(2) + S(4)*b*(-a*d + b*c)*exp(-a - b*x)/d**S(3) - S(6)*b*(-a*d + b*c)**S(2)*exp(-a - b*x)/d**S(4) - S(4)*b*(-a*d + b*c)**S(3)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(5) - b*(-a*d + b*c)**S(4)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(6) - (-a*d + b*c)**S(4)*exp(-a - b*x)/(d**S(5)*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*exp(-a - b*x)/(c + d*x)**S(3), x), x, -b**S(3)*x*exp(-a - b*x)/d**S(3) - b**S(2)*exp(-a - b*x)/d**S(3) + b**S(2)*(-S(4)*a*d + S(3)*b*c)*exp(-a - b*x)/d**S(4) + S(6)*b**S(2)*(-a*d + b*c)**S(2)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(5) + S(4)*b**S(2)*(-a*d + b*c)**S(3)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(6) + b**S(2)*(-a*d + b*c)**S(4)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/(S(2)*d**S(7)) + S(4)*b*(-a*d + b*c)**S(3)*exp(-a - b*x)/(d**S(5)*(c + d*x)) + b*(-a*d + b*c)**S(4)*exp(-a - b*x)/(S(2)*d**S(6)*(c + d*x)) - (-a*d + b*c)**S(4)*exp(-a - b*x)/(S(2)*d**S(5)*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*exp(-a - b*x)/(c + d*x)**S(4), x), x, -b**S(3)*exp(-a - b*x)/d**S(4) - S(4)*b**S(3)*(-a*d + b*c)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(5) - S(6)*b**S(3)*(-a*d + b*c)**S(2)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(6) - S(2)*b**S(3)*(-a*d + b*c)**S(3)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(7) - b**S(3)*(-a*d + b*c)**S(4)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/(S(6)*d**S(8)) - S(6)*b**S(2)*(-a*d + b*c)**S(2)*exp(-a - b*x)/(d**S(5)*(c + d*x)) - S(2)*b**S(2)*(-a*d + b*c)**S(3)*exp(-a - b*x)/(d**S(6)*(c + d*x)) - b**S(2)*(-a*d + b*c)**S(4)*exp(-a - b*x)/(S(6)*d**S(7)*(c + d*x)) + S(2)*b*(-a*d + b*c)**S(3)*exp(-a - b*x)/(d**S(5)*(c + d*x)**S(2)) + b*(-a*d + b*c)**S(4)*exp(-a - b*x)/(S(6)*d**S(6)*(c + d*x)**S(2)) - (-a*d + b*c)**S(4)*exp(-a - b*x)/(S(3)*d**S(5)*(c + d*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*exp(-a - b*x)/(c + d*x)**S(5), x), x, b**S(4)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(5) + S(4)*b**S(4)*(-a*d + b*c)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(6) + S(3)*b**S(4)*(-a*d + b*c)**S(2)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/d**S(7) + S(2)*b**S(4)*(-a*d + b*c)**S(3)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/(S(3)*d**S(8)) + b**S(4)*(-a*d + b*c)**S(4)*exp(-a + b*c/d)*Ei(-b*(c + d*x)/d)/(S(24)*d**S(9)) + S(4)*b**S(3)*(-a*d + b*c)*exp(-a - b*x)/(d**S(5)*(c + d*x)) + S(3)*b**S(3)*(-a*d + b*c)**S(2)*exp(-a - b*x)/(d**S(6)*(c + d*x)) + S(2)*b**S(3)*(-a*d + b*c)**S(3)*exp(-a - b*x)/(S(3)*d**S(7)*(c + d*x)) + b**S(3)*(-a*d + b*c)**S(4)*exp(-a - b*x)/(S(24)*d**S(8)*(c + d*x)) - S(3)*b**S(2)*(-a*d + b*c)**S(2)*exp(-a - b*x)/(d**S(5)*(c + d*x)**S(2)) - S(2)*b**S(2)*(-a*d + b*c)**S(3)*exp(-a - b*x)/(S(3)*d**S(6)*(c + d*x)**S(2)) - b**S(2)*(-a*d + b*c)**S(4)*exp(-a - b*x)/(S(24)*d**S(7)*(c + d*x)**S(2)) + S(4)*b*(-a*d + b*c)**S(3)*exp(-a - b*x)/(S(3)*d**S(5)*(c + d*x)**S(3)) + b*(-a*d + b*c)**S(4)*exp(-a - b*x)/(S(12)*d**S(6)*(c + d*x)**S(3)) - (-a*d + b*c)**S(4)*exp(-a - b*x)/(S(4)*d**S(5)*(c + d*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*x**m*(e*n + e*(b*c*x*log(F) + m + S(1))*log(d*x) + e)*log(d*x)**n, x), x, F**(c*(a + b*x))*e*x**(m + S(1))*log(d*x)**(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*x**S(2)*(e*n + e*(b*c*x*log(F) + S(3))*log(d*x) + e)*log(d*x)**n, x), x, F**(c*(a + b*x))*e*x**S(3)*log(d*x)**(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*x*(e*n + e*(b*c*x*log(F) + S(2))*log(d*x) + e)*log(d*x)**n, x), x, F**(c*(a + b*x))*e*x**S(2)*log(d*x)**(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(e*n + e*(b*c*x*log(F) + S(1))*log(d*x) + e)*log(d*x)**n, x), x, F**(c*(a + b*x))*e*x*log(d*x)**(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(b*c*e*x*log(F)*log(d*x) + e*n + e)*log(d*x)**n/x, x), x, F**(c*(a + b*x))*e*log(d*x)**(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(e*n + e*(b*c*x*log(F) + S(-1))*log(d*x) + e)*log(d*x)**n/x**S(2), x), x, F**(c*(a + b*x))*e*log(d*x)**(n + S(1))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x))*(e*n + e*(b*c*x*log(F) + S(-2))*log(d*x) + e)*log(d*x)**n/x**S(3), x), x, F**(c*(a + b*x))*e*log(d*x)**(n + S(1))/x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(exp(a + b*x)), x), x, S(2)*x**S(4)*sqrt(exp(a + b*x))/b - S(16)*x**S(3)*sqrt(exp(a + b*x))/b**S(2) + S(96)*x**S(2)*sqrt(exp(a + b*x))/b**S(3) - S(384)*x*sqrt(exp(a + b*x))/b**S(4) + S(768)*sqrt(exp(a + b*x))/b**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(exp(a + b*x)), x), x, S(2)*x**S(3)*sqrt(exp(a + b*x))/b - S(12)*x**S(2)*sqrt(exp(a + b*x))/b**S(2) + S(48)*x*sqrt(exp(a + b*x))/b**S(3) - S(96)*sqrt(exp(a + b*x))/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(exp(a + b*x)), x), x, S(2)*x**S(2)*sqrt(exp(a + b*x))/b - S(8)*x*sqrt(exp(a + b*x))/b**S(2) + S(16)*sqrt(exp(a + b*x))/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(exp(a + b*x)), x), x, S(2)*x*sqrt(exp(a + b*x))/b - S(4)*sqrt(exp(a + b*x))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(exp(a + b*x)), x), x, S(2)*sqrt(exp(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(exp(a + b*x))/x, x), x, exp(-b*x/S(2))*sqrt(exp(a + b*x))*Ei(b*x/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(exp(a + b*x))/x**S(2), x), x, b*exp(-b*x/S(2))*sqrt(exp(a + b*x))*Ei(b*x/S(2))/S(2) - sqrt(exp(a + b*x))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(exp(a + b*x))/x**S(3), x), x, b**S(2)*exp(-b*x/S(2))*sqrt(exp(a + b*x))*Ei(b*x/S(2))/S(8) - b*sqrt(exp(a + b*x))/(S(4)*x) - sqrt(exp(a + b*x))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(exp(a + b*x))/x**S(4), x), x, b**S(3)*exp(-b*x/S(2))*sqrt(exp(a + b*x))*Ei(b*x/S(2))/S(48) - b**S(2)*sqrt(exp(a + b*x))/(S(24)*x) - b*sqrt(exp(a + b*x))/(S(12)*x**S(2)) - sqrt(exp(a + b*x))/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) def test_2(): assert rubi_test(rubi_integrate(f**(c + d*x)*x**S(3)/(a + b*f**(c + d*x)), x), x, x**S(3)*log(S(1) + b*f**(c + d*x)/a)/(b*d*log(f)) + S(3)*x**S(2)*polylog(S(2), -b*f**(c + d*x)/a)/(b*d**S(2)*log(f)**S(2)) - S(6)*x*polylog(S(3), -b*f**(c + d*x)/a)/(b*d**S(3)*log(f)**S(3)) + S(6)*polylog(S(4), -b*f**(c + d*x)/a)/(b*d**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)*x**S(2)/(a + b*f**(c + d*x)), x), x, x**S(2)*log(S(1) + b*f**(c + d*x)/a)/(b*d*log(f)) + S(2)*x*polylog(S(2), -b*f**(c + d*x)/a)/(b*d**S(2)*log(f)**S(2)) - S(2)*polylog(S(3), -b*f**(c + d*x)/a)/(b*d**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)*x/(a + b*f**(c + d*x)), x), x, x*log(S(1) + b*f**(c + d*x)/a)/(b*d*log(f)) + polylog(S(2), -b*f**(c + d*x)/a)/(b*d**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(a + b*f**(c + d*x)), x), x, log(a + b*f**(c + d*x))/(b*d*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(x*(a + b*f**(c + d*x))), x), x, Integral(f**(c + d*x)/(x*(a + b*f**(c + d*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(x**S(2)*(a + b*f**(c + d*x))), x), x, Integral(f**(c + d*x)/(x**S(2)*(a + b*f**(c + d*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)*x**S(3)/(a + b*f**(c + d*x))**S(2), x), x, -x**S(3)/(b*d*(a + b*f**(c + d*x))*log(f)) - S(3)*x**S(2)*log(a*f**(-c - d*x)/b + S(1))/(a*b*d**S(2)*log(f)**S(2)) + S(6)*x*polylog(S(2), -a*f**(-c - d*x)/b)/(a*b*d**S(3)*log(f)**S(3)) + S(6)*polylog(S(3), -a*f**(-c - d*x)/b)/(a*b*d**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)*x**S(2)/(a + b*f**(c + d*x))**S(2), x), x, -x**S(2)/(b*d*(a + b*f**(c + d*x))*log(f)) - S(2)*x*log(a*f**(-c - d*x)/b + S(1))/(a*b*d**S(2)*log(f)**S(2)) + S(2)*polylog(S(2), -a*f**(-c - d*x)/b)/(a*b*d**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)*x/(a + b*f**(c + d*x))**S(2), x), x, -x/(b*d*(a + b*f**(c + d*x))*log(f)) + x/(a*b*d*log(f)) - log(a + b*f**(c + d*x))/(a*b*d**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(a + b*f**(c + d*x))**S(2), x), x, -S(1)/(b*d*(a + b*f**(c + d*x))*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(x*(a + b*f**(c + d*x))**S(2)), x), x, -Integral(S(1)/(x**S(2)*(a + b*f**(c + d*x))), x)/(b*d*log(f)) - S(1)/(b*d*x*(a + b*f**(c + d*x))*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(x**S(2)*(a + b*f**(c + d*x))**S(2)), x), x, -S(2)*Integral(S(1)/(x**S(3)*(a + b*f**(c + d*x))), x)/(b*d*log(f)) - S(1)/(b*d*x**S(2)*(a + b*f**(c + d*x))*log(f)), expand=True, _diff=True, _numerical=True) # recursion assert rubi_test(rubi_integrate(f**(c + d*x)*x**S(3)/(a + b*f**(c + d*x))**S(3), x), x, -x**S(3)/(S(2)*b*d*(a + b*f**(c + d*x))**S(2)*log(f)) + S(3)*x**S(2)/(S(2)*a*b*d**S(2)*(a + b*f**(c + d*x))*log(f)**S(2)) + x**S(3)/(S(2)*a**S(2)*b*d*log(f)) - S(3)*x**S(2)*log(S(1) + b*f**(c + d*x)/a)/(S(2)*a**S(2)*b*d**S(2)*log(f)**S(2)) + S(3)*x*log(a*f**(-c - d*x)/b + S(1))/(a**S(2)*b*d**S(3)*log(f)**S(3)) - S(3)*x*polylog(S(2), -b*f**(c + d*x)/a)/(a**S(2)*b*d**S(3)*log(f)**S(3)) - S(3)*polylog(S(2), -a*f**(-c - d*x)/b)/(a**S(2)*b*d**S(4)*log(f)**S(4)) + S(3)*polylog(S(3), -b*f**(c + d*x)/a)/(a**S(2)*b*d**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)*x**S(2)/(a + b*f**(c + d*x))**S(3), x), x, -x**S(2)/(S(2)*b*d*(a + b*f**(c + d*x))**S(2)*log(f)) + x/(a*b*d**S(2)*(a + b*f**(c + d*x))*log(f)**S(2)) + x**S(2)/(S(2)*a**S(2)*b*d*log(f)) - x*log(S(1) + b*f**(c + d*x)/a)/(a**S(2)*b*d**S(2)*log(f)**S(2)) - x/(a**S(2)*b*d**S(2)*log(f)**S(2)) + log(a + b*f**(c + d*x))/(a**S(2)*b*d**S(3)*log(f)**S(3)) - polylog(S(2), -b*f**(c + d*x)/a)/(a**S(2)*b*d**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)*x/(a + b*f**(c + d*x))**S(3), x), x, -x/(S(2)*b*d*(a + b*f**(c + d*x))**S(2)*log(f)) + S(1)/(S(2)*a*b*d**S(2)*(a + b*f**(c + d*x))*log(f)**S(2)) + x/(S(2)*a**S(2)*b*d*log(f)) - log(a + b*f**(c + d*x))/(S(2)*a**S(2)*b*d**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(a + b*f**(c + d*x))**S(3), x), x, -S(1)/(S(2)*b*d*(a + b*f**(c + d*x))**S(2)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(x*(a + b*f**(c + d*x))**S(3)), x), x, -Integral(S(1)/(x**S(2)*(a + b*f**(c + d*x))**S(2)), x)/(S(2)*b*d*log(f)) - S(1)/(S(2)*b*d*x*(a + b*f**(c + d*x))**S(2)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c + d*x)/(x**S(2)*(a + b*f**(c + d*x))**S(3)), x), x, -Integral(S(1)/(x**S(3)*(a + b*f**(c + d*x))**S(2)), x)/(b*d*log(f)) - S(1)/(S(2)*b*d*x**S(2)*(a + b*f**(c + d*x))**S(2)*log(f)), expand=True, _diff=True, _numerical=True) def test_3(): assert rubi_test(rubi_integrate(exp(x)/(S(6)*exp(x) + S(4)), x), x, log(S(3)*exp(x) + S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(a + b*exp(x)), x), x, log(a + b*exp(x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(d*x)/(a + b*exp(c + d*x)), x), x, exp(-c)*log(a + b*exp(c + d*x))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(c + d*x)/(a + b*exp(c + d*x)), x), x, log(a + b*exp(c + d*x))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(x))**n*exp(x), x), x, (a + b*exp(x))**(n + S(1))/(b*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(c + d*x))**n*exp(d*x), x), x, (a + b*exp(c + d*x))**(n + S(1))*exp(-c)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(c + d*x))**n*exp(c + d*x), x), x, (a + b*exp(c + d*x))**(n + S(1))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**x/(F**x*b + a), x), x, log(F**x*b + a)/(b*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(d*x)/(F**(c + d*x)*b + a), x), x, F**(-c)*log(F**(c + d*x)*b + a)/(b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c + d*x)/(F**(c + d*x)*b + a), x), x, log(F**(c + d*x)*b + a)/(b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**x*(F**x*b + a)**n, x), x, (F**x*b + a)**(n + S(1))/(b*(n + S(1))*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(d*x)*(F**(c + d*x)*b + a)**n, x), x, F**(-c)*(F**(c + d*x)*b + a)**(n + S(1))/(b*d*(n + S(1))*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c + d*x)*(F**(c + d*x)*b + a)**n, x), x, (F**(c + d*x)*b + a)**(n + S(1))/(b*d*(n + S(1))*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**m, x), x, -f**a*x**(m + S(1))*(-b*x**S(2)*log(f))**(-m/S(2) + S(-1)/2)*Gamma(m/S(2) + S(1)/2, -b*x**S(2)*log(f))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(11), x), x, -f**a*Gamma(S(6), -b*x**S(2)*log(f))/(S(2)*b**S(6)*log(f)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(9), x), x, f**a*Gamma(S(5), -b*x**S(2)*log(f))/(S(2)*b**S(5)*log(f)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(7), x), x, f**(a + b*x**S(2))*x**S(6)/(S(2)*b*log(f)) - S(3)*f**(a + b*x**S(2))*x**S(4)/(S(2)*b**S(2)*log(f)**S(2)) + S(3)*f**(a + b*x**S(2))*x**S(2)/(b**S(3)*log(f)**S(3)) - S(3)*f**(a + b*x**S(2))/(b**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(5), x), x, f**(a + b*x**S(2))*x**S(4)/(S(2)*b*log(f)) - f**(a + b*x**S(2))*x**S(2)/(b**S(2)*log(f)**S(2)) + f**(a + b*x**S(2))/(b**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(3), x), x, f**(a + b*x**S(2))*x**S(2)/(S(2)*b*log(f)) - f**(a + b*x**S(2))/(S(2)*b**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x, x), x, f**(a + b*x**S(2))/(S(2)*b*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x, x), x, f**a*Ei(b*x**S(2)*log(f))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(3), x), x, b*f**a*log(f)*Ei(b*x**S(2)*log(f))/S(2) - f**(a + b*x**S(2))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(5), x), x, b**S(2)*f**a*log(f)**S(2)*Ei(b*x**S(2)*log(f))/S(4) - b*f**(a + b*x**S(2))*log(f)/(S(4)*x**S(2)) - f**(a + b*x**S(2))/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(7), x), x, b**S(3)*f**a*log(f)**S(3)*Ei(b*x**S(2)*log(f))/S(12) - b**S(2)*f**(a + b*x**S(2))*log(f)**S(2)/(S(12)*x**S(2)) - b*f**(a + b*x**S(2))*log(f)/(S(12)*x**S(4)) - f**(a + b*x**S(2))/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(9), x), x, -b**S(4)*f**a*Gamma(S(-4), -b*x**S(2)*log(f))*log(f)**S(4)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(11), x), x, b**S(5)*f**a*Gamma(S(-5), -b*x**S(2)*log(f))*log(f)**S(5)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(12), x), x, -f**a*x**S(13)*Gamma(S(13)/2, -b*x**S(2)*log(f))/(S(2)*(-b*x**S(2)*log(f))**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(10), x), x, -f**a*x**S(11)*Gamma(S(11)/2, -b*x**S(2)*log(f))/(S(2)*(-b*x**S(2)*log(f))**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(8), x), x, f**(a + b*x**S(2))*x**S(7)/(S(2)*b*log(f)) - S(7)*f**(a + b*x**S(2))*x**S(5)/(S(4)*b**S(2)*log(f)**S(2)) + S(35)*f**(a + b*x**S(2))*x**S(3)/(S(8)*b**S(3)*log(f)**S(3)) - S(105)*f**(a + b*x**S(2))*x/(S(16)*b**S(4)*log(f)**S(4)) + S(105)*sqrt(pi)*f**a*erfi(sqrt(b)*x*sqrt(log(f)))/(S(32)*b**(S(9)/2)*log(f)**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(6), x), x, f**(a + b*x**S(2))*x**S(5)/(S(2)*b*log(f)) - S(5)*f**(a + b*x**S(2))*x**S(3)/(S(4)*b**S(2)*log(f)**S(2)) + S(15)*f**(a + b*x**S(2))*x/(S(8)*b**S(3)*log(f)**S(3)) - S(15)*sqrt(pi)*f**a*erfi(sqrt(b)*x*sqrt(log(f)))/(S(16)*b**(S(7)/2)*log(f)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(4), x), x, f**(a + b*x**S(2))*x**S(3)/(S(2)*b*log(f)) - S(3)*f**(a + b*x**S(2))*x/(S(4)*b**S(2)*log(f)**S(2)) + S(3)*sqrt(pi)*f**a*erfi(sqrt(b)*x*sqrt(log(f)))/(S(8)*b**(S(5)/2)*log(f)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))*x**S(2), x), x, f**(a + b*x**S(2))*x/(S(2)*b*log(f)) - sqrt(pi)*f**a*erfi(sqrt(b)*x*sqrt(log(f)))/(S(4)*b**(S(3)/2)*log(f)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2)), x), x, sqrt(pi)*f**a*erfi(sqrt(b)*x*sqrt(log(f)))/(S(2)*sqrt(b)*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(2), x), x, sqrt(pi)*sqrt(b)*f**a*sqrt(log(f))*erfi(sqrt(b)*x*sqrt(log(f))) - f**(a + b*x**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(4), x), x, S(2)*sqrt(pi)*b**(S(3)/2)*f**a*log(f)**(S(3)/2)*erfi(sqrt(b)*x*sqrt(log(f)))/S(3) - S(2)*b*f**(a + b*x**S(2))*log(f)/(S(3)*x) - f**(a + b*x**S(2))/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(6), x), x, S(4)*sqrt(pi)*b**(S(5)/2)*f**a*log(f)**(S(5)/2)*erfi(sqrt(b)*x*sqrt(log(f)))/S(15) - S(4)*b**S(2)*f**(a + b*x**S(2))*log(f)**S(2)/(S(15)*x) - S(2)*b*f**(a + b*x**S(2))*log(f)/(S(15)*x**S(3)) - f**(a + b*x**S(2))/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(8), x), x, S(8)*sqrt(pi)*b**(S(7)/2)*f**a*log(f)**(S(7)/2)*erfi(sqrt(b)*x*sqrt(log(f)))/S(105) - S(8)*b**S(3)*f**(a + b*x**S(2))*log(f)**S(3)/(S(105)*x) - S(4)*b**S(2)*f**(a + b*x**S(2))*log(f)**S(2)/(S(105)*x**S(3)) - S(2)*b*f**(a + b*x**S(2))*log(f)/(S(35)*x**S(5)) - f**(a + b*x**S(2))/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(10), x), x, -f**a*(-b*x**S(2)*log(f))**(S(9)/2)*Gamma(S(-9)/2, -b*x**S(2)*log(f))/(S(2)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(2))/x**S(12), x), x, -f**a*(-b*x**S(2)*log(f))**(S(11)/2)*Gamma(S(-11)/2, -b*x**S(2)*log(f))/(S(2)*x**S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**m, x), x, -f**a*x**(m + S(1))*(-b*x**S(3)*log(f))**(-m/S(3) + S(-1)/3)*Gamma(m/S(3) + S(1)/3, -b*x**S(3)*log(f))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(17), x), x, -f**a*Gamma(S(6), -b*x**S(3)*log(f))/(S(3)*b**S(6)*log(f)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(14), x), x, f**a*Gamma(S(5), -b*x**S(3)*log(f))/(S(3)*b**S(5)*log(f)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(11), x), x, f**(a + b*x**S(3))*x**S(9)/(S(3)*b*log(f)) - f**(a + b*x**S(3))*x**S(6)/(b**S(2)*log(f)**S(2)) + S(2)*f**(a + b*x**S(3))*x**S(3)/(b**S(3)*log(f)**S(3)) - S(2)*f**(a + b*x**S(3))/(b**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(8), x), x, f**(a + b*x**S(3))*x**S(6)/(S(3)*b*log(f)) - S(2)*f**(a + b*x**S(3))*x**S(3)/(S(3)*b**S(2)*log(f)**S(2)) + S(2)*f**(a + b*x**S(3))/(S(3)*b**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(5), x), x, f**(a + b*x**S(3))*x**S(3)/(S(3)*b*log(f)) - f**(a + b*x**S(3))/(S(3)*b**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(2), x), x, f**(a + b*x**S(3))/(S(3)*b*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x, x), x, f**a*Ei(b*x**S(3)*log(f))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x**S(4), x), x, b*f**a*log(f)*Ei(b*x**S(3)*log(f))/S(3) - f**(a + b*x**S(3))/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x**S(7), x), x, b**S(2)*f**a*log(f)**S(2)*Ei(b*x**S(3)*log(f))/S(6) - b*f**(a + b*x**S(3))*log(f)/(S(6)*x**S(3)) - f**(a + b*x**S(3))/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x**S(10), x), x, b**S(3)*f**a*log(f)**S(3)*Ei(b*x**S(3)*log(f))/S(18) - b**S(2)*f**(a + b*x**S(3))*log(f)**S(2)/(S(18)*x**S(3)) - b*f**(a + b*x**S(3))*log(f)/(S(18)*x**S(6)) - f**(a + b*x**S(3))/(S(9)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x**S(13), x), x, -b**S(4)*f**a*Gamma(S(-4), -b*x**S(3)*log(f))*log(f)**S(4)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x**S(16), x), x, b**S(5)*f**a*Gamma(S(-5), -b*x**S(3)*log(f))*log(f)**S(5)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(4), x), x, -f**a*x**S(5)*Gamma(S(5)/3, -b*x**S(3)*log(f))/(S(3)*(-b*x**S(3)*log(f))**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x**S(3), x), x, -f**a*x**S(4)*Gamma(S(4)/3, -b*x**S(3)*log(f))/(S(3)*(-b*x**S(3)*log(f))**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))*x, x), x, -f**a*x**S(2)*Gamma(S(2)/3, -b*x**S(3)*log(f))/(S(3)*(-b*x**S(3)*log(f))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3)), x), x, -f**a*x*Gamma(S(1)/3, -b*x**S(3)*log(f))/(S(3)*(-b*x**S(3)*log(f))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x**S(2), x), x, -f**a*(-b*x**S(3)*log(f))**(S(1)/3)*Gamma(S(-1)/3, -b*x**S(3)*log(f))/(S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**S(3))/x**S(3), x), x, -f**a*(-b*x**S(3)*log(f))**(S(2)/3)*Gamma(S(-2)/3, -b*x**S(3)*log(f))/(S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(S(4)*x**S(3)), x), x, exp(S(4)*x**S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)*x**m, x), x, f**a*x**(m + S(1))*(-b*log(f)/x)**(m + S(1))*Gamma(-m + S(-1), -b*log(f)/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)*x**S(4), x), x, -b**S(5)*f**a*Gamma(S(-5), -b*log(f)/x)*log(f)**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)*x**S(3), x), x, b**S(4)*f**a*Gamma(S(-4), -b*log(f)/x)*log(f)**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)*x**S(2), x), x, -b**S(3)*f**a*log(f)**S(3)*Ei(b*log(f)/x)/S(6) + b**S(2)*f**(a + b/x)*x*log(f)**S(2)/S(6) + b*f**(a + b/x)*x**S(2)*log(f)/S(6) + f**(a + b/x)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)*x, x), x, -b**S(2)*f**a*log(f)**S(2)*Ei(b*log(f)/x)/S(2) + b*f**(a + b/x)*x*log(f)/S(2) + f**(a + b/x)*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x), x), x, -b*f**a*log(f)*Ei(b*log(f)/x) + f**(a + b/x)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)/x, x), x, -f**a*Ei(b*log(f)/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)/x**S(2), x), x, -f**(a + b/x)/(b*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)/x**S(3), x), x, -f**(a + b/x)/(b*x*log(f)) + f**(a + b/x)/(b**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)/x**S(4), x), x, -f**(a + b/x)/(b*x**S(2)*log(f)) + S(2)*f**(a + b/x)/(b**S(2)*x*log(f)**S(2)) - S(2)*f**(a + b/x)/(b**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)/x**S(5), x), x, -f**(a + b/x)/(b*x**S(3)*log(f)) + S(3)*f**(a + b/x)/(b**S(2)*x**S(2)*log(f)**S(2)) - S(6)*f**(a + b/x)/(b**S(3)*x*log(f)**S(3)) + S(6)*f**(a + b/x)/(b**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)/x**S(6), x), x, -f**a*Gamma(S(5), -b*log(f)/x)/(b**S(5)*log(f)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x)/x**S(7), x), x, f**a*Gamma(S(6), -b*log(f)/x)/(b**S(6)*log(f)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**m, x), x, f**a*x**(m + S(1))*(-b*log(f)/x**S(2))**(m/S(2) + S(1)/2)*Gamma(-m/S(2) + S(-1)/2, -b*log(f)/x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(9), x), x, -b**S(5)*f**a*Gamma(S(-5), -b*log(f)/x**S(2))*log(f)**S(5)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(7), x), x, b**S(4)*f**a*Gamma(S(-4), -b*log(f)/x**S(2))*log(f)**S(4)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(5), x), x, -b**S(3)*f**a*log(f)**S(3)*Ei(b*log(f)/x**S(2))/S(12) + b**S(2)*f**(a + b/x**S(2))*x**S(2)*log(f)**S(2)/S(12) + b*f**(a + b/x**S(2))*x**S(4)*log(f)/S(12) + f**(a + b/x**S(2))*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(3), x), x, -b**S(2)*f**a*log(f)**S(2)*Ei(b*log(f)/x**S(2))/S(4) + b*f**(a + b/x**S(2))*x**S(2)*log(f)/S(4) + f**(a + b/x**S(2))*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x, x), x, -b*f**a*log(f)*Ei(b*log(f)/x**S(2))/S(2) + f**(a + b/x**S(2))*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x, x), x, -f**a*Ei(b*log(f)/x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(3), x), x, -f**(a + b/x**S(2))/(S(2)*b*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(5), x), x, -f**(a + b/x**S(2))/(S(2)*b*x**S(2)*log(f)) + f**(a + b/x**S(2))/(S(2)*b**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(7), x), x, -f**(a + b/x**S(2))/(S(2)*b*x**S(4)*log(f)) + f**(a + b/x**S(2))/(b**S(2)*x**S(2)*log(f)**S(2)) - f**(a + b/x**S(2))/(b**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(9), x), x, -f**(a + b/x**S(2))/(S(2)*b*x**S(6)*log(f)) + S(3)*f**(a + b/x**S(2))/(S(2)*b**S(2)*x**S(4)*log(f)**S(2)) - S(3)*f**(a + b/x**S(2))/(b**S(3)*x**S(2)*log(f)**S(3)) + S(3)*f**(a + b/x**S(2))/(b**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(11), x), x, -f**a*Gamma(S(5), -b*log(f)/x**S(2))/(S(2)*b**S(5)*log(f)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(13), x), x, f**a*Gamma(S(6), -b*log(f)/x**S(2))/(S(2)*b**S(6)*log(f)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(10), x), x, f**a*x**S(11)*(-b*log(f)/x**S(2))**(S(11)/2)*Gamma(S(-11)/2, -b*log(f)/x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(8), x), x, f**a*x**S(9)*(-b*log(f)/x**S(2))**(S(9)/2)*Gamma(S(-9)/2, -b*log(f)/x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(6), x), x, -S(8)*sqrt(pi)*b**(S(7)/2)*f**a*log(f)**(S(7)/2)*erfi(sqrt(b)*sqrt(log(f))/x)/S(105) + S(8)*b**S(3)*f**(a + b/x**S(2))*x*log(f)**S(3)/S(105) + S(4)*b**S(2)*f**(a + b/x**S(2))*x**S(3)*log(f)**S(2)/S(105) + S(2)*b*f**(a + b/x**S(2))*x**S(5)*log(f)/S(35) + f**(a + b/x**S(2))*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(4), x), x, -S(4)*sqrt(pi)*b**(S(5)/2)*f**a*log(f)**(S(5)/2)*erfi(sqrt(b)*sqrt(log(f))/x)/S(15) + S(4)*b**S(2)*f**(a + b/x**S(2))*x*log(f)**S(2)/S(15) + S(2)*b*f**(a + b/x**S(2))*x**S(3)*log(f)/S(15) + f**(a + b/x**S(2))*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))*x**S(2), x), x, -S(2)*sqrt(pi)*b**(S(3)/2)*f**a*log(f)**(S(3)/2)*erfi(sqrt(b)*sqrt(log(f))/x)/S(3) + S(2)*b*f**(a + b/x**S(2))*x*log(f)/S(3) + f**(a + b/x**S(2))*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2)), x), x, -sqrt(pi)*sqrt(b)*f**a*sqrt(log(f))*erfi(sqrt(b)*sqrt(log(f))/x) + f**(a + b/x**S(2))*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(2), x), x, -sqrt(pi)*f**a*erfi(sqrt(b)*sqrt(log(f))/x)/(S(2)*sqrt(b)*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(4), x), x, -f**(a + b/x**S(2))/(S(2)*b*x*log(f)) + sqrt(pi)*f**a*erfi(sqrt(b)*sqrt(log(f))/x)/(S(4)*b**(S(3)/2)*log(f)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(6), x), x, -f**(a + b/x**S(2))/(S(2)*b*x**S(3)*log(f)) + S(3)*f**(a + b/x**S(2))/(S(4)*b**S(2)*x*log(f)**S(2)) - S(3)*sqrt(pi)*f**a*erfi(sqrt(b)*sqrt(log(f))/x)/(S(8)*b**(S(5)/2)*log(f)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(8), x), x, -f**(a + b/x**S(2))/(S(2)*b*x**S(5)*log(f)) + S(5)*f**(a + b/x**S(2))/(S(4)*b**S(2)*x**S(3)*log(f)**S(2)) - S(15)*f**(a + b/x**S(2))/(S(8)*b**S(3)*x*log(f)**S(3)) + S(15)*sqrt(pi)*f**a*erfi(sqrt(b)*sqrt(log(f))/x)/(S(16)*b**(S(7)/2)*log(f)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(10), x), x, -f**(a + b/x**S(2))/(S(2)*b*x**S(7)*log(f)) + S(7)*f**(a + b/x**S(2))/(S(4)*b**S(2)*x**S(5)*log(f)**S(2)) - S(35)*f**(a + b/x**S(2))/(S(8)*b**S(3)*x**S(3)*log(f)**S(3)) + S(105)*f**(a + b/x**S(2))/(S(16)*b**S(4)*x*log(f)**S(4)) - S(105)*sqrt(pi)*f**a*erfi(sqrt(b)*sqrt(log(f))/x)/(S(32)*b**(S(9)/2)*log(f)**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(12), x), x, f**a*Gamma(S(11)/2, -b*log(f)/x**S(2))/(S(2)*x**S(11)*(-b*log(f)/x**S(2))**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(2))/x**S(14), x), x, f**a*Gamma(S(13)/2, -b*log(f)/x**S(2))/(S(2)*x**S(13)*(-b*log(f)/x**S(2))**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**m, x), x, f**a*x**(m + S(1))*(-b*log(f)/x**S(3))**(m/S(3) + S(1)/3)*Gamma(-m/S(3) + S(-1)/3, -b*log(f)/x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**S(14), x), x, -b**S(5)*f**a*Gamma(S(-5), -b*log(f)/x**S(3))*log(f)**S(5)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**S(11), x), x, b**S(4)*f**a*Gamma(S(-4), -b*log(f)/x**S(3))*log(f)**S(4)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**S(8), x), x, -b**S(3)*f**a*log(f)**S(3)*Ei(b*log(f)/x**S(3))/S(18) + b**S(2)*f**(a + b/x**S(3))*x**S(3)*log(f)**S(2)/S(18) + b*f**(a + b/x**S(3))*x**S(6)*log(f)/S(18) + f**(a + b/x**S(3))*x**S(9)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**S(5), x), x, -b**S(2)*f**a*log(f)**S(2)*Ei(b*log(f)/x**S(3))/S(6) + b*f**(a + b/x**S(3))*x**S(3)*log(f)/S(6) + f**(a + b/x**S(3))*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**S(2), x), x, -b*f**a*log(f)*Ei(b*log(f)/x**S(3))/S(3) + f**(a + b/x**S(3))*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x, x), x, -f**a*Ei(b*log(f)/x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(4), x), x, -f**(a + b/x**S(3))/(S(3)*b*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(7), x), x, -f**(a + b/x**S(3))/(S(3)*b*x**S(3)*log(f)) + f**(a + b/x**S(3))/(S(3)*b**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(10), x), x, -f**(a + b/x**S(3))/(S(3)*b*x**S(6)*log(f)) + S(2)*f**(a + b/x**S(3))/(S(3)*b**S(2)*x**S(3)*log(f)**S(2)) - S(2)*f**(a + b/x**S(3))/(S(3)*b**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(13), x), x, -f**(a + b/x**S(3))/(S(3)*b*x**S(9)*log(f)) + f**(a + b/x**S(3))/(b**S(2)*x**S(6)*log(f)**S(2)) - S(2)*f**(a + b/x**S(3))/(b**S(3)*x**S(3)*log(f)**S(3)) + S(2)*f**(a + b/x**S(3))/(b**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(16), x), x, -f**a*Gamma(S(5), -b*log(f)/x**S(3))/(S(3)*b**S(5)*log(f)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(19), x), x, f**a*Gamma(S(6), -b*log(f)/x**S(3))/(S(3)*b**S(6)*log(f)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**S(4), x), x, f**a*x**S(5)*(-b*log(f)/x**S(3))**(S(5)/3)*Gamma(S(-5)/3, -b*log(f)/x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x**S(3), x), x, f**a*x**S(4)*(-b*log(f)/x**S(3))**(S(4)/3)*Gamma(S(-4)/3, -b*log(f)/x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))*x, x), x, f**a*x**S(2)*(-b*log(f)/x**S(3))**(S(2)/3)*Gamma(S(-2)/3, -b*log(f)/x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3)), x), x, f**a*x*(-b*log(f)/x**S(3))**(S(1)/3)*Gamma(S(-1)/3, -b*log(f)/x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(2), x), x, f**a*Gamma(S(1)/3, -b*log(f)/x**S(3))/(S(3)*x*(-b*log(f)/x**S(3))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(3), x), x, f**a*Gamma(S(2)/3, -b*log(f)/x**S(3))/(S(3)*x**S(2)*(-b*log(f)/x**S(3))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b/x**S(3))/x**S(5), x), x, f**a*Gamma(S(4)/3, -b*log(f)/x**S(3))/(S(3)*x**S(4)*(-b*log(f)/x**S(3))**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**m, x), x, -f**a*x**(m + S(1))*(-b*x**n*log(f))**(-(m + S(1))/n)*Gamma((m + S(1))/n, -b*x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**S(3), x), x, -f**a*x**S(4)*(-b*x**n*log(f))**(-S(4)/n)*Gamma(S(4)/n, -b*x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**S(2), x), x, -f**a*x**S(3)*(-b*x**n*log(f))**(-S(3)/n)*Gamma(S(3)/n, -b*x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x, x), x, -f**a*x**S(2)*(-b*x**n*log(f))**(-S(2)/n)*Gamma(S(2)/n, -b*x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n), x), x, -f**a*x*(-b*x**n*log(f))**(-S(1)/n)*Gamma(S(1)/n, -b*x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)/x, x), x, f**a*Ei(b*x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)/x**S(2), x), x, -f**a*(-b*x**n*log(f))**(S(1)/n)*Gamma(-S(1)/n, -b*x**n*log(f))/(n*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)/x**S(3), x), x, -f**a*(-b*x**n*log(f))**(S(2)/n)*Gamma(-S(2)/n, -b*x**n*log(f))/(n*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)/x**S(4), x), x, -f**a*(-b*x**n*log(f))**(S(3)/n)*Gamma(-S(3)/n, -b*x**n*log(f))/(n*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(S(3)*n + S(-1)), x), x, f**(a + b*x**n)*x**(S(2)*n)/(b*n*log(f)) - S(2)*f**(a + b*x**n)*x**n/(b**S(2)*n*log(f)**S(2)) + S(2)*f**(a + b*x**n)/(b**S(3)*n*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(S(2)*n + S(-1)), x), x, f**(a + b*x**n)*x**n/(b*n*log(f)) - f**(a + b*x**n)/(b**S(2)*n*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(n + S(-1)), x), x, f**(a + b*x**n)/(b*n*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)/x, x), x, f**a*Ei(b*x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(-n + S(-1)), x), x, b*f**a*log(f)*Ei(b*x**n*log(f))/n - f**(a + b*x**n)*x**(-n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(-S(2)*n + S(-1)), x), x, b**S(2)*f**a*log(f)**S(2)*Ei(b*x**n*log(f))/(S(2)*n) - b*f**(a + b*x**n)*x**(-n)*log(f)/(S(2)*n) - f**(a + b*x**n)*x**(-S(2)*n)/(S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(S(5)*n/S(2) + S(-1)), x), x, f**(a + b*x**n)*x**(S(3)*n/S(2))/(b*n*log(f)) - S(3)*f**(a + b*x**n)*x**(n/S(2))/(S(2)*b**S(2)*n*log(f)**S(2)) + S(3)*sqrt(pi)*f**a*erfi(sqrt(b)*x**(n/S(2))*sqrt(log(f)))/(S(4)*b**(S(5)/2)*n*log(f)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(S(3)*n/S(2) + S(-1)), x), x, f**(a + b*x**n)*x**(n/S(2))/(b*n*log(f)) - sqrt(pi)*f**a*erfi(sqrt(b)*x**(n/S(2))*sqrt(log(f)))/(S(2)*b**(S(3)/2)*n*log(f)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(n/S(2) + S(-1)), x), x, sqrt(pi)*f**a*erfi(sqrt(b)*x**(n/S(2))*sqrt(log(f)))/(sqrt(b)*n*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(-n/S(2) + S(-1)), x), x, S(2)*sqrt(pi)*sqrt(b)*f**a*sqrt(log(f))*erfi(sqrt(b)*x**(n/S(2))*sqrt(log(f)))/n - S(2)*f**(a + b*x**n)*x**(-n/S(2))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x**n)*x**(-S(3)*n/S(2) + S(-1)), x), x, S(4)*sqrt(pi)*b**(S(3)/2)*f**a*log(f)**(S(3)/2)*erfi(sqrt(b)*x**(n/S(2))*sqrt(log(f)))/(S(3)*n) - S(4)*b*f**(a + b*x**n)*x**(-n/S(2))*log(f)/(S(3)*n) - S(2)*f**(a + b*x**n)*x**(-S(3)*n/S(2))/(S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(-0.1*x), x), x, -10.0*x*exp(-0.1*x) - 100.0*exp(-0.1*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2))*x**m, x), x, Integral(f**(a**S(2)*c + S(2)*a*b*c*x + b**S(2)*c*x**S(2))*x**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2))*x**S(3), x), x, -sqrt(pi)*a**S(3)*erfi(sqrt(c)*(a + b*x)*sqrt(log(f)))/(S(2)*b**S(4)*sqrt(c)*sqrt(log(f))) + S(3)*a**S(2)*f**(c*(a + b*x)**S(2))/(S(2)*b**S(4)*c*log(f)) - S(3)*a*f**(c*(a + b*x)**S(2))*(a + b*x)/(S(2)*b**S(4)*c*log(f)) + S(3)*sqrt(pi)*a*erfi(sqrt(c)*(a + b*x)*sqrt(log(f)))/(S(4)*b**S(4)*c**(S(3)/2)*log(f)**(S(3)/2)) + f**(c*(a + b*x)**S(2))*(a + b*x)**S(2)/(S(2)*b**S(4)*c*log(f)) - f**(c*(a + b*x)**S(2))/(S(2)*b**S(4)*c**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2))*x**S(2), x), x, sqrt(pi)*a**S(2)*erfi(sqrt(c)*(a + b*x)*sqrt(log(f)))/(S(2)*b**S(3)*sqrt(c)*sqrt(log(f))) - a*f**(c*(a + b*x)**S(2))/(b**S(3)*c*log(f)) + f**(c*(a + b*x)**S(2))*(a + b*x)/(S(2)*b**S(3)*c*log(f)) - sqrt(pi)*erfi(sqrt(c)*(a + b*x)*sqrt(log(f)))/(S(4)*b**S(3)*c**(S(3)/2)*log(f)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2))*x, x), x, -sqrt(pi)*a*erfi(sqrt(c)*(a + b*x)*sqrt(log(f)))/(S(2)*b**S(2)*sqrt(c)*sqrt(log(f))) + f**(c*(a + b*x)**S(2))/(S(2)*b**S(2)*c*log(f)), expand=True, _diff=True, _numerical=True) # long time in rubi_test(1940 is matched before 1909) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2)), x), x, sqrt(pi)*erfi(sqrt(c)*(a + b*x)*sqrt(log(f)))/(S(2)*b*sqrt(c)*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2))/x, x), x, Integral(f**(c*(a + b*x)**S(2))/x, x), expand=True, _diff=True, _numerical=True) # long time in rubi_test(1940 is matched before 1909) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2))/x**S(2), x), x, S(2)*a*b*c*log(f)*Integral(f**(c*(a + b*x)**S(2))/x, x) + sqrt(pi)*b*sqrt(c)*sqrt(log(f))*erfi(sqrt(c)*(a + b*x)*sqrt(log(f))) - f**(c*(a + b*x)**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(2))/x**S(3), x), x, S(2)*a**S(2)*b**S(2)*c**S(2)*log(f)**S(2)*Integral(f**(c*(a + b*x)**S(2))/x, x) + sqrt(pi)*a*b**S(2)*c**(S(3)/2)*log(f)**(S(3)/2)*erfi(sqrt(c)*(a + b*x)*sqrt(log(f))) - a*b*c*f**(c*(a + b*x)**S(2))*log(f)/x + b**S(2)*c*log(f)*Integral(f**(c*(a + b*x)**S(2))/x, x) - f**(c*(a + b*x)**S(2))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(3))*x**m, x), x, Integral(f**(c*(a + b*x)**S(3))*x**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(3))*x**S(2), x), x, -a**S(2)*(a + b*x)*Gamma(S(1)/3, -c*(a + b*x)**S(3)*log(f))/(S(3)*b**S(3)*(-c*(a + b*x)**S(3)*log(f))**(S(1)/3)) + S(2)*a*(a + b*x)**S(2)*Gamma(S(2)/3, -c*(a + b*x)**S(3)*log(f))/(S(3)*b**S(3)*(-c*(a + b*x)**S(3)*log(f))**(S(2)/3)) + f**(c*(a + b*x)**S(3))/(S(3)*b**S(3)*c*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(3))*x, x), x, a*(a + b*x)*Gamma(S(1)/3, -c*(a + b*x)**S(3)*log(f))/(S(3)*b**S(2)*(-c*(a + b*x)**S(3)*log(f))**(S(1)/3)) - (a + b*x)**S(2)*Gamma(S(2)/3, -c*(a + b*x)**S(3)*log(f))/(S(3)*b**S(2)*(-c*(a + b*x)**S(3)*log(f))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(3)), x), x, (-a/S(3) - b*x/S(3))*Gamma(S(1)/3, -c*(a + b*x)**S(3)*log(f))/(b*(-c*(a + b*x)**S(3)*log(f))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(3))/x, x), x, Integral(f**(c*(a + b*x)**S(3))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(3))/x**S(2), x), x, S(3)*a**S(2)*b*c*log(f)*Integral(f**(c*(a + b*x)**S(3))/x, x) - a*b*c*(a + b*x)*Gamma(S(1)/3, -c*(a + b*x)**S(3)*log(f))*log(f)/(-c*(a + b*x)**S(3)*log(f))**(S(1)/3) - b*c*(a + b*x)**S(2)*Gamma(S(2)/3, -c*(a + b*x)**S(3)*log(f))*log(f)/(-c*(a + b*x)**S(3)*log(f))**(S(2)/3) - f**(c*(a + b*x)**S(3))/x, expand=True, _diff=True, _numerical=True) # difference in simplify of sympy and mathematica assert rubi_test(rubi_integrate(f**(c*(a + b*x)**S(3))/x**S(3), x), x, S(9)*a**S(4)*b**S(2)*c**S(2)*log(f)**S(2)*Integral(f**(c*(a + b*x)**S(3))/x, x)/S(2) - S(3)*a**S(3)*b**S(2)*c**S(2)*(a + b*x)*Gamma(S(1)/3, -c*(a + b*x)**S(3)*log(f))*log(f)**S(2)/(S(2)*(-c*(a + b*x)**S(3)*log(f))**(S(1)/3)) - S(3)*a**S(2)*b**S(2)*c**S(2)*(a + b*x)**S(2)*Gamma(S(2)/3, -c*(a + b*x)**S(3)*log(f))*log(f)**S(2)/(S(2)*(-c*(a + b*x)**S(3)*log(f))**(S(2)/3)) - S(3)*a**S(2)*b*c*f**(c*(a + b*x)**S(3))*log(f)/(S(2)*x) + S(3)*a*b**S(2)*c*log(f)*Integral(f**(c*(a + b*x)**S(3))/x, x) - b**S(2)*c*(a + b*x)*Gamma(S(1)/3, -c*(a + b*x)**S(3)*log(f))*log(f)/(S(2)*(-c*(a + b*x)**S(3)*log(f))**(S(1)/3)) - f**(c*(a + b*x)**S(3))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), x, Integral(x**m*exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), x, -a**S(4)*(a + b*x)*Gamma(S(1)/3, -(a + b*x)**S(3))/(S(3)*b**S(5)*(-(a + b*x)**S(3))**(S(1)/3)) + S(4)*a**S(3)*(a + b*x)**S(2)*Gamma(S(2)/3, -(a + b*x)**S(3))/(S(3)*b**S(5)*(-(a + b*x)**S(3))**(S(2)/3)) + S(2)*a**S(2)*exp((a + b*x)**S(3))/b**S(5) + S(4)*a*(a + b*x)**S(4)*Gamma(S(4)/3, -(a + b*x)**S(3))/(S(3)*b**S(5)*(-(a + b*x)**S(3))**(S(4)/3)) - (a + b*x)**S(5)*Gamma(S(5)/3, -(a + b*x)**S(3))/(S(3)*b**S(5)*(-(a + b*x)**S(3))**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), x, a**S(3)*(a + b*x)*Gamma(S(1)/3, -(a + b*x)**S(3))/(S(3)*b**S(4)*(-(a + b*x)**S(3))**(S(1)/3)) - a**S(2)*(a + b*x)**S(2)*Gamma(S(2)/3, -(a + b*x)**S(3))/(b**S(4)*(-(a + b*x)**S(3))**(S(2)/3)) - a*exp((a + b*x)**S(3))/b**S(4) - (a + b*x)**S(4)*Gamma(S(4)/3, -(a + b*x)**S(3))/(S(3)*b**S(4)*(-(a + b*x)**S(3))**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), x, -a**S(2)*(a + b*x)*Gamma(S(1)/3, -(a + b*x)**S(3))/(S(3)*b**S(3)*(-(a + b*x)**S(3))**(S(1)/3)) + S(2)*a*(a + b*x)**S(2)*Gamma(S(2)/3, -(a + b*x)**S(3))/(S(3)*b**S(3)*(-(a + b*x)**S(3))**(S(2)/3)) + exp((a + b*x)**S(3))/(S(3)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), x, a*(a + b*x)*Gamma(S(1)/3, -(a + b*x)**S(3))/(S(3)*b**S(2)*(-(a + b*x)**S(3))**(S(1)/3)) - (a + b*x)**S(2)*Gamma(S(2)/3, -(a + b*x)**S(3))/(S(3)*b**S(2)*(-(a + b*x)**S(3))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), x, (-a/S(3) - b*x/S(3))*Gamma(S(1)/3, -(a + b*x)**S(3))/(b*(-(a + b*x)**S(3))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))/x, x), x, Integral(exp(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(sqrt(S(3)*x + S(5))), x), x, S(2)*sqrt(S(3)*x + S(5))*exp(sqrt(S(3)*x + S(5)))/S(3) - S(2)*exp(sqrt(S(3)*x + S(5)))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))*x**m, x), x, Integral(f**(c/(a + b*x))*x**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))*x**S(4), x), x, -a**S(4)*c*log(f)*Ei(c*log(f)/(a + b*x))/b**S(5) + a**S(4)*f**(c/(a + b*x))*(a + b*x)/b**S(5) + S(2)*a**S(3)*c**S(2)*log(f)**S(2)*Ei(c*log(f)/(a + b*x))/b**S(5) - S(2)*a**S(3)*c*f**(c/(a + b*x))*(a + b*x)*log(f)/b**S(5) - S(2)*a**S(3)*f**(c/(a + b*x))*(a + b*x)**S(2)/b**S(5) - a**S(2)*c**S(3)*log(f)**S(3)*Ei(c*log(f)/(a + b*x))/b**S(5) + a**S(2)*c**S(2)*f**(c/(a + b*x))*(a + b*x)*log(f)**S(2)/b**S(5) + a**S(2)*c*f**(c/(a + b*x))*(a + b*x)**S(2)*log(f)/b**S(5) + S(2)*a**S(2)*f**(c/(a + b*x))*(a + b*x)**S(3)/b**S(5) - S(4)*a*c**S(4)*Gamma(S(-4), -c*log(f)/(a + b*x))*log(f)**S(4)/b**S(5) - c**S(5)*Gamma(S(-5), -c*log(f)/(a + b*x))*log(f)**S(5)/b**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))*x**S(3), x), x, a**S(3)*c*log(f)*Ei(c*log(f)/(a + b*x))/b**S(4) - a**S(3)*f**(c/(a + b*x))*(a + b*x)/b**S(4) - S(3)*a**S(2)*c**S(2)*log(f)**S(2)*Ei(c*log(f)/(a + b*x))/(S(2)*b**S(4)) + S(3)*a**S(2)*c*f**(c/(a + b*x))*(a + b*x)*log(f)/(S(2)*b**S(4)) + S(3)*a**S(2)*f**(c/(a + b*x))*(a + b*x)**S(2)/(S(2)*b**S(4)) + a*c**S(3)*log(f)**S(3)*Ei(c*log(f)/(a + b*x))/(S(2)*b**S(4)) - a*c**S(2)*f**(c/(a + b*x))*(a + b*x)*log(f)**S(2)/(S(2)*b**S(4)) - a*c*f**(c/(a + b*x))*(a + b*x)**S(2)*log(f)/(S(2)*b**S(4)) - a*f**(c/(a + b*x))*(a + b*x)**S(3)/b**S(4) + c**S(4)*Gamma(S(-4), -c*log(f)/(a + b*x))*log(f)**S(4)/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))*x**S(2), x), x, -a**S(2)*c*log(f)*Ei(c*log(f)/(a + b*x))/b**S(3) + a**S(2)*f**(c/(a + b*x))*(a + b*x)/b**S(3) + a*c**S(2)*log(f)**S(2)*Ei(c*log(f)/(a + b*x))/b**S(3) - a*c*f**(c/(a + b*x))*(a + b*x)*log(f)/b**S(3) - a*f**(c/(a + b*x))*(a + b*x)**S(2)/b**S(3) - c**S(3)*log(f)**S(3)*Ei(c*log(f)/(a + b*x))/(S(6)*b**S(3)) + c**S(2)*f**(c/(a + b*x))*(a + b*x)*log(f)**S(2)/(S(6)*b**S(3)) + c*f**(c/(a + b*x))*(a + b*x)**S(2)*log(f)/(S(6)*b**S(3)) + f**(c/(a + b*x))*(a + b*x)**S(3)/(S(3)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))*x, x), x, a*c*log(f)*Ei(c*log(f)/(a + b*x))/b**S(2) - a*f**(c/(a + b*x))*(a + b*x)/b**S(2) - c**S(2)*log(f)**S(2)*Ei(c*log(f)/(a + b*x))/(S(2)*b**S(2)) + c*f**(c/(a + b*x))*(a + b*x)*log(f)/(S(2)*b**S(2)) + f**(c/(a + b*x))*(a + b*x)**S(2)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)), x), x, -c*log(f)*Ei(c*log(f)/(a + b*x))/b + f**(c/(a + b*x))*(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))/x, x), x, f**(c/a)*Ei(-b*c*x*log(f)/(a*(a + b*x))) - Ei(c*log(f)/(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))/x**S(2), x), x, -f**(c/(a + b*x))/x - b*f**(c/(a + b*x))/a - b*c*f**(c/a)*log(f)*Ei(-b*c*x*log(f)/(a*(a + b*x)))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x))/x**S(3), x), x, -f**(c/(a + b*x))/(S(2)*x**S(2)) + b**S(2)*f**(c/(a + b*x))/(S(2)*a**S(2)) + b*c*f**(c/(a + b*x))*log(f)/(S(2)*a**S(2)*x) + b**S(2)*c*f**(c/a)*log(f)*Ei(-b*c*x*log(f)/(a*(a + b*x)))/a**S(3) + b**S(2)*c*f**(c/(a + b*x))*log(f)/(S(2)*a**S(3)) + b**S(2)*c**S(2)*f**(c/a)*log(f)**S(2)*Ei(-b*c*x*log(f)/(a*(a + b*x)))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))*x**m, x), x, Integral(f**(c/(a + b*x)**S(2))*x**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))*x**S(4), x), x, -sqrt(pi)*a**S(4)*sqrt(c)*sqrt(log(f))*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/b**S(5) + a**S(4)*f**(c/(a + b*x)**S(2))*(a + b*x)/b**S(5) + S(2)*a**S(3)*c*log(f)*Ei(c*log(f)/(a + b*x)**S(2))/b**S(5) - S(2)*a**S(3)*f**(c/(a + b*x)**S(2))*(a + b*x)**S(2)/b**S(5) - S(4)*sqrt(pi)*a**S(2)*c**(S(3)/2)*log(f)**(S(3)/2)*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/b**S(5) + S(4)*a**S(2)*c*f**(c/(a + b*x)**S(2))*(a + b*x)*log(f)/b**S(5) + S(2)*a**S(2)*f**(c/(a + b*x)**S(2))*(a + b*x)**S(3)/b**S(5) + a*c**S(2)*log(f)**S(2)*Ei(c*log(f)/(a + b*x)**S(2))/b**S(5) - a*c*f**(c/(a + b*x)**S(2))*(a + b*x)**S(2)*log(f)/b**S(5) - a*f**(c/(a + b*x)**S(2))*(a + b*x)**S(4)/b**S(5) - S(4)*sqrt(pi)*c**(S(5)/2)*log(f)**(S(5)/2)*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/(S(15)*b**S(5)) + S(4)*c**S(2)*f**(c/(a + b*x)**S(2))*(a + b*x)*log(f)**S(2)/(S(15)*b**S(5)) + S(2)*c*f**(c/(a + b*x)**S(2))*(a + b*x)**S(3)*log(f)/(S(15)*b**S(5)) + f**(c/(a + b*x)**S(2))*(a + b*x)**S(5)/(S(5)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))*x**S(3), x), x, sqrt(pi)*a**S(3)*sqrt(c)*sqrt(log(f))*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/b**S(4) - a**S(3)*f**(c/(a + b*x)**S(2))*(a + b*x)/b**S(4) - S(3)*a**S(2)*c*log(f)*Ei(c*log(f)/(a + b*x)**S(2))/(S(2)*b**S(4)) + S(3)*a**S(2)*f**(c/(a + b*x)**S(2))*(a + b*x)**S(2)/(S(2)*b**S(4)) + S(2)*sqrt(pi)*a*c**(S(3)/2)*log(f)**(S(3)/2)*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/b**S(4) - S(2)*a*c*f**(c/(a + b*x)**S(2))*(a + b*x)*log(f)/b**S(4) - a*f**(c/(a + b*x)**S(2))*(a + b*x)**S(3)/b**S(4) - c**S(2)*log(f)**S(2)*Ei(c*log(f)/(a + b*x)**S(2))/(S(4)*b**S(4)) + c*f**(c/(a + b*x)**S(2))*(a + b*x)**S(2)*log(f)/(S(4)*b**S(4)) + f**(c/(a + b*x)**S(2))*(a + b*x)**S(4)/(S(4)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))*x**S(2), x), x, -sqrt(pi)*a**S(2)*sqrt(c)*sqrt(log(f))*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/b**S(3) + a**S(2)*f**(c/(a + b*x)**S(2))*(a + b*x)/b**S(3) + a*c*log(f)*Ei(c*log(f)/(a + b*x)**S(2))/b**S(3) - a*f**(c/(a + b*x)**S(2))*(a + b*x)**S(2)/b**S(3) - S(2)*sqrt(pi)*c**(S(3)/2)*log(f)**(S(3)/2)*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/(S(3)*b**S(3)) + S(2)*c*f**(c/(a + b*x)**S(2))*(a + b*x)*log(f)/(S(3)*b**S(3)) + f**(c/(a + b*x)**S(2))*(a + b*x)**S(3)/(S(3)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))*x, x), x, sqrt(pi)*a*sqrt(c)*sqrt(log(f))*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/b**S(2) - a*f**(c/(a + b*x)**S(2))*(a + b*x)/b**S(2) - c*log(f)*Ei(c*log(f)/(a + b*x)**S(2))/(S(2)*b**S(2)) + f**(c/(a + b*x)**S(2))*(a + b*x)**S(2)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2)), x), x, -sqrt(pi)*sqrt(c)*sqrt(log(f))*erfi(sqrt(c)*sqrt(log(f))/(a + b*x))/b + f**(c/(a + b*x)**S(2))*(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))/x, x), x, Integral(f**(c/(a + b*x)**S(2))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))/x**S(2), x), x, Integral(f**(c/(a + b*x)**S(2))/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(2))/x**S(3), x), x, Integral(f**(c/(a + b*x)**S(2))/x**S(3), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))*x**m, x), x, Integral(f**(c/(a + b*x)**S(3))*x**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))*x**S(4), x), x, a**S(4)*(-c*log(f)/(a + b*x)**S(3))**(S(1)/3)*(a + b*x)*Gamma(S(-1)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(5)) - S(4)*a**S(3)*(-c*log(f)/(a + b*x)**S(3))**(S(2)/3)*(a + b*x)**S(2)*Gamma(S(-2)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(5)) - S(2)*a**S(2)*c*log(f)*Ei(c*log(f)/(a + b*x)**S(3))/b**S(5) + S(2)*a**S(2)*f**(c/(a + b*x)**S(3))*(a + b*x)**S(3)/b**S(5) - S(4)*a*(-c*log(f)/(a + b*x)**S(3))**(S(4)/3)*(a + b*x)**S(4)*Gamma(S(-4)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(5)) + (-c*log(f)/(a + b*x)**S(3))**(S(5)/3)*(a + b*x)**S(5)*Gamma(S(-5)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))*x**S(3), x), x, -a**S(3)*(-c*log(f)/(a + b*x)**S(3))**(S(1)/3)*(a + b*x)*Gamma(S(-1)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(4)) + a**S(2)*(-c*log(f)/(a + b*x)**S(3))**(S(2)/3)*(a + b*x)**S(2)*Gamma(S(-2)/3, -c*log(f)/(a + b*x)**S(3))/b**S(4) + a*c*log(f)*Ei(c*log(f)/(a + b*x)**S(3))/b**S(4) - a*f**(c/(a + b*x)**S(3))*(a + b*x)**S(3)/b**S(4) + (-c*log(f)/(a + b*x)**S(3))**(S(4)/3)*(a + b*x)**S(4)*Gamma(S(-4)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))*x**S(2), x), x, a**S(2)*(-c*log(f)/(a + b*x)**S(3))**(S(1)/3)*(a + b*x)*Gamma(S(-1)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(3)) - S(2)*a*(-c*log(f)/(a + b*x)**S(3))**(S(2)/3)*(a + b*x)**S(2)*Gamma(S(-2)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(3)) - c*log(f)*Ei(c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(3)) + f**(c/(a + b*x)**S(3))*(a + b*x)**S(3)/(S(3)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))*x, x), x, -a*(-c*log(f)/(a + b*x)**S(3))**(S(1)/3)*(a + b*x)*Gamma(S(-1)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(2)) + (-c*log(f)/(a + b*x)**S(3))**(S(2)/3)*(a + b*x)**S(2)*Gamma(S(-2)/3, -c*log(f)/(a + b*x)**S(3))/(S(3)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3)), x), x, (-c*log(f)/(a + b*x)**S(3))**(S(1)/3)*(a/S(3) + b*x/S(3))*Gamma(S(-1)/3, -c*log(f)/(a + b*x)**S(3))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))/x, x), x, Integral(f**(c/(a + b*x)**S(3))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))/x**S(2), x), x, Integral(f**(c/(a + b*x)**S(3))/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c/(a + b*x)**S(3))/x**S(3), x), x, Integral(f**(c/(a + b*x)**S(3))/x**S(3), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n)*x**m, x), x, Integral(f**(c*(a + b*x)**n)*x**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n)*x**S(3), x), x, a**S(3)*(-c*(a + b*x)**n*log(f))**(-S(1)/n)*(a + b*x)*Gamma(S(1)/n, -c*(a + b*x)**n*log(f))/(b**S(4)*n) - S(3)*a**S(2)*(-c*(a + b*x)**n*log(f))**(-S(2)/n)*(a + b*x)**S(2)*Gamma(S(2)/n, -c*(a + b*x)**n*log(f))/(b**S(4)*n) + S(3)*a*(-c*(a + b*x)**n*log(f))**(-S(3)/n)*(a + b*x)**S(3)*Gamma(S(3)/n, -c*(a + b*x)**n*log(f))/(b**S(4)*n) - (-c*(a + b*x)**n*log(f))**(-S(4)/n)*(a + b*x)**S(4)*Gamma(S(4)/n, -c*(a + b*x)**n*log(f))/(b**S(4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n)*x**S(2), x), x, -a**S(2)*(-c*(a + b*x)**n*log(f))**(-S(1)/n)*(a + b*x)*Gamma(S(1)/n, -c*(a + b*x)**n*log(f))/(b**S(3)*n) + S(2)*a*(-c*(a + b*x)**n*log(f))**(-S(2)/n)*(a + b*x)**S(2)*Gamma(S(2)/n, -c*(a + b*x)**n*log(f))/(b**S(3)*n) - (-c*(a + b*x)**n*log(f))**(-S(3)/n)*(a + b*x)**S(3)*Gamma(S(3)/n, -c*(a + b*x)**n*log(f))/(b**S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n)*x, x), x, a*(-c*(a + b*x)**n*log(f))**(-S(1)/n)*(a + b*x)*Gamma(S(1)/n, -c*(a + b*x)**n*log(f))/(b**S(2)*n) - (-c*(a + b*x)**n*log(f))**(-S(2)/n)*(a + b*x)**S(2)*Gamma(S(2)/n, -c*(a + b*x)**n*log(f))/(b**S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n), x), x, (-c*(a + b*x)**n*log(f))**(-S(1)/n)*(-a - b*x)*Gamma(S(1)/n, -c*(a + b*x)**n*log(f))/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n)/x, x), x, Integral(f**(c*(a + b*x)**n)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n)/x**S(2), x), x, Integral(f**(c*(a + b*x)**n)/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(c*(a + b*x)**n)/x**S(3), x), x, Integral(f**(c*(a + b*x)**n)/x**S(3), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**m, x), x, -F**a*(-b*(c + d*x)**S(2)*log(F))**(-m/S(2) + S(-1)/2)*(c + d*x)**(m + S(1))*Gamma(m/S(2) + S(1)/2, -b*(c + d*x)**S(2)*log(F))/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(11), x), x, -F**a*Gamma(S(6), -b*(c + d*x)**S(2)*log(F))/(S(2)*b**S(6)*d*log(F)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(9), x), x, F**a*Gamma(S(5), -b*(c + d*x)**S(2)*log(F))/(S(2)*b**S(5)*d*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(7), x), x, F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(6)/(S(2)*b*d*log(F)) - S(3)*F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(4)/(S(2)*b**S(2)*d*log(F)**S(2)) + S(3)*F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(2)/(b**S(3)*d*log(F)**S(3)) - S(3)*F**(a + b*(c + d*x)**S(2))/(b**S(4)*d*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(5), x), x, F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(4)/(S(2)*b*d*log(F)) - F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(2)/(b**S(2)*d*log(F)**S(2)) + F**(a + b*(c + d*x)**S(2))/(b**S(3)*d*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(3), x), x, F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(2)/(S(2)*b*d*log(F)) - F**(a + b*(c + d*x)**S(2))/(S(2)*b**S(2)*d*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x), x), x, F**(a + b*(c + d*x)**S(2))/(S(2)*b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x), x), x, F**a*Ei(b*(c + d*x)**S(2)*log(F))/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(3), x), x, F**a*b*log(F)*Ei(b*(c + d*x)**S(2)*log(F))/(S(2)*d) - F**(a + b*(c + d*x)**S(2))/(S(2)*d*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(5), x), x, F**a*b**S(2)*log(F)**S(2)*Ei(b*(c + d*x)**S(2)*log(F))/(S(4)*d) - F**(a + b*(c + d*x)**S(2))*b*log(F)/(S(4)*d*(c + d*x)**S(2)) - F**(a + b*(c + d*x)**S(2))/(S(4)*d*(c + d*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(7), x), x, F**a*b**S(3)*log(F)**S(3)*Ei(b*(c + d*x)**S(2)*log(F))/(S(12)*d) - F**(a + b*(c + d*x)**S(2))*b**S(2)*log(F)**S(2)/(S(12)*d*(c + d*x)**S(2)) - F**(a + b*(c + d*x)**S(2))*b*log(F)/(S(12)*d*(c + d*x)**S(4)) - F**(a + b*(c + d*x)**S(2))/(S(6)*d*(c + d*x)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(9), x), x, -F**a*b**S(4)*Gamma(S(-4), -b*(c + d*x)**S(2)*log(F))*log(F)**S(4)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(11), x), x, F**a*b**S(5)*Gamma(S(-5), -b*(c + d*x)**S(2)*log(F))*log(F)**S(5)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(12), x), x, -F**a*(c + d*x)**S(13)*Gamma(S(13)/2, -b*(c + d*x)**S(2)*log(F))/(S(2)*d*(-b*(c + d*x)**S(2)*log(F))**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(10), x), x, -F**a*(c + d*x)**S(11)*Gamma(S(11)/2, -b*(c + d*x)**S(2)*log(F))/(S(2)*d*(-b*(c + d*x)**S(2)*log(F))**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(8), x), x, S(105)*sqrt(pi)*F**a*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(32)*b**(S(9)/2)*d*log(F)**(S(9)/2)) + F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(7)/(S(2)*b*d*log(F)) - S(7)*F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(5)/(S(4)*b**S(2)*d*log(F)**S(2)) + S(35)*F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(3)/(S(8)*b**S(3)*d*log(F)**S(3)) - S(105)*F**(a + b*(c + d*x)**S(2))*(c + d*x)/(S(16)*b**S(4)*d*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(6), x), x, -S(15)*sqrt(pi)*F**a*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(16)*b**(S(7)/2)*d*log(F)**(S(7)/2)) + F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(5)/(S(2)*b*d*log(F)) - S(5)*F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(3)/(S(4)*b**S(2)*d*log(F)**S(2)) + S(15)*F**(a + b*(c + d*x)**S(2))*(c + d*x)/(S(8)*b**S(3)*d*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(4), x), x, S(3)*sqrt(pi)*F**a*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(8)*b**(S(5)/2)*d*log(F)**(S(5)/2)) + F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(3)/(S(2)*b*d*log(F)) - S(3)*F**(a + b*(c + d*x)**S(2))*(c + d*x)/(S(4)*b**S(2)*d*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(c + d*x)**S(2), x), x, -sqrt(pi)*F**a*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(4)*b**(S(3)/2)*d*log(F)**(S(3)/2)) + F**(a + b*(c + d*x)**S(2))*(c + d*x)/(S(2)*b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2)), x), x, sqrt(pi)*F**a*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*sqrt(b)*d*sqrt(log(F))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(2), x), x, sqrt(pi)*F**a*sqrt(b)*sqrt(log(F))*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/d - F**(a + b*(c + d*x)**S(2))/(d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(4), x), x, S(2)*sqrt(pi)*F**a*b**(S(3)/2)*log(F)**(S(3)/2)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(3)*d) - S(2)*F**(a + b*(c + d*x)**S(2))*b*log(F)/(S(3)*d*(c + d*x)) - F**(a + b*(c + d*x)**S(2))/(S(3)*d*(c + d*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(6), x), x, S(4)*sqrt(pi)*F**a*b**(S(5)/2)*log(F)**(S(5)/2)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(15)*d) - S(4)*F**(a + b*(c + d*x)**S(2))*b**S(2)*log(F)**S(2)/(S(15)*d*(c + d*x)) - S(2)*F**(a + b*(c + d*x)**S(2))*b*log(F)/(S(15)*d*(c + d*x)**S(3)) - F**(a + b*(c + d*x)**S(2))/(S(5)*d*(c + d*x)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(8), x), x, S(8)*sqrt(pi)*F**a*b**(S(7)/2)*log(F)**(S(7)/2)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(105)*d) - S(8)*F**(a + b*(c + d*x)**S(2))*b**S(3)*log(F)**S(3)/(S(105)*d*(c + d*x)) - S(4)*F**(a + b*(c + d*x)**S(2))*b**S(2)*log(F)**S(2)/(S(105)*d*(c + d*x)**S(3)) - S(2)*F**(a + b*(c + d*x)**S(2))*b*log(F)/(S(35)*d*(c + d*x)**S(5)) - F**(a + b*(c + d*x)**S(2))/(S(7)*d*(c + d*x)**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(10), x), x, -F**a*(-b*(c + d*x)**S(2)*log(F))**(S(9)/2)*Gamma(S(-9)/2, -b*(c + d*x)**S(2)*log(F))/(S(2)*d*(c + d*x)**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(c + d*x)**S(12), x), x, -F**a*(-b*(c + d*x)**S(2)*log(F))**(S(11)/2)*Gamma(S(-11)/2, -b*(c + d*x)**S(2)*log(F))/(S(2)*d*(c + d*x)**S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**m, x), x, -F**a*(-b*(c + d*x)**S(3)*log(F))**(-m/S(3) + S(-1)/3)*(c + d*x)**(m + S(1))*Gamma(m/S(3) + S(1)/3, -b*(c + d*x)**S(3)*log(F))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(17), x), x, -F**a*Gamma(S(6), -b*(c + d*x)**S(3)*log(F))/(S(3)*b**S(6)*d*log(F)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(14), x), x, F**a*Gamma(S(5), -b*(c + d*x)**S(3)*log(F))/(S(3)*b**S(5)*d*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(11), x), x, F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(9)/(S(3)*b*d*log(F)) - F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(6)/(b**S(2)*d*log(F)**S(2)) + S(2)*F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(3)/(b**S(3)*d*log(F)**S(3)) - S(2)*F**(a + b*(c + d*x)**S(3))/(b**S(4)*d*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(8), x), x, F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(6)/(S(3)*b*d*log(F)) - S(2)*F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(3)/(S(3)*b**S(2)*d*log(F)**S(2)) + S(2)*F**(a + b*(c + d*x)**S(3))/(S(3)*b**S(3)*d*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(5), x), x, F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(3)/(S(3)*b*d*log(F)) - F**(a + b*(c + d*x)**S(3))/(S(3)*b**S(2)*d*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(2), x), x, F**(a + b*(c + d*x)**S(3))/(S(3)*b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x), x), x, F**a*Ei(b*(c + d*x)**S(3)*log(F))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(4), x), x, F**a*b*log(F)*Ei(b*(c + d*x)**S(3)*log(F))/(S(3)*d) - F**(a + b*(c + d*x)**S(3))/(S(3)*d*(c + d*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(7), x), x, F**a*b**S(2)*log(F)**S(2)*Ei(b*(c + d*x)**S(3)*log(F))/(S(6)*d) - F**(a + b*(c + d*x)**S(3))*b*log(F)/(S(6)*d*(c + d*x)**S(3)) - F**(a + b*(c + d*x)**S(3))/(S(6)*d*(c + d*x)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(10), x), x, F**a*b**S(3)*log(F)**S(3)*Ei(b*(c + d*x)**S(3)*log(F))/(S(18)*d) - F**(a + b*(c + d*x)**S(3))*b**S(2)*log(F)**S(2)/(S(18)*d*(c + d*x)**S(3)) - F**(a + b*(c + d*x)**S(3))*b*log(F)/(S(18)*d*(c + d*x)**S(6)) - F**(a + b*(c + d*x)**S(3))/(S(9)*d*(c + d*x)**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(13), x), x, -F**a*b**S(4)*Gamma(S(-4), -b*(c + d*x)**S(3)*log(F))*log(F)**S(4)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(16), x), x, F**a*b**S(5)*Gamma(S(-5), -b*(c + d*x)**S(3)*log(F))*log(F)**S(5)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x)**S(3), x), x, -F**a*(c + d*x)**S(4)*Gamma(S(4)/3, -b*(c + d*x)**S(3)*log(F))/(S(3)*d*(-b*(c + d*x)**S(3)*log(F))**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))*(c + d*x), x), x, -F**a*(c + d*x)**S(2)*Gamma(S(2)/3, -b*(c + d*x)**S(3)*log(F))/(S(3)*d*(-b*(c + d*x)**S(3)*log(F))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3)), x), x, -F**a*(c + d*x)*Gamma(S(1)/3, -b*(c + d*x)**S(3)*log(F))/(S(3)*d*(-b*(c + d*x)**S(3)*log(F))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(2), x), x, -F**a*(-b*(c + d*x)**S(3)*log(F))**(S(1)/3)*Gamma(S(-1)/3, -b*(c + d*x)**S(3)*log(F))/(S(3)*d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(3), x), x, -F**a*(-b*(c + d*x)**S(3)*log(F))**(S(2)/3)*Gamma(S(-2)/3, -b*(c + d*x)**S(3)*log(F))/(S(3)*d*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(3))/(c + d*x)**S(5), x), x, -F**a*(-b*(c + d*x)**S(3)*log(F))**(S(4)/3)*Gamma(S(-4)/3, -b*(c + d*x)**S(3)*log(F))/(S(3)*d*(c + d*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*sqrt(c + d*x)), x), x, S(2)*f**(a + b*sqrt(c + d*x))*sqrt(c + d*x)/(b*d*log(f)) - S(2)*f**(a + b*sqrt(c + d*x))/(b**S(2)*d*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*(c + d*x)**(S(1)/3)), x), x, S(3)*f**(a + b*(c + d*x)**(S(1)/3))*(c + d*x)**(S(2)/3)/(b*d*log(f)) - S(6)*f**(a + b*(c + d*x)**(S(1)/3))*(c + d*x)**(S(1)/3)/(b**S(2)*d*log(f)**S(2)) + S(6)*f**(a + b*(c + d*x)**(S(1)/3))/(b**S(3)*d*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))*(c + d*x)**m, x), x, F**a*(-b*log(F)/(c + d*x))**(m + S(1))*(c + d*x)**(m + S(1))*Gamma(-m + S(-1), -b*log(F)/(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))*(c + d*x)**S(4), x), x, -F**a*b**S(5)*Gamma(S(-5), -b*log(F)/(c + d*x))*log(F)**S(5)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))*(c + d*x)**S(3), x), x, F**a*b**S(4)*Gamma(S(-4), -b*log(F)/(c + d*x))*log(F)**S(4)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))*(c + d*x)**S(2), x), x, -F**a*b**S(3)*log(F)**S(3)*Ei(b*log(F)/(c + d*x))/(S(6)*d) + F**(a + b/(c + d*x))*b**S(2)*(c + d*x)*log(F)**S(2)/(S(6)*d) + F**(a + b/(c + d*x))*b*(c + d*x)**S(2)*log(F)/(S(6)*d) + F**(a + b/(c + d*x))*(c + d*x)**S(3)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))*(c + d*x), x), x, -F**a*b**S(2)*log(F)**S(2)*Ei(b*log(F)/(c + d*x))/(S(2)*d) + F**(a + b/(c + d*x))*b*(c + d*x)*log(F)/(S(2)*d) + F**(a + b/(c + d*x))*(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)), x), x, -F**a*b*log(F)*Ei(b*log(F)/(c + d*x))/d + F**(a + b/(c + d*x))*(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(c + d*x), x), x, -F**a*Ei(b*log(F)/(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(c + d*x)**S(2), x), x, -F**(a + b/(c + d*x))/(b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(c + d*x)**S(3), x), x, -F**(a + b/(c + d*x))/(b*d*(c + d*x)*log(F)) + F**(a + b/(c + d*x))/(b**S(2)*d*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(c + d*x)**S(4), x), x, -F**(a + b/(c + d*x))/(b*d*(c + d*x)**S(2)*log(F)) + S(2)*F**(a + b/(c + d*x))/(b**S(2)*d*(c + d*x)*log(F)**S(2)) - S(2)*F**(a + b/(c + d*x))/(b**S(3)*d*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(c + d*x)**S(5), x), x, -F**(a + b/(c + d*x))/(b*d*(c + d*x)**S(3)*log(F)) + S(3)*F**(a + b/(c + d*x))/(b**S(2)*d*(c + d*x)**S(2)*log(F)**S(2)) - S(6)*F**(a + b/(c + d*x))/(b**S(3)*d*(c + d*x)*log(F)**S(3)) + S(6)*F**(a + b/(c + d*x))/(b**S(4)*d*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(c + d*x)**S(6), x), x, -F**a*Gamma(S(5), -b*log(F)/(c + d*x))/(b**S(5)*d*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(c + d*x)**S(7), x), x, F**a*Gamma(S(6), -b*log(F)/(c + d*x))/(b**S(6)*d*log(F)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**m, x), x, F**a*(-b*log(F)/(c + d*x)**S(2))**(m/S(2) + S(1)/2)*(c + d*x)**(m + S(1))*Gamma(-m/S(2) + S(-1)/2, -b*log(F)/(c + d*x)**S(2))/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(9), x), x, -F**a*b**S(5)*Gamma(S(-5), -b*log(F)/(c + d*x)**S(2))*log(F)**S(5)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(7), x), x, F**a*b**S(4)*Gamma(S(-4), -b*log(F)/(c + d*x)**S(2))*log(F)**S(4)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(5), x), x, -F**a*b**S(3)*log(F)**S(3)*Ei(b*log(F)/(c + d*x)**S(2))/(S(12)*d) + F**(a + b/(c + d*x)**S(2))*b**S(2)*(c + d*x)**S(2)*log(F)**S(2)/(S(12)*d) + F**(a + b/(c + d*x)**S(2))*b*(c + d*x)**S(4)*log(F)/(S(12)*d) + F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(6)/(S(6)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(3), x), x, -F**a*b**S(2)*log(F)**S(2)*Ei(b*log(F)/(c + d*x)**S(2))/(S(4)*d) + F**(a + b/(c + d*x)**S(2))*b*(c + d*x)**S(2)*log(F)/(S(4)*d) + F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(4)/(S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x), x), x, -F**a*b*log(F)*Ei(b*log(F)/(c + d*x)**S(2))/(S(2)*d) + F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x), x), x, -F**a*Ei(b*log(F)/(c + d*x)**S(2))/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(3), x), x, -F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(5), x), x, -F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*(c + d*x)**S(2)*log(F)) + F**(a + b/(c + d*x)**S(2))/(S(2)*b**S(2)*d*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(7), x), x, -F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*(c + d*x)**S(4)*log(F)) + F**(a + b/(c + d*x)**S(2))/(b**S(2)*d*(c + d*x)**S(2)*log(F)**S(2)) - F**(a + b/(c + d*x)**S(2))/(b**S(3)*d*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(9), x), x, -F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*(c + d*x)**S(6)*log(F)) + S(3)*F**(a + b/(c + d*x)**S(2))/(S(2)*b**S(2)*d*(c + d*x)**S(4)*log(F)**S(2)) - S(3)*F**(a + b/(c + d*x)**S(2))/(b**S(3)*d*(c + d*x)**S(2)*log(F)**S(3)) + S(3)*F**(a + b/(c + d*x)**S(2))/(b**S(4)*d*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(11), x), x, -F**a*Gamma(S(5), -b*log(F)/(c + d*x)**S(2))/(S(2)*b**S(5)*d*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(13), x), x, F**a*Gamma(S(6), -b*log(F)/(c + d*x)**S(2))/(S(2)*b**S(6)*d*log(F)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(10), x), x, F**a*(-b*log(F)/(c + d*x)**S(2))**(S(11)/2)*(c + d*x)**S(11)*Gamma(S(-11)/2, -b*log(F)/(c + d*x)**S(2))/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(8), x), x, F**a*(-b*log(F)/(c + d*x)**S(2))**(S(9)/2)*(c + d*x)**S(9)*Gamma(S(-9)/2, -b*log(F)/(c + d*x)**S(2))/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(6), x), x, -S(8)*sqrt(pi)*F**a*b**(S(7)/2)*log(F)**(S(7)/2)*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(105)*d) + S(8)*F**(a + b/(c + d*x)**S(2))*b**S(3)*(c + d*x)*log(F)**S(3)/(S(105)*d) + S(4)*F**(a + b/(c + d*x)**S(2))*b**S(2)*(c + d*x)**S(3)*log(F)**S(2)/(S(105)*d) + S(2)*F**(a + b/(c + d*x)**S(2))*b*(c + d*x)**S(5)*log(F)/(S(35)*d) + F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(7)/(S(7)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(4), x), x, -S(4)*sqrt(pi)*F**a*b**(S(5)/2)*log(F)**(S(5)/2)*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(15)*d) + S(4)*F**(a + b/(c + d*x)**S(2))*b**S(2)*(c + d*x)*log(F)**S(2)/(S(15)*d) + S(2)*F**(a + b/(c + d*x)**S(2))*b*(c + d*x)**S(3)*log(F)/(S(15)*d) + F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(5)/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(2), x), x, -S(2)*sqrt(pi)*F**a*b**(S(3)/2)*log(F)**(S(3)/2)*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(3)*d) + S(2)*F**(a + b/(c + d*x)**S(2))*b*(c + d*x)*log(F)/(S(3)*d) + F**(a + b/(c + d*x)**S(2))*(c + d*x)**S(3)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2)), x), x, -sqrt(pi)*F**a*sqrt(b)*sqrt(log(F))*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/d + F**(a + b/(c + d*x)**S(2))*(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(2), x), x, -sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(2)*sqrt(b)*d*sqrt(log(F))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(4), x), x, sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(4)*b**(S(3)/2)*d*log(F)**(S(3)/2)) - F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*(c + d*x)*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(6), x), x, -S(3)*sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(8)*b**(S(5)/2)*d*log(F)**(S(5)/2)) - F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*(c + d*x)**S(3)*log(F)) + S(3)*F**(a + b/(c + d*x)**S(2))/(S(4)*b**S(2)*d*(c + d*x)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(8), x), x, S(15)*sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(16)*b**(S(7)/2)*d*log(F)**(S(7)/2)) - F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*(c + d*x)**S(5)*log(F)) + S(5)*F**(a + b/(c + d*x)**S(2))/(S(4)*b**S(2)*d*(c + d*x)**S(3)*log(F)**S(2)) - S(15)*F**(a + b/(c + d*x)**S(2))/(S(8)*b**S(3)*d*(c + d*x)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(10), x), x, -S(105)*sqrt(pi)*F**a*erfi(sqrt(b)*sqrt(log(F))/(c + d*x))/(S(32)*b**(S(9)/2)*d*log(F)**(S(9)/2)) - F**(a + b/(c + d*x)**S(2))/(S(2)*b*d*(c + d*x)**S(7)*log(F)) + S(7)*F**(a + b/(c + d*x)**S(2))/(S(4)*b**S(2)*d*(c + d*x)**S(5)*log(F)**S(2)) - S(35)*F**(a + b/(c + d*x)**S(2))/(S(8)*b**S(3)*d*(c + d*x)**S(3)*log(F)**S(3)) + S(105)*F**(a + b/(c + d*x)**S(2))/(S(16)*b**S(4)*d*(c + d*x)*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(12), x), x, F**a*Gamma(S(11)/2, -b*log(F)/(c + d*x)**S(2))/(S(2)*d*(-b*log(F)/(c + d*x)**S(2))**(S(11)/2)*(c + d*x)**S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(2))/(c + d*x)**S(14), x), x, F**a*Gamma(S(13)/2, -b*log(F)/(c + d*x)**S(2))/(S(2)*d*(-b*log(F)/(c + d*x)**S(2))**(S(13)/2)*(c + d*x)**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x)**m, x), x, F**a*(-b*log(F)/(c + d*x)**S(3))**(m/S(3) + S(1)/3)*(c + d*x)**(m + S(1))*Gamma(-m/S(3) + S(-1)/3, -b*log(F)/(c + d*x)**S(3))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(14), x), x, -F**a*b**S(5)*Gamma(S(-5), -b*log(F)/(c + d*x)**S(3))*log(F)**S(5)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(11), x), x, F**a*b**S(4)*Gamma(S(-4), -b*log(F)/(c + d*x)**S(3))*log(F)**S(4)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(8), x), x, -F**a*b**S(3)*log(F)**S(3)*Ei(b*log(F)/(c + d*x)**S(3))/(S(18)*d) + F**(a + b/(c + d*x)**S(3))*b**S(2)*(c + d*x)**S(3)*log(F)**S(2)/(S(18)*d) + F**(a + b/(c + d*x)**S(3))*b*(c + d*x)**S(6)*log(F)/(S(18)*d) + F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(9)/(S(9)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(5), x), x, -F**a*b**S(2)*log(F)**S(2)*Ei(b*log(F)/(c + d*x)**S(3))/(S(6)*d) + F**(a + b/(c + d*x)**S(3))*b*(c + d*x)**S(3)*log(F)/(S(6)*d) + F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(6)/(S(6)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(2), x), x, -F**a*b*log(F)*Ei(b*log(F)/(c + d*x)**S(3))/(S(3)*d) + F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(3)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x), x), x, -F**a*Ei(b*log(F)/(c + d*x)**S(3))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(4), x), x, -F**(a + b/(c + d*x)**S(3))/(S(3)*b*d*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(7), x), x, -F**(a + b/(c + d*x)**S(3))/(S(3)*b*d*(c + d*x)**S(3)*log(F)) + F**(a + b/(c + d*x)**S(3))/(S(3)*b**S(2)*d*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(10), x), x, -F**(a + b/(c + d*x)**S(3))/(S(3)*b*d*(c + d*x)**S(6)*log(F)) + S(2)*F**(a + b/(c + d*x)**S(3))/(S(3)*b**S(2)*d*(c + d*x)**S(3)*log(F)**S(2)) - S(2)*F**(a + b/(c + d*x)**S(3))/(S(3)*b**S(3)*d*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(13), x), x, -F**(a + b/(c + d*x)**S(3))/(S(3)*b*d*(c + d*x)**S(9)*log(F)) + F**(a + b/(c + d*x)**S(3))/(b**S(2)*d*(c + d*x)**S(6)*log(F)**S(2)) - S(2)*F**(a + b/(c + d*x)**S(3))/(b**S(3)*d*(c + d*x)**S(3)*log(F)**S(3)) + S(2)*F**(a + b/(c + d*x)**S(3))/(b**S(4)*d*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(16), x), x, -F**a*Gamma(S(5), -b*log(F)/(c + d*x)**S(3))/(S(3)*b**S(5)*d*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(19), x), x, F**a*Gamma(S(6), -b*log(F)/(c + d*x)**S(3))/(S(3)*b**S(6)*d*log(F)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x)**S(3), x), x, F**a*(-b*log(F)/(c + d*x)**S(3))**(S(4)/3)*(c + d*x)**S(4)*Gamma(S(-4)/3, -b*log(F)/(c + d*x)**S(3))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))*(c + d*x), x), x, F**a*(-b*log(F)/(c + d*x)**S(3))**(S(2)/3)*(c + d*x)**S(2)*Gamma(S(-2)/3, -b*log(F)/(c + d*x)**S(3))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3)), x), x, F**a*(-b*log(F)/(c + d*x)**S(3))**(S(1)/3)*(c + d*x)*Gamma(S(-1)/3, -b*log(F)/(c + d*x)**S(3))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(2), x), x, F**a*Gamma(S(1)/3, -b*log(F)/(c + d*x)**S(3))/(S(3)*d*(-b*log(F)/(c + d*x)**S(3))**(S(1)/3)*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(3), x), x, F**a*Gamma(S(2)/3, -b*log(F)/(c + d*x)**S(3))/(S(3)*d*(-b*log(F)/(c + d*x)**S(3))**(S(2)/3)*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x)**S(3))/(c + d*x)**S(5), x), x, F**a*Gamma(S(4)/3, -b*log(F)/(c + d*x)**S(3))/(S(3)*d*(-b*log(F)/(c + d*x)**S(3))**(S(4)/3)*(c + d*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**m, x), x, -F**a*(-b*(c + d*x)**n*log(F))**(-(m + S(1))/n)*(c + d*x)**(m + S(1))*Gamma((m + S(1))/n, -b*(c + d*x)**n*log(F))/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**S(3), x), x, -F**a*(-b*(c + d*x)**n*log(F))**(-S(4)/n)*(c + d*x)**S(4)*Gamma(S(4)/n, -b*(c + d*x)**n*log(F))/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**S(2), x), x, -F**a*(-b*(c + d*x)**n*log(F))**(-S(3)/n)*(c + d*x)**S(3)*Gamma(S(3)/n, -b*(c + d*x)**n*log(F))/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x), x), x, -F**a*(-b*(c + d*x)**n*log(F))**(-S(2)/n)*(c + d*x)**S(2)*Gamma(S(2)/n, -b*(c + d*x)**n*log(F))/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n), x), x, -F**a*(-b*(c + d*x)**n*log(F))**(-S(1)/n)*(c + d*x)*Gamma(S(1)/n, -b*(c + d*x)**n*log(F))/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)/(c + d*x), x), x, F**a*Ei(b*(c + d*x)**n*log(F))/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)/(c + d*x)**S(2), x), x, -F**a*(-b*(c + d*x)**n*log(F))**(S(1)/n)*Gamma(-S(1)/n, -b*(c + d*x)**n*log(F))/(d*n*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)/(c + d*x)**S(3), x), x, -F**a*(-b*(c + d*x)**n*log(F))**(S(2)/n)*Gamma(-S(2)/n, -b*(c + d*x)**n*log(F))/(d*n*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)/(c + d*x)**S(4), x), x, -F**a*(-b*(c + d*x)**n*log(F))**(S(3)/n)*Gamma(-S(3)/n, -b*(c + d*x)**n*log(F))/(d*n*(c + d*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(S(6)*n + S(-1)), x), x, -F**a*Gamma(S(6), -b*(c + d*x)**n*log(F))/(b**S(6)*d*n*log(F)**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(S(5)*n + S(-1)), x), x, F**a*Gamma(S(5), -b*(c + d*x)**n*log(F))/(b**S(5)*d*n*log(F)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(S(4)*n + S(-1)), x), x, F**(a + b*(c + d*x)**n)*(c + d*x)**(S(3)*n)/(b*d*n*log(F)) - S(3)*F**(a + b*(c + d*x)**n)*(c + d*x)**(S(2)*n)/(b**S(2)*d*n*log(F)**S(2)) + S(6)*F**(a + b*(c + d*x)**n)*(c + d*x)**n/(b**S(3)*d*n*log(F)**S(3)) - S(6)*F**(a + b*(c + d*x)**n)/(b**S(4)*d*n*log(F)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(S(3)*n + S(-1)), x), x, F**(a + b*(c + d*x)**n)*(c + d*x)**(S(2)*n)/(b*d*n*log(F)) - S(2)*F**(a + b*(c + d*x)**n)*(c + d*x)**n/(b**S(2)*d*n*log(F)**S(2)) + S(2)*F**(a + b*(c + d*x)**n)/(b**S(3)*d*n*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(S(2)*n + S(-1)), x), x, F**(a + b*(c + d*x)**n)*(c + d*x)**n/(b*d*n*log(F)) - F**(a + b*(c + d*x)**n)/(b**S(2)*d*n*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(n + S(-1)), x), x, F**(a + b*(c + d*x)**n)/(b*d*n*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)/(c + d*x), x), x, F**a*Ei(b*(c + d*x)**n*log(F))/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(-n + S(-1)), x), x, F**a*b*log(F)*Ei(b*(c + d*x)**n*log(F))/(d*n) - F**(a + b*(c + d*x)**n)*(c + d*x)**(-n)/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(-S(2)*n + S(-1)), x), x, F**a*b**S(2)*log(F)**S(2)*Ei(b*(c + d*x)**n*log(F))/(S(2)*d*n) - F**(a + b*(c + d*x)**n)*b*(c + d*x)**(-n)*log(F)/(S(2)*d*n) - F**(a + b*(c + d*x)**n)*(c + d*x)**(-S(2)*n)/(S(2)*d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(-S(3)*n + S(-1)), x), x, F**a*b**S(3)*log(F)**S(3)*Ei(b*(c + d*x)**n*log(F))/(S(6)*d*n) - F**(a + b*(c + d*x)**n)*b**S(2)*(c + d*x)**(-n)*log(F)**S(2)/(S(6)*d*n) - F**(a + b*(c + d*x)**n)*b*(c + d*x)**(-S(2)*n)*log(F)/(S(6)*d*n) - F**(a + b*(c + d*x)**n)*(c + d*x)**(-S(3)*n)/(S(3)*d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(-S(4)*n + S(-1)), x), x, -F**a*b**S(4)*Gamma(S(-4), -b*(c + d*x)**n*log(F))*log(F)**S(4)/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**n)*(c + d*x)**(-S(5)*n + S(-1)), x), x, F**a*b**S(5)*Gamma(S(-5), -b*(c + d*x)**n*log(F))*log(F)**S(5)/(d*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(c*(a + b*x)**n)*(a + b*x)**(n/S(2) + S(-1)), x), x, sqrt(pi)*erfi(sqrt(c)*(a + b*x)**(n/S(2))*sqrt(log(F)))/(b*sqrt(c)*n*sqrt(log(F))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(-c*(a + b*x)**n)*(a + b*x)**(n/S(2) + S(-1)), x), x, sqrt(pi)*erf(sqrt(c)*(a + b*x)**(n/S(2))*sqrt(log(F)))/(b*sqrt(c)*n*sqrt(log(F))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(e + f*x)**S(5), x), x, sqrt(pi)*F**a*(-c*f + d*e)**S(5)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*sqrt(b)*d**S(6)*sqrt(log(F))) - S(5)*sqrt(pi)*F**a*f**S(2)*(-c*f + d*e)**S(3)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*b**(S(3)/2)*d**S(6)*log(F)**(S(3)/2)) + S(15)*sqrt(pi)*F**a*f**S(4)*(-c*f + d*e)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(8)*b**(S(5)/2)*d**S(6)*log(F)**(S(5)/2)) + F**(a + b*(c + d*x)**S(2))*f**S(5)*(c + d*x)**S(4)/(S(2)*b*d**S(6)*log(F)) + S(5)*F**(a + b*(c + d*x)**S(2))*f**S(4)*(c + d*x)**S(3)*(-c*f + d*e)/(S(2)*b*d**S(6)*log(F)) + S(5)*F**(a + b*(c + d*x)**S(2))*f**S(3)*(c + d*x)**S(2)*(-c*f + d*e)**S(2)/(b*d**S(6)*log(F)) + S(5)*F**(a + b*(c + d*x)**S(2))*f**S(2)*(c + d*x)*(-c*f + d*e)**S(3)/(b*d**S(6)*log(F)) + S(5)*F**(a + b*(c + d*x)**S(2))*f*(-c*f + d*e)**S(4)/(S(2)*b*d**S(6)*log(F)) - F**(a + b*(c + d*x)**S(2))*f**S(5)*(c + d*x)**S(2)/(b**S(2)*d**S(6)*log(F)**S(2)) - S(15)*F**(a + b*(c + d*x)**S(2))*f**S(4)*(c + d*x)*(-c*f + d*e)/(S(4)*b**S(2)*d**S(6)*log(F)**S(2)) - S(5)*F**(a + b*(c + d*x)**S(2))*f**S(3)*(-c*f + d*e)**S(2)/(b**S(2)*d**S(6)*log(F)**S(2)) + F**(a + b*(c + d*x)**S(2))*f**S(5)/(b**S(3)*d**S(6)*log(F)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(e + f*x)**S(4), x), x, sqrt(pi)*F**a*(-c*f + d*e)**S(4)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*sqrt(b)*d**S(5)*sqrt(log(F))) - S(3)*sqrt(pi)*F**a*f**S(2)*(-c*f + d*e)**S(2)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*b**(S(3)/2)*d**S(5)*log(F)**(S(3)/2)) + S(3)*sqrt(pi)*F**a*f**S(4)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(8)*b**(S(5)/2)*d**S(5)*log(F)**(S(5)/2)) + F**(a + b*(c + d*x)**S(2))*f**S(4)*(c + d*x)**S(3)/(S(2)*b*d**S(5)*log(F)) + S(2)*F**(a + b*(c + d*x)**S(2))*f**S(3)*(c + d*x)**S(2)*(-c*f + d*e)/(b*d**S(5)*log(F)) + S(3)*F**(a + b*(c + d*x)**S(2))*f**S(2)*(c + d*x)*(-c*f + d*e)**S(2)/(b*d**S(5)*log(F)) + S(2)*F**(a + b*(c + d*x)**S(2))*f*(-c*f + d*e)**S(3)/(b*d**S(5)*log(F)) - S(3)*F**(a + b*(c + d*x)**S(2))*f**S(4)*(c + d*x)/(S(4)*b**S(2)*d**S(5)*log(F)**S(2)) - S(2)*F**(a + b*(c + d*x)**S(2))*f**S(3)*(-c*f + d*e)/(b**S(2)*d**S(5)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(e + f*x)**S(3), x), x, sqrt(pi)*F**a*(-c*f + d*e)**S(3)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*sqrt(b)*d**S(4)*sqrt(log(F))) - S(3)*sqrt(pi)*F**a*f**S(2)*(-c*f + d*e)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(4)*b**(S(3)/2)*d**S(4)*log(F)**(S(3)/2)) + F**(a + b*(c + d*x)**S(2))*f**S(3)*(c + d*x)**S(2)/(S(2)*b*d**S(4)*log(F)) + S(3)*F**(a + b*(c + d*x)**S(2))*f**S(2)*(c + d*x)*(-c*f + d*e)/(S(2)*b*d**S(4)*log(F)) + S(3)*F**(a + b*(c + d*x)**S(2))*f*(-c*f + d*e)**S(2)/(S(2)*b*d**S(4)*log(F)) - F**(a + b*(c + d*x)**S(2))*f**S(3)/(S(2)*b**S(2)*d**S(4)*log(F)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(e + f*x)**S(2), x), x, sqrt(pi)*F**a*(-c*f + d*e)**S(2)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*sqrt(b)*d**S(3)*sqrt(log(F))) - sqrt(pi)*F**a*f**S(2)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(4)*b**(S(3)/2)*d**S(3)*log(F)**(S(3)/2)) + F**(a + b*(c + d*x)**S(2))*f**S(2)*(c + d*x)/(S(2)*b*d**S(3)*log(F)) + F**(a + b*(c + d*x)**S(2))*f*(-c*f + d*e)/(b*d**S(3)*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))*(e + f*x), x), x, sqrt(pi)*F**a*(-c*f/S(2) + d*e/S(2))*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(sqrt(b)*d**S(2)*sqrt(log(F))) + F**(a + b*(c + d*x)**S(2))*f/(S(2)*b*d**S(2)*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2)), x), x, sqrt(pi)*F**a*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/(S(2)*sqrt(b)*d*sqrt(log(F))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(e + f*x), x), x, Integral(F**(a + b*(c + d*x)**S(2))/(e + f*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(e + f*x)**S(2), x), x, sqrt(pi)*F**a*sqrt(b)*d*sqrt(log(F))*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/f**S(2) - F**(a + b*(c + d*x)**S(2))/(f*(e + f*x)) - S(2)*b*d*(-c*f + d*e)*log(F)*Integral(F**(a + b*(c + d*x)**S(2))/(e + f*x), x)/f**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*(c + d*x)**S(2))/(e + f*x)**S(3), x), x, -sqrt(pi)*F**a*b**(S(3)/2)*d**S(2)*(-c*f + d*e)*log(F)**(S(3)/2)*erfi(sqrt(b)*(c + d*x)*sqrt(log(F)))/f**S(4) + F**(a + b*(c + d*x)**S(2))*b*d*(-c*f + d*e)*log(F)/(f**S(3)*(e + f*x)) - F**(a + b*(c + d*x)**S(2))/(S(2)*f*(e + f*x)**S(2)) + S(2)*b**S(2)*d**S(2)*(-c*f + d*e)**S(2)*log(F)**S(2)*Integral(F**(a + b*(c + d*x)**S(2))/(e + f*x), x)/f**S(4) + b*d**S(2)*log(F)*Integral(F**(a + b*(c + d*x)**S(2))/(e + f*x), x)/f**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(e*(c + d*x)**S(3)), x), x, -b**S(3)*(c + d*x)**S(4)*Gamma(S(4)/3, -e*(c + d*x)**S(3))/(S(3)*d**S(4)*(-e*(c + d*x)**S(3))**(S(4)/3)) - b**S(2)*(-a*d + b*c)*exp(e*(c + d*x)**S(3))/(d**S(4)*e) - b*(c + d*x)**S(2)*(-a*d + b*c)**S(2)*Gamma(S(2)/3, -e*(c + d*x)**S(3))/(d**S(4)*(-e*(c + d*x)**S(3))**(S(2)/3)) + (c + d*x)*(-a*d + b*c)**S(3)*Gamma(S(1)/3, -e*(c + d*x)**S(3))/(S(3)*d**S(4)*(-e*(c + d*x)**S(3))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*exp(e*(c + d*x)**S(3)), x), x, b**S(2)*exp(e*(c + d*x)**S(3))/(S(3)*d**S(3)*e) + S(2)*b*(c + d*x)**S(2)*(-a*d + b*c)*Gamma(S(2)/3, -e*(c + d*x)**S(3))/(S(3)*d**S(3)*(-e*(c + d*x)**S(3))**(S(2)/3)) - (c + d*x)*(-a*d + b*c)**S(2)*Gamma(S(1)/3, -e*(c + d*x)**S(3))/(S(3)*d**S(3)*(-e*(c + d*x)**S(3))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*exp(e*(c + d*x)**S(3)), x), x, -b*(c + d*x)**S(2)*Gamma(S(2)/3, -e*(c + d*x)**S(3))/(S(3)*d**S(2)*(-e*(c + d*x)**S(3))**(S(2)/3)) + (c + d*x)*(-a*d/S(3) + b*c/S(3))*Gamma(S(1)/3, -e*(c + d*x)**S(3))/(d**S(2)*(-e*(c + d*x)**S(3))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e*(c + d*x)**S(3)), x), x, (-c/S(3) - d*x/S(3))*Gamma(S(1)/3, -e*(c + d*x)**S(3))/(d*(-e*(c + d*x)**S(3))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e*(c + d*x)**S(3))/(a + b*x), x), x, Integral(exp(e*(c + d*x)**S(3))/(a + b*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e*(c + d*x)**S(3))/(a + b*x)**S(2), x), x, -exp(e*(c + d*x)**S(3))/(b*(a + b*x)) - d*e*(c + d*x)**S(2)*Gamma(S(2)/3, -e*(c + d*x)**S(3))/(b**S(2)*(-e*(c + d*x)**S(3))**(S(2)/3)) + S(3)*d*e*(-a*d + b*c)**S(2)*Integral(exp(e*(c + d*x)**S(3))/(a + b*x), x)/b**S(3) - d*e*(c + d*x)*(-a*d + b*c)*Gamma(S(1)/3, -e*(c + d*x)**S(3))/(b**S(3)*(-e*(c + d*x)**S(3))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(e + f*x), x), x, -F**a*Ei(b*log(F)/(c + d*x))/f + F**(a - b*f/(-c*f + d*e))*Ei(b*d*(e + f*x)*log(F)/((c + d*x)*(-c*f + d*e)))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(e + f*x)**S(2), x), x, F**(a + b/(c + d*x))*d/(f*(-c*f + d*e)) - F**(a + b/(c + d*x))/(f*(e + f*x)) - F**(a - b*f/(-c*f + d*e))*b*d*log(F)*Ei(b*d*(e + f*x)*log(F)/((c + d*x)*(-c*f + d*e)))/(-c*f + d*e)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(e + f*x)**S(3), x), x, -F**(a + b/(c + d*x))*b*d**S(2)*log(F)/(S(2)*(-c*f + d*e)**S(3)) + F**(a + b/(c + d*x))*b*d*log(F)/(S(2)*(e + f*x)*(-c*f + d*e)**S(2)) + F**(a + b/(c + d*x))*d**S(2)/(S(2)*f*(-c*f + d*e)**S(2)) - F**(a + b/(c + d*x))/(S(2)*f*(e + f*x)**S(2)) + F**(a - b*f/(-c*f + d*e))*b**S(2)*d**S(2)*f*log(F)**S(2)*Ei(b*d*(e + f*x)*log(F)/((c + d*x)*(-c*f + d*e)))/(S(2)*(-c*f + d*e)**S(4)) - F**(a - b*f/(-c*f + d*e))*b*d**S(2)*log(F)*Ei(b*d*(e + f*x)*log(F)/((c + d*x)*(-c*f + d*e)))/(-c*f + d*e)**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b/(c + d*x))/(e + f*x)**S(4), x), x, F**(a + b/(c + d*x))*b**S(2)*d**S(3)*f*log(F)**S(2)/(S(6)*(-c*f + d*e)**S(5)) - F**(a + b/(c + d*x))*b**S(2)*d**S(2)*f*log(F)**S(2)/(S(6)*(e + f*x)*(-c*f + d*e)**S(4)) - S(5)*F**(a + b/(c + d*x))*b*d**S(3)*log(F)/(S(6)*(-c*f + d*e)**S(4)) + S(2)*F**(a + b/(c + d*x))*b*d**S(2)*log(F)/(S(3)*(e + f*x)*(-c*f + d*e)**S(3)) + F**(a + b/(c + d*x))*b*d*log(F)/(S(6)*(e + f*x)**S(2)*(-c*f + d*e)**S(2)) + F**(a + b/(c + d*x))*d**S(3)/(S(3)*f*(-c*f + d*e)**S(3)) - F**(a + b/(c + d*x))/(S(3)*f*(e + f*x)**S(3)) - F**(a - b*f/(-c*f + d*e))*b**S(3)*d**S(3)*f**S(2)*log(F)**S(3)*Ei(b*d*(e + f*x)*log(F)/((c + d*x)*(-c*f + d*e)))/(S(6)*(-c*f + d*e)**S(6)) + F**(a - b*f/(-c*f + d*e))*b**S(2)*d**S(3)*f*log(F)**S(2)*Ei(b*d*(e + f*x)*log(F)/((c + d*x)*(-c*f + d*e)))/(-c*f + d*e)**S(5) - F**(a - b*f/(-c*f + d*e))*b*d**S(3)*log(F)*Ei(b*d*(e + f*x)*log(F)/((c + d*x)*(-c*f + d*e)))/(-c*f + d*e)**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(4)*exp(e/(c + d*x)), x), x, -b**S(4)*e**S(5)*Gamma(S(-5), -e/(c + d*x))/d**S(5) - S(4)*b**S(3)*e**S(4)*(-a*d + b*c)*Gamma(S(-4), -e/(c + d*x))/d**S(5) - b**S(2)*e**S(3)*(-a*d + b*c)**S(2)*Ei(e/(c + d*x))/d**S(5) + b**S(2)*e**S(2)*(c + d*x)*(-a*d + b*c)**S(2)*exp(e/(c + d*x))/d**S(5) + b**S(2)*e*(c + d*x)**S(2)*(-a*d + b*c)**S(2)*exp(e/(c + d*x))/d**S(5) + S(2)*b**S(2)*(c + d*x)**S(3)*(-a*d + b*c)**S(2)*exp(e/(c + d*x))/d**S(5) + S(2)*b*e**S(2)*(-a*d + b*c)**S(3)*Ei(e/(c + d*x))/d**S(5) - S(2)*b*e*(c + d*x)*(-a*d + b*c)**S(3)*exp(e/(c + d*x))/d**S(5) - S(2)*b*(c + d*x)**S(2)*(-a*d + b*c)**S(3)*exp(e/(c + d*x))/d**S(5) - e*(-a*d + b*c)**S(4)*Ei(e/(c + d*x))/d**S(5) + (c + d*x)*(-a*d + b*c)**S(4)*exp(e/(c + d*x))/d**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(e/(c + d*x)), x), x, b**S(3)*e**S(4)*Gamma(S(-4), -e/(c + d*x))/d**S(4) + b**S(2)*e**S(3)*(-a*d + b*c)*Ei(e/(c + d*x))/(S(2)*d**S(4)) - b**S(2)*e**S(2)*(c + d*x)*(-a*d + b*c)*exp(e/(c + d*x))/(S(2)*d**S(4)) - b**S(2)*e*(c + d*x)**S(2)*(-a*d + b*c)*exp(e/(c + d*x))/(S(2)*d**S(4)) - b**S(2)*(c + d*x)**S(3)*(-a*d + b*c)*exp(e/(c + d*x))/d**S(4) - S(3)*b*e**S(2)*(-a*d + b*c)**S(2)*Ei(e/(c + d*x))/(S(2)*d**S(4)) + S(3)*b*e*(c + d*x)*(-a*d + b*c)**S(2)*exp(e/(c + d*x))/(S(2)*d**S(4)) + S(3)*b*(c + d*x)**S(2)*(-a*d + b*c)**S(2)*exp(e/(c + d*x))/(S(2)*d**S(4)) + e*(-a*d + b*c)**S(3)*Ei(e/(c + d*x))/d**S(4) - (c + d*x)*(-a*d + b*c)**S(3)*exp(e/(c + d*x))/d**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*exp(e/(c + d*x)), x), x, -b**S(2)*e**S(3)*Ei(e/(c + d*x))/(S(6)*d**S(3)) + b**S(2)*e**S(2)*(c + d*x)*exp(e/(c + d*x))/(S(6)*d**S(3)) + b**S(2)*e*(c + d*x)**S(2)*exp(e/(c + d*x))/(S(6)*d**S(3)) + b**S(2)*(c + d*x)**S(3)*exp(e/(c + d*x))/(S(3)*d**S(3)) + b*e**S(2)*(-a*d + b*c)*Ei(e/(c + d*x))/d**S(3) - b*e*(c + d*x)*(-a*d + b*c)*exp(e/(c + d*x))/d**S(3) - b*(c + d*x)**S(2)*(-a*d + b*c)*exp(e/(c + d*x))/d**S(3) - e*(-a*d + b*c)**S(2)*Ei(e/(c + d*x))/d**S(3) + (c + d*x)*(-a*d + b*c)**S(2)*exp(e/(c + d*x))/d**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*exp(e/(c + d*x)), x), x, -b*e**S(2)*Ei(e/(c + d*x))/(S(2)*d**S(2)) + b*e*(c + d*x)*exp(e/(c + d*x))/(S(2)*d**S(2)) + b*(c + d*x)**S(2)*exp(e/(c + d*x))/(S(2)*d**S(2)) + e*(-a*d + b*c)*Ei(e/(c + d*x))/d**S(2) + (c + d*x)*(a*d - b*c)*exp(e/(c + d*x))/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)), x), x, -e*Ei(e/(c + d*x))/d + (c + d*x)*exp(e/(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x))/(a + b*x), x), x, exp(b*e/(-a*d + b*c))*Ei(-d*e*(a + b*x)/((c + d*x)*(-a*d + b*c)))/b - Ei(e/(c + d*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x))/(a + b*x)**S(2), x), x, -d*e*exp(b*e/(-a*d + b*c))*Ei(-d*e*(a + b*x)/((c + d*x)*(-a*d + b*c)))/(-a*d + b*c)**S(2) - d*exp(e/(c + d*x))/(b*(-a*d + b*c)) - exp(e/(c + d*x))/(b*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x))/(a + b*x)**S(3), x), x, b*d**S(2)*e**S(2)*exp(b*e/(-a*d + b*c))*Ei(-d*e*(a + b*x)/((c + d*x)*(-a*d + b*c)))/(S(2)*(-a*d + b*c)**S(4)) + d**S(2)*e*exp(e/(c + d*x))/(S(2)*(-a*d + b*c)**S(3)) + d**S(2)*e*exp(b*e/(-a*d + b*c))*Ei(-d*e*(a + b*x)/((c + d*x)*(-a*d + b*c)))/(-a*d + b*c)**S(3) + d*e*exp(e/(c + d*x))/(S(2)*(a + b*x)*(-a*d + b*c)**S(2)) + d**S(2)*exp(e/(c + d*x))/(S(2)*b*(-a*d + b*c)**S(2)) - exp(e/(c + d*x))/(S(2)*b*(a + b*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(e/(c + d*x)**S(2)), x), x, -b**S(3)*e**S(2)*Ei(e/(c + d*x)**S(2))/(S(4)*d**S(4)) + b**S(3)*e*(c + d*x)**S(2)*exp(e/(c + d*x)**S(2))/(S(4)*d**S(4)) + b**S(3)*(c + d*x)**S(4)*exp(e/(c + d*x)**S(2))/(S(4)*d**S(4)) + S(2)*sqrt(pi)*b**S(2)*e**(S(3)/2)*(-a*d + b*c)*erfi(sqrt(e)/(c + d*x))/d**S(4) - S(2)*b**S(2)*e*(c + d*x)*(-a*d + b*c)*exp(e/(c + d*x)**S(2))/d**S(4) - b**S(2)*(c + d*x)**S(3)*(-a*d + b*c)*exp(e/(c + d*x)**S(2))/d**S(4) - S(3)*b*e*(-a*d + b*c)**S(2)*Ei(e/(c + d*x)**S(2))/(S(2)*d**S(4)) + S(3)*b*(c + d*x)**S(2)*(-a*d + b*c)**S(2)*exp(e/(c + d*x)**S(2))/(S(2)*d**S(4)) + sqrt(pi)*sqrt(e)*(-a*d + b*c)**S(3)*erfi(sqrt(e)/(c + d*x))/d**S(4) - (c + d*x)*(-a*d + b*c)**S(3)*exp(e/(c + d*x)**S(2))/d**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*exp(e/(c + d*x)**S(2)), x), x, -S(2)*sqrt(pi)*b**S(2)*e**(S(3)/2)*erfi(sqrt(e)/(c + d*x))/(S(3)*d**S(3)) + S(2)*b**S(2)*e*(c + d*x)*exp(e/(c + d*x)**S(2))/(S(3)*d**S(3)) + b**S(2)*(c + d*x)**S(3)*exp(e/(c + d*x)**S(2))/(S(3)*d**S(3)) + b*e*(-a*d + b*c)*Ei(e/(c + d*x)**S(2))/d**S(3) - b*(c + d*x)**S(2)*(-a*d + b*c)*exp(e/(c + d*x)**S(2))/d**S(3) - sqrt(pi)*sqrt(e)*(-a*d + b*c)**S(2)*erfi(sqrt(e)/(c + d*x))/d**S(3) + (c + d*x)*(-a*d + b*c)**S(2)*exp(e/(c + d*x)**S(2))/d**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*exp(e/(c + d*x)**S(2)), x), x, -b*e*Ei(e/(c + d*x)**S(2))/(S(2)*d**S(2)) + b*(c + d*x)**S(2)*exp(e/(c + d*x)**S(2))/(S(2)*d**S(2)) + sqrt(pi)*sqrt(e)*(-a*d + b*c)*erfi(sqrt(e)/(c + d*x))/d**S(2) + (c + d*x)*(a*d - b*c)*exp(e/(c + d*x)**S(2))/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)**S(2)), x), x, -sqrt(pi)*sqrt(e)*erfi(sqrt(e)/(c + d*x))/d + (c + d*x)*exp(e/(c + d*x)**S(2))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)**S(2))/(a + b*x), x), x, Integral(exp(e/(c + d*x)**S(2))/(a + b*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)**S(2))/(a + b*x)**S(2), x), x, Integral(exp(e/(c + d*x)**S(2))/(a + b*x)**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)**S(2))/(a + b*x)**S(3), x), x, Integral(exp(e/(c + d*x)**S(2))/(a + b*x)**S(3), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*exp(e/(c + d*x)**S(3)), x), x, b**S(3)*(-e/(c + d*x)**S(3))**(S(4)/3)*(c + d*x)**S(4)*Gamma(S(-4)/3, -e/(c + d*x)**S(3))/(S(3)*d**S(4)) + b**S(2)*e*(-a*d + b*c)*Ei(e/(c + d*x)**S(3))/d**S(4) - b**S(2)*(c + d*x)**S(3)*(-a*d + b*c)*exp(e/(c + d*x)**S(3))/d**S(4) + b*(-e/(c + d*x)**S(3))**(S(2)/3)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)*Gamma(S(-2)/3, -e/(c + d*x)**S(3))/d**S(4) - (-e/(c + d*x)**S(3))**(S(1)/3)*(c + d*x)*(-a*d + b*c)**S(3)*Gamma(S(-1)/3, -e/(c + d*x)**S(3))/(S(3)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*exp(e/(c + d*x)**S(3)), x), x, -b**S(2)*e*Ei(e/(c + d*x)**S(3))/(S(3)*d**S(3)) + b**S(2)*(c + d*x)**S(3)*exp(e/(c + d*x)**S(3))/(S(3)*d**S(3)) - S(2)*b*(-e/(c + d*x)**S(3))**(S(2)/3)*(c + d*x)**S(2)*(-a*d + b*c)*Gamma(S(-2)/3, -e/(c + d*x)**S(3))/(S(3)*d**S(3)) + (-e/(c + d*x)**S(3))**(S(1)/3)*(c + d*x)*(-a*d + b*c)**S(2)*Gamma(S(-1)/3, -e/(c + d*x)**S(3))/(S(3)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*exp(e/(c + d*x)**S(3)), x), x, b*(-e/(c + d*x)**S(3))**(S(2)/3)*(c + d*x)**S(2)*Gamma(S(-2)/3, -e/(c + d*x)**S(3))/(S(3)*d**S(2)) - (-e/(c + d*x)**S(3))**(S(1)/3)*(c + d*x)*(-a*d/S(3) + b*c/S(3))*Gamma(S(-1)/3, -e/(c + d*x)**S(3))/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)**S(3)), x), x, (-e/(c + d*x)**S(3))**(S(1)/3)*(c + d*x)*Gamma(S(-1)/3, -e/(c + d*x)**S(3))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)**S(3))/(a + b*x), x), x, Integral(exp(e/(c + d*x)**S(3))/(a + b*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(e/(c + d*x)**S(3))/(a + b*x)**S(2), x), x, Integral(exp(e/(c + d*x)**S(3))/(a + b*x)**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(e + f*(a + b*x)/(c + d*x))/(g + h*x), x), x, F**(e + f*(-a*h + b*g)/(-c*h + d*g))*Ei(f*(g + h*x)*(a*d - b*c)*log(F)/((c + d*x)*(-c*h + d*g)))/h - F**(b*f/d + e)*Ei(f*(a*d - b*c)*log(F)/(d*(c + d*x)))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(e + f*(a + b*x)/(c + d*x))/(g + h*x)**S(2), x), x, -F**(e + f*(a + b*x)/(c + d*x))/(h*(g + h*x)) + F**(e + f*(-a*h + b*g)/(-c*h + d*g))*f*(-a*d + b*c)*log(F)*Ei(f*(g + h*x)*(a*d - b*c)*log(F)/((c + d*x)*(-c*h + d*g)))/(-c*h + d*g)**S(2) + F**(b*f/d + e - f*(-a*d + b*c)/(d*(c + d*x)))*d/(h*(-c*h + d*g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(e + f*(a + b*x)/(c + d*x))/(g + h*x)**S(3), x), x, -F**(e + f*(a + b*x)/(c + d*x))*f*(-a*d/S(2) + b*c/S(2))*log(F)/((g + h*x)*(-c*h + d*g)**S(2)) - F**(e + f*(a + b*x)/(c + d*x))/(S(2)*h*(g + h*x)**S(2)) + F**(e + f*(-a*h + b*g)/(-c*h + d*g))*d*f*(-a*d + b*c)*log(F)*Ei(f*(g + h*x)*(a*d - b*c)*log(F)/((c + d*x)*(-c*h + d*g)))/(-c*h + d*g)**S(3) + F**(e + f*(-a*h + b*g)/(-c*h + d*g))*f**S(2)*h*(-a*d + b*c)**S(2)*log(F)**S(2)*Ei(f*(g + h*x)*(a*d - b*c)*log(F)/((c + d*x)*(-c*h + d*g)))/(S(2)*(-c*h + d*g)**S(4)) + F**(b*f/d + e - f*(-a*d + b*c)/(d*(c + d*x)))*d**S(2)/(S(2)*h*(-c*h + d*g)**S(2)) + F**(b*f/d + e - f*(-a*d + b*c)/(d*(c + d*x)))*d*f*(-a*d + b*c)*log(F)/(S(2)*(-c*h + d*g)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(e + f*(a + b*x)/(c + d*x))/(g + h*x)**S(4), x), x, -S(2)*F**(e + f*(a + b*x)/(c + d*x))*d*f*(-a*d + b*c)*log(F)/(S(3)*(g + h*x)*(-c*h + d*g)**S(3)) - F**(e + f*(a + b*x)/(c + d*x))*f**S(2)*h*(-a*d + b*c)**S(2)*log(F)**S(2)/(S(6)*(g + h*x)*(-c*h + d*g)**S(4)) - F**(e + f*(a + b*x)/(c + d*x))*f*(-a*d/S(6) + b*c/S(6))*log(F)/((g + h*x)**S(2)*(-c*h + d*g)**S(2)) - F**(e + f*(a + b*x)/(c + d*x))/(S(3)*h*(g + h*x)**S(3)) + F**(e + f*(-a*h + b*g)/(-c*h + d*g))*d**S(2)*f*(-a*d + b*c)*log(F)*Ei(f*(g + h*x)*(a*d - b*c)*log(F)/((c + d*x)*(-c*h + d*g)))/(-c*h + d*g)**S(4) + F**(e + f*(-a*h + b*g)/(-c*h + d*g))*d*f**S(2)*h*(-a*d + b*c)**S(2)*log(F)**S(2)*Ei(f*(g + h*x)*(a*d - b*c)*log(F)/((c + d*x)*(-c*h + d*g)))/(-c*h + d*g)**S(5) + F**(e + f*(-a*h + b*g)/(-c*h + d*g))*f**S(3)*h**S(2)*(-a*d + b*c)**S(3)*log(F)**S(3)*Ei(f*(g + h*x)*(a*d - b*c)*log(F)/((c + d*x)*(-c*h + d*g)))/(S(6)*(-c*h + d*g)**S(6)) + F**(b*f/d + e - f*(-a*d + b*c)/(d*(c + d*x)))*d**S(3)/(S(3)*h*(-c*h + d*g)**S(3)) + S(5)*F**(b*f/d + e - f*(-a*d + b*c)/(d*(c + d*x)))*d**S(2)*f*(-a*d + b*c)*log(F)/(S(6)*(-c*h + d*g)**S(4)) + F**(b*f/d + e - f*(-a*d + b*c)/(d*(c + d*x)))*d*f**S(2)*h*(-a*d + b*c)**S(2)*log(F)**S(2)/(S(6)*(-c*h + d*g)**S(5)), expand=True, _diff=True, _numerical=True) # fails 1940 and 1939 recursion assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*x**S(3), x), x, -sqrt(pi)*b**S(3)*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(16)*c**(S(7)/2)*sqrt(log(f))) + b**S(2)*f**(a + b*x + c*x**S(2))/(S(8)*c**S(3)*log(f)) - b*f**(a + b*x + c*x**S(2))*x/(S(4)*c**S(2)*log(f)) + S(3)*sqrt(pi)*b*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(8)*c**(S(5)/2)*log(f)**(S(3)/2)) + f**(a + b*x + c*x**S(2))*x**S(2)/(S(2)*c*log(f)) - f**(a + b*x + c*x**S(2))/(S(2)*c**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*x**S(2), x), x, sqrt(pi)*b**S(2)*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(8)*c**(S(5)/2)*sqrt(log(f))) - b*f**(a + b*x + c*x**S(2))/(S(4)*c**S(2)*log(f)) + f**(a + b*x + c*x**S(2))*x/(S(2)*c*log(f)) - sqrt(pi)*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(4)*c**(S(3)/2)*log(f)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*x, x), x, -sqrt(pi)*b*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(4)*c**(S(3)/2)*sqrt(log(f))) + f**(a + b*x + c*x**S(2))/(S(2)*c*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2)), x), x, sqrt(pi)*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(2)*sqrt(c)*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/x, x), x, Integral(f**(a + b*x + c*x**S(2))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/x**S(2), x), x, b*log(f)*Integral(f**(a + b*x + c*x**S(2))/x, x) + sqrt(pi)*sqrt(c)*f**(a - b**S(2)/(S(4)*c))*sqrt(log(f))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c)) - f**(a + b*x + c*x**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(a + b*x - c*x**S(2)), x), x, -sqrt(pi)*b**S(3)*exp(a + b**S(2)/(S(4)*c))*erf((b/S(2) - c*x)/sqrt(c))/(S(16)*c**(S(7)/2)) - b**S(2)*exp(a + b*x - c*x**S(2))/(S(8)*c**S(3)) - b*x*exp(a + b*x - c*x**S(2))/(S(4)*c**S(2)) - S(3)*sqrt(pi)*b*exp(a + b**S(2)/(S(4)*c))*erf((b/S(2) - c*x)/sqrt(c))/(S(8)*c**(S(5)/2)) - x**S(2)*exp(a + b*x - c*x**S(2))/(S(2)*c) - exp(a + b*x - c*x**S(2))/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(a + b*x - c*x**S(2)), x), x, -sqrt(pi)*b**S(2)*exp(a + b**S(2)/(S(4)*c))*erf((b/S(2) - c*x)/sqrt(c))/(S(8)*c**(S(5)/2)) - b*exp(a + b*x - c*x**S(2))/(S(4)*c**S(2)) - x*exp(a + b*x - c*x**S(2))/(S(2)*c) - sqrt(pi)*exp(a + b**S(2)/(S(4)*c))*erf((b/S(2) - c*x)/sqrt(c))/(S(4)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(a + b*x - c*x**S(2)), x), x, -sqrt(pi)*b*exp(a + b**S(2)/(S(4)*c))*erf((b/S(2) - c*x)/sqrt(c))/(S(4)*c**(S(3)/2)) - exp(a + b*x - c*x**S(2))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x - c*x**S(2)), x), x, -sqrt(pi)*exp(a + b**S(2)/(S(4)*c))*erf((b/S(2) - c*x)/sqrt(c))/(S(2)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x - c*x**S(2))/x, x), x, Integral(exp(a + b*x - c*x**S(2))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x - c*x**S(2))/x**S(2), x), x, b*Integral(exp(a + b*x - c*x**S(2))/x, x) + sqrt(pi)*sqrt(c)*exp(a + b**S(2)/(S(4)*c))*erf((b/S(2) - c*x)/sqrt(c)) - exp(a + b*x - c*x**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp((a + b*x)*(c + d*x)), x), x, x**S(2)*exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/(S(2)*b*d) - x*(a*d/S(4) + b*c/S(4))*exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/(b**S(2)*d**S(2)) - exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/(S(2)*b**S(2)*d**S(2)) + (a*d + b*c)**S(2)*exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/(S(8)*b**S(3)*d**S(3)) + sqrt(pi)*(S(3)*a*d/S(8) + S(3)*b*c/S(8))*exp(-(-a*d + b*c)**S(2)/(S(4)*b*d))*erfi((a*d/S(2) + b*c/S(2) + b*d*x)/(sqrt(b)*sqrt(d)))/(b**(S(5)/2)*d**(S(5)/2)) - sqrt(pi)*(a*d + b*c)**S(3)*exp(-(-a*d + b*c)**S(2)/(S(4)*b*d))*erfi((a*d/S(2) + b*c/S(2) + b*d*x)/(sqrt(b)*sqrt(d)))/(S(16)*b**(S(7)/2)*d**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp((a + b*x)*(c + d*x)), x), x, x*exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/(S(2)*b*d) + (-a*d/S(4) - b*c/S(4))*exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/(b**S(2)*d**S(2)) - sqrt(pi)*exp(-(-a*d + b*c)**S(2)/(S(4)*b*d))*erfi((a*d/S(2) + b*c/S(2) + b*d*x)/(sqrt(b)*sqrt(d)))/(S(4)*b**(S(3)/2)*d**(S(3)/2)) + sqrt(pi)*(a*d + b*c)**S(2)*exp(-(-a*d + b*c)**S(2)/(S(4)*b*d))*erfi((a*d/S(2) + b*c/S(2) + b*d*x)/(sqrt(b)*sqrt(d)))/(S(8)*b**(S(5)/2)*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp((a + b*x)*(c + d*x)), x), x, exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/(S(2)*b*d) - sqrt(pi)*(a*d/S(4) + b*c/S(4))*exp(-(-a*d + b*c)**S(2)/(S(4)*b*d))*erfi((a*d/S(2) + b*c/S(2) + b*d*x)/(sqrt(b)*sqrt(d)))/(b**(S(3)/2)*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp((a + b*x)*(c + d*x)), x), x, sqrt(pi)*exp(-(-a*d + b*c)**S(2)/(S(4)*b*d))*erfi((a*d/S(2) + b*c/S(2) + b*d*x)/(sqrt(b)*sqrt(d)))/(S(2)*sqrt(b)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp((a + b*x)*(c + d*x))/x, x), x, Integral(exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp((a + b*x)*(c + d*x))/x**S(2), x), x, sqrt(pi)*sqrt(b)*sqrt(d)*exp(-(-a*d + b*c)**S(2)/(S(4)*b*d))*erfi((a*d/S(2) + b*c/S(2) + b*d*x)/(sqrt(b)*sqrt(d))) + (a*d + b*c)*Integral(exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/x, x) - exp(a*c + b*d*x**S(2) + x*(a*d + b*c))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*(d + e*x)**S(3), x), x, e*f**(a + b*x + c*x**S(2))*(d + e*x)**S(2)/(S(2)*c*log(f)) - e**S(3)*f**(a + b*x + c*x**S(2))/(S(2)*c**S(2)*log(f)**S(2)) + e*f**(a + b*x + c*x**S(2))*(d + e*x)*(-b*e + S(2)*c*d)/(S(4)*c**S(2)*log(f)) + e*f**(a + b*x + c*x**S(2))*(-b*e + S(2)*c*d)**S(2)/(S(8)*c**S(3)*log(f)) - S(3)*sqrt(pi)*e**S(2)*f**(a - b**S(2)/(S(4)*c))*(-b*e + S(2)*c*d)*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(8)*c**(S(5)/2)*log(f)**(S(3)/2)) + sqrt(pi)*f**(a - b**S(2)/(S(4)*c))*(-b*e + S(2)*c*d)**S(3)*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(16)*c**(S(7)/2)*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*(d + e*x)**S(2), x), x, e*f**(a + b*x + c*x**S(2))*(d + e*x)/(S(2)*c*log(f)) + e*f**(a + b*x + c*x**S(2))*(-b*e + S(2)*c*d)/(S(4)*c**S(2)*log(f)) - sqrt(pi)*e**S(2)*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(4)*c**(S(3)/2)*log(f)**(S(3)/2)) + sqrt(pi)*f**(a - b**S(2)/(S(4)*c))*(-b*e + S(2)*c*d)**S(2)*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(8)*c**(S(5)/2)*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*(d + e*x), x), x, e*f**(a + b*x + c*x**S(2))/(S(2)*c*log(f)) + sqrt(pi)*f**(a - b**S(2)/(S(4)*c))*(-b*e/S(4) + c*d/S(2))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(c**(S(3)/2)*sqrt(log(f))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/(d + e*x), x), x, Integral(f**(a + b*x + c*x**S(2))/(d + e*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/(d + e*x)**S(2), x), x, sqrt(pi)*sqrt(c)*f**(a - b**S(2)/(S(4)*c))*sqrt(log(f))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/e**S(2) - f**(a + b*x + c*x**S(2))/(e*(d + e*x)) - (-b*e + S(2)*c*d)*log(f)*Integral(f**(a + b*x + c*x**S(2))/(d + e*x), x)/e**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/(d + e*x)**S(3), x), x, -sqrt(pi)*sqrt(c)*f**(a - b**S(2)/(S(4)*c))*(-b*e/S(2) + c*d)*log(f)**(S(3)/2)*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/e**S(4) + c*log(f)*Integral(f**(a + b*x + c*x**S(2))/(d + e*x), x)/e**S(2) - f**(a + b*x + c*x**S(2))/(S(2)*e*(d + e*x)**S(2)) + f**(a + b*x + c*x**S(2))*(-b*e/S(2) + c*d)*log(f)/(e**S(3)*(d + e*x)) + (-b*e + S(2)*c*d)**S(2)*log(f)**S(2)*Integral(f**(a + b*x + c*x**S(2))/(d + e*x), x)/(S(2)*e**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*(b + S(2)*c*x)**S(3), x), x, -S(4)*c*f**(a + b*x + c*x**S(2))/log(f)**S(2) + f**(a + b*x + c*x**S(2))*(b + S(2)*c*x)**S(2)/log(f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*(b + S(2)*c*x)**S(2), x), x, -sqrt(pi)*sqrt(c)*f**(a - b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/log(f)**(S(3)/2) + f**(a + b*x + c*x**S(2))*(b + S(2)*c*x)/log(f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*(b + S(2)*c*x), x), x, f**(a + b*x + c*x**S(2))/log(f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/(b + S(2)*c*x), x), x, f**(a - b**S(2)/(S(4)*c))*Ei((b + S(2)*c*x)**S(2)*log(f)/(S(4)*c))/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/(b + S(2)*c*x)**S(2), x), x, -f**(a + b*x + c*x**S(2))/(S(2)*c*(b + S(2)*c*x)) + sqrt(pi)*f**(a - b**S(2)/(S(4)*c))*sqrt(log(f))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(4)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))/(b + S(2)*c*x)**S(3), x), x, -f**(a + b*x + c*x**S(2))/(S(4)*c*(b + S(2)*c*x)**S(2)) + f**(a - b**S(2)/(S(4)*c))*log(f)*Ei((b + S(2)*c*x)**S(2)*log(f)/(S(4)*c))/(S(16)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(b*x + c*x**S(2))*(b + S(2)*c*x)**S(3), x), x, -S(4)*c*f**(b*x + c*x**S(2))/log(f)**S(2) + f**(b*x + c*x**S(2))*(b + S(2)*c*x)**S(2)/log(f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(b*x + c*x**S(2))*(b + S(2)*c*x)**S(2), x), x, -sqrt(pi)*sqrt(c)*f**(-b**S(2)/(S(4)*c))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/log(f)**(S(3)/2) + f**(b*x + c*x**S(2))*(b + S(2)*c*x)/log(f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(b*x + c*x**S(2))*(b + S(2)*c*x), x), x, f**(b*x + c*x**S(2))/log(f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(b*x + c*x**S(2))/(b + S(2)*c*x), x), x, f**(-b**S(2)/(S(4)*c))*Ei((b + S(2)*c*x)**S(2)*log(f)/(S(4)*c))/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(b*x + c*x**S(2))/(b + S(2)*c*x)**S(2), x), x, -f**(b*x + c*x**S(2))/(S(2)*c*(b + S(2)*c*x)) + sqrt(pi)*f**(-b**S(2)/(S(4)*c))*sqrt(log(f))*erfi((b/S(2) + c*x)*sqrt(log(f))/sqrt(c))/(S(4)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(b*x + c*x**S(2))/(b + S(2)*c*x)**S(3), x), x, -f**(b*x + c*x**S(2))/(S(4)*c*(b + S(2)*c*x)**S(2)) + f**(-b**S(2)/(S(4)*c))*log(f)*Ei((b + S(2)*c*x)**S(2)*log(f)/(S(4)*c))/(S(16)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*exp(c + d*x))), x), x, Integral(S(1)/(x*(a + b*exp(c + d*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*exp(c + d*x)), x), x, x/a - log(a + b*exp(c + d*x))/(a*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*exp(c + d*x)), x), x, -x*log(a*exp(-c - d*x)/b + S(1))/(a*d) + polylog(S(2), -a*exp(-c - d*x)/b)/(a*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*exp(c + d*x)), x), x, -x**S(2)*log(a*exp(-c - d*x)/b + S(1))/(a*d) + S(2)*x*polylog(S(2), -a*exp(-c - d*x)/b)/(a*d**S(2)) + S(2)*polylog(S(3), -a*exp(-c - d*x)/b)/(a*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*exp(c + d*x)), x), x, -x**S(3)*log(a*exp(-c - d*x)/b + S(1))/(a*d) + S(3)*x**S(2)*polylog(S(2), -a*exp(-c - d*x)/b)/(a*d**S(2)) + S(6)*x*polylog(S(3), -a*exp(-c - d*x)/b)/(a*d**S(3)) + S(6)*polylog(S(4), -a*exp(-c - d*x)/b)/(a*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*exp(c - d*x)), x), x, x/a + log(a + b*exp(c - d*x))/(a*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*exp(-c - d*x)), x), x, x/a + log(a + b*exp(-c - d*x))/(a*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*exp(c + d*x))**S(2)), x), x, Integral(S(1)/(x*(a + b*exp(c + d*x))**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(c + d*x))**(S(-2)), x), x, S(1)/(a*d*(a + b*exp(c + d*x))) + x/a**S(2) - log(a + b*exp(c + d*x))/(a**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*exp(c + d*x))**S(2), x), x, x/(a*d*(a + b*exp(c + d*x))) + x**S(2)/(S(2)*a**S(2)) - x*log(S(1) + b*exp(c + d*x)/a)/(a**S(2)*d) - x/(a**S(2)*d) + log(a + b*exp(c + d*x))/(a**S(2)*d**S(2)) - polylog(S(2), -b*exp(c + d*x)/a)/(a**S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*exp(c + d*x))**S(2), x), x, x**S(2)/(a*d*(a + b*exp(c + d*x))) + x**S(3)/(S(3)*a**S(2)) - x**S(2)*log(S(1) + b*exp(c + d*x)/a)/(a**S(2)*d) + S(2)*x*log(a*exp(-c - d*x)/b + S(1))/(a**S(2)*d**S(2)) - S(2)*x*polylog(S(2), -b*exp(c + d*x)/a)/(a**S(2)*d**S(2)) - S(2)*polylog(S(2), -a*exp(-c - d*x)/b)/(a**S(2)*d**S(3)) + S(2)*polylog(S(3), -b*exp(c + d*x)/a)/(a**S(2)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*exp(c + d*x))**S(2), x), x, x**S(3)/(a*d*(a + b*exp(c + d*x))) + x**S(4)/(S(4)*a**S(2)) - x**S(3)*log(S(1) + b*exp(c + d*x)/a)/(a**S(2)*d) + S(3)*x**S(2)*log(a*exp(-c - d*x)/b + S(1))/(a**S(2)*d**S(2)) - S(3)*x**S(2)*polylog(S(2), -b*exp(c + d*x)/a)/(a**S(2)*d**S(2)) - S(6)*x*polylog(S(2), -a*exp(-c - d*x)/b)/(a**S(2)*d**S(3)) + S(6)*x*polylog(S(3), -b*exp(c + d*x)/a)/(a**S(2)*d**S(3)) - S(6)*polylog(S(3), -a*exp(-c - d*x)/b)/(a**S(2)*d**S(4)) - S(6)*polylog(S(4), -b*exp(c + d*x)/a)/(a**S(2)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(c - d*x))**(S(-2)), x), x, -S(1)/(a*d*(a + b*exp(c - d*x))) + x/a**S(2) + log(a + b*exp(c - d*x))/(a**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(-c - d*x))**(S(-2)), x), x, -S(1)/(a*d*(a + b*exp(-c - d*x))) + x/a**S(2) + log(a + b*exp(-c - d*x))/(a**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*exp(c + d*x))**S(3)), x), x, Integral(S(1)/(x*(a + b*exp(c + d*x))**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(c + d*x))**(S(-3)), x), x, S(1)/(S(2)*a*d*(a + b*exp(c + d*x))**S(2)) + S(1)/(a**S(2)*d*(a + b*exp(c + d*x))) + x/a**S(3) - log(a + b*exp(c + d*x))/(a**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*exp(c + d*x))**S(3), x), x, x/(S(2)*a*d*(a + b*exp(c + d*x))**S(2)) + x/(a**S(2)*d*(a + b*exp(c + d*x))) - S(1)/(S(2)*a**S(2)*d**S(2)*(a + b*exp(c + d*x))) + x**S(2)/(S(2)*a**S(3)) - x*log(S(1) + b*exp(c + d*x)/a)/(a**S(3)*d) - S(3)*x/(S(2)*a**S(3)*d) + S(3)*log(a + b*exp(c + d*x))/(S(2)*a**S(3)*d**S(2)) - polylog(S(2), -b*exp(c + d*x)/a)/(a**S(3)*d**S(2)), expand=True, _diff=True, _numerical=True) # recursion assert rubi_test(rubi_integrate(x**S(2)/(a + b*exp(c + d*x))**S(3), x), x, x**S(2)/(S(2)*a*d*(a + b*exp(c + d*x))**S(2)) + x**S(2)/(a**S(2)*d*(a + b*exp(c + d*x))) - x/(a**S(2)*d**S(2)*(a + b*exp(c + d*x))) + x**S(3)/(S(3)*a**S(3)) - x**S(2)*log(S(1) + b*exp(c + d*x)/a)/(a**S(3)*d) - S(3)*x**S(2)/(S(2)*a**S(3)*d) + S(3)*x*log(S(1) + b*exp(c + d*x)/a)/(a**S(3)*d**S(2)) - S(2)*x*polylog(S(2), -b*exp(c + d*x)/a)/(a**S(3)*d**S(2)) + x/(a**S(3)*d**S(2)) - log(a + b*exp(c + d*x))/(a**S(3)*d**S(3)) + S(3)*polylog(S(2), -b*exp(c + d*x)/a)/(a**S(3)*d**S(3)) + S(2)*polylog(S(3), -b*exp(c + d*x)/a)/(a**S(3)*d**S(3)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)/(a + b*exp(c + d*x))**S(3), x), x, x**S(2)/(S(2)*a*d*(a + b*exp(c + d*x))**S(2)) + x**S(2)/(a**S(2)*d*(a + b*exp(c + d*x))) - x/(a**S(2)*d**S(2)*(a + b*exp(c + d*x))) + x**S(3)/(S(3)*a**S(3)) - x**S(2)*log(S(1) + b*exp(c + d*x)/a)/(a**S(3)*d) - x**S(2)/(S(2)*a**S(3)*d) + x*log(S(1) + b*exp(c + d*x)/a)/(a**S(3)*d**S(2)) + S(2)*x*log(a*exp(-c - d*x)/b + S(1))/(a**S(3)*d**S(2)) - S(2)*x*polylog(S(2), -b*exp(c + d*x)/a)/(a**S(3)*d**S(2)) + x/(a**S(3)*d**S(2)) - log(a + b*exp(c + d*x))/(a**S(3)*d**S(3)) + polylog(S(2), -b*exp(c + d*x)/a)/(a**S(3)*d**S(3)) - S(2)*polylog(S(2), -a*exp(-c - d*x)/b)/(a**S(3)*d**S(3)) + S(2)*polylog(S(3), -b*exp(c + d*x)/a)/(a**S(3)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(c - d*x))**(S(-3)), x), x, -S(1)/(S(2)*a*d*(a + b*exp(c - d*x))**S(2)) - S(1)/(a**S(2)*d*(a + b*exp(c - d*x))) + x/a**S(3) + log(a + b*exp(c - d*x))/(a**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(-c - d*x))**(S(-3)), x), x, -S(1)/(S(2)*a*d*(a + b*exp(-c - d*x))**S(2)) - S(1)/(a**S(2)*d*(a + b*exp(-c - d*x))) + x/a**S(3) + log(a + b*exp(-c - d*x))/(a**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x)/(x**S(2)*(c + d*x**S(2))), x), x, b*exp(a)*Ei(b*x)/c - sqrt(d)*exp(a - b*sqrt(-c)/sqrt(d))*Ei(b*(sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*(-c)**(S(3)/2)) + sqrt(d)*exp(a + b*sqrt(-c)/sqrt(d))*Ei(-b*(-sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*(-c)**(S(3)/2)) - exp(a + b*x)/(c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x)/(x*(c + d*x**S(2))), x), x, exp(a)*Ei(b*x)/c - exp(a - b*sqrt(-c)/sqrt(d))*Ei(b*(sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*c) - exp(a + b*sqrt(-c)/sqrt(d))*Ei(-b*(-sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x)/(c + d*x**S(2)), x), x, -exp(a - b*sqrt(-c)/sqrt(d))*Ei(b*(sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*sqrt(d)*sqrt(-c)) + exp(a + b*sqrt(-c)/sqrt(d))*Ei(-b*(-sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*sqrt(d)*sqrt(-c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(a + b*x)/(c + d*x**S(2)), x), x, exp(a - b*sqrt(-c)/sqrt(d))*Ei(b*(sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*d) + exp(a + b*sqrt(-c)/sqrt(d))*Ei(-b*(-sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(a + b*x)/(c + d*x**S(2)), x), x, -sqrt(-c)*exp(a - b*sqrt(-c)/sqrt(d))*Ei(b*(sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*d**(S(3)/2)) + sqrt(-c)*exp(a + b*sqrt(-c)/sqrt(d))*Ei(-b*(-sqrt(d)*x + sqrt(-c))/sqrt(d))/(S(2)*d**(S(3)/2)) + exp(a + b*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(d + e*x)/(x**S(2)*(a + b*x + c*x**S(2))), x), x, e*exp(d)*Ei(e*x)/a - exp(d + e*x)/(a*x) - b*exp(d)*Ei(e*x)/a**S(2) + (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*exp(d - e*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*a**S(2)) + (b + (S(2)*a*c - b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*exp(d - e*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(d + e*x)/(x*(a + b*x + c*x**S(2))), x), x, -(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*exp(d - e*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*a) - (b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*exp(d - e*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*a) + exp(d)*Ei(e*x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(d + e*x)/(a + b*x + c*x**S(2)), x), x, exp(d - e*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/sqrt(-S(4)*a*c + b**S(2)) - exp(d - e*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(d + e*x)/(a + b*x + c*x**S(2)), x), x, (-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*exp(d - e*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*c) + (b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*exp(d - e*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(d + e*x)/(a + b*x + c*x**S(2)), x), x, exp(d + e*x)/(c*e) - (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*exp(d - e*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*c**S(2)) - (b + (S(2)*a*c - b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*exp(d - e*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(d + e*x)/(a + b*x + c*x**S(2)), x), x, -b*exp(d + e*x)/(c**S(2)*e) + x*exp(d + e*x)/(c*e) - exp(d + e*x)/(c*e**S(2)) + (-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*exp(d - e*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*c**S(3)) + (-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*exp(d - e*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))*Ei(e*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/(S(2)**x*b + a), x), x, S(2)**x/(b*log(S(2))) - a*log(S(2)**x*b + a)/(b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/(S(2)**x*b + a), x), x, S(2)**x/(b*log(S(2))) - a*log(S(2)**x*b + a)/(b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/(-S(2)**x*b + a), x), x, -S(2)**x/(b*log(S(2))) - a*log(-S(2)**x*b + a)/(b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/(-S(2)**x*b + a), x), x, -S(2)**x/(b*log(S(2))) - a*log(-S(2)**x*b + a)/(b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/(a + S(2)**(-x)*b), x), x, -S(2)**x*b/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))/(a*log(S(2))) + b**S(2)*x/a**S(3) + b**S(2)*log(a + S(2)**(-x)*b)/(a**S(3)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/(a + S(2)**(-x)*b), x), x, -S(2)**x*b/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))/(a*log(S(2))) + b**S(2)*x/a**S(3) + b**S(2)*log(a + S(2)**(-x)*b)/(a**S(3)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/(a - S(2)**(-x)*b), x), x, S(2)**x*b/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))/(a*log(S(2))) + b**S(2)*x/a**S(3) + b**S(2)*log(a - S(2)**(-x)*b)/(a**S(3)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/(a - S(2)**(-x)*b), x), x, S(2)**x*b/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))/(a*log(S(2))) + b**S(2)*x/a**S(3) + b**S(2)*log(a - S(2)**(-x)*b)/(a**S(3)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(S(4)**x*b + a), x), x, atan(S(2)**x*sqrt(b)/sqrt(a))/(sqrt(a)*sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(S(2)**(S(2)*x)*b + a), x), x, atan(S(2)**x*sqrt(b)/sqrt(a))/(sqrt(a)*sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(-S(4)**x*b + a), x), x, atanh(S(2)**x*sqrt(b)/sqrt(a))/(sqrt(a)*sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(-S(2)**(S(2)*x)*b + a), x), x, atanh(S(2)**x*sqrt(b)/sqrt(a))/(sqrt(a)*sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(a + S(4)**(-x)*b), x), x, S(2)**x/(a*log(S(2))) - sqrt(b)*atan(S(2)**x*sqrt(a)/sqrt(b))/(a**(S(3)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(a + S(2)**(-S(2)*x)*b), x), x, S(2)**x/(a*log(S(2))) - sqrt(b)*atan(S(2)**x*sqrt(a)/sqrt(b))/(a**(S(3)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(a - S(4)**(-x)*b), x), x, S(2)**x/(a*log(S(2))) - sqrt(b)*atanh(S(2)**x*sqrt(a)/sqrt(b))/(a**(S(3)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/(a - S(2)**(-S(2)*x)*b), x), x, S(2)**x/(a*log(S(2))) - sqrt(b)*atanh(S(2)**x*sqrt(a)/sqrt(b))/(a**(S(3)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(S(4)**x*b + a), x), x, atanh(S(2)**x*sqrt(b)/sqrt(S(2)**(S(2)*x)*b + a))/(sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(S(2)**(S(2)*x)*b + a), x), x, atanh(S(2)**x*sqrt(b)/sqrt(S(2)**(S(2)*x)*b + a))/(sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(-S(4)**x*b + a), x), x, atan(S(2)**x*sqrt(b)/sqrt(-S(2)**(S(2)*x)*b + a))/(sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(-S(2)**(S(2)*x)*b + a), x), x, atan(S(2)**x*sqrt(b)/sqrt(-S(2)**(S(2)*x)*b + a))/(sqrt(b)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(a + S(4)**(-x)*b), x), x, S(2)**x*sqrt(a + S(2)**(-S(2)*x)*b)/(a*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(a + S(2)**(-S(2)*x)*b), x), x, S(2)**x*sqrt(a + S(2)**(-S(2)*x)*b)/(a*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(a - S(4)**(-x)*b), x), x, S(2)**x*sqrt(a - S(2)**(-S(2)*x)*b)/(a*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x/sqrt(a - S(2)**(-S(2)*x)*b), x), x, S(2)**x*sqrt(a - S(2)**(-S(2)*x)*b)/(a*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/sqrt(S(2)**x*b + a), x), x, -S(2)*a*sqrt(S(2)**x*b + a)/(b**S(2)*log(S(2))) + S(2)*(S(2)**x*b + a)**(S(3)/2)/(S(3)*b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/sqrt(S(2)**x*b + a), x), x, -S(2)*a*sqrt(S(2)**x*b + a)/(b**S(2)*log(S(2))) + S(2)*(S(2)**x*b + a)**(S(3)/2)/(S(3)*b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/sqrt(-S(2)**x*b + a), x), x, -S(2)*a*sqrt(-S(2)**x*b + a)/(b**S(2)*log(S(2))) + S(2)*(-S(2)**x*b + a)**(S(3)/2)/(S(3)*b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/sqrt(-S(2)**x*b + a), x), x, -S(2)*a*sqrt(-S(2)**x*b + a)/(b**S(2)*log(S(2))) + S(2)*(-S(2)**x*b + a)**(S(3)/2)/(S(3)*b**S(2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/sqrt(a + S(2)**(-x)*b), x), x, -S(3)*S(2)**(x + S(-2))*b*sqrt(a + S(2)**(-x)*b)/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))*sqrt(a + S(2)**(-x)*b)/(a*log(S(2))) + S(3)*b**S(2)*atanh(sqrt(a + S(2)**(-x)*b)/sqrt(a))/(S(4)*a**(S(5)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/sqrt(a + S(2)**(-x)*b), x), x, -S(3)*S(2)**(x + S(-2))*b*sqrt(a + S(2)**(-x)*b)/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))*sqrt(a + S(2)**(-x)*b)/(a*log(S(2))) + S(3)*b**S(2)*atanh(sqrt(a + S(2)**(-x)*b)/sqrt(a))/(S(4)*a**(S(5)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)**x/sqrt(a - S(2)**(-x)*b), x), x, S(3)*S(2)**(x + S(-2))*b*sqrt(a - S(2)**(-x)*b)/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))*sqrt(a - S(2)**(-x)*b)/(a*log(S(2))) + S(3)*b**S(2)*atanh(sqrt(a - S(2)**(-x)*b)/sqrt(a))/(S(4)*a**(S(5)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(2)*x)/sqrt(a - S(2)**(-x)*b), x), x, S(3)*S(2)**(x + S(-2))*b*sqrt(a - S(2)**(-x)*b)/(a**S(2)*log(S(2))) + S(2)**(S(2)*x + S(-1))*sqrt(a - S(2)**(-x)*b)/(a*log(S(2))) + S(3)*b**S(2)*atanh(sqrt(a - S(2)**(-x)*b)/sqrt(a))/(S(4)*a**(S(5)/2)*log(S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(S(2)*x) + S(2)*exp(x) + S(1)), x), x, x - log(exp(x) + S(1)) + S(1)/(exp(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(S(2)*x) + S(3)*exp(x) + S(2)), x), x, x/S(2) - log(exp(x) + S(1)) + log(exp(x) + S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(S(2)*x) + exp(x) + S(-1)), x), x, -x + (-sqrt(S(5)) + S(5))*log(S(2)*exp(x) + S(1) + sqrt(S(5)))/S(10) + (sqrt(S(5)) + S(5))*log(S(2)*exp(x) - sqrt(S(5)) + S(1))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(S(2)*x) + S(3)*exp(x) + S(3)), x), x, x/S(3) - log(exp(S(2)*x) + S(3)*exp(x) + S(3))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*exp(x) + S(3))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*exp(x) + c*exp(S(2)*x)), x), x, b*atanh((b + S(2)*c*exp(x))/sqrt(-S(4)*a*c + b**S(2)))/(a*sqrt(-S(4)*a*c + b**S(2))) + x/a - log(a + b*exp(x) + c*exp(S(2)*x))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(exp(S(2)*x) + S(2)*exp(x) + S(1)), x), x, x**S(2)/S(2) - x*log(exp(x) + S(1)) - x + x/(exp(x) + S(1)) + log(exp(x) + S(1)) - polylog(S(2), -exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(exp(S(2)*x) + S(3)*exp(x) + S(2)), x), x, -x*log(S(1) + exp(-x)) + x*log(S(1) + S(2)*exp(-x))/S(2) - polylog(S(2), -S(2)*exp(-x))/S(2) + polylog(S(2), -exp(-x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(exp(S(2)*x) + exp(x) + S(-1)), x), x, S(2)*sqrt(S(5))*x*log(S(1) + (S(1)/2 + sqrt(S(5))/S(2))*exp(-x))/(S(5)*(S(1) + sqrt(S(5)))) - S(2)*sqrt(S(5))*x*log(S(1) + (-sqrt(S(5))/S(2) + S(1)/2)*exp(-x))/(S(5)*(-sqrt(S(5)) + S(1))) + S(2)*sqrt(S(5))*polylog(S(2), (S(-1)/2 + sqrt(S(5))/S(2))*exp(-x))/(S(5)*(-sqrt(S(5)) + S(1))) - S(2)*sqrt(S(5))*polylog(S(2), (-sqrt(S(5))/S(2) + S(-1)/2)*exp(-x))/(S(5)*(S(1) + sqrt(S(5)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(exp(S(2)*x) + S(3)*exp(x) + S(3)), x), x, -S(2)*sqrt(S(3))*x*log(S(1) + (S(3)/2 - sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(sqrt(S(3)) + S(3)*I)) + S(2)*sqrt(S(3))*x*log(S(1) + (S(3)/2 + sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(-sqrt(S(3)) + S(3)*I)) - S(2)*sqrt(S(3))*polylog(S(2), (S(-3)/2 - sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(-sqrt(S(3)) + S(3)*I)) + S(2)*sqrt(S(3))*polylog(S(2), (S(-3)/2 + sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(sqrt(S(3)) + S(3)*I)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*exp(x) + c*exp(S(2)*x)), x), x, S(2)*c*x*log(S(1) + (b/S(2) + sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*x*log(S(1) + (b/S(2) - sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*polylog(S(2), (-b/S(2) - sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*polylog(S(2), (-b/S(2) + sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(exp(S(2)*x) + S(2)*exp(x) + S(1)), x), x, x**S(3)/S(3) - x**S(2)*log(exp(x) + S(1)) + x**S(2)/(exp(x) + S(1)) + S(2)*x*log(S(1) + exp(-x)) - S(2)*x*polylog(S(2), -exp(x)) - S(2)*polylog(S(2), -exp(-x)) + S(2)*polylog(S(3), -exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(exp(S(2)*x) + S(3)*exp(x) + S(2)), x), x, -x**S(2)*log(S(1) + exp(-x)) + x**S(2)*log(S(1) + S(2)*exp(-x))/S(2) - x*polylog(S(2), -S(2)*exp(-x)) + S(2)*x*polylog(S(2), -exp(-x)) - polylog(S(3), -S(2)*exp(-x)) + S(2)*polylog(S(3), -exp(-x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(exp(S(2)*x) + exp(x) + S(-1)), x), x, S(2)*sqrt(S(5))*x**S(2)*log(S(1) + (S(1)/2 + sqrt(S(5))/S(2))*exp(-x))/(S(5)*(S(1) + sqrt(S(5)))) - S(2)*sqrt(S(5))*x**S(2)*log(S(1) + (-sqrt(S(5))/S(2) + S(1)/2)*exp(-x))/(S(5)*(-sqrt(S(5)) + S(1))) + S(4)*sqrt(S(5))*x*polylog(S(2), (S(-1)/2 + sqrt(S(5))/S(2))*exp(-x))/(S(5)*(-sqrt(S(5)) + S(1))) - S(4)*sqrt(S(5))*x*polylog(S(2), (-sqrt(S(5))/S(2) + S(-1)/2)*exp(-x))/(S(5)*(S(1) + sqrt(S(5)))) + S(4)*sqrt(S(5))*polylog(S(3), (S(-1)/2 + sqrt(S(5))/S(2))*exp(-x))/(S(5)*(-sqrt(S(5)) + S(1))) - S(4)*sqrt(S(5))*polylog(S(3), (-sqrt(S(5))/S(2) + S(-1)/2)*exp(-x))/(S(5)*(S(1) + sqrt(S(5)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(exp(S(2)*x) + S(3)*exp(x) + S(3)), x), x, -S(2)*sqrt(S(3))*x**S(2)*log(S(1) + (S(3)/2 - sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(sqrt(S(3)) + S(3)*I)) + S(2)*sqrt(S(3))*x**S(2)*log(S(1) + (S(3)/2 + sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(-sqrt(S(3)) + S(3)*I)) - S(4)*sqrt(S(3))*x*polylog(S(2), (S(-3)/2 - sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(-sqrt(S(3)) + S(3)*I)) + S(4)*sqrt(S(3))*x*polylog(S(2), (S(-3)/2 + sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(sqrt(S(3)) + S(3)*I)) - S(4)*sqrt(S(3))*polylog(S(3), (S(-3)/2 - sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(-sqrt(S(3)) + S(3)*I)) + S(4)*sqrt(S(3))*polylog(S(3), (S(-3)/2 + sqrt(S(3))*I/S(2))*exp(-x))/(S(3)*(sqrt(S(3)) + S(3)*I)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*exp(x) + c*exp(S(2)*x)), x), x, S(2)*c*x**S(2)*log(S(1) + (b/S(2) + sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*x**S(2)*log(S(1) + (b/S(2) - sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - S(4)*c*x*polylog(S(2), (-b/S(2) - sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(4)*c*x*polylog(S(2), (-b/S(2) + sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - S(4)*c*polylog(S(3), (-b/S(2) - sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(4)*c*polylog(S(3), (-b/S(2) + sqrt(-S(4)*a*c + b**S(2))/S(2))*exp(-x)/c)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(2)*f**(c + d*x) + f**(S(2)*c + S(2)*d*x) + S(1)), x), x, x - log(f**(c + d*x) + S(1))/(d*log(f)) + S(1)/(d*(f**(c + d*x) + S(1))*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*f**(c + d*x) + c*f**(S(2)*c + S(2)*d*x)), x), x, b*atanh((b + S(2)*c*f**(c + d*x))/sqrt(-S(4)*a*c + b**S(2)))/(a*d*sqrt(-S(4)*a*c + b**S(2))*log(f)) + x/a - log(a + b*f**(c + d*x) + c*f**(S(2)*c + S(2)*d*x))/(S(2)*a*d*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*f**(g + h*x) + c*f**(S(2)*g + S(2)*h*x)), x), x, b*atanh((b + S(2)*c*f**(g + h*x))/sqrt(-S(4)*a*c + b**S(2)))/(a*h*sqrt(-S(4)*a*c + b**S(2))*log(f)) + x/a - log(a + b*f**(g + h*x) + c*f**(S(2)*g + S(2)*h*x))/(S(2)*a*h*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(S(2)*f**(c + d*x) + f**(S(2)*c + S(2)*d*x) + S(1)), x), x, x**S(2)/S(2) - x*log(f**(c + d*x) + S(1))/(d*log(f)) - x/(d*log(f)) + x/(d*(f**(c + d*x) + S(1))*log(f)) + log(f**(c + d*x) + S(1))/(d**S(2)*log(f)**S(2)) - polylog(S(2), -f**(c + d*x))/(d**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*f**(c + d*x) + c*f**(S(2)*c + S(2)*d*x)), x), x, S(2)*c*x*log(S(1) + f**(-c - d*x)*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d*(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)) - S(2)*c*x*log(S(1) + f**(-c - d*x)*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d*(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)) - S(2)*c*polylog(S(2), -f**(-c - d*x)*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)**S(2)) + S(2)*c*polylog(S(2), -f**(-c - d*x)*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(S(2)*f**(c + d*x) + f**(S(2)*c + S(2)*d*x) + S(1)), x), x, x**S(3)/S(3) - x**S(2)*log(f**(c + d*x) + S(1))/(d*log(f)) + x**S(2)/(d*(f**(c + d*x) + S(1))*log(f)) + S(2)*x*log(f**(-c - d*x) + S(1))/(d**S(2)*log(f)**S(2)) - S(2)*x*polylog(S(2), -f**(c + d*x))/(d**S(2)*log(f)**S(2)) - S(2)*polylog(S(2), -f**(-c - d*x))/(d**S(3)*log(f)**S(3)) + S(2)*polylog(S(3), -f**(c + d*x))/(d**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*f**(c + d*x) + c*f**(S(2)*c + S(2)*d*x)), x), x, S(2)*c*x**S(2)*log(S(1) + f**(-c - d*x)*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d*(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)) - S(2)*c*x**S(2)*log(S(1) + f**(-c - d*x)*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d*(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)) - S(4)*c*x*polylog(S(2), -f**(-c - d*x)*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)**S(2)) + S(4)*c*x*polylog(S(2), -f**(-c - d*x)*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)**S(2)) - S(4)*c*polylog(S(3), -f**(-c - d*x)*(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d**S(3)*(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)**S(3)) + S(4)*c*polylog(S(3), -f**(-c - d*x)*(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c))/(d**S(3)*(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*f**(g + h*x))/(a + b*f**(g + h*x) + c*f**(S(2)*g + S(2)*h*x)), x), x, d*x/a - d*log(a + b*f**(g + h*x) + c*f**(S(2)*g + S(2)*h*x))/(S(2)*a*h*log(f)) + (-S(2)*a*e + b*d)*atanh((b + S(2)*c*f**(g + h*x))/sqrt(-S(4)*a*c + b**S(2)))/(a*h*sqrt(-S(4)*a*c + b**S(2))*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*f**(g + h*x))/(a + b*f**(g + h*x) + c*f**(S(2)*g + S(2)*h*x)), x), x, d*x/a - d*log(a + b*f**(g + h*x) + c*f**(S(2)*g + S(2)*h*x))/(S(2)*a*h*log(f)) + (-S(2)*a*e + b*d)*atanh((b + S(2)*c*f**(g + h*x))/sqrt(-S(4)*a*c + b**S(2)))/(a*h*sqrt(-S(4)*a*c + b**S(2))*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(x) + S(2) + exp(-x)), x), x, -S(1)/(exp(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(exp(x) + S(2) + exp(-x)), x), x, x - x/(exp(x) + S(1)) - log(exp(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(exp(x) + S(2) + exp(-x)), x), x, -x**S(2)/(exp(x) + S(1)) - S(2)*x*log(S(1) + exp(-x)) + S(2)*polylog(S(2), -exp(-x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(f**(-c - d*x) + f**(c + d*x) + S(2)), x), x, -S(1)/(d*(f**(c + d*x) + S(1))*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(f**(-c - d*x) + f**(c + d*x) + S(2)), x), x, x/(d*log(f)) - x/(d*(f**(c + d*x) + S(1))*log(f)) - log(f**(c + d*x) + S(1))/(d**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(f**(-c - d*x) + f**(c + d*x) + S(2)), x), x, -x**S(2)/(d*(f**(c + d*x) + S(1))*log(f)) - S(2)*x*log(f**(-c - d*x) + S(1))/(d**S(2)*log(f)**S(2)) + S(2)*polylog(S(2), -f**(-c - d*x))/(d**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(3)**x + S(2) + S(3)**(-x)), x), x, -S(1)/((S(3)**x + S(1))*log(S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(2)*exp(x) + S(1) - exp(-x)), x), x, log(-S(2)*exp(x) + S(1))/S(3) - log(exp(x) + S(1))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*exp(-x) + c*exp(x)), x), x, -S(2)*atanh((a + S(2)*c*exp(x))/sqrt(a**S(2) - S(4)*b*c))/sqrt(a**S(2) - S(4)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*exp(-x) + c*exp(x)), x), x, x*log(S(2)*c*exp(x)/(a - sqrt(a**S(2) - S(4)*b*c)) + S(1))/sqrt(a**S(2) - S(4)*b*c) - x*log(S(2)*c*exp(x)/(a + sqrt(a**S(2) - S(4)*b*c)) + S(1))/sqrt(a**S(2) - S(4)*b*c) + polylog(S(2), -S(2)*c*exp(x)/(a - sqrt(a**S(2) - S(4)*b*c)))/sqrt(a**S(2) - S(4)*b*c) - polylog(S(2), -S(2)*c*exp(x)/(a + sqrt(a**S(2) - S(4)*b*c)))/sqrt(a**S(2) - S(4)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*exp(-x) + c*exp(x)), x), x, x**S(2)*log(S(2)*c*exp(x)/(a - sqrt(a**S(2) - S(4)*b*c)) + S(1))/sqrt(a**S(2) - S(4)*b*c) - x**S(2)*log(S(2)*c*exp(x)/(a + sqrt(a**S(2) - S(4)*b*c)) + S(1))/sqrt(a**S(2) - S(4)*b*c) + S(2)*x*polylog(S(2), -S(2)*c*exp(x)/(a - sqrt(a**S(2) - S(4)*b*c)))/sqrt(a**S(2) - S(4)*b*c) - S(2)*x*polylog(S(2), -S(2)*c*exp(x)/(a + sqrt(a**S(2) - S(4)*b*c)))/sqrt(a**S(2) - S(4)*b*c) - S(2)*polylog(S(3), -S(2)*c*exp(x)/(a - sqrt(a**S(2) - S(4)*b*c)))/sqrt(a**S(2) - S(4)*b*c) + S(2)*polylog(S(3), -S(2)*c*exp(x)/(a + sqrt(a**S(2) - S(4)*b*c)))/sqrt(a**S(2) - S(4)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*f**(-c - d*x) + c*f**(c + d*x)), x), x, -S(2)*atanh((a + S(2)*c*f**(c + d*x))/sqrt(a**S(2) - S(4)*b*c))/(d*sqrt(a**S(2) - S(4)*b*c)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*f**(-c - d*x) + c*f**(c + d*x)), x), x, x*log(S(2)*c*f**(c + d*x)/(a - sqrt(a**S(2) - S(4)*b*c)) + S(1))/(d*sqrt(a**S(2) - S(4)*b*c)*log(f)) - x*log(S(2)*c*f**(c + d*x)/(a + sqrt(a**S(2) - S(4)*b*c)) + S(1))/(d*sqrt(a**S(2) - S(4)*b*c)*log(f)) + polylog(S(2), -S(2)*c*f**(c + d*x)/(a - sqrt(a**S(2) - S(4)*b*c)))/(d**S(2)*sqrt(a**S(2) - S(4)*b*c)*log(f)**S(2)) - polylog(S(2), -S(2)*c*f**(c + d*x)/(a + sqrt(a**S(2) - S(4)*b*c)))/(d**S(2)*sqrt(a**S(2) - S(4)*b*c)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*f**(-c - d*x) + c*f**(c + d*x)), x), x, x**S(2)*log(S(2)*c*f**(c + d*x)/(a - sqrt(a**S(2) - S(4)*b*c)) + S(1))/(d*sqrt(a**S(2) - S(4)*b*c)*log(f)) - x**S(2)*log(S(2)*c*f**(c + d*x)/(a + sqrt(a**S(2) - S(4)*b*c)) + S(1))/(d*sqrt(a**S(2) - S(4)*b*c)*log(f)) + S(2)*x*polylog(S(2), -S(2)*c*f**(c + d*x)/(a - sqrt(a**S(2) - S(4)*b*c)))/(d**S(2)*sqrt(a**S(2) - S(4)*b*c)*log(f)**S(2)) - S(2)*x*polylog(S(2), -S(2)*c*f**(c + d*x)/(a + sqrt(a**S(2) - S(4)*b*c)))/(d**S(2)*sqrt(a**S(2) - S(4)*b*c)*log(f)**S(2)) - S(2)*polylog(S(3), -S(2)*c*f**(c + d*x)/(a - sqrt(a**S(2) - S(4)*b*c)))/(d**S(3)*sqrt(a**S(2) - S(4)*b*c)*log(f)**S(3)) + S(2)*polylog(S(3), -S(2)*c*f**(c + d*x)/(a + sqrt(a**S(2) - S(4)*b*c)))/(d**S(3)*sqrt(a**S(2) - S(4)*b*c)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((F**(sqrt(-a*x + S(1))/sqrt(a*x + S(1))))**n/(-a**S(2)*x**S(2) + S(1)), x), x, -F**(-n*sqrt(-a*x + S(1))/sqrt(a*x + S(1)))*(F**(sqrt(-a*x + S(1))/sqrt(a*x + S(1))))**n*Ei(n*sqrt(-a*x + S(1))*log(F)/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(S(3)*sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/(-a**S(2)*x**S(2) + S(1)), x), x, -Ei(S(3)*sqrt(-a*x + S(1))*log(F)/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(S(2)*sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/(-a**S(2)*x**S(2) + S(1)), x), x, -Ei(S(2)*sqrt(-a*x + S(1))*log(F)/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/(-a**S(2)*x**S(2) + S(1)), x), x, -Ei(sqrt(-a*x + S(1))*log(F)/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(-sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/(-a**S(2)*x**S(2) + S(1)), x), x, -Ei(-sqrt(-a*x + S(1))*log(F)/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(-S(2)*sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/(-a**S(2)*x**S(2) + S(1)), x), x, -Ei(-S(2)*sqrt(-a*x + S(1))*log(F)/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((F**(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))*b + a)**n/(-c**S(2)*x**S(2) + S(1)), x), x, -Integral((F**x*b + a)**n/x, (x, sqrt(-c*x + S(1))/sqrt(c*x + S(1))))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((F**(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))*b + a)**S(3)/(-c**S(2)*x**S(2) + S(1)), x), x, -a**S(3)*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/c - S(3)*a**S(2)*b*Ei(sqrt(-c*x + S(1))*log(F)/sqrt(c*x + S(1)))/c - S(3)*a*b**S(2)*Ei(S(2)*sqrt(-c*x + S(1))*log(F)/sqrt(c*x + S(1)))/c - b**S(3)*Ei(S(3)*sqrt(-c*x + S(1))*log(F)/sqrt(c*x + S(1)))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((F**(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))*b + a)**S(2)/(-c**S(2)*x**S(2) + S(1)), x), x, -a**S(2)*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/c - S(2)*a*b*Ei(sqrt(-c*x + S(1))*log(F)/sqrt(c*x + S(1)))/c - b**S(2)*Ei(S(2)*sqrt(-c*x + S(1))*log(F)/sqrt(c*x + S(1)))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((F**(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))*b + a)/(-c**S(2)*x**S(2) + S(1)), x), x, -a*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/c - b*Ei(sqrt(-c*x + S(1))*log(F)/sqrt(c*x + S(1)))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((F**(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))*b + a)*(-c**S(2)*x**S(2) + S(1))), x), x, -Integral(S(1)/(x*(F**x*b + a)), (x, sqrt(-c*x + S(1))/sqrt(c*x + S(1))))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((F**(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))*b + a)**S(2)*(-c**S(2)*x**S(2) + S(1))), x), x, -Integral(S(1)/(x*(F**x*b + a)**S(2)), (x, sqrt(-c*x + S(1))/sqrt(c*x + S(1))))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**x*x**S(2), x), x, a**x*b**x*x**S(2)/(log(a) + log(b)) - S(2)*a**x*b**x*x/(log(a) + log(b))**S(2) + S(2)*a**x*b**x/(log(a) + log(b))**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**x*x, x), x, a**x*b**x*x/(log(a) + log(b)) - a**x*b**x/(log(a) + log(b))**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**x, x), x, a**x*b**x/(log(a) + log(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**x/x, x), x, Ei(x*(log(a) + log(b))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**x/x**S(2), x), x, -a**x*b**x/x + (log(a) + log(b))*Ei(x*(log(a) + log(b))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**x/x**S(3), x), x, -a**x*b**x*(log(a) + log(b))/(S(2)*x) - a**x*b**x/(S(2)*x**S(2)) + (log(a) + log(b))**S(2)*Ei(x*(log(a) + log(b)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**x*c**x, x), x, a**x*b**x*c**x/(log(a) + log(b) + log(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**(-x), x), x, a**x*b**(-x)/(log(a) - log(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**x*b**(-x)*x**S(2), x), x, a**x*b**(-x)*x**S(2)/(log(a) - log(b)) - S(2)*a**x*b**(-x)*x/(log(a) - log(b))**S(2) + S(2)*a**x*b**(-x)/(log(a) - log(b))**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(a + b*exp(x)), x), x, -a*log(a + b*exp(x))/b**S(2) + exp(x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(a + b*exp(x))**S(2), x), x, a/(b**S(2)*(a + b*exp(x))) + log(a + b*exp(x))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(a + b*exp(x))**S(3), x), x, exp(S(2)*x)/(S(2)*a*(a + b*exp(x))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(a + b*exp(x))**S(4), x), x, a/(S(3)*b**S(2)*(a + b*exp(x))**S(3)) - S(1)/(S(2)*b**S(2)*(a + b*exp(x))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(4)*x)/(a + b*exp(S(2)*x)), x), x, -a*log(a + b*exp(S(2)*x))/(S(2)*b**S(2)) + exp(S(2)*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(4)*x)/(a + b*exp(S(2)*x))**S(2), x), x, a/(S(2)*b**S(2)*(a + b*exp(S(2)*x))) + log(a + b*exp(S(2)*x))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(4)*x)/(a + b*exp(S(2)*x))**S(3), x), x, exp(S(4)*x)/(S(4)*a*(a + b*exp(S(2)*x))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(4)*x)/(a + b*exp(S(2)*x))**S(4), x), x, a/(S(6)*b**S(2)*(a + b*exp(S(2)*x))**S(3)) - S(1)/(S(4)*b**S(2)*(a + b*exp(S(2)*x))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(4)*x)/(a + b*exp(S(2)*x))**(S(2)/3), x), x, -S(3)*a*(a + b*exp(S(2)*x))**(S(1)/3)/(S(2)*b**S(2)) + S(3)*(a + b*exp(S(2)*x))**(S(4)/3)/(S(8)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(n*x))*exp(-n*x), x), x, -a*exp(-n*x)/n + b*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(n*x))**S(2)*exp(-n*x), x), x, -a**S(2)*exp(-n*x)/n + S(2)*a*b*x + b**S(2)*exp(n*x)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(n*x))**S(3)*exp(-n*x), x), x, -a**S(3)*exp(-n*x)/n + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*exp(n*x)/n + b**S(3)*exp(S(2)*n*x)/(S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(-n*x)/(a + b*exp(n*x)), x), x, -exp(-n*x)/(a*n) - b*x/a**S(2) + b*log(a + b*exp(n*x))/(a**S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(-n*x)/(a + b*exp(n*x))**S(2), x), x, -b/(a**S(2)*n*(a + b*exp(n*x))) - exp(-n*x)/(a**S(2)*n) - S(2)*b*x/a**S(3) + S(2)*b*log(a + b*exp(n*x))/(a**S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(-n*x)/(a + b*exp(n*x))**S(3), x), x, -b/(S(2)*a**S(2)*n*(a + b*exp(n*x))**S(2)) - S(2)*b/(a**S(3)*n*(a + b*exp(n*x))) - exp(-n*x)/(a**S(3)*n) - S(3)*b*x/a**S(4) + S(3)*b*log(a + b*exp(n*x))/(a**S(4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x)/(c + d*f**(S(2)*b*x + e)), x), x, f**(a - e/S(2))*atan(sqrt(d)*f**(b*x + e/S(2))/sqrt(c))/(b*sqrt(c)*sqrt(d)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + S(2)*b*x)/(c + d*f**(S(2)*b*x + e)), x), x, f**(a - e)*log(c + d*f**(S(2)*b*x + e))/(S(2)*b*d*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + S(3)*b*x)/(c + d*f**(S(2)*b*x + e)), x), x, -sqrt(c)*f**(a - S(3)*e/S(2))*atan(sqrt(d)*f**(b*x + e/S(2))/sqrt(c))/(b*d**(S(3)/2)*log(f)) + f**(a + b*x - e)/(b*d*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + S(4)*b*x)/(c + d*f**(S(2)*b*x + e)), x), x, -c*f**(a - S(2)*e)*log(c + d*f**(S(2)*b*x + e))/(S(2)*b*d**S(2)*log(f)) + f**(a + S(2)*b*x - e)/(S(2)*b*d*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + S(5)*b*x)/(c + d*f**(S(2)*b*x + e)), x), x, c**(S(3)/2)*f**(a - S(5)*e/S(2))*atan(sqrt(d)*f**(b*x + e/S(2))/sqrt(c))/(b*d**(S(5)/2)*log(f)) - c*f**(a + b*x - S(2)*e)/(b*d**S(2)*log(f)) + f**(a + S(3)*b*x - e)/(S(3)*b*d*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) + S(1)), x), x, atan(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(-exp(S(2)*x) + S(1)), x), x, atanh(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(x)/(-exp(S(2)*x) + S(1)), x), x, x*atanh(exp(x)) + polylog(S(2), -exp(x))/S(2) - polylog(S(2), exp(x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(x)/(-exp(S(2)*x) + S(1)), x), x, x**S(2)*atanh(exp(x)) + x*polylog(S(2), -exp(x)) - x*polylog(S(2), exp(x)) - polylog(S(3), -exp(x)) + polylog(S(3), exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(x)/(-exp(S(2)*x) + S(1)), x), x, x**S(3)*atanh(exp(x)) + S(3)*x**S(2)*polylog(S(2), -exp(x))/S(2) - S(3)*x**S(2)*polylog(S(2), exp(x))/S(2) - S(3)*x*polylog(S(3), -exp(x)) + S(3)*x*polylog(S(3), exp(x)) + S(3)*polylog(S(4), -exp(x)) - S(3)*polylog(S(4), exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x/(a + b*f**(S(2)*x)), x), x, atan(sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x/(a + b*f**(S(2)*x)), x), x, x*atan(sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)) - I*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)) + I*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x**S(2)/(a + b*f**(S(2)*x)), x), x, x**S(2)*atan(sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)) - I*x*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(2)) + I*x*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(2)) + I*polylog(S(3), -I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(3)) - I*polylog(S(3), I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x**S(3)/(a + b*f**(S(2)*x)), x), x, x**S(3)*atan(sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)) - S(3)*I*x**S(2)*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)) + S(3)*I*x**S(2)*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)) + S(3)*I*x*polylog(S(3), -I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(3)) - S(3)*I*x*polylog(S(3), I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(3)) - S(3)*I*polylog(S(4), -I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(4)) + S(3)*I*polylog(S(4), I*sqrt(b)*f**x/sqrt(a))/(sqrt(a)*sqrt(b)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x/(a + b*f**(S(2)*x))**S(2), x), x, f**x/(S(2)*a*(a + b*f**(S(2)*x))*log(f)) + atan(sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x/(a + b*f**(S(2)*x))**S(2), x), x, f**x*x/(S(2)*a*(a + b*f**(S(2)*x))*log(f)) + x*atan(sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)) - atan(sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)) - I*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(4)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)) + I*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(4)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x**S(2)/(a + b*f**(S(2)*x))**S(2), x), x, f**x*x**S(2)/(S(2)*a*(a + b*f**(S(2)*x))*log(f)) + x**S(2)*atan(sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)) - x*atan(sqrt(b)*f**x/sqrt(a))/(a**(S(3)/2)*sqrt(b)*log(f)**S(2)) - I*x*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)) + I*x*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)) + I*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)) - I*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)) + I*polylog(S(3), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)) - I*polylog(S(3), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x**S(3)/(a + b*f**(S(2)*x))**S(2), x), x, f**x*x**S(3)/(S(2)*a*(a + b*f**(S(2)*x))*log(f)) + x**S(3)*atan(sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)) - S(3)*x**S(2)*atan(sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)) - S(3)*I*x**S(2)*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(4)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)) + S(3)*I*x**S(2)*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(4)*a**(S(3)/2)*sqrt(b)*log(f)**S(2)) + S(3)*I*x*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)) - S(3)*I*x*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)) + S(3)*I*x*polylog(S(3), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)) - S(3)*I*x*polylog(S(3), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(3)) - S(3)*I*polylog(S(3), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(4)) + S(3)*I*polylog(S(3), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(4)) - S(3)*I*polylog(S(4), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(4)) + S(3)*I*polylog(S(4), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x/(a + b*f**(S(2)*x))**S(3), x), x, f**x*x/(S(4)*a*(a + b*f**(S(2)*x))**S(2)*log(f)) + S(3)*f**x*x/(S(8)*a**S(2)*(a + b*f**(S(2)*x))*log(f)) - f**x/(S(8)*a**S(2)*(a + b*f**(S(2)*x))*log(f)**S(2)) + S(3)*x*atan(sqrt(b)*f**x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*log(f)) - atan(sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(5)/2)*sqrt(b)*log(f)**S(2)) - S(3)*I*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(16)*a**(S(5)/2)*sqrt(b)*log(f)**S(2)) + S(3)*I*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(16)*a**(S(5)/2)*sqrt(b)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x*x**S(2)/(a + b*f**(S(2)*x))**S(3), x), x, f**x*x**S(2)/(S(4)*a*(a + b*f**(S(2)*x))**S(2)*log(f)) + S(3)*f**x*x**S(2)/(S(8)*a**S(2)*(a + b*f**(S(2)*x))*log(f)) - f**x*x/(S(4)*a**S(2)*(a + b*f**(S(2)*x))*log(f)**S(2)) + S(3)*x**S(2)*atan(sqrt(b)*f**x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*log(f)) - x*atan(sqrt(b)*f**x/sqrt(a))/(a**(S(5)/2)*sqrt(b)*log(f)**S(2)) - S(3)*I*x*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*log(f)**S(2)) + S(3)*I*x*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*log(f)**S(2)) + atan(sqrt(b)*f**x/sqrt(a))/(S(4)*a**(S(5)/2)*sqrt(b)*log(f)**S(3)) + I*polylog(S(2), -I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(5)/2)*sqrt(b)*log(f)**S(3)) - I*polylog(S(2), I*sqrt(b)*f**x/sqrt(a))/(S(2)*a**(S(5)/2)*sqrt(b)*log(f)**S(3)) + S(3)*I*polylog(S(3), -I*sqrt(b)*f**x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*log(f)**S(3)) - S(3)*I*polylog(S(3), I*sqrt(b)*f**x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*f**x + b*f**(-x)), x), x, x*atan(sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)) - I*polylog(S(2), -I*sqrt(a)*f**x/sqrt(b))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)) + I*polylog(S(2), I*sqrt(a)*f**x/sqrt(b))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*f**x + b*f**(-x)), x), x, x**S(2)*atan(sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)) - I*x*polylog(S(2), -I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(2)) + I*x*polylog(S(2), I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(2)) + I*polylog(S(3), -I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(3)) - I*polylog(S(3), I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*f**x + b*f**(-x)), x), x, x**S(3)*atan(sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)) - S(3)*I*x**S(2)*polylog(S(2), -I*sqrt(a)*f**x/sqrt(b))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)) + S(3)*I*x**S(2)*polylog(S(2), I*sqrt(a)*f**x/sqrt(b))/(S(2)*sqrt(a)*sqrt(b)*log(f)**S(2)) + S(3)*I*x*polylog(S(3), -I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(3)) - S(3)*I*x*polylog(S(3), I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(3)) - S(3)*I*polylog(S(4), -I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(4)) + S(3)*I*polylog(S(4), I*sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**x/(a + b*f**(S(2)*x))**S(3), x), x, f**x/(S(4)*a*(a + b*f**(S(2)*x))**S(2)*log(f)) + S(3)*f**x/(S(8)*a**S(2)*(a + b*f**(S(2)*x))*log(f)) + S(3)*atan(sqrt(b)*f**x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*f**x + b*f**(-x)), x), x, atan(sqrt(a)*f**x/sqrt(b))/(sqrt(a)*sqrt(b)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*f**x + b*f**(-x))**(S(-2)), x), x, -S(1)/(S(2)*a*(a*f**(S(2)*x) + b)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*f**x + b*f**(-x))**S(2), x), x, -x/(S(2)*a*(a*f**(S(2)*x) + b)*log(f)) + x/(S(2)*a*b*log(f)) - log(a*f**(S(2)*x) + b)/(S(4)*a*b*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*f**x + b*f**(-x))**S(2), x), x, -x**S(2)/(S(2)*a*(a*f**(S(2)*x) + b)*log(f)) - x*log(S(1) + b*f**(-S(2)*x)/a)/(S(2)*a*b*log(f)**S(2)) + polylog(S(2), -b*f**(-S(2)*x)/a)/(S(4)*a*b*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*f**x + b*f**(-x))**S(2), x), x, -x**S(3)/(S(2)*a*(a*f**(S(2)*x) + b)*log(f)) - S(3)*x**S(2)*log(S(1) + b*f**(-S(2)*x)/a)/(S(4)*a*b*log(f)**S(2)) + S(3)*x*polylog(S(2), -b*f**(-S(2)*x)/a)/(S(4)*a*b*log(f)**S(3)) + S(3)*polylog(S(3), -b*f**(-S(2)*x)/a)/(S(8)*a*b*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*f**x + b*f**(-x))**(S(-3)), x), x, -f**x/(S(4)*a*(a*f**(S(2)*x) + b)**S(2)*log(f)) + f**x/(S(8)*a*b*(a*f**(S(2)*x) + b)*log(f)) + atan(sqrt(a)*f**x/sqrt(b))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*f**x + b*f**(-x))**S(3), x), x, -f**x*x/(S(4)*a*(a*f**(S(2)*x) + b)**S(2)*log(f)) + f**x*x/(S(8)*a*b*(a*f**(S(2)*x) + b)*log(f)) + f**x/(S(8)*a*b*(a*f**(S(2)*x) + b)*log(f)**S(2)) + x*atan(sqrt(a)*f**x/sqrt(b))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*log(f)) - I*polylog(S(2), -I*sqrt(a)*f**x/sqrt(b))/(S(16)*a**(S(3)/2)*b**(S(3)/2)*log(f)**S(2)) + I*polylog(S(2), I*sqrt(a)*f**x/sqrt(b))/(S(16)*a**(S(3)/2)*b**(S(3)/2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*f**x + b*f**(-x))**S(3), x), x, -f**x*x**S(2)/(S(4)*a*(a*f**(S(2)*x) + b)**S(2)*log(f)) + f**x*x**S(2)/(S(8)*a*b*(a*f**(S(2)*x) + b)*log(f)) + f**x*x/(S(4)*a*b*(a*f**(S(2)*x) + b)*log(f)**S(2)) + x**S(2)*atan(sqrt(a)*f**x/sqrt(b))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*log(f)) - I*x*polylog(S(2), -I*sqrt(a)*f**x/sqrt(b))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*log(f)**S(2)) + I*x*polylog(S(2), I*sqrt(a)*f**x/sqrt(b))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*log(f)**S(2)) - atan(sqrt(a)*f**x/sqrt(b))/(S(4)*a**(S(3)/2)*b**(S(3)/2)*log(f)**S(3)) + I*polylog(S(3), -I*sqrt(a)*f**x/sqrt(b))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*log(f)**S(3)) - I*polylog(S(3), I*sqrt(a)*f**x/sqrt(b))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(a + b*x + c*x**S(2))*g**(d + e*x + f*x**S(2)), x), x, sqrt(pi)*f**a*g**d*exp(-(b*log(f) + e*log(g))**S(2)/(S(4)*(c*log(f) + f*log(g))))*erfi((b*log(f)/S(2) + e*log(g)/S(2) + x*(c*log(f) + f*log(g)))/sqrt(c*log(f) + f*log(g)))/(S(2)*sqrt(c*log(f) + f*log(g))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(e*(c + d*x))*(G**(h*(f + g*x))*b + a)**n, x), x, F**(e*(c + d*x))*(G**(h*(f + g*x))*b + a)**(n + S(1))*hyper((S(1), d*e*log(F)/(g*h*log(G)) + n + S(1)), (d*e*log(F)/(g*h*log(G)) + S(1),), -G**(h*(f + g*x))*b/a)/(a*d*e*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(e*(c + d*x))*H**(t*(r + s*x))/(F**(e*(c + d*x))*b + a), x), x, H**(t*(r + s*x))*hyper((S(1), -s*t*log(H)/(d*e*log(F))), (S(1) - s*t*log(H)/(d*e*log(F)),), -F**(-e*(c + d*x))*a/b)/(b*s*t*log(H)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(e*(d*x + f))*H**(t*(r + s*x))/(F**(e*(c + d*x))*b + a), x), x, F**(-e*(c - f))*H**(t*(r + s*x))*hyper((S(1), -s*t*log(H)/(d*e*log(F))), (S(1) - s*t*log(H)/(d*e*log(F)),), -F**(-e*(c + d*x))*a/b)/(b*s*t*log(H)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*exp(h + i*x))*(f + g*x)**S(3)/(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x)), x), x, S(6)*g**S(3)*(e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(4), -(b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(4)*(b + sqrt(-S(4)*a*c + b**S(2)))) + S(6)*g**S(3)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(4), -(b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(4)*(b - sqrt(-S(4)*a*c + b**S(2)))) + S(6)*g**S(2)*(e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)*polylog(S(3), -(b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(3)*(b + sqrt(-S(4)*a*c + b**S(2)))) + S(6)*g**S(2)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)*polylog(S(3), -(b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(3)*(b - sqrt(-S(4)*a*c + b**S(2)))) + S(3)*g*(e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)**S(2)*polylog(S(2), -(b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))) + S(3)*g*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)**S(2)*polylog(S(2), -(b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))) - (e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)**S(3)*log(S(1) + (b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i*(b + sqrt(-S(4)*a*c + b**S(2)))) - (e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)**S(3)*log(S(1) + (b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i*(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*exp(h + i*x))*(f + g*x)**S(2)/(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x)), x), x, S(2)*g**S(2)*(e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(3), -(b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(3)*(b + sqrt(-S(4)*a*c + b**S(2)))) + S(2)*g**S(2)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(3), -(b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(3)*(b - sqrt(-S(4)*a*c + b**S(2)))) + S(2)*g*(e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)*polylog(S(2), -(b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))) + S(2)*g*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)*polylog(S(2), -(b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))) - (e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)**S(2)*log(S(1) + (b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i*(b + sqrt(-S(4)*a*c + b**S(2)))) - (e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)**S(2)*log(S(1) + (b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i*(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*exp(h + i*x))*(f + g*x)/(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x)), x), x, g*(e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -(b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))) + g*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -(b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))) - (e + (b*e - S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(f + g*x)*log(S(1) + (b + sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i*(b + sqrt(-S(4)*a*c + b**S(2)))) + (e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*(-f - g*x)*log(S(1) + (b - sqrt(-S(4)*a*c + b**S(2)))*exp(-h - i*x)/(S(2)*c))/(i*(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*exp(h + i*x))/(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x)), x), x, d*x/a - d*log(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x))/(S(2)*a*i) + (-S(2)*a*e + b*d)*atanh((b + S(2)*c*exp(h + i*x))/sqrt(-S(4)*a*c + b**S(2)))/(a*i*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d + e*exp(h + i*x))/((f + g*x)*(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x))), x), x, d*Integral(S(1)/((f + g*x)*(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x))), x) + e*Integral(exp(h + i*x)/((f + g*x)*(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x))), x), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d + e*exp(h + i*x))/((f + g*x)**S(2)*(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x))), x), x, d*Integral(S(1)/((f + g*x)**S(2)*(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x))), x) + e*Integral(exp(h + i*x)/((f + g*x)**S(2)*(a + b*exp(h + i*x) + c*exp(S(2)*h + S(2)*i*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(-a*e*exp(c + d*x) + b*e)/(-S(2)*a*e*exp(c + d*x) - b*e*exp(S(2)*c + S(2)*d*x) + b*e), x), x, -x*log(S(1) + (a - sqrt(a**S(2) + b**S(2)))*exp(-c - d*x)/b)/(S(2)*d) - x*log(S(1) + (a + sqrt(a**S(2) + b**S(2)))*exp(-c - d*x)/b)/(S(2)*d) + polylog(S(2), -(a - sqrt(a**S(2) + b**S(2)))*exp(-c - d*x)/b)/(S(2)*d**S(2)) + polylog(S(2), -(a + sqrt(a**S(2) + b**S(2)))*exp(-c - d*x)/b)/(S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(a + b*x + c*x**S(3))*(b + S(3)*c*x**S(2)), x), x, F**(a + b*x + c*x**S(3))/log(F), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(F**(S(1)/(a + b*x + c*x**S(2)))*(b + S(2)*c*x)/(a + b*x + c*x**S(2))**S(2), x), x, -F**(S(1)/(a + b*x + c*x**S(2)))/log(F), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**m*exp(a + b*x + c*x**S(2)), x), x, (-a - b*x - c*x**S(2))**(-m)*(a + b*x + c*x**S(2))**m*Gamma(m + S(1), -a - b*x - c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**S(3)*exp(a + b*x + c*x**S(2)), x), x, (a + b*x + c*x**S(2))**S(3)*exp(a + b*x + c*x**S(2)) - S(3)*(a + b*x + c*x**S(2))**S(2)*exp(a + b*x + c*x**S(2)) + S(6)*(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2)) - S(6)*exp(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**S(2)*exp(a + b*x + c*x**S(2)), x), x, (a + b*x + c*x**S(2))**S(2)*exp(a + b*x + c*x**S(2)) - S(2)*(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2)) + S(2)*exp(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2)), x), x, (a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2)) - exp(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2)), x), x, exp(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2)), x), x, Ei(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2))**S(2), x), x, Ei(a + b*x + c*x**S(2)) - exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2))**S(3), x), x, Ei(a + b*x + c*x**S(2))/S(2) - exp(a + b*x + c*x**S(2))/(S(2)*(a + b*x + c*x**S(2))) - exp(a + b*x + c*x**S(2))/(S(2)*(a + b*x + c*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**(S(7)/2)*exp(a + b*x + c*x**S(2)), x), x, (a + b*x + c*x**S(2))**(S(7)/2)*exp(a + b*x + c*x**S(2)) - S(7)*(a + b*x + c*x**S(2))**(S(5)/2)*exp(a + b*x + c*x**S(2))/S(2) + S(35)*(a + b*x + c*x**S(2))**(S(3)/2)*exp(a + b*x + c*x**S(2))/S(4) - S(105)*sqrt(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2))/S(8) + S(105)*sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2)))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**(S(5)/2)*exp(a + b*x + c*x**S(2)), x), x, (a + b*x + c*x**S(2))**(S(5)/2)*exp(a + b*x + c*x**S(2)) - S(5)*(a + b*x + c*x**S(2))**(S(3)/2)*exp(a + b*x + c*x**S(2))/S(2) + S(15)*sqrt(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2))/S(4) - S(15)*sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2)))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**(S(3)/2)*exp(a + b*x + c*x**S(2)), x), x, (a + b*x + c*x**S(2))**(S(3)/2)*exp(a + b*x + c*x**S(2)) - S(3)*sqrt(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2))/S(2) + S(3)*sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*sqrt(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2)), x), x, sqrt(a + b*x + c*x**S(2))*exp(a + b*x + c*x**S(2)) - sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/sqrt(a + b*x + c*x**S(2)), x), x, sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2))**(S(3)/2), x), x, S(2)*sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2))) - S(2)*exp(a + b*x + c*x**S(2))/sqrt(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2))**(S(5)/2), x), x, S(4)*sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2)))/S(3) - S(4)*exp(a + b*x + c*x**S(2))/(S(3)*sqrt(a + b*x + c*x**S(2))) - S(2)*exp(a + b*x + c*x**S(2))/(S(3)*(a + b*x + c*x**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2))**(S(7)/2), x), x, S(8)*sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2)))/S(15) - S(8)*exp(a + b*x + c*x**S(2))/(S(15)*sqrt(a + b*x + c*x**S(2))) - S(4)*exp(a + b*x + c*x**S(2))/(S(15)*(a + b*x + c*x**S(2))**(S(3)/2)) - S(2)*exp(a + b*x + c*x**S(2))/(S(5)*(a + b*x + c*x**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*exp(a + b*x + c*x**S(2))/(a + b*x + c*x**S(2))**(S(9)/2), x), x, S(16)*sqrt(pi)*erfi(sqrt(a + b*x + c*x**S(2)))/S(105) - S(16)*exp(a + b*x + c*x**S(2))/(S(105)*sqrt(a + b*x + c*x**S(2))) - S(8)*exp(a + b*x + c*x**S(2))/(S(105)*(a + b*x + c*x**S(2))**(S(3)/2)) - S(4)*exp(a + b*x + c*x**S(2))/(S(35)*(a + b*x + c*x**S(2))**(S(5)/2)) - S(2)*exp(a + b*x + c*x**S(2))/(S(7)*(a + b*x + c*x**S(2))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(-x)/sqrt(S(1) - exp(-S(2)*x)), x), x, -asin(exp(-x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) + S(4)), x), x, atan(exp(x)/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(-exp(S(2)*x) + S(1)), x), x, atanh(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(-S(4)*exp(S(2)*x) + S(3)), x), x, sqrt(S(3))*atanh(S(2)*sqrt(S(3))*exp(x)/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-S(4)*exp(S(2)*x) + S(3))*exp(x), x), x, sqrt(-S(4)*exp(S(2)*x) + S(3))*exp(x)/S(2) + S(3)*asin(S(2)*sqrt(S(3))*exp(x)/S(3))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(x**S(2)), x), x, x**S(2)*exp(x**S(2))/S(2) - exp(x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-exp(S(2)*x) + S(1))*exp(x), x), x, sqrt(-exp(S(2)*x) + S(1))*exp(x)/S(2) + asin(exp(x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/sqrt(exp(S(2)*x) + exp(x) + S(1)), x), x, asinh(sqrt(S(3))*(S(2)*exp(x) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) + S(-4)), x), x, -atanh(exp(x)/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(-x**S(2) + S(2)), x), x, -exp(-x**S(2) + S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-x**E + exp(x), x), x, -x**(E + S(1))/(E + S(1)) + exp(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(S(2)*x) + S(-1))/(exp(S(2)*x) + S(3)), x), x, -x/S(3) + S(2)*log(exp(S(2)*x) + S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/sqrt(-exp(S(2)*x) + S(1)), x), x, asin(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(exp(S(4)*x) + S(1)), x), x, atan(exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(S(2)*x) - S(3)*exp(x)), x), x, -x/S(9) + log(-exp(x) + S(3))/S(9) + exp(-x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) + S(-2))*exp(x)/(exp(x) + S(1)), x), x, exp(x) - S(3)*log(exp(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) + S(-1)), x), x, -atanh(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) + S(1)), x), x, atan(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) + exp(-x))/(exp(x) - exp(-x)), x), x, log(-exp(x) + exp(-x)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((exp(x) + exp(-x))/(exp(x) - exp(-x)), x), x, -x + log(-exp(S(2)*x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) - exp(-x))/(exp(x) + exp(-x)), x), x, log(exp(x) + exp(-x)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((exp(x) - exp(-x))/(exp(x) + exp(-x)), x), x, -x + log(exp(S(2)*x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(S(2)*x) + exp(-S(2)*x))/(exp(S(2)*x) - exp(-S(2)*x)), x), x, -x + log(-exp(S(4)*x) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/sqrt(exp(S(2)*x) + S(1)), x), x, asinh(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(sqrt(x + S(4)))/sqrt(x + S(4)), x), x, S(2)*exp(sqrt(x + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(exp(S(2)*x**S(2)) + S(-1)), x), x, atan(sqrt(exp(S(2)*x**S(2)) + S(-1)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(exp(S(2)*x) + S(9))*exp(x), x), x, sqrt(exp(S(2)*x) + S(9))*exp(x)/S(2) + S(9)*asinh(exp(x)/S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(exp(S(2)*x) + S(1))*exp(x), x), x, sqrt(exp(S(2)*x) + S(1))*exp(x)/S(2) + asinh(exp(x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(x**S(2))/(exp(S(2)*x**S(2)) + S(1)), x), x, atan(exp(x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(x**(S(3)/2)), x), x, S(2)*x**(S(3)/2)*exp(x**(S(3)/2))/S(3) - S(2)*exp(x**(S(3)/2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/sqrt(exp(S(2)*x) + S(-3)), x), x, atanh(exp(x)/sqrt(exp(S(2)*x) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(-exp(S(2)*x) + S(16)), x), x, atanh(exp(x)/S(4))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(5)*x)/(exp(S(10)*x) + S(1)), x), x, atan(exp(S(5)*x))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(4)*x)/sqrt(exp(S(8)*x) + S(16)), x), x, asinh(exp(S(4)*x)/S(4))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(S(4)*x**S(3))*cos(S(7)*x**S(3)), x), x, S(7)*exp(S(4)*x**S(3))*sin(S(7)*x**S(3))/S(195) + S(4)*exp(S(4)*x**S(3))*cos(S(7)*x**S(3))/S(195), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(x**S(2) + S(1)), x), x, exp(x**S(2) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(x**S(3) + S(1)), x), x, exp(x**S(3) + S(1))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(sqrt(x))/sqrt(x), x), x, S(2)*exp(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x**(S(1)/3))/x**(S(2)/3), x), x, S(3)*exp(x**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(5) + S(2)*x**S(3) + S(-8))*exp(S(3)*x), x), x, x**S(5)*exp(S(3)*x)/S(3) - S(5)*x**S(4)*exp(S(3)*x)/S(9) + S(38)*x**S(3)*exp(S(3)*x)/S(27) - S(38)*x**S(2)*exp(S(3)*x)/S(27) + S(76)*x*exp(S(3)*x)/S(81) - S(724)*exp(S(3)*x)/S(243), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + exp(x))**S(2), x), x, x**S(3)/S(3) + S(2)*x*exp(x) + exp(S(2)*x)/S(2) - S(2)*exp(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(S(3)*x) + exp(S(2)*x) + exp(x))*exp(-S(4)*x), x), x, -exp(-x) - exp(-S(2)*x)/S(2) - exp(-S(3)*x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) + S(2)*exp(x) + S(1)), x), x, -S(1)/(exp(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(-x)*cos(S(3)*x), x), x, S(3)*exp(-x)*sin(S(3)*x)/S(10) - exp(-x)*cos(S(3)*x)/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(exp(S(2)*x) + S(3)*exp(x) + S(2)), x), x, -log(exp(x) + S(1)) + S(2)*log(exp(x) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(exp(x) + S(1)), x), x, exp(x) - log(exp(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(3)*x)*cos(S(5)*x), x), x, S(5)*exp(S(3)*x)*sin(S(5)*x)/S(34) + S(3)*exp(S(3)*x)*cos(S(5)*x)/S(34), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)*sech(exp(x)), x), x, atan(sinh(exp(x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(-x)/(S(2)*exp(x) + S(1)), x), x, -S(2)*x + S(2)*log(S(2)*exp(x) + S(1)) - exp(-x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)*cos(S(3)*x + S(4)), x), x, S(3)*exp(x)*sin(S(3)*x + S(4))/S(10) + exp(x)*cos(S(3)*x + S(4))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(exp(x) + exp(-x)), x), x, x*exp(x) - x*exp(-x) - exp(x) - exp(-x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) + S(3)*exp(x) + S(2)), x), x, -S(2)*atanh(S(2)*exp(x) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(exp(x) + S(1))**(S(1)/3), x), x, S(3)*(exp(x) + S(1))**(S(5)/3)/S(5) - S(3)*(exp(x) + S(1))**(S(2)/3)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(2)*x)/(exp(x) + S(1))**(S(1)/4), x), x, S(4)*(exp(x) + S(1))**(S(7)/4)/S(7) - S(4)*(exp(x) + S(1))**(S(3)/4)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*exp(S(2)*x) - exp(x))/sqrt(S(3)*exp(S(2)*x) - S(6)*exp(x) + S(-1)), x), x, S(2)*sqrt(S(3)*exp(S(2)*x) - S(6)*exp(x) + S(-1))/S(3) - sqrt(S(3))*atanh(sqrt(S(3))*(-exp(x) + S(1))/sqrt(S(3)*exp(S(2)*x) - S(6)*exp(x) + S(-1)))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(5)*x)*exp(x), x), x, x**S(2)*exp(x) - S(7)*x*exp(x) + S(7)*exp(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - x)*exp(S(3)*x), x), x, x**S(2)*exp(S(3)*x)/S(3) - S(5)*x*exp(S(3)*x)/S(9) + S(5)*exp(S(3)*x)/S(27), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*x)*(log(x) + S(1))*exp(x**x), x), x, (x**x + S(-1))*exp(x**x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(S(7)*x) + exp(S(5)*x))/(exp(x) + exp(-x)), x), x, exp(S(6)*x)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(-2) - S(1)/x)*(-log(x) + S(1)), x), x, -x**(-S(1)/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(x))**S(2), x), x, a**S(2)*x + S(2)*a*b*exp(x) + b**S(2)*exp(S(2)*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(x))**S(3), x), x, a**S(3)*x + S(3)*a**S(2)*b*exp(x) + S(3)*a*b**S(2)*exp(S(2)*x)/S(2) + b**S(3)*exp(S(3)*x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*exp(x))**S(4), x), x, a**S(4)*x + S(4)*a**S(3)*b*exp(x) + S(3)*a**S(2)*b**S(2)*exp(S(2)*x) + S(4)*a*b**S(3)*exp(S(3)*x)/S(3) + b**S(4)*exp(S(4)*x)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*exp(c + d*x)), x), x, -S(2)*atanh(sqrt(a + b*exp(c + d*x))/sqrt(a))/(sqrt(a)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-a + b*exp(c + d*x)), x), x, S(2)*atan(sqrt(-a + b*exp(c + d*x))/sqrt(a))/(sqrt(a)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*exp(c + d*x)), x), x, -S(2)*sqrt(a)*atanh(sqrt(a + b*exp(c + d*x))/sqrt(a))/d + S(2)*sqrt(a + b*exp(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a + b*exp(c + d*x)), x), x, -S(2)*sqrt(a)*atan(sqrt(-a + b*exp(c + d*x))/sqrt(a))/d + S(2)*sqrt(-a + b*exp(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(6)*x)*sin(S(3)*x), x), x, S(2)*exp(S(6)*x)*sin(S(3)*x)/S(15) - exp(S(6)*x)*cos(S(3)*x)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(3)*x)/(exp(S(2)*x) + S(1)), x), x, exp(x) - atan(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(3)*x)/(exp(S(2)*x) + S(-1)), x), x, exp(x) - atanh(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(-x)/sqrt(exp(S(2)*x) + S(1)), x), x, -sqrt(exp(S(2)*x) + S(1))*exp(-x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(exp(S(2)*x) - S(8)*exp(x) + S(-1)), x), x, sqrt(S(17))*atanh(sqrt(S(17))*(-exp(x) + S(4))/S(17))/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(S(7)*x), x), x, x**S(3)*exp(S(7)*x)/S(7) - S(3)*x**S(2)*exp(S(7)*x)/S(49) + S(6)*x*exp(S(7)*x)/S(343) - S(6)*exp(S(7)*x)/S(2401), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(-S(2)*x + S(8)), x), x, -x**S(3)*exp(-S(2)*x + S(8))/S(2) - S(3)*x**S(2)*exp(-S(2)*x + S(8))/S(4) - S(3)*x*exp(-S(2)*x + S(8))/S(4) - S(3)*exp(-S(2)*x + S(8))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-exp(S(2)*x) + S(9))*exp(x), x), x, sqrt(-exp(S(2)*x) + S(9))*exp(x)/S(2) + S(9)*asin(exp(x)/S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-exp(S(2)*x) + S(9))*exp(S(6)*x), x), x, -(-exp(S(2)*x) + S(9))**(S(7)/2)/S(7) + S(18)*(-exp(S(2)*x) + S(9))**(S(5)/2)/S(5) - S(27)*(-exp(S(2)*x) + S(9))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(6)*x)/(-exp(x) + S(9))**(S(5)/2), x), x, S(2)*(-exp(x) + S(9))**(S(7)/2)/S(7) - S(18)*(-exp(x) + S(9))**(S(5)/2) + S(540)*(-exp(x) + S(9))**(S(3)/2) - S(14580)*sqrt(-exp(x) + S(9)) - S(65610)/sqrt(-exp(x) + S(9)) + S(39366)/(-exp(x) + S(9))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(-S(7)*exp(x**S(4)) + S(2))**S(5), x), x, S(8)*x**S(4) - S(16807)*exp(S(5)*x**S(4))/S(20) + S(12005)*exp(S(4)*x**S(4))/S(8) - S(3430)*exp(S(3)*x**S(4))/S(3) + S(490)*exp(S(2)*x**S(4)) - S(140)*exp(x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(-exp(S(2)*x**S(2)) + S(1))*exp(x**S(2)), x), x, sqrt(-exp(S(2)*x**S(2)) + S(1))*exp(x**S(2))/S(4) + asin(exp(x**S(2)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(-exp(S(4)*x**S(3)) + S(1))**S(2)*exp(x**S(3)), x), x, exp(S(9)*x**S(3))/S(27) - S(2)*exp(S(5)*x**S(3))/S(15) + exp(x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x + exp(x)), x), x, exp(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x + exp(x) + exp(exp(x))), x), x, exp(exp(exp(x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) + exp(-x))**S(2), x), x, S(2)*x + exp(S(2)*x)/S(2) - exp(-S(2)*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(x) + exp(-x)), x), x, atan(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) + exp(-x))**(S(-2)), x), x, -S(1)/(S(2)*(exp(S(2)*x) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(x) - exp(-x)), x), x, -atanh(exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) - exp(-x))**(S(-2)), x), x, S(1)/(S(2)*(-exp(S(2)*x) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) - exp(-x))**S(2)*exp(x), x), x, exp(S(3)*x)/S(3) - S(2)*exp(x) - exp(-x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) - exp(-x))**S(3)*exp(x), x), x, S(3)*x + exp(S(4)*x)/S(4) - S(3)*exp(S(2)*x)/S(2) + exp(-S(2)*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)**x + S(1))/(S(2)**x + S(1)), x), x, S(2)**x/log(S(2)) + x - S(2)*log(S(2)**x + S(1))/log(S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)**x + S(1))/(S(1) + S(2)**(-x)), x), x, -S(2)**x/log(S(2)) + S(2)**(S(2)*x + S(-1))/log(S(2)) + S(2)*log(S(2)**x + S(1))/log(S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-S(2)*a*exp((a + x)**S(2))/x + exp((a + x)**S(2))/x**S(2), x), x, sqrt(pi)*erfi(a + x) - exp((a + x)**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(8) + x**S(6) + x**S(4))*exp(-x**S(2)), x), x, -x**S(7)*exp(-x**S(2))/S(2) - S(9)*x**S(5)*exp(-x**S(2))/S(4) - S(49)*x**S(3)*exp(-x**S(2))/S(8) - S(147)*x*exp(-x**S(2))/S(16) + S(147)*sqrt(pi)*erf(x)/S(32), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(exp(S(3)*x) - exp(x)), x), x, -atanh(exp(x)) + exp(-x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + x + S(-5))*exp(x)/(x + S(-1))**S(2), x), x, exp(x) - S(3)*exp(x)/(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*exp(x**S(2))/(x**S(2) + S(1))**S(2), x), x, exp(x**S(2))/(S(2)*(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(S(3)*x)/sqrt(S(16)*exp(S(2)*x) + S(25)), x), x, sqrt(S(16)*exp(S(2)*x) + S(25))*exp(x)/S(32) - S(25)*asinh(S(4)*exp(x)/S(5))/S(128), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) + S(1))/sqrt(x + exp(x)), x), x, S(2)*sqrt(x + exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) + S(1))/(x + exp(x)), x), x, log(x + exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x**S(2))/x**S(2), x), x, sqrt(pi)*erfi(x) - exp(x**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(4) + S(1))*exp(x**S(2))/x**S(2), x), x, S(2)*x*exp(x**S(2)) - exp(x**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*sqrt(f**x), x), x, S(16)*b**S(2)*sqrt(f**x)/log(f)**S(3) - S(8)*b*(a + b*x)*sqrt(f**x)/log(f)**S(2) + S(2)*(a + b*x)**S(2)*sqrt(f**x)/log(f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(3)**(x**S(2) + S(1))*x, x), x, S(3)**(x**S(2) + S(1))/(S(2)*log(S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(sqrt(x))/sqrt(x), x), x, S(2)**(sqrt(x) + S(1))/log(S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**(S(1)/x)/x**S(2), x), x, -S(2)**(S(1)/x)/log(S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**x + S(2)**(-x), x), x, S(2)**x/log(S(2)) - S(2)**(-x)/log(S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))*exp(-S(4)*x), x), x, -x**S(2)*exp(-S(4)*x)/S(4) + S(5)*x*exp(-S(4)*x)/S(8) - S(11)*exp(-S(4)*x)/S(32), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(k**(x/S(2)) + x**(sqrt(k)), x), x, S(2)*k**(x/S(2))/log(k) + x**(sqrt(k) + S(1))/(sqrt(k) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(10)**(sqrt(x))/sqrt(x), x), x, S(2)**(sqrt(x) + S(1))*S(5)**(sqrt(x))/log(S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/sqrt(x + exp(x)) + S(1)/sqrt(x + exp(x)), x), x, S(2)*sqrt(x + exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(exp(x) + S(1))/sqrt(x + exp(x)) + S(2)*sqrt(x + exp(x)), x), x, S(2)*x*sqrt(x + exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(x)/sqrt(x + exp(x)) + x/sqrt(x + exp(x)) + S(2)*sqrt(x + exp(x)), x), x, S(2)*x*sqrt(x + exp(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(exp(x) + S(1))/sqrt(x + exp(x)), x), x, S(2)*x*sqrt(x + exp(x)) - S(2)*Integral(sqrt(x + exp(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(x)/sqrt(x + exp(x)) + x/sqrt(x + exp(x)), x), x, S(2)*x*sqrt(x + exp(x)) - S(2)*Integral(sqrt(x + exp(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp(x)/sqrt(x + exp(x)), x), x, S(2)*x*sqrt(x + exp(x)) + S(2)*sqrt(x + exp(x)) - Integral(S(1)/sqrt(x + exp(x)), x) - S(3)*Integral(sqrt(x + exp(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(S(3)*x**S(2) + S(5)*exp(x))/(S(5)*sqrt(x**S(3) + S(5)*exp(x))) + S(4)*x*sqrt(x**S(3) + S(5)*exp(x))/S(5), x), x, S(2)*x**S(2)*sqrt(x**S(3) + S(5)*exp(x))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*exp(x)/sqrt(x**S(3) + S(5)*exp(x)), x), x, S(2)*x**S(2)*sqrt(x**S(3) + S(5)*exp(x))/S(5) - S(4)*Integral(x*sqrt(x**S(3) + S(5)*exp(x)), x)/S(5) - S(3)*Integral(x**S(4)/sqrt(x**S(3) + S(5)*exp(x)), x)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-exp(x) + S(-1))/(x + exp(x))**(S(1)/3), x), x, -S(3)*(x + exp(x))**(S(2)/3)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x + exp(x))**(S(1)/3) - (x + exp(x))**(S(2)/3) - S(1)/(x + exp(x))**(S(1)/3), x), x, -S(3)*(x + exp(x))**(S(2)/3)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x + exp(x))**(S(1)/3), x), x, -S(3)*(x + exp(x))**(S(2)/3)/S(2) + Integral((x + exp(x))**(S(-1)/3), x) + Integral((x + exp(x))**(S(2)/3), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x + (S(2)*x + S(3))*exp(x))/(x + exp(x))**(S(1)/3), x), x, S(3)*x*(x + exp(x))**(S(2)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)*x*exp(x)/(x + exp(x))**(S(1)/3) + S(2)*x/(x + exp(x))**(S(1)/3) + S(3)*(x + exp(x))**(S(2)/3), x), x, S(3)*x*(x + exp(x))**(S(2)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((exp(x) - exp(-x))*(exp(x) + exp(-x))**S(2)*exp(x), x), x, -x + exp(S(4)*x)/S(4) + exp(S(2)*x)/S(2) + exp(-S(2)*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x + exp(x)), x), x, Integral(x/(x + exp(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(x + exp(x)), x), x, Integral(x**S(2)/sqrt(x + exp(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(x + exp(x)), x), x, Integral(exp(x)/(x + exp(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)/(x**S(2) + exp(x)), x), x, Integral(exp(x)/(x**S(2) + exp(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f(x)/(x + f(x)), x), x, x - Integral(x/(x + f(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f(x)/(x**S(2) + f(x)), x), x, x - Integral(x**S(2)/(x**S(2) + f(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f(x)/(x + f(x))**S(2), x), x, -Integral(x/(x + f(x))**S(2), x) + Integral(S(1)/(x + f(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f(x)/(x**S(2) + f(x))**S(2), x), x, -Integral(x**S(2)/(x**S(2) + f(x))**S(2), x) + Integral(S(1)/(x**S(2) + f(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((F**(c + d*x)*a)**m*(F**(e + f*x)*b)**n, x), x, (F**(c + d*x)*a)**m*(F**(e + f*x)*b)**n/((d*m + f*n)*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x**n + c + d*x**n), x), x, -x*(x**n*(-b - d))**(-S(1)/n)*Gamma(S(1)/n, x**n*(-b - d))*exp(a + c)/n, expand=True, _diff=True, _numerical=True) # (difference in simplify `exp(a*log(f) + c*log(g))` converts to `f**a*g**c` in mathematica) # failing assert rubi_test(rubi_integrate(f**(a + b*x**n)*g**(c + d*x**n), x), x, -f**a*g**c*x*(-x**n*(b*log(f) + d*log(g)))**(-S(1)/n)*Gamma(S(1)/n, -x**n*(b*log(f) + d*log(g)))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*exp(x**n), x), x, -x**(m + S(1))*(-x**n)**(-(m + S(1))/n)*Gamma((m + S(1))/n, -x**n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**(x**n)*x**m, x), x, -x**(m + S(1))*(-x**n*log(f))**(-(m + S(1))/n)*Gamma((m + S(1))/n, -x**n*log(f))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**m*exp((a + b*x)**n), x), x, -(-(a + b*x)**n)**(-(m + S(1))/n)*(a + b*x)**(m + S(1))*Gamma((m + S(1))/n, -(a + b*x)**n)/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(f**((a + b*x)**n)*(a + b*x)**m, x), x, -(-(a + b*x)**n*log(f))**(-(m + S(1))/n)*(a + b*x)**(m + S(1))*Gamma((m + S(1))/n, -(a + b*x)**n*log(f))/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*exp((a + b*x)**S(3)), x), x, a*(a + b*x)*Gamma(S(1)/3, -(a + b*x)**S(3))/(S(3)*b**S(2)*(-(a + b*x)**S(3))**(S(1)/3)) - (a + b*x)**S(2)*Gamma(S(2)/3, -(a + b*x)**S(3))/(S(3)*b**S(2)*(-(a + b*x)**S(3))**(S(2)/3)), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_hyperbolic_sine.py000066400000000000000000002333001412543434000301520ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.utility_function import ( sympy_op_factory, Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ ) from sympy import (Integral, Integral as Integrate, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf, exp, log) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec) from sympy import pi as Pi from sympy.integrals.rubi.rubi import rubi_integrate a, b, c, d, e, f, m, n, x, u , k, p, r, s, t, i, j= symbols('a b c d e f m n x u k p r s t i j') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F', ) def test_1(): assert rubi_test(rubi_integrate((c + d*x)**S(4)*sinh(a + b*x), x), x, (c + d*x)**S(4)*cosh(a + b*x)/b - S(4)*d*(c + d*x)**S(3)*sinh(a + b*x)/b**S(2) + S(12)*d**S(2)*(c + d*x)**S(2)*cosh(a + b*x)/b**S(3) - S(24)*d**S(3)*(c + d*x)*sinh(a + b*x)/b**S(4) + S(24)*d**S(4)*cosh(a + b*x)/b**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)*sinh(a + b*x), x), x, (c + d*x)**S(3)*cosh(a + b*x)/b - S(3)*d*(c + d*x)**S(2)*sinh(a + b*x)/b**S(2) + S(6)*d**S(2)*(c + d*x)*cosh(a + b*x)/b**S(3) - S(6)*d**S(3)*sinh(a + b*x)/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*sinh(a + b*x), x), x, (c + d*x)**S(2)*cosh(a + b*x)/b - S(2)*d*(c + d*x)*sinh(a + b*x)/b**S(2) + S(2)*d**S(2)*cosh(a + b*x)/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*sinh(a + b*x), x), x, (c + d*x)*cosh(a + b*x)/b - d*sinh(a + b*x)/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)/(c + d*x), x), x, CoshIntegral(b*c/d + b*x)*sinh(a - b*c/d)/d + SinhIntegral(b*c/d + b*x)*cosh(a - b*c/d)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)/(c + d*x)**S(2), x), x, b*CoshIntegral(b*c/d + b*x)*cosh(a - b*c/d)/d**S(2) + b*SinhIntegral(b*c/d + b*x)*sinh(a - b*c/d)/d**S(2) - sinh(a + b*x)/(d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)/(c + d*x)**S(3), x), x, b**S(2)*CoshIntegral(b*c/d + b*x)*sinh(a - b*c/d)/(S(2)*d**S(3)) + b**S(2)*SinhIntegral(b*c/d + b*x)*cosh(a - b*c/d)/(S(2)*d**S(3)) - b*cosh(a + b*x)/(S(2)*d**S(2)*(c + d*x)) - sinh(a + b*x)/(S(2)*d*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(4)*sinh(a + b*x)**S(2), x), x, -(c + d*x)**S(5)/(S(10)*d) + (c + d*x)**S(4)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - d*(c + d*x)**S(3)*sinh(a + b*x)**S(2)/b**S(2) - d*(c + d*x)**S(3)/(S(2)*b**S(2)) + S(3)*d**S(2)*(c + d*x)**S(2)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b**S(3)) - S(3)*d**S(4)*x/(S(4)*b**S(4)) - S(3)*d**S(3)*(c + d*x)*sinh(a + b*x)**S(2)/(S(2)*b**S(4)) + S(3)*d**S(4)*sinh(a + b*x)*cosh(a + b*x)/(S(4)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)*sinh(a + b*x)**S(2), x), x, -(c + d*x)**S(4)/(S(8)*d) + (c + d*x)**S(3)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - S(3)*c*d**S(2)*x/(S(4)*b**S(2)) - S(3)*d**S(3)*x**S(2)/(S(8)*b**S(2)) - S(3)*d*(c + d*x)**S(2)*sinh(a + b*x)**S(2)/(S(4)*b**S(2)) + S(3)*d**S(2)*(c + d*x)*sinh(a + b*x)*cosh(a + b*x)/(S(4)*b**S(3)) - S(3)*d**S(3)*sinh(a + b*x)**S(2)/(S(8)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*sinh(a + b*x)**S(2), x), x, -(c + d*x)**S(3)/(S(6)*d) + (c + d*x)**S(2)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - d**S(2)*x/(S(4)*b**S(2)) - d*(c + d*x)*sinh(a + b*x)**S(2)/(S(2)*b**S(2)) + d**S(2)*sinh(a + b*x)*cosh(a + b*x)/(S(4)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*sinh(a + b*x)**S(2), x), x, -c*x/S(2) - d*x**S(2)/S(4) + (c + d*x)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - d*sinh(a + b*x)**S(2)/(S(4)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x), x), x, CoshIntegral(S(2)*b*c/d + S(2)*b*x)*cosh(S(2)*a - S(2)*b*c/d)/(S(2)*d) + SinhIntegral(S(2)*b*c/d + S(2)*b*x)*sinh(S(2)*a - S(2)*b*c/d)/(S(2)*d) - log(c + d*x)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x)**S(2), x), x, b*CoshIntegral(S(2)*b*c/d + S(2)*b*x)*sinh(S(2)*a - S(2)*b*c/d)/d**S(2) + b*SinhIntegral(S(2)*b*c/d + S(2)*b*x)*cosh(S(2)*a - S(2)*b*c/d)/d**S(2) - sinh(a + b*x)**S(2)/(d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x)**S(3), x), x, b**S(2)*CoshIntegral(S(2)*b*c/d + S(2)*b*x)*cosh(S(2)*a - S(2)*b*c/d)/d**S(3) + b**S(2)*SinhIntegral(S(2)*b*c/d + S(2)*b*x)*sinh(S(2)*a - S(2)*b*c/d)/d**S(3) - b*sinh(a + b*x)*cosh(a + b*x)/(d**S(2)*(c + d*x)) - sinh(a + b*x)**S(2)/(S(2)*d*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x)**S(4), x), x, S(2)*b**S(3)*CoshIntegral(S(2)*b*c/d + S(2)*b*x)*sinh(S(2)*a - S(2)*b*c/d)/(S(3)*d**S(4)) + S(2)*b**S(3)*SinhIntegral(S(2)*b*c/d + S(2)*b*x)*cosh(S(2)*a - S(2)*b*c/d)/(S(3)*d**S(4)) - S(2)*b**S(2)*sinh(a + b*x)**S(2)/(S(3)*d**S(3)*(c + d*x)) - b**S(2)/(S(3)*d**S(3)*(c + d*x)) - b*sinh(a + b*x)*cosh(a + b*x)/(S(3)*d**S(2)*(c + d*x)**S(2)) - sinh(a + b*x)**S(2)/(S(3)*d*(c + d*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(4)*sinh(a + b*x)**S(3), x), x, (c + d*x)**S(4)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(3)*b) - S(2)*(c + d*x)**S(4)*cosh(a + b*x)/(S(3)*b) - S(4)*d*(c + d*x)**S(3)*sinh(a + b*x)**S(3)/(S(9)*b**S(2)) + S(8)*d*(c + d*x)**S(3)*sinh(a + b*x)/(S(3)*b**S(2)) + S(4)*d**S(2)*(c + d*x)**S(2)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(9)*b**S(3)) - S(80)*d**S(2)*(c + d*x)**S(2)*cosh(a + b*x)/(S(9)*b**S(3)) - S(8)*d**S(3)*(c + d*x)*sinh(a + b*x)**S(3)/(S(27)*b**S(4)) + S(160)*d**S(3)*(c + d*x)*sinh(a + b*x)/(S(9)*b**S(4)) + S(8)*d**S(4)*cosh(a + b*x)**S(3)/(S(81)*b**S(5)) - S(488)*d**S(4)*cosh(a + b*x)/(S(27)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)*sinh(a + b*x)**S(3), x), x, (c + d*x)**S(3)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(3)*b) - S(2)*(c + d*x)**S(3)*cosh(a + b*x)/(S(3)*b) - d*(c + d*x)**S(2)*sinh(a + b*x)**S(3)/(S(3)*b**S(2)) + S(2)*d*(c + d*x)**S(2)*sinh(a + b*x)/b**S(2) + S(2)*d**S(2)*(c + d*x)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(9)*b**S(3)) - S(40)*d**S(2)*(c + d*x)*cosh(a + b*x)/(S(9)*b**S(3)) - S(2)*d**S(3)*sinh(a + b*x)**S(3)/(S(27)*b**S(4)) + S(40)*d**S(3)*sinh(a + b*x)/(S(9)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*sinh(a + b*x)**S(3), x), x, (c + d*x)**S(2)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(3)*b) - S(2)*(c + d*x)**S(2)*cosh(a + b*x)/(S(3)*b) - S(2)*d*(c + d*x)*sinh(a + b*x)**S(3)/(S(9)*b**S(2)) + S(4)*d*(c + d*x)*sinh(a + b*x)/(S(3)*b**S(2)) + S(2)*d**S(2)*cosh(a + b*x)**S(3)/(S(27)*b**S(3)) - S(14)*d**S(2)*cosh(a + b*x)/(S(9)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*sinh(a + b*x)**S(3), x), x, (c + d*x)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(3)*b) - S(2)*(c + d*x)*cosh(a + b*x)/(S(3)*b) - d*sinh(a + b*x)**S(3)/(S(9)*b**S(2)) + S(2)*d*sinh(a + b*x)/(S(3)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(3)/(c + d*x), x), x, -S(3)*CoshIntegral(b*c/d + b*x)*sinh(a - b*c/d)/(S(4)*d) + CoshIntegral(S(3)*b*c/d + S(3)*b*x)*sinh(S(3)*a - S(3)*b*c/d)/(S(4)*d) - S(3)*SinhIntegral(b*c/d + b*x)*cosh(a - b*c/d)/(S(4)*d) + SinhIntegral(S(3)*b*c/d + S(3)*b*x)*cosh(S(3)*a - S(3)*b*c/d)/(S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(3)/(c + d*x)**S(2), x), x, -S(3)*b*CoshIntegral(b*c/d + b*x)*cosh(a - b*c/d)/(S(4)*d**S(2)) + S(3)*b*CoshIntegral(S(3)*b*c/d + S(3)*b*x)*cosh(S(3)*a - S(3)*b*c/d)/(S(4)*d**S(2)) - S(3)*b*SinhIntegral(b*c/d + b*x)*sinh(a - b*c/d)/(S(4)*d**S(2)) + S(3)*b*SinhIntegral(S(3)*b*c/d + S(3)*b*x)*sinh(S(3)*a - S(3)*b*c/d)/(S(4)*d**S(2)) - sinh(a + b*x)**S(3)/(d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(3)/(c + d*x)**S(3), x), x, -S(3)*b**S(2)*CoshIntegral(b*c/d + b*x)*sinh(a - b*c/d)/(S(8)*d**S(3)) + S(9)*b**S(2)*CoshIntegral(S(3)*b*c/d + S(3)*b*x)*sinh(S(3)*a - S(3)*b*c/d)/(S(8)*d**S(3)) - S(3)*b**S(2)*SinhIntegral(b*c/d + b*x)*cosh(a - b*c/d)/(S(8)*d**S(3)) + S(9)*b**S(2)*SinhIntegral(S(3)*b*c/d + S(3)*b*x)*cosh(S(3)*a - S(3)*b*c/d)/(S(8)*d**S(3)) - S(3)*b*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(2)*d**S(2)*(c + d*x)) - sinh(a + b*x)**S(3)/(S(2)*d*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)/sinh(a + b*x), x), x, -S(2)*(c + d*x)**S(3)*atanh(exp(a + b*x))/b - S(3)*d*(c + d*x)**S(2)*PolyLog(S(2), -exp(a + b*x))/b**S(2) + S(3)*d*(c + d*x)**S(2)*PolyLog(S(2), exp(a + b*x))/b**S(2) + S(6)*d**S(2)*(c + d*x)*PolyLog(S(3), -exp(a + b*x))/b**S(3) - S(6)*d**S(2)*(c + d*x)*PolyLog(S(3), exp(a + b*x))/b**S(3) - S(6)*d**S(3)*PolyLog(S(4), -exp(a + b*x))/b**S(4) + S(6)*d**S(3)*PolyLog(S(4), exp(a + b*x))/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/sinh(a + b*x), x), x, -S(2)*(c + d*x)**S(2)*atanh(exp(a + b*x))/b - S(2)*d*(c + d*x)*PolyLog(S(2), -exp(a + b*x))/b**S(2) + S(2)*d*(c + d*x)*PolyLog(S(2), exp(a + b*x))/b**S(2) + S(2)*d**S(2)*PolyLog(S(3), -exp(a + b*x))/b**S(3) - S(2)*d**S(2)*PolyLog(S(3), exp(a + b*x))/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/sinh(a + b*x), x), x, -S(2)*(c + d*x)*atanh(exp(a + b*x))/b - d*PolyLog(S(2), -exp(a + b*x))/b**S(2) + d*PolyLog(S(2), exp(a + b*x))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)*sinh(a + b*x)), x), x, Integrate(S(1)/((c + d*x)*sinh(a + b*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)**S(2)*sinh(a + b*x)), x), x, Integrate(S(1)/((c + d*x)**S(2)*sinh(a + b*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)/sinh(a + b*x)**S(2), x), x, -(c + d*x)**S(3)/b - (c + d*x)**S(3)/(b*tanh(a + b*x)) + S(3)*d*(c + d*x)**S(2)*log(-exp(S(2)*a + S(2)*b*x) + S(1))/b**S(2) + S(3)*d**S(2)*(c + d*x)*PolyLog(S(2), exp(S(2)*a + S(2)*b*x))/b**S(3) - S(3)*d**S(3)*PolyLog(S(3), exp(S(2)*a + S(2)*b*x))/(S(2)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/sinh(a + b*x)**S(2), x), x, -(c + d*x)**S(2)/b - (c + d*x)**S(2)/(b*tanh(a + b*x)) + S(2)*d*(c + d*x)*log(-exp(S(2)*a + S(2)*b*x) + S(1))/b**S(2) + d**S(2)*PolyLog(S(2), exp(S(2)*a + S(2)*b*x))/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/sinh(a + b*x)**S(2), x), x, -(c + d*x)/(b*tanh(a + b*x)) + d*log(sinh(a + b*x))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)*sinh(a + b*x)**S(2)), x), x, Integrate(S(1)/((c + d*x)*sinh(a + b*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)**S(2)*sinh(a + b*x)**S(2)), x), x, Integrate(S(1)/((c + d*x)**S(2)*sinh(a + b*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)/sinh(a + b*x)**S(3), x), x, (c + d*x)**S(3)*atanh(exp(a + b*x))/b - (c + d*x)**S(3)/(S(2)*b*sinh(a + b*x)*tanh(a + b*x)) + S(3)*d*(c + d*x)**S(2)*PolyLog(S(2), -exp(a + b*x))/(S(2)*b**S(2)) - S(3)*d*(c + d*x)**S(2)*PolyLog(S(2), exp(a + b*x))/(S(2)*b**S(2)) - S(3)*d*(c + d*x)**S(2)/(S(2)*b**S(2)*sinh(a + b*x)) - S(3)*d**S(2)*(c + d*x)*PolyLog(S(3), -exp(a + b*x))/b**S(3) + S(3)*d**S(2)*(c + d*x)*PolyLog(S(3), exp(a + b*x))/b**S(3) - S(6)*d**S(2)*(c + d*x)*atanh(exp(a + b*x))/b**S(3) - S(3)*d**S(3)*PolyLog(S(2), -exp(a + b*x))/b**S(4) + S(3)*d**S(3)*PolyLog(S(2), exp(a + b*x))/b**S(4) + S(3)*d**S(3)*PolyLog(S(4), -exp(a + b*x))/b**S(4) - S(3)*d**S(3)*PolyLog(S(4), exp(a + b*x))/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/sinh(a + b*x)**S(3), x), x, (c + d*x)**S(2)*atanh(exp(a + b*x))/b - (c + d*x)**S(2)/(S(2)*b*sinh(a + b*x)*tanh(a + b*x)) + d*(c + d*x)*PolyLog(S(2), -exp(a + b*x))/b**S(2) - d*(c + d*x)*PolyLog(S(2), exp(a + b*x))/b**S(2) - d*(c + d*x)/(b**S(2)*sinh(a + b*x)) - d**S(2)*PolyLog(S(3), -exp(a + b*x))/b**S(3) + d**S(2)*PolyLog(S(3), exp(a + b*x))/b**S(3) - d**S(2)*atanh(cosh(a + b*x))/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/sinh(a + b*x)**S(3), x), x, (c + d*x)*atanh(exp(a + b*x))/b - (c + d*x)/(S(2)*b*sinh(a + b*x)*tanh(a + b*x)) + d*PolyLog(S(2), -exp(a + b*x))/(S(2)*b**S(2)) - d*PolyLog(S(2), exp(a + b*x))/(S(2)*b**S(2)) - d/(S(2)*b**S(2)*sinh(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)*sinh(a + b*x)**S(3)), x), x, Integrate(S(1)/((c + d*x)*sinh(a + b*x)**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)**S(2)*sinh(a + b*x)**S(3)), x), x, Integrate(S(1)/((c + d*x)**S(2)*sinh(a + b*x)**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**(S(5)/2)*sinh(a + b*x), x), x, -S(15)*sqrt(Pi)*d**(S(5)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(16)*b**(S(7)/2)) - S(15)*sqrt(Pi)*d**(S(5)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(16)*b**(S(7)/2)) + (c + d*x)**(S(5)/2)*cosh(a + b*x)/b - S(5)*d*(c + d*x)**(S(3)/2)*sinh(a + b*x)/(S(2)*b**S(2)) + S(15)*d**S(2)*sqrt(c + d*x)*cosh(a + b*x)/(S(4)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**(S(3)/2)*sinh(a + b*x), x), x, -S(3)*sqrt(Pi)*d**(S(3)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(8)*b**(S(5)/2)) + S(3)*sqrt(Pi)*d**(S(3)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(8)*b**(S(5)/2)) + (c + d*x)**(S(3)/2)*cosh(a + b*x)/b - S(3)*d*sqrt(c + d*x)*sinh(a + b*x)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x)*sinh(a + b*x), x), x, -sqrt(Pi)*sqrt(d)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(4)*b**(S(3)/2)) - sqrt(Pi)*sqrt(d)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(4)*b**(S(3)/2)) + sqrt(c + d*x)*cosh(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)/sqrt(c + d*x), x), x, -sqrt(Pi)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(2)*sqrt(b)*sqrt(d)) + sqrt(Pi)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(2)*sqrt(b)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)/(c + d*x)**(S(3)/2), x), x, sqrt(Pi)*sqrt(b)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/d**(S(3)/2) + sqrt(Pi)*sqrt(b)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/d**(S(3)/2) - S(2)*sinh(a + b*x)/(d*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)/(c + d*x)**(S(5)/2), x), x, -S(2)*sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(3)*d**(S(5)/2)) + S(2)*sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(3)*d**(S(5)/2)) - S(4)*b*cosh(a + b*x)/(S(3)*d**S(2)*sqrt(c + d*x)) - S(2)*sinh(a + b*x)/(S(3)*d*(c + d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)/(c + d*x)**(S(7)/2), x), x, S(4)*sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(15)*d**(S(7)/2)) + S(4)*sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(15)*d**(S(7)/2)) - S(8)*b**S(2)*sinh(a + b*x)/(S(15)*d**S(3)*sqrt(c + d*x)) - S(4)*b*cosh(a + b*x)/(S(15)*d**S(2)*(c + d*x)**(S(3)/2)) - S(2)*sinh(a + b*x)/(S(5)*d*(c + d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**(S(5)/2)*sinh(a + b*x)**S(2), x), x, S(15)*sqrt(S(2))*sqrt(Pi)*d**(S(5)/2)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(512)*b**(S(7)/2)) - S(15)*sqrt(S(2))*sqrt(Pi)*d**(S(5)/2)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(512)*b**(S(7)/2)) - (c + d*x)**(S(7)/2)/(S(7)*d) + (c + d*x)**(S(5)/2)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - S(5)*d*(c + d*x)**(S(3)/2)*sinh(a + b*x)**S(2)/(S(8)*b**S(2)) - S(5)*d*(c + d*x)**(S(3)/2)/(S(16)*b**S(2)) + S(15)*d**S(2)*sqrt(c + d*x)*sinh(S(2)*a + S(2)*b*x)/(S(64)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**(S(3)/2)*sinh(a + b*x)**S(2), x), x, S(3)*sqrt(S(2))*sqrt(Pi)*d**(S(3)/2)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(128)*b**(S(5)/2)) + S(3)*sqrt(S(2))*sqrt(Pi)*d**(S(3)/2)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(128)*b**(S(5)/2)) - (c + d*x)**(S(5)/2)/(S(5)*d) + (c + d*x)**(S(3)/2)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - S(3)*d*sqrt(c + d*x)*sinh(a + b*x)**S(2)/(S(8)*b**S(2)) - S(3)*d*sqrt(c + d*x)/(S(16)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x)*sinh(a + b*x)**S(2), x), x, sqrt(S(2))*sqrt(Pi)*sqrt(d)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(32)*b**(S(3)/2)) - sqrt(S(2))*sqrt(Pi)*sqrt(d)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(32)*b**(S(3)/2)) - (c + d*x)**(S(3)/2)/(S(3)*d) + sqrt(c + d*x)*sinh(S(2)*a + S(2)*b*x)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/sqrt(c + d*x), x), x, sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(8)*sqrt(b)*sqrt(d)) + sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(8)*sqrt(b)*sqrt(d)) - sqrt(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x)**(S(3)/2), x), x, -sqrt(S(2))*sqrt(Pi)*sqrt(b)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(2)*d**(S(3)/2)) + sqrt(S(2))*sqrt(Pi)*sqrt(b)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(2)*d**(S(3)/2)) - S(2)*sinh(a + b*x)**S(2)/(d*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x)**(S(5)/2), x), x, S(2)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(3)*d**(S(5)/2)) + S(2)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(3)*d**(S(5)/2)) - S(8)*b*sinh(a + b*x)*cosh(a + b*x)/(S(3)*d**S(2)*sqrt(c + d*x)) - S(2)*sinh(a + b*x)**S(2)/(S(3)*d*(c + d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x)**(S(7)/2), x), x, -S(8)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(15)*d**(S(7)/2)) + S(8)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(15)*d**(S(7)/2)) - S(32)*b**S(2)*sinh(a + b*x)**S(2)/(S(15)*d**S(3)*sqrt(c + d*x)) - S(16)*b**S(2)/(S(15)*d**S(3)*sqrt(c + d*x)) - S(8)*b*sinh(a + b*x)*cosh(a + b*x)/(S(15)*d**S(2)*(c + d*x)**(S(3)/2)) - S(2)*sinh(a + b*x)**S(2)/(S(5)*d*(c + d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) # taking long time assert rubi_test(rubi_integrate(sinh(a + b*x)**S(2)/(c + d*x)**(S(9)/2), x), x, S(32)*sqrt(S(2))*sqrt(Pi)*b**(S(7)/2)*Erf(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(2)*a + S(2)*b*c/d)/(S(105)*d**(S(9)/2)) + S(32)*sqrt(S(2))*sqrt(Pi)*b**(S(7)/2)*Erfi(sqrt(S(2))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(2)*a - S(2)*b*c/d)/(S(105)*d**(S(9)/2)) - S(128)*b**S(3)*sinh(a + b*x)*cosh(a + b*x)/(S(105)*d**S(4)*sqrt(c + d*x)) - S(32)*b**S(2)*sinh(a + b*x)**S(2)/(S(105)*d**S(3)*(c + d*x)**(S(3)/2)) - S(16)*b**S(2)/(S(105)*d**S(3)*(c + d*x)**(S(3)/2)) - S(8)*b*sinh(a + b*x)*cosh(a + b*x)/(S(35)*d**S(2)*(c + d*x)**(S(5)/2)) - S(2)*sinh(a + b*x)**S(2)/(S(7)*d*(c + d*x)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**(S(5)/2)*sinh(a + b*x)**S(3), x), x, S(45)*sqrt(Pi)*d**(S(5)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(64)*b**(S(7)/2)) - S(5)*sqrt(S(3))*sqrt(Pi)*d**(S(5)/2)*Erf(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(3)*a + S(3)*b*c/d)/(S(1728)*b**(S(7)/2)) + S(45)*sqrt(Pi)*d**(S(5)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(64)*b**(S(7)/2)) - S(5)*sqrt(S(3))*sqrt(Pi)*d**(S(5)/2)*Erfi(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(3)*a - S(3)*b*c/d)/(S(1728)*b**(S(7)/2)) + (c + d*x)**(S(5)/2)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(3)*b) - S(2)*(c + d*x)**(S(5)/2)*cosh(a + b*x)/(S(3)*b) - S(5)*d*(c + d*x)**(S(3)/2)*sinh(a + b*x)**S(3)/(S(18)*b**S(2)) + S(5)*d*(c + d*x)**(S(3)/2)*sinh(a + b*x)/(S(3)*b**S(2)) - S(45)*d**S(2)*sqrt(c + d*x)*cosh(a + b*x)/(S(16)*b**S(3)) + S(5)*d**S(2)*sqrt(c + d*x)*cosh(S(3)*a + S(3)*b*x)/(S(144)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**(S(3)/2)*sinh(a + b*x)**S(3), x), x, S(9)*sqrt(Pi)*d**(S(3)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(32)*b**(S(5)/2)) - sqrt(S(3))*sqrt(Pi)*d**(S(3)/2)*Erf(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(3)*a + S(3)*b*c/d)/(S(288)*b**(S(5)/2)) - S(9)*sqrt(Pi)*d**(S(3)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(32)*b**(S(5)/2)) + sqrt(S(3))*sqrt(Pi)*d**(S(3)/2)*Erfi(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(3)*a - S(3)*b*c/d)/(S(288)*b**(S(5)/2)) + (c + d*x)**(S(3)/2)*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(3)*b) - S(2)*(c + d*x)**(S(3)/2)*cosh(a + b*x)/(S(3)*b) - d*sqrt(c + d*x)*sinh(a + b*x)**S(3)/(S(6)*b**S(2)) + d*sqrt(c + d*x)*sinh(a + b*x)/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x)*sinh(a + b*x)**S(3), x), x, S(3)*sqrt(Pi)*sqrt(d)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(16)*b**(S(3)/2)) - sqrt(S(3))*sqrt(Pi)*sqrt(d)*Erf(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(3)*a + S(3)*b*c/d)/(S(144)*b**(S(3)/2)) + S(3)*sqrt(Pi)*sqrt(d)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(16)*b**(S(3)/2)) - sqrt(S(3))*sqrt(Pi)*sqrt(d)*Erfi(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(3)*a - S(3)*b*c/d)/(S(144)*b**(S(3)/2)) - S(3)*sqrt(c + d*x)*cosh(a + b*x)/(S(4)*b) + sqrt(c + d*x)*cosh(S(3)*a + S(3)*b*x)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(3)/sqrt(c + d*x), x), x, S(3)*sqrt(Pi)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(8)*sqrt(b)*sqrt(d)) - sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(3)*a + S(3)*b*c/d)/(S(24)*sqrt(b)*sqrt(d)) - S(3)*sqrt(Pi)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(8)*sqrt(b)*sqrt(d)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(3)*a - S(3)*b*c/d)/(S(24)*sqrt(b)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(3)/(c + d*x)**(S(3)/2), x), x, -S(3)*sqrt(Pi)*sqrt(b)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(4)*d**(S(3)/2)) + sqrt(S(3))*sqrt(Pi)*sqrt(b)*Erf(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(3)*a + S(3)*b*c/d)/(S(4)*d**(S(3)/2)) - S(3)*sqrt(Pi)*sqrt(b)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(4)*d**(S(3)/2)) + sqrt(S(3))*sqrt(Pi)*sqrt(b)*Erfi(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(3)*a - S(3)*b*c/d)/(S(4)*d**(S(3)/2)) - S(2)*sinh(a + b*x)**S(3)/(d*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(a + b*x)**S(3)/(c + d*x)**(S(5)/2), x), x, sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(2)*d**(S(5)/2)) - sqrt(S(3))*sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(3)*a + S(3)*b*c/d)/(S(2)*d**(S(5)/2)) - sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(2)*d**(S(5)/2)) + sqrt(S(3))*sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(3)*a - S(3)*b*c/d)/(S(2)*d**(S(5)/2)) - S(4)*b*sinh(a + b*x)**S(2)*cosh(a + b*x)/(d**S(2)*sqrt(c + d*x)) - S(2)*sinh(a + b*x)**S(3)/(S(3)*d*(c + d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate(sinh(a + b*x)**S(3)/(c + d*x)**(S(7)/2), x), x, -sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-a + b*c/d)/(S(5)*d**(S(7)/2)) + S(3)*sqrt(S(3))*sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(-S(3)*a + S(3)*b*c/d)/(S(5)*d**(S(7)/2)) - sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(a - b*c/d)/(S(5)*d**(S(7)/2)) + S(3)*sqrt(S(3))*sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(S(3))*sqrt(b)*sqrt(c + d*x)/sqrt(d))*exp(S(3)*a - S(3)*b*c/d)/(S(5)*d**(S(7)/2)) - S(24)*b**S(2)*sinh(a + b*x)**S(3)/(S(5)*d**S(3)*sqrt(c + d*x)) - S(16)*b**S(2)*sinh(a + b*x)/(S(5)*d**S(3)*sqrt(c + d*x)) - S(4)*b*sinh(a + b*x)**S(2)*cosh(a + b*x)/(S(5)*d**S(2)*(c + d*x)**(S(3)/2)) - S(2)*sinh(a + b*x)**S(3)/(S(5)*d*(c + d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*sinh(f*x), x), x, -S(3)*sqrt(Pi)*d**(S(3)/2)*Erf(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(8)*f**(S(5)/2)) + S(3)*sqrt(Pi)*d**(S(3)/2)*Erfi(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(8)*f**(S(5)/2)) - S(3)*d*sqrt(d*x)*sinh(f*x)/(S(2)*f**S(2)) + (d*x)**(S(3)/2)*cosh(f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*sinh(f*x), x), x, -sqrt(Pi)*sqrt(d)*Erf(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(4)*f**(S(3)/2)) - sqrt(Pi)*sqrt(d)*Erfi(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(4)*f**(S(3)/2)) + sqrt(d*x)*cosh(f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(f*x)/sqrt(d*x), x), x, -sqrt(Pi)*Erf(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(2)*sqrt(d)*sqrt(f)) + sqrt(Pi)*Erfi(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(f*x)/(d*x)**(S(3)/2), x), x, sqrt(Pi)*sqrt(f)*Erf(sqrt(f)*sqrt(d*x)/sqrt(d))/d**(S(3)/2) + sqrt(Pi)*sqrt(f)*Erfi(sqrt(f)*sqrt(d*x)/sqrt(d))/d**(S(3)/2) - S(2)*sinh(f*x)/(d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(f*x)/(d*x)**(S(5)/2), x), x, -S(2)*sqrt(Pi)*f**(S(3)/2)*Erf(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(3)*d**(S(5)/2)) + S(2)*sqrt(Pi)*f**(S(3)/2)*Erfi(sqrt(f)*sqrt(d*x)/sqrt(d))/(S(3)*d**(S(5)/2)) - S(2)*sinh(f*x)/(S(3)*d*(d*x)**(S(3)/2)) - S(4)*f*cosh(f*x)/(S(3)*d**S(2)*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x)/sinh(a + b*x), x), x, Integrate(sqrt(c + d*x)/sinh(a + b*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c + d*x)*sinh(a + b*x)), x), x, Integrate(S(1)/(sqrt(c + d*x)*sinh(a + b*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sinh(x)**(S(3)/2)/x**S(3), x), x, S(3)*Integrate(S(1)/(x*sqrt(sinh(x))), x)/S(8) + S(9)*Integrate(sinh(x)**(S(3)/2)/x, x)/S(8) - S(3)*sqrt(sinh(x))*cosh(x)/(S(4)*x) - sinh(x)**(S(3)/2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-x*sqrt(sinh(x)) + x/sinh(x)**(S(3)/2), x), x, -S(2)*x*cosh(x)/sqrt(sinh(x)) + S(4)*sqrt(sinh(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(S(3)*sqrt(sinh(x))) + x/sinh(x)**(S(5)/2), x), x, -S(2)*x*cosh(x)/(S(3)*sinh(x)**(S(3)/2)) - S(4)/(S(3)*sqrt(sinh(x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(3)*x*sqrt(sinh(x))/S(5) + x/sinh(x)**(S(7)/2), x), x, S(6)*x*cosh(x)/(S(5)*sqrt(sinh(x))) - S(2)*x*cosh(x)/(S(5)*sinh(x)**(S(5)/2)) - S(12)*sqrt(sinh(x))/S(5) - S(4)/(S(15)*sinh(x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-x**S(2)*sqrt(sinh(x)) + x**S(2)/sinh(x)**(S(3)/2), x), x, -S(2)*x**S(2)*cosh(x)/sqrt(sinh(x)) + S(8)*x*sqrt(sinh(x)) - S(16)*I*EllipticE(Pi/S(4) - I*x/S(2), S(2))*sqrt(sinh(x))/sqrt(I*sinh(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sinh(e + f*x))**n*(c + d*x)**m, x), x, Integrate((b*sinh(e + f*x))**n*(c + d*x)**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m*sinh(a + b*x)**S(3), x), x, S(3)**(-m + S(-1))*(-b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(3)*b*(c + d*x)/d)*exp(S(3)*a - S(3)*b*c/d)/(S(8)*b) + S(3)**(-m + S(-1))*(b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(3)*b*(c + d*x)/d)*exp(-S(3)*a + S(3)*b*c/d)/(S(8)*b) - S(3)*(-b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -b*(c + d*x)/d)*exp(a - b*c/d)/(S(8)*b) - S(3)*(b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), b*(c + d*x)/d)*exp(-a + b*c/d)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m*sinh(a + b*x)**S(2), x), x, S(2)**(-m + S(-3))*(-b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(2)*b*(c + d*x)/d)*exp(S(2)*a - S(2)*b*c/d)/b - S(2)**(-m + S(-3))*(b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(2)*b*(c + d*x)/d)*exp(-S(2)*a + S(2)*b*c/d)/b - (c + d*x)**(m + S(1))/(S(2)*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m*sinh(a + b*x), x), x, (-b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -b*(c + d*x)/d)*exp(a - b*c/d)/(S(2)*b) + (b*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), b*(c + d*x)/d)*exp(-a + b*c/d)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m/sinh(a + b*x), x), x, Integrate((c + d*x)**m/sinh(a + b*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m/sinh(a + b*x)**S(2), x), x, Integrate((c + d*x)**m/sinh(a + b*x)**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(3))*sinh(a + b*x), x), x, -x**m*(-b*x)**(-m)*Gamma(m + S(4), -b*x)*exp(a)/(S(2)*b**S(4)) + x**m*(b*x)**(-m)*Gamma(m + S(4), b*x)*exp(-a)/(S(2)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(2))*sinh(a + b*x), x), x, x**m*(-b*x)**(-m)*Gamma(m + S(3), -b*x)*exp(a)/(S(2)*b**S(3)) + x**m*(b*x)**(-m)*Gamma(m + S(3), b*x)*exp(-a)/(S(2)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(1))*sinh(a + b*x), x), x, -x**m*(-b*x)**(-m)*Gamma(m + S(2), -b*x)*exp(a)/(S(2)*b**S(2)) + x**m*(b*x)**(-m)*Gamma(m + S(2), b*x)*exp(-a)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sinh(a + b*x), x), x, x**m*(-b*x)**(-m)*Gamma(m + S(1), -b*x)*exp(a)/(S(2)*b) + x**m*(b*x)**(-m)*Gamma(m + S(1), b*x)*exp(-a)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(-1))*sinh(a + b*x), x), x, -x**m*(-b*x)**(-m)*Gamma(m, -b*x)*exp(a)/S(2) + x**m*(b*x)**(-m)*Gamma(m, b*x)*exp(-a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(-2))*sinh(a + b*x), x), x, b*x**m*(-b*x)**(-m)*Gamma(m + S(-1), -b*x)*exp(a)/S(2) + b*x**m*(b*x)**(-m)*Gamma(m + S(-1), b*x)*exp(-a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(-3))*sinh(a + b*x), x), x, -b**S(2)*x**m*(-b*x)**(-m)*Gamma(m + S(-2), -b*x)*exp(a)/S(2) + b**S(2)*x**m*(b*x)**(-m)*Gamma(m + S(-2), b*x)*exp(-a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(3))*sinh(a + b*x)**S(2), x), x, -S(2)**(-m + S(-6))*x**m*(-b*x)**(-m)*Gamma(m + S(4), -S(2)*b*x)*exp(S(2)*a)/b**S(4) - S(2)**(-m + S(-6))*x**m*(b*x)**(-m)*Gamma(m + S(4), S(2)*b*x)*exp(-S(2)*a)/b**S(4) - x**(m + S(4))/(S(2)*m + S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(2))*sinh(a + b*x)**S(2), x), x, S(2)**(-m + S(-5))*x**m*(-b*x)**(-m)*Gamma(m + S(3), -S(2)*b*x)*exp(S(2)*a)/b**S(3) - S(2)**(-m + S(-5))*x**m*(b*x)**(-m)*Gamma(m + S(3), S(2)*b*x)*exp(-S(2)*a)/b**S(3) - x**(m + S(3))/(S(2)*m + S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(1))*sinh(a + b*x)**S(2), x), x, -S(2)**(-m + S(-4))*x**m*(-b*x)**(-m)*Gamma(m + S(2), -S(2)*b*x)*exp(S(2)*a)/b**S(2) - S(2)**(-m + S(-4))*x**m*(b*x)**(-m)*Gamma(m + S(2), S(2)*b*x)*exp(-S(2)*a)/b**S(2) - x**(m + S(2))/(S(2)*m + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sinh(a + b*x)**S(2), x), x, S(2)**(-m + S(-3))*x**m*(-b*x)**(-m)*Gamma(m + S(1), -S(2)*b*x)*exp(S(2)*a)/b - S(2)**(-m + S(-3))*x**m*(b*x)**(-m)*Gamma(m + S(1), S(2)*b*x)*exp(-S(2)*a)/b - x**(m + S(1))/(S(2)*m + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(-1))*sinh(a + b*x)**S(2), x), x, -S(2)**(-m + S(-2))*x**m*(-b*x)**(-m)*Gamma(m, -S(2)*b*x)*exp(S(2)*a) - S(2)**(-m + S(-2))*x**m*(b*x)**(-m)*Gamma(m, S(2)*b*x)*exp(-S(2)*a) - x**m/(S(2)*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(-2))*sinh(a + b*x)**S(2), x), x, S(2)**(-m + S(-1))*b*x**m*(-b*x)**(-m)*Gamma(m + S(-1), -S(2)*b*x)*exp(S(2)*a) - S(2)**(-m + S(-1))*b*x**m*(b*x)**(-m)*Gamma(m + S(-1), S(2)*b*x)*exp(-S(2)*a) + x**(m + S(-1))/(-S(2)*m + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(-3))*sinh(a + b*x)**S(2), x), x, x**(m + S(-2))/(-S(2)*m + S(4)) - S(2)**(-m)*b**S(2)*x**m*(-b*x)**(-m)*Gamma(m + S(-2), -S(2)*b*x)*exp(S(2)*a) - S(2)**(-m)*b**S(2)*x**m*(b*x)**(-m)*Gamma(m + S(-2), S(2)*b*x)*exp(-S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(S(1)/sinh(x))/S(3) + x/(S(1)/sinh(x))**(S(3)/2), x), x, S(2)*x*cosh(x)/(S(3)*sqrt(S(1)/sinh(x))) - S(4)/(S(9)*(S(1)/sinh(x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(3)*x/(S(5)*sqrt(S(1)/sinh(x))) + x/(S(1)/sinh(x))**(S(5)/2), x), x, S(2)*x*cosh(x)/(S(5)*(S(1)/sinh(x))**(S(3)/2)) - S(4)/(S(25)*(S(1)/sinh(x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-S(5)*x*sqrt(S(1)/sinh(x))/S(21) + x/(S(1)/sinh(x))**(S(7)/2), x), x, -S(10)*x*cosh(x)/(S(21)*sqrt(S(1)/sinh(x))) + S(2)*x*cosh(x)/(S(7)*(S(1)/sinh(x))**(S(5)/2)) + S(20)/(S(63)*(S(1)/sinh(x))**(S(3)/2)) - S(4)/(S(49)*(S(1)/sinh(x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(S(1)/sinh(x))/S(3) + x**S(2)/(S(1)/sinh(x))**(S(3)/2), x), x, S(2)*x**S(2)*cosh(x)/(S(3)*sqrt(S(1)/sinh(x))) - S(8)*x/(S(9)*(S(1)/sinh(x))**(S(3)/2)) - S(16)*I*sqrt(I*sinh(x))*sqrt(S(1)/sinh(x))*EllipticF(Pi/S(4) - I*x/S(2), S(2))/S(27) + S(16)*cosh(x)/(S(27)*sqrt(S(1)/sinh(x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)*(I*a*sinh(e + f*x) + a), x), x, -S(6)*I*a*d**S(3)*sinh(e + f*x)/f**S(4) + S(6)*I*a*d**S(2)*(c + d*x)*cosh(e + f*x)/f**S(3) - S(3)*I*a*d*(c + d*x)**S(2)*sinh(e + f*x)/f**S(2) + I*a*(c + d*x)**S(3)*cosh(e + f*x)/f + a*(c + d*x)**S(4)/(S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*(I*a*sinh(e + f*x) + a), x), x, S(2)*I*a*d**S(2)*cosh(e + f*x)/f**S(3) - S(2)*I*a*d*(c + d*x)*sinh(e + f*x)/f**S(2) + I*a*(c + d*x)**S(2)*cosh(e + f*x)/f + a*(c + d*x)**S(3)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*(I*a*sinh(e + f*x) + a), x), x, -I*a*d*sinh(e + f*x)/f**S(2) + I*a*(c + d*x)*cosh(e + f*x)/f + a*(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((I*a*sinh(e + f*x) + a)/(c + d*x), x), x, I*a*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d + I*a*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d + a*log(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((I*a*sinh(e + f*x) + a)/(c + d*x)**S(2), x), x, -I*a*sinh(e + f*x)/(d*(c + d*x)) - a/(d*(c + d*x)) + I*a*f*CoshIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d**S(2) + I*a*f*SinhIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((I*a*sinh(e + f*x) + a)/(c + d*x)**S(3), x), x, -I*a*sinh(e + f*x)/(S(2)*d*(c + d*x)**S(2)) - a/(S(2)*d*(c + d*x)**S(2)) - I*a*f*cosh(e + f*x)/(S(2)*d**S(2)*(c + d*x)) + I*a*f**S(2)*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/(S(2)*d**S(3)) + I*a*f**S(2)*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/(S(2)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)*(I*a*sinh(e + f*x) + a)**S(2), x), x, S(3)*a**S(2)*c*d**S(2)*x/(S(4)*f**S(2)) + S(3)*a**S(2)*d**S(3)*x**S(2)/(S(8)*f**S(2)) + S(3)*a**S(2)*d**S(3)*sinh(e + f*x)**S(2)/(S(8)*f**S(4)) - S(12)*I*a**S(2)*d**S(3)*sinh(e + f*x)/f**S(4) - S(3)*a**S(2)*d**S(2)*(c + d*x)*sinh(e + f*x)*cosh(e + f*x)/(S(4)*f**S(3)) + S(12)*I*a**S(2)*d**S(2)*(c + d*x)*cosh(e + f*x)/f**S(3) + S(3)*a**S(2)*d*(c + d*x)**S(2)*sinh(e + f*x)**S(2)/(S(4)*f**S(2)) - S(6)*I*a**S(2)*d*(c + d*x)**S(2)*sinh(e + f*x)/f**S(2) - a**S(2)*(c + d*x)**S(3)*sinh(e + f*x)*cosh(e + f*x)/(S(2)*f) + S(2)*I*a**S(2)*(c + d*x)**S(3)*cosh(e + f*x)/f + S(3)*a**S(2)*(c + d*x)**S(4)/(S(8)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*(I*a*sinh(e + f*x) + a)**S(2), x), x, a**S(2)*d**S(2)*x/(S(4)*f**S(2)) - a**S(2)*d**S(2)*sinh(e + f*x)*cosh(e + f*x)/(S(4)*f**S(3)) + S(4)*I*a**S(2)*d**S(2)*cosh(e + f*x)/f**S(3) + a**S(2)*d*(c + d*x)*sinh(e + f*x)**S(2)/(S(2)*f**S(2)) - S(4)*I*a**S(2)*d*(c + d*x)*sinh(e + f*x)/f**S(2) - a**S(2)*(c + d*x)**S(2)*sinh(e + f*x)*cosh(e + f*x)/(S(2)*f) + S(2)*I*a**S(2)*(c + d*x)**S(2)*cosh(e + f*x)/f + a**S(2)*(c + d*x)**S(3)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*(I*a*sinh(e + f*x) + a)**S(2), x), x, a**S(2)*c*x/S(2) + a**S(2)*d*x**S(2)/S(4) + a**S(2)*d*sinh(e + f*x)**S(2)/(S(4)*f**S(2)) - S(2)*I*a**S(2)*d*sinh(e + f*x)/f**S(2) - a**S(2)*(c + d*x)*sinh(e + f*x)*cosh(e + f*x)/(S(2)*f) + S(2)*I*a**S(2)*(c + d*x)*cosh(e + f*x)/f + a**S(2)*(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((I*a*sinh(e + f*x) + a)**S(2)/(c + d*x), x), x, S(2)*I*a**S(2)*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d - a**S(2)*CoshIntegral(S(2)*c*f/d + S(2)*f*x)*cosh(-S(2)*c*f/d + S(2)*e)/(S(2)*d) + S(2)*I*a**S(2)*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d - a**S(2)*SinhIntegral(S(2)*c*f/d + S(2)*f*x)*sinh(-S(2)*c*f/d + S(2)*e)/(S(2)*d) + S(3)*a**S(2)*log(c + d*x)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((I*a*sinh(e + f*x) + a)**S(2)/(c + d*x)**S(2), x), x, -S(4)*a**S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(4)/(d*(c + d*x)) + S(2)*I*a**S(2)*f*CoshIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d**S(2) - a**S(2)*f*CoshIntegral(S(2)*c*f/d + S(2)*f*x)*sinh(-S(2)*c*f/d + S(2)*e)/d**S(2) + S(2)*I*a**S(2)*f*SinhIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d**S(2) - a**S(2)*f*SinhIntegral(S(2)*c*f/d + S(2)*f*x)*cosh(-S(2)*c*f/d + S(2)*e)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((I*a*sinh(e + f*x) + a)**S(2)/(c + d*x)**S(3), x), x, -S(2)*a**S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(4)/(d*(c + d*x)**S(2)) - S(4)*a**S(2)*f*sinh(I*Pi/S(4) + e/S(2) + f*x/S(2))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(3)/(d**S(2)*(c + d*x)) + I*a**S(2)*f**S(2)*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d**S(3) - a**S(2)*f**S(2)*CoshIntegral(S(2)*c*f/d + S(2)*f*x)*cosh(-S(2)*c*f/d + S(2)*e)/d**S(3) + I*a**S(2)*f**S(2)*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d**S(3) - a**S(2)*f**S(2)*SinhIntegral(S(2)*c*f/d + S(2)*f*x)*sinh(-S(2)*c*f/d + S(2)*e)/d**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)/(I*a*sinh(e + f*x) + a), x), x, S(12)*d**S(3)*PolyLog(S(3), -exp(I*Pi/S(2) + e + f*x))/(a*f**S(4)) - S(12)*d**S(2)*(c + d*x)*PolyLog(S(2), -exp(I*Pi/S(2) + e + f*x))/(a*f**S(3)) - S(6)*d*(c + d*x)**S(2)*log(exp(I*Pi/S(2) + e + f*x) + S(1))/(a*f**S(2)) + (c + d*x)**S(3)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f) + (c + d*x)**S(3)/(a*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/(I*a*sinh(e + f*x) + a), x), x, -S(4)*d**S(2)*PolyLog(S(2), -exp(I*Pi/S(2) + e + f*x))/(a*f**S(3)) - S(4)*d*(c + d*x)*log(exp(I*Pi/S(2) + e + f*x) + S(1))/(a*f**S(2)) + (c + d*x)**S(2)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f) + (c + d*x)**S(2)/(a*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/(I*a*sinh(e + f*x) + a), x), x, -S(2)*d*log(cosh(I*Pi/S(4) + e/S(2) + f*x/S(2)))/(a*f**S(2)) + (c + d*x)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)*(I*a*sinh(e + f*x) + a)), x), x, Integrate(S(1)/((c + d*x)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)), x)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)**S(2)*(I*a*sinh(e + f*x) + a)), x), x, Integrate(S(1)/((c + d*x)**S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)), x)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)/(I*a*sinh(e + f*x) + a)**S(2), x), x, S(4)*d**S(3)*PolyLog(S(3), -exp(I*Pi/S(2) + e + f*x))/(a**S(2)*f**S(4)) + S(4)*d**S(3)*log(cosh(I*Pi/S(4) + e/S(2) + f*x/S(2)))/(a**S(2)*f**S(4)) - S(4)*d**S(2)*(c + d*x)*PolyLog(S(2), -exp(I*Pi/S(2) + e + f*x))/(a**S(2)*f**S(3)) - S(2)*d**S(2)*(c + d*x)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a**S(2)*f**S(3)) - S(2)*d*(c + d*x)**S(2)*log(exp(I*Pi/S(2) + e + f*x) + S(1))/(a**S(2)*f**S(2)) + d*(c + d*x)**S(2)/(S(2)*a**S(2)*f**S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)) + (c + d*x)**S(3)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(3)*a**S(2)*f) + (c + d*x)**S(3)/(S(3)*a**S(2)*f) + (c + d*x)**S(3)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(6)*a**S(2)*f*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/(I*a*sinh(e + f*x) + a)**S(2), x), x, -S(4)*d**S(2)*PolyLog(S(2), -exp(I*Pi/S(2) + e + f*x))/(S(3)*a**S(2)*f**S(3)) - S(2)*d**S(2)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(3)*a**S(2)*f**S(3)) - S(4)*d*(c + d*x)*log(exp(I*Pi/S(2) + e + f*x) + S(1))/(S(3)*a**S(2)*f**S(2)) + d*(c + d*x)/(S(3)*a**S(2)*f**S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)) + (c + d*x)**S(2)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(3)*a**S(2)*f) + (c + d*x)**S(2)/(S(3)*a**S(2)*f) + (c + d*x)**S(2)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(6)*a**S(2)*f*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/(I*a*sinh(e + f*x) + a)**S(2), x), x, -S(2)*d*log(cosh(I*Pi/S(4) + e/S(2) + f*x/S(2)))/(S(3)*a**S(2)*f**S(2)) + d/(S(6)*a**S(2)*f**S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)) + (c + d*x)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(3)*a**S(2)*f) + (c + d*x)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(6)*a**S(2)*f*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)*(I*a*sinh(e + f*x) + a)**S(2)), x), x, Integrate(S(1)/((c + d*x)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(4)), x)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)**S(2)*(I*a*sinh(e + f*x) + a)**S(2)), x), x, Integrate(S(1)/((c + d*x)**S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(4)), x)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(I*a*sinh(e + f*x) + a)/x, x), x, sqrt(I*a*sinh(e + f*x) + a)*CoshIntegral(f*x/S(2))*cosh(I*Pi/S(4) + e/S(2))/cosh(I*Pi/S(4) + e/S(2) + f*x/S(2)) + sqrt(I*a*sinh(e + f*x) + a)*SinhIntegral(f*x/S(2))*sinh(I*Pi/S(4) + e/S(2))/cosh(I*Pi/S(4) + e/S(2) + f*x/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(I*a*sinh(e + f*x) + a)/x**S(2), x), x, f*sqrt(I*a*sinh(e + f*x) + a)*CoshIntegral(f*x/S(2))*sinh(I*Pi/S(4) + e/S(2))/(S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))) + f*sqrt(I*a*sinh(e + f*x) + a)*SinhIntegral(f*x/S(2))*cosh(I*Pi/S(4) + e/S(2))/(S(2)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))) - sqrt(I*a*sinh(e + f*x) + a)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(I*a*sinh(e + f*x) + a)/x**S(3), x), x, f**S(2)*sqrt(I*a*sinh(e + f*x) + a)*CoshIntegral(f*x/S(2))*cosh(I*Pi/S(4) + e/S(2))/(S(8)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))) + f**S(2)*sqrt(I*a*sinh(e + f*x) + a)*SinhIntegral(f*x/S(2))*sinh(I*Pi/S(4) + e/S(2))/(S(8)*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))) - f*sqrt(I*a*sinh(e + f*x) + a)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(4)*x) - sqrt(I*a*sinh(e + f*x) + a)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(I*a*sinh(e + f*x) + a)), x), x, Integrate(S(1)/(x*sqrt(I*a*sinh(e + f*x) + a)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(I*a*sinh(e + f*x) + a)), x), x, Integrate(S(1)/(x**S(2)*sqrt(I*a*sinh(e + f*x) + a)), x), expand=True, _diff=True, _numerical=True) ''' long time # assert rubi_test(rubi_integrate(x**S(3)/(I*a*sinh(e + f*x) + a)**(S(3)/2), x), x, x**S(3)*ArcTan(exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f*sqrt(I*a*sinh(e + f*x) + a)) + x**S(3)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(2)*a*f*sqrt(I*a*sinh(e + f*x) + a)) - S(3)*I*x**S(2)*PolyLog(S(2), -I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) + S(3)*I*x**S(2)*PolyLog(S(2), I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) + S(3)*x**S(2)/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) - S(24)*x*ArcTan(exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(3)*sqrt(I*a*sinh(e + f*x) + a)) + S(12)*I*x*PolyLog(S(3), -I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(3)*sqrt(I*a*sinh(e + f*x) + a)) - S(12)*I*x*PolyLog(S(3), I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(3)*sqrt(I*a*sinh(e + f*x) + a)) + S(24)*I*PolyLog(S(2), -I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(4)*sqrt(I*a*sinh(e + f*x) + a)) - S(24)*I*PolyLog(S(2), I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(4)*sqrt(I*a*sinh(e + f*x) + a)) - S(24)*I*PolyLog(S(4), -I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(4)*sqrt(I*a*sinh(e + f*x) + a)) + S(24)*I*PolyLog(S(4), I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(4)*sqrt(I*a*sinh(e + f*x) + a)), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(x**S(2)/(I*a*sinh(e + f*x) + a)**(S(3)/2), x), x, x**S(2)*ArcTan(exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f*sqrt(I*a*sinh(e + f*x) + a)) + x**S(2)*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(2)*a*f*sqrt(I*a*sinh(e + f*x) + a)) - S(2)*I*x*PolyLog(S(2), -I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) + S(2)*I*x*PolyLog(S(2), I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) + S(2)*x/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) - S(4)*ArcTan(sinh(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(3)*sqrt(I*a*sinh(e + f*x) + a)) + S(4)*I*PolyLog(S(3), -I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(3)*sqrt(I*a*sinh(e + f*x) + a)) - S(4)*I*PolyLog(S(3), I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(3)*sqrt(I*a*sinh(e + f*x) + a)), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(x/(I*a*sinh(e + f*x) + a)**(S(3)/2), x), x, x*ArcTan(exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f*sqrt(I*a*sinh(e + f*x) + a)) + x*tanh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(S(2)*a*f*sqrt(I*a*sinh(e + f*x) + a)) - I*PolyLog(S(2), -I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) + I*PolyLog(S(2), I*exp(I*Pi/S(4) + e/S(2) + f*x/S(2)))*cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)) + S(1)/(a*f**S(2)*sqrt(I*a*sinh(e + f*x) + a)), expand=True, _diff=True, _numerical=True) ''' assert rubi_test(rubi_integrate(S(1)/(x*(I*a*sinh(e + f*x) + a)**(S(3)/2)), x), x, Integrate(S(1)/(x*(I*a*sinh(e + f*x) + a)**(S(3)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(I*a*sinh(e + f*x) + a)**(S(3)/2)), x), x, Integrate(S(1)/(x**S(2)*(I*a*sinh(e + f*x) + a)**(S(3)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(I*a*sinh(c + d*x) + a)**(S(5)/2)), x), x, Integrate(S(1)/(x*(I*a*sinh(c + d*x) + a)**(S(5)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((I*a*sinh(e + f*x) + a)**(S(1)/3)/x, x), x, Integrate((I*a*sinh(e + f*x) + a)**(S(1)/3)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m*(I*a*sinh(e + f*x) + a)**n, x), x, Integrate((c + d*x)**m*(I*a*sinh(e + f*x) + a)**n, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m*(I*a*sinh(e + f*x) + a)**S(3), x), x, -S(3)*S(2)**(-m + S(-3))*a**S(3)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(2)*f*(c + d*x)/d)*exp(-S(2)*c*f/d + S(2)*e)/f + S(3)*S(2)**(-m + S(-3))*a**S(3)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(2)*f*(c + d*x)/d)*exp(S(2)*c*f/d - S(2)*e)/f - S(3)**(-m + S(-1))*I*a**S(3)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(3)*f*(c + d*x)/d)*exp(-S(3)*c*f/d + S(3)*e)/(S(8)*f) - S(3)**(-m + S(-1))*I*a**S(3)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(3)*f*(c + d*x)/d)*exp(S(3)*c*f/d - S(3)*e)/(S(8)*f) + S(15)*I*a**S(3)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -f*(c + d*x)/d)*exp(-c*f/d + e)/(S(8)*f) + S(15)*I*a**S(3)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), f*(c + d*x)/d)*exp(c*f/d - e)/(S(8)*f) + S(5)*a**S(3)*(c + d*x)**(m + S(1))/(S(2)*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m*(I*a*sinh(e + f*x) + a)**S(2), x), x, -S(2)**(-m + S(-3))*a**S(2)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(2)*f*(c + d*x)/d)*exp(-S(2)*c*f/d + S(2)*e)/f + S(2)**(-m + S(-3))*a**S(2)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(2)*f*(c + d*x)/d)*exp(S(2)*c*f/d - S(2)*e)/f + I*a**S(2)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -f*(c + d*x)/d)*exp(-c*f/d + e)/f + I*a**S(2)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), f*(c + d*x)/d)*exp(c*f/d - e)/f + S(3)*a**S(2)*(c + d*x)**(m + S(1))/(S(2)*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m*(I*a*sinh(e + f*x) + a), x), x, I*a*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -f*(c + d*x)/d)*exp(-c*f/d + e)/(S(2)*f) + I*a*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), f*(c + d*x)/d)*exp(c*f/d - e)/(S(2)*f) + a*(c + d*x)**(m + S(1))/(d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m/(I*a*sinh(e + f*x) + a), x), x, Integrate((c + d*x)**m/cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(2), x)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m/(I*a*sinh(e + f*x) + a)**S(2), x), x, Integrate((c + d*x)**m/cosh(I*Pi/S(4) + e/S(2) + f*x/S(2))**S(4), x)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))*(c + d*x)**S(3), x), x, a*(c + d*x)**S(4)/(S(4)*d) - S(6)*b*d**S(3)*sinh(e + f*x)/f**S(4) + S(6)*b*d**S(2)*(c + d*x)*cosh(e + f*x)/f**S(3) - S(3)*b*d*(c + d*x)**S(2)*sinh(e + f*x)/f**S(2) + b*(c + d*x)**S(3)*cosh(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))*(c + d*x)**S(2), x), x, a*(c + d*x)**S(3)/(S(3)*d) + S(2)*b*d**S(2)*cosh(e + f*x)/f**S(3) - S(2)*b*d*(c + d*x)*sinh(e + f*x)/f**S(2) + b*(c + d*x)**S(2)*cosh(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))*(c + d*x), x), x, a*(c + d*x)**S(2)/(S(2)*d) - b*d*sinh(e + f*x)/f**S(2) + b*(c + d*x)*cosh(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))/(c + d*x), x), x, a*log(c + d*x)/d + b*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d + b*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))/(c + d*x)**S(2), x), x, -a/(d*(c + d*x)) - b*sinh(e + f*x)/(d*(c + d*x)) + b*f*CoshIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d**S(2) + b*f*SinhIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))/(c + d*x)**S(3), x), x, -a/(S(2)*d*(c + d*x)**S(2)) - b*sinh(e + f*x)/(S(2)*d*(c + d*x)**S(2)) - b*f*cosh(e + f*x)/(S(2)*d**S(2)*(c + d*x)) + b*f**S(2)*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/(S(2)*d**S(3)) + b*f**S(2)*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/(S(2)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(2)*(c + d*x)**S(3), x), x, a**S(2)*(c + d*x)**S(4)/(S(4)*d) - S(12)*a*b*d**S(3)*sinh(e + f*x)/f**S(4) + S(12)*a*b*d**S(2)*(c + d*x)*cosh(e + f*x)/f**S(3) - S(6)*a*b*d*(c + d*x)**S(2)*sinh(e + f*x)/f**S(2) + S(2)*a*b*(c + d*x)**S(3)*cosh(e + f*x)/f - S(3)*b**S(2)*c*d**S(2)*x/(S(4)*f**S(2)) - S(3)*b**S(2)*d**S(3)*x**S(2)/(S(8)*f**S(2)) - S(3)*b**S(2)*d**S(3)*sinh(e + f*x)**S(2)/(S(8)*f**S(4)) + S(3)*b**S(2)*d**S(2)*(c + d*x)*sinh(e + f*x)*cosh(e + f*x)/(S(4)*f**S(3)) - S(3)*b**S(2)*d*(c + d*x)**S(2)*sinh(e + f*x)**S(2)/(S(4)*f**S(2)) + b**S(2)*(c + d*x)**S(3)*sinh(e + f*x)*cosh(e + f*x)/(S(2)*f) - b**S(2)*(c + d*x)**S(4)/(S(8)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(2)*(c + d*x)**S(2), x), x, a**S(2)*(c + d*x)**S(3)/(S(3)*d) + S(4)*a*b*d**S(2)*cosh(e + f*x)/f**S(3) - S(4)*a*b*d*(c + d*x)*sinh(e + f*x)/f**S(2) + S(2)*a*b*(c + d*x)**S(2)*cosh(e + f*x)/f - b**S(2)*d**S(2)*x/(S(4)*f**S(2)) + b**S(2)*d**S(2)*sinh(e + f*x)*cosh(e + f*x)/(S(4)*f**S(3)) - b**S(2)*d*(c + d*x)*sinh(e + f*x)**S(2)/(S(2)*f**S(2)) + b**S(2)*(c + d*x)**S(2)*sinh(e + f*x)*cosh(e + f*x)/(S(2)*f) - b**S(2)*(c + d*x)**S(3)/(S(6)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(2)*(c + d*x), x), x, a**S(2)*(c + d*x)**S(2)/(S(2)*d) - S(2)*a*b*d*sinh(e + f*x)/f**S(2) + S(2)*a*b*(c + d*x)*cosh(e + f*x)/f - b**S(2)*c*x/S(2) - b**S(2)*d*x**S(2)/S(4) - b**S(2)*d*sinh(e + f*x)**S(2)/(S(4)*f**S(2)) + b**S(2)*(c + d*x)*sinh(e + f*x)*cosh(e + f*x)/(S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(2)/(c + d*x), x), x, a**S(2)*log(c + d*x)/d + S(2)*a*b*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d + S(2)*a*b*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d + b**S(2)*CoshIntegral(S(2)*c*f/d + S(2)*f*x)*cosh(-S(2)*c*f/d + S(2)*e)/(S(2)*d) + b**S(2)*SinhIntegral(S(2)*c*f/d + S(2)*f*x)*sinh(-S(2)*c*f/d + S(2)*e)/(S(2)*d) - b**S(2)*log(c + d*x)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(2)/(c + d*x)**S(2), x), x, -a**S(2)/(d*(c + d*x)) - S(2)*a*b*sinh(e + f*x)/(d*(c + d*x)) + S(2)*a*b*f*CoshIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d**S(2) + S(2)*a*b*f*SinhIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d**S(2) - b**S(2)*sinh(e + f*x)**S(2)/(d*(c + d*x)) + b**S(2)*f*CoshIntegral(S(2)*c*f/d + S(2)*f*x)*sinh(-S(2)*c*f/d + S(2)*e)/d**S(2) + b**S(2)*f*SinhIntegral(S(2)*c*f/d + S(2)*f*x)*cosh(-S(2)*c*f/d + S(2)*e)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(2)/(c + d*x)**S(3), x), x, -a**S(2)/(S(2)*d*(c + d*x)**S(2)) - a*b*sinh(e + f*x)/(d*(c + d*x)**S(2)) - a*b*f*cosh(e + f*x)/(d**S(2)*(c + d*x)) + a*b*f**S(2)*CoshIntegral(c*f/d + f*x)*sinh(-c*f/d + e)/d**S(3) + a*b*f**S(2)*SinhIntegral(c*f/d + f*x)*cosh(-c*f/d + e)/d**S(3) - b**S(2)*sinh(e + f*x)**S(2)/(S(2)*d*(c + d*x)**S(2)) - b**S(2)*f*sinh(e + f*x)*cosh(e + f*x)/(d**S(2)*(c + d*x)) + b**S(2)*f**S(2)*CoshIntegral(S(2)*c*f/d + S(2)*f*x)*cosh(-S(2)*c*f/d + S(2)*e)/d**S(3) + b**S(2)*f**S(2)*SinhIntegral(S(2)*c*f/d + S(2)*f*x)*sinh(-S(2)*c*f/d + S(2)*e)/d**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)/(a + b*sinh(e + f*x)), x), x, S(6)*d**S(3)*PolyLog(S(4), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(4)*sqrt(a**S(2) + b**S(2))) - S(6)*d**S(3)*PolyLog(S(4), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(4)*sqrt(a**S(2) + b**S(2))) - S(6)*d**S(2)*(c + d*x)*PolyLog(S(3), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(3)*sqrt(a**S(2) + b**S(2))) + S(6)*d**S(2)*(c + d*x)*PolyLog(S(3), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(3)*sqrt(a**S(2) + b**S(2))) + S(3)*d*(c + d*x)**S(2)*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(2)*sqrt(a**S(2) + b**S(2))) - S(3)*d*(c + d*x)**S(2)*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(2)*sqrt(a**S(2) + b**S(2))) + (c + d*x)**S(3)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f*sqrt(a**S(2) + b**S(2))) - (c + d*x)**S(3)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f*sqrt(a**S(2) + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/(a + b*sinh(e + f*x)), x), x, -S(2)*d**S(2)*PolyLog(S(3), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(3)*sqrt(a**S(2) + b**S(2))) + S(2)*d**S(2)*PolyLog(S(3), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(3)*sqrt(a**S(2) + b**S(2))) + S(2)*d*(c + d*x)*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(2)*sqrt(a**S(2) + b**S(2))) - S(2)*d*(c + d*x)*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(2)*sqrt(a**S(2) + b**S(2))) + (c + d*x)**S(2)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f*sqrt(a**S(2) + b**S(2))) - (c + d*x)**S(2)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f*sqrt(a**S(2) + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/(a + b*sinh(e + f*x)), x), x, d*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(2)*sqrt(a**S(2) + b**S(2))) - d*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(2)*sqrt(a**S(2) + b**S(2))) + (c + d*x)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f*sqrt(a**S(2) + b**S(2))) - (c + d*x)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f*sqrt(a**S(2) + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*sinh(e + f*x))*(c + d*x)), x), x, Integrate(S(1)/((a + b*sinh(e + f*x))*(c + d*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*sinh(e + f*x))*(c + d*x)**S(2)), x), x, Integrate(S(1)/((a + b*sinh(e + f*x))*(c + d*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)/(a + b*sinh(e + f*x))**S(2), x), x, S(6)*a*d**S(3)*PolyLog(S(4), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(4)*(a**S(2) + b**S(2))**(S(3)/2)) - S(6)*a*d**S(3)*PolyLog(S(4), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(4)*(a**S(2) + b**S(2))**(S(3)/2)) - S(6)*a*d**S(2)*(c + d*x)*PolyLog(S(3), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))**(S(3)/2)) + S(6)*a*d**S(2)*(c + d*x)*PolyLog(S(3), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))**(S(3)/2)) + S(3)*a*d*(c + d*x)**S(2)*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) - S(3)*a*d*(c + d*x)**S(2)*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) + a*(c + d*x)**S(3)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f*(a**S(2) + b**S(2))**(S(3)/2)) - a*(c + d*x)**S(3)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f*(a**S(2) + b**S(2))**(S(3)/2)) - b*(c + d*x)**S(3)*cosh(e + f*x)/(f*(a + b*sinh(e + f*x))*(a**S(2) + b**S(2))) - S(6)*d**S(3)*PolyLog(S(3), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(4)*(a**S(2) + b**S(2))) - S(6)*d**S(3)*PolyLog(S(3), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(4)*(a**S(2) + b**S(2))) + S(6)*d**S(2)*(c + d*x)*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))) + S(6)*d**S(2)*(c + d*x)*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))) + S(3)*d*(c + d*x)**S(2)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f**S(2)*(a**S(2) + b**S(2))) + S(3)*d*(c + d*x)**S(2)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f**S(2)*(a**S(2) + b**S(2))) - (c + d*x)**S(3)/(f*(a**S(2) + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/(a + b*sinh(e + f*x))**S(2), x), x, -S(2)*a*d**S(2)*PolyLog(S(3), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))**(S(3)/2)) + S(2)*a*d**S(2)*PolyLog(S(3), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))**(S(3)/2)) + S(2)*a*d*(c + d*x)*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) - S(2)*a*d*(c + d*x)*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) + a*(c + d*x)**S(2)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f*(a**S(2) + b**S(2))**(S(3)/2)) - a*(c + d*x)**S(2)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f*(a**S(2) + b**S(2))**(S(3)/2)) - b*(c + d*x)**S(2)*cosh(e + f*x)/(f*(a + b*sinh(e + f*x))*(a**S(2) + b**S(2))) + S(2)*d**S(2)*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))) + S(2)*d**S(2)*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(3)*(a**S(2) + b**S(2))) + S(2)*d*(c + d*x)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f**S(2)*(a**S(2) + b**S(2))) + S(2)*d*(c + d*x)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f**S(2)*(a**S(2) + b**S(2))) - (c + d*x)**S(2)/(f*(a**S(2) + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/(a + b*sinh(e + f*x))**S(2), x), x, a*d*PolyLog(S(2), -b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))))/(f**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) - a*d*PolyLog(S(2), -b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))))/(f**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) + a*(c + d*x)*log(b*exp(e + f*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(f*(a**S(2) + b**S(2))**(S(3)/2)) - a*(c + d*x)*log(b*exp(e + f*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(f*(a**S(2) + b**S(2))**(S(3)/2)) - b*(c + d*x)*cosh(e + f*x)/(f*(a + b*sinh(e + f*x))*(a**S(2) + b**S(2))) + d*log(a + b*sinh(e + f*x))/(f**S(2)*(a**S(2) + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*sinh(e + f*x))**S(2)*(c + d*x)), x), x, Integrate(S(1)/((a + b*sinh(e + f*x))**S(2)*(c + d*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*sinh(e + f*x))**S(2)*(c + d*x)**S(2)), x), x, Integrate(S(1)/((a + b*sinh(e + f*x))**S(2)*(c + d*x)**S(2)), x), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((e + f*x)**S(2)/(a + b*sinh(c + d*x))**S(3), x), x, S(3)*a**S(2)*(e + f*x)**S(2)*log(b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(5)/2)) - S(3)*a**S(2)*(e + f*x)**S(2)*log(b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(5)/2)) + S(3)*a**S(2)*f*(e + f*x)*PolyLog(S(2), -b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))))/(d**S(2)*(a**S(2) + b**S(2))**(S(5)/2)) - S(3)*a**S(2)*f*(e + f*x)*PolyLog(S(2), -b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))))/(d**S(2)*(a**S(2) + b**S(2))**(S(5)/2)) - S(3)*a**S(2)*f**S(2)*PolyLog(S(3), -b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))))/(d**S(3)*(a**S(2) + b**S(2))**(S(5)/2)) + S(3)*a**S(2)*f**S(2)*PolyLog(S(3), -b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))))/(d**S(3)*(a**S(2) + b**S(2))**(S(5)/2)) - S(3)*a*b*(e + f*x)**S(2)*cosh(c + d*x)/(S(2)*d*(a + b*sinh(c + d*x))*(a**S(2) + b**S(2))**S(2)) - S(3)*a*(e + f*x)**S(2)/(S(2)*d*(a**S(2) + b**S(2))**S(2)) + S(3)*a*f*(e + f*x)*log(b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(d**S(2)*(a**S(2) + b**S(2))**S(2)) + S(3)*a*f*(e + f*x)*log(b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(d**S(2)*(a**S(2) + b**S(2))**S(2)) + S(3)*a*f**S(2)*PolyLog(S(2), -b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))))/(d**S(3)*(a**S(2) + b**S(2))**S(2)) + S(3)*a*f**S(2)*PolyLog(S(2), -b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))))/(d**S(3)*(a**S(2) + b**S(2))**S(2)) - b*(e + f*x)**S(2)*cosh(c + d*x)/(S(2)*d*(a + b*sinh(c + d*x))**S(2)*(a**S(2) + b**S(2))) - (e + f*x)**S(2)*log(b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(3)/2)) + (e + f*x)**S(2)*log(b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(3)/2)) - f*(e + f*x)*PolyLog(S(2), -b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))))/(d**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) + f*(e + f*x)*PolyLog(S(2), -b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))))/(d**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) - f*(e + f*x)/(d**S(2)*(a + b*sinh(c + d*x))*(a**S(2) + b**S(2))) + f**S(2)*PolyLog(S(3), -b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))))/(d**S(3)*(a**S(2) + b**S(2))**(S(3)/2)) - f**S(2)*PolyLog(S(3), -b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))))/(d**S(3)*(a**S(2) + b**S(2))**(S(3)/2)) - S(2)*f**S(2)*atanh((-a*tanh(c/S(2) + d*x/S(2)) + b)/sqrt(a**S(2) + b**S(2)))/(d**S(3)*(a**S(2) + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e + f*x)/(a + b*sinh(c + d*x))**S(3), x), x, S(3)*a**S(2)*(e + f*x)*log(b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(5)/2)) - S(3)*a**S(2)*(e + f*x)*log(b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(5)/2)) + S(3)*a**S(2)*f*PolyLog(S(2), -b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))))/(S(2)*d**S(2)*(a**S(2) + b**S(2))**(S(5)/2)) - S(3)*a**S(2)*f*PolyLog(S(2), -b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))))/(S(2)*d**S(2)*(a**S(2) + b**S(2))**(S(5)/2)) - S(3)*a*b*(e + f*x)*cosh(c + d*x)/(S(2)*d*(a + b*sinh(c + d*x))*(a**S(2) + b**S(2))**S(2)) + S(3)*a*f*log(a + b*sinh(c + d*x))/(S(2)*d**S(2)*(a**S(2) + b**S(2))**S(2)) - b*(e + f*x)*cosh(c + d*x)/(S(2)*d*(a + b*sinh(c + d*x))**S(2)*(a**S(2) + b**S(2))) - (e + f*x)*log(b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(3)/2)) + (e + f*x)*log(b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))) + S(1))/(S(2)*d*(a**S(2) + b**S(2))**(S(3)/2)) - f*PolyLog(S(2), -b*exp(c + d*x)/(a - sqrt(a**S(2) + b**S(2))))/(S(2)*d**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) + f*PolyLog(S(2), -b*exp(c + d*x)/(a + sqrt(a**S(2) + b**S(2))))/(S(2)*d**S(2)*(a**S(2) + b**S(2))**(S(3)/2)) - f/(S(2)*d**S(2)*(a + b*sinh(c + d*x))*(a**S(2) + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*sinh(c + d*x))**S(3)*(e + f*x)), x), x, Integrate(S(1)/((a + b*sinh(c + d*x))**S(3)*(e + f*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*sinh(c + d*x))**S(3)*(e + f*x)**S(2)), x), x, Integrate(S(1)/((a + b*sinh(c + d*x))**S(3)*(e + f*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**n*(c + d*x)**m, x), x, Integrate((a + b*sinh(e + f*x))**n*(c + d*x)**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(3)*(c + d*x)**m, x), x, S(3)*S(2)**(-m + S(-3))*a*b**S(2)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(2)*f*(c + d*x)/d)*exp(-S(2)*c*f/d + S(2)*e)/f - S(3)*S(2)**(-m + S(-3))*a*b**S(2)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(2)*f*(c + d*x)/d)*exp(S(2)*c*f/d - S(2)*e)/f + S(3)**(-m + S(-1))*b**S(3)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(3)*f*(c + d*x)/d)*exp(-S(3)*c*f/d + S(3)*e)/(S(8)*f) + S(3)**(-m + S(-1))*b**S(3)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(3)*f*(c + d*x)/d)*exp(S(3)*c*f/d - S(3)*e)/(S(8)*f) + a**S(3)*(c + d*x)**(m + S(1))/(d*(m + S(1))) + S(3)*a**S(2)*b*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -f*(c + d*x)/d)*exp(-c*f/d + e)/(S(2)*f) + S(3)*a**S(2)*b*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), f*(c + d*x)/d)*exp(c*f/d - e)/(S(2)*f) - S(3)*a*b**S(2)*(c + d*x)**(m + S(1))/(S(2)*d*(m + S(1))) - S(3)*b**S(3)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -f*(c + d*x)/d)*exp(-c*f/d + e)/(S(8)*f) - S(3)*b**S(3)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), f*(c + d*x)/d)*exp(c*f/d - e)/(S(8)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))**S(2)*(c + d*x)**m, x), x, S(2)**(-m + S(-3))*b**S(2)*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -S(2)*f*(c + d*x)/d)*exp(-S(2)*c*f/d + S(2)*e)/f - S(2)**(-m + S(-3))*b**S(2)*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), S(2)*f*(c + d*x)/d)*exp(S(2)*c*f/d - S(2)*e)/f + a**S(2)*(c + d*x)**(m + S(1))/(d*(m + S(1))) + a*b*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -f*(c + d*x)/d)*exp(-c*f/d + e)/f + a*b*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), f*(c + d*x)/d)*exp(c*f/d - e)/f - b**S(2)*(c + d*x)**(m + S(1))/(S(2)*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sinh(e + f*x))*(c + d*x)**m, x), x, a*(c + d*x)**(m + S(1))/(d*(m + S(1))) + b*(-f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), -f*(c + d*x)/d)*exp(-c*f/d + e)/(S(2)*f) + b*(f*(c + d*x)/d)**(-m)*(c + d*x)**m*Gamma(m + S(1), f*(c + d*x)/d)*exp(c*f/d - e)/(S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m/(a + b*sinh(e + f*x)), x), x, Integrate((c + d*x)**m/(a + b*sinh(e + f*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**m/(a + b*sinh(e + f*x))**S(2), x), x, Integrate((c + d*x)**m/(a + b*sinh(e + f*x))**S(2), x), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_inverse_hyperbolic_sine.py000066400000000000000000001772241412543434000317210ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.utility_function import ( sympy_op_factory, Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ ) from sympy import (Integral, Integral as Integrate, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf, exp, log) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec) from sympy import pi as Pi from sympy.integrals.rubi.rubi import rubi_integrate a, b, c, d, e, f, m, n, x, u , k, p, r, s, t, i, j= symbols('a b c d e f m n x u k p r s t i j') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F', ) def test_1(): assert rubi_test(rubi_integrate(x**S(4)*asinh(a*x), x), x, x**S(5)*asinh(a*x)/S(5) - (a**S(2)*x**S(2) + S(1))**(S(5)/2)/(S(25)*a**S(5)) + S(2)*(a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(15)*a**S(5)) - sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asinh(a*x), x), x, x**S(4)*asinh(a*x)/S(4) - x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(16)*a) + S(3)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(32)*a**S(3)) - S(3)*asinh(a*x)/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asinh(a*x), x), x, x**S(3)*asinh(a*x)/S(3) - (a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(9)*a**S(3)) + sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asinh(a*x), x), x, x**S(2)*asinh(a*x)/S(2) - x*sqrt(a**S(2)*x**S(2) + S(1))/(S(4)*a) + asinh(a*x)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x), x), x, x*asinh(a*x) - sqrt(a**S(2)*x**S(2) + S(1))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)/x, x), x, PolyLog(S(2), exp(S(2)*asinh(a*x)))/S(2) + log(-exp(S(2)*asinh(a*x)) + S(1))*asinh(a*x) - asinh(a*x)**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)/x**S(2), x), x, -a*atanh(sqrt(a**S(2)*x**S(2) + S(1))) - asinh(a*x)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)/x**S(3), x), x, -a*sqrt(a**S(2)*x**S(2) + S(1))/(S(2)*x) - asinh(a*x)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)/x**S(4), x), x, a**S(3)*atanh(sqrt(a**S(2)*x**S(2) + S(1)))/S(6) - a*sqrt(a**S(2)*x**S(2) + S(1))/(S(6)*x**S(2)) - asinh(a*x)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)/x**S(5), x), x, a**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(6)*x) - a*sqrt(a**S(2)*x**S(2) + S(1))/(S(12)*x**S(3)) - asinh(a*x)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)/x**S(6), x), x, -S(3)*a**S(5)*atanh(sqrt(a**S(2)*x**S(2) + S(1)))/S(40) + S(3)*a**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(40)*x**S(2)) - a*sqrt(a**S(2)*x**S(2) + S(1))/(S(20)*x**S(4)) - asinh(a*x)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asinh(a*x)**S(2), x), x, x**S(5)*asinh(a*x)**S(2)/S(5) + S(2)*x**S(5)/S(125) - S(2)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(25)*a) - S(8)*x**S(3)/(S(225)*a**S(2)) + S(8)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(75)*a**S(3)) + S(16)*x/(S(75)*a**S(4)) - S(16)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(75)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asinh(a*x)**S(2), x), x, x**S(4)*asinh(a*x)**S(2)/S(4) + x**S(4)/S(32) - x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(8)*a) - S(3)*x**S(2)/(S(32)*a**S(2)) + S(3)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(16)*a**S(3)) - S(3)*asinh(a*x)**S(2)/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asinh(a*x)**S(2), x), x, x**S(3)*asinh(a*x)**S(2)/S(3) + S(2)*x**S(3)/S(27) - S(2)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(9)*a) - S(4)*x/(S(9)*a**S(2)) + S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(9)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asinh(a*x)**S(2), x), x, x**S(2)*asinh(a*x)**S(2)/S(2) + x**S(2)/S(4) - x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(2)*a) + asinh(a*x)**S(2)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(2), x), x, x*asinh(a*x)**S(2) + S(2)*x - S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(2)/x, x), x, PolyLog(S(2), exp(S(2)*asinh(a*x)))*asinh(a*x) - PolyLog(S(3), exp(S(2)*asinh(a*x)))/S(2) + log(-exp(S(2)*asinh(a*x)) + S(1))*asinh(a*x)**S(2) - asinh(a*x)**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(2)/x**S(2), x), x, -S(2)*a*PolyLog(S(2), -exp(asinh(a*x))) + S(2)*a*PolyLog(S(2), exp(asinh(a*x))) - S(4)*a*asinh(a*x)*atanh(exp(asinh(a*x))) - asinh(a*x)**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(2)/x**S(3), x), x, a**S(2)*log(x) - a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/x - asinh(a*x)**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(2)/x**S(4), x), x, a**S(3)*PolyLog(S(2), -exp(asinh(a*x)))/S(3) - a**S(3)*PolyLog(S(2), exp(asinh(a*x)))/S(3) + S(2)*a**S(3)*asinh(a*x)*atanh(exp(asinh(a*x)))/S(3) - a**S(2)/(S(3)*x) - a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(3)*x**S(2)) - asinh(a*x)**S(2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(2)/x**S(5), x), x, -a**S(4)*log(x)/S(3) + a**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(3)*x) - a**S(2)/(S(12)*x**S(2)) - a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(6)*x**S(3)) - asinh(a*x)**S(2)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asinh(a*x)**S(3), x), x, x**S(5)*asinh(a*x)**S(3)/S(5) + S(6)*x**S(5)*asinh(a*x)/S(125) - S(3)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(25)*a) - S(8)*x**S(3)*asinh(a*x)/(S(75)*a**S(2)) + S(4)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(25)*a**S(3)) + S(16)*x*asinh(a*x)/(S(25)*a**S(4)) - S(6)*(a**S(2)*x**S(2) + S(1))**(S(5)/2)/(S(625)*a**S(5)) + S(76)*(a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(1125)*a**S(5)) - S(8)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(25)*a**S(5)) - S(298)*sqrt(a**S(2)*x**S(2) + S(1))/(S(375)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asinh(a*x)**S(3), x), x, x**S(4)*asinh(a*x)**S(3)/S(4) + S(3)*x**S(4)*asinh(a*x)/S(32) - S(3)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(16)*a) - S(3)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(128)*a) - S(9)*x**S(2)*asinh(a*x)/(S(32)*a**S(2)) + S(9)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(32)*a**S(3)) + S(45)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(256)*a**S(3)) - S(3)*asinh(a*x)**S(3)/(S(32)*a**S(4)) - S(45)*asinh(a*x)/(S(256)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asinh(a*x)**S(3), x), x, x**S(3)*asinh(a*x)**S(3)/S(3) + S(2)*x**S(3)*asinh(a*x)/S(9) - x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(3)*a) - S(4)*x*asinh(a*x)/(S(3)*a**S(2)) - S(2)*(a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(27)*a**S(3)) + S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(3)*a**S(3)) + S(14)*sqrt(a**S(2)*x**S(2) + S(1))/(S(9)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asinh(a*x)**S(3), x), x, x**S(2)*asinh(a*x)**S(3)/S(2) + S(3)*x**S(2)*asinh(a*x)/S(4) - S(3)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(4)*a) - S(3)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(8)*a) + asinh(a*x)**S(3)/(S(4)*a**S(2)) + S(3)*asinh(a*x)/(S(8)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(3), x), x, x*asinh(a*x)**S(3) + S(6)*x*asinh(a*x) - S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/a - S(6)*sqrt(a**S(2)*x**S(2) + S(1))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(3)/x, x), x, S(3)*PolyLog(S(2), exp(S(2)*asinh(a*x)))*asinh(a*x)**S(2)/S(2) - S(3)*PolyLog(S(3), exp(S(2)*asinh(a*x)))*asinh(a*x)/S(2) + S(3)*PolyLog(S(4), exp(S(2)*asinh(a*x)))/S(4) + log(-exp(S(2)*asinh(a*x)) + S(1))*asinh(a*x)**S(3) - asinh(a*x)**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(3)/x**S(2), x), x, -S(6)*a*PolyLog(S(2), -exp(asinh(a*x)))*asinh(a*x) + S(6)*a*PolyLog(S(2), exp(asinh(a*x)))*asinh(a*x) + S(6)*a*PolyLog(S(3), -exp(asinh(a*x))) - S(6)*a*PolyLog(S(3), exp(asinh(a*x))) - S(6)*a*asinh(a*x)**S(2)*atanh(exp(asinh(a*x))) - asinh(a*x)**S(3)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(3)/x**S(3), x), x, S(3)*a**S(2)*PolyLog(S(2), exp(S(2)*asinh(a*x)))/S(2) + S(3)*a**S(2)*log(-exp(S(2)*asinh(a*x)) + S(1))*asinh(a*x) - S(3)*a**S(2)*asinh(a*x)**S(2)/S(2) - S(3)*a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(2)*x) - asinh(a*x)**S(3)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(3)/x**S(4), x), x, a**S(3)*PolyLog(S(2), -exp(asinh(a*x)))*asinh(a*x) - a**S(3)*PolyLog(S(2), exp(asinh(a*x)))*asinh(a*x) - a**S(3)*PolyLog(S(3), -exp(asinh(a*x))) + a**S(3)*PolyLog(S(3), exp(asinh(a*x))) + a**S(3)*asinh(a*x)**S(2)*atanh(exp(asinh(a*x))) - a**S(3)*atanh(sqrt(a**S(2)*x**S(2) + S(1))) - a**S(2)*asinh(a*x)/x - a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(2)*x**S(2)) - asinh(a*x)**S(3)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(3)/x**S(5), x), x, -a**S(4)*PolyLog(S(2), exp(S(2)*asinh(a*x)))/S(2) - a**S(4)*log(-exp(S(2)*asinh(a*x)) + S(1))*asinh(a*x) + a**S(4)*asinh(a*x)**S(2)/S(2) + a**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(2)*x) - a**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(4)*x) - a**S(2)*asinh(a*x)/(S(4)*x**S(2)) - a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(2)/(S(4)*x**S(3)) - asinh(a*x)**S(3)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*asinh(a*x)**S(4), x), x, x**S(6)*asinh(a*x)**S(4)/S(6) + x**S(6)*asinh(a*x)**S(2)/S(18) + x**S(6)/S(324) - x**S(5)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(9)*a) - x**S(5)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(54)*a) - S(5)*x**S(4)*asinh(a*x)**S(2)/(S(48)*a**S(2)) - S(65)*x**S(4)/(S(3456)*a**S(2)) + S(5)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(36)*a**S(3)) + S(65)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(864)*a**S(3)) + S(5)*x**S(2)*asinh(a*x)**S(2)/(S(16)*a**S(4)) + S(245)*x**S(2)/(S(1152)*a**S(4)) - S(5)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(24)*a**S(5)) - S(245)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(576)*a**S(5)) + S(5)*asinh(a*x)**S(4)/(S(96)*a**S(6)) + S(245)*asinh(a*x)**S(2)/(S(1152)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asinh(a*x)**S(4), x), x, x**S(5)*asinh(a*x)**S(4)/S(5) + S(12)*x**S(5)*asinh(a*x)**S(2)/S(125) + S(24)*x**S(5)/S(3125) - S(4)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(25)*a) - S(24)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(625)*a) - S(16)*x**S(3)*asinh(a*x)**S(2)/(S(75)*a**S(2)) - S(1088)*x**S(3)/(S(16875)*a**S(2)) + S(16)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(75)*a**S(3)) + S(1088)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(5625)*a**S(3)) + S(32)*x*asinh(a*x)**S(2)/(S(25)*a**S(4)) + S(16576)*x/(S(5625)*a**S(4)) - S(32)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(75)*a**S(5)) - S(16576)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(5625)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asinh(a*x)**S(4), x), x, x**S(4)*asinh(a*x)**S(4)/S(4) + S(3)*x**S(4)*asinh(a*x)**S(2)/S(16) + S(3)*x**S(4)/S(128) - x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(4)*a) - S(3)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(32)*a) - S(9)*x**S(2)*asinh(a*x)**S(2)/(S(16)*a**S(2)) - S(45)*x**S(2)/(S(128)*a**S(2)) + S(3)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(8)*a**S(3)) + S(45)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(64)*a**S(3)) - S(3)*asinh(a*x)**S(4)/(S(32)*a**S(4)) - S(45)*asinh(a*x)**S(2)/(S(128)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asinh(a*x)**S(4), x), x, x**S(3)*asinh(a*x)**S(4)/S(3) + S(4)*x**S(3)*asinh(a*x)**S(2)/S(9) + S(8)*x**S(3)/S(81) - S(4)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(9)*a) - S(8)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(27)*a) - S(8)*x*asinh(a*x)**S(2)/(S(3)*a**S(2)) - S(160)*x/(S(27)*a**S(2)) + S(8)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(9)*a**S(3)) + S(160)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(27)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asinh(a*x)**S(4), x), x, x**S(2)*asinh(a*x)**S(4)/S(2) + S(3)*x**S(2)*asinh(a*x)**S(2)/S(2) + S(3)*x**S(2)/S(4) - x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/a - S(3)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/(S(2)*a) + asinh(a*x)**S(4)/(S(4)*a**S(2)) + S(3)*asinh(a*x)**S(2)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(4), x), x, x*asinh(a*x)**S(4) + S(12)*x*asinh(a*x)**S(2) + S(24)*x - S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/a - S(24)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(4)/x, x), x, S(2)*PolyLog(S(2), exp(S(2)*asinh(a*x)))*asinh(a*x)**S(3) - S(3)*PolyLog(S(3), exp(S(2)*asinh(a*x)))*asinh(a*x)**S(2) + S(3)*PolyLog(S(4), exp(S(2)*asinh(a*x)))*asinh(a*x) - S(3)*PolyLog(S(5), exp(S(2)*asinh(a*x)))/S(2) + log(-exp(S(2)*asinh(a*x)) + S(1))*asinh(a*x)**S(4) - asinh(a*x)**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(4)/x**S(2), x), x, -S(12)*a*PolyLog(S(2), -exp(asinh(a*x)))*asinh(a*x)**S(2) + S(12)*a*PolyLog(S(2), exp(asinh(a*x)))*asinh(a*x)**S(2) + S(24)*a*PolyLog(S(3), -exp(asinh(a*x)))*asinh(a*x) - S(24)*a*PolyLog(S(3), exp(asinh(a*x)))*asinh(a*x) - S(24)*a*PolyLog(S(4), -exp(asinh(a*x))) + S(24)*a*PolyLog(S(4), exp(asinh(a*x))) - S(8)*a*asinh(a*x)**S(3)*atanh(exp(asinh(a*x))) - asinh(a*x)**S(4)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(4)/x**S(3), x), x, S(6)*a**S(2)*PolyLog(S(2), exp(S(2)*asinh(a*x)))*asinh(a*x) - S(3)*a**S(2)*PolyLog(S(3), exp(S(2)*asinh(a*x))) + S(6)*a**S(2)*log(-exp(S(2)*asinh(a*x)) + S(1))*asinh(a*x)**S(2) - S(2)*a**S(2)*asinh(a*x)**S(3) - S(2)*a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/x - asinh(a*x)**S(4)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**S(4)/x**S(4), x), x, S(2)*a**S(3)*PolyLog(S(2), -exp(asinh(a*x)))*asinh(a*x)**S(2) - S(4)*a**S(3)*PolyLog(S(2), -exp(asinh(a*x))) - S(2)*a**S(3)*PolyLog(S(2), exp(asinh(a*x)))*asinh(a*x)**S(2) + S(4)*a**S(3)*PolyLog(S(2), exp(asinh(a*x))) - S(4)*a**S(3)*PolyLog(S(3), -exp(asinh(a*x)))*asinh(a*x) + S(4)*a**S(3)*PolyLog(S(3), exp(asinh(a*x)))*asinh(a*x) + S(4)*a**S(3)*PolyLog(S(4), -exp(asinh(a*x))) - S(4)*a**S(3)*PolyLog(S(4), exp(asinh(a*x))) + S(4)*a**S(3)*asinh(a*x)**S(3)*atanh(exp(asinh(a*x)))/S(3) - S(8)*a**S(3)*asinh(a*x)*atanh(exp(asinh(a*x))) - S(2)*a**S(2)*asinh(a*x)**S(2)/x - S(2)*a*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**S(3)/(S(3)*x**S(2)) - asinh(a*x)**S(4)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/asinh(a*x), x), x, -S(5)*CoshIntegral(asinh(a*x))/(S(64)*a**S(7)) + S(9)*CoshIntegral(S(3)*asinh(a*x))/(S(64)*a**S(7)) - S(5)*CoshIntegral(S(5)*asinh(a*x))/(S(64)*a**S(7)) + CoshIntegral(S(7)*asinh(a*x))/(S(64)*a**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/asinh(a*x), x), x, S(5)*SinhIntegral(S(2)*asinh(a*x))/(S(32)*a**S(6)) - SinhIntegral(S(4)*asinh(a*x))/(S(8)*a**S(6)) + SinhIntegral(S(6)*asinh(a*x))/(S(32)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asinh(a*x), x), x, CoshIntegral(asinh(a*x))/(S(8)*a**S(5)) - S(3)*CoshIntegral(S(3)*asinh(a*x))/(S(16)*a**S(5)) + CoshIntegral(S(5)*asinh(a*x))/(S(16)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asinh(a*x), x), x, -SinhIntegral(S(2)*asinh(a*x))/(S(4)*a**S(4)) + SinhIntegral(S(4)*asinh(a*x))/(S(8)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asinh(a*x), x), x, -CoshIntegral(asinh(a*x))/(S(4)*a**S(3)) + CoshIntegral(S(3)*asinh(a*x))/(S(4)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asinh(a*x), x), x, SinhIntegral(S(2)*asinh(a*x))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/asinh(a*x), x), x, CoshIntegral(asinh(a*x))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asinh(a*x)), x), x, Integrate(S(1)/(x*asinh(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asinh(a*x)), x), x, Integrate(S(1)/(x**S(2)*asinh(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/asinh(a*x)**S(2), x), x, -x**S(6)*sqrt(a**S(2)*x**S(2) + S(1))/(a*asinh(a*x)) - S(5)*SinhIntegral(asinh(a*x))/(S(64)*a**S(7)) + S(27)*SinhIntegral(S(3)*asinh(a*x))/(S(64)*a**S(7)) - S(25)*SinhIntegral(S(5)*asinh(a*x))/(S(64)*a**S(7)) + S(7)*SinhIntegral(S(7)*asinh(a*x))/(S(64)*a**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/asinh(a*x)**S(2), x), x, -x**S(5)*sqrt(a**S(2)*x**S(2) + S(1))/(a*asinh(a*x)) + S(5)*CoshIntegral(S(2)*asinh(a*x))/(S(16)*a**S(6)) - CoshIntegral(S(4)*asinh(a*x))/(S(2)*a**S(6)) + S(3)*CoshIntegral(S(6)*asinh(a*x))/(S(16)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asinh(a*x)**S(2), x), x, -x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(a*asinh(a*x)) + SinhIntegral(asinh(a*x))/(S(8)*a**S(5)) - S(9)*SinhIntegral(S(3)*asinh(a*x))/(S(16)*a**S(5)) + S(5)*SinhIntegral(S(5)*asinh(a*x))/(S(16)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asinh(a*x)**S(2), x), x, -x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(a*asinh(a*x)) - CoshIntegral(S(2)*asinh(a*x))/(S(2)*a**S(4)) + CoshIntegral(S(4)*asinh(a*x))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asinh(a*x)**S(2), x), x, -x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(a*asinh(a*x)) - SinhIntegral(asinh(a*x))/(S(4)*a**S(3)) + S(3)*SinhIntegral(S(3)*asinh(a*x))/(S(4)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asinh(a*x)**S(2), x), x, -x*sqrt(a**S(2)*x**S(2) + S(1))/(a*asinh(a*x)) + CoshIntegral(S(2)*asinh(a*x))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(-2)), x), x, -sqrt(a**S(2)*x**S(2) + S(1))/(a*asinh(a*x)) + SinhIntegral(asinh(a*x))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asinh(a*x)**S(2)), x), x, Integrate(S(1)/(x*asinh(a*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asinh(a*x)**S(2)), x), x, Integrate(S(1)/(x**S(2)*asinh(a*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asinh(a*x)**S(3), x), x, -S(5)*x**S(5)/(S(2)*asinh(a*x)) - x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(S(2)*a*asinh(a*x)**S(2)) - S(2)*x**S(3)/(a**S(2)*asinh(a*x)) + CoshIntegral(asinh(a*x))/(S(16)*a**S(5)) - S(27)*CoshIntegral(S(3)*asinh(a*x))/(S(32)*a**S(5)) + S(25)*CoshIntegral(S(5)*asinh(a*x))/(S(32)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asinh(a*x)**S(3), x), x, -S(2)*x**S(4)/asinh(a*x) - x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(2)*a*asinh(a*x)**S(2)) - S(3)*x**S(2)/(S(2)*a**S(2)*asinh(a*x)) - SinhIntegral(S(2)*asinh(a*x))/(S(2)*a**S(4)) + SinhIntegral(S(4)*asinh(a*x))/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asinh(a*x)**S(3), x), x, -S(3)*x**S(3)/(S(2)*asinh(a*x)) - x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(2)*a*asinh(a*x)**S(2)) - x/(a**S(2)*asinh(a*x)) - CoshIntegral(asinh(a*x))/(S(8)*a**S(3)) + S(9)*CoshIntegral(S(3)*asinh(a*x))/(S(8)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asinh(a*x)**S(3), x), x, -x**S(2)/asinh(a*x) - x*sqrt(a**S(2)*x**S(2) + S(1))/(S(2)*a*asinh(a*x)**S(2)) + SinhIntegral(S(2)*asinh(a*x))/a**S(2) - S(1)/(S(2)*a**S(2)*asinh(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(-3)), x), x, -x/(S(2)*asinh(a*x)) - sqrt(a**S(2)*x**S(2) + S(1))/(S(2)*a*asinh(a*x)**S(2)) + CoshIntegral(asinh(a*x))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asinh(a*x)**S(3)), x), x, Integrate(S(1)/(x*asinh(a*x)**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asinh(a*x)**S(3)), x), x, Integrate(S(1)/(x**S(2)*asinh(a*x)**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asinh(a*x)**S(4), x), x, -S(5)*x**S(5)/(S(6)*asinh(a*x)**S(2)) - S(25)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(S(6)*a*asinh(a*x)) - x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**S(3)) - S(2)*x**S(3)/(S(3)*a**S(2)*asinh(a*x)**S(2)) - S(2)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(a**S(3)*asinh(a*x)) + SinhIntegral(asinh(a*x))/(S(48)*a**S(5)) - S(27)*SinhIntegral(S(3)*asinh(a*x))/(S(32)*a**S(5)) + S(125)*SinhIntegral(S(5)*asinh(a*x))/(S(96)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asinh(a*x)**S(4), x), x, -S(2)*x**S(4)/(S(3)*asinh(a*x)**S(2)) - S(8)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)) - x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**S(3)) - x**S(2)/(S(2)*a**S(2)*asinh(a*x)**S(2)) - x*sqrt(a**S(2)*x**S(2) + S(1))/(a**S(3)*asinh(a*x)) - CoshIntegral(S(2)*asinh(a*x))/(S(3)*a**S(4)) + S(4)*CoshIntegral(S(4)*asinh(a*x))/(S(3)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asinh(a*x)**S(4), x), x, -x**S(3)/(S(2)*asinh(a*x)**S(2)) - S(3)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(2)*a*asinh(a*x)) - x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**S(3)) - x/(S(3)*a**S(2)*asinh(a*x)**S(2)) - sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a**S(3)*asinh(a*x)) - SinhIntegral(asinh(a*x))/(S(24)*a**S(3)) + S(9)*SinhIntegral(S(3)*asinh(a*x))/(S(8)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asinh(a*x)**S(4), x), x, -x**S(2)/(S(3)*asinh(a*x)**S(2)) - S(2)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)) - x*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**S(3)) + S(2)*CoshIntegral(S(2)*asinh(a*x))/(S(3)*a**S(2)) - S(1)/(S(6)*a**S(2)*asinh(a*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(-4)), x), x, -x/(S(6)*asinh(a*x)**S(2)) - sqrt(a**S(2)*x**S(2) + S(1))/(S(6)*a*asinh(a*x)) - sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**S(3)) + SinhIntegral(asinh(a*x))/(S(6)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asinh(a*x)**S(4)), x), x, Integrate(S(1)/(x*asinh(a*x)**S(4)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asinh(a*x)**S(4)), x), x, Integrate(S(1)/(x**S(2)*asinh(a*x)**S(4)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(asinh(a*x)), x), x, -sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(192)*a**S(5)) + sqrt(S(5))*sqrt(Pi)*Erf(sqrt(S(5))*sqrt(asinh(a*x)))/(S(1600)*a**S(5)) + sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(32)*a**S(5)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(192)*a**S(5)) - sqrt(S(5))*sqrt(Pi)*Erfi(sqrt(S(5))*sqrt(asinh(a*x)))/(S(1600)*a**S(5)) - sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(32)*a**S(5)) + x**S(5)*sqrt(asinh(a*x))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(asinh(a*x)), x), x, sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(64)*a**S(4)) - sqrt(Pi)*Erf(S(2)*sqrt(asinh(a*x)))/(S(256)*a**S(4)) + sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(64)*a**S(4)) - sqrt(Pi)*Erfi(S(2)*sqrt(asinh(a*x)))/(S(256)*a**S(4)) + x**S(4)*sqrt(asinh(a*x))/S(4) - S(3)*sqrt(asinh(a*x))/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(asinh(a*x)), x), x, sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(144)*a**S(3)) - sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(16)*a**S(3)) - sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(144)*a**S(3)) + sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(16)*a**S(3)) + x**S(3)*sqrt(asinh(a*x))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(asinh(a*x)), x), x, -sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(32)*a**S(2)) - sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(32)*a**S(2)) + x**S(2)*sqrt(asinh(a*x))/S(2) + sqrt(asinh(a*x))/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(asinh(a*x)), x), x, sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(4)*a) - sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(4)*a) + x*sqrt(asinh(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(asinh(a*x))/x, x), x, Integrate(sqrt(asinh(a*x))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asinh(a*x)**(S(3)/2), x), x, -sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(384)*a**S(5)) + S(3)*sqrt(S(5))*sqrt(Pi)*Erf(sqrt(S(5))*sqrt(asinh(a*x)))/(S(16000)*a**S(5)) + S(3)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(64)*a**S(5)) - sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(384)*a**S(5)) + S(3)*sqrt(S(5))*sqrt(Pi)*Erfi(sqrt(S(5))*sqrt(asinh(a*x)))/(S(16000)*a**S(5)) + S(3)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(64)*a**S(5)) + x**S(5)*asinh(a*x)**(S(3)/2)/S(5) - S(3)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(50)*a) + S(2)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(25)*a**S(3)) - S(4)*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(25)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asinh(a*x)**(S(3)/2), x), x, S(3)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(256)*a**S(4)) - S(3)*sqrt(Pi)*Erf(S(2)*sqrt(asinh(a*x)))/(S(2048)*a**S(4)) - S(3)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(256)*a**S(4)) + S(3)*sqrt(Pi)*Erfi(S(2)*sqrt(asinh(a*x)))/(S(2048)*a**S(4)) + x**S(4)*asinh(a*x)**(S(3)/2)/S(4) - S(3)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(32)*a) + S(9)*x*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(64)*a**S(3)) - S(3)*asinh(a*x)**(S(3)/2)/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asinh(a*x)**(S(3)/2), x), x, sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(288)*a**S(3)) - S(3)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(32)*a**S(3)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(288)*a**S(3)) - S(3)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(32)*a**S(3)) + x**S(3)*asinh(a*x)**(S(3)/2)/S(3) - x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(6)*a) + sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(3)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asinh(a*x)**(S(3)/2), x), x, -S(3)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(128)*a**S(2)) + S(3)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(128)*a**S(2)) + x**S(2)*asinh(a*x)**(S(3)/2)/S(2) - S(3)*x*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(8)*a) + asinh(a*x)**(S(3)/2)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(3)/2), x), x, S(3)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(8)*a) + S(3)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(8)*a) + x*asinh(a*x)**(S(3)/2) - S(3)*sqrt(a**S(2)*x**S(2) + S(1))*sqrt(asinh(a*x))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(3)/2)/x, x), x, Integrate(asinh(a*x)**(S(3)/2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asinh(a*x)**(S(5)/2), x), x, -S(5)*sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(2304)*a**S(5)) + S(3)*sqrt(S(5))*sqrt(Pi)*Erf(sqrt(S(5))*sqrt(asinh(a*x)))/(S(32000)*a**S(5)) + S(15)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(128)*a**S(5)) + S(5)*sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(2304)*a**S(5)) - S(3)*sqrt(S(5))*sqrt(Pi)*Erfi(sqrt(S(5))*sqrt(asinh(a*x)))/(S(32000)*a**S(5)) - S(15)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(128)*a**S(5)) + x**S(5)*asinh(a*x)**(S(5)/2)/S(5) + S(3)*x**S(5)*sqrt(asinh(a*x))/S(100) - x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(10)*a) - x**S(3)*sqrt(asinh(a*x))/(S(15)*a**S(2)) + S(2)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(15)*a**S(3)) + S(2)*x*sqrt(asinh(a*x))/(S(5)*a**S(4)) - S(4)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(15)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asinh(a*x)**(S(5)/2), x), x, S(15)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(1024)*a**S(4)) - S(15)*sqrt(Pi)*Erf(S(2)*sqrt(asinh(a*x)))/(S(16384)*a**S(4)) + S(15)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(1024)*a**S(4)) - S(15)*sqrt(Pi)*Erfi(S(2)*sqrt(asinh(a*x)))/(S(16384)*a**S(4)) + x**S(4)*asinh(a*x)**(S(5)/2)/S(4) + S(15)*x**S(4)*sqrt(asinh(a*x))/S(256) - S(5)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(32)*a) - S(45)*x**S(2)*sqrt(asinh(a*x))/(S(256)*a**S(2)) + S(15)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(64)*a**S(3)) - S(3)*asinh(a*x)**(S(5)/2)/(S(32)*a**S(4)) - S(225)*sqrt(asinh(a*x))/(S(2048)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asinh(a*x)**(S(5)/2), x), x, S(5)*sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(1728)*a**S(3)) - S(15)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(64)*a**S(3)) - S(5)*sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(1728)*a**S(3)) + S(15)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(64)*a**S(3)) + x**S(3)*asinh(a*x)**(S(5)/2)/S(3) + S(5)*x**S(3)*sqrt(asinh(a*x))/S(36) - S(5)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(18)*a) - S(5)*x*sqrt(asinh(a*x))/(S(6)*a**S(2)) + S(5)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(9)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asinh(a*x)**(S(5)/2), x), x, -S(15)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(512)*a**S(2)) - S(15)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(512)*a**S(2)) + x**S(2)*asinh(a*x)**(S(5)/2)/S(2) + S(15)*x**S(2)*sqrt(asinh(a*x))/S(32) - S(5)*x*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(8)*a) + asinh(a*x)**(S(5)/2)/(S(4)*a**S(2)) + S(15)*sqrt(asinh(a*x))/(S(64)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(5)/2), x), x, S(15)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(16)*a) - S(15)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(16)*a) + x*asinh(a*x)**(S(5)/2) + S(15)*x*sqrt(asinh(a*x))/S(4) - S(5)*sqrt(a**S(2)*x**S(2) + S(1))*asinh(a*x)**(S(3)/2)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(5)/2)/x, x), x, Integrate(asinh(a*x)**(S(5)/2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(asinh(a*x)), x), x, -sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(32)*a**S(5)) + sqrt(S(5))*sqrt(Pi)*Erf(sqrt(S(5))*sqrt(asinh(a*x)))/(S(160)*a**S(5)) + sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(16)*a**S(5)) - sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(32)*a**S(5)) + sqrt(S(5))*sqrt(Pi)*Erfi(sqrt(S(5))*sqrt(asinh(a*x)))/(S(160)*a**S(5)) + sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(16)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(asinh(a*x)), x), x, sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(16)*a**S(4)) - sqrt(Pi)*Erf(S(2)*sqrt(asinh(a*x)))/(S(32)*a**S(4)) - sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(16)*a**S(4)) + sqrt(Pi)*Erfi(S(2)*sqrt(asinh(a*x)))/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(asinh(a*x)), x), x, sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(24)*a**S(3)) - sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(8)*a**S(3)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(24)*a**S(3)) - sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(8)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(asinh(a*x)), x), x, -sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(8)*a**S(2)) + sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(8)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(asinh(a*x)), x), x, sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(2)*a) + sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(asinh(a*x))), x), x, Integrate(S(1)/(x*sqrt(asinh(a*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(asinh(a*x))), x), x, Integrate(S(1)/(x**S(2)*sqrt(asinh(a*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asinh(a*x)**(S(3)/2), x), x, S(3)*sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(16)*a**S(5)) - sqrt(S(5))*sqrt(Pi)*Erf(sqrt(S(5))*sqrt(asinh(a*x)))/(S(16)*a**S(5)) - sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(8)*a**S(5)) - S(3)*sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(16)*a**S(5)) + sqrt(S(5))*sqrt(Pi)*Erfi(sqrt(S(5))*sqrt(asinh(a*x)))/(S(16)*a**S(5)) + sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(8)*a**S(5)) - S(2)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(a*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asinh(a*x)**(S(3)/2), x), x, -sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(4)*a**S(4)) + sqrt(Pi)*Erf(S(2)*sqrt(asinh(a*x)))/(S(4)*a**S(4)) - sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(4)*a**S(4)) + sqrt(Pi)*Erfi(S(2)*sqrt(asinh(a*x)))/(S(4)*a**S(4)) - S(2)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(a*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asinh(a*x)**(S(3)/2), x), x, -sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(4)*a**S(3)) + sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(4)*a**S(3)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(4)*a**S(3)) - sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(4)*a**S(3)) - S(2)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(a*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asinh(a*x)**(S(3)/2), x), x, sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(2)*a**S(2)) + sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(2)*a**S(2)) - S(2)*x*sqrt(a**S(2)*x**S(2) + S(1))/(a*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(-3)/2), x), x, -sqrt(Pi)*Erf(sqrt(asinh(a*x)))/a + sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/a - S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(a*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asinh(a*x)**(S(3)/2)), x), x, Integrate(S(1)/(x*asinh(a*x)**(S(3)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asinh(a*x)**(S(5)/2), x), x, -S(3)*sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(8)*a**S(5)) + S(5)*sqrt(S(5))*sqrt(Pi)*Erf(sqrt(S(5))*sqrt(asinh(a*x)))/(S(24)*a**S(5)) + sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(12)*a**S(5)) - S(3)*sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(8)*a**S(5)) + S(5)*sqrt(S(5))*sqrt(Pi)*Erfi(sqrt(S(5))*sqrt(asinh(a*x)))/(S(24)*a**S(5)) + sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(12)*a**S(5)) - S(20)*x**S(5)/(S(3)*sqrt(asinh(a*x))) - S(2)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**(S(3)/2)) - S(16)*x**S(3)/(S(3)*a**S(2)*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asinh(a*x)**(S(5)/2), x), x, sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(3)*a**S(4)) - S(2)*sqrt(Pi)*Erf(S(2)*sqrt(asinh(a*x)))/(S(3)*a**S(4)) - sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(3)*a**S(4)) + S(2)*sqrt(Pi)*Erfi(S(2)*sqrt(asinh(a*x)))/(S(3)*a**S(4)) - S(16)*x**S(4)/(S(3)*sqrt(asinh(a*x))) - S(2)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**(S(3)/2)) - S(4)*x**S(2)/(a**S(2)*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asinh(a*x)**(S(5)/2), x), x, sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(2)*a**S(3)) - sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(6)*a**S(3)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(2)*a**S(3)) - sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(6)*a**S(3)) - S(4)*x**S(3)/sqrt(asinh(a*x)) - S(2)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**(S(3)/2)) - S(8)*x/(S(3)*a**S(2)*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asinh(a*x)**(S(5)/2), x), x, -S(2)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(3)*a**S(2)) + S(2)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(3)*a**S(2)) - S(8)*x**S(2)/(S(3)*sqrt(asinh(a*x))) - S(2)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**(S(3)/2)) - S(4)/(S(3)*a**S(2)*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(-5)/2), x), x, S(2)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(3)*a) + S(2)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(3)*a) - S(4)*x/(S(3)*sqrt(asinh(a*x))) - S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*asinh(a*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asinh(a*x)**(S(5)/2)), x), x, Integrate(S(1)/(x*asinh(a*x)**(S(5)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asinh(a*x)**(S(7)/2), x), x, S(9)*sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(20)*a**S(5)) - S(5)*sqrt(S(5))*sqrt(Pi)*Erf(sqrt(S(5))*sqrt(asinh(a*x)))/(S(12)*a**S(5)) - sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(30)*a**S(5)) - S(9)*sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(20)*a**S(5)) + S(5)*sqrt(S(5))*sqrt(Pi)*Erfi(sqrt(S(5))*sqrt(asinh(a*x)))/(S(12)*a**S(5)) + sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(30)*a**S(5)) - S(4)*x**S(5)/(S(3)*asinh(a*x)**(S(3)/2)) - S(40)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(S(3)*a*sqrt(asinh(a*x))) - S(2)*x**S(4)*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a*asinh(a*x)**(S(5)/2)) - S(16)*x**S(3)/(S(15)*a**S(2)*asinh(a*x)**(S(3)/2)) - S(32)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a**S(3)*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asinh(a*x)**(S(7)/2), x), x, -S(4)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(15)*a**S(4)) + S(16)*sqrt(Pi)*Erf(S(2)*sqrt(asinh(a*x)))/(S(15)*a**S(4)) - S(4)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(15)*a**S(4)) + S(16)*sqrt(Pi)*Erfi(S(2)*sqrt(asinh(a*x)))/(S(15)*a**S(4)) - S(16)*x**S(4)/(S(15)*asinh(a*x)**(S(3)/2)) - S(128)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(15)*a*sqrt(asinh(a*x))) - S(2)*x**S(3)*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a*asinh(a*x)**(S(5)/2)) - S(4)*x**S(2)/(S(5)*a**S(2)*asinh(a*x)**(S(3)/2)) - S(16)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a**S(3)*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asinh(a*x)**(S(7)/2), x), x, -S(3)*sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(asinh(a*x)))/(S(5)*a**S(3)) + sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(15)*a**S(3)) + S(3)*sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(asinh(a*x)))/(S(5)*a**S(3)) - sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(15)*a**S(3)) - S(4)*x**S(3)/(S(5)*asinh(a*x)**(S(3)/2)) - S(24)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a*sqrt(asinh(a*x))) - S(2)*x**S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a*asinh(a*x)**(S(5)/2)) - S(8)*x/(S(15)*a**S(2)*asinh(a*x)**(S(3)/2)) - S(16)*sqrt(a**S(2)*x**S(2) + S(1))/(S(15)*a**S(3)*sqrt(asinh(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asinh(a*x)**(S(7)/2), x), x, S(8)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(asinh(a*x)))/(S(15)*a**S(2)) + S(8)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(asinh(a*x)))/(S(15)*a**S(2)) - S(8)*x**S(2)/(S(15)*asinh(a*x)**(S(3)/2)) - S(32)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(15)*a*sqrt(asinh(a*x))) - S(2)*x*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a*asinh(a*x)**(S(5)/2)) - S(4)/(S(15)*a**S(2)*asinh(a*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**(S(-7)/2), x), x, -S(4)*sqrt(Pi)*Erf(sqrt(asinh(a*x)))/(S(15)*a) + S(4)*sqrt(Pi)*Erfi(sqrt(asinh(a*x)))/(S(15)*a) - S(4)*x/(S(15)*asinh(a*x)**(S(3)/2)) - S(8)*sqrt(a**S(2)*x**S(2) + S(1))/(S(15)*a*sqrt(asinh(a*x))) - S(2)*sqrt(a**S(2)*x**S(2) + S(1))/(S(5)*a*asinh(a*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asinh(a*x)**(S(7)/2)), x), x, Integrate(S(1)/(x*asinh(a*x)**(S(7)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*asinh(a*x)**S(4), x), x, -S(4)*a*Integrate(x**(m + S(1))*asinh(a*x)**S(3)/sqrt(a**S(2)*x**S(2) + S(1)), x)/(m + S(1)) + x**(m + S(1))*asinh(a*x)**S(4)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*asinh(a*x)**S(3), x), x, -S(3)*a*Integrate(x**(m + S(1))*asinh(a*x)**S(2)/sqrt(a**S(2)*x**S(2) + S(1)), x)/(m + S(1)) + x**(m + S(1))*asinh(a*x)**S(3)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*asinh(a*x)**S(2), x), x, S(2)*a**S(2)*x**(m + S(3))*HypergeometricPFQ(List(S(1), m/S(2) + S(3)/2, m/S(2) + S(3)/2), List(m/S(2) + S(2), m/S(2) + S(5)/2), -a**S(2)*x**S(2))/(m**S(3) + S(6)*m**S(2) + S(11)*m + S(6)) - S(2)*a*x**(m + S(2))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1), m/S(2) + S(2), -a**S(2)*x**S(2))*asinh(a*x)/(m**S(2) + S(3)*m + S(2)) + x**(m + S(1))*asinh(a*x)**S(2)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*asinh(a*x), x), x, -a*x**(m + S(2))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1), m/S(2) + S(2), -a**S(2)*x**S(2))/(m**S(2) + S(3)*m + S(2)) + x**(m + S(1))*asinh(a*x)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/asinh(a*x), x), x, Integrate(x**m/asinh(a*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/asinh(a*x)**S(2), x), x, Integrate(x**m/asinh(a*x)**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*asinh(a*x)**(S(5)/2), x), x, Integrate(x**m*asinh(a*x)**(S(5)/2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*asinh(a*x)**(S(3)/2), x), x, Integrate(x**m*asinh(a*x)**(S(3)/2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(asinh(a*x)), x), x, Integrate(x**m*sqrt(asinh(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/sqrt(asinh(a*x)), x), x, Integrate(x**m/sqrt(asinh(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/asinh(a*x)**(S(3)/2), x), x, Integrate(x**m/asinh(a*x)**(S(3)/2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*asinh(a*x)**n, x), x, Integrate((b*x)**m*asinh(a*x)**n, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asinh(a*x)**n, x), x, -S(5)**(-n + S(-1))*Gamma(n + S(1), S(5)*asinh(a*x))/(S(32)*a**S(5)) + S(5)**(-n + S(-1))*(-asinh(a*x))**(-n)*Gamma(n + S(1), -S(5)*asinh(a*x))*asinh(a*x)**n/(S(32)*a**S(5)) - Gamma(n + S(1), asinh(a*x))/(S(16)*a**S(5)) + (-asinh(a*x))**(-n)*Gamma(n + S(1), -asinh(a*x))*asinh(a*x)**n/(S(16)*a**S(5)) + S(3)**(-n)*Gamma(n + S(1), S(3)*asinh(a*x))/(S(32)*a**S(5)) - S(3)**(-n)*(-asinh(a*x))**(-n)*Gamma(n + S(1), -S(3)*asinh(a*x))*asinh(a*x)**n/(S(32)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asinh(a*x)**n, x), x, -S(3)**(-n + S(-1))*Gamma(n + S(1), S(3)*asinh(a*x))/(S(8)*a**S(3)) + S(3)**(-n + S(-1))*(-asinh(a*x))**(-n)*Gamma(n + S(1), -S(3)*asinh(a*x))*asinh(a*x)**n/(S(8)*a**S(3)) + Gamma(n + S(1), asinh(a*x))/(S(8)*a**S(3)) - (-asinh(a*x))**(-n)*Gamma(n + S(1), -asinh(a*x))*asinh(a*x)**n/(S(8)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asinh(a*x)**n, x), x, S(2)**(-n + S(-3))*Gamma(n + S(1), S(2)*asinh(a*x))/a**S(2) + S(2)**(-n + S(-3))*(-asinh(a*x))**(-n)*Gamma(n + S(1), -S(2)*asinh(a*x))*asinh(a*x)**n/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**n, x), x, -Gamma(n + S(1), asinh(a*x))/(S(2)*a) + (-asinh(a*x))**(-n)*Gamma(n + S(1), -asinh(a*x))*asinh(a*x)**n/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**n/x, x), x, Integrate(asinh(a*x)**n/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asinh(a*x)**n/x**S(2), x), x, Integrate(asinh(a*x)**n/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a + b*asinh(c*x)), x), x, -sqrt(Pi)*sqrt(b)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(16)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*sqrt(b)*Erf(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(3)*a/b)/(S(144)*c**S(3)) + sqrt(Pi)*sqrt(b)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(16)*c**S(3)) - sqrt(S(3))*sqrt(Pi)*sqrt(b)*Erfi(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(3)*a/b)/(S(144)*c**S(3)) + x**S(3)*sqrt(a + b*asinh(c*x))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*asinh(c*x)), x), x, -sqrt(S(2))*sqrt(Pi)*sqrt(b)*Erf(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(2)*a/b)/(S(32)*c**S(2)) - sqrt(S(2))*sqrt(Pi)*sqrt(b)*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(2)*a/b)/(S(32)*c**S(2)) + x**S(2)*sqrt(a + b*asinh(c*x))/S(2) + sqrt(a + b*asinh(c*x))/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*asinh(c*x)), x), x, sqrt(Pi)*sqrt(b)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(4)*c) - sqrt(Pi)*sqrt(b)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(4)*c) + x*sqrt(a + b*asinh(c*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*asinh(c*x))**(S(3)/2), x), x, -S(3)*sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(32)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(3)*a/b)/(S(288)*c**S(3)) - S(3)*sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(32)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(3)*a/b)/(S(288)*c**S(3)) - b*x**S(2)*sqrt(a + b*asinh(c*x))*sqrt(c**S(2)*x**S(2) + S(1))/(S(6)*c) + b*sqrt(a + b*asinh(c*x))*sqrt(c**S(2)*x**S(2) + S(1))/(S(3)*c**S(3)) + x**S(3)*(a + b*asinh(c*x))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*asinh(c*x))**(S(3)/2), x), x, -S(3)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(2)*a/b)/(S(128)*c**S(2)) + S(3)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(2)*a/b)/(S(128)*c**S(2)) - S(3)*b*x*sqrt(a + b*asinh(c*x))*sqrt(c**S(2)*x**S(2) + S(1))/(S(8)*c) + x**S(2)*(a + b*asinh(c*x))**(S(3)/2)/S(2) + (a + b*asinh(c*x))**(S(3)/2)/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asinh(c*x))**(S(3)/2), x), x, S(3)*sqrt(Pi)*b**(S(3)/2)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(8)*c) + S(3)*sqrt(Pi)*b**(S(3)/2)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(8)*c) - S(3)*b*sqrt(a + b*asinh(c*x))*sqrt(c**S(2)*x**S(2) + S(1))/(S(2)*c) + x*(a + b*asinh(c*x))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*asinh(c*x))**(S(5)/2), x), x, -S(15)*sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(64)*c**S(3)) + S(5)*sqrt(S(3))*sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(3)*a/b)/(S(1728)*c**S(3)) + S(15)*sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(64)*c**S(3)) - S(5)*sqrt(S(3))*sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(3)*a/b)/(S(1728)*c**S(3)) + S(5)*b**S(2)*x**S(3)*sqrt(a + b*asinh(c*x))/S(36) - S(5)*b**S(2)*x*sqrt(a + b*asinh(c*x))/(S(6)*c**S(2)) - S(5)*b*x**S(2)*(a + b*asinh(c*x))**(S(3)/2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(18)*c) + S(5)*b*(a + b*asinh(c*x))**(S(3)/2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(9)*c**S(3)) + x**S(3)*(a + b*asinh(c*x))**(S(5)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*asinh(c*x))**(S(5)/2), x), x, -S(15)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(2)*a/b)/(S(512)*c**S(2)) - S(15)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(2)*a/b)/(S(512)*c**S(2)) + S(15)*b**S(2)*x**S(2)*sqrt(a + b*asinh(c*x))/S(32) + S(15)*b**S(2)*sqrt(a + b*asinh(c*x))/(S(64)*c**S(2)) - S(5)*b*x*(a + b*asinh(c*x))**(S(3)/2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(8)*c) + x**S(2)*(a + b*asinh(c*x))**(S(5)/2)/S(2) + (a + b*asinh(c*x))**(S(5)/2)/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asinh(c*x))**(S(5)/2), x), x, S(15)*sqrt(Pi)*b**(S(5)/2)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(16)*c) - S(15)*sqrt(Pi)*b**(S(5)/2)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(16)*c) + S(15)*b**S(2)*x*sqrt(a + b*asinh(c*x))/S(4) - S(5)*b*(a + b*asinh(c*x))**(S(3)/2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(2)*c) + x*(a + b*asinh(c*x))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*asinh(c*x)), x), x, -sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(8)*sqrt(b)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(3)*a/b)/(S(24)*sqrt(b)*c**S(3)) - sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(8)*sqrt(b)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(3)*a/b)/(S(24)*sqrt(b)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*asinh(c*x)), x), x, -sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(2)*a/b)/(S(8)*sqrt(b)*c**S(2)) + sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(2)*a/b)/(S(8)*sqrt(b)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*asinh(c*x)), x), x, sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(2)*sqrt(b)*c) + sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(2)*sqrt(b)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asinh(c*x))**(S(3)/2), x), x, sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(4)*b**(S(3)/2)*c**S(3)) - sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(3)*a/b)/(S(4)*b**(S(3)/2)*c**S(3)) - sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(4)*b**(S(3)/2)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(3)*a/b)/(S(4)*b**(S(3)/2)*c**S(3)) - S(2)*x**S(2)*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asinh(c*x))**(S(3)/2), x), x, sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(2)*a/b)/(S(2)*b**(S(3)/2)*c**S(2)) + sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(2)*a/b)/(S(2)*b**(S(3)/2)*c**S(2)) - S(2)*x*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asinh(c*x))**(S(-3)/2), x), x, -sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(b**(S(3)/2)*c) + sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(b**(S(3)/2)*c) - S(2)*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asinh(c*x))**(S(5)/2), x), x, -sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(6)*b**(S(5)/2)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(3)*a/b)/(S(2)*b**(S(5)/2)*c**S(3)) - sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(6)*b**(S(5)/2)*c**S(3)) + sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(3)*a/b)/(S(2)*b**(S(5)/2)*c**S(3)) - S(2)*x**S(2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(3)*b*c*(a + b*asinh(c*x))**(S(3)/2)) - S(4)*x**S(3)/(b**S(2)*sqrt(a + b*asinh(c*x))) - S(8)*x/(S(3)*b**S(2)*c**S(2)*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asinh(c*x))**(S(5)/2), x), x, -S(2)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(2)*a/b)/(S(3)*b**(S(5)/2)*c**S(2)) + S(2)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(2)*a/b)/(S(3)*b**(S(5)/2)*c**S(2)) - S(2)*x*sqrt(c**S(2)*x**S(2) + S(1))/(S(3)*b*c*(a + b*asinh(c*x))**(S(3)/2)) - S(8)*x**S(2)/(S(3)*b**S(2)*sqrt(a + b*asinh(c*x))) - S(4)/(S(3)*b**S(2)*c**S(2)*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asinh(c*x))**(S(-5)/2), x), x, S(2)*sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(3)*b**(S(5)/2)*c) + S(2)*sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(3)*b**(S(5)/2)*c) - S(2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(3)*b*c*(a + b*asinh(c*x))**(S(3)/2)) - S(4)*x/(S(3)*b**S(2)*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asinh(c*x))**(S(7)/2), x), x, sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(15)*b**(S(7)/2)*c**S(3)) - S(3)*sqrt(S(3))*sqrt(Pi)*Erf(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(3)*a/b)/(S(5)*b**(S(7)/2)*c**S(3)) - sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(15)*b**(S(7)/2)*c**S(3)) + S(3)*sqrt(S(3))*sqrt(Pi)*Erfi(sqrt(S(3))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(3)*a/b)/(S(5)*b**(S(7)/2)*c**S(3)) - S(2)*x**S(2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(5)*b*c*(a + b*asinh(c*x))**(S(5)/2)) - S(4)*x**S(3)/(S(5)*b**S(2)*(a + b*asinh(c*x))**(S(3)/2)) - S(8)*x/(S(15)*b**S(2)*c**S(2)*(a + b*asinh(c*x))**(S(3)/2)) - S(24)*x**S(2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(5)*b**S(3)*c*sqrt(a + b*asinh(c*x))) - S(16)*sqrt(c**S(2)*x**S(2) + S(1))/(S(15)*b**S(3)*c**S(3)*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asinh(c*x))**(S(7)/2), x), x, S(8)*sqrt(S(2))*sqrt(Pi)*Erf(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(S(2)*a/b)/(S(15)*b**(S(7)/2)*c**S(2)) + S(8)*sqrt(S(2))*sqrt(Pi)*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-S(2)*a/b)/(S(15)*b**(S(7)/2)*c**S(2)) - S(2)*x*sqrt(c**S(2)*x**S(2) + S(1))/(S(5)*b*c*(a + b*asinh(c*x))**(S(5)/2)) - S(8)*x**S(2)/(S(15)*b**S(2)*(a + b*asinh(c*x))**(S(3)/2)) - S(4)/(S(15)*b**S(2)*c**S(2)*(a + b*asinh(c*x))**(S(3)/2)) - S(32)*x*sqrt(c**S(2)*x**S(2) + S(1))/(S(15)*b**S(3)*c*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asinh(c*x))**(S(-7)/2), x), x, -S(4)*sqrt(Pi)*Erf(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(a/b)/(S(15)*b**(S(7)/2)*c) + S(4)*sqrt(Pi)*Erfi(sqrt(a + b*asinh(c*x))/sqrt(b))*exp(-a/b)/(S(15)*b**(S(7)/2)*c) - S(2)*sqrt(c**S(2)*x**S(2) + S(1))/(S(5)*b*c*(a + b*asinh(c*x))**(S(5)/2)) - S(4)*x/(S(15)*b**S(2)*(a + b*asinh(c*x))**(S(3)/2)) - S(8)*sqrt(c**S(2)*x**S(2) + S(1))/(S(15)*b**S(3)*c*sqrt(a + b*asinh(c*x))), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_inverse_sine.py000066400000000000000000002443561412543434000275020ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.utility_function import ( sympy_op_factory, Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ ) from sympy import (Integral, Integral as Integrate, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf, exp, log) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec) from sympy import pi as Pi from sympy.integrals.rubi.rubi import rubi_integrate a, b, c, d, e, f, m, n, x, u , k, p, r, s, t, i, j= symbols('a b c d e f m n x u k p r s t i j') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F', ) def test_1(): assert rubi_test(rubi_integrate(x**S(4)*asin(a*x), x), x, x**S(5)*asin(a*x)/S(5) + (-a**S(2)*x**S(2) + S(1))**(S(5)/2)/(S(25)*a**S(5)) - S(2)*(-a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(15)*a**S(5)) + sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asin(a*x), x), x, x**S(4)*asin(a*x)/S(4) + x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(16)*a) + S(3)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(32)*a**S(3)) - S(3)*asin(a*x)/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asin(a*x), x), x, x**S(3)*asin(a*x)/S(3) - (-a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(9)*a**S(3)) + sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asin(a*x), x), x, x**S(2)*asin(a*x)/S(2) + x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(4)*a) - asin(a*x)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x), x), x, x*asin(a*x) + sqrt(-a**S(2)*x**S(2) + S(1))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)/x, x), x, -I*PolyLog(S(2), exp(S(2)*I*asin(a*x)))/S(2) + log(-exp(S(2)*I*asin(a*x)) + S(1))*asin(a*x) - I*asin(a*x)**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)/x**S(2), x), x, -a*atanh(sqrt(-a**S(2)*x**S(2) + S(1))) - asin(a*x)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)/x**S(3), x), x, -a*sqrt(-a**S(2)*x**S(2) + S(1))/(S(2)*x) - asin(a*x)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)/x**S(4), x), x, -a**S(3)*atanh(sqrt(-a**S(2)*x**S(2) + S(1)))/S(6) - a*sqrt(-a**S(2)*x**S(2) + S(1))/(S(6)*x**S(2)) - asin(a*x)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)/x**S(5), x), x, -a**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(6)*x) - a*sqrt(-a**S(2)*x**S(2) + S(1))/(S(12)*x**S(3)) - asin(a*x)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)/x**S(6), x), x, -S(3)*a**S(5)*atanh(sqrt(-a**S(2)*x**S(2) + S(1)))/S(40) - S(3)*a**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(40)*x**S(2)) - a*sqrt(-a**S(2)*x**S(2) + S(1))/(S(20)*x**S(4)) - asin(a*x)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asin(a*x)**S(2), x), x, x**S(5)*asin(a*x)**S(2)/S(5) - S(2)*x**S(5)/S(125) + S(2)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(25)*a) - S(8)*x**S(3)/(S(225)*a**S(2)) + S(8)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(75)*a**S(3)) - S(16)*x/(S(75)*a**S(4)) + S(16)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(75)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asin(a*x)**S(2), x), x, x**S(4)*asin(a*x)**S(2)/S(4) - x**S(4)/S(32) + x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(8)*a) - S(3)*x**S(2)/(S(32)*a**S(2)) + S(3)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(16)*a**S(3)) - S(3)*asin(a*x)**S(2)/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asin(a*x)**S(2), x), x, x**S(3)*asin(a*x)**S(2)/S(3) - S(2)*x**S(3)/S(27) + S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(9)*a) - S(4)*x/(S(9)*a**S(2)) + S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(9)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asin(a*x)**S(2), x), x, x**S(2)*asin(a*x)**S(2)/S(2) - x**S(2)/S(4) + x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(2)*a) - asin(a*x)**S(2)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(2), x), x, x*asin(a*x)**S(2) - S(2)*x + S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(2)/x, x), x, -I*PolyLog(S(2), exp(S(2)*I*asin(a*x)))*asin(a*x) + PolyLog(S(3), exp(S(2)*I*asin(a*x)))/S(2) + log(-exp(S(2)*I*asin(a*x)) + S(1))*asin(a*x)**S(2) - I*asin(a*x)**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(2)/x**S(2), x), x, S(2)*I*a*PolyLog(S(2), -exp(I*asin(a*x))) - S(2)*I*a*PolyLog(S(2), exp(I*asin(a*x))) - S(4)*a*asin(a*x)*atanh(exp(I*asin(a*x))) - asin(a*x)**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(2)/x**S(3), x), x, a**S(2)*log(x) - a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/x - asin(a*x)**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) # sympy and mathematica assert rubi_test(rubi_integrate(asin(a*x)**S(2)/x**S(4), x), x, I*a**S(3)*PolyLog(S(2), -exp(I*asin(a*x)))/S(3) - I*a**S(3)*PolyLog(S(2), exp(I*asin(a*x)))/S(3) - S(2)*a**S(3)*asin(a*x)*atanh(exp(I*asin(a*x)))/S(3) - a**S(2)/(S(3)*x) - a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(3)*x**S(2)) - asin(a*x)**S(2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(2)/x**S(5), x), x, a**S(4)*log(x)/S(3) - a**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(3)*x) - a**S(2)/(S(12)*x**S(2)) - a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(6)*x**S(3)) - asin(a*x)**S(2)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asin(a*x)**S(3), x), x, x**S(5)*asin(a*x)**S(3)/S(5) - S(6)*x**S(5)*asin(a*x)/S(125) + S(3)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(25)*a) - S(8)*x**S(3)*asin(a*x)/(S(75)*a**S(2)) + S(4)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(25)*a**S(3)) - S(16)*x*asin(a*x)/(S(25)*a**S(4)) - S(6)*(-a**S(2)*x**S(2) + S(1))**(S(5)/2)/(S(625)*a**S(5)) + S(76)*(-a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(1125)*a**S(5)) + S(8)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(25)*a**S(5)) - S(298)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(375)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asin(a*x)**S(3), x), x, x**S(4)*asin(a*x)**S(3)/S(4) - S(3)*x**S(4)*asin(a*x)/S(32) + S(3)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(16)*a) - S(3)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(128)*a) - S(9)*x**S(2)*asin(a*x)/(S(32)*a**S(2)) + S(9)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(32)*a**S(3)) - S(45)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(256)*a**S(3)) - S(3)*asin(a*x)**S(3)/(S(32)*a**S(4)) + S(45)*asin(a*x)/(S(256)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asin(a*x)**S(3), x), x, x**S(3)*asin(a*x)**S(3)/S(3) - S(2)*x**S(3)*asin(a*x)/S(9) + x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(3)*a) - S(4)*x*asin(a*x)/(S(3)*a**S(2)) + S(2)*(-a**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(27)*a**S(3)) + S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(3)*a**S(3)) - S(14)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(9)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asin(a*x)**S(3), x), x, x**S(2)*asin(a*x)**S(3)/S(2) - S(3)*x**S(2)*asin(a*x)/S(4) + S(3)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(4)*a) - S(3)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(8)*a) - asin(a*x)**S(3)/(S(4)*a**S(2)) + S(3)*asin(a*x)/(S(8)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(3), x), x, x*asin(a*x)**S(3) - S(6)*x*asin(a*x) + S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/a - S(6)*sqrt(-a**S(2)*x**S(2) + S(1))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(3)/x, x), x, -S(3)*I*PolyLog(S(2), exp(S(2)*I*asin(a*x)))*asin(a*x)**S(2)/S(2) + S(3)*PolyLog(S(3), exp(S(2)*I*asin(a*x)))*asin(a*x)/S(2) + S(3)*I*PolyLog(S(4), exp(S(2)*I*asin(a*x)))/S(4) + log(-exp(S(2)*I*asin(a*x)) + S(1))*asin(a*x)**S(3) - I*asin(a*x)**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(3)/x**S(2), x), x, S(6)*I*a*PolyLog(S(2), -exp(I*asin(a*x)))*asin(a*x) - S(6)*I*a*PolyLog(S(2), exp(I*asin(a*x)))*asin(a*x) - S(6)*a*PolyLog(S(3), -exp(I*asin(a*x))) + S(6)*a*PolyLog(S(3), exp(I*asin(a*x))) - S(6)*a*asin(a*x)**S(2)*atanh(exp(I*asin(a*x))) - asin(a*x)**S(3)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(3)/x**S(3), x), x, -S(3)*I*a**S(2)*PolyLog(S(2), exp(S(2)*I*asin(a*x)))/S(2) + S(3)*a**S(2)*log(-exp(S(2)*I*asin(a*x)) + S(1))*asin(a*x) - S(3)*I*a**S(2)*asin(a*x)**S(2)/S(2) - S(3)*a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(2)*x) - asin(a*x)**S(3)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) # sympy and mathematica assert rubi_test(rubi_integrate(asin(a*x)**S(3)/x**S(4), x), x, I*a**S(3)*PolyLog(S(2), -exp(I*asin(a*x)))*asin(a*x) - I*a**S(3)*PolyLog(S(2), exp(I*asin(a*x)))*asin(a*x) - a**S(3)*PolyLog(S(3), -exp(I*asin(a*x))) + a**S(3)*PolyLog(S(3), exp(I*asin(a*x))) - a**S(3)*asin(a*x)**S(2)*atanh(exp(I*asin(a*x))) - a**S(3)*atanh(sqrt(-a**S(2)*x**S(2) + S(1))) - a**S(2)*asin(a*x)/x - a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(2)*x**S(2)) - asin(a*x)**S(3)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(3)/x**S(5), x), x, -I*a**S(4)*PolyLog(S(2), exp(S(2)*I*asin(a*x)))/S(2) + a**S(4)*log(-exp(S(2)*I*asin(a*x)) + S(1))*asin(a*x) - I*a**S(4)*asin(a*x)**S(2)/S(2) - a**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(2)*x) - a**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(4)*x) - a**S(2)*asin(a*x)/(S(4)*x**S(2)) - a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(2)/(S(4)*x**S(3)) - asin(a*x)**S(3)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*asin(a*x)**S(4), x), x, x**S(6)*asin(a*x)**S(4)/S(6) - x**S(6)*asin(a*x)**S(2)/S(18) + x**S(6)/S(324) + x**S(5)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(9)*a) - x**S(5)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(54)*a) - S(5)*x**S(4)*asin(a*x)**S(2)/(S(48)*a**S(2)) + S(65)*x**S(4)/(S(3456)*a**S(2)) + S(5)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(36)*a**S(3)) - S(65)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(864)*a**S(3)) - S(5)*x**S(2)*asin(a*x)**S(2)/(S(16)*a**S(4)) + S(245)*x**S(2)/(S(1152)*a**S(4)) + S(5)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(24)*a**S(5)) - S(245)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(576)*a**S(5)) - S(5)*asin(a*x)**S(4)/(S(96)*a**S(6)) + S(245)*asin(a*x)**S(2)/(S(1152)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asin(a*x)**S(4), x), x, x**S(5)*asin(a*x)**S(4)/S(5) - S(12)*x**S(5)*asin(a*x)**S(2)/S(125) + S(24)*x**S(5)/S(3125) + S(4)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(25)*a) - S(24)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(625)*a) - S(16)*x**S(3)*asin(a*x)**S(2)/(S(75)*a**S(2)) + S(1088)*x**S(3)/(S(16875)*a**S(2)) + S(16)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(75)*a**S(3)) - S(1088)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(5625)*a**S(3)) - S(32)*x*asin(a*x)**S(2)/(S(25)*a**S(4)) + S(16576)*x/(S(5625)*a**S(4)) + S(32)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(75)*a**S(5)) - S(16576)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(5625)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asin(a*x)**S(4), x), x, x**S(4)*asin(a*x)**S(4)/S(4) - S(3)*x**S(4)*asin(a*x)**S(2)/S(16) + S(3)*x**S(4)/S(128) + x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(4)*a) - S(3)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(32)*a) - S(9)*x**S(2)*asin(a*x)**S(2)/(S(16)*a**S(2)) + S(45)*x**S(2)/(S(128)*a**S(2)) + S(3)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(8)*a**S(3)) - S(45)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(64)*a**S(3)) - S(3)*asin(a*x)**S(4)/(S(32)*a**S(4)) + S(45)*asin(a*x)**S(2)/(S(128)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asin(a*x)**S(4), x), x, x**S(3)*asin(a*x)**S(4)/S(3) - S(4)*x**S(3)*asin(a*x)**S(2)/S(9) + S(8)*x**S(3)/S(81) + S(4)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(9)*a) - S(8)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(27)*a) - S(8)*x*asin(a*x)**S(2)/(S(3)*a**S(2)) + S(160)*x/(S(27)*a**S(2)) + S(8)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(9)*a**S(3)) - S(160)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(27)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asin(a*x)**S(4), x), x, x**S(2)*asin(a*x)**S(4)/S(2) - S(3)*x**S(2)*asin(a*x)**S(2)/S(2) + S(3)*x**S(2)/S(4) + x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/a - S(3)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/(S(2)*a) - asin(a*x)**S(4)/(S(4)*a**S(2)) + S(3)*asin(a*x)**S(2)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(4), x), x, x*asin(a*x)**S(4) - S(12)*x*asin(a*x)**S(2) + S(24)*x + S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/a - S(24)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(4)/x, x), x, -S(2)*I*PolyLog(S(2), exp(S(2)*I*asin(a*x)))*asin(a*x)**S(3) + S(3)*PolyLog(S(3), exp(S(2)*I*asin(a*x)))*asin(a*x)**S(2) + S(3)*I*PolyLog(S(4), exp(S(2)*I*asin(a*x)))*asin(a*x) - S(3)*PolyLog(S(5), exp(S(2)*I*asin(a*x)))/S(2) + log(-exp(S(2)*I*asin(a*x)) + S(1))*asin(a*x)**S(4) - I*asin(a*x)**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(4)/x**S(2), x), x, S(12)*I*a*PolyLog(S(2), -exp(I*asin(a*x)))*asin(a*x)**S(2) - S(12)*I*a*PolyLog(S(2), exp(I*asin(a*x)))*asin(a*x)**S(2) - S(24)*a*PolyLog(S(3), -exp(I*asin(a*x)))*asin(a*x) + S(24)*a*PolyLog(S(3), exp(I*asin(a*x)))*asin(a*x) - S(24)*I*a*PolyLog(S(4), -exp(I*asin(a*x))) + S(24)*I*a*PolyLog(S(4), exp(I*asin(a*x))) - S(8)*a*asin(a*x)**S(3)*atanh(exp(I*asin(a*x))) - asin(a*x)**S(4)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(4)/x**S(3), x), x, -S(6)*I*a**S(2)*PolyLog(S(2), exp(S(2)*I*asin(a*x)))*asin(a*x) + S(3)*a**S(2)*PolyLog(S(3), exp(S(2)*I*asin(a*x))) + S(6)*a**S(2)*log(-exp(S(2)*I*asin(a*x)) + S(1))*asin(a*x)**S(2) - S(2)*I*a**S(2)*asin(a*x)**S(3) - S(2)*a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/x - asin(a*x)**S(4)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**S(4)/x**S(4), x), x, S(2)*I*a**S(3)*PolyLog(S(2), -exp(I*asin(a*x)))*asin(a*x)**S(2) + S(4)*I*a**S(3)*PolyLog(S(2), -exp(I*asin(a*x))) - S(2)*I*a**S(3)*PolyLog(S(2), exp(I*asin(a*x)))*asin(a*x)**S(2) - S(4)*I*a**S(3)*PolyLog(S(2), exp(I*asin(a*x))) - S(4)*a**S(3)*PolyLog(S(3), -exp(I*asin(a*x)))*asin(a*x) + S(4)*a**S(3)*PolyLog(S(3), exp(I*asin(a*x)))*asin(a*x) - S(4)*I*a**S(3)*PolyLog(S(4), -exp(I*asin(a*x))) + S(4)*I*a**S(3)*PolyLog(S(4), exp(I*asin(a*x))) - S(4)*a**S(3)*asin(a*x)**S(3)*atanh(exp(I*asin(a*x)))/S(3) - S(8)*a**S(3)*asin(a*x)*atanh(exp(I*asin(a*x))) - S(2)*a**S(2)*asin(a*x)**S(2)/x - S(2)*a*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**S(3)/(S(3)*x**S(2)) - asin(a*x)**S(4)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/asin(a*x), x), x, S(5)*CosIntegral(asin(a*x))/(S(64)*a**S(7)) - S(9)*CosIntegral(S(3)*asin(a*x))/(S(64)*a**S(7)) + S(5)*CosIntegral(S(5)*asin(a*x))/(S(64)*a**S(7)) - CosIntegral(S(7)*asin(a*x))/(S(64)*a**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/asin(a*x), x), x, S(5)*SinIntegral(S(2)*asin(a*x))/(S(32)*a**S(6)) - SinIntegral(S(4)*asin(a*x))/(S(8)*a**S(6)) + SinIntegral(S(6)*asin(a*x))/(S(32)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asin(a*x), x), x, CosIntegral(asin(a*x))/(S(8)*a**S(5)) - S(3)*CosIntegral(S(3)*asin(a*x))/(S(16)*a**S(5)) + CosIntegral(S(5)*asin(a*x))/(S(16)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asin(a*x), x), x, SinIntegral(S(2)*asin(a*x))/(S(4)*a**S(4)) - SinIntegral(S(4)*asin(a*x))/(S(8)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asin(a*x), x), x, CosIntegral(asin(a*x))/(S(4)*a**S(3)) - CosIntegral(S(3)*asin(a*x))/(S(4)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asin(a*x), x), x, SinIntegral(S(2)*asin(a*x))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/asin(a*x), x), x, CosIntegral(asin(a*x))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asin(a*x)), x), x, Integrate(S(1)/(x*asin(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asin(a*x)), x), x, Integrate(S(1)/(x**S(2)*asin(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/asin(a*x)**S(2), x), x, -x**S(6)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*asin(a*x)) - S(5)*SinIntegral(asin(a*x))/(S(64)*a**S(7)) + S(27)*SinIntegral(S(3)*asin(a*x))/(S(64)*a**S(7)) - S(25)*SinIntegral(S(5)*asin(a*x))/(S(64)*a**S(7)) + S(7)*SinIntegral(S(7)*asin(a*x))/(S(64)*a**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/asin(a*x)**S(2), x), x, -x**S(5)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*asin(a*x)) + S(5)*CosIntegral(S(2)*asin(a*x))/(S(16)*a**S(6)) - CosIntegral(S(4)*asin(a*x))/(S(2)*a**S(6)) + S(3)*CosIntegral(S(6)*asin(a*x))/(S(16)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asin(a*x)**S(2), x), x, -x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*asin(a*x)) - SinIntegral(asin(a*x))/(S(8)*a**S(5)) + S(9)*SinIntegral(S(3)*asin(a*x))/(S(16)*a**S(5)) - S(5)*SinIntegral(S(5)*asin(a*x))/(S(16)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asin(a*x)**S(2), x), x, -x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*asin(a*x)) + CosIntegral(S(2)*asin(a*x))/(S(2)*a**S(4)) - CosIntegral(S(4)*asin(a*x))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asin(a*x)**S(2), x), x, -x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*asin(a*x)) - SinIntegral(asin(a*x))/(S(4)*a**S(3)) + S(3)*SinIntegral(S(3)*asin(a*x))/(S(4)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asin(a*x)**S(2), x), x, -x*sqrt(-a**S(2)*x**S(2) + S(1))/(a*asin(a*x)) + CosIntegral(S(2)*asin(a*x))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(-2)), x), x, -sqrt(-a**S(2)*x**S(2) + S(1))/(a*asin(a*x)) - SinIntegral(asin(a*x))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asin(a*x)**S(2)), x), x, Integrate(S(1)/(x*asin(a*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asin(a*x)**S(2)), x), x, Integrate(S(1)/(x**S(2)*asin(a*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asin(a*x)**S(3), x), x, S(5)*x**S(5)/(S(2)*asin(a*x)) - x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(2)*a*asin(a*x)**S(2)) - S(2)*x**S(3)/(a**S(2)*asin(a*x)) - CosIntegral(asin(a*x))/(S(16)*a**S(5)) + S(27)*CosIntegral(S(3)*asin(a*x))/(S(32)*a**S(5)) - S(25)*CosIntegral(S(5)*asin(a*x))/(S(32)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asin(a*x)**S(3), x), x, S(2)*x**S(4)/asin(a*x) - x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(2)*a*asin(a*x)**S(2)) - S(3)*x**S(2)/(S(2)*a**S(2)*asin(a*x)) - SinIntegral(S(2)*asin(a*x))/(S(2)*a**S(4)) + SinIntegral(S(4)*asin(a*x))/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asin(a*x)**S(3), x), x, S(3)*x**S(3)/(S(2)*asin(a*x)) - x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(2)*a*asin(a*x)**S(2)) - x/(a**S(2)*asin(a*x)) - CosIntegral(asin(a*x))/(S(8)*a**S(3)) + S(9)*CosIntegral(S(3)*asin(a*x))/(S(8)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asin(a*x)**S(3), x), x, x**S(2)/asin(a*x) - x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(2)*a*asin(a*x)**S(2)) - SinIntegral(S(2)*asin(a*x))/a**S(2) - S(1)/(S(2)*a**S(2)*asin(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(-3)), x), x, x/(S(2)*asin(a*x)) - sqrt(-a**S(2)*x**S(2) + S(1))/(S(2)*a*asin(a*x)**S(2)) - CosIntegral(asin(a*x))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asin(a*x)**S(3)), x), x, Integrate(S(1)/(x*asin(a*x)**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asin(a*x)**S(3)), x), x, Integrate(S(1)/(x**S(2)*asin(a*x)**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asin(a*x)**S(4), x), x, S(5)*x**S(5)/(S(6)*asin(a*x)**S(2)) + S(25)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(6)*a*asin(a*x)) - x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**S(3)) - S(2)*x**S(3)/(S(3)*a**S(2)*asin(a*x)**S(2)) - S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(a**S(3)*asin(a*x)) + SinIntegral(asin(a*x))/(S(48)*a**S(5)) - S(27)*SinIntegral(S(3)*asin(a*x))/(S(32)*a**S(5)) + S(125)*SinIntegral(S(5)*asin(a*x))/(S(96)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asin(a*x)**S(4), x), x, S(2)*x**S(4)/(S(3)*asin(a*x)**S(2)) + S(8)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)) - x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**S(3)) - x**S(2)/(S(2)*a**S(2)*asin(a*x)**S(2)) - x*sqrt(-a**S(2)*x**S(2) + S(1))/(a**S(3)*asin(a*x)) - CosIntegral(S(2)*asin(a*x))/(S(3)*a**S(4)) + S(4)*CosIntegral(S(4)*asin(a*x))/(S(3)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asin(a*x)**S(4), x), x, x**S(3)/(S(2)*asin(a*x)**S(2)) + S(3)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(2)*a*asin(a*x)) - x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**S(3)) - x/(S(3)*a**S(2)*asin(a*x)**S(2)) - sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a**S(3)*asin(a*x)) + SinIntegral(asin(a*x))/(S(24)*a**S(3)) - S(9)*SinIntegral(S(3)*asin(a*x))/(S(8)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asin(a*x)**S(4), x), x, x**S(2)/(S(3)*asin(a*x)**S(2)) + S(2)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)) - x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**S(3)) - S(2)*CosIntegral(S(2)*asin(a*x))/(S(3)*a**S(2)) - S(1)/(S(6)*a**S(2)*asin(a*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(-4)), x), x, x/(S(6)*asin(a*x)**S(2)) + sqrt(-a**S(2)*x**S(2) + S(1))/(S(6)*a*asin(a*x)) - sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**S(3)) + SinIntegral(asin(a*x))/(S(6)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asin(a*x)**S(4)), x), x, Integrate(S(1)/(x*asin(a*x)**S(4)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*asin(a*x)**S(4)), x), x, Integrate(S(1)/(x**S(2)*asin(a*x)**S(4)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(asin(a*x)), x), x, -sqrt(S(10))*sqrt(Pi)*FresnelS(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(800)*a**S(5)) - sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(16)*a**S(5)) + sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(96)*a**S(5)) + x**S(5)*sqrt(asin(a*x))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(asin(a*x)), x), x, sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(16)*a**S(4)) - sqrt(S(2))*sqrt(Pi)*FresnelC(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(128)*a**S(4)) + x**S(4)*sqrt(asin(a*x))/S(4) - S(3)*sqrt(asin(a*x))/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(asin(a*x)), x), x, -sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8)*a**S(3)) + sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(72)*a**S(3)) + x**S(3)*sqrt(asin(a*x))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(asin(a*x)), x), x, sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(8)*a**S(2)) + x**S(2)*sqrt(asin(a*x))/S(2) - sqrt(asin(a*x))/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(asin(a*x)), x), x, -sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(2)*a) + x*sqrt(asin(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(asin(a*x))/x, x), x, Integrate(sqrt(asin(a*x))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asin(a*x)**(S(3)/2), x), x, -S(3)*sqrt(S(10))*sqrt(Pi)*FresnelC(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8000)*a**S(5)) - S(3)*sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(32)*a**S(5)) + sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(192)*a**S(5)) + x**S(5)*asin(a*x)**(S(3)/2)/S(5) + S(3)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(50)*a) + S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(25)*a**S(3)) + S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(25)*a**S(5)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(4)*asin(a*x)**(S(3)/2), x), x, -S(3)*sqrt(S(10))*sqrt(Pi)*FresnelC(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8000)*a**S(5)) - S(3)*sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(32)*a**S(5)) + sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(192)*a**S(5)) + x**S(5)*asin(a*x)**(S(3)/2)/S(5) + S(3)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(50)*a) + S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(25)*a**S(3)) + S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(25)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asin(a*x)**(S(3)/2), x), x, -S(3)*sqrt(Pi)*FresnelS(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(64)*a**S(4)) + S(3)*sqrt(S(2))*sqrt(Pi)*FresnelS(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(1024)*a**S(4)) + x**S(4)*asin(a*x)**(S(3)/2)/S(4) + S(3)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(32)*a) + S(9)*x*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(64)*a**S(3)) - S(3)*asin(a*x)**(S(3)/2)/(S(32)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asin(a*x)**(S(3)/2), x), x, -S(3)*sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(16)*a**S(3)) + sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(144)*a**S(3)) + x**S(3)*asin(a*x)**(S(3)/2)/S(3) + x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(6)*a) + sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(3)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asin(a*x)**(S(3)/2), x), x, -S(3)*sqrt(Pi)*FresnelS(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(32)*a**S(2)) + x**S(2)*asin(a*x)**(S(3)/2)/S(2) + S(3)*x*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(8)*a) - asin(a*x)**(S(3)/2)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(3)/2), x), x, -S(3)*sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(4)*a) + x*asin(a*x)**(S(3)/2) + S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*sqrt(asin(a*x))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(3)/2)/x, x), x, Integrate(asin(a*x)**(S(3)/2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*asin(a*x)**(S(5)/2), x), x, S(3)*sqrt(S(10))*sqrt(Pi)*FresnelS(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(16000)*a**S(5)) + S(15)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(64)*a**S(5)) - S(5)*sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(1152)*a**S(5)) + x**S(5)*asin(a*x)**(S(5)/2)/S(5) - S(3)*x**S(5)*sqrt(asin(a*x))/S(100) + x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(10)*a) - x**S(3)*sqrt(asin(a*x))/(S(15)*a**S(2)) + S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(15)*a**S(3)) - S(2)*x*sqrt(asin(a*x))/(S(5)*a**S(4)) + S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(15)*a**S(5)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(4)*asin(a*x)**(S(5)/2), x), x, S(3)*sqrt(S(10))*sqrt(Pi)*FresnelS(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(16000)*a**S(5)) + S(15)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(64)*a**S(5)) - S(5)*sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(1152)*a**S(5)) + x**S(5)*asin(a*x)**(S(5)/2)/S(5) - S(3)*x**S(5)*sqrt(asin(a*x))/S(100) + x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(10)*a) - x**S(3)*sqrt(asin(a*x))/(S(15)*a**S(2)) + S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(15)*a**S(3)) - S(2)*x*sqrt(asin(a*x))/(S(5)*a**S(4)) + S(4)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(15)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*asin(a*x)**(S(5)/2), x), x, -S(15)*sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(256)*a**S(4)) + S(15)*sqrt(S(2))*sqrt(Pi)*FresnelC(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8192)*a**S(4)) + x**S(4)*asin(a*x)**(S(5)/2)/S(4) - S(15)*x**S(4)*sqrt(asin(a*x))/S(256) + S(5)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(32)*a) - S(45)*x**S(2)*sqrt(asin(a*x))/(S(256)*a**S(2)) + S(15)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(64)*a**S(3)) - S(3)*asin(a*x)**(S(5)/2)/(S(32)*a**S(4)) + S(225)*sqrt(asin(a*x))/(S(2048)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asin(a*x)**(S(5)/2), x), x, S(15)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(32)*a**S(3)) - S(5)*sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(864)*a**S(3)) + x**S(3)*asin(a*x)**(S(5)/2)/S(3) - S(5)*x**S(3)*sqrt(asin(a*x))/S(36) + S(5)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(18)*a) - S(5)*x*sqrt(asin(a*x))/(S(6)*a**S(2)) + S(5)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(9)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asin(a*x)**(S(5)/2), x), x, -S(15)*sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(128)*a**S(2)) + x**S(2)*asin(a*x)**(S(5)/2)/S(2) - S(15)*x**S(2)*sqrt(asin(a*x))/S(32) + S(5)*x*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(8)*a) - asin(a*x)**(S(5)/2)/(S(4)*a**S(2)) + S(15)*sqrt(asin(a*x))/(S(64)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(5)/2), x), x, S(15)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8)*a) + x*asin(a*x)**(S(5)/2) - S(15)*x*sqrt(asin(a*x))/S(4) + S(5)*sqrt(-a**S(2)*x**S(2) + S(1))*asin(a*x)**(S(3)/2)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(5)/2)/x, x), x, Integrate(asin(a*x)**(S(5)/2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(asin(a*x)), x), x, sqrt(S(10))*sqrt(Pi)*FresnelC(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(80)*a**S(5)) + sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8)*a**S(5)) - sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(16)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(asin(a*x)), x), x, sqrt(Pi)*FresnelS(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(4)*a**S(4)) - sqrt(S(2))*sqrt(Pi)*FresnelS(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(16)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(asin(a*x)), x), x, sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(4)*a**S(3)) - sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(12)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(asin(a*x)), x), x, sqrt(Pi)*FresnelS(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(asin(a*x)), x), x, sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(asin(a*x))), x), x, Integrate(S(1)/(x*sqrt(asin(a*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(asin(a*x))), x), x, Integrate(S(1)/(x**S(2)*sqrt(asin(a*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/asin(a*x)**(S(3)/2), x), x, -S(5)*sqrt(S(10))*sqrt(Pi)*FresnelS(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(32)*a**S(7)) + sqrt(S(14))*sqrt(Pi)*FresnelS(sqrt(S(14))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(32)*a**S(7)) - S(5)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(32)*a**S(7)) + S(9)*sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(32)*a**S(7)) - S(2)*x**S(6)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/asin(a*x)**(S(3)/2), x), x, S(5)*sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(8)*a**S(6)) - sqrt(S(2))*sqrt(Pi)*FresnelC(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(2)*a**S(6)) + sqrt(S(3))*sqrt(Pi)*FresnelC(S(2)*sqrt(S(3))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8)*a**S(6)) - S(2)*x**S(5)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asin(a*x)**(S(3)/2), x), x, -sqrt(S(10))*sqrt(Pi)*FresnelS(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8)*a**S(5)) - sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(4)*a**S(5)) + S(3)*sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(8)*a**S(5)) - S(2)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asin(a*x)**(S(3)/2), x), x, sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/a**S(4) - sqrt(S(2))*sqrt(Pi)*FresnelC(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(2)*a**S(4)) - S(2)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asin(a*x)**(S(3)/2), x), x, -sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(2)*a**S(3)) + sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(2)*a**S(3)) - S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asin(a*x)**(S(3)/2), x), x, S(2)*sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/a**S(2) - S(2)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(a*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(-3)/2), x), x, -S(2)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/a - S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(a*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asin(a*x)**(S(3)/2)), x), x, Integrate(S(1)/(x*asin(a*x)**(S(3)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asin(a*x)**(S(5)/2), x), x, -S(5)*sqrt(S(10))*sqrt(Pi)*FresnelC(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(12)*a**S(5)) - sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(6)*a**S(5)) + S(3)*sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(4)*a**S(5)) + S(20)*x**S(5)/(S(3)*sqrt(asin(a*x))) - S(2)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**(S(3)/2)) - S(16)*x**S(3)/(S(3)*a**S(2)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(4)/asin(a*x)**(S(5)/2), x), x, -S(5)*sqrt(S(10))*sqrt(Pi)*FresnelC(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(12)*a**S(5)) - sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(6)*a**S(5)) + S(3)*sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(4)*a**S(5)) + S(20)*x**S(5)/(S(3)*sqrt(asin(a*x))) - S(2)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**(S(3)/2)) - S(16)*x**S(3)/(S(3)*a**S(2)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asin(a*x)**(S(5)/2), x), x, -S(4)*sqrt(Pi)*FresnelS(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(3)*a**S(4)) + S(4)*sqrt(S(2))*sqrt(Pi)*FresnelS(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(3)*a**S(4)) + S(16)*x**S(4)/(S(3)*sqrt(asin(a*x))) - S(2)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**(S(3)/2)) - S(4)*x**S(2)/(a**S(2)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asin(a*x)**(S(5)/2), x), x, -sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(3)*a**S(3)) + sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/a**S(3) + S(4)*x**S(3)/sqrt(asin(a*x)) - S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**(S(3)/2)) - S(8)*x/(S(3)*a**S(2)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asin(a*x)**(S(5)/2), x), x, -S(8)*sqrt(Pi)*FresnelS(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(3)*a**S(2)) + S(8)*x**S(2)/(S(3)*sqrt(asin(a*x))) - S(2)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**(S(3)/2)) - S(4)/(S(3)*a**S(2)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(-5)/2), x), x, -S(4)*sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(3)*a) + S(4)*x/(S(3)*sqrt(asin(a*x))) - S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*asin(a*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asin(a*x)**(S(5)/2)), x), x, Integrate(S(1)/(x*asin(a*x)**(S(5)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/asin(a*x)**(S(7)/2), x), x, S(5)*sqrt(S(10))*sqrt(Pi)*FresnelS(sqrt(S(10))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(6)*a**S(5)) + sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(15)*a**S(5)) - S(9)*sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(10)*a**S(5)) + S(4)*x**S(5)/(S(3)*asin(a*x)**(S(3)/2)) + S(40)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(3)*a*sqrt(asin(a*x))) - S(2)*x**S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a*asin(a*x)**(S(5)/2)) - S(16)*x**S(3)/(S(15)*a**S(2)*asin(a*x)**(S(3)/2)) - S(32)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a**S(3)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/asin(a*x)**(S(7)/2), x), x, -S(16)*sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(15)*a**S(4)) + S(32)*sqrt(S(2))*sqrt(Pi)*FresnelC(S(2)*sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(15)*a**S(4)) + S(16)*x**S(4)/(S(15)*asin(a*x)**(S(3)/2)) + S(128)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(15)*a*sqrt(asin(a*x))) - S(2)*x**S(3)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a*asin(a*x)**(S(5)/2)) - S(4)*x**S(2)/(S(5)*a**S(2)*asin(a*x)**(S(3)/2)) - S(16)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a**S(3)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/asin(a*x)**(S(7)/2), x), x, S(2)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(15)*a**S(3)) - S(6)*sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(5)*a**S(3)) + S(4)*x**S(3)/(S(5)*asin(a*x)**(S(3)/2)) + S(24)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a*sqrt(asin(a*x))) - S(2)*x**S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a*asin(a*x)**(S(5)/2)) - S(8)*x/(S(15)*a**S(2)*asin(a*x)**(S(3)/2)) - S(16)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(15)*a**S(3)*sqrt(asin(a*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/asin(a*x)**(S(7)/2), x), x, -S(32)*sqrt(Pi)*FresnelC(S(2)*sqrt(asin(a*x))/sqrt(Pi))/(S(15)*a**S(2)) + S(8)*x**S(2)/(S(15)*asin(a*x)**(S(3)/2)) + S(32)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(15)*a*sqrt(asin(a*x))) - S(2)*x*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a*asin(a*x)**(S(5)/2)) - S(4)/(S(15)*a**S(2)*asin(a*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**(S(-7)/2), x), x, S(8)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(S(1)/Pi)*sqrt(asin(a*x)))/(S(15)*a) + S(4)*x/(S(15)*asin(a*x)**(S(3)/2)) + S(8)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(15)*a*sqrt(asin(a*x))) - S(2)*sqrt(-a**S(2)*x**S(2) + S(1))/(S(5)*a*asin(a*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*asin(a*x)**(S(7)/2)), x), x, Integrate(S(1)/(x*asin(a*x)**(S(7)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*asin(a*x)**S(4), x), x, -S(4)*a*Integrate((b*x)**(m + S(1))*asin(a*x)**S(3)/sqrt(-a**S(2)*x**S(2) + S(1)), x)/(b*(m + S(1))) + (b*x)**(m + S(1))*asin(a*x)**S(4)/(b*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*asin(a*x)**S(3), x), x, -S(3)*a*Integrate((b*x)**(m + S(1))*asin(a*x)**S(2)/sqrt(-a**S(2)*x**S(2) + S(1)), x)/(b*(m + S(1))) + (b*x)**(m + S(1))*asin(a*x)**S(3)/(b*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*asin(a*x)**S(2), x), x, S(2)*a**S(2)*(b*x)**(m + S(3))*HypergeometricPFQ(List(S(1), m/S(2) + S(3)/2, m/S(2) + S(3)/2), List(m/S(2) + S(2), m/S(2) + S(5)/2), a**S(2)*x**S(2))/(b**S(3)*(m + S(1))*(m + S(2))*(m + S(3))) - S(2)*a*(b*x)**(m + S(2))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1), m/S(2) + S(2), a**S(2)*x**S(2))*asin(a*x)/(b**S(2)*(m + S(1))*(m + S(2))) + (b*x)**(m + S(1))*asin(a*x)**S(2)/(b*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*asin(a*x), x), x, -a*(b*x)**(m + S(2))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1), m/S(2) + S(2), a**S(2)*x**S(2))/(b**S(2)*(m + S(1))*(m + S(2))) + (b*x)**(m + S(1))*asin(a*x)/(b*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m/asin(a*x), x), x, Integrate((b*x)**m/asin(a*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m/asin(a*x)**S(2), x), x, Integrate((b*x)**m/asin(a*x)**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*asin(a*x)**(S(3)/2), x), x, Integrate((b*x)**m*asin(a*x)**(S(3)/2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*sqrt(asin(a*x)), x), x, Integrate((b*x)**m*sqrt(asin(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m/sqrt(asin(a*x)), x), x, Integrate((b*x)**m/sqrt(asin(a*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m/asin(a*x)**(S(3)/2), x), x, Integrate((b*x)**m/asin(a*x)**(S(3)/2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**m*asin(a*x)**n, x), x, Integrate((b*x)**m*asin(a*x)**n, x), expand=True, _diff=True, _numerical=True) # sympy and mathematicA assert rubi_test(rubi_integrate(x**S(3)*asin(a*x)**n, x), x, S(2)**(-S(2)*n + S(-6))*(-I*asin(a*x))**(-n)*Gamma(n + S(1), -S(4)*I*asin(a*x))*asin(a*x)**n/a**S(4) + S(2)**(-S(2)*n + S(-6))*(I*asin(a*x))**(-n)*Gamma(n + S(1), S(4)*I*asin(a*x))*asin(a*x)**n/a**S(4) - S(2)**(-n + S(-4))*(-I*asin(a*x))**(-n)*Gamma(n + S(1), -S(2)*I*asin(a*x))*asin(a*x)**n/a**S(4) - S(2)**(-n + S(-4))*(I*asin(a*x))**(-n)*Gamma(n + S(1), S(2)*I*asin(a*x))*asin(a*x)**n/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*asin(a*x)**n, x), x, S(3)**(-n + S(-1))*I*(-I*asin(a*x))**(-n)*Gamma(n + S(1), -S(3)*I*asin(a*x))*asin(a*x)**n/(S(8)*a**S(3)) - S(3)**(-n + S(-1))*I*(I*asin(a*x))**(-n)*Gamma(n + S(1), S(3)*I*asin(a*x))*asin(a*x)**n/(S(8)*a**S(3)) - I*(-I*asin(a*x))**(-n)*Gamma(n + S(1), -I*asin(a*x))*asin(a*x)**n/(S(8)*a**S(3)) + I*(I*asin(a*x))**(-n)*Gamma(n + S(1), I*asin(a*x))*asin(a*x)**n/(S(8)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*asin(a*x)**n, x), x, -S(2)**(-n + S(-3))*(-I*asin(a*x))**(-n)*Gamma(n + S(1), -S(2)*I*asin(a*x))*asin(a*x)**n/a**S(2) - S(2)**(-n + S(-3))*(I*asin(a*x))**(-n)*Gamma(n + S(1), S(2)*I*asin(a*x))*asin(a*x)**n/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**n, x), x, -I*(-I*asin(a*x))**(-n)*Gamma(n + S(1), -I*asin(a*x))*asin(a*x)**n/(S(2)*a) + I*(I*asin(a*x))**(-n)*Gamma(n + S(1), I*asin(a*x))*asin(a*x)**n/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**n/x, x), x, Integrate(asin(a*x)**n/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**n/x**S(2), x), x, Integrate(asin(a*x)**n/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x)**(S(3)/2)*asin(a*x)**n, x), x, Integrate((b*x)**(S(3)/2)*asin(a*x)**n, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x)*asin(a*x)**n, x), x, Integrate(sqrt(b*x)*asin(a*x)**n, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**n/sqrt(b*x), x), x, Integrate(asin(a*x)**n/sqrt(b*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(asin(a*x)**n/(b*x)**(S(3)/2), x), x, Integrate(asin(a*x)**n/(b*x)**(S(3)/2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*asin(c*x)), x), x, b*x**S(3)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(16)*c) + S(3)*b*x*sqrt(-c**S(2)*x**S(2) + S(1))/(S(32)*c**S(3)) - S(3)*b*asin(c*x)/(S(32)*c**S(4)) + x**S(4)*(a + b*asin(c*x))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*asin(c*x)), x), x, -b*(-c**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(9)*c**S(3)) + b*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*c**S(3)) + x**S(3)*(a + b*asin(c*x))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*asin(c*x)), x), x, b*x*sqrt(-c**S(2)*x**S(2) + S(1))/(S(4)*c) - b*asin(c*x)/(S(4)*c**S(2)) + x**S(2)*(a + b*asin(c*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*asin(c*x), x), x, a*x + b*x*asin(c*x) + b*sqrt(-c**S(2)*x**S(2) + S(1))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))/x, x), x, -I*b*PolyLog(S(2), exp(S(2)*I*asin(c*x)))/S(2) + (a + b*asin(c*x))*log(-exp(S(2)*I*asin(c*x)) + S(1)) - I*(a + b*asin(c*x))**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))/x**S(2), x), x, -b*c*atanh(sqrt(-c**S(2)*x**S(2) + S(1))) - (a + b*asin(c*x))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))/x**S(3), x), x, -b*c*sqrt(-c**S(2)*x**S(2) + S(1))/(S(2)*x) - (a + b*asin(c*x))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))/x**S(4), x), x, -b*c**S(3)*atanh(sqrt(-c**S(2)*x**S(2) + S(1)))/S(6) - b*c*sqrt(-c**S(2)*x**S(2) + S(1))/(S(6)*x**S(2)) - (a + b*asin(c*x))/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*asin(c*x))**S(2), x), x, -S(2)*b**S(2)*x**S(3)/S(27) - S(4)*b**S(2)*x/(S(9)*c**S(2)) + S(2)*b*x**S(2)*(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/(S(9)*c) + S(4)*b*(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/(S(9)*c**S(3)) + x**S(3)*(a + b*asin(c*x))**S(2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*asin(c*x))**S(2), x), x, -b**S(2)*x**S(2)/S(4) + b*x*(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/(S(2)*c) + x**S(2)*(a + b*asin(c*x))**S(2)/S(2) - (a + b*asin(c*x))**S(2)/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(2), x), x, -S(2)*b**S(2)*x + S(2)*b*(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/c + x*(a + b*asin(c*x))**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(2)/x, x), x, b**S(2)*PolyLog(S(3), exp(S(2)*I*asin(c*x)))/S(2) - I*b*(a + b*asin(c*x))*PolyLog(S(2), exp(S(2)*I*asin(c*x))) + (a + b*asin(c*x))**S(2)*log(-exp(S(2)*I*asin(c*x)) + S(1)) - I*(a + b*asin(c*x))**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(2)/x**S(2), x), x, S(2)*I*b**S(2)*c*PolyLog(S(2), -exp(I*asin(c*x))) - S(2)*I*b**S(2)*c*PolyLog(S(2), exp(I*asin(c*x))) - S(4)*b*c*(a + b*asin(c*x))*atanh(exp(I*asin(c*x))) - (a + b*asin(c*x))**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*asin(c*x))**S(3), x), x, -S(4)*a*b**S(2)*x/(S(3)*c**S(2)) - S(4)*b**S(3)*x*asin(c*x)/(S(3)*c**S(2)) + S(2)*b**S(3)*(-c**S(2)*x**S(2) + S(1))**(S(3)/2)/(S(27)*c**S(3)) - S(14)*b**S(3)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(9)*c**S(3)) - S(2)*b**S(2)*x**S(3)*(a + b*asin(c*x))/S(9) + b*x**S(2)*(a + b*asin(c*x))**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*c) + S(2)*b*(a + b*asin(c*x))**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*c**S(3)) + x**S(3)*(a + b*asin(c*x))**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*asin(c*x))**S(3), x), x, -S(3)*b**S(3)*x*sqrt(-c**S(2)*x**S(2) + S(1))/(S(8)*c) + S(3)*b**S(3)*asin(c*x)/(S(8)*c**S(2)) - S(3)*b**S(2)*x**S(2)*(a + b*asin(c*x))/S(4) + S(3)*b*x*(a + b*asin(c*x))**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(4)*c) + x**S(2)*(a + b*asin(c*x))**S(3)/S(2) - (a + b*asin(c*x))**S(3)/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(3), x), x, -S(6)*a*b**S(2)*x - S(6)*b**S(3)*x*asin(c*x) - S(6)*b**S(3)*sqrt(-c**S(2)*x**S(2) + S(1))/c + S(3)*b*(a + b*asin(c*x))**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/c + x*(a + b*asin(c*x))**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(3)/x, x), x, S(3)*I*b**S(3)*PolyLog(S(4), exp(S(2)*I*asin(c*x)))/S(4) + S(3)*b**S(2)*(a + b*asin(c*x))*PolyLog(S(3), exp(S(2)*I*asin(c*x)))/S(2) - S(3)*I*b*(a + b*asin(c*x))**S(2)*PolyLog(S(2), exp(S(2)*I*asin(c*x)))/S(2) + (a + b*asin(c*x))**S(3)*log(-exp(S(2)*I*asin(c*x)) + S(1)) - I*(a + b*asin(c*x))**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(3)/x**S(2), x), x, -S(6)*b**S(3)*c*PolyLog(S(3), -exp(I*asin(c*x))) + S(6)*b**S(3)*c*PolyLog(S(3), exp(I*asin(c*x))) + S(6)*I*b**S(2)*c*(a + b*asin(c*x))*PolyLog(S(2), -exp(I*asin(c*x))) - S(6)*I*b**S(2)*c*(a + b*asin(c*x))*PolyLog(S(2), exp(I*asin(c*x))) - S(6)*b*c*(a + b*asin(c*x))**S(2)*atanh(exp(I*asin(c*x))) - (a + b*asin(c*x))**S(3)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asin(c*x)), x), x, CosIntegral(a/b + asin(c*x))*cos(a/b)/(S(4)*b*c**S(3)) - CosIntegral(S(3)*a/b + S(3)*asin(c*x))*cos(S(3)*a/b)/(S(4)*b*c**S(3)) + SinIntegral(a/b + asin(c*x))*sin(a/b)/(S(4)*b*c**S(3)) - SinIntegral(S(3)*a/b + S(3)*asin(c*x))*sin(S(3)*a/b)/(S(4)*b*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asin(c*x)), x), x, -CosIntegral(S(2)*a/b + S(2)*asin(c*x))*sin(S(2)*a/b)/(S(2)*b*c**S(2)) + SinIntegral(S(2)*a/b + S(2)*asin(c*x))*cos(S(2)*a/b)/(S(2)*b*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*asin(c*x)), x), x, CosIntegral((a + b*asin(c*x))/b)*cos(a/b)/(b*c) + SinIntegral((a + b*asin(c*x))/b)*sin(a/b)/(b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*asin(c*x))), x), x, Integrate(S(1)/(x*(a + b*asin(c*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*asin(c*x))), x), x, Integrate(S(1)/(x**S(2)*(a + b*asin(c*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asin(c*x))**S(2), x), x, -x**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(a + b*asin(c*x))) + CosIntegral(a/b + asin(c*x))*sin(a/b)/(S(4)*b**S(2)*c**S(3)) - S(3)*CosIntegral(S(3)*a/b + S(3)*asin(c*x))*sin(S(3)*a/b)/(S(4)*b**S(2)*c**S(3)) - SinIntegral(a/b + asin(c*x))*cos(a/b)/(S(4)*b**S(2)*c**S(3)) + S(3)*SinIntegral(S(3)*a/b + S(3)*asin(c*x))*cos(S(3)*a/b)/(S(4)*b**S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asin(c*x))**S(2), x), x, -x*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(a + b*asin(c*x))) + CosIntegral(S(2)*a/b + S(2)*asin(c*x))*cos(S(2)*a/b)/(b**S(2)*c**S(2)) + SinIntegral(S(2)*a/b + S(2)*asin(c*x))*sin(S(2)*a/b)/(b**S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(-2)), x), x, -sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(a + b*asin(c*x))) + CosIntegral(a/b + asin(c*x))*sin(a/b)/(b**S(2)*c) - SinIntegral(a/b + asin(c*x))*cos(a/b)/(b**S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*asin(c*x))**S(2)), x), x, Integrate(S(1)/(x*(a + b*asin(c*x))**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**S(2)), x), x, Integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asin(c*x))**S(3), x), x, -x**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(2)*b*c*(a + b*asin(c*x))**S(2)) + S(3)*x**S(3)/(S(2)*b**S(2)*(a + b*asin(c*x))) - x/(b**S(2)*c**S(2)*(a + b*asin(c*x))) + CosIntegral((a + b*asin(c*x))/b)*cos(a/b)/(b**S(3)*c**S(3)) - S(9)*CosIntegral(a/b + asin(c*x))*cos(a/b)/(S(8)*b**S(3)*c**S(3)) + S(9)*CosIntegral(S(3)*a/b + S(3)*asin(c*x))*cos(S(3)*a/b)/(S(8)*b**S(3)*c**S(3)) + SinIntegral((a + b*asin(c*x))/b)*sin(a/b)/(b**S(3)*c**S(3)) - S(9)*SinIntegral(a/b + asin(c*x))*sin(a/b)/(S(8)*b**S(3)*c**S(3)) + S(9)*SinIntegral(S(3)*a/b + S(3)*asin(c*x))*sin(S(3)*a/b)/(S(8)*b**S(3)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asin(c*x))**S(3), x), x, -x*sqrt(-c**S(2)*x**S(2) + S(1))/(S(2)*b*c*(a + b*asin(c*x))**S(2)) + x**S(2)/(b**S(2)*(a + b*asin(c*x))) - S(1)/(S(2)*b**S(2)*c**S(2)*(a + b*asin(c*x))) + CosIntegral(S(2)*a/b + S(2)*asin(c*x))*sin(S(2)*a/b)/(b**S(3)*c**S(2)) - SinIntegral(S(2)*a/b + S(2)*asin(c*x))*cos(S(2)*a/b)/(b**S(3)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(-3)), x), x, -sqrt(-c**S(2)*x**S(2) + S(1))/(S(2)*b*c*(a + b*asin(c*x))**S(2)) + x/(S(2)*b**S(2)*(a + b*asin(c*x))) - CosIntegral((a + b*asin(c*x))/b)*cos(a/b)/(S(2)*b**S(3)*c) - SinIntegral((a + b*asin(c*x))/b)*sin(a/b)/(S(2)*b**S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*asin(c*x))**S(3)), x), x, Integrate(S(1)/(x*(a + b*asin(c*x))**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**S(3)), x), x, Integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a + b*asin(c*x)), x), x, sqrt(S(2))*sqrt(Pi)*sqrt(b)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(8)*c**S(3)) - sqrt(S(6))*sqrt(Pi)*sqrt(b)*FresnelC(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(S(3)*a/b)/(S(72)*c**S(3)) - sqrt(S(2))*sqrt(Pi)*sqrt(b)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(8)*c**S(3)) + sqrt(S(6))*sqrt(Pi)*sqrt(b)*FresnelS(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(S(3)*a/b)/(S(72)*c**S(3)) + x**S(3)*sqrt(a + b*asin(c*x))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*asin(c*x)), x), x, sqrt(Pi)*sqrt(b)*FresnelC(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*cos(S(2)*a/b)/(S(8)*c**S(2)) + sqrt(Pi)*sqrt(b)*FresnelS(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*sin(S(2)*a/b)/(S(8)*c**S(2)) + x**S(2)*sqrt(a + b*asin(c*x))/S(2) - sqrt(a + b*asin(c*x))/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*asin(c*x)), x), x, sqrt(S(2))*sqrt(Pi)*sqrt(b)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(2)*c) - sqrt(S(2))*sqrt(Pi)*sqrt(b)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(2)*c) + x*sqrt(a + b*asin(c*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*asin(c*x))/x, x), x, Integrate(sqrt(a + b*asin(c*x))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*asin(c*x))/x**S(2), x), x, Integrate(sqrt(a + b*asin(c*x))/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*asin(c*x))**(S(3)/2), x), x, -S(3)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(16)*c**S(3)) + sqrt(S(6))*sqrt(Pi)*b**(S(3)/2)*FresnelC(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(S(3)*a/b)/(S(144)*c**S(3)) - S(3)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(16)*c**S(3)) + sqrt(S(6))*sqrt(Pi)*b**(S(3)/2)*FresnelS(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(S(3)*a/b)/(S(144)*c**S(3)) + b*x**S(2)*sqrt(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/(S(6)*c) + b*sqrt(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*c**S(3)) + x**S(3)*(a + b*asin(c*x))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*asin(c*x))**(S(3)/2), x), x, S(3)*sqrt(Pi)*b**(S(3)/2)*FresnelC(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*sin(S(2)*a/b)/(S(32)*c**S(2)) - S(3)*sqrt(Pi)*b**(S(3)/2)*FresnelS(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*cos(S(2)*a/b)/(S(32)*c**S(2)) + S(3)*b*x*sqrt(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/(S(8)*c) + x**S(2)*(a + b*asin(c*x))**(S(3)/2)/S(2) - (a + b*asin(c*x))**(S(3)/2)/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(3)/2), x), x, -S(3)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(4)*c) - S(3)*sqrt(S(2))*sqrt(Pi)*b**(S(3)/2)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(4)*c) + S(3)*b*sqrt(a + b*asin(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))/(S(2)*c) + x*(a + b*asin(c*x))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(3)/2)/x, x), x, Integrate((a + b*asin(c*x))**(S(3)/2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(3)/2)/x**S(2), x), x, Integrate((a + b*asin(c*x))**(S(3)/2)/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*asin(c*x))**(S(5)/2), x), x, -S(15)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(32)*c**S(3)) + S(5)*sqrt(S(6))*sqrt(Pi)*b**(S(5)/2)*FresnelC(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(S(3)*a/b)/(S(864)*c**S(3)) + S(15)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(32)*c**S(3)) - S(5)*sqrt(S(6))*sqrt(Pi)*b**(S(5)/2)*FresnelS(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(S(3)*a/b)/(S(864)*c**S(3)) - S(5)*b**S(2)*x**S(3)*sqrt(a + b*asin(c*x))/S(36) - S(5)*b**S(2)*x*sqrt(a + b*asin(c*x))/(S(6)*c**S(2)) + S(5)*b*x**S(2)*(a + b*asin(c*x))**(S(3)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(18)*c) + S(5)*b*(a + b*asin(c*x))**(S(3)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(9)*c**S(3)) + x**S(3)*(a + b*asin(c*x))**(S(5)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*asin(c*x))**(S(5)/2), x), x, -S(15)*sqrt(Pi)*b**(S(5)/2)*FresnelC(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*cos(S(2)*a/b)/(S(128)*c**S(2)) - S(15)*sqrt(Pi)*b**(S(5)/2)*FresnelS(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*sin(S(2)*a/b)/(S(128)*c**S(2)) - S(15)*b**S(2)*x**S(2)*sqrt(a + b*asin(c*x))/S(32) + S(15)*b**S(2)*sqrt(a + b*asin(c*x))/(S(64)*c**S(2)) + S(5)*b*x*(a + b*asin(c*x))**(S(3)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(8)*c) + x**S(2)*(a + b*asin(c*x))**(S(5)/2)/S(2) - (a + b*asin(c*x))**(S(5)/2)/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(5)/2), x), x, -S(15)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(8)*c) + S(15)*sqrt(S(2))*sqrt(Pi)*b**(S(5)/2)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(8)*c) - S(15)*b**S(2)*x*sqrt(a + b*asin(c*x))/S(4) + S(5)*b*(a + b*asin(c*x))**(S(3)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(2)*c) + x*(a + b*asin(c*x))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(5)/2)/x, x), x, Integrate((a + b*asin(c*x))**(S(5)/2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(5)/2)/x**S(2), x), x, Integrate((a + b*asin(c*x))**(S(5)/2)/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*asin(c*x)), x), x, sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(4)*sqrt(b)*c**S(3)) - sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(S(3)*a/b)/(S(12)*sqrt(b)*c**S(3)) + sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(4)*sqrt(b)*c**S(3)) - sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(S(3)*a/b)/(S(12)*sqrt(b)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*asin(c*x)), x), x, -sqrt(Pi)*FresnelC(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*sin(S(2)*a/b)/(S(2)*sqrt(b)*c**S(2)) + sqrt(Pi)*FresnelS(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*cos(S(2)*a/b)/(S(2)*sqrt(b)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*asin(c*x)), x), x, sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(sqrt(b)*c) + sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(sqrt(b)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*asin(c*x))), x), x, Integrate(S(1)/(x*sqrt(a + b*asin(c*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*asin(c*x))), x), x, Integrate(S(1)/(x**S(2)*sqrt(a + b*asin(c*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asin(c*x))**(S(3)/2), x), x, sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(2)*b**(S(3)/2)*c**S(3)) - sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(S(3)*a/b)/(S(2)*b**(S(3)/2)*c**S(3)) - sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(2)*b**(S(3)/2)*c**S(3)) + sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(S(3)*a/b)/(S(2)*b**(S(3)/2)*c**S(3)) - S(2)*x**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*sqrt(a + b*asin(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asin(c*x))**(S(3)/2), x), x, S(2)*sqrt(Pi)*FresnelC(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*cos(S(2)*a/b)/(b**(S(3)/2)*c**S(2)) + S(2)*sqrt(Pi)*FresnelS(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*sin(S(2)*a/b)/(b**(S(3)/2)*c**S(2)) - S(2)*x*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*sqrt(a + b*asin(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(-3)/2), x), x, S(2)*sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(b**(S(3)/2)*c) - S(2)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(b**(S(3)/2)*c) - S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*sqrt(a + b*asin(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*asin(c*x))**(S(3)/2)), x), x, Integrate(S(1)/(x*(a + b*asin(c*x))**(S(3)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**(S(3)/2)), x), x, Integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**(S(3)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*asin(c*x))**(S(5)/2), x), x, -sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(3)*b**(S(5)/2)*c**S(3)) + sqrt(S(6))*sqrt(Pi)*FresnelC(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(S(3)*a/b)/(b**(S(5)/2)*c**S(3)) - sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(3)*b**(S(5)/2)*c**S(3)) + sqrt(S(6))*sqrt(Pi)*FresnelS(sqrt(S(6))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(S(3)*a/b)/(b**(S(5)/2)*c**S(3)) - S(2)*x**S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*b*c*(a + b*asin(c*x))**(S(3)/2)) + S(4)*x**S(3)/(b**S(2)*sqrt(a + b*asin(c*x))) - S(8)*x/(S(3)*b**S(2)*c**S(2)*sqrt(a + b*asin(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*asin(c*x))**(S(5)/2), x), x, S(8)*sqrt(Pi)*FresnelC(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*sin(S(2)*a/b)/(S(3)*b**(S(5)/2)*c**S(2)) - S(8)*sqrt(Pi)*FresnelS(S(2)*sqrt(a + b*asin(c*x))/(sqrt(Pi)*sqrt(b)))*cos(S(2)*a/b)/(S(3)*b**(S(5)/2)*c**S(2)) - S(2)*x*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*b*c*(a + b*asin(c*x))**(S(3)/2)) + S(8)*x**S(2)/(S(3)*b**S(2)*sqrt(a + b*asin(c*x))) - S(4)/(S(3)*b**S(2)*c**S(2)*sqrt(a + b*asin(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**(S(-5)/2), x), x, -S(4)*sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*cos(a/b)/(S(3)*b**(S(5)/2)*c) - S(4)*sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*sqrt(a + b*asin(c*x))*sqrt(S(1)/Pi)/sqrt(b))*sin(a/b)/(S(3)*b**(S(5)/2)*c) - S(2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*b*c*(a + b*asin(c*x))**(S(3)/2)) + S(4)*x/(S(3)*b**S(2)*sqrt(a + b*asin(c*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*asin(c*x))**(S(5)/2)), x), x, Integrate(S(1)/(x*(a + b*asin(c*x))**(S(5)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**(S(5)/2)), x), x, Integrate(S(1)/(x**S(2)*(a + b*asin(c*x))**(S(5)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*(a + b*asin(c*x)), x), x, S(4)*b*(d*x)**(S(5)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(49)*c) + S(20)*b*d**S(2)*sqrt(d*x)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(147)*c**S(3)) - S(20)*b*d**(S(5)/2)*EllipticF(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(S(147)*c**(S(7)/2)) + S(2)*(d*x)**(S(7)/2)*(a + b*asin(c*x))/(S(7)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a + b*asin(c*x)), x), x, S(4)*b*(d*x)**(S(3)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(25)*c) - S(12)*b*d**(S(3)/2)*EllipticE(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(S(25)*c**(S(5)/2)) + S(12)*b*d**(S(3)/2)*EllipticF(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(S(25)*c**(S(5)/2)) + S(2)*(d*x)**(S(5)/2)*(a + b*asin(c*x))/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a + b*asin(c*x)), x), x, S(4)*b*sqrt(d*x)*sqrt(-c**S(2)*x**S(2) + S(1))/(S(9)*c) - S(4)*b*sqrt(d)*EllipticF(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(S(9)*c**(S(3)/2)) + S(2)*(d*x)**(S(3)/2)*(a + b*asin(c*x))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))/sqrt(d*x), x), x, -S(4)*b*EllipticE(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(sqrt(c)*sqrt(d)) + S(4)*b*EllipticF(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(sqrt(c)*sqrt(d)) + S(2)*sqrt(d*x)*(a + b*asin(c*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))/(d*x)**(S(3)/2), x), x, S(4)*b*sqrt(c)*EllipticF(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/d**(S(3)/2) - (S(2)*a + S(2)*b*asin(c*x))/(d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))/(d*x)**(S(5)/2), x), x, -S(4)*b*c**(S(3)/2)*EllipticE(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(S(3)*d**(S(5)/2)) + S(4)*b*c**(S(3)/2)*EllipticF(asin(sqrt(c)*sqrt(d*x)/sqrt(d)), S(-1))/(S(3)*d**(S(5)/2)) - S(4)*b*c*sqrt(-c**S(2)*x**S(2) + S(1))/(S(3)*d**S(2)*sqrt(d*x)) - (S(2)*a + S(2)*b*asin(c*x))/(S(3)*d*(d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*(a + b*asin(c*x))**S(2), x), x, S(16)*b**S(2)*c**S(2)*(d*x)**(S(11)/2)*HypergeometricPFQ(List(S(1), S(11)/4, S(11)/4), List(S(13)/4, S(15)/4), c**S(2)*x**S(2))/(S(693)*d**S(3)) - S(8)*b*c*(d*x)**(S(9)/2)*(a + b*asin(c*x))*Hypergeometric2F1(S(1)/2, S(9)/4, S(13)/4, c**S(2)*x**S(2))/(S(63)*d**S(2)) + S(2)*(d*x)**(S(7)/2)*(a + b*asin(c*x))**S(2)/(S(7)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a + b*asin(c*x))**S(2), x), x, S(16)*b**S(2)*c**S(2)*(d*x)**(S(9)/2)*HypergeometricPFQ(List(S(1), S(9)/4, S(9)/4), List(S(11)/4, S(13)/4), c**S(2)*x**S(2))/(S(315)*d**S(3)) - S(8)*b*c*(d*x)**(S(7)/2)*(a + b*asin(c*x))*Hypergeometric2F1(S(1)/2, S(7)/4, S(11)/4, c**S(2)*x**S(2))/(S(35)*d**S(2)) + S(2)*(d*x)**(S(5)/2)*(a + b*asin(c*x))**S(2)/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a + b*asin(c*x))**S(2), x), x, S(16)*b**S(2)*c**S(2)*(d*x)**(S(7)/2)*HypergeometricPFQ(List(S(1), S(7)/4, S(7)/4), List(S(9)/4, S(11)/4), c**S(2)*x**S(2))/(S(105)*d**S(3)) - S(8)*b*c*(d*x)**(S(5)/2)*(a + b*asin(c*x))*Hypergeometric2F1(S(1)/2, S(5)/4, S(9)/4, c**S(2)*x**S(2))/(S(15)*d**S(2)) + S(2)*(d*x)**(S(3)/2)*(a + b*asin(c*x))**S(2)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(2)/sqrt(d*x), x), x, S(16)*b**S(2)*c**S(2)*(d*x)**(S(5)/2)*HypergeometricPFQ(List(S(1), S(5)/4, S(5)/4), List(S(7)/4, S(9)/4), c**S(2)*x**S(2))/(S(15)*d**S(3)) - S(8)*b*c*(d*x)**(S(3)/2)*(a + b*asin(c*x))*Hypergeometric2F1(S(1)/2, S(3)/4, S(7)/4, c**S(2)*x**S(2))/(S(3)*d**S(2)) + S(2)*sqrt(d*x)*(a + b*asin(c*x))**S(2)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(2)/(d*x)**(S(3)/2), x), x, -S(16)*b**S(2)*c**S(2)*(d*x)**(S(3)/2)*HypergeometricPFQ(List(S(3)/4, S(3)/4, S(1)), List(S(5)/4, S(7)/4), c**S(2)*x**S(2))/(S(3)*d**S(3)) + S(8)*b*c*sqrt(d*x)*(a + b*asin(c*x))*Hypergeometric2F1(S(1)/4, S(1)/2, S(5)/4, c**S(2)*x**S(2))/d**S(2) - S(2)*(a + b*asin(c*x))**S(2)/(d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(2)/(d*x)**(S(5)/2), x), x, S(16)*b**S(2)*c**S(2)*sqrt(d*x)*HypergeometricPFQ(List(S(1)/4, S(1)/4, S(1)), List(S(3)/4, S(5)/4), c**S(2)*x**S(2))/(S(3)*d**S(3)) - S(8)*b*c*(a + b*asin(c*x))*Hypergeometric2F1(S(-1)/4, S(1)/2, S(3)/4, c**S(2)*x**S(2))/(S(3)*d**S(2)*sqrt(d*x)) - S(2)*(a + b*asin(c*x))**S(2)/(S(3)*d*(d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a + b*asin(c*x))**S(3), x), x, -S(6)*b*c*Integrate((d*x)**(S(5)/2)*(a + b*asin(c*x))**S(2)/sqrt(-c**S(2)*x**S(2) + S(1)), x)/(S(5)*d) + S(2)*(d*x)**(S(5)/2)*(a + b*asin(c*x))**S(3)/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a + b*asin(c*x))**S(3), x), x, -S(2)*b*c*Integrate((d*x)**(S(3)/2)*(a + b*asin(c*x))**S(2)/sqrt(-c**S(2)*x**S(2) + S(1)), x)/d + S(2)*(d*x)**(S(3)/2)*(a + b*asin(c*x))**S(3)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(3)/sqrt(d*x), x), x, -S(6)*b*c*Integrate(sqrt(d*x)*(a + b*asin(c*x))**S(2)/sqrt(-c**S(2)*x**S(2) + S(1)), x)/d + S(2)*sqrt(d*x)*(a + b*asin(c*x))**S(3)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(3)/(d*x)**(S(3)/2), x), x, S(6)*b*c*Integrate((a + b*asin(c*x))**S(2)/(sqrt(d*x)*sqrt(-c**S(2)*x**S(2) + S(1))), x)/d - S(2)*(a + b*asin(c*x))**S(3)/(d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*asin(c*x))**S(3)/(d*x)**(S(5)/2), x), x, S(2)*b*c*Integrate((a + b*asin(c*x))**S(2)/((d*x)**(S(3)/2)*sqrt(-c**S(2)*x**S(2) + S(1))), x)/d - S(2)*(a + b*asin(c*x))**S(3)/(S(3)*d*(d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a + b*asin(c*x)), x), x, Integrate((d*x)**(S(3)/2)/(a + b*asin(c*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a + b*asin(c*x)), x), x, Integrate(sqrt(d*x)/(a + b*asin(c*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a + b*asin(c*x))), x), x, Integrate(S(1)/(sqrt(d*x)*(a + b*asin(c*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a + b*asin(c*x))), x), x, Integrate(S(1)/((d*x)**(S(3)/2)*(a + b*asin(c*x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a + b*asin(c*x))**S(2), x), x, Integrate((d*x)**(S(3)/2)/(a + b*asin(c*x))**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a + b*asin(c*x))**S(2), x), x, Integrate(sqrt(d*x)/(a + b*asin(c*x))**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a + b*asin(c*x))**S(2)), x), x, Integrate(S(1)/(sqrt(d*x)*(a + b*asin(c*x))**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a + b*asin(c*x))**S(2)), x), x, Integrate(S(1)/((d*x)**(S(3)/2)*(a + b*asin(c*x))**S(2)), x), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_logarithms.py000066400000000000000000015374171412543434000271660ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.rubi import rubi_integrate from sympy.functions import log, sqrt, exp, cos, sin, tan, sec, csc, cot,cosh, sinh, tanh, coth, csch, csch, sech from sympy import acsch , acsc, asinh,asin,acos,acosh,atan,atanh from sympy.integrals.rubi.utility_function import (EllipticE, EllipticF, Int, ArcCsch, ArcCsc, Gamma, Factorial, PolyGamma , LogGamma , Subst , hypergeom, rubi_test, AppellF1, EllipticPi, Log, Sqrt, ArcTan, ArcTanh, ArcSin, ArcSinh, ArcCosh, ArcTanh, ArcCos, Hypergeometric2F1,) from sympy import pi from sympy import S, hyper, I, simplify, exp_polar, symbols, exp, Ei,erf, erfi, li, Integral, polylog, hyper as HypergeometricPFQ from sympy import EulerGamma, expint, Chi, Shi, Ci, Si, E from sympy.testing.pytest import SKIP a, b, c, d, e, f, m, n, x, u , k, p, r, s, t, i, j= symbols('a b c d e f m n x u k p r s t i j') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F', ) def test_1(): assert rubi_test(rubi_integrate((e + f*x)**(p + S(-1))/log(d*(e + f*x)**p), x), x, li(d*(e + f*x)**p)/(d*f*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e*g + f*g*x)**(p + S(-1))/log(d*(e + f*x)**p), x), x, (e + f*x)**(-p + S(1))*(e*g + f*g*x)**(p + S(-1))*li(d*(e + f*x)**p)/(d*f*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**m, x), x, b*f*p*q*(g + h*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), f*(g + h*x)/(-e*h + f*g))/(h*(m + S(1))*(m + S(2))*(-e*h + f*g)) + (a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(m + S(1))/(h*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(4), x), x, -b*p*q*(g + h*x)**S(5)/(S(25)*h) - b*p*q*(g + h*x)**S(4)*(-e*h + f*g)/(S(20)*f*h) - b*p*q*(g + h*x)**S(3)*(-e*h + f*g)**S(2)/(S(15)*f**S(2)*h) - b*p*q*(g + h*x)**S(2)*(-e*h + f*g)**S(3)/(S(10)*f**S(3)*h) - b*p*q*x*(-e*h + f*g)**S(4)/(S(5)*f**S(4)) - b*p*q*(-e*h + f*g)**S(5)*log(e + f*x)/(S(5)*f**S(5)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(5)/(S(5)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(3), x), x, -b*p*q*(g + h*x)**S(4)/(S(16)*h) - b*p*q*(g + h*x)**S(3)*(-e*h + f*g)/(S(12)*f*h) - b*p*q*(g + h*x)**S(2)*(-e*h + f*g)**S(2)/(S(8)*f**S(2)*h) - b*p*q*x*(-e*h + f*g)**S(3)/(S(4)*f**S(3)) - b*p*q*(-e*h + f*g)**S(4)*log(e + f*x)/(S(4)*f**S(4)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(4)/(S(4)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(2), x), x, -b*p*q*(g + h*x)**S(3)/(S(9)*h) - b*p*q*(g + h*x)**S(2)*(-e*h + f*g)/(S(6)*f*h) - b*p*q*x*(-e*h + f*g)**S(2)/(S(3)*f**S(2)) - b*p*q*(-e*h + f*g)**S(3)*log(e + f*x)/(S(3)*f**S(3)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(3)/(S(3)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x), x), x, -b*p*q*(g + h*x)**S(2)/(S(4)*h) - b*p*q*x*(-e*h + f*g)/(S(2)*f) - b*p*q*(-e*h + f*g)**S(2)*log(e + f*x)/(S(2)*f**S(2)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(2)/(S(2)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*log(c*(d*(e + f*x)**p)**q), x), x, a*x - b*p*q*x + b*(e + f*x)*log(c*(d*(e + f*x)**p)**q)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x), x), x, b*p*q*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h + (a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(2), x), x, b*f*p*q*log(e + f*x)/(h*(-e*h + f*g)) - b*f*p*q*log(g + h*x)/(h*(-e*h + f*g)) + (-a - b*log(c*(d*(e + f*x)**p)**q))/(h*(g + h*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(3), x), x, b*f**S(2)*p*q*log(e + f*x)/(S(2)*h*(-e*h + f*g)**S(2)) - b*f**S(2)*p*q*log(g + h*x)/(S(2)*h*(-e*h + f*g)**S(2)) + b*f*p*q/(S(2)*h*(g + h*x)*(-e*h + f*g)) + (-a/S(2) - b*log(c*(d*(e + f*x)**p)**q)/S(2))/(h*(g + h*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(4), x), x, b*f**S(3)*p*q*log(e + f*x)/(S(3)*h*(-e*h + f*g)**S(3)) - b*f**S(3)*p*q*log(g + h*x)/(S(3)*h*(-e*h + f*g)**S(3)) + b*f**S(2)*p*q/(S(3)*h*(g + h*x)*(-e*h + f*g)**S(2)) + b*f*p*q/(S(6)*h*(g + h*x)**S(2)*(-e*h + f*g)) + (-a/S(3) - b*log(c*(d*(e + f*x)**p)**q)/S(3))/(h*(g + h*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(5), x), x, b*f**S(4)*p*q*log(e + f*x)/(S(4)*h*(-e*h + f*g)**S(4)) - b*f**S(4)*p*q*log(g + h*x)/(S(4)*h*(-e*h + f*g)**S(4)) + b*f**S(3)*p*q/(S(4)*h*(g + h*x)*(-e*h + f*g)**S(3)) + b*f**S(2)*p*q/(S(8)*h*(g + h*x)**S(2)*(-e*h + f*g)**S(2)) + b*f*p*q/(S(12)*h*(g + h*x)**S(3)*(-e*h + f*g)) + (-a/S(4) - b*log(c*(d*(e + f*x)**p)**q)/S(4))/(h*(g + h*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**m, x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**S(3), x), x, -a*b*p*q*x*(-e*h + f*g)**S(3)/(S(2)*f**S(3)) + b**S(2)*p**S(2)*q**S(2)*(g + h*x)**S(4)/(S(32)*h) + S(7)*b**S(2)*p**S(2)*q**S(2)*(g + h*x)**S(3)*(-e*h + f*g)/(S(72)*f*h) + S(13)*b**S(2)*p**S(2)*q**S(2)*(g + h*x)**S(2)*(-e*h + f*g)**S(2)/(S(48)*f**S(2)*h) + S(25)*b**S(2)*p**S(2)*q**S(2)*x*(-e*h + f*g)**S(3)/(S(24)*f**S(3)) - b**S(2)*p*q*(e + f*x)*(-e*h + f*g)**S(3)*log(c*(d*(e + f*x)**p)**q)/(S(2)*f**S(4)) + S(13)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**S(4)*log(e + f*x)/(S(24)*f**S(4)*h) - b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(4)/(S(8)*h) - b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(3)*(-e*h + f*g)/(S(6)*f*h) - b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(2)*(-e*h + f*g)**S(2)/(S(4)*f**S(2)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**S(4)/(S(4)*h) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-e*h + f*g)**S(4)/(S(4)*f**S(4)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**S(2), x), x, -S(2)*a*b*p*q*x*(-e*h + f*g)**S(2)/(S(3)*f**S(2)) + S(2)*b**S(2)*p**S(2)*q**S(2)*(g + h*x)**S(3)/(S(27)*h) + S(5)*b**S(2)*p**S(2)*q**S(2)*(g + h*x)**S(2)*(-e*h + f*g)/(S(18)*f*h) + S(11)*b**S(2)*p**S(2)*q**S(2)*x*(-e*h + f*g)**S(2)/(S(9)*f**S(2)) - S(2)*b**S(2)*p*q*(e + f*x)*(-e*h + f*g)**S(2)*log(c*(d*(e + f*x)**p)**q)/(S(3)*f**S(3)) + S(5)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**S(3)*log(e + f*x)/(S(9)*f**S(3)*h) - S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(3)/(S(9)*h) - b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(2)*(-e*h + f*g)/(S(3)*f*h) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**S(3)/(S(3)*h) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-e*h + f*g)**S(3)/(S(3)*f**S(3)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x), x), x, -S(2)*a*b*p*q*x*(-e*h + f*g)/f + b**S(2)*e*h*p**S(2)*q**S(2)*x/(S(2)*f) + b**S(2)*h*p**S(2)*q**S(2)*x**S(2)/S(4) + S(2)*b**S(2)*p**S(2)*q**S(2)*x*(-e*h + f*g)/f - S(2)*b**S(2)*p*q*(e + f*x)*(-e*h + f*g)*log(c*(d*(e + f*x)**p)**q)/f**S(2) - b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)/(S(2)*f**S(2)) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)/(S(2)*f**S(2)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*h + f*g)/f**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2), x), x, -S(2)*a*b*p*q*x + S(2)*b**S(2)*p**S(2)*q**S(2)*x - S(2)*b**S(2)*p*q*(e + f*x)*log(c*(d*(e + f*x)**p)**q)/f + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(g + h*x), x), x, -S(2)*b**S(2)*p**S(2)*q**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h + S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(g + h*x)**S(2), x), x, -S(2)*b**S(2)*f*p**S(2)*q**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)) - S(2)*b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(h*(-e*h + f*g)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/((g + h*x)*(-e*h + f*g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(g + h*x)**S(3), x), x, -b**S(2)*f**S(2)*p**S(2)*q**S(2)*log(e + f*x)/(h*(-e*h + f*g)**S(2)) + b**S(2)*f**S(2)*p**S(2)*q**S(2)*log(g + h*x)/(h*(-e*h + f*g)**S(2)) - b**S(2)*f**S(2)*p**S(2)*q**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(2)) - b*f**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(2)) + b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))/(h*(g + h*x)*(-e*h + f*g)) + f**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(2)*h*(-e*h + f*g)**S(2)) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(2)*h*(g + h*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(g + h*x)**S(4), x), x, -b**S(2)*f**S(3)*p**S(2)*q**S(2)*log(e + f*x)/(h*(-e*h + f*g)**S(3)) + b**S(2)*f**S(3)*p**S(2)*q**S(2)*log(g + h*x)/(h*(-e*h + f*g)**S(3)) - S(2)*b**S(2)*f**S(3)*p**S(2)*q**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(S(3)*h*(-e*h + f*g)**S(3)) - b**S(2)*f**S(2)*p**S(2)*q**S(2)/(S(3)*h*(g + h*x)*(-e*h + f*g)**S(2)) - S(2)*b*f**S(3)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(S(3)*h*(-e*h + f*g)**S(3)) + S(2)*b*f**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))/(S(3)*h*(g + h*x)*(-e*h + f*g)**S(2)) + b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))/(S(3)*h*(g + h*x)**S(2)*(-e*h + f*g)) + f**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(3)*h*(-e*h + f*g)**S(3)) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(3)*h*(g + h*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)**m, x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)**S(3), x), x, S(6)*a*b**S(2)*p**S(2)*q**S(2)*x*(-e*h + f*g)**S(3)/f**S(3) - S(9)*b**S(3)*e*h*p**S(3)*q**S(3)*x*(-e*h + f*g)**S(2)/(S(4)*f**S(3)) - S(9)*b**S(3)*h*p**S(3)*q**S(3)*x**S(2)*(-e*h + f*g)**S(2)/(S(8)*f**S(2)) - S(6)*b**S(3)*p**S(3)*q**S(3)*x*(-e*h + f*g)**S(3)/f**S(3) - S(3)*b**S(3)*h**S(3)*p**S(3)*q**S(3)*(e + f*x)**S(4)/(S(128)*f**S(4)) - S(2)*b**S(3)*h**S(2)*p**S(3)*q**S(3)*(e + f*x)**S(3)*(-e*h + f*g)/(S(9)*f**S(4)) + S(6)*b**S(3)*p**S(2)*q**S(2)*(e + f*x)*(-e*h + f*g)**S(3)*log(c*(d*(e + f*x)**p)**q)/f**S(4) + S(3)*b**S(2)*h**S(3)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(4)/(S(32)*f**S(4)) + S(2)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)*(-e*h + f*g)/(S(3)*f**S(4)) + S(9)*b**S(2)*h*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(4)*f**S(4)) - S(3)*b*h**S(3)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(4)/(S(16)*f**S(4)) - b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(3)*(-e*h + f*g)/f**S(4) - S(9)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(4)*f**S(4)) - S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*h + f*g)**S(3)/f**S(4) + h**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(4)/(S(4)*f**S(4)) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(3)*(-e*h + f*g)/f**S(4) + S(3)*h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(2)*f**S(4)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-e*h + f*g)**S(3)/f**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)**S(2), x), x, S(6)*a*b**S(2)*p**S(2)*q**S(2)*x*(-e*h + f*g)**S(2)/f**S(2) - S(3)*b**S(3)*e*h*p**S(3)*q**S(3)*x*(-e*h + f*g)/(S(2)*f**S(2)) - S(3)*b**S(3)*h*p**S(3)*q**S(3)*x**S(2)*(-e*h + f*g)/(S(4)*f) - S(6)*b**S(3)*p**S(3)*q**S(3)*x*(-e*h + f*g)**S(2)/f**S(2) - S(2)*b**S(3)*h**S(2)*p**S(3)*q**S(3)*(e + f*x)**S(3)/(S(27)*f**S(3)) + S(6)*b**S(3)*p**S(2)*q**S(2)*(e + f*x)*(-e*h + f*g)**S(2)*log(c*(d*(e + f*x)**p)**q)/f**S(3) + S(2)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)/(S(9)*f**S(3)) + S(3)*b**S(2)*h*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)/(S(2)*f**S(3)) - b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(3)/(S(3)*f**S(3)) - S(3)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)*(-e*h + f*g)/(S(2)*f**S(3)) - S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*h + f*g)**S(2)/f**S(3) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(3)/(S(3)*f**S(3)) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(2)*(-e*h + f*g)/f**S(3) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-e*h + f*g)**S(2)/f**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x), x), x, S(6)*a*b**S(2)*p**S(2)*q**S(2)*x*(-e*h + f*g)/f - S(3)*b**S(3)*e*h*p**S(3)*q**S(3)*x/(S(4)*f) - S(3)*b**S(3)*h*p**S(3)*q**S(3)*x**S(2)/S(8) - S(6)*b**S(3)*p**S(3)*q**S(3)*x*(-e*h + f*g)/f + S(6)*b**S(3)*p**S(2)*q**S(2)*(e + f*x)*(-e*h + f*g)*log(c*(d*(e + f*x)**p)**q)/f**S(2) + S(3)*b**S(2)*h*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)/(S(4)*f**S(2)) - S(3)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)/(S(4)*f**S(2)) - S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*h + f*g)/f**S(2) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(2)/(S(2)*f**S(2)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-e*h + f*g)/f**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3), x), x, S(6)*a*b**S(2)*p**S(2)*q**S(2)*x - S(6)*b**S(3)*p**S(3)*q**S(3)*x + S(6)*b**S(3)*p**S(2)*q**S(2)*(e + f*x)*log(c*(d*(e + f*x)**p)**q)/f - S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/f + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(g + h*x), x), x, S(6)*b**S(3)*p**S(3)*q**S(3)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/h - S(6)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h + S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(g + h*x)/(-e*h + f*g))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(g + h*x)**S(2), x), x, S(6)*b**S(3)*f*p**S(3)*q**S(3)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)) - S(6)*b**S(2)*f*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)) - S(3)*b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/(h*(-e*h + f*g)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)/((g + h*x)*(-e*h + f*g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(g + h*x)**S(3), x), x, S(3)*b**S(3)*f**S(2)*p**S(3)*q**S(3)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(2)) + S(3)*b**S(3)*f**S(2)*p**S(3)*q**S(3)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(2)) + S(3)*b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(2)) - S(3)*b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(2)) - S(3)*b*f**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/(S(2)*h*(-e*h + f*g)**S(2)) - S(3)*b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/(S(2)*(g + h*x)*(-e*h + f*g)**S(2)) + f**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(2)*h*(-e*h + f*g)**S(2)) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(2)*h*(g + h*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(g + h*x)**S(4), x), x, b**S(3)*f**S(3)*p**S(3)*q**S(3)*log(e + f*x)/(h*(-e*h + f*g)**S(3)) - b**S(3)*f**S(3)*p**S(3)*q**S(3)*log(g + h*x)/(h*(-e*h + f*g)**S(3)) + S(3)*b**S(3)*f**S(3)*p**S(3)*q**S(3)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(3)) + S(2)*b**S(3)*f**S(3)*p**S(3)*q**S(3)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(3)) + S(3)*b**S(2)*f**S(3)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(3)) - S(2)*b**S(2)*f**S(3)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(3)) - b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))/(h*(g + h*x)*(-e*h + f*g)**S(2)) - b*f**S(3)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/(h*(-e*h + f*g)**S(3)) - b*f**S(3)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(2)*h*(-e*h + f*g)**S(3)) - b*f**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/((g + h*x)*(-e*h + f*g)**S(3)) + b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(2)*h*(g + h*x)**S(2)*(-e*h + f*g)) + f**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(3)*h*(-e*h + f*g)**S(3)) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(3)*h*(g + h*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(g + h*x)**S(5), x), x, S(3)*b**S(3)*f**S(4)*p**S(3)*q**S(3)*log(e + f*x)/(S(2)*h*(-e*h + f*g)**S(4)) - S(3)*b**S(3)*f**S(4)*p**S(3)*q**S(3)*log(g + h*x)/(S(2)*h*(-e*h + f*g)**S(4)) + S(11)*b**S(3)*f**S(4)*p**S(3)*q**S(3)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(S(4)*h*(-e*h + f*g)**S(4)) + S(3)*b**S(3)*f**S(4)*p**S(3)*q**S(3)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(S(2)*h*(-e*h + f*g)**S(4)) + b**S(3)*f**S(3)*p**S(3)*q**S(3)/(S(4)*h*(g + h*x)*(-e*h + f*g)**S(3)) + S(11)*b**S(2)*f**S(4)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(S(4)*h*(-e*h + f*g)**S(4)) - S(3)*b**S(2)*f**S(4)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(S(2)*h*(-e*h + f*g)**S(4)) - S(5)*b**S(2)*f**S(3)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))/(S(4)*h*(g + h*x)*(-e*h + f*g)**S(3)) - b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))/(S(4)*h*(g + h*x)**S(2)*(-e*h + f*g)**S(2)) - S(3)*b*f**S(4)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/(S(4)*h*(-e*h + f*g)**S(4)) - S(5)*b*f**S(4)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(8)*h*(-e*h + f*g)**S(4)) - S(3)*b*f**S(3)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/(S(4)*(g + h*x)*(-e*h + f*g)**S(4)) + S(3)*b*f**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(8)*h*(g + h*x)**S(2)*(-e*h + f*g)**S(2)) + b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(4)*h*(g + h*x)**S(3)*(-e*h + f*g)) + f**S(4)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(4)*h*(-e*h + f*g)**S(4)) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(4)*h*(g + h*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(4), x), x, -S(24)*a*b**S(3)*p**S(3)*q**S(3)*x + S(24)*b**S(4)*p**S(4)*q**S(4)*x - S(24)*b**S(4)*p**S(3)*q**S(3)*(e + f*x)*log(c*(d*(e + f*x)**p)**q)/f + S(12)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/f - S(4)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)/f + (a + b*log(c*(d*(e + f*x)**p)**q))**S(4)*(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(4)/(g + h*x), x), x, -S(24)*b**S(4)*p**S(4)*q**S(4)*polylog(S(5), -h*(e + f*x)/(-e*h + f*g))/h + S(24)*b**S(3)*p**S(3)*q**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/h - S(12)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h + S(4)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h + (a + b*log(c*(d*(e + f*x)**p)**q))**S(4)*log(f*(g + h*x)/(-e*h + f*g))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(4)/(g + h*x)**S(2), x), x, -S(24)*b**S(4)*f*p**S(4)*q**S(4)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)) + S(24)*b**S(3)*f*p**S(3)*q**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)) - S(12)*b**S(2)*f*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(h*(-e*h + f*g)) - S(4)*b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(g + h*x)/(-e*h + f*g))/(h*(-e*h + f*g)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(4)*(e + f*x)/((g + h*x)*(-e*h + f*g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x), x), x, -x + (a + b*x)*log(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x)**S(2), x), x, S(2)*x + (a + b*x)*log(a + b*x)**S(2)/b - (S(2)*a + S(2)*b*x)*log(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x)**S(3), x), x, -S(6)*x + (a + b*x)*log(a + b*x)**S(3)/b - (S(3)*a + S(3)*b*x)*log(a + b*x)**S(2)/b + (S(6)*a + S(6)*b*x)*log(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x + c*x), x), x, -x + (a + x*(b + c))*log(a + x*(b + c))/(b + c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x + c*x)**S(2), x), x, S(2)*x + (a + x*(b + c))*log(a + x*(b + c))**S(2)/(b + c) - (S(2)*a + S(2)*x*(b + c))*log(a + x*(b + c))/(b + c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x + c*x)**S(3), x), x, -S(6)*x + (a + x*(b + c))*log(a + x*(b + c))**S(3)/(b + c) - (S(3)*a + S(3)*x*(b + c))*log(a + x*(b + c))**S(2)/(b + c) + (S(6)*a + S(6)*x*(b + c))*log(a + x*(b + c))/(b + c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-g*(d + e*x)/(-d*g + e*f))/(f + g*x), x), x, -polylog(S(2), e*(f + g*x)/(-d*g + e*f))/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(b*x + S(1))/x, x), x, -polylog(S(2), -b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x)**n)**S(2), x), x, -S(5)*a**S(3)*n**S(2)*log(a + b*x)/(S(9)*b**S(3)) + a**S(3)*log(c*(a + b*x)**n)**S(2)/(S(3)*b**S(3)) + S(11)*a**S(2)*n**S(2)*x/(S(9)*b**S(2)) - S(2)*a**S(2)*n*(a + b*x)*log(c*(a + b*x)**n)/(S(3)*b**S(3)) - S(5)*a*n**S(2)*x**S(2)/(S(18)*b) + a*n*x**S(2)*log(c*(a + b*x)**n)/(S(3)*b) + S(2)*n**S(2)*x**S(3)/S(27) - S(2)*n*x**S(3)*log(c*(a + b*x)**n)/S(9) + x**S(3)*log(c*(a + b*x)**n)**S(2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)**S(2)/x**S(4), x), x, -log(c*(a + b*x)**n)**S(2)/(S(3)*x**S(3)) - b*n*log(c*(a + b*x)**n)/(S(3)*a*x**S(2)) - b**S(2)*n**S(2)/(S(3)*a**S(2)*x) + S(2)*b**S(2)*n*log(c*(a + b*x)**n)/(S(3)*a**S(2)*x) - b**S(3)*n**S(2)*log(x)/a**S(3) + b**S(3)*n**S(2)*log(a + b*x)/a**S(3) + S(2)*b**S(3)*n**S(2)*polylog(S(2), (a + b*x)/a)/(S(3)*a**S(3)) + S(2)*b**S(3)*n*log(c*(a + b*x)**n)*log(-b*x/a)/(S(3)*a**S(3)) - b**S(3)*log(c*(a + b*x)**n)**S(2)/(S(3)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x)**n)**S(3), x), x, S(19)*a**S(3)*n**S(3)*log(a + b*x)/(S(18)*b**S(3)) - S(5)*a**S(3)*n*log(c*(a + b*x)**n)**S(2)/(S(6)*b**S(3)) + a**S(3)*log(c*(a + b*x)**n)**S(3)/(S(3)*b**S(3)) - S(85)*a**S(2)*n**S(3)*x/(S(18)*b**S(2)) + S(11)*a**S(2)*n**S(2)*(a + b*x)*log(c*(a + b*x)**n)/(S(3)*b**S(3)) - a**S(2)*n*(a + b*x)*log(c*(a + b*x)**n)**S(2)/b**S(3) + S(19)*a*n**S(3)*x**S(2)/(S(36)*b) - S(5)*a*n**S(2)*x**S(2)*log(c*(a + b*x)**n)/(S(6)*b) + a*n*x**S(2)*log(c*(a + b*x)**n)**S(2)/(S(2)*b) - S(2)*n**S(3)*x**S(3)/S(27) + S(2)*n**S(2)*x**S(3)*log(c*(a + b*x)**n)/S(9) - n*x**S(3)*log(c*(a + b*x)**n)**S(2)/S(3) + x**S(3)*log(c*(a + b*x)**n)**S(3)/S(3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x)**n)**S(3), x), x, -S(9)*a**S(2)*n**S(3)*x/(S(2)*b**S(2)) + S(6)*a**S(2)*n**S(2)*(a + b*x)*log(c*(a + b*x)**n)/b**S(3) - S(3)*a**S(2)*n*(a + b*x)*log(c*(a + b*x)**n)**S(2)/b**S(3) + a**S(2)*(a + b*x)*log(c*(a + b*x)**n)**S(3)/b**S(3) + S(3)*a*n**S(3)*x**S(2)/(S(4)*b) - S(3)*a*n**S(2)*(a + b*x)**S(2)*log(c*(a + b*x)**n)/(S(2)*b**S(3)) + S(3)*a*n*(a + b*x)**S(2)*log(c*(a + b*x)**n)**S(2)/(S(2)*b**S(3)) - a*(a + b*x)**S(2)*log(c*(a + b*x)**n)**S(3)/b**S(3) - S(2)*n**S(3)*(a + b*x)**S(3)/(S(27)*b**S(3)) + S(2)*n**S(2)*(a + b*x)**S(3)*log(c*(a + b*x)**n)/(S(9)*b**S(3)) - n*(a + b*x)**S(3)*log(c*(a + b*x)**n)**S(2)/(S(3)*b**S(3)) + (a + b*x)**S(3)*log(c*(a + b*x)**n)**S(3)/(S(3)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, Integral((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(3)/(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, h**S(3)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*Ei((S(4)*a + S(4)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(4)*p*q) + S(3)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*Ei((S(3)*a + S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(4)*p*q) + S(3)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(4)*p*q) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(4)*p*q), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(2)/(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*Ei((S(3)*a + S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(3)*p*q) + S(2)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(3)*p*q) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(3)*p*q), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)/(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(2)*p*q) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f**S(2)*p*q), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b*f*p*q), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(2)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**S(2), x), x, Integral((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(3)/(a + b*log(c*(d*(e + f*x)**p)**q))**S(2), x), x, -(e + f*x)*(g + h*x)**S(3)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))) + S(4)*h**S(3)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*Ei((S(4)*a + S(4)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(4)*p**S(2)*q**S(2)) + S(9)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*Ei((S(3)*a + S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(4)*p**S(2)*q**S(2)) + S(6)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(4)*p**S(2)*q**S(2)) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(4)*p**S(2)*q**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(2)/(a + b*log(c*(d*(e + f*x)**p)**q))**S(2), x), x, -(e + f*x)*(g + h*x)**S(2)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))) + S(3)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*Ei((S(3)*a + S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(3)*p**S(2)*q**S(2)) + S(4)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(3)*p**S(2)*q**S(2)) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(3)*p**S(2)*q**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)/(a + b*log(c*(d*(e + f*x)**p)**q))**S(2), x), x, -(e + f*x)*(g + h*x)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))) + S(2)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(2)*p**S(2)*q**S(2)) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f**S(2)*p**S(2)*q**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(-2)), x), x, (-e - f*x)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(2)*f*p**S(2)*q**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**S(2)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**S(3), x), x, Integral((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**S(3), x), expand=True, _diff=True, _numerical=True) # long time in rubi_test assert rubi_test(rubi_integrate((g + h*x)**S(3)/(a + b*log(c*(d*(e + f*x)**p)**q))**S(3), x), x, -(e/S(2) + f*x/S(2))*(g + h*x)**S(3)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)) - (S(2)*e + S(2)*f*x)*(g + h*x)**S(3)/(b**S(2)*f*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))) + (e + f*x)*(g + h*x)**S(2)*(-S(3)*e*h/S(2) + S(3)*f*g/S(2))/(b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))) + S(8)*h**S(3)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*Ei((S(4)*a + S(4)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(3)*f**S(4)*p**S(3)*q**S(3)) + S(27)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*Ei((S(3)*a + S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(S(2)*b**S(3)*f**S(4)*p**S(3)*q**S(3)) + S(6)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(3)*f**S(4)*p**S(3)*q**S(3)) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(S(2)*b**S(3)*f**S(4)*p**S(3)*q**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(2)/(a + b*log(c*(d*(e + f*x)**p)**q))**S(3), x), x, -(e/S(2) + f*x/S(2))*(g + h*x)**S(2)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)) - (S(3)*e/S(2) + S(3)*f*x/S(2))*(g + h*x)**S(2)/(b**S(2)*f*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))) + (e + f*x)*(g + h*x)*(-e*h + f*g)/(b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))) + S(9)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*Ei((S(3)*a + S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(S(2)*b**S(3)*f**S(3)*p**S(3)*q**S(3)) + S(4)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(3)*f**S(3)*p**S(3)*q**S(3)) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(S(2)*b**S(3)*f**S(3)*p**S(3)*q**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)/(a + b*log(c*(d*(e + f*x)**p)**q))**S(3), x), x, -(e/S(2) + f*x/S(2))*(g + h*x)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)) - (e + f*x)*(g + h*x)/(b**S(2)*f*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))) + (e + f*x)*(-e*h/S(2) + f*g/S(2))/(b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))) + S(2)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*Ei((S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(3)*f**S(2)*p**S(3)*q**S(3)) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h/S(2) + f*g/S(2))*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(3)*f**S(2)*p**S(3)*q**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(-3)), x), x, (-e/S(2) - f*x/S(2))/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)) + (-e/S(2) - f*x/S(2))/(b**S(2)*f*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e/S(2) + f*x/S(2))*exp(-a/(b*p*q))*Ei((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))/(b**S(3)*f*p**S(3)*q**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)**S(2)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(g + h*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**m, x), x, Integral(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(4), x), x, -sqrt(S(5))*sqrt(pi)*sqrt(b)*h**S(4)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(5)/(p*q))*(e + f*x)**S(5)*exp(-S(5)*a/(b*p*q))*erfi(sqrt(S(5))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(50)*f**S(5)) - sqrt(pi)*sqrt(b)*h**S(3)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*(-e*h + f*g)*exp(-S(4)*a/(b*p*q))*erfi(S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(4)*f**S(5)) - sqrt(S(3))*sqrt(pi)*sqrt(b)*h**S(2)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)**S(2)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(3)*f**S(5)) - sqrt(S(2))*sqrt(pi)*sqrt(b)*h*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(3)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(2)*f**S(5)) - sqrt(pi)*sqrt(b)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(4)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(2)*f**S(5)) + h**S(4)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(5)/(S(5)*f**S(5)) + h**S(3)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(4)*(-e*h + f*g)/f**S(5) + S(2)*h**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)*(-e*h + f*g)**S(2)/f**S(5) + S(2)*h*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)**S(3)/f**S(5) + sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)**S(4)/f**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(3), x), x, -sqrt(pi)*sqrt(b)*h**S(3)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*erfi(S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(16)*f**S(4)) - sqrt(S(3))*sqrt(pi)*sqrt(b)*h**S(2)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(6)*f**S(4)) - S(3)*sqrt(S(2))*sqrt(pi)*sqrt(b)*h*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(8)*f**S(4)) - sqrt(pi)*sqrt(b)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(2)*f**S(4)) + h**S(3)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(4)/(S(4)*f**S(4)) + h**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)*(-e*h + f*g)/f**S(4) + S(3)*h*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(2)*f**S(4)) + sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)**S(3)/f**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**S(2), x), x, -sqrt(S(3))*sqrt(pi)*sqrt(b)*h**S(2)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(18)*f**S(3)) - sqrt(S(2))*sqrt(pi)*sqrt(b)*h*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(4)*f**S(3)) - sqrt(pi)*sqrt(b)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(2)*f**S(3)) + h**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)/(S(3)*f**S(3)) + h*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)/f**S(3) + sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)**S(2)/f**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x), x), x, -sqrt(S(2))*sqrt(pi)*sqrt(b)*h*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(8)*f**S(2)) - sqrt(pi)*sqrt(b)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h/S(2) + f*g/S(2))*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/f**S(2) + h*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)/(S(2)*f**S(2)) + sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)/f**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, sqrt(pi)*sqrt(b)*sqrt(p)*sqrt(q)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(-e/S(2) - f*x/S(2))*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/f + sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x), x), x, Integral(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(2), x), x, -b*f*p*q*Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x)/(S(2)*(-e*h + f*g)) + sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)/((g + h*x)*(-e*h + f*g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(3), x), x, b*f*p*q*Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(g + h*x)**S(2)), x)/(S(4)*h) - sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(S(2)*h*(g + h*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(4), x), x, b*f*p*q*Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(g + h*x)**S(3)), x)/(S(6)*h) - sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(S(3)*h*(g + h*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**S(5), x), x, b*f*p*q*Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(g + h*x)**S(4)), x)/(S(8)*h) - sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(S(4)*h*(g + h*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(g + h*x)**m, x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(g + h*x)**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(g + h*x)**S(3), x), x, S(3)*sqrt(pi)*b**(S(3)/2)*h**S(3)*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*erfi(S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(128)*f**S(4)) + sqrt(S(3))*sqrt(pi)*b**(S(3)/2)*h**S(2)*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(12)*f**S(4)) + S(9)*sqrt(S(2))*sqrt(pi)*b**(S(3)/2)*h*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(32)*f**S(4)) + S(3)*sqrt(pi)*b**(S(3)/2)*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(4)*f**S(4)) - S(3)*b*h**S(3)*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(4)/(S(32)*f**S(4)) - b*h**S(2)*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)*(-e*h + f*g)/(S(2)*f**S(4)) - S(9)*b*h*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(8)*f**S(4)) - S(3)*b*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)**S(3)/(S(2)*f**S(4)) + h**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(4)/(S(4)*f**S(4)) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(3)*(-e*h + f*g)/f**S(4) + S(3)*h*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(2)*f**S(4)) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)*(-e*h + f*g)**S(3)/f**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(g + h*x)**S(2), x), x, sqrt(S(3))*sqrt(pi)*b**(S(3)/2)*h**S(2)*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(36)*f**S(3)) + S(3)*sqrt(S(2))*sqrt(pi)*b**(S(3)/2)*h*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(16)*f**S(3)) + S(3)*sqrt(pi)*b**(S(3)/2)*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(4)*f**S(3)) - b*h**S(2)*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)/(S(6)*f**S(3)) - S(3)*b*h*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)/(S(4)*f**S(3)) - S(3)*b*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)**S(2)/(S(2)*f**S(3)) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(3)/(S(3)*f**S(3)) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(2)*(-e*h + f*g)/f**S(3) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)*(-e*h + f*g)**S(2)/f**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(g + h*x), x), x, S(3)*sqrt(S(2))*sqrt(pi)*b**(S(3)/2)*h*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(32)*f**S(2)) + S(3)*sqrt(pi)*b**(S(3)/2)*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(4)*f**S(2)) - S(3)*b*h*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)/(S(8)*f**S(2)) - S(3)*b*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)/(S(2)*f**S(2)) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(2)/(S(2)*f**S(2)) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)*(-e*h + f*g)/f**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2), x), x, S(3)*sqrt(pi)*b**(S(3)/2)*p**(S(3)/2)*q**(S(3)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(4)*f) - S(3)*b*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)/(S(2)*f) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(g + h*x), x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(g + h*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(g + h*x)**S(2), x), x, -S(3)*b*f*p*q*Integral(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x), x)/(S(2)*(-e*h + f*g)) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)/((g + h*x)*(-e*h + f*g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(g + h*x)**S(3), x), x, S(3)*b*f*p*q*Integral(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/((e + f*x)*(g + h*x)**S(2)), x)/(S(4)*h) - (a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(S(2)*h*(g + h*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(g + h*x)**S(4), x), x, b*f*p*q*Integral(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/((e + f*x)*(g + h*x)**S(3)), x)/(S(2)*h) - (a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(S(3)*h*(g + h*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(g + h*x)**m, x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(g + h*x)**m, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(g + h*x)**S(3), x), x, -S(15)*sqrt(pi)*b**(S(5)/2)*h**S(3)*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*erfi(S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(1024)*f**S(4)) - S(5)*sqrt(S(3))*sqrt(pi)*b**(S(5)/2)*h**S(2)*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(72)*f**S(4)) - S(45)*sqrt(S(2))*sqrt(pi)*b**(S(5)/2)*h*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(128)*f**S(4)) - S(15)*sqrt(pi)*b**(S(5)/2)*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(8)*f**S(4)) + S(15)*b**S(2)*h**S(3)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(4)/(S(256)*f**S(4)) + S(5)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)*(-e*h + f*g)/(S(12)*f**S(4)) + S(45)*b**S(2)*h*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(32)*f**S(4)) + S(15)*b**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)**S(3)/(S(4)*f**S(4)) - S(5)*b*h**S(3)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(4)/(S(32)*f**S(4)) - S(5)*b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(3)*(-e*h + f*g)/(S(6)*f**S(4)) - S(15)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(8)*f**S(4)) - S(5)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)*(-e*h + f*g)**S(3)/(S(2)*f**S(4)) + h**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)**S(4)/(S(4)*f**S(4)) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)**S(3)*(-e*h + f*g)/f**S(4) + S(3)*h*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)**S(2)*(-e*h + f*g)**S(2)/(S(2)*f**S(4)) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)*(-e*h + f*g)**S(3)/f**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(g + h*x)**S(2), x), x, -S(5)*sqrt(S(3))*sqrt(pi)*b**(S(5)/2)*h**S(2)*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(216)*f**S(3)) - S(15)*sqrt(S(2))*sqrt(pi)*b**(S(5)/2)*h*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(64)*f**S(3)) - S(15)*sqrt(pi)*b**(S(5)/2)*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(8)*f**S(3)) + S(5)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)/(S(36)*f**S(3)) + S(15)*b**S(2)*h*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*h + f*g)/(S(16)*f**S(3)) + S(15)*b**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)**S(2)/(S(4)*f**S(3)) - S(5)*b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(3)/(S(18)*f**S(3)) - S(5)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(2)*(-e*h + f*g)/(S(4)*f**S(3)) - S(5)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)*(-e*h + f*g)**S(2)/(S(2)*f**S(3)) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)**S(3)/(S(3)*f**S(3)) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)**S(2)*(-e*h + f*g)/f**S(3) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)*(-e*h + f*g)**S(2)/f**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(g + h*x), x), x, -S(15)*sqrt(S(2))*sqrt(pi)*b**(S(5)/2)*h*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(128)*f**S(2)) - S(15)*sqrt(pi)*b**(S(5)/2)*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(8)*f**S(2)) + S(15)*b**S(2)*h*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)/(S(32)*f**S(2)) + S(15)*b**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*(-e*h + f*g)/(S(4)*f**S(2)) - S(5)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)**S(2)/(S(8)*f**S(2)) - S(5)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)*(-e*h + f*g)/(S(2)*f**S(2)) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)**S(2)/(S(2)*f**S(2)) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)*(-e*h + f*g)/f**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2), x), x, -S(15)*sqrt(pi)*b**(S(5)/2)*p**(S(5)/2)*q**(S(5)/2)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(8)*f) + S(15)*b**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)/(S(4)*f) - S(5)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(e + f*x)/(S(2)*f) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(g + h*x), x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(g + h*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(g + h*x)**S(2), x), x, -S(5)*b*f*p*q*Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/(g + h*x), x)/(S(2)*(-e*h + f*g)) + (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(e + f*x)/((g + h*x)*(-e*h + f*g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(g + h*x)**S(3), x), x, S(5)*b*f*p*q*Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/((e + f*x)*(g + h*x)**S(2)), x)/(S(4)*h) - (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(S(2)*h*(g + h*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(g + h*x)**S(4), x), x, S(5)*b*f*p*q*Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/((e + f*x)*(g + h*x)**S(3)), x)/(S(6)*h) - (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(S(3)*h*(g + h*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(g + h*x)**S(5), x), x, S(5)*b*f*p*q*Integral((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)/((e + f*x)*(g + h*x)**S(4)), x)/(S(8)*h) - (a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)/(S(4)*h*(g + h*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**m/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, Integral((g + h*x)**m/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(3)/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, sqrt(pi)*h**S(3)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*erfi(S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(2)*sqrt(b)*f**S(4)*sqrt(p)*sqrt(q)) + sqrt(S(3))*sqrt(pi)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(sqrt(b)*f**S(4)*sqrt(p)*sqrt(q)) + S(3)*sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(2)*sqrt(b)*f**S(4)*sqrt(p)*sqrt(q)) + sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(sqrt(b)*f**S(4)*sqrt(p)*sqrt(q)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(2)/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, sqrt(S(3))*sqrt(pi)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(3)*sqrt(b)*f**S(3)*sqrt(p)*sqrt(q)) + sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(sqrt(b)*f**S(3)*sqrt(p)*sqrt(q)) + sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(sqrt(b)*f**S(3)*sqrt(p)*sqrt(q)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(2)*sqrt(b)*f**S(2)*sqrt(p)*sqrt(q)) + sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(sqrt(b)*f**S(2)*sqrt(p)*sqrt(q)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(sqrt(b)*f*sqrt(p)*sqrt(q)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), x, Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2), x), x, Integral((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(3)/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2), x), x, -(S(2)*e + S(2)*f*x)*(g + h*x)**S(3)/(b*f*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + S(4)*sqrt(pi)*h**S(3)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*erfi(S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(4)*p**(S(3)/2)*q**(S(3)/2)) + S(6)*sqrt(S(3))*sqrt(pi)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(4)*p**(S(3)/2)*q**(S(3)/2)) + S(6)*sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(4)*p**(S(3)/2)*q**(S(3)/2)) + S(2)*sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(4)*p**(S(3)/2)*q**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(2)/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2), x), x, -(S(2)*e + S(2)*f*x)*(g + h*x)**S(2)/(b*f*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + S(2)*sqrt(S(3))*sqrt(pi)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(3)*p**(S(3)/2)*q**(S(3)/2)) + S(4)*sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(3)*p**(S(3)/2)*q**(S(3)/2)) + S(2)*sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(3)*p**(S(3)/2)*q**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2), x), x, -(S(2)*e + S(2)*f*x)*(g + h*x)/(b*f*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + S(2)*sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(2)*p**(S(3)/2)*q**(S(3)/2)) + sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-S(2)*e*h + S(2)*f*g)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f**S(2)*p**(S(3)/2)*q**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(-3)/2), x), x, -(S(2)*e + S(2)*f*x)/(b*f*p*q*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(S(2)*e + S(2)*f*x)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(3)/2)*f*p**(S(3)/2)*q**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(g + h*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2), x), x, Integral((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2), x), expand=True, _diff=True, _numerical=True) ''' long time in rubi test assert rubi_test(rubi_integrate((g + h*x)**S(3)/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2), x), x, (-S(2)*e/S(3) - S(2)*f*x/S(3))*(g + h*x)**S(3)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)) - (S(16)*e/S(3) + S(16)*f*x/S(3))*(g + h*x)**S(3)/(b**S(2)*f*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + (e + f*x)*(g + h*x)**S(2)*(-S(4)*e*h + S(4)*f*g)/(b**S(2)*f**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + S(32)*sqrt(pi)*h**S(3)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*(e + f*x)**S(4)*exp(-S(4)*a/(b*p*q))*erfi(S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(3)*b**(S(5)/2)*f**S(4)*p**(S(5)/2)*q**(S(5)/2)) + S(12)*sqrt(S(3))*sqrt(pi)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*(-e*h + f*g)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(5)/2)*f**S(4)*p**(S(5)/2)*q**(S(5)/2)) + S(8)*sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(5)/2)*f**S(4)*p**(S(5)/2)*q**(S(5)/2)) + S(4)*sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(3)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(3)*b**(S(5)/2)*f**S(4)*p**(S(5)/2)*q**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)**S(2)/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2), x), x, (-S(2)*e/S(3) - S(2)*f*x/S(3))*(g + h*x)**S(2)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)) - (S(4)*e + S(4)*f*x)*(g + h*x)**S(2)/(b**S(2)*f*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + (e + f*x)*(g + h*x)*(-S(8)*e*h/S(3) + S(8)*f*g/S(3))/(b**S(2)*f**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + S(4)*sqrt(S(3))*sqrt(pi)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*(e + f*x)**S(3)*exp(-S(3)*a/(b*p*q))*erfi(sqrt(S(3))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(5)/2)*f**S(3)*p**(S(5)/2)*q**(S(5)/2)) + S(16)*sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*(-e*h + f*g)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(3)*b**(S(5)/2)*f**S(3)*p**(S(5)/2)*q**(S(5)/2)) + S(4)*sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-e*h + f*g)**S(2)*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(3)*b**(S(5)/2)*f**S(3)*p**(S(5)/2)*q**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g + h*x)/(a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2), x), x, (-S(2)*e/S(3) - S(2)*f*x/S(3))*(g + h*x)/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)) - (S(8)*e/S(3) + S(8)*f*x/S(3))*(g + h*x)/(b**S(2)*f*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + (e + f*x)*(-S(4)*e*h/S(3) + S(4)*f*g/S(3))/(b**S(2)*f**S(2)*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + S(8)*sqrt(S(2))*sqrt(pi)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*(e + f*x)**S(2)*exp(-S(2)*a/(b*p*q))*erfi(sqrt(S(2))*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(S(3)*b**(S(5)/2)*f**S(2)*p**(S(5)/2)*q**(S(5)/2)) + sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*(-S(4)*e*h/S(3) + S(4)*f*g/S(3))*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(5)/2)*f**S(2)*p**(S(5)/2)*q**(S(5)/2)), expand=True, _diff=True, _numerical=True) ''' assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**(S(-5)/2), x), x, (-S(2)*e/S(3) - S(2)*f*x/S(3))/(b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**(S(3)/2)) - (S(4)*e/S(3) + S(4)*f*x/S(3))/(b**S(2)*f*p**S(2)*q**S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))) + sqrt(pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(S(4)*e/S(3) + S(4)*f*x/S(3))*exp(-a/(b*p*q))*erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(b)*sqrt(p)*sqrt(q)))/(b**(S(5)/2)*f*p**(S(5)/2)*q**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(g + h*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**(S(5)/2)*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(3)/2), x), x, -S(4)*b*p*q*(g + h*x)**(S(5)/2)/(S(25)*h) - S(4)*b*p*q*(g + h*x)**(S(3)/2)*(-e*h + f*g)/(S(15)*f*h) - S(4)*b*p*q*sqrt(g + h*x)*(-e*h + f*g)**S(2)/(S(5)*f**S(2)*h) + S(4)*b*p*q*(-e*h + f*g)**(S(5)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(5)*f**(S(5)/2)*h) + S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(5)/2)/(S(5)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x), x), x, -S(4)*b*p*q*(g + h*x)**(S(3)/2)/(S(9)*h) - S(4)*b*p*q*sqrt(g + h*x)*(-e*h + f*g)/(S(3)*f*h) + S(4)*b*p*q*(-e*h + f*g)**(S(3)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(3)*f**(S(3)/2)*h) + S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(3)/2)/(S(3)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/sqrt(g + h*x), x), x, -S(4)*b*p*q*sqrt(g + h*x)/h + S(4)*b*p*q*sqrt(-e*h + f*g)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(sqrt(f)*h) + (S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x)/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**(S(3)/2), x), x, -S(4)*b*sqrt(f)*p*q*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(h*sqrt(-e*h + f*g)) - (S(2)*a + S(2)*b*log(c*(d*(e + f*x)**p)**q))/(h*sqrt(g + h*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**(S(5)/2), x), x, -S(4)*b*f**(S(3)/2)*p*q*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(3)*h*(-e*h + f*g)**(S(3)/2)) + S(4)*b*f*p*q/(S(3)*h*sqrt(g + h*x)*(-e*h + f*g)) - (S(2)*a/S(3) + S(2)*b*log(c*(d*(e + f*x)**p)**q)/S(3))/(h*(g + h*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**(S(7)/2), x), x, -S(4)*b*f**(S(5)/2)*p*q*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(5)*h*(-e*h + f*g)**(S(5)/2)) + S(4)*b*f**S(2)*p*q/(S(5)*h*sqrt(g + h*x)*(-e*h + f*g)**S(2)) + S(4)*b*f*p*q/(S(15)*h*(g + h*x)**(S(3)/2)*(-e*h + f*g)) - (S(2)*a/S(5) + S(2)*b*log(c*(d*(e + f*x)**p)**q)/S(5))/(h*(g + h*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**(S(9)/2), x), x, -S(4)*b*f**(S(7)/2)*p*q*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(7)*h*(-e*h + f*g)**(S(7)/2)) + S(4)*b*f**S(3)*p*q/(S(7)*h*sqrt(g + h*x)*(-e*h + f*g)**S(3)) + S(4)*b*f**S(2)*p*q/(S(21)*h*(g + h*x)**(S(3)/2)*(-e*h + f*g)**S(2)) + S(4)*b*f*p*q/(S(35)*h*(g + h*x)**(S(5)/2)*(-e*h + f*g)) - (S(2)*a/S(7) + S(2)*b*log(c*(d*(e + f*x)**p)**q)/S(7))/(h*(g + h*x)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**(S(3)/2), x), x, S(16)*b**S(2)*p**S(2)*q**S(2)*(g + h*x)**(S(5)/2)/(S(125)*h) + S(128)*b**S(2)*p**S(2)*q**S(2)*(g + h*x)**(S(3)/2)*(-e*h + f*g)/(S(225)*f*h) + S(368)*b**S(2)*p**S(2)*q**S(2)*sqrt(g + h*x)*(-e*h + f*g)**S(2)/(S(75)*f**S(2)*h) + S(16)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(5)/2)*log(S(2)/(-sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g) + S(1)))*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(5)*f**(S(5)/2)*h) - S(8)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(5)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))**S(2)/(S(5)*f**(S(5)/2)*h) - S(368)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(5)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(75)*f**(S(5)/2)*h) + S(8)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(5)/2)*polylog(S(2), (-sqrt(f)*sqrt(g + h*x) - sqrt(-e*h + f*g))/(-sqrt(f)*sqrt(g + h*x) + sqrt(-e*h + f*g)))/(S(5)*f**(S(5)/2)*h) - S(8)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(5)/2)/(S(25)*h) - S(8)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(3)/2)*(-e*h + f*g)/(S(15)*f*h) - S(8)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x)*(-e*h + f*g)**S(2)/(S(5)*f**S(2)*h) + S(8)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(-e*h + f*g)**(S(5)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(5)*f**(S(5)/2)*h) + S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**(S(5)/2)/(S(5)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*sqrt(g + h*x), x), x, S(16)*b**S(2)*p**S(2)*q**S(2)*(g + h*x)**(S(3)/2)/(S(27)*h) + S(64)*b**S(2)*p**S(2)*q**S(2)*sqrt(g + h*x)*(-e*h + f*g)/(S(9)*f*h) + S(16)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(3)/2)*log(S(2)/(-sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g) + S(1)))*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(3)*f**(S(3)/2)*h) - S(8)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(3)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))**S(2)/(S(3)*f**(S(3)/2)*h) - S(64)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(3)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(9)*f**(S(3)/2)*h) + S(8)*b**S(2)*p**S(2)*q**S(2)*(-e*h + f*g)**(S(3)/2)*polylog(S(2), (-sqrt(f)*sqrt(g + h*x) - sqrt(-e*h + f*g))/(-sqrt(f)*sqrt(g + h*x) + sqrt(-e*h + f*g)))/(S(3)*f**(S(3)/2)*h) - S(8)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(3)/2)/(S(9)*h) - S(8)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x)*(-e*h + f*g)/(S(3)*f*h) + S(8)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(-e*h + f*g)**(S(3)/2)*atanh(sqrt(f)*sqrt(g + h*x)/sqrt(-e*h + f*g))/(S(3)*f**(S(3)/2)*h) + S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)**(S(3)/2)/(S(3)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x), x), x, -b*f*p*q*Integral((g + h*x)**(S(3)/2)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)), x)/(S(3)*h) + S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(3)/2)/(S(3)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/sqrt(g + h*x), x), x, -b*f*p*q*Integral(sqrt(g + h*x)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)), x)/h + S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x)/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x)**(S(3)/2), x), x, b*f*p*q*Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)*sqrt(g + h*x)), x)/h - S(2)*sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/(h*sqrt(g + h*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(g + h*x)/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), x, Integral(sqrt(g + h*x)/sqrt(a + b*log(c*(d*(e + f*x)**p)**q)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x)), x), x, Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*sqrt(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(3)/2)), x), x, Integral(S(1)/(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(S(3)/2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**m, x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**m, x), expand=True, _diff=True, _numerical=True) '''long time assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**S(3), x), x, S(3)*S(2)**(-n + S(-1))*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)**S(2)*(-e*h + f*g)**S(2)*Gamma(n + S(1), (-S(2)*a - S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-S(2)*a/(b*p*q))/f**S(4) + S(4)**(-n + S(-1))*h**S(3)*(c*(d*(e + f*x)**p)**q)**(-S(4)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)**S(4)*Gamma(n + S(1), (-S(4)*a - S(4)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-S(4)*a/(b*p*q))/f**S(4) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)*(-e*h + f*g)**S(3)*Gamma(n + S(1), (-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-a/(b*p*q))/f**S(4) + S(3)**(-n)*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)**S(3)*(-e*h + f*g)*Gamma(n + S(1), (-S(3)*a - S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-S(3)*a/(b*p*q))/f**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**S(2), x), x, S(3)**(-n + S(-1))*h**S(2)*(c*(d*(e + f*x)**p)**q)**(-S(3)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)**S(3)*Gamma(n + S(1), (-S(3)*a - S(3)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-S(3)*a/(b*p*q))/f**S(3) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)*(-e*h + f*g)**S(2)*Gamma(n + S(1), (-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-a/(b*p*q))/f**S(3) + S(2)**(-n)*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)**S(2)*(-e*h + f*g)*Gamma(n + S(1), (-S(2)*a - S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-S(2)*a/(b*p*q))/f**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x), x), x, S(2)**(-n + S(-1))*h*(c*(d*(e + f*x)**p)**q)**(-S(2)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)**S(2)*Gamma(n + S(1), (-S(2)*a - S(2)*b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-S(2)*a/(b*p*q))/f**S(2) + (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)*(-e*h + f*g)*Gamma(n + S(1), (-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-a/(b*p*q))/f**S(2), expand=True, _diff=True, _numerical=True) ''' assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**n, x), x, (c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*((-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)*Gamma(n + S(1), (-a - b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-a/(b*p*q))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**n/(g + h*x), x), x, Integral((a + b*log(c*(d*(e + f*x)**p)**q))**n/(g + h*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))*(i + j*x)**S(4)/(d*e + d*f*x), x), x, -S(4)*b*j*x*(-e*j + f*i)**S(3)/(d*f**S(4)) - b*j**S(4)*(e + f*x)**S(4)/(S(16)*d*f**S(5)) - S(4)*b*j**S(3)*(e + f*x)**S(3)*(-e*j + f*i)/(S(9)*d*f**S(5)) - S(3)*b*j**S(2)*(e + f*x)**S(2)*(-e*j + f*i)**S(2)/(S(2)*d*f**S(5)) + j**S(4)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(4)/(S(4)*d*f**S(5)) + S(4)*j**S(3)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(3)*(-e*j + f*i)/(S(3)*d*f**S(5)) + S(3)*j**S(2)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(2)*(-e*j + f*i)**S(2)/(d*f**S(5)) + S(4)*j*(a + b*log(c*(e + f*x)))*(e + f*x)*(-e*j + f*i)**S(3)/(d*f**S(5)) + (a + b*log(c*(e + f*x)))**S(2)*(-e*j + f*i)**S(4)/(S(2)*b*d*f**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))*(i + j*x)**S(3)/(d*e + d*f*x), x), x, -S(3)*b*j*x*(-e*j + f*i)**S(2)/(d*f**S(3)) - b*j**S(3)*(e + f*x)**S(3)/(S(9)*d*f**S(4)) - S(3)*b*j**S(2)*(e + f*x)**S(2)*(-e*j + f*i)/(S(4)*d*f**S(4)) + j**S(3)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(3)/(S(3)*d*f**S(4)) + S(3)*j**S(2)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(2)*(-e*j + f*i)/(S(2)*d*f**S(4)) + S(3)*j*(a + b*log(c*(e + f*x)))*(e + f*x)*(-e*j + f*i)**S(2)/(d*f**S(4)) + (a + b*log(c*(e + f*x)))**S(2)*(-e*j + f*i)**S(3)/(S(2)*b*d*f**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))*(i + j*x)**S(2)/(d*e + d*f*x), x), x, -S(2)*b*j*x*(-e*j + f*i)/(d*f**S(2)) - b*j**S(2)*(e + f*x)**S(2)/(S(4)*d*f**S(3)) + j**S(2)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(2)/(S(2)*d*f**S(3)) + S(2)*j*(a + b*log(c*(e + f*x)))*(e + f*x)*(-e*j + f*i)/(d*f**S(3)) + (a + b*log(c*(e + f*x)))**S(2)*(-e*j + f*i)**S(2)/(S(2)*b*d*f**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))*(i + j*x)/(d*e + d*f*x), x), x, -b*j*x/(d*f) + j*(a + b*log(c*(e + f*x)))*(e + f*x)/(d*f**S(2)) + (a + b*log(c*(e + f*x)))**S(2)*(-e*j/S(2) + f*i/S(2))/(b*d*f**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))/(d*e + d*f*x), x), x, (a + b*log(c*(e + f*x)))**S(2)/(S(2)*b*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))/((i + j*x)*(d*e + d*f*x)), x), x, -b*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)) - (a + b*log(c*(e + f*x)))*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)) + (a + b*log(c*(e + f*x)))**S(2)/(S(2)*b*d*(-e*j + f*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))/((i + j*x)**S(2)*(d*e + d*f*x)), x), x, -b*f*log(e + f*x)/(d*(-e*j + f*i)**S(2)) + b*f*log(i + j*x)/(d*(-e*j + f*i)**S(2)) - b*f*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(2)) - f*(a + b*log(c*(e + f*x)))*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(2)) + (a + b*log(c*(e + f*x)))/(d*(i + j*x)*(-e*j + f*i)) + f*(a + b*log(c*(e + f*x)))**S(2)/(S(2)*b*d*(-e*j + f*i)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))/((i + j*x)**S(3)*(d*e + d*f*x)), x), x, -S(3)*b*f**S(2)*log(e + f*x)/(S(2)*d*(-e*j + f*i)**S(3)) + S(3)*b*f**S(2)*log(i + j*x)/(S(2)*d*(-e*j + f*i)**S(3)) - b*f**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(3)) - b*f/(S(2)*d*(i + j*x)*(-e*j + f*i)**S(2)) - f**S(2)*(a + b*log(c*(e + f*x)))*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(3)) + f*(a + b*log(c*(e + f*x)))/(d*(i + j*x)*(-e*j + f*i)**S(2)) + (a/S(2) + b*log(c*(e + f*x))/S(2))/(d*(i + j*x)**S(2)*(-e*j + f*i)) + f**S(2)*(a + b*log(c*(e + f*x)))**S(2)/(S(2)*b*d*(-e*j + f*i)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)*(i + j*x)**S(4)/(d*e + d*f*x), x), x, S(8)*b**S(2)*j*x*(-e*j + f*i)**S(3)/(d*f**S(4)) + b**S(2)*j**S(4)*(e + f*x)**S(4)/(S(32)*d*f**S(5)) + S(8)*b**S(2)*j**S(3)*(e + f*x)**S(3)*(-e*j + f*i)/(S(27)*d*f**S(5)) + S(3)*b**S(2)*j**S(2)*(e + f*x)**S(2)*(-e*j + f*i)**S(2)/(S(2)*d*f**S(5)) - b*j**S(4)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(4)/(S(8)*d*f**S(5)) - S(8)*b*j**S(3)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(3)*(-e*j + f*i)/(S(9)*d*f**S(5)) - S(3)*b*j**S(2)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(2)*(-e*j + f*i)**S(2)/(d*f**S(5)) - S(8)*b*j*(a + b*log(c*(e + f*x)))*(e + f*x)*(-e*j + f*i)**S(3)/(d*f**S(5)) + j**S(4)*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)**S(4)/(S(4)*d*f**S(5)) + S(4)*j**S(3)*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)**S(3)*(-e*j + f*i)/(S(3)*d*f**S(5)) + S(3)*j**S(2)*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)**S(2)*(-e*j + f*i)**S(2)/(d*f**S(5)) + S(4)*j*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)*(-e*j + f*i)**S(3)/(d*f**S(5)) + (a + b*log(c*(e + f*x)))**S(3)*(-e*j + f*i)**S(4)/(S(3)*b*d*f**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)*(i + j*x)**S(3)/(d*e + d*f*x), x), x, S(6)*b**S(2)*j*x*(-e*j + f*i)**S(2)/(d*f**S(3)) + S(2)*b**S(2)*j**S(3)*(e + f*x)**S(3)/(S(27)*d*f**S(4)) + S(3)*b**S(2)*j**S(2)*(e + f*x)**S(2)*(-e*j + f*i)/(S(4)*d*f**S(4)) - S(2)*b*j**S(3)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(3)/(S(9)*d*f**S(4)) - S(3)*b*j**S(2)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(2)*(-e*j + f*i)/(S(2)*d*f**S(4)) - S(6)*b*j*(a + b*log(c*(e + f*x)))*(e + f*x)*(-e*j + f*i)**S(2)/(d*f**S(4)) + j**S(3)*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)**S(3)/(S(3)*d*f**S(4)) + S(3)*j**S(2)*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)**S(2)*(-e*j + f*i)/(S(2)*d*f**S(4)) + S(3)*j*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)*(-e*j + f*i)**S(2)/(d*f**S(4)) + (a + b*log(c*(e + f*x)))**S(3)*(-e*j + f*i)**S(3)/(S(3)*b*d*f**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)*(i + j*x)**S(2)/(d*e + d*f*x), x), x, S(4)*b**S(2)*j*x*(-e*j + f*i)/(d*f**S(2)) + b**S(2)*j**S(2)*(e + f*x)**S(2)/(S(4)*d*f**S(3)) - b*j**S(2)*(a + b*log(c*(e + f*x)))*(e + f*x)**S(2)/(S(2)*d*f**S(3)) - S(4)*b*j*(a + b*log(c*(e + f*x)))*(e + f*x)*(-e*j + f*i)/(d*f**S(3)) + j**S(2)*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)**S(2)/(S(2)*d*f**S(3)) + S(2)*j*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)*(-e*j + f*i)/(d*f**S(3)) + (a + b*log(c*(e + f*x)))**S(3)*(-e*j + f*i)**S(2)/(S(3)*b*d*f**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)*(i + j*x)/(d*e + d*f*x), x), x, S(2)*b**S(2)*j*x/(d*f) - S(2)*b*j*(a + b*log(c*(e + f*x)))*(e + f*x)/(d*f**S(2)) + j*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)/(d*f**S(2)) + (a + b*log(c*(e + f*x)))**S(3)*(-e*j/S(3) + f*i/S(3))/(b*d*f**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)/(d*e + d*f*x), x), x, (a + b*log(c*(e + f*x)))**S(3)/(S(3)*b*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)/((i + j*x)*(d*e + d*f*x)), x), x, S(2)*b**S(2)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)) - S(2)*b*(a + b*log(c*(e + f*x)))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)) - (a + b*log(c*(e + f*x)))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)) + (a + b*log(c*(e + f*x)))**S(3)/(S(3)*b*d*(-e*j + f*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)/((i + j*x)**S(2)*(d*e + d*f*x)), x), x, S(2)*b**S(2)*f*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(2)) + S(2)*b**S(2)*f*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(2)) + S(2)*b*f*(a + b*log(c*(e + f*x)))*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(2)) - S(2)*b*f*(a + b*log(c*(e + f*x)))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(2)) - f*(a + b*log(c*(e + f*x)))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(2)) - j*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)/(d*(i + j*x)*(-e*j + f*i)**S(2)) + f*(a + b*log(c*(e + f*x)))**S(3)/(S(3)*b*d*(-e*j + f*i)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)/((i + j*x)**S(3)*(d*e + d*f*x)), x), x, b**S(2)*f**S(2)*log(e + f*x)/(d*(-e*j + f*i)**S(3)) - b**S(2)*f**S(2)*log(i + j*x)/(d*(-e*j + f*i)**S(3)) + S(3)*b**S(2)*f**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(3)) + S(2)*b**S(2)*f**S(2)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(3)) + S(3)*b*f**S(2)*(a + b*log(c*(e + f*x)))*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(3)) - S(2)*b*f**S(2)*(a + b*log(c*(e + f*x)))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(3)) - b*f*(a + b*log(c*(e + f*x)))/(d*(i + j*x)*(-e*j + f*i)**S(2)) - f**S(2)*(a + b*log(c*(e + f*x)))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/(d*(-e*j + f*i)**S(3)) - f**S(2)*(a + b*log(c*(e + f*x)))**S(2)/(S(2)*d*(-e*j + f*i)**S(3)) - f*j*(a + b*log(c*(e + f*x)))**S(2)*(e + f*x)/(d*(i + j*x)*(-e*j + f*i)**S(3)) + (a + b*log(c*(e + f*x)))**S(2)/(S(2)*d*(i + j*x)**S(2)*(-e*j + f*i)) + f**S(2)*(a + b*log(c*(e + f*x)))**S(3)/(S(3)*b*d*(-e*j + f*i)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((i + j*x)**S(4)/((a + b*log(c*(e + f*x)))*(d*e + d*f*x)), x), x, (-e*j + f*i)**S(4)*log(a + b*log(c*(e + f*x)))/(b*d*f**S(5)) + S(4)*j*(-e*j + f*i)**S(3)*exp(-a/b)*Ei((a + b*log(c*(e + f*x)))/b)/(b*c*d*f**S(5)) + S(6)*j**S(2)*(-e*j + f*i)**S(2)*exp(-S(2)*a/b)*Ei((S(2)*a + S(2)*b*log(c*(e + f*x)))/b)/(b*c**S(2)*d*f**S(5)) + S(4)*j**S(3)*(-e*j + f*i)*exp(-S(3)*a/b)*Ei((S(3)*a + S(3)*b*log(c*(e + f*x)))/b)/(b*c**S(3)*d*f**S(5)) + j**S(4)*exp(-S(4)*a/b)*Ei((S(4)*a + S(4)*b*log(c*(e + f*x)))/b)/(b*c**S(4)*d*f**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((i + j*x)**S(3)/((a + b*log(c*(e + f*x)))*(d*e + d*f*x)), x), x, (-e*j + f*i)**S(3)*log(a + b*log(c*(e + f*x)))/(b*d*f**S(4)) + S(3)*j*(-e*j + f*i)**S(2)*exp(-a/b)*Ei((a + b*log(c*(e + f*x)))/b)/(b*c*d*f**S(4)) + S(3)*j**S(2)*(-e*j + f*i)*exp(-S(2)*a/b)*Ei((S(2)*a + S(2)*b*log(c*(e + f*x)))/b)/(b*c**S(2)*d*f**S(4)) + j**S(3)*exp(-S(3)*a/b)*Ei((S(3)*a + S(3)*b*log(c*(e + f*x)))/b)/(b*c**S(3)*d*f**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((i + j*x)**S(2)/((a + b*log(c*(e + f*x)))*(d*e + d*f*x)), x), x, (-e*j + f*i)**S(2)*log(a + b*log(c*(e + f*x)))/(b*d*f**S(3)) + S(2)*j*(-e*j + f*i)*exp(-a/b)*Ei((a + b*log(c*(e + f*x)))/b)/(b*c*d*f**S(3)) + j**S(2)*exp(-S(2)*a/b)*Ei((S(2)*a + S(2)*b*log(c*(e + f*x)))/b)/(b*c**S(2)*d*f**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((i + j*x)/((a + b*log(c*(e + f*x)))*(d*e + d*f*x)), x), x, (-e*j + f*i)*log(a + b*log(c*(e + f*x)))/(b*d*f**S(2)) + j*exp(-a/b)*Ei((a + b*log(c*(e + f*x)))/b)/(b*c*d*f**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(e + f*x)))*(d*e + d*f*x)), x), x, log(a + b*log(c*(e + f*x)))/(b*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(e + f*x)))*(i + j*x)*(d*e + d*f*x)), x), x, Integral(S(1)/((a + b*log(c*(e + f*x)))*(i + j*x)*(d*e + d*f*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(e + f*x)))*(i + j*x)**S(2)*(d*e + d*f*x)), x), x, Integral(S(1)/((a + b*log(c*(e + f*x)))*(i + j*x)**S(2)*(d*e + d*f*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d + e*x)**n))*(f + g*x)**(S(5)/2)/(d + e*x), x), x, -S(4)*b*n*(f + g*x)**(S(5)/2)/(S(25)*e) - S(32)*b*n*(f + g*x)**(S(3)/2)*(-d*g + e*f)/(S(45)*e**S(2)) - S(92)*b*n*sqrt(f + g*x)*(-d*g + e*f)**S(2)/(S(15)*e**S(3)) - S(4)*b*n*(-d*g + e*f)**(S(5)/2)*log(S(2)/(-sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f) + S(1)))*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/e**(S(7)/2) + S(2)*b*n*(-d*g + e*f)**(S(5)/2)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))**S(2)/e**(S(7)/2) + S(92)*b*n*(-d*g + e*f)**(S(5)/2)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/(S(15)*e**(S(7)/2)) - S(2)*b*n*(-d*g + e*f)**(S(5)/2)*polylog(S(2), (-sqrt(e)*sqrt(f + g*x) - sqrt(-d*g + e*f))/(-sqrt(e)*sqrt(f + g*x) + sqrt(-d*g + e*f)))/e**(S(7)/2) + S(2)*(a + b*log(c*(d + e*x)**n))*(f + g*x)**(S(5)/2)/(S(5)*e) + (a + b*log(c*(d + e*x)**n))*(f + g*x)**(S(3)/2)*(-S(2)*d*g/S(3) + S(2)*e*f/S(3))/e**S(2) + S(2)*(a + b*log(c*(d + e*x)**n))*sqrt(f + g*x)*(-d*g + e*f)**S(2)/e**S(3) - S(2)*(a + b*log(c*(d + e*x)**n))*(-d*g + e*f)**(S(5)/2)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/e**(S(7)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d + e*x)**n))*(f + g*x)**(S(3)/2)/(d + e*x), x), x, -S(4)*b*n*(f + g*x)**(S(3)/2)/(S(9)*e) - S(16)*b*n*sqrt(f + g*x)*(-d*g + e*f)/(S(3)*e**S(2)) - S(4)*b*n*(-d*g + e*f)**(S(3)/2)*log(S(2)/(-sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f) + S(1)))*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/e**(S(5)/2) + S(2)*b*n*(-d*g + e*f)**(S(3)/2)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))**S(2)/e**(S(5)/2) + S(16)*b*n*(-d*g + e*f)**(S(3)/2)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/(S(3)*e**(S(5)/2)) - S(2)*b*n*(-d*g + e*f)**(S(3)/2)*polylog(S(2), (-sqrt(e)*sqrt(f + g*x) - sqrt(-d*g + e*f))/(-sqrt(e)*sqrt(f + g*x) + sqrt(-d*g + e*f)))/e**(S(5)/2) + S(2)*(a + b*log(c*(d + e*x)**n))*(f + g*x)**(S(3)/2)/(S(3)*e) + (a + b*log(c*(d + e*x)**n))*sqrt(f + g*x)*(-S(2)*d*g + S(2)*e*f)/e**S(2) - S(2)*(a + b*log(c*(d + e*x)**n))*(-d*g + e*f)**(S(3)/2)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/e**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d + e*x)**n))*sqrt(f + g*x)/(d + e*x), x), x, -S(4)*b*n*sqrt(f + g*x)/e - S(4)*b*n*sqrt(-d*g + e*f)*log(S(2)/(-sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f) + S(1)))*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/e**(S(3)/2) + S(2)*b*n*sqrt(-d*g + e*f)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))**S(2)/e**(S(3)/2) + S(4)*b*n*sqrt(-d*g + e*f)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/e**(S(3)/2) - S(2)*b*n*sqrt(-d*g + e*f)*polylog(S(2), (-sqrt(e)*sqrt(f + g*x) - sqrt(-d*g + e*f))/(-sqrt(e)*sqrt(f + g*x) + sqrt(-d*g + e*f)))/e**(S(3)/2) + (S(2)*a + S(2)*b*log(c*(d + e*x)**n))*sqrt(f + g*x)/e - S(2)*(a + b*log(c*(d + e*x)**n))*sqrt(-d*g + e*f)*atanh(sqrt(e)*sqrt(f + g*x)/sqrt(-d*g + e*f))/e**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x)*log(a + b*x)/(a + b*x), x), x, S(2)*sqrt(d + e*x)*log(a + b*x)/b - S(4)*sqrt(d + e*x)/b - S(2)*sqrt(-a*e + b*d)*log(a + b*x)*atanh(sqrt(b)*sqrt(d + e*x)/sqrt(-a*e + b*d))/b**(S(3)/2) - S(4)*sqrt(-a*e + b*d)*log(S(2)/(-sqrt(b)*sqrt(d + e*x)/sqrt(-a*e + b*d) + S(1)))*atanh(sqrt(b)*sqrt(d + e*x)/sqrt(-a*e + b*d))/b**(S(3)/2) + S(2)*sqrt(-a*e + b*d)*atanh(sqrt(b)*sqrt(d + e*x)/sqrt(-a*e + b*d))**S(2)/b**(S(3)/2) + S(4)*sqrt(-a*e + b*d)*atanh(sqrt(b)*sqrt(d + e*x)/sqrt(-a*e + b*d))/b**(S(3)/2) - S(2)*sqrt(-a*e + b*d)*polylog(S(2), (-sqrt(b)*sqrt(d + e*x) - sqrt(-a*e + b*d))/(-sqrt(b)*sqrt(d + e*x) + sqrt(-a*e + b*d)))/b**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**S(2)*(i + j*x)**m/(d*e + d*f*x), x), x, Integral((a + b*log(c*(e + f*x)))**S(2)*(i + j*x)**m/(d*e + d*f*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))*(i + j*x)**m/(d*e + d*f*x), x), x, Integral((a + b*log(c*(e + f*x)))*(i + j*x)**m/(d*e + d*f*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n*(i + j*x)**m/(d*e + d*f*x), x), x, Integral((a + b*log(c*(e + f*x)))**n*(i + j*x)**m/(d*e + d*f*x), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n*(i + j*x)**S(4)/(d*e + d*f*x), x), x, S(4)*S(3)**(-n + S(-1))*j**S(3)*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*(-e*j + f*i)*Gamma(n + S(1), (-S(3)*a - S(3)*b*log(c*(e + f*x)))/b)*exp(-S(3)*a/b)/(c**S(3)*d*f**S(5)) + S(4)**(-n + S(-1))*j**S(4)*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*Gamma(n + S(1), (-S(4)*a - S(4)*b*log(c*(e + f*x)))/b)*exp(-S(4)*a/b)/(c**S(4)*d*f**S(5)) + S(4)*j*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*(-e*j + f*i)**S(3)*Gamma(n + S(1), (-a - b*log(c*(e + f*x)))/b)*exp(-a/b)/(c*d*f**S(5)) + (a + b*log(c*(e + f*x)))**(n + S(1))*(-e*j + f*i)**S(4)/(b*d*f**S(5)*(n + S(1))) + S(3)*S(2)**(-n)*j**S(2)*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*(-e*j + f*i)**S(2)*Gamma(n + S(1), (-S(2)*a - S(2)*b*log(c*(e + f*x)))/b)*exp(-S(2)*a/b)/(c**S(2)*d*f**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n*(i + j*x)**S(3)/(d*e + d*f*x), x), x, S(3)*S(2)**(-n + S(-1))*j**S(2)*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*(-e*j + f*i)*Gamma(n + S(1), (-S(2)*a - S(2)*b*log(c*(e + f*x)))/b)*exp(-S(2)*a/b)/(c**S(2)*d*f**S(4)) + S(3)**(-n + S(-1))*j**S(3)*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*Gamma(n + S(1), (-S(3)*a - S(3)*b*log(c*(e + f*x)))/b)*exp(-S(3)*a/b)/(c**S(3)*d*f**S(4)) + S(3)*j*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*(-e*j + f*i)**S(2)*Gamma(n + S(1), (-a - b*log(c*(e + f*x)))/b)*exp(-a/b)/(c*d*f**S(4)) + (a + b*log(c*(e + f*x)))**(n + S(1))*(-e*j + f*i)**S(3)/(b*d*f**S(4)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n*(i + j*x)**S(2)/(d*e + d*f*x), x), x, S(2)**(-n + S(-1))*j**S(2)*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*Gamma(n + S(1), (-S(2)*a - S(2)*b*log(c*(e + f*x)))/b)*exp(-S(2)*a/b)/(c**S(2)*d*f**S(3)) + S(2)*j*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*(-e*j + f*i)*Gamma(n + S(1), (-a - b*log(c*(e + f*x)))/b)*exp(-a/b)/(c*d*f**S(3)) + (a + b*log(c*(e + f*x)))**(n + S(1))*(-e*j + f*i)**S(2)/(b*d*f**S(3)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n*(i + j*x)/(d*e + d*f*x), x), x, j*((-a - b*log(c*(e + f*x)))/b)**(-n)*(a + b*log(c*(e + f*x)))**n*Gamma(n + S(1), (-a - b*log(c*(e + f*x)))/b)*exp(-a/b)/(c*d*f**S(2)) + (a + b*log(c*(e + f*x)))**(n + S(1))*(-e*j + f*i)/(b*d*f**S(2)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n/(d*e + d*f*x), x), x, (a + b*log(c*(e + f*x)))**(n + S(1))/(b*d*f*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n/((i + j*x)*(d*e + d*f*x)), x), x, Integral((a + b*log(c*(e + f*x)))**n/((i + j*x)*(d*e + d*f*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n/((i + j*x)**S(2)*(d*e + d*f*x)), x), x, Integral((a + b*log(c*(e + f*x)))**n/((i + j*x)**S(2)*(d*e + d*f*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(e + f*x)))**n/((i + j*x)**S(3)*(d*e + d*f*x)), x), x, Integral((a + b*log(c*(e + f*x)))**n/((i + j*x)**S(3)*(d*e + d*f*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)**S(3)/(g + h*x), x), x, a*j*x*(-g*j + h*i)**S(2)/h**S(3) - b*p*q*(i + j*x)**S(3)/(S(9)*h) - b*p*q*(i + j*x)**S(2)*(-g*j + h*i)/(S(4)*h**S(2)) - b*j*p*q*x*(-g*j + h*i)**S(2)/h**S(3) + b*p*q*(-g*j + h*i)**S(3)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(4) - b*p*q*(i + j*x)**S(2)*(-e*j + f*i)/(S(6)*f*h) - b*j*p*q*x*(-e*j + f*i)*(-g*j + h*i)/(S(2)*f*h**S(2)) + b*j*(e + f*x)*(-g*j + h*i)**S(2)*log(c*(d*(e + f*x)**p)**q)/(f*h**S(3)) - b*j*p*q*x*(-e*j + f*i)**S(2)/(S(3)*f**S(2)*h) - b*p*q*(-e*j + f*i)**S(2)*(-g*j + h*i)*log(e + f*x)/(S(2)*f**S(2)*h**S(2)) - b*p*q*(-e*j + f*i)**S(3)*log(e + f*x)/(S(3)*f**S(3)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)**S(3)/(S(3)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)**S(2)*(-g*j/S(2) + h*i/S(2))/h**S(2) + (a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)**S(3)*log(f*(g + h*x)/(-e*h + f*g))/h**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)**S(2)/(g + h*x), x), x, a*j*x*(-g*j + h*i)/h**S(2) - b*p*q*(i + j*x)**S(2)/(S(4)*h) - b*j*p*q*x*(-g*j + h*i)/h**S(2) + b*p*q*(-g*j + h*i)**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(3) - b*j*p*q*x*(-e*j + f*i)/(S(2)*f*h) + b*j*(e + f*x)*(-g*j + h*i)*log(c*(d*(e + f*x)**p)**q)/(f*h**S(2)) - b*p*q*(-e*j + f*i)**S(2)*log(e + f*x)/(S(2)*f**S(2)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)**S(2)/(S(2)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)**S(2)*log(f*(g + h*x)/(-e*h + f*g))/h**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)/(g + h*x), x), x, a*j*x/h - b*j*p*q*x/h + b*p*q*(-g*j + h*i)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(2) + b*j*(e + f*x)*log(c*(d*(e + f*x)**p)**q)/(f*h) + (a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)*log(f*(g + h*x)/(-e*h + f*g))/h**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x), x), x, b*p*q*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h + (a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/((g + h*x)*(i + j*x)), x), x, b*p*q*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i) - b*p*q*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i) + (a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i) - (a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/((g + h*x)*(i + j*x)**S(2)), x), x, -b*f*p*q*log(e + f*x)/((-e*j + f*i)*(-g*j + h*i)) + b*f*p*q*log(i + j*x)/((-e*j + f*i)*(-g*j + h*i)) + b*h*p*q*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) - b*h*p*q*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) + h*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) - h*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) + (a + b*log(c*(d*(e + f*x)**p)**q))/((i + j*x)*(-g*j + h*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/((g + h*x)*(i + j*x)**S(3)), x), x, -b*f**S(2)*p*q*log(e + f*x)/(S(2)*(-e*j + f*i)**S(2)*(-g*j + h*i)) + b*f**S(2)*p*q*log(i + j*x)/(S(2)*(-e*j + f*i)**S(2)*(-g*j + h*i)) - b*f*h*p*q*log(e + f*x)/((-e*j + f*i)*(-g*j + h*i)**S(2)) + b*f*h*p*q*log(i + j*x)/((-e*j + f*i)*(-g*j + h*i)**S(2)) - b*f*p*q/(S(2)*(i + j*x)*(-e*j + f*i)*(-g*j + h*i)) + b*h**S(2)*p*q*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) - b*h**S(2)*p*q*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) - h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) + h*(a + b*log(c*(d*(e + f*x)**p)**q))/((i + j*x)*(-g*j + h*i)**S(2)) + (a/S(2) + b*log(c*(d*(e + f*x)**p)**q)/S(2))/((i + j*x)**S(2)*(-g*j + h*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(i + j*x)**S(3)/(g + h*x), x), x, -S(2)*a*b*j*p*q*x*(-g*j + h*i)**S(2)/h**S(3) - S(2)*a*b*j*p*q*x*(-e*j + f*i)*(-g*j + h*i)/(f*h**S(2)) - S(2)*a*b*j*p*q*x*(-e*j + f*i)**S(2)/(S(3)*f**S(2)*h) + b**S(2)*e*j**S(2)*p**S(2)*q**S(2)*x*(-g*j + h*i)/(S(2)*f*h**S(2)) + S(2)*b**S(2)*p**S(2)*q**S(2)*(i + j*x)**S(3)/(S(27)*h) + b**S(2)*j**S(2)*p**S(2)*q**S(2)*x**S(2)*(-g*j + h*i)/(S(4)*h**S(2)) + S(2)*b**S(2)*j*p**S(2)*q**S(2)*x*(-g*j + h*i)**S(2)/h**S(3) - S(2)*b**S(2)*p**S(2)*q**S(2)*(-g*j + h*i)**S(3)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h**S(4) + S(5)*b**S(2)*p**S(2)*q**S(2)*(i + j*x)**S(2)*(-e*j + f*i)/(S(18)*f*h) + S(2)*b**S(2)*j*p**S(2)*q**S(2)*x*(-e*j + f*i)*(-g*j + h*i)/(f*h**S(2)) - S(2)*b**S(2)*j*p*q*(e + f*x)*(-g*j + h*i)**S(2)*log(c*(d*(e + f*x)**p)**q)/(f*h**S(3)) + S(11)*b**S(2)*j*p**S(2)*q**S(2)*x*(-e*j + f*i)**S(2)/(S(9)*f**S(2)*h) - S(2)*b**S(2)*j*p*q*(e + f*x)*(-e*j + f*i)*(-g*j + h*i)*log(c*(d*(e + f*x)**p)**q)/(f**S(2)*h**S(2)) - S(2)*b**S(2)*j*p*q*(e + f*x)*(-e*j + f*i)**S(2)*log(c*(d*(e + f*x)**p)**q)/(S(3)*f**S(3)*h) + S(5)*b**S(2)*p**S(2)*q**S(2)*(-e*j + f*i)**S(3)*log(e + f*x)/(S(9)*f**S(3)*h) - S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)**S(3)/(S(9)*h) + S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)**S(3)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(4) - b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(i + j*x)**S(2)*(-e*j + f*i)/(S(3)*f*h) - b*j**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-g*j + h*i)/(S(2)*f**S(2)*h**S(2)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(i + j*x)**S(3)/(S(3)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-g*j + h*i)**S(3)*log(f*(g + h*x)/(-e*h + f*g))/h**S(4) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-g*j + h*i)**S(2)/(f*h**S(3)) + j**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)*(-g*j + h*i)/(S(2)*f**S(2)*h**S(2)) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*j + f*i)*(-g*j + h*i)/(f**S(2)*h**S(2)) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-e*j + f*i)**S(3)/(S(3)*f**S(3)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(i + j*x)**S(2)/(g + h*x), x), x, -S(2)*a*b*j*p*q*x*(-g*j + h*i)/h**S(2) - S(2)*a*b*j*p*q*x*(-e*j + f*i)/(f*h) + b**S(2)*e*j**S(2)*p**S(2)*q**S(2)*x/(S(2)*f*h) + b**S(2)*j**S(2)*p**S(2)*q**S(2)*x**S(2)/(S(4)*h) + S(2)*b**S(2)*j*p**S(2)*q**S(2)*x*(-g*j + h*i)/h**S(2) - S(2)*b**S(2)*p**S(2)*q**S(2)*(-g*j + h*i)**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h**S(3) + S(2)*b**S(2)*j*p**S(2)*q**S(2)*x*(-e*j + f*i)/(f*h) - S(2)*b**S(2)*j*p*q*(e + f*x)*(-g*j + h*i)*log(c*(d*(e + f*x)**p)**q)/(f*h**S(2)) - S(2)*b**S(2)*j*p*q*(e + f*x)*(-e*j + f*i)*log(c*(d*(e + f*x)**p)**q)/(f**S(2)*h) + S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(3) - b*j**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)/(S(2)*f**S(2)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-g*j + h*i)**S(2)*log(f*(g + h*x)/(-e*h + f*g))/h**S(3) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-g*j + h*i)/(f*h**S(2)) + j**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)/(S(2)*f**S(2)*h) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*j + f*i)/(f**S(2)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(i + j*x)/(g + h*x), x), x, -S(2)*a*b*j*p*q*x/h + S(2)*b**S(2)*j*p**S(2)*q**S(2)*x/h - S(2)*b**S(2)*p**S(2)*q**S(2)*(-g*j + h*i)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h**S(2) - S(2)*b**S(2)*j*p*q*(e + f*x)*log(c*(d*(e + f*x)**p)**q)/(f*h) + S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(2) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-g*j + h*i)*log(f*(g + h*x)/(-e*h + f*g))/h**S(2) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/(f*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(g + h*x), x), x, -S(2)*b**S(2)*p**S(2)*q**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h + S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/((g + h*x)*(i + j*x)), x), x, -S(2)*b**S(2)*p**S(2)*q**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i) + S(2)*b**S(2)*p**S(2)*q**S(2)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i) + S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i) - S(2)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/((g + h*x)*(i + j*x)**S(2)), x), x, S(2)*b**S(2)*f*p**S(2)*q**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)) - S(2)*b**S(2)*h*p**S(2)*q**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) + S(2)*b**S(2)*h*p**S(2)*q**S(2)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) + S(2)*b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(i + j*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)) + S(2)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) - S(2)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) - h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) - j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/((i + j*x)*(-e*j + f*i)*(-g*j + h*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/((g + h*x)*(i + j*x)**S(3)), x), x, b**S(2)*f**S(2)*p**S(2)*q**S(2)*log(e + f*x)/((-e*j + f*i)**S(2)*(-g*j + h*i)) - b**S(2)*f**S(2)*p**S(2)*q**S(2)*log(i + j*x)/((-e*j + f*i)**S(2)*(-g*j + h*i)) + b**S(2)*f**S(2)*p**S(2)*q**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)**S(2)*(-g*j + h*i)) + S(2)*b**S(2)*f*h*p**S(2)*q**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)**S(2)) - S(2)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) + S(2)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) + b*f**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(i + j*x)/(-e*j + f*i))/((-e*j + f*i)**S(2)*(-g*j + h*i)) + S(2)*b*f*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(i + j*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)**S(2)) - b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))/((i + j*x)*(-e*j + f*i)*(-g*j + h*i)) + S(2)*b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) - S(2)*b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) - f**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(2)*(-e*j + f*i)**S(2)*(-g*j + h*i)) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) - h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) - h*j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/((i + j*x)*(-e*j + f*i)*(-g*j + h*i)**S(2)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(2)/(S(2)*(i + j*x)**S(2)*(-g*j + h*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(i + j*x)**S(3)/(g + h*x), x), x, S(6)*a*b**S(2)*j*p**S(2)*q**S(2)*x*(-g*j + h*i)**S(2)/h**S(3) + S(6)*a*b**S(2)*j*p**S(2)*q**S(2)*x*(-e*j + f*i)*(-g*j + h*i)/(f*h**S(2)) + S(6)*a*b**S(2)*j*p**S(2)*q**S(2)*x*(-e*j + f*i)**S(2)/(f**S(2)*h) - S(3)*b**S(3)*e*j**S(2)*p**S(3)*q**S(3)*x*(-g*j + h*i)/(S(4)*f*h**S(2)) - S(3)*b**S(3)*e*j**S(2)*p**S(3)*q**S(3)*x*(-e*j + f*i)/(S(2)*f**S(2)*h) - S(3)*b**S(3)*j**S(2)*p**S(3)*q**S(3)*x**S(2)*(-g*j + h*i)/(S(8)*h**S(2)) - S(6)*b**S(3)*j*p**S(3)*q**S(3)*x*(-g*j + h*i)**S(2)/h**S(3) + S(6)*b**S(3)*p**S(3)*q**S(3)*(-g*j + h*i)**S(3)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/h**S(4) - S(3)*b**S(3)*j**S(2)*p**S(3)*q**S(3)*x**S(2)*(-e*j + f*i)/(S(4)*f*h) - S(6)*b**S(3)*j*p**S(3)*q**S(3)*x*(-e*j + f*i)*(-g*j + h*i)/(f*h**S(2)) + S(6)*b**S(3)*j*p**S(2)*q**S(2)*(e + f*x)*(-g*j + h*i)**S(2)*log(c*(d*(e + f*x)**p)**q)/(f*h**S(3)) - S(6)*b**S(3)*j*p**S(3)*q**S(3)*x*(-e*j + f*i)**S(2)/(f**S(2)*h) + S(6)*b**S(3)*j*p**S(2)*q**S(2)*(e + f*x)*(-e*j + f*i)*(-g*j + h*i)*log(c*(d*(e + f*x)**p)**q)/(f**S(2)*h**S(2)) - S(2)*b**S(3)*j**S(3)*p**S(3)*q**S(3)*(e + f*x)**S(3)/(S(27)*f**S(3)*h) + S(6)*b**S(3)*j*p**S(2)*q**S(2)*(e + f*x)*(-e*j + f*i)**S(2)*log(c*(d*(e + f*x)**p)**q)/(f**S(3)*h) - S(6)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)**S(3)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h**S(4) + S(3)*b**S(2)*j**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-g*j + h*i)/(S(4)*f**S(2)*h**S(2)) + S(2)*b**S(2)*j**S(3)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(3)/(S(9)*f**S(3)*h) + S(3)*b**S(2)*j**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)*(-e*j + f*i)/(S(2)*f**S(3)*h) + S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-g*j + h*i)**S(3)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(4) - S(3)*b*j*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-g*j + h*i)**S(2)/(f*h**S(3)) - S(3)*b*j**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)*(-g*j + h*i)/(S(4)*f**S(2)*h**S(2)) - S(3)*b*j*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*j + f*i)*(-g*j + h*i)/(f**S(2)*h**S(2)) - b*j**S(3)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(3)/(S(3)*f**S(3)*h) - S(3)*b*j**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)*(-e*j + f*i)/(S(2)*f**S(3)*h) - S(3)*b*j*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*j + f*i)**S(2)/(f**S(3)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(-g*j + h*i)**S(3)*log(f*(g + h*x)/(-e*h + f*g))/h**S(4) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-g*j + h*i)**S(2)/(f*h**S(3)) + j**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(2)*(-g*j + h*i)/(S(2)*f**S(2)*h**S(2)) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-e*j + f*i)*(-g*j + h*i)/(f**S(2)*h**S(2)) + j**S(3)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(3)/(S(3)*f**S(3)*h) + j**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(2)*(-e*j + f*i)/(f**S(3)*h) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-e*j + f*i)**S(2)/(f**S(3)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(i + j*x)**S(2)/(g + h*x), x), x, S(6)*a*b**S(2)*j*p**S(2)*q**S(2)*x*(-g*j + h*i)/h**S(2) + S(6)*a*b**S(2)*j*p**S(2)*q**S(2)*x*(-e*j + f*i)/(f*h) - S(3)*b**S(3)*e*j**S(2)*p**S(3)*q**S(3)*x/(S(4)*f*h) - S(3)*b**S(3)*j**S(2)*p**S(3)*q**S(3)*x**S(2)/(S(8)*h) - S(6)*b**S(3)*j*p**S(3)*q**S(3)*x*(-g*j + h*i)/h**S(2) + S(6)*b**S(3)*p**S(3)*q**S(3)*(-g*j + h*i)**S(2)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/h**S(3) - S(6)*b**S(3)*j*p**S(3)*q**S(3)*x*(-e*j + f*i)/(f*h) + S(6)*b**S(3)*j*p**S(2)*q**S(2)*(e + f*x)*(-g*j + h*i)*log(c*(d*(e + f*x)**p)**q)/(f*h**S(2)) + S(6)*b**S(3)*j*p**S(2)*q**S(2)*(e + f*x)*(-e*j + f*i)*log(c*(d*(e + f*x)**p)**q)/(f**S(2)*h) - S(6)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)**S(2)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h**S(3) + S(3)*b**S(2)*j**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(e + f*x)**S(2)/(S(4)*f**S(2)*h) + S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-g*j + h*i)**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(3) - S(3)*b*j*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-g*j + h*i)/(f*h**S(2)) - S(3)*b*j**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)**S(2)/(S(4)*f**S(2)*h) - S(3)*b*j*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)*(-e*j + f*i)/(f**S(2)*h) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(-g*j + h*i)**S(2)*log(f*(g + h*x)/(-e*h + f*g))/h**S(3) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-g*j + h*i)/(f*h**S(2)) + j**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)**S(2)/(S(2)*f**S(2)*h) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)*(-e*j + f*i)/(f**S(2)*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(i + j*x)/(g + h*x), x), x, S(6)*a*b**S(2)*j*p**S(2)*q**S(2)*x/h - S(6)*b**S(3)*j*p**S(3)*q**S(3)*x/h + S(6)*b**S(3)*p**S(3)*q**S(3)*(-g*j + h*i)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/h**S(2) + S(6)*b**S(3)*j*p**S(2)*q**S(2)*(e + f*x)*log(c*(d*(e + f*x)**p)**q)/(f*h) - S(6)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*(-g*j + h*i)*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h**S(2) + S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(-g*j + h*i)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h**S(2) - S(3)*b*j*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/(f*h) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(-g*j + h*i)*log(f*(g + h*x)/(-e*h + f*g))/h**S(2) + j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)/(f*h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(g + h*x), x), x, S(6)*b**S(3)*p**S(3)*q**S(3)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/h - S(6)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/h + S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/h + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(g + h*x)/(-e*h + f*g))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/((g + h*x)*(i + j*x)), x), x, S(6)*b**S(3)*p**S(3)*q**S(3)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i) - S(6)*b**S(3)*p**S(3)*q**S(3)*polylog(S(4), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i) - S(6)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i) + S(6)*b**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i) + S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i) - S(3)*b*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i) - (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/((g + h*x)*(i + j*x)**S(2)), x), x, -S(6)*b**S(3)*f*p**S(3)*q**S(3)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)) + S(6)*b**S(3)*h*p**S(3)*q**S(3)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) - S(6)*b**S(3)*h*p**S(3)*q**S(3)*polylog(S(4), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) + S(6)*b**S(2)*f*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)) - S(6)*b**S(2)*h*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) + S(6)*b**S(2)*h*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) + S(3)*b*f*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)) + S(3)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) - S(3)*b*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) + h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i)**S(2) - h*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i)**S(2) - j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)/((i + j*x)*(-e*j + f*i)*(-g*j + h*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/((g + h*x)*(i + j*x)**S(3)), x), x, -S(3)*b**S(3)*f**S(2)*p**S(3)*q**S(3)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)**S(2)*(-g*j + h*i)) - S(3)*b**S(3)*f**S(2)*p**S(3)*q**S(3)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)**S(2)*(-g*j + h*i)) - S(6)*b**S(3)*f*h*p**S(3)*q**S(3)*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)**S(2)) + S(6)*b**S(3)*h**S(2)*p**S(3)*q**S(3)*polylog(S(4), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) - S(6)*b**S(3)*h**S(2)*p**S(3)*q**S(3)*polylog(S(4), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) - S(3)*b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*log(f*(i + j*x)/(-e*j + f*i))/((-e*j + f*i)**S(2)*(-g*j + h*i)) + S(3)*b**S(2)*f**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)**S(2)*(-g*j + h*i)) + S(6)*b**S(2)*f*h*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)**S(2)) - S(6)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) + S(6)*b**S(2)*h**S(2)*p**S(2)*q**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))*polylog(S(3), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) + S(3)*b*f**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/(S(2)*(-e*j + f*i)**S(2)*(-g*j + h*i)) + S(3)*b*f*h*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*log(f*(i + j*x)/(-e*j + f*i))/((-e*j + f*i)*(-g*j + h*i)**S(2)) + S(3)*b*f*j*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(e + f*x)/(S(2)*(i + j*x)*(-e*j + f*i)**S(2)*(-g*j + h*i)) + S(3)*b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -h*(e + f*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) - S(3)*b*h**S(2)*p*q*(a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*polylog(S(2), -j*(e + f*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) - f**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(2)*(-e*j + f*i)**S(2)*(-g*j + h*i)) + h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(g + h*x)/(-e*h + f*g))/(-g*j + h*i)**S(3) - h**S(2)*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*log(f*(i + j*x)/(-e*j + f*i))/(-g*j + h*i)**S(3) - h*j*(a + b*log(c*(d*(e + f*x)**p)**q))**S(3)*(e + f*x)/((i + j*x)*(-e*j + f*i)*(-g*j + h*i)**S(2)) + (a + b*log(c*(d*(e + f*x)**p)**q))**S(3)/(S(2)*(i + j*x)**S(2)*(-g*j + h*i)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((i + j*x)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), x, Integral((i + j*x)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)*(i + j*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)*(i + j*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)*(i + j*x)**S(2)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)*(i + j*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((i + j*x)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)), x), x, Integral((i + j*x)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)*(i + j*x)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)*(i + j*x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)*(i + j*x)**S(2)), x), x, Integral(S(1)/((a + b*log(c*(d*(e + f*x)**p)**q))**S(2)*(g + h*x)*(i + j*x)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(g + h*x**S(2)), x), x, -b*p*q*polylog(S(2), sqrt(h)*(-e - f*x)/(-e*sqrt(h) + f*sqrt(-g)))/(S(2)*sqrt(h)*sqrt(-g)) + b*p*q*polylog(S(2), sqrt(h)*(e + f*x)/(e*sqrt(h) + f*sqrt(-g)))/(S(2)*sqrt(h)*sqrt(-g)) - (a/S(2) + b*log(c*(d*(e + f*x)**p)**q)/S(2))*log(f*(sqrt(h)*x + sqrt(-g))/(-e*sqrt(h) + f*sqrt(-g)))/(sqrt(h)*sqrt(-g)) + (a/S(2) + b*log(c*(d*(e + f*x)**p)**q)/S(2))*log(f*(-sqrt(h)*x + sqrt(-g))/(e*sqrt(h) + f*sqrt(-g)))/(sqrt(h)*sqrt(-g)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/sqrt(h*x**S(2) + S(2)), x), x, -b*p*q*log(sqrt(S(2))*f*exp(asinh(sqrt(S(2))*sqrt(h)*x/S(2)))/(e*sqrt(h) - sqrt(e**S(2)*h + S(2)*f**S(2))) + S(1))*asinh(sqrt(S(2))*sqrt(h)*x/S(2))/sqrt(h) - b*p*q*log(sqrt(S(2))*f*exp(asinh(sqrt(S(2))*sqrt(h)*x/S(2)))/(e*sqrt(h) + sqrt(e**S(2)*h + S(2)*f**S(2))) + S(1))*asinh(sqrt(S(2))*sqrt(h)*x/S(2))/sqrt(h) + b*p*q*asinh(sqrt(S(2))*sqrt(h)*x/S(2))**S(2)/(S(2)*sqrt(h)) - b*p*q*polylog(S(2), -sqrt(S(2))*f*exp(asinh(sqrt(S(2))*sqrt(h)*x/S(2)))/(e*sqrt(h) - sqrt(e**S(2)*h + S(2)*f**S(2))))/sqrt(h) - b*p*q*polylog(S(2), -sqrt(S(2))*f*exp(asinh(sqrt(S(2))*sqrt(h)*x/S(2)))/(e*sqrt(h) + sqrt(e**S(2)*h + S(2)*f**S(2))))/sqrt(h) + (a + b*log(c*(d*(e + f*x)**p)**q))*asinh(sqrt(S(2))*sqrt(h)*x/S(2))/sqrt(h), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/sqrt(g + h*x**S(2)), x), x, -b*sqrt(g)*p*q*sqrt(S(1) + h*x**S(2)/g)*log(f*sqrt(g)*exp(asinh(sqrt(h)*x/sqrt(g)))/(e*sqrt(h) - sqrt(e**S(2)*h + f**S(2)*g)) + S(1))*asinh(sqrt(h)*x/sqrt(g))/(sqrt(h)*sqrt(g + h*x**S(2))) - b*sqrt(g)*p*q*sqrt(S(1) + h*x**S(2)/g)*log(f*sqrt(g)*exp(asinh(sqrt(h)*x/sqrt(g)))/(e*sqrt(h) + sqrt(e**S(2)*h + f**S(2)*g)) + S(1))*asinh(sqrt(h)*x/sqrt(g))/(sqrt(h)*sqrt(g + h*x**S(2))) + b*sqrt(g)*p*q*sqrt(S(1) + h*x**S(2)/g)*asinh(sqrt(h)*x/sqrt(g))**S(2)/(S(2)*sqrt(h)*sqrt(g + h*x**S(2))) - b*sqrt(g)*p*q*sqrt(S(1) + h*x**S(2)/g)*polylog(S(2), -f*sqrt(g)*exp(asinh(sqrt(h)*x/sqrt(g)))/(e*sqrt(h) - sqrt(e**S(2)*h + f**S(2)*g)))/(sqrt(h)*sqrt(g + h*x**S(2))) - b*sqrt(g)*p*q*sqrt(S(1) + h*x**S(2)/g)*polylog(S(2), -f*sqrt(g)*exp(asinh(sqrt(h)*x/sqrt(g)))/(e*sqrt(h) + sqrt(e**S(2)*h + f**S(2)*g)))/(sqrt(h)*sqrt(g + h*x**S(2))) + sqrt(g)*sqrt(S(1) + h*x**S(2)/g)*(a + b*log(c*(d*(e + f*x)**p)**q))*asinh(sqrt(h)*x/sqrt(g))/(sqrt(h)*sqrt(g + h*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(-h*x + S(2))*sqrt(h*x + S(2))), x), x, -b*p*q*log(S(2)*f*exp(I*asin(h*x/S(2)))/(I*e*h - sqrt(-e**S(2)*h**S(2) + S(4)*f**S(2))) + S(1))*asin(h*x/S(2))/h - b*p*q*log(S(2)*f*exp(I*asin(h*x/S(2)))/(I*e*h + sqrt(-e**S(2)*h**S(2) + S(4)*f**S(2))) + S(1))*asin(h*x/S(2))/h + I*b*p*q*asin(h*x/S(2))**S(2)/(S(2)*h) + I*b*p*q*polylog(S(2), -S(2)*f*exp(I*asin(h*x/S(2)))/(I*e*h - sqrt(-e**S(2)*h**S(2) + S(4)*f**S(2))))/h + I*b*p*q*polylog(S(2), -S(2)*f*exp(I*asin(h*x/S(2)))/(I*e*h + sqrt(-e**S(2)*h**S(2) + S(4)*f**S(2))))/h + (a + b*log(c*(d*(e + f*x)**p)**q))*asin(h*x/S(2))/h, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d*(e + f*x)**p)**q))/(sqrt(g - h*x)*sqrt(g + h*x)), x), x, -b*g*p*q*sqrt(S(1) - h**S(2)*x**S(2)/g**S(2))*log(f*g*exp(I*asin(h*x/g))/(I*e*h - sqrt(-e**S(2)*h**S(2) + f**S(2)*g**S(2))) + S(1))*asin(h*x/g)/(h*sqrt(g - h*x)*sqrt(g + h*x)) - b*g*p*q*sqrt(S(1) - h**S(2)*x**S(2)/g**S(2))*log(f*g*exp(I*asin(h*x/g))/(I*e*h + sqrt(-e**S(2)*h**S(2) + f**S(2)*g**S(2))) + S(1))*asin(h*x/g)/(h*sqrt(g - h*x)*sqrt(g + h*x)) + I*b*g*p*q*sqrt(S(1) - h**S(2)*x**S(2)/g**S(2))*asin(h*x/g)**S(2)/(S(2)*h*sqrt(g - h*x)*sqrt(g + h*x)) + I*b*g*p*q*sqrt(S(1) - h**S(2)*x**S(2)/g**S(2))*polylog(S(2), -f*g*exp(I*asin(h*x/g))/(I*e*h - sqrt(-e**S(2)*h**S(2) + f**S(2)*g**S(2))))/(h*sqrt(g - h*x)*sqrt(g + h*x)) + I*b*g*p*q*sqrt(S(1) - h**S(2)*x**S(2)/g**S(2))*polylog(S(2), -f*g*exp(I*asin(h*x/g))/(I*e*h + sqrt(-e**S(2)*h**S(2) + f**S(2)*g**S(2))))/(h*sqrt(g - h*x)*sqrt(g + h*x)) + g*sqrt(S(1) - h**S(2)*x**S(2)/g**S(2))*(a + b*log(c*(d*(e + f*x)**p)**q))*asin(h*x/g)/(h*sqrt(g - h*x)*sqrt(g + h*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(2)*e/(e + f*x))/(e**S(2) - f**S(2)*x**S(2)), x), x, polylog(S(2), (-e + f*x)/(e + f*x))/(S(2)*e*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(S(2)*e/(e + f*x)))/(e**S(2) - f**S(2)*x**S(2)), x), x, a*atanh(f*x/e)/(e*f) + b*polylog(S(2), (-e + f*x)/(e + f*x))/(S(2)*e*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e/(e + f*x))/(e**S(2) - f**S(2)*x**S(2)), x), x, -log(S(2))*atanh(f*x/e)/(e*f) + polylog(S(2), (-e + f*x)/(e + f*x))/(S(2)*e*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(e/(e + f*x)))/(e**S(2) - f**S(2)*x**S(2)), x), x, b*polylog(S(2), (-e + f*x)/(e + f*x))/(S(2)*e*f) + (a - b*log(S(2)))*atanh(f*x/e)/(e*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x)/(c + d/x**S(2)), x), x, -sqrt(d)*log(b*(sqrt(d) - x*sqrt(-c))/(a*sqrt(-c) + b*sqrt(d)))*log(a + b*x)/(S(2)*(-c)**(S(3)/2)) + sqrt(d)*log(-b*(sqrt(d) + x*sqrt(-c))/(a*sqrt(-c) - b*sqrt(d)))*log(a + b*x)/(S(2)*(-c)**(S(3)/2)) + sqrt(d)*polylog(S(2), sqrt(-c)*(a + b*x)/(a*sqrt(-c) - b*sqrt(d)))/(S(2)*(-c)**(S(3)/2)) - sqrt(d)*polylog(S(2), sqrt(-c)*(a + b*x)/(a*sqrt(-c) + b*sqrt(d)))/(S(2)*(-c)**(S(3)/2)) - x/c + (a + b*x)*log(a + b*x)/(b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)**S(3)/(d + e*x**S(2)), x), x, -S(3)*n**S(3)*polylog(S(4), sqrt(e)*(-a - b*x)/(-a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) + S(3)*n**S(3)*polylog(S(4), sqrt(e)*(a + b*x)/(a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) + S(3)*n**S(2)*log(c*(a + b*x)**n)*polylog(S(3), sqrt(e)*(-a - b*x)/(-a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) - S(3)*n**S(2)*log(c*(a + b*x)**n)*polylog(S(3), sqrt(e)*(a + b*x)/(a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) - S(3)*n*log(c*(a + b*x)**n)**S(2)*polylog(S(2), sqrt(e)*(-a - b*x)/(-a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)) + S(3)*n*log(c*(a + b*x)**n)**S(2)*polylog(S(2), sqrt(e)*(a + b*x)/(a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)) - log(c*(a + b*x)**n)**S(3)*log(b*(sqrt(e)*x + sqrt(-d))/(-a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)) + log(c*(a + b*x)**n)**S(3)*log(b*(-sqrt(e)*x + sqrt(-d))/(a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)**S(2)/(d + e*x**S(2)), x), x, n**S(2)*polylog(S(3), sqrt(e)*(-a - b*x)/(-a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) - n**S(2)*polylog(S(3), sqrt(e)*(a + b*x)/(a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) - n*log(c*(a + b*x)**n)*polylog(S(2), sqrt(e)*(-a - b*x)/(-a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) + n*log(c*(a + b*x)**n)*polylog(S(2), sqrt(e)*(a + b*x)/(a*sqrt(e) + b*sqrt(-d)))/(sqrt(e)*sqrt(-d)) - log(c*(a + b*x)**n)**S(2)*log(b*(sqrt(e)*x + sqrt(-d))/(-a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)) + log(c*(a + b*x)**n)**S(2)*log(b*(-sqrt(e)*x + sqrt(-d))/(a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)/(d + e*x**S(2)), x), x, -n*polylog(S(2), sqrt(e)*(-a - b*x)/(-a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)) + n*polylog(S(2), sqrt(e)*(a + b*x)/(a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)) - log(c*(a + b*x)**n)*log(b*(sqrt(e)*x + sqrt(-d))/(-a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)) + log(c*(a + b*x)**n)*log(b*(-sqrt(e)*x + sqrt(-d))/(a*sqrt(e) + b*sqrt(-d)))/(S(2)*sqrt(e)*sqrt(-d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*log(c*(a + b*x)**n)), x), x, Integral(S(1)/((d + e*x**S(2))*log(c*(a + b*x)**n)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*log(c + d*x)/(a + b*x**S(2)), x), x, a**S(2)*log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*b**S(3)) + a**S(2)*log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*b**S(3)) + a**S(2)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*b**S(3)) + a**S(2)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*b**S(3)) + a*c**S(2)*log(c + d*x)/(S(2)*b**S(2)*d**S(2)) - a*c*x/(S(2)*b**S(2)*d) - a*x**S(2)*log(c + d*x)/(S(2)*b**S(2)) + a*x**S(2)/(S(4)*b**S(2)) - c**S(4)*log(c + d*x)/(S(4)*b*d**S(4)) + c**S(3)*x/(S(4)*b*d**S(3)) - c**S(2)*x**S(2)/(S(8)*b*d**S(2)) + c*x**S(3)/(S(12)*b*d) + x**S(4)*log(c + d*x)/(S(4)*b) - x**S(4)/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c + d*x)/(a + b*x**S(2)), x), x, a*x/b**S(2) - a*(c + d*x)*log(c + d*x)/(b**S(2)*d) + c**S(3)*log(c + d*x)/(S(3)*b*d**S(3)) - c**S(2)*x/(S(3)*b*d**S(2)) + c*x**S(2)/(S(6)*b*d) + x**S(3)*log(c + d*x)/(S(3)*b) - x**S(3)/(S(9)*b) - (-a)**(S(3)/2)*log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*b**(S(5)/2)) + (-a)**(S(3)/2)*log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*b**(S(5)/2)) - (-a)**(S(3)/2)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*b**(S(5)/2)) + (-a)**(S(3)/2)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c + d*x)/(a + b*x**S(2)), x), x, -a*log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*b**S(2)) - a*log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*b**S(2)) - a*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*b**S(2)) - a*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*b**S(2)) - c**S(2)*log(c + d*x)/(S(2)*b*d**S(2)) + c*x/(S(2)*b*d) + x**S(2)*log(c + d*x)/(S(2)*b) - x**S(2)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c + d*x)/(a + b*x**S(2)), x), x, -x/b + (c + d*x)*log(c + d*x)/(b*d) - sqrt(-a)*log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*b**(S(3)/2)) + sqrt(-a)*log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*b**(S(3)/2)) - sqrt(-a)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*b**(S(3)/2)) + sqrt(-a)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c + d*x)/(a + b*x**S(2)), x), x, log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*b) + log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*b) + polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*b) + polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(a + b*x**S(2)), x), x, -log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*sqrt(b)*sqrt(-a)) + log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*sqrt(b)*sqrt(-a)) - polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*sqrt(b)*sqrt(-a)) + polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*sqrt(b)*sqrt(-a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x*(a + b*x**S(2))), x), x, log(-d*x/c)*log(c + d*x)/a - log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*a) - log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*a) + polylog(S(2), (c + d*x)/c)/a - polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*a) - polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x**S(2)*(a + b*x**S(2))), x), x, -sqrt(b)*log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*(-a)**(S(3)/2)) + sqrt(b)*log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*(-a)**(S(3)/2)) - sqrt(b)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*(-a)**(S(3)/2)) + sqrt(b)*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*(-a)**(S(3)/2)) - log(c + d*x)/(a*x) + d*log(x)/(a*c) - d*log(c + d*x)/(a*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x**S(3)*(a + b*x**S(2))), x), x, -log(c + d*x)/(S(2)*a*x**S(2)) - d/(S(2)*a*c*x) - d**S(2)*log(x)/(S(2)*a*c**S(2)) + d**S(2)*log(c + d*x)/(S(2)*a*c**S(2)) - b*log(-d*x/c)*log(c + d*x)/a**S(2) + b*log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/(S(2)*a**S(2)) + b*log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/(S(2)*a**S(2)) - b*polylog(S(2), (c + d*x)/c)/a**S(2) + b*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/(S(2)*a**S(2)) + b*polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*log(c + d*x)/(a + b*x**S(3)), x), x, -a*log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**S(2)) - a*log(-d*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**S(2)) - a*log((S(-1))**(S(1)/3)*d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**S(2)) - a*polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**S(2)) - a*polylog(S(2), b**(S(1)/3)*(c + d*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**S(2)) - a*polylog(S(2), b**(S(1)/3)*(c + d*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**S(2)) + c**S(3)*log(c + d*x)/(S(3)*b*d**S(3)) - c**S(2)*x/(S(3)*b*d**S(2)) + c*x**S(2)/(S(6)*b*d) + x**S(3)*log(c + d*x)/(S(3)*b) - x**S(3)/(S(9)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c + d*x)/(a + b*x**S(3)), x), x, a**(S(2)/3)*log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**(S(5)/3)) - (S(-1))**(S(1)/3)*a**(S(2)/3)*log(d*(a**(S(1)/3) - (S(-1))**(S(1)/3)*b**(S(1)/3)*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**(S(5)/3)) + (S(-1))**(S(2)/3)*a**(S(2)/3)*log(-d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**(S(5)/3)) + a**(S(2)/3)*polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**(S(5)/3)) - (S(-1))**(S(1)/3)*a**(S(2)/3)*polylog(S(2), (S(-1))**(S(1)/3)*b**(S(1)/3)*(c + d*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))/(S(3)*b**(S(5)/3)) + (S(-1))**(S(2)/3)*a**(S(2)/3)*polylog(S(2), (S(-1))**(S(2)/3)*b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))/(S(3)*b**(S(5)/3)) - c**S(2)*log(c + d*x)/(S(2)*b*d**S(2)) + c*x/(S(2)*b*d) + x**S(2)*log(c + d*x)/(S(2)*b) - x**S(2)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c + d*x)/(a + b*x**S(3)), x), x, -a**(S(1)/3)*log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**(S(4)/3)) - (S(-1))**(S(2)/3)*a**(S(1)/3)*log(d*(a**(S(1)/3) - (S(-1))**(S(1)/3)*b**(S(1)/3)*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**(S(4)/3)) + (S(-1))**(S(1)/3)*a**(S(1)/3)*log(-d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b**(S(4)/3)) - a**(S(1)/3)*polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**(S(4)/3)) - (S(-1))**(S(2)/3)*a**(S(1)/3)*polylog(S(2), (S(-1))**(S(1)/3)*b**(S(1)/3)*(c + d*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))/(S(3)*b**(S(4)/3)) + (S(-1))**(S(1)/3)*a**(S(1)/3)*polylog(S(2), (S(-1))**(S(2)/3)*b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))/(S(3)*b**(S(4)/3)) - x/b + (c + d*x)*log(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c + d*x)/(a + b*x**S(3)), x), x, log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b) + log(-d*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b) + log((S(-1))**(S(1)/3)*d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*b) + polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b) + polylog(S(2), b**(S(1)/3)*(c + d*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b) + polylog(S(2), b**(S(1)/3)*(c + d*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c + d*x)/(a + b*x**S(3)), x), x, -log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(1)/3)*b**(S(2)/3)) + (S(-1))**(S(1)/3)*log(d*(a**(S(1)/3) - (S(-1))**(S(1)/3)*b**(S(1)/3)*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(1)/3)*b**(S(2)/3)) - (S(-1))**(S(2)/3)*log(-d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(1)/3)*b**(S(2)/3)) - polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*a**(S(1)/3)*b**(S(2)/3)) + (S(-1))**(S(1)/3)*polylog(S(2), (S(-1))**(S(1)/3)*b**(S(1)/3)*(c + d*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(1)/3)*b**(S(2)/3)) - (S(-1))**(S(2)/3)*polylog(S(2), (S(-1))**(S(2)/3)*b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(1)/3)*b**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(a + b*x**S(3)), x), x, log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(2)/3)*b**(S(1)/3)) + (S(-1))**(S(2)/3)*log(d*(a**(S(1)/3) - (S(-1))**(S(1)/3)*b**(S(1)/3)*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(2)/3)*b**(S(1)/3)) - (S(-1))**(S(1)/3)*log(-d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(2)/3)*b**(S(1)/3)) + polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*a**(S(2)/3)*b**(S(1)/3)) + (S(-1))**(S(2)/3)*polylog(S(2), (S(-1))**(S(1)/3)*b**(S(1)/3)*(c + d*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(2)/3)*b**(S(1)/3)) - (S(-1))**(S(1)/3)*polylog(S(2), (S(-1))**(S(2)/3)*b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(2)/3)*b**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x*(a + b*x**S(3))), x), x, log(-d*x/c)*log(c + d*x)/a - log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a) - log(-d*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a) - log((S(-1))**(S(1)/3)*d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a) + polylog(S(2), (c + d*x)/c)/a - polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*a) - polylog(S(2), b**(S(1)/3)*(c + d*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*a) - polylog(S(2), b**(S(1)/3)*(c + d*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x**S(2)*(a + b*x**S(3))), x), x, -log(c + d*x)/(a*x) + d*log(x)/(a*c) - d*log(c + d*x)/(a*c) + b**(S(1)/3)*log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(4)/3)) - (S(-1))**(S(1)/3)*b**(S(1)/3)*log(d*(a**(S(1)/3) - (S(-1))**(S(1)/3)*b**(S(1)/3)*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(4)/3)) + (S(-1))**(S(2)/3)*b**(S(1)/3)*log(-d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(4)/3)) + b**(S(1)/3)*polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*a**(S(4)/3)) - (S(-1))**(S(1)/3)*b**(S(1)/3)*polylog(S(2), (S(-1))**(S(1)/3)*b**(S(1)/3)*(c + d*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(4)/3)) + (S(-1))**(S(2)/3)*b**(S(1)/3)*polylog(S(2), (S(-1))**(S(2)/3)*b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x**S(3)*(a + b*x**S(3))), x), x, -log(c + d*x)/(S(2)*a*x**S(2)) - d/(S(2)*a*c*x) - d**S(2)*log(x)/(S(2)*a*c**S(2)) + d**S(2)*log(c + d*x)/(S(2)*a*c**S(2)) - b**(S(2)/3)*log(-d*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(5)/3)) - (S(-1))**(S(2)/3)*b**(S(2)/3)*log(d*(a**(S(1)/3) - (S(-1))**(S(1)/3)*b**(S(1)/3)*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(5)/3)) + (S(-1))**(S(1)/3)*b**(S(2)/3)*log(-d*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))*log(c + d*x)/(S(3)*a**(S(5)/3)) - b**(S(2)/3)*polylog(S(2), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*a**(S(5)/3)) - (S(-1))**(S(2)/3)*b**(S(2)/3)*polylog(S(2), (S(-1))**(S(1)/3)*b**(S(1)/3)*(c + d*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(5)/3)) + (S(-1))**(S(1)/3)*b**(S(2)/3)*polylog(S(2), (S(-1))**(S(2)/3)*b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + (S(-1))**(S(2)/3)*b**(S(1)/3)*c))/(S(3)*a**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c + d*x)/(a + b*x**S(4)), x), x, -x/b + (c + d*x)*log(c + d*x)/(b*d) - (-a)**(S(1)/4)*log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b**(S(5)/4)) + (-a)**(S(1)/4)*log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b**(S(5)/4)) - (-a)**(S(1)/4)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*b**(S(5)/4)) + (-a)**(S(1)/4)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*b**(S(5)/4)) - sqrt(-sqrt(-a))*log(-d*(b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*b**(S(5)/4)) + sqrt(-sqrt(-a))*log(d*(-b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*b**(S(5)/4)) - sqrt(-sqrt(-a))*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))/(S(4)*b**(S(5)/4)) + sqrt(-sqrt(-a))*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))/(S(4)*b**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c + d*x)/(a + b*x**S(4)), x), x, log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b) + log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b) + log(-d*(b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b) + log(d*(-b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*b) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*b) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))/(S(4)*b) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c + d*x)/(a + b*x**S(4)), x), x, -log(-d*(b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*b**(S(3)/4)*sqrt(-sqrt(-a))) + log(d*(-b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*b**(S(3)/4)*sqrt(-sqrt(-a))) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))/(S(4)*b**(S(3)/4)*sqrt(-sqrt(-a))) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))/(S(4)*b**(S(3)/4)*sqrt(-sqrt(-a))) - log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b**(S(3)/4)*(-a)**(S(1)/4)) + log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b**(S(3)/4)*(-a)**(S(1)/4)) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(-a)**(S(1)/4)) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(-a)**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c + d*x)/(a + b*x**S(4)), x), x, log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*sqrt(b)*sqrt(-a)) + log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*sqrt(b)*sqrt(-a)) - log(-d*(b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*sqrt(b)*sqrt(-a)) - log(d*(-b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*sqrt(b)*sqrt(-a)) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*sqrt(b)*sqrt(-a)) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*sqrt(b)*sqrt(-a)) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))/(S(4)*sqrt(b)*sqrt(-a)) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))/(S(4)*sqrt(b)*sqrt(-a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(a + b*x**S(4)), x), x, -log(-d*(b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*b**(S(1)/4)*(-sqrt(-a))**(S(3)/2)) + log(d*(-b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*b**(S(1)/4)*(-sqrt(-a))**(S(3)/2)) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))/(S(4)*b**(S(1)/4)*(-sqrt(-a))**(S(3)/2)) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))/(S(4)*b**(S(1)/4)*(-sqrt(-a))**(S(3)/2)) - log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b**(S(1)/4)*(-a)**(S(3)/4)) + log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*b**(S(1)/4)*(-a)**(S(3)/4)) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*b**(S(1)/4)*(-a)**(S(3)/4)) + polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*b**(S(1)/4)*(-a)**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x*(a + b*x**S(4))), x), x, log(-d*x/c)*log(c + d*x)/a - log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*a) - log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*a) - log(-d*(b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*a) - log(d*(-b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*a) + polylog(S(2), (c + d*x)/c)/a - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*a) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*a) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))/(S(4)*a) - polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))/(S(4)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x**S(2)*(a + b*x**S(4))), x), x, -b**(S(1)/4)*log(-d*(b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*(-sqrt(-a))**(S(5)/2)) + b**(S(1)/4)*log(d*(-b**(S(1)/4)*x + sqrt(-sqrt(-a)))/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))*log(c + d*x)/(S(4)*(-sqrt(-a))**(S(5)/2)) - b**(S(1)/4)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*sqrt(-sqrt(-a))))/(S(4)*(-sqrt(-a))**(S(5)/2)) + b**(S(1)/4)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*sqrt(-sqrt(-a))))/(S(4)*(-sqrt(-a))**(S(5)/2)) - b**(S(1)/4)*log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*(-a)**(S(5)/4)) + b**(S(1)/4)*log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*(-a)**(S(5)/4)) - b**(S(1)/4)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*(-a)**(S(5)/4)) + b**(S(1)/4)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*(-a)**(S(5)/4)) - log(c + d*x)/(a*x) + d*log(x)/(a*c) - d*log(c + d*x)/(a*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c + d*x)/(x**S(3)*(a + b*x**S(4))), x), x, sqrt(b)*log(-d*(b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*(-a)**(S(3)/2)) + sqrt(b)*log(d*(-b**(S(1)/4)*x + (-a)**(S(1)/4))/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*(-a)**(S(3)/2)) - sqrt(b)*log(-d*(b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*(-a)**(S(3)/2)) - sqrt(b)*log(d*(-b**(S(1)/4)*x + I*(-a)**(S(1)/4))/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))*log(c + d*x)/(S(4)*(-a)**(S(3)/2)) + sqrt(b)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*(-a)**(S(3)/2)) + sqrt(b)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*(-a)**(S(3)/2)) - sqrt(b)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))/(S(4)*(-a)**(S(3)/2)) - sqrt(b)*polylog(S(2), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))/(S(4)*(-a)**(S(3)/2)) - log(c + d*x)/(S(2)*a*x**S(2)) - d/(S(2)*a*c*x) - d**S(2)*log(x)/(S(2)*a*c**S(2)) + d**S(2)*log(c + d*x)/(S(2)*a*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)**S(3)/(d*x + e*x**S(2)), x), x, S(6)*n**S(3)*polylog(S(4), (a + b*x)/a)/d - S(6)*n**S(3)*polylog(S(4), -e*(a + b*x)/(-a*e + b*d))/d - S(6)*n**S(2)*log(c*(a + b*x)**n)*polylog(S(3), (a + b*x)/a)/d + S(6)*n**S(2)*log(c*(a + b*x)**n)*polylog(S(3), -e*(a + b*x)/(-a*e + b*d))/d + S(3)*n*log(c*(a + b*x)**n)**S(2)*polylog(S(2), (a + b*x)/a)/d - S(3)*n*log(c*(a + b*x)**n)**S(2)*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/d + log(c*(a + b*x)**n)**S(3)*log(-b*x/a)/d - log(c*(a + b*x)**n)**S(3)*log(b*(d + e*x)/(-a*e + b*d))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)**S(2)/(d*x + e*x**S(2)), x), x, -S(2)*n**S(2)*polylog(S(3), (a + b*x)/a)/d + S(2)*n**S(2)*polylog(S(3), -e*(a + b*x)/(-a*e + b*d))/d + S(2)*n*log(c*(a + b*x)**n)*polylog(S(2), (a + b*x)/a)/d - S(2)*n*log(c*(a + b*x)**n)*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/d + log(c*(a + b*x)**n)**S(2)*log(-b*x/a)/d - log(c*(a + b*x)**n)**S(2)*log(b*(d + e*x)/(-a*e + b*d))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)/(d*x + e*x**S(2)), x), x, n*polylog(S(2), (a + b*x)/a)/d - n*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/d + log(c*(a + b*x)**n)*log(-b*x/a)/d - log(c*(a + b*x)**n)*log(b*(d + e*x)/(-a*e + b*d))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x + e*x**S(2))*log(c*(a + b*x)**n)), x), x, Integral(S(1)/(x*(d + e*x)*log(c*(a + b*x)**n)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)**S(3)/(d + e*x + f*x**S(2)), x), x, S(6)*n**S(3)*polylog(S(4), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - S(6)*n**S(3)*polylog(S(4), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - S(6)*n**S(2)*log(c*(a + b*x)**n)*polylog(S(3), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + S(6)*n**S(2)*log(c*(a + b*x)**n)*polylog(S(3), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + S(3)*n*log(c*(a + b*x)**n)**S(2)*polylog(S(2), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - S(3)*n*log(c*(a + b*x)**n)**S(2)*polylog(S(2), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + log(c*(a + b*x)**n)**S(3)*log(-b*(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - log(c*(a + b*x)**n)**S(3)*log(-b*(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)**S(2)/(d + e*x + f*x**S(2)), x), x, -S(2)*n**S(2)*polylog(S(3), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + S(2)*n**S(2)*polylog(S(3), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + S(2)*n*log(c*(a + b*x)**n)*polylog(S(2), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - S(2)*n*log(c*(a + b*x)**n)*polylog(S(2), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + log(c*(a + b*x)**n)**S(2)*log(-b*(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - log(c*(a + b*x)**n)**S(2)*log(-b*(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**n)/(d + e*x + f*x**S(2)), x), x, n*polylog(S(2), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - n*polylog(S(2), S(2)*f*(a + b*x)/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + log(c*(a + b*x)**n)*log(-b*(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/(S(2)*a*f - b*(e - sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - log(c*(a + b*x)**n)*log(-b*(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/(S(2)*a*f - b*(e + sqrt(-S(4)*d*f + e**S(2)))))/sqrt(-S(4)*d*f + e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x + f*x**S(2))*log(c*(a + b*x)**n)), x), x, Integral(S(1)/((d + e*x + f*x**S(2))*log(c*(a + b*x)**n)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(x)/(a + b*x + c*x**S(2)), x), x, -b*x*log(x)/c**S(2) + b*x/c**S(2) + x**S(2)*log(x)/(S(2)*c) - x**S(2)/(S(4)*c) + (-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(3)) + (-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(3)) + (-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(3)) + (-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(x)/(a + b*x + c*x**S(2)), x), x, x*log(x)/c - x/c - (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(2)) - (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(2)) - (b + (S(2)*a*c - b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(2)) - (b + (S(2)*a*c - b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(x)/(a + b*x + c*x**S(2)), x), x, (-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c) + (-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c) + (b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c) + (b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(a + b*x + c*x**S(2)), x), x, log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2))))/sqrt(-S(4)*a*c + b**S(2)) - log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2))))/sqrt(-S(4)*a*c + b**S(2)) + polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/sqrt(-S(4)*a*c + b**S(2)) - polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(x*(a + b*x + c*x**S(2))), x), x, -(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a) - (-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a) - (b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a) - (b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a) + log(x)**S(2)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(x**S(2)*(a + b*x + c*x**S(2))), x), x, -log(x)/(a*x) - S(1)/(a*x) - b*log(x)**S(2)/(S(2)*a**S(2)) + (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)) + (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)) + (b + (S(2)*a*c - b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)) + (b + (S(2)*a*c - b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(x**S(3)*(a + b*x + c*x**S(2))), x), x, -log(x)/(S(2)*a*x**S(2)) - S(1)/(S(4)*a*x**S(2)) + b*log(x)/(a**S(2)*x) + b/(a**S(2)*x) + (-a*c/S(2) + b**S(2)/S(2))*log(x)**S(2)/a**S(3) - (-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(3)) - (-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(3)) - (-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(3)) - (-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d + e/(f + g*x))**p))**S(4), x), x, -S(24)*b**S(4)*e*p**S(4)*polylog(S(4), (d + e/(f + g*x))/d)/(d*g) + S(24)*b**S(3)*e*p**S(3)*(a + b*log(c*(d + e/(f + g*x))**p))*polylog(S(3), (d + e/(f + g*x))/d)/(d*g) - S(12)*b**S(2)*e*p**S(2)*(a + b*log(c*(d + e/(f + g*x))**p))**S(2)*polylog(S(2), (d + e/(f + g*x))/d)/(d*g) - S(4)*b*e*p*(a + b*log(c*(d + e/(f + g*x))**p))**S(3)*log(-e/(d*(f + g*x)))/(d*g) + (a + b*log(c*(d + e/(f + g*x))**p))**S(4)*(d*(f + g*x) + e)/(d*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d + e/(f + g*x))**p))**S(3), x), x, S(6)*b**S(3)*e*p**S(3)*polylog(S(3), (d + e/(f + g*x))/d)/(d*g) - S(6)*b**S(2)*e*p**S(2)*(a + b*log(c*(d + e/(f + g*x))**p))*polylog(S(2), (d + e/(f + g*x))/d)/(d*g) - S(3)*b*e*p*(a + b*log(c*(d + e/(f + g*x))**p))**S(2)*log(-e/(d*(f + g*x)))/(d*g) + (a + b*log(c*(d + e/(f + g*x))**p))**S(3)*(d*(f + g*x) + e)/(d*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d + e/(f + g*x))**p))**S(2), x), x, -S(2)*b**S(2)*e*p**S(2)*polylog(S(2), (d + e/(f + g*x))/d)/(d*g) - S(2)*b*e*p*(a + b*log(c*(d + e/(f + g*x))**p))*log(-e/(d*(f + g*x)))/(d*g) + (a + b*log(c*(d + e/(f + g*x))**p))**S(2)*(d*(f + g*x) + e)/(d*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*log(c*(d + e/(f + g*x))**p), x), x, a*x + b*(f + g*x)*log(c*(d + e/(f + g*x))**p)/g + b*e*p*log(d*(f + g*x) + e)/(d*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*log(c*(d + e/(f + g*x))**p)), x), x, Integral(S(1)/(a + b*log(c*(d + e/x)**p)), (x, f + g*x))/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*(d + e/(f + g*x))**p))**(S(-2)), x), x, Integral((a + b*log(c*(d + e/x)**p))**(S(-2)), (x, f + g*x))/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(e*(f + g*x)**p)**q), x), x, -p*q*x + (f + g*x)*log(c*(e*(f + g*x)**p)**q)/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(d + e*(f + g*x)**p)**q), x), x, -p*q*x + p*q*(f + g*x)*hyper((S(1), S(1)/p), (S(1) + S(1)/p,), -e*(f + g*x)**p/d)/g + (f + g*x)*log(c*(d + e*(f + g*x)**p)**q)/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(d + e*(f + g*x)**S(3))**q), x), x, d**(S(1)/3)*q*log(d**(S(1)/3) + e**(S(1)/3)*(f + g*x))/(e**(S(1)/3)*g) - d**(S(1)/3)*q*log(d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*(f + g*x) + e**(S(2)/3)*(f + g*x)**S(2))/(S(2)*e**(S(1)/3)*g) - sqrt(S(3))*d**(S(1)/3)*q*atan(sqrt(S(3))*(d**(S(1)/3) - S(2)*e**(S(1)/3)*(f + g*x))/(S(3)*d**(S(1)/3)))/(e**(S(1)/3)*g) - S(3)*q*x + (f + g*x)*log(c*(d + e*(f + g*x)**S(3))**q)/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(d + e*(f + g*x)**S(2))**q), x), x, S(2)*sqrt(d)*q*atan(sqrt(e)*(f + g*x)/sqrt(d))/(sqrt(e)*g) - S(2)*q*x + (f + g*x)*log(c*(d + e*(f + g*x)**S(2))**q)/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(d + e*(f + g*x))**q), x), x, -q*x + (d + e*f + e*g*x)*log(c*(d + e*f + e*g*x)**q)/(e*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(d + e/(f + g*x))**q), x), x, (f + g*x)*log(c*(d + e/(f + g*x))**q)/g + e*q*log(d*(f + g*x) + e)/(d*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(d + e/(f + g*x)**S(2))**q), x), x, (f + g*x)*log(c*(d + e/(f + g*x)**S(2))**q)/g + S(2)*sqrt(e)*q*atan(sqrt(d)*(f + g*x)/sqrt(e))/(sqrt(d)*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(d + e/(f + g*x)**S(3))**q), x), x, (f + g*x)*log(c*(d + e/(f + g*x)**S(3))**q)/g + e**(S(1)/3)*q*log(d**(S(1)/3)*(f + g*x) + e**(S(1)/3))/(d**(S(1)/3)*g) - e**(S(1)/3)*q*log(d**(S(2)/3)*(f + g*x)**S(2) - d**(S(1)/3)*e**(S(1)/3)*(f + g*x) + e**(S(2)/3))/(S(2)*d**(S(1)/3)*g) - sqrt(S(3))*e**(S(1)/3)*q*atan(sqrt(S(3))*(-S(2)*d**(S(1)/3)*(f + g*x) + e**(S(1)/3))/(S(3)*e**(S(1)/3)))/(d**(S(1)/3)*g), expand=True, _diff=True, _numerical=True) def test_2(): assert rubi_test(rubi_integrate(x**m*log(a*x**n), x), x, -n*x**(m + S(1))/(m + S(1))**S(2) + x**(m + S(1))*log(a*x**n)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*log(a*x**n), x), x, x**n*log(a*x**n)/n - x**n/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(a*x**n), x), x, -n*x**S(4)/S(16) + x**S(4)*log(a*x**n)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(a*x**n), x), x, -n*x**S(3)/S(9) + x**S(3)*log(a*x**n)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a*x**n), x), x, -n*x**S(2)/S(4) + x**S(2)*log(a*x**n)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n), x), x, -n*x + x*log(a*x**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)/x, x), x, log(a*x**n)**S(2)/(S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)/x**S(2), x), x, -n/x - log(a*x**n)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)/x**S(3), x), x, -n/(S(4)*x**S(2)) - log(a*x**n)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(a*x**n)**S(2), x), x, S(2)*n**S(2)*x**(m + S(1))/(m + S(1))**S(3) - S(2)*n*x**(m + S(1))*log(a*x**n)/(m + S(1))**S(2) + x**(m + S(1))*log(a*x**n)**S(2)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*log(a*x**n)**S(2), x), x, x**n*log(a*x**n)**S(2)/n - S(2)*x**n*log(a*x**n)/n + S(2)*x**n/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(a*x**n)**S(2), x), x, n**S(2)*x**S(4)/S(32) - n*x**S(4)*log(a*x**n)/S(8) + x**S(4)*log(a*x**n)**S(2)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(a*x**n)**S(2), x), x, S(2)*n**S(2)*x**S(3)/S(27) - S(2)*n*x**S(3)*log(a*x**n)/S(9) + x**S(3)*log(a*x**n)**S(2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a*x**n)**S(2), x), x, n**S(2)*x**S(2)/S(4) - n*x**S(2)*log(a*x**n)/S(2) + x**S(2)*log(a*x**n)**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(2), x), x, S(2)*n**S(2)*x - S(2)*n*x*log(a*x**n) + x*log(a*x**n)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(2)/x, x), x, log(a*x**n)**S(3)/(S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(2)/x**S(2), x), x, -S(2)*n**S(2)/x - S(2)*n*log(a*x**n)/x - log(a*x**n)**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(2)/x**S(3), x), x, -n**S(2)/(S(4)*x**S(2)) - n*log(a*x**n)/(S(2)*x**S(2)) - log(a*x**n)**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(a*x**n)**S(3), x), x, -S(6)*n**S(3)*x**(m + S(1))/(m + S(1))**S(4) + S(6)*n**S(2)*x**(m + S(1))*log(a*x**n)/(m + S(1))**S(3) - S(3)*n*x**(m + S(1))*log(a*x**n)**S(2)/(m + S(1))**S(2) + x**(m + S(1))*log(a*x**n)**S(3)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*log(a*x**n)**S(3), x), x, x**n*log(a*x**n)**S(3)/n - S(3)*x**n*log(a*x**n)**S(2)/n + S(6)*x**n*log(a*x**n)/n - S(6)*x**n/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(a*x**n)**S(3), x), x, -S(3)*n**S(3)*x**S(4)/S(128) + S(3)*n**S(2)*x**S(4)*log(a*x**n)/S(32) - S(3)*n*x**S(4)*log(a*x**n)**S(2)/S(16) + x**S(4)*log(a*x**n)**S(3)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(a*x**n)**S(3), x), x, -S(2)*n**S(3)*x**S(3)/S(27) + S(2)*n**S(2)*x**S(3)*log(a*x**n)/S(9) - n*x**S(3)*log(a*x**n)**S(2)/S(3) + x**S(3)*log(a*x**n)**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a*x**n)**S(3), x), x, -S(3)*n**S(3)*x**S(2)/S(8) + S(3)*n**S(2)*x**S(2)*log(a*x**n)/S(4) - S(3)*n*x**S(2)*log(a*x**n)**S(2)/S(4) + x**S(2)*log(a*x**n)**S(3)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(3), x), x, -S(6)*n**S(3)*x + S(6)*n**S(2)*x*log(a*x**n) - S(3)*n*x*log(a*x**n)**S(2) + x*log(a*x**n)**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(3)/x, x), x, log(a*x**n)**S(4)/(S(4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(3)/x**S(2), x), x, -S(6)*n**S(3)/x - S(6)*n**S(2)*log(a*x**n)/x - S(3)*n*log(a*x**n)**S(2)/x - log(a*x**n)**S(3)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**S(3)/x**S(3), x), x, -S(3)*n**S(3)/(S(8)*x**S(2)) - S(3)*n**S(2)*log(a*x**n)/(S(4)*x**S(2)) - S(3)*n*log(a*x**n)**S(2)/(S(4)*x**S(2)) - log(a*x**n)**S(3)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*log(a*x), x), x, S(2)*x**(S(7)/2)*log(a*x)/S(7) - S(4)*x**(S(7)/2)/S(49), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*log(a*x), x), x, S(2)*x**(S(5)/2)*log(a*x)/S(5) - S(4)*x**(S(5)/2)/S(25), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*log(a*x), x), x, S(2)*x**(S(3)/2)*log(a*x)/S(3) - S(4)*x**(S(3)/2)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)/sqrt(x), x), x, S(2)*sqrt(x)*log(a*x) - S(4)*sqrt(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)/x**(S(3)/2), x), x, -S(2)*log(a*x)/sqrt(x) - S(4)/sqrt(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)/x**(S(5)/2), x), x, -S(2)*log(a*x)/(S(3)*x**(S(3)/2)) - S(4)/(S(9)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x**n), x), x, x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*Ei((m + S(1))*log(a*x**n)/n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))/log(a*x**n), x), x, li(a*x**n)/(a*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x**n), x), x, x**S(4)*(a*x**n)**(-S(4)/n)*Ei(S(4)*log(a*x**n)/n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x**n), x), x, x**S(3)*(a*x**n)**(-S(3)/n)*Ei(S(3)*log(a*x**n)/n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x**n), x), x, x**S(2)*(a*x**n)**(-S(2)/n)*Ei(S(2)*log(a*x**n)/n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/log(a*x**n), x), x, x*(a*x**n)**(-S(1)/n)*Ei(log(a*x**n)/n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x**n)), x), x, log(log(a*x**n))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x**n)), x), x, (a*x**n)**(S(1)/n)*Ei(-log(a*x**n)/n)/(n*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x**n)), x), x, (a*x**n)**(S(2)/n)*Ei(-S(2)*log(a*x**n)/n)/(n*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x**n)**S(2), x), x, -x**(m + S(1))/(n*log(a*x**n)) + x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*(m + S(1))*Ei((m + S(1))*log(a*x**n)/n)/n**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))/log(a*x**n)**S(2), x), x, -x**n/(n*log(a*x**n)) + li(a*x**n)/(a*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x**n)**S(2), x), x, -x**S(4)/(n*log(a*x**n)) + S(4)*x**S(4)*(a*x**n)**(-S(4)/n)*Ei(S(4)*log(a*x**n)/n)/n**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x**n)**S(2), x), x, -x**S(3)/(n*log(a*x**n)) + S(3)*x**S(3)*(a*x**n)**(-S(3)/n)*Ei(S(3)*log(a*x**n)/n)/n**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x**n)**S(2), x), x, -x**S(2)/(n*log(a*x**n)) + S(2)*x**S(2)*(a*x**n)**(-S(2)/n)*Ei(S(2)*log(a*x**n)/n)/n**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(-2)), x), x, -x/(n*log(a*x**n)) + x*(a*x**n)**(-S(1)/n)*Ei(log(a*x**n)/n)/n**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x**n)**S(2)), x), x, -S(1)/(n*log(a*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x**n)**S(2)), x), x, -S(1)/(n*x*log(a*x**n)) - (a*x**n)**(S(1)/n)*Ei(-log(a*x**n)/n)/(n**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x**n)**S(2)), x), x, -S(1)/(n*x**S(2)*log(a*x**n)) - S(2)*(a*x**n)**(S(2)/n)*Ei(-S(2)*log(a*x**n)/n)/(n**S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x**n)**S(3), x), x, -x**(m + S(1))/(S(2)*n*log(a*x**n)**S(2)) - x**(m + S(1))*(m/S(2) + S(1)/2)/(n**S(2)*log(a*x**n)) + x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*(m + S(1))**S(2)*Ei((m + S(1))*log(a*x**n)/n)/(S(2)*n**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))/log(a*x**n)**S(3), x), x, -x**n/(S(2)*n*log(a*x**n)) - x**n/(S(2)*n*log(a*x**n)**S(2)) + li(a*x**n)/(S(2)*a*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x**n)**S(3), x), x, -x**S(4)/(S(2)*n*log(a*x**n)**S(2)) - S(2)*x**S(4)/(n**S(2)*log(a*x**n)) + S(8)*x**S(4)*(a*x**n)**(-S(4)/n)*Ei(S(4)*log(a*x**n)/n)/n**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x**n)**S(3), x), x, -x**S(3)/(S(2)*n*log(a*x**n)**S(2)) - S(3)*x**S(3)/(S(2)*n**S(2)*log(a*x**n)) + S(9)*x**S(3)*(a*x**n)**(-S(3)/n)*Ei(S(3)*log(a*x**n)/n)/(S(2)*n**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x**n)**S(3), x), x, -x**S(2)/(S(2)*n*log(a*x**n)**S(2)) - x**S(2)/(n**S(2)*log(a*x**n)) + S(2)*x**S(2)*(a*x**n)**(-S(2)/n)*Ei(S(2)*log(a*x**n)/n)/n**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(-3)), x), x, -x/(S(2)*n*log(a*x**n)**S(2)) - x/(S(2)*n**S(2)*log(a*x**n)) + x*(a*x**n)**(-S(1)/n)*Ei(log(a*x**n)/n)/(S(2)*n**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x**n)**S(3)), x), x, -S(1)/(S(2)*n*log(a*x**n)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x**n)**S(3)), x), x, -S(1)/(S(2)*n*x*log(a*x**n)**S(2)) + S(1)/(S(2)*n**S(2)*x*log(a*x**n)) + (a*x**n)**(S(1)/n)*Ei(-log(a*x**n)/n)/(S(2)*n**S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x**n)**S(3)), x), x, -S(1)/(S(2)*n*x**S(2)*log(a*x**n)**S(2)) + S(1)/(n**S(2)*x**S(2)*log(a*x**n)) + S(2)*(a*x**n)**(S(2)/n)*Ei(-S(2)*log(a*x**n)/n)/(n**S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x), x), x, x**(m + S(1))*(a*x)**(-m + S(-1))*Ei((m + S(1))*log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x), x), x, Ei(S(4)*log(a*x))/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x), x), x, Ei(S(3)*log(a*x))/a**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x), x), x, Ei(S(2)*log(a*x))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/log(a*x), x), x, li(a*x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x)), x), x, log(log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x)), x), x, a*Ei(-log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x)), x), x, a**S(2)*Ei(-S(2)*log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x)**S(2), x), x, x**(m + S(1))*(a*x)**(-m + S(-1))*(m + S(1))*Ei((m + S(1))*log(a*x)) - x**(m + S(1))/log(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x)**S(2), x), x, -x**S(4)/log(a*x) + S(4)*Ei(S(4)*log(a*x))/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x)**S(2), x), x, -x**S(3)/log(a*x) + S(3)*Ei(S(3)*log(a*x))/a**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x)**S(2), x), x, -x**S(2)/log(a*x) + S(2)*Ei(S(2)*log(a*x))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)**(S(-2)), x), x, -x/log(a*x) + li(a*x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x)**S(2)), x), x, -S(1)/log(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x)**S(2)), x), x, -a*Ei(-log(a*x)) - S(1)/(x*log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x)**S(2)), x), x, -S(2)*a**S(2)*Ei(-S(2)*log(a*x)) - S(1)/(x**S(2)*log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x)**S(3), x), x, x**(m + S(1))*(a*x)**(-m + S(-1))*(m + S(1))**S(2)*Ei((m + S(1))*log(a*x))/S(2) - x**(m + S(1))*(m/S(2) + S(1)/2)/log(a*x) - x**(m + S(1))/(S(2)*log(a*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x)**S(3), x), x, -S(2)*x**S(4)/log(a*x) - x**S(4)/(S(2)*log(a*x)**S(2)) + S(8)*Ei(S(4)*log(a*x))/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x)**S(3), x), x, -S(3)*x**S(3)/(S(2)*log(a*x)) - x**S(3)/(S(2)*log(a*x)**S(2)) + S(9)*Ei(S(3)*log(a*x))/(S(2)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x)**S(3), x), x, -x**S(2)/log(a*x) - x**S(2)/(S(2)*log(a*x)**S(2)) + S(2)*Ei(S(2)*log(a*x))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)**(S(-3)), x), x, -x/(S(2)*log(a*x)) - x/(S(2)*log(a*x)**S(2)) + li(a*x)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x)**S(3)), x), x, -S(1)/(S(2)*log(a*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x)**S(3)), x), x, a*Ei(-log(a*x))/S(2) + S(1)/(S(2)*x*log(a*x)) - S(1)/(S(2)*x*log(a*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x)**S(3)), x), x, S(2)*a**S(2)*Ei(-S(2)*log(a*x)) + S(1)/(x**S(2)*log(a*x)) - S(1)/(S(2)*x**S(2)*log(a*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(log(a*x**n)), x), x, -sqrt(pi)*sqrt(n)*x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*erfi(sqrt(m + S(1))*sqrt(log(a*x**n))/sqrt(n))/(S(2)*(m + S(1))**(S(3)/2)) + x**(m + S(1))*sqrt(log(a*x**n))/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(log(a*x**n)), x), x, -sqrt(pi)*sqrt(n)*x**S(4)*(a*x**n)**(-S(4)/n)*erfi(S(2)*sqrt(log(a*x**n))/sqrt(n))/S(16) + x**S(4)*sqrt(log(a*x**n))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(log(a*x**n)), x), x, -sqrt(S(3))*sqrt(pi)*sqrt(n)*x**S(3)*(a*x**n)**(-S(3)/n)*erfi(sqrt(S(3))*sqrt(log(a*x**n))/sqrt(n))/S(18) + x**S(3)*sqrt(log(a*x**n))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(log(a*x**n)), x), x, -sqrt(S(2))*sqrt(pi)*sqrt(n)*x**S(2)*(a*x**n)**(-S(2)/n)*erfi(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/S(8) + x**S(2)*sqrt(log(a*x**n))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(a*x**n)), x), x, -sqrt(pi)*sqrt(n)*x*(a*x**n)**(-S(1)/n)*erfi(sqrt(log(a*x**n))/sqrt(n))/S(2) + x*sqrt(log(a*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(a*x**n))/x, x), x, S(2)*log(a*x**n)**(S(3)/2)/(S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(a*x**n))/x**S(2), x), x, sqrt(pi)*sqrt(n)*(a*x**n)**(S(1)/n)*erf(sqrt(log(a*x**n))/sqrt(n))/(S(2)*x) - sqrt(log(a*x**n))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(a*x**n))/x**S(3), x), x, sqrt(S(2))*sqrt(pi)*sqrt(n)*(a*x**n)**(S(2)/n)*erf(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/(S(8)*x**S(2)) - sqrt(log(a*x**n))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(a*x**n)**(S(3)/2), x), x, S(3)*sqrt(pi)*n**(S(3)/2)*x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*erfi(sqrt(m + S(1))*sqrt(log(a*x**n))/sqrt(n))/(S(4)*(m + S(1))**(S(5)/2)) - S(3)*n*x**(m + S(1))*sqrt(log(a*x**n))/(S(2)*(m + S(1))**S(2)) + x**(m + S(1))*log(a*x**n)**(S(3)/2)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(a*x**n)**(S(3)/2), x), x, S(3)*sqrt(pi)*n**(S(3)/2)*x**S(4)*(a*x**n)**(-S(4)/n)*erfi(S(2)*sqrt(log(a*x**n))/sqrt(n))/S(128) - S(3)*n*x**S(4)*sqrt(log(a*x**n))/S(32) + x**S(4)*log(a*x**n)**(S(3)/2)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(a*x**n)**(S(3)/2), x), x, sqrt(S(3))*sqrt(pi)*n**(S(3)/2)*x**S(3)*(a*x**n)**(-S(3)/n)*erfi(sqrt(S(3))*sqrt(log(a*x**n))/sqrt(n))/S(36) - n*x**S(3)*sqrt(log(a*x**n))/S(6) + x**S(3)*log(a*x**n)**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a*x**n)**(S(3)/2), x), x, S(3)*sqrt(S(2))*sqrt(pi)*n**(S(3)/2)*x**S(2)*(a*x**n)**(-S(2)/n)*erfi(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/S(32) - S(3)*n*x**S(2)*sqrt(log(a*x**n))/S(8) + x**S(2)*log(a*x**n)**(S(3)/2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(3)/2), x), x, S(3)*sqrt(pi)*n**(S(3)/2)*x*(a*x**n)**(-S(1)/n)*erfi(sqrt(log(a*x**n))/sqrt(n))/S(4) - S(3)*n*x*sqrt(log(a*x**n))/S(2) + x*log(a*x**n)**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(3)/2)/x, x), x, S(2)*log(a*x**n)**(S(5)/2)/(S(5)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(3)/2)/x**S(2), x), x, S(3)*sqrt(pi)*n**(S(3)/2)*(a*x**n)**(S(1)/n)*erf(sqrt(log(a*x**n))/sqrt(n))/(S(4)*x) - S(3)*n*sqrt(log(a*x**n))/(S(2)*x) - log(a*x**n)**(S(3)/2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(3)/2)/x**S(3), x), x, S(3)*sqrt(S(2))*sqrt(pi)*n**(S(3)/2)*(a*x**n)**(S(2)/n)*erf(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/(S(32)*x**S(2)) - S(3)*n*sqrt(log(a*x**n))/(S(8)*x**S(2)) - log(a*x**n)**(S(3)/2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/sqrt(log(a*x**n)), x), x, sqrt(pi)*x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*erfi(sqrt(m + S(1))*sqrt(log(a*x**n))/sqrt(n))/(sqrt(n)*sqrt(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(log(a*x**n)), x), x, sqrt(pi)*x**S(4)*(a*x**n)**(-S(4)/n)*erfi(S(2)*sqrt(log(a*x**n))/sqrt(n))/(S(2)*sqrt(n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(log(a*x**n)), x), x, sqrt(S(3))*sqrt(pi)*x**S(3)*(a*x**n)**(-S(3)/n)*erfi(sqrt(S(3))*sqrt(log(a*x**n))/sqrt(n))/(S(3)*sqrt(n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(log(a*x**n)), x), x, sqrt(S(2))*sqrt(pi)*x**S(2)*(a*x**n)**(-S(2)/n)*erfi(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/(S(2)*sqrt(n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(log(a*x**n)), x), x, sqrt(pi)*x*(a*x**n)**(-S(1)/n)*erfi(sqrt(log(a*x**n))/sqrt(n))/sqrt(n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(log(a*x**n))), x), x, S(2)*sqrt(log(a*x**n))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(log(a*x**n))), x), x, sqrt(pi)*(a*x**n)**(S(1)/n)*erf(sqrt(log(a*x**n))/sqrt(n))/(sqrt(n)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(log(a*x**n))), x), x, sqrt(S(2))*sqrt(pi)*(a*x**n)**(S(2)/n)*erf(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/(S(2)*sqrt(n)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x**n)**(S(3)/2), x), x, -S(2)*x**(m + S(1))/(n*sqrt(log(a*x**n))) + S(2)*sqrt(pi)*x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*sqrt(m + S(1))*erfi(sqrt(m + S(1))*sqrt(log(a*x**n))/sqrt(n))/n**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x**n)**(S(3)/2), x), x, -S(2)*x**S(4)/(n*sqrt(log(a*x**n))) + S(4)*sqrt(pi)*x**S(4)*(a*x**n)**(-S(4)/n)*erfi(S(2)*sqrt(log(a*x**n))/sqrt(n))/n**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x**n)**(S(3)/2), x), x, -S(2)*x**S(3)/(n*sqrt(log(a*x**n))) + S(2)*sqrt(S(3))*sqrt(pi)*x**S(3)*(a*x**n)**(-S(3)/n)*erfi(sqrt(S(3))*sqrt(log(a*x**n))/sqrt(n))/n**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x**n)**(S(3)/2), x), x, -S(2)*x**S(2)/(n*sqrt(log(a*x**n))) + S(2)*sqrt(S(2))*sqrt(pi)*x**S(2)*(a*x**n)**(-S(2)/n)*erfi(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/n**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(-3)/2), x), x, -S(2)*x/(n*sqrt(log(a*x**n))) + S(2)*sqrt(pi)*x*(a*x**n)**(-S(1)/n)*erfi(sqrt(log(a*x**n))/sqrt(n))/n**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x**n)**(S(3)/2)), x), x, -S(2)/(n*sqrt(log(a*x**n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x**n)**(S(3)/2)), x), x, -S(2)/(n*x*sqrt(log(a*x**n))) - S(2)*sqrt(pi)*(a*x**n)**(S(1)/n)*erf(sqrt(log(a*x**n))/sqrt(n))/(n**(S(3)/2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x**n)**(S(3)/2)), x), x, -S(2)/(n*x**S(2)*sqrt(log(a*x**n))) - S(2)*sqrt(S(2))*sqrt(pi)*(a*x**n)**(S(2)/n)*erf(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/(n**(S(3)/2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(a*x**n)**(S(5)/2), x), x, -S(2)*x**(m + S(1))/(S(3)*n*log(a*x**n)**(S(3)/2)) - x**(m + S(1))*(S(4)*m/S(3) + S(4)/3)/(n**S(2)*sqrt(log(a*x**n))) + S(4)*sqrt(pi)*x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*(m + S(1))**(S(3)/2)*erfi(sqrt(m + S(1))*sqrt(log(a*x**n))/sqrt(n))/(S(3)*n**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(a*x**n)**(S(5)/2), x), x, -S(2)*x**S(4)/(S(3)*n*log(a*x**n)**(S(3)/2)) - S(16)*x**S(4)/(S(3)*n**S(2)*sqrt(log(a*x**n))) + S(32)*sqrt(pi)*x**S(4)*(a*x**n)**(-S(4)/n)*erfi(S(2)*sqrt(log(a*x**n))/sqrt(n))/(S(3)*n**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(a*x**n)**(S(5)/2), x), x, -S(2)*x**S(3)/(S(3)*n*log(a*x**n)**(S(3)/2)) - S(4)*x**S(3)/(n**S(2)*sqrt(log(a*x**n))) + S(4)*sqrt(S(3))*sqrt(pi)*x**S(3)*(a*x**n)**(-S(3)/n)*erfi(sqrt(S(3))*sqrt(log(a*x**n))/sqrt(n))/n**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(a*x**n)**(S(5)/2), x), x, -S(2)*x**S(2)/(S(3)*n*log(a*x**n)**(S(3)/2)) - S(8)*x**S(2)/(S(3)*n**S(2)*sqrt(log(a*x**n))) + S(8)*sqrt(S(2))*sqrt(pi)*x**S(2)*(a*x**n)**(-S(2)/n)*erfi(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/(S(3)*n**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**(S(-5)/2), x), x, -S(2)*x/(S(3)*n*log(a*x**n)**(S(3)/2)) - S(4)*x/(S(3)*n**S(2)*sqrt(log(a*x**n))) + S(4)*sqrt(pi)*x*(a*x**n)**(-S(1)/n)*erfi(sqrt(log(a*x**n))/sqrt(n))/(S(3)*n**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(a*x**n)**(S(5)/2)), x), x, -S(2)/(S(3)*n*log(a*x**n)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(a*x**n)**(S(5)/2)), x), x, -S(2)/(S(3)*n*x*log(a*x**n)**(S(3)/2)) + S(4)/(S(3)*n**S(2)*x*sqrt(log(a*x**n))) + S(4)*sqrt(pi)*(a*x**n)**(S(1)/n)*erf(sqrt(log(a*x**n))/sqrt(n))/(S(3)*n**(S(5)/2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(a*x**n)**(S(5)/2)), x), x, -S(2)/(S(3)*n*x**S(2)*log(a*x**n)**(S(3)/2)) + S(8)/(S(3)*n**S(2)*x**S(2)*sqrt(log(a*x**n))) + S(8)*sqrt(S(2))*sqrt(pi)*(a*x**n)**(S(2)/n)*erf(sqrt(S(2))*sqrt(log(a*x**n))/sqrt(n))/(S(3)*n**(S(5)/2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(a*x)**p, x), x, x**(m + S(1))*(a*x)**(-m + S(-1))*((-m + S(-1))*log(a*x))**(-p)*Gamma(p + S(1), (-m + S(-1))*log(a*x))*log(a*x)**p/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(a*x)**p, x), x, S(4)**(-p + S(-1))*(-log(a*x))**(-p)*Gamma(p + S(1), -S(4)*log(a*x))*log(a*x)**p/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(a*x)**p, x), x, S(3)**(-p + S(-1))*(-log(a*x))**(-p)*Gamma(p + S(1), -S(3)*log(a*x))*log(a*x)**p/a**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a*x)**p, x), x, S(2)**(-p + S(-1))*(-log(a*x))**(-p)*Gamma(p + S(1), -S(2)*log(a*x))*log(a*x)**p/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)**p, x), x, (-log(a*x))**(-p)*Gamma(p + S(1), -log(a*x))*log(a*x)**p/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)**p/x, x), x, log(a*x)**(p + S(1))/(p + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)**p/x**S(2), x), x, -a*Gamma(p + S(1), log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)**p/x**S(3), x), x, -S(2)**(-p + S(-1))*a**S(2)*Gamma(p + S(1), S(2)*log(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(a*x**n)**p, x), x, x**(m + S(1))*(a*x**n)**(-(m + S(1))/n)*((-m + S(-1))*log(a*x**n)/n)**(-p)*Gamma(p + S(1), (-m + S(-1))*log(a*x**n)/n)*log(a*x**n)**p/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*log(a*x**n)**p, x), x, (-log(a*x**n))**(-p)*Gamma(p + S(1), -log(a*x**n))*log(a*x**n)**p/(a*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(a*x**n)**p, x), x, S(4)**(-p + S(-1))*x**S(4)*(a*x**n)**(-S(4)/n)*(-log(a*x**n)/n)**(-p)*Gamma(p + S(1), -S(4)*log(a*x**n)/n)*log(a*x**n)**p, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(a*x**n)**p, x), x, S(3)**(-p + S(-1))*x**S(3)*(a*x**n)**(-S(3)/n)*(-log(a*x**n)/n)**(-p)*Gamma(p + S(1), -S(3)*log(a*x**n)/n)*log(a*x**n)**p, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a*x**n)**p, x), x, S(2)**(-p + S(-1))*x**S(2)*(a*x**n)**(-S(2)/n)*(-log(a*x**n)/n)**(-p)*Gamma(p + S(1), -S(2)*log(a*x**n)/n)*log(a*x**n)**p, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**p, x), x, x*(a*x**n)**(-S(1)/n)*(-log(a*x**n)/n)**(-p)*Gamma(p + S(1), -log(a*x**n)/n)*log(a*x**n)**p, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**p/x, x), x, log(a*x**n)**(p + S(1))/(n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**p/x**S(2), x), x, -(a*x**n)**(S(1)/n)*(log(a*x**n)/n)**(-p)*Gamma(p + S(1), log(a*x**n)/n)*log(a*x**n)**p/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)**p/x**S(3), x), x, -S(2)**(-p + S(-1))*(a*x**n)**(S(2)/n)*(log(a*x**n)/n)**(-p)*Gamma(p + S(1), S(2)*log(a*x**n)/n)*log(a*x**n)**p/x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(b*x**n)**p), x), x, -n*p*x**(m + S(1))/(m + S(1))**S(2) + x**(m + S(1))*log(c*(b*x**n)**p)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(b*x**n)**p), x), x, -n*p*x**S(3)/S(9) + x**S(3)*log(c*(b*x**n)**p)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(b*x**n)**p), x), x, -n*p*x**S(2)/S(4) + x**S(2)*log(c*(b*x**n)**p)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p), x), x, -n*p*x + x*log(c*(b*x**n)**p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)/x, x), x, log(c*(b*x**n)**p)**S(2)/(S(2)*n*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)/x**S(2), x), x, -n*p/x - log(c*(b*x**n)**p)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)/x**S(3), x), x, -n*p/(S(4)*x**S(2)) - log(c*(b*x**n)**p)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)/x**S(4), x), x, -n*p/(S(9)*x**S(3)) - log(c*(b*x**n)**p)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(b*x**n)**p)**S(2), x), x, S(2)*n**S(2)*p**S(2)*x**(m + S(1))/(m + S(1))**S(3) - S(2)*n*p*x**(m + S(1))*log(c*(b*x**n)**p)/(m + S(1))**S(2) + x**(m + S(1))*log(c*(b*x**n)**p)**S(2)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(b*x**n)**p)**S(2), x), x, S(2)*n**S(2)*p**S(2)*x**S(3)/S(27) - S(2)*n*p*x**S(3)*log(c*(b*x**n)**p)/S(9) + x**S(3)*log(c*(b*x**n)**p)**S(2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(b*x**n)**p)**S(2), x), x, n**S(2)*p**S(2)*x**S(2)/S(4) - n*p*x**S(2)*log(c*(b*x**n)**p)/S(2) + x**S(2)*log(c*(b*x**n)**p)**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)**S(2), x), x, S(2)*n**S(2)*p**S(2)*x - S(2)*n*p*x*log(c*(b*x**n)**p) + x*log(c*(b*x**n)**p)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)**S(2)/x, x), x, log(c*(b*x**n)**p)**S(3)/(S(3)*n*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)**S(2)/x**S(2), x), x, -S(2)*n**S(2)*p**S(2)/x - S(2)*n*p*log(c*(b*x**n)**p)/x - log(c*(b*x**n)**p)**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)**S(2)/x**S(3), x), x, -n**S(2)*p**S(2)/(S(4)*x**S(2)) - n*p*log(c*(b*x**n)**p)/(S(2)*x**S(2)) - log(c*(b*x**n)**p)**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(b*x**n)**p)**S(2)/x**S(4), x), x, -S(2)*n**S(2)*p**S(2)/(S(27)*x**S(3)) - S(2)*n*p*log(c*(b*x**n)**p)/(S(9)*x**S(3)) - log(c*(b*x**n)**p)**S(2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(c*(b*x**n)**p), x), x, x**(m + S(1))*(c*(b*x**n)**p)**(-(m + S(1))/(n*p))*Ei((m + S(1))*log(c*(b*x**n)**p)/(n*p))/(n*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(c*(b*x**n)**p)**S(2), x), x, -x**(m + S(1))/(n*p*log(c*(b*x**n)**p)) + x**(m + S(1))*(c*(b*x**n)**p)**(-(m + S(1))/(n*p))*(m + S(1))*Ei((m + S(1))*log(c*(b*x**n)**p)/(n*p))/(n**S(2)*p**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(b*x**n)**p)**q, x), x, x**(m + S(1))*(c*(b*x**n)**p)**(-(m + S(1))/(n*p))*((-m + S(-1))*log(c*(b*x**n)**p)/(n*p))**(-q)*Gamma(q + S(1), (-m + S(-1))*log(c*(b*x**n)**p)/(n*p))*log(c*(b*x**n)**p)**q/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**m*log(c*x), x), x, (a + b*x)**(m + S(1))*log(c*x)/(b*(m + S(1))) + (a + b*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), S(1) + b*x/a)/(a*b*(m**S(2) + S(3)*m + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*log(c*x), x), x, -a**S(4)*log(x)/(S(4)*b) - a**S(3)*x - S(3)*a**S(2)*b*x**S(2)/S(4) - a*b**S(2)*x**S(3)/S(3) - b**S(3)*x**S(4)/S(16) + (a + b*x)**S(4)*log(c*x)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*log(c*x), x), x, -a**S(3)*log(x)/(S(3)*b) - a**S(2)*x - a*b*x**S(2)/S(2) - b**S(2)*x**S(3)/S(9) + (a + b*x)**S(3)*log(c*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*log(c*x), x), x, -a*x - b*x**S(2)/S(4) + x*(S(2)*a + b*x)*log(c*x)/S(2), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x)*log(c*x), x), x, -a**S(2)*log(x)/(S(2)*b) - a*x - b*x**S(2)/S(4) + (a + b*x)**S(2)*log(c*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x)/(a + b*x), x), x, log((a + b*x)/a)*log(c*x)/b + polylog(S(2), -b*x/a)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x)/(a + b*x)**S(2), x), x, -log(c*x)/(b*(a + b*x)) + log(x)/(a*b) - log(a + b*x)/(a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x)/(a + b*x)**S(3), x), x, -log(c*x)/(S(2)*b*(a + b*x)**S(2)) + S(1)/(S(2)*a*b*(a + b*x)) + log(x)/(S(2)*a**S(2)*b) - log(a + b*x)/(S(2)*a**S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x)/(a + b*x)**S(4), x), x, -log(c*x)/(S(3)*b*(a + b*x)**S(3)) + S(1)/(S(6)*a*b*(a + b*x)**S(2)) + S(1)/(S(3)*a**S(2)*b*(a + b*x)) + log(x)/(S(3)*a**S(3)*b) - log(a + b*x)/(S(3)*a**S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**m*log(c*x**n), x), x, (a + b*x)**(m + S(1))*log(c*x**n)/(b*(m + S(1))) + n*(a + b*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), S(1) + b*x/a)/(a*b*(m**S(2) + S(3)*m + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*log(c*x**n), x), x, -a**S(4)*n*log(x)/(S(4)*b) - a**S(3)*n*x - S(3)*a**S(2)*b*n*x**S(2)/S(4) - a*b**S(2)*n*x**S(3)/S(3) - b**S(3)*n*x**S(4)/S(16) + (a + b*x)**S(4)*log(c*x**n)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*log(c*x**n), x), x, -a**S(3)*n*log(x)/(S(3)*b) - a**S(2)*n*x - a*b*n*x**S(2)/S(2) - b**S(2)*n*x**S(3)/S(9) + (a + b*x)**S(3)*log(c*x**n)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*log(c*x**n), x), x, -a**S(2)*n*log(x)/(S(2)*b) - a*n*x - b*n*x**S(2)/S(4) + (a + b*x)**S(2)*log(c*x**n)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**n)/(a + b*x), x), x, n*polylog(S(2), -b*x/a)/b + log((a + b*x)/a)*log(c*x**n)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**n)/(a + b*x)**S(2), x), x, -log(c*x**n)/(b*(a + b*x)) + n*log(x)/(a*b) - n*log(a + b*x)/(a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**n)/(a + b*x)**S(3), x), x, -log(c*x**n)/(S(2)*b*(a + b*x)**S(2)) + n/(S(2)*a*b*(a + b*x)) + n*log(x)/(S(2)*a**S(2)*b) - n*log(a + b*x)/(S(2)*a**S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**n)/(a + b*x)**S(4), x), x, -log(c*x**n)/(S(3)*b*(a + b*x)**S(3)) + n/(S(6)*a*b*(a + b*x)**S(2)) + n/(S(3)*a**S(2)*b*(a + b*x)) + n*log(x)/(S(3)*a**S(3)*b) - n*log(a + b*x)/(S(3)*a**S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**n)/(S(4)*x + S(2))**S(2), x), x, n*log(x)/S(8) - n*log(S(2)*x + S(1))/S(8) - log(c*x**n)/(S(8)*(S(2)*x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)/(-a*x + S(1)), x), x, polylog(S(2), -a*x + S(1))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x/a)/(a - x), x), x, polylog(S(2), (a - x)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a*x**S(2))/(-a*x**S(2) + S(1)), x), x, polylog(S(2), -a*x**S(2) + S(1))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(x**S(2)/a)/(a - x**S(2)), x), x, polylog(S(2), (a - x**S(2))/a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*log(a*x**n)/(-a*x**n + S(1)), x), x, polylog(S(2), -a*x**n + S(1))/(a*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*log(x**n/a)/(a - x**n), x), x, polylog(S(2), (a - x**n)/a)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a/x)/(a*x - x**S(2)), x), x, polylog(S(2), -a/x + S(1))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a/x**S(2))/(a*x - x**S(3)), x), x, polylog(S(2), (-a + x**S(2))/x**S(2))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**(-n + S(1)))/(a*x - x**n), x), x, -polylog(S(2), -a*x**(-n + S(1)) + S(1))/(a*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-a*x**(-m)*(-c + S(1))/b + c)/(x*(a + b*x**m)), x), x, polylog(S(2), x**(-m)*(a + b*x**m)*(-c + S(1))/b)/(a*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**(-m)*(a*c - a + b*c*x**m)/b)/(x*(a + b*x**m)), x), x, polylog(S(2), x**(-m)*(a + b*x**m)*(-c + S(1))/b)/(a*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + x**(-m)*(a*c*d - d)/(c*e)))/(x*(d + e*x**m)), x), x, polylog(S(2), x**(-m)*(d + e*x**m)*(-a*c + S(1))/e)/(d*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**(-m)*(a*c*d + a*c*e*x**m - d)/e)/(x*(d + e*x**m)), x), x, polylog(S(2), x**(-m)*(d + e*x**m)*(-a*c + S(1))/e)/(d*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(2)*a/(a + b*x))/(a**S(2) - b**S(2)*x**S(2)), x), x, polylog(S(2), (-a + b*x)/(a + b*x))/(S(2)*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(2)*a/(a + b*x))/((a - b*x)*(a + b*x)), x), x, polylog(S(2), (-a + b*x)/(a + b*x))/(S(2)*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a*(-c + S(1)) + b*x*(c + S(1)))/(a + b*x))/(a**S(2) - b**S(2)*x**S(2)), x), x, polylog(S(2), c*(a - b*x)/(a + b*x))/(S(2)*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a*(-c + S(1)) + b*x*(c + S(1)))/(a + b*x))/((a - b*x)*(a + b*x)), x), x, polylog(S(2), c*(a - b*x)/(a + b*x))/(S(2)*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-c*(a - b*x)/(a + b*x) + S(1))/(a**S(2) - b**S(2)*x**S(2)), x), x, polylog(S(2), c*(a - b*x)/(a + b*x))/(S(2)*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-c*(a - b*x)/(a + b*x) + S(1))/((a - b*x)*(a + b*x)), x), x, polylog(S(2), c*(a - b*x)/(a + b*x))/(S(2)*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*x**n))/(d + e*x**S(2)), x), x, -I*b*n*polylog(S(2), -I*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)) + I*b*n*polylog(S(2), I*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)) + (a + b*log(c*x**n))*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*x**n))/(d + e*x + f*x**S(2)), x), x, b*n*polylog(S(2), -S(2)*f*x/(e - sqrt(-S(4)*d*f + e**S(2))))/sqrt(-S(4)*d*f + e**S(2)) - b*n*polylog(S(2), -S(2)*f*x/(e + sqrt(-S(4)*d*f + e**S(2))))/sqrt(-S(4)*d*f + e**S(2)) + (a + b*log(c*x**n))*log((e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/(e - sqrt(-S(4)*d*f + e**S(2))))/sqrt(-S(4)*d*f + e**S(2)) - (a + b*log(c*x**n))*log((e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/(e + sqrt(-S(4)*d*f + e**S(2))))/sqrt(-S(4)*d*f + e**S(2)), expand=True, _diff=True, _numerical=True) # same result as in mathematica but fails assert rubi_test(rubi_integrate((d + e*x)**m*log(c*x)/x, x), x, (d + e*x)**m*(d/(e*x) + S(1))**(-m)*log(c*x)*hyper((-m, -m), (-m + S(1),), -d/(e*x))/m - (d + e*x)**m*(d/(e*x) + S(1))**(-m)*hyper((-m, -m, -m), (-m + S(1), -m + S(1)), -d/(e*x))/m**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*x**n))**S(3), x), x, S(6)*a*b**S(2)*n**S(2)*x - S(6)*b**S(3)*n**S(3)*x + S(6)*b**S(3)*n**S(2)*x*log(c*x**n) - S(3)*b*n*x*(a + b*log(c*x**n))**S(2) + x*(a + b*log(c*x**n))**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*x**n))**S(2), x), x, -S(2)*a*b*n*x + S(2)*b**S(2)*n**S(2)*x - S(2)*b**S(2)*n*x*log(c*x**n) + x*(a + b*log(c*x**n))**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*log(c*x**n), x), x, a*x - b*n*x + b*x*log(c*x**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*log(c*x**n)), x), x, x*(c*x**n)**(-S(1)/n)*exp(-a/(b*n))*Ei((a + b*log(c*x**n))/(b*n))/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*x**n))**(S(-2)), x), x, -x/(b*n*(a + b*log(c*x**n))) + x*(c*x**n)**(-S(1)/n)*exp(-a/(b*n))*Ei((a + b*log(c*x**n))/(b*n))/(b**S(2)*n**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*x**n))**(S(-3)), x), x, -x/(S(2)*b*n*(a + b*log(c*x**n))**S(2)) - x/(S(2)*b**S(2)*n**S(2)*(a + b*log(c*x**n))) + x*(c*x**n)**(-S(1)/n)*exp(-a/(b*n))*Ei((a + b*log(c*x**n))/(b*n))/(S(2)*b**S(3)*n**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(c*x**n))**m, x), x, x*(c*x**n)**(-S(1)/n)*((-a - b*log(c*x**n))/(b*n))**(-m)*(a + b*log(c*x**n))**m*Gamma(m + S(1), (-a - b*log(c*x**n))/(b*n))*exp(-a/(b*n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(a + b*log(c*x**n)), x), x, x**(m + S(1))*(c*x**n)**(-(m + S(1))/n)*exp(-a*(m + S(1))/(b*n))*Ei((a + b*log(c*x**n))*(m + S(1))/(b*n))/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(a + b*log(c*x**n))**S(2), x), x, -x**(m + S(1))/(b*n*(a + b*log(c*x**n))) + x**(m + S(1))*(c*x**n)**(-(m + S(1))/n)*(m + S(1))*exp(-a*(m + S(1))/(b*n))*Ei((a + b*log(c*x**n))*(m + S(1))/(b*n))/(b**S(2)*n**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*log(c*x**n))**p, x), x, x**(m + S(1))*(c*x**n)**(-(m + S(1))/n)*((a + b*log(c*x**n))*(-m + S(-1))/(b*n))**(-p)*(a + b*log(c*x**n))**p*Gamma(p + S(1), (a + b*log(c*x**n))*(-m + S(-1))/(b*n))*exp(-a*(m + S(1))/(b*n))/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*log(-b*x**n/a)/(a + b*x**n), x), x, -polylog(S(2), (a + b*x**n)/a)/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(a + b*x**S(2))**p), x), x, x**(m + S(1))*log(c*(a + b*x**S(2))**p)/(m + S(1)) - S(2)*b*p*x**(m + S(3))*hyper((S(1), m/S(2) + S(3)/2), (m/S(2) + S(5)/2,), -b*x**S(2)/a)/(a*(m**S(2) + S(4)*m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c*(a + b*x**S(2))**p), x), x, S(2)*a**(S(5)/2)*p*atan(sqrt(b)*x/sqrt(a))/(S(5)*b**(S(5)/2)) - S(2)*a**S(2)*p*x/(S(5)*b**S(2)) + S(2)*a*p*x**S(3)/(S(15)*b) - S(2)*p*x**S(5)/S(25) + x**S(5)*log(c*(a + b*x**S(2))**p)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*x**S(2))**p), x), x, -a**S(2)*p*log(a + b*x**S(2))/(S(4)*b**S(2)) + a*p*x**S(2)/(S(4)*b) - p*x**S(4)/S(8) + x**S(4)*log(c*(a + b*x**S(2))**p)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x**S(2))**p), x), x, -S(2)*a**(S(3)/2)*p*atan(sqrt(b)*x/sqrt(a))/(S(3)*b**(S(3)/2)) + S(2)*a*p*x/(S(3)*b) - S(2)*p*x**S(3)/S(9) + x**S(3)*log(c*(a + b*x**S(2))**p)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x**S(2))**p), x), x, -p*x**S(2)/S(2) + (a/S(2) + b*x**S(2)/S(2))*log(c*(a + b*x**S(2))**p)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p), x), x, S(2)*sqrt(a)*p*atan(sqrt(b)*x/sqrt(a))/sqrt(b) - S(2)*p*x + x*log(c*(a + b*x**S(2))**p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x, x), x, p*polylog(S(2), (a + b*x**S(2))/a)/S(2) + log(c*(a + b*x**S(2))**p)*log(-b*x**S(2)/a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x**S(2), x), x, -log(c*(a + b*x**S(2))**p)/x + S(2)*sqrt(b)*p*atan(sqrt(b)*x/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x**S(3), x), x, b*p*log(x)/a - (a/S(2) + b*x**S(2)/S(2))*log(c*(a + b*x**S(2))**p)/(a*x**S(2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x**S(3), x), x, -log(c*(a + b*x**S(2))**p)/(S(2)*x**S(2)) + b*p*log(x)/a - b*p*log(a + b*x**S(2))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x**S(4), x), x, -log(c*(a + b*x**S(2))**p)/(S(3)*x**S(3)) - S(2)*b*p/(S(3)*a*x) - S(2)*b**(S(3)/2)*p*atan(sqrt(b)*x/sqrt(a))/(S(3)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x**S(5), x), x, -log(c*(a + b*x**S(2))**p)/(S(4)*x**S(4)) - b*p/(S(4)*a*x**S(2)) - b**S(2)*p*log(x)/(S(2)*a**S(2)) + b**S(2)*p*log(a + b*x**S(2))/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x**S(6), x), x, -log(c*(a + b*x**S(2))**p)/(S(5)*x**S(5)) - S(2)*b*p/(S(15)*a*x**S(3)) + S(2)*b**S(2)*p/(S(5)*a**S(2)*x) + S(2)*b**(S(5)/2)*p*atan(sqrt(b)*x/sqrt(a))/(S(5)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/x**S(7), x), x, -log(c*(a + b*x**S(2))**p)/(S(6)*x**S(6)) - b*p/(S(12)*a*x**S(4)) + b**S(2)*p/(S(6)*a**S(2)*x**S(2)) + b**S(3)*p*log(x)/(S(3)*a**S(3)) - b**S(3)*p*log(a + b*x**S(2))/(S(6)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(a + b*x**S(3))**p), x), x, x**(m + S(1))*log(c*(a + b*x**S(3))**p)/(m + S(1)) - S(3)*b*p*x**(m + S(4))*hyper((S(1), m/S(3) + S(4)/3), (m/S(3) + S(7)/3,), -b*x**S(3)/a)/(a*(m**S(2) + S(5)*m + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*log(c*(a + b*x**S(3))**p), x), x, -a**S(2)*p*log(a + b*x**S(3))/(S(6)*b**S(2)) + a*p*x**S(3)/(S(6)*b) - p*x**S(6)/S(12) + x**S(6)*log(c*(a + b*x**S(3))**p)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c*(a + b*x**S(3))**p), x), x, a**(S(5)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(5)*b**(S(5)/3)) - a**(S(5)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(10)*b**(S(5)/3)) + sqrt(S(3))*a**(S(5)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(5)*b**(S(5)/3)) + S(3)*a*p*x**S(2)/(S(10)*b) - S(3)*p*x**S(5)/S(25) + x**S(5)*log(c*(a + b*x**S(3))**p)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*x**S(3))**p), x), x, -a**(S(4)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(4)*b**(S(4)/3)) + a**(S(4)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(8)*b**(S(4)/3)) + sqrt(S(3))*a**(S(4)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(4)*b**(S(4)/3)) + S(3)*a*p*x/(S(4)*b) - S(3)*p*x**S(4)/S(16) + x**S(4)*log(c*(a + b*x**S(3))**p)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x**S(3))**p), x), x, -p*x**S(3)/S(3) + (a/S(3) + b*x**S(3)/S(3))*log(c*(a + b*x**S(3))**p)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x**S(3))**p), x), x, -a**(S(2)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(2)*b**(S(2)/3)) + a**(S(2)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(4)*b**(S(2)/3)) - sqrt(S(3))*a**(S(2)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(2)*b**(S(2)/3)) - S(3)*p*x**S(2)/S(4) + x**S(2)*log(c*(a + b*x**S(3))**p)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p), x), x, a**(S(1)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/b**(S(1)/3) - a**(S(1)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*b**(S(1)/3)) - sqrt(S(3))*a**(S(1)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/b**(S(1)/3) - S(3)*p*x + x*log(c*(a + b*x**S(3))**p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/x, x), x, p*polylog(S(2), (a + b*x**S(3))/a)/S(3) + log(c*(a + b*x**S(3))**p)*log(-b*x**S(3)/a)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/x**S(2), x), x, -log(c*(a + b*x**S(3))**p)/x - b**(S(1)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/a**(S(1)/3) + b**(S(1)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*a**(S(1)/3)) - sqrt(S(3))*b**(S(1)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/a**(S(1)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/x**S(3), x), x, -log(c*(a + b*x**S(3))**p)/(S(2)*x**S(2)) + b**(S(2)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(2)*a**(S(2)/3)) - b**(S(2)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(4)*a**(S(2)/3)) - sqrt(S(3))*b**(S(2)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(2)*a**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/x**S(4), x), x, -log(c*(a + b*x**S(3))**p)/(S(3)*x**S(3)) + b*p*log(x)/a - b*p*log(a + b*x**S(3))/(S(3)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/x**S(5), x), x, -log(c*(a + b*x**S(3))**p)/(S(4)*x**S(4)) - S(3)*b*p/(S(4)*a*x) + b**(S(4)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(4)*a**(S(4)/3)) - b**(S(4)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(8)*a**(S(4)/3)) + sqrt(S(3))*b**(S(4)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(4)*a**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/x**S(6), x), x, -log(c*(a + b*x**S(3))**p)/(S(5)*x**S(5)) - S(3)*b*p/(S(10)*a*x**S(2)) - b**(S(5)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(5)*a**(S(5)/3)) + b**(S(5)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(10)*a**(S(5)/3)) + sqrt(S(3))*b**(S(5)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(5)*a**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/x**S(7), x), x, -log(c*(a + b*x**S(3))**p)/(S(6)*x**S(6)) - b*p/(S(6)*a*x**S(3)) - b**S(2)*p*log(x)/(S(2)*a**S(2)) + b**S(2)*p*log(a + b*x**S(3))/(S(6)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(a + b*sqrt(x))**p), x), x, x**(m + S(1))*log(c*(a + b*sqrt(x))**p)/(m + S(1)) - b*p*x**(m + S(3)/2)*hyper((S(1), S(2)*m + S(3)), (S(2)*m + S(4),), -b*sqrt(x)/a)/(a*(S(2)*m**S(2) + S(5)*m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*sqrt(x))**p), x), x, -a**S(8)*p*log(a + b*sqrt(x))/(S(4)*b**S(8)) + a**S(7)*p*sqrt(x)/(S(4)*b**S(7)) - a**S(6)*p*x/(S(8)*b**S(6)) + a**S(5)*p*x**(S(3)/2)/(S(12)*b**S(5)) - a**S(4)*p*x**S(2)/(S(16)*b**S(4)) + a**S(3)*p*x**(S(5)/2)/(S(20)*b**S(3)) - a**S(2)*p*x**S(3)/(S(24)*b**S(2)) + a*p*x**(S(7)/2)/(S(28)*b) - p*x**S(4)/S(32) + x**S(4)*log(c*(a + b*sqrt(x))**p)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*sqrt(x))**p), x), x, -a**S(6)*p*log(a + b*sqrt(x))/(S(3)*b**S(6)) + a**S(5)*p*sqrt(x)/(S(3)*b**S(5)) - a**S(4)*p*x/(S(6)*b**S(4)) + a**S(3)*p*x**(S(3)/2)/(S(9)*b**S(3)) - a**S(2)*p*x**S(2)/(S(12)*b**S(2)) + a*p*x**(S(5)/2)/(S(15)*b) - p*x**S(3)/S(18) + x**S(3)*log(c*(a + b*sqrt(x))**p)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*sqrt(x))**p), x), x, -a**S(4)*p*log(a + b*sqrt(x))/(S(2)*b**S(4)) + a**S(3)*p*sqrt(x)/(S(2)*b**S(3)) - a**S(2)*p*x/(S(4)*b**S(2)) + a*p*x**(S(3)/2)/(S(6)*b) - p*x**S(2)/S(8) + x**S(2)*log(c*(a + b*sqrt(x))**p)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*sqrt(x))**p), x), x, -a**S(2)*p*log(a + b*sqrt(x))/b**S(2) + a*p*sqrt(x)/b - p*x/S(2) + x*log(c*(a + b*sqrt(x))**p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*sqrt(x))**p)/x, x), x, S(2)*p*polylog(S(2), (a + b*sqrt(x))/a) + S(2)*log(c*(a + b*sqrt(x))**p)*log(-b*sqrt(x)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*sqrt(x))**p)/x**S(2), x), x, -log(c*(a + b*sqrt(x))**p)/x - b*p/(a*sqrt(x)) - b**S(2)*p*log(x)/(S(2)*a**S(2)) + b**S(2)*p*log(a + b*sqrt(x))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*sqrt(x))**p)/x**S(3), x), x, -log(c*(a + b*sqrt(x))**p)/(S(2)*x**S(2)) - b*p/(S(6)*a*x**(S(3)/2)) + b**S(2)*p/(S(4)*a**S(2)*x) - b**S(3)*p/(S(2)*a**S(3)*sqrt(x)) - b**S(4)*p*log(x)/(S(4)*a**S(4)) + b**S(4)*p*log(a + b*sqrt(x))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*sqrt(x))**p)/x**S(4), x), x, -log(c*(a + b*sqrt(x))**p)/(S(3)*x**S(3)) - b*p/(S(15)*a*x**(S(5)/2)) + b**S(2)*p/(S(12)*a**S(2)*x**S(2)) - b**S(3)*p/(S(9)*a**S(3)*x**(S(3)/2)) + b**S(4)*p/(S(6)*a**S(4)*x) - b**S(5)*p/(S(3)*a**S(5)*sqrt(x)) - b**S(6)*p*log(x)/(S(6)*a**S(6)) + b**S(6)*p*log(a + b*sqrt(x))/(S(3)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*sqrt(x))/sqrt(x), x), x, -S(2)*sqrt(x) + S(2)*(a + b*sqrt(x))*log(a + b*sqrt(x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(a + b/x)**p), x), x, p*x**(m + S(1))*hyper((S(1), m + S(1)), (m + S(2),), -a*x/b)/(m + S(1))**S(2) + x**(m + S(1))*log(c*(a + b/x)**p)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c*(a + b/x)**p), x), x, x**S(5)*log(c*(a + b/x)**p)/S(5) + b*p*x**S(4)/(S(20)*a) - b**S(2)*p*x**S(3)/(S(15)*a**S(2)) + b**S(3)*p*x**S(2)/(S(10)*a**S(3)) - b**S(4)*p*x/(S(5)*a**S(4)) + b**S(5)*p*log(a*x + b)/(S(5)*a**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b/x)**p), x), x, x**S(4)*log(c*(a + b/x)**p)/S(4) + b*p*x**S(3)/(S(12)*a) - b**S(2)*p*x**S(2)/(S(8)*a**S(2)) + b**S(3)*p*x/(S(4)*a**S(3)) - b**S(4)*p*log(a*x + b)/(S(4)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b/x)**p), x), x, x**S(3)*log(c*(a + b/x)**p)/S(3) + b*p*x**S(2)/(S(6)*a) - b**S(2)*p*x/(S(3)*a**S(2)) + b**S(3)*p*log(a*x + b)/(S(3)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b/x)**p), x), x, x**S(2)*log(c*(a + b/x)**p)/S(2) + b*p*x/(S(2)*a) - b**S(2)*p*log(a*x + b)/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p), x), x, x*log(c*(a + b/x)**p) + b*p*log(a*x + b)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/x, x), x, -p*polylog(S(2), (a + b/x)/a) - log(c*(a + b/x)**p)*log(-b/(a*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/x**S(2), x), x, p/x - (a + b/x)*log(c*(a + b/x)**p)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/x**S(3), x), x, -a**S(2)*p*log(x)/(S(2)*b**S(2)) + a**S(2)*p*log(a*x + b)/(S(2)*b**S(2)) - a*p/(S(2)*b*x) + p/(S(4)*x**S(2)) - log(c*(a + b/x)**p)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/x**S(4), x), x, a**S(3)*p*log(x)/(S(3)*b**S(3)) - a**S(3)*p*log(a*x + b)/(S(3)*b**S(3)) + a**S(2)*p/(S(3)*b**S(2)*x) - a*p/(S(6)*b*x**S(2)) + p/(S(9)*x**S(3)) - log(c*(a + b/x)**p)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/x**S(5), x), x, -a**S(4)*p*log(x)/(S(4)*b**S(4)) + a**S(4)*p*log(a*x + b)/(S(4)*b**S(4)) - a**S(3)*p/(S(4)*b**S(3)*x) + a**S(2)*p/(S(8)*b**S(2)*x**S(2)) - a*p/(S(12)*b*x**S(3)) + p/(S(16)*x**S(4)) - log(c*(a + b/x)**p)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(b/x + S(1))/x, x), x, polylog(S(2), -b/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(a + b/x**S(2))**p), x), x, S(2)*p*x**(m + S(1))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -a*x**S(2)/b)/(m + S(1))**S(2) + x**(m + S(1))*log(c*(a + b/x**S(2))**p)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c*(a + b/x**S(2))**p), x), x, x**S(5)*log(c*(a + b/x**S(2))**p)/S(5) + S(2)*b*p*x**S(3)/(S(15)*a) - S(2)*b**S(2)*p*x/(S(5)*a**S(2)) + S(2)*b**(S(5)/2)*p*atan(sqrt(a)*x/sqrt(b))/(S(5)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b/x**S(2))**p), x), x, x**S(4)*log(c*(a + b/x**S(2))**p)/S(4) + b*p*x**S(2)/(S(4)*a) - b**S(2)*p*log(a*x**S(2) + b)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b/x**S(2))**p), x), x, x**S(3)*log(c*(a + b/x**S(2))**p)/S(3) + S(2)*b*p*x/(S(3)*a) - S(2)*b**(S(3)/2)*p*atan(sqrt(a)*x/sqrt(b))/(S(3)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b/x**S(2))**p), x), x, x**S(2)*log(c*(a + b/x**S(2))**p)/S(2) + b*p*log(a*x**S(2) + b)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p), x), x, x*log(c*(a + b/x**S(2))**p) + S(2)*sqrt(b)*p*atan(sqrt(a)*x/sqrt(b))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/x, x), x, -p*polylog(S(2), (a + b/x**S(2))/a)/S(2) - log(c*(a + b/x**S(2))**p)*log(-b/(a*x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/x**S(2), x), x, S(2)*sqrt(a)*p*atan(sqrt(a)*x/sqrt(b))/sqrt(b) + S(2)*p/x - log(c*(a + b/x**S(2))**p)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/x**S(3), x), x, p/(S(2)*x**S(2)) - (a/S(2) + b/(S(2)*x**S(2)))*log(c*(a + b/x**S(2))**p)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/x**S(4), x), x, -S(2)*a**(S(3)/2)*p*atan(sqrt(a)*x/sqrt(b))/(S(3)*b**(S(3)/2)) - S(2)*a*p/(S(3)*b*x) + S(2)*p/(S(9)*x**S(3)) - log(c*(a + b/x**S(2))**p)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(c*(a + b*x**n)**p), x), x, x**(m + S(1))*log(c*(a + b*x**n)**p)/(m + S(1)) - b*n*p*x**(m + n + S(1))*hyper((S(1), (m + n + S(1))/n), ((m + S(2)*n + S(1))/n,), -b*x**n/a)/(a*(m + S(1))*(m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x**n)**p), x), x, x**S(3)*log(c*(a + b*x**n)**p)/S(3) - b*n*p*x**(n + S(3))*hyper((S(1), (n + S(3))/n), (S(2) + S(3)/n,), -b*x**n/a)/(S(3)*a*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x**n)**p), x), x, x**S(2)*log(c*(a + b*x**n)**p)/S(2) - b*n*p*x**(n + S(2))*hyper((S(1), (n + S(2))/n), (S(2) + S(2)/n,), -b*x**n/a)/(S(2)*a*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**n)**p), x), x, x*log(c*(a + b*x**n)**p) - b*n*p*x**(n + S(1))*hyper((S(1), S(1) + S(1)/n), (S(2) + S(1)/n,), -b*x**n/a)/(a*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**n)**p)/x, x), x, p*polylog(S(2), (a + b*x**n)/a)/n + log(c*(a + b*x**n)**p)*log(-b*x**n/a)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**n)**p)/x**S(2), x), x, -log(c*(a + b*x**n)**p)/x - b*n*p*x**(n + S(-1))*hyper((S(1), (n + S(-1))/n), (S(2) - S(1)/n,), -b*x**n/a)/(a*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**n)**p)/x**S(3), x), x, -log(c*(a + b*x**n)**p)/(S(2)*x**S(2)) - b*n*p*x**(n + S(-2))*hyper((S(1), (n + S(-2))/n), (S(2) - S(2)/n,), -b*x**n/a)/(S(2)*a*(-n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**n)**p)/x**S(4), x), x, -log(c*(a + b*x**n)**p)/(S(3)*x**S(3)) - b*n*p*x**(n + S(-3))*hyper((S(1), (n + S(-3))/n), (S(2) - S(3)/n,), -b*x**n/a)/(S(3)*a*(-n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**m*log(c*(a + b*x)**p), x), x, b*p*(d + e*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), b*(d + e*x)/(-a*e + b*d))/(e*(m + S(1))*(m + S(2))*(-a*e + b*d)) + (d + e*x)**(m + S(1))*log(c*(a + b*x)**p)/(e*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)*log(c*(a + b*x)**p), x), x, -p*(d + e*x)**S(4)/(S(16)*e) + (d + e*x)**S(4)*log(c*(a + b*x)**p)/(S(4)*e) - p*(d + e*x)**S(3)*(-a*e/S(12) + b*d/S(12))/(b*e) - p*(d + e*x)**S(2)*(-a*e + b*d)**S(2)/(S(8)*b**S(2)*e) - p*x*(-a*e + b*d)**S(3)/(S(4)*b**S(3)) - p*(-a*e + b*d)**S(4)*log(a + b*x)/(S(4)*b**S(4)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)*log(c*(a + b*x)**p), x), x, -p*(d + e*x)**S(3)/(S(9)*e) + (d + e*x)**S(3)*log(c*(a + b*x)**p)/(S(3)*e) - p*(d + e*x)**S(2)*(-a*e/S(6) + b*d/S(6))/(b*e) - p*x*(-a*e + b*d)**S(2)/(S(3)*b**S(2)) - p*(-a*e + b*d)**S(3)*log(a + b*x)/(S(3)*b**S(3)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*log(c*(a + b*x)**p), x), x, -p*(d + e*x)**S(2)/(S(4)*e) + (d + e*x)**S(2)*log(c*(a + b*x)**p)/(S(2)*e) + p*x*(a*e/S(2) - b*d/S(2))/b - p*(-a*e + b*d)**S(2)*log(a + b*x)/(S(2)*b**S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p), x), x, -p*x + (a + b*x)*log(c*(a + b*x)**p)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(d + e*x), x), x, p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/e + log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(d + e*x)**S(2), x), x, b*p*log(a + b*x)/(e*(-a*e + b*d)) - b*p*log(d + e*x)/(e*(-a*e + b*d)) - log(c*(a + b*x)**p)/(e*(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(d + e*x)**S(3), x), x, b**S(2)*p*log(a + b*x)/(S(2)*e*(-a*e + b*d)**S(2)) - b**S(2)*p*log(d + e*x)/(S(2)*e*(-a*e + b*d)**S(2)) + b*p/(S(2)*e*(d + e*x)*(-a*e + b*d)) - log(c*(a + b*x)**p)/(S(2)*e*(d + e*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(d + e*x)**S(4), x), x, b**S(3)*p*log(a + b*x)/(S(3)*e*(-a*e + b*d)**S(3)) - b**S(3)*p*log(d + e*x)/(S(3)*e*(-a*e + b*d)**S(3)) + b**S(2)*p/(S(3)*e*(d + e*x)*(-a*e + b*d)**S(2)) + b*p/(S(6)*e*(d + e*x)**S(2)*(-a*e + b*d)) - log(c*(a + b*x)**p)/(S(3)*e*(d + e*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**m*log(c*(a + b*x**S(2))**p), x), x, sqrt(b)*p*(d + e*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/(e*(m + S(1))*(m + S(2))*(sqrt(b)*d + e*sqrt(-a))) + sqrt(b)*p*(d + e*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/(e*(m + S(1))*(m + S(2))*(sqrt(b)*d - e*sqrt(-a))) + (d + e*x)**(m + S(1))*log(c*(a + b*x**S(2))**p)/(e*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)*log(c*(a + b*x**S(2))**p), x), x, S(2)*sqrt(a)*d*p*(-a*e**S(2) + b*d**S(2))*atan(sqrt(b)*x/sqrt(a))/b**(S(3)/2) - S(2)*d*e**S(2)*p*x**S(3)/S(3) - e**S(3)*p*x**S(4)/S(8) + (d + e*x)**S(4)*log(c*(a + b*x**S(2))**p)/(S(4)*e) - S(2)*d*p*x*(-a*e**S(2) + b*d**S(2))/b - e*p*x**S(2)*(-a*e**S(2) + S(6)*b*d**S(2))/(S(4)*b) - p*(a**S(2)*e**S(4)/S(4) - S(3)*a*b*d**S(2)*e**S(2)/S(2) + b**S(2)*d**S(4)/S(4))*log(a + b*x**S(2))/(b**S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)*log(c*(a + b*x**S(2))**p), x), x, sqrt(a)*p*(-S(2)*a*e**S(2)/S(3) + S(2)*b*d**S(2))*atan(sqrt(b)*x/sqrt(a))/b**(S(3)/2) - d*e*p*x**S(2) - S(2)*e**S(2)*p*x**S(3)/S(9) + (d + e*x)**S(3)*log(c*(a + b*x**S(2))**p)/(S(3)*e) - d*p*(-S(3)*a*e**S(2) + b*d**S(2))*log(a + b*x**S(2))/(S(3)*b*e) + p*x*(S(2)*a*e**S(2)/S(3) - S(2)*b*d**S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*log(c*(a + b*x**S(2))**p), x), x, S(2)*sqrt(a)*d*p*atan(sqrt(b)*x/sqrt(a))/sqrt(b) - S(2)*d*p*x - e*p*x**S(2)/S(2) + (d + e*x)**S(2)*log(c*(a + b*x**S(2))**p)/(S(2)*e) - p*(-a*e**S(2)/S(2) + b*d**S(2)/S(2))*log(a + b*x**S(2))/(b*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p), x), x, S(2)*sqrt(a)*p*atan(sqrt(b)*x/sqrt(a))/sqrt(b) - S(2)*p*x + x*log(c*(a + b*x**S(2))**p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/(d + e*x), x), x, -p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/e - p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/e - p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/e - p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/e + log(c*(a + b*x**S(2))**p)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/(d + e*x)**S(2), x), x, S(2)*sqrt(a)*sqrt(b)*p*atan(sqrt(b)*x/sqrt(a))/(a*e**S(2) + b*d**S(2)) + b*d*p*log(a + b*x**S(2))/(e*(a*e**S(2) + b*d**S(2))) - S(2)*b*d*p*log(d + e*x)/(e*(a*e**S(2) + b*d**S(2))) - log(c*(a + b*x**S(2))**p)/(e*(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/(d + e*x)**S(3), x), x, S(2)*sqrt(a)*b**(S(3)/2)*d*p*atan(sqrt(b)*x/sqrt(a))/(a*e**S(2) + b*d**S(2))**S(2) + b*d*p/(e*(d + e*x)*(a*e**S(2) + b*d**S(2))) + b*p*(-a*e**S(2) + b*d**S(2))*log(a + b*x**S(2))/(S(2)*e*(a*e**S(2) + b*d**S(2))**S(2)) - b*p*(-a*e**S(2) + b*d**S(2))*log(d + e*x)/(e*(a*e**S(2) + b*d**S(2))**S(2)) - log(c*(a + b*x**S(2))**p)/(S(2)*e*(d + e*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**m*log(c*(a + b*x**S(3))**p), x), x, b**(S(1)/3)*p*(d + e*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/(e*(m + S(1))*(m + S(2))*(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d)) + b**(S(1)/3)*p*(d + e*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/(e*(m + S(1))*(m + S(2))*((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d)) + b**(S(1)/3)*p*(d + e*x)**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/(e*(m + S(1))*(m + S(2))*(-a**(S(1)/3)*e + b**(S(1)/3)*d)) + (d + e*x)**(m + S(1))*log(c*(a + b*x**S(3))**p)/(e*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)*log(c*(a + b*x**S(3))**p), x), x, a**(S(1)/3)*p*(-S(6)*a**(S(1)/3)*b**(S(2)/3)*d**S(2)*e - a*e**S(3) + S(4)*b*d**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(4)*b**(S(4)/3)) - a**(S(1)/3)*p*(-S(6)*a**(S(1)/3)*b**(S(2)/3)*d**S(2)*e - a*e**S(3) + S(4)*b*d**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(8)*b**(S(4)/3)) - sqrt(S(3))*a**(S(1)/3)*p*(S(6)*a**(S(1)/3)*b**(S(2)/3)*d**S(2)*e - a*e**S(3) + S(4)*b*d**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(4)*b**(S(4)/3)) - S(9)*d**S(2)*e*p*x**S(2)/S(4) - d*e**S(2)*p*x**S(3) - S(3)*e**S(3)*p*x**S(4)/S(16) + (d + e*x)**S(4)*log(c*(a + b*x**S(3))**p)/(S(4)*e) - d*p*(-S(4)*a*e**S(3) + b*d**S(3))*log(a + b*x**S(3))/(S(4)*b*e) + p*x*(S(3)*a*e**S(3)/S(4) - S(3)*b*d**S(3))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)*log(c*(a + b*x**S(3))**p), x), x, a**(S(1)/3)*d*p*(-a**(S(1)/3)*e + b**(S(1)/3)*d)*log(a**(S(1)/3) + b**(S(1)/3)*x)/b**(S(2)/3) - a**(S(1)/3)*d*p*(-a**(S(1)/3)*e + b**(S(1)/3)*d)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*b**(S(2)/3)) - sqrt(S(3))*a**(S(1)/3)*d*p*(a**(S(1)/3)*e + b**(S(1)/3)*d)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/b**(S(2)/3) - S(3)*d**S(2)*p*x - S(3)*d*e*p*x**S(2)/S(2) - e**S(2)*p*x**S(3)/S(3) + (d + e*x)**S(3)*log(c*(a + b*x**S(3))**p)/(S(3)*e) - p*(-a*e**S(3)/S(3) + b*d**S(3)/S(3))*log(a + b*x**S(3))/(b*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*log(c*(a + b*x**S(3))**p), x), x, a**(S(1)/3)*p*(-a**(S(1)/3)*e + S(2)*b**(S(1)/3)*d)*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(2)*b**(S(2)/3)) - a**(S(1)/3)*p*(-a**(S(1)/3)*e + S(2)*b**(S(1)/3)*d)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(4)*b**(S(2)/3)) - sqrt(S(3))*a**(S(1)/3)*p*(a**(S(1)/3)*e + S(2)*b**(S(1)/3)*d)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(2)*b**(S(2)/3)) - d**S(2)*p*log(a + b*x**S(3))/(S(2)*e) - S(3)*d*p*x - S(3)*e*p*x**S(2)/S(4) + (d + e*x)**S(2)*log(c*(a + b*x**S(3))**p)/(S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p), x), x, a**(S(1)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/b**(S(1)/3) - a**(S(1)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*b**(S(1)/3)) - sqrt(S(3))*a**(S(1)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/b**(S(1)/3) - S(3)*p*x + x*log(c*(a + b*x**S(3))**p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/(d + e*x), x), x, -p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e - p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e - p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e - p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/e - p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e - p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e + log(c*(a + b*x**S(3))**p)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/(d + e*x)**S(2), x), x, a**(S(1)/3)*b**(S(1)/3)*p*(a**(S(1)/3)*e + b**(S(1)/3)*d)*log(a**(S(1)/3) + b**(S(1)/3)*x)/(-a*e**S(3) + b*d**S(3)) - a**(S(1)/3)*b**(S(1)/3)*p*(a**(S(1)/3)*e + b**(S(1)/3)*d)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*(-a*e**S(3) + b*d**S(3))) - sqrt(S(3))*a**(S(1)/3)*b**(S(1)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(a**(S(2)/3)*e**S(2) + a**(S(1)/3)*b**(S(1)/3)*d*e + b**(S(2)/3)*d**S(2)) + b*d**S(2)*p*log(a + b*x**S(3))/(e*(-a*e**S(3) + b*d**S(3))) - S(3)*b*d**S(2)*p*log(d + e*x)/(e*(-a*e**S(3) + b*d**S(3))) - log(c*(a + b*x**S(3))**p)/(e*(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/(d + e*x)**S(3), x), x, -sqrt(S(3))*a**(S(1)/3)*b**(S(2)/3)*p*(-S(3)*a**(S(1)/3)*b**(S(2)/3)*d**S(2)*e + a*e**S(3) + S(2)*b*d**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(2)*(-a*e**S(3) + b*d**S(3))**S(2)) + a**(S(1)/3)*b**(S(2)/3)*p*(S(3)*a**(S(1)/3)*b**(S(2)/3)*d**S(2)*e + a*e**S(3) + S(2)*b*d**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(2)*(-a*e**S(3) + b*d**S(3))**S(2)) - a**(S(1)/3)*b**(S(2)/3)*p*(S(3)*a**(S(1)/3)*b**(S(2)/3)*d**S(2)*e + a*e**S(3) + S(2)*b*d**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(4)*(-a*e**S(3) + b*d**S(3))**S(2)) + S(3)*b*d**S(2)*p/(S(2)*e*(d + e*x)*(-a*e**S(3) + b*d**S(3))) + b*d*p*(S(2)*a*e**S(3) + b*d**S(3))*log(a + b*x**S(3))/(S(2)*e*(-a*e**S(3) + b*d**S(3))**S(2)) - S(3)*b*d*p*(S(2)*a*e**S(3) + b*d**S(3))*log(d + e*x)/(S(2)*e*(-a*e**S(3) + b*d**S(3))**S(2)) - log(c*(a + b*x**S(3))**p)/(S(2)*e*(d + e*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b/x)/(c + d*x), x), x, log(-d*x/c)*log(c + d*x)/d - log(-d*(a*x + b)/(a*c - b*d))*log(c + d*x)/d + log(a + b/x)*log(c + d*x)/d + polylog(S(2), (c + d*x)/c)/d - polylog(S(2), a*(c + d*x)/(a*c - b*d))/d, expand=True, _diff=True, _numerical=True) # recursion sympy and mathematica assert rubi_test(rubi_integrate(log(a + b*x**n)/(c + d*x), x), x, -b*n*Integral(x**(n + S(-1))*log(c + d*x)/(a + b*x**n), x)/d + log(a + b*x**n)*log(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x)/(c + d*x), x), x, log(a*x)*log((c + d*x)/c)/d + polylog(S(2), -d*x/c)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a/x)/(c + d*x), x), x, log(a/x)*log((c + d*x)/c)/d - polylog(S(2), -d*x/c)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*x**n)/(c + d*x), x), x, n*polylog(S(2), -d*x/c)/d + log(a*x**n)*log((c + d*x)/c)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**n)/(a + b*x), x), x, n*polylog(S(2), -b*x/a)/b + log(x**n)*log((a + b*x)/a)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*x)**p)/(d + e*x), x), x, a**S(3)*p*log(a + b*x)/(S(3)*b**S(3)*e) + a**S(2)*d*p*log(a + b*x)/(S(2)*b**S(2)*e**S(2)) - a**S(2)*p*x/(S(3)*b**S(2)*e) - a*d*p*x/(S(2)*b*e**S(2)) + a*p*x**S(2)/(S(6)*b*e) - d**S(3)*p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/e**S(4) - d**S(3)*log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/e**S(4) - d**S(2)*p*x/e**S(3) + d*p*x**S(2)/(S(4)*e**S(2)) - d*x**S(2)*log(c*(a + b*x)**p)/(S(2)*e**S(2)) - p*x**S(3)/(S(9)*e) + x**S(3)*log(c*(a + b*x)**p)/(S(3)*e) + d**S(2)*(a + b*x)*log(c*(a + b*x)**p)/(b*e**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x)**p)/(d + e*x), x), x, -a**S(2)*p*log(a + b*x)/(S(2)*b**S(2)*e) + a*p*x/(S(2)*b*e) + d**S(2)*p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/e**S(3) + d**S(2)*log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/e**S(3) + d*p*x/e**S(2) - p*x**S(2)/(S(4)*e) + x**S(2)*log(c*(a + b*x)**p)/(S(2)*e) - d*(a + b*x)*log(c*(a + b*x)**p)/(b*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x)**p)/(d + e*x), x), x, -d*p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/e**S(2) - d*log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/e**S(2) - p*x/e + (a + b*x)*log(c*(a + b*x)**p)/(b*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(d + e*x), x), x, p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/e + log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(x*(d + e*x)), x), x, p*polylog(S(2), (a + b*x)/a)/d - p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/d + log(c*(a + b*x)**p)*log(-b*x/a)/d - log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(x**S(2)*(d + e*x)), x), x, -log(c*(a + b*x)**p)/(d*x) - e*p*polylog(S(2), (a + b*x)/a)/d**S(2) + e*p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/d**S(2) - e*log(c*(a + b*x)**p)*log(-b*x/a)/d**S(2) + e*log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/d**S(2) + b*p*log(x)/(a*d) - b*p*log(a + b*x)/(a*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x)**p)/(x**S(3)*(d + e*x)), x), x, -log(c*(a + b*x)**p)/(S(2)*d*x**S(2)) + e*log(c*(a + b*x)**p)/(d**S(2)*x) + e**S(2)*p*polylog(S(2), (a + b*x)/a)/d**S(3) - e**S(2)*p*polylog(S(2), -e*(a + b*x)/(-a*e + b*d))/d**S(3) + e**S(2)*log(c*(a + b*x)**p)*log(-b*x/a)/d**S(3) - e**S(2)*log(c*(a + b*x)**p)*log(b*(d + e*x)/(-a*e + b*d))/d**S(3) - b*p/(S(2)*a*d*x) - b*e*p*log(x)/(a*d**S(2)) + b*e*p*log(a + b*x)/(a*d**S(2)) - b**S(2)*p*log(x)/(S(2)*a**S(2)*d) + b**S(2)*p*log(a + b*x)/(S(2)*a**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*x**S(2))**p)/(d + e*x), x), x, -S(2)*a**(S(3)/2)*p*atan(sqrt(b)*x/sqrt(a))/(S(3)*b**(S(3)/2)*e) + S(2)*sqrt(a)*d**S(2)*p*atan(sqrt(b)*x/sqrt(a))/(sqrt(b)*e**S(3)) + S(2)*a*p*x/(S(3)*b*e) + d**S(3)*p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/e**S(4) + d**S(3)*p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/e**S(4) + d**S(3)*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/e**S(4) + d**S(3)*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/e**S(4) - d**S(3)*log(c*(a + b*x**S(2))**p)*log(d + e*x)/e**S(4) - S(2)*d**S(2)*p*x/e**S(3) + d**S(2)*x*log(c*(a + b*x**S(2))**p)/e**S(3) + d*p*x**S(2)/(S(2)*e**S(2)) - S(2)*p*x**S(3)/(S(9)*e) + x**S(3)*log(c*(a + b*x**S(2))**p)/(S(3)*e) - d*(a + b*x**S(2))*log(c*(a + b*x**S(2))**p)/(S(2)*b*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x**S(2))**p)/(d + e*x), x), x, -S(2)*sqrt(a)*d*p*atan(sqrt(b)*x/sqrt(a))/(sqrt(b)*e**S(2)) - d**S(2)*p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/e**S(3) - d**S(2)*p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/e**S(3) - d**S(2)*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/e**S(3) - d**S(2)*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/e**S(3) + d**S(2)*log(c*(a + b*x**S(2))**p)*log(d + e*x)/e**S(3) + S(2)*d*p*x/e**S(2) - d*x*log(c*(a + b*x**S(2))**p)/e**S(2) - p*x**S(2)/(S(2)*e) + (a/S(2) + b*x**S(2)/S(2))*log(c*(a + b*x**S(2))**p)/(b*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x**S(2))**p)/(d + e*x), x), x, S(2)*sqrt(a)*p*atan(sqrt(b)*x/sqrt(a))/(sqrt(b)*e) + d*p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/e**S(2) + d*p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/e**S(2) + d*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/e**S(2) + d*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/e**S(2) - d*log(c*(a + b*x**S(2))**p)*log(d + e*x)/e**S(2) - S(2)*p*x/e + x*log(c*(a + b*x**S(2))**p)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/(d + e*x), x), x, -p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/e - p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/e - p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/e - p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/e + log(c*(a + b*x**S(2))**p)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/(x*(d + e*x)), x), x, p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/d + p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/d + p*polylog(S(2), (a + b*x**S(2))/a)/(S(2)*d) + p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/d + p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/d + log(c*(a + b*x**S(2))**p)*log(-b*x**S(2)/a)/(S(2)*d) - log(c*(a + b*x**S(2))**p)*log(d + e*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/(x**S(2)*(d + e*x)), x), x, -log(c*(a + b*x**S(2))**p)/(d*x) - e*p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/d**S(2) - e*p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/d**S(2) - e*p*polylog(S(2), (a + b*x**S(2))/a)/(S(2)*d**S(2)) - e*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/d**S(2) - e*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/d**S(2) - e*log(c*(a + b*x**S(2))**p)*log(-b*x**S(2)/a)/(S(2)*d**S(2)) + e*log(c*(a + b*x**S(2))**p)*log(d + e*x)/d**S(2) + S(2)*sqrt(b)*p*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**p)/(x**S(3)*(d + e*x)), x), x, -log(c*(a + b*x**S(2))**p)/(S(2)*d*x**S(2)) + e*log(c*(a + b*x**S(2))**p)/(d**S(2)*x) + e**S(2)*p*log(-e*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*d - e*sqrt(-a)))*log(d + e*x)/d**S(3) + e**S(2)*p*log(e*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*d + e*sqrt(-a)))*log(d + e*x)/d**S(3) + e**S(2)*p*polylog(S(2), (a + b*x**S(2))/a)/(S(2)*d**S(3)) + e**S(2)*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d - e*sqrt(-a)))/d**S(3) + e**S(2)*p*polylog(S(2), sqrt(b)*(d + e*x)/(sqrt(b)*d + e*sqrt(-a)))/d**S(3) + e**S(2)*log(c*(a + b*x**S(2))**p)*log(-b*x**S(2)/a)/(S(2)*d**S(3)) - e**S(2)*log(c*(a + b*x**S(2))**p)*log(d + e*x)/d**S(3) + b*p*log(x)/(a*d) - b*p*log(a + b*x**S(2))/(S(2)*a*d) - S(2)*sqrt(b)*e*p*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*x**S(3))**p)/(d + e*x), x), x, a**(S(2)/3)*d*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(2)*b**(S(2)/3)*e**S(2)) - a**(S(2)/3)*d*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(4)*b**(S(2)/3)*e**S(2)) + sqrt(S(3))*a**(S(2)/3)*d*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(2)*b**(S(2)/3)*e**S(2)) + a**(S(1)/3)*d**S(2)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(b**(S(1)/3)*e**S(3)) - a**(S(1)/3)*d**S(2)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*b**(S(1)/3)*e**S(3)) - sqrt(S(3))*a**(S(1)/3)*d**S(2)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(b**(S(1)/3)*e**S(3)) + d**S(3)*p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(4) + d**S(3)*p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(4) + d**S(3)*p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(4) + d**S(3)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(4) + d**S(3)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(4) + d**S(3)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(4) - d**S(3)*log(c*(a + b*x**S(3))**p)*log(d + e*x)/e**S(4) - S(3)*d**S(2)*p*x/e**S(3) + d**S(2)*x*log(c*(a + b*x**S(3))**p)/e**S(3) + S(3)*d*p*x**S(2)/(S(4)*e**S(2)) - d*x**S(2)*log(c*(a + b*x**S(3))**p)/(S(2)*e**S(2)) - p*x**S(3)/(S(3)*e) + (a/S(3) + b*x**S(3)/S(3))*log(c*(a + b*x**S(3))**p)/(b*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x**S(3))**p)/(d + e*x), x), x, -a**(S(2)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(2)*b**(S(2)/3)*e) + a**(S(2)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(4)*b**(S(2)/3)*e) - sqrt(S(3))*a**(S(2)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(2)*b**(S(2)/3)*e) - a**(S(1)/3)*d*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(b**(S(1)/3)*e**S(2)) + a**(S(1)/3)*d*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*b**(S(1)/3)*e**S(2)) + sqrt(S(3))*a**(S(1)/3)*d*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(b**(S(1)/3)*e**S(2)) - d**S(2)*p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(3) - d**S(2)*p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(3) - d**S(2)*p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(3) - d**S(2)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(3) - d**S(2)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(3) - d**S(2)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(3) + d**S(2)*log(c*(a + b*x**S(3))**p)*log(d + e*x)/e**S(3) + S(3)*d*p*x/e**S(2) - d*x*log(c*(a + b*x**S(3))**p)/e**S(2) - S(3)*p*x**S(2)/(S(4)*e) + x**S(2)*log(c*(a + b*x**S(3))**p)/(S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x**S(3))**p)/(d + e*x), x), x, a**(S(1)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(b**(S(1)/3)*e) - a**(S(1)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*b**(S(1)/3)*e) - sqrt(S(3))*a**(S(1)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(b**(S(1)/3)*e) + d*p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(2) + d*p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(2) + d*p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e**S(2) + d*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(2) + d*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(2) + d*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e**S(2) - d*log(c*(a + b*x**S(3))**p)*log(d + e*x)/e**S(2) - S(3)*p*x/e + x*log(c*(a + b*x**S(3))**p)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/(d + e*x), x), x, -p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e - p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e - p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/e - p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/e - p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e - p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/e + log(c*(a + b*x**S(3))**p)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/(x*(d + e*x)), x), x, p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d + p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d + p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d + p*polylog(S(2), (a + b*x**S(3))/a)/(S(3)*d) + p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/d + p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/d + p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/d + log(c*(a + b*x**S(3))**p)*log(-b*x**S(3)/a)/(S(3)*d) - log(c*(a + b*x**S(3))**p)*log(d + e*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/(x**S(2)*(d + e*x)), x), x, -log(c*(a + b*x**S(3))**p)/(d*x) - e*p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d**S(2) - e*p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d**S(2) - e*p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d**S(2) - e*p*polylog(S(2), (a + b*x**S(3))/a)/(S(3)*d**S(2)) - e*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/d**S(2) - e*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/d**S(2) - e*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/d**S(2) - e*log(c*(a + b*x**S(3))**p)*log(-b*x**S(3)/a)/(S(3)*d**S(2)) + e*log(c*(a + b*x**S(3))**p)*log(d + e*x)/d**S(2) - b**(S(1)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(a**(S(1)/3)*d) + b**(S(1)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*a**(S(1)/3)*d) - sqrt(S(3))*b**(S(1)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(a**(S(1)/3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(3))**p)/(x**S(3)*(d + e*x)), x), x, -log(c*(a + b*x**S(3))**p)/(S(2)*d*x**S(2)) + e*log(c*(a + b*x**S(3))**p)/(d**S(2)*x) + e**S(2)*p*log(-e*(a**(S(1)/3) + b**(S(1)/3)*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d**S(3) + e**S(2)*p*log(-e*((S(-1))**(S(2)/3)*a**(S(1)/3) + b**(S(1)/3)*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d**S(3) + e**S(2)*p*log((S(-1))**(S(1)/3)*e*(a**(S(1)/3) + (S(-1))**(S(2)/3)*b**(S(1)/3)*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))*log(d + e*x)/d**S(3) + e**S(2)*p*polylog(S(2), (a + b*x**S(3))/a)/(S(3)*d**S(3)) + e**S(2)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-a**(S(1)/3)*e + b**(S(1)/3)*d))/d**S(3) + e**S(2)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/d**S(3) + e**S(2)*p*polylog(S(2), b**(S(1)/3)*(d + e*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*e + b**(S(1)/3)*d))/d**S(3) + e**S(2)*log(c*(a + b*x**S(3))**p)*log(-b*x**S(3)/a)/(S(3)*d**S(3)) - e**S(2)*log(c*(a + b*x**S(3))**p)*log(d + e*x)/d**S(3) + b**(S(1)/3)*e*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(a**(S(1)/3)*d**S(2)) - b**(S(1)/3)*e*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(2)*a**(S(1)/3)*d**S(2)) + sqrt(S(3))*b**(S(1)/3)*e*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(a**(S(1)/3)*d**S(2)) + b**(S(2)/3)*p*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(2)*a**(S(2)/3)*d) - b**(S(2)/3)*p*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(4)*a**(S(2)/3)*d) - sqrt(S(3))*b**(S(2)/3)*p*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(2)*a**(S(2)/3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b/x)**p)/(d + e*x), x), x, -d**S(3)*p*log(-e*x/d)*log(d + e*x)/e**S(4) + d**S(3)*p*log(-e*(a*x + b)/(a*d - b*e))*log(d + e*x)/e**S(4) - d**S(3)*p*polylog(S(2), (d + e*x)/d)/e**S(4) + d**S(3)*p*polylog(S(2), a*(d + e*x)/(a*d - b*e))/e**S(4) - d**S(3)*log(c*(a + b/x)**p)*log(d + e*x)/e**S(4) + d**S(2)*x*log(c*(a + b/x)**p)/e**S(3) - d*x**S(2)*log(c*(a + b/x)**p)/(S(2)*e**S(2)) + x**S(3)*log(c*(a + b/x)**p)/(S(3)*e) + b*d**S(2)*p*log(a*x + b)/(a*e**S(3)) - b*d*p*x/(S(2)*a*e**S(2)) + b*p*x**S(2)/(S(6)*a*e) + b**S(2)*d*p*log(a*x + b)/(S(2)*a**S(2)*e**S(2)) - b**S(2)*p*x/(S(3)*a**S(2)*e) + b**S(3)*p*log(a*x + b)/(S(3)*a**S(3)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b/x)**p)/(d + e*x), x), x, d**S(2)*p*log(-e*x/d)*log(d + e*x)/e**S(3) - d**S(2)*p*log(-e*(a*x + b)/(a*d - b*e))*log(d + e*x)/e**S(3) + d**S(2)*p*polylog(S(2), (d + e*x)/d)/e**S(3) - d**S(2)*p*polylog(S(2), a*(d + e*x)/(a*d - b*e))/e**S(3) + d**S(2)*log(c*(a + b/x)**p)*log(d + e*x)/e**S(3) - d*x*log(c*(a + b/x)**p)/e**S(2) + x**S(2)*log(c*(a + b/x)**p)/(S(2)*e) - b*d*p*log(a*x + b)/(a*e**S(2)) + b*p*x/(S(2)*a*e) - b**S(2)*p*log(a*x + b)/(S(2)*a**S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b/x)**p)/(d + e*x), x), x, -d*p*log(-e*x/d)*log(d + e*x)/e**S(2) + d*p*log(-e*(a*x + b)/(a*d - b*e))*log(d + e*x)/e**S(2) - d*p*polylog(S(2), (d + e*x)/d)/e**S(2) + d*p*polylog(S(2), a*(d + e*x)/(a*d - b*e))/e**S(2) - d*log(c*(a + b/x)**p)*log(d + e*x)/e**S(2) + x*log(c*(a + b/x)**p)/e + b*p*log(a*x + b)/(a*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/(d + e*x), x), x, p*log(-e*x/d)*log(d + e*x)/e - p*log(-e*(a*x + b)/(a*d - b*e))*log(d + e*x)/e + p*polylog(S(2), (d + e*x)/d)/e - p*polylog(S(2), a*(d + e*x)/(a*d - b*e))/e + log(c*(a + b/x)**p)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/(x*(d + e*x)), x), x, -p*log(-e*x/d)*log(d + e*x)/d + p*log(-e*(a*x + b)/(a*d - b*e))*log(d + e*x)/d - p*polylog(S(2), (a + b/x)/a)/d - p*polylog(S(2), (d + e*x)/d)/d + p*polylog(S(2), a*(d + e*x)/(a*d - b*e))/d - log(c*(a + b/x)**p)*log(-b/(a*x))/d - log(c*(a + b/x)**p)*log(d + e*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/(x**S(2)*(d + e*x)), x), x, p/(d*x) + e*p*log(-e*x/d)*log(d + e*x)/d**S(2) - e*p*log(-e*(a*x + b)/(a*d - b*e))*log(d + e*x)/d**S(2) + e*p*polylog(S(2), (a + b/x)/a)/d**S(2) + e*p*polylog(S(2), (d + e*x)/d)/d**S(2) - e*p*polylog(S(2), a*(d + e*x)/(a*d - b*e))/d**S(2) + e*log(c*(a + b/x)**p)*log(-b/(a*x))/d**S(2) + e*log(c*(a + b/x)**p)*log(d + e*x)/d**S(2) - (a + b/x)*log(c*(a + b/x)**p)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x)**p)/(x**S(3)*(d + e*x)), x), x, -a**S(2)*p*log(x)/(S(2)*b**S(2)*d) + a**S(2)*p*log(a*x + b)/(S(2)*b**S(2)*d) - a*p/(S(2)*b*d*x) + p/(S(4)*d*x**S(2)) - log(c*(a + b/x)**p)/(S(2)*d*x**S(2)) - e*p/(d**S(2)*x) - e**S(2)*p*log(-e*x/d)*log(d + e*x)/d**S(3) + e**S(2)*p*log(-e*(a*x + b)/(a*d - b*e))*log(d + e*x)/d**S(3) - e**S(2)*p*polylog(S(2), (a + b/x)/a)/d**S(3) - e**S(2)*p*polylog(S(2), (d + e*x)/d)/d**S(3) + e**S(2)*p*polylog(S(2), a*(d + e*x)/(a*d - b*e))/d**S(3) - e**S(2)*log(c*(a + b/x)**p)*log(-b/(a*x))/d**S(3) - e**S(2)*log(c*(a + b/x)**p)*log(d + e*x)/d**S(3) + e*(a + b/x)*log(c*(a + b/x)**p)/(b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b/x**S(2))**p)/(d + e*x), x), x, -S(2)*d**S(3)*p*log(-e*x/d)*log(d + e*x)/e**S(4) + d**S(3)*p*log(e*(sqrt(b) - x*sqrt(-a))/(sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e**S(4) + d**S(3)*p*log(-e*(sqrt(b) + x*sqrt(-a))/(-sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e**S(4) - S(2)*d**S(3)*p*polylog(S(2), (d + e*x)/d)/e**S(4) + d**S(3)*p*polylog(S(2), sqrt(-a)*(d + e*x)/(-sqrt(b)*e + d*sqrt(-a)))/e**S(4) + d**S(3)*p*polylog(S(2), sqrt(-a)*(d + e*x)/(sqrt(b)*e + d*sqrt(-a)))/e**S(4) - d**S(3)*log(c*(a + b/x**S(2))**p)*log(d + e*x)/e**S(4) + d**S(2)*x*log(c*(a + b/x**S(2))**p)/e**S(3) - d*x**S(2)*log(c*(a + b/x**S(2))**p)/(S(2)*e**S(2)) + x**S(3)*log(c*(a + b/x**S(2))**p)/(S(3)*e) - b*d*p*log(a*x**S(2) + b)/(S(2)*a*e**S(2)) + S(2)*b*p*x/(S(3)*a*e) + S(2)*sqrt(b)*d**S(2)*p*atan(sqrt(a)*x/sqrt(b))/(sqrt(a)*e**S(3)) - S(2)*b**(S(3)/2)*p*atan(sqrt(a)*x/sqrt(b))/(S(3)*a**(S(3)/2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b/x**S(2))**p)/(d + e*x), x), x, S(2)*d**S(2)*p*log(-e*x/d)*log(d + e*x)/e**S(3) - d**S(2)*p*log(e*(sqrt(b) - x*sqrt(-a))/(sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e**S(3) - d**S(2)*p*log(-e*(sqrt(b) + x*sqrt(-a))/(-sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e**S(3) + S(2)*d**S(2)*p*polylog(S(2), (d + e*x)/d)/e**S(3) - d**S(2)*p*polylog(S(2), sqrt(-a)*(d + e*x)/(-sqrt(b)*e + d*sqrt(-a)))/e**S(3) - d**S(2)*p*polylog(S(2), sqrt(-a)*(d + e*x)/(sqrt(b)*e + d*sqrt(-a)))/e**S(3) + d**S(2)*log(c*(a + b/x**S(2))**p)*log(d + e*x)/e**S(3) - d*x*log(c*(a + b/x**S(2))**p)/e**S(2) + x**S(2)*log(c*(a + b/x**S(2))**p)/(S(2)*e) + b*p*log(a*x**S(2) + b)/(S(2)*a*e) - S(2)*sqrt(b)*d*p*atan(sqrt(a)*x/sqrt(b))/(sqrt(a)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b/x**S(2))**p)/(d + e*x), x), x, -S(2)*d*p*log(-e*x/d)*log(d + e*x)/e**S(2) + d*p*log(e*(sqrt(b) - x*sqrt(-a))/(sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e**S(2) + d*p*log(-e*(sqrt(b) + x*sqrt(-a))/(-sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e**S(2) - S(2)*d*p*polylog(S(2), (d + e*x)/d)/e**S(2) + d*p*polylog(S(2), sqrt(-a)*(d + e*x)/(-sqrt(b)*e + d*sqrt(-a)))/e**S(2) + d*p*polylog(S(2), sqrt(-a)*(d + e*x)/(sqrt(b)*e + d*sqrt(-a)))/e**S(2) - d*log(c*(a + b/x**S(2))**p)*log(d + e*x)/e**S(2) + x*log(c*(a + b/x**S(2))**p)/e + S(2)*sqrt(b)*p*atan(sqrt(a)*x/sqrt(b))/(sqrt(a)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/(d + e*x), x), x, S(2)*p*log(-e*x/d)*log(d + e*x)/e - p*log(e*(sqrt(b) - x*sqrt(-a))/(sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e - p*log(-e*(sqrt(b) + x*sqrt(-a))/(-sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/e + S(2)*p*polylog(S(2), (d + e*x)/d)/e - p*polylog(S(2), sqrt(-a)*(d + e*x)/(-sqrt(b)*e + d*sqrt(-a)))/e - p*polylog(S(2), sqrt(-a)*(d + e*x)/(sqrt(b)*e + d*sqrt(-a)))/e + log(c*(a + b/x**S(2))**p)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/(x*(d + e*x)), x), x, -S(2)*p*log(-e*x/d)*log(d + e*x)/d + p*log(e*(sqrt(b) - x*sqrt(-a))/(sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/d + p*log(-e*(sqrt(b) + x*sqrt(-a))/(-sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/d - p*polylog(S(2), (a + b/x**S(2))/a)/(S(2)*d) - S(2)*p*polylog(S(2), (d + e*x)/d)/d + p*polylog(S(2), sqrt(-a)*(d + e*x)/(-sqrt(b)*e + d*sqrt(-a)))/d + p*polylog(S(2), sqrt(-a)*(d + e*x)/(sqrt(b)*e + d*sqrt(-a)))/d - log(c*(a + b/x**S(2))**p)*log(-b/(a*x**S(2)))/(S(2)*d) - log(c*(a + b/x**S(2))**p)*log(d + e*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/(x**S(2)*(d + e*x)), x), x, S(2)*sqrt(a)*p*atan(sqrt(a)*x/sqrt(b))/(sqrt(b)*d) + S(2)*p/(d*x) - log(c*(a + b/x**S(2))**p)/(d*x) + S(2)*e*p*log(-e*x/d)*log(d + e*x)/d**S(2) - e*p*log(e*(sqrt(b) - x*sqrt(-a))/(sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/d**S(2) - e*p*log(-e*(sqrt(b) + x*sqrt(-a))/(-sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/d**S(2) + e*p*polylog(S(2), (a + b/x**S(2))/a)/(S(2)*d**S(2)) + S(2)*e*p*polylog(S(2), (d + e*x)/d)/d**S(2) - e*p*polylog(S(2), sqrt(-a)*(d + e*x)/(-sqrt(b)*e + d*sqrt(-a)))/d**S(2) - e*p*polylog(S(2), sqrt(-a)*(d + e*x)/(sqrt(b)*e + d*sqrt(-a)))/d**S(2) + e*log(c*(a + b/x**S(2))**p)*log(-b/(a*x**S(2)))/(S(2)*d**S(2)) + e*log(c*(a + b/x**S(2))**p)*log(d + e*x)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(2))**p)/(x**S(3)*(d + e*x)), x), x, -S(2)*sqrt(a)*e*p*atan(sqrt(a)*x/sqrt(b))/(sqrt(b)*d**S(2)) + p/(S(2)*d*x**S(2)) - S(2)*e*p/(d**S(2)*x) + e*log(c*(a + b/x**S(2))**p)/(d**S(2)*x) - S(2)*e**S(2)*p*log(-e*x/d)*log(d + e*x)/d**S(3) + e**S(2)*p*log(e*(sqrt(b) - x*sqrt(-a))/(sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/d**S(3) + e**S(2)*p*log(-e*(sqrt(b) + x*sqrt(-a))/(-sqrt(b)*e + d*sqrt(-a)))*log(d + e*x)/d**S(3) - e**S(2)*p*polylog(S(2), (a + b/x**S(2))/a)/(S(2)*d**S(3)) - S(2)*e**S(2)*p*polylog(S(2), (d + e*x)/d)/d**S(3) + e**S(2)*p*polylog(S(2), sqrt(-a)*(d + e*x)/(-sqrt(b)*e + d*sqrt(-a)))/d**S(3) + e**S(2)*p*polylog(S(2), sqrt(-a)*(d + e*x)/(sqrt(b)*e + d*sqrt(-a)))/d**S(3) - e**S(2)*log(c*(a + b/x**S(2))**p)*log(-b/(a*x**S(2)))/(S(2)*d**S(3)) - e**S(2)*log(c*(a + b/x**S(2))**p)*log(d + e*x)/d**S(3) - (a/S(2) + b/(S(2)*x**S(2)))*log(c*(a + b/x**S(2))**p)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b/x**S(3))**p)/(d + e*x), x), x, -S(3)*d**S(3)*p*log(-e*x/d)*log(d + e*x)/e**S(4) + d**S(3)*p*log(-e*(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d - b**(S(1)/3)*e))*log(d + e*x)/e**S(4) + d**S(3)*p*log(-e*(a**(S(1)/3)*x + (S(-1))**(S(2)/3)*b**(S(1)/3))/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))*log(d + e*x)/e**S(4) + d**S(3)*p*log((S(-1))**(S(1)/3)*e*((S(-1))**(S(2)/3)*a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))*log(d + e*x)/e**S(4) - S(3)*d**S(3)*p*polylog(S(2), (d + e*x)/d)/e**S(4) + d**S(3)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - b**(S(1)/3)*e))/e**S(4) + d**S(3)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/e**S(4) + d**S(3)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/e**S(4) - d**S(3)*log(c*(a + b/x**S(3))**p)*log(d + e*x)/e**S(4) + d**S(2)*x*log(c*(a + b/x**S(3))**p)/e**S(3) - d*x**S(2)*log(c*(a + b/x**S(3))**p)/(S(2)*e**S(2)) + x**S(3)*log(c*(a + b/x**S(3))**p)/(S(3)*e) + b*p*log(a*x**S(3) + b)/(S(3)*a*e) + b**(S(1)/3)*d**S(2)*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*e**S(3)) - b**(S(1)/3)*d**S(2)*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(2)*a**(S(1)/3)*e**S(3)) - sqrt(S(3))*b**(S(1)/3)*d**S(2)*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(a**(S(1)/3)*e**S(3)) + b**(S(2)/3)*d*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(S(2)*a**(S(2)/3)*e**S(2)) - b**(S(2)/3)*d*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(4)*a**(S(2)/3)*e**S(2)) + sqrt(S(3))*b**(S(2)/3)*d*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(S(2)*a**(S(2)/3)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b/x**S(3))**p)/(d + e*x), x), x, S(3)*d**S(2)*p*log(-e*x/d)*log(d + e*x)/e**S(3) - d**S(2)*p*log(-e*(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d - b**(S(1)/3)*e))*log(d + e*x)/e**S(3) - d**S(2)*p*log(-e*(a**(S(1)/3)*x + (S(-1))**(S(2)/3)*b**(S(1)/3))/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))*log(d + e*x)/e**S(3) - d**S(2)*p*log((S(-1))**(S(1)/3)*e*((S(-1))**(S(2)/3)*a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))*log(d + e*x)/e**S(3) + S(3)*d**S(2)*p*polylog(S(2), (d + e*x)/d)/e**S(3) - d**S(2)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - b**(S(1)/3)*e))/e**S(3) - d**S(2)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/e**S(3) - d**S(2)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/e**S(3) + d**S(2)*log(c*(a + b/x**S(3))**p)*log(d + e*x)/e**S(3) - d*x*log(c*(a + b/x**S(3))**p)/e**S(2) + x**S(2)*log(c*(a + b/x**S(3))**p)/(S(2)*e) - b**(S(1)/3)*d*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*e**S(2)) + b**(S(1)/3)*d*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(2)*a**(S(1)/3)*e**S(2)) + sqrt(S(3))*b**(S(1)/3)*d*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(a**(S(1)/3)*e**S(2)) - b**(S(2)/3)*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(S(2)*a**(S(2)/3)*e) + b**(S(2)/3)*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(4)*a**(S(2)/3)*e) - sqrt(S(3))*b**(S(2)/3)*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(S(2)*a**(S(2)/3)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b/x**S(3))**p)/(d + e*x), x), x, -S(3)*d*p*log(-e*x/d)*log(d + e*x)/e**S(2) + d*p*log(-e*(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d - b**(S(1)/3)*e))*log(d + e*x)/e**S(2) + d*p*log(-e*(a**(S(1)/3)*x + (S(-1))**(S(2)/3)*b**(S(1)/3))/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))*log(d + e*x)/e**S(2) + d*p*log((S(-1))**(S(1)/3)*e*((S(-1))**(S(2)/3)*a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))*log(d + e*x)/e**S(2) - S(3)*d*p*polylog(S(2), (d + e*x)/d)/e**S(2) + d*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - b**(S(1)/3)*e))/e**S(2) + d*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/e**S(2) + d*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/e**S(2) - d*log(c*(a + b/x**S(3))**p)*log(d + e*x)/e**S(2) + x*log(c*(a + b/x**S(3))**p)/e + b**(S(1)/3)*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*e) - b**(S(1)/3)*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(2)*a**(S(1)/3)*e) - sqrt(S(3))*b**(S(1)/3)*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(a**(S(1)/3)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(3))**p)/(d + e*x), x), x, S(3)*p*log(-e*x/d)*log(d + e*x)/e - p*log(-e*(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d - b**(S(1)/3)*e))*log(d + e*x)/e - p*log(-e*(a**(S(1)/3)*x + (S(-1))**(S(2)/3)*b**(S(1)/3))/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))*log(d + e*x)/e - p*log((S(-1))**(S(1)/3)*e*((S(-1))**(S(2)/3)*a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))*log(d + e*x)/e + S(3)*p*polylog(S(2), (d + e*x)/d)/e - p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - b**(S(1)/3)*e))/e - p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/e - p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/e + log(c*(a + b/x**S(3))**p)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(3))**p)/(x*(d + e*x)), x), x, -S(3)*p*log(-e*x/d)*log(d + e*x)/d + p*log(-e*(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d - b**(S(1)/3)*e))*log(d + e*x)/d + p*log(-e*(a**(S(1)/3)*x + (S(-1))**(S(2)/3)*b**(S(1)/3))/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))*log(d + e*x)/d + p*log((S(-1))**(S(1)/3)*e*((S(-1))**(S(2)/3)*a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))*log(d + e*x)/d - p*polylog(S(2), (a + b/x**S(3))/a)/(S(3)*d) - S(3)*p*polylog(S(2), (d + e*x)/d)/d + p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - b**(S(1)/3)*e))/d + p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/d + p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/d - log(c*(a + b/x**S(3))**p)*log(-b/(a*x**S(3)))/(S(3)*d) - log(c*(a + b/x**S(3))**p)*log(d + e*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(3))**p)/(x**S(2)*(d + e*x)), x), x, -a**(S(1)/3)*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(b**(S(1)/3)*d) + a**(S(1)/3)*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(2)*b**(S(1)/3)*d) - sqrt(S(3))*a**(S(1)/3)*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(b**(S(1)/3)*d) + S(3)*p/(d*x) - log(c*(a + b/x**S(3))**p)/(d*x) + S(3)*e*p*log(-e*x/d)*log(d + e*x)/d**S(2) - e*p*log(-e*(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d - b**(S(1)/3)*e))*log(d + e*x)/d**S(2) - e*p*log(-e*(a**(S(1)/3)*x + (S(-1))**(S(2)/3)*b**(S(1)/3))/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))*log(d + e*x)/d**S(2) - e*p*log((S(-1))**(S(1)/3)*e*((S(-1))**(S(2)/3)*a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))*log(d + e*x)/d**S(2) + e*p*polylog(S(2), (a + b/x**S(3))/a)/(S(3)*d**S(2)) + S(3)*e*p*polylog(S(2), (d + e*x)/d)/d**S(2) - e*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - b**(S(1)/3)*e))/d**S(2) - e*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/d**S(2) - e*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/d**S(2) + e*log(c*(a + b/x**S(3))**p)*log(-b/(a*x**S(3)))/(S(3)*d**S(2)) + e*log(c*(a + b/x**S(3))**p)*log(d + e*x)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b/x**S(3))**p)/(x**S(3)*(d + e*x)), x), x, a**(S(2)/3)*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(S(2)*b**(S(2)/3)*d) - a**(S(2)/3)*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(4)*b**(S(2)/3)*d) - sqrt(S(3))*a**(S(2)/3)*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(S(2)*b**(S(2)/3)*d) + a**(S(1)/3)*e*p*log(a**(S(1)/3)*x + b**(S(1)/3))/(b**(S(1)/3)*d**S(2)) - a**(S(1)/3)*e*p*log(a**(S(2)/3)*x**S(2) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3))/(S(2)*b**(S(1)/3)*d**S(2)) + sqrt(S(3))*a**(S(1)/3)*e*p*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*x + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(b**(S(1)/3)*d**S(2)) + S(3)*p/(S(4)*d*x**S(2)) - log(c*(a + b/x**S(3))**p)/(S(2)*d*x**S(2)) - S(3)*e*p/(d**S(2)*x) + e*log(c*(a + b/x**S(3))**p)/(d**S(2)*x) - S(3)*e**S(2)*p*log(-e*x/d)*log(d + e*x)/d**S(3) + e**S(2)*p*log(-e*(a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d - b**(S(1)/3)*e))*log(d + e*x)/d**S(3) + e**S(2)*p*log(-e*(a**(S(1)/3)*x + (S(-1))**(S(2)/3)*b**(S(1)/3))/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))*log(d + e*x)/d**S(3) + e**S(2)*p*log((S(-1))**(S(1)/3)*e*((S(-1))**(S(2)/3)*a**(S(1)/3)*x + b**(S(1)/3))/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))*log(d + e*x)/d**S(3) - e**S(2)*p*polylog(S(2), (a + b/x**S(3))/a)/(S(3)*d**S(3)) - S(3)*e**S(2)*p*polylog(S(2), (d + e*x)/d)/d**S(3) + e**S(2)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - b**(S(1)/3)*e))/d**S(3) + e**S(2)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/d**S(3) + e**S(2)*p*polylog(S(2), a**(S(1)/3)*(d + e*x)/(a**(S(1)/3)*d - (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/d**S(3) - e**S(2)*log(c*(a + b/x**S(3))**p)*log(-b/(a*x**S(3)))/(S(3)*d**S(3)) - e**S(2)*log(c*(a + b/x**S(3))**p)*log(d + e*x)/d**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d + e*x**S(2))/(-x**S(2) + S(1)), x), x, log((-sqrt(e)*x + sqrt(-d))/(-sqrt(e) + sqrt(-d)))*log(-x + S(1))/S(2) - log((sqrt(e)*x + sqrt(-d))/(-sqrt(e) + sqrt(-d)))*log(x + S(1))/S(2) - log((-sqrt(e)*x + sqrt(-d))/(sqrt(e) + sqrt(-d)))*log(x + S(1))/S(2) + log((sqrt(e)*x + sqrt(-d))/(sqrt(e) + sqrt(-d)))*log(-x + S(1))/S(2) + log(d + e*x**S(2))*atanh(x) - polylog(S(2), sqrt(e)*(-x + S(-1))/(-sqrt(e) + sqrt(-d)))/S(2) + polylog(S(2), sqrt(e)*(x + S(-1))/(-sqrt(e) + sqrt(-d)))/S(2) + polylog(S(2), sqrt(e)*(-x + S(1))/(sqrt(e) + sqrt(-d)))/S(2) - polylog(S(2), sqrt(e)*(x + S(1))/(sqrt(e) + sqrt(-d)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d + e*x**S(2))/(a + b*x**S(2)), x), x, I*log(sqrt(b)*(-sqrt(e)*x + sqrt(-d))/(-I*sqrt(a)*sqrt(e) + sqrt(b)*sqrt(-d)))*log(S(1) + I*sqrt(b)*x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)) - I*log(sqrt(b)*(-sqrt(e)*x + sqrt(-d))/(I*sqrt(a)*sqrt(e) + sqrt(b)*sqrt(-d)))*log(S(1) - I*sqrt(b)*x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)) - I*log(sqrt(b)*(sqrt(e)*x + sqrt(-d))/(-I*sqrt(a)*sqrt(e) + sqrt(b)*sqrt(-d)))*log(S(1) - I*sqrt(b)*x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)) + I*log(sqrt(b)*(sqrt(e)*x + sqrt(-d))/(I*sqrt(a)*sqrt(e) + sqrt(b)*sqrt(-d)))*log(S(1) + I*sqrt(b)*x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)) + log(d + e*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)) + I*polylog(S(2), sqrt(e)*(-sqrt(a) - I*sqrt(b)*x)/(-sqrt(a)*sqrt(e) + I*sqrt(b)*sqrt(-d)))/(S(2)*sqrt(a)*sqrt(b)) - I*polylog(S(2), sqrt(e)*(-sqrt(a) + I*sqrt(b)*x)/(-sqrt(a)*sqrt(e) + I*sqrt(b)*sqrt(-d)))/(S(2)*sqrt(a)*sqrt(b)) - I*polylog(S(2), sqrt(e)*(sqrt(a) - I*sqrt(b)*x)/(sqrt(a)*sqrt(e) + I*sqrt(b)*sqrt(-d)))/(S(2)*sqrt(a)*sqrt(b)) + I*polylog(S(2), sqrt(e)*(sqrt(a) + I*sqrt(b)*x)/(sqrt(a)*sqrt(e) + I*sqrt(b)*sqrt(-d)))/(S(2)*sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-x**S(2) + S(1))/(-x**S(2) + S(2)), x), x, sqrt(S(2))*log(-x**S(2) + S(1))*atanh(sqrt(S(2))*x/S(2))/S(2) - sqrt(S(2))*log(-S(2)*sqrt(S(2)) + S(3))*atanh(x)/S(2) + sqrt(S(2))*polylog(S(2), sqrt(S(2))*(-x + S(-1))/(-sqrt(S(2)) + S(2)))/S(4) - sqrt(S(2))*polylog(S(2), sqrt(S(2))*(x + S(-1))/(-sqrt(S(2)) + S(2)))/S(4) + sqrt(S(2))*polylog(S(2), sqrt(S(2))*(-x + S(1))/(sqrt(S(2)) + S(2)))/S(4) - sqrt(S(2))*polylog(S(2), sqrt(S(2))*(x + S(1))/(sqrt(S(2)) + S(2)))/S(4), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(log(-x**S(2) + S(1))/(-x**S(2) + S(2)), x), x, -sqrt(S(2))*log(-x + S(1))*atanh(sqrt(S(2))/S(2))/S(2) + sqrt(S(2))*log(x + S(1))*atanh(sqrt(S(2))/S(2))/S(2) + sqrt(S(2))*log(-x**S(2) + S(1))*atanh(sqrt(S(2))*x/S(2))/S(2) + sqrt(S(2))*polylog(S(2), sqrt(S(2))*(-x + S(-1))/(-sqrt(S(2)) + S(2)))/S(4) - sqrt(S(2))*polylog(S(2), sqrt(S(2))*(x + S(-1))/(-sqrt(S(2)) + S(2)))/S(4) + sqrt(S(2))*polylog(S(2), sqrt(S(2))*(-x + S(1))/(sqrt(S(2)) + S(2)))/S(4) - sqrt(S(2))*polylog(S(2), sqrt(S(2))*(x + S(1))/(sqrt(S(2)) + S(2)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(2))*log(d + e*x**S(2))/x**S(2), x), x, -a*log(d + e*x**S(2))/x + c*x*log(d + e*x**S(2)) - S(2)*c*x + (S(2)*a*e + S(2)*c*d)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*sqrt(e)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + c*x**S(2))*log(d + e*x**S(2))/x**S(2), x), x, -a*log(d + e*x**S(2))/x + S(2)*a*sqrt(e)*atan(sqrt(e)*x/sqrt(d))/sqrt(d) + S(2)*c*sqrt(d)*atan(sqrt(e)*x/sqrt(d))/sqrt(e) + c*x*log(d + e*x**S(2)) - S(2)*c*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*log(c*(a + b*x**S(2))**n)**S(2), x), x, -S(5)*a**S(3)*n**S(2)*log(a + b*x**S(2))/(S(18)*b**S(3)) + a**S(3)*log(c*(a + b*x**S(2))**n)**S(2)/(S(6)*b**S(3)) + S(11)*a**S(2)*n**S(2)*x**S(2)/(S(18)*b**S(2)) - a**S(2)*n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)/(S(3)*b**S(3)) - S(5)*a*n**S(2)*x**S(4)/(S(36)*b) + a*n*x**S(4)*log(c*(a + b*x**S(2))**n)/(S(6)*b) + n**S(2)*x**S(6)/S(27) - n*x**S(6)*log(c*(a + b*x**S(2))**n)/S(9) + x**S(6)*log(c*(a + b*x**S(2))**n)**S(2)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*x**S(2))**n)**S(2), x), x, -S(3)*a*n**S(2)*x**S(2)/(S(4)*b) + a*n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)/b**S(2) - a*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(2)/(S(2)*b**S(2)) + n**S(2)*x**S(4)/S(8) - n*(a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)/(S(4)*b**S(2)) + (a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)**S(2)/(S(4)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x**S(2))**n)**S(2), x), x, n**S(2)*x**S(2) - n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)/b + (a/S(2) + b*x**S(2)/S(2))*log(c*(a + b*x**S(2))**n)**S(2)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x, x), x, -n**S(2)*polylog(S(3), (a + b*x**S(2))/a) + n*log(c*(a + b*x**S(2))**n)*polylog(S(2), (a + b*x**S(2))/a) + log(c*(a + b*x**S(2))**n)**S(2)*log(-b*x**S(2)/a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x**S(3), x), x, b*n**S(2)*polylog(S(2), (a + b*x**S(2))/a)/a + b*n*log(c*(a + b*x**S(2))**n)*log(-b*x**S(2)/a)/a - (a/S(2) + b*x**S(2)/S(2))*log(c*(a + b*x**S(2))**n)**S(2)/(a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x**S(5), x), x, -log(c*(a + b*x**S(2))**n)**S(2)/(S(4)*x**S(4)) - b*n*log(c*(a + b*x**S(2))**n)/(S(2)*a*x**S(2)) + b**S(2)*n**S(2)*log(x)/a**S(2) - b**S(2)*n**S(2)*log(a + b*x**S(2))/(S(2)*a**S(2)) - b**S(2)*n**S(2)*polylog(S(2), (a + b*x**S(2))/a)/(S(2)*a**S(2)) - b**S(2)*n*log(c*(a + b*x**S(2))**n)*log(-b*x**S(2)/a)/(S(2)*a**S(2)) + b**S(2)*log(c*(a + b*x**S(2))**n)**S(2)/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x**S(7), x), x, -log(c*(a + b*x**S(2))**n)**S(2)/(S(6)*x**S(6)) - b*n*log(c*(a + b*x**S(2))**n)/(S(6)*a*x**S(4)) - b**S(2)*n**S(2)/(S(6)*a**S(2)*x**S(2)) + b**S(2)*n*log(c*(a + b*x**S(2))**n)/(S(3)*a**S(2)*x**S(2)) - b**S(3)*n**S(2)*log(x)/a**S(3) + b**S(3)*n**S(2)*log(a + b*x**S(2))/(S(2)*a**S(3)) + b**S(3)*n**S(2)*polylog(S(2), (a + b*x**S(2))/a)/(S(3)*a**S(3)) + b**S(3)*n*log(c*(a + b*x**S(2))**n)*log(-b*x**S(2)/a)/(S(3)*a**S(3)) - b**S(3)*log(c*(a + b*x**S(2))**n)**S(2)/(S(6)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(c*(a + b*x**S(2))**n)**S(2), x), x, S(8)*a**(S(5)/2)*n**S(2)*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/(S(5)*b**(S(5)/2)) + S(4)*I*a**(S(5)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))**S(2)/(S(5)*b**(S(5)/2)) - S(184)*a**(S(5)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))/(S(75)*b**(S(5)/2)) + S(4)*I*a**(S(5)/2)*n**S(2)*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/(S(5)*b**(S(5)/2)) + S(4)*a**(S(5)/2)*n*log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/(S(5)*b**(S(5)/2)) + S(184)*a**S(2)*n**S(2)*x/(S(75)*b**S(2)) - S(4)*a**S(2)*n*x*log(c*(a + b*x**S(2))**n)/(S(5)*b**S(2)) - S(64)*a*n**S(2)*x**S(3)/(S(225)*b) + S(4)*a*n*x**S(3)*log(c*(a + b*x**S(2))**n)/(S(15)*b) + S(8)*n**S(2)*x**S(5)/S(125) - S(4)*n*x**S(5)*log(c*(a + b*x**S(2))**n)/S(25) + x**S(5)*log(c*(a + b*x**S(2))**n)**S(2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(c*(a + b*x**S(2))**n)**S(2), x), x, -S(8)*a**(S(3)/2)*n**S(2)*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/(S(3)*b**(S(3)/2)) - S(4)*I*a**(S(3)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))**S(2)/(S(3)*b**(S(3)/2)) + S(32)*a**(S(3)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))/(S(9)*b**(S(3)/2)) - S(4)*I*a**(S(3)/2)*n**S(2)*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/(S(3)*b**(S(3)/2)) - S(4)*a**(S(3)/2)*n*log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/(S(3)*b**(S(3)/2)) - S(32)*a*n**S(2)*x/(S(9)*b) + S(4)*a*n*x*log(c*(a + b*x**S(2))**n)/(S(3)*b) + S(8)*n**S(2)*x**S(3)/S(27) - S(4)*n*x**S(3)*log(c*(a + b*x**S(2))**n)/S(9) + x**S(3)*log(c*(a + b*x**S(2))**n)**S(2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2), x), x, S(8)*sqrt(a)*n**S(2)*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/sqrt(b) + S(4)*I*sqrt(a)*n**S(2)*atan(sqrt(b)*x/sqrt(a))**S(2)/sqrt(b) - S(8)*sqrt(a)*n**S(2)*atan(sqrt(b)*x/sqrt(a))/sqrt(b) + S(4)*I*sqrt(a)*n**S(2)*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/sqrt(b) + S(4)*sqrt(a)*n*log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/sqrt(b) + S(8)*n**S(2)*x - S(4)*n*x*log(c*(a + b*x**S(2))**n) + x*log(c*(a + b*x**S(2))**n)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x**S(2), x), x, -log(c*(a + b*x**S(2))**n)**S(2)/x + S(8)*sqrt(b)*n**S(2)*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/sqrt(a) + S(4)*I*sqrt(b)*n**S(2)*atan(sqrt(b)*x/sqrt(a))**S(2)/sqrt(a) + S(4)*I*sqrt(b)*n**S(2)*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/sqrt(a) + S(4)*sqrt(b)*n*log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x**S(4), x), x, -log(c*(a + b*x**S(2))**n)**S(2)/(S(3)*x**S(3)) - S(4)*b*n*log(c*(a + b*x**S(2))**n)/(S(3)*a*x) - S(8)*b**(S(3)/2)*n**S(2)*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/(S(3)*a**(S(3)/2)) - S(4)*I*b**(S(3)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))**S(2)/(S(3)*a**(S(3)/2)) + S(8)*b**(S(3)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))/(S(3)*a**(S(3)/2)) - S(4)*I*b**(S(3)/2)*n**S(2)*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/(S(3)*a**(S(3)/2)) - S(4)*b**(S(3)/2)*n*log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/(S(3)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x**S(6), x), x, -log(c*(a + b*x**S(2))**n)**S(2)/(S(5)*x**S(5)) - S(4)*b*n*log(c*(a + b*x**S(2))**n)/(S(15)*a*x**S(3)) - S(8)*b**S(2)*n**S(2)/(S(15)*a**S(2)*x) + S(4)*b**S(2)*n*log(c*(a + b*x**S(2))**n)/(S(5)*a**S(2)*x) + S(8)*b**(S(5)/2)*n**S(2)*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/(S(5)*a**(S(5)/2)) + S(4)*I*b**(S(5)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))**S(2)/(S(5)*a**(S(5)/2)) - S(32)*b**(S(5)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))/(S(15)*a**(S(5)/2)) + S(4)*I*b**(S(5)/2)*n**S(2)*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/(S(5)*a**(S(5)/2)) + S(4)*b**(S(5)/2)*n*log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/(S(5)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(2)/x**S(8), x), x, -log(c*(a + b*x**S(2))**n)**S(2)/(S(7)*x**S(7)) - S(4)*b*n*log(c*(a + b*x**S(2))**n)/(S(35)*a*x**S(5)) - S(8)*b**S(2)*n**S(2)/(S(105)*a**S(2)*x**S(3)) + S(4)*b**S(2)*n*log(c*(a + b*x**S(2))**n)/(S(21)*a**S(2)*x**S(3)) + S(64)*b**S(3)*n**S(2)/(S(105)*a**S(3)*x) - S(4)*b**S(3)*n*log(c*(a + b*x**S(2))**n)/(S(7)*a**S(3)*x) - S(8)*b**(S(7)/2)*n**S(2)*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/(S(7)*a**(S(7)/2)) - S(4)*I*b**(S(7)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))**S(2)/(S(7)*a**(S(7)/2)) + S(184)*b**(S(7)/2)*n**S(2)*atan(sqrt(b)*x/sqrt(a))/(S(105)*a**(S(7)/2)) - S(4)*I*b**(S(7)/2)*n**S(2)*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/(S(7)*a**(S(7)/2)) - S(4)*b**(S(7)/2)*n*log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/(S(7)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*log(c*(a + b*x**S(2))**n)**S(3), x), x, -S(9)*a**S(2)*n**S(3)*x**S(2)/(S(4)*b**S(2)) + S(3)*a**S(2)*n**S(2)*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)/b**S(3) - S(3)*a**S(2)*n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(2)/(S(2)*b**S(3)) + a**S(2)*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(3)/(S(2)*b**S(3)) + S(3)*a*n**S(3)*x**S(4)/(S(8)*b) - S(3)*a*n**S(2)*(a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)/(S(4)*b**S(3)) + S(3)*a*n*(a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)**S(2)/(S(4)*b**S(3)) - a*(a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)**S(3)/(S(2)*b**S(3)) - n**S(3)*(a + b*x**S(2))**S(3)/(S(27)*b**S(3)) + n**S(2)*(a + b*x**S(2))**S(3)*log(c*(a + b*x**S(2))**n)/(S(9)*b**S(3)) - n*(a + b*x**S(2))**S(3)*log(c*(a + b*x**S(2))**n)**S(2)/(S(6)*b**S(3)) + (a + b*x**S(2))**S(3)*log(c*(a + b*x**S(2))**n)**S(3)/(S(6)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(c*(a + b*x**S(2))**n)**S(3), x), x, S(21)*a*n**S(3)*x**S(2)/(S(8)*b) - S(3)*a*n**S(2)*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)/b**S(2) + S(3)*a*n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(2)/(S(2)*b**S(2)) - a*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(3)/(S(2)*b**S(2)) - S(3)*n**S(3)*x**S(4)/S(16) + S(3)*n**S(2)*(a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)/(S(8)*b**S(2)) - S(3)*n*(a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)**S(2)/(S(8)*b**S(2)) + (a + b*x**S(2))**S(2)*log(c*(a + b*x**S(2))**n)**S(3)/(S(4)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c*(a + b*x**S(2))**n)**S(3), x), x, -S(3)*n**S(3)*x**S(2) + S(3)*n**S(2)*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)/b - S(3)*n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(2)/(S(2)*b) + (a/S(2) + b*x**S(2)/S(2))*log(c*(a + b*x**S(2))**n)**S(3)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(3)/x, x), x, S(3)*n**S(3)*polylog(S(4), (a + b*x**S(2))/a) - S(3)*n**S(2)*log(c*(a + b*x**S(2))**n)*polylog(S(3), (a + b*x**S(2))/a) + S(3)*n*log(c*(a + b*x**S(2))**n)**S(2)*polylog(S(2), (a + b*x**S(2))/a)/S(2) + log(c*(a + b*x**S(2))**n)**S(3)*log(-b*x**S(2)/a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(3)/x**S(3), x), x, -S(3)*b*n**S(3)*polylog(S(3), (a + b*x**S(2))/a)/a + S(3)*b*n**S(2)*log(c*(a + b*x**S(2))**n)*polylog(S(2), (a + b*x**S(2))/a)/a + S(3)*b*n*log(c*(a + b*x**S(2))**n)**S(2)*log(-b*x**S(2)/a)/(S(2)*a) - (a/S(2) + b*x**S(2)/S(2))*log(c*(a + b*x**S(2))**n)**S(3)/(a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(3)/x**S(5), x), x, -log(c*(a + b*x**S(2))**n)**S(3)/(S(4)*x**S(4)) + S(3)*b**S(2)*n**S(3)*polylog(S(2), (a + b*x**S(2))/a)/(S(2)*a**S(2)) + S(3)*b**S(2)*n**S(3)*polylog(S(3), (a + b*x**S(2))/a)/(S(2)*a**S(2)) + S(3)*b**S(2)*n**S(2)*log(c*(a + b*x**S(2))**n)*log(-b*x**S(2)/a)/(S(2)*a**S(2)) - S(3)*b**S(2)*n**S(2)*log(c*(a + b*x**S(2))**n)*polylog(S(2), (a + b*x**S(2))/a)/(S(2)*a**S(2)) - S(3)*b**S(2)*n*log(c*(a + b*x**S(2))**n)**S(2)*log(-b*x**S(2)/a)/(S(4)*a**S(2)) + b**S(2)*log(c*(a + b*x**S(2))**n)**S(3)/(S(4)*a**S(2)) - S(3)*b*n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(2)/(S(4)*a**S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)**S(3)/x**S(7), x), x, -log(c*(a + b*x**S(2))**n)**S(3)/(S(6)*x**S(6)) - b*n*log(c*(a + b*x**S(2))**n)**S(2)/(S(4)*a*x**S(4)) - b**S(2)*n**S(2)*log(c*(a + b*x**S(2))**n)/(S(2)*a**S(2)*x**S(2)) + b**S(3)*n**S(3)*log(x)/a**S(3) - b**S(3)*n**S(3)*log(a + b*x**S(2))/(S(2)*a**S(3)) - S(3)*b**S(3)*n**S(3)*polylog(S(2), (a + b*x**S(2))/a)/(S(2)*a**S(3)) - b**S(3)*n**S(3)*polylog(S(3), (a + b*x**S(2))/a)/a**S(3) - S(3)*b**S(3)*n**S(2)*log(c*(a + b*x**S(2))**n)*log(-b*x**S(2)/a)/(S(2)*a**S(3)) + b**S(3)*n**S(2)*log(c*(a + b*x**S(2))**n)*polylog(S(2), (a + b*x**S(2))/a)/a**S(3) + b**S(3)*n*log(c*(a + b*x**S(2))**n)**S(2)*log(-b*x**S(2)/a)/(S(2)*a**S(3)) + b**S(3)*n*log(c*(a + b*x**S(2))**n)**S(2)/(S(4)*a**S(3)) - b**S(3)*log(c*(a + b*x**S(2))**n)**S(3)/(S(6)*a**S(3)) + b**S(2)*n*(a + b*x**S(2))*log(c*(a + b*x**S(2))**n)**S(2)/(S(2)*a**S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(c*(a + b*x**S(2))**n), x), x, -a*(c*(a + b*x**S(2))**n)**(-S(1)/n)*(a + b*x**S(2))*Ei(log(c*(a + b*x**S(2))**n)/n)/(S(2)*b**S(2)*n) + (c*(a + b*x**S(2))**n)**(-S(2)/n)*(a + b*x**S(2))**S(2)*Ei(S(2)*log(c*(a + b*x**S(2))**n)/n)/(S(2)*b**S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(c*(a + b*x**S(2))**n), x), x, (c*(a + b*x**S(2))**n)**(-S(1)/n)*(a/S(2) + b*x**S(2)/S(2))*Ei(log(c*(a + b*x**S(2))**n)/n)/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(c*(a + b*x**S(2))**n)), x), x, Integral(S(1)/(x*log(c*(a + b*x)**n)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(c*(a + b*x**S(2))**n)), x), x, Integral(S(1)/(x**S(2)*log(c*(a + b*x)**n)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(c*(a + b*x**S(2))**n)**S(2), x), x, -a*(c*(a + b*x**S(2))**n)**(-S(1)/n)*(a + b*x**S(2))*Ei(log(c*(a + b*x**S(2))**n)/n)/(S(2)*b**S(2)*n**S(2)) - x**S(2)*(a + b*x**S(2))/(S(2)*b*n*log(c*(a + b*x**S(2))**n)) + (c*(a + b*x**S(2))**n)**(-S(2)/n)*(a + b*x**S(2))**S(2)*Ei(S(2)*log(c*(a + b*x**S(2))**n)/n)/(b**S(2)*n**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(c*(a + b*x**S(2))**n)**S(2), x), x, (-a/S(2) - b*x**S(2)/S(2))/(b*n*log(c*(a + b*x**S(2))**n)) + (c*(a + b*x**S(2))**n)**(-S(1)/n)*(a/S(2) + b*x**S(2)/S(2))*Ei(log(c*(a + b*x**S(2))**n)/n)/(b*n**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(c*(a + b*x**S(2))**n)**S(2)), x), x, Integral(S(1)/(x*log(c*(a + b*x)**n)**S(2)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(c*(a + b*x**S(2))**n)**S(2)), x), x, Integral(S(1)/(x**S(2)*log(c*(a + b*x)**n)**S(2)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(c*(a + b*x**S(2))**n)**S(3), x), x, -a*(a + b*x**S(2))/(S(4)*b**S(2)*n**S(2)*log(c*(a + b*x**S(2))**n)) - a*(c*(a + b*x**S(2))**n)**(-S(1)/n)*(a + b*x**S(2))*Ei(log(c*(a + b*x**S(2))**n)/n)/(S(4)*b**S(2)*n**S(3)) - x**S(2)*(a + b*x**S(2))/(S(4)*b*n*log(c*(a + b*x**S(2))**n)**S(2)) - x**S(2)*(a + b*x**S(2))/(S(2)*b*n**S(2)*log(c*(a + b*x**S(2))**n)) + (c*(a + b*x**S(2))**n)**(-S(2)/n)*(a + b*x**S(2))**S(2)*Ei(S(2)*log(c*(a + b*x**S(2))**n)/n)/(b**S(2)*n**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(c*(a + b*x**S(2))**n)**S(3), x), x, (-a/S(4) - b*x**S(2)/S(4))/(b*n*log(c*(a + b*x**S(2))**n)**S(2)) + (-a/S(4) - b*x**S(2)/S(4))/(b*n**S(2)*log(c*(a + b*x**S(2))**n)) + (c*(a + b*x**S(2))**n)**(-S(1)/n)*(a/S(4) + b*x**S(2)/S(4))*Ei(log(c*(a + b*x**S(2))**n)/n)/(b*n**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(c*(a + b*x**S(2))**n)**S(3)), x), x, Integral(S(1)/(x*log(c*(a + b*x)**n)**S(3)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(c*(a + b*x**S(2))**n)**S(3)), x), x, Integral(S(1)/(x**S(2)*log(c*(a + b*x)**n)**S(3)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(c*(a + b*x**S(2))), x), x, Integral(x**m/log(c*(a + b*x**S(2))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(c*(a + b*x**S(2))), x), x, -a*li(a*c + b*c*x**S(2))/(S(2)*b**S(2)*c) + Ei(S(2)*log(a*c + b*c*x**S(2)))/(S(2)*b**S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(c*(a + b*x**S(2))), x), x, Integral(x**S(2)/log(c*(a + b*x**S(2))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(c*(a + b*x**S(2))), x), x, li(c*(a + b*x**S(2)))/(S(2)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/log(c*(a + b*x**S(2))), x), x, Integral(S(1)/log(c*(a + b*x**S(2))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(c*(a + b*x**S(2)))), x), x, Integral(S(1)/(x*log(a*c + b*c*x)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(c*(a + b*x**S(2)))), x), x, Integral(S(1)/(x**S(2)*log(c*(a + b*x**S(2)))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(c*(a + b*x**S(2)))), x), x, Integral(S(1)/(x**S(2)*log(a*c + b*c*x)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(c*(a + b*x**S(2)))**S(2), x), x, Integral(x**m/log(c*(a + b*x**S(2)))**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(c*(a + b*x**S(2)))**S(2), x), x, -a*li(a*c + b*c*x**S(2))/(S(2)*b**S(2)*c) - x**S(2)*(a + b*x**S(2))/(S(2)*b*log(a*c + b*c*x**S(2))) + Ei(S(2)*log(a*c + b*c*x**S(2)))/(b**S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(c*(a + b*x**S(2)))**S(2), x), x, Integral(x**S(2)/log(c*(a + b*x**S(2)))**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(c*(a + b*x**S(2)))**S(2), x), x, (-a/S(2) - b*x**S(2)/S(2))/(b*log(c*(a + b*x**S(2)))) + li(c*(a + b*x**S(2)))/(S(2)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2)))**(S(-2)), x), x, Integral(log(c*(a + b*x**S(2)))**(S(-2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(c*(a + b*x**S(2)))**S(2)), x), x, Integral(S(1)/(x*log(a*c + b*c*x)**S(2)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(c*(a + b*x**S(2)))**S(2)), x), x, Integral(S(1)/(x**S(2)*log(c*(a + b*x**S(2)))**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(c*(a + b*x**S(2)))**S(2)), x), x, Integral(S(1)/(x**S(2)*log(a*c + b*c*x)**S(2)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/log(c*(a + b*x**S(2)))**S(3), x), x, Integral(x**m/log(c*(a + b*x**S(2)))**S(3), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/log(c*(a + b*x**S(2)))**S(3), x), x, -a*(a + b*x**S(2))/(S(4)*b**S(2)*log(a*c + b*c*x**S(2))) - a*li(a*c + b*c*x**S(2))/(S(4)*b**S(2)*c) - x**S(2)*(a + b*x**S(2))/(S(2)*b*log(a*c + b*c*x**S(2))) - x**S(2)*(a + b*x**S(2))/(S(4)*b*log(a*c + b*c*x**S(2))**S(2)) + Ei(S(2)*log(a*c + b*c*x**S(2)))/(b**S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/log(c*(a + b*x**S(2)))**S(3), x), x, Integral(x**S(2)/log(c*(a + b*x**S(2)))**S(3), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/log(c*(a + b*x**S(2)))**S(3), x), x, (-a/S(4) - b*x**S(2)/S(4))/(b*log(c*(a + b*x**S(2)))) + (-a/S(4) - b*x**S(2)/S(4))/(b*log(c*(a + b*x**S(2)))**S(2)) + li(c*(a + b*x**S(2)))/(S(4)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2)))**(S(-3)), x), x, Integral(log(c*(a + b*x**S(2)))**(S(-3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(c*(a + b*x**S(2)))**S(3)), x), x, Integral(S(1)/(x*log(a*c + b*c*x)**S(3)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*log(c*(a + b*x**S(2)))**S(3)), x), x, Integral(S(1)/(x**S(2)*log(c*(a + b*x**S(2)))**S(3)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*log(c*(a + b*x**S(2)))**S(3)), x), x, Integral(S(1)/(x**S(2)*log(a*c + b*c*x)**S(3)), (x, x**S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(b*x**m + S(1))/x, x), x, -polylog(S(2), -b*x**m)/m, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(b*x**m + S(2))/x, x), x, log(S(2))*log(x) - polylog(S(2), -b*x**m/S(2))/m, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(2)*b*x**m + S(6))/x, x), x, log(S(6))*log(x) - polylog(S(2), -b*x**m/S(3))/m, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**m))/x, x), x, log(c*(a + b*x**m))*log(-b*x**m/a)/m + polylog(S(2), (a + b*x**m)/a)/m, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**m)**n)/x, x), x, n*polylog(S(2), (a + b*x**m)/a)/m + log(c*(a + b*x**m)**n)*log(-b*x**m/a)/m, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**m)**n)**S(2)/x, x), x, -S(2)*n**S(2)*polylog(S(3), (a + b*x**m)/a)/m + S(2)*n*log(c*(a + b*x**m)**n)*polylog(S(2), (a + b*x**m)/a)/m + log(c*(a + b*x**m)**n)**S(2)*log(-b*x**m/a)/m, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**m)**n)**S(3)/x, x), x, S(6)*n**S(3)*polylog(S(4), (a + b*x**m)/a)/m - S(6)*n**S(2)*log(c*(a + b*x**m)**n)*polylog(S(3), (a + b*x**m)/a)/m + S(3)*n*log(c*(a + b*x**m)**n)**S(2)*polylog(S(2), (a + b*x**m)/a)/m + log(c*(a + b*x**m)**n)**S(3)*log(-b*x**m/a)/m, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(d*(b*x + c*x**S(2))**n), x), x, n*x**(m + S(1))*hyper((S(1), m + S(1)), (m + S(2),), -c*x/b)/(m + S(1))**S(2) - S(2)*n*x**(m + S(1))/(m + S(1))**S(2) + x**(m + S(1))*log(d*(b*x + c*x**S(2))**n)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(d*(b*x + c*x**S(2))**n), x), x, b**S(5)*n*log(b + c*x)/(S(5)*c**S(5)) - b**S(4)*n*x/(S(5)*c**S(4)) + b**S(3)*n*x**S(2)/(S(10)*c**S(3)) - b**S(2)*n*x**S(3)/(S(15)*c**S(2)) + b*n*x**S(4)/(S(20)*c) - S(2)*n*x**S(5)/S(25) + x**S(5)*log(d*(b*x + c*x**S(2))**n)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(d*(b*x + c*x**S(2))**n), x), x, -b**S(4)*n*log(b + c*x)/(S(4)*c**S(4)) + b**S(3)*n*x/(S(4)*c**S(3)) - b**S(2)*n*x**S(2)/(S(8)*c**S(2)) + b*n*x**S(3)/(S(12)*c) - n*x**S(4)/S(8) + x**S(4)*log(d*(b*x + c*x**S(2))**n)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(d*(b*x + c*x**S(2))**n), x), x, b**S(3)*n*log(b + c*x)/(S(3)*c**S(3)) - b**S(2)*n*x/(S(3)*c**S(2)) + b*n*x**S(2)/(S(6)*c) - S(2)*n*x**S(3)/S(9) + x**S(3)*log(d*(b*x + c*x**S(2))**n)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(d*(b*x + c*x**S(2))**n), x), x, -b**S(2)*n*log(b + c*x)/(S(2)*c**S(2)) + b*n*x/(S(2)*c) - n*x**S(2)/S(2) + x**S(2)*log(d*(b*x + c*x**S(2))**n)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(b*x + c*x**S(2))**n), x), x, b*n*log(b + c*x)/c - S(2)*n*x + x*log(d*(b*x + c*x**S(2))**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(b*x + c*x**S(2))**n)/x, x), x, -n*log(x)**S(2)/S(2) - n*log(x)*log((b + c*x)/b) - n*polylog(S(2), -c*x/b) + log(x)*log(d*(b*x + c*x**S(2))**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(b*x + c*x**S(2))**n)/x**S(2), x), x, -n/x - log(d*(b*x + c*x**S(2))**n)/x + c*n*log(x)/b - c*n*log(b + c*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(b*x + c*x**S(2))**n)/x**S(3), x), x, -n/(S(4)*x**S(2)) - log(d*(b*x + c*x**S(2))**n)/(S(2)*x**S(2)) - c*n/(S(2)*b*x) - c**S(2)*n*log(x)/(S(2)*b**S(2)) + c**S(2)*n*log(b + c*x)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(b*x + c*x**S(2))**n)/x**S(4), x), x, -n/(S(9)*x**S(3)) - log(d*(b*x + c*x**S(2))**n)/(S(3)*x**S(3)) - c*n/(S(6)*b*x**S(2)) + c**S(2)*n/(S(3)*b**S(2)*x) + c**S(3)*n*log(x)/(S(3)*b**S(3)) - c**S(3)*n*log(b + c*x)/(S(3)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(b*x + c*x**S(2))**n)/x**S(5), x), x, -n/(S(16)*x**S(4)) - log(d*(b*x + c*x**S(2))**n)/(S(4)*x**S(4)) - c*n/(S(12)*b*x**S(3)) + c**S(2)*n/(S(8)*b**S(2)*x**S(2)) - c**S(3)*n/(S(4)*b**S(3)*x) - c**S(4)*n*log(x)/(S(4)*b**S(4)) + c**S(4)*n*log(b + c*x)/(S(4)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(d*(a + b*x + c*x**S(2))**n), x), x, -S(2)*c*n*x**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2))))/((b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(m + S(2))) - S(2)*c*n*x**(m + S(2))*hyper((S(1), m + S(2)), (m + S(3),), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2))))/((b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(m + S(2))) + x**(m + S(1))*log(d*(a + b*x + c*x**S(2))**n)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*log(d*(a + b*x + c*x**S(2))**n), x), x, b*n*x**S(4)/(S(20)*c) + b*n*x**S(2)*(-S(3)*a*c + b**S(2))/(S(10)*c**S(3)) + b*n*(S(5)*a**S(2)*c**S(2) - S(5)*a*b**S(2)*c + b**S(4))*log(a + b*x + c*x**S(2))/(S(10)*c**S(5)) - S(2)*n*x**S(5)/S(25) + x**S(5)*log(d*(a + b*x + c*x**S(2))**n)/S(5) - n*x**S(3)*(-S(2)*a*c/S(15) + b**S(2)/S(15))/c**S(2) + n*x*(-S(2)*a**S(2)*c**S(2)/S(5) + S(4)*a*b**S(2)*c/S(5) - b**S(4)/S(5))/c**S(4) + n*sqrt(-S(4)*a*c + b**S(2))*(a**S(2)*c**S(2)/S(5) - S(3)*a*b**S(2)*c/S(5) + b**S(4)/S(5))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(d*(a + b*x + c*x**S(2))**n), x), x, b*n*x**S(3)/(S(12)*c) + b*n*x*(-S(3)*a*c + b**S(2))/(S(4)*c**S(3)) - b*n*sqrt(-S(4)*a*c + b**S(2))*(-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*c**S(4)) - n*x**S(4)/S(8) + x**S(4)*log(d*(a + b*x + c*x**S(2))**n)/S(4) - n*x**S(2)*(-a*c/S(4) + b**S(2)/S(8))/c**S(2) - n*(a**S(2)*c**S(2)/S(4) - a*b**S(2)*c/S(2) + b**S(4)/S(8))*log(a + b*x + c*x**S(2))/c**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(d*(a + b*x + c*x**S(2))**n), x), x, b*n*x**S(2)/(S(6)*c) + b*n*(-S(3)*a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(6)*c**S(3)) - S(2)*n*x**S(3)/S(9) + x**S(3)*log(d*(a + b*x + c*x**S(2))**n)/S(3) + n*x*(S(2)*a*c/S(3) - b**S(2)/S(3))/c**S(2) + n*sqrt(-S(4)*a*c + b**S(2))*(-a*c/S(3) + b**S(2)/S(3))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(d*(a + b*x + c*x**S(2))**n), x), x, b*n*x/(S(2)*c) - b*n*sqrt(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)) - n*x**S(2)/S(2) + x**S(2)*log(d*(a + b*x + c*x**S(2))**n)/S(2) - n*(-a*c/S(2) + b**S(2)/S(4))*log(a + b*x + c*x**S(2))/c**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n), x), x, b*n*log(a + b*x + c*x**S(2))/(S(2)*c) - S(2)*n*x + x*log(d*(a + b*x + c*x**S(2))**n) + n*sqrt(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/x, x), x, -n*log(x)*log((b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(b - sqrt(-S(4)*a*c + b**S(2)))) - n*log(x)*log((b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(b + sqrt(-S(4)*a*c + b**S(2)))) - n*polylog(S(2), -S(2)*c*x/(b - sqrt(-S(4)*a*c + b**S(2)))) - n*polylog(S(2), -S(2)*c*x/(b + sqrt(-S(4)*a*c + b**S(2)))) + log(x)*log(d*(a + b*x + c*x**S(2))**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/x**S(2), x), x, -log(d*(a + b*x + c*x**S(2))**n)/x + b*n*log(x)/a - b*n*log(a + b*x + c*x**S(2))/(S(2)*a) + n*sqrt(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/x**S(3), x), x, -log(d*(a + b*x + c*x**S(2))**n)/(S(2)*x**S(2)) - b*n/(S(2)*a*x) - b*n*sqrt(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)) - n*(-a*c + b**S(2)/S(2))*log(x)/a**S(2) + n*(-a*c/S(2) + b**S(2)/S(4))*log(a + b*x + c*x**S(2))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/x**S(4), x), x, -log(d*(a + b*x + c*x**S(2))**n)/(S(3)*x**S(3)) - b*n/(S(6)*a*x**S(2)) + n*(-S(2)*a*c/S(3) + b**S(2)/S(3))/(a**S(2)*x) + b*n*(-S(3)*a*c + b**S(2))*log(x)/(S(3)*a**S(3)) - b*n*(-S(3)*a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(6)*a**S(3)) + n*sqrt(-S(4)*a*c + b**S(2))*(-a*c/S(3) + b**S(2)/S(3))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/a**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/x**S(5), x), x, -log(d*(a + b*x + c*x**S(2))**n)/(S(4)*x**S(4)) - b*n/(S(12)*a*x**S(3)) + n*(-a*c/S(4) + b**S(2)/S(8))/(a**S(2)*x**S(2)) - b*n*(-S(3)*a*c + b**S(2))/(S(4)*a**S(3)*x) - b*n*sqrt(-S(4)*a*c + b**S(2))*(-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*a**S(4)) + n*(a**S(2)*c**S(2)/S(4) - a*b**S(2)*c/S(2) + b**S(4)/S(8))*log(a + b*x + c*x**S(2))/a**S(4) - n*(a**S(2)*c**S(2)/S(2) - a*b**S(2)*c + b**S(4)/S(4))*log(x)/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**S(2) + x + S(1)), x), x, x*log(x**S(2) + x + S(1)) - S(2)*x + log(x**S(2) + x + S(1))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3)), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d + e*x)**S(4)*log(d*(a + b*x + c*x**S(2))**n), x), x, -S(2)*e**S(4)*n*x**S(5)/S(25) + (d + e*x)**S(5)*log(d*(a + b*x + c*x**S(2))**n)/(S(5)*e) - e**S(3)*n*x**S(4)*(-b*e + S(10)*c*d)/(S(20)*c) - e**S(2)*n*x**S(3)*(b**S(2)*e**S(2) + S(20)*c**S(2)*d**S(2) - c*e*(S(2)*a*e + S(5)*b*d))/(S(15)*c**S(2)) - e*n*x**S(2)*(-b**S(3)*e**S(3) + b*c*e**S(2)*(S(3)*a*e + S(5)*b*d) + S(20)*c**S(3)*d**S(3) - S(10)*c**S(2)*d*e*(a*e + b*d))/(S(10)*c**S(3)) + n*x*(-b**S(4)*e**S(4)/S(5) + b**S(2)*c*e**S(3)*(S(4)*a*e + S(5)*b*d)/S(5) - S(2)*c**S(4)*d**S(4) + S(2)*c**S(3)*d**S(2)*e*(S(2)*a*e + b*d) - c**S(2)*e**S(2)*(S(2)*a**S(2)*e**S(2) + S(15)*a*b*d*e + S(10)*b**S(2)*d**S(2))/S(5))/c**S(4) + n*sqrt(-S(4)*a*c + b**S(2))*(b**S(4)*e**S(4)/S(5) - b**S(2)*c*e**S(3)*(S(3)*a*e + S(5)*b*d)/S(5) + c**S(4)*d**S(4) - S(2)*c**S(3)*d**S(2)*e*(a*e + b*d) + c**S(2)*e**S(2)*(a**S(2)*e**S(2) + S(10)*a*b*d*e + S(10)*b**S(2)*d**S(2))/S(5))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c**S(5) - n*(-b*e/S(10) + c*d/S(5))*(b**S(4)*e**S(4) - b**S(2)*c*e**S(3)*(S(5)*a*e + S(3)*b*d) + c**S(4)*d**S(4) - S(2)*c**S(3)*d**S(2)*e*(S(5)*a*e + b*d) + c**S(2)*e**S(2)*(S(5)*a**S(2)*e**S(2) + S(10)*a*b*d*e + S(4)*b**S(2)*d**S(2)))*log(a + b*x + c*x**S(2))/(c**S(5)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)*log(d*(a + b*x + c*x**S(2))**n), x), x, -e**S(3)*n*x**S(4)/S(8) + (d + e*x)**S(4)*log(d*(a + b*x + c*x**S(2))**n)/(S(4)*e) - e**S(2)*n*x**S(3)*(-b*e + S(8)*c*d)/(S(12)*c) - e*n*x**S(2)*(b**S(2)*e**S(2) + S(12)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + S(2)*b*d))/(S(8)*c**S(2)) + n*x*(b**S(3)*e**S(3)/S(4) - b*c*e**S(2)*(S(3)*a*e + S(4)*b*d)/S(4) - S(2)*c**S(3)*d**S(3) + c**S(2)*d*e*(S(4)*a*e + S(3)*b*d)/S(2))/c**S(3) + n*sqrt(-S(4)*a*c + b**S(2))*(-b*e/S(4) + c*d/S(2))*(b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c**S(4) - n*(b**S(4)*e**S(4)/S(8) - b**S(2)*c*e**S(3)*(a*e + b*d)/S(2) + c**S(4)*d**S(4)/S(4) - c**S(3)*d**S(2)*e*(S(3)*a*e + b*d)/S(2) + c**S(2)*e**S(2)*(a**S(2)*e**S(2) + S(6)*a*b*d*e + S(3)*b**S(2)*d**S(2))/S(4))*log(a + b*x + c*x**S(2))/(c**S(4)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)*log(d*(a + b*x + c*x**S(2))**n), x), x, -S(2)*e**S(2)*n*x**S(3)/S(9) + (d + e*x)**S(3)*log(d*(a + b*x + c*x**S(2))**n)/(S(3)*e) - e*n*x**S(2)*(-b*e + S(6)*c*d)/(S(6)*c) + n*x*(-b**S(2)*e**S(2)/S(3) - S(2)*c**S(2)*d**S(2) + c*e*(S(2)*a*e + S(3)*b*d)/S(3))/c**S(2) + n*sqrt(-S(4)*a*c + b**S(2))*(b**S(2)*e**S(2)/S(3) + c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d)/S(3))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c**S(3) - n*(-b*e/S(6) + c*d/S(3))*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))*log(a + b*x + c*x**S(2))/(c**S(3)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*log(d*(a + b*x + c*x**S(2))**n), x), x, -e*n*x**S(2)/S(2) + n*x*(b*e/(S(2)*c) - S(2)*d) + (d + e*x)**S(2)*log(d*(a + b*x + c*x**S(2))**n)/(S(2)*e) + n*sqrt(-S(4)*a*c + b**S(2))*(-b*e/S(2) + c*d)*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c**S(2) - n*(b**S(2)*e**S(2)/S(4) + c**S(2)*d**S(2)/S(2) - c*e*(a*e + b*d)/S(2))*log(a + b*x + c*x**S(2))/(c**S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n), x), x, b*n*log(a + b*x + c*x**S(2))/(S(2)*c) - S(2)*n*x + x*log(d*(a + b*x + c*x**S(2))**n) + n*sqrt(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/(d + e*x), x), x, -n*log(-e*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))*log(d + e*x)/e - n*log(-e*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))*log(d + e*x)/e - n*polylog(S(2), S(2)*c*(d + e*x)/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/e - n*polylog(S(2), S(2)*c*(d + e*x)/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/e + log(d*(a + b*x + c*x**S(2))**n)*log(d + e*x)/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/(d + e*x)**S(2), x), x, n*sqrt(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a*e**S(2) - b*d*e + c*d**S(2)) + n*(-b*e/S(2) + c*d)*log(a + b*x + c*x**S(2))/(e*(a*e**S(2) - b*d*e + c*d**S(2))) + n*(b*e - S(2)*c*d)*log(d + e*x)/(e*(a*e**S(2) - b*d*e + c*d**S(2))) - log(d*(a + b*x + c*x**S(2))**n)/(e*(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/(d + e*x)**S(3), x), x, n*sqrt(-S(4)*a*c + b**S(2))*(-b*e/S(2) + c*d)*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a*e**S(2) - b*d*e + c*d**S(2))**S(2) + n*(b**S(2)*e**S(2)/S(4) + c**S(2)*d**S(2)/S(2) - c*e*(a*e + b*d)/S(2))*log(a + b*x + c*x**S(2))/(e*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - n*(b**S(2)*e**S(2)/S(2) + c**S(2)*d**S(2) - c*e*(a*e + b*d))*log(d + e*x)/(e*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + n*(-b*e/S(2) + c*d)/(e*(d + e*x)*(a*e**S(2) - b*d*e + c*d**S(2))) - log(d*(a + b*x + c*x**S(2))**n)/(S(2)*e*(d + e*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/(d + e*x)**S(4), x), x, n*sqrt(-S(4)*a*c + b**S(2))*(b**S(2)*e**S(2)/S(3) + c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d)/S(3))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a*e**S(2) - b*d*e + c*d**S(2))**S(3) - n*(-b*e/S(3) + S(2)*c*d/S(3))*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))*log(d + e*x)/(e*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + n*(-b*e/S(6) + c*d/S(3))*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))*log(a + b*x + c*x**S(2))/(e*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + n*(b**S(2)*e**S(2)/S(3) + S(2)*c**S(2)*d**S(2)/S(3) - S(2)*c*e*(a*e + b*d)/S(3))/(e*(d + e*x)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + n*(-b*e/S(6) + c*d/S(3))/(e*(d + e*x)**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))) - log(d*(a + b*x + c*x**S(2))**n)/(S(3)*e*(d + e*x)**S(3)), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/(d + e*x)**S(5), x), x, n*sqrt(-S(4)*a*c + b**S(2))*(-b*e/S(4) + c*d/S(2))*(b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a*e**S(2) - b*d*e + c*d**S(2))**S(4) + n*(b**S(4)*e**S(4)/S(8) - b**S(2)*c*e**S(3)*(a*e + b*d)/S(2) + c**S(4)*d**S(4)/S(4) - c**S(3)*d**S(2)*e*(S(3)*a*e + b*d)/S(2) + c**S(2)*e**S(2)*(a**S(2)*e**S(2) + S(6)*a*b*d*e + S(3)*b**S(2)*d**S(2))/S(4))*log(a + b*x + c*x**S(2))/(e*(a*e**S(2) - b*d*e + c*d**S(2))**S(4)) - n*(b**S(4)*e**S(4)/S(4) - b**S(2)*c*e**S(3)*(a*e + b*d) + c**S(4)*d**S(4)/S(2) - c**S(3)*d**S(2)*e*(S(3)*a*e + b*d) + c**S(2)*e**S(2)*(a**S(2)*e**S(2) + S(6)*a*b*d*e + S(3)*b**S(2)*d**S(2))/S(2))*log(d + e*x)/(e*(a*e**S(2) - b*d*e + c*d**S(2))**S(4)) + n*(-b*e/S(4) + c*d/S(2))*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))/(e*(d + e*x)*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + n*(b**S(2)*e**S(2)/S(8) + c**S(2)*d**S(2)/S(4) - c*e*(a*e + b*d)/S(4))/(e*(d + e*x)**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + n*(-b*e/S(12) + c*d/S(6))/(e*(d + e*x)**S(3)*(a*e**S(2) - b*d*e + c*d**S(2))) - log(d*(a + b*x + c*x**S(2))**n)/(S(4)*e*(d + e*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + c*x**S(2))**n)/(a*e + c*e*x**S(2)), x), x, S(2)*n*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(c)*x))*atan(sqrt(c)*x/sqrt(a))/(sqrt(a)*sqrt(c)*e) + I*n*atan(sqrt(c)*x/sqrt(a))**S(2)/(sqrt(a)*sqrt(c)*e) + I*n*polylog(S(2), (-sqrt(a) + I*sqrt(c)*x)/(sqrt(a) + I*sqrt(c)*x))/(sqrt(a)*sqrt(c)*e) + log(d*(a + c*x**S(2))**n)*atan(sqrt(c)*x/sqrt(a))/(sqrt(a)*sqrt(c)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)/(a*e + b*e*x + c*e*x**S(2)), x), x, -S(4)*n*log(S(2)/(-b/sqrt(-S(4)*a*c + b**S(2)) - S(2)*c*x/sqrt(-S(4)*a*c + b**S(2)) + S(1)))*atanh(b/sqrt(-S(4)*a*c + b**S(2)) + S(2)*c*x/sqrt(-S(4)*a*c + b**S(2)))/(e*sqrt(-S(4)*a*c + b**S(2))) + S(2)*n*atanh(b/sqrt(-S(4)*a*c + b**S(2)) + S(2)*c*x/sqrt(-S(4)*a*c + b**S(2)))**S(2)/(e*sqrt(-S(4)*a*c + b**S(2))) - S(2)*n*polylog(S(2), (-b/sqrt(-S(4)*a*c + b**S(2)) - S(2)*c*x/sqrt(-S(4)*a*c + b**S(2)) + S(-1))/(-b/sqrt(-S(4)*a*c + b**S(2)) - S(2)*c*x/sqrt(-S(4)*a*c + b**S(2)) + S(1)))/(e*sqrt(-S(4)*a*c + b**S(2))) - S(2)*log(d*(a + b*x + c*x**S(2))**n)*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(e*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(g*(a + b*x + c*x**S(2))**n)/(d + e*x**S(2)), x), x, n*log(sqrt(e)*(-b - S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-d) - sqrt(e)*(b - sqrt(-S(4)*a*c + b**S(2)))))*log(sqrt(e)*x + sqrt(-d))/(S(2)*sqrt(e)*sqrt(-d)) - n*log(sqrt(e)*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-d) + sqrt(e)*(b - sqrt(-S(4)*a*c + b**S(2)))))*log(-sqrt(e)*x + sqrt(-d))/(S(2)*sqrt(e)*sqrt(-d)) + n*log(sqrt(e)*(-b - S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-d) - sqrt(e)*(b + sqrt(-S(4)*a*c + b**S(2)))))*log(sqrt(e)*x + sqrt(-d))/(S(2)*sqrt(e)*sqrt(-d)) - n*log(sqrt(e)*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-d) + sqrt(e)*(b + sqrt(-S(4)*a*c + b**S(2)))))*log(-sqrt(e)*x + sqrt(-d))/(S(2)*sqrt(e)*sqrt(-d)) + n*polylog(S(2), S(2)*c*(sqrt(e)*x + sqrt(-d))/(S(2)*c*sqrt(-d) - sqrt(e)*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*sqrt(e)*sqrt(-d)) - n*polylog(S(2), S(2)*c*(-sqrt(e)*x + sqrt(-d))/(S(2)*c*sqrt(-d) + sqrt(e)*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*sqrt(e)*sqrt(-d)) + n*polylog(S(2), S(2)*c*(sqrt(e)*x + sqrt(-d))/(S(2)*c*sqrt(-d) - sqrt(e)*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*sqrt(e)*sqrt(-d)) - n*polylog(S(2), S(2)*c*(-sqrt(e)*x + sqrt(-d))/(S(2)*c*sqrt(-d) + sqrt(e)*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*sqrt(e)*sqrt(-d)) + log(g*(a + b*x + c*x**S(2))**n)*log(-sqrt(e)*x + sqrt(-d))/(S(2)*sqrt(e)*sqrt(-d)) - log(g*(a + b*x + c*x**S(2))**n)*log(sqrt(e)*x + sqrt(-d))/(S(2)*sqrt(e)*sqrt(-d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(g*(a + b*x + c*x**S(2))**n)/(d + e*x + f*x**S(2)), x), x, -n*log(f*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(-c*(e - sqrt(-S(4)*d*f + e**S(2))) + f*(b + sqrt(-S(4)*a*c + b**S(2)))))*log(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/sqrt(-S(4)*d*f + e**S(2)) + n*log(f*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(-c*(e + sqrt(-S(4)*d*f + e**S(2))) + f*(b - sqrt(-S(4)*a*c + b**S(2)))))*log(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/sqrt(-S(4)*d*f + e**S(2)) + n*log(f*(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/(-c*(e + sqrt(-S(4)*d*f + e**S(2))) + f*(b + sqrt(-S(4)*a*c + b**S(2)))))*log(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/sqrt(-S(4)*d*f + e**S(2)) - n*log(-f*(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/(-b*f + c*e - c*sqrt(-S(4)*d*f + e**S(2)) + f*sqrt(-S(4)*a*c + b**S(2))))*log(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/sqrt(-S(4)*d*f + e**S(2)) - n*polylog(S(2), -c*(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/(-c*(e - sqrt(-S(4)*d*f + e**S(2))) + f*(b - sqrt(-S(4)*a*c + b**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) - n*polylog(S(2), -c*(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/(-c*(e - sqrt(-S(4)*d*f + e**S(2))) + f*(b + sqrt(-S(4)*a*c + b**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + n*polylog(S(2), -c*(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/(-c*(e + sqrt(-S(4)*d*f + e**S(2))) + f*(b - sqrt(-S(4)*a*c + b**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + n*polylog(S(2), -c*(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/(-c*(e + sqrt(-S(4)*d*f + e**S(2))) + f*(b + sqrt(-S(4)*a*c + b**S(2)))))/sqrt(-S(4)*d*f + e**S(2)) + log(g*(a + b*x + c*x**S(2))**n)*log(e + S(2)*f*x - sqrt(-S(4)*d*f + e**S(2)))/sqrt(-S(4)*d*f + e**S(2)) - log(g*(a + b*x + c*x**S(2))**n)*log(e + S(2)*f*x + sqrt(-S(4)*d*f + e**S(2)))/sqrt(-S(4)*d*f + e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(b*x + c*x**S(2))**n)**S(2), x), x, -S(2)*b*n**S(2)*log(-c*x/b)*log(b + c*x)/c - b*n**S(2)*log(b + c*x)**S(2)/c - S(4)*b*n**S(2)*log(b + c*x)/c - S(2)*b*n**S(2)*polylog(S(2), (b + c*x)/b)/c + S(2)*b*n*log(d*(b*x + c*x**S(2))**n)*log(b + c*x)/c + S(8)*n**S(2)*x - S(4)*n*x*log(d*(b*x + c*x**S(2))**n) + x*log(d*(b*x + c*x**S(2))**n)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x + c*x**S(2))**n)**S(2), x), x, -S(2)*b*n**S(2)*log(a + b*x + c*x**S(2))/c + S(8)*n**S(2)*x - S(4)*n*x*log(d*(a + b*x + c*x**S(2))**n) + x*log(d*(a + b*x + c*x**S(2))**n)**S(2) - n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*log((b/S(2) + c*x + sqrt(-S(4)*a*c + b**S(2))/S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/c - n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*log(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))**S(2)/(S(2)*c) - n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), (-b/S(2) - c*x + sqrt(-S(4)*a*c + b**S(2))/S(2))/sqrt(-S(4)*a*c + b**S(2)))/c - n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*log((-b/S(2) - c*x + sqrt(-S(4)*a*c + b**S(2))/S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/c - n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*log(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))**S(2)/(S(2)*c) - n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*polylog(S(2), (b/S(2) + c*x + sqrt(-S(4)*a*c + b**S(2))/S(2))/sqrt(-S(4)*a*c + b**S(2)))/c - S(4)*n**S(2)*sqrt(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/c + n*(b - sqrt(-S(4)*a*c + b**S(2)))*log(d*(a + b*x + c*x**S(2))**n)*log(b + S(2)*c*x - sqrt(-S(4)*a*c + b**S(2)))/c + n*(b + sqrt(-S(4)*a*c + b**S(2)))*log(d*(a + b*x + c*x**S(2))**n)*log(b + S(2)*c*x + sqrt(-S(4)*a*c + b**S(2)))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(x**S(2) + x + S(1))/(x**S(2) + S(3)*x + S(2)), x), x, x*log(x**S(2) + x + S(1)) - S(2)*x - log((-S(2)*x + S(-1) - sqrt(S(3))*I)/(S(1) - sqrt(S(3))*I))*log(S(2)*x + S(2)) - log((-S(2)*x + S(-1) + sqrt(S(3))*I)/(S(1) + sqrt(S(3))*I))*log(S(2)*x + S(2)) + S(4)*log((-S(2)*x + S(-1) - sqrt(S(3))*I)/(S(3) - sqrt(S(3))*I))*log(S(2)*x + S(4)) + S(4)*log((-S(2)*x + S(-1) + sqrt(S(3))*I)/(S(3) + sqrt(S(3))*I))*log(S(2)*x + S(4)) + log(S(2)*x + S(2))*log(x**S(2) + x + S(1)) - S(4)*log(S(2)*x + S(4))*log(x**S(2) + x + S(1)) + log(x**S(2) + x + S(1))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3)) - polylog(S(2), (S(2)*x + S(2))/(S(1) - sqrt(S(3))*I)) - polylog(S(2), (S(2)*x + S(2))/(S(1) + sqrt(S(3))*I)) + S(4)*polylog(S(2), (S(2)*x + S(4))/(S(3) - sqrt(S(3))*I)) + S(4)*polylog(S(2), (S(2)*x + S(4))/(S(3) + sqrt(S(3))*I)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**S(2) + x + S(1))**S(2), x), x, x*log(x**S(2) + x + S(1))**S(2) - S(4)*x*log(x**S(2) + x + S(1)) + S(8)*x - (S(1) + sqrt(S(3))*I)*log(sqrt(S(3))*I*(S(2)*x + S(1) - sqrt(S(3))*I)/S(6))*log(S(2)*x + S(1) + sqrt(S(3))*I) - (S(1) - sqrt(S(3))*I)*log(-sqrt(S(3))*I*(S(2)*x + S(1) + sqrt(S(3))*I)/S(6))*log(S(2)*x + S(1) - sqrt(S(3))*I) - (S(1) - sqrt(S(3))*I)*log(S(2)*x + S(1) - sqrt(S(3))*I)**S(2)/S(2) + (S(1) - sqrt(S(3))*I)*log(S(2)*x + S(1) - sqrt(S(3))*I)*log(x**S(2) + x + S(1)) - (S(1) + sqrt(S(3))*I)*log(S(2)*x + S(1) + sqrt(S(3))*I)**S(2)/S(2) + (S(1) + sqrt(S(3))*I)*log(S(2)*x + S(1) + sqrt(S(3))*I)*log(x**S(2) + x + S(1)) - S(2)*log(x**S(2) + x + S(1)) - S(4)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3)) - (S(1) - sqrt(S(3))*I)*polylog(S(2), sqrt(S(3))*I*(S(2)*x + S(1) - sqrt(S(3))*I)/S(6)) - (S(1) + sqrt(S(3))*I)*polylog(S(2), -sqrt(S(3))*I*(S(2)*x + S(1) + sqrt(S(3))*I)/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**S(2) + x + S(-1))**S(2)/x**S(3), x), x, S(3)*log(x)*log((S(2)*x + S(1) + sqrt(S(5)))/(S(1) + sqrt(S(5)))) - S(3)*log(x)*log(x**S(2) + x + S(-1)) + log(x) - (sqrt(S(5)) + S(3))*log(sqrt(S(5))*(x + S(1)/2 + sqrt(S(5))/S(2))/S(5))*log(S(2)*x - sqrt(S(5)) + S(1))/S(2) - (-sqrt(S(5)) + S(3))*log(S(2)*x + S(1) + sqrt(S(5)))**S(2)/S(4) + (-sqrt(S(5)) + S(3))*log(S(2)*x + S(1) + sqrt(S(5)))*log(x**S(2) + x + S(-1))/S(2) - (-sqrt(S(5)) + S(1))*log(S(2)*x + S(1) + sqrt(S(5)))/S(2) - (sqrt(S(5)) + S(3))*log(S(2)*x - sqrt(S(5)) + S(1))**S(2)/S(4) + (sqrt(S(5)) + S(3))*log(S(2)*x - sqrt(S(5)) + S(1))*log(x**S(2) + x + S(-1))/S(2) - (S(1) + sqrt(S(5)))*log(S(2)*x - sqrt(S(5)) + S(1))/S(2) + S(3)*log(S(-1)/2 + sqrt(S(5))/S(2))*log(S(2)*x - sqrt(S(5)) + S(1)) - (-sqrt(S(5)) + S(3))*log(S(2)*sqrt(S(5)))*log(S(2)*x - sqrt(S(5)) + S(1))/S(2) - (sqrt(S(5)) + S(3))*polylog(S(2), sqrt(S(5))*(-x + S(-1)/2 + sqrt(S(5))/S(2))/S(5))/S(2) + (-sqrt(S(5)) + S(3))*polylog(S(2), sqrt(S(5))*(-x + S(-1)/2 + sqrt(S(5))/S(2))/S(5))/S(2) + S(3)*polylog(S(2), -S(2)*x/(S(1) + sqrt(S(5)))) - S(3)*polylog(S(2), (S(2)*x - sqrt(S(5)) + S(1))/(-sqrt(S(5)) + S(1))) + log(x**S(2) + x + S(-1))/x - log(x**S(2) + x + S(-1))**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1)), x), x, x**S(4)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/S(4) - x**S(4)/S(32) + x**S(3)/S(192) - x**S(2)/S(1024) - x*(x**S(2) - x)**(S(3)/2)/S(32) + x/S(4096) + (-S(149)*x/S(1024) + S(149)/2048)*sqrt(x**S(2) - x) - (x**S(2) - x)**(S(3)/2)/S(12) - S(683)*sqrt(x**S(2) - x)/S(4096) - log(S(8)*x + S(1))/S(32768) - S(1537)*atanh(x/sqrt(x**S(2) - x))/S(16384) + atanh((-S(5)*x/S(3) + S(1)/6)/sqrt(x**S(2) - x))/S(32768), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1)), x), x, x**S(3)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/S(3) - x**S(3)/S(18) + x**S(2)/S(96) - x/S(384) + (-S(5)*x/S(32) + S(5)/64)*sqrt(x**S(2) - x) - (x**S(2) - x)**(S(3)/2)/S(18) - S(85)*sqrt(x**S(2) - x)/S(384) + log(S(8)*x + S(1))/S(3072) - S(223)*atanh(x/sqrt(x**S(2) - x))/S(1536) - atanh((-S(5)*x/S(3) + S(1)/6)/sqrt(x**S(2) - x))/S(3072), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1)), x), x, x**S(2)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/S(2) - x**S(2)/S(8) + x/S(32) + (-x/S(8) + S(1)/16)*sqrt(x**S(2) - x) - S(11)*sqrt(x**S(2) - x)/S(32) - log(S(8)*x + S(1))/S(256) - S(33)*atanh(x/sqrt(x**S(2) - x))/S(128) + atanh((-S(5)*x/S(3) + S(1)/6)/sqrt(x**S(2) - x))/S(256), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1)), x), x, x*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1)) - x/S(2) - sqrt(x**S(2) - x)/S(2) + log(S(8)*x + S(1))/S(16) - S(7)*atanh(x/sqrt(x**S(2) - x))/S(8) - atanh((-S(5)*x/S(3) + S(1)/6)/sqrt(x**S(2) - x))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1))/x, x), x, Integral(log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1))/x**S(2), x), x, S(4)*log(x) - S(4)*log(S(8)*x + S(1)) + S(4)*atanh((-S(5)*x/S(3) + S(1)/6)/sqrt(x**S(2) - x)) + S(4)*sqrt(x**S(2) - x)/x - log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1))/x**S(3), x), x, -S(16)*log(x) + S(16)*log(S(8)*x + S(1)) - S(16)*atanh((-S(5)*x/S(3) + S(1)/6)/sqrt(x**S(2) - x)) - S(10)*sqrt(x**S(2) - x)/x - S(2)/x - log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/(S(2)*x**S(2)) - S(2)*(x**S(2) - x)**(S(3)/2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1)), x), x, S(2)*x**(S(5)/2)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/S(5) - S(2)*x**(S(5)/2)/S(25) + x**(S(3)/2)/S(60) - sqrt(x)/S(160) + sqrt(S(2))*atan(S(2)*sqrt(S(2))*sqrt(x))/S(640) - S(2)*(x**S(2) - x)**(S(3)/2)/(S(25)*sqrt(x)) - S(127)*sqrt(x**S(2) - x)/(S(480)*sqrt(x)) - sqrt(S(2))*sqrt(x**S(2) - x)*atan(S(2)*sqrt(S(2))*sqrt(x + S(-1))/S(3))/(S(640)*sqrt(x)*sqrt(x + S(-1))) - (-S(2)*x/S(15) + S(2)/15)*sqrt(x**S(2) - x)/(sqrt(x)*(sqrt(x) + S(1))) - (-S(2)*x/S(15) + S(2)/15)*sqrt(x**S(2) - x)/(sqrt(x)*(-sqrt(x) + S(1))) - S(71)*(x**S(2) - x)**(S(3)/2)/(S(300)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) # failing due to apart assert rubi_test(rubi_integrate(sqrt(x)*log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1)), x), x, S(2)*x**(S(3)/2)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/S(3) - S(2)*x**(S(3)/2)/S(9) + sqrt(x)/S(12) - sqrt(S(2))*atan(S(2)*sqrt(S(2))*sqrt(x))/S(48) - S(17)*sqrt(x**S(2) - x)/(S(36)*sqrt(x)) + sqrt(S(2))*sqrt(x**S(2) - x)*atan(S(2)*sqrt(S(2))*sqrt(x + S(-1))/S(3))/(S(48)*sqrt(x)*sqrt(x + S(-1))) - (-S(2)*x/S(9) + S(2)/9)*sqrt(x**S(2) - x)/(sqrt(x)*(sqrt(x) + S(1))) - (-S(2)*x/S(9) + S(2)/9)*sqrt(x**S(2) - x)/(sqrt(x)*(-sqrt(x) + S(1))) - S(2)*(x**S(2) - x)**(S(3)/2)/(S(9)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1))/sqrt(x), x), x, S(2)*sqrt(x)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1)) - S(2)*sqrt(x) + sqrt(S(2))*atan(S(2)*sqrt(S(2))*sqrt(x))/S(2) - S(2)*sqrt(x**S(2) - x)/(S(3)*sqrt(x)) - sqrt(S(2))*sqrt(x**S(2) - x)*atan(S(2)*sqrt(S(2))*sqrt(x + S(-1))/S(3))/(S(2)*sqrt(x)*sqrt(x + S(-1))) - (-S(2)*x/S(3) + S(2)/3)*sqrt(x**S(2) - x)/(sqrt(x)*(sqrt(x) + S(1))) - (-S(2)*x/S(3) + S(2)/3)*sqrt(x**S(2) - x)/(sqrt(x)*(-sqrt(x) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1))/x**(S(3)/2), x), x, S(4)*sqrt(S(2))*atan(S(2)*sqrt(S(2))*sqrt(x)) - S(8)*atan(sqrt(x)/sqrt(x**S(2) - x)) - S(4)*sqrt(x**S(2) - x)/(S(3)*sqrt(x)) - S(2)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/sqrt(x) - S(4)*sqrt(S(2))*sqrt(x**S(2) - x)*atan(S(2)*sqrt(S(2))*sqrt(x + S(-1))/S(3))/(sqrt(x)*sqrt(x + S(-1))) + (-S(2)*x/S(3) + S(2)/3)*sqrt(x**S(2) - x)/(sqrt(x)*(sqrt(x) + S(1))) + (-S(2)*x/S(3) + S(2)/3)*sqrt(x**S(2) - x)/(sqrt(x)*(-sqrt(x) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(4)*x + S(4)*sqrt(x*(x + S(-1))) + S(-1))/x**(S(5)/2), x), x, -S(32)*sqrt(S(2))*atan(S(2)*sqrt(S(2))*sqrt(x))/S(3) + S(44)*atan(sqrt(x)/sqrt(x**S(2) - x))/S(3) - S(4)*sqrt(x**S(2) - x)/(S(9)*sqrt(x)) - S(16)/(S(3)*sqrt(x)) + S(32)*sqrt(S(2))*sqrt(x**S(2) - x)*atan(S(2)*sqrt(S(2))*sqrt(x + S(-1))/S(3))/(S(3)*sqrt(x)*sqrt(x + S(-1))) + (-S(2)*x/S(9) + S(2)/9)*sqrt(x**S(2) - x)/(sqrt(x)*(sqrt(x) + S(1))) + (-S(2)*x/S(9) + S(2)/9)*sqrt(x**S(2) - x)/(sqrt(x)*(-sqrt(x) + S(1))) + S(4)*sqrt(x**S(2) - x)/(S(3)*x**(S(3)/2)) - S(2)*log(S(4)*x + S(4)*sqrt(x**S(2) - x) + S(-1))/(S(3)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a + x)/x)/x, x), x, polylog(S(2), -a/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a + x**S(2))/x**S(2))/x, x), x, polylog(S(2), -a/x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**(-n)*(a + x**n))/x, x), x, polylog(S(2), -a*x**(-n))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a + b*x)/x)/x, x), x, -log(-a/(b*x))*log(a/x + b) - polylog(S(2), (a/x + b)/b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a + b*x**S(2))/x**S(2))/x, x), x, -log(-a/(b*x**S(2)))*log(a/x**S(2) + b)/S(2) - polylog(S(2), (a/x**S(2) + b)/b)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**(-n)*(a + b*x**n))/x, x), x, -log(-a*x**(-n)/b)*log(a*x**(-n) + b)/n - polylog(S(2), (a*x**(-n) + b)/b)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a + b*x)/x)/(c + d*x), x), x, log((a + b*x)/x)*log(c + d*x)/d + log(-d*x/c)*log(c + d*x)/d - log(-d*(a + b*x)/(-a*d + b*c))*log(c + d*x)/d + polylog(S(2), (c + d*x)/c)/d - polylog(S(2), b*(c + d*x)/(-a*d + b*c))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((a + b*x**S(2))/x**S(2))/(c + d*x), x), x, S(2)*log(-d*x/c)*log(c + d*x)/d - log(-d*(sqrt(b)*x + sqrt(-a))/(sqrt(b)*c - d*sqrt(-a)))*log(c + d*x)/d - log(d*(-sqrt(b)*x + sqrt(-a))/(sqrt(b)*c + d*sqrt(-a)))*log(c + d*x)/d + log(c + d*x)*log(a/x**S(2) + b)/d + S(2)*polylog(S(2), (c + d*x)/c)/d - polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c - d*sqrt(-a)))/d - polylog(S(2), sqrt(b)*(c + d*x)/(sqrt(b)*c + d*sqrt(-a)))/d, expand=True, _diff=True, _numerical=True) # recursion sympy and mathematica assert rubi_test(rubi_integrate(log(x**(-n)*(a + b*x**n))/(c + d*x), x), x, a*n*Integral(log(c + d*x)/(x*(a + b*x**n)), x)/d + log(c + d*x)*log(a*x**(-n) + b)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(4), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(4)/b + n**S(4)*(-S(24)*a*d + S(24)*b*c)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/(b*d) - n**S(3)*(-S(24)*a*d + S(24)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n**S(2)*(-S(12)*a*d + S(12)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n*(-S(4)*a*d + S(4)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(3)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(3), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(3)/b - n**S(3)*(-S(6)*a*d + S(6)*b*c)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n**S(2)*(-S(6)*a*d + S(6)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n*(-S(3)*a*d + S(3)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(2)/b + n**S(2)*(-S(2)*a*d + S(2)*b*c)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n*(-S(2)*a*d + S(2)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)/b - n*(-a*d + b*c)*log(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/log(e*((a + b*x)/(c + d*x))**n), x), x, Integral(S(1)/log(e*((a + b*x)/(c + d*x))**n), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**(S(-2)), x), x, Integral(log(e*((a + b*x)/(c + d*x))**n)**(S(-2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(3)/x, x), x, S(6)*n**S(3)*polylog(S(4), c*(a + b*x)/(a*(c + d*x))) - S(6)*n**S(3)*polylog(S(4), d*(a + b*x)/(b*(c + d*x))) - S(6)*n**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), c*(a + b*x)/(a*(c + d*x))) + S(6)*n**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), d*(a + b*x)/(b*(c + d*x))) + S(3)*n*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), c*(a + b*x)/(a*(c + d*x))) - S(3)*n*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x))) - log(e*((a + b*x)/(c + d*x))**n)**S(3)*log((-a*d + b*c)/(b*(c + d*x))) + log(e*((a + b*x)/(c + d*x))**n)**S(3)*log(x*(a*d - b*c)/(a*(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2)/x, x), x, -S(2)*n**S(2)*polylog(S(3), c*(a + b*x)/(a*(c + d*x))) + S(2)*n**S(2)*polylog(S(3), d*(a + b*x)/(b*(c + d*x))) + S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), c*(a + b*x)/(a*(c + d*x))) - S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x))) - log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x))) + log(e*((a + b*x)/(c + d*x))**n)**S(2)*log(x*(a*d - b*c)/(a*(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/x, x), x, -n*log(x)*log((a + b*x)/a) + n*log(x)*log((c + d*x)/c) - n*polylog(S(2), -b*x/a) + n*polylog(S(2), -d*x/c) + log(x)*log(e*((a + b*x)/(c + d*x))**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(e*((a + b*x)/(c + d*x))**n)), x), x, Integral(S(1)/(x*log(e*((a + b*x)/(c + d*x))**n)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(e*((a + b*x)/(c + d*x))**n)**S(2)), x), x, Integral(S(1)/(x*log(e*((a + b*x)/(c + d*x))**n)**S(2)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*log(e*(a + b*x)/(c + d*x)), x), x, -x*(-a*d + b*c)**S(3)/(S(4)*d**S(3)) + (a + b*x)**S(4)*log(e*(a + b*x)/(c + d*x))/(S(4)*b) - (a + b*x)**S(3)*(-a*d/S(12) + b*c/S(12))/(b*d) + (a + b*x)**S(2)*(-a*d + b*c)**S(2)/(S(8)*b*d**S(2)) + (-a*d + b*c)**S(4)*log(c + d*x)/(S(4)*b*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x)), x), x, x*(-a*d + b*c)**S(2)/(S(3)*d**S(2)) + (a + b*x)**S(3)*log(e*(a + b*x)/(c + d*x))/(S(3)*b) - (a + b*x)**S(2)*(-a*d/S(6) + b*c/S(6))/(b*d) - (-a*d + b*c)**S(3)*log(c + d*x)/(S(3)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*log(e*(a + b*x)/(c + d*x)), x), x, x*(a*d/S(2) - b*c/S(2))/d + (a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(2)*b) + (-a*d + b*c)**S(2)*log(c + d*x)/(S(2)*b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x)), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))/b - (-a*d + b*c)*log(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))/(a + b*x), x), x, -log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))/b + polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))/(a + b*x)**S(2), x), x, -(c + d*x)*log(e*(a + b*x)/(c + d*x))/((a + b*x)*(-a*d + b*c)) - S(1)/(b*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))/(a + b*x)**S(3), x), x, d**S(2)*log(a + b*x)/(S(2)*b*(-a*d + b*c)**S(2)) - d**S(2)*log(c + d*x)/(S(2)*b*(-a*d + b*c)**S(2)) + d/(S(2)*b*(a + b*x)*(-a*d + b*c)) - log(e*(a + b*x)/(c + d*x))/(S(2)*b*(a + b*x)**S(2)) - S(1)/(S(4)*b*(a + b*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)*log(e*(a + b*x)/(c + d*x))**S(2), x), x, -S(5)*x*(-a*d + b*c)**S(3)/(S(12)*d**S(3)) + (a + b*x)**S(4)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(4)*b) - (a + b*x)**S(3)*(-a*d/S(6) + b*c/S(6))*log(e*(a + b*x)/(c + d*x))/(b*d) + (a + b*x)**S(2)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(4)*b*d**S(2)) + (a + b*x)**S(2)*(-a*d + b*c)**S(2)/(S(12)*b*d**S(2)) - (a + b*x)*(-a*d + b*c)**S(3)*log(e*(a + b*x)/(c + d*x))/(S(2)*b*d**S(3)) - (-a*d + b*c)**S(4)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(S(2)*b*d**S(4)) + S(11)*(-a*d + b*c)**S(4)*log(c + d*x)/(S(12)*b*d**S(4)) - (-a*d + b*c)**S(4)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(S(2)*b*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2), x), x, x*(-a*d + b*c)**S(2)/(S(3)*d**S(2)) + (a + b*x)**S(3)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(3)*b) - (a + b*x)**S(2)*(-a*d/S(3) + b*c/S(3))*log(e*(a + b*x)/(c + d*x))/(b*d) + S(2)*(a + b*x)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(3)*b*d**S(2)) + S(2)*(-a*d + b*c)**S(3)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(S(3)*b*d**S(3)) - (-a*d + b*c)**S(3)*log(c + d*x)/(b*d**S(3)) + S(2)*(-a*d + b*c)**S(3)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(S(3)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*log(e*(a + b*x)/(c + d*x))**S(2), x), x, (a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(2)*b) + (a + b*x)*(a*d - b*c)*log(e*(a + b*x)/(c + d*x))/(b*d) - (-a*d + b*c)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(b*d**S(2)) + (-a*d + b*c)**S(2)*log(c + d*x)/(b*d**S(2)) - (-a*d + b*c)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(2)/b + (-S(2)*a*d + S(2)*b*c)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(b*d) + (-S(2)*a*d + S(2)*b*c)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2)/(a + b*x), x), x, -log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/b + S(2)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/b + S(2)*polylog(S(3), b*(c + d*x)/(d*(a + b*x)))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2)/(a + b*x)**S(2), x), x, -(c + d*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((a + b*x)*(-a*d + b*c)) - (S(2)*c + S(2)*d*x)*log(e*(a + b*x)/(c + d*x))/((a + b*x)*(-a*d + b*c)) - S(2)/(b*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2)/(a + b*x)**S(3), x), x, -b*(c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(2)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)) - b*(c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(2)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)) - b*(c + d*x)**S(2)/(S(4)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)) + d*(c + d*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((a + b*x)*(-a*d + b*c)**S(2)) + S(2)*d*(c + d*x)*log(e*(a + b*x)/(c + d*x))/((a + b*x)*(-a*d + b*c)**S(2)) + S(2)*d/(b*(a + b*x)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(3), x), x, (a + b*x)**S(3)*log(e*(a + b*x)/(c + d*x))**S(3)/(S(3)*b) - (a + b*x)**S(2)*(-a*d/S(2) + b*c/S(2))*log(e*(a + b*x)/(c + d*x))**S(2)/(b*d) + (a + b*x)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/(b*d**S(2)) + (a + b*x)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))/(b*d**S(2)) + (-a*d + b*c)**S(3)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/(b*d**S(3)) + S(3)*(-a*d + b*c)**S(3)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(b*d**S(3)) + S(2)*(-a*d + b*c)**S(3)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(3)) - (-a*d + b*c)**S(3)*log(c + d*x)/(b*d**S(3)) + S(3)*(-a*d + b*c)**S(3)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(3)) - S(2)*(-a*d + b*c)**S(3)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*log(e*(a + b*x)/(c + d*x))**S(3), x), x, (a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(3)/(S(2)*b) - (a + b*x)*(-S(3)*a*d/S(2) + S(3)*b*c/S(2))*log(e*(a + b*x)/(c + d*x))**S(2)/(b*d) - S(3)*(-a*d + b*c)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/(S(2)*b*d**S(2)) - S(3)*(-a*d + b*c)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(b*d**S(2)) - S(3)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(2)) - S(3)*(-a*d + b*c)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(2)) + S(3)*(-a*d + b*c)**S(2)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(3)/b + (-S(6)*a*d + S(6)*b*c)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) - (-S(6)*a*d + S(6)*b*c)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + (-S(3)*a*d + S(3)*b*c)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3)/(a + b*x), x), x, -log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))**S(3)/b + S(3)*log(e*(a + b*x)/(c + d*x))**S(2)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/b + S(6)*log(e*(a + b*x)/(c + d*x))*polylog(S(3), b*(c + d*x)/(d*(a + b*x)))/b + S(6)*polylog(S(4), b*(c + d*x)/(d*(a + b*x)))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3)/(a + b*x)**S(2), x), x, -(c + d*x)*log(e*(a + b*x)/(c + d*x))**S(3)/((a + b*x)*(-a*d + b*c)) - (S(3)*c + S(3)*d*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((a + b*x)*(-a*d + b*c)) - (S(6)*c + S(6)*d*x)*log(e*(a + b*x)/(c + d*x))/((a + b*x)*(-a*d + b*c)) - S(6)/(b*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3)/(a + b*x)**S(3), x), x, -b*(c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(3)/(S(2)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)) - S(3)*b*(c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(4)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)) - S(3)*b*(c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(4)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)) - S(3)*b*(c + d*x)**S(2)/(S(8)*(a + b*x)**S(2)*(-a*d + b*c)**S(2)) + d*(c + d*x)*log(e*(a + b*x)/(c + d*x))**S(3)/((a + b*x)*(-a*d + b*c)**S(2)) + S(3)*d*(c + d*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((a + b*x)*(-a*d + b*c)**S(2)) + S(6)*d*(c + d*x)*log(e*(a + b*x)/(c + d*x))/((a + b*x)*(-a*d + b*c)**S(2)) + S(6)*d/(b*(a + b*x)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n), x), x, (c + d*x)**S(4)*log(e*((a + b*x)/(c + d*x))**n)/(S(4)*d) - n*(c + d*x)**S(3)*(-a*d/S(12) + b*c/S(12))/(b*d) - n*(c + d*x)**S(2)*(-a*d + b*c)**S(2)/(S(8)*b**S(2)*d) - n*x*(-a*d + b*c)**S(3)/(S(4)*b**S(3)) - n*(-a*d + b*c)**S(4)*log(a + b*x)/(S(4)*b**S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n), x), x, (c + d*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n)/(S(3)*d) - n*(c + d*x)**S(2)*(-a*d/S(6) + b*c/S(6))/(b*d) - n*x*(-a*d + b*c)**S(2)/(S(3)*b**S(2)) - n*(-a*d + b*c)**S(3)*log(a + b*x)/(S(3)*b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*log(e*((a + b*x)/(c + d*x))**n), x), x, (c + d*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)/(S(2)*d) + n*x*(a*d/S(2) - b*c/S(2))/b - n*(-a*d + b*c)**S(2)*log(a + b*x)/(S(2)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)/b - n*(-a*d + b*c)*log(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(c + d*x), x), x, -n*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/d - log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(c + d*x)**S(2), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)/((c + d*x)*(-a*d + b*c)) + n/(d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(c + d*x)**S(3), x), x, b**S(2)*n*log(a + b*x)/(S(2)*d*(-a*d + b*c)**S(2)) - b**S(2)*n*log(c + d*x)/(S(2)*d*(-a*d + b*c)**S(2)) + b*n/(S(2)*d*(c + d*x)*(-a*d + b*c)) + n/(S(4)*d*(c + d*x)**S(2)) - log(e*((a + b*x)/(c + d*x))**n)/(S(2)*d*(c + d*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(c + d*x)**S(4), x), x, b**S(3)*n*log(a + b*x)/(S(3)*d*(-a*d + b*c)**S(3)) - b**S(3)*n*log(c + d*x)/(S(3)*d*(-a*d + b*c)**S(3)) + b**S(2)*n/(S(3)*d*(c + d*x)*(-a*d + b*c)**S(2)) + b*n/(S(6)*d*(c + d*x)**S(2)*(-a*d + b*c)) + n/(S(9)*d*(c + d*x)**S(3)) - log(e*((a + b*x)/(c + d*x))**n)/(S(3)*d*(c + d*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(3)*log(e*(a + b*x)/(c + d*x))**S(2), x), x, (c + d*x)**S(4)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(4)*d) - (c + d*x)**S(3)*(-a*d/S(6) + b*c/S(6))*log(e*(a + b*x)/(c + d*x))/(b*d) - (c + d*x)**S(2)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(4)*b**S(2)*d) + (c + d*x)**S(2)*(-a*d + b*c)**S(2)/(S(12)*b**S(2)*d) + S(5)*x*(-a*d + b*c)**S(3)/(S(12)*b**S(3)) - (a + b*x)*(-a*d + b*c)**S(3)*log(e*(a + b*x)/(c + d*x))/(S(2)*b**S(4)) + (-a*d + b*c)**S(4)*log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))/(S(2)*b**S(4)*d) + S(5)*(-a*d + b*c)**S(4)*log(a + b*x)/(S(12)*b**S(4)*d) + (-a*d + b*c)**S(4)*log(c + d*x)/(S(2)*b**S(4)*d) - (-a*d + b*c)**S(4)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(S(2)*b**S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2), x), x, (c + d*x)**S(3)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(3)*d) - (c + d*x)**S(2)*(-a*d/S(3) + b*c/S(3))*log(e*(a + b*x)/(c + d*x))/(b*d) + x*(-a*d + b*c)**S(2)/(S(3)*b**S(2)) - S(2)*(a + b*x)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(3)*b**S(3)) + S(2)*(-a*d + b*c)**S(3)*log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))/(S(3)*b**S(3)*d) + (-a*d + b*c)**S(3)*log(a + b*x)/(S(3)*b**S(3)*d) + S(2)*(-a*d + b*c)**S(3)*log(c + d*x)/(S(3)*b**S(3)*d) - S(2)*(-a*d + b*c)**S(3)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(S(3)*b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*log(e*(a + b*x)/(c + d*x))**S(2), x), x, (c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(2)*d) + (a + b*x)*(a*d - b*c)*log(e*(a + b*x)/(c + d*x))/b**S(2) + (-a*d + b*c)**S(2)*log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))/(b**S(2)*d) + (-a*d + b*c)**S(2)*log(c + d*x)/(b**S(2)*d) - (-a*d + b*c)**S(2)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(2)/b + (-S(2)*a*d + S(2)*b*c)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(b*d) + (-S(2)*a*d + S(2)*b*c)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2)/(c + d*x), x), x, -log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/d - S(2)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/d + S(2)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2)/(c + d*x)**S(2), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((c + d*x)*(-a*d + b*c)) - (S(2)*a + S(2)*b*x)*log(e*(a + b*x)/(c + d*x))/((c + d*x)*(-a*d + b*c)) - S(2)/(d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(2)/(c + d*x)**S(3), x), x, b*(a + b*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((c + d*x)*(-a*d + b*c)**S(2)) - S(2)*b*(a + b*x)*log(e*(a + b*x)/(c + d*x))/((c + d*x)*(-a*d + b*c)**S(2)) - S(2)*b/(d*(c + d*x)*(-a*d + b*c)) - d*(a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(2)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)) + d*(a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(2)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)) - d*(a + b*x)**S(2)/(S(4)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(3), x), x, (c + d*x)**S(3)*log(e*(a + b*x)/(c + d*x))**S(3)/(S(3)*d) - (c + d*x)**S(2)*(-a*d/S(2) + b*c/S(2))*log(e*(a + b*x)/(c + d*x))**S(2)/(b*d) - (a + b*x)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/b**S(3) + (a + b*x)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))/b**S(3) - S(2)*(-a*d + b*c)**S(3)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(b**S(3)*d) + (-a*d + b*c)**S(3)*log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/(b**S(3)*d) - (-a*d + b*c)**S(3)*log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))/(b**S(3)*d) - S(2)*(-a*d + b*c)**S(3)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(3)*d) - (-a*d + b*c)**S(3)*log(c + d*x)/(b**S(3)*d) - S(2)*(-a*d + b*c)**S(3)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b**S(3)*d) + (-a*d + b*c)**S(3)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(3)*d) - S(2)*(-a*d + b*c)**S(3)*polylog(S(3), b*(c + d*x)/(d*(a + b*x)))/(b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)*log(e*(a + b*x)/(c + d*x))**S(3), x), x, (c + d*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(3)/(S(2)*d) - (a + b*x)*(-S(3)*a*d/S(2) + S(3)*b*c/S(2))*log(e*(a + b*x)/(c + d*x))**S(2)/b**S(2) - S(3)*(-a*d + b*c)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))/(b**S(2)*d) + S(3)*(-a*d + b*c)**S(2)*log((a*d - b*c)/(d*(a + b*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/(S(2)*b**S(2)*d) - S(3)*(-a*d + b*c)**S(2)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(2)*d) - S(3)*(-a*d + b*c)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b**S(2)*d) - S(3)*(-a*d + b*c)**S(2)*polylog(S(3), b*(c + d*x)/(d*(a + b*x)))/(b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(3)/b + (-S(6)*a*d + S(6)*b*c)*log(e*(a + b*x)/(c + d*x))*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) - (-S(6)*a*d + S(6)*b*c)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + (-S(3)*a*d + S(3)*b*c)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3)/(c + d*x), x), x, -log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(3)/d - S(3)*log(e*(a + b*x)/(c + d*x))**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/d + S(6)*log(e*(a + b*x)/(c + d*x))*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/d - S(6)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3)/(c + d*x)**S(2), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(3)/((c + d*x)*(-a*d + b*c)) - (S(3)*a + S(3)*b*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((c + d*x)*(-a*d + b*c)) + (S(6)*a + S(6)*b*x)*log(e*(a + b*x)/(c + d*x))/((c + d*x)*(-a*d + b*c)) + S(6)/(d*(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(3)/(c + d*x)**S(3), x), x, b*(a + b*x)*log(e*(a + b*x)/(c + d*x))**S(3)/((c + d*x)*(-a*d + b*c)**S(2)) - S(3)*b*(a + b*x)*log(e*(a + b*x)/(c + d*x))**S(2)/((c + d*x)*(-a*d + b*c)**S(2)) + S(6)*b*(a + b*x)*log(e*(a + b*x)/(c + d*x))/((c + d*x)*(-a*d + b*c)**S(2)) + S(6)*b/(d*(c + d*x)*(-a*d + b*c)) - d*(a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(3)/(S(2)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)) + S(3)*d*(a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))**S(2)/(S(4)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)) - S(3)*d*(a + b*x)**S(2)*log(e*(a + b*x)/(c + d*x))/(S(4)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)) + S(3)*d*(a + b*x)**S(2)/(S(8)*(c + d*x)**S(2)*(-a*d + b*c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(4), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(4)/b - (-S(24)*a*d + S(24)*b*c)*log(e*(a + b*x)/(c + d*x))*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + (-S(24)*a*d + S(24)*b*c)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/(b*d) + (-S(12)*a*d + S(12)*b*c)*log(e*(a + b*x)/(c + d*x))**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + (-S(4)*a*d + S(4)*b*c)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(3)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(a + b*x)/(c + d*x))**S(5), x), x, (a + b*x)*log(e*(a + b*x)/(c + d*x))**S(5)/b + (-S(120)*a*d + S(120)*b*c)*log(e*(a + b*x)/(c + d*x))*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/(b*d) - (-S(120)*a*d + S(120)*b*c)*polylog(S(5), d*(a + b*x)/(b*(c + d*x)))/(b*d) - (-S(60)*a*d + S(60)*b*c)*log(e*(a + b*x)/(c + d*x))**S(2)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + (-S(20)*a*d + S(20)*b*c)*log(e*(a + b*x)/(c + d*x))**S(3)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + (-S(5)*a*d + S(5)*b*c)*log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(4)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d*(a + b*x)/(b*(c + d*x)))/(c*f + d*f*x), x), x, polylog(S(2), (-a*d + b*c)/(b*(c + d*x)))/(d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(1) + S(1)/(a + b*x))/(a + b*x), x), x, polylog(S(2), -S(1)/(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(1) - S(1)/(a + b*x))/(a + b*x), x), x, polylog(S(2), S(1)/(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n), x), x, (f + g*x)**S(4)*log(e*((a + b*x)/(c + d*x))**n)/(S(4)*g) + n*(-c*g + d*f)**S(4)*log(c + d*x)/(S(4)*d**S(4)*g) - g**S(3)*n*x**S(3)*(-a*d/S(12) + b*c/S(12))/(b*d) - g**S(2)*n*x**S(2)*(-a*d/S(8) + b*c/S(8))*(-a*d*g - b*c*g + S(4)*b*d*f)/(b**S(2)*d**S(2)) + g*n*x*(a*d/S(4) - b*c/S(4))*(a**S(2)*d**S(2)*g**S(2) - a*b*d*g*(-c*g + S(4)*d*f) + b**S(2)*(c**S(2)*g**S(2) - S(4)*c*d*f*g + S(6)*d**S(2)*f**S(2)))/(b**S(3)*d**S(3)) - n*(-a*g + b*f)**S(4)*log(a + b*x)/(S(4)*b**S(4)*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n), x), x, (f + g*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n)/(S(3)*g) + n*(-c*g + d*f)**S(3)*log(c + d*x)/(S(3)*d**S(3)*g) - g**S(2)*n*x**S(2)*(-a*d/S(6) + b*c/S(6))/(b*d) + g*n*x*(a*d/S(3) - b*c/S(3))*(-a*d*g - b*c*g + S(3)*b*d*f)/(b**S(2)*d**S(2)) - n*(-a*g + b*f)**S(3)*log(a + b*x)/(S(3)*b**S(3)*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)*log(e*((a + b*x)/(c + d*x))**n), x), x, (f + g*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)/(S(2)*g) + n*(-c*g + d*f)**S(2)*log(c + d*x)/(S(2)*d**S(2)*g) + g*n*x*(a*d/S(2) - b*c/S(2))/(b*d) - n*(-a*g + b*f)**S(2)*log(a + b*x)/(S(2)*b**S(2)*g), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)/b - n*(-a*d + b*c)*log(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(f + g*x), x), x, -n*log(-g*(a + b*x)/(-a*g + b*f))*log(f + g*x)/g + n*log(-g*(c + d*x)/(-c*g + d*f))*log(f + g*x)/g - n*polylog(S(2), b*(f + g*x)/(-a*g + b*f))/g + n*polylog(S(2), d*(f + g*x)/(-c*g + d*f))/g + log(e*((a + b*x)/(c + d*x))**n)*log(f + g*x)/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(f + g*x)**S(2), x), x, -n*(-a*d + b*c)*log(c + d*x)/((-a*g + b*f)*(-c*g + d*f)) + n*(-a*d + b*c)*log(f + g*x)/((-a*g + b*f)*(-c*g + d*f)) + (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)/((f + g*x)*(-a*g + b*f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(f + g*x)**S(3), x), x, b**S(2)*n*log(a + b*x)/(S(2)*g*(-a*g + b*f)**S(2)) - d**S(2)*n*log(c + d*x)/(S(2)*g*(-c*g + d*f)**S(2)) + n*(-a*d/S(2) + b*c/S(2))*(-a*d*g - b*c*g + S(2)*b*d*f)*log(f + g*x)/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n*(a*d/S(2) - b*c/S(2))/((f + g*x)*(-a*g + b*f)*(-c*g + d*f)) - log(e*((a + b*x)/(c + d*x))**n)/(S(2)*g*(f + g*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(f + g*x)**S(4), x), x, b**S(3)*n*log(a + b*x)/(S(3)*g*(-a*g + b*f)**S(3)) - d**S(3)*n*log(c + d*x)/(S(3)*g*(-c*g + d*f)**S(3)) + n*(-a*d/S(3) + b*c/S(3))*(a**S(2)*d**S(2)*g**S(2) - a*b*d*g*(-c*g + S(3)*d*f) + b**S(2)*(c**S(2)*g**S(2) - S(3)*c*d*f*g + S(3)*d**S(2)*f**S(2)))*log(f + g*x)/((-a*g + b*f)**S(3)*(-c*g + d*f)**S(3)) - n*(-a*d/S(3) + b*c/S(3))*(-a*d*g - b*c*g + S(2)*b*d*f)/((f + g*x)*(-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n*(a*d/S(6) - b*c/S(6))/((f + g*x)**S(2)*(-a*g + b*f)*(-c*g + d*f)) - log(e*((a + b*x)/(c + d*x))**n)/(S(3)*g*(f + g*x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n)**S(2), x), x, -a**S(3)*g**S(3)*n**S(2)*(-a*d + b*c)*log(a + b*x)/(S(6)*b**S(4)*d) + a**S(2)*g**S(2)*n**S(2)*(-a*d + b*c)*(-a*d*g - b*c*g + S(4)*b*d*f)*log(a + b*x)/(S(4)*b**S(4)*d**S(2)) + (f + g*x)**S(4)*log(e*((a + b*x)/(c + d*x))**n)**S(2)/(S(4)*g) - n**S(2)*(-c*g + d*f)**S(4)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(S(2)*d**S(4)*g) - n*(-c*g + d*f)**S(4)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(S(2)*d**S(4)*g) + c**S(3)*g**S(3)*n**S(2)*(-a*d + b*c)*log(c + d*x)/(S(6)*b*d**S(4)) - g**S(3)*n*x**S(3)*(-a*d/S(6) + b*c/S(6))*log(e*((a + b*x)/(c + d*x))**n)/(b*d) - c**S(2)*g**S(2)*n**S(2)*(-a*d + b*c)*(-a*d*g - b*c*g + S(4)*b*d*f)*log(c + d*x)/(S(4)*b**S(2)*d**S(4)) + g**S(3)*n**S(2)*x**S(2)*(-a*d + b*c)**S(2)/(S(12)*b**S(2)*d**S(2)) - g**S(2)*n*x**S(2)*(-a*d/S(4) + b*c/S(4))*(-a*d*g - b*c*g + S(4)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)/(b**S(2)*d**S(2)) - g**S(3)*n**S(2)*x*(-a*d + b*c)**S(2)*(a*d + b*c)/(S(6)*b**S(3)*d**S(3)) + g**S(2)*n**S(2)*x*(-a*d + b*c)**S(2)*(-a*d*g - b*c*g + S(4)*b*d*f)/(S(4)*b**S(3)*d**S(3)) - n**S(2)*(-a*g + b*f)**S(4)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(S(2)*b**S(4)*g) + n*(-a*g + b*f)**S(4)*log(e*((a + b*x)/(c + d*x))**n)*log((a*d - b*c)/(d*(a + b*x)))/(S(2)*b**S(4)*g) - g*n*(a + b*x)*(-a*d/S(2) + b*c/S(2))*(a**S(2)*d**S(2)*g**S(2) - a*b*d*g*(-c*g + S(4)*d*f) + b**S(2)*(c**S(2)*g**S(2) - S(4)*c*d*f*g + S(6)*d**S(2)*f**S(2)))*log(e*((a + b*x)/(c + d*x))**n)/(b**S(4)*d**S(3)) + g*n**S(2)*(-a*d + b*c)**S(2)*(a**S(2)*d**S(2)*g**S(2) - a*b*d*g*(-c*g + S(4)*d*f) + b**S(2)*(c**S(2)*g**S(2) - S(4)*c*d*f*g + S(6)*d**S(2)*f**S(2)))*log(c + d*x)/(S(2)*b**S(4)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)**S(2), x), x, a**S(2)*g**S(2)*n**S(2)*(-a*d + b*c)*log(a + b*x)/(S(3)*b**S(3)*d) + (f + g*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n)**S(2)/(S(3)*g) - S(2)*n**S(2)*(-c*g + d*f)**S(3)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(S(3)*d**S(3)*g) - S(2)*n*(-c*g + d*f)**S(3)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(S(3)*d**S(3)*g) - c**S(2)*g**S(2)*n**S(2)*(-a*d + b*c)*log(c + d*x)/(S(3)*b*d**S(3)) - g**S(2)*n*x**S(2)*(-a*d/S(3) + b*c/S(3))*log(e*((a + b*x)/(c + d*x))**n)/(b*d) + g**S(2)*n**S(2)*x*(-a*d + b*c)**S(2)/(S(3)*b**S(2)*d**S(2)) - S(2)*n**S(2)*(-a*g + b*f)**S(3)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(S(3)*b**S(3)*g) + S(2)*n*(-a*g + b*f)**S(3)*log(e*((a + b*x)/(c + d*x))**n)*log((a*d - b*c)/(d*(a + b*x)))/(S(3)*b**S(3)*g) - g*n*(a + b*x)*(-S(2)*a*d/S(3) + S(2)*b*c/S(3))*(-a*d*g - b*c*g + S(3)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)/(b**S(3)*d**S(2)) + S(2)*g*n**S(2)*(-a*d + b*c)**S(2)*(-a*d*g - b*c*g + S(3)*b*d*f)*log(c + d*x)/(S(3)*b**S(3)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)*log(e*((a + b*x)/(c + d*x))**n)**S(2), x), x, (f + g*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)**S(2)/(S(2)*g) - n**S(2)*(-c*g + d*f)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(d**S(2)*g) - n*(-c*g + d*f)**S(2)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(d**S(2)*g) - n**S(2)*(-a*g + b*f)**S(2)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(2)*g) + n*(-a*g + b*f)**S(2)*log(e*((a + b*x)/(c + d*x))**n)*log((a*d - b*c)/(d*(a + b*x)))/(b**S(2)*g) + g*n*(a + b*x)*(a*d - b*c)*log(e*((a + b*x)/(c + d*x))**n)/(b**S(2)*d) + g*n**S(2)*(-a*d + b*c)**S(2)*log(c + d*x)/(b**S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(2)/b + n**S(2)*(-S(2)*a*d + S(2)*b*c)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n*(-S(2)*a*d + S(2)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) # taking long time in rubi_test assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2)/(f + g*x), x), x, -S(2)*n**S(2)*polylog(S(3), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/g + S(2)*n**S(2)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/g + S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/g - S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/g - log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/g + log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2)/(f + g*x)**S(2), x), x, n**S(2)*(-S(2)*a*d + S(2)*b*c)*polylog(S(2), (a + b*x)*(-c*g + d*f)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)*(-c*g + d*f)) + n*(-S(2)*a*d + S(2)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)*(-c*g + d*f)) + (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(2)/((f + g*x)*(-a*g + b*f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2)/(f + g*x)**S(3), x), x, b**S(2)*n**S(2)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(g*(-a*g + b*f)**S(2)) - b**S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*log((a*d - b*c)/(d*(a + b*x)))/(g*(-a*g + b*f)**S(2)) + d**S(2)*n**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(g*(-c*g + d*f)**S(2)) + d**S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(g*(-c*g + d*f)**S(2)) - g*n**S(2)*(-a*d + b*c)**S(2)*log(c + d*x)/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + g*n**S(2)*(-a*d + b*c)**S(2)*log(f + g*x)/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + g*n*(a + b*x)*(-a*d + b*c)*log(e*((a + b*x)/(c + d*x))**n)/((f + g*x)*(-a*g + b*f)**S(2)*(-c*g + d*f)) - n**S(2)*(-a*d + b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*log(-g*(a + b*x)/(-a*g + b*f))*log(f + g*x)/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n**S(2)*(-a*d + b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*log(-g*(c + d*x)/(-c*g + d*f))*log(f + g*x)/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) - n**S(2)*(-a*d + b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*polylog(S(2), b*(f + g*x)/(-a*g + b*f))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n**S(2)*(-a*d + b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*polylog(S(2), d*(f + g*x)/(-c*g + d*f))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n*(-a*d + b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)*log(f + g*x)/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) - log(e*((a + b*x)/(c + d*x))**n)**S(2)/(S(2)*g*(f + g*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)**S(3), x), x, a**S(2)*g**S(2)*n**S(3)*(-a*d + b*c)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(3)*d) - a**S(2)*g**S(2)*n**S(2)*(-a*d + b*c)*log(e*((a + b*x)/(c + d*x))**n)*log((a*d - b*c)/(d*(a + b*x)))/(b**S(3)*d) + (f + g*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n)**S(3)/(S(3)*g) + S(2)*n**S(3)*(-c*g + d*f)**S(3)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(d**S(3)*g) - S(2)*n**S(2)*(-c*g + d*f)**S(3)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(d**S(3)*g) - n*(-c*g + d*f)**S(3)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/(d**S(3)*g) + c**S(2)*g**S(2)*n**S(3)*(-a*d + b*c)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d**S(3)) + c**S(2)*g**S(2)*n**S(2)*(-a*d + b*c)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d**S(3)) - g**S(2)*n*x**S(2)*(-a*d/S(2) + b*c/S(2))*log(e*((a + b*x)/(c + d*x))**n)**S(2)/(b*d) - S(2)*n**S(3)*(-a*g + b*f)**S(3)*polylog(S(3), b*(c + d*x)/(d*(a + b*x)))/(b**S(3)*g) - S(2)*n**S(2)*(-a*g + b*f)**S(3)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(3)*g) + n*(-a*g + b*f)**S(3)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((a*d - b*c)/(d*(a + b*x)))/(b**S(3)*g) + g**S(2)*n**S(2)*(a + b*x)*(-a*d + b*c)**S(2)*log(e*((a + b*x)/(c + d*x))**n)/(b**S(3)*d**S(2)) - g*n*(a + b*x)*(-a*d + b*c)*(-a*d*g - b*c*g + S(3)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)**S(2)/(b**S(3)*d**S(2)) - g**S(2)*n**S(3)*(-a*d + b*c)**S(3)*log(c + d*x)/(b**S(3)*d**S(3)) - S(2)*g*n**S(3)*(-a*d + b*c)**S(2)*(-a*d*g - b*c*g + S(3)*b*d*f)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b**S(3)*d**S(3)) - S(2)*g*n**S(2)*(-a*d + b*c)**S(2)*(-a*d*g - b*c*g + S(3)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(b**S(3)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f + g*x)*log(e*((a + b*x)/(c + d*x))**n)**S(3), x), x, (f + g*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)**S(3)/(S(2)*g) + S(3)*n**S(3)*(-c*g + d*f)**S(2)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(d**S(2)*g) - S(3)*n**S(2)*(-c*g + d*f)**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(d**S(2)*g) - S(3)*n*(-c*g + d*f)**S(2)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/(S(2)*d**S(2)*g) - S(3)*n**S(3)*(-a*g + b*f)**S(2)*polylog(S(3), b*(c + d*x)/(d*(a + b*x)))/(b**S(2)*g) - S(3)*n**S(2)*(-a*g + b*f)**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(b**S(2)*g) + S(3)*n*(-a*g + b*f)**S(2)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((a*d - b*c)/(d*(a + b*x)))/(S(2)*b**S(2)*g) + g*n*(a + b*x)*(S(3)*a*d/S(2) - S(3)*b*c/S(2))*log(e*((a + b*x)/(c + d*x))**n)**S(2)/(b**S(2)*d) - S(3)*g*n**S(3)*(-a*d + b*c)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b**S(2)*d**S(2)) - S(3)*g*n**S(2)*(-a*d + b*c)**S(2)*log(e*((a + b*x)/(c + d*x))**n)*log((-a*d + b*c)/(b*(c + d*x)))/(b**S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(3), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(3)/b - n**S(3)*(-S(6)*a*d + S(6)*b*c)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n**S(2)*(-S(6)*a*d + S(6)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n*(-S(3)*a*d + S(3)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) # takes long time in test assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(3)/(f + g*x), x), x, -S(6)*n**S(3)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/g + S(6)*n**S(3)*polylog(S(4), (a + b*x)*(-c*g + d*f)/((c + d*x)*(-a*g + b*f)))/g - S(6)*n**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/g + S(6)*n**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/g + S(3)*n*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/g - S(3)*n*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/g - log(e*((a + b*x)/(c + d*x))**n)**S(3)*log((-a*d + b*c)/(b*(c + d*x)))/g + log(e*((a + b*x)/(c + d*x))**n)**S(3)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/g, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(3)/(f + g*x)**S(2), x), x, -n**S(3)*(-S(6)*a*d + S(6)*b*c)*polylog(S(3), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)*(-c*g + d*f)) + n**S(2)*(-S(6)*a*d + S(6)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)*(-c*g + d*f)) + n*(-S(3)*a*d + S(3)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)*(-c*g + d*f)) + (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(3)/((f + g*x)*(-a*g + b*f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(3)/(f + g*x)**S(3), x), x, S(3)*b**S(2)*n**S(3)*polylog(S(3), b*(c + d*x)/(d*(a + b*x)))/(g*(-a*g + b*f)**S(2)) + S(3)*b**S(2)*n**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), b*(c + d*x)/(d*(a + b*x)))/(g*(-a*g + b*f)**S(2)) - S(3)*b**S(2)*n*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((a*d - b*c)/(d*(a + b*x)))/(S(2)*g*(-a*g + b*f)**S(2)) - S(3)*d**S(2)*n**S(3)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(g*(-c*g + d*f)**S(2)) + S(3)*d**S(2)*n**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(g*(-c*g + d*f)**S(2)) + S(3)*d**S(2)*n*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/(S(2)*g*(-c*g + d*f)**S(2)) + S(3)*g*n**S(3)*(-a*d + b*c)**S(2)*polylog(S(2), (a + b*x)*(-c*g + d*f)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + S(3)*g*n**S(2)*(-a*d + b*c)**S(2)*log(e*((a + b*x)/(c + d*x))**n)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + g*n*(a + b*x)*(-S(3)*a*d/S(2) + S(3)*b*c/S(2))*log(e*((a + b*x)/(c + d*x))**n)**S(2)/((f + g*x)*(-a*g + b*f)**S(2)*(-c*g + d*f)) - n**S(3)*(-S(3)*a*d + S(3)*b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*polylog(S(3), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n**S(3)*(-S(3)*a*d + S(3)*b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n**S(2)*(-S(3)*a*d + S(3)*b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) - n**S(2)*(-S(3)*a*d + S(3)*b*c)*(-a*d*g - b*c*g + S(2)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) - n*(-S(3)*a*d/S(2) + S(3)*b*c/S(2))*(-a*d*g - b*c*g + S(2)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) + n*(-S(3)*a*d/S(2) + S(3)*b*c/S(2))*(-a*d*g - b*c*g + S(2)*b*d*f)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/((-a*g + b*f)**S(2)*(-c*g + d*f)**S(2)) - log(e*((a + b*x)/(c + d*x))**n)**S(3)/(S(2)*g*(f + g*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(4), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(4)/b + n**S(4)*(-S(24)*a*d + S(24)*b*c)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/(b*d) - n**S(3)*(-S(24)*a*d + S(24)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n**S(2)*(-S(12)*a*d + S(12)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n*(-S(4)*a*d + S(4)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(3)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(5), x), x, (a + b*x)*log(e*((a + b*x)/(c + d*x))**n)**S(5)/b - n**S(5)*(-S(120)*a*d + S(120)*b*c)*polylog(S(5), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n**S(4)*(-S(120)*a*d + S(120)*b*c)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/(b*d) - n**S(3)*(-S(60)*a*d + S(60)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n**S(2)*(-S(20)*a*d + S(20)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(3)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(b*d) + n*(-S(5)*a*d + S(5)*b*c)*log(e*((a + b*x)/(c + d*x))**n)**S(4)*log((-a*d + b*c)/(b*(c + d*x)))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**m*(c + d*x)**(-m + S(-2))/log(e*((a + b*x)/(c + d*x))**n), x), x, (e*((a + b*x)/(c + d*x))**n)**(-(m + S(1))/n)*(a + b*x)**(m + S(1))*(c + d*x)**(-m + S(-1))*Ei((m + S(1))*log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(3)/((c + d*x)**S(5)*log(e*((a + b*x)/(c + d*x))**n)), x), x, (e*((a + b*x)/(c + d*x))**n)**(-S(4)/n)*(a + b*x)**S(4)*Ei(S(4)*log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(c + d*x)**S(4)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/((c + d*x)**S(4)*log(e*((a + b*x)/(c + d*x))**n)), x), x, (e*((a + b*x)/(c + d*x))**n)**(-S(3)/n)*(a + b*x)**S(3)*Ei(S(3)*log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(c + d*x)**S(3)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/((c + d*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n)), x), x, (e*((a + b*x)/(c + d*x))**n)**(-S(2)/n)*(a + b*x)**S(2)*Ei(S(2)*log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(c + d*x)**S(2)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)), x), x, (e*((a + b*x)/(c + d*x))**n)**(-S(1)/n)*(a + b*x)*Ei(log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(c + d*x)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x)*(c + d*x)*log(e*((a + b*x)/(c + d*x))**n)), x), x, log(log(e*((a + b*x)/(c + d*x))**n))/(n*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x)**S(2)*log(e*((a + b*x)/(c + d*x))**n)), x), x, (e*((a + b*x)/(c + d*x))**n)**(S(1)/n)*(c + d*x)*Ei(-log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(a + b*x)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)/((a + b*x)**S(3)*log(e*((a + b*x)/(c + d*x))**n)), x), x, (e*((a + b*x)/(c + d*x))**n)**(S(2)/n)*(c + d*x)**S(2)*Ei(-S(2)*log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(a + b*x)**S(2)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**S(2)/((a + b*x)**S(4)*log(e*((a + b*x)/(c + d*x))**n)), x), x, (e*((a + b*x)/(c + d*x))**n)**(S(3)/n)*(c + d*x)**S(3)*Ei(-S(3)*log(e*((a + b*x)/(c + d*x))**n)/n)/(n*(a + b*x)**S(3)*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**p/((a + b*x)*(c + d*x)), x), x, log(e*((a + b*x)/(c + d*x))**n)**(p + S(1))/(n*(p + S(1))*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**p/(a*c + b*d*x**S(2) + x*(a*d + b*c)), x), x, log(e*((a + b*x)/(c + d*x))**n)**(p + S(1))/(n*(p + S(1))*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x/(a + b*x))/(a + b*x), x), x, -log(a/(a + b*x))*log(c*x/(a + b*x))/b - polylog(S(2), b*x/(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x/(a + b*x))**S(2)/(x*(a + b*x)), x), x, log(c*x/(a + b*x))**S(3)/(S(3)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a/(a + b*x))*log(c*x/(a + b*x))**S(2)/(x*(a + b*x)), x), x, -log(c*x/(a + b*x))**S(2)*polylog(S(2), b*x/(a + b*x))/a + S(2)*log(c*x/(a + b*x))*polylog(S(3), b*x/(a + b*x))/a - S(2)*polylog(S(4), b*x/(a + b*x))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/((c + d*x)*(f + g*x)), x), x, -n*polylog(S(2), (a + b*x)*(-c*g + d*f)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f) - log(e*((a + b*x)/(c + d*x))**n)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f), expand=True, _diff=True, _numerical=True) # long time in test assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2)/((c + d*x)*(f + g*x)), x), x, S(2)*n**S(2)*polylog(S(3), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f) - S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(2), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f) - log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f), expand=True, _diff=True, _numerical=True) # || assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(3)/((c + d*x)*(f + g*x)), x), x, -S(6)*n**S(3)*polylog(S(4), (a + b*x)*(-c*g + d*f)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f) + S(6)*n**S(2)*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f) - S(3)*n*log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), (a*(-c*g + d*f) - b*c*g*x + b*d*f*x)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f) - log(e*((a + b*x)/(c + d*x))**n)**S(3)*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((-a*d + b*c)/(b*(c + d*x)))*log(e*(a + b*x)/(c + d*x))**S(2)/((c + d*x)*(a*g + b*g*x)), x), x, -log(e*(a + b*x)/(c + d*x))**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(g*(-a*d + b*c)) + S(2)*log(e*(a + b*x)/(c + d*x))*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(g*(-a*d + b*c)) - S(2)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/(g*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)**S(2)*log((-a*d + b*c)/(b*(c + d*x)))/((c + d*x)*(a*g + b*g*x)), x), x, -S(2)*n**S(2)*polylog(S(4), d*(a + b*x)/(b*(c + d*x)))/(g*(-a*d + b*c)) + S(2)*n*log(e*((a + b*x)/(c + d*x))**n)*polylog(S(3), d*(a + b*x)/(b*(c + d*x)))/(g*(-a*d + b*c)) - log(e*((a + b*x)/(c + d*x))**n)**S(2)*polylog(S(2), d*(a + b*x)/(b*(c + d*x)))/(g*(-a*d + b*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a*x + b)/x), x), x, b*log(x)/a + (a*x + b)*log(c*(a*x + b)/x)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a*x + b)/x)**S(2), x), x, -S(2)*b*log(-b/(a*x))*log(c*(a*x + b)/x)/a - S(2)*b*polylog(S(2), S(1) + b/(a*x))/a + (a*x + b)*log(c*(a*x + b)/x)**S(2)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a*x + b)/x)**S(3), x), x, -S(3)*b*log(-b/(a*x))*log(c*(a*x + b)/x)**S(2)/a - S(6)*b*log(c*(a*x + b)/x)*polylog(S(2), (a*x + b)/(a*x))/a + S(6)*b*polylog(S(3), (a*x + b)/(a*x))/a + (a*x + b)*log(c*(a*x + b)/x)**S(3)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a*x + b)**S(2)/x**S(2)), x), x, x*log(c*(a*x + b)**S(2)/x**S(2)) + S(2)*b*log(a*x + b)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a*x + b)**S(2)/x**S(2))**S(2), x), x, x*log(c*(a*x + b)**S(2)/x**S(2))**S(2) - S(4)*b*log(b/(a*x + b))*log(c*(a*x + b)**S(2)/x**S(2))/a + S(8)*b*polylog(S(2), a*x/(a*x + b))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a*x + b)**S(2)/x**S(2))**S(3), x), x, x*log(c*(a*x + b)**S(2)/x**S(2))**S(3) - S(6)*b*log(b/(a*x + b))*log(c*(a*x + b)**S(2)/x**S(2))**S(2)/a + S(24)*b*log(c*(a*x + b)**S(2)/x**S(2))*polylog(S(2), a*x/(a*x + b))/a + S(48)*b*polylog(S(3), a*x/(a*x + b))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**S(2)/(a*x + b)**S(2)), x), x, x*log(c*x**S(2)/(a*x + b)**S(2)) - S(2)*b*log(a*x + b)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**S(2)/(a*x + b)**S(2))**S(2), x), x, x*log(c*x**S(2)/(a*x + b)**S(2))**S(2) + S(4)*b*log(b/(a*x + b))*log(c*x**S(2)/(a*x + b)**S(2))/a + S(8)*b*polylog(S(2), a*x/(a*x + b))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**S(2)/(a*x + b)**S(2))**S(3), x), x, x*log(c*x**S(2)/(a*x + b)**S(2))**S(3) + S(6)*b*log(b/(a*x + b))*log(c*x**S(2)/(a*x + b)**S(2))**S(2)/a + S(24)*b*log(c*x**S(2)/(a*x + b)**S(2))*polylog(S(2), a*x/(a*x + b))/a - S(48)*b*polylog(S(3), a*x/(a*x + b))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b/x)/(d + e*x**S(2)), x), x, -I*log(sqrt(e)*(-a*x - b)/(I*a*sqrt(d) - b*sqrt(e)))*log(S(1) - I*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)) + I*log(sqrt(e)*(a*x + b)/(I*a*sqrt(d) + b*sqrt(e)))*log(S(1) + I*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)) + log(a + b/x)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*sqrt(e)) - I*polylog(S(2), a*(sqrt(d) - I*sqrt(e)*x)/(a*sqrt(d) + I*b*sqrt(e)))/(S(2)*sqrt(d)*sqrt(e)) + I*polylog(S(2), a*(sqrt(d) + I*sqrt(e)*x)/(a*sqrt(d) - I*b*sqrt(e)))/(S(2)*sqrt(d)*sqrt(e)) + I*polylog(S(2), -I*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)) - I*polylog(S(2), I*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(f + g*x**S(2)), x), x, -I*n*log(sqrt(g)*(-a - b*x)/(-a*sqrt(g) + I*b*sqrt(f)))*log(S(1) - I*sqrt(g)*x/sqrt(f))/(S(2)*sqrt(f)*sqrt(g)) + I*n*log(sqrt(g)*(a + b*x)/(a*sqrt(g) + I*b*sqrt(f)))*log(S(1) + I*sqrt(g)*x/sqrt(f))/(S(2)*sqrt(f)*sqrt(g)) + I*n*log(sqrt(g)*(-c - d*x)/(-c*sqrt(g) + I*d*sqrt(f)))*log(S(1) - I*sqrt(g)*x/sqrt(f))/(S(2)*sqrt(f)*sqrt(g)) - I*n*log(sqrt(g)*(c + d*x)/(c*sqrt(g) + I*d*sqrt(f)))*log(S(1) + I*sqrt(g)*x/sqrt(f))/(S(2)*sqrt(f)*sqrt(g)) - I*n*polylog(S(2), b*(sqrt(f) - I*sqrt(g)*x)/(I*a*sqrt(g) + b*sqrt(f)))/(S(2)*sqrt(f)*sqrt(g)) + I*n*polylog(S(2), b*(sqrt(f) + I*sqrt(g)*x)/(-I*a*sqrt(g) + b*sqrt(f)))/(S(2)*sqrt(f)*sqrt(g)) + I*n*polylog(S(2), d*(sqrt(f) - I*sqrt(g)*x)/(I*c*sqrt(g) + d*sqrt(f)))/(S(2)*sqrt(f)*sqrt(g)) - I*n*polylog(S(2), d*(sqrt(f) + I*sqrt(g)*x)/(-I*c*sqrt(g) + d*sqrt(f)))/(S(2)*sqrt(f)*sqrt(g)) + log(e*((a + b*x)/(c + d*x))**n)*atan(sqrt(g)*x/sqrt(f))/(sqrt(f)*sqrt(g)), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate(log(e*((a + b*x)/(c + d*x))**n)/(f + g*x + h*x**S(2)), x), x, n*log((S(2)*a*h - b*g + b*(g + S(2)*h*x))/(S(2)*a*h - b*(g + sqrt(-S(4)*f*h + g**S(2)))))*log(g/sqrt(-S(4)*f*h + g**S(2)) + S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/sqrt(-S(4)*f*h + g**S(2)) - n*log((S(2)*c*h - d*g + d*(g + S(2)*h*x))/(S(2)*c*h - d*(g + sqrt(-S(4)*f*h + g**S(2)))))*log(g/sqrt(-S(4)*f*h + g**S(2)) + S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/sqrt(-S(4)*f*h + g**S(2)) - n*log((-S(2)*a*h + b*g - b*(g + S(2)*h*x))/(-S(2)*a*h + b*g - b*sqrt(-S(4)*f*h + g**S(2))))*log(-g/sqrt(-S(4)*f*h + g**S(2)) - S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/sqrt(-S(4)*f*h + g**S(2)) + n*log((-S(2)*c*h + d*g - d*(g + S(2)*h*x))/(-S(2)*c*h + d*g - d*sqrt(-S(4)*f*h + g**S(2))))*log(-g/sqrt(-S(4)*f*h + g**S(2)) - S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/sqrt(-S(4)*f*h + g**S(2)) - n*polylog(S(2), b*sqrt(-S(4)*f*h + g**S(2))*(-g/sqrt(-S(4)*f*h + g**S(2)) - S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/(S(2)*a*h - b*(g - sqrt(-S(4)*f*h + g**S(2)))))/sqrt(-S(4)*f*h + g**S(2)) + n*polylog(S(2), -b*sqrt(-S(4)*f*h + g**S(2))*(g/sqrt(-S(4)*f*h + g**S(2)) + S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/(S(2)*a*h - b*(g + sqrt(-S(4)*f*h + g**S(2)))))/sqrt(-S(4)*f*h + g**S(2)) + n*polylog(S(2), d*sqrt(-S(4)*f*h + g**S(2))*(-g/sqrt(-S(4)*f*h + g**S(2)) - S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/(S(2)*c*h - d*(g - sqrt(-S(4)*f*h + g**S(2)))))/sqrt(-S(4)*f*h + g**S(2)) - n*polylog(S(2), -d*sqrt(-S(4)*f*h + g**S(2))*(g/sqrt(-S(4)*f*h + g**S(2)) + S(2)*h*x/sqrt(-S(4)*f*h + g**S(2)) + S(1))/(S(2)*c*h - d*(g + sqrt(-S(4)*f*h + g**S(2)))))/sqrt(-S(4)*f*h + g**S(2)) - S(2)*log(e*((a + b*x)/(c + d*x))**n)*atanh((g + S(2)*h*x)/sqrt(-S(4)*f*h + g**S(2)))/sqrt(-S(4)*f*h + g**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**n/(-c**S(2)*x**S(2) + S(1)), x), x, -(a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**(n + S(1))/(b*c*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(3)/(-c**S(2)*x**S(2) + S(1)), x), x, -(a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(4)/(S(4)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(2)/(-c**S(2)*x**S(2) + S(1)), x), x, -(a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(3)/(S(3)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))/(-c**S(2)*x**S(2) + S(1)), x), x, -(a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(2)/(S(2)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))*(-c**S(2)*x**S(2) + S(1))), x), x, -log(a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))/(b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(2)*(-c**S(2)*x**S(2) + S(1))), x), x, S(1)/(b*c*(a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(3)*(-c**S(2)*x**S(2) + S(1))), x), x, S(1)/(S(2)*b*c*(a + b*log(sqrt(-c*x + S(1))/sqrt(c*x + S(1))))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/(-a**S(2)*x**S(2) + S(1)), x), x, -log(sqrt(-a*x + S(1))/sqrt(a*x + S(1)))**S(2)/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(a + b*exp(x)), x), x, -x**S(4)*log(S(1) + b*exp(x)/a)/S(4) + x**S(4)*log(a + b*exp(x))/S(4) - x**S(3)*polylog(S(2), -b*exp(x)/a) + S(3)*x**S(2)*polylog(S(3), -b*exp(x)/a) - S(6)*x*polylog(S(4), -b*exp(x)/a) + S(6)*polylog(S(5), -b*exp(x)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(a + b*exp(x)), x), x, -x**S(3)*log(S(1) + b*exp(x)/a)/S(3) + x**S(3)*log(a + b*exp(x))/S(3) - x**S(2)*polylog(S(2), -b*exp(x)/a) + S(2)*x*polylog(S(3), -b*exp(x)/a) - S(2)*polylog(S(4), -b*exp(x)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(a + b*exp(x)), x), x, -x**S(2)*log(S(1) + b*exp(x)/a)/S(2) + x**S(2)*log(a + b*exp(x))/S(2) - x*polylog(S(2), -b*exp(x)/a) + polylog(S(3), -b*exp(x)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*exp(x)), x), x, -x*log(S(1) + b*exp(x)/a) + x*log(a + b*exp(x)) - polylog(S(2), -b*exp(x)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*exp(x))/x, x), x, Integral(log(a + b*exp(x))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(e*(f**(c*(a + b*x)))**n + S(1)), x), x, -x**S(3)*polylog(S(2), -e*(f**(c*(a + b*x)))**n)/(b*c*n*log(f)) + S(3)*x**S(2)*polylog(S(3), -e*(f**(c*(a + b*x)))**n)/(b**S(2)*c**S(2)*n**S(2)*log(f)**S(2)) - S(6)*x*polylog(S(4), -e*(f**(c*(a + b*x)))**n)/(b**S(3)*c**S(3)*n**S(3)*log(f)**S(3)) + S(6)*polylog(S(5), -e*(f**(c*(a + b*x)))**n)/(b**S(4)*c**S(4)*n**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(e*(f**(c*(a + b*x)))**n + S(1)), x), x, -x**S(2)*polylog(S(2), -e*(f**(c*(a + b*x)))**n)/(b*c*n*log(f)) + S(2)*x*polylog(S(3), -e*(f**(c*(a + b*x)))**n)/(b**S(2)*c**S(2)*n**S(2)*log(f)**S(2)) - S(2)*polylog(S(4), -e*(f**(c*(a + b*x)))**n)/(b**S(3)*c**S(3)*n**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(e*(f**(c*(a + b*x)))**n + S(1)), x), x, -x*polylog(S(2), -e*(f**(c*(a + b*x)))**n)/(b*c*n*log(f)) + polylog(S(3), -e*(f**(c*(a + b*x)))**n)/(b**S(2)*c**S(2)*n**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(f**(c*(a + b*x)))**n + S(1)), x), x, -polylog(S(2), -e*(f**(c*(a + b*x)))**n)/(b*c*n*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(e*(f**(c*(a + b*x)))**n + S(1))/x, x), x, Integral(log(e*(f**(c*(a + b*x)))**n + S(1))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log(d + e*(f**(c*(a + b*x)))**n), x), x, -x**S(4)*log(S(1) + e*(f**(c*(a + b*x)))**n/d)/S(4) + x**S(4)*log(d + e*(f**(c*(a + b*x)))**n)/S(4) - x**S(3)*polylog(S(2), -e*(f**(c*(a + b*x)))**n/d)/(b*c*n*log(f)) + S(3)*x**S(2)*polylog(S(3), -e*(f**(c*(a + b*x)))**n/d)/(b**S(2)*c**S(2)*n**S(2)*log(f)**S(2)) - S(6)*x*polylog(S(4), -e*(f**(c*(a + b*x)))**n/d)/(b**S(3)*c**S(3)*n**S(3)*log(f)**S(3)) + S(6)*polylog(S(5), -e*(f**(c*(a + b*x)))**n/d)/(b**S(4)*c**S(4)*n**S(4)*log(f)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*log(d + e*(f**(c*(a + b*x)))**n), x), x, -x**S(3)*log(S(1) + e*(f**(c*(a + b*x)))**n/d)/S(3) + x**S(3)*log(d + e*(f**(c*(a + b*x)))**n)/S(3) - x**S(2)*polylog(S(2), -e*(f**(c*(a + b*x)))**n/d)/(b*c*n*log(f)) + S(2)*x*polylog(S(3), -e*(f**(c*(a + b*x)))**n/d)/(b**S(2)*c**S(2)*n**S(2)*log(f)**S(2)) - S(2)*polylog(S(4), -e*(f**(c*(a + b*x)))**n/d)/(b**S(3)*c**S(3)*n**S(3)*log(f)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(d + e*(f**(c*(a + b*x)))**n), x), x, -x**S(2)*log(S(1) + e*(f**(c*(a + b*x)))**n/d)/S(2) + x**S(2)*log(d + e*(f**(c*(a + b*x)))**n)/S(2) - x*polylog(S(2), -e*(f**(c*(a + b*x)))**n/d)/(b*c*n*log(f)) + polylog(S(3), -e*(f**(c*(a + b*x)))**n/d)/(b**S(2)*c**S(2)*n**S(2)*log(f)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d + e*(f**(c*(a + b*x)))**n), x), x, -x*log(S(1) + e*(f**(c*(a + b*x)))**n/d) + x*log(d + e*(f**(c*(a + b*x)))**n) - polylog(S(2), -e*(f**(c*(a + b*x)))**n/d)/(b*c*n*log(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(d + e*(f**(c*(a + b*x)))**n)/x, x), x, Integral(log(d + e*(f**(c*(a + b*x)))**n)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(b*(F**(e*(c + d*x)))**n + pi), x), x, x*log(pi) - polylog(S(2), -b*(F**(e*(c + d*x)))**n/pi)/(d*e*n*log(F)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*sin(a + b*x), x), x, -log(x)*cos(a + b*x)/b - sin(a)*Si(b*x)/b + cos(a)*Ci(b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*sin(a + b*x)**S(2), x), x, x*log(x)/S(2) - x/S(2) - log(x)*sin(a + b*x)*cos(a + b*x)/(S(2)*b) + sin(S(2)*a)*Ci(S(2)*b*x)/(S(4)*b) + cos(S(2)*a)*Si(S(2)*b*x)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*sin(a + b*x)**S(3), x), x, log(x)*cos(a + b*x)**S(3)/(S(3)*b) - log(x)*cos(a + b*x)/b - S(3)*sin(a)*Si(b*x)/(S(4)*b) + sin(S(3)*a)*Si(S(3)*b*x)/(S(12)*b) + S(3)*cos(a)*Ci(b*x)/(S(4)*b) - cos(S(3)*a)*Ci(S(3)*b*x)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*cos(a + b*x), x), x, log(x)*sin(a + b*x)/b - sin(a)*Ci(b*x)/b - cos(a)*Si(b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*cos(a + b*x)**S(2), x), x, x*log(x)/S(2) - x/S(2) + log(x)*sin(a + b*x)*cos(a + b*x)/(S(2)*b) - sin(S(2)*a)*Ci(S(2)*b*x)/(S(4)*b) - cos(S(2)*a)*Si(S(2)*b*x)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*cos(a + b*x)**S(3), x), x, -log(x)*sin(a + b*x)**S(3)/(S(3)*b) + log(x)*sin(a + b*x)/b - S(3)*sin(a)*Ci(b*x)/(S(4)*b) - sin(S(3)*a)*Ci(S(3)*b*x)/(S(12)*b) - S(3)*cos(a)*Si(b*x)/(S(4)*b) - cos(S(3)*a)*Si(S(3)*b*x)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*cos(x) + sin(x)/x, x), x, log(x)*sin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sin(x)), x), x, I*x**S(2)/S(2) + x*log(a*sin(x)) - x*log(-exp(S(2)*I*x) + S(1)) + I*polylog(S(2), exp(S(2)*I*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sin(x)**S(2)), x), x, I*x**S(2) + x*log(a*sin(x)**S(2)) - S(2)*x*log(-exp(S(2)*I*x) + S(1)) + I*polylog(S(2), exp(S(2)*I*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sin(x)**n), x), x, I*n*x**S(2)/S(2) - n*x*log(-exp(S(2)*I*x) + S(1)) + I*n*polylog(S(2), exp(S(2)*I*x))/S(2) + x*log(a*sin(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cos(x)), x), x, I*x**S(2)/S(2) + x*log(a*cos(x)) - x*log(exp(S(2)*I*x) + S(1)) + I*polylog(S(2), -exp(S(2)*I*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cos(x)**S(2)), x), x, I*x**S(2) + x*log(a*cos(x)**S(2)) - S(2)*x*log(exp(S(2)*I*x) + S(1)) + I*polylog(S(2), -exp(S(2)*I*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cos(x)**n), x), x, I*n*x**S(2)/S(2) - n*x*log(exp(S(2)*I*x) + S(1)) + I*n*polylog(S(2), -exp(S(2)*I*x))/S(2) + x*log(a*cos(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*tan(x)), x), x, x*log(a*tan(x)) + S(2)*x*atanh(exp(S(2)*I*x)) - I*polylog(S(2), -exp(S(2)*I*x))/S(2) + I*polylog(S(2), exp(S(2)*I*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*tan(x)**S(2)), x), x, x*log(a*tan(x)**S(2)) + S(4)*x*atanh(exp(S(2)*I*x)) - I*polylog(S(2), -exp(S(2)*I*x)) + I*polylog(S(2), exp(S(2)*I*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*tan(x)**n), x), x, S(2)*n*x*atanh(exp(S(2)*I*x)) - I*n*polylog(S(2), -exp(S(2)*I*x))/S(2) + I*n*polylog(S(2), exp(S(2)*I*x))/S(2) + x*log(a*tan(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cot(x)), x), x, x*log(a*cot(x)) - S(2)*x*atanh(exp(S(2)*I*x)) + I*polylog(S(2), -exp(S(2)*I*x))/S(2) - I*polylog(S(2), exp(S(2)*I*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cot(x)**S(2)), x), x, x*log(a*cot(x)**S(2)) - S(4)*x*atanh(exp(S(2)*I*x)) + I*polylog(S(2), -exp(S(2)*I*x)) - I*polylog(S(2), exp(S(2)*I*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cot(x)**n), x), x, -S(2)*n*x*atanh(exp(S(2)*I*x)) + I*n*polylog(S(2), -exp(S(2)*I*x))/S(2) - I*n*polylog(S(2), exp(S(2)*I*x))/S(2) + x*log(a*cot(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sec(x)), x), x, -I*x**S(2)/S(2) + x*log(a*sec(x)) + x*log(exp(S(2)*I*x) + S(1)) - I*polylog(S(2), -exp(S(2)*I*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sec(x)**S(2)), x), x, -I*x**S(2) + x*log(a*sec(x)**S(2)) + S(2)*x*log(exp(S(2)*I*x) + S(1)) - I*polylog(S(2), -exp(S(2)*I*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sec(x)**n), x), x, -I*n*x**S(2)/S(2) + n*x*log(exp(S(2)*I*x) + S(1)) - I*n*polylog(S(2), -exp(S(2)*I*x))/S(2) + x*log(a*sec(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*csc(x)), x), x, -I*x**S(2)/S(2) + x*log(a*csc(x)) + x*log(-exp(S(2)*I*x) + S(1)) - I*polylog(S(2), exp(S(2)*I*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*csc(x)**S(2)), x), x, -I*x**S(2) + x*log(a*csc(x)**S(2)) + S(2)*x*log(-exp(S(2)*I*x) + S(1)) - I*polylog(S(2), exp(S(2)*I*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*csc(x)**n), x), x, -I*n*x**S(2)/S(2) + n*x*log(-exp(S(2)*I*x) + S(1)) - I*n*polylog(S(2), exp(S(2)*I*x))/S(2) + x*log(a*csc(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-cos(S(2)*x)/S(2) + S(1)/2)*cos(x), x), x, log(-cos(S(2)*x)/S(2) + S(1)/2)*sin(x) - S(2)*sin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(x)/log(E*sin(x)), x), x, log(log(E*sin(x))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(cot(x)/log(E*sin(x)), x), x, log(log(sin(x)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(x)/log(exp(sin(x))), x), x, log(log(exp(sin(x))))/(-log(exp(sin(x))) + sin(x)) - log(sin(x))/(-log(exp(sin(x))) + sin(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(cos(x))*sec(x)**S(2), x), x, -x + log(cos(x))*tan(x) + tan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(x))*cot(x), x), x, log(sin(x))**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(x))*sin(x)**S(2)*cos(x), x), x, log(sin(x))*sin(x)**S(3)/S(3) - sin(x)**S(3)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(a/S(2) + b*x/S(2))*cos(a/S(2) + b*x/S(2)))*cos(a + b*x), x), x, log(sin(a/S(2) + b*x/S(2))*cos(a/S(2) + b*x/S(2)))*sin(a + b*x)/b - sin(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(x)/log(cos(x)), x), x, -log(log(cos(x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(cos(x))*tan(x), x), x, -log(cos(x))**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(cos(x))*sin(x), x), x, -log(cos(x))*cos(x) + cos(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(cos(x))*cos(x), x), x, log(cos(x))*sin(x) - sin(x) + atanh(sin(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(x))*cos(x), x), x, log(sin(x))*sin(x) - sin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(x))*sin(x)**S(2), x), x, I*x**S(2)/S(4) - x*log(-exp(S(2)*I*x) + S(1))/S(2) + x*log(sin(x))/S(2) + x/S(4) - log(sin(x))*sin(x)*cos(x)/S(2) + sin(x)*cos(x)/S(4) + I*polylog(S(2), exp(S(2)*I*x))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(x))*sin(x)**S(3), x), x, log(sin(x))*cos(x)**S(3)/S(3) - log(sin(x))*cos(x) - cos(x)**S(3)/S(9) + S(2)*cos(x)/S(3) - S(2)*atanh(cos(x))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(sqrt(x))), x), x, I*x**(S(3)/2)/S(3) + I*sqrt(x)*polylog(S(2), exp(S(2)*I*sqrt(x))) - x*log(-exp(S(2)*I*sqrt(x)) + S(1)) + x*log(sin(sqrt(x))) - polylog(S(3), exp(S(2)*I*sqrt(x)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sin(x))*csc(x)**S(2), x), x, -x - log(sin(x))*cot(x) - cot(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*sinh(a + b*x), x), x, log(x)*cosh(a + b*x)/b - sinh(a)*Shi(b*x)/b - cosh(a)*Chi(b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*sinh(a + b*x)**S(2), x), x, -x*log(x)/S(2) + x/S(2) + log(x)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - sinh(S(2)*a)*Chi(S(2)*b*x)/(S(4)*b) - cosh(S(2)*a)*Shi(S(2)*b*x)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*sinh(a + b*x)**S(3), x), x, log(x)*cosh(a + b*x)**S(3)/(S(3)*b) - log(x)*cosh(a + b*x)/b + S(3)*sinh(a)*Shi(b*x)/(S(4)*b) - sinh(S(3)*a)*Shi(S(3)*b*x)/(S(12)*b) + S(3)*cosh(a)*Chi(b*x)/(S(4)*b) - cosh(S(3)*a)*Chi(S(3)*b*x)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*cosh(a + b*x), x), x, log(x)*sinh(a + b*x)/b - sinh(a)*Chi(b*x)/b - cosh(a)*Shi(b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*cosh(a + b*x)**S(2), x), x, x*log(x)/S(2) - x/S(2) + log(x)*sinh(a + b*x)*cosh(a + b*x)/(S(2)*b) - sinh(S(2)*a)*Chi(S(2)*b*x)/(S(4)*b) - cosh(S(2)*a)*Shi(S(2)*b*x)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*cosh(a + b*x)**S(3), x), x, log(x)*sinh(a + b*x)**S(3)/(S(3)*b) + log(x)*sinh(a + b*x)/b - S(3)*sinh(a)*Chi(b*x)/(S(4)*b) - sinh(S(3)*a)*Chi(S(3)*b*x)/(S(12)*b) - S(3)*cosh(a)*Shi(b*x)/(S(4)*b) - cosh(S(3)*a)*Shi(S(3)*b*x)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sinh(x)), x), x, x**S(2)/S(2) + x*log(a*sinh(x)) - x*log(-exp(S(2)*x) + S(1)) - polylog(S(2), exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sinh(x)**S(2)), x), x, x**S(2) + x*log(a*sinh(x)**S(2)) - S(2)*x*log(-exp(S(2)*x) + S(1)) - polylog(S(2), exp(S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sinh(x)**n), x), x, n*x**S(2)/S(2) - n*x*log(-exp(S(2)*x) + S(1)) - n*polylog(S(2), exp(S(2)*x))/S(2) + x*log(a*sinh(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cosh(x)), x), x, x**S(2)/S(2) + x*log(a*cosh(x)) - x*log(exp(S(2)*x) + S(1)) - polylog(S(2), -exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cosh(x)**S(2)), x), x, x**S(2) + x*log(a*cosh(x)**S(2)) - S(2)*x*log(exp(S(2)*x) + S(1)) - polylog(S(2), -exp(S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*cosh(x)**n), x), x, n*x**S(2)/S(2) - n*x*log(exp(S(2)*x) + S(1)) - n*polylog(S(2), -exp(S(2)*x))/S(2) + x*log(a*cosh(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(tanh(x)), x), x, x*log(tanh(x)) + S(2)*x*atanh(exp(S(2)*x)) + polylog(S(2), -exp(S(2)*x))/S(2) - polylog(S(2), exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*tanh(x)), x), x, x*log(a*tanh(x)) + S(2)*x*atanh(exp(S(2)*x)) + polylog(S(2), -exp(S(2)*x))/S(2) - polylog(S(2), exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*tanh(x)**S(2)), x), x, x*log(a*tanh(x)**S(2)) + S(4)*x*atanh(exp(S(2)*x)) + polylog(S(2), -exp(S(2)*x)) - polylog(S(2), exp(S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*tanh(x)**n), x), x, S(2)*n*x*atanh(exp(S(2)*x)) + n*polylog(S(2), -exp(S(2)*x))/S(2) - n*polylog(S(2), exp(S(2)*x))/S(2) + x*log(a*tanh(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(coth(x)), x), x, x*log(coth(x)) - S(2)*x*atanh(exp(S(2)*x)) - polylog(S(2), -exp(S(2)*x))/S(2) + polylog(S(2), exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*coth(x)), x), x, x*log(a*coth(x)) - S(2)*x*atanh(exp(S(2)*x)) - polylog(S(2), -exp(S(2)*x))/S(2) + polylog(S(2), exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*coth(x)**S(2)), x), x, x*log(a*coth(x)**S(2)) - S(4)*x*atanh(exp(S(2)*x)) - polylog(S(2), -exp(S(2)*x)) + polylog(S(2), exp(S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*coth(x)**n), x), x, -S(2)*n*x*atanh(exp(S(2)*x)) - n*polylog(S(2), -exp(S(2)*x))/S(2) + n*polylog(S(2), exp(S(2)*x))/S(2) + x*log(a*coth(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sech(x)), x), x, -x**S(2)/S(2) + x*log(a*sech(x)) + x*log(exp(S(2)*x) + S(1)) + polylog(S(2), -exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sech(x)**S(2)), x), x, -x**S(2) + x*log(a*sech(x)**S(2)) + S(2)*x*log(exp(S(2)*x) + S(1)) + polylog(S(2), -exp(S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*sech(x)**n), x), x, -n*x**S(2)/S(2) + n*x*log(exp(S(2)*x) + S(1)) + n*polylog(S(2), -exp(S(2)*x))/S(2) + x*log(a*sech(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*csch(x)), x), x, -x**S(2)/S(2) + x*log(a*csch(x)) + x*log(-exp(S(2)*x) + S(1)) + polylog(S(2), exp(S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*csch(x)**S(2)), x), x, -x**S(2) + x*log(a*csch(x)**S(2)) + S(2)*x*log(-exp(S(2)*x) + S(1)) + polylog(S(2), exp(S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*csch(x)**n), x), x, -n*x**S(2)/S(2) + n*x*log(-exp(S(2)*x) + S(1)) + n*polylog(S(2), exp(S(2)*x))/S(2) + x*log(a*csch(x)**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(cosh(x)**S(2))*sinh(x), x), x, log(cosh(x)**S(2))*cosh(x) - S(2)*cosh(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/sqrt(x), x), x, S(2)*sqrt(x)*log(x) - S(4)*sqrt(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(-S(3)*x**S(2) + S(2)), x), x, -x**S(2)/S(2) - (-x**S(2)/S(2) + S(1)/3)*log(-S(3)*x**S(2) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(-log(x)**S(2) + S(1))), x), x, asin(log(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(16)*x**S(3)*log(x)**S(2), x), x, S(4)*x**S(4)*log(x)**S(2) - S(2)*x**S(4)*log(x) + x**S(4)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sqrt(a + b*x)), x), x, -x/S(2) + (a + b*x)*log(sqrt(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(sqrt(x + S(2))), x), x, x**S(2)*log(sqrt(x + S(2)))/S(2) - x**S(2)/S(8) + x/S(2) - log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log((S(3)*x + S(1))**(S(1)/3)), x), x, x**S(2)*log((S(3)*x + S(1))**(S(1)/3))/S(2) - x**S(2)/S(12) + x/S(18) - log(S(3)*x + S(1))/S(54), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(x**S(3) + x), x), x, x**S(2)*log(x**S(3) + x)/S(2) - S(3)*x**S(2)/S(4) + log(x**S(2) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x + sqrt(x**S(2) + S(1))), x), x, x*log(x + sqrt(x**S(2) + S(1))) - sqrt(x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x + sqrt(x**S(2) + S(-1))), x), x, x*log(x + sqrt(x**S(2) + S(-1))) - sqrt(x**S(2) + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x - sqrt(x**S(2) + S(-1))), x), x, x*log(x - sqrt(x**S(2) + S(-1))) + sqrt(x**S(2) + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sqrt(x) + sqrt(x + S(1))), x), x, -sqrt(x)*sqrt(x + S(1))/S(2) + x*log(sqrt(x) + sqrt(x + S(1))) + asinh(sqrt(x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(1)/3)*log(x), x), x, S(3)*x**(S(4)/3)*log(x)/S(4) - S(9)*x**(S(4)/3)/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**log(x), x), x, x**(log(S(2)) + S(1))/(log(S(2)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-log(x) + S(1))/x**S(2), x), x, log(x)/x, expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-log(x) + S(1))/x**S(2), x), x, (log(x) + S(-1))/x + S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x + sqrt(x + S(1)) + S(1)), x), x, x*log(x + sqrt(x + S(1)) + S(1)) - x + sqrt(x + S(1)) + log(x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**S(3) + x), x), x, x*log(x**S(3) + x) - S(3)*x + S(2)*atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**log(S(7)*x + S(-8)), x), x, (S(7)*x + S(-8))**(log(S(2)) + S(1))/(S(7)*(log(S(2)) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((S(5)*x + S(-11))/(S(76)*x + S(5))), x), x, (x + S(-11)/5)*log((S(5)*x + S(-11))/(S(76)*x + S(5))) - S(861)*log(S(76)*x + S(5))/S(380), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((x + S(1))/(x + S(-1)))/x**S(2), x), x, S(2)*log(x) - S(2)*log(-x + S(1)) - (x + S(1))*log((-x + S(-1))/(-x + S(1)))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(1)/(x + S(13))), x), x, x + (x + S(13))*log(S(1)/(x + S(13))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log((x + S(1))/x**S(2)), x), x, x**S(2)*log((x + S(1))/x**S(2))/S(2) + x**S(2)/S(4) + x/S(2) - log(x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*log((S(5)*x + S(7))/x**S(2)), x), x, x**S(4)*log((S(5)*x + S(7))/x**S(2))/S(4) + x**S(4)/S(16) + S(7)*x**S(3)/S(60) - S(49)*x**S(2)/S(200) + S(343)*x/S(500) - S(2401)*log(S(5)*x + S(7))/S(2500), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*log(a + b*x), x), x, -a*x/S(2) - b*x**S(2)/S(4) + (a + b*x)**S(2)*log(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)*log(a + b*x), x), x, (a + b*x)**S(3)*log(a + b*x)/(S(3)*b) - (a + b*x)**S(3)/(S(9)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x)/(a + b*x), x), x, log(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x)/(a + b*x)**S(2), x), x, -log(a + b*x)/(b*(a + b*x)) - S(1)/(b*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n*log(a + b*x), x), x, (a + b*x)**(n + S(1))*log(a + b*x)/(b*(n + S(1))) - (a + b*x)**(n + S(1))/(b*(n + S(1))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*log(b*x)**p), x), x, x*log(a*log(b*x)**p) - p*li(b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*log(b*x**n)**p), x), x, -p*x*(b*x**n)**(-S(1)/n)*Ei(log(b*x**n)/n) + x*log(a*log(b*x**n)**p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*log(b*x)**p)/x, x), x, -(p - log(a*log(b*x)**p))*log(b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a*log(b*x**n)**p)/x, x), x, -(p - log(a*log(b*x**n)**p))*log(b*x**n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(a*log(b*x)**p), x), x, -p*x**(m + S(1))*(b*x)**(-m + S(-1))*Ei((m + S(1))*log(b*x))/(m + S(1)) + x**(m + S(1))*log(a*log(b*x)**p)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*log(a*log(b*x**n)**p), x), x, -p*x**(m + S(1))*(b*x**n)**(-(m + S(1))/n)*Ei((m + S(1))*log(b*x**n)/n)/(m + S(1)) + x**(m + S(1))*log(a*log(b*x**n)**p)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/sqrt(a + b*log(x)), x), x, -sqrt(pi)*a*exp(-a/b)*erfi(sqrt(a + b*log(x))/sqrt(b))/b**(S(3)/2) + x*sqrt(a + b*log(x))/b - sqrt(pi)*exp(-a/b)*erfi(sqrt(a + b*log(x))/sqrt(b))/(S(2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/sqrt(a - b*log(x)), x), x, -sqrt(pi)*a*exp(a/b)*erf(sqrt(a - b*log(x))/sqrt(b))/b**(S(3)/2) - x*sqrt(a - b*log(x))/b + sqrt(pi)*exp(a/b)*erf(sqrt(a - b*log(x))/sqrt(b))/(S(2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*log(x))/sqrt(a + b*log(x)), x), x, B*x*sqrt(a + b*log(x))/b - sqrt(pi)*B*exp(-a/b)*erfi(sqrt(a + b*log(x))/sqrt(b))/(S(2)*sqrt(b)) + sqrt(pi)*(A*b - B*a)*exp(-a/b)*erfi(sqrt(a + b*log(x))/sqrt(b))/b**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*log(x))/sqrt(a - b*log(x)), x), x, -B*x*sqrt(a - b*log(x))/b + sqrt(pi)*B*exp(a/b)*erf(sqrt(a - b*log(x))/sqrt(b))/(S(2)*sqrt(b)) + sqrt(pi)*(-A*b - B*a)*exp(a/b)*erf(sqrt(a - b*log(x))/sqrt(b))/b**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(x)/sqrt(x**S(2) + S(-1)), x), x, sqrt(x**S(2) + S(-1))*log(x) - sqrt(x**S(2) + S(-1)) + atan(sqrt(x**S(2) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(x**S(2) + S(4))*log(x), x), x, (x**S(2) + S(4))**(S(3)/2)*log(x)/S(3) - (x**S(2) + S(4))**(S(3)/2)/S(9) - S(4)*sqrt(x**S(2) + S(4))/S(3) + S(8)*atanh(sqrt(x**S(2) + S(4))/S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x*log(c*x**n)), x), x, log(a + b*log(c*x**n))/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x*log(c*x**n)**S(2)), x), x, atan(sqrt(b)*log(c*x**n)/sqrt(a))/(sqrt(a)*sqrt(b)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x*log(c*x**n)**S(3)), x), x, log(a**(S(1)/3) + b**(S(1)/3)*log(c*x**n))/(S(3)*a**(S(2)/3)*b**(S(1)/3)*n) - log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*log(c*x**n) + b**(S(2)/3)*log(c*x**n)**S(2))/(S(6)*a**(S(2)/3)*b**(S(1)/3)*n) - sqrt(S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*log(c*x**n))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*b**(S(1)/3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x*log(c*x**n)**S(4)), x), x, -sqrt(S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*log(c*x**n) + sqrt(a) + sqrt(b)*log(c*x**n)**S(2))/(S(8)*a**(S(3)/4)*b**(S(1)/4)*n) + sqrt(S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*log(c*x**n) + sqrt(a) + sqrt(b)*log(c*x**n)**S(2))/(S(8)*a**(S(3)/4)*b**(S(1)/4)*n) - sqrt(S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*log(c*x**n)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(1)/4)*n) + sqrt(S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*log(c*x**n)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(1)/4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x/log(c*x**n)), x), x, log(x)/a - b*log(a*log(c*x**n) + b)/(a**S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x/log(c*x**n)**S(2)), x), x, log(x)/a - sqrt(b)*atan(sqrt(a)*log(c*x**n)/sqrt(b))/(a**(S(3)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x/log(c*x**n)**S(3)), x), x, log(x)/a - b**(S(1)/3)*log(a**(S(1)/3)*log(c*x**n) + b**(S(1)/3))/(S(3)*a**(S(4)/3)*n) + b**(S(1)/3)*log(a**(S(2)/3)*log(c*x**n)**S(2) - a**(S(1)/3)*b**(S(1)/3)*log(c*x**n) + b**(S(2)/3))/(S(6)*a**(S(4)/3)*n) + sqrt(S(3))*b**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*a**(S(1)/3)*log(c*x**n) + b**(S(1)/3))/(S(3)*b**(S(1)/3)))/(S(3)*a**(S(4)/3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x/log(c*x**n)**S(4)), x), x, log(x)/a + sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*log(c*x**n) + sqrt(a)*log(c*x**n)**S(2) + sqrt(b))/(S(8)*a**(S(5)/4)*n) - sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*log(c*x**n) + sqrt(a)*log(c*x**n)**S(2) + sqrt(b))/(S(8)*a**(S(5)/4)*n) - sqrt(S(2))*b**(S(1)/4)*atan(sqrt(S(2))*a**(S(1)/4)*log(c*x**n)/b**(S(1)/4) + S(-1))/(S(4)*a**(S(5)/4)*n) - sqrt(S(2))*b**(S(1)/4)*atan(sqrt(S(2))*a**(S(1)/4)*log(c*x**n)/b**(S(1)/4) + S(1))/(S(4)*a**(S(5)/4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(S(4)*x*log(x)**S(2) + x), x), x, log(S(4)*log(x)**S(2) + S(1))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(S(7)*x)**S(2) + x*log(S(7)*x) + x), x), x, S(2)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*log(S(7)*x) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(S(3)*x) + S(-1))/(x*(log(S(3)*x)**S(2) - log(S(3)*x) + S(1))), x), x, log(log(S(3)*x)**S(2) - log(S(3)*x) + S(1))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*log(S(3)*x) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(S(3)*x)**S(2) + S(-1))/(x*log(S(3)*x)**S(3) + x), x), x, log(log(S(3)*x)**S(2) - log(S(3)*x) + S(1))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*log(S(3)*x) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(S(3)*x)**S(2) + S(-1))/(x*log(S(3)*x)**S(2) + x*log(S(3)*x) + x), x), x, log(x) - log(log(S(3)*x)**S(2) + log(S(3)*x) + S(1))/S(2) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*log(S(3)*x) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(log(x) + S(3))), x), x, log(log(x) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(x) + S(1))/x, x), x, S(2)*(log(x) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(x) + S(1))**S(5)/x, x), x, (log(x) + S(1))**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(log(x))), x), x, S(2)*sqrt(log(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(log(x)**S(2) + S(1))), x), x, atan(log(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(log(x)**S(2) + S(-3))), x), x, atanh(log(x)/sqrt(log(x)**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(-S(9)*log(x)**S(2) + S(4))), x), x, asin(S(3)*log(x)/S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(log(x)**S(2) + S(4))), x), x, asinh(log(x)/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(S(3)*log(S(6)*x)**S(3) + S(2))), x), x, S(2)**(S(1)/3)*S(3)**(S(2)/3)*log(S(3)**(S(1)/3)*log(S(6)*x) + S(2)**(S(1)/3))/S(18) - S(2)**(S(1)/3)*S(3)**(S(2)/3)*log(S(3)**(S(2)/3)*log(S(6)*x)**S(2) - S(6)**(S(1)/3)*log(S(6)*x) + S(2)**(S(2)/3))/S(36) - S(2)**(S(1)/3)*S(3)**(S(1)/6)*atan(sqrt(S(3))*(-S(2)**(S(2)/3)*S(3)**(S(1)/3)*log(S(6)*x) + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(log(S(6)*x))/(x*log(S(6)*x)), x), x, log(log(S(6)*x))**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)**log(x)/x, x), x, S(2)**log(x)/log(S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(log(x))**S(2)/x, x), x, log(x)/S(2) - sin(log(x))*cos(log(x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-log(x) + S(7))/(x*(log(x) + S(3))), x), x, -log(x) + S(10)*log(log(x) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-log(x) + S(2))*(log(x) + S(3))**S(2)/x, x), x, -log(x)**S(4)/S(4) - S(4)*log(x)**S(3)/S(3) + S(3)*log(x)**S(2)/S(2) + S(18)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(x)**S(2) + S(1))*log(x)**S(2)/x, x), x, sqrt(log(x)**S(2) + S(1))*log(x)**S(3)/S(4) + sqrt(log(x)**S(2) + S(1))*log(x)/S(8) - asinh(log(x))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(x) + S(1))/(x*(S(2)*log(x) + S(3))**S(2)), x), x, log(S(2)*log(x) + S(3))/S(4) + S(1)/(S(4)*(S(2)*log(x) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(x*sqrt(log(x) + S(1))), x), x, S(2)*(log(x) + S(1))**(S(3)/2)/S(3) - S(2)*sqrt(log(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(x*sqrt(S(4)*log(x) + S(-1))), x), x, (S(4)*log(x) + S(-1))**(S(3)/2)/S(24) + sqrt(S(4)*log(x) + S(-1))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(x) + S(1))/(x*log(x)), x), x, S(2)*sqrt(log(x) + S(1)) - S(2)*atanh(sqrt(log(x) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(x)**S(2) - S(4)*log(x) + S(1))/(x*(log(x) + S(-1))**S(4)), x), x, (log(x) + S(-1))**(S(-2)) + S(1)/(-log(x) + S(1)) - S(2)/(S(3)*(-log(x) + S(1))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(S(1)/x)**S(2)/x**S(5), x), x, -log(S(1)/x)**S(2)/(S(4)*x**S(4)) + log(S(1)/x)/(S(8)*x**S(4)) - S(1)/(S(32)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(a*x**n)**S(2))**p/x, x), x, (log(a*x**n)**S(2))**p*log(a*x**n)/(n*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((log(a*x**n)**m)**p/x, x), x, (log(a*x**n)**m)**p*log(a*x**n)/(n*(m*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(log(a*x**n)**S(2))/x, x), x, sqrt(log(a*x**n)**S(2))*log(a*x**n)/(S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*log(a*x**n)**m)**p/x, x), x, (b*log(a*x**n)**m)**p*log(a*x**n)/(n*(m*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-log(a*x**S(2))), x), x, -sqrt(S(2))*sqrt(pi)*x*erf(sqrt(S(2))*sqrt(-log(a*x**S(2)))/S(2))/(S(2)*sqrt(a*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-log(a/x**S(2))), x), x, sqrt(S(2))*sqrt(pi)*x*sqrt(a/x**S(2))*erfi(sqrt(S(2))*sqrt(-log(a/x**S(2)))/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-log(a*x**n)), x), x, -sqrt(pi)*x*(a*x**n)**(-S(1)/n)*erf(sqrt(-log(a*x**n))/sqrt(n))/sqrt(n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sqrt(x) - x + S(1))/x, x), x, -S(2)*log(sqrt(x))*log((-S(2)*sqrt(x) - sqrt(S(5)) + S(1))/(-sqrt(S(5)) + S(1))) + S(2)*log(sqrt(x))*log(sqrt(x) - x + S(1)) - S(2)*log(S(1)/2 + sqrt(S(5))/S(2))*log(-S(2)*sqrt(x) + S(1) + sqrt(S(5))) - S(2)*polylog(S(2), S(2)*sqrt(x)/(-sqrt(S(5)) + S(1))) + S(2)*polylog(S(2), (-S(2)*sqrt(x) + S(1) + sqrt(S(5)))/(S(1) + sqrt(S(5)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(c + d*x)/(a + b*x), x), x, -a*log(-d*(a + b*x)/(-a*d + b*c))*log(c + d*x)/b**S(2) - a*polylog(S(2), b*(c + d*x)/(-a*d + b*c))/b**S(2) - x/b + (c + d*x)*log(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(x + S(-1)), x), x, -polylog(S(2), -x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*log(-a - b*x + S(1))/(a + b*x), x), x, a*polylog(S(2), a + b*x)/b**S(2) - x/b - (-a - b*x + S(1))*log(-a - b*x + S(1))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*log(x)/(x*(b + c*x)), x), x, log(x)**S(2)/S(2) + log(x)*log((b + c*x)/b) + polylog(S(2), -c*x/b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)*sin(x*log(x)) + sin(x*log(x)), x), x, -cos(x*log(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((-(x + S(-1))**S(2) + S(1))/((x + S(-1))**S(2) + S(1)))/x**S(2), x), x, log(x)/S(2) + log(-x + S(2))/S(2) - log(x**S(2) - S(2)*x + S(2))/S(2) - atan(x + S(-1)) - log((-(-x + S(1))**S(2) + S(1))/((x + S(-1))**S(2) + S(1)))/x - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(sqrt(x) + x), x), x, sqrt(x) + x*log(sqrt(x) + x) - x - log(sqrt(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-x/(x + S(1))), x), x, x*log(-x/(x + S(1))) - log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((x + S(-1))/(x + S(1))), x), x, (x + S(-1))*log((x + S(-1))/(x + S(1))) - S(2)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log((-x**S(2) + S(1))/(x**S(2) + S(1)))/(x + S(1))**S(2), x), x, log(-x**S(2) + S(1))/S(2) - log(x**S(2) + S(1))/S(2) - atan(x) - log((-x**S(2) + S(1))/(x**S(2) + S(1)))/(x + S(1)) - S(1)/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(-x**S(2) + S(1)), x), x, log(x)*atanh(x) + polylog(S(2), -x)/S(2) - polylog(S(2), x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x)/(x**S(2) + S(1)), x), x, log(x)*atan(x) - I*polylog(S(2), -I*x)/S(2) + I*polylog(S(2), I*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(x**S(2) + S(1))**n)/(x**S(2) + S(1)), x), x, S(2)*n*log(S(2)*I/(-x + I))*atan(x) + I*n*atan(x)**S(2) + I*n*polylog(S(2), (-x - I)/(-x + I)) + log(c*(x**S(2) + S(1))**n)*atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(x**S(2)/(x**S(2) + S(1)))/(x**S(2) + S(1)), x), x, -S(2)*log(S(2)*x/(x + I))*atan(x) + log(x**S(2)/(x**S(2) + S(1)))*atan(x) + I*atan(x)**S(2) + I*polylog(S(2), (-x + I)/(x + I)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**n)/(a + b*x**S(2)), x), x, -I*n*polylog(S(2), -I*sqrt(b)*x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)) + I*n*polylog(S(2), I*sqrt(b)*x/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)) + log(c*x**n)*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*(a + b*x**S(2))**n)/(a + b*x**S(2)), x), x, S(2)*n*log(S(2)*I*sqrt(a)/(I*sqrt(a) - sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)) + I*n*atan(sqrt(b)*x/sqrt(a))**S(2)/(sqrt(a)*sqrt(b)) + I*n*polylog(S(2), (-sqrt(a) + I*sqrt(b)*x)/(sqrt(a) + I*sqrt(b)*x))/(sqrt(a)*sqrt(b)) + log(c*(a + b*x**S(2))**n)*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(c*x**S(2)/(a + b*x**S(2)))/(a + b*x**S(2)), x), x, -S(2)*log(S(2)*sqrt(b)*x/(I*sqrt(a) + sqrt(b)*x))*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)) + log(c*x**S(2)/(a + b*x**S(2)))*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)) + I*atan(sqrt(b)*x/sqrt(a))**S(2)/(sqrt(a)*sqrt(b)) + I*polylog(S(2), (sqrt(a) + I*sqrt(b)*x)/(sqrt(a) - I*sqrt(b)*x))/(sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(I*sqrt(-a*x + S(1))/sqrt(a*x + S(1)) + S(1))/(-a**S(2)*x**S(2) + S(1)), x), x, polylog(S(2), -I*sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(-I*sqrt(-a*x + S(1))/sqrt(a*x + S(1)) + S(1))/(-a**S(2)*x**S(2) + S(1)), x), x, polylog(S(2), I*sqrt(-a*x + S(1))/sqrt(a*x + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(exp(a + b*x)), x), x, log(exp(a + b*x))**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(exp(a + b*x**n)), x), x, -b*n*x**(n + S(1))/(n + S(1)) + x*log(exp(a + b*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(x)*log(a + b*exp(x)), x), x, -exp(x) + (a + b*exp(x))*log(a + b*exp(x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*log(exp(x))), x), x, -log(x)/(x - log(exp(x))) + log(log(exp(x)))/(x - log(exp(x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(exp(a + b*x)*log(x), x), x, -exp(a)*Ei(b*x)/b + exp(a + b*x)*log(x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x + log(x)), x), x, Integral(x**S(2)/(x + log(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x + log(x)), x), x, Integral(x/(x + log(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x + log(x)), x), x, Integral(S(1)/(x + log(x)), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x + log(x))), x), x, Integral(S(1)/(x*(x + log(x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x + log(x))), x), x, Integral(S(1)/(x**S(2)*(x + log(x))), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-log(x) + S(1))/(x*(x + log(x))), x), x, log(S(1) + log(x)/x), expand=True, _diff=True, _numerical=True) ''' apart # apart assert rubi_test(rubi_integrate((x + S(1))/((x + log(x))*log(x)), x), x, -log(x + log(x)) + log(log(x)) + li(x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x + S(1))/((x + log(x))*log(x)), x), x, -log(x + log(x)) + log(log(x)) + Ei(log(x)), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(log(sqrt((x + S(1))/x) + S(2)), x), x, x*log(sqrt((x + S(1))/x) + S(2)) - log(-sqrt((x + S(1))/x) + S(1))/S(6) + log(sqrt((x + S(1))/x) + S(1))/S(2) - log(sqrt((x + S(1))/x) + S(2))/S(3), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(log(sqrt((x + S(1))/x) + S(1)), x), x, x*log(sqrt((x + S(1))/x) + S(1)) + atanh(sqrt((x + S(1))/x))/S(2) - S(1)/(S(2)*(sqrt((x + S(1))/x) + S(1))), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(log(sqrt((x + S(1))/x)), x), x, (x + S(1))*log(sqrt((x + S(1))/x)) + log(x)/S(2), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(log(sqrt((x + S(1))/x) + S(-1)), x), x, x*log(sqrt((x + S(1))/x) + S(-1)) - atanh(sqrt(S(1) + S(1)/x))/S(2) - S(1)/(S(2)*(-sqrt(S(1) + S(1)/x) + S(1))), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(log(sqrt((x + S(1))/x) + S(-2)), x), x, x*log(sqrt((x + S(1))/x) + S(-2)) + log(-sqrt(S(1) + S(1)/x) + S(1))/S(2) - log(-sqrt(S(1) + S(1)/x) + S(2))/S(3) - log(sqrt(S(1) + S(1)/x) + S(1))/S(6), expand=True, _diff=True, _numerical=True) ''' assert rubi_test(rubi_integrate(x**(a*x)*log(x) + x**(a*x), x), x, x**(a*x)/a, expand=True, _diff=True, _numerical=True) # fails in mathematica too assert rubi_test(rubi_integrate((log(x)**m)**p, x), x, (-log(x))**(-m*p)*(log(x)**m)**p*Gamma(m*p + S(1), -log(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(log(a + b*x + c*sqrt(d + e*x))/(f + g*x**S(2)), x), x, -log((a*e - b*d + b*(d + e*x) + c*e*sqrt(d + e*x))/e)*log(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) + log((a*e - b*d + b*(d + e*x) + c*e*sqrt(d + e*x))/e)*log(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) - log((a*e - b*d + b*(d + e*x) + c*e*sqrt(d + e*x))/e)*log(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) + log((a*e - b*d + b*(d + e*x) + c*e*sqrt(d + e*x))/e)*log(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) + log(-g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) - g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) + log(g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) + g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) + log(-g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) - g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) + log(g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) + g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) - log(-g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) - g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) - log(g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) + g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) - log(-g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) - g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) - log(g**(S(1)/4)*(S(2)*b*sqrt(d + e*x) + c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) + g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))*log(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*sqrt(g)*sqrt(-f)) + polylog(S(2), S(2)*b*(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) - g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)) + polylog(S(2), S(2)*b*(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) + g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)) + polylog(S(2), S(2)*b*(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) - g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)) + polylog(S(2), S(2)*b*(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) - e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) - e*sqrt(-f)) + g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)) - polylog(S(2), S(2)*b*(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) - g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)) - polylog(S(2), S(2)*b*(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) + g**(S(1)/4)*(c*e - sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)) - polylog(S(2), S(2)*b*(g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) - g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)) - polylog(S(2), S(2)*b*(-g**(S(1)/4)*sqrt(d + e*x) + sqrt(d*sqrt(g) + e*sqrt(-f)))/(S(2)*b*sqrt(d*sqrt(g) + e*sqrt(-f)) + g**(S(1)/4)*(c*e + sqrt(-S(4)*a*b*e + S(4)*b**S(2)*d + c**S(2)*e**S(2)))))/(S(2)*sqrt(g)*sqrt(-f)), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_miscellaneous_algebra.py000066400000000000000000020035351412543434000313230ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.rubi import rubi_integrate from sympy.functions import log, sqrt, exp, cos, sin, tan, sec, csc, cot from sympy.functions.elementary.hyperbolic import atanh from sympy.functions.elementary.hyperbolic import asinh from sympy.functions.elementary.hyperbolic import acosh from sympy.functions.elementary.trigonometric import atan from sympy.functions.elementary.trigonometric import asin from sympy.functions.elementary.trigonometric import acos from sympy.integrals.rubi.utility_function import (EllipticE, EllipticF, hypergeom, rubi_test, AppellF1, EllipticPi, Log, Sqrt, ArcTan, ArcTanh, ArcSin, ArcCos, Hypergeometric2F1) from sympy import pi as Pi from sympy import S, hyper, I, simplify, exp_polar, symbols,elliptic_pi,elliptic_e, elliptic_f from sympy.testing.pytest import SKIP from sympy import acsch as arccsch, acsc as arccsc from sympy import acsch, acsc a, b, c, d, e, f, m, n, x, u , k, p, r, s, t= symbols('a b c d e f m n x u k p r s t') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F',) def test_1(): # difference in apart assert rubi_test(rubi_integrate(S(1)/(S(2)*sqrt(S(3))*b**(S(3)/2) - S(9)*b*x + S(9)*x**S(3)), x), x, -log(sqrt(b) - sqrt(S(3))*x)/(S(27)*b) + log(S(2)*sqrt(b) + sqrt(S(3))*x)/(S(27)*b) + sqrt(S(3))/(S(9)*sqrt(b)*(sqrt(S(3))*sqrt(b) - S(3)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))**p, x), x, (a + b*x)*(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))**p/(b*(S(3)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))**S(3), x), x, (a + b*x)**S(10)/(S(10)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))**S(2), x), x, (a + b*x)**S(7)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3), x), x, a**S(3)*x + S(3)*a**S(2)*b*x**S(2)/S(2) + a*b**S(2)*x**S(3) + b**S(3)*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3)), x), x, -S(1)/(S(2)*b*(a + b*x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))**(S(-2)), x), x, -S(1)/(S(5)*b*(a + b*x)**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(3) + S(3)*a**S(2)*b*x + S(3)*a*b**S(2)*x**S(2) + b**S(3)*x**S(3))**(S(-3)), x), x, -S(1)/(S(8)*b*(a + b*x)**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*a*b + S(3)*b**S(2)*x + S(3)*b*c*x**S(2) + c**S(2)*x**S(3))**S(3), x), x, -b**S(3)*x*(-S(3)*a*c + b**S(2))**S(3)/c**S(3) + S(3)*b**S(2)*(b + c*x)**S(4)*(-S(3)*a*c + b**S(2))**S(2)/(S(4)*c**S(4)) - S(3)*b*(b + c*x)**S(7)*(-S(3)*a*c + b**S(2))/(S(7)*c**S(4)) + (b + c*x)**S(10)/(S(10)*c**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*a*b + S(3)*b**S(2)*x + S(3)*b*c*x**S(2) + c**S(2)*x**S(3))**S(2), x), x, b**S(2)*x*(-S(3)*a*c + b**S(2))**S(2)/c**S(2) - b*(b + c*x)**S(4)*(-S(3)*a*c + b**S(2))/(S(2)*c**S(3)) + (b + c*x)**S(7)/(S(7)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(3)*a*b + S(3)*b**S(2)*x + S(3)*b*c*x**S(2) + c**S(2)*x**S(3), x), x, S(3)*a*b*x + S(3)*b**S(2)*x**S(2)/S(2) + b*c*x**S(3) + c**S(2)*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(3)*a*b + S(3)*b**S(2)*x + S(3)*b*c*x**S(2) + c**S(2)*x**S(3)), x), x, log(b**(S(1)/3)*(-S(3)*a*c + b**S(2))**(S(1)/3) - b - c*x)/(S(3)*b**(S(2)/3)*(-S(3)*a*c + b**S(2))**(S(2)/3)) - log(b**(S(2)/3)*(-S(3)*a*c + b**S(2))**(S(2)/3) + b**(S(1)/3)*(b + c*x)*(-S(3)*a*c + b**S(2))**(S(1)/3) + (b + c*x)**S(2))/(S(6)*b**(S(2)/3)*(-S(3)*a*c + b**S(2))**(S(2)/3)) - sqrt(S(3))*atan(sqrt(S(3))*(b**(S(1)/3) + (S(2)*b + S(2)*c*x)/(-S(3)*a*c + b**S(2))**(S(1)/3))/(S(3)*b**(S(1)/3)))/(S(3)*b**(S(2)/3)*(-S(3)*a*c + b**S(2))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*a*b + S(3)*b**S(2)*x + S(3)*b*c*x**S(2) + c**S(2)*x**S(3))**(S(-2)), x), x, c*(b + c*x)/(S(3)*b*(-S(3)*a*c + b**S(2))*(b*(-S(3)*a*c + b**S(2)) - (b + c*x)**S(3))) - S(2)*c*log(b**(S(1)/3)*(-S(3)*a*c + b**S(2))**(S(1)/3) - b - c*x)/(S(9)*b**(S(5)/3)*(-S(3)*a*c + b**S(2))**(S(5)/3)) + c*log(b**(S(2)/3)*(-S(3)*a*c + b**S(2))**(S(2)/3) + b**(S(1)/3)*(b + c*x)*(-S(3)*a*c + b**S(2))**(S(1)/3) + (b + c*x)**S(2))/(S(9)*b**(S(5)/3)*(-S(3)*a*c + b**S(2))**(S(5)/3)) + S(2)*sqrt(S(3))*c*atan(sqrt(S(3))*(b**(S(1)/3) + (S(2)*b + S(2)*c*x)/(-S(3)*a*c + b**S(2))**(S(1)/3))/(S(3)*b**(S(1)/3)))/(S(9)*b**(S(5)/3)*(-S(3)*a*c + b**S(2))**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*a*b + S(3)*b**S(2)*x + S(3)*b*c*x**S(2) + c**S(2)*x**S(3))**(S(-3)), x), x, -c**S(2)*(b + c*x)/(S(6)*b*(-S(3)*a*c + b**S(2))*(b*(-S(3)*a*c + b**S(2)) - (b + c*x)**S(3))**S(2)) - S(5)*c**S(2)*(b + c*x)/(S(18)*b**S(2)*(-S(3)*a*c + b**S(2))**S(2)*(b*(-S(3)*a*c + b**S(2)) - (b + c*x)**S(3))) + S(5)*c**S(2)*log(b**(S(1)/3)*(-S(3)*a*c + b**S(2))**(S(1)/3) - b - c*x)/(S(27)*b**(S(8)/3)*(-S(3)*a*c + b**S(2))**(S(8)/3)) - S(5)*c**S(2)*log(b**(S(2)/3)*(-S(3)*a*c + b**S(2))**(S(2)/3) + b**(S(1)/3)*(b + c*x)*(-S(3)*a*c + b**S(2))**(S(1)/3) + (b + c*x)**S(2))/(S(54)*b**(S(8)/3)*(-S(3)*a*c + b**S(2))**(S(8)/3)) - S(5)*sqrt(S(3))*c**S(2)*atan(sqrt(S(3))*(b**(S(1)/3) + (S(2)*b + S(2)*c*x)/(-S(3)*a*c + b**S(2))**(S(1)/3))/(S(3)*b**(S(1)/3)))/(S(27)*b**(S(8)/3)*(-S(3)*a*c + b**S(2))**(S(8)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*c*e + b*d*f*x**S(3) + x**S(2)*(a*d*f + b*c*f + b*d*e) + x*(a*c*f + a*d*e + b*c*e))**S(3), x), x, a**S(3)*c**S(3)*e**S(3)*x + S(3)*a**S(2)*c**S(2)*e**S(2)*x**S(2)*(a*c*f + a*d*e + b*c*e)/S(2) + a*c*e*x**S(3)*(a**S(2)*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2)) + S(3)*a*b*c*e*(c*f + d*e) + b**S(2)*c**S(2)*e**S(2)) + b**S(3)*d**S(3)*f**S(3)*x**S(10)/S(10) + b**S(2)*d**S(2)*f**S(2)*x**S(9)*(a*d*f + b*c*f + b*d*e)/S(3) + S(3)*b*d*f*x**S(8)*(a**S(2)*d**S(2)*f**S(2) + S(3)*a*b*d*f*(c*f + d*e) + b**S(2)*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2)))/S(8) + x**S(7)*(a**S(3)*d**S(3)*f**S(3)/S(7) + S(9)*a**S(2)*b*d**S(2)*f**S(2)*(c*f + d*e)/S(7) + S(9)*a*b**S(2)*d*f*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2))/S(7) + b**S(3)*(c**S(3)*f**S(3) + S(9)*c**S(2)*d*e*f**S(2) + S(9)*c*d**S(2)*e**S(2)*f + d**S(3)*e**S(3))/S(7)) + x**S(6)*(a**S(3)*d**S(2)*f**S(2)*(c*f + d*e)/S(2) + S(3)*a**S(2)*b*d*f*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2))/S(2) + a*b**S(2)*(c**S(3)*f**S(3) + S(9)*c**S(2)*d*e*f**S(2) + S(9)*c*d**S(2)*e**S(2)*f + d**S(3)*e**S(3))/S(2) + b**S(3)*c*e*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2))/S(2)) + x**S(5)*(S(3)*a**S(3)*d*f*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2))/S(5) + S(3)*a**S(2)*b*(c**S(3)*f**S(3) + S(9)*c**S(2)*d*e*f**S(2) + S(9)*c*d**S(2)*e**S(2)*f + d**S(3)*e**S(3))/S(5) + S(9)*a*b**S(2)*c*e*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2))/S(5) + S(3)*b**S(3)*c**S(2)*e**S(2)*(c*f + d*e)/S(5)) + x**S(4)*(a**S(3)*(c**S(3)*f**S(3) + S(9)*c**S(2)*d*e*f**S(2) + S(9)*c*d**S(2)*e**S(2)*f + d**S(3)*e**S(3))/S(4) + S(9)*a**S(2)*b*c*e*(c**S(2)*f**S(2) + S(3)*c*d*e*f + d**S(2)*e**S(2))/S(4) + S(9)*a*b**S(2)*c**S(2)*e**S(2)*(c*f + d*e)/S(4) + b**S(3)*c**S(3)*e**S(3)/S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*c*e + b*d*f*x**S(3) + x**S(2)*(a*d*f + b*c*f + b*d*e) + x*(a*c*f + a*d*e + b*c*e))**S(2), x), x, a**S(2)*c**S(2)*e**S(2)*x + a*c*e*x**S(2)*(a*c*f + a*d*e + b*c*e) + b**S(2)*d**S(2)*f**S(2)*x**S(7)/S(7) + b*d*f*x**S(6)*(a*d*f + b*c*f + b*d*e)/S(3) + x**S(5)*(a**S(2)*d**S(2)*f**S(2)/S(5) + S(4)*a*b*d*f*(c*f + d*e)/S(5) + b**S(2)*(c**S(2)*f**S(2) + S(4)*c*d*e*f + d**S(2)*e**S(2))/S(5)) + x**S(4)*(a**S(2)*d*f*(c*f + d*e)/S(2) + a*b*(c**S(2)*f**S(2) + S(4)*c*d*e*f + d**S(2)*e**S(2))/S(2) + b**S(2)*c*e*(c*f + d*e)/S(2)) + x**S(3)*(a**S(2)*(c**S(2)*f**S(2) + S(4)*c*d*e*f + d**S(2)*e**S(2))/S(3) + S(4)*a*b*c*e*(c*f + d*e)/S(3) + b**S(2)*c**S(2)*e**S(2)/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a*c*e + b*d*f*x**S(3) + x**S(2)*(a*d*f + b*c*f + b*d*e) + x*(a*c*f + a*d*e + b*c*e), x), x, a*c*e*x + b*d*f*x**S(4)/S(4) + x**S(3)*(a*d*f/S(3) + b*c*f/S(3) + b*d*e/S(3)) + x**S(2)*(a*c*f/S(2) + a*d*e/S(2) + b*c*e/S(2)), expand=True, _diff=True, _numerical=True) '''taking a long time assert rubi_test(rubi_integrate(S(1)/(a*c*e + b*d*f*x**S(3) + x**S(2)*(a*d*f + b*c*f + b*d*e) + x*(a*c*f + a*d*e + b*c*e)), x), x, b*log(a + b*x)/((-a*d + b*c)*(-a*f + b*e)) - d*log(c + d*x)/((-a*d + b*c)*(-c*f + d*e)) + f*log(e + f*x)/((-a*f + b*e)*(-c*f + d*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*c*e + b*d*f*x**S(3) + x**S(2)*(a*d*f + b*c*f + b*d*e) + x*(a*c*f + a*d*e + b*c*e))**(S(-2)), x), x, -S(2)*b**S(3)*(-S(2)*a*d*f + b*c*f + b*d*e)*log(a + b*x)/((-a*d + b*c)**S(3)*(-a*f + b*e)**S(3)) - b**S(3)/((a + b*x)*(-a*d + b*c)**S(2)*(-a*f + b*e)**S(2)) + S(2)*d**S(3)*(a*d*f - S(2)*b*c*f + b*d*e)*log(c + d*x)/((-a*d + b*c)**S(3)*(-c*f + d*e)**S(3)) - d**S(3)/((c + d*x)*(-a*d + b*c)**S(2)*(-c*f + d*e)**S(2)) + S(2)*f**S(3)*(-a*d*f - b*c*f + S(2)*b*d*e)*log(e + f*x)/((-a*f + b*e)**S(3)*(-c*f + d*e)**S(3)) - f**S(3)/((e + f*x)*(-a*f + b*e)**S(2)*(-c*f + d*e)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*c*e + b*d*f*x**S(3) + x**S(2)*(a*d*f + b*c*f + b*d*e) + x*(a*c*f + a*d*e + b*c*e))**(S(-3)), x), x, S(3)*b**S(5)*(S(7)*a**S(2)*d**S(2)*f**S(2) - S(7)*a*b*d*f*(c*f + d*e) + b**S(2)*(S(2)*c**S(2)*f**S(2) + S(3)*c*d*e*f + S(2)*d**S(2)*e**S(2)))*log(a + b*x)/((-a*d + b*c)**S(5)*(-a*f + b*e)**S(5)) + S(3)*b**S(5)*(-S(2)*a*d*f + b*c*f + b*d*e)/((a + b*x)*(-a*d + b*c)**S(4)*(-a*f + b*e)**S(4)) - b**S(5)/(S(2)*(a + b*x)**S(2)*(-a*d + b*c)**S(3)*(-a*f + b*e)**S(3)) - S(3)*d**S(5)*(S(2)*a**S(2)*d**S(2)*f**S(2) + a*b*d*f*(-S(7)*c*f + S(3)*d*e) + b**S(2)*(S(7)*c**S(2)*f**S(2) - S(7)*c*d*e*f + S(2)*d**S(2)*e**S(2)))*log(c + d*x)/((-a*d + b*c)**S(5)*(-c*f + d*e)**S(5)) + S(3)*d**S(5)*(a*d*f - S(2)*b*c*f + b*d*e)/((c + d*x)*(-a*d + b*c)**S(4)*(-c*f + d*e)**S(4)) + d**S(5)/(S(2)*(c + d*x)**S(2)*(-a*d + b*c)**S(3)*(-c*f + d*e)**S(3)) + S(3)*f**S(5)*(S(2)*a**S(2)*d**S(2)*f**S(2) - a*b*d*f*(-S(3)*c*f + S(7)*d*e) + b**S(2)*(S(2)*c**S(2)*f**S(2) - S(7)*c*d*e*f + S(7)*d**S(2)*e**S(2)))*log(e + f*x)/((-a*f + b*e)**S(5)*(-c*f + d*e)**S(5)) - S(3)*f**S(5)*(-a*d*f - b*c*f + S(2)*b*d*e)/((e + f*x)*(-a*f + b*e)**S(4)*(-c*f + d*e)**S(4)) - f**S(5)/(S(2)*(e + f*x)**S(2)*(-a*f + b*e)**S(3)*(-c*f + d*e)**S(3)), expand=True, _diff=True, _numerical=True) ''' '''matchpy and mathematica difference assert rubi_test(rubi_integrate(S(1)/(S(16)*x**S(3) - S(4)*x**S(2) + S(4)*x + S(-1)), x), x, log(-S(4)*x + S(1))/S(5) - log(S(4)*x**S(2) + S(1))/S(10) - atan(S(2)*x)/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3) + x**S(2) + x + S(1)), x), x, log(x + S(1))/S(2) - log(x**S(2) + S(1))/S(4) + atan(x)/S(2), expand=True, _diff=True, _numerical=True) ''' assert rubi_test(rubi_integrate(S(1)/(d*x**S(3)), x), x, -S(1)/(S(2)*d*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(c*x**S(2) + d*x**S(3)), x), x, -S(1)/(c*x) - d*log(x)/c**S(2) + d*log(c + d*x)/c**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(b*x + d*x**S(3)), x), x, log(x)/b - log(b + d*x**S(2))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(b*x + c*x**S(2) + d*x**S(3)), x), x, c*atanh((c + S(2)*d*x)/sqrt(-S(4)*b*d + c**S(2)))/(b*sqrt(-S(4)*b*d + c**S(2))) + log(x)/b - log(b + c*x + d*x**S(2))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + d*x**S(3)), x), x, log(a**(S(1)/3) + d**(S(1)/3)*x)/(S(3)*a**(S(2)/3)*d**(S(1)/3)) - log(a**(S(2)/3) - a**(S(1)/3)*d**(S(1)/3)*x + d**(S(2)/3)*x**S(2))/(S(6)*a**(S(2)/3)*d**(S(1)/3)) - sqrt(S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*d**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*d**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x**S(3))**n, x), x, x*(d*x**S(3))**n/(S(3)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2) + d*x**S(3))**n, x), x, x*(S(1) + d*x/c)**(-n)*(c*x**S(2) + d*x**S(3))**n*hyper((-n, S(2)*n + S(1)), (S(2)*n + S(2),), -d*x/c)/(S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x + d*x**S(3))**n, x), x, x*(b + d*x**S(2))*(b*x + d*x**S(3))**n*hyper((S(1), S(3)*n/S(2) + S(3)/2), (n/S(2) + S(3)/2,), -d*x**S(2)/b)/(b*(n + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((b*x + d*x**S(3))**n, x), x, x*(S(1) + d*x**S(2)/b)**(-n)*(b*x + d*x**S(3))**n*hyper((-n, n/S(2) + S(1)/2), (n/S(2) + S(3)/2,), -d*x**S(2)/b)/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x + c*x**S(2) + d*x**S(3))**n, x), x, x*(S(2)*d*x/(c - sqrt(-S(4)*b*d + c**S(2))) + S(1))**(-n)*(S(2)*d*x/(c + sqrt(-S(4)*b*d + c**S(2))) + S(1))**(-n)*(b*x + c*x**S(2) + d*x**S(3))**n*AppellF1(n + S(1), -n, -n, n + S(2), -S(2)*d*x/(c - sqrt(-S(4)*b*d + c**S(2))), -S(2)*d*x/(c + sqrt(-S(4)*b*d + c**S(2))))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + d*x**S(3))**n, x), x, x*(a + d*x**S(3))**(n + S(1))*hyper((S(1), n + S(4)/3), (S(4)/3,), -d*x**S(3)/a)/a, expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + d*x**S(3))**n, x), x, x*(S(1) + d*x**S(3)/a)**(-n)*(a + d*x**S(3))**n*hyper((S(1)/3, -n), (S(4)/3,), -d*x**S(3)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(5) + S(5)*a**S(4)*b*x + S(10)*a**S(3)*b**S(2)*x**S(2) + S(10)*a**S(2)*b**S(3)*x**S(3) + S(5)*a*b**S(4)*x**S(4) + b**S(5)*x**S(5))**S(3), x), x, (a + b*x)**S(16)/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(5) + S(5)*a**S(4)*b*x + S(10)*a**S(3)*b**S(2)*x**S(2) + S(10)*a**S(2)*b**S(3)*x**S(3) + S(5)*a*b**S(4)*x**S(4) + b**S(5)*x**S(5))**S(2), x), x, (a + b*x)**S(11)/(S(11)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**S(5) + S(5)*a**S(4)*b*x + S(10)*a**S(3)*b**S(2)*x**S(2) + S(10)*a**S(2)*b**S(3)*x**S(3) + S(5)*a*b**S(4)*x**S(4) + b**S(5)*x**S(5), x), x, (a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(a**S(5) + S(5)*a**S(4)*b*x + S(10)*a**S(3)*b**S(2)*x**S(2) + S(10)*a**S(2)*b**S(3)*x**S(3) + S(5)*a*b**S(4)*x**S(4) + b**S(5)*x**S(5), x), x, a**S(5)*x + S(5)*a**S(4)*b*x**S(2)/S(2) + S(10)*a**S(3)*b**S(2)*x**S(3)/S(3) + S(5)*a**S(2)*b**S(3)*x**S(4)/S(2) + a*b**S(4)*x**S(5) + b**S(5)*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a**S(5) + S(5)*a**S(4)*b*x + S(10)*a**S(3)*b**S(2)*x**S(2) + S(10)*a**S(2)*b**S(3)*x**S(3) + S(5)*a*b**S(4)*x**S(4) + b**S(5)*x**S(5)), x), x, -S(1)/(S(4)*b*(a + b*x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(5) + S(5)*a**S(4)*b*x + S(10)*a**S(3)*b**S(2)*x**S(2) + S(10)*a**S(2)*b**S(3)*x**S(3) + S(5)*a*b**S(4)*x**S(4) + b**S(5)*x**S(5))**(S(-2)), x), x, -S(1)/(S(9)*b*(a + b*x)**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(5) + S(5)*a**S(4)*b*x + S(10)*a**S(3)*b**S(2)*x**S(2) + S(10)*a**S(2)*b**S(3)*x**S(3) + S(5)*a*b**S(4)*x**S(4) + b**S(5)*x**S(5))**(S(-3)), x), x, -S(1)/(S(14)*b*(a + b*x)**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(c + (a + b*x)**S(2)), x), x, -S(3)*a*x/b**S(3) - a*(a**S(2) - S(3)*c)*atan((a + b*x)/sqrt(c))/(b**S(4)*sqrt(c)) + (a + b*x)**S(2)/(S(2)*b**S(4)) + (S(3)*a**S(2)/S(2) - c/S(2))*log(c + (a + b*x)**S(2))/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(c + (a + b*x)**S(2)), x), x, -a*log(c + (a + b*x)**S(2))/b**S(3) + x/b**S(2) + (a**S(2) - c)*atan((a + b*x)/sqrt(c))/(b**S(3)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(c + (a + b*x)**S(2)), x), x, -a*atan((a + b*x)/sqrt(c))/(b**S(2)*sqrt(c)) + log(c + (a + b*x)**S(2))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(c + (a + b*x)**S(2)), x), x, atan((a + b*x)/sqrt(c))/(b*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(c + (a + b*x)**S(2))), x), x, -a*atan((a + b*x)/sqrt(c))/(sqrt(c)*(a**S(2) + c)) + log(x)/(a**S(2) + c) - log(c + (a + b*x)**S(2))/(S(2)*(a**S(2) + c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(c + (a + b*x)**S(2))), x), x, -S(2)*a*b*log(x)/(a**S(2) + c)**S(2) + a*b*log(c + (a + b*x)**S(2))/(a**S(2) + c)**S(2) + b*(a**S(2) - c)*atan((a + b*x)/sqrt(c))/(sqrt(c)*(a**S(2) + c)**S(2)) - S(1)/(x*(a**S(2) + c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(c + (a + b*x)**S(2))), x), x, -a*b**S(2)*(a**S(2) - S(3)*c)*atan((a + b*x)/sqrt(c))/(sqrt(c)*(a**S(2) + c)**S(3)) + S(2)*a*b/(x*(a**S(2) + c)**S(2)) + b**S(2)*(S(3)*a**S(2) - c)*log(x)/(a**S(2) + c)**S(3) - b**S(2)*(S(3)*a**S(2) - c)*log(c + (a + b*x)**S(2))/(S(2)*(a**S(2) + c)**S(3)) - S(1)/(S(2)*x**S(2)*(a**S(2) + c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*(c + d*x)**S(2)), x), x, atan(sqrt(b)*(c + d*x)/sqrt(a))/(sqrt(a)*sqrt(b)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c + d*x)**S(2))**(S(-2)), x), x, (c/S(2) + d*x/S(2))/(a*d*(a + b*(c + d*x)**S(2))) + atan(sqrt(b)*(c + d*x)/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c + d*x)**S(2))**(S(-3)), x), x, (c/S(4) + d*x/S(4))/(a*d*(a + b*(c + d*x)**S(2))**S(2)) + (S(3)*c/S(8) + S(3)*d*x/S(8))/(a**S(2)*d*(a + b*(c + d*x)**S(2))) + S(3)*atan(sqrt(b)*(c + d*x)/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(b*(c + d*x)**S(2) + sqrt(-a)), x), x, atan(sqrt(b)*(c + d*x)/(-a)**(S(1)/4))/(sqrt(b)*d*(-a)**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c + d*x)**S(2) + S(1)), x), x, atan(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((c + d*x)**S(2) + S(1))**(S(-2)), x), x, (c/S(2) + d*x/S(2))/(d*((c + d*x)**S(2) + S(1))) + atan(c + d*x)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((c + d*x)**S(2) + S(1))**(S(-3)), x), x, (c/S(4) + d*x/S(4))/(d*((c + d*x)**S(2) + S(1))**S(2)) + (S(3)*c/S(8) + S(3)*d*x/S(8))/(d*((c + d*x)**S(2) + S(1))) + S(3)*atan(c + d*x)/(S(8)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-(c + d*x)**S(2) + S(1)), x), x, atanh(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-(c + d*x)**S(2) + S(1))**(S(-2)), x), x, (c/S(2) + d*x/S(2))/(d*(-(c + d*x)**S(2) + S(1))) + atanh(c + d*x)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-(c + d*x)**S(2) + S(1))**(S(-3)), x), x, (c/S(4) + d*x/S(4))/(d*(-(c + d*x)**S(2) + S(1))**S(2)) + (S(3)*c/S(8) + S(3)*d*x/S(8))/(d*(-(c + d*x)**S(2) + S(1))) + S(3)*atanh(c + d*x)/(S(8)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-(x + S(1))**S(2) + S(1)), x), x, atanh(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-(x + S(1))**S(2) + S(1))**(S(-2)), x), x, (x/S(2) + S(1)/2)/(-(x + S(1))**S(2) + S(1)) + atanh(x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-(x + S(1))**S(2) + S(1))**(S(-3)), x), x, (x/S(4) + S(1)/4)/(-(x + S(1))**S(2) + S(1))**S(2) + (S(3)*x/S(8) + S(3)/8)/(-(x + S(1))**S(2) + S(1)) + S(3)*atanh(x + S(1))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((a + b*x)**S(2) + S(1))**S(2)/x, x), x, a*b*x*(a**S(2) + S(2)) + a*(a + b*x)**S(3)/S(3) + (a + b*x)**S(4)/S(4) + (a + b*x)**S(2)*(a**S(2)/S(2) + S(1)) + (a**S(2) + S(1))**S(2)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((x + S(-1))**S(2) + S(1)), x), x, x + log((x + S(-1))**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(-(x + S(1))**S(2) + S(1)), x), x, -x*sqrt(-(x + S(1))**S(2) + S(1))/S(2) + S(3)*sqrt(-(x + S(1))**S(2) + S(1))/S(2) + S(3)*asin(x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(-(a + b*x)**S(2) + S(1)), x), x, S(3)*a*sqrt(-(a + b*x)**S(2) + S(1))/(S(2)*b**S(3)) - x*sqrt(-(a + b*x)**S(2) + S(1))/(S(2)*b**S(2)) + (a**S(2) + S(1)/2)*asin(a + b*x)/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt((a + b*x)**S(2) + S(1)), x), x, -S(3)*a*sqrt((a + b*x)**S(2) + S(1))/(S(2)*b**S(3)) + x*sqrt((a + b*x)**S(2) + S(1))/(S(2)*b**S(2)) + (a**S(2) + S(-1)/2)*asinh(a + b*x)/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2) + D*x**S(3))/(a*x**S(4) + a + b*x**S(3) + b*x + c*x**S(2)), x), x, -(D*(b - sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) + S(2)*a*(A - C))*log(S(2)*a*x**S(2) + S(2)*a + x*(b - sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) + (D*(b + sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) + S(2)*a*(A - C))*log(S(2)*a*x**S(2) + S(2)*a + x*(b + sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) - sqrt(S(2))*(S(4)*B*a**S(2) + D*b*(b + sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) - a*(A*(b + sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) + C*b + C*sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)) + S(2)*D*c))*atan(sqrt(S(2))*(S(4)*a*x + b + sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)))/(S(2)*sqrt(S(4)*a**S(2) + S(2)*a*c - b*(b + sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))))))/(S(2)*a*sqrt(S(4)*a**S(2) + S(2)*a*c - b*(b + sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))))*sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) + sqrt(S(2))*(S(4)*B*a**S(2) + D*b*(b - sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) - a*(A*(b - sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))) + C*b - C*sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)) + S(2)*D*c))*atan(sqrt(S(2))*(S(4)*a*x + b - sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)))/(S(2)*sqrt(S(4)*a**S(2) + S(2)*a*c - b*(b - sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))))))/(S(2)*a*sqrt(S(4)*a**S(2) + S(2)*a*c - b*(b - sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))))*sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2)), x), x, x**S(4)/S(4) + x**S(3)/S(3) - S(3)*x**S(2)/S(4) + S(5)*x/S(4) + log(x**S(2) + x + S(1))/S(3) - S(13)*log(S(2)*x**S(2) - x + S(2))/S(48) + sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(72) - S(10)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2)), x), x, x**S(3)/S(3) + x**S(2)/S(2) - S(3)*x/S(2) + S(2)*log(x**S(2) + x + S(1))/S(3) - log(S(2)*x**S(2) - x + S(2))/S(24) + S(5)*sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(36) + S(8)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2)), x), x, x**S(2)/S(2) + x - log(x**S(2) + x + S(1)) + log(S(2)*x**S(2) - x + S(2))/S(4) + sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(18) + S(2)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2)), x), x, x + log(x**S(2) + x + S(1))/S(3) + log(S(2)*x**S(2) - x + S(2))/S(6) - sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(9) - S(10)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2)), x), x, S(2)*log(x**S(2) + x + S(1))/S(3) - log(S(2)*x**S(2) - x + S(2))/S(6) - sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(9) + S(8)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(x*(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2))), x), x, S(5)*log(x)/S(2) - log(x**S(2) + x + S(1)) - log(S(2)*x**S(2) - x + S(2))/S(4) + sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(18) + S(2)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(x**S(2)*(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2))), x), x, -S(3)*log(x)/S(4) + log(x**S(2) + x + S(1))/S(3) + log(S(2)*x**S(2) - x + S(2))/S(24) + S(5)*sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(36) - S(10)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9) - S(5)/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(x**S(3)*(S(2)*x**S(4) + x**S(3) + S(3)*x**S(2) + x + S(2))), x), x, -S(15)*log(x)/S(8) + S(2)*log(x**S(2) + x + S(1))/S(3) + S(13)*log(S(2)*x**S(2) - x + S(2))/S(48) + sqrt(S(15))*atan(sqrt(S(15))*(-S(4)*x + S(1))/S(15))/S(72) + S(8)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9) + S(3)/(S(4)*x) - S(5)/(S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(5)*x**S(2) + x + S(2)), x), x, x**S(3)*(S(7) - S(5)*sqrt(S(7))*I)/S(42) + x**S(3)*(S(7) + S(5)*sqrt(S(7))*I)/S(42) + x**S(2)*(S(7) - S(5)*sqrt(S(7))*I)/S(28) + x**S(2)*(S(7) + S(5)*sqrt(S(7))*I)/S(28) - x*(S(35) + S(9)*sqrt(S(7))*I)/S(28) - x*(S(35) - S(9)*sqrt(S(7))*I)/S(28) + S(3)*(S(7) - S(11)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) - sqrt(S(7))*I) + S(4))/S(112) + S(3)*(S(7) + S(11)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) + sqrt(S(7))*I) + S(4))/S(112) - S(11)*(-S(5)*sqrt(S(7)) + S(9)*I)*atan((S(8)*x + S(1) + sqrt(S(7))*I)/sqrt(S(70) - S(2)*sqrt(S(7))*I))/(S(4)*sqrt(S(490) - S(14)*sqrt(S(7))*I)) + S(11)*(S(5)*sqrt(S(7)) + S(9)*I)*atan((S(8)*x + S(1) - sqrt(S(7))*I)/sqrt(S(70) + S(2)*sqrt(S(7))*I))/(S(4)*sqrt(S(490) + S(14)*sqrt(S(7))*I)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(5)*x**S(2) + x + S(2)), x), x, x**S(2)*(S(7) - S(5)*sqrt(S(7))*I)/S(28) + x**S(2)*(S(7) + S(5)*sqrt(S(7))*I)/S(28) + x*(S(7) - S(5)*sqrt(S(7))*I)/S(14) + x*(S(7) + S(5)*sqrt(S(7))*I)/S(14) - (S(35) + S(9)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) - sqrt(S(7))*I) + S(4))/S(56) - (S(35) - S(9)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) + sqrt(S(7))*I) + S(4))/S(56) + (-sqrt(S(7)) + S(53)*I)*atan((S(8)*x + S(1) + sqrt(S(7))*I)/sqrt(S(70) - S(2)*sqrt(S(7))*I))/(S(2)*sqrt(S(490) - S(14)*sqrt(S(7))*I)) - (sqrt(S(7)) + S(53)*I)*atan((S(8)*x + S(1) - sqrt(S(7))*I)/sqrt(S(70) + S(2)*sqrt(S(7))*I))/(S(2)*sqrt(S(490) + S(14)*sqrt(S(7))*I)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(5)*x**S(2) + x + S(2)), x), x, x*(S(7) - S(5)*sqrt(S(7))*I)/S(14) + x*(S(7) + S(5)*sqrt(S(7))*I)/S(14) + (S(7) + S(5)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) - sqrt(S(7))*I) + S(4))/S(28) + (S(7) - S(5)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) + sqrt(S(7))*I) + S(4))/S(28) + (-S(7)*sqrt(S(7)) + S(19)*I)*atan((S(8)*x + S(1) + sqrt(S(7))*I)/sqrt(S(70) - S(2)*sqrt(S(7))*I))/sqrt(S(490) - S(14)*sqrt(S(7))*I) - (S(7)*sqrt(S(7)) + S(19)*I)*atan((S(8)*x + S(1) - sqrt(S(7))*I)/sqrt(S(70) + S(2)*sqrt(S(7))*I))/sqrt(S(490) + S(14)*sqrt(S(7))*I), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(S(2)*x**S(4) + x**S(3) + S(5)*x**S(2) + x + S(2)), x), x, (S(7) + S(5)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) - sqrt(S(7))*I) + S(4))/S(28) + (S(7) - S(5)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) + sqrt(S(7))*I) + S(4))/S(28) - (-S(7)*sqrt(S(7)) + S(19)*I)*atan((S(8)*x + S(1) + sqrt(S(7))*I)/sqrt(S(70) - S(2)*sqrt(S(7))*I))/sqrt(S(490) - S(14)*sqrt(S(7))*I) + (S(7)*sqrt(S(7)) + S(19)*I)*atan((S(8)*x + S(1) - sqrt(S(7))*I)/sqrt(S(70) + S(2)*sqrt(S(7))*I))/sqrt(S(490) + S(14)*sqrt(S(7))*I), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(x*(S(2)*x**S(4) + x**S(3) + S(5)*x**S(2) + x + S(2))), x), x, (S(35) - S(9)*sqrt(S(7))*I)*log(x)/S(28) + (S(35) + S(9)*sqrt(S(7))*I)*log(x)/S(28) - (S(35) + S(9)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) - sqrt(S(7))*I) + S(4))/S(56) - (S(35) - S(9)*sqrt(S(7))*I)*log(S(4)*x**S(2) + x*(S(1) + sqrt(S(7))*I) + S(4))/S(56) - (-sqrt(S(7)) + S(53)*I)*atan((S(8)*x + S(1) + sqrt(S(7))*I)/sqrt(S(70) - S(2)*sqrt(S(7))*I))/(S(2)*sqrt(S(490) - S(14)*sqrt(S(7))*I)) + (sqrt(S(7)) + S(53)*I)*atan((S(8)*x + S(1) - sqrt(S(7))*I)/sqrt(S(70) + S(2)*sqrt(S(7))*I))/(S(2)*sqrt(S(490) + S(14)*sqrt(S(7))*I)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(x**S(2)*(S(2)*x**S(4) + x**S(3) + S(5)*x**S(2) + x + S(2))), x), x, -S(3)*(S(7) + S(11)*sqrt(S(7))*I)*log(x)/S(56) - S(3)*(S(7) - S(11)*sqrt(S(7))*I)*log(x)/S(56) + S(3)*(S(7) + S(11)*sqrt(S(7))*I)*log(S(4)*I*x**S(2) + x*(-sqrt(S(7)) + I) + S(4)*I)/S(112) + S(3)*(S(7) - S(11)*sqrt(S(7))*I)*log(S(4)*I*x**S(2) + x*(sqrt(S(7)) + I) + S(4)*I)/S(112) + S(11)*(S(9) + S(5)*sqrt(S(7))*I)*atanh((S(8)*I*x - sqrt(S(7)) + I)/sqrt(S(70) - S(2)*sqrt(S(7))*I))/(S(4)*sqrt(S(490) - S(14)*sqrt(S(7))*I)) - S(11)*(S(9) - S(5)*sqrt(S(7))*I)*atanh((S(8)*I*x + sqrt(S(7)) + I)/sqrt(S(70) + S(2)*sqrt(S(7))*I))/(S(4)*sqrt(S(490) + S(14)*sqrt(S(7))*I)) + (S(-5)/4 - S(9)*sqrt(S(7))*I/S(28))/x + (S(-5)/4 + S(9)*sqrt(S(7))*I/S(28))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + x + S(5))/(x**S(3)*(S(2)*x**S(4) + x**S(3) + S(5)*x**S(2) + x + S(2))), x), x, -(S(35) + S(9)*sqrt(S(7))*I)*log(x)/S(16) - (S(35) - S(9)*sqrt(S(7))*I)*log(x)/S(16) + (S(35) - S(9)*sqrt(S(7))*I)*log(S(4)*I*x**S(2) + x*(-sqrt(S(7)) + I) + S(4)*I)/S(32) + (S(35) + S(9)*sqrt(S(7))*I)*log(S(4)*I*x**S(2) + x*(sqrt(S(7)) + I) + S(4)*I)/S(32) + (S(355) - S(73)*sqrt(S(7))*I)*atanh((S(8)*I*x - sqrt(S(7)) + I)/sqrt(S(70) - S(2)*sqrt(S(7))*I))/(S(8)*sqrt(S(490) - S(14)*sqrt(S(7))*I)) - (S(355) + S(73)*sqrt(S(7))*I)*atanh((S(8)*I*x + sqrt(S(7)) + I)/sqrt(S(70) + S(2)*sqrt(S(7))*I))/(S(8)*sqrt(S(490) + S(14)*sqrt(S(7))*I)) + (S(3)/8 - S(33)*sqrt(S(7))*I/S(56))/x + (S(3)/8 + S(33)*sqrt(S(7))*I/S(56))/x + (S(-5)/8 - S(9)*sqrt(S(7))*I/S(56))/x**S(2) + (S(-5)/8 + S(9)*sqrt(S(7))*I/S(56))/x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(3)*x**S(2) + x + S(9))/((x**S(2) + S(1))*(x**S(2) + S(3))), x), x, log(x**S(2) + S(3))/S(2) + S(3)*atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) + x + S(3))/((x**S(2) + S(1))*(x**S(2) + S(3))), x), x, log(x**S(2) + S(3))/S(2) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(3) - x**S(2) + S(6)*x + S(-4))/((x**S(2) + S(1))*(x**S(2) + S(2))), x), x, S(3)*log(x**S(2) + S(1))/S(2) - S(3)*atan(x) + sqrt(S(2))*atan(sqrt(S(2))*x/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*x**S(4) + S(1))/((x + S(-2))*(x**S(2) + S(1))**S(2)), x), x, (S(2)*x/S(5) + S(-1)/5)/(x**S(2) + S(1)) - S(47)*log(-x + S(2))/S(25) - S(14)*log(x**S(2) + S(1))/S(25) - S(46)*atan(x)/S(25), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) - S(9)*x + S(-9))/(x**S(3) - S(9)*x), x), x, log(x) - log(-x + S(3)) + S(2)*log(x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(5) + S(2)*x**S(2) + S(1))/(x**S(3) - x), x), x, x**S(3)/S(3) + x - log(x) + S(2)*log(-x + S(1)) + log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(3))/(x*(x + S(-1))**S(2)), x), x, S(3)*log(x) - log(-x + S(1)) + S(5)/(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(-1))/((S(4)*x + S(-1))*(x**S(2) + S(1))), x), x, -S(7)*log(-S(4)*x + S(1))/S(34) + S(6)*log(x**S(2) + S(1))/S(17) + S(3)*atan(x)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(3)*x**S(2) + S(2)*x + S(-3))/(x**S(2) + S(1)), x), x, x**S(2)/S(2) - S(3)*x + log(x**S(2) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(6)*x**S(3) + S(10)*x**S(2) + x)/(x**S(2) + S(6)*x + S(10)), x), x, x**S(3)/S(3) + log(x**S(2) + S(6)*x + S(10))/S(2) - S(3)*atan(x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) - S(3)*x**S(3) - S(7)*x**S(2) + S(27)*x + S(-18)), x), x, log(-x + S(1))/S(8) - log(-x + S(2))/S(5) + log(-x + S(3))/S(12) - log(x + S(3))/S(120), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(1))/(x + S(-2)), x), x, x**S(3)/S(3) + x**S(2) + S(4)*x + S(9)*log(-x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(3) - S(4)*x**S(2) + S(3)*x)/(x**S(2) + S(1)), x), x, S(3)*x**S(2)/S(2) - S(4)*x + S(4)*atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x + S(5))/(x**S(3) - x**S(2) - x + S(1)), x), x, atanh(x) + S(4)/(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - x**S(3) - x + S(-1))/(x**S(3) - x**S(2)), x), x, x**S(2)/S(2) + S(2)*log(x) - S(2)*log(-x + S(1)) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) + x + S(2))/(x**S(4) + S(3)*x**S(2) + S(2)), x), x, log(x**S(2) + S(2))/S(2) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(5) - x**S(4) + S(4)*x**S(3) - S(4)*x**S(2) + S(8)*x + S(-4))/(x**S(2) + S(2))**S(3), x), x, log(x**S(2) + S(2))/S(2) - sqrt(S(2))*atan(sqrt(S(2))*x/S(2))/S(2) - S(1)/(x**S(2) + S(2))**S(2), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(5) - x**S(4) + S(4)*x**S(3) - S(4)*x**S(2) + S(8)*x + S(-4))/(x**S(2) + S(2))**S(3), x), x, x**S(2)/(S(4)*(x**S(2) + S(2))) + x**S(2)/(S(2)*(x**S(2) + S(2))**S(2)) + log(x**S(2) + S(2))/S(2) - sqrt(S(2))*atan(sqrt(S(2))*x/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(-1))/(x**S(3) + x**S(2) - S(2)*x), x), x, log(x)/S(2) - log(-x + S(1)) + S(3)*log(x + S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - S(2)*x**S(3) + S(3)*x**S(2) - x + S(3))/(x**S(3) - S(2)*x**S(2) + S(3)*x), x), x, x**S(2)/S(2) + log(x) - log(x**S(2) - S(2)*x + S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x + S(-1))/(x**S(2) + S(1))**S(2), x), x, -x/(S(2)*(x**S(2) + S(1))) + log(x**S(2) + S(1))/S(2) - atan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(8)*x**S(3) - x**S(2) + S(2)*x + S(1))/((x**S(2) + x)*(x**S(3) + S(1))), x), x, log(x) - S(2)*log(x + S(1)) + log(x**S(2) - x + S(1)) - S(2)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(3) - S(3)/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) - S(5)*x + S(15))/((x**S(2) + S(5))*(x**S(2) + S(2)*x + S(3))), x), x, log(x**S(2) + S(2)*x + S(3))/S(2) + S(5)*sqrt(S(2))*atan(sqrt(S(2))*(x + S(1))/S(2))/S(2) - sqrt(S(5))*atan(sqrt(S(5))*x/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(6) + S(7)*x**S(5) + S(15)*x**S(4) + S(32)*x**S(3) + S(23)*x**S(2) + S(25)*x + S(-3))/((x**S(2) + S(1))**S(2)*(x**S(2) + x + S(2))**S(2)), x), x, log(x**S(2) + S(1)) - log(x**S(2) + x + S(2)) + S(1)/(x**S(2) + x + S(2)) - S(3)/(x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x**S(2) + S(1))*(x**S(2) + S(4))), x), x, -atan(x/S(2))/S(6) + atan(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3))/(x**S(2) + S(1)), x), x, a*atan(x) + b*x**S(2)/S(2) - b*log(x**S(2) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + x)/((x + S(4))*(x**S(2) + S(-4))), x), x, log(x + S(4)) - atanh(x/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(4))/((x**S(2) + S(1))*(x**S(2) + S(2))), x), x, S(3)*atan(x) - sqrt(S(2))*atan(sqrt(S(2))*x/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(3)*x**S(2) - S(4)*x + S(5))/((x + S(-1))**S(2)*(x**S(2) + S(1))), x), x, x + log(-x + S(1))/S(2) + S(3)*log(x**S(2) + S(1))/S(4) + S(2)*atan(x) + S(5)/(S(2)*(-x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(1))/(x**S(2) + S(2)), x), x, x**S(3)/S(3) - S(2)*x + S(5)*sqrt(S(2))*atan(sqrt(S(2))*x/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(2)*x + S(2))/(x**S(5) + x**S(4)), x), x, log(x + S(1)) - S(2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) - S(5)*x + S(-1))/(x**S(3) - S(2)*x**S(2) - x + S(2)), x), x, S(2)*log(-x + S(1)) - log(-x + S(2)) + log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x + S(2))/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, x/(x**S(2) + S(1)) + log(x**S(2) + S(1))/S(2) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) + S(2)*x + S(1))/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, log(x**S(2) + S(1))/S(2) + atan(x) - S(1)/(S(2)*(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(3) + x**S(2) + S(2)*x + S(1))/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, x**S(2)/(S(2)*(x**S(2) + S(1))) + log(x**S(2) + S(1))/S(2) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x + S(3))/((x**S(2) + S(1))*(x**S(2) + S(2))), x), x, S(2)*log(x**S(2) + S(1)) - S(2)*log(x**S(2) + S(2)) + S(3)*atan(x) - S(3)*sqrt(S(2))*atan(sqrt(S(2))*x/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))/((x**S(2) + S(1))*(x**S(2) + S(4))), x), x, log(x**S(2) + S(1))/S(6) - log(x**S(2) + S(4))/S(6) - atan(x/S(2))/S(3) + S(2)*atan(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - x + S(2))/(x**S(2) - S(6)*x + S(-7)), x), x, x**S(2)/S(2) + S(6)*x + S(169)*log(-x + S(7))/S(4) - log(x + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(5) + S(-1))/(x**S(2) + S(-1)), x), x, x**S(4)/S(4) + x**S(2)/S(2) + log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - x**S(2) + S(2)*x + S(5))/(x**S(2) + x + S(1)), x), x, x**S(2)/S(2) - S(2)*x + S(3)*log(x**S(2) + x + S(1))/S(2) + S(11)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - S(2)*x**S(3) + x + S(-3))/(S(2)*x**S(2) - S(8)*x + S(10)), x), x, x**S(3)/S(6) + x**S(2)/S(2) + S(3)*x/S(2) + S(3)*log(x**S(2) - S(4)*x + S(5))/S(4) - S(6)*atan(x + S(-2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(3)*x**S(2) + S(2)*x + S(1))/((x + S(-3))*(x + S(-2))*(x + S(-1))), x), x, x + S(7)*log(-x + S(1))/S(2) - S(25)*log(-x + S(2)) + S(61)*log(-x + S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - x**S(3) + x**S(2) - S(7)*x + S(2))/(x**S(3) + x**S(2) - S(14)*x + S(-24)), x), x, x**S(2)/S(2) - S(2)*x + S(13)*log(-x + S(4))/S(3) - S(22)*log(x + S(2))/S(3) + S(20)*log(x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(2))/(x*(x + S(-1))**S(2)*(x + S(1))), x), x, S(2)*log(x) - S(5)*log(-x + S(1))/S(4) - S(3)*log(x + S(1))/S(4) + S(3)/(S(2)*(-x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) + S(3))/(x**S(2) + S(2))**S(2), x), x, (x/S(4) + S(1))/(x**S(2) + S(2)) + log(x**S(2) + S(2))/S(2) + S(5)*sqrt(S(2))*atan(sqrt(S(2))*x/S(2))/S(8), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(3) + x**S(2) + S(3))/(x**S(2) + S(2))**S(2), x), x, x*(-x/S(2) + S(1)/4)/(x**S(2) + S(2)) + log(x**S(2) + S(2))/S(2) + S(5)*sqrt(S(2))*atan(sqrt(S(2))*x/S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) - S(4)*x**S(2) + S(70)*x + S(-35))/((x**S(2) - S(10)*x + S(26))*(x**S(2) - S(2)*x + S(17))), x), x, S(1003)*log(x**S(2) - S(10)*x + S(26))/S(1025) + S(22)*log(x**S(2) - S(2)*x + S(17))/S(1025) - S(4607)*atan(x/S(4) + S(-1)/4)/S(4100) + S(15033)*atan(x + S(-5))/S(1025), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(2))/((x + S(-5))*(x + S(-3))*(x + S(4))), x), x, -S(11)*log(-x + S(3))/S(14) + S(3)*log(-x + S(5))/S(2) + S(2)*log(x + S(4))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/((x + S(-1))*(x**S(2) + S(2))), x), x, x**S(2)/S(2) + x + log(-x + S(1))/S(3) - S(2)*log(x**S(2) + S(2))/S(3) - S(2)*sqrt(S(2))*atan(sqrt(S(2))*x/S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(7)*x + S(-1))/(x**S(3) + x**S(2) - x + S(-1)), x), x, S(2)*log(-x + S(1)) - S(3)/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(1))/(x**S(3) - S(3)*x**S(2) + S(3)*x + S(-1)), x), x, -(S(2)*x + S(1))**S(2)/(S(6)*(-x + S(1))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(7)*x**S(2) - S(5)*x + S(5))/((x + S(-1))**S(2)*(x + S(1))**S(3)), x), x, -S(2)/(x + S(1))**S(2) + S(1)/(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) + S(3)*x + S(1))/(x**S(3) + S(2)*x**S(2) + S(2)*x + S(1)), x), x, log(x + S(1)) + log(x**S(2) + x + S(1)) - S(2)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(2)*x + S(-1))/(S(2)*x**S(3) + S(3)*x**S(2) - S(2)*x), x), x, log(x)/S(2) + log(-S(2)*x + S(1))/S(10) - log(x + S(2))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - S(2)*x**S(2) + S(4)*x + S(1))/(x**S(3) - x**S(2) - x + S(1)), x), x, x**S(2)/S(2) + x - S(2)*atanh(x) + S(2)/(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) - x + S(4))/(x**S(3) + S(4)*x), x), x, log(x) + log(x**S(2) + S(4))/S(2) - atan(x/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) + S(1))/(x*(x + S(-1))*(x**S(2) + S(1))**S(3)*(x**S(2) + x + S(1))), x), x, S(3)*x/(S(16)*(x**S(2) + S(1))) - (-S(3)*x/S(8) + S(3)/8)/(x**S(2) + S(1)) + (x/S(8) + S(1)/8)/(x**S(2) + S(1))**S(2) - log(x) + log(-x + S(1))/S(8) + S(15)*log(x**S(2) + S(1))/S(16) - log(x**S(2) + x + S(1))/S(2) + S(7)*atan(x)/S(16) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x**S(2) + S(1))**S(2), x), x, (-x/S(2) + S(1))/(x**S(2) + S(1)) - log(x**S(2) + S(1))/S(2) + S(3)*atan(x)/S(2), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x**S(2) + S(1))**S(2), x), x, -x*(S(2)*x + S(1))/(S(2)*(x**S(2) + S(1))) - log(x**S(2) + S(1))/S(2) + S(3)*atan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x*(x**S(2) + S(1))**S(2)), x), x, (-x + S(-1)/2)/(x**S(2) + S(1)) + log(x) - log(x**S(2) + S(1))/S(2) - S(2)*atan(x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x*(x**S(2) + S(1))**S(2)), x), x, x*(x/S(2) + S(-1))/(x**S(2) + S(1)) + log(x) - log(x**S(2) + S(1))/S(2) - S(2)*atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + x**S(3) - x**S(2) - x + S(1))/(x**S(3) - x), x), x, x**S(2)/S(2) + x - log(x) + log(-x**S(2) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(4)*x**S(2) + S(2))/((x**S(2) + S(1))*(x**S(2) + S(2))), x), x, -log(x**S(2) + S(1))/S(2) + log(x**S(2) + S(2)) + S(6)*atan(x) - S(5)*sqrt(S(2))*atan(sqrt(S(2))*x/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + x**S(2) + S(1))/((x**S(2) + S(1))*(x**S(2) + S(4))**S(2)), x), x, -S(13)*x/(S(24)*(x**S(2) + S(4))) + S(25)*atan(x/S(2))/S(144) + atan(x)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) + S(1))/(x**S(4) + x**S(3) + S(2)*x**S(2)), x), x, -log(x)/S(4) + S(5)*log(x**S(2) + x + S(2))/S(8) + sqrt(S(7))*atan(sqrt(S(7))*(S(2)*x + S(1))/S(7))/S(28) - S(1)/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) - S(12)*x + S(1))/(x**S(2) + x + S(-12)), x), x, x**S(2)/S(2) - S(2)*atanh(S(2)*x/S(7) + S(1)/7)/S(7), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(3) + x**S(2) - S(12)*x + S(1))/(x**S(2) + x + S(-12)), x), x, x**S(2)/S(2) + log(-x + S(3))/S(7) - log(x + S(4))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(6)*x**S(2) + S(5)*x + S(-3))/(x**S(3) + S(2)*x**S(2) - S(3)*x), x), x, log(x) + S(2)*log(-x + S(1)) + S(3)*log(x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(3)*x + S(-2))/(x**S(3) + S(2)*x**S(2)), x), x, S(2)*log(x) + S(3)*log(x + S(2)) + S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(4)*x**S(2) - S(2)*x + S(18))/(x**S(3) + S(4)*x**S(2) + x + S(-6)), x), x, log(-x + S(1)) - S(2)*log(x + S(2)) - S(3)*log(x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(2)*x**S(2) + x + S(1))/(x**S(4) + S(5)*x**S(2) + S(4)), x), x, log(x**S(2) + S(4))/S(2) - S(3)*atan(x/S(2))/S(2) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(3) - S(27)*x**S(2) + S(5)*x + S(-32))/(S(30)*x**S(5) - S(13)*x**S(4) + S(50)*x**S(3) - S(286)*x**S(2) - S(299)*x + S(-70)), x), x, -S(3146)*log(-S(3)*x + S(7))/S(80155) - S(334)*log(S(2)*x + S(1))/S(323) + S(4822)*log(S(5)*x + S(2))/S(4879) + S(11049)*log(x**S(2) + x + S(5))/S(260015) + S(3988)*sqrt(S(19))*atan(sqrt(S(19))*(S(2)*x + S(1))/S(19))/S(260015), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(12)*x**S(5) - S(7)*x**S(3) - S(13)*x**S(2) + S(8))/(S(100)*x**S(6) - S(80)*x**S(5) + S(116)*x**S(4) - S(80)*x**S(3) + S(41)*x**S(2) - S(20)*x + S(4)), x), x, (-S(251)*x/S(726) + S(-313)/1452)/(S(2)*x**S(2) + S(1)) - S(59096)*log(-S(5)*x + S(2))/S(99825) + S(2843)*log(S(2)*x**S(2) + S(1))/S(7986) + S(503)*sqrt(S(2))*atan(sqrt(S(2))*x)/S(15972) + S(5828)/(S(9075)*(-S(5)*x + S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((S(12)*x**S(5) - S(7)*x**S(3) - S(13)*x**S(2) + S(8))/(S(100)*x**S(6) - S(80)*x**S(5) + S(116)*x**S(4) - S(80)*x**S(3) + S(41)*x**S(2) - S(20)*x + S(4)), x), x, (-S(251)*x/S(726) + S(-313)/1452)/(S(2)*x**S(2) + S(1)) - S(59096)*log(-S(5)*x + S(2))/S(99825) + S(2843)*log(S(2)*x**S(2) + S(1))/S(7986) + S(503)*sqrt(S(2))*atan(sqrt(S(2))*x)/S(15972) + S(5828)/(S(9075)*(-S(5)*x + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(9))/(x**S(2)*(x**S(2) + S(9))), x), x, x - S(10)*atan(x/S(3))/S(3) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(2)*x)/(x**S(2) + S(1)), x), x, x**S(3)/S(3) - x + log(x**S(2) + S(1)) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - x)/((x + S(-1))**S(2)*(x**S(2) + S(1))), x), x, log(-x + S(1)) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + S(5)*x + S(2))/(x**S(2) + x + S(1)), x), x, x**S(2) + x + log(x**S(2) + x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(3) - S(5)*x**S(2) - S(4)*x + S(3))/(x**S(3)*(x**S(2) + x + S(-1))), x), x, S(3)*log(x) - (sqrt(S(5)) + S(15))*log(S(2)*x + S(1) + sqrt(S(5)))/S(10) - (-sqrt(S(5)) + S(15))*log(S(2)*x - sqrt(S(5)) + S(1))/S(10) - S(1)/x + S(3)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(5)*x**S(2) + S(8)*x + S(4))/(x**S(2) + S(2)*x + S(2))**S(2), x), x, log(x**S(2) + S(2)*x + S(2)) - atan(x + S(1)) - S(1)/(x**S(2) + S(2)*x + S(2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((S(2)*x**S(3) + S(5)*x**S(2) + S(8)*x + S(4))/(x**S(2) + S(2)*x + S(2))**S(2), x), x, x*(x + S(2))/(S(2)*(x**S(2) + S(2)*x + S(2))) + log(x**S(2) + S(2)*x + S(2)) - atan(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(x + S(-1))**S(4)/(x**S(2) + S(1)), x), x, x**S(7)/S(7) - S(2)*x**S(6)/S(3) + x**S(5) - S(4)*x**S(3)/S(3) + S(4)*x - S(4)*atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(2) - S(20)*x)/(x**S(4) - S(10)*x**S(2) + S(9)), x), x, log(-x + S(1)) - log(-x + S(3))/S(2) + S(3)*log(x + S(1))/S(2) - S(2)*log(x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(3) + x + S(-1))/(x**S(2)*(x + S(-1))*(x**S(2) + S(1))), x), x, S(2)*log(-x + S(1)) - log(x**S(2) + S(1)) + atan(x) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - S(4)*x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x**S(2) + S(1))**S(3), x), x, atan(x) - (S(4)*x**S(2) + S(3))**S(2)/(S(4)*(x**S(2) + S(1))**S(2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(4) - S(4)*x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x**S(2) + S(1))**S(3), x), x, x**S(2)/(S(4)*(x**S(2) + S(1))**S(2)) + atan(x) + S(7)/(S(4)*(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - S(4)*x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x**S(6) + S(3)*x**S(4) + S(3)*x**S(2) + S(1)), x), x, atan(x) + S(2)/(x**S(2) + S(1)) - S(1)/(S(4)*(x**S(2) + S(1))**S(2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(4) - S(4)*x**S(3) + S(2)*x**S(2) - S(3)*x + S(1))/(x**S(6) + S(3)*x**S(4) + S(3)*x**S(2) + S(1)), x), x, x**S(2)/(S(4)*(x**S(2) + S(1))**S(2)) + atan(x) + S(7)/(S(4)*(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(2)*x**S(2) + x + S(1))/(x**S(4) + x**S(3) + x**S(2)), x), x, log(x**S(2) + x + S(1)) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x**S(2) - S(4)*x + S(4))*(x**S(2) - S(4)*x + S(5))), x), x, -atan(x + S(-2)) + S(1)/(-x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + x + S(-3))/(x**S(2)*(x + S(-3))), x), x, log(-x + S(3)) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(2) + x + S(1))/(S(4)*x**S(3) + x), x), x, log(x) + atan(S(2)*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) - x + S(1))/(x**S(3) - x**S(2)), x), x, S(3)*log(-x + S(1)) + S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(3)*x + S(4))/(x**S(2) + x), x), x, x + S(4)*log(x) - S(2)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) + x + S(4))/(x**S(3) + x), x), x, S(4)*log(x) - log(x**S(2) + S(1))/S(2) + atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(2) - S(4)*x + S(7))/((S(4)*x + S(1))*(x**S(2) + S(1))), x), x, S(2)*log(S(4)*x + S(1)) - atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((x + S(-1))*(x**S(2) + S(2)*x + S(1))), x), x, log(-x + S(1))/S(4) + S(3)*log(x + S(1))/S(4) + S(1)/(S(2)*(x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(3)*x + S(-4))/((S(2)*x + S(-1))**S(2)*(S(2)*x + S(3))), x), x, S(41)*log(-S(2)*x + S(1))/S(128) - S(25)*log(S(2)*x + S(3))/S(128) - S(9)/(S(32)*(-S(2)*x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) - S(4)*x + S(5))/((x + S(-1))*(x**S(2) + S(1))), x), x, S(2)*log(-x + S(1)) + log(x**S(2) + S(1))/S(2) - S(3)*atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(2)*x + S(-1))/((x + S(-1))**S(2)*(x**S(2) + S(1))), x), x, log(-x + S(1)) - log(x**S(2) + S(1))/S(2) + atan(x) + S(1)/(x + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(5))/((x**S(2) - S(6)*x + S(10))*(x**S(2) - x + S(1)/2)), x), x, S(56)*log(x**S(2) - S(6)*x + S(10))/S(221) + S(109)*log(S(2)*x**S(2) - S(2)*x + S(1))/S(442) + S(1026)*atan(x + S(-3))/S(221) + S(261)*atan(S(2)*x + S(-1))/S(221), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(3)*x + S(4))/((x + S(-3))*(x + S(-2))*(x + S(-1))), x), x, S(4)*log(-x + S(1)) - S(14)*log(-x + S(2)) + S(11)*log(-x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(16)*x + S(1))/((x + S(5))**S(2)*(S(2)*x + S(-3))*(x**S(2) + x + S(1))), x), x, S(200)*log(-S(2)*x + S(3))/S(3211) + S(2731)*log(x + S(5))/S(24843) - S(481)*log(x**S(2) + x + S(1))/S(5586) + S(451)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(8379) - S(79)/(S(273)*(x + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(-1))/(x**S(2) + x + S(1)), x), x, x**S(2)/S(2) - x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(-3))/(x**S(2) - S(6)*x + S(-7)), x), x, x**S(2)/S(2) + S(6)*x + S(85)*log(-x + S(7))/S(2) + log(x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(1))/(x**S(2) + S(4)*x + S(13))**S(2), x), x, (S(47)*x/S(18) + S(67)/18)/(x**S(2) + S(4)*x + S(13)) + log(x**S(2) + S(4)*x + S(13))/S(2) - S(61)*atan(x/S(3) + S(2)/3)/S(54), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(5) - S(10)*x**S(4) + S(21)*x**S(3) - S(42)*x**S(2) + S(36)*x + S(-32))/(x*(x**S(2) + S(1))*(x**S(2) + S(4))**S(2)), x), x, -S(2)*log(x) + log(x**S(2) + S(4)) + atan(x/S(2))/S(2) + S(2)*atan(x) + S(1)/(x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(9) + S(7)*x**S(5) + x**S(4) + S(-1))/(x**S(8) + S(6)*x**S(4) + S(-7)), x), x, x**S(2)/S(2) - sqrt(S(2))*S(7)**(S(1)/4)*log(x**S(2) - sqrt(S(2))*S(7)**(S(1)/4)*x + sqrt(S(7)))/S(56) + sqrt(S(2))*S(7)**(S(1)/4)*log(x**S(2) + sqrt(S(2))*S(7)**(S(1)/4)*x + sqrt(S(7)))/S(56) + sqrt(S(2))*S(7)**(S(1)/4)*atan(sqrt(S(2))*S(7)**(S(3)/4)*x/S(7) + S(-1))/S(28) + sqrt(S(2))*S(7)**(S(1)/4)*atan(sqrt(S(2))*S(7)**(S(3)/4)*x/S(7) + S(1))/S(28) - atanh(x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(6) + x**S(3) + S(1))/(x**S(5) + x), x), x, x**S(2)/S(2) + log(x) - log(x**S(4) + S(1))/S(4) + sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(8) - sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(8) - atan(x**S(2))/S(2) + sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(4) + sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(2) - x), x), x, x - log(x) + S(2)*log(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(1))/(x**S(3) - x), x), x, x - log(x) + log(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(1))/(x**S(3) - x**S(2)), x), x, x - log(x) + S(2)*log(-x + S(1)) + S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(5) + S(-1))/(x**S(3) - x), x), x, x**S(3)/S(3) + x + log(x) - log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(1))/(x**S(5) + x**S(3)), x), x, -log(x) + log(x**S(2) + S(1)) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(3) + S(2)*x**S(2) + x), x), x, log(x) + S(2)/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(5) + S(1))/(x**S(3) - S(3)*x**S(2) - S(10)*x), x), x, x**S(3)/S(3) + S(3)*x**S(2)/S(2) + S(19)*x - log(x)/S(10) + S(3126)*log(-x + S(5))/S(35) - S(31)*log(x + S(2))/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) - S(5)*x + S(15))/((x**S(2) + S(5))*(x**S(2) + S(2)*x + S(3))), x), x, log(x**S(2) + S(2)*x + S(3))/S(2) + S(5)*sqrt(S(2))*atan(sqrt(S(2))*(x + S(1))/S(2))/S(2) - sqrt(S(5))*atan(sqrt(S(5))*x/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x**S(2) + S(1))*(S(10)*x/(x**S(2) + S(1)) + S(3))), x), x, -log(x + S(3))/S(8) + log(S(3)*x + S(1))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(S(15)*x + S(13) + S(2)/x), x), x, x**S(3)/S(45) - S(13)*x**S(2)/S(450) + S(139)*x/S(3375) - S(16)*log(S(3)*x + S(2))/S(567) + log(S(5)*x + S(1))/S(4375), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(S(15)*x + S(13) + S(2)/x), x), x, x**S(2)/S(30) - S(13)*x/S(225) + S(8)*log(S(3)*x + S(2))/S(189) - log(S(5)*x + S(1))/S(875), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(S(15)*x + S(13) + S(2)/x), x), x, x/S(15) - S(4)*log(S(3)*x + S(2))/S(63) + log(S(5)*x + S(1))/S(175), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(15)*x + S(13) + S(2)/x), x), x, S(2)*log(S(3)*x + S(2))/S(21) - log(S(5)*x + S(1))/S(35), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(S(15)*x + S(13) + S(2)/x)), x), x, -log(S(3)*x + S(2))/S(7) + log(S(5)*x + S(1))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(S(15)*x + S(13) + S(2)/x)), x), x, log(x)/S(2) + S(3)*log(S(3)*x + S(2))/S(14) - S(5)*log(S(5)*x + S(1))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(S(15)*x + S(13) + S(2)/x)), x), x, -S(13)*log(x)/S(4) - S(9)*log(S(3)*x + S(2))/S(28) + S(25)*log(S(5)*x + S(1))/S(7) - S(1)/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(S(15)*x + S(13) + S(2)/x)), x), x, S(139)*log(x)/S(8) + S(27)*log(S(3)*x + S(2))/S(56) - S(125)*log(S(5)*x + S(1))/S(7) + S(13)/(S(4)*x) - S(1)/(S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(S(15)*x + S(13) + S(2)/x)), x), x, -S(1417)*log(x)/S(16) - S(81)*log(S(3)*x + S(2))/S(112) + S(625)*log(S(5)*x + S(1))/S(7) - S(139)/(S(8)*x) + S(13)/(S(8)*x**S(2)) - S(1)/(S(6)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(a + b*(-x**S(2) + S(1))**S(4)), x), x, -atanh(b**(S(1)/8)*x/sqrt(b**(S(1)/4) + I*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(b**(S(1)/4) + I*(-a)**(S(1)/4))) + atanh(b**(S(1)/8)*x/sqrt(b**(S(1)/4) + (-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(b**(S(1)/4) + (-a)**(S(1)/4))) + atan(b**(S(1)/8)*x/sqrt(-b**(S(1)/4) + I*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(-b**(S(1)/4) + I*(-a)**(S(1)/4))) - atan(b**(S(1)/8)*x/sqrt(-b**(S(1)/4) + (-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(-b**(S(1)/4) + (-a)**(S(1)/4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(a + b*(x**S(2) + S(-1))**S(4)), x), x, -atanh(b**(S(1)/8)*x/sqrt(b**(S(1)/4) + I*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(b**(S(1)/4) + I*(-a)**(S(1)/4))) + atanh(b**(S(1)/8)*x/sqrt(b**(S(1)/4) + (-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(b**(S(1)/4) + (-a)**(S(1)/4))) + atan(b**(S(1)/8)*x/sqrt(-b**(S(1)/4) + I*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(-b**(S(1)/4) + I*(-a)**(S(1)/4))) - atan(b**(S(1)/8)*x/sqrt(-b**(S(1)/4) + (-a)**(S(1)/4)))/(S(4)*b**(S(3)/8)*sqrt(-a)*sqrt(-b**(S(1)/4) + (-a)**(S(1)/4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(5) + S(-1))/(x**S(5) + x + S(1))**S(2), x), x, -x/(x**S(5) + x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-a*d - S(2)*a*e*x - S(3)*a*f*x**S(2) + b*c - b*e*x**S(2) - S(2)*b*f*x**S(3))/(c + d*x + e*x**S(2) + f*x**S(3))**S(2), x), x, a/(c + d*x + e*x**S(2) + f*x**S(3)) + b*x/(c + d*x + e*x**S(2) + f*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(39)*x**S(8) + S(26)*x**S(6) + S(24)*x**S(5) + S(174)*x**S(4) - S(18)*x**S(2) - S(40)*x + S(9))/(x**S(4) + S(2)*x**S(2) + S(3))**S(3), x), x, S(13)*x/(x**S(4) + S(2)*x**S(2) + S(3)) + (-S(26)*x**S(3) - S(4)*x**S(2) - S(36)*x + S(2))/(x**S(4) + S(2)*x**S(2) + S(3))**S(2), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-S(39)*x**S(8) + S(26)*x**S(6) + S(24)*x**S(5) + S(174)*x**S(4) - S(18)*x**S(2) - S(40)*x + S(9))/(x**S(4) + S(2)*x**S(2) + S(3))**S(3), x), x, x*(-S(2)*x**S(3) - S(4)*x + S(117))/(S(9)*(x**S(4) + S(2)*x**S(2) + S(3))) - S(2)*x*(x**S(3) + S(39)*x**S(2) + S(8)*x + S(54))/(S(3)*(x**S(4) + S(2)*x**S(2) + S(3))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(30)*x**S(9) - S(8)*x**S(7) - S(15)*x**S(6) - S(140)*x**S(5) + S(34)*x**S(4) - S(12)*x**S(3) - S(5)*x**S(2) + S(36)*x + S(-15))/(x**S(4) + x + S(3))**S(4), x), x, -S(5)*x**S(6)/(x**S(4) + x + S(3))**S(3) + x**S(4)/(x**S(4) + x + S(3))**S(3) + S(5)*x**S(2)/(x**S(4) + x + S(3))**S(3) - S(3)*x/(x**S(4) + x + S(3))**S(3) + S(2)/(x**S(4) + x + S(3))**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(30)*x/(x**S(4) + x + S(3))**S(2) + (-S(8)*x**S(3) - S(75)*x**S(2) - S(320)*x + S(42))/(x**S(4) + x + S(3))**S(3) + (S(57)*x**S(3) + S(360)*x**S(2) + S(684)*x + S(-141))/(x**S(4) + x + S(3))**S(4), x), x, (-S(5)*x**S(6) + x**S(4) + S(5)*x**S(2) - S(3)*x + S(2))/(x**S(4) + x + S(3))**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-(S(12)*x**S(3) + S(3))*(-S(5)*x**S(6) + x**S(4) + S(5)*x**S(2) - S(3)*x + S(2))/(x**S(4) + x + S(3))**S(4) + (-S(30)*x**S(5) + S(4)*x**S(3) + S(10)*x + S(-3))/(x**S(4) + x + S(3))**S(3), x), x, (-S(5)*x**S(6) + x**S(4) + S(5)*x**S(2) - S(3)*x + S(2))/(x**S(4) + x + S(3))**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(-1))/(x**S(2) - x + S(1)), x), x, log(x**S(2) - x + S(1))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-1))/(x**S(3) + S(1)), x), x, log(x**S(2) - x + S(1))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x + S(-4))/(x**S(2) - S(2)*x + S(4)), x), x, S(3)*log(x**S(2) - S(2)*x + S(4))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) + S(2)*x + S(-8))/(x**S(3) + S(8)), x), x, S(3)*log(x**S(2) - S(2)*x + S(4))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x + S(4))/(x**S(2)*(x**S(2) + S(1))), x), x, S(4)*log(x) - S(2)*log(x**S(2) + S(1)) - S(4)*atan(x) - S(4)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x + S(24))/(x*(x**S(2) + S(-4))), x), x, -S(6)*log(x) + S(5)*log(-x + S(2)) + log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-1))/(x**S(3) - S(2)*x), x), x, log(x)/S(2) + log(-x**S(2) + S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(3) + S(3)*x), x), x, log(x)/S(3) + log(x**S(2) + S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + S(3)*b*x**S(2))/(a*x + b*x**S(3)), x), x, log(x) + log(a + b*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x + S(-2))/(x**S(3) - x), x), x, S(2)*log(x) + log(-x + S(1)) - S(3)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(4))/(x**S(3) + S(4)*x), x), x, log(x) - log(x**S(2) + S(4))/S(2) + atan(x/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) - x)/(x**S(4) - x**S(2) + S(1)), x), x, log(x**S(4) - x**S(2) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(-3))/(x**S(3) + S(3)*x**S(2) + S(2)*x), x), x, -S(3)*log(x)/S(2) + S(4)*log(x + S(1)) - S(5)*log(x + S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x + S(2))/(x**S(4) + S(2)*x**S(3) + x**S(2)), x), x, -S(2)/(x*(x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(1))/(x**S(3) + x**S(2) - S(6)*x), x), x, -log(x)/S(6) + S(3)*log(-x + S(2))/S(10) - S(2)*log(x + S(3))/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(4)*x**S(2))/(x**S(3) + x), x), x, x + S(2)*log(x**S(2) + S(1)) - atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + x)/(x**S(4) + x**S(2))**S(3), x), x, -S(1)/(S(4)*x**S(4)*(x**S(2) + S(1))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3))/(c*x**S(2) + d*x**S(3)), x), x, b*x/d - (-a*d + b*c)*log(c + d*x)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + x)/(x**S(3) - x**S(2) - S(2)*x), x), x, log(-x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(5)*x**S(2) + S(1))/(x**S(3)*(x**S(2) + S(1))), x), x, -S(6)*log(x) + S(3)*log(x**S(2) + S(1)) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)*x/((x + S(-1))*(x**S(2) + S(5))), x), x, log(-x + S(1))/S(3) - log(x**S(2) + S(5))/S(6) + sqrt(S(5))*atan(sqrt(S(5))*x/S(5))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(2))/(x + S(2)), x), x, x**S(2)/S(2) - S(2)*x + S(6)*log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(-3))*(x**S(2) + S(4))), x), x, log(-x + S(3))/S(13) - log(x**S(2) + S(4))/S(26) - S(3)*atan(x/S(2))/S(26), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(6) + S(-2))/(x*(S(2)*x**S(6) + S(5))), x), x, -S(2)*log(x)/S(5) + S(19)*log(S(2)*x**S(6) + S(5))/S(60), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(3))/((x + S(-2))*(x + S(5))), x), x, log(-x + S(2)) + log(x + S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(4) + S(5)*x**S(2) + S(4)), x), x, x - S(8)*atan(x/S(2))/S(3) + atan(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(1))*(x + S(2))**S(2)*(x + S(3))**S(3)), x), x, log(x + S(1))/S(8) + S(2)*log(x + S(2)) - S(17)*log(x + S(3))/S(8) + S(5)/(S(4)*(x + S(3))) + S(1)/(S(4)*(x + S(3))**S(2)) + S(1)/(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(2) + S(-1)), x), x, log(-x**S(2) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-1))**(S(-2)), x), x, x/(S(2)*(-x**S(2) + S(1))) + atanh(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(2) + S(1))**S(2), x), x, -x/(S(2)*(x**S(2) + S(1))) + atan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(3)*x + S(2)), x), x, log(S(3)*x + S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a**S(2) + x**S(2)), x), x, atan(x/a)/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x**S(2)), x), x, atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2) - x + S(2)), x), x, -S(2)*sqrt(S(7))*atan(sqrt(S(7))*(-S(2)*x + S(1))/S(7))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(-x**S(2) + S(4))**S(2), x), x, x**S(7)/S(7) - S(8)*x**S(5)/S(5) + S(16)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(-x**S(3) + S(1))**S(2), x), x, x**S(8)/S(8) - S(2)*x**S(5)/S(5) + x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(5)*x**S(2) + S(-4))/x**S(2), x), x, x**S(2)/S(2) + S(5)*x + S(4)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(-1))/(S(3)*x**S(2) - S(4)*x + S(3)), x), x, log(S(3)*x**S(2) - S(4)*x + S(3))/S(6) + sqrt(S(5))*atan(sqrt(S(5))*(-S(3)*x + S(2))/S(5))/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(2))**S(2), x), x, x**S(7)/S(7) + x**S(4) + S(4)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-4))/(x + S(2)), x), x, x**S(2)/S(2) - S(2)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(2))*(x**S(2) + S(1))), x), x, log(x + S(2))/S(5) - log(x**S(2) + S(1))/S(10) + S(2)*atan(x)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(1))*(x**S(2) + S(1))), x), x, log(x + S(1))/S(2) - log(x**S(2) + S(1))/S(4) + atan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((x + S(1))*(x**S(2) + S(1))), x), x, -log(x + S(1))/S(2) + log(x**S(2) + S(1))/S(4) + atan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(2)*x)/(x + S(1))**S(2), x), x, (x + S(2))**S(2)/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-10))/(S(2)*x**S(4) + S(9)*x**S(2) + S(4)), x), x, atan(x/S(2)) - S(3)*sqrt(S(2))*atan(sqrt(S(2))*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x + S(31))/(S(3)*x**S(2) - S(4)*x + S(11)), x), x, S(5)*log(S(3)*x**S(2) - S(4)*x + S(11))/S(6) - S(103)*sqrt(S(29))*atan(sqrt(S(29))*(-S(3)*x + S(2))/S(29))/S(87), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**S(2) + S(-2))/x**S(4), x), x, log(x) - S(1)/x + S(2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x + S(1))/x**S(2), x), x, x**S(2)/S(2) + log(x) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-2))/(x*(x**S(2) + S(2))), x), x, -log(x) + log(x**S(2) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(-3))*(S(4)*x**S(2) + S(-7)), x), x, x**S(4) - S(4)*x**S(3) - S(7)*x**S(2)/S(2) + S(21)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(7)*x + S(-2))**S(3), x), x, (-S(7)*x + S(2))**S(4)/S(28), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(2) + S(-7))/(S(2)*x + S(3)), x), x, x**S(2) - S(3)*x + log(S(2)*x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(1))/(x**S(2)*(x + S(-1))), x), x, -S(2)*log(x) + S(2)*log(-x + S(1)) + S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) + S(4)*x**S(3) + S(4)*x**S(2)), x), x, atanh(x + S(1))/S(2) - S(1)/(S(4)*(x + S(2))) - S(1)/(S(4)*x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/(x**S(4) + S(4)*x**S(3) + S(4)*x**S(2)), x), x, -log(x)/S(4) + log(x + S(2))/S(4) - S(1)/(S(4)*(x + S(2))) - S(1)/(S(4)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x + S(1)), x), x, x**S(2)/S(2) - x + S(2)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(3)*x**S(2) + S(3)*x + S(-1))/x**S(2), x), x, x**S(2)/S(2) - S(3)*x + S(3)*log(x) + S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(3)/2 + sqrt(S(37))/S(2))*(x - sqrt(S(37))/S(2) + S(3)/2), x), x, x**S(3)/S(3) + S(3)*x**S(2)/S(2) - S(7)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(3)*x**S(2) + S(4))/(x + S(1))**S(4), x), x, S(2)*log(x + S(1)) + S(3)/(x + S(1)) - S(5)/(S(3)*(x + S(1))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((x + S(1))**S(2)*(x**S(2) + S(1))), x), x, atan(x)/S(2) + S(1)/(S(2)*(x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) - x**S(3) + S(3)*x**S(2) - S(2)*x + S(7))/(x + S(2)), x), x, x**S(4)/S(4) - x**S(3) + S(9)*x**S(2)/S(2) - S(20)*x + S(47)*log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(-1))/(x + S(-1)), x), x, x**S(3)/S(3) + x**S(2)/S(2) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(2))/((x + S(-1))**S(3)*(x**S(2) + S(1))), x), x, atan(x) + S(1)/(x + S(-1)) - S(1)/(-x + S(1))**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(b*x + c*(d + e*x)**S(2)), x), x, -S(2)*atanh((b + S(2)*c*d*e + S(2)*c*e**S(2)*x)/(sqrt(b)*sqrt(b + S(4)*c*d*e)))/(sqrt(b)*sqrt(b + S(4)*c*d*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x + c*(d + e*x)**S(2)), x), x, -S(2)*atanh((b + S(2)*c*d*e + S(2)*c*e**S(2)*x)/sqrt(-S(4)*a*c*e**S(2) + b**S(2) + S(4)*b*c*d*e))/sqrt(-S(4)*a*c*e**S(2) + b**S(2) + S(4)*b*c*d*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((x**S(2) + S(-1))**S(2) + S(1)), x), x, log(x**S(2) - x*sqrt(S(2) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(4)*sqrt(S(2) + S(2)*sqrt(S(2)))) - log(x**S(2) + x*sqrt(S(2) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(4)*sqrt(S(2) + S(2)*sqrt(S(2)))) - sqrt(S(1)/2 + sqrt(S(2))/S(2))*atan((-S(2)*x + sqrt(S(2) + S(2)*sqrt(S(2))))/sqrt(S(-2) + S(2)*sqrt(S(2))))/S(2) + sqrt(S(1)/2 + sqrt(S(2))/S(2))*atan((S(2)*x + sqrt(S(2) + S(2)*sqrt(S(2))))/sqrt(S(-2) + S(2)*sqrt(S(2))))/S(2), expand=True, _diff=True, _numerical=True) def test_2(): assert rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), x), x, b*x**S(6)*sqrt(-c + d*x)*sqrt(c + d*x)/(S(7)*d**S(2)) + S(8)*c**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(7)*a*d**S(2) + S(6)*b*c**S(2))/(S(105)*d**S(8)) + S(4)*c**S(2)*x**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(7)*a*d**S(2) + S(6)*b*c**S(2))/(S(105)*d**S(6)) + x**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(7)*a*d**S(2) + S(6)*b*c**S(2))/(S(35)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), x), x, b*x**S(5)*sqrt(-c + d*x)*sqrt(c + d*x)/(S(6)*d**S(2)) + c**S(4)*(S(6)*a*d**S(2) + S(5)*b*c**S(2))*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/(S(8)*d**S(7)) + c**S(2)*x*sqrt(-c + d*x)*sqrt(c + d*x)*(S(6)*a*d**S(2) + S(5)*b*c**S(2))/(S(16)*d**S(6)) + x**S(3)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(6)*a*d**S(2) + S(5)*b*c**S(2))/(S(24)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), x), x, b*x**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)/(S(5)*d**S(2)) + S(2)*c**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(5)*a*d**S(2) + S(4)*b*c**S(2))/(S(15)*d**S(6)) + x**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(5)*a*d**S(2) + S(4)*b*c**S(2))/(S(15)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), x), x, b*x**S(3)*sqrt(-c + d*x)*sqrt(c + d*x)/(S(4)*d**S(2)) + c**S(2)*(S(4)*a*d**S(2) + S(3)*b*c**S(2))*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/(S(4)*d**S(5)) + x*sqrt(-c + d*x)*sqrt(c + d*x)*(S(4)*a*d**S(2) + S(3)*b*c**S(2))/(S(8)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), x), x, b*x**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)/(S(3)*d**S(2)) + sqrt(-c + d*x)*sqrt(c + d*x)*(S(3)*a*d**S(2) + S(2)*b*c**S(2))/(S(3)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), x), x, b*x*sqrt(-c + d*x)*sqrt(c + d*x)/(S(2)*d**S(2)) + (S(2)*a*d**S(2) + b*c**S(2))*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/d**S(3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), x), x, S(2)*a*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/d + b*c**S(2)*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/d**S(3) + b*x*sqrt(-c + d*x)*sqrt(c + d*x)/(S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x*sqrt(-c + d*x)*sqrt(c + d*x)), x), x, a*atan(sqrt(-c + d*x)*sqrt(c + d*x)/c)/c + b*sqrt(-c + d*x)*sqrt(c + d*x)/d**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)), x), x, a*sqrt(-c + d*x)*sqrt(c + d*x)/(c**S(2)*x) + S(2)*b*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(3)*sqrt(-c + d*x)*sqrt(c + d*x)), x), x, a*sqrt(-c + d*x)*sqrt(c + d*x)/(S(2)*c**S(2)*x**S(2)) + (a*d**S(2) + S(2)*b*c**S(2))*atan(sqrt(-c + d*x)*sqrt(c + d*x)/c)/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)), x), x, a*sqrt(-c + d*x)*sqrt(c + d*x)/(S(3)*c**S(2)*x**S(3)) + sqrt(-c + d*x)*sqrt(c + d*x)*(S(2)*a*d**S(2) + S(3)*b*c**S(2))/(S(3)*c**S(4)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(5)*sqrt(-c + d*x)*sqrt(c + d*x)), x), x, a*sqrt(-c + d*x)*sqrt(c + d*x)/(S(4)*c**S(2)*x**S(4)) + sqrt(-c + d*x)*sqrt(c + d*x)*(S(3)*a*d**S(2) + S(4)*b*c**S(2))/(S(8)*c**S(4)*x**S(2)) + d**S(2)*(S(3)*a*d**S(2) + S(4)*b*c**S(2))*atan(sqrt(-c + d*x)*sqrt(c + d*x)/c)/(S(8)*c**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(6)*sqrt(-c + d*x)*sqrt(c + d*x)), x), x, a*sqrt(-c + d*x)*sqrt(c + d*x)/(S(5)*c**S(2)*x**S(5)) + sqrt(-c + d*x)*sqrt(c + d*x)*(S(4)*a*d**S(2) + S(5)*b*c**S(2))/(S(15)*c**S(4)*x**S(3)) + S(2)*d**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(4)*a*d**S(2) + S(5)*b*c**S(2))/(S(15)*c**S(6)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(2))/((-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, b*x**S(6)/(S(5)*d**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)) + S(8)*c**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(5)*a*d**S(2) + S(6)*b*c**S(2))/(S(15)*d**S(8)) - x**S(4)*(S(5)*a*d**S(2) + S(6)*b*c**S(2))/(S(5)*d**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)) + x**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)*(S(20)*a*d**S(2) + S(24)*b*c**S(2))/(S(15)*d**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2))/((-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, b*x**S(5)/(S(4)*d**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)) + S(3)*c**S(2)*(S(4)*a*d**S(2) + S(5)*b*c**S(2))*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/(S(4)*d**S(7)) - x**S(3)*(S(4)*a*d**S(2) + S(5)*b*c**S(2))/(S(4)*d**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)) + x*sqrt(-c + d*x)*sqrt(c + d*x)*(S(12)*a*d**S(2) + S(15)*b*c**S(2))/(S(8)*d**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(2))/((-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, b*x**S(4)/(S(3)*d**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)) - x**S(2)*(S(3)*a*d**S(2) + S(4)*b*c**S(2))/(S(3)*d**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)) + sqrt(-c + d*x)*sqrt(c + d*x)*(S(6)*a*d**S(2) + S(8)*b*c**S(2))/(S(3)*d**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2))/((-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, b*x**S(3)/(S(2)*d**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)) - c*(S(2)*a*d**S(2) + S(3)*b*c**S(2))/(S(2)*d**S(5)*sqrt(-c + d*x)*sqrt(c + d*x)) - sqrt(-c + d*x)*(S(2)*a*d**S(2) + S(3)*b*c**S(2))/(S(2)*d**S(5)*sqrt(c + d*x)) + (S(2)*a*d**S(2) + S(3)*b*c**S(2))*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/d**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2))/((-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, -x**S(2)*(a/c**S(2) + b/d**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)) + sqrt(-c + d*x)*sqrt(c + d*x)*(a*d**S(2) + S(2)*b*c**S(2))/(c**S(2)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/((-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, -a*x/(c**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)) - b*c/(d**S(3)*sqrt(-c + d*x)*sqrt(c + d*x)) - b*sqrt(-c + d*x)/(d**S(3)*sqrt(c + d*x)) + S(2)*b*atanh(sqrt(-c + d*x)/sqrt(c + d*x))/d**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x*(-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, -a*atan(sqrt(-c + d*x)*sqrt(c + d*x)/c)/c**S(3) - (a/c**S(2) + b/d**S(2))/(sqrt(-c + d*x)*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(2)*(-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, a/(c**S(2)*x*sqrt(-c + d*x)*sqrt(c + d*x)) - x*(S(2)*a*d**S(2) + b*c**S(2))/(c**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(3)*(-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, a/(S(2)*c**S(2)*x**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)) - (S(3)*a*d**S(2) + S(2)*b*c**S(2))/(S(2)*c**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)) - (S(3)*a*d**S(2) + S(2)*b*c**S(2))*atan(sqrt(-c + d*x)*sqrt(c + d*x)/c)/(S(2)*c**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(4)*(-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, a/(S(3)*c**S(2)*x**S(3)*sqrt(-c + d*x)*sqrt(c + d*x)) + (S(4)*a*d**S(2) + S(3)*b*c**S(2))/(S(3)*c**S(4)*x*sqrt(-c + d*x)*sqrt(c + d*x)) - S(2)*d**S(2)*x*(S(4)*a*d**S(2) + S(3)*b*c**S(2))/(S(3)*c**S(6)*sqrt(-c + d*x)*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(5)*(-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, a/(S(4)*c**S(2)*x**S(4)*sqrt(-c + d*x)*sqrt(c + d*x)) + (S(5)*a*d**S(2) + S(4)*b*c**S(2))/(S(8)*c**S(4)*x**S(2)*sqrt(-c + d*x)*sqrt(c + d*x)) - S(3)*d**S(2)*(S(5)*a*d**S(2) + S(4)*b*c**S(2))/(S(8)*c**S(6)*sqrt(-c + d*x)*sqrt(c + d*x)) - S(3)*d**S(2)*(S(5)*a*d**S(2) + S(4)*b*c**S(2))*atan(sqrt(-c + d*x)*sqrt(c + d*x)/c)/(S(8)*c**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(6)*(-c + d*x)**(S(3)/2)*(c + d*x)**(S(3)/2)), x), x, a/(S(5)*c**S(2)*x**S(5)*sqrt(-c + d*x)*sqrt(c + d*x)) + (S(6)*a*d**S(2) + S(5)*b*c**S(2))/(S(15)*c**S(4)*x**S(3)*sqrt(-c + d*x)*sqrt(c + d*x)) + S(4)*d**S(2)*(S(6)*a*d**S(2) + S(5)*b*c**S(2))/(S(15)*c**S(6)*x*sqrt(-c + d*x)*sqrt(c + d*x)) - S(8)*d**S(4)*x*(S(6)*a*d**S(2) + S(5)*b*c**S(2))/(S(15)*c**S(8)*sqrt(-c + d*x)*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c**S(2)*x**S(2) + S(1))/(x*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x, sqrt(c*x + S(-1))*sqrt(c*x + S(1)) + atan(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**n*(c + d*x**S(3)), x), x, S(10)*a**S(2)*d*(a + b*x)**(n + S(4))/(b**S(6)*(n + S(4))) + a**S(2)*(a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)/(b**S(6)*(n + S(1))) - S(5)*a*d*(a + b*x)**(n + S(5))/(b**S(6)*(n + S(5))) - a*(a + b*x)**(n + S(2))*(-S(5)*a**S(3)*d + S(2)*b**S(3)*c)/(b**S(6)*(n + S(2))) + d*(a + b*x)**(n + S(6))/(b**S(6)*(n + S(6))) + (a + b*x)**(n + S(3))*(-S(10)*a**S(3)*d + b**S(3)*c)/(b**S(6)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**n*(c + d*x**S(3)), x), x, S(6)*a**S(2)*d*(a + b*x)**(n + S(3))/(b**S(5)*(n + S(3))) - S(4)*a*d*(a + b*x)**(n + S(4))/(b**S(5)*(n + S(4))) - a*(a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)/(b**S(5)*(n + S(1))) + d*(a + b*x)**(n + S(5))/(b**S(5)*(n + S(5))) + (a + b*x)**(n + S(2))*(-S(4)*a**S(3)*d + b**S(3)*c)/(b**S(5)*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n*(c + d*x**S(3)), x), x, S(3)*a**S(2)*d*(a + b*x)**(n + S(2))/(b**S(4)*(n + S(2))) - S(3)*a*d*(a + b*x)**(n + S(3))/(b**S(4)*(n + S(3))) + d*(a + b*x)**(n + S(4))/(b**S(4)*(n + S(4))) + (a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)/(b**S(4)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n*(c + d*x**S(3))/x, x), x, a**S(2)*d*(a + b*x)**(n + S(1))/(b**S(3)*(n + S(1))) - S(2)*a*d*(a + b*x)**(n + S(2))/(b**S(3)*(n + S(2))) + d*(a + b*x)**(n + S(3))/(b**S(3)*(n + S(3))) - c*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**n*(c + d*x**S(3))**S(2), x), x, S(28)*a**S(2)*d**S(2)*(a + b*x)**(n + S(7))/(b**S(9)*(n + S(7))) + S(4)*a**S(2)*d*(a + b*x)**(n + S(4))*(-S(14)*a**S(3)*d + S(5)*b**S(3)*c)/(b**S(9)*(n + S(4))) + a**S(2)*(a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)**S(2)/(b**S(9)*(n + S(1))) - S(8)*a*d**S(2)*(a + b*x)**(n + S(8))/(b**S(9)*(n + S(8))) - S(10)*a*d*(a + b*x)**(n + S(5))*(-S(7)*a**S(3)*d + b**S(3)*c)/(b**S(9)*(n + S(5))) - S(2)*a*(a + b*x)**(n + S(2))*(-S(4)*a**S(3)*d + b**S(3)*c)*(-a**S(3)*d + b**S(3)*c)/(b**S(9)*(n + S(2))) + d**S(2)*(a + b*x)**(n + S(9))/(b**S(9)*(n + S(9))) + S(2)*d*(a + b*x)**(n + S(6))*(-S(28)*a**S(3)*d + b**S(3)*c)/(b**S(9)*(n + S(6))) + (a + b*x)**(n + S(3))*(S(28)*a**S(6)*d**S(2) - S(20)*a**S(3)*b**S(3)*c*d + b**S(6)*c**S(2))/(b**S(9)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**n*(c + d*x**S(3))**S(2), x), x, S(21)*a**S(2)*d**S(2)*(a + b*x)**(n + S(6))/(b**S(8)*(n + S(6))) + S(3)*a**S(2)*d*(a + b*x)**(n + S(3))*(-S(7)*a**S(3)*d + S(4)*b**S(3)*c)/(b**S(8)*(n + S(3))) - S(7)*a*d**S(2)*(a + b*x)**(n + S(7))/(b**S(8)*(n + S(7))) - a*d*(a + b*x)**(n + S(4))*(-S(35)*a**S(3)*d + S(8)*b**S(3)*c)/(b**S(8)*(n + S(4))) - a*(a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)**S(2)/(b**S(8)*(n + S(1))) + d**S(2)*(a + b*x)**(n + S(8))/(b**S(8)*(n + S(8))) + d*(a + b*x)**(n + S(5))*(-S(35)*a**S(3)*d + S(2)*b**S(3)*c)/(b**S(8)*(n + S(5))) + (a + b*x)**(n + S(2))*(-S(7)*a**S(3)*d + b**S(3)*c)*(-a**S(3)*d + b**S(3)*c)/(b**S(8)*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n*(c + d*x**S(3))**S(2), x), x, S(15)*a**S(2)*d**S(2)*(a + b*x)**(n + S(5))/(b**S(7)*(n + S(5))) + S(6)*a**S(2)*d*(a + b*x)**(n + S(2))*(-a**S(3)*d + b**S(3)*c)/(b**S(7)*(n + S(2))) - S(6)*a*d**S(2)*(a + b*x)**(n + S(6))/(b**S(7)*(n + S(6))) - S(3)*a*d*(a + b*x)**(n + S(3))*(-S(5)*a**S(3)*d + S(2)*b**S(3)*c)/(b**S(7)*(n + S(3))) + d**S(2)*(a + b*x)**(n + S(7))/(b**S(7)*(n + S(7))) + S(2)*d*(a + b*x)**(n + S(4))*(-S(10)*a**S(3)*d + b**S(3)*c)/(b**S(7)*(n + S(4))) + (a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)**S(2)/(b**S(7)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n*(c + d*x**S(3))**S(2)/x, x), x, S(10)*a**S(2)*d**S(2)*(a + b*x)**(n + S(4))/(b**S(6)*(n + S(4))) + a**S(2)*d*(a + b*x)**(n + S(1))*(-a**S(3)*d + S(2)*b**S(3)*c)/(b**S(6)*(n + S(1))) - S(5)*a*d**S(2)*(a + b*x)**(n + S(5))/(b**S(6)*(n + S(5))) - a*d*(a + b*x)**(n + S(2))*(-S(5)*a**S(3)*d + S(4)*b**S(3)*c)/(b**S(6)*(n + S(2))) + d**S(2)*(a + b*x)**(n + S(6))/(b**S(6)*(n + S(6))) + S(2)*d*(a + b*x)**(n + S(3))*(-S(5)*a**S(3)*d + b**S(3)*c)/(b**S(6)*(n + S(3))) - c**S(2)*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**n*(c + d*x**S(3))**S(3), x), x, S(55)*a**S(2)*d**S(3)*(a + b*x)**(n + S(10))/(b**S(12)*(n + S(10))) + S(42)*a**S(2)*d**S(2)*(a + b*x)**(n + S(7))*(-S(11)*a**S(3)*d + S(2)*b**S(3)*c)/(b**S(12)*(n + S(7))) + S(3)*a**S(2)*d*(a + b*x)**(n + S(4))*(S(55)*a**S(6)*d**S(2) - S(56)*a**S(3)*b**S(3)*c*d + S(10)*b**S(6)*c**S(2))/(b**S(12)*(n + S(4))) + a**S(2)*(a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)**S(3)/(b**S(12)*(n + S(1))) - S(11)*a*d**S(3)*(a + b*x)**(n + S(11))/(b**S(12)*(n + S(11))) - S(6)*a*d**S(2)*(a + b*x)**(n + S(8))*(-S(55)*a**S(3)*d + S(4)*b**S(3)*c)/(b**S(12)*(n + S(8))) - S(15)*a*d*(a + b*x)**(n + S(5))*(S(22)*a**S(6)*d**S(2) - S(14)*a**S(3)*b**S(3)*c*d + b**S(6)*c**S(2))/(b**S(12)*(n + S(5))) - a*(a + b*x)**(n + S(2))*(-S(11)*a**S(3)*d + S(2)*b**S(3)*c)*(-a**S(3)*d + b**S(3)*c)**S(2)/(b**S(12)*(n + S(2))) + d**S(3)*(a + b*x)**(n + S(12))/(b**S(12)*(n + S(12))) + S(3)*d**S(2)*(a + b*x)**(n + S(9))*(-S(55)*a**S(3)*d + b**S(3)*c)/(b**S(12)*(n + S(9))) + S(3)*d*(a + b*x)**(n + S(6))*(S(154)*a**S(6)*d**S(2) - S(56)*a**S(3)*b**S(3)*c*d + b**S(6)*c**S(2))/(b**S(12)*(n + S(6))) + (a + b*x)**(n + S(3))*(-a**S(3)*d + b**S(3)*c)*(S(55)*a**S(6)*d**S(2) - S(29)*a**S(3)*b**S(3)*c*d + b**S(6)*c**S(2))/(b**S(12)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**n*(c + d*x**S(3))**S(3), x), x, S(45)*a**S(2)*d**S(3)*(a + b*x)**(n + S(9))/(b**S(11)*(n + S(9))) + S(63)*a**S(2)*d**S(2)*(a + b*x)**(n + S(6))*(-S(4)*a**S(3)*d + b**S(3)*c)/(b**S(11)*(n + S(6))) + S(9)*a**S(2)*d*(a + b*x)**(n + S(3))*(-S(5)*a**S(3)*d + S(2)*b**S(3)*c)*(-a**S(3)*d + b**S(3)*c)/(b**S(11)*(n + S(3))) - S(10)*a*d**S(3)*(a + b*x)**(n + S(10))/(b**S(11)*(n + S(10))) - S(21)*a*d**S(2)*(a + b*x)**(n + S(7))*(-S(10)*a**S(3)*d + b**S(3)*c)/(b**S(11)*(n + S(7))) - S(3)*a*d*(a + b*x)**(n + S(4))*(S(40)*a**S(6)*d**S(2) - S(35)*a**S(3)*b**S(3)*c*d + S(4)*b**S(6)*c**S(2))/(b**S(11)*(n + S(4))) - a*(a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)**S(3)/(b**S(11)*(n + S(1))) + d**S(3)*(a + b*x)**(n + S(11))/(b**S(11)*(n + S(11))) + S(3)*d**S(2)*(a + b*x)**(n + S(8))*(-S(40)*a**S(3)*d + b**S(3)*c)/(b**S(11)*(n + S(8))) + S(3)*d*(a + b*x)**(n + S(5))*(S(70)*a**S(6)*d**S(2) - S(35)*a**S(3)*b**S(3)*c*d + b**S(6)*c**S(2))/(b**S(11)*(n + S(5))) + (a + b*x)**(n + S(2))*(-S(10)*a**S(3)*d + b**S(3)*c)*(-a**S(3)*d + b**S(3)*c)**S(2)/(b**S(11)*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n*(c + d*x**S(3))**S(3), x), x, S(36)*a**S(2)*d**S(3)*(a + b*x)**(n + S(8))/(b**S(10)*(n + S(8))) + S(9)*a**S(2)*d**S(2)*(a + b*x)**(n + S(5))*(-S(14)*a**S(3)*d + S(5)*b**S(3)*c)/(b**S(10)*(n + S(5))) + S(9)*a**S(2)*d*(a + b*x)**(n + S(2))*(-a**S(3)*d + b**S(3)*c)**S(2)/(b**S(10)*(n + S(2))) - S(9)*a*d**S(3)*(a + b*x)**(n + S(9))/(b**S(10)*(n + S(9))) - S(18)*a*d**S(2)*(a + b*x)**(n + S(6))*(-S(7)*a**S(3)*d + b**S(3)*c)/(b**S(10)*(n + S(6))) - S(9)*a*d*(a + b*x)**(n + S(3))*(-S(4)*a**S(3)*d + b**S(3)*c)*(-a**S(3)*d + b**S(3)*c)/(b**S(10)*(n + S(3))) + d**S(3)*(a + b*x)**(n + S(10))/(b**S(10)*(n + S(10))) + S(3)*d**S(2)*(a + b*x)**(n + S(7))*(-S(28)*a**S(3)*d + b**S(3)*c)/(b**S(10)*(n + S(7))) + S(3)*d*(a + b*x)**(n + S(4))*(S(28)*a**S(6)*d**S(2) - S(20)*a**S(3)*b**S(3)*c*d + b**S(6)*c**S(2))/(b**S(10)*(n + S(4))) + (a + b*x)**(n + S(1))*(-a**S(3)*d + b**S(3)*c)**S(3)/(b**S(10)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n*(c + d*x**S(3))**S(3)/x, x), x, S(28)*a**S(2)*d**S(3)*(a + b*x)**(n + S(7))/(b**S(9)*(n + S(7))) + S(2)*a**S(2)*d**S(2)*(a + b*x)**(n + S(4))*(-S(28)*a**S(3)*d + S(15)*b**S(3)*c)/(b**S(9)*(n + S(4))) + a**S(2)*d*(a + b*x)**(n + S(1))*(a**S(6)*d**S(2) - S(3)*a**S(3)*b**S(3)*c*d + S(3)*b**S(6)*c**S(2))/(b**S(9)*(n + S(1))) - S(8)*a*d**S(3)*(a + b*x)**(n + S(8))/(b**S(9)*(n + S(8))) - S(5)*a*d**S(2)*(a + b*x)**(n + S(5))*(-S(14)*a**S(3)*d + S(3)*b**S(3)*c)/(b**S(9)*(n + S(5))) - a*d*(a + b*x)**(n + S(2))*(S(8)*a**S(6)*d**S(2) - S(15)*a**S(3)*b**S(3)*c*d + S(6)*b**S(6)*c**S(2))/(b**S(9)*(n + S(2))) + d**S(3)*(a + b*x)**(n + S(9))/(b**S(9)*(n + S(9))) + d**S(2)*(a + b*x)**(n + S(6))*(-S(56)*a**S(3)*d + S(3)*b**S(3)*c)/(b**S(9)*(n + S(6))) + d*(a + b*x)**(n + S(3))*(S(28)*a**S(6)*d**S(2) - S(30)*a**S(3)*b**S(3)*c*d + S(3)*b**S(6)*c**S(2))/(b**S(9)*(n + S(3))) - c**S(3)*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(e + f*x)**n/(a + b*x**S(3)), x), x, x**(m + S(1))*(S(1) + f*x/e)**(-n)*(e + f*x)**n*AppellF1(m + S(1), -n, S(1), m + S(2), -f*x/e, -b**(S(1)/3)*x/a**(S(1)/3))/(S(3)*a*(m + S(1))) + x**(m + S(1))*(S(1) + f*x/e)**(-n)*(e + f*x)**n*AppellF1(m + S(1), -n, S(1), m + S(2), -f*x/e, (S(-1))**(S(1)/3)*b**(S(1)/3)*x/a**(S(1)/3))/(S(3)*a*(m + S(1))) + x**(m + S(1))*(S(1) + f*x/e)**(-n)*(e + f*x)**n*AppellF1(m + S(1), -n, S(1), m + S(2), -f*x/e, -(S(-1))**(S(2)/3)*b**(S(1)/3)*x/a**(S(1)/3))/(S(3)*a*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(e + f*x)**n/(a + b*x**S(3)), x), x, a*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b**(S(5)/3)*(n + S(1))*(-(S(-1))**(S(2)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e)) + a*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b**(S(5)/3)*(n + S(1))*((S(-1))**(S(1)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e)) + a*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b**(S(5)/3)*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)) + e**S(2)*(e + f*x)**(n + S(1))/(b*f**S(3)*(n + S(1))) - S(2)*e*(e + f*x)**(n + S(2))/(b*f**S(3)*(n + S(2))) + (e + f*x)**(n + S(3))/(b*f**S(3)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(e + f*x)**n/(a + b*x**S(3)), x), x, (S(-1))**(S(2)/3)*a**(S(2)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(1)/3)*b**(S(1)/3)*(e + f*x)/(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/(S(3)*b**(S(4)/3)*(n + S(1))*(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e)) + (S(-1))**(S(1)/3)*a**(S(2)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(2)/3)*b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/(S(3)*b**(S(4)/3)*(n + S(1))*(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e)) - a**(S(2)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b**(S(4)/3)*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)) - e*(e + f*x)**(n + S(1))/(b*f**S(2)*(n + S(1))) + (e + f*x)**(n + S(2))/(b*f**S(2)*(n + S(2))), expand=True, _diff=True, _numerical=True) # difference in simplify assert rubi_test(rubi_integrate(x**S(3)*(e + f*x)**n/(a + b*x**S(3)), x), x, -a**(S(1)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(1)/3)*b**(S(1)/3)*(e + f*x)/(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/(S(3)*b*(n + S(1))*(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e)) + a**(S(1)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(2)/3)*b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/(S(3)*b*(n + S(1))*(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e)) + a**(S(1)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)) + (e + f*x)**(n + S(1))/(b*f*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(e + f*x)**n/(a + b*x**S(3)), x), x, -(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b**(S(2)/3)*(n + S(1))*(-(S(-1))**(S(2)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e)) - (e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b**(S(2)/3)*(n + S(1))*((S(-1))**(S(1)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e)) - (e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*b**(S(2)/3)*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(e + f*x)**n/(a + b*x**S(3)), x), x, -(S(-1))**(S(2)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(1)/3)*b**(S(1)/3)*(e + f*x)/(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/(S(3)*a**(S(1)/3)*b**(S(1)/3)*(n + S(1))*(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e)) - (S(-1))**(S(1)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(2)/3)*b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/(S(3)*a**(S(1)/3)*b**(S(1)/3)*(n + S(1))*(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e)) + (e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*a**(S(1)/3)*b**(S(1)/3)*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e + f*x)**n/(a + b*x**S(3)), x), x, (e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(1)/3)*b**(S(1)/3)*(e + f*x)/(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/(S(3)*a**(S(2)/3)*(n + S(1))*(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e)) - (e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(2)/3)*b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/(S(3)*a**(S(2)/3)*(n + S(1))*(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e)) - (e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*a**(S(2)/3)*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e + f*x)**n/(x*(a + b*x**S(3))), x), x, b**(S(1)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*a*(n + S(1))*(-(S(-1))**(S(2)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e)) + b**(S(1)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*a*(n + S(1))*((S(-1))**(S(1)/3)*a**(S(1)/3)*f + b**(S(1)/3)*e)) + b**(S(1)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*a*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)) - (e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + f*x/e)/(a*e*(n + S(1))), expand=True, _diff=True, _numerical=True) # large time in rubi_test assert rubi_test(rubi_integrate((e + f*x)**n/(x**S(2)*(a + b*x**S(3))), x), x, f*(e + f*x)**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(1) + f*x/e)/(a*e**S(2)*(n + S(1))) + (S(-1))**(S(2)/3)*b**(S(2)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(1)/3)*b**(S(1)/3)*(e + f*x)/(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e))/(S(3)*a**(S(4)/3)*(n + S(1))*(a**(S(1)/3)*f + (S(-1))**(S(1)/3)*b**(S(1)/3)*e)) + (S(-1))**(S(1)/3)*b**(S(2)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), (S(-1))**(S(2)/3)*b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e))/(S(3)*a**(S(4)/3)*(n + S(1))*(-a**(S(1)/3)*f + (S(-1))**(S(2)/3)*b**(S(1)/3)*e)) - b**(S(2)/3)*(e + f*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/3)*(e + f*x)/(-a**(S(1)/3)*f + b**(S(1)/3)*e))/(S(3)*a**(S(4)/3)*(n + S(1))*(-a**(S(1)/3)*f + b**(S(1)/3)*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c + d*x)**(n + S(1))/(a + b*x**S(3)), x), x, -(c + d*x)**(n + S(2))*hyper((S(1), n + S(2)), (n + S(3),), b**(S(1)/3)*(c + d*x)/(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**(S(2)/3)*(n + S(2))*(-(S(-1))**(S(2)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c)) - (c + d*x)**(n + S(2))*hyper((S(1), n + S(2)), (n + S(3),), b**(S(1)/3)*(c + d*x)/((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**(S(2)/3)*(n + S(2))*((S(-1))**(S(1)/3)*a**(S(1)/3)*d + b**(S(1)/3)*c)) - (c + d*x)**(n + S(2))*hyper((S(1), n + S(2)), (n + S(3),), b**(S(1)/3)*(c + d*x)/(-a**(S(1)/3)*d + b**(S(1)/3)*c))/(S(3)*b**(S(2)/3)*(n + S(2))*(-a**(S(1)/3)*d + b**(S(1)/3)*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(c + d*x)**n/(a + b*x**S(4)), x), x, -(c + d*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(1))*(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4))) - (c + d*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(1))*(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4))) - (c + d*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(1))*(b**(S(1)/4)*c + d*(-a)**(S(1)/4))) - (c + d*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(1))*(b**(S(1)/4)*c - d*(-a)**(S(1)/4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(c + d*x)**(n + S(1))/(a + b*x**S(4)), x), x, -(c + d*x)**(n + S(2))*hyper((S(1), n + S(2)), (n + S(3),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(2))*(b**(S(1)/4)*c + I*d*(-a)**(S(1)/4))) - (c + d*x)**(n + S(2))*hyper((S(1), n + S(2)), (n + S(3),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(2))*(b**(S(1)/4)*c - I*d*(-a)**(S(1)/4))) - (c + d*x)**(n + S(2))*hyper((S(1), n + S(2)), (n + S(3),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c + d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(2))*(b**(S(1)/4)*c + d*(-a)**(S(1)/4))) - (c + d*x)**(n + S(2))*hyper((S(1), n + S(2)), (n + S(3),), b**(S(1)/4)*(c + d*x)/(b**(S(1)/4)*c - d*(-a)**(S(1)/4)))/(S(4)*b**(S(3)/4)*(n + S(2))*(b**(S(1)/4)*c - d*(-a)**(S(1)/4))), expand=True, _diff=True, _numerical=True) # large time in rubi_test assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b*x**S(4))*(c + d*x + e*x**S(2))), x), x, sqrt(S(2))*e**S(2)*atanh(sqrt(S(2))*(S(4)*a*e**S(2) + b*x**S(2)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2))/(S(4)*sqrt(a + b*x**S(4))*sqrt(S(2)*a*e**S(4) + S(2)*b*c**S(2)*e**S(2) - S(4)*b*c*d**S(2)*e + b*d**S(4) + b*d*sqrt(-S(4)*c*e + d**S(2))*(-S(2)*c*e + d**S(2)))))/(S(2)*sqrt(-S(4)*c*e + d**S(2))*sqrt(S(2)*a*e**S(4) + S(2)*b*c**S(2)*e**S(2) - S(4)*b*c*d**S(2)*e + b*d**S(4) + b*d*sqrt(-S(4)*c*e + d**S(2))*(-S(2)*c*e + d**S(2)))) - sqrt(S(2))*e**S(2)*atanh(sqrt(S(2))*(S(4)*a*e**S(2) + b*x**S(2)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2))/(S(4)*sqrt(a + b*x**S(4))*sqrt(S(2)*a*e**S(4) + S(2)*b*c**S(2)*e**S(2) - S(4)*b*c*d**S(2)*e + b*d**S(4) - b*d*sqrt(-S(4)*c*e + d**S(2))*(-S(2)*c*e + d**S(2)))))/(S(2)*sqrt(-S(4)*c*e + d**S(2))*sqrt(S(2)*a*e**S(4) + S(2)*b*c**S(2)*e**S(2) - S(4)*b*c*d**S(2)*e + b*d**S(4) - b*d*sqrt(-S(4)*c*e + d**S(2))*(-S(2)*c*e + d**S(2)))) - S(2)*e*atan(x*sqrt(-(S(16)*a*e**S(4) + b*(d + sqrt(-S(4)*c*e + d**S(2)))**S(4))/(e**S(2)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2)))/(S(2)*sqrt(a + b*x**S(4))))/(sqrt(-(S(16)*a*e**S(4) + b*(d + sqrt(-S(4)*c*e + d**S(2)))**S(4))/(e**S(2)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2)))*(d + sqrt(-S(4)*c*e + d**S(2)))*sqrt(-S(4)*c*e + d**S(2))) + S(2)*e*atan(x*sqrt(-(S(16)*a*e**S(4) + b*(d - sqrt(-S(4)*c*e + d**S(2)))**S(4))/(e**S(2)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2)))/(S(2)*sqrt(a + b*x**S(4))))/(sqrt(-(S(16)*a*e**S(4) + b*(d - sqrt(-S(4)*c*e + d**S(2)))**S(4))/(e**S(2)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2)))*(d - sqrt(-S(4)*c*e + d**S(2)))*sqrt(-S(4)*c*e + d**S(2))) - e*sqrt((a + b*x**S(4))/(sqrt(a) + sqrt(b)*x**S(2))**S(2))*(sqrt(a) + sqrt(b)*x**S(2))*(S(4)*e**S(2) - sqrt(b)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))*elliptic_pi(sqrt(a)*(S(4)*e**S(2) + sqrt(b)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))**S(2)/(S(16)*sqrt(b)*e**S(2)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2)), S(2)*atan(b**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*b**(S(1)/4)*sqrt(a + b*x**S(4))*(d + sqrt(-S(4)*c*e + d**S(2)))*(S(4)*e**S(2) + sqrt(b)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))*sqrt(-S(4)*c*e + d**S(2))) + e*sqrt((a + b*x**S(4))/(sqrt(a) + sqrt(b)*x**S(2))**S(2))*(sqrt(a) + sqrt(b)*x**S(2))*(S(4)*e**S(2) - sqrt(b)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))*elliptic_pi(sqrt(a)*(S(4)*e**S(2) + sqrt(b)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))**S(2)/(S(16)*sqrt(b)*e**S(2)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2)), S(2)*atan(b**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*b**(S(1)/4)*sqrt(a + b*x**S(4))*(d - sqrt(-S(4)*c*e + d**S(2)))*(S(4)*e**S(2) + sqrt(b)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))*sqrt(-S(4)*c*e + d**S(2))) + b**(S(1)/4)*e*sqrt((a + b*x**S(4))/(sqrt(a) + sqrt(b)*x**S(2))**S(2))*(sqrt(a) + sqrt(b)*x**S(2))*(d - sqrt(-S(4)*c*e + d**S(2)))*elliptic_f(S(2)*atan(b**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(a**(S(3)/4)*sqrt(a + b*x**S(4))*(S(4)*e**S(2) + sqrt(b)*(d - sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))*sqrt(-S(4)*c*e + d**S(2))) - b**(S(1)/4)*e*sqrt((a + b*x**S(4))/(sqrt(a) + sqrt(b)*x**S(2))**S(2))*(sqrt(a) + sqrt(b)*x**S(2))*(d + sqrt(-S(4)*c*e + d**S(2)))*elliptic_f(S(2)*atan(b**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(a**(S(3)/4)*sqrt(a + b*x**S(4))*(S(4)*e**S(2) + sqrt(b)*(d + sqrt(-S(4)*c*e + d**S(2)))**S(2)/sqrt(a))*sqrt(-S(4)*c*e + d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**p, x), x, x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(1))/(b*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**S(3), x), x, x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**S(2), x), x, x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*(c*x**n)**(S(1)/n), x), x, a*x + b*x*(c*x**n)**(S(1)/n)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*(c*x**n)**(S(1)/n)), x), x, x*(c*x**n)**(-S(1)/n)*log(a + b*(c*x**n)**(S(1)/n))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**(S(-2)), x), x, x/(a**S(2) + a*b*(c*x**n)**(S(1)/n)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**(S(-2)), x), x, -x*(c*x**n)**(-S(1)/n)/(b*(a + b*(c*x**n)**(S(1)/n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**(S(-3)), x), x, -x*(c*x**n)**(-S(1)/n)/(S(2)*b*(a + b*(c*x**n)**(S(1)/n))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(2)/n))**S(3), x), x, a**S(3)*x + a**S(2)*b*x*(c*x**n)**(S(2)/n) + S(3)*a*b**S(2)*x*(c*x**n)**(S(4)/n)/S(5) + b**S(3)*x*(c*x**n)**(S(6)/n)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(2)/n))**S(2), x), x, a**S(2)*x + S(2)*a*b*x*(c*x**n)**(S(2)/n)/S(3) + b**S(2)*x*(c*x**n)**(S(4)/n)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*(c*x**n)**(S(2)/n), x), x, a*x + b*x*(c*x**n)**(S(2)/n)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*(c*x**n)**(S(2)/n)), x), x, x*(c*x**n)**(-S(1)/n)*atan(sqrt(b)*(c*x**n)**(S(1)/n)/sqrt(a))/(sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(2)/n))**(S(-2)), x), x, x/(S(2)*a*(a + b*(c*x**n)**(S(2)/n))) + x*(c*x**n)**(-S(1)/n)*atan(sqrt(b)*(c*x**n)**(S(1)/n)/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(2)/n))**(S(-3)), x), x, x/(S(4)*a*(a + b*(c*x**n)**(S(2)/n))**S(2)) + S(3)*x/(S(8)*a**S(2)*(a + b*(c*x**n)**(S(2)/n))) + S(3)*x*(c*x**n)**(-S(1)/n)*atan(sqrt(b)*(c*x**n)**(S(1)/n)/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(3)/n))**S(3), x), x, a**S(3)*x + S(3)*a**S(2)*b*x*(c*x**n)**(S(3)/n)/S(4) + S(3)*a*b**S(2)*x*(c*x**n)**(S(6)/n)/S(7) + b**S(3)*x*(c*x**n)**(S(9)/n)/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(3)/n))**S(2), x), x, a**S(2)*x + a*b*x*(c*x**n)**(S(3)/n)/S(2) + b**S(2)*x*(c*x**n)**(S(6)/n)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*(c*x**n)**(S(3)/n), x), x, a*x + b*x*(c*x**n)**(S(3)/n)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*(c*x**n)**(S(3)/n)), x), x, x*(c*x**n)**(-S(1)/n)*log(a**(S(1)/3) + b**(S(1)/3)*(c*x**n)**(S(1)/n))/(S(3)*a**(S(2)/3)*b**(S(1)/3)) - x*(c*x**n)**(-S(1)/n)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c*x**n)**(S(1)/n) + b**(S(2)/3)*(c*x**n)**(S(2)/n))/(S(6)*a**(S(2)/3)*b**(S(1)/3)) - sqrt(S(3))*x*(c*x**n)**(-S(1)/n)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c*x**n)**(S(1)/n))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*b**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(3)/n))**(S(-2)), x), x, x/(S(3)*a*(a + b*(c*x**n)**(S(3)/n))) + S(2)*x*(c*x**n)**(-S(1)/n)*log(a**(S(1)/3) + b**(S(1)/3)*(c*x**n)**(S(1)/n))/(S(9)*a**(S(5)/3)*b**(S(1)/3)) - x*(c*x**n)**(-S(1)/n)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c*x**n)**(S(1)/n) + b**(S(2)/3)*(c*x**n)**(S(2)/n))/(S(9)*a**(S(5)/3)*b**(S(1)/3)) - S(2)*sqrt(S(3))*x*(c*x**n)**(-S(1)/n)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c*x**n)**(S(1)/n))/(S(3)*a**(S(1)/3)))/(S(9)*a**(S(5)/3)*b**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(3)/n))**(S(-3)), x), x, x/(S(6)*a*(a + b*(c*x**n)**(S(3)/n))**S(2)) + S(5)*x/(S(18)*a**S(2)*(a + b*(c*x**n)**(S(3)/n))) + S(5)*x*(c*x**n)**(-S(1)/n)*log(a**(S(1)/3) + b**(S(1)/3)*(c*x**n)**(S(1)/n))/(S(27)*a**(S(8)/3)*b**(S(1)/3)) - S(5)*x*(c*x**n)**(-S(1)/n)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c*x**n)**(S(1)/n) + b**(S(2)/3)*(c*x**n)**(S(2)/n))/(S(54)*a**(S(8)/3)*b**(S(1)/3)) - S(5)*sqrt(S(3))*x*(c*x**n)**(-S(1)/n)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c*x**n)**(S(1)/n))/(S(3)*a**(S(1)/3)))/(S(27)*a**(S(8)/3)*b**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x**S(3))**(S(2)/3) + S(1)), x), x, x*atan((x**S(3))**(S(1)/3))/(x**S(3))**(S(1)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x**S(2))**(S(3)/2) + S(1)), x), x, x*log(sqrt(x**S(2)) + S(1))/(S(3)*sqrt(x**S(2))) - x*log(x**S(2) - sqrt(x**S(2)) + S(1))/(S(6)*sqrt(x**S(2))) - sqrt(S(3))*x*atan(sqrt(S(3))*(-S(2)*sqrt(x**S(2)) + S(1))/S(3))/(S(3)*sqrt(x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(4)*sqrt(x**S(4)) + S(1)), x), x, x*atan(S(2)*(x**S(4))**(S(1)/4))/(S(2)*(x**S(4))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-S(4)*sqrt(x**S(4)) + S(1)), x), x, x*atanh(S(2)*(x**S(4))**(S(1)/4))/(S(2)*(x**S(4))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(4)*(x**S(6))**(S(1)/3) + S(1)), x), x, x*atan(S(2)*(x**S(6))**(S(1)/6))/(S(2)*(x**S(6))**(S(1)/6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-S(4)*(x**S(6))**(S(1)/3) + S(1)), x), x, x*atanh(S(2)*(x**S(6))**(S(1)/6))/(S(2)*(x**S(6))**(S(1)/6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(4)*(x**(S(2)*n))**(S(1)/n) + S(1)), x), x, x*(x**(S(2)*n))**(-S(1)/(S(2)*n))*atan(S(2)*(x**(S(2)*n))**(S(1)/(S(2)*n)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-S(4)*(x**(S(2)*n))**(S(1)/n) + S(1)), x), x, x*(x**(S(2)*n))**(-S(1)/(S(2)*n))*atanh(S(2)*(x**(S(2)*n))**(S(1)/(S(2)*n)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*(c*x**n)**(S(1)/n)), x), x, -a**S(3)*x**S(4)*(c*x**n)**(-S(4)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(4) + a**S(2)*x**S(4)*(c*x**n)**(-S(3)/n)/b**S(3) - a*x**S(4)*(c*x**n)**(-S(2)/n)/(S(2)*b**S(2)) + x**S(4)*(c*x**n)**(-S(1)/n)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*(c*x**n)**(S(1)/n)), x), x, a**S(2)*x**S(3)*(c*x**n)**(-S(3)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(3) - a*x**S(3)*(c*x**n)**(-S(2)/n)/b**S(2) + x**S(3)*(c*x**n)**(-S(1)/n)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*(c*x**n)**(S(1)/n)), x), x, -a*x**S(2)*(c*x**n)**(-S(2)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(2) + x**S(2)*(c*x**n)**(-S(1)/n)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*(c*x**n)**(S(1)/n)), x), x, x*(c*x**n)**(-S(1)/n)*log(a + b*(c*x**n)**(S(1)/n))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*(c*x**n)**(S(1)/n))), x), x, log(x)/a - log(a + b*(c*x**n)**(S(1)/n))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*(c*x**n)**(S(1)/n))), x), x, -S(1)/(a*x) - b*(c*x**n)**(S(1)/n)*log(x)/(a**S(2)*x) + b*(c*x**n)**(S(1)/n)*log(a + b*(c*x**n)**(S(1)/n))/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*(c*x**n)**(S(1)/n))), x), x, -S(1)/(S(2)*a*x**S(2)) + b*(c*x**n)**(S(1)/n)/(a**S(2)*x**S(2)) + b**S(2)*(c*x**n)**(S(2)/n)*log(x)/(a**S(3)*x**S(2)) - b**S(2)*(c*x**n)**(S(2)/n)*log(a + b*(c*x**n)**(S(1)/n))/(a**S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*(c*x**n)**(S(1)/n))**S(2), x), x, a**S(3)*x**S(4)*(c*x**n)**(-S(4)/n)/(b**S(4)*(a + b*(c*x**n)**(S(1)/n))) + S(3)*a**S(2)*x**S(4)*(c*x**n)**(-S(4)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(4) - S(2)*a*x**S(4)*(c*x**n)**(-S(3)/n)/b**S(3) + x**S(4)*(c*x**n)**(-S(2)/n)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*(c*x**n)**(S(1)/n))**S(2), x), x, -a**S(2)*x**S(3)*(c*x**n)**(-S(3)/n)/(b**S(3)*(a + b*(c*x**n)**(S(1)/n))) - S(2)*a*x**S(3)*(c*x**n)**(-S(3)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(3) + x**S(3)*(c*x**n)**(-S(2)/n)/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*(c*x**n)**(S(1)/n))**S(2), x), x, a*x**S(2)*(c*x**n)**(-S(2)/n)/(b**S(2)*(a + b*(c*x**n)**(S(1)/n))) + x**S(2)*(c*x**n)**(-S(2)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**(S(-2)), x), x, -x*(c*x**n)**(-S(1)/n)/(b*(a + b*(c*x**n)**(S(1)/n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*(c*x**n)**(S(1)/n))**S(2)), x), x, S(1)/(a*(a + b*(c*x**n)**(S(1)/n))) + log(x)/a**S(2) - log(a + b*(c*x**n)**(S(1)/n))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*(c*x**n)**(S(1)/n))**S(2)), x), x, -b*(c*x**n)**(S(1)/n)/(a**S(2)*x*(a + b*(c*x**n)**(S(1)/n))) - S(1)/(a**S(2)*x) - S(2)*b*(c*x**n)**(S(1)/n)*log(x)/(a**S(3)*x) + S(2)*b*(c*x**n)**(S(1)/n)*log(a + b*(c*x**n)**(S(1)/n))/(a**S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*(c*x**n)**(S(1)/n))**S(2)), x), x, -S(1)/(S(2)*a**S(2)*x**S(2)) + b**S(2)*(c*x**n)**(S(2)/n)/(a**S(3)*x**S(2)*(a + b*(c*x**n)**(S(1)/n))) + S(2)*b*(c*x**n)**(S(1)/n)/(a**S(3)*x**S(2)) + S(3)*b**S(2)*(c*x**n)**(S(2)/n)*log(x)/(a**S(4)*x**S(2)) - S(3)*b**S(2)*(c*x**n)**(S(2)/n)*log(a + b*(c*x**n)**(S(1)/n))/(a**S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*(c*x**n)**(S(1)/n))**p, x), x, -a**S(3)*x**S(4)*(c*x**n)**(-S(4)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(1))/(b**S(4)*(p + S(1))) + S(3)*a**S(2)*x**S(4)*(c*x**n)**(-S(4)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(2))/(b**S(4)*(p + S(2))) - S(3)*a*x**S(4)*(c*x**n)**(-S(4)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(3))/(b**S(4)*(p + S(3))) + x**S(4)*(c*x**n)**(-S(4)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(4))/(b**S(4)*(p + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*(c*x**n)**(S(1)/n))**p, x), x, a**S(2)*x**S(3)*(c*x**n)**(-S(3)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(1))/(b**S(3)*(p + S(1))) - S(2)*a*x**S(3)*(c*x**n)**(-S(3)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(2))/(b**S(3)*(p + S(2))) + x**S(3)*(c*x**n)**(-S(3)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(3))/(b**S(3)*(p + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*(c*x**n)**(S(1)/n))**p, x), x, -a*x**S(2)*(c*x**n)**(-S(2)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(1))/(b**S(2)*(p + S(1))) + x**S(2)*(c*x**n)**(-S(2)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(2))/(b**S(2)*(p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**p, x), x, x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(1))/(b*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x**n)**(S(1)/n))**p/x, x), x, -(a + b*(c*x**n)**(S(1)/n))**(p + S(1))*hyper((S(1), p + S(1)), (p + S(2),), S(1) + b*(c*x**n)**(S(1)/n)/a)/(a*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((x**n)**(S(1)/n) + S(1))**S(2), x), x, x**S(2)*(x**n)**(-S(2)/n)*log((x**n)**(S(1)/n) + S(1)) + x**S(2)*(x**n)**(-S(2)/n)/((x**n)**(S(1)/n) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a*(b*x**n)**p)**q, x), x, x**(m + S(1))*(a*(b*x**n)**p)**q/(m + n*p*q + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a*(b*x**n)**p)**q, x), x, x**S(3)*(a*(b*x**n)**p)**q/(n*p*q + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a*(b*x**n)**p)**q, x), x, x**S(2)*(a*(b*x**n)**p)**q/(n*p*q + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*x**n)**p)**q, x), x, x*(a*(b*x**n)**p)**q/(n*p*q + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*x**n)**p)**q/x, x), x, (a*(b*x**n)**p)**q/(n*p*q), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*x**n)**p)**q/x**S(2), x), x, -(a*(b*x**n)**p)**q/(x*(-n*p*q + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*x**n)**p)**q/x**S(3), x), x, -(a*(b*x**n)**p)**q/(x**S(2)*(-n*p*q + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a*(b*x**m)**n)**(-S(1)/(m*n)), x), x, x**S(3)*(a*(b*x**m)**n)**(-S(1)/(m*n))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a*(b*x**m)**n)**(-S(1)/(m*n)), x), x, x**S(2)*(a*(b*x**m)**n)**(-S(1)/(m*n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*x**m)**n)**(-S(1)/(m*n)), x), x, x*(a*(b*x**m)**n)**(-S(1)/(m*n))*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*x**m)**n)**(-S(1)/(m*n))/x, x), x, -(a*(b*x**m)**n)**(-S(1)/(m*n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*x**m)**n)**(-S(1)/(m*n))/x**S(2), x), x, -(a*(b*x**m)**n)**(-S(1)/(m*n))/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n*p*q + S(2))*(a*(b*x**n)**p)**q, x), x, x**(-n*p*q + S(3))*(a*(b*x**n)**p)**q/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n*p*q + S(1))*(a*(b*x**n)**p)**q, x), x, x**(-n*p*q + S(2))*(a*(b*x**n)**p)**q/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n*p*q)*(a*(b*x**n)**p)**q, x), x, x**(-n*p*q + S(1))*(a*(b*x**n)**p)**q, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n*p*q + S(-1))*(a*(b*x**n)**p)**q, x), x, x**(-n*p*q)*(a*(b*x**n)**p)**q*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n*p*q + S(-2))*(a*(b*x**n)**p)**q, x), x, -x**(-n*p*q + S(-1))*(a*(b*x**n)**p)**q, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(c*x**S(2))*(a + b*x)**n, x), x, -a**S(3)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(4)*x*(n + S(1))) + S(3)*a**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(4)*x*(n + S(2))) - S(3)*a*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(4)*x*(n + S(3))) + sqrt(c*x**S(2))*(a + b*x)**(n + S(4))/(b**S(4)*x*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(c*x**S(2))*(a + b*x)**n, x), x, a**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(3)*x*(n + S(1))) - S(2)*a*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(3)*x*(n + S(2))) + sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(3)*x*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**n, x), x, -a*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(2)*x*(n + S(1))) + sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(2)*x*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**n/x, x), x, sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**n/x**S(2), x), x, -sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**n/x**S(3), x), x, b*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(2)*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**n/x**S(4), x), x, -b**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(3), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(3)*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**(S(3)/2)*(a + b*x)**n, x), x, a**S(4)*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(5)*x*(n + S(1))) - S(4)*a**S(3)*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(5)*x*(n + S(2))) + S(6)*a**S(2)*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(5)*x*(n + S(3))) - S(4)*a*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(4))/(b**S(5)*x*(n + S(4))) + c*sqrt(c*x**S(2))*(a + b*x)**(n + S(5))/(b**S(5)*x*(n + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**n, x), x, -a**S(3)*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(4)*x*(n + S(1))) + S(3)*a**S(2)*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(4)*x*(n + S(2))) - S(3)*a*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(4)*x*(n + S(3))) + c*sqrt(c*x**S(2))*(a + b*x)**(n + S(4))/(b**S(4)*x*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**n/x, x), x, a**S(2)*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(3)*x*(n + S(1))) - S(2)*a*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(3)*x*(n + S(2))) + c*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(3)*x*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**n/x**S(2), x), x, -a*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(2)*x*(n + S(1))) + c*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(2)*x*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**n/x**S(3), x), x, c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**n/x**S(4), x), x, -c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**n/x**S(5), x), x, b*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(2)*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**n/x**S(6), x), x, -b**S(2)*c*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(3), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(3)*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n, x), x, -a**S(5)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(6)*x*(n + S(1))) + S(5)*a**S(4)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(6)*x*(n + S(2))) - S(10)*a**S(3)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(6)*x*(n + S(3))) + S(10)*a**S(2)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(4))/(b**S(6)*x*(n + S(4))) - S(5)*a*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(5))/(b**S(6)*x*(n + S(5))) + c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(6))/(b**S(6)*x*(n + S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n/x, x), x, a**S(4)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(5)*x*(n + S(1))) - S(4)*a**S(3)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(5)*x*(n + S(2))) + S(6)*a**S(2)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(5)*x*(n + S(3))) - S(4)*a*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(4))/(b**S(5)*x*(n + S(4))) + c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(5))/(b**S(5)*x*(n + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n/x**S(2), x), x, -a**S(3)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(4)*x*(n + S(1))) + S(3)*a**S(2)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(4)*x*(n + S(2))) - S(3)*a*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(4)*x*(n + S(3))) + c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(4))/(b**S(4)*x*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n/x**S(3), x), x, a**S(2)*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(3)*x*(n + S(1))) - S(2)*a*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(3)*x*(n + S(2))) + c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(3))/(b**S(3)*x*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n/x**S(4), x), x, -a*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(2)*x*(n + S(1))) + c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(2)*x*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n/x**S(5), x), x, c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n/x**S(6), x), x, -c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**n/x**S(7), x), x, b*c**S(2)*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(2)*x*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x)**n/sqrt(c*x**S(2)), x), x, -a**S(3)*x*(a + b*x)**(n + S(1))/(b**S(4)*sqrt(c*x**S(2))*(n + S(1))) + S(3)*a**S(2)*x*(a + b*x)**(n + S(2))/(b**S(4)*sqrt(c*x**S(2))*(n + S(2))) - S(3)*a*x*(a + b*x)**(n + S(3))/(b**S(4)*sqrt(c*x**S(2))*(n + S(3))) + x*(a + b*x)**(n + S(4))/(b**S(4)*sqrt(c*x**S(2))*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)**n/sqrt(c*x**S(2)), x), x, a**S(2)*x*(a + b*x)**(n + S(1))/(b**S(3)*sqrt(c*x**S(2))*(n + S(1))) - S(2)*a*x*(a + b*x)**(n + S(2))/(b**S(3)*sqrt(c*x**S(2))*(n + S(2))) + x*(a + b*x)**(n + S(3))/(b**S(3)*sqrt(c*x**S(2))*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**n/sqrt(c*x**S(2)), x), x, -a*sqrt(c*x**S(2))*(a + b*x)**(n + S(1))/(b**S(2)*c*x*(n + S(1))) + sqrt(c*x**S(2))*(a + b*x)**(n + S(2))/(b**S(2)*c*x*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**n/sqrt(c*x**S(2)), x), x, x*(a + b*x)**(n + S(1))/(b*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n/sqrt(c*x**S(2)), x), x, -x*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n/(x*sqrt(c*x**S(2))), x), x, b*x*(a + b*x)**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(2)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n/(x**S(2)*sqrt(c*x**S(2))), x), x, -b**S(2)*x*(a + b*x)**(n + S(1))*hyper((S(3), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(3)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n/(x**S(3)*sqrt(c*x**S(2))), x), x, b**S(3)*x*(a + b*x)**(n + S(1))*hyper((S(4), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(4)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a + b*x)**n/(c*x**S(2))**(S(3)/2), x), x, -a**S(3)*x*(a + b*x)**(n + S(1))/(b**S(4)*c*sqrt(c*x**S(2))*(n + S(1))) + S(3)*a**S(2)*x*(a + b*x)**(n + S(2))/(b**S(4)*c*sqrt(c*x**S(2))*(n + S(2))) - S(3)*a*x*(a + b*x)**(n + S(3))/(b**S(4)*c*sqrt(c*x**S(2))*(n + S(3))) + x*(a + b*x)**(n + S(4))/(b**S(4)*c*sqrt(c*x**S(2))*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x)**n/(c*x**S(2))**(S(3)/2), x), x, a**S(2)*x*(a + b*x)**(n + S(1))/(b**S(3)*c*sqrt(c*x**S(2))*(n + S(1))) - S(2)*a*x*(a + b*x)**(n + S(2))/(b**S(3)*c*sqrt(c*x**S(2))*(n + S(2))) + x*(a + b*x)**(n + S(3))/(b**S(3)*c*sqrt(c*x**S(2))*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x)**n/(c*x**S(2))**(S(3)/2), x), x, -a*x*(a + b*x)**(n + S(1))/(b**S(2)*c*sqrt(c*x**S(2))*(n + S(1))) + x*(a + b*x)**(n + S(2))/(b**S(2)*c*sqrt(c*x**S(2))*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)**n/(c*x**S(2))**(S(3)/2), x), x, x*(a + b*x)**(n + S(1))/(b*c*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**n/(c*x**S(2))**(S(3)/2), x), x, -x*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*c*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**n/(c*x**S(2))**(S(3)/2), x), x, b*x*(a + b*x)**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(2)*c*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n/(c*x**S(2))**(S(3)/2), x), x, -b**S(2)*x*(a + b*x)**(n + S(1))*hyper((S(3), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(3)*c*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**n/(x*(c*x**S(2))**(S(3)/2)), x), x, b**S(3)*x*(a + b*x)**(n + S(1))*hyper((S(4), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(4)*c*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, -a**S(3)*x*(a + b*x)**(n + S(1))/(b**S(4)*c**S(2)*sqrt(c*x**S(2))*(n + S(1))) + S(3)*a**S(2)*x*(a + b*x)**(n + S(2))/(b**S(4)*c**S(2)*sqrt(c*x**S(2))*(n + S(2))) - S(3)*a*x*(a + b*x)**(n + S(3))/(b**S(4)*c**S(2)*sqrt(c*x**S(2))*(n + S(3))) + x*(a + b*x)**(n + S(4))/(b**S(4)*c**S(2)*sqrt(c*x**S(2))*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, a**S(2)*x*(a + b*x)**(n + S(1))/(b**S(3)*c**S(2)*sqrt(c*x**S(2))*(n + S(1))) - S(2)*a*x*(a + b*x)**(n + S(2))/(b**S(3)*c**S(2)*sqrt(c*x**S(2))*(n + S(2))) + x*(a + b*x)**(n + S(3))/(b**S(3)*c**S(2)*sqrt(c*x**S(2))*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, -a*x*(a + b*x)**(n + S(1))/(b**S(2)*c**S(2)*sqrt(c*x**S(2))*(n + S(1))) + x*(a + b*x)**(n + S(2))/(b**S(2)*c**S(2)*sqrt(c*x**S(2))*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, x*(a + b*x)**(n + S(1))/(b*c**S(2)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, -x*(a + b*x)**(n + S(1))*hyper((S(1), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a*c**S(2)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, b*x*(a + b*x)**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(2)*c**S(2)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, -b**S(2)*x*(a + b*x)**(n + S(1))*hyper((S(3), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(3)*c**S(2)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**n/(c*x**S(2))**(S(5)/2), x), x, b**S(3)*x*(a + b*x)**(n + S(1))*hyper((S(4), n + S(1)), (n + S(2),), S(1) + b*x/a)/(a**S(4)*c**S(2)*sqrt(c*x**S(2))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(c*x**S(2))*(a + b*x), x), x, a*x**(m + S(1))*sqrt(c*x**S(2))/(m + S(2)) + b*x**(m + S(2))*sqrt(c*x**S(2))/(m + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(c*x**S(2))*(a + b*x), x), x, a*x**S(4)*sqrt(c*x**S(2))/S(5) + b*x**S(5)*sqrt(c*x**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(c*x**S(2))*(a + b*x), x), x, a*x**S(3)*sqrt(c*x**S(2))/S(4) + b*x**S(4)*sqrt(c*x**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(c*x**S(2))*(a + b*x), x), x, a*x**S(2)*sqrt(c*x**S(2))/S(3) + b*x**S(3)*sqrt(c*x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x), x), x, a*x*sqrt(c*x**S(2))/S(2) + b*x**S(2)*sqrt(c*x**S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)/x, x), x, a*sqrt(c*x**S(2)) + b*x*sqrt(c*x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)/x**S(2), x), x, a*sqrt(c*x**S(2))*log(x)/x + b*sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)/x**S(3), x), x, -a*sqrt(c*x**S(2))/x**S(2) + b*sqrt(c*x**S(2))*log(x)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)/x**S(4), x), x, -a*sqrt(c*x**S(2))/(S(2)*x**S(3)) - b*sqrt(c*x**S(2))/x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(c*x**S(2))**(S(3)/2)*(a + b*x), x), x, a*c*x**(m + S(3))*sqrt(c*x**S(2))/(m + S(4)) + b*c*x**(m + S(4))*sqrt(c*x**S(2))/(m + S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(c*x**S(2))**(S(3)/2)*(a + b*x), x), x, a*c*x**S(6)*sqrt(c*x**S(2))/S(7) + b*c*x**S(7)*sqrt(c*x**S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c*x**S(2))**(S(3)/2)*(a + b*x), x), x, a*c*x**S(5)*sqrt(c*x**S(2))/S(6) + b*c*x**S(6)*sqrt(c*x**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**(S(3)/2)*(a + b*x), x), x, a*c*x**S(4)*sqrt(c*x**S(2))/S(5) + b*c*x**S(5)*sqrt(c*x**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x), x), x, a*c*x**S(3)*sqrt(c*x**S(2))/S(4) + b*c*x**S(4)*sqrt(c*x**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)/x, x), x, a*c*x**S(2)*sqrt(c*x**S(2))/S(3) + b*c*x**S(3)*sqrt(c*x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)/x**S(2), x), x, a*c*x*sqrt(c*x**S(2))/S(2) + b*c*x**S(2)*sqrt(c*x**S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)/x**S(3), x), x, a*c*sqrt(c*x**S(2)) + b*c*x*sqrt(c*x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)/x**S(4), x), x, a*c*sqrt(c*x**S(2))*log(x)/x + b*c*sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(c*x**S(2))**(S(5)/2)*(a + b*x), x), x, a*c**S(2)*x**(m + S(5))*sqrt(c*x**S(2))/(m + S(6)) + b*c**S(2)*x**(m + S(6))*sqrt(c*x**S(2))/(m + S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(c*x**S(2))**(S(5)/2)*(a + b*x), x), x, a*c**S(2)*x**S(8)*sqrt(c*x**S(2))/S(9) + b*c**S(2)*x**S(9)*sqrt(c*x**S(2))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c*x**S(2))**(S(5)/2)*(a + b*x), x), x, a*c**S(2)*x**S(7)*sqrt(c*x**S(2))/S(8) + b*c**S(2)*x**S(8)*sqrt(c*x**S(2))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**(S(5)/2)*(a + b*x), x), x, a*c**S(2)*x**S(6)*sqrt(c*x**S(2))/S(7) + b*c**S(2)*x**S(7)*sqrt(c*x**S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x), x), x, a*c**S(2)*x**S(5)*sqrt(c*x**S(2))/S(6) + b*c**S(2)*x**S(6)*sqrt(c*x**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)/x, x), x, a*c**S(2)*x**S(4)*sqrt(c*x**S(2))/S(5) + b*c**S(2)*x**S(5)*sqrt(c*x**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)/x**S(2), x), x, a*c**S(2)*x**S(3)*sqrt(c*x**S(2))/S(4) + b*c**S(2)*x**S(4)*sqrt(c*x**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)/x**S(3), x), x, a*c**S(2)*x**S(2)*sqrt(c*x**S(2))/S(3) + b*c**S(2)*x**S(3)*sqrt(c*x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)/x**S(4), x), x, a*c**S(2)*x*sqrt(c*x**S(2))/S(2) + b*c**S(2)*x**S(2)*sqrt(c*x**S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*x)/sqrt(c*x**S(2)), x), x, a*x**(m + S(1))/(m*sqrt(c*x**S(2))) + b*x**(m + S(2))/(sqrt(c*x**S(2))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)/sqrt(c*x**S(2)), x), x, a*x**S(4)/(S(3)*sqrt(c*x**S(2))) + b*x**S(5)/(S(4)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)/sqrt(c*x**S(2)), x), x, a*x*sqrt(c*x**S(2))/(S(2)*c) + b*x**S(2)*sqrt(c*x**S(2))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)/sqrt(c*x**S(2)), x), x, a*x**S(2)/sqrt(c*x**S(2)) + b*x**S(3)/(S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/sqrt(c*x**S(2)), x), x, a*x*log(x)/sqrt(c*x**S(2)) + b*x**S(2)/sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x*sqrt(c*x**S(2))), x), x, -a/sqrt(c*x**S(2)) + b*x*log(x)/sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(2)*sqrt(c*x**S(2))), x), x, -a/(S(2)*x*sqrt(c*x**S(2))) - b/sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(3)*sqrt(c*x**S(2))), x), x, -a/(S(3)*x**S(2)*sqrt(c*x**S(2))) - b/(S(2)*x*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(4)*sqrt(c*x**S(2))), x), x, -a/(S(4)*x**S(3)*sqrt(c*x**S(2))) - b/(S(3)*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*x)/(c*x**S(2))**(S(3)/2), x), x, -a*x**(m + S(-1))/(c*sqrt(c*x**S(2))*(-m + S(2))) - b*x**m/(c*sqrt(c*x**S(2))*(-m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)/(c*x**S(2))**(S(3)/2), x), x, a*x**S(2)/(c*sqrt(c*x**S(2))) + b*x**S(3)/(S(2)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)/(c*x**S(2))**(S(3)/2), x), x, a*x*log(x)/(c*sqrt(c*x**S(2))) + b*x**S(2)/(c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)/(c*x**S(2))**(S(3)/2), x), x, -a/(c*sqrt(c*x**S(2))) + b*x*log(x)/(c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(c*x**S(2))**(S(3)/2), x), x, -a/(S(2)*c*x*sqrt(c*x**S(2))) - b/(c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x*(c*x**S(2))**(S(3)/2)), x), x, -a/(S(3)*c*x**S(2)*sqrt(c*x**S(2))) - b/(S(2)*c*x*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(2)*(c*x**S(2))**(S(3)/2)), x), x, -a/(S(4)*c*x**S(3)*sqrt(c*x**S(2))) - b/(S(3)*c*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(3)*(c*x**S(2))**(S(3)/2)), x), x, -a/(S(5)*c*x**S(4)*sqrt(c*x**S(2))) - b/(S(4)*c*x**S(3)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(4)*(c*x**S(2))**(S(3)/2)), x), x, -a/(S(6)*c*x**S(5)*sqrt(c*x**S(2))) - b/(S(5)*c*x**S(4)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*x)/(c*x**S(2))**(S(5)/2), x), x, -a*x**(m + S(-3))/(c**S(2)*sqrt(c*x**S(2))*(-m + S(4))) - b*x**(m + S(-2))/(c**S(2)*sqrt(c*x**S(2))*(-m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)/(c*x**S(2))**(S(5)/2), x), x, -a/(c**S(2)*sqrt(c*x**S(2))) + b*x*log(x)/(c**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)/(c*x**S(2))**(S(5)/2), x), x, -a/(S(2)*c**S(2)*x*sqrt(c*x**S(2))) - b/(c**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)/(c*x**S(2))**(S(5)/2), x), x, -a/(S(3)*c**S(2)*x**S(2)*sqrt(c*x**S(2))) - b/(S(2)*c**S(2)*x*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(c*x**S(2))**(S(5)/2), x), x, -a/(S(4)*c**S(2)*x**S(3)*sqrt(c*x**S(2))) - b/(S(3)*c**S(2)*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x*(c*x**S(2))**(S(5)/2)), x), x, -a/(S(5)*c**S(2)*x**S(4)*sqrt(c*x**S(2))) - b/(S(4)*c**S(2)*x**S(3)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(2)*(c*x**S(2))**(S(5)/2)), x), x, -a/(S(6)*c**S(2)*x**S(5)*sqrt(c*x**S(2))) - b/(S(5)*c**S(2)*x**S(4)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(3)*(c*x**S(2))**(S(5)/2)), x), x, -a/(S(7)*c**S(2)*x**S(6)*sqrt(c*x**S(2))) - b/(S(6)*c**S(2)*x**S(5)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)/(x**S(4)*(c*x**S(2))**(S(5)/2)), x), x, -a/(S(8)*c**S(2)*x**S(7)*sqrt(c*x**S(2))) - b/(S(7)*c**S(2)*x**S(6)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(c*x**S(2))*(a + b*x)**S(2), x), x, a**S(2)*x**(m + S(1))*sqrt(c*x**S(2))/(m + S(2)) + S(2)*a*b*x**(m + S(2))*sqrt(c*x**S(2))/(m + S(3)) + b**S(2)*x**(m + S(3))*sqrt(c*x**S(2))/(m + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(c*x**S(2))*(a + b*x)**S(2), x), x, a**S(2)*x**S(4)*sqrt(c*x**S(2))/S(5) + a*b*x**S(5)*sqrt(c*x**S(2))/S(3) + b**S(2)*x**S(6)*sqrt(c*x**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(c*x**S(2))*(a + b*x)**S(2), x), x, a**S(2)*x**S(3)*sqrt(c*x**S(2))/S(4) + S(2)*a*b*x**S(4)*sqrt(c*x**S(2))/S(5) + b**S(2)*x**S(5)*sqrt(c*x**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(c*x**S(2))*(a + b*x)**S(2), x), x, a**S(2)*x**S(2)*sqrt(c*x**S(2))/S(3) + a*b*x**S(3)*sqrt(c*x**S(2))/S(2) + b**S(2)*x**S(4)*sqrt(c*x**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**S(2), x), x, a**S(2)*x*sqrt(c*x**S(2))/S(2) + S(2)*a*b*x**S(2)*sqrt(c*x**S(2))/S(3) + b**S(2)*x**S(3)*sqrt(c*x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**S(2)/x, x), x, sqrt(c*x**S(2))*(a + b*x)**S(3)/(S(3)*b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**S(2)/x**S(2), x), x, a**S(2)*sqrt(c*x**S(2))*log(x)/x + S(2)*a*b*sqrt(c*x**S(2)) + b**S(2)*x*sqrt(c*x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**S(2)/x**S(3), x), x, -a**S(2)*sqrt(c*x**S(2))/x**S(2) + S(2)*a*b*sqrt(c*x**S(2))*log(x)/x + b**S(2)*sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))*(a + b*x)**S(2)/x**S(4), x), x, -a**S(2)*sqrt(c*x**S(2))/(S(2)*x**S(3)) - S(2)*a*b*sqrt(c*x**S(2))/x**S(2) + b**S(2)*sqrt(c*x**S(2))*log(x)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(c*x**S(2))**(S(3)/2)*(a + b*x)**S(2), x), x, a**S(2)*c*x**(m + S(3))*sqrt(c*x**S(2))/(m + S(4)) + S(2)*a*b*c*x**(m + S(4))*sqrt(c*x**S(2))/(m + S(5)) + b**S(2)*c*x**(m + S(5))*sqrt(c*x**S(2))/(m + S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(c*x**S(2))**(S(3)/2)*(a + b*x)**S(2), x), x, a**S(2)*c*x**S(6)*sqrt(c*x**S(2))/S(7) + a*b*c*x**S(7)*sqrt(c*x**S(2))/S(4) + b**S(2)*c*x**S(8)*sqrt(c*x**S(2))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c*x**S(2))**(S(3)/2)*(a + b*x)**S(2), x), x, a**S(2)*c*x**S(5)*sqrt(c*x**S(2))/S(6) + S(2)*a*b*c*x**S(6)*sqrt(c*x**S(2))/S(7) + b**S(2)*c*x**S(7)*sqrt(c*x**S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**(S(3)/2)*(a + b*x)**S(2), x), x, a**S(2)*c*x**S(4)*sqrt(c*x**S(2))/S(5) + a*b*c*x**S(5)*sqrt(c*x**S(2))/S(3) + b**S(2)*c*x**S(6)*sqrt(c*x**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2), x), x, a**S(2)*c*x**S(3)*sqrt(c*x**S(2))/S(4) + S(2)*a*b*c*x**S(4)*sqrt(c*x**S(2))/S(5) + b**S(2)*c*x**S(5)*sqrt(c*x**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)/x, x), x, a**S(2)*c*x**S(2)*sqrt(c*x**S(2))/S(3) + a*b*c*x**S(3)*sqrt(c*x**S(2))/S(2) + b**S(2)*c*x**S(4)*sqrt(c*x**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)/x**S(2), x), x, a**S(2)*c*x*sqrt(c*x**S(2))/S(2) + S(2)*a*b*c*x**S(2)*sqrt(c*x**S(2))/S(3) + b**S(2)*c*x**S(3)*sqrt(c*x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)/x**S(3), x), x, c*sqrt(c*x**S(2))*(a + b*x)**S(3)/(S(3)*b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)/x**S(4), x), x, a**S(2)*c*sqrt(c*x**S(2))*log(x)/x + S(2)*a*b*c*sqrt(c*x**S(2)) + b**S(2)*c*x*sqrt(c*x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(c*x**S(2))**(S(5)/2)*(a + b*x)**S(2), x), x, a**S(2)*c**S(2)*x**(m + S(5))*sqrt(c*x**S(2))/(m + S(6)) + S(2)*a*b*c**S(2)*x**(m + S(6))*sqrt(c*x**S(2))/(m + S(7)) + b**S(2)*c**S(2)*x**(m + S(7))*sqrt(c*x**S(2))/(m + S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(c*x**S(2))**(S(5)/2)*(a + b*x)**S(2), x), x, a**S(2)*c**S(2)*x**S(8)*sqrt(c*x**S(2))/S(9) + a*b*c**S(2)*x**S(9)*sqrt(c*x**S(2))/S(5) + b**S(2)*c**S(2)*x**S(10)*sqrt(c*x**S(2))/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c*x**S(2))**(S(5)/2)*(a + b*x)**S(2), x), x, a**S(2)*c**S(2)*x**S(7)*sqrt(c*x**S(2))/S(8) + S(2)*a*b*c**S(2)*x**S(8)*sqrt(c*x**S(2))/S(9) + b**S(2)*c**S(2)*x**S(9)*sqrt(c*x**S(2))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**(S(5)/2)*(a + b*x)**S(2), x), x, a**S(2)*c**S(2)*x**S(6)*sqrt(c*x**S(2))/S(7) + a*b*c**S(2)*x**S(7)*sqrt(c*x**S(2))/S(4) + b**S(2)*c**S(2)*x**S(8)*sqrt(c*x**S(2))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**S(2), x), x, a**S(2)*c**S(2)*x**S(5)*sqrt(c*x**S(2))/S(6) + S(2)*a*b*c**S(2)*x**S(6)*sqrt(c*x**S(2))/S(7) + b**S(2)*c**S(2)*x**S(7)*sqrt(c*x**S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**S(2)/x, x), x, a**S(2)*c**S(2)*x**S(4)*sqrt(c*x**S(2))/S(5) + a*b*c**S(2)*x**S(5)*sqrt(c*x**S(2))/S(3) + b**S(2)*c**S(2)*x**S(6)*sqrt(c*x**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**S(2)/x**S(2), x), x, a**S(2)*c**S(2)*x**S(3)*sqrt(c*x**S(2))/S(4) + S(2)*a*b*c**S(2)*x**S(4)*sqrt(c*x**S(2))/S(5) + b**S(2)*c**S(2)*x**S(5)*sqrt(c*x**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**S(2)/x**S(3), x), x, a**S(2)*c**S(2)*x**S(2)*sqrt(c*x**S(2))/S(3) + a*b*c**S(2)*x**S(3)*sqrt(c*x**S(2))/S(2) + b**S(2)*c**S(2)*x**S(4)*sqrt(c*x**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)*(a + b*x)**S(2)/x**S(4), x), x, a**S(2)*c**S(2)*x*sqrt(c*x**S(2))/S(2) + S(2)*a*b*c**S(2)*x**S(2)*sqrt(c*x**S(2))/S(3) + b**S(2)*c**S(2)*x**S(3)*sqrt(c*x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*x)**S(2)/sqrt(c*x**S(2)), x), x, a**S(2)*x**(m + S(1))/(m*sqrt(c*x**S(2))) + S(2)*a*b*x**(m + S(2))/(sqrt(c*x**S(2))*(m + S(1))) + b**S(2)*x**(m + S(3))/(sqrt(c*x**S(2))*(m + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)**S(2)/sqrt(c*x**S(2)), x), x, a**S(2)*x**S(4)/(S(3)*sqrt(c*x**S(2))) + a*b*x**S(5)/(S(2)*sqrt(c*x**S(2))) + b**S(2)*x**S(6)/(S(5)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**S(2)/sqrt(c*x**S(2)), x), x, a**S(2)*x*sqrt(c*x**S(2))/(S(2)*c) + S(2)*a*b*x**S(2)*sqrt(c*x**S(2))/(S(3)*c) + b**S(2)*x**S(3)*sqrt(c*x**S(2))/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**S(2)/sqrt(c*x**S(2)), x), x, x*(a + b*x)**S(3)/(S(3)*b*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/sqrt(c*x**S(2)), x), x, a**S(2)*x*log(x)/sqrt(c*x**S(2)) + S(2)*a*b*x**S(2)/sqrt(c*x**S(2)) + b**S(2)*x**S(3)/(S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x*sqrt(c*x**S(2))), x), x, -a**S(2)/sqrt(c*x**S(2)) + S(2)*a*b*x*log(x)/sqrt(c*x**S(2)) + b**S(2)*x**S(2)/sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(2)*sqrt(c*x**S(2))), x), x, -a**S(2)/(S(2)*x*sqrt(c*x**S(2))) - S(2)*a*b/sqrt(c*x**S(2)) + b**S(2)*x*log(x)/sqrt(c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(3)*sqrt(c*x**S(2))), x), x, -(a + b*x)**S(3)/(S(3)*a*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(4)*sqrt(c*x**S(2))), x), x, -a**S(2)/(S(4)*x**S(3)*sqrt(c*x**S(2))) - S(2)*a*b/(S(3)*x**S(2)*sqrt(c*x**S(2))) - b**S(2)/(S(2)*x*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*x)**S(2)/(c*x**S(2))**(S(3)/2), x), x, -a**S(2)*x**(m + S(-1))/(c*sqrt(c*x**S(2))*(-m + S(2))) - S(2)*a*b*x**m/(c*sqrt(c*x**S(2))*(-m + S(1))) + b**S(2)*x**(m + S(1))/(c*m*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)**S(2)/(c*x**S(2))**(S(3)/2), x), x, x*(a + b*x)**S(3)/(S(3)*b*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**S(2)/(c*x**S(2))**(S(3)/2), x), x, a**S(2)*x*log(x)/(c*sqrt(c*x**S(2))) + S(2)*a*b*x**S(2)/(c*sqrt(c*x**S(2))) + b**S(2)*x**S(3)/(S(2)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**S(2)/(c*x**S(2))**(S(3)/2), x), x, -a**S(2)/(c*sqrt(c*x**S(2))) + S(2)*a*b*x*log(x)/(c*sqrt(c*x**S(2))) + b**S(2)*x**S(2)/(c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(c*x**S(2))**(S(3)/2), x), x, -a**S(2)/(S(2)*c*x*sqrt(c*x**S(2))) - S(2)*a*b/(c*sqrt(c*x**S(2))) + b**S(2)*x*log(x)/(c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x*(c*x**S(2))**(S(3)/2)), x), x, -(a + b*x)**S(3)/(S(3)*a*c*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(2)*(c*x**S(2))**(S(3)/2)), x), x, -a**S(2)/(S(4)*c*x**S(3)*sqrt(c*x**S(2))) - S(2)*a*b/(S(3)*c*x**S(2)*sqrt(c*x**S(2))) - b**S(2)/(S(2)*c*x*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(3)*(c*x**S(2))**(S(3)/2)), x), x, -a**S(2)/(S(5)*c*x**S(4)*sqrt(c*x**S(2))) - a*b/(S(2)*c*x**S(3)*sqrt(c*x**S(2))) - b**S(2)/(S(3)*c*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(4)*(c*x**S(2))**(S(3)/2)), x), x, -a**S(2)/(S(6)*c*x**S(5)*sqrt(c*x**S(2))) - S(2)*a*b/(S(5)*c*x**S(4)*sqrt(c*x**S(2))) - b**S(2)/(S(4)*c*x**S(3)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a + b*x)**S(2)/(c*x**S(2))**(S(5)/2), x), x, -a**S(2)*x**(m + S(-3))/(c**S(2)*sqrt(c*x**S(2))*(-m + S(4))) - S(2)*a*b*x**(m + S(-2))/(c**S(2)*sqrt(c*x**S(2))*(-m + S(3))) - b**S(2)*x**(m + S(-1))/(c**S(2)*sqrt(c*x**S(2))*(-m + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x)**S(2)/(c*x**S(2))**(S(5)/2), x), x, -a**S(2)/(c**S(2)*sqrt(c*x**S(2))) + S(2)*a*b*x*log(x)/(c**S(2)*sqrt(c*x**S(2))) + b**S(2)*x**S(2)/(c**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x)**S(2)/(c*x**S(2))**(S(5)/2), x), x, -a**S(2)/(S(2)*c**S(2)*x*sqrt(c*x**S(2))) - S(2)*a*b/(c**S(2)*sqrt(c*x**S(2))) + b**S(2)*x*log(x)/(c**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x)**S(2)/(c*x**S(2))**(S(5)/2), x), x, -(a + b*x)**S(3)/(S(3)*a*c**S(2)*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(c*x**S(2))**(S(5)/2), x), x, -a**S(2)/(S(4)*c**S(2)*x**S(3)*sqrt(c*x**S(2))) - S(2)*a*b/(S(3)*c**S(2)*x**S(2)*sqrt(c*x**S(2))) - b**S(2)/(S(2)*c**S(2)*x*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x*(c*x**S(2))**(S(5)/2)), x), x, -a**S(2)/(S(5)*c**S(2)*x**S(4)*sqrt(c*x**S(2))) - a*b/(S(2)*c**S(2)*x**S(3)*sqrt(c*x**S(2))) - b**S(2)/(S(3)*c**S(2)*x**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(2)*(c*x**S(2))**(S(5)/2)), x), x, -a**S(2)/(S(6)*c**S(2)*x**S(5)*sqrt(c*x**S(2))) - S(2)*a*b/(S(5)*c**S(2)*x**S(4)*sqrt(c*x**S(2))) - b**S(2)/(S(4)*c**S(2)*x**S(3)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(3)*(c*x**S(2))**(S(5)/2)), x), x, -a**S(2)/(S(7)*c**S(2)*x**S(6)*sqrt(c*x**S(2))) - a*b/(S(3)*c**S(2)*x**S(5)*sqrt(c*x**S(2))) - b**S(2)/(S(5)*c**S(2)*x**S(4)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)**S(2)/(x**S(4)*(c*x**S(2))**(S(5)/2)), x), x, -a**S(2)/(S(8)*c**S(2)*x**S(7)*sqrt(c*x**S(2))) - S(2)*a*b/(S(7)*c**S(2)*x**S(6)*sqrt(c*x**S(2))) - b**S(2)/(S(6)*c**S(2)*x**S(5)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(c*x**S(2))/(a + b*x), x), x, a**S(4)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(5)*x) - a**S(3)*sqrt(c*x**S(2))/b**S(4) + a**S(2)*x*sqrt(c*x**S(2))/(S(2)*b**S(3)) - a*x**S(2)*sqrt(c*x**S(2))/(S(3)*b**S(2)) + x**S(3)*sqrt(c*x**S(2))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(c*x**S(2))/(a + b*x), x), x, -a**S(3)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(4)*x) + a**S(2)*sqrt(c*x**S(2))/b**S(3) - a*x*sqrt(c*x**S(2))/(S(2)*b**S(2)) + x**S(2)*sqrt(c*x**S(2))/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(c*x**S(2))/(a + b*x), x), x, a**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(3)*x) - a*sqrt(c*x**S(2))/b**S(2) + x*sqrt(c*x**S(2))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(a + b*x), x), x, -a*sqrt(c*x**S(2))*log(a + b*x)/(b**S(2)*x) + sqrt(c*x**S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x*(a + b*x)), x), x, sqrt(c*x**S(2))*log(a + b*x)/(b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x**S(2)*(a + b*x)), x), x, sqrt(c*x**S(2))*log(x)/(a*x) - sqrt(c*x**S(2))*log(a + b*x)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x**S(3)*(a + b*x)), x), x, -sqrt(c*x**S(2))/(a*x**S(2)) - b*sqrt(c*x**S(2))*log(x)/(a**S(2)*x) + b*sqrt(c*x**S(2))*log(a + b*x)/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x**S(4)*(a + b*x)), x), x, -sqrt(c*x**S(2))/(S(2)*a*x**S(3)) + b*sqrt(c*x**S(2))/(a**S(2)*x**S(2)) + b**S(2)*sqrt(c*x**S(2))*log(x)/(a**S(3)*x) - b**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(a**S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**(S(3)/2)/(a + b*x), x), x, a**S(4)*c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(5)*x) - a**S(3)*c*sqrt(c*x**S(2))/b**S(4) + a**S(2)*c*x*sqrt(c*x**S(2))/(S(2)*b**S(3)) - a*c*x**S(2)*sqrt(c*x**S(2))/(S(3)*b**S(2)) + c*x**S(3)*sqrt(c*x**S(2))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(a + b*x), x), x, -a**S(3)*c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(4)*x) + a**S(2)*c*sqrt(c*x**S(2))/b**S(3) - a*c*x*sqrt(c*x**S(2))/(S(2)*b**S(2)) + c*x**S(2)*sqrt(c*x**S(2))/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x*(a + b*x)), x), x, a**S(2)*c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(3)*x) - a*c*sqrt(c*x**S(2))/b**S(2) + c*x*sqrt(c*x**S(2))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(2)*(a + b*x)), x), x, -a*c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(2)*x) + c*sqrt(c*x**S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(3)*(a + b*x)), x), x, c*sqrt(c*x**S(2))*log(a + b*x)/(b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(4)*(a + b*x)), x), x, c*sqrt(c*x**S(2))*log(x)/(a*x) - c*sqrt(c*x**S(2))*log(a + b*x)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(5)*(a + b*x)), x), x, -c*sqrt(c*x**S(2))/(a*x**S(2)) - b*c*sqrt(c*x**S(2))*log(x)/(a**S(2)*x) + b*c*sqrt(c*x**S(2))*log(a + b*x)/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(6)*(a + b*x)), x), x, -c*sqrt(c*x**S(2))/(S(2)*a*x**S(3)) + b*c*sqrt(c*x**S(2))/(a**S(2)*x**S(2)) + b**S(2)*c*sqrt(c*x**S(2))*log(x)/(a**S(3)*x) - b**S(2)*c*sqrt(c*x**S(2))*log(a + b*x)/(a**S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(7)*(a + b*x)), x), x, -c*sqrt(c*x**S(2))/(S(3)*a*x**S(4)) + b*c*sqrt(c*x**S(2))/(S(2)*a**S(2)*x**S(3)) - b**S(2)*c*sqrt(c*x**S(2))/(a**S(3)*x**S(2)) - b**S(3)*c*sqrt(c*x**S(2))*log(x)/(a**S(4)*x) + b**S(3)*c*sqrt(c*x**S(2))*log(a + b*x)/(a**S(4)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(a + b*x), x), x, -a**S(5)*c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(6)*x) + a**S(4)*c**S(2)*sqrt(c*x**S(2))/b**S(5) - a**S(3)*c**S(2)*x*sqrt(c*x**S(2))/(S(2)*b**S(4)) + a**S(2)*c**S(2)*x**S(2)*sqrt(c*x**S(2))/(S(3)*b**S(3)) - a*c**S(2)*x**S(3)*sqrt(c*x**S(2))/(S(4)*b**S(2)) + c**S(2)*x**S(4)*sqrt(c*x**S(2))/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(x*(a + b*x)), x), x, a**S(4)*c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(5)*x) - a**S(3)*c**S(2)*sqrt(c*x**S(2))/b**S(4) + a**S(2)*c**S(2)*x*sqrt(c*x**S(2))/(S(2)*b**S(3)) - a*c**S(2)*x**S(2)*sqrt(c*x**S(2))/(S(3)*b**S(2)) + c**S(2)*x**S(3)*sqrt(c*x**S(2))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(x**S(2)*(a + b*x)), x), x, -a**S(3)*c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(4)*x) + a**S(2)*c**S(2)*sqrt(c*x**S(2))/b**S(3) - a*c**S(2)*x*sqrt(c*x**S(2))/(S(2)*b**S(2)) + c**S(2)*x**S(2)*sqrt(c*x**S(2))/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(x**S(3)*(a + b*x)), x), x, a**S(2)*c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(3)*x) - a*c**S(2)*sqrt(c*x**S(2))/b**S(2) + c**S(2)*x*sqrt(c*x**S(2))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(x**S(4)*(a + b*x)), x), x, -a*c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(2)*x) + c**S(2)*sqrt(c*x**S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(x**S(5)*(a + b*x)), x), x, c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(x**S(6)*(a + b*x)), x), x, c**S(2)*sqrt(c*x**S(2))*log(x)/(a*x) - c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(5)/2)/(x**S(7)*(a + b*x)), x), x, -c**S(2)*sqrt(c*x**S(2))/(a*x**S(2)) - b*c**S(2)*sqrt(c*x**S(2))*log(x)/(a**S(2)*x) + b*c**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(sqrt(c*x**S(2))*(a + b*x)), x), x, -a**S(3)*x*log(a + b*x)/(b**S(4)*sqrt(c*x**S(2))) + a**S(2)*x**S(2)/(b**S(3)*sqrt(c*x**S(2))) - a*x**S(3)/(S(2)*b**S(2)*sqrt(c*x**S(2))) + x**S(4)/(S(3)*b*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(sqrt(c*x**S(2))*(a + b*x)), x), x, a**S(2)*x*log(a + b*x)/(b**S(3)*sqrt(c*x**S(2))) - a*x**S(2)/(b**S(2)*sqrt(c*x**S(2))) + x**S(3)/(S(2)*b*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(c*x**S(2))*(a + b*x)), x), x, -a*sqrt(c*x**S(2))*log(a + b*x)/(b**S(2)*c*x) + sqrt(c*x**S(2))/(b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(c*x**S(2))*(a + b*x)), x), x, x*log(a + b*x)/(b*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*x**S(2))*(a + b*x)), x), x, x*log(x)/(a*sqrt(c*x**S(2))) - x*log(a + b*x)/(a*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(c*x**S(2))*(a + b*x)), x), x, -S(1)/(a*sqrt(c*x**S(2))) - b*x*log(x)/(a**S(2)*sqrt(c*x**S(2))) + b*x*log(a + b*x)/(a**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(c*x**S(2))*(a + b*x)), x), x, -S(1)/(S(2)*a*x*sqrt(c*x**S(2))) + b/(a**S(2)*sqrt(c*x**S(2))) + b**S(2)*x*log(x)/(a**S(3)*sqrt(c*x**S(2))) - b**S(2)*x*log(a + b*x)/(a**S(3)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(c*x**S(2))*(a + b*x)), x), x, -S(1)/(S(3)*a*x**S(2)*sqrt(c*x**S(2))) + b/(S(2)*a**S(2)*x*sqrt(c*x**S(2))) - b**S(2)/(a**S(3)*sqrt(c*x**S(2))) - b**S(3)*x*log(x)/(a**S(4)*sqrt(c*x**S(2))) + b**S(3)*x*log(a + b*x)/(a**S(4)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/((c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, -a**S(3)*x*log(a + b*x)/(b**S(4)*c*sqrt(c*x**S(2))) + a**S(2)*x**S(2)/(b**S(3)*c*sqrt(c*x**S(2))) - a*x**S(3)/(S(2)*b**S(2)*c*sqrt(c*x**S(2))) + x**S(4)/(S(3)*b*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/((c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, a**S(2)*x*log(a + b*x)/(b**S(3)*c*sqrt(c*x**S(2))) - a*x**S(2)/(b**S(2)*c*sqrt(c*x**S(2))) + x**S(3)/(S(2)*b*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/((c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, -a*x*log(a + b*x)/(b**S(2)*c*sqrt(c*x**S(2))) + x**S(2)/(b*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/((c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, x*log(a + b*x)/(b*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, x*log(x)/(a*c*sqrt(c*x**S(2))) - x*log(a + b*x)/(a*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, -S(1)/(a*c*sqrt(c*x**S(2))) - b*x*log(x)/(a**S(2)*c*sqrt(c*x**S(2))) + b*x*log(a + b*x)/(a**S(2)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, -S(1)/(S(2)*a*c*x*sqrt(c*x**S(2))) + b/(a**S(2)*c*sqrt(c*x**S(2))) + b**S(2)*x*log(x)/(a**S(3)*c*sqrt(c*x**S(2))) - b**S(2)*x*log(a + b*x)/(a**S(3)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(c*x**S(2))**(S(3)/2)*(a + b*x)), x), x, -S(1)/(S(3)*a*c*x**S(2)*sqrt(c*x**S(2))) + b/(S(2)*a**S(2)*c*x*sqrt(c*x**S(2))) - b**S(2)/(a**S(3)*c*sqrt(c*x**S(2))) - b**S(3)*x*log(x)/(a**S(4)*c*sqrt(c*x**S(2))) + b**S(3)*x*log(a + b*x)/(a**S(4)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(c*x**S(2))/(a + b*x)**S(2), x), x, -a**S(4)*sqrt(c*x**S(2))/(b**S(5)*x*(a + b*x)) - S(4)*a**S(3)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(5)*x) + S(3)*a**S(2)*sqrt(c*x**S(2))/b**S(4) - a*x*sqrt(c*x**S(2))/b**S(3) + x**S(2)*sqrt(c*x**S(2))/(S(3)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(c*x**S(2))/(a + b*x)**S(2), x), x, a**S(3)*sqrt(c*x**S(2))/(b**S(4)*x*(a + b*x)) + S(3)*a**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(b**S(4)*x) - S(2)*a*sqrt(c*x**S(2))/b**S(3) + x*sqrt(c*x**S(2))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(c*x**S(2))/(a + b*x)**S(2), x), x, -a**S(2)*sqrt(c*x**S(2))/(b**S(3)*x*(a + b*x)) - S(2)*a*sqrt(c*x**S(2))*log(a + b*x)/(b**S(3)*x) + sqrt(c*x**S(2))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(a + b*x)**S(2), x), x, a*sqrt(c*x**S(2))/(b**S(2)*x*(a + b*x)) + sqrt(c*x**S(2))*log(a + b*x)/(b**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x*(a + b*x)**S(2)), x), x, -sqrt(c*x**S(2))/(b*x*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x**S(2)*(a + b*x)**S(2)), x), x, sqrt(c*x**S(2))/(a*x*(a + b*x)) + sqrt(c*x**S(2))*log(x)/(a**S(2)*x) - sqrt(c*x**S(2))*log(a + b*x)/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x**S(3)*(a + b*x)**S(2)), x), x, -b*sqrt(c*x**S(2))/(a**S(2)*x*(a + b*x)) - sqrt(c*x**S(2))/(a**S(2)*x**S(2)) - S(2)*b*sqrt(c*x**S(2))*log(x)/(a**S(3)*x) + S(2)*b*sqrt(c*x**S(2))*log(a + b*x)/(a**S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*x**S(2))/(x**S(4)*(a + b*x)**S(2)), x), x, -sqrt(c*x**S(2))/(S(2)*a**S(2)*x**S(3)) + b**S(2)*sqrt(c*x**S(2))/(a**S(3)*x*(a + b*x)) + S(2)*b*sqrt(c*x**S(2))/(a**S(3)*x**S(2)) + S(3)*b**S(2)*sqrt(c*x**S(2))*log(x)/(a**S(4)*x) - S(3)*b**S(2)*sqrt(c*x**S(2))*log(a + b*x)/(a**S(4)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**(S(3)/2)/(a + b*x)**S(2), x), x, -a**S(4)*c*sqrt(c*x**S(2))/(b**S(5)*x*(a + b*x)) - S(4)*a**S(3)*c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(5)*x) + S(3)*a**S(2)*c*sqrt(c*x**S(2))/b**S(4) - a*c*x*sqrt(c*x**S(2))/b**S(3) + c*x**S(2)*sqrt(c*x**S(2))/(S(3)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(a + b*x)**S(2), x), x, a**S(3)*c*sqrt(c*x**S(2))/(b**S(4)*x*(a + b*x)) + S(3)*a**S(2)*c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(4)*x) - S(2)*a*c*sqrt(c*x**S(2))/b**S(3) + c*x*sqrt(c*x**S(2))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x*(a + b*x)**S(2)), x), x, -a**S(2)*c*sqrt(c*x**S(2))/(b**S(3)*x*(a + b*x)) - S(2)*a*c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(3)*x) + c*sqrt(c*x**S(2))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(2)*(a + b*x)**S(2)), x), x, a*c*sqrt(c*x**S(2))/(b**S(2)*x*(a + b*x)) + c*sqrt(c*x**S(2))*log(a + b*x)/(b**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(3)*(a + b*x)**S(2)), x), x, -c*sqrt(c*x**S(2))/(b*x*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(4)*(a + b*x)**S(2)), x), x, c*sqrt(c*x**S(2))/(a*x*(a + b*x)) + c*sqrt(c*x**S(2))*log(x)/(a**S(2)*x) - c*sqrt(c*x**S(2))*log(a + b*x)/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(5)*(a + b*x)**S(2)), x), x, -b*c*sqrt(c*x**S(2))/(a**S(2)*x*(a + b*x)) - c*sqrt(c*x**S(2))/(a**S(2)*x**S(2)) - S(2)*b*c*sqrt(c*x**S(2))*log(x)/(a**S(3)*x) + S(2)*b*c*sqrt(c*x**S(2))*log(a + b*x)/(a**S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**(S(3)/2)/(x**S(6)*(a + b*x)**S(2)), x), x, -c*sqrt(c*x**S(2))/(S(2)*a**S(2)*x**S(3)) + b**S(2)*c*sqrt(c*x**S(2))/(a**S(3)*x*(a + b*x)) + S(2)*b*c*sqrt(c*x**S(2))/(a**S(3)*x**S(2)) + S(3)*b**S(2)*c*sqrt(c*x**S(2))*log(x)/(a**S(4)*x) - S(3)*b**S(2)*c*sqrt(c*x**S(2))*log(a + b*x)/(a**S(4)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, -a**S(4)*x/(b**S(5)*sqrt(c*x**S(2))*(a + b*x)) - S(4)*a**S(3)*x*log(a + b*x)/(b**S(5)*sqrt(c*x**S(2))) + S(3)*a**S(2)*x**S(2)/(b**S(4)*sqrt(c*x**S(2))) - a*x**S(3)/(b**S(3)*sqrt(c*x**S(2))) + x**S(4)/(S(3)*b**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, a**S(3)*x/(b**S(4)*sqrt(c*x**S(2))*(a + b*x)) + S(3)*a**S(2)*x*log(a + b*x)/(b**S(4)*sqrt(c*x**S(2))) - S(2)*a*x**S(2)/(b**S(3)*sqrt(c*x**S(2))) + x**S(3)/(S(2)*b**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, -a**S(2)*x/(b**S(3)*sqrt(c*x**S(2))*(a + b*x)) - S(2)*a*x*log(a + b*x)/(b**S(3)*sqrt(c*x**S(2))) + x**S(2)/(b**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, a*sqrt(c*x**S(2))/(b**S(2)*c*x*(a + b*x)) + sqrt(c*x**S(2))*log(a + b*x)/(b**S(2)*c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, -x/(b*sqrt(c*x**S(2))*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, x/(a*sqrt(c*x**S(2))*(a + b*x)) + x*log(x)/(a**S(2)*sqrt(c*x**S(2))) - x*log(a + b*x)/(a**S(2)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, -b*x/(a**S(2)*sqrt(c*x**S(2))*(a + b*x)) - S(1)/(a**S(2)*sqrt(c*x**S(2))) - S(2)*b*x*log(x)/(a**S(3)*sqrt(c*x**S(2))) + S(2)*b*x*log(a + b*x)/(a**S(3)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(c*x**S(2))*(a + b*x)**S(2)), x), x, -S(1)/(S(2)*a**S(2)*x*sqrt(c*x**S(2))) + b**S(2)*x/(a**S(3)*sqrt(c*x**S(2))*(a + b*x)) + S(2)*b/(a**S(3)*sqrt(c*x**S(2))) + S(3)*b**S(2)*x*log(x)/(a**S(4)*sqrt(c*x**S(2))) - S(3)*b**S(2)*x*log(a + b*x)/(a**S(4)*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)), x), x, -a**S(2)*x/(b**S(3)*c*sqrt(c*x**S(2))*(a + b*x)) - S(2)*a*x*log(a + b*x)/(b**S(3)*c*sqrt(c*x**S(2))) + x**S(2)/(b**S(2)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)), x), x, a*x/(b**S(2)*c*sqrt(c*x**S(2))*(a + b*x)) + x*log(a + b*x)/(b**S(2)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)), x), x, -x/(b*c*sqrt(c*x**S(2))*(a + b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)), x), x, x/(a*c*sqrt(c*x**S(2))*(a + b*x)) + x*log(x)/(a**S(2)*c*sqrt(c*x**S(2))) - x*log(a + b*x)/(a**S(2)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)), x), x, -b*x/(a**S(2)*c*sqrt(c*x**S(2))*(a + b*x)) - S(1)/(a**S(2)*c*sqrt(c*x**S(2))) - S(2)*b*x*log(x)/(a**S(3)*c*sqrt(c*x**S(2))) + S(2)*b*x*log(a + b*x)/(a**S(3)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*x**S(2))**(S(3)/2)*(a + b*x)**S(2)), x), x, -S(1)/(S(2)*a**S(2)*c*x*sqrt(c*x**S(2))) + b**S(2)*x/(a**S(3)*c*sqrt(c*x**S(2))*(a + b*x)) + S(2)*b/(a**S(3)*c*sqrt(c*x**S(2))) + S(3)*b**S(2)*x*log(x)/(a**S(4)*c*sqrt(c*x**S(2))) - S(3)*b**S(2)*x*log(a + b*x)/(a**S(4)*c*sqrt(c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(c*x**S(2))**p*(a + b*x)**(-m - S(2)*p + S(-2)), x), x, x**(m + S(1))*(c*x**S(2))**p*(a + b*x)**(-m - S(2)*p + S(-1))/(a*(m + S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-5)), x), x, x**S(4)*(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-4))/(S(2)*a*(p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-4)), x), x, x**S(3)*(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-3))/(a*(S(2)*p + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-3)), x), x, x**S(2)*(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-2))/(S(2)*a*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-2)), x), x, x*(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-1))/(a*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(-1))/x, x), x, (c*x**S(2))**p*(a + b*x)**(-S(2)*p)/(S(2)*a*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**p*(a + b*x)**(-S(2)*p)/x**S(2), x), x, -(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(1))/(a*x*(-S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(1))/x**S(3), x), x, -(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(2))/(S(2)*a*x**S(2)*(-p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(2))/x**S(4), x), x, -(c*x**S(2))**p*(a + b*x)**(-S(2)*p + S(3))/(a*x**S(3)*(-S(2)*p + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(23))/sqrt(x**S(5) + S(1)), x), x, sqrt(a*x**S(23))*sqrt(x**S(5) + S(1))/(S(10)*x**S(4)) - S(3)*sqrt(a*x**S(23))*sqrt(x**S(5) + S(1))/(S(20)*x**S(9)) + S(3)*sqrt(a*x**S(23))*asinh(x**(S(5)/2))/(S(20)*x**(S(23)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(13))/sqrt(x**S(5) + S(1)), x), x, sqrt(a*x**S(13))*sqrt(x**S(5) + S(1))/(S(5)*x**S(4)) - sqrt(a*x**S(13))*asinh(x**(S(5)/2))/(S(5)*x**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(3))/sqrt(x**S(5) + S(1)), x), x, S(2)*sqrt(a*x**S(3))*asinh(x**(S(5)/2))/(S(5)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(7))/sqrt(x**S(5) + S(1)), x), x, -S(2)*x*sqrt(a/x**S(7))*sqrt(x**S(5) + S(1))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(17))/sqrt(x**S(5) + S(1)), x), x, S(4)*x**S(6)*sqrt(a/x**S(17))*sqrt(x**S(5) + S(1))/S(15) - S(2)*x*sqrt(a/x**S(17))*sqrt(x**S(5) + S(1))/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(6))/(x*(-x**S(4) + S(1))), x), x, -sqrt(a*x**S(6))*atan(x)/(S(2)*x**S(3)) + sqrt(a*x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(6))/(-x**S(5) + x), x), x, -sqrt(a*x**S(6))*atan(x)/(S(2)*x**S(3)) + sqrt(a*x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(6))**(S(3)/2)/(x*(-x**S(4) + S(1))), x), x, -a*x**S(2)*sqrt(a*x**S(6))/S(5) - a*sqrt(a*x**S(6))/x**S(2) + a*sqrt(a*x**S(6))*atan(x)/(S(2)*x**S(3)) + a*sqrt(a*x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-x**S(4) + S(1)) - sqrt(a*x**S(6))/(x*(-x**S(4) + S(1))), x), x, atan(x)/S(2) + atanh(x)/S(2) + sqrt(a*x**S(6))*atan(x)/(S(2)*x**S(3)) - sqrt(a*x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-sqrt(a*x**S(6))/(-x**S(5) + x) + S(1)/(-x**S(4) + S(1)), x), x, atan(x)/S(2) + atanh(x)/S(2) + sqrt(a*x**S(6))*atan(x)/(S(2)*x**S(3)) - sqrt(a*x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(3))/(-x**S(3) + x), x), x, -sqrt(a*x**S(3))*atan(sqrt(x))/x**(S(3)/2) + sqrt(a*x**S(3))*atanh(sqrt(x))/x**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(4))/sqrt(x**S(2) + S(1)), x), x, sqrt(a*x**S(4))*sqrt(x**S(2) + S(1))/(S(2)*x) - sqrt(a*x**S(4))*asinh(x)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(3))/sqrt(x**S(2) + S(1)), x), x, S(2)*sqrt(a*x**S(3))*sqrt(x**S(2) + S(1))/(S(3)*x) - sqrt(a*x**S(3))*sqrt((x**S(2) + S(1))/(x + S(1))**S(2))*(x + S(1))*elliptic_f(S(2)*atan(sqrt(x)), S(1)/2)/(S(3)*x**(S(3)/2)*sqrt(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2))/sqrt(x**S(2) + S(1)), x), x, sqrt(a*x**S(2))*sqrt(x**S(2) + S(1))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x)/sqrt(x**S(2) + S(1)), x), x, -S(2)*sqrt(a)*sqrt((x**S(2) + S(1))/(x + S(1))**S(2))*(x + S(1))*elliptic_e(S(2)*atan(sqrt(a*x)/sqrt(a)), S(1)/2)/sqrt(x**S(2) + S(1)) + sqrt(a)*sqrt((x**S(2) + S(1))/(x + S(1))**S(2))*(x + S(1))*elliptic_f(S(2)*atan(sqrt(a*x)/sqrt(a)), S(1)/2)/sqrt(x**S(2) + S(1)) + S(2)*sqrt(a*x)*sqrt(x**S(2) + S(1))/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x)/sqrt(x**S(2) + S(1)), x), x, sqrt(x)*sqrt(a/x)*sqrt((x**S(2) + S(1))/(x + S(1))**S(2))*(x + S(1))*elliptic_f(S(2)*atan(sqrt(x)), S(1)/2)/sqrt(x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(2))/sqrt(x**S(2) + S(1)), x), x, -x*sqrt(a/x**S(2))*atanh(sqrt(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(3))/sqrt(x**S(2) + S(1)), x), x, -S(2)*x**(S(3)/2)*sqrt(a/x**S(3))*sqrt((x**S(2) + S(1))/(x + S(1))**S(2))*(x + S(1))*elliptic_e(S(2)*atan(sqrt(x)), S(1)/2)/sqrt(x**S(2) + S(1)) + x**(S(3)/2)*sqrt(a/x**S(3))*sqrt((x**S(2) + S(1))/(x + S(1))**S(2))*(x + S(1))*elliptic_f(S(2)*atan(sqrt(x)), S(1)/2)/sqrt(x**S(2) + S(1)) + S(2)*x**S(2)*sqrt(a/x**S(3))*sqrt(x**S(2) + S(1))/(x + S(1)) - S(2)*x*sqrt(a/x**S(3))*sqrt(x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(4))/sqrt(x**S(2) + S(1)), x), x, -x*sqrt(a/x**S(4))*sqrt(x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(4))/sqrt(x**S(3) + S(1)), x), x, S(2)*sqrt(a*x**S(4))*sqrt(x**S(3) + S(1))/(S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(3))/sqrt(x**S(3) + S(1)), x), x, -S(3)**(S(1)/4)*sqrt(a*x**S(3))*sqrt((x**S(2) - x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*(x + S(1))*elliptic_e(acos((x*(-sqrt(S(3)) + S(1)) + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))), sqrt(S(3))/S(4) + S(1)/2)/(x*sqrt(x*(x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*sqrt(x**S(3) + S(1))) - S(3)**(S(3)/4)*sqrt(a*x**S(3))*sqrt((x**S(2) - x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*(-sqrt(S(3)) + S(1))*(x + S(1))*elliptic_f(acos((x*(-sqrt(S(3)) + S(1)) + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))), sqrt(S(3))/S(4) + S(1)/2)/(S(6)*x*sqrt(x*(x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*sqrt(x**S(3) + S(1))) + sqrt(a*x**S(3))*(S(1) + sqrt(S(3)))*sqrt(x**S(3) + S(1))/(x*(x*(S(1) + sqrt(S(3))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2))/sqrt(x**S(3) + S(1)), x), x, S(2)*sqrt(a*x**S(2))*sqrt(x**S(3) + S(1))/(x*(x + S(1) + sqrt(S(3)))) - S(3)**(S(1)/4)*sqrt(a*x**S(2))*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-sqrt(S(3)) + S(2))*(x + S(1))*elliptic_e(asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(x*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))) + S(2)*sqrt(S(2))*S(3)**(S(3)/4)*sqrt(a*x**S(2))*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(x + S(1))*elliptic_f(asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(3)*x*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x)/sqrt(x**S(3) + S(1)), x), x, S(2)*sqrt(a)*asinh((a*x)**(S(3)/2)/a**(S(3)/2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x)/sqrt(x**S(3) + S(1)), x), x, S(3)**(S(3)/4)*x*sqrt(a/x)*sqrt((x**S(2) - x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*(x + S(1))*elliptic_f(acos((x*(-sqrt(S(3)) + S(1)) + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))), sqrt(S(3))/S(4) + S(1)/2)/(S(3)*sqrt(x*(x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*sqrt(x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(2))/sqrt(x**S(3) + S(1)), x), x, -S(2)*x*sqrt(a/x**S(2))*atanh(sqrt(x**S(3) + S(1)))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(3))/sqrt(x**S(3) + S(1)), x), x, -S(2)*S(3)**(S(1)/4)*x**S(2)*sqrt(a/x**S(3))*sqrt((x**S(2) - x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*(x + S(1))*elliptic_e(acos((x*(-sqrt(S(3)) + S(1)) + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))), sqrt(S(3))/S(4) + S(1)/2)/(sqrt(x*(x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*sqrt(x**S(3) + S(1))) - S(3)**(S(3)/4)*x**S(2)*sqrt(a/x**S(3))*sqrt((x**S(2) - x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*(-sqrt(S(3)) + S(1))*(x + S(1))*elliptic_f(acos((x*(-sqrt(S(3)) + S(1)) + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))), sqrt(S(3))/S(4) + S(1)/2)/(S(3)*sqrt(x*(x + S(1))/(x*(S(1) + sqrt(S(3))) + S(1))**S(2))*sqrt(x**S(3) + S(1))) + x**S(2)*sqrt(a/x**S(3))*(S(2) + S(2)*sqrt(S(3)))*sqrt(x**S(3) + S(1))/(x*(S(1) + sqrt(S(3))) + S(1)) - S(2)*x*sqrt(a/x**S(3))*sqrt(x**S(3) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a/x**S(4))/sqrt(x**S(3) + S(1)), x), x, x**S(2)*sqrt(a/x**S(4))*sqrt(x**S(3) + S(1))/(x + S(1) + sqrt(S(3))) - S(3)**(S(1)/4)*x**S(2)*sqrt(a/x**S(4))*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-sqrt(S(3)) + S(2))*(x + S(1))*elliptic_e(asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(2)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))) + sqrt(S(2))*S(3)**(S(3)/4)*x**S(2)*sqrt(a/x**S(4))*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(x + S(1))*elliptic_f(asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(3)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))) - x*sqrt(a/x**S(4))*sqrt(x**S(3) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**(S(2)*n))/sqrt(x**n + S(1)), x), x, x*sqrt(a*x**(S(2)*n))*hyper((S(1)/2, S(1) + S(1)/n), (S(2) + S(1)/n,), -x**n)/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**n)/sqrt(x**n + S(1)), x), x, S(2)*x*sqrt(a*x**n)*hyper((S(1)/2, S(1)/2 + S(1)/n), (S(3)/2 + S(1)/n,), -x**n)/(n + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**(n/S(2)))/sqrt(x**n + S(1)), x), x, S(4)*x*sqrt(a*x**(n/S(2)))*hyper((S(1)/2, S(1)/4 + S(1)/n), (S(5)/4 + S(1)/n,), -x**n)/(n + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**(S(2)*n))/sqrt(x**n + S(1)) + S(2)*x**(-n)*sqrt(a*x**(S(2)*n))/((n + S(2))*sqrt(x**n + S(1))), x), x, S(2)*x**(-n + S(1))*sqrt(a*x**(S(2)*n))*sqrt(x**n + S(1))/(n + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x)/(sqrt(d + e*x)*sqrt(e + f*x)), x), x, S(2)*sqrt(a*x)*sqrt(e*(e + f*x)/(-d*f + e**S(2)))*sqrt(d*f - e**S(2))*elliptic_e(asin(sqrt(f)*sqrt(d + e*x)/sqrt(d*f - e**S(2))), S(1) - e**S(2)/(d*f))/(e*sqrt(f)*sqrt(-e*x/d)*sqrt(e + f*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**m)**r, x), x, x*(a*x**m)**r/(m*r + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**m)**r*(b*x**n)**s, x), x, x*(a*x**m)**r*(b*x**n)**s/(m*r + n*s + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**m)**r*(b*x**n)**s*(c*x**p)**t, x), x, x*(a*x**m)**r*(b*x**n)**s*(c*x**p)**t/(m*r + n*s + p*t + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**p, x), x, -a*x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(1))/(b**S(2)*(p + S(1))) + x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**(p + S(2))/(b**S(2)*(p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**S(3), x), x, -a*x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**S(4)/(S(4)*b**S(2)) + x*(c*x**n)**(-S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**S(5)/(S(5)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)*(a + b*(c*x**n)**(S(1)/n))**S(2), x), x, a**S(2)*x*(c*x**n)**(S(1)/n)/S(2) + S(2)*a*b*x*(c*x**n)**(S(2)/n)/S(3) + b**S(2)*x*(c*x**n)**(S(3)/n)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)*(a + b*(c*x**n)**(S(1)/n)), x), x, a*x*(c*x**n)**(S(1)/n)/S(2) + b*x*(c*x**n)**(S(2)/n)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)/(a + b*(c*x**n)**(S(1)/n)), x), x, -a*x*(c*x**n)**(-S(1)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(2) + x/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)/(a + b*(c*x**n)**(S(1)/n))**S(2), x), x, a*x*(c*x**n)**(-S(1)/n)/(b**S(2)*(a + b*(c*x**n)**(S(1)/n))) + x*(c*x**n)**(-S(1)/n)*log(a + b*(c*x**n)**(S(1)/n))/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)/(a + b*(c*x**n)**(S(1)/n))**S(3), x), x, x*(c*x**n)**(S(1)/n)/(S(2)*a*(a + b*(c*x**n)**(S(1)/n))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)/(a + b*(c*x**n)**(S(1)/n))**S(4), x), x, a*x*(c*x**n)**(-S(1)/n)/(S(3)*b**S(2)*(a + b*(c*x**n)**(S(1)/n))**S(3)) - x*(c*x**n)**(-S(1)/n)/(S(2)*b**S(2)*(a + b*(c*x**n)**(S(1)/n))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*x**n)**(S(1)/n)/(a + b*(c*x**n)**(S(1)/n))**S(5), x), x, a*x*(c*x**n)**(-S(1)/n)/(S(4)*b**S(2)*(a + b*(c*x**n)**(S(1)/n))**S(4)) - x*(c*x**n)**(-S(1)/n)/(S(3)*b**S(2)*(a + b*(c*x**n)**(S(1)/n))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(a + b*x) + sqrt(b*x + c)), x), x, S(2)*a**S(2)*(a + b*x)**(S(3)/2)/(S(3)*b**S(3)*(a - c)) - S(4)*a*(a + b*x)**(S(5)/2)/(S(5)*b**S(3)*(a - c)) - S(2)*c**S(2)*(b*x + c)**(S(3)/2)/(S(3)*b**S(3)*(a - c)) + S(4)*c*(b*x + c)**(S(5)/2)/(S(5)*b**S(3)*(a - c)) + S(2)*(a + b*x)**(S(7)/2)/(S(7)*b**S(3)*(a - c)) - S(2)*(b*x + c)**(S(7)/2)/(S(7)*b**S(3)*(a - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x) + sqrt(b*x + c)), x), x, -S(2)*a*(a + b*x)**(S(3)/2)/(S(3)*b**S(2)*(a - c)) + S(2)*c*(b*x + c)**(S(3)/2)/(S(3)*b**S(2)*(a - c)) + S(2)*(a + b*x)**(S(5)/2)/(S(5)*b**S(2)*(a - c)) - S(2)*(b*x + c)**(S(5)/2)/(S(5)*b**S(2)*(a - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b*x) + sqrt(b*x + c)), x), x, S(2)*(a + b*x)**(S(3)/2)/(S(3)*b*(a - c)) - S(2)*(b*x + c)**(S(3)/2)/(S(3)*b*(a - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(sqrt(a + b*x) + sqrt(b*x + c))), x), x, -S(2)*sqrt(a)*atanh(sqrt(a + b*x)/sqrt(a))/(a - c) + S(2)*sqrt(c)*atanh(sqrt(b*x + c)/sqrt(c))/(a - c) + S(2)*sqrt(a + b*x)/(a - c) - S(2)*sqrt(b*x + c)/(a - c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(sqrt(a + b*x) + sqrt(b*x + c))), x), x, b*atanh(sqrt(b*x + c)/sqrt(c))/(sqrt(c)*(a - c)) - sqrt(a + b*x)/(x*(a - c)) + sqrt(b*x + c)/(x*(a - c)) - b*atanh(sqrt(a + b*x)/sqrt(a))/(sqrt(a)*(a - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(a + b*x) + sqrt(b*x + c))**S(2), x), x, b*x**S(4)/(S(2)*(a - c)**S(2)) + x**S(3)*(a + c)/(S(3)*(a - c)**S(2)) - x*(a + b*x)**(S(3)/2)*(b*x + c)**(S(3)/2)/(S(2)*b**S(2)*(a - c)**S(2)) - (S(4)*a*c - S(5)*(a + c)**S(2))*atanh(sqrt(a + b*x)/sqrt(b*x + c))/(S(32)*b**S(3)) - sqrt(a + b*x)*(S(4)*a*c - S(5)*(a + c)**S(2))*sqrt(b*x + c)/(S(32)*b**S(3)*(a - c)) + (a + b*x)**(S(3)/2)*(S(5)*a + S(5)*c)*(b*x + c)**(S(3)/2)/(S(12)*b**S(3)*(a - c)**S(2)) + (a + b*x)**(S(3)/2)*(S(4)*a*c - S(5)*(a + c)**S(2))*sqrt(b*x + c)/(S(16)*b**S(3)*(a - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x) + sqrt(b*x + c))**S(2), x), x, S(2)*b*x**S(3)/(S(3)*(a - c)**S(2)) + x**S(2)*(a + c)/(S(2)*(a - c)**S(2)) - (a + c)*atanh(sqrt(a + b*x)/sqrt(b*x + c))/(S(4)*b**S(2)) - (a + c)*sqrt(a + b*x)*sqrt(b*x + c)/(S(4)*b**S(2)*(a - c)) + (a + c)*(a + b*x)**(S(3)/2)*sqrt(b*x + c)/(S(2)*b**S(2)*(a - c)**S(2)) - S(2)*(a + b*x)**(S(3)/2)*(b*x + c)**(S(3)/2)/(S(3)*b**S(2)*(a - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a + b*x) + sqrt(b*x + c))**(S(-2)), x), x, (a - c)**S(2)/(S(8)*b*(sqrt(a + b*x) + sqrt(b*x + c))**S(4)) + atanh(sqrt(a + b*x)/sqrt(b*x + c))/(S(2)*b), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((sqrt(a + b*x) + sqrt(b*x + c))**(S(-2)), x), x, b*x**S(2)/(a - c)**S(2) + x*(a + c)/(a - c)**S(2) + atanh(sqrt(a + b*x)/sqrt(b*x + c))/(S(2)*b) + sqrt(a + b*x)*sqrt(b*x + c)/(S(2)*b*(a - c)) - (a + b*x)**(S(3)/2)*sqrt(b*x + c)/(b*(a - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(sqrt(a + b*x) + sqrt(b*x + c))**S(2)), x), x, S(4)*sqrt(a)*sqrt(c)*atanh(sqrt(c)*sqrt(a + b*x)/(sqrt(a)*sqrt(b*x + c)))/(a - c)**S(2) + S(2)*b*x/(a - c)**S(2) + (a + c)*log(x)/(a - c)**S(2) - S(2)*sqrt(a + b*x)*sqrt(b*x + c)/(a - c)**S(2) - (S(2)*a + S(2)*c)*atanh(sqrt(a + b*x)/sqrt(b*x + c))/(a - c)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(sqrt(a + b*x) + sqrt(b*x + c))**S(2)), x), x, S(2)*b*log(x)/(a - c)**S(2) - S(4)*b*atanh(sqrt(a + b*x)/sqrt(b*x + c))/(a - c)**S(2) - (a + c)/(x*(a - c)**S(2)) + S(2)*sqrt(a + b*x)*sqrt(b*x + c)/(x*(a - c)**S(2)) + S(2)*b*(a + c)*atanh(sqrt(c)*sqrt(a + b*x)/(sqrt(a)*sqrt(b*x + c)))/(sqrt(a)*sqrt(c)*(a - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(a + b*x) + sqrt(b*x + c))**S(3), x), x, -S(8)*a**S(3)*(a + b*x)**(S(3)/2)/(S(3)*b**S(3)*(a - c)**S(3)) + S(2)*a**S(2)*(a + S(3)*c)*(a + b*x)**(S(3)/2)/(S(3)*b**S(3)*(a - c)**S(3)) + S(24)*a**S(2)*(a + b*x)**(S(5)/2)/(S(5)*b**S(3)*(a - c)**S(3)) - S(4)*a*(a + S(3)*c)*(a + b*x)**(S(5)/2)/(S(5)*b**S(3)*(a - c)**S(3)) - S(24)*a*(a + b*x)**(S(7)/2)/(S(7)*b**S(3)*(a - c)**S(3)) + S(8)*c**S(3)*(b*x + c)**(S(3)/2)/(S(3)*b**S(3)*(a - c)**S(3)) - S(2)*c**S(2)*(S(3)*a + c)*(b*x + c)**(S(3)/2)/(S(3)*b**S(3)*(a - c)**S(3)) - S(24)*c**S(2)*(b*x + c)**(S(5)/2)/(S(5)*b**S(3)*(a - c)**S(3)) + S(4)*c*(S(3)*a + c)*(b*x + c)**(S(5)/2)/(S(5)*b**S(3)*(a - c)**S(3)) + S(24)*c*(b*x + c)**(S(7)/2)/(S(7)*b**S(3)*(a - c)**S(3)) + S(8)*(a + b*x)**(S(9)/2)/(S(9)*b**S(3)*(a - c)**S(3)) + (a + b*x)**(S(7)/2)*(S(2)*a + S(6)*c)/(S(7)*b**S(3)*(a - c)**S(3)) - (S(6)*a + S(2)*c)*(b*x + c)**(S(7)/2)/(S(7)*b**S(3)*(a - c)**S(3)) - S(8)*(b*x + c)**(S(9)/2)/(S(9)*b**S(3)*(a - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x) + sqrt(b*x + c))**S(3), x), x, S(8)*a**S(2)*(a + b*x)**(S(3)/2)/(S(3)*b**S(2)*(a - c)**S(3)) - S(2)*a*(a + S(3)*c)*(a + b*x)**(S(3)/2)/(S(3)*b**S(2)*(a - c)**S(3)) - S(16)*a*(a + b*x)**(S(5)/2)/(S(5)*b**S(2)*(a - c)**S(3)) - S(8)*c**S(2)*(b*x + c)**(S(3)/2)/(S(3)*b**S(2)*(a - c)**S(3)) + S(2)*c*(S(3)*a + c)*(b*x + c)**(S(3)/2)/(S(3)*b**S(2)*(a - c)**S(3)) + S(16)*c*(b*x + c)**(S(5)/2)/(S(5)*b**S(2)*(a - c)**S(3)) + S(8)*(a + b*x)**(S(7)/2)/(S(7)*b**S(2)*(a - c)**S(3)) + (a + b*x)**(S(5)/2)*(S(2)*a + S(6)*c)/(S(5)*b**S(2)*(a - c)**S(3)) - (S(6)*a + S(2)*c)*(b*x + c)**(S(5)/2)/(S(5)*b**S(2)*(a - c)**S(3)) - S(8)*(b*x + c)**(S(7)/2)/(S(7)*b**S(2)*(a - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a + b*x) + sqrt(b*x + c))**(S(-3)), x), x, (a - c)**S(2)/(S(10)*b*(sqrt(a + b*x) + sqrt(b*x + c))**S(5)) - S(1)/(S(2)*b*(sqrt(a + b*x) + sqrt(b*x + c))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((sqrt(a + b*x) + sqrt(b*x + c))**(S(-3)), x), x, -S(8)*a*(a + b*x)**(S(3)/2)/(S(3)*b*(a - c)**S(3)) + S(8)*c*(b*x + c)**(S(3)/2)/(S(3)*b*(a - c)**S(3)) + S(8)*(a + b*x)**(S(5)/2)/(S(5)*b*(a - c)**S(3)) + (a + b*x)**(S(3)/2)*(S(2)*a + S(6)*c)/(S(3)*b*(a - c)**S(3)) - (S(6)*a + S(2)*c)*(b*x + c)**(S(3)/2)/(S(3)*b*(a - c)**S(3)) - S(8)*(b*x + c)**(S(5)/2)/(S(5)*b*(a - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(sqrt(a + b*x) + sqrt(b*x + c))**S(3)), x), x, -S(2)*sqrt(a)*(a + S(3)*c)*atanh(sqrt(a + b*x)/sqrt(a))/(a - c)**S(3) + S(2)*sqrt(c)*(S(3)*a + c)*atanh(sqrt(b*x + c)/sqrt(c))/(a - c)**S(3) + S(8)*(a + b*x)**(S(3)/2)/(S(3)*(a - c)**S(3)) + sqrt(a + b*x)*(S(2)*a + S(6)*c)/(a - c)**S(3) - (S(6)*a + S(2)*c)*sqrt(b*x + c)/(a - c)**S(3) - S(8)*(b*x + c)**(S(3)/2)/(S(3)*(a - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(sqrt(a + b*x) + sqrt(b*x + c))**S(3)), x), x, S(8)*b*sqrt(a + b*x)/(a - c)**S(3) - S(8)*b*sqrt(b*x + c)/(a - c)**S(3) - S(3)*b*(a + S(3)*c)*atanh(sqrt(b*x + c)/sqrt(c))/(sqrt(c)*(-a + c)**S(3)) - (a + S(3)*c)*sqrt(a + b*x)/(x*(a - c)**S(3)) + (S(3)*a + c)*sqrt(b*x + c)/(x*(a - c)**S(3)) - S(3)*b*(S(3)*a + c)*atanh(sqrt(a + b*x)/sqrt(a))/(sqrt(a)*(a - c)**S(3)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/(x**S(2)*(sqrt(a + b*x) + sqrt(b*x + c))**S(3)), x), x, -S(8)*sqrt(a)*b*atanh(sqrt(a + b*x)/sqrt(a))/(a - c)**S(3) + S(8)*b*sqrt(c)*atanh(sqrt(b*x + c)/sqrt(c))/(a - c)**S(3) + S(8)*b*sqrt(a + b*x)/(a - c)**S(3) - S(8)*b*sqrt(b*x + c)/(a - c)**S(3) + b*(S(3)*a + c)*atanh(sqrt(b*x + c)/sqrt(c))/(sqrt(c)*(a - c)**S(3)) - (a + S(3)*c)*sqrt(a + b*x)/(x*(a - c)**S(3)) + (S(3)*a + c)*sqrt(b*x + c)/(x*(a - c)**S(3)) - b*(a + S(3)*c)*atanh(sqrt(a + b*x)/sqrt(a))/(sqrt(a)*(a - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x) + sqrt(x + S(1))), x), x, -S(2)*x**(S(3)/2)/S(3) + S(2)*(x + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x) + sqrt(x + S(-1))), x), x, S(2)*x**(S(3)/2)/S(3) - S(2)*(x + S(-1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x + S(-1)) + sqrt(x + S(1))), x), x, -(x + S(-1))**(S(3)/2)/S(3) + (x + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(sqrt(-x + S(1)) + sqrt(x + S(1)))**S(2), x), x, x**S(4)/S(2) + S(2)*(-x**S(2) + S(1))**(S(5)/2)/S(5) - S(2)*(-x**S(2) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(sqrt(-x + S(1)) + sqrt(x + S(1)))**S(2), x), x, x**S(3)*sqrt(-x**S(2) + S(1))/S(2) + S(2)*x**S(3)/S(3) - x*sqrt(-x**S(2) + S(1))/S(4) + asin(x)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(sqrt(-x + S(1)) + sqrt(x + S(1)))**S(2), x), x, x**S(2) - S(2)*(-x**S(2) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(-x + S(1)) + sqrt(x + S(1)))**S(2), x), x, x*sqrt(-x**S(2) + S(1)) + S(2)*x + asin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(-x + S(1)) + sqrt(x + S(1)))**S(2)/x, x), x, S(2)*sqrt(-x**S(2) + S(1)) + S(2)*log(x) - S(2)*atanh(sqrt(-x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(-x + S(1)) + sqrt(x + S(1)))**S(2)/x**S(2), x), x, -S(2)*asin(x) - S(2)*sqrt(-x**S(2) + S(1))/x - S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(-x + S(1)) + sqrt(x + S(1)))**S(2)/x**S(3), x), x, atanh(sqrt(-x**S(2) + S(1))) - sqrt(-x**S(2) + S(1))/x**S(2) - S(1)/x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(sqrt(a + b*x) + sqrt(a + c*x)), x), x, -S(2)*a**S(2)*(a + c*x)**(S(3)/2)/(c**S(3)*(S(3)*b - S(3)*c)) + S(2)*a**S(2)*(a + b*x)**(S(3)/2)/(S(3)*b**S(3)*(b - c)) + S(4)*a*(a + c*x)**(S(5)/2)/(c**S(3)*(S(5)*b - S(5)*c)) - S(4)*a*(a + b*x)**(S(5)/2)/(S(5)*b**S(3)*(b - c)) - S(2)*(a + c*x)**(S(7)/2)/(c**S(3)*(S(7)*b - S(7)*c)) + S(2)*(a + b*x)**(S(7)/2)/(S(7)*b**S(3)*(b - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(a + b*x) + sqrt(a + c*x)), x), x, S(2)*a*(a + c*x)**(S(3)/2)/(c**S(2)*(S(3)*b - S(3)*c)) - S(2)*a*(a + b*x)**(S(3)/2)/(S(3)*b**S(2)*(b - c)) - S(2)*(a + c*x)**(S(5)/2)/(c**S(2)*(S(5)*b - S(5)*c)) + S(2)*(a + b*x)**(S(5)/2)/(S(5)*b**S(2)*(b - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x) + sqrt(a + c*x)), x), x, -S(2)*(a + c*x)**(S(3)/2)/(c*(S(3)*b - S(3)*c)) + S(2)*(a + b*x)**(S(3)/2)/(S(3)*b*(b - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b*x) + sqrt(a + c*x)), x), x, -S(2)*sqrt(a)*atanh(sqrt(a + b*x)/sqrt(a))/(b - c) + S(2)*sqrt(a)*atanh(sqrt(a + c*x)/sqrt(a))/(b - c) + S(2)*sqrt(a + b*x)/(b - c) - S(2)*sqrt(a + c*x)/(b - c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(sqrt(a + b*x) + sqrt(a + c*x))), x), x, -sqrt(a + b*x)/(x*(b - c)) + sqrt(a + c*x)/(x*(b - c)) - b*atanh(sqrt(a + b*x)/sqrt(a))/(sqrt(a)*(b - c)) + c*atanh(sqrt(a + c*x)/sqrt(a))/(sqrt(a)*(b - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(sqrt(a + b*x) + sqrt(a + c*x))), x), x, -sqrt(a + b*x)/(x**S(2)*(S(2)*b - S(2)*c)) + sqrt(a + c*x)/(x**S(2)*(S(2)*b - S(2)*c)) - b*sqrt(a + b*x)/(S(4)*a*x*(b - c)) + c*sqrt(a + c*x)/(S(4)*a*x*(b - c)) + b**S(2)*atanh(sqrt(a + b*x)/sqrt(a))/(S(4)*a**(S(3)/2)*(b - c)) - c**S(2)*atanh(sqrt(a + c*x)/sqrt(a))/(S(4)*a**(S(3)/2)*(b - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(sqrt(a + b*x) + sqrt(a + c*x))**S(2), x), x, -a**S(3)*(b + c)*atanh(sqrt(c)*sqrt(a + b*x)/(sqrt(b)*sqrt(a + c*x)))/(S(4)*b**(S(5)/2)*c**(S(5)/2)) + a**S(2)*sqrt(a + b*x)*sqrt(a + c*x)*(b + c)/(S(4)*b**S(2)*c**S(2)*(b - c)) + a*x**S(2)/(b - c)**S(2) + a*(a + b*x)**(S(3)/2)*sqrt(a + c*x)*(b + c)/(S(2)*b**S(2)*c*(b - c)**S(2)) + x**S(3)*(b + c)/(S(3)*(b - c)**S(2)) - S(2)*(a + b*x)**(S(3)/2)*(a + c*x)**(S(3)/2)/(S(3)*b*c*(b - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(a + b*x) + sqrt(a + c*x))**S(2), x), x, a**S(2)*atanh(sqrt(c)*sqrt(a + b*x)/(sqrt(b)*sqrt(a + c*x)))/(S(2)*b**(S(3)/2)*c**(S(3)/2)) + S(2)*a*x/(b - c)**S(2) - a*sqrt(a + b*x)*sqrt(a + c*x)/(S(2)*b*c*(b - c)) + x**S(2)*(b + c)/(S(2)*(b - c)**S(2)) - (a + b*x)**(S(3)/2)*sqrt(a + c*x)/(b*(b - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x) + sqrt(a + c*x))**S(2), x), x, S(2)*a*log(x)/(b - c)**S(2) + S(4)*a*atanh(sqrt(a + b*x)/sqrt(a + c*x))/(b - c)**S(2) - S(2)*a*(b + c)*atanh(sqrt(c)*sqrt(a + b*x)/(sqrt(b)*sqrt(a + c*x)))/(sqrt(b)*sqrt(c)*(b - c)**S(2)) + x*(b + c)/(b - c)**S(2) - S(2)*sqrt(a + b*x)*sqrt(a + c*x)/(b - c)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a + b*x) + sqrt(a + c*x))**(S(-2)), x), x, -S(2)*a/(x*(b - c)**S(2)) - S(4)*sqrt(b)*sqrt(c)*atanh(sqrt(c)*sqrt(a + b*x)/(sqrt(b)*sqrt(a + c*x)))/(b - c)**S(2) + (b + c)*log(x)/(b - c)**S(2) + (S(2)*b + S(2)*c)*atanh(sqrt(a + b*x)/sqrt(a + c*x))/(b - c)**S(2) + S(2)*sqrt(a + b*x)*sqrt(a + c*x)/(x*(b - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(sqrt(a + b*x) + sqrt(a + c*x))**S(2)), x), x, -a/(x**S(2)*(b - c)**S(2)) - (b + c)/(x*(b - c)**S(2)) - atanh(sqrt(a + b*x)/sqrt(a + c*x))/(S(2)*a) + sqrt(a + b*x)*sqrt(a + c*x)/(S(2)*a*x*(b - c)) + sqrt(a + b*x)*(a + c*x)**(S(3)/2)/(a*x**S(2)*(b - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(sqrt(a + b*x) + sqrt(a + c*x))**S(2)), x), x, -S(2)*a/(S(3)*x**S(3)*(b - c)**S(2)) - (b + c)/(S(2)*x**S(2)*(b - c)**S(2)) + (b + c)*atanh(sqrt(a + b*x)/sqrt(a + c*x))/(S(4)*a**S(2)) - sqrt(a + b*x)*sqrt(a + c*x)*(b + c)/(S(4)*a**S(2)*x*(b - c)) - sqrt(a + b*x)*(a + c*x)**(S(3)/2)*(b + c)/(S(2)*a**S(2)*x**S(2)*(b - c)**S(2)) + S(2)*(a + b*x)**(S(3)/2)*(a + c*x)**(S(3)/2)/(S(3)*a**S(2)*x**S(3)*(b - c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(sqrt(a + b*x) + sqrt(a + c*x))**S(3), x), x, S(8)*a**S(2)*(a + c*x)**(S(3)/2)/(S(3)*c**S(2)*(b - c)**S(3)) - S(2)*a**S(2)*(a + c*x)**(S(3)/2)*(S(3)*b + c)/(S(3)*c**S(3)*(b - c)**S(3)) - S(8)*a**S(2)*(a + b*x)**(S(3)/2)/(S(3)*b**S(2)*(b - c)**S(3)) + S(2)*a**S(2)*(a + b*x)**(S(3)/2)*(b + S(3)*c)/(S(3)*b**S(3)*(b - c)**S(3)) - S(8)*a*(a + c*x)**(S(5)/2)/(S(5)*c**S(2)*(b - c)**S(3)) + S(4)*a*(a + c*x)**(S(5)/2)*(S(3)*b + c)/(S(5)*c**S(3)*(b - c)**S(3)) + S(8)*a*(a + b*x)**(S(5)/2)/(S(5)*b**S(2)*(b - c)**S(3)) - S(4)*a*(a + b*x)**(S(5)/2)*(b + S(3)*c)/(S(5)*b**S(3)*(b - c)**S(3)) - (a + c*x)**(S(7)/2)*(S(6)*b + S(2)*c)/(S(7)*c**S(3)*(b - c)**S(3)) + (a + b*x)**(S(7)/2)*(S(2)*b + S(6)*c)/(S(7)*b**S(3)*(b - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(sqrt(a + b*x) + sqrt(a + c*x))**S(3), x), x, -S(8)*a*(a + c*x)**(S(3)/2)/(S(3)*c*(b - c)**S(3)) + S(2)*a*(a + c*x)**(S(3)/2)*(S(3)*b + c)/(S(3)*c**S(2)*(b - c)**S(3)) + S(8)*a*(a + b*x)**(S(3)/2)/(S(3)*b*(b - c)**S(3)) - S(2)*a*(a + b*x)**(S(3)/2)*(b + S(3)*c)/(S(3)*b**S(2)*(b - c)**S(3)) - (a + c*x)**(S(5)/2)*(S(6)*b + S(2)*c)/(S(5)*c**S(2)*(b - c)**S(3)) + (a + b*x)**(S(5)/2)*(S(2)*b + S(6)*c)/(S(5)*b**S(2)*(b - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(a + b*x) + sqrt(a + c*x))**S(3), x), x, -S(8)*a**(S(3)/2)*atanh(sqrt(a + b*x)/sqrt(a))/(b - c)**S(3) + S(8)*a**(S(3)/2)*atanh(sqrt(a + c*x)/sqrt(a))/(b - c)**S(3) + S(8)*a*sqrt(a + b*x)/(b - c)**S(3) - S(8)*a*sqrt(a + c*x)/(b - c)**S(3) - (a + c*x)**(S(3)/2)*(S(6)*b + S(2)*c)/(S(3)*c*(b - c)**S(3)) + (a + b*x)**(S(3)/2)*(S(2)*b + S(6)*c)/(S(3)*b*(b - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x) + sqrt(a + c*x))**S(3), x), x, -S(6)*sqrt(a)*(b + c)*atanh(sqrt(a + b*x)/sqrt(a))/(b - c)**S(3) + S(6)*sqrt(a)*(b + c)*atanh(sqrt(a + c*x)/sqrt(a))/(b - c)**S(3) - S(4)*a*sqrt(a + b*x)/(x*(b - c)**S(3)) + S(4)*a*sqrt(a + c*x)/(x*(b - c)**S(3)) + sqrt(a + b*x)*(S(2)*b + S(6)*c)/(b - c)**S(3) - sqrt(a + c*x)*(S(6)*b + S(2)*c)/(b - c)**S(3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x/(sqrt(a + b*x) + sqrt(a + c*x))**S(3), x), x, -S(4)*sqrt(a)*b*atanh(sqrt(a + b*x)/sqrt(a))/(b - c)**S(3) + S(4)*sqrt(a)*c*atanh(sqrt(a + c*x)/sqrt(a))/(b - c)**S(3) - S(2)*sqrt(a)*(b + S(3)*c)*atanh(sqrt(a + b*x)/sqrt(a))/(b - c)**S(3) + S(2)*sqrt(a)*(S(3)*b + c)*atanh(sqrt(a + c*x)/sqrt(a))/(b - c)**S(3) - S(4)*a*sqrt(a + b*x)/(x*(b - c)**S(3)) + S(4)*a*sqrt(a + c*x)/(x*(b - c)**S(3)) + sqrt(a + b*x)*(S(2)*b + S(6)*c)/(b - c)**S(3) - sqrt(a + c*x)*(S(6)*b + S(2)*c)/(b - c)**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a + b*x) + sqrt(a + c*x))**(S(-3)), x), x, -S(2)*a*sqrt(a + b*x)/(x**S(2)*(b - c)**S(3)) + S(2)*a*sqrt(a + c*x)/(x**S(2)*(b - c)**S(3)) - sqrt(a + b*x)*(S(2)*b + S(3)*c)/(x*(b - c)**S(3)) + sqrt(a + c*x)*(S(3)*b + S(2)*c)/(x*(b - c)**S(3)) - S(3)*b*c*atanh(sqrt(a + b*x)/sqrt(a))/(sqrt(a)*(b - c)**S(3)) + S(3)*b*c*atanh(sqrt(a + c*x)/sqrt(a))/(sqrt(a)*(b - c)**S(3)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((sqrt(a + b*x) + sqrt(a + c*x))**(S(-3)), x), x, -S(2)*a*sqrt(a + b*x)/(x**S(2)*(b - c)**S(3)) + S(2)*a*sqrt(a + c*x)/(x**S(2)*(b - c)**S(3)) - b*sqrt(a + b*x)/(x*(b - c)**S(3)) + c*sqrt(a + c*x)/(x*(b - c)**S(3)) - sqrt(a + b*x)*(b + S(3)*c)/(x*(b - c)**S(3)) + sqrt(a + c*x)*(S(3)*b + c)/(x*(b - c)**S(3)) + b**S(2)*atanh(sqrt(a + b*x)/sqrt(a))/(sqrt(a)*(b - c)**S(3)) - b*(b + S(3)*c)*atanh(sqrt(a + b*x)/sqrt(a))/(sqrt(a)*(b - c)**S(3)) - c**S(2)*atanh(sqrt(a + c*x)/sqrt(a))/(sqrt(a)*(b - c)**S(3)) + c*(S(3)*b + c)*atanh(sqrt(a + c*x)/sqrt(a))/(sqrt(a)*(b - c)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x + S(1))*(sqrt(-x + S(1)) + sqrt(x + S(1))), x), x, -x**S(2)/S(2) + x*sqrt(-x**S(2) + S(1))/S(2) + x + asin(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(-sqrt(-x + S(1)) - sqrt(x + S(1)))*(sqrt(-x + S(1)) + sqrt(x + S(1))), x), x, -x**S(4)/S(2) - S(2)*(-x**S(2) + S(1))**(S(5)/2)/S(5) + S(2)*(-x**S(2) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(-sqrt(-x + S(1)) - sqrt(x + S(1)))*(sqrt(-x + S(1)) + sqrt(x + S(1))), x), x, -x**S(3)*sqrt(-x**S(2) + S(1))/S(2) - S(2)*x**S(3)/S(3) + x*sqrt(-x**S(2) + S(1))/S(4) - asin(x)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(-sqrt(-x + S(1)) - sqrt(x + S(1)))*(sqrt(-x + S(1)) + sqrt(x + S(1))), x), x, -x**S(2) + S(2)*(-x**S(2) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(-x + S(1)) - sqrt(x + S(1)))*(sqrt(-x + S(1)) + sqrt(x + S(1))), x), x, -x*sqrt(-x**S(2) + S(1)) - S(2)*x - asin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(-x + S(1)) - sqrt(x + S(1)))*(sqrt(-x + S(1)) + sqrt(x + S(1)))/x, x), x, -S(2)*sqrt(-x**S(2) + S(1)) - S(2)*log(x) + S(2)*atanh(sqrt(-x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(-x + S(1)) - sqrt(x + S(1)))*(sqrt(-x + S(1)) + sqrt(x + S(1)))/x**S(2), x), x, S(2)*asin(x) + S(2)*sqrt(-x**S(2) + S(1))/x + S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(-x + S(1)) - sqrt(x + S(1)))*(sqrt(-x + S(1)) + sqrt(x + S(1)))/x**S(3), x), x, -atanh(sqrt(-x**S(2) + S(1))) + sqrt(-x**S(2) + S(1))/x**S(2) + x**(S(-2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(-x + S(1)) + sqrt(x + S(1)))/(-sqrt(-x + S(1)) + sqrt(x + S(1))), x), x, sqrt(-x**S(2) + S(1)) + log(x) - atanh(sqrt(-x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(x + S(-1)) + sqrt(x + S(1)))/(sqrt(x + S(-1)) + sqrt(x + S(1))), x), x, x**S(2)/S(2) - x*sqrt(x + S(-1))*sqrt(x + S(1))/S(2) + acosh(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**n, x), x, a*f**S(2)*(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), (d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/d)/(S(2)*d**S(2)*e*(n + S(1))) + (d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))/(S(2)*e*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**S(3), x), x, -a*d**S(3)*f**S(2)/(S(2)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) + S(3)*a*d**S(2)*f**S(2)*log(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*e) + a*d*f**S(2)*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/e + a*f**S(2)*(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**S(2)/(S(4)*e) + (d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**S(4)/(S(8)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**S(2), x), x, -a*d**S(2)*f**S(2)/(S(2)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) + a*d*f**S(2)*log(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/e + a*f**S(2)*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*e) + (d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**S(3)/(S(6)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)), x), x, a*f**S(2)*atanh(e*x/(f*sqrt(a + e**S(2)*x**S(2)/f**S(2))))/(S(2)*e) + d*x + e*x**S(2)/S(2) + f*x*sqrt(a + e**S(2)*x**S(2)/f**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2))), x), x, -a*f**S(2)/(S(2)*d*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) - a*f**S(2)*log(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*d**S(2)*e) + (a*f**S(2)/d**S(2) + S(1))*log(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(-2)), x), x, -a*f**S(2)/(S(2)*d**S(2)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) - a*f**S(2)*log(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(d**S(3)*e) + a*f**S(2)*log(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(d**S(3)*e) - (a*f**S(2)/d**S(2) + S(1))/(S(2)*e*(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(-3)), x), x, -a*f**S(2)/(d**S(3)*e*(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) - a*f**S(2)/(S(2)*d**S(3)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) - S(3)*a*f**S(2)*log(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*d**S(4)*e) + S(3)*a*f**S(2)*log(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*d**S(4)*e) - (a*f**S(2)/d**S(2) + S(1))/(S(4)*e*(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(5)/2), x), x, -S(5)*a*d**(S(3)/2)*f**S(2)*atanh(sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/sqrt(d))/(S(2)*e) - a*d**S(2)*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) + S(2)*a*d*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/e + a*f**S(2)*(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2)/(S(3)*e) + (d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(7)/2)/(S(7)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2), x), x, -S(3)*a*sqrt(d)*f**S(2)*atanh(sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/sqrt(d))/(S(2)*e) - a*d*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) + a*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/e + (d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(5)/2)/(S(5)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2))), x), x, -a*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) - a*f**S(2)*atanh(sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/sqrt(d))/(S(2)*sqrt(d)*e) + (d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2)/(S(3)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2))), x), x, -a*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*d*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) + a*f**S(2)*atanh(sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/sqrt(d))/(S(2)*d**(S(3)/2)*e) + sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/e, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(-3)/2), x), x, -a*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*d**S(2)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) + S(3)*a*f**S(2)*atanh(sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/sqrt(d))/(S(2)*d**(S(5)/2)*e) - (a*f**S(2)/d**S(2) + S(1))/(e*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(-5)/2), x), x, -S(2)*a*f**S(2)/(d**S(3)*e*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) - a*f**S(2)*sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/(S(2)*d**S(3)*e*(e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))) + S(5)*a*f**S(2)*atanh(sqrt(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))/sqrt(d))/(S(2)*d**(S(7)/2)*e) - (a*f**S(2)/d**S(2) + S(1))/(S(3)*e*(d + e*x + f*sqrt(a + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x - sqrt(x**S(2) + S(-4))), x), x, (x - sqrt(x**S(2) + S(-4)))**(S(3)/2)/S(3) + S(4)/sqrt(x - sqrt(x**S(2) + S(-4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x + b*sqrt(a**S(2)*x**S(2)/b**S(2) + c)), x), x, -b**S(2)*c/(a*sqrt(a*x + b*sqrt(a**S(2)*x**S(2)/b**S(2) + c))) + (a*x + b*sqrt(a**S(2)*x**S(2)/b**S(2) + c))**(S(3)/2)/(S(3)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(-x**S(2) + S(1)) + S(1)), x), x, -S(2)*x**S(3)/(S(3)*(sqrt(-x**S(2) + S(1)) + S(1))**(S(3)/2)) + S(2)*x/sqrt(sqrt(-x**S(2) + S(1)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(x**S(2) + S(1)) + S(1)), x), x, S(2)*x**S(3)/(S(3)*(sqrt(x**S(2) + S(1)) + S(1))**(S(3)/2)) + S(2)*x/sqrt(sqrt(x**S(2) + S(1)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(x**S(2) + S(25)) + S(5)), x), x, S(2)*x**S(3)/(S(3)*(sqrt(x**S(2) + S(25)) + S(5))**(S(3)/2)) + S(10)*x/sqrt(sqrt(x**S(2) + S(25)) + S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(a**S(2)/b**S(2) + c*x**S(2))), x), x, S(2)*a*x/sqrt(a + b*sqrt(a**S(2)/b**S(2) + c*x**S(2))) + S(2)*b**S(2)*c*x**S(3)/(S(3)*(a + b*sqrt(a**S(2)/b**S(2) + c*x**S(2)))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**n, x), x, f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))*hyper((S(2), n + S(1)), (n + S(2),), S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(-b*f**S(2) + S(2)*d*e))/(S(2)*e*(n + S(1))*(-b*f**S(2) + S(2)*d*e)**S(2)) + (d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))/(S(2)*e*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**S(3), x), x, (d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**S(4)/(S(8)*e) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**S(2)/(S(16)*e**S(3)) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)*(e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(S(8)*e**S(4)) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)**S(3)/(S(32)*e**S(5)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) + S(3)*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)**S(2)*log(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))/(S(32)*e**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**S(2), x), x, (d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**S(3)/(S(6)*e) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(S(8)*e**S(3)) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)**S(2)/(S(16)*e**S(4)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)*log(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))/(S(8)*e**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)), x), x, d*x + e*x**S(2)/S(2) + f*(b*f**S(2) + S(2)*e**S(2)*x)*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))/(S(4)*e**S(2)) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*atanh((b*f**S(2) + S(2)*e**S(2)*x)/(S(2)*e*f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))/(S(8)*e**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))), x), x, (S(2)*a*e*f**S(2) - S(2)*b*d*f**S(2) + S(2)*d**S(2)*e)*log(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(-b*f**S(2) + S(2)*d*e)**S(2) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))/(S(2)*e*(-b*f**S(2) + S(2)*d*e)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) - f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*log(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))/(S(2)*e*(-b*f**S(2) + S(2)*d*e)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(-2)), x), x, f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))/((-b*f**S(2) + S(2)*d*e)**S(2)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) + S(2)*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*log(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(-b*f**S(2) + S(2)*d*e)**S(3) - S(2)*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*log(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))/(-b*f**S(2) + S(2)*d*e)**S(3) - (S(2)*a*e*f**S(2) - S(2)*b*d*f**S(2) + S(2)*d**S(2)*e)/((-b*f**S(2) + S(2)*d*e)**S(2)*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(-3)), x), x, S(2)*e*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))/((-b*f**S(2) + S(2)*d*e)**S(3)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) + S(6)*e*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*log(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(-b*f**S(2) + S(2)*d*e)**S(4) - S(6)*e*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*log(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))/(-b*f**S(2) + S(2)*d*e)**S(4) - S(2)*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))/((-b*f**S(2) + S(2)*d*e)**S(3)*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))) - (a*e*f**S(2) - b*d*f**S(2) + d**S(2)*e)/((-b*f**S(2) + S(2)*d*e)**S(2)*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(5)/2), x), x, (d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(7)/2)/(S(7)*e) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2)/(S(12)*e**S(3)) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)**S(2)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(S(16)*e**S(4)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(S(4)*e**S(4)) - S(5)*sqrt(S(2))*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)**(S(3)/2)*atanh(sqrt(S(2))*sqrt(e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/sqrt(-b*f**S(2) + S(2)*d*e))/(S(32)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2), x), x, (d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(5)/2)/(S(5)*e) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*(-b*f**S(2) + S(2)*d*e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(S(8)*e**S(3)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) + f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(S(4)*e**S(3)) - S(3)*sqrt(S(2))*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*sqrt(-b*f**S(2) + S(2)*d*e)*atanh(sqrt(S(2))*sqrt(e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/sqrt(-b*f**S(2) + S(2)*d*e))/(S(16)*e**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))), x), x, f**S(2)*(S(4)*a - b**S(2)*f**S(2)/e**S(2))*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(-S(4)*b*f**S(2) + S(8)*d*e - S(8)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))) + (d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2)/(S(3)*e) - sqrt(S(2))*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*atanh(sqrt(S(2))*sqrt(e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/sqrt(-b*f**S(2) + S(2)*d*e))/(S(8)*e**(S(5)/2)*sqrt(-b*f**S(2) + S(2)*d*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))), x), x, f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/(S(2)*e*(-b*f**S(2) + S(2)*d*e)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) + sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/e + sqrt(S(2))*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*atanh(sqrt(S(2))*sqrt(e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/sqrt(-b*f**S(2) + S(2)*d*e))/(S(4)*e**(S(3)/2)*(-b*f**S(2) + S(2)*d*e)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(-3)/2), x), x, f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/((-b*f**S(2) + S(2)*d*e)**S(2)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) - (S(4)*a*e*f**S(2) - S(4)*b*d*f**S(2) + S(4)*d**S(2)*e)/((-b*f**S(2) + S(2)*d*e)**S(2)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))) + S(3)*sqrt(S(2))*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*atanh(sqrt(S(2))*sqrt(e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/sqrt(-b*f**S(2) + S(2)*d*e))/(S(2)*sqrt(e)*(-b*f**S(2) + S(2)*d*e)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(-5)/2), x), x, S(5)*sqrt(S(2))*sqrt(e)*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*atanh(sqrt(S(2))*sqrt(e)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/sqrt(-b*f**S(2) + S(2)*d*e))/(-b*f**S(2) + S(2)*d*e)**(S(7)/2) + S(2)*e*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))/((-b*f**S(2) + S(2)*d*e)**S(3)*(-b*f**S(2) + S(2)*d*e - S(2)*e*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2))))) - S(4)*f**S(2)*(S(4)*a*e**S(2) - b**S(2)*f**S(2))/((-b*f**S(2) + S(2)*d*e)**S(3)*sqrt(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))) - (S(4)*a*e*f**S(2) - S(4)*b*d*f**S(2) + S(4)*d**S(2)*e)/(S(3)*(-b*f**S(2) + S(2)*d*e)**S(2)*(d + e*x + f*sqrt(a + b*x + e**S(2)*x**S(2)/f**S(2)))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))**S(2)*(x + sqrt(a + x**S(2)))**n, x), x, -a**S(5)*(x + sqrt(a + x**S(2)))**(n + S(-5))/(-S(32)*n + S(160)) - S(5)*a**S(4)*(x + sqrt(a + x**S(2)))**(n + S(-3))/(-S(32)*n + S(96)) - S(5)*a**S(3)*(x + sqrt(a + x**S(2)))**(n + S(-1))/(-S(16)*n + S(16)) + S(5)*a**S(2)*(x + sqrt(a + x**S(2)))**(n + S(1))/(S(16)*n + S(16)) + S(5)*a*(x + sqrt(a + x**S(2)))**(n + S(3))/(S(32)*n + S(96)) + (x + sqrt(a + x**S(2)))**(n + S(5))/(S(32)*n + S(160)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))*(x + sqrt(a + x**S(2)))**n, x), x, -a**S(3)*(x + sqrt(a + x**S(2)))**(n + S(-3))/(-S(8)*n + S(24)) - S(3)*a**S(2)*(x + sqrt(a + x**S(2)))**(n + S(-1))/(-S(8)*n + S(8)) + S(3)*a*(x + sqrt(a + x**S(2)))**(n + S(1))/(S(8)*n + S(8)) + (x + sqrt(a + x**S(2)))**(n + S(3))/(S(8)*n + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(a + x**S(2)))**n, x), x, -a*(x + sqrt(a + x**S(2)))**(n + S(-1))/(-S(2)*n + S(2)) + (x + sqrt(a + x**S(2)))**(n + S(1))/(S(2)*n + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(a + x**S(2)))**n/(a + x**S(2)), x), x, S(2)*(x + sqrt(a + x**S(2)))**(n + S(1))*hyper((S(1), n/S(2) + S(1)/2), (n/S(2) + S(3)/2,), -(x + sqrt(a + x**S(2)))**S(2)/a)/(a*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(a + x**S(2)))**n/(a + x**S(2))**S(2), x), x, S(8)*(x + sqrt(a + x**S(2)))**(n + S(3))*hyper((S(3), n/S(2) + S(3)/2), (n/S(2) + S(5)/2,), -(x + sqrt(a + x**S(2)))**S(2)/a)/(a**S(3)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))**S(2)*(x - sqrt(a + x**S(2)))**n, x), x, -a**S(5)*(x - sqrt(a + x**S(2)))**(n + S(-5))/(-S(32)*n + S(160)) - S(5)*a**S(4)*(x - sqrt(a + x**S(2)))**(n + S(-3))/(-S(32)*n + S(96)) - S(5)*a**S(3)*(x - sqrt(a + x**S(2)))**(n + S(-1))/(-S(16)*n + S(16)) + S(5)*a**S(2)*(x - sqrt(a + x**S(2)))**(n + S(1))/(S(16)*n + S(16)) + S(5)*a*(x - sqrt(a + x**S(2)))**(n + S(3))/(S(32)*n + S(96)) + (x - sqrt(a + x**S(2)))**(n + S(5))/(S(32)*n + S(160)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))*(x - sqrt(a + x**S(2)))**n, x), x, -a**S(3)*(x - sqrt(a + x**S(2)))**(n + S(-3))/(-S(8)*n + S(24)) - S(3)*a**S(2)*(x - sqrt(a + x**S(2)))**(n + S(-1))/(-S(8)*n + S(8)) + S(3)*a*(x - sqrt(a + x**S(2)))**(n + S(1))/(S(8)*n + S(8)) + (x - sqrt(a + x**S(2)))**(n + S(3))/(S(8)*n + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(a + x**S(2)))**n, x), x, -a*(x - sqrt(a + x**S(2)))**(n + S(-1))/(-S(2)*n + S(2)) + (x - sqrt(a + x**S(2)))**(n + S(1))/(S(2)*n + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(a + x**S(2)))**n/(a + x**S(2)), x), x, S(2)*(x - sqrt(a + x**S(2)))**(n + S(1))*hyper((S(1), n/S(2) + S(1)/2), (n/S(2) + S(3)/2,), -(x - sqrt(a + x**S(2)))**S(2)/a)/(a*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(a + x**S(2)))**n/(a + x**S(2))**S(2), x), x, S(8)*(x - sqrt(a + x**S(2)))**(n + S(3))*hyper((S(3), n/S(2) + S(3)/2), (n/S(2) + S(5)/2,), -(x - sqrt(a + x**S(2)))**S(2)/a)/(a**S(3)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))**(S(5)/2)*(x + sqrt(a + x**S(2)))**n, x), x, -a**S(6)*(x + sqrt(a + x**S(2)))**(n + S(-6))/(-S(64)*n + S(384)) - S(3)*a**S(5)*(x + sqrt(a + x**S(2)))**(n + S(-4))/(-S(32)*n + S(128)) - S(15)*a**S(4)*(x + sqrt(a + x**S(2)))**(n + S(-2))/(-S(64)*n + S(128)) + S(5)*a**S(3)*(x + sqrt(a + x**S(2)))**n/(S(16)*n) + S(15)*a**S(2)*(x + sqrt(a + x**S(2)))**(n + S(2))/(S(64)*n + S(128)) + S(3)*a*(x + sqrt(a + x**S(2)))**(n + S(4))/(S(32)*n + S(128)) + (x + sqrt(a + x**S(2)))**(n + S(6))/(S(64)*n + S(384)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))**(S(3)/2)*(x + sqrt(a + x**S(2)))**n, x), x, -a**S(4)*(x + sqrt(a + x**S(2)))**(n + S(-4))/(-S(16)*n + S(64)) - a**S(3)*(x + sqrt(a + x**S(2)))**(n + S(-2))/(-S(4)*n + S(8)) + S(3)*a**S(2)*(x + sqrt(a + x**S(2)))**n/(S(8)*n) + a*(x + sqrt(a + x**S(2)))**(n + S(2))/(S(4)*n + S(8)) + (x + sqrt(a + x**S(2)))**(n + S(4))/(S(16)*n + S(64)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + x**S(2))*(x + sqrt(a + x**S(2)))**n, x), x, -a**S(2)*(x + sqrt(a + x**S(2)))**(n + S(-2))/(-S(4)*n + S(8)) + a*(x + sqrt(a + x**S(2)))**n/(S(2)*n) + (x + sqrt(a + x**S(2)))**(n + S(2))/(S(4)*n + S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(a + x**S(2)))**n/sqrt(a + x**S(2)), x), x, (x + sqrt(a + x**S(2)))**n/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(a + x**S(2)))**n/(a + x**S(2))**(S(3)/2), x), x, S(4)*(x + sqrt(a + x**S(2)))**(n + S(2))*hyper((S(2), n/S(2) + S(1)), (n/S(2) + S(2),), -(x + sqrt(a + x**S(2)))**S(2)/a)/(a**S(2)*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(a + x**S(2)))**n/(a + x**S(2))**(S(5)/2), x), x, S(16)*(x + sqrt(a + x**S(2)))**(n + S(4))*hyper((S(4), n/S(2) + S(2)), (n/S(2) + S(3),), -(x + sqrt(a + x**S(2)))**S(2)/a)/(a**S(4)*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))**(S(5)/2)*(x - sqrt(a + x**S(2)))**n, x), x, a**S(6)*(x - sqrt(a + x**S(2)))**(n + S(-6))/(-S(64)*n + S(384)) + S(3)*a**S(5)*(x - sqrt(a + x**S(2)))**(n + S(-4))/(-S(32)*n + S(128)) + S(15)*a**S(4)*(x - sqrt(a + x**S(2)))**(n + S(-2))/(-S(64)*n + S(128)) - S(5)*a**S(3)*(x - sqrt(a + x**S(2)))**n/(S(16)*n) - S(15)*a**S(2)*(x - sqrt(a + x**S(2)))**(n + S(2))/(S(64)*n + S(128)) - S(3)*a*(x - sqrt(a + x**S(2)))**(n + S(4))/(S(32)*n + S(128)) - (x - sqrt(a + x**S(2)))**(n + S(6))/(S(64)*n + S(384)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2))**(S(3)/2)*(x - sqrt(a + x**S(2)))**n, x), x, a**S(4)*(x - sqrt(a + x**S(2)))**(n + S(-4))/(-S(16)*n + S(64)) + a**S(3)*(x - sqrt(a + x**S(2)))**(n + S(-2))/(-S(4)*n + S(8)) - S(3)*a**S(2)*(x - sqrt(a + x**S(2)))**n/(S(8)*n) - a*(x - sqrt(a + x**S(2)))**(n + S(2))/(S(4)*n + S(8)) - (x - sqrt(a + x**S(2)))**(n + S(4))/(S(16)*n + S(64)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + x**S(2))*(x - sqrt(a + x**S(2)))**n, x), x, a**S(2)*(x - sqrt(a + x**S(2)))**(n + S(-2))/(-S(4)*n + S(8)) - a*(x - sqrt(a + x**S(2)))**n/(S(2)*n) - (x - sqrt(a + x**S(2)))**(n + S(2))/(S(4)*n + S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(a + x**S(2)))**n/sqrt(a + x**S(2)), x), x, -(x - sqrt(a + x**S(2)))**n/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(a + x**S(2)))**n/(a + x**S(2))**(S(3)/2), x), x, -S(4)*(x - sqrt(a + x**S(2)))**(n + S(2))*hyper((S(2), n/S(2) + S(1)), (n/S(2) + S(2),), -(x - sqrt(a + x**S(2)))**S(2)/a)/(a**S(2)*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(a + x**S(2)))**n/(a + x**S(2))**(S(5)/2), x), x, -S(16)*(x - sqrt(a + x**S(2)))**(n + S(4))*hyper((S(4), n/S(2) + S(2)), (n/S(2) + S(3),), -(x - sqrt(a + x**S(2)))**S(2)/a)/(a**S(4)*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n, x), x, (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(5))/(S(32)*e*f**S(4)*(n + S(5))) - (-S(5)*a*f**S(2) + S(5)*d**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(3))/(S(32)*e*f**S(4)*(n + S(3))) + S(5)*(-a*f**S(2) + d**S(2))**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))/(S(16)*e*f**S(4)*(n + S(1))) + (-a*f**S(2) + d**S(2))**S(5)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-5))/(S(32)*e*f**S(4)*(-n + S(5))) - S(5)*(-a*f**S(2) + d**S(2))**S(4)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-3))/(S(32)*e*f**S(4)*(-n + S(3))) + S(5)*(-a*f**S(2) + d**S(2))**S(3)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-1))/(S(16)*e*f**S(4)*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n, x), x, (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(3))/(S(8)*e*f**S(2)*(n + S(3))) - (-S(3)*a*f**S(2) + S(3)*d**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))/(S(8)*e*f**S(2)*(n + S(1))) + (-a*f**S(2) + d**S(2))**S(3)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-3))/(S(8)*e*f**S(2)*(-n + S(3))) - S(3)*(-a*f**S(2) + d**S(2))**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-1))/(S(8)*e*f**S(2)*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n, x), x, (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))/(S(2)*e*(n + S(1))) + (-a*f**S(2) + d**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-1))/(S(2)*e*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)), x), x, -S(2)*f**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))*hyper((S(1), n/S(2) + S(1)/2), (n/S(2) + S(3)/2,), (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**S(2)/(-a*f**S(2) + d**S(2)))/(e*(n + S(1))*(-a*f**S(2) + d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))**S(2), x), x, -S(8)*f**S(4)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(3))*hyper((S(3), n/S(2) + S(3)/2), (n/S(2) + S(5)/2,), (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**S(2)/(-a*f**S(2) + d**S(2)))/(e*(n + S(3))*(-a*f**S(2) + d**S(2))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt((a*f**S(2) + e*x*(S(2)*d + e*x))/f**S(2)))**n, x), x, (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))/(S(2)*e*(n + S(1))) + (-a*f**S(2) + d**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-1))/(S(2)*e*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt((a*f**S(2) + e*x*(S(2)*d + e*x))/f**S(2)))**n/(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)), x), x, -S(2)*f**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(1))*hyper((S(1), n/S(2) + S(1)/2), (n/S(2) + S(3)/2,), (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**S(2)/(-a*f**S(2) + d**S(2)))/(e*(n + S(1))*(-a*f**S(2) + d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))**(S(3)/2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n, x), x, (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(4))/(S(16)*e*f**S(3)*(n + S(4))) - (-a*f**S(2) + d**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(2))/(S(4)*e*f**S(3)*(n + S(2))) - (-a*f**S(2) + d**S(2))**S(4)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-4))/(S(16)*e*f**S(3)*(-n + S(4))) + (-a*f**S(2) + d**S(2))**S(3)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-2))/(S(4)*e*f**S(3)*(-n + S(2))) + S(3)*(-a*f**S(2) + d**S(2))**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(S(8)*e*f**S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n, x), x, (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(2))/(S(4)*e*f*(n + S(2))) - (-a*f**S(2) + d**S(2))**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-2))/(S(4)*e*f*(-n + S(2))) - (-a*f**S(2) + d**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(S(2)*e*f*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)), x), x, f*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(e*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))**(S(3)/2), x), x, S(4)*f**S(3)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(2))*hyper((S(2), n/S(2) + S(1)), (n/S(2) + S(2),), (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**S(2)/(-a*f**S(2) + d**S(2)))/(e*(n + S(2))*(-a*f**S(2) + d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt((a*f**S(2) + e*x*(S(2)*d + e*x))/f**S(2)))**n/sqrt((a*f**S(2) + e*x*(S(2)*d + e*x))/f**S(2)), x), x, f*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(e*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n*sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2)), x), x, (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(2))*sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2))/(S(4)*e*f*(n + S(2))*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))) - (-a*f**S(2) + d**S(2))**S(2)*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(-2))*sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2))/(S(4)*e*f*(-n + S(2))*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))) - (-a*f**S(2) + d**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n*sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2))/(S(2)*e*f*n*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2)), x), x, f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(e*n*sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2))**(S(3)/2), x), x, S(4)*f**S(3)*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**(n + S(2))*hyper((S(2), n/S(2) + S(1)), (n/S(2) + S(2),), (d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**S(2)/(-a*f**S(2) + d**S(2)))/(e*g*(n + S(2))*(-a*f**S(2) + d**S(2))**S(2)*sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*sqrt((a*f**S(2) + e*x*(S(2)*d + e*x))/f**S(2)))**n/sqrt((a*f**S(2)*g + e*g*x*(S(2)*d + e*x))/f**S(2)), x), x, f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2))*(d + e*x + f*sqrt(a + S(2)*d*e*x/f**S(2) + e**S(2)*x**S(2)/f**S(2)))**n/(e*n*sqrt(a*g + S(2)*d*e*g*x/f**S(2) + e**S(2)*g*x**S(2)/f**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + c*x**S(4))*(d + e*x)), x), x, -e*atanh((a*e**S(2) + c*d**S(2)*x**S(2))/(sqrt(a + c*x**S(4))*sqrt(a*e**S(4) + c*d**S(4))))/(S(2)*sqrt(a*e**S(4) + c*d**S(4))) + atan(x*sqrt(-(a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))/sqrt(a + c*x**S(4)))/(S(2)*d*sqrt(-(a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))) + c**(S(1)/4)*d*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*sqrt(a + c*x**S(4))*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))) - sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*elliptic_pi((sqrt(a)*e**S(2) + sqrt(c)*d**S(2))**S(2)/(S(4)*sqrt(a)*sqrt(c)*d**S(2)*e**S(2)), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(4)*a**(S(1)/4)*c**(S(1)/4)*d*sqrt(a + c*x**S(4))*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + c*x**S(4))*(d + e*x)**S(2)), x), x, -a**(S(1)/4)*c**(S(1)/4)*e**S(2)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(sqrt(a + c*x**S(4))*(a*e**S(4) + c*d**S(4))) - a**(S(1)/4)*c**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-e**S(2) + sqrt(c)*d**S(2)/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(sqrt(a + c*x**S(4))*(S(2)*a*e**S(4) + S(2)*c*d**S(4))) + sqrt(c)*e**S(2)*x*sqrt(a + c*x**S(4))/((sqrt(a) + sqrt(c)*x**S(2))*(a*e**S(4) + c*d**S(4))) - c*d**S(3)*e*atanh((a*e**S(2) + c*d**S(2)*x**S(2))/(sqrt(a + c*x**S(4))*sqrt(a*e**S(4) + c*d**S(4))))/(a*e**S(4) + c*d**S(4))**(S(3)/2) - c*atan(x*sqrt(-(a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))/sqrt(a + c*x**S(4)))/(e**S(2)*(-(a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))**(S(3)/2)) - e**S(3)*sqrt(a + c*x**S(4))/((d + e*x)*(a*e**S(4) + c*d**S(4))) + c**(S(5)/4)*d**S(4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(a**(S(1)/4)*sqrt(a + c*x**S(4))*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*(a*e**S(4) + c*d**S(4))) - c**(S(3)/4)*d**S(2)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*elliptic_pi((sqrt(a)*e**S(2) + sqrt(c)*d**S(2))**S(2)/(S(4)*sqrt(a)*sqrt(c)*d**S(2)*e**S(2)), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*sqrt(a + c*x**S(4))*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*(a*e**S(4) + c*d**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -e*atanh((S(2)*a*e**S(2) + b*d**S(2) + x**S(2)*(b*e**S(2) + S(2)*c*d**S(2)))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))))/(S(2)*sqrt(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))) + atan(x*sqrt(-b - (a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))/sqrt(a + b*x**S(2) + c*x**S(4)))/(S(2)*d*sqrt(-b - (a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))) + c**(S(1)/4)*d*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*elliptic_pi((sqrt(a)*e**S(2) + sqrt(c)*d**S(2))**S(2)/(S(4)*sqrt(a)*sqrt(c)*d**S(2)*e**S(2)), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(4)*a**(S(1)/4)*c**(S(1)/4)*d*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -a**(S(1)/4)*c**(S(1)/4)*e**S(2)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))) - a**(S(1)/4)*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-e**S(2) + sqrt(c)*d**S(2)/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(sqrt(a + b*x**S(2) + c*x**S(4))*(S(2)*a*e**S(4) + S(2)*b*d**S(2)*e**S(2) + S(2)*c*d**S(4))) + sqrt(c)*e**S(2)*x*sqrt(a + b*x**S(2) + c*x**S(4))/((sqrt(a) + sqrt(c)*x**S(2))*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))) - d*e*(b*e**S(2) + S(2)*c*d**S(2))*atanh((S(2)*a*e**S(2) + b*d**S(2) + x**S(2)*(b*e**S(2) + S(2)*c*d**S(2)))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))))/(S(2)*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))**(S(3)/2)) - e**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))/((d + e*x)*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))) - (b*e**S(2) + S(2)*c*d**S(2))*atan(x*sqrt(-b - (a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))/sqrt(a + b*x**S(2) + c*x**S(4)))/(S(2)*d**S(2)*e**S(2)*(-b - (a*e**S(4) + c*d**S(4))/(d**S(2)*e**S(2)))**(S(3)/2)) + c**(S(1)/4)*d**S(2)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(b*e**S(2) + S(2)*c*d**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))) - sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*(b*e**S(2) + S(2)*c*d**S(2))*elliptic_pi((sqrt(a)*e**S(2) + sqrt(c)*d**S(2))**S(2)/(S(4)*sqrt(a)*sqrt(c)*d**S(2)*e**S(2)), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(4)*a**(S(1)/4)*c**(S(1)/4)*(sqrt(a)*e**S(2) + sqrt(c)*d**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/(a*d - c*d*x**S(4)), x), x, -sqrt(-S(2)*sqrt(a)*sqrt(c) + b)*atanh(x*sqrt(-S(2)*sqrt(a)*sqrt(c) + b)/sqrt(a + b*x**S(2) + c*x**S(4)))/(S(4)*sqrt(a)*sqrt(c)*d) + sqrt(S(2)*sqrt(a)*sqrt(c) + b)*atanh(x*sqrt(S(2)*sqrt(a)*sqrt(c) + b)/sqrt(a + b*x**S(2) + c*x**S(4)))/(S(4)*sqrt(a)*sqrt(c)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) - c*x**S(4))/(a*d + c*d*x**S(4)), x), x, sqrt(S(2))*sqrt(-b + sqrt(S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*x*sqrt(-b + sqrt(S(4)*a*c + b**S(2)))*(b - S(2)*c*x**S(2) + sqrt(S(4)*a*c + b**S(2)))/(S(4)*sqrt(a)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))))/(S(4)*sqrt(a)*sqrt(c)*d) - sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*x*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(b - S(2)*c*x**S(2) - sqrt(S(4)*a*c + b**S(2)))/(S(4)*sqrt(a)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))))/(S(4)*sqrt(a)*sqrt(c)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x), x), x, b*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(c + d*x**S(2) + e*x)**(S(3)/2)/(S(5)*d*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(c + d*x**S(2) + e*x)**(S(3)/2)*(-S(80)*a*d**S(2) + S(32)*b*c*d + S(42)*b*d*e*x - S(35)*b*e**S(2))/(S(240)*d**S(3)*(a + b*x**S(2))) + e*(S(2)*d*x + e)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)*(-S(16)*a*d**S(2) + S(12)*b*c*d - S(7)*b*e**S(2))/(S(128)*d**S(4)*(a + b*x**S(2))) + e*(S(4)*c*d - e**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(-S(16)*a*d**S(2) + S(12)*b*c*d - S(7)*b*e**S(2))*atanh((S(2)*d*x + e)/(S(2)*sqrt(d)*sqrt(c + d*x**S(2) + e*x)))/(S(256)*d**(S(9)/2)*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x), x), x, -b*(-S(6)*d*x + S(5)*e)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(c + d*x**S(2) + e*x)**(S(3)/2)/(S(24)*d**S(2)*(a + b*x**S(2))) - (S(2)*d*x + e)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)*(-S(16)*a*d**S(2) + S(4)*b*c*d - S(5)*b*e**S(2))/(S(64)*d**S(3)*(a + b*x**S(2))) - (S(4)*c*d - e**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(-S(16)*a*d**S(2) + S(4)*b*c*d - S(5)*b*e**S(2))*atanh((S(2)*d*x + e)/(S(2)*sqrt(d)*sqrt(c + d*x**S(2) + e*x)))/(S(128)*d**(S(7)/2)*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)/x, x), x, -a*sqrt(c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh((S(2)*c + e*x)/(S(2)*sqrt(c)*sqrt(c + d*x**S(2) + e*x)))/(a + b*x**S(2)) + b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(c + d*x**S(2) + e*x)**(S(3)/2)/(S(3)*d*(a + b*x**S(2))) + sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)*(S(8)*a*d**S(2) - S(2)*b*d*e*x - b*e**S(2))/(S(8)*d**S(2)*(a + b*x**S(2))) + e*(S(8)*a*d**S(2) - b*(S(4)*c*d - e**S(2)))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh((S(2)*d*x + e)/(S(2)*sqrt(d)*sqrt(c + d*x**S(2) + e*x)))/(S(16)*d**(S(5)/2)*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)/x**S(2), x), x, -a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(c + d*x**S(2) + e*x)**(S(3)/2)/(c*x*(a + b*x**S(2))) - a*e*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh((S(2)*c + e*x)/(S(2)*sqrt(c)*sqrt(c + d*x**S(2) + e*x)))/(S(2)*sqrt(c)*(a + b*x**S(2))) + sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(S(8)*a*d**S(2) + S(4)*b*c*d - b*e**S(2))*atanh((S(2)*d*x + e)/(S(2)*sqrt(d)*sqrt(c + d*x**S(2) + e*x)))/(S(8)*d**(S(3)/2)*(a + b*x**S(2))) + (S(2)*d*x*(S(2)*a*d + b*c) + e*(S(4)*a*d + b*c))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)/(S(4)*c*d*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)/x**S(3), x), x, -a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(c + d*x**S(2) + e*x)**(S(3)/2)/(S(2)*c*x**S(2)*(a + b*x**S(2))) + b*e*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh((S(2)*d*x + e)/(S(2)*sqrt(d)*sqrt(c + d*x**S(2) + e*x)))/(S(2)*sqrt(d)*(a + b*x**S(2))) + (a*e + x*(S(2)*a*d + S(4)*b*c))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)/(S(4)*c*x*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(S(4)*a*c*d - a*e**S(2) + S(8)*b*c**S(2))*atanh((S(2)*c + e*x)/(S(2)*sqrt(c)*sqrt(c + d*x**S(2) + e*x)))/(S(8)*c**(S(3)/2)*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)/x**S(4), x), x, -a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*(c + d*x**S(2) + e*x)**(S(3)/2)/(S(3)*c*x**S(3)*(a + b*x**S(2))) + b*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh((S(2)*d*x + e)/(S(2)*sqrt(d)*sqrt(c + d*x**S(2) + e*x)))/(a + b*x**S(2)) + (S(2)*a*c*e - x*(-a*e**S(2) + S(8)*b*c**S(2)))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*sqrt(c + d*x**S(2) + e*x)/(S(8)*c**S(2)*x**S(2)*(a + b*x**S(2))) - e*(-a*(S(4)*c*d - e**S(2)) + S(8)*b*c**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh((S(2)*c + e*x)/(S(2)*sqrt(c)*sqrt(c + d*x**S(2) + e*x)))/(S(16)*c**(S(5)/2)*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(3))*sqrt(x**S(3) + S(1))), x), x, sqrt(S(26))*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(x + S(1))*atan(sqrt(S(2))*S(3)**(S(3)/4)*sqrt(S(1) - (x - sqrt(S(3)) + S(1))**S(2)/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-S(13)*sqrt(S(3)) + S(26))/(S(6)*sqrt(-S(4)*sqrt(S(3)) + S(7) + (x - sqrt(S(3)) + S(1))**S(2)/(x + S(1) + sqrt(S(3)))**S(2))))/(S(26)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))) + S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(S(15)*sqrt(S(3)) + S(26))*(x + S(1))*elliptic_f(asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(3)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))) - S(4)*S(3)**(S(1)/4)*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(x + S(1))*elliptic_pi(-S(56)*sqrt(S(3)) + S(97), asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-sqrt(S(3)) + S(2))*sqrt(x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(3))*sqrt(-x**S(3) + S(1))), x), x, -sqrt(S(7))*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*(-x + S(1))*atanh(S(3)**(S(3)/4)*sqrt(S(1) - (-x - sqrt(S(3)) + S(1))**S(2)/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-S(7)*sqrt(S(3)) + S(14))/(S(6)*sqrt(-S(4)*sqrt(S(3)) + S(7) + (-x - sqrt(S(3)) + S(1))**S(2)/(-x + S(1) + sqrt(S(3)))**S(2))))/(S(14)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))) - S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(sqrt(S(3)) + S(2))*(-x + S(1))*elliptic_f(asin((-x - sqrt(S(3)) + S(1))/(-x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(3)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*(sqrt(S(3)) + S(4))*sqrt(-x**S(3) + S(1))) - S(4)*S(3)**(S(1)/4)*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(sqrt(S(3)) + S(2))*(-x + S(1))*elliptic_pi(S(304)*sqrt(S(3))/S(169) + S(553)/169, asin((-x - sqrt(S(3)) + S(1))/(-x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(13)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(3))*sqrt(x**S(3) + S(-1))), x), x, -sqrt(S(7))*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*(-x + S(1))*atan(S(3)**(S(3)/4)*sqrt(S(7)*sqrt(S(3)) + S(14))*sqrt(-(-x + S(1) + sqrt(S(3)))**S(2)/(-x - sqrt(S(3)) + S(1))**S(2) + S(1))/(S(6)*sqrt((-x + S(1) + sqrt(S(3)))**S(2)/(-x - sqrt(S(3)) + S(1))**S(2) + S(4)*sqrt(S(3)) + S(7))))/(S(14)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))) - S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(-S(3)*sqrt(S(3)) + S(14))*(-x + S(1))*elliptic_f(asin((-x + S(1) + sqrt(S(3)))/(-x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(39)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))) + S(4)*S(3)**(S(1)/4)*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(-sqrt(S(3)) + S(2))*(-x + S(1))*elliptic_pi(-S(304)*sqrt(S(3))/S(169) + S(553)/169, asin((-x + S(1) + sqrt(S(3)))/(-x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(13)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(3))*sqrt(-x**S(3) + S(-1))), x), x, sqrt(S(26))*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*(x + S(1))*atanh(sqrt(S(2))*S(3)**(S(3)/4)*sqrt(S(13)*sqrt(S(3)) + S(26))*sqrt(-(x + S(1) + sqrt(S(3)))**S(2)/(x - sqrt(S(3)) + S(1))**S(2) + S(1))/(S(6)*sqrt((x + S(1) + sqrt(S(3)))**S(2)/(x - sqrt(S(3)) + S(1))**S(2) + S(4)*sqrt(S(3)) + S(7))))/(S(26)*sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-x**S(3) + S(-1))) + S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-S(15)*sqrt(S(3)) + S(26))*(x + S(1))*elliptic_f(asin((x + S(1) + sqrt(S(3)))/(x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(3)*sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-x**S(3) + S(-1))) + S(4)*S(3)**(S(1)/4)*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*(x + S(1))*elliptic_pi(S(56)*sqrt(S(3)) + S(97), asin((x + S(1) + sqrt(S(3)))/(x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(sqrt(S(3)) + S(2))*sqrt(-x**S(3) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((x + S(3))*sqrt(x**S(3) + S(1))), x), x, -S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(S(112)*sqrt(S(3)) + S(194))*(x + S(1))*elliptic_f(asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(3)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))) + S(12)*S(3)**(S(1)/4)*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(x + S(1))*elliptic_pi(-S(56)*sqrt(S(3)) + S(97), asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-sqrt(S(3)) + S(2))*sqrt(x**S(3) + S(1))) - sqrt(S(26))*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(S(3)*x + S(3))*atan(sqrt(S(2))*S(3)**(S(3)/4)*sqrt(S(1) - (x - sqrt(S(3)) + S(1))**S(2)/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-S(13)*sqrt(S(3)) + S(26))/(S(6)*sqrt(-S(4)*sqrt(S(3)) + S(7) + (x - sqrt(S(3)) + S(1))**S(2)/(x + S(1) + sqrt(S(3)))**S(2))))/(S(26)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((x + S(3))*sqrt(-x**S(3) + S(1))), x), x, sqrt(S(7))*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*(-S(3)*x + S(3))*atanh(S(3)**(S(3)/4)*sqrt(S(1) - (-x - sqrt(S(3)) + S(1))**S(2)/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-S(7)*sqrt(S(3)) + S(14))/(S(6)*sqrt(-S(4)*sqrt(S(3)) + S(7) + (-x - sqrt(S(3)) + S(1))**S(2)/(-x + S(1) + sqrt(S(3)))**S(2))))/(S(14)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))) - S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(S(40)*sqrt(S(3)) + S(74))*(-x + S(1))*elliptic_f(asin((-x - sqrt(S(3)) + S(1))/(-x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(39)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))) + S(12)*S(3)**(S(1)/4)*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(sqrt(S(3)) + S(2))*(-x + S(1))*elliptic_pi(S(304)*sqrt(S(3))/S(169) + S(553)/169, asin((-x - sqrt(S(3)) + S(1))/(-x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(13)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((x + S(3))*sqrt(x**S(3) + S(-1))), x), x, sqrt(S(7))*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*(-S(3)*x + S(3))*atan(S(3)**(S(3)/4)*sqrt(S(7)*sqrt(S(3)) + S(14))*sqrt(-(-x + S(1) + sqrt(S(3)))**S(2)/(-x - sqrt(S(3)) + S(1))**S(2) + S(1))/(S(6)*sqrt((-x + S(1) + sqrt(S(3)))**S(2)/(-x - sqrt(S(3)) + S(1))**S(2) + S(4)*sqrt(S(3)) + S(7))))/(S(14)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))) + S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(-S(40)*sqrt(S(3)) + S(74))*(-x + S(1))*elliptic_f(asin((-x + S(1) + sqrt(S(3)))/(-x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(39)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))) - S(12)*S(3)**(S(1)/4)*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(-sqrt(S(3)) + S(2))*(-x + S(1))*elliptic_pi(-S(304)*sqrt(S(3))/S(169) + S(553)/169, asin((-x + S(1) + sqrt(S(3)))/(-x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(13)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((x + S(3))*sqrt(-x**S(3) + S(-1))), x), x, S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-S(112)*sqrt(S(3)) + S(194))*(x + S(1))*elliptic_f(asin((x + S(1) + sqrt(S(3)))/(x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(3)*sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-x**S(3) + S(-1))) - S(12)*S(3)**(S(1)/4)*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*(x + S(1))*elliptic_pi(S(56)*sqrt(S(3)) + S(97), asin((x + S(1) + sqrt(S(3)))/(x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(sqrt(S(3)) + S(2))*sqrt(-x**S(3) + S(-1))) - sqrt(S(26))*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*(S(3)*x + S(3))*atanh(sqrt(S(2))*S(3)**(S(3)/4)*sqrt(S(13)*sqrt(S(3)) + S(26))*sqrt(-(x + S(1) + sqrt(S(3)))**S(2)/(x - sqrt(S(3)) + S(1))**S(2) + S(1))/(S(6)*sqrt((x + S(1) + sqrt(S(3)))**S(2)/(x - sqrt(S(3)) + S(1))**S(2) + S(4)*sqrt(S(3)) + S(7))))/(S(26)*sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-x**S(3) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*x + S(2))/((x + S(3))*sqrt(x**S(3) + S(1))), x), x, S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(S(1560)*sqrt(S(3)) + S(2702))*(x + S(1))*elliptic_f(asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(3)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))) - S(44)*S(3)**(S(1)/4)*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(x + S(1))*elliptic_pi(-S(56)*sqrt(S(3)) + S(97), asin((x - sqrt(S(3)) + S(1))/(x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-sqrt(S(3)) + S(2))*sqrt(x**S(3) + S(1))) + sqrt(S(26))*sqrt((x**S(2) - x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*(S(11)*x + S(11))*atan(sqrt(S(2))*S(3)**(S(3)/4)*sqrt(S(1) - (x - sqrt(S(3)) + S(1))**S(2)/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(-S(13)*sqrt(S(3)) + S(26))/(S(6)*sqrt(-S(4)*sqrt(S(3)) + S(7) + (x - sqrt(S(3)) + S(1))**S(2)/(x + S(1) + sqrt(S(3)))**S(2))))/(S(26)*sqrt((x + S(1))/(x + S(1) + sqrt(S(3)))**S(2))*sqrt(x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*x + S(2))/((x + S(3))*sqrt(-x**S(3) + S(1))), x), x, -sqrt(S(7))*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*(-S(11)*x + S(11))*atanh(S(3)**(S(3)/4)*sqrt(S(1) - (-x - sqrt(S(3)) + S(1))**S(2)/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-S(7)*sqrt(S(3)) + S(14))/(S(6)*sqrt(-S(4)*sqrt(S(3)) + S(7) + (-x - sqrt(S(3)) + S(1))**S(2)/(-x + S(1) + sqrt(S(3)))**S(2))))/(S(14)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))) + S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(S(168)*sqrt(S(3)) + S(446))*(-x + S(1))*elliptic_f(asin((-x - sqrt(S(3)) + S(1))/(-x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(39)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))) - S(44)*S(3)**(S(1)/4)*sqrt((x**S(2) + x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(sqrt(S(3)) + S(2))*(-x + S(1))*elliptic_pi(S(304)*sqrt(S(3))/S(169) + S(553)/169, asin((-x - sqrt(S(3)) + S(1))/(-x + S(1) + sqrt(S(3)))), S(-7) - S(4)*sqrt(S(3)))/(S(13)*sqrt((-x + S(1))/(-x + S(1) + sqrt(S(3)))**S(2))*sqrt(-x**S(3) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*x + S(2))/((x + S(3))*sqrt(x**S(3) + S(-1))), x), x, -sqrt(S(7))*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*(-S(11)*x + S(11))*atan(S(3)**(S(3)/4)*sqrt(S(7)*sqrt(S(3)) + S(14))*sqrt(-(-x + S(1) + sqrt(S(3)))**S(2)/(-x - sqrt(S(3)) + S(1))**S(2) + S(1))/(S(6)*sqrt((-x + S(1) + sqrt(S(3)))**S(2)/(-x - sqrt(S(3)) + S(1))**S(2) + S(4)*sqrt(S(3)) + S(7))))/(S(14)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))) - S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(-S(168)*sqrt(S(3)) + S(446))*(-x + S(1))*elliptic_f(asin((-x + S(1) + sqrt(S(3)))/(-x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(39)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))) + S(44)*S(3)**(S(1)/4)*sqrt((x**S(2) + x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(-sqrt(S(3)) + S(2))*(-x + S(1))*elliptic_pi(-S(304)*sqrt(S(3))/S(169) + S(553)/169, asin((-x + S(1) + sqrt(S(3)))/(-x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(13)*sqrt(-(-x + S(1))/(-x - sqrt(S(3)) + S(1))**S(2))*sqrt(x**S(3) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*x + S(2))/((x + S(3))*sqrt(-x**S(3) + S(-1))), x), x, -S(2)*S(3)**(S(3)/4)*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-S(1560)*sqrt(S(3)) + S(2702))*(x + S(1))*elliptic_f(asin((x + S(1) + sqrt(S(3)))/(x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(S(3)*sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-x**S(3) + S(-1))) + S(44)*S(3)**(S(1)/4)*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*(x + S(1))*elliptic_pi(S(56)*sqrt(S(3)) + S(97), asin((x + S(1) + sqrt(S(3)))/(x - sqrt(S(3)) + S(1))), S(-7) + S(4)*sqrt(S(3)))/(sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(sqrt(S(3)) + S(2))*sqrt(-x**S(3) + S(-1))) + sqrt(S(26))*sqrt((x**S(2) - x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*(S(11)*x + S(11))*atanh(sqrt(S(2))*S(3)**(S(3)/4)*sqrt(S(13)*sqrt(S(3)) + S(26))*sqrt(-(x + S(1) + sqrt(S(3)))**S(2)/(x - sqrt(S(3)) + S(1))**S(2) + S(1))/(S(6)*sqrt((x + S(1) + sqrt(S(3)))**S(2)/(x - sqrt(S(3)) + S(1))**S(2) + S(4)*sqrt(S(3)) + S(7))))/(S(26)*sqrt(-(x + S(1))/(x - sqrt(S(3)) + S(1))**S(2))*sqrt(-x**S(3) + S(-1))), expand=True, _diff=True, _numerical=True) # sympy and mathematica assert rubi_test(rubi_integrate((d**S(3) + e**S(3)*x**S(3))**p/(d + e*x), x), x, (S(1) + (S(2)*d + S(2)*e*x)/(d*(S(-3) + sqrt(S(3))*I)))**(-p)*(S(1) - (S(2)*d + S(2)*e*x)/(d*(S(3) + sqrt(S(3))*I)))**(-p)*(d**S(3) + e**S(3)*x**S(3))**p*AppellF1(p, -p, -p, p + S(1), -(S(2)*d + S(2)*e*x)/(d*(S(-3) + sqrt(S(3))*I)), (S(2)*d + S(2)*e*x)/(d*(S(3) + sqrt(S(3))*I)))/(e*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x)*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x, a*sqrt(e)*sqrt(f)*sqrt(c + d*x**S(2))*elliptic_f(atan(sqrt(f)*x/sqrt(e)), S(1) - d*e/(c*f))/(c*sqrt(e*(c + d*x**S(2))/(c*(e + f*x**S(2))))*sqrt(e + f*x**S(2))*(a**S(2)*f + b**S(2)*e)) - b*atanh(sqrt(c + d*x**S(2))*sqrt(a**S(2)*f + b**S(2)*e)/(sqrt(e + f*x**S(2))*sqrt(a**S(2)*d + b**S(2)*c)))/(sqrt(a**S(2)*d + b**S(2)*c)*sqrt(a**S(2)*f + b**S(2)*e)) + b**S(2)*e**(S(3)/2)*sqrt(c + d*x**S(2))*elliptic_pi(S(1) + b**S(2)*e/(a**S(2)*f), atan(sqrt(f)*x/sqrt(e)), S(1) - d*e/(c*f))/(a*c*sqrt(f)*sqrt(e*(c + d*x**S(2))/(c*(e + f*x**S(2))))*sqrt(e + f*x**S(2))*(a**S(2)*f + b**S(2)*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e - S(2)*f*x**S(2))/(S(4)*d*f*x**S(2) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, -log(e - S(2)*sqrt(f)*x*sqrt(-d) + S(2)*f*x**S(2))/(S(4)*sqrt(f)*sqrt(-d)) + log(e + S(2)*sqrt(f)*x*sqrt(-d) + S(2)*f*x**S(2))/(S(4)*sqrt(f)*sqrt(-d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e - S(2)*f*x**S(2))/(-S(4)*d*f*x**S(2) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, -log(-S(2)*sqrt(d)*sqrt(f)*x + e + S(2)*f*x**S(2))/(S(4)*sqrt(d)*sqrt(f)) + log(S(2)*sqrt(d)*sqrt(f)*x + e + S(2)*f*x**S(2))/(S(4)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e - S(4)*f*x**S(3))/(S(4)*d*f*x**S(2) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x/(e + S(2)*f*x**S(3)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e - S(4)*f*x**S(3))/(-S(4)*d*f*x**S(2) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x/(e + S(2)*f*x**S(3)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e - S(2)*f*x**n*(n + S(-1)))/(S(4)*d*f*x**S(2) + e**S(2) + S(4)*e*f*x**n + S(4)*f**S(2)*x**(S(2)*n)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x/(e + S(2)*f*x**n))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((e - S(2)*f*x**n*(n + S(-1)))/(-S(4)*d*f*x**S(2) + e**S(2) + S(4)*e*f*x**n + S(4)*f**S(2)*x**(S(2)*n)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x/(e + S(2)*f*x**n))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(S(4)*d*f*x**S(4) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, atan(sqrt(f)*(e + x**S(2)*(S(2)*d + S(2)*f))/(sqrt(d)*e))/(S(4)*sqrt(d)*e*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(-S(4)*d*f*x**S(4) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, -atanh(sqrt(f)*(e - x**S(2)*(S(2)*d - S(2)*f))/(sqrt(d)*e))/(S(4)*sqrt(d)*e*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(S(3)*e + S(2)*f*x**S(2))/(S(4)*d*f*x**S(6) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x**S(3)/(e + S(2)*f*x**S(2)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(S(3)*e + S(2)*f*x**S(2))/(-S(4)*d*f*x**S(6) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x**S(3)/(e + S(2)*f*x**S(2)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**S(2)*(m + S(-1)))/(S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))/(e + S(2)*f*x**S(2)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**S(2)*(m + S(-1)))/(S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))*(-m**S(2) + S(1))/((e + S(2)*f*x**S(2))*(-m + S(1))*(m + S(1))))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**S(2)*(m + S(-1)))/(-S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))/(e + S(2)*f*x**S(2)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**S(2)*(m + S(-1)))/(-S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**S(2) + S(4)*f**S(2)*x**S(4)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))*(-m**S(2) + S(1))/((e + S(2)*f*x**S(2))*(-m + S(1))*(m + S(1))))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*e - S(2)*f*x**S(3))/(S(4)*d*f*x**S(4) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x**S(2)/(e + S(2)*f*x**S(3)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*e - S(2)*f*x**S(3))/(-S(4)*d*f*x**S(4) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x**S(2)/(e + S(2)*f*x**S(3)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(S(4)*d*f*x**S(6) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, atan(sqrt(f)*(e + x**S(3)*(S(2)*d + S(2)*f))/(sqrt(d)*e))/(S(6)*sqrt(d)*e*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(-S(4)*d*f*x**S(6) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, -atanh(sqrt(f)*(e - x**S(3)*(S(2)*d - S(2)*f))/(sqrt(d)*e))/(S(6)*sqrt(d)*e*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**S(3)*(m + S(-2)))/(S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))/(e + S(2)*f*x**S(3)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**S(3)*(m + S(-2)))/(-S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**S(3) + S(4)*f**S(2)*x**S(6)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))/(e + S(2)*f*x**S(3)))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**n*(m - n + S(1)))/(S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**n + S(4)*f**S(2)*x**(S(2)*n)), x), x, atan(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))/(e + S(2)*f*x**n))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(e*(m + S(1)) + S(2)*f*x**n*(m - n + S(1)))/(-S(4)*d*f*x**(S(2)*m + S(2)) + e**S(2) + S(4)*e*f*x**n + S(4)*f**S(2)*x**(S(2)*n)), x), x, atanh(S(2)*sqrt(d)*sqrt(f)*x**(m + S(1))/(e + S(2)*f*x**n))/(S(2)*sqrt(d)*sqrt(f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2))), x), x, -x**S(2)*(S(2)*a*c**S(2) - d**S(2))/(S(2)*b**S(2)*c**S(3)) + (a + b*x**S(2))**S(2)/(S(4)*b**S(3)*c) - d*(a + b*x**S(2))**(S(3)/2)/(S(3)*b**S(3)*c**S(2)) + d*sqrt(a + b*x**S(2))*(S(2)*a*c**S(2) - d**S(2))/(b**S(3)*c**S(4)) + (a*c**S(2) - d**S(2))**S(2)*log(c*sqrt(a + b*x**S(2)) + d)/(b**S(3)*c**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2))), x), x, x**S(2)/(S(2)*b*c) - d*sqrt(a + b*x**S(2))/(b**S(2)*c**S(2)) - (a*c**S(2) - d**S(2))*log(c*sqrt(a + b*x**S(2)) + d)/(b**S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2))), x), x, log(c*sqrt(a + b*x**S(2)) + d)/(b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2)))), x), x, c*log(x)/(a*c**S(2) - d**S(2)) - c*log(c*sqrt(a + b*x**S(2)) + d)/(a*c**S(2) - d**S(2)) + d*atanh(sqrt(a + b*x**S(2))/sqrt(a))/(sqrt(a)*(a*c**S(2) - d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2)))), x), x, -b*c**S(3)*log(x)/(a*c**S(2) - d**S(2))**S(2) + b*c**S(3)*log(c*sqrt(a + b*x**S(2)) + d)/(a*c**S(2) - d**S(2))**S(2) - (a*c - d*sqrt(a + b*x**S(2)))/(S(2)*a*x**S(2)*(a*c**S(2) - d**S(2))) - b*d*(S(3)*a*c**S(2) - d**S(2))*atanh(sqrt(a + b*x**S(2))/sqrt(a))/(S(2)*a**(S(3)/2)*(a*c**S(2) - d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2))), x), x, x/(b*c) - d*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(b**(S(3)/2)*c**S(2)) - sqrt(a*c**S(2) - d**S(2))*atan(sqrt(b)*c*x/sqrt(a*c**S(2) - d**S(2)))/(b**(S(3)/2)*c**S(2)) + sqrt(a*c**S(2) - d**S(2))*atan(sqrt(b)*d*x/(sqrt(a + b*x**S(2))*sqrt(a*c**S(2) - d**S(2))))/(b**(S(3)/2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2))), x), x, atan(sqrt(b)*c*x/sqrt(a*c**S(2) - d**S(2)))/(sqrt(b)*sqrt(a*c**S(2) - d**S(2))) - atan(sqrt(b)*d*x/(sqrt(a + b*x**S(2))*sqrt(a*c**S(2) - d**S(2))))/(sqrt(b)*sqrt(a*c**S(2) - d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a*c + b*c*x**S(2) + d*sqrt(a + b*x**S(2)))), x), x, -sqrt(b)*c**S(2)*atan(sqrt(b)*c*x/sqrt(a*c**S(2) - d**S(2)))/(a*c**S(2) - d**S(2))**(S(3)/2) + sqrt(b)*c**S(2)*atan(sqrt(b)*d*x/(sqrt(a + b*x**S(2))*sqrt(a*c**S(2) - d**S(2))))/(a*c**S(2) - d**S(2))**(S(3)/2) - c/(x*(a*c**S(2) - d**S(2))) + d*sqrt(a + b*x**S(2))/(a*x*(a*c**S(2) - d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3))), x), x, -x**S(3)*(S(2)*a*c**S(2) - d**S(2))/(S(3)*b**S(2)*c**S(3)) + (a + b*x**S(3))**S(2)/(S(6)*b**S(3)*c) - S(2)*d*(a + b*x**S(3))**(S(3)/2)/(S(9)*b**S(3)*c**S(2)) + S(2)*d*sqrt(a + b*x**S(3))*(S(2)*a*c**S(2) - d**S(2))/(S(3)*b**S(3)*c**S(4)) + S(2)*(a*c**S(2) - d**S(2))**S(2)*log(c*sqrt(a + b*x**S(3)) + d)/(S(3)*b**S(3)*c**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3))), x), x, x**S(3)/(S(3)*b*c) - S(2)*d*sqrt(a + b*x**S(3))/(S(3)*b**S(2)*c**S(2)) - (S(2)*a*c**S(2) - S(2)*d**S(2))*log(c*sqrt(a + b*x**S(3)) + d)/(S(3)*b**S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3))), x), x, S(2)*log(c*sqrt(a + b*x**S(3)) + d)/(S(3)*b*c), expand=True, _diff=True, _numerical=True) # taking a long time assert rubi_test(rubi_integrate(S(1)/(x*(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3)))), x), x, -S(2)*c*log(c*sqrt(a + b*x**S(3)) + d)/(S(3)*a*c**S(2) - S(3)*d**S(2)) + c*log(x)/(a*c**S(2) - d**S(2)) + S(2)*d*atanh(sqrt(a + b*x**S(3))/sqrt(a))/(S(3)*sqrt(a)*(a*c**S(2) - d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3)))), x), x, -b*c**S(3)*log(x)/(a*c**S(2) - d**S(2))**S(2) + S(2)*b*c**S(3)*log(c*sqrt(a + b*x**S(3)) + d)/(S(3)*(a*c**S(2) - d**S(2))**S(2)) - (a*c - d*sqrt(a + b*x**S(3)))/(S(3)*a*x**S(3)*(a*c**S(2) - d**S(2))) - b*d*(S(3)*a*c**S(2) - d**S(2))*atanh(sqrt(a + b*x**S(3))/sqrt(a))/(S(3)*a**(S(3)/2)*(a*c**S(2) - d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3))), x), x, -d*x**S(4)*sqrt(S(1) + b*x**S(3)/a)*AppellF1(S(4)/3, S(1)/2, S(1), S(7)/3, -b*x**S(3)/a, -b*c**S(2)*x**S(3)/(a*c**S(2) - d**S(2)))/(sqrt(a + b*x**S(3))*(S(4)*a*c**S(2) - S(4)*d**S(2))) + x/(b*c) - (a*c**S(2) - d**S(2))**(S(1)/3)*log(b**(S(1)/3)*c**(S(2)/3)*x + (a*c**S(2) - d**S(2))**(S(1)/3))/(S(3)*b**(S(4)/3)*c**(S(5)/3)) + (a*c**S(2) - d**S(2))**(S(1)/3)*log(b**(S(2)/3)*c**(S(4)/3)*x**S(2) - b**(S(1)/3)*c**(S(2)/3)*x*(a*c**S(2) - d**S(2))**(S(1)/3) + (a*c**S(2) - d**S(2))**(S(2)/3))/(S(6)*b**(S(4)/3)*c**(S(5)/3)) + sqrt(S(3))*(a*c**S(2) - d**S(2))**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*b**(S(1)/3)*c**(S(2)/3)*x/(a*c**S(2) - d**S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*b**(S(4)/3)*c**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3))), x), x, -d*x**S(2)*sqrt(S(1) + b*x**S(3)/a)*AppellF1(S(2)/3, S(1)/2, S(1), S(5)/3, -b*x**S(3)/a, -b*c**S(2)*x**S(3)/(a*c**S(2) - d**S(2)))/(sqrt(a + b*x**S(3))*(S(2)*a*c**S(2) - S(2)*d**S(2))) - log(b**(S(1)/3)*c**(S(2)/3)*x + (a*c**S(2) - d**S(2))**(S(1)/3))/(S(3)*b**(S(2)/3)*c**(S(1)/3)*(a*c**S(2) - d**S(2))**(S(1)/3)) + log(b**(S(2)/3)*c**(S(4)/3)*x**S(2) - b**(S(1)/3)*c**(S(2)/3)*x*(a*c**S(2) - d**S(2))**(S(1)/3) + (a*c**S(2) - d**S(2))**(S(2)/3))/(S(6)*b**(S(2)/3)*c**(S(1)/3)*(a*c**S(2) - d**S(2))**(S(1)/3)) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*b**(S(1)/3)*c**(S(2)/3)*x/(a*c**S(2) - d**S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*b**(S(2)/3)*c**(S(1)/3)*(a*c**S(2) - d**S(2))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3))), x), x, -d*x*sqrt(S(1) + b*x**S(3)/a)*AppellF1(S(1)/3, S(1)/2, S(1), S(4)/3, -b*x**S(3)/a, -b*c**S(2)*x**S(3)/(a*c**S(2) - d**S(2)))/(sqrt(a + b*x**S(3))*(a*c**S(2) - d**S(2))) + c**(S(1)/3)*log(b**(S(1)/3)*c**(S(2)/3)*x + (a*c**S(2) - d**S(2))**(S(1)/3))/(S(3)*b**(S(1)/3)*(a*c**S(2) - d**S(2))**(S(2)/3)) - c**(S(1)/3)*log(b**(S(2)/3)*c**(S(4)/3)*x**S(2) - b**(S(1)/3)*c**(S(2)/3)*x*(a*c**S(2) - d**S(2))**(S(1)/3) + (a*c**S(2) - d**S(2))**(S(2)/3))/(S(6)*b**(S(1)/3)*(a*c**S(2) - d**S(2))**(S(2)/3)) - sqrt(S(3))*c**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*b**(S(1)/3)*c**(S(2)/3)*x/(a*c**S(2) - d**S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*b**(S(1)/3)*(a*c**S(2) - d**S(2))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3)))), x), x, b**(S(1)/3)*c**(S(5)/3)*log(b**(S(1)/3)*c**(S(2)/3)*x + (a*c**S(2) - d**S(2))**(S(1)/3))/(S(3)*(a*c**S(2) - d**S(2))**(S(4)/3)) - b**(S(1)/3)*c**(S(5)/3)*log(b**(S(2)/3)*c**(S(4)/3)*x**S(2) - b**(S(1)/3)*c**(S(2)/3)*x*(a*c**S(2) - d**S(2))**(S(1)/3) + (a*c**S(2) - d**S(2))**(S(2)/3))/(S(6)*(a*c**S(2) - d**S(2))**(S(4)/3)) + sqrt(S(3))*b**(S(1)/3)*c**(S(5)/3)*atan(sqrt(S(3))*(-S(2)*b**(S(1)/3)*c**(S(2)/3)*x/(a*c**S(2) - d**S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(a*c**S(2) - d**S(2))**(S(4)/3)) - c/(x*(a*c**S(2) - d**S(2))) + d*sqrt(S(1) + b*x**S(3)/a)*AppellF1(S(-1)/3, S(1)/2, S(1), S(2)/3, -b*x**S(3)/a, -b*c**S(2)*x**S(3)/(a*c**S(2) - d**S(2)))/(x*sqrt(a + b*x**S(3))*(a*c**S(2) - d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a*c + b*c*x**S(3) + d*sqrt(a + b*x**S(3)))), x), x, -b**(S(2)/3)*c**(S(7)/3)*log(b**(S(1)/3)*c**(S(2)/3)*x + (a*c**S(2) - d**S(2))**(S(1)/3))/(S(3)*(a*c**S(2) - d**S(2))**(S(5)/3)) + b**(S(2)/3)*c**(S(7)/3)*log(b**(S(2)/3)*c**(S(4)/3)*x**S(2) - b**(S(1)/3)*c**(S(2)/3)*x*(a*c**S(2) - d**S(2))**(S(1)/3) + (a*c**S(2) - d**S(2))**(S(2)/3))/(S(6)*(a*c**S(2) - d**S(2))**(S(5)/3)) + sqrt(S(3))*b**(S(2)/3)*c**(S(7)/3)*atan(sqrt(S(3))*(-S(2)*b**(S(1)/3)*c**(S(2)/3)*x/(a*c**S(2) - d**S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(a*c**S(2) - d**S(2))**(S(5)/3)) - c/(x**S(2)*(S(2)*a*c**S(2) - S(2)*d**S(2))) + d*sqrt(S(1) + b*x**S(3)/a)*AppellF1(S(-2)/3, S(1)/2, S(1), S(1)/3, -b*x**S(3)/a, -b*c**S(2)*x**S(3)/(a*c**S(2) - d**S(2)))/(x**S(2)*sqrt(a + b*x**S(3))*(S(2)*a*c**S(2) - S(2)*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*c + b*c*x**n + d*sqrt(a + b*x**n)), x), x, c*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -b*c**S(2)*x**n/(a*c**S(2) - d**S(2)))/(a*c**S(2) - d**S(2)) - d*x*sqrt(S(1) + b*x**n/a)*AppellF1(S(1)/n, S(1)/2, S(1), S(1) + S(1)/n, -b*x**n/a, -b*c**S(2)*x**n/(a*c**S(2) - d**S(2)))/(sqrt(a + b*x**n)*(a*c**S(2) - d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(a*c + b*c*x**n + d*sqrt(a + b*x**n)), x), x, c*x**(m + S(1))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -b*c**S(2)*x**n/(a*c**S(2) - d**S(2)))/((m + S(1))*(a*c**S(2) - d**S(2))) - d*x**(m + S(1))*sqrt(S(1) + b*x**n/a)*AppellF1((m + S(1))/n, S(1)/2, S(1), (m + n + S(1))/n, -b*x**n/a, -b*c**S(2)*x**n/(a*c**S(2) - d**S(2)))/(sqrt(a + b*x**n)*(m + S(1))*(a*c**S(2) - d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))/(a*c + b*c*x**n + d*sqrt(a + b*x**n)), x), x, S(2)*log(c*sqrt(a + b*x**n) + d)/(b*c*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(4)*x**(S(3)/2) + sqrt(x)), x), x, atan(S(2)*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-x**(S(5)/2) + sqrt(x)), x), x, atan(sqrt(x)) + atanh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-x**(S(1)/4) + sqrt(x)), x), x, S(4)*x**(S(1)/4) + S(2)*sqrt(x) + S(4)*log(-x**(S(1)/4) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(1)/3) + sqrt(x)), x), x, S(6)*x**(S(1)/6) - S(3)*x**(S(1)/3) + S(2)*sqrt(x) - S(6)*log(x**(S(1)/6) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(1)/4) + sqrt(x)), x), x, -S(4)*x**(S(1)/4) + S(2)*sqrt(x) + S(4)*log(x**(S(1)/4) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(2)/3) - x**(S(1)/3)), x), x, S(3)*x**(S(1)/3) + S(3)*log(-x**(S(1)/3) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x) + x**(S(-1)/4)), x), x, S(2)*sqrt(x) + S(4)*log(x**(S(1)/4) + S(1))/S(3) - S(2)*log(-x**(S(1)/4) + sqrt(x) + S(1))/S(3) + S(4)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**(S(1)/4) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(1)/4) + x**(S(1)/3)), x), x, -S(12)*x**(S(7)/12)/S(7) - S(12)*x**(S(5)/12)/S(5) - S(12)*x**(S(1)/12) + S(6)*x**(S(1)/6) - S(4)*x**(S(1)/4) + S(3)*x**(S(2)/3)/S(2) + S(3)*x**(S(1)/3) + S(2)*sqrt(x) + S(12)*log(x**(S(1)/12) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(-1)/3) + x**(S(-1)/4)), x), x, S(12)*x**(S(13)/12)/S(13) + S(12)*x**(S(11)/12)/S(11) + S(12)*x**(S(7)/12)/S(7) + S(12)*x**(S(5)/12)/S(5) + S(12)*x**(S(1)/12) - S(6)*x**(S(7)/6)/S(7) - S(6)*x**(S(5)/6)/S(5) - S(6)*x**(S(1)/6) + S(4)*x**(S(5)/4)/S(5) + S(4)*x**(S(3)/4)/S(3) + S(4)*x**(S(1)/4) - S(3)*x**(S(2)/3)/S(2) - S(3)*x**(S(1)/3) - S(2)*sqrt(x) - x - S(12)*log(x**(S(1)/12) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x) - S(1)/x**(S(1)/3)), x), x, S(2)*sqrt(x) + S(6)*log(-x**(S(1)/6) + S(1))/S(5) - (-S(3)*sqrt(S(5))/S(10) + S(3)/10)*log(x**(S(1)/6) + sqrt(S(5))*x**(S(1)/6) + S(2)*x**(S(1)/3) + S(2)) - (S(3)/10 + S(3)*sqrt(S(5))/S(10))*log(-sqrt(S(5))*x**(S(1)/6) + x**(S(1)/6) + S(2)*x**(S(1)/3) + S(2)) - S(3)*sqrt(S(2)*sqrt(S(5)) + S(10))*atan(sqrt(sqrt(S(5))/S(10) + S(1)/2)*(S(4)*x**(S(1)/6) + S(1) + sqrt(S(5)))/S(2))/S(5) + S(3)*sqrt(-S(2)*sqrt(S(5)) + S(10))*atan((S(4)*x**(S(1)/6) - sqrt(S(5)) + S(1))/sqrt(S(2)*sqrt(S(5)) + S(10)))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(x**S(2) + x), x), x, S(2)*atan(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(S(4)*sqrt(x) + x), x), x, -S(8)*sqrt(x) + x + S(32)*log(sqrt(x) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(x**(S(1)/3) + x), x), x, S(2)*sqrt(x) - S(3)*sqrt(S(2))*log(-sqrt(S(2))*x**(S(1)/6) + x**(S(1)/3) + S(1))/S(4) + S(3)*sqrt(S(2))*log(sqrt(S(2))*x**(S(1)/6) + x**(S(1)/3) + S(1))/S(4) - S(3)*sqrt(S(2))*atan(sqrt(S(2))*x**(S(1)/6) + S(-1))/S(2) - S(3)*sqrt(S(2))*atan(sqrt(S(2))*x**(S(1)/6) + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(1)/3)/(x**(S(1)/4) + sqrt(x)), x), x, -S(12)*x**(S(7)/12)/S(7) - S(12)*x**(S(1)/12) + S(6)*x**(S(5)/6)/S(5) + S(3)*x**(S(1)/3) + S(6)*log(x**(S(1)/12) + S(1)) - S(2)*log(x**(S(1)/4) + S(1)) - S(4)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**(S(1)/12) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(x**(S(1)/4) + x**(S(1)/3)), x), x, -S(12)*x**(S(13)/12)/S(13) - S(12)*x**(S(11)/12)/S(11) - S(12)*x**(S(7)/12)/S(7) - S(12)*x**(S(5)/12)/S(5) - S(12)*x**(S(1)/12) + S(6)*x**(S(7)/6)/S(7) + S(6)*x**(S(5)/6)/S(5) + S(6)*x**(S(1)/6) - S(4)*x**(S(3)/4)/S(3) - S(4)*x**(S(1)/4) + S(3)*x**(S(2)/3)/S(2) + S(3)*x**(S(1)/3) + S(2)*sqrt(x) + x + S(12)*log(x**(S(1)/12) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(sqrt(x) - S(1)/x**(S(1)/3)), x), x, S(6)*x**(S(1)/6) + x + S(6)*log(-x**(S(1)/6) + S(1))/S(5) - (S(3)/10 + S(3)*sqrt(S(5))/S(10))*log(x**(S(1)/6) + sqrt(S(5))*x**(S(1)/6) + S(2)*x**(S(1)/3) + S(2)) - (-S(3)*sqrt(S(5))/S(10) + S(3)/10)*log(-sqrt(S(5))*x**(S(1)/6) + x**(S(1)/6) + S(2)*x**(S(1)/3) + S(2)) - S(3)*sqrt(-S(2)*sqrt(S(5)) + S(10))*atan(sqrt(sqrt(S(5))/S(10) + S(1)/2)*(S(4)*x**(S(1)/6) + S(1) + sqrt(S(5)))/S(2))/S(5) - S(3)*sqrt(S(2)*sqrt(S(5)) + S(10))*atan((S(4)*x**(S(1)/6) - sqrt(S(5)) + S(1))/sqrt(S(2)*sqrt(S(5)) + S(10)))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + sqrt(a + b**S(2)*x**S(4)))/sqrt(a + b**S(2)*x**S(4)), x), x, sqrt(S(2))*atanh(sqrt(S(2))*sqrt(b)*x/sqrt(b*x**S(2) + sqrt(a + b**S(2)*x**S(4))))/(S(2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-b*x**S(2) + sqrt(a + b**S(2)*x**S(4)))/sqrt(a + b**S(2)*x**S(4)), x), x, sqrt(S(2))*atan(sqrt(S(2))*sqrt(b)*x/sqrt(-b*x**S(2) + sqrt(a + b**S(2)*x**S(4))))/(S(2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x**S(2) + sqrt(S(4)*x**S(4) + S(3)))/((c + d*x)*sqrt(S(4)*x**S(4) + S(3))), x), x, -(S(1)/2 + I/S(2))*atanh((-S(2)*I*c*x + sqrt(S(3))*d)/(sqrt(S(2)*I*c**S(2) + sqrt(S(3))*d**S(2))*sqrt(S(2)*I*x**S(2) + sqrt(S(3)))))/sqrt(S(2)*I*c**S(2) + sqrt(S(3))*d**S(2)) + (S(1)/2 - I/S(2))*atan((S(2)*I*c*x + sqrt(S(3))*d)/(sqrt(S(2)*I*c**S(2) - sqrt(S(3))*d**S(2))*sqrt(-S(2)*I*x**S(2) + sqrt(S(3)))))/sqrt(S(2)*I*c**S(2) - sqrt(S(3))*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x**S(2) + sqrt(S(4)*x**S(4) + S(3)))/((c + d*x)**S(2)*sqrt(S(4)*x**S(4) + S(3))), x), x, c*(S(1) - I)*atanh((-S(2)*I*c*x + sqrt(S(3))*d)/(sqrt(S(2)*I*c**S(2) + sqrt(S(3))*d**S(2))*sqrt(S(2)*I*x**S(2) + sqrt(S(3)))))/(S(2)*I*c**S(2) + sqrt(S(3))*d**S(2))**(S(3)/2) + c*(S(1) + I)*atan((S(2)*I*c*x + sqrt(S(3))*d)/(sqrt(S(2)*I*c**S(2) - sqrt(S(3))*d**S(2))*sqrt(-S(2)*I*x**S(2) + sqrt(S(3)))))/(S(2)*I*c**S(2) - sqrt(S(3))*d**S(2))**(S(3)/2) - d*(S(1)/2 + I/S(2))*sqrt(S(2)*I*x**S(2) + sqrt(S(3)))/((c + d*x)*(S(2)*I*c**S(2) + sqrt(S(3))*d**S(2))) + d*(S(1)/2 - I/S(2))*sqrt(-S(2)*I*x**S(2) + sqrt(S(3)))/((c + d*x)*(S(2)*I*c**S(2) - sqrt(S(3))*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(-4))/(sqrt(x)*(x**(S(1)/3) + S(1))), x), x, S(6)*x**(S(7)/6)/S(7) - S(6)*x**(S(5)/6)/S(5) - S(30)*x**(S(1)/6) + S(2)*sqrt(x) + S(30)*atan(x**(S(1)/6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(x) + S(1))/(x**(S(7)/6) + x**(S(5)/6)), x), x, S(3)*x**(S(1)/3) - S(3)*log(x**(S(1)/3) + S(1)) + S(6)*atan(x**(S(1)/6)), expand=True, _diff=True, _numerical=True) # difference in simplify assert rubi_test(rubi_integrate((sqrt(x) + S(1))/(sqrt(x)*(x**(S(1)/3) + S(1))), x), x, S(6)*x**(S(1)/6) + S(3)*x**(S(2)/3)/S(2) - S(3)*x**(S(1)/3) + S(3)*log(x**(S(1)/3) + S(1)) - S(6)*atan(x**(S(1)/6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b/x**S(2) + S(2))/(b + S(2)*x**S(2)), x), x, -acsch(sqrt(S(2))*x/sqrt(b))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-b/x**S(2) + S(2))/(-b + S(2)*x**S(2)), x), x, -acsc(sqrt(S(2))*x/sqrt(b))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + c/x**S(2))/(d + e*x), x), x, sqrt(a)*atanh(sqrt(a + c/x**S(2))/sqrt(a))/e - sqrt(c)*atanh(sqrt(c)/(x*sqrt(a + c/x**S(2))))/d - sqrt(a*d**S(2) + c*e**S(2))*atanh((a*d - c*e/x)/(sqrt(a + c/x**S(2))*sqrt(a*d**S(2) + c*e**S(2))))/(d*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b/x + c/x**S(2))/(d + e*x), x), x, sqrt(a)*atanh((S(2)*a + b/x)/(S(2)*sqrt(a)*sqrt(a + b/x + c/x**S(2))))/e - sqrt(c)*atanh((b + S(2)*c/x)/(S(2)*sqrt(c)*sqrt(a + b/x + c/x**S(2))))/d - sqrt(a*d**S(2) - e*(b*d - c*e))*atanh((S(2)*a*d - b*e + (b*d - S(2)*c*e)/x)/(S(2)*sqrt(a*d**S(2) - e*(b*d - c*e))*sqrt(a + b/x + c/x**S(2))))/(d*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**(S(1)/6) + (x**S(3))**(S(1)/5))/sqrt(x), x), x, S(3)*x**(S(2)/3)/S(2) + S(10)*sqrt(x)*(x**S(3))**(S(1)/5)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))/sqrt(-x**S(2) + S(4)*x), x), x, -sqrt(-x**S(2) + S(4)*x) + S(4)*asin(x/S(2) + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(3))/(x**S(2) + S(6)*x)**(S(1)/3), x), x, S(3)*(x**S(2) + S(6)*x)**(S(2)/3)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(4))/(-x**S(2) + S(6)*x)**(S(3)/2), x), x, -(-S(7)*x + S(12))/(S(9)*sqrt(-x**S(2) + S(6)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(1))*sqrt(x**S(2) + S(2)*x)), x), x, atan(sqrt(x**S(2) + S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((S(2)*x + S(1))*sqrt(x**S(2) + x)), x), x, atan(S(2)*sqrt(x**S(2) + x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(-1))/sqrt(-x**S(2) + S(2)*x), x), x, -sqrt(-x**S(2) + S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + x)/(x + S(1)), x), x, sqrt(-x**S(2) + x) + S(3)*asin(S(2)*x + S(-1))/S(2) + sqrt(S(2))*atan(sqrt(S(2))*(-S(3)*x + S(1))/(S(4)*sqrt(-x**S(2) + x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**(S(1)/4) + x), x), x, x**(S(1)/4)*sqrt(x**(S(1)/4) + x)/S(3) + S(2)*x*sqrt(x**(S(1)/4) + x)/S(3) - atanh(sqrt(x)/sqrt(x**(S(1)/4) + x))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**(S(3)/2) + x), x), x, -S(16)*(x**(S(3)/2) + x)**(S(3)/2)/(S(35)*x) + S(4)*(x**(S(3)/2) + x)**(S(3)/2)/(S(7)*sqrt(x)) + S(32)*(x**(S(3)/2) + x)**(S(3)/2)/(S(105)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(x**(S(3)/2) + x), x), x, S(4)*sqrt(x)*(x**(S(3)/2) + x)**(S(3)/2)/S(11) - S(32)*(x**(S(3)/2) + x)**(S(3)/2)/S(99) - S(256)*(x**(S(3)/2) + x)**(S(3)/2)/(S(1155)*x) + S(64)*(x**(S(3)/2) + x)**(S(3)/2)/(S(231)*sqrt(x)) + S(512)*(x**(S(3)/2) + x)**(S(3)/2)/(S(3465)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))*sqrt(S(1)/(-x**S(2) + S(2))), x), x, x/(S(2)*sqrt(S(1)/(-x**S(2) + S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(4) + x**S(3) + x**S(2)), x), x, -(-S(2)*x + S(1))*sqrt(-x**S(4) + x**S(3) + x**S(2))/(S(8)*x) - (-x**S(2) + x + S(1))*sqrt(-x**S(4) + x**S(3) + x**S(2))/(S(3)*x) - S(5)*sqrt(-x**S(4) + x**S(3) + x**S(2))*asin(sqrt(S(5))*(-S(2)*x + S(1))/S(5))/(S(16)*x*sqrt(-x**S(2) + x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((a**S(2) + x**S(2))**S(3)), x), x, x*(a**S(2) + x**S(2))/(a**S(2)*sqrt((a**S(2) + x**S(2))**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(sqrt(x) + x + S(1)), x), x, S(2)*sqrt(x) - log(sqrt(x) + x + S(1)) - S(2)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*sqrt(x) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(x) + x + S(1)), x), x, -S(2)*sqrt(x) + x + S(4)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*sqrt(x) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(sqrt(x) + x + S(1))**(S(7)/2)), x), x, (S(8)*sqrt(x) + S(4))/(S(15)*(sqrt(x) + x + S(1))**(S(5)/2)) + (S(128)*sqrt(x) + S(64))/(S(135)*(sqrt(x) + x + S(1))**(S(3)/2)) + (S(1024)*sqrt(x) + S(512))/(S(405)*sqrt(sqrt(x) + x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(-1))/(sqrt(x**S(2) + S(1)) + S(1)), x), x, sqrt(x**S(2) + S(1)) - log(sqrt(x**S(2) + S(1)) + S(1)) - asinh(x) + sqrt(x**S(2) + S(1))/x - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(1))**(S(2)/3)*(x**S(2) + S(-1))**(S(2)/3)), x), x, S(3)*(x**S(2) + S(-1))**(S(1)/3)/(S(2)*(x + S(1))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(-x**S(2) + S(1))/(x + S(1)), x), x, -sqrt(-x**S(2) + S(1))/S(2) - asin(x)/S(2) - (-x**S(2) + S(1))**(S(3)/2)/(S(2)*x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(6) + S(1))**(S(2)/3) + (-x**S(6) + S(1))**(S(2)/3)/x**S(6), x), x, x*(-x**S(6) + S(1))**(S(2)/3)/S(5) - (-x**S(6) + S(1))**(S(2)/3)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(m + S(-1))*(S(2)*a*m + b*x**n*(S(2)*m - n))/(S(2)*(a + b*x**n)**(S(3)/2)), x), x, x**m/sqrt(a + b*x**n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(3) + x)/sqrt(S(3)*x + S(2)), x), x, -S(4)*(S(3)*x + S(2))**(S(7)/2)/S(567) + S(8)*(S(3)*x + S(2))**(S(5)/2)/S(135) - S(10)*(S(3)*x + S(2))**(S(3)/2)/S(81) - S(4)*sqrt(S(3)*x + S(2))/S(81), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(1))**(S(1)/4) + sqrt(x + S(1))), x), x, -S(4)*(x + S(1))**(S(1)/4) + S(2)*sqrt(x + S(1)) + S(4)*log((x + S(1))**(S(1)/4) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(1))/sqrt(x**S(2) + x), x), x, S(2)*sqrt(x**S(2) + x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(2)*sqrt(x)*(x + S(1))), x), x, atan(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(-x**S(2) + S(6)*x)), x), x, -sqrt(-x**S(2) + S(6)*x)/(S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(sqrt(x) + S(1)), x), x, S(2)*x**(S(3)/2)/S(3) + x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(x) + S(1))/x**(S(1)/3), x), x, -S(6)*x**(S(7)/6)/S(7) + S(3)*x**(S(2)/3)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(x**(S(1)/3) + S(1)), x), x, S(6)*x**(S(7)/6)/S(7) - S(6)*x**(S(5)/6)/S(5) - S(6)*x**(S(1)/6) + S(2)*sqrt(x) + S(6)*atan(x**(S(1)/6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(x) + S(1))**(S(1)/3)/x, x), x, S(6)*(sqrt(x) + S(1))**(S(1)/3) - log(x)/S(2) + S(3)*log(-(sqrt(x) + S(1))**(S(1)/3) + S(1)) - S(2)*sqrt(S(3))*atan(sqrt(S(3))*(S(2)*(sqrt(x) + S(1))**(S(1)/3) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-sqrt(x) + S(1), x), x, -S(2)*x**(S(3)/2)/S(3) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-x**(S(1)/4) + S(1), x), x, -S(4)*x**(S(5)/4)/S(5) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(x) + S(1))/(x**(S(1)/4) + S(1)), x), x, -S(4)*x**(S(5)/4)/S(5) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((a + b*x)*(c + d*x)), x), x, atanh((a*d + b*c + S(2)*b*d*x)/(S(2)*sqrt(b)*sqrt(d)*sqrt(a*c + b*d*x**S(2) + x*(a*d + b*c))))/(sqrt(b)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((a + b*x)*(c - d*x)), x), x, -atan((-a*d + b*c - S(2)*b*d*x)/(S(2)*sqrt(b)*sqrt(d)*sqrt(a*c - b*d*x**S(2) + x*(-a*d + b*c))))/(sqrt(b)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(-x**S(2) + S(1))), x), x, atan(sqrt(x)) + atanh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(-x**S(3) + x), x), x, atan(sqrt(x)) + atanh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(2) + x*(S(1) + sqrt(S(3))) - sqrt(S(3)) + S(2)), x), x, log(x**S(2) + x*(S(1) + sqrt(S(3))) - sqrt(S(3)) + S(2))/S(2) + sqrt(S(13)/23 + S(8)*sqrt(S(3))/S(23))*atanh((S(2)*x + S(1) + sqrt(S(3)))/sqrt(S(-4) + S(6)*sqrt(S(3)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(3) + x**S(2)), x), x, S(2)*(x**S(3) + x**S(2))**(S(3)/2)/(S(5)*x**S(2)) - S(4)*(x**S(3) + x**S(2))**(S(3)/2)/(S(15)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x + S(1))*sqrt(x**S(2) + S(2)*x)), x), x, atan(sqrt(x**S(2) + S(2)*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*sqrt(-sqrt(x) - x + S(1)), x), x, -sqrt(x)*(-sqrt(x) - x + S(1))**(S(3)/2)/S(2) + (S(9)*sqrt(x)/S(16) + S(9)/32)*sqrt(-sqrt(x) - x + S(1)) + S(5)*(-sqrt(x) - x + S(1))**(S(3)/2)/S(12) + S(45)*asin(sqrt(S(5))*(S(2)*sqrt(x) + S(1))/S(5))/S(64), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(x + S(-3)) + S(1))**(S(1)/3), x), x, S(6)*(sqrt(x + S(-3)) + S(1))**(S(7)/3)/S(7) - S(3)*(sqrt(x + S(-3)) + S(1))**(S(4)/3)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sqrt(S(2)*x + S(-1)) + S(3)), x), x, S(2)*(sqrt(S(2)*x + S(-1)) + S(3))**(S(3)/2)/S(3) - S(6)*sqrt(sqrt(S(2)*x + S(-1)) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x + S(1))/(sqrt(x) + S(1)), x), x, -sqrt(-x + S(1)) - asin(sqrt(x)) - (-x + S(1))**(S(3)/2)/(sqrt(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x + S(1))/(-sqrt(x) + S(1)), x), x, -sqrt(-x + S(1)) + asin(sqrt(x)) - (-x + S(1))**(S(3)/2)/(-sqrt(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x - sqrt(x**S(2) + S(1))), x), x, -x**S(3)/S(3) - (x**S(2) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x - sqrt(-x**S(2) + S(1))), x), x, x/S(2) + sqrt(-x**S(2) + S(1))/S(2) - sqrt(S(2))*atanh(sqrt(S(2))*x)/S(4) - sqrt(S(2))*atanh(sqrt(S(2))*sqrt(-x**S(2) + S(1)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x - sqrt(S(2)*x**S(2) + S(1))), x), x, -x - sqrt(S(2)*x**S(2) + S(1)) + atan(x) + atan(sqrt(S(2)*x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*sqrt(sqrt(x) + x), x), x, sqrt(x)*(sqrt(x) + x)**(S(3)/2)/S(2) + (S(5)*sqrt(x)/S(16) + S(5)/32)*sqrt(sqrt(x) + x) - S(5)*(sqrt(x) + x)**(S(3)/2)/S(12) - S(5)*atanh(sqrt(x)/sqrt(sqrt(x) + x))/S(32), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**(S(1)/3) + S(1))/(sqrt(x) + S(1)), x), x, S(6)*x**(S(5)/6)/S(5) - S(3)*x**(S(1)/3) + S(2)*sqrt(x) - S(4)*log(x**(S(1)/6) + S(1)) - log(-x**(S(1)/6) + x**(S(1)/3) + S(1)) - S(2)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**(S(1)/6) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**(S(1)/3) + S(1))/(x**(S(1)/4) + S(1)), x), x, S(12)*x**(S(13)/12)/S(13) + S(12)*x**(S(7)/12)/S(7) + S(12)*x**(S(1)/12) - S(6)*x**(S(5)/6)/S(5) + S(4)*x**(S(3)/4)/S(3) + S(4)*x**(S(1)/4) - S(3)*x**(S(1)/3) - S(2)*sqrt(x) - S(8)*log(x**(S(1)/12) + S(1)) - S(2)*log(-x**(S(1)/12) + x**(S(1)/6) + S(1)) + S(4)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**(S(1)/12) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(2) + sqrt(-x**S(2) + S(1)) + S(-1)), x), x, x + asin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x + S(1))/x), x), x, x*sqrt(S(1) + S(1)/x) + atanh(sqrt(S(1) + S(1)/x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((-x + S(1))/x), x), x, x*sqrt(S(-1) + S(1)/x) - atan(sqrt(S(-1) + S(1)/x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x + S(-1))/x), x), x, sqrt(x)*sqrt(x + S(-1)) - asinh(sqrt(x + S(-1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt((x + S(-1))/x), x), x, x*sqrt(S(1) - S(1)/x) - atanh(sqrt(S(1) - S(1)/x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x + S(1))/x)/x, x), x, -S(2)*sqrt(S(1) + S(1)/x) + S(2)*atanh(sqrt(S(1) + S(1)/x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x/(x + S(1))), x), x, sqrt(x)*sqrt(x + S(1)) - asinh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((-x + S(-1))/x), x), x, -x*sqrt(S(-1) - S(1)/x) + atan(sqrt(S(-1) - S(1)/x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x*(-x + S(4))), x), x, (x/S(2) + S(-1))*sqrt(-x**S(2) + S(4)*x) + S(2)*asin(x/S(2) + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x*(-x + S(1))), x), x, asin(S(2)*x + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x*(x + S(2)))**(S(3)/2), x), x, x/sqrt(x**S(2) + S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(1) + S(1)/x)/(-x**S(2) + S(1)), x), x, sqrt(S(2))*atanh(sqrt(S(2))*sqrt(S(1) + S(1)/x)/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-x**S(2) + sqrt(S(5))*x**S(2) + S(1) + sqrt(S(5))), x), x, atan(x*sqrt(-sqrt(S(5))/S(2) + S(3)/2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((-a + x)*(b - x)), x), x, -(a - b)**S(2)*atan((a + b - S(2)*x)/(S(2)*sqrt(-a*b - x**S(2) + x*(a + b))))/S(8) + (-a/S(4) - b/S(4) + x/S(2))*sqrt(-a*b - x**S(2) + x*(a + b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((-a + x)*(b - x)), x), x, -atan((a + b - S(2)*x)/(S(2)*sqrt(-a*b - x**S(2) + x*(a + b)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((-x**S(2) + S(1))*(x**S(2) + S(3))), x), x, x*sqrt(-x**S(4) - S(2)*x**S(2) + S(3))/S(3) - S(2)*sqrt(S(3))*elliptic_e(asin(x), S(-1)/3)/S(3) + S(4)*sqrt(S(3))*elliptic_f(asin(x), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((-x**S(2) + S(1))*(x**S(2) + S(3))), x), x, sqrt(S(3))*elliptic_f(asin(x), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*x + b*x**S(2)), x), x, S(2)*atanh(sqrt(b)*x/sqrt(a*x + b*x**S(2)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x*(a + b*x)), x), x, S(2)*atanh(sqrt(b)*x/sqrt(a*x + b*x**S(2)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x**S(2)*(a/x + b)), x), x, S(2)*atanh(sqrt(b)*x/sqrt(a*x + b*x**S(2)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x**S(3)*(a/x**S(2) + b/x)), x), x, S(2)*atanh(sqrt(b)*x/sqrt(a*x + b*x**S(2)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((a*x**S(2) + b*x**S(3))/x), x), x, S(2)*atanh(sqrt(b)*x/sqrt(a*x + b*x**S(2)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((a*x**S(3) + b*x**S(4))/x**S(2)), x), x, S(2)*atanh(sqrt(b)*x/sqrt(a*x + b*x**S(2)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*c*x + b*c*x**S(2)), x), x, S(2)*atanh(sqrt(b)*sqrt(c)*x/sqrt(a*c*x + b*c*x**S(2)))/(sqrt(b)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(c*(a*x + b*x**S(2))), x), x, S(2)*atanh(sqrt(b)*sqrt(c)*x/sqrt(a*c*x + b*c*x**S(2)))/(sqrt(b)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(c*x*(a + b*x)), x), x, S(2)*atanh(sqrt(b)*sqrt(c)*x/sqrt(a*c*x + b*c*x**S(2)))/(sqrt(b)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(c*x**S(2)*(a/x + b)), x), x, S(2)*atanh(sqrt(b)*sqrt(c)*x/sqrt(a*c*x + b*c*x**S(2)))/(sqrt(b)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + x*sqrt(x**S(2) + S(-1)) + S(1)), x), x, (S(3)*x/S(4) + sqrt(x**S(2) + S(-1))/S(4))*sqrt(-x**S(2) + x*sqrt(x**S(2) + S(-1)) + S(1)) + S(3)*sqrt(S(2))*asin(x - sqrt(x**S(2) + S(-1)))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(x)*sqrt(x + S(1)) - x)/sqrt(x + S(1)), x), x, (sqrt(x)/S(2) + S(3)*sqrt(x + S(1))/S(2))*sqrt(sqrt(x)*sqrt(x + S(1)) - x) - S(3)*sqrt(S(2))*asin(sqrt(x) - sqrt(x + S(1)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-(x + S(2)*sqrt(x**S(2) + S(1)))/(x**S(3) + x + sqrt(x**S(2) + S(1))), x), x, -sqrt(S(2) + S(2)*sqrt(S(5)))*atan(sqrt(S(-2) + sqrt(S(5)))*(x + sqrt(x**S(2) + S(1)))) + sqrt(S(-2) + S(2)*sqrt(S(5)))*atanh(sqrt(S(2) + sqrt(S(5)))*(x + sqrt(x**S(2) + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(1))/((x**S(2) + S(1))*sqrt(x**S(2) + S(2)*x + S(2))), x), x, -sqrt(S(1)/2 + sqrt(S(5))/S(2))*atan((-x*(sqrt(S(5)) + S(5)) + S(2)*sqrt(S(5)))/(sqrt(S(10) + S(10)*sqrt(S(5)))*sqrt(x**S(2) + S(2)*x + S(2)))) - sqrt(S(-1)/2 + sqrt(S(5))/S(2))*atanh((x*(-sqrt(S(5)) + S(5)) + S(2)*sqrt(S(5)))/(sqrt(S(-10) + S(10)*sqrt(S(5)))*sqrt(x**S(2) + S(2)*x + S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(-x**S(2) + sqrt(x**S(4) + S(1)))*(x**S(4) + S(1))), x), x, atan(x/sqrt(-x**S(2) + sqrt(x**S(4) + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(4))*sqrt(c*x**S(2) + d*sqrt(a + b*x**S(4)))), x), x, atanh(sqrt(c)*x/sqrt(c*x**S(2) + d*sqrt(a + b*x**S(4))))/(a*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(4))*sqrt(-c*x**S(2) + d*sqrt(a + b*x**S(4)))), x), x, atan(sqrt(c)*x/sqrt(-c*x**S(2) + d*sqrt(a + b*x**S(4))))/(a*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*c**S(4) + S(4)*b*c**S(3)*d*x + S(6)*b*c**S(2)*d**S(2)*x**S(2) + S(4)*b*c*d**S(3)*x**S(3) + b*d**S(4)*x**S(4)), x), x, atanh(sqrt(b)*d**S(2)*(c/d + x)**S(2)/sqrt(a + b*d**S(4)*(c/d + x)**S(4)))/(S(2)*sqrt(b)*d**S(2)) - c*sqrt((a + b*d**S(4)*(c/d + x)**S(4))/(sqrt(a) + sqrt(b)*d**S(2)*(c/d + x)**S(2))**S(2))*(sqrt(a) + sqrt(b)*d**S(2)*(c/d + x)**S(2))*elliptic_f(S(2)*atan(b**(S(1)/4)*d*(c/d + x)/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*b**(S(1)/4)*d**S(2)*sqrt(a + b*d**S(4)*(c/d + x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*c**S(4) + S(4)*b*c**S(3)*d*x + S(6)*b*c**S(2)*d**S(2)*x**S(2) + S(4)*b*c*d**S(3)*x**S(3) + b*d**S(4)*x**S(4)), x), x, sqrt((a + b*d**S(4)*(c/d + x)**S(4))/(sqrt(a) + sqrt(b)*d**S(2)*(c/d + x)**S(2))**S(2))*(sqrt(a) + sqrt(b)*d**S(2)*(c/d + x)**S(2))*elliptic_f(S(2)*atan(b**(S(1)/4)*d*(c/d + x)/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*b**(S(1)/4)*d*sqrt(a + b*d**S(4)*(c/d + x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - c*x**S(4))/(sqrt(a + b*x**S(2) + c*x**S(4))*(a*d + a*e*x**S(2) + c*d*x**S(4))), x), x, atanh(x*sqrt(-a*e + b*d)/(sqrt(d)*sqrt(a + b*x**S(2) + c*x**S(4))))/(sqrt(d)*sqrt(-a*e + b*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - c*x**S(4))/(sqrt(a - b*x**S(2) + c*x**S(4))*(a*d + a*e*x**S(2) + c*d*x**S(4))), x), x, atan(x*sqrt(a*e + b*d)/(sqrt(d)*sqrt(a - b*x**S(2) + c*x**S(4))))/(sqrt(d)*sqrt(a*e + b*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((x**S(3) + S(8))*sqrt(x**S(2) - S(2)*x + S(5))), x), x, -sqrt(S(3))*atan(sqrt(S(3))*(-x + S(1))/(S(3)*sqrt(x**S(2) - S(2)*x + S(5))))/S(12) - sqrt(S(13))*atanh(sqrt(S(13))*(-S(3)*x + S(7))/(S(13)*sqrt(x**S(2) - S(2)*x + S(5))))/S(156) + atanh(sqrt(x**S(2) - S(2)*x + S(5)))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(2)/(x**S(2) + S(1))), x), x, sqrt(x**S(2) + S(1))*sqrt(x**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**n/(x**n + S(1))), x), x, S(2)*x*sqrt(x**n)*hyper((S(1)/2, S(1)/2 + S(1)/n), (S(3)/2 + S(1)/n,), -x**n)/(n + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-e*f*x**S(2) + e*f)/((a*d*x**S(2) + a*d + b*d*x)*sqrt(a*x**S(4) + a + b*x**S(3) + b*x + c*x**S(2))), x), x, e*f*atan((a*b*x**S(2) + a*b + x*(S(4)*a**S(2) - S(2)*a*c + b**S(2)))/(S(2)*a*sqrt(S(2)*a - c)*sqrt(a*x**S(4) + a + b*x**S(3) + b*x + c*x**S(2))))/(a*d*sqrt(S(2)*a - c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-e*f*x**S(2) + e*f)/((-a*d*x**S(2) - a*d + b*d*x)*sqrt(-a*x**S(4) - a + b*x**S(3) + b*x + c*x**S(2))), x), x, e*f*atanh((a*b*x**S(2) + a*b - x*(S(4)*a**S(2) + S(2)*a*c + b**S(2)))/(S(2)*a*sqrt(S(2)*a + c)*sqrt(-a*x**S(4) - a + b*x**S(3) + b*x + c*x**S(2))))/(a*d*sqrt(S(2)*a + c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x*sqrt(a**S(2)*x**S(2)/b**S(2) - a/b**S(2)))/(x*sqrt(a**S(2)*x**S(2)/b**S(2) - a/b**S(2))), x), x, sqrt(S(2))*b*asinh((a*x + b*sqrt(a**S(2)*x**S(2)/b**S(2) - a/b**S(2)))/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a*x**S(2) + b*x*sqrt(a**S(2)*x**S(2)/b**S(2) + a/b**S(2)))/(x*sqrt(a**S(2)*x**S(2)/b**S(2) + a/b**S(2))), x), x, sqrt(S(2))*b*asin((a*x - b*sqrt(a**S(2)*x**S(2)/b**S(2) + a/b**S(2)))/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x*(a*x + b*sqrt(a**S(2)*x**S(2)/b**S(2) - a/b**S(2))))/(x*sqrt(a**S(2)*x**S(2)/b**S(2) - a/b**S(2))), x), x, sqrt(S(2))*b*asinh((a*x + b*sqrt(a**S(2)*x**S(2)/b**S(2) - a/b**S(2)))/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x*(-a*x + b*sqrt(a**S(2)*x**S(2)/b**S(2) + a/b**S(2))))/(x*sqrt(a**S(2)*x**S(2)/b**S(2) + a/b**S(2))), x), x, sqrt(S(2))*b*asin((a*x - b*sqrt(a**S(2)*x**S(2)/b**S(2) + a/b**S(2)))/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x*sqrt(x + S(-4)) + x*sqrt(x + S(-1)) - sqrt(x + S(-4)) - S(4)*sqrt(x + S(-1)))/((x**S(2) - S(5)*x + S(4))*(sqrt(x + S(-4)) + sqrt(x + S(-1)) + S(1))), x), x, S(2)*log(sqrt(x + S(-4)) + sqrt(x + S(-1)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(2) + S(3)*x + S(3))*(x**S(3) + S(3)*x**S(2) + S(3)*x + S(3))**(S(1)/3)), x), x, S(3)**(S(2)/3)*log(-S(3)**(S(1)/3)*(x + S(1))/((x + S(1))**S(3) + S(2))**(S(1)/3) + S(1))/S(9) - S(3)**(S(2)/3)*log(S(3)**(S(2)/3)*(x + S(1))**S(2)/((x + S(1))**S(3) + S(2))**(S(2)/3) + S(3)**(S(1)/3)*(x + S(1))/((x + S(1))**S(3) + S(2))**(S(1)/3) + S(1))/S(18) - S(3)**(S(1)/6)*atan(sqrt(S(3))*(S(2)*S(3)**(S(1)/3)*(x + S(1))/((x + S(1))**S(3) + S(2))**(S(1)/3) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/((-x**S(3) + S(1))**(S(2)/3)*(x**S(2) - x + S(1))), x), x, S(3)*S(2)**(S(1)/3)*log(S(2)**(S(1)/3)*(-x + S(1)) + (-x**S(3) + S(1))**(S(1)/3))/S(4) - S(2)**(S(1)/3)*log(-x**S(3) + S(2)*(-x + S(1))**S(3) + S(1))/S(4) + S(2)**(S(1)/3)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*(-x + S(1))/(-x**S(3) + S(1))**(S(1)/3) + S(1))/S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(x**S(4) + S(-1))*(x**S(4) + S(1))), x), x, -atan((x**S(2) + S(1))/(x*sqrt(x**S(4) + S(-1))))/S(4) - atanh((-x**S(2) + S(1))/(x*sqrt(x**S(4) + S(-1))))/S(4), expand=True, _diff=True, _numerical=True) def test_3(): assert rubi_test(rubi_integrate(sqrt(x**S(2) + S(-1))/sqrt(x**S(4) + S(-1)), x), x, sqrt(x**S(2) + S(-1))*sqrt(x**S(2) + S(1))*asinh(x)/sqrt(x**S(4) + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(2) + S(1))/sqrt(x**S(4) + S(-1)), x), x, -sqrt(x**S(4) + S(-1))*asin(x)/sqrt(-x**S(4) + S(1)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(x**S(2) + S(1))/sqrt(x**S(4) + S(-1)), x), x, sqrt(x**S(2) + S(-1))*sqrt(x**S(2) + S(1))*atanh(x/sqrt(x**S(2) + S(-1)))/sqrt(x**S(4) + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(x**S(2) + S(-1)) + sqrt(x**S(2) + S(1)))/sqrt(x**S(4) + S(-1)), x), x, sqrt(x**S(2) + S(-1))*sqrt(x**S(4) + S(-1))*asinh(x)/((-x**S(2) + S(1))*sqrt(x**S(2) + S(1))) - sqrt(x**S(4) + S(-1))*asin(x)/(sqrt(-x**S(2) + S(1))*sqrt(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-sqrt(x**S(2) + S(-1)) + sqrt(x**S(2) + S(1)))/sqrt(x**S(4) + S(-1)), x), x, -sqrt(x**S(2) + S(-1))*sqrt(x**S(2) + S(1))*asinh(x)/sqrt(x**S(4) + S(-1)) + sqrt(x**S(2) + S(-1))*sqrt(x**S(2) + S(1))*atanh(x/sqrt(x**S(2) + S(-1)))/sqrt(x**S(4) + S(-1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(-x**S(2) + S(1))**S(5), x), x, S(1)/(S(8)*(-x**S(2) + S(1))**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-S(5)/(S(256)*(x + S(1))**S(2)) - S(5)/(S(128)*(x + S(1))**S(3)) - S(3)/(S(64)*(x + S(1))**S(4)) - S(1)/(S(32)*(x + S(1))**S(5)) + S(5)/(S(256)*(x + S(-1))**S(2)) - S(5)/(S(128)*(x + S(-1))**S(3)) + S(3)/(S(64)*(x + S(-1))**S(4)) - S(1)/(S(32)*(x + S(-1))**S(5)), x), x, S(1)/(S(8)*(-x**S(2) + S(1))**S(4)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(-S(5)/(S(256)*(x + S(1))**S(2)) - S(5)/(S(128)*(x + S(1))**S(3)) - S(3)/(S(64)*(x + S(1))**S(4)) - S(1)/(S(32)*(x + S(1))**S(5)) + S(5)/(S(256)*(x + S(-1))**S(2)) - S(5)/(S(128)*(x + S(-1))**S(3)) + S(3)/(S(64)*(x + S(-1))**S(4)) - S(1)/(S(32)*(x + S(-1))**S(5)), x), x, S(5)/(S(256)*(x + S(1))) + S(5)/(S(256)*(x + S(1))**S(2)) + S(1)/(S(64)*(x + S(1))**S(3)) + S(1)/(S(128)*(x + S(1))**S(4)) + S(5)/(S(256)*(-x + S(1))) + S(5)/(S(256)*(-x + S(1))**S(2)) + S(1)/(S(64)*(-x + S(1))**S(3)) + S(1)/(S(128)*(-x + S(1))**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))/(x**S(2) + S(2)*x + S(-1)), x), x, (-sqrt(S(2)) + S(2))*log(x + S(1) + sqrt(S(2)))/S(4) + (sqrt(S(2)) + S(2))*log(x - sqrt(S(2)) + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-4))/(x**S(3) - S(5)*x + S(2)), x), x, (-sqrt(S(2)) + S(2))*log(x + S(1) + sqrt(S(2)))/S(4) + (sqrt(S(2)) + S(2))*log(x - sqrt(S(2)) + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(8) + S(1))/(x*(x**S(8) + S(1))**(S(3)/2)), x), x, -atanh(sqrt(x**S(8) + S(1)))/S(4) - S(1)/(S(4)*sqrt(x**S(8) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(8) + S(1))*(S(2)*x**S(8) + S(1))/(x**S(17) + S(2)*x**S(9) + x), x), x, -atanh(sqrt(x**S(8) + S(1)))/S(4) - S(1)/(S(4)*sqrt(x**S(8) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-S(9)*x**S(2) + x/sqrt(-S(9)*x**S(2) + S(1)) + S(1), x), x, -S(3)*x**S(3) + x - sqrt(-S(9)*x**S(2) + S(1))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + (-S(9)*x**S(2) + S(1))**(S(3)/2))/sqrt(-S(9)*x**S(2) + S(1)), x), x, -S(3)*x**S(3) + x - sqrt(-S(9)*x**S(2) + S(1))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*sqrt(x) + x)**(S(2)/3)*(S(2)*sqrt(x) + S(-3))/sqrt(x), x), x, S(6)*(-S(3)*sqrt(x) + x)**(S(5)/3)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(9)*sqrt(x) + S(2)*x + S(9))/(-S(3)*sqrt(x) + x)**(S(1)/3), x), x, S(6)*(-S(3)*sqrt(x) + x)**(S(5)/3)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(2)/(S(4)*x**S(2) + S(-1)), x), x, -atanh(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-S(1)/(S(2)*x + S(1)) + S(1)/(S(2)*x + S(-1)), x), x, log(-S(2)*x + S(1))/S(2) - log(S(2)*x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(9)*x**S(2) + S(4)), x), x, asin(S(3)*x/S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(-S(3)*x + S(2))*sqrt(S(3)*x + S(2))), x), x, asin(S(3)*x/S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((-S(3)*x + S(2))*(S(3)*x + S(2))), x), x, asin(S(3)*x/S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x**S(2) - S(2)*x + S(15)), x), x, asin(x/S(4) + S(1)/4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(-x + S(3))*sqrt(x + S(5))), x), x, asin(x/S(4) + S(1)/4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((-x + S(3))*(x + S(5))), x), x, asin(x/S(4) + S(1)/4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x**S(2) - S(8)*x + S(-15)), x), x, asin(x + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(-x + S(-3))*sqrt(x + S(5))), x), x, asin(x + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt((-x + S(-3))*(x + S(5))), x), x, asin(x + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(-sqrt(x) + S(1), x), x, -S(2)*x**(S(3)/2)/S(3) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x + S(1))/(sqrt(x) + S(1)), x), x, -S(2)*x**(S(3)/2)/S(3) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(1)/(-x**S(2) + S(1))), x), x, sqrt(-x**S(2) + S(1))*sqrt(S(1)/(-x**S(2) + S(1)))*asin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x**S(2) + S(1))/(-x**S(4) + S(1))), x), x, sqrt(-x**S(2) + S(1))*sqrt(S(1)/(-x**S(2) + S(1)))*asin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(1)/(x**S(2) + S(-1))), x), x, sqrt(x**S(2) + S(-1))*sqrt(S(1)/(x**S(2) + S(-1)))*atanh(x/sqrt(x**S(2) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x**S(2) + S(1))/(x**S(4) + S(-1))), x), x, sqrt(x**S(2) + S(-1))*sqrt(S(1)/(x**S(2) + S(-1)))*atanh(x/sqrt(x**S(2) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(6) + S(1))/(x**S(6) + S(-1)), x), x, x + log(x**S(2) - x + S(1))/S(6) - log(x**S(2) + x + S(1))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(3) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(3) - S(2)*atanh(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x**(S(-3)))/(x**S(3) - S(1)/x**S(3)), x), x, x + log(x**S(2) - x + S(1))/S(6) - log(x**S(2) + x + S(1))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(3) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(3) - S(2)*atanh(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x + S(1)), x), x, -S(2)*sqrt(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x + S(1))/sqrt(-x**S(2) + S(1)), x), x, -S(2)*sqrt(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x + S(1)), x), x, S(2)*sqrt(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x + S(1))/sqrt(-x**S(2) + S(1)), x), x, S(2)*sqrt(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x + S(1)), x), x, -S(2)*(-x + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1))/sqrt(x + S(1)), x), x, -S(2)*(-x + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x + S(1)), x), x, S(2)*(x + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1))/sqrt(-x + S(1)), x), x, S(2)*(x + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(3)*x + S(2))/sqrt(x + S(1)), x), x, sqrt(x + S(1))*sqrt(S(3)*x + S(2)) - sqrt(S(3))*asinh(sqrt(S(3)*x + S(2)))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x + S(1))*sqrt(S(3)*x + S(2))/sqrt(-x**S(2) + S(1)), x), x, sqrt(x + S(1))*sqrt(S(3)*x + S(2)) - sqrt(S(3))*asinh(sqrt(S(3)*x + S(2)))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(1))**(S(3)/2)/(x*(-x + S(1))**(S(3)/2)), x), x, -asin(x) - atanh(sqrt(-x + S(1))*sqrt(x + S(1))) + S(4)*sqrt(x + S(1))/sqrt(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(1))**S(3)/(x*(-x**S(2) + S(1))**(S(3)/2)), x), x, -asin(x) - atanh(sqrt(-x**S(2) + S(1))) + S(4)*sqrt(-x**S(2) + S(1))/(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + S(1))**(S(3)/2)/(x*(-a*x + S(1))**(S(3)/2)), x), x, -asin(a*x) - atanh(sqrt(-a*x + S(1))*sqrt(a*x + S(1))) + S(4)*sqrt(a*x + S(1))/sqrt(-a*x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + S(1))**S(3)/(x*(-a**S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, -asin(a*x) - atanh(sqrt(-a**S(2)*x**S(2) + S(1))) + S(4)*sqrt(-a**S(2)*x**S(2) + S(1))/(-a*x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x**S(2) + S(1)), x), x, asin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(2) + S(1))/sqrt(-x**S(4) + S(1)), x), x, asin(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x**S(2) + S(1)), x), x, asinh(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1))/sqrt(-x**S(4) + S(1)), x), x, asinh(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1)), x), x, x*sqrt(-x**S(2) + S(1))/S(2) + asin(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(4) + S(1))/sqrt(x**S(2) + S(1)), x), x, x*sqrt(-x**S(2) + S(1))/S(2) + asin(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(2) + S(1)), x), x, x*sqrt(x**S(2) + S(1))/S(2) + asinh(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(4) + S(1))/sqrt(-x**S(2) + S(1)), x), x, x*sqrt(x**S(2) + S(1))/S(2) + asinh(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2)*c + a**S(2)*d*x + S(2)*a*b*c*x**S(2) + S(2)*a*b*d*x**S(3) + b**S(2)*c*x**S(4) + b**S(2)*d*x**S(5))/(c + d*x), x), x, a**S(2)*x + S(2)*a*b*x**S(3)/S(3) + b**S(2)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2)*c + a**S(2)*d*x + S(2)*a*b*c*x**S(2) + S(2)*a*b*d*x**S(3) + b**S(2)*c*x**S(4) + b**S(2)*d*x**S(5))/(c + d*x)**S(2), x), x, -b**S(2)*c*x**S(3)/(S(3)*d**S(2)) + b**S(2)*x**S(4)/(S(4)*d) - b*c*x*(S(2)*a*d**S(2) + b*c**S(2))/d**S(4) + b*x**S(2)*(S(2)*a*d**S(2) + b*c**S(2))/(S(2)*d**S(3)) + (a*d**S(2) + b*c**S(2))**S(2)*log(c + d*x)/d**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2)*c + a**S(2)*d*x + S(2)*a*b*c*x**S(2) + S(2)*a*b*d*x**S(3) + b**S(2)*c*x**S(4) + b**S(2)*d*x**S(5))/(a + b*x**S(2)), x), x, a*c*x + a*d*x**S(2)/S(2) + b*c*x**S(3)/S(3) + b*d*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2)*c + a**S(2)*d*x + S(2)*a*b*c*x**S(2) + S(2)*a*b*d*x**S(3) + b**S(2)*c*x**S(4) + b**S(2)*d*x**S(5))/(a + b*x**S(2))**S(2), x), x, c*x + d*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2)*c + a**S(2)*d*x + S(2)*a*b*c*x**S(2) + S(2)*a*b*d*x**S(3) + b**S(2)*c*x**S(4) + b**S(2)*d*x**S(5))/(a + b*x**S(2))**S(3), x), x, d*log(a + b*x**S(2))/(S(2)*b) + c*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((a + b + c*x**S(2))/d)**m, x), x, d*x*(c*x**S(2)/d + (a + b)/d)**(m + S(1))*hyper((S(1), m + S(3)/2), (S(3)/2,), -c*x**S(2)/(a + b))/(a + b), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(((a + b + c*x**S(2))/d)**m, x), x, x*(c*x**S(2)/d + (a + b)/d)**m*(c*x**S(2)/(a + b) + S(1))**(-m)*hyper((S(1)/2, -m), (S(3)/2,), -c*x**S(2)/(a + b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x - sqrt(x**S(2) + S(1))), x), x, -x**S(2)/S(2) - x*sqrt(x**S(2) + S(1))/S(2) - asinh(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x - sqrt(-x**S(2) + S(1))), x), x, log(-S(2)*x**S(2) + S(1))/S(4) - asin(x)/S(2) - atanh(x/sqrt(-x**S(2) + S(1)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x - sqrt(S(2)*x**S(2) + S(1))), x), x, -log(x**S(2) + S(1))/S(2) - sqrt(S(2))*asinh(sqrt(S(2))*x) + atanh(x/sqrt(S(2)*x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + x**S(2)*sqrt(-x**S(2) + S(2)) + S(2)*x)/(S(2)*x**S(2) + S(-2)), x), x, -x**S(2)/S(4) + x*sqrt(-x**S(2) + S(2))/S(4) + log(-x**S(2) + S(1))/S(4) - atanh(x/sqrt(-x**S(2) + S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(-x**S(2) + S(2))/(x - sqrt(-x**S(2) + S(2))), x), x, -x**S(2)/S(4) + x*sqrt(-x**S(2) + S(2))/S(4) + log(-x + S(1))/S(4) + log(x + S(1))/S(4) - atanh(x/sqrt(-x**S(2) + S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(-x + sqrt(-x**S(2) + S(2)*x)), x), x, -x/S(2) - sqrt(-x**S(2) + S(2)*x)/S(2) - log(-x + S(1))/S(2) + atanh(sqrt(-x**S(2) + S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(-x**S(2) + S(2)*x))/(-S(2)*x + S(2)), x), x, -x/S(2) - sqrt(-x**S(2) + S(2)*x)/S(2) - log(-x + S(1))/S(2) + atanh(sqrt(-x**S(2) + S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(x)*sqrt(-x + S(2)) + x)/(-S(2)*x + S(2)), x), x, -x/S(2) - sqrt(-x**S(2) + S(2)*x)/S(2) - log(-x + S(1))/S(2) + atanh(sqrt(-x**S(2) + S(2)*x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(-sqrt(x) + sqrt(-x + S(2))), x), x, -sqrt(x)*sqrt(-x + S(2))/S(2) - x/S(2) - log(-x + S(1))/S(2) + atanh(sqrt(x)*sqrt(-x + S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*sqrt(-x + S(3)) + S(3)/sqrt(x + S(1)))**S(2)/x, x), x, -S(4)*x + S(21)*log(x) - S(9)*log(x + S(1)) - S(12)*asin(x/S(2) + S(-1)/2) - S(24)*sqrt(S(3))*atanh(sqrt(S(3))*sqrt(x + S(1))/sqrt(-x + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + x + S(-1))/(sqrt(x**S(2) + S(1)) + S(1)), x), x, x*sqrt(x**S(2) + S(1))/S(2) - x + sqrt(x**S(2) + S(1)) - log(sqrt(x**S(2) + S(1)) + S(1)) - asinh(x)/S(2) + sqrt(x**S(2) + S(1))/x - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + x + S(-1))/(x + sqrt(x**S(2) + S(1)) + S(1)), x), x, x**S(3)/S(6) + x**S(2)/S(2) + sqrt(x**S(2) + S(1))*(-S(2)*x**S(2) - S(3)*x + S(4))/S(12) - log(sqrt(x**S(2) + S(1)) + S(1))/S(2) - asinh(x)/S(4), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(2) + x + S(-1))/(x + sqrt(x**S(2) + S(1)) + S(1)), x), x, x**S(3)/S(6) + x**S(2)/S(2) - x*sqrt(x**S(2) + S(1))/S(4) + x/S(2) - (x**S(2) + S(1))**(S(3)/2)/S(6) + log(x + sqrt(x**S(2) + S(1)))/S(2) - log(x + sqrt(x**S(2) + S(1)) + S(1)) - asinh(x)/S(4) + S(1)/(S(2)*(x + sqrt(x**S(2) + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2)*sqrt(x + S(-1)))/(x*sqrt(x + S(-1))), x), x, S(2)*sqrt(x + S(-1)) + S(2)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**(S(2)/3) + c*sqrt(x))**S(2), x), x, a**S(2)*x + S(6)*a*b*x**(S(5)/3)/S(5) + S(4)*a*c*x**(S(3)/2)/S(3) + S(3)*b**S(2)*x**(S(7)/3)/S(7) + S(12)*b*c*x**(S(13)/6)/S(13) + c**S(2)*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**(S(2)/3) + c*sqrt(x))**S(3), x), x, a**S(3)*x + S(9)*a**S(2)*b*x**(S(5)/3)/S(5) + S(2)*a**S(2)*c*x**(S(3)/2) + S(9)*a*b**S(2)*x**(S(7)/3)/S(7) + S(36)*a*b*c*x**(S(13)/6)/S(13) + S(3)*a*c**S(2)*x**S(2)/S(2) + b**S(3)*x**S(3)/S(3) + S(18)*b**S(2)*c*x**(S(17)/6)/S(17) + S(9)*b*c**S(2)*x**(S(8)/3)/S(8) + S(2)*c**S(3)*x**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-1))/(x**S(3)*sqrt(a - b + b/x**S(2))), x), x, atanh(sqrt(a - b + b/x**S(2))/sqrt(a - b))/sqrt(a - b) + sqrt(a - b + b/x**S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-1))/(x**S(3)*sqrt(a + b*(S(-1) + x**(S(-2))))), x), x, atanh(sqrt(a - b + b/x**S(2))/sqrt(a - b))/sqrt(a - b) + sqrt(a - b + b/x**S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c + d*x)**S(2)/(a + b*x**S(3)), x), x, -a**(S(1)/3)*d*(-a**(S(1)/3)*d + S(2)*b**(S(1)/3)*c)*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*b**(S(5)/3)) + a**(S(1)/3)*d*(-a**(S(1)/3)*d + S(2)*b**(S(1)/3)*c)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*b**(S(5)/3)) + sqrt(S(3))*a**(S(1)/3)*d*(a**(S(1)/3)*d + S(2)*b**(S(1)/3)*c)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*b**(S(5)/3)) + c**S(2)*log(a + b*x**S(3))/(S(3)*b) + S(2)*c*d*x/b + d**S(2)*x**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(1))/((x**S(2) + S(4))*sqrt(x**S(2) + S(9))), x), x, sqrt(S(5))*atan(sqrt(S(5))*x/(S(2)*sqrt(x**S(2) + S(9))))/S(10) - sqrt(S(5))*atanh(sqrt(S(5))*sqrt(x**S(2) + S(9))/S(5))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(sqrt(-x**S(2) + S(1)) + S(1)), x), x, x**S(2)/S(2) - (-x**S(2) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(sqrt(-x + S(1))*sqrt(x + S(1)) + S(1)), x), x, x**S(2)/S(2) - (-x**S(2) + S(1))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(1) + S(1)/(sqrt(x + S(2))*sqrt(x + S(3)))), x), x, x**S(2)/S(2) + sqrt(x + S(2))*sqrt(x + S(3)) - S(5)*asinh(sqrt(x + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(x**S(6)))/(x*(-x**S(4) + S(1))), x), x, atan(x)/S(2) + atanh(x)/S(2) + sqrt(x**S(6))*atan(x)/(S(2)*x**S(3)) - sqrt(x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(1) - sqrt(x**S(6))/x)/(-x**S(4) + S(1)), x), x, atan(x)/S(2) + atanh(x)/S(2) + sqrt(x**S(6))*atan(x)/(S(2)*x**S(3)) - sqrt(x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x - sqrt(x**S(6)))/(-x**S(5) + x), x), x, atan(x)/S(2) + atanh(x)/S(2) + sqrt(x**S(6))*atan(x)/(S(2)*x**S(3)) - sqrt(x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x + sqrt(x**S(6))), x), x, atan(x)/S(2) + atanh(x)/S(2) + sqrt(x**S(6))*atan(x)/(S(2)*x**S(3)) - sqrt(x**S(6))*atanh(x)/(S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(x) - sqrt(x**S(3)))/(-x**S(3) + x), x), x, atan(sqrt(x)) + atanh(sqrt(x)) + sqrt(x**S(3))*atan(sqrt(x))/x**(S(3)/2) - sqrt(x**S(3))*atanh(sqrt(x))/x**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x) + sqrt(x**S(3))), x), x, atan(sqrt(x)) + atanh(sqrt(x)) + sqrt(x**S(3))*atan(sqrt(x))/x**(S(3)/2) - sqrt(x**S(3))*atanh(sqrt(x))/x**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x + S(-1)) + sqrt((x + S(-1))**S(3))), x), x, atan(sqrt(x + S(-1))) + atanh(sqrt(x + S(-1))) + sqrt((x + S(-1))**S(3))*atan(sqrt(x + S(-1)))/(x + S(-1))**(S(3)/2) - sqrt((x + S(-1))**S(3))*atanh(sqrt(x + S(-1)))/(x + S(-1))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(4)*x + S(-5))/((S(5)*x + S(4))**S(2)*sqrt(-x**S(2) + S(1))) - S(3)/(S(5)*x + S(4))**S(2), x), x, sqrt(-x**S(2) + S(1))/(S(5)*x + S(4)) + S(3)/(S(5)*(S(5)*x + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(4)*x - S(3)*sqrt(-x**S(2) + S(1)) + S(-5))/((S(5)*x + S(4))**S(2)*sqrt(-x**S(2) + S(1))), x), x, sqrt(-x**S(2) + S(1))/(S(5)*x + S(4)) + S(3)/(S(5)*(S(5)*x + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-S(3)*x**S(2) + (-S(4)*x + S(-5))*sqrt(-x**S(2) + S(1)) + S(3)), x), x, sqrt(-x**S(2) + S(1))/(S(5)*x + S(4)) + S(3)/(S(5)*(S(5)*x + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-S(3)*x**S(2) - S(4)*x*sqrt(-x**S(2) + S(1)) - S(5)*sqrt(-x**S(2) + S(1)) + S(3)), x), x, sqrt(-x**S(2) + S(1))/(S(5)*x + S(4)) + S(3)/(S(5)*(S(5)*x + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(-x**S(2) + S(1)) + S(-1))/(sqrt(-x**S(2) + S(1))*(x - S(2)*sqrt(-x**S(2) + S(1)) + S(2))**S(2)), x), x, sqrt(-x**S(2) + S(1))/(S(5)*x + S(4)) + S(3)/(S(5)*(S(5)*x + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**(n + S(-1)))/(c*x + d*x**n), x), x, b*log(x)/d - (-a*d + b*c)*log(c*x**(-n + S(1)) + d)/(c*d*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(5) + S(2)*x**S(3) - x)/(x**S(4) + S(2)*x**S(2) + S(3))**S(2), x), x, (-S(7)*x**S(2)/S(8) + S(5)/8)/(x**S(4) + S(2)*x**S(2) + S(3)) + S(9)*sqrt(S(2))*atan(sqrt(S(2))*(x**S(2) + S(1))/S(2))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(5) + x)/(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**S(3), x), x, (x**S(2)/S(4) + S(3)/16)/(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**S(2) + (x**S(2) + S(1)/2)/(S(2)*x**S(4) + S(2)*x**S(2) + S(1)) + atan(S(2)*x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x + c*x**S(2))/(d + e*x**S(2) + f*x**S(4)), x), x, -b*atanh((e + S(2)*f*x**S(2))/sqrt(-S(4)*d*f + e**S(2)))/sqrt(-S(4)*d*f + e**S(2)) + sqrt(S(2))*(c + (-S(2)*a*f + c*e)/sqrt(-S(4)*d*f + e**S(2)))*atan(sqrt(S(2))*sqrt(f)*x/sqrt(e + sqrt(-S(4)*d*f + e**S(2))))/(S(2)*sqrt(f)*sqrt(e + sqrt(-S(4)*d*f + e**S(2)))) + sqrt(S(2))*(c + (S(2)*a*f - c*e)/sqrt(-S(4)*d*f + e**S(2)))*atan(sqrt(S(2))*sqrt(f)*x/sqrt(e - sqrt(-S(4)*d*f + e**S(2))))/(S(2)*sqrt(f)*sqrt(e - sqrt(-S(4)*d*f + e**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)/(a + b*x**S(2) + c*x**S(4)), x), x, -S(2)*d*e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)) + sqrt(S(2))*(e**S(2) + (b*e**S(2) - S(2)*c*d**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(e**S(2) + (-b*e**S(2) + S(2)*c*d**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x**S(2) + S(1))/(sqrt(S(2)*x**S(2) + S(1)) + S(1)), x), x, x - sqrt(S(2))*asinh(sqrt(S(2))*x)/S(2) + sqrt(S(2)*x**S(2) + S(1))/(S(2)*x) - S(1)/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(4)*x**S(2) + S(-1))/(x + sqrt(S(4)*x**S(2) + S(-1))), x), x, S(4)*x/S(3) - sqrt(S(4)*x**S(2) + S(-1))/S(3) - sqrt(S(3))*atanh(sqrt(S(3))*x)/S(9) + sqrt(S(3))*atanh(sqrt(S(3))*sqrt(S(4)*x**S(2) + S(-1)))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((a + b*x)*(c + d*x)), x), x, a**S(2)*log(a + b*x)/(b**S(2)*(-a*d + b*c)) - c**S(2)*log(c + d*x)/(d**S(2)*(-a*d + b*c)) + x/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((a + b*x**S(2))*(c + d*x)), x), x, -sqrt(a)*c*atan(sqrt(b)*x/sqrt(a))/(sqrt(b)*(a*d**S(2) + b*c**S(2))) + a*d*log(a + b*x**S(2))/(S(2)*b*(a*d**S(2) + b*c**S(2))) + c**S(2)*log(c + d*x)/(d*(a*d**S(2) + b*c**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((a + b*x**S(3))*(c + d*x)), x), x, a**(S(1)/3)*d*(a**(S(1)/3)*d + b**(S(1)/3)*c)*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*b**(S(2)/3)*(-a*d**S(3) + b*c**S(3))) - a**(S(1)/3)*d*(a**(S(1)/3)*d + b**(S(1)/3)*c)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*b**(S(2)/3)*(-a*d**S(3) + b*c**S(3))) - sqrt(S(3))*a**(S(1)/3)*d*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*b**(S(2)/3)*(a**(S(2)/3)*d**S(2) + a**(S(1)/3)*b**(S(1)/3)*c*d + b**(S(2)/3)*c**S(2))) + c**S(2)*log(a + b*x**S(3))/(S(3)*(-a*d**S(3) + b*c**S(3))) - c**S(2)*log(c + d*x)/(-a*d**S(3) + b*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((a + b*x**S(4))*(c + d*x)), x), x, sqrt(a)*d**S(3)*atan(sqrt(b)*x**S(2)/sqrt(a))/(S(2)*sqrt(b)*(a*d**S(4) + b*c**S(4))) - c**S(2)*d*log(a + b*x**S(4))/(S(4)*(a*d**S(4) + b*c**S(4))) + c**S(2)*d*log(c + d*x)/(a*d**S(4) + b*c**S(4)) - sqrt(S(2))*c*(-sqrt(a)*d**S(2) + sqrt(b)*c**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(1)/4)*b**(S(1)/4)*(a*d**S(4) + b*c**S(4))) + sqrt(S(2))*c*(-sqrt(a)*d**S(2) + sqrt(b)*c**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(1)/4)*b**(S(1)/4)*(a*d**S(4) + b*c**S(4))) + sqrt(S(2))*c*(sqrt(a)*d**S(2) + sqrt(b)*c**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(8)*a**(S(1)/4)*b**(S(1)/4)*(a*d**S(4) + b*c**S(4))) - sqrt(S(2))*c*(sqrt(a)*d**S(2) + sqrt(b)*c**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(8)*a**(S(1)/4)*b**(S(1)/4)*(a*d**S(4) + b*c**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((-x + S(1))*(x + S(1))**S(2)), x), x, atanh(x)/S(2) + S(1)/(S(2)*(x + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((-x**S(2) + S(1))*(x**S(2) + S(1))**S(2)), x), x, -x/(S(4)*(x**S(2) + S(1))) + atanh(x)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/((-x**S(3) + S(1))*(x**S(3) + S(1))**S(2)), x), x, -x/(S(6)*(x**S(3) + S(1))) - log(-x + S(1))/S(12) - log(x + S(1))/S(36) + log(x**S(2) - x + S(1))/S(72) + log(x**S(2) + x + S(1))/S(24) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x + c*x**S(2))/((d + e*x)**S(3)*sqrt(x**S(2) + S(-1))), x), x, (a*(S(2)*d**S(2) + e**S(2))/S(2) - S(3)*b*d*e/S(2) + c*(d**S(2) + S(2)*e**S(2))/S(2))*atanh((d*x + e)/(sqrt(d**S(2) - e**S(2))*sqrt(x**S(2) + S(-1))))/(d**S(2) - e**S(2))**(S(5)/2) + sqrt(x**S(2) + S(-1))*(c*(d**S(3) - S(4)*d*e**S(2))/S(2) - e*(S(3)*a*d*e - b*(d**S(2) + S(2)*e**S(2)))/S(2))/(e*(d + e*x)*(d**S(2) - e**S(2))**S(2)) - sqrt(x**S(2) + S(-1))*(a*e**S(2)/S(2) - b*d*e/S(2) + c*d**S(2)/S(2))/(e*(d + e*x)**S(2)*(d**S(2) - e**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x + c*x**S(2))/((d + e*x)**S(3)*sqrt(x + S(-1))*sqrt(x + S(1))), x), x, (-S(3)*b*d*e + d**S(2)*(S(2)*a + c) + e**S(2)*(a + S(2)*c))*atanh(sqrt(d + e)*sqrt(x + S(1))/(sqrt(d - e)*sqrt(x + S(-1))))/((d - e)**(S(5)/2)*(d + e)**(S(5)/2)) + sqrt(x + S(-1))*sqrt(x + S(1))*(b*d**S(2)*e/S(2) + b*e**S(3) + c*d**S(3)/S(2) - d*e**S(2)*(S(3)*a + S(4)*c)/S(2))/(e*(d + e*x)*(d**S(2) - e**S(2))**S(2)) - sqrt(x + S(-1))*sqrt(x + S(1))*(a*e**S(2)/S(2) - b*d*e/S(2) + c*d**S(2)/S(2))/(e*(d + e*x)**S(2)*(d**S(2) - e**S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x + c*x**S(2))/((d + e*x)**S(3)*sqrt(x + S(-1))*sqrt(x + S(1))), x), x, S(2)*c*atanh(sqrt(d + e)*sqrt(x + S(1))/(sqrt(d - e)*sqrt(x + S(-1))))/(e**S(2)*sqrt(d - e)*sqrt(d + e)) - S(3)*d*sqrt(x + S(-1))*sqrt(x + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*e*(d + e*x)*(d**S(2) - e**S(2))**S(2)) - S(2)*d*(-b*e + S(2)*c*d)*atanh(sqrt(d + e)*sqrt(x + S(1))/(sqrt(d - e)*sqrt(x + S(-1))))/(e**S(2)*(d - e)**(S(3)/2)*(d + e)**(S(3)/2)) + sqrt(x + S(-1))*sqrt(x + S(1))*(-b*e + S(2)*c*d)/(e*(d + e*x)*(d**S(2) - e**S(2))) - sqrt(x + S(-1))*sqrt(x + S(1))*(a*e**S(2)/S(2) - b*d*e/S(2) + c*d**S(2)/S(2))/(e*(d + e*x)**S(2)*(d**S(2) - e**S(2))) + (S(2)*d**S(2) + e**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))*atanh(sqrt(d + e)*sqrt(x + S(1))/(sqrt(d - e)*sqrt(x + S(-1))))/(e**S(2)*(d - e)**(S(5)/2)*(d + e)**(S(5)/2)), expand=True, _diff=True, _numerical=True) def test_4(): assert rubi_test(rubi_integrate((b + S(2)*c*x + S(3)*d*x**S(2))*(a + b*x + c*x**S(2) + d*x**S(3))**n, x), x, (a + b*x + c*x**S(2) + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x + S(3)*d*x**S(2))*(b*x + c*x**S(2) + d*x**S(3))**n, x), x, (b*x + c*x**S(2) + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**n*(b + c*x + d*x**S(2))**n*(b + S(2)*c*x + S(3)*d*x**S(2)), x), x, x**(n + S(1))*(b + c*x + d*x**S(2))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(3)*d*x**S(2))*(a + b*x + d*x**S(3))**n, x), x, (a + b*x + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(3)*d*x**S(2))*(b*x + d*x**S(3))**n, x), x, (b*x + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**n*(b + d*x**S(2))**n*(b + S(3)*d*x**S(2)), x), x, x**(n + S(1))*(b + d*x**S(2))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*c*x + S(3)*d*x**S(2))*(a + c*x**S(2) + d*x**S(3))**n, x), x, (a + c*x**S(2) + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*c*x + S(3)*d*x**S(2))*(c*x**S(2) + d*x**S(3))**n, x), x, (c*x**S(2) + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**n*(c*x + d*x**S(2))**n*(S(2)*c*x + S(3)*d*x**S(2)), x), x, x**(n + S(1))*(c*x + d*x**S(2))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n)*(c + d*x)**n*(S(2)*c*x + S(3)*d*x**S(2)), x), x, x**(S(2)*n + S(2))*(c + d*x)**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*c + S(3)*d*x)*(a + c*x**S(2) + d*x**S(3))**n, x), x, (a + c*x**S(2) + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*c + S(3)*d*x)*(c*x**S(2) + d*x**S(3))**n, x), x, (c*x**S(2) + d*x**S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x + S(3)*d*x**S(2))*(a + b*x + c*x**S(2) + d*x**S(3))**S(7), x), x, (a + b*x + c*x**S(2) + d*x**S(3))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x + S(3)*d*x**S(2))*(b*x + c*x**S(2) + d*x**S(3))**S(7), x), x, x**S(8)*(b + c*x + d*x**S(2))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(b + c*x + d*x**S(2))**S(7)*(b + S(2)*c*x + S(3)*d*x**S(2)), x), x, x**S(8)*(b + c*x + d*x**S(2))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(3)*d*x**S(2))*(a + b*x + d*x**S(3))**S(7), x), x, (a + b*x + d*x**S(3))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(b + d*x**S(2))**S(7)*(b + S(3)*d*x**S(2)), x), x, x**S(8)*(b + d*x**S(2))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(3)*d*x**S(2))*(b*x + d*x**S(3))**S(7), x), x, x**S(8)*(b + d*x**S(2))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*c*x + S(3)*d*x**S(2))*(a + c*x**S(2) + d*x**S(3))**S(7), x), x, (a + c*x**S(2) + d*x**S(3))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*c*x + S(3)*d*x**S(2))*(c*x**S(2) + d*x**S(3))**S(7), x), x, x**S(16)*(c + d*x)**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(c*x + d*x**S(2))**S(7)*(S(2)*c*x + S(3)*d*x**S(2)), x), x, x**S(16)*(c + d*x)**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)*(c + d*x)**S(7)*(S(2)*c*x + S(3)*d*x**S(2)), x), x, x**S(16)*(c + d*x)**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*c + S(3)*d*x)*(a + c*x**S(2) + d*x**S(3))**S(7), x), x, (a + c*x**S(2) + d*x**S(3))**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(2)*c + S(3)*d*x)*(c*x**S(2) + d*x**S(3))**S(7), x), x, x**S(16)*(c + d*x)**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(S(2)*c + S(3)*d*x)*(c*x + d*x**S(2))**S(7), x), x, x**S(16)*(c + d*x)**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(15)*(c + d*x)**S(7)*(S(2)*c + S(3)*d*x), x), x, x**S(16)*(c + d*x)**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*((a*x + b*x**S(2)/S(2))**S(4) + S(1)), x), x, a*x + b*x**S(2)/S(2) + (a*x + b*x**S(2)/S(2))**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*((a*x + b*x**S(2)/S(2) + c)**S(4) + S(1)), x), x, a*x + b*x**S(2)/S(2) + (a*x + b*x**S(2)/S(2) + c)**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*((a*x + b*x**S(2)/S(2))**n + S(1)), x), x, a*x + b*x**S(2)/S(2) + (a*x + b*x**S(2)/S(2))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x)*((a*x + b*x**S(2)/S(2) + c)**n + S(1)), x), x, a*x + b*x**S(2)/S(2) + (a*x + b*x**S(2)/S(2) + c)**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(2))*((a*x + c*x**S(3)/S(3))**S(5) + S(1)), x), x, a*x + c*x**S(3)/S(3) + (a*x + c*x**S(3)/S(3))**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(2))*((a*x + c*x**S(3)/S(3) + d)**S(5) + S(1)), x), x, a*x + c*x**S(3)/S(3) + (a*x + c*x**S(3)/S(3) + d)**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x + c*x**S(2))*((b*x**S(2)/S(2) + c*x**S(3)/S(3))**S(5) + S(1)), x), x, b*x**S(2)/S(2) + c*x**S(3)/S(3) + (b*x**S(2)/S(2) + c*x**S(3)/S(3))**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x + c*x**S(2))*((b*x**S(2)/S(2) + c*x**S(3)/S(3) + d)**S(5) + S(1)), x), x, b*x**S(2)/S(2) + c*x**S(3)/S(3) + (b*x**S(2)/S(2) + c*x**S(3)/S(3) + d)**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3))**S(5) + S(1))*(a + b*x + c*x**S(2)), x), x, a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3) + (a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3))**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3) + d)**S(5) + S(1))*(a + b*x + c*x**S(2)), x), x, a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3) + (a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3) + d)**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(2))*((a*x + c*x**S(3)/S(3))**n + S(1)), x), x, a*x + c*x**S(3)/S(3) + (a*x + c*x**S(3)/S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x + c*x**S(2))*((b*x**S(2)/S(2) + c*x**S(3)/S(3))**n + S(1)), x), x, b*x**S(2)/S(2) + c*x**S(3)/S(3) + (b*x**S(2)/S(2) + c*x**S(3)/S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3))**n + S(1))*(a + b*x + c*x**S(2)), x), x, a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3) + (a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3))**(n + S(1))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(b*x + c*x**S(2))**S(13), x), x, (b*x + c*x**S(2))**S(14)/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)*(b + S(2)*c*x**S(2))*(b*x + c*x**S(3))**S(13), x), x, x**S(28)*(b + c*x**S(2))**S(14)/S(28), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(28)*(b + S(2)*c*x**S(3))*(b*x + c*x**S(4))**S(13), x), x, x**S(42)*(b + c*x**S(3))**S(14)/S(42), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(14)*n + S(-14))*(b + S(2)*c*x**n)*(b*x + c*x**(n + S(1)))**S(13), x), x, x**(S(14)*n)*(b + c*x**n)**S(14)/(S(14)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(b*x + c*x**S(2)), x), x, log(b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x**S(2))/(b*x + c*x**S(3)), x), x, log(x) + log(b + c*x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x**S(3))/(b*x + c*x**S(4)), x), x, log(x) + log(b + c*x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x**n)/(b*x + c*x**(n + S(1))), x), x, log(x) + log(b + c*x**n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(b*x + c*x**S(2))**S(8), x), x, -S(1)/(S(7)*(b*x + c*x**S(2))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x**S(2))/(x**S(7)*(b*x + c*x**S(3))**S(8)), x), x, -S(1)/(S(14)*x**S(14)*(b + c*x**S(2))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x**S(3))/(x**S(14)*(b*x + c*x**S(4))**S(8)), x), x, -S(1)/(S(21)*x**S(21)*(b + c*x**S(3))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-S(7)*n + S(7))*(b + S(2)*c*x**n)/(b*x + c*x**(n + S(1)))**S(8), x), x, -x**(-S(7)*n)/(S(7)*n*(b + c*x**n)**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(b*x + c*x**S(2))**p, x), x, (b*x + c*x**S(2))**(p + S(1))/(p + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(p + S(1))*(b + S(2)*c*x**S(2))*(b*x + c*x**S(3))**p, x), x, x**(p + S(1))*(b*x + c*x**S(3))**(p + S(1))/(S(2)*p + S(2)), expand=True, _diff=True, _numerical=True) # fails in mathematica too assert rubi_test(rubi_integrate(b*x**(p + S(1))*(b*x + c*x**S(3))**p + S(2)*c*x**(p + S(3))*(b*x + c*x**S(3))**p, x), x, x**(p + S(1))*(b*x + c*x**S(3))**(p + S(1))/(S(2)*p + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*p + S(2))*(b + S(2)*c*x**S(3))*(b*x + c*x**S(4))**p, x), x, x**(S(2)*p + S(2))*(b*x + c*x**S(4))**(p + S(1))/(S(3)*p + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**((n + S(-1))*(p + S(1)))*(b + S(2)*c*x**n)*(b*x + c*x**(n + S(1)))**p, x), x, x**(-(-n + S(1))*(p + S(1)))*(b*x + c*x**(n + S(1)))**(p + S(1))/(n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(4)*x + S(-4))*(x**S(3) + S(6)*x**S(2) - S(12)*x + S(5)), x), x, (x**S(3) + S(6)*x**S(2) - S(12)*x + S(5))**S(2)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(2)*x)*(x**S(4) + S(4)*x**S(2) + S(1)), x), x, (x**S(4) + S(4)*x**S(2) + S(1))**S(2)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(1))*(x**S(2) + x)**S(3)*(S(7)*(x**S(2) + x)**S(3) + S(-18))**S(2), x), x, S(49)*x**S(10)*(x + S(1))**S(10)/S(10) - S(36)*x**S(7)*(x + S(1))**S(7) + S(81)*x**S(4)*(x + S(1))**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(x + S(1))**S(3)*(S(2)*x + S(1))*(S(7)*x**S(3)*(x + S(1))**S(3) + S(-18))**S(2), x), x, S(49)*x**S(10)*(x + S(1))**S(10)/S(10) - S(36)*x**S(7)*(x + S(1))**S(7) + S(81)*x**S(4)*(x + S(1))**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(2))/(x**S(3) - S(6)*x + S(1))**S(5), x), x, S(1)/(S(12)*(x**S(3) - S(6)*x + S(1))**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(2)*x)/(x**S(3) + S(3)*x**S(2) + S(4)), x), x, log(x**S(3) + S(3)*x**S(2) + S(4))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + x + S(1))/(x**S(4) + S(2)*x**S(2) + S(4)*x), x), x, log(x*(x**S(3) + S(2)*x + S(4)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(-1))/(x**S(4) - S(4)*x)**(S(2)/3), x), x, S(3)*(x**S(4) - S(4)*x)**(S(1)/3)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(2))*(-x**S(3) + S(6)*x)**(S(1)/4), x), x, S(4)*(-x**S(3) + S(6)*x)**(S(5)/4)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(1))*sqrt(x**S(5) + S(5)*x), x), x, S(2)*(x**S(5) + S(5)*x)**(S(3)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(4) + S(2))*sqrt(x**S(5) + S(2)*x), x), x, S(2)*(x**S(5) + S(2)*x)**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) + x)/sqrt(S(2)*x**S(3) + x**S(2)), x), x, sqrt(S(2)*x**S(3) + x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((-S(5)*x + S(1))**(S(1)/3) + S(2))/((-S(5)*x + S(1))**(S(1)/3) + S(3)), x), x, x + S(3)*(-S(5)*x + S(1))**(S(2)/3)/S(10) - S(9)*(-S(5)*x + S(1))**(S(1)/3)/S(5) + S(27)*log((-S(5)*x + S(1))**(S(1)/3) + S(3))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(x) + S(1))/(sqrt(x) + S(-1)), x), x, S(4)*sqrt(x) + x + S(4)*log(-sqrt(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-sqrt(S(3)*x + S(2)) + S(1))/(sqrt(S(3)*x + S(2)) + S(1)), x), x, -x + S(4)*sqrt(S(3)*x + S(2))/S(3) - S(4)*log(sqrt(S(3)*x + S(2)) + S(1))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a + b*x) + S(-1))/(sqrt(a + b*x) + S(1)), x), x, x - S(4)*sqrt(a + b*x)/b + S(4)*log(sqrt(a + b*x) + S(1))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*n*x**(n + S(-1)))/(a*x + b*x**n), x), x, log(a*x + b*x**n), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*n*x**(n + S(-1)))/(a*x + b*x**n), x), x, n*log(x) + log(a*x**(-n + S(1)) + b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n)*(a + b*n*x**(n + S(-1)))/(a*x**(-n + S(1)) + b), x), x, n*log(x) + log(a*x**(-n + S(1)) + b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*(c + d*x)**S(3)), x), x, -c*log(a + b*(c + d*x)**S(3))/(b*d**S(4)) + x/(b*d**S(3)) + sqrt(S(3))*(-S(3)*a**(S(1)/3)*b**(S(2)/3)*c**S(2) + a + b*c**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*b**(S(4)/3)*d**S(4)) - (S(3)*a**(S(1)/3)*b**(S(2)/3)*c**S(2) + a + b*c**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*b**(S(4)/3)*d**S(4)) + (S(3)*a**(S(1)/3)*b**(S(2)/3)*c**S(2) + a + b*c**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*b**(S(4)/3)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*(c + d*x)**S(3)), x), x, log(a + b*(c + d*x)**S(3))/(S(3)*b*d**S(3)) + sqrt(S(3))*c*(S(2)*a**(S(1)/3) - b**(S(1)/3)*c)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*b**(S(2)/3)*d**S(3)) + c*(S(2)*a**(S(1)/3) + b**(S(1)/3)*c)*log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*b**(S(2)/3)*d**S(3)) - c*(S(2)*a**(S(1)/3) + b**(S(1)/3)*c)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*b**(S(2)/3)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*(c + d*x)**S(3)), x), x, -sqrt(S(3))*(a**(S(1)/3) - b**(S(1)/3)*c)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*b**(S(2)/3)*d**S(2)) - (a**(S(1)/3) + b**(S(1)/3)*c)*log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*b**(S(2)/3)*d**S(2)) + (a**(S(1)/3) + b**(S(1)/3)*c)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*b**(S(2)/3)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*(c + d*x)**S(3)), x), x, log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*b**(S(1)/3)*d) - log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*b**(S(1)/3)*d) - sqrt(S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*b**(S(1)/3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*(c + d*x)**S(3))), x), x, log(x)/(a + b*c**S(3)) + sqrt(S(3))*b**(S(1)/3)*c*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*c + b**(S(2)/3)*c**S(2))) - (S(2)*a**(S(1)/3) - b**(S(1)/3)*c)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*c + b**(S(2)/3)*c**S(2))) - log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*(a**(S(1)/3) + b**(S(1)/3)*c)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/(x*(a + b*(c + d*x)**S(3))), x), x, -log(a + b*(c + d*x)**S(3))/(S(3)*a + S(3)*b*c**S(3)) + log(x)/(a + b*c**S(3)) + b**(S(1)/3)*c*(a**(S(1)/3) - b**(S(1)/3)*c)*log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*(a + b*c**S(3))) - b**(S(1)/3)*c*(a**(S(1)/3) - b**(S(1)/3)*c)*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*(a + b*c**S(3))) + sqrt(S(3))*b**(S(1)/3)*c*(a**(S(1)/3) + b**(S(1)/3)*c)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*(a + b*c**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*(c + d*x)**S(3))), x), x, -S(3)*b*c**S(2)*d*log(x)/(a + b*c**S(3))**S(2) + b*c**S(2)*d*log(a + b*(c + d*x)**S(3))/(a + b*c**S(3))**S(2) - S(1)/(x*(a + b*c**S(3))) + sqrt(S(3))*b**(S(1)/3)*d*(a**(S(1)/3) - b**(S(1)/3)*c)*(a**(S(1)/3) + b**(S(1)/3)*c)**S(3)*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*(a + b*c**S(3))**S(2)) + b**(S(1)/3)*d*(a**(S(1)/3)*(a - S(2)*b*c**S(3)) - b**(S(1)/3)*(S(2)*a*c - b*c**S(4)))*log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*(a + b*c**S(3))**S(2)) - b**(S(1)/3)*d*(a**(S(1)/3)*(a - S(2)*b*c**S(3)) - b**(S(1)/3)*(S(2)*a*c - b*c**S(4)))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*(a + b*c**S(3))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*(c + d*x)**S(3))), x), x, S(3)*b*c**S(2)*d/(x*(a + b*c**S(3))**S(2)) - S(3)*b*c*d**S(2)*(a - S(2)*b*c**S(3))*log(x)/(a + b*c**S(3))**S(3) + b*c*d**S(2)*(a - S(2)*b*c**S(3))*log(a + b*(c + d*x)**S(3))/(a + b*c**S(3))**S(3) - S(1)/(x**S(2)*(S(2)*a + S(2)*b*c**S(3))) + sqrt(S(3))*b**(S(2)/3)*d**S(2)*(a**(S(1)/3) + b**(S(1)/3)*c)**S(3)*(-S(3)*a**(S(2)/3)*b**(S(1)/3)*c + a + b*c**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*(a + b*c**S(3))**S(3)) - b**(S(2)/3)*d**S(2)*(S(6)*a**(S(4)/3)*b**(S(2)/3)*c**S(2) - S(3)*a**(S(1)/3)*b**(S(5)/3)*c**S(5) + a**S(2) - S(7)*a*b*c**S(3) + b**S(2)*c**S(6))*log(a**(S(1)/3) + b**(S(1)/3)*(c + d*x))/(S(3)*a**(S(2)/3)*(a + b*c**S(3))**S(3)) + b**(S(2)/3)*d**S(2)*(S(6)*a**(S(4)/3)*b**(S(2)/3)*c**S(2) - S(3)*a**(S(1)/3)*b**(S(5)/3)*c**S(5) + a**S(2) - S(7)*a*b*c**S(3) + b**S(2)*c**S(6))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*(c + d*x) + b**(S(2)/3)*(c + d*x)**S(2))/(S(6)*a**(S(2)/3)*(a + b*c**S(3))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*(c + d*x)**S(4)), x), x, log(a + b*(c + d*x)**S(4))/(S(4)*b*d**S(4)) + S(3)*c**S(2)*atan(sqrt(b)*(c + d*x)**S(2)/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)*d**S(4)) - sqrt(S(2))*c*(S(3)*sqrt(a) - sqrt(b)*c**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)*d**S(4)) + sqrt(S(2))*c*(S(3)*sqrt(a) - sqrt(b)*c**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)*d**S(4)) + sqrt(S(2))*c*(S(3)*sqrt(a) + sqrt(b)*c**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)*d**S(4)) - sqrt(S(2))*c*(S(3)*sqrt(a) + sqrt(b)*c**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*(c + d*x)**S(4)), x), x, -c*atan(sqrt(b)*(c + d*x)**S(2)/sqrt(a))/(sqrt(a)*sqrt(b)*d**S(3)) + sqrt(S(2))*(sqrt(a) - sqrt(b)*c**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)*d**S(3)) - sqrt(S(2))*(sqrt(a) - sqrt(b)*c**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)*d**S(3)) - sqrt(S(2))*(sqrt(a) + sqrt(b)*c**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)*d**S(3)) + sqrt(S(2))*(sqrt(a) + sqrt(b)*c**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*(c + d*x)**S(4)), x), x, atan(sqrt(b)*(c + d*x)**S(2)/sqrt(a))/(S(2)*sqrt(a)*sqrt(b)*d**S(2)) + sqrt(S(2))*c*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(1)/4)*d**S(2)) - sqrt(S(2))*c*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(1)/4)*d**S(2)) + sqrt(S(2))*c*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(1)/4)*d**S(2)) - sqrt(S(2))*c*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(1)/4)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*(c + d*x)**S(4)), x), x, -sqrt(S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(1)/4)*d) + sqrt(S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*b**(S(1)/4)*d) - sqrt(S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(1)/4)*d) + sqrt(S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(1)/4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*(c + d*x)**S(4))), x), x, -log(a + b*(c + d*x)**S(4))/(S(4)*a + S(4)*b*c**S(4)) + log(x)/(a + b*c**S(4)) - sqrt(b)*c**S(2)*atan(sqrt(b)*(c + d*x)**S(2)/sqrt(a))/(S(2)*sqrt(a)*(a + b*c**S(4))) - sqrt(S(2))*b**(S(1)/4)*c*(sqrt(a) - sqrt(b)*c**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*(a + b*c**S(4))) + sqrt(S(2))*b**(S(1)/4)*c*(sqrt(a) - sqrt(b)*c**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*(a + b*c**S(4))) + sqrt(S(2))*b**(S(1)/4)*c*(sqrt(a) + sqrt(b)*c**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*(a + b*c**S(4))) - sqrt(S(2))*b**(S(1)/4)*c*(sqrt(a) + sqrt(b)*c**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*(a + b*c**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*(c + d*x)**S(4))), x), x, -S(4)*b*c**S(3)*d*log(x)/(a + b*c**S(4))**S(2) + b*c**S(3)*d*log(a + b*(c + d*x)**S(4))/(a + b*c**S(4))**S(2) - S(1)/(x*(a + b*c**S(4))) - sqrt(b)*c*d*(a - b*c**S(4))*atan(sqrt(b)*(c + d*x)**S(2)/sqrt(a))/(sqrt(a)*(a + b*c**S(4))**S(2)) + sqrt(S(2))*b**(S(1)/4)*d*(sqrt(a)*(a - S(3)*b*c**S(4)) + sqrt(b)*c**S(2)*(S(3)*a - b*c**S(4)))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*(a + b*c**S(4))**S(2)) - sqrt(S(2))*b**(S(1)/4)*d*(sqrt(a)*(a - S(3)*b*c**S(4)) + sqrt(b)*c**S(2)*(S(3)*a - b*c**S(4)))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*(c + d*x)/a**(S(1)/4))/(S(4)*a**(S(3)/4)*(a + b*c**S(4))**S(2)) - sqrt(S(2))*b**(S(1)/4)*d*(a**(S(3)/2) - S(3)*sqrt(a)*b*c**S(4) - S(3)*a*sqrt(b)*c**S(2) + b**(S(3)/2)*c**S(6))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*(a + b*c**S(4))**S(2)) + sqrt(S(2))*b**(S(1)/4)*d*(a**(S(3)/2) - S(3)*sqrt(a)*b*c**S(4) - S(3)*a*sqrt(b)*c**S(2) + b**(S(3)/2)*c**S(6))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*(c + d*x) + sqrt(a) + sqrt(b)*(c + d*x)**S(2))/(S(8)*a**(S(3)/4)*(a + b*c**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*sqrt(c + d*x))**S(2), x), x, -a**S(2)*c**S(3)*x/d**S(3) - S(4)*a*b*c**S(3)*(c + d*x)**(S(3)/2)/(S(3)*d**S(4)) + S(12)*a*b*c**S(2)*(c + d*x)**(S(5)/2)/(S(5)*d**S(4)) - S(12)*a*b*c*(c + d*x)**(S(7)/2)/(S(7)*d**S(4)) + S(4)*a*b*(c + d*x)**(S(9)/2)/(S(9)*d**S(4)) + b**S(2)*(c + d*x)**S(5)/(S(5)*d**S(4)) + c**S(2)*(S(3)*a**S(2) - b**S(2)*c)*(c + d*x)**S(2)/(S(2)*d**S(4)) - c*(a**S(2) - b**S(2)*c)*(c + d*x)**S(3)/d**S(4) + (a**S(2) - S(3)*b**S(2)*c)*(c + d*x)**S(4)/(S(4)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*sqrt(c + d*x))**S(2), x), x, a**S(2)*c**S(2)*x/d**S(2) + S(4)*a*b*c**S(2)*(c + d*x)**(S(3)/2)/(S(3)*d**S(3)) - S(8)*a*b*c*(c + d*x)**(S(5)/2)/(S(5)*d**S(3)) + S(4)*a*b*(c + d*x)**(S(7)/2)/(S(7)*d**S(3)) + b**S(2)*(c + d*x)**S(4)/(S(4)*d**S(3)) - c*(S(2)*a**S(2) - b**S(2)*c)*(c + d*x)**S(2)/(S(2)*d**S(3)) + (a**S(2) - S(2)*b**S(2)*c)*(c + d*x)**S(3)/(S(3)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*sqrt(c + d*x))**S(2), x), x, -a**S(2)*c*x/d - S(4)*a*b*c*(c + d*x)**(S(3)/2)/(S(3)*d**S(2)) + S(4)*a*b*(c + d*x)**(S(5)/2)/(S(5)*d**S(2)) + b**S(2)*(c + d*x)**S(3)/(S(3)*d**S(2)) + (a**S(2) - b**S(2)*c)*(c + d*x)**S(2)/(S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sqrt(c + d*x))**S(2), x), x, a**S(2)*x + S(4)*a*b*(c + d*x)**(S(3)/2)/(S(3)*d) + b**S(2)*(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sqrt(c + d*x))**S(2)/x, x), x, -S(4)*a*b*sqrt(c)*atanh(sqrt(c + d*x)/sqrt(c)) + S(4)*a*b*sqrt(c + d*x) + b**S(2)*d*x + (a**S(2) + b**S(2)*c)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sqrt(c + d*x))**S(2)/x**S(2), x), x, -S(2)*a*b*d*atanh(sqrt(c + d*x)/sqrt(c))/sqrt(c) + b**S(2)*d*log(x) - (a + b*sqrt(c + d*x))**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sqrt(c + d*x))**S(2)/x**S(3), x), x, a*b*d**S(2)*atanh(sqrt(c + d*x)/sqrt(c))/(S(2)*c**(S(3)/2)) - b*d*(a*sqrt(c + d*x) + b*c)/(S(2)*c*x) - (a + b*sqrt(c + d*x))**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(a + b*sqrt(c + d*x)), x), x, -S(28)*a*(a + b*sqrt(c + d*x))**(S(15)/2)/(S(15)*b**S(8)*d**S(4)) - S(20)*a*(a + b*sqrt(c + d*x))**(S(11)/2)*(S(7)*a**S(2) - S(3)*b**S(2)*c)/(S(11)*b**S(8)*d**S(4)) - S(12)*a*(a + b*sqrt(c + d*x))**(S(7)/2)*(a**S(2) - b**S(2)*c)*(S(7)*a**S(2) - S(3)*b**S(2)*c)/(S(7)*b**S(8)*d**S(4)) - S(4)*a*(a + b*sqrt(c + d*x))**(S(3)/2)*(a**S(2) - b**S(2)*c)**S(3)/(S(3)*b**S(8)*d**S(4)) + S(4)*(a + b*sqrt(c + d*x))**(S(17)/2)/(S(17)*b**S(8)*d**S(4)) + (a + b*sqrt(c + d*x))**(S(13)/2)*(S(84)*a**S(2) - S(12)*b**S(2)*c)/(S(13)*b**S(8)*d**S(4)) + (a + b*sqrt(c + d*x))**(S(9)/2)*(S(140)*a**S(4) - S(120)*a**S(2)*b**S(2)*c + S(12)*b**S(4)*c**S(2))/(S(9)*b**S(8)*d**S(4)) + S(4)*(a + b*sqrt(c + d*x))**(S(5)/2)*(a**S(2) - b**S(2)*c)**S(2)*(S(7)*a**S(2) - b**S(2)*c)/(S(5)*b**S(8)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a + b*sqrt(c + d*x)), x), x, -S(20)*a*(a + b*sqrt(c + d*x))**(S(11)/2)/(S(11)*b**S(6)*d**S(3)) - S(8)*a*(a + b*sqrt(c + d*x))**(S(7)/2)*(S(5)*a**S(2) - S(3)*b**S(2)*c)/(S(7)*b**S(6)*d**S(3)) - S(4)*a*(a + b*sqrt(c + d*x))**(S(3)/2)*(a**S(2) - b**S(2)*c)**S(2)/(S(3)*b**S(6)*d**S(3)) + S(4)*(a + b*sqrt(c + d*x))**(S(13)/2)/(S(13)*b**S(6)*d**S(3)) + (a + b*sqrt(c + d*x))**(S(9)/2)*(S(40)*a**S(2) - S(8)*b**S(2)*c)/(S(9)*b**S(6)*d**S(3)) + (a + b*sqrt(c + d*x))**(S(5)/2)*(S(20)*a**S(4) - S(24)*a**S(2)*b**S(2)*c + S(4)*b**S(4)*c**S(2))/(S(5)*b**S(6)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*sqrt(c + d*x)), x), x, -S(12)*a*(a + b*sqrt(c + d*x))**(S(7)/2)/(S(7)*b**S(4)*d**S(2)) - S(4)*a*(a + b*sqrt(c + d*x))**(S(3)/2)*(a**S(2) - b**S(2)*c)/(S(3)*b**S(4)*d**S(2)) + S(4)*(a + b*sqrt(c + d*x))**(S(9)/2)/(S(9)*b**S(4)*d**S(2)) + (a + b*sqrt(c + d*x))**(S(5)/2)*(S(12)*a**S(2) - S(4)*b**S(2)*c)/(S(5)*b**S(4)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c + d*x)), x), x, -S(4)*a*(a + b*sqrt(c + d*x))**(S(3)/2)/(S(3)*b**S(2)*d) + S(4)*(a + b*sqrt(c + d*x))**(S(5)/2)/(S(5)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c + d*x))/x, x), x, -S(2)*sqrt(a - b*sqrt(c))*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a - b*sqrt(c))) - S(2)*sqrt(a + b*sqrt(c))*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a + b*sqrt(c))) + S(4)*sqrt(a + b*sqrt(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c + d*x))/x**S(2), x), x, -b*d*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a + b*sqrt(c)))/(S(2)*sqrt(c)*sqrt(a + b*sqrt(c))) + b*d*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a - b*sqrt(c)))/(S(2)*sqrt(c)*sqrt(a - b*sqrt(c))) - sqrt(a + b*sqrt(c + d*x))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c + d*x))/x**S(3), x), x, b*d*sqrt(a + b*sqrt(c + d*x))*(-a*sqrt(c + d*x) + b*c)/(S(8)*c*x*(a**S(2) - b**S(2)*c)) + b*d**S(2)*(S(2)*a + S(3)*b*sqrt(c))*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a + b*sqrt(c)))/(S(16)*c**(S(3)/2)*(a + b*sqrt(c))**(S(3)/2)) - b*d**S(2)*(S(2)*a - S(3)*b*sqrt(c))*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a - b*sqrt(c)))/(S(16)*c**(S(3)/2)*(a - b*sqrt(c))**(S(3)/2)) - sqrt(a + b*sqrt(c + d*x))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*sqrt(c + d*x)), x), x, -a*(c + d*x)**S(3)/(S(3)*b**S(2)*d**S(4)) - a*(a**S(2) - S(3)*b**S(2)*c)*(c + d*x)**S(2)/(S(2)*b**S(4)*d**S(4)) - a*x*(a**S(4) - S(3)*a**S(2)*b**S(2)*c + S(3)*b**S(4)*c**S(2))/(b**S(6)*d**S(3)) - S(2)*a*(a**S(2) - b**S(2)*c)**S(3)*log(a + b*sqrt(c + d*x))/(b**S(8)*d**S(4)) + S(2)*(c + d*x)**(S(7)/2)/(S(7)*b*d**S(4)) + (S(2)*a**S(2) - S(6)*b**S(2)*c)*(c + d*x)**(S(5)/2)/(S(5)*b**S(3)*d**S(4)) + (c + d*x)**(S(3)/2)*(S(2)*a**S(4) - S(6)*a**S(2)*b**S(2)*c + S(6)*b**S(4)*c**S(2))/(S(3)*b**S(5)*d**S(4)) + S(2)*(a**S(2) - b**S(2)*c)**S(3)*sqrt(c + d*x)/(b**S(7)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*sqrt(c + d*x)), x), x, -a*(c + d*x)**S(2)/(S(2)*b**S(2)*d**S(3)) - a*x*(a**S(2) - S(2)*b**S(2)*c)/(b**S(4)*d**S(2)) - S(2)*a*(a**S(2) - b**S(2)*c)**S(2)*log(a + b*sqrt(c + d*x))/(b**S(6)*d**S(3)) + S(2)*(c + d*x)**(S(5)/2)/(S(5)*b*d**S(3)) + (S(2)*a**S(2) - S(4)*b**S(2)*c)*(c + d*x)**(S(3)/2)/(S(3)*b**S(3)*d**S(3)) + S(2)*(a**S(2) - b**S(2)*c)**S(2)*sqrt(c + d*x)/(b**S(5)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*sqrt(c + d*x)), x), x, -a*x/(b**S(2)*d) - S(2)*a*(a**S(2) - b**S(2)*c)*log(a + b*sqrt(c + d*x))/(b**S(4)*d**S(2)) + S(2)*(c + d*x)**(S(3)/2)/(S(3)*b*d**S(2)) + (S(2)*a**S(2) - S(2)*b**S(2)*c)*sqrt(c + d*x)/(b**S(3)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*sqrt(c + d*x)), x), x, -S(2)*a*log(a + b*sqrt(c + d*x))/(b**S(2)*d) + S(2)*sqrt(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*sqrt(c + d*x))), x), x, a*log(x)/(a**S(2) - b**S(2)*c) - S(2)*a*log(a + b*sqrt(c + d*x))/(a**S(2) - b**S(2)*c) + S(2)*b*sqrt(c)*atanh(sqrt(c + d*x)/sqrt(c))/(a**S(2) - b**S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*sqrt(c + d*x))), x), x, a*b**S(2)*d*log(x)/(a**S(2) - b**S(2)*c)**S(2) - S(2)*a*b**S(2)*d*log(a + b*sqrt(c + d*x))/(a**S(2) - b**S(2)*c)**S(2) + b*d*(a**S(2) + b**S(2)*c)*atanh(sqrt(c + d*x)/sqrt(c))/(sqrt(c)*(a**S(2) - b**S(2)*c)**S(2)) - (a - b*sqrt(c + d*x))/(x*(a**S(2) - b**S(2)*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*sqrt(c + d*x))), x), x, a*b**S(4)*d**S(2)*log(x)/(a**S(2) - b**S(2)*c)**S(3) - S(2)*a*b**S(4)*d**S(2)*log(a + b*sqrt(c + d*x))/(a**S(2) - b**S(2)*c)**S(3) - b*d*(S(4)*a*b*c - (a**S(2) + S(3)*b**S(2)*c)*sqrt(c + d*x))/(S(4)*c*x*(a**S(2) - b**S(2)*c)**S(2)) - b*d**S(2)*(a**S(4) - S(6)*a**S(2)*b**S(2)*c - S(3)*b**S(4)*c**S(2))*atanh(sqrt(c + d*x)/sqrt(c))/(S(4)*c**(S(3)/2)*(a**S(2) - b**S(2)*c)**S(3)) - (a - b*sqrt(c + d*x))/(x**S(2)*(S(2)*a**S(2) - S(2)*b**S(2)*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*sqrt(c + d*x))**S(2), x), x, -S(4)*a*(c + d*x)**(S(5)/2)/(S(5)*b**S(3)*d**S(4)) - S(4)*a*(S(2)*a**S(2) - S(3)*b**S(2)*c)*(c + d*x)**(S(3)/2)/(S(3)*b**S(5)*d**S(4)) - S(12)*a*(a**S(2) - b**S(2)*c)**S(2)*sqrt(c + d*x)/(b**S(7)*d**S(4)) + S(2)*a*(a**S(2) - b**S(2)*c)**S(3)/(b**S(8)*d**S(4)*(a + b*sqrt(c + d*x))) + (c + d*x)**S(3)/(S(3)*b**S(2)*d**S(4)) + (S(3)*a**S(2) - S(3)*b**S(2)*c)*(c + d*x)**S(2)/(S(2)*b**S(4)*d**S(4)) + x*(S(5)*a**S(4) - S(9)*a**S(2)*b**S(2)*c + S(3)*b**S(4)*c**S(2))/(b**S(6)*d**S(3)) + S(2)*(a**S(2) - b**S(2)*c)**S(2)*(S(7)*a**S(2) - b**S(2)*c)*log(a + b*sqrt(c + d*x))/(b**S(8)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*sqrt(c + d*x))**S(2), x), x, -S(4)*a*(c + d*x)**(S(3)/2)/(S(3)*b**S(3)*d**S(3)) - S(8)*a*(a**S(2) - b**S(2)*c)*sqrt(c + d*x)/(b**S(5)*d**S(3)) + S(2)*a*(a**S(2) - b**S(2)*c)**S(2)/(b**S(6)*d**S(3)*(a + b*sqrt(c + d*x))) + (c + d*x)**S(2)/(S(2)*b**S(2)*d**S(3)) + x*(S(3)*a**S(2) - S(2)*b**S(2)*c)/(b**S(4)*d**S(2)) + (S(10)*a**S(4) - S(12)*a**S(2)*b**S(2)*c + S(2)*b**S(4)*c**S(2))*log(a + b*sqrt(c + d*x))/(b**S(6)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*sqrt(c + d*x))**S(2), x), x, -S(4)*a*sqrt(c + d*x)/(b**S(3)*d**S(2)) + S(2)*a*(a**S(2) - b**S(2)*c)/(b**S(4)*d**S(2)*(a + b*sqrt(c + d*x))) + x/(b**S(2)*d) + (S(6)*a**S(2) - S(2)*b**S(2)*c)*log(a + b*sqrt(c + d*x))/(b**S(4)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sqrt(c + d*x))**(S(-2)), x), x, S(2)*a/(b**S(2)*d*(a + b*sqrt(c + d*x))) + S(2)*log(a + b*sqrt(c + d*x))/(b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*sqrt(c + d*x))**S(2)), x), x, S(4)*a*b*sqrt(c)*atanh(sqrt(c + d*x)/sqrt(c))/(a**S(2) - b**S(2)*c)**S(2) + S(2)*a/((a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)) + (a**S(2) + b**S(2)*c)*log(x)/(a**S(2) - b**S(2)*c)**S(2) - (S(2)*a**S(2) + S(2)*b**S(2)*c)*log(a + b*sqrt(c + d*x))/(a**S(2) - b**S(2)*c)**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*sqrt(c + d*x))**S(2)), x), x, S(4)*a*b**S(2)*d/((a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)**S(2)) + S(2)*a*b*d*(a**S(2) + S(3)*b**S(2)*c)*atanh(sqrt(c + d*x)/sqrt(c))/(sqrt(c)*(a**S(2) - b**S(2)*c)**S(3)) + b**S(2)*d*(S(3)*a**S(2) + b**S(2)*c)*log(x)/(a**S(2) - b**S(2)*c)**S(3) - S(2)*b**S(2)*d*(S(3)*a**S(2) + b**S(2)*c)*log(a + b*sqrt(c + d*x))/(a**S(2) - b**S(2)*c)**S(3) - (a - b*sqrt(c + d*x))/(x*(a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*sqrt(c + d*x))**S(2)), x), x, a*b**S(2)*d**S(2)*(a**S(2) + S(11)*b**S(2)*c)/(S(2)*c*(a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)**S(3)) - a*b*d**S(2)*(a**S(4) - S(10)*a**S(2)*b**S(2)*c - S(15)*b**S(4)*c**S(2))*atanh(sqrt(c + d*x)/sqrt(c))/(S(2)*c**(S(3)/2)*(a**S(2) - b**S(2)*c)**S(4)) + b**S(4)*d**S(2)*(S(5)*a**S(2) + b**S(2)*c)*log(x)/(a**S(2) - b**S(2)*c)**S(4) - S(2)*b**S(4)*d**S(2)*(S(5)*a**S(2) + b**S(2)*c)*log(a + b*sqrt(c + d*x))/(a**S(2) - b**S(2)*c)**S(4) - b*d*(S(3)*a*b*c - (a**S(2) + S(2)*b**S(2)*c)*sqrt(c + d*x))/(S(2)*c*x*(a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)**S(2)) - (a - b*sqrt(c + d*x))/(x**S(2)*(a + b*sqrt(c + d*x))*(S(2)*a**S(2) - S(2)*b**S(2)*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a + b*sqrt(c + d*x)), x), x, -S(28)*a*(a + b*sqrt(c + d*x))**(S(13)/2)/(S(13)*b**S(8)*d**S(4)) - S(20)*a*(a + b*sqrt(c + d*x))**(S(9)/2)*(S(7)*a**S(2) - S(3)*b**S(2)*c)/(S(9)*b**S(8)*d**S(4)) - S(12)*a*(a + b*sqrt(c + d*x))**(S(5)/2)*(a**S(2) - b**S(2)*c)*(S(7)*a**S(2) - S(3)*b**S(2)*c)/(S(5)*b**S(8)*d**S(4)) - S(4)*a*sqrt(a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)**S(3)/(b**S(8)*d**S(4)) + S(4)*(a + b*sqrt(c + d*x))**(S(15)/2)/(S(15)*b**S(8)*d**S(4)) + (a + b*sqrt(c + d*x))**(S(11)/2)*(S(84)*a**S(2) - S(12)*b**S(2)*c)/(S(11)*b**S(8)*d**S(4)) + (a + b*sqrt(c + d*x))**(S(7)/2)*(S(140)*a**S(4) - S(120)*a**S(2)*b**S(2)*c + S(12)*b**S(4)*c**S(2))/(S(7)*b**S(8)*d**S(4)) + S(4)*(a + b*sqrt(c + d*x))**(S(3)/2)*(a**S(2) - b**S(2)*c)**S(2)*(S(7)*a**S(2) - b**S(2)*c)/(S(3)*b**S(8)*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*sqrt(c + d*x)), x), x, -S(20)*a*(a + b*sqrt(c + d*x))**(S(9)/2)/(S(9)*b**S(6)*d**S(3)) - S(8)*a*(a + b*sqrt(c + d*x))**(S(5)/2)*(S(5)*a**S(2) - S(3)*b**S(2)*c)/(S(5)*b**S(6)*d**S(3)) - S(4)*a*sqrt(a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)**S(2)/(b**S(6)*d**S(3)) + S(4)*(a + b*sqrt(c + d*x))**(S(11)/2)/(S(11)*b**S(6)*d**S(3)) + (a + b*sqrt(c + d*x))**(S(7)/2)*(S(40)*a**S(2) - S(8)*b**S(2)*c)/(S(7)*b**S(6)*d**S(3)) + (a + b*sqrt(c + d*x))**(S(3)/2)*(S(20)*a**S(4) - S(24)*a**S(2)*b**S(2)*c + S(4)*b**S(4)*c**S(2))/(S(3)*b**S(6)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*sqrt(c + d*x)), x), x, -S(12)*a*(a + b*sqrt(c + d*x))**(S(5)/2)/(S(5)*b**S(4)*d**S(2)) - S(4)*a*sqrt(a + b*sqrt(c + d*x))*(a**S(2) - b**S(2)*c)/(b**S(4)*d**S(2)) + S(4)*(a + b*sqrt(c + d*x))**(S(7)/2)/(S(7)*b**S(4)*d**S(2)) + (a + b*sqrt(c + d*x))**(S(3)/2)*(S(12)*a**S(2) - S(4)*b**S(2)*c)/(S(3)*b**S(4)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*sqrt(c + d*x)), x), x, -S(4)*a*sqrt(a + b*sqrt(c + d*x))/(b**S(2)*d) + S(4)*(a + b*sqrt(c + d*x))**(S(3)/2)/(S(3)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*sqrt(c + d*x))), x), x, -S(2)*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a + b*sqrt(c)))/sqrt(a + b*sqrt(c)) - S(2)*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a - b*sqrt(c)))/sqrt(a - b*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*sqrt(c + d*x))), x), x, b*d*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a + b*sqrt(c)))/(S(2)*sqrt(c)*(a + b*sqrt(c))**(S(3)/2)) - b*d*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a - b*sqrt(c)))/(S(2)*sqrt(c)*(a - b*sqrt(c))**(S(3)/2)) - (a - b*sqrt(c + d*x))*sqrt(a + b*sqrt(c + d*x))/(x*(a**S(2) - b**S(2)*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + b*sqrt(c + d*x))), x), x, -b*d*sqrt(a + b*sqrt(c + d*x))*(S(6)*a*b*c - (a**S(2) + S(5)*b**S(2)*c)*sqrt(c + d*x))/(S(8)*c*x*(a**S(2) - b**S(2)*c)**S(2)) - b*d**S(2)*(S(2)*a + S(5)*b*sqrt(c))*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a + b*sqrt(c)))/(S(16)*c**(S(3)/2)*(a + b*sqrt(c))**(S(5)/2)) + b*d**S(2)*(S(2)*a - S(5)*b*sqrt(c))*atanh(sqrt(a + b*sqrt(c + d*x))/sqrt(a - b*sqrt(c)))/(S(16)*c**(S(3)/2)*(a - b*sqrt(c))**(S(5)/2)) - (a - b*sqrt(c + d*x))*sqrt(a + b*sqrt(c + d*x))/(x**S(2)*(S(2)*a**S(2) - S(2)*b**S(2)*c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*sqrt(c + d*x))**p, x), x, -S(2)*a*(a + b*sqrt(c + d*x))**(p + S(1))*(a**S(2) - b**S(2)*c)**S(3)/(b**S(8)*d**S(4)*(p + S(1))) - S(6)*a*(a + b*sqrt(c + d*x))**(p + S(3))*(a**S(2) - b**S(2)*c)*(S(7)*a**S(2) - S(3)*b**S(2)*c)/(b**S(8)*d**S(4)*(p + S(3))) - S(10)*a*(a + b*sqrt(c + d*x))**(p + S(5))*(S(7)*a**S(2) - S(3)*b**S(2)*c)/(b**S(8)*d**S(4)*(p + S(5))) - S(14)*a*(a + b*sqrt(c + d*x))**(p + S(7))/(b**S(8)*d**S(4)*(p + S(7))) + S(2)*(a + b*sqrt(c + d*x))**(p + S(2))*(a**S(2) - b**S(2)*c)**S(2)*(S(7)*a**S(2) - b**S(2)*c)/(b**S(8)*d**S(4)*(p + S(2))) + (a + b*sqrt(c + d*x))**(p + S(4))*(S(70)*a**S(4) - S(60)*a**S(2)*b**S(2)*c + S(6)*b**S(4)*c**S(2))/(b**S(8)*d**S(4)*(p + S(4))) + (a + b*sqrt(c + d*x))**(p + S(6))*(S(42)*a**S(2) - S(6)*b**S(2)*c)/(b**S(8)*d**S(4)*(p + S(6))) + S(2)*(a + b*sqrt(c + d*x))**(p + S(8))/(b**S(8)*d**S(4)*(p + S(8))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*sqrt(c + d*x))**p, x), x, -S(2)*a*(a + b*sqrt(c + d*x))**(p + S(1))*(a**S(2) - b**S(2)*c)**S(2)/(b**S(6)*d**S(3)*(p + S(1))) - S(4)*a*(a + b*sqrt(c + d*x))**(p + S(3))*(S(5)*a**S(2) - S(3)*b**S(2)*c)/(b**S(6)*d**S(3)*(p + S(3))) - S(10)*a*(a + b*sqrt(c + d*x))**(p + S(5))/(b**S(6)*d**S(3)*(p + S(5))) + (a + b*sqrt(c + d*x))**(p + S(2))*(S(10)*a**S(4) - S(12)*a**S(2)*b**S(2)*c + S(2)*b**S(4)*c**S(2))/(b**S(6)*d**S(3)*(p + S(2))) + (a + b*sqrt(c + d*x))**(p + S(4))*(S(20)*a**S(2) - S(4)*b**S(2)*c)/(b**S(6)*d**S(3)*(p + S(4))) + S(2)*(a + b*sqrt(c + d*x))**(p + S(6))/(b**S(6)*d**S(3)*(p + S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*sqrt(c + d*x))**p, x), x, -S(2)*a*(a + b*sqrt(c + d*x))**(p + S(1))*(a**S(2) - b**S(2)*c)/(b**S(4)*d**S(2)*(p + S(1))) - S(6)*a*(a + b*sqrt(c + d*x))**(p + S(3))/(b**S(4)*d**S(2)*(p + S(3))) + (a + b*sqrt(c + d*x))**(p + S(2))*(S(6)*a**S(2) - S(2)*b**S(2)*c)/(b**S(4)*d**S(2)*(p + S(2))) + S(2)*(a + b*sqrt(c + d*x))**(p + S(4))/(b**S(4)*d**S(2)*(p + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sqrt(c + d*x))**p, x), x, -S(2)*a*(a + b*sqrt(c + d*x))**(p + S(1))/(b**S(2)*d*(p + S(1))) + S(2)*(a + b*sqrt(c + d*x))**(p + S(2))/(b**S(2)*d*(p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*sqrt(c + d*x))**p/x, x), x, -(a + b*sqrt(c + d*x))**(p + S(1))*hyper((S(1), p + S(1)), (p + S(2),), (a + b*sqrt(c + d*x))/(a + b*sqrt(c)))/((a + b*sqrt(c))*(p + S(1))) - (a + b*sqrt(c + d*x))**(p + S(1))*hyper((S(1), p + S(1)), (p + S(2),), (a + b*sqrt(c + d*x))/(a - b*sqrt(c)))/((a - b*sqrt(c))*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x)**n)**(S(5)/2)/x, x), x, -S(2)*a**(S(5)/2)*atanh(sqrt(a + b*(c*x)**n)/sqrt(a))/n + S(2)*a**S(2)*sqrt(a + b*(c*x)**n)/n + S(2)*a*(a + b*(c*x)**n)**(S(3)/2)/(S(3)*n) + S(2)*(a + b*(c*x)**n)**(S(5)/2)/(S(5)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(c*x)**n)**(S(3)/2)/x, x), x, -S(2)*a**(S(3)/2)*atanh(sqrt(a + b*(c*x)**n)/sqrt(a))/n + S(2)*a*sqrt(a + b*(c*x)**n)/n + S(2)*(a + b*(c*x)**n)**(S(3)/2)/(S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*(c*x)**n)/x, x), x, -S(2)*sqrt(a)*atanh(sqrt(a + b*(c*x)**n)/sqrt(a))/n + S(2)*sqrt(a + b*(c*x)**n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*(c*x)**n)), x), x, -S(2)*atanh(sqrt(a + b*(c*x)**n)/sqrt(a))/(sqrt(a)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*(c*x)**n)**(S(3)/2)), x), x, S(2)/(a*n*sqrt(a + b*(c*x)**n)) - S(2)*atanh(sqrt(a + b*(c*x)**n)/sqrt(a))/(a**(S(3)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*(c*x)**n)**(S(5)/2)), x), x, S(2)/(S(3)*a*n*(a + b*(c*x)**n)**(S(3)/2)) + S(2)/(a**S(2)*n*sqrt(a + b*(c*x)**n)) - S(2)*atanh(sqrt(a + b*(c*x)**n)/sqrt(a))/(a**(S(5)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-a + b*(c*x)**n)**(S(5)/2)/x, x), x, -S(2)*a**(S(5)/2)*atan(sqrt(-a + b*(c*x)**n)/sqrt(a))/n + S(2)*a**S(2)*sqrt(-a + b*(c*x)**n)/n - S(2)*a*(-a + b*(c*x)**n)**(S(3)/2)/(S(3)*n) + S(2)*(-a + b*(c*x)**n)**(S(5)/2)/(S(5)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-a + b*(c*x)**n)**(S(3)/2)/x, x), x, S(2)*a**(S(3)/2)*atan(sqrt(-a + b*(c*x)**n)/sqrt(a))/n - S(2)*a*sqrt(-a + b*(c*x)**n)/n + S(2)*(-a + b*(c*x)**n)**(S(3)/2)/(S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a + b*(c*x)**n)/x, x), x, -S(2)*sqrt(a)*atan(sqrt(-a + b*(c*x)**n)/sqrt(a))/n + S(2)*sqrt(-a + b*(c*x)**n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(-a + b*(c*x)**n)), x), x, S(2)*atan(sqrt(-a + b*(c*x)**n)/sqrt(a))/(sqrt(a)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(-a + b*(c*x)**n)**(S(3)/2)), x), x, -S(2)/(a*n*sqrt(-a + b*(c*x)**n)) - S(2)*atan(sqrt(-a + b*(c*x)**n)/sqrt(a))/(a**(S(3)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(-a + b*(c*x)**n)**(S(5)/2)), x), x, -S(2)/(S(3)*a*n*(-a + b*(c*x)**n)**(S(3)/2)) + S(2)/(a**S(2)*n*sqrt(-a + b*(c*x)**n)) + S(2)*atan(sqrt(-a + b*(c*x)**n)/sqrt(a))/(a**(S(5)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*x)), x), x, -S(2)*atanh(sqrt(a + b*x)/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*(c*x)**m)), x), x, -S(2)*atanh(sqrt(a + b*(c*x)**m)/sqrt(a))/(sqrt(a)*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*(c*(d*x)**m)**n)), x), x, -S(2)*atanh(sqrt(a + b*(c*(d*x)**m)**n)/sqrt(a))/(sqrt(a)*m*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*(c*(d*(e*x)**m)**n)**p)), x), x, -S(2)*atanh(sqrt(a + b*(c*(d*(e*x)**m)**n)**p)/sqrt(a))/(sqrt(a)*m*n*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*(c*(d*(e*(f*x)**m)**n)**p)**q)), x), x, -S(2)*atanh(sqrt(a + b*(c*(d*(e*(f*x)**m)**n)**p)**q)/sqrt(a))/(sqrt(a)*m*n*p*q), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(-1) + x**(S(-2)))*(x**S(2) + S(-1))**S(3)/x, x), x, -x**S(6)*(S(-1) + x**(S(-2)))**(S(7)/2)/S(6) - S(7)*x**S(4)*(S(-1) + x**(S(-2)))**(S(5)/2)/S(24) - S(35)*x**S(2)*(S(-1) + x**(S(-2)))**(S(3)/2)/S(48) + S(35)*sqrt(S(-1) + x**(S(-2)))/S(16) - S(35)*atan(sqrt(S(-1) + x**(S(-2))))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(-1) + x**(S(-2)))*(x**S(2) + S(-1))**S(2)/x, x), x, x**S(4)*(S(-1) + x**(S(-2)))**(S(5)/2)/S(4) + S(5)*x**S(2)*(S(-1) + x**(S(-2)))**(S(3)/2)/S(8) - S(15)*sqrt(S(-1) + x**(S(-2)))/S(8) + S(15)*atan(sqrt(S(-1) + x**(S(-2))))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(-1) + x**(S(-2)))*(x**S(2) + S(-1))/x, x), x, -x**S(2)*(S(-1) + x**(S(-2)))**(S(3)/2)/S(2) + S(3)*sqrt(S(-1) + x**(S(-2)))/S(2) - S(3)*atan(sqrt(S(-1) + x**(S(-2))))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(-1) + x**(S(-2)))/(x*(x**S(2) + S(-1))), x), x, sqrt(S(-1) + x**(S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(-1) + x**(S(-2)))/(x*(x**S(2) + S(-1))**S(2)), x), x, -sqrt(S(-1) + x**(S(-2))) + S(1)/sqrt(S(-1) + x**(S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(-1) + x**(S(-2)))/(x*(x**S(2) + S(-1))**S(3)), x), x, sqrt(S(-1) + x**(S(-2))) - S(2)/sqrt(S(-1) + x**(S(-2))) - S(1)/(S(3)*(S(-1) + x**(S(-2)))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(S(1) + x**(S(-2)))/(x**S(2) + S(1))**S(2), x), x, S(1)/sqrt(S(1) + x**(S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(S(1) + x**(S(-2)))*(x**S(2) + S(1))), x), x, S(1)/sqrt(S(1) + x**(S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(2) + sqrt(a + b*x**S(2))), x), x, log(sqrt(a + b*x**S(2)) + S(1))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(2) - (x**S(2))**(S(1)/3)), x), x, S(3)*log(-(x**S(2))**(S(2)/3) + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(x**S(2) + S(1))**S(3)*sqrt(x**S(4) + S(2)*x**S(2) + S(2)), x), x, (x**S(2) + S(1))**S(2)*(x**S(4) + S(2)*x**S(2) + S(2))**(S(3)/2)/S(10) - (x**S(4) + S(2)*x**S(2) + S(2))**(S(3)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt((-x**S(2) + S(1))/(x**S(2) + S(1))), x), x, sqrt((-x**S(2) + S(1))/(x**S(2) + S(1)))*(x**S(2) + S(1))/S(2) - atan(sqrt((-x**S(2) + S(1))/(x**S(2) + S(1)))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x*sqrt((-x**S(2) + S(1))/(x**S(2) + S(1))), x), x, sqrt((-x**S(2) + S(1))/(x**S(2) + S(1)))/((-x**S(2) + S(1))/(x**S(2) + S(1)) + S(1)) - atan(sqrt((-x**S(2) + S(1))/(x**S(2) + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt((-S(7)*x**S(2) + S(5))/(S(5)*x**S(2) + S(7))), x), x, sqrt((-S(7)*x**S(2) + S(5))/(S(5)*x**S(2) + S(7)))*(S(5)*x**S(2) + S(7))/S(10) - S(37)*sqrt(S(35))*atan(sqrt(S(35))*sqrt((-S(7)*x**S(2) + S(5))/(S(5)*x**S(2) + S(7)))/S(7))/S(175), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x*sqrt((-S(7)*x**S(2) + S(5))/(S(5)*x**S(2) + S(7))), x), x, S(37)*sqrt((-S(7)*x**S(2) + S(5))/(S(5)*x**S(2) + S(7)))/(S(5)*(-S(35)*x**S(2) + S(25))/(S(5)*x**S(2) + S(7)) + S(35)) - S(37)*sqrt(S(35))*atan(sqrt(S(35))*sqrt((-S(7)*x**S(2) + S(5))/(S(5)*x**S(2) + S(7)))/S(7))/S(175), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt((-x**S(3) + S(1))/(x**S(3) + S(1))), x), x, sqrt((-x**S(3) + S(1))/(x**S(3) + S(1)))*(x**S(3) + S(1))/S(3) - S(2)*atan(sqrt((-x**S(3) + S(1))/(x**S(3) + S(1))))/S(3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)*sqrt((-x**S(3) + S(1))/(x**S(3) + S(1))), x), x, S(2)*sqrt((-x**S(3) + S(1))/(x**S(3) + S(1)))/(S(3)*(-x**S(3) + S(1))/(x**S(3) + S(1)) + S(3)) - S(2)*atan(sqrt((-x**S(3) + S(1))/(x**S(3) + S(1))))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(-x**S(3) + S(1))*(x**S(9) + S(1))**S(2), x), x, S(2)*(-x**S(3) + S(1))**(S(17)/2)/S(51) - S(14)*(-x**S(3) + S(1))**(S(15)/2)/S(45) + S(14)*(-x**S(3) + S(1))**(S(13)/2)/S(13) - S(74)*(-x**S(3) + S(1))**(S(11)/2)/S(33) + S(86)*(-x**S(3) + S(1))**(S(9)/2)/S(27) - S(22)*(-x**S(3) + S(1))**(S(7)/2)/S(7) + S(32)*(-x**S(3) + S(1))**(S(5)/2)/S(15) - S(8)*(-x**S(3) + S(1))**(S(3)/2)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*sqrt((-x**S(3) + S(1))/(x**S(3) + S(1))), x), x, -S(8)*((-x**S(3) + S(1))/(x**S(3) + S(1)))**(S(3)/2)/(S(9)*((-x**S(3) + S(1))/(x**S(3) + S(1)) + S(1))**S(3)) + sqrt((-x**S(3) + S(1))/(x**S(3) + S(1)))/((-x**S(3) + S(1))/(x**S(3) + S(1)) + S(1)) - S(2)*sqrt((-x**S(3) + S(1))/(x**S(3) + S(1)))/(S(3)*((-x**S(3) + S(1))/(x**S(3) + S(1)) + S(1))**S(2)) - atan(sqrt((-x**S(3) + S(1))/(x**S(3) + S(1))))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)*sqrt((-S(7)*x**S(5) + S(5))/(S(5)*x**S(5) + S(7))), x), x, -S(999)*sqrt((-S(7)*x**S(5) + S(5))/(S(5)*x**S(5) + S(7)))/(S(175)*(-S(35)*x**S(5) + S(25))/(S(5)*x**S(5) + S(7)) + S(1225)) + S(2738)*sqrt((-S(7)*x**S(5) + S(5))/(S(5)*x**S(5) + S(7)))/(S(125)*((-S(35)*x**S(5) + S(25))/(S(5)*x**S(5) + S(7)) + S(7))**S(2)) + S(2257)*sqrt(S(35))*atan(sqrt(S(35))*sqrt((-S(7)*x**S(5) + S(5))/(S(5)*x**S(5) + S(7)))/S(7))/S(30625), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x**S(2))*(x**S(2) + S(1))) + x/(a + b*x**S(2))**(S(3)/2), x), x, -atanh(sqrt(a + b*x**S(2))/sqrt(a - b))/sqrt(a - b) - S(1)/(b*sqrt(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + x**S(2) + S(1))/((a + b*x**S(2))**(S(3)/2)*(x**S(2) + S(1))), x), x, -atanh(sqrt(a + b*x**S(2))/sqrt(a - b))/sqrt(a - b) - S(1)/(b*sqrt(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(a + b*x**S(2))*(x**S(2) + S(1))) + x/(a + b*x**S(2))**(S(3)/2) + x/(a + b*x**S(2))**(S(5)/2), x), x, -atanh(sqrt(a + b*x**S(2))/sqrt(a - b))/sqrt(a - b) - S(1)/(b*sqrt(a + b*x**S(2))) - S(1)/(S(3)*b*(a + b*x**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(2) + a*x**S(2) + a + b**S(2)*x**S(4) + b*x**S(4) + b*x**S(2) + x**S(2) + S(1))/((a + b*x**S(2))**(S(5)/2)*(x**S(2) + S(1))), x), x, -atanh(sqrt(a + b*x**S(2))/sqrt(a - b))/sqrt(a - b) - S(1)/(b*sqrt(a + b*x**S(2))) - S(1)/(S(3)*b*(a + b*x**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sqrt(x) + x), x), x, S(2)*sqrt(sqrt(x) + x) - S(2)*atanh(sqrt(x)/sqrt(sqrt(x) + x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(x) + x), x), x, sqrt(x)*sqrt(sqrt(x) + x)/S(6) + S(2)*x*sqrt(sqrt(x) + x)/S(3) - sqrt(sqrt(x) + x)/S(4) + atanh(sqrt(x)/sqrt(sqrt(x) + x))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x)*(x + sqrt(-x)), x), x, -x**S(2)/S(2) + S(2)*(-x)**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**(S(1)/4) + S(5))/(x + S(-6)), x), x, S(4)*x**(S(1)/4) + S(5)*log(-x + S(6)) - S(2)*S(6)**(S(1)/4)*atan(S(6)**(S(3)/4)*x**(S(1)/4)/S(6)) - S(2)*S(6)**(S(1)/4)*atanh(S(6)**(S(3)/4)*x**(S(1)/4)/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(-x + sqrt(-x + S(4)) + S(4)), x), x, -S(2)*log(sqrt(-x + S(4)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x - sqrt(x + S(2)) + S(1)), x), x, (sqrt(S(5))/S(5) + S(1))*log(-S(2)*sqrt(x + S(2)) + S(1) + sqrt(S(5))) + (-sqrt(S(5))/S(5) + S(1))*log(-S(2)*sqrt(x + S(2)) - sqrt(S(5)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x + sqrt(x + S(1)) + S(4)), x), x, log(x + sqrt(x + S(1)) + S(4)) - S(2)*sqrt(S(11))*atan(sqrt(S(11))*(S(2)*sqrt(x + S(1)) + S(1))/S(11))/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x - sqrt(x + S(1))), x), x, (sqrt(S(5))/S(5) + S(1))*log(-S(2)*sqrt(x + S(1)) + S(1) + sqrt(S(5))) + (-sqrt(S(5))/S(5) + S(1))*log(-S(2)*sqrt(x + S(1)) - sqrt(S(5)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x - sqrt(x + S(2))), x), x, S(4)*log(-sqrt(x + S(2)) + S(2))/S(3) + S(2)*log(sqrt(x + S(2)) + S(1))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x - sqrt(-x + S(1))), x), x, (sqrt(S(5))/S(5) + S(1))*log(S(2)*sqrt(-x + S(1)) + S(1) + sqrt(S(5))) + (-sqrt(S(5))/S(5) + S(1))*log(S(2)*sqrt(-x + S(1)) - sqrt(S(5)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(x) + x + S(1)), x), x, (-sqrt(x)/S(2) + S(-1)/4)*sqrt(sqrt(x) + x + S(1)) + S(2)*(sqrt(x) + x + S(1))**(S(3)/2)/S(3) - S(3)*asinh(sqrt(S(3))*(S(2)*sqrt(x) + S(1))/S(3))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x + sqrt(x + S(1)) + S(1)), x), x, -(S(2)*sqrt(x + S(1)) + S(1))*sqrt(x + sqrt(x + S(1)) + S(1))/S(4) + S(2)*(x + sqrt(x + S(1)) + S(1))**(S(3)/2)/S(3) + atanh(sqrt(x + S(1))/sqrt(x + sqrt(x + S(1)) + S(1)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x + sqrt(x + S(-1))), x), x, S(2)*(x + sqrt(x + S(-1)))**(S(3)/2)/S(3) + sqrt(x + sqrt(x + S(-1)))*(-sqrt(x + S(-1))/S(2) + S(-1)/4) - S(3)*asinh(sqrt(S(3))*(S(2)*sqrt(x + S(-1)) + S(1))/S(3))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x + sqrt(S(2)*x + S(-1))), x), x, (S(2)*x + sqrt(S(2)*x + S(-1)))**(S(3)/2)/S(3) - sqrt(S(2)*x + sqrt(S(2)*x + S(-1)))*(S(2)*sqrt(S(2)*x + S(-1)) + S(1))/S(8) - S(3)*asinh(sqrt(S(3))*(S(2)*sqrt(S(2)*x + S(-1)) + S(1))/S(3))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(3)*x + sqrt(S(8)*x + S(-7))), x), x, sqrt(S(2))*(S(24)*x + S(8)*sqrt(S(8)*x + S(-7)))**(S(3)/2)/S(144) - sqrt(S(2))*sqrt(S(24)*x + S(8)*sqrt(S(8)*x + S(-7)))*(S(3)*sqrt(S(8)*x + S(-7)) + S(4))/S(72) - S(47)*sqrt(S(6))*asinh(sqrt(S(47))*(S(3)*sqrt(S(8)*x + S(-7)) + S(4))/S(47))/S(216), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x + sqrt(x + S(1))), x), x, S(2)*sqrt(x + sqrt(x + S(1))) - atanh((S(2)*sqrt(x + S(1)) + S(1))/(S(2)*sqrt(x + sqrt(x + S(1))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(1))/(x + sqrt(S(6)*x + S(-9)) + S(4)), x), x, x - S(2)*sqrt(S(3))*sqrt(S(2)*x + S(-3)) + S(3)*log(x + sqrt(S(3))*sqrt(S(2)*x + S(-3)) + S(4)) + S(4)*sqrt(S(6))*atan(sqrt(S(6))*(sqrt(S(6)*x + S(-9)) + S(3))/S(12)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x + S(12))/(x + sqrt(S(6)*x + S(-9)) + S(4)), x), x, -x + S(2)*sqrt(S(3))*sqrt(S(2)*x + S(-3)) + S(10)*log(x + sqrt(S(3))*sqrt(S(2)*x + S(-3)) + S(4)) - S(21)*sqrt(S(6))*atan(sqrt(S(6))*(sqrt(S(6)*x + S(-9)) + S(3))/S(12))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(-1))/(sqrt(x)*(x**S(2) + S(1))), x), x, S(2)*x**(S(3)/2)/S(3) - sqrt(S(2))*atan(sqrt(S(2))*sqrt(x) + S(-1)) - sqrt(S(2))*atan(sqrt(S(2))*sqrt(x) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(2)*sqrt(x + S(-1))*sqrt(x - sqrt(x + S(-1)))), x), x, -asinh(sqrt(S(3))*(-S(2)*sqrt(x + S(-1)) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**(S(7)/2) + S(1))/(-x**S(2) + S(1)), x), x, -S(2)*x**(S(5)/2)/S(5) - S(2)*sqrt(x) - log(-sqrt(x) + S(1)) + log(x + S(1))/S(2) + atan(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(4))/((S(2)*x + S(-1))**(S(1)/3) + sqrt(S(2)*x + S(-1))), x), x, -x + S(3)*(S(2)*x + S(-1))**(S(7)/6)/S(7) + S(3)*(S(2)*x + S(-1))**(S(5)/6)/S(5) + S(18)*(S(2)*x + S(-1))**(S(1)/6) - S(3)*(S(2)*x + S(-1))**(S(4)/3)/S(8) - S(3)*(S(2)*x + S(-1))**(S(2)/3)/S(4) - S(9)*(S(2)*x + S(-1))**(S(1)/3) + (S(2)*x + S(-1))**(S(3)/2)/S(3) + S(6)*sqrt(S(2)*x + S(-1)) - S(18)*log((S(2)*x + S(-1))**(S(1)/6) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sqrt(sqrt(x) + S(1)) + S(2)), x), x, S(8)*(sqrt(sqrt(x) + S(1)) + S(2))**(S(7)/2)/S(7) - S(48)*(sqrt(sqrt(x) + S(1)) + S(2))**(S(5)/2)/S(5) + S(88)*(sqrt(sqrt(x) + S(1)) + S(2))**(S(3)/2)/S(3) - S(48)*sqrt(sqrt(sqrt(x) + S(1)) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(sqrt(x) + S(4)) + S(2)), x), x, S(8)*(sqrt(sqrt(x) + S(4)) + S(2))**(S(9)/2)/S(9) - S(48)*(sqrt(sqrt(x) + S(4)) + S(2))**(S(7)/2)/S(7) + S(64)*(sqrt(sqrt(x) + S(4)) + S(2))**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-sqrt(sqrt(S(5)*x + S(-9)) + S(4)) + S(2)), x), x, S(8)*(-sqrt(sqrt(S(5)*x + S(-9)) + S(4)) + S(2))**(S(9)/2)/S(45) - S(48)*(-sqrt(sqrt(S(5)*x + S(-9)) + S(4)) + S(2))**(S(7)/2)/S(35) + S(64)*(-sqrt(sqrt(S(5)*x + S(-9)) + S(4)) + S(2))**(S(5)/2)/S(25), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sqrt(sqrt(x) + S(1)) + S(2)), x), x, S(8)*(sqrt(sqrt(x) + S(1)) + S(2))**(S(7)/2)/S(7) - S(48)*(sqrt(sqrt(x) + S(1)) + S(2))**(S(5)/2)/S(5) + S(88)*(sqrt(sqrt(x) + S(1)) + S(2))**(S(3)/2)/S(3) - S(48)*sqrt(sqrt(sqrt(x) + S(1)) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1)), x), x, S(16)*(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1))**(S(17)/2)/S(17) - S(112)*(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1))**(S(15)/2)/S(15) + S(288)*(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1))**(S(13)/2)/S(13) - S(320)*(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1))**(S(11)/2)/S(11) + S(112)*(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1))**(S(9)/2)/S(9) + S(48)*(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1))**(S(7)/2)/S(7) - S(32)*(sqrt(sqrt(sqrt(x) + S(1)) + S(1)) + S(1))**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2)), x), x, S(4)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(17)/2)/S(17) - S(56)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(15)/2)/S(15) + S(300)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(13)/2)/S(13) - S(760)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(11)/2)/S(11) + S(304)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(9)/2)/S(3) - S(480)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(7)/2)/S(7) + S(136)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(5)/2)/S(5) - S(16)*(sqrt(sqrt(S(2)*sqrt(x) + S(-1)) + S(3)) + S(2))**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(sqrt(sqrt(x + S(-1)) + S(1)) + S(1)), x), x, S(8)*(sqrt(sqrt(x + S(-1)) + S(1)) + S(1))**(S(17)/2)/S(17) - S(56)*(sqrt(sqrt(x + S(-1)) + S(1)) + S(1))**(S(15)/2)/S(15) + S(144)*(sqrt(sqrt(x + S(-1)) + S(1)) + S(1))**(S(13)/2)/S(13) - S(160)*(sqrt(sqrt(x + S(-1)) + S(1)) + S(1))**(S(11)/2)/S(11) + S(8)*(sqrt(sqrt(x + S(-1)) + S(1)) + S(1))**(S(9)/2) - S(24)*(sqrt(sqrt(x + S(-1)) + S(1)) + S(1))**(S(7)/2)/S(7) + S(16)*(sqrt(sqrt(x + S(-1)) + S(1)) + S(1))**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x + S(-1))*sqrt(x - sqrt(x + S(-1)))), x), x, -S(2)*asinh(sqrt(S(3))*(-S(2)*sqrt(x + S(-1)) + S(1))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x + sqrt(S(2)*x + S(-1)) + S(1)), x), x, S(2)*sqrt(x + sqrt(S(2)*x + S(-1)) + S(1)) - sqrt(S(2))*asinh(sqrt(S(2))*(sqrt(S(2)*x + S(-1)) + S(1))/S(2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/sqrt(x + sqrt(S(2)*x + S(-1)) + S(1)), x), x, sqrt(S(2))*sqrt(S(2)*x + S(2)*sqrt(S(2)*x + S(-1)) + S(2)) - sqrt(S(2))*asinh(sqrt(S(2))*(sqrt(S(2)*x + S(-1)) + S(1))/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((p*x + q)/((f + sqrt(a*x + b))*sqrt(a*x + b)), x), x, p*x/a - S(2)*f*p*sqrt(a*x + b)/a**S(2) - (-S(2)*a*q + S(2)*b*p - S(2)*f**S(2)*p)*log(f + sqrt(a*x + b))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-sqrt(x) - x + S(1)), x), x, (-sqrt(x)/S(2) + S(-1)/4)*sqrt(-sqrt(x) - x + S(1)) - S(2)*(-sqrt(x) - x + S(1))**(S(3)/2)/S(3) - S(5)*asin(sqrt(S(5))*(S(2)*sqrt(x) + S(1))/S(5))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(6)*sqrt(x) + x + S(9))/(S(4)*sqrt(x) + x), x), x, S(4)*sqrt(x) + x + S(2)*log(sqrt(x) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(8)*x**(S(7)/2) + S(6))/(-S(9)*sqrt(x) + S(5)), x), x, S(80)*x**(S(7)/2)/S(567) + S(400)*x**(S(5)/2)/S(6561) + S(50000)*x**(S(3)/2)/S(1594323) - S(56145628)*sqrt(x)/S(43046721) + S(2)*x**S(4)/S(9) + S(200)*x**S(3)/S(2187) + S(2500)*x**S(2)/S(59049) + S(125000)*x/S(4782969) - S(280728140)*log(-S(9)*sqrt(x) + S(5))/S(387420489), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x + S(1))*(x**S(3) + S(1))/(x**S(2) + S(1)), x), x, S(2)*(x + S(1))**(S(5)/2)/S(5) - S(2)*(x + S(1))**(S(3)/2)/S(3) - S(2)*sqrt(x + S(1)) + (S(1) - I)**(S(3)/2)*atanh(sqrt(x + S(1))/sqrt(S(1) - I)) + (S(1) + I)**(S(3)/2)*atanh(sqrt(x + S(1))/sqrt(S(1) + I)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(x + S(1))*(x**S(3) + S(1))/(x**S(2) + S(1)), x), x, S(2)*(x + S(1))**(S(5)/2)/S(5) - S(2)*(x + S(1))**(S(3)/2)/S(3) - S(2)*sqrt(x + S(1)) - log(x - sqrt(S(2) + S(2)*sqrt(S(2)))*sqrt(x + S(1)) + S(1) + sqrt(S(2)))/(S(2)*sqrt(S(1) + sqrt(S(2)))) + log(x + sqrt(S(2) + S(2)*sqrt(S(2)))*sqrt(x + S(1)) + S(1) + sqrt(S(2)))/(S(2)*sqrt(S(1) + sqrt(S(2)))) - sqrt(S(1) + sqrt(S(2)))*atan((-S(2)*sqrt(x + S(1)) + sqrt(S(2) + S(2)*sqrt(S(2))))/sqrt(S(-2) + S(2)*sqrt(S(2)))) + sqrt(S(1) + sqrt(S(2)))*atan((S(2)*sqrt(x + S(1)) + sqrt(S(2) + S(2)*sqrt(S(2))))/sqrt(S(-2) + S(2)*sqrt(S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-sqrt(x) + x + S(-1))/(sqrt(x)*(x + S(-1))), x), x, atan((-sqrt(x) + S(3))/(S(2)*sqrt(-sqrt(x) + x + S(-1)))) - S(2)*atanh((-S(2)*sqrt(x) + S(1))/(S(2)*sqrt(-sqrt(x) + x + S(-1)))) - atanh((S(3)*sqrt(x) + S(1))/(S(2)*sqrt(-sqrt(x) + x + S(-1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*sqrt(x + S(1)) + S(1))/(x*sqrt(x + S(1))*sqrt(x + sqrt(x + S(1)))), x), x, -atan((sqrt(x + S(1)) + S(3))/(S(2)*sqrt(x + sqrt(x + S(1))))) + S(3)*atanh((-S(3)*sqrt(x + S(1)) + S(1))/(S(2)*sqrt(x + sqrt(x + S(1))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*sqrt(x + S(1))), x), x, S(2)*asinh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x/(x + S(1)))/x, x), x, S(2)*asinh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/sqrt(x + S(1)), x), x, sqrt(x)*sqrt(x + S(1)) - asinh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x/(x + S(1))), x), x, sqrt(x)*sqrt(x + S(1)) - asinh(sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x + S(-1))/(x**S(2)*sqrt(x + S(1))), x), x, atan(sqrt(x + S(-1))*sqrt(x + S(1))) - sqrt(x + S(-1))*sqrt(x + S(1))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x + S(-1))/(x + S(1)))/x**S(2), x), x, atan(sqrt(x + S(-1))*sqrt(x + S(1))) - sqrt(x + S(-1))*sqrt(x + S(1))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(x + S(-1))/sqrt(x + S(1)), x), x, x**S(2)*(x + S(-1))**(S(3)/2)*sqrt(x + S(1))/S(4) + (-x/S(12) + S(7)/24)*(x + S(-1))**(S(3)/2)*sqrt(x + S(1)) - S(3)*sqrt(x + S(-1))*sqrt(x + S(1))/S(8) + S(3)*acosh(x)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt((x + S(-1))/(x + S(1))), x), x, x**S(2)*(x + S(-1))**(S(3)/2)*sqrt(x + S(1))/S(4) + (-x/S(12) + S(7)/24)*(x + S(-1))**(S(3)/2)*sqrt(x + S(1)) - S(3)*sqrt(x + S(-1))*sqrt(x + S(1))/S(8) + S(3)*acosh(x)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x/(x + S(1)))/x, x), x, S(2)*atan(sqrt(-x/(x + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((-x + S(1))/(x + S(1)))/(x + S(-1)), x), x, S(2)*atan(sqrt((-x + S(1))/(x + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((a + b*x)/(-b*x + c))/(a + b*x), x), x, S(2)*atan(sqrt((a + b*x)/(-b*x + c)))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((a + b*x)/(c + d*x))/(a + b*x), x), x, S(2)*atanh(sqrt(d)*sqrt((a + b*x)/(c + d*x))/sqrt(b))/(sqrt(b)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x/(x + S(1))), x), x, sqrt(-x/(x + S(1)))*(x + S(1)) - atan(sqrt(-x/(x + S(1)))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(-x/(x + S(1))), x), x, sqrt(-x/(x + S(1)))/(-x/(x + S(1)) + S(1)) - atan(sqrt(-x/(x + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((-x + S(1))/(x + S(1))), x), x, sqrt((-x + S(1))/(x + S(1)))*(x + S(1)) - S(2)*atan(sqrt((-x + S(1))/(x + S(1)))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt((-x + S(1))/(x + S(1))), x), x, S(2)*sqrt((-x + S(1))/(x + S(1)))/((-x + S(1))/(x + S(1)) + S(1)) - S(2)*atan(sqrt((-x + S(1))/(x + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((a + x)/(a - x)), x), x, S(2)*a*atan(sqrt((a + x)/(a - x))) - sqrt((a + x)/(a - x))*(a - x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt((a + x)/(a - x)), x), x, -S(2)*a*sqrt((a + x)/(a - x))/(S(1) + (a + x)/(a - x)) + S(2)*a*atan(sqrt((a + x)/(a - x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((-a + x)/(a + x)), x), x, -S(2)*a*atanh(sqrt(-(a - x)/(a + x))) + sqrt(-(a - x)/(a + x))*(a + x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt((-a + x)/(a + x)), x), x, S(2)*a*sqrt(-(a - x)/(a + x))/((a - x)/(a + x) + S(1)) - S(2)*a*atanh(sqrt(-(a - x)/(a + x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((a + b*x)/(c + d*x)), x), x, sqrt((a + b*x)/(c + d*x))*(c + d*x)/d - (-a*d + b*c)*atanh(sqrt(d)*sqrt((a + b*x)/(c + d*x))/sqrt(b))/(sqrt(b)*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt((a + b*x)/(c + d*x)), x), x, sqrt((a + b*x)/(c + d*x))*(-a*d + b*c)/(d*(b - d*(a + b*x)/(c + d*x))) - (-a*d + b*c)*atanh(sqrt(d)*sqrt((a + b*x)/(c + d*x))/sqrt(b))/(sqrt(b)*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x + S(-1))/(S(3)*x + S(5))), x), x, sqrt(x + S(-1))*sqrt(S(3)*x + S(5))/S(3) - S(8)*sqrt(S(3))*asinh(sqrt(S(6))*sqrt(x + S(-1))/S(4))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((S(5)*x + S(-1))/(S(7)*x + S(1)))/x**S(2), x), x, -S(12)*atan(sqrt(S(7)*x + S(1))/sqrt(S(5)*x + S(-1))) - sqrt(S(5)*x + S(-1))*sqrt(S(7)*x + S(1))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt((-x + S(1))/(x + S(1)))*(x + S(1))), x), x, -(-x + S(1))/sqrt((-x + S(1))/(x + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x/(sqrt((-x + S(1))/(x + S(1)))*(x + S(1))), x), x, -S(2)*sqrt((-x + S(1))/(x + S(1)))/((-x + S(1))/(x + S(1)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt(S(-1) + S(2)/(x + S(1)))*(x + S(1))), x), x, -sqrt(S(-1) + S(2)/(x + S(1)))*(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(sqrt((x + S(2))/(x + S(3)))*(x + S(1))), x), x, sqrt(x + S(2))*sqrt(x + S(3)) - asinh(sqrt(x + S(2))) + S(2)*sqrt(S(2))*atanh(sqrt(S(2))*sqrt(x + S(2))/sqrt(x + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(1) + S(1)/x)/(x + S(1))**S(2), x), x, S(2)/sqrt(S(1) + S(1)/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(1) + S(1)/x)/sqrt(-x**S(2) + S(1)), x), x, sqrt(x)*sqrt(S(1) + S(1)/x)*asin(S(2)*x + S(-1))/sqrt(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(a + b*sqrt(c/x)), x), x, S(4)*x**(m + S(1))*(a + b*sqrt(c/x))**(S(3)/2)*hyper((S(1), -S(2)*m + S(-1)/2), (S(5)/2,), (a + b*sqrt(c/x))/a)/(S(3)*a), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**m*sqrt(a + b*sqrt(c/x)), x), x, S(4)*b**S(2)*c*x**m*(-b*sqrt(c/x)/a)**(S(2)*m)*(a + b*sqrt(c/x))**(S(3)/2)*hyper((S(3)/2, S(2)*m + S(3)), (S(5)/2,), S(1) + b*sqrt(c/x)/a)/(S(3)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*sqrt(c/x)), x), x, x**S(2)*sqrt(a + b*sqrt(c/x))/S(2) + b*c**S(2)*sqrt(a + b*sqrt(c/x))/(S(12)*a*(c/x)**(S(3)/2)) - S(5)*b**S(2)*c*x*sqrt(a + b*sqrt(c/x))/(S(48)*a**S(2)) + S(5)*b**S(3)*c**S(2)*sqrt(a + b*sqrt(c/x))/(S(32)*a**S(3)*sqrt(c/x)) - S(5)*b**S(4)*c**S(2)*atanh(sqrt(a + b*sqrt(c/x))/sqrt(a))/(S(32)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c/x)), x), x, x*sqrt(a + b*sqrt(c/x)) + b*c*sqrt(a + b*sqrt(c/x))/(S(2)*a*sqrt(c/x)) - b**S(2)*c*atanh(sqrt(a + b*sqrt(c/x))/sqrt(a))/(S(2)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c/x))/x, x), x, S(4)*sqrt(a)*atanh(sqrt(a + b*sqrt(c/x))/sqrt(a)) - S(4)*sqrt(a + b*sqrt(c/x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c/x))/x**S(2), x), x, S(4)*a*(a + b*sqrt(c/x))**(S(3)/2)/(S(3)*b**S(2)*c) - S(4)*(a + b*sqrt(c/x))**(S(5)/2)/(S(5)*b**S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c/x))/x**S(3), x), x, S(4)*a**S(3)*(a + b*sqrt(c/x))**(S(3)/2)/(S(3)*b**S(4)*c**S(2)) - S(12)*a**S(2)*(a + b*sqrt(c/x))**(S(5)/2)/(S(5)*b**S(4)*c**S(2)) + S(12)*a*(a + b*sqrt(c/x))**(S(7)/2)/(S(7)*b**S(4)*c**S(2)) - S(4)*(a + b*sqrt(c/x))**(S(9)/2)/(S(9)*b**S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(c/x))/x**S(4), x), x, S(4)*a**S(5)*(a + b*sqrt(c/x))**(S(3)/2)/(S(3)*b**S(6)*c**S(3)) - S(4)*a**S(4)*(a + b*sqrt(c/x))**(S(5)/2)/(b**S(6)*c**S(3)) + S(40)*a**S(3)*(a + b*sqrt(c/x))**(S(7)/2)/(S(7)*b**S(6)*c**S(3)) - S(40)*a**S(2)*(a + b*sqrt(c/x))**(S(9)/2)/(S(9)*b**S(6)*c**S(3)) + S(20)*a*(a + b*sqrt(c/x))**(S(11)/2)/(S(11)*b**S(6)*c**S(3)) - S(4)*(a + b*sqrt(c/x))**(S(13)/2)/(S(13)*b**S(6)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/sqrt(a + b*sqrt(c/x)), x), x, S(4)*x**(m + S(1))*sqrt(a + b*sqrt(c/x))*hyper((S(1), -S(2)*m + S(-3)/2), (S(3)/2,), (a + b*sqrt(c/x))/a)/a, expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**m/sqrt(a + b*sqrt(c/x)), x), x, S(4)*b**S(2)*c*x**m*(-b*sqrt(c/x)/a)**(S(2)*m)*sqrt(a + b*sqrt(c/x))*hyper((S(1)/2, S(2)*m + S(3)), (S(3)/2,), S(1) + b*sqrt(c/x)/a)/a**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*sqrt(c/x)), x), x, x**S(2)*sqrt(a + b*sqrt(c/x))/(S(2)*a) - S(7)*b*c**S(2)*sqrt(a + b*sqrt(c/x))/(S(12)*a**S(2)*(c/x)**(S(3)/2)) + S(35)*b**S(2)*c*x*sqrt(a + b*sqrt(c/x))/(S(48)*a**S(3)) - S(35)*b**S(3)*c**S(2)*sqrt(a + b*sqrt(c/x))/(S(32)*a**S(4)*sqrt(c/x)) + S(35)*b**S(4)*c**S(2)*atanh(sqrt(a + b*sqrt(c/x))/sqrt(a))/(S(32)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*sqrt(c/x)), x), x, x*sqrt(a + b*sqrt(c/x))/a - S(3)*b*c*sqrt(a + b*sqrt(c/x))/(S(2)*a**S(2)*sqrt(c/x)) + S(3)*b**S(2)*c*atanh(sqrt(a + b*sqrt(c/x))/sqrt(a))/(S(2)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*sqrt(c/x))), x), x, S(4)*atanh(sqrt(a + b*sqrt(c/x))/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*sqrt(c/x))), x), x, S(4)*a*sqrt(a + b*sqrt(c/x))/(b**S(2)*c) - S(4)*(a + b*sqrt(c/x))**(S(3)/2)/(S(3)*b**S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + b*sqrt(c/x))), x), x, S(4)*a**S(3)*sqrt(a + b*sqrt(c/x))/(b**S(4)*c**S(2)) - S(4)*a**S(2)*(a + b*sqrt(c/x))**(S(3)/2)/(b**S(4)*c**S(2)) + S(12)*a*(a + b*sqrt(c/x))**(S(5)/2)/(S(5)*b**S(4)*c**S(2)) - S(4)*(a + b*sqrt(c/x))**(S(7)/2)/(S(7)*b**S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a + b*sqrt(c/x))), x), x, S(4)*a**S(5)*sqrt(a + b*sqrt(c/x))/(b**S(6)*c**S(3)) - S(20)*a**S(4)*(a + b*sqrt(c/x))**(S(3)/2)/(S(3)*b**S(6)*c**S(3)) + S(8)*a**S(3)*(a + b*sqrt(c/x))**(S(5)/2)/(b**S(6)*c**S(3)) - S(40)*a**S(2)*(a + b*sqrt(c/x))**(S(7)/2)/(S(7)*b**S(6)*c**S(3)) + S(20)*a*(a + b*sqrt(c/x))**(S(9)/2)/(S(9)*b**S(6)*c**S(3)) - S(4)*(a + b*sqrt(c/x))**(S(11)/2)/(S(11)*b**S(6)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sqrt(S(1)/x) + S(1)), x), x, x*sqrt(sqrt(S(1)/x) + S(1)) - S(3)*sqrt(sqrt(S(1)/x) + S(1))/(S(2)*sqrt(S(1)/x)) + S(3)*atanh(sqrt(sqrt(S(1)/x) + S(1)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(a + b*sqrt(d/x) + c/x), x), x, x**(m + S(1))*sqrt(a + b*sqrt(d/x) + c/x)*AppellF1(-S(2)*m + S(-2), S(-1)/2, S(-1)/2, -S(2)*m + S(-1), -S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) - sqrt(-S(4)*a*c + b**S(2)*d))), -S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) + sqrt(-S(4)*a*c + b**S(2)*d))))/((m + S(1))*sqrt(S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) - sqrt(-S(4)*a*c + b**S(2)*d))) + S(1))*sqrt(S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) + sqrt(-S(4)*a*c + b**S(2)*d))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a + b*sqrt(d/x) + c/x), x), x, x**S(3)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(3)*a) - S(3)*b*d**S(3)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(10)*a**S(2)*(d/x)**(S(5)/2)) - x**S(2)*(S(20)*a*c - S(21)*b**S(2)*d)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(80)*a**S(3)) + S(7)*b*d**S(2)*(S(28)*a*c - S(15)*b**S(2)*d)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(480)*a**S(4)*(d/x)**(S(3)/2)) + x*(S(2)*a + b*sqrt(d/x))*sqrt(a + b*sqrt(d/x) + c/x)*(S(16)*a**S(2)*c**S(2) - S(56)*a*b**S(2)*c*d + S(21)*b**S(4)*d**S(2))/(S(256)*a**S(5)) + (S(4)*a*c - b**S(2)*d)*(S(16)*a**S(2)*c**S(2) - S(56)*a*b**S(2)*c*d + S(21)*b**S(4)*d**S(2))*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(512)*a**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*sqrt(d/x) + c/x), x), x, x**S(2)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(2)*a) - S(5)*b*d**S(2)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(12)*a**S(2)*(d/x)**(S(3)/2)) - x*(S(2)*a + b*sqrt(d/x))*(S(4)*a*c - S(5)*b**S(2)*d)*sqrt(a + b*sqrt(d/x) + c/x)/(S(32)*a**S(3)) - (S(4)*a*c - S(5)*b**S(2)*d)*(S(4)*a*c - b**S(2)*d)*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(64)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(d/x) + c/x), x), x, x*(S(2)*a + b*sqrt(d/x))*sqrt(a + b*sqrt(d/x) + c/x)/(S(2)*a) + (S(4)*a*c - b**S(2)*d)*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(4)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(d/x) + c/x)/x, x), x, S(2)*sqrt(a)*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x))) - b*sqrt(d)*atanh((b*d + S(2)*c*sqrt(d/x))/(S(2)*sqrt(c)*sqrt(d)*sqrt(a + b*sqrt(d/x) + c/x)))/sqrt(c) - S(2)*sqrt(a + b*sqrt(d/x) + c/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(d/x) + c/x)/x**S(2), x), x, b*(b*d + S(2)*c*sqrt(d/x))*sqrt(a + b*sqrt(d/x) + c/x)/(S(4)*c**S(2)) + b*sqrt(d)*(S(4)*a*c - b**S(2)*d)*atanh((b*d + S(2)*c*sqrt(d/x))/(S(2)*sqrt(c)*sqrt(d)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(8)*c**(S(5)/2)) - S(2)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(d/x) + c/x)/x**S(3), x), x, -b*(S(12)*a*c - S(7)*b**S(2)*d)*(b*d + S(2)*c*sqrt(d/x))*sqrt(a + b*sqrt(d/x) + c/x)/(S(64)*c**S(4)) - b*sqrt(d)*(S(4)*a*c - b**S(2)*d)*(S(12)*a*c - S(7)*b**S(2)*d)*atanh((b*d + S(2)*c*sqrt(d/x))/(S(2)*sqrt(c)*sqrt(d)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(128)*c**(S(9)/2)) - S(2)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(5)*c*x) + (a + b*sqrt(d/x) + c/x)**(S(3)/2)*(S(32)*a*c - S(35)*b**S(2)*d + S(42)*b*c*sqrt(d/x))/(S(120)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(d/x) + c/x)/x**S(4), x), x, S(11)*b*(d/x)**(S(3)/2)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(42)*c**S(2)*d) + b*(b*d + S(2)*c*sqrt(d/x))*sqrt(a + b*sqrt(d/x) + c/x)*(S(80)*a**S(2)*c**S(2) - S(120)*a*b**S(2)*c*d + S(33)*b**S(4)*d**S(2))/(S(512)*c**S(6)) + b*sqrt(d)*(S(4)*a*c - b**S(2)*d)*(S(80)*a**S(2)*c**S(2) - S(120)*a*b**S(2)*c*d + S(33)*b**S(4)*d**S(2))*atanh((b*d + S(2)*c*sqrt(d/x))/(S(2)*sqrt(c)*sqrt(d)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(1024)*c**(S(13)/2)) - S(2)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(7)*c*x**S(2)) + (S(32)*a*c - S(33)*b**S(2)*d)*(a + b*sqrt(d/x) + c/x)**(S(3)/2)/(S(140)*c**S(3)*x) - (a + b*sqrt(d/x) + c/x)**(S(3)/2)*(S(1024)*a**S(2)*c**S(2) - S(3276)*a*b**S(2)*c*d + S(1155)*b**S(4)*d**S(2) + S(18)*b*c*sqrt(d/x)*(S(148)*a*c - S(77)*b**S(2)*d))/(S(6720)*c**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/sqrt(a + b*sqrt(d/x) + c/x), x), x, x**(m + S(1))*sqrt(S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) - sqrt(-S(4)*a*c + b**S(2)*d))) + S(1))*sqrt(S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) + sqrt(-S(4)*a*c + b**S(2)*d))) + S(1))*AppellF1(-S(2)*m + S(-2), S(1)/2, S(1)/2, -S(2)*m + S(-1), -S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) - sqrt(-S(4)*a*c + b**S(2)*d))), -S(2)*c*sqrt(d/x)/(sqrt(d)*(b*sqrt(d) + sqrt(-S(4)*a*c + b**S(2)*d))))/((m + S(1))*sqrt(a + b*sqrt(d/x) + c/x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*sqrt(d/x) + c/x), x), x, x**S(3)*sqrt(a + b*sqrt(d/x) + c/x)/(S(3)*a) - S(11)*b*d**S(3)*sqrt(a + b*sqrt(d/x) + c/x)/(S(30)*a**S(2)*(d/x)**(S(5)/2)) - x**S(2)*(S(100)*a*c - S(99)*b**S(2)*d)*sqrt(a + b*sqrt(d/x) + c/x)/(S(240)*a**S(3)) + b*d**S(2)*(S(156)*a*c - S(77)*b**S(2)*d)*sqrt(a + b*sqrt(d/x) + c/x)/(S(160)*a**S(4)*(d/x)**(S(3)/2)) + x*sqrt(a + b*sqrt(d/x) + c/x)*(S(400)*a**S(2)*c**S(2) - S(1176)*a*b**S(2)*c*d + S(385)*b**S(4)*d**S(2))/(S(640)*a**S(5)) - S(7)*b*d*sqrt(a + b*sqrt(d/x) + c/x)*(S(528)*a**S(2)*c**S(2) - S(680)*a*b**S(2)*c*d + S(165)*b**S(4)*d**S(2))/(S(1280)*a**S(6)*sqrt(d/x)) - (S(320)*a**S(3)*c**S(3) - S(1680)*a**S(2)*b**S(2)*c**S(2)*d + S(1260)*a*b**S(4)*c*d**S(2) - S(231)*b**S(6)*d**S(3))*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(512)*a**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*sqrt(d/x) + c/x), x), x, x**S(2)*sqrt(a + b*sqrt(d/x) + c/x)/(S(2)*a) - S(7)*b*d**S(2)*sqrt(a + b*sqrt(d/x) + c/x)/(S(12)*a**S(2)*(d/x)**(S(3)/2)) - x*(S(36)*a*c - S(35)*b**S(2)*d)*sqrt(a + b*sqrt(d/x) + c/x)/(S(48)*a**S(3)) + S(5)*b*d*(S(44)*a*c - S(21)*b**S(2)*d)*sqrt(a + b*sqrt(d/x) + c/x)/(S(96)*a**S(4)*sqrt(d/x)) + (S(48)*a**S(2)*c**S(2) - S(120)*a*b**S(2)*c*d + S(35)*b**S(4)*d**S(2))*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(64)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*sqrt(d/x) + c/x), x), x, x*sqrt(a + b*sqrt(d/x) + c/x)/a - S(3)*b*d*sqrt(a + b*sqrt(d/x) + c/x)/(S(2)*a**S(2)*sqrt(d/x)) - (S(4)*a*c - S(3)*b**S(2)*d)*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(4)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*sqrt(d/x) + c/x)), x), x, S(2)*atanh((S(2)*a + b*sqrt(d/x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(d/x) + c/x)))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*sqrt(d/x) + c/x)), x), x, b*sqrt(d)*atanh((b*d + S(2)*c*sqrt(d/x))/(S(2)*sqrt(c)*sqrt(d)*sqrt(a + b*sqrt(d/x) + c/x)))/c**(S(3)/2) - S(2)*sqrt(a + b*sqrt(d/x) + c/x)/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + b*sqrt(d/x) + c/x)), x), x, -b*sqrt(d)*(S(12)*a*c - S(5)*b**S(2)*d)*atanh((b*d + S(2)*c*sqrt(d/x))/(S(2)*sqrt(c)*sqrt(d)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(8)*c**(S(7)/2)) - S(2)*sqrt(a + b*sqrt(d/x) + c/x)/(S(3)*c*x) + sqrt(a + b*sqrt(d/x) + c/x)*(S(16)*a*c - S(15)*b**S(2)*d + S(10)*b*c*sqrt(d/x))/(S(12)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a + b*sqrt(d/x) + c/x)), x), x, S(9)*b*(d/x)**(S(3)/2)*sqrt(a + b*sqrt(d/x) + c/x)/(S(20)*c**S(2)*d) + b*sqrt(d)*(S(240)*a**S(2)*c**S(2) - S(280)*a*b**S(2)*c*d + S(63)*b**S(4)*d**S(2))*atanh((b*d + S(2)*c*sqrt(d/x))/(S(2)*sqrt(c)*sqrt(d)*sqrt(a + b*sqrt(d/x) + c/x)))/(S(128)*c**(S(11)/2)) - S(2)*sqrt(a + b*sqrt(d/x) + c/x)/(S(5)*c*x**S(2)) + (S(64)*a*c - S(63)*b**S(2)*d)*sqrt(a + b*sqrt(d/x) + c/x)/(S(120)*c**S(3)*x) - sqrt(a + b*sqrt(d/x) + c/x)*(S(1024)*a**S(2)*c**S(2) - S(2940)*a*b**S(2)*c*d + S(945)*b**S(4)*d**S(2) + S(14)*b*c*sqrt(d/x)*(S(92)*a*c - S(45)*b**S(2)*d))/(S(960)*c**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(S(1)/x) + S(1)/x), x), x, S(4)*(sqrt(S(1)/x) + S(1)/x)**(S(3)/2)/(S(3)*(S(1)/x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sqrt(S(1)/x) + S(2) + S(1)/x), x), x, x*(sqrt(S(1)/x)/S(4) + S(1))*sqrt(sqrt(S(1)/x) + S(2) + S(1)/x) + S(7)*sqrt(S(2))*atanh(sqrt(S(2))*(sqrt(S(1)/x) + S(4))/(S(4)*sqrt(sqrt(S(1)/x) + S(2) + S(1)/x)))/S(16), expand=True, _diff=True, _numerical=True) # difference in simplify assert rubi_test(rubi_integrate(S(1)/(x + sqrt(-x**S(2) - S(2)*x + S(3))), x), x, -log(-(-x - sqrt(S(3))*sqrt(-x**S(2) - S(2)*x + S(3)) + S(3))/x**S(2))/S(2) + (-sqrt(S(7))/S(14) + S(1)/2)*log(S(1) + sqrt(S(3)) + sqrt(S(7)) - sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x) + (sqrt(S(7))/S(14) + S(1)/2)*log(-sqrt(S(7)) + S(1) + sqrt(S(3)) - sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x) + atan((-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(-x**S(2) - S(2)*x + S(3)))**(S(-2)), x), x, (-S(2)*sqrt(S(3)) + S(8) + S(2)*(-S(3)*sqrt(-x**S(2) - S(2)*x + S(3)) + S(3)*sqrt(S(3)))/x)/(-S(7)*sqrt(S(3)) + S(14) - S(7)*(S(2) + S(2)*sqrt(S(3)))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x + S(7)*sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))**S(2)/x**S(2)) - S(8)*sqrt(S(7))*atanh(sqrt(S(7))*(S(1) + sqrt(S(3)) - sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x)/S(7))/S(49), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(-x**S(2) - S(2)*x + S(3)))**(S(-3)), x), x, S(4)*sqrt(S(3))*(S(1) + sqrt(S(3)) - sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x)/(-S(49)*sqrt(S(3)) + S(98) - S(49)*(S(2) + S(2)*sqrt(S(3)))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x + S(49)*sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))**S(2)/x**S(2)) - sqrt(S(3))*(-S(2)*sqrt(S(3)) + S(8) + S(2)*(-S(7)*sqrt(S(3)) + S(10))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x)/(S(21)*(-sqrt(S(3)) + S(2) - (S(2) + S(2)*sqrt(S(3)))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x + sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))**S(2)/x**S(2))**S(2)) - S(12)*sqrt(S(7))*atanh(sqrt(S(7))*(S(1) + sqrt(S(3)) - sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x)/S(7))/S(343) + (S(6) + S(4)*sqrt(S(3)))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))**S(2)/(S(3)*x**S(2)*(-sqrt(S(3)) + S(2) - (S(2) + S(2)*sqrt(S(3)))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x + sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))**S(2)/x**S(2))**S(2)) - S(2)*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))**S(3)/(x**S(3)*(-sqrt(S(3)) + S(2) - (S(2) + S(2)*sqrt(S(3)))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))/x + sqrt(S(3))*(-sqrt(-x**S(2) - S(2)*x + S(3)) + sqrt(S(3)))**S(2)/x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x + sqrt(x**S(2) - S(2)*x + S(-3))), x), x, -S(3)*log(x + sqrt(x**S(2) - S(2)*x + S(-3)))/S(2) + S(2)*log(-x - sqrt(x**S(2) - S(2)*x + S(-3)) + S(1)) - S(2)/(-x - sqrt(x**S(2) - S(2)*x + S(-3)) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(x**S(2) - S(2)*x + S(-3)))**(S(-2)), x), x, -S(4)*log(x + sqrt(x**S(2) - S(2)*x + S(-3))) + S(4)*log(-x - sqrt(x**S(2) - S(2)*x + S(-3)) + S(1)) - S(2)/(-x - sqrt(x**S(2) - S(2)*x + S(-3)) + S(1)) + S(3)/(S(2)*x + S(2)*sqrt(x**S(2) - S(2)*x + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(x**S(2) - S(2)*x + S(-3)))**(S(-3)), x), x, -S(6)*log(x + sqrt(x**S(2) - S(2)*x + S(-3))) + S(6)*log(-x - sqrt(x**S(2) - S(2)*x + S(-3)) + S(1)) - S(2)/(-x - sqrt(x**S(2) - S(2)*x + S(-3)) + S(1)) + S(4)/(x + sqrt(x**S(2) - S(2)*x + S(-3))) + S(3)/(S(4)*(x + sqrt(x**S(2) - S(2)*x + S(-3)))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x + sqrt(-x**S(2) - S(4)*x + S(-3))), x), x, log((x*sqrt(-x + S(-1)) + x*sqrt(x + S(3)) + S(3)*sqrt(-x + S(-1)))/(x + S(3))**(S(3)/2))/S(2) - log(S(1)/(x + S(3)))/S(2) - sqrt(S(2))*atan(sqrt(S(2))*(-S(3)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(1))/S(2)) - atan(sqrt(-x + S(-1))/sqrt(x + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(-x**S(2) - S(4)*x + S(-3)))**(S(-2)), x), x, (-sqrt(-x + S(-1))/sqrt(x + S(3)) + S(1))/(-S(2)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(1) - (S(3)*x + S(3))/(x + S(3))) + sqrt(S(2))*atan(sqrt(S(2))*(-S(3)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(1))/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + sqrt(-x**S(2) - S(4)*x + S(-3)))**(S(-3)), x), x, -(-S(9)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(5))/(-S(18)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(9) - S(9)*(S(3)*x + S(3))/(x + S(3))) - (-S(3)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(1))/(-S(12)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(6) - S(6)*(S(3)*x + S(3))/(x + S(3))) - (-S(2)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(4))/(S(9)*(-S(2)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(1) - (S(3)*x + S(3))/(x + S(3)))**S(2)) - S(3)*sqrt(S(2))*atan(sqrt(S(2))*(-S(3)*sqrt(-x + S(-1))/sqrt(x + S(3)) + S(1))/S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(x + S(1))**S(3)*(S(2)*x + S(1))*sqrt(-x**S(4) - S(2)*x**S(3) - x**S(2) + S(1)), x), x, -(-x**S(4) - S(2)*x**S(3) - x**S(2) + S(1))**(S(3)/2)*(S(3)*x**S(4) + S(6)*x**S(3) + S(3)*x**S(2) + S(2))/S(15), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(3)*(x + S(1))**S(3)*(S(2)*x + S(1))*sqrt(-x**S(4) - S(2)*x**S(3) - x**S(2) + S(1)), x), x, -(-S(4)*(x + S(1)/2)**S(2) + S(1))**S(2)*(-S(16)*(x + S(1)/2)**S(4) + S(8)*(x + S(1)/2)**S(2) + S(15))**(S(3)/2)/S(5120) - (-S(16)*(x + S(1)/2)**S(4) + S(8)*(x + S(1)/2)**S(2) + S(15))**(S(3)/2)/S(480), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x + S(1))*(x**S(2) + x)**S(3)*sqrt(-(x**S(2) + x)**S(2) + S(1)), x), x, -(-x**S(4) - S(2)*x**S(3) - x**S(2) + S(1))**(S(3)/2)*(S(3)*x**S(4) + S(6)*x**S(3) + S(3)*x**S(2) + S(2))/S(15), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((S(2)*x + S(1))*(x**S(2) + x)**S(3)*sqrt(-(x**S(2) + x)**S(2) + S(1)), x), x, -(-S(4)*(x + S(1)/2)**S(2) + S(1))**S(2)*(-S(16)*(x + S(1)/2)**S(4) + S(8)*(x + S(1)/2)**S(2) + S(15))**(S(3)/2)/S(5120) - (-S(16)*(x + S(1)/2)**S(4) + S(8)*(x + S(1)/2)**S(2) + S(15))**(S(3)/2)/S(480), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(3)*x**S(2) + S(3)*x)/(x**S(4) + S(4)*x**S(3) + S(6)*x**S(2) + S(4)*x + S(1)), x), x, log(x + S(1)) + S(1)/(S(3)*(x + S(1))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(3)*x**S(2) + S(3)*x + S(-1))/(x**S(4) + S(4)*x**S(3) + S(6)*x**S(2) + S(4)*x + S(1)), x), x, log(x + S(1)) + S(6)/(x + S(1)) - S(6)/(x + S(1))**S(2) + S(8)/(S(3)*(x + S(1))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(3)/2), x), x, (x + S(-1))*(-S(6)*(x + S(-1))**S(2)/S(35) + S(26)/35)*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + (x + S(-1))*(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2)/S(7) - S(16)*sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(5) + S(176)*sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(35), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, (x + S(-1))*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))/S(3) - S(2)*sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(3) + S(4)*sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(-3)/2), x), x, (x + S(-1))*((x + S(-1))**S(2) + S(5))/(S(24)*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) - sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(24) + sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(-5)/2), x), x, (x + S(-1))*((x + S(-1))**S(2) + S(5))/(S(72)*(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2)) + (x + S(-1))*(S(7)*(x + S(-1))**S(2) + S(26))/(S(432)*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) - S(7)*sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(432) + S(11)*sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(432), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x*(-x + S(2))*(x**S(2) - S(2)*x + S(4)))**(S(3)/2), x), x, (x + S(-1))*(-S(6)*(x + S(-1))**S(2)/S(35) + S(26)/35)*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + (x + S(-1))*(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2)/S(7) - S(16)*sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(5) + S(176)*sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(35), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x*(-x + S(2))*(x**S(2) - S(2)*x + S(4))), x), x, (x + S(-1))*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))/S(3) - S(2)*sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(3) + S(4)*sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x*(-x + S(2))*(x**S(2) - S(2)*x + S(4))), x), x, sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x*(-x + S(2))*(x**S(2) - S(2)*x + S(4)))**(S(-3)/2), x), x, (x + S(-1))*((x + S(-1))**S(2) + S(5))/(S(24)*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) - sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(24) + sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x*(-x + S(2))*(x**S(2) - S(2)*x + S(4)))**(S(-5)/2), x), x, (x + S(-1))*((x + S(-1))**S(2) + S(5))/(S(72)*(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2)) + (x + S(-1))*(S(7)*(x + S(-1))**S(2) + S(26))/(S(432)*sqrt(-(x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) - S(7)*sqrt(S(3))*elliptic_e(asin(x + S(-1)), S(-1)/3)/S(432) + S(11)*sqrt(S(3))*elliptic_f(asin(x + S(-1)), S(-1)/3)/S(432), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4))**S(4), x), x, -S(8)*c**S(5)*(S(4)*a*d**S(2) + c**S(3))**S(3)*(c/d + x)**S(3)/(S(3)*d**S(6)) - S(8)*c**S(4)*(S(4)*a*d**S(2) + c**S(3))*(S(12)*a*d**S(2) + S(7)*c**S(3))*(c/d + x)**S(7)/(S(7)*d**S(2)) + c**S(4)*x*(S(4)*a*d**S(2) + c**S(3))**S(4)/d**S(8) - S(8)*c**S(3)*d**S(2)*(S(12)*a*d**S(2) + S(7)*c**S(3))*(c/d + x)**S(11)/S(11) + S(4)*c**S(3)*(S(4)*a*d**S(2) + c**S(3))**S(2)*(S(4)*a*d**S(2) + S(7)*c**S(3))*(c/d + x)**S(5)/(S(5)*d**S(4)) - S(8)*c**S(2)*d**S(6)*(c/d + x)**S(15)/S(15) + S(2)*c**S(2)*(c/d + x)**S(9)*(S(48)*a**S(2)*d**S(4) + S(120)*a*c**S(3)*d**S(2) + S(35)*c**S(6))/S(9) + S(4)*c*d**S(4)*(S(4)*a*d**S(2) + S(7)*c**S(3))*(c/d + x)**S(13)/S(13) + d**S(8)*(c/d + x)**S(17)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4))**S(3), x), x, S(64)*a**S(3)*c**S(3)*x + S(64)*a**S(2)*c**S(4)*x**S(3) + S(48)*a**S(2)*c**S(3)*d*x**S(4) + S(64)*a*c**S(4)*d*x**S(6) + S(48)*a*c**S(2)*x**S(5)*(a*d**S(2) + S(4)*c**S(3))/S(5) + S(16)*c**S(3)*d**S(3)*x**S(10) + S(32)*c**S(3)*x**S(7)*(S(9)*a*d**S(2) + S(2)*c**S(3))/S(7) + S(60)*c**S(2)*d**S(4)*x**S(11)/S(11) + S(12)*c**S(2)*d*x**S(8)*(a*d**S(2) + S(2)*c**S(3)) + c*d**S(5)*x**S(12) + S(4)*c*d**S(2)*x**S(9)*(a*d**S(2) + S(20)*c**S(3))/S(3) + d**S(6)*x**S(13)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4))**S(2), x), x, S(16)*a**S(2)*c**S(2)*x + S(32)*a*c**S(3)*x**S(3)/S(3) + S(8)*a*c**S(2)*d*x**S(4) + S(16)*c**S(3)*d*x**S(6)/S(3) + S(24)*c**S(2)*d**S(2)*x**S(7)/S(7) + c*d**S(3)*x**S(8) + S(8)*c*x**S(5)*(a*d**S(2) + S(2)*c**S(3))/S(5) + d**S(4)*x**S(9)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4), x), x, S(4)*a*c*x + S(4)*c**S(2)*x**S(3)/S(3) + c*d*x**S(4) + d**S(2)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4)), x), x, -atanh(d*(c/d + x)/(c**(S(1)/4)*sqrt(c**(S(3)/2) + S(2)*d*sqrt(-a))))/(S(4)*c**(S(3)/4)*sqrt(-a)*sqrt(c**(S(3)/2) + S(2)*d*sqrt(-a))) + atanh(d*(c/d + x)/(c**(S(1)/4)*sqrt(c**(S(3)/2) - S(2)*d*sqrt(-a))))/(S(4)*c**(S(3)/4)*sqrt(-a)*sqrt(c**(S(3)/2) - S(2)*d*sqrt(-a))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4))**(S(-2)), x), x, (S(6)*a*d**S(2) + c**(S(3)/2)*d*sqrt(-a) + c**S(3))*atanh(d*(c/d + x)/(c**(S(1)/4)*sqrt(c**(S(3)/2) + S(2)*d*sqrt(-a))))/(S(32)*c**(S(7)/4)*(-a)**(S(3)/2)*sqrt(c**(S(3)/2) + S(2)*d*sqrt(-a))*(S(4)*a*d**S(2) + c**S(3))) - (S(6)*a*d**S(2) - c**(S(3)/2)*d*sqrt(-a) + c**S(3))*atanh(d*(c/d + x)/(c**(S(1)/4)*sqrt(c**(S(3)/2) - S(2)*d*sqrt(-a))))/(S(32)*c**(S(7)/4)*(-a)**(S(3)/2)*sqrt(c**(S(3)/2) - S(2)*d*sqrt(-a))*(S(4)*a*d**S(2) + c**S(3))) - (c/d + x)*(-S(4)*a*d**S(2) + c**S(3) - c*d**S(2)*(c/d + x)**S(2))/(S(16)*a*c*(S(4)*a*d**S(2) + c**S(3))*(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4))**(S(3)/2), x), x, S(16)*c**(S(13)/4)*sqrt((-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/((S(4)*a + c**S(3)/d**S(2))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))**S(2)))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*(S(4)*a*d**S(2) + c**S(3))**(S(3)/4)*(S(8)*a*d**S(2) + c**S(3))*elliptic_e(S(2)*atan(d*(c/d + x)/(c**(S(1)/4)*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4))), c**(S(3)/2)/(S(2)*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(1)/2)/(S(35)*d**S(5)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))) + S(8)*c**(S(7)/4)*sqrt((-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/((S(4)*a + c**S(3)/d**S(2))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))**S(2)))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*(S(4)*a*d**S(2) + c**S(3))**(S(3)/4)*(-c**(S(3)/2)*(S(8)*a*d**S(2) + c**S(3)) + sqrt(S(4)*a*d**S(2) + c**S(3))*(S(5)*a*d**S(2) + c**S(3)))*elliptic_f(S(2)*atan(d*(c/d + x)/(c**(S(1)/4)*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4))), c**(S(3)/2)/(S(2)*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(1)/2)/(S(35)*d**S(5)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))) - S(16)*c**S(3)*(S(8)*a*d**S(2) + c**S(3))*(c/d + x)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/(S(35)*d**S(2)*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(2)*c*(c/d + x)*(S(20)*a*d**S(2) + S(7)*c**S(3) - S(3)*c*d**S(2)*(c/d + x)**S(2))*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/(S(35)*d**S(2)) + (c/(S(7)*d) + x/S(7))*(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4)), x), x, S(2)*c**(S(9)/4)*sqrt((-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/((S(4)*a + c**S(3)/d**S(2))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))**S(2)))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*(S(4)*a*d**S(2) + c**S(3))**(S(3)/4)*elliptic_e(S(2)*atan(d*(c/d + x)/(c**(S(1)/4)*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4))), c**(S(3)/2)/(S(2)*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(1)/2)/(S(3)*d**S(3)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))) + c**(S(3)/4)*sqrt((-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/((S(4)*a + c**S(3)/d**S(2))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))**S(2)))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4)*(S(4)*a*d**S(2) - c**(S(3)/2)*sqrt(S(4)*a*d**S(2) + c**S(3)) + c**S(3))*elliptic_f(S(2)*atan(d*(c/d + x)/(c**(S(1)/4)*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4))), c**(S(3)/2)/(S(2)*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(1)/2)/(S(3)*d**S(3)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))) - S(2)*c**S(2)*(c/d + x)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/(S(3)*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*sqrt(S(4)*a*d**S(2) + c**S(3))) + (c/(S(3)*d) + x/S(3))*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4)), x), x, sqrt((-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/((S(4)*a + c**S(3)/d**S(2))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))**S(2)))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4)*elliptic_f(S(2)*atan(d*(c/d + x)/(c**(S(1)/4)*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4))), c**(S(3)/2)/(S(2)*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(1)/2)/(S(2)*c**(S(1)/4)*d*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*a*c + S(4)*c**S(2)*x**S(2) + S(4)*c*d*x**S(3) + d**S(2)*x**S(4))**(S(-3)/2), x), x, c**(S(1)/4)*sqrt((-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/((S(4)*a + c**S(3)/d**S(2))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))**S(2)))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*elliptic_e(S(2)*atan(d*(c/d + x)/(c**(S(1)/4)*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4))), c**(S(3)/2)/(S(2)*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(1)/2)/(S(8)*a*d*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))) - d**S(2)*(c/d + x)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/(S(8)*a*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*(S(4)*a*d**S(2) + c**S(3))**(S(3)/2)) - (c/d + x)*(-S(4)*a*d**S(2) + c**S(3) - c*d**S(2)*(c/d + x)**S(2))/(S(8)*a*c*(S(4)*a*d**S(2) + c**S(3))*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))) + sqrt((-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))/((S(4)*a + c**S(3)/d**S(2))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))**S(2)))*(sqrt(c) + d**S(2)*(c/d + x)**S(2)/sqrt(S(4)*a*d**S(2) + c**S(3)))*(S(4)*a*d**S(2) - c**(S(3)/2)*sqrt(S(4)*a*d**S(2) + c**S(3)) + c**S(3))*elliptic_f(S(2)*atan(d*(c/d + x)/(c**(S(1)/4)*(S(4)*a*d**S(2) + c**S(3))**(S(1)/4))), c**(S(3)/2)/(S(2)*sqrt(S(4)*a*d**S(2) + c**S(3))) + S(1)/2)/(S(16)*a*c**(S(5)/4)*d*(S(4)*a*d**S(2) + c**S(3))**(S(3)/4)*sqrt(-S(2)*c**S(2)*(c/d + x)**S(2) + c*(S(4)*a + c**S(3)/d**S(2)) + d**S(2)*(c/d + x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4))**S(4), x), x, -S(2048)*d**S(2)*e**S(10)*(d/(S(4)*e) + x)**S(15)/S(5) - S(72)*d**S(2)*e**S(6)*(S(256)*a*e**S(3) + S(17)*d**S(4))*(d/(S(4)*e) + x)**S(11)/S(11) - S(9)*d**S(2)*e**S(2)*(d/(S(4)*e) + x)**S(7)*(S(65536)*a**S(2)*e**S(6) + S(5632)*a*d**S(4)*e**S(3) + S(85)*d**S(8))/S(224) - d**S(2)*(S(256)*a*e**S(3) + S(5)*d**S(4))**S(3)*(d/(S(4)*e) + x)**S(3)/(S(8192)*e**S(2)) + S(4096)*e**S(12)*(d/(S(4)*e) + x)**S(17)/S(17) + S(64)*e**S(8)*(S(256)*a*e**S(3) + S(59)*d**S(4))*(d/(S(4)*e) + x)**S(13)/S(13) + e**S(4)*(d/(S(4)*e) + x)**S(9)*(S(65536)*a**S(2)*e**S(6) + S(20992)*a*d**S(4)*e**S(3) + S(601)*d**S(8))/S(24) + (S(256)*a*e**S(3) + S(5)*d**S(4))**S(2)*(S(256)*a*e**S(3) + S(59)*d**S(4))*(d/(S(4)*e) + x)**S(5)/S(5120) + x*(S(256)*a*e**S(3) + S(5)*d**S(4))**S(4)/(S(1048576)*e**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4))**S(3), x), x, S(512)*a**S(3)*e**S(6)*x - S(96)*a**S(2)*d**S(3)*e**S(4)*x**S(2) + S(8)*a*d**S(6)*e**S(2)*x**S(3) - S(384)*a*e**S(4)*x**S(5)*(-S(4)*a*e**S(3) + d**S(4))/S(5) + S(32)*d**S(3)*e**S(6)*x**S(10) + S(4)*d**S(3)*e**S(2)*x**S(6)*(-S(16)*a*e**S(3) + d**S(4)) + S(1536)*d**S(2)*e**S(7)*x**S(11)/S(11) + S(24)*d**S(2)*e**S(3)*x**S(7)*(S(64)*a*e**S(3) + d**S(4))/S(7) + S(128)*d*e**S(8)*x**S(12) - S(24)*d*e**S(4)*x**S(8)*(-S(16)*a*e**S(3) + d**S(4)) - d*x**S(4)*(-S(1536)*a**S(2)*e**S(6) + d**S(8))/S(4) + S(512)*e**S(9)*x**S(13)/S(13) - S(128)*e**S(5)*x**S(9)*(-S(4)*a*e**S(3) + d**S(4))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4))**S(2), x), x, S(64)*a**S(2)*e**S(4)*x - S(8)*a*d**S(3)*e**S(2)*x**S(2) + S(32)*a*d*e**S(4)*x**S(4) + d**S(6)*x**S(3)/S(3) - S(8)*d**S(3)*e**S(3)*x**S(6)/S(3) + S(64)*d**S(2)*e**S(4)*x**S(7)/S(7) + S(16)*d*e**S(5)*x**S(8) + S(64)*e**S(6)*x**S(9)/S(9) - S(16)*e**S(2)*x**S(5)*(-S(8)*a*e**S(3) + d**S(4))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4), x), x, S(8)*a*e**S(2)*x - d**S(3)*x**S(2)/S(2) + S(2)*d*e**S(2)*x**S(4) + S(8)*e**S(3)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4)), x), x, -S(2)*atanh(S(4)*e*(d/(S(4)*e) + x)/sqrt(S(3)*d**S(2) + S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4))))/(sqrt(S(3)*d**S(2) + S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4)))*sqrt(-S(64)*a*e**S(3) + d**S(4))) + S(2)*atanh(S(4)*e*(d/(S(4)*e) + x)/sqrt(S(3)*d**S(2) - S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4))))/(sqrt(S(3)*d**S(2) - S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4)))*sqrt(-S(64)*a*e**S(3) + d**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4))**(S(-2)), x), x, S(64)*e*(d/(S(4)*e) + x)*(-S(256)*a*e**S(3) + S(13)*d**S(4) - S(48)*d**S(2)*e**S(2)*(d/(S(4)*e) + x)**S(2))/((-S(16384)*a**S(2)*e**S(6) - S(64)*a*d**S(4)*e**S(3) + S(5)*d**S(8))*(S(256)*a*e**S(2) + S(5)*d**S(4)/e - S(96)*d**S(2)*e*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(3)*(d/(S(4)*e) + x)**S(4))) + S(24)*e*(S(128)*a*e**S(3) + d**S(4) + d**S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4)))*atanh(S(4)*e*(d/(S(4)*e) + x)/sqrt(S(3)*d**S(2) + S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4))))/(sqrt(S(3)*d**S(2) + S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4)))*(-S(64)*a*e**S(3) + d**S(4))**(S(3)/2)*(S(256)*a*e**S(3) + S(5)*d**S(4))) - S(24)*e*(S(128)*a*e**S(3) + d**S(4) - d**S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4)))*atanh(S(4)*e*(d/(S(4)*e) + x)/sqrt(S(3)*d**S(2) - S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4))))/(sqrt(S(3)*d**S(2) - S(2)*sqrt(-S(64)*a*e**S(3) + d**S(4)))*(-S(64)*a*e**S(3) + d**S(4))**(S(3)/2)*(S(256)*a*e**S(3) + S(5)*d**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4)), x), x, -sqrt(S(2))*d**S(2)*(d/(S(4)*e) + x)*sqrt(S(256)*a*e**S(2) + S(5)*d**S(4)/e - S(96)*d**S(2)*e*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(3)*(d/(S(4)*e) + x)**S(4))/(S(4)*sqrt(S(256)*a*e**S(3) + S(5)*d**S(4))*(S(16)*e**S(2)*(d/(S(4)*e) + x)**S(2)/sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)) + S(1))) + sqrt(S(2))*d**S(2)*sqrt((S(256)*a*e**S(3) + S(5)*d**S(4) - S(96)*d**S(2)*e**S(2)*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(4)*(d/(S(4)*e) + x)**S(4))/((S(256)*a*e**S(3) + S(5)*d**S(4))*(S(16)*e**S(2)*(d/(S(4)*e) + x)**S(2)/sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)) + S(1))**S(2)))*(S(256)*a*e**S(3) + S(5)*d**S(4))**(S(3)/4)*(S(16)*e**S(2)*(d/(S(4)*e) + x)**S(2)/sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)) + S(1))*elliptic_e(S(2)*atan(S(4)*e*(d/(S(4)*e) + x)/(S(256)*a*e**S(3) + S(5)*d**S(4))**(S(1)/4)), S(3)*d**S(2)/(S(2)*sqrt(S(256)*a*e**S(3) + S(5)*d**S(4))) + S(1)/2)/(S(16)*e**S(2)*sqrt(S(256)*a*e**S(2) + S(5)*d**S(4)/e - S(96)*d**S(2)*e*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(3)*(d/(S(4)*e) + x)**S(4))) + sqrt(S(2))*(d/(S(4)*e) + x)*sqrt(S(256)*a*e**S(2) + S(5)*d**S(4)/e - S(96)*d**S(2)*e*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(3)*(d/(S(4)*e) + x)**S(4))/S(24) + sqrt(S(2))*sqrt((S(256)*a*e**S(3) + S(5)*d**S(4) - S(96)*d**S(2)*e**S(2)*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(4)*(d/(S(4)*e) + x)**S(4))/((S(256)*a*e**S(3) + S(5)*d**S(4))*(S(16)*e**S(2)*(d/(S(4)*e) + x)**S(2)/sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)) + S(1))**S(2)))*(S(256)*a*e**S(3) + S(5)*d**S(4))**(S(1)/4)*(S(16)*e**S(2)*(d/(S(4)*e) + x)**S(2)/sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)) + S(1))*(S(256)*a*e**S(3) + S(5)*d**S(4) - S(3)*d**S(2)*sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)))*elliptic_f(S(2)*atan(S(4)*e*(d/(S(4)*e) + x)/(S(256)*a*e**S(3) + S(5)*d**S(4))**(S(1)/4)), S(3)*d**S(2)/(S(2)*sqrt(S(256)*a*e**S(3) + S(5)*d**S(4))) + S(1)/2)/(S(96)*e**S(2)*sqrt(S(256)*a*e**S(2) + S(5)*d**S(4)/e - S(96)*d**S(2)*e*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(3)*(d/(S(4)*e) + x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(8)*a*e**S(2) - d**S(3)*x + S(8)*d*e**S(2)*x**S(3) + S(8)*e**S(3)*x**S(4)), x), x, sqrt(S(2))*sqrt((S(256)*a*e**S(3) + S(5)*d**S(4) - S(96)*d**S(2)*e**S(2)*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(4)*(d/(S(4)*e) + x)**S(4))/((S(256)*a*e**S(3) + S(5)*d**S(4))*(S(16)*e**S(2)*(d/(S(4)*e) + x)**S(2)/sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)) + S(1))**S(2)))*(S(256)*a*e**S(3) + S(5)*d**S(4))**(S(1)/4)*(S(16)*e**S(2)*(d/(S(4)*e) + x)**S(2)/sqrt(S(256)*a*e**S(3) + S(5)*d**S(4)) + S(1))*elliptic_f(S(2)*atan(S(4)*e*(d/(S(4)*e) + x)/(S(256)*a*e**S(3) + S(5)*d**S(4))**(S(1)/4)), S(3)*d**S(2)/(S(2)*sqrt(S(256)*a*e**S(3) + S(5)*d**S(4))) + S(1)/2)/(S(2)*e*sqrt(S(256)*a*e**S(2) + S(5)*d**S(4)/e - S(96)*d**S(2)*e*(d/(S(4)*e) + x)**S(2) + S(256)*e**S(3)*(d/(S(4)*e) + x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(4), x), x, x*(a + S(3))**S(4) + (-S(4)*a/S(5) + S(12)/5)*(a + S(3))**S(2)*(x + S(-1))**S(5) + (-S(4)*a/S(13) + S(12)/13)*(x + S(-1))**S(13) - S(8)*(a + S(3))**S(3)*(x + S(-1))**S(3)/S(3) + (S(8)*a/S(7) + S(24)/7)*(S(3)*a + S(5))*(x + S(-1))**S(7) - (S(24)*a/S(11) + S(40)/11)*(x + S(-1))**S(11) + (x + S(-1))**S(17)/S(17) + S(8)*(x + S(-1))**S(15)/S(15) - (x + S(-1))**S(9)*(-S(2)*a**S(2)/S(3) + S(4)*a/S(3) + S(74)/9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(3), x), x, a**S(3)*x + S(12)*a**S(2)*x**S(2) + a*x**S(3)*(-S(8)*a + S(64)) - x**S(13)/S(13) + x**S(12) - S(72)*x**S(11)/S(11) + S(28)*x**S(10) - x**S(9)*(-a/S(3) + S(256)/3) + x**S(8)*(-S(3)*a + S(192)) - x**S(7)*(-S(96)*a/S(7) + S(320)) + x**S(6)*(-S(40)*a + S(384)) - x**S(5)*(S(3)*a**S(2)/S(5) - S(384)*a/S(5) + S(1536)/5) + x**S(4)*(S(3)*a**S(2) - S(96)*a + S(128)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(2), x), x, a**S(2)*x + S(8)*a*x**S(2) + x**S(9)/S(9) - x**S(8) + S(32)*x**S(7)/S(7) - S(40)*x**S(6)/S(3) + x**S(5)*(-S(2)*a/S(5) + S(128)/5) - x**S(4)*(-S(2)*a + S(32)) + x**S(3)*(-S(16)*a/S(3) + S(64)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x, x), x, a*x - x**S(5)/S(5) + x**S(4) - S(8)*x**S(3)/S(3) + S(4)*x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1)))/(S(2)*sqrt(a + S(4))*sqrt(sqrt(a + S(4)) + S(1))) - atan((x + S(-1))/sqrt(-sqrt(a + S(4)) + S(1)))/(S(2)*sqrt(a + S(4))*sqrt(-sqrt(a + S(4)) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(-2)), x), x, (x + S(-1))*(a + (x + S(-1))**S(2) + S(5))/((S(4)*a**S(2) + S(28)*a + S(48))*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (S(3)*a - sqrt(a + S(4)) + S(10))*atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1)))/((a + S(4))**(S(3)/2)*(S(8)*a + S(24))*sqrt(sqrt(a + S(4)) + S(1))) - (S(3)*a + sqrt(a + S(4)) + S(10))*atan((x + S(-1))/sqrt(-sqrt(a + S(4)) + S(1)))/((a + S(4))**(S(3)/2)*(S(8)*a + S(24))*sqrt(-sqrt(a + S(4)) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(4), x), x, a**S(4)*x**S(2)/S(2) + S(32)*a**S(3)*x**S(3)/S(3) + a**S(2)*x**S(4)*(-S(8)*a + S(96)) + S(16)*a*x**S(5)*(a**S(2) - S(48)*a + S(128))/S(5) + x**S(18)/S(18) - S(16)*x**S(17)/S(17) + S(8)*x**S(16) - S(224)*x**S(15)/S(5) + x**S(14)*(-S(2)*a/S(7) + S(1280)/7) - x**S(13)*(-S(48)*a/S(13) + S(7424)/13) + x**S(12)*(-S(24)*a + S(4192)/3) - x**S(11)*(-S(1120)*a/S(11) + S(29696)/11) + x**S(10)*(S(3)*a**S(2)/S(5) - S(1536)*a/S(5) + S(4096)) - x**S(9)*(S(16)*a**S(2)/S(3) - S(2048)*a/S(3) + S(14336)/3) + x**S(8)*(-S(24)*a + S(1024))*(-a + S(4)) - x**S(7)*(S(480)*a**S(2)/S(7) - S(9216)*a/S(7) + S(16384)/7) + x**S(6)*(-S(2)*a**S(3)/S(3) + S(128)*a**S(2) - S(1024)*a + S(2048)/3), expand=True, _diff=True, _numerical=True) # long time in rubi_int assert rubi_test(rubi_integrate(x*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(3), x), x, a**S(3)*x**S(2)/S(2) + S(8)*a**S(2)*x**S(3) + a*x**S(4)*(-S(6)*a + S(48)) - x**S(14)/S(14) + S(12)*x**S(13)/S(13) - S(6)*x**S(12) + S(280)*x**S(11)/S(11) - x**S(10)*(-S(3)*a/S(10) + S(384)/5) + x**S(9)*(-S(8)*a/S(3) + S(512)/3) - x**S(8)*(-S(12)*a + S(280)) + x**S(7)*(-S(240)*a/S(7) + S(2304)/7) - x**S(6)*(a**S(2)/S(2) - S(64)*a + S(256)) + x**S(5)*(S(12)*a**S(2)/S(5) - S(384)*a/S(5) + S(512)/5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(2), x), x, a**S(2)*x**S(2)/S(2) + S(16)*a*x**S(3)/S(3) + x**S(10)/S(10) - S(8)*x**S(9)/S(9) + S(4)*x**S(8) - S(80)*x**S(7)/S(7) + x**S(6)*(-a/S(3) + S(64)/3) - x**S(5)*(-S(8)*a/S(5) + S(128)/5) + x**S(4)*(-S(4)*a + S(16)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, a*x**S(2)/S(2) - x**S(6)/S(6) + S(4)*x**S(5)/S(5) - S(2)*x**S(4) + S(8)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, atanh(((x + S(-1))**S(2) + S(1))/sqrt(a + S(4)))/(S(2)*sqrt(a + S(4))) + atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1)))/(S(2)*sqrt(a + S(4))*sqrt(sqrt(a + S(4)) + S(1))) - atan((x + S(-1))/sqrt(-sqrt(a + S(4)) + S(1)))/(S(2)*sqrt(a + S(4))*sqrt(-sqrt(a + S(4)) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(2), x), x, (x + S(-1))*(a + (a + S(5))*(x + S(-1)) + (x + S(-1))**S(3) + (x + S(-1))**S(2) + S(5))/((S(4)*a**S(2) + S(28)*a + S(48))*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + atanh(((x + S(-1))**S(2) + S(1))/sqrt(a + S(4)))/(S(4)*(a + S(4))**(S(3)/2)) + (S(3)*a - sqrt(a + S(4)) + S(10))*atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1)))/((a + S(4))**(S(3)/2)*(S(8)*a + S(24))*sqrt(sqrt(a + S(4)) + S(1))) - (S(3)*a + sqrt(a + S(4)) + S(10))*atan((x + S(-1))/sqrt(-sqrt(a + S(4)) + S(1)))/((a + S(4))**(S(3)/2)*(S(8)*a + S(24))*sqrt(-sqrt(a + S(4)) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(4), x), x, a**S(4)*x**S(3)/S(3) + S(8)*a**S(3)*x**S(4) + a**S(2)*x**S(5)*(-S(32)*a/S(5) + S(384)/5) + S(8)*a*x**S(6)*(a**S(2) - S(48)*a + S(128))/S(3) + x**S(19)/S(19) - S(8)*x**S(18)/S(9) + S(128)*x**S(17)/S(17) - S(42)*x**S(16) + x**S(15)*(-S(4)*a/S(15) + S(512)/3) - x**S(14)*(-S(24)*a/S(7) + S(3712)/7) + x**S(13)*(-S(288)*a/S(13) + S(16768)/13) - x**S(12)*(-S(280)*a/S(3) + S(7424)/3) + x**S(11)*(S(6)*a**S(2)/S(11) - S(3072)*a/S(11) + S(40960)/11) - x**S(10)*(S(24)*a**S(2)/S(5) - S(3072)*a/S(5) + S(21504)/5) + x**S(9)*(-S(64)*a/S(3) + S(8192)/9)*(-a + S(4)) - x**S(8)*(S(60)*a**S(2) - S(1152)*a + S(2048)) + x**S(7)*(-S(4)*a**S(3)/S(7) + S(768)*a**S(2)/S(7) - S(6144)*a/S(7) + S(4096)/7), expand=True, _diff=True, _numerical=True) # long time in rubi_int assert rubi_test(rubi_integrate(x**S(2)*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(3), x), x, a**S(3)*x**S(3)/S(3) + S(6)*a**S(2)*x**S(4) + a*x**S(5)*(-S(24)*a/S(5) + S(192)/5) - x**S(15)/S(15) + S(6)*x**S(14)/S(7) - S(72)*x**S(13)/S(13) + S(70)*x**S(12)/S(3) - x**S(11)*(-S(3)*a/S(11) + S(768)/11) + x**S(10)*(-S(12)*a/S(5) + S(768)/5) - x**S(9)*(-S(32)*a/S(3) + S(2240)/9) + x**S(8)*(-S(30)*a + S(288)) - x**S(7)*(S(3)*a**S(2)/S(7) - S(384)*a/S(7) + S(1536)/7) + x**S(6)*(S(2)*a**S(2) - S(64)*a + S(256)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(2), x), x, a**S(2)*x**S(3)/S(3) + S(4)*a*x**S(4) + x**S(11)/S(11) - S(4)*x**S(10)/S(5) + S(32)*x**S(9)/S(9) - S(10)*x**S(8) + x**S(7)*(-S(2)*a/S(7) + S(128)/7) - x**S(6)*(-S(4)*a/S(3) + S(64)/3) + x**S(5)*(-S(16)*a/S(5) + S(64)/5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, a*x**S(3)/S(3) - x**S(7)/S(7) + S(2)*x**S(6)/S(3) - S(8)*x**S(5)/S(5) + S(2)*x**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, -atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1)))/(S(2)*sqrt(sqrt(a + S(4)) + S(1))) - atan((x + S(-1))/sqrt(-sqrt(a + S(4)) + S(1)))/(S(2)*sqrt(-sqrt(a + S(4)) + S(1))) + atanh(((x + S(-1))**S(2) + S(1))/sqrt(a + S(4)))/sqrt(a + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**S(2), x), x, (x + S(-1))*(S(2)*a + (a + S(4))*(x + S(-1))**S(2) + (S(2)*a + S(10))*(x + S(-1)) + S(2)*(x + S(-1))**S(3) + S(8))/((S(4)*a**S(2) + S(28)*a + S(48))*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (-sqrt(a + S(4)) + S(1))*atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1)))/(sqrt(a + S(4))*(S(8)*a + S(24))*sqrt(sqrt(a + S(4)) + S(1))) - (sqrt(a + S(4)) + S(1))*atan((x + S(-1))/sqrt(-sqrt(a + S(4)) + S(1)))/(sqrt(a + S(4))*(S(8)*a + S(24))*sqrt(-sqrt(a + S(4)) + S(1))) + atanh(((x + S(-1))**S(2) + S(1))/sqrt(a + S(4)))/(S(2)*(a + S(4))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(3)/2), x), x, -(S(32)*a + S(112))*(x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))/(S(35)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (x + S(-1))*(S(2)*a/S(7) - S(6)*(x + S(-1))**S(2)/S(35) + S(26)/35)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + (x + S(-1))*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2)/S(7) + (S(4)*a + S(12))*(S(5)*a + S(16))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(35)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (S(32)*a + S(112))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(35)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, -(x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-S(2)*sqrt(a + S(4)) + S(2))/(S(3)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (x + S(-1))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))/S(3) + (S(2)*a + S(6))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(3)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-S(2)*sqrt(a + S(4)) + S(2))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(3)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(3)/2), x), x, (S(3)*a/S(16) + S(3)/4)*((x + S(-1))**S(2) + S(1))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + S(3)*(a + S(4))**S(2)*atan(((x + S(-1))**S(2) + S(1))/sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)))/S(16) - (S(32)*a + S(112))*(x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))/(S(35)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (x + S(-1))*(S(2)*a/S(7) - S(6)*(x + S(-1))**S(2)/S(35) + S(26)/35)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + (x + S(-1))*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2)/S(7) + ((x + S(-1))**S(2)/S(8) + S(1)/8)*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2) + (S(4)*a + S(12))*(S(5)*a + S(16))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(35)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (S(32)*a + S(112))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(35)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, (a/S(4) + S(1))*atan(((x + S(-1))**S(2) + S(1))/sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) - (x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-S(2)*sqrt(a + S(4)) + S(2))/(S(3)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (x + S(-1))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))/S(3) + ((x + S(-1))**S(2)/S(4) + S(1)/4)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + (S(2)*a + S(6))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(3)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-S(2)*sqrt(a + S(4)) + S(2))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(3)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, atan(((x + S(-1))**S(2) + S(1))/sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)))/S(2) + ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(3)/2), x), x, (S(3)*a/S(8) + S(3)/2)*((x + S(-1))**S(2) + S(1))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + S(3)*(a + S(4))**S(2)*atan(((x + S(-1))**S(2) + S(1))/sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)))/S(8) + (x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))*(S(84)*a**S(2) + S(444)*a + S(560))/(S(315)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (x + S(-1))*((x + S(-1))**S(2)/S(9) + S(5)/21)*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2) + (x + S(-1))*(S(12)*a/S(35) + S(2)*(S(21)*a + S(60))*(x + S(-1))**S(2)/S(315) + S(64)/63)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + ((x + S(-1))**S(2)/S(4) + S(1)/4)*(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))**(S(3)/2) + (S(4)*a + S(12))*(S(33)*a + S(100))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(315)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) - ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*(S(84)*a**S(2) + S(444)*a + S(560))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(315)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, (a/S(2) + S(2))*atan(((x + S(-1))**S(2) + S(1))/sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (S(6)*a + S(16))*(x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))/(S(15)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (x + S(-1))*((x + S(-1))**S(2)/S(5) + S(7)/15)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + ((x + S(-1))**S(2)/S(2) + S(1)/2)*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) - (S(6)*a + S(16))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(15)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + (S(8)*a + S(24))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(S(15)*sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x), x), x, (x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))/sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3)) + atan(((x + S(-1))**S(2) + S(1))/sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) - ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_f(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a - x**S(4) + S(4)*x**S(3) - S(8)*x**S(2) + S(8)*x)**(S(3)/2), x), x, (x + S(-1))*(S(2)*a + (a + S(4))*(x + S(-1))**S(2) + (S(2)*a + S(10))*(x + S(-1)) + S(2)*(x + S(-1))**S(3) + S(8))/((S(2)*a**S(2) + S(14)*a + S(24))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))/(a**S(2) + S(7)*a + S(12)) - (x + S(-1))*((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))/((S(2)*a + S(6))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))) + ((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))*(-sqrt(a + S(4)) + S(1))*sqrt(sqrt(a + S(4)) + S(1))*elliptic_e(atan((x + S(-1))/sqrt(sqrt(a + S(4)) + S(1))), -S(2)*sqrt(a + S(4))/(-sqrt(a + S(4)) + S(1)))/(sqrt(((x + S(-1))**S(2)/(-sqrt(a + S(4)) + S(1)) + S(1))/((x + S(-1))**S(2)/(sqrt(a + S(4)) + S(1)) + S(1)))*(S(2)*a + S(6))*sqrt(a - (x + S(-1))**S(4) - S(2)*(x + S(-1))**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - x**S(3) + S(8)*x + S(8))**S(4), x), x, S(4096)*x**S(17)/S(17) - S(128)*x**S(16) + S(128)*x**S(15)/S(5) + S(1168)*x**S(14) + S(10241)*x**S(13)/S(13) - S(448)*x**S(12) + S(25312)*x**S(11)/S(11) + S(21488)*x**S(10)/S(5) + S(1408)*x**S(9) + S(1376)*x**S(8) + S(6784)*x**S(7) + S(7168)*x**S(6) + S(14336)*x**S(5)/S(5) + S(3584)*x**S(4) + S(8192)*x**S(3) + S(8192)*x**S(2) + S(4096)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - x**S(3) + S(8)*x + S(8))**S(3), x), x, S(512)*x**S(13)/S(13) - S(16)*x**S(12) + S(24)*x**S(11)/S(11) + S(307)*x**S(10)/S(2) + S(128)*x**S(9) - S(45)*x**S(8) + S(1560)*x**S(7)/S(7) + S(480)*x**S(6) + S(1152)*x**S(5)/S(5) + S(80)*x**S(4) + S(512)*x**S(3) + S(768)*x**S(2) + S(512)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - x**S(3) + S(8)*x + S(8))**S(2), x), x, S(64)*x**S(9)/S(9) - S(2)*x**S(8) + x**S(7)/S(7) + S(64)*x**S(6)/S(3) + S(112)*x**S(5)/S(5) - S(4)*x**S(4) + S(64)*x**S(3)/S(3) + S(64)*x**S(2) + S(64)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(8)*x**S(4) - x**S(3) + S(8)*x + S(8), x), x, S(8)*x**S(5)/S(5) - x**S(4)/S(4) + S(4)*x**S(2) + S(8)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(8)*x**S(4) - x**S(3) + S(8)*x + S(8)), x), x, -sqrt(S(-109)/1218 + S(67)*sqrt(S(29))/S(1218))*log((S(1) + S(4)/x)**S(2) - (S(1) + S(4)/x)*sqrt(S(6) + S(6)*sqrt(S(29))) + S(3)*sqrt(S(29)))/S(24) + sqrt(S(-109)/1218 + S(67)*sqrt(S(29))/S(1218))*log((S(1) + S(4)/x)**S(2) + (S(1) + S(4)/x)*sqrt(S(6) + S(6)*sqrt(S(29))) + S(3)*sqrt(S(29)))/S(24) - sqrt(S(7))*atan(sqrt(S(7))*(-(S(1) + S(4)/x)**S(2) + S(3))/S(42))/S(84) + sqrt(S(109)/1218 + S(67)*sqrt(S(29))/S(1218))*atan((S(-2) + sqrt(S(6) + S(6)*sqrt(S(29))) - S(8)/x)/sqrt(S(-6) + S(6)*sqrt(S(29))))/S(12) - sqrt(S(109)/1218 + S(67)*sqrt(S(29))/S(1218))*atan((S(2) + sqrt(S(6) + S(6)*sqrt(S(29))) + S(8)/x)/sqrt(S(-6) + S(6)*sqrt(S(29))))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - x**S(3) + S(8)*x + S(8))**(S(-2)), x), x, (S(1) + S(4)/x)*(S(207)*(S(1) + S(4)/x)**S(3) + S(995)*(S(1) + S(4)/x)**S(2) + S(16974) - S(35244)/x)/(S(87696)*(S(1) + S(4)/x)**S(4) - S(526176)*(S(1) + S(4)/x)**S(2) + S(22888656)) - sqrt(S(-180983329)/1218 + S(1583563)*sqrt(S(29))/S(42))*log((S(1) + S(4)/x)**S(2) - (S(1) + S(4)/x)*sqrt(S(6) + S(6)*sqrt(S(29))) + S(3)*sqrt(S(29)))/S(175392) + sqrt(S(-180983329)/1218 + S(1583563)*sqrt(S(29))/S(42))*log((S(1) + S(4)/x)**S(2) + (S(1) + S(4)/x)*sqrt(S(6) + S(6)*sqrt(S(29))) + S(3)*sqrt(S(29)))/S(175392) - S(17)*sqrt(S(7))*atan(sqrt(S(7))*(-(S(1) + S(4)/x)**S(2) + S(3))/S(42))/S(7056) + sqrt(S(180983329)/1218 + S(1583563)*sqrt(S(29))/S(42))*atan((S(-2) + sqrt(S(6) + S(6)*sqrt(S(29))) - S(8)/x)/sqrt(S(-6) + S(6)*sqrt(S(29))))/S(87696) - sqrt(S(180983329)/1218 + S(1583563)*sqrt(S(29))/S(42))*atan((S(2) + sqrt(S(6) + S(6)*sqrt(S(29))) + S(8)/x)/sqrt(S(-6) + S(6)*sqrt(S(29))))/S(87696), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1))**S(4), x), x, S(256)*x**S(17)/S(17) + S(1024)*x**S(15)/S(15) + S(512)*x**S(14)/S(7) + S(1792)*x**S(13)/S(13) + S(256)*x**S(12) + S(3328)*x**S(11)/S(11) + S(384)*x**S(10) + S(4192)*x**S(9)/S(9) + S(448)*x**S(8) + S(2752)*x**S(7)/S(7) + S(992)*x**S(6)/S(3) + S(1136)*x**S(5)/S(5) + S(112)*x**S(4) + S(112)*x**S(3)/S(3) + S(8)*x**S(2) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1))**S(3), x), x, S(64)*x**S(13)/S(13) + S(192)*x**S(11)/S(11) + S(96)*x**S(10)/S(5) + S(80)*x**S(9)/S(3) + S(48)*x**S(8) + S(352)*x**S(7)/S(7) + S(48)*x**S(6) + S(252)*x**S(5)/S(5) + S(40)*x**S(4) + S(20)*x**S(3) + S(6)*x**S(2) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1))**S(2), x), x, S(16)*x**S(9)/S(9) + S(32)*x**S(7)/S(7) + S(16)*x**S(6)/S(3) + S(24)*x**S(5)/S(5) + S(8)*x**S(4) + S(8)*x**S(3) + S(4)*x**S(2) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1), x), x, S(4)*x**S(5)/S(5) + S(4)*x**S(3)/S(3) + S(2)*x**S(2) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1)), x), x, -sqrt(S(-2)/5 + sqrt(S(5))/S(5))*log((S(1) + S(1)/x)**S(2) - (S(1) + S(1)/x)*sqrt(S(2) + S(2)*sqrt(S(5))) + sqrt(S(5)))/S(4) + sqrt(S(-2)/5 + sqrt(S(5))/S(5))*log((S(1) + S(1)/x)**S(2) + (S(1) + S(1)/x)*sqrt(S(2) + S(2)*sqrt(S(5))) + sqrt(S(5)))/S(4) + sqrt(S(2)/5 + sqrt(S(5))/S(5))*atan((S(-2) + sqrt(S(2) + S(2)*sqrt(S(5))) - S(2)/x)/sqrt(S(-2) + S(2)*sqrt(S(5))))/S(2) - sqrt(S(2)/5 + sqrt(S(5))/S(5))*atan((S(2) + sqrt(S(2) + S(2)*sqrt(S(5))) + S(2)/x)/sqrt(S(-2) + S(2)*sqrt(S(5))))/S(2) + atan((S(1) + S(1)/x)**S(2)/S(2) + S(-1)/2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1))**(S(-2)), x), x, (S(1) + S(1)/x)*(S(17)*(S(1) + S(1)/x)**S(3) - S(17)*(S(1) + S(1)/x)**S(2) + S(30) - S(29)/x)/(S(10)*(S(1) + S(1)/x)**S(4) - S(20)*(S(1) + S(1)/x)**S(2) + S(50)) + sqrt(S(-5959)/10 + S(533)*sqrt(S(5))/S(2))*log((S(1) + S(1)/x)**S(2) - (S(1) + S(1)/x)*sqrt(S(2) + S(2)*sqrt(S(5))) + sqrt(S(5)))/S(40) - sqrt(S(-5959)/10 + S(533)*sqrt(S(5))/S(2))*log((S(1) + S(1)/x)**S(2) + (S(1) + S(1)/x)*sqrt(S(2) + S(2)*sqrt(S(5))) + sqrt(S(5)))/S(40) + sqrt(S(5959)/10 + S(533)*sqrt(S(5))/S(2))*atan((S(-2) + sqrt(S(2) + S(2)*sqrt(S(5))) - S(2)/x)/sqrt(S(-2) + S(2)*sqrt(S(5))))/S(20) - sqrt(S(5959)/10 + S(533)*sqrt(S(5))/S(2))*atan((S(2) + sqrt(S(2) + S(2)*sqrt(S(5))) + S(2)/x)/sqrt(S(-2) + S(2)*sqrt(S(5))))/S(20) + S(7)*atan((S(1) + S(1)/x)**S(2)/S(2) + S(-1)/2)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8))**S(4), x), x, S(4096)*x**S(17)/S(17) - S(1920)*x**S(16) + S(102784)*x**S(15)/S(15) - S(75504)*x**S(14)/S(7) - S(12095)*x**S(13)/S(13) + S(31128)*x**S(12) - S(331040)*x**S(11)/S(11) - S(169584)*x**S(10)/S(5) + S(641152)*x**S(9)/S(9) + S(36384)*x**S(8) - S(566912)*x**S(7)/S(7) - S(30720)*x**S(6) + S(538624)*x**S(5)/S(5) + S(139776)*x**S(4) + S(237568)*x**S(3)/S(3) + S(24576)*x**S(2) + S(4096)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8))**S(3), x), x, S(512)*x**S(13)/S(13) - S(240)*x**S(12) + S(6936)*x**S(11)/S(11) - S(4527)*x**S(10)/S(10) - S(2936)*x**S(9)/S(3) + S(2097)*x**S(8) + S(5528)*x**S(7)/S(7) - S(2976)*x**S(6) - S(384)*x**S(5)/S(5) + S(5040)*x**S(4) + S(5120)*x**S(3) + S(2304)*x**S(2) + S(512)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8))**S(2), x), x, S(64)*x**S(9)/S(9) - S(30)*x**S(8) + S(353)*x**S(7)/S(7) + S(24)*x**S(6) - S(528)*x**S(5)/S(5) + S(36)*x**S(4) + S(704)*x**S(3)/S(3) + S(192)*x**S(2) + S(64)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8), x), x, S(8)*x**S(5)/S(5) - S(15)*x**S(4)/S(4) + S(8)*x**S(3)/S(3) + S(12)*x**S(2) + S(8)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8)), x), x, -sqrt(S(-5167)/40326 + S(5)*sqrt(S(517))/S(858))*log((S(3) + S(4)/x)**S(2) - (S(3) + S(4)/x)*sqrt(S(38) + S(2)*sqrt(S(517))) + sqrt(S(517)))/S(8) + sqrt(S(-5167)/40326 + S(5)*sqrt(S(517))/S(858))*log((S(3) + S(4)/x)**S(2) + (S(3) + S(4)/x)*sqrt(S(38) + S(2)*sqrt(S(517))) + sqrt(S(517)))/S(8) - sqrt(S(39))*atan(sqrt(S(39))*(-(S(3) + S(4)/x)**S(2) + S(19))/S(78))/S(52) + sqrt(S(5167)/40326 + S(5)*sqrt(S(517))/S(858))*atan((S(-6) + sqrt(S(38) + S(2)*sqrt(S(517))) - S(8)/x)/sqrt(S(-38) + S(2)*sqrt(S(517))))/S(4) - sqrt(S(5167)/40326 + S(5)*sqrt(S(517))/S(858))*atan((S(6) + sqrt(S(38) + S(2)*sqrt(S(517))) + S(8)/x)/sqrt(S(-38) + S(2)*sqrt(S(517))))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8))**(S(-2)), x), x, (S(3) + S(4)/x)*(S(30231)*(S(3) + S(4)/x)**S(3) - S(129631)*(S(3) + S(4)/x)**S(2) + S(1375210) - S(2603628)/x)/(S(322608)*(S(3) + S(4)/x)**S(4) - S(12259104)*(S(3) + S(4)/x)**S(2) + S(166788336)) - sqrt(S(-59644114671451)/40326 + S(5073830635)*sqrt(S(517))/S(78))*log((S(3) + S(4)/x)**S(2) - (S(3) + S(4)/x)*sqrt(S(38) + S(2)*sqrt(S(517))) + sqrt(S(517)))/S(645216) + sqrt(S(-59644114671451)/40326 + S(5073830635)*sqrt(S(517))/S(78))*log((S(3) + S(4)/x)**S(2) + (S(3) + S(4)/x)*sqrt(S(38) + S(2)*sqrt(S(517))) + sqrt(S(517)))/S(645216) - S(73)*sqrt(S(39))*atan(sqrt(S(39))*(-(S(3) + S(4)/x)**S(2) + S(19))/S(78))/S(2704) + sqrt(S(19)/40326 + sqrt(S(517))/S(40326))*(S(1678181) + S(74897)*sqrt(S(517)))*atan((S(-6) + sqrt(S(38) + S(2)*sqrt(S(517))) - S(8)/x)/sqrt(S(-38) + S(2)*sqrt(S(517))))/S(645216) - sqrt(S(19)/40326 + sqrt(S(517))/S(40326))*(S(1678181) + S(74897)*sqrt(S(517)))*atan((S(6) + sqrt(S(38) + S(2)*sqrt(S(517))) + S(8)/x)/sqrt(S(-38) + S(2)*sqrt(S(517))))/S(645216), expand=True, _diff=True, _numerical=True) '''Takes a long time in rubi test, final results contain subs with Integral assert rubi_test(rubi_integrate(S(1)/sqrt(S(8)*x**S(4) - x**S(3) + S(8)*x + S(8)), x), x, -S(29)**(S(3)/4)*sqrt(S(6))*x**S(2)*sqrt(((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261))/(sqrt(S(29))*(S(1) + S(4)/x)**S(2) + S(87))**S(2))*(sqrt(S(29))*(S(1) + S(4)/x)**S(2) + S(87))*elliptic_f(S(2)*atan(S(29)**(S(3)/4)*sqrt(S(3))*(S(1) + S(4)/x)/S(87)), sqrt(S(29))/S(58) + S(1)/2)/(S(174)*sqrt(x**S(4)*((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - x**S(3) + S(8)*x + S(8))**(S(-3)/2), x), x, S(29)**(S(1)/4)*sqrt(S(6))*x**S(2)*sqrt(((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261))/(sqrt(S(29))*(S(1) + S(4)/x)**S(2) + S(87))**S(2))*(-S(5)*sqrt(S(29)) + S(14))*(sqrt(S(29))*(S(1) + S(4)/x)**S(2) + S(87))*elliptic_f(S(2)*atan(S(29)**(S(3)/4)*sqrt(S(3))*(S(1) + S(4)/x)/S(87)), sqrt(S(29))/S(58) + S(1)/2)/(S(12528)*sqrt(x**S(4)*((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261)))) - S(29)**(S(1)/4)*sqrt(S(6))*x**S(2)*sqrt(((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261))/(sqrt(S(29))*(S(1) + S(4)/x)**S(2) + S(87))**S(2))*(S(7)*sqrt(S(29))*(S(1) + S(4)/x)**S(2) + S(609))*elliptic_e(S(2)*atan(S(29)**(S(3)/4)*sqrt(S(3))*(S(1) + S(4)/x)/S(87)), sqrt(S(29))/S(58) + S(1)/2)/(S(3132)*sqrt(x**S(4)*((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261)))) + sqrt(S(2))*x**S(2)*(S(1) + S(4)/x)*(S(22)*(S(1) + S(4)/x)**S(3) - S(49)*(S(1) + S(4)/x)**S(2) + S(1467) - S(180)/x)/(S(21924)*sqrt(x**S(4)*((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261)))) + sqrt(S(58))*x**S(2)*(S(1) + S(4)/x)*(S(7)*(S(1) + S(4)/x)**S(4) - S(42)*(S(1) + S(4)/x)**S(2) + S(1827))/(S(3132)*sqrt(x**S(4)*((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261)))*(sqrt(S(29))*(S(1) + S(4)/x)**S(2) + S(87))) - sqrt(S(2))*x**S(2)*(S(11)*(S(1) + S(4)/x)**S(4) - S(66)*(S(1) + S(4)/x)**S(2) + S(2871))/(S(10962)*sqrt(x**S(4)*((S(1) + S(4)/x)**S(4) - S(6)*(S(1) + S(4)/x)**S(2) + S(261)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1)), x), x, -S(5)**(S(3)/4)*x**S(2)*sqrt(((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5))/((S(1) + S(1)/x)**S(2) + sqrt(S(5)))**S(2))*((S(1) + S(1)/x)**S(2) + sqrt(S(5)))*elliptic_f(S(2)*atan(S(5)**(S(3)/4)*(S(1) + S(1)/x)/S(5)), sqrt(S(5))/S(10) + S(1)/2)/(S(10)*sqrt(x**S(4)*((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(4) + S(4)*x**S(2) + S(4)*x + S(1))**(S(-3)/2), x), x, S(5)**(S(1)/4)*x**S(2)*sqrt(((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5))/((S(1) + S(1)/x)**S(2) + sqrt(S(5)))**S(2))*(-S(3)*sqrt(S(5)) + S(9))*((S(1) + S(1)/x)**S(2) + sqrt(S(5)))*elliptic_f(S(2)*atan(S(5)**(S(3)/4)*(S(1) + S(1)/x)/S(5)), sqrt(S(5))/S(10) + S(1)/2)/(S(20)*sqrt(x**S(4)*((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5)))) - S(5)**(S(1)/4)*x**S(2)*sqrt(((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5))/((S(1) + S(1)/x)**S(2) + sqrt(S(5)))**S(2))*(S(9)*(S(1) + S(1)/x)**S(2) + S(9)*sqrt(S(5)))*elliptic_e(S(2)*atan(S(5)**(S(3)/4)*(S(1) + S(1)/x)/S(5)), sqrt(S(5))/S(10) + S(1)/2)/(S(10)*sqrt(x**S(4)*((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5)))) + x**S(2)*(S(1) + S(1)/x)*(S(6)*(S(1) + S(1)/x)**S(3) - S(9)*(S(1) + S(1)/x)**S(2) + S(11) - S(2)/x)/(S(10)*sqrt(x**S(4)*((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5)))) + x**S(2)*(S(1) + S(1)/x)*(S(9)*(S(1) + S(1)/x)**S(4) - S(18)*(S(1) + S(1)/x)**S(2) + S(45))/(sqrt(x**S(4)*((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5)))*(S(10)*(S(1) + S(1)/x)**S(2) + S(10)*sqrt(S(5)))) - x**S(2)*(S(3)*(S(1) + S(1)/x)**S(4) - S(6)*(S(1) + S(1)/x)**S(2) + S(15))/(S(5)*sqrt(x**S(4)*((S(1) + S(1)/x)**S(4) - S(2)*(S(1) + S(1)/x)**S(2) + S(5)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8)), x), x, -sqrt(S(2))*S(517)**(S(3)/4)*x**S(2)*sqrt(((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517))/((S(3) + S(4)/x)**S(2) + sqrt(S(517)))**S(2))*((S(3) + S(4)/x)**S(2) + sqrt(S(517)))*elliptic_f(S(2)*atan(S(517)**(S(3)/4)*(S(3) + S(4)/x)/S(517)), S(19)*sqrt(S(517))/S(1034) + S(1)/2)/(S(1034)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8))**(S(-3)/2), x), x, sqrt(S(2))*S(517)**(S(1)/4)*x**S(2)*sqrt(((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517))/((S(3) + S(4)/x)**S(2) + sqrt(S(517)))**S(2))*(-S(203)*sqrt(S(517)) + S(4910))*((S(3) + S(4)/x)**S(2) + sqrt(S(517)))*elliptic_f(S(2)*atan(S(517)**(S(3)/4)*(S(3) + S(4)/x)/S(517)), S(19)*sqrt(S(517))/S(1034) + S(1)/2)/(S(322608)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))) - sqrt(S(2))*S(517)**(S(1)/4)*x**S(2)*sqrt(((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517))/((S(3) + S(4)/x)**S(2) + sqrt(S(517)))**S(2))*(S(2455)*(S(3) + S(4)/x)**S(2) + S(2455)*sqrt(S(517)))*elliptic_e(S(2)*atan(S(517)**(S(3)/4)*(S(3) + S(4)/x)/S(517)), S(19)*sqrt(S(517))/S(1034) + S(1)/2)/(S(80652)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))) + sqrt(S(2))*x**S(2)*(S(3) + S(4)/x)*(S(516)*(S(3) + S(4)/x)**S(3) - S(2455)*(S(3) + S(4)/x)**S(2) + S(24643) - S(35004)/x)/(S(80652)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))) + sqrt(S(2))*x**S(2)*(S(3) + S(4)/x)*(S(2455)*(S(3) + S(4)/x)**S(4) - S(93290)*(S(3) + S(4)/x)**S(2) + S(1269235))/(S(80652)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))*((S(3) + S(4)/x)**S(2) + sqrt(S(517)))) - S(43)*sqrt(S(2))*x**S(2)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517))/(S(6721)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(8)*x**S(4) - S(15)*x**S(3) + S(8)*x**S(2) + S(24)*x + S(8))**(S(-5)/2), x), x, sqrt(S(2))*S(517)**(S(1)/4)*x**S(2)*sqrt(((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517))/((S(3) + S(4)/x)**S(2) + sqrt(S(517)))**S(2))*(-S(175318963)*sqrt(S(517)) + S(4346103976))*((S(3) + S(4)/x)**S(2) + sqrt(S(517)))*elliptic_f(S(2)*atan(S(517)**(S(3)/4)*(S(3) + S(4)/x)/S(517)), S(19)*sqrt(S(517))/S(1034) + S(1)/2)/(S(156113882496)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))) - sqrt(S(2))*S(517)**(S(1)/4)*x**S(2)*sqrt(((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517))/((S(3) + S(4)/x)**S(2) + sqrt(S(517)))**S(2))*(S(543262997)*(S(3) + S(4)/x)**S(2) + S(543262997)*sqrt(S(517)))*elliptic_e(S(2)*atan(S(517)**(S(3)/4)*(S(3) + S(4)/x)/S(517)), S(19)*sqrt(S(517))/S(1034) + S(1)/2)/(S(9757117656)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))) + sqrt(S(2))*x**S(2)*(S(3) + S(4)/x)*(S(223148517)*(S(3) + S(4)/x)**S(3) - S(1086525994)*(S(3) + S(4)/x)**S(2) + S(8668521901) - S(13685866440)/x)/(S(19514235312)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))) + sqrt(S(2))*x**S(2)*(S(3) + S(4)/x)*(S(193467)*(S(3) + S(4)/x)**S(3) - S(718994)*(S(3) + S(4)/x)**S(2) + S(8297705) - S(20727588)/x)/(S(241956)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517))) + sqrt(S(2))*x**S(2)*(S(3) + S(4)/x)*(S(543262997)*(S(3) + S(4)/x)**S(4) - S(20643993886)*(S(3) + S(4)/x)**S(2) + S(280866969449))/(S(9757117656)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))*((S(3) + S(4)/x)**S(2) + sqrt(S(517)))) - sqrt(S(2))*x**S(2)*(S(74382839)*(S(3) + S(4)/x)**S(4) - S(2826547882)*(S(3) + S(4)/x)**S(2) + S(38455927763))/(S(6504745104)*sqrt(x**S(4)*((S(3) + S(4)/x)**S(4) - S(38)*(S(3) + S(4)/x)**S(2) + S(517)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(15)*x**S(3) - S(44)*x**S(2) - S(6)*x + S(9)), x), x, S(613)**(S(3)/4)*x**S(2)*sqrt(((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613))/((S(-1) + S(6)/x)**S(2) + sqrt(S(613)))**S(2))*((S(-1) + S(6)/x)**S(2) + sqrt(S(613)))*elliptic_f(S(2)*atan(S(613)**(S(3)/4)*(S(1) - S(6)/x)/S(613)), S(1)/2 + S(91)*sqrt(S(613))/S(1226))/(S(613)*sqrt(x**S(4)*((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(4) + S(15)*x**S(3) - S(44)*x**S(2) - S(6)*x + S(9))**(S(-3)/2), x), x, S(613)**(S(1)/4)*x**S(2)*sqrt(((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613))/((S(-1) + S(6)/x)**S(2) + sqrt(S(613)))**S(2))*(-S(145)*sqrt(S(613)) + S(7444))*((S(-1) + S(6)/x)**S(2) + sqrt(S(613)))*elliptic_f(S(2)*atan(S(613)**(S(3)/4)*(S(1) - S(6)/x)/S(613)), S(1)/2 + S(91)*sqrt(S(613))/S(1226))/(S(10576089)*sqrt(x**S(4)*((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613)))) - S(613)**(S(1)/4)*x**S(2)*sqrt(((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613))/((S(-1) + S(6)/x)**S(2) + sqrt(S(613)))**S(2))*(S(14888)*(S(-1) + S(6)/x)**S(2) + S(14888)*sqrt(S(613)))*elliptic_e(S(2)*atan(S(613)**(S(3)/4)*(S(1) - S(6)/x)/S(613)), S(1)/2 + S(91)*sqrt(S(613))/S(1226))/(S(10576089)*sqrt(x**S(4)*((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613)))) + x**S(2)*(S(1) - S(6)/x)*(S(704)*(S(1) - S(6)/x)**S(3) - S(14888)*(S(1) - S(6)/x)**S(2) + S(109872) + S(430392)/x)/(S(10576089)*sqrt(x**S(4)*((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613)))) + x**S(2)*(S(1) - S(6)/x)*(S(14888)*(S(-1) + S(6)/x)**S(4) - S(2709616)*(S(1) - S(6)/x)**S(2) + S(9126344))/(sqrt(x**S(4)*((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613)))*(S(10576089)*(S(-1) + S(6)/x)**S(2) + S(10576089)*sqrt(S(613)))) - x**S(2)*(S(704)*(S(-1) + S(6)/x)**S(4) - S(128128)*(S(1) - S(6)/x)**S(2) + S(431552))/(S(10576089)*sqrt(x**S(4)*((S(-1) + S(6)/x)**S(4) - S(182)*(S(1) - S(6)/x)**S(2) + S(613)))), expand=True, _diff=True, _numerical=True) ''' def test_5(): assert rubi_test(rubi_integrate(x**m*sqrt(-a/x + b)/sqrt(a - b*x), x), x, S(2)*x**(m + S(1))*sqrt(-a/x + b)/(sqrt(a - b*x)*(S(2)*m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(-a/x + b)/sqrt(a - b*x), x), x, S(2)*x**S(3)*sqrt(-a/x + b)/(S(5)*sqrt(a - b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(-a/x + b)/sqrt(a - b*x), x), x, S(2)*x**S(2)*sqrt(-a/x + b)/(S(3)*sqrt(a - b*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a/x + b)/sqrt(a - b*x), x), x, S(2)*x*sqrt(-a/x + b)/sqrt(a - b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a/x + b)/(x*sqrt(a - b*x)), x), x, -S(2)*sqrt(-a/x + b)/sqrt(a - b*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a/x + b)/(x**S(2)*sqrt(a - b*x)), x), x, -S(2)*sqrt(-a/x + b)/(S(3)*x*sqrt(a - b*x)), expand=True, _diff=True, _numerical=True) # appellf1 assert rubi_test(rubi_integrate((a + b/x)**m*(c + d*x)**n, x), x, x*(S(1) + d*x/c)**(-n)*(a + b/x)**m*(c + d*x)**n*(a*x/b + S(1))**(-m)*AppellF1(-m + S(1), -m, -n, -m + S(2), -a*x/b, -d*x/c)/(-m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x)**m*(c + d*x)**S(2), x), x, d**S(2)*x**S(3)*(a + b/x)**(m + S(1))/(S(3)*a) + d*x**S(2)*(a + b/x)**(m + S(1))*(S(6)*a*c - b*d*(-m + S(2)))/(S(6)*a**S(2)) - b*(a + b/x)**(m + S(1))*(S(6)*a**S(2)*c**S(2) - S(6)*a*b*c*d*(-m + S(1)) + b**S(2)*d**S(2)*(m**S(2) - S(3)*m + S(2)))*hyper((S(2), m + S(1)), (m + S(2),), S(1) + b/(a*x))/(S(6)*a**S(4)*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x)**m*(c + d*x), x), x, d*x**S(2)*(a + b/x)**(m + S(1))/(S(2)*a) - b*(a + b/x)**(m + S(1))*(S(2)*a*c - b*d*(-m + S(1)))*hyper((S(2), m + S(1)), (m + S(2),), S(1) + b/(a*x))/(S(2)*a**S(3)*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x)**m, x), x, -b*(a + b/x)**(m + S(1))*hyper((S(2), m + S(1)), (m + S(2),), S(1) + b/(a*x))/(a**S(2)*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x)**m/(c + d*x), x), x, -c*(a + b/x)**(m + S(1))*hyper((S(1), m + S(1)), (m + S(2),), c*(a + b/x)/(a*c - b*d))/(d*(m + S(1))*(a*c - b*d)) + (a + b/x)**(m + S(1))*hyper((S(1), m + S(1)), (m + S(2),), S(1) + b/(a*x))/(a*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x)**m/(c + d*x)**S(2), x), x, -b*(a + b/x)**(m + S(1))*hyper((S(2), m + S(1)), (m + S(2),), c*(a + b/x)/(a*c - b*d))/((m + S(1))*(a*c - b*d)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x)**m/(c + d*x)**S(3), x), x, -b*(a + b/x)**(m + S(1))*(S(2)*a*c - b*d*(m + S(1)))*hyper((S(2), m + S(1)), (m + S(2),), c*(a + b/x)/(a*c - b*d))/(S(2)*c*(m + S(1))*(a*c - b*d)**S(3)) - d*(a + b/x)**(m + S(1))/(S(2)*c*(a*c - b*d)*(c/x + d)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x)**m/(c + d*x)**S(4), x), x, -b*(a + b/x)**(m + S(1))*(S(6)*a**S(2)*c**S(2) - S(6)*a*b*c*d*(m + S(1)) + b**S(2)*d**S(2)*(m**S(2) + S(3)*m + S(2)))*hyper((S(2), m + S(1)), (m + S(2),), c*(a + b/x)/(a*c - b*d))/(S(6)*c**S(2)*(m + S(1))*(a*c - b*d)**S(4)) + d**S(2)*(a + b/x)**(m + S(1))/(S(3)*c**S(2)*(a*c - b*d)*(c/x + d)**S(3)) - d*(a + b/x)**(m + S(1))*(S(6)*a*c - b*d*(m + S(4)))/(S(6)*c**S(2)*(a*c - b*d)**S(2)*(c/x + d)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(-a/x**S(2) + b)/sqrt(a - b*x**S(2)), x), x, x**(m + S(1))*sqrt(-a/x**S(2) + b)/(m*sqrt(a - b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(-a/x**S(2) + b)/sqrt(a - b*x**S(2)), x), x, x**S(3)*sqrt(-a/x**S(2) + b)/(S(2)*sqrt(a - b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(-a/x**S(2) + b)/sqrt(a - b*x**S(2)), x), x, x**S(2)*sqrt(-a/x**S(2) + b)/sqrt(a - b*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a/x**S(2) + b)/sqrt(a - b*x**S(2)), x), x, x*sqrt(-a/x**S(2) + b)*log(x)/sqrt(a - b*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a/x**S(2) + b)/(x*sqrt(a - b*x**S(2))), x), x, -sqrt(-a/x**S(2) + b)/sqrt(a - b*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-a/x**S(2) + b)/(x**S(2)*sqrt(a - b*x**S(2))), x), x, -sqrt(-a/x**S(2) + b)/(S(2)*x*sqrt(a - b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x)**(S(3)/2)/sqrt(a + b/x**S(2)), x), x, -2*sqrt(b)*c*sqrt(a*(c + d*x)/(a*c - sqrt(b)*d*sqrt(-a)))*(a*c**2 + b*d**2)*sqrt(a*x**2/b + 1)*EllipticF(asin(sqrt(2)*sqrt(1 - x*sqrt(-a)/sqrt(b))/2), -2*sqrt(b)*d*sqrt(-a)/(a*c - sqrt(b)*d*sqrt(-a)))/(5*d*x*(-a)**(3/2)*sqrt(a + b/x**2)*sqrt(c + d*x)) + 2*sqrt(b)*sqrt(c + d*x)*(a*c**2 - 3*b*d**2)*sqrt(a*x**2/b + 1)*EllipticE(asin(sqrt(2)*sqrt(1 - x*sqrt(-a)/sqrt(b))/2), -2*sqrt(b)*d*sqrt(-a)/(a*c - sqrt(b)*d*sqrt(-a)))/(5*d*x*(-a)**(3/2)*sqrt(a*(c + d*x)/(a*c - sqrt(b)*d*sqrt(-a)))*sqrt(a + b/x**2)) + 2*c*sqrt(c + d*x)*(a*x**2 + b)/(5*a*x*sqrt(a + b/x**2)) + 2*(c + d*x)**(3/2)*(a*x**2 + b)/(5*a*x*sqrt(a + b/x**2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))**(S(5)/2)/sqrt(a**S(2) - b**S(2)*x**S(4)), x), x, S(19)*a**S(2)*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a - b*x**S(2)))/(S(8)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))) - S(9)*a*x*(a - b*x**S(2))*sqrt(a + b*x**S(2))/(S(8)*sqrt(a**S(2) - b**S(2)*x**S(4))) - x*(a - b*x**S(2))*(a + b*x**S(2))**(S(3)/2)/(S(4)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))**(S(3)/2)/sqrt(a**S(2) - b**S(2)*x**S(4)), x), x, S(3)*a*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a - b*x**S(2)))/(S(2)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))) - x*(a - b*x**S(2))*sqrt(a + b*x**S(2))/(S(2)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2))/sqrt(a**S(2) - b**S(2)*x**S(4)), x), x, sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a - b*x**S(2)))/(sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b*x**S(2))*sqrt(a**S(2) - b**S(2)*x**S(4))), x), x, sqrt(S(2))*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atan(sqrt(S(2))*sqrt(b)*x/sqrt(a - b*x**S(2)))/(S(2)*a*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(2))**(S(3)/2)*sqrt(a**S(2) - b**S(2)*x**S(4))), x), x, x*(a - b*x**S(2))/(S(4)*a**S(2)*sqrt(a + b*x**S(2))*sqrt(a**S(2) - b**S(2)*x**S(4))) + S(3)*sqrt(S(2))*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atan(sqrt(S(2))*sqrt(b)*x/sqrt(a - b*x**S(2)))/(S(8)*a**S(2)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(2))**(S(5)/2)*sqrt(a**S(2) - b**S(2)*x**S(4))), x), x, x*(a - b*x**S(2))/(S(8)*a**S(2)*(a + b*x**S(2))**(S(3)/2)*sqrt(a**S(2) - b**S(2)*x**S(4))) + S(9)*x*(a - b*x**S(2))/(S(32)*a**S(3)*sqrt(a + b*x**S(2))*sqrt(a**S(2) - b**S(2)*x**S(4))) + S(19)*sqrt(S(2))*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atan(sqrt(S(2))*sqrt(b)*x/sqrt(a - b*x**S(2)))/(S(64)*a**S(3)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - b*x**S(2))**(S(5)/2)/sqrt(a**S(2) - b**S(2)*x**S(4)), x), x, S(19)*a**S(2)*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(8)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))) - S(9)*a*x*sqrt(a - b*x**S(2))*(a + b*x**S(2))/(S(8)*sqrt(a**S(2) - b**S(2)*x**S(4))) - x*(a - b*x**S(2))**(S(3)/2)*(a + b*x**S(2))/(S(4)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - b*x**S(2))**(S(3)/2)/sqrt(a**S(2) - b**S(2)*x**S(4)), x), x, S(3)*a*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(2)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))) - x*sqrt(a - b*x**S(2))*(a + b*x**S(2))/(S(2)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a - b*x**S(2))/sqrt(a**S(2) - b**S(2)*x**S(4)), x), x, sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a - b*x**S(2))*sqrt(a**S(2) - b**S(2)*x**S(4))), x), x, sqrt(S(2))*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atanh(sqrt(S(2))*sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(2)*a*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a - b*x**S(2))**(S(3)/2)*sqrt(a**S(2) - b**S(2)*x**S(4))), x), x, x*(a + b*x**S(2))/(S(4)*a**S(2)*sqrt(a - b*x**S(2))*sqrt(a**S(2) - b**S(2)*x**S(4))) + S(3)*sqrt(S(2))*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atanh(sqrt(S(2))*sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(8)*a**S(2)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a - b*x**S(2))**(S(5)/2)*sqrt(a**S(2) - b**S(2)*x**S(4))), x), x, x*(a + b*x**S(2))/(S(8)*a**S(2)*(a - b*x**S(2))**(S(3)/2)*sqrt(a**S(2) - b**S(2)*x**S(4))) + S(9)*x*(a + b*x**S(2))/(S(32)*a**S(3)*sqrt(a - b*x**S(2))*sqrt(a**S(2) - b**S(2)*x**S(4))) + S(19)*sqrt(S(2))*sqrt(a - b*x**S(2))*sqrt(a + b*x**S(2))*atanh(sqrt(S(2))*sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(64)*a**S(3)*sqrt(b)*sqrt(a**S(2) - b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(2)/(x**S(2) + S(-1)))/(x**S(2) + S(1)), x), x, sqrt(S(2))*sqrt(-x**S(2)/(-x**S(2) + S(1)))*sqrt(x**S(2) + S(-1))*atan(sqrt(S(2))*sqrt(x**S(2) + S(-1))/S(2))/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(2)/(a + x**S(2)*(a + S(1)) + S(-1)))/(x**S(2) + S(1)), x), x, sqrt(S(2))*sqrt(-x**S(2)/(-a - x**S(2)*(a + S(1)) + S(1)))*sqrt(a + x**S(2)*(a + S(1)) + S(-1))*atan(sqrt(S(2))*sqrt(a + x**S(2)*(a + S(1)) + S(-1))/S(2))/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((x + S(1))*(x**S(2) + S(-1)))**(S(-2)/3), x), x, (S(3)*x**S(2)/S(2) + S(-3)/2)/((-x + S(-1))*(-x**S(2) + S(1)))**(S(2)/3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(((x + S(1))*(x**S(2) + S(-1)))**(S(-2)/3), x), x, (x + S(1))*(S(3)*x/S(2) + S(-3)/2)/(x**S(3) + x**S(2) - x + S(-1))**(S(2)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-1))/(sqrt(x*(x**S(2) + S(1)))*(x**S(2) + S(1))), x), x, -S(2)*x/sqrt(x*(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(-1))/((x**S(2) + S(1))*sqrt(x**S(3) + x)), x), x, -S(2)*x/sqrt(x**S(3) + x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x**S(2) + S(-1))**S(2)/(x*(x**S(2) + S(1))))/(x**S(2) + S(1)), x), x, S(2)*x*sqrt((-x**S(2) + S(1))**S(2)/(x*(x**S(2) + S(1))))/(-x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x**S(2) + S(-1))**S(2)/(x**S(3) + x))/(x**S(2) + S(1)), x), x, S(2)*x*sqrt((-x**S(2) + S(1))**S(2)/(x**S(3) + x))/(-x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + b/x**S(2))*sqrt(c + d*x**S(2))), x), x, sqrt(a*x**S(2) + b)*atanh(sqrt(d)*sqrt(a*x**S(2) + b)/(sqrt(a)*sqrt(c + d*x**S(2))))/(sqrt(a)*sqrt(d)*x*sqrt(a + b/x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(4) - S(2)*x**S(2))/((x**S(2) + S(-1))*(x**S(2) + S(2))), x), x, S(2)*sqrt(x**S(4) - S(2)*x**S(2))*atan(sqrt(x**S(2) + S(-2))/S(2))/(S(3)*x*sqrt(x**S(2) + S(-2))) - sqrt(x**S(4) - S(2)*x**S(2))*atan(sqrt(x**S(2) + S(-2)))/(S(3)*x*sqrt(x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(1) - S(1)/(x**S(2) + S(-1))**S(2))/(-x**S(2) + S(2)), x), x, sqrt(S(1) - S(1)/(-x**S(2) + S(1))**S(2))*(-x**S(2) + S(1))*atan(sqrt(x**S(2) + S(-2)))/(x*sqrt(x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(S(1) - S(1)/(x**S(2) + S(-1))**S(2))/(-x**S(2) + S(2)), x), x, sqrt(S(1) - S(1)/(-x**S(2) + S(1))**S(2))*(-x**S(2) + S(1))*sqrt(x**S(4) - S(2)*x**S(2))*atan(sqrt(x**S(2) + S(-2)))/(x*sqrt(x**S(2) + S(-2))*sqrt((x**S(2) + S(-1))**S(2) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt((x**S(4) - S(2)*x**S(2))/(x**S(2) + S(-1))**S(2))/(x**S(2) + S(2)), x), x, sqrt((x**S(4) - S(2)*x**S(2))/(-x**S(2) + S(1))**S(2))*(-x**S(2)/S(3) + S(1)/3)*atan(sqrt(x**S(2) + S(-2)))/(x*sqrt(x**S(2) + S(-2))) + sqrt((x**S(4) - S(2)*x**S(2))/(-x**S(2) + S(1))**S(2))*(S(2)*x**S(2)/S(3) + S(-2)/3)*atan(sqrt(x**S(2) + S(-2))/S(2))/(x*sqrt(x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x/(x**S(2) + S(1)) + S(1))**(S(5)/2), x), x, -(-x/S(3) + S(1)/3)*(x + S(1))**S(3)*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))/(x**S(2) + S(1)) + (x + S(1))*(S(8)*x/S(3) + S(-4)/3)*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1)) - (S(3)*x + S(4))*(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))/(x + S(1)) + S(5)*sqrt(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))*asinh(x)/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x/(x**S(2) + S(1)) + S(1))**(S(3)/2), x), x, -x*(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))/(x + S(1)) + (x + S(-1))*(x + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1)) + S(3)*sqrt(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))*asinh(x)/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x/(x**S(2) + S(1)) + S(1)), x), x, sqrt(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))*asinh(x)/(x + S(1)) + (x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x/(x**S(2) + S(1)) + S(1)), x), x, (x + S(1))/sqrt(S(2)*x/(x**S(2) + S(1)) + S(1)) - (x + S(1))*asinh(x)/(sqrt(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))) - sqrt(S(2))*(x + S(1))*atanh(sqrt(S(2))*(-x + S(1))/(S(2)*sqrt(x**S(2) + S(1))))/(sqrt(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x/(x**S(2) + S(1)) + S(1))**(S(-3)/2), x), x, (S(3)*x/S(2) + S(3))/sqrt(S(2)*x/(x**S(2) + S(1)) + S(1)) - (S(3)*x + S(3))*asinh(x)/(sqrt(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))) - sqrt(S(2))*(S(9)*x/S(2) + S(9)/2)*atanh(sqrt(S(2))*(-x + S(1))/(S(2)*sqrt(x**S(2) + S(1))))/(S(2)*sqrt(x**S(2) + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))) + (-x**S(2)/S(2) + S(-1)/2)/((x + S(1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))/(x**S(2) + S(1)), x), x, (x + S(-1))*sqrt(S(2)*x/(x**S(2) + S(1)) + S(1))/(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c/(a + b*x**S(2)))**(S(3)/2), x), x, -c*x*sqrt(c/(a + b*x**S(2)))/b + c*sqrt(c/(a + b*x**S(2)))*sqrt(a + b*x**S(2))*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/b**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c/(a + b*x**S(2)))**(S(3)/2), x), x, -c*sqrt(c/(a + b*x**S(2)))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c/(a + b*x**S(2)))**(S(3)/2), x), x, c*x*sqrt(c/(a + b*x**S(2)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c/(a + b*x**S(2)))**(S(3)/2)/x, x), x, c*sqrt(c/(a + b*x**S(2)))/a - c*sqrt(c/(a + b*x**S(2)))*sqrt(a + b*x**S(2))*atanh(sqrt(a + b*x**S(2))/sqrt(a))/a**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c/(a + b*x**S(2)))**(S(3)/2)/x**S(2), x), x, -c*sqrt(c/(a + b*x**S(2)))/(a*x) - S(2)*b*c*x*sqrt(c/(a + b*x**S(2)))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c/(a + b*x**S(2)))**(S(3)/2)/x**S(3), x), x, c*sqrt(c/(a + b*x**S(2)))/(a*x**S(2)) - S(3)*c*sqrt(c/(a + b*x**S(2)))*(a + b*x**S(2))/(S(2)*a**S(2)*x**S(2)) + S(3)*b*c*sqrt(c/(a + b*x**S(2)))*sqrt(a + b*x**S(2))*atanh(sqrt(a + b*x**S(2))/sqrt(a))/(S(2)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(c*(a + b*x**S(2))**S(3))**(S(3)/2), x), x, -S(21)*a**S(6)*c*sqrt(c*(a + b*x**S(2))**S(3))*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(1024)*b**(S(3)/2)*(a + b*x**S(2))**(S(3)/2)) + S(21)*a**S(5)*c*x*sqrt(c*(a + b*x**S(2))**S(3))/(S(1024)*b*(a + b*x**S(2))) + S(21)*a**S(4)*c*x**S(3)*sqrt(c*(a + b*x**S(2))**S(3))/(S(512)*(a + b*x**S(2))) + S(7)*a**S(3)*c*x**S(3)*sqrt(c*(a + b*x**S(2))**S(3))/S(128) + S(21)*a**S(2)*c*x**S(3)*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))/S(320) + S(3)*a*c*x**S(3)*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(2)/S(40) + c*x**S(3)*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(3)/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(c*(a + b*x**S(2))**S(3))**(S(3)/2), x), x, c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(4)/(S(11)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*(a + b*x**S(2))**S(3))**(S(3)/2), x), x, S(63)*a**S(5)*c*sqrt(c*(a + b*x**S(2))**S(3))*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(256)*sqrt(b)*(a + b*x**S(2))**(S(3)/2)) + S(63)*a**S(4)*c*x*sqrt(c*(a + b*x**S(2))**S(3))/(S(256)*(a + b*x**S(2))) + S(21)*a**S(3)*c*x*sqrt(c*(a + b*x**S(2))**S(3))/S(128) + S(21)*a**S(2)*c*x*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))/S(160) + S(9)*a*c*x*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(2)/S(80) + c*x*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(3)/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*(a + b*x**S(2))**S(3))**(S(3)/2)/x, x), x, -a**(S(9)/2)*c*sqrt(c*(a + b*x**S(2))**S(3))*atanh(sqrt(a + b*x**S(2))/sqrt(a))/(a + b*x**S(2))**(S(3)/2) + a**S(4)*c*sqrt(c*(a + b*x**S(2))**S(3))/(a + b*x**S(2)) + a**S(3)*c*sqrt(c*(a + b*x**S(2))**S(3))/S(3) + a**S(2)*c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))/S(5) + a*c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(2)/S(7) + c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(3)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*(a + b*x**S(2))**S(3))**(S(3)/2)/x**S(2), x), x, S(315)*a**S(4)*sqrt(b)*c*sqrt(c*(a + b*x**S(2))**S(3))*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(128)*(a + b*x**S(2))**(S(3)/2)) + S(315)*a**S(3)*b*c*x*sqrt(c*(a + b*x**S(2))**S(3))/(S(128)*(a + b*x**S(2))) + S(105)*a**S(2)*b*c*x*sqrt(c*(a + b*x**S(2))**S(3))/S(64) + S(21)*a*b*c*x*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))/S(16) + S(9)*b*c*x*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(2)/S(8) - c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(3)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*(a + b*x**S(2))**S(3))**(S(3)/2)/x**S(3), x), x, -S(9)*a**(S(7)/2)*b*c*sqrt(c*(a + b*x**S(2))**S(3))*atanh(sqrt(a + b*x**S(2))/sqrt(a))/(S(2)*(a + b*x**S(2))**(S(3)/2)) + S(9)*a**S(3)*b*c*sqrt(c*(a + b*x**S(2))**S(3))/(S(2)*(a + b*x**S(2))) + S(3)*a**S(2)*b*c*sqrt(c*(a + b*x**S(2))**S(3))/S(2) + S(9)*a*b*c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))/S(10) + S(9)*b*c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(2)/S(14) - c*sqrt(c*(a + b*x**S(2))**S(3))*(a + b*x**S(2))**S(3)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_secant.py000066400000000000000000002663251412543434000262660ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.utility_function import ( sympy_op_factory, Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf, exp, log) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec) from sympy import pi as Pi from sympy.integrals.rubi.rubi import rubi_integrate a, b, c, d, e, f, m, n, x, u , k, p, r, s, t, i, j= symbols('a b c d e f m n x u k p r s t i j') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F', ) def test_1(): assert rubi_test(rubi_integrate(sec(a + b*x), x), x, atanh(sin(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(2), x), x, tan(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3), x), x, tan(a + b*x)*sec(a + b*x)/(S(2)*b) + atanh(sin(a + b*x))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(4), x), x, tan(a + b*x)**S(3)/(S(3)*b) + tan(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(5), x), x, tan(a + b*x)*sec(a + b*x)**S(3)/(S(4)*b) + S(3)*tan(a + b*x)*sec(a + b*x)/(S(8)*b) + S(3)*atanh(sin(a + b*x))/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(6), x), x, tan(a + b*x)**S(5)/(S(5)*b) + S(2)*tan(a + b*x)**S(3)/(S(3)*b) + tan(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(7), x), x, tan(a + b*x)*sec(a + b*x)**S(5)/(S(6)*b) + S(5)*tan(a + b*x)*sec(a + b*x)**S(3)/(S(24)*b) + S(5)*tan(a + b*x)*sec(a + b*x)/(S(16)*b) + S(5)*atanh(sin(a + b*x))/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(8), x), x, tan(a + b*x)**S(7)/(S(7)*b) + S(3)*tan(a + b*x)**S(5)/(S(5)*b) + tan(a + b*x)**S(3)/b + tan(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(7)/2), x), x, -S(6)*EllipticE(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/(S(5)*b) + S(2)*sin(a + b*x)*sec(a + b*x)**(S(5)/2)/(S(5)*b) + S(6)*sin(a + b*x)*sqrt(sec(a + b*x))/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(5)/2), x), x, S(2)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/(S(3)*b) + S(2)*sin(a + b*x)*sec(a + b*x)**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(3)/2), x), x, -S(2)*EllipticE(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/b + S(2)*sin(a + b*x)*sqrt(sec(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sec(a + b*x)), x), x, S(2)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sec(a + b*x)), x), x, S(2)*EllipticE(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(-3)/2), x), x, S(2)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/(S(3)*b) + S(2)*sin(a + b*x)/(S(3)*b*sqrt(sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(-5)/2), x), x, S(6)*EllipticE(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/(S(5)*b) + S(2)*sin(a + b*x)/(S(5)*b*sec(a + b*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(-7)/2), x), x, S(10)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))*sqrt(sec(a + b*x))/(S(21)*b) + S(10)*sin(a + b*x)/(S(21)*b*sqrt(sec(a + b*x))) + S(2)*sin(a + b*x)/(S(7)*b*sec(a + b*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(7)/2), x), x, -S(6)*c**S(4)*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*sqrt(c*sec(a + b*x))*sqrt(cos(a + b*x))) + S(6)*c**S(3)*sqrt(c*sec(a + b*x))*sin(a + b*x)/(S(5)*b) + S(2)*c*(c*sec(a + b*x))**(S(5)/2)*sin(a + b*x)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2), x), x, S(2)*c**S(2)*sqrt(c*sec(a + b*x))*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(3)*b) + S(2)*c*(c*sec(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2), x), x, -S(2)*c**S(2)*EllipticE(a/S(2) + b*x/S(2), S(2))/(b*sqrt(c*sec(a + b*x))*sqrt(cos(a + b*x))) + S(2)*c*sqrt(c*sec(a + b*x))*sin(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x)), x), x, S(2)*sqrt(c*sec(a + b*x))*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(c*sec(a + b*x)), x), x, S(2)*EllipticE(a/S(2) + b*x/S(2), S(2))/(b*sqrt(c*sec(a + b*x))*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(-3)/2), x), x, S(2)*sin(a + b*x)/(S(3)*b*c*sqrt(c*sec(a + b*x))) + S(2)*sqrt(c*sec(a + b*x))*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(3)*b*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(-5)/2), x), x, S(2)*sin(a + b*x)/(S(5)*b*c*(c*sec(a + b*x))**(S(3)/2)) + S(6)*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*c**S(2)*sqrt(c*sec(a + b*x))*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(-7)/2), x), x, S(2)*sin(a + b*x)/(S(7)*b*c*(c*sec(a + b*x))**(S(5)/2)) + S(10)*sin(a + b*x)/(S(21)*b*c**S(3)*sqrt(c*sec(a + b*x))) + S(10)*sqrt(c*sec(a + b*x))*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(21)*b*c**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(4)/3), x), x, S(3)*Hypergeometric2F1(S(-1)/6, S(1)/2, S(5)/6, cos(a + b*x)**S(2))*sin(a + b*x)*sec(a + b*x)**(S(1)/3)/(b*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(2)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/6, S(1)/2, S(7)/6, cos(a + b*x)**S(2))*sin(a + b*x)/(b*sqrt(sin(a + b*x)**S(2))*sec(a + b*x)**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(1)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/3, S(1)/2, S(4)/3, cos(a + b*x)**S(2))*sin(a + b*x)/(S(2)*b*sqrt(sin(a + b*x)**S(2))*sec(a + b*x)**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(-1)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/2, S(2)/3, S(5)/3, cos(a + b*x)**S(2))*sin(a + b*x)/(S(4)*b*sqrt(sin(a + b*x)**S(2))*sec(a + b*x)**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(-2)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/2, S(5)/6, S(11)/6, cos(a + b*x)**S(2))*sin(a + b*x)/(S(5)*b*sqrt(sin(a + b*x)**S(2))*sec(a + b*x)**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**(S(-4)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/2, S(7)/6, S(13)/6, cos(a + b*x)**S(2))*sin(a + b*x)/(S(7)*b*sqrt(sin(a + b*x)**S(2))*sec(a + b*x)**(S(7)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(4)/3), x), x, S(3)*c*(c*sec(a + b*x))**(S(1)/3)*Hypergeometric2F1(S(-1)/6, S(1)/2, S(5)/6, cos(a + b*x)**S(2))*sin(a + b*x)/(b*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(2)/3), x), x, -S(3)*c*Hypergeometric2F1(S(1)/6, S(1)/2, S(7)/6, cos(a + b*x)**S(2))*sin(a + b*x)/(b*(c*sec(a + b*x))**(S(1)/3)*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(1)/3), x), x, -S(3)*c*Hypergeometric2F1(S(1)/3, S(1)/2, S(4)/3, cos(a + b*x)**S(2))*sin(a + b*x)/(S(2)*b*(c*sec(a + b*x))**(S(2)/3)*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(-1)/3), x), x, -S(3)*c*Hypergeometric2F1(S(1)/2, S(2)/3, S(5)/3, cos(a + b*x)**S(2))*sin(a + b*x)/(S(4)*b*(c*sec(a + b*x))**(S(4)/3)*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(-2)/3), x), x, -S(3)*c*Hypergeometric2F1(S(1)/2, S(5)/6, S(11)/6, cos(a + b*x)**S(2))*sin(a + b*x)/(S(5)*b*(c*sec(a + b*x))**(S(5)/3)*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(-4)/3), x), x, -S(3)*c*Hypergeometric2F1(S(1)/2, S(7)/6, S(13)/6, cos(a + b*x)**S(2))*sin(a + b*x)/(S(7)*b*(c*sec(a + b*x))**(S(7)/3)*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**n, x), x, -Hypergeometric2F1(S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(a + b*x)**S(2))*sin(a + b*x)*sec(a + b*x)**(n + S(-1))/(b*(-n + S(1))*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**n, x), x, -c*(c*sec(a + b*x))**(n + S(-1))*Hypergeometric2F1(S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(a + b*x)**S(2))*sin(a + b*x)/(b*(-n + S(1))*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sec(x)**S(2))**(S(7)/2), x), x, (sec(x)**S(2))**(S(5)/2)*tan(x)/S(6) + S(5)*(sec(x)**S(2))**(S(3)/2)*tan(x)/S(24) + S(5)*sqrt(sec(x)**S(2))*tan(x)/S(16) + S(5)*asinh(tan(x))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sec(x)**S(2))**(S(5)/2), x), x, (sec(x)**S(2))**(S(3)/2)*tan(x)/S(4) + S(3)*sqrt(sec(x)**S(2))*tan(x)/S(8) + S(3)*asinh(tan(x))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sec(x)**S(2))**(S(3)/2), x), x, sqrt(sec(x)**S(2))*tan(x)/S(2) + asinh(tan(x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sec(x)**S(2)), x), x, asinh(tan(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sec(x)**S(2)), x), x, tan(x)/sqrt(sec(x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sec(x)**S(2))**(S(-3)/2), x), x, S(2)*tan(x)/(S(3)*sqrt(sec(x)**S(2))) + tan(x)/(S(3)*(sec(x)**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sec(x)**S(2))**(S(-5)/2), x), x, S(8)*tan(x)/(S(15)*sqrt(sec(x)**S(2))) + S(4)*tan(x)/(S(15)*(sec(x)**S(2))**(S(3)/2)) + tan(x)/(S(5)*(sec(x)**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sec(x)**S(2))**(S(-7)/2), x), x, S(16)*tan(x)/(S(35)*sqrt(sec(x)**S(2))) + S(8)*tan(x)/(S(35)*(sec(x)**S(2))**(S(3)/2)) + S(6)*tan(x)/(S(35)*(sec(x)**S(2))**(S(5)/2)) + tan(x)/(S(7)*(sec(x)**S(2))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(2))**(S(7)/2), x), x, S(5)*a**(S(7)/2)*atanh(sqrt(a)*tan(x)/sqrt(a*sec(x)**S(2)))/S(16) + S(5)*a**S(3)*sqrt(a*sec(x)**S(2))*tan(x)/S(16) + S(5)*a**S(2)*(a*sec(x)**S(2))**(S(3)/2)*tan(x)/S(24) + a*(a*sec(x)**S(2))**(S(5)/2)*tan(x)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(2))**(S(5)/2), x), x, S(3)*a**(S(5)/2)*atanh(sqrt(a)*tan(x)/sqrt(a*sec(x)**S(2)))/S(8) + S(3)*a**S(2)*sqrt(a*sec(x)**S(2))*tan(x)/S(8) + a*(a*sec(x)**S(2))**(S(3)/2)*tan(x)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(2))**(S(3)/2), x), x, a**(S(3)/2)*atanh(sqrt(a)*tan(x)/sqrt(a*sec(x)**S(2)))/S(2) + a*sqrt(a*sec(x)**S(2))*tan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*sec(x)**S(2)), x), x, sqrt(a)*atanh(sqrt(a)*tan(x)/sqrt(a*sec(x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*sec(x)**S(2)), x), x, tan(x)/sqrt(a*sec(x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(2))**(S(-3)/2), x), x, tan(x)/(S(3)*(a*sec(x)**S(2))**(S(3)/2)) + S(2)*tan(x)/(S(3)*a*sqrt(a*sec(x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(2))**(S(-5)/2), x), x, tan(x)/(S(5)*(a*sec(x)**S(2))**(S(5)/2)) + S(4)*tan(x)/(S(15)*a*(a*sec(x)**S(2))**(S(3)/2)) + S(8)*tan(x)/(S(15)*a**S(2)*sqrt(a*sec(x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(2))**(S(-7)/2), x), x, tan(x)/(S(7)*(a*sec(x)**S(2))**(S(7)/2)) + S(6)*tan(x)/(S(35)*a*(a*sec(x)**S(2))**(S(5)/2)) + S(8)*tan(x)/(S(35)*a**S(2)*(a*sec(x)**S(2))**(S(3)/2)) + S(16)*tan(x)/(S(35)*a**S(3)*sqrt(a*sec(x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(3))**(S(5)/2), x), x, -S(154)*a**S(2)*sqrt(a*sec(x)**S(3))*EllipticE(x/S(2), S(2))*cos(x)**(S(3)/2)/S(195) + S(154)*a**S(2)*sqrt(a*sec(x)**S(3))*sin(x)*cos(x)/S(195) + S(2)*a**S(2)*sqrt(a*sec(x)**S(3))*tan(x)*sec(x)**S(4)/S(13) + S(22)*a**S(2)*sqrt(a*sec(x)**S(3))*tan(x)*sec(x)**S(2)/S(117) + S(154)*a**S(2)*sqrt(a*sec(x)**S(3))*tan(x)/S(585), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(3))**(S(3)/2), x), x, S(10)*a*sqrt(a*sec(x)**S(3))*EllipticF(x/S(2), S(2))*cos(x)**(S(3)/2)/S(21) + S(10)*a*sqrt(a*sec(x)**S(3))*sin(x)/S(21) + S(2)*a*sqrt(a*sec(x)**S(3))*tan(x)*sec(x)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*sec(x)**S(3)), x), x, -S(2)*sqrt(a*sec(x)**S(3))*EllipticE(x/S(2), S(2))*cos(x)**(S(3)/2) + S(2)*sqrt(a*sec(x)**S(3))*sin(x)*cos(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*sec(x)**S(3)), x), x, S(2)*EllipticF(x/S(2), S(2))/(S(3)*sqrt(a*sec(x)**S(3))*cos(x)**(S(3)/2)) + S(2)*tan(x)/(S(3)*sqrt(a*sec(x)**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(3))**(S(-3)/2), x), x, S(14)*EllipticE(x/S(2), S(2))/(S(15)*a*sqrt(a*sec(x)**S(3))*cos(x)**(S(3)/2)) + S(2)*sin(x)*cos(x)**S(2)/(S(9)*a*sqrt(a*sec(x)**S(3))) + S(14)*sin(x)/(S(45)*a*sqrt(a*sec(x)**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(3))**(S(-5)/2), x), x, S(26)*EllipticF(x/S(2), S(2))/(S(77)*a**S(2)*sqrt(a*sec(x)**S(3))*cos(x)**(S(3)/2)) + S(2)*sin(x)*cos(x)**S(5)/(S(15)*a**S(2)*sqrt(a*sec(x)**S(3))) + S(26)*sin(x)*cos(x)**S(3)/(S(165)*a**S(2)*sqrt(a*sec(x)**S(3))) + S(78)*sin(x)*cos(x)/(S(385)*a**S(2)*sqrt(a*sec(x)**S(3))) + S(26)*tan(x)/(S(77)*a**S(2)*sqrt(a*sec(x)**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(4))**(S(7)/2), x), x, a**S(3)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(11)/S(13) + S(6)*a**S(3)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(9)/S(11) + S(5)*a**S(3)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(7)/S(3) + S(20)*a**S(3)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(5)/S(7) + S(3)*a**S(3)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(3) + S(2)*a**S(3)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x) + a**S(3)*sqrt(a*sec(x)**S(4))*sin(x)*cos(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(4))**(S(5)/2), x), x, a**S(2)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(7)/S(9) + S(4)*a**S(2)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(5)/S(7) + S(6)*a**S(2)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(3)/S(5) + S(4)*a**S(2)*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)/S(3) + a**S(2)*sqrt(a*sec(x)**S(4))*sin(x)*cos(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(4))**(S(3)/2), x), x, a*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)**S(3)/S(5) + S(2)*a*sqrt(a*sec(x)**S(4))*sin(x)**S(2)*tan(x)/S(3) + a*sqrt(a*sec(x)**S(4))*sin(x)*cos(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*sec(x)**S(4)), x), x, sqrt(a*sec(x)**S(4))*sin(x)*cos(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*sec(x)**S(4)), x), x, x*sec(x)**S(2)/(S(2)*sqrt(a*sec(x)**S(4))) + tan(x)/(S(2)*sqrt(a*sec(x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(4))**(S(-3)/2), x), x, S(5)*x*sec(x)**S(2)/(S(16)*a*sqrt(a*sec(x)**S(4))) + sin(x)*cos(x)**S(3)/(S(6)*a*sqrt(a*sec(x)**S(4))) + S(5)*sin(x)*cos(x)/(S(24)*a*sqrt(a*sec(x)**S(4))) + S(5)*tan(x)/(S(16)*a*sqrt(a*sec(x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(x)**S(4))**(S(-5)/2), x), x, S(63)*x*sec(x)**S(2)/(S(256)*a**S(2)*sqrt(a*sec(x)**S(4))) + sin(x)*cos(x)**S(7)/(S(10)*a**S(2)*sqrt(a*sec(x)**S(4))) + S(9)*sin(x)*cos(x)**S(5)/(S(80)*a**S(2)*sqrt(a*sec(x)**S(4))) + S(21)*sin(x)*cos(x)**S(3)/(S(160)*a**S(2)*sqrt(a*sec(x)**S(4))) + S(21)*sin(x)*cos(x)/(S(128)*a**S(2)*sqrt(a*sec(x)**S(4))) + S(63)*tan(x)/(S(256)*a**S(2)*sqrt(a*sec(x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(((b*sec(c + d*x))**p)**n, x), x, -((b*sec(c + d*x))**p)**n*Hypergeometric2F1(S(1)/2, -n*p/S(2) + S(1)/2, -n*p/S(2) + S(3)/2, cos(c + d*x)**S(2))*sin(c + d*x)*cos(c + d*x)/(d*(-n*p + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*sec(c + d*x))**p)**n, x), x, -(a*(b*sec(c + d*x))**p)**n*Hypergeometric2F1(S(1)/2, -n*p/S(2) + S(1)/2, -n*p/S(2) + S(3)/2, cos(c + d*x)**S(2))*sin(c + d*x)*cos(c + d*x)/(d*(-n*p + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x)**S(4), x), x, S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*d) + S(10)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(21)*b*d) + S(2)*(b*sec(c + d*x))**(S(7)/2)*sin(c + d*x)/(S(7)*b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x)**S(3), x), x, -S(6)*b*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(6)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(5)*d) + S(2)*(b*sec(c + d*x))**(S(5)/2)*sin(c + d*x)/(S(5)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x)**S(2), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*d) + S(2)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(3)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x), x), x, -S(2)*b*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x)), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*cos(c + d*x), x), x, S(2)*b*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*cos(c + d*x)**S(2), x), x, S(2)*b*sin(c + d*x)/(S(3)*d*sqrt(b*sec(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*cos(c + d*x)**S(3), x), x, S(2)*b**S(2)*sin(c + d*x)/(S(5)*d*(b*sec(c + d*x))**(S(3)/2)) + S(6)*b*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*cos(c + d*x)**S(4), x), x, S(2)*b**S(3)*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(5)/2)) + S(10)*b*sin(c + d*x)/(S(21)*d*sqrt(b*sec(c + d*x))) + S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*cos(c + d*x)**S(5), x), x, S(2)*b**S(4)*sin(c + d*x)/(S(9)*d*(b*sec(c + d*x))**(S(7)/2)) + S(14)*b**S(2)*sin(c + d*x)/(S(45)*d*(b*sec(c + d*x))**(S(3)/2)) + S(14)*b*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(15)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x)**S(3), x), x, S(10)*b*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*d) + S(10)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(21)*d) + S(2)*(b*sec(c + d*x))**(S(7)/2)*sin(c + d*x)/(S(7)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x)**S(2), x), x, -S(6)*b**S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(6)*b*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(5)*d) + S(2)*(b*sec(c + d*x))**(S(5)/2)*sin(c + d*x)/(S(5)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x), x), x, S(2)*b*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*d) + S(2)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2), x), x, -S(2)*b**S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(2)*b*sqrt(b*sec(c + d*x))*sin(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*cos(c + d*x), x), x, S(2)*b*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*cos(c + d*x)**S(2), x), x, S(2)*b**S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*cos(c + d*x)**S(3), x), x, S(2)*b**S(2)*sin(c + d*x)/(S(3)*d*sqrt(b*sec(c + d*x))) + S(2)*b*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*cos(c + d*x)**S(4), x), x, S(2)*b**S(3)*sin(c + d*x)/(S(5)*d*(b*sec(c + d*x))**(S(3)/2)) + S(6)*b**S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*cos(c + d*x)**S(5), x), x, S(2)*b**S(4)*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(5)/2)) + S(10)*b**S(2)*sin(c + d*x)/(S(21)*d*sqrt(b*sec(c + d*x))) + S(10)*b*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*cos(c + d*x)**S(6), x), x, S(2)*b**S(5)*sin(c + d*x)/(S(9)*d*(b*sec(c + d*x))**(S(7)/2)) + S(14)*b**S(3)*sin(c + d*x)/(S(45)*d*(b*sec(c + d*x))**(S(3)/2)) + S(14)*b**S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(15)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*sec(c + d*x)**S(2), x), x, S(10)*b**S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*d) + S(10)*b*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(21)*d) + S(2)*(b*sec(c + d*x))**(S(7)/2)*sin(c + d*x)/(S(7)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*sec(c + d*x), x), x, -S(6)*b**S(3)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(6)*b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(5)*d) + S(2)*(b*sec(c + d*x))**(S(5)/2)*sin(c + d*x)/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2), x), x, S(2)*b**S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*d) + S(2)*b*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*cos(c + d*x), x), x, -S(2)*b**S(3)*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(2)*b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*cos(c + d*x)**S(2), x), x, S(2)*b**S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*cos(c + d*x)**S(3), x), x, S(2)*b**S(3)*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*cos(c + d*x)**S(4), x), x, S(2)*b**S(3)*sin(c + d*x)/(S(3)*d*sqrt(b*sec(c + d*x))) + S(2)*b**S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*cos(c + d*x)**S(5), x), x, S(2)*b**S(4)*sin(c + d*x)/(S(5)*d*(b*sec(c + d*x))**(S(3)/2)) + S(6)*b**S(3)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*cos(c + d*x)**S(6), x), x, S(2)*b**S(5)*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(5)/2)) + S(10)*b**S(3)*sin(c + d*x)/(S(21)*d*sqrt(b*sec(c + d*x))) + S(10)*b**S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*cos(c + d*x)**S(7), x), x, S(2)*b**S(6)*sin(c + d*x)/(S(9)*d*(b*sec(c + d*x))**(S(7)/2)) + S(14)*b**S(4)*sin(c + d*x)/(S(45)*d*(b*sec(c + d*x))**(S(3)/2)) + S(14)*b**S(3)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(15)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(7)/2), x), x, -S(6)*b**S(4)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(6)*b**S(3)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(5)*d) + S(2)*b*(b*sec(c + d*x))**(S(5)/2)*sin(c + d*x)/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(5)/sqrt(b*sec(c + d*x)), x), x, S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*b*d) + S(10)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(21)*b**S(2)*d) + S(2)*(b*sec(c + d*x))**(S(7)/2)*sin(c + d*x)/(S(7)*b**S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(4)/sqrt(b*sec(c + d*x)), x), x, -S(6)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(6)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(5)*b*d) + S(2)*(b*sec(c + d*x))**(S(5)/2)*sin(c + d*x)/(S(5)*b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(3)/sqrt(b*sec(c + d*x)), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*b*d) + S(2)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(3)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(2)/sqrt(b*sec(c + d*x)), x), x, -S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)/sqrt(b*sec(c + d*x)), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*sec(c + d*x)), x), x, S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)/sqrt(b*sec(c + d*x)), x), x, S(2)*sin(c + d*x)/(S(3)*d*sqrt(b*sec(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(2)/sqrt(b*sec(c + d*x)), x), x, S(2)*b*sin(c + d*x)/(S(5)*d*(b*sec(c + d*x))**(S(3)/2)) + S(6)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(3)/sqrt(b*sec(c + d*x)), x), x, S(2)*b**S(2)*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(5)/2)) + S(10)*sin(c + d*x)/(S(21)*d*sqrt(b*sec(c + d*x))) + S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(4)/sqrt(b*sec(c + d*x)), x), x, S(2)*b**S(3)*sin(c + d*x)/(S(9)*d*(b*sec(c + d*x))**(S(7)/2)) + S(14)*b*sin(c + d*x)/(S(45)*d*(b*sec(c + d*x))**(S(3)/2)) + S(14)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(15)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(6)/(b*sec(c + d*x))**(S(3)/2), x), x, S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*b**S(2)*d) + S(10)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(21)*b**S(3)*d) + S(2)*(b*sec(c + d*x))**(S(7)/2)*sin(c + d*x)/(S(7)*b**S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(5)/(b*sec(c + d*x))**(S(3)/2), x), x, -S(6)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*b*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(6)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(5)*b**S(2)*d) + S(2)*(b*sec(c + d*x))**(S(5)/2)*sin(c + d*x)/(S(5)*b**S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(4)/(b*sec(c + d*x))**(S(3)/2), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*b**S(2)*d) + S(2)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(3)*b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(3)/(b*sec(c + d*x))**(S(3)/2), x), x, -S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(b*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(2)/(b*sec(c + d*x))**(S(3)/2), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)/(b*sec(c + d*x))**(S(3)/2), x), x, S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(b*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(-3)/2), x), x, S(2)*sin(c + d*x)/(S(3)*b*d*sqrt(b*sec(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)/(b*sec(c + d*x))**(S(3)/2), x), x, S(2)*sin(c + d*x)/(S(5)*d*(b*sec(c + d*x))**(S(3)/2)) + S(6)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*b*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(2)/(b*sec(c + d*x))**(S(3)/2), x), x, S(2)*b*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(5)/2)) + S(10)*sin(c + d*x)/(S(21)*b*d*sqrt(b*sec(c + d*x))) + S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*b**S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(3)/(b*sec(c + d*x))**(S(3)/2), x), x, S(2)*b**S(2)*sin(c + d*x)/(S(9)*d*(b*sec(c + d*x))**(S(7)/2)) + S(14)*sin(c + d*x)/(S(45)*d*(b*sec(c + d*x))**(S(3)/2)) + S(14)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(15)*b*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(7)/(b*sec(c + d*x))**(S(5)/2), x), x, S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*b**S(3)*d) + S(10)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(21)*b**S(4)*d) + S(2)*(b*sec(c + d*x))**(S(7)/2)*sin(c + d*x)/(S(7)*b**S(6)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(6)/(b*sec(c + d*x))**(S(5)/2), x), x, -S(6)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*b**S(2)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(6)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(5)*b**S(3)*d) + S(2)*(b*sec(c + d*x))**(S(5)/2)*sin(c + d*x)/(S(5)*b**S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(5)/(b*sec(c + d*x))**(S(5)/2), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*b**S(3)*d) + S(2)*(b*sec(c + d*x))**(S(3)/2)*sin(c + d*x)/(S(3)*b**S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(4)/(b*sec(c + d*x))**(S(5)/2), x), x, -S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(b**S(2)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(3)/(b*sec(c + d*x))**(S(5)/2), x), x, S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(2)/(b*sec(c + d*x))**(S(5)/2), x), x, S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/(b**S(2)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)/(b*sec(c + d*x))**(S(5)/2), x), x, S(2)*sin(c + d*x)/(S(3)*b**S(2)*d*sqrt(b*sec(c + d*x))) + S(2)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(3)*b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(-5)/2), x), x, S(2)*sin(c + d*x)/(S(5)*b*d*(b*sec(c + d*x))**(S(3)/2)) + S(6)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(5)*b**S(2)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)/(b*sec(c + d*x))**(S(5)/2), x), x, S(2)*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(5)/2)) + S(10)*sin(c + d*x)/(S(21)*b**S(2)*d*sqrt(b*sec(c + d*x))) + S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*b**S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(2)/(b*sec(c + d*x))**(S(5)/2), x), x, S(2)*b*sin(c + d*x)/(S(9)*d*(b*sec(c + d*x))**(S(7)/2)) + S(14)*sin(c + d*x)/(S(45)*b*d*(b*sec(c + d*x))**(S(3)/2)) + S(14)*EllipticE(c/S(2) + d*x/S(2), S(2))/(S(15)*b**S(2)*d*sqrt(b*sec(c + d*x))*sqrt(cos(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(-7)/2), x), x, S(2)*sin(c + d*x)/(S(7)*b*d*(b*sec(c + d*x))**(S(5)/2)) + S(10)*sin(c + d*x)/(S(21)*b**S(3)*d*sqrt(b*sec(c + d*x))) + S(10)*sqrt(b*sec(c + d*x))*EllipticF(c/S(2) + d*x/S(2), S(2))*sqrt(cos(c + d*x))/(S(21)*b**S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(9)/2), x), x, sqrt(b*sec(c + d*x))*sin(c + d*x)*sec(c + d*x)**(S(7)/2)/(S(4)*d) + S(3)*sqrt(b*sec(c + d*x))*sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(S(8)*d) + S(3)*sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(S(8)*d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(7)/2), x), x, sqrt(b*sec(c + d*x))*sin(c + d*x)**S(3)*sec(c + d*x)**(S(5)/2)/(S(3)*d) + sqrt(b*sec(c + d*x))*sin(c + d*x)*sqrt(sec(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(5)/2), x), x, sqrt(b*sec(c + d*x))*sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(S(2)*d) + sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(S(2)*d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(3)/2), x), x, sqrt(b*sec(c + d*x))*sin(c + d*x)*sqrt(sec(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))*sqrt(sec(c + d*x)), x), x, sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))/sqrt(sec(c + d*x)), x), x, x*sqrt(b*sec(c + d*x))/sqrt(sec(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))/sec(c + d*x)**(S(3)/2), x), x, sqrt(b*sec(c + d*x))*sin(c + d*x)/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))/sec(c + d*x)**(S(5)/2), x), x, x*sqrt(b*sec(c + d*x))/(S(2)*sqrt(sec(c + d*x))) + sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(2)*d*sec(c + d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))/sec(c + d*x)**(S(7)/2), x), x, -sqrt(b*sec(c + d*x))*sin(c + d*x)**S(3)/(S(3)*d*sqrt(sec(c + d*x))) + sqrt(b*sec(c + d*x))*sin(c + d*x)/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(c + d*x))/sec(c + d*x)**(S(9)/2), x), x, S(3)*x*sqrt(b*sec(c + d*x))/(S(8)*sqrt(sec(c + d*x))) + S(3)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(8)*d*sec(c + d*x)**(S(3)/2)) + sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(4)*d*sec(c + d*x)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x)**(S(7)/2), x), x, b*sqrt(b*sec(c + d*x))*sin(c + d*x)*sec(c + d*x)**(S(7)/2)/(S(4)*d) + S(3)*b*sqrt(b*sec(c + d*x))*sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(S(8)*d) + S(3)*b*sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(S(8)*d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x)**(S(5)/2), x), x, b*sqrt(b*sec(c + d*x))*sin(c + d*x)**S(3)*sec(c + d*x)**(S(5)/2)/(S(3)*d) + b*sqrt(b*sec(c + d*x))*sin(c + d*x)*sqrt(sec(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x)**(S(3)/2), x), x, b*sqrt(b*sec(c + d*x))*sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(S(2)*d) + b*sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(S(2)*d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)*sqrt(sec(c + d*x)), x), x, b*sqrt(b*sec(c + d*x))*sin(c + d*x)*sqrt(sec(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)/sqrt(sec(c + d*x)), x), x, b*sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)/sec(c + d*x)**(S(3)/2), x), x, b*x*sqrt(b*sec(c + d*x))/sqrt(sec(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)/sec(c + d*x)**(S(5)/2), x), x, b*sqrt(b*sec(c + d*x))*sin(c + d*x)/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)/sec(c + d*x)**(S(7)/2), x), x, b*x*sqrt(b*sec(c + d*x))/(S(2)*sqrt(sec(c + d*x))) + b*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(2)*d*sec(c + d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)/sec(c + d*x)**(S(9)/2), x), x, -b*sqrt(b*sec(c + d*x))*sin(c + d*x)**S(3)/(S(3)*d*sqrt(sec(c + d*x))) + b*sqrt(b*sec(c + d*x))*sin(c + d*x)/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(3)/2)/sec(c + d*x)**(S(11)/2), x), x, S(3)*b*x*sqrt(b*sec(c + d*x))/(S(8)*sqrt(sec(c + d*x))) + S(3)*b*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(8)*d*sec(c + d*x)**(S(3)/2)) + b*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(4)*d*sec(c + d*x)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*sec(c + d*x)**(S(7)/2), x), x, b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)**S(5)*sec(c + d*x)**(S(9)/2)/(S(5)*d) + S(2)*b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)**S(3)*sec(c + d*x)**(S(5)/2)/(S(3)*d) + b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)*sqrt(sec(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*sec(c + d*x)**(S(3)/2), x), x, b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)**S(3)*sec(c + d*x)**(S(5)/2)/(S(3)*d) + b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)*sqrt(sec(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)*sqrt(sec(c + d*x)), x), x, b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(S(2)*d) + b**S(2)*sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(S(2)*d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)/sqrt(sec(c + d*x)), x), x, b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)*sqrt(sec(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)/sec(c + d*x)**(S(3)/2), x), x, b**S(2)*sqrt(b*sec(c + d*x))*atanh(sin(c + d*x))/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)/sec(c + d*x)**(S(5)/2), x), x, b**S(2)*x*sqrt(b*sec(c + d*x))/sqrt(sec(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)/sec(c + d*x)**(S(7)/2), x), x, b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)/sec(c + d*x)**(S(9)/2), x), x, b**S(2)*x*sqrt(b*sec(c + d*x))/(S(2)*sqrt(sec(c + d*x))) + b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(S(2)*d*sec(c + d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(5)/2)/sec(c + d*x)**(S(11)/2), x), x, -b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)**S(3)/(S(3)*d*sqrt(sec(c + d*x))) + b**S(2)*sqrt(b*sec(c + d*x))*sin(c + d*x)/(d*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(7)/2)/sqrt(b*sec(c + d*x)), x), x, sin(c + d*x)*sec(c + d*x)**(S(5)/2)/(S(2)*d*sqrt(b*sec(c + d*x))) + atanh(sin(c + d*x))*sqrt(sec(c + d*x))/(S(2)*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(5)/2)/sqrt(b*sec(c + d*x)), x), x, sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(3)/2)/sqrt(b*sec(c + d*x)), x), x, atanh(sin(c + d*x))*sqrt(sec(c + d*x))/(d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sec(c + d*x))/sqrt(b*sec(c + d*x)), x), x, x*sqrt(sec(c + d*x))/sqrt(b*sec(c + d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(c + d*x))*sqrt(sec(c + d*x))), x), x, sin(c + d*x)*sqrt(sec(c + d*x))/(d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(3)/2)), x), x, x*sqrt(sec(c + d*x))/(S(2)*sqrt(b*sec(c + d*x))) + sin(c + d*x)/(S(2)*d*sqrt(b*sec(c + d*x))*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(5)/2)), x), x, -sin(c + d*x)**S(3)*sqrt(sec(c + d*x))/(S(3)*d*sqrt(b*sec(c + d*x))) + sin(c + d*x)*sqrt(sec(c + d*x))/(d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(9)/2)/(b*sec(c + d*x))**(S(3)/2), x), x, sin(c + d*x)*sec(c + d*x)**(S(5)/2)/(S(2)*b*d*sqrt(b*sec(c + d*x))) + atanh(sin(c + d*x))*sqrt(sec(c + d*x))/(S(2)*b*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(7)/2)/(b*sec(c + d*x))**(S(3)/2), x), x, sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(b*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(5)/2)/(b*sec(c + d*x))**(S(3)/2), x), x, atanh(sin(c + d*x))*sqrt(sec(c + d*x))/(b*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(3)/2)/(b*sec(c + d*x))**(S(3)/2), x), x, x*sqrt(sec(c + d*x))/(b*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sec(c + d*x))/(b*sec(c + d*x))**(S(3)/2), x), x, sin(c + d*x)*sqrt(sec(c + d*x))/(b*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*sec(c + d*x))**(S(3)/2)*sqrt(sec(c + d*x))), x), x, x*sqrt(sec(c + d*x))/(S(2)*b*sqrt(b*sec(c + d*x))) + sin(c + d*x)/(S(2)*b*d*sqrt(b*sec(c + d*x))*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x)**(S(3)/2)), x), x, -sin(c + d*x)**S(3)*sqrt(sec(c + d*x))/(S(3)*b*d*sqrt(b*sec(c + d*x))) + sin(c + d*x)*sqrt(sec(c + d*x))/(b*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*sec(c + d*x))**(S(3)/2)*sec(c + d*x)**(S(5)/2)), x), x, S(3)*x*sqrt(sec(c + d*x))/(S(8)*b*sqrt(b*sec(c + d*x))) + S(3)*sin(c + d*x)/(S(8)*b*d*sqrt(b*sec(c + d*x))*sqrt(sec(c + d*x))) + sin(c + d*x)/(S(4)*b*d*sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(11)/2)/(b*sec(c + d*x))**(S(5)/2), x), x, sin(c + d*x)*sec(c + d*x)**(S(5)/2)/(S(2)*b**S(2)*d*sqrt(b*sec(c + d*x))) + atanh(sin(c + d*x))*sqrt(sec(c + d*x))/(S(2)*b**S(2)*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(9)/2)/(b*sec(c + d*x))**(S(5)/2), x), x, sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(b**S(2)*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(7)/2)/(b*sec(c + d*x))**(S(5)/2), x), x, atanh(sin(c + d*x))*sqrt(sec(c + d*x))/(b**S(2)*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(5)/2)/(b*sec(c + d*x))**(S(5)/2), x), x, x*sqrt(sec(c + d*x))/(b**S(2)*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**(S(3)/2)/(b*sec(c + d*x))**(S(5)/2), x), x, sin(c + d*x)*sqrt(sec(c + d*x))/(b**S(2)*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sec(c + d*x))/(b*sec(c + d*x))**(S(5)/2), x), x, x*sqrt(sec(c + d*x))/(S(2)*b**S(2)*sqrt(b*sec(c + d*x))) + sin(c + d*x)/(S(2)*b**S(2)*d*sqrt(b*sec(c + d*x))*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*sec(c + d*x))**(S(5)/2)*sqrt(sec(c + d*x))), x), x, -sin(c + d*x)**S(3)*sqrt(sec(c + d*x))/(S(3)*b**S(2)*d*sqrt(b*sec(c + d*x))) + sin(c + d*x)*sqrt(sec(c + d*x))/(b**S(2)*d*sqrt(b*sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*sec(c + d*x))**(S(5)/2)*sec(c + d*x)**(S(3)/2)), x), x, S(3)*x*sqrt(sec(c + d*x))/(S(8)*b**S(2)*sqrt(b*sec(c + d*x))) + S(3)*sin(c + d*x)/(S(8)*b**S(2)*d*sqrt(b*sec(c + d*x))*sqrt(sec(c + d*x))) + sin(c + d*x)/(S(4)*b**S(2)*d*sqrt(b*sec(c + d*x))*sec(c + d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(1)/3)*sec(c + d*x)**S(2), x), x, S(3)*(b*sec(c + d*x))**(S(4)/3)*Hypergeometric2F1(S(-2)/3, S(1)/2, S(1)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(4)*b*d*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(1)/3)*sec(c + d*x), x), x, S(3)*(b*sec(c + d*x))**(S(1)/3)*Hypergeometric2F1(S(-1)/6, S(1)/2, S(5)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(d*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(1)/3), x), x, -S(3)*b*Hypergeometric2F1(S(1)/3, S(1)/2, S(4)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(2)*d*(b*sec(c + d*x))**(S(2)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(1)/3)*cos(c + d*x), x), x, -S(3)*b**S(2)*Hypergeometric2F1(S(1)/2, S(5)/6, S(11)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(S(5)*d*(b*sec(c + d*x))**(S(5)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(1)/3)*cos(c + d*x)**S(2), x), x, -S(3)*b**S(3)*Hypergeometric2F1(S(1)/2, S(4)/3, S(7)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(8)*d*(b*sec(c + d*x))**(S(8)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(4)/3)*sec(c + d*x)**S(2), x), x, S(3)*(b*sec(c + d*x))**(S(7)/3)*Hypergeometric2F1(S(-7)/6, S(1)/2, S(-1)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(S(7)*b*d*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(4)/3)*sec(c + d*x), x), x, S(3)*(b*sec(c + d*x))**(S(4)/3)*Hypergeometric2F1(S(-2)/3, S(1)/2, S(1)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(4)*d*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(4)/3), x), x, S(3)*b*(b*sec(c + d*x))**(S(1)/3)*Hypergeometric2F1(S(-1)/6, S(1)/2, S(5)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(d*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(4)/3)*cos(c + d*x), x), x, -S(3)*b**S(2)*Hypergeometric2F1(S(1)/3, S(1)/2, S(4)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(2)*d*(b*sec(c + d*x))**(S(2)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(4)/3)*cos(c + d*x)**S(2), x), x, -S(3)*b**S(3)*Hypergeometric2F1(S(1)/2, S(5)/6, S(11)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(S(5)*d*(b*sec(c + d*x))**(S(5)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(2)/(b*sec(c + d*x))**(S(1)/3), x), x, S(3)*(b*sec(c + d*x))**(S(2)/3)*Hypergeometric2F1(S(-1)/3, S(1)/2, S(2)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(2)*b*d*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)/(b*sec(c + d*x))**(S(1)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/6, S(1)/2, S(7)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(d*(b*sec(c + d*x))**(S(1)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(-1)/3), x), x, -S(3)*b*Hypergeometric2F1(S(1)/2, S(2)/3, S(5)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(4)*d*(b*sec(c + d*x))**(S(4)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)/(b*sec(c + d*x))**(S(1)/3), x), x, -S(3)*b**S(2)*Hypergeometric2F1(S(1)/2, S(7)/6, S(13)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(7)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(2)/(b*sec(c + d*x))**(S(1)/3), x), x, -S(3)*b**S(3)*Hypergeometric2F1(S(1)/2, S(5)/3, S(8)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(10)*d*(b*sec(c + d*x))**(S(10)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**S(2)/(b*sec(c + d*x))**(S(4)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/6, S(1)/2, S(7)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(b*d*(b*sec(c + d*x))**(S(1)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)/(b*sec(c + d*x))**(S(4)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/2, S(2)/3, S(5)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(4)*d*(b*sec(c + d*x))**(S(4)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(-4)/3), x), x, -S(3)*b*Hypergeometric2F1(S(1)/2, S(7)/6, S(13)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(S(7)*d*(b*sec(c + d*x))**(S(7)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)/(b*sec(c + d*x))**(S(4)/3), x), x, -S(3)*b**S(2)*Hypergeometric2F1(S(1)/2, S(5)/3, S(8)/3, cos(c + d*x)**S(2))*sin(c + d*x)/(S(10)*d*(b*sec(c + d*x))**(S(10)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(c + d*x)**S(2)/(b*sec(c + d*x))**(S(4)/3), x), x, -S(3)*b**S(3)*Hypergeometric2F1(S(1)/2, S(13)/6, S(19)/6, cos(c + d*x)**S(2))*sin(c + d*x)/(S(13)*d*(b*sec(c + d*x))**(S(13)/3)*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(4)/3)*sec(c + d*x)**m, x), x, S(3)*b*(b*sec(c + d*x))**(S(1)/3)*Hypergeometric2F1(S(1)/2, -m/S(2) + S(-1)/6, -m/S(2) + S(5)/6, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**m/(d*(S(3)*m + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(2)/3)*sec(c + d*x)**m, x), x, -S(3)*(b*sec(c + d*x))**(S(2)/3)*Hypergeometric2F1(S(1)/2, -m/S(2) + S(1)/6, -m/S(2) + S(7)/6, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**(m + S(-1))/(d*(-S(3)*m + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**(S(1)/3)*sec(c + d*x)**m, x), x, -S(3)*(b*sec(c + d*x))**(S(1)/3)*Hypergeometric2F1(S(1)/2, -m/S(2) + S(1)/3, -m/S(2) + S(4)/3, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**(m + S(-1))/(d*(-S(3)*m + S(2))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**m/(b*sec(c + d*x))**(S(1)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/2, -m/S(2) + S(2)/3, -m/S(2) + S(5)/3, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**(m + S(-1))/(d*(b*sec(c + d*x))**(S(1)/3)*(-S(3)*m + S(4))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**m/(b*sec(c + d*x))**(S(2)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/2, -m/S(2) + S(5)/6, -m/S(2) + S(11)/6, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**(m + S(-1))/(d*(b*sec(c + d*x))**(S(2)/3)*(-S(3)*m + S(5))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(c + d*x)**m/(b*sec(c + d*x))**(S(4)/3), x), x, -S(3)*Hypergeometric2F1(S(1)/2, -m/S(2) + S(7)/6, -m/S(2) + S(13)/6, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**(m + S(-2))/(b*d*(b*sec(c + d*x))**(S(1)/3)*(-S(3)*m + S(7))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*sec(c + d*x)**m, x), x, -(b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -m/S(2) - n/S(2) + S(1)/2, -m/S(2) - n/S(2) + S(3)/2, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**(m + S(-1))/(d*(-m - n + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*sec(c + d*x)**S(2), x), x, (b*sec(c + d*x))**(n + S(1))*Hypergeometric2F1(S(1)/2, -n/S(2) + S(-1)/2, -n/S(2) + S(1)/2, cos(c + d*x)**S(2))*sin(c + d*x)/(b*d*(n + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*sec(c + d*x), x), x, (b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -n/S(2), -n/S(2) + S(1), cos(c + d*x)**S(2))*sin(c + d*x)/(d*n*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n, x), x, -b*(b*sec(c + d*x))**(n + S(-1))*Hypergeometric2F1(S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-n + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*cos(c + d*x), x), x, -b**S(2)*(b*sec(c + d*x))**(n + S(-2))*Hypergeometric2F1(S(1)/2, -n/S(2) + S(1), -n/S(2) + S(2), cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-n + S(2))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*cos(c + d*x)**S(2), x), x, -b**S(3)*(b*sec(c + d*x))**(n + S(-3))*Hypergeometric2F1(S(1)/2, -n/S(2) + S(3)/2, -n/S(2) + S(5)/2, cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-n + S(3))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*cos(c + d*x)**S(3), x), x, -b**S(4)*(b*sec(c + d*x))**(n + S(-4))*Hypergeometric2F1(S(1)/2, -n/S(2) + S(2), -n/S(2) + S(3), cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-n + S(4))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*sec(c + d*x)**(S(5)/2), x), x, S(2)*(b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -n/S(2) + S(-3)/4, -n/S(2) + S(1)/4, cos(c + d*x)**S(2))*sin(c + d*x)*sec(c + d*x)**(S(3)/2)/(d*(S(2)*n + S(3))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*sec(c + d*x)**(S(3)/2), x), x, S(2)*(b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -n/S(2) + S(-1)/4, -n/S(2) + S(3)/4, cos(c + d*x)**S(2))*sin(c + d*x)*sqrt(sec(c + d*x))/(d*(S(2)*n + S(1))*sqrt(sin(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n*sqrt(sec(c + d*x)), x), x, -S(2)*(b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -n/S(2) + S(1)/4, -n/S(2) + S(5)/4, cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-S(2)*n + S(1))*sqrt(sin(c + d*x)**S(2))*sqrt(sec(c + d*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n/sqrt(sec(c + d*x)), x), x, -S(2)*(b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -n/S(2) + S(3)/4, -n/S(2) + S(7)/4, cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-S(2)*n + S(3))*sqrt(sin(c + d*x)**S(2))*sec(c + d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n/sec(c + d*x)**(S(3)/2), x), x, -S(2)*(b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -n/S(2) + S(5)/4, -n/S(2) + S(9)/4, cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-S(2)*n + S(5))*sqrt(sin(c + d*x)**S(2))*sec(c + d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(c + d*x))**n/sec(c + d*x)**(S(5)/2), x), x, -S(2)*(b*sec(c + d*x))**n*Hypergeometric2F1(S(1)/2, -n/S(2) + S(7)/4, -n/S(2) + S(11)/4, cos(c + d*x)**S(2))*sin(c + d*x)/(d*(-S(2)*n + S(7))*sqrt(sin(c + d*x)**S(2))*sec(c + d*x)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(a + b*x))**(S(7)/2)*sin(a + b*x), x), x, S(2)*d*(d*sec(a + b*x))**(S(5)/2)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(a + b*x))**(S(5)/2)*sin(a + b*x), x), x, S(2)*d*(d*sec(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(a + b*x))**(S(3)/2)*sin(a + b*x), x), x, S(2)*d*sqrt(d*sec(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*sec(a + b*x))*sin(a + b*x), x), x, -S(2)*d/(b*sqrt(d*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/sqrt(d*sec(a + b*x)), x), x, -S(2)*d/(S(3)*b*(d*sec(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(a + b*x))**(S(5)/2)*sin(a + b*x)**S(3), x), x, S(2)*d**S(3)/(b*sqrt(d*sec(a + b*x))) + S(2)*d*(d*sec(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(a + b*x))**(S(9)/2)*sin(a + b*x)**S(3), x), x, -S(2)*d**S(3)*(d*sec(a + b*x))**(S(3)/2)/(S(3)*b) + S(2)*d*(d*sec(a + b*x))**(S(7)/2)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(9)/2), x), x, -S(4)*c*d**S(3)*(d*csc(a + b*x))**(S(3)/2)/(S(7)*b*sqrt(c*sec(a + b*x))) - S(2)*c*d*(d*csc(a + b*x))**(S(7)/2)/(S(7)*b*sqrt(c*sec(a + b*x))) + S(4)*d**S(4)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(7)/2), x), x, -S(8)*c*d**S(3)*sqrt(d*csc(a + b*x))/(S(5)*b*sqrt(c*sec(a + b*x))) - S(2)*c*d*(d*csc(a + b*x))**(S(5)/2)/(S(5)*b*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(5)/2), x), x, -S(2)*c*d*(d*csc(a + b*x))**(S(3)/2)/(S(3)*b*sqrt(c*sec(a + b*x))) + S(2)*d**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(3)/2), x), x, -S(2)*c*d*sqrt(d*csc(a + b*x))/(b*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x)), x), x, sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))/sqrt(d*csc(a + b*x)), x), x, -sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(2)*b*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(2)*b*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + sqrt(S(2))*sqrt(c*sec(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - sqrt(S(2))*sqrt(c*sec(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))/(d*csc(a + b*x))**(S(3)/2), x), x, -c/(b*d*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))) + sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(2)*b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sec(a + b*x))/(d*csc(a + b*x))**(S(5)/2), x), x, -c/(S(2)*b*d*sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(3)/2)) - S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(8)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(8)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(16)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(16)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(9)/2), x), x, S(64)*c*d**S(5)*sqrt(c*sec(a + b*x))/(S(21)*b*sqrt(d*csc(a + b*x))) - S(16)*c*d**S(3)*sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(3)/2)/(S(21)*b) - S(2)*c*d*sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(7)/2)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(7)/2), x), x, -S(24)*c**S(2)*d**S(4)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(5)*b*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))) + S(24)*c*d**S(5)*sqrt(c*sec(a + b*x))/(S(5)*b*(d*csc(a + b*x))**(S(3)/2)) - S(12)*c*d**S(3)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))/(S(5)*b) - S(2)*c*d*sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(5)/2)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(5)/2), x), x, S(8)*c*d**S(3)*sqrt(c*sec(a + b*x))/(S(3)*b*sqrt(d*csc(a + b*x))) - S(2)*c*d*sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(3)/2), x), x, -S(4)*c**S(2)*d**S(2)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))) + S(4)*c*d**S(3)*sqrt(c*sec(a + b*x))/(b*(d*csc(a + b*x))**(S(3)/2)) - S(2)*c*d*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x)), x), x, S(2)*c*d*sqrt(c*sec(a + b*x))/(b*sqrt(d*csc(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)/sqrt(d*csc(a + b*x)), x), x, -S(2)*c**S(2)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*c*d*sqrt(c*sec(a + b*x))/(b*(d*csc(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)/(d*csc(a + b*x))**(S(3)/2), x), x, sqrt(S(2))*c**S(2)*sqrt(d*csc(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(2)*b*d**S(2)*sqrt(c*sec(a + b*x))) - sqrt(S(2))*c**S(2)*sqrt(d*csc(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(2)*b*d**S(2)*sqrt(c*sec(a + b*x))) + sqrt(S(2))*c**S(2)*sqrt(d*csc(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(4)*b*d**S(2)*sqrt(c*sec(a + b*x))) - sqrt(S(2))*c**S(2)*sqrt(d*csc(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(4)*b*d**S(2)*sqrt(c*sec(a + b*x))) + S(2)*c*sqrt(c*sec(a + b*x))/(b*d*sqrt(d*csc(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(3)/2)/(d*csc(a + b*x))**(S(5)/2), x), x, -S(3)*c**S(2)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*d**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*c*sqrt(c*sec(a + b*x))/(b*d*(d*csc(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(9)/2), x), x, S(40)*c**S(2)*d**S(4)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(21)*b) + S(40)*c*d**S(5)*(c*sec(a + b*x))**(S(3)/2)/(S(21)*b*sqrt(d*csc(a + b*x))) - S(20)*c*d**S(3)*(c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(3)/2)/(S(21)*b) - S(2)*c*d*(c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(7)/2)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(7)/2), x), x, S(64)*c*d**S(5)*(c*sec(a + b*x))**(S(3)/2)/(S(15)*b*(d*csc(a + b*x))**(S(3)/2)) - S(16)*c*d**S(3)*(c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x))/(S(5)*b) - S(2)*c*d*(c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(5)/2)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(5)/2), x), x, S(4)*c**S(2)*d**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(3)*b) + S(4)*c*d**S(3)*(c*sec(a + b*x))**(S(3)/2)/(S(3)*b*sqrt(d*csc(a + b*x))) - S(2)*c*d*(c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(3)/2), x), x, S(8)*c*d**S(3)*(c*sec(a + b*x))**(S(3)/2)/(S(3)*b*(d*csc(a + b*x))**(S(3)/2)) - S(2)*c*d*(c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)*sqrt(d*csc(a + b*x)), x), x, S(2)*c**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(3)*b) + S(2)*c*d*(c*sec(a + b*x))**(S(3)/2)/(S(3)*b*sqrt(d*csc(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)/sqrt(d*csc(a + b*x)), x), x, S(2)*c*d*(c*sec(a + b*x))**(S(3)/2)/(S(3)*b*(d*csc(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)/(d*csc(a + b*x))**(S(3)/2), x), x, -c**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(3)*b*d**S(2)) + S(2)*c*(c*sec(a + b*x))**(S(3)/2)/(S(3)*b*d*sqrt(d*csc(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sec(a + b*x))**(S(5)/2)/(d*csc(a + b*x))**(S(5)/2), x), x, sqrt(S(2))*c**S(2)*sqrt(c*sec(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(2)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - sqrt(S(2))*c**S(2)*sqrt(c*sec(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(2)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - sqrt(S(2))*c**S(2)*sqrt(c*sec(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + sqrt(S(2))*c**S(2)*sqrt(c*sec(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + S(2)*c*(c*sec(a + b*x))**(S(3)/2)/(S(3)*b*d*(d*csc(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(9)/2)/sqrt(c*sec(a + b*x)), x), x, -S(8)*c*d**S(3)*(d*csc(a + b*x))**(S(3)/2)/(S(21)*b*(c*sec(a + b*x))**(S(3)/2)) - S(2)*c*d*(d*csc(a + b*x))**(S(7)/2)/(S(7)*b*(c*sec(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(7)/2)/sqrt(c*sec(a + b*x)), x), x, -S(4)*c*d**S(3)*sqrt(d*csc(a + b*x))/(S(5)*b*(c*sec(a + b*x))**(S(3)/2)) - S(2)*c*d*(d*csc(a + b*x))**(S(5)/2)/(S(5)*b*(c*sec(a + b*x))**(S(3)/2)) - S(4)*d**S(4)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(5)*b*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(5)/2)/sqrt(c*sec(a + b*x)), x), x, -S(2)*c*d*(d*csc(a + b*x))**(S(3)/2)/(S(3)*b*(c*sec(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(3)/2)/sqrt(c*sec(a + b*x)), x), x, -S(2)*c*d*sqrt(d*csc(a + b*x))/(b*(c*sec(a + b*x))**(S(3)/2)) - S(2)*d**S(2)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(a + b*x))/sqrt(c*sec(a + b*x)), x), x, -sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(2)*b*sqrt(c*sec(a + b*x))) + sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(2)*b*sqrt(c*sec(a + b*x))) - sqrt(S(2))*sqrt(d*csc(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(4)*b*sqrt(c*sec(a + b*x))) + sqrt(S(2))*sqrt(d*csc(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(4)*b*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))), x), x, EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(3)/2)), x), x, -c/(S(2)*b*d*(c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x))) - sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(8)*b*d**S(2)*sqrt(c*sec(a + b*x))) + sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(8)*b*d**S(2)*sqrt(c*sec(a + b*x))) - sqrt(S(2))*sqrt(d*csc(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(16)*b*d**S(2)*sqrt(c*sec(a + b*x))) + sqrt(S(2))*sqrt(d*csc(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(16)*b*d**S(2)*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(5)/2)), x), x, -c/(S(3)*b*d*(c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(3)/2)) + EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(2)*b*d**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(11)/2)/(c*sec(a + b*x))**(S(3)/2), x), x, S(8)*d**S(5)*sqrt(d*csc(a + b*x))/(S(45)*b*c*sqrt(c*sec(a + b*x))) + S(2)*d**S(3)*(d*csc(a + b*x))**(S(5)/2)/(S(45)*b*c*sqrt(c*sec(a + b*x))) - S(2)*d*(d*csc(a + b*x))**(S(9)/2)/(S(9)*b*c*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(9)/2)/(c*sec(a + b*x))**(S(3)/2), x), x, S(2)*d**S(3)*(d*csc(a + b*x))**(S(3)/2)/(S(21)*b*c*sqrt(c*sec(a + b*x))) - S(2)*d*(d*csc(a + b*x))**(S(7)/2)/(S(7)*b*c*sqrt(c*sec(a + b*x))) - S(2)*d**S(4)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(21)*b*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(7)/2)/(c*sec(a + b*x))**(S(3)/2), x), x, -S(2)*c*d*(d*csc(a + b*x))**(S(5)/2)/(S(5)*b*(c*sec(a + b*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(5)/2)/(c*sec(a + b*x))**(S(3)/2), x), x, -S(2)*d*(d*csc(a + b*x))**(S(3)/2)/(S(3)*b*c*sqrt(c*sec(a + b*x))) - d**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(3)*b*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(3)/2)/(c*sec(a + b*x))**(S(3)/2), x), x, -S(2)*d*sqrt(d*csc(a + b*x))/(b*c*sqrt(c*sec(a + b*x))) + sqrt(S(2))*d**S(2)*sqrt(c*sec(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(2)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - sqrt(S(2))*d**S(2)*sqrt(c*sec(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(2)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - sqrt(S(2))*d**S(2)*sqrt(c*sec(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + sqrt(S(2))*d**S(2)*sqrt(c*sec(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(a + b*x))/(c*sec(a + b*x))**(S(3)/2), x), x, d/(b*c*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))) + sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(2)*b*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x))), x), x, d/(S(2)*b*c*sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(3)/2)) - sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(8)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(8)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + sqrt(S(2))*sqrt(c*sec(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(16)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - sqrt(S(2))*sqrt(c*sec(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(16)*b*c**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(3)/2)), x), x, -c/(S(3)*b*d*(c*sec(a + b*x))**(S(5)/2)*sqrt(d*csc(a + b*x))) + S(1)/(S(6)*b*c*d*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))) + sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(12)*b*c**S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(5)/2)), x), x, -c/(S(4)*b*d*(c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(3)/2)) + S(3)/(S(16)*b*c*d*sqrt(c*sec(a + b*x))*(d*csc(a + b*x))**(S(3)/2)) - S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(64)*b*c**S(2)*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))/(S(64)*b*c**S(2)*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) + S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(128)*b*c**S(2)*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))) - S(3)*sqrt(S(2))*sqrt(c*sec(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))/(S(128)*b*c**S(2)*d**S(2)*sqrt(d*csc(a + b*x))*sqrt(tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(9)/2)/(c*sec(a + b*x))**(S(5)/2), x), x, -S(2)*c*d*(d*csc(a + b*x))**(S(7)/2)/(S(7)*b*(c*sec(a + b*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(7)/2)/(c*sec(a + b*x))**(S(5)/2), x), x, S(6)*d**S(3)*sqrt(d*csc(a + b*x))/(S(5)*b*c*(c*sec(a + b*x))**(S(3)/2)) - S(2)*d*(d*csc(a + b*x))**(S(5)/2)/(S(5)*b*c*(c*sec(a + b*x))**(S(3)/2)) + S(6)*d**S(4)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(5)*b*c**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(5)/2)/(c*sec(a + b*x))**(S(5)/2), x), x, -S(2)*d*(d*csc(a + b*x))**(S(3)/2)/(S(3)*b*c*(c*sec(a + b*x))**(S(3)/2)) + sqrt(S(2))*d**S(2)*sqrt(d*csc(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(2)*b*c**S(2)*sqrt(c*sec(a + b*x))) - sqrt(S(2))*d**S(2)*sqrt(d*csc(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(2)*b*c**S(2)*sqrt(c*sec(a + b*x))) + sqrt(S(2))*d**S(2)*sqrt(d*csc(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(4)*b*c**S(2)*sqrt(c*sec(a + b*x))) - sqrt(S(2))*d**S(2)*sqrt(d*csc(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(4)*b*c**S(2)*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(a + b*x))**(S(3)/2)/(c*sec(a + b*x))**(S(5)/2), x), x, -S(2)*d*sqrt(d*csc(a + b*x))/(b*c*(c*sec(a + b*x))**(S(3)/2)) - S(3)*d**S(2)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*c**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(a + b*x))/(c*sec(a + b*x))**(S(5)/2), x), x, d/(S(2)*b*c*(c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x))) - S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(8)*b*c**S(2)*sqrt(c*sec(a + b*x))) + S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(8)*b*c**S(2)*sqrt(c*sec(a + b*x))) - S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(16)*b*c**S(2)*sqrt(c*sec(a + b*x))) + S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(16)*b*c**S(2)*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*sec(a + b*x))**(S(5)/2)*sqrt(d*csc(a + b*x))), x), x, d/(S(3)*b*c*(c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(3)/2)) + EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(2)*b*c**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(3)/2)), x), x, -c/(S(4)*b*d*(c*sec(a + b*x))**(S(7)/2)*sqrt(d*csc(a + b*x))) + S(1)/(S(16)*b*c*d*(c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x))) - S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(64)*b*c**S(2)*d**S(2)*sqrt(c*sec(a + b*x))) + S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(64)*b*c**S(2)*d**S(2)*sqrt(c*sec(a + b*x))) - S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(128)*b*c**S(2)*d**S(2)*sqrt(c*sec(a + b*x))) + S(3)*sqrt(S(2))*sqrt(d*csc(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(128)*b*c**S(2)*d**S(2)*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(5)/2)), x), x, -c/(S(5)*b*d*(c*sec(a + b*x))**(S(7)/2)*(d*csc(a + b*x))**(S(3)/2)) + S(1)/(S(10)*b*c*d*(c*sec(a + b*x))**(S(3)/2)*(d*csc(a + b*x))**(S(3)/2)) + S(3)*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(20)*b*c**S(2)*d**S(2)*sqrt(c*sec(a + b*x))*sqrt(d*csc(a + b*x))*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((c*sec(a + b*x))**(S(5)/2)*(d*csc(a + b*x))**(S(7)/2)), x), x, -c/(S(6)*b*d*(c*sec(a + b*x))**(S(7)/2)*(d*csc(a + b*x))**(S(5)/2)) - S(5)*c/(S(48)*b*d**S(3)*(c*sec(a + b*x))**(S(7)/2)*sqrt(d*csc(a + b*x))) + S(5)/(S(192)*b*c*d**S(3)*(c*sec(a + b*x))**(S(3)/2)*sqrt(d*csc(a + b*x))) - S(5)*sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(-sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(256)*b*c**S(2)*d**S(4)*sqrt(c*sec(a + b*x))) + S(5)*sqrt(S(2))*sqrt(d*csc(a + b*x))*ArcTan(sqrt(S(2))*sqrt(tan(a + b*x)) + S(1))*sqrt(tan(a + b*x))/(S(256)*b*c**S(2)*d**S(4)*sqrt(c*sec(a + b*x))) - S(5)*sqrt(S(2))*sqrt(d*csc(a + b*x))*log(-sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(512)*b*c**S(2)*d**S(4)*sqrt(c*sec(a + b*x))) + S(5)*sqrt(S(2))*sqrt(d*csc(a + b*x))*log(sqrt(S(2))*sqrt(tan(a + b*x)) + tan(a + b*x) + S(1))*sqrt(tan(a + b*x))/(S(512)*b*c**S(2)*d**S(4)*sqrt(c*sec(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**n*sec(e + f*x)**m, x), x, (cos(e + f*x)**S(2))**(m/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, sin(e + f*x)**S(2))*csc(e + f*x)**(n + S(-1))*sec(e + f*x)**(m + S(1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(e + f*x))**m*csc(e + f*x)**n, x), x, -(a*sec(e + f*x))**m*(sin(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(-m/S(2) + S(1)/2, n/S(2) + S(1)/2, -m/S(2) + S(3)/2, cos(e + f*x)**S(2))*cos(e + f*x)*csc(e + f*x)**(n + S(1))/(f*(-m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*csc(e + f*x))**n*sec(e + f*x)**m, x), x, (b*csc(e + f*x))**n*(cos(e + f*x)**S(2))**(m/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, sin(e + f*x)**S(2))*sin(e + f*x)*sec(e + f*x)**(m + S(1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_sine.py000066400000000000000000005010251412543434000257340ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.utility_function import ( sympy_op_factory, Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf, exp, log) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec) from sympy import pi as Pi from sympy.integrals.rubi.rubi import rubi_integrate a, b, c, d, e, f, m, n, x, u , k, p, r, s, t, i, j= symbols('a b c d e f m n x u k p r s t i j') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F', ) def test_1(): assert rubi_test(rubi_integrate(sin(a + b*x), x), x, -cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2), x), x, x/S(2) - sin(a + b*x)*cos(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3), x), x, cos(a + b*x)**S(3)/(S(3)*b) - cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4), x), x, S(3)*x/S(8) - sin(a + b*x)**S(3)*cos(a + b*x)/(S(4)*b) - S(3)*sin(a + b*x)*cos(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5), x), x, -cos(a + b*x)**S(5)/(S(5)*b) + S(2)*cos(a + b*x)**S(3)/(S(3)*b) - cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(6), x), x, S(5)*x/S(16) - sin(a + b*x)**S(5)*cos(a + b*x)/(S(6)*b) - S(5)*sin(a + b*x)**S(3)*cos(a + b*x)/(S(24)*b) - S(5)*sin(a + b*x)*cos(a + b*x)/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(7), x), x, cos(a + b*x)**S(7)/(S(7)*b) - S(3)*cos(a + b*x)**S(5)/(S(5)*b) + cos(a + b*x)**S(3)/b - cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(8), x), x, S(35)*x/S(128) - sin(a + b*x)**S(7)*cos(a + b*x)/(S(8)*b) - S(7)*sin(a + b*x)**S(5)*cos(a + b*x)/(S(48)*b) - S(35)*sin(a + b*x)**S(3)*cos(a + b*x)/(S(192)*b) - S(35)*sin(a + b*x)*cos(a + b*x)/(S(128)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(7)/2), x), x, S(10)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(S(21)*b) - S(2)*sin(a + b*x)**(S(5)/2)*cos(a + b*x)/(S(7)*b) - S(10)*sqrt(sin(a + b*x))*cos(a + b*x)/(S(21)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(5)/2), x), x, S(6)*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(S(5)*b) - S(2)*sin(a + b*x)**(S(3)/2)*cos(a + b*x)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(3)/2), x), x, S(2)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(S(3)*b) - S(2)*sqrt(sin(a + b*x))*cos(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sin(a + b*x)), x), x, S(2)*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(sin(a + b*x)), x), x, S(2)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(-3)/2), x), x, -S(2)*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/b - S(2)*cos(a + b*x)/(b*sqrt(sin(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(-5)/2), x), x, S(2)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(S(3)*b) - S(2)*cos(a + b*x)/(S(3)*b*sin(a + b*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(-7)/2), x), x, -S(6)*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(S(5)*b) - S(6)*cos(a + b*x)/(S(5)*b*sqrt(sin(a + b*x))) - S(2)*cos(a + b*x)/(S(5)*b*sin(a + b*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(7)/2), x), x, S(10)*c**S(4)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))*sqrt(sin(a + b*x))/(S(21)*b*sqrt(c*sin(a + b*x))) - S(10)*c**S(3)*sqrt(c*sin(a + b*x))*cos(a + b*x)/(S(21)*b) - S(2)*c*(c*sin(a + b*x))**(S(5)/2)*cos(a + b*x)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2), x), x, S(6)*c**S(2)*sqrt(c*sin(a + b*x))*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(S(5)*b*sqrt(sin(a + b*x))) - S(2)*c*(c*sin(a + b*x))**(S(3)/2)*cos(a + b*x)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2), x), x, S(2)*c**S(2)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))*sqrt(sin(a + b*x))/(S(3)*b*sqrt(c*sin(a + b*x))) - S(2)*c*sqrt(c*sin(a + b*x))*cos(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x)), x), x, S(2)*sqrt(c*sin(a + b*x))*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(b*sqrt(sin(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(c*sin(a + b*x)), x), x, S(2)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))*sqrt(sin(a + b*x))/(b*sqrt(c*sin(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-3)/2), x), x, -S(2)*cos(a + b*x)/(b*c*sqrt(c*sin(a + b*x))) - S(2)*sqrt(c*sin(a + b*x))*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(b*c**S(2)*sqrt(sin(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-5)/2), x), x, -S(2)*cos(a + b*x)/(S(3)*b*c*(c*sin(a + b*x))**(S(3)/2)) + S(2)*EllipticF(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))*sqrt(sin(a + b*x))/(S(3)*b*c**S(2)*sqrt(c*sin(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-7)/2), x), x, -S(2)*cos(a + b*x)/(S(5)*b*c*(c*sin(a + b*x))**(S(5)/2)) - S(6)*cos(a + b*x)/(S(5)*b*c**S(3)*sqrt(c*sin(a + b*x))) - S(6)*sqrt(c*sin(a + b*x))*EllipticE(-Pi/S(4) + a/S(2) + b*x/S(2), S(2))/(S(5)*b*c**S(4)*sqrt(sin(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(4)/3), x), x, S(3)*(c*sin(a + b*x))**(S(7)/3)*Hypergeometric2F1(S(1)/2, S(7)/6, S(13)/6, sin(a + b*x)**S(2))*cos(a + b*x)/(S(7)*b*c*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(2)/3), x), x, S(3)*(c*sin(a + b*x))**(S(5)/3)*Hypergeometric2F1(S(1)/2, S(5)/6, S(11)/6, sin(a + b*x)**S(2))*cos(a + b*x)/(S(5)*b*c*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(1)/3), x), x, -S(3)*c**(S(1)/3)*sqrt(S(1) - (c*sin(a + b*x))**(S(2)/3)/c**(S(2)/3))*sqrt(S(9)/2 - S(3)*sqrt(S(3))*I/S(2))*sqrt((-sqrt(S(3)) + I)/(-sqrt(S(3)) + S(3)*I) + S(2)*(c*sin(a + b*x))**(S(2)/3)/(c**(S(2)/3)*(S(3) + sqrt(S(3))*I)))*sqrt((sqrt(S(3)) + I)/(sqrt(S(3)) + S(3)*I) + S(2)*(c*sin(a + b*x))**(S(2)/3)/(c**(S(2)/3)*(S(3) - sqrt(S(3))*I)))*EllipticE(asin(sqrt(S(2))*sqrt(S(1) - (c*sin(a + b*x))**(S(2)/3)/c**(S(2)/3))/sqrt(S(3) + sqrt(S(3))*I)), (-sqrt(S(3)) + S(3)*I)/(sqrt(S(3)) + S(3)*I))*sec(a + b*x)/b + S(3)*sqrt(S(2))*c**(S(1)/3)*(S(1) - sqrt(S(3))*I)*sqrt(S(1) - (c*sin(a + b*x))**(S(2)/3)/c**(S(2)/3))*sqrt(S(3) - sqrt(S(3))*I)*sqrt((-sqrt(S(3)) + I)/(-sqrt(S(3)) + S(3)*I) + S(2)*(c*sin(a + b*x))**(S(2)/3)/(c**(S(2)/3)*(S(3) + sqrt(S(3))*I)))*sqrt((sqrt(S(3)) + I)/(sqrt(S(3)) + S(3)*I) + S(2)*(c*sin(a + b*x))**(S(2)/3)/(c**(S(2)/3)*(S(3) - sqrt(S(3))*I)))*EllipticF(asin(sqrt(S(2))*sqrt(S(1) - (c*sin(a + b*x))**(S(2)/3)/c**(S(2)/3))/sqrt(S(3) - sqrt(S(3))*I)), (sqrt(S(3)) + S(3)*I)/(-sqrt(S(3)) + S(3)*I))*sec(a + b*x)/(S(4)*b), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((c*sin(a + b*x))**(S(1)/3), x), x, S(3)*(c*sin(a + b*x))**(S(4)/3)*Hypergeometric2F1(S(1)/2, S(2)/3, S(5)/3, sin(a + b*x)**S(2))*cos(a + b*x)/(S(4)*b*c*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-1)/3), x), x, -S(3)*sqrt(S(2))*sqrt(S(1) - (c*sin(a + b*x))**(S(2)/3)/c**(S(2)/3))*sqrt(S(3) - sqrt(S(3))*I)*sqrt((-sqrt(S(3)) + I)/(-sqrt(S(3)) + S(3)*I) + S(2)*(c*sin(a + b*x))**(S(2)/3)/(c**(S(2)/3)*(S(3) + sqrt(S(3))*I)))*sqrt((sqrt(S(3)) + I)/(sqrt(S(3)) + S(3)*I) + S(2)*(c*sin(a + b*x))**(S(2)/3)/(c**(S(2)/3)*(S(3) - sqrt(S(3))*I)))*EllipticF(asin(sqrt(S(2))*sqrt(S(1) - (c*sin(a + b*x))**(S(2)/3)/c**(S(2)/3))/sqrt(S(3) - sqrt(S(3))*I)), (sqrt(S(3)) + S(3)*I)/(-sqrt(S(3)) + S(3)*I))*sec(a + b*x)/(S(2)*b*c**(S(1)/3)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-1)/3), x), x, S(3)*(c*sin(a + b*x))**(S(2)/3)*Hypergeometric2F1(S(1)/3, S(1)/2, S(4)/3, sin(a + b*x)**S(2))*cos(a + b*x)/(S(2)*b*c*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-2)/3), x), x, S(3)**(S(3)/4)*(c*sin(a + b*x))**(S(1)/3)*sqrt(c**(S(4)/3)*(S(1) + (c*sin(a + b*x))**(S(2)/3)/c**(S(2)/3) + (c*sin(a + b*x))**(S(4)/3)/c**(S(4)/3))/(c**(S(2)/3) - (c*sin(a + b*x))**(S(2)/3)*(S(1) + sqrt(S(3))))**S(2))*(c**(S(2)/3) - (c*sin(a + b*x))**(S(2)/3))*EllipticF(acos((c**(S(2)/3) - (c*sin(a + b*x))**(S(2)/3)*(-sqrt(S(3)) + S(1)))/(c**(S(2)/3) - (c*sin(a + b*x))**(S(2)/3)*(S(1) + sqrt(S(3))))), sqrt(S(3))/S(4) + S(1)/2)*sec(a + b*x)/(S(2)*b*c**(S(5)/3)*sqrt(-(c*sin(a + b*x))**(S(2)/3)*(c**(S(2)/3) - (c*sin(a + b*x))**(S(2)/3))/(c**(S(2)/3) - (c*sin(a + b*x))**(S(2)/3)*(S(1) + sqrt(S(3))))**S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-2)/3), x), x, S(3)*(c*sin(a + b*x))**(S(1)/3)*Hypergeometric2F1(S(1)/6, S(1)/2, S(7)/6, sin(a + b*x)**S(2))*cos(a + b*x)/(b*c*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(-4)/3), x), x, -S(3)*Hypergeometric2F1(S(-1)/6, S(1)/2, S(5)/6, sin(a + b*x)**S(2))*cos(a + b*x)/(b*c*(c*sin(a + b*x))**(S(1)/3)*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**n, x), x, Hypergeometric2F1(S(1)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)**(n + S(1))*cos(a + b*x)/(b*(n + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**n, x), x, (c*sin(a + b*x))**(n + S(1))*Hypergeometric2F1(S(1)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(a + b*x)**S(2))*cos(a + b*x)/(b*c*(n + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(2))**(S(5)/2), x), x, -S(8)*a**S(2)*sqrt(a*sin(x)**S(2))*cot(x)/S(15) - S(4)*a*(a*sin(x)**S(2))**(S(3)/2)*cot(x)/S(15) - (a*sin(x)**S(2))**(S(5)/2)*cot(x)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(2))**(S(3)/2), x), x, -S(2)*a*sqrt(a*sin(x)**S(2))*cot(x)/S(3) - (a*sin(x)**S(2))**(S(3)/2)*cot(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*sin(x)**S(2)), x), x, -sqrt(a*sin(x)**S(2))*cot(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*sin(x)**S(2)), x), x, -sin(x)*atanh(cos(x))/sqrt(a*sin(x)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(2))**(S(-3)/2), x), x, -sin(x)*atanh(cos(x))/(S(2)*a*sqrt(a*sin(x)**S(2))) - cot(x)/(S(2)*a*sqrt(a*sin(x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(2))**(S(-5)/2), x), x, -cot(x)/(S(4)*a*(a*sin(x)**S(2))**(S(3)/2)) - S(3)*sin(x)*atanh(cos(x))/(S(8)*a**S(2)*sqrt(a*sin(x)**S(2))) - S(3)*cot(x)/(S(8)*a**S(2)*sqrt(a*sin(x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(3))**(S(5)/2), x), x, -S(26)*a**S(2)*sqrt(a*sin(x)**S(3))*EllipticF(Pi/S(4) - x/S(2), S(2))/(S(77)*sin(x)**(S(3)/2)) - S(2)*a**S(2)*sqrt(a*sin(x)**S(3))*sin(x)**S(5)*cos(x)/S(15) - S(26)*a**S(2)*sqrt(a*sin(x)**S(3))*sin(x)**S(3)*cos(x)/S(165) - S(78)*a**S(2)*sqrt(a*sin(x)**S(3))*sin(x)*cos(x)/S(385) - S(26)*a**S(2)*sqrt(a*sin(x)**S(3))*cot(x)/S(77), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(3))**(S(3)/2), x), x, -S(14)*a*sqrt(a*sin(x)**S(3))*EllipticE(Pi/S(4) - x/S(2), S(2))/(S(15)*sin(x)**(S(3)/2)) - S(2)*a*sqrt(a*sin(x)**S(3))*sin(x)**S(2)*cos(x)/S(9) - S(14)*a*sqrt(a*sin(x)**S(3))*cos(x)/S(45), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*sin(x)**S(3)), x), x, -S(2)*sqrt(a*sin(x)**S(3))*EllipticF(Pi/S(4) - x/S(2), S(2))/(S(3)*sin(x)**(S(3)/2)) - S(2)*sqrt(a*sin(x)**S(3))*cot(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*sin(x)**S(3)), x), x, S(2)*EllipticE(Pi/S(4) - x/S(2), S(2))*sin(x)**(S(3)/2)/sqrt(a*sin(x)**S(3)) - S(2)*sin(x)*cos(x)/sqrt(a*sin(x)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(3))**(S(-3)/2), x), x, -S(10)*EllipticF(Pi/S(4) - x/S(2), S(2))*sin(x)**(S(3)/2)/(S(21)*a*sqrt(a*sin(x)**S(3))) - S(10)*cos(x)/(S(21)*a*sqrt(a*sin(x)**S(3))) - S(2)*cot(x)*csc(x)/(S(7)*a*sqrt(a*sin(x)**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(3))**(S(-5)/2), x), x, S(154)*EllipticE(Pi/S(4) - x/S(2), S(2))*sin(x)**(S(3)/2)/(S(195)*a**S(2)*sqrt(a*sin(x)**S(3))) - S(154)*sin(x)*cos(x)/(S(195)*a**S(2)*sqrt(a*sin(x)**S(3))) - S(2)*cot(x)*csc(x)**S(4)/(S(13)*a**S(2)*sqrt(a*sin(x)**S(3))) - S(22)*cot(x)*csc(x)**S(2)/(S(117)*a**S(2)*sqrt(a*sin(x)**S(3))) - S(154)*cot(x)/(S(585)*a**S(2)*sqrt(a*sin(x)**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(4))**(S(5)/2), x), x, S(63)*a**S(2)*x*sqrt(a*sin(x)**S(4))*csc(x)**S(2)/S(256) - a**S(2)*sqrt(a*sin(x)**S(4))*sin(x)**S(7)*cos(x)/S(10) - S(9)*a**S(2)*sqrt(a*sin(x)**S(4))*sin(x)**S(5)*cos(x)/S(80) - S(21)*a**S(2)*sqrt(a*sin(x)**S(4))*sin(x)**S(3)*cos(x)/S(160) - S(21)*a**S(2)*sqrt(a*sin(x)**S(4))*sin(x)*cos(x)/S(128) - S(63)*a**S(2)*sqrt(a*sin(x)**S(4))*cot(x)/S(256), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(4))**(S(3)/2), x), x, S(5)*a*x*sqrt(a*sin(x)**S(4))*csc(x)**S(2)/S(16) - a*sqrt(a*sin(x)**S(4))*sin(x)**S(3)*cos(x)/S(6) - S(5)*a*sqrt(a*sin(x)**S(4))*sin(x)*cos(x)/S(24) - S(5)*a*sqrt(a*sin(x)**S(4))*cot(x)/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*sin(x)**S(4)), x), x, x*sqrt(a*sin(x)**S(4))*csc(x)**S(2)/S(2) - sqrt(a*sin(x)**S(4))*cot(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*sin(x)**S(4)), x), x, -sin(x)*cos(x)/sqrt(a*sin(x)**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(4))**(S(-3)/2), x), x, -sin(x)*cos(x)/(a*sqrt(a*sin(x)**S(4))) - cos(x)**S(2)*cot(x)**S(3)/(S(5)*a*sqrt(a*sin(x)**S(4))) - S(2)*cos(x)**S(2)*cot(x)/(S(3)*a*sqrt(a*sin(x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(x)**S(4))**(S(-5)/2), x), x, -sin(x)*cos(x)/(a**S(2)*sqrt(a*sin(x)**S(4))) - cos(x)**S(2)*cot(x)**S(7)/(S(9)*a**S(2)*sqrt(a*sin(x)**S(4))) - S(4)*cos(x)**S(2)*cot(x)**S(5)/(S(7)*a**S(2)*sqrt(a*sin(x)**S(4))) - S(6)*cos(x)**S(2)*cot(x)**S(3)/(S(5)*a**S(2)*sqrt(a*sin(x)**S(4))) - S(4)*cos(x)**S(2)*cot(x)/(S(3)*a**S(2)*sqrt(a*sin(x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(c + d*x)**p)**n, x), x, (b*sin(c + d*x)**p)**n*Hypergeometric2F1(S(1)/2, n*p/S(2) + S(1)/2, n*p/S(2) + S(3)/2, sin(c + d*x)**S(2))*sin(c + d*x)*cos(c + d*x)/(d*(n*p + S(1))*sqrt(cos(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**S(2))**n, x), x, (c*sin(a + b*x)**S(2))**n*Hypergeometric2F1(S(1)/2, n + S(1)/2, n + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)*cos(a + b*x)/(b*(S(2)*n + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**S(3))**n, x), x, (c*sin(a + b*x)**S(3))**n*Hypergeometric2F1(S(1)/2, S(3)*n/S(2) + S(1)/2, S(3)*n/S(2) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)*cos(a + b*x)/(b*(S(3)*n + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**S(4))**n, x), x, (c*sin(a + b*x)**S(4))**n*Hypergeometric2F1(S(1)/2, S(2)*n + S(1)/2, S(2)*n + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)*cos(a + b*x)/(b*(S(4)*n + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**m)**(S(5)/2), x), x, S(2)*c**S(2)*sqrt(c*sin(a + b*x)**m)*Hypergeometric2F1(S(1)/2, S(5)*m/S(4) + S(1)/2, S(5)*m/S(4) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)**(S(2)*m + S(1))*cos(a + b*x)/(b*(S(5)*m + S(2))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**m)**(S(3)/2), x), x, S(2)*c*sqrt(c*sin(a + b*x)**m)*Hypergeometric2F1(S(1)/2, S(3)*m/S(4) + S(1)/2, S(3)*m/S(4) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)**(m + S(1))*cos(a + b*x)/(b*(S(3)*m + S(2))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x)**m), x), x, S(2)*sqrt(c*sin(a + b*x)**m)*Hypergeometric2F1(S(1)/2, m/S(4) + S(1)/2, m/S(4) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)*cos(a + b*x)/(b*(m + S(2))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(c*sin(a + b*x)**m), x), x, S(2)*Hypergeometric2F1(S(1)/2, -m/S(4) + S(1)/2, -m/S(4) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)*cos(a + b*x)/(b*sqrt(c*sin(a + b*x)**m)*(-m + S(2))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**m)**(S(-3)/2), x), x, S(2)*Hypergeometric2F1(S(1)/2, -S(3)*m/S(4) + S(1)/2, -S(3)*m/S(4) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)**(-m + S(1))*cos(a + b*x)/(b*c*sqrt(c*sin(a + b*x)**m)*(-S(3)*m + S(2))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**m)**(S(-5)/2), x), x, S(2)*Hypergeometric2F1(S(1)/2, -S(5)*m/S(4) + S(1)/2, -S(5)*m/S(4) + S(3)/2, sin(a + b*x)**S(2))*sin(a + b*x)**(-S(2)*m + S(1))*cos(a + b*x)/(b*c**S(2)*sqrt(c*sin(a + b*x)**m)*(-S(5)*m + S(2))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x)**m)**(S(1)/m), x), x, -(c*sin(a + b*x)**m)**(S(1)/m)*cot(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*sin(c + d*x))**p)**n, x), x, (a*(b*sin(c + d*x))**p)**n*Hypergeometric2F1(S(1)/2, n*p/S(2) + S(1)/2, n*p/S(2) + S(3)/2, sin(c + d*x)**S(2))*sin(c + d*x)*cos(c + d*x)/(d*(n*p + S(1))*sqrt(cos(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(e + f*x))**m*(b*sin(e + f*x))**n, x), x, (a*sin(e + f*x))**(m + S(1))*(b*sin(e + f*x))**n*Hypergeometric2F1(S(1)/2, m/S(2) + n/S(2) + S(1)/2, m/S(2) + n/S(2) + S(3)/2, sin(e + f*x)**S(2))*cos(e + f*x)/(a*f*(m + n + S(1))*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)*cos(a + b*x)**S(3), x), x, -cos(a + b*x)**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)*cos(a + b*x)**S(2), x), x, -cos(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)*cos(a + b*x), x), x, sin(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)*sec(a + b*x), x), x, -log(cos(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)*sec(a + b*x)**S(2), x), x, sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)*sec(a + b*x)**S(3), x), x, sec(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)*sec(a + b*x)**S(4), x), x, sec(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*cos(a + b*x)**S(7), x), x, -sin(a + b*x)**S(9)/(S(9)*b) + S(3)*sin(a + b*x)**S(7)/(S(7)*b) - S(3)*sin(a + b*x)**S(5)/(S(5)*b) + sin(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*cos(a + b*x)**S(5), x), x, sin(a + b*x)**S(7)/(S(7)*b) - S(2)*sin(a + b*x)**S(5)/(S(5)*b) + sin(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*cos(a + b*x)**S(3), x), x, -sin(a + b*x)**S(5)/(S(5)*b) + sin(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*cos(a + b*x), x), x, sin(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(2), x), x, -x + tan(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(4), x), x, tan(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(6), x), x, tan(a + b*x)**S(5)/(S(5)*b) + tan(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(8), x), x, tan(a + b*x)**S(7)/(S(7)*b) + S(2)*tan(a + b*x)**S(5)/(S(5)*b) + tan(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(10), x), x, tan(a + b*x)**S(9)/(S(9)*b) + S(3)*tan(a + b*x)**S(7)/(S(7)*b) + S(3)*tan(a + b*x)**S(5)/(S(5)*b) + tan(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*cos(a + b*x)**S(6), x), x, S(5)*x/S(128) - sin(a + b*x)*cos(a + b*x)**S(7)/(S(8)*b) + sin(a + b*x)*cos(a + b*x)**S(5)/(S(48)*b) + S(5)*sin(a + b*x)*cos(a + b*x)**S(3)/(S(192)*b) + S(5)*sin(a + b*x)*cos(a + b*x)/(S(128)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*cos(a + b*x)**S(4), x), x, x/S(16) - sin(a + b*x)*cos(a + b*x)**S(5)/(S(6)*b) + sin(a + b*x)*cos(a + b*x)**S(3)/(S(24)*b) + sin(a + b*x)*cos(a + b*x)/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*cos(a + b*x)**S(2), x), x, x/S(8) - sin(a + b*x)*cos(a + b*x)**S(3)/(S(4)*b) + sin(a + b*x)*cos(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2), x), x, x/S(2) - sin(a + b*x)*cos(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x), x), x, -sin(a + b*x)/b + atanh(sin(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(3), x), x, tan(a + b*x)*sec(a + b*x)/(S(2)*b) - atanh(sin(a + b*x))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(5), x), x, tan(a + b*x)*sec(a + b*x)**S(3)/(S(4)*b) - tan(a + b*x)*sec(a + b*x)/(S(8)*b) - atanh(sin(a + b*x))/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)*sec(a + b*x)**S(7), x), x, tan(a + b*x)*sec(a + b*x)**S(5)/(S(6)*b) - tan(a + b*x)*sec(a + b*x)**S(3)/(S(24)*b) - tan(a + b*x)*sec(a + b*x)/(S(16)*b) - atanh(sin(a + b*x))/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*cos(a + b*x)**S(5), x), x, cos(a + b*x)**S(8)/(S(8)*b) - cos(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*cos(a + b*x)**S(4), x), x, cos(a + b*x)**S(7)/(S(7)*b) - cos(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*cos(a + b*x)**S(3), x), x, -sin(a + b*x)**S(6)/(S(6)*b) + sin(a + b*x)**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*cos(a + b*x)**S(2), x), x, cos(a + b*x)**S(5)/(S(5)*b) - cos(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*cos(a + b*x), x), x, sin(a + b*x)**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x), x), x, -log(cos(a + b*x))/b + cos(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(2), x), x, cos(a + b*x)/b + sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(3), x), x, log(cos(a + b*x))/b + tan(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(4), x), x, sec(a + b*x)**S(3)/(S(3)*b) - sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(5), x), x, tan(a + b*x)**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(6), x), x, sec(a + b*x)**S(5)/(S(5)*b) - sec(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(7), x), x, sec(a + b*x)**S(6)/(S(6)*b) - sec(a + b*x)**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(8), x), x, sec(a + b*x)**S(7)/(S(7)*b) - sec(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)*sec(a + b*x)**S(9), x), x, sec(a + b*x)**S(8)/(S(8)*b) - sec(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*cos(a + b*x)**S(7), x), x, -sin(a + b*x)**S(11)/(S(11)*b) + sin(a + b*x)**S(9)/(S(3)*b) - S(3)*sin(a + b*x)**S(7)/(S(7)*b) + sin(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*cos(a + b*x)**S(5), x), x, sin(a + b*x)**S(9)/(S(9)*b) - S(2)*sin(a + b*x)**S(7)/(S(7)*b) + sin(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*cos(a + b*x)**S(3), x), x, -sin(a + b*x)**S(7)/(S(7)*b) + sin(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*cos(a + b*x), x), x, sin(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(2), x), x, -S(3)*x/S(2) - sin(a + b*x)**S(2)*tan(a + b*x)/(S(2)*b) + S(3)*tan(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(4), x), x, x + tan(a + b*x)**S(3)/(S(3)*b) - tan(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(6), x), x, tan(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(8), x), x, tan(a + b*x)**S(7)/(S(7)*b) + tan(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(10), x), x, tan(a + b*x)**S(9)/(S(9)*b) + S(2)*tan(a + b*x)**S(7)/(S(7)*b) + tan(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*cos(a + b*x)**S(6), x), x, S(3)*x/S(256) - sin(a + b*x)**S(3)*cos(a + b*x)**S(7)/(S(10)*b) - S(3)*sin(a + b*x)*cos(a + b*x)**S(7)/(S(80)*b) + sin(a + b*x)*cos(a + b*x)**S(5)/(S(160)*b) + sin(a + b*x)*cos(a + b*x)**S(3)/(S(128)*b) + S(3)*sin(a + b*x)*cos(a + b*x)/(S(256)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*cos(a + b*x)**S(4), x), x, S(3)*x/S(128) - sin(a + b*x)**S(3)*cos(a + b*x)**S(5)/(S(8)*b) - sin(a + b*x)*cos(a + b*x)**S(5)/(S(16)*b) + sin(a + b*x)*cos(a + b*x)**S(3)/(S(64)*b) + S(3)*sin(a + b*x)*cos(a + b*x)/(S(128)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*cos(a + b*x)**S(2), x), x, x/S(16) - sin(a + b*x)**S(3)*cos(a + b*x)**S(3)/(S(6)*b) - sin(a + b*x)*cos(a + b*x)**S(3)/(S(8)*b) + sin(a + b*x)*cos(a + b*x)/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4), x), x, S(3)*x/S(8) - sin(a + b*x)**S(3)*cos(a + b*x)/(S(4)*b) - S(3)*sin(a + b*x)*cos(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x), x), x, -sin(a + b*x)**S(3)/(S(3)*b) - sin(a + b*x)/b + atanh(sin(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(3), x), x, sin(a + b*x)*tan(a + b*x)**S(2)/(S(2)*b) + S(3)*sin(a + b*x)/(S(2)*b) - S(3)*atanh(sin(a + b*x))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(5), x), x, tan(a + b*x)**S(3)*sec(a + b*x)/(S(4)*b) - S(3)*tan(a + b*x)*sec(a + b*x)/(S(8)*b) + S(3)*atanh(sin(a + b*x))/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(7), x), x, tan(a + b*x)**S(3)*sec(a + b*x)**S(3)/(S(6)*b) - tan(a + b*x)*sec(a + b*x)**S(3)/(S(8)*b) + tan(a + b*x)*sec(a + b*x)/(S(16)*b) + atanh(sin(a + b*x))/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)*sec(a + b*x)**S(9), x), x, tan(a + b*x)**S(3)*sec(a + b*x)**S(5)/(S(8)*b) - tan(a + b*x)*sec(a + b*x)**S(5)/(S(16)*b) + tan(a + b*x)*sec(a + b*x)**S(3)/(S(64)*b) + S(3)*tan(a + b*x)*sec(a + b*x)/(S(128)*b) + S(3)*atanh(sin(a + b*x))/(S(128)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x)**S(7), x), x, -cos(a + b*x)**S(12)/(S(12)*b) + cos(a + b*x)**S(10)/(S(5)*b) - cos(a + b*x)**S(8)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x)**S(6), x), x, -cos(a + b*x)**S(11)/(S(11)*b) + S(2)*cos(a + b*x)**S(9)/(S(9)*b) - cos(a + b*x)**S(7)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x)**S(5), x), x, sin(a + b*x)**S(10)/(S(10)*b) - sin(a + b*x)**S(8)/(S(4)*b) + sin(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x)**S(4), x), x, -cos(a + b*x)**S(9)/(S(9)*b) + S(2)*cos(a + b*x)**S(7)/(S(7)*b) - cos(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x)**S(3), x), x, -sin(a + b*x)**S(8)/(S(8)*b) + sin(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x)**S(2), x), x, -cos(a + b*x)**S(7)/(S(7)*b) + S(2)*cos(a + b*x)**S(5)/(S(5)*b) - cos(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x), x), x, sin(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x), x), x, -log(cos(a + b*x))/b - cos(a + b*x)**S(4)/(S(4)*b) + cos(a + b*x)**S(2)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(2), x), x, -cos(a + b*x)**S(3)/(S(3)*b) + S(2)*cos(a + b*x)/b + sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(3), x), x, S(2)*log(cos(a + b*x))/b - cos(a + b*x)**S(2)/(S(2)*b) + sec(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(4), x), x, -cos(a + b*x)/b + sec(a + b*x)**S(3)/(S(3)*b) - S(2)*sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(5), x), x, -log(cos(a + b*x))/b + tan(a + b*x)**S(4)/(S(4)*b) - tan(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(6), x), x, sec(a + b*x)**S(5)/(S(5)*b) - S(2)*sec(a + b*x)**S(3)/(S(3)*b) + sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(7), x), x, tan(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(8), x), x, sec(a + b*x)**S(7)/(S(7)*b) - S(2)*sec(a + b*x)**S(5)/(S(5)*b) + sec(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(9), x), x, tan(a + b*x)**S(8)/(S(8)*b) + tan(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(10), x), x, sec(a + b*x)**S(9)/(S(9)*b) - S(2)*sec(a + b*x)**S(7)/(S(7)*b) + sec(a + b*x)**S(5)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(11), x), x, sec(a + b*x)**S(10)/(S(10)*b) - sec(a + b*x)**S(8)/(S(4)*b) + sec(a + b*x)**S(6)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(12), x), x, sec(a + b*x)**S(11)/(S(11)*b) - S(2)*sec(a + b*x)**S(9)/(S(9)*b) + sec(a + b*x)**S(7)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*sec(a + b*x)**S(13), x), x, sec(a + b*x)**S(12)/(S(12)*b) - sec(a + b*x)**S(10)/(S(5)*b) + sec(a + b*x)**S(8)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(6)*sec(a + b*x)**S(3), x), x, sin(a + b*x)**S(3)*tan(a + b*x)**S(2)/(S(2)*b) + S(5)*sin(a + b*x)**S(3)/(S(6)*b) + S(5)*sin(a + b*x)/(S(2)*b) - S(5)*atanh(sin(a + b*x))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(7)*sec(a + b*x)**S(6), x), x, cos(a + b*x)/b + sec(a + b*x)**S(5)/(S(5)*b) - sec(a + b*x)**S(3)/b + S(3)*sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(6)/sin(a + b*x), x), x, cos(a + b*x)**S(5)/(S(5)*b) + cos(a + b*x)**S(3)/(S(3)*b) + cos(a + b*x)/b - atanh(cos(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(5)/sin(a + b*x), x), x, log(sin(a + b*x))/b + sin(a + b*x)**S(4)/(S(4)*b) - sin(a + b*x)**S(2)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(4)/sin(a + b*x), x), x, cos(a + b*x)**S(3)/(S(3)*b) + cos(a + b*x)/b - atanh(cos(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(3)/sin(a + b*x), x), x, log(sin(a + b*x))/b - sin(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(2)/sin(a + b*x), x), x, cos(a + b*x)/b - atanh(cos(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)/sin(a + b*x), x), x, log(sin(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)/sin(a + b*x), x), x, log(tan(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(2)/sin(a + b*x), x), x, -atanh(cos(a + b*x))/b + sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3)/sin(a + b*x), x), x, log(tan(a + b*x))/b + tan(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(4)/sin(a + b*x), x), x, -atanh(cos(a + b*x))/b + sec(a + b*x)**S(3)/(S(3)*b) + sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(5)/sin(a + b*x), x), x, log(tan(a + b*x))/b + tan(a + b*x)**S(4)/(S(4)*b) + tan(a + b*x)**S(2)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(6)/sin(a + b*x), x), x, -atanh(cos(a + b*x))/b + sec(a + b*x)**S(5)/(S(5)*b) + sec(a + b*x)**S(3)/(S(3)*b) + sec(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(7)/sin(a + b*x), x), x, log(tan(a + b*x))/b + tan(a + b*x)**S(6)/(S(6)*b) + S(3)*tan(a + b*x)**S(4)/(S(4)*b) + S(3)*tan(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(7)/sin(a + b*x)**S(2), x), x, -sin(a + b*x)**S(5)/(S(5)*b) + sin(a + b*x)**S(3)/b - S(3)*sin(a + b*x)/b - csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(6)/sin(a + b*x)**S(2), x), x, -S(15)*x/S(8) + cos(a + b*x)**S(4)*cot(a + b*x)/(S(4)*b) + S(5)*cos(a + b*x)**S(2)*cot(a + b*x)/(S(8)*b) - S(15)*cot(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(5)/sin(a + b*x)**S(2), x), x, sin(a + b*x)**S(3)/(S(3)*b) - S(2)*sin(a + b*x)/b - csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(4)/sin(a + b*x)**S(2), x), x, -S(3)*x/S(2) + cos(a + b*x)**S(2)*cot(a + b*x)/(S(2)*b) - S(3)*cot(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(3)/sin(a + b*x)**S(2), x), x, -sin(a + b*x)/b - csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(2)/sin(a + b*x)**S(2), x), x, -x - cot(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)/sin(a + b*x)**S(2), x), x, -csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)/sin(a + b*x)**S(2), x), x, atanh(sin(a + b*x))/b - csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(2)/sin(a + b*x)**S(2), x), x, tan(a + b*x)/b - cot(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3)/sin(a + b*x)**S(2), x), x, S(3)*atanh(sin(a + b*x))/(S(2)*b) + csc(a + b*x)*sec(a + b*x)**S(2)/(S(2)*b) - S(3)*csc(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(4)/sin(a + b*x)**S(2), x), x, tan(a + b*x)**S(3)/(S(3)*b) + S(2)*tan(a + b*x)/b - cot(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(5)/sin(a + b*x)**S(2), x), x, S(15)*atanh(sin(a + b*x))/(S(8)*b) + csc(a + b*x)*sec(a + b*x)**S(4)/(S(4)*b) + S(5)*csc(a + b*x)*sec(a + b*x)**S(2)/(S(8)*b) - S(15)*csc(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(7)/sin(a + b*x)**S(3), x), x, -S(3)*log(sin(a + b*x))/b - sin(a + b*x)**S(4)/(S(4)*b) + S(3)*sin(a + b*x)**S(2)/(S(2)*b) - csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(6)/sin(a + b*x)**S(3), x), x, -cos(a + b*x)**S(3)*cot(a + b*x)**S(2)/(S(2)*b) - S(5)*cos(a + b*x)**S(3)/(S(6)*b) - S(5)*cos(a + b*x)/(S(2)*b) + S(5)*atanh(cos(a + b*x))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(5)/sin(a + b*x)**S(3), x), x, -S(2)*log(sin(a + b*x))/b + sin(a + b*x)**S(2)/(S(2)*b) - csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(4)/sin(a + b*x)**S(3), x), x, -cos(a + b*x)*cot(a + b*x)**S(2)/(S(2)*b) - S(3)*cos(a + b*x)/(S(2)*b) + S(3)*atanh(cos(a + b*x))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(3)/sin(a + b*x)**S(3), x), x, -log(sin(a + b*x))/b - cot(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(2)/sin(a + b*x)**S(3), x), x, -cot(a + b*x)*csc(a + b*x)/(S(2)*b) + atanh(cos(a + b*x))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)/sin(a + b*x)**S(3), x), x, -csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)/sin(a + b*x)**S(3), x), x, log(tan(a + b*x))/b - cot(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(2)/sin(a + b*x)**S(3), x), x, -S(3)*atanh(cos(a + b*x))/(S(2)*b) - csc(a + b*x)**S(2)*sec(a + b*x)/(S(2)*b) + S(3)*sec(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3)/sin(a + b*x)**S(3), x), x, S(2)*log(tan(a + b*x))/b + tan(a + b*x)**S(2)/(S(2)*b) - cot(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(4)/sin(a + b*x)**S(3), x), x, -S(5)*atanh(cos(a + b*x))/(S(2)*b) - csc(a + b*x)**S(2)*sec(a + b*x)**S(3)/(S(2)*b) + S(5)*sec(a + b*x)**S(3)/(S(6)*b) + S(5)*sec(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(5)/sin(a + b*x)**S(3), x), x, S(3)*log(tan(a + b*x))/b + tan(a + b*x)**S(4)/(S(4)*b) + S(3)*tan(a + b*x)**S(2)/(S(2)*b) - cot(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(9)/sin(a + b*x)**S(4), x), x, sin(a + b*x)**S(5)/(S(5)*b) - S(4)*sin(a + b*x)**S(3)/(S(3)*b) + S(6)*sin(a + b*x)/b - csc(a + b*x)**S(3)/(S(3)*b) + S(4)*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(8)/sin(a + b*x)**S(4), x), x, S(35)*x/S(8) + cos(a + b*x)**S(4)*cot(a + b*x)**S(3)/(S(4)*b) + S(7)*cos(a + b*x)**S(2)*cot(a + b*x)**S(3)/(S(8)*b) - S(35)*cot(a + b*x)**S(3)/(S(24)*b) + S(35)*cot(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(7)/sin(a + b*x)**S(4), x), x, -sin(a + b*x)**S(3)/(S(3)*b) + S(3)*sin(a + b*x)/b - csc(a + b*x)**S(3)/(S(3)*b) + S(3)*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(6)/sin(a + b*x)**S(4), x), x, S(5)*x/S(2) + cos(a + b*x)**S(2)*cot(a + b*x)**S(3)/(S(2)*b) - S(5)*cot(a + b*x)**S(3)/(S(6)*b) + S(5)*cot(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(5)/sin(a + b*x)**S(4), x), x, sin(a + b*x)/b - csc(a + b*x)**S(3)/(S(3)*b) + S(2)*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(4)/sin(a + b*x)**S(4), x), x, x - cot(a + b*x)**S(3)/(S(3)*b) + cot(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(3)/sin(a + b*x)**S(4), x), x, -csc(a + b*x)**S(3)/(S(3)*b) + csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(2)/sin(a + b*x)**S(4), x), x, -cot(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)/sin(a + b*x)**S(4), x), x, -csc(a + b*x)**S(3)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)/sin(a + b*x)**S(4), x), x, atanh(sin(a + b*x))/b - csc(a + b*x)**S(3)/(S(3)*b) - csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(2)/sin(a + b*x)**S(4), x), x, tan(a + b*x)/b - cot(a + b*x)**S(3)/(S(3)*b) - S(2)*cot(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3)/sin(a + b*x)**S(4), x), x, S(5)*atanh(sin(a + b*x))/(S(2)*b) + csc(a + b*x)**S(3)*sec(a + b*x)**S(2)/(S(2)*b) - S(5)*csc(a + b*x)**S(3)/(S(6)*b) - S(5)*csc(a + b*x)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(4)/sin(a + b*x)**S(4), x), x, tan(a + b*x)**S(3)/(S(3)*b) + S(3)*tan(a + b*x)/b - cot(a + b*x)**S(3)/(S(3)*b) - S(3)*cot(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(5)/sin(a + b*x)**S(4), x), x, S(35)*atanh(sin(a + b*x))/(S(8)*b) + csc(a + b*x)**S(3)*sec(a + b*x)**S(4)/(S(4)*b) + S(7)*csc(a + b*x)**S(3)*sec(a + b*x)**S(2)/(S(8)*b) - S(35)*csc(a + b*x)**S(3)/(S(24)*b) - S(35)*csc(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(9)/sin(a + b*x)**S(5), x), x, S(6)*log(sin(a + b*x))/b + sin(a + b*x)**S(4)/(S(4)*b) - S(2)*sin(a + b*x)**S(2)/b - csc(a + b*x)**S(4)/(S(4)*b) + S(2)*csc(a + b*x)**S(2)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(8)/sin(a + b*x)**S(5), x), x, -cos(a + b*x)**S(3)*cot(a + b*x)**S(4)/(S(4)*b) + S(7)*cos(a + b*x)**S(3)*cot(a + b*x)**S(2)/(S(8)*b) + S(35)*cos(a + b*x)**S(3)/(S(24)*b) + S(35)*cos(a + b*x)/(S(8)*b) - S(35)*atanh(cos(a + b*x))/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(7)/sin(a + b*x)**S(5), x), x, S(3)*log(sin(a + b*x))/b - sin(a + b*x)**S(2)/(S(2)*b) - csc(a + b*x)**S(4)/(S(4)*b) + S(3)*csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(6)/sin(a + b*x)**S(5), x), x, -cos(a + b*x)*cot(a + b*x)**S(4)/(S(4)*b) + S(5)*cos(a + b*x)*cot(a + b*x)**S(2)/(S(8)*b) + S(15)*cos(a + b*x)/(S(8)*b) - S(15)*atanh(cos(a + b*x))/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(5)/sin(a + b*x)**S(5), x), x, log(sin(a + b*x))/b - cot(a + b*x)**S(4)/(S(4)*b) + cot(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(4)/sin(a + b*x)**S(5), x), x, -cot(a + b*x)**S(3)*csc(a + b*x)/(S(4)*b) + S(3)*cot(a + b*x)*csc(a + b*x)/(S(8)*b) - S(3)*atanh(cos(a + b*x))/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(3)/sin(a + b*x)**S(5), x), x, -cot(a + b*x)**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(2)/sin(a + b*x)**S(5), x), x, -cot(a + b*x)*csc(a + b*x)**S(3)/(S(4)*b) + cot(a + b*x)*csc(a + b*x)/(S(8)*b) + atanh(cos(a + b*x))/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)/sin(a + b*x)**S(5), x), x, -csc(a + b*x)**S(4)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)/sin(a + b*x)**S(5), x), x, log(tan(a + b*x))/b - cot(a + b*x)**S(4)/(S(4)*b) - cot(a + b*x)**S(2)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(2)/sin(a + b*x)**S(5), x), x, -S(15)*atanh(cos(a + b*x))/(S(8)*b) - csc(a + b*x)**S(4)*sec(a + b*x)/(S(4)*b) - S(5)*csc(a + b*x)**S(2)*sec(a + b*x)/(S(8)*b) + S(15)*sec(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3)/sin(a + b*x)**S(5), x), x, S(3)*log(tan(a + b*x))/b + tan(a + b*x)**S(2)/(S(2)*b) - cot(a + b*x)**S(4)/(S(4)*b) - S(3)*cot(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(4)/sin(a + b*x)**S(5), x), x, -S(35)*atanh(cos(a + b*x))/(S(8)*b) - csc(a + b*x)**S(4)*sec(a + b*x)**S(3)/(S(4)*b) - S(7)*csc(a + b*x)**S(2)*sec(a + b*x)**S(3)/(S(8)*b) + S(35)*sec(a + b*x)**S(3)/(S(24)*b) + S(35)*sec(a + b*x)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(5)/sin(a + b*x)**S(5), x), x, S(6)*log(tan(a + b*x))/b + tan(a + b*x)**S(4)/(S(4)*b) + S(2)*tan(a + b*x)**S(2)/b - cot(a + b*x)**S(4)/(S(4)*b) - S(2)*cot(a + b*x)**S(2)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(x)**S(2)/sin(x)**S(6), x), x, -cot(x)**S(5)/S(5) - cot(x)**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(x)**S(3)/sin(x)**S(7), x), x, -csc(x)**S(6)/S(6) + csc(x)**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(3)/2)*sin(a + b*x), x), x, -S(2)*(d*cos(a + b*x))**(S(5)/2)/(S(5)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))*sin(a + b*x), x), x, -S(2)*(d*cos(a + b*x))**(S(3)/2)/(S(3)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/sqrt(d*cos(a + b*x)), x), x, -S(2)*sqrt(d*cos(a + b*x))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/(d*cos(a + b*x))**(S(3)/2), x), x, S(2)/(b*d*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/(d*cos(a + b*x))**(S(5)/2), x), x, S(2)/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/(d*cos(a + b*x))**(S(7)/2), x), x, S(2)/(S(5)*b*d*(d*cos(a + b*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/(d*cos(a + b*x))**(S(9)/2), x), x, S(2)/(S(7)*b*d*(d*cos(a + b*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(9)/2)*sin(a + b*x)**S(2), x), x, S(28)*d**S(4)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(195)*b*sqrt(cos(a + b*x))) + S(28)*d**S(3)*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(585)*b) + S(4)*d*(d*cos(a + b*x))**(S(7)/2)*sin(a + b*x)/(S(117)*b) - S(2)*(d*cos(a + b*x))**(S(11)/2)*sin(a + b*x)/(S(13)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(7)/2)*sin(a + b*x)**S(2), x), x, S(20)*d**S(4)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(231)*b*sqrt(d*cos(a + b*x))) + S(20)*d**S(3)*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(231)*b) + S(4)*d*(d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)/(S(77)*b) - S(2)*(d*cos(a + b*x))**(S(9)/2)*sin(a + b*x)/(S(11)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)**S(2), x), x, S(4)*d**S(2)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(15)*b*sqrt(cos(a + b*x))) + S(4)*d*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(45)*b) - S(2)*(d*cos(a + b*x))**(S(7)/2)*sin(a + b*x)/(S(9)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)**S(2), x), x, S(4)*d**S(2)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(21)*b*sqrt(d*cos(a + b*x))) + S(4)*d*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(21)*b) - S(2)*(d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)/(S(7)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))*sin(a + b*x)**S(2), x), x, S(4)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*sqrt(cos(a + b*x))) - S(2)*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(5)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/sqrt(d*cos(a + b*x)), x), x, S(4)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(3)*b*sqrt(d*cos(a + b*x))) - S(2)*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(3)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/(d*cos(a + b*x))**(S(3)/2), x), x, S(2)*sin(a + b*x)/(b*d*sqrt(d*cos(a + b*x))) - S(4)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(b*d**S(2)*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/(d*cos(a + b*x))**(S(5)/2), x), x, S(2)*sin(a + b*x)/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)) - S(4)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(3)*b*d**S(2)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/(d*cos(a + b*x))**(S(7)/2), x), x, S(2)*sin(a + b*x)/(S(5)*b*d*(d*cos(a + b*x))**(S(5)/2)) - S(4)*sin(a + b*x)/(S(5)*b*d**S(3)*sqrt(d*cos(a + b*x))) + S(4)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*d**S(4)*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/(d*cos(a + b*x))**(S(9)/2), x), x, S(2)*sin(a + b*x)/(S(7)*b*d*(d*cos(a + b*x))**(S(7)/2)) - S(4)*sin(a + b*x)/(S(21)*b*d**S(3)*(d*cos(a + b*x))**(S(3)/2)) - S(4)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(21)*b*d**S(4)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))*sin(a + b*x)**S(3), x), x, -S(2)*(d*cos(a + b*x))**(S(3)/2)/(S(3)*b*d) + S(2)*(d*cos(a + b*x))**(S(7)/2)/(S(7)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/sqrt(d*cos(a + b*x)), x), x, -S(2)*sqrt(d*cos(a + b*x))/(b*d) + S(2)*(d*cos(a + b*x))**(S(5)/2)/(S(5)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/(d*cos(a + b*x))**(S(3)/2), x), x, S(2)/(b*d*sqrt(d*cos(a + b*x))) + S(2)*(d*cos(a + b*x))**(S(3)/2)/(S(3)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/(d*cos(a + b*x))**(S(5)/2), x), x, S(2)/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)) + S(2)*sqrt(d*cos(a + b*x))/(b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/(d*cos(a + b*x))**(S(7)/2), x), x, S(2)/(S(5)*b*d*(d*cos(a + b*x))**(S(5)/2)) - S(2)/(b*d**S(3)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/(d*cos(a + b*x))**(S(9)/2), x), x, S(2)/(S(7)*b*d*(d*cos(a + b*x))**(S(7)/2)) - S(2)/(S(3)*b*d**S(3)*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/(d*cos(a + b*x))**(S(11)/2), x), x, S(2)/(S(9)*b*d*(d*cos(a + b*x))**(S(9)/2)) - S(2)/(S(5)*b*d**S(3)*(d*cos(a + b*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(9)/2)*sin(a + b*x)**S(4), x), x, S(56)*d**S(4)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(1105)*b*sqrt(cos(a + b*x))) + S(56)*d**S(3)*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(3315)*b) + S(8)*d*(d*cos(a + b*x))**(S(7)/2)*sin(a + b*x)/(S(663)*b) - S(2)*(d*cos(a + b*x))**(S(11)/2)*sin(a + b*x)**S(3)/(S(17)*b*d) - S(12)*(d*cos(a + b*x))**(S(11)/2)*sin(a + b*x)/(S(221)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(7)/2)*sin(a + b*x)**S(4), x), x, S(8)*d**S(4)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(231)*b*sqrt(d*cos(a + b*x))) + S(8)*d**S(3)*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(231)*b) + S(8)*d*(d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)/(S(385)*b) - S(2)*(d*cos(a + b*x))**(S(9)/2)*sin(a + b*x)**S(3)/(S(15)*b*d) - S(4)*(d*cos(a + b*x))**(S(9)/2)*sin(a + b*x)/(S(55)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)**S(4), x), x, S(8)*d**S(2)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(65)*b*sqrt(cos(a + b*x))) + S(8)*d*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(195)*b) - S(2)*(d*cos(a + b*x))**(S(7)/2)*sin(a + b*x)**S(3)/(S(13)*b*d) - S(4)*(d*cos(a + b*x))**(S(7)/2)*sin(a + b*x)/(S(39)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)**S(4), x), x, S(8)*d**S(2)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(77)*b*sqrt(d*cos(a + b*x))) + S(8)*d*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(77)*b) - S(2)*(d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)**S(3)/(S(11)*b*d) - S(12)*(d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)/(S(77)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))*sin(a + b*x)**S(4), x), x, S(8)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(15)*b*sqrt(cos(a + b*x))) - S(2)*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)**S(3)/(S(9)*b*d) - S(4)*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(15)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/sqrt(d*cos(a + b*x)), x), x, S(8)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(7)*b*sqrt(d*cos(a + b*x))) - S(2)*sqrt(d*cos(a + b*x))*sin(a + b*x)**S(3)/(S(7)*b*d) - S(4)*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(7)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/(d*cos(a + b*x))**(S(3)/2), x), x, S(2)*sin(a + b*x)**S(3)/(b*d*sqrt(d*cos(a + b*x))) - S(24)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*d**S(2)*sqrt(cos(a + b*x))) + S(12)*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(5)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/(d*cos(a + b*x))**(S(5)/2), x), x, S(2)*sin(a + b*x)**S(3)/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)) - S(8)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(3)*b*d**S(2)*sqrt(d*cos(a + b*x))) + S(4)*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(3)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/(d*cos(a + b*x))**(S(7)/2), x), x, S(2)*sin(a + b*x)**S(3)/(S(5)*b*d*(d*cos(a + b*x))**(S(5)/2)) - S(12)*sin(a + b*x)/(S(5)*b*d**S(3)*sqrt(d*cos(a + b*x))) + S(24)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*d**S(4)*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/(d*cos(a + b*x))**(S(9)/2), x), x, S(2)*sin(a + b*x)**S(3)/(S(7)*b*d*(d*cos(a + b*x))**(S(7)/2)) - S(4)*sin(a + b*x)/(S(7)*b*d**S(3)*(d*cos(a + b*x))**(S(3)/2)) + S(8)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(7)*b*d**S(4)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)*cos(a + b*x)**(S(3)/2), x), x, -S(2)*cos(a + b*x)**(S(13)/2)/(S(13)*b) + S(4)*cos(a + b*x)**(S(9)/2)/(S(9)*b) - S(2)*cos(a + b*x)**(S(5)/2)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(9)/2)*csc(a + b*x), x), x, d**(S(9)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/b - d**(S(9)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/b + S(2)*d**S(3)*(d*cos(a + b*x))**(S(3)/2)/(S(3)*b) + S(2)*d*(d*cos(a + b*x))**(S(7)/2)/(S(7)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(7)/2)*csc(a + b*x), x), x, -d**(S(7)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/b - d**(S(7)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/b + S(2)*d**S(3)*sqrt(d*cos(a + b*x))/b + S(2)*d*(d*cos(a + b*x))**(S(5)/2)/(S(5)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(5)/2)*csc(a + b*x), x), x, d**(S(5)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/b - d**(S(5)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/b + S(2)*d*(d*cos(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(3)/2)*csc(a + b*x), x), x, -d**(S(3)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/b - d**(S(3)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/b + S(2)*d*sqrt(d*cos(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))*csc(a + b*x), x), x, sqrt(d)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/b - sqrt(d)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/sqrt(d*cos(a + b*x)), x), x, -ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(b*sqrt(d)) - atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(b*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/(d*cos(a + b*x))**(S(3)/2), x), x, S(2)/(b*d*sqrt(d*cos(a + b*x))) + ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(3)/2)) - atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/(d*cos(a + b*x))**(S(5)/2), x), x, S(2)/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)) - ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(5)/2)) - atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/(d*cos(a + b*x))**(S(7)/2), x), x, S(2)/(S(5)*b*d*(d*cos(a + b*x))**(S(5)/2)) + S(2)/(b*d**S(3)*sqrt(d*cos(a + b*x))) + ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(7)/2)) - atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/(d*cos(a + b*x))**(S(9)/2), x), x, S(2)/(S(7)*b*d*(d*cos(a + b*x))**(S(7)/2)) + S(2)/(S(3)*b*d**S(3)*(d*cos(a + b*x))**(S(3)/2)) - ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(9)/2)) - atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(b*d**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(11)/2)*csc(a + b*x)**S(2), x), x, -S(15)*d**S(6)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(7)*b*sqrt(d*cos(a + b*x))) - S(15)*d**S(5)*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(7)*b) - S(9)*d**S(3)*(d*cos(a + b*x))**(S(5)/2)*sin(a + b*x)/(S(7)*b) - d*(d*cos(a + b*x))**(S(9)/2)*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(9)/2)*csc(a + b*x)**S(2), x), x, -S(21)*d**S(4)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*sqrt(cos(a + b*x))) - S(7)*d**S(3)*(d*cos(a + b*x))**(S(3)/2)*sin(a + b*x)/(S(5)*b) - d*(d*cos(a + b*x))**(S(7)/2)*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(7)/2)*csc(a + b*x)**S(2), x), x, -S(5)*d**S(4)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(3)*b*sqrt(d*cos(a + b*x))) - S(5)*d**S(3)*sqrt(d*cos(a + b*x))*sin(a + b*x)/(S(3)*b) - d*(d*cos(a + b*x))**(S(5)/2)*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(5)/2)*csc(a + b*x)**S(2), x), x, -S(3)*d**S(2)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(b*sqrt(cos(a + b*x))) - d*(d*cos(a + b*x))**(S(3)/2)*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(3)/2)*csc(a + b*x)**S(2), x), x, -d**S(2)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(b*sqrt(d*cos(a + b*x))) - d*sqrt(d*cos(a + b*x))*csc(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))*csc(a + b*x)**S(2), x), x, -sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(b*sqrt(cos(a + b*x))) - (d*cos(a + b*x))**(S(3)/2)*csc(a + b*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(2)/sqrt(d*cos(a + b*x)), x), x, EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(b*sqrt(d*cos(a + b*x))) - sqrt(d*cos(a + b*x))*csc(a + b*x)/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(2)/(d*cos(a + b*x))**(S(3)/2), x), x, S(3)*sin(a + b*x)/(b*d*sqrt(d*cos(a + b*x))) - csc(a + b*x)/(b*d*sqrt(d*cos(a + b*x))) - S(3)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(b*d**S(2)*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(2)/(d*cos(a + b*x))**(S(5)/2), x), x, S(5)*sin(a + b*x)/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)) - csc(a + b*x)/(b*d*(d*cos(a + b*x))**(S(3)/2)) + S(5)*EllipticF(a/S(2) + b*x/S(2), S(2))*sqrt(cos(a + b*x))/(S(3)*b*d**S(2)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(2)/(d*cos(a + b*x))**(S(7)/2), x), x, S(7)*sin(a + b*x)/(S(5)*b*d*(d*cos(a + b*x))**(S(5)/2)) - csc(a + b*x)/(b*d*(d*cos(a + b*x))**(S(5)/2)) + S(21)*sin(a + b*x)/(S(5)*b*d**S(3)*sqrt(d*cos(a + b*x))) - S(21)*sqrt(d*cos(a + b*x))*EllipticE(a/S(2) + b*x/S(2), S(2))/(S(5)*b*d**S(4)*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(11)/2)*csc(a + b*x)**S(3), x), x, S(9)*d**(S(11)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) + S(9)*d**(S(11)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) - S(9)*d**S(5)*sqrt(d*cos(a + b*x))/(S(2)*b) - S(9)*d**S(3)*(d*cos(a + b*x))**(S(5)/2)/(S(10)*b) - d*(d*cos(a + b*x))**(S(9)/2)*csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(9)/2)*csc(a + b*x)**S(3), x), x, -S(7)*d**(S(9)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) + S(7)*d**(S(9)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) - S(7)*d**S(3)*(d*cos(a + b*x))**(S(3)/2)/(S(6)*b) - d*(d*cos(a + b*x))**(S(7)/2)*csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(7)/2)*csc(a + b*x)**S(3), x), x, S(5)*d**(S(7)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) + S(5)*d**(S(7)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) - S(5)*d**S(3)*sqrt(d*cos(a + b*x))/(S(2)*b) - d*(d*cos(a + b*x))**(S(5)/2)*csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(5)/2)*csc(a + b*x)**S(3), x), x, -S(3)*d**(S(5)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) + S(3)*d**(S(5)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) - d*(d*cos(a + b*x))**(S(3)/2)*csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(3)/2)*csc(a + b*x)**S(3), x), x, d**(S(3)/2)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) + d**(S(3)/2)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) - d*sqrt(d*cos(a + b*x))*csc(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))*csc(a + b*x)**S(3), x), x, sqrt(d)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) - sqrt(d)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b) - (d*cos(a + b*x))**(S(3)/2)*csc(a + b*x)**S(2)/(S(2)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(3)/sqrt(d*cos(a + b*x)), x), x, -sqrt(d*cos(a + b*x))*csc(a + b*x)**S(2)/(S(2)*b*d) - S(3)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*sqrt(d)) - S(3)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(3)/(d*cos(a + b*x))**(S(3)/2), x), x, -csc(a + b*x)**S(2)/(S(2)*b*d*sqrt(d*cos(a + b*x))) + S(5)/(S(2)*b*d*sqrt(d*cos(a + b*x))) + S(5)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*d**(S(3)/2)) - S(5)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(3)/(d*cos(a + b*x))**(S(5)/2), x), x, -csc(a + b*x)**S(2)/(S(2)*b*d*(d*cos(a + b*x))**(S(3)/2)) + S(7)/(S(6)*b*d*(d*cos(a + b*x))**(S(3)/2)) - S(7)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*d**(S(5)/2)) - S(7)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(3)/(d*cos(a + b*x))**(S(7)/2), x), x, -csc(a + b*x)**S(2)/(S(2)*b*d*(d*cos(a + b*x))**(S(5)/2)) + S(9)/(S(10)*b*d*(d*cos(a + b*x))**(S(5)/2)) + S(9)/(S(2)*b*d**S(3)*sqrt(d*cos(a + b*x))) + S(9)*ArcTan(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*d**(S(7)/2)) - S(9)*atanh(sqrt(d*cos(a + b*x))/sqrt(d))/(S(4)*b*d**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(1)/5)*sin(a + b*x), x), x, -S(5)*(d*cos(a + b*x))**(S(6)/5)/(S(6)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sin(x))*cos(x)**S(3), x), x, -S(2)*sin(x)**(S(7)/2)/S(7) + S(2)*sin(x)**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(x)**(S(3)/2)*cos(x)**S(3), x), x, -S(2)*sin(x)**(S(9)/2)/S(9) + S(2)*sin(x)**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(x)**(S(5)/2)*cos(x)**S(3), x), x, -S(2)*sin(x)**(S(11)/2)/S(11) + S(2)*sin(x)**(S(7)/2)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(x)**S(3)/sqrt(sin(x)), x), x, -S(2)*sin(x)**(S(5)/2)/S(5) + S(2)*sqrt(sin(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(9)/2), x), x, S(7)*d**S(4)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(20)*b*sqrt(sin(S(2)*a + S(2)*b*x))) + S(7)*d**S(3)*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(3)/2)/(S(30)*b*c) + d*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(7)/2)/(S(5)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(5)/2), x), x, d**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(2)*b*sqrt(sin(S(2)*a + S(2)*b*x))) + d*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(3)/2)/(S(3)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x)), x), x, sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))/(d*cos(a + b*x))**(S(3)/2), x), x, -S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*(c*sin(a + b*x))**(S(3)/2)/(b*c*d*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))/(d*cos(a + b*x))**(S(7)/2), x), x, -S(4)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(5)*b*d**S(4)*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*(c*sin(a + b*x))**(S(3)/2)/(S(5)*b*c*d*(d*cos(a + b*x))**(S(5)/2)) + S(4)*(c*sin(a + b*x))**(S(3)/2)/(S(5)*b*c*d**S(3)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(3)/2), x), x, -sqrt(S(2))*sqrt(c)*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(8)*b) + sqrt(S(2))*sqrt(c)*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(8)*b) + sqrt(S(2))*sqrt(c)*d**(S(3)/2)*log(sqrt(c)*tan(a + b*x) + sqrt(c) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(16)*b) - sqrt(S(2))*sqrt(c)*d**(S(3)/2)*log(sqrt(c)*tan(a + b*x) + sqrt(c) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(16)*b) + d*(c*sin(a + b*x))**(S(3)/2)*sqrt(d*cos(a + b*x))/(S(2)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)), x), x, -sqrt(S(2))*sqrt(c)*ArcTan(S(1) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(2)*b*sqrt(d)) + sqrt(S(2))*sqrt(c)*ArcTan(S(1) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(2)*b*sqrt(d)) + sqrt(S(2))*sqrt(c)*log(sqrt(c)*tan(a + b*x) + sqrt(c) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(4)*b*sqrt(d)) - sqrt(S(2))*sqrt(c)*log(sqrt(c)*tan(a + b*x) + sqrt(c) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(4)*b*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))/(d*cos(a + b*x))**(S(5)/2), x), x, S(2)*(c*sin(a + b*x))**(S(3)/2)/(S(3)*b*c*d*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))/(d*cos(a + b*x))**(S(9)/2), x), x, S(2)*(c*sin(a + b*x))**(S(3)/2)/(S(7)*b*c*d*(d*cos(a + b*x))**(S(7)/2)) + S(8)*(c*sin(a + b*x))**(S(3)/2)/(S(21)*b*c*d**S(3)*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))/(d*cos(a + b*x))**(S(13)/2), x), x, S(2)*(c*sin(a + b*x))**(S(3)/2)/(S(11)*b*c*d*(d*cos(a + b*x))**(S(11)/2)) + S(16)*(c*sin(a + b*x))**(S(3)/2)/(S(77)*b*c*d**S(3)*(d*cos(a + b*x))**(S(7)/2)) + S(64)*(c*sin(a + b*x))**(S(3)/2)/(S(231)*b*c*d**S(5)*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(3)/2), x), x, c**S(2)*d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(12)*b*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) + c*d*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))/(S(6)*b) - c*sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(5)/2)/(S(3)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)/sqrt(d*cos(a + b*x)), x), x, c**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(2)*b*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) - c*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))/(b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)/(d*cos(a + b*x))**(S(5)/2), x), x, -c**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(3)*b*d**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) + S(2)*c*sqrt(c*sin(a + b*x))/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)/(d*cos(a + b*x))**(S(9)/2), x), x, -S(2)*c**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(21)*b*d**S(4)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) + S(2)*c*sqrt(c*sin(a + b*x))/(S(7)*b*d*(d*cos(a + b*x))**(S(7)/2)) - S(2)*c*sqrt(c*sin(a + b*x))/(S(21)*b*d**S(3)*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)*sqrt(d*cos(a + b*x)), x), x, sqrt(S(2))*c**(S(3)/2)*sqrt(d)*ArcTan(-sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/(sqrt(d)*sqrt(c*sin(a + b*x))) + S(1))/(S(8)*b) - sqrt(S(2))*c**(S(3)/2)*sqrt(d)*ArcTan(sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/(sqrt(d)*sqrt(c*sin(a + b*x))) + S(1))/(S(8)*b) - sqrt(S(2))*c**(S(3)/2)*sqrt(d)*log(-sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/sqrt(c*sin(a + b*x)) + sqrt(d)*cot(a + b*x) + sqrt(d))/(S(16)*b) + sqrt(S(2))*c**(S(3)/2)*sqrt(d)*log(sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/sqrt(c*sin(a + b*x)) + sqrt(d)*cot(a + b*x) + sqrt(d))/(S(16)*b) - c*sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(3)/2)/(S(2)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)/(d*cos(a + b*x))**(S(3)/2), x), x, -sqrt(S(2))*c**(S(3)/2)*ArcTan(-sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/(sqrt(d)*sqrt(c*sin(a + b*x))) + S(1))/(S(2)*b*d**(S(3)/2)) + sqrt(S(2))*c**(S(3)/2)*ArcTan(sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/(sqrt(d)*sqrt(c*sin(a + b*x))) + S(1))/(S(2)*b*d**(S(3)/2)) + sqrt(S(2))*c**(S(3)/2)*log(-sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/sqrt(c*sin(a + b*x)) + sqrt(d)*cot(a + b*x) + sqrt(d))/(S(4)*b*d**(S(3)/2)) - sqrt(S(2))*c**(S(3)/2)*log(sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/sqrt(c*sin(a + b*x)) + sqrt(d)*cot(a + b*x) + sqrt(d))/(S(4)*b*d**(S(3)/2)) + S(2)*c*sqrt(c*sin(a + b*x))/(b*d*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)/(d*cos(a + b*x))**(S(7)/2), x), x, S(2)*(c*sin(a + b*x))**(S(5)/2)/(S(5)*b*c*d*(d*cos(a + b*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)/(d*cos(a + b*x))**(S(11)/2), x), x, S(2)*c*sqrt(c*sin(a + b*x))/(S(9)*b*d*(d*cos(a + b*x))**(S(9)/2)) - S(2)*c*sqrt(c*sin(a + b*x))/(S(45)*b*d**S(3)*(d*cos(a + b*x))**(S(5)/2)) - S(8)*c*sqrt(c*sin(a + b*x))/(S(45)*b*d**S(5)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)/(d*cos(a + b*x))**(S(15)/2), x), x, S(2)*c*sqrt(c*sin(a + b*x))/(S(13)*b*d*(d*cos(a + b*x))**(S(13)/2)) - S(2)*c*sqrt(c*sin(a + b*x))/(S(117)*b*d**S(3)*(d*cos(a + b*x))**(S(9)/2)) - S(16)*c*sqrt(c*sin(a + b*x))/(S(585)*b*d**S(5)*(d*cos(a + b*x))**(S(5)/2)) - S(64)*c*sqrt(c*sin(a + b*x))/(S(585)*b*d**S(7)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)*(d*cos(a + b*x))**(S(9)/2), x), x, S(3)*c**S(2)*d**S(4)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(40)*b*sqrt(sin(S(2)*a + S(2)*b*x))) + c*d**S(3)*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(3)/2)/(S(20)*b) + S(3)*c*d*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(7)/2)/(S(70)*b) - c*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(11)/2)/(S(7)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)*(d*cos(a + b*x))**(S(5)/2), x), x, S(3)*c**S(2)*d**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(20)*b*sqrt(sin(S(2)*a + S(2)*b*x))) + c*d*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(3)/2)/(S(10)*b) - c*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(7)/2)/(S(5)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)*sqrt(d*cos(a + b*x)), x), x, c**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(2)*b*sqrt(sin(S(2)*a + S(2)*b*x))) - c*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(S(3)/2)/(S(3)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/(d*cos(a + b*x))**(S(3)/2), x), x, -S(3)*c**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(b*d*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/(d*cos(a + b*x))**(S(7)/2), x), x, S(6)*c**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(5)*b*d**S(4)*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(S(5)*b*d*(d*cos(a + b*x))**(S(5)/2)) - S(6)*c*(c*sin(a + b*x))**(S(3)/2)/(S(5)*b*d**S(3)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/(d*cos(a + b*x))**(S(11)/2), x), x, S(4)*c**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))/(S(15)*b*d**S(6)*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(S(9)*b*d*(d*cos(a + b*x))**(S(9)/2)) - S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(S(15)*b*d**S(3)*(d*cos(a + b*x))**(S(5)/2)) - S(4)*c*(c*sin(a + b*x))**(S(3)/2)/(S(15)*b*d**S(5)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/sqrt(d*cos(a + b*x)), x), x, -S(3)*sqrt(S(2))*c**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(8)*b*sqrt(d)) + S(3)*sqrt(S(2))*c**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(8)*b*sqrt(d)) + S(3)*sqrt(S(2))*c**(S(5)/2)*log(sqrt(c)*tan(a + b*x) + sqrt(c) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(16)*b*sqrt(d)) - S(3)*sqrt(S(2))*c**(S(5)/2)*log(sqrt(c)*tan(a + b*x) + sqrt(c) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(16)*b*sqrt(d)) - c*(c*sin(a + b*x))**(S(3)/2)*sqrt(d*cos(a + b*x))/(S(2)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/(d*cos(a + b*x))**(S(5)/2), x), x, sqrt(S(2))*c**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(2)*b*d**(S(5)/2)) - sqrt(S(2))*c**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/(sqrt(c)*sqrt(d*cos(a + b*x))))/(S(2)*b*d**(S(5)/2)) - sqrt(S(2))*c**(S(5)/2)*log(sqrt(c)*tan(a + b*x) + sqrt(c) - sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(4)*b*d**(S(5)/2)) + sqrt(S(2))*c**(S(5)/2)*log(sqrt(c)*tan(a + b*x) + sqrt(c) + sqrt(S(2))*sqrt(d)*sqrt(c*sin(a + b*x))/sqrt(d*cos(a + b*x)))/(S(4)*b*d**(S(5)/2)) + S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(S(3)*b*d*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/(d*cos(a + b*x))**(S(9)/2), x), x, S(2)*(c*sin(a + b*x))**(S(7)/2)/(S(7)*b*c*d*(d*cos(a + b*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/(d*cos(a + b*x))**(S(13)/2), x), x, S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(S(11)*b*d*(d*cos(a + b*x))**(S(11)/2)) - S(6)*c*(c*sin(a + b*x))**(S(3)/2)/(S(77)*b*d**S(3)*(d*cos(a + b*x))**(S(7)/2)) - S(8)*c*(c*sin(a + b*x))**(S(3)/2)/(S(77)*b*d**S(5)*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)/(d*cos(a + b*x))**(S(17)/2), x), x, S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(S(15)*b*d*(d*cos(a + b*x))**(S(15)/2)) - S(2)*c*(c*sin(a + b*x))**(S(3)/2)/(S(55)*b*d**S(3)*(d*cos(a + b*x))**(S(11)/2)) - S(16)*c*(c*sin(a + b*x))**(S(3)/2)/(S(385)*b*d**S(5)*(d*cos(a + b*x))**(S(7)/2)) - S(64)*c*(c*sin(a + b*x))**(S(3)/2)/(S(1155)*b*d**S(7)*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(7)/2)/cos(a + b*x)**(S(7)/2), x), x, sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(2)*b) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(2)*b) - sqrt(S(2))*log(cot(a + b*x) + S(1) - sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(4)*b) + sqrt(S(2))*log(cot(a + b*x) + S(1) + sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(4)*b) + S(2)*sin(a + b*x)**(S(5)/2)/(S(5)*b*cos(a + b*x)**(S(5)/2)) - S(2)*sqrt(sin(a + b*x))/(b*sqrt(cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(x)**(S(3)/2)/cos(x)**(S(7)/2), x), x, S(2)*sin(x)**(S(5)/2)/(S(5)*cos(x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sin(x))/sqrt(cos(x)), x), x, -sqrt(S(2))*ArcTan(-sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + S(1))/S(2) + sqrt(S(2))*ArcTan(sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + S(1))/S(2) + sqrt(S(2))*log(-sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + tan(x) + S(1))/S(4) - sqrt(S(2))*log(sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + tan(x) + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(x)**(S(5)/2)/sqrt(cos(x)), x), x, -S(3)*sqrt(S(2))*ArcTan(-sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + S(1))/S(8) + S(3)*sqrt(S(2))*ArcTan(sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + S(1))/S(8) + S(3)*sqrt(S(2))*log(-sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + tan(x) + S(1))/S(16) - S(3)*sqrt(S(2))*log(sqrt(S(2))*sqrt(sin(x))/sqrt(cos(x)) + tan(x) + S(1))/S(16) - sin(x)**(S(3)/2)*sqrt(cos(x))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(7)/2)/sqrt(c*sin(a + b*x)), x), x, S(5)*d**S(4)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(12)*b*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) + S(5)*d**S(3)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))/(S(6)*b*c) + d*sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(5)/2)/(S(3)*b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**(S(3)/2)/sqrt(c*sin(a + b*x)), x), x, d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(2)*b*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) + d*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))/(b*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))), x), x, EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(b*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(5)/2)), x), x, S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(3)*b*d**S(2)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) + S(2)*sqrt(c*sin(a + b*x))/(S(3)*b*c*d*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(9)/2)), x), x, S(4)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))/(S(7)*b*d**S(4)*sqrt(c*sin(a + b*x))*sqrt(d*cos(a + b*x))) + S(2)*sqrt(c*sin(a + b*x))/(S(7)*b*c*d*(d*cos(a + b*x))**(S(7)/2)) + S(4)*sqrt(c*sin(a + b*x))/(S(7)*b*c*d**S(3)*(d*cos(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cos(a + b*x))/sqrt(c*sin(a + b*x)), x), x, sqrt(S(2))*sqrt(d)*ArcTan(-sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/(sqrt(d)*sqrt(c*sin(a + b*x))) + S(1))/(S(2)*b*sqrt(c)) - sqrt(S(2))*sqrt(d)*ArcTan(sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/(sqrt(d)*sqrt(c*sin(a + b*x))) + S(1))/(S(2)*b*sqrt(c)) - sqrt(S(2))*sqrt(d)*log(-sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/sqrt(c*sin(a + b*x)) + sqrt(d)*cot(a + b*x) + sqrt(d))/(S(4)*b*sqrt(c)) + sqrt(S(2))*sqrt(d)*log(sqrt(S(2))*sqrt(c)*sqrt(d*cos(a + b*x))/sqrt(c*sin(a + b*x)) + sqrt(d)*cot(a + b*x) + sqrt(d))/(S(4)*b*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(3)/2)), x), x, S(2)*sqrt(c*sin(a + b*x))/(b*c*d*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(7)/2)), x), x, S(2)*sqrt(c*sin(a + b*x))/(S(5)*b*c*d*(d*cos(a + b*x))**(S(5)/2)) + S(8)*sqrt(c*sin(a + b*x))/(S(5)*b*c*d**S(3)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(S(11)/2)), x), x, S(2)*sqrt(c*sin(a + b*x))/(S(9)*b*c*d*(d*cos(a + b*x))**(S(9)/2)) + S(16)*sqrt(c*sin(a + b*x))/(S(45)*b*c*d**S(3)*(d*cos(a + b*x))**(S(5)/2)) + S(64)*sqrt(c*sin(a + b*x))/(S(45)*b*c*d**S(5)*sqrt(d*cos(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(cos(a + b*x))/sqrt(sin(a + b*x)), x), x, sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(2)*b) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(2)*b) - sqrt(S(2))*log(cot(a + b*x) + S(1) - sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(4)*b) + sqrt(S(2))*log(cot(a + b*x) + S(1) + sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(3)/2)/sin(a + b*x)**(S(3)/2), x), x, sqrt(S(2))*ArcTan(-sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + S(1))/(S(2)*b) - sqrt(S(2))*ArcTan(sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + S(1))/(S(2)*b) - sqrt(S(2))*log(-sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b) + sqrt(S(2))*log(sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b) - S(2)*sqrt(cos(a + b*x))/(b*sqrt(sin(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(5)/2)/sin(a + b*x)**(S(5)/2), x), x, -sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(2)*b) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(2)*b) + sqrt(S(2))*log(cot(a + b*x) + S(1) - sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(4)*b) - sqrt(S(2))*log(cot(a + b*x) + S(1) + sqrt(S(2))*sqrt(cos(a + b*x))/sqrt(sin(a + b*x)))/(S(4)*b) - S(2)*cos(a + b*x)**(S(3)/2)/(S(3)*b*sin(a + b*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(7)/2)/sin(a + b*x)**(S(7)/2), x), x, -sqrt(S(2))*ArcTan(-sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + S(1))/(S(2)*b) + sqrt(S(2))*ArcTan(sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + S(1))/(S(2)*b) + sqrt(S(2))*log(-sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b) - sqrt(S(2))*log(sqrt(S(2))*sqrt(sin(a + b*x))/sqrt(cos(a + b*x)) + tan(a + b*x) + S(1))/(S(4)*b) + S(2)*sqrt(cos(a + b*x))/(b*sqrt(sin(a + b*x))) - S(2)*cos(a + b*x)**(S(5)/2)/(S(5)*b*sin(a + b*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(1)/3)*cos(e + f*x)**S(4), x), x, S(3)*(b*sin(e + f*x))**(S(4)/3)*Hypergeometric2F1(S(-3)/2, S(2)/3, S(5)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(4)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(1)/3)*cos(e + f*x)**S(2), x), x, S(3)*(b*sin(e + f*x))**(S(4)/3)*Hypergeometric2F1(S(-1)/2, S(2)/3, S(5)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(4)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(1)/3), x), x, S(3)*(b*sin(e + f*x))**(S(4)/3)*Hypergeometric2F1(S(1)/2, S(2)/3, S(5)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(4)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(1)/3)*sec(e + f*x)**S(2), x), x, S(3)*(b*sin(e + f*x))**(S(4)/3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(2)/3, S(3)/2, S(5)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(4)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(1)/3)*sec(e + f*x)**S(4), x), x, S(3)*(b*sin(e + f*x))**(S(4)/3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(2)/3, S(5)/2, S(5)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(4)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(5)/3)*cos(e + f*x)**S(4), x), x, S(3)*(b*sin(e + f*x))**(S(8)/3)*Hypergeometric2F1(S(-3)/2, S(4)/3, S(7)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(8)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(5)/3)*cos(e + f*x)**S(2), x), x, S(3)*(b*sin(e + f*x))**(S(8)/3)*Hypergeometric2F1(S(-1)/2, S(4)/3, S(7)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(8)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(5)/3), x), x, S(3)*(b*sin(e + f*x))**(S(8)/3)*Hypergeometric2F1(S(1)/2, S(4)/3, S(7)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(8)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(5)/3)*sec(e + f*x)**S(2), x), x, S(3)*(b*sin(e + f*x))**(S(8)/3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(4)/3, S(3)/2, S(7)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(8)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(5)/3)*sec(e + f*x)**S(4), x), x, S(3)*(b*sin(e + f*x))**(S(8)/3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(4)/3, S(5)/2, S(7)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(8)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(e + f*x)**S(4)/(b*sin(e + f*x))**(S(1)/3), x), x, S(3)*(b*sin(e + f*x))**(S(2)/3)*Hypergeometric2F1(S(-3)/2, S(1)/3, S(4)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(2)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(e + f*x)**S(2)/(b*sin(e + f*x))**(S(1)/3), x), x, S(3)*(b*sin(e + f*x))**(S(2)/3)*Hypergeometric2F1(S(-1)/2, S(1)/3, S(4)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(2)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(-1)/3), x), x, S(3)*(b*sin(e + f*x))**(S(2)/3)*Hypergeometric2F1(S(1)/3, S(1)/2, S(4)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(2)*b*f*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(e + f*x)**S(2)/(b*sin(e + f*x))**(S(1)/3), x), x, S(3)*(b*sin(e + f*x))**(S(2)/3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(1)/3, S(3)/2, S(4)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(2)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(e + f*x)**S(4)/(b*sin(e + f*x))**(S(1)/3), x), x, S(3)*(b*sin(e + f*x))**(S(2)/3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(1)/3, S(5)/2, S(4)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(2)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(e + f*x)**S(4)/(b*sin(e + f*x))**(S(5)/3), x), x, -S(3)*Hypergeometric2F1(S(-3)/2, S(-1)/3, S(2)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(2)*b*f*(b*sin(e + f*x))**(S(2)/3)*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(e + f*x)**S(2)/(b*sin(e + f*x))**(S(5)/3), x), x, -S(3)*Hypergeometric2F1(S(-1)/2, S(-1)/3, S(2)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(2)*b*f*(b*sin(e + f*x))**(S(2)/3)*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(-5)/3), x), x, -S(3)*Hypergeometric2F1(S(-1)/3, S(1)/2, S(2)/3, sin(e + f*x)**S(2))*cos(e + f*x)/(S(2)*b*f*(b*sin(e + f*x))**(S(2)/3)*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(e + f*x)**S(2)/(b*sin(e + f*x))**(S(5)/3), x), x, -S(3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(-1)/3, S(3)/2, S(2)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(2)*b*f*(b*sin(e + f*x))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(e + f*x)**S(4)/(b*sin(e + f*x))**(S(5)/3), x), x, -S(3)*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(-1)/3, S(5)/2, S(2)/3, sin(e + f*x)**S(2))*sec(e + f*x)/(S(2)*b*f*(b*sin(e + f*x))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3), x), x, -sqrt(S(3))*ArcTan(sqrt(S(3))*(-S(2)*sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/S(3))/(S(2)*b) - log(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/(S(2)*b) + log(sin(a + b*x)**(S(4)/3)/cos(a + b*x)**(S(4)/3) - sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3), x), x, ArcTan(sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3))/b - ArcTan(-S(2)*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + sqrt(S(3)))/(S(2)*b) + ArcTan(S(2)*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + sqrt(S(3)))/(S(2)*b) + sqrt(S(3))*log(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) - sqrt(S(3))*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + S(1))/(S(4)*b) - sqrt(S(3))*log(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + sqrt(S(3))*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + S(1))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(4)/3)/cos(a + b*x)**(S(4)/3), x), x, ArcTan(cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3))/b - ArcTan(sqrt(S(3)) - S(2)*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3))/(S(2)*b) + ArcTan(sqrt(S(3)) + S(2)*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3))/(S(2)*b) + sqrt(S(3))*log(S(1) - sqrt(S(3))*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3) + cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/(S(4)*b) - sqrt(S(3))*log(S(1) + sqrt(S(3))*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3) + cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/(S(4)*b) + S(3)*sin(a + b*x)**(S(1)/3)/(b*cos(a + b*x)**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(5)/3)/cos(a + b*x)**(S(5)/3), x), x, -sqrt(S(3))*ArcTan(sqrt(S(3))*(S(1) - S(2)*cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/S(3))/(S(2)*b) - log(S(1) + cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/(S(2)*b) + log(S(1) - cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3) + cos(a + b*x)**(S(4)/3)/sin(a + b*x)**(S(4)/3))/(S(4)*b) + S(3)*sin(a + b*x)**(S(2)/3)/(S(2)*b*cos(a + b*x)**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**(S(7)/3)/cos(a + b*x)**(S(7)/3), x), x, sqrt(S(3))*ArcTan(sqrt(S(3))*(-S(2)*sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/S(3))/(S(2)*b) + log(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/(S(2)*b) - log(sin(a + b*x)**(S(4)/3)/cos(a + b*x)**(S(4)/3) - sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/(S(4)*b) + S(3)*sin(a + b*x)**(S(4)/3)/(S(4)*b*cos(a + b*x)**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3), x), x, sqrt(S(3))*ArcTan(sqrt(S(3))*(S(1) - S(2)*cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/S(3))/(S(2)*b) + log(S(1) + cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/(S(2)*b) - log(S(1) - cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3) + cos(a + b*x)**(S(4)/3)/sin(a + b*x)**(S(4)/3))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3), x), x, -ArcTan(cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3))/b + ArcTan(sqrt(S(3)) - S(2)*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3))/(S(2)*b) - ArcTan(sqrt(S(3)) + S(2)*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3))/(S(2)*b) - sqrt(S(3))*log(S(1) - sqrt(S(3))*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3) + cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/(S(4)*b) + sqrt(S(3))*log(S(1) + sqrt(S(3))*cos(a + b*x)**(S(1)/3)/sin(a + b*x)**(S(1)/3) + cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(4)/3)/sin(a + b*x)**(S(4)/3), x), x, -ArcTan(sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3))/b + ArcTan(-S(2)*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + sqrt(S(3)))/(S(2)*b) - ArcTan(S(2)*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + sqrt(S(3)))/(S(2)*b) - sqrt(S(3))*log(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) - sqrt(S(3))*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + S(1))/(S(4)*b) + sqrt(S(3))*log(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + sqrt(S(3))*sin(a + b*x)**(S(1)/3)/cos(a + b*x)**(S(1)/3) + S(1))/(S(4)*b) - S(3)*cos(a + b*x)**(S(1)/3)/(b*sin(a + b*x)**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(5)/3)/sin(a + b*x)**(S(5)/3), x), x, sqrt(S(3))*ArcTan(sqrt(S(3))*(-S(2)*sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/S(3))/(S(2)*b) + log(sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/(S(2)*b) - log(sin(a + b*x)**(S(4)/3)/cos(a + b*x)**(S(4)/3) - sin(a + b*x)**(S(2)/3)/cos(a + b*x)**(S(2)/3) + S(1))/(S(4)*b) - S(3)*cos(a + b*x)**(S(2)/3)/(S(2)*b*sin(a + b*x)**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**(S(7)/3)/sin(a + b*x)**(S(7)/3), x), x, -sqrt(S(3))*ArcTan(sqrt(S(3))*(S(1) - S(2)*cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/S(3))/(S(2)*b) - log(S(1) + cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3))/(S(2)*b) + log(S(1) - cos(a + b*x)**(S(2)/3)/sin(a + b*x)**(S(2)/3) + cos(a + b*x)**(S(4)/3)/sin(a + b*x)**(S(4)/3))/(S(4)*b) - S(3)*cos(a + b*x)**(S(4)/3)/(S(4)*b*sin(a + b*x)**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(x)**(S(2)/3)/sin(x)**(S(8)/3), x), x, -S(3)*cos(x)**(S(5)/3)/(S(5)*sin(x)**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(x)**(S(2)/3)/cos(x)**(S(8)/3), x), x, S(3)*sin(x)**(S(5)/3)/(S(5)*cos(x)**(S(5)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**m*cos(e + f*x)**n, x), x, (cos(e + f*x)**S(2))**(-n/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, -n/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(e + f*x)**S(2))*sin(e + f*x)**(m + S(1))*cos(e + f*x)**(n + S(-1))/(f*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(e + f*x))**n*sin(e + f*x)**m, x), x, -(d*cos(e + f*x))**(n + S(1))*(sin(e + f*x)**S(2))**(-m/S(2) + S(1)/2)*Hypergeometric2F1(-m/S(2) + S(1)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(e + f*x)**S(2))*sin(e + f*x)**(m + S(-1))/(d*f*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*cos(e + f*x)**n, x), x, (b*sin(e + f*x))**(m + S(1))*(cos(e + f*x)**S(2))**(-n/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, -n/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(e + f*x)**S(2))*cos(e + f*x)**(n + S(-1))/(b*f*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*(d*cos(e + f*x))**n, x), x, d*(b*sin(e + f*x))**(m + S(1))*(d*cos(e + f*x))**(n + S(-1))*(cos(e + f*x)**S(2))**(-n/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, -n/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(e + f*x)**S(2))/(b*f*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*cos(a + b*x)**S(5), x), x, (c*sin(a + b*x))**(m + S(1))/(b*c*(m + S(1))) - S(2)*(c*sin(a + b*x))**(m + S(3))/(b*c**S(3)*(m + S(3))) + (c*sin(a + b*x))**(m + S(5))/(b*c**S(5)*(m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*cos(a + b*x)**S(3), x), x, (c*sin(a + b*x))**(m + S(1))/(b*c*(m + S(1))) - (c*sin(a + b*x))**(m + S(3))/(b*c**S(3)*(m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*cos(a + b*x), x), x, (c*sin(a + b*x))**(m + S(1))/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*sec(a + b*x), x), x, (c*sin(a + b*x))**(m + S(1))*Hypergeometric2F1(S(1), m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*sec(a + b*x)**S(3), x), x, (c*sin(a + b*x))**(m + S(1))*Hypergeometric2F1(S(2), m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*cos(a + b*x)**S(4), x), x, (c*sin(a + b*x))**(m + S(1))*Hypergeometric2F1(S(-3)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*cos(a + b*x)/(b*c*(m + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*cos(a + b*x)**S(2), x), x, (c*sin(a + b*x))**(m + S(1))*Hypergeometric2F1(S(-1)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*cos(a + b*x)/(b*c*(m + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m, x), x, (c*sin(a + b*x))**(m + S(1))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*cos(a + b*x)/(b*c*(m + S(1))*sqrt(cos(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*sec(a + b*x)**S(2), x), x, (c*sin(a + b*x))**(m + S(1))*sqrt(cos(a + b*x)**S(2))*Hypergeometric2F1(S(3)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*sec(a + b*x)/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*sec(a + b*x)**S(4), x), x, (c*sin(a + b*x))**(m + S(1))*sqrt(cos(a + b*x)**S(2))*Hypergeometric2F1(S(5)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*sec(a + b*x)/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*(d*cos(a + b*x))**(S(3)/2), x), x, d*(c*sin(a + b*x))**(m + S(1))*sqrt(d*cos(a + b*x))*Hypergeometric2F1(S(-1)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*(m + S(1))*(cos(a + b*x)**S(2))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*sqrt(d*cos(a + b*x)), x), x, d*(c*sin(a + b*x))**(m + S(1))*(cos(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(1)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*sqrt(d*cos(a + b*x))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m/sqrt(d*cos(a + b*x)), x), x, d*(c*sin(a + b*x))**(m + S(1))*(cos(a + b*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*(d*cos(a + b*x))**(S(3)/2)*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m/(d*cos(a + b*x))**(S(3)/2), x), x, (c*sin(a + b*x))**(m + S(1))*(cos(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*d*sqrt(d*cos(a + b*x))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m/(d*cos(a + b*x))**(S(5)/2), x), x, (c*sin(a + b*x))**(m + S(1))*(cos(a + b*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(7)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*d*(d*cos(a + b*x))**(S(3)/2)*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*sin(a + b*x)**S(5), x), x, -(d*cos(a + b*x))**(n + S(1))/(b*d*(n + S(1))) + S(2)*(d*cos(a + b*x))**(n + S(3))/(b*d**S(3)*(n + S(3))) - (d*cos(a + b*x))**(n + S(5))/(b*d**S(5)*(n + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*sin(a + b*x)**S(3), x), x, -(d*cos(a + b*x))**(n + S(1))/(b*d*(n + S(1))) + (d*cos(a + b*x))**(n + S(3))/(b*d**S(3)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*sin(a + b*x), x), x, -(d*cos(a + b*x))**(n + S(1))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*csc(a + b*x), x), x, -(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(1), n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*csc(a + b*x)**S(3), x), x, -(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(2), n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*csc(a + b*x)**S(5), x), x, -(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(3), n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*sin(a + b*x)**S(4), x), x, -(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(-3)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))*sin(a + b*x)/(b*d*(n + S(1))*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*sin(a + b*x)**S(2), x), x, -(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(-1)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))*sin(a + b*x)/(b*d*(n + S(1))*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n, x), x, -(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(1)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))*sin(a + b*x)/(b*d*(n + S(1))*sqrt(sin(a + b*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*csc(a + b*x)**S(2), x), x, -(d*cos(a + b*x))**(n + S(1))*sqrt(sin(a + b*x)**S(2))*Hypergeometric2F1(S(3)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))*csc(a + b*x)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n*csc(a + b*x)**S(4), x), x, -(d*cos(a + b*x))**(n + S(1))*sqrt(sin(a + b*x)**S(2))*Hypergeometric2F1(S(5)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))*csc(a + b*x)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(5)/2)*(d*cos(a + b*x))**n, x), x, -c*(c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(-3)/4, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*d*(n + S(1))*(sin(a + b*x)**S(2))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**(S(3)/2)*(d*cos(a + b*x))**n, x), x, -c*sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**(n + S(1))*Hypergeometric2F1(S(-1)/4, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*d*(n + S(1))*(sin(a + b*x)**S(2))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c*sin(a + b*x))*(d*cos(a + b*x))**n, x), x, -c*(d*cos(a + b*x))**(n + S(1))*(sin(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(1)/4, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*d*sqrt(c*sin(a + b*x))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n/sqrt(c*sin(a + b*x)), x), x, -c*(d*cos(a + b*x))**(n + S(1))*(sin(a + b*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*d*(c*sin(a + b*x))**(S(3)/2)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cos(a + b*x))**n/(c*sin(a + b*x))**(S(3)/2), x), x, -(d*cos(a + b*x))**(n + S(1))*(sin(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(a + b*x)**S(2))/(b*c*d*sqrt(c*sin(a + b*x))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*sin(e + f*x)**S(7), x), x, S(2)*b**S(7)/(S(13)*f*(b*sec(e + f*x))**(S(13)/2)) - S(2)*b**S(5)/(S(3)*f*(b*sec(e + f*x))**(S(9)/2)) + S(6)*b**S(3)/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)) - S(2)*b/(f*sqrt(b*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*sin(e + f*x)**S(5), x), x, -S(2)*b**S(5)/(S(9)*f*(b*sec(e + f*x))**(S(9)/2)) + S(4)*b**S(3)/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)) - S(2)*b/(f*sqrt(b*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*sin(e + f*x)**S(3), x), x, S(2)*b**S(3)/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)) - S(2)*b/(f*sqrt(b*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*sin(e + f*x), x), x, -S(2)*b/(f*sqrt(b*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*csc(e + f*x), x), x, sqrt(b)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/f - sqrt(b)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*csc(e + f*x)**S(3), x), x, S(3)*sqrt(b)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*f) - S(3)*sqrt(b)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*f) - (b*sec(e + f*x))**(S(3)/2)*cot(e + f*x)**S(2)/(S(2)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*csc(e + f*x)**S(5), x), x, S(21)*sqrt(b)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*f) - S(21)*sqrt(b)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*f) - S(7)*(b*sec(e + f*x))**(S(3)/2)*cot(e + f*x)**S(2)/(S(16)*b*f) - (b*sec(e + f*x))**(S(7)/2)*cot(e + f*x)**S(4)/(S(4)*b**S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*sin(e + f*x)**S(6), x), x, -S(2)*b*sin(e + f*x)**S(5)/(S(11)*f*sqrt(b*sec(e + f*x))) - S(20)*b*sin(e + f*x)**S(3)/(S(77)*f*sqrt(b*sec(e + f*x))) - S(40)*b*sin(e + f*x)/(S(77)*f*sqrt(b*sec(e + f*x))) + S(80)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(77)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*sin(e + f*x)**S(4), x), x, -S(2)*b*sin(e + f*x)**S(3)/(S(7)*f*sqrt(b*sec(e + f*x))) - S(4)*b*sin(e + f*x)/(S(7)*f*sqrt(b*sec(e + f*x))) + S(8)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(7)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*sin(e + f*x)**S(2), x), x, -S(2)*b*sin(e + f*x)/(S(3)*f*sqrt(b*sec(e + f*x))) + S(4)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x)), x), x, S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*csc(e + f*x)**S(2), x), x, -b*csc(e + f*x)/(f*sqrt(b*sec(e + f*x))) + sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*csc(e + f*x)**S(4), x), x, -b*csc(e + f*x)**S(3)/(S(3)*f*sqrt(b*sec(e + f*x))) - S(5)*b*csc(e + f*x)/(S(6)*f*sqrt(b*sec(e + f*x))) + S(5)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(6)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*csc(e + f*x)**S(6), x), x, -b*csc(e + f*x)**S(5)/(S(5)*f*sqrt(b*sec(e + f*x))) - S(3)*b*csc(e + f*x)**S(3)/(S(10)*f*sqrt(b*sec(e + f*x))) - S(3)*b*csc(e + f*x)/(S(4)*f*sqrt(b*sec(e + f*x))) + S(3)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(7), x), x, S(2)*b**S(7)/(S(11)*f*(b*sec(e + f*x))**(S(11)/2)) - S(6)*b**S(5)/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)) + S(2)*b**S(3)/(f*(b*sec(e + f*x))**(S(3)/2)) + S(2)*b*sqrt(b*sec(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(5), x), x, -S(2)*b**S(5)/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)) + S(4)*b**S(3)/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)) + S(2)*b*sqrt(b*sec(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(3), x), x, S(2)*b**S(3)/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)) + S(2)*b*sqrt(b*sec(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*sin(e + f*x), x), x, S(2)*b*sqrt(b*sec(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*csc(e + f*x), x), x, -b**(S(3)/2)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/f - b**(S(3)/2)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/f + S(2)*b*sqrt(b*sec(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*csc(e + f*x)**S(3), x), x, -S(5)*b**(S(3)/2)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*f) - S(5)*b**(S(3)/2)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*f) + S(5)*b*sqrt(b*sec(e + f*x))/(S(2)*f) - (b*sec(e + f*x))**(S(5)/2)*cot(e + f*x)**S(2)/(S(2)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(6), x), x, S(20)*b**S(3)*sin(e + f*x)**S(3)/(S(9)*f*(b*sec(e + f*x))**(S(3)/2)) + S(8)*b**S(3)*sin(e + f*x)/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)) - S(16)*b**S(2)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(3)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))) + S(2)*b*sqrt(b*sec(e + f*x))*sin(e + f*x)**S(5)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(4), x), x, S(12)*b**S(3)*sin(e + f*x)/(S(5)*f*(b*sec(e + f*x))**(S(3)/2)) - S(24)*b**S(2)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(5)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))) + S(2)*b*sqrt(b*sec(e + f*x))*sin(e + f*x)**S(3)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(2), x), x, -S(4)*b**S(2)*EllipticE(e/S(2) + f*x/S(2), S(2))/(f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))) + S(2)*b*sqrt(b*sec(e + f*x))*sin(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2), x), x, -S(2)*b**S(2)*EllipticE(e/S(2) + f*x/S(2), S(2))/(f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))) + S(2)*b*sqrt(b*sec(e + f*x))*sin(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*csc(e + f*x)**S(2), x), x, -S(3)*b**S(2)*EllipticE(e/S(2) + f*x/S(2), S(2))/(f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))) + S(3)*b*sqrt(b*sec(e + f*x))*sin(e + f*x)/f - b*sqrt(b*sec(e + f*x))*csc(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*csc(e + f*x)**S(4), x), x, -S(7)*b**S(2)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))) + S(7)*b*sqrt(b*sec(e + f*x))*sin(e + f*x)/(S(2)*f) - b*sqrt(b*sec(e + f*x))*csc(e + f*x)**S(3)/(S(3)*f) - S(7)*b*sqrt(b*sec(e + f*x))*csc(e + f*x)/(S(6)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*sin(e + f*x)**S(7), x), x, S(2)*b**S(7)/(S(9)*f*(b*sec(e + f*x))**(S(9)/2)) - S(6)*b**S(5)/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)) + S(6)*b**S(3)/(f*sqrt(b*sec(e + f*x))) + S(2)*b*(b*sec(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*sin(e + f*x)**S(5), x), x, -S(2)*b**S(5)/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)) + S(4)*b**S(3)/(f*sqrt(b*sec(e + f*x))) + S(2)*b*(b*sec(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*sin(e + f*x)**S(3), x), x, S(2)*b**S(3)/(f*sqrt(b*sec(e + f*x))) + S(2)*b*(b*sec(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*sin(e + f*x), x), x, S(2)*b*(b*sec(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*csc(e + f*x), x), x, b**(S(5)/2)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/f - b**(S(5)/2)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/f + S(2)*b*(b*sec(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*csc(e + f*x)**S(3), x), x, S(7)*b**(S(5)/2)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*f) - S(7)*b**(S(5)/2)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*f) + S(7)*b*(b*sec(e + f*x))**(S(3)/2)/(S(6)*f) - (b*sec(e + f*x))**(S(7)/2)*cot(e + f*x)**S(2)/(S(2)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*csc(e + f*x)**S(5), x), x, S(77)*b**(S(5)/2)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*f) - S(77)*b**(S(5)/2)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*f) + S(77)*b*(b*sec(e + f*x))**(S(3)/2)/(S(48)*f) - S(11)*(b*sec(e + f*x))**(S(7)/2)*cot(e + f*x)**S(2)/(S(16)*b*f) - (b*sec(e + f*x))**(S(11)/2)*cot(e + f*x)**S(4)/(S(4)*b**S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*sin(e + f*x)**S(6), x), x, S(20)*b**S(3)*sin(e + f*x)**S(3)/(S(21)*f*sqrt(b*sec(e + f*x))) + S(40)*b**S(3)*sin(e + f*x)/(S(21)*f*sqrt(b*sec(e + f*x))) - S(80)*b**S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(21)*f) + S(2)*b*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(5)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*sin(e + f*x)**S(4), x), x, S(4)*b**S(3)*sin(e + f*x)/(S(3)*f*sqrt(b*sec(e + f*x))) - S(8)*b**S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(3)*f) + S(2)*b*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**S(3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*sin(e + f*x)**S(2), x), x, -S(4)*b**S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(3)*f) + S(2)*b*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2), x), x, S(2)*b**S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(3)*f) + S(2)*b*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*csc(e + f*x)**S(2), x), x, S(5)*b**S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(3)*f) + S(5)*b*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)/(S(3)*f) - b*(b*sec(e + f*x))**(S(3)/2)*csc(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(5)/2)*csc(e + f*x)**S(4), x), x, S(5)*b**S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(2)*f) + S(5)*b*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)/(S(2)*f) - b*(b*sec(e + f*x))**(S(3)/2)*csc(e + f*x)**S(3)/(S(3)*f) - S(3)*b*(b*sec(e + f*x))**(S(3)/2)*csc(e + f*x)/(S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(7)/sqrt(b*sec(e + f*x)), x), x, S(2)*b**S(7)/(S(15)*f*(b*sec(e + f*x))**(S(15)/2)) - S(6)*b**S(5)/(S(11)*f*(b*sec(e + f*x))**(S(11)/2)) + S(6)*b**S(3)/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)) - S(2)*b/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(5)/sqrt(b*sec(e + f*x)), x), x, -S(2)*b**S(5)/(S(11)*f*(b*sec(e + f*x))**(S(11)/2)) + S(4)*b**S(3)/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)) - S(2)*b/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(3)/sqrt(b*sec(e + f*x)), x), x, S(2)*b**S(3)/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)) - S(2)*b/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)/sqrt(b*sec(e + f*x)), x), x, -S(2)*b/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)/sqrt(b*sec(e + f*x)), x), x, -ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(sqrt(b)*f) - atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(sqrt(b)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(3)/sqrt(b*sec(e + f*x)), x), x, -sqrt(b*sec(e + f*x))*cot(e + f*x)**S(2)/(S(2)*b*f) - ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*sqrt(b)*f) - atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*sqrt(b)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(5)/sqrt(b*sec(e + f*x)), x), x, -S(5)*sqrt(b*sec(e + f*x))*cot(e + f*x)**S(2)/(S(16)*b*f) - (b*sec(e + f*x))**(S(5)/2)*cot(e + f*x)**S(4)/(S(4)*b**S(3)*f) - S(5)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*sqrt(b)*f) - S(5)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*sqrt(b)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(6)/sqrt(b*sec(e + f*x)), x), x, -S(2)*b*sin(e + f*x)**S(5)/(S(13)*f*(b*sec(e + f*x))**(S(3)/2)) - S(20)*b*sin(e + f*x)**S(3)/(S(117)*f*(b*sec(e + f*x))**(S(3)/2)) - S(8)*b*sin(e + f*x)/(S(39)*f*(b*sec(e + f*x))**(S(3)/2)) + S(16)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(39)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(4)/sqrt(b*sec(e + f*x)), x), x, -S(2)*b*sin(e + f*x)**S(3)/(S(9)*f*(b*sec(e + f*x))**(S(3)/2)) - S(4)*b*sin(e + f*x)/(S(15)*f*(b*sec(e + f*x))**(S(3)/2)) + S(8)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(15)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(2)/sqrt(b*sec(e + f*x)), x), x, -S(2)*b*sin(e + f*x)/(S(5)*f*(b*sec(e + f*x))**(S(3)/2)) + S(4)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(5)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*sec(e + f*x)), x), x, S(2)*EllipticE(e/S(2) + f*x/S(2), S(2))/(f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(2)/sqrt(b*sec(e + f*x)), x), x, -b*csc(e + f*x)/(f*(b*sec(e + f*x))**(S(3)/2)) - EllipticE(e/S(2) + f*x/S(2), S(2))/(f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(4)/sqrt(b*sec(e + f*x)), x), x, -b*csc(e + f*x)**S(3)/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)) - b*csc(e + f*x)/(S(2)*f*(b*sec(e + f*x))**(S(3)/2)) - EllipticE(e/S(2) + f*x/S(2), S(2))/(S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(6)/sqrt(b*sec(e + f*x)), x), x, -b*csc(e + f*x)**S(5)/(S(5)*f*(b*sec(e + f*x))**(S(3)/2)) - S(7)*b*csc(e + f*x)**S(3)/(S(30)*f*(b*sec(e + f*x))**(S(3)/2)) - S(7)*b*csc(e + f*x)/(S(20)*f*(b*sec(e + f*x))**(S(3)/2)) - S(7)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(20)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(7)/(b*sec(e + f*x))**(S(3)/2), x), x, S(2)*b**S(7)/(S(17)*f*(b*sec(e + f*x))**(S(17)/2)) - S(6)*b**S(5)/(S(13)*f*(b*sec(e + f*x))**(S(13)/2)) + S(2)*b**S(3)/(S(3)*f*(b*sec(e + f*x))**(S(9)/2)) - S(2)*b/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(5)/(b*sec(e + f*x))**(S(3)/2), x), x, -S(2)*b**S(5)/(S(13)*f*(b*sec(e + f*x))**(S(13)/2)) + S(4)*b**S(3)/(S(9)*f*(b*sec(e + f*x))**(S(9)/2)) - S(2)*b/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(3)/(b*sec(e + f*x))**(S(3)/2), x), x, S(2)*b**S(3)/(S(9)*f*(b*sec(e + f*x))**(S(9)/2)) - S(2)*b/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)/(b*sec(e + f*x))**(S(3)/2), x), x, -S(2)*b/(S(5)*f*(b*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)/(b*sec(e + f*x))**(S(3)/2), x), x, S(2)/(b*f*sqrt(b*sec(e + f*x))) + ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(b**(S(3)/2)*f) - atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(b**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(3)/(b*sec(e + f*x))**(S(3)/2), x), x, -(b*sec(e + f*x))**(S(3)/2)*cot(e + f*x)**S(2)/(S(2)*b**S(3)*f) - ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*b**(S(3)/2)*f) + atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*b**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(5)/(b*sec(e + f*x))**(S(3)/2), x), x, -(b*sec(e + f*x))**(S(3)/2)*cot(e + f*x)**S(4)/(S(4)*b**S(3)*f) - S(3)*(b*sec(e + f*x))**(S(3)/2)*cot(e + f*x)**S(2)/(S(16)*b**S(3)*f) - S(3)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*b**(S(3)/2)*f) + S(3)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*b**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(4)/(b*sec(e + f*x))**(S(3)/2), x), x, -S(2)*b*sin(e + f*x)**S(3)/(S(11)*f*(b*sec(e + f*x))**(S(5)/2)) - S(12)*b*sin(e + f*x)/(S(77)*f*(b*sec(e + f*x))**(S(5)/2)) + S(8)*sin(e + f*x)/(S(77)*b*f*sqrt(b*sec(e + f*x))) + S(8)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(77)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(2)/(b*sec(e + f*x))**(S(3)/2), x), x, -S(2)*b*sin(e + f*x)/(S(7)*f*(b*sec(e + f*x))**(S(5)/2)) + S(4)*sin(e + f*x)/(S(21)*b*f*sqrt(b*sec(e + f*x))) + S(4)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(21)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(-3)/2), x), x, S(2)*sin(e + f*x)/(S(3)*b*f*sqrt(b*sec(e + f*x))) + S(2)*sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(3)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(2)/(b*sec(e + f*x))**(S(3)/2), x), x, -csc(e + f*x)/(b*f*sqrt(b*sec(e + f*x))) - sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(4)/(b*sec(e + f*x))**(S(3)/2), x), x, -csc(e + f*x)**S(3)/(S(3)*b*f*sqrt(b*sec(e + f*x))) + csc(e + f*x)/(S(6)*b*f*sqrt(b*sec(e + f*x))) - sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(6)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(6)/(b*sec(e + f*x))**(S(3)/2), x), x, -csc(e + f*x)**S(5)/(S(5)*b*f*sqrt(b*sec(e + f*x))) + csc(e + f*x)**S(3)/(S(30)*b*f*sqrt(b*sec(e + f*x))) + csc(e + f*x)/(S(12)*b*f*sqrt(b*sec(e + f*x))) - sqrt(b*sec(e + f*x))*EllipticF(e/S(2) + f*x/S(2), S(2))*sqrt(cos(e + f*x))/(S(12)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(7)/(b*sec(e + f*x))**(S(5)/2), x), x, S(2)*b**S(7)/(S(19)*f*(b*sec(e + f*x))**(S(19)/2)) - S(2)*b**S(5)/(S(5)*f*(b*sec(e + f*x))**(S(15)/2)) + S(6)*b**S(3)/(S(11)*f*(b*sec(e + f*x))**(S(11)/2)) - S(2)*b/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(5)/(b*sec(e + f*x))**(S(5)/2), x), x, -S(2)*b**S(5)/(S(15)*f*(b*sec(e + f*x))**(S(15)/2)) + S(4)*b**S(3)/(S(11)*f*(b*sec(e + f*x))**(S(11)/2)) - S(2)*b/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(3)/(b*sec(e + f*x))**(S(5)/2), x), x, S(2)*b**S(3)/(S(11)*f*(b*sec(e + f*x))**(S(11)/2)) - S(2)*b/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)/(b*sec(e + f*x))**(S(5)/2), x), x, -S(2)*b/(S(7)*f*(b*sec(e + f*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)/(b*sec(e + f*x))**(S(5)/2), x), x, S(2)/(S(3)*b*f*(b*sec(e + f*x))**(S(3)/2)) - ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(b**(S(5)/2)*f) - atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(b**(S(5)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(3)/(b*sec(e + f*x))**(S(5)/2), x), x, -sqrt(b*sec(e + f*x))*cot(e + f*x)**S(2)/(S(2)*b**S(3)*f) + S(3)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*b**(S(5)/2)*f) + S(3)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(4)*b**(S(5)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(5)/(b*sec(e + f*x))**(S(5)/2), x), x, -sqrt(b*sec(e + f*x))*cot(e + f*x)**S(4)/(S(4)*b**S(3)*f) - sqrt(b*sec(e + f*x))*cot(e + f*x)**S(2)/(S(16)*b**S(3)*f) + S(3)*ArcTan(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*b**(S(5)/2)*f) + S(3)*atanh(sqrt(b*sec(e + f*x))/sqrt(b))/(S(32)*b**(S(5)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(4)/(b*sec(e + f*x))**(S(5)/2), x), x, -S(2)*b*sin(e + f*x)**S(3)/(S(13)*f*(b*sec(e + f*x))**(S(7)/2)) - S(4)*b*sin(e + f*x)/(S(39)*f*(b*sec(e + f*x))**(S(7)/2)) + S(8)*sin(e + f*x)/(S(195)*b*f*(b*sec(e + f*x))**(S(3)/2)) + S(8)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(65)*b**S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(2)/(b*sec(e + f*x))**(S(5)/2), x), x, -S(2)*b*sin(e + f*x)/(S(9)*f*(b*sec(e + f*x))**(S(7)/2)) + S(4)*sin(e + f*x)/(S(45)*b*f*(b*sec(e + f*x))**(S(3)/2)) + S(4)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(15)*b**S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(-5)/2), x), x, S(2)*sin(e + f*x)/(S(5)*b*f*(b*sec(e + f*x))**(S(3)/2)) + S(6)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(5)*b**S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(2)/(b*sec(e + f*x))**(S(5)/2), x), x, -csc(e + f*x)/(b*f*(b*sec(e + f*x))**(S(3)/2)) - S(3)*EllipticE(e/S(2) + f*x/S(2), S(2))/(b**S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(4)/(b*sec(e + f*x))**(S(5)/2), x), x, -csc(e + f*x)**S(3)/(S(3)*b*f*(b*sec(e + f*x))**(S(3)/2)) + csc(e + f*x)/(S(2)*b*f*(b*sec(e + f*x))**(S(3)/2)) + EllipticE(e/S(2) + f*x/S(2), S(2))/(S(2)*b**S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(6)/(b*sec(e + f*x))**(S(5)/2), x), x, -csc(e + f*x)**S(5)/(S(5)*b*f*(b*sec(e + f*x))**(S(3)/2)) + csc(e + f*x)**S(3)/(S(10)*b*f*(b*sec(e + f*x))**(S(3)/2)) + S(3)*csc(e + f*x)/(S(20)*b*f*(b*sec(e + f*x))**(S(3)/2)) + S(3)*EllipticE(e/S(2) + f*x/S(2), S(2))/(S(20)*b**S(2)*f*sqrt(b*sec(e + f*x))*sqrt(cos(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**(S(9)/2)/sqrt(b*sec(e + f*x)), x), x, -b*sin(e + f*x)**(S(7)/2)/(S(5)*f*(b*sec(e + f*x))**(S(3)/2)) - S(7)*b*sin(e + f*x)**(S(3)/2)/(S(30)*f*(b*sec(e + f*x))**(S(3)/2)) + S(7)*sqrt(b*sec(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(e + f*x))*cos(e + f*x)/(S(20)*b*f*sqrt(sin(S(2)*e + S(2)*f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**(S(5)/2)/sqrt(b*sec(e + f*x)), x), x, -b*sin(e + f*x)**(S(3)/2)/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)) + sqrt(b*sec(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(e + f*x))*cos(e + f*x)/(S(2)*b*f*sqrt(sin(S(2)*e + S(2)*f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(sin(e + f*x))/sqrt(b*sec(e + f*x)), x), x, sqrt(b*sec(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(e + f*x))*cos(e + f*x)/(b*f*sqrt(sin(S(2)*e + S(2)*f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(e + f*x))*sin(e + f*x)**(S(3)/2)), x), x, -S(2)*b/(f*(b*sec(e + f*x))**(S(3)/2)*sqrt(sin(e + f*x))) - S(2)*sqrt(b*sec(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(e + f*x))*cos(e + f*x)/(b*f*sqrt(sin(S(2)*e + S(2)*f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(e + f*x))*sin(e + f*x)**(S(7)/2)), x), x, -S(4)*b/(S(5)*f*(b*sec(e + f*x))**(S(3)/2)*sqrt(sin(e + f*x))) - S(2)*b/(S(5)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(5)/2)) - S(4)*sqrt(b*sec(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(e + f*x))*cos(e + f*x)/(S(5)*b*f*sqrt(sin(S(2)*e + S(2)*f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**(S(3)/2)/sqrt(b*sec(e + f*x)), x), x, -b*sqrt(sin(e + f*x))/(S(2)*f*(b*sec(e + f*x))**(S(3)/2)) + sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*ArcTan(-sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + S(1))/(S(8)*sqrt(b)*f) - sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*ArcTan(sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + S(1))/(S(8)*sqrt(b)*f) - sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*log(-sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + cot(e + f*x) + S(1))/(S(16)*sqrt(b)*f) + sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*log(sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + cot(e + f*x) + S(1))/(S(16)*sqrt(b)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(e + f*x))*sqrt(sin(e + f*x))), x), x, sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*ArcTan(-sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + S(1))/(S(2)*sqrt(b)*f) - sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*ArcTan(sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + S(1))/(S(2)*sqrt(b)*f) - sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*log(-sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + cot(e + f*x) + S(1))/(S(4)*sqrt(b)*f) + sqrt(S(2))*sqrt(cos(e + f*x)/b)*sqrt(b*sec(e + f*x))*log(sqrt(S(2))*sqrt(b)*sqrt(cos(e + f*x)/b)/sqrt(sin(e + f*x)) + cot(e + f*x) + S(1))/(S(4)*sqrt(b)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(e + f*x))*sin(e + f*x)**(S(5)/2)), x), x, -S(2)*b/(S(3)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(e + f*x))*sin(e + f*x)**(S(9)/2)), x), x, -S(8)*b/(S(21)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(3)/2)) - S(2)*b/(S(7)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(e + f*x))*sin(e + f*x)**(S(13)/2)), x), x, -S(64)*b/(S(231)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(3)/2)) - S(16)*b/(S(77)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(7)/2)) - S(2)*b/(S(11)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*sec(e + f*x))*sin(e + f*x)**(S(17)/2)), x), x, -S(256)*b/(S(1155)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(3)/2)) - S(64)*b/(S(385)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(7)/2)) - S(8)*b/(S(55)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(11)/2)) - S(2)*b/(S(15)*f*(b*sec(e + f*x))**(S(3)/2)*sin(e + f*x)**(S(15)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*(d*sec(a + b*x))**(S(5)/2), x), x, d**S(2)*(c*sin(a + b*x))**(m + S(1))*sqrt(d*sec(a + b*x))*(cos(a + b*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(7)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*sec(a + b*x)/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*(d*sec(a + b*x))**(S(3)/2), x), x, d*(c*sin(a + b*x))**(m + S(1))*sqrt(d*sec(a + b*x))*(cos(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m*sqrt(d*sec(a + b*x)), x), x, (c*sin(a + b*x))**(m + S(1))*sqrt(d*sec(a + b*x))*(cos(a + b*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*sec(a + b*x)/(b*c*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m/sqrt(d*sec(a + b*x)), x), x, (c*sin(a + b*x))**(m + S(1))*sqrt(d*sec(a + b*x))*(cos(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(1)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))/(b*c*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c*sin(a + b*x))**m/(d*sec(a + b*x))**(S(3)/2), x), x, (c*sin(a + b*x))**(m + S(1))*sqrt(d*sec(a + b*x))*Hypergeometric2F1(S(-1)/4, m/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(a + b*x)**S(2))*cos(a + b*x)/(b*c*d**S(2)*(m + S(1))*(cos(a + b*x)**S(2))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**m*sec(e + f*x)**n, x), x, (cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, n/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(e + f*x)**S(2))*sin(e + f*x)**(m + S(1))*sec(e + f*x)**(n + S(1))/(f*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(e + f*x))**m*sec(e + f*x)**n, x), x, (a*sin(e + f*x))**(m + S(1))*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, n/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(e + f*x)**S(2))*sec(e + f*x)**(n + S(1))/(a*f*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x)**m, x), x, -b*(b*sec(e + f*x))**(n + S(-1))*(sin(e + f*x)**S(2))**(-m/S(2) + S(1)/2)*Hypergeometric2F1(-m/S(2) + S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*sin(e + f*x)**(m + S(-1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x)**m, x), x, -(b*sec(e + f*x))**n*(sin(e + f*x)**S(2))**(-m/S(2) + S(1)/2)*Hypergeometric2F1(-m/S(2) + S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*sin(e + f*x)**(m + S(-1))*cos(e + f*x)/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(e + f*x))**m*(b*sec(e + f*x))**n, x), x, (a*sin(e + f*x))**(m + S(1))*(b*sec(e + f*x))**(n + S(1))*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, n/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(e + f*x)**S(2))/(a*b*f*(m + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a*sin(e + f*x))**m*(b*sec(e + f*x))**n, x), x, (a*sin(e + f*x))**(m + S(1))*(b*sec(e + f*x))**n*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(m/S(2) + S(1)/2, n/S(2) + S(1)/2, m/S(2) + S(3)/2, sin(e + f*x)**S(2))*sec(e + f*x)/(a*f*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x)**S(5), x), x, -b**S(5)*(b*sec(e + f*x))**(n + S(-5))/(f*(-n + S(5))) + S(2)*b**S(3)*(b*sec(e + f*x))**(n + S(-3))/(f*(-n + S(3))) - b*(b*sec(e + f*x))**(n + S(-1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x)**S(3), x), x, b**S(3)*(b*sec(e + f*x))**(n + S(-3))/(f*(-n + S(3))) - b*(b*sec(e + f*x))**(n + S(-1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x), x), x, -b*(b*sec(e + f*x))**(n + S(-1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*csc(e + f*x), x), x, -(b*sec(e + f*x))**(n + S(1))*Hypergeometric2F1(S(1), n/S(2) + S(1)/2, n/S(2) + S(3)/2, sec(e + f*x)**S(2))/(b*f*(n + S(1))), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*csc(e + f*x)**S(3), x), x, (b*sec(e + f*x))**(n + S(3))*Hypergeometric2F1(S(2), n/S(2) + S(3)/2, n/S(2) + S(5)/2, sec(e + f*x)**S(2))/(b**S(3)*f*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x)**S(6), x), x, -(b*sec(e + f*x))**n*Hypergeometric2F1(S(-5)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*sin(e + f*x)*cos(e + f*x)/(f*(-n + S(1))*sqrt(sin(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x)**S(4), x), x, -(b*sec(e + f*x))**n*Hypergeometric2F1(S(-3)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*sin(e + f*x)*cos(e + f*x)/(f*(-n + S(1))*sqrt(sin(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*sin(e + f*x)**S(2), x), x, -(b*sec(e + f*x))**n*Hypergeometric2F1(S(-1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*sin(e + f*x)*cos(e + f*x)/(f*(-n + S(1))*sqrt(sin(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n, x), x, -b*(b*sec(e + f*x))**(n + S(-1))*Hypergeometric2F1(S(1)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*sin(e + f*x)/(f*(-n + S(1))*sqrt(sin(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*csc(e + f*x)**S(2), x), x, -(b*sec(e + f*x))**n*sqrt(sin(e + f*x)**S(2))*Hypergeometric2F1(S(3)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*cot(e + f*x)/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**n*csc(e + f*x)**S(4), x), x, -(b*sec(e + f*x))**n*sqrt(sin(e + f*x)**S(2))*Hypergeometric2F1(S(5)/2, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(e + f*x)**S(2))*cot(e + f*x)/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(a + b*x))**n*(c*sin(a + b*x))**(S(3)/2), x), x, -c*(b*sec(a + b*x))**n*sqrt(c*sin(a + b*x))*Hypergeometric2F1(S(-1)/4, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(a + b*x)**S(2))*cos(a + b*x)/(b*(-n + S(1))*(sin(a + b*x)**S(2))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(a + b*x))**n*sqrt(c*sin(a + b*x)), x), x, -c*(b*sec(a + b*x))**n*(sin(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(1)/4, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(a + b*x)**S(2))*cos(a + b*x)/(b*sqrt(c*sin(a + b*x))*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(a + b*x))**n/sqrt(c*sin(a + b*x)), x), x, -c*(b*sec(a + b*x))**n*(sin(a + b*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(a + b*x)**S(2))*cos(a + b*x)/(b*(c*sin(a + b*x))**(S(3)/2)*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(a + b*x))**n/(c*sin(a + b*x))**(S(3)/2), x), x, -(b*sec(a + b*x))**n*(sin(a + b*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, -n/S(2) + S(1)/2, -n/S(2) + S(3)/2, cos(a + b*x)**S(2))*cos(a + b*x)/(b*c*sqrt(c*sin(a + b*x))*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x))*sin(e + f*x)**S(4), x), x, -S(2)*d**S(3)*cos(e + f*x)/(S(7)*f*(d*csc(e + f*x))**(S(5)/2)) - S(10)*d*cos(e + f*x)/(S(21)*f*sqrt(d*csc(e + f*x))) + S(10)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(21)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x))*sin(e + f*x)**S(3), x), x, -S(2)*d**S(2)*cos(e + f*x)/(S(5)*f*(d*csc(e + f*x))**(S(3)/2)) + S(6)*d*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x))*sin(e + f*x)**S(2), x), x, -S(2)*d*cos(e + f*x)/(S(3)*f*sqrt(d*csc(e + f*x))) + S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x))*sin(e + f*x), x), x, S(2)*d*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x)), x), x, S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x))*csc(e + f*x), x), x, -S(2)*d*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))) - S(2)*sqrt(d*csc(e + f*x))*cos(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x))*csc(e + f*x)**S(2), x), x, S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*f) - S(2)*(d*csc(e + f*x))**(S(3)/2)*cos(e + f*x)/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*csc(e + f*x))*csc(e + f*x)**S(3), x), x, -S(6)*d*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))) - S(6)*sqrt(d*csc(e + f*x))*cos(e + f*x)/(S(5)*f) - S(2)*(d*csc(e + f*x))**(S(5)/2)*cos(e + f*x)/(S(5)*d**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2)*sin(e + f*x)**S(5), x), x, -S(2)*d**S(4)*cos(e + f*x)/(S(7)*f*(d*csc(e + f*x))**(S(5)/2)) - S(10)*d**S(2)*cos(e + f*x)/(S(21)*f*sqrt(d*csc(e + f*x))) + S(10)*d*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(21)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2)*sin(e + f*x)**S(4), x), x, -S(2)*d**S(3)*cos(e + f*x)/(S(5)*f*(d*csc(e + f*x))**(S(3)/2)) + S(6)*d**S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2)*sin(e + f*x)**S(3), x), x, -S(2)*d**S(2)*cos(e + f*x)/(S(3)*f*sqrt(d*csc(e + f*x))) + S(2)*d*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2)*sin(e + f*x)**S(2), x), x, S(2)*d**S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2)*sin(e + f*x), x), x, S(2)*d*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2), x), x, -S(2)*d**S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))) - S(2)*d*sqrt(d*csc(e + f*x))*cos(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2)*csc(e + f*x), x), x, S(2)*d*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*f) - S(2)*(d*csc(e + f*x))**(S(3)/2)*cos(e + f*x)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(3)/2)*csc(e + f*x)**S(2), x), x, -S(6)*d**S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))) - S(6)*d*sqrt(d*csc(e + f*x))*cos(e + f*x)/(S(5)*f) - S(2)*(d*csc(e + f*x))**(S(5)/2)*cos(e + f*x)/(S(5)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(3)/sqrt(d*csc(e + f*x)), x), x, -S(2)*d**S(2)*cos(e + f*x)/(S(7)*f*(d*csc(e + f*x))**(S(5)/2)) - S(10)*cos(e + f*x)/(S(21)*f*sqrt(d*csc(e + f*x))) + S(10)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(21)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(2)/sqrt(d*csc(e + f*x)), x), x, -S(2)*d*cos(e + f*x)/(S(5)*f*(d*csc(e + f*x))**(S(3)/2)) + S(6)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)/sqrt(d*csc(e + f*x)), x), x, -S(2)*cos(e + f*x)/(S(3)*f*sqrt(d*csc(e + f*x))) + S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(d*csc(e + f*x)), x), x, S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)/sqrt(d*csc(e + f*x)), x), x, S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(2)/sqrt(d*csc(e + f*x)), x), x, -S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))) - S(2)*sqrt(d*csc(e + f*x))*cos(e + f*x)/(d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(3)/sqrt(d*csc(e + f*x)), x), x, S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*d*f) - S(2)*(d*csc(e + f*x))**(S(3)/2)*cos(e + f*x)/(S(3)*d**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)**S(2)/(d*csc(e + f*x))**(S(3)/2), x), x, -S(2)*d*cos(e + f*x)/(S(7)*f*(d*csc(e + f*x))**(S(5)/2)) - S(10)*cos(e + f*x)/(S(21)*d*f*sqrt(d*csc(e + f*x))) + S(10)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(21)*d**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(e + f*x)/(d*csc(e + f*x))**(S(3)/2), x), x, -S(2)*cos(e + f*x)/(S(5)*f*(d*csc(e + f*x))**(S(3)/2)) + S(6)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*d*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*csc(e + f*x))**(S(-3)/2), x), x, -S(2)*cos(e + f*x)/(S(3)*d*f*sqrt(d*csc(e + f*x))) + S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*d**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)/(d*csc(e + f*x))**(S(3)/2), x), x, S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(d*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(2)/(d*csc(e + f*x))**(S(3)/2), x), x, S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(d**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(3)/(d*csc(e + f*x))**(S(3)/2), x), x, -S(2)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(d*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))) - S(2)*sqrt(d*csc(e + f*x))*cos(e + f*x)/(d**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(4)/(d*csc(e + f*x))**(S(3)/2), x), x, S(2)*sqrt(d*csc(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*d**S(2)*f) - S(2)*(d*csc(e + f*x))**(S(3)/2)*cos(e + f*x)/(S(3)*d**S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(e + f*x)**S(5)/(d*csc(e + f*x))**(S(3)/2), x), x, -S(6)*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*d*f*sqrt(d*csc(e + f*x))*sqrt(sin(e + f*x))) - S(6)*sqrt(d*csc(e + f*x))*cos(e + f*x)/(S(5)*d**S(2)*f) - S(2)*(d*csc(e + f*x))**(S(5)/2)*cos(e + f*x)/(S(5)*d**S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(e + f*x))**m*(b*csc(e + f*x))**n, x), x, (a*sin(e + f*x))**(m + S(1))*(b*csc(e + f*x))**n*Hypergeometric2F1(S(1)/2, m/S(2) - n/S(2) + S(1)/2, m/S(2) - n/S(2) + S(3)/2, sin(e + f*x)**S(2))*cos(e + f*x)/(a*f*(m - n + S(1))*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_special_functions.py000066400000000000000000001363331412543434000305140ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: disabled = True if sys.version_info[:2] < (3, 6): disabled = True if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( sympy_op_factory, Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, exp, log, Discriminant ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi from sympy.integrals.rubi.rubi import rubi_integrate from sympy import Integral as Integrate, exp, log 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 = symbols('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') A, B, C, F, G, H, J, K, L, M, N, O, P, Q, R, T, U, V, W, X, Y, Z = symbols('A B C F G H J K L M N O P Q R T U V W X Y Z') def test_error_functions(): assert rubi_test(rubi_integrate(x**S(5)*Erf(b*x)**S(2), x), x, x**S(6)*Erf(b*x)**S(2)/S(6) - S(5)*Erf(b*x)**S(2)/(S(16)*b**S(6)) + x**S(4)*exp(-S(2)*b**S(2)*x**S(2))/(S(6)*Pi*b**S(2)) + S(7)*x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(12)*Pi*b**S(4)) + S(11)*exp(-S(2)*b**S(2)*x**S(2))/(S(12)*Pi*b**S(6)) + x**S(5)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b) + S(5)*x**S(3)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*b**S(3)) + S(5)*x*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*Erf(b*x)**S(2), x), x, x**S(5)*Erf(b*x)**S(2)/S(5) + x**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(5)*Pi*b**S(2)) + S(11)*x*exp(-S(2)*b**S(2)*x**S(2))/(S(20)*Pi*b**S(4)) + S(2)*x**S(4)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b) + S(4)*x**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b**S(3)) + S(4)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b**S(5)) - S(43)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(80)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erf(b*x)**S(2), x), x, x**S(4)*Erf(b*x)**S(2)/S(4) - S(3)*Erf(b*x)**S(2)/(S(16)*b**S(4)) + x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*Pi*b**S(2)) + exp(-S(2)*b**S(2)*x**S(2))/(S(2)*Pi*b**S(4)) + x**S(3)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*sqrt(Pi)*b) + S(3)*x*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erf(b*x)**S(2), x), x, x**S(3)*Erf(b*x)**S(2)/S(3) + x*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*Pi*b**S(2)) + S(2)*x**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b) + S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b**S(3)) - S(5)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(12)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erf(b*x)**S(2), x), x, x**S(2)*Erf(b*x)**S(2)/S(2) - Erf(b*x)**S(2)/(S(4)*b**S(2)) + exp(-S(2)*b**S(2)*x**S(2))/(S(2)*Pi*b**S(2)) + x*Erf(b*x)*exp(-b**S(2)*x**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2), x), x, x*Erf(b*x)**S(2) - sqrt(S(2))*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*b*x)/b + S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x, x), x, Integrate(Erf(b*x)**S(2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x**S(2), x), x, Integrate(Erf(b*x)**S(2)/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x**S(3), x), x, -b**S(2)*Erf(b*x)**S(2) - Erf(b*x)**S(2)/(S(2)*x**S(2)) + S(2)*b**S(2)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/Pi - S(2)*b*Erf(b*x)*exp(-b**S(2)*x**S(2))/(sqrt(Pi)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x**S(4), x), x, Integrate(Erf(b*x)**S(2)/x**S(4), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x**S(5), x), x, b**S(4)*Erf(b*x)**S(2)/S(3) - Erf(b*x)**S(2)/(S(4)*x**S(4)) - S(4)*b**S(4)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(3)*Pi) - b**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*Pi*x**S(2)) + S(2)*b**S(3)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x) - b*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x**S(6), x), x, Integrate(Erf(b*x)**S(2)/x**S(6), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x**S(7), x), x, -S(4)*b**S(6)*Erf(b*x)**S(2)/S(45) - Erf(b*x)**S(2)/(S(6)*x**S(6)) + S(28)*b**S(6)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(45)*Pi) + S(2)*b**S(4)*exp(-S(2)*b**S(2)*x**S(2))/(S(9)*Pi*x**S(2)) - b**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(15)*Pi*x**S(4)) - S(8)*b**S(5)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(45)*sqrt(Pi)*x) + S(4)*b**S(3)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(45)*sqrt(Pi)*x**S(3)) - S(2)*b*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(15)*sqrt(Pi)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)**S(2)/x**S(8), x), x, Integrate(Erf(b*x)**S(2)/x**S(8), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erf(a + b*x), x), x, -a**S(4)*Erf(a + b*x)/(S(4)*b**S(4)) - S(3)*a**S(2)*Erf(a + b*x)/(S(4)*b**S(4)) + x**S(4)*Erf(a + b*x)/S(4) - S(3)*Erf(a + b*x)/(S(16)*b**S(4)) - a**S(3)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) + S(3)*a**S(2)*(a + b*x)*exp(-(a + b*x)**S(2))/(S(2)*sqrt(Pi)*b**S(4)) - a*(a + b*x)**S(2)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) - a*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) + (a + b*x)**S(3)*exp(-(a + b*x)**S(2))/(S(4)*sqrt(Pi)*b**S(4)) + (S(3)*a + S(3)*b*x)*exp(-(a + b*x)**S(2))/(S(8)*sqrt(Pi)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erf(a + b*x), x), x, a**S(3)*Erf(a + b*x)/(S(3)*b**S(3)) + a*Erf(a + b*x)/(S(2)*b**S(3)) + x**S(3)*Erf(a + b*x)/S(3) + a**S(2)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) - a*(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) + (a + b*x)**S(2)*exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)) + exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erf(a + b*x), x), x, -a**S(2)*Erf(a + b*x)/(S(2)*b**S(2)) + x**S(2)*Erf(a + b*x)/S(2) - Erf(a + b*x)/(S(4)*b**S(2)) - a*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(2)) + (a + b*x)*exp(-(a + b*x)**S(2))/(S(2)*sqrt(Pi)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(a + b*x), x), x, (a + b*x)*Erf(a + b*x)/b + exp(-(a + b*x)**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(a + b*x)/x, x), x, Integrate(Erf(a + b*x)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(a + b*x)/x**S(2), x), x, -Erf(a + b*x)/x + S(2)*b*Integrate(exp(-(a + b*x)**S(2))/x, x)/sqrt(Pi), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erf(a + b*x)**S(2), x), x, a**S(2)*(a + b*x)*Erf(a + b*x)**S(2)/b**S(3) - sqrt(S(2))*a**S(2)*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*(a + b*x))/b**S(3) - a*(a + b*x)**S(2)*Erf(a + b*x)**S(2)/b**S(3) + a*Erf(a + b*x)**S(2)/(S(2)*b**S(3)) + (a + b*x)**S(3)*Erf(a + b*x)**S(2)/(S(3)*b**S(3)) - a*exp(-S(2)*(a + b*x)**S(2))/(Pi*b**S(3)) + (a + b*x)*exp(-S(2)*(a + b*x)**S(2))/(S(3)*Pi*b**S(3)) + S(2)*a**S(2)*Erf(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) - S(2)*a*(a + b*x)*Erf(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) + S(2)*(a + b*x)**S(2)*Erf(a + b*x)*exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)) - S(5)*sqrt(S(2))*Erf(sqrt(S(2))*(a + b*x))/(S(12)*sqrt(Pi)*b**S(3)) + S(2)*Erf(a + b*x)*exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erf(a + b*x)**S(2), x), x, -a*(a + b*x)*Erf(a + b*x)**S(2)/b**S(2) + sqrt(S(2))*a*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*(a + b*x))/b**S(2) + (a + b*x)**S(2)*Erf(a + b*x)**S(2)/(S(2)*b**S(2)) - Erf(a + b*x)**S(2)/(S(4)*b**S(2)) + exp(-S(2)*(a + b*x)**S(2))/(S(2)*Pi*b**S(2)) - S(2)*a*Erf(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(2)) + (a + b*x)*Erf(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(a + b*x)**S(2), x), x, (a + b*x)*Erf(a + b*x)**S(2)/b - sqrt(S(2))*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*(a + b*x))/b + S(2)*Erf(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(a + b*x)**S(2)/x, x), x, Integrate(Erf(a + b*x)**S(2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(a + b*x)**S(2)/x**S(2), x), x, Integrate(Erf(a + b*x)**S(2)/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x, S(15)*sqrt(Pi)*Erf(b*x)**S(2)/(S(32)*b**S(7)) - x**S(5)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - S(5)*x**S(3)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*b**S(4)) - S(15)*x*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(8)*b**S(6)) - x**S(4)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) - S(7)*x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(8)*sqrt(Pi)*b**S(5)) - S(11)*exp(-S(2)*b**S(2)*x**S(2))/(S(8)*sqrt(Pi)*b**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x, -x**S(4)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - x**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/b**S(4) - Erf(b*x)*exp(-b**S(2)*x**S(2))/b**S(6) + S(43)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(64)*b**S(6)) - x**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) - S(11)*x*exp(-S(2)*b**S(2)*x**S(2))/(S(16)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x, S(3)*sqrt(Pi)*Erf(b*x)**S(2)/(S(16)*b**S(5)) - x**S(3)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - S(3)*x*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*b**S(4)) - x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) - exp(-S(2)*b**S(2)*x**S(2))/(S(2)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x, -x**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(4)) + S(5)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(16)*b**S(4)) - x*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x, sqrt(Pi)*Erf(b*x)**S(2)/(S(8)*b**S(3)) - x*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x, -Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) + sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(4)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x, sqrt(Pi)*Erf(b*x)**S(2)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x, x), x, Integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x**S(2), x), x, -sqrt(Pi)*b*Erf(b*x)**S(2)/S(2) - Erf(b*x)*exp(-b**S(2)*x**S(2))/x + b*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/sqrt(Pi), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x**S(3), x), x, -sqrt(S(2))*b**S(2)*Erf(sqrt(S(2))*b*x) - b**S(2)*Integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x, x) - Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*x**S(2)) - b*exp(-S(2)*b**S(2)*x**S(2))/(sqrt(Pi)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x**S(4), x), x, sqrt(Pi)*b**S(3)*Erf(b*x)**S(2)/S(3) + S(2)*b**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*x) - Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*x**S(3)) - S(4)*b**S(3)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)) - b*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x**S(5), x), x, S(7)*sqrt(S(2))*b**S(4)*Erf(sqrt(S(2))*b*x)/S(6) + b**S(4)*Integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x, x)/S(2) + b**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*x**S(2)) - Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*x**S(4)) + S(7)*b**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*x) - b*exp(-S(2)*b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erf(b*x)*exp(-b**S(2)*x**S(2))/x**S(6), x), x, -S(2)*sqrt(Pi)*b**S(5)*Erf(b*x)**S(2)/S(15) - S(4)*b**S(4)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(15)*x) + S(2)*b**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(15)*x**S(3)) - Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*x**S(5)) + S(14)*b**S(5)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(15)*sqrt(Pi)) + b**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(2)) - b*exp(-S(2)*b**S(2)*x**S(2))/(S(10)*sqrt(Pi)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(b**S(2)*Erf(b*x)*exp(-b**S(2)*x**S(2))/x + Erf(b*x)*exp(-b**S(2)*x**S(2))/x**S(3), x), x, -sqrt(S(2))*b**S(2)*Erf(sqrt(S(2))*b*x) - Erf(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*x**S(2)) - b*exp(-S(2)*b**S(2)*x**S(2))/(sqrt(Pi)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x**S(8), x), x, Integrate(Erfc(b*x)**S(2)/x**S(8), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x**S(7), x), x, -S(4)*b**S(6)*Erfc(b*x)**S(2)/S(45) - Erfc(b*x)**S(2)/(S(6)*x**S(6)) + S(28)*b**S(6)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(45)*Pi) + S(2)*b**S(4)*exp(-S(2)*b**S(2)*x**S(2))/(S(9)*Pi*x**S(2)) - b**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(15)*Pi*x**S(4)) + S(8)*b**S(5)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(45)*sqrt(Pi)*x) - S(4)*b**S(3)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(45)*sqrt(Pi)*x**S(3)) + S(2)*b*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(15)*sqrt(Pi)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x**S(6), x), x, Integrate(Erfc(b*x)**S(2)/x**S(6), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x**S(5), x), x, b**S(4)*Erfc(b*x)**S(2)/S(3) - Erfc(b*x)**S(2)/(S(4)*x**S(4)) - S(4)*b**S(4)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(3)*Pi) - b**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*Pi*x**S(2)) - S(2)*b**S(3)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x) + b*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x**S(4), x), x, Integrate(Erfc(b*x)**S(2)/x**S(4), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x**S(3), x), x, -b**S(2)*Erfc(b*x)**S(2) - Erfc(b*x)**S(2)/(S(2)*x**S(2)) + S(2)*b**S(2)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/Pi + S(2)*b*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(sqrt(Pi)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x**S(2), x), x, Integrate(Erfc(b*x)**S(2)/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2)/x, x), x, Integrate(Erfc(b*x)**S(2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)**S(2), x), x, x*Erfc(b*x)**S(2) - sqrt(S(2))*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*b*x)/b - S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfc(b*x)**S(2), x), x, x**S(2)*Erfc(b*x)**S(2)/S(2) - Erfc(b*x)**S(2)/(S(4)*b**S(2)) + exp(-S(2)*b**S(2)*x**S(2))/(S(2)*Pi*b**S(2)) - x*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfc(b*x)**S(2), x), x, x**S(3)*Erfc(b*x)**S(2)/S(3) + x*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*Pi*b**S(2)) - S(2)*x**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b) - S(5)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(12)*sqrt(Pi)*b**S(3)) - S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erfc(b*x)**S(2), x), x, x**S(4)*Erfc(b*x)**S(2)/S(4) - S(3)*Erfc(b*x)**S(2)/(S(16)*b**S(4)) + x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*Pi*b**S(2)) + exp(-S(2)*b**S(2)*x**S(2))/(S(2)*Pi*b**S(4)) - x**S(3)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*sqrt(Pi)*b) - S(3)*x*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*Erfc(b*x)**S(2), x), x, x**S(5)*Erfc(b*x)**S(2)/S(5) + x**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(5)*Pi*b**S(2)) + S(11)*x*exp(-S(2)*b**S(2)*x**S(2))/(S(20)*Pi*b**S(4)) - S(2)*x**S(4)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b) - S(4)*x**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b**S(3)) - S(43)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(80)*sqrt(Pi)*b**S(5)) - S(4)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*Erfc(b*x)**S(2), x), x, x**S(6)*Erfc(b*x)**S(2)/S(6) - S(5)*Erfc(b*x)**S(2)/(S(16)*b**S(6)) + x**S(4)*exp(-S(2)*b**S(2)*x**S(2))/(S(6)*Pi*b**S(2)) + S(7)*x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(12)*Pi*b**S(4)) + S(11)*exp(-S(2)*b**S(2)*x**S(2))/(S(12)*Pi*b**S(6)) - x**S(5)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b) - S(5)*x**S(3)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*b**S(3)) - S(5)*x*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(a + b*x)/x, x), x, Integrate(Erfc(a + b*x)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(a + b*x), x), x, (a + b*x)*Erfc(a + b*x)/b - exp(-(a + b*x)**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfc(a + b*x), x), x, a**S(2)*Erf(a + b*x)/(S(2)*b**S(2)) + x**S(2)*Erfc(a + b*x)/S(2) + Erf(a + b*x)/(S(4)*b**S(2)) + a*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(2)) - (a + b*x)*exp(-(a + b*x)**S(2))/(S(2)*sqrt(Pi)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfc(a + b*x), x), x, -a**S(3)*Erf(a + b*x)/(S(3)*b**S(3)) - a*Erf(a + b*x)/(S(2)*b**S(3)) + x**S(3)*Erfc(a + b*x)/S(3) - a**S(2)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) + a*(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) - (a + b*x)**S(2)*exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)) - exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erfc(a + b*x), x), x, a**S(4)*Erf(a + b*x)/(S(4)*b**S(4)) + S(3)*a**S(2)*Erf(a + b*x)/(S(4)*b**S(4)) + x**S(4)*Erfc(a + b*x)/S(4) + S(3)*Erf(a + b*x)/(S(16)*b**S(4)) + a**S(3)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) - S(3)*a**S(2)*(a + b*x)*exp(-(a + b*x)**S(2))/(S(2)*sqrt(Pi)*b**S(4)) + a*(a + b*x)**S(2)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) + a*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) - (a + b*x)**S(3)*exp(-(a + b*x)**S(2))/(S(4)*sqrt(Pi)*b**S(4)) - (S(3)*a + S(3)*b*x)*exp(-(a + b*x)**S(2))/(S(8)*sqrt(Pi)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(a + b*x)**S(2)/x, x), x, Integrate(Erfc(a + b*x)**S(2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(a + b*x)**S(2), x), x, (a + b*x)*Erfc(a + b*x)**S(2)/b - sqrt(S(2))*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*(a + b*x))/b - S(2)*Erfc(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfc(a + b*x)**S(2), x), x, -a*(a + b*x)*Erfc(a + b*x)**S(2)/b**S(2) + sqrt(S(2))*a*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*(a + b*x))/b**S(2) + (a + b*x)**S(2)*Erfc(a + b*x)**S(2)/(S(2)*b**S(2)) - Erfc(a + b*x)**S(2)/(S(4)*b**S(2)) + exp(-S(2)*(a + b*x)**S(2))/(S(2)*Pi*b**S(2)) + S(2)*a*Erfc(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(2)) - (a + b*x)*Erfc(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfc(a + b*x)**S(2), x), x, a**S(2)*(a + b*x)*Erfc(a + b*x)**S(2)/b**S(3) - sqrt(S(2))*a**S(2)*sqrt(S(1)/Pi)*Erf(sqrt(S(2))*(a + b*x))/b**S(3) - a*(a + b*x)**S(2)*Erfc(a + b*x)**S(2)/b**S(3) + a*Erfc(a + b*x)**S(2)/(S(2)*b**S(3)) + (a + b*x)**S(3)*Erfc(a + b*x)**S(2)/(S(3)*b**S(3)) - a*exp(-S(2)*(a + b*x)**S(2))/(Pi*b**S(3)) + (a + b*x)*exp(-S(2)*(a + b*x)**S(2))/(S(3)*Pi*b**S(3)) - S(2)*a**S(2)*Erfc(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) + S(2)*a*(a + b*x)*Erfc(a + b*x)*exp(-(a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) - S(2)*(a + b*x)**S(2)*Erfc(a + b*x)*exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)) - S(5)*sqrt(S(2))*Erf(sqrt(S(2))*(a + b*x))/(S(12)*sqrt(Pi)*b**S(3)) - S(2)*Erfc(a + b*x)*exp(-(a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x**S(8), x), x, -S(4)*sqrt(Pi)*b**S(7)*Erfc(b*x)**S(2)/S(105) + S(8)*b**S(6)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(105)*x) - S(4)*b**S(4)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(105)*x**S(3)) + S(2)*b**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(35)*x**S(5)) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(7)*x**S(7)) + S(16)*b**S(7)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(35)*sqrt(Pi)) + S(4)*b**S(5)*exp(-S(2)*b**S(2)*x**S(2))/(S(21)*sqrt(Pi)*x**S(2)) - S(8)*b**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(105)*sqrt(Pi)*x**S(4)) + b*exp(-S(2)*b**S(2)*x**S(2))/(S(21)*sqrt(Pi)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x**S(7), x), x, S(67)*sqrt(S(2))*b**S(6)*Erf(sqrt(S(2))*b*x)/S(90) - b**S(6)*Integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x, x)/S(6) - b**S(4)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(12)*x**S(2)) + b**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(12)*x**S(4)) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(6)*x**S(6)) + S(67)*b**S(5)*exp(-S(2)*b**S(2)*x**S(2))/(S(90)*sqrt(Pi)*x) - S(13)*b**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(90)*sqrt(Pi)*x**S(3)) + b*exp(-S(2)*b**S(2)*x**S(2))/(S(15)*sqrt(Pi)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x**S(6), x), x, S(2)*sqrt(Pi)*b**S(5)*Erfc(b*x)**S(2)/S(15) - S(4)*b**S(4)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(15)*x) + S(2)*b**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(15)*x**S(3)) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(5)*x**S(5)) - S(14)*b**S(5)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(15)*sqrt(Pi)) - b**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(2)) + b*exp(-S(2)*b**S(2)*x**S(2))/(S(10)*sqrt(Pi)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x**S(5), x), x, -S(7)*sqrt(S(2))*b**S(4)*Erf(sqrt(S(2))*b*x)/S(6) + b**S(4)*Integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x, x)/S(2) + b**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*x**S(2)) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*x**S(4)) - S(7)*b**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*x) + b*exp(-S(2)*b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x**S(4), x), x, -sqrt(Pi)*b**S(3)*Erfc(b*x)**S(2)/S(3) + S(2)*b**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*x) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(3)*x**S(3)) + S(4)*b**S(3)*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)) + b*exp(-S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x**S(3), x), x, sqrt(S(2))*b**S(2)*Erf(sqrt(S(2))*b*x) - b**S(2)*Integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x, x) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*x**S(2)) + b*exp(-S(2)*b**S(2)*x**S(2))/(sqrt(Pi)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x**S(2), x), x, sqrt(Pi)*b*Erfc(b*x)**S(2)/S(2) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/x - b*ExpIntegralEi(-S(2)*b**S(2)*x**S(2))/sqrt(Pi), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x, x), x, Integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x, -sqrt(Pi)*Erfc(b*x)**S(2)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x, -sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(4)*b**S(2)) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x, -sqrt(Pi)*Erfc(b*x)**S(2)/(S(8)*b**S(3)) - x*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) + exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x, -x**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - S(5)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(16)*b**S(4)) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(4)) + x*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x, -S(3)*sqrt(Pi)*Erfc(b*x)**S(2)/(S(16)*b**S(5)) - x**S(3)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - S(3)*x*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*b**S(4)) + x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) + exp(-S(2)*b**S(2)*x**S(2))/(S(2)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x, -x**S(4)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - x**S(2)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/b**S(4) - S(43)*sqrt(S(2))*Erf(sqrt(S(2))*b*x)/(S(64)*b**S(6)) - Erfc(b*x)*exp(-b**S(2)*x**S(2))/b**S(6) + x**S(3)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) + S(11)*x*exp(-S(2)*b**S(2)*x**S(2))/(S(16)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x, -S(15)*sqrt(Pi)*Erfc(b*x)**S(2)/(S(32)*b**S(7)) - x**S(5)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(2)*b**S(2)) - S(5)*x**S(3)*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(4)*b**S(4)) - S(15)*x*Erfc(b*x)*exp(-b**S(2)*x**S(2))/(S(8)*b**S(6)) + x**S(4)*exp(-S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) + S(7)*x**S(2)*exp(-S(2)*b**S(2)*x**S(2))/(S(8)*sqrt(Pi)*b**S(5)) + S(11)*exp(-S(2)*b**S(2)*x**S(2))/(S(8)*sqrt(Pi)*b**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x**S(8), x), x, Integrate(Erfi(b*x)**S(2)/x**S(8), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x**S(7), x), x, S(4)*b**S(6)*Erfi(b*x)**S(2)/S(45) - Erfi(b*x)**S(2)/(S(6)*x**S(6)) + S(28)*b**S(6)*ExpIntegralEi(S(2)*b**S(2)*x**S(2))/(S(45)*Pi) - S(2)*b**S(4)*exp(S(2)*b**S(2)*x**S(2))/(S(9)*Pi*x**S(2)) - b**S(2)*exp(S(2)*b**S(2)*x**S(2))/(S(15)*Pi*x**S(4)) - S(8)*b**S(5)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(45)*sqrt(Pi)*x) - S(4)*b**S(3)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(45)*sqrt(Pi)*x**S(3)) - S(2)*b*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(15)*sqrt(Pi)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x**S(6), x), x, Integrate(Erfi(b*x)**S(2)/x**S(6), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x**S(5), x), x, b**S(4)*Erfi(b*x)**S(2)/S(3) - Erfi(b*x)**S(2)/(S(4)*x**S(4)) + S(4)*b**S(4)*ExpIntegralEi(S(2)*b**S(2)*x**S(2))/(S(3)*Pi) - b**S(2)*exp(S(2)*b**S(2)*x**S(2))/(S(3)*Pi*x**S(2)) - S(2)*b**S(3)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x) - b*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x**S(4), x), x, Integrate(Erfi(b*x)**S(2)/x**S(4), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x**S(3), x), x, b**S(2)*Erfi(b*x)**S(2) - Erfi(b*x)**S(2)/(S(2)*x**S(2)) + S(2)*b**S(2)*ExpIntegralEi(S(2)*b**S(2)*x**S(2))/Pi - S(2)*b*Erfi(b*x)*exp(b**S(2)*x**S(2))/(sqrt(Pi)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x**S(2), x), x, Integrate(Erfi(b*x)**S(2)/x**S(2), x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2)/x, x), x, Integrate(Erfi(b*x)**S(2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)**S(2), x), x, x*Erfi(b*x)**S(2) + sqrt(S(2))*sqrt(S(1)/Pi)*Erfi(sqrt(S(2))*b*x)/b - S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfi(b*x)**S(2), x), x, x**S(2)*Erfi(b*x)**S(2)/S(2) + Erfi(b*x)**S(2)/(S(4)*b**S(2)) + exp(S(2)*b**S(2)*x**S(2))/(S(2)*Pi*b**S(2)) - x*Erfi(b*x)*exp(b**S(2)*x**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfi(b*x)**S(2), x), x, x**S(3)*Erfi(b*x)**S(2)/S(3) + x*exp(S(2)*b**S(2)*x**S(2))/(S(3)*Pi*b**S(2)) - S(2)*x**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b) + S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b**S(3)) - S(5)*sqrt(S(2))*Erfi(sqrt(S(2))*b*x)/(S(12)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erfi(b*x)**S(2), x), x, x**S(4)*Erfi(b*x)**S(2)/S(4) - S(3)*Erfi(b*x)**S(2)/(S(16)*b**S(4)) + x**S(2)*exp(S(2)*b**S(2)*x**S(2))/(S(4)*Pi*b**S(2)) - exp(S(2)*b**S(2)*x**S(2))/(S(2)*Pi*b**S(4)) - x**S(3)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*sqrt(Pi)*b) + S(3)*x*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*Erfi(b*x)**S(2), x), x, x**S(5)*Erfi(b*x)**S(2)/S(5) + x**S(3)*exp(S(2)*b**S(2)*x**S(2))/(S(5)*Pi*b**S(2)) - S(11)*x*exp(S(2)*b**S(2)*x**S(2))/(S(20)*Pi*b**S(4)) - S(2)*x**S(4)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b) + S(4)*x**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b**S(3)) - S(4)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(5)*sqrt(Pi)*b**S(5)) + S(43)*sqrt(S(2))*Erfi(sqrt(S(2))*b*x)/(S(80)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*Erfi(b*x)**S(2), x), x, x**S(6)*Erfi(b*x)**S(2)/S(6) + S(5)*Erfi(b*x)**S(2)/(S(16)*b**S(6)) + x**S(4)*exp(S(2)*b**S(2)*x**S(2))/(S(6)*Pi*b**S(2)) - S(7)*x**S(2)*exp(S(2)*b**S(2)*x**S(2))/(S(12)*Pi*b**S(4)) + S(11)*exp(S(2)*b**S(2)*x**S(2))/(S(12)*Pi*b**S(6)) - x**S(5)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*b) + S(5)*x**S(3)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*b**S(3)) - S(5)*x*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(a + b*x)/x, x), x, Integrate(Erfi(a + b*x)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(a + b*x), x), x, (a + b*x)*Erfi(a + b*x)/b - exp((a + b*x)**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfi(a + b*x), x), x, -a**S(2)*Erfi(a + b*x)/(S(2)*b**S(2)) + x**S(2)*Erfi(a + b*x)/S(2) + Erfi(a + b*x)/(S(4)*b**S(2)) + a*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(2)) - (a + b*x)*exp((a + b*x)**S(2))/(S(2)*sqrt(Pi)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfi(a + b*x), x), x, a**S(3)*Erfi(a + b*x)/(S(3)*b**S(3)) - a*Erfi(a + b*x)/(S(2)*b**S(3)) + x**S(3)*Erfi(a + b*x)/S(3) - a**S(2)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) + a*(a + b*x)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) - (a + b*x)**S(2)*exp((a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)) + exp((a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erfi(a + b*x), x), x, -a**S(4)*Erfi(a + b*x)/(S(4)*b**S(4)) + S(3)*a**S(2)*Erfi(a + b*x)/(S(4)*b**S(4)) + x**S(4)*Erfi(a + b*x)/S(4) - S(3)*Erfi(a + b*x)/(S(16)*b**S(4)) + a**S(3)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) - S(3)*a**S(2)*(a + b*x)*exp((a + b*x)**S(2))/(S(2)*sqrt(Pi)*b**S(4)) + a*(a + b*x)**S(2)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) - a*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(4)) - (a + b*x)**S(3)*exp((a + b*x)**S(2))/(S(4)*sqrt(Pi)*b**S(4)) + S(3)*(a + b*x)*exp((a + b*x)**S(2))/(S(8)*sqrt(Pi)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(a + b*x)**S(2)/x, x), x, Integrate(Erfi(a + b*x)**S(2)/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(a + b*x)**S(2), x), x, (a + b*x)*Erfi(a + b*x)**S(2)/b + sqrt(S(2))*sqrt(S(1)/Pi)*Erfi(sqrt(S(2))*(a + b*x))/b - S(2)*Erfi(a + b*x)*exp((a + b*x)**S(2))/(sqrt(Pi)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfi(a + b*x)**S(2), x), x, -a*(a + b*x)*Erfi(a + b*x)**S(2)/b**S(2) - sqrt(S(2))*a*sqrt(S(1)/Pi)*Erfi(sqrt(S(2))*(a + b*x))/b**S(2) + (a + b*x)**S(2)*Erfi(a + b*x)**S(2)/(S(2)*b**S(2)) + Erfi(a + b*x)**S(2)/(S(4)*b**S(2)) + exp(S(2)*(a + b*x)**S(2))/(S(2)*Pi*b**S(2)) + S(2)*a*Erfi(a + b*x)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(2)) - (a + b*x)*Erfi(a + b*x)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfi(a + b*x)**S(2), x), x, a**S(2)*(a + b*x)*Erfi(a + b*x)**S(2)/b**S(3) + sqrt(S(2))*a**S(2)*sqrt(S(1)/Pi)*Erfi(sqrt(S(2))*(a + b*x))/b**S(3) - a*(a + b*x)**S(2)*Erfi(a + b*x)**S(2)/b**S(3) - a*Erfi(a + b*x)**S(2)/(S(2)*b**S(3)) + (a + b*x)**S(3)*Erfi(a + b*x)**S(2)/(S(3)*b**S(3)) - a*exp(S(2)*(a + b*x)**S(2))/(Pi*b**S(3)) + (a + b*x)*exp(S(2)*(a + b*x)**S(2))/(S(3)*Pi*b**S(3)) - S(2)*a**S(2)*Erfi(a + b*x)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) + S(2)*a*(a + b*x)*Erfi(a + b*x)*exp((a + b*x)**S(2))/(sqrt(Pi)*b**S(3)) - S(2)*(a + b*x)**S(2)*Erfi(a + b*x)*exp((a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)) - S(5)*sqrt(S(2))*Erfi(sqrt(S(2))*(a + b*x))/(S(12)*sqrt(Pi)*b**S(3)) + S(2)*Erfi(a + b*x)*exp((a + b*x)**S(2))/(S(3)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x**S(8), x), x, S(4)*sqrt(Pi)*b**S(7)*Erfi(b*x)**S(2)/S(105) - S(8)*b**S(6)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(105)*x) - S(4)*b**S(4)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(105)*x**S(3)) - S(2)*b**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(35)*x**S(5)) - Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(7)*x**S(7)) + S(16)*b**S(7)*ExpIntegralEi(S(2)*b**S(2)*x**S(2))/(S(35)*sqrt(Pi)) - S(4)*b**S(5)*exp(S(2)*b**S(2)*x**S(2))/(S(21)*sqrt(Pi)*x**S(2)) - S(8)*b**S(3)*exp(S(2)*b**S(2)*x**S(2))/(S(105)*sqrt(Pi)*x**S(4)) - b*exp(S(2)*b**S(2)*x**S(2))/(S(21)*sqrt(Pi)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x**S(7), x), x, S(67)*sqrt(S(2))*b**S(6)*Erfi(sqrt(S(2))*b*x)/S(90) + b**S(6)*Integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x, x)/S(6) - b**S(4)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(12)*x**S(2)) - b**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(12)*x**S(4)) - Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(6)*x**S(6)) - S(67)*b**S(5)*exp(S(2)*b**S(2)*x**S(2))/(S(90)*sqrt(Pi)*x) - S(13)*b**S(3)*exp(S(2)*b**S(2)*x**S(2))/(S(90)*sqrt(Pi)*x**S(3)) - b*exp(S(2)*b**S(2)*x**S(2))/(S(15)*sqrt(Pi)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x**S(6), x), x, S(2)*sqrt(Pi)*b**S(5)*Erfi(b*x)**S(2)/S(15) - S(4)*b**S(4)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(15)*x) - S(2)*b**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(15)*x**S(3)) - Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(5)*x**S(5)) + S(14)*b**S(5)*ExpIntegralEi(S(2)*b**S(2)*x**S(2))/(S(15)*sqrt(Pi)) - b**S(3)*exp(S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(2)) - b*exp(S(2)*b**S(2)*x**S(2))/(S(10)*sqrt(Pi)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x**S(5), x), x, S(7)*sqrt(S(2))*b**S(4)*Erfi(sqrt(S(2))*b*x)/S(6) + b**S(4)*Integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x, x)/S(2) - b**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(4)*x**S(2)) - Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(4)*x**S(4)) - S(7)*b**S(3)*exp(S(2)*b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*x) - b*exp(S(2)*b**S(2)*x**S(2))/(S(6)*sqrt(Pi)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x**S(4), x), x, sqrt(Pi)*b**S(3)*Erfi(b*x)**S(2)/S(3) - S(2)*b**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(3)*x) - Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(3)*x**S(3)) + S(4)*b**S(3)*ExpIntegralEi(S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)) - b*exp(S(2)*b**S(2)*x**S(2))/(S(3)*sqrt(Pi)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x**S(3), x), x, sqrt(S(2))*b**S(2)*Erfi(sqrt(S(2))*b*x) + b**S(2)*Integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x, x) - Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*x**S(2)) - b*exp(S(2)*b**S(2)*x**S(2))/(sqrt(Pi)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x**S(2), x), x, sqrt(Pi)*b*Erfi(b*x)**S(2)/S(2) - Erfi(b*x)*exp(b**S(2)*x**S(2))/x + b*ExpIntegralEi(S(2)*b**S(2)*x**S(2))/sqrt(Pi), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x, x), x, Integrate(Erfi(b*x)*exp(b**S(2)*x**S(2))/x, x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x, sqrt(Pi)*Erfi(b*x)**S(2)/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x, Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*b**S(2)) - sqrt(S(2))*Erfi(sqrt(S(2))*b*x)/(S(4)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x, -sqrt(Pi)*Erfi(b*x)**S(2)/(S(8)*b**S(3)) + x*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*b**S(2)) - exp(S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x, x**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*b**S(2)) - Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*b**S(4)) + S(5)*sqrt(S(2))*Erfi(sqrt(S(2))*b*x)/(S(16)*b**S(4)) - x*exp(S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x, S(3)*sqrt(Pi)*Erfi(b*x)**S(2)/(S(16)*b**S(5)) + x**S(3)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*b**S(2)) - S(3)*x*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(4)*b**S(4)) - x**S(2)*exp(S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) + exp(S(2)*b**S(2)*x**S(2))/(S(2)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x, x**S(4)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*b**S(2)) - x**S(2)*Erfi(b*x)*exp(b**S(2)*x**S(2))/b**S(4) + Erfi(b*x)*exp(b**S(2)*x**S(2))/b**S(6) - S(43)*sqrt(S(2))*Erfi(sqrt(S(2))*b*x)/(S(64)*b**S(6)) - x**S(3)*exp(S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) + S(11)*x*exp(S(2)*b**S(2)*x**S(2))/(S(16)*sqrt(Pi)*b**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x, -S(15)*sqrt(Pi)*Erfi(b*x)**S(2)/(S(32)*b**S(7)) + x**S(5)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(2)*b**S(2)) - S(5)*x**S(3)*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(4)*b**S(4)) + S(15)*x*Erfi(b*x)*exp(b**S(2)*x**S(2))/(S(8)*b**S(6)) - x**S(4)*exp(S(2)*b**S(2)*x**S(2))/(S(4)*sqrt(Pi)*b**S(3)) + S(7)*x**S(2)*exp(S(2)*b**S(2)*x**S(2))/(S(8)*sqrt(Pi)*b**S(5)) - S(11)*exp(S(2)*b**S(2)*x**S(2))/(S(8)*sqrt(Pi)*b**S(7)), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_tangent.py000066400000000000000000004024261412543434000264430ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.utility_function import ( sympy_op_factory, Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf, exp, log) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec) from sympy import pi as Pi from sympy.integrals.rubi.rubi import rubi_integrate a, b, c, d, e, f, m, n, x, u , k, p, r, s, t, i, j= symbols('a b c d e f m n x u k p r s t i j') A, B, C, D, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C D a b c d e f g h y z m n p q u v w F', ) def test_1(): assert rubi_test(rubi_integrate(tan(c + d*x), x), x, -log(cos(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(c + d*x)**S(2), x), x, -x + tan(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(c + d*x)**S(3), x), x, log(cos(c + d*x))/d + tan(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(c + d*x)**S(4), x), x, x + tan(c + d*x)**S(3)/(S(3)*d) - tan(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(c + d*x)**S(5), x), x, -log(cos(c + d*x))/d + tan(c + d*x)**S(4)/(S(4)*d) - tan(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(c + d*x)**S(6), x), x, -x + tan(c + d*x)**S(5)/(S(5)*d) - tan(c + d*x)**S(3)/(S(3)*d) + tan(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(c + d*x)**S(7), x), x, log(cos(c + d*x))/d + tan(c + d*x)**S(6)/(S(6)*d) - tan(c + d*x)**S(4)/(S(4)*d) + tan(c + d*x)**S(2)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(c + d*x)**S(8), x), x, x + tan(c + d*x)**S(7)/(S(7)*d) - tan(c + d*x)**S(5)/(S(5)*d) + tan(c + d*x)**S(3)/(S(3)*d) - tan(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(7)/2), x), x, -sqrt(S(2))*b**(S(7)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) + sqrt(S(2))*b**(S(7)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) - sqrt(S(2))*b**(S(7)/2)*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d) + sqrt(S(2))*b**(S(7)/2)*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d) - S(2)*b**S(3)*sqrt(b*tan(c + d*x))/d + S(2)*b*(b*tan(c + d*x))**(S(5)/2)/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(5)/2), x), x, sqrt(S(2))*b**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) - sqrt(S(2))*b**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) - sqrt(S(2))*b**(S(5)/2)*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d) + sqrt(S(2))*b**(S(5)/2)*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d) + S(2)*b*(b*tan(c + d*x))**(S(3)/2)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(3)/2), x), x, sqrt(S(2))*b**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) - sqrt(S(2))*b**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) + sqrt(S(2))*b**(S(3)/2)*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d) - sqrt(S(2))*b**(S(3)/2)*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d) + S(2)*b*sqrt(b*tan(c + d*x))/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(c + d*x)), x), x, -sqrt(S(2))*sqrt(b)*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) + sqrt(S(2))*sqrt(b)*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*d) + sqrt(S(2))*sqrt(b)*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d) - sqrt(S(2))*sqrt(b)*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*tan(c + d*x)), x), x, -sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*sqrt(b)*d) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*sqrt(b)*d) - sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*sqrt(b)*d) + sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*sqrt(b)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(-3)/2), x), x, -S(2)/(b*d*sqrt(b*tan(c + d*x))) + sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*b**(S(3)/2)*d) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*b**(S(3)/2)*d) - sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*b**(S(3)/2)*d) + sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*b**(S(3)/2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(-5)/2), x), x, -S(2)/(S(3)*b*d*(b*tan(c + d*x))**(S(3)/2)) + sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*b**(S(5)/2)*d) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*b**(S(5)/2)*d) + sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*b**(S(5)/2)*d) - sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*b**(S(5)/2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(-7)/2), x), x, -S(2)/(S(5)*b*d*(b*tan(c + d*x))**(S(5)/2)) + S(2)/(b**S(3)*d*sqrt(b*tan(c + d*x))) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*b**(S(7)/2)*d) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(b*tan(c + d*x))/sqrt(b))/(S(2)*b**(S(7)/2)*d) + sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) - sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*b**(S(7)/2)*d) - sqrt(S(2))*log(sqrt(b)*tan(c + d*x) + sqrt(b) + sqrt(S(2))*sqrt(b*tan(c + d*x)))/(S(4)*b**(S(7)/2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(4)/3), x), x, -b**(S(4)/3)*ArcTan((b*tan(c + d*x))**(S(1)/3)/b**(S(1)/3))/d + b**(S(4)/3)*ArcTan((sqrt(S(3))*b**(S(1)/3) - S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*d) - b**(S(4)/3)*ArcTan((sqrt(S(3))*b**(S(1)/3) + S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*d) + sqrt(S(3))*b**(S(4)/3)*log(b**(S(2)/3) - sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*d) - sqrt(S(3))*b**(S(4)/3)*log(b**(S(2)/3) + sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*d) + S(3)*b*(b*tan(c + d*x))**(S(1)/3)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(2)/3), x), x, b**(S(2)/3)*ArcTan((b*tan(c + d*x))**(S(1)/3)/b**(S(1)/3))/d - b**(S(2)/3)*ArcTan((sqrt(S(3))*b**(S(1)/3) - S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*d) + b**(S(2)/3)*ArcTan((sqrt(S(3))*b**(S(1)/3) + S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*d) + sqrt(S(3))*b**(S(2)/3)*log(b**(S(2)/3) - sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*d) - sqrt(S(3))*b**(S(2)/3)*log(b**(S(2)/3) + sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(1)/3), x), x, -sqrt(S(3))*b**(S(1)/3)*ArcTan(sqrt(S(3))*(b**(S(2)/3) - S(2)*(b*tan(c + d*x))**(S(2)/3))/(S(3)*b**(S(2)/3)))/(S(2)*d) - b**(S(1)/3)*log(b**(S(2)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(2)*d) + b**(S(1)/3)*log(b**(S(4)/3) - b**(S(2)/3)*(b*tan(c + d*x))**(S(2)/3) + (b*tan(c + d*x))**(S(4)/3))/(S(4)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(-1)/3), x), x, -sqrt(S(3))*ArcTan(sqrt(S(3))*(b**(S(2)/3) - S(2)*(b*tan(c + d*x))**(S(2)/3))/(S(3)*b**(S(2)/3)))/(S(2)*b**(S(1)/3)*d) + log(b**(S(2)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(2)*b**(S(1)/3)*d) - log(b**(S(4)/3) - b**(S(2)/3)*(b*tan(c + d*x))**(S(2)/3) + (b*tan(c + d*x))**(S(4)/3))/(S(4)*b**(S(1)/3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(-2)/3), x), x, ArcTan((b*tan(c + d*x))**(S(1)/3)/b**(S(1)/3))/(b**(S(2)/3)*d) - ArcTan((sqrt(S(3))*b**(S(1)/3) - S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*b**(S(2)/3)*d) + ArcTan((sqrt(S(3))*b**(S(1)/3) + S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*b**(S(2)/3)*d) - sqrt(S(3))*log(b**(S(2)/3) - sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*b**(S(2)/3)*d) + sqrt(S(3))*log(b**(S(2)/3) + sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*b**(S(2)/3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**(S(-4)/3), x), x, -S(3)/(b*d*(b*tan(c + d*x))**(S(1)/3)) - ArcTan((b*tan(c + d*x))**(S(1)/3)/b**(S(1)/3))/(b**(S(4)/3)*d) + ArcTan((sqrt(S(3))*b**(S(1)/3) - S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*b**(S(4)/3)*d) - ArcTan((sqrt(S(3))*b**(S(1)/3) + S(2)*(b*tan(c + d*x))**(S(1)/3))/b**(S(1)/3))/(S(2)*b**(S(4)/3)*d) - sqrt(S(3))*log(b**(S(2)/3) - sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*b**(S(4)/3)*d) + sqrt(S(3))*log(b**(S(2)/3) + sqrt(S(3))*b**(S(1)/3)*(b*tan(c + d*x))**(S(1)/3) + (b*tan(c + d*x))**(S(2)/3))/(S(4)*b**(S(4)/3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x))**n, x), x, (b*tan(c + d*x))**(n + S(1))*Hypergeometric2F1(S(1), n/S(2) + S(1)/2, n/S(2) + S(3)/2, -tan(c + d*x)**S(2))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(2))**(S(5)/2), x), x, -b**S(2)*sqrt(b*tan(c + d*x)**S(2))*log(cos(c + d*x))*cot(c + d*x)/d + b**S(2)*sqrt(b*tan(c + d*x)**S(2))*tan(c + d*x)**S(3)/(S(4)*d) - b**S(2)*sqrt(b*tan(c + d*x)**S(2))*tan(c + d*x)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(2))**(S(3)/2), x), x, b*sqrt(b*tan(c + d*x)**S(2))*log(cos(c + d*x))*cot(c + d*x)/d + b*sqrt(b*tan(c + d*x)**S(2))*tan(c + d*x)/(S(2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(c + d*x)**S(2)), x), x, -sqrt(b*tan(c + d*x)**S(2))*log(cos(c + d*x))*cot(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*tan(c + d*x)**S(2)), x), x, log(sin(c + d*x))*tan(c + d*x)/(d*sqrt(b*tan(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(2))**(S(-3)/2), x), x, -log(sin(c + d*x))*tan(c + d*x)/(b*d*sqrt(b*tan(c + d*x)**S(2))) - cot(c + d*x)/(S(2)*b*d*sqrt(b*tan(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(2))**(S(-5)/2), x), x, log(sin(c + d*x))*tan(c + d*x)/(b**S(2)*d*sqrt(b*tan(c + d*x)**S(2))) - cot(c + d*x)**S(3)/(S(4)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(2))) + cot(c + d*x)/(S(2)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(3))**(S(5)/2), x), x, -sqrt(S(2))*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*ArcTan(-sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))/(S(2)*d*tan(c + d*x)**(S(3)/2)) + sqrt(S(2))*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*ArcTan(sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))/(S(2)*d*tan(c + d*x)**(S(3)/2)) - sqrt(S(2))*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*log(-sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))/(S(4)*d*tan(c + d*x)**(S(3)/2)) + sqrt(S(2))*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*log(sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))/(S(4)*d*tan(c + d*x)**(S(3)/2)) + S(2)*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*tan(c + d*x)**S(5)/(S(13)*d) - S(2)*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*tan(c + d*x)**S(3)/(S(9)*d) + S(2)*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*tan(c + d*x)/(S(5)*d) - S(2)*b**S(2)*sqrt(b*tan(c + d*x)**S(3))*cot(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(3))**(S(3)/2), x), x, -sqrt(S(2))*b*sqrt(b*tan(c + d*x)**S(3))*ArcTan(-sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))/(S(2)*d*tan(c + d*x)**(S(3)/2)) + sqrt(S(2))*b*sqrt(b*tan(c + d*x)**S(3))*ArcTan(sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))/(S(2)*d*tan(c + d*x)**(S(3)/2)) + sqrt(S(2))*b*sqrt(b*tan(c + d*x)**S(3))*log(-sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))/(S(4)*d*tan(c + d*x)**(S(3)/2)) - sqrt(S(2))*b*sqrt(b*tan(c + d*x)**S(3))*log(sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))/(S(4)*d*tan(c + d*x)**(S(3)/2)) + S(2)*b*sqrt(b*tan(c + d*x)**S(3))*tan(c + d*x)**S(2)/(S(7)*d) - S(2)*b*sqrt(b*tan(c + d*x)**S(3))/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(c + d*x)**S(3)), x), x, sqrt(S(2))*sqrt(b*tan(c + d*x)**S(3))*ArcTan(-sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))/(S(2)*d*tan(c + d*x)**(S(3)/2)) - sqrt(S(2))*sqrt(b*tan(c + d*x)**S(3))*ArcTan(sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))/(S(2)*d*tan(c + d*x)**(S(3)/2)) + sqrt(S(2))*sqrt(b*tan(c + d*x)**S(3))*log(-sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))/(S(4)*d*tan(c + d*x)**(S(3)/2)) - sqrt(S(2))*sqrt(b*tan(c + d*x)**S(3))*log(sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))/(S(4)*d*tan(c + d*x)**(S(3)/2)) + S(2)*sqrt(b*tan(c + d*x)**S(3))*cot(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*tan(c + d*x)**S(3)), x), x, sqrt(S(2))*ArcTan(-sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))*tan(c + d*x)**(S(3)/2)/(S(2)*d*sqrt(b*tan(c + d*x)**S(3))) - sqrt(S(2))*ArcTan(sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))*tan(c + d*x)**(S(3)/2)/(S(2)*d*sqrt(b*tan(c + d*x)**S(3))) - sqrt(S(2))*log(-sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))*tan(c + d*x)**(S(3)/2)/(S(4)*d*sqrt(b*tan(c + d*x)**S(3))) + sqrt(S(2))*log(sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))*tan(c + d*x)**(S(3)/2)/(S(4)*d*sqrt(b*tan(c + d*x)**S(3))) - S(2)*tan(c + d*x)/(d*sqrt(b*tan(c + d*x)**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(3))**(S(-3)/2), x), x, -sqrt(S(2))*ArcTan(-sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))*tan(c + d*x)**(S(3)/2)/(S(2)*b*d*sqrt(b*tan(c + d*x)**S(3))) + sqrt(S(2))*ArcTan(sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))*tan(c + d*x)**(S(3)/2)/(S(2)*b*d*sqrt(b*tan(c + d*x)**S(3))) - sqrt(S(2))*log(-sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))*tan(c + d*x)**(S(3)/2)/(S(4)*b*d*sqrt(b*tan(c + d*x)**S(3))) + sqrt(S(2))*log(sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))*tan(c + d*x)**(S(3)/2)/(S(4)*b*d*sqrt(b*tan(c + d*x)**S(3))) - S(2)*cot(c + d*x)**S(2)/(S(7)*b*d*sqrt(b*tan(c + d*x)**S(3))) + S(2)/(S(3)*b*d*sqrt(b*tan(c + d*x)**S(3))), expand=True, _diff=True, _numerical=True) # taking a long time assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(3))**(S(-5)/2), x), x, -sqrt(S(2))*ArcTan(-sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))*tan(c + d*x)**(S(3)/2)/(S(2)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))) + sqrt(S(2))*ArcTan(sqrt(S(2))*sqrt(tan(c + d*x)) + S(1))*tan(c + d*x)**(S(3)/2)/(S(2)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))) + sqrt(S(2))*log(-sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))*tan(c + d*x)**(S(3)/2)/(S(4)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))) - sqrt(S(2))*log(sqrt(S(2))*sqrt(tan(c + d*x)) + tan(c + d*x) + S(1))*tan(c + d*x)**(S(3)/2)/(S(4)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))) + S(2)*tan(c + d*x)/(b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))) - S(2)*cot(c + d*x)**S(5)/(S(13)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))) + S(2)*cot(c + d*x)**S(3)/(S(9)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))) - S(2)*cot(c + d*x)/(S(5)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(4))**(S(5)/2), x), x, -b**S(2)*x*sqrt(b*tan(c + d*x)**S(4))*cot(c + d*x)**S(2) + b**S(2)*sqrt(b*tan(c + d*x)**S(4))*tan(c + d*x)**S(7)/(S(9)*d) - b**S(2)*sqrt(b*tan(c + d*x)**S(4))*tan(c + d*x)**S(5)/(S(7)*d) + b**S(2)*sqrt(b*tan(c + d*x)**S(4))*tan(c + d*x)**S(3)/(S(5)*d) - b**S(2)*sqrt(b*tan(c + d*x)**S(4))*tan(c + d*x)/(S(3)*d) + b**S(2)*sqrt(b*tan(c + d*x)**S(4))*cot(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(4))**(S(3)/2), x), x, -b*x*sqrt(b*tan(c + d*x)**S(4))*cot(c + d*x)**S(2) + b*sqrt(b*tan(c + d*x)**S(4))*tan(c + d*x)**S(3)/(S(5)*d) - b*sqrt(b*tan(c + d*x)**S(4))*tan(c + d*x)/(S(3)*d) + b*sqrt(b*tan(c + d*x)**S(4))*cot(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(c + d*x)**S(4)), x), x, -x*sqrt(b*tan(c + d*x)**S(4))*cot(c + d*x)**S(2) + sqrt(b*tan(c + d*x)**S(4))*cot(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*tan(c + d*x)**S(4)), x), x, -x*tan(c + d*x)**S(2)/sqrt(b*tan(c + d*x)**S(4)) - tan(c + d*x)/(d*sqrt(b*tan(c + d*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(4))**(S(-3)/2), x), x, -x*tan(c + d*x)**S(2)/(b*sqrt(b*tan(c + d*x)**S(4))) - tan(c + d*x)/(b*d*sqrt(b*tan(c + d*x)**S(4))) - cot(c + d*x)**S(3)/(S(5)*b*d*sqrt(b*tan(c + d*x)**S(4))) + cot(c + d*x)/(S(3)*b*d*sqrt(b*tan(c + d*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(4))**(S(-5)/2), x), x, -x*tan(c + d*x)**S(2)/(b**S(2)*sqrt(b*tan(c + d*x)**S(4))) - tan(c + d*x)/(b**S(2)*d*sqrt(b*tan(c + d*x)**S(4))) - cot(c + d*x)**S(7)/(S(9)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(4))) + cot(c + d*x)**S(5)/(S(7)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(4))) - cot(c + d*x)**S(3)/(S(5)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(4))) + cot(c + d*x)/(S(3)*b**S(2)*d*sqrt(b*tan(c + d*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**p)**n, x), x, (b*tan(c + d*x)**p)**n*Hypergeometric2F1(S(1), n*p/S(2) + S(1)/2, n*p/S(2) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)/(d*(n*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(2))**n, x), x, (b*tan(c + d*x)**S(2))**n*Hypergeometric2F1(S(1), n + S(1)/2, n + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)/(d*(S(2)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(3))**n, x), x, (b*tan(c + d*x)**S(3))**n*Hypergeometric2F1(S(1), S(3)*n/S(2) + S(1)/2, S(3)*n/S(2) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)/(d*(S(3)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**S(4))**n, x), x, (b*tan(c + d*x)**S(4))**n*Hypergeometric2F1(S(1), S(2)*n + S(1)/2, S(2)*n + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)/(d*(S(4)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**p)**(S(5)/2), x), x, S(2)*b**S(2)*sqrt(b*tan(c + d*x)**p)*Hypergeometric2F1(S(1), S(5)*p/S(4) + S(1)/2, S(5)*p/S(4) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)**(S(2)*p + S(1))/(d*(S(5)*p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**p)**(S(3)/2), x), x, S(2)*b*sqrt(b*tan(c + d*x)**p)*Hypergeometric2F1(S(1), S(3)*p/S(4) + S(1)/2, S(3)*p/S(4) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)**(p + S(1))/(d*(S(3)*p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(c + d*x)**p), x), x, S(2)*sqrt(b*tan(c + d*x)**p)*Hypergeometric2F1(S(1), p/S(4) + S(1)/2, p/S(4) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)/(d*(p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*tan(c + d*x)**p), x), x, S(2)*Hypergeometric2F1(S(1), -p/S(4) + S(1)/2, -p/S(4) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)/(d*sqrt(b*tan(c + d*x)**p)*(-p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**p)**(S(-3)/2), x), x, S(2)*Hypergeometric2F1(S(1), -S(3)*p/S(4) + S(1)/2, -S(3)*p/S(4) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)**(-p + S(1))/(b*d*sqrt(b*tan(c + d*x)**p)*(-S(3)*p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**p)**(S(-5)/2), x), x, S(2)*Hypergeometric2F1(S(1), -S(5)*p/S(4) + S(1)/2, -S(5)*p/S(4) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)**(-S(2)*p + S(1))/(b**S(2)*d*sqrt(b*tan(c + d*x)**p)*(-S(5)*p + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(c + d*x)**p)**(S(1)/p), x), x, -(b*tan(c + d*x)**p)**(S(1)/p)*log(cos(c + d*x))*cot(c + d*x)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*(b*tan(c + d*x))**p)**n, x), x, (a*(b*tan(c + d*x))**p)**n*Hypergeometric2F1(S(1), n*p/S(2) + S(1)/2, n*p/S(2) + S(3)/2, -tan(c + d*x)**S(2))*tan(c + d*x)/(d*(n*p + S(1))), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*sin(a + b*x)**S(4), x), x, -S(21)*sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b) + S(21)*sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b) + S(21)*sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b) - S(21)*sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b) - S(7)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(2)/(S(16)*b*d) - (d*tan(a + b*x))**(S(7)/2)*cos(a + b*x)**S(4)/(S(4)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*sin(a + b*x)**S(2), x), x, -S(3)*sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) + S(3)*sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) + S(3)*sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) - S(3)*sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) - (d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(2)/(S(2)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*csc(a + b*x)**S(2), x), x, -S(2)*d/(b*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*csc(a + b*x)**S(4), x), x, -S(2)*d**S(3)/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)) - S(2)*d/(b*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*csc(a + b*x)**S(6), x), x, -S(2)*d**S(5)/(S(9)*b*(d*tan(a + b*x))**(S(9)/2)) - S(4)*d**S(3)/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)) - S(2)*d/(b*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*sin(a + b*x)**S(3), x), x, S(5)*d*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(12)*b*sqrt(d*tan(a + b*x))) - S(5)*sqrt(d*tan(a + b*x))*cos(a + b*x)/(S(6)*b) - (d*tan(a + b*x))**(S(5)/2)*cos(a + b*x)**S(3)/(S(3)*b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*sin(a + b*x), x), x, d*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(2)*b*sqrt(d*tan(a + b*x))) - sqrt(d*tan(a + b*x))*cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*csc(a + b*x), x), x, d*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(b*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*csc(a + b*x)**S(3), x), x, -S(2)*d**S(2)*sec(a + b*x)/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)) + S(2)*d*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(3)*b*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(a + b*x))*csc(a + b*x)**S(5), x), x, -S(2)*d**S(4)*sec(a + b*x)**S(3)/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)) - S(4)*d**S(2)*sec(a + b*x)/(S(7)*b*(d*tan(a + b*x))**(S(3)/2)) + S(4)*d*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(7)*b*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sin(a + b*x)**S(4), x), x, S(45)*sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b) - S(45)*sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b) + S(45)*sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b) - S(45)*sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b) + S(45)*d*sqrt(d*tan(a + b*x))/(S(16)*b) - S(9)*(d*tan(a + b*x))**(S(5)/2)*cos(a + b*x)**S(2)/(S(16)*b*d) - (d*tan(a + b*x))**(S(9)/2)*cos(a + b*x)**S(4)/(S(4)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sin(a + b*x)**S(2), x), x, S(5)*sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) - S(5)*sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) + S(5)*sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) - S(5)*sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) + S(5)*d*sqrt(d*tan(a + b*x))/(S(2)*b) - (d*tan(a + b*x))**(S(5)/2)*cos(a + b*x)**S(2)/(S(2)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*csc(a + b*x)**S(2), x), x, S(2)*d*sqrt(d*tan(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*csc(a + b*x)**S(4), x), x, -S(2)*d**S(3)/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)) + S(2)*d*sqrt(d*tan(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*csc(a + b*x)**S(6), x), x, -S(2)*d**S(5)/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)) - S(4)*d**S(3)/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)) + S(2)*d*sqrt(d*tan(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sin(a + b*x)**S(3), x), x, -S(7)*d*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(2)*b*sqrt(sin(S(2)*a + S(2)*b*x))) + S(7)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)/(S(3)*b) - (d*tan(a + b*x))**(S(7)/2)*cos(a + b*x)**S(3)/(S(3)*b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sin(a + b*x), x), x, -S(3)*d*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*csc(a + b*x), x), x, -S(2)*d*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*sqrt(sin(S(2)*a + S(2)*b*x))) + S(2)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*csc(a + b*x)**S(3), x), x, -S(2)*d**S(2)*sec(a + b*x)/(b*sqrt(d*tan(a + b*x))) - S(4)*d*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*sqrt(sin(S(2)*a + S(2)*b*x))) + S(4)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*sin(a + b*x)**S(4), x), x, S(77)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b) - S(77)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b) - S(77)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b) + S(77)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b) + S(77)*d*(d*tan(a + b*x))**(S(3)/2)/(S(48)*b) - S(11)*(d*tan(a + b*x))**(S(7)/2)*cos(a + b*x)**S(2)/(S(16)*b*d) - (d*tan(a + b*x))**(S(11)/2)*cos(a + b*x)**S(4)/(S(4)*b*d**S(3)), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*sin(a + b*x)**S(2), x), x, S(7)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) - S(7)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) - S(7)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) + S(7)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) + S(7)*d*(d*tan(a + b*x))**(S(3)/2)/(S(6)*b) - (d*tan(a + b*x))**(S(7)/2)*cos(a + b*x)**S(2)/(S(2)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*csc(a + b*x)**S(2), x), x, S(2)*d*(d*tan(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*csc(a + b*x)**S(4), x), x, -S(2)*d**S(3)/(b*sqrt(d*tan(a + b*x))) + S(2)*d*(d*tan(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*csc(a + b*x)**S(6), x), x, -S(2)*d**S(5)/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)) - S(4)*d**S(3)/(b*sqrt(d*tan(a + b*x))) + S(2)*d*(d*tan(a + b*x))**(S(3)/2)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*sin(a + b*x)**S(3), x), x, -S(5)*d**S(3)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(4)*b*sqrt(d*tan(a + b*x))) + S(5)*d**S(2)*sqrt(d*tan(a + b*x))*cos(a + b*x)/(S(2)*b) + (d*tan(a + b*x))**(S(5)/2)*cos(a + b*x)/b - (d*tan(a + b*x))**(S(9)/2)*cos(a + b*x)**S(3)/(S(3)*b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*sin(a + b*x), x), x, -S(5)*d**S(3)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(6)*b*sqrt(d*tan(a + b*x))) + S(5)*d**S(2)*sqrt(d*tan(a + b*x))*cos(a + b*x)/(S(3)*b) + S(2)*(d*tan(a + b*x))**(S(5)/2)*cos(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*csc(a + b*x), x), x, -d**S(3)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(3)*b*sqrt(d*tan(a + b*x))) + S(2)*d**S(2)*sqrt(d*tan(a + b*x))*sec(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*csc(a + b*x)**S(3), x), x, S(2)*d**S(3)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(3)*b*sqrt(d*tan(a + b*x))) + S(2)*d**S(2)*sqrt(d*tan(a + b*x))*sec(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*csc(a + b*x)**S(5), x), x, -S(2)*d**S(4)*sec(a + b*x)**S(3)/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)) + S(4)*d**S(3)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(3)*b*sqrt(d*tan(a + b*x))) + S(4)*d**S(2)*sqrt(d*tan(a + b*x))*sec(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(5)/2)*csc(a + b*x)**S(7), x), x, -S(2)*d**S(6)*sec(a + b*x)**S(5)/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)) - S(20)*d**S(4)*sec(a + b*x)**S(3)/(S(21)*b*(d*tan(a + b*x))**(S(3)/2)) + S(40)*d**S(3)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(21)*b*sqrt(d*tan(a + b*x))) + S(40)*d**S(2)*sqrt(d*tan(a + b*x))*sec(a + b*x)/(S(21)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/sqrt(d*tan(a + b*x)), x), x, -S(5)*sqrt(d*tan(a + b*x))*cos(a + b*x)**S(2)/(S(16)*b*d) - (d*tan(a + b*x))**(S(5)/2)*cos(a + b*x)**S(4)/(S(4)*b*d**S(3)) - S(5)*sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b*sqrt(d)) + S(5)*sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b*sqrt(d)) - S(5)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b*sqrt(d)) + S(5)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/sqrt(d*tan(a + b*x)), x), x, -sqrt(d*tan(a + b*x))*cos(a + b*x)**S(2)/(S(2)*b*d) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*sqrt(d)) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*sqrt(d)) - sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*sqrt(d)) + sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(2)/sqrt(d*tan(a + b*x)), x), x, -S(2)*d/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(4)/sqrt(d*tan(a + b*x)), x), x, -S(2)*d**S(3)/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)) - S(2)*d/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(6)/sqrt(d*tan(a + b*x)), x), x, -S(2)*d**S(5)/(S(11)*b*(d*tan(a + b*x))**(S(11)/2)) - S(4)*d**S(3)/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)) - S(2)*d/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/sqrt(d*tan(a + b*x)), x), x, sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(2)*b*d*sqrt(sin(S(2)*a + S(2)*b*x))) - (d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(3)/(S(3)*b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/sqrt(d*tan(a + b*x)), x), x, sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*d*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/sqrt(d*tan(a + b*x)), x), x, -S(2)*cos(a + b*x)/(b*sqrt(d*tan(a + b*x))) - S(2)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*d*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(3)/sqrt(d*tan(a + b*x)), x), x, -S(2)*d**S(2)*sec(a + b*x)/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)) - S(4)*cos(a + b*x)/(S(5)*b*sqrt(d*tan(a + b*x))) - S(4)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(5)*b*d*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/(d*tan(a + b*x))**(S(3)/2), x), x, -(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(4)/(S(4)*b*d**S(3)) + S(3)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(2)/(S(16)*b*d**S(3)) - S(3)*sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b*d**(S(3)/2)) + S(3)*sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b*d**(S(3)/2)) + S(3)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b*d**(S(3)/2)) - S(3)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/(d*tan(a + b*x))**(S(3)/2), x), x, (d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(2)/(S(2)*b*d**S(3)) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*d**(S(3)/2)) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*d**(S(3)/2)) + sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*d**(S(3)/2)) - sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(2)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*d/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(4)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*d**S(3)/(S(9)*b*(d*tan(a + b*x))**(S(9)/2)) - S(2)*d/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(6)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*d**S(5)/(S(13)*b*(d*tan(a + b*x))**(S(13)/2)) - S(4)*d**S(3)/(S(9)*b*(d*tan(a + b*x))**(S(9)/2)) - S(2)*d/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/(d*tan(a + b*x))**(S(3)/2), x), x, EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(12)*b*d*sqrt(d*tan(a + b*x))) - sqrt(d*tan(a + b*x))*cos(a + b*x)**S(3)/(S(3)*b*d**S(2)) + sqrt(d*tan(a + b*x))*cos(a + b*x)/(S(6)*b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/(d*tan(a + b*x))**(S(3)/2), x), x, EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(2)*b*d*sqrt(d*tan(a + b*x))) + sqrt(d*tan(a + b*x))*cos(a + b*x)/(b*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*sec(a + b*x)/(S(3)*b*(d*tan(a + b*x))**(S(3)/2)) - EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(3)*b*d*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(3)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*d**S(2)*sec(a + b*x)/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)) - S(4)*sec(a + b*x)/(S(21)*b*(d*tan(a + b*x))**(S(3)/2)) - S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(21)*b*d*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(4)/(d*tan(a + b*x))**(S(5)/2), x), x, -sqrt(d*tan(a + b*x))*cos(a + b*x)**S(4)/(S(4)*b*d**S(3)) + sqrt(d*tan(a + b*x))*cos(a + b*x)**S(2)/(S(16)*b*d**S(3)) - S(3)*sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b*d**(S(5)/2)) + S(3)*sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(64)*b*d**(S(5)/2)) - S(3)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b*d**(S(5)/2)) + S(3)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(128)*b*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(2)/(d*tan(a + b*x))**(S(5)/2), x), x, sqrt(d*tan(a + b*x))*cos(a + b*x)**S(2)/(S(2)*b*d**S(3)) - S(3)*sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*d**(S(5)/2)) + S(3)*sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*d**(S(5)/2)) - S(3)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*d**(S(5)/2)) + S(3)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(2)/(d*tan(a + b*x))**(S(5)/2), x), x, -S(2)*d/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(4)/(d*tan(a + b*x))**(S(5)/2), x), x, -S(2)*d**S(3)/(S(11)*b*(d*tan(a + b*x))**(S(11)/2)) - S(2)*d/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(6)/(d*tan(a + b*x))**(S(5)/2), x), x, -S(2)*d**S(5)/(S(15)*b*(d*tan(a + b*x))**(S(15)/2)) - S(4)*d**S(3)/(S(11)*b*(d*tan(a + b*x))**(S(11)/2)) - S(2)*d/(S(7)*b*(d*tan(a + b*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(5)/(d*tan(a + b*x))**(S(5)/2), x), x, S(3)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(20)*b*d**S(3)*sqrt(sin(S(2)*a + S(2)*b*x))) - (d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(5)/(S(5)*b*d**S(4)) + (d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(3)/(S(10)*b*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)**S(3)/(d*tan(a + b*x))**(S(5)/2), x), x, sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(2)*b*d**S(3)*sqrt(sin(S(2)*a + S(2)*b*x))) + (d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(3)/(S(3)*b*d**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(a + b*x)/(d*tan(a + b*x))**(S(5)/2), x), x, -S(2)*cos(a + b*x)/(b*d**S(2)*sqrt(d*tan(a + b*x))) - S(3)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*d**S(3)*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)/(d*tan(a + b*x))**(S(5)/2), x), x, -S(2)*sec(a + b*x)/(S(5)*b*(d*tan(a + b*x))**(S(5)/2)) + S(6)*cos(a + b*x)/(S(5)*b*d**S(2)*sqrt(d*tan(a + b*x))) + S(6)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(5)*b*d**S(3)*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(csc(a + b*x)**S(3)/(d*tan(a + b*x))**(S(5)/2), x), x, -S(2)*d**S(2)*sec(a + b*x)/(S(9)*b*(d*tan(a + b*x))**(S(9)/2)) - S(4)*sec(a + b*x)/(S(45)*b*(d*tan(a + b*x))**(S(5)/2)) + S(4)*cos(a + b*x)/(S(15)*b*d**S(2)*sqrt(d*tan(a + b*x))) + S(4)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(15)*b*d**S(3)*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(3)/2), x), x, S(8)*b**S(2)*d*sqrt(d*tan(e + f*x))/(S(3)*f*sqrt(b*sin(e + f*x))) - S(2)*d*(b*sin(e + f*x))**(S(3)/2)*sqrt(d*tan(e + f*x))/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sin(x)**(S(5)/2)/tan(x)**(S(3)/2), x), x, -S(2)*sin(x)**(S(5)/2)/(S(5)*tan(x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(4)/3)*sqrt(d*tan(e + f*x)), x), x, S(6)*(b*sin(e + f*x))**(S(4)/3)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, S(17)/12, S(29)/12, sin(e + f*x)**S(2))/(S(17)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(1)/3)*sqrt(d*tan(e + f*x)), x), x, S(6)*(b*sin(e + f*x))**(S(1)/3)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, S(11)/12, S(23)/12, sin(e + f*x)**S(2))/(S(11)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))/(b*sin(e + f*x))**(S(1)/3), x), x, S(6)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(7)/12, S(3)/4, S(19)/12, sin(e + f*x)**S(2))/(S(7)*d*f*(b*sin(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))/(b*sin(e + f*x))**(S(4)/3), x), x, S(6)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(1)/12, S(3)/4, S(13)/12, sin(e + f*x)**S(2))/(d*f*(b*sin(e + f*x))**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(4)/3)*(d*tan(e + f*x))**(S(3)/2), x), x, S(6)*d*(b*sin(e + f*x))**(S(10)/3)*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, S(23)/12, S(35)/12, sin(e + f*x)**S(2))/(S(23)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(1)/3)*(d*tan(e + f*x))**(S(3)/2), x), x, S(6)*d*(b*sin(e + f*x))**(S(7)/3)*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, S(17)/12, S(29)/12, sin(e + f*x)**S(2))/(S(17)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(3)/2)/(b*sin(e + f*x))**(S(1)/3), x), x, S(6)*d*(b*sin(e + f*x))**(S(5)/3)*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(13)/12, S(5)/4, S(25)/12, sin(e + f*x)**S(2))/(S(13)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(3)/2)/(b*sin(e + f*x))**(S(4)/3), x), x, S(6)*d*(b*sin(e + f*x))**(S(2)/3)*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(7)/12, S(5)/4, S(19)/12, sin(e + f*x)**S(2))/(S(7)*b**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sin(e + f*x))*(d*tan(e + f*x))**(S(4)/3), x), x, S(6)*d*(b*sin(e + f*x))**(S(5)/2)*(d*tan(e + f*x))**(S(1)/3)*(cos(e + f*x)**S(2))**(S(1)/6)*Hypergeometric2F1(S(7)/6, S(17)/12, S(29)/12, sin(e + f*x)**S(2))/(S(17)*b**S(2)*f), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(b*sin(e + f*x))*(d*tan(e + f*x))**(S(4)/3), x), x, -S(3)*d*sqrt(b*sin(e + f*x))*(d*tan(e + f*x))**(S(1)/3)*(sec(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/12, S(5)/4, S(17)/12, -tan(e + f*x)**S(2))/f + S(3)*d*sqrt(b*sin(e + f*x))*(d*tan(e + f*x))**(S(1)/3)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sin(e + f*x))*(d*tan(e + f*x))**(S(1)/3), x), x, S(6)*sqrt(b*sin(e + f*x))*(d*tan(e + f*x))**(S(4)/3)*(cos(e + f*x)**S(2))**(S(2)/3)*Hypergeometric2F1(S(2)/3, S(11)/12, S(23)/12, sin(e + f*x)**S(2))/(S(11)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sin(e + f*x))/(d*tan(e + f*x))**(S(1)/3), x), x, S(6)*sqrt(b*sin(e + f*x))*(d*tan(e + f*x))**(S(2)/3)*(cos(e + f*x)**S(2))**(S(1)/3)*Hypergeometric2F1(S(1)/3, S(7)/12, S(19)/12, sin(e + f*x)**S(2))/(S(7)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sin(e + f*x))/(d*tan(e + f*x))**(S(4)/3), x), x, S(6)*sqrt(b*sin(e + f*x))*Hypergeometric2F1(S(-1)/6, S(1)/12, S(13)/12, sin(e + f*x)**S(2))/(d*f*(d*tan(e + f*x))**(S(1)/3)*(cos(e + f*x)**S(2))**(S(1)/6)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(b*sin(e + f*x))/(d*tan(e + f*x))**(S(4)/3), x), x, S(4)*sqrt(b*sin(e + f*x))*(sec(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(1)/12, S(1)/4, S(13)/12, -tan(e + f*x)**S(2))/(d*f*(d*tan(e + f*x))**(S(1)/3)) + S(2)*sqrt(b*sin(e + f*x))/(d*f*(d*tan(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(4)/3), x), x, S(6)*d*(b*sin(e + f*x))**(S(7)/2)*(d*tan(e + f*x))**(S(1)/3)*(cos(e + f*x)**S(2))**(S(1)/6)*Hypergeometric2F1(S(7)/6, S(23)/12, S(35)/12, sin(e + f*x)**S(2))/(S(23)*b**S(2)*f), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(4)/3), x), x, -S(3)*d*(b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(1)/3)*(sec(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(11)/12, S(7)/4, S(23)/12, -tan(e + f*x)**S(2))/f + S(3)*d*(b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(1)/3)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(1)/3), x), x, S(6)*(b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(4)/3)*(cos(e + f*x)**S(2))**(S(2)/3)*Hypergeometric2F1(S(2)/3, S(17)/12, S(29)/12, sin(e + f*x)**S(2))/(S(17)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(3)/2)/(d*tan(e + f*x))**(S(1)/3), x), x, S(6)*(b*sin(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(2)/3)*(cos(e + f*x)**S(2))**(S(1)/3)*Hypergeometric2F1(S(1)/3, S(13)/12, S(25)/12, sin(e + f*x)**S(2))/(S(13)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**(S(3)/2)/(d*tan(e + f*x))**(S(4)/3), x), x, S(6)*(b*sin(e + f*x))**(S(3)/2)*Hypergeometric2F1(S(-1)/6, S(7)/12, S(19)/12, sin(e + f*x)**S(2))/(S(7)*d*f*(d*tan(e + f*x))**(S(1)/3)*(cos(e + f*x)**S(2))**(S(1)/6)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((b*sin(e + f*x))**(S(3)/2)/(d*tan(e + f*x))**(S(4)/3), x), x, S(4)*(b*sin(e + f*x))**(S(3)/2)*(sec(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(7)/12, S(3)/4, S(19)/12, -tan(e + f*x)**S(2))/(S(21)*d*f*(d*tan(e + f*x))**(S(1)/3)) + S(2)*(b*sin(e + f*x))**(S(3)/2)/(S(3)*d*f*(d*tan(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*tan(e + f*x)**S(3), x), x, (b*sin(e + f*x))**(m + S(4))*Hypergeometric2F1(S(2), m/S(2) + S(2), m/S(2) + S(3), sin(e + f*x)**S(2))/(b**S(4)*f*(m + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*tan(e + f*x), x), x, (b*sin(e + f*x))**(m + S(2))*Hypergeometric2F1(S(1), m/S(2) + S(1), m/S(2) + S(2), sin(e + f*x)**S(2))/(b**S(2)*f*(m + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*cot(e + f*x), x), x, (b*sin(e + f*x))**m/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*cot(e + f*x)**S(3), x), x, -b**S(2)*(b*sin(e + f*x))**(m + S(-2))/(f*(-m + S(2))) - (b*sin(e + f*x))**m/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*cot(e + f*x)**S(5), x), x, -b**S(4)*(b*sin(e + f*x))**(m + S(-4))/(f*(-m + S(4))) + S(2)*b**S(2)*(b*sin(e + f*x))**(m + S(-2))/(f*(-m + S(2))) + (b*sin(e + f*x))**m/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*tan(e + f*x)**S(4), x), x, (b*sin(e + f*x))**(m + S(5))*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(5)/2, m/S(2) + S(5)/2, m/S(2) + S(7)/2, sin(e + f*x)**S(2))*sec(e + f*x)/(b**S(5)*f*(m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*tan(e + f*x)**S(2), x), x, (b*sin(e + f*x))**(m + S(3))*sqrt(cos(e + f*x)**S(2))*Hypergeometric2F1(S(3)/2, m/S(2) + S(3)/2, m/S(2) + S(5)/2, sin(e + f*x)**S(2))*sec(e + f*x)/(b**S(3)*f*(m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*cot(e + f*x)**S(2), x), x, -b*(b*sin(e + f*x))**(m + S(-1))*Hypergeometric2F1(S(-1)/2, m/S(2) + S(-1)/2, m/S(2) + S(1)/2, sin(e + f*x)**S(2))*cos(e + f*x)/(f*(-m + S(1))*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*cot(e + f*x)**S(4), x), x, -b**S(3)*(b*sin(e + f*x))**(m + S(-3))*Hypergeometric2F1(S(-3)/2, m/S(2) + S(-3)/2, m/S(2) + S(-1)/2, sin(e + f*x)**S(2))*cos(e + f*x)/(f*(-m + S(3))*sqrt(cos(e + f*x)**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*(d*tan(e + f*x))**(S(3)/2), x), x, S(2)*d*(b*sin(e + f*x))**(m + S(2))*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, m/S(2) + S(5)/4, m/S(2) + S(9)/4, sin(e + f*x)**S(2))/(b**S(2)*f*(S(2)*m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m*sqrt(d*tan(e + f*x)), x), x, S(2)*(b*sin(e + f*x))**m*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, m/S(2) + S(3)/4, m/S(2) + S(7)/4, sin(e + f*x)**S(2))/(d*f*(S(2)*m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m/sqrt(d*tan(e + f*x)), x), x, S(2)*(b*sin(e + f*x))**m*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(1)/4, m/S(2) + S(1)/4, m/S(2) + S(5)/4, sin(e + f*x)**S(2))/(d*f*(S(2)*m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sin(e + f*x))**m/(d*tan(e + f*x))**(S(3)/2), x), x, -S(2)*(b*sin(e + f*x))**m*Hypergeometric2F1(S(-1)/4, m/S(2) + S(-1)/4, m/S(2) + S(3)/4, sin(e + f*x)**S(2))/(d*f*sqrt(d*tan(e + f*x))*(-S(2)*m + S(1))*(cos(e + f*x)**S(2))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sin(e + f*x))**m*(b*tan(e + f*x))**n, x), x, (a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, m/S(2) + n/S(2) + S(1)/2, m/S(2) + n/S(2) + S(3)/2, sin(e + f*x)**S(2))/(b*f*(m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*sin(e + f*x)**S(4), x), x, (b*tan(e + f*x))**(n + S(5))*Hypergeometric2F1(S(3), n/S(2) + S(5)/2, n/S(2) + S(7)/2, -tan(e + f*x)**S(2))/(b**S(5)*f*(n + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*sin(e + f*x)**S(2), x), x, (b*tan(e + f*x))**(n + S(3))*Hypergeometric2F1(S(2), n/S(2) + S(3)/2, n/S(2) + S(5)/2, -tan(e + f*x)**S(2))/(b**S(3)*f*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*csc(e + f*x)**S(2), x), x, -b*(b*tan(e + f*x))**(n + S(-1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*csc(e + f*x)**S(4), x), x, -b**S(3)*(b*tan(e + f*x))**(n + S(-3))/(f*(-n + S(3))) - b*(b*tan(e + f*x))**(n + S(-1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*csc(e + f*x)**S(6), x), x, -b**S(5)*(b*tan(e + f*x))**(n + S(-5))/(f*(-n + S(5))) - S(2)*b**S(3)*(b*tan(e + f*x))**(n + S(-3))/(f*(-n + S(3))) - b*(b*tan(e + f*x))**(n + S(-1))/(f*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*sin(e + f*x)**S(3), x), x, (b*tan(e + f*x))**(n + S(4))*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, n/S(2) + S(2), n/S(2) + S(3), sin(e + f*x)**S(2))*cos(e + f*x)**S(3)/(b**S(4)*f*(n + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*sin(e + f*x), x), x, (b*tan(e + f*x))**(n + S(2))*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, n/S(2) + S(1), n/S(2) + S(2), sin(e + f*x)**S(2))*cos(e + f*x)/(b**S(2)*f*(n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*csc(e + f*x), x), x, (b*tan(e + f*x))**n*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2), n/S(2) + S(1)/2, n/S(2) + S(1), sin(e + f*x)**S(2))*sec(e + f*x)/(f*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*csc(e + f*x)**S(3), x), x, -b**S(2)*(b*tan(e + f*x))**(n + S(-2))*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(-1), n/S(2) + S(1)/2, n/S(2), sin(e + f*x)**S(2))*sec(e + f*x)**S(3)/(f*(-n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*cos(e + f*x))**m*(b*tan(e + f*x))**n, x), x, (a*cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))*(cos(e + f*x)**S(2))**(-m/S(2) + n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, -m/S(2) + n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(e + f*x)**S(2))/(b*f*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*tan(e + f*x))**m*(b*tan(e + f*x))**n, x), x, (a*tan(e + f*x))**(m + S(1))*(b*tan(e + f*x))**n*Hypergeometric2F1(S(1), m/S(2) + n/S(2) + S(1)/2, m/S(2) + n/S(2) + S(3)/2, -tan(e + f*x)**S(2))/(a*f*(m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x))*tan(e + f*x)**S(4), x), x, sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*d**S(3)/(S(5)*f*(d*cot(e + f*x))**(S(5)/2)) - S(2)*d/(f*sqrt(d*cot(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x))*tan(e + f*x)**S(3), x), x, -sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*d**S(2)/(S(3)*f*(d*cot(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x))*tan(e + f*x)**S(2), x), x, -sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*d/(f*sqrt(d*cot(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x))*tan(e + f*x), x), x, sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x)), x), x, sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x))*cot(e + f*x), x), x, -sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - S(2)*sqrt(d*cot(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x))*cot(e + f*x)**S(2), x), x, -sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - S(2)*(d*cot(e + f*x))**(S(3)/2)/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*cot(e + f*x))*cot(e + f*x)**S(3), x), x, sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*sqrt(d*cot(e + f*x))/f - S(2)*(d*cot(e + f*x))**(S(5)/2)/(S(5)*d**S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2)*tan(e + f*x)**S(5), x), x, sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*d**S(4)/(S(5)*f*(d*cot(e + f*x))**(S(5)/2)) - S(2)*d**S(2)/(f*sqrt(d*cot(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2)*tan(e + f*x)**S(4), x), x, -sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*d**S(3)/(S(3)*f*(d*cot(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2)*tan(e + f*x)**S(3), x), x, -sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*d**S(2)/(f*sqrt(d*cot(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2)*tan(e + f*x)**S(2), x), x, sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2)*tan(e + f*x), x), x, sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2), x), x, -sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - S(2)*d*sqrt(d*cot(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2)*cot(e + f*x), x), x, -sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - S(2)*(d*cot(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(3)/2)*cot(e + f*x)**S(2), x), x, sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*f) + S(2)*d*sqrt(d*cot(e + f*x))/f - S(2)*(d*cot(e + f*x))**(S(5)/2)/(S(5)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(3)/sqrt(d*cot(e + f*x)), x), x, S(2)*d**S(2)/(S(5)*f*(d*cot(e + f*x))**(S(5)/2)) - S(2)/(f*sqrt(d*cot(e + f*x))) + sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)/sqrt(d*cot(e + f*x)), x), x, S(2)*d/(S(3)*f*(d*cot(e + f*x))**(S(3)/2)) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)/sqrt(d*cot(e + f*x)), x), x, S(2)/(f*sqrt(d*cot(e + f*x))) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(d*cot(e + f*x)), x), x, sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)/sqrt(d*cot(e + f*x)), x), x, sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)**S(2)/sqrt(d*cot(e + f*x)), x), x, -S(2)*sqrt(d*cot(e + f*x))/(d*f) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)**S(3)/sqrt(d*cot(e + f*x)), x), x, -S(2)*(d*cot(e + f*x))**(S(3)/2)/(S(3)*d**S(2)*f) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*sqrt(d)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*sqrt(d)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)/(d*cot(e + f*x))**(S(3)/2), x), x, S(2)*d/(S(5)*f*(d*cot(e + f*x))**(S(5)/2)) - S(2)/(d*f*sqrt(d*cot(e + f*x))) + sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)/(d*cot(e + f*x))**(S(3)/2), x), x, S(2)/(S(3)*f*(d*cot(e + f*x))**(S(3)/2)) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*cot(e + f*x))**(S(-3)/2), x), x, S(2)/(d*f*sqrt(d*cot(e + f*x))) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)/(d*cot(e + f*x))**(S(3)/2), x), x, sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)**S(2)/(d*cot(e + f*x))**(S(3)/2), x), x, sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)**S(3)/(d*cot(e + f*x))**(S(3)/2), x), x, -S(2)*sqrt(d*cot(e + f*x))/(d**S(2)*f) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)**S(4)/(d*cot(e + f*x))**(S(3)/2), x), x, -S(2)*(d*cot(e + f*x))**(S(3)/2)/(S(3)*d**S(3)*f) - sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cot(e + f*x)**S(5)/(d*cot(e + f*x))**(S(3)/2), x), x, S(2)*sqrt(d*cot(e + f*x))/(d**S(2)*f) - S(2)*(d*cot(e + f*x))**(S(5)/2)/(S(5)*d**S(4)*f) + sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*cot(e + f*x))/sqrt(d))/(S(2)*d**(S(3)/2)*f) + sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f) - sqrt(S(2))*log(sqrt(d)*cot(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*cot(e + f*x)))/(S(4)*d**(S(3)/2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**n*cot(e + f*x)**m, x), x, Hypergeometric2F1(S(1), -m/S(2) + n/S(2) + S(1)/2, -m/S(2) + n/S(2) + S(3)/2, -tan(e + f*x)**S(2))*tan(e + f*x)**(n + S(1))*cot(e + f*x)**m/(f*(-m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**n*cot(e + f*x)**m, x), x, (b*tan(e + f*x))**(n + S(1))*Hypergeometric2F1(S(1), -m/S(2) + n/S(2) + S(1)/2, -m/S(2) + n/S(2) + S(3)/2, -tan(e + f*x)**S(2))*cot(e + f*x)**m/(b*f*(-m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*cot(e + f*x))**m*tan(e + f*x)**n, x), x, (a*cot(e + f*x))**m*Hypergeometric2F1(S(1), -m/S(2) + n/S(2) + S(1)/2, -m/S(2) + n/S(2) + S(3)/2, -tan(e + f*x)**S(2))*tan(e + f*x)**(n + S(1))/(f*(-m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*cot(e + f*x))**m*(b*tan(e + f*x))**n, x), x, (a*cot(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))*Hypergeometric2F1(S(1), -m/S(2) + n/S(2) + S(1)/2, -m/S(2) + n/S(2) + S(3)/2, -tan(e + f*x)**S(2))/(b*f*(-m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*sec(e + f*x)**S(6), x), x, S(2)*(d*tan(e + f*x))**(S(3)/2)/(S(3)*d*f) + S(4)*(d*tan(e + f*x))**(S(7)/2)/(S(7)*d**S(3)*f) + S(2)*(d*tan(e + f*x))**(S(11)/2)/(S(11)*d**S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*sec(e + f*x)**S(4), x), x, S(2)*(d*tan(e + f*x))**(S(3)/2)/(S(3)*d*f) + S(2)*(d*tan(e + f*x))**(S(7)/2)/(S(7)*d**S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*sec(e + f*x)**S(2), x), x, S(2)*(d*tan(e + f*x))**(S(3)/2)/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x)), x), x, -sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(2)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(4)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*cos(e + f*x)**S(2), x), x, -sqrt(S(2))*sqrt(d)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(8)*f) + sqrt(S(2))*sqrt(d)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(8)*f) + sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(16)*f) - sqrt(S(2))*sqrt(d)*log(sqrt(d)*tan(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(16)*f) + (d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)**S(2)/(S(2)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*sec(e + f*x)**S(3), x), x, -S(4)*sqrt(d*tan(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*cos(e + f*x)/(S(5)*f*sqrt(sin(S(2)*e + S(2)*f*x))) + S(4)*(d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)/(S(5)*d*f) + S(2)*(d*tan(e + f*x))**(S(3)/2)*sec(e + f*x)/(S(5)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*sec(e + f*x), x), x, -S(2)*sqrt(d*tan(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*cos(e + f*x)/(f*sqrt(sin(S(2)*e + S(2)*f*x))) + S(2)*(d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)/(d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*cos(e + f*x), x), x, sqrt(d*tan(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*cos(e + f*x)/(f*sqrt(sin(S(2)*e + S(2)*f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*cos(e + f*x)**S(3), x), x, sqrt(d*tan(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*cos(e + f*x)/(S(2)*f*sqrt(sin(S(2)*e + S(2)*f*x))) + (d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)**S(3)/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))*cos(e + f*x)**S(5), x), x, S(7)*sqrt(d*tan(e + f*x))*EllipticE(-Pi/S(4) + e + f*x, S(2))*cos(e + f*x)/(S(20)*f*sqrt(sin(S(2)*e + S(2)*f*x))) + (d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)**S(5)/(S(5)*d*f) + S(7)*(d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)**S(3)/(S(30)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sec(a + b*x)**S(6), x), x, S(2)*(d*tan(a + b*x))**(S(5)/2)/(S(5)*b*d) + S(4)*(d*tan(a + b*x))**(S(9)/2)/(S(9)*b*d**S(3)) + S(2)*(d*tan(a + b*x))**(S(13)/2)/(S(13)*b*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sec(a + b*x)**S(4), x), x, S(2)*(d*tan(a + b*x))**(S(5)/2)/(S(5)*b*d) + S(2)*(d*tan(a + b*x))**(S(9)/2)/(S(9)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sec(a + b*x)**S(2), x), x, S(2)*(d*tan(a + b*x))**(S(5)/2)/(S(5)*b*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2), x), x, sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(2)*b) - sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(2)*b) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(4)*b) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(4)*b) + S(2)*d*sqrt(d*tan(a + b*x))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(2), x), x, -sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) + sqrt(S(2))*d**(S(3)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b) - sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b) - d*sqrt(d*tan(a + b*x))*cos(a + b*x)**S(2)/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sec(a + b*x)**S(5), x), x, -S(4)*d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(77)*b*sqrt(d*tan(a + b*x))) + S(2)*d*sqrt(d*tan(a + b*x))*sec(a + b*x)**S(5)/(S(11)*b) - S(2)*d*sqrt(d*tan(a + b*x))*sec(a + b*x)**S(3)/(S(77)*b) - S(4)*d*sqrt(d*tan(a + b*x))*sec(a + b*x)/(S(77)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sec(a + b*x)**S(3), x), x, -S(2)*d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(21)*b*sqrt(d*tan(a + b*x))) + S(2)*d*sqrt(d*tan(a + b*x))*sec(a + b*x)**S(3)/(S(7)*b) - S(2)*d*sqrt(d*tan(a + b*x))*sec(a + b*x)/(S(21)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*sec(a + b*x), x), x, -d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(3)*b*sqrt(d*tan(a + b*x))) + S(2)*d*sqrt(d*tan(a + b*x))*sec(a + b*x)/(S(3)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*cos(a + b*x), x), x, d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(2)*b*sqrt(d*tan(a + b*x))) - d*sqrt(d*tan(a + b*x))*cos(a + b*x)/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(3), x), x, d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(12)*b*sqrt(d*tan(a + b*x))) - d*sqrt(d*tan(a + b*x))*cos(a + b*x)**S(3)/(S(3)*b) + d*sqrt(d*tan(a + b*x))*cos(a + b*x)/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(5), x), x, d**S(2)*EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(24)*b*sqrt(d*tan(a + b*x))) - d*sqrt(d*tan(a + b*x))*cos(a + b*x)**S(5)/(S(5)*b) + d*sqrt(d*tan(a + b*x))*cos(a + b*x)**S(3)/(S(30)*b) + d*sqrt(d*tan(a + b*x))*cos(a + b*x)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(5)/2)*sec(e + f*x)**S(6), x), x, S(2)*(d*tan(e + f*x))**(S(7)/2)/(S(7)*d*f) + S(4)*(d*tan(e + f*x))**(S(11)/2)/(S(11)*d**S(3)*f) + S(2)*(d*tan(e + f*x))**(S(15)/2)/(S(15)*d**S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(5)/2)*sec(e + f*x)**S(4), x), x, S(2)*(d*tan(e + f*x))**(S(7)/2)/(S(7)*d*f) + S(2)*(d*tan(e + f*x))**(S(11)/2)/(S(11)*d**S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(5)/2)*sec(e + f*x)**S(2), x), x, S(2)*(d*tan(e + f*x))**(S(7)/2)/(S(7)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(5)/2), x), x, sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(2)*f) - sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(4)*f) + sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(4)*f) + S(2)*d*(d*tan(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(5)/2)*cos(e + f*x)**S(2), x), x, -S(3)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(8)*f) + S(3)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(8)*f) + S(3)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(16)*f) - S(3)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(16)*f) - d*(d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)**S(2)/(S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(5)/2)*cos(e + f*x)**S(4), x), x, -S(3)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(64)*f) + S(3)*sqrt(S(2))*d**(S(5)/2)*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(e + f*x))/sqrt(d))/(S(64)*f) + S(3)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(e + f*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(128)*f) - S(3)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(d)*tan(e + f*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(e + f*x)))/(S(128)*f) - d*(d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)**S(4)/(S(4)*f) + S(3)*d*(d*tan(e + f*x))**(S(3)/2)*cos(e + f*x)**S(2)/(S(16)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(e + f*x)**S(5)/sqrt(d*tan(e + f*x)), x), x, S(4)*EllipticF(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(S(2)*e + S(2)*f*x))*sec(e + f*x)/(S(7)*f*sqrt(d*tan(e + f*x))) + S(2)*sqrt(d*tan(e + f*x))*sec(e + f*x)**S(3)/(S(7)*d*f) + S(4)*sqrt(d*tan(e + f*x))*sec(e + f*x)/(S(7)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(e + f*x)**S(3)/sqrt(d*tan(e + f*x)), x), x, S(2)*EllipticF(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(S(2)*e + S(2)*f*x))*sec(e + f*x)/(S(3)*f*sqrt(d*tan(e + f*x))) + S(2)*sqrt(d*tan(e + f*x))*sec(e + f*x)/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(e + f*x)/sqrt(d*tan(e + f*x)), x), x, EllipticF(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(S(2)*e + S(2)*f*x))*sec(e + f*x)/(f*sqrt(d*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(e + f*x)/sqrt(d*tan(e + f*x)), x), x, EllipticF(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(S(2)*e + S(2)*f*x))*sec(e + f*x)/(S(2)*f*sqrt(d*tan(e + f*x))) + sqrt(d*tan(e + f*x))*cos(e + f*x)/(d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(e + f*x)**S(3)/sqrt(d*tan(e + f*x)), x), x, S(5)*EllipticF(-Pi/S(4) + e + f*x, S(2))*sqrt(sin(S(2)*e + S(2)*f*x))*sec(e + f*x)/(S(12)*f*sqrt(d*tan(e + f*x))) + sqrt(d*tan(e + f*x))*cos(e + f*x)**S(3)/(S(3)*d*f) + S(5)*sqrt(d*tan(e + f*x))*cos(e + f*x)/(S(6)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(6)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)/(b*d*sqrt(d*tan(a + b*x))) + S(4)*(d*tan(a + b*x))**(S(3)/2)/(S(3)*b*d**S(3)) + S(2)*(d*tan(a + b*x))**(S(7)/2)/(S(7)*b*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(4)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)/(b*d*sqrt(d*tan(a + b*x))) + S(2)*(d*tan(a + b*x))**(S(3)/2)/(S(3)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(2)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)/(b*d*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**(S(-3)/2), x), x, -S(2)/(b*d*sqrt(d*tan(a + b*x))) + sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(2)*b*d**(S(3)/2)) - sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(2)*b*d**(S(3)/2)) - sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(4)*b*d**(S(3)/2)) + sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(4)*b*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(2)/(d*tan(a + b*x))**(S(3)/2), x), x, cos(a + b*x)**S(2)/(S(2)*b*d*sqrt(d*tan(a + b*x))) - S(5)/(S(2)*b*d*sqrt(d*tan(a + b*x))) + S(5)*sqrt(S(2))*ArcTan(S(1) - sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*d**(S(3)/2)) - S(5)*sqrt(S(2))*ArcTan(S(1) + sqrt(S(2))*sqrt(d*tan(a + b*x))/sqrt(d))/(S(8)*b*d**(S(3)/2)) - S(5)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) - sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*d**(S(3)/2)) + S(5)*sqrt(S(2))*log(sqrt(d)*tan(a + b*x) + sqrt(d) + sqrt(S(2))*sqrt(d*tan(a + b*x)))/(S(16)*b*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(5)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*sec(a + b*x)**S(3)/(b*d*sqrt(d*tan(a + b*x))) - S(24)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(5)*b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))) + S(24)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)/(S(5)*b*d**S(3)) + S(12)*(d*tan(a + b*x))**(S(3)/2)*sec(a + b*x)/(S(5)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*sec(a + b*x)/(b*d*sqrt(d*tan(a + b*x))) - S(4)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))) + S(4)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)/(b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*cos(a + b*x)/(b*d*sqrt(d*tan(a + b*x))) - S(2)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*cos(a + b*x)/(b*d*sqrt(d*tan(a + b*x))) - S(3)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(3)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*cos(a + b*x)**S(3)/(b*d*sqrt(d*tan(a + b*x))) - S(7)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(2)*b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))) - S(7)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(3)/(S(3)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(cos(a + b*x)**S(5)/(d*tan(a + b*x))**(S(3)/2), x), x, -S(2)*cos(a + b*x)**S(5)/(b*d*sqrt(d*tan(a + b*x))) - S(77)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(20)*b*d**S(2)*sqrt(sin(S(2)*a + S(2)*b*x))) - S(11)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(5)/(S(5)*b*d**S(3)) - S(77)*(d*tan(a + b*x))**(S(3)/2)*cos(a + b*x)**S(3)/(S(30)*b*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)/(d*tan(a + b*x))**(S(5)/2), x), x, -S(2)*sec(a + b*x)/(S(3)*b*d*(d*tan(a + b*x))**(S(3)/2)) - EllipticF(-Pi/S(4) + a + b*x, S(2))*sqrt(sin(S(2)*a + S(2)*b*x))*sec(a + b*x)/(S(3)*b*d**S(2)*sqrt(d*tan(a + b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sec(a + b*x)**S(3)/(d*tan(a + b*x))**(S(7)/2), x), x, -S(2)*sec(a + b*x)/(S(5)*b*d*(d*tan(a + b*x))**(S(5)/2)) - S(4)*cos(a + b*x)/(S(5)*b*d**S(3)*sqrt(d*tan(a + b*x))) - S(4)*sqrt(d*tan(a + b*x))*EllipticE(-Pi/S(4) + a + b*x, S(2))*cos(a + b*x)/(S(5)*b*d**S(4)*sqrt(sin(S(2)*a + S(2)*b*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)*sec(e + f*x)**(S(4)/3), x), x, (cos(e + f*x)**S(2))**(S(1)/6)*Hypergeometric2F1(S(3)/2, S(13)/6, S(5)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(3)*sec(e + f*x)**(S(1)/3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)*sec(e + f*x)**(S(2)/3), x), x, (cos(e + f*x)**S(2))**(S(5)/6)*Hypergeometric2F1(S(3)/2, S(11)/6, S(5)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(3)*sec(e + f*x)**(S(5)/3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)*sec(e + f*x)**(S(1)/3), x), x, (cos(e + f*x)**S(2))**(S(2)/3)*Hypergeometric2F1(S(3)/2, S(5)/3, S(5)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(3)*sec(e + f*x)**(S(4)/3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)/sec(e + f*x)**(S(1)/3), x), x, (cos(e + f*x)**S(2))**(S(1)/3)*Hypergeometric2F1(S(4)/3, S(3)/2, S(5)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(3)*sec(e + f*x)**(S(2)/3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)/sec(e + f*x)**(S(2)/3), x), x, (cos(e + f*x)**S(2))**(S(1)/6)*Hypergeometric2F1(S(7)/6, S(3)/2, S(5)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(3)*sec(e + f*x)**(S(1)/3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(4)*sec(e + f*x)**(S(4)/3), x), x, (cos(e + f*x)**S(2))**(S(1)/6)*Hypergeometric2F1(S(5)/2, S(19)/6, S(7)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(5)*sec(e + f*x)**(S(1)/3)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(4)*sec(e + f*x)**(S(2)/3), x), x, (cos(e + f*x)**S(2))**(S(5)/6)*Hypergeometric2F1(S(5)/2, S(17)/6, S(7)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(5)*sec(e + f*x)**(S(5)/3)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(4)*sec(e + f*x)**(S(1)/3), x), x, (cos(e + f*x)**S(2))**(S(2)/3)*Hypergeometric2F1(S(5)/2, S(8)/3, S(7)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(5)*sec(e + f*x)**(S(4)/3)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(4)/sec(e + f*x)**(S(1)/3), x), x, (cos(e + f*x)**S(2))**(S(1)/3)*Hypergeometric2F1(S(7)/3, S(5)/2, S(7)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(5)*sec(e + f*x)**(S(2)/3)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(4)/sec(e + f*x)**(S(2)/3), x), x, (cos(e + f*x)**S(2))**(S(1)/6)*Hypergeometric2F1(S(13)/6, S(5)/2, S(7)/2, sin(e + f*x)**S(2))*sin(e + f*x)**S(5)*sec(e + f*x)**(S(1)/3)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(4)/3)*tan(e + f*x)**S(2), x), x, (d*sec(e + f*x))**(S(4)/3)*(cos(e + f*x)**S(2))**(S(13)/6)*Hypergeometric2F1(S(3)/2, S(13)/6, S(5)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(2)/3)*tan(e + f*x)**S(2), x), x, (d*sec(e + f*x))**(S(2)/3)*(cos(e + f*x)**S(2))**(S(11)/6)*Hypergeometric2F1(S(3)/2, S(11)/6, S(5)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(1)/3)*tan(e + f*x)**S(2), x), x, (d*sec(e + f*x))**(S(1)/3)*(cos(e + f*x)**S(2))**(S(5)/3)*Hypergeometric2F1(S(3)/2, S(5)/3, S(5)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)/(d*sec(e + f*x))**(S(1)/3), x), x, (cos(e + f*x)**S(2))**(S(4)/3)*Hypergeometric2F1(S(4)/3, S(3)/2, S(5)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(3)/(S(3)*f*(d*sec(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(2)/(d*sec(e + f*x))**(S(2)/3), x), x, (cos(e + f*x)**S(2))**(S(7)/6)*Hypergeometric2F1(S(7)/6, S(3)/2, S(5)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(3)/(S(3)*f*(d*sec(e + f*x))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(4)/3)*tan(e + f*x)**S(4), x), x, (d*sec(e + f*x))**(S(4)/3)*(cos(e + f*x)**S(2))**(S(19)/6)*Hypergeometric2F1(S(5)/2, S(19)/6, S(7)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(5)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(2)/3)*tan(e + f*x)**S(4), x), x, (d*sec(e + f*x))**(S(2)/3)*(cos(e + f*x)**S(2))**(S(17)/6)*Hypergeometric2F1(S(5)/2, S(17)/6, S(7)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(5)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(1)/3)*tan(e + f*x)**S(4), x), x, (d*sec(e + f*x))**(S(1)/3)*(cos(e + f*x)**S(2))**(S(8)/3)*Hypergeometric2F1(S(5)/2, S(8)/3, S(7)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(5)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(4)/(d*sec(e + f*x))**(S(1)/3), x), x, (cos(e + f*x)**S(2))**(S(7)/3)*Hypergeometric2F1(S(7)/3, S(5)/2, S(7)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(5)/(S(5)*f*(d*sec(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(tan(e + f*x)**S(4)/(d*sec(e + f*x))**(S(2)/3), x), x, (cos(e + f*x)**S(2))**(S(13)/6)*Hypergeometric2F1(S(13)/6, S(5)/2, S(7)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(5)/(S(5)*f*(d*sec(e + f*x))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(5)/2), x), x, -sqrt(b)*d**S(3)*sqrt(b*tan(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) + sqrt(b)*d**S(3)*sqrt(b*tan(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) + d**S(2)*(b*tan(e + f*x))**(S(3)/2)*sqrt(d*sec(e + f*x))/(S(2)*b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(3)/2), x), x, -d**S(2)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) + d**S(2)*(b*tan(e + f*x))**(S(3)/2)/(b*f*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))*sqrt(d*sec(e + f*x)), x), x, -sqrt(b)*d*sqrt(b*tan(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) + sqrt(b)*d*sqrt(b*tan(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))/sqrt(d*sec(e + f*x)), x), x, S(2)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))/(d*sec(e + f*x))**(S(3)/2), x), x, S(2)*(b*tan(e + f*x))**(S(3)/2)/(S(3)*b*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))/(d*sec(e + f*x))**(S(5)/2), x), x, S(4)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*d**S(2)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) + S(2)*(b*tan(e + f*x))**(S(3)/2)/(S(5)*b*f*(d*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))/(d*sec(e + f*x))**(S(7)/2), x), x, S(2)*(b*tan(e + f*x))**(S(3)/2)/(S(7)*b*f*(d*sec(e + f*x))**(S(7)/2)) + S(8)*(b*tan(e + f*x))**(S(3)/2)/(S(21)*b*d**S(2)*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*tan(e + f*x))/(d*sec(e + f*x))**(S(9)/2), x), x, S(8)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(15)*d**S(4)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) + S(2)*(b*tan(e + f*x))**(S(3)/2)/(S(9)*b*f*(d*sec(e + f*x))**(S(9)/2)) + S(4)*(b*tan(e + f*x))**(S(3)/2)/(S(15)*b*d**S(2)*f*(d*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(5)/2), x), x, -b**S(2)*d**S(2)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(6)*f*sqrt(b*tan(e + f*x))) - b*d**S(2)*sqrt(b*tan(e + f*x))*sqrt(d*sec(e + f*x))/(S(6)*f) + b*sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(5)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(3)/2), x), x, -b**(S(3)/2)*d*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*f*sqrt(b*tan(e + f*x))) - b**(S(3)/2)*d*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*f*sqrt(b*tan(e + f*x))) + b*sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(3)/2)/(S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)*sqrt(d*sec(e + f*x)), x), x, -b**S(2)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(f*sqrt(b*tan(e + f*x))) + b*sqrt(b*tan(e + f*x))*sqrt(d*sec(e + f*x))/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)/sqrt(d*sec(e + f*x)), x), x, b**(S(3)/2)*d*(b*tan(e + f*x))**(S(3)/2)*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(f*(b*sin(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(3)/2)) + b**(S(3)/2)*d*(b*tan(e + f*x))**(S(3)/2)*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(f*(b*sin(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(3)/2)) - S(2)*d*(b*tan(e + f*x))**(S(3)/2)*csc(e + f*x)/(f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)/(d*sec(e + f*x))**(S(3)/2), x), x, S(2)*b**S(2)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*d**S(2)*f*sqrt(b*tan(e + f*x))) - S(2)*b*sqrt(b*tan(e + f*x))/(S(3)*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)/(d*sec(e + f*x))**(S(5)/2), x), x, S(2)*(b*tan(e + f*x))**(S(5)/2)/(S(5)*b*f*(d*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)/(d*sec(e + f*x))**(S(7)/2), x), x, S(4)*b**S(2)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(21)*d**S(4)*f*sqrt(b*tan(e + f*x))) - S(2)*b*sqrt(b*tan(e + f*x))/(S(7)*f*(d*sec(e + f*x))**(S(7)/2)) + S(2)*b*sqrt(b*tan(e + f*x))/(S(21)*d**S(2)*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(3)/2)/(d*sec(e + f*x))**(S(9)/2), x), x, -S(2)*b*sqrt(b*tan(e + f*x))/(S(9)*f*(d*sec(e + f*x))**(S(9)/2)) + S(2)*b*sqrt(b*tan(e + f*x))/(S(45)*d**S(2)*f*(d*sec(e + f*x))**(S(5)/2)) + S(8)*b*sqrt(b*tan(e + f*x))/(S(45)*d**S(4)*f*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)*(d*sec(e + f*x))**(S(5)/2), x), x, S(3)*b**(S(5)/2)*d**S(3)*sqrt(b*tan(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(S(32)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) - S(3)*b**(S(5)/2)*d**S(3)*sqrt(b*tan(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(S(32)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) - S(3)*b*d**S(2)*(b*tan(e + f*x))**(S(3)/2)*sqrt(d*sec(e + f*x))/(S(16)*f) + b*(b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(5)/2)/(S(4)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)*(d*sec(e + f*x))**(S(3)/2), x), x, b**S(2)*d**S(2)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(2)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) - b*d**S(2)*(b*tan(e + f*x))**(S(3)/2)/(S(2)*f*sqrt(d*sec(e + f*x))) + b*(b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(3)/2)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)*sqrt(d*sec(e + f*x)), x), x, S(3)*b**(S(5)/2)*d*sqrt(b*tan(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) - S(3)*b**(S(5)/2)*d*sqrt(b*tan(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) + b*(b*tan(e + f*x))**(S(3)/2)*sqrt(d*sec(e + f*x))/(S(2)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)/sqrt(d*sec(e + f*x)), x), x, -S(3)*b**S(2)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) + b*(b*tan(e + f*x))**(S(3)/2)/(f*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)/(d*sec(e + f*x))**(S(3)/2), x), x, -b**(S(5)/2)*sqrt(b*tan(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(d*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) + b**(S(5)/2)*sqrt(b*tan(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(d*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) - S(2)*b*(b*tan(e + f*x))**(S(3)/2)/(S(3)*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)/(d*sec(e + f*x))**(S(5)/2), x), x, S(6)*b**S(2)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*d**S(2)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) - S(2)*b*(b*tan(e + f*x))**(S(3)/2)/(S(5)*f*(d*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)/(d*sec(e + f*x))**(S(7)/2), x), x, S(2)*(b*tan(e + f*x))**(S(7)/2)/(S(7)*b*f*(d*sec(e + f*x))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*tan(e + f*x))**(S(5)/2)/(d*sec(e + f*x))**(S(9)/2), x), x, S(4)*b**S(2)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(15)*d**S(4)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) - S(2)*b*(b*tan(e + f*x))**(S(3)/2)/(S(9)*f*(d*sec(e + f*x))**(S(9)/2)) + S(2)*b*(b*tan(e + f*x))**(S(3)/2)/(S(15)*d**S(2)*f*(d*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(7)/2)/sqrt(b*tan(e + f*x)), x), x, d**S(2)*sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(3)/2)/(S(2)*b*f) + S(3)*d**S(3)*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*sqrt(b)*f*sqrt(b*tan(e + f*x))) + S(3)*d**S(3)*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(S(4)*sqrt(b)*f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(5)/2)/sqrt(b*tan(e + f*x)), x), x, d**S(2)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(f*sqrt(b*tan(e + f*x))) + d**S(2)*sqrt(b*tan(e + f*x))*sqrt(d*sec(e + f*x))/(b*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(3)/2)/sqrt(b*tan(e + f*x)), x), x, d*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(sqrt(b)*f*sqrt(b*tan(e + f*x))) + d*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(sqrt(b)*f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*sec(e + f*x))/sqrt(b*tan(e + f*x)), x), x, S(2)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*tan(e + f*x))*sqrt(d*sec(e + f*x))), x), x, S(2)*sqrt(b*tan(e + f*x))/(b*f*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(3)/2)), x), x, S(4)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*d**S(2)*f*sqrt(b*tan(e + f*x))) + S(2)*sqrt(b*tan(e + f*x))/(S(3)*b*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(5)/2)), x), x, S(2)*sqrt(b*tan(e + f*x))/(S(5)*b*f*(d*sec(e + f*x))**(S(5)/2)) + S(8)*sqrt(b*tan(e + f*x))/(S(5)*b*d**S(2)*f*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(5)/2)/(b*tan(e + f*x))**(S(3)/2), x), x, -S(2)*d**S(2)*sqrt(d*sec(e + f*x))/(b*f*sqrt(b*tan(e + f*x))) - d**S(3)*sqrt(b*tan(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(b**(S(3)/2)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))) + d**S(3)*sqrt(b*tan(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(b**(S(3)/2)*f*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(3)/2)/(b*tan(e + f*x))**(S(3)/2), x), x, -S(2)*d**S(2)/(b*f*sqrt(b*tan(e + f*x))*sqrt(d*sec(e + f*x))) - S(2)*d**S(2)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(b**S(2)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*sec(e + f*x))/(b*tan(e + f*x))**(S(3)/2), x), x, -S(2)*sqrt(d*sec(e + f*x))/(b*f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*tan(e + f*x))**(S(3)/2)*sqrt(d*sec(e + f*x))), x), x, -S(2)/(b*f*sqrt(b*tan(e + f*x))*sqrt(d*sec(e + f*x))) - S(4)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(b**S(2)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(3)/2)), x), x, S(2)/(S(3)*b*f*sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(3)/2)) - S(8)*sqrt(d*sec(e + f*x))/(S(3)*b*d**S(2)*f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/((b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(3)/2)), x), x, -S(2)/(b*f*sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(3)/2)) - S(8)*(b*tan(e + f*x))**(S(3)/2)/(S(3)*b**S(3)*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(5)/2)), x), x, -S(2)/(b*f*sqrt(b*tan(e + f*x))*(d*sec(e + f*x))**(S(5)/2)) - S(24)*sqrt(b*tan(e + f*x))*EllipticE(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))/(S(5)*b**S(2)*d**S(2)*f*sqrt(d*sec(e + f*x))*sqrt(sin(e + f*x))) - S(12)*(b*tan(e + f*x))**(S(3)/2)/(S(5)*b**S(3)*f*(d*sec(e + f*x))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(7)/2)/(b*tan(e + f*x))**(S(5)/2), x), x, -S(2)*d**S(2)*(d*sec(e + f*x))**(S(3)/2)/(S(3)*b*f*(b*tan(e + f*x))**(S(3)/2)) + d**S(3)*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*ArcTan(sqrt(b*sin(e + f*x))/sqrt(b))/(b**(S(5)/2)*f*sqrt(b*tan(e + f*x))) + d**S(3)*sqrt(b*sin(e + f*x))*sqrt(d*sec(e + f*x))*atanh(sqrt(b*sin(e + f*x))/sqrt(b))/(b**(S(5)/2)*f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(5)/2)/(b*tan(e + f*x))**(S(5)/2), x), x, -S(2)*d**S(2)*sqrt(d*sec(e + f*x))/(S(3)*b*f*(b*tan(e + f*x))**(S(3)/2)) + S(2)*d**S(2)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*b**S(2)*f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*sec(e + f*x))**(S(3)/2)/(b*tan(e + f*x))**(S(5)/2), x), x, -S(2)*(d*sec(e + f*x))**(S(3)/2)/(S(3)*b*f*(b*tan(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*sec(e + f*x))/(b*tan(e + f*x))**(S(5)/2), x), x, -S(2)*sqrt(d*sec(e + f*x))/(S(3)*b*f*(b*tan(e + f*x))**(S(3)/2)) - S(4)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*b**S(2)*f*sqrt(b*tan(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*tan(e + f*x))**(S(5)/2)*sqrt(d*sec(e + f*x))), x), x, -S(2)/(S(3)*b*f*(b*tan(e + f*x))**(S(3)/2)*sqrt(d*sec(e + f*x))) - S(8)*sqrt(b*tan(e + f*x))/(S(3)*b**S(3)*f*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*tan(e + f*x))**(S(5)/2)*(d*sec(e + f*x))**(S(3)/2)), x), x, -S(2)/(S(3)*b*f*(b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(3)/2)) - S(8)*sqrt(d*sec(e + f*x))*EllipticF(-Pi/S(4) + e/S(2) + f*x/S(2), S(2))*sqrt(sin(e + f*x))/(S(3)*b**S(2)*d**S(2)*f*sqrt(b*tan(e + f*x))) - S(4)*sqrt(b*tan(e + f*x))/(S(3)*b**S(3)*f*(d*sec(e + f*x))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((b*tan(e + f*x))**(S(5)/2)*(d*sec(e + f*x))**(S(5)/2)), x), x, -S(2)/(S(3)*b*f*(b*tan(e + f*x))**(S(3)/2)*(d*sec(e + f*x))**(S(5)/2)) - S(16)*sqrt(b*tan(e + f*x))/(S(15)*b**S(3)*f*(d*sec(e + f*x))**(S(5)/2)) - S(64)*sqrt(b*tan(e + f*x))/(S(15)*b**S(3)*d**S(2)*f*sqrt(d*sec(e + f*x))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(4)/3)*sqrt(d*tan(e + f*x)), x), x, S(2)*(b*sec(e + f*x))**(S(4)/3)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(17)/12)*Hypergeometric2F1(S(3)/4, S(17)/12, S(7)/4, sin(e + f*x)**S(2))/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(1)/3)*sqrt(d*tan(e + f*x)), x), x, S(2)*(b*sec(e + f*x))**(S(1)/3)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(11)/12)*Hypergeometric2F1(S(3)/4, S(11)/12, S(7)/4, sin(e + f*x)**S(2))/(S(3)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))/(b*sec(e + f*x))**(S(1)/3), x), x, S(2)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(7)/12)*Hypergeometric2F1(S(7)/12, S(3)/4, S(7)/4, sin(e + f*x)**S(2))/(S(3)*d*f*(b*sec(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*tan(e + f*x))/(b*sec(e + f*x))**(S(4)/3), x), x, S(2)*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(1)/12)*Hypergeometric2F1(S(1)/12, S(3)/4, S(7)/4, sin(e + f*x)**S(2))/(S(3)*d*f*(b*sec(e + f*x))**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(4)/3)*(d*tan(e + f*x))**(S(3)/2), x), x, S(2)*(b*sec(e + f*x))**(S(4)/3)*(d*tan(e + f*x))**(S(5)/2)*(cos(e + f*x)**S(2))**(S(23)/12)*Hypergeometric2F1(S(5)/4, S(23)/12, S(9)/4, sin(e + f*x)**S(2))/(S(5)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(1)/3)*(d*tan(e + f*x))**(S(3)/2), x), x, S(2)*(b*sec(e + f*x))**(S(1)/3)*(d*tan(e + f*x))**(S(5)/2)*(cos(e + f*x)**S(2))**(S(17)/12)*Hypergeometric2F1(S(5)/4, S(17)/12, S(9)/4, sin(e + f*x)**S(2))/(S(5)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(3)/2)/(b*sec(e + f*x))**(S(1)/3), x), x, S(2)*(d*tan(e + f*x))**(S(5)/2)*(cos(e + f*x)**S(2))**(S(13)/12)*Hypergeometric2F1(S(13)/12, S(5)/4, S(9)/4, sin(e + f*x)**S(2))/(S(5)*d*f*(b*sec(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(e + f*x))**(S(3)/2)/(b*sec(e + f*x))**(S(4)/3), x), x, S(2)*(d*tan(e + f*x))**(S(5)/2)*(cos(e + f*x)**S(2))**(S(7)/12)*Hypergeometric2F1(S(7)/12, S(5)/4, S(9)/4, sin(e + f*x)**S(2))/(S(5)*d*f*(b*sec(e + f*x))**(S(4)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*(d*tan(e + f*x))**(S(4)/3), x), x, S(3)*sqrt(b*sec(e + f*x))*(d*tan(e + f*x))**(S(7)/3)*(cos(e + f*x)**S(2))**(S(17)/12)*Hypergeometric2F1(S(7)/6, S(17)/12, S(13)/6, sin(e + f*x)**S(2))/(S(7)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))*(d*tan(e + f*x))**(S(1)/3), x), x, S(3)*sqrt(b*sec(e + f*x))*(d*tan(e + f*x))**(S(4)/3)*(cos(e + f*x)**S(2))**(S(11)/12)*Hypergeometric2F1(S(2)/3, S(11)/12, S(5)/3, sin(e + f*x)**S(2))/(S(4)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))/(d*tan(e + f*x))**(S(1)/3), x), x, S(3)*sqrt(b*sec(e + f*x))*(d*tan(e + f*x))**(S(2)/3)*(cos(e + f*x)**S(2))**(S(7)/12)*Hypergeometric2F1(S(1)/3, S(7)/12, S(4)/3, sin(e + f*x)**S(2))/(S(2)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*sec(e + f*x))/(d*tan(e + f*x))**(S(4)/3), x), x, -S(3)*sqrt(b*sec(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/12)*Hypergeometric2F1(S(-1)/6, S(1)/12, S(5)/6, sin(e + f*x)**S(2))/(d*f*(d*tan(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(4)/3), x), x, S(3)*(b*sec(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(7)/3)*(cos(e + f*x)**S(2))**(S(23)/12)*Hypergeometric2F1(S(7)/6, S(23)/12, S(13)/6, sin(e + f*x)**S(2))/(S(7)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(1)/3), x), x, S(3)*(b*sec(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(4)/3)*(cos(e + f*x)**S(2))**(S(17)/12)*Hypergeometric2F1(S(2)/3, S(17)/12, S(5)/3, sin(e + f*x)**S(2))/(S(4)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)/(d*tan(e + f*x))**(S(1)/3), x), x, S(3)*(b*sec(e + f*x))**(S(3)/2)*(d*tan(e + f*x))**(S(2)/3)*(cos(e + f*x)**S(2))**(S(13)/12)*Hypergeometric2F1(S(1)/3, S(13)/12, S(4)/3, sin(e + f*x)**S(2))/(S(2)*d*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**(S(3)/2)/(d*tan(e + f*x))**(S(4)/3), x), x, -S(3)*(b*sec(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(7)/12)*Hypergeometric2F1(S(-1)/6, S(7)/12, S(5)/6, sin(e + f*x)**S(2))/(d*f*(d*tan(e + f*x))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*tan(e + f*x)**S(5), x), x, (b*sec(e + f*x))**m/(f*m) - S(2)*(b*sec(e + f*x))**(m + S(2))/(b**S(2)*f*(m + S(2))) + (b*sec(e + f*x))**(m + S(4))/(b**S(4)*f*(m + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*tan(e + f*x)**S(3), x), x, -(b*sec(e + f*x))**m/(f*m) + (b*sec(e + f*x))**(m + S(2))/(b**S(2)*f*(m + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*tan(e + f*x), x), x, (b*sec(e + f*x))**m/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*cot(e + f*x), x), x, -(b*sec(e + f*x))**m*Hypergeometric2F1(S(1), m/S(2), m/S(2) + S(1), sec(e + f*x)**S(2))/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*cot(e + f*x)**S(3), x), x, (b*sec(e + f*x))**m*Hypergeometric2F1(S(2), m/S(2), m/S(2) + S(1), sec(e + f*x)**S(2))/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*cot(e + f*x)**S(5), x), x, -(b*sec(e + f*x))**m*Hypergeometric2F1(S(3), m/S(2), m/S(2) + S(1), sec(e + f*x)**S(2))/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*tan(e + f*x)**S(4), x), x, (b*sec(e + f*x))**m*(cos(e + f*x)**S(2))**(m/S(2) + S(5)/2)*Hypergeometric2F1(S(5)/2, m/S(2) + S(5)/2, S(7)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(5)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*tan(e + f*x)**S(2), x), x, (b*sec(e + f*x))**m*(cos(e + f*x)**S(2))**(m/S(2) + S(3)/2)*Hypergeometric2F1(S(3)/2, m/S(2) + S(3)/2, S(5)/2, sin(e + f*x)**S(2))*tan(e + f*x)**S(3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*cot(e + f*x)**S(2), x), x, -(b*sec(e + f*x))**m*(cos(e + f*x)**S(2))**(m/S(2) + S(-1)/2)*Hypergeometric2F1(S(-1)/2, m/S(2) + S(-1)/2, S(1)/2, sin(e + f*x)**S(2))*cot(e + f*x)/f, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*cot(e + f*x)**S(4), x), x, -(b*sec(e + f*x))**m*(cos(e + f*x)**S(2))**(m/S(2) + S(-3)/2)*Hypergeometric2F1(S(-3)/2, m/S(2) + S(-3)/2, S(-1)/2, sin(e + f*x)**S(2))*cot(e + f*x)**S(3)/(S(3)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*sec(e + f*x))**m*cot(e + f*x)**S(6), x), x, -(b*sec(e + f*x))**m*(cos(e + f*x)**S(2))**(m/S(2) + S(-5)/2)*Hypergeometric2F1(S(-5)/2, m/S(2) + S(-5)/2, S(-3)/2, sin(e + f*x)**S(2))*cot(e + f*x)**S(5)/(S(5)*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*sec(e + f*x))**m*(b*tan(e + f*x))**n, x), x, (a*sec(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))*(cos(e + f*x)**S(2))**(m/S(2) + n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, m/S(2) + n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(e + f*x)**S(2))/(b*f*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*sec(a + b*x)**S(6), x), x, (d*tan(a + b*x))**(n + S(1))/(b*d*(n + S(1))) + S(2)*(d*tan(a + b*x))**(n + S(3))/(b*d**S(3)*(n + S(3))) + (d*tan(a + b*x))**(n + S(5))/(b*d**S(5)*(n + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*sec(a + b*x)**S(4), x), x, (d*tan(a + b*x))**(n + S(1))/(b*d*(n + S(1))) + (d*tan(a + b*x))**(n + S(3))/(b*d**S(3)*(n + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*sec(a + b*x)**S(2), x), x, (d*tan(a + b*x))**(n + S(1))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n, x), x, (d*tan(a + b*x))**(n + S(1))*Hypergeometric2F1(S(1), n/S(2) + S(1)/2, n/S(2) + S(3)/2, -tan(a + b*x)**S(2))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*cos(a + b*x)**S(2), x), x, (d*tan(a + b*x))**(n + S(1))*Hypergeometric2F1(S(2), n/S(2) + S(1)/2, n/S(2) + S(3)/2, -tan(a + b*x)**S(2))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*cos(a + b*x)**S(4), x), x, (d*tan(a + b*x))**(n + S(1))*Hypergeometric2F1(S(3), n/S(2) + S(1)/2, n/S(2) + S(3)/2, -tan(a + b*x)**S(2))/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*sec(a + b*x)**S(5), x), x, (d*tan(a + b*x))**(n + S(1))*(cos(a + b*x)**S(2))**(n/S(2) + S(3))*Hypergeometric2F1(n/S(2) + S(1)/2, n/S(2) + S(3), n/S(2) + S(3)/2, sin(a + b*x)**S(2))*sec(a + b*x)**S(5)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*sec(a + b*x)**S(3), x), x, (d*tan(a + b*x))**(n + S(1))*(cos(a + b*x)**S(2))**(n/S(2) + S(2))*Hypergeometric2F1(n/S(2) + S(1)/2, n/S(2) + S(2), n/S(2) + S(3)/2, sin(a + b*x)**S(2))*sec(a + b*x)**S(3)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*sec(a + b*x), x), x, (d*tan(a + b*x))**(n + S(1))*(cos(a + b*x)**S(2))**(n/S(2) + S(1))*Hypergeometric2F1(n/S(2) + S(1)/2, n/S(2) + S(1), n/S(2) + S(3)/2, sin(a + b*x)**S(2))*sec(a + b*x)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*cos(a + b*x), x), x, (d*tan(a + b*x))**(n + S(1))*(cos(a + b*x)**S(2))**(n/S(2))*Hypergeometric2F1(n/S(2), n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(a + b*x)**S(2))*cos(a + b*x)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*tan(a + b*x))**n*cos(a + b*x)**S(3), x), x, (d*tan(a + b*x))**(n + S(1))*(cos(a + b*x)**S(2))**(n/S(2) + S(-1))*Hypergeometric2F1(n/S(2) + S(-1), n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(a + b*x)**S(2))*cos(a + b*x)**S(3)/(b*d*(n + S(1))), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((b*csc(e + f*x))**m*tan(e + f*x)**S(3), x), x, -(b*csc(e + f*x))**m*Hypergeometric2F1(S(2), m/S(2), m/S(2) + S(1), csc(e + f*x)**S(2))/(f*m), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*csc(e + f*x))**m*(d*tan(e + f*x))**(S(3)/2), x), x, (b*csc(e + f*x))**m*(d*tan(e + f*x))**(S(5)/2)*(cos(e + f*x)**S(2))**(S(5)/4)*Hypergeometric2F1(S(5)/4, -m/S(2) + S(5)/4, -m/S(2) + S(9)/4, sin(e + f*x)**S(2))/(d*f*(-m + S(5)/2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((b*csc(e + f*x))**m*(d*tan(e + f*x))**(S(3)/2), x), x, S(2)*d*(b*csc(e + f*x))**m*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(5)/4, -m/S(2) + S(5)/4, -m/S(2) + S(9)/4, sin(e + f*x)**S(2))*sin(e + f*x)**S(2)/(f*(-S(2)*m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*csc(e + f*x))**m*sqrt(d*tan(e + f*x)), x), x, S(2)*(b*csc(e + f*x))**m*(d*tan(e + f*x))**(S(3)/2)*(cos(e + f*x)**S(2))**(S(3)/4)*Hypergeometric2F1(S(3)/4, -m/S(2) + S(3)/4, -m/S(2) + S(7)/4, sin(e + f*x)**S(2))/(d*f*(-S(2)*m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*csc(e + f*x))**m/sqrt(d*tan(e + f*x)), x), x, S(2)*(b*csc(e + f*x))**m*sqrt(d*tan(e + f*x))*(cos(e + f*x)**S(2))**(S(1)/4)*Hypergeometric2F1(S(1)/4, -m/S(2) + S(1)/4, -m/S(2) + S(5)/4, sin(e + f*x)**S(2))/(d*f*(-S(2)*m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*csc(e + f*x))**m/(d*tan(e + f*x))**(S(3)/2), x), x, -S(2)*(b*csc(e + f*x))**m*Hypergeometric2F1(S(-1)/4, -m/S(2) + S(-1)/4, -m/S(2) + S(3)/4, sin(e + f*x)**S(2))/(d*f*sqrt(d*tan(e + f*x))*(S(2)*m + S(1))*(cos(e + f*x)**S(2))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*csc(e + f*x))**m*(b*tan(e + f*x))**n, x), x, (a*csc(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))*(cos(e + f*x)**S(2))**(n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, -m/S(2) + n/S(2) + S(1)/2, -m/S(2) + n/S(2) + S(3)/2, sin(e + f*x)**S(2))/(b*f*(-m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-tan(e + f*x)**S(2))**n*sin(e + f*x), x), x, -Hypergeometric2F1(S(-1)/2, -n, S(1)/2, sec(e + f*x)**S(2))*cos(e + f*x)/f, expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubi_tests/tests/test_trinomials.py000066400000000000000000056020631412543434000271700ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.rubi import rubi_integrate from sympy.functions import log, sqrt, exp, cos, sin, tan, sec, csc, cot from sympy.functions.elementary.hyperbolic import atanh, asinh, acosh from sympy.functions.elementary.hyperbolic import atanh as arctanh from sympy.functions.elementary.hyperbolic import asinh as arcsinh from sympy.functions.elementary.hyperbolic import acosh as arccosh from sympy.functions.elementary.trigonometric import atan, asin, acos from sympy.functions.elementary.trigonometric import atan as arctan from sympy.functions.elementary.trigonometric import asin as arcsin from sympy.functions.elementary.trigonometric import acos as arccos from sympy.integrals.rubi.utility_function import (EllipticE, EllipticF, hypergeom, rubi_test, AppellF1, EllipticPi, Log, Sqrt, ArcTan, ArcTanh, ArcSin, Hypergeometric2F1) from sympy import pi as Pi, elliptic_e, elliptic_f, elliptic_pi, Mod from sympy import S, hyper, I, simplify, exp_polar, symbols, sqrt from sympy.testing.pytest import SKIP a, b, c, d, e, f, m, n, x, u , k, p, j, l , i= symbols('a b c d e f m n x u k p j l i1') A, B, C, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B C a b c d e f g h y z m n p q u v w F', real=True, imaginary=False) def test_1(): assert rubi_test(rubi_integrate(x**m*(b*x**S(2) + c*x**S(4)), x), x, b*x**(m + S(3))/(m + S(3)) + c*x**(m + S(5))/(m + S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b*x**S(2) + c*x**S(4)), x), x, b*x**S(5)/S(5) + c*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b*x**S(2) + c*x**S(4)), x), x, b*x**S(4)/S(4) + c*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(b*x**S(2) + c*x**S(4), x), x, b*x**S(3)/S(3) + c*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x, x), x, b*x**S(2)/S(2) + c*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**S(2), x), x, b*x + c*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**S(3), x), x, b*log(x) + c*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**S(4), x), x, -b/x + c*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**S(5), x), x, -b/(S(2)*x**S(2)) + c*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**S(6), x), x, -b/(S(3)*x**S(3)) - c/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**S(7), x), x, -b/(S(4)*x**S(4)) - c/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**S(8), x), x, -b/(S(5)*x**S(5)) - c/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(b*x**S(2) + c*x**S(4))**S(2), x), x, b**S(2)*x**(m + S(5))/(m + S(5)) + S(2)*b*c*x**(m + S(7))/(m + S(7)) + c**S(2)*x**(m + S(9))/(m + S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2), x), x, b**S(2)*x**S(5)/S(5) + S(2)*b*c*x**S(7)/S(7) + c**S(2)*x**S(9)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x, x), x, b**S(2)*x**S(4)/S(4) + b*c*x**S(6)/S(3) + c**S(2)*x**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(2), x), x, b**S(2)*x**S(3)/S(3) + S(2)*b*c*x**S(5)/S(5) + c**S(2)*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(3), x), x, (b + c*x**S(2))**S(3)/(S(6)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(4), x), x, b**S(2)*x + S(2)*b*c*x**S(3)/S(3) + c**S(2)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(5), x), x, b**S(2)*log(x) + b*c*x**S(2) + c**S(2)*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(6), x), x, -b**S(2)/x + S(2)*b*c*x + c**S(2)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(7), x), x, -b**S(2)/(S(2)*x**S(2)) + S(2)*b*c*log(x) + c**S(2)*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(8), x), x, -b**S(2)/(S(3)*x**S(3)) - S(2)*b*c/x + c**S(2)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(9), x), x, -b**S(2)/(S(4)*x**S(4)) - b*c/x**S(2) + c**S(2)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(10), x), x, -b**S(2)/(S(5)*x**S(5)) - S(2)*b*c/(S(3)*x**S(3)) - c**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(11), x), x, -(b + c*x**S(2))**S(3)/(S(6)*b*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**S(12), x), x, -b**S(2)/(S(7)*x**S(7)) - S(2)*b*c/(S(5)*x**S(5)) - c**S(2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(b*x**S(2) + c*x**S(4))**S(3), x), x, b**S(3)*x**(m + S(7))/(m + S(7)) + S(3)*b**S(2)*c*x**(m + S(9))/(m + S(9)) + S(3)*b*c**S(2)*x**(m + S(11))/(m + S(11)) + c**S(3)*x**(m + S(13))/(m + S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(2), x), x, b**S(3)*x**S(5)/S(5) + S(3)*b**S(2)*c*x**S(7)/S(7) + b*c**S(2)*x**S(9)/S(3) + c**S(3)*x**S(11)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(3), x), x, -b*(b + c*x**S(2))**S(4)/(S(8)*c**S(2)) + (b + c*x**S(2))**S(5)/(S(10)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(4), x), x, b**S(3)*x**S(3)/S(3) + S(3)*b**S(2)*c*x**S(5)/S(5) + S(3)*b*c**S(2)*x**S(7)/S(7) + c**S(3)*x**S(9)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(5), x), x, (b + c*x**S(2))**S(4)/(S(8)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(6), x), x, b**S(3)*x + b**S(2)*c*x**S(3) + S(3)*b*c**S(2)*x**S(5)/S(5) + c**S(3)*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(7), x), x, b**S(3)*log(x) + S(3)*b**S(2)*c*x**S(2)/S(2) + S(3)*b*c**S(2)*x**S(4)/S(4) + c**S(3)*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(8), x), x, -b**S(3)/x + S(3)*b**S(2)*c*x + b*c**S(2)*x**S(3) + c**S(3)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(9), x), x, -b**S(3)/(S(2)*x**S(2)) + S(3)*b**S(2)*c*log(x) + S(3)*b*c**S(2)*x**S(2)/S(2) + c**S(3)*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(10), x), x, -b**S(3)/(S(3)*x**S(3)) - S(3)*b**S(2)*c/x + S(3)*b*c**S(2)*x + c**S(3)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(11), x), x, -b**S(3)/(S(4)*x**S(4)) - S(3)*b**S(2)*c/(S(2)*x**S(2)) + S(3)*b*c**S(2)*log(x) + c**S(3)*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(12), x), x, -b**S(3)/(S(5)*x**S(5)) - b**S(2)*c/x**S(3) - S(3)*b*c**S(2)/x + c**S(3)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(13), x), x, -b**S(3)/(S(6)*x**S(6)) - S(3)*b**S(2)*c/(S(4)*x**S(4)) - S(3)*b*c**S(2)/(S(2)*x**S(2)) + c**S(3)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(14), x), x, -b**S(3)/(S(7)*x**S(7)) - S(3)*b**S(2)*c/(S(5)*x**S(5)) - b*c**S(2)/x**S(3) - c**S(3)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(15), x), x, -(b + c*x**S(2))**S(4)/(S(8)*b*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(16), x), x, -b**S(3)/(S(9)*x**S(9)) - S(3)*b**S(2)*c/(S(7)*x**S(7)) - S(3)*b*c**S(2)/(S(5)*x**S(5)) - c**S(3)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**S(17), x), x, -b**S(3)/(S(10)*x**S(10)) - S(3)*b**S(2)*c/(S(8)*x**S(8)) - b*c**S(2)/(S(2)*x**S(6)) - c**S(3)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(b*x**S(2) + c*x**S(4)), x), x, b**(S(7)/2)*atan(sqrt(c)*x/sqrt(b))/c**(S(9)/2) - b**S(3)*x/c**S(4) + b**S(2)*x**S(3)/(S(3)*c**S(3)) - b*x**S(5)/(S(5)*c**S(2)) + x**S(7)/(S(7)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(b*x**S(2) + c*x**S(4)), x), x, -b**S(3)*log(b + c*x**S(2))/(S(2)*c**S(4)) + b**S(2)*x**S(2)/(S(2)*c**S(3)) - b*x**S(4)/(S(4)*c**S(2)) + x**S(6)/(S(6)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(b*x**S(2) + c*x**S(4)), x), x, -b**(S(5)/2)*atan(sqrt(c)*x/sqrt(b))/c**(S(7)/2) + b**S(2)*x/c**S(3) - b*x**S(3)/(S(3)*c**S(2)) + x**S(5)/(S(5)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(b*x**S(2) + c*x**S(4)), x), x, b**S(2)*log(b + c*x**S(2))/(S(2)*c**S(3)) - b*x**S(2)/(S(2)*c**S(2)) + x**S(4)/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(b*x**S(2) + c*x**S(4)), x), x, b**(S(3)/2)*atan(sqrt(c)*x/sqrt(b))/c**(S(5)/2) - b*x/c**S(2) + x**S(3)/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(b*x**S(2) + c*x**S(4)), x), x, -b*log(b + c*x**S(2))/(S(2)*c**S(2)) + x**S(2)/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(b*x**S(2) + c*x**S(4)), x), x, -sqrt(b)*atan(sqrt(c)*x/sqrt(b))/c**(S(3)/2) + x/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(b*x**S(2) + c*x**S(4)), x), x, log(b + c*x**S(2))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(b*x**S(2) + c*x**S(4)), x), x, atan(sqrt(c)*x/sqrt(b))/(sqrt(b)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(b*x**S(2) + c*x**S(4)), x), x, log(x)/b - log(b + c*x**S(2))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(b*x**S(2) + c*x**S(4)), x), x, -S(1)/(b*x) - sqrt(c)*atan(sqrt(c)*x/sqrt(b))/b**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(2)*b*x**S(2)) - c*log(x)/b**S(2) + c*log(b + c*x**S(2))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(3)*b*x**S(3)) + c/(b**S(2)*x) + c**(S(3)/2)*atan(sqrt(c)*x/sqrt(b))/b**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(4)*b*x**S(4)) + c/(S(2)*b**S(2)*x**S(2)) + c**S(2)*log(x)/b**S(3) - c**S(2)*log(b + c*x**S(2))/(S(2)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(5)*b*x**S(5)) + c/(S(3)*b**S(2)*x**S(3)) - c**S(2)/(b**S(3)*x) - c**(S(5)/2)*atan(sqrt(c)*x/sqrt(b))/b**(S(7)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(6)*b*x**S(6)) + c/(S(4)*b**S(2)*x**S(4)) - c**S(2)/(S(2)*b**S(3)*x**S(2)) - c**S(3)*log(x)/b**S(4) + c**S(3)*log(b + c*x**S(2))/(S(2)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(12)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -S(7)*b**(S(5)/2)*atan(sqrt(c)*x/sqrt(b))/(S(2)*c**(S(9)/2)) + S(7)*b**S(2)*x/(S(2)*c**S(4)) - S(7)*b*x**S(3)/(S(6)*c**S(3)) - x**S(7)/(S(2)*c*(b + c*x**S(2))) + S(7)*x**S(5)/(S(10)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(b*x**S(2) + c*x**S(4))**S(2), x), x, b**S(3)/(S(2)*c**S(4)*(b + c*x**S(2))) + S(3)*b**S(2)*log(b + c*x**S(2))/(S(2)*c**S(4)) - b*x**S(2)/c**S(3) + x**S(4)/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(b*x**S(2) + c*x**S(4))**S(2), x), x, S(5)*b**(S(3)/2)*atan(sqrt(c)*x/sqrt(b))/(S(2)*c**(S(7)/2)) - S(5)*b*x/(S(2)*c**S(3)) - x**S(5)/(S(2)*c*(b + c*x**S(2))) + S(5)*x**S(3)/(S(6)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -b**S(2)/(S(2)*c**S(3)*(b + c*x**S(2))) - b*log(b + c*x**S(2))/c**S(3) + x**S(2)/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -S(3)*sqrt(b)*atan(sqrt(c)*x/sqrt(b))/(S(2)*c**(S(5)/2)) - x**S(3)/(S(2)*c*(b + c*x**S(2))) + S(3)*x/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(b*x**S(2) + c*x**S(4))**S(2), x), x, b/(S(2)*c**S(2)*(b + c*x**S(2))) + log(b + c*x**S(2))/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -x/(S(2)*c*(b + c*x**S(2))) + atan(sqrt(c)*x/sqrt(b))/(S(2)*sqrt(b)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -S(1)/(S(2)*c*(b + c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(b*x**S(2) + c*x**S(4))**S(2), x), x, x/(S(2)*b*(b + c*x**S(2))) + atan(sqrt(c)*x/sqrt(b))/(S(2)*b**(S(3)/2)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(b*x**S(2) + c*x**S(4))**S(2), x), x, S(1)/(S(2)*b*(b + c*x**S(2))) + log(x)/b**S(2) - log(b + c*x**S(2))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, S(1)/(S(2)*b*x*(b + c*x**S(2))) - S(3)/(S(2)*b**S(2)*x) - S(3)*sqrt(c)*atan(sqrt(c)*x/sqrt(b))/(S(2)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(b*x**S(2) + c*x**S(4))**S(2), x), x, -c/(S(2)*b**S(2)*(b + c*x**S(2))) - S(1)/(S(2)*b**S(2)*x**S(2)) - S(2)*c*log(x)/b**S(3) + c*log(b + c*x**S(2))/b**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(-2)), x), x, S(1)/(S(2)*b*x**S(3)*(b + c*x**S(2))) - S(5)/(S(6)*b**S(2)*x**S(3)) + S(5)*c/(S(2)*b**S(3)*x) + S(5)*c**(S(3)/2)*atan(sqrt(c)*x/sqrt(b))/(S(2)*b**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(b*x**S(2) + c*x**S(4))**S(2)), x), x, -S(1)/(S(4)*b**S(2)*x**S(4)) + c**S(2)/(S(2)*b**S(3)*(b + c*x**S(2))) + c/(b**S(3)*x**S(2)) + S(3)*c**S(2)*log(x)/b**S(4) - S(3)*c**S(2)*log(b + c*x**S(2))/(S(2)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(b*x**S(2) + c*x**S(4))**S(2)), x), x, S(1)/(S(2)*b*x**S(5)*(b + c*x**S(2))) - S(7)/(S(10)*b**S(2)*x**S(5)) + S(7)*c/(S(6)*b**S(3)*x**S(3)) - S(7)*c**S(2)/(S(2)*b**S(4)*x) - S(7)*c**(S(5)/2)*atan(sqrt(c)*x/sqrt(b))/(S(2)*b**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(35)*b**(S(3)/2)*atan(sqrt(c)*x/sqrt(b))/(S(8)*c**(S(9)/2)) - S(35)*b*x/(S(8)*c**S(4)) - x**S(7)/(S(4)*c*(b + c*x**S(2))**S(2)) - S(7)*x**S(5)/(S(8)*c**S(2)*(b + c*x**S(2))) + S(35)*x**S(3)/(S(24)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(13)/(b*x**S(2) + c*x**S(4))**S(3), x), x, b**S(3)/(S(4)*c**S(4)*(b + c*x**S(2))**S(2)) - S(3)*b**S(2)/(S(2)*c**S(4)*(b + c*x**S(2))) - S(3)*b*log(b + c*x**S(2))/(S(2)*c**S(4)) + x**S(2)/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(12)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -S(15)*sqrt(b)*atan(sqrt(c)*x/sqrt(b))/(S(8)*c**(S(7)/2)) - x**S(5)/(S(4)*c*(b + c*x**S(2))**S(2)) - S(5)*x**S(3)/(S(8)*c**S(2)*(b + c*x**S(2))) + S(15)*x/(S(8)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -b**S(2)/(S(4)*c**S(3)*(b + c*x**S(2))**S(2)) + b/(c**S(3)*(b + c*x**S(2))) + log(b + c*x**S(2))/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -x**S(3)/(S(4)*c*(b + c*x**S(2))**S(2)) - S(3)*x/(S(8)*c**S(2)*(b + c*x**S(2))) + S(3)*atan(sqrt(c)*x/sqrt(b))/(S(8)*sqrt(b)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(b*x**S(2) + c*x**S(4))**S(3), x), x, x**S(4)/(S(4)*b*(b + c*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -x/(S(4)*c*(b + c*x**S(2))**S(2)) + x/(S(8)*b*c*(b + c*x**S(2))) + atan(sqrt(c)*x/sqrt(b))/(S(8)*b**(S(3)/2)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -S(1)/(S(4)*c*(b + c*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(b*x**S(2) + c*x**S(4))**S(3), x), x, x/(S(4)*b*(b + c*x**S(2))**S(2)) + S(3)*x/(S(8)*b**S(2)*(b + c*x**S(2))) + S(3)*atan(sqrt(c)*x/sqrt(b))/(S(8)*b**(S(5)/2)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*(b + c*x**S(2))**S(2)) + S(1)/(S(2)*b**S(2)*(b + c*x**S(2))) + log(x)/b**S(3) - log(b + c*x**S(2))/(S(2)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*x*(b + c*x**S(2))**S(2)) + S(5)/(S(8)*b**S(2)*x*(b + c*x**S(2))) - S(15)/(S(8)*b**S(3)*x) - S(15)*sqrt(c)*atan(sqrt(c)*x/sqrt(b))/(S(8)*b**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -c/(S(4)*b**S(2)*(b + c*x**S(2))**S(2)) - c/(b**S(3)*(b + c*x**S(2))) - S(1)/(S(2)*b**S(3)*x**S(2)) - S(3)*c*log(x)/b**S(4) + S(3)*c*log(b + c*x**S(2))/(S(2)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*x**S(3)*(b + c*x**S(2))**S(2)) + S(7)/(S(8)*b**S(2)*x**S(3)*(b + c*x**S(2))) - S(35)/(S(24)*b**S(3)*x**S(3)) + S(35)*c/(S(8)*b**S(4)*x) + S(35)*c**(S(3)/2)*atan(sqrt(c)*x/sqrt(b))/(S(8)*b**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(b*x**S(2) + c*x**S(4))**S(3), x), x, c**S(2)/(S(4)*b**S(3)*(b + c*x**S(2))**S(2)) - S(1)/(S(4)*b**S(3)*x**S(4)) + S(3)*c**S(2)/(S(2)*b**S(4)*(b + c*x**S(2))) + S(3)*c/(S(2)*b**S(4)*x**S(2)) + S(6)*c**S(2)*log(x)/b**S(5) - S(3)*c**S(2)*log(b + c*x**S(2))/b**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(-3)), x), x, S(1)/(S(4)*b*x**S(5)*(b + c*x**S(2))**S(2)) + S(9)/(S(8)*b**S(2)*x**S(5)*(b + c*x**S(2))) - S(63)/(S(40)*b**S(3)*x**S(5)) + S(21)*c/(S(8)*b**S(4)*x**S(3)) - S(63)*c**S(2)/(S(8)*b**S(5)*x) - S(63)*c**(S(5)/2)*atan(sqrt(c)*x/sqrt(b))/(S(8)*b**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(b*x**S(2) + c*x**S(4))**S(3)), x), x, -S(1)/(S(6)*b**S(3)*x**S(6)) - c**S(3)/(S(4)*b**S(4)*(b + c*x**S(2))**S(2)) + S(3)*c/(S(4)*b**S(4)*x**S(4)) - S(2)*c**S(3)/(b**S(5)*(b + c*x**S(2))) - S(3)*c**S(2)/(b**S(5)*x**S(2)) - S(10)*c**S(3)*log(x)/b**S(6) + S(5)*c**S(3)*log(b + c*x**S(2))/b**S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(5)*b**S(4)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(128)*c**(S(7)/2)) + S(5)*b**S(2)*(b + S(2)*c*x**S(2))*sqrt(b*x**S(2) + c*x**S(4))/(S(128)*c**S(3)) - S(5)*b*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(48)*c**S(2)) + x**S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(8)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(b*x**S(2) + c*x**S(4)), x), x, b**S(3)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(16)*c**(S(5)/2)) - b*(b + S(2)*c*x**S(2))*sqrt(b*x**S(2) + c*x**S(4))/(S(16)*c**S(2)) + (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(b*x**S(2) + c*x**S(4)), x), x, -b**S(2)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*c**(S(3)/2)) + (b + S(2)*c*x**S(2))*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x, x), x, b*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*sqrt(c)) + sqrt(b*x**S(2) + c*x**S(4))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(3), x), x, sqrt(c)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4))) - sqrt(b*x**S(2) + c*x**S(4))/x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(5), x), x, -(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(3)*b*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(7), x), x, -(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(5)*b*x**S(8)) + S(2)*c*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(15)*b**S(2)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(9), x), x, -(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(7)*b*x**S(10)) + S(4)*c*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(35)*b**S(2)*x**S(8)) - S(8)*c**S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(105)*b**S(3)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(11), x), x, -(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(9)*b*x**S(12)) + S(2)*c*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(21)*b**S(2)*x**S(10)) - S(8)*c**S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(105)*b**S(3)*x**S(8)) + S(16)*c**S(3)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(315)*b**S(4)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(13), x), x, -(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(11)*b*x**S(14)) + S(8)*c*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(99)*b**S(2)*x**S(12)) - S(16)*c**S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(231)*b**S(3)*x**S(10)) + S(64)*c**S(3)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(1155)*b**S(4)*x**S(8)) - S(128)*c**S(4)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(3465)*b**S(5)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(b*x**S(2) + c*x**S(4)), x), x, S(8)*b**S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(105)*c**S(3)*x**S(3)) - S(4)*b*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(35)*c**S(2)*x) + x*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(7)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(2)*b*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(15)*c**S(2)*x**S(3)) + (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(5)*c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4)), x), x, (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(3)*c*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(2), x), x, -sqrt(b)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4))) + sqrt(b*x**S(2) + c*x**S(4))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(4), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(2)*x**S(3)) - c*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(6), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(4)*x**S(5)) - c*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*b*x**S(3)) + c**S(2)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**S(8), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(6)*x**S(7)) - c*sqrt(b*x**S(2) + c*x**S(4))/(S(24)*b*x**S(5)) + c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(16)*b**S(2)*x**S(3)) - c**S(3)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(16)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(3)*b**S(5)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(256)*c**(S(7)/2)) + S(3)*b**S(3)*(b + S(2)*c*x**S(2))*sqrt(b*x**S(2) + c*x**S(4))/(S(256)*c**S(3)) - b*(b + S(2)*c*x**S(2))*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(32)*c**S(2)) + (b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(10)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(3)*b**S(4)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(128)*c**(S(5)/2)) - S(3)*b**S(2)*(b + S(2)*c*x**S(2))*sqrt(b*x**S(2) + c*x**S(4))/(S(128)*c**S(2)) + (b + S(2)*c*x**S(2))*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(16)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x, x), x, -b**S(3)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(16)*c**(S(3)/2)) + b*(b + S(2)*c*x**S(2))*sqrt(b*x**S(2) + c*x**S(4))/(S(16)*c) + (b*x**S(2) + c*x**S(4))**(S(3)/2)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(3), x), x, S(3)*b**S(2)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*sqrt(c)) + S(3)*b*sqrt(b*x**S(2) + c*x**S(4))/S(8) + (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(5), x), x, S(3)*b*sqrt(c)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/S(2) + S(3)*c*sqrt(b*x**S(2) + c*x**S(4))/S(2) - (b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(7), x), x, c**(S(3)/2)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4))) - c*sqrt(b*x**S(2) + c*x**S(4))/x**S(2) - (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(3)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(9), x), x, -(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(5)*b*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(11), x), x, -(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(7)*b*x**S(12)) + S(2)*c*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(35)*b**S(2)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(13), x), x, -(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(9)*b*x**S(14)) + S(4)*c*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(63)*b**S(2)*x**S(12)) - S(8)*c**S(2)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(315)*b**S(3)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(15), x), x, -(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(11)*b*x**S(16)) + S(2)*c*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(33)*b**S(2)*x**S(14)) - S(8)*c**S(2)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(231)*b**S(3)*x**S(12)) + S(16)*c**S(3)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(1155)*b**S(4)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(17), x), x, -(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(13)*b*x**S(18)) + S(8)*c*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(143)*b**S(2)*x**S(16)) - S(16)*c**S(2)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(429)*b**S(3)*x**S(14)) + S(64)*c**S(3)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(3003)*b**S(4)*x**S(12)) - S(128)*c**S(4)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(15015)*b**S(5)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(128)*b**S(4)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(15015)*c**S(5)*x**S(5)) - S(64)*b**S(3)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(3003)*c**S(4)*x**S(3)) + S(16)*b**S(2)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(429)*c**S(3)*x) - S(8)*b*x*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(143)*c**S(2)) + x**S(3)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(13)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(16)*b**S(3)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(1155)*c**S(4)*x**S(5)) + S(8)*b**S(2)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(231)*c**S(3)*x**S(3)) - S(2)*b*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(33)*c**S(2)*x) + x*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(11)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(8)*b**S(2)*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(315)*c**S(3)*x**S(5)) - S(4)*b*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(63)*c**S(2)*x**S(3)) + (b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(9)*c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(2)*b*(b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(35)*c**S(2)*x**S(5)) + (b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(7)*c*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(2), x), x, (b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(5)*c*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(4), x), x, -b**(S(3)/2)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4))) + b*sqrt(b*x**S(2) + c*x**S(4))/x + (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(6), x), x, -S(3)*sqrt(b)*c*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/S(2) + S(3)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(2)*x) - (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(2)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(8), x), x, -S(3)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*x**S(3)) - (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(4)*x**S(7)) - S(3)*c**S(2)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(10), x), x, -c*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*x**S(5)) - (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*x**S(9)) - c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(16)*b*x**S(3)) + c**S(3)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(16)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(12), x), x, -c*sqrt(b*x**S(2) + c*x**S(4))/(S(16)*x**S(7)) - (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(8)*x**S(11)) - c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(64)*b*x**S(5)) + S(3)*c**S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(128)*b**S(2)*x**S(3)) - S(3)*c**S(4)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(128)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(14), x), x, -S(3)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(80)*x**S(9)) - (b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(10)*x**S(13)) - c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(160)*b*x**S(7)) + c**S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(128)*b**S(2)*x**S(5)) - S(3)*c**S(4)*sqrt(b*x**S(2) + c*x**S(4))/(S(256)*b**S(3)*x**S(3)) + S(3)*c**S(5)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(256)*b**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(5)*b**S(3)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(16)*c**(S(7)/2)) + S(5)*b**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(16)*c**S(3)) - S(5)*b*x**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(24)*c**S(2)) + x**S(4)*sqrt(b*x**S(2) + c*x**S(4))/(S(6)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/sqrt(b*x**S(2) + c*x**S(4)), x), x, S(3)*b**S(2)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*c**(S(5)/2)) - S(3)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*c**S(2)) + x**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -b*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*c**(S(3)/2)) + sqrt(b*x**S(2) + c*x**S(4))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(b*x**S(2) + c*x**S(4)), x), x, atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/sqrt(c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(b*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b*x**S(4)) + S(2)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b**S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b*x**S(6)) + S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(15)*b**S(2)*x**S(4)) - S(8)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(15)*b**S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(7)*b*x**S(8)) + S(6)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(35)*b**S(2)*x**S(6)) - S(8)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(35)*b**S(3)*x**S(4)) + S(16)*c**S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(35)*b**S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(2)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*c**S(2)*x) + x*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, sqrt(b*x**S(2) + c*x**S(4))/(c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(2)*b*x**S(3)) + c*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(4)*b*x**S(5)) + S(3)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*b**S(2)*x**S(3)) - S(3)*c**S(2)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(15)*b**S(2)*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*c**(S(7)/2)) - S(15)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*c**S(3)) - x**S(6)/(c*sqrt(b*x**S(2) + c*x**S(4))) + S(5)*x**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(3)*b*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*c**(S(5)/2)) - x**S(4)/(c*sqrt(b*x**S(2) + c*x**S(4))) + S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -x**S(2)/(c*sqrt(b*x**S(2) + c*x**S(4))) + atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/c**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, x**S(2)/(b*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -(b + S(2)*c*x**S(2))/(b**S(2)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(1)/(b*x**S(2)*sqrt(b*x**S(2) + c*x**S(4))) - S(4)*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b**S(2)*x**S(4)) + S(8)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b**S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(1)/(b*x**S(4)*sqrt(b*x**S(2) + c*x**S(4))) - S(6)*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b**S(2)*x**S(6)) + S(8)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b**S(3)*x**S(4)) - S(16)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b**S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(1)/(b*x**S(6)*sqrt(b*x**S(2) + c*x**S(4))) - S(8)*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*b**S(2)*x**S(8)) + S(48)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(35)*b**S(3)*x**S(6)) - S(64)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(35)*b**S(4)*x**S(4)) + S(128)*c**S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(35)*b**S(5)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -x**S(3)/(c*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*sqrt(b*x**S(2) + c*x**S(4))/(c**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -x/(c*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, x/(b*sqrt(b*x**S(2) + c*x**S(4))) - atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/b**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(-3)/2), x), x, S(1)/(b*x*sqrt(b*x**S(2) + c*x**S(4))) - S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(2)*b**S(2)*x**S(3)) + S(3)*c*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(1)/(b*x**S(3)*sqrt(b*x**S(2) + c*x**S(4))) - S(5)*sqrt(b*x**S(2) + c*x**S(4))/(S(4)*b**S(2)*x**S(5)) + S(15)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*b**S(3)*x**S(3)) - S(15)*c**S(2)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*b**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(-S(4)*x**S(4) + S(3)*x**S(2)), x), x, -sqrt(-S(4)*x**S(4) + S(3)*x**S(2))/S(8) + S(3)*asin(S(8)*x**S(2)/S(3) + S(-1))/S(32), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(-S(4)*x**S(4) - S(3)*x**S(2)), x), x, -sqrt(-S(4)*x**S(4) - S(3)*x**S(2))/S(8) - S(3)*asin(S(8)*x**S(2)/S(3) + S(1))/S(32), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(S(4)*x**S(4) + S(3)*x**S(2)), x), x, sqrt(S(4)*x**S(4) + S(3)*x**S(2))/S(8) - S(3)*atanh(S(2)*x**S(2)/sqrt(S(4)*x**S(4) + S(3)*x**S(2)))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(S(4)*x**S(4) - S(3)*x**S(2)), x), x, sqrt(S(4)*x**S(4) - S(3)*x**S(2))/S(8) + S(3)*atanh(S(2)*x**S(2)/sqrt(S(4)*x**S(4) - S(3)*x**S(2)))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a*x**S(2) + b*x**S(4)), x), x, -a*atanh(sqrt(b)*x**S(2)/sqrt(a*x**S(2) + b*x**S(4)))/(S(2)*b**(S(3)/2)) + sqrt(a*x**S(2) + b*x**S(4))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a*x**S(2) - b*x**S(4)), x), x, a*atan(sqrt(b)*x**S(2)/sqrt(a*x**S(2) - b*x**S(4)))/(S(2)*b**(S(3)/2)) - sqrt(a*x**S(2) - b*x**S(4))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)*(b*x**S(2) + c*x**S(4)), x), x, S(2)*b*x**(S(13)/2)/S(13) + S(2)*c*x**(S(17)/2)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*(b*x**S(2) + c*x**S(4)), x), x, S(2)*b*x**(S(11)/2)/S(11) + S(2)*c*x**(S(15)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(b*x**S(2) + c*x**S(4)), x), x, S(2)*b*x**(S(9)/2)/S(9) + S(2)*c*x**(S(13)/2)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(b*x**S(2) + c*x**S(4)), x), x, S(2)*b*x**(S(7)/2)/S(7) + S(2)*c*x**(S(11)/2)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/sqrt(x), x), x, S(2)*b*x**(S(5)/2)/S(5) + S(2)*c*x**(S(9)/2)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**(S(3)/2), x), x, S(2)*b*x**(S(3)/2)/S(3) + S(2)*c*x**(S(7)/2)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**(S(5)/2), x), x, S(2)*b*sqrt(x) + S(2)*c*x**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))/x**(S(7)/2), x), x, -S(2)*b/sqrt(x) + S(2)*c*x**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)*(b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*b**S(2)*x**(S(17)/2)/S(17) + S(4)*b*c*x**(S(21)/2)/S(21) + S(2)*c**S(2)*x**(S(25)/2)/S(25), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*(b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*b**S(2)*x**(S(15)/2)/S(15) + S(4)*b*c*x**(S(19)/2)/S(19) + S(2)*c**S(2)*x**(S(23)/2)/S(23), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*b**S(2)*x**(S(13)/2)/S(13) + S(4)*b*c*x**(S(17)/2)/S(17) + S(2)*c**S(2)*x**(S(21)/2)/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*b**S(2)*x**(S(11)/2)/S(11) + S(4)*b*c*x**(S(15)/2)/S(15) + S(2)*c**S(2)*x**(S(19)/2)/S(19), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/sqrt(x), x), x, S(2)*b**S(2)*x**(S(9)/2)/S(9) + S(4)*b*c*x**(S(13)/2)/S(13) + S(2)*c**S(2)*x**(S(17)/2)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**(S(3)/2), x), x, S(2)*b**S(2)*x**(S(7)/2)/S(7) + S(4)*b*c*x**(S(11)/2)/S(11) + S(2)*c**S(2)*x**(S(15)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**(S(5)/2), x), x, S(2)*b**S(2)*x**(S(5)/2)/S(5) + S(4)*b*c*x**(S(9)/2)/S(9) + S(2)*c**S(2)*x**(S(13)/2)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(2)/x**(S(7)/2), x), x, S(2)*b**S(2)*x**(S(3)/2)/S(3) + S(4)*b*c*x**(S(7)/2)/S(7) + S(2)*c**S(2)*x**(S(11)/2)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)*(b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*b**S(3)*x**(S(21)/2)/S(21) + S(6)*b**S(2)*c*x**(S(25)/2)/S(25) + S(6)*b*c**S(2)*x**(S(29)/2)/S(29) + S(2)*c**S(3)*x**(S(33)/2)/S(33), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*(b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*b**S(3)*x**(S(19)/2)/S(19) + S(6)*b**S(2)*c*x**(S(23)/2)/S(23) + S(2)*b*c**S(2)*x**(S(27)/2)/S(9) + S(2)*c**S(3)*x**(S(31)/2)/S(31), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*b**S(3)*x**(S(17)/2)/S(17) + S(2)*b**S(2)*c*x**(S(21)/2)/S(7) + S(6)*b*c**S(2)*x**(S(25)/2)/S(25) + S(2)*c**S(3)*x**(S(29)/2)/S(29), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*b**S(3)*x**(S(15)/2)/S(15) + S(6)*b**S(2)*c*x**(S(19)/2)/S(19) + S(6)*b*c**S(2)*x**(S(23)/2)/S(23) + S(2)*c**S(3)*x**(S(27)/2)/S(27), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/sqrt(x), x), x, S(2)*b**S(3)*x**(S(13)/2)/S(13) + S(6)*b**S(2)*c*x**(S(17)/2)/S(17) + S(2)*b*c**S(2)*x**(S(21)/2)/S(7) + S(2)*c**S(3)*x**(S(25)/2)/S(25), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**(S(3)/2), x), x, S(2)*b**S(3)*x**(S(11)/2)/S(11) + S(2)*b**S(2)*c*x**(S(15)/2)/S(5) + S(6)*b*c**S(2)*x**(S(19)/2)/S(19) + S(2)*c**S(3)*x**(S(23)/2)/S(23), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**(S(5)/2), x), x, S(2)*b**S(3)*x**(S(9)/2)/S(9) + S(6)*b**S(2)*c*x**(S(13)/2)/S(13) + S(6)*b*c**S(2)*x**(S(17)/2)/S(17) + S(2)*c**S(3)*x**(S(21)/2)/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**S(3)/x**(S(7)/2), x), x, S(2)*b**S(3)*x**(S(7)/2)/S(7) + S(6)*b**S(2)*c*x**(S(11)/2)/S(11) + S(2)*b*c**S(2)*x**(S(15)/2)/S(5) + S(2)*c**S(3)*x**(S(19)/2)/S(19), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)/(b*x**S(2) + c*x**S(4)), x), x, sqrt(S(2))*b**(S(7)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(11)/4)) - sqrt(S(2))*b**(S(7)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(11)/4)) - sqrt(S(2))*b**(S(7)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(11)/4)) + sqrt(S(2))*b**(S(7)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(11)/4)) - S(2)*b*x**(S(3)/2)/(S(3)*c**S(2)) + S(2)*x**(S(7)/2)/(S(7)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(11)/2)/(b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*b**(S(5)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(9)/4)) + sqrt(S(2))*b**(S(5)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(9)/4)) - sqrt(S(2))*b**(S(5)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(9)/4)) + sqrt(S(2))*b**(S(5)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(9)/4)) - S(2)*b*sqrt(x)/c**S(2) + S(2)*x**(S(5)/2)/(S(5)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/(b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*b**(S(3)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(7)/4)) + sqrt(S(2))*b**(S(3)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(7)/4)) + sqrt(S(2))*b**(S(3)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(7)/4)) - sqrt(S(2))*b**(S(3)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(7)/4)) + S(2)*x**(S(3)/2)/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/(b*x**S(2) + c*x**S(4)), x), x, sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(5)/4)) - sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*c**(S(5)/4)) + sqrt(S(2))*b**(S(1)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(5)/4)) - sqrt(S(2))*b**(S(1)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*c**(S(5)/4)) + S(2)*sqrt(x)/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/(b*x**S(2) + c*x**S(4)), x), x, sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(1)/4)*c**(S(3)/4)) - sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(1)/4)*c**(S(3)/4)) - sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(1)/4)*c**(S(3)/4)) + sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(1)/4)*c**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(3)/4)*c**(S(1)/4)) + sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(3)/4)*c**(S(1)/4)) - sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(3)/4)*c**(S(1)/4)) + sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(3)/4)*c**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(b*x**S(2) + c*x**S(4)), x), x, -S(2)/(b*sqrt(x)) - sqrt(S(2))*c**(S(1)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(5)/4)) + sqrt(S(2))*c**(S(1)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(5)/4)) + sqrt(S(2))*c**(S(1)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(5)/4)) - sqrt(S(2))*c**(S(1)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(b*x**S(2) + c*x**S(4))), x), x, -S(2)/(S(3)*b*x**(S(3)/2)) + sqrt(S(2))*c**(S(3)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(7)/4)) - sqrt(S(2))*c**(S(3)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(7)/4)) + sqrt(S(2))*c**(S(3)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(7)/4)) - sqrt(S(2))*c**(S(3)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(7)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*(b*x**S(2) + c*x**S(4))), x), x, -S(2)/(S(5)*b*x**(S(5)/2)) + S(2)*c/(b**S(2)*sqrt(x)) + sqrt(S(2))*c**(S(5)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(9)/4)) - sqrt(S(2))*c**(S(5)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(9)/4)) - sqrt(S(2))*c**(S(5)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(9)/4)) + sqrt(S(2))*c**(S(5)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(9)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(5)/2)*(b*x**S(2) + c*x**S(4))), x), x, -S(2)/(S(7)*b*x**(S(7)/2)) + S(2)*c/(S(3)*b**S(2)*x**(S(3)/2)) - sqrt(S(2))*c**(S(7)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(11)/4)) + sqrt(S(2))*c**(S(7)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(11)/4)) - sqrt(S(2))*c**(S(7)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(11)/4)) + sqrt(S(2))*c**(S(7)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(11)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(7)/2)*(b*x**S(2) + c*x**S(4))), x), x, -S(2)/(S(9)*b*x**(S(9)/2)) + S(2)*c/(S(5)*b**S(2)*x**(S(5)/2)) - S(2)*c**S(2)/(b**S(3)*sqrt(x)) - sqrt(S(2))*c**(S(9)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(13)/4)) + sqrt(S(2))*c**(S(9)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(4)*b**(S(13)/4)) + sqrt(S(2))*c**(S(9)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(13)/4)) - sqrt(S(2))*c**(S(9)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(2)*b**(S(13)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(19)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -S(9)*sqrt(S(2))*b**(S(5)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*c**(S(13)/4)) + S(9)*sqrt(S(2))*b**(S(5)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*c**(S(13)/4)) - S(9)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*c**(S(13)/4)) + S(9)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*c**(S(13)/4)) - S(9)*b*sqrt(x)/(S(2)*c**S(3)) - x**(S(9)/2)/(S(2)*c*(b + c*x**S(2))) + S(9)*x**(S(5)/2)/(S(10)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(17)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -S(7)*sqrt(S(2))*b**(S(3)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*c**(S(11)/4)) + S(7)*sqrt(S(2))*b**(S(3)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*c**(S(11)/4)) + S(7)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*c**(S(11)/4)) - S(7)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*c**(S(11)/4)) - x**(S(7)/2)/(S(2)*c*(b + c*x**S(2))) + S(7)*x**(S(3)/2)/(S(6)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(15)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, S(5)*sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*c**(S(9)/4)) - S(5)*sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*c**(S(9)/4)) + S(5)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*c**(S(9)/4)) - S(5)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*c**(S(9)/4)) - x**(S(5)/2)/(S(2)*c*(b + c*x**S(2))) + S(5)*sqrt(x)/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -x**(S(3)/2)/(S(2)*c*(b + c*x**S(2))) + S(3)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(1)/4)*c**(S(7)/4)) - S(3)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(1)/4)*c**(S(7)/4)) - S(3)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(1)/4)*c**(S(7)/4)) + S(3)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(1)/4)*c**(S(7)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(11)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, -sqrt(x)/(S(2)*c*(b + c*x**S(2))) - sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(3)/4)*c**(S(5)/4)) + sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(3)/4)*c**(S(5)/4)) - sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(3)/4)*c**(S(5)/4)) + sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(3)/4)*c**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, x**(S(3)/2)/(S(2)*b*(b + c*x**S(2))) + sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(5)/4)*c**(S(3)/4)) - sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(5)/4)*c**(S(3)/4)) - sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(5)/4)*c**(S(3)/4)) + sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(5)/4)*c**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, sqrt(x)/(S(2)*b*(b + c*x**S(2))) - S(3)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(7)/4)*c**(S(1)/4)) + S(3)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(7)/4)*c**(S(1)/4)) - S(3)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(7)/4)*c**(S(1)/4)) + S(3)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(7)/4)*c**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, S(1)/(S(2)*b*sqrt(x)*(b + c*x**S(2))) - S(5)/(S(2)*b**S(2)*sqrt(x)) - S(5)*sqrt(S(2))*c**(S(1)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(9)/4)) + S(5)*sqrt(S(2))*c**(S(1)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(9)/4)) + S(5)*sqrt(S(2))*c**(S(1)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(9)/4)) - S(5)*sqrt(S(2))*c**(S(1)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(9)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(b*x**S(2) + c*x**S(4))**S(2), x), x, S(1)/(S(2)*b*x**(S(3)/2)*(b + c*x**S(2))) - S(7)/(S(6)*b**S(2)*x**(S(3)/2)) + S(7)*sqrt(S(2))*c**(S(3)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(11)/4)) - S(7)*sqrt(S(2))*c**(S(3)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(11)/4)) + S(7)*sqrt(S(2))*c**(S(3)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(11)/4)) - S(7)*sqrt(S(2))*c**(S(3)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(11)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(b*x**S(2) + c*x**S(4))**S(2), x), x, S(1)/(S(2)*b*x**(S(5)/2)*(b + c*x**S(2))) - S(9)/(S(10)*b**S(2)*x**(S(5)/2)) + S(9)*c/(S(2)*b**S(3)*sqrt(x)) + S(9)*sqrt(S(2))*c**(S(5)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(13)/4)) - S(9)*sqrt(S(2))*c**(S(5)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(13)/4)) - S(9)*sqrt(S(2))*c**(S(5)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(13)/4)) + S(9)*sqrt(S(2))*c**(S(5)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(13)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(b*x**S(2) + c*x**S(4))**S(2)), x), x, S(1)/(S(2)*b*x**(S(7)/2)*(b + c*x**S(2))) - S(11)/(S(14)*b**S(2)*x**(S(7)/2)) + S(11)*c/(S(6)*b**S(3)*x**(S(3)/2)) - S(11)*sqrt(S(2))*c**(S(7)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(15)/4)) + S(11)*sqrt(S(2))*c**(S(7)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(15)/4)) - S(11)*sqrt(S(2))*c**(S(7)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(15)/4)) + S(11)*sqrt(S(2))*c**(S(7)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(15)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*(b*x**S(2) + c*x**S(4))**S(2)), x), x, S(1)/(S(2)*b*x**(S(9)/2)*(b + c*x**S(2))) - S(13)/(S(18)*b**S(2)*x**(S(9)/2)) + S(13)*c/(S(10)*b**S(3)*x**(S(5)/2)) - S(13)*c**S(2)/(S(2)*b**S(4)*sqrt(x)) - S(13)*sqrt(S(2))*c**(S(9)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(17)/4)) + S(13)*sqrt(S(2))*c**(S(9)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(16)*b**(S(17)/4)) + S(13)*sqrt(S(2))*c**(S(9)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(17)/4)) - S(13)*sqrt(S(2))*c**(S(9)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(8)*b**(S(17)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(23)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(45)*sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*c**(S(13)/4)) - S(45)*sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*c**(S(13)/4)) + S(45)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*c**(S(13)/4)) - S(45)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*c**(S(13)/4)) - x**(S(9)/2)/(S(4)*c*(b + c*x**S(2))**S(2)) - S(9)*x**(S(5)/2)/(S(16)*c**S(2)*(b + c*x**S(2))) + S(45)*sqrt(x)/(S(16)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(21)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -x**(S(7)/2)/(S(4)*c*(b + c*x**S(2))**S(2)) - S(7)*x**(S(3)/2)/(S(16)*c**S(2)*(b + c*x**S(2))) + S(21)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(1)/4)*c**(S(11)/4)) - S(21)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(1)/4)*c**(S(11)/4)) - S(21)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(1)/4)*c**(S(11)/4)) + S(21)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(1)/4)*c**(S(11)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(19)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -x**(S(5)/2)/(S(4)*c*(b + c*x**S(2))**S(2)) - S(5)*sqrt(x)/(S(16)*c**S(2)*(b + c*x**S(2))) - S(5)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(3)/4)*c**(S(9)/4)) + S(5)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(3)/4)*c**(S(9)/4)) - S(5)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(3)/4)*c**(S(9)/4)) + S(5)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(3)/4)*c**(S(9)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(17)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -x**(S(3)/2)/(S(4)*c*(b + c*x**S(2))**S(2)) + S(3)*x**(S(3)/2)/(S(16)*b*c*(b + c*x**S(2))) + S(3)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(5)/4)*c**(S(7)/4)) - S(3)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(5)/4)*c**(S(7)/4)) - S(3)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(5)/4)*c**(S(7)/4)) + S(3)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(5)/4)*c**(S(7)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(15)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, -sqrt(x)/(S(4)*c*(b + c*x**S(2))**S(2)) + sqrt(x)/(S(16)*b*c*(b + c*x**S(2))) - S(3)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(7)/4)*c**(S(5)/4)) + S(3)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(7)/4)*c**(S(5)/4)) - S(3)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(7)/4)*c**(S(5)/4)) + S(3)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(7)/4)*c**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, x**(S(3)/2)/(S(4)*b*(b + c*x**S(2))**S(2)) + S(5)*x**(S(3)/2)/(S(16)*b**S(2)*(b + c*x**S(2))) + S(5)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(9)/4)*c**(S(3)/4)) - S(5)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(9)/4)*c**(S(3)/4)) - S(5)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(9)/4)*c**(S(3)/4)) + S(5)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(9)/4)*c**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(11)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, sqrt(x)/(S(4)*b*(b + c*x**S(2))**S(2)) + S(7)*sqrt(x)/(S(16)*b**S(2)*(b + c*x**S(2))) - S(21)*sqrt(S(2))*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(11)/4)*c**(S(1)/4)) + S(21)*sqrt(S(2))*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(11)/4)*c**(S(1)/4)) - S(21)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(11)/4)*c**(S(1)/4)) + S(21)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(11)/4)*c**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*sqrt(x)*(b + c*x**S(2))**S(2)) + S(9)/(S(16)*b**S(2)*sqrt(x)*(b + c*x**S(2))) - S(45)/(S(16)*b**S(3)*sqrt(x)) - S(45)*sqrt(S(2))*c**(S(1)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(13)/4)) + S(45)*sqrt(S(2))*c**(S(1)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(13)/4)) + S(45)*sqrt(S(2))*c**(S(1)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(13)/4)) - S(45)*sqrt(S(2))*c**(S(1)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(13)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*x**(S(3)/2)*(b + c*x**S(2))**S(2)) + S(11)/(S(16)*b**S(2)*x**(S(3)/2)*(b + c*x**S(2))) - S(77)/(S(48)*b**S(3)*x**(S(3)/2)) + S(77)*sqrt(S(2))*c**(S(3)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(15)/4)) - S(77)*sqrt(S(2))*c**(S(3)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(15)/4)) + S(77)*sqrt(S(2))*c**(S(3)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(15)/4)) - S(77)*sqrt(S(2))*c**(S(3)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(15)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*x**(S(5)/2)*(b + c*x**S(2))**S(2)) + S(13)/(S(16)*b**S(2)*x**(S(5)/2)*(b + c*x**S(2))) - S(117)/(S(80)*b**S(3)*x**(S(5)/2)) + S(117)*c/(S(16)*b**S(4)*sqrt(x)) + S(117)*sqrt(S(2))*c**(S(5)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(17)/4)) - S(117)*sqrt(S(2))*c**(S(5)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(17)/4)) - S(117)*sqrt(S(2))*c**(S(5)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(17)/4)) + S(117)*sqrt(S(2))*c**(S(5)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(17)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*x**(S(7)/2)*(b + c*x**S(2))**S(2)) + S(15)/(S(16)*b**S(2)*x**(S(7)/2)*(b + c*x**S(2))) - S(165)/(S(112)*b**S(3)*x**(S(7)/2)) + S(55)*c/(S(16)*b**S(4)*x**(S(3)/2)) - S(165)*sqrt(S(2))*c**(S(7)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(19)/4)) + S(165)*sqrt(S(2))*c**(S(7)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(19)/4)) - S(165)*sqrt(S(2))*c**(S(7)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(19)/4)) + S(165)*sqrt(S(2))*c**(S(7)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(19)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(b*x**S(2) + c*x**S(4))**S(3), x), x, S(1)/(S(4)*b*x**(S(9)/2)*(b + c*x**S(2))**S(2)) + S(17)/(S(16)*b**S(2)*x**(S(9)/2)*(b + c*x**S(2))) - S(221)/(S(144)*b**S(3)*x**(S(9)/2)) + S(221)*c/(S(80)*b**S(4)*x**(S(5)/2)) - S(221)*c**S(2)/(S(16)*b**S(5)*sqrt(x)) - S(221)*sqrt(S(2))*c**(S(9)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(21)/4)) + S(221)*sqrt(S(2))*c**(S(9)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(21)/4)) + S(221)*sqrt(S(2))*c**(S(9)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(21)/4)) - S(221)*sqrt(S(2))*c**(S(9)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(21)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(b*x**S(2) + c*x**S(4))**S(3)), x), x, S(1)/(S(4)*b*x**(S(11)/2)*(b + c*x**S(2))**S(2)) + S(19)/(S(16)*b**S(2)*x**(S(11)/2)*(b + c*x**S(2))) - S(285)/(S(176)*b**S(3)*x**(S(11)/2)) + S(285)*c/(S(112)*b**S(4)*x**(S(7)/2)) - S(95)*c**S(2)/(S(16)*b**S(5)*x**(S(3)/2)) + S(285)*sqrt(S(2))*c**(S(11)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(23)/4)) - S(285)*sqrt(S(2))*c**(S(11)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*sqrt(x) + sqrt(b) + sqrt(c)*x)/(S(128)*b**(S(23)/4)) + S(285)*sqrt(S(2))*c**(S(11)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(23)/4)) - S(285)*sqrt(S(2))*c**(S(11)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*sqrt(x)/b**(S(1)/4))/(S(64)*b**(S(23)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)*sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(28)*b**(S(13)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(195)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(14)*b**(S(13)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(195)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(28)*b**S(3)*x**(S(3)/2)*(b + c*x**S(2))/(S(195)*c**(S(5)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(28)*b**S(2)*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/(S(585)*c**S(2)) + S(4)*b*x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(117)*c) + S(2)*x**(S(9)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4)), x), x, S(10)*b**(S(11)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(231)*c**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(20)*b**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(231)*c**S(2)*sqrt(x)) + S(4)*b*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*c) + S(2)*x**(S(7)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4)), x), x, S(4)*b**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(2)*b**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(4)*b**S(2)*x**(S(3)/2)*(b + c*x**S(2))/(S(15)*c**(S(3)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*b*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/(S(45)*c) + S(2)*x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(2)*b**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(21)*c**(S(5)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(21)*c*sqrt(x)) + S(2)*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/sqrt(x), x), x, -S(4)*b**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*b**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*b*x**(S(3)/2)*(b + c*x**S(2))/(S(5)*sqrt(c)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**(S(3)/2), x), x, S(2)*b**(S(3)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(3)*c**(S(1)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**(S(5)/2), x), x, -S(4)*b**(S(1)/4)*c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/sqrt(b*x**S(2) + c*x**S(4)) + S(2)*b**(S(1)/4)*c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/sqrt(b*x**S(2) + c*x**S(4)) + S(4)*sqrt(c)*x**(S(3)/2)*(b + c*x**S(2))/((sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(2)*sqrt(b*x**S(2) + c*x**S(4))/x**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**(S(7)/2), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*x**(S(5)/2)) + S(2)*c**(S(3)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(3)*b**(S(1)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**(S(9)/2), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*x**(S(7)/2)) + S(4)*c**(S(3)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(5)*b*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b*x**(S(3)/2)) - S(4)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*b**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*b**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**(S(11)/2), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*x**(S(9)/2)) - S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(21)*b*x**(S(5)/2)) - S(2)*c**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(21)*b**(S(5)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**(S(13)/2), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(9)*x**(S(11)/2)) - S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(45)*b*x**(S(7)/2)) - S(4)*c**(S(5)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(15)*b**S(2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(15)*b**S(2)*x**(S(3)/2)) + S(4)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(2)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(b*x**S(2) + c*x**S(4))/x**(S(15)/2), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(11)*x**(S(13)/2)) - S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*b*x**(S(9)/2)) + S(20)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(231)*b**S(2)*x**(S(5)/2)) + S(10)*c**(S(11)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(231)*b**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(56)*b**(S(17)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(1105)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(28)*b**(S(17)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(1105)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(56)*b**S(4)*x**(S(3)/2)*(b + c*x**S(2))/(S(1105)*c**(S(5)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(56)*b**S(3)*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/(S(3315)*c**S(2)) + S(8)*b**S(2)*x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(663)*c) + S(12)*b*x**(S(9)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(221) + S(2)*x**(S(5)/2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(4)*b**(S(15)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(231)*c**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(8)*b**S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(231)*c**S(2)*sqrt(x)) + S(8)*b**S(2)*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(385)*c) + S(4)*b*x**(S(7)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(55) + S(2)*x**(S(3)/2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/sqrt(x), x), x, S(8)*b**(S(13)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(65)*c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(4)*b**(S(13)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(65)*c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(8)*b**S(3)*x**(S(3)/2)*(b + c*x**S(2))/(S(65)*c**(S(3)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(8)*b**S(2)*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/(S(195)*c) + S(4)*b*x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(39) + S(2)*sqrt(x)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(3)/2), x), x, -S(4)*b**(S(11)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(77)*c**(S(5)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(8)*b**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*c*sqrt(x)) + S(12)*b*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))/S(77) + S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(11)*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(5)/2), x), x, -S(8)*b**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*b**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(8)*b**S(2)*x**(S(3)/2)*(b + c*x**S(2))/(S(15)*sqrt(c)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*b*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/S(15) + S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(9)*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(7)/2), x), x, S(4)*b**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(7)*c**(S(1)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*sqrt(x)) + S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(7)*x**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(9)/2), x), x, -S(24)*b**(S(5)/4)*c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*sqrt(b*x**S(2) + c*x**S(4))) + S(12)*b**(S(5)/4)*c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*sqrt(b*x**S(2) + c*x**S(4))) + S(24)*b*sqrt(c)*x**(S(3)/2)*(b + c*x**S(2))/((S(5)*sqrt(b) + S(5)*sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(12)*c*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/S(5) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(7)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(11)/2), x), x, S(4)*b**(S(3)/4)*c**(S(3)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(3)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*sqrt(x)) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(3)*x**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(13)/2), x), x, -S(24)*b**(S(1)/4)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*sqrt(b*x**S(2) + c*x**S(4))) + S(12)*b**(S(1)/4)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*sqrt(b*x**S(2) + c*x**S(4))) + S(24)*c**(S(3)/2)*x**(S(3)/2)*(b + c*x**S(2))/((S(5)*sqrt(b) + S(5)*sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(12)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*x**(S(3)/2)) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(5)*x**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(15)/2), x), x, -S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*x**(S(5)/2)) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(7)*x**(S(13)/2)) + S(4)*c**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(7)*b**(S(1)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(17)/2), x), x, -S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(15)*x**(S(7)/2)) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(9)*x**(S(15)/2)) + S(8)*c**(S(5)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(15)*b*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(8)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(15)*b*x**(S(3)/2)) - S(8)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*b**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(4)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*b**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(19)/2), x), x, -S(12)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*x**(S(9)/2)) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(11)*x**(S(17)/2)) - S(8)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*b*x**(S(5)/2)) - S(4)*c**(S(11)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(77)*b**(S(5)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(21)/2), x), x, -S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(39)*x**(S(11)/2)) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(13)*x**(S(19)/2)) - S(8)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(195)*b*x**(S(7)/2)) - S(8)*c**(S(7)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(65)*b**S(2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(8)*c**S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(65)*b**S(2)*x**(S(3)/2)) + S(8)*c**(S(13)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(65)*b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(4)*c**(S(13)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(65)*b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + c*x**S(4))**(S(3)/2)/x**(S(23)/2), x), x, -S(4)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(55)*x**(S(13)/2)) - S(2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(15)*x**(S(21)/2)) - S(8)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(385)*b*x**(S(9)/2)) + S(8)*c**S(3)*sqrt(b*x**S(2) + c*x**S(4))/(S(231)*b**S(2)*x**(S(5)/2)) + S(4)*c**(S(15)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(231)*b**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(15)*b**(S(11)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(77)*c**(S(13)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(30)*b**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*c**S(3)*sqrt(x)) - S(18)*b*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*c**S(2)) + S(2)*x**(S(7)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(11)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(11)/2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(14)*b**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(7)*b**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(14)*b**S(2)*x**(S(3)/2)*(b + c*x**S(2))/(S(15)*c**(S(5)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(14)*b*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/(S(45)*c**S(2)) + S(2)*x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(9)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, S(5)*b**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(21)*c**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(10)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(21)*c**S(2)*sqrt(x)) + S(2)*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, S(6)*b**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(3)*b**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(6)*b*x**(S(3)/2)*(b + c*x**S(2))/(S(5)*c**(S(3)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -b**(S(3)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(3)*c**(S(5)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*c*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(2)*b**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + b**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(2)*x**(S(3)/2)*(b + c*x**S(2))/(sqrt(c)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/sqrt(b*x**S(2) + c*x**S(4)), x), x, x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(b**(S(1)/4)*c**(S(1)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))), x), x, S(2)*sqrt(c)*x**(S(3)/2)*(b + c*x**S(2))/(b*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(2)*sqrt(b*x**S(2) + c*x**S(4))/(b*x**(S(3)/2)) - S(2)*c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(b**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) + c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(b**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b*x**(S(5)/2)) - c**(S(3)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(3)*b**(S(5)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b*x**(S(7)/2)) - S(6)*c**(S(3)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(5)*b**S(2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(6)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b**S(2)*x**(S(3)/2)) + S(6)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(3)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(7)/2)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*b*x**(S(9)/2)) + S(10)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(21)*b**S(2)*x**(S(5)/2)) + S(5)*c**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(21)*b**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(9)/2)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(9)*b*x**(S(11)/2)) + S(14)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(45)*b**S(2)*x**(S(7)/2)) + S(14)*c**(S(5)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(15)*b**S(3)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(14)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(15)*b**S(3)*x**(S(3)/2)) - S(14)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*b**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(7)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*b**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(11)/2)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(11)*b*x**(S(13)/2)) + S(18)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*b**S(2)*x**(S(9)/2)) - S(30)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(77)*b**S(3)*x**(S(5)/2)) - S(15)*c**(S(11)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(77)*b**(S(13)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(17)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(15)*b**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(14)*c**(S(13)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(15)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*c**S(3)*sqrt(x)) - x**(S(11)/2)/(c*sqrt(b*x**S(2) + c*x**S(4))) + S(9)*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(15)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(21)*b**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(21)*b**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(10)*c**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(21)*b*x**(S(3)/2)*(b + c*x**S(2))/(S(5)*c**(S(5)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - x**(S(9)/2)/(c*sqrt(b*x**S(2) + c*x**S(4))) + S(7)*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(5)*b**(S(3)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(6)*c**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))) - x**(S(7)/2)/(c*sqrt(b*x**S(2) + c*x**S(4))) + S(5)*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*c**S(2)*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(11)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(3)*b**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(3)*b**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(2)*c**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) - x**(S(5)/2)/(c*sqrt(b*x**S(2) + c*x**S(4))) + S(3)*x**(S(3)/2)*(b + c*x**S(2))/(c**(S(3)/2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -x**(S(3)/2)/(c*sqrt(b*x**S(2) + c*x**S(4))) + x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(2)*b**(S(1)/4)*c**(S(5)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, x**(S(5)/2)/(b*sqrt(b*x**S(2) + c*x**S(4))) - x**(S(3)/2)*(b + c*x**S(2))/(b*sqrt(c)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(b**(S(3)/4)*c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))) - x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(2)*b**(S(3)/4)*c**(S(3)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, x**(S(3)/2)/(b*sqrt(b*x**S(2) + c*x**S(4))) + x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(2)*b**(S(5)/4)*c**(S(1)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, sqrt(x)/(b*sqrt(b*x**S(2) + c*x**S(4))) + S(3)*sqrt(c)*x**(S(3)/2)*(b + c*x**S(2))/(b**S(2)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(3)*sqrt(b*x**S(2) + c*x**S(4))/(b**S(2)*x**(S(3)/2)) - S(3)*c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(3)*c**(S(1)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(2)*b**(S(7)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(1)/(b*sqrt(x)*sqrt(b*x**S(2) + c*x**S(4))) - S(5)*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b**S(2)*x**(S(5)/2)) - S(5)*c**(S(3)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(6)*b**(S(9)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(1)/(b*x**(S(3)/2)*sqrt(b*x**S(2) + c*x**S(4))) - S(7)*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b**S(2)*x**(S(7)/2)) - S(21)*c**(S(3)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(5)*b**S(3)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) + S(21)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(5)*b**S(3)*x**(S(3)/2)) + S(21)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(5)*b**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))) - S(21)*c**(S(5)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(10)*b**(S(11)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(1)/(b*x**(S(5)/2)*sqrt(b*x**S(2) + c*x**S(4))) - S(9)*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*b**S(2)*x**(S(9)/2)) + S(15)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(7)*b**S(3)*x**(S(5)/2)) + S(15)*c**(S(7)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(14)*b**(S(13)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(5)/2)*(b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(1)/(b*x**(S(7)/2)*sqrt(b*x**S(2) + c*x**S(4))) - S(11)*sqrt(b*x**S(2) + c*x**S(4))/(S(9)*b**S(2)*x**(S(11)/2)) + S(77)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(45)*b**S(3)*x**(S(7)/2)) + S(77)*c**(S(5)/2)*x**(S(3)/2)*(b + c*x**S(2))/(S(15)*b**S(4)*(sqrt(b) + sqrt(c)*x)*sqrt(b*x**S(2) + c*x**S(4))) - S(77)*c**S(2)*sqrt(b*x**S(2) + c*x**S(4))/(S(15)*b**S(4)*x**(S(3)/2)) - S(77)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_e(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(15)*b**(S(15)/4)*sqrt(b*x**S(2) + c*x**S(4))) + S(77)*c**(S(9)/4)*x*sqrt((b + c*x**S(2))/(sqrt(b) + sqrt(c)*x)**S(2))*(sqrt(b) + sqrt(c)*x)*elliptic_f(S(2)*atan(c**(S(1)/4)*sqrt(x)/b**(S(1)/4)), S(1)/2)/(S(30)*b**(S(15)/4)*sqrt(b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a**S(2)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(2)*a*b*(d*x)**(m + S(3))/(d**S(3)*(m + S(3))) + b**S(2)*(d*x)**(m + S(5))/(d**S(5)*(m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a**S(2)*x**S(4)/S(4) + a*b*x**S(6)/S(3) + b**S(2)*x**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a**S(2)*x**S(3)/S(3) + S(2)*a*b*x**S(5)/S(5) + b**S(2)*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a**S(2)*x**S(2)/S(2) + a*b*x**S(4)/S(2) + b**S(2)*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4), x), x, a**S(2)*x + S(2)*a*b*x**S(3)/S(3) + b**S(2)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x, x), x, a**S(2)*log(x) + a*b*x**S(2) + b**S(2)*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(2), x), x, -a**S(2)/x + S(2)*a*b*x + b**S(2)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(3), x), x, -a**S(2)/(S(2)*x**S(2)) + S(2)*a*b*log(x) + b**S(2)*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(4), x), x, -a**S(2)/(S(3)*x**S(3)) - S(2)*a*b/x + b**S(2)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(5), x), x, -a**S(2)/(S(4)*x**S(4)) - a*b/x**S(2) + b**S(2)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(6), x), x, -a**S(2)/(S(5)*x**S(5)) - S(2)*a*b/(S(3)*x**S(3)) - b**S(2)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(7), x), x, -a**S(2)/(S(6)*x**S(6)) - a*b/(S(2)*x**S(4)) - b**S(2)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(8), x), x, -a**S(2)/(S(7)*x**S(7)) - S(2)*a*b/(S(5)*x**S(5)) - b**S(2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(4)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(4)*a**S(3)*b*(d*x)**(m + S(3))/(d**S(3)*(m + S(3))) + S(6)*a**S(2)*b**S(2)*(d*x)**(m + S(5))/(d**S(5)*(m + S(5))) + S(4)*a*b**S(3)*(d*x)**(m + S(7))/(d**S(7)*(m + S(7))) + b**S(4)*(d*x)**(m + S(9))/(d**S(9)*(m + S(9))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(4)*x**S(7)/S(7) + S(4)*a**S(3)*b*x**S(9)/S(9) + S(6)*a**S(2)*b**S(2)*x**S(11)/S(11) + S(4)*a*b**S(3)*x**S(13)/S(13) + b**S(4)*x**S(15)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(4)*x**S(6)/S(6) + a**S(3)*b*x**S(8)/S(2) + S(3)*a**S(2)*b**S(2)*x**S(10)/S(5) + a*b**S(3)*x**S(12)/S(3) + b**S(4)*x**S(14)/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(4)*x**S(5)/S(5) + S(4)*a**S(3)*b*x**S(7)/S(7) + S(2)*a**S(2)*b**S(2)*x**S(9)/S(3) + S(4)*a*b**S(3)*x**S(11)/S(11) + b**S(4)*x**S(13)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -a*(a + b*x**S(2))**S(5)/(S(10)*b**S(2)) + (a + b*x**S(2))**S(6)/(S(12)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(4)*x**S(3)/S(3) + S(4)*a**S(3)*b*x**S(5)/S(5) + S(6)*a**S(2)*b**S(2)*x**S(7)/S(7) + S(4)*a*b**S(3)*x**S(9)/S(9) + b**S(4)*x**S(11)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, (a + b*x**S(2))**S(5)/(S(10)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(4)*x + S(4)*a**S(3)*b*x**S(3)/S(3) + S(6)*a**S(2)*b**S(2)*x**S(5)/S(5) + S(4)*a*b**S(3)*x**S(7)/S(7) + b**S(4)*x**S(9)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x, x), x, a**S(4)*log(x) + S(2)*a**S(3)*b*x**S(2) + S(3)*a**S(2)*b**S(2)*x**S(4)/S(2) + S(2)*a*b**S(3)*x**S(6)/S(3) + b**S(4)*x**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(2), x), x, -a**S(4)/x + S(4)*a**S(3)*b*x + S(2)*a**S(2)*b**S(2)*x**S(3) + S(4)*a*b**S(3)*x**S(5)/S(5) + b**S(4)*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(3), x), x, -a**S(4)/(S(2)*x**S(2)) + S(4)*a**S(3)*b*log(x) + S(3)*a**S(2)*b**S(2)*x**S(2) + a*b**S(3)*x**S(4) + b**S(4)*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(4), x), x, -a**S(4)/(S(3)*x**S(3)) - S(4)*a**S(3)*b/x + S(6)*a**S(2)*b**S(2)*x + S(4)*a*b**S(3)*x**S(3)/S(3) + b**S(4)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(5), x), x, -a**S(4)/(S(4)*x**S(4)) - S(2)*a**S(3)*b/x**S(2) + S(6)*a**S(2)*b**S(2)*log(x) + S(2)*a*b**S(3)*x**S(2) + b**S(4)*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(6), x), x, -a**S(4)/(S(5)*x**S(5)) - S(4)*a**S(3)*b/(S(3)*x**S(3)) - S(6)*a**S(2)*b**S(2)/x + S(4)*a*b**S(3)*x + b**S(4)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(7), x), x, -a**S(4)/(S(6)*x**S(6)) - a**S(3)*b/x**S(4) - S(3)*a**S(2)*b**S(2)/x**S(2) + S(4)*a*b**S(3)*log(x) + b**S(4)*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(8), x), x, -a**S(4)/(S(7)*x**S(7)) - S(4)*a**S(3)*b/(S(5)*x**S(5)) - S(2)*a**S(2)*b**S(2)/x**S(3) - S(4)*a*b**S(3)/x + b**S(4)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(9), x), x, -a**S(4)/(S(8)*x**S(8)) - S(2)*a**S(3)*b/(S(3)*x**S(6)) - S(3)*a**S(2)*b**S(2)/(S(2)*x**S(4)) - S(2)*a*b**S(3)/x**S(2) + b**S(4)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(10), x), x, -a**S(4)/(S(9)*x**S(9)) - S(4)*a**S(3)*b/(S(7)*x**S(7)) - S(6)*a**S(2)*b**S(2)/(S(5)*x**S(5)) - S(4)*a*b**S(3)/(S(3)*x**S(3)) - b**S(4)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(11), x), x, -(a + b*x**S(2))**S(5)/(S(10)*a*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(12), x), x, -a**S(4)/(S(11)*x**S(11)) - S(4)*a**S(3)*b/(S(9)*x**S(9)) - S(6)*a**S(2)*b**S(2)/(S(7)*x**S(7)) - S(4)*a*b**S(3)/(S(5)*x**S(5)) - b**S(4)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(13), x), x, -(a + b*x**S(2))**S(5)/(S(12)*a*x**S(12)) + b*(a + b*x**S(2))**S(5)/(S(60)*a**S(2)*x**S(10)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(13), x), x, -a**S(4)/(S(12)*x**S(12)) - S(2)*a**S(3)*b/(S(5)*x**S(10)) - S(3)*a**S(2)*b**S(2)/(S(4)*x**S(8)) - S(2)*a*b**S(3)/(S(3)*x**S(6)) - b**S(4)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(14), x), x, -a**S(4)/(S(13)*x**S(13)) - S(4)*a**S(3)*b/(S(11)*x**S(11)) - S(2)*a**S(2)*b**S(2)/(S(3)*x**S(9)) - S(4)*a*b**S(3)/(S(7)*x**S(7)) - b**S(4)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(15), x), x, -a**S(4)/(S(14)*x**S(14)) - a**S(3)*b/(S(3)*x**S(12)) - S(3)*a**S(2)*b**S(2)/(S(5)*x**S(10)) - a*b**S(3)/(S(2)*x**S(8)) - b**S(4)/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/x**S(16), x), x, -a**S(4)/(S(15)*x**S(15)) - S(4)*a**S(3)*b/(S(13)*x**S(13)) - S(6)*a**S(2)*b**S(2)/(S(11)*x**S(11)) - S(4)*a*b**S(3)/(S(9)*x**S(9)) - b**S(4)/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(6)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(6)*a**S(5)*b*(d*x)**(m + S(3))/(d**S(3)*(m + S(3))) + S(15)*a**S(4)*b**S(2)*(d*x)**(m + S(5))/(d**S(5)*(m + S(5))) + S(20)*a**S(3)*b**S(3)*(d*x)**(m + S(7))/(d**S(7)*(m + S(7))) + S(15)*a**S(2)*b**S(4)*(d*x)**(m + S(9))/(d**S(9)*(m + S(9))) + S(6)*a*b**S(5)*(d*x)**(m + S(11))/(d**S(11)*(m + S(11))) + b**S(6)*(d*x)**(m + S(13))/(d**S(13)*(m + S(13))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(6)*x**S(9)/S(9) + S(6)*a**S(5)*b*x**S(11)/S(11) + S(15)*a**S(4)*b**S(2)*x**S(13)/S(13) + S(4)*a**S(3)*b**S(3)*x**S(15)/S(3) + S(15)*a**S(2)*b**S(4)*x**S(17)/S(17) + S(6)*a*b**S(5)*x**S(19)/S(19) + b**S(6)*x**S(21)/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(6)*x**S(8)/S(8) + S(3)*a**S(5)*b*x**S(10)/S(5) + S(5)*a**S(4)*b**S(2)*x**S(12)/S(4) + S(10)*a**S(3)*b**S(3)*x**S(14)/S(7) + S(15)*a**S(2)*b**S(4)*x**S(16)/S(16) + a*b**S(5)*x**S(18)/S(3) + b**S(6)*x**S(20)/S(20), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(6)*x**S(7)/S(7) + S(2)*a**S(5)*b*x**S(9)/S(3) + S(15)*a**S(4)*b**S(2)*x**S(11)/S(11) + S(20)*a**S(3)*b**S(3)*x**S(13)/S(13) + a**S(2)*b**S(4)*x**S(15) + S(6)*a*b**S(5)*x**S(17)/S(17) + b**S(6)*x**S(19)/S(19), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(2)*(a + b*x**S(2))**S(7)/(S(14)*b**S(3)) - a*(a + b*x**S(2))**S(8)/(S(8)*b**S(3)) + (a + b*x**S(2))**S(9)/(S(18)*b**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(6)*x**S(5)/S(5) + S(6)*a**S(5)*b*x**S(7)/S(7) + S(5)*a**S(4)*b**S(2)*x**S(9)/S(3) + S(20)*a**S(3)*b**S(3)*x**S(11)/S(11) + S(15)*a**S(2)*b**S(4)*x**S(13)/S(13) + S(2)*a*b**S(5)*x**S(15)/S(5) + b**S(6)*x**S(17)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -a*(a + b*x**S(2))**S(7)/(S(14)*b**S(2)) + (a + b*x**S(2))**S(8)/(S(16)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(6)*x**S(3)/S(3) + S(6)*a**S(5)*b*x**S(5)/S(5) + S(15)*a**S(4)*b**S(2)*x**S(7)/S(7) + S(20)*a**S(3)*b**S(3)*x**S(9)/S(9) + S(15)*a**S(2)*b**S(4)*x**S(11)/S(11) + S(6)*a*b**S(5)*x**S(13)/S(13) + b**S(6)*x**S(15)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, (a + b*x**S(2))**S(7)/(S(14)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(6)*x + S(2)*a**S(5)*b*x**S(3) + S(3)*a**S(4)*b**S(2)*x**S(5) + S(20)*a**S(3)*b**S(3)*x**S(7)/S(7) + S(5)*a**S(2)*b**S(4)*x**S(9)/S(3) + S(6)*a*b**S(5)*x**S(11)/S(11) + b**S(6)*x**S(13)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x, x), x, a**S(6)*log(x) + S(3)*a**S(5)*b*x**S(2) + S(15)*a**S(4)*b**S(2)*x**S(4)/S(4) + S(10)*a**S(3)*b**S(3)*x**S(6)/S(3) + S(15)*a**S(2)*b**S(4)*x**S(8)/S(8) + S(3)*a*b**S(5)*x**S(10)/S(5) + b**S(6)*x**S(12)/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(2), x), x, -a**S(6)/x + S(6)*a**S(5)*b*x + S(5)*a**S(4)*b**S(2)*x**S(3) + S(4)*a**S(3)*b**S(3)*x**S(5) + S(15)*a**S(2)*b**S(4)*x**S(7)/S(7) + S(2)*a*b**S(5)*x**S(9)/S(3) + b**S(6)*x**S(11)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(3), x), x, -a**S(6)/(S(2)*x**S(2)) + S(6)*a**S(5)*b*log(x) + S(15)*a**S(4)*b**S(2)*x**S(2)/S(2) + S(5)*a**S(3)*b**S(3)*x**S(4) + S(5)*a**S(2)*b**S(4)*x**S(6)/S(2) + S(3)*a*b**S(5)*x**S(8)/S(4) + b**S(6)*x**S(10)/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(4), x), x, -a**S(6)/(S(3)*x**S(3)) - S(6)*a**S(5)*b/x + S(15)*a**S(4)*b**S(2)*x + S(20)*a**S(3)*b**S(3)*x**S(3)/S(3) + S(3)*a**S(2)*b**S(4)*x**S(5) + S(6)*a*b**S(5)*x**S(7)/S(7) + b**S(6)*x**S(9)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(5), x), x, -a**S(6)/(S(4)*x**S(4)) - S(3)*a**S(5)*b/x**S(2) + S(15)*a**S(4)*b**S(2)*log(x) + S(10)*a**S(3)*b**S(3)*x**S(2) + S(15)*a**S(2)*b**S(4)*x**S(4)/S(4) + a*b**S(5)*x**S(6) + b**S(6)*x**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(6), x), x, -a**S(6)/(S(5)*x**S(5)) - S(2)*a**S(5)*b/x**S(3) - S(15)*a**S(4)*b**S(2)/x + S(20)*a**S(3)*b**S(3)*x + S(5)*a**S(2)*b**S(4)*x**S(3) + S(6)*a*b**S(5)*x**S(5)/S(5) + b**S(6)*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(7), x), x, -a**S(6)/(S(6)*x**S(6)) - S(3)*a**S(5)*b/(S(2)*x**S(4)) - S(15)*a**S(4)*b**S(2)/(S(2)*x**S(2)) + S(20)*a**S(3)*b**S(3)*log(x) + S(15)*a**S(2)*b**S(4)*x**S(2)/S(2) + S(3)*a*b**S(5)*x**S(4)/S(2) + b**S(6)*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(8), x), x, -a**S(6)/(S(7)*x**S(7)) - S(6)*a**S(5)*b/(S(5)*x**S(5)) - S(5)*a**S(4)*b**S(2)/x**S(3) - S(20)*a**S(3)*b**S(3)/x + S(15)*a**S(2)*b**S(4)*x + S(2)*a*b**S(5)*x**S(3) + b**S(6)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(9), x), x, -a**S(6)/(S(8)*x**S(8)) - a**S(5)*b/x**S(6) - S(15)*a**S(4)*b**S(2)/(S(4)*x**S(4)) - S(10)*a**S(3)*b**S(3)/x**S(2) + S(15)*a**S(2)*b**S(4)*log(x) + S(3)*a*b**S(5)*x**S(2) + b**S(6)*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(10), x), x, -a**S(6)/(S(9)*x**S(9)) - S(6)*a**S(5)*b/(S(7)*x**S(7)) - S(3)*a**S(4)*b**S(2)/x**S(5) - S(20)*a**S(3)*b**S(3)/(S(3)*x**S(3)) - S(15)*a**S(2)*b**S(4)/x + S(6)*a*b**S(5)*x + b**S(6)*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(11), x), x, -a**S(6)/(S(10)*x**S(10)) - S(3)*a**S(5)*b/(S(4)*x**S(8)) - S(5)*a**S(4)*b**S(2)/(S(2)*x**S(6)) - S(5)*a**S(3)*b**S(3)/x**S(4) - S(15)*a**S(2)*b**S(4)/(S(2)*x**S(2)) + S(6)*a*b**S(5)*log(x) + b**S(6)*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(12), x), x, -a**S(6)/(S(11)*x**S(11)) - S(2)*a**S(5)*b/(S(3)*x**S(9)) - S(15)*a**S(4)*b**S(2)/(S(7)*x**S(7)) - S(4)*a**S(3)*b**S(3)/x**S(5) - S(5)*a**S(2)*b**S(4)/x**S(3) - S(6)*a*b**S(5)/x + b**S(6)*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(13), x), x, -a**S(6)/(S(12)*x**S(12)) - S(3)*a**S(5)*b/(S(5)*x**S(10)) - S(15)*a**S(4)*b**S(2)/(S(8)*x**S(8)) - S(10)*a**S(3)*b**S(3)/(S(3)*x**S(6)) - S(15)*a**S(2)*b**S(4)/(S(4)*x**S(4)) - S(3)*a*b**S(5)/x**S(2) + b**S(6)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(14), x), x, -a**S(6)/(S(13)*x**S(13)) - S(6)*a**S(5)*b/(S(11)*x**S(11)) - S(5)*a**S(4)*b**S(2)/(S(3)*x**S(9)) - S(20)*a**S(3)*b**S(3)/(S(7)*x**S(7)) - S(3)*a**S(2)*b**S(4)/x**S(5) - S(2)*a*b**S(5)/x**S(3) - b**S(6)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(15), x), x, -(a + b*x**S(2))**S(7)/(S(14)*a*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(16), x), x, -a**S(6)/(S(15)*x**S(15)) - S(6)*a**S(5)*b/(S(13)*x**S(13)) - S(15)*a**S(4)*b**S(2)/(S(11)*x**S(11)) - S(20)*a**S(3)*b**S(3)/(S(9)*x**S(9)) - S(15)*a**S(2)*b**S(4)/(S(7)*x**S(7)) - S(6)*a*b**S(5)/(S(5)*x**S(5)) - b**S(6)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(17), x), x, -(a + b*x**S(2))**S(7)/(S(16)*a*x**S(16)) + b*(a + b*x**S(2))**S(7)/(S(112)*a**S(2)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(18), x), x, -a**S(6)/(S(17)*x**S(17)) - S(2)*a**S(5)*b/(S(5)*x**S(15)) - S(15)*a**S(4)*b**S(2)/(S(13)*x**S(13)) - S(20)*a**S(3)*b**S(3)/(S(11)*x**S(11)) - S(5)*a**S(2)*b**S(4)/(S(3)*x**S(9)) - S(6)*a*b**S(5)/(S(7)*x**S(7)) - b**S(6)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(19), x), x, -(a + b*x**S(2))**S(7)/(S(18)*a*x**S(18)) + b*(a + b*x**S(2))**S(7)/(S(72)*a**S(2)*x**S(16)) - b**S(2)*(a + b*x**S(2))**S(7)/(S(504)*a**S(3)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(20), x), x, -a**S(6)/(S(19)*x**S(19)) - S(6)*a**S(5)*b/(S(17)*x**S(17)) - a**S(4)*b**S(2)/x**S(15) - S(20)*a**S(3)*b**S(3)/(S(13)*x**S(13)) - S(15)*a**S(2)*b**S(4)/(S(11)*x**S(11)) - S(2)*a*b**S(5)/(S(3)*x**S(9)) - b**S(6)/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(21), x), x, -a**S(6)/(S(20)*x**S(20)) - a**S(5)*b/(S(3)*x**S(18)) - S(15)*a**S(4)*b**S(2)/(S(16)*x**S(16)) - S(10)*a**S(3)*b**S(3)/(S(7)*x**S(14)) - S(5)*a**S(2)*b**S(4)/(S(4)*x**S(12)) - S(3)*a*b**S(5)/(S(5)*x**S(10)) - b**S(6)/(S(8)*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/x**S(22), x), x, -a**S(6)/(S(21)*x**S(21)) - S(6)*a**S(5)*b/(S(19)*x**S(19)) - S(15)*a**S(4)*b**S(2)/(S(17)*x**S(17)) - S(4)*a**S(3)*b**S(3)/(S(3)*x**S(15)) - S(15)*a**S(2)*b**S(4)/(S(13)*x**S(13)) - S(6)*a*b**S(5)/(S(11)*x**S(11)) - b**S(6)/(S(9)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, (d*x)**(m + S(1))*hyper((S(2), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a**S(2)*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a**S(5)/(S(2)*b**S(6)*(a + b*x**S(2))) + S(5)*a**S(4)*log(a + b*x**S(2))/(S(2)*b**S(6)) - S(2)*a**S(3)*x**S(2)/b**S(5) + S(3)*a**S(2)*x**S(4)/(S(4)*b**S(4)) - a*x**S(6)/(S(3)*b**S(3)) + x**S(8)/(S(8)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -a**S(4)/(S(2)*b**S(5)*(a + b*x**S(2))) - S(2)*a**S(3)*log(a + b*x**S(2))/b**S(5) + S(3)*a**S(2)*x**S(2)/(S(2)*b**S(4)) - a*x**S(4)/(S(2)*b**S(3)) + x**S(6)/(S(6)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a**S(3)/(S(2)*b**S(4)*(a + b*x**S(2))) + S(3)*a**S(2)*log(a + b*x**S(2))/(S(2)*b**S(4)) - a*x**S(2)/b**S(3) + x**S(4)/(S(4)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -a**S(2)/(S(2)*b**S(3)*(a + b*x**S(2))) - a*log(a + b*x**S(2))/b**S(3) + x**S(2)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a/(S(2)*b**S(2)*(a + b*x**S(2))) + log(a + b*x**S(2))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -S(1)/(S(2)*b*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, S(1)/(S(2)*a*(a + b*x**S(2))) + log(x)/a**S(2) - log(a + b*x**S(2))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -b/(S(2)*a**S(2)*(a + b*x**S(2))) - S(1)/(S(2)*a**S(2)*x**S(2)) - S(2)*b*log(x)/a**S(3) + b*log(a + b*x**S(2))/a**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -S(1)/(S(4)*a**S(2)*x**S(4)) + b**S(2)/(S(2)*a**S(3)*(a + b*x**S(2))) + b/(a**S(3)*x**S(2)) + S(3)*b**S(2)*log(x)/a**S(4) - S(3)*b**S(2)*log(a + b*x**S(2))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(9)*a**(S(7)/2)*atan(sqrt(b)*x/sqrt(a))/(S(2)*b**(S(11)/2)) - S(9)*a**S(3)*x/(S(2)*b**S(5)) + S(3)*a**S(2)*x**S(3)/(S(2)*b**S(4)) - S(9)*a*x**S(5)/(S(10)*b**S(3)) - x**S(9)/(S(2)*b*(a + b*x**S(2))) + S(9)*x**S(7)/(S(14)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -S(7)*a**(S(5)/2)*atan(sqrt(b)*x/sqrt(a))/(S(2)*b**(S(9)/2)) + S(7)*a**S(2)*x/(S(2)*b**S(4)) - S(7)*a*x**S(3)/(S(6)*b**S(3)) - x**S(7)/(S(2)*b*(a + b*x**S(2))) + S(7)*x**S(5)/(S(10)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(5)*a**(S(3)/2)*atan(sqrt(b)*x/sqrt(a))/(S(2)*b**(S(7)/2)) - S(5)*a*x/(S(2)*b**S(3)) - x**S(5)/(S(2)*b*(a + b*x**S(2))) + S(5)*x**S(3)/(S(6)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -S(3)*sqrt(a)*atan(sqrt(b)*x/sqrt(a))/(S(2)*b**(S(5)/2)) - x**S(3)/(S(2)*b*(a + b*x**S(2))) + S(3)*x/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -x/(S(2)*b*(a + b*x**S(2))) + atan(sqrt(b)*x/sqrt(a))/(S(2)*sqrt(a)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, x/(S(2)*a*(a + b*x**S(2))) + atan(sqrt(b)*x/sqrt(a))/(S(2)*a**(S(3)/2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, S(1)/(S(2)*a*x*(a + b*x**S(2))) - S(3)/(S(2)*a**S(2)*x) - S(3)*sqrt(b)*atan(sqrt(b)*x/sqrt(a))/(S(2)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, S(1)/(S(2)*a*x**S(3)*(a + b*x**S(2))) - S(5)/(S(6)*a**S(2)*x**S(3)) + S(5)*b/(S(2)*a**S(3)*x) + S(5)*b**(S(3)/2)*atan(sqrt(b)*x/sqrt(a))/(S(2)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, S(1)/(S(2)*a*x**S(5)*(a + b*x**S(2))) - S(7)/(S(10)*a**S(2)*x**S(5)) + S(7)*b/(S(6)*a**S(3)*x**S(3)) - S(7)*b**S(2)/(S(2)*a**S(4)*x) - S(7)*b**(S(5)/2)*atan(sqrt(b)*x/sqrt(a))/(S(2)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, (d*x)**(m + S(1))*hyper((S(4), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a**S(4)*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(5)/(S(6)*b**S(6)*(a + b*x**S(2))**S(3)) - S(5)*a**S(4)/(S(4)*b**S(6)*(a + b*x**S(2))**S(2)) + S(5)*a**S(3)/(b**S(6)*(a + b*x**S(2))) + S(5)*a**S(2)*log(a + b*x**S(2))/b**S(6) - S(2)*a*x**S(2)/b**S(5) + x**S(4)/(S(4)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -a**S(4)/(S(6)*b**S(5)*(a + b*x**S(2))**S(3)) + a**S(3)/(b**S(5)*(a + b*x**S(2))**S(2)) - S(3)*a**S(2)/(b**S(5)*(a + b*x**S(2))) - S(2)*a*log(a + b*x**S(2))/b**S(5) + x**S(2)/(S(2)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a**S(3)/(S(6)*b**S(4)*(a + b*x**S(2))**S(3)) - S(3)*a**S(2)/(S(4)*b**S(4)*(a + b*x**S(2))**S(2)) + S(3)*a/(S(2)*b**S(4)*(a + b*x**S(2))) + log(a + b*x**S(2))/(S(2)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, x**S(6)/(S(6)*a*(a + b*x**S(2))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, a/(S(6)*b**S(2)*(a + b*x**S(2))**S(3)) - S(1)/(S(4)*b**S(2)*(a + b*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -S(1)/(S(6)*b*(a + b*x**S(2))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, S(1)/(S(6)*a*(a + b*x**S(2))**S(3)) + S(1)/(S(4)*a**S(2)*(a + b*x**S(2))**S(2)) + S(1)/(S(2)*a**S(3)*(a + b*x**S(2))) + log(x)/a**S(4) - log(a + b*x**S(2))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, -b/(S(6)*a**S(2)*(a + b*x**S(2))**S(3)) - b/(S(2)*a**S(3)*(a + b*x**S(2))**S(2)) - S(3)*b/(S(2)*a**S(4)*(a + b*x**S(2))) - S(1)/(S(2)*a**S(4)*x**S(2)) - S(4)*b*log(x)/a**S(5) + S(2)*b*log(a + b*x**S(2))/a**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, b**S(2)/(S(6)*a**S(3)*(a + b*x**S(2))**S(3)) + S(3)*b**S(2)/(S(4)*a**S(4)*(a + b*x**S(2))**S(2)) - S(1)/(S(4)*a**S(4)*x**S(4)) + S(3)*b**S(2)/(a**S(5)*(a + b*x**S(2))) + S(2)*b/(a**S(5)*x**S(2)) + S(10)*b**S(2)*log(x)/a**S(6) - S(5)*b**S(2)*log(a + b*x**S(2))/a**S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(12)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -S(231)*a**(S(5)/2)*atan(sqrt(b)*x/sqrt(a))/(S(16)*b**(S(13)/2)) + S(231)*a**S(2)*x/(S(16)*b**S(6)) - S(77)*a*x**S(3)/(S(16)*b**S(5)) - x**S(11)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(11)*x**S(9)/(S(24)*b**S(2)*(a + b*x**S(2))**S(2)) - S(33)*x**S(7)/(S(16)*b**S(3)*(a + b*x**S(2))) + S(231)*x**S(5)/(S(80)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, S(105)*a**(S(3)/2)*atan(sqrt(b)*x/sqrt(a))/(S(16)*b**(S(11)/2)) - S(105)*a*x/(S(16)*b**S(5)) - x**S(9)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(3)*x**S(7)/(S(8)*b**S(2)*(a + b*x**S(2))**S(2)) - S(21)*x**S(5)/(S(16)*b**S(3)*(a + b*x**S(2))) + S(35)*x**S(3)/(S(16)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -S(35)*sqrt(a)*atan(sqrt(b)*x/sqrt(a))/(S(16)*b**(S(9)/2)) - x**S(7)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(7)*x**S(5)/(S(24)*b**S(2)*(a + b*x**S(2))**S(2)) - S(35)*x**S(3)/(S(48)*b**S(3)*(a + b*x**S(2))) + S(35)*x/(S(16)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -x**S(5)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(5)*x**S(3)/(S(24)*b**S(2)*(a + b*x**S(2))**S(2)) - S(5)*x/(S(16)*b**S(3)*(a + b*x**S(2))) + S(5)*atan(sqrt(b)*x/sqrt(a))/(S(16)*sqrt(a)*b**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -x**S(3)/(S(6)*b*(a + b*x**S(2))**S(3)) - x/(S(8)*b**S(2)*(a + b*x**S(2))**S(2)) + x/(S(16)*a*b**S(2)*(a + b*x**S(2))) + atan(sqrt(b)*x/sqrt(a))/(S(16)*a**(S(3)/2)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -x/(S(6)*b*(a + b*x**S(2))**S(3)) + x/(S(24)*a*b*(a + b*x**S(2))**S(2)) + x/(S(16)*a**S(2)*b*(a + b*x**S(2))) + atan(sqrt(b)*x/sqrt(a))/(S(16)*a**(S(5)/2)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(-2)), x), x, x/(S(6)*a*(a + b*x**S(2))**S(3)) + S(5)*x/(S(24)*a**S(2)*(a + b*x**S(2))**S(2)) + S(5)*x/(S(16)*a**S(3)*(a + b*x**S(2))) + S(5)*atan(sqrt(b)*x/sqrt(a))/(S(16)*a**(S(7)/2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, S(1)/(S(6)*a*x*(a + b*x**S(2))**S(3)) + S(7)/(S(24)*a**S(2)*x*(a + b*x**S(2))**S(2)) + S(35)/(S(48)*a**S(3)*x*(a + b*x**S(2))) - S(35)/(S(16)*a**S(4)*x) - S(35)*sqrt(b)*atan(sqrt(b)*x/sqrt(a))/(S(16)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, S(1)/(S(6)*a*x**S(3)*(a + b*x**S(2))**S(3)) + S(3)/(S(8)*a**S(2)*x**S(3)*(a + b*x**S(2))**S(2)) + S(21)/(S(16)*a**S(3)*x**S(3)*(a + b*x**S(2))) - S(35)/(S(16)*a**S(4)*x**S(3)) + S(105)*b/(S(16)*a**S(5)*x) + S(105)*b**(S(3)/2)*atan(sqrt(b)*x/sqrt(a))/(S(16)*a**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, S(1)/(S(6)*a*x**S(5)*(a + b*x**S(2))**S(3)) + S(11)/(S(24)*a**S(2)*x**S(5)*(a + b*x**S(2))**S(2)) + S(33)/(S(16)*a**S(3)*x**S(5)*(a + b*x**S(2))) - S(231)/(S(80)*a**S(4)*x**S(5)) + S(77)*b/(S(16)*a**S(5)*x**S(3)) - S(231)*b**S(2)/(S(16)*a**S(6)*x) - S(231)*b**(S(5)/2)*atan(sqrt(b)*x/sqrt(a))/(S(16)*a**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, (d*x)**(m + S(1))*hyper((S(6), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a**S(6)*d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(15)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(7)/(S(10)*b**S(8)*(a + b*x**S(2))**S(5)) - S(7)*a**S(6)/(S(8)*b**S(8)*(a + b*x**S(2))**S(4)) + S(7)*a**S(5)/(S(2)*b**S(8)*(a + b*x**S(2))**S(3)) - S(35)*a**S(4)/(S(4)*b**S(8)*(a + b*x**S(2))**S(2)) + S(35)*a**S(3)/(S(2)*b**S(8)*(a + b*x**S(2))) + S(21)*a**S(2)*log(a + b*x**S(2))/(S(2)*b**S(8)) - S(3)*a*x**S(2)/b**S(7) + x**S(4)/(S(4)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(13)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -a**S(6)/(S(10)*b**S(7)*(a + b*x**S(2))**S(5)) + S(3)*a**S(5)/(S(4)*b**S(7)*(a + b*x**S(2))**S(4)) - S(5)*a**S(4)/(S(2)*b**S(7)*(a + b*x**S(2))**S(3)) + S(5)*a**S(3)/(b**S(7)*(a + b*x**S(2))**S(2)) - S(15)*a**S(2)/(S(2)*b**S(7)*(a + b*x**S(2))) - S(3)*a*log(a + b*x**S(2))/b**S(7) + x**S(2)/(S(2)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a**S(5)/(S(10)*b**S(6)*(a + b*x**S(2))**S(5)) - S(5)*a**S(4)/(S(8)*b**S(6)*(a + b*x**S(2))**S(4)) + S(5)*a**S(3)/(S(3)*b**S(6)*(a + b*x**S(2))**S(3)) - S(5)*a**S(2)/(S(2)*b**S(6)*(a + b*x**S(2))**S(2)) + S(5)*a/(S(2)*b**S(6)*(a + b*x**S(2))) + log(a + b*x**S(2))/(S(2)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, x**S(10)/(S(10)*a*(a + b*x**S(2))**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, x**S(8)/(S(10)*a*(a + b*x**S(2))**S(5)) + x**S(8)/(S(40)*a**S(2)*(a + b*x**S(2))**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -a**S(2)/(S(10)*b**S(3)*(a + b*x**S(2))**S(5)) + a/(S(4)*b**S(3)*(a + b*x**S(2))**S(4)) - S(1)/(S(6)*b**S(3)*(a + b*x**S(2))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, a/(S(10)*b**S(2)*(a + b*x**S(2))**S(5)) - S(1)/(S(8)*b**S(2)*(a + b*x**S(2))**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -S(1)/(S(10)*b*(a + b*x**S(2))**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, S(1)/(S(10)*a*(a + b*x**S(2))**S(5)) + S(1)/(S(8)*a**S(2)*(a + b*x**S(2))**S(4)) + S(1)/(S(6)*a**S(3)*(a + b*x**S(2))**S(3)) + S(1)/(S(4)*a**S(4)*(a + b*x**S(2))**S(2)) + S(1)/(S(2)*a**S(5)*(a + b*x**S(2))) + log(x)/a**S(6) - log(a + b*x**S(2))/(S(2)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, -b/(S(10)*a**S(2)*(a + b*x**S(2))**S(5)) - b/(S(4)*a**S(3)*(a + b*x**S(2))**S(4)) - b/(S(2)*a**S(4)*(a + b*x**S(2))**S(3)) - b/(a**S(5)*(a + b*x**S(2))**S(2)) - S(5)*b/(S(2)*a**S(6)*(a + b*x**S(2))) - S(1)/(S(2)*a**S(6)*x**S(2)) - S(6)*b*log(x)/a**S(7) + S(3)*b*log(a + b*x**S(2))/a**S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, b**S(2)/(S(10)*a**S(3)*(a + b*x**S(2))**S(5)) + S(3)*b**S(2)/(S(8)*a**S(4)*(a + b*x**S(2))**S(4)) + b**S(2)/(a**S(5)*(a + b*x**S(2))**S(3)) + S(5)*b**S(2)/(S(2)*a**S(6)*(a + b*x**S(2))**S(2)) - S(1)/(S(4)*a**S(6)*x**S(4)) + S(15)*b**S(2)/(S(2)*a**S(7)*(a + b*x**S(2))) + S(3)*b/(a**S(7)*x**S(2)) + S(21)*b**S(2)*log(x)/a**S(8) - S(21)*b**S(2)*log(a + b*x**S(2))/(S(2)*a**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(16)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -S(9009)*a**(S(5)/2)*atan(sqrt(b)*x/sqrt(a))/(S(256)*b**(S(17)/2)) + S(9009)*a**S(2)*x/(S(256)*b**S(8)) - S(3003)*a*x**S(3)/(S(256)*b**S(7)) - x**S(15)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(3)*x**S(13)/(S(16)*b**S(2)*(a + b*x**S(2))**S(4)) - S(13)*x**S(11)/(S(32)*b**S(3)*(a + b*x**S(2))**S(3)) - S(143)*x**S(9)/(S(128)*b**S(4)*(a + b*x**S(2))**S(2)) - S(1287)*x**S(7)/(S(256)*b**S(5)*(a + b*x**S(2))) + S(9009)*x**S(5)/(S(1280)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, S(3003)*a**(S(3)/2)*atan(sqrt(b)*x/sqrt(a))/(S(256)*b**(S(15)/2)) - S(3003)*a*x/(S(256)*b**S(7)) - x**S(13)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(13)*x**S(11)/(S(80)*b**S(2)*(a + b*x**S(2))**S(4)) - S(143)*x**S(9)/(S(480)*b**S(3)*(a + b*x**S(2))**S(3)) - S(429)*x**S(7)/(S(640)*b**S(4)*(a + b*x**S(2))**S(2)) - S(3003)*x**S(5)/(S(1280)*b**S(5)*(a + b*x**S(2))) + S(1001)*x**S(3)/(S(256)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(12)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -S(693)*sqrt(a)*atan(sqrt(b)*x/sqrt(a))/(S(256)*b**(S(13)/2)) - x**S(11)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(11)*x**S(9)/(S(80)*b**S(2)*(a + b*x**S(2))**S(4)) - S(33)*x**S(7)/(S(160)*b**S(3)*(a + b*x**S(2))**S(3)) - S(231)*x**S(5)/(S(640)*b**S(4)*(a + b*x**S(2))**S(2)) - S(231)*x**S(3)/(S(256)*b**S(5)*(a + b*x**S(2))) + S(693)*x/(S(256)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -x**S(9)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(9)*x**S(7)/(S(80)*b**S(2)*(a + b*x**S(2))**S(4)) - S(21)*x**S(5)/(S(160)*b**S(3)*(a + b*x**S(2))**S(3)) - S(21)*x**S(3)/(S(128)*b**S(4)*(a + b*x**S(2))**S(2)) - S(63)*x/(S(256)*b**S(5)*(a + b*x**S(2))) + S(63)*atan(sqrt(b)*x/sqrt(a))/(S(256)*sqrt(a)*b**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -x**S(7)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(7)*x**S(5)/(S(80)*b**S(2)*(a + b*x**S(2))**S(4)) - S(7)*x**S(3)/(S(96)*b**S(3)*(a + b*x**S(2))**S(3)) - S(7)*x/(S(128)*b**S(4)*(a + b*x**S(2))**S(2)) + S(7)*x/(S(256)*a*b**S(4)*(a + b*x**S(2))) + S(7)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(3)/2)*b**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -x**S(5)/(S(10)*b*(a + b*x**S(2))**S(5)) - x**S(3)/(S(16)*b**S(2)*(a + b*x**S(2))**S(4)) - x/(S(32)*b**S(3)*(a + b*x**S(2))**S(3)) + x/(S(128)*a*b**S(3)*(a + b*x**S(2))**S(2)) + S(3)*x/(S(256)*a**S(2)*b**S(3)*(a + b*x**S(2))) + S(3)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(5)/2)*b**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -x**S(3)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(3)*x/(S(80)*b**S(2)*(a + b*x**S(2))**S(4)) + x/(S(160)*a*b**S(2)*(a + b*x**S(2))**S(3)) + x/(S(128)*a**S(2)*b**S(2)*(a + b*x**S(2))**S(2)) + S(3)*x/(S(256)*a**S(3)*b**S(2)*(a + b*x**S(2))) + S(3)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(7)/2)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -x/(S(10)*b*(a + b*x**S(2))**S(5)) + x/(S(80)*a*b*(a + b*x**S(2))**S(4)) + S(7)*x/(S(480)*a**S(2)*b*(a + b*x**S(2))**S(3)) + S(7)*x/(S(384)*a**S(3)*b*(a + b*x**S(2))**S(2)) + S(7)*x/(S(256)*a**S(4)*b*(a + b*x**S(2))) + S(7)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(9)/2)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(-3)), x), x, x/(S(10)*a*(a + b*x**S(2))**S(5)) + S(9)*x/(S(80)*a**S(2)*(a + b*x**S(2))**S(4)) + S(21)*x/(S(160)*a**S(3)*(a + b*x**S(2))**S(3)) + S(21)*x/(S(128)*a**S(4)*(a + b*x**S(2))**S(2)) + S(63)*x/(S(256)*a**S(5)*(a + b*x**S(2))) + S(63)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(11)/2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, S(1)/(S(10)*a*x*(a + b*x**S(2))**S(5)) + S(11)/(S(80)*a**S(2)*x*(a + b*x**S(2))**S(4)) + S(33)/(S(160)*a**S(3)*x*(a + b*x**S(2))**S(3)) + S(231)/(S(640)*a**S(4)*x*(a + b*x**S(2))**S(2)) + S(231)/(S(256)*a**S(5)*x*(a + b*x**S(2))) - S(693)/(S(256)*a**S(6)*x) - S(693)*sqrt(b)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, S(1)/(S(10)*a*x**S(3)*(a + b*x**S(2))**S(5)) + S(13)/(S(80)*a**S(2)*x**S(3)*(a + b*x**S(2))**S(4)) + S(143)/(S(480)*a**S(3)*x**S(3)*(a + b*x**S(2))**S(3)) + S(429)/(S(640)*a**S(4)*x**S(3)*(a + b*x**S(2))**S(2)) + S(3003)/(S(1280)*a**S(5)*x**S(3)*(a + b*x**S(2))) - S(1001)/(S(256)*a**S(6)*x**S(3)) + S(3003)*b/(S(256)*a**S(7)*x) + S(3003)*b**(S(3)/2)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(15)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, S(1)/(S(10)*a*x**S(5)*(a + b*x**S(2))**S(5)) + S(3)/(S(16)*a**S(2)*x**S(5)*(a + b*x**S(2))**S(4)) + S(13)/(S(32)*a**S(3)*x**S(5)*(a + b*x**S(2))**S(3)) + S(143)/(S(128)*a**S(4)*x**S(5)*(a + b*x**S(2))**S(2)) + S(1287)/(S(256)*a**S(5)*x**S(5)*(a + b*x**S(2))) - S(9009)/(S(1280)*a**S(6)*x**S(5)) + S(3003)*b/(S(256)*a**S(7)*x**S(3)) - S(9009)*b**S(2)/(S(256)*a**S(8)*x) - S(9009)*b**(S(5)/2)*atan(sqrt(b)*x/sqrt(a))/(S(256)*a**(S(17)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, x/(S(2)*x**S(2) + S(2)) + atan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, -S(1)/(S(2)*x**S(2) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, -x/(S(2)*x**S(2) + S(2)) + atan(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, log(x**S(2) + S(1))/S(2) + S(1)/(S(2)*x**S(2) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(4) - S(18)*x**S(2) + S(81)), x), x, S(1)/(-S(2)*x**S(2) + S(18)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(4) - S(8)*x**S(2) + S(16)), x), x, log(-x**S(2) + S(4))/S(2) + S(2)/(-x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(2)*a*(d*x)**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*(a + b*x**S(2))*(m**S(2) + S(4)*m + S(3))) + (d*x)**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*(m + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a*x**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(24)*a + S(24)*b*x**S(2)) + x**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(2)*a*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(35)*a + S(35)*b*x**S(2)) + x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a*x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(12)*a + S(12)*b*x**S(2)) + x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(2)*a*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*a + S(15)*b*x**S(2)) + x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, (a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(2)*a*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*a + S(3)*b*x**S(2)) + x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x, x), x, a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(2), x), x, -S(2)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(x*(a + b*x**S(2))) + sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(3), x), x, -a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*x**S(2)*(a + b*x**S(2))) + b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(4), x), x, S(2)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*x**S(3)*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(5), x), x, -(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*a*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(6), x), x, S(2)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*x**S(5)*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(7), x), x, a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(12)*x**S(6)*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(8), x), x, S(2)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(35)*x**S(7)*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(9), x), x, a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(24)*x**S(8)*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(6)*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(10), x), x, S(2)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x**S(9)*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(7)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(11), x), x, a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(40)*x**S(10)*(a + b*x**S(2))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(8)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, a**S(3)*x**S(10)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(560)*a + S(560)*b*x**S(2)) + a**S(2)*x**S(10)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(112) + S(3)*a*x**S(10)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(112) + x**S(10)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(16)*a**S(3)*x**S(9)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(6435)*a + S(6435)*b*x**S(2)) + S(8)*a**S(2)*x**S(9)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(715) + S(2)*a*x**S(9)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(65) + x**S(9)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, a**S(3)*x**S(8)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(280)*a + S(280)*b*x**S(2)) + a**S(2)*x**S(8)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(70) + a*x**S(8)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(28) + x**S(8)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(16)*a**S(3)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3003)*a + S(3003)*b*x**S(2)) + S(8)*a**S(2)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(429) + S(6)*a*x**S(7)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(143) + x**S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, a**S(2)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(24)*b**S(3)) - a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(30)*b**S(3)) + x**S(4)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(16)*a**S(3)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1155)*a + S(1155)*b*x**S(2)) + S(8)*a**S(2)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(231) + S(2)*a*x**S(5)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(33) + x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, -a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(8)*b**S(2)) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(10)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(16)*a**S(3)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(315)*a + S(315)*b*x**S(2)) + S(8)*a**S(2)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(105) + S(2)*a*x**S(3)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(21) + x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, (a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(8)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(16)*a**S(3)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(35)*a + S(35)*b*x**S(2)) + S(8)*a**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(35) + S(6)*a*x*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(35) + x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x, x), x, a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2) + a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(4) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(2), x), x, -S(16)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*x*(a + b*x**S(2))) + S(8)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*x) + S(2)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*x) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(5)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(3), x), x, S(3)*a**S(2)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + S(3)*a*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2) - S(3)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*x**S(2)) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(4), x), x, S(16)*a*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*a + S(3)*b*x**S(2)) + S(2)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(3) + S(8)*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(3) - S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(5), x), x, S(3)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + S(3)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*x**S(4)) + S(3)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2) - (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(6), x), x, -S(16)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*x*(a + b*x**S(2))) + S(2)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*x**S(5)) + S(8)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*x) - S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(7), x), x, -a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*x**S(2)*(a + b*x**S(2))) + a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*x**S(6)) + b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) - S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(12)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(8), x), x, S(16)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(35)*x**S(3)*(a + b*x**S(2))) + S(6)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(35)*x**S(7)) - S(24)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(35)*x**S(3)) - S(11)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(35)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(9), x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(8)*a*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(10), x), x, S(16)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(315)*x**S(5)*(a + b*x**S(2))) + S(2)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(21)*x**S(9)) - S(8)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x**S(5)) - S(13)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(63)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(11), x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(8)*a*x**S(10)) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(40)*a**S(2)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(12), x), x, S(16)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1155)*x**S(7)*(a + b*x**S(2))) + S(2)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(33)*x**S(11)) - S(8)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(165)*x**S(7)) - S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(33)*x**S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(13), x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(12)*a*x**S(12)) + b*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(24)*a**S(2)*x**S(10)) - b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(120)*a**S(3)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(14), x), x, S(16)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3003)*x**S(9)*(a + b*x**S(2))) + S(6)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(143)*x**S(13)) - S(24)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1001)*x**S(9)) - S(17)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(143)*x**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(15), x), x, a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(280)*x**S(10)*(a + b*x**S(2))) + a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(28)*x**S(14)) - b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(56)*x**S(10)) - S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(28)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(16), x), x, S(16)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(6435)*x**S(11)*(a + b*x**S(2))) + S(2)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(65)*x**S(15)) - S(8)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(585)*x**S(11)) - S(19)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(195)*x**S(15)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/x**S(17), x), x, a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(560)*x**S(12)*(a + b*x**S(2))) + S(3)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(112)*x**S(16)) - S(3)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(280)*x**S(12)) - S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(56)*x**S(16)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(13)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a**S(5)*x**S(14)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(11088)*a + S(11088)*b*x**S(2)) + a**S(4)*x**S(14)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(1584) + a**S(3)*x**S(14)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(396) + a**S(2)*x**S(14)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(132) + S(5)*a*x**S(14)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(264) + x**S(14)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(24), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(12)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(256)*a**S(5)*x**S(13)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2028117)*a + S(2028117)*b*x**S(2)) + S(128)*a**S(4)*x**S(13)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(156009) + S(160)*a**S(3)*x**S(13)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(52003) + S(80)*a**S(2)*x**S(13)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(9177) + S(10)*a*x**S(13)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(483) + x**S(13)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(23), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a**S(5)*x**S(12)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5544)*a + S(5544)*b*x**S(2)) + a**S(4)*x**S(12)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(924) + a**S(3)*x**S(12)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(264) + a**S(2)*x**S(12)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(99) + a*x**S(12)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(44) + x**S(12)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(22), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(256)*a**S(5)*x**S(11)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(969969)*a + S(969969)*b*x**S(2)) + S(128)*a**S(4)*x**S(11)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(88179) + S(32)*a**S(3)*x**S(11)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(6783) + S(80)*a**S(2)*x**S(11)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(6783) + S(10)*a*x**S(11)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(399) + x**S(11)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a**S(4)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(360)*b**S(5)) - a**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(7)/2)/(S(420)*b**S(5)) + a**S(2)*x**S(4)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(120)*b**S(3)) - a*x**S(6)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(45)*b**S(2)) + x**S(8)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(20)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(256)*a**S(5)*x**S(9)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(415701)*a + S(415701)*b*x**S(2)) + S(128)*a**S(4)*x**S(9)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(46189) + S(32)*a**S(3)*x**S(9)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(4199) + S(16)*a**S(2)*x**S(9)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(969) + S(10)*a*x**S(9)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(323) + x**S(9)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(19), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, -a**S(3)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(144)*b**S(4)) + a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(7)/2)/(S(168)*b**S(4)) - a*x**S(4)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(48)*b**S(2)) + x**S(6)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(18)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(256)*a**S(5)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(153153)*a + S(153153)*b*x**S(2)) + S(128)*a**S(4)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(21879) + S(32)*a**S(3)*x**S(7)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2431) + S(16)*a**S(2)*x**S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(663) + S(2)*a*x**S(7)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(51) + x**S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a**S(2)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(48)*b**S(3)) - a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(7)/2)/(S(56)*b**S(3)) + x**S(4)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(16)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(256)*a**S(5)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(45045)*a + S(45045)*b*x**S(2)) + S(128)*a**S(4)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(9009) + S(32)*a**S(3)*x**S(5)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(1287) + S(16)*a**S(2)*x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(429) + S(2)*a*x**S(5)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(39) + x**S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, -a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(12)*b**S(2)) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(7)/2)/(S(14)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(256)*a**S(5)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(9009)*a + S(9009)*b*x**S(2)) + S(128)*a**S(4)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(3003) + S(160)*a**S(3)*x**S(3)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(3003) + S(80)*a**S(2)*x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(1287) + S(10)*a*x**S(3)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(143) + x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, (a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(256)*a**S(5)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(693)*a + S(693)*b*x**S(2)) + S(128)*a**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(693) + S(32)*a**S(3)*x*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(231) + S(80)*a**S(2)*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(693) + S(10)*a*x*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(99) + x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x, x), x, a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2) + a**S(3)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(4) + a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(6) + a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(8) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(2), x), x, -S(256)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x*(a + b*x**S(2))) + S(128)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x) + S(32)*a**S(3)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x) + S(16)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(63)*x) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(63)*x) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(9)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(3), x), x, S(5)*a**S(4)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + S(5)*a**S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2) + S(5)*a**S(2)*b*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(4) + S(5)*a*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(6) - S(5)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(8)*x**S(2)) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(8)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(4), x), x, S(256)*a**S(3)*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(21)*a + S(21)*b*x**S(2)) + S(128)*a**S(2)*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(21) + S(32)*a*b**S(2)*x*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(7) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(3)*x**S(3)) + S(80)*b**S(2)*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(21) - S(11)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(5), x), x, S(10)*a**S(3)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + S(5)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)) + S(5)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2) + S(5)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(4)*x**S(4)) + S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/S(3) - S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(2)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(6), x), x, -S(256)*a**S(3)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*x*(a + b*x**S(2))) + S(128)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*x) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*x) + S(2)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(3)*x**S(5)) + S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(15)*x) - S(13)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(15)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(7), x), x, S(10)*a**S(2)*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + S(5)*a*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)) - S(5)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*x**S(2)) + S(5)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(12)*x**S(6)) + S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(6)*x**S(2)) - S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(12)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(8), x), x, S(256)*a*b**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(21)*a + S(21)*b*x**S(2)) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(7)*x**S(3)) + S(2)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(7)*x**S(7)) + S(128)*b**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(21) - S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(3)*x**S(3)) - S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(9), x), x, S(5)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) + S(5)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*x**S(4)) + S(5)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(24)*x**S(8)) + S(5)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/S(2) - S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(3)*x**S(4)) - (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(3)*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(10), x), x, -S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x*(a + b*x**S(2))) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x**S(5)) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(63)*x**S(9)) + S(128)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(63)*x) - S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(21)*x**S(5)) - S(17)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(63)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(11), x), x, -a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*x**S(2)*(a + b*x**S(2))) + a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*x**S(6)) + a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(8)*x**S(10)) + b**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*log(x)/(a + b*x**S(2)) - S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(12)*x**S(6)) - S(9)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(40)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(12), x), x, S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(693)*x**S(3)*(a + b*x**S(2))) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(231)*x**S(7)) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(99)*x**S(11)) - S(128)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(231)*x**S(3)) - S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(63)*x**S(7)) - S(19)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(99)*x**S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(13), x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(12)*a*x**S(12)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(14), x), x, S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(9009)*x**S(5)*(a + b*x**S(2))) + S(160)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3003)*x**S(9)) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(143)*x**S(13)) - S(640)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(9009)*x**S(5)) - S(80)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(693)*x**S(9)) - S(21)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(143)*x**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(15), x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(12)*a*x**S(14)) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(7)/2)/(S(84)*a**S(2)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(16), x), x, S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(45045)*x**S(7)*(a + b*x**S(2))) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1287)*x**S(11)) + S(2)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(39)*x**S(15)) - S(128)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(6435)*x**S(7)) - S(80)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(1287)*x**S(11)) - S(23)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(195)*x**S(15)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(17), x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(16)*a*x**S(16)) + b*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(48)*a**S(2)*x**S(14)) - b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(7)/2)/(S(336)*a**S(3)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(18), x), x, S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(153153)*x**S(9)*(a + b*x**S(2))) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2431)*x**S(13)) + S(2)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(51)*x**S(17)) - S(128)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(17017)*x**S(9)) - S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(429)*x**S(13)) - S(5)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(51)*x**S(17)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(19), x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(18)*a*x**S(18)) + b*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(48)*a**S(2)*x**S(16)) - b**S(2)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(144)*a**S(3)*x**S(14)) + b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(7)/2)/(S(1008)*a**S(4)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(20), x), x, S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(415701)*x**S(11)*(a + b*x**S(2))) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4199)*x**S(15)) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(323)*x**S(19)) - S(128)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(37791)*x**S(11)) - S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(663)*x**S(15)) - S(27)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(323)*x**S(19)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(21), x), x, a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2520)*x**S(12)*(a + b*x**S(2))) + a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(168)*x**S(16)) + a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(36)*x**S(20)) - b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(420)*x**S(12)) - S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(252)*x**S(16)) - S(7)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(90)*x**S(20)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(22), x), x, S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(969969)*x**S(13)*(a + b*x**S(2))) + S(32)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(6783)*x**S(17)) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(399)*x**S(21)) - S(128)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(74613)*x**S(13)) - S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(969)*x**S(17)) - S(29)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(399)*x**S(21)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(23), x), x, a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5544)*x**S(14)*(a + b*x**S(2))) + a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(264)*x**S(18)) + a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(44)*x**S(22)) - b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(792)*x**S(14)) - b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(72)*x**S(18)) - S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(44)*x**S(22)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(24), x), x, S(256)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2028117)*x**S(15)*(a + b*x**S(2))) + S(160)*a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(52003)*x**S(19)) + S(10)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(483)*x**S(23)) - S(640)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(676039)*x**S(15)) - S(80)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(6783)*x**S(19)) - S(31)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(483)*x**S(23)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/x**S(25), x), x, a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(11088)*x**S(16)*(a + b*x**S(2))) + a*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(396)*x**S(20)) + S(5)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(264)*x**S(24)) - b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1386)*x**S(16)) - b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(99)*x**S(20)) - S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(33)*x**S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, (d*x)**(m + S(1))*(a + b*x**S(2))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a*d*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, a**(S(3)/2)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(b**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - a*x*(a + b*x**S(2))/(b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + x**S(3)*(a + b*x**S(2))/(S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -a*(a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -sqrt(a)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(b**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + x*(a + b*x**S(2))/(b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, (a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, (a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*sqrt(b)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, (a + b*x**S(2))*log(x)/(a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -(a + b*x**S(2))/(a*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(b)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(a**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -b*(a + b*x**S(2))*log(x)/(a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + b*(a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*a**S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -(a + b*x**S(2))/(S(3)*a*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + b*(a + b*x**S(2))/(a**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + b**(S(3)/2)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(a**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, (d*x)**(m + S(1))*(a + b*x**S(2))*hyper((S(3), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a**S(3)*d*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, a*x*(a + b*x**S(2))/(S(4)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(5)*x/(S(8)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (S(3)*a + S(3)*b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(8)*sqrt(a)*b**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, x**S(4)*(a + b*x**S(2))/(S(4)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, x**S(3)*(a + b*x**S(2))/(S(4)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - x/(S(8)*a*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(8)*a**(S(3)/2)*b**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, -(a + b*x**S(2))/(S(4)*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(-3)/2), x), x, x*(a + b*x**S(2))/(S(4)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(3)*x/(S(8)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (S(3)*a + S(3)*b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(8)*a**(S(5)/2)*sqrt(b)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (a + b*x**S(2))/(S(4)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(1)/(S(2)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*log(x)/(a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (a + b*x**S(2))/(S(4)*a*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(5)/(S(8)*a**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(15)*a + S(15)*b*x**S(2))/(S(8)*a**S(3)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(15)*sqrt(b)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(8)*a**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (a + b*x**S(2))/(S(4)*a*x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(3)/(S(4)*a**S(2)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3)*b*(a + b*x**S(2))*log(x)/(a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3)*b*(a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*a**S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (a + b*x**S(2))/(S(4)*a*x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(7)/(S(8)*a**S(2)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(35)*a + S(35)*b*x**S(2))/(S(24)*a**S(3)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(35)*b*(a + b*x**S(2))/(S(8)*a**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(35)*b**(S(3)/2)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(8)*a**(S(9)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, (d*x)**(m + S(1))*(a + b*x**S(2))*hyper((S(5), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a**S(5)*d*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*x**S(3)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(11)*x**S(3)/(S(48)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(5)*x**S(3)*(a + b*x**S(2))/(S(64)*a*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(5)*x/(S(128)*a*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (S(5)*a + S(5)*b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(128)*a**(S(3)/2)*b**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, x**S(6)*(a + b*x**S(2))/(S(8)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + x**S(6)/(S(24)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*x*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(3)*x/(S(16)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + x*(a + b*x**S(2))/(S(64)*a*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(3)*x/(S(128)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (S(3)*a + S(3)*b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(128)*a**(S(5)/2)*b**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(1)/(S(6)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, x**S(3)*(a + b*x**S(2))/(S(8)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(5)*x/(S(48)*a*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(5)*x*(a + b*x**S(2))/(S(192)*a**S(2)*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(5)*x/(S(128)*a**S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (S(5)*a + S(5)*b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(128)*a**(S(7)/2)*b**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, -(a + b*x**S(2))/(S(8)*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(-5)/2), x), x, x*(a + b*x**S(2))/(S(8)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(7)*x/(S(48)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(35)*x*(a + b*x**S(2))/(S(192)*a**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(35)*x/(S(128)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (S(35)*a + S(35)*b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(128)*a**(S(9)/2)*sqrt(b)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, (a + b*x**S(2))/(S(8)*a*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(1)/(S(6)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + (a + b*x**S(2))/(S(4)*a**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(1)/(S(2)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*log(x)/(a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, (a + b*x**S(2))/(S(8)*a*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(3)/(S(16)*a**S(2)*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + (S(21)*a + S(21)*b*x**S(2))/(S(64)*a**S(3)*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(105)/(S(128)*a**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(315)*a + S(315)*b*x**S(2))/(S(128)*a**S(5)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(315)*sqrt(b)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(128)*a**(S(11)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, (a + b*x**S(2))/(S(8)*a*x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(5)/(S(24)*a**S(2)*x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + (S(5)*a + S(5)*b*x**S(2))/(S(12)*a**S(3)*x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(5)/(S(4)*a**S(4)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(5)*b*(a + b*x**S(2))*log(x)/(a**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(5)*b*(a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*a**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*a**S(6)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, (a + b*x**S(2))/(S(8)*a*x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(11)/(S(48)*a**S(2)*x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + (S(33)*a + S(33)*b*x**S(2))/(S(64)*a**S(3)*x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(231)/(S(128)*a**S(4)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(385)*a + S(385)*b*x**S(2))/(S(128)*a**S(5)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(1155)*b*(a + b*x**S(2))/(S(128)*a**S(6)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(1155)*b**(S(3)/2)*(a + b*x**S(2))*atan(sqrt(b)*x/sqrt(a))/(S(128)*a**(S(13)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(2)*a**S(2)*(d*x)**(S(7)/2)/(S(7)*d) + S(4)*a*b*(d*x)**(S(11)/2)/(S(11)*d**S(3)) + S(2)*b**S(2)*(d*x)**(S(15)/2)/(S(15)*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(2)*a**S(2)*(d*x)**(S(5)/2)/(S(5)*d) + S(4)*a*b*(d*x)**(S(9)/2)/(S(9)*d**S(3)) + S(2)*b**S(2)*(d*x)**(S(13)/2)/(S(13)*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(2)*a**S(2)*(d*x)**(S(3)/2)/(S(3)*d) + S(4)*a*b*(d*x)**(S(7)/2)/(S(7)*d**S(3)) + S(2)*b**S(2)*(d*x)**(S(11)/2)/(S(11)*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/sqrt(d*x), x), x, S(2)*a**S(2)*sqrt(d*x)/d + S(4)*a*b*(d*x)**(S(5)/2)/(S(5)*d**S(3)) + S(2)*b**S(2)*(d*x)**(S(9)/2)/(S(9)*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*x)**(S(3)/2), x), x, -S(2)*a**S(2)/(d*sqrt(d*x)) + S(4)*a*b*(d*x)**(S(3)/2)/(S(3)*d**S(3)) + S(2)*b**S(2)*(d*x)**(S(7)/2)/(S(7)*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*x)**(S(5)/2), x), x, -S(2)*a**S(2)/(S(3)*d*(d*x)**(S(3)/2)) + S(4)*a*b*sqrt(d*x)/d**S(3) + S(2)*b**S(2)*(d*x)**(S(5)/2)/(S(5)*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*x)**(S(7)/2), x), x, -S(2)*a**S(2)/(S(5)*d*(d*x)**(S(5)/2)) - S(4)*a*b/(d**S(3)*sqrt(d*x)) + S(2)*b**S(2)*(d*x)**(S(3)/2)/(S(3)*d**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, S(2)*a**S(4)*(d*x)**(S(7)/2)/(S(7)*d) + S(8)*a**S(3)*b*(d*x)**(S(11)/2)/(S(11)*d**S(3)) + S(4)*a**S(2)*b**S(2)*(d*x)**(S(15)/2)/(S(5)*d**S(5)) + S(8)*a*b**S(3)*(d*x)**(S(19)/2)/(S(19)*d**S(7)) + S(2)*b**S(4)*(d*x)**(S(23)/2)/(S(23)*d**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, S(2)*a**S(4)*(d*x)**(S(5)/2)/(S(5)*d) + S(8)*a**S(3)*b*(d*x)**(S(9)/2)/(S(9)*d**S(3)) + S(12)*a**S(2)*b**S(2)*(d*x)**(S(13)/2)/(S(13)*d**S(5)) + S(8)*a*b**S(3)*(d*x)**(S(17)/2)/(S(17)*d**S(7)) + S(2)*b**S(4)*(d*x)**(S(21)/2)/(S(21)*d**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, S(2)*a**S(4)*(d*x)**(S(3)/2)/(S(3)*d) + S(8)*a**S(3)*b*(d*x)**(S(7)/2)/(S(7)*d**S(3)) + S(12)*a**S(2)*b**S(2)*(d*x)**(S(11)/2)/(S(11)*d**S(5)) + S(8)*a*b**S(3)*(d*x)**(S(15)/2)/(S(15)*d**S(7)) + S(2)*b**S(4)*(d*x)**(S(19)/2)/(S(19)*d**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/sqrt(d*x), x), x, S(2)*a**S(4)*sqrt(d*x)/d + S(8)*a**S(3)*b*(d*x)**(S(5)/2)/(S(5)*d**S(3)) + S(4)*a**S(2)*b**S(2)*(d*x)**(S(9)/2)/(S(3)*d**S(5)) + S(8)*a*b**S(3)*(d*x)**(S(13)/2)/(S(13)*d**S(7)) + S(2)*b**S(4)*(d*x)**(S(17)/2)/(S(17)*d**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/(d*x)**(S(3)/2), x), x, -S(2)*a**S(4)/(d*sqrt(d*x)) + S(8)*a**S(3)*b*(d*x)**(S(3)/2)/(S(3)*d**S(3)) + S(12)*a**S(2)*b**S(2)*(d*x)**(S(7)/2)/(S(7)*d**S(5)) + S(8)*a*b**S(3)*(d*x)**(S(11)/2)/(S(11)*d**S(7)) + S(2)*b**S(4)*(d*x)**(S(15)/2)/(S(15)*d**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/(d*x)**(S(5)/2), x), x, -S(2)*a**S(4)/(S(3)*d*(d*x)**(S(3)/2)) + S(8)*a**S(3)*b*sqrt(d*x)/d**S(3) + S(12)*a**S(2)*b**S(2)*(d*x)**(S(5)/2)/(S(5)*d**S(5)) + S(8)*a*b**S(3)*(d*x)**(S(9)/2)/(S(9)*d**S(7)) + S(2)*b**S(4)*(d*x)**(S(13)/2)/(S(13)*d**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)/(d*x)**(S(7)/2), x), x, -S(2)*a**S(4)/(S(5)*d*(d*x)**(S(5)/2)) - S(8)*a**S(3)*b/(d**S(3)*sqrt(d*x)) + S(4)*a**S(2)*b**S(2)*(d*x)**(S(3)/2)/d**S(5) + S(8)*a*b**S(3)*(d*x)**(S(7)/2)/(S(7)*d**S(7)) + S(2)*b**S(4)*(d*x)**(S(11)/2)/(S(11)*d**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, S(2)*a**S(6)*(d*x)**(S(7)/2)/(S(7)*d) + S(12)*a**S(5)*b*(d*x)**(S(11)/2)/(S(11)*d**S(3)) + S(2)*a**S(4)*b**S(2)*(d*x)**(S(15)/2)/d**S(5) + S(40)*a**S(3)*b**S(3)*(d*x)**(S(19)/2)/(S(19)*d**S(7)) + S(30)*a**S(2)*b**S(4)*(d*x)**(S(23)/2)/(S(23)*d**S(9)) + S(4)*a*b**S(5)*(d*x)**(S(27)/2)/(S(9)*d**S(11)) + S(2)*b**S(6)*(d*x)**(S(31)/2)/(S(31)*d**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, S(2)*a**S(6)*(d*x)**(S(5)/2)/(S(5)*d) + S(4)*a**S(5)*b*(d*x)**(S(9)/2)/(S(3)*d**S(3)) + S(30)*a**S(4)*b**S(2)*(d*x)**(S(13)/2)/(S(13)*d**S(5)) + S(40)*a**S(3)*b**S(3)*(d*x)**(S(17)/2)/(S(17)*d**S(7)) + S(10)*a**S(2)*b**S(4)*(d*x)**(S(21)/2)/(S(7)*d**S(9)) + S(12)*a*b**S(5)*(d*x)**(S(25)/2)/(S(25)*d**S(11)) + S(2)*b**S(6)*(d*x)**(S(29)/2)/(S(29)*d**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, S(2)*a**S(6)*(d*x)**(S(3)/2)/(S(3)*d) + S(12)*a**S(5)*b*(d*x)**(S(7)/2)/(S(7)*d**S(3)) + S(30)*a**S(4)*b**S(2)*(d*x)**(S(11)/2)/(S(11)*d**S(5)) + S(8)*a**S(3)*b**S(3)*(d*x)**(S(15)/2)/(S(3)*d**S(7)) + S(30)*a**S(2)*b**S(4)*(d*x)**(S(19)/2)/(S(19)*d**S(9)) + S(12)*a*b**S(5)*(d*x)**(S(23)/2)/(S(23)*d**S(11)) + S(2)*b**S(6)*(d*x)**(S(27)/2)/(S(27)*d**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/sqrt(d*x), x), x, S(2)*a**S(6)*sqrt(d*x)/d + S(12)*a**S(5)*b*(d*x)**(S(5)/2)/(S(5)*d**S(3)) + S(10)*a**S(4)*b**S(2)*(d*x)**(S(9)/2)/(S(3)*d**S(5)) + S(40)*a**S(3)*b**S(3)*(d*x)**(S(13)/2)/(S(13)*d**S(7)) + S(30)*a**S(2)*b**S(4)*(d*x)**(S(17)/2)/(S(17)*d**S(9)) + S(4)*a*b**S(5)*(d*x)**(S(21)/2)/(S(7)*d**S(11)) + S(2)*b**S(6)*(d*x)**(S(25)/2)/(S(25)*d**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/(d*x)**(S(3)/2), x), x, -S(2)*a**S(6)/(d*sqrt(d*x)) + S(4)*a**S(5)*b*(d*x)**(S(3)/2)/d**S(3) + S(30)*a**S(4)*b**S(2)*(d*x)**(S(7)/2)/(S(7)*d**S(5)) + S(40)*a**S(3)*b**S(3)*(d*x)**(S(11)/2)/(S(11)*d**S(7)) + S(2)*a**S(2)*b**S(4)*(d*x)**(S(15)/2)/d**S(9) + S(12)*a*b**S(5)*(d*x)**(S(19)/2)/(S(19)*d**S(11)) + S(2)*b**S(6)*(d*x)**(S(23)/2)/(S(23)*d**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/(d*x)**(S(5)/2), x), x, -S(2)*a**S(6)/(S(3)*d*(d*x)**(S(3)/2)) + S(12)*a**S(5)*b*sqrt(d*x)/d**S(3) + S(6)*a**S(4)*b**S(2)*(d*x)**(S(5)/2)/d**S(5) + S(40)*a**S(3)*b**S(3)*(d*x)**(S(9)/2)/(S(9)*d**S(7)) + S(30)*a**S(2)*b**S(4)*(d*x)**(S(13)/2)/(S(13)*d**S(9)) + S(12)*a*b**S(5)*(d*x)**(S(17)/2)/(S(17)*d**S(11)) + S(2)*b**S(6)*(d*x)**(S(21)/2)/(S(21)*d**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)/(d*x)**(S(7)/2), x), x, -S(2)*a**S(6)/(S(5)*d*(d*x)**(S(5)/2)) - S(12)*a**S(5)*b/(d**S(3)*sqrt(d*x)) + S(10)*a**S(4)*b**S(2)*(d*x)**(S(3)/2)/d**S(5) + S(40)*a**S(3)*b**S(3)*(d*x)**(S(7)/2)/(S(7)*d**S(7)) + S(30)*a**S(2)*b**S(4)*(d*x)**(S(11)/2)/(S(11)*d**S(9)) + S(4)*a*b**S(5)*(d*x)**(S(15)/2)/(S(5)*d**S(11)) + S(2)*b**S(6)*(d*x)**(S(19)/2)/(S(19)*d**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(11)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -S(9)*sqrt(S(2))*a**(S(5)/4)*d**(S(11)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*b**(S(13)/4)) + S(9)*sqrt(S(2))*a**(S(5)/4)*d**(S(11)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*b**(S(13)/4)) - S(9)*sqrt(S(2))*a**(S(5)/4)*d**(S(11)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*b**(S(13)/4)) + S(9)*sqrt(S(2))*a**(S(5)/4)*d**(S(11)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*b**(S(13)/4)) - S(9)*a*d**S(5)*sqrt(d*x)/(S(2)*b**S(3)) - d*(d*x)**(S(9)/2)/(S(2)*b*(a + b*x**S(2))) + S(9)*d**S(3)*(d*x)**(S(5)/2)/(S(10)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(9)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -S(7)*sqrt(S(2))*a**(S(3)/4)*d**(S(9)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*b**(S(11)/4)) + S(7)*sqrt(S(2))*a**(S(3)/4)*d**(S(9)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*b**(S(11)/4)) + S(7)*sqrt(S(2))*a**(S(3)/4)*d**(S(9)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*b**(S(11)/4)) - S(7)*sqrt(S(2))*a**(S(3)/4)*d**(S(9)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*b**(S(11)/4)) - d*(d*x)**(S(7)/2)/(S(2)*b*(a + b*x**S(2))) + S(7)*d**S(3)*(d*x)**(S(3)/2)/(S(6)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(7)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(5)*sqrt(S(2))*a**(S(1)/4)*d**(S(7)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*b**(S(9)/4)) - S(5)*sqrt(S(2))*a**(S(1)/4)*d**(S(7)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*b**(S(9)/4)) + S(5)*sqrt(S(2))*a**(S(1)/4)*d**(S(7)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*b**(S(9)/4)) - S(5)*sqrt(S(2))*a**(S(1)/4)*d**(S(7)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*b**(S(9)/4)) - d*(d*x)**(S(5)/2)/(S(2)*b*(a + b*x**S(2))) + S(5)*d**S(3)*sqrt(d*x)/(S(2)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -d*(d*x)**(S(3)/2)/(S(2)*b*(a + b*x**S(2))) + S(3)*sqrt(S(2))*d**(S(5)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(1)/4)*b**(S(7)/4)) - S(3)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(1)/4)*b**(S(7)/4)) - S(3)*sqrt(S(2))*d**(S(5)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(1)/4)*b**(S(7)/4)) + S(3)*sqrt(S(2))*d**(S(5)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(1)/4)*b**(S(7)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -d*sqrt(d*x)/(S(2)*b*(a + b*x**S(2))) - sqrt(S(2))*d**(S(3)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(3)/4)*b**(S(5)/4)) + sqrt(S(2))*d**(S(3)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(3)/4)*b**(S(5)/4)) - sqrt(S(2))*d**(S(3)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(3)/4)*b**(S(5)/4)) + sqrt(S(2))*d**(S(3)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(3)/4)*b**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, (d*x)**(S(3)/2)/(S(2)*a*d*(a + b*x**S(2))) + sqrt(S(2))*sqrt(d)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(5)/4)*b**(S(3)/4)) - sqrt(S(2))*sqrt(d)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(5)/4)*b**(S(3)/4)) - sqrt(S(2))*sqrt(d)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(5)/4)*b**(S(3)/4)) + sqrt(S(2))*sqrt(d)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(5)/4)*b**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, sqrt(d*x)/(S(2)*a*d*(a + b*x**S(2))) - S(3)*sqrt(S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(7)/4)*b**(S(1)/4)*sqrt(d)) + S(3)*sqrt(S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(7)/4)*b**(S(1)/4)*sqrt(d)) - S(3)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(7)/4)*b**(S(1)/4)*sqrt(d)) + S(3)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(7)/4)*b**(S(1)/4)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, S(1)/(S(2)*a*d*sqrt(d*x)*(a + b*x**S(2))) - S(5)/(S(2)*a**S(2)*d*sqrt(d*x)) - S(5)*sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(9)/4)*d**(S(3)/2)) + S(5)*sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(9)/4)*d**(S(3)/2)) + S(5)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(9)/4)*d**(S(3)/2)) - S(5)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(9)/4)*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, S(1)/(S(2)*a*d*(d*x)**(S(3)/2)*(a + b*x**S(2))) - S(7)/(S(6)*a**S(2)*d*(d*x)**(S(3)/2)) + S(7)*sqrt(S(2))*b**(S(3)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(11)/4)*d**(S(5)/2)) - S(7)*sqrt(S(2))*b**(S(3)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(11)/4)*d**(S(5)/2)) + S(7)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(11)/4)*d**(S(5)/2)) - S(7)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(11)/4)*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, S(1)/(S(2)*a*d*(d*x)**(S(5)/2)*(a + b*x**S(2))) - S(9)/(S(10)*a**S(2)*d*(d*x)**(S(5)/2)) + S(9)*b/(S(2)*a**S(3)*d**S(3)*sqrt(d*x)) + S(9)*sqrt(S(2))*b**(S(5)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(13)/4)*d**(S(7)/2)) - S(9)*sqrt(S(2))*b**(S(5)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(16)*a**(S(13)/4)*d**(S(7)/2)) - S(9)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(13)/4)*d**(S(7)/2)) + S(9)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(8)*a**(S(13)/4)*d**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(19)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -S(663)*sqrt(S(2))*a**(S(5)/4)*d**(S(19)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*b**(S(21)/4)) + S(663)*sqrt(S(2))*a**(S(5)/4)*d**(S(19)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*b**(S(21)/4)) - S(663)*sqrt(S(2))*a**(S(5)/4)*d**(S(19)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*b**(S(21)/4)) + S(663)*sqrt(S(2))*a**(S(5)/4)*d**(S(19)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*b**(S(21)/4)) - S(663)*a*d**S(9)*sqrt(d*x)/(S(64)*b**S(5)) - d*(d*x)**(S(17)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(17)*d**S(3)*(d*x)**(S(13)/2)/(S(48)*b**S(2)*(a + b*x**S(2))**S(2)) - S(221)*d**S(5)*(d*x)**(S(9)/2)/(S(192)*b**S(3)*(a + b*x**S(2))) + S(663)*d**S(7)*(d*x)**(S(5)/2)/(S(320)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(17)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -S(385)*sqrt(S(2))*a**(S(3)/4)*d**(S(17)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*b**(S(19)/4)) + S(385)*sqrt(S(2))*a**(S(3)/4)*d**(S(17)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*b**(S(19)/4)) + S(385)*sqrt(S(2))*a**(S(3)/4)*d**(S(17)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*b**(S(19)/4)) - S(385)*sqrt(S(2))*a**(S(3)/4)*d**(S(17)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*b**(S(19)/4)) - d*(d*x)**(S(15)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(5)*d**S(3)*(d*x)**(S(11)/2)/(S(16)*b**S(2)*(a + b*x**S(2))**S(2)) - S(55)*d**S(5)*(d*x)**(S(7)/2)/(S(64)*b**S(3)*(a + b*x**S(2))) + S(385)*d**S(7)*(d*x)**(S(3)/2)/(S(192)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(15)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, S(195)*sqrt(S(2))*a**(S(1)/4)*d**(S(15)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*b**(S(17)/4)) - S(195)*sqrt(S(2))*a**(S(1)/4)*d**(S(15)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*b**(S(17)/4)) + S(195)*sqrt(S(2))*a**(S(1)/4)*d**(S(15)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*b**(S(17)/4)) - S(195)*sqrt(S(2))*a**(S(1)/4)*d**(S(15)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*b**(S(17)/4)) - d*(d*x)**(S(13)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(13)*d**S(3)*(d*x)**(S(9)/2)/(S(48)*b**S(2)*(a + b*x**S(2))**S(2)) - S(39)*d**S(5)*(d*x)**(S(5)/2)/(S(64)*b**S(3)*(a + b*x**S(2))) + S(195)*d**S(7)*sqrt(d*x)/(S(64)*b**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(13)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -d*(d*x)**(S(11)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(11)*d**S(3)*(d*x)**(S(7)/2)/(S(48)*b**S(2)*(a + b*x**S(2))**S(2)) - S(77)*d**S(5)*(d*x)**(S(3)/2)/(S(192)*b**S(3)*(a + b*x**S(2))) + S(77)*sqrt(S(2))*d**(S(13)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(1)/4)*b**(S(15)/4)) - S(77)*sqrt(S(2))*d**(S(13)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(1)/4)*b**(S(15)/4)) - S(77)*sqrt(S(2))*d**(S(13)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(1)/4)*b**(S(15)/4)) + S(77)*sqrt(S(2))*d**(S(13)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(1)/4)*b**(S(15)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(11)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -d*(d*x)**(S(9)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(3)*d**S(3)*(d*x)**(S(5)/2)/(S(16)*b**S(2)*(a + b*x**S(2))**S(2)) - S(15)*d**S(5)*sqrt(d*x)/(S(64)*b**S(3)*(a + b*x**S(2))) - S(15)*sqrt(S(2))*d**(S(11)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(3)/4)*b**(S(13)/4)) + S(15)*sqrt(S(2))*d**(S(11)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(3)/4)*b**(S(13)/4)) - S(15)*sqrt(S(2))*d**(S(11)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(3)/4)*b**(S(13)/4)) + S(15)*sqrt(S(2))*d**(S(11)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(3)/4)*b**(S(13)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(9)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -d*(d*x)**(S(7)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(7)*d**S(3)*(d*x)**(S(3)/2)/(S(48)*b**S(2)*(a + b*x**S(2))**S(2)) + S(7)*d**S(3)*(d*x)**(S(3)/2)/(S(64)*a*b**S(2)*(a + b*x**S(2))) + S(7)*sqrt(S(2))*d**(S(9)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(5)/4)*b**(S(11)/4)) - S(7)*sqrt(S(2))*d**(S(9)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(5)/4)*b**(S(11)/4)) - S(7)*sqrt(S(2))*d**(S(9)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(5)/4)*b**(S(11)/4)) + S(7)*sqrt(S(2))*d**(S(9)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(5)/4)*b**(S(11)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(7)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -d*(d*x)**(S(5)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) - S(5)*d**S(3)*sqrt(d*x)/(S(48)*b**S(2)*(a + b*x**S(2))**S(2)) + S(5)*d**S(3)*sqrt(d*x)/(S(192)*a*b**S(2)*(a + b*x**S(2))) - S(5)*sqrt(S(2))*d**(S(7)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(7)/4)*b**(S(9)/4)) + S(5)*sqrt(S(2))*d**(S(7)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(7)/4)*b**(S(9)/4)) - S(5)*sqrt(S(2))*d**(S(7)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(7)/4)*b**(S(9)/4)) + S(5)*sqrt(S(2))*d**(S(7)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(7)/4)*b**(S(9)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -d*(d*x)**(S(3)/2)/(S(6)*b*(a + b*x**S(2))**S(3)) + d*(d*x)**(S(3)/2)/(S(16)*a*b*(a + b*x**S(2))**S(2)) + S(5)*d*(d*x)**(S(3)/2)/(S(64)*a**S(2)*b*(a + b*x**S(2))) + S(5)*sqrt(S(2))*d**(S(5)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(9)/4)*b**(S(7)/4)) - S(5)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(9)/4)*b**(S(7)/4)) - S(5)*sqrt(S(2))*d**(S(5)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(9)/4)*b**(S(7)/4)) + S(5)*sqrt(S(2))*d**(S(5)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(9)/4)*b**(S(7)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, -d*sqrt(d*x)/(S(6)*b*(a + b*x**S(2))**S(3)) + d*sqrt(d*x)/(S(48)*a*b*(a + b*x**S(2))**S(2)) + S(7)*d*sqrt(d*x)/(S(192)*a**S(2)*b*(a + b*x**S(2))) - S(7)*sqrt(S(2))*d**(S(3)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(11)/4)*b**(S(5)/4)) + S(7)*sqrt(S(2))*d**(S(3)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(11)/4)*b**(S(5)/4)) - S(7)*sqrt(S(2))*d**(S(3)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(11)/4)*b**(S(5)/4)) + S(7)*sqrt(S(2))*d**(S(3)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(11)/4)*b**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2), x), x, (d*x)**(S(3)/2)/(S(6)*a*d*(a + b*x**S(2))**S(3)) + S(3)*(d*x)**(S(3)/2)/(S(16)*a**S(2)*d*(a + b*x**S(2))**S(2)) + S(15)*(d*x)**(S(3)/2)/(S(64)*a**S(3)*d*(a + b*x**S(2))) + S(15)*sqrt(S(2))*sqrt(d)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(13)/4)*b**(S(3)/4)) - S(15)*sqrt(S(2))*sqrt(d)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(13)/4)*b**(S(3)/4)) - S(15)*sqrt(S(2))*sqrt(d)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(13)/4)*b**(S(3)/4)) + S(15)*sqrt(S(2))*sqrt(d)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(13)/4)*b**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, sqrt(d*x)/(S(6)*a*d*(a + b*x**S(2))**S(3)) + S(11)*sqrt(d*x)/(S(48)*a**S(2)*d*(a + b*x**S(2))**S(2)) + S(77)*sqrt(d*x)/(S(192)*a**S(3)*d*(a + b*x**S(2))) - S(77)*sqrt(S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(15)/4)*b**(S(1)/4)*sqrt(d)) + S(77)*sqrt(S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(15)/4)*b**(S(1)/4)*sqrt(d)) - S(77)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(15)/4)*b**(S(1)/4)*sqrt(d)) + S(77)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(15)/4)*b**(S(1)/4)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, S(1)/(S(6)*a*d*sqrt(d*x)*(a + b*x**S(2))**S(3)) + S(13)/(S(48)*a**S(2)*d*sqrt(d*x)*(a + b*x**S(2))**S(2)) + S(39)/(S(64)*a**S(3)*d*sqrt(d*x)*(a + b*x**S(2))) - S(195)/(S(64)*a**S(4)*d*sqrt(d*x)) - S(195)*sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(17)/4)*d**(S(3)/2)) + S(195)*sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(17)/4)*d**(S(3)/2)) + S(195)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(17)/4)*d**(S(3)/2)) - S(195)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(17)/4)*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, S(1)/(S(6)*a*d*(d*x)**(S(3)/2)*(a + b*x**S(2))**S(3)) + S(5)/(S(16)*a**S(2)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))**S(2)) + S(55)/(S(64)*a**S(3)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))) - S(385)/(S(192)*a**S(4)*d*(d*x)**(S(3)/2)) + S(385)*sqrt(S(2))*b**(S(3)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(19)/4)*d**(S(5)/2)) - S(385)*sqrt(S(2))*b**(S(3)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(19)/4)*d**(S(5)/2)) + S(385)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(19)/4)*d**(S(5)/2)) - S(385)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(19)/4)*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(2)), x), x, S(1)/(S(6)*a*d*(d*x)**(S(5)/2)*(a + b*x**S(2))**S(3)) + S(17)/(S(48)*a**S(2)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))**S(2)) + S(221)/(S(192)*a**S(3)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))) - S(663)/(S(320)*a**S(4)*d*(d*x)**(S(5)/2)) + S(663)*b/(S(64)*a**S(5)*d**S(3)*sqrt(d*x)) + S(663)*sqrt(S(2))*b**(S(5)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(21)/4)*d**(S(7)/2)) - S(663)*sqrt(S(2))*b**(S(5)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(512)*a**(S(21)/4)*d**(S(7)/2)) - S(663)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(21)/4)*d**(S(7)/2)) + S(663)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(256)*a**(S(21)/4)*d**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(27)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -S(69615)*sqrt(S(2))*a**(S(5)/4)*d**(S(27)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*b**(S(29)/4)) + S(69615)*sqrt(S(2))*a**(S(5)/4)*d**(S(27)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*b**(S(29)/4)) - S(69615)*sqrt(S(2))*a**(S(5)/4)*d**(S(27)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*b**(S(29)/4)) + S(69615)*sqrt(S(2))*a**(S(5)/4)*d**(S(27)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*b**(S(29)/4)) - S(69615)*a*d**S(13)*sqrt(d*x)/(S(4096)*b**S(7)) - d*(d*x)**(S(25)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(5)*d**S(3)*(d*x)**(S(21)/2)/(S(32)*b**S(2)*(a + b*x**S(2))**S(4)) - S(35)*d**S(5)*(d*x)**(S(17)/2)/(S(128)*b**S(3)*(a + b*x**S(2))**S(3)) - S(595)*d**S(7)*(d*x)**(S(13)/2)/(S(1024)*b**S(4)*(a + b*x**S(2))**S(2)) - S(7735)*d**S(9)*(d*x)**(S(9)/2)/(S(4096)*b**S(5)*(a + b*x**S(2))) + S(13923)*d**S(11)*(d*x)**(S(5)/2)/(S(4096)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(25)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -S(33649)*sqrt(S(2))*a**(S(3)/4)*d**(S(25)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*b**(S(27)/4)) + S(33649)*sqrt(S(2))*a**(S(3)/4)*d**(S(25)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*b**(S(27)/4)) + S(33649)*sqrt(S(2))*a**(S(3)/4)*d**(S(25)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*b**(S(27)/4)) - S(33649)*sqrt(S(2))*a**(S(3)/4)*d**(S(25)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*b**(S(27)/4)) - d*(d*x)**(S(23)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(23)*d**S(3)*(d*x)**(S(19)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) - S(437)*d**S(5)*(d*x)**(S(15)/2)/(S(1920)*b**S(3)*(a + b*x**S(2))**S(3)) - S(437)*d**S(7)*(d*x)**(S(11)/2)/(S(1024)*b**S(4)*(a + b*x**S(2))**S(2)) - S(4807)*d**S(9)*(d*x)**(S(7)/2)/(S(4096)*b**S(5)*(a + b*x**S(2))) + S(33649)*d**S(11)*(d*x)**(S(3)/2)/(S(12288)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(23)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, S(13923)*sqrt(S(2))*a**(S(1)/4)*d**(S(23)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*b**(S(25)/4)) - S(13923)*sqrt(S(2))*a**(S(1)/4)*d**(S(23)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*b**(S(25)/4)) + S(13923)*sqrt(S(2))*a**(S(1)/4)*d**(S(23)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*b**(S(25)/4)) - S(13923)*sqrt(S(2))*a**(S(1)/4)*d**(S(23)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*b**(S(25)/4)) - d*(d*x)**(S(21)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(21)*d**S(3)*(d*x)**(S(17)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) - S(119)*d**S(5)*(d*x)**(S(13)/2)/(S(640)*b**S(3)*(a + b*x**S(2))**S(3)) - S(1547)*d**S(7)*(d*x)**(S(9)/2)/(S(5120)*b**S(4)*(a + b*x**S(2))**S(2)) - S(13923)*d**S(9)*(d*x)**(S(5)/2)/(S(20480)*b**S(5)*(a + b*x**S(2))) + S(13923)*d**S(11)*sqrt(d*x)/(S(4096)*b**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(21)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(19)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(19)*d**S(3)*(d*x)**(S(15)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) - S(19)*d**S(5)*(d*x)**(S(11)/2)/(S(128)*b**S(3)*(a + b*x**S(2))**S(3)) - S(209)*d**S(7)*(d*x)**(S(7)/2)/(S(1024)*b**S(4)*(a + b*x**S(2))**S(2)) - S(1463)*d**S(9)*(d*x)**(S(3)/2)/(S(4096)*b**S(5)*(a + b*x**S(2))) + S(4389)*sqrt(S(2))*d**(S(21)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(1)/4)*b**(S(23)/4)) - S(4389)*sqrt(S(2))*d**(S(21)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(1)/4)*b**(S(23)/4)) - S(4389)*sqrt(S(2))*d**(S(21)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(1)/4)*b**(S(23)/4)) + S(4389)*sqrt(S(2))*d**(S(21)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(1)/4)*b**(S(23)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(19)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(17)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(17)*d**S(3)*(d*x)**(S(13)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) - S(221)*d**S(5)*(d*x)**(S(9)/2)/(S(1920)*b**S(3)*(a + b*x**S(2))**S(3)) - S(663)*d**S(7)*(d*x)**(S(5)/2)/(S(5120)*b**S(4)*(a + b*x**S(2))**S(2)) - S(663)*d**S(9)*sqrt(d*x)/(S(4096)*b**S(5)*(a + b*x**S(2))) - S(663)*sqrt(S(2))*d**(S(19)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(3)/4)*b**(S(21)/4)) + S(663)*sqrt(S(2))*d**(S(19)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(3)/4)*b**(S(21)/4)) - S(663)*sqrt(S(2))*d**(S(19)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(3)/4)*b**(S(21)/4)) + S(663)*sqrt(S(2))*d**(S(19)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(3)/4)*b**(S(21)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(17)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(15)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(3)*d**S(3)*(d*x)**(S(11)/2)/(S(32)*b**S(2)*(a + b*x**S(2))**S(4)) - S(11)*d**S(5)*(d*x)**(S(7)/2)/(S(128)*b**S(3)*(a + b*x**S(2))**S(3)) - S(77)*d**S(7)*(d*x)**(S(3)/2)/(S(1024)*b**S(4)*(a + b*x**S(2))**S(2)) + S(231)*d**S(7)*(d*x)**(S(3)/2)/(S(4096)*a*b**S(4)*(a + b*x**S(2))) + S(231)*sqrt(S(2))*d**(S(17)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(5)/4)*b**(S(19)/4)) - S(231)*sqrt(S(2))*d**(S(17)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(5)/4)*b**(S(19)/4)) - S(231)*sqrt(S(2))*d**(S(17)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(5)/4)*b**(S(19)/4)) + S(231)*sqrt(S(2))*d**(S(17)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(5)/4)*b**(S(19)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(15)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(13)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(13)*d**S(3)*(d*x)**(S(9)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) - S(39)*d**S(5)*(d*x)**(S(5)/2)/(S(640)*b**S(3)*(a + b*x**S(2))**S(3)) - S(39)*d**S(7)*sqrt(d*x)/(S(1024)*b**S(4)*(a + b*x**S(2))**S(2)) + S(39)*d**S(7)*sqrt(d*x)/(S(4096)*a*b**S(4)*(a + b*x**S(2))) - S(117)*sqrt(S(2))*d**(S(15)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(7)/4)*b**(S(17)/4)) + S(117)*sqrt(S(2))*d**(S(15)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(7)/4)*b**(S(17)/4)) - S(117)*sqrt(S(2))*d**(S(15)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(7)/4)*b**(S(17)/4)) + S(117)*sqrt(S(2))*d**(S(15)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(7)/4)*b**(S(17)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(13)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(11)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(11)*d**S(3)*(d*x)**(S(7)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) - S(77)*d**S(5)*(d*x)**(S(3)/2)/(S(1920)*b**S(3)*(a + b*x**S(2))**S(3)) + S(77)*d**S(5)*(d*x)**(S(3)/2)/(S(5120)*a*b**S(3)*(a + b*x**S(2))**S(2)) + S(77)*d**S(5)*(d*x)**(S(3)/2)/(S(4096)*a**S(2)*b**S(3)*(a + b*x**S(2))) + S(77)*sqrt(S(2))*d**(S(13)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(9)/4)*b**(S(15)/4)) - S(77)*sqrt(S(2))*d**(S(13)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(9)/4)*b**(S(15)/4)) - S(77)*sqrt(S(2))*d**(S(13)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(9)/4)*b**(S(15)/4)) + S(77)*sqrt(S(2))*d**(S(13)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(9)/4)*b**(S(15)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(11)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(9)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(9)*d**S(3)*(d*x)**(S(5)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) - S(3)*d**S(5)*sqrt(d*x)/(S(128)*b**S(3)*(a + b*x**S(2))**S(3)) + S(3)*d**S(5)*sqrt(d*x)/(S(1024)*a*b**S(3)*(a + b*x**S(2))**S(2)) + S(21)*d**S(5)*sqrt(d*x)/(S(4096)*a**S(2)*b**S(3)*(a + b*x**S(2))) - S(63)*sqrt(S(2))*d**(S(11)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(11)/4)*b**(S(13)/4)) + S(63)*sqrt(S(2))*d**(S(11)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(11)/4)*b**(S(13)/4)) - S(63)*sqrt(S(2))*d**(S(11)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(11)/4)*b**(S(13)/4)) + S(63)*sqrt(S(2))*d**(S(11)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(11)/4)*b**(S(13)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(9)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(7)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - S(7)*d**S(3)*(d*x)**(S(3)/2)/(S(160)*b**S(2)*(a + b*x**S(2))**S(4)) + S(7)*d**S(3)*(d*x)**(S(3)/2)/(S(640)*a*b**S(2)*(a + b*x**S(2))**S(3)) + S(63)*d**S(3)*(d*x)**(S(3)/2)/(S(5120)*a**S(2)*b**S(2)*(a + b*x**S(2))**S(2)) + S(63)*d**S(3)*(d*x)**(S(3)/2)/(S(4096)*a**S(3)*b**S(2)*(a + b*x**S(2))) + S(63)*sqrt(S(2))*d**(S(9)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(13)/4)*b**(S(11)/4)) - S(63)*sqrt(S(2))*d**(S(9)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(13)/4)*b**(S(11)/4)) - S(63)*sqrt(S(2))*d**(S(9)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(13)/4)*b**(S(11)/4)) + S(63)*sqrt(S(2))*d**(S(9)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(13)/4)*b**(S(11)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(7)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(5)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) - d**S(3)*sqrt(d*x)/(S(32)*b**S(2)*(a + b*x**S(2))**S(4)) + d**S(3)*sqrt(d*x)/(S(384)*a*b**S(2)*(a + b*x**S(2))**S(3)) + S(11)*d**S(3)*sqrt(d*x)/(S(3072)*a**S(2)*b**S(2)*(a + b*x**S(2))**S(2)) + S(77)*d**S(3)*sqrt(d*x)/(S(12288)*a**S(3)*b**S(2)*(a + b*x**S(2))) - S(77)*sqrt(S(2))*d**(S(7)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(15)/4)*b**(S(9)/4)) + S(77)*sqrt(S(2))*d**(S(7)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(15)/4)*b**(S(9)/4)) - S(77)*sqrt(S(2))*d**(S(7)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(15)/4)*b**(S(9)/4)) + S(77)*sqrt(S(2))*d**(S(7)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(15)/4)*b**(S(9)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*(d*x)**(S(3)/2)/(S(10)*b*(a + b*x**S(2))**S(5)) + S(3)*d*(d*x)**(S(3)/2)/(S(160)*a*b*(a + b*x**S(2))**S(4)) + S(13)*d*(d*x)**(S(3)/2)/(S(640)*a**S(2)*b*(a + b*x**S(2))**S(3)) + S(117)*d*(d*x)**(S(3)/2)/(S(5120)*a**S(3)*b*(a + b*x**S(2))**S(2)) + S(117)*d*(d*x)**(S(3)/2)/(S(4096)*a**S(4)*b*(a + b*x**S(2))) + S(117)*sqrt(S(2))*d**(S(5)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(17)/4)*b**(S(7)/4)) - S(117)*sqrt(S(2))*d**(S(5)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(17)/4)*b**(S(7)/4)) - S(117)*sqrt(S(2))*d**(S(5)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(17)/4)*b**(S(7)/4)) + S(117)*sqrt(S(2))*d**(S(5)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(17)/4)*b**(S(7)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, -d*sqrt(d*x)/(S(10)*b*(a + b*x**S(2))**S(5)) + d*sqrt(d*x)/(S(160)*a*b*(a + b*x**S(2))**S(4)) + d*sqrt(d*x)/(S(128)*a**S(2)*b*(a + b*x**S(2))**S(3)) + S(11)*d*sqrt(d*x)/(S(1024)*a**S(3)*b*(a + b*x**S(2))**S(2)) + S(77)*d*sqrt(d*x)/(S(4096)*a**S(4)*b*(a + b*x**S(2))) - S(231)*sqrt(S(2))*d**(S(3)/2)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(19)/4)*b**(S(5)/4)) + S(231)*sqrt(S(2))*d**(S(3)/2)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(19)/4)*b**(S(5)/4)) - S(231)*sqrt(S(2))*d**(S(3)/2)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(19)/4)*b**(S(5)/4)) + S(231)*sqrt(S(2))*d**(S(3)/2)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(19)/4)*b**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3), x), x, (d*x)**(S(3)/2)/(S(10)*a*d*(a + b*x**S(2))**S(5)) + S(17)*(d*x)**(S(3)/2)/(S(160)*a**S(2)*d*(a + b*x**S(2))**S(4)) + S(221)*(d*x)**(S(3)/2)/(S(1920)*a**S(3)*d*(a + b*x**S(2))**S(3)) + S(663)*(d*x)**(S(3)/2)/(S(5120)*a**S(4)*d*(a + b*x**S(2))**S(2)) + S(663)*(d*x)**(S(3)/2)/(S(4096)*a**S(5)*d*(a + b*x**S(2))) + S(663)*sqrt(S(2))*sqrt(d)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(21)/4)*b**(S(3)/4)) - S(663)*sqrt(S(2))*sqrt(d)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(21)/4)*b**(S(3)/4)) - S(663)*sqrt(S(2))*sqrt(d)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(21)/4)*b**(S(3)/4)) + S(663)*sqrt(S(2))*sqrt(d)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(21)/4)*b**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, sqrt(d*x)/(S(10)*a*d*(a + b*x**S(2))**S(5)) + S(19)*sqrt(d*x)/(S(160)*a**S(2)*d*(a + b*x**S(2))**S(4)) + S(19)*sqrt(d*x)/(S(128)*a**S(3)*d*(a + b*x**S(2))**S(3)) + S(209)*sqrt(d*x)/(S(1024)*a**S(4)*d*(a + b*x**S(2))**S(2)) + S(1463)*sqrt(d*x)/(S(4096)*a**S(5)*d*(a + b*x**S(2))) - S(4389)*sqrt(S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(23)/4)*b**(S(1)/4)*sqrt(d)) + S(4389)*sqrt(S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(23)/4)*b**(S(1)/4)*sqrt(d)) - S(4389)*sqrt(S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(23)/4)*b**(S(1)/4)*sqrt(d)) + S(4389)*sqrt(S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(23)/4)*b**(S(1)/4)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, S(1)/(S(10)*a*d*sqrt(d*x)*(a + b*x**S(2))**S(5)) + S(21)/(S(160)*a**S(2)*d*sqrt(d*x)*(a + b*x**S(2))**S(4)) + S(119)/(S(640)*a**S(3)*d*sqrt(d*x)*(a + b*x**S(2))**S(3)) + S(1547)/(S(5120)*a**S(4)*d*sqrt(d*x)*(a + b*x**S(2))**S(2)) + S(13923)/(S(20480)*a**S(5)*d*sqrt(d*x)*(a + b*x**S(2))) - S(13923)/(S(4096)*a**S(6)*d*sqrt(d*x)) - S(13923)*sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(25)/4)*d**(S(3)/2)) + S(13923)*sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(25)/4)*d**(S(3)/2)) + S(13923)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(25)/4)*d**(S(3)/2)) - S(13923)*sqrt(S(2))*b**(S(1)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(25)/4)*d**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, S(1)/(S(10)*a*d*(d*x)**(S(3)/2)*(a + b*x**S(2))**S(5)) + S(23)/(S(160)*a**S(2)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))**S(4)) + S(437)/(S(1920)*a**S(3)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))**S(3)) + S(437)/(S(1024)*a**S(4)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))**S(2)) + S(4807)/(S(4096)*a**S(5)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))) - S(33649)/(S(12288)*a**S(6)*d*(d*x)**(S(3)/2)) + S(33649)*sqrt(S(2))*b**(S(3)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(27)/4)*d**(S(5)/2)) - S(33649)*sqrt(S(2))*b**(S(3)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(27)/4)*d**(S(5)/2)) + S(33649)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(27)/4)*d**(S(5)/2)) - S(33649)*sqrt(S(2))*b**(S(3)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(27)/4)*d**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**S(3)), x), x, S(1)/(S(10)*a*d*(d*x)**(S(5)/2)*(a + b*x**S(2))**S(5)) + S(5)/(S(32)*a**S(2)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))**S(4)) + S(35)/(S(128)*a**S(3)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))**S(3)) + S(595)/(S(1024)*a**S(4)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))**S(2)) + S(7735)/(S(4096)*a**S(5)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))) - S(13923)/(S(4096)*a**S(6)*d*(d*x)**(S(5)/2)) + S(69615)*b/(S(4096)*a**S(7)*d**S(3)*sqrt(d*x)) + S(69615)*sqrt(S(2))*b**(S(5)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(29)/4)*d**(S(7)/2)) - S(69615)*sqrt(S(2))*b**(S(5)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(32768)*a**(S(29)/4)*d**(S(7)/2)) - S(69615)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(29)/4)*d**(S(7)/2)) + S(69615)*sqrt(S(2))*b**(S(5)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(16384)*a**(S(29)/4)*d**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(8)*a*(d*x)**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(77)*d*(a + b*x**S(2))) + S(2)*(d*x)**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(11)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(8)*a*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(45)*d*(a + b*x**S(2))) + S(2)*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(9)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, S(8)*a*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(21)*d*(a + b*x**S(2))) + S(2)*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(7)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/sqrt(d*x), x), x, S(8)*a*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*d*(a + b*x**S(2))) + S(2)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*x)**(S(3)/2), x), x, -S(8)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*d*sqrt(d*x)*(a + b*x**S(2))) + S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*x)**(S(5)/2), x), x, -S(8)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))) + S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*(d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*x)**(S(7)/2), x), x, S(8)*a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))) - S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(d*(d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(256)*a**S(3)*(d*x)**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(7315)*d*(a + b*x**S(2))) + S(64)*a**S(2)*(d*x)**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1045)*d) + S(8)*a*(d*x)**(S(7)/2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(95)*d) + S(2)*(d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(19)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(256)*a**S(3)*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3315)*d*(a + b*x**S(2))) + S(64)*a**S(2)*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(663)*d) + S(24)*a*(d*x)**(S(5)/2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(221)*d) + S(2)*(d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(17)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(256)*a**S(3)*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1155)*d*(a + b*x**S(2))) + S(64)*a**S(2)*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(385)*d) + S(8)*a*(d*x)**(S(3)/2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(55)*d) + S(2)*(d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(15)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/sqrt(d*x), x), x, S(256)*a**S(3)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(195)*d*(a + b*x**S(2))) + S(64)*a**S(2)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(195)*d) + S(8)*a*sqrt(d*x)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(39)*d) + S(2)*sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(13)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(d*x)**(S(3)/2), x), x, -S(256)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(77)*d*sqrt(d*x)*(a + b*x**S(2))) + S(64)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(77)*d*sqrt(d*x)) + S(24)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(77)*d*sqrt(d*x)) + S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(11)*d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(d*x)**(S(5)/2), x), x, -S(256)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(45)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))) + S(64)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*d*(d*x)**(S(3)/2)) + S(8)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*d*(d*x)**(S(3)/2)) + S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(9)*d*(d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(d*x)**(S(7)/2), x), x, S(256)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(35)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))) - S(64)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(7)*d*(d*x)**(S(5)/2)) + S(8)*a*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(7)*d*(d*x)**(S(5)/2)) + S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(7)*d*(d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(16384)*a**S(5)*(d*x)**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(908523)*d*(a + b*x**S(2))) + S(4096)*a**S(4)*(d*x)**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(129789)*d) + S(512)*a**S(3)*(d*x)**(S(7)/2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(11799)*d) + S(640)*a**S(2)*(d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(11799)*d) + S(40)*a*(d*x)**(S(7)/2)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(621)*d) + S(2)*(d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(27)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(16384)*a**S(5)*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(348075)*d*(a + b*x**S(2))) + S(4096)*a**S(4)*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(69615)*d) + S(512)*a**S(3)*(d*x)**(S(5)/2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(7735)*d) + S(128)*a**S(2)*(d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(1785)*d) + S(8)*a*(d*x)**(S(5)/2)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(105)*d) + S(2)*(d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(25)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(16384)*a**S(5)*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(100947)*d*(a + b*x**S(2))) + S(4096)*a**S(4)*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(33649)*d) + S(512)*a**S(3)*(d*x)**(S(3)/2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4807)*d) + S(128)*a**S(2)*(d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(1311)*d) + S(40)*a*(d*x)**(S(3)/2)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(437)*d) + S(2)*(d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(23)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/sqrt(d*x), x), x, S(16384)*a**S(5)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(13923)*d*(a + b*x**S(2))) + S(4096)*a**S(4)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(13923)*d) + S(2560)*a**S(3)*sqrt(d*x)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(13923)*d) + S(640)*a**S(2)*sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(4641)*d) + S(40)*a*sqrt(d*x)*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(357)*d) + S(2)*sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(21)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(d*x)**(S(3)/2), x), x, -S(16384)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4389)*d*sqrt(d*x)*(a + b*x**S(2))) + S(4096)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4389)*d*sqrt(d*x)) + S(512)*a**S(3)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1463)*d*sqrt(d*x)) + S(128)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(627)*d*sqrt(d*x)) + S(8)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(57)*d*sqrt(d*x)) + S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(19)*d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(d*x)**(S(5)/2), x), x, -S(16384)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1989)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))) + S(4096)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(663)*d*(d*x)**(S(3)/2)) + S(512)*a**S(3)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(663)*d*(d*x)**(S(3)/2)) + S(640)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(1989)*d*(d*x)**(S(3)/2)) + S(40)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(221)*d*(d*x)**(S(3)/2)) + S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(17)*d*(d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(d*x)**(S(7)/2), x), x, S(16384)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(1155)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))) - S(4096)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(231)*d*(d*x)**(S(5)/2)) + S(512)*a**S(3)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(231)*d*(d*x)**(S(5)/2)) + S(128)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(231)*d*(d*x)**(S(5)/2)) + S(8)*a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)/(S(33)*d*(d*x)**(S(5)/2)) + S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)/(S(15)*d*(d*x)**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(7)/2)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -sqrt(S(2))*a**(S(5)/4)*d**(S(7)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*a**(S(5)/4)*d**(S(7)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*a**(S(5)/4)*d**(S(7)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*a**(S(5)/4)*d**(S(7)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(2)*a*d**S(3)*sqrt(d*x)*(a + b*x**S(2))/(b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(2)*d*(d*x)**(S(5)/2)*(a + b*x**S(2))/(S(5)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -sqrt(S(2))*a**(S(3)/4)*d**(S(5)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*a**(S(3)/4)*d**(S(5)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*a**(S(3)/4)*d**(S(5)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*a**(S(3)/4)*d**(S(5)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(2)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, sqrt(S(2))*a**(S(1)/4)*d**(S(3)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*a**(S(1)/4)*d**(S(3)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*a**(S(1)/4)*d**(S(3)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*a**(S(1)/4)*d**(S(3)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(2)*d*sqrt(d*x)*(a + b*x**S(2))/(b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(1)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(1)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(1)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(1)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -sqrt(S(2))*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(3)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(3)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(3)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(3)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, (-S(2)*a - S(2)*b*x**S(2))/(a*d*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(5)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(5)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(5)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(5)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, (-S(2)*a - S(2)*b*x**S(2))/(S(3)*a*d*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(7)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(7)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(7)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(7)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, (-S(2)*a - S(2)*b*x**S(2))/(S(5)*a*d*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(2)*b*(a + b*x**S(2))/(a**S(2)*d**S(3)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(9)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(4)*a**(S(9)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(9)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(2)*a**(S(9)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(15)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, -S(117)*sqrt(S(2))*a**(S(5)/4)*d**(S(15)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(117)*sqrt(S(2))*a**(S(5)/4)*d**(S(15)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(117)*sqrt(S(2))*a**(S(5)/4)*d**(S(15)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(117)*sqrt(S(2))*a**(S(5)/4)*d**(S(15)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + a*d**S(3)*(d*x)**(S(9)/2)*(a + b*x**S(2))/(S(4)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(117)*a*d**S(7)*sqrt(d*x)*(a + b*x**S(2))/(S(16)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(17)*d**S(3)*(d*x)**(S(9)/2)/(S(16)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(117)*d**S(5)*(d*x)**(S(5)/2)*(a + b*x**S(2))/(S(80)*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(13)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, -S(77)*sqrt(S(2))*a**(S(3)/4)*d**(S(13)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*a**(S(3)/4)*d**(S(13)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*a**(S(3)/4)*d**(S(13)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(77)*sqrt(S(2))*a**(S(3)/4)*d**(S(13)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + a*d**S(3)*(d*x)**(S(7)/2)*(a + b*x**S(2))/(S(4)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(15)*d**S(3)*(d*x)**(S(7)/2)/(S(16)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*d**S(5)*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(48)*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(11)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, S(45)*sqrt(S(2))*a**(S(1)/4)*d**(S(11)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*a**(S(1)/4)*d**(S(11)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*sqrt(S(2))*a**(S(1)/4)*d**(S(11)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*a**(S(1)/4)*d**(S(11)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + a*d**S(3)*(d*x)**(S(5)/2)*(a + b*x**S(2))/(S(4)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(13)*d**S(3)*(d*x)**(S(5)/2)/(S(16)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*d**S(5)*sqrt(d*x)*(a + b*x**S(2))/(S(16)*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(9)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, a*d**S(3)*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(4)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(11)*d**S(3)*(d*x)**(S(3)/2)/(S(16)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(21)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(1)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(21)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(1)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(21)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(1)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(21)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(1)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(7)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, a*d**S(3)*sqrt(d*x)*(a + b*x**S(2))/(S(4)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(9)*d**S(3)*sqrt(d*x)/(S(16)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(5)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(3)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(5)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(3)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(5)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(3)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(5)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(3)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, (d*x)**(S(7)/2)*(a + b*x**S(2))/(S(4)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - d*(d*x)**(S(3)/2)/(S(16)*a*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(5)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(5)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(5)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(5)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, (d*x)**(S(5)/2)*(a + b*x**S(2))/(S(4)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(3)*d*sqrt(d*x)/(S(16)*a*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(7)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(7)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(7)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(7)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, (d*x)**(S(3)/2)*(a + b*x**S(2))/(S(4)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(5)*(d*x)**(S(3)/2)/(S(16)*a**S(2)*d*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(5)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(9)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(5)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(9)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(5)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(9)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(5)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(9)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, sqrt(d*x)*(a + b*x**S(2))/(S(4)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(7)*sqrt(d*x)/(S(16)*a**S(2)*d*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*(S(21)*a + S(21)*b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(11)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*(S(21)*a + S(21)*b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(11)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*(S(21)*a + S(21)*b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(11)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*(S(21)*a + S(21)*b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(11)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (a + b*x**S(2))/(S(4)*a*d*sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(9)/(S(16)*a**S(2)*d*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(45)*a + S(45)*b*x**S(2))/(S(16)*a**S(3)*d*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(13)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(13)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(13)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(13)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (a + b*x**S(2))/(S(4)*a*d*(d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(11)/(S(16)*a**S(2)*d*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(77)*a + S(77)*b*x**S(2))/(S(48)*a**S(3)*d*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(15)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(77)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(15)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(15)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(77)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(15)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (a + b*x**S(2))/(S(4)*a*d*(d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(13)/(S(16)*a**S(2)*d*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(117)*a + S(117)*b*x**S(2))/(S(80)*a**S(3)*d*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(117)*b*(a + b*x**S(2))/(S(16)*a**S(4)*d**S(3)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(117)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(17)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(117)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(128)*a**(S(17)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(117)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(17)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(117)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(64)*a**(S(17)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(23)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, -S(13923)*sqrt(S(2))*a**(S(5)/4)*d**(S(23)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*b**(S(25)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(13923)*sqrt(S(2))*a**(S(5)/4)*d**(S(23)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*b**(S(25)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(13923)*sqrt(S(2))*a**(S(5)/4)*d**(S(23)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*b**(S(25)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(13923)*sqrt(S(2))*a**(S(5)/4)*d**(S(23)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*b**(S(25)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + a*d**S(3)*(d*x)**(S(17)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(119)*a*d**S(7)*(d*x)**(S(9)/2)*(a + b*x**S(2))/(S(256)*b**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(13923)*a*d**S(11)*sqrt(d*x)*(a + b*x**S(2))/(S(1024)*b**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(11)*d**S(3)*(d*x)**(S(17)/2)/(S(32)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(2023)*d**S(7)*(d*x)**(S(9)/2)/(S(1024)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(13923)*d**S(9)*(d*x)**(S(5)/2)*(a + b*x**S(2))/(S(5120)*b**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(21)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, -S(7315)*sqrt(S(2))*a**(S(3)/4)*d**(S(21)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*b**(S(23)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(7315)*sqrt(S(2))*a**(S(3)/4)*d**(S(21)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*b**(S(23)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(7315)*sqrt(S(2))*a**(S(3)/4)*d**(S(21)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*b**(S(23)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(7315)*sqrt(S(2))*a**(S(3)/4)*d**(S(21)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*b**(S(23)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + a*d**S(3)*(d*x)**(S(15)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(95)*a*d**S(7)*(d*x)**(S(7)/2)*(a + b*x**S(2))/(S(256)*b**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(31)*d**S(3)*(d*x)**(S(15)/2)/(S(96)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(1425)*d**S(7)*(d*x)**(S(7)/2)/(S(1024)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(7315)*d**S(9)*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(3072)*b**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(19)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, S(3315)*sqrt(S(2))*a**(S(1)/4)*d**(S(19)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*b**(S(21)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3315)*sqrt(S(2))*a**(S(1)/4)*d**(S(19)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*b**(S(21)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3315)*sqrt(S(2))*a**(S(1)/4)*d**(S(19)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*b**(S(21)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3315)*sqrt(S(2))*a**(S(1)/4)*d**(S(19)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*b**(S(21)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + a*d**S(3)*(d*x)**(S(13)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(221)*a*d**S(7)*(d*x)**(S(5)/2)*(a + b*x**S(2))/(S(768)*b**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(29)*d**S(3)*(d*x)**(S(13)/2)/(S(96)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(2873)*d**S(7)*(d*x)**(S(5)/2)/(S(3072)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3315)*d**S(9)*sqrt(d*x)*(a + b*x**S(2))/(S(1024)*b**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(17)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*d**S(3)*(d*x)**(S(11)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(55)*a*d**S(7)*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(256)*b**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(9)*d**S(3)*(d*x)**(S(11)/2)/(S(32)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(605)*d**S(7)*(d*x)**(S(3)/2)/(S(1024)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(1155)*sqrt(S(2))*d**(S(17)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(1)/4)*b**(S(19)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(1155)*sqrt(S(2))*d**(S(17)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(1)/4)*b**(S(19)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(1155)*sqrt(S(2))*d**(S(17)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(1)/4)*b**(S(19)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(1155)*sqrt(S(2))*d**(S(17)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(1)/4)*b**(S(19)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(15)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*d**S(3)*(d*x)**(S(9)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(39)*a*d**S(7)*sqrt(d*x)*(a + b*x**S(2))/(S(256)*b**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(25)*d**S(3)*(d*x)**(S(9)/2)/(S(96)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(351)*d**S(7)*sqrt(d*x)/(S(1024)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(195)*sqrt(S(2))*d**(S(15)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(3)/4)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(195)*sqrt(S(2))*d**(S(15)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(3)/4)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(195)*sqrt(S(2))*d**(S(15)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(3)/4)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(195)*sqrt(S(2))*d**(S(15)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(3)/4)*b**(S(17)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(13)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*d**S(3)*(d*x)**(S(7)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(23)*d**S(3)*(d*x)**(S(7)/2)/(S(96)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(77)*d**S(3)*(d*x)**(S(7)/2)*(a + b*x**S(2))/(S(768)*a*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(77)*d**S(5)*(d*x)**(S(3)/2)/(S(3072)*a*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*d**(S(13)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(5)/4)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(77)*sqrt(S(2))*d**(S(13)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(5)/4)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(77)*sqrt(S(2))*d**(S(13)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(5)/4)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*d**(S(13)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(5)/4)*b**(S(15)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(11)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*d**S(3)*(d*x)**(S(5)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(7)*d**S(3)*(d*x)**(S(5)/2)/(S(32)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(15)*d**S(3)*(d*x)**(S(5)/2)*(a + b*x**S(2))/(S(256)*a*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) - S(45)*d**S(5)*sqrt(d*x)/(S(1024)*a*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*d**(S(11)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(7)/4)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*sqrt(S(2))*d**(S(11)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(7)/4)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*d**(S(11)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(7)/4)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*sqrt(S(2))*d**(S(11)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(7)/4)*b**(S(13)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(9)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*d**S(3)*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(19)*d**S(3)*(d*x)**(S(3)/2)/(S(96)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(7)*d**S(3)*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(256)*a*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(35)*d**S(3)*(d*x)**(S(3)/2)/(S(1024)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(35)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(9)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(35)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(9)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(35)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(9)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(35)*sqrt(S(2))*d**(S(9)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(9)/4)*b**(S(11)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(7)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, a*d**S(3)*sqrt(d*x)*(a + b*x**S(2))/(S(8)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(17)*d**S(3)*sqrt(d*x)/(S(96)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(5)*d**S(3)*sqrt(d*x)*(a + b*x**S(2))/(S(768)*a*b**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(35)*d**S(3)*sqrt(d*x)/(S(3072)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(35)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(11)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(35)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(11)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(35)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(11)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(35)*sqrt(S(2))*d**(S(7)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(11)/4)*b**(S(9)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(5)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, (d*x)**(S(7)/2)*(a + b*x**S(2))/(S(8)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(3)*d*(d*x)**(S(3)/2)/(S(32)*a*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(9)*d*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(256)*a**S(2)*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(45)*d*(d*x)**(S(3)/2)/(S(1024)*a**S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(13)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(13)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(45)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(13)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(45)*sqrt(S(2))*d**(S(5)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(13)/4)*b**(S(7)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, (d*x)**(S(5)/2)*(a + b*x**S(2))/(S(8)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) - S(11)*d*sqrt(d*x)/(S(96)*a*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(11)*d*sqrt(d*x)*(a + b*x**S(2))/(S(768)*a**S(2)*b*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(77)*d*sqrt(d*x)/(S(3072)*a**S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(77)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(15)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(15)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(77)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(15)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(77)*sqrt(S(2))*d**(S(3)/2)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(15)/4)*b**(S(5)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2), x), x, (d*x)**(S(3)/2)*(a + b*x**S(2))/(S(8)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(13)*(d*x)**(S(3)/2)/(S(96)*a**S(2)*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(39)*(d*x)**(S(3)/2)*(a + b*x**S(2))/(S(256)*a**S(3)*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(195)*(d*x)**(S(3)/2)/(S(1024)*a**S(4)*d*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(195)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(17)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(195)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(17)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(195)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(17)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(195)*sqrt(S(2))*sqrt(d)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(17)/4)*b**(S(3)/4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, sqrt(d*x)*(a + b*x**S(2))/(S(8)*a*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(5)*sqrt(d*x)/(S(32)*a**S(2)*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(55)*sqrt(d*x)*(a + b*x**S(2))/(S(256)*a**S(3)*d*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(385)*sqrt(d*x)/(S(1024)*a**S(4)*d*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*(S(1155)*a + S(1155)*b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(19)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*(S(1155)*a + S(1155)*b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(19)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - sqrt(S(2))*(S(1155)*a + S(1155)*b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(19)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + sqrt(S(2))*(S(1155)*a + S(1155)*b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(19)/4)*b**(S(1)/4)*sqrt(d)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, (a + b*x**S(2))/(S(8)*a*d*sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(17)/(S(96)*a**S(2)*d*sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + (S(221)*a + S(221)*b*x**S(2))/(S(768)*a**S(3)*d*sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(663)/(S(1024)*a**S(4)*d*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(3315)*a + S(3315)*b*x**S(2))/(S(1024)*a**S(5)*d*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3315)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(21)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3315)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(21)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(3315)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(21)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(3315)*sqrt(S(2))*b**(S(1)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(21)/4)*d**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, (a + b*x**S(2))/(S(8)*a*d*(d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(19)/(S(96)*a**S(2)*d*(d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + (S(95)*a + S(95)*b*x**S(2))/(S(256)*a**S(3)*d*(d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(1045)/(S(1024)*a**S(4)*d*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(7315)*a + S(7315)*b*x**S(2))/(S(3072)*a**S(5)*d*(d*x)**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(7315)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(23)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(7315)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(23)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(7315)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(23)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(7315)*sqrt(S(2))*b**(S(3)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(23)/4)*d**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(7)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)), x), x, (a + b*x**S(2))/(S(8)*a*d*(d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(5)/2)) + S(7)/(S(32)*a**S(2)*d*(d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + (S(119)*a + S(119)*b*x**S(2))/(S(256)*a**S(3)*d*(d*x)**(S(5)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)) + S(1547)/(S(1024)*a**S(4)*d*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (S(13923)*a + S(13923)*b*x**S(2))/(S(5120)*a**S(5)*d*(d*x)**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(13923)*b*(a + b*x**S(2))/(S(1024)*a**S(6)*d**S(3)*sqrt(d*x)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(13923)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(25)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(13923)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*sqrt(d*x) + sqrt(a)*sqrt(d) + sqrt(b)*sqrt(d)*x)/(S(8192)*a**(S(25)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - S(13923)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(25)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + S(13923)*sqrt(S(2))*b**(S(5)/4)*(a + b*x**S(2))*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*sqrt(d*x)/(a**(S(1)/4)*sqrt(d)))/(S(4096)*a**(S(25)/4)*d**(S(7)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(4)/3)), x), x, S(3)/(S(10)*a*x*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(1)/3)) + S(39)/(S(40)*a**S(2)*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(1)/3)) - (S(91)*a + S(91)*b*x**S(2))/(S(40)*a**S(3)*x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(1)/3)) + S(91)*S(3)**(S(3)/4)*sqrt((a**(S(2)/3)*b**(S(2)/3) + a**(S(1)/3)*b**(S(1)/3)*(a*b + b**S(2)*x**S(2))**(S(1)/3) + (a*b + b**S(2)*x**S(2))**(S(2)/3))/(a**(S(1)/3)*b**(S(1)/3)*(-sqrt(S(3)) + S(1)) - (a*b + b**S(2)*x**S(2))**(S(1)/3))**S(2))*sqrt(-sqrt(S(3)) + S(2))*(a**(S(1)/3)*b**(S(1)/3) - (a*b + b**S(2)*x**S(2))**(S(1)/3))*(a*b + b**S(2)*x**S(2))**(S(2)/3)*elliptic_f(asin((a**(S(1)/3)*b**(S(1)/3)*(S(1) + sqrt(S(3))) - (a*b + b**S(2)*x**S(2))**(S(1)/3))/(a**(S(1)/3)*b**(S(1)/3)*(-sqrt(S(3)) + S(1)) - (a*b + b**S(2)*x**S(2))**(S(1)/3))), S(-7) + S(4)*sqrt(S(3)))/(S(120)*a**S(3)*b*x*sqrt(-a**(S(1)/3)*b**(S(1)/3)*(a**(S(1)/3)*b**(S(1)/3) - (a*b + b**S(2)*x**S(2))**(S(1)/3))/(a**(S(1)/3)*b**(S(1)/3)*(-sqrt(S(3)) + S(1)) - (a*b + b**S(2)*x**S(2))**(S(1)/3))**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, (d*x)**(m + S(1))*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(1), m/S(2) + S(2)*p + S(3)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a*d*(m + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((d*x)**m*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, (d*x)**(m + S(1))*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((m/S(2) + S(1)/2, -S(2)*p), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, -a*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/(S(2)*b**S(2)*(S(2)*p + S(1))) + (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(p + S(1))/(S(4)*b**S(2)*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, (a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/(S(2)*b*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/x, x), x, -(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(1), S(2)*p + S(1)), (S(2)*p + S(2),), S(1) + b*x**S(2)/a)/(S(2)*a*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/x**S(3), x), x, b*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(2), S(2)*p + S(1)), (S(2)*p + S(2),), S(1) + b*x**S(2)/a)/(S(2)*a**S(2)*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, x**S(5)*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(5)/2, -S(2)*p), (S(7)/2,), -b*x**S(2)/a)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, x**S(3)*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(3)/2, -S(2)*p), (S(5)/2,), -b*x**S(2)/a)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, x*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(1)/2, -S(2)*p), (S(3)/2,), -b*x**S(2)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/x**S(2), x), x, -(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(-1)/2, -S(2)*p), (S(1)/2,), -b*x**S(2)/a)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/x**S(4), x), x, -(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(-3)/2, -S(2)*p), (S(-1)/2,), -b*x**S(2)/a)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, S(2)*(d*x)**(S(5)/2)*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(5)/4, -S(2)*p), (S(9)/4,), -b*x**S(2)/a)/(S(5)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, S(2)*(d*x)**(S(3)/2)*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(3)/4, -S(2)*p), (S(7)/4,), -b*x**S(2)/a)/(S(3)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/sqrt(d*x), x), x, S(2)*sqrt(d*x)*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(1)/4, -S(2)*p), (S(5)/4,), -b*x**S(2)/a)/d, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/(d*x)**(S(3)/2), x), x, -S(2)*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(-1)/4, -S(2)*p), (S(3)/4,), -b*x**S(2)/a)/(d*sqrt(d*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p/(d*x)**(S(5)/2), x), x, -S(2)*(S(1) + b*x**S(2)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p*hyper((S(-3)/4, -S(2)*p), (S(1)/4,), -b*x**S(2)/a)/(S(3)*d*(d*x)**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4)), x), x, a*x**S(3)/S(3) + b*x**S(5)/S(5) + c*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4)), x), x, a*x**S(2)/S(2) + b*x**S(4)/S(4) + c*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a + b*x**S(2) + c*x**S(4), x), x, a*x + b*x**S(3)/S(3) + c*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x, x), x, a*log(x) + b*x**S(2)/S(2) + c*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**S(2), x), x, -a/x + b*x + c*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**S(3), x), x, -a/(S(2)*x**S(2)) + b*log(x) + c*x**S(2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**S(4), x), x, -a/(S(3)*x**S(3)) - b/x + c*x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**S(5), x), x, -a/(S(4)*x**S(4)) - b/(S(2)*x**S(2)) + c*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**S(6), x), x, -a/(S(5)*x**S(5)) - b/(S(3)*x**S(3)) - c/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**S(7), x), x, -a/(S(6)*x**S(6)) - b/(S(4)*x**S(4)) - c/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**S(8), x), x, -a/(S(7)*x**S(7)) - b/(S(5)*x**S(5)) - c/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*x**S(3)/S(3) + S(2)*a*b*x**S(5)/S(5) + S(2)*b*c*x**S(9)/S(9) + c**S(2)*x**S(11)/S(11) + x**S(7)*(S(2)*a*c/S(7) + b**S(2)/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*x**S(2)/S(2) + a*b*x**S(4)/S(2) + b*c*x**S(8)/S(4) + c**S(2)*x**S(10)/S(10) + x**S(6)*(a*c/S(3) + b**S(2)/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*x + S(2)*a*b*x**S(3)/S(3) + S(2)*b*c*x**S(7)/S(7) + c**S(2)*x**S(9)/S(9) + x**S(5)*(S(2)*a*c/S(5) + b**S(2)/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x, x), x, a**S(2)*log(x) + a*b*x**S(2) + b*c*x**S(6)/S(3) + c**S(2)*x**S(8)/S(8) + x**S(4)*(a*c/S(2) + b**S(2)/S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(2), x), x, -a**S(2)/x + S(2)*a*b*x + S(2)*b*c*x**S(5)/S(5) + c**S(2)*x**S(7)/S(7) + x**S(3)*(S(2)*a*c/S(3) + b**S(2)/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(3), x), x, -a**S(2)/(S(2)*x**S(2)) + S(2)*a*b*log(x) + b*c*x**S(4)/S(2) + c**S(2)*x**S(6)/S(6) + x**S(2)*(a*c + b**S(2)/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(4), x), x, -a**S(2)/(S(3)*x**S(3)) - S(2)*a*b/x + S(2)*b*c*x**S(3)/S(3) + c**S(2)*x**S(5)/S(5) + x*(S(2)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(5), x), x, -a**S(2)/(S(4)*x**S(4)) - a*b/x**S(2) + b*c*x**S(2) + c**S(2)*x**S(4)/S(4) + (S(2)*a*c + b**S(2))*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(6), x), x, -a**S(2)/(S(5)*x**S(5)) - S(2)*a*b/(S(3)*x**S(3)) + S(2)*b*c*x + c**S(2)*x**S(3)/S(3) - (S(2)*a*c + b**S(2))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(7), x), x, -a**S(2)/(S(6)*x**S(6)) - a*b/(S(2)*x**S(4)) + S(2)*b*c*log(x) + c**S(2)*x**S(2)/S(2) - (S(2)*a*c + b**S(2))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(8), x), x, -a**S(2)/(S(7)*x**S(7)) - S(2)*a*b/(S(5)*x**S(5)) - S(2)*b*c/x + c**S(2)*x - (S(2)*a*c + b**S(2))/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(9), x), x, -a**S(2)/(S(8)*x**S(8)) - a*b/(S(3)*x**S(6)) - b*c/x**S(2) + c**S(2)*log(x) - (S(2)*a*c + b**S(2))/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(10), x), x, -a**S(2)/(S(9)*x**S(9)) - S(2)*a*b/(S(7)*x**S(7)) - S(2)*b*c/(S(3)*x**S(3)) - c**S(2)/x - (S(2)*a*c + b**S(2))/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(11), x), x, -a**S(2)/(S(10)*x**S(10)) - a*b/(S(4)*x**S(8)) - b*c/(S(2)*x**S(4)) - c**S(2)/(S(2)*x**S(2)) - (S(2)*a*c + b**S(2))/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(12), x), x, -a**S(2)/(S(11)*x**S(11)) - S(2)*a*b/(S(9)*x**S(9)) - S(2)*b*c/(S(5)*x**S(5)) - c**S(2)/(S(3)*x**S(3)) - (S(2)*a*c + b**S(2))/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**S(13), x), x, -a**S(2)/(S(12)*x**S(12)) - a*b/(S(5)*x**S(10)) - b*c/(S(3)*x**S(6)) - c**S(2)/(S(4)*x**S(4)) - (S(2)*a*c + b**S(2))/(S(8)*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, a**S(3)*x**S(3)/S(3) + S(3)*a**S(2)*b*x**S(5)/S(5) + S(3)*a*x**S(7)*(a*c + b**S(2))/S(7) + S(3)*b*c**S(2)*x**S(13)/S(13) + b*x**S(9)*(S(6)*a*c + b**S(2))/S(9) + c**S(3)*x**S(15)/S(15) + S(3)*c*x**S(11)*(a*c + b**S(2))/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, a**S(3)*x**S(2)/S(2) + S(3)*a**S(2)*b*x**S(4)/S(4) + a*x**S(6)*(a*c + b**S(2))/S(2) + b*c**S(2)*x**S(12)/S(4) + b*x**S(8)*(S(6)*a*c + b**S(2))/S(8) + c**S(3)*x**S(14)/S(14) + S(3)*c*x**S(10)*(a*c + b**S(2))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3), x), x, a**S(3)*x + a**S(2)*b*x**S(3) + S(3)*a*x**S(5)*(a*c + b**S(2))/S(5) + S(3)*b*c**S(2)*x**S(11)/S(11) + b*x**S(7)*(S(6)*a*c + b**S(2))/S(7) + c**S(3)*x**S(13)/S(13) + c*x**S(9)*(a*c + b**S(2))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/x, x), x, a**S(3)*log(x) + S(3)*a**S(2)*b*x**S(2)/S(2) + S(3)*a*x**S(4)*(a*c + b**S(2))/S(4) + S(3)*b*c**S(2)*x**S(10)/S(10) + b*x**S(6)*(S(6)*a*c + b**S(2))/S(6) + c**S(3)*x**S(12)/S(12) + S(3)*c*x**S(8)*(a*c + b**S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/x**S(2), x), x, -a**S(3)/x + S(3)*a**S(2)*b*x + a*x**S(3)*(a*c + b**S(2)) + b*c**S(2)*x**S(9)/S(3) + b*x**S(5)*(S(6)*a*c + b**S(2))/S(5) + c**S(3)*x**S(11)/S(11) + S(3)*c*x**S(7)*(a*c + b**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/x**S(3), x), x, -a**S(3)/(S(2)*x**S(2)) + S(3)*a**S(2)*b*log(x) + S(3)*a*x**S(2)*(a*c + b**S(2))/S(2) + S(3)*b*c**S(2)*x**S(8)/S(8) + b*x**S(4)*(S(6)*a*c + b**S(2))/S(4) + c**S(3)*x**S(10)/S(10) + c*x**S(6)*(a*c + b**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/x**S(4), x), x, -a**S(3)/(S(3)*x**S(3)) - S(3)*a**S(2)*b/x + S(3)*a*x*(a*c + b**S(2)) + S(3)*b*c**S(2)*x**S(7)/S(7) + b*x**S(3)*(S(6)*a*c + b**S(2))/S(3) + c**S(3)*x**S(9)/S(9) + S(3)*c*x**S(5)*(a*c + b**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a + b*x**S(2) + c*x**S(4)), x), x, -b*x**S(2)/(S(2)*c**S(2)) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*sqrt(-S(4)*a*c + b**S(2))) + x**S(4)/(S(4)*c) + (-a*c + b**S(2))*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a + b*x**S(2) + c*x**S(4)), x), x, -b*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) + x**S(2)/(S(2)*c) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**S(2) + c*x**S(4)), x), x, b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*x**S(2) + c*x**S(4))/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(2) + c*x**S(4)), x), x, -atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**S(2) + c*x**S(4))), x), x, b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a + b*x**S(2) + c*x**S(4))/(S(4)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(2)*a*x**S(2)) - b*log(x)/a**S(2) + b*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(4)*a*x**S(4)) + b/(S(2)*a**S(2)*x**S(2)) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*sqrt(-S(4)*a*c + b**S(2))) + (-a*c + b**S(2))*log(x)/a**S(3) - (-a*c + b**S(2))*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a + b*x**S(2) + c*x**S(4)), x), x, -b*x/c**S(2) + x**S(3)/(S(3)*c) + sqrt(S(2))*(-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a + b*x**S(2) + c*x**S(4)), x), x, x/c - sqrt(S(2))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - S(1)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(3)*a*x**S(3)) + b/(a**S(2)*x) + sqrt(S(2))*sqrt(c)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*sqrt(c)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -b*x**S(2)/(S(2)*c*(-S(4)*a*c + b**S(2))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x**S(4)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*a*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + x**S(2)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + (S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*c*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - (b + S(2)*c*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + log(x)/a**S(2) - log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (-S(3)*a*c + b**S(2))/(a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) - S(2)*b*log(x)/a**S(3) + b*log(a + b*x**S(2) + c*x**S(4))/(S(2)*a**S(3)) - (S(6)*a**S(2)*c**S(2) - S(6)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -b*x**S(3)/(S(2)*c*(-S(4)*a*c + b**S(2))) + x**S(5)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + x*(-S(10)*a*c + S(3)*b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*(-S(13)*a*b*c + S(3)*b**S(3) + (S(20)*a**S(2)*c**S(2) - S(19)*a*b**S(2)*c + S(3)*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*(-S(13)*a*b*c + S(3)*b**S(3) - (S(20)*a**S(2)*c**S(2) - S(19)*a*b**S(2)*c + S(3)*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -b*x/(S(2)*c*(-S(4)*a*c + b**S(2))) + x**S(3)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(-S(6)*a*c + b**S(2) + b*(-S(8)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(-S(6)*a*c + b**S(2) - b*(-S(8)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, x*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(b - (S(4)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -sqrt(S(2))*sqrt(c)*(S(2)*b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(S(2)*b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - x*(b + S(2)*c*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(-2)), x), x, -sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*x*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) - (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) + (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-S(10)*a*c + S(3)*b**S(2))/(S(2)*a**S(2)*x*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -b*x**S(2)*(-S(7)*a*c + b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)) + b*(S(30)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x**S(8)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + x**S(4)*(a*(-S(16)*a*c + b**S(2)) + b*x**S(2)*(-S(10)*a*c + b**S(2)))/(S(4)*c*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(6)*a**S(2)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) - S(3)*a*x**S(2)*(S(2)*a + b*x**S(2))/(S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + x**S(6)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(3)*a*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + S(3)*b*x**S(2)*(S(2)*a + b*x**S(2))/(S(4)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - x**S(6)*(b + S(2)*c*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, x**S(2)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + (S(3)*a*b + x**S(2)*(S(2)*a*c + b**S(2)))/(S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - (S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(3)*b*c*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) - S(3)*b*(b + S(2)*c*x**S(2))/(S(4)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + (S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(6)*c**S(2)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + S(3)*c*(b + S(2)*c*x**S(2))/(S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - (b + S(2)*c*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**S(2) + c*x**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + (S(16)*a**S(2)*c**S(2) - S(15)*a*b**S(2)*c + S(2)*b**S(4) + S(2)*b*c*x**S(2)*(-S(7)*a*c + b**S(2)))/(S(4)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + b*(S(30)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + log(x)/a**S(3) - log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**S(2) + c*x**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(4)*a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + (S(20)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4) + S(3)*b*c*x**S(2)*(-S(6)*a*c + b**S(2)))/(S(4)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - (S(30)*a**S(2)*c**S(2) - S(21)*a*b**S(2)*c + S(3)*b**S(4))/(S(2)*a**S(3)*x**S(2)*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*b*log(x)/a**S(4) + S(3)*b*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(4)) - (-S(60)*a**S(3)*c**S(3) + S(90)*a**S(2)*b**S(2)*c**S(2) - S(30)*a*b**S(4)*c + S(3)*b**S(6))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(4)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(3)*b*x*(-S(8)*a*c + b**S(2))/(S(8)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)) + x**S(7)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + x**S(5)*(S(12)*a*b - x**S(2)*(-S(28)*a*c + b**S(2)))/(S(8)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + x**S(3)*(-S(28)*a*c + b**S(2))/(S(8)*c*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(S(84)*a**S(2)*c**S(2) - S(27)*a*b**S(2)*c + S(3)*b**S(4) + S(3)*(S(44)*a**S(2)*b*c**S(2) - S(11)*a*b**S(3)*c + b**S(5))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(S(84)*a**S(2)*c**S(2) - S(27)*a*b**S(2)*c + S(3)*b**S(4) - S(3)*b*(S(44)*a**S(2)*c**S(2) - S(11)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, x**S(5)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + x**S(3)*(S(12)*a*b + x**S(2)*(S(20)*a*c + b**S(2)))/(S(8)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - x*(S(20)*a*c + b**S(2))/(S(8)*c*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(-S(16)*a*b*c + b**S(3) + (-S(40)*a**S(2)*c**S(2) - S(18)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(-S(16)*a*b*c + b**S(3) - (-S(40)*a**S(2)*c**S(2) - S(18)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, x**S(3)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + S(3)*x*(S(4)*a*b + x**S(2)*(S(4)*a*c + b**S(2)))/(S(8)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(S(12)*a*c + S(3)*b**S(2) + S(3)*b*(S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(S(12)*a*c + S(3)*b**S(2) - S(3)*b*(S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(3)*sqrt(S(2))*sqrt(c)*(S(4)*a*c + S(3)*b**S(2) + S(2)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(8)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*sqrt(S(2))*sqrt(c)*(S(4)*a*c + S(3)*b**S(2) - S(2)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(8)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - x*(-S(4)*a*c + S(7)*b**S(2) + S(12)*b*c*x**S(2))/(S(8)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x*(b + S(2)*c*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + sqrt(S(2))*sqrt(c)*(S(20)*a*c + b**S(2) - b*(-S(52)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*sqrt(c)*(S(20)*a*c + b**S(2) + b*(-S(52)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + x*(b*(S(8)*a*c + b**S(2)) + c*x**S(2)*(S(20)*a*c + b**S(2)))/(S(8)*a*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(-3)), x), x, x*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + S(3)*sqrt(S(2))*sqrt(c)*(-S(8)*a*b*c + b**S(3) - (S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + S(3)*sqrt(S(2))*sqrt(c)*(S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4) + b*(-S(8)*a*c + b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(3)*b*c*x**S(2)*(-S(8)*a*c + b**S(2)) + (-S(7)*a*c + b**S(2))*(-S(4)*a*c + S(3)*b**S(2)))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**S(2) + c*x**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(4)*a*x*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + (S(36)*a**S(2)*c**S(2) - S(35)*a*b**S(2)*c + S(5)*b**S(4) + b*c*x**S(2)*(-S(32)*a*c + S(5)*b**S(2)))/(S(8)*a**S(2)*x*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - S(3)*sqrt(S(2))*sqrt(c)*((-S(12)*a*c + S(5)*b**S(2))*(-S(5)*a*c + b**S(2)) - (S(124)*a**S(2)*b*c**S(2) - S(47)*a*b**S(3)*c + S(5)*b**S(5))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(3)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*sqrt(S(2))*sqrt(c)*(b*(S(124)*a**S(2)*c**S(2) - S(47)*a*b**S(2)*c + S(5)*b**S(4))/sqrt(-S(4)*a*c + b**S(2)) + (-S(12)*a*c + S(5)*b**S(2))*(-S(5)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(3)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - (-S(36)*a*c + S(15)*b**S(2))*(-S(5)*a*c + b**S(2))/(S(8)*a**S(3)*x*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a - b*x**S(2) + c*x**S(4)), x), x, b*log(a - b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) + x**S(2)/(S(2)*c) + (-S(2)*a*c + b**S(2))*atanh((b - S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a - b*x**S(2) + c*x**S(4)), x), x, b*atanh((b - S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) + log(a - b*x**S(2) + c*x**S(4))/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a - b*x**S(2) + c*x**S(4)), x), x, atanh((b - S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a - b*x**S(2) + c*x**S(4))), x), x, b*atanh((b - S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a - b*x**S(2) + c*x**S(4))/(S(4)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a - b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(2)*a*x**S(2)) + b*log(x)/a**S(2) - b*log(a - b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) + (-S(2)*a*c + b**S(2))*atanh((b - S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a - b*x**S(2) + c*x**S(4)), x), x, x/c - sqrt(S(2))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a - b*x**S(2) + c*x**S(4)), x), x, sqrt(S(2))*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) - sqrt(S(2))*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a - b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*sqrt(c)*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a - b*x**S(2) + c*x**S(4))), x), x, sqrt(S(2))*sqrt(c)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*sqrt(c)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - S(1)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*x**S(4) + S(2)*a*x**S(2) + a + b), x), x, x**S(2)/(S(2)*a) - log(a*x**S(4) + S(2)*a*x**S(2) + a + b)/(S(2)*a) + (a - b)*atan(sqrt(a)*(x**S(2) + S(1))/sqrt(b))/(S(2)*a**(S(3)/2)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*x**S(4) + S(2)*a*x**S(2) + a + b), x), x, log(a*x**S(4) + S(2)*a*x**S(2) + a + b)/(S(4)*a) - atan(sqrt(a)*(x**S(2) + S(1))/sqrt(b))/(S(2)*sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*x**S(4) + S(2)*a*x**S(2) + a + b), x), x, atan(sqrt(a)*(x**S(2) + S(1))/sqrt(b))/(S(2)*sqrt(a)*sqrt(b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a*x**S(4) + S(2)*a*x**S(2) + a + b)), x), x, -sqrt(a)*atan(sqrt(a)*(x**S(2) + S(1))/sqrt(b))/(S(2)*sqrt(b)*(a + b)) - log(a*x**S(4) + S(2)*a*x**S(2) + a + b)/(S(4)*a + S(4)*b) + log(x)/(a + b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a*x**S(4) + S(2)*a*x**S(2) + a + b)), x), x, sqrt(a)*(a - b)*atan(sqrt(a)*(x**S(2) + S(1))/sqrt(b))/(S(2)*sqrt(b)*(a + b)**S(2)) - S(2)*a*log(x)/(a + b)**S(2) + a*log(a*x**S(4) + S(2)*a*x**S(2) + a + b)/(S(2)*(a + b)**S(2)) - S(1)/(x**S(2)*(S(2)*a + S(2)*b)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a*x**S(4) + S(2)*a*x**S(2) + a + b), x), x, (S(2)*sqrt(-a) + (a - b)/sqrt(b))*atan(x*(-a)**(S(1)/4)/sqrt(-sqrt(b) + sqrt(-a)))/(S(2)*(-a)**(S(5)/4)*sqrt(-sqrt(b) + sqrt(-a))) - (a - S(2)*sqrt(b)*sqrt(-a) - b)*atan(x*(-a)**(S(1)/4)/sqrt(sqrt(b) + sqrt(-a)))/(S(2)*sqrt(b)*(-a)**(S(5)/4)*sqrt(sqrt(b) + sqrt(-a))) + x/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*x**S(4) + S(2)*a*x**S(2) + a + b), x), x, sqrt(-sqrt(b) + sqrt(-a))*atan(x*(-a)**(S(1)/4)/sqrt(-sqrt(b) + sqrt(-a)))/(S(2)*sqrt(b)*(-a)**(S(3)/4)) - sqrt(sqrt(b) + sqrt(-a))*atan(x*(-a)**(S(1)/4)/sqrt(sqrt(b) + sqrt(-a)))/(S(2)*sqrt(b)*(-a)**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x**S(4) + S(2)*a*x**S(2) + a + b), x), x, atan(x*(-a)**(S(1)/4)/sqrt(sqrt(b) + sqrt(-a)))/(S(2)*sqrt(b)*(-a)**(S(1)/4)*sqrt(sqrt(b) + sqrt(-a))) - atan(x*(-a)**(S(1)/4)/sqrt(-sqrt(b) + sqrt(-a)))/(S(2)*sqrt(b)*(-a)**(S(1)/4)*sqrt(-sqrt(b) + sqrt(-a))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a*x**S(4) + S(2)*a*x**S(2) + a + b)), x), x, -S(1)/(x*(a + b)) + (-a)**(S(1)/4)*(-sqrt(b) + sqrt(-a))*atan(x*(-a)**(S(1)/4)/sqrt(sqrt(b) + sqrt(-a)))/(S(2)*sqrt(b)*(a + b)*sqrt(sqrt(b) + sqrt(-a))) - (-a)**(S(1)/4)*(sqrt(b) + sqrt(-a))*atan(x*(-a)**(S(1)/4)/sqrt(-sqrt(b) + sqrt(-a)))/(S(2)*sqrt(b)*(a + b)*sqrt(-sqrt(b) + sqrt(-a))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a**S(2) + S(2)*a*x**S(2) + b + x**S(4)), x), x, -atan(x/sqrt(a + sqrt(-b)))/(S(2)*sqrt(-b)*sqrt(a + sqrt(-b))) + atan(x/sqrt(a - sqrt(-b)))/(S(2)*sqrt(-b)*sqrt(a - sqrt(-b))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a**S(2) + S(2)*a*x**S(2) + x**S(4) + S(-1)), x), x, -atan(x/sqrt(a + S(1)))/(S(2)*sqrt(a + S(1))) - atanh(x/sqrt(-a + S(1)))/(S(2)*sqrt(-a + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a**S(2) + S(2)*a*x**S(2) + x**S(4) + S(1)), x), x, -sqrt(S(2))*atan((-sqrt(S(2))*x + sqrt(-a + sqrt(a**S(2) + S(1))))/sqrt(a + sqrt(a**S(2) + S(1))))/(S(4)*sqrt(a + sqrt(a**S(2) + S(1)))*sqrt(a**S(2) + S(1))) + sqrt(S(2))*atan((sqrt(S(2))*x + sqrt(-a + sqrt(a**S(2) + S(1))))/sqrt(a + sqrt(a**S(2) + S(1))))/(S(4)*sqrt(a + sqrt(a**S(2) + S(1)))*sqrt(a**S(2) + S(1))) - sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x*sqrt(-a + sqrt(a**S(2) + S(1))) + sqrt(a**S(2) + S(1)))/(S(8)*sqrt(-a + sqrt(a**S(2) + S(1)))*sqrt(a**S(2) + S(1))) + sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x*sqrt(-a + sqrt(a**S(2) + S(1))) + sqrt(a**S(2) + S(1)))/(S(8)*sqrt(-a + sqrt(a**S(2) + S(1)))*sqrt(a**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, -atanh(x/S(2))/S(6) + atanh(x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) + S(4)*x**S(2) + S(3)), x), x, atan(x)/S(2) - sqrt(S(3))*atan(sqrt(S(3))*x/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) + S(5)*x**S(2) + S(9)), x), x, -log(x**S(2) - x + S(3))/S(12) + log(x**S(2) + x + S(3))/S(12) - sqrt(S(11))*atan(sqrt(S(11))*(-S(2)*x + S(1))/S(11))/S(66) + sqrt(S(11))*atan(sqrt(S(11))*(S(2)*x + S(1))/S(11))/S(66), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) - x**S(2) + S(1)), x), x, -sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(12) + sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(12) + atan(S(2)*x - sqrt(S(3)))/S(2) + atan(S(2)*x + sqrt(S(3)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4) + S(2)*x**S(2) + S(2)), x), x, -log(x**S(2) - x*sqrt(S(-2) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(8)*sqrt(S(-1) + sqrt(S(2)))) + log(x**S(2) + x*sqrt(S(-2) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(8)*sqrt(S(-1) + sqrt(S(2)))) - sqrt(S(-1) + sqrt(S(2)))*atan((-S(2)*x + sqrt(S(-2) + S(2)*sqrt(S(2))))/sqrt(S(2) + S(2)*sqrt(S(2))))/S(4) + sqrt(S(-1) + sqrt(S(2)))*atan((S(2)*x + sqrt(S(-2) + S(2)*sqrt(S(2))))/sqrt(S(2) + S(2)*sqrt(S(2))))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(4) + x**S(2) + S(1)), x), x, sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(4) + S(2)*x**S(2) + S(10)), x), x, atan(x**S(2)/S(3) + S(1)/3)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(4) + S(9)*x**S(2) + S(20)), x), x, -S(2)*atan(x/S(2)) + sqrt(S(5))*atan(sqrt(S(5))*x/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(4) - x**S(2) + S(1)), x), x, sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(12) - sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(12) + atan(S(2)*x - sqrt(S(3)))/S(2) + atan(S(2)*x + sqrt(S(3)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(4) - S(2)*x**S(2) + S(2)), x), x, log(x**S(2) - x*sqrt(S(2) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(4)*sqrt(S(2) + S(2)*sqrt(S(2)))) - log(x**S(2) + x*sqrt(S(2) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(4)*sqrt(S(2) + S(2)*sqrt(S(2)))) - sqrt(S(1)/2 + sqrt(S(2))/S(2))*atan((-S(2)*x + sqrt(S(2) + S(2)*sqrt(S(2))))/sqrt(S(-2) + S(2)*sqrt(S(2))))/S(2) + sqrt(S(1)/2 + sqrt(S(2))/S(2))*atan((S(2)*x + sqrt(S(2) + S(2)*sqrt(S(2))))/sqrt(S(-2) + S(2)*sqrt(S(2))))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -b*(b + S(2)*c*x**S(2))*(-S(12)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(256)*c**S(4)) + b*(-S(12)*a*c + S(7)*b**S(2))*(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(512)*c**(S(9)/2)) + x**S(4)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(10)*c) + (a + b*x**S(2) + c*x**S(4))**(S(3)/2)*(-S(32)*a*c + S(35)*b**S(2) - S(42)*b*c*x**S(2))/(S(480)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -S(5)*b*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(48)*c**S(2)) + x**S(2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(8)*c) + (b + S(2)*c*x**S(2))*(-S(4)*a*c + S(5)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(128)*c**S(3)) - (-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(5)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*c**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -b*(b + S(2)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(16)*c**S(2)) + b*(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(5)/2)) + (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, (b + S(2)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*c) - (-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x, x), x, -sqrt(a)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(2) + b*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(c)) + sqrt(a + b*x**S(2) + c*x**S(4))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(3), x), x, sqrt(c)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(2) - sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*x**S(2)) - b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(5), x), x, -(S(2)*a + b*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*a*x**S(4)) + (-S(4)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(7), x), x, -(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*a*x**S(6)) + b*(S(2)*a + b*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(16)*a**S(2)*x**S(4)) - b*(-S(4)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(9), x), x, -(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(8)*a*x**S(8)) + S(5)*b*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(48)*a**S(2)*x**S(6)) - (S(2)*a + b*x**S(2))*(-S(4)*a*c + S(5)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(128)*a**S(3)*x**S(4)) + (-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(5)*b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(11), x), x, -(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(10)*a*x**S(10)) + S(7)*b*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(80)*a**S(2)*x**S(8)) - (-S(32)*a*c + S(35)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(480)*a**S(3)*x**S(6)) + b*(S(2)*a + b*x**S(2))*(-S(12)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(256)*a**S(4)*x**S(4)) - b*(-S(12)*a*c + S(7)*b**S(2))*(-S(4)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(512)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -a**(S(1)/4)*b*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(29)*a*c + S(8)*b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(105)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*sqrt(a)*sqrt(c)*(-S(5)*a*c + S(2)*b**S(2)) - S(29)*a*b*c + S(8)*b**S(3))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(210)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + b*x*(-S(29)*a*c + S(8)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(105)*c**(S(5)/2)*(sqrt(a) + sqrt(c)*x**S(2))) + x**S(3)*(b + S(5)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(35)*c) - x*(-S(10)*a*c + S(4)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(105)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(15)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*b*sqrt(c) - S(6)*a*c + S(2)*b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(30)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + x*(b + S(3)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*c) - x*(-S(6)*a*c + S(2)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -a**(S(1)/4)*b*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*sqrt(a)*sqrt(c) + b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + b*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))) + x*sqrt(a + b*x**S(2) + c*x**S(4))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(2), x), x, -S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/sqrt(a + b*x**S(2) + c*x**S(4)) + S(2)*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2)) - sqrt(a + b*x**S(2) + c*x**S(4))/x + sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*sqrt(a)*sqrt(c) + b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(4), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*x**S(3)) + b*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a*(sqrt(a) + sqrt(c)*x**S(2))) - b*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a*x) - b*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*sqrt(a)*sqrt(c) + b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/x**S(6), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))/(S(5)*x**S(5)) - b*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*a*x**S(3)) - S(2)*sqrt(c)*x*(-S(3)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*a**S(2)*(sqrt(a) + sqrt(c)*x**S(2))) + (-S(6)*a*c + S(2)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*a**S(2)*x) + S(2)*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(15)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*b*sqrt(c) - S(6)*a*c + S(2)*b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(30)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -b*(b + S(2)*c*x**S(2))*(-S(4)*a*c + S(3)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(256)*c**S(4)) + S(3)*b*(b + S(2)*c*x**S(2))*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2048)*c**S(5)) - S(3)*b*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(3)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4096)*c**(S(11)/2)) + x**S(4)*(a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(14)*c) + (a + b*x**S(2) + c*x**S(4))**(S(5)/2)*(-S(16)*a*c + S(21)*b**S(2) - S(30)*b*c*x**S(2))/(S(560)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(7)*b*(a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(120)*c**S(2)) + x**S(2)*(a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(12)*c) + (b + S(2)*c*x**S(2))*(-S(4)*a*c + S(7)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(384)*c**S(3)) - (b + S(2)*c*x**S(2))*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(1024)*c**S(4)) + (-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(7)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2048)*c**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -b*(b + S(2)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(32)*c**S(2)) + S(3)*b*(b + S(2)*c*x**S(2))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(256)*c**S(3)) - S(3)*b*(-S(4)*a*c + b**S(2))**S(2)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(512)*c**(S(7)/2)) + (a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(10)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, (b + S(2)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(16)*c) - (b + S(2)*c*x**S(2))*(-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(128)*c**S(2)) + S(3)*(-S(4)*a*c + b**S(2))**S(2)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x, x), x, -a**(S(3)/2)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(2) - b*(-S(12)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(3)/2)) + (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/S(6) + sqrt(a + b*x**S(2) + c*x**S(4))*(S(8)*a*c + b**S(2) + S(2)*b*c*x**S(2))/(S(16)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(3), x), x, -S(3)*sqrt(a)*b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(4) + (S(9)*b/S(8) + S(3)*c*x**S(2)/S(4))*sqrt(a + b*x**S(2) + c*x**S(4)) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(2)*x**S(2)) + (S(12)*a*c + S(3)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(5), x), x, S(3)*b*sqrt(c)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(4) - (S(3)*b - S(6)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*x**S(2)) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(4)*x**S(4)) - (S(12)*a*c + S(3)*b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(7), x), x, c**(S(3)/2)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(2) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*x**S(6)) - (S(2)*a*b + x**S(2)*(S(8)*a*c + b**S(2)))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(16)*a*x**S(4)) + b*(-S(12)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(9), x), x, -(S(2)*a + b*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(16)*a*x**S(8)) + (S(2)*a + b*x**S(2))*(-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(128)*a**S(2)*x**S(4)) - S(3)*(-S(4)*a*c + b**S(2))**S(2)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(11), x), x, -(a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(10)*a*x**S(10)) + b*(S(2)*a + b*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(32)*a**S(2)*x**S(8)) - S(3)*b*(S(2)*a + b*x**S(2))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(256)*a**S(3)*x**S(4)) + S(3)*b*(-S(4)*a*c + b**S(2))**S(2)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(512)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(13), x), x, -(a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(12)*a*x**S(12)) + S(7)*b*(a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(120)*a**S(2)*x**S(10)) - (S(2)*a + b*x**S(2))*(-S(4)*a*c + S(7)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(384)*a**S(3)*x**S(8)) + (S(2)*a + b*x**S(2))*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(1024)*a**S(4)*x**S(4)) - (-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(7)*b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2048)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(8)*a**(S(1)/4)*b*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(9)*a*c + S(2)*b**S(2))*(-S(3)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(1155)*c**(S(15)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*sqrt(c)*(S(60)*a**S(2)*c**S(2) - S(51)*a*b**S(2)*c + S(8)*b**S(4)) + S(8)*b*(-S(9)*a*c + S(2)*b**S(2))*(-S(3)*a*c + b**S(2)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2310)*c**(S(15)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - S(8)*b*x*(-S(9)*a*c + S(2)*b**S(2))*(-S(3)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(1155)*c**(S(7)/2)*(sqrt(a) + sqrt(c)*x**S(2))) + x**S(3)*(b + S(3)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(33)*c) - x**S(3)*(b*(a*c + S(2)*b**S(2)) + S(10)*c*x**S(2)*(-S(3)*a*c + b**S(2)))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(385)*c**S(2)) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(S(60)*a**S(2)*c**S(2) - S(51)*a*b**S(2)*c + S(8)*b**S(4))/(S(1155)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(84)*a**S(2)*c**S(2) - S(57)*a*b**S(2)*c + S(8)*b**S(4))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(315)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(4)*sqrt(a)*b*sqrt(c)*(-S(6)*a*c + b**S(2)) + S(84)*a**S(2)*c**S(2) - S(57)*a*b**S(2)*c + S(8)*b**S(4))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(630)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + x*(S(3)*b + S(7)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(63)*c) - x*(b*(-S(9)*a*c + S(4)*b**S(2)) + S(6)*c*x**S(2)*(-S(7)*a*c + S(2)*b**S(2)))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(315)*c**S(2)) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(S(84)*a**S(2)*c**S(2) - S(57)*a*b**S(2)*c + S(8)*b**S(4))/(S(315)*c**(S(5)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*a**(S(1)/4)*b*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(8)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(35)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*sqrt(c)*(-S(20)*a*c + b**S(2)) + S(2)*b*(-S(8)*a*c + b**S(2)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(70)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - S(2)*b*x*(-S(8)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(35)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))) + x*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/S(7) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(S(10)*a*c + b**S(2) + S(3)*b*c*x**S(2))/(S(35)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(2), x), x, -a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(12)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(5)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(8)*sqrt(a)*b*sqrt(c) + S(12)*a*c + b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(10)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + x*(S(7)*b + S(6)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/S(5) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x + x*(S(12)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(5)*sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(4), x), x, -S(8)*a**(S(1)/4)*b*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*sqrt(a + b*x**S(2) + c*x**S(4))) + S(8)*b*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*sqrt(a) + S(3)*sqrt(c)*x**S(2)) - (S(3)*b - S(2)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*x) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(3)*x**S(3)) + sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(8)*sqrt(a)*b*sqrt(c) + S(4)*a*c + S(3)*b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*a**(S(1)/4)*c**(S(1)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(6), x), x, -(b - S(6)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(5)*x**S(3)) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(5)*x**S(5)) + sqrt(c)*x*(S(12)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(5)*a*(sqrt(a) + sqrt(c)*x**S(2))) - (S(12)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(5)*a*x) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(12)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(5)*a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(8)*sqrt(a)*b*sqrt(c) + S(12)*a*c + b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(10)*a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(8), x), x, -(S(3)*b + S(30)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(35)*x**S(5)) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(7)*x**S(7)) - (-S(20)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(35)*a*x**S(3)) - S(2)*b*sqrt(c)*x*(-S(8)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(35)*a**S(2)*(sqrt(a) + sqrt(c)*x**S(2))) + S(2)*b*(-S(8)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(35)*a**S(2)*x) + S(2)*b*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(8)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(35)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*sqrt(c)*(-S(20)*a*c + b**S(2)) + S(2)*b*(-S(8)*a*c + b**S(2)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(70)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(4) - S(2)*x**S(2) + S(3)), x), x, x*sqrt(-x**S(4) - S(2)*x**S(2) + S(3))/S(3) - S(2)*sqrt(S(3))*elliptic_e(asin(x), S(-1)/3)/S(3) + S(4)*sqrt(S(3))*elliptic_f(asin(x), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -b*(-S(12)*a*c + S(5)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(7)/2)) + x**S(4)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(6)*c) + sqrt(a + b*x**S(2) + c*x**S(4))*(-S(16)*a*c + S(15)*b**S(2) - S(10)*b*c*x**S(2))/(S(48)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -S(3)*b*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*c**S(2)) + x**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(4)*c) + (-S(4)*a*c + S(3)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -b*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*c**(S(3)/2)) + sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*a*x**S(2)) + b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))/(S(4)*a*x**S(4)) + S(3)*b*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*a**S(2)*x**S(2)) - (-S(4)*a*c + S(3)*b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))/(S(6)*a*x**S(6)) + S(5)*b*sqrt(a + b*x**S(2) + c*x**S(4))/(S(24)*a**S(2)*x**S(4)) - (-S(16)*a*c + S(15)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(48)*a**S(3)*x**S(2)) + b*(-S(12)*a*c + S(5)*b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*a**(S(1)/4)*b*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*sqrt(c) + S(2)*b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - S(2)*b*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))) + x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + x*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(a*(sqrt(a) + sqrt(c)*x**S(2))) - sqrt(a + b*x**S(2) + c*x**S(4))/(a*x) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a*x**S(3)) - S(2)*b*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a**S(2)*(sqrt(a) + sqrt(c)*x**S(2))) + S(2)*b*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a**S(2)*x) + S(2)*b*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*sqrt(c) + S(2)*b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -b*(S(12)*a*c + S(5)*b**S(2))*atan((b - S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))))/(S(32)*c**(S(7)/2)) - x**S(4)*sqrt(a + b*x**S(2) - c*x**S(4))/(S(6)*c) - sqrt(a + b*x**S(2) - c*x**S(4))*(S(16)*a*c + S(15)*b**S(2) + S(10)*b*c*x**S(2))/(S(48)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -S(3)*b*sqrt(a + b*x**S(2) - c*x**S(4))/(S(8)*c**S(2)) - x**S(2)*sqrt(a + b*x**S(2) - c*x**S(4))/(S(4)*c) - (S(4)*a*c + S(3)*b**S(2))*atan((b - S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))))/(S(16)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -b*atan((b - S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))))/(S(4)*c**(S(3)/2)) - sqrt(a + b*x**S(2) - c*x**S(4))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -atan((b - S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))))/(S(2)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(-a + b*x**S(2) + c*x**S(4))), x), x, -atan((S(2)*a - b*x**S(2))/(S(2)*sqrt(a)*sqrt(-a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(-a + b*x**S(2) + c*x**S(4))), x), x, sqrt(-a + b*x**S(2) + c*x**S(4))/(S(2)*a*x**S(2)) - b*atan((S(2)*a - b*x**S(2))/(S(2)*sqrt(a)*sqrt(-a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*sqrt(-a + b*x**S(2) + c*x**S(4))), x), x, sqrt(-a + b*x**S(2) + c*x**S(4))/(S(4)*a*x**S(4)) + S(3)*b*sqrt(-a + b*x**S(2) + c*x**S(4))/(S(8)*a**S(2)*x**S(2)) - (S(4)*a*c + S(3)*b**S(2))*atan((S(2)*a - b*x**S(2))/(S(2)*sqrt(a)*sqrt(-a + b*x**S(2) + c*x**S(4))))/(S(16)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*sqrt(-a + b*x**S(2) + c*x**S(4))), x), x, sqrt(-a + b*x**S(2) + c*x**S(4))/(S(6)*a*x**S(6)) + S(5)*b*sqrt(-a + b*x**S(2) + c*x**S(4))/(S(24)*a**S(2)*x**S(4)) + (S(16)*a*c + S(15)*b**S(2))*sqrt(-a + b*x**S(2) + c*x**S(4))/(S(48)*a**S(3)*x**S(2)) - b*(S(12)*a*c + S(5)*b**S(2))*atan((S(2)*a - b*x**S(2))/(S(2)*sqrt(a)*sqrt(-a + b*x**S(2) + c*x**S(4))))/(S(32)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -sqrt(S(2))*b*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(6)*c**(S(5)/2)*sqrt(a + b*x**S(2) - c*x**S(4))) - x*sqrt(a + b*x**S(2) - c*x**S(4))/(S(3)*c) + sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*(a*c + b**S(2) - b*sqrt(S(4)*a*c + b**S(2)))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(6)*c**(S(5)/2)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -sqrt(S(2))*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(a + b*x**S(2) - c*x**S(4))) + sqrt(S(2))*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*x**S(2) - c*x**S(4))), x), x, -sqrt(a + b*x**S(2) - c*x**S(4))/(a*x) + sqrt(S(2))*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))) - sqrt(S(2))*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a + b*x**S(2) - c*x**S(4))), x), x, -sqrt(a + b*x**S(2) - c*x**S(4))/(S(3)*a*x**S(3)) + S(2)*b*sqrt(a + b*x**S(2) - c*x**S(4))/(S(3)*a**S(2)*x) - sqrt(S(2))*b*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(6)*a**S(2)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))) + sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*(a*c + b**S(2) - b*sqrt(S(4)*a*c + b**S(2)))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(6)*a**S(2)*sqrt(c)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -b*x**S(4)*sqrt(a + b*x**S(2) + c*x**S(4))/(c*(-S(4)*a*c + b**S(2))) + x**S(6)*(S(2)*a + b*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - (b*(-S(52)*a*c + S(15)*b**S(2)) - S(2)*c*x**S(2)*(-S(12)*a*c + S(5)*b**S(2)))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*c**S(3)*(-S(4)*a*c + b**S(2))) + (-S(12)*a*c + S(15)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*c**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(3)*b*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*c**(S(5)/2)) + x**S(4)*(S(2)*a + b*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + sqrt(a + b*x**S(2) + c*x**S(4))*(-S(8)*a*c + S(3)*b**S(2) - S(2)*b*c*x**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -b*sqrt(a + b*x**S(2) + c*x**S(4))/(c*(-S(4)*a*c + b**S(2))) + x**S(2)*(S(2)*a + b*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, (S(2)*a + b*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -(b + S(2)*c*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*x**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - (-S(8)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) + S(3)*b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*x**S(4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - (-S(12)*a*c + S(5)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)*x**S(4)*(-S(4)*a*c + b**S(2))) + b*(-S(52)*a*c + S(15)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*a**S(3)*x**S(2)*(-S(4)*a*c + b**S(2))) - (-S(12)*a*c + S(15)*b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(2)*a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*b*sqrt(c) - S(6)*a*c + S(2)*b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*c**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - b*x*sqrt(a + b*x**S(2) + c*x**S(4))/(c*(-S(4)*a*c + b**S(2))) + x**S(3)*(S(2)*a + b*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + x*(-S(6)*a*c + S(2)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, a**(S(1)/4)*b*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(3)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(3)/4)*(-S(4)*sqrt(a)*sqrt(c) + S(2)*b)*sqrt(a + b*x**S(2) + c*x**S(4))) - b*x*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))) + x*(S(2)*a + b*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/((sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))) - x*(b + S(2)*c*x**S(2))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*c**(S(1)/4)*(-S(2)*sqrt(a)*sqrt(c) + b)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(-3)/2), x), x, -b*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(a*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))) + x*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + b*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(3)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(3)/4)*(-S(2)*sqrt(a)*sqrt(c) + b)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*x*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*sqrt(c)*x*(-S(3)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(a**S(2)*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))) - (-S(6)*a*c + S(2)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(a**S(2)*x*(-S(4)*a*c + b**S(2))) - S(2)*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*b*sqrt(c) - S(6)*a*c + S(2)*b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, elliptic_f(asin(sqrt(S(2))*x/S(2)), S(-6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(4)*x**S(2) + S(2)), x), x, sqrt(S(1)/3 + sqrt(S(10))/S(6))*elliptic_f(asin(x*sqrt(S(-1) + sqrt(S(10))/S(2))), S(-7)/3 - S(2)*sqrt(S(10))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(3)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(sqrt(S(6))*x/sqrt(S(3) + sqrt(S(33)))), S(-7)/4 - sqrt(S(33))/S(4))/sqrt(S(-3) + sqrt(S(33))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(2)*x**S(2) + S(2)), x), x, elliptic_f(asin(sqrt(S(3))*x/sqrt(S(1) + sqrt(S(7)))), S(-4)/3 - sqrt(S(7))/S(3))/sqrt(S(-1) + sqrt(S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(x), S(-3)/2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(2)), x), x, S(6)**(S(3)/4)*elliptic_f(asin(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), S(-1))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - x**S(2) + S(2)), x), x, sqrt(S(3))*elliptic_f(asin(sqrt(S(6))*x/S(2)), S(-2)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(2)*x**S(2) + S(2)), x), x, elliptic_f(asin(sqrt(S(3))*x/sqrt(S(-1) + sqrt(S(7)))), S(-4)/3 + sqrt(S(7))/S(3))/sqrt(S(1) + sqrt(S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(3)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(sqrt(S(6))*x/sqrt(S(-3) + sqrt(S(33)))), S(-7)/4 + sqrt(S(33))/S(4))/sqrt(S(3) + sqrt(S(33))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(4)*x**S(2) + S(2)), x), x, sqrt(S(-1)/3 + sqrt(S(10))/S(6))*elliptic_f(asin(x*sqrt(S(1) + sqrt(S(10))/S(2))), S(-7)/3 + S(2)*sqrt(S(10))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(5)*x**S(2) + S(2)), x), x, sqrt(S(6))*elliptic_f(asin(sqrt(S(3))*x), S(-1)/6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(7)*x**S(2) + S(3)), x), x, sqrt(S(2))*elliptic_f(asin(S(2)*x/sqrt(S(7) + sqrt(S(73)))), S(-61)/12 - S(7)*sqrt(S(73))/S(12))/sqrt(S(-7) + sqrt(S(73))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(6)*x**S(2) + S(3)), x), x, sqrt(S(1)/2 + sqrt(S(15))/S(6))*elliptic_f(asin(x*sqrt(S(-1) + sqrt(S(15))/S(3))), S(-4) - sqrt(S(15))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(5)*x**S(2) + S(3)), x), x, elliptic_f(asin(sqrt(S(3))*x/S(3)), S(-6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(4)*x**S(2) + S(3)), x), x, elliptic_f(asin(sqrt(S(2))*x/sqrt(S(2) + sqrt(S(10)))), S(-7)/3 - S(2)*sqrt(S(10))/S(3))/sqrt(S(-2) + sqrt(S(10))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(3)*x**S(2) + S(3)), x), x, sqrt(S(2))*elliptic_f(asin(S(2)*x/sqrt(S(3) + sqrt(S(33)))), S(-7)/4 - sqrt(S(33))/S(4))/sqrt(S(-3) + sqrt(S(33))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(2)*x**S(2) + S(3)), x), x, elliptic_f(asin(sqrt(S(2))*x/sqrt(S(1) + sqrt(S(7)))), S(-4)/3 - sqrt(S(7))/S(3))/sqrt(S(-1) + sqrt(S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + x**S(2) + S(3)), x), x, sqrt(S(2))*elliptic_f(asin(sqrt(S(6))*x/S(3)), S(-3)/2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(3)), x), x, S(6)**(S(3)/4)*elliptic_f(asin(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), S(-1))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - x**S(2) + S(3)), x), x, sqrt(S(3))*elliptic_f(asin(x), S(-2)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(2)*x**S(2) + S(3)), x), x, elliptic_f(asin(sqrt(S(2))*x/sqrt(S(-1) + sqrt(S(7)))), S(-4)/3 + sqrt(S(7))/S(3))/sqrt(S(1) + sqrt(S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(3)*x**S(2) + S(3)), x), x, sqrt(S(2))*elliptic_f(asin(S(2)*x/sqrt(S(-3) + sqrt(S(33)))), S(-7)/4 + sqrt(S(33))/S(4))/sqrt(S(3) + sqrt(S(33))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(4)*x**S(2) + S(3)), x), x, elliptic_f(asin(sqrt(S(2))*x/sqrt(S(-2) + sqrt(S(10)))), S(-7)/3 + S(2)*sqrt(S(10))/S(3))/sqrt(S(2) + sqrt(S(10))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(5)*x**S(2) + S(3)), x), x, sqrt(S(6))*elliptic_f(asin(sqrt(S(2))*x), S(-1)/6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(6)*x**S(2) + S(3)), x), x, sqrt(S(-1)/2 + sqrt(S(15))/S(6))*elliptic_f(asin(x*sqrt(S(1) + sqrt(S(15))/S(3))), S(-4) + sqrt(S(15))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(7)*x**S(2) + S(3)), x), x, sqrt(S(2))*elliptic_f(asin(S(2)*x/sqrt(S(-7) + sqrt(S(73)))), S(-61)/12 + S(7)*sqrt(S(73))/S(12))/sqrt(S(7) + sqrt(S(73))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(5)*x**S(2) + S(-2)), x), x, sqrt(S(7))*sqrt(x**S(2) + S(2))*sqrt(S(3)*x**S(2) + S(-1))*elliptic_f(asin(sqrt(S(14))*x/(S(2)*sqrt(S(3)*x**S(2) + S(-1)))), S(6)/7)/(S(7)*sqrt(S(3)*x**S(4) + S(5)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(4)*x**S(2) + S(-2)), x), x, S(10)**(S(3)/4)*sqrt((-x**S(2)*(-sqrt(S(10)) + S(2)) + S(2))/(-x**S(2)*(S(2) + sqrt(S(10))) + S(2)))*sqrt(x**S(2)*(S(2) + sqrt(S(10))) + S(-2))*elliptic_f(asin(S(2)**(S(3)/4)*S(5)**(S(1)/4)*x/sqrt(x**S(2)*(S(2) + sqrt(S(10))) + S(-2))), sqrt(S(10))/S(10) + S(1)/2)/(S(20)*sqrt(S(3)*x**S(4) + S(4)*x**S(2) + S(-2))*sqrt(S(1)/(-x**S(2)*(S(2) + sqrt(S(10))) + S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(3)*x**S(2) + S(-2)), x), x, sqrt(S(2))*S(33)**(S(3)/4)*sqrt((-x**S(2)*(-sqrt(S(33)) + S(3)) + S(4))/(-x**S(2)*(S(3) + sqrt(S(33))) + S(4)))*sqrt(x**S(2)*(S(3) + sqrt(S(33))) + S(-4))*elliptic_f(asin(sqrt(S(2))*S(33)**(S(1)/4)*x/sqrt(x**S(2)*(S(3) + sqrt(S(33))) + S(-4))), sqrt(S(33))/S(22) + S(1)/2)/(S(132)*sqrt(S(3)*x**S(4) + S(3)*x**S(2) + S(-2))*sqrt(S(1)/(-x**S(2)*(S(3) + sqrt(S(33))) + S(4)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(2)*x**S(2) + S(-2)), x), x, S(7)**(S(3)/4)*sqrt((-x**S(2)*(-sqrt(S(7)) + S(1)) + S(2))/(-x**S(2)*(S(1) + sqrt(S(7))) + S(2)))*sqrt(x**S(2)*(S(1) + sqrt(S(7))) + S(-2))*elliptic_f(asin(sqrt(S(2))*S(7)**(S(1)/4)*x/sqrt(x**S(2)*(S(1) + sqrt(S(7))) + S(-2))), sqrt(S(7))/S(14) + S(1)/2)/(S(14)*sqrt(S(3)*x**S(4) + S(2)*x**S(2) + S(-2))*sqrt(S(1)/(-x**S(2)*(S(1) + sqrt(S(7))) + S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + x**S(2) + S(-2)), x), x, sqrt(S(5))*sqrt(x**S(2) + S(1))*sqrt(S(3)*x**S(2) + S(-2))*elliptic_f(asin(sqrt(S(5))*x/sqrt(S(3)*x**S(2) + S(-2))), S(3)/5)/(S(5)*sqrt(S(3)*x**S(4) + x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((sqrt(S(6))*x**S(2) + S(2))/(-sqrt(S(6))*x**S(2) + S(2)))*sqrt(sqrt(S(6))*x**S(2) + S(-2))*elliptic_f(asin(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/sqrt(sqrt(S(6))*x**S(2) + S(-2))), S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) + S(-2))*sqrt(S(1)/(-sqrt(S(6))*x**S(2) + S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - x**S(2) + S(-2)), x), x, sqrt(S(5))*sqrt(x**S(2) + S(-1))*sqrt(S(3)*x**S(2) + S(2))*elliptic_f(asin(sqrt(S(10))*x/(S(2)*sqrt(x**S(2) + S(-1)))), S(2)/5)/(S(5)*sqrt(S(3)*x**S(4) - x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(2)*x**S(2) + S(-2)), x), x, S(7)**(S(3)/4)*sqrt((x**S(2)*(S(1) + sqrt(S(7))) + S(2))/(x**S(2)*(-sqrt(S(7)) + S(1)) + S(2)))*sqrt(-x**S(2)*(-sqrt(S(7)) + S(1)) + S(-2))*elliptic_f(asin(sqrt(S(2))*S(7)**(S(1)/4)*x/sqrt(-x**S(2)*(-sqrt(S(7)) + S(1)) + S(-2))), -sqrt(S(7))/S(14) + S(1)/2)/(S(14)*sqrt(S(3)*x**S(4) - S(2)*x**S(2) + S(-2))*sqrt(S(1)/(x**S(2)*(-sqrt(S(7)) + S(1)) + S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(3)*x**S(2) + S(-2)), x), x, sqrt(S(2))*S(33)**(S(3)/4)*sqrt((x**S(2)*(S(3) + sqrt(S(33))) + S(4))/(x**S(2)*(-sqrt(S(33)) + S(3)) + S(4)))*sqrt(-x**S(2)*(-sqrt(S(33)) + S(3)) + S(-4))*elliptic_f(asin(sqrt(S(2))*S(33)**(S(1)/4)*x/sqrt(-x**S(2)*(-sqrt(S(33)) + S(3)) + S(-4))), -sqrt(S(33))/S(22) + S(1)/2)/(S(132)*sqrt(S(3)*x**S(4) - S(3)*x**S(2) + S(-2))*sqrt(S(1)/(x**S(2)*(-sqrt(S(33)) + S(3)) + S(4)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(4)*x**S(2) + S(-2)), x), x, S(10)**(S(3)/4)*sqrt((x**S(2)*(S(2) + sqrt(S(10))) + S(2))/(x**S(2)*(-sqrt(S(10)) + S(2)) + S(2)))*sqrt(-x**S(2)*(-sqrt(S(10)) + S(2)) + S(-2))*elliptic_f(asin(S(2)**(S(3)/4)*S(5)**(S(1)/4)*x/sqrt(-x**S(2)*(-sqrt(S(10)) + S(2)) + S(-2))), -sqrt(S(10))/S(10) + S(1)/2)/(S(20)*sqrt(S(3)*x**S(4) - S(4)*x**S(2) + S(-2))*sqrt(S(1)/(x**S(2)*(-sqrt(S(10)) + S(2)) + S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(5)*x**S(2) + S(-2)), x), x, sqrt(S(7))*sqrt(x**S(2) + S(-2))*sqrt(S(3)*x**S(2) + S(1))*elliptic_f(asin(sqrt(S(7))*x/sqrt(x**S(2) + S(-2))), S(1)/7)/(S(7)*sqrt(S(3)*x**S(4) - S(5)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(7)*x**S(2) + S(-3)), x), x, sqrt(S(3))*S(73)**(S(3)/4)*sqrt((-x**S(2)*(-sqrt(S(73)) + S(7)) + S(6))/(-x**S(2)*(S(7) + sqrt(S(73))) + S(6)))*sqrt(x**S(2)*(S(7) + sqrt(S(73))) + S(-6))*elliptic_f(asin(sqrt(S(2))*S(73)**(S(1)/4)*x/sqrt(x**S(2)*(S(7) + sqrt(S(73))) + S(-6))), S(7)*sqrt(S(73))/S(146) + S(1)/2)/(S(438)*sqrt(S(2)*x**S(4) + S(7)*x**S(2) + S(-3))*sqrt(S(1)/(-x**S(2)*(S(7) + sqrt(S(73))) + S(6)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(6)*x**S(2) + S(-3)), x), x, sqrt(S(2))*S(3)**(S(1)/4)*S(5)**(S(3)/4)*sqrt((-x**S(2)*(-sqrt(S(15)) + S(3)) + S(3))/(-x**S(2)*(S(3) + sqrt(S(15))) + S(3)))*sqrt(x**S(2)*(S(3) + sqrt(S(15))) + S(-3))*elliptic_f(asin(S(15)**(S(1)/4)*sqrt(S(2))*x/sqrt(x**S(2)*(S(3) + sqrt(S(15))) + S(-3))), sqrt(S(15))/S(10) + S(1)/2)/(S(30)*sqrt(S(2)*x**S(4) + S(6)*x**S(2) + S(-3))*sqrt(S(1)/(-x**S(2)*(S(3) + sqrt(S(15))) + S(3)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(5)*x**S(2) + S(-3)), x), x, sqrt(S(7))*sqrt(x**S(2) + S(3))*sqrt(S(2)*x**S(2) + S(-1))*elliptic_f(asin(sqrt(S(21))*x/(S(3)*sqrt(S(2)*x**S(2) + S(-1)))), S(6)/7)/(S(7)*sqrt(S(2)*x**S(4) + S(5)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(4)*x**S(2) + S(-3)), x), x, S(2)**(S(1)/4)*sqrt(S(3))*S(5)**(S(3)/4)*sqrt((-x**S(2)*(-sqrt(S(10)) + S(2)) + S(3))/(-x**S(2)*(S(2) + sqrt(S(10))) + S(3)))*sqrt(x**S(2)*(S(2) + sqrt(S(10))) + S(-3))*elliptic_f(asin(S(2)**(S(3)/4)*S(5)**(S(1)/4)*x/sqrt(x**S(2)*(S(2) + sqrt(S(10))) + S(-3))), sqrt(S(10))/S(10) + S(1)/2)/(S(30)*sqrt(S(2)*x**S(4) + S(4)*x**S(2) + S(-3))*sqrt(S(1)/(-x**S(2)*(S(2) + sqrt(S(10))) + S(3)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(3)*x**S(2) + S(-3)), x), x, S(11)**(S(3)/4)*S(3)**(S(1)/4)*sqrt((-x**S(2)*(-sqrt(S(33)) + S(3)) + S(6))/(-x**S(2)*(S(3) + sqrt(S(33))) + S(6)))*sqrt(x**S(2)*(S(3) + sqrt(S(33))) + S(-6))*elliptic_f(asin(sqrt(S(2))*S(33)**(S(1)/4)*x/sqrt(x**S(2)*(S(3) + sqrt(S(33))) + S(-6))), sqrt(S(33))/S(22) + S(1)/2)/(S(66)*sqrt(S(2)*x**S(4) + S(3)*x**S(2) + S(-3))*sqrt(S(1)/(-x**S(2)*(S(3) + sqrt(S(33))) + S(6)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(-3)), x), x, sqrt(S(6))*S(7)**(S(3)/4)*sqrt((-x**S(2)*(-sqrt(S(7)) + S(1)) + S(3))/(-x**S(2)*(S(1) + sqrt(S(7))) + S(3)))*sqrt(x**S(2)*(S(1) + sqrt(S(7))) + S(-3))*elliptic_f(asin(sqrt(S(2))*S(7)**(S(1)/4)*x/sqrt(x**S(2)*(S(1) + sqrt(S(7))) + S(-3))), sqrt(S(7))/S(14) + S(1)/2)/(S(42)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(-3))*sqrt(S(1)/(-x**S(2)*(S(1) + sqrt(S(7))) + S(3)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + x**S(2) + S(-3)), x), x, sqrt(S(5))*sqrt(x**S(2) + S(-1))*sqrt(S(2)*x**S(2) + S(3))*elliptic_f(asin(sqrt(S(15))*x/(S(3)*sqrt(x**S(2) + S(-1)))), S(3)/5)/(S(5)*sqrt(S(2)*x**S(4) + x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(-3)), x), x, S(6)**(S(1)/4)*sqrt((sqrt(S(6))*x**S(2) + S(3))/(-sqrt(S(6))*x**S(2) + S(3)))*sqrt(sqrt(S(6))*x**S(2) + S(-3))*elliptic_f(asin(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/sqrt(sqrt(S(6))*x**S(2) + S(-3))), S(1)/2)/(S(6)*sqrt(S(2)*x**S(4) + S(-3))*sqrt(S(1)/(-sqrt(S(6))*x**S(2) + S(3)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - x**S(2) + S(-3)), x), x, sqrt(S(5))*sqrt(x**S(2) + S(1))*sqrt(S(2)*x**S(2) + S(-3))*elliptic_f(asin(sqrt(S(5))*x/sqrt(S(2)*x**S(2) + S(-3))), S(2)/5)/(S(5)*sqrt(S(2)*x**S(4) - x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(2)*x**S(2) + S(-3)), x), x, sqrt(S(6))*S(7)**(S(3)/4)*sqrt((x**S(2)*(S(1) + sqrt(S(7))) + S(3))/(x**S(2)*(-sqrt(S(7)) + S(1)) + S(3)))*sqrt(-x**S(2)*(-sqrt(S(7)) + S(1)) + S(-3))*elliptic_f(asin(sqrt(S(2))*S(7)**(S(1)/4)*x/sqrt(-x**S(2)*(-sqrt(S(7)) + S(1)) + S(-3))), -sqrt(S(7))/S(14) + S(1)/2)/(S(42)*sqrt(S(2)*x**S(4) - S(2)*x**S(2) + S(-3))*sqrt(S(1)/(x**S(2)*(-sqrt(S(7)) + S(1)) + S(3)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(3)*x**S(2) + S(-3)), x), x, S(11)**(S(3)/4)*S(3)**(S(1)/4)*sqrt((x**S(2)*(S(3) + sqrt(S(33))) + S(6))/(x**S(2)*(-sqrt(S(33)) + S(3)) + S(6)))*sqrt(-x**S(2)*(-sqrt(S(33)) + S(3)) + S(-6))*elliptic_f(asin(sqrt(S(2))*S(33)**(S(1)/4)*x/sqrt(-x**S(2)*(-sqrt(S(33)) + S(3)) + S(-6))), -sqrt(S(33))/S(22) + S(1)/2)/(S(66)*sqrt(S(2)*x**S(4) - S(3)*x**S(2) + S(-3))*sqrt(S(1)/(x**S(2)*(-sqrt(S(33)) + S(3)) + S(6)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(4)*x**S(2) + S(-3)), x), x, S(2)**(S(1)/4)*sqrt(S(3))*S(5)**(S(3)/4)*sqrt((x**S(2)*(S(2) + sqrt(S(10))) + S(3))/(x**S(2)*(-sqrt(S(10)) + S(2)) + S(3)))*sqrt(-x**S(2)*(-sqrt(S(10)) + S(2)) + S(-3))*elliptic_f(asin(S(2)**(S(3)/4)*S(5)**(S(1)/4)*x/sqrt(-x**S(2)*(-sqrt(S(10)) + S(2)) + S(-3))), -sqrt(S(10))/S(10) + S(1)/2)/(S(30)*sqrt(S(2)*x**S(4) - S(4)*x**S(2) + S(-3))*sqrt(S(1)/(x**S(2)*(-sqrt(S(10)) + S(2)) + S(3)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(5)*x**S(2) + S(-3)), x), x, sqrt(S(7))*sqrt(x**S(2) + S(-3))*sqrt(S(2)*x**S(2) + S(1))*elliptic_f(asin(sqrt(S(7))*x/sqrt(x**S(2) + S(-3))), S(1)/7)/(S(7)*sqrt(S(2)*x**S(4) - S(5)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*sqrt((S(3)*x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(-1)/2)/(S(2)*sqrt(S(3)*x**S(4) + S(5)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(4)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(4)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) + S(4)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(3)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(3)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(2)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(2)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) + S(2)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) + x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) - x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(2)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(2)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) - S(2)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(3)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(3)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) - S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(4)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(4)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(S(3)*x**S(4) - S(4)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(5)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(5)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), S(1)/2 + S(5)*sqrt(S(6))/S(24))/(S(12)*sqrt(S(3)*x**S(4) - S(5)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) - S(6)*x**S(2) + S(2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(6)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), S(1)/2 + sqrt(S(6))/S(4))/(S(12)*sqrt(S(3)*x**S(4) - S(6)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(9)*x**S(2) + S(3)), x), x, sqrt((x**S(2)*(-sqrt(S(57)) + S(9)) + S(6))/(x**S(2)*(sqrt(S(57)) + S(9)) + S(6)))*(x**S(2)*(sqrt(S(57)) + S(9)) + S(6))*elliptic_f(atan(x*sqrt(sqrt(S(57))/S(6) + S(3)/2)), S(-19)/4 + S(3)*sqrt(S(57))/S(4))/(sqrt(S(6)*sqrt(S(57)) + S(54))*sqrt(S(2)*x**S(4) + S(9)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(8)*x**S(2) + S(3)), x), x, sqrt((x**S(2)*(-sqrt(S(10)) + S(4)) + S(3))/(x**S(2)*(sqrt(S(10)) + S(4)) + S(3)))*(x**S(2)*(sqrt(S(10)) + S(4)) + S(3))*elliptic_f(atan(x*sqrt(sqrt(S(10))/S(3) + S(4)/3)), S(-10)/3 + S(4)*sqrt(S(10))/S(3))/(sqrt(S(3)*sqrt(S(10)) + S(12))*sqrt(S(2)*x**S(4) + S(8)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(7)*x**S(2) + S(3)), x), x, sqrt(S(6))*sqrt((x**S(2) + S(3))/(S(2)*x**S(2) + S(1)))*(S(2)*x**S(2) + S(1))*elliptic_f(atan(sqrt(S(2))*x), S(5)/6)/(S(6)*sqrt(S(2)*x**S(4) + S(7)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(6)*x**S(2) + S(3)), x), x, sqrt((x**S(2)*(-sqrt(S(3)) + S(3)) + S(3))/(x**S(2)*(sqrt(S(3)) + S(3)) + S(3)))*(x**S(2)*(sqrt(S(3)) + S(3)) + S(3))*elliptic_f(atan(x*sqrt(sqrt(S(3))/S(3) + S(1))), S(-1) + sqrt(S(3)))/(sqrt(S(3)*sqrt(S(3)) + S(9))*sqrt(S(2)*x**S(4) + S(6)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(5)*x**S(2) + S(3)), x), x, sqrt(S(3))*sqrt((S(2)*x**S(2) + S(3))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/3)/(S(3)*sqrt(S(2)*x**S(4) + S(5)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(4)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(4)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(4)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(3)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(3)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(3)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) - x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(2)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(2)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) - S(2)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(3)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(3)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) - S(3)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(4)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(4)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) - S(4)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(5)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(5)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), S(1)/2 + S(5)*sqrt(S(6))/S(24))/(S(12)*sqrt(S(2)*x**S(4) - S(5)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(6)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(6)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), S(1)/2 + sqrt(S(6))/S(4))/(S(12)*sqrt(S(2)*x**S(4) - S(6)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) - S(7)*x**S(2) + S(3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(7)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), S(1)/2 + S(7)*sqrt(S(6))/S(24))/(S(12)*sqrt(S(2)*x**S(4) - S(7)*x**S(2) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(7)*x**S(2) + S(-3)), x), x, -sqrt(S(5))*elliptic_f(acos(sqrt(S(3))*x/S(3)), S(6)/5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(6)*x**S(2) + S(-3)), x), x, -sqrt(S(2))*S(3)**(S(3)/4)*elliptic_f(acos(x*sqrt(-sqrt(S(3))/S(3) + S(1))), S(1)/2 + sqrt(S(3))/S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(5)*x**S(2) + S(-3)), x), x, -elliptic_f(acos(sqrt(S(6))*x/S(3)), S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(4)*x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(4)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) + S(4)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(3)*x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(3)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) + S(3)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(2)*x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - S(2)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) + S(2)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) - x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) + x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) - x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(2)*x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) - S(2)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(3)*x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(3)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) - S(3)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(4)*x**S(2) + S(-3)), x), x, S(6)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(4)*x**S(2) + S(3))/(sqrt(S(6))*x**S(2) + S(3))**S(2))*(sqrt(S(6))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*S(3)**(S(3)/4)*x/S(3)), -sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(-S(2)*x**S(4) - S(4)*x**S(2) + S(-3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) - S(5)*x**S(2) + S(-3)), x), x, sqrt(S(3))*sqrt(S(2)*x**S(2) + S(3))*elliptic_f(atan(x), S(1)/3)/(S(3)*sqrt((S(2)*x**S(2) + S(3))/(x**S(2) + S(1)))*sqrt(-x**S(2) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(6)*x**S(2) + S(-2)), x), x, -sqrt(S(2))*S(3)**(S(3)/4)*elliptic_f(acos(sqrt(S(3))*x/sqrt(sqrt(S(3)) + S(3))), S(1)/2 + sqrt(S(3))/S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(5)*x**S(2) + S(-2)), x), x, -elliptic_f(acos(x), S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(4)*x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(4)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) + S(4)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(3)*x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(3)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) + S(3)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(2)*x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - S(2)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) + S(2)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) - x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) + x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(24) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) - x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(2)*x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(2)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(12) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) - S(2)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(3)*x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(3)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(8) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) - S(3)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(4)*x**S(2) + S(-2)), x), x, S(6)**(S(3)/4)*sqrt((S(3)*x**S(4) + S(4)*x**S(2) + S(2))/(sqrt(S(6))*x**S(2) + S(2))**S(2))*(sqrt(S(6))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(3)**(S(1)/4)*x/S(2)), -sqrt(S(6))/S(6) + S(1)/2)/(S(12)*sqrt(-S(3)*x**S(4) - S(4)*x**S(2) + S(-2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) - S(5)*x**S(2) + S(-2)), x), x, -sqrt(S(2))*sqrt(-S(3)*x**S(2) + S(-2))*elliptic_f(atan(x), S(-1)/2)/(S(2)*sqrt((S(3)*x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(5)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, S(10)**(S(3)/4)*sqrt((S(5)*x**S(4) + S(5)*x**S(2) + S(2))/(sqrt(S(10))*x**S(2) + S(2))**S(2))*(sqrt(S(10))*x**S(2) + S(2))*elliptic_f(S(2)*atan(S(2)**(S(3)/4)*S(5)**(S(1)/4)*x/S(2)), -sqrt(S(10))/S(8) + S(1)/2)/(S(20)*sqrt(S(5)*x**S(4) + S(5)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(4)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, S(2)**(S(1)/4)*sqrt((S(4)*x**S(4) + S(5)*x**S(2) + S(2))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -S(5)*sqrt(S(2))/S(16) + S(1)/2)/(S(4)*sqrt(S(4)*x**S(4) + S(5)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(3)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*sqrt((S(3)*x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(-1)/2)/(S(2)*sqrt(S(3)*x**S(4) + S(5)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(S(2)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt((x**S(2) + S(2))/(S(2)*x**S(2) + S(1)))*(S(2)*x**S(2) + S(1))*elliptic_f(atan(sqrt(S(2))*x), S(3)/4)/(S(2)*sqrt(S(2)*x**S(4) + S(5)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt((x**S(2)*(-sqrt(S(17)) + S(5)) + S(4))/(x**S(2)*(sqrt(S(17)) + S(5)) + S(4)))*(x**S(2)*(sqrt(S(17)) + S(5)) + S(4))*elliptic_f(atan(x*sqrt(sqrt(S(17)) + S(5))/S(2)), S(-17)/4 + S(5)*sqrt(S(17))/S(4))/(S(2)*sqrt(sqrt(S(17)) + S(5))*sqrt(x**S(4) + S(5)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(sqrt(S(2))*x/sqrt(S(5) + sqrt(S(33)))), S(-29)/4 - S(5)*sqrt(S(33))/S(4))/sqrt(S(-5) + sqrt(S(33))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(2)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(S(2)*x/sqrt(S(5) + sqrt(S(41)))), S(-33)/8 - S(5)*sqrt(S(41))/S(8))/sqrt(S(-5) + sqrt(S(41))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(3)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, elliptic_f(asin(sqrt(S(2))*x/S(2)), S(-6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(4)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(S(2)*sqrt(S(2))*x/sqrt(S(5) + sqrt(S(57)))), S(-41)/16 - S(5)*sqrt(S(57))/S(16))/sqrt(S(-5) + sqrt(S(57))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(5)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(sqrt(S(10))*x/sqrt(S(5) + sqrt(S(65)))), S(-9)/4 - sqrt(S(65))/S(4))/sqrt(S(-5) + sqrt(S(65))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(6)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(S(2)*sqrt(S(3))*x/sqrt(S(5) + sqrt(S(73)))), S(-49)/24 - S(5)*sqrt(S(73))/S(24))/sqrt(S(-5) + sqrt(S(73))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(7)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(x), S(-7)/2)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(8)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(S(4)*x/sqrt(S(5) + sqrt(S(89)))), S(-57)/32 - S(5)*sqrt(S(89))/S(32))/sqrt(S(-5) + sqrt(S(89))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-S(9)*x**S(4) + S(5)*x**S(2) + S(2)), x), x, sqrt(S(2))*elliptic_f(asin(S(3)*sqrt(S(2))*x/sqrt(S(5) + sqrt(S(97)))), S(-61)/36 - S(5)*sqrt(S(97))/S(36))/sqrt(S(-5) + sqrt(S(97))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -S(2)*b*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*c**S(2)*x) + x*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -b*atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*c**(S(3)/2)) + sqrt(b*x**S(2) + c*x**S(4))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(b*x**S(2) + c*x**S(4)), x), x, sqrt(b*x**S(2) + c*x**S(4))/(c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(b*x**S(2) + c*x**S(4)), x), x, atanh(sqrt(c)*x**S(2)/sqrt(b*x**S(2) + c*x**S(4)))/sqrt(c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(b*x**S(2) + c*x**S(4)), x), x, -atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(b*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(2)*b*x**S(3)) + c*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(2)*b**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b*x**S(4)) + S(2)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(3)*b**S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(b*x**S(2) + c*x**S(4))), x), x, -sqrt(b*x**S(2) + c*x**S(4))/(S(4)*b*x**S(5)) + S(3)*c*sqrt(b*x**S(2) + c*x**S(4))/(S(8)*b**S(2)*x**S(3)) - S(3)*c**S(2)*atanh(sqrt(b)*x/sqrt(b*x**S(2) + c*x**S(4)))/(S(8)*b**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(a + c*x**S(4)), x), x, -a**(S(3)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(6)*c**(S(5)/4)*sqrt(a + c*x**S(4))) + x*sqrt(a + c*x**S(4))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a + c*x**S(4)), x), x, sqrt(a + c*x**S(4))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + c*x**S(4)), x), x, -a**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(c**(S(3)/4)*sqrt(a + c*x**S(4))) + a**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*c**(S(3)/4)*sqrt(a + c*x**S(4))) + x*sqrt(a + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + c*x**S(4)), x), x, atanh(sqrt(c)*x**S(2)/sqrt(a + c*x**S(4)))/(S(2)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + c*x**S(4)), x), x, sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt(a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + c*x**S(4))), x), x, -atanh(sqrt(a + c*x**S(4))/sqrt(a))/(S(2)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + c*x**S(4))), x), x, sqrt(c)*x*sqrt(a + c*x**S(4))/(a*(sqrt(a) + sqrt(c)*x**S(2))) - sqrt(a + c*x**S(4))/(a*x) - c**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(a**(S(3)/4)*sqrt(a + c*x**S(4))) + c**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(3)/4)*sqrt(a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + c*x**S(4))), x), x, -sqrt(a + c*x**S(4))/(S(2)*a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a + c*x**S(4))), x), x, -sqrt(a + c*x**S(4))/(S(3)*a*x**S(3)) - c**(S(3)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(6)*a**(S(5)/4)*sqrt(a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(a + b*x**S(2)), x), x, S(3)*a**S(2)*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(8)*b**(S(5)/2)) - S(3)*a*x*sqrt(a + b*x**S(2))/(S(8)*b**S(2)) + x**S(3)*sqrt(a + b*x**S(2))/(S(4)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a + b*x**S(2)), x), x, -a*sqrt(a + b*x**S(2))/b**S(2) + (a + b*x**S(2))**(S(3)/2)/(S(3)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*x**S(2)), x), x, -a*atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/(S(2)*b**(S(3)/2)) + x*sqrt(a + b*x**S(2))/(S(2)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*x**S(2)), x), x, sqrt(a + b*x**S(2))/b, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*x**S(2)), x), x, atanh(sqrt(b)*x/sqrt(a + b*x**S(2)))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*x**S(2))), x), x, -atanh(sqrt(a + b*x**S(2))/sqrt(a))/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*x**S(2))), x), x, -sqrt(a + b*x**S(2))/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + b*x**S(2))), x), x, -sqrt(a + b*x**S(2))/(S(2)*a*x**S(2)) + b*atanh(sqrt(a + b*x**S(2))/sqrt(a))/(S(2)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a + b*x**S(2))), x), x, -sqrt(a + b*x**S(2))/(S(3)*a*x**S(3)) + S(2)*b*sqrt(a + b*x**S(2))/(S(3)*a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(c*x**S(4)), x), x, x*sqrt(c*x**S(4))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(c*x**S(4)), x), x, sqrt(c*x**S(4))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(c*x**S(4)), x), x, x**S(3)/sqrt(c*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(c*x**S(4)), x), x, x**S(2)*log(x)/sqrt(c*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(c*x**S(4)), x), x, -x/sqrt(c*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(c*x**S(4))), x), x, -S(1)/(S(2)*sqrt(c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(c*x**S(4))), x), x, -S(1)/(S(3)*x*sqrt(c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(c*x**S(4))), x), x, -S(1)/(S(4)*x**S(2)*sqrt(c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(c*x**S(4))), x), x, -S(1)/(S(5)*x**S(3)*sqrt(c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(a), x), x, x**S(5)/(S(5)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a), x), x, x**S(4)/(S(4)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a), x), x, x**S(3)/(S(3)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a), x), x, x**S(2)/(S(2)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a), x), x, x/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a)*x), x), x, log(x)/sqrt(a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a)*x**S(2)), x), x, -S(1)/(sqrt(a)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a)*x**S(3)), x), x, -S(1)/(S(2)*sqrt(a)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a)*x**S(4)), x), x, -S(1)/(S(3)*sqrt(a)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x**S(4) - S(2)*x**S(2) + S(3)), x), x, sqrt(S(3))*elliptic_f(asin(x), S(-1)/3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(-x**S(4) + S(5)*x**S(2) + S(-1)), x), x, -S(21)**(S(3)/4)*elliptic_f(acos(sqrt(S(2))*x/sqrt(sqrt(S(21)) + S(5))), S(1)/2 + S(5)*sqrt(S(21))/S(42))/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*a*x**(S(7)/2)/S(7) + S(2)*b*x**(S(11)/2)/S(11) + S(2)*c*x**(S(15)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*a*x**(S(5)/2)/S(5) + S(2)*b*x**(S(9)/2)/S(9) + S(2)*c*x**(S(13)/2)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*a*x**(S(3)/2)/S(3) + S(2)*b*x**(S(7)/2)/S(7) + S(2)*c*x**(S(11)/2)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/sqrt(x), x), x, S(2)*a*sqrt(x) + S(2)*b*x**(S(5)/2)/S(5) + S(2)*c*x**(S(9)/2)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**(S(3)/2), x), x, -S(2)*a/sqrt(x) + S(2)*b*x**(S(3)/2)/S(3) + S(2)*c*x**(S(7)/2)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**(S(5)/2), x), x, -S(2)*a/(S(3)*x**(S(3)/2)) + S(2)*b*sqrt(x) + S(2)*c*x**(S(5)/2)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/x**(S(7)/2), x), x, -S(2)*a/(S(5)*x**(S(5)/2)) - S(2)*b/sqrt(x) + S(2)*c*x**(S(3)/2)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*a**S(2)*x**(S(7)/2)/S(7) + S(4)*a*b*x**(S(11)/2)/S(11) + S(4)*b*c*x**(S(19)/2)/S(19) + S(2)*c**S(2)*x**(S(23)/2)/S(23) + x**(S(15)/2)*(S(4)*a*c/S(15) + S(2)*b**S(2)/S(15)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*a**S(2)*x**(S(5)/2)/S(5) + S(4)*a*b*x**(S(9)/2)/S(9) + S(4)*b*c*x**(S(17)/2)/S(17) + S(2)*c**S(2)*x**(S(21)/2)/S(21) + x**(S(13)/2)*(S(4)*a*c/S(13) + S(2)*b**S(2)/S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*a**S(2)*x**(S(3)/2)/S(3) + S(4)*a*b*x**(S(7)/2)/S(7) + S(4)*b*c*x**(S(15)/2)/S(15) + S(2)*c**S(2)*x**(S(19)/2)/S(19) + x**(S(11)/2)*(S(4)*a*c/S(11) + S(2)*b**S(2)/S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/sqrt(x), x), x, S(2)*a**S(2)*sqrt(x) + S(4)*a*b*x**(S(5)/2)/S(5) + S(4)*b*c*x**(S(13)/2)/S(13) + S(2)*c**S(2)*x**(S(17)/2)/S(17) + x**(S(9)/2)*(S(4)*a*c/S(9) + S(2)*b**S(2)/S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**(S(3)/2), x), x, -S(2)*a**S(2)/sqrt(x) + S(4)*a*b*x**(S(3)/2)/S(3) + S(4)*b*c*x**(S(11)/2)/S(11) + S(2)*c**S(2)*x**(S(15)/2)/S(15) + x**(S(7)/2)*(S(4)*a*c/S(7) + S(2)*b**S(2)/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**(S(5)/2), x), x, -S(2)*a**S(2)/(S(3)*x**(S(3)/2)) + S(4)*a*b*sqrt(x) + S(4)*b*c*x**(S(9)/2)/S(9) + S(2)*c**S(2)*x**(S(13)/2)/S(13) + x**(S(5)/2)*(S(4)*a*c/S(5) + S(2)*b**S(2)/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/x**(S(7)/2), x), x, -S(2)*a**S(2)/(S(5)*x**(S(5)/2)) - S(4)*a*b/sqrt(x) + S(4)*b*c*x**(S(7)/2)/S(7) + S(2)*c**S(2)*x**(S(11)/2)/S(11) + x**(S(3)/2)*(S(4)*a*c/S(3) + S(2)*b**S(2)/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*a**S(3)*x**(S(7)/2)/S(7) + S(6)*a**S(2)*b*x**(S(11)/2)/S(11) + S(2)*a*x**(S(15)/2)*(a*c + b**S(2))/S(5) + S(2)*b*c**S(2)*x**(S(27)/2)/S(9) + S(2)*b*x**(S(19)/2)*(S(6)*a*c + b**S(2))/S(19) + S(2)*c**S(3)*x**(S(31)/2)/S(31) + S(6)*c*x**(S(23)/2)*(a*c + b**S(2))/S(23), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*a**S(3)*x**(S(5)/2)/S(5) + S(2)*a**S(2)*b*x**(S(9)/2)/S(3) + S(6)*a*x**(S(13)/2)*(a*c + b**S(2))/S(13) + S(6)*b*c**S(2)*x**(S(25)/2)/S(25) + S(2)*b*x**(S(17)/2)*(S(6)*a*c + b**S(2))/S(17) + S(2)*c**S(3)*x**(S(29)/2)/S(29) + S(2)*c*x**(S(21)/2)*(a*c + b**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*a**S(3)*x**(S(3)/2)/S(3) + S(6)*a**S(2)*b*x**(S(7)/2)/S(7) + S(6)*a*x**(S(11)/2)*(a*c + b**S(2))/S(11) + S(6)*b*c**S(2)*x**(S(23)/2)/S(23) + S(2)*b*x**(S(15)/2)*(S(6)*a*c + b**S(2))/S(15) + S(2)*c**S(3)*x**(S(27)/2)/S(27) + S(6)*c*x**(S(19)/2)*(a*c + b**S(2))/S(19), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/sqrt(x), x), x, S(2)*a**S(3)*sqrt(x) + S(6)*a**S(2)*b*x**(S(5)/2)/S(5) + S(2)*a*x**(S(9)/2)*(a*c + b**S(2))/S(3) + S(2)*b*c**S(2)*x**(S(21)/2)/S(7) + S(2)*b*x**(S(13)/2)*(S(6)*a*c + b**S(2))/S(13) + S(2)*c**S(3)*x**(S(25)/2)/S(25) + S(6)*c*x**(S(17)/2)*(a*c + b**S(2))/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/x**(S(3)/2), x), x, -S(2)*a**S(3)/sqrt(x) + S(2)*a**S(2)*b*x**(S(3)/2) + S(6)*a*x**(S(7)/2)*(a*c + b**S(2))/S(7) + S(6)*b*c**S(2)*x**(S(19)/2)/S(19) + S(2)*b*x**(S(11)/2)*(S(6)*a*c + b**S(2))/S(11) + S(2)*c**S(3)*x**(S(23)/2)/S(23) + S(2)*c*x**(S(15)/2)*(a*c + b**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/x**(S(5)/2), x), x, -S(2)*a**S(3)/(S(3)*x**(S(3)/2)) + S(6)*a**S(2)*b*sqrt(x) + S(6)*a*x**(S(5)/2)*(a*c + b**S(2))/S(5) + S(6)*b*c**S(2)*x**(S(17)/2)/S(17) + S(2)*b*x**(S(9)/2)*(S(6)*a*c + b**S(2))/S(9) + S(2)*c**S(3)*x**(S(21)/2)/S(21) + S(6)*c*x**(S(13)/2)*(a*c + b**S(2))/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)/x**(S(7)/2), x), x, -S(2)*a**S(3)/(S(5)*x**(S(5)/2)) - S(6)*a**S(2)*b/sqrt(x) + S(2)*a*x**(S(3)/2)*(a*c + b**S(2)) + S(2)*b*c**S(2)*x**(S(15)/2)/S(5) + S(2)*b*x**(S(7)/2)*(S(6)*a*c + b**S(2))/S(7) + S(2)*c**S(3)*x**(S(19)/2)/S(19) + S(6)*c*x**(S(11)/2)*(a*c + b**S(2))/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*x**(S(3)/2)/(S(3)*c) - S(2)**(S(1)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(7)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(7)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(7)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(7)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*sqrt(x)/c + S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, -S(2)**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, S(2)**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(a + b*x**S(2) + c*x**S(4)), x), x, S(2)**(S(1)/4)*c**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*c**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*c**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*c**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)**(S(3)/4)*c**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*c**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/((-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)**(S(1)/4)*c**(S(1)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*c**(S(1)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*c**(S(1)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*c**(S(1)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)/(a*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(5)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, S(2)**(S(3)/4)*c**(S(3)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)/(S(3)*a*x**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(7)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)/(S(5)*a*x**(S(5)/2)) + S(2)*b/(a**S(2)*sqrt(x)) + S(2)**(S(1)/4)*c**(S(1)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*c**(S(1)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*c**(S(1)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*c**(S(1)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -b*x**(S(3)/2)/(S(2)*c*(-S(4)*a*c + b**S(2))) + x**(S(7)/2)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - S(2)**(S(1)/4)*(-S(20)*a*b*c + S(3)*b**S(3) - (-S(14)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(7)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(1)/4)*(-S(20)*a*b*c + S(3)*b**S(3) - (-S(14)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(7)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(1)/4)*(-S(20)*a*b*c + S(3)*b**S(3) + (-S(14)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(7)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(1)/4)*(-S(20)*a*b*c + S(3)*b**S(3) + (-S(14)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(7)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(11)/2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -b*sqrt(x)/(S(2)*c*(-S(4)*a*c + b**S(2))) + x**(S(5)/2)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - S(2)**(S(3)/4)*(-S(10)*a*c + b**S(2) - b*(-S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*(-S(10)*a*c + b**S(2) - b*(-S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*(-S(10)*a*c + b**S(2) + b*(-S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*(-S(10)*a*c + b**S(2) + b*(-S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, x**(S(3)/2)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + S(2)**(S(1)/4)*(b - (S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*(b - (S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*(S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(1)/4)*(S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, sqrt(x)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + S(2)**(S(3)/4)*(S(4)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(3)/4)*(S(4)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(3)/4)*(S(4)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(3)/4)*(S(4)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*c**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)**(S(1)/4)*c**(S(1)/4)*(S(4)*b - sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(1)/4)*c**(S(1)/4)*(S(4)*b - sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(1)/4)*c**(S(1)/4)*(S(4)*b + sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(1)/4)*c**(S(1)/4)*(S(4)*b + sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - x**(S(3)/2)*(b + S(2)*c*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)**(S(3)/4)*c**(S(3)/4)*(-S(4)*b/sqrt(-S(4)*a*c + b**S(2)) + S(3))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*(-S(4)*b/sqrt(-S(4)*a*c + b**S(2)) + S(3))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*(S(4)*b/sqrt(-S(4)*a*c + b**S(2)) + S(3))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*(S(4)*b/sqrt(-S(4)*a*c + b**S(2)) + S(3))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))) - sqrt(x)*(b + S(2)*c*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)**(S(1)/4)*c**(S(1)/4)*(b + (-S(20)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*c**(S(1)/4)*(b + (-S(20)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*c**(S(1)/4)*(b - (-S(20)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*c**(S(1)/4)*(b - (-S(20)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))) + x**(S(3)/2)*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -S(2)**(S(3)/4)*c**(S(3)/4)*(-S(28)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(3)/4)*c**(S(3)/4)*(-S(28)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(3)/4)*c**(S(3)/4)*(-S(28)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(3)/4)*c**(S(3)/4)*(-S(28)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(x)*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*sqrt(x)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - S(2)**(S(1)/4)*c**(S(1)/4)*(-S(28)*a*b*c + S(5)*b**S(3) + (-S(18)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(1)/4)*c**(S(1)/4)*(-S(28)*a*b*c + S(5)*b**S(3) + (-S(18)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)**(S(1)/4)*c**(S(1)/4)*(-S(28)*a*b*c + S(5)*b**S(3) - (-S(18)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)**(S(1)/4)*c**(S(1)/4)*(-S(28)*a*b*c + S(5)*b**S(3) - (-S(18)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(8)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-S(18)*a*c + S(5)*b**S(2))/(S(2)*a**S(2)*sqrt(x)*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(15)/2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, x**(S(9)/2)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + S(3)*x**(S(5)/2)*(S(8)*a*b + x**S(2)*(S(12)*a*c + b**S(2)))/(S(16)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - sqrt(x)*(S(36)*a*c + S(3)*b**S(2))/(S(16)*c*(-S(4)*a*c + b**S(2))**S(2)) - S(2)**(S(3)/4)*(-S(84)*a*b*c + S(3)*b**S(3) - S(3)*(-S(24)*a**S(2)*c**S(2) - S(30)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(2)**(S(3)/4)*(-S(84)*a*b*c + S(3)*b**S(3) - S(3)*(-S(24)*a**S(2)*c**S(2) - S(30)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(2)**(S(3)/4)*(-S(84)*a*b*c + S(3)*b**S(3) + S(3)*(-S(24)*a**S(2)*c**S(2) - S(30)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(2)**(S(3)/4)*(-S(84)*a*b*c + S(3)*b**S(3) + S(3)*(-S(24)*a**S(2)*c**S(2) - S(30)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(13)/2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, x**(S(7)/2)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + x**(S(3)/2)*(S(24)*a*b + x**S(2)*(S(28)*a*c + S(5)*b**S(2)))/(S(16)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + S(2)**(S(1)/4)*(S(28)*a*c + S(5)*b**S(2) - (S(172)*a*b*c + S(5)*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(2)**(S(1)/4)*(S(28)*a*c + S(5)*b**S(2) - (S(172)*a*b*c + S(5)*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**S(2)) + S(2)**(S(1)/4)*(S(172)*a*b*c + S(5)*b**S(3) + sqrt(-S(4)*a*c + b**S(2))*(S(28)*a*c + S(5)*b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(2)**(S(1)/4)*(S(172)*a*b*c + S(5)*b**S(3) + sqrt(-S(4)*a*c + b**S(2))*(S(28)*a*c + S(5)*b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(11)/2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, x**(S(5)/2)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + sqrt(x)*(S(24)*a*b + x**S(2)*(S(20)*a*c + S(7)*b**S(2)))/(S(16)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - S(2)**(S(3)/4)*(S(60)*a*c + S(21)*b**S(2) - S(3)*(S(36)*a*b*c + S(7)*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(2)**(S(3)/4)*(S(60)*a*c + S(21)*b**S(2) - S(3)*(S(36)*a*b*c + S(7)*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(2)**(S(3)/4)*(S(108)*a*b*c + S(21)*b**S(3) + S(3)*sqrt(-S(4)*a*c + b**S(2))*(S(20)*a*c + S(7)*b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(2)**(S(3)/4)*(S(108)*a*b*c + S(21)*b**S(3) + S(3)*sqrt(-S(4)*a*c + b**S(2))*(S(20)*a*c + S(7)*b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*c**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(9)/2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(S(20)*a*c + S(11)*b**S(2) - S(4)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(S(20)*a*c + S(11)*b**S(2) - S(4)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(S(20)*a*c + S(11)*b**S(2) + S(4)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(S(20)*a*c + S(11)*b**S(2) + S(4)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x**(S(3)/2)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - S(3)*x**(S(3)/2)*(-S(4)*a*c + S(5)*b**S(2) + S(8)*b*c*x**S(2))/(S(16)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(7)/2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(2)**(S(3)/4)*c**(S(3)/4)*(S(28)*a*c + S(41)*b**S(2) - S(36)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(2)**(S(3)/4)*c**(S(3)/4)*(S(28)*a*c + S(41)*b**S(2) - S(36)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(2)**(S(3)/4)*c**(S(3)/4)*(S(28)*a*c + S(41)*b**S(2) + S(36)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(2)**(S(3)/4)*c**(S(3)/4)*(S(28)*a*c + S(41)*b**S(2) + S(36)*b*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(32)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(x)*(S(2)*a + b*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - sqrt(x)*(-S(4)*a*c + S(13)*b**S(2) + S(24)*b*c*x**S(2))/(S(16)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(5)/2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x**(S(3)/2)*(b + S(2)*c*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(-S(68)*a*b*c + b**S(3) + sqrt(-S(4)*a*c + b**S(2))*(S(12)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(-S(68)*a*b*c + b**S(3) + sqrt(-S(4)*a*c + b**S(2))*(S(12)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(S(68)*a*b*c/sqrt(-S(4)*a*c + b**S(2)) + S(12)*a*c - b**S(3)/sqrt(-S(4)*a*c + b**S(2)) + b**S(2))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*S(2)**(S(1)/4)*c**(S(1)/4)*(S(68)*a*b*c/sqrt(-S(4)*a*c + b**S(2)) + S(12)*a*c - b**S(3)/sqrt(-S(4)*a*c + b**S(2)) + b**S(2))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**S(2)) + S(3)*x**(S(3)/2)*(b*(S(4)*a*c + b**S(2)) + c*x**S(2)*(S(12)*a*c + b**S(2)))/(S(16)*a*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -sqrt(x)*(b + S(2)*c*x**S(2))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(-S(68)*a*b*c + b**S(3) + sqrt(-S(4)*a*c + b**S(2))*(S(44)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(-S(68)*a*b*c + b**S(3) + sqrt(-S(4)*a*c + b**S(2))*(S(44)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(S(68)*a*b*c/sqrt(-S(4)*a*c + b**S(2)) + S(44)*a*c - b**S(3)/sqrt(-S(4)*a*c + b**S(2)) + b**S(2))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(S(68)*a*b*c/sqrt(-S(4)*a*c + b**S(2)) + S(44)*a*c - b**S(3)/sqrt(-S(4)*a*c + b**S(2)) + b**S(2))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(x)*(b*(S(20)*a*c + b**S(2)) + c*x**S(2)*(S(44)*a*c + b**S(2)))/(S(16)*a*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, x**(S(3)/2)*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + S(2)**(S(1)/4)*c**(S(1)/4)*(S(520)*a**S(2)*c**S(2) - S(54)*a*b**S(2)*c + S(5)*b**S(4) + b*(-S(44)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(2)**(S(1)/4)*c**(S(1)/4)*(S(520)*a**S(2)*c**S(2) - S(54)*a*b**S(2)*c + S(5)*b**S(4) + b*(-S(44)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(2)**(S(1)/4)*c**(S(1)/4)*(S(520)*a**S(2)*c**S(2) - S(54)*a*b**S(2)*c + S(5)*b**S(4) - b*(-S(44)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(2)**(S(1)/4)*c**(S(1)/4)*(S(520)*a**S(2)*c**S(2) - S(54)*a*b**S(2)*c + S(5)*b**S(4) - b*(-S(44)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x**(S(3)/2)*(S(52)*a**S(2)*c**S(2) - S(45)*a*b**S(2)*c + S(5)*b**S(4) + b*c*x**S(2)*(-S(44)*a*c + S(5)*b**S(2)))/(S(16)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(a + b*x**S(2) + c*x**S(4))**S(3)), x), x, sqrt(x)*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(S(280)*a**S(2)*c**S(2) - S(66)*a*b**S(2)*c + S(7)*b**S(4) + b*(-S(52)*a*c + S(7)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(S(280)*a**S(2)*c**S(2) - S(66)*a*b**S(2)*c + S(7)*b**S(4) + b*(-S(52)*a*c + S(7)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(S(280)*a**S(2)*c**S(2) - S(66)*a*b**S(2)*c + S(7)*b**S(4) - b*(-S(52)*a*c + S(7)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*S(2)**(S(3)/4)*c**(S(3)/4)*(S(280)*a**S(2)*c**S(2) - S(66)*a*b**S(2)*c + S(7)*b**S(4) - b*(-S(52)*a*c + S(7)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(x)/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(64)*a**S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(x)*(S(60)*a**S(2)*c**S(2) - S(55)*a*b**S(2)*c + S(7)*b**S(4) + b*c*x**S(2)*(-S(52)*a*c + S(7)*b**S(2)))/(S(16)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*(d*x)**(S(5)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(5)/4, S(-1)/2, S(-1)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*(d*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(3)/4, S(-1)/2, S(-1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/sqrt(d*x), x), x, S(2)*sqrt(d*x)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(1)/4, S(-1)/2, S(-1)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/(d*x)**(S(3)/2), x), x, -S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(-1)/4, S(-1)/2, S(-1)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*sqrt(d*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*a*(d*x)**(S(5)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(5)/4, S(-3)/2, S(-3)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*a*(d*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(3)/4, S(-3)/2, S(-3)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/sqrt(d*x), x), x, S(2)*a*sqrt(d*x)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(1)/4, S(-3)/2, S(-3)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(d*x)**(S(3)/2), x), x, -S(2)*a*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(-1)/4, S(-3)/2, S(-3)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*sqrt(d*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*(d*x)**(S(5)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(5)/4, S(1)/2, S(1)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*d*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*(d*x)**(S(3)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(1)/2, S(1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*d*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, S(2)*sqrt(d*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/4, S(1)/2, S(1)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-1)/4, S(1)/2, S(1)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*sqrt(d*x)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(S(3)/2)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*(d*x)**(S(5)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(5)/4, S(3)/2, S(3)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*a*d*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d*x)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*(d*x)**(S(3)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(3)/2, S(3)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*d*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d*x)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(2)*sqrt(d*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/4, S(3)/2, S(3)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*d*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*x)**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -S(2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-1)/4, S(3)/2, S(3)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*d*sqrt(d*x)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, a**S(3)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(3)*a**S(2)*b*(d*x)**(m + S(3))/(d**S(3)*(m + S(3))) + S(3)*a*(d*x)**(m + S(5))*(a*c + b**S(2))/(d**S(5)*(m + S(5))) + S(3)*b*c**S(2)*(d*x)**(m + S(11))/(d**S(11)*(m + S(11))) + b*(d*x)**(m + S(7))*(S(6)*a*c + b**S(2))/(d**S(7)*(m + S(7))) + c**S(3)*(d*x)**(m + S(13))/(d**S(13)*(m + S(13))) + S(3)*c*(d*x)**(m + S(9))*(a*c + b**S(2))/(d**S(9)*(m + S(9))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(2)*a*b*(d*x)**(m + S(3))/(d**S(3)*(m + S(3))) + S(2)*b*c*(d*x)**(m + S(7))/(d**S(7)*(m + S(7))) + c**S(2)*(d*x)**(m + S(9))/(d**S(9)*(m + S(9))) + (d*x)**(m + S(5))*(S(2)*a*c + b**S(2))/(d**S(5)*(m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(2) + c*x**S(4)), x), x, a*(d*x)**(m + S(1))/(d*(m + S(1))) + b*(d*x)**(m + S(3))/(d**S(3)*(m + S(3))) + c*(d*x)**(m + S(5))/(d**S(5)*(m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**S(2) + c*x**S(4)), x), x, -S(2)*c*(d*x)**(m + S(1))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*(d*x)**(m + S(1))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/(d*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -c*(d*x)**(m + S(1))*(-S(4)*a*c*(-m + S(3)) + b**S(2)*(-m + S(1)) - b*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*d*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + c*(d*x)**(m + S(1))*(-S(4)*a*c*(-m + S(3)) + b**S(2)*(-m + S(1)) + b*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*d*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (d*x)**(m + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*d*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**p/x, x), x, S(4)**(p + S(-1))*((b + S(2)*c*x**S(2) - sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(2)))**(-p)*((b + S(2)*c*x**S(2) + sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(2)))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(-S(2)*p, -p, -p, -S(2)*p + S(1), -(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(2)), -(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(2)))/p, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**p/x**S(3), x), x, -S(2)**(S(2)*p + S(-1))*((b + S(2)*c*x**S(2) - sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(2)))**(-p)*((b + S(2)*c*x**S(2) + sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(2)))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(-S(2)*p + S(1), -p, -p, -S(2)*p + S(2), -(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(2)), -(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(2)))/(x**S(2)*(-S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**p/x**S(5), x), x, -S(4)**(p + S(-1))*((b + S(2)*c*x**S(2) - sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(2)))**(-p)*((b + S(2)*c*x**S(2) + sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(2)))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(-S(2)*p + S(2), -p, -p, -S(2)*p + S(3), -(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(2)), -(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(2)))/(x**S(4)*(-p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2) + c*x**S(4))**p, x), x, x**S(5)*(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(S(5)/2, -p, -p, S(7)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))**p, x), x, x**S(3)*(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(S(3)/2, -p, -p, S(5)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**p, x), x, x*(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(S(1)/2, -p, -p, S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**p/x**S(2), x), x, -(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(S(-1)/2, -p, -p, S(1)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**p/x**S(4), x), x, -(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(S(-3)/2, -p, -p, S(-1)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, a*(d*x)**(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(m/S(2) + S(1)/2, S(-3)/2, S(-3)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, (d*x)**(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(m/S(2) + S(1)/2, S(-1)/2, S(-1)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, (d*x)**(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(2) + S(1)/2, S(1)/2, S(1)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, (d*x)**(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(2) + S(1)/2, S(3)/2, S(3)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*d*(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(2) + c*x**S(4))**p, x), x, (d*x)**(m + S(1))*(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(2) + c*x**S(4))**p*AppellF1(m/S(2) + S(1)/2, -p, -p, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(2) + c*x**S(4))**p, x), x, S(2)**(p + S(-1))*b*(-(b + S(2)*c*x**S(2) - sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))**(-p + S(-1))*(a + b*x**S(2) + c*x**S(4))**(p + S(1))*hyper((-p, p + S(1)), (p + S(2),), (b + S(2)*c*x**S(2) + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*sqrt(-S(4)*a*c + b**S(2))))/(c*(p + S(1))*sqrt(-S(4)*a*c + b**S(2))) + (a + b*x**S(2) + c*x**S(4))**(p + S(1))/(S(4)*c*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4))**p, x), x, -S(2)**p*(-(b + S(2)*c*x**S(2) - sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))**(-p + S(-1))*(a + b*x**S(2) + c*x**S(4))**(p + S(1))*hyper((-p, p + S(1)), (p + S(2),), (b + S(2)*c*x**S(2) + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*sqrt(-S(4)*a*c + b**S(2))))/((p + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(3) + b*x**S(6))**(S(5)/3), x), x, -S(3)*a*(a*x**S(3) + b*x**S(6))**(S(8)/3)/(S(88)*b**S(2)*x**S(8)) + (a*x**S(3) + b*x**S(6))**(S(8)/3)/(S(11)*b*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(3) + b*x**S(6))**(S(2)/3), x), x, (a*x**S(3) + b*x**S(6))**(S(5)/3)/(S(5)*b*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(3) + b*x**S(6))**(S(-2)/3), x), x, -(a*x**S(3) + b*x**S(6))**(S(1)/3)/(a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(3) + b*x**S(6))**(S(-5)/3), x), x, S(1)/(S(2)*a*x**S(2)*(a*x**S(3) + b*x**S(6))**(S(2)/3)) - S(3)*(a*x**S(3) + b*x**S(6))**(S(1)/3)/(S(4)*a**S(2)*x**S(5)) + S(9)*b*(a*x**S(3) + b*x**S(6))**(S(1)/3)/(S(4)*a**S(3)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6) - x**S(3)), x), x, log(-x + S(1))/S(3) - log(x**S(2) + x + S(1))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(3) + S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, S(3)*a*x**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/((a + b*x**S(3))*(m**S(2) + S(5)*m + S(4))) + x**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(m + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, a*x**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(18)*a + S(18)*b*x**S(3)) + x**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, S(3)*a*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(40)*a + S(40)*b*x**S(3)) + x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, S(3)*a*x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*a + S(28)*b*x**S(3)) + x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, (a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(6)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, S(3)*a*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(10)*a + S(10)*b*x**S(3)) + x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, S(3)*a*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(4)*a + S(4)*b*x**S(3)) + x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x, x), x, a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(2), x), x, -S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2)*x*(a + b*x**S(3))) + sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(3), x), x, -S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2)*x**S(2)*(a + b*x**S(3))) + sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(4), x), x, -a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3)*x**S(3)*(a + b*x**S(3))) + b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(5), x), x, S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(4)*x**S(4)*(a + b*x**S(3))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(6), x), x, S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(10)*x**S(5)*(a + b*x**S(3))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(7), x), x, -(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(6)*a*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(8), x), x, S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*x**S(7)*(a + b*x**S(3))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(4)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(9), x), x, S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(40)*x**S(8)*(a + b*x**S(3))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(5)*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(10), x), x, a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(18)*x**S(9)*(a + b*x**S(3))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(6)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/x**S(11), x), x, S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(70)*x**S(10)*(a + b*x**S(3))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(7)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(162)*a**S(3)*x**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/((a + b*x**S(3))*(m + S(7))*(m + S(10))*(m**S(2) + S(5)*m + S(4))) + S(54)*a**S(2)*x**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/((m + S(4))*(m + S(7))*(m + S(10))) + S(9)*a*x**(m + S(1))*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(m**S(2) + S(17)*m + S(70)) + x**(m + S(1))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(m + S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(81)*a**S(3)*x**S(10)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(19760)*a + S(19760)*b*x**S(3)) + S(27)*a**S(2)*x**S(10)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(1976) + S(9)*a*x**S(10)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(304) + x**S(10)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(19), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, a**S(2)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(36)*b**S(3)) - a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(45)*b**S(3)) + x**S(6)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(18)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(81)*a**S(3)*x**S(8)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(10472)*a + S(10472)*b*x**S(3)) + S(27)*a**S(2)*x**S(8)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(1309) + S(9)*a*x**S(8)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(238) + x**S(8)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(81)*a**S(3)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(7280)*a + S(7280)*b*x**S(3)) + S(27)*a**S(2)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(1040) + S(9)*a*x**S(7)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(208) + x**S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, -a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(12)*b**S(2)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(15)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(81)*a**S(3)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3080)*a + S(3080)*b*x**S(3)) + S(27)*a**S(2)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(616) + S(9)*a*x**S(5)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(154) + x**S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(81)*a**S(3)*x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(1820)*a + S(1820)*b*x**S(3)) + S(27)*a**S(2)*x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(455) + S(9)*a*x**S(4)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(130) + x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(13), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, (a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(12)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(81)*a**S(3)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(440)*a + S(440)*b*x**S(3)) + S(27)*a**S(2)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(220) + S(9)*a*x**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(88) + x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, S(81)*a**S(3)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(140)*a + S(140)*b*x**S(3)) + S(27)*a**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(140) + S(9)*a*x*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(70) + x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x, x), x, a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3) + a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(6) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(2), x), x, -S(81)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(40)*x*(a + b*x**S(3))) + S(27)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(40)*x) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(40)*x) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(8)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(3), x), x, -S(81)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*x**S(2)*(a + b*x**S(3))) + S(27)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(14)*x**S(2)) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*x**S(2)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(7)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(4), x), x, S(3)*a**S(2)*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + a*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)) - a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2)*x**S(3)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(6)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(5), x), x, S(81)*a*b**S(2)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(20)*a + S(20)*b*x**S(3)) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(4)*x**S(4)) + S(27)*b**S(2)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(10) - S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(2)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(6), x), x, S(81)*a*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(20)*a + S(20)*b*x**S(3)) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(10)*x**S(5)) + S(27)*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(20) - S(11)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(10)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(7), x), x, S(3)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2)*x**S(6)) + b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)) - S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(3)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(8), x), x, -S(81)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*x*(a + b*x**S(3))) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*x**S(7)) + S(27)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*x) - S(13)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(28)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(9), x), x, -S(81)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(40)*x**S(2)*(a + b*x**S(3))) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(40)*x**S(8)) + S(27)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(20)*x**S(2)) - S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(20)*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(10), x), x, -a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3)*x**S(3)*(a + b*x**S(3))) + a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(6)*x**S(9)) + b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) - S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(18)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(11), x), x, S(81)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(140)*x**S(4)*(a + b*x**S(3))) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(70)*x**S(10)) - S(27)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(35)*x**S(4)) - S(8)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(35)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(12), x), x, S(81)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(440)*x**S(5)*(a + b*x**S(3))) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(88)*x**S(11)) - S(27)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(88)*x**S(5)) - S(17)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(88)*x**S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(13), x), x, -(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(12)*a*x**S(12)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(14), x), x, S(81)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(1820)*x**S(7)*(a + b*x**S(3))) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(130)*x**S(13)) - S(27)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(260)*x**S(7)) - S(19)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(130)*x**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(15), x), x, S(81)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3080)*x**S(8)*(a + b*x**S(3))) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(154)*x**S(14)) - S(27)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(385)*x**S(8)) - S(10)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(77)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(16), x), x, -(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(12)*a*x**S(15)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(60)*a**S(2)*x**S(15)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/x**S(17), x), x, S(81)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(7280)*x**S(10)*(a + b*x**S(3))) + S(9)*a*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(208)*x**S(16)) - S(27)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(728)*x**S(10)) - S(11)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(104)*x**S(16)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(29160)*a**S(5)*x**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/((a + b*x**S(3))*(m + S(7))*(m + S(10))*(m + S(13))*(m + S(16))*(m**S(2) + S(5)*m + S(4))) + S(9720)*a**S(4)*x**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/((m + S(4))*(m + S(7))*(m + S(10))*(m + S(13))*(m + S(16))) + S(1620)*a**S(3)*x**(m + S(1))*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/((m + S(13))*(m + S(16))*(m**S(2) + S(17)*m + S(70))) + S(180)*a**S(2)*x**(m + S(1))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/((m + S(10))*(m + S(13))*(m + S(16))) + S(15)*a*x**(m + S(1))*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(m**S(2) + S(29)*m + S(208)) + x**(m + S(1))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(m + S(16)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(13)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(14)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2063698)*a + S(2063698)*b*x**S(3)) + S(243)*a**S(4)*x**S(14)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(147407) + S(81)*a**S(3)*x**S(14)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(17342) + S(90)*a**S(2)*x**S(14)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(8671) + S(15)*a*x**S(14)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(754) + x**S(14)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(29), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(12)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(13)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(1521520)*a + S(1521520)*b*x**S(3)) + S(243)*a**S(4)*x**S(13)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(117040) + S(81)*a**S(3)*x**S(13)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(14630) + S(9)*a**S(2)*x**S(13)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(770) + S(3)*a*x**S(13)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(140) + x**S(13)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(28), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, -a**S(3)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(216)*b**S(4)) + a**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(7)/2)/(S(252)*b**S(4)) - a*x**S(6)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(72)*b**S(2)) + x**S(9)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(27)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(11)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(782782)*a + S(782782)*b*x**S(3)) + S(243)*a**S(4)*x**S(11)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(71162) + S(81)*a**S(3)*x**S(11)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(10166) + S(9)*a**S(2)*x**S(11)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(598) + S(15)*a*x**S(11)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(598) + x**S(11)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(26), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(10)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(543400)*a + S(543400)*b*x**S(3)) + S(243)*a**S(4)*x**S(10)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(54340) + S(81)*a**S(3)*x**S(10)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(8360) + S(18)*a**S(2)*x**S(10)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(1045) + S(3)*a*x**S(10)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(110) + x**S(10)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(25), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, a**S(2)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(72)*b**S(3)) - a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(7)/2)/(S(84)*b**S(3)) + x**S(6)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(24)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(8)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(240856)*a + S(240856)*b*x**S(3)) + S(243)*a**S(4)*x**S(8)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(30107) + S(81)*a**S(3)*x**S(8)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(5474) + S(9)*a**S(2)*x**S(8)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(391) + S(3)*a*x**S(8)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(92) + x**S(8)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(23), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(152152)*a + S(152152)*b*x**S(3)) + S(243)*a**S(4)*x**S(7)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(21736) + S(405)*a**S(3)*x**S(7)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(21736) + S(45)*a**S(2)*x**S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(1672) + S(15)*a*x**S(7)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(418) + x**S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(22), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, -a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(18)*b**S(2)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(7)/2)/(S(21)*b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(52360)*a + S(52360)*b*x**S(3)) + S(243)*a**S(4)*x**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(10472) + S(81)*a**S(3)*x**S(5)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(2618) + S(9)*a**S(2)*x**S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(238) + S(3)*a*x**S(5)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(68) + x**S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(20), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(27664)*a + S(27664)*b*x**S(3)) + S(243)*a**S(4)*x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(6916) + S(81)*a**S(3)*x**S(4)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(1976) + S(45)*a**S(2)*x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(988) + S(15)*a*x**S(4)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(304) + x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(19), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, (a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(18)*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(5236)*a + S(5236)*b*x**S(3)) + S(243)*a**S(4)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(2618) + S(405)*a**S(3)*x**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(5236) + S(90)*a**S(2)*x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(1309) + S(15)*a*x**S(2)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(238) + x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(17), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, S(729)*a**S(5)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(1456)*a + S(1456)*b*x**S(3)) + S(243)*a**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(1456) + S(81)*a**S(3)*x*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(728) + S(9)*a**S(2)*x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(104) + S(15)*a*x*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(208) + x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x, x), x, a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3) + a**S(3)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(6) + a**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(9) + a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(12) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(2), x), x, -S(729)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(308)*x*(a + b*x**S(3))) + S(243)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(308)*x) + S(81)*a**S(3)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(308)*x) + S(45)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(308)*x) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(154)*x) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(14)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(3), x), x, -S(729)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(182)*x**S(2)*(a + b*x**S(3))) + S(243)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(91)*x**S(2)) + S(81)*a**S(3)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(182)*x**S(2)) + S(18)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(91)*x**S(2)) + S(3)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(26)*x**S(2)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(13)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(4), x), x, S(5)*a**S(4)*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + S(5)*a**S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3) + S(5)*a**S(2)*b*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(6) + S(5)*a*b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(9) - S(5)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(12)*x**S(3)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(12)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(5), x), x, S(729)*a**S(3)*b**S(2)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(88)*a + S(88)*b*x**S(3)) + S(243)*a**S(2)*b**S(2)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(44) + S(405)*a*b**S(2)*x**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(88) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(4)*x**S(4)) + S(45)*b**S(2)*x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(11) - S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(6), x), x, S(729)*a**S(3)*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(70)*a + S(70)*b*x**S(3)) + S(243)*a**S(2)*b**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(70) + S(81)*a*b**S(2)*x*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(35) + S(3)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(2)*x**S(5)) + S(9)*b**S(2)*x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(5) - S(17)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(10)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(7), x), x, S(10)*a**S(3)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + S(10)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3) + S(5)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3) + S(5)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(6)*x**S(6)) + S(10)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/S(9) - (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(8), x), x, -S(729)*a**S(3)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(56)*x*(a + b*x**S(3))) + S(243)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(56)*x) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(56)*x) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(28)*x**S(7)) + S(45)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(56)*x) - S(19)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(28)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(9), x), x, -S(729)*a**S(3)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(56)*x**S(2)*(a + b*x**S(3))) + S(243)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(28)*x**S(2)) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(56)*x**S(2)) + S(3)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(8)*x**S(8)) + S(9)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(14)*x**S(2)) - (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(2)*x**S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(10), x), x, S(10)*a**S(2)*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + S(10)*a*b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3) - S(5)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3)*x**S(3)) + S(5)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(18)*x**S(9)) + S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(9)*x**S(3)) - S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(18)*x**S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(11), x), x, S(729)*a*b**S(4)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(70)*a + S(70)*b*x**S(3)) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(14)*x**S(4)) + S(3)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(14)*x**S(10)) + S(243)*b**S(4)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(35) - S(45)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(7)*x**S(4)) - S(11)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(35)*x**S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(12), x), x, S(729)*a*b**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(88)*a + S(88)*b*x**S(3)) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(44)*x**S(5)) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(88)*x**S(11)) + S(243)*b**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(88) - S(9)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(4)*x**S(5)) - S(23)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(88)*x**S(11)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(13), x), x, S(5)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) + S(5)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(6)*x**S(6)) + S(5)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(36)*x**S(12)) + S(5)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/S(3) - S(10)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(9)*x**S(6)) - S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(9)*x**S(12)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(14), x), x, -S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(182)*x*(a + b*x**S(3))) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(182)*x**S(7)) + S(3)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(26)*x**S(13)) + S(243)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(182)*x) - S(9)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(14)*x**S(7)) - S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(26)*x**S(13)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(15), x), x, -S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(308)*x**S(2)*(a + b*x**S(3))) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(308)*x**S(8)) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(154)*x**S(14)) + S(243)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(154)*x**S(2)) - S(9)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(22)*x**S(8)) - S(13)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(77)*x**S(14)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(16), x), x, -a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3)*x**S(3)*(a + b*x**S(3))) + a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(6)*x**S(9)) + a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(12)*x**S(15)) + b**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))*log(x)/(a + b*x**S(3)) - S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(18)*x**S(9)) - S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(20)*x**S(15)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(17), x), x, S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(1456)*x**S(4)*(a + b*x**S(3))) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(728)*x**S(10)) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(208)*x**S(16)) - S(243)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(364)*x**S(4)) - S(18)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(91)*x**S(10)) - S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(52)*x**S(16)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(18), x), x, S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(5236)*x**S(5)*(a + b*x**S(3))) + S(405)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(5236)*x**S(11)) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(238)*x**S(17)) - S(1215)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(5236)*x**S(5)) - S(45)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(308)*x**S(11)) - S(29)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(238)*x**S(17)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(19), x), x, -(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(18)*a*x**S(18)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(20), x), x, S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(27664)*x**S(7)*(a + b*x**S(3))) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(1976)*x**S(13)) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(304)*x**S(19)) - S(243)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3952)*x**S(7)) - S(9)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(104)*x**S(13)) - S(31)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(304)*x**S(19)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(21), x), x, S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(52360)*x**S(8)*(a + b*x**S(3))) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(2618)*x**S(14)) + S(3)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(68)*x**S(20)) - S(243)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(6545)*x**S(8)) - S(90)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(1309)*x**S(14)) - S(8)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(85)*x**S(20)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(22), x), x, -(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(18)*a*x**S(21)) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(7)/2)/(S(126)*a**S(2)*x**S(21)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(23), x), x, S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(152152)*x**S(10)*(a + b*x**S(3))) + S(405)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(21736)*x**S(16)) + S(15)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(418)*x**S(22)) - S(1215)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(76076)*x**S(10)) - S(45)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(988)*x**S(16)) - S(17)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(209)*x**S(22)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(24), x), x, S(729)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(240856)*x**S(11)*(a + b*x**S(3))) + S(81)*a*b**S(2)*(a + b*x**S(3))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(5474)*x**S(17)) + S(3)*a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(92)*x**S(23)) - S(243)*b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(21896)*x**S(11)) - S(9)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)/(S(238)*x**S(17)) - S(7)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(92)*x**S(23)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/x**S(25), x), x, -(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(24)*a*x**S(24)) + b*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)/(S(72)*a**S(2)*x**S(21)) - b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(7)/2)/(S(504)*a**S(3)*x**S(21)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, x**(m + S(1))*(a + b*x**S(3))*hyper((S(1), m/S(3) + S(1)/3), (m/S(3) + S(4)/3,), -b*x**S(3)/a)/(a*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, a**(S(2)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - a**(S(2)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + sqrt(S(3))*a**(S(2)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + x**S(2)*(a + b*x**S(3))/(S(2)*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, -a**(S(1)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + a**(S(1)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + sqrt(S(3))*a**(S(1)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + x*(a + b*x**S(3))/(b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, (a + b*x**S(3))*log(a + b*x**S(3))/(S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, -(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*a**(S(1)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(1)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6)), x), x, (a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*a**(S(2)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*a**(S(2)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(2)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), x), x, (a + b*x**S(3))*log(x)/(a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (a + b*x**S(3))*log(a + b*x**S(3))/(S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), x), x, -(a + b*x**S(3))/(a*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + b**(S(1)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*a**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - b**(S(1)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*a**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + sqrt(S(3))*b**(S(1)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), x), x, (-a - b*x**S(3))/(S(2)*a*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - b**(S(2)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(3)*a**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + b**(S(2)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(6)*a**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + sqrt(S(3))*b**(S(2)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(3)*a**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), x), x, -b*(a + b*x**S(3))*log(x)/(a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + b*(a + b*x**S(3))*log(a + b*x**S(3))/(S(3)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3)*a**S(2)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, x**(m + S(1))*(a + b*x**S(3))*hyper((S(3), m/S(3) + S(1)/3), (m/S(3) + S(4)/3,), -b*x**S(3)/a)/(a**S(3)*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, x**S(5)*(a + b*x**S(3))/(S(6)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) - x**S(2)/(S(18)*a*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(27)*a**(S(4)/3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(54)*a**(S(4)/3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(27)*a**(S(4)/3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, x**S(4)*(a + b*x**S(3))/(S(6)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) - x/(S(9)*a*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(27)*a**(S(5)/3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(54)*a**(S(5)/3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(27)*a**(S(5)/3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, (-a - b*x**S(3))/(S(6)*b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2), x), x, x**S(2)*(a + b*x**S(3))/(S(6)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(2)*x**S(2)/(S(9)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(27)*a**(S(7)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(2)*a + S(2)*b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(27)*a**(S(7)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(S(2)*a + S(2)*b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(27)*a**(S(7)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(-3)/2), x), x, x*(a + b*x**S(3))/(S(6)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(5)*x/(S(18)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (S(5)*a + S(5)*b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(27)*a**(S(8)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(5)*a + S(5)*b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(54)*a**(S(8)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(S(5)*a + S(5)*b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(27)*a**(S(8)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)), x), x, (a + b*x**S(3))/(S(6)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(1)/(S(3)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (a + b*x**S(3))*log(x)/(a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (a + b*x**S(3))*log(a + b*x**S(3))/(S(3)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)), x), x, (a + b*x**S(3))/(S(6)*a*x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(7)/(S(18)*a**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(14)*a + S(14)*b*x**S(3))/(S(9)*a**S(3)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(14)*b**(S(1)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(27)*a**(S(10)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - S(7)*b**(S(1)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(27)*a**(S(10)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(14)*sqrt(S(3))*b**(S(1)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(27)*a**(S(10)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)), x), x, (a + b*x**S(3))/(S(6)*a*x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(4)/(S(9)*a**S(2)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(10)*a + S(10)*b*x**S(3))/(S(9)*a**S(3)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - S(20)*b**(S(2)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(27)*a**(S(11)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(10)*b**(S(2)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(27)*a**(S(11)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(20)*sqrt(S(3))*b**(S(2)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(27)*a**(S(11)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)), x), x, (a + b*x**S(3))/(S(6)*a*x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(1)/(S(2)*a**S(2)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - S(3)*b*(a + b*x**S(3))*log(x)/(a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + b*(a + b*x**S(3))*log(a + b*x**S(3))/(a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(a**S(4)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, x**(m + S(1))*(a + b*x**S(3))*hyper((S(5), m/S(3) + S(1)/3), (m/S(3) + S(4)/3,), -b*x**S(3)/a)/(a**S(5)*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, a*x*(a + b*x**S(3))/(S(12)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) - S(13)*x/(S(108)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + x*(a + b*x**S(3))/(S(162)*a*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(5)*x/(S(486)*a**S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (S(5)*a + S(5)*b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(729)*a**(S(8)/3)*b**(S(7)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(5)*a + S(5)*b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(1458)*a**(S(8)/3)*b**(S(7)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(S(5)*a + S(5)*b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(729)*a**(S(8)/3)*b**(S(7)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, a*(a + b*x**S(3))/(S(12)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) - S(1)/(S(9)*b**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, x**S(5)*(a + b*x**S(3))/(S(12)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) - S(7)*x**S(2)/(S(108)*a*b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(7)*x**S(2)*(a + b*x**S(3))/(S(324)*a**S(2)*b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(7)*x**S(2)/(S(243)*a**S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(7)*a + S(7)*b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(729)*a**(S(10)/3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (S(7)*a + S(7)*b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(1458)*a**(S(10)/3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(S(7)*a + S(7)*b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(729)*a**(S(10)/3)*b**(S(5)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, x**S(4)*(a + b*x**S(3))/(S(12)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) - S(2)*x/(S(27)*a*b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + x*(a + b*x**S(3))/(S(81)*a**S(2)*b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(5)*x/(S(243)*a**S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(5)*a + S(5)*b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(729)*a**(S(11)/3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (S(10)*a + S(10)*b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(729)*a**(S(11)/3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(S(10)*a + S(10)*b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(729)*a**(S(11)/3)*b**(S(4)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, (-a - b*x**S(3))/(S(12)*b*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2), x), x, x**S(2)*(a + b*x**S(3))/(S(12)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) + S(5)*x**S(2)/(S(54)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(35)*x**S(2)*(a + b*x**S(3))/(S(324)*a**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(35)*x**S(2)/(S(243)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(35)*a + S(35)*b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(729)*a**(S(13)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (S(35)*a + S(35)*b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(1458)*a**(S(13)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(S(35)*a + S(35)*b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(729)*a**(S(13)/3)*b**(S(2)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(-5)/2), x), x, x*(a + b*x**S(3))/(S(12)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) + S(11)*x/(S(108)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(11)*x*(a + b*x**S(3))/(S(81)*a**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(55)*x/(S(243)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(55)*a + S(55)*b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(729)*a**(S(14)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (S(110)*a + S(110)*b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(729)*a**(S(14)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - sqrt(S(3))*(S(110)*a + S(110)*b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(729)*a**(S(14)/3)*b**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)), x), x, (a + b*x**S(3))/(S(12)*a*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) + S(1)/(S(9)*a**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + (a + b*x**S(3))/(S(6)*a**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(1)/(S(3)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + (a + b*x**S(3))*log(x)/(a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (a + b*x**S(3))*log(a + b*x**S(3))/(S(3)*a**S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)), x), x, (a + b*x**S(3))/(S(12)*a*x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) + S(13)/(S(108)*a**S(2)*x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + (S(65)*a + S(65)*b*x**S(3))/(S(324)*a**S(3)*x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(455)/(S(972)*a**S(4)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(455)*a + S(455)*b*x**S(3))/(S(243)*a**S(5)*x*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(455)*b**(S(1)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(729)*a**(S(16)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - S(455)*b**(S(1)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(1458)*a**(S(16)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(455)*sqrt(S(3))*b**(S(1)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(729)*a**(S(16)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)), x), x, (a + b*x**S(3))/(S(12)*a*x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) + S(7)/(S(54)*a**S(2)*x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + (S(77)*a + S(77)*b*x**S(3))/(S(324)*a**S(3)*x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(154)/(S(243)*a**S(4)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - (S(385)*a + S(385)*b*x**S(3))/(S(243)*a**S(5)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - S(770)*b**(S(2)/3)*(a + b*x**S(3))*log(a**(S(1)/3) + b**(S(1)/3)*x)/(S(729)*a**(S(17)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(385)*b**(S(2)/3)*(a + b*x**S(3))*log(a**(S(2)/3) - a**(S(1)/3)*b**(S(1)/3)*x + b**(S(2)/3)*x**S(2))/(S(729)*a**(S(17)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(770)*sqrt(S(3))*b**(S(2)/3)*(a + b*x**S(3))*atan(sqrt(S(3))*(a**(S(1)/3) - S(2)*b**(S(1)/3)*x)/(S(3)*a**(S(1)/3)))/(S(729)*a**(S(17)/3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)), x), x, (a + b*x**S(3))/(S(12)*a*x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(5)/2)) + S(5)/(S(36)*a**S(2)*x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + (S(5)*a + S(5)*b*x**S(3))/(S(18)*a**S(3)*x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(S(3)/2)) + S(5)/(S(6)*a**S(4)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - S(5)*b*(a + b*x**S(3))*log(x)/(a**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) + S(5)*b*(a + b*x**S(3))*log(a + b*x**S(3))/(S(3)*a**S(6)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))) - S(5)*sqrt(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))/(S(3)*a**S(6)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x**(m + S(1))*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(1), m/S(3) + S(2)*p + S(4)/3), (m/S(3) + S(4)/3,), -b*x**S(3)/a)/(a*(m + S(1))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**m*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x**(m + S(1))*(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((m/S(3) + S(1)/3, -S(2)*p), (m/S(3) + S(4)/3,), -b*x**S(3)/a)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, -a*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p/(S(3)*b**S(2)*(S(2)*p + S(1))) + (a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**(p + S(1))/(S(6)*b**S(2)*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x**S(5)*(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(5)/3, -S(2)*p), (S(8)/3,), -b*x**S(3)/a)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x**S(4)*(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(4)/3, -S(2)*p), (S(7)/3,), -b*x**S(3)/a)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, (a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p/(S(3)*b*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x**S(2)*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(1), S(2)*p + S(5)/3), (S(5)/3,), -b*x**S(3)/a)/(S(2)*a), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x**S(2)*(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(2)/3, -S(2)*p), (S(5)/3,), -b*x**S(3)/a)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(1), S(2)*p + S(4)/3), (S(4)/3,), -b*x**S(3)/a)/a, expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p, x), x, x*(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(1)/3, -S(2)*p), (S(4)/3,), -b*x**S(3)/a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p/x, x), x, -(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(1), S(2)*p + S(1)), (S(2)*p + S(2),), S(1) + b*x**S(3)/a)/(S(3)*a*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p/x**S(2), x), x, -(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(-1)/3, -S(2)*p), (S(2)/3,), -b*x**S(3)/a)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p/x**S(3), x), x, -(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(-2)/3, -S(2)*p), (S(1)/3,), -b*x**S(3)/a)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p/x**S(4), x), x, b*(a + b*x**S(3))*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(2), S(2)*p + S(1)), (S(2)*p + S(2),), S(1) + b*x**S(3)/a)/(S(3)*a**S(2)*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p/x**S(5), x), x, -(S(1) + b*x**S(3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**S(3) + b**S(2)*x**S(6))**p*hyper((S(-4)/3, -S(2)*p), (S(-1)/3,), -b*x**S(3)/a)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a + b*x**S(3) + c*x**S(6)), x), x, -b*log(a + b*x**S(3) + c*x**S(6))/(S(6)*c**S(2)) + x**S(3)/(S(3)*c) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a + b*x**S(3) + c*x**S(6)), x), x, b*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*c*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*x**S(3) + c*x**S(6))/(S(6)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**S(3) + c*x**S(6)), x), x, -S(2)*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**S(3) + c*x**S(6))), x), x, b*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*a*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a + b*x**S(3) + c*x**S(6))/(S(6)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a + b*x**S(3) + c*x**S(6))), x), x, -S(1)/(S(3)*a*x**S(3)) - b*log(x)/a**S(2) + b*log(a + b*x**S(3) + c*x**S(6))/(S(6)*a**S(2)) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a + b*x**S(3) + c*x**S(6)), x), x, x**S(2)/(S(2)*c) + S(2)**(S(1)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(5)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(5)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(5)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(5)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(5)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(5)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a + b*x**S(3) + c*x**S(6)), x), x, x/c - S(2)**(S(2)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a + b*x**S(3) + c*x**S(6)), x), x, S(2)**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/3)*sqrt(S(3))*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/3)*sqrt(S(3))*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**S(3) + c*x**S(6)), x), x, -S(2)**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*sqrt(S(3))*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(2)/3)*sqrt(S(3))*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(3) + c*x**S(6)), x), x, S(2)**(S(1)/3)*c**(S(1)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/3)*c**(S(1)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(6)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/3)*sqrt(S(3))*c**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/3)*c**(S(1)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/3)*c**(S(1)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(6)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/3)*sqrt(S(3))*c**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x**S(3) + c*x**S(6)), x), x, -S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(6)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(6)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**S(3) + c*x**S(6))), x), x, S(2)**(S(1)/3)*c**(S(1)/3)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*c**(S(1)/3)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*c**(S(1)/3)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*c**(S(1)/3)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*c**(S(1)/3)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*c**(S(1)/3)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(1)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**S(3) + c*x**S(6))), x), x, -S(2)**(S(2)/3)*c**(S(2)/3)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*c**(S(2)/3)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*c**(S(2)/3)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*c**(S(2)/3)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(1)/(S(2)*a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, x**S(6)/S(6) - S(4)*x**S(3)/S(3) - log(x**S(3) + S(1))/S(6) + S(9)*log(x**S(3) + S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, x**S(3)/S(3) + log(x**S(3) + S(1))/S(6) - S(3)*log(x**S(3) + S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, -log(x**S(3) + S(1))/S(6) + log(x**S(3) + S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, -atanh(x**S(3) + S(2))/S(3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, log(x**S(3) + S(1))/S(6) - log(x**S(3) + S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(6) + S(4)*x**S(3) + S(3))), x), x, log(x)/S(3) - log(x**S(3) + S(1))/S(6) + log(x**S(3) + S(3))/S(18), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(x**S(6) + S(4)*x**S(3) + S(3))), x), x, -S(4)*log(x)/S(9) + log(x**S(3) + S(1))/S(6) - log(x**S(3) + S(3))/S(54) - S(1)/(S(9)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(x**S(6) + S(4)*x**S(3) + S(3))), x), x, S(13)*log(x)/S(27) - log(x**S(3) + S(1))/S(6) + log(x**S(3) + S(3))/S(162) + S(4)/(S(27)*x**S(3)) - S(1)/(S(18)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, x**S(5)/S(5) - S(2)*x**S(2) + log(x + S(1))/S(6) - S(3)*S(3)**(S(2)/3)*log(x + S(3)**(S(1)/3))/S(2) - log(x**S(2) - x + S(1))/S(12) + S(3)*S(3)**(S(2)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(4) - S(9)*S(3)**(S(1)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, x**S(4)/S(4) - S(4)*x - log(x + S(1))/S(6) + S(3)*S(3)**(S(1)/3)*log(x + S(3)**(S(1)/3))/S(2) + log(x**S(2) - x + S(1))/S(12) - S(3)*S(3)**(S(1)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(4) - S(3)*S(3)**(S(5)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, x**S(2)/S(2) - log(x + S(1))/S(6) + S(3)**(S(2)/3)*log(x + S(3)**(S(1)/3))/S(2) + log(x**S(2) - x + S(1))/S(12) - S(3)**(S(2)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(4) + S(3)*S(3)**(S(1)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(2) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, x + log(x + S(1))/S(6) - S(3)**(S(1)/3)*log(x + S(3)**(S(1)/3))/S(2) - log(x**S(2) - x + S(1))/S(12) + S(3)**(S(1)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(4) + S(3)**(S(5)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(2) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, log(x + S(1))/S(6) - S(3)**(S(2)/3)*log(x + S(3)**(S(1)/3))/S(6) - log(x**S(2) - x + S(1))/S(12) + S(3)**(S(2)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(12) - S(3)**(S(1)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, -log(x + S(1))/S(6) + S(3)**(S(1)/3)*log(x + S(3)**(S(1)/3))/S(6) + log(x**S(2) - x + S(1))/S(12) - S(3)**(S(1)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(12) - S(3)**(S(5)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, -log(x + S(1))/S(6) + S(3)**(S(2)/3)*log(x + S(3)**(S(1)/3))/S(18) + log(x**S(2) - x + S(1))/S(12) - S(3)**(S(2)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(36) + S(3)**(S(1)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6) + S(4)*x**S(3) + S(3)), x), x, log(x + S(1))/S(6) - S(3)**(S(1)/3)*log(x + S(3)**(S(1)/3))/S(18) - log(x**S(2) - x + S(1))/S(12) + S(3)**(S(1)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(36) + S(3)**(S(5)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(18) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x**S(6) + S(4)*x**S(3) + S(3))), x), x, log(x + S(1))/S(6) - S(3)**(S(2)/3)*log(x + S(3)**(S(1)/3))/S(54) - log(x**S(2) - x + S(1))/S(12) + S(3)**(S(2)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(108) - S(3)**(S(1)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(18) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) - S(1)/(S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(6) + S(4)*x**S(3) + S(3))), x), x, -log(x + S(1))/S(6) + S(3)**(S(1)/3)*log(x + S(3)**(S(1)/3))/S(54) + log(x**S(2) - x + S(1))/S(12) - S(3)**(S(1)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(108) - S(3)**(S(5)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(54) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) - S(1)/(S(6)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(6) + S(4)*x**S(3) + S(3))), x), x, -log(x + S(1))/S(6) + S(3)**(S(2)/3)*log(x + S(3)**(S(1)/3))/S(162) + log(x**S(2) - x + S(1))/S(12) - S(3)**(S(2)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(324) + S(3)**(S(1)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(54) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + S(4)/(S(9)*x) - S(1)/(S(12)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(x**S(6) + S(4)*x**S(3) + S(3))), x), x, log(x + S(1))/S(6) - S(3)**(S(1)/3)*log(x + S(3)**(S(1)/3))/S(162) - log(x**S(2) - x + S(1))/S(12) + S(3)**(S(1)/3)*log(x**S(2) - S(3)**(S(1)/3)*x + S(3)**(S(2)/3))/S(324) + S(3)**(S(5)/6)*atan(S(3)**(S(1)/6)*(-S(2)*x + S(3)**(S(1)/3))/S(3))/S(162) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + S(2)/(S(9)*x**S(2)) - S(1)/(S(15)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(x**S(6) - x**S(3) + S(1)), x), x, x + S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(6) - x**S(3) + S(1)), x), x, log(x**S(6) - x**S(3) + S(1))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(6) - x**S(3) + S(1)), x), x, S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(6) - x**S(3) + S(1)), x), x, S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(6) - x**S(3) + S(1)), x), x, -S(2)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(6) - x**S(3) + S(1)), x), x, sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3)) - sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3)) - I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6) - x**S(3) + S(1)), x), x, -(S(-1))**(S(5)/18)*sqrt(S(3))*(S(3)*log(-x + (S(-1))**(S(1)/9)) + log(S(2)))/S(27) + (S(-1))**(S(13)/18)*sqrt(S(3))*log(-S(2)**(S(1)/3)*(x + (S(-1))**(S(8)/9)))/S(9) - (S(-1))**(S(13)/18)*sqrt(S(3))*log(-S(2)**(S(2)/3)*(x*(-x + (S(-1))**(S(8)/9)) + (S(-1))**(S(7)/9)))/S(18) + (S(-1))**(S(5)/18)*sqrt(S(3))*log(S(2)**(S(2)/3)*(x*(x + (S(-1))**(S(1)/9)) + (S(-1))**(S(2)/9)))/S(18) - (S(-1))**(S(13)/18)*atan(sqrt(S(3))*(S(2)*(S(-1))**(S(1)/9)*x + S(1))/S(3))/S(3) + (S(-1))**(S(5)/18)*atan(sqrt(S(3))*(-S(2)*(S(-1))**(S(8)/9)*x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/(x**S(6) - x**S(3) + S(1)), x), x, sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(2)/3)) - sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(2)/3)) + I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(6) - x**S(3) + S(1))), x), x, log(x) - log(x**S(6) - x**S(3) + S(1))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x**S(6) - x**S(3) + S(1))), x), x, -S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(6) - x**S(3) + S(1))), x), x, -S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(x**S(6) - x**S(3) + S(1))), x), x, log(x) - log(x**S(6) - x**S(3) + S(1))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9) - S(1)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(6) - x**S(3) + S(1))), x), x, -S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) - S(1)/x - S(1)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6) + x**S(3) + S(2)), x), x, -sqrt(S(7))*I*log(S(2)**(S(1)/3)*x + (S(1) - sqrt(S(7))*I)**(S(1)/3))/(S(21)*(S(1)/2 - sqrt(S(7))*I/S(2))**(S(2)/3)) + sqrt(S(7))*I*log(S(2)**(S(1)/3)*x + (S(1) + sqrt(S(7))*I)**(S(1)/3))/(S(21)*(S(1)/2 + sqrt(S(7))*I/S(2))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(7))*I*log(S(2)**(S(2)/3)*x**S(2) - x*(S(2) - S(2)*sqrt(S(7))*I)**(S(1)/3) + (S(1) - sqrt(S(7))*I)**(S(2)/3))/(S(42)*(S(1) - sqrt(S(7))*I)**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(7))*I*log(S(2)**(S(2)/3)*x**S(2) - x*(S(2) + S(2)*sqrt(S(7))*I)**(S(1)/3) + (S(1) + sqrt(S(7))*I)**(S(2)/3))/(S(42)*(S(1) + sqrt(S(7))*I)**(S(2)/3)) + sqrt(S(21))*I*atan(sqrt(S(3))*(-S(2)*x/(S(1)/2 - sqrt(S(7))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(21)*(S(1)/2 - sqrt(S(7))*I/S(2))**(S(2)/3)) - sqrt(S(21))*I*atan(sqrt(S(3))*(-S(2)*x/(S(1)/2 + sqrt(S(7))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(21)*(S(1)/2 + sqrt(S(7))*I/S(2))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(6) + x**S(3) + S(2)), x), x, S(2)*sqrt(S(7))*atan(sqrt(S(7))*(S(2)*x**S(3) + S(1))/S(7))/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(6) + x**S(3) + S(2)), x), x, S(2)**(S(2)/3)*(S(7) + sqrt(S(7))*I)*log(S(2)**(S(1)/3)*x + (S(1) - sqrt(S(7))*I)**(S(1)/3))/(S(42)*(S(1) - sqrt(S(7))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(7) - sqrt(S(7))*I)*log(S(2)**(S(1)/3)*x + (S(1) + sqrt(S(7))*I)**(S(1)/3))/(S(42)*(S(1) + sqrt(S(7))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(7) + sqrt(S(7))*I)*log(S(2)**(S(2)/3)*x**S(2) - x*(S(2) - S(2)*sqrt(S(7))*I)**(S(1)/3) + (S(1) - sqrt(S(7))*I)**(S(2)/3))/(S(84)*(S(1) - sqrt(S(7))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(7) - sqrt(S(7))*I)*log(S(2)**(S(2)/3)*x**S(2) - x*(S(2) + S(2)*sqrt(S(7))*I)**(S(1)/3) + (S(1) + sqrt(S(7))*I)**(S(2)/3))/(S(84)*(S(1) + sqrt(S(7))*I)**(S(2)/3)) - sqrt(S(21))*I*(S(1)/2 - sqrt(S(7))*I/S(2))**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*x/(S(1)/2 - sqrt(S(7))*I/S(2))**(S(1)/3) + S(1))/S(3))/S(21) + sqrt(S(21))*I*(S(1)/2 + sqrt(S(7))*I/S(2))**(S(1)/3)*atan(sqrt(S(3))*(-S(2)*x/(S(1)/2 + sqrt(S(7))*I/S(2))**(S(1)/3) + S(1))/S(3))/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -b*x**S(6)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(20)*c**S(2)) + x**S(9)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(18)*c) - (S(7)*b*(-S(28)*a*c + S(15)*b**S(2)) - S(6)*c*x**S(3)*(-S(20)*a*c + S(21)*b**S(2)))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(2880)*c**S(4)) + (b + S(2)*c*x**S(3))*sqrt(a + b*x**S(3) + c*x**S(6))*(S(16)*a**S(2)*c**S(2) - S(56)*a*b**S(2)*c + S(21)*b**S(4))/(S(1536)*c**S(5)) - (-S(4)*a*c + b**S(2))*(S(16)*a**S(2)*c**S(2) - S(56)*a*b**S(2)*c + S(21)*b**S(4))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(3072)*c**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -b*(b + S(2)*c*x**S(3))*(-S(12)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(384)*c**S(4)) + b*(-S(12)*a*c + S(7)*b**S(2))*(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(768)*c**(S(9)/2)) + x**S(6)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(15)*c) + (a + b*x**S(3) + c*x**S(6))**(S(3)/2)*(-S(32)*a*c + S(35)*b**S(2) - S(42)*b*c*x**S(3))/(S(720)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -S(5)*b*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(72)*c**S(2)) + x**S(3)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(12)*c) + (b + S(2)*c*x**S(3))*(-S(4)*a*c + S(5)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(192)*c**S(3)) - (-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(5)*b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(384)*c**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -b*(b + S(2)*c*x**S(3))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(24)*c**S(2)) + b*(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(48)*c**(S(5)/2)) + (a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(9)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, (b + S(2)*c*x**S(3))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(12)*c) - (-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(24)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x, x), x, -sqrt(a)*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/S(3) + b*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(6)*sqrt(c)) + sqrt(a + b*x**S(3) + c*x**S(6))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x**S(4), x), x, sqrt(c)*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/S(3) - sqrt(a + b*x**S(3) + c*x**S(6))/(S(3)*x**S(3)) - b*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(6)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x**S(7), x), x, -(S(2)*a + b*x**S(3))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(12)*a*x**S(6)) + (-S(4)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(24)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x**S(10), x), x, -(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(9)*a*x**S(9)) + b*(S(2)*a + b*x**S(3))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(24)*a**S(2)*x**S(6)) - b*(-S(4)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(48)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x**S(13), x), x, -(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(12)*a*x**S(12)) + S(5)*b*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(72)*a**S(2)*x**S(9)) - (S(2)*a + b*x**S(3))*(-S(4)*a*c + S(5)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(192)*a**S(3)*x**S(6)) + (-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(5)*b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(384)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x**S(16), x), x, -(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(15)*a*x**S(15)) + S(7)*b*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(120)*a**S(2)*x**S(12)) - (-S(32)*a*c + S(35)*b**S(2))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(720)*a**S(3)*x**S(9)) + b*(S(2)*a + b*x**S(3))*(-S(12)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(384)*a**S(4)*x**S(6)) - b*(-S(12)*a*c + S(7)*b**S(2))*(-S(4)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(768)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, x**S(4)*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(4)/3, S(-1)/2, S(-1)/2, S(7)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, x**S(2)*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(2)/3, S(-1)/2, S(-1)/2, S(5)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6)), x), x, x*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(1)/3, S(-1)/2, S(-1)/2, S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x**S(2), x), x, -sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(-1)/3, S(-1)/2, S(-1)/2, S(2)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(x*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(3) + c*x**S(6))/x**S(3), x), x, -sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(-2)/3, S(-1)/2, S(-1)/2, S(1)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*x**S(2)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, a*x**S(4)*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(4)/3, S(-3)/2, S(-3)/2, S(7)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, a*x**S(2)*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(2)/3, S(-3)/2, S(-3)/2, S(5)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, a*x*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(1)/3, S(-3)/2, S(-3)/2, S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(2), x), x, -a*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(-1)/3, S(-3)/2, S(-3)/2, S(2)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(x*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(3), x), x, -a*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(S(-2)/3, S(-3)/2, S(-3)/2, S(1)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*x**S(2)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, x**S(4)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(4)/3, S(1)/2, S(1)/2, S(7)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, x**S(2)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(2)/3, S(1)/2, S(1)/2, S(5)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, x*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/3, S(1)/2, S(1)/2, S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/sqrt(a + b*x**S(3) + c*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*x**S(3) + c*x**S(6))), x), x, -sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-1)/3, S(1)/2, S(1)/2, S(2)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(x*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + b*x**S(3) + c*x**S(6))), x), x, -sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-2)/3, S(1)/2, S(1)/2, S(1)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*x**S(2)*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, x**S(4)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(4)/3, S(3)/2, S(3)/2, S(7)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, x**S(2)*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(2)/3, S(3)/2, S(3)/2, S(5)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(-3)/2), x), x, x*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/3, S(3)/2, S(3)/2, S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)), x), x, -sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-1)/3, S(3)/2, S(3)/2, S(2)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*x*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)), x), x, -sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-2)/3, S(3)/2, S(3)/2, S(1)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*x**S(2)*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, a*(d*x)**(m + S(1))*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(m/S(3) + S(1)/3, S(-3)/2, S(-3)/2, m/S(3) + S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*sqrt(a + b*x**S(3) + c*x**S(6)), x), x, (d*x)**(m + S(1))*sqrt(a + b*x**S(3) + c*x**S(6))*AppellF1(m/S(3) + S(1)/3, S(-1)/2, S(-1)/2, m/S(3) + S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, (d*x)**(m + S(1))*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(3) + S(1)/3, S(1)/2, S(1)/2, m/S(3) + S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, (d*x)**(m + S(1))*sqrt(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(3) + S(1)/3, S(3)/2, S(3)/2, m/S(3) + S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*d*(m + S(1))*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(3) + c*x**S(6))**p, x), x, (d*x)**(m + S(1))*(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(m/S(3) + S(1)/3, -p, -p, m/S(3) + S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(3) + c*x**S(6))**p, x), x, x**S(5)*(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(5)/3, -p, -p, S(8)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(3) + c*x**S(6))**p, x), x, x**S(4)*(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(4)/3, -p, -p, S(7)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(3) + c*x**S(6))**p, x), x, x**S(2)*(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(2)/3, -p, -p, S(5)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p, x), x, x*(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(1)/3, -p, -p, S(4)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p/x, x), x, S(2)**(S(2)*p + S(-1))*((b + S(2)*c*x**S(3) - sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(3)))**(-p)*((b + S(2)*c*x**S(3) + sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(3)))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(-S(2)*p, -p, -p, -S(2)*p + S(1), -(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(3)), -(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(3)))/(S(3)*p), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p/x**S(2), x), x, -(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(-1)/3, -p, -p, S(2)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p/x**S(3), x), x, -(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(-2)/3, -p, -p, S(1)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p/x**S(4), x), x, -S(4)**p*((b + S(2)*c*x**S(3) - sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(3)))**(-p)*((b + S(2)*c*x**S(3) + sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(3)))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(-S(2)*p + S(1), -p, -p, -S(2)*p + S(2), -(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(3)), -(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(3)))/(x**S(3)*(-S(6)*p + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p/x**S(5), x), x, -(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(-4)/3, -p, -p, S(-1)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p/x**S(6), x), x, -(S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(S(-5)/3, -p, -p, S(-2)/3, -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**p/x**S(7), x), x, -S(2)**(S(2)*p + S(-1))*((b + S(2)*c*x**S(3) - sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(3)))**(-p)*((b + S(2)*c*x**S(3) + sqrt(-S(4)*a*c + b**S(2)))/(c*x**S(3)))**(-p)*(a + b*x**S(3) + c*x**S(6))**p*AppellF1(-S(2)*p + S(2), -p, -p, -S(2)*p + S(3), -(b - sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(3)), -(b + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*x**S(3)))/(x**S(6)*(-S(3)*p + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -S(11)*b*x**S(6)*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(336)*c**S(2)) + x**S(9)*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(24)*c) - (S(3)*b*(-S(124)*a*c + S(77)*b**S(2)) - S(10)*c*x**S(3)*(-S(28)*a*c + S(33)*b**S(2)))*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(13440)*c**S(4)) + (b + S(2)*c*x**S(3))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)*(S(16)*a**S(2)*c**S(2) - S(72)*a*b**S(2)*c + S(33)*b**S(4))/(S(6144)*c**S(5)) - (b + S(2)*c*x**S(3))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))*(S(16)*a**S(2)*c**S(2) - S(72)*a*b**S(2)*c + S(33)*b**S(4))/(S(16384)*c**S(6)) + (-S(4)*a*c + b**S(2))**S(2)*(S(16)*a**S(2)*c**S(2) - S(72)*a*b**S(2)*c + S(33)*b**S(4))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(32768)*c**(S(13)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -b*(b + S(2)*c*x**S(3))*(-S(4)*a*c + S(3)*b**S(2))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(384)*c**S(4)) + b*(b + S(2)*c*x**S(3))*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(1024)*c**S(5)) - b*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(3)*b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(2048)*c**(S(11)/2)) + x**S(6)*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(21)*c) + (a + b*x**S(3) + c*x**S(6))**(S(5)/2)*(-S(16)*a*c + S(21)*b**S(2) - S(30)*b*c*x**S(3))/(S(840)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -S(7)*b*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(180)*c**S(2)) + x**S(3)*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(18)*c) + (b + S(2)*c*x**S(3))*(-S(4)*a*c + S(7)*b**S(2))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(576)*c**S(3)) - (b + S(2)*c*x**S(3))*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(1536)*c**S(4)) + (-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(7)*b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(3072)*c**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -b*(b + S(2)*c*x**S(3))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(48)*c**S(2)) + b*(b + S(2)*c*x**S(3))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(128)*c**S(3)) - b*(-S(4)*a*c + b**S(2))**S(2)*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(256)*c**(S(7)/2)) + (a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(15)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, (b + S(2)*c*x**S(3))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(24)*c) - (b + S(2)*c*x**S(3))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(64)*c**S(2)) + (-S(4)*a*c + b**S(2))**S(2)*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(128)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x, x), x, -a**(S(3)/2)*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/S(3) - b*(-S(12)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(48)*c**(S(3)/2)) + (a + b*x**S(3) + c*x**S(6))**(S(3)/2)/S(9) + sqrt(a + b*x**S(3) + c*x**S(6))*(S(8)*a*c + b**S(2) + S(2)*b*c*x**S(3))/(S(24)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(4), x), x, -sqrt(a)*b*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/S(2) + (S(3)*b/S(4) + c*x**S(3)/S(2))*sqrt(a + b*x**S(3) + c*x**S(6)) - (a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(3)*x**S(3)) + (S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(8)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(7), x), x, b*sqrt(c)*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/S(2) - (b - S(2)*c*x**S(3))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(4)*x**S(3)) - (a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(6)*x**S(6)) - (S(4)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(8)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(10), x), x, c**(S(3)/2)*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/S(3) - (a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(9)*x**S(9)) - (S(2)*a*b + x**S(3)*(S(8)*a*c + b**S(2)))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(24)*a*x**S(6)) + b*(-S(12)*a*c + b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(48)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(13), x), x, -(S(2)*a + b*x**S(3))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(24)*a*x**S(12)) + (S(2)*a + b*x**S(3))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(64)*a**S(2)*x**S(6)) - (-S(4)*a*c + b**S(2))**S(2)*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(128)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(16), x), x, -(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(15)*a*x**S(15)) + b*(S(2)*a + b*x**S(3))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(48)*a**S(2)*x**S(12)) - b*(S(2)*a + b*x**S(3))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(128)*a**S(3)*x**S(6)) + b*(-S(4)*a*c + b**S(2))**S(2)*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(256)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(19), x), x, -(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(18)*a*x**S(18)) + S(7)*b*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(180)*a**S(2)*x**S(15)) - (S(2)*a + b*x**S(3))*(-S(4)*a*c + S(7)*b**S(2))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(576)*a**S(3)*x**S(12)) + (S(2)*a + b*x**S(3))*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(1536)*a**S(4)*x**S(6)) - (-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(7)*b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(3072)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))**(S(3)/2)/x**S(22), x), x, -(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(21)*a*x**S(21)) + b*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(28)*a**S(2)*x**S(18)) - (-S(16)*a*c + S(21)*b**S(2))*(a + b*x**S(3) + c*x**S(6))**(S(5)/2)/(S(840)*a**S(3)*x**S(15)) + b*(S(2)*a + b*x**S(3))*(-S(4)*a*c + S(3)*b**S(2))*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)/(S(384)*a**S(4)*x**S(12)) - b*(S(2)*a + b*x**S(3))*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(1024)*a**S(5)*x**S(6)) + b*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(3)*b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(2048)*a**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, x**(m + S(1))*hyper((S(2), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), -x**S(4))/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -S(7)*b*x**S(6)*sqrt(a + b*x**S(3) + c*x**S(6))/(S(72)*c**S(2)) + x**S(9)*sqrt(a + b*x**S(3) + c*x**S(6))/(S(12)*c) - (S(5)*b*(-S(44)*a*c + S(21)*b**S(2)) - S(2)*c*x**S(3)*(-S(36)*a*c + S(35)*b**S(2)))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(576)*c**S(4)) + (S(48)*a**S(2)*c**S(2) - S(120)*a*b**S(2)*c + S(35)*b**S(4))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(384)*c**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -b*(-S(12)*a*c + S(5)*b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(48)*c**(S(7)/2)) + x**S(6)*sqrt(a + b*x**S(3) + c*x**S(6))/(S(9)*c) + sqrt(a + b*x**S(3) + c*x**S(6))*(-S(16)*a*c + S(15)*b**S(2) - S(10)*b*c*x**S(3))/(S(72)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -b*sqrt(a + b*x**S(3) + c*x**S(6))/(S(4)*c**S(2)) + x**S(3)*sqrt(a + b*x**S(3) + c*x**S(6))/(S(6)*c) + (-S(4)*a*c + S(3)*b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(24)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, -b*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(6)*c**(S(3)/2)) + sqrt(a + b*x**S(3) + c*x**S(6))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*x**S(3) + c*x**S(6)), x), x, atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(3)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*x**S(3) + c*x**S(6))), x), x, -atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(3)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(a + b*x**S(3) + c*x**S(6))), x), x, -sqrt(a + b*x**S(3) + c*x**S(6))/(S(3)*a*x**S(3)) + b*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(6)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*sqrt(a + b*x**S(3) + c*x**S(6))), x), x, -sqrt(a + b*x**S(3) + c*x**S(6))/(S(6)*a*x**S(6)) + b*sqrt(a + b*x**S(3) + c*x**S(6))/(S(4)*a**S(2)*x**S(3)) - (-S(4)*a*c + S(3)*b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(24)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(10)*sqrt(a + b*x**S(3) + c*x**S(6))), x), x, -sqrt(a + b*x**S(3) + c*x**S(6))/(S(9)*a*x**S(9)) + S(5)*b*sqrt(a + b*x**S(3) + c*x**S(6))/(S(36)*a**S(2)*x**S(6)) - (-S(16)*a*c + S(15)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(72)*a**S(3)*x**S(3)) + b*(-S(12)*a*c + S(5)*b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(48)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(13)*sqrt(a + b*x**S(3) + c*x**S(6))), x), x, -sqrt(a + b*x**S(3) + c*x**S(6))/(S(12)*a*x**S(12)) + S(7)*b*sqrt(a + b*x**S(3) + c*x**S(6))/(S(72)*a**S(2)*x**S(9)) - (-S(36)*a*c + S(35)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(288)*a**S(3)*x**S(6)) + S(5)*b*(-S(44)*a*c + S(21)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(576)*a**S(4)*x**S(3)) - (S(48)*a**S(2)*c**S(2) - S(120)*a*b**S(2)*c + S(35)*b**S(4))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(384)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(14)/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -S(2)*b*x**S(6)*sqrt(a + b*x**S(3) + c*x**S(6))/(S(3)*c*(-S(4)*a*c + b**S(2))) + S(2)*x**S(9)*(S(2)*a + b*x**S(3))/((-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))) - (b*(-S(52)*a*c + S(15)*b**S(2)) - S(2)*c*x**S(3)*(-S(12)*a*c + S(5)*b**S(2)))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(12)*c**S(3)*(-S(4)*a*c + b**S(2))) + (-S(4)*a*c + S(5)*b**S(2))*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(8)*c**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -b*atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(2)*c**(S(5)/2)) + S(2)*x**S(6)*(S(2)*a + b*x**S(3))/((-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))) + sqrt(a + b*x**S(3) + c*x**S(6))*(-S(8)*a*c + S(3)*b**S(2) - S(2)*b*c*x**S(3))/(S(3)*c**S(2)*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -S(2)*b*sqrt(a + b*x**S(3) + c*x**S(6))/(S(3)*c*(-S(4)*a*c + b**S(2))) + S(2)*x**S(3)*(S(2)*a + b*x**S(3))/((-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))) + atanh((b + S(2)*c*x**S(3))/(S(2)*sqrt(c)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(3)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, (S(4)*a + S(2)*b*x**S(3))/((-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**S(3) + c*x**S(6))**(S(3)/2), x), x, -(S(2)*b + S(4)*c*x**S(3))/((-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x**S(3))/(S(3)*a*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))) - atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(3)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x**S(3))/(S(3)*a*x**S(3)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))) - (-S(8)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(3)*a**S(2)*x**S(3)*(-S(4)*a*c + b**S(2))) + b*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(2)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x**S(3))/(S(3)*a*x**S(6)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))) - (-S(12)*a*c + S(5)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(6)*a**S(2)*x**S(6)*(-S(4)*a*c + b**S(2))) + b*(-S(52)*a*c + S(15)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(12)*a**S(3)*x**S(3)*(-S(4)*a*c + b**S(2))) - (-S(4)*a*c + S(5)*b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(8)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(10)*(a + b*x**S(3) + c*x**S(6))**(S(3)/2)), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x**S(3))/(S(3)*a*x**S(9)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))) - (-S(16)*a*c + S(7)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(9)*a**S(2)*x**S(9)*(-S(4)*a*c + b**S(2))) + b*(-S(116)*a*c + S(35)*b**S(2))*sqrt(a + b*x**S(3) + c*x**S(6))/(S(36)*a**S(3)*x**S(6)*(-S(4)*a*c + b**S(2))) - sqrt(a + b*x**S(3) + c*x**S(6))*(S(256)*a**S(2)*c**S(2) - S(460)*a*b**S(2)*c + S(105)*b**S(4))/(S(72)*a**S(4)*x**S(3)*(-S(4)*a*c + b**S(2))) + S(5)*b*(-S(12)*a*c + S(7)*b**S(2))*atanh((S(2)*a + b*x**S(3))/(S(2)*sqrt(a)*sqrt(a + b*x**S(3) + c*x**S(6))))/(S(48)*a**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(3) + c*x**S(6))**S(2), x), x, a**S(2)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(2)*a*b*(d*x)**(m + S(4))/(d**S(4)*(m + S(4))) + S(2)*b*c*(d*x)**(m + S(10))/(d**S(10)*(m + S(10))) + c**S(2)*(d*x)**(m + S(13))/(d**S(13)*(m + S(13))) + (d*x)**(m + S(7))*(S(2)*a*c + b**S(2))/(d**S(7)*(m + S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**S(3) + c*x**S(6)), x), x, a*(d*x)**(m + S(1))/(d*(m + S(1))) + b*(d*x)**(m + S(4))/(d**S(4)*(m + S(4))) + c*(d*x)**(m + S(7))/(d**S(7)*(m + S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**S(3) + c*x**S(6)), x), x, -S(2)*c*(d*x)**(m + S(1))*hyper((S(1), m/S(3) + S(1)/3), (m/S(3) + S(4)/3,), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*(d*x)**(m + S(1))*hyper((S(1), m/S(3) + S(1)/3), (m/S(3) + S(4)/3,), -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))))/(d*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**S(3) + c*x**S(6))**S(2), x), x, -c*(d*x)**(m + S(1))*(-S(4)*a*c*(-m + S(5)) + b**S(2)*(-m + S(2)) - b*(-m + S(2))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(3) + S(1)/3), (m/S(3) + S(4)/3,), -S(2)*c*x**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*d*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + c*(d*x)**(m + S(1))*(-S(4)*a*c*(-m + S(5)) + b**S(2)*(-m + S(2)) + b*(-m + S(2))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(3) + S(1)/3), (m/S(3) + S(4)/3,), -S(2)*c*x**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*d*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (d*x)**(m + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**S(3))/(S(3)*a*d*(-S(4)*a*c + b**S(2))*(a + b*x**S(3) + c*x**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(3) + c*x**S(6))**p, x), x, S(2)**p*b*(-(b + S(2)*c*x**S(3) - sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))**(-p + S(-1))*(a + b*x**S(3) + c*x**S(6))**(p + S(1))*hyper((-p, p + S(1)), (p + S(2),), (b + S(2)*c*x**S(3) + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*sqrt(-S(4)*a*c + b**S(2))))/(S(3)*c*(p + S(1))*sqrt(-S(4)*a*c + b**S(2))) + (a + b*x**S(3) + c*x**S(6))**(p + S(1))/(S(6)*c*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(3) + c*x**S(6))**p, x), x, -S(2)**(p + S(1))*(-(b + S(2)*c*x**S(3) - sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))**(-p + S(-1))*(a + b*x**S(3) + c*x**S(6))**(p + S(1))*hyper((-p, p + S(1)), (p + S(2),), (b + S(2)*c*x**S(3) + sqrt(-S(4)*a*c + b**S(2)))/(S(2)*sqrt(-S(4)*a*c + b**S(2))))/(S(3)*(p + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, -x**S(6)/(S(4)*x**S(4) + S(4)) + S(3)*x**S(2)/S(4) - S(3)*atan(x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, log(x**S(4) + S(1))/S(4) + S(1)/(S(4)*x**S(4) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, -x**S(2)/(S(4)*x**S(4) + S(4)) + atan(x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, -S(1)/(S(4)*x**S(4) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, x**S(2)/(S(4)*x**S(4) + S(4)) + atan(x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, log(x) - log(x**S(4) + S(1))/S(4) + S(1)/(S(4)*x**S(4) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, -S(3)*atan(x**S(2))/S(4) - S(3)/(S(4)*x**S(2)) + S(1)/(S(4)*x**S(2)*(x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, -S(2)*log(x) + log(x**S(4) + S(1))/S(2) - S(1)/(S(4)*x**S(4) + S(4)) - S(1)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, S(5)*atan(x**S(2))/S(4) + S(5)/(S(4)*x**S(2)) - S(5)/(S(12)*x**S(6)) + S(1)/(S(4)*x**S(6)*(x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, -x**S(5)/(S(4)*x**S(4) + S(4)) + S(5)*x/S(4) + S(5)*sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) - S(5)*sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) - S(5)*sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) - S(5)*sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, -x**S(3)/(S(4)*x**S(4) + S(4)) + S(3)*sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) - S(3)*sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) + S(3)*sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) + S(3)*sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, -x/(S(4)*x**S(4) + S(4)) - sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) + sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) + sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) + sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, x**S(3)/(S(4)*x**S(4) + S(4)) + sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) - sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) + sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) + sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8) + S(2)*x**S(4) + S(1)), x), x, x/(S(4)*x**S(4) + S(4)) - S(3)*sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) + S(3)*sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) + S(3)*sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) + S(3)*sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, -S(5)*sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) + S(5)*sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) - S(5)*sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) - S(5)*sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16) - S(5)/(S(4)*x) + S(1)/(S(4)*x*(x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, S(7)*sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) - S(7)*sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) - S(7)*sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) - S(7)*sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16) - S(7)/(S(12)*x**S(3)) + S(1)/(S(4)*x**S(3)*(x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, S(9)*sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) - S(9)*sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) + S(9)*sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) + S(9)*sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16) + S(9)/(S(4)*x) - S(9)/(S(20)*x**S(5)) + S(1)/(S(4)*x**S(5)*(x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8)*(x**S(8) + S(2)*x**S(4) + S(1))), x), x, -S(11)*sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(32) + S(11)*sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(32) + S(11)*sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(16) + S(11)*sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(16) + S(11)/(S(12)*x**S(3)) - S(11)/(S(28)*x**S(7)) + S(1)/(S(4)*x**S(7)*(x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x**(m + S(1))*hyper((S(2), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), x**S(4))/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x**S(6)/(-S(4)*x**S(4) + S(4)) + S(3)*x**S(2)/S(4) - S(3)*atanh(x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, log(-x**S(4) + S(1))/S(4) + S(1)/(-S(4)*x**S(4) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x**S(2)/(-S(4)*x**S(4) + S(4)) - atanh(x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, S(1)/(-S(4)*x**S(4) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x**S(2)/(-S(4)*x**S(4) + S(4)) + atanh(x**S(2))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, log(x) - log(-x**S(4) + S(1))/S(4) + S(1)/(-S(4)*x**S(4) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, S(3)*atanh(x**S(2))/S(4) - S(3)/(S(4)*x**S(2)) + S(1)/(S(4)*x**S(2)*(-x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, S(2)*log(x) - log(-x**S(4) + S(1))/S(2) + S(1)/(-S(4)*x**S(4) + S(4)) - S(1)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, S(5)*atanh(x**S(2))/S(4) - S(5)/(S(4)*x**S(2)) - S(5)/(S(12)*x**S(6)) + S(1)/(S(4)*x**S(6)*(-x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x**S(5)/(-S(4)*x**S(4) + S(4)) + S(5)*x/S(4) - S(5)*atan(x)/S(8) - S(5)*atanh(x)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x**S(3)/(-S(4)*x**S(4) + S(4)) + S(3)*atan(x)/S(8) - S(3)*atanh(x)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x/(-S(4)*x**S(4) + S(4)) - atan(x)/S(8) - atanh(x)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x**S(3)/(-S(4)*x**S(4) + S(4)) - atan(x)/S(8) + atanh(x)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8) - S(2)*x**S(4) + S(1)), x), x, x/(-S(4)*x**S(4) + S(4)) + S(3)*atan(x)/S(8) + S(3)*atanh(x)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, -S(5)*atan(x)/S(8) + S(5)*atanh(x)/S(8) - S(5)/(S(4)*x) + S(1)/(S(4)*x*(-x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, S(7)*atan(x)/S(8) + S(7)*atanh(x)/S(8) - S(7)/(S(12)*x**S(3)) + S(1)/(S(4)*x**S(3)*(-x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, -S(9)*atan(x)/S(8) + S(9)*atanh(x)/S(8) - S(9)/(S(4)*x) - S(9)/(S(20)*x**S(5)) + S(1)/(S(4)*x**S(5)*(-x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8)*(x**S(8) - S(2)*x**S(4) + S(1))), x), x, S(11)*atan(x)/S(8) + S(11)*atanh(x)/S(8) - S(11)/(S(12)*x**S(3)) - S(11)/(S(28)*x**S(7)) + S(1)/(S(4)*x**S(7)*(-x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(a + b*x**S(4) + c*x**S(8)), x), x, -S(2)*c*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), -S(2)*c*x**S(4)/(b + sqrt(-S(4)*a*c + b**S(2))))/((b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), -S(2)*c*x**S(4)/(b - sqrt(-S(4)*a*c + b**S(2))))/((b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(a + b*x**S(4) + c*x**S(8)), x), x, -b*log(a + b*x**S(4) + c*x**S(8))/(S(8)*c**S(2)) + x**S(4)/(S(4)*c) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(4))/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(a + b*x**S(4) + c*x**S(8)), x), x, x**S(2)/(S(2)*c) - sqrt(S(2))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a + b*x**S(4) + c*x**S(8)), x), x, b*atanh((b + S(2)*c*x**S(4))/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*c*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*x**S(4) + c*x**S(8))/(S(8)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a + b*x**S(4) + c*x**S(8)), x), x, -sqrt(S(2))*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**S(4) + c*x**S(8)), x), x, -atanh((b + S(2)*c*x**S(4))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**S(4) + c*x**S(8)), x), x, -sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**S(4) + c*x**S(8))), x), x, b*atanh((b + S(2)*c*x**S(4))/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*a*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a + b*x**S(4) + c*x**S(8))/(S(8)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**S(4) + c*x**S(8))), x), x, -sqrt(S(2))*sqrt(c)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - S(1)/(S(2)*a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a + b*x**S(4) + c*x**S(8))), x), x, -S(1)/(S(4)*a*x**S(4)) - b*log(x)/a**S(2) + b*log(a + b*x**S(4) + c*x**S(8))/(S(8)*a**S(2)) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(4))/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(a + b*x**S(4) + c*x**S(8)), x), x, x**S(3)/(S(3)*c) - S(2)**(S(1)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(7)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(7)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(7)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(7)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a + b*x**S(4) + c*x**S(8)), x), x, x/c + S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a + b*x**S(4) + c*x**S(8)), x), x, -S(2)**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a + b*x**S(4) + c*x**S(8)), x), x, S(2)**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**S(4) + c*x**S(8)), x), x, S(2)**(S(1)/4)*c**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*c**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(1)/4)*c**(S(1)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(1)/4)*c**(S(1)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x**S(4) + c*x**S(8)), x), x, -S(2)**(S(3)/4)*c**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(3)/4)*c**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(2)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**S(4) + c*x**S(8))), x), x, -S(2)**(S(1)/4)*c**(S(1)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*c**(S(1)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*c**(S(1)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*c**(S(1)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(1)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a + b*x**S(4) + c*x**S(8))), x), x, S(2)**(S(3)/4)*c**(S(3)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(1)/(S(3)*a*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(x**S(8) + x**S(4) + S(1)), x), x, S(2)*sqrt(S(3))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), -S(2)*x**S(4)/(S(1) - sqrt(S(3))*I))/(S(3)*(sqrt(S(3)) + I)*(m + S(1))) - S(2)*sqrt(S(3))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), -S(2)*x**S(4)/(S(1) + sqrt(S(3))*I))/(S(3)*(-sqrt(S(3)) + I)*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(x**S(8) + x**S(4) + S(1)), x), x, x**S(4)/S(4) - log(x**S(8) + x**S(4) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(8) + x**S(4) + S(1)), x), x, x**S(2)/S(2) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(2) + S(1))/S(3))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(x**S(8) + x**S(4) + S(1)), x), x, log(x**S(8) + x**S(4) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(8) + x**S(4) + S(1)), x), x, log(x**S(4) - x**S(2) + S(1))/S(8) - log(x**S(4) + x**S(2) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(2) + S(1))/S(3))/S(12) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(8) + x**S(4) + S(1)), x), x, sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(4) + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(8) + x**S(4) + S(1)), x), x, -log(x**S(4) - x**S(2) + S(1))/S(8) + log(x**S(4) + x**S(2) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(2) + S(1))/S(3))/S(12) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(8) + x**S(4) + S(1))), x), x, log(x) - log(x**S(8) + x**S(4) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(8) + x**S(4) + S(1))), x), x, sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(2) + S(1))/S(3))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(6) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(8) + x**S(4) + S(1))), x), x, -log(x) + log(x**S(8) + x**S(4) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(4) + S(1))/S(3))/S(12) - S(1)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(x**S(8) + x**S(4) + S(1))), x), x, log(x**S(4) - x**S(2) + S(1))/S(8) - log(x**S(4) + x**S(2) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(2) + S(1))/S(3))/S(12) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(12) + S(1)/(S(2)*x**S(2)) - S(1)/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(x**S(8) + x**S(4) + S(1)), x), x, x + log(x**S(2) - x + S(1))/S(8) - log(x**S(2) + x + S(1))/S(8) + sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(24) - sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12) - atan(S(2)*x - sqrt(S(3)))/S(4) - atan(S(2)*x + sqrt(S(3)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(x**S(8) + x**S(4) + S(1)), x), x, sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(12) - sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(8) + x**S(4) + S(1)), x), x, -log(x**S(2) - x + S(1))/S(8) + log(x**S(2) + x + S(1))/S(8) + sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(24) - sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12) + atan(S(2)*x - sqrt(S(3)))/S(4) + atan(S(2)*x + sqrt(S(3)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(8) + x**S(4) + S(1)), x), x, log(x**S(2) - x + S(1))/S(8) - log(x**S(2) + x + S(1))/S(8) - sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12) + atan(S(2)*x - sqrt(S(3)))/S(4) + atan(S(2)*x + sqrt(S(3)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8) + x**S(4) + S(1)), x), x, -sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(12) + sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x**S(8) + x**S(4) + S(1))), x), x, -log(x**S(2) - x + S(1))/S(8) + log(x**S(2) + x + S(1))/S(8) - sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12) - atan(S(2)*x - sqrt(S(3)))/S(4) - atan(S(2)*x + sqrt(S(3)))/S(4) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(x**S(8) + x**S(4) + S(1))), x), x, log(x**S(2) - x + S(1))/S(8) - log(x**S(2) + x + S(1))/S(8) + sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(24) - sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12) - atan(S(2)*x - sqrt(S(3)))/S(4) - atan(S(2)*x + sqrt(S(3)))/S(4) - S(1)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(x**S(8) + x**S(4) + S(1))), x), x, sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(12) - sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6) + S(1)/x - S(1)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8)*(x**S(8) + x**S(4) + S(1))), x), x, -log(x**S(2) - x + S(1))/S(8) + log(x**S(2) + x + S(1))/S(8) + sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(24) - sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(12) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12) + atan(S(2)*x - sqrt(S(3)))/S(4) + atan(S(2)*x + sqrt(S(3)))/S(4) + S(1)/(S(3)*x**S(3)) - S(1)/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(x**S(8) - x**S(4) + S(1)), x), x, S(2)*sqrt(S(3))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), S(2)*x**S(4)/(S(1) - sqrt(S(3))*I))/(S(3)*(sqrt(S(3)) + I)*(m + S(1))) - S(2)*sqrt(S(3))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), S(2)*x**S(4)/(S(1) + sqrt(S(3))*I))/(S(3)*(-sqrt(S(3)) + I)*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(x**S(8) - x**S(4) + S(1)), x), x, x**S(4)/S(4) + log(x**S(8) - x**S(4) + S(1))/S(8) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(8) - x**S(4) + S(1)), x), x, x**S(2)/S(2) + sqrt(S(3))*log(x**S(4) - sqrt(S(3))*x**S(2) + S(1))/S(12) - sqrt(S(3))*log(x**S(4) + sqrt(S(3))*x**S(2) + S(1))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(x**S(8) - x**S(4) + S(1)), x), x, log(x**S(8) - x**S(4) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(8) - x**S(4) + S(1)), x), x, sqrt(S(3))*log(x**S(4) - sqrt(S(3))*x**S(2) + S(1))/S(24) - sqrt(S(3))*log(x**S(4) + sqrt(S(3))*x**S(2) + S(1))/S(24) + atan(S(2)*x**S(2) - sqrt(S(3)))/S(4) + atan(S(2)*x**S(2) + sqrt(S(3)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(8) - x**S(4) + S(1)), x), x, -sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(4) + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(8) - x**S(4) + S(1)), x), x, -sqrt(S(3))*log(x**S(4) - sqrt(S(3))*x**S(2) + S(1))/S(24) + sqrt(S(3))*log(x**S(4) + sqrt(S(3))*x**S(2) + S(1))/S(24) + atan(S(2)*x**S(2) - sqrt(S(3)))/S(4) + atan(S(2)*x**S(2) + sqrt(S(3)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(8) - x**S(4) + S(1))), x), x, log(x) - log(x**S(8) - x**S(4) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(8) - x**S(4) + S(1))), x), x, -sqrt(S(3))*log(x**S(4) - sqrt(S(3))*x**S(2) + S(1))/S(12) + sqrt(S(3))*log(x**S(4) + sqrt(S(3))*x**S(2) + S(1))/S(12) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(8) - x**S(4) + S(1))), x), x, log(x) - log(x**S(8) - x**S(4) + S(1))/S(8) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(4) + S(1))/S(3))/S(12) - S(1)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(x**S(8) - x**S(4) + S(1))), x), x, -sqrt(S(3))*log(x**S(4) - sqrt(S(3))*x**S(2) + S(1))/S(24) + sqrt(S(3))*log(x**S(4) + sqrt(S(3))*x**S(2) + S(1))/S(24) - atan(S(2)*x**S(2) - sqrt(S(3)))/S(4) - atan(S(2)*x**S(2) + sqrt(S(3)))/S(4) - S(1)/(S(2)*x**S(2)) - S(1)/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(x**S(8) - x**S(4) + S(1)), x), x, x - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) - atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) + atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) + atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))) - atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(x**S(8) - x**S(4) + S(1)), x), x, sqrt(S(6))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) - sqrt(S(6))*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(8) - x**S(4) + S(1)), x), x, -log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(-S(3)*sqrt(S(3)) + S(6))) + log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(-S(3)*sqrt(S(3)) + S(6))) + log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(S(3)*sqrt(S(3)) + S(6))) - log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(S(3)*sqrt(S(3)) + S(6))) - atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))) + atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))) + atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) - atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(8) - x**S(4) + S(1)), x), x, log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(-S(3)*sqrt(S(3)) + S(6))) - log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(-S(3)*sqrt(S(3)) + S(6))) - log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(S(3)*sqrt(S(3)) + S(6))) + log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(S(3)*sqrt(S(3)) + S(6))) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) + sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8) - x**S(4) + S(1)), x), x, -sqrt(S(6))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) - sqrt(S(6))*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x**S(8) - x**S(4) + S(1))), x), x, sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) - atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) + atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) + atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))) - atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(x**S(8) - x**S(4) + S(1))), x), x, sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) - S(1)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(x**S(8) - x**S(4) + S(1))), x), x, -sqrt(S(6))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) - sqrt(S(6))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12) - sqrt(S(6))*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12) - S(1)/x - S(1)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8)*(x**S(8) - x**S(4) + S(1))), x), x, sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) + sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) - S(1)/(S(3)*x**S(3)) - S(1)/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(x**S(8) + S(3)*x**S(4) + S(1)), x), x, S(2)*sqrt(S(5))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), -S(2)*x**S(4)/(-sqrt(S(5)) + S(3)))/(S(5)*(-sqrt(S(5)) + S(3))*(m + S(1))) - S(2)*sqrt(S(5))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), -S(2)*x**S(4)/(sqrt(S(5)) + S(3)))/(S(5)*(sqrt(S(5)) + S(3))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(x**S(8) + S(3)*x**S(4) + S(1)), x), x, x**S(4)/S(4) - (-S(7)*sqrt(S(5))/S(40) + S(3)/8)*log(S(2)*x**S(4) - sqrt(S(5)) + S(3)) - (S(3)/8 + S(7)*sqrt(S(5))/S(40))*log(S(2)*x**S(4) + sqrt(S(5)) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(8) + S(3)*x**S(4) + S(1)), x), x, x**S(2)/S(2) + sqrt(-S(4)*sqrt(S(5))/S(5) + S(9)/5)*atan(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) - sqrt(S(4)*sqrt(S(5))/S(5) + S(9)/5)*atan(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(x**S(8) + S(3)*x**S(4) + S(1)), x), x, (-S(3)*sqrt(S(5))/S(40) + S(1)/8)*log(S(2)*x**S(4) - sqrt(S(5)) + S(3)) + (S(1)/8 + S(3)*sqrt(S(5))/S(40))*log(S(2)*x**S(4) + sqrt(S(5)) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(8) + S(3)*x**S(4) + S(1)), x), x, -sqrt(-sqrt(S(5))/S(10) + S(3)/10)*atan(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) + sqrt(sqrt(S(5))/S(10) + S(3)/10)*atan(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(8) + S(3)*x**S(4) + S(1)), x), x, -sqrt(S(5))*atanh(sqrt(S(5))*(S(2)*x**S(4) + S(3))/S(5))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(8) + S(3)*x**S(4) + S(1)), x), x, sqrt(sqrt(S(5))/S(10) + S(3)/10)*atan(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) - atan(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/sqrt(S(10)*sqrt(S(5)) + S(30)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(8) + S(3)*x**S(4) + S(1))), x), x, log(x) - (S(1)/8 + S(3)*sqrt(S(5))/S(40))*log(S(2)*x**S(4) - sqrt(S(5)) + S(3)) - (-S(3)*sqrt(S(5))/S(40) + S(1)/8)*log(S(2)*x**S(4) + sqrt(S(5)) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(8) + S(3)*x**S(4) + S(1))), x), x, -sqrt(S(10))*(sqrt(S(5)) + S(3))**(S(3)/2)*atan(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(40) + sqrt(-S(4)*sqrt(S(5))/S(5) + S(9)/5)*atan(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(8) + S(3)*x**S(4) + S(1))), x), x, -S(3)*log(x) + (S(3)/8 + S(7)*sqrt(S(5))/S(40))*log(S(2)*x**S(4) - sqrt(S(5)) + S(3)) + (-S(7)*sqrt(S(5))/S(40) + S(3)/8)*log(S(2)*x**S(4) + sqrt(S(5)) + S(3)) - S(1)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(x**S(8) + S(3)*x**S(4) + S(1))), x), x, sqrt(S(11)*sqrt(S(5))/S(2) + S(123)/10)*atan(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) - sqrt(-S(11)*sqrt(S(5))/S(2) + S(123)/10)*atan(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2) + S(3)/(S(2)*x**S(2)) - S(1)/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, S(2)*sqrt(S(5))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), S(2)*x**S(4)/(-sqrt(S(5)) + S(3)))/(S(5)*(-sqrt(S(5)) + S(3))*(m + S(1))) - S(2)*sqrt(S(5))*x**(m + S(1))*hyper((S(1), m/S(4) + S(1)/4), (m/S(4) + S(5)/4,), S(2)*x**S(4)/(sqrt(S(5)) + S(3)))/(S(5)*(sqrt(S(5)) + S(3))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, x**S(4)/S(4) + (-S(7)*sqrt(S(5))/S(40) + S(3)/8)*log(-S(2)*x**S(4) - sqrt(S(5)) + S(3)) + (S(3)/8 + S(7)*sqrt(S(5))/S(40))*log(-S(2)*x**S(4) + sqrt(S(5)) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, x**S(2)/S(2) + sqrt(-S(4)*sqrt(S(5))/S(5) + S(9)/5)*atanh(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) - sqrt(S(4)*sqrt(S(5))/S(5) + S(9)/5)*atanh(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, (-S(3)*sqrt(S(5))/S(40) + S(1)/8)*log(-S(2)*x**S(4) - sqrt(S(5)) + S(3)) + (S(1)/8 + S(3)*sqrt(S(5))/S(40))*log(-S(2)*x**S(4) + sqrt(S(5)) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, sqrt(-sqrt(S(5))/S(10) + S(3)/10)*atanh(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) - sqrt(sqrt(S(5))/S(10) + S(3)/10)*atanh(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, sqrt(S(5))*atanh(sqrt(S(5))*(-S(2)*x**S(4) + S(3))/S(5))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, sqrt(sqrt(S(5))/S(10) + S(3)/10)*atanh(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) - atanh(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/sqrt(S(10)*sqrt(S(5)) + S(30)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(8) - S(3)*x**S(4) + S(1))), x), x, log(x) - (S(1)/8 + S(3)*sqrt(S(5))/S(40))*log(-S(2)*x**S(4) - sqrt(S(5)) + S(3)) - (-S(3)*sqrt(S(5))/S(40) + S(1)/8)*log(-S(2)*x**S(4) + sqrt(S(5)) + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(x**S(8) - S(3)*x**S(4) + S(1))), x), x, sqrt(S(10))*(sqrt(S(5)) + S(3))**(S(3)/2)*atanh(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(40) - sqrt(-S(4)*sqrt(S(5))/S(5) + S(9)/5)*atanh(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(x**S(8) - S(3)*x**S(4) + S(1))), x), x, S(3)*log(x) - (S(3)/8 + S(7)*sqrt(S(5))/S(40))*log(-S(2)*x**S(4) - sqrt(S(5)) + S(3)) - (-S(7)*sqrt(S(5))/S(40) + S(3)/8)*log(-S(2)*x**S(4) + sqrt(S(5)) + S(3)) - S(1)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(x**S(8) - S(3)*x**S(4) + S(1))), x), x, sqrt(S(11)*sqrt(S(5))/S(2) + S(123)/10)*atanh(x**S(2)*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(2) - sqrt(-S(11)*sqrt(S(5))/S(2) + S(123)/10)*atanh(sqrt(S(2))*x**S(2)/sqrt(sqrt(S(5)) + S(3)))/S(2) - S(3)/(S(2)*x**S(2)) - S(1)/(S(6)*x**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, x + sqrt(S(5))*(-S(440)*sqrt(S(5)) + S(984))**(S(1)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(20) - sqrt(S(5))*(S(55)*sqrt(S(5))/S(2) + S(123)/2)**(S(1)/4)*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10) + sqrt(S(5))*(-S(440)*sqrt(S(5)) + S(984))**(S(1)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(20) - sqrt(S(5))*(S(55)*sqrt(S(5))/S(2) + S(123)/2)**(S(1)/4)*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, -sqrt(S(5))*(-S(64)*sqrt(S(5)) + S(144))**(S(1)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(20) + S(2)**(S(1)/4)*sqrt(S(5))*(sqrt(S(5)) + S(3))**(S(3)/4)*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(20) + sqrt(S(5))*(-S(64)*sqrt(S(5)) + S(144))**(S(1)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(20) - S(2)**(S(1)/4)*sqrt(S(5))*(sqrt(S(5)) + S(3))**(S(3)/4)*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(20), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, sqrt(S(5))*(-sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) - sqrt(S(5))*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10) + sqrt(S(5))*(-sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) - sqrt(S(5))*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, sqrt(S(-10) + S(10)*sqrt(S(5)))*atan(x*sqrt(S(-2) + S(2)*sqrt(S(5)))/S(2))/S(20) - sqrt(S(10) + S(10)*sqrt(S(5)))*atan(x*sqrt(S(2) + S(2)*sqrt(S(5)))/S(2))/S(20) - sqrt(S(-10) + S(10)*sqrt(S(5)))*atanh(x*sqrt(S(-2) + S(2)*sqrt(S(5)))/S(2))/S(20) + sqrt(S(10) + S(10)*sqrt(S(5)))*atanh(x*sqrt(S(2) + S(2)*sqrt(S(5)))/S(2))/S(20), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, -sqrt(S(5))*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) + S(2)**(S(1)/4)*sqrt(S(5))*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/(S(10)*(sqrt(S(5)) + S(3))**(S(1)/4)) + sqrt(S(5))*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) - S(2)**(S(1)/4)*sqrt(S(5))*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/(S(10)*(sqrt(S(5)) + S(3))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(x**S(8) - S(3)*x**S(4) + S(1))), x), x, -S(2)**(S(3)/4)*sqrt(S(5))*(sqrt(S(5)) + S(3))**(S(5)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(40) + sqrt(S(5))*(-S(440)*sqrt(S(5)) + S(984))**(S(1)/4)*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(20) + S(2)**(S(3)/4)*sqrt(S(5))*(sqrt(S(5)) + S(3))**(S(5)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(40) - sqrt(S(5))*(-S(440)*sqrt(S(5)) + S(984))**(S(1)/4)*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(20) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(x**S(8) - S(3)*x**S(4) + S(1))), x), x, -sqrt(S(5))*(S(1292)*sqrt(S(5)) + S(2889))**(S(1)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) + sqrt(S(5))*(-S(1292)*sqrt(S(5)) + S(2889))**(S(1)/4)*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10) + sqrt(S(5))*(S(1292)*sqrt(S(5)) + S(2889))**(S(1)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) - sqrt(S(5))*(-S(1292)*sqrt(S(5)) + S(2889))**(S(1)/4)*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10) - S(3)/x - S(1)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8)*(x**S(8) - S(3)*x**S(4) + S(1))), x), x, sqrt(S(5))*(S(17711)*sqrt(S(5))/S(2) + S(39603)/2)**(S(1)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) - sqrt(S(5))*(-S(17711)*sqrt(S(5))/S(2) + S(39603)/2)**(S(1)/4)*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10) + sqrt(S(5))*(S(17711)*sqrt(S(5))/S(2) + S(39603)/2)**(S(1)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) - sqrt(S(5))*(-S(17711)*sqrt(S(5))/S(2) + S(39603)/2)**(S(1)/4)*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10) - S(1)/x**S(3) - S(1)/(S(7)*x**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(x**S(8) + S(3)*x**S(4) + S(2)), x), x, -atanh(S(2)*x**S(4) + S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(x**S(8) + S(3)*x**S(4) + S(2)), x), x, x**S(4)/S(4) + log(x**S(4) + S(1))/S(4) - log(x**S(4) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(x**S(10) + x**S(5) + S(2)), x), x, log(x**S(10) + x**S(5) + S(2))/S(10) - sqrt(S(7))*atan(sqrt(S(7))*(S(2)*x**S(5) + S(1))/S(7))/S(35), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(x**S(10) + x**S(5) + S(2)), x), x, S(2)*sqrt(S(7))*atan(sqrt(S(7))*(S(2)*x**S(5) + S(1))/S(7))/S(35), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(x**S(10) + x**S(5) + S(1))), x), x, log(x) - log(x**S(10) + x**S(5) + S(1))/S(10) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(5) + S(1))/S(3))/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(x**S(10) + x**S(5) + S(1))), x), x, -log(x) + log(x**S(10) + x**S(5) + S(1))/S(10) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(5) + S(1))/S(3))/S(15) - S(1)/(S(5)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(11) + x**S(6) + x), x), x, log(x) - log(x**S(10) + x**S(5) + S(1))/S(10) - sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(5) + S(1))/S(3))/S(15), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a/x**S(2) + b/x + c), x), x, -b*x**S(3)/(S(3)*c**S(2)) - b*x*(-S(2)*a*c + b**S(2))/c**S(4) + b*(S(5)*a**S(2)*c**S(2) - S(5)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(5)*sqrt(-S(4)*a*c + b**S(2))) + x**S(4)/(S(4)*c) + x**S(2)*(-a*c + b**S(2))/(S(2)*c**S(3)) + (a**S(2)*c**S(2) - S(3)*a*b**S(2)*c + b**S(4))*log(a + b*x + c*x**S(2))/(S(2)*c**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a/x**S(2) + b/x + c), x), x, -b*x**S(2)/(S(2)*c**S(2)) - b*(-S(2)*a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*c**S(4)) + x**S(3)/(S(3)*c) + x*(-a*c + b**S(2))/c**S(3) - (S(2)*a**S(2)*c**S(2) - S(4)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a/x**S(2) + b/x + c), x), x, -b*x/c**S(2) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*sqrt(-S(4)*a*c + b**S(2))) + x**S(2)/(S(2)*c) + (-a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a/x**S(2) + b/x + c), x), x, -b*log(a + b*x + c*x**S(2))/(S(2)*c**S(2)) + x/c - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a/x**S(2) + b/x + c)), x), x, b*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*x + c*x**S(2))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a/x**S(2) + b/x + c)), x), x, S(2)*atanh((S(2)*a/x + b)/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a/x**S(2) + b/x + c)), x), x, b*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a + b*x + c*x**S(2))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a/x**S(2) + b/x + c)), x), x, -S(1)/(a*x) - b*log(x)/a**S(2) + b*log(a + b*x + c*x**S(2))/(S(2)*a**S(2)) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a/x**S(2) + b/x + c)), x), x, -S(1)/(S(2)*a*x**S(2)) + b/(a**S(2)*x) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*sqrt(-S(4)*a*c + b**S(2))) + (-a*c + b**S(2))*log(x)/a**S(3) - (-a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(a/x**S(2) + b/x + c)), x), x, -S(1)/(S(3)*a*x**S(3)) + b/(S(2)*a**S(2)*x**S(2)) - (-a*c + b**S(2))/(a**S(3)*x) - b*(-S(2)*a*c + b**S(2))*log(x)/a**S(4) + b*(-S(2)*a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*a**S(4)) - (S(2)*a**S(2)*c**S(2) - S(4)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a/x**S(2) + b/x + c)**S(2), x), x, -b*x**S(3)/(c*(-S(4)*a*c + b**S(2))) - b*x*(-S(11)*a*c + S(3)*b**S(2))/(c**S(3)*(-S(4)*a*c + b**S(2))) + b*(S(30)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x**S(4)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + x**S(2)*(-S(8)*a*c + S(3)*b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))) + (-S(2)*a*c + S(3)*b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*c**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a/x**S(2) + b/x + c)**(S(-2)), x), x, -b*x**S(2)/(c*(-S(4)*a*c + b**S(2))) - b*log(a + b*x + c*x**S(2))/c**S(3) + x**S(3)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + x*(-S(6)*a*c + S(2)*b**S(2))/(c**S(2)*(-S(4)*a*c + b**S(2))) - (S(12)*a**S(2)*c**S(2) - S(12)*a*b**S(2)*c + S(2)*b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a/x**S(2) + b/x + c)**S(2)), x), x, -b*x/(c*(-S(4)*a*c + b**S(2))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x**S(2)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + log(a + b*x + c*x**S(2))/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a/x**S(2) + b/x + c)**S(2)), x), x, -S(4)*a*atanh((S(2)*a/x + b)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + (S(2)*a/x + b)/((-S(4)*a*c + b**S(2))*(a/x**S(2) + b/x + c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a/x**S(2) + b/x + c)**S(2)), x), x, -S(2)*b*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + (S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a/x**S(2) + b/x + c)**S(2)), x), x, S(4)*c*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - (b + S(2)*c*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a/x**S(2) + b/x + c)**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + log(x)/a**S(2) - log(a + b*x + c*x**S(2))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(a/x**S(2) + b/x + c)**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*x*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + (S(6)*a*c - S(2)*b**S(2))/(a**S(2)*x*(-S(4)*a*c + b**S(2))) - S(2)*b*log(x)/a**S(3) + b*log(a + b*x + c*x**S(2))/a**S(3) - (S(12)*a**S(2)*c**S(2) - S(12)*a*b**S(2)*c + S(2)*b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(a/x**S(2) + b/x + c)**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) - (-S(8)*a*c + S(3)*b**S(2))/(S(2)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) + b*(-S(11)*a*c + S(3)*b**S(2))/(a**S(3)*x*(-S(4)*a*c + b**S(2))) + b*(S(30)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (-S(2)*a*c + S(3)*b**S(2))*log(x)/a**S(4) - (-S(2)*a*c + S(3)*b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a/x**S(2) + b/x + c)**(S(-3)), x), x, -S(3)*b*x**S(2)*(-S(6)*a*c + b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*b*log(a + b*x + c*x**S(2))/(S(2)*c**S(4)) + x**S(5)*(S(2)*a + b*x)/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x + c*x**S(2))**S(2)) + x**S(3)*(a*(-S(10)*a*c + b**S(2)) + b*x*(-S(7)*a*c + b**S(2)))/(c*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) + x*(S(30)*a**S(2)*c**S(2) - S(21)*a*b**S(2)*c + S(3)*b**S(4))/(c**S(3)*(-S(4)*a*c + b**S(2))**S(2)) - (-S(60)*a**S(3)*c**S(3) + S(90)*a**S(2)*b**S(2)*c**S(2) - S(30)*a*b**S(4)*c + S(3)*b**S(6))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(4)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a/x**S(2) + b/x + c)**S(3)), x), x, -b*x*(-S(7)*a*c + b**S(2))/(c**S(2)*(-S(4)*a*c + b**S(2))**S(2)) + b*(S(30)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x**S(4)*(S(2)*a + b*x)/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x + c*x**S(2))**S(2)) + x**S(2)*(a*(-S(16)*a*c + b**S(2)) + b*x*(-S(10)*a*c + b**S(2)))/(S(2)*c*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) + log(a + b*x + c*x**S(2))/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a/x**S(2) + b/x + c)**S(3)), x), x, S(12)*a**S(2)*atanh((S(2)*a/x + b)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) - S(3)*a*(S(2)*a/x + b)/((-S(4)*a*c + b**S(2))**S(2)*(a/x**S(2) + b/x + c)) + (S(2)*a/x + b)/((-S(8)*a*c + S(2)*b**S(2))*(a/x**S(2) + b/x + c)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a/x**S(2) + b/x + c)**S(3)), x), x, S(6)*a*b*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + S(3)*b*x*(S(2)*a + b*x)/(S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) - x**S(3)*(b + S(2)*c*x)/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x + c*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(a/x**S(2) + b/x + c)**S(3)), x), x, x*(S(2)*a + b*x)/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x + c*x**S(2))**S(2)) + (S(3)*a*b + x*(S(2)*a*c + b**S(2)))/((-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) - (S(4)*a*c + S(2)*b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(a/x**S(2) + b/x + c)**S(3)), x), x, S(6)*b*c*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) - S(3)*b*(b + S(2)*c*x)/(S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) + (S(2)*a + b*x)/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x + c*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(a/x**S(2) + b/x + c)**S(3)), x), x, -S(12)*c**S(2)*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + S(3)*c*(b + S(2)*c*x)/((-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) + (-b - S(2)*c*x)/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x + c*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(7)*(a/x**S(2) + b/x + c)**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))**S(2)) + (S(16)*a**S(2)*c**S(2) - S(15)*a*b**S(2)*c + S(2)*b**S(4) + S(2)*b*c*x*(-S(7)*a*c + b**S(2)))/(S(2)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) + b*(S(30)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + log(x)/a**S(3) - log(a + b*x + c*x**S(2))/(S(2)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(8)*(a/x**S(2) + b/x + c)**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(S(2)*a*x*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))**S(2)) + (S(20)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4) + S(3)*b*c*x*(-S(6)*a*c + b**S(2)))/(S(2)*a**S(2)*x*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) - (S(30)*a**S(2)*c**S(2) - S(21)*a*b**S(2)*c + S(3)*b**S(4))/(a**S(3)*x*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*b*log(x)/a**S(4) + S(3)*b*log(a + b*x + c*x**S(2))/(S(2)*a**S(4)) - (-S(60)*a**S(3)*c**S(3) + S(90)*a**S(2)*b**S(2)*c**S(2) - S(30)*a*b**S(4)*c + S(3)*b**S(6))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(4)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(S(15) + S(13)/x + S(2)/x**S(2)), x), x, x**S(3)/S(45) - S(13)*x**S(2)/S(450) + S(139)*x/S(3375) - S(16)*log(S(3)*x + S(2))/S(567) + log(S(5)*x + S(1))/S(4375), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(S(15) + S(13)/x + S(2)/x**S(2)), x), x, x**S(2)/S(30) - S(13)*x/S(225) + S(8)*log(S(3)*x + S(2))/S(189) - log(S(5)*x + S(1))/S(875), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(S(15) + S(13)/x + S(2)/x**S(2)), x), x, x/S(15) - S(4)*log(S(3)*x + S(2))/S(63) + log(S(5)*x + S(1))/S(175), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(S(15) + S(13)/x + S(2)/x**S(2))), x), x, S(2)*log(S(3)*x + S(2))/S(21) - log(S(5)*x + S(1))/S(35), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(S(15) + S(13)/x + S(2)/x**S(2))), x), x, -log(S(3) + S(2)/x)/S(7) + log(S(5) + S(1)/x)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(S(15) + S(13)/x + S(2)/x**S(2))), x), x, log(x)/S(2) + S(3)*log(S(3)*x + S(2))/S(14) - S(5)*log(S(5)*x + S(1))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(S(15) + S(13)/x + S(2)/x**S(2))), x), x, -S(13)*log(x)/S(4) - S(9)*log(S(3)*x + S(2))/S(28) + S(25)*log(S(5)*x + S(1))/S(7) - S(1)/(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(S(15) + S(13)/x + S(2)/x**S(2))), x), x, S(139)*log(x)/S(8) + S(27)*log(S(3)*x + S(2))/S(56) - S(125)*log(S(5)*x + S(1))/S(7) + S(13)/(S(4)*x) - S(1)/(S(4)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*(S(15) + S(13)/x + S(2)/x**S(2))), x), x, -S(1417)*log(x)/S(16) - S(81)*log(S(3)*x + S(2))/S(112) + S(625)*log(S(5)*x + S(1))/S(7) - S(139)/(S(8)*x) + S(13)/(S(8)*x**S(2)) - S(1)/(S(6)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x + c/x**S(2))**(S(5)/2), x), x, S(5)*a**(S(3)/2)*b*atanh((S(2)*a + b/x)/(S(2)*sqrt(a)*sqrt(a + b/x + c/x**S(2))))/S(2) + x*(a + b/x + c/x**S(2))**(S(5)/2) - S(5)*(S(7)*b + S(6)*c/x)*(a + b/x + c/x**S(2))**(S(3)/2)/S(24) - S(5)*(b*(S(44)*a*c + b**S(2)) + S(2)*c*(S(12)*a*c + b**S(2))/x)*sqrt(a + b/x + c/x**S(2))/(S(64)*c) + (-S(240)*a**S(2)*c**S(2) - S(120)*a*b**S(2)*c + S(5)*b**S(4))*atanh((b + S(2)*c/x)/(S(2)*sqrt(c)*sqrt(a + b/x + c/x**S(2))))/(S(128)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x + c/x**S(2))**(S(3)/2), x), x, S(3)*sqrt(a)*b*atanh((S(2)*a + b/x)/(S(2)*sqrt(a)*sqrt(a + b/x + c/x**S(2))))/S(2) + x*(a + b/x + c/x**S(2))**(S(3)/2) - S(3)*(S(3)*b + S(2)*c/x)*sqrt(a + b/x + c/x**S(2))/S(4) - (S(12)*a*c + S(3)*b**S(2))*atanh((b + S(2)*c/x)/(S(2)*sqrt(c)*sqrt(a + b/x + c/x**S(2))))/(S(8)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b/x + c/x**S(2)), x), x, -sqrt(c)*atanh((b + S(2)*c/x)/(S(2)*sqrt(c)*sqrt(a + b/x + c/x**S(2)))) + x*sqrt(a + b/x + c/x**S(2)) + b*atanh((S(2)*a + b/x)/(S(2)*sqrt(a)*sqrt(a + b/x + c/x**S(2))))/(S(2)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b/x + c/x**S(2)), x), x, x*sqrt(a + b/x + c/x**S(2))/a - b*atanh((S(2)*a + b/x)/(S(2)*sqrt(a)*sqrt(a + b/x + c/x**S(2))))/(S(2)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x + c/x**S(2))**(S(-3)/2), x), x, -x*(-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c/x)/(a*(-S(4)*a*c + b**S(2))*sqrt(a + b/x + c/x**S(2))) + x*(-S(8)*a*c + S(3)*b**S(2))*sqrt(a + b/x + c/x**S(2))/(a**S(2)*(-S(4)*a*c + b**S(2))) - S(3)*b*atanh((S(2)*a + b/x)/(S(2)*sqrt(a)*sqrt(a + b/x + c/x**S(2))))/(S(2)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b/x + c/x**S(2))**(S(-5)/2), x), x, -x*(-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c/x)/(S(3)*a*(-S(4)*a*c + b**S(2))*(a + b/x + c/x**S(2))**(S(3)/2)) - x*(S(64)*a**S(2)*c**S(2) - S(64)*a*b**S(2)*c + S(10)*b**S(4) + S(2)*b*c*(-S(28)*a*c + S(5)*b**S(2))/x)/(S(3)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b/x + c/x**S(2))) + x*sqrt(a + b/x + c/x**S(2))*(S(128)*a**S(2)*c**S(2) - S(100)*a*b**S(2)*c + S(15)*b**S(4))/(S(3)*a**S(3)*(-S(4)*a*c + b**S(2))**S(2)) - S(5)*b*atanh((S(2)*a + b/x)/(S(2)*sqrt(a)*sqrt(a + b/x + c/x**S(2))))/(S(2)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b/x + b**S(2)/x**S(2)), x), x, a*x*sqrt(a**S(2) + S(2)*a*b/x + b**S(2)/x**S(2))/(a + b/x) + b*sqrt(a**S(2) + S(2)*a*b/x + b**S(2)/x**S(2))*log(x)/(a + b/x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a/x**S(4) + b/x**S(2) + c), x), x, x/c - sqrt(S(2))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a/x**S(6) + b/x**S(3) + c), x), x, x/c - S(2)**(S(2)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a/x**S(8) + b/x**S(4) + c), x), x, x/c + S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*sqrt(x) + c*x)/x, x), x, -S(2)*sqrt(a)*atanh((S(2)*a + b*sqrt(x))/(S(2)*sqrt(a)*sqrt(a + b*sqrt(x) + c*x))) + b*atanh((b + S(2)*c*sqrt(x))/(S(2)*sqrt(c)*sqrt(a + b*sqrt(x) + c*x)))/sqrt(c) + S(2)*sqrt(a + b*sqrt(x) + c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b**S(2)/(S(4)*c) + b*sqrt(x) + c*x)**S(2), x), x, -b*(b + S(2)*c*sqrt(x))**S(5)/(S(160)*c**S(4)) + (b + S(2)*c*sqrt(x))**S(6)/(S(192)*c**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a**S(2) + S(2)*a*b*sqrt(x) + b**S(2)*x), x), x, -S(2)*a*(a + b*sqrt(x))*log(a + b*sqrt(x))/(b**S(2)*sqrt(a**S(2) + S(2)*a*b*sqrt(x) + b**S(2)*x)) + S(2)*sqrt(a**S(2) + S(2)*a*b*sqrt(x) + b**S(2)*x)/b**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p, x), x, x*(d*x)**m*(S(1) + b*x**(S(1)/3)/a)**(-S(2)*p)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p*hyper((S(3)*m + S(3), -S(2)*p), (S(3)*m + S(4),), -b*x**(S(1)/3)/a)/(m + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p, x), x, S(3)*a**S(8)*(a + b*x**(S(1)/3))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(9)*(S(2)*p + S(1))) - S(12)*a**S(7)*(a*b + b**S(2)*x**(S(1)/3))**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(11)*(p + S(1))) + S(84)*a**S(6)*(a*b + b**S(2)*x**(S(1)/3))**S(3)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(12)*(S(2)*p + S(3))) - S(84)*a**S(5)*(a*b + b**S(2)*x**(S(1)/3))**S(4)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(13)*(p + S(2))) + S(210)*a**S(4)*(a*b + b**S(2)*x**(S(1)/3))**S(5)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(14)*(S(2)*p + S(5))) - S(84)*a**S(3)*(a*b + b**S(2)*x**(S(1)/3))**S(6)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(15)*(p + S(3))) + S(84)*a**S(2)*(a*b + b**S(2)*x**(S(1)/3))**S(7)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(16)*(S(2)*p + S(7))) - S(12)*a*(a*b + b**S(2)*x**(S(1)/3))**S(8)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(17)*(p + S(4))) + S(3)*(a*b + b**S(2)*x**(S(1)/3))**S(9)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(18)*(S(2)*p + S(9))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p, x), x, -S(3)*a**S(5)*(a + b*x**(S(1)/3))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(6)*(S(2)*p + S(1))) + S(15)*a**S(4)*(a*b + b**S(2)*x**(S(1)/3))**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(S(2)*b**S(8)*(p + S(1))) - S(30)*a**S(3)*(a*b + b**S(2)*x**(S(1)/3))**S(3)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(9)*(S(2)*p + S(3))) + S(15)*a**S(2)*(a*b + b**S(2)*x**(S(1)/3))**S(4)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(10)*(p + S(2))) - S(15)*a*(a*b + b**S(2)*x**(S(1)/3))**S(5)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(b**S(11)*(S(2)*p + S(5))) + S(3)*(a*b + b**S(2)*x**(S(1)/3))**S(6)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(S(2)*b**S(12)*(p + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/x, x), x, -(S(3)*a + S(3)*b*x**(S(1)/3))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p*hyper((S(1), S(2)*p + S(1)), (S(2)*p + S(2),), S(1) + b*x**(S(1)/3)/a)/(a*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/x**S(2), x), x, (S(3)*a*b**S(3) + S(3)*b**S(4)*x**(S(1)/3))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p*hyper((S(4), S(2)*p + S(1)), (S(2)*p + S(2),), S(1) + b*x**(S(1)/3)/a)/(a**S(4)*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/x**S(2) - S(2)*b**S(3)*p*(-S(2)*p + S(1))*(-p + S(1))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(S(3)*a**S(3)*x), x), x, -(a + b*x**(S(1)/3))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(a*x) + b*(a + b*x**(S(1)/3))*(-p + S(1))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(a**S(2)*x**(S(2)/3)) - b**S(2)*(a + b*x**(S(1)/3))*(-S(2)*p + S(1))*(-p + S(1))*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**p/(a**S(3)*x**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/4) + b**S(2)*sqrt(x))**(S(-3)/2), x), x, -S(12)*a*(a + b*x**(S(1)/4))*log(a + b*x**(S(1)/4))/(b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/4) + b**S(2)*sqrt(x))) - x**(S(3)/4)*(S(2)*a + S(2)*b*x**(S(1)/4))/(b*(a**S(2) + S(2)*a*b*x**(S(1)/4) + b**S(2)*sqrt(x))**(S(3)/2)) - S(6)*sqrt(x)/(b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/4) + b**S(2)*sqrt(x))) + S(12)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/4) + b**S(2)*sqrt(x))/b**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/6) + b**S(2)*x**(S(1)/3))**(S(-5)/2), x), x, -S(30)*a*(a + b*x**(S(1)/6))*log(a + b*x**(S(1)/6))/(b**S(6)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/6) + b**S(2)*x**(S(1)/3))) - x**(S(5)/6)*(S(3)*a + S(3)*b*x**(S(1)/6))/(S(2)*b*(a**S(2) + S(2)*a*b*x**(S(1)/6) + b**S(2)*x**(S(1)/3))**(S(5)/2)) - S(5)*x**(S(2)/3)/(S(2)*b**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/6) + b**S(2)*x**(S(1)/3))**(S(3)/2)) - sqrt(x)*(S(5)*a + S(5)*b*x**(S(1)/6))/(b**S(3)*(a**S(2) + S(2)*a*b*x**(S(1)/6) + b**S(2)*x**(S(1)/3))**(S(3)/2)) - S(15)*x**(S(1)/3)/(b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/6) + b**S(2)*x**(S(1)/3))) + S(30)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/6) + b**S(2)*x**(S(1)/3))/b**S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b/sqrt(x) + b**S(2)/x)**(S(3)/2), x), x, -S(6)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b/sqrt(x) + b**S(2)/x)*log(S(1)/sqrt(x))/(a + b/sqrt(x)) - S(6)*b**S(2)*sqrt(a**S(2) + S(2)*a*b/sqrt(x) + b**S(2)/x) + S(3)*b*sqrt(x)*(a + b/sqrt(x))*sqrt(a**S(2) + S(2)*a*b/sqrt(x) + b**S(2)/x) + x*(a**S(2) + S(2)*a*b/sqrt(x) + b**S(2)/x)**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(7)/2), x), x, -S(105)*a**S(4)*b**S(3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))*log(x**(S(-1)/3))/(a + b/x**(S(1)/3)) - S(105)*a**S(3)*b**S(3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3)) - S(105)*a**S(2)*b**S(3)*(a + b/x**(S(1)/3))*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))/S(2) - S(35)*a*b**S(3)*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(3)/2) - S(105)*b**S(3)*(a + b/x**(S(1)/3))*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(3)/2)/S(4) + S(21)*b**S(2)*x**(S(1)/3)*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(5)/2) + S(7)*b*x**(S(2)/3)*(a + b/x**(S(1)/3))*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(5)/2)/S(2) + x*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(7)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(5)/2), x), x, -S(30)*a**S(2)*b**S(3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))*log(x**(S(-1)/3))/(a + b/x**(S(1)/3)) - S(30)*a*b**S(3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3)) - S(15)*b**S(3)*(a + b/x**(S(1)/3))*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3)) + S(10)*b**S(2)*x**(S(1)/3)*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(3)/2) + S(5)*b*x**(S(2)/3)*(a + b/x**(S(1)/3))*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(3)/2)/S(2) + x*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(3)/2), x), x, S(3)*a*b**S(2)*x**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))/(a + b/x**(S(1)/3)) - S(3)*b**S(3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))*log(x**(S(-1)/3))/(a + b/x**(S(1)/3)) + S(3)*b*x**(S(2)/3)*(a + b/x**(S(1)/3))*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))/S(2) + x*(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3)), x), x, -a*x*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))/(S(2)*a + S(2)*b/x**(S(1)/3)) + S(3)*x*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3)), x), x, x*(a + b/x**(S(1)/3))/(a*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))) - S(3)*b*x**(S(2)/3)*(a + b/x**(S(1)/3))/(S(2)*a**S(2)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))) + S(3)*b**S(2)*x**(S(1)/3)*(a + b/x**(S(1)/3))/(a**S(3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))) - S(3)*b**S(3)*(a + b/x**(S(1)/3))*log(a*x**(S(1)/3) + b)/(a**S(4)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3)), x), x, x*(a + b/x**(S(1)/3))/(a*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))) - S(3)*b*x**(S(2)/3)*(a + b/x**(S(1)/3))/(S(2)*a**S(2)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))) + S(3)*b**S(3)*(a + b/x**(S(1)/3))*log(x**(S(-1)/3))/(a**S(4)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))) - S(3)*b**S(3)*(a + b/x**(S(1)/3))*log(a + b/x**(S(1)/3))/(a**S(4)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))) + S(3)*b**S(2)*x**(S(1)/3)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/3) + b**S(2)/x**(S(2)/3))/a**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(-3)/2), x), x, -x**(S(2)/3)*(S(3)*a + S(3)*b*x**(S(1)/3))/(S(2)*b*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(3)/2)) - S(3)*x**(S(1)/3)/(b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))) + (S(3)*a + S(3)*b*x**(S(1)/3))*log(a + b*x**(S(1)/3))/(b**S(3)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(-5)/2), x), x, x*(S(3)*a + S(3)*b*x**(S(1)/3))/(S(4)*a*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(5)/2)) + x/(S(4)*a**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(-7)/2), x), x, -x**(S(2)/3)*(a + b*x**(S(1)/3))/(S(2)*b*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(7)/2)) - x**(S(1)/3)/(S(5)*b**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(5)/2)) - (a + b*x**(S(1)/3))/(S(20)*b**S(3)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(-9)/2), x), x, -x**(S(2)/3)*(S(3)*a + S(3)*b*x**(S(1)/3))/(S(8)*b*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(9)/2)) - S(3)*x**(S(1)/3)/(S(28)*b**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(7)/2)) - (a + b*x**(S(1)/3))/(S(56)*b**S(3)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(-11)/2), x), x, -x**(S(2)/3)*(S(3)*a + S(3)*b*x**(S(1)/3))/(S(10)*b*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(11)/2)) - x**(S(1)/3)/(S(15)*b**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(9)/2)) - (a + b*x**(S(1)/3))/(S(120)*b**S(3)*(a**S(2) + S(2)*a*b*x**(S(1)/3) + b**S(2)*x**(S(2)/3))**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b/x**(S(1)/4) + b**S(2)/sqrt(x))**(S(5)/2), x), x, -S(20)*a*b**S(4)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/4) + b**S(2)/sqrt(x))*log(x**(S(-1)/4))/(a + b/x**(S(1)/4)) - S(20)*b**S(4)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/4) + b**S(2)/sqrt(x)) + S(10)*b**S(3)*x**(S(1)/4)*(a + b/x**(S(1)/4))*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/4) + b**S(2)/sqrt(x)) + S(10)*b**S(2)*sqrt(x)*(a**S(2) + S(2)*a*b/x**(S(1)/4) + b**S(2)/sqrt(x))**(S(3)/2)/S(3) + S(5)*b*x**(S(3)/4)*(a + b/x**(S(1)/4))*(a**S(2) + S(2)*a*b/x**(S(1)/4) + b**S(2)/sqrt(x))**(S(3)/2)/S(3) + x*(a**S(2) + S(2)*a*b/x**(S(1)/4) + b**S(2)/sqrt(x))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b/x**(S(1)/5) + b**S(2)/x**(S(2)/5))**(S(5)/2), x), x, S(5)*a*b**S(4)*x**(S(1)/5)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/5) + b**S(2)/x**(S(2)/5))/(a + b/x**(S(1)/5)) - S(5)*b**S(5)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/5) + b**S(2)/x**(S(2)/5))*log(x**(S(-1)/5))/(a + b/x**(S(1)/5)) + S(5)*b**S(3)*x**(S(2)/5)*(a + b/x**(S(1)/5))*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/5) + b**S(2)/x**(S(2)/5))/S(2) + S(5)*b**S(2)*x**(S(3)/5)*(a**S(2) + S(2)*a*b/x**(S(1)/5) + b**S(2)/x**(S(2)/5))**(S(3)/2)/S(3) + S(5)*b*x**(S(4)/5)*(a + b/x**(S(1)/5))*(a**S(2) + S(2)*a*b/x**(S(1)/5) + b**S(2)/x**(S(2)/5))**(S(3)/2)/S(4) + x*(a**S(2) + S(2)*a*b/x**(S(1)/5) + b**S(2)/x**(S(2)/5))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(S(1)/5) + b**S(2)*x**(S(2)/5))**(S(-5)/2), x), x, -x**(S(4)/5)*(S(5)*a + S(5)*b*x**(S(1)/5))/(S(4)*b*(a**S(2) + S(2)*a*b*x**(S(1)/5) + b**S(2)*x**(S(2)/5))**(S(5)/2)) - S(5)*x**(S(3)/5)/(S(3)*b**S(2)*(a**S(2) + S(2)*a*b*x**(S(1)/5) + b**S(2)*x**(S(2)/5))**(S(3)/2)) - x**(S(2)/5)*(S(5)*a + S(5)*b*x**(S(1)/5))/(S(2)*b**S(3)*(a**S(2) + S(2)*a*b*x**(S(1)/5) + b**S(2)*x**(S(2)/5))**(S(3)/2)) - S(5)*x**(S(1)/5)/(b**S(4)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/5) + b**S(2)*x**(S(2)/5))) + (S(5)*a + S(5)*b*x**(S(1)/5))*log(a + b*x**(S(1)/5))/(b**S(5)*sqrt(a**S(2) + S(2)*a*b*x**(S(1)/5) + b**S(2)*x**(S(2)/5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3))**(S(7)/2), x), x, -S(42)*a*b**S(6)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3))*log(x**(S(-1)/6))/(a + b/x**(S(1)/6)) - S(42)*b**S(6)*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3)) + S(21)*b**S(5)*x**(S(1)/6)*(a + b/x**(S(1)/6))*sqrt(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3)) + S(7)*b**S(4)*x**(S(1)/3)*(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3))**(S(3)/2) + S(7)*b**S(3)*sqrt(x)*(a + b/x**(S(1)/6))*(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3))**(S(3)/2)/S(2) + S(21)*b**S(2)*x**(S(2)/3)*(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3))**(S(5)/2)/S(10) + S(7)*b*x**(S(5)/6)*(a + b/x**(S(1)/6))*(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3))**(S(5)/2)/S(5) + x*(a**S(2) + S(2)*a*b/x**(S(1)/6) + b**S(2)/x**(S(1)/3))**(S(7)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(4)*n + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, b**S(2)*log(b + c*x**n)/(c**S(3)*n) - b*x**n/(c**S(2)*n) + x**(S(2)*n)/(S(2)*c*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)*n + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -b*log(b + c*x**n)/(c**S(2)*n) + x**n/(c*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, log(b + c*x**n)/(c*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, log(x)/b - log(b + c*x**n)/(b*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -x**(-S(2)*n)/(S(2)*b*n) + c*x**(-n)/(b**S(2)*n) + c**S(2)*log(x)/b**S(3) - c**S(2)*log(b + c*x**n)/(b**S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-S(2)*n + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -x**(-S(3)*n)/(S(3)*b*n) + c*x**(-S(2)*n)/(S(2)*b**S(2)*n) - c**S(2)*x**(-n)/(b**S(3)*n) - c**S(3)*log(x)/b**S(4) + c**S(3)*log(b + c*x**n)/(b**S(4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-S(3)*n + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -x**(-S(4)*n)/(S(4)*b*n) + c*x**(-S(3)*n)/(S(3)*b**S(2)*n) - c**S(2)*x**(-S(2)*n)/(S(2)*b**S(3)*n) + c**S(3)*x**(-n)/(b**S(4)*n) + c**S(4)*log(x)/b**S(5) - c**S(4)*log(b + c*x**n)/(b**S(5)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(4) + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -S(4)*x**(-S(3)*n/S(4))/(S(3)*b*n) + sqrt(S(2))*c**(S(3)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*x**(n/S(4)) + sqrt(b) + sqrt(c)*x**(n/S(2)))/(S(2)*b**(S(7)/4)*n) - sqrt(S(2))*c**(S(3)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*x**(n/S(4)) + sqrt(b) + sqrt(c)*x**(n/S(2)))/(S(2)*b**(S(7)/4)*n) + sqrt(S(2))*c**(S(3)/4)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*x**(n/S(4))/b**(S(1)/4))/(b**(S(7)/4)*n) - sqrt(S(2))*c**(S(3)/4)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*x**(n/S(4))/b**(S(1)/4))/(b**(S(7)/4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(3) + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -S(3)*x**(-S(2)*n/S(3))/(S(2)*b*n) - c**(S(2)/3)*log(b**(S(1)/3) + c**(S(1)/3)*x**(n/S(3)))/(b**(S(5)/3)*n) + c**(S(2)/3)*log(b**(S(2)/3) - b**(S(1)/3)*c**(S(1)/3)*x**(n/S(3)) + c**(S(2)/3)*x**(S(2)*n/S(3)))/(S(2)*b**(S(5)/3)*n) + sqrt(S(3))*c**(S(2)/3)*atan(sqrt(S(3))*(b**(S(1)/3) - S(2)*c**(S(1)/3)*x**(n/S(3)))/(S(3)*b**(S(1)/3)))/(b**(S(5)/3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(2) + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -S(2)*x**(-n/S(2))/(b*n) + S(2)*sqrt(c)*atan(sqrt(b)*x**(-n/S(2))/sqrt(c))/(b**(S(3)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n/S(2) + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -S(2)*x**(-S(3)*n/S(2))/(S(3)*b*n) + S(2)*c*x**(-n/S(2))/(b**S(2)*n) - S(2)*c**(S(3)/2)*atan(sqrt(b)*x**(-n/S(2))/sqrt(c))/(b**(S(5)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n/S(3) + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -S(3)*x**(-S(4)*n/S(3))/(S(4)*b*n) + S(3)*c*x**(-n/S(3))/(b**S(2)*n) - c**(S(4)/3)*log(b**(S(1)/3)*x**(-n/S(3)) + c**(S(1)/3))/(b**(S(7)/3)*n) + c**(S(4)/3)*log(b**(S(2)/3)*x**(-S(2)*n/S(3)) - b**(S(1)/3)*c**(S(1)/3)*x**(-n/S(3)) + c**(S(2)/3))/(S(2)*b**(S(7)/3)*n) + sqrt(S(3))*c**(S(4)/3)*atan(sqrt(S(3))*(-S(2)*b**(S(1)/3)*x**(-n/S(3)) + c**(S(1)/3))/(S(3)*c**(S(1)/3)))/(b**(S(7)/3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n/S(4) + S(-1))/(b*x**n + c*x**(S(2)*n)), x), x, -S(4)*x**(-S(5)*n/S(4))/(S(5)*b*n) + S(4)*c*x**(-n/S(4))/(b**S(2)*n) + sqrt(S(2))*c**(S(5)/4)*log(-sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*x**(-n/S(4)) + sqrt(b)*x**(-n/S(2)) + sqrt(c))/(S(2)*b**(S(9)/4)*n) - sqrt(S(2))*c**(S(5)/4)*log(sqrt(S(2))*b**(S(1)/4)*c**(S(1)/4)*x**(-n/S(4)) + sqrt(b)*x**(-n/S(2)) + sqrt(c))/(S(2)*b**(S(9)/4)*n) - sqrt(S(2))*c**(S(5)/4)*atan(sqrt(S(2))*b**(S(1)/4)*x**(-n/S(4))/c**(S(1)/4) + S(-1))/(b**(S(9)/4)*n) - sqrt(S(2))*c**(S(5)/4)*atan(sqrt(S(2))*b**(S(1)/4)*x**(-n/S(4))/c**(S(1)/4) + S(1))/(b**(S(9)/4)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n*(p + S(-1)) + S(-1))*(b*x**n + c*x**(S(2)*n))**p, x), x, x**(-n*(p + S(1)))*(b*x**n + c*x**(S(2)*n))**(p + S(1))/(c*n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n*(S(2)*p + S(1)) + S(-1))*(b*x**n + c*x**(S(2)*n))**p, x), x, -x**(-S(2)*n*(p + S(1)))*(b*x**n + c*x**(S(2)*n))**(p + S(1))/(b*n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**p, x), x, -a*(a + b*x**n)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**p/(b**S(2)*n*(S(2)*p + S(1))) + (a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(p + S(1))/(S(2)*b**S(2)*n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(5)/2), x), x, -a*(a + b*x**n)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(5)/2)/(S(6)*b**S(2)*n) + (a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(7)/2)/(S(7)*b**S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, -a*(a + b*x**n)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)/(S(4)*b**S(2)*n) + (a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(5)/2)/(S(5)*b**S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, a*x**(S(2)*n)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(6)*n*(a + b*x**n)) + x**(S(2)*n)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))/sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, -a*(a + b*x**n)*log(a + b*x**n)/(b**S(2)*n*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))) + sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(b**S(2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, x**(S(2)*n)*(a + b*x**n)/(S(2)*a*n*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(5)/2), x), x, a*(a + b*x**n)/(S(4)*b**S(2)*n*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(5)/2)) - S(1)/(S(3)*b**S(2)*n*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(7)/2), x), x, a*(a + b*x**n)/(S(6)*b**S(2)*n*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(7)/2)) - S(1)/(S(5)*b**S(2)*n*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, a*n*(d*x)**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(d*(a + b*x**n)*(m + S(1))*(m + n + S(1))) + (d*x)**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(d*(m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, a*n*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((a + b*x**n)*(S(3)*n + S(9))) + x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(n + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, a*n*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((a + b*x**n)*(S(2)*n + S(4))) + x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(n + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, a*n*x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((a + b*x**n)*(n + S(1))) + x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/x, x), x, a*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))*log(x)/(a + b*x**n) + sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/x**S(2), x), x, a*n*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(x*(a + b*x**n)*(-n + S(1))) - sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(x*(-n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/x**S(3), x), x, a*n*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(x**S(2)*(a + b*x**n)*(-S(2)*n + S(4))) - sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(x**S(2)*(-n + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, a**S(3)*(d*x)**(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(d*(a + b*x**n)*(m + S(1))) + S(3)*a**S(2)*b**S(2)*x**(n + S(1))*(d*x)**m*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((a*b + b**S(2)*x**n)*(m + n + S(1))) + S(3)*a*b**S(3)*x**(S(2)*n + S(1))*(d*x)**m*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((a*b + b**S(2)*x**n)*(m + S(2)*n + S(1))) + b**S(4)*x**(S(3)*n + S(1))*(d*x)**m*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((a*b + b**S(2)*x**n)*(m + S(3)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, a**S(3)*x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(3)*a + S(3)*b*x**n) + S(3)*a**S(2)*b**S(2)*x**(n + S(3))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((n + S(3))*(a*b + b**S(2)*x**n)) + S(3)*a*b**S(3)*x**(S(2)*n + S(3))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((S(2)*n + S(3))*(a*b + b**S(2)*x**n)) + b**S(4)*x**(S(3)*n + S(3))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((S(3)*n + S(3))*(a*b + b**S(2)*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, a**S(3)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(2)*a + S(2)*b*x**n) + S(3)*a**S(2)*b**S(2)*x**(n + S(2))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((n + S(2))*(a*b + b**S(2)*x**n)) + S(3)*a*b**S(3)*x**(S(2)*n + S(2))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((S(2)*n + S(2))*(a*b + b**S(2)*x**n)) + b**S(4)*x**(S(3)*n + S(2))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((S(3)*n + S(2))*(a*b + b**S(2)*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, S(6)*a**S(3)*n**S(3)*x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((a + b*x**n)*(S(6)*n**S(3) + S(11)*n**S(2) + S(6)*n + S(1))) + S(6)*a**S(2)*n**S(2)*x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(6)*n**S(3) + S(11)*n**S(2) + S(6)*n + S(1)) + S(3)*n*x*(a**S(2) + a*b*x**n)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(6)*n**S(2) + S(5)*n + S(1)) + x*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)/(S(3)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)/x, x), x, a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))*log(x)/(a + b*x**n) + a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/n + (a**S(2) + a*b*x**n)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(2)*n) + (a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)/(S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)/x**S(2), x), x, -a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(x*(a + b*x**n)) - S(3)*a**S(2)*b**S(2)*x**(n + S(-1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((-n + S(1))*(a*b + b**S(2)*x**n)) - S(3)*a*b**S(3)*x**(S(2)*n + S(-1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((-S(2)*n + S(1))*(a*b + b**S(2)*x**n)) - b**S(4)*x**(S(3)*n + S(-1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((-S(3)*n + S(1))*(a*b + b**S(2)*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)/x**S(3), x), x, -a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/(S(2)*x**S(2)*(a + b*x**n)) - S(3)*a**S(2)*b**S(2)*x**(n + S(-2))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((-n + S(2))*(a*b + b**S(2)*x**n)) - S(3)*a*b**S(3)*x**(S(2)*n + S(-2))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((-S(2)*n + S(2))*(a*b + b**S(2)*x**n)) - b**S(4)*x**(S(3)*n + S(-2))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))/((-S(3)*n + S(2))*(a*b + b**S(2)*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, (d*x)**(m + S(1))*(a + b*x**n)*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -b*x**n/a)/(a*d*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, x**S(3)*(a + b*x**n)*hyper((S(1), S(3)/n), ((n + S(3))/n,), -b*x**n/a)/(S(3)*a*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, x**S(2)*(a + b*x**n)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -b*x**n/a)/(S(2)*a*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n)), x), x, x*(a + b*x**n)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -b*x**n/a)/(a*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), x), x, (a + b*x**n)*log(x)/(a*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))) - (a + b*x**n)*log(a + b*x**n)/(a*n*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), x), x, -(a + b*x**n)*hyper((S(1), -S(1)/n), (-(-n + S(1))/n,), -b*x**n/a)/(a*x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), x), x, -(a + b*x**n)*hyper((S(1), -S(2)/n), (-(-n + S(2))/n,), -b*x**n/a)/(S(2)*a*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, (d*x)**(m + S(1))*(a + b*x**n)*hyper((S(3), (m + S(1))/n), ((m + n + S(1))/n,), -b*x**n/a)/(a**S(3)*d*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, x**S(3)*(a + b*x**n)*hyper((S(3), S(3)/n), ((n + S(3))/n,), -b*x**n/a)/(S(3)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2), x), x, x**S(2)*(a + b*x**n)*hyper((S(3), S(2)/n), ((n + S(2))/n,), -b*x**n/a)/(S(2)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(-3)/2), x), x, x*(a + b*x**n)*hyper((S(3), S(1)/n), (S(1) + S(1)/n,), -b*x**n/a)/(a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)), x), x, (a + b*x**n)/(S(2)*a*n*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)) + S(1)/(a**S(2)*n*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))) + (a + b*x**n)*log(x)/(a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))) - (a + b*x**n)*log(a + b*x**n)/(a**S(3)*n*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)), x), x, -(a + b*x**n)*hyper((S(3), -S(1)/n), (-(-n + S(1))/n,), -b*x**n/a)/(a**S(3)*x*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(3)/2)), x), x, -(a + b*x**n)*hyper((S(3), -S(2)/n), (-(-n + S(2))/n,), -b*x**n/a)/(S(2)*a**S(3)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(-S(1)/(S(2)*p + S(1))) + b**S(2)*x**(-S(2)/(S(2)*p + S(1))))**p, x), x, x*(a + b*x**(S(1)/(-S(2)*p + S(-1))))*(a**S(2) + S(2)*a*b*x**(S(1)/(-S(2)*p + S(-1))) + b**S(2)*x**(-S(2)/(S(2)*p + S(1))))**p/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**((-n + S(-1))/(S(2)*n)), x), x, x*(a + b*x**n)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(-(n + S(1))/(S(2)*n))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**(-S(1)/(S(2)*p + S(2))) + b**S(2)*x**(-S(1)/(p + S(1))))**p, x), x, x*(a + b*x**(-S(1)/(S(2)*p + S(2))))*(S(2)*p + S(2))*(a**S(2) + S(2)*a*b*x**(-S(1)/(S(2)*p + S(2))) + b**S(2)*x**(-S(1)/(p + S(1))))**p/(a*(S(2)*p + S(1))) - x*(a**S(2) + S(2)*a*b*x**(-S(1)/(S(2)*p + S(2))) + b**S(2)*x**(-S(1)/(p + S(1))))**(p + S(1))/(a**S(2)*(S(2)*p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**((-S(2)*n + S(-1))/(S(2)*n)), x), x, x*(a + b*x**n)*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(S(-1) - S(1)/(S(2)*n))/(a*(n + S(1))) + n*x*(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n))**(-S(1)/(S(2)*n))/(a**S(2)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(4)*n + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -b*x**n/(c**S(2)*n) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*n*sqrt(-S(4)*a*c + b**S(2))) + x**(S(2)*n)/(S(2)*c*n) + (-a*c + b**S(2))*log(a + b*x**n + c*x**(S(2)*n))/(S(2)*c**S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)*n + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -b*log(a + b*x**n + c*x**(S(2)*n))/(S(2)*c**S(2)*n) + x**n/(c*n) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(2)*n*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(2)*n + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, b*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(c*n*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*x**n + c*x**(S(2)*n))/(S(2)*c*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(n*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -x**(-n)/(a*n) - b*log(x)/a**S(2) + b*log(a + b*x**n + c*x**(S(2)*n))/(S(2)*a**S(2)*n) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(2)*n*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-S(2)*n + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -x**(-S(2)*n)/(S(2)*a*n) + b*x**(-n)/(a**S(2)*n) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*n*sqrt(-S(4)*a*c + b**S(2))) + (-a*c + b**S(2))*log(x)/a**S(3) - (-a*c + b**S(2))*log(a + b*x**n + c*x**(S(2)*n))/(S(2)*a**S(3)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-S(3)*n + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -x**(-S(3)*n)/(S(3)*a*n) + b*x**(-S(2)*n)/(S(2)*a**S(2)*n) - x**(-n)*(-a*c + b**S(2))/(a**S(3)*n) - b*(-S(2)*a*c + b**S(2))*log(x)/a**S(4) + b*(-S(2)*a*c + b**S(2))*log(a + b*x**n + c*x**(S(2)*n))/(S(2)*a**S(4)*n) - (S(2)*a**S(2)*c**S(2) - S(4)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(4)*n*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(4) + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*S(2)**(S(3)/4)*c**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x**(n/S(4))/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(n*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) - S(2)*S(2)**(S(3)/4)*c**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x**(n/S(4))/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(n*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)*S(2)**(S(3)/4)*c**(S(3)/4)*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x**(n/S(4))/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(n*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))) + S(2)*S(2)**(S(3)/4)*c**(S(3)/4)*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x**(n/S(4))/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(n*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(3) + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x**(n/S(3)) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(n*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**(S(2)*n/S(3)) - S(2)**(S(1)/3)*c**(S(1)/3)*x**(n/S(3))*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(2)*n*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x**(n/S(3))/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(n*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(1)/3)*c**(S(1)/3)*x**(n/S(3)) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(n*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(2)/3)*c**(S(2)/3)*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**(S(2)*n/S(3)) - S(2)**(S(1)/3)*c**(S(1)/3)*x**(n/S(3))*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(2)*n*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))) - S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x**(n/S(3))/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(n*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(2) + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x**(n/S(2))/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(n*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x**(n/S(2))/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(n*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n/S(2) + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*x**(-n/S(2))/(a*n) + sqrt(S(2))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(a)*x**(-n/S(2))/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(a**(S(3)/2)*n*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(a)*x**(-n/S(2))/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(a**(S(3)/2)*n*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n/S(3) + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(3)*x**(-n/S(3))/(a*n) + S(2)**(S(2)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*a**(S(1)/3)*x**(-n/S(3)) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(2)*a**(S(4)/3)*n*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*a**(S(2)/3)*x**(-S(2)*n/S(3)) - S(2)**(S(1)/3)*a**(S(1)/3)*x**(-n/S(3))*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(4)*a**(S(4)/3)*n*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*a**(S(1)/3)*x**(-n/S(3))/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(2)*a**(S(4)/3)*n*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*a**(S(1)/3)*x**(-n/S(3)) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(2)*a**(S(4)/3)*n*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*a**(S(2)/3)*x**(-S(2)*n/S(3)) - S(2)**(S(1)/3)*a**(S(1)/3)*x**(-n/S(3))*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(4)*a**(S(4)/3)*n*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*a**(S(1)/3)*x**(-n/S(3))/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(2)*a**(S(4)/3)*n*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(-n/S(4) + S(-1))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(4)*x**(-n/S(4))/(a*n) - S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*a**(S(1)/4)*x**(-n/S(4))/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(a**(S(5)/4)*n*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*a**(S(1)/4)*x**(-n/S(4))/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(a**(S(5)/4)*n*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*a**(S(1)/4)*x**(-n/S(4))/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(a**(S(5)/4)*n*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*a**(S(1)/4)*x**(-n/S(4))/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(a**(S(5)/4)*n*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*x**S(3)*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(12)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*x**S(3)*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(12)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**n + c*x**(S(2)*n)), x), x, -c*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - c*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**n + c*x**(S(2)*n))), x), x, b*atanh((b + S(2)*c*x**n)/sqrt(-S(4)*a*c + b**S(2)))/(a*n*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a + b*x**n + c*x**(S(2)*n))/(S(2)*a*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**n + c*x**(S(2)*n))), x), x, S(2)*c*hyper((S(1), -S(1)/n), (-(-n + S(1))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(x*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) + S(2)*c*hyper((S(1), -S(1)/n), (-(-n + S(1))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(x*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**n + c*x**(S(2)*n))), x), x, c*hyper((S(1), -S(2)/n), (-(-n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(x**S(2)*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) + c*hyper((S(1), -S(2)/n), (-(-n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(x**S(2)*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x**S(4)*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(4)/n, S(-1)/2, S(-1)/2, (n + S(4))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x**S(3)*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(3)/n, S(-1)/2, S(-1)/2, (n + S(3))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x**S(2)*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(2)/n, S(-1)/2, S(-1)/2, (n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(1)/n, S(-1)/2, S(-1)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**n + c*x**(S(2)*n))/x**S(2), x), x, -sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(-S(1)/n, S(-1)/2, S(-1)/2, -(-n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(x*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**n + c*x**(S(2)*n))/x**S(3), x), x, -sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(-S(2)/n, S(-1)/2, S(-1)/2, -(-n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*x**S(2)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, a*x**S(4)*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(4)/n, S(-3)/2, S(-3)/2, (n + S(4))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, a*x**S(3)*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(3)/n, S(-3)/2, S(-3)/2, (n + S(3))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, a*x**S(2)*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(2)/n, S(-3)/2, S(-3)/2, (n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, a*x*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(1)/n, S(-3)/2, S(-3)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**n + c*x**(S(2)*n))**(S(3)/2)/x**S(2), x), x, -a*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(-S(1)/n, S(-3)/2, S(-3)/2, -(-n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(x*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**n + c*x**(S(2)*n))**(S(3)/2)/x**S(3), x), x, -a*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(-S(2)/n, S(-3)/2, S(-3)/2, -(-n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*x**S(2)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x**S(4)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(4)/n, S(1)/2, S(1)/2, (n + S(4))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x**S(3)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/n, S(1)/2, S(1)/2, (n + S(3))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x**S(2)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(2)/n, S(1)/2, S(1)/2, (n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, x*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/n, S(1)/2, S(1)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/sqrt(a + b*x**n + c*x**(S(2)*n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, x**S(3)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/n, S(3)/2, S(3)/2, (n + S(3))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, x**S(2)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(2)/n, S(3)/2, S(3)/2, (n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**n + c*x**(S(2)*n))**(S(-3)/2), x), x, x*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/n, S(3)/2, S(3)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2)), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**n + c*x**(S(2)*n))) - atanh((S(2)*a + b*x**n)/(S(2)*sqrt(a)*sqrt(a + b*x**n + c*x**(S(2)*n))))/(a**(S(3)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2)), x), x, -sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(-S(1)/n, S(3)/2, S(3)/2, -(-n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*x*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2)), x), x, -sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(-S(2)/n, S(3)/2, S(3)/2, -(-n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*x**S(2)*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a + b*x**n + c*x**(S(2)*n))), x), x, -sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(-S(1)/n, S(1)/2, S(1)/2, -(-n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(x*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*sqrt(a + b*x**n + c*x**(S(2)*n))), x), x, -sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(-S(2)/n, S(1)/2, S(1)/2, -(-n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*x**S(2)*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, x**S(4)*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(4)/n, S(3)/2, S(3)/2, (n + S(4))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, a*(d*x)**(m + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1((m + S(1))/n, S(-3)/2, S(-3)/2, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, (d*x)**(m + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1((m + S(1))/n, S(-1)/2, S(-1)/2, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, (d*x)**(m + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1((m + S(1))/n, S(1)/2, S(1)/2, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, (d*x)**(m + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1((m + S(1))/n, S(3)/2, S(3)/2, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*d*(m + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x, (d*x)**(m + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1((m + S(1))/n, -p, -p, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a + b*(d + e*x)**S(3) + c*(d + e*x)**S(6)), x), x, -d*(d + e*x)*sqrt(S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/3, S(1)/2, S(1)/2, S(4)/3, -S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(e**S(2)*sqrt(a + b*(d + e*x)**S(3) + c*(d + e*x)**S(6))) + (d + e*x)**S(2)*sqrt(S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(2)/3, S(1)/2, S(1)/2, S(5)/3, -S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*e**S(2)*sqrt(a + b*(d + e*x)**S(3) + c*(d + e*x)**S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a + b*(d + e*x)**S(3) + c*(d + e*x)**S(6)), x), x, d**S(2)*(d + e*x)*sqrt(S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/3, S(1)/2, S(1)/2, S(4)/3, -S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(e**S(3)*sqrt(a + b*(d + e*x)**S(3) + c*(d + e*x)**S(6))) - d*(d + e*x)**S(2)*sqrt(S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(2)/3, S(1)/2, S(1)/2, S(5)/3, -S(2)*c*(d + e*x)**S(3)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*(d + e*x)**S(3)/(b + sqrt(-S(4)*a*c + b**S(2))))/(e**S(3)*sqrt(a + b*(d + e*x)**S(3) + c*(d + e*x)**S(6))) + atanh((b + S(2)*c*(d + e*x)**S(3))/(S(2)*sqrt(c)*sqrt(a + b*(d + e*x)**S(3) + c*(d + e*x)**S(6))))/(S(3)*sqrt(c)*e**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**n + c*x**(S(2)*n))/x, x), x, -sqrt(a)*atanh((S(2)*a + b*x**n)/(S(2)*sqrt(a)*sqrt(a + b*x**n + c*x**(S(2)*n))))/n + b*atanh((b + S(2)*c*x**n)/(S(2)*sqrt(c)*sqrt(a + b*x**n + c*x**(S(2)*n))))/(S(2)*sqrt(c)*n) + sqrt(a + b*x**n + c*x**(S(2)*n))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**n + c*x**(S(2)*n))**(S(3)/2)/x, x), x, -a**(S(3)/2)*atanh((S(2)*a + b*x**n)/(S(2)*sqrt(a)*sqrt(a + b*x**n + c*x**(S(2)*n))))/n - b*(-S(12)*a*c + b**S(2))*atanh((b + S(2)*c*x**n)/(S(2)*sqrt(c)*sqrt(a + b*x**n + c*x**(S(2)*n))))/(S(16)*c**(S(3)/2)*n) + (a + b*x**n + c*x**(S(2)*n))**(S(3)/2)/(S(3)*n) + sqrt(a + b*x**n + c*x**(S(2)*n))*(S(8)*a*c + b**S(2) + S(2)*b*c*x**n)/(S(8)*c*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a + b*x**n + c*x**(S(2)*n))), x), x, -atanh((S(2)*a + b*x**n)/(S(2)*sqrt(a)*sqrt(a + b*x**n + c*x**(S(2)*n))))/(sqrt(a)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**S(3), x), x, a**S(3)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(3)*a**S(2)*b*x**(n + S(1))*(d*x)**m/(m + n + S(1)) + S(3)*a*x**(S(2)*n + S(1))*(d*x)**m*(a*c + b**S(2))/(m + S(2)*n + S(1)) + S(3)*b*c**S(2)*x**(S(5)*n + S(1))*(d*x)**m/(m + S(5)*n + S(1)) + b*x**(S(3)*n + S(1))*(d*x)**m*(S(6)*a*c + b**S(2))/(m + S(3)*n + S(1)) + c**S(3)*x**(S(6)*n + S(1))*(d*x)**m/(m + S(6)*n + S(1)) + S(3)*c*x**(S(4)*n + S(1))*(d*x)**m*(a*c + b**S(2))/(m + S(4)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, a**S(2)*(d*x)**(m + S(1))/(d*(m + S(1))) + S(2)*a*b*x**(n + S(1))*(d*x)**m/(m + n + S(1)) + S(2)*b*c*x**(S(3)*n + S(1))*(d*x)**m/(m + S(3)*n + S(1)) + c**S(2)*x**(S(4)*n + S(1))*(d*x)**m/(m + S(4)*n + S(1)) + x**(S(2)*n + S(1))*(d*x)**m*(S(2)*a*c + b**S(2))/(m + S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m*(a + b*x**n + c*x**(S(2)*n)), x), x, a*(d*x)**(m + S(1))/(d*(m + S(1))) + b*x**(n + S(1))*(d*x)**m/(m + n + S(1)) + c*x**(S(2)*n + S(1))*(d*x)**m/(m + S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*(d*x)**(m + S(1))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(d*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*(d*x)**(m + S(1))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(d*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, -c*(d*x)**(m + S(1))*(S(4)*a*c*(m - S(2)*n + S(1)) - b**S(2)*(m - n + S(1)) + b*sqrt(-S(4)*a*c + b**S(2))*(m - n + S(1)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*d*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + c*(d*x)**(m + S(1))*(-b*(m - n + S(1)) + (S(4)*a*c*(m - S(2)*n + S(1)) - b**S(2)*(m - n + S(1)))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*d*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))) + (d*x)**(m + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*d*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**m/(a + b*x**n + c*x**(S(2)*n))**S(3), x), x, (d*x)**(m + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**n)/(S(2)*a*d*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))**S(2)) - c*(d*x)**(m + S(1))*(S(8)*a**S(2)*c**S(2)*(m**S(2) + m*(-S(6)*n + S(2)) + S(8)*n**S(2) - S(6)*n + S(1)) - S(6)*a*b**S(2)*c*(m**S(2) + m*(-S(4)*n + S(2)) + S(3)*n**S(2) - S(4)*n + S(1)) + b**S(4)*(m**S(2) + m*(-S(3)*n + S(2)) + S(2)*n**S(2) - S(3)*n + S(1)) + b*sqrt(-S(4)*a*c + b**S(2))*(S(2)*a*c*(S(2)*m - S(7)*n + S(2)) - b**S(2)*(m - S(2)*n + S(1)))*(m - n + S(1)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*d*n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(5)/2)) - c*(d*x)**(m + S(1))*(-S(8)*a**S(2)*c**S(2)*(m**S(2) + m*(-S(6)*n + S(2)) + S(8)*n**S(2) - S(6)*n + S(1)) + S(6)*a*b**S(2)*c*(m**S(2) + m*(-S(4)*n + S(2)) + S(3)*n**S(2) - S(4)*n + S(1)) - b**S(4)*(m**S(2) + m*(-S(3)*n + S(2)) + S(2)*n**S(2) - S(3)*n + S(1)) + b*sqrt(-S(4)*a*c + b**S(2))*(S(2)*a*c*(S(2)*m - S(7)*n + S(2)) - b**S(2)*(m - S(2)*n + S(1)))*(m - n + S(1)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*d*n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(5)/2)) - (d*x)**(m + S(1))*(S(4)*a**S(2)*c**S(2)*(m - S(4)*n + S(1)) - S(5)*a*b**S(2)*c*(m - S(3)*n + S(1)) + b**S(4)*(m - S(2)*n + S(1)) - b*c*x**n*(S(2)*a*c*(S(2)*m - S(7)*n + S(2)) - b**S(2)*(m - S(2)*n + S(1))))/(S(2)*a**S(2)*d*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, a*(d + e*x)**S(4)/(S(4)*e) + b*(d + e*x)**S(6)/(S(6)*e) + c*(d + e*x)**S(8)/(S(8)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, a**S(2)*(d + e*x)**S(4)/(S(4)*e) + a*b*(d + e*x)**S(6)/(S(3)*e) + b*c*(d + e*x)**S(10)/(S(5)*e) + c**S(2)*(d + e*x)**S(12)/(S(12)*e) + (d + e*x)**S(8)*(S(2)*a*c + b**S(2))/(S(8)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, a**S(3)*(d + e*x)**S(4)/(S(4)*e) + a**S(2)*b*(d + e*x)**S(6)/(S(2)*e) + S(3)*a*(d + e*x)**S(8)*(a*c + b**S(2))/(S(8)*e) + S(3)*b*c**S(2)*(d + e*x)**S(14)/(S(14)*e) + b*(d + e*x)**S(10)*(S(6)*a*c + b**S(2))/(S(10)*e) + c**S(3)*(d + e*x)**S(16)/(S(16)*e) + c*(d + e*x)**S(12)*(a*c + b**S(2))/(S(4)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, a*f**S(3)*(d + e*x)**S(4)/(S(4)*e) + b*f**S(3)*(d + e*x)**S(6)/(S(6)*e) + c*f**S(3)*(d + e*x)**S(8)/(S(8)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, a**S(2)*f**S(3)*(d + e*x)**S(4)/(S(4)*e) + a*b*f**S(3)*(d + e*x)**S(6)/(S(3)*e) + b*c*f**S(3)*(d + e*x)**S(10)/(S(5)*e) + c**S(2)*f**S(3)*(d + e*x)**S(12)/(S(12)*e) + f**S(3)*(d + e*x)**S(8)*(S(2)*a*c + b**S(2))/(S(8)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, a**S(3)*f**S(3)*(d + e*x)**S(4)/(S(4)*e) + a**S(2)*b*f**S(3)*(d + e*x)**S(6)/(S(2)*e) + S(3)*a*f**S(3)*(d + e*x)**S(8)*(a*c + b**S(2))/(S(8)*e) + S(3)*b*c**S(2)*f**S(3)*(d + e*x)**S(14)/(S(14)*e) + b*f**S(3)*(d + e*x)**S(10)*(S(6)*a*c + b**S(2))/(S(10)*e) + c**S(3)*f**S(3)*(d + e*x)**S(16)/(S(16)*e) + c*f**S(3)*(d + e*x)**S(12)*(a*c + b**S(2))/(S(4)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(4)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, x/c - sqrt(S(2))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, b*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*e*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*c*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, -sqrt(S(2))*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*e*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*e*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, -atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, b*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*e*sqrt(-S(4)*a*c + b**S(2))) + log(d + e*x)/(a*e) - log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - S(1)/(a*e*(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, -S(1)/(S(2)*a*e*(d + e*x)**S(2)) - b*log(d + e*x)/(a**S(2)*e) + b*log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(2)*e) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*e*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(4)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, -S(1)/(S(3)*a*e*(d + e*x)**S(3)) + b/(a**S(2)*e*(d + e*x)) + sqrt(S(2))*sqrt(c)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*sqrt(c)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(4)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, (S(2)*a + b*(d + e*x)**S(2))*(d + e*x)/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + sqrt(S(2))*(b - (S(4)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, -b*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (S(2)*a + b*(d + e*x)**S(2))/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, -sqrt(S(2))*sqrt(c)*(S(2)*b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(S(2)*b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (b + S(2)*c*(d + e*x)**S(2))*(d + e*x)/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, S(2)*c*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (-b - S(2)*c*(d + e*x)**S(2))/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**(S(-2)), x), x, -sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (d + e*x)*(-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*e*(-S(4)*a*c + b**S(2))**(S(3)/2)) + log(d + e*x)/(a**S(2)*e) - log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*(d + e*x)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) - (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) + (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-S(10)*a*c + S(3)*b**S(2))/(S(2)*a**S(2)*e*(d + e*x)*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - (-S(3)*a*c + b**S(2))/(a**S(2)*e*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))) - S(2)*b*log(d + e*x)/(a**S(3)*e) + b*log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(2)*a**S(3)*e) - (S(6)*a**S(2)*c**S(2) - S(6)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*e*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(4)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*(d + e*x)**S(3)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - (-S(14)*a*c + S(5)*b**S(2))/(S(6)*a**S(2)*e*(d + e*x)**S(3)*(-S(4)*a*c + b**S(2))) + b*(-S(19)*a*c + S(5)*b**S(2))/(S(2)*a**S(3)*e*(d + e*x)*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*sqrt(c)*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c + S(5)*b**S(4) - b*(-S(19)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c + S(5)*b**S(4) + b*(-S(19)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(4)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, -S(3)*sqrt(S(2))*sqrt(c)*(S(4)*a*c + S(3)*b**S(2) + S(2)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(8)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*sqrt(S(2))*sqrt(c)*(S(4)*a*c + S(3)*b**S(2) - S(2)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(8)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + (S(2)*a + b*(d + e*x)**S(2))*(d + e*x)/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) - (d + e*x)*(-S(4)*a*c + S(7)*b**S(2) + S(12)*b*c*(d + e*x)**S(2))/(S(8)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(3)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, S(3)*b*c*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*b*(b + S(2)*c*(d + e*x)**S(2))/(S(4)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + (S(2)*a + b*(d + e*x)**S(2))/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)**S(2)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, -(b + S(2)*c*(d + e*x)**S(2))*(d + e*x)/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + sqrt(S(2))*sqrt(c)*(S(20)*a*c + b**S(2) - b*(-S(52)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*sqrt(c)*(S(20)*a*c + b**S(2) + b*(-S(52)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + (d + e*x)*(b*(S(8)*a*c + b**S(2)) + c*(d + e*x)**S(2)*(S(20)*a*c + b**S(2)))/(S(8)*a*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, -S(6)*c**S(2)*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*c*(b + S(2)*c*(d + e*x)**S(2))/(S(2)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + (-b - S(2)*c*(d + e*x)**S(2))/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**(S(-3)), x), x, (d + e*x)*(-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(4)*a*e*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + S(3)*sqrt(S(2))*sqrt(c)*(-S(8)*a*b*c + b**S(3) - (S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + S(3)*sqrt(S(2))*sqrt(c)*(S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4) + b*(-S(8)*a*c + b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + (d + e*x)*(S(3)*b*c*(d + e*x)**S(2)*(-S(8)*a*c + b**S(2)) + (-S(7)*a*c + b**S(2))*(-S(4)*a*c + S(3)*b**S(2)))/(S(8)*a**S(2)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(4)*a*e*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + (S(16)*a**S(2)*c**S(2) - S(15)*a*b**S(2)*c + S(2)*b**S(4) + S(2)*b*c*(d + e*x)**S(2)*(-S(7)*a*c + b**S(2)))/(S(4)*a**S(2)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + b*(S(30)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*e*(-S(4)*a*c + b**S(2))**(S(5)/2)) + log(d + e*x)/(a**S(3)*e) - log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(3)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(4)*a*e*(d + e*x)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + (S(36)*a**S(2)*c**S(2) - S(35)*a*b**S(2)*c + S(5)*b**S(4) + b*c*(d + e*x)**S(2)*(-S(32)*a*c + S(5)*b**S(2)))/(S(8)*a**S(2)*e*(d + e*x)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - S(3)*sqrt(S(2))*sqrt(c)*((-S(12)*a*c + S(5)*b**S(2))*(-S(5)*a*c + b**S(2)) - (S(124)*a**S(2)*b*c**S(2) - S(47)*a*b**S(3)*c + S(5)*b**S(5))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(3)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*sqrt(S(2))*sqrt(c)*(b*(S(124)*a**S(2)*c**S(2) - S(47)*a*b**S(2)*c + S(5)*b**S(4))/sqrt(-S(4)*a*c + b**S(2)) + (-S(12)*a*c + S(5)*b**S(2))*(-S(5)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(3)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - (-S(36)*a*c + S(15)*b**S(2))*(-S(5)*a*c + b**S(2))/(S(8)*a**S(3)*e*(d + e*x)*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(4)*a*e*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + (S(20)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4) + S(3)*b*c*(d + e*x)**S(2)*(-S(6)*a*c + b**S(2)))/(S(4)*a**S(2)*e*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - (S(30)*a**S(2)*c**S(2) - S(21)*a*b**S(2)*c + S(3)*b**S(4))/(S(2)*a**S(3)*e*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*b*log(d + e*x)/(a**S(4)*e) + S(3)*b*log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(4)*e) - (-S(60)*a**S(3)*c**S(3) + S(90)*a**S(2)*b**S(2)*c**S(2) - S(30)*a*b**S(4)*c + S(3)*b**S(6))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(4)*e*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(4)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, f**S(4)*x/c - sqrt(S(2))*f**S(4)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*f**S(4)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(3)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, b*f**S(3)*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*e*sqrt(-S(4)*a*c + b**S(2))) + f**S(3)*log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*c*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(2)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, -sqrt(S(2))*f**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*e*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*f**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*e*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4)), x), x, -f*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, b*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*e*f*sqrt(-S(4)*a*c + b**S(2))) + log(d + e*x)/(a*e*f) - log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a*e*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*e*f**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*e*f**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - S(1)/(a*e*f**S(2)*(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, -S(1)/(S(2)*a*e*f**S(3)*(d + e*x)**S(2)) - b*log(d + e*x)/(a**S(2)*e*f**S(3)) + b*log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(2)*e*f**S(3)) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*e*f**S(3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(4)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), x), x, -S(1)/(S(3)*a*e*f**S(4)*(d + e*x)**S(3)) + b/(a**S(2)*e*f**S(4)*(d + e*x)) + sqrt(S(2))*sqrt(c)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*e*f**S(4)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*sqrt(c)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*e*f**S(4)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(4)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, f**S(4)*(S(2)*a + b*(d + e*x)**S(2))*(d + e*x)/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + sqrt(S(2))*f**S(4)*(b - (S(4)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*f**S(4)*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(3)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, -b*f**S(3)*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(3)/2)) + f**S(3)*(S(2)*a + b*(d + e*x)**S(2))/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(2)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, -sqrt(S(2))*sqrt(c)*f**S(2)*(S(2)*b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*f**S(2)*(S(2)*b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - f**S(2)*(b + S(2)*c*(d + e*x)**S(2))*(d + e*x)/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2), x), x, S(2)*c*f*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(3)/2)) - f*(b + S(2)*c*(d + e*x)**S(2))/(e*(-S(8)*a*c + S(2)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*f*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*e*f*(-S(4)*a*c + b**S(2))**(S(3)/2)) + log(d + e*x)/(a**S(2)*e*f) - log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(2)*e*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*f**S(2)*(d + e*x)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) - (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*e*f**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) + (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*e*f**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-S(10)*a*c + S(3)*b**S(2))/(S(2)*a**S(2)*e*f**S(2)*(d + e*x)*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*f**S(3)*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - (-S(3)*a*c + b**S(2))/(a**S(2)*e*f**S(3)*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))) - S(2)*b*log(d + e*x)/(a**S(3)*e*f**S(3)) + b*log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(2)*a**S(3)*e*f**S(3)) - (S(6)*a**S(2)*c**S(2) - S(6)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*e*f**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(4)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(2)*a*e*f**S(4)*(d + e*x)**S(3)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - (-S(14)*a*c + S(5)*b**S(2))/(S(6)*a**S(2)*e*f**S(4)*(d + e*x)**S(3)*(-S(4)*a*c + b**S(2))) + b*(-S(19)*a*c + S(5)*b**S(2))/(S(2)*a**S(3)*e*f**S(4)*(d + e*x)*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*sqrt(c)*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c + S(5)*b**S(4) - b*(-S(19)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*e*f**S(4)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c + S(5)*b**S(4) + b*(-S(19)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*e*f**S(4)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(4)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, -S(3)*sqrt(S(2))*sqrt(c)*f**S(4)*(S(4)*a*c + S(3)*b**S(2) + S(2)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(8)*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*sqrt(S(2))*sqrt(c)*f**S(4)*(S(4)*a*c + S(3)*b**S(2) - S(2)*b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(8)*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + f**S(4)*(S(2)*a + b*(d + e*x)**S(2))*(d + e*x)/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) - f**S(4)*(d + e*x)*(-S(4)*a*c + S(7)*b**S(2) + S(12)*b*c*(d + e*x)**S(2))/(S(8)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(3)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, S(3)*b*c*f**S(3)*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(5)/2)) - S(3)*b*f**S(3)*(b + S(2)*c*(d + e*x)**S(2))/(S(4)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + f**S(3)*(S(2)*a + b*(d + e*x)**S(2))/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)**S(2)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, -f**S(2)*(b + S(2)*c*(d + e*x)**S(2))*(d + e*x)/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + sqrt(S(2))*sqrt(c)*f**S(2)*(S(20)*a*c + b**S(2) - b*(-S(52)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*e*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*sqrt(c)*f**S(2)*(S(20)*a*c + b**S(2) + b*(-S(52)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*e*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + f**S(2)*(d + e*x)*(b*(S(8)*a*c + b**S(2)) + c*(d + e*x)**S(2)*(S(20)*a*c + b**S(2)))/(S(8)*a*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*f + e*f*x)/(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3), x), x, -S(6)*c**S(2)*f*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(e*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*c*f*(b + S(2)*c*(d + e*x)**S(2))/(S(2)*e*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - f*(b + S(2)*c*(d + e*x)**S(2))/(e*(-S(16)*a*c + S(4)*b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(4)*a*e*f*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + (S(16)*a**S(2)*c**S(2) - S(15)*a*b**S(2)*c + S(2)*b**S(4) + S(2)*b*c*(d + e*x)**S(2)*(-S(7)*a*c + b**S(2)))/(S(4)*a**S(2)*e*f*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) + b*(S(30)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*e*f*(-S(4)*a*c + b**S(2))**(S(5)/2)) + log(d + e*x)/(a**S(3)*e*f) - log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(3)*e*f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(4)*a*e*f**S(2)*(d + e*x)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + (S(36)*a**S(2)*c**S(2) - S(35)*a*b**S(2)*c + S(5)*b**S(4) + b*c*(d + e*x)**S(2)*(-S(32)*a*c + S(5)*b**S(2)))/(S(8)*a**S(2)*e*f**S(2)*(d + e*x)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - S(3)*sqrt(S(2))*sqrt(c)*((-S(12)*a*c + S(5)*b**S(2))*(-S(5)*a*c + b**S(2)) - (S(124)*a**S(2)*b*c**S(2) - S(47)*a*b**S(3)*c + S(5)*b**S(5))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(3)*e*f**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*sqrt(S(2))*sqrt(c)*(b*(S(124)*a**S(2)*c**S(2) - S(47)*a*b**S(2)*c + S(5)*b**S(4))/sqrt(-S(4)*a*c + b**S(2)) + (-S(12)*a*c + S(5)*b**S(2))*(-S(5)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*(d + e*x)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(3)*e*f**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - (-S(36)*a*c + S(15)*b**S(2))*(-S(5)*a*c + b**S(2))/(S(8)*a**S(3)*e*f**S(2)*(d + e*x)*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d*f + e*f*x)**S(3)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(3)), x), x, (-S(2)*a*c + b**S(2) + b*c*(d + e*x)**S(2))/(S(4)*a*e*f**S(3)*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))**S(2)) + (S(20)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4) + S(3)*b*c*(d + e*x)**S(2)*(-S(6)*a*c + b**S(2)))/(S(4)*a**S(2)*e*f**S(3)*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))) - (S(30)*a**S(2)*c**S(2) - S(21)*a*b**S(2)*c + S(3)*b**S(4))/(S(2)*a**S(3)*e*f**S(3)*(d + e*x)**S(2)*(-S(4)*a*c + b**S(2))**S(2)) - S(3)*b*log(d + e*x)/(a**S(4)*e*f**S(3)) + S(3)*b*log(a + b*(d + e*x)**S(2) + c*(d + e*x)**S(4))/(S(4)*a**S(4)*e*f**S(3)) - (-S(60)*a**S(3)*c**S(3) + S(90)*a**S(2)*b**S(2)*c**S(2) - S(30)*a*b**S(4)*c + S(3)*b**S(6))*atanh((b + S(2)*c*(d + e*x)**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(4)*e*f**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x + S(2))**S(6)*((S(3)*x + S(2))**S(14) + (S(3)*x + S(2))**S(7) + S(1)), x), x, (S(3)*x + S(2))**S(21)/S(63) + (S(3)*x + S(2))**S(14)/S(42) + (S(3)*x + S(2))**S(7)/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x + S(2))**S(6)*((S(3)*x + S(2))**S(14) + (S(3)*x + S(2))**S(7) + S(1))**S(2), x), x, (S(3)*x + S(2))**S(35)/S(105) + (S(3)*x + S(2))**S(28)/S(42) + (S(3)*x + S(2))**S(21)/S(21) + (S(3)*x + S(2))**S(14)/S(21) + (S(3)*x + S(2))**S(7)/S(21), expand=True, _diff=True, _numerical=True) def test_2(): assert rubi_test(rubi_integrate((c + d*x**S(2))/(a + b*x**S(4)), x), x, -sqrt(S(2))*(-sqrt(a)*d + sqrt(b)*c)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)) + sqrt(S(2))*(-sqrt(a)*d + sqrt(b)*c)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)) - sqrt(S(2))*(sqrt(a)*d + sqrt(b)*c)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)) + sqrt(S(2))*(sqrt(a)*d + sqrt(b)*c)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c - d*x**S(2))/(a + b*x**S(4)), x), x, -sqrt(S(2))*(-sqrt(a)*d + sqrt(b)*c)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)) + sqrt(S(2))*(-sqrt(a)*d + sqrt(b)*c)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(3)/4)*b**(S(3)/4)) - sqrt(S(2))*(sqrt(a)*d + sqrt(b)*c)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)) + sqrt(S(2))*(sqrt(a)*d + sqrt(b)*c)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(8)*a**(S(3)/4)*b**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c + d*x**S(2))/(a - b*x**S(4)), x), x, (-sqrt(a)*d + sqrt(b)*c)*atan(b**(S(1)/4)*x/a**(S(1)/4))/(S(2)*a**(S(3)/4)*b**(S(3)/4)) + (sqrt(a)*d + sqrt(b)*c)*atanh(b**(S(1)/4)*x/a**(S(1)/4))/(S(2)*a**(S(3)/4)*b**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c - d*x**S(2))/(a - b*x**S(4)), x), x, (-sqrt(a)*d + sqrt(b)*c)*atanh(b**(S(1)/4)*x/a**(S(1)/4))/(S(2)*a**(S(3)/4)*b**(S(3)/4)) + (sqrt(a)*d + sqrt(b)*c)*atan(b**(S(1)/4)*x/a**(S(1)/4))/(S(2)*a**(S(3)/4)*b**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) + S(2))/(S(9)*x**S(4) + S(4)), x), x, sqrt(S(3))*atan(sqrt(S(3))*x + S(-1))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*x + S(1))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*x**S(2) + S(2))/(S(9)*x**S(4) + S(4)), x), x, -sqrt(S(3))*log(S(3)*x**S(2) - S(2)*sqrt(S(3))*x + S(2))/S(12) + sqrt(S(3))*log(S(3)*x**S(2) + S(2)*sqrt(S(3))*x + S(2))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) + S(2))/(-S(9)*x**S(4) + S(4)), x), x, sqrt(S(6))*atanh(sqrt(S(6))*x/S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(3)*x**S(2) + S(2))/(-S(9)*x**S(4) + S(4)), x), x, sqrt(S(6))*atan(sqrt(S(6))*x/S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a)*sqrt(b) + b*x**S(2))/(a + b*x**S(4)), x), x, -sqrt(S(2))*b**(S(1)/4)*atan(S(1) - sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(2)*a**(S(1)/4)) + sqrt(S(2))*b**(S(1)/4)*atan(S(1) + sqrt(S(2))*b**(S(1)/4)*x/a**(S(1)/4))/(S(2)*a**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a)*sqrt(b) - b*x**S(2))/(a + b*x**S(4)), x), x, -sqrt(S(2))*b**(S(1)/4)*log(-sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(4)*a**(S(1)/4)) + sqrt(S(2))*b**(S(1)/4)*log(sqrt(S(2))*a**(S(1)/4)*b**(S(1)/4)*x + sqrt(a) + sqrt(b)*x**S(2))/(S(4)*a**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(d**S(2) + e**S(2)*x**S(4)), x), x, -sqrt(S(2))*atan(S(1) - sqrt(S(2))*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)) + sqrt(S(2))*atan(S(1) + sqrt(S(2))*sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d - e*x**S(2))/(d**S(2) + e**S(2)*x**S(4)), x), x, -sqrt(S(2))*log(-sqrt(S(2))*sqrt(d)*sqrt(e)*x + d + e*x**S(2))/(S(4)*sqrt(d)*sqrt(e)) + sqrt(S(2))*log(sqrt(S(2))*sqrt(d)*sqrt(e)*x + d + e*x**S(2))/(S(4)*sqrt(d)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(5))/(x**S(4) + S(-1)), x), x, -S(3)*atan(x)/S(2) - S(7)*atanh(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/sqrt(a + c*x**S(4)), x), x, -S(3)*a**(S(1)/4)*e*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-a*e**S(2) + S(5)*c*d**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(5)*c**(S(7)/4)*sqrt(a + c*x**S(4))) + a**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*a*e**S(3) + S(15)*c*d**S(2)*e + S(5)*sqrt(c)*d*(-a*e**S(2) + c*d**S(2))/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(10)*c**(S(7)/4)*sqrt(a + c*x**S(4))) + d*e**S(2)*x*sqrt(a + c*x**S(4))/c + e**S(3)*x**S(3)*sqrt(a + c*x**S(4))/(S(5)*c) + S(3)*e*x*sqrt(a + c*x**S(4))*(-a*e**S(2) + S(5)*c*d**S(2))/(S(5)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/sqrt(a + c*x**S(4)), x), x, -S(2)*a**(S(1)/4)*d*e*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(c**(S(3)/4)*sqrt(a + c*x**S(4))) + e**S(2)*x*sqrt(a + c*x**S(4))/(S(3)*c) + S(2)*d*e*x*sqrt(a + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))) + sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(6)*sqrt(a)*sqrt(c)*d*e - a*e**S(2) + S(3)*c*d**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(6)*a**(S(1)/4)*c**(S(5)/4)*sqrt(a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(a + c*x**S(4)), x), x, -a**(S(1)/4)*e*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(c**(S(3)/4)*sqrt(a + c*x**S(4))) + a**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*c**(S(3)/4)*sqrt(a + c*x**S(4))) + e*x*sqrt(a + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + c*x**S(4))*(d + e*x**S(2))), x), x, atan(x*sqrt(a*e/d + c*d/e)/sqrt(a + c*x**S(4)))/(S(2)*d*sqrt(a*e/d + c*d/e)) + c**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*sqrt(a + c*x**S(4))*(-sqrt(a)*e + sqrt(c)*d)) - sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_pi(-sqrt(a)*(-e + sqrt(c)*d/sqrt(a))**S(2)/(S(4)*sqrt(c)*d*e), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(4)*a**(S(1)/4)*c**(S(1)/4)*d*sqrt(a + c*x**S(4))*(-e + sqrt(c)*d/sqrt(a))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + c*x**S(4))*(d + e*x**S(2))**S(2)), x), x, a**(S(1)/4)*c**(S(1)/4)*e*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*d*sqrt(a + c*x**S(4))*(a*e**S(2) + c*d**S(2))) - a**(S(1)/4)*c**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(4)*d*sqrt(a + c*x**S(4))*(a*e**S(2) + c*d**S(2))) - a**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*(a*e**S(2) + S(3)*c*d**S(2))*elliptic_pi(-(-sqrt(a)*e + sqrt(c)*d)**S(2)/(S(4)*sqrt(a)*sqrt(c)*d*e), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(8)*c**(S(1)/4)*d**S(2)*sqrt(a + c*x**S(4))*(-sqrt(a)*e + sqrt(c)*d)*(a*e**S(2) + c*d**S(2))) - sqrt(c)*e*x*sqrt(a + c*x**S(4))/(S(2)*d*(sqrt(a) + sqrt(c)*x**S(2))*(a*e**S(2) + c*d**S(2))) + e**S(2)*x*sqrt(a + c*x**S(4))/(S(2)*d*(d + e*x**S(2))*(a*e**S(2) + c*d**S(2))) + (a*e**S(2) + S(3)*c*d**S(2))*atan(x*sqrt(a*e/d + c*d/e)/sqrt(a + c*x**S(4)))/(S(4)*d**S(3)*e*(a*e/d + c*d/e)**(S(3)/2)) + c**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(a*e**S(2) + S(3)*c*d**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(4)*a**(S(1)/4)*d*sqrt(a + c*x**S(4))*(-sqrt(a)*e + sqrt(c)*d)*(a*e**S(2) + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/sqrt(a - c*x**S(4)), x), x, S(3)*a**(S(3)/4)*e*sqrt(S(1) - c*x**S(4)/a)*(a*e**S(2) + S(5)*c*d**S(2))*elliptic_e(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(S(5)*c**(S(7)/4)*sqrt(a - c*x**S(4))) - a**(S(3)/4)*sqrt(S(1) - c*x**S(4)/a)*(S(3)*a*e**S(3) + S(15)*c*d**S(2)*e - S(5)*sqrt(c)*d*(a*e**S(2) + c*d**S(2))/sqrt(a))*elliptic_f(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(S(5)*c**(S(7)/4)*sqrt(a - c*x**S(4))) - d*e**S(2)*x*sqrt(a - c*x**S(4))/c - e**S(3)*x**S(3)*sqrt(a - c*x**S(4))/(S(5)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/sqrt(a - c*x**S(4)), x), x, S(2)*a**(S(3)/4)*d*e*sqrt(S(1) - c*x**S(4)/a)*elliptic_e(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(3)/4)*sqrt(a - c*x**S(4))) + a**(S(1)/4)*sqrt(S(1) - c*x**S(4)/a)*(-S(6)*sqrt(a)*sqrt(c)*d*e + a*e**S(2) + S(3)*c*d**S(2))*elliptic_f(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(S(3)*c**(S(5)/4)*sqrt(a - c*x**S(4))) - e**S(2)*x*sqrt(a - c*x**S(4))/(S(3)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(a - c*x**S(4)), x), x, a**(S(3)/4)*e*sqrt(S(1) - c*x**S(4)/a)*elliptic_e(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(3)/4)*sqrt(a - c*x**S(4))) + a**(S(3)/4)*sqrt(S(1) - c*x**S(4)/a)*(-e + sqrt(c)*d/sqrt(a))*elliptic_f(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(3)/4)*sqrt(a - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a - c*x**S(4))*(d + e*x**S(2))), x), x, a**(S(1)/4)*sqrt(S(1) - c*x**S(4)/a)*elliptic_pi(-sqrt(a)*e/(sqrt(c)*d), asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(1)/4)*d*sqrt(a - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a - c*x**S(4))*(d + e*x**S(2))**S(2)), x), x, -a**(S(3)/4)*c**(S(1)/4)*e*sqrt(S(1) - c*x**S(4)/a)*elliptic_e(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(S(2)*d*sqrt(a - c*x**S(4))*(-a*e**S(2) + c*d**S(2))) - a**(S(1)/4)*c**(S(1)/4)*sqrt(S(1) - c*x**S(4)/a)*elliptic_f(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(S(2)*d*sqrt(a - c*x**S(4))*(sqrt(a)*e + sqrt(c)*d)) + a**(S(1)/4)*sqrt(S(1) - c*x**S(4)/a)*(-a*e**S(2) + S(3)*c*d**S(2))*elliptic_pi(-sqrt(a)*e/(sqrt(c)*d), asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(S(2)*c**(S(1)/4)*d**S(2)*sqrt(a - c*x**S(4))*(-a*e**S(2) + c*d**S(2))) - e**S(2)*x*sqrt(a - c*x**S(4))/(S(2)*d*(d + e*x**S(2))*(-a*e**S(2) + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(-a + c*x**S(4)), x), x, a**(S(3)/4)*e*sqrt(S(1) - c*x**S(4)/a)*elliptic_e(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(3)/4)*sqrt(-a + c*x**S(4))) + a**(S(3)/4)*sqrt(S(1) - c*x**S(4)/a)*(-e + sqrt(c)*d/sqrt(a))*elliptic_f(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(3)/4)*sqrt(-a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(-a + c*x**S(4))*(d + e*x**S(2))), x), x, a**(S(1)/4)*sqrt(S(1) - c*x**S(4)/a)*elliptic_pi(-sqrt(a)*e/(sqrt(c)*d), asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(1)/4)*d*sqrt(-a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((sqrt(a) + sqrt(c)*x**S(2))/sqrt(-a + c*x**S(4)), x), x, a**(S(3)/4)*sqrt(S(1) - c*x**S(4)/a)*elliptic_e(asin(c**(S(1)/4)*x/a**(S(1)/4)), S(-1))/(c**(S(1)/4)*sqrt(-a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2)*sqrt(c/a) + S(1))/sqrt(-a + c*x**S(4)), x), x, sqrt(S(1) - c*x**S(4)/a)*elliptic_e(asin(x*(c/a)**(S(1)/4)), S(-1))/((c/a)**(S(1)/4)*sqrt(-a + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(-a - c*x**S(4)), x), x, -a**(S(1)/4)*e*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(c**(S(3)/4)*sqrt(-a - c*x**S(4))) + a**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*c**(S(3)/4)*sqrt(-a - c*x**S(4))) - e*x*sqrt(-a - c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(-a - c*x**S(4))*(d + e*x**S(2))), x), x, atan(x*sqrt(-a*e/d - c*d/e)/sqrt(-a - c*x**S(4)))/(S(2)*d*sqrt(-a*e/d - c*d/e)) + c**(S(1)/4)*sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(2)*a**(S(1)/4)*sqrt(-a - c*x**S(4))*(-sqrt(a)*e + sqrt(c)*d)) - sqrt((a + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_pi(-sqrt(a)*(-e + sqrt(c)*d/sqrt(a))**S(2)/(S(4)*sqrt(c)*d*e), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2)/(S(4)*a**(S(1)/4)*c**(S(1)/4)*d*sqrt(-a - c*x**S(4))*(-e + sqrt(c)*d/sqrt(a))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(2))*sqrt(-S(5)*x**S(4) + S(4))), x), x, sqrt(S(2))*S(5)**(S(3)/4)*elliptic_pi(-S(2)*sqrt(S(5))*b/(S(5)*a), asin(sqrt(S(2))*S(5)**(S(1)/4)*x/S(2)), S(-1))/(S(10)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(2))*sqrt(S(5)*x**S(4) + S(4))), x), x, sqrt(S(2))*S(5)**(S(1)/4)*sqrt((S(5)*x**S(4) + S(4))/(sqrt(S(5))*x**S(2) + S(2))**S(2))*(sqrt(S(5))*x**S(2) + S(2))*elliptic_f(S(2)*atan(sqrt(S(2))*S(5)**(S(1)/4)*x/S(2)), S(1)/2)/(S(4)*sqrt(S(5)*x**S(4) + S(4))*(sqrt(S(5))*a - S(2)*b)) - sqrt(S(2))*S(5)**(S(3)/4)*sqrt((S(5)*x**S(4) + S(4))/(sqrt(S(5))*x**S(2) + S(2))**S(2))*(sqrt(S(5))*a + S(2)*b)*(sqrt(S(5))*x**S(2) + S(2))*elliptic_pi(-sqrt(S(5))*(sqrt(S(5))*a - S(2)*b)**S(2)/(S(40)*a*b), S(2)*atan(sqrt(S(2))*S(5)**(S(1)/4)*x/S(2)), S(1)/2)/(S(40)*a*sqrt(S(5)*x**S(4) + S(4))*(sqrt(S(5))*a - S(2)*b)) + atan(x*sqrt(S(5)*a/b + S(4)*b/a)/sqrt(S(5)*x**S(4) + S(4)))/(S(2)*a*sqrt(S(5)*a/b + S(4)*b/a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(2))*sqrt(-d*x**S(4) + S(4))), x), x, sqrt(S(2))*elliptic_pi(-S(2)*b/(a*sqrt(d)), asin(sqrt(S(2))*d**(S(1)/4)*x/S(2)), S(-1))/(S(2)*a*d**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((a + b*x**S(2))*sqrt(d*x**S(4) + S(4))), x), x, -sqrt(S(2))*d**(S(1)/4)*sqrt((d*x**S(4) + S(4))/(sqrt(d)*x**S(2) + S(2))**S(2))*(sqrt(d)*x**S(2) + S(2))*elliptic_f(S(2)*atan(sqrt(S(2))*d**(S(1)/4)*x/S(2)), S(1)/2)/(S(4)*(-a*sqrt(d) + S(2)*b)*sqrt(d*x**S(4) + S(4))) + atan(x*sqrt(a*d/b + S(4)*b/a)/sqrt(d*x**S(4) + S(4)))/(S(2)*a*sqrt(a*d/b + S(4)*b/a)) + sqrt(S(2))*sqrt((d*x**S(4) + S(4))/(sqrt(d)*x**S(2) + S(2))**S(2))*(a*sqrt(d) + S(2)*b)*(sqrt(d)*x**S(2) + S(2))*elliptic_pi(-(-a*sqrt(d) + S(2)*b)**S(2)/(S(8)*a*b*sqrt(d)), S(2)*atan(sqrt(S(2))*d**(S(1)/4)*x/S(2)), S(1)/2)/(S(8)*a*d**(S(1)/4)*(-a*sqrt(d) + S(2)*b)*sqrt(d*x**S(4) + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x, elliptic_e(asin(c*x), S(-1))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c**S(2)*x**S(2) + S(1))/sqrt(-c**S(4)*x**S(4) + S(1)), x), x, elliptic_e(asin(c*x), S(-1))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x, -elliptic_e(asin(c*x), S(-1))/c + S(2)*elliptic_f(asin(c*x), S(-1))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-c**S(2)*x**S(2) + S(1))/sqrt(-c**S(4)*x**S(4) + S(1)), x), x, -elliptic_e(asin(c*x), S(-1))/c + S(2)*elliptic_f(asin(c*x), S(-1))/c, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + S(1))/sqrt(-b**S(2)*x**S(4) + S(1)), x), x, elliptic_e(asin(sqrt(b)*x), S(-1))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-b*x**S(2) + S(1))/sqrt(-b**S(2)*x**S(4) + S(1)), x), x, -elliptic_e(asin(sqrt(b)*x), S(-1))/sqrt(b) + S(2)*elliptic_f(asin(sqrt(b)*x), S(-1))/sqrt(b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + S(1))/sqrt(b**S(2)*x**S(4) + S(-1)), x), x, sqrt(-b**S(2)*x**S(4) + S(1))*elliptic_e(asin(sqrt(b)*x), S(-1))/(sqrt(b)*sqrt(b**S(2)*x**S(4) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-b*x**S(2) + S(1))/sqrt(b**S(2)*x**S(4) + S(-1)), x), x, -sqrt(-b**S(2)*x**S(4) + S(1))*elliptic_e(asin(sqrt(b)*x), S(-1))/(sqrt(b)*sqrt(b**S(2)*x**S(4) + S(-1))) + S(2)*sqrt(-b**S(2)*x**S(4) + S(1))*elliptic_f(asin(sqrt(b)*x), S(-1))/(sqrt(b)*sqrt(b**S(2)*x**S(4) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-b*x**S(2) + S(1))/sqrt(b**S(2)*x**S(4) + S(1)), x), x, -x*sqrt(b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1)) + sqrt((b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1))**S(2))*(b*x**S(2) + S(1))*elliptic_e(S(2)*atan(sqrt(b)*x), S(1)/2)/(sqrt(b)*sqrt(b**S(2)*x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + S(1))/sqrt(b**S(2)*x**S(4) + S(1)), x), x, x*sqrt(b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1)) - sqrt((b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1))**S(2))*(b*x**S(2) + S(1))*elliptic_e(S(2)*atan(sqrt(b)*x), S(1)/2)/(sqrt(b)*sqrt(b**S(2)*x**S(4) + S(1))) + sqrt((b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1))**S(2))*(b*x**S(2) + S(1))*elliptic_f(S(2)*atan(sqrt(b)*x), S(1)/2)/(sqrt(b)*sqrt(b**S(2)*x**S(4) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-b*x**S(2) + S(1))/sqrt(-b**S(2)*x**S(4) + S(-1)), x), x, x*sqrt(-b**S(2)*x**S(4) + S(-1))/(b*x**S(2) + S(1)) + sqrt((b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1))**S(2))*(b*x**S(2) + S(1))*elliptic_e(S(2)*atan(sqrt(b)*x), S(1)/2)/(sqrt(b)*sqrt(-b**S(2)*x**S(4) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b*x**S(2) + S(1))/sqrt(-b**S(2)*x**S(4) + S(-1)), x), x, -x*sqrt(-b**S(2)*x**S(4) + S(-1))/(b*x**S(2) + S(1)) - sqrt((b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1))**S(2))*(b*x**S(2) + S(1))*elliptic_e(S(2)*atan(sqrt(b)*x), S(1)/2)/(sqrt(b)*sqrt(-b**S(2)*x**S(4) + S(-1))) + sqrt((b**S(2)*x**S(4) + S(1))/(b*x**S(2) + S(1))**S(2))*(b*x**S(2) + S(1))*elliptic_f(S(2)*atan(sqrt(b)*x), S(1)/2)/(sqrt(b)*sqrt(-b**S(2)*x**S(4) + S(-1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(4)/(-d**S(2) + e**S(2)*x**S(4)), x), x, -S(8)*d**(S(5)/2)*atanh(sqrt(e)*x/sqrt(d))/sqrt(e) + S(7)*d**S(2)*x + S(4)*d*e*x**S(3)/S(3) + e**S(2)*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/(-d**S(2) + e**S(2)*x**S(4)), x), x, -S(4)*d**(S(3)/2)*atanh(sqrt(e)*x/sqrt(d))/sqrt(e) + S(3)*d*x + e*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/(-d**S(2) + e**S(2)*x**S(4)), x), x, -S(2)*sqrt(d)*atanh(sqrt(e)*x/sqrt(d))/sqrt(e) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(-d**S(2) + e**S(2)*x**S(4)), x), x, -atanh(sqrt(e)*x/sqrt(d))/(sqrt(d)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*(-d**S(2) + e**S(2)*x**S(4))), x), x, -x/(S(4)*d**S(2)*(d + e*x**S(2))) - atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(5)/2)*sqrt(e)) - atanh(sqrt(e)*x/sqrt(d))/(S(4)*d**(S(5)/2)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*(-d**S(2) + e**S(2)*x**S(4))), x), x, -x/(S(8)*d**S(2)*(d + e*x**S(2))**S(2)) - S(5)*x/(S(16)*d**S(3)*(d + e*x**S(2))) - S(7)*atan(sqrt(e)*x/sqrt(d))/(S(16)*d**(S(7)/2)*sqrt(e)) - atanh(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(7)/2)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)/(-d**S(2) + e**S(2)*x**S(4)), x), x, atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/sqrt(e) - sqrt(S(2))*atanh(sqrt(S(2))*sqrt(e)*x/sqrt(d + e*x**S(2)))/sqrt(e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(-d**S(2) + e**S(2)*x**S(4)), x), x, -sqrt(S(2))*atanh(sqrt(S(2))*sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*d*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d + e*x**S(2))*(-d**S(2) + e**S(2)*x**S(4))), x), x, -x/(S(2)*d**S(2)*sqrt(d + e*x**S(2))) - sqrt(S(2))*atanh(sqrt(S(2))*sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(4)*d**S(2)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**(S(3)/2)*(-d**S(2) + e**S(2)*x**S(4))), x), x, -x/(S(6)*d**S(2)*(d + e*x**S(2))**(S(3)/2)) - S(7)*x/(S(12)*d**S(3)*sqrt(d + e*x**S(2))) - sqrt(S(2))*atanh(sqrt(S(2))*sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(8)*d**S(3)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(4)/(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4)), x), x, e**S(2)*x**S(5)/(S(5)*c) + e*x**S(3)*(-b*e + S(4)*c*d)/(S(3)*c**S(2)) + x*(b**S(2)*e**S(2) - S(5)*b*c*d*e + S(7)*c**S(2)*d**S(2))/c**S(3) - (-b*e + S(2)*c*d)**S(3)*atanh(sqrt(c)*sqrt(e)*x/sqrt(-b*e + c*d))/(c**(S(7)/2)*sqrt(e)*sqrt(-b*e + c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4)), x), x, e*x**S(3)/(S(3)*c) + x*(-b*e + S(3)*c*d)/c**S(2) - (-b*e + S(2)*c*d)**S(2)*atanh(sqrt(c)*sqrt(e)*x/sqrt(-b*e + c*d))/(c**(S(5)/2)*sqrt(e)*sqrt(-b*e + c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4)), x), x, x/c - (-b*e + S(2)*c*d)*atanh(sqrt(c)*sqrt(e)*x/sqrt(-b*e + c*d))/(c**(S(3)/2)*sqrt(e)*sqrt(-b*e + c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4)), x), x, -atanh(sqrt(c)*sqrt(e)*x/sqrt(-b*e + c*d))/(sqrt(c)*sqrt(e)*sqrt(-b*e + c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4))), x), x, -c**(S(3)/2)*atanh(sqrt(c)*sqrt(e)*x/sqrt(-b*e + c*d))/(sqrt(e)*sqrt(-b*e + c*d)*(-b*e + S(2)*c*d)**S(2)) - x/(S(2)*d*(d + e*x**S(2))*(-b*e + S(2)*c*d)) - (-b*e + S(4)*c*d)*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*sqrt(e)*(-b*e + S(2)*c*d)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4))), x), x, -c**(S(5)/2)*atanh(sqrt(c)*sqrt(e)*x/sqrt(-b*e + c*d))/(sqrt(e)*sqrt(-b*e + c*d)*(-b*e + S(2)*c*d)**S(3)) - x/(S(4)*d*(d + e*x**S(2))**S(2)*(-b*e + S(2)*c*d)) - x*(-S(3)*b*e + S(10)*c*d)/(S(8)*d**S(2)*(d + e*x**S(2))*(-b*e + S(2)*c*d)**S(2)) - (S(3)*b**S(2)*e**S(2) - S(16)*b*c*d*e + S(28)*c**S(2)*d**S(2))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(5)/2)*sqrt(e)*(-b*e + S(2)*c*d)**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(5)/2)/(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4)), x), x, x*sqrt(d + e*x**S(2))/(S(2)*c) + (-S(2)*b*e + S(5)*c*d)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c**S(2)*sqrt(e)) - (-b*e + S(2)*c*d)**(S(3)/2)*atanh(sqrt(e)*x*sqrt(-b*e + S(2)*c*d)/(sqrt(d + e*x**S(2))*sqrt(-b*e + c*d)))/(c**S(2)*sqrt(e)*sqrt(-b*e + c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)/(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4)), x), x, atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(c*sqrt(e)) - sqrt(-b*e + S(2)*c*d)*atanh(sqrt(e)*x*sqrt(-b*e + S(2)*c*d)/(sqrt(d + e*x**S(2))*sqrt(-b*e + c*d)))/(c*sqrt(e)*sqrt(-b*e + c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4)), x), x, -atanh(sqrt(e)*x*sqrt(-b*e + S(2)*c*d)/(sqrt(d + e*x**S(2))*sqrt(-b*e + c*d)))/(sqrt(e)*sqrt(-b*e + c*d)*sqrt(-b*e + S(2)*c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d + e*x**S(2))*(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4))), x), x, -c*atanh(sqrt(e)*x*sqrt(-b*e + S(2)*c*d)/(sqrt(d + e*x**S(2))*sqrt(-b*e + c*d)))/(sqrt(e)*sqrt(-b*e + c*d)*(-b*e + S(2)*c*d)**(S(3)/2)) - x/(d*sqrt(d + e*x**S(2))*(-b*e + S(2)*c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**(S(3)/2)*(b*d*e + b*e**S(2)*x**S(2) - c*d**S(2) + c*e**S(2)*x**S(4))), x), x, -c**S(2)*atanh(sqrt(e)*x*sqrt(-b*e + S(2)*c*d)/(sqrt(d + e*x**S(2))*sqrt(-b*e + c*d)))/(sqrt(e)*sqrt(-b*e + c*d)*(-b*e + S(2)*c*d)**(S(5)/2)) - x/(S(3)*d*(d + e*x**S(2))**(S(3)/2)*(-b*e + S(2)*c*d)) - x*(-S(2)*b*e + S(7)*c*d)/(S(3)*d**S(2)*sqrt(d + e*x**S(2))*(-b*e + S(2)*c*d)**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(b*x**S(2) + d**S(2) + e**S(2)*x**S(4)), x), x, -atan((-S(2)*e*x + sqrt(-b + S(2)*d*e))/sqrt(b + S(2)*d*e))/sqrt(b + S(2)*d*e) + atan((S(2)*e*x + sqrt(-b + S(2)*d*e))/sqrt(b + S(2)*d*e))/sqrt(b + S(2)*d*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(-b*x**S(2) + d**S(2) + e**S(2)*x**S(4)), x), x, atanh((-S(2)*e*x + sqrt(b + S(2)*d*e))/sqrt(b - S(2)*d*e))/sqrt(b - S(2)*d*e) - atanh((S(2)*e*x + sqrt(b + S(2)*d*e))/sqrt(b - S(2)*d*e))/sqrt(b - S(2)*d*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(d**S(2) + e**S(2)*x**S(4) + f*x**S(2)), x), x, -atan((-S(2)*e*x + sqrt(S(2)*d*e - f))/sqrt(S(2)*d*e + f))/sqrt(S(2)*d*e + f) + atan((S(2)*e*x + sqrt(S(2)*d*e - f))/sqrt(S(2)*d*e + f))/sqrt(S(2)*d*e + f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(d**S(2) + e**S(2)*x**S(4) - f*x**S(2)), x), x, -atan((-S(2)*e*x + sqrt(S(2)*d*e + f))/sqrt(S(2)*d*e - f))/sqrt(S(2)*d*e - f) + atan((S(2)*e*x + sqrt(S(2)*d*e + f))/sqrt(S(2)*d*e - f))/sqrt(S(2)*d*e - f), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d - e*x**S(2))/(b*x**S(2) + d**S(2) + e**S(2)*x**S(4)), x), x, -log(d + e*x**S(2) - x*sqrt(-b + S(2)*d*e))/(S(2)*sqrt(-b + S(2)*d*e)) + log(d + e*x**S(2) + x*sqrt(-b + S(2)*d*e))/(S(2)*sqrt(-b + S(2)*d*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d - e*x**S(2))/(-b*x**S(2) + d**S(2) + e**S(2)*x**S(4)), x), x, -log(d + e*x**S(2) - x*sqrt(b + S(2)*d*e))/(S(2)*sqrt(b + S(2)*d*e)) + log(d + e*x**S(2) + x*sqrt(b + S(2)*d*e))/(S(2)*sqrt(b + S(2)*d*e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d - e*x**S(2))/(d**S(2) + e**S(2)*x**S(4) + f*x**S(2)), x), x, -log(d + e*x**S(2) - x*sqrt(S(2)*d*e - f))/(S(2)*sqrt(S(2)*d*e - f)) + log(d + e*x**S(2) + x*sqrt(S(2)*d*e - f))/(S(2)*sqrt(S(2)*d*e - f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d - e*x**S(2))/(d**S(2) + e**S(2)*x**S(4) - f*x**S(2)), x), x, -log(d + e*x**S(2) - x*sqrt(S(2)*d*e + f))/(S(2)*sqrt(S(2)*d*e + f)) + log(d + e*x**S(2) + x*sqrt(S(2)*d*e + f))/(S(2)*sqrt(S(2)*d*e + f)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d - e*x**S(2))/(b*x**S(2) + c*d**S(2)/e**S(2) + c*x**S(4)), x), x, -e**(S(3)/2)*log(sqrt(c)*d + sqrt(c)*e*x**S(2) - sqrt(e)*x*sqrt(-b*e + S(2)*c*d))/(S(2)*sqrt(c)*sqrt(-b*e + S(2)*c*d)) + e**(S(3)/2)*log(sqrt(c)*d + sqrt(c)*e*x**S(2) + sqrt(e)*x*sqrt(-b*e + S(2)*c*d))/(S(2)*sqrt(c)*sqrt(-b*e + S(2)*c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(b*x**S(2) + c*d**S(2)/e**S(2) + c*x**S(4)), x), x, -e**(S(3)/2)*atan((-S(2)*sqrt(c)*sqrt(e)*x + sqrt(-b*e + S(2)*c*d))/sqrt(b*e + S(2)*c*d))/(sqrt(c)*sqrt(b*e + S(2)*c*d)) + e**(S(3)/2)*atan((S(2)*sqrt(c)*sqrt(e)*x + sqrt(-b*e + S(2)*c*d))/sqrt(b*e + S(2)*c*d))/(sqrt(c)*sqrt(b*e + S(2)*c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(b*x**S(2) + c*(d**S(2)/e**S(2) + x**S(4))), x), x, -e**(S(3)/2)*atan((-S(2)*sqrt(c)*sqrt(e)*x + sqrt(-b*e + S(2)*c*d))/sqrt(b*e + S(2)*c*d))/(sqrt(c)*sqrt(b*e + S(2)*c*d)) + e**(S(3)/2)*atan((S(2)*sqrt(c)*sqrt(e)*x + sqrt(-b*e + S(2)*c*d))/sqrt(b*e + S(2)*c*d))/(sqrt(c)*sqrt(b*e + S(2)*c*d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a - b*x**S(2))/(a**S(2) + b**S(2)*x**S(4) + x**S(2)*(S(2)*a*b + S(-1))), x), x, -log(a + b*x**S(2) - x)/S(2) + log(a + b*x**S(2) + x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(a**S(2) + b**S(2)*x**S(4) + x**S(2)*(S(2)*a*b + S(-1))), x), x, atanh((-S(2)*b*x + S(1))/sqrt(-S(4)*a*b + S(1)))/sqrt(-S(4)*a*b + S(1)) - atanh((S(2)*b*x + S(1))/sqrt(-S(4)*a*b + S(1)))/sqrt(-S(4)*a*b + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(b*x**S(2) + S(4)*x**S(4) + S(1)), x), x, -atan((-S(4)*x + sqrt(-b + S(4)))/sqrt(b + S(4)))/sqrt(b + S(4)) + atan((S(4)*x + sqrt(-b + S(4)))/sqrt(b + S(4)))/sqrt(b + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(-b*x**S(2) + S(4)*x**S(4) + S(1)), x), x, -atan((-S(4)*x + sqrt(b + S(4)))/sqrt(-b + S(4)))/sqrt(-b + S(4)) + atan((S(4)*x + sqrt(b + S(4)))/sqrt(-b + S(4)))/sqrt(-b + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(6)*x**S(2) + S(1)), x), x, sqrt(S(10))*atan(S(2)*x/sqrt(-sqrt(S(5)) + S(3)))/S(10) + sqrt(S(10))*atan(S(2)*x/sqrt(sqrt(S(5)) + S(3)))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(5)*x**S(2) + S(1)), x), x, atan(x)/S(3) + atan(S(2)*x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(4)*x**S(2) + S(1)), x), x, sqrt(S(2))*atan(sqrt(S(2))*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(3)*x**S(2) + S(1)), x), x, -sqrt(S(7))*atan(sqrt(S(7))*(-S(4)*x + S(1))/S(7))/S(7) + sqrt(S(7))*atan(sqrt(S(7))*(S(4)*x + S(1))/S(7))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(2)*x**S(2) + S(1)), x), x, -sqrt(S(6))*atan(sqrt(S(6))*(-S(4)*x + sqrt(S(2)))/S(6))/S(6) + sqrt(S(6))*atan(sqrt(S(6))*(S(4)*x + sqrt(S(2)))/S(6))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + x**S(2) + S(1)), x), x, -sqrt(S(5))*atan(sqrt(S(5))*(-S(4)*x + sqrt(S(3)))/S(5))/S(5) + sqrt(S(5))*atan(sqrt(S(5))*(S(4)*x + sqrt(S(3)))/S(5))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(1)), x), x, atan(S(2)*x + S(-1))/S(2) + atan(S(2)*x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - x**S(2) + S(1)), x), x, -sqrt(S(3))*atan(sqrt(S(3))*(-S(4)*x + sqrt(S(5)))/S(3))/S(3) + sqrt(S(3))*atan(sqrt(S(3))*(S(4)*x + sqrt(S(5)))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(2)*x**S(2) + S(1)), x), x, -sqrt(S(2))*atan(sqrt(S(2))*(-S(4)*x + sqrt(S(6)))/S(2))/S(2) + sqrt(S(2))*atan(sqrt(S(2))*(S(4)*x + sqrt(S(6)))/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(3)*x**S(2) + S(1)), x), x, atan(S(4)*x - sqrt(S(7))) + atan(S(4)*x + sqrt(S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(4)*x**S(2) + S(1)), x), x, x/(-S(2)*x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(5)*x**S(2) + S(1)), x), x, -log(-S(2)*x**S(2) - x + S(1))/S(2) + log(-S(2)*x**S(2) + x + S(1))/S(2), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(5)*x**S(2) + S(1)), x), x, -log(-S(2)*x + S(1))/S(2) + log(-x + S(1))/S(2) - log(x + S(1))/S(2) + log(S(2)*x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(6)*x**S(2) + S(1)), x), x, -sqrt(S(10))*log(S(2)*x**S(2) - sqrt(S(10))*x + S(1))/S(20) + sqrt(S(10))*log(S(2)*x**S(2) + sqrt(S(10))*x + S(1))/S(20), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(6)*x**S(2) + S(1)), x), x, sqrt(S(2))*atanh(sqrt(S(2))*(-S(4)*x + sqrt(S(10)))/S(2))/S(2) - sqrt(S(2))*atanh(sqrt(S(2))*(S(4)*x + sqrt(S(10)))/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(b*x**S(2) + S(4)*x**S(4) + S(1)), x), x, -log(S(2)*x**S(2) - x*sqrt(-b + S(4)) + S(1))/(S(2)*sqrt(-b + S(4))) + log(S(2)*x**S(2) + x*sqrt(-b + S(4)) + S(1))/(S(2)*sqrt(-b + S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(6)*x**S(2) + S(1)), x), x, sqrt(S(2))*atan(S(2)*x/sqrt(-sqrt(S(5)) + S(3)))/S(2) - sqrt(S(2))*atan(S(2)*x/sqrt(sqrt(S(5)) + S(3)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(5)*x**S(2) + S(1)), x), x, -atan(x) + atan(S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(4)*x**S(2) + S(1)), x), x, x/(S(2)*x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(3)*x**S(2) + S(1)), x), x, -log(S(2)*x**S(2) - x + S(1))/S(2) + log(S(2)*x**S(2) + x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(2)*x**S(2) + S(1)), x), x, -sqrt(S(2))*log(S(2)*x**S(2) - sqrt(S(2))*x + S(1))/S(4) + sqrt(S(2))*log(S(2)*x**S(2) + sqrt(S(2))*x + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + x**S(2) + S(1)), x), x, -sqrt(S(3))*log(S(2)*x**S(2) - sqrt(S(3))*x + S(1))/S(6) + sqrt(S(3))*log(S(2)*x**S(2) + sqrt(S(3))*x + S(1))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) + S(1)), x), x, -log(S(2)*x**S(2) - S(2)*x + S(1))/S(4) + log(S(2)*x**S(2) + S(2)*x + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - x**S(2) + S(1)), x), x, -sqrt(S(5))*log(S(2)*x**S(2) - sqrt(S(5))*x + S(1))/S(10) + sqrt(S(5))*log(S(2)*x**S(2) + sqrt(S(5))*x + S(1))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(2)*x**S(2) + S(1)), x), x, -sqrt(S(6))*log(S(2)*x**S(2) - sqrt(S(6))*x + S(1))/S(12) + sqrt(S(6))*log(S(2)*x**S(2) + sqrt(S(6))*x + S(1))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(3)*x**S(2) + S(1)), x), x, -sqrt(S(7))*log(S(2)*x**S(2) - sqrt(S(7))*x + S(1))/S(14) + sqrt(S(7))*log(S(2)*x**S(2) + sqrt(S(7))*x + S(1))/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(4)*x**S(2) + S(1)), x), x, sqrt(S(2))*atanh(sqrt(S(2))*x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(5)*x**S(2) + S(1)), x), x, -log(S(2)*x**S(2) - S(3)*x + S(1))/S(6) + log(S(2)*x**S(2) + S(3)*x + S(1))/S(6), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(5)*x**S(2) + S(1)), x), x, atanh(x)/S(3) + atanh(S(2)*x)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(6)*x**S(2) + S(1)), x), x, -sqrt(S(10))*log(S(2)*x**S(2) - sqrt(S(10))*x + S(1))/S(20) + sqrt(S(10))*log(S(2)*x**S(2) + sqrt(S(10))*x + S(1))/S(20), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-S(2)*x**S(2) + S(1))/(S(4)*x**S(4) - S(6)*x**S(2) + S(1)), x), x, sqrt(S(10))*atanh(S(2)*x/sqrt(-sqrt(S(5)) + S(3)))/S(10) + sqrt(S(10))*atanh(S(2)*x/sqrt(sqrt(S(5)) + S(3)))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(b*x**S(2) + x**S(4) + S(1)), x), x, -atan((-S(2)*x + sqrt(-b + S(2)))/sqrt(b + S(2)))/sqrt(b + S(2)) + atan((S(2)*x + sqrt(-b + S(2)))/sqrt(b + S(2)))/sqrt(b + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) + S(5)*x**S(2) + S(1)), x), x, sqrt(S(7))*atan(x*sqrt(sqrt(S(21))/S(2) + S(5)/2))/S(7) + sqrt(S(7))*atan(sqrt(S(2))*x/sqrt(sqrt(S(21)) + S(5)))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) + S(4)*x**S(2) + S(1)), x), x, sqrt(S(6))*atan(x/sqrt(-sqrt(S(3)) + S(2)))/S(6) + sqrt(S(6))*atan(x/sqrt(sqrt(S(3)) + S(2)))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) + S(3)*x**S(2) + S(1)), x), x, sqrt(S(5))*atan(x*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(5) + sqrt(S(5))*atan(sqrt(S(2))*x/sqrt(sqrt(S(5)) + S(3)))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, atan(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) + x**S(2) + S(1)), x), x, -sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(3) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) + S(1)), x), x, sqrt(S(2))*atan(sqrt(S(2))*x + S(-1))/S(2) + sqrt(S(2))*atan(sqrt(S(2))*x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) - x**S(2) + S(1)), x), x, atan(S(2)*x - sqrt(S(3))) + atan(S(2)*x + sqrt(S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) - S(2)*x**S(2) + S(1)), x), x, x/(-x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) - S(3)*x**S(2) + S(1)), x), x, atanh(-S(2)*x + sqrt(S(5))) - atanh(S(2)*x + sqrt(S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) - S(4)*x**S(2) + S(1)), x), x, sqrt(S(2))*atanh(-sqrt(S(2))*x + sqrt(S(3)))/S(2) - sqrt(S(2))*atanh(sqrt(S(2))*x + sqrt(S(3)))/S(2), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) - S(4)*x**S(2) + S(1)), x), x, sqrt(S(2))*atanh(sqrt(S(2))*(-S(2)*x + sqrt(S(6)))/S(2))/S(2) - sqrt(S(2))*atanh(sqrt(S(2))*(S(2)*x + sqrt(S(6)))/S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))/(x**S(4) - S(5)*x**S(2) + S(1)), x), x, sqrt(S(3))*atanh(sqrt(S(3))*(-S(2)*x + sqrt(S(7)))/S(3))/S(3) - sqrt(S(3))*atanh(sqrt(S(3))*(S(2)*x + sqrt(S(7)))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(b*x**S(2) + x**S(4) + S(1)), x), x, -log(x**S(2) - x*sqrt(-b + S(2)) + S(1))/(S(2)*sqrt(-b + S(2))) + log(x**S(2) + x*sqrt(-b + S(2)) + S(1))/(S(2)*sqrt(-b + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) + S(5)*x**S(2) + S(1)), x), x, sqrt(S(3))*atan(x*sqrt(sqrt(S(21))/S(2) + S(5)/2))/S(3) - sqrt(S(3))*atan(sqrt(S(2))*x/sqrt(sqrt(S(21)) + S(5)))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) + S(4)*x**S(2) + S(1)), x), x, sqrt(S(2))*atan(x/sqrt(-sqrt(S(3)) + S(2)))/S(2) - sqrt(S(2))*atan(x/sqrt(sqrt(S(3)) + S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) + S(3)*x**S(2) + S(1)), x), x, atan(x*sqrt(sqrt(S(5))/S(2) + S(3)/2)) - atan(sqrt(S(2))*x/sqrt(sqrt(S(5)) + S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) + S(2)*x**S(2) + S(1)), x), x, x/(x**S(2) + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) + x**S(2) + S(1)), x), x, -log(x**S(2) - x + S(1))/S(2) + log(x**S(2) + x + S(1))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) + S(1)), x), x, -sqrt(S(2))*log(x**S(2) - sqrt(S(2))*x + S(1))/S(4) + sqrt(S(2))*log(x**S(2) + sqrt(S(2))*x + S(1))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - x**S(2) + S(1)), x), x, -sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(6) + sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - S(2)*x**S(2) + S(1)), x), x, atanh(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - S(3)*x**S(2) + S(1)), x), x, -sqrt(S(5))*log(x**S(2) - sqrt(S(5))*x + S(1))/S(10) + sqrt(S(5))*log(x**S(2) + sqrt(S(5))*x + S(1))/S(10), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - S(3)*x**S(2) + S(1)), x), x, sqrt(S(5))*atanh(x*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(5) + sqrt(S(5))*atanh(sqrt(S(2))*x/sqrt(sqrt(S(5)) + S(3)))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - S(4)*x**S(2) + S(1)), x), x, -sqrt(S(6))*log(x**S(2) - sqrt(S(6))*x + S(1))/S(12) + sqrt(S(6))*log(x**S(2) + sqrt(S(6))*x + S(1))/S(12), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - S(4)*x**S(2) + S(1)), x), x, sqrt(S(6))*atanh(x/sqrt(-sqrt(S(3)) + S(2)))/S(6) + sqrt(S(6))*atanh(x/sqrt(sqrt(S(3)) + S(2)))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - S(5)*x**S(2) + S(1)), x), x, -sqrt(S(7))*log(x**S(2) - sqrt(S(7))*x + S(1))/S(14) + sqrt(S(7))*log(x**S(2) + sqrt(S(7))*x + S(1))/S(14), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((-x**S(2) + S(1))/(x**S(4) - S(5)*x**S(2) + S(1)), x), x, sqrt(S(7))*atanh(x*sqrt(sqrt(S(21))/S(2) + S(5)/2))/S(7) + sqrt(S(7))*atanh(sqrt(S(2))*x/sqrt(sqrt(S(21)) + S(5)))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(4)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d**S(4)*x + c*e**S(4)*x**S(13)/S(13) + d**S(3)*x**S(3)*(S(4)*a*e + b*d)/S(3) + d**S(2)*x**S(5)*(S(6)*a*e**S(2) + S(4)*b*d*e + c*d**S(2))/S(5) + S(2)*d*e*x**S(7)*(S(2)*c*d**S(2) + e*(S(2)*a*e + S(3)*b*d))/S(7) + e**S(3)*x**S(11)*(b*e + S(4)*c*d)/S(11) + e**S(2)*x**S(9)*(S(6)*c*d**S(2) + e*(a*e + S(4)*b*d))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d**S(3)*x + c*e**S(3)*x**S(11)/S(11) + d**S(2)*x**S(3)*(S(3)*a*e + b*d)/S(3) + d*x**S(5)*(c*d**S(2) + S(3)*e*(a*e + b*d))/S(5) + e**S(2)*x**S(9)*(b*e + S(3)*c*d)/S(9) + e*x**S(7)*(S(3)*c*d**S(2) + e*(a*e + S(3)*b*d))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d**S(2)*x + c*e**S(2)*x**S(9)/S(9) + d*x**S(3)*(S(2)*a*e + b*d)/S(3) + e*x**S(7)*(b*e + S(2)*c*d)/S(7) + x**S(5)*(c*d**S(2) + e*(a*e + S(2)*b*d))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, a*d*x + c*e*x**S(7)/S(7) + x**S(5)*(b*e + c*d)/S(5) + x**S(3)*(a*e + b*d)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2)), x), x, c*x**S(3)/(S(3)*e) - x*(-b*e + c*d)/e**S(2) + (a*e**S(2) - b*d*e + c*d**S(2))*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(2), x), x, c*x/e**S(2) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d*e**S(2)*(d + e*x**S(2))) - (S(3)*c*d**S(2) - e*(a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(3), x), x, x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*d*e**S(2)*(d + e*x**S(2))**S(2)) - x*(S(5)*c*d**S(2) - e*(S(3)*a*e + b*d))/(S(8)*d**S(2)*e**S(2)*(d + e*x**S(2))) + (S(3)*c*d**S(2) + e*(S(3)*a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(5)/2)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(4), x), x, x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(6)*d*e**S(2)*(d + e*x**S(2))**S(3)) - x*(S(7)*c*d**S(2) - e*(S(5)*a*e + b*d))/(S(24)*d**S(2)*e**S(2)*(d + e*x**S(2))**S(2)) + x*(c*d**S(2) + e*(S(5)*a*e + b*d))/(S(16)*d**S(3)*e**S(2)*(d + e*x**S(2))) + (c*d**S(2) + e*(S(5)*a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(16)*d**(S(7)/2)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*d**S(3)*x + a*d**S(2)*x**S(3)*(S(3)*a*e + S(2)*b*d)/S(3) + c**S(2)*e**S(3)*x**S(15)/S(15) + c*e**S(2)*x**S(13)*(S(2)*b*e + S(3)*c*d)/S(13) + d*x**S(5)*(S(6)*a*b*d*e + a*(S(3)*a*e**S(2) + S(2)*c*d**S(2)) + b**S(2)*d**S(2))/S(5) + e*x**S(11)*(b**S(2)*e**S(2) + S(3)*c**S(2)*d**S(2) + S(2)*c*e*(a*e + S(3)*b*d))/S(11) + x**S(9)*(b*e**S(2)*(S(2)*a*e + S(3)*b*d)/S(9) + c**S(2)*d**S(3)/S(9) + S(2)*c*d*e*(a*e + b*d)/S(3)) + x**S(7)*(a**S(2)*e**S(3)/S(7) + S(6)*a*b*d*e**S(2)/S(7) + S(6)*a*c*d**S(2)*e/S(7) + S(3)*b**S(2)*d**S(2)*e/S(7) + S(2)*b*c*d**S(3)/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*d**S(2)*x + S(2)*a*d*x**S(3)*(a*e + b*d)/S(3) + c**S(2)*e**S(2)*x**S(13)/S(13) + S(2)*c*e*x**S(11)*(b*e + c*d)/S(11) + x**S(9)*(b**S(2)*e**S(2)/S(9) + c**S(2)*d**S(2)/S(9) + S(2)*c*e*(a*e + S(2)*b*d)/S(9)) + x**S(7)*(S(2)*a*b*e**S(2)/S(7) + S(4)*a*c*d*e/S(7) + S(2)*b**S(2)*d*e/S(7) + S(2)*b*c*d**S(2)/S(7)) + x**S(5)*(S(4)*a*b*d*e/S(5) + a*(a*e**S(2) + S(2)*c*d**S(2))/S(5) + b**S(2)*d**S(2)/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*d*x + a*x**S(3)*(a*e + S(2)*b*d)/S(3) + c**S(2)*e*x**S(11)/S(11) + c*x**S(9)*(S(2)*b*e + c*d)/S(9) + x**S(7)*(S(2)*a*c*e/S(7) + b**S(2)*e/S(7) + S(2)*b*c*d/S(7)) + x**S(5)*(S(2)*a*b*e/S(5) + S(2)*a*c*d/S(5) + b**S(2)*d/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*x + S(2)*a*b*x**S(3)/S(3) + S(2)*b*c*x**S(7)/S(7) + c**S(2)*x**S(9)/S(9) + x**S(5)*(S(2)*a*c/S(5) + b**S(2)/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/(d + e*x**S(2)), x), x, c**S(2)*x**S(7)/(S(7)*e) - c*x**S(5)*(-S(2)*b*e + c*d)/(S(5)*e**S(2)) + x**S(3)*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - S(2)*c*e*(-a*e + b*d))/(S(3)*e**S(3)) - x*(-b*e + c*d)*(c*d**S(2) - e*(-S(2)*a*e + b*d))/e**S(4) + (a*e**S(2) - b*d*e + c*d**S(2))**S(2)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/(d + e*x**S(2))**S(2), x), x, c**S(2)*x**S(7)/(S(5)*e*(d + e*x**S(2))) - c*x**S(3)*(-S(10)*b*e + S(7)*c*d)/(S(15)*e**S(3)) + x*(S(5)*b**S(2)*e**S(2) + S(14)*c**S(2)*d**S(2) - S(10)*c*e*(-a*e + S(2)*b*d))/(S(5)*e**S(4)) + x*(S(7)*c**S(2)*d**S(4) - S(10)*c*d**S(2)*e*(-a*e + b*d) + S(5)*e**S(2)*(-a*e + b*d)**S(2))/(S(10)*d*e**S(4)*(d + e*x**S(2))) - (S(7)*c*d**S(2) - e*(a*e + S(3)*b*d))*(a*e**S(2) - b*d*e + c*d**S(2))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/(d + e*x**S(2))**S(3), x), x, c**S(2)*x**S(7)/(S(3)*e*(d + e*x**S(2))**S(2)) - c*x*(-S(6)*b*e + S(7)*c*d)/(S(3)*e**S(4)) + x*(S(7)*c**S(2)*d**S(4) - S(6)*c*d**S(2)*e*(-a*e + b*d) + S(3)*e**S(2)*(-a*e + b*d)**S(2))/(S(12)*d*e**S(4)*(d + e*x**S(2))**S(2)) - x*(S(21)*c**S(2)*d**S(4) - S(2)*c*d**S(2)*e*(-S(5)*a*e + S(9)*b*d) + e**S(2)*(-S(3)*a**S(2)*e**S(2) - S(2)*a*b*d*e + S(5)*b**S(2)*d**S(2)))/(S(8)*d**S(2)*e**S(4)*(d + e*x**S(2))) + (S(35)*c**S(2)*d**S(4) - S(6)*c*d**S(2)*e*(-a*e + S(5)*b*d) + e**S(2)*(S(3)*a**S(2)*e**S(2) + S(2)*a*b*d*e + S(3)*b**S(2)*d**S(2)))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(5)/2)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/(d + e*x**S(2))**S(4), x), x, c**S(2)*x**S(7)/(e*(d + e*x**S(2))**S(3)) + x*(S(7)*c**S(2)*d**S(4) - S(2)*c*d**S(2)*e*(-a*e + b*d) + e**S(2)*(-a*e + b*d)**S(2))/(S(6)*d*e**S(4)*(d + e*x**S(2))**S(3)) - x*(S(91)*c**S(2)*d**S(4) - S(2)*c*d**S(2)*e*(-S(7)*a*e + S(13)*b*d) + e**S(2)*(-S(5)*a**S(2)*e**S(2) - S(2)*a*b*d*e + S(7)*b**S(2)*d**S(2)))/(S(24)*d**S(2)*e**S(4)*(d + e*x**S(2))**S(2)) + x*(S(77)*c**S(2)*d**S(4) - S(2)*c*d**S(2)*e*(-a*e + S(11)*b*d) + e**S(2)*(S(5)*a**S(2)*e**S(2) + S(2)*a*b*d*e + b**S(2)*d**S(2)))/(S(16)*d**S(3)*e**S(4)*(d + e*x**S(2))) - (S(35)*c**S(2)*d**S(4) - S(2)*c*d**S(2)*e*(a*e + S(5)*b*d) - e**S(2)*(S(5)*a**S(2)*e**S(2) + S(2)*a*b*d*e + b**S(2)*d**S(2)))*atan(sqrt(e)*x/sqrt(d))/(S(16)*d**(S(7)/2)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)/(d + e*x**S(2))**S(5), x), x, -c**S(2)*x**S(7)/(e*(d + e*x**S(2))**S(4)) - x*(S(7)*c**S(2)*d**S(4) + S(2)*c*d**S(2)*e*(-a*e + b*d) - e**S(2)*(-a*e + b*d)**S(2))/(S(8)*d*e**S(4)*(d + e*x**S(2))**S(4)) + x*(S(119)*c**S(2)*d**S(4) + S(2)*c*d**S(2)*e*(-S(9)*a*e + S(17)*b*d) - e**S(2)*(-S(7)*a**S(2)*e**S(2) - S(2)*a*b*d*e + S(9)*b**S(2)*d**S(2)))/(S(48)*d**S(2)*e**S(4)*(d + e*x**S(2))**S(3)) - x*(S(413)*c**S(2)*d**S(4) + S(2)*c*d**S(2)*e*(-S(3)*a*e + S(59)*b*d) - e**S(2)*(S(35)*a**S(2)*e**S(2) + S(10)*a*b*d*e + S(3)*b**S(2)*d**S(2)))/(S(192)*d**S(3)*e**S(4)*(d + e*x**S(2))**S(2)) + x*(S(35)*c**S(2)*d**S(4) + S(2)*c*d**S(2)*e*(S(3)*a*e + S(5)*b*d) + e**S(2)*(S(35)*a**S(2)*e**S(2) + S(10)*a*b*d*e + S(3)*b**S(2)*d**S(2)))/(S(128)*d**S(4)*e**S(4)*(d + e*x**S(2))) + (S(35)*c**S(2)*d**S(4) + S(2)*c*d**S(2)*e*(S(3)*a*e + S(5)*b*d) + e**S(2)*(S(35)*a**S(2)*e**S(2) + S(10)*a*b*d*e + S(3)*b**S(2)*d**S(2)))*atan(sqrt(e)*x/sqrt(d))/(S(128)*d**(S(9)/2)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(2), x), x, c*x/e**S(2) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d*e**S(2)*(d + e*x**S(2))) - (S(3)*c*d**S(2) - e*(a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + x**S(2)*(b + c*x**S(2)))/(d + e*x**S(2))**S(2), x), x, c*x/e**S(2) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d*e**S(2)*(d + e*x**S(2))) - (S(3)*c*d**S(2) - e*(a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(4)/(a + b*x**S(2) + c*x**S(4)), x), x, e**S(4)*x**S(5)/(S(5)*c) + e**S(3)*x**S(3)*(-b*e + S(4)*c*d)/(S(3)*c**S(2)) + e**S(2)*x*(b**S(2)*e**S(2) + S(6)*c**S(2)*d**S(2) - c*e*(a*e + S(4)*b*d))/c**S(3) + sqrt(S(2))*(e*(-b*e + S(2)*c*d)*(b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d)) - (b**S(4)*e**S(4) - S(4)*b**S(2)*c*e**S(3)*(a*e + b*d) + S(2)*c**S(4)*d**S(4) - S(4)*c**S(3)*d**S(2)*e*(S(3)*a*e + b*d) + S(2)*c**S(2)*e**S(2)*(a**S(2)*e**S(2) + S(6)*a*b*d*e + S(3)*b**S(2)*d**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(7)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(e*(-b*e + S(2)*c*d)*(b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d)) + (b**S(4)*e**S(4) - S(4)*b**S(2)*c*e**S(3)*(a*e + b*d) + S(2)*c**S(4)*d**S(4) - S(4)*c**S(3)*d**S(2)*e*(S(3)*a*e + b*d) + S(2)*c**S(2)*e**S(2)*(a**S(2)*e**S(2) + S(6)*a*b*d*e + S(3)*b**S(2)*d**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(7)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/(a + b*x**S(2) + c*x**S(4)), x), x, e**S(3)*x**S(3)/(S(3)*c) + e**S(2)*x*(-b*e + S(3)*c*d)/c**S(2) + sqrt(S(2))*(e*(b**S(2)*e**S(2) + S(3)*c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d)) - (-b*e + S(2)*c*d)*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(e*(b**S(2)*e**S(2) + S(3)*c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d)) + (-b*e + S(2)*c*d)*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/(a + b*x**S(2) + c*x**S(4)), x), x, e**S(2)*x/c + sqrt(S(2))*(e*(-b*e + S(2)*c*d) - (b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(e*(-b*e + S(2)*c*d) + (b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(S(2))*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*sqrt(c)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) + e**(S(3)/2)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(b*e**S(2)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d - d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + sqrt(S(2))*sqrt(c)*(b*e**S(2)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d + d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**S(2)*x/(S(2)*d*(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + e**(S(3)/2)*(-b*e + S(2)*c*d)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**(S(3)/2)*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, x*(-a*b*e*(a*e**S(2) + S(3)*c*d**S(2)) - S(2)*a*c*d*(-S(3)*a*e**S(2) + c*d**S(2)) + b**S(2)*c*d**S(3) - x**S(2)*(a*b**S(2)*e**S(3) + S(2)*a*c*e*(-a*e**S(2) + S(3)*c*d**S(2)) - b*c*d*(S(3)*a*e**S(2) + c*d**S(2))))/(S(2)*a*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(a*b**S(3)*e**S(3) + S(6)*a*c*(a*e**S(2) + c*d**S(2))*(S(2)*c*d - e*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*(-S(3)*a*c*d*e**S(2) - a*e**S(3)*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*d**S(3)) + b*c*(a*e**S(2)*(-S(8)*a*e + S(3)*d*sqrt(-S(4)*a*c + b**S(2))) + c*d**S(2)*(-S(12)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*(a*b**S(3)*e**S(3) + S(6)*a*c*(a*e**S(2) + c*d**S(2))*(S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*(-S(3)*a*c*d*e**S(2) + a*e**S(3)*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*d**S(3)) - b*c*(a*e**S(2)*(S(8)*a*e + S(3)*d*sqrt(-S(4)*a*c + b**S(2))) + c*d**S(2)*(S(12)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, x*(-S(2)*a*b*d*e - S(2)*a*(-a*e**S(2) + c*d**S(2)) + b**S(2)*d**S(2) + x**S(2)*(a*b*e**S(2) - S(4)*a*c*d*e + b*c*d**S(2)))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(-S(4)*a*c*(S(3)*c*d**S(2) - e*(-a*e + d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(2)*(-a*e**S(2) + c*d**S(2)) - b*(a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) + c*d*(-S(8)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(-S(4)*a*c*(S(3)*c*d**S(2) + e*(a*e + d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(2)*(-a*e**S(2) + c*d**S(2)) + b*(a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) + c*d*(S(8)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, sqrt(S(2))*sqrt(c)*(-S(2)*a*e + b*d - (S(4)*a*b*e - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(-S(2)*a*e + b*d + (S(4)*a*b*e - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + x*(-a*b*e - S(2)*a*c*d + b**S(2)*d + c*x**S(2)*(-S(2)*a*e + b*d))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(-2)), x), x, -sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -sqrt(S(2))*sqrt(c)*e**S(2)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - sqrt(S(2))*sqrt(c)*e**S(2)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**(S(7)/2)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + sqrt(S(2))*sqrt(c)*(S(2)*a*c*e - b**S(2)*e + b*c*d - (S(8)*a*b*c*e - S(12)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(S(2))*sqrt(c)*(S(2)*a*c*e - b**S(2)*e + b*c*d + (S(8)*a*b*c*e - S(12)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + x*(S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d + c*x**S(2)*(S(2)*a*c*e - b**S(2)*e + b*c*d))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -sqrt(S(2))*sqrt(c)*e**S(2)*(b*e**S(2)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(3)*c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d - S(2)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + sqrt(S(2))*sqrt(c)*e**S(2)*(b*e**S(2)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(3)*c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d + S(2)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + e**S(4)*x/(S(2)*d*(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + S(2)*e**(S(7)/2)*(-b*e + S(2)*c*d)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + e**(S(7)/2)*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - sqrt(S(2))*sqrt(c)*(-S(4)*a*c**S(2)*(S(3)*c*d**S(2) + e*(-S(3)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(4)*e**S(2) - b**S(3)*e*(S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*c*(c*d**S(2) + e*(-S(9)*a*e + S(2)*d*sqrt(-S(4)*a*c + b**S(2)))) + b*c*(S(3)*a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) - c*d*(-S(16)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + sqrt(S(2))*sqrt(c)*(-S(4)*a*c**S(2)*(S(3)*c*d**S(2) - e*(S(3)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(4)*e**S(2) - b**S(3)*e*(S(2)*c*d - e*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*c*(c*d**S(2) - e*(S(9)*a*e + S(2)*d*sqrt(-S(4)*a*c + b**S(2)))) - b*c*(S(3)*a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) - c*d*(S(16)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - x*(-S(6)*a*b*c**S(2)*d*e + S(2)*a*c**S(2)*(-a*e**S(2) + c*d**S(2)) - b**S(4)*e**S(2) + S(2)*b**S(3)*c*d*e - b**S(2)*c*(-S(4)*a*e**S(2) + c*d**S(2)) + c*x**S(2)*(-S(4)*a*c**S(2)*d*e - b**S(3)*e**S(2) + S(2)*b**S(2)*c*d*e - b*c*(-S(3)*a*e**S(2) + c*d**S(2))))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(2) + S(3))/(x**S(4) - S(2)*x**S(2) + S(1)), x), x, S(5)*x/(-S(2)*x**S(2) + S(2)) + atanh(x)/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(3)*x**S(2) + S(2))/(S(3)*x**S(4) - S(8)*x**S(2) + S(5)), x), x, S(5)*atanh(x)/S(2) - S(7)*sqrt(S(15))*atanh(sqrt(S(15))*x/S(5))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(S(3)*x**S(4) - S(8)*x**S(2) + S(5)), x), x, (d/S(2) + e/S(2))*atanh(x) - sqrt(S(15))*(S(3)*d + S(5)*e)*atanh(sqrt(S(15))*x/S(5))/S(30), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(3))/(x**S(4) + S(3)*x**S(2) + S(1)), x), x, sqrt(S(10))*(sqrt(S(5)) + S(3))**(S(3)/2)*atan(x*sqrt(sqrt(S(5))/S(2) + S(3)/2))/S(20) - sqrt(-S(80)*sqrt(S(5)) + S(180))*atan(sqrt(S(2))*x/sqrt(sqrt(S(5)) + S(3)))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(4) + x**S(2) + S(1)), x), x, -(a/S(4) - b/S(4))*log(x**S(2) - x + S(1)) + (a/S(4) - b/S(4))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(a + b)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*(a + b)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(4) + x**S(2) + S(1))**S(2), x), x, x*(a + b - x**S(2)*(a - S(2)*b))/(S(6)*x**S(4) + S(6)*x**S(2) + S(6)) - (a/S(4) - b/S(8))*log(x**S(2) - x + S(1)) + (a/S(4) - b/S(8))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(4)*a + b)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*(S(4)*a + b)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(36), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(4) + x**S(2) + S(2)), x), x, -(a - sqrt(S(2))*b)*log(x**S(2) - x*sqrt(S(-1) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(4)*sqrt(S(-2) + S(4)*sqrt(S(2)))) + (a - sqrt(S(2))*b)*log(x**S(2) + x*sqrt(S(-1) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(4)*sqrt(S(-2) + S(4)*sqrt(S(2)))) - sqrt(S(-1)/14 + sqrt(S(2))/S(7))*(a + sqrt(S(2))*b)*atan((-S(2)*x + sqrt(S(-1) + S(2)*sqrt(S(2))))/sqrt(S(1) + S(2)*sqrt(S(2))))/S(2) + sqrt(S(-1)/14 + sqrt(S(2))/S(7))*(a + sqrt(S(2))*b)*atan((S(2)*x + sqrt(S(-1) + S(2)*sqrt(S(2))))/sqrt(S(1) + S(2)*sqrt(S(2))))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2))/(x**S(4) + x**S(2) + S(2))**S(2), x), x, x*(S(3)*a + S(2)*b - x**S(2)*(a - S(4)*b))/(S(28)*x**S(4) + S(28)*x**S(2) + S(56)) - sqrt(S(-1)/14 + sqrt(S(2))/S(7))*(a*(-sqrt(S(2)) + S(11)) - b*(-S(4)*sqrt(S(2)) + S(2)))*atan((-S(2)*x + sqrt(S(-1) + S(2)*sqrt(S(2))))/sqrt(S(1) + S(2)*sqrt(S(2))))/S(56) + sqrt(S(-1)/14 + sqrt(S(2))/S(7))*(a*(-sqrt(S(2)) + S(11)) - b*(-S(4)*sqrt(S(2)) + S(2)))*atan((S(2)*x + sqrt(S(-1) + S(2)*sqrt(S(2))))/sqrt(S(1) + S(2)*sqrt(S(2))))/S(56) - (S(11)*a - S(2)*b + sqrt(S(2))*(a - S(4)*b))*log(x**S(2) - x*sqrt(S(-1) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(112)*sqrt(S(-2) + S(4)*sqrt(S(2)))) + (a*(sqrt(S(2)) + S(11)) - S(4)*sqrt(S(2))*b - S(2)*b)*log(x**S(2) + x*sqrt(S(-1) + S(2)*sqrt(S(2))) + sqrt(S(2)))/(S(112)*sqrt(S(-2) + S(4)*sqrt(S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + sqrt(S(2)))/(x**S(4) - sqrt(S(2))*x**S(2) + S(1)), x), x, -sqrt(sqrt(S(2))/S(2) + S(1))*log(x**S(2) - x*sqrt(sqrt(S(2)) + S(2)) + S(1))/S(4) + sqrt(sqrt(S(2))/S(2) + S(1))*log(x**S(2) + x*sqrt(sqrt(S(2)) + S(2)) + S(1))/S(4) - atan((-S(2)*x + sqrt(sqrt(S(2)) + S(2)))/sqrt(-sqrt(S(2)) + S(2)))/(S(2)*sqrt(sqrt(S(2)) + S(2))) + atan((S(2)*x + sqrt(sqrt(S(2)) + S(2)))/sqrt(-sqrt(S(2)) + S(2)))/(S(2)*sqrt(sqrt(S(2)) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + sqrt(S(2)))/(x**S(4) + sqrt(S(2))*x**S(2) + S(1)), x), x, -sqrt(-sqrt(S(2))/S(2) + S(1))*log(x**S(2) - x*sqrt(-sqrt(S(2)) + S(2)) + S(1))/S(4) + sqrt(-sqrt(S(2))/S(2) + S(1))*log(x**S(2) + x*sqrt(-sqrt(S(2)) + S(2)) + S(1))/S(4) - atan((-S(2)*x + sqrt(-sqrt(S(2)) + S(2)))/sqrt(sqrt(S(2)) + S(2)))/(S(2)*sqrt(-sqrt(S(2)) + S(2))) + atan((S(2)*x + sqrt(-sqrt(S(2)) + S(2)))/sqrt(sqrt(S(2)) + S(2)))/(S(2)*sqrt(-sqrt(S(2)) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + sqrt(S(2)))/(b*x**S(2) + x**S(4) + S(1)), x), x, (-sqrt(S(2)) + S(1))*atan((-S(2)*x + sqrt(-b + S(2)))/sqrt(b + S(2)))/(S(2)*sqrt(b + S(2))) - (-sqrt(S(2)) + S(1))*atan((S(2)*x + sqrt(-b + S(2)))/sqrt(b + S(2)))/(S(2)*sqrt(b + S(2))) - (S(1) + sqrt(S(2)))*log(x**S(2) - x*sqrt(-b + S(2)) + S(1))/(S(4)*sqrt(-b + S(2))) + (S(1) + sqrt(S(2)))*log(x**S(2) + x*sqrt(-b + S(2)) + S(1))/(S(4)*sqrt(-b + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + sqrt(S(2)))/(b*x**S(2) + x**S(4) + S(1)), x), x, -(S(1) + sqrt(S(2)))*atan((-S(2)*x + sqrt(-b + S(2)))/sqrt(b + S(2)))/(S(2)*sqrt(b + S(2))) + (S(1) + sqrt(S(2)))*atan((S(2)*x + sqrt(-b + S(2)))/sqrt(b + S(2)))/(S(2)*sqrt(b + S(2))) + (-sqrt(S(2)) + S(1))*log(x**S(2) - x*sqrt(-b + S(2)) + S(1))/(S(4)*sqrt(-b + S(2))) - (-sqrt(S(2)) + S(1))*log(x**S(2) + x*sqrt(-b + S(2)) + S(1))/(S(4)*sqrt(-b + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*a - x**S(2))/(a**S(2) - a*x**S(2) + x**S(4)), x), x, -sqrt(S(3))*log(-sqrt(S(3))*sqrt(a)*x + a + x**S(2))/(S(4)*sqrt(a)) + sqrt(S(3))*log(sqrt(S(3))*sqrt(a)*x + a + x**S(2))/(S(4)*sqrt(a)) - atan((sqrt(S(3))*sqrt(a) - S(2)*x)/sqrt(a))/(S(2)*sqrt(a)) + atan((sqrt(S(3))*sqrt(a) + S(2)*x)/sqrt(a))/(S(2)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*sqrt(a) - x**S(2))/(-sqrt(a)*x**S(2) + a + x**S(4)), x), x, -sqrt(S(3))*log(-sqrt(S(3))*a**(S(1)/4)*x + sqrt(a) + x**S(2))/(S(4)*a**(S(1)/4)) + sqrt(S(3))*log(sqrt(S(3))*a**(S(1)/4)*x + sqrt(a) + x**S(2))/(S(4)*a**(S(1)/4)) - atan((sqrt(S(3))*a**(S(1)/4) - S(2)*x)/a**(S(1)/4))/(S(2)*a**(S(1)/4)) + atan((sqrt(S(3))*a**(S(1)/4) + S(2)*x)/a**(S(1)/4))/(S(2)*a**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*b**(S(2)/3) + x**S(2))/(b**(S(4)/3) + b**(S(2)/3)*x**S(2) + x**S(4)), x), x, -log(b**(S(2)/3) - b**(S(1)/3)*x + x**S(2))/(S(4)*b**(S(1)/3)) + log(b**(S(2)/3) + b**(S(1)/3)*x + x**S(2))/(S(4)*b**(S(1)/3)) - sqrt(S(3))*atan(sqrt(S(3))*(b**(S(1)/3) - S(2)*x)/(S(3)*b**(S(1)/3)))/(S(2)*b**(S(1)/3)) + sqrt(S(3))*atan(sqrt(S(3))*(b**(S(1)/3) + S(2)*x)/(S(3)*b**(S(1)/3)))/(S(2)*b**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(a**S(2) - a*x**S(2) + x**S(4)), x), x, -sqrt(S(3))*(A - B*a)*log(-sqrt(S(3))*sqrt(a)*x + a + x**S(2))/(S(12)*a**(S(3)/2)) + sqrt(S(3))*(A - B*a)*log(sqrt(S(3))*sqrt(a)*x + a + x**S(2))/(S(12)*a**(S(3)/2)) - (A + B*a)*atan((sqrt(S(3))*sqrt(a) - S(2)*x)/sqrt(a))/(S(2)*a**(S(3)/2)) + (A + B*a)*atan((sqrt(S(3))*sqrt(a) + S(2)*x)/sqrt(a))/(S(2)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(-sqrt(a)*x**S(2) + a + x**S(4)), x), x, -sqrt(S(3))*(A - B*sqrt(a))*log(-sqrt(S(3))*a**(S(1)/4)*x + sqrt(a) + x**S(2))/(S(12)*a**(S(3)/4)) + sqrt(S(3))*(A - B*sqrt(a))*log(sqrt(S(3))*a**(S(1)/4)*x + sqrt(a) + x**S(2))/(S(12)*a**(S(3)/4)) - (A + B*sqrt(a))*atan((sqrt(S(3))*a**(S(1)/4) - S(2)*x)/a**(S(1)/4))/(S(2)*a**(S(3)/4)) + (A + B*sqrt(a))*atan((sqrt(S(3))*a**(S(1)/4) + S(2)*x)/a**(S(1)/4))/(S(2)*a**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(a + c*x**S(4) - x**S(2)*sqrt(a*c)), x), x, -(A - B*sqrt(a)/sqrt(c))*log(sqrt(a) + sqrt(c)*x**S(2) - x*sqrt(S(2)*sqrt(a)*sqrt(c) + sqrt(a*c)))/(S(4)*sqrt(a)*sqrt(S(2)*sqrt(a)*sqrt(c) + sqrt(a*c))) + (A - B*sqrt(a)/sqrt(c))*log(sqrt(a) + sqrt(c)*x**S(2) + x*sqrt(S(2)*sqrt(a)*sqrt(c) + sqrt(a*c)))/(S(4)*sqrt(a)*sqrt(S(2)*sqrt(a)*sqrt(c) + sqrt(a*c))) - (A*sqrt(c) + B*sqrt(a))*atan((-S(2)*sqrt(c)*x + sqrt(S(2)*sqrt(a)*sqrt(c) + sqrt(a*c)))/sqrt(S(2)*sqrt(a)*sqrt(c) - sqrt(a*c)))/(S(2)*sqrt(a)*sqrt(c)*sqrt(S(2)*sqrt(a)*sqrt(c) - sqrt(a*c))) + (A*sqrt(c) + B*sqrt(a))*atan((S(2)*sqrt(c)*x + sqrt(S(2)*sqrt(a)*sqrt(c) + sqrt(a*c)))/sqrt(S(2)*sqrt(a)*sqrt(c) - sqrt(a*c)))/(S(2)*sqrt(a)*sqrt(c)*sqrt(S(2)*sqrt(a)*sqrt(c) - sqrt(a*c))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(-sqrt(a)*sqrt(c)*x**S(2) + a + c*x**S(4)), x), x, -sqrt(S(3))*(A - B*sqrt(a)/sqrt(c))*log(-sqrt(S(3))*a**(S(1)/4)*c**(S(1)/4)*x + sqrt(a) + sqrt(c)*x**S(2))/(S(12)*a**(S(3)/4)*c**(S(1)/4)) + sqrt(S(3))*(A - B*sqrt(a)/sqrt(c))*log(sqrt(S(3))*a**(S(1)/4)*c**(S(1)/4)*x + sqrt(a) + sqrt(c)*x**S(2))/(S(12)*a**(S(3)/4)*c**(S(1)/4)) - (A*sqrt(c) + B*sqrt(a))*atan((sqrt(S(3))*a**(S(1)/4) - S(2)*c**(S(1)/4)*x)/a**(S(1)/4))/(S(2)*a**(S(3)/4)*c**(S(3)/4)) + (A*sqrt(c) + B*sqrt(a))*atan((sqrt(S(3))*a**(S(1)/4) + S(2)*c**(S(1)/4)*x)/a**(S(1)/4))/(S(2)*a**(S(3)/4)*c**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, S(125)*x**S(3)*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/S(9) + S(577)*x*(x**S(2) + S(2))/(S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(757)*x**S(2) + S(2608))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(21) + S(275)*x*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/S(7) - S(577)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(2945)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(21)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, S(31)*x*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + x*(S(114)*x**S(2) + S(407))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(21) + S(25)*x*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/S(7) - S(31)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + S(472)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(21)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))*sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, S(5)*x*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + x*(S(3)*x**S(2) + S(10))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(3) - S(5)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + S(11)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, x*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(3) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + S(2)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(5)*x**S(2) + S(7)), x), x, x*(x**S(2) + S(2))/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(3)*x**S(2) + S(3))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(70)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt((x**S(2) + S(2))/(S(2)*x**S(2) + S(2)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(5)*x**S(2) + S(7)), x), x, x*(x**S(2) + S(2))/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(4)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(25)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(3)*x**S(2) + S(3))*elliptic_f(atan(x), S(1)/2)/(S(50)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*(S(3)*x**S(2) + S(6))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(70)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(5)*x**S(2) + S(7))**S(2), x), x, x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(70)*x**S(2) + S(98)) - x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(70)*x**S(2) + S(70)) + sqrt(S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))*elliptic_e(atan(x), S(1)/2)/(S(70)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))) + S(3)*sqrt(S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))*elliptic_f(atan(x), S(1)/2)/(S(280)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))) - sqrt(S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(1960)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(3)*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2), x), x, S(125)*x**S(3)*(x**S(4) + S(3)*x**S(2) + S(2))**(S(5)/2)/S(13) + S(20884)*x*(x**S(2) + S(2))/(S(65)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(65345)*x**S(2) + S(208212))*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/S(3003) + x*(S(297911)*x**S(2) + S(1032541))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(5005) + S(3825)*x*(x**S(4) + S(3)*x**S(2) + S(2))**(S(5)/2)/S(143) - S(20884)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(65)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(1171349)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(5005)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(2)*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2), x), x, S(742)*x*(x**S(2) + S(2))/(S(15)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(2240)*x**S(2) + S(7281))*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/S(693) + x*(S(10643)*x**S(2) + S(36783))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(1155) + S(25)*x*(x**S(4) + S(3)*x**S(2) + S(2))**(S(5)/2)/S(11) - S(742)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(15)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(13879)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(385)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2), x), x, S(116)*x*(x**S(2) + S(2))/(S(15)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(35)*x**S(2) + S(108))*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/S(63) + x*(S(149)*x**S(2) + S(519))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(105) - S(116)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(15)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(197)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(35)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2), x), x, S(6)*x*(x**S(2) + S(2))/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(9)*x**S(2) + S(29))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(35) + x*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/S(7) - S(6)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(31)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(35)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/(S(5)*x**S(2) + S(7)), x), x, x**S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(25) + S(24)*x*(x**S(2) + S(2))/(S(125)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(11)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(75) - S(24)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(125)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(47)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(375)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + (S(24)*x**S(2) + S(24))*elliptic_pi(S(-3)/7, atan(sqrt(S(2))*x/S(2)), S(-1))/(S(875)*sqrt((x**S(2) + S(1))/(x**S(2) + S(2)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)/(S(5)*x**S(2) + S(7))**S(2), x), x, x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(75) - S(3)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(875)*x**S(2) + S(1225)) + S(9)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(175)*x**S(2) + S(175)) + S(8)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))*elliptic_pi(S(-3)/7, atan(sqrt(S(2))*x/S(2)), S(-1))/(S(875)*sqrt((x**S(2) + S(1))/(x**S(2) + S(2)))*(x**S(2) + S(2))) - S(9)*sqrt(S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))*elliptic_e(atan(x), S(1)/2)/(sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(175)*x**S(2) + S(175))) + S(211)*sqrt(S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))*elliptic_f(atan(x), S(1)/2)/(S(10500)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))) + S(129)*sqrt(S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(24500)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(9)*a*e**S(3)/c + S(8)*b**S(2)*e**S(3)/c**S(2) - S(30)*b*d*e**S(2)/c + S(45)*d**S(2)*e + (S(4)*a*b*e**S(3) - S(15)*a*c*d*e**S(2) + S(15)*c**S(2)*d**S(3))/(sqrt(a)*c**(S(3)/2)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(30)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*e*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(8)*b**S(2)*e**S(2) + S(45)*c**S(2)*d**S(2) - S(3)*c*e*(S(3)*a*e + S(10)*b*d))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(15)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + e**S(3)*x**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(5)*c) + e**S(2)*x*(-S(4)*b*e + S(15)*c*d)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*c**S(2)) + e*x*sqrt(a + b*x**S(2) + c*x**S(4))*(S(8)*b**S(2)*e**S(2) + S(45)*c**S(2)*d**S(2) - S(3)*c*e*(S(3)*a*e + S(10)*b*d))/(S(15)*c**(S(5)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(2)*b*e**S(2)/c + S(6)*d*e + (-a*e**S(2) + S(3)*c*d**S(2))/(sqrt(a)*sqrt(c)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - S(2)*a**(S(1)/4)*e*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-b*e + S(3)*c*d)*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + e**S(2)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*c) + S(2)*e*x*(-b*e + S(3)*c*d)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -a**(S(1)/4)*e*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + e*x*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, atan(x*sqrt(a*e/d - b + c*d/e)/sqrt(a + b*x**S(2) + c*x**S(4)))/(S(2)*d*sqrt(a*e/d - b + c*d/e)) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*(-sqrt(a)*e + sqrt(c)*d)*sqrt(a + b*x**S(2) + c*x**S(4))) - sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_pi(-sqrt(a)*(-e + sqrt(c)*d/sqrt(a))**S(2)/(S(4)*sqrt(c)*d*e), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(4)*a**(S(1)/4)*c**(S(1)/4)*d*(-e + sqrt(c)*d/sqrt(a))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, a**(S(1)/4)*c**(S(1)/4)*e*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*d*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))) - a**(S(1)/4)*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(4)*d*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*(S(3)*c*d**S(2) - e*(-a*e + S(2)*b*d))*elliptic_pi(-(-sqrt(a)*e + sqrt(c)*d)**S(2)/(S(4)*sqrt(a)*sqrt(c)*d*e), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(8)*c**(S(1)/4)*d**S(2)*(-sqrt(a)*e + sqrt(c)*d)*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(c)*e*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*d*(sqrt(a) + sqrt(c)*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + e**S(2)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*d*(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + (S(3)*c*d**S(2) - e*(-a*e + S(2)*b*d))*atan(x*sqrt(a*e/d - b + c*d/e)/sqrt(a + b*x**S(2) + c*x**S(4)))/(S(4)*d**S(3)*e*(a*e/d - b + c*d/e)**(S(3)/2)) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(3)*c*d**S(2) - e*(-a*e + S(2)*b*d))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(4)*a**(S(1)/4)*d*(-sqrt(a)*e + sqrt(c)*d)*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -e**S(3)*x**S(3)*sqrt(a + b*x**S(2) - c*x**S(4))/(S(5)*c) - e**S(2)*x*(S(4)*b*e + S(15)*c*d)*sqrt(a + b*x**S(2) - c*x**S(4))/(S(15)*c**S(2)) + sqrt(S(2))*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*(S(9)*a*e**S(3)/c + S(8)*b**S(2)*e**S(3)/c**S(2) + S(30)*b*d*e**S(2)/c + S(45)*d**S(2)*e + (S(8)*a*b*e**S(3) + S(30)*a*c*d*e**S(2) + S(30)*c**S(2)*d**S(3))/(b*c - c*sqrt(S(4)*a*c + b**S(2))))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(60)*c**(S(3)/2)*sqrt(a + b*x**S(2) - c*x**S(4))) - sqrt(S(2))*e*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*(S(8)*b**S(2)*e**S(2) + S(45)*c**S(2)*d**S(2) + S(3)*c*e*(S(3)*a*e + S(10)*b*d))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(60)*c**(S(7)/2)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -e**S(2)*x*sqrt(a + b*x**S(2) - c*x**S(4))/(S(3)*c) - sqrt(S(2))*e*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(b*e + S(3)*c*d)*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(6)*c**(S(5)/2)*sqrt(a + b*x**S(2) - c*x**S(4))) + sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*(b*e**S(2)*(b - sqrt(S(4)*a*c + b**S(2))) + S(3)*c**S(2)*d**S(2) + c*e*(a*e + S(3)*b*d - S(3)*d*sqrt(S(4)*a*c + b**S(2))))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(6)*c**(S(5)/2)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(a + b*x**S(2) - c*x**S(4)), x), x, -sqrt(S(2))*e*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(a + b*x**S(2) - c*x**S(4))) + sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(S(2)*c*d + e*(b - sqrt(S(4)*a*c + b**S(2))))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*sqrt(a + b*x**S(2) - c*x**S(4))), x), x, sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_pi(-e*(b + sqrt(S(4)*a*c + b**S(2)))/(S(2)*c*d), asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*d*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*sqrt(a + b*x**S(2) - c*x**S(4))), x), x, -e**S(2)*x*sqrt(a + b*x**S(2) - c*x**S(4))/(S(2)*d*(d + e*x**S(2))*(-a*e**S(2) + b*d*e + c*d**S(2))) + sqrt(S(2))*e*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(8)*sqrt(c)*d*(c*d**S(2) + e*(-a*e + b*d))*sqrt(a + b*x**S(2) - c*x**S(4))) - sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(S(2)*c*d + e*(b - sqrt(S(4)*a*c + b**S(2))))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_f(asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(8)*sqrt(c)*d*(c*d**S(2) + e*(-a*e + b*d))*sqrt(a + b*x**S(2) - c*x**S(4))) + sqrt(S(2))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(S(3)*c*d**S(2) + e*(-a*e + S(2)*b*d))*sqrt(-S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(-S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_pi(-e*(b + sqrt(S(4)*a*c + b**S(2)))/(S(2)*c*d), asin(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), (b + sqrt(S(4)*a*c + b**S(2)))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*d**S(2)*(c*d**S(2) + e*(-a*e + b*d))*sqrt(a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(-a + b*x**S(2) + c*x**S(4)), x), x, e*x*(b - sqrt(S(4)*a*c + b**S(2)))*(S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))/(S(2)*c*sqrt(-a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*d*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_f(atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), -S(2)*sqrt(S(4)*a*c + b**S(2))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt((S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))/(S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1)))*sqrt(-a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*e*(b - sqrt(S(4)*a*c + b**S(2)))*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_e(atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), -S(2)*sqrt(S(4)*a*c + b**S(2))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt((S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))/(S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1)))*sqrt(-a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*sqrt(-a + b*x**S(2) + c*x**S(4))), x), x, sqrt(S(2))*sqrt(-b + sqrt(S(4)*a*c + b**S(2)))*sqrt(S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_pi(e*(b - sqrt(S(4)*a*c + b**S(2)))/(S(2)*c*d), asin(sqrt(S(2))*sqrt(c)*x/sqrt(-b + sqrt(S(4)*a*c + b**S(2)))), (b - sqrt(S(4)*a*c + b**S(2)))/(b + sqrt(S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*d*sqrt(-a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*sqrt(-a + b*x**S(2) + c*x**S(4))), x), x, sqrt(S(2))*sqrt(c)*sqrt(b + sqrt(S(4)*a*c + b**S(2)))*(S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_f(atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), -S(2)*sqrt(S(4)*a*c + b**S(2))/(b - sqrt(S(4)*a*c + b**S(2))))/(sqrt((S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))/(S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1)))*(S(2)*c*d - e*(b + sqrt(S(4)*a*c + b**S(2))))*sqrt(-a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*e*(b + sqrt(S(4)*a*c + b**S(2)))**(S(3)/2)*(S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))*elliptic_pi(S(1) - e*(b + sqrt(S(4)*a*c + b**S(2)))/(S(2)*c*d), atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(S(4)*a*c + b**S(2)))), -S(2)*sqrt(S(4)*a*c + b**S(2))/(b - sqrt(S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*d*sqrt((S(2)*c*x**S(2)/(b - sqrt(S(4)*a*c + b**S(2))) + S(1))/(S(2)*c*x**S(2)/(b + sqrt(S(4)*a*c + b**S(2))) + S(1)))*(S(2)*c*d - e*(b + sqrt(S(4)*a*c + b**S(2))))*sqrt(-a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(-a + b*x**S(2) - c*x**S(4)), x), x, -a**(S(1)/4)*e*sqrt((a - b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 + b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(3)/4)*sqrt(-a + b*x**S(2) - c*x**S(4))) + a**(S(1)/4)*sqrt((a - b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 + b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*c**(S(3)/4)*sqrt(-a + b*x**S(2) - c*x**S(4))) - e*x*sqrt(-a + b*x**S(2) - c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*sqrt(-a + b*x**S(2) - c*x**S(4))), x), x, atan(x*sqrt(-a*e/d - b - c*d/e)/sqrt(-a + b*x**S(2) - c*x**S(4)))/(S(2)*d*sqrt(-a*e/d - b - c*d/e)) + c**(S(1)/4)*sqrt((a - b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 + b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*(-sqrt(a)*e + sqrt(c)*d)*sqrt(-a + b*x**S(2) - c*x**S(4))) - sqrt((a - b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(e + sqrt(c)*d/sqrt(a))*elliptic_pi(-sqrt(a)*(-e + sqrt(c)*d/sqrt(a))**S(2)/(S(4)*sqrt(c)*d*e), S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 + b/(S(4)*sqrt(a)*sqrt(c)))/(S(4)*a**(S(1)/4)*c**(S(1)/4)*d*(-e + sqrt(c)*d/sqrt(a))*sqrt(-a + b*x**S(2) - c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(3)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, e**S(3)*x**S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(5) + e**S(2)*x*(d - S(4)*e/S(5))*sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + S(3)*e*x*(x**S(2) + S(2))*(S(5)*d**S(2) - S(10)*d*e + S(6)*e**S(2))/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - S(3)*sqrt(S(2))*e*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*(S(5)*d**S(2) - S(10)*d*e + S(6)*e**S(2))*elliptic_e(atan(x), S(1)/2)/(S(5)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*(S(5)*d**S(3) - S(10)*d*e**S(2) + S(8)*e**S(3))*elliptic_f(atan(x), S(1)/2)/(S(10)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, e**S(2)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(3) + e*x*(S(2)*d - S(2)*e)*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) - S(2)*sqrt(S(2))*e*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(d - e)*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(3)*d**S(2) - S(2)*e**S(2))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(6)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, sqrt(S(2))*d*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + e*x*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) - sqrt(S(2))*e*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), x), x, sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(2)*(d - e)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*e*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_pi(S(1) - e/d, atan(x), S(1)/2)/(S(2)*d*(d - e)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), x), x, sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(2)*(d - e)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*e*(x**S(2) + S(2))*elliptic_pi(S(1) - e/d, atan(x), S(1)/2)/(S(2)*d*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(d - e)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), x), x, e**S(2)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(2)*d*(d + e*x**S(2))*(d**S(2) - S(3)*d*e + S(2)*e**S(2))) - e*x*(x**S(2) + S(2))/(S(2)*d*(d**S(2) - S(3)*d*e + S(2)*e**S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*e*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(2)*d*(d - S(2)*e)*(d - e)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt((x**S(2) + S(2))/(S(2)*x**S(2) + S(2)))*(S(2)*d - e)*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(2)*d*(d - e)**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*e*(x**S(2) + S(2))*(S(3)*d**S(2) - S(6)*d*e + S(2)*e**S(2))*elliptic_pi(S(1) - e/d, atan(x), S(1)/2)/(S(4)*d**S(2)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(d - S(2)*e)*(d - e)**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), x), x, -sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(4)*(d - S(2)*e)*(d - e)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + e**S(2)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(2)*d*(d + e*x**S(2))*(d**S(2) - S(3)*d*e + S(2)*e**S(2))) - e*x*(x**S(2) + S(2))/(S(2)*d*(d**S(2) - S(3)*d*e + S(2)*e**S(2))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*e*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(2)*d*(d - S(2)*e)*(d - e)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*(S(3)*d**S(2) - S(6)*d*e + S(2)*e**S(2))*elliptic_f(atan(x), S(1)/2)/(S(4)*d*(d - S(2)*e)*(d - e)**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*e*(x**S(2) + S(2))*(S(3)*d**S(2) - S(6)*d*e + S(2)*e**S(2))*elliptic_pi(S(1) - e/d, atan(x), S(1)/2)/(S(4)*d**S(2)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(d - S(2)*e)*(d - e)**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(3)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, S(25)*x**S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + S(135)*x*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + S(75)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2)) - S(135)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(193)*x**S(2) + S(193))*elliptic_f(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, S(20)*x*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + S(25)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/S(3) - S(20)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(97)*x**S(2) + S(97))*elliptic_f(atan(x), S(1)/2)/(S(6)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, S(5)*x*(x**S(2) + S(2))/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) - S(5)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(7)*x**S(2) + S(7))*elliptic_f(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)), x), x, sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((S(5)*x**S(2) + S(7))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), x), x, sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(4)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*(S(5)*x**S(2) + S(10))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(28)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((S(5)*x**S(2) + S(7))**S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), x), x, S(5)*x*(x**S(2) + S(2))/(S(84)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - S(25)*x*sqrt(x**S(4) + S(3)*x**S(2) + S(2))/(S(420)*x**S(2) + S(588)) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(5)*x**S(2) + S(5))*elliptic_e(atan(x), S(1)/2)/(S(84)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(9)*x**S(2) + S(9))*elliptic_f(atan(x), S(1)/2)/(S(112)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*(S(65)*x**S(2) + S(130))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(2352)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(3)/(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2), x), x, x*(-S(11)*x**S(2) + S(5))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(261)*x*(x**S(2) + S(2))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(169)*x**S(2) + S(169))*elliptic_f(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(261)*x**S(2) + S(261))*elliptic_e(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))**S(2)/(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2), x), x, -S(17)*x*(x**S(2) + S(2))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(17)*x**S(2) + S(25))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + S(6)*sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(17)*x**S(2) + S(17))*elliptic_e(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(5)*x**S(2) + S(7))/(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2), x), x, -x*(x**S(2) + S(2))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(x**S(2) + S(5))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(3)*x**S(2) + S(2))**(S(-3)/2), x), x, -S(3)*x*(x**S(2) + S(2))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(3)*x**S(2) + S(5))/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_f(atan(x), S(1)/2)/sqrt(x**S(4) + S(3)*x**S(2) + S(2)) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(3)*x**S(2) + S(3))*elliptic_e(atan(x), S(1)/2)/(S(2)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((S(5)*x**S(2) + S(7))*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)), x), x, x/(S(6)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(125)*x**S(2) + S(125))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(168)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt((x**S(2) + S(2))/(S(2)*x**S(2) + S(2)))*(S(9)*x**S(2) + S(9))*elliptic_f(atan(x), S(1)/2)/(S(4)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/((S(5)*x**S(2) + S(7))*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)), x), x, -x*(x**S(2) + S(2))/(S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + x*(S(2)*x**S(2) + S(5))/(S(6)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(x**S(2) + S(1))*elliptic_e(atan(x), S(1)/2)/(S(3)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(9)*x**S(2) + S(9))*elliptic_f(atan(x), S(1)/2)/(S(8)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*(S(125)*x**S(2) + S(250))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(168)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((S(5)*x**S(2) + S(7))**S(2)*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)), x), x, S(625)*x*(x**S(2) + S(1))*(x**S(2) + S(2))/((S(2520)*x**S(2) + S(3528))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - S(125)*x*(x**S(2) + S(2))/(S(504)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - x/(S(18)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(31)*x**S(2) + S(31))*elliptic_e(atan(x), S(1)/2)/(S(56)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*(S(375)*x**S(2) + S(375))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(1568)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt((x**S(2) + S(2))/(S(2)*x**S(2) + S(2)))*(S(463)*x**S(2) + S(463))*elliptic_f(atan(x), S(1)/2)/(S(336)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/((S(5)*x**S(2) + S(7))**S(2)*(x**S(4) + S(3)*x**S(2) + S(2))**(S(3)/2)), x), x, S(625)*x*(x**S(2) + S(1))*(x**S(2) + S(2))/((S(2520)*x**S(2) + S(3528))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - S(125)*x*(x**S(2) + S(2))/(S(504)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - x/(S(18)*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + (S(125)*x**S(2) + S(125))*elliptic_pi(S(-3)/7, atan(sqrt(S(2))*x/S(2)), S(-1))/(S(189)*sqrt((x**S(2) + S(1))/(x**S(2) + S(2)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*(S(31)*x**S(2) + S(62))*elliptic_e(atan(x), S(1)/2)/(S(56)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) + sqrt(S(2))*(S(6875)*x**S(2) + S(13750))*elliptic_pi(S(2)/7, atan(x), S(1)/2)/(S(14112)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))) - sqrt(S(2))*(S(7667)*x**S(2) + S(15334))*elliptic_f(atan(x), S(1)/2)/(S(6048)*sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(3))/sqrt(-x**S(4) + x**S(2) + S(3)), x), x, -sqrt(S(-1)/2 + sqrt(S(13))/S(2))*elliptic_e(asin(sqrt(S(2))*x/sqrt(S(1) + sqrt(S(13)))), S(-7)/6 - sqrt(S(13))/S(6)) + sqrt(S(7) + S(2)*sqrt(S(13)))*elliptic_f(asin(sqrt(S(2))*x/sqrt(S(1) + sqrt(S(13)))), S(-7)/6 - sqrt(S(13))/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(3))/sqrt(-x**S(4) + S(2)*x**S(2) + S(3)), x), x, -elliptic_e(asin(sqrt(S(3))*x/S(3)), S(-3)) + S(4)*elliptic_f(asin(sqrt(S(3))*x/S(3)), S(-3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(3))/sqrt(-x**S(4) + S(3)*x**S(2) + S(3)), x), x, -sqrt(S(-3)/2 + sqrt(S(21))/S(2))*elliptic_e(asin(sqrt(S(2))*x/sqrt(S(3) + sqrt(S(21)))), S(-5)/2 - sqrt(S(21))/S(2)) + sqrt(S(9) + S(2)*sqrt(S(21)))*elliptic_f(asin(sqrt(S(2))*x/sqrt(S(3) + sqrt(S(21)))), S(-5)/2 - sqrt(S(21))/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(3))/sqrt(-x**S(4) - x**S(2) + S(3)), x), x, -sqrt(S(1)/2 + sqrt(S(13))/S(2))*elliptic_e(asin(sqrt(S(2))*x/sqrt(S(-1) + sqrt(S(13)))), S(-7)/6 + sqrt(S(13))/S(6)) + sqrt(S(5) + S(2)*sqrt(S(13)))*elliptic_f(asin(sqrt(S(2))*x/sqrt(S(-1) + sqrt(S(13)))), S(-7)/6 + sqrt(S(13))/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(3))/sqrt(-x**S(4) - S(2)*x**S(2) + S(3)), x), x, -sqrt(S(3))*elliptic_e(asin(x), S(-1)/3) + S(2)*sqrt(S(3))*elliptic_f(asin(x), S(-1)/3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(2) + S(3))/sqrt(-x**S(4) - S(3)*x**S(2) + S(3)), x), x, -sqrt(S(3)/2 + sqrt(S(21))/S(2))*elliptic_e(asin(sqrt(S(2))*x/sqrt(S(-3) + sqrt(S(21)))), S(-5)/2 + sqrt(S(21))/S(2)) + sqrt(S(3) + S(2)*sqrt(S(21)))*elliptic_f(asin(sqrt(S(2))*x/sqrt(S(-3) + sqrt(S(21)))), S(-5)/2 + sqrt(S(21))/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x**S(2) - sqrt(-S(4)*a*c + b**S(2)))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/sqrt(a + b*x**S(2) + c*x**S(4)) + S(2)*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2)) + sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*sqrt(a)*sqrt(c) + b - sqrt(-S(4)*a*c + b**S(2)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(2))/((x**S(2) + S(1))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), x), x, sqrt(S(2))*(x**S(2) + S(2))*elliptic_e(atan(x), S(1)/2)/(sqrt((x**S(2) + S(2))/(x**S(2) + S(1)))*sqrt(x**S(4) + S(3)*x**S(2) + S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(5)/2)*(a + b*x**S(2) + c*x**S(4)), x), x, c*x**S(3)*(d + e*x**S(2))**(S(7)/2)/(S(10)*e) + d**S(3)*(S(80)*a*e**S(2) - S(10)*b*d*e + S(3)*c*d**S(2))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(256)*e**(S(5)/2)) + d**S(2)*x*sqrt(d + e*x**S(2))*(S(80)*a*e**S(2) - S(10)*b*d*e + S(3)*c*d**S(2))/(S(256)*e**S(2)) + d*x*(d + e*x**S(2))**(S(3)/2)*(S(80)*a*e**S(2) - S(10)*b*d*e + S(3)*c*d**S(2))/(S(384)*e**S(2)) - x*(d + e*x**S(2))**(S(7)/2)*(-S(10)*b*e + S(3)*c*d)/(S(80)*e**S(2)) + x*(d + e*x**S(2))**(S(5)/2)*(S(80)*a*e**S(2) - S(10)*b*d*e + S(3)*c*d**S(2))/(S(480)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4)), x), x, c*x**S(3)*(d + e*x**S(2))**(S(5)/2)/(S(8)*e) + d**S(2)*(S(48)*a*e**S(2) - S(8)*b*d*e + S(3)*c*d**S(2))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(128)*e**(S(5)/2)) + d*x*sqrt(d + e*x**S(2))*(S(48)*a*e**S(2) - S(8)*b*d*e + S(3)*c*d**S(2))/(S(128)*e**S(2)) - x*(d + e*x**S(2))**(S(5)/2)*(-S(8)*b*e + S(3)*c*d)/(S(48)*e**S(2)) + x*(d + e*x**S(2))**(S(3)/2)*(S(48)*a*e**S(2) - S(8)*b*d*e + S(3)*c*d**S(2))/(S(192)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, c*x**S(3)*(d + e*x**S(2))**(S(3)/2)/(S(6)*e) + d*(S(8)*a*e**S(2) - S(2)*b*d*e + c*d**S(2))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(16)*e**(S(5)/2)) - x*(d + e*x**S(2))**(S(3)/2)*(-S(2)*b*e + c*d)/(S(8)*e**S(2)) + x*sqrt(d + e*x**S(2))*(S(8)*a*e**S(2) - S(2)*b*d*e + c*d**S(2))/(S(16)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/sqrt(d + e*x**S(2)), x), x, c*x**S(3)*sqrt(d + e*x**S(2))/(S(4)*e) - x*sqrt(d + e*x**S(2))*(-S(4)*b*e + S(3)*c*d)/(S(8)*e**S(2)) + (S(8)*a*e**S(2) - S(4)*b*d*e + S(3)*c*d**S(2))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(8)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**(S(3)/2), x), x, c*x*sqrt(d + e*x**S(2))/(S(2)*e**S(2)) - (-S(2)*b*e + S(3)*c*d)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*e**(S(5)/2)) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(d*e**S(2)*sqrt(d + e*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**(S(5)/2), x), x, c*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/e**(S(5)/2) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(3)*d*e**S(2)*(d + e*x**S(2))**(S(3)/2)) - x*(S(4)*c*d**S(2) - e*(S(2)*a*e + b*d))/(S(3)*d**S(2)*e**S(2)*sqrt(d + e*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**(S(7)/2), x), x, x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(5)*d*e**S(2)*(d + e*x**S(2))**(S(5)/2)) - x*(c*d**S(2) - S(5)*c*d*e*x**S(2) - e*(S(4)*a*e + b*d))/(S(15)*d**S(2)*e**S(2)*(d + e*x**S(2))**(S(3)/2)) - x*(S(2)*c*d**S(2) - S(2)*e*(S(4)*a*e + b*d))/(S(15)*d**S(3)*e**S(2)*sqrt(d + e*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**(S(9)/2), x), x, x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(7)*d*e**S(2)*(d + e*x**S(2))**(S(7)/2)) - x*(S(8)*c*d**S(2) - e*(S(6)*a*e + b*d))/(S(35)*d**S(2)*e**S(2)*(d + e*x**S(2))**(S(5)/2)) + x*(S(3)*c*d**S(2) + S(4)*e*(S(6)*a*e + b*d))/(S(105)*d**S(3)*e**S(2)*(d + e*x**S(2))**(S(3)/2)) + x*(S(6)*c*d**S(2) + S(8)*e*(S(6)*a*e + b*d))/(S(105)*d**S(4)*e**S(2)*sqrt(d + e*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**(S(11)/2), x), x, x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(9)*d*e**S(2)*(d + e*x**S(2))**(S(9)/2)) - x*(S(10)*c*d**S(2) - e*(S(8)*a*e + b*d))/(S(63)*d**S(2)*e**S(2)*(d + e*x**S(2))**(S(7)/2)) + x*(c*d**S(2) + S(2)*e*(S(8)*a*e + b*d))/(S(105)*d**S(3)*e**S(2)*(d + e*x**S(2))**(S(5)/2)) + x*(S(4)*c*d**S(2) + S(8)*e*(S(8)*a*e + b*d))/(S(315)*d**S(4)*e**S(2)*(d + e*x**S(2))**(S(3)/2)) + x*(S(8)*c*d**S(2) + S(16)*e*(S(8)*a*e + b*d))/(S(315)*d**S(5)*e**S(2)*sqrt(d + e*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(3)/(a + c*x**(S(2)*n)), x), x, S(3)*d*e**S(2)*x/c + e**S(3)*x**(n + S(1))/(c*(n + S(1))) - x*(-a*e**S(3) + sqrt(c)*d*(-S(3)*a*e**S(2) + c*d**S(2))/sqrt(-a) + S(3)*c*d**S(2)*e)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*c**(S(3)/2)*sqrt(-a)) + x*(-S(3)*a*sqrt(c)*d*e**S(2) + a*e**S(3)*sqrt(-a) + c**(S(3)/2)*d**S(3) - S(3)*c*d**S(2)*e*sqrt(-a))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(2)/(a + c*x**(S(2)*n)), x), x, e**S(2)*x/c + x*(-a*e**S(2) - S(2)*sqrt(c)*d*e*sqrt(-a) + c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*c) + x*(-a*e**S(2) + S(2)*sqrt(c)*d*e*sqrt(-a) + c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + c*x**(S(2)*n)), x), x, x*(d - e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a) + x*(d + e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))*(d + e*x**n)), x), x, e**S(2)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))) + c*x*(d - e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))) + c*x*(d + e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))*(d + e*x**n)**S(2)), x), x, S(2)*c*e**S(2)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(a*e**S(2) + c*d**S(2))**S(2) + e**S(2)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(2)*(a*e**S(2) + c*d**S(2))) + c*x*(-a*e**S(2) - S(2)*sqrt(c)*d*e*sqrt(-a) + c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(2)) + c*x*(-a*e**S(2) + S(2)*sqrt(c)*d*e*sqrt(-a) + c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))*(d + e*x**n)**S(3)), x), x, c**(S(3)/2)*x*(-a*e**S(3) - sqrt(c)*d*(-S(3)*a*e**S(2) + c*d**S(2))/sqrt(-a) + S(3)*c*d**S(2)*e)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*sqrt(-a)*(a*e**S(2) + c*d**S(2))**S(3)) + c*e**S(2)*x*(-a*e**S(2) + S(3)*c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(3)) + S(2)*c*e**S(2)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(2)) + e**S(2)*x*hyper((S(3), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(3)*(a*e**S(2) + c*d**S(2))) + c**(S(3)/2)*x*(-S(3)*a*sqrt(c)*d*e**S(2) + c**(S(3)/2)*d**S(3) + S(3)*c*d**S(2)*e*sqrt(-a) + e**S(3)*(-a)**(S(3)/2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a - c*x**(S(2)*n)), x), x, x*(-sqrt(a)*e/sqrt(c) + d)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(a))/(S(2)*a) + x*(sqrt(a)*e/sqrt(c) + d)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(a))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(3)/(a + c*x**(S(2)*n))**S(2), x), x, -x*(sqrt(c)*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) - (-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*c**(S(3)/2)*n*(-a)**(S(3)/2)) - x*(sqrt(c)*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) + (-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*c**(S(3)/2)*n*(-a)**(S(3)/2)) + e**S(2)*x*(S(3)*d - e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*c) + e**S(2)*x*(S(3)*d + e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*c) + x*(d*(-S(3)*a*e**S(2) + c*d**S(2)) + e*x**n*(-a*e**S(2) + S(3)*c*d**S(2)))/(S(2)*a*c*n*(a + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(2)/(a + c*x**(S(2)*n))**S(2), x), x, e**S(2)*x*hyper((S(1), S(1)/(S(2)*n)), (S(1) + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(a*c) + x*(-a*e**S(2) + c*d**S(2) + S(2)*c*d*e*x**n)/(S(2)*a*c*n*(a + c*x**(S(2)*n))) - x*(-a*e**S(2)*(-S(2)*n + S(1)) - S(2)*sqrt(c)*d*e*sqrt(-a)*(-n + S(1)) + c*d**S(2)*(-S(2)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*c*n) - x*(-a*e**S(2)*(-S(2)*n + S(1)) + S(2)*sqrt(c)*d*e*sqrt(-a)*(-n + S(1)) + c*d**S(2)*(-S(2)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*c*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + c*x**(S(2)*n))**S(2), x), x, x*(d + e*x**n)/(S(2)*a*n*(a + c*x**(S(2)*n))) - x*(sqrt(c)*(-S(2)*d*n + d) + e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*sqrt(c)*n) - x*(sqrt(c)*d*(-S(2)*n + S(1)) - e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*sqrt(c)*n), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))**S(2)*(d + e*x**n)), x), x, e**S(4)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(2)) + c*e**S(2)*x*(d - e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(2)) + c*e**S(2)*x*(d + e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(2)) + c*x*(d - e*x**n)/(S(2)*a*n*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))) - sqrt(c)*x*(sqrt(c)*(-S(2)*d*n + d) + e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))) - sqrt(c)*x*(sqrt(c)*d*(-S(2)*n + S(1)) - e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))), expand=True, _diff=True, _numerical=True) # apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))**S(2)*(d + e*x**n)**S(2)), x), x, S(4)*c*e**S(4)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(a*e**S(2) + c*d**S(2))**S(3) + e**S(4)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(2)*(a*e**S(2) + c*d**S(2))**S(2)) + c*e**S(2)*x*(-a*e**S(2) - S(4)*sqrt(c)*d*e*sqrt(-a) + S(3)*c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(3)) + c*e**S(2)*x*(-a*e**S(2) + S(4)*sqrt(c)*d*e*sqrt(-a) + S(3)*c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(3)) + c*x*(-a*e**S(2) + c*d**S(2) - S(2)*c*d*e*x**n)/(S(2)*a*n*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))**S(2)) - c*x*(-a*e**S(2)*(-S(2)*n + S(1)) - S(2)*sqrt(c)*d*e*sqrt(-a)*(-n + S(1)) + c*d**S(2)*(-S(2)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))**S(2)) - c*x*(-a*e**S(2)*(-S(2)*n + S(1)) + S(2)*sqrt(c)*d*e*sqrt(-a)*(-n + S(1)) + c*d**S(2)*(-S(2)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) # apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))**S(2)*(d + e*x**n)**S(3)), x), x, c**(S(3)/2)*e**S(2)*x*(-a*e**S(3) - S(3)*sqrt(c)*d*(-a*e**S(2) + c*d**S(2))/sqrt(-a) + S(5)*c*d**S(2)*e)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(sqrt(-a)*(a*e**S(2) + c*d**S(2))**S(4)) - c**(S(3)/2)*x*(sqrt(c)*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) - (-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*n*(-a)**(S(3)/2)*(a*e**S(2) + c*d**S(2))**S(3)) - c**(S(3)/2)*x*(sqrt(c)*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) + (-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*n*(-a)**(S(3)/2)*(a*e**S(2) + c*d**S(2))**S(3)) + S(2)*c*e**S(4)*x*(-a*e**S(2) + S(5)*c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(4)) + S(4)*c*e**S(4)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(3)) + e**S(4)*x*hyper((S(3), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(3)*(a*e**S(2) + c*d**S(2))**S(2)) + c**(S(3)/2)*e**S(2)*x*(-S(3)*a*sqrt(c)*d*e**S(2) + S(3)*c**(S(3)/2)*d**S(3) + S(5)*c*d**S(2)*e*sqrt(-a) + e**S(3)*(-a)**(S(3)/2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(a*(a*e**S(2) + c*d**S(2))**S(4)) + c**S(2)*x*(d*(-S(3)*a*e**S(2) + c*d**S(2)) - e*x**n*(-a*e**S(2) + S(3)*c*d**S(2)))/(S(2)*a*n*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(3)/(a + c*x**(S(2)*n))**S(3), x), x, -x*(sqrt(c)*(-S(4)*n + S(1))*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) - (-S(3)*n + S(1))*(-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(16)*c**(S(3)/2)*n**S(2)*(-a)**(S(5)/2)) - x*(sqrt(c)*(-S(4)*n + S(1))*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) + (-S(3)*n + S(1))*(-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(16)*c**(S(3)/2)*n**S(2)*(-a)**(S(5)/2)) + e**S(2)*x*(S(3)*d + e*x**n)/(S(2)*a*c*n*(a + c*x**(S(2)*n))) + x*(d*(-S(3)*a*e**S(2) + c*d**S(2)) + e*x**n*(-a*e**S(2) + S(3)*c*d**S(2)))/(S(4)*a*c*n*(a + c*x**(S(2)*n))**S(2)) - x*(d*(-S(4)*n + S(1))*(-S(3)*a*e**S(2) + c*d**S(2)) + e*x**n*(-S(3)*n + S(1))*(-a*e**S(2) + S(3)*c*d**S(2)))/(S(8)*a**S(2)*c*n**S(2)*(a + c*x**(S(2)*n))) - e**S(2)*x*(sqrt(c)*d*(-S(6)*n + S(3)) - e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*c**(S(3)/2)*n) - e**S(2)*x*(sqrt(c)*d*(-S(6)*n + S(3)) + e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*c**(S(3)/2)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(2)/(a + c*x**(S(2)*n))**S(3), x), x, x*(-a*e**S(2) + c*d**S(2) + S(2)*c*d*e*x**n)/(S(4)*a*c*n*(a + c*x**(S(2)*n))**S(2)) + e**S(2)*x*hyper((S(2), S(1)/(S(2)*n)), (S(1) + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(a**S(2)*c) - x*(S(2)*c*d*e*x**n*(-S(3)*n + S(1)) + (-S(4)*n + S(1))*(-a*e**S(2) + c*d**S(2)))/(S(8)*a**S(2)*c*n**S(2)*(a + c*x**(S(2)*n))) + x*(-a*e**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*sqrt(c)*d*e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)) + c*d**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*c*n**S(2)) - x*(a*e**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*sqrt(c)*d*e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)) - c*d**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*c*n**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + c*x**(S(2)*n))**S(3), x), x, x*(d + e*x**n)/(S(4)*a*n*(a + c*x**(S(2)*n))**S(2)) - x*(d*(-S(4)*n + S(1)) + e*x**n*(-S(3)*n + S(1)))/(S(8)*a**S(2)*n**S(2)*(a + c*x**(S(2)*n))) - x*(-sqrt(c)*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*sqrt(c)*n**S(2)) + x*(sqrt(c)*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*sqrt(c)*n**S(2)), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))**S(3)*(d + e*x**n)), x), x, e**S(6)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(3)) + c*e**S(4)*x*(d - e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(3)) + c*e**S(4)*x*(d + e*sqrt(-a)/sqrt(c))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(3)) + c*e**S(2)*x*(d - e*x**n)/(S(2)*a*n*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))**S(2)) + c*x*(d - e*x**n)/(S(4)*a*n*(a + c*x**(S(2)*n))**S(2)*(a*e**S(2) + c*d**S(2))) - sqrt(c)*e**S(2)*x*(sqrt(c)*(-S(2)*d*n + d) + e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))**S(2)) - sqrt(c)*e**S(2)*x*(sqrt(c)*d*(-S(2)*n + S(1)) - e*sqrt(-a)*(-n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))**S(2)) - c*x*(d*(-S(4)*n + S(1)) - e*x**n*(-S(3)*n + S(1)))/(S(8)*a**S(2)*n**S(2)*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))) - sqrt(c)*x*(-sqrt(c)*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*n**S(2)*(a*e**S(2) + c*d**S(2))) + sqrt(c)*x*(sqrt(c)*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*n**S(2)*(a*e**S(2) + c*d**S(2))), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))**S(3)*(d + e*x**n)**S(2)), x), x, S(6)*c*e**S(6)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(a*e**S(2) + c*d**S(2))**S(4) + e**S(6)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(2)*(a*e**S(2) + c*d**S(2))**S(3)) + c*e**S(4)*x*(-a*e**S(2) - S(6)*sqrt(c)*d*e*sqrt(-a) + S(5)*c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(4)) + c*e**S(4)*x*(-a*e**S(2) + S(6)*sqrt(c)*d*e*sqrt(-a) + S(5)*c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(4)) + c*e**S(2)*x*(-a*e**S(2) + S(3)*c*d**S(2) - S(4)*c*d*e*x**n)/(S(2)*a*n*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))**S(3)) + c*x*(-a*e**S(2) + c*d**S(2) - S(2)*c*d*e*x**n)/(S(4)*a*n*(a + c*x**(S(2)*n))**S(2)*(a*e**S(2) + c*d**S(2))**S(2)) - c*e**S(2)*x*(-a*e**S(2)*(-S(2)*n + S(1)) - S(4)*sqrt(c)*d*e*sqrt(-a)*(-n + S(1)) + S(3)*c*d**S(2)*(-S(2)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))**S(3)) - c*e**S(2)*x*(-a*e**S(2)*(-S(2)*n + S(1)) + S(4)*sqrt(c)*d*e*sqrt(-a)*(-n + S(1)) + S(3)*c*d**S(2)*(-S(2)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(4)*a**S(2)*n*(a*e**S(2) + c*d**S(2))**S(3)) - c*x*(-S(2)*c*d*e*x**n*(-S(3)*n + S(1)) + (-S(4)*n + S(1))*(-a*e**S(2) + c*d**S(2)))/(S(8)*a**S(2)*n**S(2)*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))**S(2)) + c*x*(-a*e**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*sqrt(c)*d*e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)) + c*d**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*n**S(2)*(a*e**S(2) + c*d**S(2))**S(2)) - c*x*(a*e**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*sqrt(c)*d*e*sqrt(-a)*(S(3)*n**S(2) - S(4)*n + S(1)) - c*d**S(2)*(S(8)*n**S(2) - S(6)*n + S(1)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(16)*a**S(3)*n**S(2)*(a*e**S(2) + c*d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((a + c*x**(S(2)*n))**S(3)*(d + e*x**n)**S(3)), x), x, S(3)*c**(S(3)/2)*e**S(4)*x*(-a*e**S(3) - sqrt(c)*d*(-S(3)*a*e**S(2) + S(5)*c*d**S(2))/sqrt(-a) + S(7)*c*d**S(2)*e)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*sqrt(-a)*(a*e**S(2) + c*d**S(2))**S(5)) - c**(S(3)/2)*e**S(2)*x*(S(3)*sqrt(c)*(-S(2)*n + S(1))*(-a*d*e**S(2) + c*d**S(3))/sqrt(-a) - (-n + S(1))*(-a*e**S(3) + S(5)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(2)*n*(-a)**(S(3)/2)*(a*e**S(2) + c*d**S(2))**S(4)) - c**(S(3)/2)*e**S(2)*x*(S(3)*sqrt(c)*(-S(2)*n + S(1))*(-a*d*e**S(2) + c*d**S(3))/sqrt(-a) + (-n + S(1))*(-a*e**S(3) + S(5)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*n*(-a)**(S(3)/2)*(a*e**S(2) + c*d**S(2))**S(4)) - c**(S(3)/2)*x*(sqrt(c)*(-S(4)*n + S(1))*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) - (-S(3)*n + S(1))*(-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), sqrt(c)*x**n/sqrt(-a))/(S(16)*n**S(2)*(-a)**(S(5)/2)*(a*e**S(2) + c*d**S(2))**S(3)) - c**(S(3)/2)*x*(sqrt(c)*(-S(4)*n + S(1))*(-S(2)*n + S(1))*(-S(3)*a*d*e**S(2) + c*d**S(3))/sqrt(-a) + (-S(3)*n + S(1))*(-n + S(1))*(-a*e**S(3) + S(3)*c*d**S(2)*e))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(16)*n**S(2)*(-a)**(S(5)/2)*(a*e**S(2) + c*d**S(2))**S(3)) + S(3)*c*e**S(6)*x*(-a*e**S(2) + S(7)*c*d**S(2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(5)) + S(6)*c*e**S(6)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) + c*d**S(2))**S(4)) + e**S(6)*x*hyper((S(3), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(3)*(a*e**S(2) + c*d**S(2))**S(3)) + S(3)*c**(S(3)/2)*e**S(4)*x*(-S(3)*a*sqrt(c)*d*e**S(2) + S(5)*c**(S(3)/2)*d**S(3) + S(7)*c*d**S(2)*e*sqrt(-a) + e**S(3)*(-a)**(S(3)/2))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -sqrt(c)*x**n/sqrt(-a))/(S(2)*a*(a*e**S(2) + c*d**S(2))**S(5)) + c**S(2)*e**S(2)*x*(S(3)*d*(-a*e**S(2) + c*d**S(2)) - e*x**n*(-a*e**S(2) + S(5)*c*d**S(2)))/(a*n*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))**S(4)) + c**S(2)*x*(d*(-S(3)*a*e**S(2) + c*d**S(2)) - e*x**n*(-a*e**S(2) + S(3)*c*d**S(2)))/(S(4)*a*n*(a + c*x**(S(2)*n))**S(2)*(a*e**S(2) + c*d**S(2))**S(3)) - c**S(2)*x*(d*(-S(4)*n + S(1))*(-S(3)*a*e**S(2) + c*d**S(2)) - e*x**n*(-S(3)*n + S(1))*(-a*e**S(2) + S(3)*c*d**S(2)))/(S(8)*a**S(2)*n**S(2)*(a + c*x**(S(2)*n))*(a*e**S(2) + c*d**S(2))**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**(S(2)*n))**p*(d + e*x**n)**S(3), x), x, d**S(3)*x*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper((S(1)/(S(2)*n), -p), (S(1) + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a) + S(3)*d**S(2)*e*x**(n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((n + S(1))/(S(2)*n), -p), (S(3)/2 + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(n + S(1)) + S(3)*d*e**S(2)*x**(S(2)*n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper((S(1) + S(1)/(S(2)*n), -p), (S(2) + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(S(2)*n + S(1)) + e**S(3)*x**(S(3)*n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper((S(3)/2 + S(1)/(S(2)*n), -p), (S(5)/2 + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(S(3)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**(S(2)*n))**p*(d + e*x**n)**S(2), x), x, d**S(2)*x*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper((S(1)/(S(2)*n), -p), (S(1) + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a) + S(2)*d*e*x**(n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((n + S(1))/(S(2)*n), -p), (S(3)/2 + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(n + S(1)) + e**S(2)*x**(S(2)*n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper((S(1) + S(1)/(S(2)*n), -p), (S(2) + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**(S(2)*n))**p*(d + e*x**n), x), x, d*x*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper((S(1)/(S(2)*n), -p), (S(1) + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a) + e*x**(n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((n + S(1))/(S(2)*n), -p), (S(3)/2 + S(1)/(S(2)*n),), -c*x**(S(2)*n)/a)/(n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n)), x), x, a*d*x + c*e*x**(S(3)*n + S(1))/(S(3)*n + S(1)) + x**(n + S(1))*(a*e + b*d)/(n + S(1)) + x**(S(2)*n + S(1))*(b*e + c*d)/(S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, a**S(2)*d*x + a*x**(n + S(1))*(a*e + S(2)*b*d)/(n + S(1)) + c**S(2)*e*x**(S(5)*n + S(1))/(S(5)*n + S(1)) + c*x**(S(4)*n + S(1))*(S(2)*b*e + c*d)/(S(4)*n + S(1)) + x**(S(2)*n + S(1))*(S(2)*a*b*e + S(2)*a*c*d + b**S(2)*d)/(S(2)*n + S(1)) + x**(S(3)*n + S(1))*(S(2)*a*c*e + b**S(2)*e + S(2)*b*c*d)/(S(3)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**S(3), x), x, a**S(3)*d*x + a**S(2)*x**(n + S(1))*(a*e + S(3)*b*d)/(n + S(1)) + S(3)*a*x**(S(2)*n + S(1))*(a*b*e + a*c*d + b**S(2)*d)/(S(2)*n + S(1)) + c**S(3)*e*x**(S(7)*n + S(1))/(S(7)*n + S(1)) + c**S(2)*x**(S(6)*n + S(1))*(S(3)*b*e + c*d)/(S(6)*n + S(1)) + S(3)*c*x**(S(5)*n + S(1))*(a*c*e + b**S(2)*e + b*c*d)/(S(5)*n + S(1)) + x**(S(3)*n + S(1))*(S(3)*a**S(2)*c*e + S(3)*a*b**S(2)*e + S(6)*a*b*c*d + b**S(3)*d)/(S(3)*n + S(1)) + x**(S(4)*n + S(1))*(S(6)*a*b*c*e + S(3)*a*c**S(2)*d + b**S(3)*e + S(3)*b**S(2)*c*d)/(S(4)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(3)/(a + b*x**n + c*x**(S(2)*n)), x), x, e**S(3)*x**(n + S(1))/(c*(n + S(1))) + e**S(2)*x*(-b*e + S(3)*c*d)/c**S(2) + x*(-a*c*e**S(3) + b**S(2)*e**S(3) - S(3)*b*c*d*e**S(2) + S(3)*c**S(2)*d**S(2)*e - (-b*e + S(2)*c*d)*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(c**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))) + x*(-a*c*e**S(3) + b**S(2)*e**S(3) - S(3)*b*c*d*e**S(2) + S(3)*c**S(2)*d**S(2)*e + (-b*e + S(2)*c*d)*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - c*e*(S(3)*a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(c**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(2)/(a + b*x**n + c*x**(S(2)*n)), x), x, e**S(2)*x/c + x*(-b*e**S(2) + S(2)*c*d*e - (b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(c*(b + sqrt(-S(4)*a*c + b**S(2)))) + x*(-b*e**S(2) + S(2)*c*d*e + (b**S(2)*e**S(2) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(c*(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + b*x**n + c*x**(S(2)*n)), x), x, x*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(b + sqrt(-S(4)*a*c + b**S(2))) + x*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(b - sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))), x), x, -c*x*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) - c*x*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) + e**S(2)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((d + e*x**n)**S(2)*(a + b*x**n + c*x**(S(2)*n))), x), x, -c*x*(b*e**S(2)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d - d*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - c*x*(b*e**S(2)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d + d*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**S(2)*x*(-b*e + S(2)*c*d)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**S(2)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate(S(1)/((d + e*x**n)**S(3)*(a + b*x**n + c*x**(S(2)*n))), x), x, -c*x*(-b**S(2)*e**S(3)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(3)*d**S(3) - S(3)*c**S(2)*d*e*(S(2)*a*e + b*d - d*sqrt(-S(4)*a*c + b**S(2))) + c*e**S(2)*(S(3)*a*b*e - a*e*sqrt(-S(4)*a*c + b**S(2)) + S(3)*b**S(2)*d - S(3)*b*d*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) - c*x*(-b**S(2)*e**S(3)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(3)*d**S(3) - S(3)*c**S(2)*d*e*(S(2)*a*e + b*d + d*sqrt(-S(4)*a*c + b**S(2))) + c*e**S(2)*(a*e*sqrt(-S(4)*a*c + b**S(2)) + S(3)*b**S(2)*d + S(3)*b*(a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + e**S(2)*x*(b**S(2)*e**S(2) + S(3)*c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + e**S(2)*x*(-b*e + S(2)*c*d)*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**S(2)*x*hyper((S(3), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(3)*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(3)/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, e**S(2)*x*(e - (-S(3)*b*e + S(6)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(c*(b + sqrt(-S(4)*a*c + b**S(2)))) + e**S(2)*x*(e + (-S(3)*b*e + S(6)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(c*(b - sqrt(-S(4)*a*c + b**S(2)))) + x*(-a*b*e*(a*e**S(2) + S(3)*c*d**S(2)) - S(2)*a*c*d*(-S(3)*a*e**S(2) + c*d**S(2)) + b**S(2)*c*d**S(3) - x**n*(a*b**S(2)*e**S(3) + S(2)*a*c*e*(-a*e**S(2) + S(3)*c*d**S(2)) - b*c*d*(S(3)*a*e**S(2) + c*d**S(2))))/(a*c*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + x*((-n + S(1))*(a*b**S(2)*e**S(3) + S(2)*a*c*e*(-a*e**S(2) + S(3)*c*d**S(2)) - b*c*d*(S(3)*a*e**S(2) + c*d**S(2))) - (-a*b**S(3)*e**S(3)*(-S(3)*n + S(1)) + S(2)*a*b*c*e*(a*e**S(2)*(-S(5)*n + S(2)) + S(3)*c*d**S(2)*n) + S(4)*a*c**S(2)*d*(-S(2)*n + S(1))*(-S(3)*a*e**S(2) + c*d**S(2)) + b**S(2)*c*d*(S(3)*a*e**S(2)*(-S(3)*n + S(1)) - c*d**S(2)*(-n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*c*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + x*((-n + S(1))*(a*b**S(2)*e**S(3) + S(2)*a*c*e*(-a*e**S(2) + S(3)*c*d**S(2)) - b*c*d*(S(3)*a*e**S(2) + c*d**S(2))) + (-a*b**S(3)*e**S(3)*(-S(3)*n + S(1)) + S(2)*a*b*c*e*(a*e**S(2)*(-S(5)*n + S(2)) + S(3)*c*d**S(2)*n) + S(4)*a*c**S(2)*d*(-S(2)*n + S(1))*(-S(3)*a*e**S(2) + c*d**S(2)) + b**S(2)*c*d*(S(3)*a*e**S(2)*(-S(3)*n + S(1)) - c*d**S(2)*(-n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*c*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(2)/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, -S(2)*e**S(2)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*e**S(2)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) + x*(-S(2)*a*b*d*e - S(2)*a*(-a*e**S(2) + c*d**S(2)) + b**S(2)*d**S(2) + x**n*(a*b*e**S(2) - S(4)*a*c*d*e + b*c*d**S(2)))/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) - x*((-n + S(1))*(a*b*e**S(2) - S(4)*a*c*d*e + b*c*d**S(2)) + (S(4)*a*b*c*d*e*n + S(4)*a*c*(-S(2)*n + S(1))*(-a*e**S(2) + c*d**S(2)) + b**S(2)*(a*e**S(2)*(-S(3)*n + S(1)) - c*d**S(2)*(-n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) - x*((-n + S(1))*(a*b*e**S(2) - S(4)*a*c*d*e + b*c*d**S(2)) - (S(4)*a*b*c*d*e*n + S(4)*a*c*(-S(2)*n + S(1))*(-a*e**S(2) + c*d**S(2)) + b**S(2)*(a*e**S(2)*(-S(3)*n + S(1)) - c*d**S(2)*(-n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, -c*x*(S(2)*a*(c*d*(-S(4)*n + S(2)) - e*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*d*(-n + S(1)) + b*(S(2)*a*e*n + d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*x*(S(2)*a*(S(2)*c*d*(-S(2)*n + S(1)) + e*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*(-d*n + d) - b*(-S(2)*a*e*n + d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + x*(-a*b*e - S(2)*a*c*d + b**S(2)*d + c*x**n*(-S(2)*a*e + b*d))/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) #Apart assert rubi_test(rubi_integrate(S(1)/((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**S(2)), x), x, -c*e**S(2)*x*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - c*e**S(2)*x*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**S(4)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + c*x*(-S(2)*a*c*(S(2)*c*d*(-S(2)*n + S(1)) + e*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))) - b**S(3)*e*(-n + S(1)) + b**S(2)*(-n + S(1))*(c*d + e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(S(2)*a*e*(-S(3)*n + S(2)) - d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) - c*x*((-n + S(1))*(S(2)*a*c*e - b**S(2)*e + b*c*d) + (S(2)*a*b*c*e*(-S(3)*n + S(2)) - S(4)*a*c**S(2)*d*(-S(2)*n + S(1)) - b**S(3)*e*(-n + S(1)) + b**S(2)*c*d*(-n + S(1)))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + x*(S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d + c*x**n*(S(2)*a*c*e - b**S(2)*e + b*c*d))/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) #Apart assert rubi_test(rubi_integrate(S(1)/((d + e*x**n)**S(2)*(a + b*x**n + c*x**(S(2)*n))**S(2)), x), x, -S(2)*c*e**S(2)*x*(b*e**S(2)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(3)*c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d - S(2)*d*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) - S(2)*c*e**S(2)*x*(b*e**S(2)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(3)*c**S(2)*d**S(2) - c*e*(a*e + S(3)*b*d + S(2)*d*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + S(2)*e**S(4)*x*(-b*e + S(2)*c*d)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + e**S(4)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + c*x*(S(4)*a*c**S(2)*(-c*d**S(2)*(-S(2)*n + S(1)) + e*(a*e*(-S(2)*n + S(1)) - d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + b**S(4)*e**S(2)*(-n + S(1)) - b**S(3)*e*(-n + S(1))*(S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*c*(-c*d**S(2)*(-n + S(1)) + e*(a*e*(-S(7)*n + S(5)) - S(2)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + b*c*(S(3)*a*e**S(2)*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)) + c*d*(S(4)*a*e*(-S(3)*n + S(2)) - d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + c*x*(S(4)*a*c**S(2)*(-c*d**S(2)*(-S(2)*n + S(1)) + e*(a*e*(-S(2)*n + S(1)) + d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + b**S(4)*e**S(2)*(-n + S(1)) - b**S(3)*e*(-n + S(1))*(S(2)*c*d - e*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*c*(-c*d**S(2)*(-n + S(1)) + e*(a*e*(-S(7)*n + S(5)) + S(2)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + b*c*(-S(3)*a*e**S(2)*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)) + c*d*(S(4)*a*e*(-S(3)*n + S(2)) + d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - x*(-S(6)*a*b*c**S(2)*d*e + S(2)*a*c**S(2)*(-a*e**S(2) + c*d**S(2)) - b**S(4)*e**S(2) + S(2)*b**S(3)*c*d*e - b**S(2)*c*(-S(4)*a*e**S(2) + c*d**S(2)) + c*x**n*(-S(4)*a*c**S(2)*d*e - b**S(3)*e**S(2) + S(2)*b**S(2)*c*d*e - b*c*(-S(3)*a*e**S(2) + c*d**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(3)/(a + b*x**n + c*x**(S(2)*n))**S(3), x), x, e**S(2)*x*(-S(2)*a*c*(S(6)*c*d*(-S(2)*n + S(1)) - e*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))) - b**S(3)*e*(-n + S(1)) + b**S(2)*(-n + S(1))*(S(3)*c*d + e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(S(2)*a*e*(-S(5)*n + S(2)) - S(3)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*c*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) + e**S(2)*x*(-S(2)*a*c*(S(6)*c*d*(-S(2)*n + S(1)) + e*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))) - b**S(3)*e*(-n + S(1)) + b**S(2)*(-n + S(1))*(S(3)*c*d - e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(S(2)*a*e*(-S(5)*n + S(2)) + S(3)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*c*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + x*(-a*b*e*(a*e**S(2) + S(3)*c*d**S(2)) - S(2)*a*c*d*(-S(3)*a*e**S(2) + c*d**S(2)) + b**S(2)*c*d**S(3) - x**n*(a*b**S(2)*e**S(3) + S(2)*a*c*e*(-a*e**S(2) + S(3)*c*d**S(2)) - b*c*d*(S(3)*a*e**S(2) + c*d**S(2))))/(S(2)*a*c*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))**S(2)) + e**S(2)*x*(a*b*c*e - S(6)*a*c**S(2)*d - b**S(3)*e + S(3)*b**S(2)*c*d + c*x**n*(-S(2)*a*c*e - b**S(2)*e + S(3)*b*c*d))/(a*c**S(2)*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + x*((-n + S(1))*(S(4)*a**S(2)*c**S(2)*e*(-S(3)*n + S(1))*(-a*e**S(2) + S(3)*c*d**S(2)) - S(2)*a*b**S(4)*e**S(3)*n - a*b**S(2)*c*e*(-a*e**S(2)*(S(2)*n + S(1)) + S(3)*c*d**S(2)) - S(2)*a*b*c**S(2)*d*(S(3)*a*e**S(2)*n + c*d**S(2)*(-S(7)*n + S(2))) + b**S(3)*c*d*(S(6)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1)))) + (-S(4)*a**S(2)*b*c**S(2)*e*(a*e**S(2)*(S(19)*n**S(2) - S(11)*n + S(1)) + S(3)*c*d**S(2)*(-S(3)*n**S(2) - n + S(1))) - S(8)*a**S(2)*c**S(3)*d*(-S(3)*a*e**S(2) + c*d**S(2))*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*a*b**S(5)*e**S(3)*n*(-n + S(1)) + a*b**S(3)*c*e*(a*e**S(2)*(S(30)*n**S(2) - S(19)*n + S(1)) + S(3)*c*d**S(2)*(-n + S(1))) + S(6)*a*b**S(2)*c**S(2)*d*(-a*e**S(2)*(S(15)*n**S(2) - S(10)*n + S(1)) + c*d**S(2)*(S(3)*n**S(2) - S(4)*n + S(1))) - b**S(4)*c*d*(-n + S(1))*(S(6)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*c*n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + x*((-n + S(1))*(S(4)*a**S(2)*c**S(2)*e*(-S(3)*n + S(1))*(-a*e**S(2) + S(3)*c*d**S(2)) - S(2)*a*b**S(4)*e**S(3)*n - a*b**S(2)*c*e*(-a*e**S(2)*(S(2)*n + S(1)) + S(3)*c*d**S(2)) - S(2)*a*b*c**S(2)*d*(S(3)*a*e**S(2)*n + c*d**S(2)*(-S(7)*n + S(2))) + b**S(3)*c*d*(S(6)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1)))) - (-S(4)*a**S(2)*b*c**S(2)*e*(a*e**S(2)*(S(19)*n**S(2) - S(11)*n + S(1)) + S(3)*c*d**S(2)*(-S(3)*n**S(2) - n + S(1))) - S(8)*a**S(2)*c**S(3)*d*(-S(3)*a*e**S(2) + c*d**S(2))*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*a*b**S(5)*e**S(3)*n*(-n + S(1)) + a*b**S(3)*c*e*(a*e**S(2)*(S(30)*n**S(2) - S(19)*n + S(1)) + S(3)*c*d**S(2)*(-n + S(1))) + S(6)*a*b**S(2)*c**S(2)*d*(-a*e**S(2)*(S(15)*n**S(2) - S(10)*n + S(1)) + c*d**S(2)*(S(3)*n**S(2) - S(4)*n + S(1))) - b**S(4)*c*d*(-n + S(1))*(S(6)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*c*n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - x*(S(2)*a**S(2)*b*c**S(2)*e*(-S(5)*a*e**S(2)*n + S(3)*c*d**S(2)*(-S(3)*n + S(2))) + S(4)*a**S(2)*c**S(3)*d*(-S(4)*n + S(1))*(-S(3)*a*e**S(2) + c*d**S(2)) - S(2)*a*b**S(5)*e**S(3)*n - S(3)*a*b**S(3)*c*e*(-S(3)*a*e**S(2)*n + c*d**S(2)) + a*b**S(2)*c**S(2)*d*(S(3)*a*e**S(2)*(-S(9)*n + S(1)) - S(5)*c*d**S(2)*(-S(3)*n + S(1))) + b**S(4)*c*d*(S(6)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1))) + c*x**n*(S(4)*a**S(2)*c**S(2)*e*(-S(3)*n + S(1))*(-a*e**S(2) + S(3)*c*d**S(2)) - S(2)*a*b**S(4)*e**S(3)*n - a*b**S(2)*c*e*(-a*e**S(2)*(S(2)*n + S(1)) + S(3)*c*d**S(2)) - S(2)*a*b*c**S(2)*d*(S(3)*a*e**S(2)*n + c*d**S(2)*(-S(7)*n + S(2))) + b**S(3)*c*d*(S(6)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1)))))/(S(2)*a**S(2)*c**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(2)/(a + b*x**n + c*x**(S(2)*n))**S(3), x), x, -e**S(2)*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) + b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - e**S(2)*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) - b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + x*(-S(2)*a*b*d*e - S(2)*a*(-a*e**S(2) + c*d**S(2)) + b**S(2)*d**S(2) + x**n*(a*b*e**S(2) - S(4)*a*c*d*e + b*c*d**S(2)))/(S(2)*a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))**S(2)) + e**S(2)*x*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*c*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) - x*((-n + S(1))*(-S(8)*a**S(2)*c**S(2)*d*e*(-S(3)*n + S(1)) + S(2)*a*b**S(2)*c*d*e + S(2)*a*b*c*(a*e**S(2)*n + c*d**S(2)*(-S(7)*n + S(2))) - b**S(3)*(S(2)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1)))) - (-S(8)*a**S(2)*b*c**S(2)*d*e*(-S(3)*n**S(2) - n + S(1)) - S(8)*a**S(2)*c**S(2)*(-a*e**S(2) + c*d**S(2))*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*a*b**S(3)*c*d*e*(-n + S(1)) + S(2)*a*b**S(2)*c*(-a*e**S(2)*(S(15)*n**S(2) - S(10)*n + S(1)) + S(3)*c*d**S(2)*(S(3)*n**S(2) - S(4)*n + S(1))) - b**S(4)*(-n + S(1))*(S(2)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - x*((-n + S(1))*(-S(8)*a**S(2)*c**S(2)*d*e*(-S(3)*n + S(1)) + S(2)*a*b**S(2)*c*d*e + S(2)*a*b*c*(a*e**S(2)*n + c*d**S(2)*(-S(7)*n + S(2))) - b**S(3)*(S(2)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1)))) + (-S(8)*a**S(2)*b*c**S(2)*d*e*(-S(3)*n**S(2) - n + S(1)) - S(8)*a**S(2)*c**S(2)*(-a*e**S(2) + c*d**S(2))*(S(8)*n**S(2) - S(6)*n + S(1)) + S(2)*a*b**S(3)*c*d*e*(-n + S(1)) + S(2)*a*b**S(2)*c*(-a*e**S(2)*(S(15)*n**S(2) - S(10)*n + S(1)) + S(3)*c*d**S(2)*(S(3)*n**S(2) - S(4)*n + S(1))) - b**S(4)*(-n + S(1))*(S(2)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + x*(-S(4)*a**S(2)*b*c**S(2)*d*e*(-S(3)*n + S(2)) - S(4)*a**S(2)*c**S(2)*(-S(4)*n + S(1))*(-a*e**S(2) + c*d**S(2)) + S(2)*a*b**S(3)*c*d*e - a*b**S(2)*c*(a*e**S(2)*(-S(9)*n + S(1)) - S(5)*c*d**S(2)*(-S(3)*n + S(1))) - b**S(4)*(S(2)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1))) + c*x**n*(-S(8)*a**S(2)*c**S(2)*d*e*(-S(3)*n + S(1)) + S(2)*a*b**S(2)*c*d*e + S(2)*a*b*c*(a*e**S(2)*n + c*d**S(2)*(-S(7)*n + S(2))) - b**S(3)*(S(2)*a*e**S(2)*n + c*d**S(2)*(-S(2)*n + S(1)))))/(S(2)*a**S(2)*c*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + b*x**n + c*x**(S(2)*n))**S(3), x), x, x*(-a*b*e - S(2)*a*c*d + b**S(2)*d + c*x**n*(-S(2)*a*e + b*d))/(S(2)*a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))**S(2)) - c*x*(-S(4)*a**S(2)*c*(-S(2)*c*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-S(4)*a*c + b**S(2))*(S(3)*n**S(2) - S(4)*n + S(1))) + a*b**S(2)*(-n + S(1))*(-S(6)*c*d*(-S(3)*n + S(1)) + e*sqrt(-S(4)*a*c + b**S(2))) + S(2)*a*b*c*(S(2)*a*e*(-S(3)*n**S(2) - n + S(1)) + d*sqrt(-S(4)*a*c + b**S(2))*(S(7)*n**S(2) - S(9)*n + S(2))) + b**S(4)*d*(S(2)*n**S(2) - S(3)*n + S(1)) - b**S(3)*(-n + S(1))*(a*e + d*(-S(2)*n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) + c*x*(-S(4)*a**S(2)*c*(S(2)*c*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-S(4)*a*c + b**S(2))*(S(3)*n**S(2) - S(4)*n + S(1))) + a*b**S(2)*(-n + S(1))*(S(6)*c*d*(-S(3)*n + S(1)) + e*sqrt(-S(4)*a*c + b**S(2))) - S(2)*a*b*c*(S(2)*a*e*(-S(3)*n**S(2) - n + S(1)) - d*sqrt(-S(4)*a*c + b**S(2))*(S(7)*n**S(2) - S(9)*n + S(2))) - b**S(4)*d*(S(2)*n**S(2) - S(3)*n + S(1)) + b**S(3)*(-n + S(1))*(a*e - d*(-S(2)*n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + x*(-S(2)*a**S(2)*b*c*e*(-S(3)*n + S(2)) - S(4)*a**S(2)*c**S(2)*d*(-S(4)*n + S(1)) + a*b**S(3)*e + S(5)*a*b**S(2)*c*d*(-S(3)*n + S(1)) - b**S(4)*d*(-S(2)*n + S(1)) + c*x**n*(-S(4)*a**S(2)*c*e*(-S(3)*n + S(1)) + a*b**S(2)*e + S(2)*a*b*c*d*(-S(7)*n + S(2)) - b**S(3)*d*(-S(2)*n + S(1))))/(S(2)*a**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) #Apart# assert rubi_test(rubi_integrate(S(1)/((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**S(3)), x), x, -c*e**S(4)*x*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) - c*e**S(4)*x*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + e**S(6)*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + c*e**S(2)*x*(-S(2)*a*c*(S(2)*c*d*(-S(2)*n + S(1)) + e*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))) - b**S(3)*e*(-n + S(1)) + b**S(2)*(-n + S(1))*(c*d + e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(S(2)*a*e*(-S(3)*n + S(2)) - d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + c*e**S(2)*x*(-S(2)*a*c*(S(2)*c*d*(-S(2)*n + S(1)) - e*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))) - b**S(3)*e*(-n + S(1)) + b**S(2)*(-n + S(1))*(c*d - e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(S(2)*a*e*(-S(3)*n + S(2)) + d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + e**S(2)*x*(S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d + c*x**n*(S(2)*a*c*e - b**S(2)*e + b*c*d))/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + x*(S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d + c*x**n*(S(2)*a*c*e - b**S(2)*e + b*c*d))/(S(2)*a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))) - c*x*(-S(4)*a**S(2)*c**S(2)*(-S(2)*c*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-S(4)*a*c + b**S(2))*(S(3)*n**S(2) - S(4)*n + S(1))) + a*b**S(2)*c*(-n + S(1))*(-S(6)*c*d*(-S(3)*n + S(1)) + e*(-S(14)*n + S(5))*sqrt(-S(4)*a*c + b**S(2))) - S(2)*a*b*c**S(2)*(S(2)*a*e*(S(13)*n**S(2) - S(13)*n + S(3)) + d*sqrt(-S(4)*a*c + b**S(2))*(S(7)*n**S(2) - S(9)*n + S(2))) - b**S(5)*e*(S(2)*n**S(2) - S(3)*n + S(1)) + b**S(4)*(c*d - e*sqrt(-S(4)*a*c + b**S(2)))*(S(2)*n**S(2) - S(3)*n + S(1)) + b**S(3)*c*(-n + S(1))*(a*e*(-S(18)*n + S(7)) + d*(-S(2)*n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) + c*x*(-S(4)*a**S(2)*c**S(2)*(S(2)*c*d*(S(8)*n**S(2) - S(6)*n + S(1)) + e*sqrt(-S(4)*a*c + b**S(2))*(S(3)*n**S(2) - S(4)*n + S(1))) + a*b**S(2)*c*(-n + S(1))*(S(6)*c*d*(-S(3)*n + S(1)) + e*(-S(14)*n + S(5))*sqrt(-S(4)*a*c + b**S(2))) - S(2)*a*b*c**S(2)*(-S(2)*a*e*(S(13)*n**S(2) - S(13)*n + S(3)) + d*sqrt(-S(4)*a*c + b**S(2))*(S(7)*n**S(2) - S(9)*n + S(2))) + b**S(5)*e*(S(2)*n**S(2) - S(3)*n + S(1)) - b**S(4)*(c*d + e*sqrt(-S(4)*a*c + b**S(2)))*(S(2)*n**S(2) - S(3)*n + S(1)) - b**S(3)*c*(-n + S(1))*(a*e*(-S(18)*n + S(7)) - d*(-S(2)*n + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(c*d**S(2) - e*(-a*e + b*d))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) + x*(S(2)*a**S(2)*b*c**S(2)*e*(-S(11)*n + S(4)) - S(4)*a**S(2)*c**S(3)*d*(-S(4)*n + S(1)) - S(3)*a*b**S(3)*c*e*(-S(5)*n + S(2)) + S(5)*a*b**S(2)*c**S(2)*d*(-S(3)*n + S(1)) + b**S(5)*(-S(2)*e*n + e) - b**S(4)*c*d*(-S(2)*n + S(1)) - c*x**n*(-S(4)*a**S(2)*c**S(2)*e*(-S(3)*n + S(1)) + a*b**S(2)*c*e*(-S(14)*n + S(5)) - S(2)*a*b*c**S(2)*d*(-S(7)*n + S(2)) - b**S(4)*e*(-S(2)*n + S(1)) + b**S(3)*c*d*(-S(2)*n + S(1))))/(S(2)*a**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**n + c*x**(S(2)*n))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) #Apart# assert rubi_test(rubi_integrate(S(1)/((d + e*x**n)**S(2)*(a + b*x**n + c*x**(S(2)*n))**S(3)), x), x, -c*e**S(4)*x*(S(3)*b*e**S(2)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(10)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + S(5)*b*d - S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(4)) - c*e**S(4)*x*(S(3)*b*e**S(2)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(10)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + S(5)*b*d + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/((-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(4)) + S(3)*e**S(6)*x*(-b*e + S(2)*c*d)*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d*(a*e**S(2) - b*d*e + c*d**S(2))**S(4)) + e**S(6)*x*hyper((S(2), S(1)/n), (S(1) + S(1)/n,), -e*x**n/d)/(d**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + c*e**S(2)*x*(S(4)*a*c**S(2)*(-S(3)*c*d**S(2)*(-S(2)*n + S(1)) + e*(a*e*(-S(2)*n + S(1)) - S(2)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + S(2)*b**S(4)*e**S(2)*(-n + S(1)) - b**S(3)*e*(-n + S(1))*(S(5)*c*d + S(2)*e*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*c*(-S(3)*c*d**S(2)*(-n + S(1)) + e*(a*e*(-S(13)*n + S(9)) - S(5)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + b*c*(S(5)*a*e**S(2)*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)) + c*d*(S(4)*a*e*(-S(8)*n + S(5)) - S(3)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) + c*e**S(2)*x*(S(4)*a*c**S(2)*(-S(3)*c*d**S(2)*(-S(2)*n + S(1)) + e*(a*e*(-S(2)*n + S(1)) + S(2)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + S(2)*b**S(4)*e**S(2)*(-n + S(1)) - b**S(3)*e*(-n + S(1))*(S(5)*c*d - S(2)*e*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*c*(-S(3)*c*d**S(2)*(-n + S(1)) + e*(a*e*(-S(13)*n + S(9)) + S(5)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))) + b*c*(-S(5)*a*e**S(2)*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)) + c*d*(S(4)*a*e*(-S(8)*n + S(5)) + S(3)*d*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) - e**S(2)*x*(-S(14)*a*b*c**S(2)*d*e + S(2)*a*c**S(2)*(-a*e**S(2) + S(3)*c*d**S(2)) - S(2)*b**S(4)*e**S(2) + S(5)*b**S(3)*c*d*e - b**S(2)*c*(-S(7)*a*e**S(2) + S(3)*c*d**S(2)) + c*x**n*(-S(8)*a*c**S(2)*d*e - S(2)*b**S(3)*e**S(2) + S(5)*b**S(2)*c*d*e - b*c*(-S(5)*a*e**S(2) + S(3)*c*d**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))*(a*e**S(2) - b*d*e + c*d**S(2))**S(3)) - x*(-S(6)*a*b*c**S(2)*d*e + S(2)*a*c**S(2)*(-a*e**S(2) + c*d**S(2)) - b**S(4)*e**S(2) + S(2)*b**S(3)*c*d*e - b**S(2)*c*(-S(4)*a*e**S(2) + c*d**S(2)) + c*x**n*(-S(4)*a*c**S(2)*d*e - b**S(3)*e**S(2) + S(2)*b**S(2)*c*d*e - b*c*(-S(3)*a*e**S(2) + c*d**S(2))))/(S(2)*a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + c*x*((-n + S(1))*(-S(8)*a**S(2)*c**S(3)*d*e*(-S(3)*n + S(1)) + S(2)*a*b**S(2)*c**S(2)*d*e*(-S(14)*n + S(5)) + S(2)*a*b*c**S(2)*(a*e**S(2)*(-S(13)*n + S(4)) - c*d**S(2)*(-S(7)*n + S(2))) + b**S(5)*e**S(2)*(-S(2)*n + S(1)) - S(2)*b**S(4)*c*d*e*(-S(2)*n + S(1)) - b**S(3)*c*(S(2)*a*e**S(2)*(-S(8)*n + S(3)) - c*d**S(2)*(-S(2)*n + S(1)))) + (S(8)*a**S(2)*b*c**S(3)*d*e*(S(13)*n**S(2) - S(13)*n + S(3)) - S(8)*a**S(2)*c**S(3)*(-a*e**S(2) + c*d**S(2))*(S(8)*n**S(2) - S(6)*n + S(1)) - S(2)*a*b**S(3)*c**S(2)*d*e*(S(18)*n**S(2) - S(25)*n + S(7)) + S(2)*a*b**S(2)*c**S(2)*(-a*e**S(2)*(S(35)*n**S(2) - S(38)*n + S(9)) + S(3)*c*d**S(2)*(S(3)*n**S(2) - S(4)*n + S(1))) - b**S(6)*e**S(2)*(S(2)*n**S(2) - S(3)*n + S(1)) + S(2)*b**S(5)*c*d*e*(S(2)*n**S(2) - S(3)*n + S(1)) + b**S(4)*c*(-n + S(1))*(S(4)*a*e**S(2)*(-S(5)*n + S(2)) - c*d**S(2)*(-S(2)*n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) + c*x*((-n + S(1))*(-S(8)*a**S(2)*c**S(3)*d*e*(-S(3)*n + S(1)) + S(2)*a*b**S(2)*c**S(2)*d*e*(-S(14)*n + S(5)) + S(2)*a*b*c**S(2)*(a*e**S(2)*(-S(13)*n + S(4)) - c*d**S(2)*(-S(7)*n + S(2))) + b**S(5)*e**S(2)*(-S(2)*n + S(1)) - S(2)*b**S(4)*c*d*e*(-S(2)*n + S(1)) - b**S(3)*c*(S(2)*a*e**S(2)*(-S(8)*n + S(3)) - c*d**S(2)*(-S(2)*n + S(1)))) - (S(8)*a**S(2)*b*c**S(3)*d*e*(S(13)*n**S(2) - S(13)*n + S(3)) - S(8)*a**S(2)*c**S(3)*(-a*e**S(2) + c*d**S(2))*(S(8)*n**S(2) - S(6)*n + S(1)) - S(2)*a*b**S(3)*c**S(2)*d*e*(S(18)*n**S(2) - S(25)*n + S(7)) + S(2)*a*b**S(2)*c**S(2)*(-a*e**S(2)*(S(35)*n**S(2) - S(38)*n + S(9)) + S(3)*c*d**S(2)*(S(3)*n**S(2) - S(4)*n + S(1))) - b**S(6)*e**S(2)*(S(2)*n**S(2) - S(3)*n + S(1)) + S(2)*b**S(5)*c*d*e*(S(2)*n**S(2) - S(3)*n + S(1)) + b**S(4)*c*(-n + S(1))*(S(4)*a*e**S(2)*(-S(5)*n + S(2)) - c*d**S(2)*(-S(2)*n + S(1))))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)) - x*(-S(4)*a**S(2)*b*c**S(3)*d*e*(-S(11)*n + S(4)) + S(4)*a**S(2)*c**S(3)*(-S(4)*n + S(1))*(-a*e**S(2) + c*d**S(2)) + S(6)*a*b**S(3)*c**S(2)*d*e*(-S(5)*n + S(2)) + a*b**S(2)*c**S(2)*(a*e**S(2)*(-S(37)*n + S(13)) - S(5)*c*d**S(2)*(-S(3)*n + S(1))) + b**S(6)*e**S(2)*(-S(2)*n + S(1)) - S(2)*b**S(5)*c*d*e*(-S(2)*n + S(1)) - b**S(4)*c*(a*e**S(2)*(-S(17)*n + S(7)) - c*d**S(2)*(-S(2)*n + S(1))) + c*x**n*(-S(8)*a**S(2)*c**S(3)*d*e*(-S(3)*n + S(1)) + S(2)*a*b**S(2)*c**S(2)*d*e*(-S(14)*n + S(5)) + S(2)*a*b*c**S(2)*(a*e**S(2)*(-S(13)*n + S(4)) - c*d**S(2)*(-S(7)*n + S(2))) + b**S(5)*e**S(2)*(-S(2)*n + S(1)) - S(2)*b**S(4)*c*d*e*(-S(2)*n + S(1)) - b**S(3)*c*(S(2)*a*e**S(2)*(-S(8)*n + S(3)) - c*d**S(2)*(-S(2)*n + S(1)))))/(S(2)*a**S(2)*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**n + c*x**(S(2)*n))*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**(S(2)*n))**p/(d + e*x**n), x), x, x*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1(S(1)/(S(2)*n), -p, S(1), S(1) + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/d - e*x**(n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((n + S(1))/(S(2)*n), -p, S(1), S(3)/2 + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(2)*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**(S(2)*n))**p/(d + e*x**n)**S(2), x), x, x*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1(S(1)/(S(2)*n), -p, S(2), S(1) + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/d**S(2) - S(2)*e*x**(n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((n + S(1))/(S(2)*n), -p, S(2), S(3)/2 + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(3)*(n + S(1))) + e**S(2)*x**(S(2)*n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1(S(1) + S(1)/(S(2)*n), -p, S(2), S(2) + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(4)*(S(2)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**(S(2)*n))**p/(d + e*x**n)**S(3), x), x, x*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1(S(1)/(S(2)*n), -p, S(3), S(1) + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/d**S(3) - S(3)*e*x**(n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((n + S(1))/(S(2)*n), -p, S(3), S(3)/2 + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(4)*(n + S(1))) + S(3)*e**S(2)*x**(S(2)*n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1(S(1) + S(1)/(S(2)*n), -p, S(3), S(2) + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(5)*(S(2)*n + S(1))) - e**S(3)*x**(S(3)*n + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1(S(3)/2 + S(1)/(S(2)*n), -p, S(3), S(5)/2 + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(6)*(S(3)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(a + c*x**(S(2)*n))*(d + e*x**n)), x), x, x*sqrt(S(1) + c*x**(S(2)*n)/a)*AppellF1(S(1)/(S(2)*n), S(1)/2, S(1), S(1) + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d*sqrt(a + c*x**(S(2)*n))) - e*x**(n + S(1))*sqrt(S(1) + c*x**(S(2)*n)/a)*AppellF1((n + S(1))/(S(2)*n), S(1)/2, S(1), S(3)/2 + S(1)/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(2)*sqrt(a + c*x**(S(2)*n))*(n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)*sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, d*x*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(1)/n, S(-1)/2, S(-1)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + e*x**(n + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(1) + S(1)/n, S(-1)/2, S(-1)/2, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((n + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, a*d*x*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(1)/n, S(-3)/2, S(-3)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + a*e*x**(n + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))*AppellF1(S(1) + S(1)/n, S(-3)/2, S(-3)/2, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((n + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/sqrt(a + b*x**n + c*x**(S(2)*n)), x), x, d*x*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/n, S(1)/2, S(1)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/sqrt(a + b*x**n + c*x**(S(2)*n)) + e*x**(n + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1) + S(1)/n, S(1)/2, S(1)/2, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/((n + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, d*x*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/n, S(3)/2, S(3)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*sqrt(a + b*x**n + c*x**(S(2)*n))) + e*x**(n + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1) + S(1)/n, S(3)/2, S(3)/2, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*(n + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)/(a + b*x**n + c*x**(S(2)*n))**(S(5)/2), x), x, d*x*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/n, S(5)/2, S(5)/2, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a**S(2)*sqrt(a + b*x**n + c*x**(S(2)*n))) + e*x**(n + S(1))*sqrt(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1) + S(1)/n, S(5)/2, S(5)/2, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a**S(2)*(n + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(3)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, d**S(3)*x*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(1)/n, -p, -p, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2)))) + S(3)*d**S(2)*e*x**(n + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(1) + S(1)/n, -p, -p, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(n + S(1)) + S(3)*d*e**S(2)*x**(S(2)*n + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(2) + S(1)/n, -p, -p, S(3) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*n + S(1)) + e**S(3)*x**(S(3)*n + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(3) + S(1)/n, -p, -p, S(4) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**S(2)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, d**S(2)*x*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(1)/n, -p, -p, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2)))) + S(2)*d*e*x**(n + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(1) + S(1)/n, -p, -p, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(n + S(1)) + e**S(2)*x**(S(2)*n + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(2) + S(1)/n, -p, -p, S(3) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, d*x*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(1)/n, -p, -p, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2)))) + e*x**(n + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1(S(1) + S(1)/n, -p, -p, S(2) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(n + S(1)), expand=True, _diff=True, _numerical=True) def test_3(): assert rubi_test(rubi_integrate(x**S(3)*(a + c*x**S(4))**S(5)*(d + e*x**S(2)), x), x, a**S(5)*d*x**S(4)/S(4) + a**S(5)*e*x**S(6)/S(6) + S(5)*a**S(4)*c*d*x**S(8)/S(8) + a**S(4)*c*e*x**S(10)/S(2) + S(5)*a**S(3)*c**S(2)*d*x**S(12)/S(6) + S(5)*a**S(3)*c**S(2)*e*x**S(14)/S(7) + S(5)*a**S(2)*c**S(3)*d*x**S(16)/S(8) + S(5)*a**S(2)*c**S(3)*e*x**S(18)/S(9) + a*c**S(4)*d*x**S(20)/S(4) + S(5)*a*c**S(4)*e*x**S(22)/S(22) + c**S(5)*d*x**S(24)/S(24) + c**S(5)*e*x**S(26)/S(26), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + c*x**S(4))**S(5)*(d + e*x**S(2)), x), x, a**S(5)*d*x**S(3)/S(3) + a**S(5)*e*x**S(5)/S(5) + S(5)*a**S(4)*c*d*x**S(7)/S(7) + S(5)*a**S(4)*c*e*x**S(9)/S(9) + S(10)*a**S(3)*c**S(2)*d*x**S(11)/S(11) + S(10)*a**S(3)*c**S(2)*e*x**S(13)/S(13) + S(2)*a**S(2)*c**S(3)*d*x**S(15)/S(3) + S(10)*a**S(2)*c**S(3)*e*x**S(17)/S(17) + S(5)*a*c**S(4)*d*x**S(19)/S(19) + S(5)*a*c**S(4)*e*x**S(21)/S(21) + c**S(5)*d*x**S(23)/S(23) + c**S(5)*e*x**S(25)/S(25), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + c*x**S(4))**S(5)*(d + e*x**S(2)), x), x, a**S(5)*d*x**S(2)/S(2) + S(5)*a**S(4)*c*d*x**S(6)/S(6) + a**S(3)*c**S(2)*d*x**S(10) + S(5)*a**S(2)*c**S(3)*d*x**S(14)/S(7) + S(5)*a*c**S(4)*d*x**S(18)/S(18) + c**S(5)*d*x**S(22)/S(22) + e*(a + c*x**S(4))**S(6)/(S(24)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(4))**S(5)*(d + e*x**S(2)), x), x, a**S(5)*d*x + a**S(5)*e*x**S(3)/S(3) + a**S(4)*c*d*x**S(5) + S(5)*a**S(4)*c*e*x**S(7)/S(7) + S(10)*a**S(3)*c**S(2)*d*x**S(9)/S(9) + S(10)*a**S(3)*c**S(2)*e*x**S(11)/S(11) + S(10)*a**S(2)*c**S(3)*d*x**S(13)/S(13) + S(2)*a**S(2)*c**S(3)*e*x**S(15)/S(3) + S(5)*a*c**S(4)*d*x**S(17)/S(17) + S(5)*a*c**S(4)*e*x**S(19)/S(19) + c**S(5)*d*x**S(21)/S(21) + c**S(5)*e*x**S(23)/S(23), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(4))**S(5)*(d + e*x**S(2))/x, x), x, a**S(5)*d*log(x) + a**S(5)*e*x**S(2)/S(2) + S(5)*a**S(4)*c*d*x**S(4)/S(4) + S(5)*a**S(4)*c*e*x**S(6)/S(6) + S(5)*a**S(3)*c**S(2)*d*x**S(8)/S(4) + a**S(3)*c**S(2)*e*x**S(10) + S(5)*a**S(2)*c**S(3)*d*x**S(12)/S(6) + S(5)*a**S(2)*c**S(3)*e*x**S(14)/S(7) + S(5)*a*c**S(4)*d*x**S(16)/S(16) + S(5)*a*c**S(4)*e*x**S(18)/S(18) + c**S(5)*d*x**S(20)/S(20) + c**S(5)*e*x**S(22)/S(22), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(4))**S(5)*(d + e*x**S(2))/x**S(2), x), x, -a**S(5)*d/x + a**S(5)*e*x + S(5)*a**S(4)*c*d*x**S(3)/S(3) + a**S(4)*c*e*x**S(5) + S(10)*a**S(3)*c**S(2)*d*x**S(7)/S(7) + S(10)*a**S(3)*c**S(2)*e*x**S(9)/S(9) + S(10)*a**S(2)*c**S(3)*d*x**S(11)/S(11) + S(10)*a**S(2)*c**S(3)*e*x**S(13)/S(13) + a*c**S(4)*d*x**S(15)/S(3) + S(5)*a*c**S(4)*e*x**S(17)/S(17) + c**S(5)*d*x**S(19)/S(19) + c**S(5)*e*x**S(21)/S(21), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + c*x**S(4))**S(5)*(d + e*x**S(2))/x**S(3), x), x, -a**S(5)*d/(S(2)*x**S(2)) + a**S(5)*e*log(x) + S(5)*a**S(4)*c*d*x**S(2)/S(2) + S(5)*a**S(4)*c*e*x**S(4)/S(4) + S(5)*a**S(3)*c**S(2)*d*x**S(6)/S(3) + S(5)*a**S(3)*c**S(2)*e*x**S(8)/S(4) + a**S(2)*c**S(3)*d*x**S(10) + S(5)*a**S(2)*c**S(3)*e*x**S(12)/S(6) + S(5)*a*c**S(4)*d*x**S(14)/S(14) + S(5)*a*c**S(4)*e*x**S(16)/S(16) + c**S(5)*d*x**S(18)/S(18) + c**S(5)*e*x**S(20)/S(20), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, d*(f*x)**(m + S(1))/(f*(m + S(1))) + e*(f*x)**(m + S(23))/(f**S(23)*(m + S(23))) + (f*x)**(m + S(3))*(S(10)*d + e)/(f**S(3)*(m + S(3))) + (f*x)**(m + S(5))*(S(45)*d + S(10)*e)/(f**S(5)*(m + S(5))) + (f*x)**(m + S(7))*(S(120)*d + S(45)*e)/(f**S(7)*(m + S(7))) + (f*x)**(m + S(9))*(S(210)*d + S(120)*e)/(f**S(9)*(m + S(9))) + (f*x)**(m + S(11))*(S(252)*d + S(210)*e)/(f**S(11)*(m + S(11))) + (f*x)**(m + S(13))*(S(210)*d + S(252)*e)/(f**S(13)*(m + S(13))) + (f*x)**(m + S(15))*(S(120)*d + S(210)*e)/(f**S(15)*(m + S(15))) + (f*x)**(m + S(17))*(S(45)*d + S(120)*e)/(f**S(17)*(m + S(17))) + (f*x)**(m + S(19))*(S(10)*d + S(45)*e)/(f**S(19)*(m + S(19))) + (f*x)**(m + S(21))*(d + S(10)*e)/(f**S(21)*(m + S(21))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, e*(x**S(2) + S(1))**S(14)/S(28) + (d/S(26) - S(3)*e/S(26))*(x**S(2) + S(1))**S(13) + (d/S(22) - e/S(22))*(x**S(2) + S(1))**S(11) - (d/S(12) - e/S(8))*(x**S(2) + S(1))**S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, d*x**S(5)/S(5) + e*x**S(27)/S(27) + x**S(25)*(d/S(25) + S(2)*e/S(5)) + x**S(23)*(S(10)*d/S(23) + S(45)*e/S(23)) + x**S(21)*(S(15)*d/S(7) + S(40)*e/S(7)) + x**S(19)*(S(120)*d/S(19) + S(210)*e/S(19)) + x**S(17)*(S(210)*d/S(17) + S(252)*e/S(17)) + x**S(15)*(S(84)*d/S(5) + S(14)*e) + x**S(13)*(S(210)*d/S(13) + S(120)*e/S(13)) + x**S(11)*(S(120)*d/S(11) + S(45)*e/S(11)) + x**S(9)*(S(5)*d + S(10)*e/S(9)) + x**S(7)*(S(10)*d/S(7) + e/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, e*(x**S(2) + S(1))**S(13)/S(26) + (-d/S(22) + e/S(22))*(x**S(2) + S(1))**S(11) + (d/S(24) - e/S(12))*(x**S(2) + S(1))**S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, d*x**S(3)/S(3) + e*x**S(25)/S(25) + x**S(23)*(d/S(23) + S(10)*e/S(23)) + x**S(21)*(S(10)*d/S(21) + S(15)*e/S(7)) + x**S(19)*(S(45)*d/S(19) + S(120)*e/S(19)) + x**S(17)*(S(120)*d/S(17) + S(210)*e/S(17)) + x**S(15)*(S(14)*d + S(84)*e/S(5)) + x**S(13)*(S(252)*d/S(13) + S(210)*e/S(13)) + x**S(11)*(S(210)*d/S(11) + S(120)*e/S(11)) + x**S(9)*(S(40)*d/S(3) + S(5)*e) + x**S(7)*(S(45)*d/S(7) + S(10)*e/S(7)) + x**S(5)*(S(2)*d + e/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, e*(x**S(2) + S(1))**S(12)/S(24) + (d/S(22) - e/S(22))*(x**S(2) + S(1))**S(11), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, d*x + e*x**S(23)/S(23) + x**S(21)*(d/S(21) + S(10)*e/S(21)) + x**S(19)*(S(10)*d/S(19) + S(45)*e/S(19)) + x**S(17)*(S(45)*d/S(17) + S(120)*e/S(17)) + x**S(15)*(S(8)*d + S(14)*e) + x**S(13)*(S(210)*d/S(13) + S(252)*e/S(13)) + x**S(11)*(S(252)*d/S(11) + S(210)*e/S(11)) + x**S(9)*(S(70)*d/S(3) + S(40)*e/S(3)) + x**S(7)*(S(120)*d/S(7) + S(45)*e/S(7)) + x**S(5)*(S(9)*d + S(2)*e) + x**S(3)*(S(10)*d/S(3) + e/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5)/x, x), x, d*x**S(20)/S(20) + S(5)*d*x**S(18)/S(9) + S(45)*d*x**S(16)/S(16) + S(60)*d*x**S(14)/S(7) + S(35)*d*x**S(12)/S(2) + S(126)*d*x**S(10)/S(5) + S(105)*d*x**S(8)/S(4) + S(20)*d*x**S(6) + S(45)*d*x**S(4)/S(4) + S(5)*d*x**S(2) + d*log(x) + e*(x**S(2) + S(1))**S(11)/S(22), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5)/x**S(2), x), x, -d/x + e*x**S(21)/S(21) + x**S(19)*(d/S(19) + S(10)*e/S(19)) + x**S(17)*(S(10)*d/S(17) + S(45)*e/S(17)) + x**S(15)*(S(3)*d + S(8)*e) + x**S(13)*(S(120)*d/S(13) + S(210)*e/S(13)) + x**S(11)*(S(210)*d/S(11) + S(252)*e/S(11)) + x**S(9)*(S(28)*d + S(70)*e/S(3)) + x**S(7)*(S(30)*d + S(120)*e/S(7)) + x**S(5)*(S(24)*d + S(9)*e) + x**S(3)*(S(15)*d + S(10)*e/S(3)) + x*(S(10)*d + e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5)/x**S(3), x), x, -d/(S(2)*x**S(2)) + e*x**S(20)/S(20) + x**S(18)*(d/S(18) + S(5)*e/S(9)) + x**S(16)*(S(5)*d/S(8) + S(45)*e/S(16)) + x**S(14)*(S(45)*d/S(14) + S(60)*e/S(7)) + x**S(12)*(S(10)*d + S(35)*e/S(2)) + x**S(10)*(S(21)*d + S(126)*e/S(5)) + x**S(8)*(S(63)*d/S(2) + S(105)*e/S(4)) + x**S(6)*(S(35)*d + S(20)*e) + x**S(4)*(S(30)*d + S(45)*e/S(4)) + x**S(2)*(S(45)*d/S(2) + S(5)*e) + (S(10)*d + e)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, (f*x)**(m + S(1))/(f*(m + S(1))) + S(11)*(f*x)**(m + S(3))/(f**S(3)*(m + S(3))) + S(55)*(f*x)**(m + S(5))/(f**S(5)*(m + S(5))) + S(165)*(f*x)**(m + S(7))/(f**S(7)*(m + S(7))) + S(330)*(f*x)**(m + S(9))/(f**S(9)*(m + S(9))) + S(462)*(f*x)**(m + S(11))/(f**S(11)*(m + S(11))) + S(462)*(f*x)**(m + S(13))/(f**S(13)*(m + S(13))) + S(330)*(f*x)**(m + S(15))/(f**S(15)*(m + S(15))) + S(165)*(f*x)**(m + S(17))/(f**S(17)*(m + S(17))) + S(55)*(f*x)**(m + S(19))/(f**S(19)*(m + S(19))) + S(11)*(f*x)**(m + S(21))/(f**S(21)*(m + S(21))) + (f*x)**(m + S(23))/(f**S(23)*(m + S(23))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, (x**S(2) + S(1))**S(14)/S(28) - (x**S(2) + S(1))**S(13)/S(13) + (x**S(2) + S(1))**S(12)/S(24), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, x**S(27)/S(27) + S(11)*x**S(25)/S(25) + S(55)*x**S(23)/S(23) + S(55)*x**S(21)/S(7) + S(330)*x**S(19)/S(19) + S(462)*x**S(17)/S(17) + S(154)*x**S(15)/S(5) + S(330)*x**S(13)/S(13) + S(15)*x**S(11) + S(55)*x**S(9)/S(9) + S(11)*x**S(7)/S(7) + x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, (x**S(2) + S(1))**S(13)/S(26) - (x**S(2) + S(1))**S(12)/S(24), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, x**S(25)/S(25) + S(11)*x**S(23)/S(23) + S(55)*x**S(21)/S(21) + S(165)*x**S(19)/S(19) + S(330)*x**S(17)/S(17) + S(154)*x**S(15)/S(5) + S(462)*x**S(13)/S(13) + S(30)*x**S(11) + S(55)*x**S(9)/S(3) + S(55)*x**S(7)/S(7) + S(11)*x**S(5)/S(5) + x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, (x**S(2) + S(1))**S(12)/S(24), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5), x), x, x**S(23)/S(23) + S(11)*x**S(21)/S(21) + S(55)*x**S(19)/S(19) + S(165)*x**S(17)/S(17) + S(22)*x**S(15) + S(462)*x**S(13)/S(13) + S(42)*x**S(11) + S(110)*x**S(9)/S(3) + S(165)*x**S(7)/S(7) + S(11)*x**S(5) + S(11)*x**S(3)/S(3) + x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5)/x, x), x, x**S(22)/S(22) + S(11)*x**S(20)/S(20) + S(55)*x**S(18)/S(18) + S(165)*x**S(16)/S(16) + S(165)*x**S(14)/S(7) + S(77)*x**S(12)/S(2) + S(231)*x**S(10)/S(5) + S(165)*x**S(8)/S(4) + S(55)*x**S(6)/S(2) + S(55)*x**S(4)/S(4) + S(11)*x**S(2)/S(2) + log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5)/x**S(2), x), x, x**S(21)/S(21) + S(11)*x**S(19)/S(19) + S(55)*x**S(17)/S(17) + S(11)*x**S(15) + S(330)*x**S(13)/S(13) + S(42)*x**S(11) + S(154)*x**S(9)/S(3) + S(330)*x**S(7)/S(7) + S(33)*x**S(5) + S(55)*x**S(3)/S(3) + S(11)*x - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) + S(1))*(x**S(4) + S(2)*x**S(2) + S(1))**S(5)/x**S(3), x), x, x**S(20)/S(20) + S(11)*x**S(18)/S(18) + S(55)*x**S(16)/S(16) + S(165)*x**S(14)/S(14) + S(55)*x**S(12)/S(2) + S(231)*x**S(10)/S(5) + S(231)*x**S(8)/S(4) + S(55)*x**S(6) + S(165)*x**S(4)/S(4) + S(55)*x**S(2)/S(2) + S(11)*log(x) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, e*(f*x)**(m + S(1))*(a + b*x**S(2))/(b*f*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (f*x)**(m + S(1))*(a + b*x**S(2))*(-a*e + b*d)*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(a*b*f*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(2))/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, -sqrt(a)*(a + b*x**S(2))*(-a*e + b*d)*atan(sqrt(b)*x/sqrt(a))/(b**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + e*x**S(3)*(a + b*x**S(2))/(S(3)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + x*(a + b*x**S(2))*(-a*e + b*d)/(b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(2))/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, e*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*b**S(2)) + (a + b*x**S(2))*(-a*e + b*d)*log(a + b*x**S(2))/(S(2)*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, e*x*(a + b*x**S(2))/(b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*(-a*e + b*d)*atan(sqrt(b)*x/sqrt(a))/(sqrt(a)*b**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, d*(a + b*x**S(2))*log(x)/(a*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*(-a*e + b*d)*log(a + b*x**S(2))/(S(2)*a*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -d*(a + b*x**S(2))/(a*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*(-a*e + b*d)*atan(sqrt(b)*x/sqrt(a))/(a**(S(3)/2)*sqrt(b)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(x**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), x), x, -d*(a + b*x**S(2))/(S(2)*a*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*(-a*e + b*d)*log(x)/(a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*(-a*e + b*d)*log(a + b*x**S(2))/(S(2)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, (f*x)**(m + S(1))*(-a*e + b*d)/(S(4)*a*b*f*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (f*x)**(m + S(1))*(a + b*x**S(2))*(a*e*(m + S(1)) + b*d*(-m + S(3)))*hyper((S(2), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -b*x**S(2)/a)/(S(4)*a**S(3)*b*f*(m + S(1))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(2))/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, -x*(-a*e + b*d)/(S(4)*b**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + x*(-S(5)*a*e + b*d)/(S(8)*a*b**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*(S(3)*a*e + b*d)*atan(sqrt(b)*x/sqrt(a))/(S(8)*a**(S(3)/2)*b**(S(5)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(2))/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, -(a + b*x**S(2))*(d + e*x**S(2))**S(2)/((-S(4)*a*e + S(4)*b*d)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2), x), x, x*(-a*e + b*d)/(S(4)*a*b*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + x*(a*e + S(3)*b*d)/(S(8)*a**S(2)*b*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*(a*e + S(3)*b*d)*atan(sqrt(b)*x/sqrt(a))/(S(8)*a**(S(5)/2)*b**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(x*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, (-a*e + b*d)/(S(4)*a*b*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + d/(S(2)*a**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + d*(a + b*x**S(2))*log(x)/(a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - d*(a + b*x**S(2))*log(a + b*x**S(2))/(S(2)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(x**S(2)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, -x*(-a*e + b*d)/(S(4)*a**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - d*(a + b*x**S(2))/(a**S(3)*x*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - x*(-S(3)*a*e + S(7)*b*d)/(S(8)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*(-S(3)*a*e + S(15)*b*d)*atan(sqrt(b)*x/sqrt(a))/(S(8)*a**(S(7)/2)*sqrt(b)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(x**S(3)*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(S(3)/2)), x), x, -(-a*e + b*d)/(S(4)*a**S(2)*(a + b*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - d*(a + b*x**S(2))/(S(2)*a**S(3)*x**S(2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (-a*e + S(2)*b*d)/(S(2)*a**S(3)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) - (a + b*x**S(2))*(-a*e + S(3)*b*d)*log(x)/(a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))) + (a + b*x**S(2))*(-a*e + S(3)*b*d)*log(a + b*x**S(2))/(S(2)*a**S(4)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2))*(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**p, x), x, (a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))**(p + S(1))/(S(4)*b*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(c + d*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, b*x**S(3)*(c + d*x**S(2))**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(6)*d*(a + b*x**S(2))) + c**S(2)*(-S(2)*a*d + b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh(sqrt(d)*x/sqrt(c + d*x**S(2)))/(S(16)*d**(S(5)/2)*(a + b*x**S(2))) - c*x*sqrt(c + d*x**S(2))*(-S(2)*a*d + b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(16)*d**S(2)*(a + b*x**S(2))) - x**S(3)*sqrt(c + d*x**S(2))*(-S(2)*a*d + b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(8)*d*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(c + d*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, (c + d*x**S(2))**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(5)*d) - (c + d*x**S(2))**(S(3)/2)*(-S(2)*a*d + S(2)*b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(15)*d**S(2)*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4)), x), x, b*x*(c + d*x**S(2))**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(4)*d*(a + b*x**S(2))) - c*(-S(4)*a*d + b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh(sqrt(d)*x/sqrt(c + d*x**S(2)))/(S(8)*d**(S(3)/2)*(a + b*x**S(2))) - x*sqrt(c + d*x**S(2))*(-S(4)*a*d + b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(8)*d*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x, x), x, -a*sqrt(c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh(sqrt(c + d*x**S(2))/sqrt(c))/(a + b*x**S(2)) + a*sqrt(c + d*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(a + b*x**S(2)) + b*(c + d*x**S(2))**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(3)*d*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(2), x), x, -a*(c + d*x**S(2))**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(c*x*(a + b*x**S(2))) + (S(2)*a*d + b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh(sqrt(d)*x/sqrt(c + d*x**S(2)))/(S(2)*sqrt(d)*(a + b*x**S(2))) + x*sqrt(c + d*x**S(2))*(S(2)*a*d + b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*c*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(c + d*x**S(2))*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/x**S(3), x), x, -a*(c + d*x**S(2))**(S(3)/2)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*c*x**S(2)*(a + b*x**S(2))) + sqrt(c + d*x**S(2))*(a*d + S(2)*b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))/(S(2)*c*(a + b*x**S(2))) - (a*d + S(2)*b*c)*sqrt(a**S(2) + S(2)*a*b*x**S(2) + b**S(2)*x**S(4))*atanh(sqrt(c + d*x**S(2))/sqrt(c))/(S(2)*sqrt(c)*(a + b*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, A*a**S(3)*x**S(4)/S(4) + B*c**S(3)*x**S(18)/S(18) + a**S(2)*x**S(6)*(S(3)*A*b + B*a)/S(6) + S(3)*a*x**S(8)*(A*(a*c + b**S(2)) + B*a*b)/S(8) + c**S(2)*x**S(16)*(A*c + S(3)*B*b)/S(16) + S(3)*c*x**S(14)*(A*b*c + B*a*c + B*b**S(2))/S(14) + x**S(12)*(A*a*c**S(2)/S(4) + A*b**S(2)*c/S(4) + B*a*b*c/S(2) + B*b**S(3)/S(12)) + x**S(10)*(A*(S(6)*a*b*c + b**S(3))/S(10) + S(3)*B*a*(a*c + b**S(2))/S(10)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, A*a**S(3)*x**S(3)/S(3) + B*c**S(3)*x**S(17)/S(17) + a**S(2)*x**S(5)*(S(3)*A*b + B*a)/S(5) + S(3)*a*x**S(7)*(A*(a*c + b**S(2)) + B*a*b)/S(7) + c**S(2)*x**S(15)*(A*c + S(3)*B*b)/S(15) + S(3)*c*x**S(13)*(A*b*c + B*a*c + B*b**S(2))/S(13) + x**S(11)*(S(3)*A*a*c**S(2)/S(11) + S(3)*A*b**S(2)*c/S(11) + S(6)*B*a*b*c/S(11) + B*b**S(3)/S(11)) + x**S(9)*(A*(S(6)*a*b*c + b**S(3))/S(9) + B*a*(a*c + b**S(2))/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, A*a**S(3)*x**S(2)/S(2) + B*c**S(3)*x**S(16)/S(16) + a**S(2)*x**S(4)*(S(3)*A*b + B*a)/S(4) + a*x**S(6)*(A*(a*c + b**S(2)) + B*a*b)/S(2) + c**S(2)*x**S(14)*(A*c + S(3)*B*b)/S(14) + c*x**S(12)*(A*b*c + B*a*c + B*b**S(2))/S(4) + x**S(10)*(S(3)*A*a*c**S(2)/S(10) + S(3)*A*b**S(2)*c/S(10) + S(3)*B*a*b*c/S(5) + B*b**S(3)/S(10)) + x**S(8)*(A*(S(6)*a*b*c + b**S(3))/S(8) + S(3)*B*a*(a*c + b**S(2))/S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, A*a**S(3)*x + B*c**S(3)*x**S(15)/S(15) + a**S(2)*x**S(3)*(S(3)*A*b + B*a)/S(3) + S(3)*a*x**S(5)*(A*(a*c + b**S(2)) + B*a*b)/S(5) + c**S(2)*x**S(13)*(A*c + S(3)*B*b)/S(13) + S(3)*c*x**S(11)*(A*b*c + B*a*c + B*b**S(2))/S(11) + x**S(9)*(A*a*c**S(2)/S(3) + A*b**S(2)*c/S(3) + S(2)*B*a*b*c/S(3) + B*b**S(3)/S(9)) + x**S(7)*(A*(S(6)*a*b*c + b**S(3))/S(7) + S(3)*B*a*(a*c + b**S(2))/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3)/x, x), x, A*a**S(3)*log(x) + B*c**S(3)*x**S(14)/S(14) + a**S(2)*x**S(2)*(S(3)*A*b + B*a)/S(2) + S(3)*a*x**S(4)*(A*(a*c + b**S(2)) + B*a*b)/S(4) + c**S(2)*x**S(12)*(A*c + S(3)*B*b)/S(12) + S(3)*c*x**S(10)*(A*b*c + B*a*c + B*b**S(2))/S(10) + x**S(8)*(S(3)*A*a*c**S(2)/S(8) + S(3)*A*b**S(2)*c/S(8) + S(3)*B*a*b*c/S(4) + B*b**S(3)/S(8)) + x**S(6)*(A*(S(6)*a*b*c + b**S(3))/S(6) + B*a*(a*c + b**S(2))/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3)/x**S(2), x), x, -A*a**S(3)/x + B*c**S(3)*x**S(13)/S(13) + a**S(2)*x*(S(3)*A*b + B*a) + a*x**S(3)*(A*(a*c + b**S(2)) + B*a*b) + c**S(2)*x**S(11)*(A*c + S(3)*B*b)/S(11) + c*x**S(9)*(A*b*c + B*a*c + B*b**S(2))/S(3) + x**S(7)*(S(3)*A*a*c**S(2)/S(7) + S(3)*A*b**S(2)*c/S(7) + S(6)*B*a*b*c/S(7) + B*b**S(3)/S(7)) + x**S(5)*(A*(S(6)*a*b*c + b**S(3))/S(5) + S(3)*B*a*(a*c + b**S(2))/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3)/x**S(3), x), x, -A*a**S(3)/(S(2)*x**S(2)) + B*c**S(3)*x**S(12)/S(12) + a**S(2)*(S(3)*A*b + B*a)*log(x) + S(3)*a*x**S(2)*(A*(a*c + b**S(2)) + B*a*b)/S(2) + c**S(2)*x**S(10)*(A*c + S(3)*B*b)/S(10) + S(3)*c*x**S(8)*(A*b*c + B*a*c + B*b**S(2))/S(8) + x**S(6)*(A*a*c**S(2)/S(2) + A*b**S(2)*c/S(2) + B*a*b*c + B*b**S(3)/S(6)) + x**S(4)*(A*(S(6)*a*b*c + b**S(3))/S(4) + S(3)*B*a*(a*c + b**S(2))/S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, B*x**S(4)/(S(4)*c) - x**S(2)*(-A*c + B*b)/(S(2)*c**S(2)) + (-A*b*c - B*a*c + B*b**S(2))*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)) + (S(2)*A*a*c**S(2) - A*b**S(2)*c - S(3)*B*a*b*c + B*b**S(3))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, B*x**S(2)/(S(2)*c) - (-A*c + B*b)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) - (-A*b*c - S(2)*B*a*c + B*b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, B*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c) + (-S(2)*A*c + B*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x*(a + b*x**S(2) + c*x**S(4))), x), x, A*log(x)/a - A*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a) + (A*b - S(2)*B*a)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(3)*(a + b*x**S(2) + c*x**S(4))), x), x, -A/(S(2)*a*x**S(2)) - (A*b - B*a)*log(x)/a**S(2) + (A*b - B*a)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) - (-S(2)*A*a*c + A*b**S(2) - B*a*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, B*x**S(3)/(S(3)*c) - x*(-A*c + B*b)/c**S(2) + sqrt(S(2))*(-A*b*c - B*a*c + B*b**S(2) + (S(2)*A*a*c**S(2) - A*b**S(2)*c - S(3)*B*a*b*c + B*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(-A*b*c - B*a*c + B*b**S(2) - (S(2)*A*a*c**S(2) - A*b**S(2)*c - S(3)*B*a*b*c + B*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, B*x/c - sqrt(S(2))*(-A*c + B*b + (-A*b*c - S(2)*B*a*c + B*b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(-A*c + B*b - (-A*b*c - S(2)*B*a*c + B*b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(S(2))*(B - (-S(2)*A*c + B*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(B + (-S(2)*A*c + B*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, -A/(a*x) - sqrt(S(2))*sqrt(c)*(A - (A*b - S(2)*B*a)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(A + (A*b - S(2)*B*a)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(4)*(a + b*x**S(2) + c*x**S(4))), x), x, -A/(S(3)*a*x**S(3)) + sqrt(S(2))*sqrt(c)*(-A*(-S(2)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) + B*a*(b - sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) - sqrt(S(2))*sqrt(c)*(-A*(-S(2)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) + B*a*(b + sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + (A*b - B*a)/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -x**S(4)*(a*(-S(2)*A*c + B*b) + x**S(2)*(-A*b*c - S(2)*B*a*c + B*b**S(2)))/(S(2)*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + x**S(2)*(-A*b*c - S(6)*B*a*c + S(2)*B*b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))) - (-A*c + S(2)*B*b)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)) - (S(6)*A*a*b*c**S(2) - A*b**S(3)*c + S(12)*B*a**S(2)*c**S(2) - S(12)*B*a*b**S(2)*c + S(2)*B*b**S(4))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, B*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) - x**S(2)*(a*(-S(2)*A*c + B*b) + x**S(2)*(-A*b*c - S(2)*B*a*c + B*b**S(2)))/(S(2)*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + (S(4)*A*a*c**S(2) - S(6)*B*a*b*c + B*b**S(3))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, (A + B*x**S(2))*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (A*b - S(2)*B*a)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -(-S(2)*A*c + B*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - (A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, A*log(x)/a**S(2) - A*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) - (-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + (A*(-S(6)*a*b*c + b**S(3)) + S(4)*B*a**S(2)*c)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(3)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(2)*a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (-S(6)*A*a*c + S(2)*A*b**S(2) - B*a*b)/(S(2)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) - (S(2)*A*b - B*a)*log(x)/a**S(3) + (S(2)*A*b - B*a)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(3)) + (-S(2)*A*(S(6)*a**S(2)*c**S(2) - S(6)*a*b**S(2)*c + b**S(4)) + B*a*b*(-S(6)*a*c + b**S(2)))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -x**S(5)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - x**S(3)*(-S(2)*A*c + B*b)/(S(2)*c*(-S(4)*a*c + b**S(2))) + x*(-A*b*c - S(10)*B*a*c + S(3)*B*b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*(S(6)*A*a*c**S(2) - A*b**S(2)*c - S(13)*B*a*b*c + S(3)*B*b**S(3) + (S(8)*A*a*b*c**S(2) - A*b**S(3)*c + S(20)*B*a**S(2)*c**S(2) - S(19)*B*a*b**S(2)*c + S(3)*B*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*(S(6)*A*a*c**S(2) - A*b**S(2)*c - S(13)*B*a*b*c + S(3)*B*b**S(3) - (S(8)*A*a*b*c**S(2) - A*b**S(3)*c + S(20)*B*a**S(2)*c**S(2) - S(19)*B*a*b**S(2)*c + S(3)*B*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -x**S(3)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - x*(-S(2)*A*c + B*b)/(S(2)*c*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(A*b*c - S(6)*B*a*c + B*b**S(2) + (S(4)*A*a*c**S(2) + A*b**S(2)*c - S(8)*B*a*b*c + B*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(A*b*c - S(6)*B*a*c + B*b**S(2) - (S(4)*A*a*c**S(2) + A*b**S(2)*c - S(8)*B*a*b*c + B*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -x*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(-S(2)*A*c + B*b + (-S(4)*A*b*c + S(4)*B*a*c + B*b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(-S(2)*A*c + B*b - (-S(4)*A*b*c + S(4)*B*a*c + B*b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, sqrt(S(2))*sqrt(c)*(A*b - S(2)*B*a - (-S(12)*A*a*c + A*b**S(2) + S(4)*B*a*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(A*b - S(2)*B*a + (A*(-S(12)*a*c + b**S(2)) + S(4)*B*a*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) - x*(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(2)*a*x*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*sqrt(c)*(-S(10)*A*a*c + S(3)*A*b**S(2) - B*a*b + (-A*(-S(16)*a*b*c + S(3)*b**S(3)) + B*a*(-S(12)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(-A*(-S(16)*a*b*c - S(10)*a*c*sqrt(-S(4)*a*c + b**S(2)) + S(3)*b**S(3) + S(3)*b**S(2)*sqrt(-S(4)*a*c + b**S(2))) + B*a*(-S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-S(10)*A*a*c + S(3)*A*b**S(2) - B*a*b)/(S(2)*a**S(2)*x*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(4)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(2)*a*x**S(3)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (-S(14)*A*a*c + S(5)*A*b**S(2) - S(3)*B*a*b)/(S(6)*a**S(2)*x**S(3)*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(-A*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c + S(19)*a*b*c*sqrt(-S(4)*a*c + b**S(2)) + S(5)*b**S(4) - S(5)*b**S(3)*sqrt(-S(4)*a*c + b**S(2))) + B*a*(-S(16)*a*b*c + S(10)*a*c*sqrt(-S(4)*a*c + b**S(2)) + S(3)*b**S(3) - S(3)*b**S(2)*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*sqrt(c)*(-A*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c - S(19)*a*b*c*sqrt(-S(4)*a*c + b**S(2)) + S(5)*b**S(4) + S(5)*b**S(3)*sqrt(-S(4)*a*c + b**S(2))) + B*a*(-S(16)*a*b*c - S(10)*a*c*sqrt(-S(4)*a*c + b**S(2)) + S(3)*b**S(3) + S(3)*b**S(2)*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-A*(-S(19)*a*b*c + S(5)*b**S(3)) + B*a*(-S(10)*a*c + S(3)*b**S(2)))/(S(2)*a**S(3)*x*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x**S(8)*(a*(-S(2)*A*c + B*b) + x**S(2)*(-A*b*c - S(2)*B*a*c + B*b**S(2)))/(S(4)*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - x**S(4)*(a*(S(16)*A*a*c**S(2) - A*b**S(2)*c - S(18)*B*a*b*c + S(3)*B*b**S(3)) + x**S(2)*(S(10)*A*a*b*c**S(2) - A*b**S(3)*c + S(20)*B*a**S(2)*c**S(2) - S(20)*B*a*b**S(2)*c + S(3)*B*b**S(4)))/(S(4)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - x**S(2)*(A*(-S(7)*a*b*c + b**S(3)) + S(3)*B*(-S(10)*a**S(2)*c + S(7)*a*b**S(2) - b**S(4)/c))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)) - (-A*c + S(3)*B*b)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(4)) - (-S(30)*A*a**S(2)*b*c**S(3) + S(10)*A*a*b**S(3)*c**S(2) - A*b**S(5)*c - S(60)*B*a**S(3)*c**S(3) + S(90)*B*a**S(2)*b**S(2)*c**S(2) - S(30)*B*a*b**S(4)*c + S(3)*B*b**S(6))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(4)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, B*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)) - x**S(6)*(a*(-S(2)*A*c + B*b) + x**S(2)*(-A*b*c - S(2)*B*a*c + B*b**S(2)))/(S(4)*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - x**S(2)*(S(2)*a*(S(6)*A*a*c**S(2) - S(7)*B*a*b*c + B*b**S(3)) + x**S(2)*(S(6)*A*a*b*c**S(2) + S(16)*B*a**S(2)*c**S(2) - S(15)*B*a*b**S(2)*c + S(2)*B*b**S(4)))/(S(4)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + (-S(12)*A*a**S(2)*c**S(3) + S(30)*B*a**S(2)*b*c**S(2) - S(10)*B*a*b**S(3)*c + B*b**S(5))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(3)*a*(A*b - S(2)*B*a)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) - x**S(6)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + x**S(2)*(S(2)*a + b*x**S(2))*(S(3)*A*b - S(6)*B*a)/(S(4)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x**S(4)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + (S(2)*a + b*x**S(2))*(S(2)*A*b - S(4)*B*a + x**S(2)*(-S(2)*A*c + B*b))/(S(4)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + (-A*(S(2)*a*c + b**S(2)) + S(3)*B*a*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -(-S(3)*A*b*c + S(2)*B*a*c + B*b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + (b + S(2)*c*x**S(2))*(-S(3)*A*b*c + S(2)*B*a*c + B*b**S(2))/(S(4)*c*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - (a*(-S(2)*A*c + B*b) + x**S(2)*(-A*b*c - S(2)*B*a*c + B*b**S(2)))/(S(4)*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(3)*c*(-S(2)*A*c + B*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) - (b + S(2)*c*x**S(2))*(-S(6)*A*c + S(3)*B*b)/(S(4)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - (A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x*(a + b*x**S(2) + c*x**S(4))**S(3)), x), x, A*log(x)/a**S(3) - A*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(3)) - (-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + (A*(S(16)*a**S(2)*c**S(2) - S(15)*a*b**S(2)*c + S(2)*b**S(4)) + S(6)*B*a**S(2)*b*c + S(2)*c*x**S(2)*(A*(-S(7)*a*b*c + b**S(3)) + S(6)*B*a**S(2)*c))/(S(4)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - (-A*(S(30)*a**S(2)*b*c**S(2) - S(10)*a*b**S(3)*c + b**S(5)) + S(12)*B*a**S(3)*c**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(3)*(a + b*x**S(2) + c*x**S(4))**S(3)), x), x, -(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(4)*a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - (-A*(S(20)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4)) + B*a*b*(-S(10)*a*c + b**S(2)) + c*x**S(2)*(-S(3)*A*(-S(6)*a*b*c + b**S(3)) + B*a*(-S(16)*a*c + b**S(2))))/(S(4)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + (-S(3)*A*(S(10)*a**S(2)*c**S(2) - S(7)*a*b**S(2)*c + b**S(4)) + B*a*b*(-S(7)*a*c + b**S(2)))/(S(2)*a**S(3)*x**S(2)*(-S(4)*a*c + b**S(2))**S(2)) - (S(3)*A*b - B*a)*log(x)/a**S(4) + (S(3)*A*b - B*a)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(4)) + (-S(3)*A*(-S(20)*a**S(3)*c**S(3) + S(30)*a**S(2)*b**S(2)*c**S(2) - S(10)*a*b**S(4)*c + b**S(6)) + B*a*b*(S(30)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4)))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(4)*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x**S(7)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - x**S(5)*(-S(4)*A*a*c + S(7)*A*b**S(2) - S(12)*B*a*b + x**S(2)*(S(12)*A*b*c - S(28)*B*a*c + B*b**S(2)))/(S(8)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + x**S(3)*(S(12)*A*b*c - S(28)*B*a*c + B*b**S(2))/(S(8)*c*(-S(4)*a*c + b**S(2))**S(2)) - x*(S(20)*A*a*c**S(2) + A*b**S(2)*c - S(24)*B*a*b*c + S(3)*B*b**S(3))/(S(8)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(-S(16)*A*a*b*c**S(2) + A*b**S(3)*c + S(84)*B*a**S(2)*c**S(2) - S(27)*B*a*b**S(2)*c + S(3)*B*b**S(4) + (-S(40)*A*a**S(2)*c**S(3) - S(18)*A*a*b**S(2)*c**S(2) + A*b**S(4)*c + S(132)*B*a**S(2)*b*c**S(2) - S(33)*B*a*b**S(3)*c + S(3)*B*b**S(5))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(-S(16)*A*a*b*c**S(2) + A*b**S(3)*c + S(84)*B*a**S(2)*c**S(2) - S(27)*B*a*b**S(2)*c + S(3)*B*b**S(4) - (-S(40)*A*a**S(2)*c**S(3) - S(18)*A*a*b**S(2)*c**S(2) + A*b**S(4)*c + S(132)*B*a**S(2)*b*c**S(2) - S(33)*B*a*b**S(3)*c + S(3)*B*b**S(5))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x**S(5)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - x**S(3)*(S(4)*A*a*c + S(5)*A*b**S(2) - S(12)*B*a*b - x**S(2)*(-S(12)*A*b*c + S(20)*B*a*c + B*b**S(2)))/(S(8)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - x*(-S(12)*A*b*c + S(20)*B*a*c + B*b**S(2))/(S(8)*c*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(S(12)*A*a*c**S(2) + S(3)*A*b**S(2)*c - S(16)*B*a*b*c + B*b**S(3) + (S(36)*A*a*b*c**S(2) + S(3)*A*b**S(3)*c - S(40)*B*a**S(2)*c**S(2) - S(18)*B*a*b**S(2)*c + B*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(S(12)*A*a*c**S(2) + S(3)*A*b**S(2)*c - S(16)*B*a*b*c + B*b**S(3) - (S(36)*A*a*b*c**S(2) + S(3)*A*b**S(3)*c - S(40)*B*a**S(2)*c**S(2) - S(18)*B*a*b**S(2)*c + B*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x**S(3)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + S(3)*x*(-A*(S(4)*a*c + b**S(2)) + S(4)*B*a*b + x**S(2)*(-S(4)*A*b*c + S(4)*B*a*c + B*b**S(2)))/(S(8)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(-S(12)*A*b*c + S(12)*B*a*c + S(3)*B*b**S(2) + S(3)*(-S(8)*A*a*c**S(2) - S(6)*A*b**S(2)*c + S(12)*B*a*b*c + B*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*(-S(12)*A*b*c + S(12)*B*a*c + S(3)*B*b**S(2) - S(3)*(-S(8)*A*a*c**S(2) - S(6)*A*b**S(2)*c + S(12)*B*a*b*c + B*b**S(3))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(16)*a*c + S(4)*b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - sqrt(S(2))*sqrt(c)*(-A*(S(20)*a*c + b**S(2)) + S(12)*B*a*b + (A*(-S(52)*a*b*c + b**S(3)) + S(6)*B*a*(S(4)*a*c + S(3)*b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - sqrt(S(2))*sqrt(c)*(-A*(S(20)*a*c + b**S(2)) + S(12)*B*a*b - (A*(-S(52)*a*b*c + b**S(3)) + S(6)*B*a*(S(4)*a*c + S(3)*b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) - x*(-A*(S(8)*a*b*c + b**S(3)) + B*a*(-S(4)*a*c + S(7)*b**S(2)) + c*x**S(2)*(-A*(S(20)*a*c + b**S(2)) + S(12)*B*a*b))/(S(8)*a*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -x*(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + sqrt(S(2))*sqrt(c)*(S(3)*A*(-S(8)*a*b*c + b**S(3)) + B*a*(S(20)*a*c + b**S(2)) - (S(3)*A*(S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4)) + B*a*b*(-S(52)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + sqrt(S(2))*sqrt(c)*(S(3)*A*(-S(8)*a*b*c + b**S(3)) + B*a*(S(20)*a*c + b**S(2)) + (S(3)*A*(S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4)) + B*a*b*(-S(52)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**S(2)) + x*(A*(S(28)*a**S(2)*c**S(2) - S(25)*a*b**S(2)*c + S(3)*b**S(4)) + B*a*b*(S(8)*a*c + b**S(2)) + c*x**S(2)*(S(3)*A*(-S(8)*a*b*c + b**S(3)) + B*a*(S(20)*a*c + b**S(2))))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(S(4)*x**S(2) + S(-7))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, log(-x**S(2) + S(1))/S(2) + S(3)*log(-x**S(2) + S(4))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(4)*x**S(3) - S(7)*x)/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, log(-x**S(2) + S(1))/S(2) + S(3)*log(-x**S(2) + S(4))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(x**S(2) + S(2))/(x**S(4) + x**S(2) + S(1)), x), x, log(x**S(4) + x**S(2) + S(1))/S(4) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(2)*x)/(x**S(4) + x**S(2) + S(1)), x), x, log(x**S(4) + x**S(2) + S(1))/S(4) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(3) + S(11)*x)/(x**S(4) + S(2)*x**S(2) + S(3))**S(2), x), x, (S(9)*x**S(2) + S(5))/(S(8)*x**S(4) + S(16)*x**S(2) + S(24)) + S(9)*sqrt(S(2))*atan(sqrt(S(2))*(x**S(2) + S(1))/S(2))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -(a + b*x**S(2) + c*x**S(4))**(S(5)/2)*(-S(12)*A*c + S(7)*B*b - S(10)*B*c*x**S(2))/(S(120)*c**S(2)) + (b + S(2)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)*(-S(12)*A*b*c - S(4)*B*a*c + S(7)*B*b**S(2))/(S(384)*c**S(3)) - (b + S(2)*c*x**S(2))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(-S(12)*A*b*c - S(4)*B*a*c + S(7)*B*b**S(2))/(S(1024)*c**S(4)) + (-S(4)*a*c + b**S(2))**S(2)*(-S(12)*A*b*c - S(4)*B*a*c + S(7)*B*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2048)*c**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, B*(a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(10)*c) - (b + S(2)*c*x**S(2))*(-S(2)*A*c + B*b)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(32)*c**S(2)) + (b + S(2)*c*x**S(2))*(-S(2)*A*c + B*b)*(-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(256)*c**S(3)) - S(3)*(-S(2)*A*c + B*b)*(-S(4)*a*c + b**S(2))**S(2)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(512)*c**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x, x), x, -A*a**(S(3)/2)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(2) + (a + b*x**S(2) + c*x**S(4))**(S(3)/2)*(S(8)*A*c + S(3)*B*b + S(6)*B*c*x**S(2))/(S(48)*c) - sqrt(a + b*x**S(2) + c*x**S(4))*(-S(64)*A*a*c**S(2) - S(8)*A*b**S(2)*c - S(12)*B*a*b*c + S(3)*B*b**S(3) + S(2)*c*x**S(2)*(-S(8)*A*b*c - S(12)*B*a*c + S(3)*B*b**S(2)))/(S(128)*c**S(2)) + (S(64)*A*a*b*c**S(2) + (-S(4)*a*c + b**S(2))*(-S(8)*A*b*c - S(12)*B*a*c + S(3)*B*b**S(2)))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(3), x), x, -sqrt(a)*(S(3)*A*b + S(2)*B*a)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/S(4) - (S(3)*A - B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*x**S(2)) + sqrt(a + b*x**S(2) + c*x**S(4))*(S(18)*A*b*c + S(8)*B*a*c + B*b**S(2) + S(2)*c*x**S(2)*(S(6)*A*c + B*b))/(S(16)*c) - (-S(24)*A*a*c**S(2) - S(6)*A*b**S(2)*c - S(12)*B*a*b*c + B*b**S(3))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(5), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))*(S(3)*A*b + S(6)*B*a - S(3)*x**S(2)*(S(2)*A*c + B*b))/(S(8)*x**S(2)) - (A - B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(4)*x**S(4)) + (S(12)*A*b*c + S(12)*B*a*c + S(3)*B*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*sqrt(c)) - (S(3)*A*(S(4)*a*c + b**S(2)) + S(12)*B*a*b)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*sqrt(a)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(144)*A*a*b*c**S(2) - S(18)*A*b**S(3)*c + S(84)*B*a**S(2)*c**S(2) - S(57)*B*a*b**S(2)*c + S(8)*B*b**S(4))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(315)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(144)*A*a*b*c**S(2) - S(18)*A*b**S(3)*c + S(84)*B*a**S(2)*c**S(2) - S(57)*B*a*b**S(2)*c + S(8)*B*b**S(4) + sqrt(a)*sqrt(c)*(S(180)*A*a*c**S(2) - S(9)*A*b**S(2)*c - S(24)*B*a*b*c + S(4)*B*b**S(3)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(630)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + x*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)*(S(9)*A*c + S(3)*B*b + S(7)*B*c*x**S(2))/(S(63)*c) - x*sqrt(a + b*x**S(2) + c*x**S(4))*(-S(90)*A*a*c**S(2) - S(9)*A*b**S(2)*c - S(9)*B*a*b*c + S(4)*B*b**S(3) + S(3)*c*x**S(2)*(-S(9)*A*b*c - S(14)*B*a*c + S(4)*B*b**S(2)))/(S(315)*c**S(2)) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(S(144)*A*a*b*c**S(2) - S(18)*A*b**S(3)*c + S(84)*B*a**S(2)*c**S(2) - S(57)*B*a*b**S(2)*c + S(8)*B*b**S(4))/(S(315)*c**(S(5)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(2), x), x, a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(84)*A*a*c**S(2) - S(7)*A*b**S(2)*c - S(16)*B*a*b*c + S(2)*B*b**S(3))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(35)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(84)*A*a*c**S(2) - S(7)*A*b**S(2)*c - S(16)*B*a*b*c + S(2)*B*b**S(3) + sqrt(a)*sqrt(c)*(-S(56)*A*b*c - S(20)*B*a*c + B*b**S(2)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(70)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - (S(7)*A - B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(7)*x) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(S(49)*A*b*c + S(10)*B*a*c + B*b**S(2) + S(3)*c*x**S(2)*(S(14)*A*c + B*b))/(S(35)*c) - x*sqrt(a + b*x**S(2) + c*x**S(4))*(-S(84)*A*a*c**S(2) - S(7)*A*b**S(2)*c - S(16)*B*a*b*c + S(2)*B*b**S(3))/(S(35)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(4), x), x, -a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(40)*A*b*c + S(36)*B*a*c + S(3)*B*b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(15)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(40)*A*b*c + S(36)*B*a*c + S(3)*B*b**S(2) + sqrt(c)*(S(5)*A*(S(4)*a*c + S(3)*b**S(2)) + S(24)*B*a*b)/sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(30)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - sqrt(a + b*x**S(2) + c*x**S(4))*(S(15)*A*b + S(18)*B*a - x**S(2)*(S(10)*A*c + S(3)*B*b))/(S(15)*x) - (S(5)*A - S(3)*B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(15)*x**S(3)) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(S(40)*A*b*c + S(36)*B*a*c + S(3)*B*b**S(2))/(S(15)*sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/x**S(6), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))*(S(3)*A*b + S(10)*B*a - x**S(2)*(S(18)*A*c + S(15)*B*b))/(S(15)*x**S(3)) - (S(3)*A - S(5)*B*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(15)*x**S(5)) + sqrt(c)*x*(S(3)*A*(S(12)*a*c + b**S(2)) + S(40)*B*a*b)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*a*(sqrt(a) + sqrt(c)*x**S(2))) - (S(3)*A*(S(12)*a*c + b**S(2)) + S(40)*B*a*b)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*a*x) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(3)*A*(S(12)*a*c + b**S(2)) + S(40)*B*a*b)*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(15)*a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*sqrt(a)*sqrt(c) + b)*(S(3)*A*b*sqrt(c) + S(10)*B*a*sqrt(c) + S(3)*sqrt(a)*(S(6)*A*c + S(5)*B*b))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(30)*a**(S(3)/4)*c**(S(1)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(A + B*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, B*x**S(4)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(6)*c) + sqrt(a + b*x**S(2) + c*x**S(4))*(-S(18)*A*b*c - S(16)*B*a*c + S(15)*B*b**S(2) - S(2)*c*x**S(2)*(-S(6)*A*c + S(5)*B*b))/(S(48)*c**S(3)) - (S(8)*A*a*c**S(2) - S(6)*A*b**S(2)*c - S(12)*B*a*b*c + S(5)*B*b**S(3))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(a + b*x**S(2) + c*x**S(4))*(-S(4)*A*c + S(3)*B*b - S(2)*B*c*x**S(2))/(S(8)*c**S(2)) + (-S(4)*A*b*c - S(4)*B*a*c + S(3)*B*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, B*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*c) - (-S(2)*A*c + B*b)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*c**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -A*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(a)) + B*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(c)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -A*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*a*x**S(2)) + (A*b - S(2)*B*a)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(5)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -A*sqrt(a + b*x**S(2) + c*x**S(4))/(S(4)*a*x**S(4)) + (S(3)*A*b - S(4)*B*a)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*a**S(2)*x**S(2)) - (-S(4)*A*a*c + S(3)*A*b**S(2) - S(4)*B*a*b)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(7)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -A*sqrt(a + b*x**S(2) + c*x**S(4))/(S(6)*a*x**S(6)) + (S(5)*A*b - S(6)*B*a)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(24)*a**S(2)*x**S(4)) - sqrt(a + b*x**S(2) + c*x**S(4))*(-S(16)*A*a*c + S(15)*A*b**S(2) - S(18)*B*a*b)/(S(48)*a**S(3)*x**S(2)) + (-S(12)*A*a*b*c + S(5)*A*b**S(3) + S(8)*B*a**S(2)*c - S(6)*B*a*b**S(2))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*a**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(A + B*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, B*x**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(5)*c) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(10)*A*b*c - S(9)*B*a*c + S(8)*B*b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(15)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(10)*A*b*c - S(9)*B*a*c + S(8)*B*b**S(2) + sqrt(a)*sqrt(c)*(-S(5)*A*c + S(4)*B*b))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(30)*c**(S(11)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - x*(-S(5)*A*c + S(4)*B*b)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(15)*c**S(2)) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(-S(10)*A*b*c - S(9)*B*a*c + S(8)*B*b**S(2))/(S(15)*c**(S(5)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, B*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*c) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*A*c + S(2)*B*b)*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*A*c + B*sqrt(a)*sqrt(c) + S(2)*B*b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*c**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - x*(-S(3)*A*c + S(2)*B*b)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, -B*a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + B*x*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(A*sqrt(c)/sqrt(a) + B)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*c**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, A*sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(a*(sqrt(a) + sqrt(c)*x**S(2))) - A*sqrt(a + b*x**S(2) + c*x**S(4))/(a*x) - A*c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(3)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) + sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(A*sqrt(c) + B*sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(3)/4)*c**(S(1)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(4)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -A*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a*x**S(3)) - sqrt(c)*x*(S(2)*A*b - S(3)*B*a)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a**S(2)*(sqrt(a) + sqrt(c)*x**S(2))) + (S(2)*A*b - S(3)*B*a)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(3)*a**S(2)*x) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*A*b - S(3)*B*a)*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(A*sqrt(a)*sqrt(c) + S(2)*A*b - S(3)*B*a)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*a**(S(7)/4)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -x**S(2)*(a*(-S(2)*A*c + B*b) + x**S(2)*(-A*b*c - S(2)*B*a*c + B*b**S(2)))/(c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + sqrt(a + b*x**S(2) + c*x**S(4))*(-S(2)*A*b*c - S(8)*B*a*c + S(3)*B*b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))) - (-S(2)*A*c + S(3)*B*b)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*c**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, B*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*c**(S(3)/2)) - (a*(-S(2)*A*c + B*b) + x**S(2)*(-A*b*c - S(2)*B*a*c + B*b**S(2)))/(c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -A*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*a**(S(3)/2)) - (-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(a*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(3)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(a*x**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - sqrt(a + b*x**S(2) + c*x**S(4))*(-S(8)*A*a*c + S(3)*A*b**S(2) - S(2)*B*a*b)/(S(2)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) + (S(3)*A*b - S(2)*B*a)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-A*b*c - S(6)*B*a*c + S(2)*B*b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-A*c - S(3)*B*sqrt(a)*sqrt(c) + S(2)*B*b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(7)/4)*(-S(4)*sqrt(a)*sqrt(c) + S(2)*b)*sqrt(a + b*x**S(2) + c*x**S(4))) - x**S(3)*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - x*(-S(2)*A*c + B*b)*sqrt(a + b*x**S(2) + c*x**S(4))/(c*(-S(4)*a*c + b**S(2))) + x*sqrt(a + b*x**S(2) + c*x**S(4))*(-A*b*c - S(6)*B*a*c + S(2)*B*b**S(2))/(c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, a**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(2)*A*c + B*b)*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(c**(S(3)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - x*(A*b - S(2)*B*a - x**S(2)*(-S(2)*A*c + B*b))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - x*(-S(2)*A*c + B*b)*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))) - sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-A*sqrt(c) + B*sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*c**(S(3)/4)*(-S(2)*sqrt(a)*sqrt(c) + b)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -sqrt(c)*x*(A*b - S(2)*B*a)*sqrt(a + b*x**S(2) + c*x**S(4))/(a*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))) - x*(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(a*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(A*b - S(2)*B*a)*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(3)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-A*sqrt(c) + B*sqrt(a))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(3)/4)*c**(S(1)/4)*(-S(2)*sqrt(a)*sqrt(c) + b)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x**S(2))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -(-A*(-S(2)*a*c + b**S(2)) + B*a*b - c*x**S(2)*(A*b - S(2)*B*a))/(a*x*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + sqrt(c)*x*sqrt(a + b*x**S(2) + c*x**S(4))*(-S(6)*A*a*c + S(2)*A*b**S(2) - B*a*b)/(a**S(2)*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))) - sqrt(a + b*x**S(2) + c*x**S(4))*(-S(6)*A*a*c + S(2)*A*b**S(2) - B*a*b)/(a**S(2)*x*(-S(4)*a*c + b**S(2))) - c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(6)*A*a*c + S(2)*A*b**S(2) - B*a*b)*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + c**(S(1)/4)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*A*sqrt(a)*sqrt(c) + S(2)*A*b - B*a)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(7)/4)*(-S(2)*sqrt(a)*sqrt(c) + b)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**(S(3)/2)*(d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*d*(f*x)**(S(5)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(5)/4, S(-1)/2, S(-1)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*f*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*e*(f*x)**(S(9)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(9)/4, S(-1)/2, S(-1)/2, S(13)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(9)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(f*x)*(d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*d*(f*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(3)/4, S(-1)/2, S(-1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*f*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*e*(f*x)**(S(7)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(7)/4, S(-1)/2, S(-1)/2, S(11)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(7)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/sqrt(f*x), x), x, S(2)*d*sqrt(f*x)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(1)/4, S(-1)/2, S(-1)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*e*(f*x)**(S(5)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(5)/4, S(-1)/2, S(-1)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(f*x)**(S(3)/2), x), x, -S(2)*d*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(-1)/4, S(-1)/2, S(-1)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*sqrt(f*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*e*(f*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(3)/4, S(-1)/2, S(-1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**(S(3)/2)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*a*d*(f*x)**(S(5)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(5)/4, S(-3)/2, S(-3)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*f*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*a*e*(f*x)**(S(9)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(9)/4, S(-3)/2, S(-3)/2, S(13)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(9)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(f*x)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*a*d*(f*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(3)/4, S(-3)/2, S(-3)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*f*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*a*e*(f*x)**(S(7)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(7)/4, S(-3)/2, S(-3)/2, S(11)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(7)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/sqrt(f*x), x), x, S(2)*a*d*sqrt(f*x)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(1)/4, S(-3)/2, S(-3)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*a*e*(f*x)**(S(5)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(5)/4, S(-3)/2, S(-3)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(f*x)**(S(3)/2), x), x, -S(2)*a*d*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(-1)/4, S(-3)/2, S(-3)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*sqrt(f*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + S(2)*a*e*(f*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(S(3)/4, S(-3)/2, S(-3)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*f**S(3)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**(S(3)/2)*(d + e*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*d*(f*x)**(S(5)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(5)/4, S(1)/2, S(1)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*f*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(9)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(9)/4, S(1)/2, S(1)/2, S(13)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(9)*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(f*x)*(d + e*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, S(2)*d*(f*x)**(S(3)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(1)/2, S(1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*f*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(7)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(7)/4, S(1)/2, S(1)/2, S(11)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(7)*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(sqrt(f*x)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, S(2)*d*sqrt(f*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/4, S(1)/2, S(1)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(5)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(5)/4, S(1)/2, S(1)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/((f*x)**(S(3)/2)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)*d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-1)/4, S(1)/2, S(1)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*sqrt(f*x)*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(3)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(1)/2, S(1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**(S(3)/2)*(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*d*(f*x)**(S(5)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(5)/4, S(3)/2, S(3)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*a*f*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(9)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(9)/4, S(3)/2, S(3)/2, S(13)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(9)*a*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(f*x)*(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, S(2)*d*(f*x)**(S(3)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(3)/2, S(3)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*f*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(7)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(7)/4, S(3)/2, S(3)/2, S(11)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(7)*a*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/(sqrt(f*x)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, S(2)*d*sqrt(f*x)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(1)/4, S(3)/2, S(3)/2, S(5)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*f*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(5)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(5)/4, S(3)/2, S(3)/2, S(9)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(5)*a*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))/((f*x)**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -S(2)*d*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(-1)/4, S(3)/2, S(3)/2, S(3)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*f*sqrt(f*x)*sqrt(a + b*x**S(2) + c*x**S(4))) + S(2)*e*(f*x)**(S(3)/2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(3)/2, S(3)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*f**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -c*(f*x)**(m + S(1))*(S(2)*a*(-S(2)*c*d*(-m + S(3)) + e*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*d*(-m + S(1)) + b*(S(4)*a*e - d*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*f*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + c*(f*x)**(m + S(1))*(-S(2)*a*(S(2)*c*d*(-m + S(3)) + e*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*(-d*m + d) + b*(S(4)*a*e + d*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*f*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (f*x)**(m + S(1))*(-a*b*e - S(2)*a*c*d + b**S(2)*d + c*x**S(2)*(-S(2)*a*e + b*d))/(S(2)*a*f*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, a*d*(f*x)**(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(m/S(2) + S(1)/2, S(-3)/2, S(-3)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + a*e*(f*x)**(m + S(3))*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(m/S(2) + S(3)/2, S(-3)/2, S(-3)/2, m/S(2) + S(5)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f**S(3)*(m + S(3))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4)), x), x, d*(f*x)**(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(m/S(2) + S(1)/2, S(-1)/2, S(-1)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))) + e*(f*x)**(m + S(3))*sqrt(a + b*x**S(2) + c*x**S(4))*AppellF1(m/S(2) + S(3)/2, S(-1)/2, S(-1)/2, m/S(2) + S(5)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f**S(3)*(m + S(3))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, d*(f*x)**(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(2) + S(1)/2, S(1)/2, S(1)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))) + e*(f*x)**(m + S(3))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(2) + S(3)/2, S(1)/2, S(1)/2, m/S(2) + S(5)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f**S(3)*(m + S(3))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, d*(f*x)**(m + S(1))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(2) + S(1)/2, S(3)/2, S(3)/2, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*f*(m + S(1))*sqrt(a + b*x**S(2) + c*x**S(4))) + e*(f*x)**(m + S(3))*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(m/S(2) + S(3)/2, S(3)/2, S(3)/2, m/S(2) + S(5)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*f**S(3)*(m + S(3))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(3), x), x, a**S(3)*d*(f*x)**(m + S(1))/(f*(m + S(1))) + a**S(2)*(f*x)**(m + S(3))*(a*e + S(3)*b*d)/(f**S(3)*(m + S(3))) + S(3)*a*(f*x)**(m + S(5))*(a*b*e + a*c*d + b**S(2)*d)/(f**S(5)*(m + S(5))) + c**S(3)*e*(f*x)**(m + S(15))/(f**S(15)*(m + S(15))) + c**S(2)*(f*x)**(m + S(13))*(S(3)*b*e + c*d)/(f**S(13)*(m + S(13))) + S(3)*c*(f*x)**(m + S(11))*(a*c*e + b**S(2)*e + b*c*d)/(f**S(11)*(m + S(11))) + (f*x)**(m + S(7))*(S(3)*a**S(2)*c*e + S(3)*a*b**S(2)*e + S(6)*a*b*c*d + b**S(3)*d)/(f**S(7)*(m + S(7))) + (f*x)**(m + S(9))*(S(6)*a*b*c*e + S(3)*a*c**S(2)*d + b**S(3)*e + S(3)*b**S(2)*c*d)/(f**S(9)*(m + S(9))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*d*(f*x)**(m + S(1))/(f*(m + S(1))) + a*(f*x)**(m + S(3))*(a*e + S(2)*b*d)/(f**S(3)*(m + S(3))) + c**S(2)*e*(f*x)**(m + S(11))/(f**S(11)*(m + S(11))) + c*(f*x)**(m + S(9))*(S(2)*b*e + c*d)/(f**S(9)*(m + S(9))) + (f*x)**(m + S(5))*(S(2)*a*b*e + S(2)*a*c*d + b**S(2)*d)/(f**S(5)*(m + S(5))) + (f*x)**(m + S(7))*(S(2)*a*c*e + b**S(2)*e + S(2)*b*c*d)/(f**S(7)*(m + S(7))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, a*d*(f*x)**(m + S(1))/(f*(m + S(1))) + c*e*(f*x)**(m + S(7))/(f**S(7)*(m + S(7))) + (f*x)**(m + S(3))*(a*e + b*d)/(f**S(3)*(m + S(3))) + (f*x)**(m + S(5))*(b*e + c*d)/(f**S(5)*(m + S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, (f*x)**(m + S(1))*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))) + (f*x)**(m + S(1))*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/(f*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d**S(2)*x**S(4)/S(4) + c*e**S(2)*x**S(12)/S(12) + d*x**S(6)*(S(2)*a*e + b*d)/S(6) + e*x**S(10)*(b*e + S(2)*c*d)/S(10) + x**S(8)*(c*d**S(2)/S(8) + e*(a*e + S(2)*b*d)/S(8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d**S(2)*x**S(3)/S(3) + c*e**S(2)*x**S(11)/S(11) + d*x**S(5)*(S(2)*a*e + b*d)/S(5) + e*x**S(9)*(b*e + S(2)*c*d)/S(9) + x**S(7)*(c*d**S(2)/S(7) + e*(a*e + S(2)*b*d)/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d**S(2)*x**S(2)/S(2) + c*e**S(2)*x**S(10)/S(10) + d*x**S(4)*(S(2)*a*e + b*d)/S(4) + e*x**S(8)*(b*e + S(2)*c*d)/S(8) + x**S(6)*(c*d**S(2)/S(6) + e*(a*e + S(2)*b*d)/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d**S(2)*x + c*e**S(2)*x**S(9)/S(9) + d*x**S(3)*(S(2)*a*e + b*d)/S(3) + e*x**S(7)*(b*e + S(2)*c*d)/S(7) + x**S(5)*(c*d**S(2)/S(5) + e*(a*e + S(2)*b*d)/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))/x, x), x, a*d**S(2)*log(x) + c*e**S(2)*x**S(8)/S(8) + d*x**S(2)*(S(2)*a*e + b*d)/S(2) + e*x**S(6)*(b*e + S(2)*c*d)/S(6) + x**S(4)*(c*d**S(2)/S(4) + e*(a*e + S(2)*b*d)/S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))/x**S(2), x), x, -a*d**S(2)/x + c*e**S(2)*x**S(7)/S(7) + d*x*(S(2)*a*e + b*d) + e*x**S(5)*(b*e + S(2)*c*d)/S(5) + x**S(3)*(c*d**S(2)/S(3) + e*(a*e + S(2)*b*d)/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))/x**S(3), x), x, -a*d**S(2)/(S(2)*x**S(2)) + c*e**S(2)*x**S(6)/S(6) + d*(S(2)*a*e + b*d)*log(x) + e*x**S(4)*(b*e + S(2)*c*d)/S(4) + x**S(2)*(c*d**S(2)/S(2) + e*(a*e + S(2)*b*d)/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(2), x), x, c*x**S(7)/(S(7)*e**S(2)) + d**(S(3)/2)*(S(9)*c*d**S(2) - e*(-S(5)*a*e + S(7)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*e**(S(11)/2)) - d**S(2)*x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*e**S(5)*(d + e*x**S(2))) - d*x*(S(4)*c*d**S(2) - e*(-S(2)*a*e + S(3)*b*d))/e**S(5) - x**S(5)*(-b*e + S(2)*c*d)/(S(5)*e**S(3)) + x**S(3)*(S(3)*c*d**S(2) - e*(-a*e + S(2)*b*d))/(S(3)*e**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(2), x), x, c*x**S(5)/(S(5)*e**S(2)) - sqrt(d)*(S(7)*c*d**S(2) - e*(-S(3)*a*e + S(5)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*e**(S(9)/2)) + d*x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*e**S(4)*(d + e*x**S(2))) - x**S(3)*(-b*e + S(2)*c*d)/(S(3)*e**S(3)) + x*(S(3)*c*d**S(2) - e*(-a*e + S(2)*b*d))/e**S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(2), x), x, c*x**S(3)/(S(3)*e**S(2)) - x*(-b*e + S(2)*c*d)/e**S(3) - x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*e**S(3)*(d + e*x**S(2))) + (S(5)*c*d**S(2) - e*(-a*e + S(3)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*sqrt(d)*e**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(2), x), x, c*x/e**S(2) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d*e**S(2)*(d + e*x**S(2))) - (S(3)*c*d**S(2) - e*(a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(3)/2)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(2)*(d + e*x**S(2))**S(2)), x), x, -a/(d**S(2)*x) - x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d**S(2)*e*(d + e*x**S(2))) + (c*d**S(2) + e*(-S(3)*a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(5)/2)*e**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(4)*(d + e*x**S(2))**S(2)), x), x, -a/(S(3)*d**S(2)*x**S(3)) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d**S(3)*(d + e*x**S(2))) - (-S(2)*a*e + b*d)/(d**S(3)*x) + (c*d**S(2) - e*(-S(5)*a*e + S(3)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(7)/2)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(6)*(d + e*x**S(2))**S(2)), x), x, -a/(S(5)*d**S(2)*x**S(5)) - (-S(2)*a*e + b*d)/(S(3)*d**S(3)*x**S(3)) - e*x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d**S(4)*(d + e*x**S(2))) - (c*d**S(2) - e*(-S(3)*a*e + S(2)*b*d))/(d**S(4)*x) - sqrt(e)*(S(3)*c*d**S(2) - e*(-S(7)*a*e + S(5)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(8)*(d + e*x**S(2))**S(2)), x), x, -a/(S(7)*d**S(2)*x**S(7)) - (-S(2)*a*e + b*d)/(S(5)*d**S(3)*x**S(5)) - (c*d**S(2) - e*(-S(3)*a*e + S(2)*b*d))/(S(3)*d**S(4)*x**S(3)) + e**S(2)*x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(2)*d**S(5)*(d + e*x**S(2))) + e*(S(2)*c*d**S(2) - e*(-S(4)*a*e + S(3)*b*d))/(d**S(5)*x) + e**(S(3)/2)*(S(5)*c*d**S(2) - e*(-S(9)*a*e + S(7)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(2)*d**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(3), x), x, c*x**S(5)/(S(5)*e**S(3)) - sqrt(d)*(S(15)*a*e**S(2) - S(35)*b*d*e + S(63)*c*d**S(2))*atan(sqrt(e)*x/sqrt(d))/(S(8)*e**(S(11)/2)) - d**S(2)*x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*e**S(5)*(d + e*x**S(2))**S(2)) + d*x*(S(17)*c*d**S(2) - e*(-S(9)*a*e + S(13)*b*d))/(S(8)*e**S(5)*(d + e*x**S(2))) - x**S(3)*(-b*e + S(3)*c*d)/(S(3)*e**S(4)) + x*(S(6)*c*d**S(2) - e*(-a*e + S(3)*b*d))/e**S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(3), x), x, c*x**S(3)/(S(3)*e**S(3)) + d*x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*e**S(4)*(d + e*x**S(2))**S(2)) - x*(-b*e + S(3)*c*d)/e**S(4) - x*(S(13)*c*d**S(2) - e*(-S(5)*a*e + S(9)*b*d))/(S(8)*e**S(4)*(d + e*x**S(2))) + (S(35)*c*d**S(2) - S(3)*e*(-a*e + S(5)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(8)*sqrt(d)*e**(S(9)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(3), x), x, c*x/e**S(3) - x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*e**S(3)*(d + e*x**S(2))**S(2)) + x*(S(9)*c*d**S(2) - e*(-a*e + S(5)*b*d))/(S(8)*d*e**S(3)*(d + e*x**S(2))) - (S(15)*c*d**S(2) - e*(a*e + S(3)*b*d))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(3)/2)*e**(S(7)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2))**S(3), x), x, x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*d*e**S(2)*(d + e*x**S(2))**S(2)) - x*(S(5)*c*d**S(2) - e*(S(3)*a*e + b*d))/(S(8)*d**S(2)*e**S(2)*(d + e*x**S(2))) + (S(3)*c*d**S(2) + e*(S(3)*a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(5)/2)*e**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(2)*(d + e*x**S(2))**S(3)), x), x, -a/(d**S(3)*x) - x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*d**S(2)*e*(d + e*x**S(2))**S(2)) + x*(c*d**S(2) + e*(-S(7)*a*e + S(3)*b*d))/(S(8)*d**S(3)*e*(d + e*x**S(2))) + (c*d**S(2) + S(3)*e*(-S(5)*a*e + b*d))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(7)/2)*e**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(4)*(d + e*x**S(2))**S(3)), x), x, -a/(S(3)*d**S(3)*x**S(3)) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*d**S(3)*(d + e*x**S(2))**S(2)) + x*(S(3)*c*d**S(2) - e*(-S(11)*a*e + S(7)*b*d))/(S(8)*d**S(4)*(d + e*x**S(2))) - (-S(3)*a*e + b*d)/(d**S(4)*x) + (S(35)*a*e**S(2) - S(15)*b*d*e + S(3)*c*d**S(2))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(9)/2)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(6)*(d + e*x**S(2))**S(3)), x), x, -a/(S(5)*d**S(3)*x**S(5)) - e*x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(4)*d**S(4)*(d + e*x**S(2))**S(2)) - (-S(3)*a*e + b*d)/(S(3)*d**S(4)*x**S(3)) - e*x*(S(7)*c*d**S(2) - e*(-S(15)*a*e + S(11)*b*d))/(S(8)*d**S(5)*(d + e*x**S(2))) - (S(6)*a*e**S(2) - S(3)*b*d*e + c*d**S(2))/(d**S(5)*x) - sqrt(e)*(S(63)*a*e**S(2) - S(35)*b*d*e + S(15)*c*d**S(2))*atan(sqrt(e)*x/sqrt(d))/(S(8)*d**(S(11)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, d**S(4)*log(d + e*x**S(2))/(S(2)*e**S(3)*(a*e**S(2) - b*d*e + c*d**S(2))) + x**S(4)/(S(4)*c*e) - x**S(2)*(b*e + c*d)/(S(2)*c**S(2)*e**S(2)) - (a**S(2)*c*e - a*b**S(2)*e - S(2)*a*b*c*d + b**S(3)*d)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)*(a*e**S(2) - b*d*e + c*d**S(2))) - (S(3)*a**S(2)*b*c*e + S(2)*a**S(2)*c**S(2)*d - a*b**S(3)*e - S(4)*a*b**S(2)*c*d + b**S(4)*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -d**S(3)*log(d + e*x**S(2))/(S(2)*e**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))) + x**S(2)/(S(2)*c*e) + (-a*b*e - a*c*d + b**S(2)*d)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))) + (S(2)*a**S(2)*c*e - a*b**S(2)*e - S(3)*a*b*c*d + b**S(3)*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, d**S(2)*log(d + e*x**S(2))/(S(2)*e*(a*e**S(2) - b*d*e + c*d**S(2))) - (-a*e + b*d)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c*(a*e**S(2) - b*d*e + c*d**S(2))) - (-a*b*e - S(2)*a*c*d + b**S(2)*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, d*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a*e**S(2) - S(4)*b*d*e + S(4)*c*d**S(2)) - d*log(d + e*x**S(2))/(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2)) + (-S(2)*a*e + b*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -e*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a*e**S(2) - S(4)*b*d*e + S(4)*c*d**S(2)) + e*log(d + e*x**S(2))/(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2)) - (-b*e + S(2)*c*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -e**S(2)*log(d + e*x**S(2))/(S(2)*d*(a*e**S(2) - b*d*e + c*d**S(2))) - (-b*e + c*d)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a*(a*e**S(2) - b*d*e + c*d**S(2))) + (S(2)*a*c*e - b**S(2)*e + b*c*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + log(x)/(a*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, e**S(3)*log(d + e*x**S(2))/(S(2)*d**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))) - S(1)/(S(2)*a*d*x**S(2)) + (a*c*e - b**S(2)*e + b*c*d)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))) - (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - (a*e + b*d)*log(x)/(a**S(2)*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(5)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -e**S(4)*log(d + e*x**S(2))/(S(2)*d**S(3)*(a*e**S(2) - b*d*e + c*d**S(2))) - S(1)/(S(4)*a*d*x**S(4)) + (a*e + b*d)/(S(2)*a**S(2)*d**S(2)*x**S(2)) - (S(2)*a*b*c*e - a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(3)*(a*e**S(2) - b*d*e + c*d**S(2))) + (-S(2)*a**S(2)*c**S(2)*e + S(4)*a*b**S(2)*c*e - S(3)*a*b*c**S(2)*d - b**S(4)*e + b**S(3)*c*d)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + (a*b*d*e - a*(-a*e**S(2) + c*d**S(2)) + b**S(2)*d**S(2))*log(x)/(a**S(3)*d**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, d**(S(7)/2)*atan(sqrt(e)*x/sqrt(d))/(e**(S(5)/2)*(a*e**S(2) - b*d*e + c*d**S(2))) + x**S(3)/(S(3)*c*e) - x*(b*e + c*d)/(c**S(2)*e**S(2)) - sqrt(S(2))*(a**S(2)*c*e - a*b**S(2)*e - S(2)*a*b*c*d + b**S(3)*d + (S(3)*a**S(2)*b*c*e + S(2)*a**S(2)*c**S(2)*d - a*b**S(3)*e - S(4)*a*b**S(2)*c*d + b**S(4)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*(a**S(2)*c*e - a*b**S(2)*e - S(2)*a*b*c*d + b**S(3)*d - (S(3)*a**S(2)*b*c*e + S(2)*a**S(2)*c**S(2)*d - a*b**S(3)*e - S(4)*a*b**S(2)*c*d + b**S(4)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -d**(S(5)/2)*atan(sqrt(e)*x/sqrt(d))/(e**(S(3)/2)*(a*e**S(2) - b*d*e + c*d**S(2))) + x/(c*e) + sqrt(S(2))*(-a*b*e - a*c*d + b**S(2)*d + (S(2)*a**S(2)*c*e - a*b**S(2)*e - S(3)*a*b*c*d + b**S(3)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(S(2))*(-a*b*e - a*c*d + b**S(2)*d - (S(2)*a**S(2)*c*e - a*b**S(2)*e - S(3)*a*b*c*d + b**S(3)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, d**(S(3)/2)*atan(sqrt(e)*x/sqrt(d))/(sqrt(e)*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*(-a*e + b*d + (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*(-a*e + b*d - (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, sqrt(S(2))*sqrt(c)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(S(2))*sqrt(c)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(d)*sqrt(e)*atan(sqrt(e)*x/sqrt(d))/(a*e**S(2) - b*d*e + c*d**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*sqrt(c)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) + e**(S(3)/2)*atan(sqrt(e)*x/sqrt(d))/(sqrt(d)*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -e**(S(5)/2)*atan(sqrt(e)*x/sqrt(d))/(d**(S(3)/2)*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(S(2))*sqrt(c)*(S(2)*a*c*e - b**S(2)*e + b*c*d - sqrt(-S(4)*a*c + b**S(2))*(-b*e + c*d))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*sqrt(c)*(S(2)*a*c*e - b**S(2)*e + b*c*d + sqrt(-S(4)*a*c + b**S(2))*(-b*e + c*d))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - S(1)/(a*d*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, e**(S(7)/2)*atan(sqrt(e)*x/sqrt(d))/(d**(S(5)/2)*(a*e**S(2) - b*d*e + c*d**S(2))) - S(1)/(S(3)*a*d*x**S(3)) + sqrt(S(2))*sqrt(c)*(a*c*(S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))) + b**S(3)*e - b**S(2)*(c*d + e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(-S(3)*a*e + d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(S(2))*sqrt(c)*(a*c*e - b**S(2)*e + b*c*d + (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(a*e**S(2) - b*d*e + c*d**S(2))) + (a*e + b*d)/(a**S(2)*d**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(f*x)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)**(S(3)/4)*c**(S(3)/4)*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(f*x)/(sqrt(f)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)))/(S(2)*sqrt(f)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - S(2)**(S(3)/4)*c**(S(3)/4)*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(f*x)/(sqrt(f)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)))/(S(2)*sqrt(f)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(f*x)/(sqrt(f)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)))/(S(2)*sqrt(f)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + S(2)**(S(3)/4)*c**(S(3)/4)*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*sqrt(f*x)/(sqrt(f)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)))/(S(2)*sqrt(f)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)*sqrt(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*e**(S(7)/4)*log(-sqrt(S(2))*d**(S(1)/4)*e**(S(1)/4)*sqrt(f*x) + sqrt(d)*sqrt(f) + sqrt(e)*sqrt(f)*x)/(S(4)*d**(S(3)/4)*sqrt(f)*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(S(2))*e**(S(7)/4)*log(sqrt(S(2))*d**(S(1)/4)*e**(S(1)/4)*sqrt(f*x) + sqrt(d)*sqrt(f) + sqrt(e)*sqrt(f)*x)/(S(4)*d**(S(3)/4)*sqrt(f)*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(S(2))*e**(S(7)/4)*atan(S(1) - sqrt(S(2))*e**(S(1)/4)*sqrt(f*x)/(d**(S(1)/4)*sqrt(f)))/(S(2)*d**(S(3)/4)*sqrt(f)*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(S(2))*e**(S(7)/4)*atan(S(1) + sqrt(S(2))*e**(S(1)/4)*sqrt(f*x)/(d**(S(1)/4)*sqrt(f)))/(S(2)*d**(S(3)/4)*sqrt(f)*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2)), x), x, -b*(b + S(2)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(16)*c**S(2)*e) + b*(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(5)/2)*e) + d**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*e**S(3)) + d**S(2)*sqrt(a*e**S(2) - b*d*e + c*d**S(2))*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e**S(4)) - d*(b + S(2)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*c*e**S(2)) + (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*c*e) - d**S(2)*(-b*e + S(2)*c*d)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(c)*e**S(4)) + d*(-S(4)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*c**(S(3)/2)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2)), x), x, -d*sqrt(a*e**S(2) - b*d*e + c*d**S(2))*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e**S(3)) - sqrt(a + b*x**S(2) + c*x**S(4))*(-b*e + S(4)*c*d - S(2)*c*e*x**S(2))/(S(8)*c*e**S(2)) + (-b**S(2)*e**S(2) + S(8)*c**S(2)*d**S(2) - S(4)*c*e*(-a*e + b*d))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*c**(S(3)/2)*e**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a + b*x**S(2) + c*x**S(4))/(d + e*x**S(2)), x), x, sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*e) + sqrt(a*e**S(2) - b*d*e + c*d**S(2))*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e**S(2)) - (-b*e + S(2)*c*d)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(c)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/(x*(d + e*x**S(2))), x), x, -sqrt(a)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*d) + sqrt(c)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*e) - sqrt(a*e**S(2) - b*d*e + c*d**S(2))*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a + b*x**S(2) + c*x**S(4))/(x**S(3)*(d + e*x**S(2))), x), x, sqrt(a)*e*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*d**S(2)) - b*e*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(c)*d**S(2)) + sqrt(c)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*d) - sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*d*x**S(2)) + sqrt(a*e**S(2) - b*d*e + c*d**S(2))*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d**S(2)) - (-b*e + S(2)*c*d)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(c)*d**S(2)) - b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(a)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*x**S(2) + S(3)), x), x, x*(S(3)*x**S(2) + S(1))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(30) - x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(4) + S(109)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(120)*(sqrt(S(2))*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(-70) + S(263)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(120)*(S(-2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(15)*sqrt(S(2)) + S(45))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(32)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(109)*sqrt(S(2))*x**S(2) + S(109))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(120)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(3)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(16), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(4)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*x**S(2) + S(3)), x), x, x*(S(3)*x**S(2) + S(1))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(30) - x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(4) + S(109)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(120)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(1) + sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(139)*sqrt(S(2)) + S(139))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(480)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(15)*sqrt(S(2)) + S(45))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(32)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(45)*sqrt(S(2))*x**S(2) + S(45))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(109)*sqrt(S(2))*x**S(2) + S(109))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(120)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(3)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*x**S(2) + S(3)), x), x, x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(6) - S(7)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(12)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(-4) + S(17)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*(S(-2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(15))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(7)*sqrt(S(2))*x**S(2) + S(7))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(8), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*x**S(2) + S(3)), x), x, x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(6) - S(7)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(12)*(sqrt(S(2))*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(3)*sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(1) + sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(15))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(7)*sqrt(S(2))*x**S(2) + S(7))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(15)*sqrt(S(2))*x**S(2) + S(15))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*x**S(2) + S(3)), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(2)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((S(-2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(15))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(24)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(12), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*x**S(2) + S(3)), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(2)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(2)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-sqrt(S(2)) + S(1))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(15))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(24)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2))*x**S(2) + S(5))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(4)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(x**S(2)*(S(2)*x**S(2) + S(3))), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*sqrt(S(2))*x**S(2) + S(3)) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((S(-6) + S(9)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(15))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(36)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(18) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(x**S(2)*(S(2)*x**S(2) + S(3))), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*sqrt(S(2))*x**S(2) + S(3)) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(15))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(36)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2))*x**S(2) + S(5))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(6)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(18) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(x**S(4)*(S(2)*x**S(2) + S(3))), x), x, -S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(18)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(5)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(27)*sqrt(S(2)) + S(18))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(15))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(54)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(27) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(9)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(x**S(6)*(S(2)*x**S(2) + S(3))), x), x, S(4)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(45)*sqrt(S(2))*x**S(2) + S(45)) - S(4)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(45)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(10)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(81)*sqrt(S(2)) + S(54))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(2)*sqrt(S(2)) + S(19))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(135)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(5)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(27)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(5)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(243)*sqrt(S(2)) + S(162))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(81) - S(4)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(45)*x) + S(4)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(135)*x**S(3)) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(15)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(d + e*x**S(2)), x), x, -b*(b + S(2)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(32)*c**S(2)*e) + S(3)*b*(b + S(2)*c*x**S(2))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(256)*c**S(3)*e) - S(3)*b*(-S(4)*a*c + b**S(2))**S(2)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(512)*c**(S(7)/2)*e) + d**S(2)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*e**S(3)) + d**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e**S(6)) + d**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*(b**S(2)*e**S(2) + S(8)*c**S(2)*d**S(2) - S(2)*c*e*x**S(2)*(-b*e + S(2)*c*d) - S(2)*c*e*(-S(4)*a*e + S(5)*b*d))/(S(16)*c*e**S(5)) - d*(b + S(2)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(16)*c*e**S(2)) + (a + b*x**S(2) + c*x**S(4))**(S(5)/2)/(S(10)*c*e) + d*(b + S(2)*c*x**S(2))*(-S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(128)*c**S(2)*e**S(2)) - d**S(2)*(-b*e + S(2)*c*d)*(-b**S(2)*e**S(2) + S(8)*c**S(2)*d**S(2) - S(4)*c*e*(-S(3)*a*e + S(2)*b*d))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(3)/2)*e**S(6)) - S(3)*d*(-S(4)*a*c + b**S(2))**S(2)*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*c**(S(5)/2)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(d + e*x**S(2)), x), x, -d*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e**S(5)) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)*(-S(3)*b*e + S(8)*c*d - S(6)*c*e*x**S(2))/(S(48)*c*e**S(2)) - sqrt(a + b*x**S(2) + c*x**S(4))*(S(3)*b**S(3)*e**S(3) + S(4)*b*c*e**S(2)*(-S(3)*a*e + S(2)*b*d) + S(64)*c**S(3)*d**S(3) - S(16)*c**S(2)*d*e*(-S(4)*a*e + S(5)*b*d) - S(2)*c*e*x**S(2)*(-S(3)*b**S(2)*e**S(2) + S(16)*c**S(2)*d**S(2) - S(4)*c*e*(-S(3)*a*e + S(2)*b*d)))/(S(128)*c**S(2)*e**S(4)) + (S(3)*b**S(4)*e**S(4) + S(8)*b**S(2)*c*e**S(3)*(-S(3)*a*e + b*d) + S(128)*c**S(4)*d**S(4) - S(192)*c**S(3)*d**S(2)*e*(-a*e + b*d) + S(48)*c**S(2)*e**S(2)*(-a*e + b*d)**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*c**(S(5)/2)*e**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(d + e*x**S(2)), x), x, (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(6)*e) + (a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e**S(4)) + sqrt(a + b*x**S(2) + c*x**S(4))*(b**S(2)*e**S(2) + S(8)*c**S(2)*d**S(2) - S(2)*c*e*x**S(2)*(-b*e + S(2)*c*d) - S(2)*c*e*(-S(4)*a*e + S(5)*b*d))/(S(16)*c*e**S(3)) - (-b*e + S(2)*c*d)*(-b**S(2)*e**S(2) + S(8)*c**S(2)*d**S(2) - S(4)*c*e*(-S(3)*a*e + S(2)*b*d))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(3)/2)*e**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(x*(d + e*x**S(2))), x), x, -a**(S(3)/2)*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*d) + a*b*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(c)*d) + a*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*d) - sqrt(a + b*x**S(2) + c*x**S(4))*(S(4)*c*d**S(2) - S(2)*c*d*e*x**S(2) - e*(-S(4)*a*e + S(5)*b*d))/(S(8)*d*e**S(2)) - (a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d*e**S(3)) + (b*e**S(2)*(-S(4)*a*e + S(3)*b*d) + S(8)*c**S(2)*d**S(3) - S(12)*c*d*e*(-a*e + b*d))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*sqrt(c)*d*e**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(x**S(3)*(d + e*x**S(2))), x), x, a**(S(3)/2)*e*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*d**S(2)) - S(3)*sqrt(a)*b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*d) + b*e*(-S(12)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(3)/2)*d**S(2)) + (S(9)*b + S(6)*c*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(8)*d) - (a + b*x**S(2) + c*x**S(4))**(S(3)/2)/(S(2)*d*x**S(2)) + (a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d**S(2)*e**S(2)) - e*sqrt(a + b*x**S(2) + c*x**S(4))*(S(8)*a*c + b**S(2) + S(2)*b*c*x**S(2))/(S(16)*c*d**S(2)) + sqrt(a + b*x**S(2) + c*x**S(4))*(b**S(2)*e**S(2) + S(8)*c**S(2)*d**S(2) - S(2)*c*e*x**S(2)*(-b*e + S(2)*c*d) - S(2)*c*e*(-S(4)*a*e + S(5)*b*d))/(S(16)*c*d**S(2)*e) + (S(12)*a*c + S(3)*b**S(2))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*sqrt(c)*d) - (-b*e + S(2)*c*d)*(-b**S(2)*e**S(2) + S(8)*c**S(2)*d**S(2) - S(4)*c*e*(-S(3)*a*e + S(2)*b*d))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(32)*c**(S(3)/2)*d**S(2)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/(-S(2)*x**S(2) + S(3)), x), x, -S(27)*x**S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(70) - x*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/S(14) - S(213)*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(140) - S(2211)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(280)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(1542) + S(8151)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(280)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(289)*sqrt(S(2)) + S(867))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(S(1)/2 + S(11)*sqrt(S(2))/S(24), S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(32)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(2211)*sqrt(S(2))*x**S(2) + S(2211))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(280)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(17)*sqrt(S(51))*atanh(sqrt(S(51))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(16), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/(-S(2)*x**S(2) + S(3)), x), x, -S(3)*x*(x**S(2) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(35) - x*(S(3)*x**S(2) + S(1))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(10) - x*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/S(14) - S(5)*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(4) - S(6)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(35)*sqrt(S(2))*x**S(2) + S(35)) - S(309)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(40)*(sqrt(S(2))*x**S(2) + S(1))) + S(6)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(35)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(51)*sqrt(S(2)) + S(255))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(32)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5) + S(5)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(6)*sqrt(S(2)) + S(9))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(140)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-sqrt(S(2)) + S(1))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(40)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(289)*sqrt(S(2)) + S(867))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(S(1)/2 + S(11)*sqrt(S(2))/S(24), S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(32)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(309)*sqrt(S(2))*x**S(2) + S(309))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(40)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(867)*sqrt(S(2))*x**S(2) + S(867))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(17)*sqrt(S(51))*atanh(sqrt(S(51))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(16), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/(-S(2)*x**S(2) + S(3)), x), x, -x**S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(5) - S(9)*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(10) - S(103)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(20)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(66) + S(383)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(289)*sqrt(S(2)) + S(867))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(S(1)/2 + S(11)*sqrt(S(2))/S(24), S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(48)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(103)*sqrt(S(2))*x**S(2) + S(103))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(17)*sqrt(S(51))*atanh(sqrt(S(51))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(24), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/(-S(2)*x**S(2) + S(3)), x), x, -x*(S(3)*x**S(2) + S(1))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(15) - S(5)*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(6) - S(103)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(20)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(17)*sqrt(S(2)) + S(85))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5) + S(5)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-sqrt(S(2)) + S(1))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(60)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(289)*sqrt(S(2)) + S(867))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(S(1)/2 + S(11)*sqrt(S(2))/S(24), S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(48)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(103)*sqrt(S(2))*x**S(2) + S(103))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(289)*sqrt(S(2))*x**S(2) + S(289))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(17)*sqrt(S(51))*atanh(sqrt(S(51))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(24), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/(x**S(2)*(-S(2)*x**S(2) + S(3))), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*sqrt(S(2))*x**S(2) + S(3)) - S(17)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(6)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(17)*sqrt(S(2)) + S(85))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(24)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(6)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(289)*sqrt(S(2)) + S(867))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(S(1)/2 + S(11)*sqrt(S(2))/S(24), S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(72)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(17)*sqrt(S(2))*x**S(2) + S(17))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(6)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(289)*sqrt(S(2))*x**S(2) + S(289))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(17)*sqrt(S(51))*atanh(sqrt(S(51))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(36) - (x**S(2) + S(1))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/(x**S(4)*(-S(2)*x**S(2) + S(3))), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(9)*sqrt(S(2))*x**S(2) + S(9)) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(9)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(17)*sqrt(S(2)) + S(85))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(36)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(5)*sqrt(S(2)) + S(9))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(9)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(289)*sqrt(S(2)) + S(867))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(S(1)/2 + S(11)*sqrt(S(2))/S(24), S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(108)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(289)*sqrt(S(2))*x**S(2) + S(289))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(18)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(17)*sqrt(S(51))*atanh(sqrt(S(51))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(54) - S(2)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/x - (-S(8)*x**S(2) + S(1))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(9)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)/(x**S(6)*(-S(2)*x**S(2) + S(3))), x), x, S(262)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(135)*sqrt(S(2))*x**S(2) + S(135)) - S(262)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(135)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(17)*sqrt(S(2)) + S(51))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(54)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(23)*sqrt(S(2)) + S(37))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(135)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(289)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((S(54) + S(81)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-S(289)*sqrt(S(2)) + S(867))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(S(1)/2 + S(11)*sqrt(S(2))/S(24), S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(162)*(S(2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(17)*sqrt(S(51))*atanh(sqrt(S(51))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(81) - S(262)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(135)*x) + S(74)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(135)*x**S(3)) - (S(40)*x**S(2) + S(3))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(45)*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -b*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*c**(S(3)/2)*e) + d**S(2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e**S(2)*sqrt(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*c*e) - d*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(c)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -d*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e*sqrt(a*e**S(2) - b*d*e + c*d**S(2))) + atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(c)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*sqrt(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, -e*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d*sqrt(a*e**S(2) - b*d*e + c*d**S(2))) - atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(a)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x, e**S(2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d**S(2)*sqrt(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*a*d*x**S(2)) + e*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(a)*d**S(2)) + b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(3)/2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/((S(2)*x**S(2) + S(3))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(4)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(4)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2)) + S(9))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(16)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(9)*sqrt(S(2))*x**S(2) + S(9))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(3)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(40), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((S(2)*x**S(2) + S(3))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))), x), x, S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(8)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(4)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(20), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((S(2)*x**S(2) + S(3))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))), x), x, -S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(2)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(30), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(S(2)*x**S(2) + S(3))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))), x), x, sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*sqrt(S(2))*x**S(2) + S(3)) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(9)*sqrt(S(2)) + S(6))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(6)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(18)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(45) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(S(2)*x**S(2) + S(3))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))), x), x, -S(2)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*sqrt(S(2))*x**S(2) + S(3)) + S(2)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(1) + S(2)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(18)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(9)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(27)*sqrt(S(2)) + S(18))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(81)*sqrt(S(2)) + S(54))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(135) + S(2)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*x) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(9)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -b*sqrt(a + b*x**S(2) + c*x**S(4))/(c*e*(-S(4)*a*c + b**S(2))) - d**S(3)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*e*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)) + d**S(3)*(S(2)*a*c*e - b**S(2)*e + b*c*d + c*x**S(2)*(-b*e + S(2)*c*d))/(e**S(3)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))) - d**S(2)*(b + S(2)*c*x**S(2))/(e**S(3)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - d*(S(2)*a + b*x**S(2))/(e**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + x**S(2)*(S(2)*a + b*x**S(2))/(e*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*c**(S(3)/2)*e), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, d**S(2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)) - d**S(2)*(S(2)*a*c*e - b**S(2)*e + b*c*d + c*x**S(2)*(-b*e + S(2)*c*d))/(e**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))) + d*(b + S(2)*c*x**S(2))/(e**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) + (S(2)*a + b*x**S(2))/(e*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -d*e*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)) + (a*(-b*e + S(2)*c*d) + c*x**S(2)*(-S(2)*a*e + b*d))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/((d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, e**S(2)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)) - (S(2)*a*c*e - b**S(2)*e + b*c*d + c*x**S(2)*(-b*e + S(2)*c*d))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, -e**S(3)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)) + e*(S(2)*a*c*e - b**S(2)*e + b*c*d + c*x**S(2)*(-b*e + S(2)*c*d))/(d*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))) + (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*d*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*a**(S(3)/2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))**(S(3)/2)), x), x, e**S(4)*atanh((-S(2)*a*e + b*d + x**S(2)*(-b*e + S(2)*c*d))/(S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*sqrt(a*e**S(2) - b*d*e + c*d**S(2))))/(S(2)*d**S(2)*(a*e**S(2) - b*d*e + c*d**S(2))**(S(3)/2)) - e**S(2)*(S(2)*a*c*e - b**S(2)*e + b*c*d + c*x**S(2)*(-b*e + S(2)*c*d))/(d**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*(a*e**S(2) - b*d*e + c*d**S(2))) + (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*d*x**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - e*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*d**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))) - (-S(8)*a*c + S(3)*b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*a**S(2)*d*x**S(2)*(-S(4)*a*c + b**S(2))) + e*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*a**(S(3)/2)*d**S(2)) + S(3)*b*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(5)/2)*d), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/((S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, x**S(3)*(-S(2)*x**S(2) + S(1))/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/S(20) + sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(20)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(7))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(80)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(27)*sqrt(S(2)) + S(81))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(160)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(9)*sqrt(S(2))*x**S(2) + S(9))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(80)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(27)*sqrt(S(2))*x**S(2) + S(27))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(160)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(81)*sqrt(S(2))*x**S(2) + S(81))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(80)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(27)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(400), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/((S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, x*(-S(2)*x**S(2) + S(1))/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(20)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-sqrt(S(2)) + S(1))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(80)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(9)*sqrt(S(2)) + S(27))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(80)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(9)*sqrt(S(2))*x**S(2) + S(9))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(80)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(27)*sqrt(S(2))*x**S(2) + S(27))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(40)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(9)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(200), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/((S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, -x*(x**S(2) + S(2))/(S(10)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(20)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-sqrt(S(2)) + S(1))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(40)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2)) + S(9))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(40)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(9)*sqrt(S(2))*x**S(2) + S(9))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(3)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(100), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, x*(S(4)*x**S(2) + S(3))/(S(10)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(5)*sqrt(S(2))*x**S(2) + S(5)) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(5)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(1) + S(2)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(40)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(10)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(50), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, -x*(S(3)*x**S(2) + S(1))/(S(5)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(3)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(10)*(sqrt(S(2))*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(4)*(S(-2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(30)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2))*x**S(2) + S(3))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(10)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(75), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/((S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, -x*(S(3)*x**S(2) + S(1))/(S(5)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(3)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(10)*(sqrt(S(2))*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(15)*sqrt(S(2)) + S(10))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(10)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(30)*(-S(3)*sqrt(S(2)) + S(2))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2))*x**S(2) + S(3))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(10)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(3)*sqrt(S(2))*x**S(2) + S(3))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(20)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(75), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, S(2)*x*(S(3)*x**S(2) + S(1))/(S(15)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(15)*sqrt(S(2))*x**S(2) + S(15)) - S(2)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(15)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(S(-7) + S(3)*sqrt(S(2)))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(6)*(S(-2) + S(3)*sqrt(S(2)))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(135)*sqrt(S(2)) + S(90))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(225) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/(x**S(2)*(S(2)*x**S(2) + S(3))*(S(2)*x**S(4) + S(2)*x**S(2) + S(1))**(S(3)/2)), x), x, S(2)*x*(S(3)*x**S(2) + S(1))/(S(15)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)*sqrt(S(2))*x*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(15)*sqrt(S(2))*x**S(2) + S(15)) - S(2)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_e(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(15)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(10)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(15)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) + S(2)*S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(45)*sqrt(S(2)) + S(30))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(3)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(-sqrt(S(2)) + S(1))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_f(S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/(S(12)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)**(S(1)/4)*sqrt((S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(sqrt(S(2))*x**S(2) + S(1))**S(2))*(sqrt(S(2)) + S(3))*(sqrt(S(2))*x**S(2) + S(1))*elliptic_pi(-S(11)*sqrt(S(2))/S(24) + S(1)/2, S(2)*atan(S(2)**(S(1)/4)*x), -sqrt(S(2))/S(4) + S(1)/2)/((-S(135)*sqrt(S(2)) + S(90))*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))) - S(2)*sqrt(S(15))*atan(sqrt(S(15))*x/(S(3)*sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))))/S(225) - sqrt(S(2)*x**S(4) + S(2)*x**S(2) + S(1))/(S(3)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)*sqrt(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, (d + e*x**S(2))**(S(5)/2)/(S(5)*c*e**S(2)) - (d + e*x**S(2))**(S(3)/2)*(b*e + c*d)/(S(3)*c**S(2)*e**S(2)) + sqrt(d + e*x**S(2))*(-a*c + b**S(2))/c**S(3) - sqrt(S(2))*(S(2)*a*b*c*e - a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d + (-S(2)*a**S(2)*c**S(2)*e + S(4)*a*b**S(2)*c*e - S(3)*a*b*c**S(2)*d - b**S(4)*e + b**S(3)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(7)/2)*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - sqrt(S(2))*(S(2)*a*b*c*e - a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d - (-S(2)*a**S(2)*c**S(2)*e + S(4)*a*b**S(2)*c*e - S(3)*a*b*c**S(2)*d - b**S(4)*e + b**S(3)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(7)/2)*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -b*sqrt(d + e*x**S(2))/c**S(2) + (d + e*x**S(2))**(S(3)/2)/(S(3)*c*e) + sqrt(S(2))*(a*c*e - b**S(2)*e + b*c*d + (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(5)/2)*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + sqrt(S(2))*(a*c*e - b**S(2)*e + b*c*d - (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(5)/2)*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(d + e*x**S(2))/c - sqrt(S(2))*(S(2)*a*c*e - b**S(2)*e + b*c*d + sqrt(-S(4)*a*c + b**S(2))*(-b*e + c*d))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(3)/2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + sqrt(S(2))*(S(2)*a*c*e - b**S(2)*e + b*c*d - sqrt(-S(4)*a*c + b**S(2))*(-b*e + c*d))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(3)/2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(x*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(-S(2)*a*e + b*d - d*sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + sqrt(S(2))*sqrt(c)*(-S(2)*a*e + b*d + d*sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - sqrt(d)*atanh(sqrt(d + e*x**S(2))/sqrt(d))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(x**S(5)*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(d + e*x**S(2))/(S(4)*a*x**S(4)) + S(3)*e*sqrt(d + e*x**S(2))/(S(8)*a*d*x**S(2)) - S(3)*e**S(2)*atanh(sqrt(d + e*x**S(2))/sqrt(d))/(S(8)*a*d**(S(3)/2)) + sqrt(d + e*x**S(2))*(-a*e + b*d)/(S(2)*a**S(2)*d*x**S(2)) - e*(-a*e + b*d)*atanh(sqrt(d + e*x**S(2))/sqrt(d))/(S(2)*a**S(2)*d**(S(3)/2)) - sqrt(S(2))*sqrt(c)*(-a*b*(S(3)*c*d - e*sqrt(-S(4)*a*c + b**S(2))) + a*c*(S(2)*a*e + d*sqrt(-S(4)*a*c + b**S(2))) + b**S(3)*d - b**S(2)*(a*e + d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a**S(3)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + sqrt(S(2))*sqrt(c)*(-a*b*(S(3)*c*d + e*sqrt(-S(4)*a*c + b**S(2))) - a*c*(-S(2)*a*e + d*sqrt(-S(4)*a*c + b**S(2))) + b**S(3)*d + b**S(2)*(-a*e + d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a**S(3)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - (-a*b*e - a*c*d + b**S(2)*d)*atanh(sqrt(d + e*x**S(2))/sqrt(d))/(a**S(3)*sqrt(d)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, x*sqrt(d + e*x**S(2))/(S(2)*c) - (a*c*e - b**S(2)*e + b*c*d + (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - (a*c*e - b**S(2)*e + b*c*d - (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) + (-S(2)*b*e + c*d)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c**S(2)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(e)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/c + (-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + (-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, -c*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - c*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - sqrt(d + e*x**S(2))/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(x**S(4)*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(d + e*x**S(2))/(S(3)*a*x**S(3)) + S(2)*e*sqrt(d + e*x**S(2))/(S(3)*a*d*x) + c*(-a*e + b*d - (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + c*(-a*e + b*d + (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) + sqrt(d + e*x**S(2))*(-a*e + b*d)/(a**S(2)*d*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(2))/(x**S(6)*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(d + e*x**S(2))/(S(5)*a*x**S(5)) + S(4)*e*sqrt(d + e*x**S(2))/(S(15)*a*d*x**S(3)) - S(8)*e**S(2)*sqrt(d + e*x**S(2))/(S(15)*a*d**S(2)*x) + sqrt(d + e*x**S(2))*(-a*e + b*d)/(S(3)*a**S(2)*d*x**S(3)) - S(2)*e*sqrt(d + e*x**S(2))*(-a*e + b*d)/(S(3)*a**S(2)*d**S(2)*x) - c*(-a*b*e - a*c*d + b**S(2)*d - (S(2)*a**S(2)*c*e - a*b**S(2)*e - S(3)*a*b*c*d + b**S(3)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(3)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - c*(-a*b*e - a*c*d + b**S(2)*d + (S(2)*a**S(2)*c*e - a*b**S(2)*e - S(3)*a*b*c*d + b**S(3)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(3)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - sqrt(d + e*x**S(2))*(-a*b*e - a*c*d + b**S(2)*d)/(a**S(3)*d*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(d + e*x**S(2))**(S(3)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, (d + e*x**S(2))**(S(3)/2)/(S(3)*c) + sqrt(d + e*x**S(2))*(-b*e + c*d)/c**S(2) - sqrt(S(2))*(b**S(3)*e**S(2) - b**S(2)*e*(S(2)*c*d - e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(c*d**S(2) - e*(S(3)*a*e + S(2)*d*sqrt(-S(4)*a*c + b**S(2)))) - c*(a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) - c*d*(S(4)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(5)/2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + sqrt(S(2))*(b**S(3)*e**S(2) - b**S(2)*e*(S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))) + b*c*(c*d**S(2) + e*(-S(3)*a*e + S(2)*d*sqrt(-S(4)*a*c + b**S(2)))) + c*(a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) - c*d*(-S(4)*a*e + d*sqrt(-S(4)*a*c + b**S(2)))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(5)/2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(2))**(S(3)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, e*sqrt(d + e*x**S(2))/c + sqrt(S(2))*(b*e**S(2)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d + d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(3)/2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - sqrt(S(2))*(b*e**S(2)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d - d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c**(S(3)/2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)/(x*(a + b*x**S(2) + c*x**S(4))), x), x, -d**(S(3)/2)*atanh(sqrt(d + e*x**S(2))/sqrt(d))/a - sqrt(S(2))*(a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) + b*(a*e**S(2) + c*d**S(2)) - c*d*(S(4)*a*e + d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - sqrt(S(2))*(a*e**S(2)*sqrt(-S(4)*a*c + b**S(2)) - b*(a*e**S(2) + c*d**S(2)) - c*d*(-S(4)*a*e + d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)/(x**S(3)*(a + b*x**S(2) + c*x**S(4))), x), x, sqrt(d)*e*atanh(sqrt(d + e*x**S(2))/sqrt(d))/(S(2)*a) - d*sqrt(d + e*x**S(2))/(S(2)*a*x**S(2)) + sqrt(S(2))*sqrt(c)*(-S(2)*a*(c*d**S(2) - e*(a*e + d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(2)*d**S(2) - b*d*(S(2)*a*e + d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - sqrt(S(2))*sqrt(c)*(-S(2)*a*(c*d**S(2) + e*(-a*e + d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(2)*d**S(2) + b*d*(-S(2)*a*e + d*sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(d + e*x**S(2))/sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) + sqrt(d)*(-S(2)*a*e + b*d)*atanh(sqrt(d + e*x**S(2))/sqrt(d))/a**S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(d + e*x**S(2))**(S(3)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, x*(d + e*x**S(2))**(S(3)/2)/(S(4)*c) + d*(-S(4)*b*e + S(3)*c*d)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(8)*c**S(2)*sqrt(e)) + x*sqrt(d + e*x**S(2))*(-S(4)*b*e + S(3)*c*d)/(S(8)*c**S(2)) - sqrt(e)*(a*c*e - b**S(2)*e + b*c*d - (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c**S(3)) - sqrt(e)*(a*c*e - b**S(2)*e + b*c*d + (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c**S(3)) - sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(a*c*e - b**S(2)*e + b*c*d + (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(S(2)*c**S(3)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(a*c*e - b**S(2)*e + b*c*d - (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(S(2)*c**S(3)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(2))**(S(3)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, d*sqrt(e)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c) + e*x*sqrt(d + e*x**S(2))/(S(2)*c) + sqrt(e)*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c**S(2)) + sqrt(e)*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c**S(2)) + sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(S(2)*c**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(S(2)*c**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)/(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(e)*(S(3)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) - sqrt(e)*(S(3)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) - (b*e**S(2)*(b + sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d + d*sqrt(-S(4)*a*c + b**S(2))))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + (b*e**S(2)*(b - sqrt(-S(4)*a*c + b**S(2))) + S(2)*c**S(2)*d**S(2) - S(2)*c*e*(a*e + b*d - d*sqrt(-S(4)*a*c + b**S(2))))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)/(x**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, (S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/((b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/2)*sqrt(-S(4)*a*c + b**S(2))) - (S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/((b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/2)*sqrt(-S(4)*a*c + b**S(2))) - d*sqrt(d + e*x**S(2))/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(2))**(S(3)/2)/(x**S(4)*(a + b*x**S(2) + c*x**S(4))), x), x, -(d + e*x**S(2))**(S(3)/2)/(S(3)*a*x**S(3)) - sqrt(e)*(-a*e + b*d)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/a**S(2) + sqrt(e)*(-a*e + b*d - (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*a**S(2)) + sqrt(e)*(-a*e + b*d + (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*a**S(2)) + sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(-a*e + b*d - (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(S(2)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(-a*e + b*d + (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(S(2)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) + sqrt(d + e*x**S(2))*(-a*e + b*d)/(a**S(2)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*sqrt(-x**S(2) + S(1))/(a + b*x**S(2) + c*x**S(4)), x), x, -b*sqrt(-x**S(2) + S(1))/c**S(2) - (-x**S(2) + S(1))**(S(3)/2)/(S(3)*c) + sqrt(S(2))*(-a*c + b**S(2) + b*c + (-S(3)*a*b*c - S(2)*a*c**S(2) + b**S(3) + b**S(2)*c)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(-a*c + b**S(2) + b*c - (-S(3)*a*b*c - S(2)*a*c**S(2) + b**S(3) + b**S(2)*c)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*sqrt(-x**S(2) + S(1))/(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(-x**S(2) + S(1))/c - sqrt(S(2))*(b + c - (-S(2)*a*c + b**S(2) + b*c)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b + c + (-S(2)*a*c + b**S(2) + b*c)/sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(-x**S(2) + S(1))/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1))/(x*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(S(2))*sqrt(c)*(S(2)*a + b - sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*sqrt(c)*(S(2)*a + b + sqrt(-S(4)*a*c + b**S(2)))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))) - atanh(sqrt(-x**S(2) + S(1)))/a, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1))/(x**S(3)*(a + b*x**S(2) + c*x**S(4))), x), x, S(1)/(S(4)*a*(sqrt(-x**S(2) + S(1)) + S(1))) - S(1)/(S(4)*a*(-sqrt(-x**S(2) + S(1)) + S(1))) + sqrt(S(2))*sqrt(c)*(a*(b - S(2)*c - sqrt(-S(4)*a*c + b**S(2))) + b*(b - sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(a*(b - S(2)*c + sqrt(-S(4)*a*c + b**S(2))) + b*(b + sqrt(-S(4)*a*c + b**S(2))))*atanh(sqrt(S(2))*sqrt(c)*sqrt(-x**S(2) + S(1))/sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))) + (a + S(2)*b)*atanh(sqrt(-x**S(2) + S(1)))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*sqrt(-x**S(2) + S(1))/(a + b*x**S(2) + c*x**S(4)), x), x, x*sqrt(-x**S(2) + S(1))/(S(2)*c) + (S(2)*b + c)*asin(x)/(S(2)*c**S(2)) - (-a*c + b**S(2) + b*c + (-S(3)*a*b*c - S(2)*a*c**S(2) + b**S(3) + b**S(2)*c)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(c**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))) - (-a*c + b**S(2) + b*c - (-S(3)*a*b*c - S(2)*a*c**S(2) + b**S(3) + b**S(2)*c)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(c**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(-x**S(2) + S(1))/(a + b*x**S(2) + c*x**S(4)), x), x, -asin(x)/c + (b + c + (-S(2)*a*c + b**S(2) + b*c)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(c*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))) + (b + c - (-S(2)*a*c + b**S(2) + b*c)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(c*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1))/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(-x**S(2) + S(1))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, -c*(-(S(2)*a + b)/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(x*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(b + S(2)*c + sqrt(-S(4)*a*c + b**S(2)))) - c*((S(2)*a + b)/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(x*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-x**S(2) + S(1))))/(a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(b + S(2)*c - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(-x**S(2) + S(1))/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(-x**S(2) + S(1))/(x**S(4) + x**S(2) + S(-1)), x), x, -asin(x) + sqrt(S(2)/5 + sqrt(S(5))/S(5))*atan(x*sqrt(S(1)/2 + sqrt(S(5))/S(2))/sqrt(-x**S(2) + S(1))) - sqrt(S(-2)/5 + sqrt(S(5))/S(5))*atanh(x*sqrt(S(-1)/2 + sqrt(S(5))/S(2))/sqrt(-x**S(2) + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, b*d*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c**S(2)*e**(S(3)/2)) - b*x*sqrt(d + e*x**S(2))/(S(2)*c**S(2)*e) + S(3)*d**S(2)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(8)*c*e**(S(5)/2)) - S(3)*d*x*sqrt(d + e*x**S(2))/(S(8)*c*e**S(2)) + x**S(3)*sqrt(d + e*x**S(2))/(S(4)*c*e) - (-S(2)*a*b*c + b**S(3) + (S(2)*a**S(2)*c**S(2) - S(4)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c**S(3)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - (-S(2)*a*b*c + b**S(3) - (S(2)*a**S(2)*c**S(2) - S(4)*a*b**S(2)*c + b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c**S(3)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) + (-a*c + b**S(2))*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(c**S(3)*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -b*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(c**S(2)*sqrt(e)) - d*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(S(2)*c*e**(S(3)/2)) + x*sqrt(d + e*x**S(2))/(S(2)*c*e) + (-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + (-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(c*sqrt(e)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) + sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)*c*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + S(2)*c*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -c*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - c*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - sqrt(d + e*x**S(2))/(a*d*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(d + e*x**S(2))/(S(3)*a*d*x**S(3)) + S(2)*e*sqrt(d + e*x**S(2))/(S(3)*a*d**S(2)*x) + b*sqrt(d + e*x**S(2))/(a**S(2)*d*x) + c*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + c*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(6)*sqrt(d + e*x**S(2))*(a + b*x**S(2) + c*x**S(4))), x), x, -sqrt(d + e*x**S(2))/(S(5)*a*d*x**S(5)) + S(4)*e*sqrt(d + e*x**S(2))/(S(15)*a*d**S(2)*x**S(3)) - S(8)*e**S(2)*sqrt(d + e*x**S(2))/(S(15)*a*d**S(3)*x) + b*sqrt(d + e*x**S(2))/(S(3)*a**S(2)*d*x**S(3)) - S(2)*b*e*sqrt(d + e*x**S(2))/(S(3)*a**S(2)*d**S(2)*x) - c*(-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(3)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - c*(-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(3)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - sqrt(d + e*x**S(2))*(-a*c + b**S(2))/(a**S(3)*d*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/((d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -d**S(2)*x/(e*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + (-S(2)*a*c + S(2)*b**S(2) + S(2)*b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)) + (-S(2)*a*c + S(2)*b**S(2) - S(2)*b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)) + atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(c*e**(S(3)/2)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(6)/((d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -d**S(2)*x/(e*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + d**S(2)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(e**(S(3)/2)*(a*e**S(2) - b*d*e + c*d**S(2))) + (-a*b*e - a*c*d + b**S(2)*d + (S(2)*a**S(2)*c*e - a*b**S(2)*e - S(3)*a*b*c*d + b**S(3)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) + (-a*b*e - a*c*d + b**S(2)*d - (S(2)*a**S(2)*c*e - a*b**S(2)*e - S(3)*a*b*c*d + b**S(3)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(c*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) - (-a*e + b*d)*atanh(sqrt(e)*x/sqrt(d + e*x**S(2)))/(c*sqrt(e)*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/((d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, d*x/(sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - (-a*e + b*d + (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) - (-a*e + b*d - (-a*b*e - S(2)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/((d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, c*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) + c*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) - e*x/(sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/((d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -c*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) - c*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) + e**S(2)*x/(d*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(2)*c**S(2)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)) - S(2)*c**S(2)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)) + e*x*(-b*e + c*d)/(a*d*sqrt(d + e*x**S(2))*(c*d**S(2) + e*(a*e - b*d))) + (-d - S(2)*e*x**S(2))/(a*d**S(2)*x*sqrt(d + e*x**S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/(x**S(2)*(d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -e**S(2)/(d*x*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - S(2)*e**S(3)*x/(d**S(2)*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - c*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) - c*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(d + e*x**S(2))*(-b*e + c*d)/(a*d*x*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(4)*(d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -S(1)/(S(3)*a*d*x**S(3)*sqrt(d + e*x**S(2))) + S(2)*c**S(2)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)) + S(2)*c**S(2)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))**(S(3)/2)) - e*x*(a*c*e - b**S(2)*e + b*c*d)/(a**S(2)*d*sqrt(d + e*x**S(2))*(c*d**S(2) + e*(a*e - b*d))) + (S(4)*a*e + S(3)*b*d)/(S(3)*a**S(2)*d**S(2)*x*sqrt(d + e*x**S(2))) + S(2)*e*x*(S(4)*a*e + S(3)*b*d)/(S(3)*a**S(2)*d**S(3)*sqrt(d + e*x**S(2))), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(S(1)/(x**S(4)*(d + e*x**S(2))**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))), x), x, -e**S(2)/(S(3)*d*x**S(3)*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + S(4)*e**S(3)/(S(3)*d**S(2)*x*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) + S(8)*e**S(4)*x/(S(3)*d**S(3)*sqrt(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))) - sqrt(d + e*x**S(2))*(-b*e + c*d)/(S(3)*a*d*x**S(3)*(a*e**S(2) - b*d*e + c*d**S(2))) + S(2)*e*sqrt(d + e*x**S(2))*(-b*e + c*d)/(S(3)*a*d**S(2)*x*(a*e**S(2) - b*d*e + c*d**S(2))) + c*(a*c*e - b**S(2)*e + b*c*d - (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) + c*(a*c*e - b**S(2)*e + b*c*d + (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(x*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(d + e*x**S(2))))/(a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))*(a*e**S(2) - b*d*e + c*d**S(2))) + sqrt(d + e*x**S(2))*(a*c*e - b**S(2)*e + b*c*d)/(a**S(2)*d*x*(a*e**S(2) - b*d*e + c*d**S(2))), expand=True, _diff=True, _numerical=True) # '''Apart # assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, -S(2)*c*(f*x)**(m + S(1))*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*AppellF1(m/S(2) + S(1)/2, S(1), -q, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(f*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*(f*x)**(m + S(1))*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*AppellF1(m/S(2) + S(1)/2, S(1), -q, m/S(2) + S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(f*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(x**S(7)*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, (d + e*x**S(2))**(q + S(1))*(a - b**S(2)/c - b*(-S(3)*a*c + b**S(2))/(c*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c*(q + S(1))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + (d + e*x**S(2))**(q + S(1))*(a - b**S(2)/c + b*(-S(3)*a*c + b**S(2))/(c*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c*(q + S(1))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) + (d + e*x**S(2))**(q + S(2))/(S(2)*c*e**S(2)*(q + S(2))) - (d + e*x**S(2))**(q + S(1))*(b*e + c*d)/(S(2)*c**S(2)*e**S(2)*(q + S(1))), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(x**S(5)*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, (b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c*(q + S(1))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) + (b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*c*(q + S(1))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + (d + e*x**S(2))**(q + S(1))/(S(2)*c*e*(q + S(1))), expand=True, _diff=True, _numerical=True) # assert rubi_test(rubi_integrate(x**S(3)*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, -(d + e*x**S(2))**(q + S(1))*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/((q + S(1))*(S(4)*c*d - S(2)*e*(b - sqrt(-S(4)*a*c + b**S(2))))) - (d + e*x**S(2))**(q + S(1))*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/((q + S(1))*(S(4)*c*d - S(2)*e*(b + sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate(x*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, c*(d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/((q + S(1))*sqrt(-S(4)*a*c + b**S(2))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - c*(d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/((q + S(1))*sqrt(-S(4)*a*c + b**S(2))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate((d + e*x**S(2))**q/(x*(a + b*x**S(2) + c*x**S(4))), x), x, c*(d + e*x**S(2))**(q + S(1))*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a*(q + S(1))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + c*(d + e*x**S(2))**(q + S(1))*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*(q + S(1))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - (d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(1) + e*x**S(2)/d)/(S(2)*a*d*(q + S(1))), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate((d + e*x**S(2))**q/(x**S(3)*(a + b*x**S(2) + c*x**S(4))), x), x, e*(d + e*x**S(2))**(q + S(1))*hyper((S(2), q + S(1)), (q + S(2),), S(1) + e*x**S(2)/d)/(S(2)*a*d**S(2)*(q + S(1))) + b*(d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(1) + e*x**S(2)/d)/(S(2)*a**S(2)*d*(q + S(1))) - c*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(S(2)*a**S(2)*(q + S(1))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) - c*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**S(2))/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*(q + S(1))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate(x**S(6)*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, -b*x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*hyper((S(1)/2, -q), (S(3)/2,), -e*x**S(2)/d)/c**S(2) + x**S(3)*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*hyper((S(3)/2, -q), (S(5)/2,), -e*x**S(2)/d)/(S(3)*c) + x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*(-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(c**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))) + x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*(-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(c**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate(x**S(4)*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, -x*(S(1) + e*x**S(2)/d)**(-q)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(c*(b - sqrt(-S(4)*a*c + b**S(2)))) - x*(S(1) + e*x**S(2)/d)**(-q)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(c*(b + sqrt(-S(4)*a*c + b**S(2)))) + x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*hyper((S(1)/2, -q), (S(3)/2,), -e*x**S(2)/d)/c, expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, -x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/sqrt(-S(4)*a*c + b**S(2)) + x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate((d + e*x**S(2))**q/(a + b*x**S(2) + c*x**S(4)), x), x, -S(2)*c*x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate((d + e*x**S(2))**q/(x**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, -c*x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(a*(b + sqrt(-S(4)*a*c + b**S(2)))) - c*x*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(a*(b - sqrt(-S(4)*a*c + b**S(2)))) - (S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*hyper((S(-1)/2, -q), (S(1)/2,), -e*x**S(2)/d)/(a*x), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate((d + e*x**S(2))**q/(x**S(4)*(a + b*x**S(2) + c*x**S(4))), x), x, -(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*hyper((S(-3)/2, -q), (S(-1)/2,), -e*x**S(2)/d)/(S(3)*a*x**S(3)) + b*(S(1) + e*x**S(2)/d)**(-q)*(d + e*x**S(2))**q*hyper((S(-1)/2, -q), (S(1)/2,), -e*x**S(2)/d)/(a**S(2)*x) + c*x*(S(1) + e*x**S(2)/d)**(-q)*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(a**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))) + c*x*(S(1) + e*x**S(2)/d)**(-q)*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*(d + e*x**S(2))**q*AppellF1(S(1)/2, S(1), -q, S(3)/2, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**S(2)/d)/(a**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate((d + e*x**S(3))/(a + c*x**S(6)), x), x, -(sqrt(c)*d - e*sqrt(-a))*log(c**(S(1)/6)*x + (-a)**(S(1)/6))/(S(6)*c**(S(2)/3)*(-a)**(S(5)/6)) + (sqrt(c)*d - e*sqrt(-a))*log(-c**(S(1)/6)*x*(-a)**(S(1)/6) + c**(S(1)/3)*x**S(2) + (-a)**(S(1)/3))/(S(12)*c**(S(2)/3)*(-a)**(S(5)/6)) + sqrt(S(3))*(sqrt(c)*d - e*sqrt(-a))*atan(sqrt(S(3))*(-S(2)*c**(S(1)/6)*x/(-a)**(S(1)/6) + S(1))/S(3))/(S(6)*c**(S(2)/3)*(-a)**(S(5)/6)) + (sqrt(c)*d + e*sqrt(-a))*log(-c**(S(1)/6)*x + (-a)**(S(1)/6))/(S(6)*c**(S(2)/3)*(-a)**(S(5)/6)) - (sqrt(c)*d + e*sqrt(-a))*log(c**(S(1)/6)*x*(-a)**(S(1)/6) + c**(S(1)/3)*x**S(2) + (-a)**(S(1)/3))/(S(12)*c**(S(2)/3)*(-a)**(S(5)/6)) - sqrt(S(3))*(sqrt(c)*d + e*sqrt(-a))*atan(sqrt(S(3))*(S(2)*c**(S(1)/6)*x/(-a)**(S(1)/6) + S(1))/S(3))/(S(6)*c**(S(2)/3)*(-a)**(S(5)/6)), expand=True, _diff=True, _numerical=True) # NC assert rubi_test(rubi_integrate((d + e*x**S(3))/(a - c*x**S(6)), x), x, (-sqrt(a)*e + sqrt(c)*d)*log(a**(S(1)/6) + c**(S(1)/6)*x)/(S(6)*a**(S(5)/6)*c**(S(2)/3)) - (-sqrt(a)*e + sqrt(c)*d)*log(-a**(S(1)/6)*c**(S(1)/6)*x + a**(S(1)/3) + c**(S(1)/3)*x**S(2))/(S(12)*a**(S(5)/6)*c**(S(2)/3)) - sqrt(S(3))*(-sqrt(a)*e + sqrt(c)*d)*atan(sqrt(S(3))*(a**(S(1)/6) - S(2)*c**(S(1)/6)*x)/(S(3)*a**(S(1)/6)))/(S(6)*a**(S(5)/6)*c**(S(2)/3)) - (sqrt(a)*e + sqrt(c)*d)*log(a**(S(1)/6) - c**(S(1)/6)*x)/(S(6)*a**(S(5)/6)*c**(S(2)/3)) + (sqrt(a)*e + sqrt(c)*d)*log(a**(S(1)/6)*c**(S(1)/6)*x + a**(S(1)/3) + c**(S(1)/3)*x**S(2))/(S(12)*a**(S(5)/6)*c**(S(2)/3)) + sqrt(S(3))*(sqrt(a)*e + sqrt(c)*d)*atan(sqrt(S(3))*(a**(S(1)/6) + S(2)*c**(S(1)/6)*x)/(S(3)*a**(S(1)/6)))/(S(6)*a**(S(5)/6)*c**(S(2)/3)), expand=True, _diff=True, _numerical=True) # nc assert rubi_test(rubi_integrate((d + e*x**S(3))**S(5)*(a + b*x**S(3) + c*x**S(6)), x), x, a*d**S(5)*x + c*e**S(5)*x**S(22)/S(22) + d**S(4)*x**S(4)*(S(5)*a*e + b*d)/S(4) + d**S(3)*x**S(7)*(c*d**S(2) + S(5)*e*(S(2)*a*e + b*d))/S(7) + d**S(2)*e*x**S(10)*(c*d**S(2) + S(2)*e*(a*e + b*d))/S(2) + S(5)*d*e**S(2)*x**S(13)*(S(2)*c*d**S(2) + e*(a*e + S(2)*b*d))/S(13) + e**S(4)*x**S(19)*(b*e + S(5)*c*d)/S(19) + e**S(3)*x**S(16)*(S(10)*c*d**S(2) + e*(a*e + S(5)*b*d))/S(16), expand=True, _diff=True, _numerical=True) # nc assert rubi_test(rubi_integrate((d + e*x**S(3))**S(4)*(a + b*x**S(3) + c*x**S(6)), x), x, a*d**S(4)*x + c*e**S(4)*x**S(19)/S(19) + d**S(3)*x**S(4)*(S(4)*a*e + b*d)/S(4) + d**S(2)*x**S(7)*(S(6)*a*e**S(2) + S(4)*b*d*e + c*d**S(2))/S(7) + d*e*x**S(10)*(S(2)*c*d**S(2) + e*(S(2)*a*e + S(3)*b*d))/S(5) + e**S(3)*x**S(16)*(b*e + S(4)*c*d)/S(16) + e**S(2)*x**S(13)*(S(6)*c*d**S(2) + e*(a*e + S(4)*b*d))/S(13), expand=True, _diff=True, _numerical=True) # nc assert rubi_test(rubi_integrate((d + e*x**S(3))**S(3)*(a + b*x**S(3) + c*x**S(6)), x), x, a*d**S(3)*x + c*e**S(3)*x**S(16)/S(16) + d**S(2)*x**S(4)*(S(3)*a*e + b*d)/S(4) + d*x**S(7)*(c*d**S(2) + S(3)*e*(a*e + b*d))/S(7) + e**S(2)*x**S(13)*(b*e + S(3)*c*d)/S(13) + e*x**S(10)*(S(3)*c*d**S(2) + e*(a*e + S(3)*b*d))/S(10), expand=True, _diff=True, _numerical=True) # ncassert rubi_test(rubi_integrate((d + e*x**S(3))**S(2)*(a + b*x**S(3) + c*x**S(6)), x), x, a*d**S(2)*x + c*e**S(2)*x**S(13)/S(13) + d*x**S(4)*(S(2)*a*e + b*d)/S(4) + e*x**S(10)*(b*e + S(2)*c*d)/S(10) + x**S(7)*(c*d**S(2) + e*(a*e + S(2)*b*d))/S(7), expand=True, _diff=True, _numerical=True) # nc assert rubi_test(rubi_integrate((d + e*x**S(3))*(a + b*x**S(3) + c*x**S(6)), x), x, a*d*x + c*e*x**S(10)/S(10) + x**S(7)*(b*e + c*d)/S(7) + x**S(4)*(a*e + b*d)/S(4), expand=True, _diff=True, _numerical=True) # nc assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/(d + e*x**S(3)), x), x, c*x**S(4)/(S(4)*e) - x*(-b*e + c*d)/e**S(2) + (a*e**S(2) - b*d*e + c*d**S(2))*log(d**(S(1)/3) + e**(S(1)/3)*x)/(S(3)*d**(S(2)/3)*e**(S(7)/3)) - (a*e**S(2) - b*d*e + c*d**S(2))*log(d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(S(6)*d**(S(2)/3)*e**(S(7)/3)) - sqrt(S(3))*(a*e**S(2) - b*d*e + c*d**S(2))*atan(sqrt(S(3))*(d**(S(1)/3) - S(2)*e**(S(1)/3)*x)/(S(3)*d**(S(1)/3)))/(S(3)*d**(S(2)/3)*e**(S(7)/3)), expand=True, _diff=True, _numerical=True) # nc assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/(d + e*x**S(3))**S(2), x), x, c*x/e**S(2) + x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(3)*d*e**S(2)*(d + e*x**S(3))) - (S(4)*c*d**S(2) - e*(S(2)*a*e + b*d))*log(d**(S(1)/3) + e**(S(1)/3)*x)/(S(9)*d**(S(5)/3)*e**(S(7)/3)) + (S(4)*c*d**S(2) - e*(S(2)*a*e + b*d))*log(d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(S(18)*d**(S(5)/3)*e**(S(7)/3)) + sqrt(S(3))*(S(4)*c*d**S(2) - e*(S(2)*a*e + b*d))*atan(sqrt(S(3))*(d**(S(1)/3) - S(2)*e**(S(1)/3)*x)/(S(3)*d**(S(1)/3)))/(S(9)*d**(S(5)/3)*e**(S(7)/3)), expand=True, _diff=True, _numerical=True) # nc assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/(d + e*x**S(3))**S(3), x), x, x*(a*e**S(2) - b*d*e + c*d**S(2))/(S(6)*d*e**S(2)*(d + e*x**S(3))**S(2)) - x*(S(7)*c*d**S(2) - e*(S(5)*a*e + b*d))/(S(18)*d**S(2)*e**S(2)*(d + e*x**S(3))) + (S(2)*c*d**S(2) + e*(S(5)*a*e + b*d))*log(d**(S(1)/3) + e**(S(1)/3)*x)/(S(27)*d**(S(8)/3)*e**(S(7)/3)) - (S(2)*c*d**S(2) + e*(S(5)*a*e + b*d))*log(d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(S(54)*d**(S(8)/3)*e**(S(7)/3)) - sqrt(S(3))*(S(2)*c*d**S(2) + e*(S(5)*a*e + b*d))*atan(sqrt(S(3))*(d**(S(1)/3) - S(2)*e**(S(1)/3)*x)/(S(3)*d**(S(1)/3)))/(S(27)*d**(S(8)/3)*e**(S(7)/3)), expand=True, _diff=True, _numerical=True) # ''' assert rubi_test(rubi_integrate(x**S(8)*(d + e*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, e*x**S(6)/(S(6)*c) + x**S(3)*(-b*e + c*d)/(S(3)*c**S(2)) - (a*c*e - b**S(2)*e + b*c*d)*log(a + b*x**S(3) + c*x**S(6))/(S(6)*c**S(3)) - (S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d)*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*c**S(3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(d + e*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, e*x**S(3)/(S(3)*c) + (-b*e + c*d)*log(a + b*x**S(3) + c*x**S(6))/(S(6)*c**S(2)) + (S(2)*a*c*e - b**S(2)*e + b*c*d)*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, e*log(a + b*x**S(3) + c*x**S(6))/(S(6)*c) - (-b*e + S(2)*c*d)*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*c*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(3))/(x*(a + b*x**S(3) + c*x**S(6))), x), x, d*log(x)/a - d*log(a + b*x**S(3) + c*x**S(6))/(S(6)*a) + (-S(2)*a*e + b*d)*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*a*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(3))/(x**S(4)*(a + b*x**S(3) + c*x**S(6))), x), x, -d/(S(3)*a*x**S(3)) - (-a*e + b*d)*log(x)/a**S(2) + (-a*e + b*d)*log(a + b*x**S(3) + c*x**S(6))/(S(6)*a**S(2)) - (-a*b*e - S(2)*a*c*d + b**S(2)*d)*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(d + e*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, e*x**S(2)/(S(2)*c) - S(2)**(S(1)/3)*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(5)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(5)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(5)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(5)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(5)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(5)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(d + e*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, e*x/c + S(2)**(S(2)/3)*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, -S(2)**(S(1)/3)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, S(2)**(S(2)/3)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(3))/(x**S(2)*(a + b*x**S(3) + c*x**S(6))), x), x, S(2)**(S(1)/3)*c**(S(1)/3)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*c**(S(1)/3)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*c**(S(1)/3)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*c**(S(1)/3)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*c**(S(1)/3)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*c**(S(1)/3)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - d/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(3))/(x**S(3)*(a + b*x**S(3) + c*x**S(6))), x), x, -S(2)**(S(2)/3)*c**(S(2)/3)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*c**(S(2)/3)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*c**(S(2)/3)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*c**(S(2)/3)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*c**(S(2)/3)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*a*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - d/(S(2)*a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)*(-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -x**S(6)/S(6) + log(x**S(6) - x**S(3) + S(1))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -x**S(3)/S(3) - S(2)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -log(x**S(6) - x**S(3) + S(1))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + S(1))/(x*(x**S(6) - x**S(3) + S(1))), x), x, log(x) - log(x**S(6) - x**S(3) + S(1))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + S(1))/(x**S(4)*(x**S(6) - x**S(3) + S(1))), x), x, S(2)*sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(9) - S(1)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)*(-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -x**S(4)/S(4) + S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -x**S(2)/S(2) + sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3)) - sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3)) - I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -x + sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(2)/3)) - sqrt(S(3))*I*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(9)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*I*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 - sqrt(S(3))*I/S(2))**(S(2)/3)) + I*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(3)*(S(1)/2 + sqrt(S(3))*I/S(2))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + S(1))/(x**S(6) - x**S(3) + S(1)), x), x, -S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + S(1))/(x**S(2)*(x**S(6) - x**S(3) + S(1))), x), x, -S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) - S(2)**(S(1)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(1)/3)) + S(2)**(S(1)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(1)/3)) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(3) + S(1))/(x**S(3)*(x**S(6) - x**S(3) + S(1))), x), x, -S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) - sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(-S(2)**(S(1)/3)*x + (S(1) + sqrt(S(3))*I)**(S(1)/3))/(S(18)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) + sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) - S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) - sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(S(3) - sqrt(S(3))*I)*log(S(2)**(S(2)/3)*x**S(2) + x*(S(2) + S(2)*sqrt(S(3))*I)**(S(1)/3) + (S(1) + sqrt(S(3))*I)**(S(2)/3))/(S(36)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) + S(2)**(S(2)/3)*(sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 - sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) - sqrt(S(3))*I)**(S(2)/3)) - S(2)**(S(2)/3)*(-sqrt(S(3)) + I)*atan(sqrt(S(3))*(S(2)*x/(S(1)/2 + sqrt(S(3))*I/S(2))**(S(1)/3) + S(1))/S(3))/(S(6)*(S(1) + sqrt(S(3))*I)**(S(2)/3)) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(x**S(3) + S(-2))/(x**S(6) - x**S(3) + S(1)), x), x, log(x**S(6) - x**S(3) + S(1))/S(6) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(1))/(x*(x**S(6) - x**S(3) + S(1))), x), x, log(x) - log(x**S(6) - x**S(3) + S(1))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) + S(1))/(x**S(7) - x**S(4) + x), x), x, log(x) - log(x**S(6) - x**S(3) + S(1))/S(6) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(3) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(3))**(S(5)/2)*(a + b*x**S(3) + c*x**S(6)), x), x, S(2)*c*x**S(4)*(d + e*x**S(3))**(S(7)/2)/(S(29)*e) + S(54)*S(3)**(S(3)/4)*d**S(3)*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(667)*a*e**S(2) - S(58)*b*d*e + S(16)*c*d**S(2))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(124729)*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))) + S(54)*d**S(2)*x*sqrt(d + e*x**S(3))*(S(667)*a*e**S(2) - S(58)*b*d*e + S(16)*c*d**S(2))/(S(124729)*e**S(2)) + S(30)*d*x*(d + e*x**S(3))**(S(3)/2)*(S(667)*a*e**S(2) - S(58)*b*d*e + S(16)*c*d**S(2))/(S(124729)*e**S(2)) - x*(d + e*x**S(3))**(S(7)/2)*(-S(58)*b*e + S(16)*c*d)/(S(667)*e**S(2)) + x*(d + e*x**S(3))**(S(5)/2)*(S(1334)*a*e**S(2) - S(116)*b*d*e + S(32)*c*d**S(2))/(S(11339)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(3))**(S(3)/2)*(a + b*x**S(3) + c*x**S(6)), x), x, S(2)*c*x**S(4)*(d + e*x**S(3))**(S(5)/2)/(S(23)*e) + S(18)*S(3)**(S(3)/4)*d**S(2)*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(391)*a*e**S(2) - S(46)*b*d*e + S(16)*c*d**S(2))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(21505)*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))) + S(18)*d*x*sqrt(d + e*x**S(3))*(S(391)*a*e**S(2) - S(46)*b*d*e + S(16)*c*d**S(2))/(S(21505)*e**S(2)) - x*(d + e*x**S(3))**(S(5)/2)*(-S(46)*b*e + S(16)*c*d)/(S(391)*e**S(2)) + x*(d + e*x**S(3))**(S(3)/2)*(S(782)*a*e**S(2) - S(92)*b*d*e + S(32)*c*d**S(2))/(S(4301)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(d + e*x**S(3))*(a + b*x**S(3) + c*x**S(6)), x), x, S(2)*c*x**S(4)*(d + e*x**S(3))**(S(3)/2)/(S(17)*e) + S(2)*S(3)**(S(3)/4)*d*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(187)*a*e**S(2) - S(34)*b*d*e + S(16)*c*d**S(2))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(935)*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))) - x*(d + e*x**S(3))**(S(3)/2)*(-S(34)*b*e + S(16)*c*d)/(S(187)*e**S(2)) + x*sqrt(d + e*x**S(3))*(S(374)*a*e**S(2) - S(68)*b*d*e + S(32)*c*d**S(2))/(S(935)*e**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/sqrt(d + e*x**S(3)), x), x, S(2)*c*x**S(4)*sqrt(d + e*x**S(3))/(S(11)*e) - x*sqrt(d + e*x**S(3))*(-S(22)*b*e + S(16)*c*d)/(S(55)*e**S(2)) + S(2)*S(3)**(S(3)/4)*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(55)*a*e**S(2) - S(22)*b*d*e + S(16)*c*d**S(2))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(165)*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/(d + e*x**S(3))**(S(3)/2), x), x, S(2)*c*x*sqrt(d + e*x**S(3))/(S(5)*e**S(2)) + x*(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2))/(S(3)*d*e**S(2)*sqrt(d + e*x**S(3))) - S(2)*S(3)**(S(3)/4)*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(16)*c*d**S(2) - S(5)*e*(a*e + S(2)*b*d))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(45)*d*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/(d + e*x**S(3))**(S(5)/2), x), x, x*(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2))/(S(9)*d*e**S(2)*(d + e*x**S(3))**(S(3)/2)) - x*(-S(14)*a*e**S(2) - S(4)*b*d*e + S(22)*c*d**S(2))/(S(27)*d**S(2)*e**S(2)*sqrt(d + e*x**S(3))) + S(2)*S(3)**(S(3)/4)*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(16)*c*d**S(2) + e*(S(7)*a*e + S(2)*b*d))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(81)*d**S(2)*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/(d + e*x**S(3))**(S(7)/2), x), x, x*(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2))/(S(15)*d*e**S(2)*(d + e*x**S(3))**(S(5)/2)) - x*(-S(26)*a*e**S(2) - S(4)*b*d*e + S(34)*c*d**S(2))/(S(135)*d**S(2)*e**S(2)*(d + e*x**S(3))**(S(3)/2)) + x*(S(182)*a*e**S(2) + S(28)*b*d*e + S(32)*c*d**S(2))/(S(405)*d**S(3)*e**S(2)*sqrt(d + e*x**S(3))) + S(2)*S(3)**(S(3)/4)*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(91)*a*e**S(2) + S(14)*b*d*e + S(16)*c*d**S(2))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(1215)*d**S(3)*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(3) + c*x**S(6))/(d + e*x**S(3))**(S(9)/2), x), x, x*(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2))/(S(21)*d*e**S(2)*(d + e*x**S(3))**(S(7)/2)) - x*(-S(38)*a*e**S(2) - S(4)*b*d*e + S(46)*c*d**S(2))/(S(315)*d**S(2)*e**S(2)*(d + e*x**S(3))**(S(5)/2)) + x*(S(494)*a*e**S(2) + S(52)*b*d*e + S(32)*c*d**S(2))/(S(2835)*d**S(3)*e**S(2)*(d + e*x**S(3))**(S(3)/2)) + x*(S(494)*a*e**S(2) + S(52)*b*d*e + S(32)*c*d**S(2))/(S(1215)*d**S(4)*e**S(2)*sqrt(d + e*x**S(3))) + S(2)*S(3)**(S(3)/4)*sqrt((d**(S(2)/3) - d**(S(1)/3)*e**(S(1)/3)*x + e**(S(2)/3)*x**S(2))/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(sqrt(S(3)) + S(2))*(d**(S(1)/3) + e**(S(1)/3)*x)*(S(247)*a*e**S(2) + S(26)*b*d*e + S(16)*c*d**S(2))*elliptic_f(asin((d**(S(1)/3)*(-sqrt(S(3)) + S(1)) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)), S(-7) - S(4)*sqrt(S(3)))/(S(3645)*d**S(4)*e**(S(7)/3)*sqrt(d**(S(1)/3)*(d**(S(1)/3) + e**(S(1)/3)*x)/(d**(S(1)/3)*(S(1) + sqrt(S(3))) + e**(S(1)/3)*x)**S(2))*sqrt(d + e*x**S(3))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(4))/(a + c*x**S(8)), x), x, sqrt(S(2))*(sqrt(c)*d - e*sqrt(-a))*log(-sqrt(S(2))*c**(S(1)/8)*x*(-a)**(S(1)/8) + c**(S(1)/4)*x**S(2) + (-a)**(S(1)/4))/(S(16)*c**(S(5)/8)*(-a)**(S(7)/8)) - sqrt(S(2))*(sqrt(c)*d - e*sqrt(-a))*log(sqrt(S(2))*c**(S(1)/8)*x*(-a)**(S(1)/8) + c**(S(1)/4)*x**S(2) + (-a)**(S(1)/4))/(S(16)*c**(S(5)/8)*(-a)**(S(7)/8)) - sqrt(S(2))*(sqrt(c)*d - e*sqrt(-a))*atan(sqrt(S(2))*c**(S(1)/8)*x/(-a)**(S(1)/8) + S(-1))/(S(8)*c**(S(5)/8)*(-a)**(S(7)/8)) - sqrt(S(2))*(sqrt(c)*d - e*sqrt(-a))*atan(sqrt(S(2))*c**(S(1)/8)*x/(-a)**(S(1)/8) + S(1))/(S(8)*c**(S(5)/8)*(-a)**(S(7)/8)) - (sqrt(c)*d + e*sqrt(-a))*atan(c**(S(1)/8)*x/(-a)**(S(1)/8))/(S(4)*c**(S(5)/8)*(-a)**(S(7)/8)) - (sqrt(c)*d + e*sqrt(-a))*atanh(c**(S(1)/8)*x/(-a)**(S(1)/8))/(S(4)*c**(S(5)/8)*(-a)**(S(7)/8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(4))/(a - c*x**S(8)), x), x, -sqrt(S(2))*(-sqrt(a)*e + sqrt(c)*d)*log(-sqrt(S(2))*a**(S(1)/8)*c**(S(1)/8)*x + a**(S(1)/4) + c**(S(1)/4)*x**S(2))/(S(16)*a**(S(7)/8)*c**(S(5)/8)) + sqrt(S(2))*(-sqrt(a)*e + sqrt(c)*d)*log(sqrt(S(2))*a**(S(1)/8)*c**(S(1)/8)*x + a**(S(1)/4) + c**(S(1)/4)*x**S(2))/(S(16)*a**(S(7)/8)*c**(S(5)/8)) - sqrt(S(2))*(-sqrt(a)*e + sqrt(c)*d)*atan(S(1) - sqrt(S(2))*c**(S(1)/8)*x/a**(S(1)/8))/(S(8)*a**(S(7)/8)*c**(S(5)/8)) + sqrt(S(2))*(-sqrt(a)*e + sqrt(c)*d)*atan(S(1) + sqrt(S(2))*c**(S(1)/8)*x/a**(S(1)/8))/(S(8)*a**(S(7)/8)*c**(S(5)/8)) + (sqrt(a)*e + sqrt(c)*d)*atan(c**(S(1)/8)*x/a**(S(1)/8))/(S(4)*a**(S(7)/8)*c**(S(5)/8)) + (sqrt(a)*e + sqrt(c)*d)*atanh(c**(S(1)/8)*x/a**(S(1)/8))/(S(4)*a**(S(7)/8)*c**(S(5)/8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(d + e*x**S(4))/(a + b*x**S(4) + c*x**S(8)), x), x, e*x/c - S(2)**(S(3)/4)*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(-b*e + c*d - (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(-b*e + c*d + (S(2)*a*c*e - b**S(2)*e + b*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(d + e*x**S(4))/(a + b*x**S(4) + c*x**S(8)), x), x, e*log(a + b*x**S(4) + c*x**S(8))/(S(8)*c) - (-b*e + S(2)*c*d)*atanh((b + S(2)*c*x**S(4))/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*c*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**S(4))/(a + b*x**S(4) + c*x**S(8)), x), x, S(2)**(S(1)/4)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(3)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(4))/(a + b*x**S(4) + c*x**S(8)), x), x, sqrt(S(2))*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(4))/(a + b*x**S(4) + c*x**S(8)), x), x, -S(2)**(S(3)/4)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - S(2)**(S(3)/4)*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(1)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(4))/(x*(a + b*x**S(4) + c*x**S(8))), x), x, d*log(x)/a - d*log(a + b*x**S(4) + c*x**S(8))/(S(8)*a) + (-S(2)*a*e + b*d)*atanh((b + S(2)*c*x**S(4))/sqrt(-S(4)*a*c + b**S(2)))/(S(4)*a*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(4))/(x**S(2)*(a + b*x**S(4) + c*x**S(8))), x), x, -S(2)**(S(1)/4)*c**(S(1)/4)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*c**(S(1)/4)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - S(2)**(S(1)/4)*c**(S(1)/4)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) + S(2)**(S(1)/4)*c**(S(1)/4)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4)) - d/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(4))/(x**S(3)*(a + b*x**S(4) + c*x**S(8))), x), x, -sqrt(S(2))*sqrt(c)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x**S(2)/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - d/(S(2)*a*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**S(4))/(x**S(4)*(a + b*x**S(4) + c*x**S(8))), x), x, S(2)**(S(3)/4)*c**(S(3)/4)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(d + (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*c**(S(3)/4)*(d - (-S(2)*a*e + b*d)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*a*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) - d/(S(3)*a*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(-x**S(4) + S(1))/(x**S(8) - x**S(4) + S(1)), x), x, -x - sqrt(S(6))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) - sqrt(S(6))*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(-x**S(4) + S(1))/(x**S(8) - x**S(4) + S(1)), x), x, -log(x**S(8) - x**S(4) + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(-x**S(4) + S(1))/(x**S(8) - x**S(4) + S(1)), x), x, sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) - atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) + atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) + atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))) - atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(-x**S(4) + S(1))/(x**S(8) - x**S(4) + S(1)), x), x, -sqrt(S(3))*log(x**S(4) - sqrt(S(3))*x**S(2) + S(1))/S(12) + sqrt(S(3))*log(x**S(4) + sqrt(S(3))*x**S(2) + S(1))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(1))/(x**S(8) - x**S(4) + S(1)), x), x, sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) - atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/(S(4)*sqrt(S(3)*sqrt(S(3)) + S(6))) - atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))) + atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/(S(4)*sqrt(-S(3)*sqrt(S(3)) + S(6))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(1))/(x*(x**S(8) - x**S(4) + S(1))), x), x, log(x) - log(x**S(8) - x**S(4) + S(1))/S(8) + sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x**S(4) + S(1))/S(3))/S(12), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(1))/(x**S(2)*(x**S(8) - x**S(4) + S(1))), x), x, -sqrt(S(6))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(24) - sqrt(S(6))*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(24) + sqrt(S(6))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) - sqrt(S(6))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(12) + sqrt(S(6))*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12) - sqrt(S(6))*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(12) - S(1)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(1))/(x**S(3)*(x**S(8) - x**S(4) + S(1))), x), x, -sqrt(S(3))*log(x**S(4) - sqrt(S(3))*x**S(2) + S(1))/S(24) + sqrt(S(3))*log(x**S(4) + sqrt(S(3))*x**S(2) + S(1))/S(24) - atan(S(2)*x**S(2) - sqrt(S(3)))/S(4) - atan(S(2)*x**S(2) + sqrt(S(3)))/S(4) - S(1)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(1))/(x**S(4)*(x**S(8) - x**S(4) + S(1))), x), x, sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(8) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(-sqrt(S(3))/S(3) + S(2)/3)*log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/S(8) + sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) - sqrt(sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) - sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) + sqrt(-sqrt(S(3))/S(3) + S(2)/3)*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) - S(1)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(1))/(x**S(8) + x**S(4) + S(1)), x), x, -log(x**S(2) - x + S(1))/S(8) + log(x**S(2) + x + S(1))/S(8) - sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(24) + sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(24) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(12) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(12) + atan(S(2)*x - sqrt(S(3)))/S(4) + atan(S(2)*x + sqrt(S(3)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(1))/(x**S(8) + x**S(4) + S(1)), x), x, log(x**S(2) - x + S(1))/S(8) - log(x**S(2) + x + S(1))/S(8) - sqrt(S(3))*log(x**S(2) - sqrt(S(3))*x + S(1))/S(8) + sqrt(S(3))*log(x**S(2) + sqrt(S(3))*x + S(1))/S(8) - sqrt(S(3))*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(4) + sqrt(S(3))*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(4) - atan(S(2)*x - sqrt(S(3)))/S(4) - atan(S(2)*x + sqrt(S(3)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4) + S(1))/(x**S(8) - x**S(4) + S(1)), x), x, -log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(-sqrt(S(3)) + S(2))) + log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(-sqrt(S(3)) + S(2))) - log(x**S(2) - x*sqrt(sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(sqrt(S(3)) + S(2))) + log(x**S(2) + x*sqrt(sqrt(S(3)) + S(2)) + S(1))/(S(8)*sqrt(sqrt(S(3)) + S(2))) - sqrt(sqrt(S(3)) + S(2))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) + sqrt(sqrt(S(3)) + S(2))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(4) - sqrt(-sqrt(S(3)) + S(2))*atan((-S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4) + sqrt(-sqrt(S(3)) + S(2))*atan((S(2)*x + sqrt(-sqrt(S(3)) + S(2)))/sqrt(sqrt(S(3)) + S(2)))/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-x**S(4) + S(1))/(x**S(8) - S(3)*x**S(4) + S(1)), x), x, sqrt(S(5))*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atan(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) + sqrt(S(5))*(-sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atan(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10) + sqrt(S(5))*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atanh(x*(sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4))/S(10) + sqrt(S(5))*(-sqrt(S(5))/S(2) + S(3)/2)**(S(1)/4)*atanh(S(2)**(S(1)/4)*x/(sqrt(S(5)) + S(3))**(S(1)/4))/S(10), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((S(2)*x**S(4) + S(-1) + sqrt(S(3)))/(x**S(8) - x**S(4) + S(1)), x), x, -sqrt(S(2))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(4) + sqrt(S(2))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(4) - sqrt(S(2))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(2) + sqrt(S(2))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4)*(S(1) + sqrt(S(3))) + S(1))/(x**S(8) - x**S(4) + S(1)), x), x, -sqrt(sqrt(S(3)) + S(2))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(4) + sqrt(sqrt(S(3)) + S(2))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(4) - sqrt(sqrt(S(3)) + S(2))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(2) + sqrt(sqrt(S(3)) + S(2))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(4)*(S(-3) + sqrt(S(3))) - S(2)*sqrt(S(3)) + S(3))/(x**S(8) - x**S(4) + S(1)), x), x, sqrt(-S(3)*sqrt(S(3)) + S(6))*log(x**S(2) - x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(4) - sqrt(-S(3)*sqrt(S(3)) + S(6))*log(x**S(2) + x*sqrt(-sqrt(S(3)) + S(2)) + S(1))/S(4) + sqrt(-S(3)*sqrt(S(3)) + S(6))*atan((-S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(2) - sqrt(-S(3)*sqrt(S(3)) + S(6))*atan((S(2)*x + sqrt(sqrt(S(3)) + S(2)))/sqrt(-sqrt(S(3)) + S(2)))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x)/(a/x**S(2) + c), x), x, -sqrt(a)*d*atan(sqrt(c)*x/sqrt(a))/c**(S(3)/2) + d*x/c + e*log(a + c*x**S(2))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x)/(a/x**S(2) + b/x + c), x), x, d*x/c - (b*d - c*e)*log(a + b*x + c*x**S(2))/(S(2)*c**S(2)) - (-S(2)*a*c*d + b**S(2)*d - b*c*e)*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x**S(2))/(a/x**S(4) + c), x), x, d*x/c + sqrt(S(2))*(sqrt(a)*d - sqrt(c)*e)*atan(S(1) - sqrt(S(2))*c**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(1)/4)*c**(S(5)/4)) - sqrt(S(2))*(sqrt(a)*d - sqrt(c)*e)*atan(S(1) + sqrt(S(2))*c**(S(1)/4)*x/a**(S(1)/4))/(S(4)*a**(S(1)/4)*c**(S(5)/4)) + sqrt(S(2))*(sqrt(a)*d + sqrt(c)*e)*log(-sqrt(S(2))*a**(S(1)/4)*c**(S(1)/4)*x + sqrt(a) + sqrt(c)*x**S(2))/(S(8)*a**(S(1)/4)*c**(S(5)/4)) - sqrt(S(2))*(sqrt(a)*d + sqrt(c)*e)*log(sqrt(S(2))*a**(S(1)/4)*c**(S(1)/4)*x + sqrt(a) + sqrt(c)*x**S(2))/(S(8)*a**(S(1)/4)*c**(S(5)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x**S(2))/(a/x**S(4) + b/x**S(2) + c), x), x, d*x/c - sqrt(S(2))*(b*d - c*e + (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b*d - c*e - (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x**S(3))/(a/x**S(6) + c), x), x, d*x/c - (-sqrt(c)*e + d*sqrt(-a))*log(c**(S(1)/6)*x + (-a)**(S(1)/6))/(S(6)*c**(S(7)/6)*(-a)**(S(1)/3)) + (-sqrt(c)*e + d*sqrt(-a))*log(-c**(S(1)/6)*x*(-a)**(S(1)/6) + c**(S(1)/3)*x**S(2) + (-a)**(S(1)/3))/(S(12)*c**(S(7)/6)*(-a)**(S(1)/3)) + sqrt(S(3))*(-sqrt(c)*e + d*sqrt(-a))*atan(sqrt(S(3))*(-S(2)*c**(S(1)/6)*x/(-a)**(S(1)/6) + S(1))/S(3))/(S(6)*c**(S(7)/6)*(-a)**(S(1)/3)) + (sqrt(c)*e + d*sqrt(-a))*log(-c**(S(1)/6)*x + (-a)**(S(1)/6))/(S(6)*c**(S(7)/6)*(-a)**(S(1)/3)) - (sqrt(c)*e + d*sqrt(-a))*log(c**(S(1)/6)*x*(-a)**(S(1)/6) + c**(S(1)/3)*x**S(2) + (-a)**(S(1)/3))/(S(12)*c**(S(7)/6)*(-a)**(S(1)/3)) - sqrt(S(3))*(sqrt(c)*e + d*sqrt(-a))*atan(sqrt(S(3))*(S(2)*c**(S(1)/6)*x/(-a)**(S(1)/6) + S(1))/S(3))/(S(6)*c**(S(7)/6)*(-a)**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x**S(3))/(a/x**S(6) + b/x**S(3) + c), x), x, d*x/c - S(2)**(S(2)/3)*(b*d - c*e + (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(b*d - c*e + (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*(b*d - c*e + (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(b*d - c*e - (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(b*d - c*e - (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*sqrt(S(3))*(b*d - c*e - (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(4)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x**S(4))/(a/x**S(8) + c), x), x, d*x/c + sqrt(S(2))*(-sqrt(c)*e + d*sqrt(-a))*log(-sqrt(S(2))*c**(S(1)/8)*x*(-a)**(S(1)/8) + c**(S(1)/4)*x**S(2) + (-a)**(S(1)/4))/(S(16)*c**(S(9)/8)*(-a)**(S(3)/8)) - sqrt(S(2))*(-sqrt(c)*e + d*sqrt(-a))*log(sqrt(S(2))*c**(S(1)/8)*x*(-a)**(S(1)/8) + c**(S(1)/4)*x**S(2) + (-a)**(S(1)/4))/(S(16)*c**(S(9)/8)*(-a)**(S(3)/8)) - sqrt(S(2))*(-sqrt(c)*e + d*sqrt(-a))*atan(sqrt(S(2))*c**(S(1)/8)*x/(-a)**(S(1)/8) + S(-1))/(S(8)*c**(S(9)/8)*(-a)**(S(3)/8)) - sqrt(S(2))*(-sqrt(c)*e + d*sqrt(-a))*atan(sqrt(S(2))*c**(S(1)/8)*x/(-a)**(S(1)/8) + S(1))/(S(8)*c**(S(9)/8)*(-a)**(S(3)/8)) - (sqrt(c)*e + d*sqrt(-a))*atan(c**(S(1)/8)*x/(-a)**(S(1)/8))/(S(4)*c**(S(9)/8)*(-a)**(S(3)/8)) - (sqrt(c)*e + d*sqrt(-a))*atanh(c**(S(1)/8)*x/(-a)**(S(1)/8))/(S(4)*c**(S(9)/8)*(-a)**(S(3)/8)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e/x**S(4))/(a/x**S(8) + b/x**S(4) + c), x), x, d*x/c + S(2)**(S(3)/4)*(b*d - c*e - (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b*d - c*e - (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b + sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b*d - c*e + (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atan(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)) + S(2)**(S(3)/4)*(b*d - c*e + (-S(2)*a*c*d + b**S(2)*d - b*c*e)/sqrt(-S(4)*a*c + b**S(2)))*atanh(S(2)**(S(1)/4)*c**(S(1)/4)*x/(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/4))/(S(4)*c**(S(5)/4)*(-b - sqrt(-S(4)*a*c + b**S(2)))**(S(3)/4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**S(3), x), x, d**S(3)*(f*x)**(m + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + S(1))/(S(2)*n), -p), (S(1) + (m + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(f*(m + S(1))) + S(3)*d**S(2)*e*x**(n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + n + S(1))/(S(2)*n), -p), ((m + S(3)*n + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(m + n + S(1)) + S(3)*d*e**S(2)*x**(S(2)*n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + S(2)*n + S(1))/(S(2)*n), -p), ((m + S(4)*n + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(m + S(2)*n + S(1)) + e**S(3)*x**(S(3)*n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + S(3)*n + S(1))/(S(2)*n), -p), ((m + S(5)*n + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(m + S(3)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**S(2), x), x, d**S(2)*(f*x)**(m + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + S(1))/(S(2)*n), -p), (S(1) + (m + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(f*(m + S(1))) + S(2)*d*e*x**(n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + n + S(1))/(S(2)*n), -p), ((m + S(3)*n + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(m + n + S(1)) + e**S(2)*x**(S(2)*n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + S(2)*n + S(1))/(S(2)*n), -p), ((m + S(4)*n + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(m + S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(a + c*x**(S(2)*n))**p*(d + e*x**n), x), x, d*(f*x)**(m + S(1))*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + S(1))/(S(2)*n), -p), (S(1) + (m + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(f*(m + S(1))) + e*x**(n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*hyper(((m + n + S(1))/(S(2)*n), -p), ((m + S(3)*n + S(1))/(S(2)*n),), -c*x**(S(2)*n)/a)/(m + n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**S(13), x), x, (a + b*x + c*x**S(2))**S(14)/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(13), x), x, (a + b*x**S(2) + c*x**S(4))**S(14)/S(28), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))*(a + b*x**S(3) + c*x**S(6))**S(13), x), x, (a + b*x**S(3) + c*x**S(6))**S(14)/S(42), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**S(13), x), x, (a + b*x**n + c*x**(S(2)*n))**S(14)/(S(14)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(-a + b*x + c*x**S(2))**S(13), x), x, (-a + b*x + c*x**S(2))**S(14)/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))*(-a + b*x**S(2) + c*x**S(4))**S(13), x), x, (a - b*x**S(2) - c*x**S(4))**S(14)/S(28), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))*(-a + b*x**S(3) + c*x**S(6))**S(13), x), x, (a - b*x**S(3) - c*x**S(6))**S(14)/S(42), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)*(-a + b*x**n + c*x**(S(2)*n))**S(13), x), x, (a - b*x**n - c*x**(S(2)*n))**S(14)/(S(14)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(b*x + c*x**S(2))**S(13), x), x, (b*x + c*x**S(2))**S(14)/S(14), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))*(b*x**S(2) + c*x**S(4))**S(13), x), x, x**S(28)*(b + c*x**S(2))**S(14)/S(28), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))*(b*x**S(3) + c*x**S(6))**S(13), x), x, x**S(42)*(b + c*x**S(3))**S(14)/S(42), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)*(b*x**n + c*x**(S(2)*n))**S(13), x), x, x**(S(14)*n)*(b + c*x**n)**S(14)/(S(14)*n), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(a + b*x + c*x**S(2)), x), x, log(a + b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, log(a + b*x**S(2) + c*x**S(4))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))/(a + b*x**S(3) + c*x**S(6)), x), x, log(a + b*x**S(3) + c*x**S(6))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)/(a + b*x**n + c*x**(S(2)*n)), x), x, log(a + b*x**n + c*x**(S(2)*n))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(a + b*x + c*x**S(2))**S(8), x), x, -S(1)/(S(7)*(a + b*x + c*x**S(2))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(8), x), x, -S(1)/(S(14)*(a + b*x**S(2) + c*x**S(4))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))/(a + b*x**S(3) + c*x**S(6))**S(8), x), x, -S(1)/(S(21)*(a + b*x**S(3) + c*x**S(6))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)/(a + b*x**n + c*x**(S(2)*n))**S(8), x), x, -S(1)/(S(7)*n*(a + b*x**n + c*x**(S(2)*n))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(-a + b*x + c*x**S(2)), x), x, log(a - b*x - c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))/(-a + b*x**S(2) + c*x**S(4)), x), x, log(a - b*x**S(2) - c*x**S(4))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))/(-a + b*x**S(3) + c*x**S(6)), x), x, log(a - b*x**S(3) - c*x**S(6))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)/(-a + b*x**n + c*x**(S(2)*n)), x), x, log(a - b*x**n - c*x**(S(2)*n))/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(-a + b*x + c*x**S(2))**S(8), x), x, -S(1)/(S(7)*(-a + b*x + c*x**S(2))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))/(-a + b*x**S(2) + c*x**S(4))**S(8), x), x, S(1)/(S(14)*(a - b*x**S(2) - c*x**S(4))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))/(-a + b*x**S(3) + c*x**S(6))**S(8), x), x, S(1)/(S(21)*(a - b*x**S(3) - c*x**S(6))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)/(-a + b*x**n + c*x**(S(2)*n))**S(8), x), x, S(1)/(S(7)*n*(a - b*x**n - c*x**(S(2)*n))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(b*x + c*x**S(2)), x), x, log(b*x + c*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))/(b*x**S(2) + c*x**S(4)), x), x, log(x) + log(b + c*x**S(2))/S(2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))/(b*x**S(3) + c*x**S(6)), x), x, log(x) + log(b + c*x**S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)/(b*x**n + c*x**(S(2)*n)), x), x, log(x) + log(b + c*x**n)/n, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)/(b*x + c*x**S(2))**S(8), x), x, -S(1)/(S(7)*(b*x + c*x**S(2))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))/(b*x**S(2) + c*x**S(4))**S(8), x), x, -S(1)/(S(14)*x**S(14)*(b + c*x**S(2))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))/(b*x**S(3) + c*x**S(6))**S(8), x), x, -S(1)/(S(21)*x**S(21)*(b + c*x**S(3))**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)/(b*x**n + c*x**(S(2)*n))**S(8), x), x, -x**(-S(7)*n)/(S(7)*n*(b + c*x**n)**S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(a + b*x + c*x**S(2))**p, x), x, (a + b*x + c*x**S(2))**(p + S(1))/(p + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))*(a + b*x**S(2) + c*x**S(4))**p, x), x, (a + b*x**S(2) + c*x**S(4))**(p + S(1))/(S(2)*p + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))*(a + b*x**S(3) + c*x**S(6))**p, x), x, (a + b*x**S(3) + c*x**S(6))**(p + S(1))/(S(3)*p + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, (a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(-a + b*x + c*x**S(2))**p, x), x, (-a + b*x + c*x**S(2))**(p + S(1))/(p + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))*(-a + b*x**S(2) + c*x**S(4))**p, x), x, (-a + b*x**S(2) + c*x**S(4))**(p + S(1))/(S(2)*p + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))*(-a + b*x**S(3) + c*x**S(6))**p, x), x, (-a + b*x**S(3) + c*x**S(6))**(p + S(1))/(S(3)*p + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)*(-a + b*x**n + c*x**(S(2)*n))**p, x), x, (-a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((b + S(2)*c*x)*(b*x + c*x**S(2))**p, x), x, (b*x + c*x**S(2))**(p + S(1))/(p + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(b + S(2)*c*x**S(2))*(b*x**S(2) + c*x**S(4))**p, x), x, (b*x**S(2) + c*x**S(4))**(p + S(1))/(S(2)*p + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(b + S(2)*c*x**S(3))*(b*x**S(3) + c*x**S(6))**p, x), x, (b*x**S(3) + c*x**S(6))**(p + S(1))/(S(3)*p + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n + S(-1))*(b + S(2)*c*x**n)*(b*x**n + c*x**(S(2)*n))**p, x), x, (b*x**n + c*x**(S(2)*n))**(p + S(1))/(n*(p + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**n)/(a + b*x**n + c*x**(S(2)*n)), x), x, (f*x)**(m + S(1))*(e - (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))) + (f*x)**(m + S(1))*(e + (-b*e + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(f*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**n)/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, -c*(f*x)**(m + S(1))*((-S(2)*a*e + b*d)*(m - n + S(1)) + (S(2)*a*b*e*n + S(4)*a*c*d*(m - S(2)*n + S(1)) - b**S(2)*d*(m - n + S(1)))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*f*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))) - c*(f*x)**(m + S(1))*((-S(2)*a*e + b*d)*(m - n + S(1)) - (S(2)*a*b*e*n + S(4)*a*c*d*(m - S(2)*n + S(1)) - b**S(2)*d*(m - n + S(1)))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*f*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))) + (f*x)**(m + S(1))*(-a*b*e - S(2)*a*c*d + b**S(2)*d + c*x**n*(-S(2)*a*e + b*d))/(a*f*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) # large time assert rubi_test(rubi_integrate((d + e*x**n)**q/(x*(a + b*x**n + c*x**(S(2)*n))), x), x, c*(d + e*x**n)**(q + S(1))*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**n)/(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2)))))/(a*n*(q + S(1))*(S(2)*c*d - e*(b + sqrt(-S(4)*a*c + b**S(2))))) + c*(d + e*x**n)**(q + S(1))*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(2)*c*(d + e*x**n)/(-b*e + S(2)*c*d + e*sqrt(-S(4)*a*c + b**S(2))))/(a*n*(q + S(1))*(S(2)*c*d - e*(b - sqrt(-S(4)*a*c + b**S(2))))) - (d + e*x**n)**(q + S(1))*hyper((S(1), q + S(1)), (q + S(2),), S(1) + e*x**n/d)/(a*d*n*(q + S(1))), expand=True, _diff=True, _numerical=True) # Apart assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**n)/(a + b*x**n + c*x**(S(2)*n))**S(3), x), x, (f*x)**(m + S(1))*(-a*b*e - S(2)*a*c*d + b**S(2)*d + c*x**n*(-S(2)*a*e + b*d))/(S(2)*a*f*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))**S(2)) - c*(f*x)**(m + S(1))*((m - n + S(1))*(-S(4)*a**S(2)*c*e*(m - S(3)*n + S(1)) + a*b**S(2)*e*(m + S(1)) + S(2)*a*b*c*d*(S(2)*m - S(7)*n + S(2)) - b**S(3)*d*(m - S(2)*n + S(1))) - (-S(4)*a**S(2)*b*c*e*(m**S(2) + m*(-n + S(2)) - S(3)*n**S(2) - n + S(1)) - S(8)*a**S(2)*c**S(2)*d*(m**S(2) + m*(-S(6)*n + S(2)) + S(8)*n**S(2) - S(6)*n + S(1)) + a*b**S(3)*e*(m + S(1))*(m - n + S(1)) + S(6)*a*b**S(2)*c*d*(m**S(2) + m*(-S(4)*n + S(2)) + S(3)*n**S(2) - S(4)*n + S(1)) - b**S(4)*d*(m**S(2) + m*(-S(3)*n + S(2)) + S(2)*n**S(2) - S(3)*n + S(1)))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*f*n**S(2)*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**S(2)) - c*(f*x)**(m + S(1))*((m - n + S(1))*(-S(4)*a**S(2)*c*e*(m - S(3)*n + S(1)) + a*b**S(2)*e*(m + S(1)) + S(2)*a*b*c*d*(S(2)*m - S(7)*n + S(2)) - b**S(3)*d*(m - S(2)*n + S(1))) + (-S(4)*a**S(2)*b*c*e*(m**S(2) + m*(-n + S(2)) - S(3)*n**S(2) - n + S(1)) - S(8)*a**S(2)*c**S(2)*d*(m**S(2) + m*(-S(6)*n + S(2)) + S(8)*n**S(2) - S(6)*n + S(1)) + a*b**S(3)*e*(m + S(1))*(m - n + S(1)) + S(6)*a*b**S(2)*c*d*(m**S(2) + m*(-S(4)*n + S(2)) + S(3)*n**S(2) - S(4)*n + S(1)) - b**S(4)*d*(m**S(2) + m*(-S(3)*n + S(2)) + S(2)*n**S(2) - S(3)*n + S(1)))/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), (m + S(1))/n), ((m + n + S(1))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a**S(2)*f*n**S(2)*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**S(2)) + (f*x)**(m + S(1))*(a*b*c*(-S(2)*a*e + b*d)*(m - S(3)*n + S(1)) + c*x**n*(-S(4)*a**S(2)*c*e*(m - S(3)*n + S(1)) + a*b**S(2)*e*(m + S(1)) + S(2)*a*b*c*d*(S(2)*m - S(7)*n + S(2)) - b**S(3)*d*(m - S(2)*n + S(1))) + (-S(2)*a*c + b**S(2))*(a*b*e*(m + S(1)) + S(2)*a*c*d*(m - S(4)*n + S(1)) - b**S(2)*d*(m - S(2)*n + S(1))))/(S(2)*a**S(2)*f*n**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((c**(S(1)/3) - S(2)*d**(S(1)/3)*x**(S(1)/3))/(-c**(S(2)/3)*d**(S(2)/3)*x + c**(S(1)/3)*d*x**(S(4)/3) + c*d**(S(1)/3)*x**(S(2)/3)), x), x, -S(3)*log(c**(S(2)/3) - c**(S(1)/3)*d**(S(1)/3)*x**(S(1)/3) + d**(S(2)/3)*x**(S(2)/3))/(c**(S(1)/3)*d**(S(2)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, -c*(d - e*x)**(S(9)/2)*(d + e*x)**(S(9)/2)/(S(9)*e**S(10)) - d**S(4)*sqrt(d - e*x)*sqrt(d + e*x)*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))/e**S(10) + d**S(2)*(d - e*x)**(S(3)/2)*(d + e*x)**(S(3)/2)*(S(2)*a*e**S(4) + S(3)*b*d**S(2)*e**S(2) + S(4)*c*d**S(4))/(S(3)*e**S(10)) + (d - e*x)**(S(7)/2)*(d + e*x)**(S(7)/2)*(b*e**S(2) + S(4)*c*d**S(2))/(S(7)*e**S(10)) - (d - e*x)**(S(5)/2)*(d + e*x)**(S(5)/2)*(a*e**S(4) + S(3)*b*d**S(2)*e**S(2) + S(6)*c*d**S(4))/(S(5)*e**S(10)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(5)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, -c*(d**S(2) - e**S(2)*x**S(2))**S(5)/(S(9)*e**S(10)*sqrt(d - e*x)*sqrt(d + e*x)) - d**S(4)*(d**S(2) - e**S(2)*x**S(2))*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))/(e**S(10)*sqrt(d - e*x)*sqrt(d + e*x)) + d**S(2)*(d**S(2) - e**S(2)*x**S(2))**S(2)*(S(2)*a*e**S(4) + S(3)*b*d**S(2)*e**S(2) + S(4)*c*d**S(4))/(S(3)*e**S(10)*sqrt(d - e*x)*sqrt(d + e*x)) + (d**S(2) - e**S(2)*x**S(2))**S(4)*(b*e**S(2) + S(4)*c*d**S(2))/(S(7)*e**S(10)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))**S(3)*(a*e**S(4) + S(3)*b*d**S(2)*e**S(2) + S(6)*c*d**S(4))/(S(5)*e**S(10)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, c*(d - e*x)**(S(7)/2)*(d + e*x)**(S(7)/2)/(S(7)*e**S(8)) - d**S(2)*sqrt(d - e*x)*sqrt(d + e*x)*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))/e**S(8) - (d - e*x)**(S(5)/2)*(d + e*x)**(S(5)/2)*(b*e**S(2) + S(3)*c*d**S(2))/(S(5)*e**S(8)) + (d - e*x)**(S(3)/2)*(d + e*x)**(S(3)/2)*(a*e**S(4) + S(2)*b*d**S(2)*e**S(2) + S(3)*c*d**S(4))/(S(3)*e**S(8)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(3)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, c*(d**S(2) - e**S(2)*x**S(2))**S(4)/(S(7)*e**S(8)*sqrt(d - e*x)*sqrt(d + e*x)) - d**S(2)*(d**S(2) - e**S(2)*x**S(2))*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))/(e**S(8)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))**S(3)*(b*e**S(2) + S(3)*c*d**S(2))/(S(5)*e**S(8)*sqrt(d - e*x)*sqrt(d + e*x)) + (d**S(2) - e**S(2)*x**S(2))**S(2)*(a*e**S(4) + S(2)*b*d**S(2)*e**S(2) + S(3)*c*d**S(4))/(S(3)*e**S(8)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, -c*(d - e*x)**(S(5)/2)*(d + e*x)**(S(5)/2)/(S(5)*e**S(6)) + (d - e*x)**(S(3)/2)*(d + e*x)**(S(3)/2)*(b*e**S(2) + S(2)*c*d**S(2))/(S(3)*e**S(6)) - sqrt(d - e*x)*sqrt(d + e*x)*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))/e**S(6), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, -c*(d**S(2) - e**S(2)*x**S(2))**S(3)/(S(5)*e**S(6)*sqrt(d - e*x)*sqrt(d + e*x)) + (d**S(2) - e**S(2)*x**S(2))**S(2)*(b*e**S(2) + S(2)*c*d**S(2))/(S(3)*e**S(6)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))/(e**S(6)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*atanh(sqrt(d - e*x)*sqrt(d + e*x)/d)/d + c*(d - e*x)**(S(3)/2)*(d + e*x)**(S(3)/2)/(S(3)*e**S(4)) - sqrt(d - e*x)*sqrt(d + e*x)*(b*e**S(2) + c*d**S(2))/e**S(4), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*sqrt(d**S(2) - e**S(2)*x**S(2))*atanh(sqrt(d**S(2) - e**S(2)*x**S(2))/d)/(d*sqrt(d - e*x)*sqrt(d + e*x)) + c*(d**S(2) - e**S(2)*x**S(2))**S(2)/(S(3)*e**S(4)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))*(b*e**S(2) + c*d**S(2))/(e**S(4)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(3)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*sqrt(d - e*x)*sqrt(d + e*x)/(S(2)*d**S(2)*x**S(2)) - c*sqrt(d - e*x)*sqrt(d + e*x)/e**S(2) - (a*e**S(2) + S(2)*b*d**S(2))*atanh(sqrt(d - e*x)*sqrt(d + e*x)/d)/(S(2)*d**S(3)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(3)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*(d**S(2) - e**S(2)*x**S(2))/(S(2)*d**S(2)*x**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) - c*(d**S(2) - e**S(2)*x**S(2))/(e**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) - sqrt(d**S(2) - e**S(2)*x**S(2))*(a*e**S(2) + S(2)*b*d**S(2))*atanh(sqrt(d**S(2) - e**S(2)*x**S(2))/d)/(S(2)*d**S(3)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(5)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*sqrt(d - e*x)*sqrt(d + e*x)/(S(4)*d**S(2)*x**S(4)) - sqrt(d - e*x)*sqrt(d + e*x)*(S(3)*a*e**S(2) + S(4)*b*d**S(2))/(S(8)*d**S(4)*x**S(2)) - (S(3)*a*e**S(4) + S(4)*b*d**S(2)*e**S(2) + S(8)*c*d**S(4))*atanh(sqrt(d - e*x)*sqrt(d + e*x)/d)/(S(8)*d**S(5)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(5)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*(d**S(2) - e**S(2)*x**S(2))/(S(4)*d**S(2)*x**S(4)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))*(S(3)*a*e**S(2) + S(4)*b*d**S(2))/(S(8)*d**S(4)*x**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) - sqrt(d**S(2) - e**S(2)*x**S(2))*(S(3)*a*e**S(4) + S(4)*b*d**S(2)*e**S(2) + S(8)*c*d**S(4))*atanh(sqrt(d**S(2) - e**S(2)*x**S(2))/d)/(S(8)*d**S(5)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(7)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*sqrt(d - e*x)*sqrt(d + e*x)/(S(6)*d**S(2)*x**S(6)) - sqrt(d - e*x)*sqrt(d + e*x)*(S(5)*a*e**S(2) + S(6)*b*d**S(2))/(S(24)*d**S(4)*x**S(4)) - sqrt(d - e*x)*sqrt(d + e*x)*(S(5)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(8)*c*d**S(4))/(S(16)*d**S(6)*x**S(2)) - e**S(2)*sqrt(d**S(2) - e**S(2)*x**S(2))*(S(5)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(8)*c*d**S(4))*atanh(sqrt(d**S(2) - e**S(2)*x**S(2))/d)/(S(16)*d**S(7)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(7)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*(d**S(2) - e**S(2)*x**S(2))/(S(6)*d**S(2)*x**S(6)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))*(S(5)*a*e**S(2) + S(6)*b*d**S(2))/(S(24)*d**S(4)*x**S(4)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))*(S(5)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(8)*c*d**S(4))/(S(16)*d**S(6)*x**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) - e**S(2)*sqrt(d**S(2) - e**S(2)*x**S(2))*(S(5)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(8)*c*d**S(4))*atanh(sqrt(d**S(2) - e**S(2)*x**S(2))/d)/(S(16)*d**S(7)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, c*x**S(7)*(-d + e*x)*sqrt(d + e*x)/(S(8)*e**S(2)*sqrt(d - e*x)) + d**S(4)*sqrt(d**S(2) - e**S(2)*x**S(2))*(S(48)*a*e**S(4) + S(40)*b*d**S(2)*e**S(2) + S(35)*c*d**S(4))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(S(128)*e**S(9)*sqrt(d - e*x)*sqrt(d + e*x)) - d**S(2)*x*sqrt(d - e*x)*sqrt(d + e*x)*(S(48)*a*e**S(4) + S(40)*b*d**S(2)*e**S(2) + S(35)*c*d**S(4))/(S(128)*e**S(8)) - x**S(5)*sqrt(d - e*x)*sqrt(d + e*x)*(S(8)*b*e**S(2) + S(7)*c*d**S(2))/(S(48)*e**S(4)) - x**S(3)*sqrt(d - e*x)*sqrt(d + e*x)*(S(48)*a*e**S(4) + S(40)*b*d**S(2)*e**S(2) + S(35)*c*d**S(4))/(S(192)*e**S(6)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(4)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, -c*x**S(7)*(d**S(2) - e**S(2)*x**S(2))/(S(8)*e**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) + d**S(4)*sqrt(d**S(2) - e**S(2)*x**S(2))*(S(48)*a*e**S(4) + S(40)*b*d**S(2)*e**S(2) + S(35)*c*d**S(4))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(S(128)*e**S(9)*sqrt(d - e*x)*sqrt(d + e*x)) - d**S(2)*x*(d**S(2) - e**S(2)*x**S(2))*(S(48)*a*e**S(4) + S(40)*b*d**S(2)*e**S(2) + S(35)*c*d**S(4))/(S(128)*e**S(8)*sqrt(d - e*x)*sqrt(d + e*x)) - x**S(5)*(d**S(2) - e**S(2)*x**S(2))*(S(8)*b*e**S(2) + S(7)*c*d**S(2))/(S(48)*e**S(4)*sqrt(d - e*x)*sqrt(d + e*x)) - x**S(3)*(d**S(2) - e**S(2)*x**S(2))*(S(48)*a*e**S(4) + S(40)*b*d**S(2)*e**S(2) + S(35)*c*d**S(4))/(S(192)*e**S(6)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, c*x**S(5)*(-d + e*x)*sqrt(d + e*x)/(S(6)*e**S(2)*sqrt(d - e*x)) + d**S(2)*sqrt(d**S(2) - e**S(2)*x**S(2))*(S(8)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(5)*c*d**S(4))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(S(16)*e**S(7)*sqrt(d - e*x)*sqrt(d + e*x)) - x**S(3)*sqrt(d - e*x)*sqrt(d + e*x)*(S(6)*b*e**S(2) + S(5)*c*d**S(2))/(S(24)*e**S(4)) - x*sqrt(d - e*x)*sqrt(d + e*x)*(S(8)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(5)*c*d**S(4))/(S(16)*e**S(6)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, -c*x**S(5)*(d**S(2) - e**S(2)*x**S(2))/(S(6)*e**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) + d**S(2)*sqrt(d**S(2) - e**S(2)*x**S(2))*(S(8)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(5)*c*d**S(4))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(S(16)*e**S(7)*sqrt(d - e*x)*sqrt(d + e*x)) - x**S(3)*(d**S(2) - e**S(2)*x**S(2))*(S(6)*b*e**S(2) + S(5)*c*d**S(2))/(S(24)*e**S(4)*sqrt(d - e*x)*sqrt(d + e*x)) - x*(d**S(2) - e**S(2)*x**S(2))*(S(8)*a*e**S(4) + S(6)*b*d**S(2)*e**S(2) + S(5)*c*d**S(4))/(S(16)*e**S(6)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, c*x**S(3)*(-d + e*x)*sqrt(d + e*x)/(S(4)*e**S(2)*sqrt(d - e*x)) - x*sqrt(d - e*x)*sqrt(d + e*x)*(S(4)*b*e**S(2) + S(3)*c*d**S(2))/(S(8)*e**S(4)) - (S(8)*a*e**S(4) + S(4)*b*d**S(2)*e**S(2) + S(3)*c*d**S(4))*atan(sqrt(d - e*x)/sqrt(d + e*x))/(S(4)*e**S(5)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(sqrt(d - e*x)*sqrt(d + e*x)), x), x, -c*x**S(3)*(d**S(2) - e**S(2)*x**S(2))/(S(4)*e**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) - x*(d**S(2) - e**S(2)*x**S(2))*(S(4)*b*e**S(2) + S(3)*c*d**S(2))/(S(8)*e**S(4)*sqrt(d - e*x)*sqrt(d + e*x)) + sqrt(d**S(2) - e**S(2)*x**S(2))*(S(8)*a*e**S(4) + S(4)*b*d**S(2)*e**S(2) + S(3)*c*d**S(4))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(S(8)*e**S(5)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(2)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*sqrt(d - e*x)*sqrt(d + e*x)/(d**S(2)*x) + c*x*(-d + e*x)*sqrt(d + e*x)/(S(2)*e**S(2)*sqrt(d - e*x)) - (S(2)*b*e**S(2) + c*d**S(2))*atan(sqrt(d - e*x)/sqrt(d + e*x))/e**S(3), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(2)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*(d**S(2) - e**S(2)*x**S(2))/(d**S(2)*x*sqrt(d - e*x)*sqrt(d + e*x)) - c*x*(d**S(2) - e**S(2)*x**S(2))/(S(2)*e**S(2)*sqrt(d - e*x)*sqrt(d + e*x)) + sqrt(d**S(2) - e**S(2)*x**S(2))*(S(2)*b*e**S(2) + c*d**S(2))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(S(2)*e**S(3)*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(4)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*sqrt(d - e*x)*sqrt(d + e*x)/(S(3)*d**S(2)*x**S(3)) - S(2)*a*e**S(2)*sqrt(d - e*x)*sqrt(d + e*x)/(S(3)*d**S(4)*x) - b*sqrt(d - e*x)*sqrt(d + e*x)/(d**S(2)*x) + c*sqrt(d**S(2) - e**S(2)*x**S(2))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(e*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(4)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*(d**S(2) - e**S(2)*x**S(2))/(S(3)*d**S(2)*x**S(3)*sqrt(d - e*x)*sqrt(d + e*x)) - S(2)*a*e**S(2)*(d**S(2) - e**S(2)*x**S(2))/(S(3)*d**S(4)*x*sqrt(d - e*x)*sqrt(d + e*x)) - b*(d**S(2) - e**S(2)*x**S(2))/(d**S(2)*x*sqrt(d - e*x)*sqrt(d + e*x)) + c*sqrt(d**S(2) - e**S(2)*x**S(2))*atan(e*x/sqrt(d**S(2) - e**S(2)*x**S(2)))/(e*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(6)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*sqrt(d - e*x)*sqrt(d + e*x)/(S(5)*d**S(2)*x**S(5)) - c*(-d + e*x)*sqrt(d + e*x)/(S(2)*e**S(2)*x**S(3)*sqrt(d - e*x)) - sqrt(d - e*x)*sqrt(d + e*x)*(S(8)*a*e**S(4) + S(10)*b*d**S(2)*e**S(2) + S(15)*c*d**S(4))/(S(30)*d**S(4)*e**S(2)*x**S(3)) - sqrt(d - e*x)*sqrt(d + e*x)*(S(8)*a*e**S(4) + S(10)*b*d**S(2)*e**S(2) + S(15)*c*d**S(4))/(S(15)*d**S(6)*x), expand=True, _diff=True, _numerical=True) or rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))/(x**S(6)*sqrt(d - e*x)*sqrt(d + e*x)), x), x, -a*(d**S(2) - e**S(2)*x**S(2))/(S(5)*d**S(2)*x**S(5)*sqrt(d - e*x)*sqrt(d + e*x)) + c*(d**S(2) - e**S(2)*x**S(2))/(S(2)*e**S(2)*x**S(3)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))*(S(8)*a*e**S(4) + S(10)*b*d**S(2)*e**S(2) + S(15)*c*d**S(4))/(S(30)*d**S(4)*e**S(2)*x**S(3)*sqrt(d - e*x)*sqrt(d + e*x)) - (d**S(2) - e**S(2)*x**S(2))*(S(8)*a*e**S(4) + S(10)*b*d**S(2)*e**S(2) + S(15)*c*d**S(4))/(S(15)*d**S(6)*x*sqrt(d - e*x)*sqrt(d + e*x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(a + c*x**(S(2)*n))**p/(d + e*x**n), x), x, x*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + S(1))/(S(2)*n), -p, S(1), S(1) + (m + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d*(m + S(1))) - e*x**(n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + n + S(1))/(S(2)*n), -p, S(1), (m + S(3)*n + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(2)*(m + n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(a + c*x**(S(2)*n))**p/(d + e*x**n)**S(2), x), x, x*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + S(1))/(S(2)*n), -p, S(2), S(1) + (m + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(2)*(m + S(1))) - S(2)*e*x**(n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + n + S(1))/(S(2)*n), -p, S(2), (m + S(3)*n + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(3)*(m + n + S(1))) + e**S(2)*x**(S(2)*n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + S(2)*n + S(1))/(S(2)*n), -p, S(2), (m + S(4)*n + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(4)*(m + S(2)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(a + c*x**(S(2)*n))**p/(d + e*x**n)**S(3), x), x, x*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + S(1))/(S(2)*n), -p, S(3), S(1) + (m + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(3)*(m + S(1))) - S(3)*e*x**(n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + n + S(1))/(S(2)*n), -p, S(3), (m + S(3)*n + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(4)*(m + n + S(1))) + S(3)*e**S(2)*x**(S(2)*n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + S(2)*n + S(1))/(S(2)*n), -p, S(3), (m + S(4)*n + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(5)*(m + S(2)*n + S(1))) - e**S(3)*x**(S(3)*n + S(1))*(f*x)**m*(S(1) + c*x**(S(2)*n)/a)**(-p)*(a + c*x**(S(2)*n))**p*AppellF1((m + S(3)*n + S(1))/(S(2)*n), -p, S(3), (m + S(5)*n + S(1))/(S(2)*n), -c*x**(S(2)*n)/a, e**S(2)*x**(S(2)*n)/d**S(2))/(d**S(6)*(m + S(3)*n + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**n)**S(2)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, d**S(2)*(f*x)**(m + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1((m + S(1))/n, -p, -p, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(m + S(1))) + S(2)*d*e*x**(n + S(1))*(f*x)**m*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1((m + n + S(1))/n, -p, -p, (m + S(2)*n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(m + n + S(1)) + e**S(2)*x**(S(2)*n + S(1))*(f*x)**m*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1((m + S(2)*n + S(1))/n, -p, -p, (m + S(3)*n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(m + S(2)*n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, d*(f*x)**(m + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1((m + S(1))/n, -p, -p, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(m + S(1))) + e*x**(n + S(1))*(f*x)**m*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1((m + n + S(1))/n, -p, -p, (m + S(2)*n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(m + n + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x, (f*x)**(m + S(1))*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**(-p)*(a + b*x**n + c*x**(S(2)*n))**p*AppellF1((m + S(1))/n, -p, -p, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(f*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((f*x)**m*(d + e*x**n)**q/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*(f*x)**(m + S(1))*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1((m + S(1))/n, S(1), -q, (m + n + S(1))/n, -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(f*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*c*(f*x)**(m + S(1))*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1((m + S(1))/n, S(1), -q, (m + n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(f*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(d + e*x**n)**q/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*x**S(3)*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(S(3)/n, S(1), -q, (n + S(3))/n, -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(-S(12)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*x**S(3)*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(S(3)/n, S(1), -q, (n + S(3))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(-S(12)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**n)**q/(a + b*x**n + c*x**(S(2)*n)), x), x, -c*x**S(2)*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(S(2)/n, S(1), -q, (n + S(2))/n, -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - c*x**S(2)*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(S(2)/n, S(1), -q, (n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**q/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*x*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(S(1)/n, S(1), -q, S(1) + S(1)/n, -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*x*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(S(1)/n, S(1), -q, S(1) + S(1)/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**q/(x**S(2)*(a + b*x**n + c*x**(S(2)*n))), x), x, S(2)*c*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(-S(1)/n, S(1), -q, -(-n + S(1))/n, -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(x*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) + S(2)*c*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(-S(1)/n, S(1), -q, -(-n + S(1))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(x*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x**n)**q/(x**S(3)*(a + b*x**n + c*x**(S(2)*n))), x), x, c*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(-S(2)/n, S(1), -q, -(-n + S(2))/n, -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(x**S(2)*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) + c*(S(1) + e*x**n/d)**(-q)*(d + e*x**n)**q*AppellF1(-S(2)/n, S(1), -q, -(-n + S(2))/n, -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))), -e*x**n/d)/(x**S(2)*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) def test_4(): assert rubi_test(rubi_integrate((x**S(3) + x**S(2))/(x**S(2) + x + S(-2)), x), x, x**S(2)/S(2) + S(2)*log(-x + S(1))/S(3) + S(4)*log(x + S(2))/S(3), expand=True, _diff=True, _numerical=True) # Large time assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + j*x**S(5) + k*x**S(6) + l*x**S(7) + m*x**S(8))/(a + b*x + c*x**S(2)), x), x, m*x**S(7)/(S(7)*c) + x**S(6)*(-b*m + c*l)/(S(6)*c**S(2)) + x**S(5)*(b**S(2)*m + c**S(2)*k - c*(a*m + b*l))/(S(5)*c**S(3)) + x**S(4)*(-b**S(3)*m + b*c*(S(2)*a*m + b*l) + c**S(3)*j - c**S(2)*(a*l + b*k))/(S(4)*c**S(4)) + x**S(3)*(b**S(4)*m - b**S(2)*c*(S(3)*a*m + b*l) + c**S(4)*h - c**S(3)*(a*k + b*j) + c**S(2)*(a**S(2)*m + S(2)*a*b*l + b**S(2)*k))/(S(3)*c**S(5)) + x**S(2)*(-b**S(5)*m + b**S(3)*c*(S(4)*a*m + b*l) - b*c**S(2)*(S(3)*a**S(2)*m + S(3)*a*b*l + b**S(2)*k) + c**S(5)*g - c**S(4)*(a*j + b*h) + c**S(3)*(a**S(2)*l + S(2)*a*b*k + b**S(2)*j))/(S(2)*c**S(6)) + x*(b**S(6)*m - b**S(4)*c*(S(5)*a*m + b*l) + b**S(2)*c**S(2)*(S(6)*a**S(2)*m + S(4)*a*b*l + b**S(2)*k) + c**S(6)*f - c**S(5)*(a*h + b*g) + c**S(4)*(a**S(2)*k + S(2)*a*b*j + b**S(2)*h) - c**S(3)*(a**S(3)*m + S(3)*a**S(2)*b*l + S(3)*a*b**S(2)*k + b**S(3)*j))/c**S(7) + (-b**S(7)*m + b**S(5)*c*(S(6)*a*m + b*l) - b**S(3)*c**S(2)*(S(10)*a**S(2)*m + S(5)*a*b*l + b**S(2)*k) + b*c**S(3)*(S(4)*a**S(3)*m + S(6)*a**S(2)*b*l + S(4)*a*b**S(2)*k + b**S(3)*j) + c**S(7)*e - c**S(6)*(a*g + b*f) + c**S(5)*(a**S(2)*j + S(2)*a*b*h + b**S(2)*g) - c**S(4)*(a**S(3)*l + S(3)*a**S(2)*b*k + S(3)*a*b**S(2)*j + b**S(3)*h))*log(a + b*x + c*x**S(2))/(S(2)*c**S(8)) - (b**S(8)*m - b**S(6)*c*(S(8)*a*m + b*l) + b**S(4)*c**S(2)*(S(20)*a**S(2)*m + S(7)*a*b*l + b**S(2)*k) - b**S(2)*c**S(3)*(S(16)*a**S(3)*m + S(14)*a**S(2)*b*l + S(6)*a*b**S(2)*k + b**S(3)*j) + S(2)*c**S(8)*d - c**S(7)*(S(2)*a*f + b*e) + c**S(6)*(S(2)*a**S(2)*h + S(3)*a*b*g + b**S(2)*f) - c**S(5)*(S(2)*a**S(3)*k + S(5)*a**S(2)*b*j + S(4)*a*b**S(2)*h + b**S(3)*g) + c**S(4)*(S(2)*a**S(4)*m + S(7)*a**S(3)*b*l + S(9)*a**S(2)*b**S(2)*k + S(5)*a*b**S(3)*j + b**S(4)*h))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(8)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(a + b*x + c*x**S(2))**S(2), x), x, g*log(a + b*x + c*x**S(2))/(S(2)*c**S(2)) - (-a*b**S(2)*g - S(2)*a*c*(-a*g + c*e) + b*c*(a*f + c*d) + x*(-b**S(3)*g + b*c*(S(3)*a*g + b*f) + S(2)*c**S(3)*d - c**S(2)*(S(2)*a*f + b*e)))/(c**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + (-S(6)*a*b*c*g + b**S(3)*g + S(4)*c**S(3)*d - c**S(2)*(-S(4)*a*f + S(2)*b*e))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(a + b*x + c*x**S(2))**S(3), x), x, -x**S(3)*(-S(5)*b*i + S(2)*c*h)/(S(2)*c**S(2)*(a + b*x + c*x**S(2))**S(2)) + i*log(a + b*x + c*x**S(2))/(S(2)*c**S(3)) - x**S(2)*(-S(4)*a*c*i - S(9)*b**S(2)*i + S(2)*b*c*h + S(2)*c**S(2)*g)/(S(4)*c**S(3)*(a + b*x + c*x**S(2))**S(2)) - (-S(30)*a**S(2)*b*c**S(2)*i + S(10)*a*b**S(3)*c*i - b**S(5)*i + S(12)*c**S(5)*d - c**S(4)*(-S(4)*a*f + S(6)*b*e) + S(2)*c**S(3)*(S(6)*a**S(2)*h - S(3)*a*b*g + b**S(2)*f))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)) + (b + S(2)*c*x)*(-S(30)*a**S(2)*b*c**S(2)*i + S(10)*a*b**S(3)*c*i - b**S(5)*i + S(12)*c**S(5)*d - c**S(4)*(-S(4)*a*f + S(6)*b*e) + S(2)*c**S(3)*(S(6)*a**S(2)*h - S(3)*a*b*g + b**S(2)*f))/(S(4)*c**S(4)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x + c*x**S(2))) - (c**S(3)*(-a*b**S(4)*i/c**S(3) - S(4)*a*(-S(3)*a**S(2)*i/c + a*g + c*e) + S(2)*b*(a**S(2)*h/c + a*f + c*d)) + x*(-S(8)*a*b**S(3)*c*i + S(2)*a*b*c**S(2)*(S(23)*a*i + S(2)*b*h) - b**S(5)*i + S(4)*c**S(5)*d - S(2)*c**S(4)*(S(2)*a*f + b*e) + S(2)*c**S(3)*(-S(6)*a**S(2)*h - a*b*g + b**S(2)*f)))/(S(4)*c**S(4)*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(a + b*x + c*x**S(2))**(S(5)/2), x), x, -x**S(2)*(-S(2)*b*h + c*g)/(c**S(2)*(a + b*x + c*x**S(2))**(S(3)/2)) + (b + S(2)*c*x)*(-S(4)*b**S(4)*h + b**S(2)*c*(S(28)*a*h + b*g) + S(16)*c**S(4)*d - c**S(3)*(-S(8)*a*f + S(8)*b*e) + S(2)*c**S(2)*(-S(16)*a**S(2)*h - S(6)*a*b*g + b**S(2)*f))/(S(3)*c**S(3)*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x + c*x**S(2))) - (c**S(2)*(-S(4)*a*b**S(3)*h/c**S(2) + a*b**S(2)*g/c - S(4)*a*(S(2)*a*g + c*e) + S(2)*b*(S(9)*a**S(2)*h/c + a*f + c*d)) + x*(-S(4)*b**S(4)*h + b**S(2)*c*(S(16)*a*h + b*g) + S(4)*c**S(4)*d - S(2)*c**S(3)*(S(2)*a*f + b*e) + S(2)*c**S(2)*(S(2)*a**S(2)*h - S(3)*a*b*g + b**S(2)*f)))/(S(3)*c**S(3)*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))**(S(3)/2)) + h*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/c**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(a + b*x - c*x**S(2))**(S(5)/2), x), x, x**S(2)*(S(2)*b*h + c*g)/(c**S(2)*(a + b*x - c*x**S(2))**(S(3)/2)) - (b - S(2)*c*x)*(-S(4)*b**S(4)*h - b**S(2)*c*(S(28)*a*h + b*g) + S(16)*c**S(4)*d + S(8)*c**S(3)*(-a*f + b*e) + S(2)*c**S(2)*(-S(16)*a**S(2)*h - S(6)*a*b*g + b**S(2)*f))/(S(3)*c**S(3)*(S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x - c*x**S(2))) - (c**S(2)*(S(4)*a*b**S(3)*h/c**S(2) + a*b**S(2)*g/c - S(4)*a*(-S(2)*a*g + c*e) + S(2)*b*(S(9)*a**S(2)*h/c - a*f + c*d)) - x*(-S(4)*b**S(4)*h - b**S(2)*c*(S(16)*a*h + b*g) + S(4)*c**S(4)*d + S(2)*c**S(3)*(S(2)*a*f + b*e) + S(2)*c**S(2)*(S(2)*a**S(2)*h - S(3)*a*b*g + b**S(2)*f)))/(S(3)*c**S(3)*(S(4)*a*c + b**S(2))*(a + b*x - c*x**S(2))**(S(3)/2)) - h*atan((b - S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x - c*x**S(2))))/c**(S(5)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(a + b*x**S(2) + c*x**S(4)), x), x, a*d*x + a*e*x**S(2)/S(2) + b*d*x**S(3)/S(3) + b*e*x**S(4)/S(4) + c*d*x**S(5)/S(5) + c*e*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))*(d + e*x + f*x**S(2)), x), x, a*d*x + a*e*x**S(2)/S(2) + b*e*x**S(4)/S(4) + c*e*x**S(6)/S(6) + c*f*x**S(7)/S(7) + x**S(5)*(b*f/S(5) + c*d/S(5)) + x**S(3)*(a*f/S(3) + b*d/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))*(d + e*x + f*x**S(2) + g*x**S(3)), x), x, a*d*x + a*e*x**S(2)/S(2) + c*f*x**S(7)/S(7) + c*g*x**S(8)/S(8) + x**S(6)*(b*g/S(6) + c*e/S(6)) + x**S(5)*(b*f/S(5) + c*d/S(5)) + x**S(4)*(a*g/S(4) + b*e/S(4)) + x**S(3)*(a*f/S(3) + b*d/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4)), x), x, a*d*x + a*e*x**S(2)/S(2) + c*g*x**S(8)/S(8) + c*h*x**S(9)/S(9) + x**S(7)*(b*h/S(7) + c*f/S(7)) + x**S(6)*(b*g/S(6) + c*e/S(6)) + x**S(5)*(a*h/S(5) + b*f/S(5) + c*d/S(5)) + x**S(4)*(a*g/S(4) + b*e/S(4)) + x**S(3)*(a*f/S(3) + b*d/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5)), x), x, a*d*x + a*e*x**S(2)/S(2) + c*h*x**S(9)/S(9) + c*i*x**S(10)/S(10) + x**S(8)*(b*i/S(8) + c*g/S(8)) + x**S(7)*(b*h/S(7) + c*f/S(7)) + x**S(6)*(a*i/S(6) + b*g/S(6) + c*e/S(6)) + x**S(5)*(a*h/S(5) + b*f/S(5) + c*d/S(5)) + x**S(4)*(a*g/S(4) + b*e/S(4)) + x**S(3)*(a*f/S(3) + b*d/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, a**S(2)*d*x + a**S(2)*e*x**S(2)/S(2) + S(2)*a*b*d*x**S(3)/S(3) + a*b*e*x**S(4)/S(2) + S(2)*b*c*d*x**S(7)/S(7) + b*c*e*x**S(8)/S(4) + c**S(2)*d*x**S(9)/S(9) + c**S(2)*e*x**S(10)/S(10) + d*x**S(5)*(S(2)*a*c/S(5) + b**S(2)/S(5)) + e*x**S(6)*(a*c/S(3) + b**S(2)/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)*(d + e*x + f*x**S(2)), x), x, a**S(2)*d*x + a**S(2)*e*x**S(2)/S(2) + a*b*e*x**S(4)/S(2) + a*x**S(3)*(a*f + S(2)*b*d)/S(3) + b*c*e*x**S(8)/S(4) + c**S(2)*e*x**S(10)/S(10) + c**S(2)*f*x**S(11)/S(11) + c*x**S(9)*(S(2)*b*f + c*d)/S(9) + e*x**S(6)*(a*c/S(3) + b**S(2)/S(6)) + x**S(7)*(S(2)*a*c*f/S(7) + b**S(2)*f/S(7) + S(2)*b*c*d/S(7)) + x**S(5)*(S(2)*a*b*f/S(5) + S(2)*a*c*d/S(5) + b**S(2)*d/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)*(d + e*x + f*x**S(2) + g*x**S(3)), x), x, a**S(2)*d*x + a**S(2)*e*x**S(2)/S(2) + a*x**S(4)*(a*g + S(2)*b*e)/S(4) + a*x**S(3)*(a*f + S(2)*b*d)/S(3) + c**S(2)*f*x**S(11)/S(11) + c**S(2)*g*x**S(12)/S(12) + c*x**S(10)*(S(2)*b*g + c*e)/S(10) + c*x**S(9)*(S(2)*b*f + c*d)/S(9) + x**S(8)*(a*c*g/S(4) + b**S(2)*g/S(8) + b*c*e/S(4)) + x**S(7)*(S(2)*a*c*f/S(7) + b**S(2)*f/S(7) + S(2)*b*c*d/S(7)) + x**S(6)*(a*b*g/S(3) + a*c*e/S(3) + b**S(2)*e/S(6)) + x**S(5)*(S(2)*a*b*f/S(5) + S(2)*a*c*d/S(5) + b**S(2)*d/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4)), x), x, a**S(2)*d*x + a**S(2)*e*x**S(2)/S(2) + a*x**S(4)*(a*g + S(2)*b*e)/S(4) + a*x**S(3)*(a*f + S(2)*b*d)/S(3) + c**S(2)*g*x**S(12)/S(12) + c**S(2)*h*x**S(13)/S(13) + c*x**S(11)*(S(2)*b*h + c*f)/S(11) + c*x**S(10)*(S(2)*b*g + c*e)/S(10) + x**S(9)*(b**S(2)*h/S(9) + c**S(2)*d/S(9) + S(2)*c*(a*h + b*f)/S(9)) + x**S(8)*(a*c*g/S(4) + b**S(2)*g/S(8) + b*c*e/S(4)) + x**S(7)*(S(2)*a*c*f/S(7) + b**S(2)*f/S(7) + S(2)*b*(a*h + c*d)/S(7)) + x**S(6)*(a*b*g/S(3) + a*c*e/S(3) + b**S(2)*e/S(6)) + x**S(5)*(S(2)*a*b*f/S(5) + a*(a*h + S(2)*c*d)/S(5) + b**S(2)*d/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, -d*atanh(x/S(2))/S(6) + d*atanh(x)/S(3) - e*log(-x**S(2) + S(1))/S(6) + e*log(-x**S(2) + S(4))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, -e*log(-x**S(2) + S(1))/S(6) + e*log(-x**S(2) + S(4))/S(6) + (-d/S(6) - S(2)*f/S(3))*atanh(x/S(2)) + (d/S(3) + f/S(3))*atanh(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, (-d/S(6) - S(2)*f/S(3))*atanh(x/S(2)) + (d/S(3) + f/S(3))*atanh(x) - (e/S(6) + g/S(6))*log(-x**S(2) + S(1)) + (e/S(6) + S(2)*g/S(3))*log(-x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, h*x - (e/S(6) + g/S(6))*log(-x**S(2) + S(1)) + (e/S(6) + S(2)*g/S(3))*log(-x**S(2) + S(4)) - (d/S(6) + S(2)*f/S(3) + S(8)*h/S(3))*atanh(x/S(2)) + (d/S(3) + f/S(3) + h/S(3))*atanh(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, h*x + i*x**S(2)/S(2) - (d/S(6) + S(2)*f/S(3) + S(8)*h/S(3))*atanh(x/S(2)) + (d/S(3) + f/S(3) + h/S(3))*atanh(x) - (e/S(6) + g/S(6) + i/S(6))*log(-x**S(2) + S(1)) + (e/S(6) + S(2)*g/S(3) + S(8)*i/S(3))*log(-x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(x**S(4) + x**S(2) + S(1)), x), x, -d*log(x**S(2) - x + S(1))/S(4) + d*log(x**S(2) + x + S(1))/S(4) - sqrt(S(3))*d*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*d*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*e*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(x**S(4) + x**S(2) + S(1)), x), x, sqrt(S(3))*e*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(3) - (d/S(4) - f/S(4))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(4))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(d + f)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*(d + f)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) + x**S(2) + S(1)), x), x, g*log(x**S(4) + x**S(2) + S(1))/S(4) - (d/S(4) - f/S(4))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(4))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(d + f)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*(d + f)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*(S(2)*e - g)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) + x**S(2) + S(1)), x), x, g*log(x**S(4) + x**S(2) + S(1))/S(4) + h*x - (d/S(4) - f/S(4))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(4))*log(x**S(2) + x + S(1)) + sqrt(S(3))*(S(2)*e - g)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(6) - sqrt(S(3))*(d + f - S(2)*h)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*(d + f - S(2)*h)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) + x**S(2) + S(1)), x), x, h*x + i*x**S(2)/S(2) - (d/S(4) - f/S(4))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(4))*log(x**S(2) + x + S(1)) + (g/S(4) - i/S(4))*log(x**S(4) + x**S(2) + S(1)) - sqrt(S(3))*(d + f - S(2)*h)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*(d + f - S(2)*h)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(6) + sqrt(S(3))*(S(2)*e - g - i)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*sqrt(c)*d*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*d*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) - e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)) + sqrt(S(2))*(f - (-b*f + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(f + (-b*f + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(a + b*x**S(2) + c*x**S(4)), x), x, g*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c) - (-b*g + S(2)*c*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(f - (-b*f + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(f + (-b*f + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(a + b*x**S(2) + c*x**S(4)), x), x, g*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c) + h*x/c - (-b*g + S(2)*c*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(-b*h/c + f - (-S(2)*a*c*h + b**S(2)*h - b*c*f + S(2)*c**S(2)*d)/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(-b*h/c + f + (b**S(2)*h + S(2)*c**S(2)*d - c*(S(2)*a*h + b*f))/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(a + b*x**S(2) + c*x**S(4)), x), x, h*x/c + i*x**S(2)/(S(2)*c) + (-b*i + c*g)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) - (-S(2)*a*c*i + b**S(2)*i - b*c*g + S(2)*c**S(2)*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(-b*h/c + f - (-S(2)*a*c*h + b**S(2)*h - b*c*f + S(2)*c**S(2)*d)/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(-b*h/c + f + (b**S(2)*h + S(2)*c**S(2)*d - c*(S(2)*a*h + b*f))/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) # failing assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + j*x**S(5) + k*x**S(6) + l*x**S(7) + m*x**S(8))/(a + b*x**S(2) + c*x**S(4)), x), x, l*x**S(4)/(S(4)*c) + m*x**S(5)/(S(5)*c) + x**S(3)*(-b*m + c*k)/(S(3)*c**S(2)) + x**S(2)*(-b*l + c*j)/(S(2)*c**S(2)) + x*(b**S(2)*m + c**S(2)*h - c*(a*m + b*k))/c**S(3) + (b**S(2)*l + c**S(2)*g - c*(a*l + b*j))*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)) - (-b**S(3)*l + b*c*(S(3)*a*l + b*j) + S(2)*c**S(3)*e - c**S(2)*(S(2)*a*j + b*g))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(S(2)*a*b*m/c**S(2) - a*k/c - b**S(3)*m/c**S(3) + b**S(2)*k/c**S(2) - b*h/c + f - (b**S(4)*m - b**S(2)*c*(S(4)*a*m + b*k) + S(2)*c**S(4)*d - c**S(3)*(S(2)*a*h + b*f) + c**S(2)*(S(2)*a**S(2)*m + S(3)*a*b*k + b**S(2)*h))/(c**S(3)*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(S(2)*a*b*m/c**S(2) - a*k/c - b**S(3)*m/c**S(3) + b**S(2)*k/c**S(2) - b*h/c + f + (b**S(4)*m - b**S(2)*c*(S(4)*a*m + b*k) + S(2)*c**S(4)*d - c**S(3)*(S(2)*a*h + b*f) + c**S(2)*(S(2)*a**S(2)*m + S(3)*a*b*k + b**S(2)*h))/(c**S(3)*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, S(19)*d*atanh(x/S(2))/S(432) - d*atanh(x)/S(54) + e*log(-x**S(2) + S(1))/S(27) - e*log(-x**S(2) + S(4))/S(27) + x*(-S(5)*d*x**S(2) + S(17)*d - S(5)*e*x**S(3) + S(17)*e*x)/(S(72)*x**S(4) - S(360)*x**S(2) + S(288)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, e*log(-x**S(2) + S(1))/S(27) - e*log(-x**S(2) + S(4))/S(27) + x*(S(17)*d - S(5)*e*x**S(3) + S(17)*e*x + S(20)*f - x**S(2)*(S(5)*d + S(8)*f))/(S(72)*x**S(4) - S(360)*x**S(2) + S(288)) - (d/S(54) + S(7)*f/S(54))*atanh(x) + (S(19)*d/S(432) + S(13)*f/S(108))*atanh(x/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, x*(S(17)*d + S(20)*f - x**S(3)*(S(5)*e + S(8)*g) - x**S(2)*(S(5)*d + S(8)*f) + x*(S(17)*e + S(20)*g))/(S(72)*x**S(4) - S(360)*x**S(2) + S(288)) - (d/S(54) + S(7)*f/S(54))*atanh(x) + (S(19)*d/S(432) + S(13)*f/S(108))*atanh(x/S(2)) + (e/S(27) + S(5)*g/S(54))*log(-x**S(2) + S(1)) - (e/S(27) + S(5)*g/S(54))*log(-x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, x*(S(17)*d + S(20)*f + S(32)*h - x**S(3)*(S(5)*e + S(8)*g) - x**S(2)*(S(5)*d + S(8)*f + S(20)*h) + x*(S(17)*e + S(20)*g))/(S(72)*x**S(4) - S(360)*x**S(2) + S(288)) + (e/S(27) + S(5)*g/S(54))*log(-x**S(2) + S(1)) - (e/S(27) + S(5)*g/S(54))*log(-x**S(2) + S(4)) - (d/S(54) + S(7)*f/S(54) + S(13)*h/S(54))*atanh(x) + (S(19)*d/S(432) + S(13)*f/S(108) + S(7)*h/S(27))*atanh(x/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, x*(S(17)*d + S(20)*f + S(32)*h - x**S(3)*(S(5)*e + S(8)*g + S(20)*i) - x**S(2)*(S(5)*d + S(8)*f + S(20)*h) + x*(S(17)*e + S(20)*g + S(32)*i))/(S(72)*x**S(4) - S(360)*x**S(2) + S(288)) - (d/S(54) + S(7)*f/S(54) + S(13)*h/S(54))*atanh(x) + (S(19)*d/S(432) + S(13)*f/S(108) + S(7)*h/S(27))*atanh(x/S(2)) + (e/S(27) + S(5)*g/S(54) + S(4)*i/S(27))*log(-x**S(2) + S(1)) - (e/S(27) + S(5)*g/S(54) + S(4)*i/S(27))*log(-x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(x**S(4) + x**S(2) + S(1))**S(2), x), x, -d*log(x**S(2) - x + S(1))/S(4) + d*log(x**S(2) + x + S(1))/S(4) - sqrt(S(3))*d*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(9) + sqrt(S(3))*d*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(9) + S(2)*sqrt(S(3))*e*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9) + x*(-d*x**S(2) + d - e*x**S(3) + e*x)/(S(6)*x**S(4) + S(6)*x**S(2) + S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(x**S(4) + x**S(2) + S(1))**S(2), x), x, S(2)*sqrt(S(3))*e*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9) + x*(d - e*x**S(3) + e*x + f - x**S(2)*(d - S(2)*f))/(S(6)*x**S(4) + S(6)*x**S(2) + S(6)) - (d/S(4) - f/S(8))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(8))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(4)*d + f)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*(S(4)*d + f)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(36), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) + x**S(2) + S(1))**S(2), x), x, x*(d + f - x**S(3)*(e - S(2)*g) - x**S(2)*(d - S(2)*f) + x*(e + g))/(S(6)*x**S(4) + S(6)*x**S(2) + S(6)) - (d/S(4) - f/S(8))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(8))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(4)*d + f)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*(S(4)*d + f)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*(S(2)*e - g)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) + x**S(2) + S(1))**S(2), x), x, x*(d + f - S(2)*h - x**S(3)*(e - S(2)*g) - x**S(2)*(d - S(2)*f + h) + x*(e + g))/(S(6)*x**S(4) + S(6)*x**S(2) + S(6)) + sqrt(S(3))*(S(2)*e - g)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9) - (d/S(4) - f/S(8) + h/S(8))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(8) + h/S(8))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(4)*d + f + h)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*(S(4)*d + f + h)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(36), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) + x**S(2) + S(1))**S(2), x), x, x*(d + f - S(2)*h - x**S(3)*(e - S(2)*g + i) - x**S(2)*(d - S(2)*f + h) + x*(e + g - S(2)*i))/(S(6)*x**S(4) + S(6)*x**S(2) + S(6)) - (d/S(4) - f/S(8) + h/S(8))*log(x**S(2) - x + S(1)) + (d/S(4) - f/S(8) + h/S(8))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(4)*d + f + h)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*(S(4)*d + f + h)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(36) + sqrt(S(3))*(S(2)*e - g + S(2)*i)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*c*e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + sqrt(S(2))*sqrt(c)*d*(b - (-S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*d*(b + (-S(12)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + x*(b*c*d*x**S(2) + b*c*e*x**S(3) + d*(-S(2)*a*c + b**S(2)) + e*x*(-S(2)*a*c + b**S(2)))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*c*e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + sqrt(S(2))*sqrt(c)*(-S(2)*a*f + b*d - (S(4)*a*b*f - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(-S(2)*a*f + b*d + (S(4)*a*b*f - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + x*(-a*b*f - S(2)*a*c*d + b**S(2)*d + b*c*e*x**S(3) + c*x**S(2)*(-S(2)*a*f + b*d) + e*x*(-S(2)*a*c + b**S(2)))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, (-b*g + S(2)*c*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + sqrt(S(2))*sqrt(c)*(-S(2)*a*f + b*d - (S(4)*a*b*f - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(-S(2)*a*f + b*d + (S(4)*a*b*f - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + x*(-a*b*f - S(2)*a*c*d + b**S(2)*d + c*x**S(3)*(-S(2)*a*g + b*e) + c*x**S(2)*(-S(2)*a*f + b*d) + x*(-a*b*g - S(2)*a*c*e + b**S(2)*e))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, (-b*g + S(2)*c*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + x*(-a*b*f - S(2)*a*(-a*h + c*d) + b**S(2)*d + c*x**S(3)*(-S(2)*a*g + b*e) + x**S(2)*(a*b*h - S(2)*a*c*f + b*c*d) + x*(-a*b*g - S(2)*a*c*e + b**S(2)*e))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(-S(2)*a*c*(S(2)*a*h + S(6)*c*d - f*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*(-a*h + c*d) - b*(-S(4)*a*c*f + a*h*sqrt(-S(4)*a*c + b**S(2)) + c*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(-S(2)*a*c*(S(2)*a*h + S(6)*c*d + f*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*(-a*h + c*d) + b*(S(4)*a*c*f + a*h*sqrt(-S(4)*a*c + b**S(2)) + c*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, (S(2)*a*i - b*g + S(2)*c*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + x*(-a*b*f - S(2)*a*(-a*h + c*d) + b**S(2)*d + x**S(3)*(a*b*i - S(2)*a*c*g + b*c*e) + x**S(2)*(a*b*h - S(2)*a*c*f + b*c*d) + x*(-a*b*g - S(2)*a*(-a*i + c*e) + b**S(2)*e))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(-S(2)*a*c*(S(2)*a*h + S(6)*c*d - f*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*(-a*h + c*d) - b*(-S(4)*a*c*f + a*h*sqrt(-S(4)*a*c + b**S(2)) + c*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(-S(2)*a*c*(S(2)*a*h + S(6)*c*d + f*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*(-a*h + c*d) + b*(S(4)*a*c*f + a*h*sqrt(-S(4)*a*c + b**S(2)) + c*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + j*x**S(5) + k*x**S(6) + l*x**S(7) + m*x**S(8))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, l*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) + m*x/c**S(2) + (-S(6)*a*b*c*l + b**S(3)*l + S(4)*c**S(3)*e - c**S(2)*(-S(4)*a*j + S(2)*b*g))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) - x*(a*b*c*(a*k + c*f) + S(2)*a*c*(a**S(2)*m - a*c*h + c**S(2)*d) - b**S(2)*(a**S(2)*m + c**S(2)*d) - c*x**S(3)*(-a*b**S(2)*l - S(2)*a*c*(-a*l + c*g) + b*c*(a*j + c*e)) - c*x*(-a*b*(a*l + c*g) - S(2)*a*c*(-a*j + c*e) + b**S(2)*c*e) + x**S(2)*(-a*b**S(3)*m + a*b**S(2)*c*k + S(2)*a*c**S(2)*(-a*k + c*f) - b*c*(-S(3)*a**S(2)*m + a*c*h + c**S(2)*d)))/(S(2)*a*c**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(3)*a*b**S(4)*m - a*b**S(3)*(c*k - S(3)*m*sqrt(-S(4)*a*c + b**S(2))) - S(2)*a*c**S(2)*(-S(10)*a**S(2)*m + S(2)*a*c*h - S(3)*a*k*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c**S(2)*d - c*f*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*c*(-a*c*h - a*(S(19)*a*m + k*sqrt(-S(4)*a*c + b**S(2))) + c**S(2)*d) - b*c*(S(13)*a**S(2)*m*sqrt(-S(4)*a*c + b**S(2)) + a*c*(-S(8)*a*k + h*sqrt(-S(4)*a*c + b**S(2))) + c**S(2)*(-S(4)*a*f + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(S(3)*a*b**S(4)*m - a*b**S(3)*(c*k + S(3)*m*sqrt(-S(4)*a*c + b**S(2))) - S(2)*a*c**S(2)*(-S(10)*a**S(2)*m + S(2)*a*c*h + S(3)*a*k*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c**S(2)*d + c*f*sqrt(-S(4)*a*c + b**S(2))) + b**S(2)*c*(-a*c*h + a*(-S(19)*a*m + k*sqrt(-S(4)*a*c + b**S(2))) + c**S(2)*d) + b*c*(S(13)*a**S(2)*m*sqrt(-S(4)*a*c + b**S(2)) + a*c*(S(8)*a*k + h*sqrt(-S(4)*a*c + b**S(2))) + c**S(2)*(S(4)*a*f + d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(x**S(4) - S(5)*x**S(2) + S(4))**S(3), x), x, -S(313)*d*atanh(x/S(2))/S(20736) + S(13)*d*atanh(x)/S(648) - e*log(-x**S(2) + S(1))/S(81) + e*log(-x**S(2) + S(4))/S(81) - x*(-S(35)*d*x**S(2) + S(59)*d - S(50)*e*x**S(3) + S(122)*e*x)/(S(3456)*x**S(4) - S(17280)*x**S(2) + S(13824)) + x*(-S(5)*d*x**S(2) + S(17)*d - S(5)*e*x**S(3) + S(17)*e*x)/(S(144)*(x**S(4) - S(5)*x**S(2) + S(4))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(3), x), x, -e*log(-x**S(2) + S(1))/S(81) + e*log(-x**S(2) + S(4))/S(81) - x*(S(59)*d - S(50)*e*x**S(3) + S(122)*e*x + S(380)*f - x**S(2)*(S(35)*d + S(140)*f))/(S(3456)*x**S(4) - S(17280)*x**S(2) + S(13824)) + x*(S(17)*d - S(5)*e*x**S(3) + S(17)*e*x + S(20)*f - x**S(2)*(S(5)*d + S(8)*f))/(S(144)*(x**S(4) - S(5)*x**S(2) + S(4))**S(2)) + (S(13)*d/S(648) + S(25)*f/S(648))*atanh(x) - (S(313)*d + S(820)*f)*atanh(x/S(2))/S(20736), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) - S(5)*x**S(2) + S(4))**S(3), x), x, -x*(S(59)*d + S(380)*f - x**S(3)*(S(50)*e + S(152)*g) - x**S(2)*(S(35)*d + S(140)*f) + x*(S(122)*e + S(440)*g))/(S(3456)*x**S(4) - S(17280)*x**S(2) + S(13824)) + x*(S(17)*d + S(20)*f - x**S(3)*(S(5)*e + S(8)*g) - x**S(2)*(S(5)*d + S(8)*f) + x*(S(17)*e + S(20)*g))/(S(144)*(x**S(4) - S(5)*x**S(2) + S(4))**S(2)) + (S(13)*d/S(648) + S(25)*f/S(648))*atanh(x) - (S(313)*d + S(820)*f)*atanh(x/S(2))/S(20736) - (e/S(81) + S(5)*g/S(162))*log(-x**S(2) + S(1)) + (e/S(81) + S(5)*g/S(162))*log(-x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4))**S(3), x), x, -x*(S(59)*d + S(380)*f + S(848)*h - x**S(3)*(S(50)*e + S(152)*g) - x**S(2)*(S(35)*d + S(140)*f + S(320)*h) + x*(S(122)*e + S(440)*g))/(S(3456)*x**S(4) - S(17280)*x**S(2) + S(13824)) + x*(S(17)*d + S(20)*f + S(32)*h - x**S(3)*(S(5)*e + S(8)*g) - x**S(2)*(S(5)*d + S(8)*f + S(20)*h) + x*(S(17)*e + S(20)*g))/(S(144)*(x**S(4) - S(5)*x**S(2) + S(4))**S(2)) - (e/S(81) + S(5)*g/S(162))*log(-x**S(2) + S(1)) + (e/S(81) + S(5)*g/S(162))*log(-x**S(2) + S(4)) + (S(13)*d/S(648) + S(25)*f/S(648) + S(61)*h/S(648))*atanh(x) - (S(313)*d + S(820)*f + S(1936)*h)*atanh(x/S(2))/S(20736), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4))**S(3), x), x, -x*(S(59)*d + S(380)*f + S(848)*h - x**S(3)*(S(50)*e + S(152)*g + S(320)*i) - x**S(2)*(S(35)*d + S(140)*f + S(320)*h) + x*(S(122)*e + S(440)*g + S(896)*i))/(S(3456)*x**S(4) - S(17280)*x**S(2) + S(13824)) + x*(S(17)*d + S(20)*f + S(32)*h - x**S(3)*(S(5)*e + S(8)*g + S(20)*i) - x**S(2)*(S(5)*d + S(8)*f + S(20)*h) + x*(S(17)*e + S(20)*g + S(32)*i))/(S(144)*(x**S(4) - S(5)*x**S(2) + S(4))**S(2)) + (S(13)*d/S(648) + S(25)*f/S(648) + S(61)*h/S(648))*atanh(x) - (S(313)*d + S(820)*f + S(1936)*h)*atanh(x/S(2))/S(20736) - (e/S(81) + S(5)*g/S(162) + S(11)*i/S(162))*log(-x**S(2) + S(1)) + (e/S(81) + S(5)*g/S(162) + S(11)*i/S(162))*log(-x**S(2) + S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(x**S(4) + x**S(2) + S(1))**S(3), x), x, -S(9)*d*log(x**S(2) - x + S(1))/S(32) + S(9)*d*log(x**S(2) + x + S(1))/S(32) - S(13)*sqrt(S(3))*d*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(144) + S(13)*sqrt(S(3))*d*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(144) + S(2)*sqrt(S(3))*e*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9) + x*(-S(7)*d*x**S(2) + S(2)*d - S(6)*e*x**S(3) + S(2)*e*x)/(S(24)*x**S(4) + S(24)*x**S(2) + S(24)) + x*(-d*x**S(2) + d - e*x**S(3) + e*x)/(S(12)*(x**S(4) + x**S(2) + S(1))**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(x**S(4) + x**S(2) + S(1))**S(3), x), x, S(2)*sqrt(S(3))*e*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9) + x*(S(2)*d - S(6)*e*x**S(3) + S(2)*e*x + S(3)*f - x**S(2)*(S(7)*d - S(7)*f))/(S(24)*x**S(4) + S(24)*x**S(2) + S(24)) + x*(d - e*x**S(3) + e*x + f - x**S(2)*(d - S(2)*f))/(S(12)*(x**S(4) + x**S(2) + S(1))**S(2)) - (S(9)*d/S(32) - f/S(8))*log(x**S(2) - x + S(1)) + (S(9)*d/S(32) - f/S(8))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(13)*d + S(2)*f)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(144) + sqrt(S(3))*(S(13)*d + S(2)*f)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(144), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) + x**S(2) + S(1))**S(3), x), x, x*(S(2)*d + S(3)*f - x**S(3)*(S(6)*e - S(6)*g) - x**S(2)*(S(7)*d - S(7)*f) + x*(S(2)*e + S(2)*g))/(S(24)*x**S(4) + S(24)*x**S(2) + S(24)) + x*(d + f - x**S(3)*(e - S(2)*g) - x**S(2)*(d - S(2)*f) + x*(e + g))/(S(12)*(x**S(4) + x**S(2) + S(1))**S(2)) - (S(9)*d/S(32) - f/S(8))*log(x**S(2) - x + S(1)) + (S(9)*d/S(32) - f/S(8))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(13)*d + S(2)*f)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(144) + sqrt(S(3))*(S(13)*d + S(2)*f)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(144) + sqrt(S(3))*(S(2)*e - g)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) + x**S(2) + S(1))**S(3), x), x, x*(S(2)*d + S(3)*f - h - x**S(3)*(S(6)*e - S(6)*g) - x**S(2)*(S(7)*d - S(7)*f + S(4)*h) + x*(S(2)*e + S(2)*g))/(S(24)*x**S(4) + S(24)*x**S(2) + S(24)) + x*(d + f - S(2)*h - x**S(3)*(e - S(2)*g) - x**S(2)*(d - S(2)*f + h) + x*(e + g))/(S(12)*(x**S(4) + x**S(2) + S(1))**S(2)) + sqrt(S(3))*(S(2)*e - g)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9) - (S(9)*d/S(32) - f/S(8) + S(3)*h/S(32))*log(x**S(2) - x + S(1)) + (S(9)*d/S(32) - f/S(8) + S(3)*h/S(32))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(13)*d + S(2)*f + h)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(144) + sqrt(S(3))*(S(13)*d + S(2)*f + h)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(144), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) + x**S(2) + S(1))**S(3), x), x, x*(S(2)*d + S(3)*f - h - x**S(3)*(S(6)*e - S(6)*g + S(4)*i) - x**S(2)*(S(7)*d - S(7)*f + S(4)*h) + x*(S(2)*e + S(2)*g))/(S(24)*x**S(4) + S(24)*x**S(2) + S(24)) + x*(d + f - S(2)*h - x**S(3)*(e - S(2)*g + i) - x**S(2)*(d - S(2)*f + h) + x*(e + g - S(2)*i))/(S(12)*(x**S(4) + x**S(2) + S(1))**S(2)) - (S(9)*d/S(32) - f/S(8) + S(3)*h/S(32))*log(x**S(2) - x + S(1)) + (S(9)*d/S(32) - f/S(8) + S(3)*h/S(32))*log(x**S(2) + x + S(1)) - sqrt(S(3))*(S(13)*d + S(2)*f + h)*atan(sqrt(S(3))*(-S(2)*x + S(1))/S(3))/S(144) + sqrt(S(3))*(S(13)*d + S(2)*f + h)*atan(sqrt(S(3))*(S(2)*x + S(1))/S(3))/S(144) + sqrt(S(3))*(S(2)*e - g + i)*atan(sqrt(S(3))*(S(2)*x**S(2) + S(1))/S(3))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(6)*c**S(2)*e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + x*(b*c*d*x**S(2) + b*c*e*x**S(3) + d*(-S(2)*a*c + b**S(2)) + e*x*(-S(2)*a*c + b**S(2)))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - S(3)*sqrt(S(2))*sqrt(c)*d*(S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4) - b*(-S(8)*a*c + b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + S(3)*sqrt(S(2))*sqrt(c)*d*(S(56)*a**S(2)*c**S(2) - S(10)*a*b**S(2)*c + b**S(4) + b*(-S(8)*a*c + b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(3)*b*c*d*x**S(2)*(-S(8)*a*c + b**S(2)) + S(2)*b*c*e*x**S(3)*(-S(10)*a*c + b**S(2)) + d*(-S(7)*a*c + b**S(2))*(-S(4)*a*c + S(3)*b**S(2)) + e*x*(S(24)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(2)*b**S(4)))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(6)*c**S(2)*e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + x*(-a*b*f - S(2)*a*c*d + b**S(2)*d + b*c*e*x**S(3) + c*x**S(2)*(-S(2)*a*f + b*d) + e*x*(-S(2)*a*c + b**S(2)))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(42)*c*d - S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(S(30)*c*d + f*sqrt(-S(4)*a*c + b**S(2))) + S(4)*a*b*c*(-S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d - b**S(3)*(-a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(42)*c*d + S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(S(30)*c*d - f*sqrt(-S(4)*a*c + b**S(2))) - S(4)*a*b*c*(S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d + b**S(3)*(a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(8)*a**S(2)*b*c*f + S(28)*a**S(2)*c**S(2)*d + a*b**S(3)*f - S(25)*a*b**S(2)*c*d + S(3)*b**S(4)*d + S(2)*b*c*e*x**S(3)*(-S(10)*a*c + b**S(2)) + c*x**S(2)*(S(20)*a**S(2)*c*f + a*b**S(2)*f - S(24)*a*b*c*d + S(3)*b**S(3)*d) + e*x*(S(24)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(2)*b**S(4)))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(3)*c*(-b*g + S(2)*c*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + x*(-a*b*f - S(2)*a*c*d + b**S(2)*d + c*x**S(3)*(-S(2)*a*g + b*e) + c*x**S(2)*(-S(2)*a*f + b*d) + x*(-a*b*g - S(2)*a*c*e + b**S(2)*e))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(42)*c*d - S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(S(30)*c*d + f*sqrt(-S(4)*a*c + b**S(2))) + S(4)*a*b*c*(-S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d - b**S(3)*(-a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(42)*c*d + S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(S(30)*c*d - f*sqrt(-S(4)*a*c + b**S(2))) - S(4)*a*b*c*(S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d + b**S(3)*(a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(8)*a**S(2)*b*c*f + S(28)*a**S(2)*c**S(2)*d + a*b**S(3)*f - S(25)*a*b**S(2)*c*d + S(3)*b**S(4)*d + S(2)*c*x**S(3)*(S(8)*a**S(2)*c*g + a*b**S(2)*g - S(10)*a*b*c*e + b**S(3)*e) + c*x**S(2)*(S(20)*a**S(2)*c*f + a*b**S(2)*f - S(24)*a*b*c*d + S(3)*b**S(3)*d) + x*(S(4)*a**S(2)*b*c*g + S(24)*a**S(2)*c**S(2)*e + S(2)*a*b**S(3)*g - S(20)*a*b**S(2)*c*e + S(2)*b**S(4)*e))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -S(3)*c*(-b*g + S(2)*c*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + x*(-a*b*f - S(2)*a*(-a*h + c*d) + b**S(2)*d + c*x**S(3)*(-S(2)*a*g + b*e) + x**S(2)*(a*b*h - S(2)*a*c*f + b*c*d) + x*(-a*b*g - S(2)*a*c*e + b**S(2)*e))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(6)*a*h + S(42)*c*d - S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(-S(18)*a*h + S(30)*c*d + f*sqrt(-S(4)*a*c + b**S(2))) + S(4)*a*b*(-S(13)*a*c*f + S(3)*a*h*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d - b**S(3)*(-a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(6)*a*h + S(42)*c*d + S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(-S(18)*a*h + S(30)*c*d - f*sqrt(-S(4)*a*c + b**S(2))) - S(4)*a*b*(S(13)*a*c*f + S(3)*a*h*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d + b**S(3)*(a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(8)*a**S(2)*b*c*f + S(4)*a**S(2)*c*(a*h + S(7)*c*d) + a*b**S(3)*f - a*b**S(2)*(S(7)*a*h + S(25)*c*d) + S(3)*b**S(4)*d + S(2)*c*x**S(3)*(S(8)*a**S(2)*c*g + a*b**S(2)*g - S(10)*a*b*c*e + b**S(3)*e) + c*x**S(2)*(S(20)*a**S(2)*c*f + a*b**S(2)*f - S(12)*a*b*(a*h + S(2)*c*d) + S(3)*b**S(3)*d) + x*(S(4)*a**S(2)*b*c*g + S(24)*a**S(2)*c**S(2)*e + S(2)*a*b**S(3)*g - S(20)*a*b**S(2)*c*e + S(2)*b**S(4)*e))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -(S(2)*a*c*i + b**S(2)*i - S(3)*b*c*g + S(6)*c**S(2)*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + x*(-a*b*f - S(2)*a*(-a*h + c*d) + b**S(2)*d + x**S(3)*(a*b*i - S(2)*a*c*g + b*c*e) + x**S(2)*(a*b*h - S(2)*a*c*f + b*c*d) + x*(-a*b*g - S(2)*a*(-a*i + c*e) + b**S(2)*e))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(6)*a*h + S(42)*c*d - S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(-S(18)*a*h + S(30)*c*d + f*sqrt(-S(4)*a*c + b**S(2))) + S(4)*a*b*(-S(13)*a*c*f + S(3)*a*h*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d - b**S(3)*(-a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(6)*a*h + S(42)*c*d + S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(-S(18)*a*h + S(30)*c*d - f*sqrt(-S(4)*a*c + b**S(2))) - S(4)*a*b*(S(13)*a*c*f + S(3)*a*h*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d + b**S(3)*(a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(8)*a**S(2)*b*c*f + S(4)*a**S(2)*c*(a*h + S(7)*c*d) + a*b**S(3)*f - a*b**S(2)*(S(7)*a*h + S(25)*c*d) + S(3)*b**S(4)*d + S(2)*c*x**S(3)*(S(8)*a**S(2)*c*g + a*b**S(2)*g - S(2)*a*b*(S(3)*a*i + S(5)*c*e) + b**S(3)*e) + c*x**S(2)*(S(20)*a**S(2)*c*f + a*b**S(2)*f - S(12)*a*b*(a*h + S(2)*c*d) + S(3)*b**S(3)*d) + x*(S(4)*a**S(2)*b*c*g + S(8)*a**S(2)*c*(a*i + S(3)*c*e) + S(2)*a*b**S(3)*g - S(4)*a*b**S(2)*(S(2)*a*i + S(5)*c*e) + S(2)*b**S(4)*e))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + j*x**S(5) + k*x**S(6) + l*x**S(7) + m*x**S(8))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, -(-S(3)*a*b*l + S(2)*a*c*j + b**S(2)*j - S(3)*b*c*g + S(6)*c**S(2)*e)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) - x*(a*b*c*(a*k + c*f) + S(2)*a*c*(a**S(2)*m - a*c*h + c**S(2)*d) - b**S(2)*(a**S(2)*m + c**S(2)*d) - c*x**S(3)*(-a*b**S(2)*l - S(2)*a*c*(-a*l + c*g) + b*c*(a*j + c*e)) - c*x*(-a*b*(a*l + c*g) - S(2)*a*c*(-a*j + c*e) + b**S(2)*c*e) + x**S(2)*(-a*b**S(3)*m + a*b**S(2)*c*k + S(2)*a*c**S(2)*(-a*k + c*f) - b*c*(-S(3)*a**S(2)*m + a*c*h + c**S(2)*d)))/(S(4)*a*c**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + x*(S(4)*a**S(2)*b*c**S(2)*(a*k + S(2)*c*f) + S(4)*a**S(2)*c**S(2)*(-S(9)*a**S(2)*m + a*c*h + S(7)*c**S(2)*d) + a*b**S(3)*c*(S(2)*a*k + c*f) - a*b**S(2)*c*(-S(11)*a**S(2)*m + S(7)*a*c*h + S(25)*c**S(2)*d) + b**S(4)*(-S(2)*a**S(2)*m + S(3)*c**S(2)*d) + S(2)*c**S(2)*x**S(3)*(S(8)*a**S(2)*c*(a*l + c*g) + a*b**S(2)*(a*l + c*g) - S(2)*a*b*c*(S(3)*a*j + S(5)*c*e) + b**S(3)*c*e) + c*x**S(2)*(S(4)*a**S(2)*c**S(2)*(S(3)*a*k + S(5)*c*f) + a*b**S(2)*c*(S(3)*a*k + c*f) - S(4)*a*b*c*(S(4)*a**S(2)*m + S(3)*a*c*h + S(6)*c**S(2)*d) + b**S(3)*(a**S(2)*m + S(3)*c**S(2)*d)) + S(2)*c*x*(S(2)*a**S(2)*b*c*(a*l + c*g) + S(4)*a**S(2)*c**S(2)*(a*j + S(3)*c*e) + a*b**S(3)*(a*l + c*g) - S(2)*a*b**S(2)*c*(S(2)*a*j + S(5)*c*e) + b**S(4)*c*e))/(S(8)*a**S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(4)*a**S(2)*c**S(2)*(S(10)*a**S(2)*m + S(6)*a*c*h - S(3)*a*k*sqrt(-S(4)*a*c + b**S(2)) + S(42)*c**S(2)*d - S(5)*c*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*c*(S(3)*a*(-S(6)*a*m + k*sqrt(-S(4)*a*c + b**S(2))) + S(30)*c**S(2)*d + c*(-S(18)*a*h + f*sqrt(-S(4)*a*c + b**S(2)))) + S(4)*a*b*c*(S(4)*a**S(2)*m*sqrt(-S(4)*a*c + b**S(2)) + S(3)*a*c*(-S(3)*a*k + h*sqrt(-S(4)*a*c + b**S(2))) + c**S(2)*(-S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(4)*(-a**S(2)*m + S(3)*c**S(2)*d) - b**S(3)*(S(3)*a**S(2)*c*k + a**S(2)*m*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*(-a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(S(2))*(S(4)*a**S(2)*c**S(2)*(S(10)*a**S(2)*m + S(6)*a*c*h + S(3)*a*k*sqrt(-S(4)*a*c + b**S(2)) + S(42)*c**S(2)*d + S(5)*c*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*c*(-S(3)*a*(S(6)*a*m + k*sqrt(-S(4)*a*c + b**S(2))) + S(30)*c**S(2)*d - c*(S(18)*a*h + f*sqrt(-S(4)*a*c + b**S(2)))) - S(4)*a*b*c*(S(4)*a**S(2)*m*sqrt(-S(4)*a*c + b**S(2)) + S(3)*a*c*(S(3)*a*k + h*sqrt(-S(4)*a*c + b**S(2))) + c**S(2)*(S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2)))) + b**S(4)*(-a**S(2)*m + S(3)*c**S(2)*d) + b**S(3)*(-S(3)*a**S(2)*c*k + a**S(2)*m*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*(a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5) + j*x**S(6) + k*x**S(7))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, k*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) + (-S(6)*a*b*c*k + b**S(3)*k + S(4)*c**S(3)*e - c**S(2)*(-S(4)*a*i + S(2)*b*g))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x*(-a*b*(a*j + c*f) - S(2)*a*c*(-a*h + c*d) + b**S(2)*c*d + x**S(3)*(-a*b**S(2)*k - S(2)*a*c*(-a*k + c*g) + b*c*(a*i + c*e)) + x**S(2)*(-a*b**S(2)*j - S(2)*a*c*(-a*j + c*f) + b*c*(a*h + c*d)) + x*(-a*b*(a*k + c*g) - S(2)*a*c*(-a*i + c*e) + b**S(2)*c*e))/(S(2)*a*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(a*b**S(3)*j + S(2)*a*c*(S(2)*a*c*h - S(3)*a*j*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c**S(2)*d - c*f*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*(-a*c*h - a*j*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*d) + b*c*(-S(8)*a**S(2)*j - S(4)*a*c*f + a*h*sqrt(-S(4)*a*c + b**S(2)) + c*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*(a*b**S(3)*j + S(2)*a*c*(S(2)*a*c*h + S(3)*a*j*sqrt(-S(4)*a*c + b**S(2)) + S(6)*c**S(2)*d + c*f*sqrt(-S(4)*a*c + b**S(2))) - b**S(2)*(-a*c*h + a*j*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*d) - b*c*(S(8)*a**S(2)*j + S(4)*a*c*f + a*h*sqrt(-S(4)*a*c + b**S(2)) + c*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) # long time assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5) + j*x**S(8) + k*x**S(11))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, k*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)) - (-S(30)*a**S(2)*b*c**S(2)*k + S(10)*a*b**S(3)*c*k - b**S(5)*k + S(2)*b**S(2)*c**S(3)*i + S(12)*c**S(5)*e - c**S(4)*(-S(4)*a*i + S(6)*b*g))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*(-S(4)*a*c + b**S(2))**(S(5)/2)) - x*(c*x**S(2)*(-a*b**S(3)*j + S(2)*a*c**S(3)*f - b*c*(-S(3)*a**S(2)*j + a*c*h + c**S(2)*d)) + c*(a*b*c**S(2)*f + S(2)*a*c*(a**S(2)*j - a*c*h + c**S(2)*d) - b**S(2)*(a**S(2)*j + c**S(2)*d)) - x**S(3)*(-S(2)*a**S(3)*c**S(2)*k + S(4)*a**S(2)*b**S(2)*c*k - a*b**S(4)*k - S(2)*a*c**S(4)*g + b*c**S(3)*(a*i + c*e)) - x*(-a**S(2)*b**S(3)*k - S(2)*a*c**S(3)*(-a*i + c*e) + b**S(2)*c**S(3)*e - b*(-S(3)*a**S(3)*c*k + a*c**S(3)*g)))/(S(4)*a*c**S(3)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) + x*(c**S(2)*x**S(2)*(S(20)*a**S(2)*c**S(3)*f + a*b**S(2)*c**S(2)*f - S(4)*a*b*c*(S(4)*a**S(2)*j + S(3)*a*c*h + S(6)*c**S(2)*d) + b**S(3)*(a**S(2)*j + S(3)*c**S(2)*d)) + S(2)*c*x**S(3)*(-S(24)*a**S(4)*c**S(2)*k - S(3)*a**S(2)*b**S(4)*k + S(8)*a**S(2)*c**S(4)*g - S(2)*a*b*c**S(3)*(S(3)*a*i + S(5)*c*e) + b**S(3)*c**S(3)*e + b**S(2)*(S(21)*a**S(3)*c*k + a*c**S(3)*g)) + c*(S(8)*a**S(2)*b*c**S(3)*f + S(4)*a**S(2)*c**S(2)*(-S(9)*a**S(2)*j + a*c*h + S(7)*c**S(2)*d) + a*b**S(3)*c**S(2)*f - a*b**S(2)*c*(-S(11)*a**S(2)*j + S(7)*a*c*h + S(25)*c**S(2)*d) + b**S(4)*(-S(2)*a**S(2)*j + S(3)*c**S(2)*d)) + x*(S(2)*a**S(2)*b**S(5)*k + S(8)*a**S(2)*c**S(4)*(a*i + S(3)*c*e) - S(4)*a*b**S(2)*c**S(3)*(S(2)*a*i + S(5)*c*e) + S(2)*b**S(4)*c**S(3)*e + S(2)*b**S(3)*(-S(9)*a**S(3)*c*k + a*c**S(3)*g) + S(4)*b*(S(13)*a**S(4)*c**S(2)*k + a**S(2)*c**S(4)*g)))/(S(8)*a**S(2)*c**S(3)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(-S(4)*a**S(2)*c**S(2)*(S(10)*a**S(2)*j + S(6)*a*c*h + S(42)*c**S(2)*d - S(5)*c*f*sqrt(-S(4)*a*c + b**S(2))) + a*b**S(2)*c*(-S(18)*a**S(2)*j - S(18)*a*c*h + S(30)*c**S(2)*d + c*f*sqrt(-S(4)*a*c + b**S(2))) - S(4)*a*b*c*(S(4)*a**S(2)*j*sqrt(-S(4)*a*c + b**S(2)) + S(3)*a*c*h*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*(-S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2)))) - b**S(4)*(-a**S(2)*j + S(3)*c**S(2)*d) + b**S(3)*(a**S(2)*j*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*(-a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) - sqrt(S(2))*(-S(4)*a**S(2)*c**S(2)*(S(10)*a**S(2)*j + S(6)*a*c*h + S(42)*c**S(2)*d + S(5)*c*f*sqrt(-S(4)*a*c + b**S(2))) + a*b**S(2)*c*(-S(18)*a**S(2)*j - S(18)*a*c*h + S(30)*c**S(2)*d - c*f*sqrt(-S(4)*a*c + b**S(2))) + S(4)*a*b*c*(S(4)*a**S(2)*j*sqrt(-S(4)*a*c + b**S(2)) + S(3)*a*c*h*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*(S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2)))) - b**S(4)*(-a**S(2)*j + S(3)*c**S(2)*d) - b**S(3)*(a**S(2)*j*sqrt(-S(4)*a*c + b**S(2)) + c**S(2)*(a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2)))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(3)*(a*d + a*e*x + b*e*x**S(3) + c*e*x**S(5) + c*f*x**S(6) + x**S(4)*(b*f + c*d) + x**S(2)*(a*f + b*d)), x), x, a**S(4)*d*x + a**S(4)*e*x**S(2)/S(2) + a**S(3)*b*e*x**S(4) + a**S(3)*x**S(3)*(a*f + S(4)*b*d)/S(3) + a**S(2)*e*x**S(6)*(S(2)*a*c + S(3)*b**S(2))/S(3) + S(2)*a**S(2)*x**S(5)*(S(2)*a*b*f + S(2)*a*c*d + S(3)*b**S(2)*d)/S(5) + a*b*e*x**S(8)*(S(3)*a*c + b**S(2))/S(2) + S(2)*a*x**S(7)*(S(2)*a**S(2)*c*f + S(3)*a*b**S(2)*f + S(6)*a*b*c*d + S(2)*b**S(3)*d)/S(7) + b*c**S(3)*e*x**S(16)/S(4) + b*c*e*x**S(12)*(S(3)*a*c + b**S(2))/S(3) + c**S(4)*e*x**S(18)/S(18) + c**S(4)*f*x**S(19)/S(19) + c**S(3)*x**S(17)*(S(4)*b*f + c*d)/S(17) + c**S(2)*e*x**S(14)*(S(2)*a*c + S(3)*b**S(2))/S(7) + S(2)*c**S(2)*x**S(15)*(S(2)*a*c*f + S(3)*b**S(2)*f + S(2)*b*c*d)/S(15) + S(2)*c*x**S(13)*(S(6)*a*b*c*f + S(2)*a*c**S(2)*d + S(2)*b**S(3)*f + S(3)*b**S(2)*c*d)/S(13) + e*x**S(10)*(S(3)*a**S(2)*c**S(2)/S(5) + S(6)*a*b**S(2)*c/S(5) + b**S(4)/S(10)) + x**S(11)*(S(6)*a**S(2)*c**S(2)*f/S(11) + S(12)*a*b**S(2)*c*f/S(11) + S(12)*a*b*c**S(2)*d/S(11) + b**S(4)*f/S(11) + S(4)*b**S(3)*c*d/S(11)) + x**S(9)*(S(4)*a**S(2)*b*c*f/S(3) + S(2)*a**S(2)*c**S(2)*d/S(3) + S(4)*a*b**S(3)*f/S(9) + S(4)*a*b**S(2)*c*d/S(3) + b**S(4)*d/S(9)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))**S(2)*(a*d + a*e*x + b*e*x**S(3) + c*e*x**S(5) + c*f*x**S(6) + x**S(4)*(b*f + c*d) + x**S(2)*(a*f + b*d)), x), x, a**S(3)*d*x + a**S(3)*e*x**S(2)/S(2) + S(3)*a**S(2)*b*e*x**S(4)/S(4) + a**S(2)*x**S(3)*(a*f + S(3)*b*d)/S(3) + a*e*x**S(6)*(a*c + b**S(2))/S(2) + S(3)*a*x**S(5)*(a*b*f + a*c*d + b**S(2)*d)/S(5) + b*c**S(2)*e*x**S(12)/S(4) + b*e*x**S(8)*(S(6)*a*c + b**S(2))/S(8) + c**S(3)*e*x**S(14)/S(14) + c**S(3)*f*x**S(15)/S(15) + c**S(2)*x**S(13)*(S(3)*b*f + c*d)/S(13) + S(3)*c*e*x**S(10)*(a*c + b**S(2))/S(10) + S(3)*c*x**S(11)*(a*c*f + b**S(2)*f + b*c*d)/S(11) + x**S(9)*(S(2)*a*b*c*f/S(3) + a*c**S(2)*d/S(3) + b**S(3)*f/S(9) + b**S(2)*c*d/S(3)) + x**S(7)*(S(3)*a**S(2)*c*f/S(7) + S(3)*a*b**S(2)*f/S(7) + S(6)*a*b*c*d/S(7) + b**S(3)*d/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**S(2) + c*x**S(4))*(a*d + a*e*x + b*e*x**S(3) + c*e*x**S(5) + c*f*x**S(6) + x**S(4)*(b*f + c*d) + x**S(2)*(a*f + b*d)), x), x, a**S(2)*d*x + a**S(2)*e*x**S(2)/S(2) + a*b*e*x**S(4)/S(2) + a*x**S(3)*(a*f + S(2)*b*d)/S(3) + b*c*e*x**S(8)/S(4) + c**S(2)*e*x**S(10)/S(10) + c**S(2)*f*x**S(11)/S(11) + c*x**S(9)*(S(2)*b*f + c*d)/S(9) + e*x**S(6)*(a*c/S(3) + b**S(2)/S(6)) + x**S(7)*(S(2)*a*c*f/S(7) + b**S(2)*f/S(7) + S(2)*b*c*d/S(7)) + x**S(5)*(S(2)*a*b*f/S(5) + S(2)*a*c*d/S(5) + b**S(2)*d/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*d + a*e*x + b*e*x**S(3) + c*e*x**S(5) + c*f*x**S(6) + x**S(4)*(b*f + c*d) + x**S(2)*(a*f + b*d))/(a + b*x**S(2) + c*x**S(4)), x), x, d*x + e*x**S(2)/S(2) + f*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*d + a*e*x + b*e*x**S(3) + c*e*x**S(5) + c*f*x**S(6) + x**S(4)*(b*f + c*d) + x**S(2)*(a*f + b*d))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)) + sqrt(S(2))*(f - (-b*f + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(f + (-b*f + S(2)*c*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*d + a*e*x + b*e*x**S(3) + c*e*x**S(5) + c*f*x**S(6) + x**S(4)*(b*f + c*d) + x**S(2)*(a*f + b*d))/(a + b*x**S(2) + c*x**S(4))**S(3), x), x, S(2)*c*e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + sqrt(S(2))*sqrt(c)*(-S(2)*a*f + b*d - (S(4)*a*b*f - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(-S(2)*a*f + b*d + (S(4)*a*b*f - S(12)*a*c*d + b**S(2)*d)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + x*(-a*b*f - S(2)*a*c*d + b**S(2)*d + b*c*e*x**S(3) + c*x**S(2)*(-S(2)*a*f + b*d) + e*x*(-S(2)*a*c + b**S(2)))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*d + a*e*x + b*e*x**S(3) + c*e*x**S(5) + c*f*x**S(6) + x**S(4)*(b*f + c*d) + x**S(2)*(a*f + b*d))/(a + b*x**S(2) + c*x**S(4))**S(4), x), x, -S(6)*c**S(2)*e*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(5)/2) + x*(-a*b*f - S(2)*a*c*d + b**S(2)*d + b*c*e*x**S(3) + c*x**S(2)*(-S(2)*a*f + b*d) + e*x*(-S(2)*a*c + b**S(2)))/(S(4)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)) - sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(42)*c*d - S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(S(30)*c*d + f*sqrt(-S(4)*a*c + b**S(2))) + S(4)*a*b*c*(-S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d - b**S(3)*(-a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + sqrt(S(2))*sqrt(c)*(S(4)*a**S(2)*c*(S(42)*c*d + S(5)*f*sqrt(-S(4)*a*c + b**S(2))) - a*b**S(2)*(S(30)*c*d - f*sqrt(-S(4)*a*c + b**S(2))) - S(4)*a*b*c*(S(13)*a*f + S(6)*d*sqrt(-S(4)*a*c + b**S(2))) + S(3)*b**S(4)*d + b**S(3)*(a*f + S(3)*d*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(16)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(5)/2)) + x*(S(8)*a**S(2)*b*c*f + S(28)*a**S(2)*c**S(2)*d + a*b**S(3)*f - S(25)*a*b**S(2)*c*d + S(3)*b**S(4)*d + S(2)*b*c*e*x**S(3)*(-S(10)*a*c + b**S(2)) + c*x**S(2)*(S(20)*a**S(2)*c*f + a*b**S(2)*f - S(24)*a*b*c*d + S(3)*b**S(3)*d) + e*x*(S(24)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(2)*b**S(4)))/(S(8)*a**S(2)*(-S(4)*a*c + b**S(2))**S(2)*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, e*x + (d - S(2)*e)*log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))*(x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, f*(x + S(2))**S(2)/S(2) + x*(e - S(4)*f) + (d - S(2)*e + S(4)*f)*log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))*(x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, g*(x + S(2))**S(3)/S(3) + x*(e - S(4)*f + S(12)*g) + (f/S(2) - S(3)*g)*(x + S(2))**S(2) + (d - S(2)*e + S(4)*f - S(8)*g)*log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(2)*x**S(2) - x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, h*x**S(4)/S(4) + x**S(3)*(g/S(3) - S(2)*h/S(3)) + x**S(2)*(f/S(2) - g + S(2)*h) + x*(e - S(2)*f + S(4)*g - S(8)*h) + (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h)*log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(2)*x**S(2) - x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, i*x**S(5)/S(5) + x**S(4)*(h/S(4) - i/S(2)) + x**S(3)*(g/S(3) - S(2)*h/S(3) + S(4)*i/S(3)) + x**S(2)*(f/S(2) - g + S(2)*h - S(4)*i) + x*(e - S(2)*f + S(4)*g - S(8)*h + S(16)*i) + (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h - S(32)*i)*log(x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, -S(2)*atanh(S(2)*x + S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(x**S(2) - S(3)*x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, -(d - S(2)*e)*log(x + S(2)) + (d - e)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))*(x**S(2) - S(3)*x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, f*x - (d - S(2)*e + S(4)*f)*log(x + S(2)) + (d - e + f)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, g*x**S(2)/S(2) + x*(f - S(3)*g) - (d - S(2)*e + S(4)*f - S(8)*g)*log(x + S(2)) + (d - e + f - g)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, h*x**S(3)/S(3) + x**S(2)*(g/S(2) - S(3)*h/S(2)) + x*(f - S(3)*g + S(7)*h) - (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h)*log(x + S(2)) + (d - e + f - g + h)*log(x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, i*x**S(4)/S(4) + x**S(3)*(h/S(3) - i) + x**S(2)*(g/S(2) - S(3)*h/S(2) + S(7)*i/S(2)) + x*(f - S(3)*g + S(7)*h - S(15)*i) - (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h - S(32)*i)*log(x + S(2)) + (d - e + f - g + h - i)*log(x + S(1)), expand=True, _diff=True, _numerical=True) # wromg result (rule) assert rubi_test(rubi_integrate((x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, -log(-x + S(1))/S(2) + log(-x + S(2))/S(3) + log(x + S(1))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, (-d/S(2) - e/S(2))*log(-x + S(1)) + (d/S(6) - e/S(6))*log(x + S(1)) + (d/S(3) + S(2)*e/S(3))*log(-x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, (-d/S(2) - e/S(2) - f/S(2))*log(-x + S(1)) + (d/S(6) - e/S(6) + f/S(6))*log(x + S(1)) + (d/S(3) + S(2)*e/S(3) + S(4)*f/S(3))*log(-x + S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, g*x + (d/S(6) - e/S(6) + f/S(6) - g/S(6))*log(x + S(1)) + (d/S(3) + S(2)*e/S(3) + S(4)*f/S(3) + S(8)*g/S(3))*log(-x + S(2)) - (d/S(2) + e/S(2) + f/S(2) + g/S(2))*log(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, h*x**S(2)/S(2) + x*(g + S(2)*h) + (d/S(6) - e/S(6) + f/S(6) - g/S(6) + h/S(6))*log(x + S(1)) + (d/S(3) + S(2)*e/S(3) + S(4)*f/S(3) + S(8)*g/S(3) + S(16)*h/S(3))*log(-x + S(2)) - (d/S(2) + e/S(2) + f/S(2) + g/S(2) + h/S(2))*log(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4)), x), x, i*x**S(3)/S(3) + x**S(2)*(h/S(2) + i) + x*(g + S(2)*h + S(5)*i) + (d/S(6) - e/S(6) + f/S(6) - g/S(6) + h/S(6) - i/S(6))*log(x + S(1)) + (d/S(3) + S(2)*e/S(3) + S(4)*f/S(3) + S(8)*g/S(3) + S(16)*h/S(3) + S(32)*i/S(3))*log(-x + S(2)) - (d/S(2) + e/S(2) + f/S(2) + g/S(2) + h/S(2) + i/S(2))*log(-x + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, -log(-x + S(1))/S(18) + log(-x + S(2))/S(48) + log(x + S(1))/S(6) - S(19)*log(x + S(2))/S(144) + S(1)/(S(12)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(48) + e/S(24))*log(-x + S(2)) - (d/S(18) + e/S(18))*log(-x + S(1)) - (S(19)*d/S(144) - S(13)*e/S(72))*log(x + S(2)) + (d/S(6) - e/S(6))*log(x + S(1)) + (d - S(2)*e)/(S(12)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))*(x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(48) + e/S(24) + f/S(12))*log(-x + S(2)) - (d/S(18) + e/S(18) + f/S(18))*log(-x + S(1)) - (S(19)*d/S(144) - S(13)*e/S(72) + S(7)*f/S(36))*log(x + S(2)) + (d/S(6) - e/S(6) + f/S(6))*log(x + S(1)) + (d - S(2)*e + S(4)*f)/(S(12)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))*(x**S(3) - S(2)*x**S(2) - x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(48) + e/S(24) + f/S(12) + g/S(6))*log(-x + S(2)) - (d/S(18) + e/S(18) + f/S(18) + g/S(18))*log(-x + S(1)) - (S(19)*d/S(144) - S(13)*e/S(72) + S(7)*f/S(36) - g/S(18))*log(x + S(2)) + (d/S(6) - e/S(6) + f/S(6) - g/S(6))*log(x + S(1)) + (d - S(2)*e + S(4)*f - S(8)*g)/(S(12)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(2)*x**S(2) - x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(48) + e/S(24) + f/S(12) + g/S(6) + h/S(3))*log(-x + S(2)) - (d/S(18) + e/S(18) + f/S(18) + g/S(18) + h/S(18))*log(-x + S(1)) - (S(19)*d/S(144) - S(13)*e/S(72) + S(7)*f/S(36) - g/S(18) - S(5)*h/S(9))*log(x + S(2)) + (d/S(6) - e/S(6) + f/S(6) - g/S(6) + h/S(6))*log(x + S(1)) + (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h)/(S(12)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(3) - S(2)*x**S(2) - x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, i*x + (d/S(48) + e/S(24) + f/S(12) + g/S(6) + h/S(3) + S(2)*i/S(3))*log(-x + S(2)) - (d/S(18) + e/S(18) + f/S(18) + g/S(18) + h/S(18) + i/S(18))*log(-x + S(1)) - (S(19)*d/S(144) - S(13)*e/S(72) + S(7)*f/S(36) - g/S(18) - S(5)*h/S(9) + S(22)*i/S(9))*log(x + S(2)) + (d/S(6) - e/S(6) + f/S(6) - g/S(6) + h/S(6) - i/S(6))*log(x + S(1)) + (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h - S(32)*i)/(S(12)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, -(S(3)*x + S(5))/(S(12)*x**S(2) + S(36)*x + S(24)) - log(-x + S(1))/S(36) + log(-x + S(2))/S(144) - S(7)*log(x + S(1))/S(36) + S(31)*log(x + S(2))/S(144), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(x**S(2) - S(3)*x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) + e/S(72))*log(-x + S(2)) - (d/S(36) + e/S(36))*log(-x + S(1)) - (S(7)*d/S(36) - S(13)*e/S(36))*log(x + S(1)) + (S(31)*d/S(144) - S(25)*e/S(72))*log(x + S(2)) - (S(5)*d - S(6)*e + x*(S(3)*d - S(4)*e))/(S(12)*x**S(2) + S(36)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))*(x**S(2) - S(3)*x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) + e/S(72) + f/S(36))*log(-x + S(2)) - (d/S(36) + e/S(36) + f/S(36))*log(-x + S(1)) - (S(7)*d/S(36) - S(13)*e/S(36) + S(19)*f/S(36))*log(x + S(1)) + (S(31)*d/S(144) - S(25)*e/S(72) + S(19)*f/S(36))*log(x + S(2)) - (S(5)*d - S(6)*e + S(8)*f + x*(S(3)*d - S(4)*e + S(6)*f))/(S(12)*x**S(2) + S(36)*x + S(24)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) + e/S(72) + f/S(36) + g/S(18))*log(-x + S(2)) - (d/S(36) + e/S(36) + f/S(36) + g/S(36))*log(-x + S(1)) - (S(7)*d/S(36) - S(13)*e/S(36) + S(19)*f/S(36) - S(25)*g/S(36))*log(x + S(1)) + (S(31)*d/S(144) - S(25)*e/S(72) + S(19)*f/S(36) - S(13)*g/S(18))*log(x + S(2)) - (d - S(2)*e + S(4)*f - S(8)*g)/(S(12)*x + S(24)) - (d - e + f - g)/(S(6)*x + S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) + e/S(72) + f/S(36) + g/S(18) + h/S(9))*log(-x + S(2)) - (d/S(36) + e/S(36) + f/S(36) + g/S(36) + h/S(36))*log(-x + S(1)) - (S(7)*d/S(36) - S(13)*e/S(36) + S(19)*f/S(36) - S(25)*g/S(36) + S(31)*h/S(36))*log(x + S(1)) + (S(31)*d/S(144) - S(25)*e/S(72) + S(19)*f/S(36) - S(13)*g/S(18) + S(7)*h/S(9))*log(x + S(2)) - (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h)/(S(12)*x + S(24)) - (d - e + f - g + h)/(S(6)*x + S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x**S(2) - S(3)*x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) + e/S(72) + f/S(36) + g/S(18) + h/S(9) + S(2)*i/S(9))*log(-x + S(2)) - (d/S(36) + e/S(36) + f/S(36) + g/S(36) + h/S(36) + i/S(36))*log(-x + S(1)) - (S(7)*d/S(36) - S(13)*e/S(36) + S(19)*f/S(36) - S(25)*g/S(36) + S(31)*h/S(36) - S(37)*i/S(36))*log(x + S(1)) + (S(31)*d/S(144) - S(25)*e/S(72) + S(19)*f/S(36) - S(13)*g/S(18) + S(7)*h/S(9) - S(2)*i/S(9))*log(x + S(2)) - (d - S(2)*e + S(4)*f - S(8)*g + S(16)*h - S(32)*i)/(S(12)*x + S(24)) - (d - e + f - g + h - i)/(S(6)*x + S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, log(-x + S(1))/S(18) - S(35)*log(-x + S(2))/S(432) + log(x + S(1))/S(54) + log(x + S(2))/S(144) - S(1)/(S(36)*x + S(36)) + S(1)/(-S(12)*x + S(12)) + S(1)/(-S(36)*x + S(72)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)*(x + S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) - e/S(72))*log(x + S(2)) + (d/S(54) + e/S(108))*log(x + S(1)) + (d/S(18) + S(5)*e/S(36))*log(-x + S(1)) - (S(35)*d/S(432) + S(29)*e/S(216))*log(-x + S(2)) - (d - e)/(S(36)*x + S(36)) + (d + e)/(-S(12)*x + S(12)) + (d + S(2)*e)/(-S(36)*x + S(72)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) - e/S(72) + f/S(36))*log(x + S(2)) + (d/S(54) + e/S(108) - f/S(27))*log(x + S(1)) + (d/S(18) + S(5)*e/S(36) + S(2)*f/S(9))*log(-x + S(1)) - (S(35)*d/S(432) + S(29)*e/S(216) + S(23)*f/S(108))*log(-x + S(2)) - (d - e + f)/(S(36)*x + S(36)) + (d + e + f)/(-S(12)*x + S(12)) + (d + S(2)*e + S(4)*f)/(-S(36)*x + S(72)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) - e/S(72) + f/S(36) - g/S(18))*log(x + S(2)) + (d/S(54) + e/S(108) - f/S(27) + S(7)*g/S(108))*log(x + S(1)) + (d/S(18) + S(5)*e/S(36) + S(2)*f/S(9) + S(11)*g/S(36))*log(-x + S(1)) - (S(35)*d/S(432) + S(29)*e/S(216) + S(23)*f/S(108) + S(17)*g/S(54))*log(-x + S(2)) - (d - e + f - g)/(S(36)*x + S(36)) + (d + e + f + g)/(-S(12)*x + S(12)) + (d + S(2)*e + S(4)*f + S(8)*g)/(-S(36)*x + S(72)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) - e/S(72) + f/S(36) - g/S(18) + h/S(9))*log(x + S(2)) + (d/S(54) + e/S(108) - f/S(27) + S(7)*g/S(108) - S(5)*h/S(54))*log(x + S(1)) + (d/S(18) + S(5)*e/S(36) + S(2)*f/S(9) + S(11)*g/S(36) + S(7)*h/S(18))*log(-x + S(1)) - (S(35)*d/S(432) + S(29)*e/S(216) + S(23)*f/S(108) + S(17)*g/S(54) + S(11)*h/S(27))*log(-x + S(2)) - (d - e + f - g + h)/(S(36)*x + S(36)) + (d + e + f + g + h)/(-S(12)*x + S(12)) + (d + S(2)*e + S(4)*f + S(8)*g + S(16)*h)/(-S(36)*x + S(72)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((x + S(2))*(d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + i*x**S(5))/(x**S(4) - S(5)*x**S(2) + S(4))**S(2), x), x, (d/S(144) - e/S(72) + f/S(36) - g/S(18) + h/S(9) - S(2)*i/S(9))*log(x + S(2)) + (d/S(54) + e/S(108) - f/S(27) + S(7)*g/S(108) - S(5)*h/S(54) + S(13)*i/S(108))*log(x + S(1)) + (d/S(18) + S(5)*e/S(36) + S(2)*f/S(9) + S(11)*g/S(36) + S(7)*h/S(18) + S(17)*i/S(36))*log(-x + S(1)) - (S(35)*d/S(432) + S(29)*e/S(216) + S(23)*f/S(108) + S(17)*g/S(54) + S(11)*h/S(27) + S(10)*i/S(27))*log(-x + S(2)) - (d - e + f - g + h - i)/(S(36)*x + S(36)) + (d + e + f + g + h + i)/(-S(12)*x + S(12)) + (d + S(2)*e + S(4)*f + S(8)*g + S(16)*h + S(32)*i)/(-S(36)*x + S(72)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*g - c*g*x**S(4))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, g*x/sqrt(a + b*x**S(2) + c*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*g - c*g*x**S(4) + e*x)/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -(b*e + S(2)*c*e*x**S(2) - g*x*(-S(4)*a*c + b**S(2)))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*g - c*g*x**S(4) + f*x**S(3))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, (S(2)*a*f + b*f*x**S(2) + g*x*(-S(4)*a*c + b**S(2)))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*g - c*g*x**S(4) + e*x + f*x**S(3))/(a + b*x**S(2) + c*x**S(4))**(S(3)/2), x), x, -(-S(2)*a*f + b*e - g*x*(-S(4)*a*c + b**S(2)) + x**S(2)*(-b*f + S(2)*c*e))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) # large time assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3) + h*x**S(4) + j*x**S(5) + k*x**S(6) + l*x**S(7) + m*x**S(8))/(a + b*x**S(3) + c*x**S(6)), x), x, k*x/c + l*x**S(2)/(S(2)*c) + m*x**S(3)/(S(3)*c) + (-b*m + c*j)*log(a + b*x**S(3) + c*x**S(6))/(S(6)*c**S(2)) - (-S(2)*a*c*m + b**S(2)*m - b*c*j + S(2)*c**S(2)*f)*atanh((b + S(2)*c*x**S(3))/sqrt(-S(4)*a*c + b**S(2)))/(S(3)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))) + S(2)**(S(2)/3)*(-b*k/c + g - (-S(2)*a*c*k + b**S(2)*k - b*c*g + S(2)*c**S(2)*d)/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(-b*k/c + g - (-S(2)*a*c*k + b**S(2)*k - b*c*g + S(2)*c**S(2)*d)/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(-b*k/c + g - (-S(2)*a*c*k + b**S(2)*k - b*c*g + S(2)*c**S(2)*d)/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(1)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) + S(2)**(S(2)/3)*(-b*k/c + g + (b**S(2)*k + S(2)*c**S(2)*d - c*(S(2)*a*k + b*g))/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*(-b*k/c + g + (b**S(2)*k + S(2)*c**S(2)*d - c*(S(2)*a*k + b*g))/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(2)/3)*sqrt(S(3))*(-b*k/c + g + (b**S(2)*k + S(2)*c**S(2)*d - c*(S(2)*a*k + b*g))/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(1)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3)) - S(2)**(S(1)/3)*(-b*l/c + h - (-S(2)*a*c*l + b**S(2)*l - b*c*h + S(2)*c**S(2)*e)/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*(-b*l/c + h - (-S(2)*a*c*l + b**S(2)*l - b*c*h + S(2)*c**S(2)*e)/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b + sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*(-b*l/c + h - (-S(2)*a*c*l + b**S(2)*l - b*c*h + S(2)*c**S(2)*e)/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(2)/3)*(b + sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*(-b*l/c + h + (b**S(2)*l + S(2)*c**S(2)*e - c*(S(2)*a*l + b*h))/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(1)/3)*c**(S(1)/3)*x + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3))/(S(6)*c**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) + S(2)**(S(1)/3)*(-b*l/c + h + (b**S(2)*l + S(2)*c**S(2)*e - c*(S(2)*a*l + b*h))/(c*sqrt(-S(4)*a*c + b**S(2))))*log(S(2)**(S(2)/3)*c**(S(2)/3)*x**S(2) - S(2)**(S(1)/3)*c**(S(1)/3)*x*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + (b - sqrt(-S(4)*a*c + b**S(2)))**(S(2)/3))/(S(12)*c**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)) - S(2)**(S(1)/3)*sqrt(S(3))*(-b*l/c + h + (b**S(2)*l + S(2)*c**S(2)*e - c*(S(2)*a*l + b*h))/(c*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(3))*(-S(2)*S(2)**(S(1)/3)*c**(S(1)/3)*x/(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3) + S(1))/S(3))/(S(6)*c**(S(2)/3)*(b - sqrt(-S(4)*a*c + b**S(2)))**(S(1)/3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*d*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*d*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - c*e*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - c*e*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*d*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*d*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - c*e*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - c*e*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*f*x**S(3)*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(12)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*f*x**S(3)*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(12)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(a + b*x**n + c*x**(S(2)*n)), x), x, -S(2)*c*d*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*d*x*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - c*e*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) - c*e*x**S(2)*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*f*x**S(3)*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(12)*a*c + S(3)*b**S(2) + S(3)*b*sqrt(-S(4)*a*c + b**S(2))) - S(2)*c*f*x**S(3)*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(12)*a*c + S(3)*b**S(2) - S(3)*b*sqrt(-S(4)*a*c + b**S(2))) - c*g*x**S(4)*hyper((S(1), S(4)/n), ((n + S(4))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(-S(8)*a*c + S(2)*b**S(2) + S(2)*b*sqrt(-S(4)*a*c + b**S(2))) - c*g*x**S(4)*hyper((S(1), S(4)/n), ((n + S(4))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(-S(8)*a*c + S(2)*b**S(2) - S(2)*b*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**n + c*x**(S(2)*n))**(S(-2)), x), x, -c*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) + b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) - b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + x*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x)/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, S(2)*b*c**S(2)*e*x**(n + S(2))*(-n + S(2))*hyper((S(1), (n + S(2))/n), (S(2) + S(2)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(n + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)*b*c**S(2)*e*x**(n + S(2))*(-n + S(2))*hyper((S(1), (n + S(2))/n), (S(2) + S(2)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(n + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - c*d*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) + b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*d*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) - b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) - c*e*x**S(2)*(S(4)*a*c*(-n + S(1)) - b**S(2)*(-n + S(2)))*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*e*x**S(2)*(S(4)*a*c*(-n + S(1)) - b**S(2)*(-n + S(2)))*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + d*x*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + e*x**S(2)*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2))/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, S(2)*b*c**S(2)*e*x**(n + S(2))*(-n + S(2))*hyper((S(1), (n + S(2))/n), (S(2) + S(2)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(n + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)*b*c**S(2)*e*x**(n + S(2))*(-n + S(2))*hyper((S(1), (n + S(2))/n), (S(2) + S(2)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(n + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)*b*c**S(2)*f*x**(n + S(3))*(-n + S(3))*hyper((S(1), (n + S(3))/n), (S(2) + S(3)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(n + S(3))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)*b*c**S(2)*f*x**(n + S(3))*(-n + S(3))*hyper((S(1), (n + S(3))/n), (S(2) + S(3)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(n + S(3))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - c*d*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) + b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*d*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) - b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) - c*e*x**S(2)*(S(4)*a*c*(-n + S(1)) - b**S(2)*(-n + S(2)))*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*e*x**S(2)*(S(4)*a*c*(-n + S(1)) - b**S(2)*(-n + S(2)))*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) - S(2)*c*f*x**S(3)*(S(2)*a*c*(-S(2)*n + S(3)) - b**S(2)*(-n + S(3)))*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - S(2)*c*f*x**S(3)*(S(2)*a*c*(-S(2)*n + S(3)) - b**S(2)*(-n + S(3)))*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + d*x*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + e*x**S(2)*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + f*x**S(3)*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d + e*x + f*x**S(2) + g*x**S(3))/(a + b*x**n + c*x**(S(2)*n))**S(2), x), x, S(2)*b*c**S(2)*e*x**(n + S(2))*(-n + S(2))*hyper((S(1), (n + S(2))/n), (S(2) + S(2)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(n + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)*b*c**S(2)*e*x**(n + S(2))*(-n + S(2))*hyper((S(1), (n + S(2))/n), (S(2) + S(2)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(n + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)*b*c**S(2)*f*x**(n + S(3))*(-n + S(3))*hyper((S(1), (n + S(3))/n), (S(2) + S(3)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(n + S(3))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)*b*c**S(2)*f*x**(n + S(3))*(-n + S(3))*hyper((S(1), (n + S(3))/n), (S(2) + S(3)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(n + S(3))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + S(2)*b*c**S(2)*g*x**(n + S(4))*(-n + S(4))*hyper((S(1), (n + S(4))/n), (S(2) + S(4)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b + sqrt(-S(4)*a*c + b**S(2)))*(n + S(4))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - S(2)*b*c**S(2)*g*x**(n + S(4))*(-n + S(4))*hyper((S(1), (n + S(4))/n), (S(2) + S(4)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(b - sqrt(-S(4)*a*c + b**S(2)))*(n + S(4))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - c*d*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) + b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*d*x*(S(4)*a*c*(-S(2)*n + S(1)) - b**S(2)*(-n + S(1)) - b*(-n + S(1))*sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), S(1)/n), (S(1) + S(1)/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) - c*e*x**S(2)*(S(4)*a*c*(-n + S(1)) - b**S(2)*(-n + S(2)))*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*e*x**S(2)*(S(4)*a*c*(-n + S(1)) - b**S(2)*(-n + S(2)))*hyper((S(1), S(2)/n), ((n + S(2))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) - S(2)*c*f*x**S(3)*(S(2)*a*c*(-S(2)*n + S(3)) - b**S(2)*(-n + S(3)))*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - S(2)*c*f*x**S(3)*(S(2)*a*c*(-S(2)*n + S(3)) - b**S(2)*(-n + S(3)))*hyper((S(1), S(3)/n), ((n + S(3))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(3)*a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) - c*g*x**S(4)*(S(4)*a*c*(-n + S(2)) - b**S(2)*(-n + S(4)))*hyper((S(1), S(4)/n), ((n + S(4))/n,), -S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))) - c*g*x**S(4)*(S(4)*a*c*(-n + S(2)) - b**S(2)*(-n + S(4)))*hyper((S(1), S(4)/n), ((n + S(4))/n,), -S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*n*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))) + d*x*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + e*x**S(2)*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + f*x**S(3)*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))) + g*x**S(4)*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(-S(4)*a*c + b**S(2))*(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((-a*h*x**(n/S(2) + S(-1)) + c*f*x**(n + S(-1)) + c*g*x**(S(2)*n + S(-1)) + c*h*x**(S(5)*n/S(2) + S(-1)))/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, -(S(2)*c*x**n*(-b*g + S(2)*c*f) + S(2)*c*(-S(2)*a*g + b*f) + S(2)*h*x**(n/S(2))*(-S(4)*a*c + b**S(2)))/(n*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a + b*x**n + c*x**(S(2)*n))**p*(a + b*x**n*(n*p + n + S(1)) + c*x**(S(2)*n)*(S(2)*n*(p + S(1)) + S(1))), x), x, x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, A*a*x**(m + S(1))/(m + S(1)) + B*a*x**(m + S(2))/(m + S(2)) + B*b*x**(m + S(4))/(m + S(4)) + B*c*x**(m + S(6))/(m + S(6)) + C*c*x**(m + S(7))/(m + S(7)) + x**(m + S(3))*(A*b + C*a)/(m + S(3)) + x**(m + S(5))*(A*c + C*b)/(m + S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, A*a*x**S(4)/S(4) + B*a*x**S(5)/S(5) + B*b*x**S(7)/S(7) + B*c*x**S(9)/S(9) + C*c*x**S(10)/S(10) + x**S(8)*(A*c/S(8) + C*b/S(8)) + x**S(6)*(A*b/S(6) + C*a/S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, A*a*x**S(3)/S(3) + B*a*x**S(4)/S(4) + B*b*x**S(6)/S(6) + B*c*x**S(8)/S(8) + C*c*x**S(9)/S(9) + x**S(7)*(A*c/S(7) + C*b/S(7)) + x**S(5)*(A*b/S(5) + C*a/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, A*a*x**S(2)/S(2) + B*a*x**S(3)/S(3) + B*b*x**S(5)/S(5) + B*c*x**S(7)/S(7) + C*c*x**S(8)/S(8) + x**S(6)*(A*c/S(6) + C*b/S(6)) + x**S(4)*(A*b/S(4) + C*a/S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4)), x), x, A*a*x + B*a*x**S(2)/S(2) + B*b*x**S(4)/S(4) + B*c*x**S(6)/S(6) + C*c*x**S(7)/S(7) + x**S(5)*(A*c/S(5) + C*b/S(5)) + x**S(3)*(A*b/S(3) + C*a/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))/x, x), x, A*a*log(x) + B*a*x + B*b*x**S(3)/S(3) + B*c*x**S(5)/S(5) + C*c*x**S(6)/S(6) + x**S(4)*(A*c/S(4) + C*b/S(4)) + x**S(2)*(A*b/S(2) + C*a/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))/x**S(2), x), x, -A*a/x + B*a*log(x) + B*b*x**S(2)/S(2) + B*c*x**S(4)/S(4) + C*c*x**S(5)/S(5) + x**S(3)*(A*c/S(3) + C*b/S(3)) + x*(A*b + C*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))/x**S(3), x), x, -A*a/(S(2)*x**S(2)) - B*a/x + B*b*x + B*c*x**S(3)/S(3) + C*c*x**S(4)/S(4) + x**S(2)*(A*c/S(2) + C*b/S(2)) + (A*b + C*a)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))/x**S(4), x), x, -A*a/(S(3)*x**S(3)) - B*a/(S(2)*x**S(2)) + B*b*log(x) + B*c*x**S(2)/S(2) + C*c*x**S(3)/S(3) + x*(A*c + C*b) - (A*b + C*a)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))/x**S(5), x), x, -A*a/(S(4)*x**S(4)) - B*a/(S(3)*x**S(3)) - B*b/x + B*c*x + C*c*x**S(2)/S(2) + (A*c + C*b)*log(x) - (A*b + C*a)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))/x**S(6), x), x, -A*a/(S(5)*x**S(5)) - B*a/(S(4)*x**S(4)) - B*b/(S(2)*x**S(2)) + B*c*log(x) + C*c*x - (A*c + C*b)/x - (A*b + C*a)/(S(3)*x**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))/x**S(7), x), x, -A*a/(S(6)*x**S(6)) - B*a/(S(5)*x**S(5)) - B*b/(S(3)*x**S(3)) - B*c/x + C*c*log(x) - (A*c + C*b)/(S(2)*x**S(2)) - (A*b + C*a)/(S(4)*x**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, A*a**S(2)*x**(m + S(1))/(m + S(1)) + B*a**S(2)*x**(m + S(2))/(m + S(2)) + S(2)*B*a*b*x**(m + S(4))/(m + S(4)) + S(2)*B*b*c*x**(m + S(8))/(m + S(8)) + B*c**S(2)*x**(m + S(10))/(m + S(10)) + B*x**(m + S(6))*(S(2)*a*c + b**S(2))/(m + S(6)) + C*c**S(2)*x**(m + S(11))/(m + S(11)) + a*x**(m + S(3))*(S(2)*A*b + C*a)/(m + S(3)) + c*x**(m + S(9))*(A*c + S(2)*C*b)/(m + S(9)) + x**(m + S(5))*(A*(S(2)*a*c + b**S(2)) + S(2)*C*a*b)/(m + S(5)) + x**(m + S(7))*(S(2)*A*b*c + C*(S(2)*a*c + b**S(2)))/(m + S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, A*a**S(2)*x**S(4)/S(4) + B*a**S(2)*x**S(5)/S(5) + S(2)*B*a*b*x**S(7)/S(7) + S(2)*B*b*c*x**S(11)/S(11) + B*c**S(2)*x**S(13)/S(13) + B*x**S(9)*(S(2)*a*c + b**S(2))/S(9) + C*c**S(2)*x**S(14)/S(14) + a*x**S(6)*(S(2)*A*b + C*a)/S(6) + c*x**S(12)*(A*c + S(2)*C*b)/S(12) + x**S(10)*(A*b*c/S(5) + C*(S(2)*a*c + b**S(2))/S(10)) + x**S(8)*(A*(S(2)*a*c + b**S(2))/S(8) + C*a*b/S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, A*a**S(2)*x**S(3)/S(3) + B*a**S(2)*x**S(4)/S(4) + B*a*b*x**S(6)/S(3) + B*b*c*x**S(10)/S(5) + B*c**S(2)*x**S(12)/S(12) + B*x**S(8)*(S(2)*a*c + b**S(2))/S(8) + C*c**S(2)*x**S(13)/S(13) + a*x**S(5)*(S(2)*A*b + C*a)/S(5) + c*x**S(11)*(A*c + S(2)*C*b)/S(11) + x**S(9)*(S(2)*A*b*c/S(9) + C*(S(2)*a*c + b**S(2))/S(9)) + x**S(7)*(A*(S(2)*a*c + b**S(2))/S(7) + S(2)*C*a*b/S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, A*a**S(2)*x**S(2)/S(2) + B*a**S(2)*x**S(3)/S(3) + S(2)*B*a*b*x**S(5)/S(5) + S(2)*B*b*c*x**S(9)/S(9) + B*c**S(2)*x**S(11)/S(11) + B*x**S(7)*(S(2)*a*c + b**S(2))/S(7) + C*c**S(2)*x**S(12)/S(12) + a*x**S(4)*(S(2)*A*b + C*a)/S(4) + c*x**S(10)*(A*c + S(2)*C*b)/S(10) + x**S(8)*(A*b*c/S(4) + C*(S(2)*a*c + b**S(2))/S(8)) + x**S(6)*(A*(S(2)*a*c + b**S(2))/S(6) + C*a*b/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2), x), x, A*a**S(2)*x + B*a**S(2)*x**S(2)/S(2) + B*a*b*x**S(4)/S(2) + B*b*c*x**S(8)/S(4) + B*c**S(2)*x**S(10)/S(10) + B*x**S(6)*(S(2)*a*c + b**S(2))/S(6) + C*c**S(2)*x**S(11)/S(11) + a*x**S(3)*(S(2)*A*b + C*a)/S(3) + c*x**S(9)*(A*c + S(2)*C*b)/S(9) + x**S(7)*(S(2)*A*b*c/S(7) + C*(S(2)*a*c + b**S(2))/S(7)) + x**S(5)*(A*(S(2)*a*c + b**S(2))/S(5) + S(2)*C*a*b/S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)/x, x), x, A*a**S(2)*log(x) + B*a**S(2)*x + S(2)*B*a*b*x**S(3)/S(3) + S(2)*B*b*c*x**S(7)/S(7) + B*c**S(2)*x**S(9)/S(9) + B*x**S(5)*(S(2)*a*c + b**S(2))/S(5) + C*c**S(2)*x**S(10)/S(10) + a*x**S(2)*(S(2)*A*b + C*a)/S(2) + c*x**S(8)*(A*c + S(2)*C*b)/S(8) + x**S(6)*(A*b*c/S(3) + C*(S(2)*a*c + b**S(2))/S(6)) + x**S(4)*(A*(S(2)*a*c + b**S(2))/S(4) + C*a*b/S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)/x**S(2), x), x, -A*a**S(2)/x + B*a**S(2)*log(x) + B*a*b*x**S(2) + B*b*c*x**S(6)/S(3) + B*c**S(2)*x**S(8)/S(8) + B*x**S(4)*(S(2)*a*c + b**S(2))/S(4) + C*c**S(2)*x**S(9)/S(9) + a*x*(S(2)*A*b + C*a) + c*x**S(7)*(A*c + S(2)*C*b)/S(7) + x**S(5)*(S(2)*A*b*c/S(5) + C*(S(2)*a*c + b**S(2))/S(5)) + x**S(3)*(A*(S(2)*a*c + b**S(2))/S(3) + S(2)*C*a*b/S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)/x**S(3), x), x, -A*a**S(2)/(S(2)*x**S(2)) - B*a**S(2)/x + S(2)*B*a*b*x + S(2)*B*b*c*x**S(5)/S(5) + B*c**S(2)*x**S(7)/S(7) + B*x**S(3)*(S(2)*a*c + b**S(2))/S(3) + C*c**S(2)*x**S(8)/S(8) + a*(S(2)*A*b + C*a)*log(x) + c*x**S(6)*(A*c + S(2)*C*b)/S(6) + x**S(4)*(A*b*c/S(2) + C*(S(2)*a*c + b**S(2))/S(4)) + x**S(2)*(A*(S(2)*a*c + b**S(2))/S(2) + C*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)/x**S(4), x), x, -A*a**S(2)/(S(3)*x**S(3)) - B*a**S(2)/(S(2)*x**S(2)) + S(2)*B*a*b*log(x) + B*b*c*x**S(4)/S(2) + B*c**S(2)*x**S(6)/S(6) + B*x**S(2)*(S(2)*a*c + b**S(2))/S(2) + C*c**S(2)*x**S(7)/S(7) - a*(S(2)*A*b + C*a)/x + c*x**S(5)*(A*c + S(2)*C*b)/S(5) + x**S(3)*(S(2)*A*b*c/S(3) + C*(S(2)*a*c + b**S(2))/S(3)) + x*(A*(S(2)*a*c + b**S(2)) + S(2)*C*a*b), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)/x**S(5), x), x, -A*a**S(2)/(S(4)*x**S(4)) - B*a**S(2)/(S(3)*x**S(3)) - S(2)*B*a*b/x + S(2)*B*b*c*x**S(3)/S(3) + B*c**S(2)*x**S(5)/S(5) + B*x*(S(2)*a*c + b**S(2)) + C*c**S(2)*x**S(6)/S(6) - a*(S(2)*A*b + C*a)/(S(2)*x**S(2)) + c*x**S(4)*(A*c + S(2)*C*b)/S(4) + x**S(2)*(A*b*c + C*(S(2)*a*c + b**S(2))/S(2)) + (A*(S(2)*a*c + b**S(2)) + S(2)*C*a*b)*log(x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)/x**S(6), x), x, -A*a**S(2)/(S(5)*x**S(5)) - B*a**S(2)/(S(4)*x**S(4)) - B*a*b/x**S(2) + B*b*c*x**S(2) + B*c**S(2)*x**S(4)/S(4) + B*(S(2)*a*c + b**S(2))*log(x) + C*c**S(2)*x**S(5)/S(5) - a*(S(2)*A*b + C*a)/(S(3)*x**S(3)) + c*x**S(3)*(A*c + S(2)*C*b)/S(3) + x*(S(2)*A*b*c + C*(S(2)*a*c + b**S(2))) - (A*(S(2)*a*c + b**S(2)) + S(2)*C*a*b)/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))*(a + b*x**S(2) + c*x**S(4))**S(2)/x**S(7), x), x, -A*a**S(2)/(S(6)*x**S(6)) - B*a**S(2)/(S(5)*x**S(5)) - S(2)*B*a*b/(S(3)*x**S(3)) + S(2)*B*b*c*x + B*c**S(2)*x**S(3)/S(3) - B*(S(2)*a*c + b**S(2))/x + C*c**S(2)*x**S(4)/S(4) - a*(S(2)*A*b + C*a)/(S(4)*x**S(4)) + c*x**S(2)*(A*c + S(2)*C*b)/S(2) + (S(2)*A*b*c + C*(S(2)*a*c + b**S(2)))*log(x) - (A*(S(2)*a*c + b**S(2)) + S(2)*C*a*b)/(S(2)*x**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -S(2)*B*c*x**(m + S(2))*hyper((S(1), m/S(2) + S(1)), (m/S(2) + S(2),), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/((b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(2))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*B*c*x**(m + S(2))*hyper((S(1), m/S(2) + S(1)), (m/S(2) + S(2),), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/((b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(2))*sqrt(-S(4)*a*c + b**S(2))) + x**(m + S(1))*(C - (S(2)*A*c - C*b)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/((b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))) + x**(m + S(1))*(C + (S(2)*A*c - C*b)/sqrt(-S(4)*a*c + b**S(2)))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/((b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -B*b*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) + B*x**S(2)/(S(2)*c) - B*(-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))) + C*x**S(3)/(S(3)*c) + x*(A*c - C*b)/c**S(2) - sqrt(S(2))*(A*b*c + C*a*c - C*b**S(2) + (A*c*(-S(2)*a*c + b**S(2)) - C*b*(-S(3)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(A*b*c + C*a*c - C*b**S(2) - (A*c*(-S(2)*a*c + b**S(2)) - C*b*(-S(3)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, B*x/c - sqrt(S(2))*B*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*B*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + C*x**S(2)/(S(2)*c) + (A*c - C*b)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) + (A*b*c + S(2)*C*a*c - C*b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) + B*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c) + C*x/c + sqrt(S(2))*(A*c - C*b + (A*b*c + S(2)*C*a*c - C*b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(A*c - C*b - (A*b*c - C*(-S(2)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -sqrt(S(2))*B*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*B*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) + C*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c) - (S(2)*A*c - C*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x, -B*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)) + sqrt(S(2))*(C - (S(2)*A*c - C*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(C + (S(2)*A*c - C*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(x*(a + b*x**S(2) + c*x**S(4))), x), x, A*log(x)/a - A*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a) - sqrt(S(2))*B*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*B*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + (A*b - S(2)*C*a)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))), x), x, -A/(a*x) + B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))) + B*log(x)/a - B*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a) - sqrt(S(2))*sqrt(c)*(A - (A*b - S(2)*C*a)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(A + (A*b - S(2)*C*a)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(x**S(3)*(a + b*x**S(2) + c*x**S(4))), x), x, -A/(S(2)*a*x**S(2)) - sqrt(S(2))*B*sqrt(c)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*B*sqrt(c)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - B/(a*x) - (A*b - C*a)*log(x)/a**S(2) + (A*b - C*a)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) - (A*(-S(2)*a*c + b**S(2)) - C*a*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, B*c*x**(m + S(2))*(S(4)*a*c*(-m + S(2)) + b*m*(b - sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), m/S(2) + S(1)), (m/S(2) + S(2),), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - B*c*x**(m + S(2))*(S(4)*a*c*(-m + S(2)) + b*m*(b + sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), m/S(2) + S(1)), (m/S(2) + S(2),), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(2))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + B*x**(m + S(2))*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - c*x**(m + S(1))*(A*(-S(4)*a*c*(-m + S(3)) + b**S(2)*(-m + S(1)) - b*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*C*a*(S(2)*b + (-m + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*(b + sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + c*x**(m + S(1))*(A*(-S(4)*a*c*(-m + S(3)) + b**S(2)*(-m + S(1)) + b*(-m + S(1))*sqrt(-S(4)*a*c + b**S(2))) + S(2)*C*a*(S(2)*b - (-m + S(1))*sqrt(-S(4)*a*c + b**S(2))))*hyper((S(1), m/S(2) + S(1)/2), (m/S(2) + S(3)/2,), -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*(b - sqrt(-S(4)*a*c + b**S(2)))*(m + S(1))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x**(m + S(1))*(A*(-S(2)*a*c + b**S(2)) - C*a*b + c*x**S(2)*(A*b - S(2)*C*a))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*B*a*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + x*(S(2)*B*a*c*x + B*b*c*x**S(3) + a*(S(2)*A*c - C*b) + x**S(2)*(A*b*c + S(2)*C*a*c - C*b**S(2)))/(S(2)*c*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(A*c*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))) + C*(-S(8)*a*b*c - S(6)*a*c*sqrt(-S(4)*a*c + b**S(2)) + b**S(3) + b**S(2)*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*(A*c*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))) + C*(-S(8)*a*b*c + S(6)*a*c*sqrt(-S(4)*a*c + b**S(2)) + b**S(3) - b**S(2)*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, sqrt(S(2))*B*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*B*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x*(S(2)*B*a + B*b*x**S(2) - x**S(3)*(S(2)*A*c - C*b) - x*(A*b - S(2)*C*a))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (A*b - S(2)*C*a)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - x*(A*b + B*b*x + S(2)*B*c*x**S(3) - S(2)*C*a + x**S(2)*(S(2)*A*c - C*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(2)*A*c*(S(2)*b + sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(S(2)*A*c*(S(2)*b - sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -sqrt(S(2))*B*sqrt(c)*(S(2)*b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*B*sqrt(c)*(S(2)*b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (S(2)*A*c - C*b)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - x*(B*a*b + S(2)*B*a*c*x**S(2) - c*x**S(3)*(A*b - S(2)*C*a) - x*(A*(-S(2)*a*c + b**S(2)) - C*a*b))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, S(2)*B*c*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + sqrt(S(2))*sqrt(c)*(A*b - S(2)*C*a - (-S(12)*A*a*c + A*b**S(2) + S(4)*C*a*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*(A*b - S(2)*C*a + (A*(-S(12)*a*c + b**S(2)) + S(4)*C*a*b)/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + x*(A*(-S(2)*a*c + b**S(2)) + B*b*c*x**S(3) + B*x*(-S(2)*a*c + b**S(2)) - C*a*b + c*x**S(2)*(A*b - S(2)*C*a))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(x*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, A*log(x)/a**S(2) - A*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) - sqrt(S(2))*B*sqrt(c)*(-S(12)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*B*sqrt(c)*(-S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + B*x*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + (A*(-S(2)*a*c + b**S(2)) - C*a*b + c*x**S(2)*(A*b - S(2)*C*a))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + (A*(-S(6)*a*b*c + b**S(3)) + S(4)*C*a**S(2)*c)*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, B*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + B*b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + B*log(x)/a**S(2) - B*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) + (A*(-S(2)*a*c + b**S(2)) - C*a*b + c*x**S(2)*(A*b - S(2)*C*a))/(S(2)*a*x*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*sqrt(c)*(-S(10)*A*a*c + S(3)*A*b**S(2) - C*a*b - (A*(-S(16)*a*b*c + S(3)*b**S(3)) - C*a*(-S(12)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*sqrt(c)*(A*(-S(16)*a*b*c - S(10)*a*c*sqrt(-S(4)*a*c + b**S(2)) + S(3)*b**S(3) + S(3)*b**S(2)*sqrt(-S(4)*a*c + b**S(2))) - C*a*(-S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-S(10)*A*a*c + S(3)*A*b**S(2) - C*a*b)/(S(2)*a**S(2)*x*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A + B*x + C*x**S(2))/(x**S(3)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, B*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*x*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*B*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) - (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*B*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) + (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - B*(-S(10)*a*c + S(3)*b**S(2))/(S(2)*a**S(2)*x*(-S(4)*a*c + b**S(2))) + (A*(-S(2)*a*c + b**S(2)) - C*a*b + c*x**S(2)*(A*b - S(2)*C*a))/(S(2)*a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (-S(6)*A*a*c + S(2)*A*b**S(2) - C*a*b)/(S(2)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) - (S(2)*A*b - C*a)*log(x)/a**S(3) + (S(2)*A*b - C*a)*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(3)) - (S(2)*A*(S(6)*a**S(2)*c**S(2) - S(6)*a*b**S(2)*c + b**S(4)) - C*a*b*(-S(6)*a*c + b**S(2)))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(A + B*x + C*x**S(2))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - x*(A*b + B*b*x + S(2)*B*c*x**S(3) - S(2)*C*a + x**S(2)*(S(2)*A*c - C*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(2)*A*c*(S(2)*b + sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(S(2)*A*c*(S(2)*b - sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(A*x + B*x**S(2) + C*x**S(3))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - x*(A*b + B*b*x + S(2)*B*c*x**S(3) - S(2)*C*a + x**S(2)*(S(2)*A*c - C*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(2)*A*c*(S(2)*b + sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(S(2)*A*c*(S(2)*b - sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A*x**S(2) + B*x**S(3) + C*x**S(4))/(a + b*x**S(2) + c*x**S(4))**S(2), x), x, -B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - x*(A*b + B*b*x + S(2)*B*c*x**S(3) - S(2)*C*a + x**S(2)*(S(2)*A*c - C*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(2)*A*c*(S(2)*b + sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(S(2)*A*c*(S(2)*b - sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A*x**S(3) + B*x**S(4) + C*x**S(5))/(x*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - x*(A*b + B*b*x + S(2)*B*c*x**S(3) - S(2)*C*a + x**S(2)*(S(2)*A*c - C*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(2)*A*c*(S(2)*b + sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(S(2)*A*c*(S(2)*b - sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((A*x**S(4) + B*x**S(5) + C*x**S(6))/(x**S(2)*(a + b*x**S(2) + c*x**S(4))**S(2)), x), x, -B*b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - x*(A*b + B*b*x + S(2)*B*c*x**S(3) - S(2)*C*a + x**S(2)*(S(2)*A*c - C*b))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) - sqrt(S(2))*(S(2)*A*c*(S(2)*b + sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*(S(2)*A*c*(S(2)*b - sqrt(-S(4)*a*c + b**S(2))) - C*(S(4)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2))))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(2) + f*x**S(4) + g*x**S(6))/(a + b*x**S(2) + c*x**S(4)), x), x, g*x**S(4)/(S(4)*c) + x**S(2)*(-b*g + c*f)/(S(2)*c**S(2)) + (b**S(2)*g + c**S(2)*e - c*(a*g + b*f))*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)) - (-b**S(3)*g + b*c*(S(3)*a*g + b*f) + S(2)*c**S(3)*d - c**S(2)*(S(2)*a*f + b*e))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a + b*x**S(2) + c*x**S(4))**p*(S(3)*a + b*x**S(2)*(S(2)*p + S(5)) + c*x**S(4)*(S(4)*p + S(7))), x), x, x**S(3)*(a + b*x**S(2) + c*x**S(4))**(p + S(1)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(4) + S(-1))*(-a*h + c*f*x**(n/S(4)) + c*g*x**(S(3)*n/S(4)) + c*h*x**n)/(a + c*x**n)**(S(3)/2), x), x, -(S(2)*a*g + S(4)*a*h*x**(n/S(4)) - S(2)*c*f*x**(n/S(2)))/(a*n*sqrt(a + c*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(n/S(4) + S(-1))*(-a*h + c*f*x**(n/S(4)) + c*g*x**(S(3)*n/S(4)) + c*h*x**n)/(a + c*x**n)**(S(3)/2), x), x, -S(2)*x**(-n/S(4) + S(1))*(d*x)**(n/S(4) + S(-1))*(a*g + S(2)*a*h*x**(n/S(4)) - c*f*x**(n/S(2)))/(a*n*sqrt(a + c*x**n)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(n/S(2) + S(-1))*(-a*h + c*f*x**(n/S(2)) + c*g*x**(S(3)*n/S(2)) + c*h*x**(S(2)*n))/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, -(S(2)*c*x**n*(-b*g + S(2)*c*f) + S(2)*c*(-S(2)*a*g + b*f) + S(2)*h*x**(n/S(2))*(-S(4)*a*c + b**S(2)))/(n*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((d*x)**(n/S(2) + S(-1))*(-a*h + c*f*x**(n/S(2)) + c*g*x**(S(3)*n/S(2)) + c*h*x**(S(2)*n))/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x, -S(2)*x**(-n/S(2) + S(1))*(d*x)**(n/S(2) + S(-1))*(c*x**n*(-b*g + S(2)*c*f) + c*(-S(2)*a*g + b*f) + h*x**(n/S(2))*(-S(4)*a*c + b**S(2)))/(n*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**n + c*x**(S(2)*n))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((g*x)**m*(a + b*x**n + c*x**(S(2)*n))**p*(a*(m + S(1)) + b*x**n*(m + n*p + n + S(1)) + c*x**(S(2)*n)*(m + S(2)*n*(p + S(1)) + S(1))), x), x, (g*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/g, expand=True, _diff=True, _numerical=True) def test_5(): assert rubi_test(rubi_integrate(x**S(2)*(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, a*x**S(5)/S(5) + b*x**S(6)/S(6) + c*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, a*x**S(4)/S(4) + b*x**S(5)/S(5) + c*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a*x**S(2) + b*x**S(3) + c*x**S(4), x), x, a*x**S(3)/S(3) + b*x**S(4)/S(4) + c*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))/x, x), x, a*x**S(2)/S(2) + b*x**S(3)/S(3) + c*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))/x**S(2), x), x, a*x + b*x**S(2)/S(2) + c*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, a**S(2)*x**S(7)/S(7) + a*b*x**S(8)/S(4) + b*c*x**S(10)/S(5) + c**S(2)*x**S(11)/S(11) + x**S(9)*(S(2)*a*c + b**S(2))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, a**S(2)*x**S(6)/S(6) + S(2)*a*b*x**S(7)/S(7) + S(2)*b*c*x**S(9)/S(9) + c**S(2)*x**S(10)/S(10) + x**S(8)*(S(2)*a*c + b**S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, a**S(2)*x**S(5)/S(5) + a*b*x**S(6)/S(3) + b*c*x**S(8)/S(4) + c**S(2)*x**S(9)/S(9) + x**S(7)*(S(2)*a*c + b**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2)/x, x), x, a**S(2)*x**S(4)/S(4) + S(2)*a*b*x**S(5)/S(5) + S(2)*b*c*x**S(7)/S(7) + c**S(2)*x**S(8)/S(8) + x**S(6)*(S(2)*a*c + b**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2)/x**S(2), x), x, a**S(2)*x**S(3)/S(3) + a*b*x**S(4)/S(2) + b*c*x**S(6)/S(3) + c**S(2)*x**S(7)/S(7) + x**S(5)*(S(2)*a*c + b**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -b*x/c**S(2) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*sqrt(-S(4)*a*c + b**S(2))) + x**S(2)/(S(2)*c) + (-a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -b*log(a + b*x + c*x**S(2))/(S(2)*c**S(2)) + x/c - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, b*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*x + c*x**S(2))/(S(2)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -S(2)*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, b*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a + b*x + c*x**S(2))/(S(2)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -S(1)/(a*x) - b*log(x)/a**S(2) + b*log(a + b*x + c*x**S(2))/(S(2)*a**S(2)) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a*x**S(2) + b*x**S(3) + c*x**S(4))), x), x, -S(1)/(S(2)*a*x**S(2)) + b/(a**S(2)*x) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*sqrt(-S(4)*a*c + b**S(2))) + (-a*c + b**S(2))*log(x)/a**S(3) - (-a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*a**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a*x**S(2) + b*x**S(3) + c*x**S(4))), x), x, -S(1)/(S(3)*a*x**S(3)) + b/(S(2)*a**S(2)*x**S(2)) - (-a*c + b**S(2))/(a**S(3)*x) - b*(-S(2)*a*c + b**S(2))*log(x)/a**S(4) + b*(-S(2)*a*c + b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*a**S(4)) - (S(2)*a**S(2)*c**S(2) - S(4)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(4)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, -b*x**S(2)/(c*(-S(4)*a*c + b**S(2))) - b*log(a + b*x + c*x**S(2))/c**S(3) + x**S(3)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + x*(-S(6)*a*c + S(2)*b**S(2))/(c**S(2)*(-S(4)*a*c + b**S(2))) - (S(12)*a**S(2)*c**S(2) - S(12)*a*b**S(2)*c + S(2)*b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, -b*x/(c*(-S(4)*a*c + b**S(2))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x**S(2)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + log(a + b*x + c*x**S(2))/(S(2)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, S(4)*a*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + x*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, -S(2)*b*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + (S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, S(4)*c*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - (b + S(2)*c*x)/((-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + log(x)/a**S(2) - log(a + b*x + c*x**S(2))/(S(2)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*x*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) + (S(6)*a*c - S(2)*b**S(2))/(a**S(2)*x*(-S(4)*a*c + b**S(2))) - S(2)*b*log(x)/a**S(3) + b*log(a + b*x + c*x**S(2))/a**S(3) - (S(12)*a**S(2)*c**S(2) - S(12)*a*b**S(2)*c + S(2)*b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) - (-S(8)*a*c + S(3)*b**S(2))/(S(2)*a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) + b*(-S(11)*a*c + S(3)*b**S(2))/(a**S(3)*x*(-S(4)*a*c + b**S(2))) + b*(S(30)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (-S(2)*a*c + S(3)*b**S(2))*log(x)/a**S(4) - (-S(2)*a*c + S(3)*b**S(2))*log(a + b*x + c*x**S(2))/(S(2)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(-2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*x**S(3)*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) - (-S(10)*a*c + S(4)*b**S(2))/(S(3)*a**S(2)*x**S(3)*(-S(4)*a*c + b**S(2))) + b*(-S(7)*a*c + S(2)*b**S(2))/(a**S(3)*x**S(2)*(-S(4)*a*c + b**S(2))) - (S(10)*a**S(2)*c**S(2) - S(18)*a*b**S(2)*c + S(4)*b**S(4))/(a**S(4)*x*(-S(4)*a*c + b**S(2))) - S(2)*b*(-S(3)*a*c + S(2)*b**S(2))*log(x)/a**S(5) + b*(-S(3)*a*c + S(2)*b**S(2))*log(a + b*x + c*x**S(2))/a**S(5) - (-S(20)*a**S(3)*c**S(3) + S(60)*a**S(2)*b**S(2)*c**S(2) - S(30)*a*b**S(4)*c + S(4)*b**S(6))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(5)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a*x**S(2) + b*x**S(3) + c*x**S(4))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x)/(a*x**S(4)*(-S(4)*a*c + b**S(2))*(a + b*x + c*x**S(2))) - (-S(12)*a*c + S(5)*b**S(2))/(S(4)*a**S(2)*x**S(4)*(-S(4)*a*c + b**S(2))) + b*(-S(17)*a*c + S(5)*b**S(2))/(S(3)*a**S(3)*x**S(3)*(-S(4)*a*c + b**S(2))) - (S(12)*a**S(2)*c**S(2) - S(22)*a*b**S(2)*c + S(5)*b**S(4))/(S(2)*a**S(4)*x**S(2)*(-S(4)*a*c + b**S(2))) + b*(S(29)*a**S(2)*c**S(2) - S(27)*a*b**S(2)*c + S(5)*b**S(4))/(a**S(5)*x*(-S(4)*a*c + b**S(2))) + b*(-S(70)*a**S(3)*c**S(3) + S(105)*a**S(2)*b**S(2)*c**S(2) - S(42)*a*b**S(4)*c + S(5)*b**S(6))*atanh((b + S(2)*c*x)/sqrt(-S(4)*a*c + b**S(2)))/(a**S(6)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (S(3)*a**S(2)*c**S(2) - S(12)*a*b**S(2)*c + S(5)*b**S(4))*log(x)/a**S(6) - (S(3)*a**S(2)*c**S(2) - S(12)*a*b**S(2)*c + S(5)*b**S(4))*log(a + b*x + c*x**S(2))/(S(2)*a**S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, b*(-S(116)*a*c + S(35)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(960)*c**S(3)) + b*x*(-S(12)*a*c + S(7)*b**S(2))*(-S(4)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(256)*c**(S(9)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + x**S(2)*(b + S(8)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(40)*c) - x*(-S(16)*a*c + S(7)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(240)*c**S(2)) - sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(256)*a**S(2)*c**S(2) - S(460)*a*b**S(2)*c + S(105)*b**S(4))/(S(1920)*c**S(4)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, b*(-S(52)*a*c + S(15)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(192)*c**S(3)*x) + x*(b + S(6)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(24)*c) - (-S(12)*a*c + S(5)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(96)*c**S(2)) - x*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(5)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(128)*c**(S(7)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -b*(b + S(2)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(8)*c**S(2)*x) + b*(-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(16)*c**(S(5)/2)*x*sqrt(a + b*x + c*x**S(2))) + (a + b*x + c*x**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(3)*c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x, x), x, (b + S(2)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*c*x) - x*(-S(4)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(8)*c**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x**S(2), x), x, -sqrt(a)*x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)) + b*x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(2)*sqrt(c)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x, expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x**S(3), x), x, sqrt(c)*x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)) - sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x**S(2) - b*x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(2)*sqrt(a)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x**S(4), x), x, -sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(2)*x**S(3)) - b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*a*x**S(2)) + x*(-S(4)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(8)*a**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x**S(5), x), x, -sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(3)*x**S(4)) - b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(12)*a*x**S(3)) + (-S(8)*a*c + S(3)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(24)*a**S(2)*x**S(2)) - b*x*(-S(4)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(16)*a**(S(5)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/x**S(6), x), x, -sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*x**S(5)) - b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(24)*a*x**S(4)) + (-S(12)*a*c + S(5)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(96)*a**S(2)*x**S(3)) - b*(-S(52)*a*c + S(15)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(192)*a**S(3)*x**S(2)) + x*(-S(4)*a*c + b**S(2))*(-S(4)*a*c + S(5)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(128)*a**(S(7)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, -b*x*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(2416)*a**S(2)*c**S(2) - S(1560)*a*b**S(2)*c + S(231)*b**S(4))/(S(71680)*c**S(4)) - b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(-S(58816)*a**S(3)*c**S(3) + S(81648)*a**S(2)*b**S(2)*c**S(2) - S(30660)*a*b**S(4)*c + S(3465)*b**S(6))/(S(573440)*c**S(6)*x) + x*(S(3)*b + S(14)*c*x)*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(112)*c) - x**S(3)*(b*(S(68)*a*c + S(11)*b**S(2)) + S(10)*c*x*(-S(28)*a*c + S(11)*b**S(2)))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4480)*c**S(2)) + x**S(2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(560)*a**S(2)*c**S(2) - S(568)*a*b**S(2)*c + S(99)*b**S(4))/(S(35840)*c**S(3)) + sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(-S(6720)*a**S(3)*c**S(3) + S(18896)*a**S(2)*b**S(2)*c**S(2) - S(8988)*a*b**S(4)*c + S(1155)*b**S(6))/(S(286720)*c**S(5)) + S(3)*x*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x + c*x**S(2))*(S(16)*a**S(2)*c**S(2) - S(72)*a*b**S(2)*c + S(33)*b**S(4))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(32768)*c**(S(13)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, -b*x**S(2)*(-S(44)*a*c + S(9)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(2240)*c**S(2)) - b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(1168)*a**S(2)*c**S(2) - S(728)*a*b**S(2)*c + S(105)*b**S(4))/(S(17920)*c**S(4)) - S(3)*b*x*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(3)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(2048)*c**(S(11)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + x*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/S(7) + x**S(3)*(S(24)*a*c + b**S(2) + S(10)*b*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(280)*c) + x*(-S(32)*a*c + S(7)*b**S(2))*(-S(4)*a*c + S(3)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4480)*c**S(3)) + sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(-S(2048)*a**S(3)*c**S(3) + S(5488)*a**S(2)*b**S(2)*c**S(2) - S(2520)*a*b**S(4)*c + S(315)*b**S(6))/(S(35840)*c**S(5)*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x, x), x, -b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(1296)*a**S(2)*c**S(2) - S(760)*a*b**S(2)*c + S(105)*b**S(4))/(S(7680)*c**S(4)*x) + (S(3)*b + S(10)*c*x)*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(60)*c*x) - x*(b*(S(12)*a*c + S(7)*b**S(2)) + S(6)*c*x*(-S(20)*a*c + S(7)*b**S(2)))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(960)*c**S(2)) + sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(240)*a**S(2)*c**S(2) - S(216)*a*b**S(2)*c + S(35)*b**S(4))/(S(3840)*c**S(3)) + x*(-S(4)*a*c + b**S(2))**S(2)*(-S(4)*a*c + S(7)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(1024)*c**(S(9)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(2), x), x, -b*(b + S(2)*c*x)*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(16)*c**S(2)*x**S(3)) + S(3)*b*(b + S(2)*c*x)*(-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(128)*c**S(3)*x) - S(3)*b*x*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(256)*c**(S(7)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + (a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(5)/2)/(S(5)*c*x**S(5)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(3), x), x, (b + S(2)*c*x)*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(8)*c*x**S(3)) - (b + S(2)*c*x)*(-S(12)*a*c + S(3)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(64)*c**S(2)*x) + S(3)*x*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(128)*c**(S(5)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(4), x), x, -a**(S(3)/2)*x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)) - b*x*(-S(12)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(16)*c**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + (a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(3)*x**S(3)) + (S(8)*a*c + b**S(2) + S(2)*b*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(8)*c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(5), x), x, -S(3)*sqrt(a)*b*x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + (S(9)*b + S(6)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*x) - (a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(4) + x*(S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(8)*sqrt(c)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(6), x), x, S(3)*b*sqrt(c)*x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) - (S(3)*b - S(6)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*x**S(2)) - (a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(2)*x**S(5)) - x*(S(12)*a*c + S(3)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(8)*sqrt(a)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(7), x), x, c**(S(3)/2)*x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)) - (a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(3)*x**S(6)) - b*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(4)*a*x**S(5)) + (-S(8)*a*c + b**S(2) + S(2)*b*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(8)*a*x**S(2)) + b*x*(-S(12)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(16)*a**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(8), x), x, -(b + S(6)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(8)*x**S(4)) - (a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(4)*x**S(7)) - (-S(12)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(32)*a*x**S(3)) + b*(-S(20)*a*c + S(3)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(64)*a**S(2)*x**S(2)) - S(3)*x*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(128)*a**(S(5)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/x**S(9), x), x, -(S(3)*b + S(12)*c*x)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(40)*x**S(5)) - (a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)/(S(5)*x**S(8)) - (-S(8)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(80)*a*x**S(4)) + b*(-S(28)*a*c + S(5)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(320)*a**S(2)*x**S(3)) - sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(128)*a**S(2)*c**S(2) - S(100)*a*b**S(2)*c + S(15)*b**S(4))/(S(640)*a**S(3)*x**S(2)) + S(3)*b*x*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(256)*a**(S(7)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -S(3)*b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*c**S(2)*x) + sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(2)*c) + x*(-S(4)*a*c + S(3)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(8)*c**(S(5)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -b*x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(2)*c**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(c*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(sqrt(c)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4)), x), x, -x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(sqrt(a)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), x), x, -sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(a*x**S(2)) + b*x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(2)*a**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), x), x, -sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(2)*a*x**S(3)) + S(3)*b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*a**S(2)*x**S(2)) - x*(-S(4)*a*c + S(3)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(8)*a**(S(5)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, -S(2)*b*x*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(c*(-S(4)*a*c + b**S(2))) - b*(-S(52)*a*c + S(15)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*c**S(3)*x*(-S(4)*a*c + b**S(2))) + S(2)*x**S(4)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + (-S(12)*a*c + S(5)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))) + x*(-S(12)*a*c + S(15)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(8)*c**(S(7)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, -S(2)*b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(c*(-S(4)*a*c + b**S(2))) - S(3)*b*x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(S(2)*c**(S(5)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + S(2)*x**S(3)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + (-S(8)*a*c + S(3)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(c**S(2)*x*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, -S(2)*b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(c*x*(-S(4)*a*c + b**S(2))) + S(2)*x**S(2)*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) + x*sqrt(a + b*x + c*x**S(2))*atanh((b + S(2)*c*x)/(S(2)*sqrt(c)*sqrt(a + b*x + c*x**S(2))))/(c**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, S(2)*x*(S(2)*a + b*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, -S(2)*x*(b + S(2)*c*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, S(2)*x*(-S(2)*a*c + b**S(2) + b*c*x)/(a*(-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) - x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(a**(S(3)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x)/(a*(-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) - (-S(8)*a*c + S(3)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) + S(3)*b*x*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(2)*a**(S(5)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(-3)/2), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x)/(a*x*(-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) - (-S(12)*a*c + S(5)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(2)*a**S(2)*x**S(3)*(-S(4)*a*c + b**S(2))) + b*(-S(52)*a*c + S(15)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*a**S(3)*x**S(2)*(-S(4)*a*c + b**S(2))) - x*(-S(12)*a*c + S(15)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(8)*a**(S(7)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x)/(a*x**S(2)*(-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) - (-S(16)*a*c + S(7)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(3)*a**S(2)*x**S(4)*(-S(4)*a*c + b**S(2))) + b*(-S(116)*a*c + S(35)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(12)*a**S(3)*x**S(3)*(-S(4)*a*c + b**S(2))) - sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(256)*a**S(2)*c**S(2) - S(460)*a*b**S(2)*c + S(105)*b**S(4))/(S(24)*a**S(4)*x**S(2)*(-S(4)*a*c + b**S(2))) + S(5)*b*x*(-S(12)*a*c + S(7)*b**S(2))*sqrt(a + b*x + c*x**S(2))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(16)*a**(S(9)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a*x**S(2) + b*x**S(3) + c*x**S(4))**(S(3)/2)), x), x, (-S(4)*a*c + S(2)*b**S(2) + S(2)*b*c*x)/(a*x**S(3)*(-S(4)*a*c + b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))) - (-S(20)*a*c + S(9)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(4)*a**S(2)*x**S(5)*(-S(4)*a*c + b**S(2))) + b*(-S(68)*a*c + S(21)*b**S(2))*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))/(S(8)*a**S(3)*x**S(4)*(-S(4)*a*c + b**S(2))) - sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(240)*a**S(2)*c**S(2) - S(448)*a*b**S(2)*c + S(105)*b**S(4))/(S(32)*a**S(4)*x**S(3)*(-S(4)*a*c + b**S(2))) + b*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))*(S(1808)*a**S(2)*c**S(2) - S(1680)*a*b**S(2)*c + S(315)*b**S(4))/(S(64)*a**S(5)*x**S(2)*(-S(4)*a*c + b**S(2))) - x*sqrt(a + b*x + c*x**S(2))*(S(240)*a**S(2)*c**S(2) - S(840)*a*b**S(2)*c + S(315)*b**S(4))*atanh((S(2)*a + b*x)/(S(2)*sqrt(a)*sqrt(a + b*x + c*x**S(2))))/(S(128)*a**(S(11)/2)*sqrt(a*x**S(2) + b*x**S(3) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a*x + b*x**S(3) + c*x**S(5)), x), x, a*x**(m + S(2))/(m + S(2)) + b*x**(m + S(4))/(m + S(4)) + c*x**(m + S(6))/(m + S(6)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a*x + b*x**S(3) + c*x**S(5)), x), x, a*x**S(4)/S(4) + b*x**S(6)/S(6) + c*x**S(8)/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a*x + b*x**S(3) + c*x**S(5)), x), x, a*x**S(3)/S(3) + b*x**S(5)/S(5) + c*x**S(7)/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(a*x + b*x**S(3) + c*x**S(5), x), x, a*x**S(2)/S(2) + b*x**S(4)/S(4) + c*x**S(6)/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))/x, x), x, a*x + b*x**S(3)/S(3) + c*x**S(5)/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))/x**S(2), x), x, a*log(x) + b*x**S(2)/S(2) + c*x**S(4)/S(4), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))/x**S(3), x), x, -a/x + b*x + c*x**S(3)/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**m*(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, a**S(2)*x**(m + S(3))/(m + S(3)) + S(2)*a*b*x**(m + S(5))/(m + S(5)) + S(2)*b*c*x**(m + S(9))/(m + S(9)) + c**S(2)*x**(m + S(11))/(m + S(11)) + x**(m + S(7))*(S(2)*a*c + b**S(2))/(m + S(7)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)*(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, a**S(2)*x**S(5)/S(5) + S(2)*a*b*x**S(7)/S(7) + S(2)*b*c*x**S(11)/S(11) + c**S(2)*x**S(13)/S(13) + x**S(9)*(S(2)*a*c + b**S(2))/S(9), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, a**S(2)*x**S(4)/S(4) + a*b*x**S(6)/S(3) + b*c*x**S(10)/S(5) + c**S(2)*x**S(12)/S(12) + x**S(8)*(S(2)*a*c + b**S(2))/S(8), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, a**S(2)*x**S(3)/S(3) + S(2)*a*b*x**S(5)/S(5) + S(2)*b*c*x**S(9)/S(9) + c**S(2)*x**S(11)/S(11) + x**S(7)*(S(2)*a*c + b**S(2))/S(7), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))**S(2)/x, x), x, a**S(2)*x**S(2)/S(2) + a*b*x**S(4)/S(2) + b*c*x**S(8)/S(4) + c**S(2)*x**S(10)/S(10) + x**S(6)*(S(2)*a*c + b**S(2))/S(6), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))**S(2)/x**S(2), x), x, a**S(2)*x + S(2)*a*b*x**S(3)/S(3) + S(2)*b*c*x**S(7)/S(7) + c**S(2)*x**S(9)/S(9) + x**S(5)*(S(2)*a*c + b**S(2))/S(5), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a*x + b*x**S(3) + c*x**S(5)), x), x, -b*x**S(2)/(S(2)*c**S(2)) + b*(-S(3)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(3)*sqrt(-S(4)*a*c + b**S(2))) + x**S(4)/(S(4)*c) + (-a*c + b**S(2))*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(3)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a*x + b*x**S(3) + c*x**S(5)), x), x, -b*x/c**S(2) + x**S(3)/(S(3)*c) + sqrt(S(2))*(-a*c + b**S(2) + b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) + sqrt(S(2))*(-a*c + b**S(2) - b*(-S(3)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a*x + b*x**S(3) + c*x**S(5)), x), x, -b*log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)) + x**S(2)/(S(2)*c) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*x + b*x**S(3) + c*x**S(5)), x), x, x/c - sqrt(S(2))*(b - (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*(b + (-S(2)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a*x + b*x**S(3) + c*x**S(5)), x), x, b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c*sqrt(-S(4)*a*c + b**S(2))) + log(a + b*x**S(2) + c*x**S(4))/(S(4)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*x + b*x**S(3) + c*x**S(5)), x), x, -sqrt(S(2))*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(c)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*x + b*x**S(3) + c*x**S(5)), x), x, -atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/sqrt(-S(4)*a*c + b**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*x + b*x**S(3) + c*x**S(5)), x), x, -sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))) + sqrt(S(2))*sqrt(c)*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(a*x + b*x**S(3) + c*x**S(5)), x), x, b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a*sqrt(-S(4)*a*c + b**S(2))) + log(x)/a - log(a + b*x**S(2) + c*x**S(4))/(S(4)*a), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a*x + b*x**S(3) + c*x**S(5))), x), x, -sqrt(S(2))*sqrt(c)*(-b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))) - sqrt(S(2))*sqrt(c)*(b/sqrt(-S(4)*a*c + b**S(2)) + S(1))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))) - S(1)/(a*x), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a*x + b*x**S(3) + c*x**S(5))), x), x, -S(1)/(S(2)*a*x**S(2)) - b*log(x)/a**S(2) + b*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)) - (-S(2)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*sqrt(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(11)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, -b*x**S(4)/(S(2)*c*(-S(4)*a*c + b**S(2))) - b*log(a + b*x**S(2) + c*x**S(4))/(S(2)*c**S(3)) + x**S(6)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + x**S(2)*(-S(3)*a*c + b**S(2))/(c**S(2)*(-S(4)*a*c + b**S(2))) - (S(6)*a**S(2)*c**S(2) - S(6)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(c**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(10)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, -b*x**S(3)/(S(2)*c*(-S(4)*a*c + b**S(2))) + x**S(5)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + x*(-S(10)*a*c + S(3)*b**S(2))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*(-S(13)*a*b*c + S(3)*b**S(3) + (S(20)*a**S(2)*c**S(2) - S(19)*a*b**S(2)*c + S(3)*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(5)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*(-S(13)*a*b*c + S(3)*b**S(3) - (S(20)*a**S(2)*c**S(2) - S(19)*a*b**S(2)*c + S(3)*b**S(4))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(5)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(9)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, -b*x**S(2)/(S(2)*c*(-S(4)*a*c + b**S(2))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*c**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x**S(4)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + log(a + b*x**S(2) + c*x**S(4))/(S(4)*c**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(8)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, -b*x/(S(2)*c*(-S(4)*a*c + b**S(2))) + x**S(3)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(-S(6)*a*c + b**S(2) + b*(-S(8)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(-S(6)*a*c + b**S(2) - b*(-S(8)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*c**(S(3)/2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(7)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, S(2)*a*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + x**S(2)*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(6)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, x*(S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*(b - (S(4)*a*c + b**S(2))/sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))) + sqrt(S(2))*(S(4)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*sqrt(c)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(5)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, -b*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) + (S(2)*a + b*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(4)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, -sqrt(S(2))*sqrt(c)*(S(2)*b + sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(S(2)*b - sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - x*(b + S(2)*c*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(3)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, S(2)*c*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(-S(4)*a*c + b**S(2))**(S(3)/2) - (b + S(2)*c*x**S(2))/((-S(8)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**S(2)/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, -sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) - b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(-S(12)*a*c + b**S(2) + b*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + x*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/(a*x + b*x**S(3) + c*x**S(5))**S(2), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + b*(-S(6)*a*c + b**S(2))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(2)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + log(x)/a**S(2) - log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))**(S(-2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*x*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) + sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) - (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - sqrt(S(2))*sqrt(c)*(-S(16)*a*b*c + S(3)*b**S(3) + (-S(10)*a*c + S(3)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(2)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) - (-S(10)*a*c + S(3)*b**S(2))/(S(2)*a**S(2)*x*(-S(4)*a*c + b**S(2))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x*(a*x + b*x**S(3) + c*x**S(5))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*x**S(2)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (-S(3)*a*c + b**S(2))/(a**S(2)*x**S(2)*(-S(4)*a*c + b**S(2))) - S(2)*b*log(x)/a**S(3) + b*log(a + b*x**S(2) + c*x**S(4))/(S(2)*a**S(3)) - (S(6)*a**S(2)*c**S(2) - S(6)*a*b**S(2)*c + b**S(4))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(a**S(3)*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(2)*(a*x + b*x**S(3) + c*x**S(5))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*x**S(3)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (-S(14)*a*c + S(5)*b**S(2))/(S(6)*a**S(2)*x**S(3)*(-S(4)*a*c + b**S(2))) + b*(-S(19)*a*c + S(5)*b**S(2))/(S(2)*a**S(3)*x*(-S(4)*a*c + b**S(2))) - sqrt(S(2))*sqrt(c)*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c + S(5)*b**S(4) - b*(-S(19)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b + sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*sqrt(b + sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)) + sqrt(S(2))*sqrt(c)*(S(28)*a**S(2)*c**S(2) - S(29)*a*b**S(2)*c + S(5)*b**S(4) + b*(-S(19)*a*c + S(5)*b**S(2))*sqrt(-S(4)*a*c + b**S(2)))*atan(sqrt(S(2))*sqrt(c)*x/sqrt(b - sqrt(-S(4)*a*c + b**S(2))))/(S(4)*a**S(3)*sqrt(b - sqrt(-S(4)*a*c + b**S(2)))*(-S(4)*a*c + b**S(2))**(S(3)/2)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**S(3)*(a*x + b*x**S(3) + c*x**S(5))**S(2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(S(2)*a*x**S(4)*(-S(4)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))) - (-S(8)*a*c + S(3)*b**S(2))/(S(4)*a**S(2)*x**S(4)*(-S(4)*a*c + b**S(2))) + b*(-S(11)*a*c + S(3)*b**S(2))/(S(2)*a**S(3)*x**S(2)*(-S(4)*a*c + b**S(2))) + b*(S(30)*a**S(2)*c**S(2) - S(20)*a*b**S(2)*c + S(3)*b**S(4))*atanh((b + S(2)*c*x**S(2))/sqrt(-S(4)*a*c + b**S(2)))/(S(2)*a**S(4)*(-S(4)*a*c + b**S(2))**(S(3)/2)) + (-S(2)*a*c + S(3)*b**S(2))*log(x)/a**S(4) - (-S(2)*a*c + S(3)*b**S(2))*log(a + b*x**S(2) + c*x**S(4))/(S(4)*a**S(4)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*sqrt(a*x + b*x**S(3) + c*x**S(5)), x), x, S(2)*a**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(15)*c**(S(7)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) - a**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*b*sqrt(c) - S(6)*a*c + S(2)*b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(30)*c**(S(7)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + sqrt(x)*(b + S(3)*c*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(15)*c) - x**(S(3)/2)*(-S(6)*a*c + S(2)*b**S(2))*(a + b*x**S(2) + c*x**S(4))/(S(15)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*sqrt(a*x + b*x**S(3) + c*x**S(5)), x), x, (b + S(2)*c*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(8)*c*sqrt(x)) - sqrt(x)*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(16)*c**(S(3)/2)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x + b*x**S(3) + c*x**S(5))/sqrt(x), x), x, -a**(S(1)/4)*b*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(3)*c**(S(3)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + a**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(2)*sqrt(a)*sqrt(c) + b)*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(6)*c**(S(3)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + b*x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))/(S(3)*sqrt(c)*(sqrt(a) + sqrt(c)*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) + sqrt(x)*sqrt(a*x + b*x**S(3) + c*x**S(5))/S(3), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(a*x + b*x**S(3) + c*x**S(5))/x**(S(3)/2), x), x, -sqrt(a)*sqrt(x)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + b*sqrt(x)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*sqrt(c)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(2)*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)*(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2), x), x, -S(3)*b*sqrt(x)*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(512)*c**(S(7)/2)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + sqrt(x)*(S(3)*b + S(8)*c*x**S(2))*(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)/(S(80)*c) - x**(S(3)/2)*(b*(-S(4)*a*c + S(5)*b**S(2)) + S(4)*c*x**S(2)*(-S(16)*a*c + S(5)*b**S(2)))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(640)*c**S(2)) + sqrt(a*x + b*x**S(3) + c*x**S(5))*(S(128)*a**S(2)*c**S(2) - S(100)*a*b**S(2)*c + S(15)*b**S(4))/(S(1280)*c**S(3)*sqrt(x)), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)*(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2), x), x, -a**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(84)*a**S(2)*c**S(2) - S(57)*a*b**S(2)*c + S(8)*b**S(4))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(315)*c**(S(11)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + a**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(S(4)*sqrt(a)*b*sqrt(c)*(-S(6)*a*c + b**S(2)) + S(84)*a**S(2)*c**S(2) - S(57)*a*b**S(2)*c + S(8)*b**S(4))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(630)*c**(S(11)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + (S(3)*b + S(7)*c*x**S(2))*(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)/(S(63)*c*sqrt(x)) - sqrt(x)*(b*(-S(9)*a*c + S(4)*b**S(2)) + S(6)*c*x**S(2)*(-S(7)*a*c + S(2)*b**S(2)))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(315)*c**S(2)) + x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))*(S(84)*a**S(2)*c**S(2) - S(57)*a*b**S(2)*c + S(8)*b**S(4))/(S(315)*c**(S(5)/2)*(sqrt(a) + sqrt(c)*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)/sqrt(x), x), x, (b + S(2)*c*x**S(2))*(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)/(S(16)*c*x**(S(3)/2)) - (b + S(2)*c*x**S(2))*(-S(12)*a*c + S(3)*b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(128)*c**S(2)*sqrt(x)) + S(3)*sqrt(x)*(-S(4)*a*c + b**S(2))**S(2)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(256)*c**(S(5)/2)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate((a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)/x**(S(3)/2), x), x, S(2)*a**(S(1)/4)*b*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(8)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(35)*c**(S(7)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) - a**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*sqrt(c)*(-S(20)*a*c + b**S(2)) + S(2)*b*(-S(8)*a*c + b**S(2)))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(70)*c**(S(7)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) - S(2)*b*x**(S(3)/2)*(-S(8)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))/(S(35)*c**(S(3)/2)*(sqrt(a) + sqrt(c)*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) + (a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)/(S(7)*sqrt(x)) + sqrt(x)*(S(10)*a*c + b**S(2) + S(3)*b*c*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(35)*c), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/sqrt(a*x + b*x**S(3) + c*x**S(5)), x), x, sqrt(x)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((b + S(2)*c*x**S(2))/(S(2)*sqrt(c)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(c)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/sqrt(a*x + b*x**S(3) + c*x**S(5)), x), x, sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(1)/4)*c**(S(1)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*sqrt(a*x + b*x**S(3) + c*x**S(5))), x), x, -sqrt(x)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*sqrt(a)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*sqrt(a*x + b*x**S(3) + c*x**S(5))), x), x, sqrt(c)*x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))/(a*(sqrt(a) + sqrt(c)*x**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) - sqrt(a*x + b*x**S(3) + c*x**S(5))/(a*x**(S(3)/2)) - c**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(3)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + c**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(3)/4)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)/2)/(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2), x), x, -b*sqrt(c)*x**(S(3)/2)*(a + b*x**S(2) + c*x**S(4))/(a*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) + x**(S(3)/2)*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) + b*c**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(3)/4)*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) - c**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(3)/4)*(-S(2)*sqrt(a)*sqrt(c) + b)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(sqrt(x)/(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2), x), x, sqrt(x)*(-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) - sqrt(x)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(2)*a**(S(3)/2)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(sqrt(x)*(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*sqrt(x)*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) + S(2)*sqrt(c)*x**(S(3)/2)*(-S(3)*a*c + b**S(2))*(a + b*x**S(2) + c*x**S(4))/(a**S(2)*(sqrt(a) + sqrt(c)*x**S(2))*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) - (-S(6)*a*c + S(2)*b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(a**S(2)*x**(S(3)/2)*(-S(4)*a*c + b**S(2))) - S(2)*c**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(-S(3)*a*c + b**S(2))*elliptic_e(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(a**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) + c**(S(1)/4)*sqrt(x)*sqrt((a + b*x**S(2) + c*x**S(4))/(sqrt(a) + sqrt(c)*x**S(2))**S(2))*(sqrt(a) + sqrt(c)*x**S(2))*(sqrt(a)*b*sqrt(c) - S(6)*a*c + S(2)*b**S(2))*elliptic_f(S(2)*atan(c**(S(1)/4)*x/a**(S(1)/4)), S(1)/2 - b/(S(4)*sqrt(a)*sqrt(c)))/(S(2)*a**(S(7)/4)*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(S(1)/(x**(S(3)/2)*(a*x + b*x**S(3) + c*x**S(5))**(S(3)/2)), x), x, (-S(2)*a*c + b**S(2) + b*c*x**S(2))/(a*x**(S(3)/2)*(-S(4)*a*c + b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))) - (-S(8)*a*c + S(3)*b**S(2))*sqrt(a*x + b*x**S(3) + c*x**S(5))/(S(2)*a**S(2)*x**(S(5)/2)*(-S(4)*a*c + b**S(2))) + S(3)*b*sqrt(x)*sqrt(a + b*x**S(2) + c*x**S(4))*atanh((S(2)*a + b*x**S(2))/(S(2)*sqrt(a)*sqrt(a + b*x**S(2) + c*x**S(4))))/(S(4)*a**(S(5)/2)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x**(S(3)*n/S(2) + S(-3)/2)/(a*x**(n + S(-1)) + b*x**n + c*x**(n + S(1)))**(S(3)/2), x), x, -S(2)*x**(n/S(2) + S(-1)/2)*(b + S(2)*c*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**(n + S(-1)) + b*x**n + c*x**(n + S(1)))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x/sqrt(a*x + b*x**S(3) + c*x**S(5)), x), x, S(2)*x**S(2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(1)/2, S(1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) assert rubi_test(rubi_integrate(x*(d + e*x**S(2))/sqrt(a*x + b*x**S(3) + c*x**S(5)), x), x, S(2)*d*x**S(2)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(3)/4, S(1)/2, S(1)/2, S(7)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(3)*sqrt(a*x + b*x**S(3) + c*x**S(5))) + S(2)*e*x**S(4)*sqrt(S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))*sqrt(S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))*AppellF1(S(7)/4, S(1)/2, S(1)/2, S(11)/4, -S(2)*c*x**S(2)/(b - sqrt(-S(4)*a*c + b**S(2))), -S(2)*c*x**S(2)/(b + sqrt(-S(4)*a*c + b**S(2))))/(S(7)*sqrt(a*x + b*x**S(3) + c*x**S(5))), expand=True, _diff=True, _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/rubimain.py000066400000000000000000000176501412543434000222260ustar00rootroot00000000000000from sympy.external import import_module from sympy.utilities.decorator import doctest_depends_on from sympy.core import Integer, Float from sympy import Pow, Add, Integral, Mul, S, Function, E from sympy.functions import exp as sym_exp import inspect import re from sympy import powsimp matchpy = import_module("matchpy") if matchpy: from matchpy import ManyToOneReplacer, ManyToOneMatcher from sympy.integrals.rubi.utility_function import ( rubi_exp, rubi_unevaluated_expr, process_trig ) from sympy.utilities.matchpy_connector import op_iter, op_len @doctest_depends_on(modules=('matchpy',)) def get_rubi_object(): """ Returns rubi ManyToOneReplacer by adding all rules from different modules. Uncomment the lines to add integration capabilities of that module. Currently, there are parsing issues with special_function, derivative and miscellaneous_integration. Hence they are commented. """ from sympy.integrals.rubi.rules.integrand_simplification import integrand_simplification from sympy.integrals.rubi.rules.linear_products import linear_products from sympy.integrals.rubi.rules.quadratic_products import quadratic_products from sympy.integrals.rubi.rules.binomial_products import binomial_products from sympy.integrals.rubi.rules.trinomial_products import trinomial_products from sympy.integrals.rubi.rules.miscellaneous_algebraic import miscellaneous_algebraic from sympy.integrals.rubi.rules.exponential import exponential from sympy.integrals.rubi.rules.logarithms import logarithms from sympy.integrals.rubi.rules.sine import sine from sympy.integrals.rubi.rules.tangent import tangent from sympy.integrals.rubi.rules.secant import secant from sympy.integrals.rubi.rules.miscellaneous_trig import miscellaneous_trig from sympy.integrals.rubi.rules.inverse_trig import inverse_trig from sympy.integrals.rubi.rules.hyperbolic import hyperbolic from sympy.integrals.rubi.rules.inverse_hyperbolic import inverse_hyperbolic from sympy.integrals.rubi.rules.special_functions import special_functions #from sympy.integrals.rubi.rules.derivative import derivative #from sympy.integrals.rubi.rules.piecewise_linear import piecewise_linear from sympy.integrals.rubi.rules.miscellaneous_integration import miscellaneous_integration rules = [] rules += integrand_simplification() rules += linear_products() rules += quadratic_products() rules += binomial_products() rules += trinomial_products() rules += miscellaneous_algebraic() rules += exponential() rules += logarithms() rules += special_functions() rules += sine() rules += tangent() rules += secant() rules += miscellaneous_trig() rules += inverse_trig() rules += hyperbolic() rules += inverse_hyperbolic() #rubi = piecewise_linear(rubi) rules += miscellaneous_integration() rubi = ManyToOneReplacer(*rules) return rubi, rules _E = rubi_unevaluated_expr(E) class LoadRubiReplacer: """ Class trick to load RUBI only once. """ _instance = None def __new__(cls): if matchpy is None: print("MatchPy library not found") return None if LoadRubiReplacer._instance is not None: return LoadRubiReplacer._instance obj = object.__new__(cls) obj._rubi = None obj._rules = None LoadRubiReplacer._instance = obj return obj def load(self): if self._rubi is not None: return self._rubi rubi, rules = get_rubi_object() self._rubi = rubi self._rules = rules return rubi def to_pickle(self, filename): import pickle rubi = self.load() with open(filename, "wb") as fout: pickle.dump(rubi, fout) def to_dill(self, filename): import dill rubi = self.load() with open(filename, "wb") as fout: dill.dump(rubi, fout) def from_pickle(self, filename): import pickle with open(filename, "rb") as fin: self._rubi = pickle.load(fin) return self._rubi def from_dill(self, filename): import dill with open(filename, "rb") as fin: self._rubi = dill.load(fin) return self._rubi @doctest_depends_on(modules=('matchpy',)) def process_final_integral(expr): """ Rubi's `rubi_exp` need to be replaced back to SymPy's general `exp`. Examples ======== >>> from sympy import Function, E, Integral >>> from sympy.integrals.rubi.rubimain import process_final_integral >>> from sympy.integrals.rubi.utility_function import rubi_unevaluated_expr >>> from sympy.abc import a, x >>> _E = rubi_unevaluated_expr(E) >>> process_final_integral(Integral(a, x)) Integral(a, x) >>> process_final_integral(_E**5) exp(5) """ if expr.has(_E): expr = expr.replace(_E, E) return expr @doctest_depends_on(modules=('matchpy',)) def rubi_powsimp(expr): """ This function is needed to preprocess an expression as done in matchpy `x^a*x^b` in matchpy auotmatically transforms to `x^(a+b)` Examples ======== >>> from sympy.integrals.rubi.rubimain import rubi_powsimp >>> from sympy.abc import a, b, x >>> rubi_powsimp(x**a*x**b) x**(a + b) """ lst_pow = [] lst_non_pow = [] if isinstance(expr, Mul): for i in expr.args: if isinstance(i, (Pow, rubi_exp, sym_exp)): lst_pow.append(i) else: lst_non_pow.append(i) return powsimp(Mul(*lst_pow))*Mul(*lst_non_pow) return expr @doctest_depends_on(modules=('matchpy',)) def rubi_integrate(expr, var, showsteps=False): """ Rule based algorithm for integration. Integrates the expression by applying transformation rules to the expression. Returns `Integrate` if an expression cannot be integrated. Parameters ========== expr : integrand expression var : variable of integration Returns Integral object if unable to integrate. """ rubi = LoadRubiReplacer().load() expr = expr.replace(sym_exp, rubi_exp) expr = process_trig(expr) expr = rubi_powsimp(expr) if isinstance(expr, (int, Integer)) or isinstance(expr, (float, Float)): return S(expr)*var if isinstance(expr, Add): results = 0 for ex in expr.args: results += rubi.replace(Integral(ex, var)) return process_final_integral(results) results = util_rubi_integrate(Integral(expr, var)) return process_final_integral(results) @doctest_depends_on(modules=('matchpy',)) def util_rubi_integrate(expr, showsteps=False, max_loop=10): rubi = LoadRubiReplacer().load() expr = process_trig(expr) expr = expr.replace(sym_exp, rubi_exp) for i in range(max_loop): results = expr.replace( lambda x: isinstance(x, Integral), lambda x: rubi.replace(x, max_count=10) ) if expr == results: return results return results @doctest_depends_on(modules=('matchpy',)) def get_matching_rule_definition(expr, var): """ Prints the list or rules which match to `expr`. Parameters ========== expr : integrand expression var : variable of integration """ rubi = LoadRubiReplacer() matcher = rubi.matcher miter = matcher.match(Integral(expr, var)) for fun, e in miter: print("Rule matching: ") print(inspect.getsourcefile(fun)) code, lineno = inspect.getsourcelines(fun) print("On line: ", lineno) print("\n".join(code)) print("Pattern matching: ") pattno = int(re.match(r"^\s*rule(\d+)", code[0]).group(1)) print(matcher.patterns[pattno-1]) print(e) print() sympy-sympy-1.9/sympy/integrals/rubi/rules/000077500000000000000000000000001412543434000211675ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/rules/__init__.py000066400000000000000000000000001412543434000232660ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/rules/binomial_products.py000066400000000000000000006050021412543434000252610ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def binomial_products(): from sympy.integrals.rubi.constraints import cons461, cons3, cons4, cons5, cons462, cons2, cons463, cons56, cons464, cons89, cons465, cons40, cons466, cons150, cons13, cons165, cons467, cons468, cons45, cons450, cons69, cons139, cons469, cons470, cons471, cons472, cons473, cons474, cons475, cons476, cons477, cons478, cons479, cons480, cons481, cons482, cons483, cons484, cons485, cons486, cons107, cons487, cons488, cons489, cons490, cons198, cons491, cons130, cons359, cons492, cons493, cons494, cons495, cons70, cons71, cons57, cons496, cons59, cons60, cons61, cons62, cons497, cons498, cons499, cons500, cons149, cons8, cons19, cons501, cons502, cons503, cons21, cons504, cons505, cons68, cons506, cons507, cons508, cons509, cons20, cons246, cons96, cons510, cons511, cons512, cons513, cons514, cons515, cons516, cons517, cons518, cons519, cons520, cons521, cons522, cons523, cons64, cons524, cons525, cons526, cons527, cons528, cons529, cons530, cons531, cons33, cons532, cons533, cons534, cons535, cons536, cons537, cons538, cons369, cons539, cons540, cons541, cons542, cons358, cons543, cons25, cons544, cons545, cons546, cons547, cons548, cons549, cons550, cons551, cons552, cons553, cons554, cons555, cons556, cons73, cons557, cons29, cons222, cons52, cons558, cons87, cons559, cons397, cons405, cons65, cons560, cons561, cons562, cons563, cons564, cons565, cons566, cons567, cons568, cons569, cons570, cons571, cons72, cons572, cons573, cons574, cons575, cons404, cons576, cons577, cons578, cons407, cons579, cons580, cons581, cons582, cons583, cons179, cons584, cons585, cons119, cons586, cons587, cons588, cons589, cons388, cons590, cons591, cons592, cons593, cons50, cons55, cons594, cons595, cons596, cons597, cons598, cons95, cons599, cons600, cons601, cons602, cons603, cons604, cons605, cons606, cons90, cons607, cons608, cons609, cons610, cons611, cons612, cons613, cons614, cons615, cons616, cons617, cons618, cons619, cons620, cons621, cons622, cons623, cons624, cons625, cons626, cons627, cons628, cons629, cons48, cons630, cons127, cons631, cons632, cons633, cons155, cons634, cons635, cons178, cons636, cons637, cons638, cons639, cons640, cons180, cons641, cons642, cons398, cons643, cons54, cons644, cons645, cons646, cons647, cons648, cons649, cons650, cons651, cons652, cons653, cons654, cons655, cons656, cons657, cons658, cons210, cons659, cons660, cons661, cons662, cons663, cons382, cons664, cons665 pattern692 = Pattern(Integral((x_**n_*WC('b', S(1)))**p_, x_), cons3, cons4, cons5, cons461) rule692 = ReplacementRule(pattern692, replacement692) pattern693 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons4, cons5, cons462) rule693 = ReplacementRule(pattern693, replacement693) pattern694 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons4, cons5, cons463, cons56) rule694 = ReplacementRule(pattern694, replacement694) pattern695 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons4, cons464) rule695 = ReplacementRule(pattern695, replacement695) pattern696 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons89, cons465, cons40) rule696 = ReplacementRule(pattern696, replacement696) pattern697 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons466) rule697 = ReplacementRule(pattern697, replacement697) pattern698 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons150, cons13, cons165, cons467) rule698 = ReplacementRule(pattern698, replacement698) pattern699 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-5)/4), x_), cons2, cons3, cons468, cons45) rule699 = ReplacementRule(pattern699, replacement699) pattern700 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-5)/4), x_), cons2, cons3, cons468, cons450) rule700 = ReplacementRule(pattern700, replacement700) pattern701 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-7)/6), x_), cons2, cons3, cons69) rule701 = ReplacementRule(pattern701, replacement701) pattern702 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons150, cons13, cons139, cons467) rule702 = ReplacementRule(pattern702, replacement702) pattern703 = Pattern(Integral(S(1)/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons69) rule703 = ReplacementRule(pattern703, replacement703) pattern704 = Pattern(Integral(S(1)/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons469, cons470) rule704 = ReplacementRule(pattern704, With704) pattern705 = Pattern(Integral(S(1)/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons469, cons471) rule705 = ReplacementRule(pattern705, With705) pattern706 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons470, cons472) rule706 = ReplacementRule(pattern706, replacement706) pattern707 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons470, cons473) rule707 = ReplacementRule(pattern707, replacement707) pattern708 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons470) rule708 = ReplacementRule(pattern708, replacement708) pattern709 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons471, cons474) rule709 = ReplacementRule(pattern709, replacement709) pattern710 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons471, cons475) rule710 = ReplacementRule(pattern710, replacement710) pattern711 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons471) rule711 = ReplacementRule(pattern711, replacement711) pattern712 = Pattern(Integral(S(1)/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons476, cons470) rule712 = ReplacementRule(pattern712, With712) pattern713 = Pattern(Integral(S(1)/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons476, cons471) rule713 = ReplacementRule(pattern713, With713) pattern714 = Pattern(Integral(S(1)/(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons477) rule714 = ReplacementRule(pattern714, With714) pattern715 = Pattern(Integral(S(1)/(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons478) rule715 = ReplacementRule(pattern715, With715) pattern716 = Pattern(Integral(S(1)/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons479, cons480) rule716 = ReplacementRule(pattern716, With716) pattern717 = Pattern(Integral(S(1)/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons479, cons478) rule717 = ReplacementRule(pattern717, With717) pattern718 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons45, cons481) rule718 = ReplacementRule(pattern718, replacement718) pattern719 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons45, cons482) rule719 = ReplacementRule(pattern719, replacement719) pattern720 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons450) rule720 = ReplacementRule(pattern720, replacement720) pattern721 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons483) rule721 = ReplacementRule(pattern721, With721) pattern722 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons484) rule722 = ReplacementRule(pattern722, With722) pattern723 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons468) rule723 = ReplacementRule(pattern723, With723) pattern724 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons485, cons45) rule724 = ReplacementRule(pattern724, replacement724) pattern725 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons486, cons107, CustomConstraint(With725)) rule725 = ReplacementRule(pattern725, replacement725) pattern726 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons486, cons107) rule726 = ReplacementRule(pattern726, With726) pattern727 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons485, cons450) rule727 = ReplacementRule(pattern727, replacement727) pattern728 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(6)*WC('b', S(1))), x_), cons2, cons3, cons69) rule728 = ReplacementRule(pattern728, With728) pattern729 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(8)*WC('b', S(1))), x_), cons2, cons3, cons69) rule729 = ReplacementRule(pattern729, replacement729) pattern730 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-1)/4), x_), cons2, cons3, cons468) rule730 = ReplacementRule(pattern730, replacement730) pattern731 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-1)/4), x_), cons2, cons3, cons485, cons45) rule731 = ReplacementRule(pattern731, replacement731) pattern732 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-1)/4), x_), cons2, cons3, cons485, cons450) rule732 = ReplacementRule(pattern732, replacement732) pattern733 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-3)/4), x_), cons2, cons3, cons45, cons468) rule733 = ReplacementRule(pattern733, replacement733) pattern734 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-3)/4), x_), cons2, cons3, cons45, cons485) rule734 = ReplacementRule(pattern734, replacement734) pattern735 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-3)/4), x_), cons2, cons3, cons450) rule735 = ReplacementRule(pattern735, replacement735) pattern736 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-1)/3), x_), cons2, cons3, cons69) rule736 = ReplacementRule(pattern736, replacement736) pattern737 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-2)/3), x_), cons2, cons3, cons69) rule737 = ReplacementRule(pattern737, replacement737) pattern738 = Pattern(Integral((a_ + x_**S(4)*WC('b', S(1)))**(S(-3)/4), x_), cons2, cons3, cons69) rule738 = ReplacementRule(pattern738, replacement738) pattern739 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(-1)/6), x_), cons2, cons3, cons69) rule739 = ReplacementRule(pattern739, replacement739) pattern740 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons150, cons13, cons487, cons488, cons489) rule740 = ReplacementRule(pattern740, replacement740) pattern741 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons150, cons13, cons487, cons488, cons490) rule741 = ReplacementRule(pattern741, replacement741) pattern742 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons198) rule742 = ReplacementRule(pattern742, replacement742) pattern743 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons491) rule743 = ReplacementRule(pattern743, With743) pattern744 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons4, cons130) rule744 = ReplacementRule(pattern744, replacement744) pattern745 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons4, cons5, cons359, cons492, cons493, cons494) rule745 = ReplacementRule(pattern745, replacement745) pattern746 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons4, cons5, cons359, cons492, cons493, cons495) rule746 = ReplacementRule(pattern746, replacement746) pattern747 = Pattern(Integral((u_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons4, cons5, cons70, cons71) rule747 = ReplacementRule(pattern747, replacement747) pattern748 = Pattern(Integral((x_**n_*WC('b1', S(1)) + WC('a1', S(0)))**WC('p', S(1))*(x_**n_*WC('b2', S(1)) + WC('a2', S(0)))**WC('p', S(1)), x_), cons59, cons60, cons61, cons62, cons4, cons5, cons57, cons496) rule748 = ReplacementRule(pattern748, replacement748) pattern749 = Pattern(Integral((a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**WC('p', S(1)), x_), cons59, cons60, cons61, cons62, cons57, cons497, cons13, cons165, cons498) rule749 = ReplacementRule(pattern749, replacement749) pattern750 = Pattern(Integral((a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**p_*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons57, cons497, cons13, cons139, cons498) rule750 = ReplacementRule(pattern750, replacement750) pattern751 = Pattern(Integral((a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons5, cons57, cons499) rule751 = ReplacementRule(pattern751, replacement751) pattern752 = Pattern(Integral((a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons5, cons57, cons500) rule752 = ReplacementRule(pattern752, With752) pattern753 = Pattern(Integral((x_**n_*WC('b1', S(1)) + WC('a1', S(0)))**p_*(x_**n_*WC('b2', S(1)) + WC('a2', S(0)))**p_, x_), cons59, cons60, cons61, cons62, cons4, cons5, cons57, cons149) rule753 = ReplacementRule(pattern753, replacement753) pattern754 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons57, cons496) rule754 = ReplacementRule(pattern754, replacement754) pattern755 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**n_*WC('b', S(1)))**p_, x_), cons3, cons8, cons19, cons4, cons5, cons501, cons502) rule755 = ReplacementRule(pattern755, replacement755) pattern756 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons3, cons8, cons19, cons4, cons5, cons501, cons503) rule756 = ReplacementRule(pattern756, replacement756) pattern757 = Pattern(Integral((c_*x_)**m_*(x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons3, cons8, cons19, cons4, cons5, cons21) rule757 = ReplacementRule(pattern757, replacement757) pattern758 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons40, cons504) rule758 = ReplacementRule(pattern758, replacement758) pattern759 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons505, cons68) rule759 = ReplacementRule(pattern759, replacement759) pattern760 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons57, cons506, cons68) rule760 = ReplacementRule(pattern760, replacement760) pattern761 = Pattern(Integral(x_**WC('m', S(1))*(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons5, cons502) rule761 = ReplacementRule(pattern761, replacement761) pattern762 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons19, cons4, cons5, cons57, cons507) rule762 = ReplacementRule(pattern762, replacement762) pattern763 = Pattern(Integral((c_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons502) rule763 = ReplacementRule(pattern763, replacement763) pattern764 = Pattern(Integral((c_*x_)**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons57, cons507) rule764 = ReplacementRule(pattern764, replacement764) pattern765 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons130) rule765 = ReplacementRule(pattern765, replacement765) pattern766 = Pattern(Integral(x_**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons5, cons508, cons68) rule766 = ReplacementRule(pattern766, replacement766) pattern767 = Pattern(Integral(x_**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons19, cons4, cons5, cons57, cons509, cons68) rule767 = ReplacementRule(pattern767, replacement767) pattern768 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons508, cons56) rule768 = ReplacementRule(pattern768, replacement768) pattern769 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons57, cons509, cons56) rule769 = ReplacementRule(pattern769, replacement769) pattern770 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons150, cons20, CustomConstraint(With770)) rule770 = ReplacementRule(pattern770, replacement770) pattern771 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons5, cons57, cons497, cons20, CustomConstraint(With771)) rule771 = ReplacementRule(pattern771, replacement771) pattern772 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons150, cons246, cons165, cons96, cons510, cons511) rule772 = ReplacementRule(pattern772, replacement772) pattern773 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons57, cons497, cons246, cons165, cons512, cons513) rule773 = ReplacementRule(pattern773, replacement773) pattern774 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons150, cons246, cons165, cons514, cons511) rule774 = ReplacementRule(pattern774, replacement774) pattern775 = Pattern(Integral(x_**S(2)/(a_ + x_**S(4)*WC('b', S(1)))**(S(5)/4), x_), cons2, cons3, cons468) rule775 = ReplacementRule(pattern775, replacement775) pattern776 = Pattern(Integral(x_**m_/(a_ + x_**S(4)*WC('b', S(1)))**(S(5)/4), x_), cons2, cons3, cons468, cons515) rule776 = ReplacementRule(pattern776, replacement776) pattern777 = Pattern(Integral(x_**m_/(a_ + x_**S(4)*WC('b', S(1)))**(S(5)/4), x_), cons2, cons3, cons468, cons516) rule777 = ReplacementRule(pattern777, replacement777) pattern778 = Pattern(Integral(sqrt(x_*WC('c', S(1)))/(a_ + x_**S(2)*WC('b', S(1)))**(S(5)/4), x_), cons2, cons3, cons8, cons468) rule778 = ReplacementRule(pattern778, replacement778) pattern779 = Pattern(Integral((x_*WC('c', S(1)))**m_/(a_ + x_**S(2)*WC('b', S(1)))**(S(5)/4), x_), cons2, cons3, cons8, cons468, cons517, cons518) rule779 = ReplacementRule(pattern779, replacement779) pattern780 = Pattern(Integral((x_*WC('c', S(1)))**m_/(a_ + x_**S(2)*WC('b', S(1)))**(S(5)/4), x_), cons2, cons3, cons8, cons468, cons517, cons96) rule780 = ReplacementRule(pattern780, replacement780) pattern781 = Pattern(Integral(x_**S(2)/(a_ + x_**S(4)*WC('b', S(1)))**(S(5)/4), x_), cons2, cons3, cons485) rule781 = ReplacementRule(pattern781, replacement781) pattern782 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons150, cons246, cons139, cons519, cons520, cons511) rule782 = ReplacementRule(pattern782, replacement782) pattern783 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons57, cons497, cons246, cons139, cons521, cons522, cons513) rule783 = ReplacementRule(pattern783, replacement783) pattern784 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons150, cons246, cons139, cons511) rule784 = ReplacementRule(pattern784, replacement784) pattern785 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons57, cons497, cons246, cons139, cons513) rule785 = ReplacementRule(pattern785, replacement785) pattern786 = Pattern(Integral(x_/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons69) rule786 = ReplacementRule(pattern786, replacement786) pattern787 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons523, cons64, cons524, cons470) rule787 = ReplacementRule(pattern787, With787) pattern788 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons525, cons64, cons524, cons471) rule788 = ReplacementRule(pattern788, With788) pattern789 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons526, cons64, cons524, cons470) rule789 = ReplacementRule(pattern789, With789) pattern790 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons526, cons64, cons524, cons471) rule790 = ReplacementRule(pattern790, With790) pattern791 = Pattern(Integral(x_**S(2)/(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons477) rule791 = ReplacementRule(pattern791, With791) pattern792 = Pattern(Integral(x_**S(2)/(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons478) rule792 = ReplacementRule(pattern792, With792) pattern793 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons527, cons64, cons524, cons480) rule793 = ReplacementRule(pattern793, With793) pattern794 = Pattern(Integral(x_**m_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons527, cons64, cons528, cons478) rule794 = ReplacementRule(pattern794, With794) pattern795 = Pattern(Integral(x_**m_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons527, cons64, cons529, cons478) rule795 = ReplacementRule(pattern795, With795) pattern796 = Pattern(Integral(x_**m_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons530, cons531) rule796 = ReplacementRule(pattern796, replacement796) pattern797 = Pattern(Integral(x_/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons483) rule797 = ReplacementRule(pattern797, With797) pattern798 = Pattern(Integral(x_/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons484) rule798 = ReplacementRule(pattern798, With798) pattern799 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons468) rule799 = ReplacementRule(pattern799, With799) pattern800 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons486, cons107) rule800 = ReplacementRule(pattern800, With800) pattern801 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons485) rule801 = ReplacementRule(pattern801, With801) pattern802 = Pattern(Integral(x_**S(4)/sqrt(a_ + x_**S(6)*WC('b', S(1))), x_), cons2, cons3, cons69) rule802 = ReplacementRule(pattern802, With802) pattern803 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(8)*WC('b', S(1))), x_), cons2, cons3, cons69) rule803 = ReplacementRule(pattern803, replacement803) pattern804 = Pattern(Integral(x_**S(2)/(a_ + x_**S(4)*WC('b', S(1)))**(S(1)/4), x_), cons2, cons3, cons468) rule804 = ReplacementRule(pattern804, replacement804) pattern805 = Pattern(Integral(x_**S(2)/(a_ + x_**S(4)*WC('b', S(1)))**(S(1)/4), x_), cons2, cons3, cons485) rule805 = ReplacementRule(pattern805, replacement805) pattern806 = Pattern(Integral(S(1)/(x_**S(2)*(a_ + x_**S(4)*WC('b', S(1)))**(S(1)/4)), x_), cons2, cons3, cons468) rule806 = ReplacementRule(pattern806, replacement806) pattern807 = Pattern(Integral(S(1)/(x_**S(2)*(a_ + x_**S(4)*WC('b', S(1)))**(S(1)/4)), x_), cons2, cons3, cons485) rule807 = ReplacementRule(pattern807, replacement807) pattern808 = Pattern(Integral(sqrt(c_*x_)/(a_ + x_**S(2)*WC('b', S(1)))**(S(1)/4), x_), cons2, cons3, cons8, cons468) rule808 = ReplacementRule(pattern808, replacement808) pattern809 = Pattern(Integral(sqrt(c_*x_)/(a_ + x_**S(2)*WC('b', S(1)))**(S(1)/4), x_), cons2, cons3, cons8, cons485) rule809 = ReplacementRule(pattern809, replacement809) pattern810 = Pattern(Integral(S(1)/((x_*WC('c', S(1)))**(S(3)/2)*(a_ + x_**S(2)*WC('b', S(1)))**(S(1)/4)), x_), cons2, cons3, cons8, cons468) rule810 = ReplacementRule(pattern810, replacement810) pattern811 = Pattern(Integral(S(1)/((x_*WC('c', S(1)))**(S(3)/2)*(a_ + x_**S(2)*WC('b', S(1)))**(S(1)/4)), x_), cons2, cons3, cons8, cons485) rule811 = ReplacementRule(pattern811, replacement811) pattern812 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons150, cons33, cons532, cons514, cons511) rule812 = ReplacementRule(pattern812, replacement812) pattern813 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons150, cons533, cons514, cons534) rule813 = ReplacementRule(pattern813, replacement813) pattern814 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons5, cons57, cons497, cons33, cons531, cons512, cons513) rule814 = ReplacementRule(pattern814, replacement814) pattern815 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons5, cons57, cons497, cons535, cons512, cons536) rule815 = ReplacementRule(pattern815, replacement815) pattern816 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons150, cons33, cons96, cons511) rule816 = ReplacementRule(pattern816, replacement816) pattern817 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons150, cons537, cons534) rule817 = ReplacementRule(pattern817, replacement817) pattern818 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons5, cons57, cons497, cons33, cons96, cons513) rule818 = ReplacementRule(pattern818, replacement818) pattern819 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons5, cons57, cons497, cons538, cons536) rule819 = ReplacementRule(pattern819, replacement819) pattern820 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons150, cons369, cons511) rule820 = ReplacementRule(pattern820, With820) pattern821 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons5, cons57, cons497, cons369, cons513) rule821 = ReplacementRule(pattern821, With821) pattern822 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons150, cons13, cons487, cons488, cons539) rule822 = ReplacementRule(pattern822, replacement822) pattern823 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons57, cons497, cons13, cons487, cons488, cons540) rule823 = ReplacementRule(pattern823, replacement823) pattern824 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons150, cons13, cons487, cons488, cons20, cons541) rule824 = ReplacementRule(pattern824, replacement824) pattern825 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons57, cons497, cons13, cons487, cons488, cons20, cons542) rule825 = ReplacementRule(pattern825, replacement825) pattern826 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons198, cons20) rule826 = ReplacementRule(pattern826, replacement826) pattern827 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons5, cons57, cons499, cons20) rule827 = ReplacementRule(pattern827, replacement827) pattern828 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons198, cons369) rule828 = ReplacementRule(pattern828, With828) pattern829 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons5, cons57, cons499, cons369) rule829 = ReplacementRule(pattern829, With829) pattern830 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons198, cons358) rule830 = ReplacementRule(pattern830, replacement830) pattern831 = Pattern(Integral((x_*WC('c', S(1)))**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons5, cons57, cons499, cons358) rule831 = ReplacementRule(pattern831, replacement831) pattern832 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons5, cons491) rule832 = ReplacementRule(pattern832, With832) pattern833 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons19, cons5, cons57, cons500) rule833 = ReplacementRule(pattern833, With833) pattern834 = Pattern(Integral((c_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons491) rule834 = ReplacementRule(pattern834, replacement834) pattern835 = Pattern(Integral((c_*x_)**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons5, cons57, cons500) rule835 = ReplacementRule(pattern835, replacement835) pattern836 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons5, cons543, cons25) rule836 = ReplacementRule(pattern836, replacement836) pattern837 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons19, cons4, cons5, cons57, cons544, cons545) rule837 = ReplacementRule(pattern837, replacement837) pattern838 = Pattern(Integral((c_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons543, cons25) rule838 = ReplacementRule(pattern838, replacement838) pattern839 = Pattern(Integral((c_*x_)**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons57, cons544, cons545) rule839 = ReplacementRule(pattern839, replacement839) pattern840 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons546, cons13, cons165) rule840 = ReplacementRule(pattern840, replacement840) pattern841 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons19, cons4, cons57, cons547, cons13, cons165) rule841 = ReplacementRule(pattern841, replacement841) pattern842 = Pattern(Integral((c_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons546, cons13, cons165) rule842 = ReplacementRule(pattern842, replacement842) pattern843 = Pattern(Integral((c_*x_)**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons57, cons547, cons13, cons165) rule843 = ReplacementRule(pattern843, replacement843) pattern844 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons548, cons13, cons165, cons514) rule844 = ReplacementRule(pattern844, replacement844) pattern845 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons57, cons549, cons13, cons165, cons512) rule845 = ReplacementRule(pattern845, replacement845) pattern846 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons548, cons13, cons487) rule846 = ReplacementRule(pattern846, With846) pattern847 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons19, cons4, cons57, cons549, cons13, cons487) rule847 = ReplacementRule(pattern847, With847) pattern848 = Pattern(Integral((c_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons548, cons13, cons487) rule848 = ReplacementRule(pattern848, replacement848) pattern849 = Pattern(Integral((c_*x_)**m_*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons57, cons549, cons13, cons487) rule849 = ReplacementRule(pattern849, replacement849) pattern850 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons548, cons13, cons139) rule850 = ReplacementRule(pattern850, replacement850) pattern851 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons57, cons548, cons13, cons139) rule851 = ReplacementRule(pattern851, replacement851) pattern852 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons19, cons4, cons550, cons533) rule852 = ReplacementRule(pattern852, With852) pattern853 = Pattern(Integral(x_**m_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons19, cons4, cons550, cons537) rule853 = ReplacementRule(pattern853, replacement853) pattern854 = Pattern(Integral((c_*x_)**m_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons19, cons4, cons550, cons551) rule854 = ReplacementRule(pattern854, replacement854) pattern855 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons359, cons552) rule855 = ReplacementRule(pattern855, replacement855) pattern856 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons359, cons553) rule856 = ReplacementRule(pattern856, replacement856) pattern857 = Pattern(Integral(x_**WC('m', S(1))*(a_ + v_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons4, cons5, cons554, cons20, cons555) rule857 = ReplacementRule(pattern857, replacement857) pattern858 = Pattern(Integral(u_**WC('m', S(1))*(a_ + v_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons19, cons4, cons5, cons556) rule858 = ReplacementRule(pattern858, replacement858) pattern859 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**n_*WC('b1', S(1)))**p_*(a2_ + x_**n_*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons57, cons149) rule859 = ReplacementRule(pattern859, replacement859) pattern860 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons73, cons557) rule860 = ReplacementRule(pattern860, replacement860) pattern861 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons73, cons222, cons504) rule861 = ReplacementRule(pattern861, replacement861) pattern862 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons52, cons73, cons198) rule862 = ReplacementRule(pattern862, replacement862) pattern863 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons52, cons73, cons491) rule863 = ReplacementRule(pattern863, With863) pattern864 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons558, cons87) rule864 = ReplacementRule(pattern864, replacement864) pattern865 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons73, cons559, cons397, cons405, cons56) rule865 = ReplacementRule(pattern865, replacement865) pattern866 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons52, cons73, cons559, cons65) rule866 = ReplacementRule(pattern866, replacement866) pattern867 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons73, cons559) rule867 = ReplacementRule(pattern867, replacement867) pattern868 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons73, cons560, cons561) rule868 = ReplacementRule(pattern868, replacement868) pattern869 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons52, cons73, cons560, cons562, cons56) rule869 = ReplacementRule(pattern869, replacement869) pattern870 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons73, cons563) rule870 = ReplacementRule(pattern870, replacement870) pattern871 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons73, cons564) rule871 = ReplacementRule(pattern871, replacement871) pattern872 = Pattern(Integral((c_ + x_**n_*WC('d', S(1)))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons73, cons89, cons465) rule872 = ReplacementRule(pattern872, replacement872) pattern873 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons73, cons565) rule873 = ReplacementRule(pattern873, replacement873) pattern874 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons73, cons466, cons566, cons567) rule874 = ReplacementRule(pattern874, replacement874) pattern875 = Pattern(Integral(S(1)/((a_ + x_**n_*WC('b', S(1)))*(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons4, cons73) rule875 = ReplacementRule(pattern875, replacement875) pattern876 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))**(S(1)/3)*(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons568, cons468) rule876 = ReplacementRule(pattern876, replacement876) pattern877 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))**(S(1)/3)*(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons568, cons485) rule877 = ReplacementRule(pattern877, replacement877) pattern878 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**(S(2)/3)/(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons568) rule878 = ReplacementRule(pattern878, replacement878) pattern879 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))**(S(1)/4)*(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73) rule879 = ReplacementRule(pattern879, replacement879) pattern880 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))**(S(3)/4)*(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73) rule880 = ReplacementRule(pattern880, replacement880) pattern881 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**WC('p', S(1))/(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons13, cons165, cons569) rule881 = ReplacementRule(pattern881, replacement881) pattern882 = Pattern(Integral((a_ + x_**S(2)*WC('b', S(1)))**p_/(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons13, cons139, cons570, cons571) rule882 = ReplacementRule(pattern882, replacement882) pattern883 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('b', S(1)))/(c_ + x_**S(4)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons72, cons572) rule883 = ReplacementRule(pattern883, replacement883) pattern884 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('b', S(1)))/(c_ + x_**S(4)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons72, cons573) rule884 = ReplacementRule(pattern884, With884) pattern885 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('b', S(1)))/(c_ + x_**S(4)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73) rule885 = ReplacementRule(pattern885, replacement885) pattern886 = Pattern(Integral((a_ + x_**S(4)*WC('b', S(1)))**(S(1)/4)/(c_ + x_**S(4)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73) rule886 = ReplacementRule(pattern886, replacement886) pattern887 = Pattern(Integral((a_ + x_**S(4)*WC('b', S(1)))**p_/(c_ + x_**S(4)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons13, cons574) rule887 = ReplacementRule(pattern887, replacement887) pattern888 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('b', S(1)))*(c_ + x_**S(4)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73) rule888 = ReplacementRule(pattern888, replacement888) pattern889 = Pattern(Integral(S(1)/((a_ + x_**S(4)*WC('b', S(1)))**(S(3)/4)*(c_ + x_**S(4)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73) rule889 = ReplacementRule(pattern889, replacement889) pattern890 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons468, cons575) rule890 = ReplacementRule(pattern890, replacement890) pattern891 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons73, cons404, cons139, cons576, cons577) rule891 = ReplacementRule(pattern891, replacement891) pattern892 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons73, cons404, cons139, cons578, cons577) rule892 = ReplacementRule(pattern892, replacement892) pattern893 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons52, cons73, cons13, cons139, cons407, cons577) rule893 = ReplacementRule(pattern893, replacement893) pattern894 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons73, cons150, cons222, cons579) rule894 = ReplacementRule(pattern894, replacement894) pattern895 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons73, cons397, cons578, cons580, cons581, cons577) rule895 = ReplacementRule(pattern895, replacement895) pattern896 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons73, cons404, cons405, cons165, cons577) rule896 = ReplacementRule(pattern896, replacement896) pattern897 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons575, cons468, cons582) rule897 = ReplacementRule(pattern897, replacement897) pattern898 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons583, cons179, cons45, cons584) rule898 = ReplacementRule(pattern898, replacement898) pattern899 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons583, cons179, cons585) rule899 = ReplacementRule(pattern899, replacement899) pattern900 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons119) rule900 = ReplacementRule(pattern900, replacement900) pattern901 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/sqrt(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons575, cons468) rule901 = ReplacementRule(pattern901, replacement901) pattern902 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/sqrt(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons575, cons485) rule902 = ReplacementRule(pattern902, replacement902) pattern903 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/sqrt(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons583, cons179, cons45) rule903 = ReplacementRule(pattern903, replacement903) pattern904 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/sqrt(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons583, cons179, cons585) rule904 = ReplacementRule(pattern904, replacement904) pattern905 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/sqrt(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons583, cons179, cons450) rule905 = ReplacementRule(pattern905, replacement905) pattern906 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/sqrt(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons583, cons119) rule906 = ReplacementRule(pattern906, replacement906) pattern907 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons52, cons73, cons130) rule907 = ReplacementRule(pattern907, replacement907) pattern908 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons73, cons586, cons45, cons179) rule908 = ReplacementRule(pattern908, replacement908) pattern909 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons73, cons586, cons450) rule909 = ReplacementRule(pattern909, replacement909) pattern910 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons587, cons588, cons589) rule910 = ReplacementRule(pattern910, replacement910) pattern911 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons587, cons388, cons149) rule911 = ReplacementRule(pattern911, replacement911) pattern912 = Pattern(Integral((u_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**n_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons70, cons71) rule912 = ReplacementRule(pattern912, replacement912) pattern913 = Pattern(Integral(u_**WC('p', S(1))*v_**WC('q', S(1)), x_), cons5, cons52, cons590) rule913 = ReplacementRule(pattern913, replacement913) pattern914 = Pattern(Integral(u_**WC('p', S(1))*v_**WC('q', S(1))*x_**WC('m', S(1)), x_), cons5, cons52, cons591, cons592) rule914 = ReplacementRule(pattern914, replacement914) pattern915 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons593, cons502) rule915 = ReplacementRule(pattern915, replacement915) pattern916 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons593, cons503) rule916 = ReplacementRule(pattern916, replacement916) pattern917 = Pattern(Integral((e_*x_)**m_*(x_**WC('n', S(1))*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons21) rule917 = ReplacementRule(pattern917, replacement917) pattern918 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons52, cons73, cons55) rule918 = ReplacementRule(pattern918, replacement918) pattern919 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons73, cons222, cons504) rule919 = ReplacementRule(pattern919, replacement919) pattern920 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons52, cons73, cons502) rule920 = ReplacementRule(pattern920, replacement920) pattern921 = Pattern(Integral((e_*x_)**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons73, cons502) rule921 = ReplacementRule(pattern921, replacement921) pattern922 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons73, cons557) rule922 = ReplacementRule(pattern922, replacement922) pattern923 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons73, cons594, cons68) rule923 = ReplacementRule(pattern923, replacement923) pattern924 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons50, cons19, cons4, cons5, cons595, cons57, cons596, cons68) rule924 = ReplacementRule(pattern924, replacement924) pattern925 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons73, cons597, cons598, cons95, cons599) rule925 = ReplacementRule(pattern925, replacement925) pattern926 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons73, cons597, cons68) rule926 = ReplacementRule(pattern926, replacement926) pattern927 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons73, cons598, cons95, cons599, cons600) rule927 = ReplacementRule(pattern927, replacement927) pattern928 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons50, cons5, cons595, cons57, cons598, cons95, cons599, cons600) rule928 = ReplacementRule(pattern928, replacement928) pattern929 = Pattern(Integral(x_**m_*(a_ + x_**S(2)*WC('b', S(1)))**p_*(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons13, cons139, cons601, cons602) rule929 = ReplacementRule(pattern929, replacement929) pattern930 = Pattern(Integral(x_**m_*(a_ + x_**S(2)*WC('b', S(1)))**p_*(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons13, cons139, cons603, cons602) rule930 = ReplacementRule(pattern930, replacement930) pattern931 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons73, cons13, cons139, cons604) rule931 = ReplacementRule(pattern931, replacement931) pattern932 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons50, cons19, cons4, cons595, cons57, cons13, cons139, cons604) rule932 = ReplacementRule(pattern932, replacement932) pattern933 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons73, cons605) rule933 = ReplacementRule(pattern933, replacement933) pattern934 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1))), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons50, cons19, cons4, cons5, cons595, cons57, cons605) rule934 = ReplacementRule(pattern934, replacement934) pattern935 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons73, cons150, cons130, cons606) rule935 = ReplacementRule(pattern935, replacement935) pattern936 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons73, cons150, cons95, cons96, cons90) rule936 = ReplacementRule(pattern936, replacement936) pattern937 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons73, cons150, cons13, cons139) rule937 = ReplacementRule(pattern937, replacement937) pattern938 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons73, cons150, cons607) rule938 = ReplacementRule(pattern938, replacement938) pattern939 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons5, cons52, cons73, cons150, cons20, CustomConstraint(With939)) rule939 = ReplacementRule(pattern939, replacement939) pattern940 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons73, cons150, cons369, cons40) rule940 = ReplacementRule(pattern940, With940) pattern941 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons73, cons150, cons608, cons139, cons405, cons609, cons610) rule941 = ReplacementRule(pattern941, replacement941) pattern942 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons73, cons150, cons404, cons139, cons578, cons610) rule942 = ReplacementRule(pattern942, replacement942) pattern943 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons73, cons150, cons404, cons139, cons576, cons610) rule943 = ReplacementRule(pattern943, replacement943) pattern944 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons52, cons73, cons150, cons246, cons139, cons611, cons610) rule944 = ReplacementRule(pattern944, replacement944) pattern945 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons52, cons73, cons150, cons246, cons139, cons612, cons610) rule945 = ReplacementRule(pattern945, replacement945) pattern946 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons52, cons73, cons150, cons13, cons139, cons610) rule946 = ReplacementRule(pattern946, replacement946) pattern947 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons73, cons150, cons608, cons405, cons96, cons165, cons610) rule947 = ReplacementRule(pattern947, replacement947) pattern948 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons73, cons150, cons613, cons578, cons96, cons610) rule948 = ReplacementRule(pattern948, replacement948) pattern949 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons73, cons150, cons613, cons576, cons96, cons610) rule949 = ReplacementRule(pattern949, replacement949) pattern950 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons73, cons150, cons404, cons405, cons165, cons610) rule950 = ReplacementRule(pattern950, replacement950) pattern951 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons73, cons150, cons397, cons578, cons610) rule951 = ReplacementRule(pattern951, replacement951) pattern952 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons73, cons150, cons613, cons405, cons609, cons610) rule952 = ReplacementRule(pattern952, replacement952) pattern953 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons73, cons150, cons33, cons611, cons610) rule953 = ReplacementRule(pattern953, replacement953) pattern954 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons73, cons150, cons33, cons96, cons610) rule954 = ReplacementRule(pattern954, replacement954) pattern955 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))/((a_ + x_**n_*WC('b', S(1)))*(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons73, cons150, cons33, cons614) rule955 = ReplacementRule(pattern955, replacement955) pattern956 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))/((a_ + x_**n_*WC('b', S(1)))*(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons73, cons150) rule956 = ReplacementRule(pattern956, replacement956) pattern957 = Pattern(Integral(x_**m_/((a_ + x_**n_*WC('b', S(1)))*sqrt(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons615, cons616, cons617) rule957 = ReplacementRule(pattern957, replacement957) pattern958 = Pattern(Integral(x_**S(2)/((a_ + x_**S(4)*WC('b', S(1)))*sqrt(c_ + x_**S(4)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73) rule958 = ReplacementRule(pattern958, With958) pattern959 = Pattern(Integral(x_/((a_ + x_**S(3)*WC('b', S(1)))*sqrt(c_ + x_**S(3)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons618) rule959 = ReplacementRule(pattern959, With959) pattern960 = Pattern(Integral(x_**m_/((a_ + x_**S(3)*WC('b', S(1)))*sqrt(c_ + x_**S(3)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons618, cons619) rule960 = ReplacementRule(pattern960, replacement960) pattern961 = Pattern(Integral(x_**m_/((a_ + x_**S(3)*WC('b', S(1)))*sqrt(c_ + x_**S(3)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons618, cons620) rule961 = ReplacementRule(pattern961, replacement961) pattern962 = Pattern(Integral(x_**S(2)*sqrt(c_ + x_**S(4)*WC('d', S(1)))/(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons73) rule962 = ReplacementRule(pattern962, replacement962) pattern963 = Pattern(Integral(x_**WC('m', S(1))*sqrt(c_ + x_**S(3)*WC('d', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons73, cons618, cons621) rule963 = ReplacementRule(pattern963, replacement963) pattern964 = Pattern(Integral(x_**S(2)/(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons468, cons575, cons582) rule964 = ReplacementRule(pattern964, replacement964) pattern965 = Pattern(Integral(x_**n_/(sqrt(a_ + x_**n_*WC('b', S(1)))*sqrt(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons73, cons622, cons623) rule965 = ReplacementRule(pattern965, replacement965) pattern966 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons150, cons246, cons624, cons487) rule966 = ReplacementRule(pattern966, With966) pattern967 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons5, cons52, cons73, cons198, cons20) rule967 = ReplacementRule(pattern967, replacement967) pattern968 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons198, cons369) rule968 = ReplacementRule(pattern968, With968) pattern969 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons52, cons73, cons198, cons358) rule969 = ReplacementRule(pattern969, replacement969) pattern970 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons52, cons73, cons491) rule970 = ReplacementRule(pattern970, With970) pattern971 = Pattern(Integral((e_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons52, cons73, cons491) rule971 = ReplacementRule(pattern971, replacement971) pattern972 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons52, cons73, cons543, cons25) rule972 = ReplacementRule(pattern972, replacement972) pattern973 = Pattern(Integral((e_*x_)**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons73, cons543, cons25) rule973 = ReplacementRule(pattern973, replacement973) pattern974 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons73, cons404, cons139, cons578, cons610) rule974 = ReplacementRule(pattern974, replacement974) pattern975 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons73, cons404, cons139, cons576, cons610) rule975 = ReplacementRule(pattern975, replacement975) pattern976 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons52, cons73, cons13, cons139, cons610) rule976 = ReplacementRule(pattern976, replacement976) pattern977 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons73, cons404, cons405, cons165, cons610) rule977 = ReplacementRule(pattern977, replacement977) pattern978 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons73, cons397, cons578, cons610) rule978 = ReplacementRule(pattern978, replacement978) pattern979 = Pattern(Integral(x_**m_/((a_ + x_**n_*WC('b', S(1)))*(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons73, cons625) rule979 = ReplacementRule(pattern979, replacement979) pattern980 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))/((a_ + x_**n_*WC('b', S(1)))*(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons19, cons73) rule980 = ReplacementRule(pattern980, replacement980) pattern981 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons73, cons626, cons627, cons628) rule981 = ReplacementRule(pattern981, replacement981) pattern982 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons587, cons588, cons589) rule982 = ReplacementRule(pattern982, replacement982) pattern983 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons52, cons587, cons388, cons149) rule983 = ReplacementRule(pattern983, replacement983) pattern984 = Pattern(Integral((e_*x_)**m_*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons587) rule984 = ReplacementRule(pattern984, replacement984) pattern985 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons73, cons68, cons629, cons45, cons179) rule985 = ReplacementRule(pattern985, replacement985) pattern986 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons73, cons68, cons629, cons450) rule986 = ReplacementRule(pattern986, replacement986) pattern987 = Pattern(Integral(x_**WC('m', S(1))*(v_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(v_**n_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons554, cons20, cons555) rule987 = ReplacementRule(pattern987, replacement987) pattern988 = Pattern(Integral(u_**WC('m', S(1))*(v_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(v_**n_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons52, cons556) rule988 = ReplacementRule(pattern988, replacement988) pattern989 = Pattern(Integral((a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**WC('p', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('u', S(1)), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons4, cons5, cons52, cons595, cons57, cons496) rule989 = ReplacementRule(pattern989, replacement989) pattern990 = Pattern(Integral((a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**WC('p', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)) + x_**WC('n2', S(1))*WC('e', S(1)))**WC('q', S(1))*WC('u', S(1)), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons50, cons4, cons5, cons52, cons595, cons48, cons57, cons496) rule990 = ReplacementRule(pattern990, replacement990) pattern991 = Pattern(Integral((a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**p_*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**p_*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('u', S(1)), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons4, cons5, cons52, cons595, cons57) rule991 = ReplacementRule(pattern991, replacement991) pattern992 = Pattern(Integral((a1_ + x_**WC('non2', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('non2', S(1))*WC('b2', S(1)))**WC('p', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)) + x_**WC('n2', S(1))*WC('e', S(1)))**WC('q', S(1))*WC('u', S(1)), x_), cons59, cons60, cons61, cons62, cons8, cons29, cons50, cons4, cons5, cons52, cons595, cons48, cons57) rule992 = ReplacementRule(pattern992, replacement992) pattern993 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons630) rule993 = ReplacementRule(pattern993, replacement993) pattern994 = Pattern(Integral((e_ + x_**n_*WC('f', S(1)))/((a_ + x_**n_*WC('b', S(1)))*(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons631) rule994 = ReplacementRule(pattern994, replacement994) pattern995 = Pattern(Integral((e_ + x_**n_*WC('f', S(1)))/((a_ + x_**n_*WC('b', S(1)))*sqrt(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons631) rule995 = ReplacementRule(pattern995, replacement995) pattern996 = Pattern(Integral((e_ + x_**n_*WC('f', S(1)))/(sqrt(a_ + x_**n_*WC('b', S(1)))*sqrt(c_ + x_**n_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons632) rule996 = ReplacementRule(pattern996, replacement996) pattern997 = Pattern(Integral((e_ + x_**S(2)*WC('f', S(1)))/(sqrt(a_ + x_**S(2)*WC('b', S(1)))*(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons468, cons575) rule997 = ReplacementRule(pattern997, replacement997) pattern998 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons404, cons139, cons405) rule998 = ReplacementRule(pattern998, replacement998) pattern999 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons52, cons13, cons139) rule999 = ReplacementRule(pattern999, replacement999) pattern1000 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons397, cons405, cons633) rule1000 = ReplacementRule(pattern1000, replacement1000) pattern1001 = Pattern(Integral((e_ + x_**S(4)*WC('f', S(1)))/((a_ + x_**S(4)*WC('b', S(1)))**(S(3)/4)*(c_ + x_**S(4)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1001 = ReplacementRule(pattern1001, replacement1001) pattern1002 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(e_ + x_**n_*WC('f', S(1)))/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons4, cons634) rule1002 = ReplacementRule(pattern1002, replacement1002) pattern1003 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons52, cons635) rule1003 = ReplacementRule(pattern1003, replacement1003) pattern1004 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))*(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1004 = ReplacementRule(pattern1004, replacement1004) pattern1005 = Pattern(Integral(S(1)/(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons8, cons29, cons50, cons127, cons178) rule1005 = ReplacementRule(pattern1005, replacement1005) pattern1006 = Pattern(Integral(sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons636, cons637, cons638) rule1006 = ReplacementRule(pattern1006, replacement1006) pattern1007 = Pattern(Integral(sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons639) rule1007 = ReplacementRule(pattern1007, replacement1007) pattern1008 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons575, cons640, cons638) rule1008 = ReplacementRule(pattern1008, replacement1008) pattern1009 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons583, cons179, cons180, cons641) rule1009 = ReplacementRule(pattern1009, replacement1009) pattern1010 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons119) rule1010 = ReplacementRule(pattern1010, replacement1010) pattern1011 = Pattern(Integral(sqrt(c_ + x_**S(2)*WC('d', S(1)))/((a_ + x_**S(2)*WC('b', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons575) rule1011 = ReplacementRule(pattern1011, replacement1011) pattern1012 = Pattern(Integral(sqrt(c_ + x_**S(2)*WC('d', S(1)))/((a_ + x_**S(2)*WC('b', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons583) rule1012 = ReplacementRule(pattern1012, replacement1012) pattern1013 = Pattern(Integral(sqrt(e_ + x_**S(2)*WC('f', S(1)))/((a_ + x_**S(2)*WC('b', S(1)))*(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons575, cons640) rule1013 = ReplacementRule(pattern1013, replacement1013) pattern1014 = Pattern(Integral((e_ + x_**S(2)*WC('f', S(1)))**(S(3)/2)/((a_ + x_**S(2)*WC('b', S(1)))*(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons575, cons640) rule1014 = ReplacementRule(pattern1014, replacement1014) pattern1015 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2)*sqrt(e_ + x_**S(2)*WC('f', S(1)))/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons575, cons640) rule1015 = ReplacementRule(pattern1015, replacement1015) pattern1016 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**q_*(e_ + x_**S(2)*WC('f', S(1)))**r_/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons642, cons398, cons643) rule1016 = ReplacementRule(pattern1016, replacement1016) pattern1017 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**q_*(e_ + x_**S(2)*WC('f', S(1)))**r_/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons54, cons397, cons578) rule1017 = ReplacementRule(pattern1017, replacement1017) pattern1018 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**q_*(e_ + x_**S(2)*WC('f', S(1)))**r_/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons54, cons397, cons398) rule1018 = ReplacementRule(pattern1018, replacement1018) pattern1019 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**q_*(e_ + x_**S(2)*WC('f', S(1)))**r_/(a_ + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons54, cons397, cons644) rule1019 = ReplacementRule(pattern1019, replacement1019) pattern1020 = Pattern(Integral(sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))/(a_ + x_**S(2)*WC('b', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1020 = ReplacementRule(pattern1020, replacement1020) pattern1021 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('b', S(1)))**S(2)*sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1021 = ReplacementRule(pattern1021, replacement1021) pattern1022 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1)))**r_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons54, cons65, cons397, cons405) rule1022 = ReplacementRule(pattern1022, replacement1022) pattern1023 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1)))**r_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons52, cons65, cons397, cons644) rule1023 = ReplacementRule(pattern1023, replacement1023) pattern1024 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1024 = ReplacementRule(pattern1024, replacement1024) pattern1025 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))/(sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1025 = ReplacementRule(pattern1025, replacement1025) pattern1026 = Pattern(Integral(sqrt(c_ + x_**S(2)*WC('d', S(1)))/((a_ + x_**S(2)*WC('b', S(1)))**(S(3)/2)*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1026 = ReplacementRule(pattern1026, replacement1026) pattern1027 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))/sqrt(e_ + x_**S(2)*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons645) rule1027 = ReplacementRule(pattern1027, replacement1027) pattern1028 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))/sqrt(e_ + x_**S(2)*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons646) rule1028 = ReplacementRule(pattern1028, replacement1028) pattern1029 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))/(e_ + x_**S(2)*WC('f', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1029 = ReplacementRule(pattern1029, replacement1029) pattern1030 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1)))**r_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons54, cons150, CustomConstraint(With1030)) rule1030 = ReplacementRule(pattern1030, replacement1030) pattern1031 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1)))**r_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons54, cons198) rule1031 = ReplacementRule(pattern1031, replacement1031) pattern1032 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons52, cons54, cons647) rule1032 = ReplacementRule(pattern1032, replacement1032) pattern1033 = Pattern(Integral((u_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(v_**n_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1))*(w_**n_*WC('f', S(1)) + WC('e', S(0)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons4, cons52, cons54, cons648, cons649, cons70, cons71) rule1033 = ReplacementRule(pattern1033, replacement1033) pattern1034 = Pattern(Integral((c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**WC('n', S(1))*WC('f', S(1)))**WC('r', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons54, cons587, cons588) rule1034 = ReplacementRule(pattern1034, replacement1034) pattern1035 = Pattern(Integral((c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**WC('n', S(1))*WC('f', S(1)))**WC('r', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons52, cons587, cons40, cons650) rule1035 = ReplacementRule(pattern1035, replacement1035) pattern1036 = Pattern(Integral((c_ + x_**WC('mn', S(1))*WC('d', S(1)))**q_*(e_ + x_**WC('n', S(1))*WC('f', S(1)))**WC('r', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons52, cons54, cons587, cons388) rule1036 = ReplacementRule(pattern1036, replacement1036) pattern1037 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e1_ + x_**WC('n2', S(1))*WC('f1', S(1)))**WC('r', S(1))*(e2_ + x_**WC('n2', S(1))*WC('f2', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons654, cons655, cons656, cons657, cons4, cons5, cons52, cons54, cons651, cons652, cons653) rule1037 = ReplacementRule(pattern1037, replacement1037) pattern1038 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e1_ + x_**WC('n2', S(1))*WC('f1', S(1)))**WC('r', S(1))*(e2_ + x_**WC('n2', S(1))*WC('f2', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons654, cons655, cons656, cons657, cons4, cons5, cons52, cons54, cons651, cons652) rule1038 = ReplacementRule(pattern1038, replacement1038) pattern1039 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons54, cons658, cons502) rule1039 = ReplacementRule(pattern1039, replacement1039) pattern1040 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons54, cons658, cons503) rule1040 = ReplacementRule(pattern1040, replacement1040) pattern1041 = Pattern(Integral((g_*x_)**m_*(x_**WC('n', S(1))*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons54, cons21) rule1041 = ReplacementRule(pattern1041, replacement1041) pattern1042 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons659) rule1042 = ReplacementRule(pattern1042, replacement1042) pattern1043 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons54, cons55) rule1043 = ReplacementRule(pattern1043, replacement1043) pattern1044 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons660, cons504) rule1044 = ReplacementRule(pattern1044, replacement1044) pattern1045 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons54, cons502) rule1045 = ReplacementRule(pattern1045, replacement1045) pattern1046 = Pattern(Integral((g_*x_)**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons54, cons502) rule1046 = ReplacementRule(pattern1046, replacement1046) pattern1047 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons54, cons150, cons20, CustomConstraint(With1047)) rule1047 = ReplacementRule(pattern1047, replacement1047) pattern1048 = Pattern(Integral((x_*WC('g', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1)))**r_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons52, cons54, cons150, cons369) rule1048 = ReplacementRule(pattern1048, With1048) pattern1049 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons150, cons404, cons139, cons405, cons661) rule1049 = ReplacementRule(pattern1049, replacement1049) pattern1050 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons52, cons150, cons246, cons139, cons609) rule1050 = ReplacementRule(pattern1050, replacement1050) pattern1051 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons52, cons150, cons13, cons139) rule1051 = ReplacementRule(pattern1051, replacement1051) pattern1052 = Pattern(Integral((x_*WC('g', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons150, cons613, cons405, cons96, cons662) rule1052 = ReplacementRule(pattern1052, replacement1052) pattern1053 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons150, cons397, cons405, cons662) rule1053 = ReplacementRule(pattern1053, replacement1053) pattern1054 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons52, cons150, cons33, cons532) rule1054 = ReplacementRule(pattern1054, replacement1054) pattern1055 = Pattern(Integral((x_*WC('g', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons52, cons150, cons33, cons96) rule1055 = ReplacementRule(pattern1055, replacement1055) pattern1056 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(e_ + x_**n_*WC('f', S(1)))/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons150) rule1056 = ReplacementRule(pattern1056, replacement1056) pattern1057 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons52, cons150) rule1057 = ReplacementRule(pattern1057, replacement1057) pattern1058 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons52, cons150, cons663) rule1058 = ReplacementRule(pattern1058, replacement1058) pattern1059 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons54, cons198, cons20) rule1059 = ReplacementRule(pattern1059, replacement1059) pattern1060 = Pattern(Integral((x_*WC('g', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons52, cons54, cons198, cons369) rule1060 = ReplacementRule(pattern1060, With1060) pattern1061 = Pattern(Integral((x_*WC('g', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons52, cons54, cons198, cons358) rule1061 = ReplacementRule(pattern1061, replacement1061) pattern1062 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons52, cons54, cons491) rule1062 = ReplacementRule(pattern1062, With1062) pattern1063 = Pattern(Integral((g_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons52, cons54, cons491) rule1063 = ReplacementRule(pattern1063, replacement1063) pattern1064 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons54, cons543) rule1064 = ReplacementRule(pattern1064, replacement1064) pattern1065 = Pattern(Integral((g_*x_)**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons54, cons543) rule1065 = ReplacementRule(pattern1065, replacement1065) pattern1066 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons404, cons139, cons405, cons661) rule1066 = ReplacementRule(pattern1066, replacement1066) pattern1067 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons52, cons13, cons139) rule1067 = ReplacementRule(pattern1067, replacement1067) pattern1068 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons397, cons405, cons662) rule1068 = ReplacementRule(pattern1068, replacement1068) pattern1069 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(e_ + x_**n_*WC('f', S(1)))/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons382) rule1069 = ReplacementRule(pattern1069, replacement1069) pattern1070 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*(c_ + x_**n_*WC('d', S(1)))**q_*(e_ + x_**n_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons664) rule1070 = ReplacementRule(pattern1070, replacement1070) pattern1071 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**WC('n', S(1))*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons54, cons587, cons588) rule1071 = ReplacementRule(pattern1071, replacement1071) pattern1072 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**WC('n', S(1))*WC('f', S(1)))**WC('r', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons52, cons587, cons40, cons650) rule1072 = ReplacementRule(pattern1072, replacement1072) pattern1073 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**q_*(e_ + x_**WC('n', S(1))*WC('f', S(1)))**WC('r', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons54, cons587, cons388) rule1073 = ReplacementRule(pattern1073, replacement1073) pattern1074 = Pattern(Integral((g_*x_)**m_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('mn', S(1))*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**WC('n', S(1))*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons54, cons587) rule1074 = ReplacementRule(pattern1074, replacement1074) pattern1075 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e_ + x_**n_*WC('f', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons54, cons665) rule1075 = ReplacementRule(pattern1075, replacement1075) pattern1076 = Pattern(Integral(u_**WC('m', S(1))*(e_ + v_**n_*WC('f', S(1)))**WC('r', S(1))*(v_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(v_**n_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons54, cons556) rule1076 = ReplacementRule(pattern1076, replacement1076) pattern1077 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e1_ + x_**WC('n2', S(1))*WC('f1', S(1)))**WC('r', S(1))*(e2_ + x_**WC('n2', S(1))*WC('f2', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons654, cons655, cons656, cons657, cons210, cons19, cons4, cons5, cons52, cons54, cons651, cons652, cons653) rule1077 = ReplacementRule(pattern1077, replacement1077) pattern1078 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(e1_ + x_**WC('n2', S(1))*WC('f1', S(1)))**WC('r', S(1))*(e2_ + x_**WC('n2', S(1))*WC('f2', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons29, cons654, cons655, cons656, cons657, cons210, cons19, cons4, cons5, cons52, cons54, cons651, cons652) rule1078 = ReplacementRule(pattern1078, replacement1078) return [rule692, rule693, rule694, rule695, rule696, rule697, rule698, rule699, rule700, rule701, rule702, rule703, rule704, rule705, rule706, rule707, rule708, rule709, rule710, rule711, rule712, rule713, rule714, rule715, rule716, rule717, rule718, rule719, rule720, rule721, rule722, rule723, rule724, rule725, rule726, rule727, rule728, rule729, rule730, rule731, rule732, rule733, rule734, rule735, rule736, rule737, rule738, rule739, rule740, rule741, rule742, rule743, rule744, rule745, rule746, rule747, rule748, rule749, rule750, rule751, rule752, rule753, rule754, rule755, rule756, rule757, rule758, rule759, rule760, rule761, rule762, rule763, rule764, rule765, rule766, rule767, rule768, rule769, rule770, rule771, rule772, rule773, rule774, rule775, rule776, rule777, rule778, rule779, rule780, rule781, rule782, rule783, rule784, rule785, rule786, rule787, rule788, rule789, rule790, rule791, rule792, rule793, rule794, rule795, rule796, rule797, rule798, rule799, rule800, rule801, rule802, rule803, rule804, rule805, rule806, rule807, rule808, rule809, rule810, rule811, rule812, rule813, rule814, rule815, rule816, rule817, rule818, rule819, rule820, rule821, rule822, rule823, rule824, rule825, rule826, rule827, rule828, rule829, rule830, rule831, rule832, rule833, rule834, rule835, rule836, rule837, rule838, rule839, rule840, rule841, rule842, rule843, rule844, rule845, rule846, rule847, rule848, rule849, rule850, rule851, rule852, rule853, rule854, rule855, rule856, rule857, rule858, rule859, rule860, rule861, rule862, rule863, rule864, rule865, rule866, rule867, rule868, rule869, rule870, rule871, rule872, rule873, rule874, rule875, rule876, rule877, rule878, rule879, rule880, rule881, rule882, rule883, rule884, rule885, rule886, rule887, rule888, rule889, rule890, rule891, rule892, rule893, rule894, rule895, rule896, rule897, rule898, rule899, rule900, rule901, rule902, rule903, rule904, rule905, rule906, rule907, rule908, rule909, rule910, rule911, rule912, rule913, rule914, rule915, rule916, rule917, rule918, rule919, rule920, rule921, rule922, rule923, rule924, rule925, rule926, rule927, rule928, rule929, rule930, rule931, rule932, rule933, rule934, rule935, rule936, rule937, rule938, rule939, rule940, rule941, rule942, rule943, rule944, rule945, rule946, rule947, rule948, rule949, rule950, rule951, rule952, rule953, rule954, rule955, rule956, rule957, rule958, rule959, rule960, rule961, rule962, rule963, rule964, rule965, rule966, rule967, rule968, rule969, rule970, rule971, rule972, rule973, rule974, rule975, rule976, rule977, rule978, rule979, rule980, rule981, rule982, rule983, rule984, rule985, rule986, rule987, rule988, rule989, rule990, rule991, rule992, rule993, rule994, rule995, rule996, rule997, rule998, rule999, rule1000, rule1001, rule1002, rule1003, rule1004, rule1005, rule1006, rule1007, rule1008, rule1009, rule1010, rule1011, rule1012, rule1013, rule1014, rule1015, rule1016, rule1017, rule1018, rule1019, rule1020, rule1021, rule1022, rule1023, rule1024, rule1025, rule1026, rule1027, rule1028, rule1029, rule1030, rule1031, rule1032, rule1033, rule1034, rule1035, rule1036, rule1037, rule1038, rule1039, rule1040, rule1041, rule1042, rule1043, rule1044, rule1045, rule1046, rule1047, rule1048, rule1049, rule1050, rule1051, rule1052, rule1053, rule1054, rule1055, rule1056, rule1057, rule1058, rule1059, rule1060, rule1061, rule1062, rule1063, rule1064, rule1065, rule1066, rule1067, rule1068, rule1069, rule1070, rule1071, rule1072, rule1073, rule1074, rule1075, rule1076, rule1077, rule1078, ] def replacement692(b, n, p, x): return Dist(b**IntPart(p)*x**(-n*FracPart(p))*(b*x**n)**FracPart(p), Int(x**(n*p), x), x) def replacement693(a, b, n, p, x): return Simp(x*(a + b*x**n)**(p + S(1))/a, x) def replacement694(a, b, n, p, x): return Dist((n*(p + S(1)) + S(1))/(a*n*(p + S(1))), Int((a + b*x**n)**(p + S(1)), x), x) - Simp(x*(a + b*x**n)**(p + S(1))/(a*n*(p + S(1))), x) def replacement695(a, b, n, x): return Int(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n), x) def replacement696(a, b, n, p, x): return Int(x**(n*p)*(a*x**(-n) + b)**p, x) def replacement697(a, b, n, p, x): return Int(ExpandIntegrand((a + b*x**n)**p, x), x) def replacement698(a, b, n, p, x): return Dist(a*n*p/(n*p + S(1)), Int((a + b*x**n)**(p + S(-1)), x), x) + Simp(x*(a + b*x**n)**p/(n*p + S(1)), x) def replacement699(a, b, x): return Simp(S(2)*EllipticE(ArcTan(x*Rt(b/a, S(2)))/S(2), S(2))/(a**(S(5)/4)*Rt(b/a, S(2))), x) def replacement700(a, b, x): return Dist((S(1) + b*x**S(2)/a)**(S(1)/4)/(a*(a + b*x**S(2))**(S(1)/4)), Int((S(1) + b*x**S(2)/a)**(S(-5)/4), x), x) def replacement701(a, b, x): return Dist(S(1)/((a/(a + b*x**S(2)))**(S(2)/3)*(a + b*x**S(2))**(S(2)/3)), Subst(Int((-b*x**S(2) + S(1))**(S(-1)/3), x), x, x/sqrt(a + b*x**S(2))), x) def replacement702(a, b, n, p, x): return Dist((n*(p + S(1)) + S(1))/(a*n*(p + S(1))), Int((a + b*x**n)**(p + S(1)), x), x) - Simp(x*(a + b*x**n)**(p + S(1))/(a*n*(p + S(1))), x) def replacement703(a, b, x): return Dist(S(1)/(S(3)*Rt(a, S(3))**S(2)), Int((-x*Rt(b, S(3)) + S(2)*Rt(a, S(3)))/(x**S(2)*Rt(b, S(3))**S(2) - x*Rt(a, S(3))*Rt(b, S(3)) + Rt(a, S(3))**S(2)), x), x) + Dist(S(1)/(S(3)*Rt(a, S(3))**S(2)), Int(S(1)/(x*Rt(b, S(3)) + Rt(a, S(3))), x), x) def With704(a, b, n, x): r = Numerator(Rt(a/b, n)) s = Denominator(Rt(a/b, n)) k = Symbol('k') u = Symbol('u') u = Int((r - s*x*cos(Pi*(S(2)*k + S(-1))/n))/(r**S(2) - S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) u = Int((r - s*x*cos(Pi*(2*k - 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) return Simp(Dist(2*r/(a*n), Sum_doit(u, List(k, 1, n/2 - 1/2)), x) + r*Int(1/(r + s*x), x)/(a*n), x) def With705(a, b, n, x): r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) k = Symbol('k') u = Symbol('u') u = Int((r + s*x*cos(Pi*(S(2)*k + S(-1))/n))/(r**S(2) + S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) u = Int((r + s*x*cos(Pi*(2*k - 1)/n))/(r**2 + 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) return Simp(Dist(2*r/(a*n), Sum_doit(u, List(k, 1, n/2 - 1/2)), x) + r*Int(1/(r - s*x), x)/(a*n), x) def replacement706(a, b, x): return Simp(ArcTan(x*Rt(b, S(2))/Rt(a, S(2)))/(Rt(a, S(2))*Rt(b, S(2))), x) def replacement707(a, b, x): return -Simp(ArcTan(x*Rt(-b, S(2))/Rt(-a, S(2)))/(Rt(-a, S(2))*Rt(-b, S(2))), x) def replacement708(a, b, x): return Simp(ArcTan(x/Rt(a/b, S(2)))*Rt(a/b, S(2))/a, x) def replacement709(a, b, x): return Simp(atanh(x*Rt(-b, S(2))/Rt(a, S(2)))/(Rt(a, S(2))*Rt(-b, S(2))), x) def replacement710(a, b, x): return -Simp(atanh(x*Rt(b, S(2))/Rt(-a, S(2)))/(Rt(-a, S(2))*Rt(b, S(2))), x) def replacement711(a, b, x): return Simp(Rt(-a/b, S(2))*atanh(x/Rt(-a/b, S(2)))/a, x) def With712(a, b, n, x): r = Numerator(Rt(a/b, n)) s = Denominator(Rt(a/b, n)) k = Symbol('k') u = Symbol('u') v = Symbol('v') u = Int((r - s*x*cos(Pi*(S(2)*k + S(-1))/n))/(r**S(2) - S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) + Int((r + s*x*cos(Pi*(S(2)*k + S(-1))/n))/(r**S(2) + S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) u = Int((r - s*x*cos(Pi*(2*k - 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) + Int((r + s*x*cos(Pi*(2*k - 1)/n))/(r**2 + 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) return Simp(Dist(2*r/(a*n), Sum_doit(u, List(k, 1, n/4 - 1/2)), x) + 2*r**2*Int(1/(r**2 + s**2*x**2), x)/(a*n), x) def With713(a, b, n, x): r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) k = Symbol('k') u = Symbol('u') u = Int((r - s*x*cos(S(2)*Pi*k/n))/(r**S(2) - S(2)*r*s*x*cos(S(2)*Pi*k/n) + s**S(2)*x**S(2)), x) + Int((r + s*x*cos(S(2)*Pi*k/n))/(r**S(2) + S(2)*r*s*x*cos(S(2)*Pi*k/n) + s**S(2)*x**S(2)), x) u = Int((r - s*x*cos(2*Pi*k/n))/(r**2 - 2*r*s*x*cos(2*Pi*k/n) + s**2*x**2), x) + Int((r + s*x*cos(2*Pi*k/n))/(r**2 + 2*r*s*x*cos(2*Pi*k/n) + s**2*x**2), x) return Simp(Dist(2*r/(a*n), Sum_doit(u, List(k, 1, n/4 - 1/2)), x) + 2*r**2*Int(1/(r**2 - s**2*x**2), x)/(a*n), x) def With714(a, b, x): r = Numerator(Rt(a/b, S(2))) s = Denominator(Rt(a/b, S(2))) return Dist(S(1)/(S(2)*r), Int((r - s*x**S(2))/(a + b*x**S(4)), x), x) + Dist(S(1)/(S(2)*r), Int((r + s*x**S(2))/(a + b*x**S(4)), x), x) def With715(a, b, x): r = Numerator(Rt(-a/b, S(2))) s = Denominator(Rt(-a/b, S(2))) return Dist(r/(S(2)*a), Int(S(1)/(r - s*x**S(2)), x), x) + Dist(r/(S(2)*a), Int(S(1)/(r + s*x**S(2)), x), x) def With716(a, b, n, x): r = Numerator(Rt(a/b, S(4))) s = Denominator(Rt(a/b, S(4))) return Dist(sqrt(S(2))*r/(S(4)*a), Int((sqrt(S(2))*r - s*x**(n/S(4)))/(r**S(2) - sqrt(S(2))*r*s*x**(n/S(4)) + s**S(2)*x**(n/S(2))), x), x) + Dist(sqrt(S(2))*r/(S(4)*a), Int((sqrt(S(2))*r + s*x**(n/S(4)))/(r**S(2) + sqrt(S(2))*r*s*x**(n/S(4)) + s**S(2)*x**(n/S(2))), x), x) def With717(a, b, n, x): r = Numerator(Rt(-a/b, S(2))) s = Denominator(Rt(-a/b, S(2))) return Dist(r/(S(2)*a), Int(S(1)/(r - s*x**(n/S(2))), x), x) + Dist(r/(S(2)*a), Int(S(1)/(r + s*x**(n/S(2))), x), x) def replacement718(a, b, x): return Simp(asinh(x*Rt(b, S(2))/sqrt(a))/Rt(b, S(2)), x) def replacement719(a, b, x): return Simp(asin(x*Rt(-b, S(2))/sqrt(a))/Rt(-b, S(2)), x) def replacement720(a, b, x): return Subst(Int(S(1)/(-b*x**S(2) + S(1)), x), x, x/sqrt(a + b*x**S(2))) def With721(a, b, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Simp(S(2)*S(3)**(S(3)/4)*sqrt((r**S(2)*x**S(2) - r*s*x + s**S(2))/(r*x + s*(S(1) + sqrt(S(3))))**S(2))*sqrt(sqrt(S(3)) + S(2))*(r*x + s)*EllipticF(asin((r*x + s*(S(1) - sqrt(S(3))))/(r*x + s*(S(1) + sqrt(S(3))))), S(-7) - S(4)*sqrt(S(3)))/(S(3)*r*sqrt(s*(r*x + s)/(r*x + s*(S(1) + sqrt(S(3))))**S(2))*sqrt(a + b*x**S(3))), x) def With722(a, b, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Simp(S(2)*S(3)**(S(3)/4)*sqrt((r**S(2)*x**S(2) - r*s*x + s**S(2))/(r*x + s*(S(1) - sqrt(S(3))))**S(2))*sqrt(S(2) - sqrt(S(3)))*(r*x + s)*EllipticF(asin((r*x + s*(S(1) + sqrt(S(3))))/(r*x + s*(S(1) - sqrt(S(3))))), S(-7) + S(4)*sqrt(S(3)))/(S(3)*r*sqrt(-s*(r*x + s)/(r*x + s*(S(1) - sqrt(S(3))))**S(2))*sqrt(a + b*x**S(3))), x) def With723(a, b, x): q = Rt(b/a, S(4)) return Simp(sqrt((a + b*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(q**S(2)*x**S(2) + S(1))*EllipticF(S(2)*ArcTan(q*x), S(1)/2)/(S(2)*q*sqrt(a + b*x**S(4))), x) def replacement724(a, b, x): return Simp(EllipticF(asin(x*Rt(-b, S(4))/Rt(a, S(4))), S(-1))/(Rt(a, S(4))*Rt(-b, S(4))), x) def With725(a, b, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-a*b, S(2)) if IntegerQ(q): return True return False def replacement725(a, b, x): q = Rt(-a*b, S(2)) return Simp(sqrt(S(2))*sqrt((a + q*x**S(2))/q)*sqrt(-a + q*x**S(2))*EllipticF(asin(sqrt(S(2))*x/sqrt((a + q*x**S(2))/q)), S(1)/2)/(S(2)*sqrt(-a)*sqrt(a + b*x**S(4))), x) def With726(a, b, x): q = Rt(-a*b, S(2)) return Simp(sqrt(S(2))*sqrt((a + q*x**S(2))/q)*sqrt((a - q*x**S(2))/(a + q*x**S(2)))*EllipticF(asin(sqrt(S(2))*x/sqrt((a + q*x**S(2))/q)), S(1)/2)/(S(2)*sqrt(a/(a + q*x**S(2)))*sqrt(a + b*x**S(4))), x) def replacement727(a, b, x): return Dist(sqrt(S(1) + b*x**S(4)/a)/sqrt(a + b*x**S(4)), Int(S(1)/sqrt(S(1) + b*x**S(4)/a), x), x) def With728(a, b, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Simp(S(3)**(S(3)/4)*x*sqrt((r**S(2)*x**S(4) - r*s*x**S(2) + s**S(2))/(r*x**S(2)*(S(1) + sqrt(S(3))) + s)**S(2))*(r*x**S(2) + s)*EllipticF(acos((r*x**S(2)*(S(1) - sqrt(S(3))) + s)/(r*x**S(2)*(S(1) + sqrt(S(3))) + s)), sqrt(S(3))/S(4) + S(1)/2)/(S(6)*s*sqrt(r*x**S(2)*(r*x**S(2) + s)/(r*x**S(2)*(S(1) + sqrt(S(3))) + s)**S(2))*sqrt(a + b*x**S(6))), x) def replacement729(a, b, x): return Dist(S(1)/2, Int((-x**S(2)*Rt(b/a, S(4)) + S(1))/sqrt(a + b*x**S(8)), x), x) + Dist(S(1)/2, Int((x**S(2)*Rt(b/a, S(4)) + S(1))/sqrt(a + b*x**S(8)), x), x) def replacement730(a, b, x): return -Dist(a, Int((a + b*x**S(2))**(S(-5)/4), x), x) + Simp(S(2)*x/(a + b*x**S(2))**(S(1)/4), x) def replacement731(a, b, x): return Simp(S(2)*EllipticE(asin(x*Rt(-b/a, S(2)))/S(2), S(2))/(a**(S(1)/4)*Rt(-b/a, S(2))), x) def replacement732(a, b, x): return Dist((S(1) + b*x**S(2)/a)**(S(1)/4)/(a + b*x**S(2))**(S(1)/4), Int((S(1) + b*x**S(2)/a)**(S(-1)/4), x), x) def replacement733(a, b, x): return Simp(S(2)*EllipticF(ArcTan(x*Rt(b/a, S(2)))/S(2), S(2))/(a**(S(3)/4)*Rt(b/a, S(2))), x) def replacement734(a, b, x): return Simp(S(2)*EllipticF(asin(x*Rt(-b/a, S(2)))/S(2), S(2))/(a**(S(3)/4)*Rt(-b/a, S(2))), x) def replacement735(a, b, x): return Dist((S(1) + b*x**S(2)/a)**(S(3)/4)/(a + b*x**S(2))**(S(3)/4), Int((S(1) + b*x**S(2)/a)**(S(-3)/4), x), x) def replacement736(a, b, x): return Dist(S(3)*sqrt(b*x**S(2))/(S(2)*b*x), Subst(Int(x/sqrt(-a + x**S(3)), x), x, (a + b*x**S(2))**(S(1)/3)), x) def replacement737(a, b, x): return Dist(S(3)*sqrt(b*x**S(2))/(S(2)*b*x), Subst(Int(S(1)/sqrt(-a + x**S(3)), x), x, (a + b*x**S(2))**(S(1)/3)), x) def replacement738(a, b, x): return Dist(x**S(3)*(a/(b*x**S(4)) + S(1))**(S(3)/4)/(a + b*x**S(4))**(S(3)/4), Int(S(1)/(x**S(3)*(a/(b*x**S(4)) + S(1))**(S(3)/4)), x), x) def replacement739(a, b, x): return -Dist(a/S(2), Int((a + b*x**S(2))**(S(-7)/6), x), x) + Simp(S(3)*x/(S(2)*(a + b*x**S(2))**(S(1)/6)), x) def replacement740(a, b, n, p, x): return Dist(a**(p + S(1)/n), Subst(Int((-b*x**n + S(1))**(-p + S(-1) - S(1)/n), x), x, x*(a + b*x**n)**(-S(1)/n)), x) def replacement741(a, b, n, p, x): return Dist((a/(a + b*x**n))**(p + S(1)/n)*(a + b*x**n)**(p + S(1)/n), Subst(Int((-b*x**n + S(1))**(-p + S(-1) - S(1)/n), x), x, x*(a + b*x**n)**(-S(1)/n)), x) def replacement742(a, b, n, p, x): return -Subst(Int((a + b*x**(-n))**p/x**S(2), x), x, S(1)/x) def With743(a, b, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k + S(-1))*(a + b*x**(k*n))**p, x), x, x**(S(1)/k)), x) def replacement744(a, b, n, p, x): return Int(ExpandIntegrand((a + b*x**n)**p, x), x) def replacement745(a, b, n, p, x): return Simp(a**p*x*Hypergeometric2F1(-p, S(1)/n, S(1) + S(1)/n, -b*x**n/a), x) def replacement746(a, b, n, p, x): return Dist(a**IntPart(p)*(S(1) + b*x**n/a)**(-FracPart(p))*(a + b*x**n)**FracPart(p), Int((S(1) + b*x**n/a)**p, x), x) def replacement747(a, b, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x**n)**p, x), x, u), x) def replacement748(a1, a2, b1, b2, n, p, x): return Int((a1*a2 + b1*b2*x**(S(2)*n))**p, x) def replacement749(a1, a2, b1, b2, n, p, x): return Dist(S(2)*a1*a2*n*p/(S(2)*n*p + S(1)), Int((a1 + b1*x**n)**(p + S(-1))*(a2 + b2*x**n)**(p + S(-1)), x), x) + Simp(x*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p/(S(2)*n*p + S(1)), x) def replacement750(a1, a2, b1, b2, n, p, x): return Dist((S(2)*n*(p + S(1)) + S(1))/(S(2)*a1*a2*n*(p + S(1))), Int((a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1)), x), x) - Simp(x*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(S(2)*a1*a2*n*(p + S(1))), x) def replacement751(a1, a2, b1, b2, n, p, x): return -Subst(Int((a1 + b1*x**(-n))**p*(a2 + b2*x**(-n))**p/x**S(2), x), x, S(1)/x) def With752(a1, a2, b1, b2, n, p, x): k = Denominator(S(2)*n) return Dist(k, Subst(Int(x**(k + S(-1))*(a1 + b1*x**(k*n))**p*(a2 + b2*x**(k*n))**p, x), x, x**(S(1)/k)), x) def replacement753(a1, a2, b1, b2, n, p, x): return Dist((a1 + b1*x**n)**FracPart(p)*(a2 + b2*x**n)**FracPart(p)*(a1*a2 + b1*b2*x**(S(2)*n))**(-FracPart(p)), Int((a1*a2 + b1*b2*x**(S(2)*n))**p, x), x) def replacement754(a1, a2, b1, b2, c, m, n, p, x): return Int((c*x)**m*(a1*a2 + b1*b2*x**(S(2)*n))**p, x) def replacement755(b, c, m, n, p, x): return Dist(b**(S(1) - (m + S(1))/n)*c**m/n, Subst(Int((b*x)**(p + S(-1) + (m + S(1))/n), x), x, x**n), x) def replacement756(b, c, m, n, p, x): return Dist(b**IntPart(p)*c**m*x**(-n*FracPart(p))*(b*x**n)**FracPart(p), Int(x**(m + n*p), x), x) def replacement757(b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(b*x**n)**p, x), x) def replacement758(a, b, m, n, p, x): return Int(x**(m + n*p)*(a*x**(-n) + b)**p, x) def replacement759(a, b, c, m, n, p, x): return Simp((c*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*c*(m + S(1))), x) def replacement760(a1, a2, b1, b2, c, m, n, p, x): return Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(a1*a2*c*(m + S(1))), x) def replacement761(a, b, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*x)**p, x), x, x**n), x) def replacement762(a1, a2, b1, b2, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a1 + b1*x)**p*(a2 + b2*x)**p, x), x, x**n), x) def replacement763(a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a + b*x**n)**p, x), x) def replacement764(a1, a2, b1, b2, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) def replacement765(a, b, c, m, n, p, x): return Int(ExpandIntegrand((c*x)**m*(a + b*x**n)**p, x), x) def replacement766(a, b, m, n, p, x): return -Dist(b*(m + n*(p + S(1)) + S(1))/(a*(m + S(1))), Int(x**(m + n)*(a + b*x**n)**p, x), x) + Simp(x**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*(m + S(1))), x) def replacement767(a1, a2, b1, b2, m, n, p, x): return -Dist(b1*b2*(m + S(2)*n*(p + S(1)) + S(1))/(a1*a2*(m + S(1))), Int(x**(m + S(2)*n)*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) + Simp(x**(m + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(a1*a2*(m + S(1))), x) def replacement768(a, b, c, m, n, p, x): return Dist((m + n*(p + S(1)) + S(1))/(a*n*(p + S(1))), Int((c*x)**m*(a + b*x**n)**(p + S(1)), x), x) - Simp((c*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*c*n*(p + S(1))), x) def replacement769(a1, a2, b1, b2, c, m, n, p, x): return Dist((m + S(2)*n*(p + S(1)) + S(1))/(S(2)*a1*a2*n*(p + S(1))), Int((c*x)**m*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1)), x), x) - Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(S(2)*a1*a2*c*n*(p + S(1))), x) def With770(a, b, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False k = GCD(m + S(1), n) if Unequal(k, S(1)): return True return False def replacement770(a, b, m, n, p, x): k = GCD(m + S(1), n) return Dist(S(1)/k, Subst(Int(x**(S(-1) + (m + S(1))/k)*(a + b*x**(n/k))**p, x), x, x**k), x) def With771(a1, a2, b1, b2, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False k = GCD(m + S(1), S(2)*n) if Unequal(k, S(1)): return True return False def replacement771(a1, a2, b1, b2, m, n, p, x): k = GCD(m + S(1), S(2)*n) return Dist(S(1)/k, Subst(Int(x**(S(-1) + (m + S(1))/k)*(a1 + b1*x**(n/k))**p*(a2 + b2*x**(n/k))**p, x), x, x**k), x) def replacement772(a, b, c, m, n, p, x): return -Dist(b*c**(-n)*n*p/(m + S(1)), Int((c*x)**(m + n)*(a + b*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a + b*x**n)**p/(c*(m + S(1))), x) def replacement773(a1, a2, b1, b2, c, m, n, p, x): return Dist(S(2)*a1*a2*n*p/(m + S(2)*n*p + S(1)), Int((c*x)**m*(a1 + b1*x**n)**(p + S(-1))*(a2 + b2*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p/(c*(m + S(2)*n*p + S(1))), x) def replacement774(a, b, c, m, n, p, x): return Dist(a*n*p/(m + n*p + S(1)), Int((c*x)**m*(a + b*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a + b*x**n)**p/(c*(m + n*p + S(1))), x) def replacement775(a, b, x): return Dist(x*(a/(b*x**S(4)) + S(1))**(S(1)/4)/(b*(a + b*x**S(4))**(S(1)/4)), Int(S(1)/(x**S(3)*(a/(b*x**S(4)) + S(1))**(S(5)/4)), x), x) def replacement776(a, b, m, x): return -Dist(a*(m + S(-3))/(b*(m + S(-4))), Int(x**(m + S(-4))/(a + b*x**S(4))**(S(5)/4), x), x) + Simp(x**(m + S(-3))/(b*(a + b*x**S(4))**(S(1)/4)*(m + S(-4))), x) def replacement777(a, b, m, x): return -Dist(b*m/(a*(m + S(1))), Int(x**(m + S(4))/(a + b*x**S(4))**(S(5)/4), x), x) + Simp(x**(m + S(1))/(a*(a + b*x**S(4))**(S(1)/4)*(m + S(1))), x) def replacement778(a, b, c, x): return Dist(sqrt(c*x)*(a/(b*x**S(2)) + S(1))**(S(1)/4)/(b*(a + b*x**S(2))**(S(1)/4)), Int(S(1)/(x**S(2)*(a/(b*x**S(2)) + S(1))**(S(5)/4)), x), x) def replacement779(a, b, c, m, x): return -Dist(S(2)*a*c**S(2)*(m + S(-1))/(b*(S(2)*m + S(-3))), Int((c*x)**(m + S(-2))/(a + b*x**S(2))**(S(5)/4), x), x) + Simp(S(2)*c*(c*x)**(m + S(-1))/(b*(a + b*x**S(2))**(S(1)/4)*(S(2)*m + S(-3))), x) def replacement780(a, b, c, m, x): return -Dist(b*(S(2)*m + S(1))/(S(2)*a*c**S(2)*(m + S(1))), Int((c*x)**(m + S(2))/(a + b*x**S(2))**(S(5)/4), x), x) + Simp((c*x)**(m + S(1))/(a*c*(a + b*x**S(2))**(S(1)/4)*(m + S(1))), x) def replacement781(a, b, x): return -Dist(S(1)/b, Int(S(1)/(x**S(2)*(a + b*x**S(4))**(S(1)/4)), x), x) - Simp(S(1)/(b*x*(a + b*x**S(4))**(S(1)/4)), x) def replacement782(a, b, c, m, n, p, x): return -Dist(c**n*(m - n + S(1))/(b*n*(p + S(1))), Int((c*x)**(m - n)*(a + b*x**n)**(p + S(1)), x), x) + Simp(c**(n + S(-1))*(c*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement783(a1, a2, b1, b2, c, m, n, p, x): return -Dist(c**(S(2)*n)*(m - S(2)*n + S(1))/(S(2)*b1*b2*n*(p + S(1))), Int((c*x)**(m - S(2)*n)*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1)), x), x) + Simp(c**(S(2)*n + S(-1))*(c*x)**(m - S(2)*n + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(S(2)*b1*b2*n*(p + S(1))), x) def replacement784(a, b, c, m, n, p, x): return Dist((m + n*(p + S(1)) + S(1))/(a*n*(p + S(1))), Int((c*x)**m*(a + b*x**n)**(p + S(1)), x), x) - Simp((c*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*c*n*(p + S(1))), x) def replacement785(a1, a2, b1, b2, c, m, n, p, x): return Dist((m + S(2)*n*(p + S(1)) + S(1))/(S(2)*a1*a2*n*(p + S(1))), Int((c*x)**m*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1)), x), x) - Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(S(2)*a1*a2*c*n*(p + S(1))), x) def replacement786(a, b, x): return Dist(S(1)/(S(3)*Rt(a, S(3))*Rt(b, S(3))), Int((x*Rt(b, S(3)) + Rt(a, S(3)))/(x**S(2)*Rt(b, S(3))**S(2) - x*Rt(a, S(3))*Rt(b, S(3)) + Rt(a, S(3))**S(2)), x), x) - Dist(S(1)/(S(3)*Rt(a, S(3))*Rt(b, S(3))), Int(S(1)/(x*Rt(b, S(3)) + Rt(a, S(3))), x), x) def With787(a, b, m, n, x): r = Numerator(Rt(a/b, n)) s = Denominator(Rt(a/b, n)) k = Symbol('k') u = Symbol('u') u = Int((r*cos(Pi*m*(S(2)*k + S(-1))/n) - s*x*cos(Pi*(S(2)*k + S(-1))*(m + S(1))/n))/(r**S(2) - S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) u = Int((r*cos(Pi*m*(2*k - 1)/n) - s*x*cos(Pi*(2*k - 1)*(m + 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) return Simp(Dist(2*r**(m + 1)*s**(-m)/(a*n), Sum_doit(u, List(k, 1, n/2 - 1/2)), x) - s**(-m)*(-r)**(m + 1)*Int(1/(r + s*x), x)/(a*n), x) def With788(a, b, m, n, x): r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) k = Symbol('k') u = Symbol('u') u = Int((r*cos(Pi*m*(S(2)*k + S(-1))/n) + s*x*cos(Pi*(S(2)*k + S(-1))*(m + S(1))/n))/(r**S(2) + S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) u = Int((r*cos(Pi*m*(2*k - 1)/n) + s*x*cos(Pi*(2*k - 1)*(m + 1)/n))/(r**2 + 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) return Simp(-Dist(2*s**(-m)*(-r)**(m + 1)/(a*n), Sum_doit(u, List(k, 1, n/2 - 1/2)), x) + r**(m + 1)*s**(-m)*Int(1/(r - s*x), x)/(a*n), x) def With789(a, b, m, n, x): r = Numerator(Rt(a/b, n)) s = Denominator(Rt(a/b, n)) k = Symbol('k') u = Symbol('u') u = Int((r*cos(Pi*m*(S(2)*k + S(-1))/n) - s*x*cos(Pi*(S(2)*k + S(-1))*(m + S(1))/n))/(r**S(2) - S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) + Int((r*cos(Pi*m*(S(2)*k + S(-1))/n) + s*x*cos(Pi*(S(2)*k + S(-1))*(m + S(1))/n))/(r**S(2) + S(2)*r*s*x*cos(Pi*(S(2)*k + S(-1))/n) + s**S(2)*x**S(2)), x) u = Int((r*cos(Pi*m*(2*k - 1)/n) - s*x*cos(Pi*(2*k - 1)*(m + 1)/n))/(r**2 - 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) + Int((r*cos(Pi*m*(2*k - 1)/n) + s*x*cos(Pi*(2*k - 1)*(m + 1)/n))/(r**2 + 2*r*s*x*cos(Pi*(2*k - 1)/n) + s**2*x**2), x) return Simp(2*(-1)**(m/2)*r**(m + 2)*s**(-m)*Int(1/(r**2 + s**2*x**2), x)/(a*n) + Dist(2*r**(m + 1)*s**(-m)/(a*n), Sum_doit(u, List(k, 1, n/4 - 1/2)), x), x) def With790(a, b, m, n, x): r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) k = Symbol('k') u = Symbol('u') u = Int((r*cos(S(2)*Pi*k*m/n) - s*x*cos(S(2)*Pi*k*(m + S(1))/n))/(r**S(2) - S(2)*r*s*x*cos(S(2)*Pi*k/n) + s**S(2)*x**S(2)), x) + Int((r*cos(S(2)*Pi*k*m/n) + s*x*cos(S(2)*Pi*k*(m + S(1))/n))/(r**S(2) + S(2)*r*s*x*cos(S(2)*Pi*k/n) + s**S(2)*x**S(2)), x) u = Int((r*cos(2*Pi*k*m/n) - s*x*cos(2*Pi*k*(m + 1)/n))/(r**2 - 2*r*s*x*cos(2*Pi*k/n) + s**2*x**2), x) + Int((r*cos(2*Pi*k*m/n) + s*x*cos(2*Pi*k*(m + 1)/n))/(r**2 + 2*r*s*x*cos(2*Pi*k/n) + s**2*x**2), x) return Simp(Dist(2*r**(m + 1)*s**(-m)/(a*n), Sum_doit(u, List(k, 1, n/4 - 1/2)), x) + 2*r**(m + 2)*s**(-m)*Int(1/(r**2 - s**2*x**2), x)/(a*n), x) def With791(a, b, x): r = Numerator(Rt(a/b, S(2))) s = Denominator(Rt(a/b, S(2))) return -Dist(S(1)/(S(2)*s), Int((r - s*x**S(2))/(a + b*x**S(4)), x), x) + Dist(S(1)/(S(2)*s), Int((r + s*x**S(2))/(a + b*x**S(4)), x), x) def With792(a, b, x): r = Numerator(Rt(-a/b, S(2))) s = Denominator(Rt(-a/b, S(2))) return -Dist(s/(S(2)*b), Int(S(1)/(r - s*x**S(2)), x), x) + Dist(s/(S(2)*b), Int(S(1)/(r + s*x**S(2)), x), x) def With793(a, b, m, n, x): r = Numerator(Rt(a/b, S(4))) s = Denominator(Rt(a/b, S(4))) return Dist(sqrt(S(2))*s**S(3)/(S(4)*b*r), Int(x**(m - n/S(4))/(r**S(2) - sqrt(S(2))*r*s*x**(n/S(4)) + s**S(2)*x**(n/S(2))), x), x) - Dist(sqrt(S(2))*s**S(3)/(S(4)*b*r), Int(x**(m - n/S(4))/(r**S(2) + sqrt(S(2))*r*s*x**(n/S(4)) + s**S(2)*x**(n/S(2))), x), x) def With794(a, b, m, n, x): r = Numerator(Rt(-a/b, S(2))) s = Denominator(Rt(-a/b, S(2))) return Dist(r/(S(2)*a), Int(x**m/(r - s*x**(n/S(2))), x), x) + Dist(r/(S(2)*a), Int(x**m/(r + s*x**(n/S(2))), x), x) def With795(a, b, m, n, x): r = Numerator(Rt(-a/b, S(2))) s = Denominator(Rt(-a/b, S(2))) return -Dist(s/(S(2)*b), Int(x**(m - n/S(2))/(r - s*x**(n/S(2))), x), x) + Dist(s/(S(2)*b), Int(x**(m - n/S(2))/(r + s*x**(n/S(2))), x), x) def replacement796(a, b, m, n, x): return Int(PolynomialDivide(x**m, a + b*x**n, x), x) def With797(a, b, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Dist(S(1)/r, Int((r*x + s*(S(1) - sqrt(S(3))))/sqrt(a + b*x**S(3)), x), x) + Dist(sqrt(S(2))*s/(r*sqrt(sqrt(S(3)) + S(2))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With798(a, b, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Dist(S(1)/r, Int((r*x + s*(S(1) + sqrt(S(3))))/sqrt(a + b*x**S(3)), x), x) - Dist(sqrt(S(2))*s/(r*sqrt(S(2) - sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With799(a, b, x): q = Rt(b/a, S(2)) return -Dist(S(1)/q, Int((-q*x**S(2) + S(1))/sqrt(a + b*x**S(4)), x), x) + Dist(S(1)/q, Int(S(1)/sqrt(a + b*x**S(4)), x), x) def With800(a, b, x): q = Rt(-b/a, S(2)) return -Dist(S(1)/q, Int((-q*x**S(2) + S(1))/sqrt(a + b*x**S(4)), x), x) + Dist(S(1)/q, Int(S(1)/sqrt(a + b*x**S(4)), x), x) def With801(a, b, x): q = Rt(-b/a, S(2)) return Dist(S(1)/q, Int((q*x**S(2) + S(1))/sqrt(a + b*x**S(4)), x), x) - Dist(S(1)/q, Int(S(1)/sqrt(a + b*x**S(4)), x), x) def With802(a, b, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return -Dist(S(1)/(S(2)*r**S(2)), Int((-S(2)*r**S(2)*x**S(4) + s**S(2)*(S(-1) + sqrt(S(3))))/sqrt(a + b*x**S(6)), x), x) + Dist(s**S(2)*(S(-1) + sqrt(S(3)))/(S(2)*r**S(2)), Int(S(1)/sqrt(a + b*x**S(6)), x), x) def replacement803(a, b, x): return -Dist(S(1)/(S(2)*Rt(b/a, S(4))), Int((-x**S(2)*Rt(b/a, S(4)) + S(1))/sqrt(a + b*x**S(8)), x), x) + Dist(S(1)/(S(2)*Rt(b/a, S(4))), Int((x**S(2)*Rt(b/a, S(4)) + S(1))/sqrt(a + b*x**S(8)), x), x) def replacement804(a, b, x): return -Dist(a/S(2), Int(x**S(2)/(a + b*x**S(4))**(S(5)/4), x), x) + Simp(x**S(3)/(S(2)*(a + b*x**S(4))**(S(1)/4)), x) def replacement805(a, b, x): return Dist(a/(S(2)*b), Int(S(1)/(x**S(2)*(a + b*x**S(4))**(S(1)/4)), x), x) + Simp((a + b*x**S(4))**(S(3)/4)/(S(2)*b*x), x) def replacement806(a, b, x): return -Dist(b, Int(x**S(2)/(a + b*x**S(4))**(S(5)/4), x), x) - Simp(S(1)/(x*(a + b*x**S(4))**(S(1)/4)), x) def replacement807(a, b, x): return Dist(x*(a/(b*x**S(4)) + S(1))**(S(1)/4)/(a + b*x**S(4))**(S(1)/4), Int(S(1)/(x**S(3)*(a/(b*x**S(4)) + S(1))**(S(1)/4)), x), x) def replacement808(a, b, c, x): return -Dist(a/S(2), Int(sqrt(c*x)/(a + b*x**S(2))**(S(5)/4), x), x) + Simp(x*sqrt(c*x)/(a + b*x**S(2))**(S(1)/4), x) def replacement809(a, b, c, x): return Dist(a*c**S(2)/(S(2)*b), Int(S(1)/((c*x)**(S(3)/2)*(a + b*x**S(2))**(S(1)/4)), x), x) + Simp(c*(a + b*x**S(2))**(S(3)/4)/(b*sqrt(c*x)), x) def replacement810(a, b, c, x): return -Dist(b/c**S(2), Int(sqrt(c*x)/(a + b*x**S(2))**(S(5)/4), x), x) + Simp(-S(2)/(c*sqrt(c*x)*(a + b*x**S(2))**(S(1)/4)), x) def replacement811(a, b, c, x): return Dist(sqrt(c*x)*(a/(b*x**S(2)) + S(1))**(S(1)/4)/(c**S(2)*(a + b*x**S(2))**(S(1)/4)), Int(S(1)/(x**S(2)*(a/(b*x**S(2)) + S(1))**(S(1)/4)), x), x) def replacement812(a, b, c, m, n, p, x): return -Dist(a*c**n*(m - n + S(1))/(b*(m + n*p + S(1))), Int((c*x)**(m - n)*(a + b*x**n)**p, x), x) + Simp(c**(n + S(-1))*(c*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))/(b*(m + n*p + S(1))), x) def replacement813(a, b, c, m, n, p, x): return -Dist(a*c**n*(m - n + S(1))/(b*(m + n*p + S(1))), Int((c*x)**(m - n)*(a + b*x**n)**p, x), x) + Simp(c**(n + S(-1))*(c*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))/(b*(m + n*p + S(1))), x) def replacement814(a1, a2, b1, b2, c, m, n, p, x): return -Dist(a1*a2*c**(S(2)*n)*(m - S(2)*n + S(1))/(b1*b2*(m + S(2)*n*p + S(1))), Int((c*x)**(m - S(2)*n)*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) + Simp(c**(S(2)*n + S(-1))*(c*x)**(m - S(2)*n + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(b1*b2*(m + S(2)*n*p + S(1))), x) def replacement815(a1, a2, b1, b2, c, m, n, p, x): return -Dist(a1*a2*c**(S(2)*n)*(m - S(2)*n + S(1))/(b1*b2*(m + S(2)*n*p + S(1))), Int((c*x)**(m - S(2)*n)*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) + Simp(c**(S(2)*n + S(-1))*(c*x)**(m - S(2)*n + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(b1*b2*(m + S(2)*n*p + S(1))), x) def replacement816(a, b, c, m, n, p, x): return -Dist(b*c**(-n)*(m + n*(p + S(1)) + S(1))/(a*(m + S(1))), Int((c*x)**(m + n)*(a + b*x**n)**p, x), x) + Simp((c*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*c*(m + S(1))), x) def replacement817(a, b, c, m, n, p, x): return -Dist(b*c**(-n)*(m + n*(p + S(1)) + S(1))/(a*(m + S(1))), Int((c*x)**(m + n)*(a + b*x**n)**p, x), x) + Simp((c*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*c*(m + S(1))), x) def replacement818(a1, a2, b1, b2, c, m, n, p, x): return -Dist(b1*b2*c**(-S(2)*n)*(m + S(2)*n*(p + S(1)) + S(1))/(a1*a2*(m + S(1))), Int((c*x)**(m + S(2)*n)*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) + Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(a1*a2*c*(m + S(1))), x) def replacement819(a1, a2, b1, b2, c, m, n, p, x): return -Dist(b1*b2*c**(-S(2)*n)*(m + S(2)*n*(p + S(1)) + S(1))/(a1*a2*(m + S(1))), Int((c*x)**(m + S(2)*n)*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) + Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(a1*a2*c*(m + S(1))), x) def With820(a, b, c, m, n, p, x): k = Denominator(m) return Dist(k/c, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*c**(-n)*x**(k*n))**p, x), x, (c*x)**(S(1)/k)), x) def With821(a1, a2, b1, b2, c, m, n, p, x): k = Denominator(m) return Dist(k/c, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a1 + b1*c**(-n)*x**(k*n))**p*(a2 + b2*c**(-n)*x**(k*n))**p, x), x, (c*x)**(S(1)/k)), x) def replacement822(a, b, m, n, p, x): return Dist(a**(p + (m + S(1))/n), Subst(Int(x**m*(-b*x**n + S(1))**(-p + S(-1) - (m + S(1))/n), x), x, x*(a + b*x**n)**(-S(1)/n)), x) def replacement823(a1, a2, b1, b2, m, n, p, x): return Dist((a1*a2)**(p + (m + S(1))/(S(2)*n)), Subst(Int(x**m*(-b1*x**n + S(1))**(-p + S(-1) - (m + S(1))/(S(2)*n))*(-b2*x**n + S(1))**(-p + S(-1) - (m + S(1))/(S(2)*n)), x), x, x*(a1 + b1*x**n)**(-S(1)/(S(2)*n))*(a2 + b2*x**n)**(-S(1)/(S(2)*n))), x) def replacement824(a, b, m, n, p, x): return Dist((a/(a + b*x**n))**(p + (m + S(1))/n)*(a + b*x**n)**(p + (m + S(1))/n), Subst(Int(x**m*(-b*x**n + S(1))**(-p + S(-1) - (m + S(1))/n), x), x, x*(a + b*x**n)**(-S(1)/n)), x) def replacement825(a1, a2, b1, b2, m, n, p, x): return Dist((a1/(a1 + b1*x**n))**(p + (m + S(1))/(S(2)*n))*(a2/(a2 + b2*x**n))**(p + (m + S(1))/(S(2)*n))*(a1 + b1*x**n)**(p + (m + S(1))/(S(2)*n))*(a2 + b2*x**n)**(p + (m + S(1))/(S(2)*n)), Subst(Int(x**m*(-b1*x**n + S(1))**(-p + S(-1) - (m + S(1))/(S(2)*n))*(-b2*x**n + S(1))**(-p + S(-1) - (m + S(1))/(S(2)*n)), x), x, x*(a1 + b1*x**n)**(-S(1)/(S(2)*n))*(a2 + b2*x**n)**(-S(1)/(S(2)*n))), x) def replacement826(a, b, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(a + b*x**(-n))**p, x), x, S(1)/x) def replacement827(a1, a2, b1, b2, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(a1 + b1*x**(-n))**p*(a2 + b2*x**(-n))**p, x), x, S(1)/x) def With828(a, b, c, m, n, p, x): k = Denominator(m) return -Dist(k/c, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*c**(-n)*x**(-k*n))**p, x), x, (c*x)**(-S(1)/k)), x) def With829(a1, a2, b1, b2, c, m, n, p, x): k = Denominator(m) return -Dist(k/c, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a1 + b1*c**(-n)*x**(-k*n))**p*(a2 + b2*c**(-n)*x**(-k*n))**p, x), x, (c*x)**(-S(1)/k)), x) def replacement830(a, b, c, m, n, p, x): return -Dist((c*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a + b*x**(-n))**p, x), x, S(1)/x), x) def replacement831(a1, a2, b1, b2, c, m, n, p, x): return -Dist((c*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a1 + b1*x**(-n))**p*(a2 + b2*x**(-n))**p, x), x, S(1)/x), x) def With832(a, b, m, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*x**(k*n))**p, x), x, x**(S(1)/k)), x) def With833(a1, a2, b1, b2, m, n, p, x): k = Denominator(S(2)*n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a1 + b1*x**(k*n))**p*(a2 + b2*x**(k*n))**p, x), x, x**(S(1)/k)), x) def replacement834(a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a + b*x**n)**p, x), x) def replacement835(a1, a2, b1, b2, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) def replacement836(a, b, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*x**(n/(m + S(1))))**p, x), x, x**(m + S(1))), x) def replacement837(a1, a2, b1, b2, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a1 + b1*x**(n/(m + S(1))))**p*(a2 + b2*x**(n/(m + S(1))))**p, x), x, x**(m + S(1))), x) def replacement838(a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a + b*x**n)**p, x), x) def replacement839(a1, a2, b1, b2, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) def replacement840(a, b, m, n, p, x): return -Dist(b*n*p/(m + S(1)), Int(x**(m + n)*(a + b*x**n)**(p + S(-1)), x), x) + Simp(x**(m + S(1))*(a + b*x**n)**p/(m + S(1)), x) def replacement841(a1, a2, b1, b2, m, n, p, x): return -Dist(S(2)*b1*b2*n*p/(m + S(1)), Int(x**(m + n)*(a1 + b1*x**n)**(p + S(-1))*(a2 + b2*x**n)**(p + S(-1)), x), x) + Simp(x**(m + S(1))*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p/(m + S(1)), x) def replacement842(a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a + b*x**n)**p, x), x) def replacement843(a1, a2, b1, b2, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) def replacement844(a, b, c, m, n, p, x): return Dist(a*n*p/(m + n*p + S(1)), Int((c*x)**m*(a + b*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a + b*x**n)**p/(c*(m + n*p + S(1))), x) def replacement845(a1, a2, b1, b2, c, m, n, p, x): return Dist(S(2)*a1*a2*n*p/(m + S(2)*n*p + S(1)), Int((c*x)**m*(a1 + b1*x**n)**(p + S(-1))*(a2 + b2*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p/(c*(m + S(2)*n*p + S(1))), x) def With846(a, b, m, n, p, x): k = Denominator(p) return Dist(a**(p + (m + S(1))/n)*k/n, Subst(Int(x**(k*(m + S(1))/n + S(-1))*(-b*x**k + S(1))**(-p + S(-1) - (m + S(1))/n), x), x, x**(n/k)*(a + b*x**n)**(-S(1)/k)), x) def With847(a1, a2, b1, b2, m, n, p, x): k = Denominator(p) return Dist(k*(a1*a2)**(p + (m + S(1))/(S(2)*n))/(S(2)*n), Subst(Int(x**(k*(m + S(1))/(S(2)*n) + S(-1))*(-b1*x**k + S(1))**(-p + S(-1) - (m + S(1))/(S(2)*n))*(-b2*x**k + S(1))**(-p + S(-1) - (m + S(1))/(S(2)*n)), x), x, x**(S(2)*n/k)*(a1 + b1*x**n)**(-S(1)/k)*(a2 + b2*x**n)**(-S(1)/k)), x) def replacement848(a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a + b*x**n)**p, x), x) def replacement849(a1, a2, b1, b2, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a1 + b1*x**n)**p*(a2 + b2*x**n)**p, x), x) def replacement850(a, b, c, m, n, p, x): return Dist((m + n*(p + S(1)) + S(1))/(a*n*(p + S(1))), Int((c*x)**m*(a + b*x**n)**(p + S(1)), x), x) - Simp((c*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*c*n*(p + S(1))), x) def replacement851(a1, a2, b1, b2, c, m, n, p, x): return Dist((m + S(2)*n*(p + S(1)) + S(1))/(S(2)*a1*a2*n*(p + S(1))), Int((c*x)**m*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1)), x), x) - Simp((c*x)**(m + S(1))*(a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(S(2)*a1*a2*c*n*(p + S(1))), x) def With852(a, b, m, n, x): mn = m - n return -Dist(a/b, Int(x**mn/(a + b*x**n), x), x) + Simp(x**(mn + S(1))/(b*(mn + S(1))), x) def replacement853(a, b, m, n, x): return -Dist(b/a, Int(x**(m + n)/(a + b*x**n), x), x) + Simp(x**(m + S(1))/(a*(m + S(1))), x) def replacement854(a, b, c, m, n, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m/(a + b*x**n), x), x) def replacement855(a, b, c, m, n, p, x): return Simp(a**p*(c*x)**(m + S(1))*Hypergeometric2F1(-p, (m + S(1))/n, S(1) + (m + S(1))/n, -b*x**n/a)/(c*(m + S(1))), x) def replacement856(a, b, c, m, n, p, x): return Dist(a**IntPart(p)*(S(1) + b*x**n/a)**(-FracPart(p))*(a + b*x**n)**FracPart(p), Int((c*x)**m*(S(1) + b*x**n/a)**p, x), x) def replacement857(a, b, m, n, p, v, x): return Dist(Coefficient(v, x, S(1))**(-m + S(-1)), Subst(Int(SimplifyIntegrand((a + b*x**n)**p*(x - Coefficient(v, x, S(0)))**m, x), x), x, v), x) def replacement858(a, b, m, n, p, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(a + b*x**n)**p, x), x, v), x) def replacement859(a1, a2, b1, b2, c, m, n, p, x): return Dist((a1 + b1*x**n)**FracPart(p)*(a2 + b2*x**n)**FracPart(p)*(a1*a2 + b1*b2*x**(S(2)*n))**(-FracPart(p)), Int((c*x)**m*(a1*a2 + b1*b2*x**(S(2)*n))**p, x), x) def replacement860(a, b, c, d, n, p, q, x): return Int(ExpandIntegrand((a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement861(a, b, c, d, n, p, q, x): return Int(x**(n*(p + q))*(a*x**(-n) + b)**p*(c*x**(-n) + d)**q, x) def replacement862(a, b, c, d, n, p, q, x): return -Subst(Int((a + b*x**(-n))**p*(c + d*x**(-n))**q/x**S(2), x), x, S(1)/x) def With863(a, b, c, d, n, p, q, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g + S(-1))*(a + b*x**(g*n))**p*(c + d*x**(g*n))**q, x), x, x**(S(1)/g)), x) def replacement864(a, b, c, d, n, p, x): return Subst(Int(S(1)/(c - x**n*(-a*d + b*c)), x), x, x*(a + b*x**n)**(-S(1)/n)) def replacement865(a, b, c, d, n, p, q, x): return -Dist(c*q/(a*(p + S(1))), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1)), x), x) - Simp(x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(a*n*(p + S(1))), x) def replacement866(a, b, c, d, n, p, q, x): return Simp(a**p*c**(-p + S(-1))*x*(c + d*x**n)**(-S(1)/n)*Hypergeometric2F1(S(1)/n, -p, S(1) + S(1)/n, -x**n*(-a*d + b*c)/(a*(c + d*x**n))), x) def replacement867(a, b, c, d, n, p, q, x): return Simp(x*(c*(a + b*x**n)/(a*(c + d*x**n)))**(-p)*(a + b*x**n)**p*(c + d*x**n)**(-p - S(1)/n)*Hypergeometric2F1(S(1)/n, -p, S(1) + S(1)/n, -x**n*(-a*d + b*c)/(a*(c + d*x**n)))/c, x) def replacement868(a, b, c, d, n, p, q, x): return Simp(x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(a*c), x) def replacement869(a, b, c, d, n, p, q, x): return Dist((b*c + n*(p + S(1))*(-a*d + b*c))/(a*n*(p + S(1))*(-a*d + b*c)), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**q, x), x) - Simp(b*x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(a*n*(p + S(1))*(-a*d + b*c)), x) def replacement870(a, b, c, d, n, p, x): return Simp(c*x*(a + b*x**n)**(p + S(1))/a, x) def replacement871(a, b, c, d, n, p, x): return -Dist((a*d - b*c*(n*(p + S(1)) + S(1)))/(a*b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1)), x), x) - Simp(x*(a + b*x**n)**(p + S(1))*(-a*d + b*c)/(a*b*n*(p + S(1))), x) def replacement872(a, b, c, d, n, x): return -Dist((-a*d + b*c)/a, Int(S(1)/(a*x**(-n) + b), x), x) + Simp(c*x/a, x) def replacement873(a, b, c, d, n, p, x): return -Dist((a*d - b*c*(n*(p + S(1)) + S(1)))/(b*(n*(p + S(1)) + S(1))), Int((a + b*x**n)**p, x), x) + Simp(d*x*(a + b*x**n)**(p + S(1))/(b*(n*(p + S(1)) + S(1))), x) def replacement874(a, b, c, d, n, p, q, x): return Int(PolynomialDivide((a + b*x**n)**p, (c + d*x**n)**(-q), x), x) def replacement875(a, b, c, d, n, x): return Dist(b/(-a*d + b*c), Int(S(1)/(a + b*x**n), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/(c + d*x**n), x), x) def replacement876(a, b, c, d, x): return Dist(sqrt(S(3))/(S(2)*c), Int(S(1)/((a + b*x**S(2))**(S(1)/3)*(-x*Rt(b/a, S(2)) + sqrt(S(3)))), x), x) + Dist(sqrt(S(3))/(S(2)*c), Int(S(1)/((a + b*x**S(2))**(S(1)/3)*(x*Rt(b/a, S(2)) + sqrt(S(3)))), x), x) def replacement877(a, b, c, d, x): return Dist(S(1)/6, Int((-x*Rt(-b/a, S(2)) + S(3))/((a + b*x**S(2))**(S(1)/3)*(c + d*x**S(2))), x), x) + Dist(S(1)/6, Int((x*Rt(-b/a, S(2)) + S(3))/((a + b*x**S(2))**(S(1)/3)*(c + d*x**S(2))), x), x) def replacement878(a, b, c, d, x): return Dist(b/d, Int((a + b*x**S(2))**(S(-1)/3), x), x) - Dist((-a*d + b*c)/d, Int(S(1)/((a + b*x**S(2))**(S(1)/3)*(c + d*x**S(2))), x), x) def replacement879(a, b, c, d, x): return Dist(sqrt(-b*x**S(2)/a)/(S(2)*x), Subst(Int(S(1)/(sqrt(-b*x/a)*(a + b*x)**(S(1)/4)*(c + d*x)), x), x, x**S(2)), x) def replacement880(a, b, c, d, x): return Dist(sqrt(-b*x**S(2)/a)/(S(2)*x), Subst(Int(S(1)/(sqrt(-b*x/a)*(a + b*x)**(S(3)/4)*(c + d*x)), x), x, x**S(2)), x) def replacement881(a, b, c, d, p, x): return Dist(b/d, Int((a + b*x**S(2))**(p + S(-1)), x), x) - Dist((-a*d + b*c)/d, Int((a + b*x**S(2))**(p + S(-1))/(c + d*x**S(2)), x), x) def replacement882(a, b, c, d, p, x): return Dist(b/(-a*d + b*c), Int((a + b*x**S(2))**p, x), x) - Dist(d/(-a*d + b*c), Int((a + b*x**S(2))**(p + S(1))/(c + d*x**S(2)), x), x) def replacement883(a, b, c, d, x): return Dist(a/c, Subst(Int(S(1)/(-S(4)*a*b*x**S(4) + S(1)), x), x, x/sqrt(a + b*x**S(4))), x) def With884(a, b, c, d, x): q = Rt(-a*b, S(4)) return Simp(a*ArcTan(q*x*(a + q**S(2)*x**S(2))/(a*sqrt(a + b*x**S(4))))/(S(2)*c*q), x) + Simp(a*atanh(q*x*(a - q**S(2)*x**S(2))/(a*sqrt(a + b*x**S(4))))/(S(2)*c*q), x) def replacement885(a, b, c, d, x): return Dist(b/d, Int(S(1)/sqrt(a + b*x**S(4)), x), x) - Dist((-a*d + b*c)/d, Int(S(1)/(sqrt(a + b*x**S(4))*(c + d*x**S(4))), x), x) def replacement886(a, b, c, d, x): return Dist(sqrt(a/(a + b*x**S(4)))*sqrt(a + b*x**S(4)), Subst(Int(S(1)/((c - x**S(4)*(-a*d + b*c))*sqrt(-b*x**S(4) + S(1))), x), x, x/(a + b*x**S(4))**(S(1)/4)), x) def replacement887(a, b, c, d, p, x): return Dist(b/d, Int((a + b*x**S(4))**(p + S(-1)), x), x) - Dist((-a*d + b*c)/d, Int((a + b*x**S(4))**(p + S(-1))/(c + d*x**S(4)), x), x) def replacement888(a, b, c, d, x): return Dist(S(1)/(S(2)*c), Int(S(1)/(sqrt(a + b*x**S(4))*(-x**S(2)*Rt(-d/c, S(2)) + S(1))), x), x) + Dist(S(1)/(S(2)*c), Int(S(1)/(sqrt(a + b*x**S(4))*(x**S(2)*Rt(-d/c, S(2)) + S(1))), x), x) def replacement889(a, b, c, d, x): return Dist(b/(-a*d + b*c), Int((a + b*x**S(4))**(S(-3)/4), x), x) - Dist(d/(-a*d + b*c), Int((a + b*x**S(4))**(S(1)/4)/(c + d*x**S(4)), x), x) def replacement890(a, b, c, d, x): return Simp(sqrt(a + b*x**S(2))*EllipticE(ArcTan(x*Rt(d/c, S(2))), S(1) - b*c/(a*d))/(c*sqrt(c*(a + b*x**S(2))/(a*(c + d*x**S(2))))*sqrt(c + d*x**S(2))*Rt(d/c, S(2))), x) def replacement891(a, b, c, d, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*Simp(c*(n*(p + S(1)) + S(1)) + d*x**n*(n*(p + q + S(1)) + S(1)), x), x), x) - Simp(x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(a*n*(p + S(1))), x) def replacement892(a, b, c, d, n, p, q, x): return -Dist(S(1)/(a*b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-2))*Simp(c*(a*d - b*c*(n*(p + S(1)) + S(1))) + d*x**n*(a*d*(n*(q + S(-1)) + S(1)) - b*c*(n*(p + q) + S(1))), x), x), x) + Simp(x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*(a*d - b*c)/(a*b*n*(p + S(1))), x) def replacement893(a, b, c, d, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))*(-a*d + b*c)), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(b*c + b*d*x**n*(n*(p + q + S(2)) + S(1)) + n*(p + S(1))*(-a*d + b*c), x), x), x) - Simp(b*x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(a*n*(p + S(1))*(-a*d + b*c)), x) def replacement894(a, b, c, d, n, p, q, x): return Int(ExpandIntegrand((a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement895(a, b, c, d, n, p, q, x): return Dist(S(1)/(b*(n*(p + q) + S(1))), Int((a + b*x**n)**p*(c + d*x**n)**(q + S(-2))*Simp(c*(-a*d + b*c*(n*(p + q) + S(1))) + d*x**n*(-a*d*(n*(q + S(-1)) + S(1)) + b*c*(n*(p + S(2)*q + S(-1)) + S(1))), x), x), x) + Simp(d*x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))/(b*(n*(p + q) + S(1))), x) def replacement896(a, b, c, d, n, p, q, x): return Dist(n/(n*(p + q) + S(1)), Int((a + b*x**n)**(p + S(-1))*(c + d*x**n)**(q + S(-1))*Simp(a*c*(p + q) + x**n*(a*d*(p + q) + q*(-a*d + b*c)), x), x), x) + Simp(x*(a + b*x**n)**p*(c + d*x**n)**q/(n*(p + q) + S(1)), x) def replacement897(a, b, c, d, x): return Simp(sqrt(a + b*x**S(2))*EllipticF(ArcTan(x*Rt(d/c, S(2))), S(1) - b*c/(a*d))/(a*sqrt(c*(a + b*x**S(2))/(a*(c + d*x**S(2))))*sqrt(c + d*x**S(2))*Rt(d/c, S(2))), x) def replacement898(a, b, c, d, x): return Simp(EllipticF(asin(x*Rt(-d/c, S(2))), b*c/(a*d))/(sqrt(a)*sqrt(c)*Rt(-d/c, S(2))), x) def replacement899(a, b, c, d, x): return -Simp(EllipticF(acos(x*Rt(-d/c, S(2))), b*c/(-a*d + b*c))/(sqrt(c)*sqrt(a - b*c/d)*Rt(-d/c, S(2))), x) def replacement900(a, b, c, d, x): return Dist(sqrt(S(1) + d*x**S(2)/c)/sqrt(c + d*x**S(2)), Int(S(1)/(sqrt(S(1) + d*x**S(2)/c)*sqrt(a + b*x**S(2))), x), x) def replacement901(a, b, c, d, x): return Dist(a, Int(S(1)/(sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) + Dist(b, Int(x**S(2)/(sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) def replacement902(a, b, c, d, x): return Dist(b/d, Int(sqrt(c + d*x**S(2))/sqrt(a + b*x**S(2)), x), x) - Dist((-a*d + b*c)/d, Int(S(1)/(sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) def replacement903(a, b, c, d, x): return Simp(sqrt(a)*EllipticE(asin(x*Rt(-d/c, S(2))), b*c/(a*d))/(sqrt(c)*Rt(-d/c, S(2))), x) def replacement904(a, b, c, d, x): return -Simp(sqrt(a - b*c/d)*EllipticE(acos(x*Rt(-d/c, S(2))), b*c/(-a*d + b*c))/(sqrt(c)*Rt(-d/c, S(2))), x) def replacement905(a, b, c, d, x): return Dist(sqrt(a + b*x**S(2))/sqrt(S(1) + b*x**S(2)/a), Int(sqrt(S(1) + b*x**S(2)/a)/sqrt(c + d*x**S(2)), x), x) def replacement906(a, b, c, d, x): return Dist(sqrt(S(1) + d*x**S(2)/c)/sqrt(c + d*x**S(2)), Int(sqrt(a + b*x**S(2))/sqrt(S(1) + d*x**S(2)/c), x), x) def replacement907(a, b, c, d, n, p, q, x): return Int(ExpandIntegrand((a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement908(a, b, c, d, n, p, q, x): return Simp(a**p*c**q*x*AppellF1(S(1)/n, -p, -q, S(1) + S(1)/n, -b*x**n/a, -d*x**n/c), x) def replacement909(a, b, c, d, n, p, q, x): return Dist(a**IntPart(p)*(S(1) + b*x**n/a)**(-FracPart(p))*(a + b*x**n)**FracPart(p), Int((S(1) + b*x**n/a)**p*(c + d*x**n)**q, x), x) def replacement910(a, b, c, d, mn, n, p, q, x): return Int(x**(-n*q)*(a + b*x**n)**p*(c*x**n + d)**q, x) def replacement911(a, b, c, d, mn, n, p, q, x): return Dist(x**(n*FracPart(q))*(c + d*x**(-n))**FracPart(q)*(c*x**n + d)**(-FracPart(q)), Int(x**(-n*q)*(a + b*x**n)**p*(c*x**n + d)**q, x), x) def replacement912(a, b, c, d, n, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x**n)**p*(c + d*x**n)**q, x), x, u), x) def replacement913(p, q, u, v, x): return Int(NormalizePseudoBinomial(u, x)**p*NormalizePseudoBinomial(v, x)**q, x) def replacement914(m, p, q, u, v, x): return Int(NormalizePseudoBinomial(v, x)**q*NormalizePseudoBinomial(u*x**(m/p), x)**p, x) def replacement915(b, c, d, e, m, n, p, q, x): return Dist(b**(S(1) - (m + S(1))/n)*e**m/n, Subst(Int((b*x)**(p + S(-1) + (m + S(1))/n)*(c + d*x)**q, x), x, x**n), x) def replacement916(b, c, d, e, m, n, p, q, x): return Dist(b**IntPart(p)*e**m*x**(-n*FracPart(p))*(b*x**n)**FracPart(p), Int(x**(m + n*p)*(c + d*x**n)**q, x), x) def replacement917(b, c, d, e, m, n, p, q, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(b*x**n)**p*(c + d*x**n)**q, x), x) def replacement918(a, b, c, d, m, n, p, q, x): return Dist(S(1)/n, Subst(Int((a + b*x)**p*(c + d*x)**q, x), x, x**n), x) def replacement919(a, b, c, d, m, n, p, q, x): return Int(x**(m + n*(p + q))*(a*x**(-n) + b)**p*(c*x**(-n) + d)**q, x) def replacement920(a, b, c, d, m, n, p, q, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*x)**p*(c + d*x)**q, x), x, x**n), x) def replacement921(a, b, c, d, e, m, n, p, q, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement922(a, b, c, d, e, m, n, p, q, x): return Int(ExpandIntegrand((e*x)**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement923(a, b, c, d, e, m, n, p, x): return Simp(c*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*e*(m + S(1))), x) def replacement924(a1, a2, b1, b2, c, d, e, m, n, non2, p, x): return Simp(c*(e*x)**(m + S(1))*(a1 + b1*x**(n/S(2)))**(p + S(1))*(a2 + b2*x**(n/S(2)))**(p + S(1))/(a1*a2*e*(m + S(1))), x) def replacement925(a, b, c, d, e, m, n, p, x): return Dist(d*e**(-n), Int((e*x)**(m + n)*(a + b*x**n)**p, x), x) + Simp(c*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*e*(m + S(1))), x) def replacement926(a, b, c, d, e, m, n, p, x): return Dist(d/b, Int((e*x)**m*(a + b*x**n)**(p + S(1)), x), x) + Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(-a*d + b*c)/(a*b*e*(m + S(1))), x) def replacement927(a, b, c, d, e, m, n, p, x): return Dist(e**(-n)*(a*d*(m + S(1)) - b*c*(m + n*(p + S(1)) + S(1)))/(a*(m + S(1))), Int((e*x)**(m + n)*(a + b*x**n)**p, x), x) + Simp(c*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*e*(m + S(1))), x) def replacement928(a1, a2, b1, b2, c, d, e, m, n, non2, p, x): return Dist(e**(-n)*(a1*a2*d*(m + S(1)) - b1*b2*c*(m + n*(p + S(1)) + S(1)))/(a1*a2*(m + S(1))), Int((e*x)**(m + n)*(a1 + b1*x**(n/S(2)))**p*(a2 + b2*x**(n/S(2)))**p, x), x) + Simp(c*(e*x)**(m + S(1))*(a1 + b1*x**(n/S(2)))**(p + S(1))*(a2 + b2*x**(n/S(2)))**(p + S(1))/(a1*a2*e*(m + S(1))), x) def replacement929(a, b, c, d, m, p, x): return Dist(b**(-m/S(2) + S(-1))/(S(2)*(p + S(1))), Int((a + b*x**S(2))**(p + S(1))*ExpandToSum(S(2)*b*x**S(2)*(p + S(1))*Together((b**(m/S(2))*x**(m + S(-2))*(c + d*x**S(2)) - (-a)**(m/S(2) + S(-1))*(-a*d + b*c))/(a + b*x**S(2))) - (-a)**(m/S(2) + S(-1))*(-a*d + b*c), x), x), x) + Simp(b**(-m/S(2) + S(-1))*x*(-a)**(m/S(2) + S(-1))*(a + b*x**S(2))**(p + S(1))*(-a*d + b*c)/(S(2)*(p + S(1))), x) def replacement930(a, b, c, d, m, p, x): return Dist(b**(-m/S(2) + S(-1))/(S(2)*(p + S(1))), Int(x**m*(a + b*x**S(2))**(p + S(1))*ExpandToSum(S(2)*b*(p + S(1))*Together((b**(m/S(2))*(c + d*x**S(2)) - x**(S(2) - m)*(-a)**(m/S(2) + S(-1))*(-a*d + b*c))/(a + b*x**S(2))) - x**(-m)*(-a)**(m/S(2) + S(-1))*(-a*d + b*c), x), x), x) + Simp(b**(-m/S(2) + S(-1))*x*(-a)**(m/S(2) + S(-1))*(a + b*x**S(2))**(p + S(1))*(-a*d + b*c)/(S(2)*(p + S(1))), x) def replacement931(a, b, c, d, e, m, n, p, x): return -Dist((a*d*(m + S(1)) - b*c*(m + n*(p + S(1)) + S(1)))/(a*b*n*(p + S(1))), Int((e*x)**m*(a + b*x**n)**(p + S(1)), x), x) - Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(-a*d + b*c)/(a*b*e*n*(p + S(1))), x) def replacement932(a1, a2, b1, b2, c, d, e, m, n, non2, p, x): return -Dist((a1*a2*d*(m + S(1)) - b1*b2*c*(m + n*(p + S(1)) + S(1)))/(a1*a2*b1*b2*n*(p + S(1))), Int((e*x)**m*(a1 + b1*x**(n/S(2)))**(p + S(1))*(a2 + b2*x**(n/S(2)))**(p + S(1)), x), x) - Simp((e*x)**(m + S(1))*(a1 + b1*x**(n/S(2)))**(p + S(1))*(a2 + b2*x**(n/S(2)))**(p + S(1))*(-a1*a2*d + b1*b2*c)/(a1*a2*b1*b2*e*n*(p + S(1))), x) def replacement933(a, b, c, d, e, m, n, p, x): return -Dist((a*d*(m + S(1)) - b*c*(m + n*(p + S(1)) + S(1)))/(b*(m + n*(p + S(1)) + S(1))), Int((e*x)**m*(a + b*x**n)**p, x), x) + Simp(d*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(b*e*(m + n*(p + S(1)) + S(1))), x) def replacement934(a1, a2, b1, b2, c, d, e, m, n, non2, p, x): return -Dist((a1*a2*d*(m + S(1)) - b1*b2*c*(m + n*(p + S(1)) + S(1)))/(b1*b2*(m + n*(p + S(1)) + S(1))), Int((e*x)**m*(a1 + b1*x**(n/S(2)))**p*(a2 + b2*x**(n/S(2)))**p, x), x) + Simp(d*(e*x)**(m + S(1))*(a1 + b1*x**(n/S(2)))**(p + S(1))*(a2 + b2*x**(n/S(2)))**(p + S(1))/(b1*b2*e*(m + n*(p + S(1)) + S(1))), x) def replacement935(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand((e*x)**m*(a + b*x**n)**p/(c + d*x**n), x), x) def replacement936(a, b, c, d, e, m, n, p, x): return -Dist(e**(-n)/(a*(m + S(1))), Int((e*x)**(m + n)*(a + b*x**n)**p*Simp(-a*d**S(2)*x**n*(m + S(1)) + b*c**S(2)*n*(p + S(1)) + c*(m + S(1))*(-S(2)*a*d + b*c), x), x), x) + Simp(c**S(2)*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*e*(m + S(1))), x) def replacement937(a, b, c, d, e, m, n, p, x): return Dist(S(1)/(a*b**S(2)*n*(p + S(1))), Int((e*x)**m*(a + b*x**n)**(p + S(1))*Simp(a*b*d**S(2)*n*x**n*(p + S(1)) + b**S(2)*c**S(2)*n*(p + S(1)) + (m + S(1))*(-a*d + b*c)**S(2), x), x), x) - Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(-a*d + b*c)**S(2)/(a*b**S(2)*e*n*(p + S(1))), x) def replacement938(a, b, c, d, e, m, n, p, x): return Dist(S(1)/(b*(m + n*(p + S(2)) + S(1))), Int((e*x)**m*(a + b*x**n)**p*Simp(b*c**S(2)*(m + n*(p + S(2)) + S(1)) + d*x**n*(S(2)*b*c*n*(p + S(1)) + (-a*d + S(2)*b*c)*(m + n + S(1))), x), x), x) + Simp(d**S(2)*e**(-n + S(-1))*(e*x)**(m + n + S(1))*(a + b*x**n)**(p + S(1))/(b*(m + n*(p + S(2)) + S(1))), x) def With939(a, b, c, d, m, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False k = GCD(m + S(1), n) if Unequal(k, S(1)): return True return False def replacement939(a, b, c, d, m, n, p, q, x): k = GCD(m + S(1), n) return Dist(S(1)/k, Subst(Int(x**(S(-1) + (m + S(1))/k)*(a + b*x**(n/k))**p*(c + d*x**(n/k))**q, x), x, x**k), x) def With940(a, b, c, d, e, m, n, p, q, x): k = Denominator(m) return Dist(k/e, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*e**(-n)*x**(k*n))**p*(c + d*e**(-n)*x**(k*n))**q, x), x, (e*x)**(S(1)/k)), x) def replacement941(a, b, c, d, e, m, n, p, q, x): return -Dist(e**n/(b*n*(p + S(1))), Int((e*x)**(m - n)*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*Simp(c*(m - n + S(1)) + d*x**n*(m + n*(q + S(-1)) + S(1)), x), x), x) + Simp(e**(n + S(-1))*(e*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(b*n*(p + S(1))), x) def replacement942(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(a*b*n*(p + S(1))), Int((e*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-2))*Simp(c*(b*c*n*(p + S(1)) + (m + S(1))*(-a*d + b*c)) + d*x**n*(b*c*n*(p + S(1)) + (-a*d + b*c)*(m + n*(q + S(-1)) + S(1))), x), x), x) - Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*(-a*d + b*c)/(a*b*e*n*(p + S(1))), x) def replacement943(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))), Int((e*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*Simp(c*(m + n*(p + S(1)) + S(1)) + d*x**n*(m + n*(p + q + S(1)) + S(1)), x), x), x) - Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(a*e*n*(p + S(1))), x) def replacement944(a, b, c, d, e, m, n, p, q, x): return Dist(e**(S(2)*n)/(b*n*(p + S(1))*(-a*d + b*c)), Int((e*x)**(m - S(2)*n)*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(a*c*(m - S(2)*n + S(1)) + x**n*(a*d*(m + n*q - n + S(1)) + b*c*n*(p + S(1))), x), x), x) - Simp(a*e**(S(2)*n + S(-1))*(e*x)**(m - S(2)*n + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(b*n*(p + S(1))*(-a*d + b*c)), x) def replacement945(a, b, c, d, e, m, n, p, q, x): return -Dist(e**n/(n*(p + S(1))*(-a*d + b*c)), Int((e*x)**(m - n)*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(c*(m - n + S(1)) + d*x**n*(m + n*(p + q + S(1)) + S(1)), x), x), x) + Simp(e**(n + S(-1))*(e*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(n*(p + S(1))*(-a*d + b*c)), x) def replacement946(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))*(-a*d + b*c)), Int((e*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(b*c*(m + S(1)) + b*d*x**n*(m + n*(p + q + S(2)) + S(1)) + n*(p + S(1))*(-a*d + b*c), x), x), x) - Simp(b*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(a*e*n*(p + S(1))*(-a*d + b*c)), x) def replacement947(a, b, c, d, e, m, n, p, q, x): return -Dist(e**(-n)*n/(m + S(1)), Int((e*x)**(m + n)*(a + b*x**n)**(p + S(-1))*(c + d*x**n)**(q + S(-1))*Simp(a*d*q + b*c*p + b*d*x**n*(p + q), x), x), x) + Simp((e*x)**(m + S(1))*(a + b*x**n)**p*(c + d*x**n)**q/(e*(m + S(1))), x) def replacement948(a, b, c, d, e, m, n, p, q, x): return -Dist(e**(-n)/(a*(m + S(1))), Int((e*x)**(m + n)*(a + b*x**n)**p*(c + d*x**n)**(q + S(-2))*Simp(c*n*(a*d*(q + S(-1)) + b*c*(p + S(1))) + c*(m + S(1))*(-a*d + b*c) + d*x**n*(b*c*n*(p + q) + (m + S(1))*(-a*d + b*c)), x), x), x) + Simp(c*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))/(a*e*(m + S(1))), x) def replacement949(a, b, c, d, e, m, n, p, q, x): return -Dist(e**(-n)/(a*(m + S(1))), Int((e*x)**(m + n)*(a + b*x**n)**p*(c + d*x**n)**(q + S(-1))*Simp(b*c*(m + S(1)) + d*x**n*(b*n*(p + q + S(1)) + b*(m + S(1))) + n*(a*d*q + b*c*(p + S(1))), x), x), x) + Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(a*e*(m + S(1))), x) def replacement950(a, b, c, d, e, m, n, p, q, x): return Dist(n/(m + n*(p + q) + S(1)), Int((e*x)**m*(a + b*x**n)**(p + S(-1))*(c + d*x**n)**(q + S(-1))*Simp(a*c*(p + q) + x**n*(a*d*(p + q) + q*(-a*d + b*c)), x), x), x) + Simp((e*x)**(m + S(1))*(a + b*x**n)**p*(c + d*x**n)**q/(e*(m + n*(p + q) + S(1))), x) def replacement951(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(b*(m + n*(p + q) + S(1))), Int((e*x)**m*(a + b*x**n)**p*(c + d*x**n)**(q + S(-2))*Simp(c*(b*c*n*(p + q) + (m + S(1))*(-a*d + b*c)) + x**n*(b*c*d*n*(p + q) + d*n*(q + S(-1))*(-a*d + b*c) + d*(m + S(1))*(-a*d + b*c)), x), x), x) + Simp(d*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))/(b*e*(m + n*(p + q) + S(1))), x) def replacement952(a, b, c, d, e, m, n, p, q, x): return -Dist(e**n/(b*(m + n*(p + q) + S(1))), Int((e*x)**(m - n)*(a + b*x**n)**p*(c + d*x**n)**(q + S(-1))*Simp(a*c*(m - n + S(1)) + x**n*(a*d*(m - n + S(1)) - n*q*(-a*d + b*c)), x), x), x) + Simp(e**(n + S(-1))*(e*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(b*(m + n*(p + q) + S(1))), x) def replacement953(a, b, c, d, e, m, n, p, q, x): return -Dist(e**(S(2)*n)/(b*d*(m + n*(p + q) + S(1))), Int((e*x)**(m - S(2)*n)*(a + b*x**n)**p*(c + d*x**n)**q*Simp(a*c*(m - S(2)*n + S(1)) + x**n*(a*d*(m + n*(q + S(-1)) + S(1)) + b*c*(m + n*(p + S(-1)) + S(1))), x), x), x) + Simp(e**(S(2)*n + S(-1))*(e*x)**(m - S(2)*n + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(b*d*(m + n*(p + q) + S(1))), x) def replacement954(a, b, c, d, e, m, n, p, q, x): return -Dist(e**(-n)/(a*c*(m + S(1))), Int((e*x)**(m + n)*(a + b*x**n)**p*(c + d*x**n)**q*Simp(b*d*x**n*(m + n*(p + q + S(2)) + S(1)) + n*(a*d*q + b*c*p) + (a*d + b*c)*(m + n + S(1)), x), x), x) + Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(a*c*e*(m + S(1))), x) def replacement955(a, b, c, d, e, m, n, x): return -Dist(a*e**n/(-a*d + b*c), Int((e*x)**(m - n)/(a + b*x**n), x), x) + Dist(c*e**n/(-a*d + b*c), Int((e*x)**(m - n)/(c + d*x**n), x), x) def replacement956(a, b, c, d, e, m, n, x): return Dist(b/(-a*d + b*c), Int((e*x)**m/(a + b*x**n), x), x) - Dist(d/(-a*d + b*c), Int((e*x)**m/(c + d*x**n), x), x) def replacement957(a, b, c, d, m, n, x): return Dist(S(1)/b, Int(x**(m - n)/sqrt(c + d*x**n), x), x) - Dist(a/b, Int(x**(m - n)/((a + b*x**n)*sqrt(c + d*x**n)), x), x) def With958(a, b, c, d, x): r = Numerator(Rt(-a/b, S(2))) s = Denominator(Rt(-a/b, S(2))) return -Dist(s/(S(2)*b), Int(S(1)/(sqrt(c + d*x**S(4))*(r - s*x**S(2))), x), x) + Dist(s/(S(2)*b), Int(S(1)/(sqrt(c + d*x**S(4))*(r + s*x**S(2))), x), x) def With959(a, b, c, d, x): q = Rt(d/c, S(3)) return Simp(S(2)**(S(1)/3)*q*log(-S(2)**(S(1)/3)*q*x + S(1) - sqrt(c + d*x**S(3))/sqrt(c))/(S(12)*b*sqrt(c)), x) - Simp(S(2)**(S(1)/3)*q*log(-S(2)**(S(1)/3)*q*x + S(1) + sqrt(c + d*x**S(3))/sqrt(c))/(S(12)*b*sqrt(c)), x) + Simp(S(2)**(S(1)/3)*q*atanh(sqrt(c + d*x**S(3))/sqrt(c))/(S(18)*b*sqrt(c)), x) - Simp(S(2)**(S(1)/3)*sqrt(S(3))*q*ArcTan(sqrt(S(3))/S(3) + S(2)**(S(2)/3)*sqrt(S(3))*(sqrt(c) - sqrt(c + d*x**S(3)))/(S(3)*sqrt(c)*q*x))/(S(18)*b*sqrt(c)), x) + Simp(S(2)**(S(1)/3)*sqrt(S(3))*q*ArcTan(sqrt(S(3))/S(3) + S(2)**(S(2)/3)*sqrt(S(3))*(sqrt(c) + sqrt(c + d*x**S(3)))/(S(3)*sqrt(c)*q*x))/(S(18)*b*sqrt(c)), x) def replacement960(a, b, c, d, m, x): return Dist(S(1)/b, Int(x**(m + S(-3))/sqrt(c + d*x**S(3)), x), x) - Dist(a/b, Int(x**(m + S(-3))/((a + b*x**S(3))*sqrt(c + d*x**S(3))), x), x) def replacement961(a, b, c, d, m, x): return Dist(S(1)/a, Int(x**m/sqrt(c + d*x**S(3)), x), x) - Dist(b/a, Int(x**(m + S(3))/((a + b*x**S(3))*sqrt(c + d*x**S(3))), x), x) def replacement962(a, b, c, d, x): return Dist(d/b, Int(x**S(2)/sqrt(c + d*x**S(4)), x), x) + Dist((-a*d + b*c)/b, Int(x**S(2)/((a + b*x**S(4))*sqrt(c + d*x**S(4))), x), x) def replacement963(a, b, c, d, m, x): return Dist(d/b, Int(x**m/sqrt(c + d*x**S(3)), x), x) + Dist((-a*d + b*c)/b, Int(x**m/((a + b*x**S(3))*sqrt(c + d*x**S(3))), x), x) def replacement964(a, b, c, d, x): return -Dist(c/b, Int(sqrt(a + b*x**S(2))/(c + d*x**S(2))**(S(3)/2), x), x) + Simp(x*sqrt(a + b*x**S(2))/(b*sqrt(c + d*x**S(2))), x) def replacement965(a, b, c, d, n, x): return Dist(S(1)/b, Int(sqrt(a + b*x**n)/sqrt(c + d*x**n), x), x) - Dist(a/b, Int(S(1)/(sqrt(a + b*x**n)*sqrt(c + d*x**n)), x), x) def With966(a, b, c, d, m, n, p, q, x): k = Denominator(p) return Dist(a**(p + (m + S(1))/n)*k/n, Subst(Int(x**(k*(m + S(1))/n + S(-1))*(c - x**k*(-a*d + b*c))**q*(-b*x**k + S(1))**(-p - q + S(-1) - (m + S(1))/n), x), x, x**(n/k)*(a + b*x**n)**(-S(1)/k)), x) def replacement967(a, b, c, d, m, n, p, q, x): return -Subst(Int(x**(-m + S(-2))*(a + b*x**(-n))**p*(c + d*x**(-n))**q, x), x, S(1)/x) def With968(a, b, c, d, e, m, n, p, q, x): g = Denominator(m) return -Dist(g/e, Subst(Int(x**(-g*(m + S(1)) + S(-1))*(a + b*e**(-n)*x**(-g*n))**p*(c + d*e**(-n)*x**(-g*n))**q, x), x, (e*x)**(-S(1)/g)), x) def replacement969(a, b, c, d, e, m, n, p, q, x): return -Dist((e*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a + b*x**(-n))**p*(c + d*x**(-n))**q, x), x, S(1)/x), x) def With970(a, b, c, d, m, n, p, q, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g*(m + S(1)) + S(-1))*(a + b*x**(g*n))**p*(c + d*x**(g*n))**q, x), x, x**(S(1)/g)), x) def replacement971(a, b, c, d, e, m, n, p, q, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement972(a, b, c, d, m, n, p, q, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*x**(n/(m + S(1))))**p*(c + d*x**(n/(m + S(1))))**q, x), x, x**(m + S(1))), x) def replacement973(a, b, c, d, e, m, n, p, q, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement974(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(a*b*n*(p + S(1))), Int((e*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-2))*Simp(c*(b*c*n*(p + S(1)) + (m + S(1))*(-a*d + b*c)) + d*x**n*(b*c*n*(p + S(1)) + (-a*d + b*c)*(m + n*(q + S(-1)) + S(1))), x), x), x) - Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*(-a*d + b*c)/(a*b*e*n*(p + S(1))), x) def replacement975(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))), Int((e*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*Simp(c*(m + n*(p + S(1)) + S(1)) + d*x**n*(m + n*(p + q + S(1)) + S(1)), x), x), x) - Simp((e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(a*e*n*(p + S(1))), x) def replacement976(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))*(-a*d + b*c)), Int((e*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(b*c*(m + S(1)) + b*d*x**n*(m + n*(p + q + S(2)) + S(1)) + n*(p + S(1))*(-a*d + b*c), x), x), x) - Simp(b*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(a*e*n*(p + S(1))*(-a*d + b*c)), x) def replacement977(a, b, c, d, e, m, n, p, q, x): return Dist(n/(m + n*(p + q) + S(1)), Int((e*x)**m*(a + b*x**n)**(p + S(-1))*(c + d*x**n)**(q + S(-1))*Simp(a*c*(p + q) + x**n*(a*d*(p + q) + q*(-a*d + b*c)), x), x), x) + Simp((e*x)**(m + S(1))*(a + b*x**n)**p*(c + d*x**n)**q/(e*(m + n*(p + q) + S(1))), x) def replacement978(a, b, c, d, e, m, n, p, q, x): return Dist(S(1)/(b*(m + n*(p + q) + S(1))), Int((e*x)**m*(a + b*x**n)**p*(c + d*x**n)**(q + S(-2))*Simp(c*(b*c*n*(p + q) + (m + S(1))*(-a*d + b*c)) + x**n*(b*c*d*n*(p + q) + d*n*(q + S(-1))*(-a*d + b*c) + d*(m + S(1))*(-a*d + b*c)), x), x), x) + Simp(d*(e*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))/(b*e*(m + n*(p + q) + S(1))), x) def replacement979(a, b, c, d, m, n, x): return -Dist(a/(-a*d + b*c), Int(x**(m - n)/(a + b*x**n), x), x) + Dist(c/(-a*d + b*c), Int(x**(m - n)/(c + d*x**n), x), x) def replacement980(a, b, c, d, e, m, n, x): return Dist(b/(-a*d + b*c), Int((e*x)**m/(a + b*x**n), x), x) - Dist(d/(-a*d + b*c), Int((e*x)**m/(c + d*x**n), x), x) def replacement981(a, b, c, d, e, m, n, p, q, x): return Int(ExpandIntegrand((e*x)**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement982(a, b, c, d, m, mn, n, p, q, x): return Int(x**(m - n*q)*(a + b*x**n)**p*(c*x**n + d)**q, x) def replacement983(a, b, c, d, m, mn, n, p, q, x): return Dist(x**(n*FracPart(q))*(c + d*x**(-n))**FracPart(q)*(c*x**n + d)**(-FracPart(q)), Int(x**(m - n*q)*(a + b*x**n)**p*(c*x**n + d)**q, x), x) def replacement984(a, b, c, d, e, m, mn, n, p, q, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**(-n))**q, x), x) def replacement985(a, b, c, d, e, m, n, p, q, x): return Simp(a**p*c**q*(e*x)**(m + S(1))*AppellF1((m + S(1))/n, -p, -q, S(1) + (m + S(1))/n, -b*x**n/a, -d*x**n/c)/(e*(m + S(1))), x) def replacement986(a, b, c, d, e, m, n, p, q, x): return Dist(a**IntPart(p)*(S(1) + b*x**n/a)**(-FracPart(p))*(a + b*x**n)**FracPart(p), Int((e*x)**m*(S(1) + b*x**n/a)**p*(c + d*x**n)**q, x), x) def replacement987(a, b, c, d, m, n, p, q, v, x): return Dist(Coefficient(v, x, S(1))**(-m + S(-1)), Subst(Int(SimplifyIntegrand((a + b*x**n)**p*(c + d*x**n)**q*(x - Coefficient(v, x, S(0)))**m, x), x), x, v), x) def replacement988(a, b, c, d, m, n, p, q, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x, v), x) def replacement989(a1, a2, b1, b2, c, d, n, non2, p, q, u, x): return Int(u*(c + d*x**n)**q*(a1*a2 + b1*b2*x**n)**p, x) def replacement990(a1, a2, b1, b2, c, d, e, n, n2, non2, p, q, u, x): return Int(u*(a1*a2 + b1*b2*x**n)**p*(c + d*x**n + e*x**(S(2)*n))**q, x) def replacement991(a1, a2, b1, b2, c, d, n, non2, p, q, u, x): return Dist((a1 + b1*x**(n/S(2)))**FracPart(p)*(a2 + b2*x**(n/S(2)))**FracPart(p)*(a1*a2 + b1*b2*x**n)**(-FracPart(p)), Int(u*(c + d*x**n)**q*(a1*a2 + b1*b2*x**n)**p, x), x) def replacement992(a1, a2, b1, b2, c, d, e, n, n2, non2, p, q, u, x): return Dist((a1 + b1*x**(n/S(2)))**FracPart(p)*(a2 + b2*x**(n/S(2)))**FracPart(p)*(a1*a2 + b1*b2*x**n)**(-FracPart(p)), Int(u*(a1*a2 + b1*b2*x**n)**p*(c + d*x**n + e*x**(S(2)*n))**q, x), x) def replacement993(a, b, c, d, e, f, n, p, q, r, x): return Int(ExpandIntegrand((a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def replacement994(a, b, c, d, e, f, n, x): return Dist((-a*f + b*e)/(-a*d + b*c), Int(S(1)/(a + b*x**n), x), x) - Dist((-c*f + d*e)/(-a*d + b*c), Int(S(1)/(c + d*x**n), x), x) def replacement995(a, b, c, d, e, f, n, x): return Dist(f/b, Int(S(1)/sqrt(c + d*x**n), x), x) + Dist((-a*f + b*e)/b, Int(S(1)/((a + b*x**n)*sqrt(c + d*x**n)), x), x) def replacement996(a, b, c, d, e, f, n, x): return Dist(f/b, Int(sqrt(a + b*x**n)/sqrt(c + d*x**n), x), x) + Dist((-a*f + b*e)/b, Int(S(1)/(sqrt(a + b*x**n)*sqrt(c + d*x**n)), x), x) def replacement997(a, b, c, d, e, f, x): return Dist((-a*f + b*e)/(-a*d + b*c), Int(S(1)/(sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) - Dist((-c*f + d*e)/(-a*d + b*c), Int(sqrt(a + b*x**S(2))/(c + d*x**S(2))**(S(3)/2), x), x) def replacement998(a, b, c, d, e, f, n, p, q, x): return Dist(S(1)/(a*b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*Simp(c*(-a*f + b*e*n*(p + S(1)) + b*e) + d*x**n*(b*e*n*(p + S(1)) + (-a*f + b*e)*(n*q + S(1))), x), x), x) - Simp(x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*(-a*f + b*e)/(a*b*n*(p + S(1))), x) def replacement999(a, b, c, d, e, f, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))*(-a*d + b*c)), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(c*(-a*f + b*e) + d*x**n*(-a*f + b*e)*(n*(p + q + S(2)) + S(1)) + e*n*(p + S(1))*(-a*d + b*c), x), x), x) - Simp(x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))*(-a*f + b*e)/(a*n*(p + S(1))*(-a*d + b*c)), x) def replacement1000(a, b, c, d, e, f, n, p, q, x): return Dist(S(1)/(b*(n*(p + q + S(1)) + S(1))), Int((a + b*x**n)**p*(c + d*x**n)**(q + S(-1))*Simp(c*(-a*f + b*e*n*(p + q + S(1)) + b*e) + x**n*(b*d*e*n*(p + q + S(1)) + d*(-a*f + b*e) + f*n*q*(-a*d + b*c)), x), x), x) + Simp(f*x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(b*(n*(p + q + S(1)) + S(1))), x) def replacement1001(a, b, c, d, e, f, x): return Dist((-a*f + b*e)/(-a*d + b*c), Int((a + b*x**S(4))**(S(-3)/4), x), x) - Dist((-c*f + d*e)/(-a*d + b*c), Int((a + b*x**S(4))**(S(1)/4)/(c + d*x**S(4)), x), x) def replacement1002(a, b, c, d, e, f, n, p, x): return Dist(f/d, Int((a + b*x**n)**p, x), x) + Dist((-c*f + d*e)/d, Int((a + b*x**n)**p/(c + d*x**n), x), x) def replacement1003(a, b, c, d, e, f, n, p, q, x): return Dist(e, Int((a + b*x**n)**p*(c + d*x**n)**q, x), x) + Dist(f, Int(x**n*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement1004(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/((a + b*x**S(2))*sqrt(e + f*x**S(2))), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/((c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) def replacement1005(c, d, e, f, x): return Dist(S(1)/c, Int(S(1)/(x**S(2)*sqrt(e + f*x**S(2))), x), x) - Dist(d/c, Int(S(1)/((c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) def replacement1006(a, b, c, d, e, f, x): return Dist(d/b, Int(sqrt(e + f*x**S(2))/sqrt(c + d*x**S(2)), x), x) + Dist((-a*d + b*c)/b, Int(sqrt(e + f*x**S(2))/((a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) def replacement1007(a, b, c, d, e, f, x): return Dist(d/b, Int(sqrt(e + f*x**S(2))/sqrt(c + d*x**S(2)), x), x) + Dist((-a*d + b*c)/b, Int(sqrt(e + f*x**S(2))/((a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) def replacement1008(a, b, c, d, e, f, x): return Dist(b/(-a*f + b*e), Int(sqrt(e + f*x**S(2))/((a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) - Dist(f/(-a*f + b*e), Int(S(1)/(sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) def replacement1009(a, b, c, d, e, f, x): return Simp(EllipticPi(b*c/(a*d), asin(x*Rt(-d/c, S(2))), c*f/(d*e))/(a*sqrt(c)*sqrt(e)*Rt(-d/c, S(2))), x) def replacement1010(a, b, c, d, e, f, x): return Dist(sqrt(S(1) + d*x**S(2)/c)/sqrt(c + d*x**S(2)), Int(S(1)/(sqrt(S(1) + d*x**S(2)/c)*(a + b*x**S(2))*sqrt(e + f*x**S(2))), x), x) def replacement1011(a, b, c, d, e, f, x): return Simp(c*sqrt(e + f*x**S(2))*EllipticPi(S(1) - b*c/(a*d), ArcTan(x*Rt(d/c, S(2))), -c*f/(d*e) + S(1))/(a*e*sqrt(c*(e + f*x**S(2))/(e*(c + d*x**S(2))))*sqrt(c + d*x**S(2))*Rt(d/c, S(2))), x) def replacement1012(a, b, c, d, e, f, x): return Dist(d/b, Int(S(1)/(sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) + Dist((-a*d + b*c)/b, Int(S(1)/((a + b*x**S(2))*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) def replacement1013(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(sqrt(e + f*x**S(2))/((a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) - Dist(d/(-a*d + b*c), Int(sqrt(e + f*x**S(2))/(c + d*x**S(2))**(S(3)/2), x), x) def replacement1014(a, b, c, d, e, f, x): return Dist((-a*f + b*e)/(-a*d + b*c), Int(sqrt(e + f*x**S(2))/((a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) - Dist((-c*f + d*e)/(-a*d + b*c), Int(sqrt(e + f*x**S(2))/(c + d*x**S(2))**(S(3)/2), x), x) def replacement1015(a, b, c, d, e, f, x): return Dist(d/b**S(2), Int(sqrt(e + f*x**S(2))*(-a*d + S(2)*b*c + b*d*x**S(2))/sqrt(c + d*x**S(2)), x), x) + Dist((-a*d + b*c)**S(2)/b**S(2), Int(sqrt(e + f*x**S(2))/((a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) def replacement1016(a, b, c, d, e, f, q, r, x): return Dist(b*(-a*f + b*e)/(-a*d + b*c)**S(2), Int((c + d*x**S(2))**(q + S(2))*(e + f*x**S(2))**(r + S(-1))/(a + b*x**S(2)), x), x) - Dist((-a*d + b*c)**(S(-2)), Int((c + d*x**S(2))**q*(e + f*x**S(2))**(r + S(-1))*(-a*d**S(2)*e - b*c**S(2)*f + S(2)*b*c*d*e + d**S(2)*x**S(2)*(-a*f + b*e)), x), x) def replacement1017(a, b, c, d, e, f, q, r, x): return Dist(d/b, Int((c + d*x**S(2))**(q + S(-1))*(e + f*x**S(2))**r, x), x) + Dist((-a*d + b*c)/b, Int((c + d*x**S(2))**(q + S(-1))*(e + f*x**S(2))**r/(a + b*x**S(2)), x), x) def replacement1018(a, b, c, d, e, f, q, r, x): return Dist(b**S(2)/(-a*d + b*c)**S(2), Int((c + d*x**S(2))**(q + S(2))*(e + f*x**S(2))**r/(a + b*x**S(2)), x), x) - Dist(d/(-a*d + b*c)**S(2), Int((c + d*x**S(2))**q*(e + f*x**S(2))**r*(-a*d + S(2)*b*c + b*d*x**S(2)), x), x) def replacement1019(a, b, c, d, e, f, q, r, x): return Dist(b/(-a*d + b*c), Int((c + d*x**S(2))**(q + S(1))*(e + f*x**S(2))**r/(a + b*x**S(2)), x), x) - Dist(d/(-a*d + b*c), Int((c + d*x**S(2))**q*(e + f*x**S(2))**r, x), x) def replacement1020(a, b, c, d, e, f, x): return Dist((-a**S(2)*d*f + b**S(2)*c*e)/(S(2)*a*b**S(2)), Int(S(1)/((a + b*x**S(2))*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) + Dist(d*f/(S(2)*a*b**S(2)), Int((a - b*x**S(2))/(sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) + Simp(x*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))/(S(2)*a*(a + b*x**S(2))), x) def replacement1021(a, b, c, d, e, f, x): return Dist((S(3)*a**S(2)*d*f - S(2)*a*b*(c*f + d*e) + b**S(2)*c*e)/(S(2)*a*(-a*d + b*c)*(-a*f + b*e)), Int(S(1)/((a + b*x**S(2))*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) - Dist(d*f/(S(2)*a*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x**S(2))/(sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) + Simp(b**S(2)*x*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))/(S(2)*a*(a + b*x**S(2))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement1022(a, b, c, d, e, f, n, p, q, r, x): return Dist(d/b, Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*(e + f*x**n)**r, x), x) + Dist((-a*d + b*c)/b, Int((a + b*x**n)**p*(c + d*x**n)**(q + S(-1))*(e + f*x**n)**r, x), x) def replacement1023(a, b, c, d, e, f, n, p, q, r, x): return Dist(b/(-a*d + b*c), Int((a + b*x**n)**p*(c + d*x**n)**(q + S(1))*(e + f*x**n)**r, x), x) - Dist(d/(-a*d + b*c), Int((a + b*x**n)**(p + S(1))*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def replacement1024(a, b, c, d, e, f, x): return Dist(sqrt(a*(e + f*x**S(2))/(e*(a + b*x**S(2))))*sqrt(c + d*x**S(2))/(c*sqrt(a*(c + d*x**S(2))/(c*(a + b*x**S(2))))*sqrt(e + f*x**S(2))), Subst(Int(S(1)/(sqrt(S(1) - x**S(2)*(-a*d + b*c)/c)*sqrt(S(1) - x**S(2)*(-a*f + b*e)/e)), x), x, x/sqrt(a + b*x**S(2))), x) def replacement1025(a, b, c, d, e, f, x): return Dist(a*sqrt(a*(e + f*x**S(2))/(e*(a + b*x**S(2))))*sqrt(c + d*x**S(2))/(c*sqrt(a*(c + d*x**S(2))/(c*(a + b*x**S(2))))*sqrt(e + f*x**S(2))), Subst(Int(S(1)/(sqrt(S(1) - x**S(2)*(-a*d + b*c)/c)*sqrt(S(1) - x**S(2)*(-a*f + b*e)/e)*(-b*x**S(2) + S(1))), x), x, x/sqrt(a + b*x**S(2))), x) def replacement1026(a, b, c, d, e, f, x): return Dist(sqrt(a*(e + f*x**S(2))/(e*(a + b*x**S(2))))*sqrt(c + d*x**S(2))/(a*sqrt(a*(c + d*x**S(2))/(c*(a + b*x**S(2))))*sqrt(e + f*x**S(2))), Subst(Int(sqrt(S(1) - x**S(2)*(-a*d + b*c)/c)/sqrt(S(1) - x**S(2)*(-a*f + b*e)/e), x), x, x/sqrt(a + b*x**S(2))), x) def replacement1027(a, b, c, d, e, f, x): return -Dist(c*(-c*f + d*e)/(S(2)*f), Int(sqrt(a + b*x**S(2))/((c + d*x**S(2))**(S(3)/2)*sqrt(e + f*x**S(2))), x), x) - Dist((-a*d*f - b*c*f + b*d*e)/(S(2)*d*f), Int(sqrt(c + d*x**S(2))/(sqrt(a + b*x**S(2))*sqrt(e + f*x**S(2))), x), x) + Dist(b*c*(-c*f + d*e)/(S(2)*d*f), Int(S(1)/(sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) + Simp(d*x*sqrt(a + b*x**S(2))*sqrt(e + f*x**S(2))/(S(2)*f*sqrt(c + d*x**S(2))), x) def replacement1028(a, b, c, d, e, f, x): return -Dist((-a*d*f - b*c*f + b*d*e)/(S(2)*f**S(2)), Int(sqrt(e + f*x**S(2))/(sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))), x), x) + Dist(e*(-a*f + b*e)/(S(2)*f), Int(sqrt(c + d*x**S(2))/(sqrt(a + b*x**S(2))*(e + f*x**S(2))**(S(3)/2)), x), x) + Dist((-a*f + b*e)*(-S(2)*c*f + d*e)/(S(2)*f**S(2)), Int(S(1)/(sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) + Simp(x*sqrt(a + b*x**S(2))*sqrt(c + d*x**S(2))/(S(2)*sqrt(e + f*x**S(2))), x) def replacement1029(a, b, c, d, e, f, x): return Dist(b/f, Int(sqrt(c + d*x**S(2))/(sqrt(a + b*x**S(2))*sqrt(e + f*x**S(2))), x), x) - Dist((-a*f + b*e)/f, Int(sqrt(c + d*x**S(2))/(sqrt(a + b*x**S(2))*(e + f*x**S(2))**(S(3)/2)), x), x) def With1030(a, b, c, d, e, f, n, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x) if SumQ(u): return True return False def replacement1030(a, b, c, d, e, f, n, p, q, r, x): u = ExpandIntegrand((a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x) return Int(u, x) def replacement1031(a, b, c, d, e, f, n, p, q, r, x): return -Subst(Int((a + b*x**(-n))**p*(c + d*x**(-n))**q*(e + f*x**(-n))**r/x**S(2), x), x, S(1)/x) def replacement1032(a, b, c, d, e, f, n, p, q, r, x): return Int((a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x) def replacement1033(a, b, c, d, e, f, n, p, q, r, u, v, w, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x, u), x) def replacement1034(a, b, c, d, e, f, mn, n, p, q, r, x): return Int(x**(-n*q)*(a + b*x**n)**p*(e + f*x**n)**r*(c*x**n + d)**q, x) def replacement1035(a, b, c, d, e, f, mn, n, p, q, r, x): return Int(x**(n*(p + r))*(c + d*x**(-n))**q*(a*x**(-n) + b)**p*(e*x**(-n) + f)**r, x) def replacement1036(a, b, c, d, e, f, mn, n, p, q, r, x): return Dist(x**(n*FracPart(q))*(c + d*x**(-n))**FracPart(q)*(c*x**n + d)**(-FracPart(q)), Int(x**(-n*q)*(a + b*x**n)**p*(e + f*x**n)**r*(c*x**n + d)**q, x), x) def replacement1037(a, b, c, d, e1, e2, f1, f2, n, n2, p, q, r, x): return Int((a + b*x**n)**p*(c + d*x**n)**q*(e1*e2 + f1*f2*x**n)**r, x) def replacement1038(a, b, c, d, e1, e2, f1, f2, n, n2, p, q, r, x): return Dist((e1 + f1*x**(n/S(2)))**FracPart(r)*(e2 + f2*x**(n/S(2)))**FracPart(r)*(e1*e2 + f1*f2*x**n)**(-FracPart(r)), Int((a + b*x**n)**p*(c + d*x**n)**q*(e1*e2 + f1*f2*x**n)**r, x), x) def replacement1039(b, c, d, e, f, g, m, n, p, q, r, x): return Dist(b**(S(1) - (m + S(1))/n)*g**m/n, Subst(Int((b*x)**(p + S(-1) + (m + S(1))/n)*(c + d*x)**q*(e + f*x)**r, x), x, x**n), x) def replacement1040(b, c, d, e, f, g, m, n, p, q, r, x): return Dist(b**IntPart(p)*g**m*x**(-n*FracPart(p))*(b*x**n)**FracPart(p), Int(x**(m + n*p)*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def replacement1041(b, c, d, e, f, g, m, n, p, q, r, x): return Dist(g**IntPart(m)*x**(-FracPart(m))*(g*x)**FracPart(m), Int(x**m*(b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def replacement1042(a, b, c, d, e, f, g, m, n, p, q, r, x): return Int(ExpandIntegrand((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def replacement1043(a, b, c, d, e, f, m, n, p, q, r, x): return Dist(S(1)/n, Subst(Int((a + b*x)**p*(c + d*x)**q*(e + f*x)**r, x), x, x**n), x) def replacement1044(a, b, c, d, e, f, m, n, p, q, r, x): return Int(x**(m + n*(p + q + r))*(a*x**(-n) + b)**p*(c*x**(-n) + d)**q*(e*x**(-n) + f)**r, x) def replacement1045(a, b, c, d, e, f, m, n, p, q, r, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*x)**p*(c + d*x)**q*(e + f*x)**r, x), x, x**n), x) def replacement1046(a, b, c, d, e, f, g, m, n, p, q, r, x): return Dist(g**IntPart(m)*x**(-FracPart(m))*(g*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def With1047(a, b, c, d, e, f, m, n, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False k = GCD(m + S(1), n) if Unequal(k, S(1)): return True return False def replacement1047(a, b, c, d, e, f, m, n, p, q, r, x): k = GCD(m + S(1), n) return Dist(S(1)/k, Subst(Int(x**(S(-1) + (m + S(1))/k)*(a + b*x**(n/k))**p*(c + d*x**(n/k))**q*(e + f*x**(n/k))**r, x), x, x**k), x) def With1048(a, b, c, d, e, f, g, m, n, p, q, r, x): k = Denominator(m) return Dist(k/g, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*g**(-n)*x**(k*n))**p*(c + d*g**(-n)*x**(k*n))**q*(e + f*g**(-n)*x**(k*n))**r, x), x, (g*x)**(S(1)/k)), x) def replacement1049(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(S(1)/(a*b*n*(p + S(1))), Int((g*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*Simp(c*(b*e*n*(p + S(1)) + (m + S(1))*(-a*f + b*e)) + d*x**n*(b*e*n*(p + S(1)) + (-a*f + b*e)*(m + n*q + S(1))), x), x), x) - Simp((g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*(-a*f + b*e)/(a*b*g*n*(p + S(1))), x) def replacement1050(a, b, c, d, e, f, g, m, n, p, q, x): return -Dist(g**n/(b*n*(p + S(1))*(-a*d + b*c)), Int((g*x)**(m - n)*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(c*(-a*f + b*e)*(m - n + S(1)) + x**n*(-b*n*(p + S(1))*(c*f - d*e) + d*(-a*f + b*e)*(m + n*q + S(1))), x), x), x) + Simp(g**(n + S(-1))*(g*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))*(-a*f + b*e)/(b*n*(p + S(1))*(-a*d + b*c)), x) def replacement1051(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))*(-a*d + b*c)), Int((g*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(c*(m + S(1))*(-a*f + b*e) + d*x**n*(-a*f + b*e)*(m + n*(p + q + S(2)) + S(1)) + e*n*(p + S(1))*(-a*d + b*c), x), x), x) - Simp((g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))*(-a*f + b*e)/(a*g*n*(p + S(1))*(-a*d + b*c)), x) def replacement1052(a, b, c, d, e, f, g, m, n, p, q, x): return -Dist(g**(-n)/(a*(m + S(1))), Int((g*x)**(m + n)*(a + b*x**n)**p*(c + d*x**n)**(q + S(-1))*Simp(c*(m + S(1))*(-a*f + b*e) + d*x**n*(b*e*n*(p + q + S(1)) + (m + S(1))*(-a*f + b*e)) + e*n*(a*d*q + b*c*(p + S(1))), x), x), x) + Simp(e*(g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(a*g*(m + S(1))), x) def replacement1053(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(S(1)/(b*(m + n*(p + q + S(1)) + S(1))), Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**(q + S(-1))*Simp(c*(b*e*n*(p + q + S(1)) + (m + S(1))*(-a*f + b*e)) + x**n*(b*d*e*n*(p + q + S(1)) + d*(m + S(1))*(-a*f + b*e) + f*n*q*(-a*d + b*c)), x), x), x) + Simp(f*(g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(b*g*(m + n*(p + q + S(1)) + S(1))), x) def replacement1054(a, b, c, d, e, f, g, m, n, p, q, x): return -Dist(g**n/(b*d*(m + n*(p + q + S(1)) + S(1))), Int((g*x)**(m - n)*(a + b*x**n)**p*(c + d*x**n)**q*Simp(a*c*f*(m - n + S(1)) + x**n*(a*d*f*(m + n*q + S(1)) + b*(c*f*(m + n*p + S(1)) - d*e*(m + n*(p + q + S(1)) + S(1)))), x), x), x) + Simp(f*g**(n + S(-1))*(g*x)**(m - n + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(b*d*(m + n*(p + q + S(1)) + S(1))), x) def replacement1055(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(g**(-n)/(a*c*(m + S(1))), Int((g*x)**(m + n)*(a + b*x**n)**p*(c + d*x**n)**q*Simp(a*c*f*(m + S(1)) - b*d*e*x**n*(m + n*(p + q + S(2)) + S(1)) - e*n*(a*d*q + b*c*p) - e*(a*d + b*c)*(m + n + S(1)), x), x), x) + Simp(e*(g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))/(a*c*g*(m + S(1))), x) def replacement1056(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((g*x)**m*(a + b*x**n)**p*(e + f*x**n)/(c + d*x**n), x), x) def replacement1057(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(e, Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) + Dist(e**(-n)*f, Int((g*x)**(m + n)*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement1058(a, b, c, d, e, f, g, m, n, p, q, r, x): return Dist(e, Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**(r + S(-1)), x), x) + Dist(e**(-n)*f, Int((g*x)**(m + n)*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**(r + S(-1)), x), x) def replacement1059(a, b, c, d, e, f, m, n, p, q, r, x): return -Subst(Int(x**(-m + S(-2))*(a + b*x**(-n))**p*(c + d*x**(-n))**q*(e + f*x**(-n))**r, x), x, S(1)/x) def With1060(a, b, c, d, e, f, g, m, n, p, q, r, x): k = Denominator(m) return -Dist(k/g, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*g**(-n)*x**(-k*n))**p*(c + d*g**(-n)*x**(-k*n))**q*(e + f*g**(-n)*x**(-k*n))**r, x), x, (g*x)**(-S(1)/k)), x) def replacement1061(a, b, c, d, e, f, g, m, n, p, q, r, x): return -Dist((g*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a + b*x**(-n))**p*(c + d*x**(-n))**q*(e + f*x**(-n))**r, x), x, S(1)/x), x) def With1062(a, b, c, d, e, f, m, n, p, q, r, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*x**(k*n))**p*(c + d*x**(k*n))**q*(e + f*x**(k*n))**r, x), x, x**(S(1)/k)), x) def replacement1063(a, b, c, d, e, f, g, m, n, p, q, r, x): return Dist(g**IntPart(m)*x**(-FracPart(m))*(g*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def replacement1064(a, b, c, d, e, f, m, n, p, q, r, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*x**(n/(m + S(1))))**p*(c + d*x**(n/(m + S(1))))**q*(e + f*x**(n/(m + S(1))))**r, x), x, x**(m + S(1))), x) def replacement1065(a, b, c, d, e, f, g, m, n, p, q, r, x): return Dist(g**IntPart(m)*x**(-FracPart(m))*(g*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x) def replacement1066(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(S(1)/(a*b*n*(p + S(1))), Int((g*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(-1))*Simp(c*(b*e*n*(p + S(1)) + (m + S(1))*(-a*f + b*e)) + d*x**n*(b*e*n*(p + S(1)) + (-a*f + b*e)*(m + n*q + S(1))), x), x), x) - Simp((g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*(-a*f + b*e)/(a*b*g*n*(p + S(1))), x) def replacement1067(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(S(1)/(a*n*(p + S(1))*(-a*d + b*c)), Int((g*x)**m*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q*Simp(c*(m + S(1))*(-a*f + b*e) + d*x**n*(-a*f + b*e)*(m + n*(p + q + S(2)) + S(1)) + e*n*(p + S(1))*(-a*d + b*c), x), x), x) - Simp((g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(q + S(1))*(-a*f + b*e)/(a*g*n*(p + S(1))*(-a*d + b*c)), x) def replacement1068(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(S(1)/(b*(m + n*(p + q + S(1)) + S(1))), Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**(q + S(-1))*Simp(c*(b*e*n*(p + q + S(1)) + (m + S(1))*(-a*f + b*e)) + x**n*(b*d*e*n*(p + q + S(1)) + d*(m + S(1))*(-a*f + b*e) + f*n*q*(-a*d + b*c)), x), x), x) + Simp(f*(g*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**q/(b*g*(m + n*(p + q + S(1)) + S(1))), x) def replacement1069(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((g*x)**m*(a + b*x**n)**p*(e + f*x**n)/(c + d*x**n), x), x) def replacement1070(a, b, c, d, e, f, g, m, n, p, q, x): return Dist(e, Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) + Dist(f*x**(-m)*(g*x)**m, Int(x**(m + n)*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def replacement1071(a, b, c, d, e, f, m, mn, n, p, q, r, x): return Int(x**(m - n*q)*(a + b*x**n)**p*(e + f*x**n)**r*(c*x**n + d)**q, x) def replacement1072(a, b, c, d, e, f, m, mn, n, p, q, r, x): return Int(x**(m + n*(p + r))*(c + d*x**(-n))**q*(a*x**(-n) + b)**p*(e*x**(-n) + f)**r, x) def replacement1073(a, b, c, d, e, f, m, mn, n, p, q, r, x): return Dist(x**(n*FracPart(q))*(c + d*x**(-n))**FracPart(q)*(c*x**n + d)**(-FracPart(q)), Int(x**(m - n*q)*(a + b*x**n)**p*(e + f*x**n)**r*(c*x**n + d)**q, x), x) def replacement1074(a, b, c, d, e, f, g, m, mn, n, p, q, r, x): return Dist(g**IntPart(m)*x**(-FracPart(m))*(g*x)**FracPart(m), Int(x**m*(a + b*x**n)**p*(c + d*x**(-n))**q*(e + f*x**n)**r, x), x) def replacement1075(a, b, c, d, e, f, g, m, n, p, q, r, x): return Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x) def replacement1076(a, b, c, d, e, f, m, n, p, q, r, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q*(e + f*x**n)**r, x), x, v), x) def replacement1077(a, b, c, d, e1, e2, f1, f2, g, m, n, n2, p, q, r, x): return Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**q*(e1*e2 + f1*f2*x**n)**r, x) def replacement1078(a, b, c, d, e1, e2, f1, f2, g, m, n, n2, p, q, r, x): return Dist((e1 + f1*x**(n/S(2)))**FracPart(r)*(e2 + f2*x**(n/S(2)))**FracPart(r)*(e1*e2 + f1*f2*x**n)**(-FracPart(r)), Int((g*x)**m*(a + b*x**n)**p*(c + d*x**n)**q*(e1*e2 + f1*f2*x**n)**r, x), x) sympy-sympy-1.9/sympy/integrals/rubi/rules/exponential.py000066400000000000000000001726341412543434000241040ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def exponential(): from sympy.integrals.rubi.constraints import cons33, cons170, cons517, cons1100, cons1101, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons96, cons20, cons21, cons19, cons1102, cons130, cons2, cons246, cons139, cons554, cons1103, cons1104, cons5, cons382, cons56, cons1105, cons1106, cons1107, cons211, cons226, cons798, cons799, cons52, cons1108, cons806, cons1109, cons814, cons1110, cons1111, cons1112, cons1113, cons586, cons1114, cons1115, cons481, cons482, cons1116, cons198, cons25, cons1117, cons55, cons1118, cons1119, cons1120, cons1121, cons87, cons1122, cons358, cons533, cons1123, cons1124, cons537, cons95, cons1125, cons1126, cons178, cons369, cons168, cons746, cons70, cons842, cons1127, cons1128, cons1129, cons27, cons73, cons1130, cons1131, cons1132, cons820, cons1133, cons1134, cons1135, cons1136, cons821, cons1137, cons1138, cons1139, cons1140, cons150, cons812, cons813, cons1141, cons1142, cons54, cons802, cons1143, cons1144, cons1145, cons815, cons1146, cons228, cons64, cons1147, cons1148, cons1149, cons1150, cons1151, cons1152, cons1153, cons465, cons1154, cons45, cons450, cons1155, cons1156, cons1157, cons1019 pattern1904 = Pattern(Integral((F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1)))*WC('b', S(1)))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons33, cons170, cons517, cons1100) rule1904 = ReplacementRule(pattern1904, replacement1904) pattern1905 = Pattern(Integral((F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1)))*WC('b', S(1)))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons1101, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons33, cons96, cons517, cons1100) rule1905 = ReplacementRule(pattern1905, replacement1905) pattern1906 = Pattern(Integral(F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons1101, cons8, cons29, cons50, cons127, cons210, cons1100) rule1906 = ReplacementRule(pattern1906, replacement1906) pattern1907 = Pattern(Integral(F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons8, cons29, cons50, cons127, cons210, cons20) rule1907 = ReplacementRule(pattern1907, replacement1907) pattern1908 = Pattern(Integral(F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1)))/sqrt(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons1101, cons8, cons29, cons50, cons127, cons210, cons1100) rule1908 = ReplacementRule(pattern1908, replacement1908) pattern1909 = Pattern(Integral(F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1)))*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons1101, cons8, cons29, cons50, cons127, cons210, cons19, cons21) rule1909 = ReplacementRule(pattern1909, replacement1909) pattern1910 = Pattern(Integral((F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1)))*WC('b', S(1)))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons1102) rule1910 = ReplacementRule(pattern1910, replacement1910) pattern1911 = Pattern(Integral((a_ + (F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons130) rule1911 = ReplacementRule(pattern1911, replacement1911) pattern1912 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + (F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons33, cons170) rule1912 = ReplacementRule(pattern1912, replacement1912) pattern1913 = Pattern(Integral((a_ + (F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)))**p_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons246, cons170, cons139) rule1913 = ReplacementRule(pattern1913, With1913) pattern1914 = Pattern(Integral(u_**WC('m', S(1))*((F_**(v_*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons1101, cons2, cons3, cons210, cons4, cons5, cons554, cons1103, cons1104, cons20) rule1914 = ReplacementRule(pattern1914, replacement1914) pattern1915 = Pattern(Integral(u_**WC('m', S(1))*((F_**(v_*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons1101, cons2, cons3, cons210, cons19, cons4, cons5, cons554, cons1103, cons1104, cons21) rule1915 = ReplacementRule(pattern1915, With1915) pattern1916 = Pattern(Integral((a_ + (F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons382) rule1916 = ReplacementRule(pattern1916, replacement1916) pattern1917 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))/(a_ + (F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons33, cons170) rule1917 = ReplacementRule(pattern1917, replacement1917) pattern1918 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*((F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons56) rule1918 = ReplacementRule(pattern1918, replacement1918) pattern1919 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*((F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons1105) rule1919 = ReplacementRule(pattern1919, replacement1919) pattern1920 = Pattern(Integral((G_**((x_*WC('i', S(1)) + WC('h', S(0)))*WC('j', S(1)))*WC('k', S(1)))**WC('q', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*((F_**((x_*WC('f', S(1)) + WC('e', S(0)))*WC('g', S(1))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons798, cons799, cons19, cons4, cons5, cons52, cons1106, cons1107) rule1920 = ReplacementRule(pattern1920, replacement1920) pattern1921 = Pattern(Integral((F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons4, cons1108) rule1921 = ReplacementRule(pattern1921, replacement1921) pattern1922 = Pattern(Integral(F_**(v_*WC('c', S(1)))*u_, x_), cons1101, cons8, cons806, cons554, cons1109) rule1922 = ReplacementRule(pattern1922, replacement1922) pattern1923 = Pattern(Integral(F_**(v_*WC('c', S(1)))*u_, x_), cons1101, cons8, cons806, cons554, cons1100) rule1923 = ReplacementRule(pattern1923, replacement1923) pattern1924 = Pattern(Integral(F_**(v_*WC('c', S(1)))*u_**WC('m', S(1))*w_, x_), cons1101, cons8, cons19, cons814, cons1110) rule1924 = ReplacementRule(pattern1924, replacement1924) pattern1925 = Pattern(Integral(F_**(v_*WC('c', S(1)))*u_**WC('m', S(1))*w_, x_), cons1101, cons8, cons1111, cons554, cons1103, cons20, cons1109) rule1925 = ReplacementRule(pattern1925, replacement1925) pattern1926 = Pattern(Integral(F_**(v_*WC('c', S(1)))*u_**WC('m', S(1))*w_, x_), cons1101, cons8, cons1111, cons554, cons1103, cons20, cons1100) rule1926 = ReplacementRule(pattern1926, replacement1926) pattern1927 = Pattern(Integral(F_**(v_*WC('c', S(1)))*u_**WC('m', S(1))*w_, x_), cons1101, cons8, cons19, cons1111, cons554, cons1103, cons21) rule1927 = ReplacementRule(pattern1927, With1927) pattern1928 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(e_ + (x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1))*log(x_*WC('d', S(1))))*log(x_*WC('d', S(1)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons1112, cons1113, cons586) rule1928 = ReplacementRule(pattern1928, replacement1928) pattern1929 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*x_**WC('m', S(1))*(e_ + (x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1))*log(x_*WC('d', S(1))))*log(x_*WC('d', S(1)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons1114, cons1113, cons586) rule1929 = ReplacementRule(pattern1929, replacement1929) pattern1930 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons1115) rule1930 = ReplacementRule(pattern1930, replacement1930) pattern1931 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**S(2)*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons481) rule1931 = ReplacementRule(pattern1931, replacement1931) pattern1932 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**S(2)*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons482) rule1932 = ReplacementRule(pattern1932, replacement1932) pattern1933 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons1116, cons198) rule1933 = ReplacementRule(pattern1933, replacement1933) pattern1934 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons1116, cons25) rule1934 = ReplacementRule(pattern1934, With1934) pattern1935 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons4, cons1117) rule1935 = ReplacementRule(pattern1935, replacement1935) pattern1936 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons55, cons1118) rule1936 = ReplacementRule(pattern1936, replacement1936) pattern1937 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))/(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1118) rule1937 = ReplacementRule(pattern1937, replacement1937) pattern1938 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons19, cons4, cons1119) rule1938 = ReplacementRule(pattern1938, replacement1938) pattern1939 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons33, cons1120, cons1121, cons87, cons1122) rule1939 = ReplacementRule(pattern1939, replacement1939) pattern1940 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons19, cons4, cons1120, cons1121, cons358, cons533) rule1940 = ReplacementRule(pattern1940, replacement1940) pattern1941 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons33, cons1120, cons1123, cons87, cons1124) rule1941 = ReplacementRule(pattern1941, replacement1941) pattern1942 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons19, cons4, cons1120, cons1123, cons358, cons537) rule1942 = ReplacementRule(pattern1942, replacement1942) pattern1943 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons95, cons1120, cons1121, cons25) rule1943 = ReplacementRule(pattern1943, With1943) pattern1944 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1118, cons1120, cons1125, cons21, cons1126) rule1944 = ReplacementRule(pattern1944, replacement1944) pattern1945 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1118) rule1945 = ReplacementRule(pattern1945, replacement1945) pattern1946 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**S(2)*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons178, cons369, cons168) rule1946 = ReplacementRule(pattern1946, replacement1946) pattern1947 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**S(2)*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons178, cons33, cons96) rule1947 = ReplacementRule(pattern1947, replacement1947) pattern1948 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons178, cons87, cons746, cons33, cons96) rule1948 = ReplacementRule(pattern1948, replacement1948) pattern1949 = Pattern(Integral(F_**(WC('a', S(0)) + WC('b', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))/(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons178) rule1949 = ReplacementRule(pattern1949, replacement1949) pattern1950 = Pattern(Integral(F_**(WC('a', S(0)) + WC('b', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))*(x_*WC('f', S(1)) + WC('e', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons178, cons20, cons96) rule1950 = ReplacementRule(pattern1950, replacement1950) pattern1951 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))/(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons178) rule1951 = ReplacementRule(pattern1951, replacement1951) pattern1952 = Pattern(Integral(F_**v_*u_**WC('m', S(1)), x_), cons1101, cons19, cons70, cons842, cons1127) rule1952 = ReplacementRule(pattern1952, replacement1952) pattern1953 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**n_*WC('b', S(1)) + WC('a', S(0)))*u_, x_), cons1101, cons2, cons3, cons8, cons29, cons4, cons806) rule1953 = ReplacementRule(pattern1953, replacement1953) pattern1954 = Pattern(Integral(F_**(v_*WC('b', S(1)) + WC('a', S(0)))*WC('u', S(1)), x_), cons1101, cons2, cons3, cons806, cons1128, cons1129) rule1954 = ReplacementRule(pattern1954, replacement1954) pattern1955 = Pattern(Integral(F_**(WC('a', S(0)) + WC('b', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))/((x_*WC('f', S(1)) + WC('e', S(0)))*(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons1118) rule1955 = ReplacementRule(pattern1955, replacement1955) pattern1956 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))) + WC('e', S(0)))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons27) rule1956 = ReplacementRule(pattern1956, replacement1956) pattern1957 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))) + WC('e', S(0)))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons73, cons1130) rule1957 = ReplacementRule(pattern1957, replacement1957) pattern1958 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))) + WC('e', S(0)))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons73, cons1131) rule1958 = ReplacementRule(pattern1958, replacement1958) pattern1959 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))) + WC('e', S(0)))*(x_*WC('h', S(1)) + WC('g', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons73, cons1131, cons20, cons96) rule1959 = ReplacementRule(pattern1959, replacement1959) pattern1960 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))) + WC('e', S(0)))/((x_*WC('h', S(1)) + WC('g', S(0)))*(x_*WC('j', S(1)) + WC('i', S(0)))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons1130) rule1960 = ReplacementRule(pattern1960, replacement1960) pattern1961 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons1132) rule1961 = ReplacementRule(pattern1961, replacement1961) pattern1962 = Pattern(Integral(F_**v_, x_), cons1101, cons820, cons1133) rule1962 = ReplacementRule(pattern1962, replacement1962) pattern1963 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1134) rule1963 = ReplacementRule(pattern1963, replacement1963) pattern1964 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1134, cons33, cons168) rule1964 = ReplacementRule(pattern1964, replacement1964) pattern1965 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1134) rule1965 = ReplacementRule(pattern1965, replacement1965) pattern1966 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1134, cons33, cons96) rule1966 = ReplacementRule(pattern1966, replacement1966) pattern1967 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1135) rule1967 = ReplacementRule(pattern1967, replacement1967) pattern1968 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1135, cons33, cons168) rule1968 = ReplacementRule(pattern1968, replacement1968) pattern1969 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1135, cons33, cons96) rule1969 = ReplacementRule(pattern1969, replacement1969) pattern1970 = Pattern(Integral(F_**(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons19, cons1136) rule1970 = ReplacementRule(pattern1970, replacement1970) pattern1971 = Pattern(Integral(F_**v_*u_**WC('m', S(1)), x_), cons1101, cons19, cons70, cons820, cons821) rule1971 = ReplacementRule(pattern1971, replacement1971) pattern1972 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*x_**WC('m', S(1))*(F_**v_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1137, cons33, cons170, cons198) rule1972 = ReplacementRule(pattern1972, With1972) pattern1973 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons1101, cons1139, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons1138, CustomConstraint(With1973)) rule1973 = ReplacementRule(pattern1973, replacement1973) pattern1974 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons1101, cons1139, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons1138, CustomConstraint(With1974)) rule1974 = ReplacementRule(pattern1974, replacement1974) pattern1975 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons1101, cons1139, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons1140, cons150) rule1975 = ReplacementRule(pattern1975, replacement1975) pattern1976 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**n_, x_), cons1101, cons1139, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons1140, cons198) rule1976 = ReplacementRule(pattern1976, replacement1976) pattern1977 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**n_, x_), cons1101, cons1139, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons1140, cons25) rule1977 = ReplacementRule(pattern1977, replacement1977) pattern1978 = Pattern(Integral(G_**(u_*WC('h', S(1)))*(F_**(v_*WC('e', S(1)))*WC('b', S(1)) + a_)**n_, x_), cons1101, cons1139, cons2, cons3, cons50, cons211, cons4, cons812, cons813) rule1978 = ReplacementRule(pattern1978, replacement1978) pattern1979 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*H_**((x_*WC('s', S(1)) + WC('r', S(0)))*WC('t', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons1101, cons1139, cons1142, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons54, cons802, cons1143, cons4, cons1141, CustomConstraint(With1979)) rule1979 = ReplacementRule(pattern1979, replacement1979) pattern1980 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*H_**((x_*WC('s', S(1)) + WC('r', S(0)))*WC('t', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons1101, cons1139, cons1142, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons54, cons802, cons1143, cons1144, cons87) rule1980 = ReplacementRule(pattern1980, replacement1980) pattern1981 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*H_**((x_*WC('s', S(1)) + WC('r', S(0)))*WC('t', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons1101, cons1139, cons1142, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons54, cons802, cons1143, cons1145, cons150) rule1981 = ReplacementRule(pattern1981, replacement1981) pattern1982 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*H_**((x_*WC('s', S(1)) + WC('r', S(0)))*WC('t', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**n_, x_), cons1101, cons1139, cons1142, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons54, cons802, cons1143, cons1145, cons198) rule1982 = ReplacementRule(pattern1982, replacement1982) pattern1983 = Pattern(Integral(G_**((x_*WC('g', S(1)) + WC('f', S(0)))*WC('h', S(1)))*H_**((x_*WC('s', S(1)) + WC('r', S(0)))*WC('t', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + a_)**n_, x_), cons1101, cons1139, cons1142, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons54, cons802, cons1143, cons4, cons1145, cons25) rule1983 = ReplacementRule(pattern1983, replacement1983) pattern1984 = Pattern(Integral(G_**(u_*WC('h', S(1)))*H_**(w_*WC('t', S(1)))*(F_**(v_*WC('e', S(1)))*WC('b', S(1)) + a_)**n_, x_), cons1101, cons1139, cons1142, cons2, cons3, cons50, cons211, cons1143, cons4, cons814, cons815) rule1984 = ReplacementRule(pattern1984, replacement1984) pattern1985 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + x_**WC('n', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons56) rule1985 = ReplacementRule(pattern1985, replacement1985) pattern1986 = Pattern(Integral(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*x_**WC('m', S(1))*(F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1)))*WC('b', S(1)) + x_**WC('n', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons56) rule1986 = ReplacementRule(pattern1986, replacement1986) pattern1987 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/(F_**u_*WC('b', S(1)) + F_**v_*WC('c', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons127, cons210, cons1146, cons70, cons228, cons64) rule1987 = ReplacementRule(pattern1987, With1987) pattern1988 = Pattern(Integral(F_**u_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/(F_**u_*WC('b', S(1)) + F_**v_*WC('c', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons127, cons210, cons1146, cons70, cons228, cons64) rule1988 = ReplacementRule(pattern1988, With1988) pattern1989 = Pattern(Integral((F_**u_*WC('i', S(1)) + h_)*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/(F_**u_*WC('b', S(1)) + F_**v_*WC('c', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons127, cons210, cons211, cons226, cons1146, cons70, cons228, cons64) rule1989 = ReplacementRule(pattern1989, With1989) pattern1990 = Pattern(Integral(x_**WC('m', S(1))/(F_**v_*WC('b', S(1)) + F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('a', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons1147, cons33, cons170) rule1990 = ReplacementRule(pattern1990, With1990) pattern1991 = Pattern(Integral(u_/(F_**v_*WC('b', S(1)) + F_**w_*WC('c', S(1)) + a_), x_), cons1101, cons2, cons3, cons8, cons554, cons1148, cons1149, cons1150) rule1991 = ReplacementRule(pattern1991, replacement1991) pattern1992 = Pattern(Integral(F_**((x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1))*WC('g', S(1)))/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons210, cons4, cons1151) rule1992 = ReplacementRule(pattern1992, replacement1992) pattern1993 = Pattern(Integral(F_**((x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1))*WC('g', S(1)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons1101, cons2, cons8, cons29, cons50, cons210, cons4, cons1152) rule1993 = ReplacementRule(pattern1993, replacement1993) pattern1994 = Pattern(Integral(F_**((x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1))*WC('g', S(1)))*u_**WC('m', S(1))/(c_*x_**S(2) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons210, cons4, cons806, cons20) rule1994 = ReplacementRule(pattern1994, replacement1994) pattern1995 = Pattern(Integral(F_**((x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1))*WC('g', S(1)))*u_**WC('m', S(1))/(a_ + c_*x_**S(2)), x_), cons1101, cons2, cons8, cons29, cons50, cons210, cons4, cons806, cons20) rule1995 = ReplacementRule(pattern1995, replacement1995) pattern1996 = Pattern(Integral(F_**((x_**S(4)*WC('b', S(1)) + WC('a', S(0)))/x_**S(2)), x_), cons1101, cons2, cons3, cons1153) rule1996 = ReplacementRule(pattern1996, replacement1996) pattern1997 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('m', S(1)) + exp(x_))**n_, x_), cons95, cons170, cons465, cons1154) rule1997 = ReplacementRule(pattern1997, replacement1997) pattern1998 = Pattern(Integral(log(a_ + (F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1))))**WC('n', S(1))*WC('b', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons45) rule1998 = ReplacementRule(pattern1998, replacement1998) pattern1999 = Pattern(Integral(log(a_ + (F_**((x_*WC('d', S(1)) + WC('c', S(0)))*WC('e', S(1))))**WC('n', S(1))*WC('b', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons450) rule1999 = ReplacementRule(pattern1999, replacement1999) pattern2000 = Pattern(Integral((F_**v_*WC('a', S(1)))**n_*WC('u', S(1)), x_), cons1101, cons2, cons4, cons25) rule2000 = ReplacementRule(pattern2000, replacement2000) pattern2001 = Pattern(Integral(u_, x_), cons1155) rule2001 = ReplacementRule(pattern2001, With2001) pattern2002 = Pattern(Integral((F_**v_*WC('a', S(1)) + F_**w_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons1101, cons2, cons3, cons4, cons198, cons1156) rule2002 = ReplacementRule(pattern2002, replacement2002) pattern2003 = Pattern(Integral((F_**v_*WC('a', S(1)) + G_**w_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons1101, cons1139, cons2, cons3, cons4, cons198, cons1156) rule2003 = ReplacementRule(pattern2003, replacement2003) pattern2004 = Pattern(Integral((F_**v_*WC('a', S(1)) + F_**w_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons1101, cons2, cons3, cons4, cons25, cons1156) rule2004 = ReplacementRule(pattern2004, replacement2004) pattern2005 = Pattern(Integral((F_**v_*WC('a', S(1)) + G_**w_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons1101, cons1139, cons2, cons3, cons4, cons25, cons1156) rule2005 = ReplacementRule(pattern2005, replacement2005) pattern2006 = Pattern(Integral(F_**v_*G_**w_*WC('u', S(1)), x_), cons1101, cons1139, cons1157) rule2006 = ReplacementRule(pattern2006, replacement2006) pattern2007 = Pattern(Integral(F_**u_*(v_ + w_)*WC('y', S(1)), x_), cons1101, cons1101, CustomConstraint(With2007)) rule2007 = ReplacementRule(pattern2007, replacement2007) pattern2008 = Pattern(Integral(F_**u_*v_**WC('n', S(1))*w_, x_), cons1101, cons4, cons806, cons1019, cons1111, CustomConstraint(With2008)) rule2008 = ReplacementRule(pattern2008, replacement2008) return [rule1904, rule1905, rule1906, rule1907, rule1908, rule1909, rule1910, rule1911, rule1912, rule1913, rule1914, rule1915, rule1916, rule1917, rule1918, rule1919, rule1920, rule1921, rule1922, rule1923, rule1924, rule1925, rule1926, rule1927, rule1928, rule1929, rule1930, rule1931, rule1932, rule1933, rule1934, rule1935, rule1936, rule1937, rule1938, rule1939, rule1940, rule1941, rule1942, rule1943, rule1944, rule1945, rule1946, rule1947, rule1948, rule1949, rule1950, rule1951, rule1952, rule1953, rule1954, rule1955, rule1956, rule1957, rule1958, rule1959, rule1960, rule1961, rule1962, rule1963, rule1964, rule1965, rule1966, rule1967, rule1968, rule1969, rule1970, rule1971, rule1972, rule1973, rule1974, rule1975, rule1976, rule1977, rule1978, rule1979, rule1980, rule1981, rule1982, rule1983, rule1984, rule1985, rule1986, rule1987, rule1988, rule1989, rule1990, rule1991, rule1992, rule1993, rule1994, rule1995, rule1996, rule1997, rule1998, rule1999, rule2000, rule2001, rule2002, rule2003, rule2004, rule2005, rule2006, rule2007, rule2008, ] def replacement1904(F, b, c, d, e, f, g, m, n, x): return -Dist(d*m/(f*g*n*log(F)), Int((F**(g*(e + f*x))*b)**n*(c + d*x)**(m + S(-1)), x), x) + Simp((F**(g*(e + f*x))*b)**n*(c + d*x)**m/(f*g*n*log(F)), x) def replacement1905(F, b, c, d, e, f, g, m, n, x): return -Dist(f*g*n*log(F)/(d*(m + S(1))), Int((F**(g*(e + f*x))*b)**n*(c + d*x)**(m + S(1)), x), x) + Simp((F**(g*(e + f*x))*b)**n*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement1906(F, c, d, e, f, g, x): return Simp(F**(g*(-c*f/d + e))*ExpIntegralEi(f*g*(c + d*x)*log(F)/d)/d, x) def replacement1907(F, c, d, e, f, g, m, x): return Simp(F**(g*(-c*f/d + e))*f**(-m + S(-1))*g**(-m + S(-1))*(-d)**m*Gamma(m + S(1), -f*g*(c + d*x)*log(F)/d)*log(F)**(-m + S(-1)), x) def replacement1908(F, c, d, e, f, g, x): return Dist(S(2)/d, Subst(Int(F**(g*(-c*f/d + e) + f*g*x**S(2)/d), x), x, sqrt(c + d*x)), x) def replacement1909(F, c, d, e, f, g, m, x): return -Simp(F**(g*(-c*f/d + e))*(-f*g*log(F)/d)**(-IntPart(m) + S(-1))*(-f*g*(c + d*x)*log(F)/d)**(-FracPart(m))*(c + d*x)**FracPart(m)*Gamma(m + S(1), -f*g*(c + d*x)*log(F)/d)/d, x) def replacement1910(F, b, c, d, e, f, g, m, n, x): return Dist(F**(-g*n*(e + f*x))*(F**(g*(e + f*x))*b)**n, Int(F**(g*n*(e + f*x))*(c + d*x)**m, x), x) def replacement1911(F, a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b*(F**(g*(e + f*x)))**n)**p, x), x) def replacement1912(F, a, b, c, d, e, f, g, m, n, x): return Dist(d*m/(a*f*g*n*log(F)), Int((c + d*x)**(m + S(-1))*log(a*(F**(g*(e + f*x)))**(-n)/b + S(1)), x), x) - Simp((c + d*x)**m*log(a*(F**(g*(e + f*x)))**(-n)/b + S(1))/(a*f*g*n*log(F)), x) def With1913(F, a, b, c, d, e, f, g, m, n, p, x): u = IntHide((a + b*(F**(g*(e + f*x)))**n)**p, x) return -Dist(d*m, Int(u*(c + d*x)**(m + S(-1)), x), x) + Dist((c + d*x)**m, u, x) def replacement1914(F, a, b, g, m, n, p, u, v, x): return Int((a + b*(F**(g*ExpandToSum(v, x)))**n)**p*NormalizePowerOfLinear(u, x)**m, x) def With1915(F, a, b, g, m, n, p, u, v, x): uu = NormalizePowerOfLinear(u, x) z = Symbol('z') z = If(And(PowerQ(uu), FreeQ(Part(uu, S(2)), x)), Part(uu, S(1))**(m*Part(uu, S(2))), uu**m) z = If(And(PowerQ(uu), FreeQ(Part(uu, 2), x)), Part(uu, 1)**(m*Part(uu, 2)), uu**m) return Simp(uu**m*Int(z*(a + b*(F**(g*ExpandToSum(v, x)))**n)**p, x)/z, x) def replacement1916(F, a, b, c, d, e, f, g, m, n, p, x): return Int((a + b*(F**(g*(e + f*x)))**n)**p*(c + d*x)**m, x) def replacement1917(F, a, b, c, d, e, f, g, m, n, x): return -Dist(d*m/(b*f*g*n*log(F)), Int((c + d*x)**(m + S(-1))*log(S(1) + b*(F**(g*(e + f*x)))**n/a), x), x) + Simp((c + d*x)**m*log(S(1) + b*(F**(g*(e + f*x)))**n/a)/(b*f*g*n*log(F)), x) def replacement1918(F, a, b, c, d, e, f, g, m, n, p, x): return -Dist(d*m/(b*f*g*n*(p + S(1))*log(F)), Int((a + b*(F**(g*(e + f*x)))**n)**(p + S(1))*(c + d*x)**(m + S(-1)), x), x) + Simp((a + b*(F**(g*(e + f*x)))**n)**(p + S(1))*(c + d*x)**m/(b*f*g*n*(p + S(1))*log(F)), x) def replacement1919(F, a, b, c, d, e, f, g, m, n, p, x): return Int((a + b*(F**(g*(e + f*x)))**n)**p*(c + d*x)**m*(F**(g*(e + f*x)))**n, x) def replacement1920(F, G, a, b, c, d, e, f, g, h, i, j, k, m, n, p, q, x): return Dist((G**(j*(h + i*x))*k)**q*(F**(g*(e + f*x)))**(-n), Int((a + b*(F**(g*(e + f*x)))**n)**p*(c + d*x)**m*(F**(g*(e + f*x)))**n, x), x) def replacement1921(F, a, b, c, n, x): return Simp((F**(c*(a + b*x)))**n/(b*c*n*log(F)), x) def replacement1922(F, c, u, v, x): return Int(ExpandIntegrand(F**(c*ExpandToSum(v, x))*u, x), x) def replacement1923(F, c, u, v, x): return Int(ExpandIntegrand(F**(c*ExpandToSum(v, x)), u, x), x) def replacement1924(F, c, m, u, v, w, x): return Simp(F**(c*v)*u**(m + S(1))*Coefficient(w, x, S(1))/(c*Coefficient(u, x, S(1))*Coefficient(v, x, S(1))*log(F)), x) def replacement1925(F, c, m, u, v, w, x): return Int(ExpandIntegrand(F**(c*ExpandToSum(v, x))*w*NormalizePowerOfLinear(u, x)**m, x), x) def replacement1926(F, c, m, u, v, w, x): return Int(ExpandIntegrand(F**(c*ExpandToSum(v, x)), w*NormalizePowerOfLinear(u, x)**m, x), x) def With1927(F, c, m, u, v, w, x): uu = NormalizePowerOfLinear(u, x) z = Symbol('z') z = If(And(PowerQ(uu), FreeQ(Part(uu, S(2)), x)), Part(uu, S(1))**(m*Part(uu, S(2))), uu**m) z = If(And(PowerQ(uu), FreeQ(Part(uu, 2), x)), Part(uu, 1)**(m*Part(uu, 2)), uu**m) return Simp(uu**m*Int(ExpandIntegrand(F**(c*ExpandToSum(v, x))*w*z, x), x)/z, x) def replacement1928(F, a, b, c, d, e, f, g, h, n, x): return Simp(F**(c*(a + b*x))*e*x*log(d*x)**(n + S(1))/(n + S(1)), x) def replacement1929(F, a, b, c, d, e, f, g, h, m, n, x): return Simp(F**(c*(a + b*x))*e*x**(m + S(1))*log(d*x)**(n + S(1))/(n + S(1)), x) def replacement1930(F, a, b, c, d, x): return Simp(F**(a + b*(c + d*x))/(b*d*log(F)), x) def replacement1931(F, a, b, c, d, x): return Simp(F**a*sqrt(Pi)*Erfi((c + d*x)*Rt(b*log(F), S(2)))/(S(2)*d*Rt(b*log(F), S(2))), x) def replacement1932(F, a, b, c, d, x): return Simp(F**a*sqrt(Pi)*Erf((c + d*x)*Rt(-b*log(F), S(2)))/(S(2)*d*Rt(-b*log(F), S(2))), x) def replacement1933(F, a, b, c, d, n, x): return -Dist(b*n*log(F), Int(F**(a + b*(c + d*x)**n)*(c + d*x)**n, x), x) + Simp(F**(a + b*(c + d*x)**n)*(c + d*x)/d, x) def With1934(F, a, b, c, d, n, x): k = Denominator(n) return Dist(k/d, Subst(Int(F**(a + b*x**(k*n))*x**(k + S(-1)), x), x, (c + d*x)**(S(1)/k)), x) def replacement1935(F, a, b, c, d, n, x): return -Simp(F**a*(-b*(c + d*x)**n*log(F))**(-S(1)/n)*(c + d*x)*Gamma(S(1)/n, -b*(c + d*x)**n*log(F))/(d*n), x) def replacement1936(F, a, b, c, d, e, f, m, n, x): return Simp(F**(a + b*(c + d*x)**n)*(c + d*x)**(-n)*(e + f*x)**n/(b*f*n*log(F)), x) def replacement1937(F, a, b, c, d, e, f, n, x): return Simp(F**a*ExpIntegralEi(b*(c + d*x)**n*log(F))/(f*n), x) def replacement1938(F, a, b, c, d, m, n, x): return Dist(S(1)/(d*(m + S(1))), Subst(Int(F**(a + b*x**S(2)), x), x, (c + d*x)**(m + S(1))), x) def replacement1939(F, a, b, c, d, m, n, x): return -Dist((m - n + S(1))/(b*n*log(F)), Int(F**(a + b*(c + d*x)**n)*(c + d*x)**(m - n), x), x) + Simp(F**(a + b*(c + d*x)**n)*(c + d*x)**(m - n + S(1))/(b*d*n*log(F)), x) def replacement1940(F, a, b, c, d, m, n, x): return -Dist((m - n + S(1))/(b*n*log(F)), Int(F**(a + b*(c + d*x)**n)*(c + d*x)**(m - n), x), x) + Simp(F**(a + b*(c + d*x)**n)*(c + d*x)**(m - n + S(1))/(b*d*n*log(F)), x) def replacement1941(F, a, b, c, d, m, n, x): return -Dist(b*n*log(F)/(m + S(1)), Int(F**(a + b*(c + d*x)**n)*(c + d*x)**(m + n), x), x) + Simp(F**(a + b*(c + d*x)**n)*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement1942(F, a, b, c, d, m, n, x): return -Dist(b*n*log(F)/(m + S(1)), Int(F**(a + b*(c + d*x)**n)*(c + d*x)**(m + n), x), x) + Simp(F**(a + b*(c + d*x)**n)*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def With1943(F, a, b, c, d, m, n, x): k = Denominator(n) return Dist(k/d, Subst(Int(F**(a + b*x**(k*n))*x**(k*(m + S(1)) + S(-1)), x), x, (c + d*x)**(S(1)/k)), x) def replacement1944(F, a, b, c, d, e, f, m, n, x): return Dist((c + d*x)**(-m)*(e + f*x)**m, Int(F**(a + b*(c + d*x)**n)*(c + d*x)**m, x), x) def replacement1945(F, a, b, c, d, e, f, m, n, x): return -Simp(F**a*(-b*(c + d*x)**n*log(F))**(-(m + S(1))/n)*(e + f*x)**(m + S(1))*Gamma((m + S(1))/n, -b*(c + d*x)**n*log(F))/(f*n), x) def replacement1946(F, a, b, c, d, e, f, m, x): return Dist((-c*f + d*e)/d, Int(F**(a + b*(c + d*x)**S(2))*(e + f*x)**(m + S(-1)), x), x) - Dist(f**S(2)*(m + S(-1))/(S(2)*b*d**S(2)*log(F)), Int(F**(a + b*(c + d*x)**S(2))*(e + f*x)**(m + S(-2)), x), x) + Simp(F**(a + b*(c + d*x)**S(2))*f*(e + f*x)**(m + S(-1))/(S(2)*b*d**S(2)*log(F)), x) def replacement1947(F, a, b, c, d, e, f, m, x): return -Dist(S(2)*b*d**S(2)*log(F)/(f**S(2)*(m + S(1))), Int(F**(a + b*(c + d*x)**S(2))*(e + f*x)**(m + S(2)), x), x) + Dist(S(2)*b*d*(-c*f + d*e)*log(F)/(f**S(2)*(m + S(1))), Int(F**(a + b*(c + d*x)**S(2))*(e + f*x)**(m + S(1)), x), x) + Simp(F**(a + b*(c + d*x)**S(2))*(e + f*x)**(m + S(1))/(f*(m + S(1))), x) def replacement1948(F, a, b, c, d, e, f, m, n, x): return -Dist(b*d*n*log(F)/(f*(m + S(1))), Int(F**(a + b*(c + d*x)**n)*(c + d*x)**(n + S(-1))*(e + f*x)**(m + S(1)), x), x) + Simp(F**(a + b*(c + d*x)**n)*(e + f*x)**(m + S(1))/(f*(m + S(1))), x) def replacement1949(F, a, b, c, d, e, f, x): return Dist(d/f, Int(F**(a + b/(c + d*x))/(c + d*x), x), x) - Dist((-c*f + d*e)/f, Int(F**(a + b/(c + d*x))/((c + d*x)*(e + f*x)), x), x) def replacement1950(F, a, b, c, d, e, f, m, x): return Dist(b*d*log(F)/(f*(m + S(1))), Int(F**(a + b/(c + d*x))*(e + f*x)**(m + S(1))/(c + d*x)**S(2), x), x) + Simp(F**(a + b/(c + d*x))*(e + f*x)**(m + S(1))/(f*(m + S(1))), x) def replacement1951(F, a, b, c, d, e, f, n, x): return Int(F**(a + b*(c + d*x)**n)/(e + f*x), x) def replacement1952(F, m, u, v, x): return Int(F**ExpandToSum(v, x)*ExpandToSum(u, x)**m, x) def replacement1953(F, a, b, c, d, n, u, x): return Int(ExpandLinearProduct(F**(a + b*(c + d*x)**n), u, c, d, x), x) def replacement1954(F, a, b, u, v, x): return Int(F**(a + b*NormalizePowerOfLinear(v, x))*u, x) def replacement1955(F, a, b, c, d, e, f, g, h, x): return -Dist(d/(f*(-c*h + d*g)), Subst(Int(F**(a + b*d*x/(-c*h + d*g) - b*h/(-c*h + d*g))/x, x), x, (g + h*x)/(c + d*x)), x) def replacement1956(F, a, b, c, d, e, f, g, h, m, x): return Dist(F**(b*f/d + e), Int((g + h*x)**m, x), x) def replacement1957(F, a, b, c, d, e, f, g, h, m, x): return Int(F**(-f*(-a*d + b*c)/(d*(c + d*x)) + (b*f + d*e)/d)*(g + h*x)**m, x) def replacement1958(F, a, b, c, d, e, f, g, h, x): return Dist(d/h, Int(F**(e + f*(a + b*x)/(c + d*x))/(c + d*x), x), x) - Dist((-c*h + d*g)/h, Int(F**(e + f*(a + b*x)/(c + d*x))/((c + d*x)*(g + h*x)), x), x) def replacement1959(F, a, b, c, d, e, f, g, h, m, x): return -Dist(f*(-a*d + b*c)*log(F)/(h*(m + S(1))), Int(F**(e + f*(a + b*x)/(c + d*x))*(g + h*x)**(m + S(1))/(c + d*x)**S(2), x), x) + Simp(F**(e + f*(a + b*x)/(c + d*x))*(g + h*x)**(m + S(1))/(h*(m + S(1))), x) def replacement1960(F, a, b, c, d, e, f, g, h, i, j, x): return -Dist(d/(h*(-c*j + d*i)), Subst(Int(F**(e - f*x*(-a*d + b*c)/(-c*j + d*i) + f*(-a*j + b*i)/(-c*j + d*i))/x, x), x, (i + j*x)/(c + d*x)), x) def replacement1961(F, a, b, c, x): return Dist(F**(a - b**S(2)/(S(4)*c)), Int(F**((b + S(2)*c*x)**S(2)/(S(4)*c)), x), x) def replacement1962(F, v, x): return Int(F**ExpandToSum(v, x), x) def replacement1963(F, a, b, c, d, e, x): return Simp(F**(a + b*x + c*x**S(2))*e/(S(2)*c*log(F)), x) def replacement1964(F, a, b, c, d, e, m, x): return -Dist(e**S(2)*(m + S(-1))/(S(2)*c*log(F)), Int(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(-2)), x), x) + Simp(F**(a + b*x + c*x**S(2))*e*(d + e*x)**(m + S(-1))/(S(2)*c*log(F)), x) def replacement1965(F, a, b, c, d, e, x): return Simp(F**(a - b**S(2)/(S(4)*c))*ExpIntegralEi((b + S(2)*c*x)**S(2)*log(F)/(S(4)*c))/(S(2)*e), x) def replacement1966(F, a, b, c, d, e, m, x): return -Dist(S(2)*c*log(F)/(e**S(2)*(m + S(1))), Int(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(2)), x), x) + Simp(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def replacement1967(F, a, b, c, d, e, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int(F**(a + b*x + c*x**S(2)), x), x) + Simp(F**(a + b*x + c*x**S(2))*e/(S(2)*c*log(F)), x) def replacement1968(F, a, b, c, d, e, m, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(-1)), x), x) - Dist(e**S(2)*(m + S(-1))/(S(2)*c*log(F)), Int(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(-2)), x), x) + Simp(F**(a + b*x + c*x**S(2))*e*(d + e*x)**(m + S(-1))/(S(2)*c*log(F)), x) def replacement1969(F, a, b, c, d, e, m, x): return -Dist(S(2)*c*log(F)/(e**S(2)*(m + S(1))), Int(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(2)), x), x) - Dist((b*e - S(2)*c*d)*log(F)/(e**S(2)*(m + S(1))), Int(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(1)), x), x) + Simp(F**(a + b*x + c*x**S(2))*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def replacement1970(F, a, b, c, d, e, m, x): return Int(F**(a + b*x + c*x**S(2))*(d + e*x)**m, x) def replacement1971(F, m, u, v, x): return Int(F**ExpandToSum(v, x)*ExpandToSum(u, x)**m, x) def With1972(F, a, b, c, d, e, m, n, v, x): u = IntHide(F**(e*(c + d*x))*(F**v*b + a)**n, x) return -Dist(m, Int(u*x**(m + S(-1)), x), x) + Dist(x**m, u, x) def With1973(F, G, a, b, c, d, e, f, g, h, n, x): if isinstance(x, (int, Integer, float, Float)): return False m = FullSimplify(g*h*log(G)/(d*e*log(F))) if And(RationalQ(m), GreaterEqual(Abs(m), S(1))): return True return False def replacement1973(F, G, a, b, c, d, e, f, g, h, n, x): m = FullSimplify(g*h*log(G)/(d*e*log(F))) return Dist(G**(-c*g*h/d + f*h)*Denominator(m)/(d*e*log(F)), Subst(Int(x**(Numerator(m) + S(-1))*(a + b*x**Denominator(m))**n, x), x, F**(e*(c + d*x)/Denominator(m))), x) def With1974(F, G, a, b, c, d, e, f, g, h, n, x): if isinstance(x, (int, Integer, float, Float)): return False m = FullSimplify(d*e*log(F)/(g*h*log(G))) if And(RationalQ(m), Greater(Abs(m), S(1))): return True return False def replacement1974(F, G, a, b, c, d, e, f, g, h, n, x): m = FullSimplify(d*e*log(F)/(g*h*log(G))) return Dist(Denominator(m)/(g*h*log(G)), Subst(Int(x**(Denominator(m) + S(-1))*(F**(c*e - d*e*f/g)*b*x**Numerator(m) + a)**n, x), x, G**(h*(f + g*x)/Denominator(m))), x) def replacement1975(F, G, a, b, c, d, e, f, g, h, n, x): return Int(G**(f*h)*G**(g*h*x)*(F**(c*e)*F**(d*e*x)*b + a)**n, x) def replacement1976(F, G, a, b, c, d, e, f, g, h, n, x): return Simp(G**(h*(f + g*x))*a**n*Hypergeometric2F1(-n, g*h*log(G)/(d*e*log(F)), S(1) + g*h*log(G)/(d*e*log(F)), -F**(e*(c + d*x))*b/a)/(g*h*log(G)), x) def replacement1977(F, G, a, b, c, d, e, f, g, h, n, x): return Simp(G**(h*(f + g*x))*(F**(e*(c + d*x))*b + a)**(n + S(1))*Hypergeometric2F1(S(1), n + S(1) + g*h*log(G)/(d*e*log(F)), S(1) + g*h*log(G)/(d*e*log(F)), -F**(e*(c + d*x))*b/a)/(a*g*h*log(G)), x) def replacement1978(F, G, a, b, e, h, n, u, v, x): return Int(G**(h*ExpandToSum(u, x))*(F**(e*ExpandToSum(v, x))*b + a)**n, x) def With1979(F, G, H, a, b, c, d, e, f, g, h, n, r, s, t, x): if isinstance(x, (int, Integer, float, Float)): return False m = FullSimplify((g*h*log(G) + s*t*log(H))/(d*e*log(F))) if RationalQ(m): return True return False def replacement1979(F, G, H, a, b, c, d, e, f, g, h, n, r, s, t, x): m = FullSimplify((g*h*log(G) + s*t*log(H))/(d*e*log(F))) return Dist(G**(-c*g*h/d + f*h)*H**(-c*s*t/d + r*t)*Denominator(m)/(d*e*log(F)), Subst(Int(x**(Numerator(m) + S(-1))*(a + b*x**Denominator(m))**n, x), x, F**(e*(c + d*x)/Denominator(m))), x) def replacement1980(F, G, H, a, b, c, d, e, f, g, h, n, r, s, t, x): return Dist(G**(h*(-c*g/d + f)), Int(H**(t*(r + s*x))*(b + F**(-e*(c + d*x))*a)**n, x), x) def replacement1981(F, G, H, a, b, c, d, e, f, g, h, n, r, s, t, x): return Int(G**(f*h)*G**(g*h*x)*H**(r*t)*H**(s*t*x)*(F**(c*e)*F**(d*e*x)*b + a)**n, x) def replacement1982(F, G, H, a, b, c, d, e, f, g, h, n, r, s, t, x): return Simp(G**(h*(f + g*x))*H**(t*(r + s*x))*a**n*Hypergeometric2F1(-n, (g*h*log(G) + s*t*log(H))/(d*e*log(F)), S(1) + (g*h*log(G) + s*t*log(H))/(d*e*log(F)), -F**(e*(c + d*x))*b/a)/(g*h*log(G) + s*t*log(H)), x) def replacement1983(F, G, H, a, b, c, d, e, f, g, h, n, r, s, t, x): return Simp(G**(h*(f + g*x))*H**(t*(r + s*x))*((F**(e*(c + d*x))*b + a)/a)**(-n)*(F**(e*(c + d*x))*b + a)**n*Hypergeometric2F1(-n, (g*h*log(G) + s*t*log(H))/(d*e*log(F)), S(1) + (g*h*log(G) + s*t*log(H))/(d*e*log(F)), -F**(e*(c + d*x))*b/a)/(g*h*log(G) + s*t*log(H)), x) def replacement1984(F, G, H, a, b, e, h, n, t, u, v, w, x): return Int(G**(h*ExpandToSum(u, x))*H**(t*ExpandToSum(w, x))*(F**(e*ExpandToSum(v, x))*b + a)**n, x) def replacement1985(F, a, b, c, d, e, n, p, x): return -Dist(a*n/(b*d*e*log(F)), Int(x**(n + S(-1))*(F**(e*(c + d*x))*b + a*x**n)**p, x), x) + Simp((F**(e*(c + d*x))*b + a*x**n)**(p + S(1))/(b*d*e*(p + S(1))*log(F)), x) def replacement1986(F, a, b, c, d, e, m, n, p, x): return -Dist(a*n/(b*d*e*log(F)), Int(x**(m + n + S(-1))*(F**(e*(c + d*x))*b + a*x**n)**p, x), x) - Dist(m/(b*d*e*(p + S(1))*log(F)), Int(x**(m + S(-1))*(F**(e*(c + d*x))*b + a*x**n)**(p + S(1)), x), x) + Simp(x**m*(F**(e*(c + d*x))*b + a*x**n)**(p + S(1))/(b*d*e*(p + S(1))*log(F)), x) def With1987(F, a, b, c, f, g, m, u, v, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int((f + g*x)**m/(S(2)*F**u*c + b - q), x), x) - Dist(S(2)*c/q, Int((f + g*x)**m/(S(2)*F**u*c + b + q), x), x) def With1988(F, a, b, c, f, g, m, u, v, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(F**u*(f + g*x)**m/(S(2)*F**u*c + b - q), x), x) - Dist(S(2)*c/q, Int(F**u*(f + g*x)**m/(S(2)*F**u*c + b + q), x), x) def With1989(F, a, b, c, f, g, h, i, m, u, v, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return -Dist(-i + (-b*i + S(2)*c*h)/q, Int((f + g*x)**m/(S(2)*F**u*c + b + q), x), x) + Dist(i + (-b*i + S(2)*c*h)/q, Int((f + g*x)**m/(S(2)*F**u*c + b - q), x), x) def With1990(F, a, b, c, d, m, v, x): u = IntHide(S(1)/(F**v*b + F**(c + d*x)*a), x) return -Dist(m, Int(u*x**(m + S(-1)), x), x) + Simp(u*x**m, x) def replacement1991(F, a, b, c, u, v, w, x): return Int(F**v*u/(F**(S(2)*v)*b + F**v*a + c), x) def replacement1992(F, a, b, c, d, e, g, n, x): return Int(ExpandIntegrand(F**(g*(d + e*x)**n), S(1)/(a + b*x + c*x**S(2)), x), x) def replacement1993(F, a, c, d, e, g, n, x): return Int(ExpandIntegrand(F**(g*(d + e*x)**n), S(1)/(a + c*x**S(2)), x), x) def replacement1994(F, a, b, c, d, e, g, m, n, u, x): return Int(ExpandIntegrand(F**(g*(d + e*x)**n), u**m/(a + b*x + c*x**S(2)), x), x) def replacement1995(F, a, c, d, e, g, m, n, u, x): return Int(ExpandIntegrand(F**(g*(d + e*x)**n), u**m/(a + c*x**S(2)), x), x) def replacement1996(F, a, b, x): return -Simp(sqrt(Pi)*Erf((-x**S(2)*sqrt(-b*log(F)) + sqrt(-a*log(F)))/x)*exp(-S(2)*sqrt(-a*log(F))*sqrt(-b*log(F)))/(S(4)*sqrt(-b*log(F))), x) + Simp(sqrt(Pi)*Erf((x**S(2)*sqrt(-b*log(F)) + sqrt(-a*log(F)))/x)*exp(S(2)*sqrt(-a*log(F))*sqrt(-b*log(F)))/(S(4)*sqrt(-b*log(F))), x) def replacement1997(m, n, x): return Dist(m, Int(x**(m + S(-1))*(x**m + exp(x))**n, x), x) + Int((x**m + exp(x))**(n + S(1)), x) - Simp((x**m + exp(x))**(n + S(1))/(n + S(1)), x) def replacement1998(F, a, b, c, d, e, n, x): return Dist(S(1)/(d*e*n*log(F)), Subst(Int(log(a + b*x)/x, x), x, (F**(e*(c + d*x)))**n), x) def replacement1999(F, a, b, c, d, e, n, x): return -Dist(b*d*e*n*log(F), Int(x*(F**(e*(c + d*x)))**n/(a + b*(F**(e*(c + d*x)))**n), x), x) + Simp(x*log(a + b*(F**(e*(c + d*x)))**n), x) def replacement2000(F, a, n, u, v, x): return Dist(F**(-n*v)*(F**v*a)**n, Int(F**(n*v)*u, x), x) def With2001(u, x): v = FunctionOfExponential(u, x) return Dist(v/D(v, x), Subst(Int(FunctionOfExponentialFunction(u, x)/x, x), x, v), x) def replacement2002(F, a, b, n, u, v, w, x): return Int(F**(n*v)*u*(F**ExpandToSum(-v + w, x)*b + a)**n, x) def replacement2003(F, G, a, b, n, u, v, w, x): return Int(F**(n*v)*u*(a + b*exp(ExpandToSum(-v*log(F) + w*log(G), x)))**n, x) def replacement2004(F, a, b, n, u, v, w, x): return Dist(F**(-n*v)*(F**v*a + F**w*b)**n*(F**ExpandToSum(-v + w, x)*b + a)**(-n), Int(F**(n*v)*u*(F**ExpandToSum(-v + w, x)*b + a)**n, x), x) def replacement2005(F, G, a, b, n, u, v, w, x): return Dist(F**(-n*v)*(a + b*exp(ExpandToSum(-v*log(F) + w*log(G), x)))**(-n)*(F**v*a + G**w*b)**n, Int(F**(n*v)*u*(a + b*exp(ExpandToSum(-v*log(F) + w*log(G), x)))**n, x), x) def replacement2006(F, G, u, v, w, x): return Int(u*NormalizeIntegrand(exp(v*log(F) + w*log(G)), x), x) def With2007(F, u, v, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False z = v*y/(D(u, x)*log(F)) if ZeroQ(-w*y + D(z, x)): return True return False def replacement2007(F, u, v, w, x, y): z = v*y/(D(u, x)*log(F)) return Simp(F**u*z, x) def With2008(F, n, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False z = v*D(u, x)*log(F) + (n + S(1))*D(v, x) if And(Equal(Exponent(w, x), Exponent(z, x)), ZeroQ(w*Coefficient(z, x, Exponent(z, x)) - z*Coefficient(w, x, Exponent(w, x)))): return True return False def replacement2008(F, n, u, v, w, x): z = v*D(u, x)*log(F) + (n + S(1))*D(v, x) return Simp(F**u*v**(n + S(1))*Coefficient(w, x, Exponent(w, x))/Coefficient(z, x, Exponent(z, x)), x) sympy-sympy-1.9/sympy/integrals/rubi/rules/hyperbolic.py000066400000000000000000006516241412543434000237170ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def hyperbolic(): from sympy.integrals.rubi.constraints import cons33, cons170, cons8, cons29, cons50, cons127, cons96, cons1118, cons178, cons1490, cons19, cons89, cons167, cons3, cons95, cons168, cons87, cons1491, cons247, cons249, cons91, cons1444, cons150, cons1861, cons2, cons1492, cons1441, cons810, cons1493, cons1494, cons1456, cons1442, cons64, cons1269, cons1495, cons812, cons813, cons4, cons1362, cons130, cons40, cons139, cons746, cons65, cons1496, cons198, cons1497, cons5, cons55, cons13, cons598, cons1498, cons20, cons1499, cons378, cons148, cons491, cons1500, cons70, cons71, cons825, cons826, cons1501, cons1503, cons1257, cons1504, cons58, cons152, cons1505, cons1506, cons685, cons369, cons1507, cons358, cons68, cons856, cons25, cons1508, cons56, cons14, cons820, cons1133, cons1134, cons1135, cons1509, cons821, cons530, cons1267, cons1512, cons21, cons1573, cons1574, cons1575, cons1576, cons1577, cons1578, cons1579, cons1580, cons1581, cons1045, cons1582, cons1646, cons1738, cons1647, cons586, cons466, cons1685, cons1410, cons1686, cons1687, cons1862, cons1863, cons1690, cons814, cons815, cons557, cons1864, cons1865, cons27, cons1693, cons1866, cons1101, cons1867, cons1868, cons1397, cons1869, cons1695, cons1870, cons965, cons1871, cons1872, cons210, cons1702, cons1013, cons1553, cons1703, cons1704, cons211, cons226, cons1701, cons1873, cons1705, cons1706, cons1874, cons1708, cons1709, cons1875, cons1876, cons1877, cons1878, cons1879, cons1880, cons1881, cons1882, cons1883, cons1884, cons1885, cons1886, cons1887, cons1888, cons1722, cons1889, cons1890, cons1891, cons1725, cons1892, cons165, cons340, cons164, cons629, cons73, cons1727, cons1728, cons1729, cons90, cons1730, cons1458, cons465, cons1731, cons1480, cons1732, cons1893, cons36, cons37, cons1476, cons1483, cons1735 pattern5646 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons170) rule5646 = ReplacementRule(pattern5646, replacement5646) pattern5647 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons170) rule5647 = ReplacementRule(pattern5647, replacement5647) pattern5648 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*sinh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons96) rule5648 = ReplacementRule(pattern5648, replacement5648) pattern5649 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*cosh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons96) rule5649 = ReplacementRule(pattern5649, replacement5649) pattern5650 = Pattern(Integral(sinh(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons1118) rule5650 = ReplacementRule(pattern5650, replacement5650) pattern5651 = Pattern(Integral(cosh(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons1118) rule5651 = ReplacementRule(pattern5651, replacement5651) pattern5652 = Pattern(Integral(sinh(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons178) rule5652 = ReplacementRule(pattern5652, replacement5652) pattern5653 = Pattern(Integral(cosh(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons178) rule5653 = ReplacementRule(pattern5653, replacement5653) pattern5654 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons19, cons1490) rule5654 = ReplacementRule(pattern5654, replacement5654) pattern5655 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons19, cons1490) rule5655 = ReplacementRule(pattern5655, replacement5655) pattern5656 = Pattern(Integral((WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons167) rule5656 = ReplacementRule(pattern5656, replacement5656) pattern5657 = Pattern(Integral((WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons167) rule5657 = ReplacementRule(pattern5657, replacement5657) pattern5658 = Pattern(Integral((WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons168) rule5658 = ReplacementRule(pattern5658, replacement5658) pattern5659 = Pattern(Integral((WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons168) rule5659 = ReplacementRule(pattern5659, replacement5659) pattern5660 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*sinh(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons1491) rule5660 = ReplacementRule(pattern5660, replacement5660) pattern5661 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*cosh(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons1491) rule5661 = ReplacementRule(pattern5661, replacement5661) pattern5662 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*sinh(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons33, cons247) rule5662 = ReplacementRule(pattern5662, replacement5662) pattern5663 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*cosh(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons33, cons247) rule5663 = ReplacementRule(pattern5663, replacement5663) pattern5664 = Pattern(Integral((WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons249) rule5664 = ReplacementRule(pattern5664, replacement5664) pattern5665 = Pattern(Integral((WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons249) rule5665 = ReplacementRule(pattern5665, replacement5665) pattern5666 = Pattern(Integral((WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons91, cons1444) rule5666 = ReplacementRule(pattern5666, replacement5666) pattern5667 = Pattern(Integral((WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons91, cons1444) rule5667 = ReplacementRule(pattern5667, replacement5667) pattern5668 = Pattern(Integral((WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons1444, cons168) rule5668 = ReplacementRule(pattern5668, replacement5668) pattern5669 = Pattern(Integral((WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons1444, cons168) rule5669 = ReplacementRule(pattern5669, replacement5669) pattern5670 = Pattern(Integral((a_ + WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons150, cons1861) rule5670 = ReplacementRule(pattern5670, replacement5670) pattern5671 = Pattern(Integral((a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons150, cons1492) rule5671 = ReplacementRule(pattern5671, replacement5671) pattern5672 = Pattern(Integral((a_ + WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1441, cons87) rule5672 = ReplacementRule(pattern5672, replacement5672) pattern5673 = Pattern(Integral((a_ + WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1441, cons810, cons1493) rule5673 = ReplacementRule(pattern5673, replacement5673) pattern5674 = Pattern(Integral((a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1494, cons87) rule5674 = ReplacementRule(pattern5674, replacement5674) pattern5675 = Pattern(Integral((a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1456, cons87) rule5675 = ReplacementRule(pattern5675, replacement5675) pattern5676 = Pattern(Integral((a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1494, cons810, cons1493) rule5676 = ReplacementRule(pattern5676, replacement5676) pattern5677 = Pattern(Integral((a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1456, cons810, cons1493) rule5677 = ReplacementRule(pattern5677, replacement5677) pattern5678 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442, cons64) rule5678 = ReplacementRule(pattern5678, replacement5678) pattern5679 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule5679 = ReplacementRule(pattern5679, replacement5679) pattern5680 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442, cons64) rule5680 = ReplacementRule(pattern5680, replacement5680) pattern5681 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule5681 = ReplacementRule(pattern5681, replacement5681) pattern5682 = Pattern(Integral((a_ + WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442, cons1495, cons64) rule5682 = ReplacementRule(pattern5682, replacement5682) pattern5683 = Pattern(Integral((a_ + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons1495, cons64) rule5683 = ReplacementRule(pattern5683, replacement5683) pattern5684 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule5684 = ReplacementRule(pattern5684, replacement5684) pattern5685 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule5685 = ReplacementRule(pattern5685, replacement5685) pattern5686 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule5686 = ReplacementRule(pattern5686, replacement5686) pattern5687 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule5687 = ReplacementRule(pattern5687, replacement5687) pattern5688 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons130) rule5688 = ReplacementRule(pattern5688, replacement5688) pattern5689 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons130) rule5689 = ReplacementRule(pattern5689, replacement5689) pattern5690 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons139, cons746) rule5690 = ReplacementRule(pattern5690, replacement5690) pattern5691 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons139, cons746) rule5691 = ReplacementRule(pattern5691, replacement5691) pattern5692 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons150, cons1496) rule5692 = ReplacementRule(pattern5692, replacement5692) pattern5693 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons150, cons1496) rule5693 = ReplacementRule(pattern5693, replacement5693) pattern5694 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons198) rule5694 = ReplacementRule(pattern5694, replacement5694) pattern5695 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons198) rule5695 = ReplacementRule(pattern5695, replacement5695) pattern5696 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule5696 = ReplacementRule(pattern5696, replacement5696) pattern5697 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule5697 = ReplacementRule(pattern5697, replacement5697) pattern5698 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule5698 = ReplacementRule(pattern5698, replacement5698) pattern5699 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule5699 = ReplacementRule(pattern5699, replacement5699) pattern5700 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons55, cons13, cons139, cons598) rule5700 = ReplacementRule(pattern5700, replacement5700) pattern5701 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons55, cons13, cons139, cons598) rule5701 = ReplacementRule(pattern5701, replacement5701) pattern5702 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons33, cons139, cons1498) rule5702 = ReplacementRule(pattern5702, replacement5702) pattern5703 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons33, cons139, cons1498) rule5703 = ReplacementRule(pattern5703, replacement5703) pattern5704 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons20, cons150, cons1496) rule5704 = ReplacementRule(pattern5704, replacement5704) pattern5705 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons20, cons150, cons1496) rule5705 = ReplacementRule(pattern5705, replacement5705) pattern5706 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons65, cons198) rule5706 = ReplacementRule(pattern5706, replacement5706) pattern5707 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons65, cons198) rule5707 = ReplacementRule(pattern5707, replacement5707) pattern5708 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5708 = ReplacementRule(pattern5708, replacement5708) pattern5709 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5709 = ReplacementRule(pattern5709, replacement5709) pattern5710 = Pattern(Integral(sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons87, cons167) rule5710 = ReplacementRule(pattern5710, replacement5710) pattern5711 = Pattern(Integral(cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons87, cons167) rule5711 = ReplacementRule(pattern5711, replacement5711) pattern5712 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons378, cons167, cons148) rule5712 = ReplacementRule(pattern5712, replacement5712) pattern5713 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons378, cons167, cons148) rule5713 = ReplacementRule(pattern5713, replacement5713) pattern5714 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198) rule5714 = ReplacementRule(pattern5714, replacement5714) pattern5715 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198) rule5715 = ReplacementRule(pattern5715, replacement5715) pattern5716 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons491) rule5716 = ReplacementRule(pattern5716, With5716) pattern5717 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons491) rule5717 = ReplacementRule(pattern5717, With5717) pattern5718 = Pattern(Integral(sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons4, cons1500) rule5718 = ReplacementRule(pattern5718, replacement5718) pattern5719 = Pattern(Integral(cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons4, cons1500) rule5719 = ReplacementRule(pattern5719, replacement5719) pattern5720 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons130) rule5720 = ReplacementRule(pattern5720, replacement5720) pattern5721 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons130) rule5721 = ReplacementRule(pattern5721, replacement5721) pattern5722 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sinh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons40, cons70, cons71) rule5722 = ReplacementRule(pattern5722, replacement5722) pattern5723 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cosh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons40, cons70, cons71) rule5723 = ReplacementRule(pattern5723, replacement5723) pattern5724 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sinh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70) rule5724 = ReplacementRule(pattern5724, replacement5724) pattern5725 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cosh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70) rule5725 = ReplacementRule(pattern5725, replacement5725) pattern5726 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sinh(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule5726 = ReplacementRule(pattern5726, replacement5726) pattern5727 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cosh(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule5727 = ReplacementRule(pattern5727, replacement5727) pattern5728 = Pattern(Integral(sinh(x_**n_*WC('d', S(1)))/x_, x_), cons29, cons4, cons1501) rule5728 = ReplacementRule(pattern5728, replacement5728) pattern5729 = Pattern(Integral(cosh(x_**n_*WC('d', S(1)))/x_, x_), cons29, cons4, cons1501) rule5729 = ReplacementRule(pattern5729, replacement5729) pattern5730 = Pattern(Integral(sinh(c_ + x_**n_*WC('d', S(1)))/x_, x_), cons8, cons29, cons4, cons1500) rule5730 = ReplacementRule(pattern5730, replacement5730) pattern5731 = Pattern(Integral(cosh(c_ + x_**n_*WC('d', S(1)))/x_, x_), cons8, cons29, cons4, cons1500) rule5731 = ReplacementRule(pattern5731, replacement5731) pattern5732 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, CustomConstraint(With5732)) rule5732 = ReplacementRule(pattern5732, replacement5732) pattern5733 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, CustomConstraint(With5733)) rule5733 = ReplacementRule(pattern5733, replacement5733) pattern5734 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, CustomConstraint(With5734)) rule5734 = ReplacementRule(pattern5734, replacement5734) pattern5735 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, CustomConstraint(With5735)) rule5735 = ReplacementRule(pattern5735, replacement5735) pattern5736 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons1503) rule5736 = ReplacementRule(pattern5736, replacement5736) pattern5737 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons1503) rule5737 = ReplacementRule(pattern5737, replacement5737) pattern5738 = Pattern(Integral((x_*WC('e', S(1)))**m_*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons96) rule5738 = ReplacementRule(pattern5738, replacement5738) pattern5739 = Pattern(Integral((x_*WC('e', S(1)))**m_*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons96) rule5739 = ReplacementRule(pattern5739, replacement5739) pattern5740 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons150) rule5740 = ReplacementRule(pattern5740, replacement5740) pattern5741 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons150) rule5741 = ReplacementRule(pattern5741, replacement5741) pattern5742 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons378, cons1257, cons148, cons1504) rule5742 = ReplacementRule(pattern5742, replacement5742) pattern5743 = Pattern(Integral(x_**WC('m', S(1))*cosh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons378, cons1257, cons148, cons1504) rule5743 = ReplacementRule(pattern5743, replacement5743) pattern5744 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons148) rule5744 = ReplacementRule(pattern5744, replacement5744) pattern5745 = Pattern(Integral(x_**WC('m', S(1))*cosh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons148) rule5745 = ReplacementRule(pattern5745, replacement5745) pattern5746 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1505) rule5746 = ReplacementRule(pattern5746, replacement5746) pattern5747 = Pattern(Integral(x_**WC('m', S(1))*cosh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1505) rule5747 = ReplacementRule(pattern5747, replacement5747) pattern5748 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1506, cons685) rule5748 = ReplacementRule(pattern5748, replacement5748) pattern5749 = Pattern(Integral(x_**WC('m', S(1))*cosh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1506, cons685) rule5749 = ReplacementRule(pattern5749, replacement5749) pattern5750 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150, cons369) rule5750 = ReplacementRule(pattern5750, With5750) pattern5751 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150, cons369) rule5751 = ReplacementRule(pattern5751, With5751) pattern5752 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons148) rule5752 = ReplacementRule(pattern5752, replacement5752) pattern5753 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons148) rule5753 = ReplacementRule(pattern5753, replacement5753) pattern5754 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons139, cons1507) rule5754 = ReplacementRule(pattern5754, replacement5754) pattern5755 = Pattern(Integral(x_**WC('m', S(1))*cosh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons139, cons1507) rule5755 = ReplacementRule(pattern5755, replacement5755) pattern5756 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons139, cons1507, cons1505) rule5756 = ReplacementRule(pattern5756, replacement5756) pattern5757 = Pattern(Integral(x_**WC('m', S(1))*cosh(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons139, cons1507, cons1505) rule5757 = ReplacementRule(pattern5757, replacement5757) pattern5758 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198, cons20) rule5758 = ReplacementRule(pattern5758, replacement5758) pattern5759 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198, cons20) rule5759 = ReplacementRule(pattern5759, replacement5759) pattern5760 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons198, cons369) rule5760 = ReplacementRule(pattern5760, With5760) pattern5761 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons198, cons369) rule5761 = ReplacementRule(pattern5761, With5761) pattern5762 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons198, cons358) rule5762 = ReplacementRule(pattern5762, replacement5762) pattern5763 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons198, cons358) rule5763 = ReplacementRule(pattern5763, replacement5763) pattern5764 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons40, cons491) rule5764 = ReplacementRule(pattern5764, With5764) pattern5765 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons40, cons491) rule5765 = ReplacementRule(pattern5765, With5765) pattern5766 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons491) rule5766 = ReplacementRule(pattern5766, replacement5766) pattern5767 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons491) rule5767 = ReplacementRule(pattern5767, replacement5767) pattern5768 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, cons68, cons856, cons25) rule5768 = ReplacementRule(pattern5768, replacement5768) pattern5769 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, cons68, cons856, cons25) rule5769 = ReplacementRule(pattern5769, replacement5769) pattern5770 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons68, cons856, cons25) rule5770 = ReplacementRule(pattern5770, replacement5770) pattern5771 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons68, cons856, cons25) rule5771 = ReplacementRule(pattern5771, replacement5771) pattern5772 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons4, cons1508) rule5772 = ReplacementRule(pattern5772, replacement5772) pattern5773 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons4, cons1508) rule5773 = ReplacementRule(pattern5773, replacement5773) pattern5774 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule5774 = ReplacementRule(pattern5774, replacement5774) pattern5775 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule5775 = ReplacementRule(pattern5775, replacement5775) pattern5776 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71, cons20) rule5776 = ReplacementRule(pattern5776, replacement5776) pattern5777 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71, cons20) rule5777 = ReplacementRule(pattern5777, replacement5777) pattern5778 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons70) rule5778 = ReplacementRule(pattern5778, replacement5778) pattern5779 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons70) rule5779 = ReplacementRule(pattern5779, replacement5779) pattern5780 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sinh(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule5780 = ReplacementRule(pattern5780, replacement5780) pattern5781 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cosh(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule5781 = ReplacementRule(pattern5781, replacement5781) pattern5782 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cosh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons4, cons5, cons55, cons56) rule5782 = ReplacementRule(pattern5782, replacement5782) pattern5783 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*cosh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons19, cons4, cons5, cons55, cons56) rule5783 = ReplacementRule(pattern5783, replacement5783) pattern5784 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cosh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons5, cons95, cons1503, cons56) rule5784 = ReplacementRule(pattern5784, replacement5784) pattern5785 = Pattern(Integral(x_**WC('m', S(1))*sinh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*cosh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons5, cons95, cons1503, cons56) rule5785 = ReplacementRule(pattern5785, replacement5785) pattern5786 = Pattern(Integral(sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons14) rule5786 = ReplacementRule(pattern5786, replacement5786) pattern5787 = Pattern(Integral(cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons14) rule5787 = ReplacementRule(pattern5787, replacement5787) pattern5788 = Pattern(Integral(sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons87, cons167) rule5788 = ReplacementRule(pattern5788, replacement5788) pattern5789 = Pattern(Integral(cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons87, cons167) rule5789 = ReplacementRule(pattern5789, replacement5789) pattern5790 = Pattern(Integral(sinh(v_)**WC('n', S(1)), x_), cons150, cons820, cons1133) rule5790 = ReplacementRule(pattern5790, replacement5790) pattern5791 = Pattern(Integral(cosh(v_)**WC('n', S(1)), x_), cons150, cons820, cons1133) rule5791 = ReplacementRule(pattern5791, replacement5791) pattern5792 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1134) rule5792 = ReplacementRule(pattern5792, replacement5792) pattern5793 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1134) rule5793 = ReplacementRule(pattern5793, replacement5793) pattern5794 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1135) rule5794 = ReplacementRule(pattern5794, replacement5794) pattern5795 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1135) rule5795 = ReplacementRule(pattern5795, replacement5795) pattern5796 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1134) rule5796 = ReplacementRule(pattern5796, replacement5796) pattern5797 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1134) rule5797 = ReplacementRule(pattern5797, replacement5797) pattern5798 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1135) rule5798 = ReplacementRule(pattern5798, replacement5798) pattern5799 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1135) rule5799 = ReplacementRule(pattern5799, replacement5799) pattern5800 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1134) rule5800 = ReplacementRule(pattern5800, replacement5800) pattern5801 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1134) rule5801 = ReplacementRule(pattern5801, replacement5801) pattern5802 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1135) rule5802 = ReplacementRule(pattern5802, replacement5802) pattern5803 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1135) rule5803 = ReplacementRule(pattern5803, replacement5803) pattern5804 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1509) rule5804 = ReplacementRule(pattern5804, replacement5804) pattern5805 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1509) rule5805 = ReplacementRule(pattern5805, replacement5805) pattern5806 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*sinh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons87, cons167) rule5806 = ReplacementRule(pattern5806, replacement5806) pattern5807 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cosh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons87, cons167) rule5807 = ReplacementRule(pattern5807, replacement5807) pattern5808 = Pattern(Integral(u_**WC('m', S(1))*sinh(v_)**WC('n', S(1)), x_), cons19, cons150, cons70, cons820, cons821) rule5808 = ReplacementRule(pattern5808, replacement5808) pattern5809 = Pattern(Integral(u_**WC('m', S(1))*cosh(v_)**WC('n', S(1)), x_), cons19, cons150, cons70, cons820, cons821) rule5809 = ReplacementRule(pattern5809, replacement5809) pattern5810 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons64) rule5810 = ReplacementRule(pattern5810, replacement5810) pattern5811 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons64) rule5811 = ReplacementRule(pattern5811, replacement5811) pattern5812 = Pattern(Integral((WC('c', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons95, cons167, cons170) rule5812 = ReplacementRule(pattern5812, replacement5812) pattern5813 = Pattern(Integral((WC('c', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons95, cons167, cons170) rule5813 = ReplacementRule(pattern5813, replacement5813) pattern5814 = Pattern(Integral((WC('c', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons95, cons91, cons170) rule5814 = ReplacementRule(pattern5814, replacement5814) pattern5815 = Pattern(Integral((WC('c', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons95, cons91, cons170) rule5815 = ReplacementRule(pattern5815, replacement5815) pattern5816 = Pattern(Integral((a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule5816 = ReplacementRule(pattern5816, replacement5816) pattern5817 = Pattern(Integral((a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule5817 = ReplacementRule(pattern5817, replacement5817) pattern5818 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons170) rule5818 = ReplacementRule(pattern5818, replacement5818) pattern5819 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons170) rule5819 = ReplacementRule(pattern5819, replacement5819) pattern5820 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267) rule5820 = ReplacementRule(pattern5820, replacement5820) pattern5821 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267) rule5821 = ReplacementRule(pattern5821, replacement5821) pattern5822 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons96, cons1512) rule5822 = ReplacementRule(pattern5822, replacement5822) pattern5823 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons96, cons1512) rule5823 = ReplacementRule(pattern5823, replacement5823) pattern5824 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267) rule5824 = ReplacementRule(pattern5824, replacement5824) pattern5825 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267) rule5825 = ReplacementRule(pattern5825, replacement5825) pattern5826 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1267, cons21) rule5826 = ReplacementRule(pattern5826, replacement5826) pattern5827 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1267, cons21) rule5827 = ReplacementRule(pattern5827, replacement5827) pattern5828 = Pattern(Integral((a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons1573) rule5828 = ReplacementRule(pattern5828, replacement5828) pattern5829 = Pattern(Integral((a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons1573) rule5829 = ReplacementRule(pattern5829, replacement5829) pattern5830 = Pattern(Integral((a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1267, cons198) rule5830 = ReplacementRule(pattern5830, replacement5830) pattern5831 = Pattern(Integral((a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1267, cons198) rule5831 = ReplacementRule(pattern5831, replacement5831) pattern5832 = Pattern(Integral((a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons1574, cons33, cons170) rule5832 = ReplacementRule(pattern5832, With5832) pattern5833 = Pattern(Integral((a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons1574, cons33, cons170) rule5833 = ReplacementRule(pattern5833, With5833) pattern5834 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule5834 = ReplacementRule(pattern5834, replacement5834) pattern5835 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule5835 = ReplacementRule(pattern5835, replacement5835) pattern5836 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269) rule5836 = ReplacementRule(pattern5836, replacement5836) pattern5837 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269) rule5837 = ReplacementRule(pattern5837, replacement5837) pattern5838 = Pattern(Integral((a_ + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons198, cons64) rule5838 = ReplacementRule(pattern5838, replacement5838) pattern5839 = Pattern(Integral((a_ + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons198, cons64) rule5839 = ReplacementRule(pattern5839, replacement5839) pattern5840 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tanh(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule5840 = ReplacementRule(pattern5840, replacement5840) pattern5841 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tanh(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule5841 = ReplacementRule(pattern5841, replacement5841) pattern5842 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tanh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule5842 = ReplacementRule(pattern5842, replacement5842) pattern5843 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tanh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule5843 = ReplacementRule(pattern5843, replacement5843) pattern5844 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule5844 = ReplacementRule(pattern5844, replacement5844) pattern5845 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule5845 = ReplacementRule(pattern5845, replacement5845) pattern5846 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule5846 = ReplacementRule(pattern5846, replacement5846) pattern5847 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule5847 = ReplacementRule(pattern5847, replacement5847) pattern5848 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tanh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule5848 = ReplacementRule(pattern5848, replacement5848) pattern5849 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tanh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule5849 = ReplacementRule(pattern5849, replacement5849) pattern5850 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tanh(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule5850 = ReplacementRule(pattern5850, replacement5850) pattern5851 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tanh(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule5851 = ReplacementRule(pattern5851, replacement5851) pattern5852 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule5852 = ReplacementRule(pattern5852, replacement5852) pattern5853 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule5853 = ReplacementRule(pattern5853, replacement5853) pattern5854 = Pattern(Integral(x_**WC('m', S(1))*tanh(x_**n_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons8, cons29, cons19, cons4, cons1577) rule5854 = ReplacementRule(pattern5854, replacement5854) pattern5855 = Pattern(Integral(x_**WC('m', S(1))/tanh(x_**n_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons8, cons29, cons19, cons4, cons1577) rule5855 = ReplacementRule(pattern5855, replacement5855) pattern5856 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule5856 = ReplacementRule(pattern5856, replacement5856) pattern5857 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule5857 = ReplacementRule(pattern5857, replacement5857) pattern5858 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5858 = ReplacementRule(pattern5858, replacement5858) pattern5859 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tanh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5859 = ReplacementRule(pattern5859, replacement5859) pattern5860 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tanh(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule5860 = ReplacementRule(pattern5860, replacement5860) pattern5861 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tanh(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule5861 = ReplacementRule(pattern5861, replacement5861) pattern5862 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cosh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1))*tanh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1580) rule5862 = ReplacementRule(pattern5862, replacement5862) pattern5863 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sinh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1))*(S(1)/tanh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('q', S(1)), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1580) rule5863 = ReplacementRule(pattern5863, replacement5863) pattern5864 = Pattern(Integral(tanh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule5864 = ReplacementRule(pattern5864, replacement5864) pattern5865 = Pattern(Integral((S(1)/tanh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule5865 = ReplacementRule(pattern5865, replacement5865) pattern5866 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*tanh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule5866 = ReplacementRule(pattern5866, replacement5866) pattern5867 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))/tanh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule5867 = ReplacementRule(pattern5867, replacement5867) pattern5868 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*tanh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule5868 = ReplacementRule(pattern5868, replacement5868) pattern5869 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(S(1)/tanh(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule5869 = ReplacementRule(pattern5869, replacement5869) pattern5870 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule5870 = ReplacementRule(pattern5870, replacement5870) pattern5871 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule5871 = ReplacementRule(pattern5871, replacement5871) pattern5872 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/cosh(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons33, cons170) rule5872 = ReplacementRule(pattern5872, replacement5872) pattern5873 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/sinh(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons33, cons170) rule5873 = ReplacementRule(pattern5873, replacement5873) pattern5874 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons89, cons167, cons1646) rule5874 = ReplacementRule(pattern5874, replacement5874) pattern5875 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons89, cons167, cons1646) rule5875 = ReplacementRule(pattern5875, replacement5875) pattern5876 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons95, cons167, cons1646, cons168) rule5876 = ReplacementRule(pattern5876, replacement5876) pattern5877 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons95, cons167, cons1646, cons168) rule5877 = ReplacementRule(pattern5877, replacement5877) pattern5878 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons89, cons91) rule5878 = ReplacementRule(pattern5878, replacement5878) pattern5879 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons89, cons91) rule5879 = ReplacementRule(pattern5879, replacement5879) pattern5880 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons95, cons91, cons168) rule5880 = ReplacementRule(pattern5880, replacement5880) pattern5881 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons95, cons91, cons168) rule5881 = ReplacementRule(pattern5881, replacement5881) pattern5882 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons25) rule5882 = ReplacementRule(pattern5882, replacement5882) pattern5883 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons25) rule5883 = ReplacementRule(pattern5883, replacement5883) pattern5884 = Pattern(Integral((a_ + WC('b', S(1))/cosh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule5884 = ReplacementRule(pattern5884, replacement5884) pattern5885 = Pattern(Integral((a_ + WC('b', S(1))/sinh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule5885 = ReplacementRule(pattern5885, replacement5885) pattern5886 = Pattern(Integral((a_ + WC('b', S(1))/cosh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons198, cons64) rule5886 = ReplacementRule(pattern5886, replacement5886) pattern5887 = Pattern(Integral((a_ + WC('b', S(1))/sinh(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons198, cons64) rule5887 = ReplacementRule(pattern5887, replacement5887) pattern5888 = Pattern(Integral(u_**WC('m', S(1))*(S(1)/cosh(v_))**WC('n', S(1)), x_), cons19, cons4, cons812, cons813) rule5888 = ReplacementRule(pattern5888, replacement5888) pattern5889 = Pattern(Integral(u_**WC('m', S(1))*(S(1)/sinh(v_))**WC('n', S(1)), x_), cons19, cons4, cons812, cons813) rule5889 = ReplacementRule(pattern5889, replacement5889) pattern5890 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1738) rule5890 = ReplacementRule(pattern5890, replacement5890) pattern5891 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1738) rule5891 = ReplacementRule(pattern5891, replacement5891) pattern5892 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule5892 = ReplacementRule(pattern5892, replacement5892) pattern5893 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule5893 = ReplacementRule(pattern5893, replacement5893) pattern5894 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule5894 = ReplacementRule(pattern5894, replacement5894) pattern5895 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule5895 = ReplacementRule(pattern5895, replacement5895) pattern5896 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cosh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule5896 = ReplacementRule(pattern5896, replacement5896) pattern5897 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sinh(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule5897 = ReplacementRule(pattern5897, replacement5897) pattern5898 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cosh(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule5898 = ReplacementRule(pattern5898, replacement5898) pattern5899 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sinh(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule5899 = ReplacementRule(pattern5899, replacement5899) pattern5900 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule5900 = ReplacementRule(pattern5900, replacement5900) pattern5901 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule5901 = ReplacementRule(pattern5901, replacement5901) pattern5902 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule5902 = ReplacementRule(pattern5902, replacement5902) pattern5903 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule5903 = ReplacementRule(pattern5903, replacement5903) pattern5904 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cosh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5904 = ReplacementRule(pattern5904, replacement5904) pattern5905 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sinh(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5905 = ReplacementRule(pattern5905, replacement5905) pattern5906 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cosh(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule5906 = ReplacementRule(pattern5906, replacement5906) pattern5907 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sinh(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule5907 = ReplacementRule(pattern5907, replacement5907) pattern5908 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cosh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**p_*sinh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1647) rule5908 = ReplacementRule(pattern5908, replacement5908) pattern5909 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sinh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**p_*cosh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1647) rule5909 = ReplacementRule(pattern5909, replacement5909) pattern5910 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule5910 = ReplacementRule(pattern5910, replacement5910) pattern5911 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))*cosh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule5911 = ReplacementRule(pattern5911, replacement5911) pattern5912 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*cosh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons466) rule5912 = ReplacementRule(pattern5912, replacement5912) pattern5913 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons466) rule5913 = ReplacementRule(pattern5913, replacement5913) pattern5914 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1))*cosh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons466) rule5914 = ReplacementRule(pattern5914, replacement5914) pattern5915 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1685, cons33, cons170) rule5915 = ReplacementRule(pattern5915, replacement5915) pattern5916 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1685, cons33, cons170) rule5916 = ReplacementRule(pattern5916, replacement5916) pattern5917 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/cosh(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule5917 = ReplacementRule(pattern5917, replacement5917) pattern5918 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))/sinh(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule5918 = ReplacementRule(pattern5918, replacement5918) pattern5919 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))**p_/cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons1410) rule5919 = ReplacementRule(pattern5919, replacement5919) pattern5920 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1410) rule5920 = ReplacementRule(pattern5920, replacement5920) pattern5921 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0))))**p_/sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons1410) rule5921 = ReplacementRule(pattern5921, replacement5921) pattern5922 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1410) rule5922 = ReplacementRule(pattern5922, replacement5922) pattern5923 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons64, cons1686) rule5923 = ReplacementRule(pattern5923, With5923) pattern5924 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons64, cons1686) rule5924 = ReplacementRule(pattern5924, With5924) pattern5925 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons33, cons87) rule5925 = ReplacementRule(pattern5925, replacement5925) pattern5926 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sinh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/cosh(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons378, cons33, cons170, cons1687) rule5926 = ReplacementRule(pattern5926, With5926) pattern5927 = Pattern(Integral(F_**v_*G_**w_*u_**WC('m', S(1)), x_), cons19, cons4, cons5, cons1862, cons1863, cons1690, cons814, cons815) rule5927 = ReplacementRule(pattern5927, replacement5927) pattern5928 = Pattern(Integral((a_ + WC('b', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule5928 = ReplacementRule(pattern5928, replacement5928) pattern5929 = Pattern(Integral((a_ + WC('b', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule5929 = ReplacementRule(pattern5929, replacement5929) pattern5930 = Pattern(Integral((a_ + WC('b', S(1))*tanh(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))/cosh(x_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule5930 = ReplacementRule(pattern5930, replacement5930) pattern5931 = Pattern(Integral((a_ + WC('b', S(1))/tanh(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))/sinh(x_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule5931 = ReplacementRule(pattern5931, replacement5931) pattern5932 = Pattern(Integral((a_ + WC('b', S(1))/cosh(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*tanh(x_*WC('d', S(1)) + WC('c', S(0)))/cosh(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule5932 = ReplacementRule(pattern5932, replacement5932) pattern5933 = Pattern(Integral((a_ + WC('b', S(1))/sinh(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))/(sinh(x_*WC('d', S(1)) + WC('c', S(0)))*tanh(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule5933 = ReplacementRule(pattern5933, replacement5933) pattern5934 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons557, cons20) rule5934 = ReplacementRule(pattern5934, replacement5934) pattern5935 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cosh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons557, cons20) rule5935 = ReplacementRule(pattern5935, replacement5935) pattern5936 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons557) rule5936 = ReplacementRule(pattern5936, replacement5936) pattern5937 = Pattern(Integral(F_**(x_*WC('b', S(1)) + WC('a', S(0)))*G_**(x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1864, cons1865, cons557, cons27, cons1693) rule5937 = ReplacementRule(pattern5937, replacement5937) pattern5938 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sinh(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1866) rule5938 = ReplacementRule(pattern5938, replacement5938) pattern5939 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cosh(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1866) rule5939 = ReplacementRule(pattern5939, replacement5939) pattern5940 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1867, cons89, cons167) rule5940 = ReplacementRule(pattern5940, replacement5940) pattern5941 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1867, cons89, cons167) rule5941 = ReplacementRule(pattern5941, replacement5941) pattern5942 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1868, cons586, cons1397) rule5942 = ReplacementRule(pattern5942, replacement5942) pattern5943 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1868, cons586, cons1397) rule5943 = ReplacementRule(pattern5943, replacement5943) pattern5944 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1869, cons89, cons91, cons1444) rule5944 = ReplacementRule(pattern5944, replacement5944) pattern5945 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1869, cons89, cons91, cons1444) rule5945 = ReplacementRule(pattern5945, replacement5945) pattern5946 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons25) rule5946 = ReplacementRule(pattern5946, replacement5946) pattern5947 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons25) rule5947 = ReplacementRule(pattern5947, replacement5947) pattern5948 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*tanh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule5948 = ReplacementRule(pattern5948, replacement5948) pattern5949 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/tanh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule5949 = ReplacementRule(pattern5949, replacement5949) pattern5950 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cosh(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1695, cons89, cons91) rule5950 = ReplacementRule(pattern5950, replacement5950) pattern5951 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sinh(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1695, cons89, cons91) rule5951 = ReplacementRule(pattern5951, replacement5951) pattern5952 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cosh(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1870, cons1504, cons965) rule5952 = ReplacementRule(pattern5952, replacement5952) pattern5953 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sinh(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1870, cons1504, cons965) rule5953 = ReplacementRule(pattern5953, replacement5953) pattern5954 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cosh(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1871, cons89, cons167, cons1646) rule5954 = ReplacementRule(pattern5954, replacement5954) pattern5955 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sinh(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1871, cons89, cons167, cons1646) rule5955 = ReplacementRule(pattern5955, replacement5955) pattern5956 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cosh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule5956 = ReplacementRule(pattern5956, replacement5956) pattern5957 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sinh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule5957 = ReplacementRule(pattern5957, replacement5957) pattern5958 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cosh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons25) rule5958 = ReplacementRule(pattern5958, replacement5958) pattern5959 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sinh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons25) rule5959 = ReplacementRule(pattern5959, replacement5959) pattern5960 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1872, cons198) rule5960 = ReplacementRule(pattern5960, replacement5960) pattern5961 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1702, cons198) rule5961 = ReplacementRule(pattern5961, replacement5961) pattern5962 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1013, cons198) rule5962 = ReplacementRule(pattern5962, replacement5962) pattern5963 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1872, cons152, cons1553) rule5963 = ReplacementRule(pattern5963, replacement5963) pattern5964 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1702, cons152, cons1553) rule5964 = ReplacementRule(pattern5964, replacement5964) pattern5965 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1013, cons152, cons1553) rule5965 = ReplacementRule(pattern5965, replacement5965) pattern5966 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(h_ + WC('i', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0))))/(f_ + WC('g', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons1872, cons1703, cons1704) rule5966 = ReplacementRule(pattern5966, replacement5966) pattern5967 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(h_ + WC('i', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0))))/(f_ + WC('g', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons1701, cons1873, cons1705) rule5967 = ReplacementRule(pattern5967, replacement5967) pattern5968 = Pattern(Integral(F_**(u_*WC('c', S(1)))*G_**v_, x_), cons1101, cons8, cons4, cons1863, cons812, cons813) rule5968 = ReplacementRule(pattern5968, replacement5968) pattern5969 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*x_**WC('m', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons33, cons170, cons150) rule5969 = ReplacementRule(pattern5969, With5969) pattern5970 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*x_**WC('m', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons33, cons170, cons150) rule5970 = ReplacementRule(pattern5970, With5970) pattern5971 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cosh(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons530) rule5971 = ReplacementRule(pattern5971, replacement5971) pattern5972 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*x_**WC('p', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cosh(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1706) rule5972 = ReplacementRule(pattern5972, replacement5972) pattern5973 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*G_**(x_*WC('e', S(1)) + WC('d', S(0)))*H_**(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons530, cons1863, cons1874) rule5973 = ReplacementRule(pattern5973, replacement5973) pattern5974 = Pattern(Integral(F_**u_*sinh(v_)**WC('n', S(1)), x_), cons1101, cons1708, cons1709, cons150) rule5974 = ReplacementRule(pattern5974, replacement5974) pattern5975 = Pattern(Integral(F_**u_*cosh(v_)**WC('n', S(1)), x_), cons1101, cons1708, cons1709, cons150) rule5975 = ReplacementRule(pattern5975, replacement5975) pattern5976 = Pattern(Integral(F_**u_*sinh(v_)**WC('m', S(1))*cosh(v_)**WC('n', S(1)), x_), cons1101, cons1708, cons1709, cons530) rule5976 = ReplacementRule(pattern5976, replacement5976) pattern5977 = Pattern(Integral(sinh(WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons8, cons1875) rule5977 = ReplacementRule(pattern5977, replacement5977) pattern5978 = Pattern(Integral(cosh(WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons8, cons1875) rule5978 = ReplacementRule(pattern5978, replacement5978) pattern5979 = Pattern(Integral(sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1876, cons56) rule5979 = ReplacementRule(pattern5979, replacement5979) pattern5980 = Pattern(Integral(cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1876, cons56) rule5980 = ReplacementRule(pattern5980, replacement5980) pattern5981 = Pattern(Integral(sqrt(sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))), x_), cons2, cons3, cons8, cons4, cons1877) rule5981 = ReplacementRule(pattern5981, replacement5981) pattern5982 = Pattern(Integral(sqrt(cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))), x_), cons2, cons3, cons8, cons4, cons1877) rule5982 = ReplacementRule(pattern5982, replacement5982) pattern5983 = Pattern(Integral(sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons130, cons1878) rule5983 = ReplacementRule(pattern5983, replacement5983) pattern5984 = Pattern(Integral(cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons130, cons1878) rule5984 = ReplacementRule(pattern5984, replacement5984) pattern5985 = Pattern(Integral(sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1879) rule5985 = ReplacementRule(pattern5985, replacement5985) pattern5986 = Pattern(Integral(cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1879) rule5986 = ReplacementRule(pattern5986, replacement5986) pattern5987 = Pattern(Integral(sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1880) rule5987 = ReplacementRule(pattern5987, replacement5987) pattern5988 = Pattern(Integral(cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1880) rule5988 = ReplacementRule(pattern5988, replacement5988) pattern5989 = Pattern(Integral(sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1507, cons1881) rule5989 = ReplacementRule(pattern5989, replacement5989) pattern5990 = Pattern(Integral(cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1507, cons1881) rule5990 = ReplacementRule(pattern5990, replacement5990) pattern5991 = Pattern(Integral(sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1880) rule5991 = ReplacementRule(pattern5991, replacement5991) pattern5992 = Pattern(Integral(cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1880) rule5992 = ReplacementRule(pattern5992, replacement5992) pattern5993 = Pattern(Integral(x_**WC('m', S(1))*sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1882, cons56, cons68) rule5993 = ReplacementRule(pattern5993, replacement5993) pattern5994 = Pattern(Integral(x_**WC('m', S(1))*cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1882, cons56, cons68) rule5994 = ReplacementRule(pattern5994, replacement5994) pattern5995 = Pattern(Integral(x_**WC('m', S(1))*sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons130, cons1883) rule5995 = ReplacementRule(pattern5995, replacement5995) pattern5996 = Pattern(Integral(x_**WC('m', S(1))*cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons130, cons1883) rule5996 = ReplacementRule(pattern5996, replacement5996) pattern5997 = Pattern(Integral(x_**WC('m', S(1))*sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1884, cons68) rule5997 = ReplacementRule(pattern5997, replacement5997) pattern5998 = Pattern(Integral(x_**WC('m', S(1))*cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1884, cons68) rule5998 = ReplacementRule(pattern5998, replacement5998) pattern5999 = Pattern(Integral(x_**WC('m', S(1))*sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons1885, cons13, cons148, cons68) rule5999 = ReplacementRule(pattern5999, replacement5999) pattern6000 = Pattern(Integral(x_**WC('m', S(1))*cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons1885, cons13, cons148, cons68) rule6000 = ReplacementRule(pattern6000, replacement6000) pattern6001 = Pattern(Integral(x_**WC('m', S(1))*sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons1886, cons13, cons139, cons1507, cons68) rule6001 = ReplacementRule(pattern6001, replacement6001) pattern6002 = Pattern(Integral(x_**WC('m', S(1))*cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons1886, cons13, cons139, cons1507, cons68) rule6002 = ReplacementRule(pattern6002, replacement6002) pattern6003 = Pattern(Integral(x_**WC('m', S(1))*sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1885) rule6003 = ReplacementRule(pattern6003, replacement6003) pattern6004 = Pattern(Integral(x_**WC('m', S(1))*cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1885) rule6004 = ReplacementRule(pattern6004, replacement6004) pattern6005 = Pattern(Integral((S(1)/cosh(WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons8, cons1875) rule6005 = ReplacementRule(pattern6005, replacement6005) pattern6006 = Pattern(Integral((S(1)/sinh(WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons8, cons1875) rule6006 = ReplacementRule(pattern6006, replacement6006) pattern6007 = Pattern(Integral(S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1887) rule6007 = ReplacementRule(pattern6007, replacement6007) pattern6008 = Pattern(Integral(S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1887) rule6008 = ReplacementRule(pattern6008, replacement6008) pattern6009 = Pattern(Integral((S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1888, cons1647) rule6009 = ReplacementRule(pattern6009, replacement6009) pattern6010 = Pattern(Integral((S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1888, cons1647) rule6010 = ReplacementRule(pattern6010, replacement6010) pattern6011 = Pattern(Integral((S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1722, cons1889) rule6011 = ReplacementRule(pattern6011, replacement6011) pattern6012 = Pattern(Integral((S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1722, cons1889) rule6012 = ReplacementRule(pattern6012, replacement6012) pattern6013 = Pattern(Integral((S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1880) rule6013 = ReplacementRule(pattern6013, replacement6013) pattern6014 = Pattern(Integral((S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1880) rule6014 = ReplacementRule(pattern6014, replacement6014) pattern6015 = Pattern(Integral((S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons1880) rule6015 = ReplacementRule(pattern6015, replacement6015) pattern6016 = Pattern(Integral((S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons1880) rule6016 = ReplacementRule(pattern6016, replacement6016) pattern6017 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cosh(WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons8, cons1890) rule6017 = ReplacementRule(pattern6017, replacement6017) pattern6018 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sinh(WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons8, cons1890) rule6018 = ReplacementRule(pattern6018, replacement6018) pattern6019 = Pattern(Integral(x_**WC('m', S(1))/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1891) rule6019 = ReplacementRule(pattern6019, replacement6019) pattern6020 = Pattern(Integral(x_**WC('m', S(1))/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1891) rule6020 = ReplacementRule(pattern6020, replacement6020) pattern6021 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1725, cons68, cons1647) rule6021 = ReplacementRule(pattern6021, replacement6021) pattern6022 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1725, cons68, cons1647) rule6022 = ReplacementRule(pattern6022, replacement6022) pattern6023 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons148, cons1722, cons1892) rule6023 = ReplacementRule(pattern6023, replacement6023) pattern6024 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons148, cons1722, cons1892) rule6024 = ReplacementRule(pattern6024, replacement6024) pattern6025 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons139, cons1885) rule6025 = ReplacementRule(pattern6025, replacement6025) pattern6026 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons139, cons1885) rule6026 = ReplacementRule(pattern6026, replacement6026) pattern6027 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cosh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1885) rule6027 = ReplacementRule(pattern6027, replacement6027) pattern6028 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sinh(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1885) rule6028 = ReplacementRule(pattern6028, replacement6028) pattern6029 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*sinh(x_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons13, cons165) rule6029 = ReplacementRule(pattern6029, replacement6029) pattern6030 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*cosh(x_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons13, cons165) rule6030 = ReplacementRule(pattern6030, replacement6030) pattern6031 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*sinh(x_**n_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons340, cons165) rule6031 = ReplacementRule(pattern6031, replacement6031) pattern6032 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*cosh(x_**n_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons340, cons165) rule6032 = ReplacementRule(pattern6032, replacement6032) pattern6033 = Pattern(Integral(x_**WC('m', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))*sinh(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons19, cons4, cons55, cons13, cons165) rule6033 = ReplacementRule(pattern6033, replacement6033) pattern6034 = Pattern(Integral(x_**WC('m', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))*cosh(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons19, cons4, cons55, cons13, cons165) rule6034 = ReplacementRule(pattern6034, replacement6034) pattern6035 = Pattern(Integral(x_**m_*log(x_*WC('b', S(1)))**WC('p', S(1))*sinh(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons164, cons165, cons629) rule6035 = ReplacementRule(pattern6035, replacement6035) pattern6036 = Pattern(Integral(x_**m_*log(x_*WC('b', S(1)))**WC('p', S(1))*cosh(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons164, cons165, cons629) rule6036 = ReplacementRule(pattern6036, replacement6036) pattern6037 = Pattern(Integral(sinh(WC('a', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons8, cons29, cons150) rule6037 = ReplacementRule(pattern6037, replacement6037) pattern6038 = Pattern(Integral(cosh(WC('a', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons8, cons29, cons150) rule6038 = ReplacementRule(pattern6038, replacement6038) pattern6039 = Pattern(Integral(sinh((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150, cons73) rule6039 = ReplacementRule(pattern6039, replacement6039) pattern6040 = Pattern(Integral(cosh((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150, cons73) rule6040 = ReplacementRule(pattern6040, replacement6040) pattern6041 = Pattern(Integral(sinh(u_)**WC('n', S(1)), x_), cons150, cons1727) rule6041 = ReplacementRule(pattern6041, With6041) pattern6042 = Pattern(Integral(cosh(u_)**WC('n', S(1)), x_), cons150, cons1727) rule6042 = ReplacementRule(pattern6042, With6042) pattern6043 = Pattern(Integral(WC('u', S(1))*sinh(v_)**WC('p', S(1))*sinh(w_)**WC('q', S(1)), x_), cons1690) rule6043 = ReplacementRule(pattern6043, replacement6043) pattern6044 = Pattern(Integral(WC('u', S(1))*cosh(v_)**WC('p', S(1))*cosh(w_)**WC('q', S(1)), x_), cons1690) rule6044 = ReplacementRule(pattern6044, replacement6044) pattern6045 = Pattern(Integral(sinh(v_)**WC('p', S(1))*sinh(w_)**WC('q', S(1)), x_), cons557, cons1728) rule6045 = ReplacementRule(pattern6045, replacement6045) pattern6046 = Pattern(Integral(cosh(v_)**WC('p', S(1))*cosh(w_)**WC('q', S(1)), x_), cons557, cons1728) rule6046 = ReplacementRule(pattern6046, replacement6046) pattern6047 = Pattern(Integral(x_**WC('m', S(1))*sinh(v_)**WC('p', S(1))*sinh(w_)**WC('q', S(1)), x_), cons1729, cons1728) rule6047 = ReplacementRule(pattern6047, replacement6047) pattern6048 = Pattern(Integral(x_**WC('m', S(1))*cosh(v_)**WC('p', S(1))*cosh(w_)**WC('q', S(1)), x_), cons1729, cons1728) rule6048 = ReplacementRule(pattern6048, replacement6048) pattern6049 = Pattern(Integral(WC('u', S(1))*sinh(v_)**WC('p', S(1))*cosh(w_)**WC('p', S(1)), x_), cons1690, cons40) rule6049 = ReplacementRule(pattern6049, replacement6049) pattern6050 = Pattern(Integral(sinh(v_)**WC('p', S(1))*cosh(w_)**WC('q', S(1)), x_), cons557, cons1728) rule6050 = ReplacementRule(pattern6050, replacement6050) pattern6051 = Pattern(Integral(x_**WC('m', S(1))*sinh(v_)**WC('p', S(1))*cosh(w_)**WC('q', S(1)), x_), cons1729, cons1728) rule6051 = ReplacementRule(pattern6051, replacement6051) pattern6052 = Pattern(Integral(sinh(v_)*tanh(w_)**WC('n', S(1)), x_), cons89, cons90, cons1730) rule6052 = ReplacementRule(pattern6052, replacement6052) pattern6053 = Pattern(Integral((S(1)/tanh(w_))**WC('n', S(1))*cosh(v_), x_), cons89, cons90, cons1730) rule6053 = ReplacementRule(pattern6053, replacement6053) pattern6054 = Pattern(Integral((S(1)/tanh(w_))**WC('n', S(1))*sinh(v_), x_), cons89, cons90, cons1730) rule6054 = ReplacementRule(pattern6054, replacement6054) pattern6055 = Pattern(Integral(cosh(v_)*tanh(w_)**WC('n', S(1)), x_), cons89, cons90, cons1730) rule6055 = ReplacementRule(pattern6055, replacement6055) pattern6056 = Pattern(Integral((S(1)/cosh(w_))**WC('n', S(1))*sinh(v_), x_), cons89, cons90, cons1730) rule6056 = ReplacementRule(pattern6056, replacement6056) pattern6057 = Pattern(Integral((S(1)/sinh(w_))**WC('n', S(1))*cosh(v_), x_), cons89, cons90, cons1730) rule6057 = ReplacementRule(pattern6057, replacement6057) pattern6058 = Pattern(Integral((S(1)/sinh(w_))**WC('n', S(1))*sinh(v_), x_), cons89, cons90, cons1730) rule6058 = ReplacementRule(pattern6058, replacement6058) pattern6059 = Pattern(Integral((S(1)/cosh(w_))**WC('n', S(1))*cosh(v_), x_), cons89, cons90, cons1730) rule6059 = ReplacementRule(pattern6059, replacement6059) pattern6060 = Pattern(Integral((a_ + WC('b', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))*cosh(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule6060 = ReplacementRule(pattern6060, replacement6060) pattern6061 = Pattern(Integral(x_**WC('m', S(1))*(a_ + WC('b', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons1458, cons152, cons170, cons465, cons1731) rule6061 = ReplacementRule(pattern6061, replacement6061) pattern6062 = Pattern(Integral(x_**WC('m', S(1))*(a_ + WC('b', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons1480, cons152, cons170, cons465, cons1731) rule6062 = ReplacementRule(pattern6062, replacement6062) pattern6063 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sinh((c_ + x_*WC('d', S(1)))**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons13) rule6063 = ReplacementRule(pattern6063, replacement6063) pattern6064 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cosh((c_ + x_*WC('d', S(1)))**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons13) rule6064 = ReplacementRule(pattern6064, replacement6064) pattern6065 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/(WC('a', S(0)) + WC('b', S(1))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('c', S(1))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons64, cons1480, cons1732) rule6065 = ReplacementRule(pattern6065, replacement6065) pattern6066 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((b_ + WC('c', S(1))*tanh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons3, cons8, cons29, cons50, cons127, cons210, cons64) rule6066 = ReplacementRule(pattern6066, replacement6066) pattern6067 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((WC('a', S(1))/cosh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('b', S(0)) + WC('c', S(1))*tanh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))*cosh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons64, cons1480, cons1732) rule6067 = ReplacementRule(pattern6067, replacement6067) pattern6068 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((c_ + WC('b', S(1))/tanh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons3, cons8, cons29, cons50, cons127, cons210, cons64) rule6068 = ReplacementRule(pattern6068, replacement6068) pattern6069 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((WC('a', S(1))/sinh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('b', S(1))/tanh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('c', S(0)))*sinh(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons64, cons1480, cons1732) rule6069 = ReplacementRule(pattern6069, replacement6069) pattern6070 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64) rule6070 = ReplacementRule(pattern6070, replacement6070) pattern6071 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64) rule6071 = ReplacementRule(pattern6071, replacement6071) pattern6072 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1441) rule6072 = ReplacementRule(pattern6072, replacement6072) pattern6073 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1267) rule6073 = ReplacementRule(pattern6073, replacement6073) pattern6074 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1442) rule6074 = ReplacementRule(pattern6074, replacement6074) pattern6075 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1269) rule6075 = ReplacementRule(pattern6075, replacement6075) pattern6076 = Pattern(Integral((A_ + WC('B', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0))))*(x_*WC('f', S(1)) + WC('e', S(0)))/(a_ + WC('b', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1893) rule6076 = ReplacementRule(pattern6076, replacement6076) pattern6077 = Pattern(Integral((A_ + WC('B', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0))))*(x_*WC('f', S(1)) + WC('e', S(0)))/(a_ + WC('b', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1476) rule6077 = ReplacementRule(pattern6077, replacement6077) pattern6078 = Pattern(Integral((a_ + WC('b', S(1))*tanh(v_))**WC('n', S(1))*(S(1)/cosh(v_))**WC('m', S(1)), x_), cons2, cons3, cons152, cons1553, cons1483) rule6078 = ReplacementRule(pattern6078, replacement6078) pattern6079 = Pattern(Integral((a_ + WC('b', S(1))/tanh(v_))**WC('n', S(1))*(S(1)/sinh(v_))**WC('m', S(1)), x_), cons2, cons3, cons152, cons1553, cons1483) rule6079 = ReplacementRule(pattern6079, replacement6079) pattern6080 = Pattern(Integral(WC('u', S(1))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*sinh(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons530) rule6080 = ReplacementRule(pattern6080, replacement6080) pattern6081 = Pattern(Integral(WC('u', S(1))*cosh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*cosh(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons530) rule6081 = ReplacementRule(pattern6081, replacement6081) pattern6082 = Pattern(Integral(S(1)/(cosh(c_ + x_*WC('d', S(1)))*cosh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule6082 = ReplacementRule(pattern6082, replacement6082) pattern6083 = Pattern(Integral(S(1)/(sinh(c_ + x_*WC('d', S(1)))*sinh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule6083 = ReplacementRule(pattern6083, replacement6083) pattern6084 = Pattern(Integral(tanh(c_ + x_*WC('d', S(1)))*tanh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule6084 = ReplacementRule(pattern6084, replacement6084) pattern6085 = Pattern(Integral(S(1)/(tanh(c_ + x_*WC('d', S(1)))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule6085 = ReplacementRule(pattern6085, replacement6085) pattern6086 = Pattern(Integral((WC('a', S(1))*cosh(v_) + WC('b', S(1))*sinh(v_))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons4, cons1267) rule6086 = ReplacementRule(pattern6086, replacement6086) return [rule5646, rule5647, rule5648, rule5649, rule5650, rule5651, rule5652, rule5653, rule5654, rule5655, rule5656, rule5657, rule5658, rule5659, rule5660, rule5661, rule5662, rule5663, rule5664, rule5665, rule5666, rule5667, rule5668, rule5669, rule5670, rule5671, rule5672, rule5673, rule5674, rule5675, rule5676, rule5677, rule5678, rule5679, rule5680, rule5681, rule5682, rule5683, rule5684, rule5685, rule5686, rule5687, rule5688, rule5689, rule5690, rule5691, rule5692, rule5693, rule5694, rule5695, rule5696, rule5697, rule5698, rule5699, rule5700, rule5701, rule5702, rule5703, rule5704, rule5705, rule5706, rule5707, rule5708, rule5709, rule5710, rule5711, rule5712, rule5713, rule5714, rule5715, rule5716, rule5717, rule5718, rule5719, rule5720, rule5721, rule5722, rule5723, rule5724, rule5725, rule5726, rule5727, rule5728, rule5729, rule5730, rule5731, rule5732, rule5733, rule5734, rule5735, rule5736, rule5737, rule5738, rule5739, rule5740, rule5741, rule5742, rule5743, rule5744, rule5745, rule5746, rule5747, rule5748, rule5749, rule5750, rule5751, rule5752, rule5753, rule5754, rule5755, rule5756, rule5757, rule5758, rule5759, rule5760, rule5761, rule5762, rule5763, rule5764, rule5765, rule5766, rule5767, rule5768, rule5769, rule5770, rule5771, rule5772, rule5773, rule5774, rule5775, rule5776, rule5777, rule5778, rule5779, rule5780, rule5781, rule5782, rule5783, rule5784, rule5785, rule5786, rule5787, rule5788, rule5789, rule5790, rule5791, rule5792, rule5793, rule5794, rule5795, rule5796, rule5797, rule5798, rule5799, rule5800, rule5801, rule5802, rule5803, rule5804, rule5805, rule5806, rule5807, rule5808, rule5809, rule5810, rule5811, rule5812, rule5813, rule5814, rule5815, rule5816, rule5817, rule5818, rule5819, rule5820, rule5821, rule5822, rule5823, rule5824, rule5825, rule5826, rule5827, rule5828, rule5829, rule5830, rule5831, rule5832, rule5833, rule5834, rule5835, rule5836, rule5837, rule5838, rule5839, rule5840, rule5841, rule5842, rule5843, rule5844, rule5845, rule5846, rule5847, rule5848, rule5849, rule5850, rule5851, rule5852, rule5853, rule5854, rule5855, rule5856, rule5857, rule5858, rule5859, rule5860, rule5861, rule5862, rule5863, rule5864, rule5865, rule5866, rule5867, rule5868, rule5869, rule5870, rule5871, rule5872, rule5873, rule5874, rule5875, rule5876, rule5877, rule5878, rule5879, rule5880, rule5881, rule5882, rule5883, rule5884, rule5885, rule5886, rule5887, rule5888, rule5889, rule5890, rule5891, rule5892, rule5893, rule5894, rule5895, rule5896, rule5897, rule5898, rule5899, rule5900, rule5901, rule5902, rule5903, rule5904, rule5905, rule5906, rule5907, rule5908, rule5909, rule5910, rule5911, rule5912, rule5913, rule5914, rule5915, rule5916, rule5917, rule5918, rule5919, rule5920, rule5921, rule5922, rule5923, rule5924, rule5925, rule5926, rule5927, rule5928, rule5929, rule5930, rule5931, rule5932, rule5933, rule5934, rule5935, rule5936, rule5937, rule5938, rule5939, rule5940, rule5941, rule5942, rule5943, rule5944, rule5945, rule5946, rule5947, rule5948, rule5949, rule5950, rule5951, rule5952, rule5953, rule5954, rule5955, rule5956, rule5957, rule5958, rule5959, rule5960, rule5961, rule5962, rule5963, rule5964, rule5965, rule5966, rule5967, rule5968, rule5969, rule5970, rule5971, rule5972, rule5973, rule5974, rule5975, rule5976, rule5977, rule5978, rule5979, rule5980, rule5981, rule5982, rule5983, rule5984, rule5985, rule5986, rule5987, rule5988, rule5989, rule5990, rule5991, rule5992, rule5993, rule5994, rule5995, rule5996, rule5997, rule5998, rule5999, rule6000, rule6001, rule6002, rule6003, rule6004, rule6005, rule6006, rule6007, rule6008, rule6009, rule6010, rule6011, rule6012, rule6013, rule6014, rule6015, rule6016, rule6017, rule6018, rule6019, rule6020, rule6021, rule6022, rule6023, rule6024, rule6025, rule6026, rule6027, rule6028, rule6029, rule6030, rule6031, rule6032, rule6033, rule6034, rule6035, rule6036, rule6037, rule6038, rule6039, rule6040, rule6041, rule6042, rule6043, rule6044, rule6045, rule6046, rule6047, rule6048, rule6049, rule6050, rule6051, rule6052, rule6053, rule6054, rule6055, rule6056, rule6057, rule6058, rule6059, rule6060, rule6061, rule6062, rule6063, rule6064, rule6065, rule6066, rule6067, rule6068, rule6069, rule6070, rule6071, rule6072, rule6073, rule6074, rule6075, rule6076, rule6077, rule6078, rule6079, rule6080, rule6081, rule6082, rule6083, rule6084, rule6085, rule6086, ] def replacement5646(c, d, e, f, m, x): return -Dist(d*m/f, Int((c + d*x)**(m + S(-1))*cosh(e + f*x), x), x) + Simp((c + d*x)**m*cosh(e + f*x)/f, x) def replacement5647(c, d, e, f, m, x): return -Dist(d*m/f, Int((c + d*x)**(m + S(-1))*sinh(e + f*x), x), x) + Simp((c + d*x)**m*sinh(e + f*x)/f, x) def replacement5648(c, d, e, f, m, x): return -Dist(f/(d*(m + S(1))), Int((c + d*x)**(m + S(1))*cosh(e + f*x), x), x) + Simp((c + d*x)**(m + S(1))*sinh(e + f*x)/(d*(m + S(1))), x) def replacement5649(c, d, e, f, m, x): return -Dist(f/(d*(m + S(1))), Int((c + d*x)**(m + S(1))*sinh(e + f*x), x), x) + Simp((c + d*x)**(m + S(1))*cosh(e + f*x)/(d*(m + S(1))), x) def replacement5650(c, d, e, f, x): return Simp(SinhIntegral(e + f*x)/d, x) def replacement5651(c, d, e, f, x): return Simp(CoshIntegral(e + f*x)/d, x) def replacement5652(c, d, e, f, x): return Dist(sinh((-c*f + d*e)/d), Int(cosh(c*f/d + f*x)/(c + d*x), x), x) + Dist(cosh((-c*f + d*e)/d), Int(sinh(c*f/d + f*x)/(c + d*x), x), x) def replacement5653(c, d, e, f, x): return Dist(sinh((-c*f + d*e)/d), Int(sinh(c*f/d + f*x)/(c + d*x), x), x) + Dist(cosh((-c*f + d*e)/d), Int(cosh(c*f/d + f*x)/(c + d*x), x), x) def replacement5654(c, d, e, f, m, x): return -Dist(S(1)/2, Int((c + d*x)**m*exp(-e - f*x), x), x) + Dist(S(1)/2, Int((c + d*x)**m*exp(e + f*x), x), x) def replacement5655(c, d, e, f, m, x): return Dist(S(1)/2, Int((c + d*x)**m*exp(-e - f*x), x), x) + Dist(S(1)/2, Int((c + d*x)**m*exp(e + f*x), x), x) def replacement5656(b, c, d, e, f, n, x): return -Dist(b**S(2)*(n + S(-1))/n, Int((b*sinh(e + f*x))**(n + S(-2))*(c + d*x), x), x) - Simp(d*(b*sinh(e + f*x))**n/(f**S(2)*n**S(2)), x) + Simp(b*(b*sinh(e + f*x))**(n + S(-1))*(c + d*x)*cosh(e + f*x)/(f*n), x) def replacement5657(b, c, d, e, f, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*cosh(e + f*x))**(n + S(-2))*(c + d*x), x), x) - Simp(d*(b*cosh(e + f*x))**n/(f**S(2)*n**S(2)), x) + Simp(b*(b*cosh(e + f*x))**(n + S(-1))*(c + d*x)*sinh(e + f*x)/(f*n), x) def replacement5658(b, c, d, e, f, m, n, x): return -Dist(b**S(2)*(n + S(-1))/n, Int((b*sinh(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) + Dist(d**S(2)*m*(m + S(-1))/(f**S(2)*n**S(2)), Int((b*sinh(e + f*x))**n*(c + d*x)**(m + S(-2)), x), x) + Simp(b*(b*sinh(e + f*x))**(n + S(-1))*(c + d*x)**m*cosh(e + f*x)/(f*n), x) - Simp(d*m*(b*sinh(e + f*x))**n*(c + d*x)**(m + S(-1))/(f**S(2)*n**S(2)), x) def replacement5659(b, c, d, e, f, m, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*cosh(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) + Dist(d**S(2)*m*(m + S(-1))/(f**S(2)*n**S(2)), Int((b*cosh(e + f*x))**n*(c + d*x)**(m + S(-2)), x), x) + Simp(b*(b*cosh(e + f*x))**(n + S(-1))*(c + d*x)**m*sinh(e + f*x)/(f*n), x) - Simp(d*m*(b*cosh(e + f*x))**n*(c + d*x)**(m + S(-1))/(f**S(2)*n**S(2)), x) def replacement5660(c, d, e, f, m, n, x): return Int(ExpandTrigReduce((c + d*x)**m, sinh(e + f*x)**n, x), x) def replacement5661(c, d, e, f, m, n, x): return Int(ExpandTrigReduce((c + d*x)**m, cosh(e + f*x)**n, x), x) def replacement5662(c, d, e, f, m, n, x): return -Dist(f*n/(d*(m + S(1))), Int(ExpandTrigReduce((c + d*x)**(m + S(1)), sinh(e + f*x)**(n + S(-1))*cosh(e + f*x), x), x), x) + Simp((c + d*x)**(m + S(1))*sinh(e + f*x)**n/(d*(m + S(1))), x) def replacement5663(c, d, e, f, m, n, x): return -Dist(f*n/(d*(m + S(1))), Int(ExpandTrigReduce((c + d*x)**(m + S(1)), sinh(e + f*x)*cosh(e + f*x)**(n + S(-1)), x), x), x) + Simp((c + d*x)**(m + S(1))*cosh(e + f*x)**n/(d*(m + S(1))), x) def replacement5664(b, c, d, e, f, m, n, x): return Dist(f**S(2)*n**S(2)/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*sinh(e + f*x))**n*(c + d*x)**(m + S(2)), x), x) + Dist(b**S(2)*f**S(2)*n*(n + S(-1))/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*sinh(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(2)), x), x) + Simp((b*sinh(e + f*x))**n*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) - Simp(b*f*n*(b*sinh(e + f*x))**(n + S(-1))*(c + d*x)**(m + S(2))*cosh(e + f*x)/(d**S(2)*(m + S(1))*(m + S(2))), x) def replacement5665(b, c, d, e, f, m, n, x): return Dist(f**S(2)*n**S(2)/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*cosh(e + f*x))**n*(c + d*x)**(m + S(2)), x), x) - Dist(b**S(2)*f**S(2)*n*(n + S(-1))/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*cosh(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(2)), x), x) + Simp((b*cosh(e + f*x))**n*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) - Simp(b*f*n*(b*cosh(e + f*x))**(n + S(-1))*(c + d*x)**(m + S(2))*sinh(e + f*x)/(d**S(2)*(m + S(1))*(m + S(2))), x) def replacement5666(b, c, d, e, f, n, x): return -Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*sinh(e + f*x))**(n + S(2))*(c + d*x), x), x) - Simp(d*(b*sinh(e + f*x))**(n + S(2))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) + Simp((b*sinh(e + f*x))**(n + S(1))*(c + d*x)*cosh(e + f*x)/(b*f*(n + S(1))), x) def replacement5667(b, c, d, e, f, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*cosh(e + f*x))**(n + S(2))*(c + d*x), x), x) + Simp(d*(b*cosh(e + f*x))**(n + S(2))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) - Simp((b*cosh(e + f*x))**(n + S(1))*(c + d*x)*sinh(e + f*x)/(b*f*(n + S(1))), x) def replacement5668(b, c, d, e, f, m, n, x): return -Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*sinh(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) + Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), Int((b*sinh(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-2)), x), x) + Simp((b*sinh(e + f*x))**(n + S(1))*(c + d*x)**m*cosh(e + f*x)/(b*f*(n + S(1))), x) - Simp(d*m*(b*sinh(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) def replacement5669(b, c, d, e, f, m, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*cosh(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) - Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), Int((b*cosh(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-2)), x), x) - Simp((b*cosh(e + f*x))**(n + S(1))*(c + d*x)**m*sinh(e + f*x)/(b*f*(n + S(1))), x) + Simp(d*m*(b*cosh(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) def replacement5670(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b*sinh(e + f*x))**n, x), x) def replacement5671(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b*cosh(e + f*x))**n, x), x) def replacement5672(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**n, Int((c + d*x)**m*cosh(-Pi*a/(S(4)*b) + e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement5673(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**IntPart(n)*(a + b*sinh(e + f*x))**FracPart(n)*cosh(-Pi*a/(S(4)*b) + e/S(2) + f*x/S(2))**(-S(2)*FracPart(n)), Int((c + d*x)**m*cosh(-Pi*a/(S(4)*b) + e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement5674(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**n, Int((c + d*x)**m*cosh(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement5675(a, b, c, d, e, f, m, n, x): return Dist((-S(2)*a)**n, Int((c + d*x)**m*sinh(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement5676(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**IntPart(n)*(a + b*cosh(e + f*x))**FracPart(n)*cosh(e/S(2) + f*x/S(2))**(-S(2)*FracPart(n)), Int((c + d*x)**m*cosh(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement5677(a, b, c, d, e, f, m, n, x): return Dist((-S(2)*a)**IntPart(n)*(a + b*cosh(e + f*x))**FracPart(n)*sinh(e/S(2) + f*x/S(2))**(-S(2)*FracPart(n)), Int((c + d*x)**m*sinh(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement5678(a, b, c, d, e, f, m, x): return Dist(S(-2), Int((c + d*x)**m*exp(e + f*x)/(-S(2)*a*exp(e + f*x) - b*exp(S(2)*e + S(2)*f*x) + b), x), x) def replacement5679(a, b, c, d, e, f, m, x): return Dist(S(2), Int((c + d*x)**m*exp(e + f*x)/(S(2)*a*exp(e + f*x) + b*exp(S(2)*e + S(2)*f*x) + b), x), x) def replacement5680(a, b, c, d, e, f, m, x): return Dist(a/(a**S(2) + b**S(2)), Int((c + d*x)**m/(a + b*sinh(e + f*x)), x), x) + Dist(b*d*m/(f*(a**S(2) + b**S(2))), Int((c + d*x)**(m + S(-1))*cosh(e + f*x)/(a + b*sinh(e + f*x)), x), x) - Simp(b*(c + d*x)**m*cosh(e + f*x)/(f*(a + b*sinh(e + f*x))*(a**S(2) + b**S(2))), x) def replacement5681(a, b, c, d, e, f, m, x): return Dist(a/(a**S(2) - b**S(2)), Int((c + d*x)**m/(a + b*cosh(e + f*x)), x), x) + Dist(b*d*m/(f*(a**S(2) - b**S(2))), Int((c + d*x)**(m + S(-1))*sinh(e + f*x)/(a + b*cosh(e + f*x)), x), x) - Simp(b*(c + d*x)**m*sinh(e + f*x)/(f*(a + b*cosh(e + f*x))*(a**S(2) - b**S(2))), x) def replacement5682(a, b, c, d, e, f, m, n, x): return Dist(a/(a**S(2) + b**S(2)), Int((a + b*sinh(e + f*x))**(n + S(1))*(c + d*x)**m, x), x) - Dist(b*(n + S(2))/((a**S(2) + b**S(2))*(n + S(1))), Int((a + b*sinh(e + f*x))**(n + S(1))*(c + d*x)**m*sinh(e + f*x), x), x) - Dist(b*d*m/(f*(a**S(2) + b**S(2))*(n + S(1))), Int((a + b*sinh(e + f*x))**(n + S(1))*(c + d*x)**(m + S(-1))*cosh(e + f*x), x), x) + Simp(b*(a + b*sinh(e + f*x))**(n + S(1))*(c + d*x)**m*cosh(e + f*x)/(f*(a**S(2) + b**S(2))*(n + S(1))), x) def replacement5683(a, b, c, d, e, f, m, n, x): return Dist(a/(a**S(2) - b**S(2)), Int((a + b*cosh(e + f*x))**(n + S(1))*(c + d*x)**m, x), x) - Dist(b*(n + S(2))/((a**S(2) - b**S(2))*(n + S(1))), Int((a + b*cosh(e + f*x))**(n + S(1))*(c + d*x)**m*cosh(e + f*x), x), x) - Dist(b*d*m/(f*(a**S(2) - b**S(2))*(n + S(1))), Int((a + b*cosh(e + f*x))**(n + S(1))*(c + d*x)**(m + S(-1))*sinh(e + f*x), x), x) + Simp(b*(a + b*cosh(e + f*x))**(n + S(1))*(c + d*x)**m*sinh(e + f*x)/(f*(a**S(2) - b**S(2))*(n + S(1))), x) def replacement5684(a, b, m, n, u, v, x): return Int((a + b*sinh(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement5685(a, b, m, n, u, v, x): return Int((a + b*cosh(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement5686(a, b, c, d, e, f, m, n, x): return Int((a + b*sinh(e + f*x))**n*(c + d*x)**m, x) def replacement5687(a, b, c, d, e, f, m, n, x): return Int((a + b*cosh(e + f*x))**n*(c + d*x)**m, x) def replacement5688(a, b, c, d, n, p, x): return Int(ExpandIntegrand(sinh(c + d*x), (a + b*x**n)**p, x), x) def replacement5689(a, b, c, d, n, p, x): return Int(ExpandIntegrand(cosh(c + d*x), (a + b*x**n)**p, x), x) def replacement5690(a, b, c, d, n, p, x): return -Dist(d/(b*n*(p + S(1))), Int(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*cosh(c + d*x), x), x) - Dist((S(1) - n)/(b*n*(p + S(1))), Int(x**(-n)*(a + b*x**n)**(p + S(1))*sinh(c + d*x), x), x) + Simp(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*sinh(c + d*x)/(b*n*(p + S(1))), x) def replacement5691(a, b, c, d, n, p, x): return -Dist(d/(b*n*(p + S(1))), Int(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*sinh(c + d*x), x), x) - Dist((S(1) - n)/(b*n*(p + S(1))), Int(x**(-n)*(a + b*x**n)**(p + S(1))*cosh(c + d*x), x), x) + Simp(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*cosh(c + d*x)/(b*n*(p + S(1))), x) def replacement5692(a, b, c, d, n, p, x): return Int(ExpandIntegrand(sinh(c + d*x), (a + b*x**n)**p, x), x) def replacement5693(a, b, c, d, n, p, x): return Int(ExpandIntegrand(cosh(c + d*x), (a + b*x**n)**p, x), x) def replacement5694(a, b, c, d, n, p, x): return Int(x**(n*p)*(a*x**(-n) + b)**p*sinh(c + d*x), x) def replacement5695(a, b, c, d, n, p, x): return Int(x**(n*p)*(a*x**(-n) + b)**p*cosh(c + d*x), x) def replacement5696(a, b, c, d, n, p, x): return Int((a + b*x**n)**p*sinh(c + d*x), x) def replacement5697(a, b, c, d, n, p, x): return Int((a + b*x**n)**p*cosh(c + d*x), x) def replacement5698(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(sinh(c + d*x), (e*x)**m*(a + b*x**n)**p, x), x) def replacement5699(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(cosh(c + d*x), (e*x)**m*(a + b*x**n)**p, x), x) def replacement5700(a, b, c, d, e, m, n, p, x): return -Dist(d*e**m/(b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*cosh(c + d*x), x), x) + Simp(e**m*(a + b*x**n)**(p + S(1))*sinh(c + d*x)/(b*n*(p + S(1))), x) def replacement5701(a, b, c, d, e, m, n, p, x): return -Dist(d*e**m/(b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*sinh(c + d*x), x), x) + Simp(e**m*(a + b*x**n)**(p + S(1))*cosh(c + d*x)/(b*n*(p + S(1))), x) def replacement5702(a, b, c, d, m, n, p, x): return -Dist(d/(b*n*(p + S(1))), Int(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*cosh(c + d*x), x), x) - Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*(a + b*x**n)**(p + S(1))*sinh(c + d*x), x), x) + Simp(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*sinh(c + d*x)/(b*n*(p + S(1))), x) def replacement5703(a, b, c, d, m, n, p, x): return -Dist(d/(b*n*(p + S(1))), Int(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*sinh(c + d*x), x), x) - Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*(a + b*x**n)**(p + S(1))*cosh(c + d*x), x), x) + Simp(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*cosh(c + d*x)/(b*n*(p + S(1))), x) def replacement5704(a, b, c, d, m, n, p, x): return Int(ExpandIntegrand(sinh(c + d*x), x**m*(a + b*x**n)**p, x), x) def replacement5705(a, b, c, d, m, n, p, x): return Int(ExpandIntegrand(cosh(c + d*x), x**m*(a + b*x**n)**p, x), x) def replacement5706(a, b, c, d, m, n, p, x): return Int(x**(m + n*p)*(a*x**(-n) + b)**p*sinh(c + d*x), x) def replacement5707(a, b, c, d, m, n, p, x): return Int(x**(m + n*p)*(a*x**(-n) + b)**p*cosh(c + d*x), x) def replacement5708(a, b, c, d, e, m, n, p, x): return Int((e*x)**m*(a + b*x**n)**p*sinh(c + d*x), x) def replacement5709(a, b, c, d, e, m, n, p, x): return Int((e*x)**m*(a + b*x**n)**p*cosh(c + d*x), x) def replacement5710(c, d, n, x): return -Dist(S(1)/2, Int(exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int(exp(c + d*x**n), x), x) def replacement5711(c, d, n, x): return Dist(S(1)/2, Int(exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int(exp(c + d*x**n), x), x) def replacement5712(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*sinh(c + d*x**n))**p, x), x) def replacement5713(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*cosh(c + d*x**n))**p, x), x) def replacement5714(a, b, c, d, n, p, x): return -Subst(Int((a + b*sinh(c + d*x**(-n)))**p/x**S(2), x), x, S(1)/x) def replacement5715(a, b, c, d, n, p, x): return -Subst(Int((a + b*cosh(c + d*x**(-n)))**p/x**S(2), x), x, S(1)/x) def With5716(a, b, c, d, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k + S(-1))*(a + b*sinh(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def With5717(a, b, c, d, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k + S(-1))*(a + b*cosh(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def replacement5718(c, d, n, x): return -Dist(S(1)/2, Int(exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int(exp(c + d*x**n), x), x) def replacement5719(c, d, n, x): return Dist(S(1)/2, Int(exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int(exp(c + d*x**n), x), x) def replacement5720(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*sinh(c + d*x**n))**p, x), x) def replacement5721(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*cosh(c + d*x**n))**p, x), x) def replacement5722(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*sinh(c + d*x**n))**p, x), x, u), x) def replacement5723(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*cosh(c + d*x**n))**p, x), x, u), x) def replacement5724(a, b, c, d, n, p, u, x): return Int((a + b*sinh(c + d*u**n))**p, x) def replacement5725(a, b, c, d, n, p, u, x): return Int((a + b*cosh(c + d*u**n))**p, x) def replacement5726(a, b, p, u, x): return Int((a + b*sinh(ExpandToSum(u, x)))**p, x) def replacement5727(a, b, p, u, x): return Int((a + b*cosh(ExpandToSum(u, x)))**p, x) def replacement5728(d, n, x): return Simp(SinhIntegral(d*x**n)/n, x) def replacement5729(d, n, x): return Simp(CoshIntegral(d*x**n)/n, x) def replacement5730(c, d, n, x): return Dist(sinh(c), Int(cosh(d*x**n)/x, x), x) + Dist(cosh(c), Int(sinh(d*x**n)/x, x), x) def replacement5731(c, d, n, x): return Dist(sinh(c), Int(sinh(d*x**n)/x, x), x) + Dist(cosh(c), Int(cosh(d*x**n)/x, x), x) def With5732(a, b, c, d, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement5732(a, b, c, d, m, n, p, x): mn = (m + S(1))/n return Dist(S(1)/n, Subst(Int(x**(mn + S(-1))*(a + b*sinh(c + d*x))**p, x), x, x**n), x) def With5733(a, b, c, d, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement5733(a, b, c, d, m, n, p, x): mn = (m + S(1))/n return Dist(S(1)/n, Subst(Int(x**(mn + S(-1))*(a + b*cosh(c + d*x))**p, x), x, x**n), x) def With5734(a, b, c, d, e, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement5734(a, b, c, d, e, m, n, p, x): mn = (m + S(1))/n return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*sinh(c + d*x**n))**p, x), x) def With5735(a, b, c, d, e, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement5735(a, b, c, d, e, m, n, p, x): mn = (m + S(1))/n return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*cosh(c + d*x**n))**p, x), x) def replacement5736(c, d, e, m, n, x): return -Dist(e**n*(m - n + S(1))/(d*n), Int((e*x)**(m - n)*cosh(c + d*x**n), x), x) + Simp(e**(n + S(-1))*(e*x)**(m - n + S(1))*cosh(c + d*x**n)/(d*n), x) def replacement5737(c, d, e, m, n, x): return -Dist(e**n*(m - n + S(1))/(d*n), Int((e*x)**(m - n)*sinh(c + d*x**n), x), x) + Simp(e**(n + S(-1))*(e*x)**(m - n + S(1))*sinh(c + d*x**n)/(d*n), x) def replacement5738(c, d, e, m, n, x): return -Dist(d*e**(-n)*n/(m + S(1)), Int((e*x)**(m + n)*cosh(c + d*x**n), x), x) + Simp((e*x)**(m + S(1))*sinh(c + d*x**n)/(e*(m + S(1))), x) def replacement5739(c, d, e, m, n, x): return -Dist(d*e**(-n)*n/(m + S(1)), Int((e*x)**(m + n)*sinh(c + d*x**n), x), x) + Simp((e*x)**(m + S(1))*cosh(c + d*x**n)/(e*(m + S(1))), x) def replacement5740(c, d, e, m, n, x): return -Dist(S(1)/2, Int((e*x)**m*exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int((e*x)**m*exp(c + d*x**n), x), x) def replacement5741(c, d, e, m, n, x): return Dist(S(1)/2, Int((e*x)**m*exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int((e*x)**m*exp(c + d*x**n), x), x) def replacement5742(a, b, m, n, p, x): return Dist(b*n*p/(n + S(-1)), Int(sinh(a + b*x**n)**(p + S(-1))*cosh(a + b*x**n), x), x) - Simp(x**(S(1) - n)*sinh(a + b*x**n)**p/(n + S(-1)), x) def replacement5743(a, b, m, n, p, x): return Dist(b*n*p/(n + S(-1)), Int(sinh(a + b*x**n)*cosh(a + b*x**n)**(p + S(-1)), x), x) - Simp(x**(S(1) - n)*cosh(a + b*x**n)**p/(n + S(-1)), x) def replacement5744(a, b, m, n, p, x): return -Dist((p + S(-1))/p, Int(x**m*sinh(a + b*x**n)**(p + S(-2)), x), x) - Simp(sinh(a + b*x**n)**p/(b**S(2)*n*p**S(2)), x) + Simp(x**n*sinh(a + b*x**n)**(p + S(-1))*cosh(a + b*x**n)/(b*n*p), x) def replacement5745(a, b, m, n, p, x): return Dist((p + S(-1))/p, Int(x**m*cosh(a + b*x**n)**(p + S(-2)), x), x) - Simp(cosh(a + b*x**n)**p/(b**S(2)*n*p**S(2)), x) + Simp(x**n*sinh(a + b*x**n)*cosh(a + b*x**n)**(p + S(-1))/(b*n*p), x) def replacement5746(a, b, m, n, p, x): return -Dist((p + S(-1))/p, Int(x**m*sinh(a + b*x**n)**(p + S(-2)), x), x) + Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*p**S(2)), Int(x**(m - S(2)*n)*sinh(a + b*x**n)**p, x), x) - Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*sinh(a + b*x**n)**p/(b**S(2)*n**S(2)*p**S(2)), x) + Simp(x**(m - n + S(1))*sinh(a + b*x**n)**(p + S(-1))*cosh(a + b*x**n)/(b*n*p), x) def replacement5747(a, b, m, n, p, x): return Dist((p + S(-1))/p, Int(x**m*cosh(a + b*x**n)**(p + S(-2)), x), x) + Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*p**S(2)), Int(x**(m - S(2)*n)*cosh(a + b*x**n)**p, x), x) - Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*cosh(a + b*x**n)**p/(b**S(2)*n**S(2)*p**S(2)), x) + Simp(x**(m - n + S(1))*sinh(a + b*x**n)*cosh(a + b*x**n)**(p + S(-1))/(b*n*p), x) def replacement5748(a, b, m, n, p, x): return Dist(b**S(2)*n**S(2)*p**S(2)/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*sinh(a + b*x**n)**p, x), x) + Dist(b**S(2)*n**S(2)*p*(p + S(-1))/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*sinh(a + b*x**n)**(p + S(-2)), x), x) + Simp(x**(m + S(1))*sinh(a + b*x**n)**p/(m + S(1)), x) - Simp(b*n*p*x**(m + n + S(1))*sinh(a + b*x**n)**(p + S(-1))*cosh(a + b*x**n)/((m + S(1))*(m + n + S(1))), x) def replacement5749(a, b, m, n, p, x): return Dist(b**S(2)*n**S(2)*p**S(2)/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*cosh(a + b*x**n)**p, x), x) - Dist(b**S(2)*n**S(2)*p*(p + S(-1))/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*cosh(a + b*x**n)**(p + S(-2)), x), x) + Simp(x**(m + S(1))*cosh(a + b*x**n)**p/(m + S(1)), x) - Simp(b*n*p*x**(m + n + S(1))*sinh(a + b*x**n)*cosh(a + b*x**n)**(p + S(-1))/((m + S(1))*(m + n + S(1))), x) def With5750(a, b, c, d, e, m, n, p, x): k = Denominator(m) return Dist(k/e, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*sinh(c + d*e**(-n)*x**(k*n)))**p, x), x, (e*x)**(S(1)/k)), x) def With5751(a, b, c, d, e, m, n, p, x): k = Denominator(m) return Dist(k/e, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*cosh(c + d*e**(-n)*x**(k*n)))**p, x), x, (e*x)**(S(1)/k)), x) def replacement5752(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*sinh(c + d*x**n))**p, x), x) def replacement5753(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*cosh(c + d*x**n))**p, x), x) def replacement5754(a, b, m, n, p, x): return -Dist((p + S(2))/(p + S(1)), Int(x**m*sinh(a + b*x**n)**(p + S(2)), x), x) - Simp(sinh(a + b*x**n)**(p + S(2))/(b**S(2)*n*(p + S(1))*(p + S(2))), x) + Simp(x**n*sinh(a + b*x**n)**(p + S(1))*cosh(a + b*x**n)/(b*n*(p + S(1))), x) def replacement5755(a, b, m, n, p, x): return Dist((p + S(2))/(p + S(1)), Int(x**m*cosh(a + b*x**n)**(p + S(2)), x), x) + Simp(cosh(a + b*x**n)**(p + S(2))/(b**S(2)*n*(p + S(1))*(p + S(2))), x) - Simp(x**n*sinh(a + b*x**n)*cosh(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement5756(a, b, m, n, p, x): return -Dist((p + S(2))/(p + S(1)), Int(x**m*sinh(a + b*x**n)**(p + S(2)), x), x) + Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**(m - S(2)*n)*sinh(a + b*x**n)**(p + S(2)), x), x) + Simp(x**(m - n + S(1))*sinh(a + b*x**n)**(p + S(1))*cosh(a + b*x**n)/(b*n*(p + S(1))), x) - Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*sinh(a + b*x**n)**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement5757(a, b, m, n, p, x): return Dist((p + S(2))/(p + S(1)), Int(x**m*cosh(a + b*x**n)**(p + S(2)), x), x) - Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**(m - S(2)*n)*cosh(a + b*x**n)**(p + S(2)), x), x) - Simp(x**(m - n + S(1))*sinh(a + b*x**n)*cosh(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) + Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*cosh(a + b*x**n)**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement5758(a, b, c, d, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(a + b*sinh(c + d*x**(-n)))**p, x), x, S(1)/x) def replacement5759(a, b, c, d, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(a + b*cosh(c + d*x**(-n)))**p, x), x, S(1)/x) def With5760(a, b, c, d, e, m, n, p, x): k = Denominator(m) return -Dist(k/e, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*sinh(c + d*e**(-n)*x**(-k*n)))**p, x), x, (e*x)**(-S(1)/k)), x) def With5761(a, b, c, d, e, m, n, p, x): k = Denominator(m) return -Dist(k/e, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*cosh(c + d*e**(-n)*x**(-k*n)))**p, x), x, (e*x)**(-S(1)/k)), x) def replacement5762(a, b, c, d, e, m, n, p, x): return -Dist((e*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a + b*sinh(c + d*x**(-n)))**p, x), x, S(1)/x), x) def replacement5763(a, b, c, d, e, m, n, p, x): return -Dist((e*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a + b*cosh(c + d*x**(-n)))**p, x), x, S(1)/x), x) def With5764(a, b, c, d, m, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*sinh(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def With5765(a, b, c, d, m, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*cosh(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def replacement5766(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*sinh(c + d*x**n))**p, x), x) def replacement5767(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*cosh(c + d*x**n))**p, x), x) def replacement5768(a, b, c, d, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*sinh(c + d*x**(n/(m + S(1)))))**p, x), x, x**(m + S(1))), x) def replacement5769(a, b, c, d, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*cosh(c + d*x**(n/(m + S(1)))))**p, x), x, x**(m + S(1))), x) def replacement5770(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*sinh(c + d*x**n))**p, x), x) def replacement5771(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*cosh(c + d*x**n))**p, x), x) def replacement5772(c, d, e, m, n, x): return -Dist(S(1)/2, Int((e*x)**m*exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int((e*x)**m*exp(c + d*x**n), x), x) def replacement5773(c, d, e, m, n, x): return Dist(S(1)/2, Int((e*x)**m*exp(-c - d*x**n), x), x) + Dist(S(1)/2, Int((e*x)**m*exp(c + d*x**n), x), x) def replacement5774(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*sinh(c + d*x**n))**p, x), x) def replacement5775(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*cosh(c + d*x**n))**p, x), x) def replacement5776(a, b, c, d, m, n, p, u, x): return Dist(Coefficient(u, x, S(1))**(-m + S(-1)), Subst(Int((a + b*sinh(c + d*x**n))**p*(x - Coefficient(u, x, S(0)))**m, x), x, u), x) def replacement5777(a, b, c, d, m, n, p, u, x): return Dist(Coefficient(u, x, S(1))**(-m + S(-1)), Subst(Int((a + b*cosh(c + d*x**n))**p*(x - Coefficient(u, x, S(0)))**m, x), x, u), x) def replacement5778(a, b, c, d, e, m, n, p, u, x): return Int((e*x)**m*(a + b*sinh(c + d*u**n))**p, x) def replacement5779(a, b, c, d, e, m, n, p, u, x): return Int((e*x)**m*(a + b*cosh(c + d*u**n))**p, x) def replacement5780(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b*sinh(ExpandToSum(u, x)))**p, x) def replacement5781(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b*cosh(ExpandToSum(u, x)))**p, x) def replacement5782(a, b, m, n, p, x): return Simp(sinh(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement5783(a, b, m, n, p, x): return Simp(cosh(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement5784(a, b, m, n, p, x): return -Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*sinh(a + b*x**n)**(p + S(1)), x), x) + Simp(x**(m - n + S(1))*sinh(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement5785(a, b, m, n, p, x): return -Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*cosh(a + b*x**n)**(p + S(1)), x), x) + Simp(x**(m - n + S(1))*cosh(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement5786(a, b, c, x): return -Dist(S(1)/2, Int(exp(-a - b*x - c*x**S(2)), x), x) + Dist(S(1)/2, Int(exp(a + b*x + c*x**S(2)), x), x) def replacement5787(a, b, c, x): return Dist(S(1)/2, Int(exp(-a - b*x - c*x**S(2)), x), x) + Dist(S(1)/2, Int(exp(a + b*x + c*x**S(2)), x), x) def replacement5788(a, b, c, n, x): return Int(ExpandTrigReduce(sinh(a + b*x + c*x**S(2))**n, x), x) def replacement5789(a, b, c, n, x): return Int(ExpandTrigReduce(cosh(a + b*x + c*x**S(2))**n, x), x) def replacement5790(n, v, x): return Int(sinh(ExpandToSum(v, x))**n, x) def replacement5791(n, v, x): return Int(cosh(ExpandToSum(v, x))**n, x) def replacement5792(a, b, c, d, e, x): return Simp(e*cosh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5793(a, b, c, d, e, x): return Simp(e*sinh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5794(a, b, c, d, e, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int(sinh(a + b*x + c*x**S(2)), x), x) + Simp(e*cosh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5795(a, b, c, d, e, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int(cosh(a + b*x + c*x**S(2)), x), x) + Simp(e*sinh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5796(a, b, c, d, e, m, x): return -Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*cosh(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*cosh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5797(a, b, c, d, e, m, x): return -Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*sinh(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*sinh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5798(a, b, c, d, e, m, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int((d + e*x)**(m + S(-1))*sinh(a + b*x + c*x**S(2)), x), x) - Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*cosh(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*cosh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5799(a, b, c, d, e, m, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int((d + e*x)**(m + S(-1))*cosh(a + b*x + c*x**S(2)), x), x) - Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*sinh(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*sinh(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement5800(a, b, c, d, e, m, x): return -Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*cosh(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*sinh(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement5801(a, b, c, d, e, m, x): return -Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*sinh(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*cosh(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement5802(a, b, c, d, e, m, x): return -Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*cosh(a + b*x + c*x**S(2)), x), x) - Dist((b*e - S(2)*c*d)/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(1))*cosh(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*sinh(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement5803(a, b, c, d, e, m, x): return -Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*sinh(a + b*x + c*x**S(2)), x), x) - Dist((b*e - S(2)*c*d)/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(1))*sinh(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*cosh(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement5804(a, b, c, d, e, m, x): return Int((d + e*x)**m*sinh(a + b*x + c*x**S(2)), x) def replacement5805(a, b, c, d, e, m, x): return Int((d + e*x)**m*cosh(a + b*x + c*x**S(2)), x) def replacement5806(a, b, c, d, e, m, n, x): return Int(ExpandTrigReduce((d + e*x)**m, sinh(a + b*x + c*x**S(2))**n, x), x) def replacement5807(a, b, c, d, e, m, n, x): return Int(ExpandTrigReduce((d + e*x)**m, cosh(a + b*x + c*x**S(2))**n, x), x) def replacement5808(m, n, u, v, x): return Int(ExpandToSum(u, x)**m*sinh(ExpandToSum(v, x))**n, x) def replacement5809(m, n, u, v, x): return Int(ExpandToSum(u, x)**m*cosh(ExpandToSum(v, x))**n, x) def replacement5810(a, b, e, f, m, x): return Dist(S(2), Int((a + b*x)**m*exp(S(2)*e + S(2)*f*x)/(exp(S(2)*e + S(2)*f*x) + S(1)), x), x) - Simp((a + b*x)**(m + S(1))/(b*(m + S(1))), x) def replacement5811(a, b, e, f, m, x): return -Dist(S(2), Int((a + b*x)**m*exp(S(2)*e + S(2)*f*x)/(S(1) - exp(S(2)*e + S(2)*f*x)), x), x) - Simp((a + b*x)**(m + S(1))/(b*(m + S(1))), x) def replacement5812(a, b, c, e, f, m, n, x): return Dist(c**S(2), Int((c*tanh(e + f*x))**(n + S(-2))*(a + b*x)**m, x), x) + Dist(b*c*m/(f*(n + S(-1))), Int((c*tanh(e + f*x))**(n + S(-1))*(a + b*x)**(m + S(-1)), x), x) - Simp(c*(c*tanh(e + f*x))**(n + S(-1))*(a + b*x)**m/(f*(n + S(-1))), x) def replacement5813(a, b, c, e, f, m, n, x): return Dist(c**S(2), Int((c/tanh(e + f*x))**(n + S(-2))*(a + b*x)**m, x), x) + Dist(b*c*m/(f*(n + S(-1))), Int((c/tanh(e + f*x))**(n + S(-1))*(a + b*x)**(m + S(-1)), x), x) - Simp(c*(c/tanh(e + f*x))**(n + S(-1))*(a + b*x)**m/(f*(n + S(-1))), x) def replacement5814(a, b, c, e, f, m, n, x): return Dist(c**(S(-2)), Int((c*tanh(e + f*x))**(n + S(2))*(a + b*x)**m, x), x) - Dist(b*m/(c*f*(n + S(1))), Int((c*tanh(e + f*x))**(n + S(1))*(a + b*x)**(m + S(-1)), x), x) + Simp((c*tanh(e + f*x))**(n + S(1))*(a + b*x)**m/(c*f*(n + S(1))), x) def replacement5815(a, b, c, e, f, m, n, x): return Dist(c**(S(-2)), Int((c/tanh(e + f*x))**(n + S(2))*(a + b*x)**m, x), x) - Dist(b*m/(c*f*(n + S(1))), Int((c/tanh(e + f*x))**(n + S(1))*(a + b*x)**(m + S(-1)), x), x) + Simp((c/tanh(e + f*x))**(n + S(1))*(a + b*x)**m/(c*f*(n + S(1))), x) def replacement5816(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b*tanh(e + f*x))**n, x), x) def replacement5817(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b/tanh(e + f*x))**n, x), x) def replacement5818(a, b, c, d, e, f, m, x): return Dist(a*d*m/(S(2)*b*f), Int((c + d*x)**(m + S(-1))/(a + b*tanh(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) - Simp(a*(c + d*x)**m/(S(2)*b*f*(a + b*tanh(e + f*x))), x) def replacement5819(a, b, c, d, e, f, m, x): return Dist(a*d*m/(S(2)*b*f), Int((c + d*x)**(m + S(-1))/(a + b/tanh(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) - Simp(a*(c + d*x)**m/(S(2)*b*f*(a + b/tanh(e + f*x))), x) def replacement5820(a, b, c, d, e, f, x): return Dist(f/(a*d), Int(sinh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) - Dist(f/(b*d), Int(cosh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) - Simp(S(1)/(d*(a + b*tanh(e + f*x))*(c + d*x)), x) def replacement5821(a, b, c, d, e, f, x): return -Dist(f/(a*d), Int(sinh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Dist(f/(b*d), Int(cosh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) - Simp(S(1)/(d*(a + b/tanh(e + f*x))*(c + d*x)), x) def replacement5822(a, b, c, d, e, f, m, x): return Dist(S(2)*b*f/(a*d*(m + S(1))), Int((c + d*x)**(m + S(1))/(a + b*tanh(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a + b*tanh(e + f*x))*(m + S(1))), x) - Simp(f*(c + d*x)**(m + S(2))/(b*d**S(2)*(m + S(1))*(m + S(2))), x) def replacement5823(a, b, c, d, e, f, m, x): return Dist(S(2)*b*f/(a*d*(m + S(1))), Int((c + d*x)**(m + S(1))/(a + b/tanh(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a + b/tanh(e + f*x))*(m + S(1))), x) - Simp(f*(c + d*x)**(m + S(2))/(b*d**S(2)*(m + S(1))*(m + S(2))), x) def replacement5824(a, b, c, d, e, f, x): return Dist(S(1)/(S(2)*a), Int(cosh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) - Dist(S(1)/(S(2)*b), Int(sinh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Simp(log(c + d*x)/(S(2)*a*d), x) def replacement5825(a, b, c, d, e, f, x): return -Dist(S(1)/(S(2)*a), Int(cosh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Dist(S(1)/(S(2)*b), Int(sinh(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Simp(log(c + d*x)/(S(2)*a*d), x) def replacement5826(a, b, c, d, e, f, m, x): return Dist(S(1)/(S(2)*a), Int((c + d*x)**m*exp(-S(2)*a*(e + f*x)/b), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) def replacement5827(a, b, c, d, e, f, m, x): return -Dist(S(1)/(S(2)*a), Int((c + d*x)**m*exp(-S(2)*a*(e + f*x)/b), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) def replacement5828(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (-sinh(S(2)*e + S(2)*f*x)/(S(2)*b) + cosh(S(2)*e + S(2)*f*x)/(S(2)*a) + S(1)/(S(2)*a))**(-n), x), x) def replacement5829(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (sinh(S(2)*e + S(2)*f*x)/(S(2)*b) - cosh(S(2)*e + S(2)*f*x)/(S(2)*a) + S(1)/(S(2)*a))**(-n), x), x) def replacement5830(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (S(1)/(S(2)*a) + exp(-S(2)*a*(e + f*x)/b)/(S(2)*a))**(-n), x), x) def replacement5831(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (S(1)/(S(2)*a) - exp(-S(2)*a*(e + f*x)/b)/(S(2)*a))**(-n), x), x) def With5832(a, b, c, d, e, f, m, n, x): u = IntHide((a + b*tanh(e + f*x))**n, x) return -Dist(d*m, Int(Dist((c + d*x)**(m + S(-1)), u, x), x), x) + Dist((c + d*x)**m, u, x) def With5833(a, b, c, d, e, f, m, n, x): u = IntHide((a + b/tanh(e + f*x))**n, x) return -Dist(d*m, Int(Dist((c + d*x)**(m + S(-1)), u, x), x), x) + Dist((c + d*x)**m, u, x) def replacement5834(a, b, c, d, e, f, m, x): return -Dist(S(2)*b, Int((c + d*x)**m/(a**S(2) - b**S(2) + (a - b)**S(2)*exp(-S(2)*e - S(2)*f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a - b)*(m + S(1))), x) def replacement5835(a, b, c, d, e, f, m, x): return Dist(S(2)*b, Int((c + d*x)**m/(a**S(2) - b**S(2) - (a + b)**S(2)*exp(S(2)*e + S(2)*f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a + b)*(m + S(1))), x) def replacement5836(a, b, c, d, e, f, x): return -Dist(S(1)/(f*(a**S(2) - b**S(2))), Int((-S(2)*a*c*f - S(2)*a*d*f*x + b*d)/(a + b*tanh(e + f*x)), x), x) - Simp((c + d*x)**S(2)/(S(2)*d*(a**S(2) - b**S(2))), x) + Simp(b*(c + d*x)/(f*(a + b*tanh(e + f*x))*(a**S(2) - b**S(2))), x) def replacement5837(a, b, c, d, e, f, x): return -Dist(S(1)/(f*(a**S(2) - b**S(2))), Int((-S(2)*a*c*f - S(2)*a*d*f*x + b*d)/(a + b/tanh(e + f*x)), x), x) - Simp((c + d*x)**S(2)/(S(2)*d*(a**S(2) - b**S(2))), x) + Simp(b*(c + d*x)/(f*(a + b/tanh(e + f*x))*(a**S(2) - b**S(2))), x) def replacement5838(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (-S(2)*b/(a**S(2) - b**S(2) + (a - b)**S(2)*exp(-S(2)*e - S(2)*f*x)) + S(1)/(a - b))**(-n), x), x) def replacement5839(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (S(2)*b/(a**S(2) - b**S(2) - (a + b)**S(2)*exp(S(2)*e + S(2)*f*x)) + S(1)/(a + b))**(-n), x), x) def replacement5840(a, b, m, n, u, v, x): return Int((a + b*tanh(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement5841(a, b, m, n, u, v, x): return Int((a + b/tanh(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement5842(a, b, c, d, e, f, m, n, x): return Int((a + b*tanh(e + f*x))**n*(c + d*x)**m, x) def replacement5843(a, b, c, d, e, f, m, n, x): return Int((a + b/tanh(e + f*x))**n*(c + d*x)**m, x) def replacement5844(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b*tanh(c + d*x))**p, x), x, x**n), x) def replacement5845(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b/tanh(c + d*x))**p, x), x, x**n), x) def replacement5846(a, b, c, d, n, p, x): return Int((a + b*tanh(c + d*x**n))**p, x) def replacement5847(a, b, c, d, n, p, x): return Int((a + b/tanh(c + d*x**n))**p, x) def replacement5848(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*tanh(c + d*x**n))**p, x), x, u), x) def replacement5849(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b/tanh(c + d*x**n))**p, x), x, u), x) def replacement5850(a, b, p, u, x): return Int((a + b*tanh(ExpandToSum(u, x)))**p, x) def replacement5851(a, b, p, u, x): return Int((a + b/tanh(ExpandToSum(u, x)))**p, x) def replacement5852(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*tanh(c + d*x))**p, x), x, x**n), x) def replacement5853(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b/tanh(c + d*x))**p, x), x, x**n), x) def replacement5854(c, d, m, n, x): return Dist((m - n + S(1))/(d*n), Int(x**(m - n)*tanh(c + d*x**n), x), x) + Int(x**m, x) - Simp(x**(m - n + S(1))*tanh(c + d*x**n)/(d*n), x) def replacement5855(c, d, m, n, x): return Dist((m - n + S(1))/(d*n), Int(x**(m - n)/tanh(c + d*x**n), x), x) + Int(x**m, x) - Simp(x**(m - n + S(1))/(d*n*tanh(c + d*x**n)), x) def replacement5856(a, b, c, d, m, n, p, x): return Int(x**m*(a + b*tanh(c + d*x**n))**p, x) def replacement5857(a, b, c, d, m, n, p, x): return Int(x**m*(a + b/tanh(c + d*x**n))**p, x) def replacement5858(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*tanh(c + d*x**n))**p, x), x) def replacement5859(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b/tanh(c + d*x**n))**p, x), x) def replacement5860(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b*tanh(ExpandToSum(u, x)))**p, x) def replacement5861(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b/tanh(ExpandToSum(u, x)))**p, x) def replacement5862(a, b, m, n, p, q, x): return Dist((m - n + S(1))/(b*n*p), Int(x**(m - n)*(S(1)/cosh(a + b*x**n))**p, x), x) - Simp(x**(m - n + S(1))*(S(1)/cosh(a + b*x**n))**p/(b*n*p), x) def replacement5863(a, b, m, n, p, q, x): return Dist((m - n + S(1))/(b*n*p), Int(x**(m - n)*(S(1)/sinh(a + b*x**n))**p, x), x) - Simp(x**(m - n + S(1))*(S(1)/sinh(a + b*x**n))**p/(b*n*p), x) def replacement5864(a, b, c, n, x): return Int(tanh(a + b*x + c*x**S(2))**n, x) def replacement5865(a, b, c, n, x): return Int((S(1)/tanh(a + b*x + c*x**S(2)))**n, x) def replacement5866(a, b, c, d, e, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int(tanh(a + b*x + c*x**S(2)), x), x) + Simp(e*log(cosh(a + b*x + c*x**S(2)))/(S(2)*c), x) def replacement5867(a, b, c, d, e, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int(S(1)/tanh(a + b*x + c*x**S(2)), x), x) + Simp(e*log(sinh(a + b*x + c*x**S(2)))/(S(2)*c), x) def replacement5868(a, b, c, d, e, m, n, x): return Int((d + e*x)**m*tanh(a + b*x + c*x**S(2))**n, x) def replacement5869(a, b, c, d, e, m, n, x): return Int((d + e*x)**m*(S(1)/tanh(a + b*x + c*x**S(2)))**n, x) def replacement5870(a, b, c, d, m, x): return -Dist(I*d*m/b, Int((c + d*x)**(m + S(-1))*log(-I*exp(a + b*x) + S(1)), x), x) + Dist(I*d*m/b, Int((c + d*x)**(m + S(-1))*log(I*exp(a + b*x) + S(1)), x), x) + Simp(S(2)*(c + d*x)**m*ArcTan(exp(a + b*x))/b, x) def replacement5871(a, b, c, d, m, x): return -Dist(d*m/b, Int((c + d*x)**(m + S(-1))*log(S(1) - exp(a + b*x)), x), x) + Dist(d*m/b, Int((c + d*x)**(m + S(-1))*log(exp(a + b*x) + S(1)), x), x) + Simp(-S(2)*(c + d*x)**m*atanh(exp(a + b*x))/b, x) def replacement5872(a, b, c, d, m, x): return -Dist(d*m/b, Int((c + d*x)**(m + S(-1))*tanh(a + b*x), x), x) + Simp((c + d*x)**m*tanh(a + b*x)/b, x) def replacement5873(a, b, c, d, m, x): return Dist(d*m/b, Int((c + d*x)**(m + S(-1))/tanh(a + b*x), x), x) - Simp((c + d*x)**m/(b*tanh(a + b*x)), x) def replacement5874(a, b, c, d, n, x): return Dist((n + S(-2))/(n + S(-1)), Int((c + d*x)*(S(1)/cosh(a + b*x))**(n + S(-2)), x), x) + Simp(d*(S(1)/cosh(a + b*x))**(n + S(-2))/(b**S(2)*(n + S(-2))*(n + S(-1))), x) + Simp((c + d*x)*(S(1)/cosh(a + b*x))**(n + S(-2))*tanh(a + b*x)/(b*(n + S(-1))), x) def replacement5875(a, b, c, d, n, x): return -Dist((n + S(-2))/(n + S(-1)), Int((c + d*x)*(S(1)/sinh(a + b*x))**(n + S(-2)), x), x) - Simp(d*(S(1)/sinh(a + b*x))**(n + S(-2))/(b**S(2)*(n + S(-2))*(n + S(-1))), x) - Simp((c + d*x)*(S(1)/sinh(a + b*x))**(n + S(-2))/(b*(n + S(-1))*tanh(a + b*x)), x) def replacement5876(a, b, c, d, m, n, x): return Dist((n + S(-2))/(n + S(-1)), Int((c + d*x)**m*(S(1)/cosh(a + b*x))**(n + S(-2)), x), x) - Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*(n + S(-2))*(n + S(-1))), Int((c + d*x)**(m + S(-2))*(S(1)/cosh(a + b*x))**(n + S(-2)), x), x) + Simp((c + d*x)**m*(S(1)/cosh(a + b*x))**(n + S(-2))*tanh(a + b*x)/(b*(n + S(-1))), x) + Simp(d*m*(c + d*x)**(m + S(-1))*(S(1)/cosh(a + b*x))**(n + S(-2))/(b**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement5877(a, b, c, d, m, n, x): return -Dist((n + S(-2))/(n + S(-1)), Int((c + d*x)**m*(S(1)/sinh(a + b*x))**(n + S(-2)), x), x) + Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*(n + S(-2))*(n + S(-1))), Int((c + d*x)**(m + S(-2))*(S(1)/sinh(a + b*x))**(n + S(-2)), x), x) - Simp((c + d*x)**m*(S(1)/sinh(a + b*x))**(n + S(-2))/(b*(n + S(-1))*tanh(a + b*x)), x) - Simp(d*m*(c + d*x)**(m + S(-1))*(S(1)/sinh(a + b*x))**(n + S(-2))/(b**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement5878(a, b, c, d, n, x): return Dist((n + S(1))/n, Int((c + d*x)*(S(1)/cosh(a + b*x))**(n + S(2)), x), x) - Simp(d*(S(1)/cosh(a + b*x))**n/(b**S(2)*n**S(2)), x) - Simp((c + d*x)*(S(1)/cosh(a + b*x))**(n + S(1))*sinh(a + b*x)/(b*n), x) def replacement5879(a, b, c, d, n, x): return -Dist((n + S(1))/n, Int((c + d*x)*(S(1)/sinh(a + b*x))**(n + S(2)), x), x) - Simp(d*(S(1)/sinh(a + b*x))**n/(b**S(2)*n**S(2)), x) - Simp((c + d*x)*(S(1)/sinh(a + b*x))**(n + S(1))*cosh(a + b*x)/(b*n), x) def replacement5880(a, b, c, d, m, n, x): return Dist((n + S(1))/n, Int((c + d*x)**m*(S(1)/cosh(a + b*x))**(n + S(2)), x), x) + Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*n**S(2)), Int((c + d*x)**(m + S(-2))*(S(1)/cosh(a + b*x))**n, x), x) - Simp((c + d*x)**m*(S(1)/cosh(a + b*x))**(n + S(1))*sinh(a + b*x)/(b*n), x) - Simp(d*m*(c + d*x)**(m + S(-1))*(S(1)/cosh(a + b*x))**n/(b**S(2)*n**S(2)), x) def replacement5881(a, b, c, d, m, n, x): return -Dist((n + S(1))/n, Int((c + d*x)**m*(S(1)/sinh(a + b*x))**(n + S(2)), x), x) + Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*n**S(2)), Int((c + d*x)**(m + S(-2))*(S(1)/sinh(a + b*x))**n, x), x) - Simp((c + d*x)**m*(S(1)/sinh(a + b*x))**(n + S(1))*cosh(a + b*x)/(b*n), x) - Simp(d*m*(c + d*x)**(m + S(-1))*(S(1)/sinh(a + b*x))**n/(b**S(2)*n**S(2)), x) def replacement5882(a, b, c, d, m, n, x): return Dist((S(1)/cosh(a + b*x))**n*cosh(a + b*x)**n, Int((c + d*x)**m*cosh(a + b*x)**(-n), x), x) def replacement5883(a, b, c, d, m, n, x): return Dist((S(1)/sinh(a + b*x))**n*sinh(a + b*x)**n, Int((c + d*x)**m*sinh(a + b*x)**(-n), x), x) def replacement5884(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b/cosh(e + f*x))**n, x), x) def replacement5885(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b/sinh(e + f*x))**n, x), x) def replacement5886(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a*cosh(e + f*x) + b)**n*cosh(e + f*x)**(-n), x), x) def replacement5887(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a*sinh(e + f*x) + b)**n*sinh(e + f*x)**(-n), x), x) def replacement5888(m, n, u, v, x): return Int((S(1)/cosh(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement5889(m, n, u, v, x): return Int((S(1)/sinh(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement5890(a, b, c, d, m, n, x): return Int((c + d*x)**m*(S(1)/cosh(a + b*x))**n, x) def replacement5891(a, b, c, d, m, n, x): return Int((c + d*x)**m*(S(1)/sinh(a + b*x))**n, x) def replacement5892(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b/cosh(c + d*x))**p, x), x, x**n), x) def replacement5893(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b/sinh(c + d*x))**p, x), x, x**n), x) def replacement5894(a, b, c, d, n, p, x): return Int((a + b/cosh(c + d*x**n))**p, x) def replacement5895(a, b, c, d, n, p, x): return Int((a + b/sinh(c + d*x**n))**p, x) def replacement5896(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b/cosh(c + d*x**n))**p, x), x, u), x) def replacement5897(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b/sinh(c + d*x**n))**p, x), x, u), x) def replacement5898(a, b, p, u, x): return Int((a + b/cosh(ExpandToSum(u, x)))**p, x) def replacement5899(a, b, p, u, x): return Int((a + b/sinh(ExpandToSum(u, x)))**p, x) def replacement5900(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b/cosh(c + d*x))**p, x), x, x**n), x) def replacement5901(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b/sinh(c + d*x))**p, x), x, x**n), x) def replacement5902(a, b, c, d, m, n, p, x): return Int(x**m*(a + b/cosh(c + d*x**n))**p, x) def replacement5903(a, b, c, d, m, n, p, x): return Int(x**m*(a + b/sinh(c + d*x**n))**p, x) def replacement5904(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b/cosh(c + d*x**n))**p, x), x) def replacement5905(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b/sinh(c + d*x**n))**p, x), x) def replacement5906(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b/cosh(ExpandToSum(u, x)))**p, x) def replacement5907(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b/sinh(ExpandToSum(u, x)))**p, x) def replacement5908(a, b, m, n, p, x): return Dist((m - n + S(1))/(b*n*(p + S(-1))), Int(x**(m - n)*(S(1)/cosh(a + b*x**n))**(p + S(-1)), x), x) - Simp(x**(m - n + S(1))*(S(1)/cosh(a + b*x**n))**(p + S(-1))/(b*n*(p + S(-1))), x) def replacement5909(a, b, m, n, p, x): return Dist((m - n + S(1))/(b*n*(p + S(-1))), Int(x**(m - n)*(S(1)/sinh(a + b*x**n))**(p + S(-1)), x), x) - Simp(x**(m - n + S(1))*(S(1)/sinh(a + b*x**n))**(p + S(-1))/(b*n*(p + S(-1))), x) def replacement5910(a, b, c, d, m, n, x): return -Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*sinh(a + b*x)**(n + S(1)), x), x) + Simp((c + d*x)**m*sinh(a + b*x)**(n + S(1))/(b*(n + S(1))), x) def replacement5911(a, b, c, d, m, n, x): return -Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*cosh(a + b*x)**(n + S(1)), x), x) + Simp((c + d*x)**m*cosh(a + b*x)**(n + S(1))/(b*(n + S(1))), x) def replacement5912(a, b, c, d, m, n, p, x): return Int(ExpandTrigReduce((c + d*x)**m, sinh(a + b*x)**n*cosh(a + b*x)**p, x), x) def replacement5913(a, b, c, d, m, n, p, x): return Int((c + d*x)**m*sinh(a + b*x)**n*tanh(a + b*x)**(p + S(-2)), x) - Int((c + d*x)**m*sinh(a + b*x)**(n + S(-2))*tanh(a + b*x)**p, x) def replacement5914(a, b, c, d, m, n, p, x): return Int((c + d*x)**m*(S(1)/tanh(a + b*x))**p*cosh(a + b*x)**(n + S(-2)), x) + Int((c + d*x)**m*(S(1)/tanh(a + b*x))**(p + S(-2))*cosh(a + b*x)**n, x) def replacement5915(a, b, c, d, m, n, p, x): return Dist(d*m/(b*n), Int((c + d*x)**(m + S(-1))*(S(1)/cosh(a + b*x))**n, x), x) - Simp((c + d*x)**m*(S(1)/cosh(a + b*x))**n/(b*n), x) def replacement5916(a, b, c, d, m, n, p, x): return Dist(d*m/(b*n), Int((c + d*x)**(m + S(-1))*(S(1)/sinh(a + b*x))**n, x), x) - Simp((c + d*x)**m*(S(1)/sinh(a + b*x))**n/(b*n), x) def replacement5917(a, b, c, d, m, n, x): return -Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*tanh(a + b*x)**(n + S(1)), x), x) + Simp((c + d*x)**m*tanh(a + b*x)**(n + S(1))/(b*(n + S(1))), x) def replacement5918(a, b, c, d, m, n, x): return Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*(S(1)/tanh(a + b*x))**(n + S(1)), x), x) - Simp((c + d*x)**m*(S(1)/tanh(a + b*x))**(n + S(1))/(b*(n + S(1))), x) def replacement5919(a, b, c, d, m, p, x): return -Int((c + d*x)**m*tanh(a + b*x)**(p + S(-2))/cosh(a + b*x)**S(3), x) + Int((c + d*x)**m*tanh(a + b*x)**(p + S(-2))/cosh(a + b*x), x) def replacement5920(a, b, c, d, m, n, p, x): return Int((c + d*x)**m*(S(1)/cosh(a + b*x))**n*tanh(a + b*x)**(p + S(-2)), x) - Int((c + d*x)**m*(S(1)/cosh(a + b*x))**(n + S(2))*tanh(a + b*x)**(p + S(-2)), x) def replacement5921(a, b, c, d, m, p, x): return Int((c + d*x)**m*(S(1)/tanh(a + b*x))**(p + S(-2))/sinh(a + b*x)**S(3), x) + Int((c + d*x)**m*(S(1)/tanh(a + b*x))**(p + S(-2))/sinh(a + b*x), x) def replacement5922(a, b, c, d, m, n, p, x): return Int((c + d*x)**m*(S(1)/sinh(a + b*x))**n*(S(1)/tanh(a + b*x))**(p + S(-2)), x) + Int((c + d*x)**m*(S(1)/sinh(a + b*x))**(n + S(2))*(S(1)/tanh(a + b*x))**(p + S(-2)), x) def With5923(a, b, c, d, m, n, p, x): u = IntHide((S(1)/cosh(a + b*x))**n*tanh(a + b*x)**p, x) return -Dist(d*m, Int(u*(c + d*x)**(m + S(-1)), x), x) + Dist((c + d*x)**m, u, x) def With5924(a, b, c, d, m, n, p, x): u = IntHide((S(1)/sinh(a + b*x))**n*(S(1)/tanh(a + b*x))**p, x) return -Dist(d*m, Int(u*(c + d*x)**(m + S(-1)), x), x) + Dist((c + d*x)**m, u, x) def replacement5925(a, b, c, d, m, n, x): return Dist(S(2)**n, Int((c + d*x)**m*(S(1)/sinh(S(2)*a + S(2)*b*x))**n, x), x) def With5926(a, b, c, d, m, n, p, x): u = IntHide((S(1)/sinh(a + b*x))**n*(S(1)/cosh(a + b*x))**p, x) return -Dist(d*m, Int(u*(c + d*x)**(m + S(-1)), x), x) + Dist((c + d*x)**m, u, x) def replacement5927(F, G, m, n, p, u, v, w, x): return Int(ExpandToSum(u, x)**m*F(ExpandToSum(v, x))**n*G(ExpandToSum(v, x))**p, x) def replacement5928(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*d*(n + S(1))), Int((a + b*sinh(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) + Simp((a + b*sinh(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement5929(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*d*(n + S(1))), Int((a + b*cosh(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) + Simp((a + b*cosh(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement5930(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*d*(n + S(1))), Int((a + b*tanh(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) + Simp((a + b*tanh(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement5931(a, b, c, d, e, f, m, n, x): return Dist(f*m/(b*d*(n + S(1))), Int((a + b/tanh(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) - Simp((a + b/tanh(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement5932(a, b, c, d, e, f, m, n, x): return Dist(f*m/(b*d*(n + S(1))), Int((a + b/cosh(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) - Simp((a + b/cosh(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement5933(a, b, c, d, e, f, m, n, x): return Dist(f*m/(b*d*(n + S(1))), Int((a + b/sinh(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) - Simp((a + b/sinh(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement5934(a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigReduce((e + f*x)**m, sinh(a + b*x)**p*sinh(c + d*x)**q, x), x) def replacement5935(a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigReduce((e + f*x)**m, cosh(a + b*x)**p*cosh(c + d*x)**q, x), x) def replacement5936(a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigReduce((e + f*x)**m, sinh(a + b*x)**p*cosh(c + d*x)**q, x), x) def replacement5937(F, G, a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigExpand((e + f*x)**m*G(c + d*x)**q, F, c + d*x, p, b/d, x), x) def replacement5938(F, a, b, c, d, e, x): return Simp(F**(c*(a + b*x))*e*cosh(d + e*x)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*sinh(d + e*x)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) def replacement5939(F, a, b, c, d, e, x): return Simp(F**(c*(a + b*x))*e*sinh(d + e*x)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*cosh(d + e*x)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) def replacement5940(F, a, b, c, d, e, n, x): return -Dist(e**S(2)*n*(n + S(-1))/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), Int(F**(c*(a + b*x))*sinh(d + e*x)**(n + S(-2)), x), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*sinh(d + e*x)**n/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) + Simp(F**(c*(a + b*x))*e*n*sinh(d + e*x)**(n + S(-1))*cosh(d + e*x)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) def replacement5941(F, a, b, c, d, e, n, x): return Dist(e**S(2)*n*(n + S(-1))/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), Int(F**(c*(a + b*x))*cosh(d + e*x)**(n + S(-2)), x), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*cosh(d + e*x)**n/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) + Simp(F**(c*(a + b*x))*e*n*sinh(d + e*x)*cosh(d + e*x)**(n + S(-1))/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) def replacement5942(F, a, b, c, d, e, n, x): return Simp(F**(c*(a + b*x))*sinh(d + e*x)**(n + S(1))*cosh(d + e*x)/(e*(n + S(1))), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*sinh(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement5943(F, a, b, c, d, e, n, x): return -Simp(F**(c*(a + b*x))*sinh(d + e*x)*cosh(d + e*x)**(n + S(1))/(e*(n + S(1))), x) + Simp(F**(c*(a + b*x))*b*c*log(F)*cosh(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement5944(F, a, b, c, d, e, n, x): return -Dist((-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2))/(e**S(2)*(n + S(1))*(n + S(2))), Int(F**(c*(a + b*x))*sinh(d + e*x)**(n + S(2)), x), x) + Simp(F**(c*(a + b*x))*sinh(d + e*x)**(n + S(1))*cosh(d + e*x)/(e*(n + S(1))), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*sinh(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement5945(F, a, b, c, d, e, n, x): return Dist((-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2))/(e**S(2)*(n + S(1))*(n + S(2))), Int(F**(c*(a + b*x))*cosh(d + e*x)**(n + S(2)), x), x) - Simp(F**(c*(a + b*x))*sinh(d + e*x)*cosh(d + e*x)**(n + S(1))/(e*(n + S(1))), x) + Simp(F**(c*(a + b*x))*b*c*log(F)*cosh(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement5946(F, a, b, c, d, e, n, x): return Dist((exp(S(2)*d + S(2)*e*x) + S(-1))**(-n)*exp(n*(d + e*x))*sinh(d + e*x)**n, Int(F**(c*(a + b*x))*(exp(S(2)*d + S(2)*e*x) + S(-1))**n*exp(-n*(d + e*x)), x), x) def replacement5947(F, a, b, c, d, e, n, x): return Dist((exp(S(2)*d + S(2)*e*x) + S(1))**(-n)*exp(n*(d + e*x))*cosh(d + e*x)**n, Int(F**(c*(a + b*x))*(exp(S(2)*d + S(2)*e*x) + S(1))**n*exp(-n*(d + e*x)), x), x) def replacement5948(F, a, b, c, d, e, n, x): return Int(ExpandIntegrand(F**(c*(a + b*x))*(exp(S(2)*d + S(2)*e*x) + S(-1))**n*(exp(S(2)*d + S(2)*e*x) + S(1))**(-n), x), x) def replacement5949(F, a, b, c, d, e, n, x): return Int(ExpandIntegrand(F**(c*(a + b*x))*(exp(S(2)*d + S(2)*e*x) + S(-1))**(-n)*(exp(S(2)*d + S(2)*e*x) + S(1))**n, x), x) def replacement5950(F, a, b, c, d, e, n, x): return Dist(e**S(2)*n*(n + S(1))/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), Int(F**(c*(a + b*x))*(S(1)/cosh(d + e*x))**(n + S(2)), x), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/cosh(d + e*x))**n*log(F)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) - Simp(F**(c*(a + b*x))*e*n*(S(1)/cosh(d + e*x))**(n + S(1))*sinh(d + e*x)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) def replacement5951(F, a, b, c, d, e, n, x): return -Dist(e**S(2)*n*(n + S(1))/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), Int(F**(c*(a + b*x))*(S(1)/sinh(d + e*x))**(n + S(2)), x), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/sinh(d + e*x))**n*log(F)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) - Simp(F**(c*(a + b*x))*e*n*(S(1)/sinh(d + e*x))**(n + S(1))*cosh(d + e*x)/(-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) def replacement5952(F, a, b, c, d, e, n, x): return Simp(F**(c*(a + b*x))*(S(1)/cosh(d + e*x))**(n + S(-1))*sinh(d + e*x)/(e*(n + S(-1))), x) + Simp(F**(c*(a + b*x))*b*c*(S(1)/cosh(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement5953(F, a, b, c, d, e, n, x): return -Simp(F**(c*(a + b*x))*(S(1)/sinh(d + e*x))**(n + S(-1))*cosh(d + e*x)/(e*(n + S(-1))), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/sinh(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement5954(F, a, b, c, d, e, n, x): return Dist((-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2))/(e**S(2)*(n + S(-2))*(n + S(-1))), Int(F**(c*(a + b*x))*(S(1)/cosh(d + e*x))**(n + S(-2)), x), x) + Simp(F**(c*(a + b*x))*(S(1)/cosh(d + e*x))**(n + S(-1))*sinh(d + e*x)/(e*(n + S(-1))), x) + Simp(F**(c*(a + b*x))*b*c*(S(1)/cosh(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement5955(F, a, b, c, d, e, n, x): return -Dist((-b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2))/(e**S(2)*(n + S(-2))*(n + S(-1))), Int(F**(c*(a + b*x))*(S(1)/sinh(d + e*x))**(n + S(-2)), x), x) - Simp(F**(c*(a + b*x))*(S(1)/sinh(d + e*x))**(n + S(-1))*cosh(d + e*x)/(e*(n + S(-1))), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/sinh(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement5956(F, a, b, c, d, e, n, x): return Simp(S(2)**n*F**(c*(a + b*x))*Hypergeometric2F1(n, b*c*log(F)/(S(2)*e) + n/S(2), b*c*log(F)/(S(2)*e) + n/S(2) + S(1), -exp(S(2)*d + S(2)*e*x))*exp(n*(d + e*x))/(b*c*log(F) + e*n), x) def replacement5957(F, a, b, c, d, e, n, x): return Simp((S(-2))**n*F**(c*(a + b*x))*Hypergeometric2F1(n, b*c*log(F)/(S(2)*e) + n/S(2), b*c*log(F)/(S(2)*e) + n/S(2) + S(1), exp(S(2)*d + S(2)*e*x))*exp(n*(d + e*x))/(b*c*log(F) + e*n), x) def replacement5958(F, a, b, c, d, e, n, x): return Dist((exp(S(2)*d + S(2)*e*x) + S(1))**n*(S(1)/cosh(d + e*x))**n*exp(-n*(d + e*x)), Int(SimplifyIntegrand(F**(c*(a + b*x))*(exp(S(2)*d + S(2)*e*x) + S(1))**(-n)*exp(n*(d + e*x)), x), x), x) def replacement5959(F, a, b, c, d, e, n, x): return Dist((S(1) - exp(-S(2)*d - S(2)*e*x))**n*(S(1)/sinh(d + e*x))**n*exp(n*(d + e*x)), Int(SimplifyIntegrand(F**(c*(a + b*x))*(S(1) - exp(-S(2)*d - S(2)*e*x))**(-n)*exp(-n*(d + e*x)), x), x), x) def replacement5960(F, a, b, c, d, e, f, g, n, x): return Dist(S(2)**n*f**n, Int(F**(c*(a + b*x))*cosh(-Pi*f/(S(4)*g) + d/S(2) + e*x/S(2))**(S(2)*n), x), x) def replacement5961(F, a, b, c, d, e, f, g, n, x): return Dist(S(2)**n*g**n, Int(F**(c*(a + b*x))*cosh(d/S(2) + e*x/S(2))**(S(2)*n), x), x) def replacement5962(F, a, b, c, d, e, f, g, n, x): return Dist(S(2)**n*g**n, Int(F**(c*(a + b*x))*sinh(d/S(2) + e*x/S(2))**(S(2)*n), x), x) def replacement5963(F, a, b, c, d, e, f, g, m, n, x): return Dist(g**n, Int(F**(c*(a + b*x))*tanh(-Pi*f/(S(4)*g) + d/S(2) + e*x/S(2))**m, x), x) def replacement5964(F, a, b, c, d, e, f, g, m, n, x): return Dist(g**n, Int(F**(c*(a + b*x))*tanh(d/S(2) + e*x/S(2))**m, x), x) def replacement5965(F, a, b, c, d, e, f, g, m, n, x): return Dist(g**n, Int(F**(c*(a + b*x))*(S(1)/tanh(d/S(2) + e*x/S(2)))**m, x), x) def replacement5966(F, a, b, c, d, e, f, g, h, i, x): return Dist(S(2)*i, Int(F**(c*(a + b*x))*cosh(d + e*x)/(f + g*sinh(d + e*x)), x), x) + Int(F**(c*(a + b*x))*(h - i*cosh(d + e*x))/(f + g*sinh(d + e*x)), x) def replacement5967(F, a, b, c, d, e, f, g, h, i, x): return Dist(S(2)*i, Int(F**(c*(a + b*x))*sinh(d + e*x)/(f + g*cosh(d + e*x)), x), x) + Int(F**(c*(a + b*x))*(h - i*sinh(d + e*x))/(f + g*cosh(d + e*x)), x) def replacement5968(F, G, c, n, u, v, x): return Int(F**(c*ExpandToSum(u, x))*G(ExpandToSum(v, x))**n, x) def With5969(F, a, b, c, d, e, m, n, x): u = IntHide(F**(c*(a + b*x))*sinh(d + e*x)**n, x) return -Dist(m, Int(u*x**(m + S(-1)), x), x) + Simp(u*x**m, x) def With5970(F, a, b, c, d, e, m, n, x): u = IntHide(F**(c*(a + b*x))*cosh(d + e*x)**n, x) return -Dist(m, Int(u*x**(m + S(-1)), x), x) + Simp(u*x**m, x) def replacement5971(F, a, b, c, d, e, f, g, m, n, x): return Int(ExpandTrigReduce(F**(c*(a + b*x)), sinh(d + e*x)**m*cosh(f + g*x)**n, x), x) def replacement5972(F, a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrigReduce(F**(c*(a + b*x))*x**p, sinh(d + e*x)**m*cosh(f + g*x)**n, x), x) def replacement5973(F, G, H, a, b, c, d, e, m, n, x): return Int(ExpandTrigToExp(F**(c*(a + b*x)), G(d + e*x)**m*H(d + e*x)**n, x), x) def replacement5974(F, n, u, v, x): return Int(ExpandTrigToExp(F**u, sinh(v)**n, x), x) def replacement5975(F, n, u, v, x): return Int(ExpandTrigToExp(F**u, cosh(v)**n, x), x) def replacement5976(F, m, n, u, v, x): return Int(ExpandTrigToExp(F**u, sinh(v)**m*cosh(v)**n, x), x) def replacement5977(b, c, n, p, x): return Int(((c*x**n)**b/S(2) - (c*x**n)**(-b)/S(2))**p, x) def replacement5978(b, c, n, p, x): return Int(((c*x**n)**b/S(2) + (c*x**n)**(-b)/S(2))**p, x) def replacement5979(a, b, c, n, p, x): return -Simp(x*(p + S(2))*sinh(a + b*log(c*x**n))**(p + S(2))/(p + S(1)), x) + Simp(x*sinh(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tanh(a + b*log(c*x**n))), x) def replacement5980(a, b, c, n, p, x): return Simp(x*(p + S(2))*cosh(a + b*log(c*x**n))**(p + S(2))/(p + S(1)), x) - Simp(x*cosh(a + b*log(c*x**n))**(p + S(2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(1))), x) def replacement5981(a, b, c, n, x): return Dist(x*sqrt(sinh(a + b*log(c*x**n)))/sqrt((c*x**n)**(S(4)/n)*exp(S(2)*a) + S(-1)), Int(sqrt((c*x**n)**(S(4)/n)*exp(S(2)*a) + S(-1))/x, x), x) def replacement5982(a, b, c, n, x): return Dist(x*sqrt(cosh(a + b*log(c*x**n)))/sqrt((c*x**n)**(S(4)/n)*exp(S(2)*a) + S(1)), Int(sqrt((c*x**n)**(S(4)/n)*exp(S(2)*a) + S(1))/x, x), x) def replacement5983(a, b, c, n, p, x): return Int(ExpandIntegrand(((c*x**n)**(S(1)/(n*p))*exp(a*b*n*p)/(S(2)*b*n*p) - (c*x**n)**(-S(1)/(n*p))*exp(-a*b*n*p)/(S(2)*b*n*p))**p, x), x) def replacement5984(a, b, c, n, p, x): return Int(ExpandIntegrand(((c*x**n)**(S(1)/(n*p))*exp(a*b*n*p)/S(2) + (c*x**n)**(-S(1)/(n*p))*exp(-a*b*n*p)/S(2))**p, x), x) def replacement5985(a, b, c, n, x): return -Simp(x*sinh(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(-1)), x) + Simp(b*n*x*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(-1)), x) def replacement5986(a, b, c, n, x): return -Simp(x*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(-1)), x) + Simp(b*n*x*sinh(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(-1)), x) def replacement5987(a, b, c, n, p, x): return -Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), Int(sinh(a + b*log(c*x**n))**(p + S(-2)), x), x) - Simp(x*sinh(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) + Simp(b*n*p*x*sinh(a + b*log(c*x**n))**(p + S(-1))*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) def replacement5988(a, b, c, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), Int(cosh(a + b*log(c*x**n))**(p + S(-2)), x), x) - Simp(x*cosh(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) + Simp(b*n*p*x*sinh(a + b*log(c*x**n))*cosh(a + b*log(c*x**n))**(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) def replacement5989(a, b, c, n, p, x): return -Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) + S(-1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(sinh(a + b*log(c*x**n))**(p + S(2)), x), x) - Simp(x*sinh(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) + Simp(x*sinh(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tanh(a + b*log(c*x**n))), x) def replacement5990(a, b, c, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) + S(-1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(cosh(a + b*log(c*x**n))**(p + S(2)), x), x) + Simp(x*cosh(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) - Simp(x*cosh(a + b*log(c*x**n))**(p + S(2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(1))), x) def replacement5991(a, b, c, n, p, x): return Simp(x*(S(2) - S(2)*(c*x**n)**(-S(2)*b)*exp(-S(2)*a))**(-p)*((c*x**n)**b*exp(a) - (c*x**n)**(-b)*exp(-a))**p*Hypergeometric2F1(-p, -(b*n*p + S(1))/(S(2)*b*n), S(1) - (b*n*p + S(1))/(S(2)*b*n), (c*x**n)**(-S(2)*b)*exp(-S(2)*a))/(b*n*p + S(1)), x) def replacement5992(a, b, c, n, p, x): return Simp(x*(S(2) + S(2)*(c*x**n)**(-S(2)*b)*exp(-S(2)*a))**(-p)*((c*x**n)**b*exp(a) + (c*x**n)**(-b)*exp(-a))**p*Hypergeometric2F1(-p, -(b*n*p + S(1))/(S(2)*b*n), S(1) - (b*n*p + S(1))/(S(2)*b*n), -(c*x**n)**(-S(2)*b)*exp(-S(2)*a))/(b*n*p + S(1)), x) def replacement5993(a, b, c, m, n, p, x): return -Simp(x**(m + S(1))*(p + S(2))*sinh(a + b*log(c*x**n))**(p + S(2))/((m + S(1))*(p + S(1))), x) + Simp(x**(m + S(1))*sinh(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tanh(a + b*log(c*x**n))), x) def replacement5994(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(p + S(2))*cosh(a + b*log(c*x**n))**(p + S(2))/((m + S(1))*(p + S(1))), x) - Simp(x**(m + S(1))*cosh(a + b*log(c*x**n))**(p + S(2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(1))), x) def replacement5995(a, b, c, m, n, p, x): return Dist(S(2)**(-p), Int(ExpandIntegrand(x**m*((c*x**n)**((m + S(1))/(n*p))*(m + S(1))*exp(a*b*n*p/(m + S(1)))/(b*n*p) - (c*x**n)**(-(m + S(1))/(n*p))*(m + S(1))*exp(-a*b*n*p/(m + S(1)))/(b*n*p))**p, x), x), x) def replacement5996(a, b, c, m, n, p, x): return Dist(S(2)**(-p), Int(ExpandIntegrand(x**m*((c*x**n)**((m + S(1))/(n*p))*exp(a*b*n*p/(m + S(1))) + (c*x**n)**(-(m + S(1))/(n*p))*exp(-a*b*n*p/(m + S(1))))**p, x), x), x) def replacement5997(a, b, c, m, n, x): return -Simp(x**(m + S(1))*(m + S(1))*sinh(a + b*log(c*x**n))/(b**S(2)*n**S(2) - (m + S(1))**S(2)), x) + Simp(b*n*x**(m + S(1))*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2) - (m + S(1))**S(2)), x) def replacement5998(a, b, c, m, n, x): return -Simp(x**(m + S(1))*(m + S(1))*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2) - (m + S(1))**S(2)), x) + Simp(b*n*x**(m + S(1))*sinh(a + b*log(c*x**n))/(b**S(2)*n**S(2) - (m + S(1))**S(2)), x) def replacement5999(a, b, c, m, n, p, x): return -Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), Int(x**m*sinh(a + b*log(c*x**n))**(p + S(-2)), x), x) - Simp(x**(m + S(1))*(m + S(1))*sinh(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) + Simp(b*n*p*x**(m + S(1))*sinh(a + b*log(c*x**n))**(p + S(-1))*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) def replacement6000(a, b, c, m, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), Int(x**m*cosh(a + b*log(c*x**n))**(p + S(-2)), x), x) - Simp(x**(m + S(1))*(m + S(1))*cosh(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) + Simp(b*n*p*x**(m + S(1))*sinh(a + b*log(c*x**n))*cosh(a + b*log(c*x**n))**(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) def replacement6001(a, b, c, m, n, p, x): return -Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) - (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**m*sinh(a + b*log(c*x**n))**(p + S(2)), x), x) + Simp(x**(m + S(1))*sinh(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tanh(a + b*log(c*x**n))), x) - Simp(x**(m + S(1))*(m + S(1))*sinh(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement6002(a, b, c, m, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) - (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**m*cosh(a + b*log(c*x**n))**(p + S(2)), x), x) - Simp(x**(m + S(1))*cosh(a + b*log(c*x**n))**(p + S(2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(1))), x) + Simp(x**(m + S(1))*(m + S(1))*cosh(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement6003(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(S(2) - S(2)*(c*x**n)**(-S(2)*b)*exp(-S(2)*a))**(-p)*((c*x**n)**b*exp(a) - (c*x**n)**(-b)*exp(-a))**p*Hypergeometric2F1(-p, -(b*n*p + m + S(1))/(S(2)*b*n), S(1) - (b*n*p + m + S(1))/(S(2)*b*n), (c*x**n)**(-S(2)*b)*exp(-S(2)*a))/(b*n*p + m + S(1)), x) def replacement6004(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(S(2) + S(2)*(c*x**n)**(-S(2)*b)*exp(-S(2)*a))**(-p)*((c*x**n)**b*exp(a) + (c*x**n)**(-b)*exp(-a))**p*Hypergeometric2F1(-p, -(b*n*p + m + S(1))/(S(2)*b*n), S(1) - (b*n*p + m + S(1))/(S(2)*b*n), -(c*x**n)**(-S(2)*b)*exp(-S(2)*a))/(b*n*p + m + S(1)), x) def replacement6005(b, c, n, p, x): return Dist(S(2)**p, Int(((c*x**n)**b/((c*x**n)**(S(2)*b) + S(1)))**p, x), x) def replacement6006(b, c, n, p, x): return Dist(S(2)**p, Int(((c*x**n)**b/((c*x**n)**(S(2)*b) + S(-1)))**p, x), x) def replacement6007(a, b, c, n, x): return Dist(S(2)*exp(-a*b*n), Int((c*x**n)**(S(1)/n)/((c*x**n)**(S(2)/n) + exp(-S(2)*a*b*n)), x), x) def replacement6008(a, b, c, n, x): return Dist(-S(2)*b*n*exp(-a*b*n), Int((c*x**n)**(S(1)/n)/(-(c*x**n)**(S(2)/n) + exp(-S(2)*a*b*n)), x), x) def replacement6009(a, b, c, n, p, x): return Simp(x*(p + S(-2))*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))/(p + S(-1)), x) + Simp(x*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) def replacement6010(a, b, c, n, p, x): return -Simp(x*(p + S(-2))*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/(p + S(-1)), x) - Simp(x*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tanh(a + b*log(c*x**n))), x) def replacement6011(a, b, c, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(-1))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int((S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2)), x), x) + Simp(x*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) + Simp(x*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) def replacement6012(a, b, c, n, p, x): return -Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(-1))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int((S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2)), x), x) - Simp(x*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) - Simp(x*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tanh(a + b*log(c*x**n))), x) def replacement6013(a, b, c, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), Int((S(1)/cosh(a + b*log(c*x**n)))**(p + S(2)), x), x) - Simp(x*(S(1)/cosh(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) - Simp(b*n*p*x*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(1))*sinh(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) def replacement6014(a, b, c, n, p, x): return -Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), Int((S(1)/sinh(a + b*log(c*x**n)))**(p + S(2)), x), x) - Simp(x*(S(1)/sinh(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) - Simp(b*n*p*x*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(1))*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + S(-1)), x) def replacement6015(a, b, c, n, p, x): return Simp(S(2)**p*x*((c*x**n)**b*exp(a)/((c*x**n)**(S(2)*b)*exp(S(2)*a) + S(1)))**p*((c*x**n)**(S(2)*b)*exp(S(2)*a) + S(1))**p*Hypergeometric2F1(p, (b*n*p + S(1))/(S(2)*b*n), S(1) + (b*n*p + S(1))/(S(2)*b*n), -(c*x**n)**(S(2)*b)*exp(S(2)*a))/(b*n*p + S(1)), x) def replacement6016(a, b, c, n, p, x): return Simp(x*((c*x**n)**b*exp(a)/((c*x**n)**(S(2)*b)*exp(S(2)*a) + S(-1)))**p*(-S(2)*(c*x**n)**(S(2)*b)*exp(S(2)*a) + S(2))**p*Hypergeometric2F1(p, (b*n*p + S(1))/(S(2)*b*n), S(1) + (b*n*p + S(1))/(S(2)*b*n), (c*x**n)**(S(2)*b)*exp(S(2)*a))/(b*n*p + S(1)), x) def replacement6017(b, c, m, n, p, x): return Dist(S(2)**p, Int(x**m*((c*x**n)**b/((c*x**n)**(S(2)*b) + S(1)))**p, x), x) def replacement6018(b, c, m, n, p, x): return Dist(S(2)**p, Int(x**m*((c*x**n)**b/((c*x**n)**(S(2)*b) + S(-1)))**p, x), x) def replacement6019(a, b, c, m, n, x): return Dist(S(2)*exp(-a*b*n/(m + S(1))), Int(x**m*(c*x**n)**((m + S(1))/n)/((c*x**n)**(S(2)*(m + S(1))/n) + exp(-S(2)*a*b*n/(m + S(1)))), x), x) def replacement6020(a, b, c, m, n, x): return Dist(-S(2)*b*n*exp(-a*b*n/(m + S(1)))/(m + S(1)), Int(x**m*(c*x**n)**((m + S(1))/n)/(-(c*x**n)**(S(2)*(m + S(1))/n) + exp(-S(2)*a*b*n/(m + S(1)))), x), x) def replacement6021(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(p + S(-2))*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))/((m + S(1))*(p + S(-1))), x) + Simp(x**(m + S(1))*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) def replacement6022(a, b, c, m, n, p, x): return -Simp(x**(m + S(1))*(p + S(-2))*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/((m + S(1))*(p + S(-1))), x) - Simp(x**(m + S(1))*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tanh(a + b*log(c*x**n))), x) def replacement6023(a, b, c, m, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) - (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int(x**m*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2)), x), x) + Simp(x**(m + S(1))*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))*tanh(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) + Simp(x**(m + S(1))*(m + S(1))*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) def replacement6024(a, b, c, m, n, p, x): return -Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) - (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int(x**m*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2)), x), x) - Simp(x**(m + S(1))*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tanh(a + b*log(c*x**n))), x) - Simp(x**(m + S(1))*(m + S(1))*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) def replacement6025(a, b, c, m, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), Int(x**m*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(2)), x), x) - Simp(x**(m + S(1))*(m + S(1))*(S(1)/cosh(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) - Simp(b*n*p*x**(m + S(1))*(S(1)/cosh(a + b*log(c*x**n)))**(p + S(1))*sinh(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) def replacement6026(a, b, c, m, n, p, x): return -Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), Int(x**m*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(2)), x), x) - Simp(x**(m + S(1))*(m + S(1))*(S(1)/sinh(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) - Simp(b*n*p*x**(m + S(1))*(S(1)/sinh(a + b*log(c*x**n)))**(p + S(1))*cosh(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) - (m + S(1))**S(2)), x) def replacement6027(a, b, c, m, n, p, x): return Simp(S(2)**p*x**(m + S(1))*((c*x**n)**b*exp(a)/((c*x**n)**(S(2)*b)*exp(S(2)*a) + S(1)))**p*((c*x**n)**(S(2)*b)*exp(S(2)*a) + S(1))**p*Hypergeometric2F1(p, (b*n*p + m + S(1))/(S(2)*b*n), S(1) + (b*n*p + m + S(1))/(S(2)*b*n), -(c*x**n)**(S(2)*b)*exp(S(2)*a))/(b*n*p + m + S(1)), x) def replacement6028(a, b, c, m, n, p, x): return Simp(S(2)**p*x**(m + S(1))*((c*x**n)**b*exp(a)/((c*x**n)**(S(2)*b)*exp(S(2)*a) + S(-1)))**p*(-(c*x**n)**(S(2)*b)*exp(S(2)*a) + S(1))**p*Hypergeometric2F1(p, (b*n*p + m + S(1))/(S(2)*b*n), S(1) + (b*n*p + m + S(1))/(S(2)*b*n), (c*x**n)**(S(2)*b)*exp(S(2)*a))/(b*n*p + m + S(1)), x) def replacement6029(a, b, p, x): return -Dist(p, Int(log(b*x)**(p + S(-1))*sinh(a*x*log(b*x)**p), x), x) + Simp(cosh(a*x*log(b*x)**p)/a, x) def replacement6030(a, b, p, x): return -Dist(p, Int(log(b*x)**(p + S(-1))*cosh(a*x*log(b*x)**p), x), x) + Simp(sinh(a*x*log(b*x)**p)/a, x) def replacement6031(a, b, n, p, x): return -Dist(p/n, Int(log(b*x)**(p + S(-1))*sinh(a*x**n*log(b*x)**p), x), x) + Dist((n + S(-1))/(a*n), Int(x**(-n)*cosh(a*x**n*log(b*x)**p), x), x) + Simp(x**(S(1) - n)*cosh(a*x**n*log(b*x)**p)/(a*n), x) def replacement6032(a, b, n, p, x): return -Dist(p/n, Int(log(b*x)**(p + S(-1))*cosh(a*x**n*log(b*x)**p), x), x) + Dist((n + S(-1))/(a*n), Int(x**(-n)*sinh(a*x**n*log(b*x)**p), x), x) + Simp(x**(S(1) - n)*sinh(a*x**n*log(b*x)**p)/(a*n), x) def replacement6033(a, b, m, n, p, x): return -Dist(p/n, Int(x**(n + S(-1))*log(b*x)**(p + S(-1))*sinh(a*x**n*log(b*x)**p), x), x) - Simp(cosh(a*x**n*log(b*x)**p)/(a*n), x) def replacement6034(a, b, m, n, p, x): return -Dist(p/n, Int(x**(n + S(-1))*log(b*x)**(p + S(-1))*cosh(a*x**n*log(b*x)**p), x), x) + Simp(sinh(a*x**n*log(b*x)**p)/(a*n), x) def replacement6035(a, b, m, n, p, x): return -Dist(p/n, Int(x**m*log(b*x)**(p + S(-1))*sinh(a*x**n*log(b*x)**p), x), x) - Dist((m - n + S(1))/(a*n), Int(x**(m - n)*cosh(a*x**n*log(b*x)**p), x), x) + Simp(x**(m - n + S(1))*cosh(a*x**n*log(b*x)**p)/(a*n), x) def replacement6036(a, b, m, n, p, x): return -Dist(p/n, Int(x**m*log(b*x)**(p + S(-1))*cosh(a*x**n*log(b*x)**p), x), x) - Dist((m - n + S(1))/(a*n), Int(x**(m - n)*sinh(a*x**n*log(b*x)**p), x), x) + Simp(x**(m - n + S(1))*sinh(a*x**n*log(b*x)**p)/(a*n), x) def replacement6037(a, c, d, n, x): return -Dist(S(1)/d, Subst(Int(sinh(a*x)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def replacement6038(a, c, d, n, x): return -Dist(S(1)/d, Subst(Int(cosh(a*x)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def replacement6039(a, b, c, d, e, n, x): return -Dist(S(1)/d, Subst(Int(sinh(b*e/d - e*x*(-a*d + b*c)/d)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def replacement6040(a, b, c, d, e, n, x): return -Dist(S(1)/d, Subst(Int(cosh(b*e/d - e*x*(-a*d + b*c)/d)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def With6041(n, u, x): lst = QuotientOfLinearsParts(u, x) return Int(sinh((x*Part(lst, S(2)) + Part(lst, S(1)))/(x*Part(lst, S(4)) + Part(lst, S(3))))**n, x) def With6042(n, u, x): lst = QuotientOfLinearsParts(u, x) return Int(cosh((x*Part(lst, S(2)) + Part(lst, S(1)))/(x*Part(lst, S(4)) + Part(lst, S(3))))**n, x) def replacement6043(p, q, u, v, w, x): return Int(u*sinh(v)**(p + q), x) def replacement6044(p, q, u, v, w, x): return Int(u*cosh(v)**(p + q), x) def replacement6045(p, q, v, w, x): return Int(ExpandTrigReduce(sinh(v)**p*sinh(w)**q, x), x) def replacement6046(p, q, v, w, x): return Int(ExpandTrigReduce(cosh(v)**p*cosh(w)**q, x), x) def replacement6047(m, p, q, v, w, x): return Int(ExpandTrigReduce(x**m, sinh(v)**p*sinh(w)**q, x), x) def replacement6048(m, p, q, v, w, x): return Int(ExpandTrigReduce(x**m, cosh(v)**p*cosh(w)**q, x), x) def replacement6049(p, u, v, w, x): return Dist(S(2)**(-p), Int(u*sinh(S(2)*v)**p, x), x) def replacement6050(p, q, v, w, x): return Int(ExpandTrigReduce(sinh(v)**p*cosh(w)**q, x), x) def replacement6051(m, p, q, v, w, x): return Int(ExpandTrigReduce(x**m, sinh(v)**p*cosh(w)**q, x), x) def replacement6052(n, v, w, x): return -Dist(cosh(v - w), Int(tanh(w)**(n + S(-1))/cosh(w), x), x) + Int(cosh(v)*tanh(w)**(n + S(-1)), x) def replacement6053(n, v, w, x): return Dist(cosh(v - w), Int((S(1)/tanh(w))**(n + S(-1))/sinh(w), x), x) + Int((S(1)/tanh(w))**(n + S(-1))*sinh(v), x) def replacement6054(n, v, w, x): return Dist(sinh(v - w), Int((S(1)/tanh(w))**(n + S(-1))/sinh(w), x), x) + Int((S(1)/tanh(w))**(n + S(-1))*cosh(v), x) def replacement6055(n, v, w, x): return -Dist(sinh(v - w), Int(tanh(w)**(n + S(-1))/cosh(w), x), x) + Int(sinh(v)*tanh(w)**(n + S(-1)), x) def replacement6056(n, v, w, x): return Dist(sinh(v - w), Int((S(1)/cosh(w))**(n + S(-1)), x), x) + Dist(cosh(v - w), Int((S(1)/cosh(w))**(n + S(-1))*tanh(w), x), x) def replacement6057(n, v, w, x): return Dist(sinh(v - w), Int((S(1)/sinh(w))**(n + S(-1)), x), x) + Dist(cosh(v - w), Int((S(1)/sinh(w))**(n + S(-1))/tanh(w), x), x) def replacement6058(n, v, w, x): return Dist(sinh(v - w), Int((S(1)/sinh(w))**(n + S(-1))/tanh(w), x), x) + Dist(cosh(v - w), Int((S(1)/sinh(w))**(n + S(-1)), x), x) def replacement6059(n, v, w, x): return Dist(sinh(v - w), Int((S(1)/cosh(w))**(n + S(-1))*tanh(w), x), x) + Dist(cosh(v - w), Int((S(1)/cosh(w))**(n + S(-1)), x), x) def replacement6060(a, b, c, d, e, f, m, n, x): return Int((a + b*sinh(S(2)*c + S(2)*d*x)/S(2))**n*(e + f*x)**m, x) def replacement6061(a, b, c, d, m, n, x): return Dist(S(2)**(-n), Int(x**m*(S(2)*a + b*cosh(S(2)*c + S(2)*d*x) - b)**n, x), x) def replacement6062(a, b, c, d, m, n, x): return Dist(S(2)**(-n), Int(x**m*(S(2)*a + b*cosh(S(2)*c + S(2)*d*x) + b)**n, x), x) def replacement6063(a, b, c, d, e, f, m, n, p, x): return Dist(d**(-m + S(-1)), Subst(Int((-c*f + d*e + f*x)**m*sinh(a + b*x**n)**p, x), x, c + d*x), x) def replacement6064(a, b, c, d, e, f, m, n, p, x): return Dist(d**(-m + S(-1)), Subst(Int((-c*f + d*e + f*x)**m*cosh(a + b*x**n)**p, x), x, c + d*x), x) def replacement6065(a, b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(S(2)*a + b - c + (b + c)*cosh(S(2)*d + S(2)*e*x)), x), x) def replacement6066(b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(b - c + (b + c)*cosh(S(2)*d + S(2)*e*x)), x), x) def replacement6067(a, b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(S(2)*a + b - c + (b + c)*cosh(S(2)*d + S(2)*e*x)), x), x) def replacement6068(b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(b - c + (b + c)*cosh(S(2)*d + S(2)*e*x)), x), x) def replacement6069(a, b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(S(2)*a + b - c + (b + c)*cosh(S(2)*d + S(2)*e*x)), x), x) def replacement6070(a, b, c, d, e, f, m, x): return Int((e + f*x)**m*exp(c + d*x)/(a + b*exp(c + d*x) - Rt(a**S(2) + b**S(2), S(2))), x) + Int((e + f*x)**m*exp(c + d*x)/(a + b*exp(c + d*x) + Rt(a**S(2) + b**S(2), S(2))), x) - Simp((e + f*x)**(m + S(1))/(b*f*(m + S(1))), x) def replacement6071(a, b, c, d, e, f, m, x): return Int((e + f*x)**m*exp(c + d*x)/(a + b*exp(c + d*x) - Rt(a**S(2) - b**S(2), S(2))), x) + Int((e + f*x)**m*exp(c + d*x)/(a + b*exp(c + d*x) + Rt(a**S(2) - b**S(2), S(2))), x) - Simp((e + f*x)**(m + S(1))/(b*f*(m + S(1))), x) def replacement6072(a, b, c, d, e, f, m, n, x): return Dist(S(1)/a, Int((e + f*x)**m*cosh(c + d*x)**(n + S(-2)), x), x) + Dist(S(1)/b, Int((e + f*x)**m*sinh(c + d*x)*cosh(c + d*x)**(n + S(-2)), x), x) def replacement6073(a, b, c, d, e, f, m, n, x): return Dist(S(1)/a, Int((e + f*x)**m*sinh(c + d*x)**(n + S(-2)), x), x) + Dist(S(1)/b, Int((e + f*x)**m*sinh(c + d*x)**(n + S(-2))*cosh(c + d*x), x), x) def replacement6074(a, b, c, d, e, f, m, n, x): return Dist(S(1)/b, Int((e + f*x)**m*sinh(c + d*x)*cosh(c + d*x)**(n + S(-2)), x), x) - Dist(a/b**S(2), Int((e + f*x)**m*cosh(c + d*x)**(n + S(-2)), x), x) + Dist((a**S(2) + b**S(2))/b**S(2), Int((e + f*x)**m*cosh(c + d*x)**(n + S(-2))/(a + b*sinh(c + d*x)), x), x) def replacement6075(a, b, c, d, e, f, m, n, x): return Dist(S(1)/b, Int((e + f*x)**m*sinh(c + d*x)**(n + S(-2))*cosh(c + d*x), x), x) - Dist(a/b**S(2), Int((e + f*x)**m*sinh(c + d*x)**(n + S(-2)), x), x) + Dist((a**S(2) - b**S(2))/b**S(2), Int((e + f*x)**m*sinh(c + d*x)**(n + S(-2))/(a + b*cosh(c + d*x)), x), x) def replacement6076(A, B, a, b, c, d, e, f, x): return -Dist(B*f/(a*d), Int(cosh(c + d*x)/(a + b*sinh(c + d*x)), x), x) + Simp(B*(e + f*x)*cosh(c + d*x)/(a*d*(a + b*sinh(c + d*x))), x) def replacement6077(A, B, a, b, c, d, e, f, x): return -Dist(B*f/(a*d), Int(sinh(c + d*x)/(a + b*cosh(c + d*x)), x), x) + Simp(B*(e + f*x)*sinh(c + d*x)/(a*d*(a + b*cosh(c + d*x))), x) def replacement6078(a, b, m, n, v, x): return Int((a*cosh(v) + b*sinh(v))**n, x) def replacement6079(a, b, m, n, v, x): return Int((a*sinh(v) + b*cosh(v))**n, x) def replacement6080(a, b, c, d, m, n, u, x): return Int(ExpandTrigReduce(u, sinh(a + b*x)**m*sinh(c + d*x)**n, x), x) def replacement6081(a, b, c, d, m, n, u, x): return Int(ExpandTrigReduce(u, cosh(a + b*x)**m*cosh(c + d*x)**n, x), x) def replacement6082(a, b, c, d, x): return Dist(S(1)/sinh((-a*d + b*c)/b), Int(tanh(c + d*x), x), x) - Dist(S(1)/sinh((-a*d + b*c)/d), Int(tanh(a + b*x), x), x) def replacement6083(a, b, c, d, x): return Dist(S(1)/sinh((-a*d + b*c)/b), Int(S(1)/tanh(a + b*x), x), x) - Dist(S(1)/sinh((-a*d + b*c)/d), Int(S(1)/tanh(c + d*x), x), x) def replacement6084(a, b, c, d, x): return -Dist(b*cosh((-a*d + b*c)/d)/d, Int(S(1)/(cosh(a + b*x)*cosh(c + d*x)), x), x) + Simp(b*x/d, x) def replacement6085(a, b, c, d, x): return Dist(cosh((-a*d + b*c)/d), Int(S(1)/(sinh(a + b*x)*sinh(c + d*x)), x), x) + Simp(b*x/d, x) def replacement6086(a, b, n, u, v, x): return Int(u*(a*exp(a*v/b))**n, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/integrand_simplification.py000066400000000000000000000552151412543434000266160ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def integrand_simplification(): from sympy.integrals.rubi.constraints import cons1, cons2, cons3, cons4, cons5, cons6, cons7, cons8, cons9, cons10, cons11, cons12, cons13, cons14, cons15, cons16, cons17, cons18, cons19, cons20, cons21, cons22, cons23, cons24, cons25, cons26, cons27, cons28, cons29, cons30, cons31, cons32, cons33, cons34, cons35, cons36, cons37, cons38, cons39, cons40, cons41, cons42, cons43, cons44, cons45, cons46, cons47, cons48, cons49, cons50, cons51, cons52, cons53, cons54, cons55, cons56, cons57, cons58, cons59, cons60, cons61, cons62, cons63, cons64, cons65, cons66, cons67 pattern1 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons4, cons5, cons1) rule1 = ReplacementRule(pattern1, replacement1) pattern2 = Pattern(Integral((x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons4, cons5, cons6) rule2 = ReplacementRule(pattern2, replacement2) pattern3 = Pattern(Integral((a_ + x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons7, cons1) rule3 = ReplacementRule(pattern3, replacement3) pattern4 = Pattern(Integral((x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons7, cons6) rule4 = ReplacementRule(pattern4, replacement4) pattern5 = Pattern(Integral((x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons7, cons9) rule5 = ReplacementRule(pattern5, replacement5) pattern6 = Pattern(Integral((v_*WC('a', S(1)) + v_*WC('b', S(1)) + WC('w', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons10) rule6 = ReplacementRule(pattern6, replacement6) pattern7 = Pattern(Integral(Pm_**p_*WC('u', S(1)), x_), cons11, cons12, cons13) rule7 = ReplacementRule(pattern7, replacement7) pattern8 = Pattern(Integral(a_, x_), cons2, cons2) rule8 = ReplacementRule(pattern8, replacement8) pattern9 = Pattern(Integral(a_*(b_ + x_*WC('c', S(1))), x_), cons2, cons3, cons8, cons14) rule9 = ReplacementRule(pattern9, replacement9) pattern10 = Pattern(Integral(-u_, x_)) rule10 = ReplacementRule(pattern10, replacement10) pattern11 = Pattern(Integral(u_*Complex(S(0), a_), x_), cons2, cons15) rule11 = ReplacementRule(pattern11, replacement11) pattern12 = Pattern(Integral(a_*u_, x_), cons2, cons16) rule12 = ReplacementRule(pattern12, replacement12) pattern13 = Pattern(Integral(u_, x_), cons17) rule13 = ReplacementRule(pattern13, replacement13) pattern14 = Pattern(Integral(u_*(x_*WC('c', S(1)))**WC('m', S(1)), x_), cons8, cons19, cons17, cons18) rule14 = ReplacementRule(pattern14, replacement14) pattern15 = Pattern(Integral(v_**WC('m', S(1))*(b_*v_)**n_*WC('u', S(1)), x_), cons3, cons4, cons20) rule15 = ReplacementRule(pattern15, replacement15) pattern16 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons2, cons3, cons19, cons21, cons22, cons23) rule16 = ReplacementRule(pattern16, replacement16) pattern17 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons2, cons3, cons19, cons21, cons24, cons23) rule17 = ReplacementRule(pattern17, replacement17) pattern18 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons2, cons3, cons19, cons4, cons21, cons25, cons23) rule18 = ReplacementRule(pattern18, replacement18) pattern19 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_*WC('b', S(1)))**n_*WC('u', S(1)), x_), cons2, cons3, cons19, cons4, cons21, cons25, cons26) rule19 = ReplacementRule(pattern19, replacement19) pattern20 = Pattern(Integral((a_ + v_*WC('b', S(1)))**WC('m', S(1))*(c_ + v_*WC('d', S(1)))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons27, cons20, cons28) rule20 = ReplacementRule(pattern20, replacement20) pattern21 = Pattern(Integral((a_ + v_*WC('b', S(1)))**m_*(c_ + v_*WC('d', S(1)))**n_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons27, cons30, cons31) rule21 = ReplacementRule(pattern21, replacement21) pattern22 = Pattern(Integral((a_ + v_*WC('b', S(1)))**m_*(c_ + v_*WC('d', S(1)))**n_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons27, cons32) rule22 = ReplacementRule(pattern22, replacement22) pattern23 = Pattern(Integral((v_*WC('a', S(1)))**m_*(v_**S(2)*WC('c', S(1)) + v_*WC('b', S(1)))*WC('u', S(1)), x_), cons2, cons3, cons8, cons33, cons34) rule23 = ReplacementRule(pattern23, replacement23) pattern24 = Pattern(Integral((a_ + v_*WC('b', S(1)))**m_*(v_**S(2)*WC('C', S(1)) + v_*WC('B', S(1)) + WC('A', S(0)))*WC('u', S(1)), x_), cons2, cons3, cons36, cons37, cons38, cons35, cons33, cons34) rule24 = ReplacementRule(pattern24, replacement24) pattern25 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('m', S(1))*(c_ + x_**WC('q', S(1))*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons39, cons40, cons41, cons42) rule25 = ReplacementRule(pattern25, replacement25) pattern26 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('m', S(1))*(c_ + x_**j_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons7, cons43, cons44, cons45, cons46) rule26 = ReplacementRule(pattern26, replacement26) pattern27 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons47, cons40) rule27 = ReplacementRule(pattern27, replacement27) pattern28 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons48, cons47, cons40) rule28 = ReplacementRule(pattern28, replacement28) pattern29 = Pattern(Integral((d_ + x_*WC('e', S(1)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons49) rule29 = ReplacementRule(pattern29, replacement29) pattern30 = Pattern(Integral((x_**WC('p', S(1))*WC('a', S(1)) + x_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1))*WC('u', S(1)), x_), cons2, cons3, cons5, cons52, cons20, cons51) rule30 = ReplacementRule(pattern30, replacement30) pattern31 = Pattern(Integral((x_**WC('p', S(1))*WC('a', S(1)) + x_**WC('q', S(1))*WC('b', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**WC('m', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons5, cons52, cons54, cons20, cons51, cons53) rule31 = ReplacementRule(pattern31, replacement31) pattern32 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons19, cons4, cons55) rule32 = ReplacementRule(pattern32, replacement32) pattern33 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons5, cons55, cons56) rule33 = ReplacementRule(pattern33, replacement33) pattern34 = Pattern(Integral(x_**WC('m', S(1))*(a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**p_*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**p_, x_), cons59, cons60, cons61, cons62, cons19, cons4, cons5, cons57, cons58, cons56) rule34 = ReplacementRule(pattern34, replacement34) pattern35 = Pattern(Integral(Qm_*(Pm_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons4, cons5, cons11, cons63, CustomConstraint(With35)) rule35 = ReplacementRule(pattern35, replacement35) pattern36 = Pattern(Integral(Qm_*(Pm_**WC('n', S(1))*WC('b', S(1)) + Pm_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons48, cons11, cons63, CustomConstraint(With36)) rule36 = ReplacementRule(pattern36, replacement36) pattern37 = Pattern(Integral(Pq_**m_*Qr_**p_*WC('u', S(1)), x_), cons64, cons65, cons66, cons67, CustomConstraint(With37)) rule37 = ReplacementRule(pattern37, replacement37) pattern38 = Pattern(Integral(Pq_*Qr_**p_*WC('u', S(1)), x_), cons65, cons66, cons67, CustomConstraint(With38)) rule38 = ReplacementRule(pattern38, replacement38) return [rule1, rule2, rule3, rule4, rule5, rule6, rule7, rule8, rule9, rule10, rule11, rule12, rule13, rule14, rule15, rule16, rule17, rule18, rule19, rule20, rule21, rule22, rule23, rule24, rule25, rule26, rule27, rule28, rule29, rule30, rule31, rule32, rule33, rule34, rule35, rule36, rule37, rule38, ] def replacement1(a, b, n, p, u, x): return Int(u*(b*x**n)**p, x) def replacement2(a, b, n, p, u, x): return Int(a**p*u, x) def replacement3(a, b, c, j, n, p, u, x): return Int(u*(b*x**n + c*x**(S(2)*n))**p, x) def replacement4(a, b, c, j, n, p, u, x): return Int(u*(a + c*x**(S(2)*n))**p, x) def replacement5(a, b, c, j, n, p, u, x): return Int(u*(a + b*x**n)**p, x) def replacement6(a, b, p, u, v, w, x): return Int(u*(v*(a + b) + w)**p, x) def replacement7(Pm, p, u, x): return Int(Pm**p*u, x) def replacement8(a, x): return Simp(a*x, x) def replacement9(a, b, c, x): return Simp(a*(b + c*x)**S(2)/(S(2)*c), x) def replacement10(u, x): return Dist(S(-1), Int(u, x), x) def replacement11(a, u, x): return Dist(Complex(S(0), a), Int(u, x), x) def replacement12(a, u, x): return Dist(a, Int(u, x), x) def replacement13(u, x): return Simp(IntSum(u, x), x) def replacement14(c, m, u, x): return Int(ExpandIntegrand(u*(c*x)**m, x), x) def replacement15(b, m, n, u, v, x): return Dist(b**(-m), Int(u*(b*v)**(m + n), x), x) def replacement16(a, b, m, n, u, v, x): return Dist(a**(m + S(1)/2)*b**(n + S(-1)/2)*sqrt(b*v)/sqrt(a*v), Int(u*v**(m + n), x), x) def replacement17(a, b, m, n, u, v, x): return Dist(a**(m + S(-1)/2)*b**(n + S(1)/2)*sqrt(a*v)/sqrt(b*v), Int(u*v**(m + n), x), x) def replacement18(a, b, m, n, u, v, x): return Dist(a**(m + n)*(a*v)**(-n)*(b*v)**n, Int(u*v**(m + n), x), x) def replacement19(a, b, m, n, u, v, x): return Dist(a**(-IntPart(n))*b**IntPart(n)*(a*v)**(-FracPart(n))*(b*v)**FracPart(n), Int(u*(a*v)**(m + n), x), x) def replacement20(a, b, c, d, m, n, u, v, x): return Dist((b/d)**m, Int(u*(c + d*v)**(m + n), x), x) def replacement21(a, b, c, d, m, n, u, v, x): return Dist((b/d)**m, Int(u*(c + d*v)**(m + n), x), x) def replacement22(a, b, c, d, m, n, u, v, x): return Dist((a + b*v)**m*(c + d*v)**(-m), Int(u*(c + d*v)**(m + n), x), x) def replacement23(a, b, c, m, u, v, x): return Dist(S(1)/a, Int(u*(a*v)**(m + S(1))*(b + c*v), x), x) def replacement24(A, B, C, a, b, m, u, v, x): return Dist(b**(S(-2)), Int(u*(a + b*v)**(m + S(1))*Simp(B*b - C*a + C*b*v, x), x), x) def replacement25(a, b, c, d, m, n, p, q, u, x): return Dist((d/a)**p, Int(u*x**(-n*p)*(a + b*x**n)**(m + p), x), x) def replacement26(a, b, c, d, j, m, n, p, u, x): return Dist((-b**S(2)/d)**m, Int(u*(a - b*x**n)**(-m), x), x) def replacement27(a, b, c, p, u, x): return Int(S(2)**(-S(2)*p)*c**(-p)*u*(b + S(2)*c*x)**(S(2)*p), x) def replacement28(a, b, c, n, n2, p, u, x): return Dist(c**(-p), Int(u*(b/S(2) + c*x**n)**(S(2)*p), x), x) def replacement29(a, b, c, d, e, p, x): return Dist(d/b, Subst(Int(x**p, x), x, a + b*x + c*x**S(2)), x) def replacement30(a, b, m, p, q, u, x): return Int(u*x**(m*p)*(a + b*x**(-p + q))**m, x) def replacement31(a, b, c, m, p, q, r, u, x): return Int(u*x**(m*p)*(a + b*x**(-p + q) + c*x**(-p + r))**m, x) def replacement32(a, b, m, n, x): return Simp(log(RemoveContent(a + b*x**n, x))/(b*n), x) def replacement33(a, b, m, n, p, x): return Simp((a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement34(a1, a2, b1, b2, m, n, p, x): return Simp((a1 + b1*x**n)**(p + S(1))*(a2 + b2*x**n)**(p + S(1))/(S(2)*b1*b2*n*(p + S(1))), x) def With35(Pm, Qm, a, b, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False m = Expon(Pm, x) if And(Equal(Expon(Qm, x), m + S(-1)), ZeroQ(-Qm*m*Coeff(Pm, x, m) + Coeff(Qm, x, m + S(-1))*D(Pm, x))): return True return False def replacement35(Pm, Qm, a, b, n, p, x): m = Expon(Pm, x) return Dist(Coeff(Qm, x, m + S(-1))/(m*Coeff(Pm, x, m)), Subst(Int((a + b*x**n)**p, x), x, Pm), x) def With36(Pm, Qm, a, b, c, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False m = Expon(Pm, x) if And(Equal(Expon(Qm, x), m + S(-1)), ZeroQ(-Qm*m*Coeff(Pm, x, m) + Coeff(Qm, x, m + S(-1))*D(Pm, x))): return True return False def replacement36(Pm, Qm, a, b, c, n, n2, p, x): m = Expon(Pm, x) return Dist(Coeff(Qm, x, m + S(-1))/(m*Coeff(Pm, x, m)), Subst(Int((a + b*x**n + c*x**(S(2)*n))**p, x), x, Pm), x) def With37(Pq, Qr, m, p, u, x): if isinstance(x, (int, Integer, float, Float)): return False gcd = PolyGCD(Pq, Qr, x) if NonzeroQ(gcd + S(-1)): return True return False def replacement37(Pq, Qr, m, p, u, x): gcd = PolyGCD(Pq, Qr, x) return Int(gcd**(m + p)*u*PolynomialQuotient(Pq, gcd, x)**m*PolynomialQuotient(Qr, gcd, x)**p, x) def With38(Pq, Qr, p, u, x): if isinstance(x, (int, Integer, float, Float)): return False gcd = PolyGCD(Pq, Qr, x) if NonzeroQ(gcd + S(-1)): return True return False def replacement38(Pq, Qr, p, u, x): gcd = PolyGCD(Pq, Qr, x) return Int(gcd**(p + S(1))*u*PolynomialQuotient(Pq, gcd, x)*PolynomialQuotient(Qr, gcd, x)**p, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/inverse_hyperbolic.py000066400000000000000000012552551412543434000254530ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def inverse_hyperbolic(): from sympy.integrals.rubi.constraints import cons89, cons90, cons2, cons3, cons8, cons91, cons1581, cons4, cons150, cons68, cons29, cons19, cons64, cons1736, cons1737, cons1738, cons1780, cons270, cons50, cons1894, cons1895, cons1896, cons1897, cons733, cons654, cons734, cons656, cons586, cons1740, cons1898, cons130, cons1739, cons340, cons165, cons40, cons349, cons139, cons232, cons669, cons5, cons1741, cons1742, cons963, cons1899, cons1743, cons1900, cons1745, cons1744, cons1746, cons1572, cons1901, cons338, cons1902, cons149, cons127, cons210, cons56, cons244, cons1748, cons1749, cons488, cons164, cons96, cons95, cons274, cons1750, cons20, cons168, cons276, cons1751, cons1752, cons21, cons240, cons239, cons1753, cons248, cons1754, cons1903, cons1755, cons1756, cons1904, cons1757, cons1758, cons1905, cons211, cons927, cons466, cons86, cons1759, cons1760, cons721, cons170, cons1761, cons1762, cons269, cons719, cons1763, cons1610, cons14, cons152, cons1200, cons1275, cons1362, cons1832, cons1765, cons36, cons37, cons38, cons1764, cons1906, cons167, cons1444, cons1767, cons1766, cons1768, cons1769, cons530, cons1232, cons1771, cons1772, cons1907, cons1908, cons87, cons806, cons33, cons342, cons1909, cons1910, cons1911, cons1778, cons1045, cons1779, cons1499, cons13, cons1781, cons1782, cons1783, cons1784, cons242, cons243, cons148, cons1785, cons1512, cons1786, cons1154, cons321, cons1787, cons1788, cons1789, cons1790, cons1912, cons1913, cons1914, cons1915, cons1795, cons1796, cons1916, cons1798, cons603, cons1799, cons263, cons1917, cons1484, cons1443, cons1918, cons1252, cons1919, cons1920, cons1804, cons1805, cons1921, cons745, cons179, cons119, cons1922, cons25, cons1923, cons1924, cons1925, cons1926, cons1927, cons676, cons1928, cons1929, cons1930, cons996, cons1582, cons1820, cons1931, cons1932, cons1933, cons1934, cons1935, cons1936, cons1937, cons1826, cons975, cons1938, cons1829, cons1939, cons1940, cons1096, cons1833, cons1834, cons1835, cons1836, cons1941, cons385, cons810, cons1588, cons820, cons465, cons1942, cons1943, cons1944, cons1945, cons1946, cons69, cons1947, cons1948, cons1949, cons1950, cons1849, cons1951, cons1952, cons1953, cons1954, cons1856, cons180, cons1857, cons1858, cons1301, cons1955, cons1956, cons1957, cons1958 pattern6087 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons89, cons90) rule6087 = ReplacementRule(pattern6087, replacement6087) pattern6088 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons89, cons90) rule6088 = ReplacementRule(pattern6088, replacement6088) pattern6089 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons89, cons91) rule6089 = ReplacementRule(pattern6089, replacement6089) pattern6090 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons89, cons91) rule6090 = ReplacementRule(pattern6090, replacement6090) pattern6091 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule6091 = ReplacementRule(pattern6091, replacement6091) pattern6092 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule6092 = ReplacementRule(pattern6092, replacement6092) pattern6093 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/x_, x_), cons2, cons3, cons8, cons150) rule6093 = ReplacementRule(pattern6093, replacement6093) pattern6094 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/x_, x_), cons2, cons3, cons8, cons150) rule6094 = ReplacementRule(pattern6094, replacement6094) pattern6095 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons150, cons68) rule6095 = ReplacementRule(pattern6095, replacement6095) pattern6096 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons150, cons68) rule6096 = ReplacementRule(pattern6096, replacement6096) pattern6097 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons90) rule6097 = ReplacementRule(pattern6097, replacement6097) pattern6098 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons90) rule6098 = ReplacementRule(pattern6098, replacement6098) pattern6099 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1736) rule6099 = ReplacementRule(pattern6099, replacement6099) pattern6100 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1736) rule6100 = ReplacementRule(pattern6100, replacement6100) pattern6101 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1737) rule6101 = ReplacementRule(pattern6101, replacement6101) pattern6102 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1737) rule6102 = ReplacementRule(pattern6102, replacement6102) pattern6103 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons64) rule6103 = ReplacementRule(pattern6103, replacement6103) pattern6104 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons64) rule6104 = ReplacementRule(pattern6104, replacement6104) pattern6105 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1738) rule6105 = ReplacementRule(pattern6105, replacement6105) pattern6106 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1738) rule6106 = ReplacementRule(pattern6106, replacement6106) pattern6107 = Pattern(Integral(S(1)/(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons270) rule6107 = ReplacementRule(pattern6107, replacement6107) pattern6108 = Pattern(Integral(S(1)/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons1896, cons1897) rule6108 = ReplacementRule(pattern6108, replacement6108) pattern6109 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons270, cons586) rule6109 = ReplacementRule(pattern6109, replacement6109) pattern6110 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons1894, cons1895, cons1896, cons1897, cons586) rule6110 = ReplacementRule(pattern6110, replacement6110) pattern6111 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons1740) rule6111 = ReplacementRule(pattern6111, replacement6111) pattern6112 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons1894, cons1895, cons1898) rule6112 = ReplacementRule(pattern6112, replacement6112) pattern6113 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons130) rule6113 = ReplacementRule(pattern6113, With6113) pattern6114 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons130) rule6114 = ReplacementRule(pattern6114, With6114) pattern6115 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons90, cons165, cons40) rule6115 = ReplacementRule(pattern6115, replacement6115) pattern6116 = Pattern(Integral(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule6116 = ReplacementRule(pattern6116, replacement6116) pattern6117 = Pattern(Integral(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons89, cons90) rule6117 = ReplacementRule(pattern6117, replacement6117) pattern6118 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons90, cons165) rule6118 = ReplacementRule(pattern6118, replacement6118) pattern6119 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons340, cons90, cons165, cons349) rule6119 = ReplacementRule(pattern6119, replacement6119) pattern6120 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons340, cons90, cons165) rule6120 = ReplacementRule(pattern6120, replacement6120) pattern6121 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule6121 = ReplacementRule(pattern6121, replacement6121) pattern6122 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/((d1_ + x_*WC('e1', S(1)))**(S(3)/2)*(d2_ + x_*WC('e2', S(1)))**(S(3)/2)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons89, cons90) rule6122 = ReplacementRule(pattern6122, replacement6122) pattern6123 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons90, cons139, cons40) rule6123 = ReplacementRule(pattern6123, replacement6123) pattern6124 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons90, cons139, cons232) rule6124 = ReplacementRule(pattern6124, replacement6124) pattern6125 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons340, cons90, cons139, cons232, cons669) rule6125 = ReplacementRule(pattern6125, replacement6125) pattern6126 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons340, cons90, cons139, cons232) rule6126 = ReplacementRule(pattern6126, replacement6126) pattern6127 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150) rule6127 = ReplacementRule(pattern6127, replacement6127) pattern6128 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule6128 = ReplacementRule(pattern6128, replacement6128) pattern6129 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons91, cons40) rule6129 = ReplacementRule(pattern6129, replacement6129) pattern6130 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons91) rule6130 = ReplacementRule(pattern6130, replacement6130) pattern6131 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons5, cons1894, cons1895, cons89, cons91, cons349) rule6131 = ReplacementRule(pattern6131, replacement6131) pattern6132 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons5, cons1894, cons1895, cons89, cons91) rule6132 = ReplacementRule(pattern6132, replacement6132) pattern6133 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons1741, cons1742) rule6133 = ReplacementRule(pattern6133, replacement6133) pattern6134 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons130) rule6134 = ReplacementRule(pattern6134, replacement6134) pattern6135 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons1894, cons1895, cons963, cons1899) rule6135 = ReplacementRule(pattern6135, replacement6135) pattern6136 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons1741, cons1743) rule6136 = ReplacementRule(pattern6136, replacement6136) pattern6137 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons1894, cons1895, cons1741, cons1898) rule6137 = ReplacementRule(pattern6137, replacement6137) pattern6138 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1900, cons1745) rule6138 = ReplacementRule(pattern6138, With6138) pattern6139 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1744, cons1745) rule6139 = ReplacementRule(pattern6139, With6139) pattern6140 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1900, cons40, cons1746) rule6140 = ReplacementRule(pattern6140, replacement6140) pattern6141 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1744, cons40, cons1746) rule6141 = ReplacementRule(pattern6141, replacement6141) pattern6142 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule6142 = ReplacementRule(pattern6142, replacement6142) pattern6143 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons40) rule6143 = ReplacementRule(pattern6143, replacement6143) pattern6144 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons5, cons1901) rule6144 = ReplacementRule(pattern6144, replacement6144) pattern6145 = Pattern(Integral((d_ + x_*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons338, cons1902, cons149) rule6145 = ReplacementRule(pattern6145, replacement6145) pattern6146 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1739, cons149) rule6146 = ReplacementRule(pattern6146, replacement6146) pattern6147 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150) rule6147 = ReplacementRule(pattern6147, replacement6147) pattern6148 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule6148 = ReplacementRule(pattern6148, replacement6148) pattern6149 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons56, cons40) rule6149 = ReplacementRule(pattern6149, replacement6149) pattern6150 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons90, cons56) rule6150 = ReplacementRule(pattern6150, replacement6150) pattern6151 = Pattern(Integral(x_*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons5, cons1894, cons1895, cons89, cons90, cons56, cons669) rule6151 = ReplacementRule(pattern6151, replacement6151) pattern6152 = Pattern(Integral(x_*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons5, cons1894, cons1895, cons89, cons90, cons56) rule6152 = ReplacementRule(pattern6152, replacement6152) pattern6153 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150) rule6153 = ReplacementRule(pattern6153, replacement6153) pattern6154 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule6154 = ReplacementRule(pattern6154, replacement6154) pattern6155 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1739, cons89, cons90, cons244, cons68, cons40) rule6155 = ReplacementRule(pattern6155, replacement6155) pattern6156 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1780, cons89, cons90, cons244, cons68) rule6156 = ReplacementRule(pattern6156, replacement6156) pattern6157 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons5, cons1894, cons1895, cons89, cons90, cons244, cons68, cons669) rule6157 = ReplacementRule(pattern6157, replacement6157) pattern6158 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons5, cons1894, cons1895, cons89, cons90, cons244, cons68) rule6158 = ReplacementRule(pattern6158, replacement6158) pattern6159 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons130) rule6159 = ReplacementRule(pattern6159, replacement6159) pattern6160 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons130) rule6160 = ReplacementRule(pattern6160, replacement6160) pattern6161 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1780, cons130, cons1748) rule6161 = ReplacementRule(pattern6161, replacement6161) pattern6162 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons130, cons1748) rule6162 = ReplacementRule(pattern6162, replacement6162) pattern6163 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons130) rule6163 = ReplacementRule(pattern6163, With6163) pattern6164 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons130) rule6164 = ReplacementRule(pattern6164, With6164) pattern6165 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons349, cons1749, cons488, cons270) rule6165 = ReplacementRule(pattern6165, With6165) pattern6166 = Pattern(Integral(x_**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons349, cons1749, cons488, cons1896, cons1897) rule6166 = ReplacementRule(pattern6166, With6166) pattern6167 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons963, cons1749) rule6167 = ReplacementRule(pattern6167, With6167) pattern6168 = Pattern(Integral(x_**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons963, cons1749) rule6168 = ReplacementRule(pattern6168, With6168) pattern6169 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons164, cons90, cons165, cons96, cons40) rule6169 = ReplacementRule(pattern6169, replacement6169) pattern6170 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1780, cons95, cons90, cons96) rule6170 = ReplacementRule(pattern6170, replacement6170) pattern6171 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons1894, cons1895, cons95, cons90, cons96) rule6171 = ReplacementRule(pattern6171, replacement6171) pattern6172 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1780, cons164, cons90, cons165, cons96) rule6172 = ReplacementRule(pattern6172, replacement6172) pattern6173 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons1894, cons1895, cons164, cons90, cons165, cons96, cons349) rule6173 = ReplacementRule(pattern6173, replacement6173) pattern6174 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons340, cons90, cons165, cons274, cons40, cons1750) rule6174 = ReplacementRule(pattern6174, replacement6174) pattern6175 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons89, cons90, cons274, cons1750) rule6175 = ReplacementRule(pattern6175, replacement6175) pattern6176 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons89, cons90, cons274, cons1750) rule6176 = ReplacementRule(pattern6176, replacement6176) pattern6177 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons340, cons90, cons165, cons274, cons1750) rule6177 = ReplacementRule(pattern6177, replacement6177) pattern6178 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons340, cons90, cons165, cons274, cons349, cons1750) rule6178 = ReplacementRule(pattern6178, replacement6178) pattern6179 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1739, cons95, cons90, cons96, cons20, cons40) rule6179 = ReplacementRule(pattern6179, replacement6179) pattern6180 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1780, cons95, cons90, cons96, cons20) rule6180 = ReplacementRule(pattern6180, replacement6180) pattern6181 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons5, cons1894, cons1895, cons95, cons90, cons96, cons20, cons669) rule6181 = ReplacementRule(pattern6181, replacement6181) pattern6182 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons5, cons1894, cons1895, cons95, cons90, cons96, cons20) rule6182 = ReplacementRule(pattern6182, replacement6182) pattern6183 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons95, cons90, cons139, cons168, cons40) rule6183 = ReplacementRule(pattern6183, replacement6183) pattern6184 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1780, cons164, cons90, cons139, cons168) rule6184 = ReplacementRule(pattern6184, replacement6184) pattern6185 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons1894, cons1895, cons164, cons90, cons139, cons168, cons669) rule6185 = ReplacementRule(pattern6185, replacement6185) pattern6186 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons1894, cons1895, cons164, cons90, cons139, cons149, cons168) rule6186 = ReplacementRule(pattern6186, replacement6186) pattern6187 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons340, cons90, cons139, cons276, cons40) rule6187 = ReplacementRule(pattern6187, replacement6187) pattern6188 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons340, cons90, cons139, cons276, cons1751) rule6188 = ReplacementRule(pattern6188, replacement6188) pattern6189 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons340, cons90, cons139, cons276, cons1752, cons669) rule6189 = ReplacementRule(pattern6189, replacement6189) pattern6190 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons340, cons90, cons139, cons276, cons1751) rule6190 = ReplacementRule(pattern6190, replacement6190) pattern6191 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1780, cons95, cons90, cons168, cons20) rule6191 = ReplacementRule(pattern6191, replacement6191) pattern6192 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons1894, cons1895, cons95, cons90, cons168, cons20) rule6192 = ReplacementRule(pattern6192, replacement6192) pattern6193 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons270, cons150, cons20) rule6193 = ReplacementRule(pattern6193, replacement6193) pattern6194 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1894, cons1895, cons150, cons1896, cons1897, cons20) rule6194 = ReplacementRule(pattern6194, replacement6194) pattern6195 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons270, cons21) rule6195 = ReplacementRule(pattern6195, replacement6195) pattern6196 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons1896, cons1897, cons21) rule6196 = ReplacementRule(pattern6196, replacement6196) pattern6197 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons89, cons90, cons1740, cons1752) rule6197 = ReplacementRule(pattern6197, replacement6197) pattern6198 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons89, cons90, cons1898, cons1752) rule6198 = ReplacementRule(pattern6198, replacement6198) pattern6199 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1739, cons95, cons90, cons168, cons240, cons40, cons20) rule6199 = ReplacementRule(pattern6199, replacement6199) pattern6200 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1780, cons95, cons90, cons168, cons240, cons20) rule6200 = ReplacementRule(pattern6200, replacement6200) pattern6201 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons5, cons1894, cons1895, cons95, cons90, cons168, cons240, cons20, cons669) rule6201 = ReplacementRule(pattern6201, replacement6201) pattern6202 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons5, cons1894, cons1895, cons95, cons90, cons168, cons240, cons20) rule6202 = ReplacementRule(pattern6202, replacement6202) pattern6203 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1739, cons89, cons91, cons239, cons40) rule6203 = ReplacementRule(pattern6203, replacement6203) pattern6204 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1780, cons89, cons91, cons239) rule6204 = ReplacementRule(pattern6204, replacement6204) pattern6205 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons5, cons1894, cons1895, cons89, cons91, cons239, cons349) rule6205 = ReplacementRule(pattern6205, replacement6205) pattern6206 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons5, cons1894, cons1895, cons89, cons91, cons239) rule6206 = ReplacementRule(pattern6206, replacement6206) pattern6207 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons89, cons91, cons270) rule6207 = ReplacementRule(pattern6207, replacement6207) pattern6208 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons89, cons91, cons1896, cons1897) rule6208 = ReplacementRule(pattern6208, replacement6208) pattern6209 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1780, cons89, cons91, cons1740) rule6209 = ReplacementRule(pattern6209, replacement6209) pattern6210 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons1894, cons1895, cons89, cons91, cons1898) rule6210 = ReplacementRule(pattern6210, replacement6210) pattern6211 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons89, cons91, cons20, cons1753, cons130) rule6211 = ReplacementRule(pattern6211, replacement6211) pattern6212 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1780, cons89, cons91, cons20, cons1753, cons1741) rule6212 = ReplacementRule(pattern6212, replacement6212) pattern6213 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons1894, cons1895, cons89, cons91, cons20, cons1753, cons963) rule6213 = ReplacementRule(pattern6213, replacement6213) pattern6214 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons248, cons1754, cons64, cons1742) rule6214 = ReplacementRule(pattern6214, replacement6214) pattern6215 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons130, cons64) rule6215 = ReplacementRule(pattern6215, replacement6215) pattern6216 = Pattern(Integral(x_**WC('m', S(1))*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons1894, cons1895, cons669, cons1754, cons64, cons1899) rule6216 = ReplacementRule(pattern6216, replacement6216) pattern6217 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons248, cons1754, cons64, cons1743) rule6217 = ReplacementRule(pattern6217, replacement6217) pattern6218 = Pattern(Integral(x_**WC('m', S(1))*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons1894, cons1895, cons248, cons1754, cons64, cons1903) rule6218 = ReplacementRule(pattern6218, replacement6218) pattern6219 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1780, cons270, cons963, cons1755, cons20, cons1756) rule6219 = ReplacementRule(pattern6219, replacement6219) pattern6220 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons4, cons1894, cons1895, cons1896, cons1897, cons963, cons1755, cons20, cons1756) rule6220 = ReplacementRule(pattern6220, replacement6220) pattern6221 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1744, cons68, cons1904) rule6221 = ReplacementRule(pattern6221, replacement6221) pattern6222 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1900, cons56) rule6222 = ReplacementRule(pattern6222, replacement6222) pattern6223 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1744, cons56) rule6223 = ReplacementRule(pattern6223, replacement6223) pattern6224 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1900, cons40, cons1757) rule6224 = ReplacementRule(pattern6224, With6224) pattern6225 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1744, cons40, cons1757) rule6225 = ReplacementRule(pattern6225, With6225) pattern6226 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1900, cons150, cons40, cons20) rule6226 = ReplacementRule(pattern6226, replacement6226) pattern6227 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1744, cons150, cons40, cons20) rule6227 = ReplacementRule(pattern6227, replacement6227) pattern6228 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons1758) rule6228 = ReplacementRule(pattern6228, replacement6228) pattern6229 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons40) rule6229 = ReplacementRule(pattern6229, replacement6229) pattern6230 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d1_ + x_*WC('e1', S(1)))**WC('p', S(1))*(d2_ + x_*WC('e2', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons19, cons4, cons5, cons1905) rule6230 = ReplacementRule(pattern6230, replacement6230) pattern6231 = Pattern(Integral((x_*WC('h', S(1)))**WC('m', S(1))*(d_ + x_*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons338, cons1902, cons149) rule6231 = ReplacementRule(pattern6231, replacement6231) pattern6232 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons1739, cons149) rule6232 = ReplacementRule(pattern6232, replacement6232) pattern6233 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons150) rule6233 = ReplacementRule(pattern6233, replacement6233) pattern6234 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons150) rule6234 = ReplacementRule(pattern6234, replacement6234) pattern6235 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons150, cons68) rule6235 = ReplacementRule(pattern6235, replacement6235) pattern6236 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons150, cons68) rule6236 = ReplacementRule(pattern6236, replacement6236) pattern6237 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons64, cons89, cons91) rule6237 = ReplacementRule(pattern6237, replacement6237) pattern6238 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons64, cons89, cons91) rule6238 = ReplacementRule(pattern6238, replacement6238) pattern6239 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons64) rule6239 = ReplacementRule(pattern6239, replacement6239) pattern6240 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons64) rule6240 = ReplacementRule(pattern6240, replacement6240) pattern6241 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons927) rule6241 = ReplacementRule(pattern6241, With6241) pattern6242 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons927) rule6242 = ReplacementRule(pattern6242, With6242) pattern6243 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons927) rule6243 = ReplacementRule(pattern6243, replacement6243) pattern6244 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons927) rule6244 = ReplacementRule(pattern6244, replacement6244) pattern6245 = Pattern(Integral(Px_*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons927) rule6245 = ReplacementRule(pattern6245, With6245) pattern6246 = Pattern(Integral(Px_*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons927) rule6246 = ReplacementRule(pattern6246, With6246) pattern6247 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons466, cons86, cons1759) rule6247 = ReplacementRule(pattern6247, With6247) pattern6248 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons466, cons86, cons1759) rule6248 = ReplacementRule(pattern6248, With6248) pattern6249 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_*(x_**S(2)*WC('h', S(1)) + x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))/(d_ + x_*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons466, cons1760) rule6249 = ReplacementRule(pattern6249, With6249) pattern6250 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_*(x_**S(2)*WC('h', S(1)) + x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))/(d_ + x_*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons466, cons1760) rule6250 = ReplacementRule(pattern6250, With6250) pattern6251 = Pattern(Integral(Px_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons927, cons150, cons20) rule6251 = ReplacementRule(pattern6251, replacement6251) pattern6252 = Pattern(Integral(Px_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons927, cons150, cons20) rule6252 = ReplacementRule(pattern6252, replacement6252) pattern6253 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1780, cons20, cons721, cons270, cons170, cons1761) rule6253 = ReplacementRule(pattern6253, With6253) pattern6254 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons1894, cons1895, cons20, cons721, cons1896, cons1897, cons170, cons1761) rule6254 = ReplacementRule(pattern6254, With6254) pattern6255 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1780, cons20, cons669, cons270, cons150, cons170, cons1762) rule6255 = ReplacementRule(pattern6255, replacement6255) pattern6256 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons1894, cons1895, cons20, cons669, cons1896, cons1897, cons150, cons170, cons1762) rule6256 = ReplacementRule(pattern6256, replacement6256) pattern6257 = Pattern(Integral(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(x_*WC('g', S(1)) + WC('f', S(0)))**m_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1780, cons20, cons270, cons150, cons269) rule6257 = ReplacementRule(pattern6257, replacement6257) pattern6258 = Pattern(Integral(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))*(f_ + x_*WC('g', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons1894, cons1895, cons20, cons1896, cons1897, cons150, cons269) rule6258 = ReplacementRule(pattern6258, replacement6258) pattern6259 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1780, cons20, cons963, cons270, cons150) rule6259 = ReplacementRule(pattern6259, replacement6259) pattern6260 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons1894, cons1895, cons20, cons963, cons1896, cons1897, cons150) rule6260 = ReplacementRule(pattern6260, replacement6260) pattern6261 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1780, cons20, cons719, cons270, cons150, cons269) rule6261 = ReplacementRule(pattern6261, replacement6261) pattern6262 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons1894, cons1895, cons20, cons719, cons1896, cons1897, cons150, cons269) rule6262 = ReplacementRule(pattern6262, replacement6262) pattern6263 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1780, cons20, cons270, cons170, cons89, cons91) rule6263 = ReplacementRule(pattern6263, replacement6263) pattern6264 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons1894, cons1895, cons20, cons1896, cons1897, cons170, cons89, cons91) rule6264 = ReplacementRule(pattern6264, replacement6264) pattern6265 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1780, cons20, cons270, cons1763) rule6265 = ReplacementRule(pattern6265, replacement6265) pattern6266 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons4, cons1894, cons1895, cons20, cons1896, cons1897, cons1763) rule6266 = ReplacementRule(pattern6266, replacement6266) pattern6267 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1780, cons20, cons721, cons270, cons150) rule6267 = ReplacementRule(pattern6267, replacement6267) pattern6268 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons1894, cons1895, cons20, cons721, cons1896, cons1897, cons150) rule6268 = ReplacementRule(pattern6268, replacement6268) pattern6269 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1780, cons20, cons349, cons1740) rule6269 = ReplacementRule(pattern6269, replacement6269) pattern6270 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1739, cons20, cons349) rule6270 = ReplacementRule(pattern6270, replacement6270) pattern6271 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons4, cons1894, cons1895, cons20, cons349, cons1898) rule6271 = ReplacementRule(pattern6271, replacement6271) pattern6272 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1)))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons1780, cons270, cons150) rule6272 = ReplacementRule(pattern6272, replacement6272) pattern6273 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1)))/(sqrt(d1_ + x_*WC('e1', S(1)))*sqrt(d2_ + x_*WC('e2', S(1)))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons211, cons19, cons1894, cons1895, cons1896, cons1897, cons150) rule6273 = ReplacementRule(pattern6273, replacement6273) pattern6274 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons1780, cons349, cons1740) rule6274 = ReplacementRule(pattern6274, replacement6274) pattern6275 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons1739, cons349) rule6275 = ReplacementRule(pattern6275, replacement6275) pattern6276 = Pattern(Integral((d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1))), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons211, cons19, cons4, cons1894, cons1895, cons349, cons1898) rule6276 = ReplacementRule(pattern6276, replacement6276) pattern6277 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(f_ + x_*WC('g', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1610) rule6277 = ReplacementRule(pattern6277, With6277) pattern6278 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(f_ + x_*WC('g', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1610) rule6278 = ReplacementRule(pattern6278, With6278) pattern6279 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons20) rule6279 = ReplacementRule(pattern6279, replacement6279) pattern6280 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons20) rule6280 = ReplacementRule(pattern6280, replacement6280) pattern6281 = Pattern(Integral(u_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons14, CustomConstraint(With6281)) rule6281 = ReplacementRule(pattern6281, replacement6281) pattern6282 = Pattern(Integral(u_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons14, CustomConstraint(With6282)) rule6282 = ReplacementRule(pattern6282, replacement6282) pattern6283 = Pattern(Integral(Px_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons927, cons1780, cons349, CustomConstraint(With6283)) rule6283 = ReplacementRule(pattern6283, replacement6283) pattern6284 = Pattern(Integral(Px_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons927, cons1894, cons1895, cons349, CustomConstraint(With6284)) rule6284 = ReplacementRule(pattern6284, replacement6284) pattern6285 = Pattern(Integral((f_ + (d_ + x_**S(2)*WC('e', S(1)))**p_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))*WC('Px', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons927, cons1780, cons963, cons152, CustomConstraint(With6285)) rule6285 = ReplacementRule(pattern6285, replacement6285) pattern6286 = Pattern(Integral((f_ + (d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))*WC('Px', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons210, cons927, cons1894, cons1895, cons963, cons152, CustomConstraint(With6286)) rule6286 = ReplacementRule(pattern6286, replacement6286) pattern6287 = Pattern(Integral(RFx_*asinh(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons1200, cons150, CustomConstraint(With6287)) rule6287 = ReplacementRule(pattern6287, replacement6287) pattern6288 = Pattern(Integral(RFx_*acosh(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons1200, cons150, CustomConstraint(With6288)) rule6288 = ReplacementRule(pattern6288, replacement6288) pattern6289 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons1200, cons150) rule6289 = ReplacementRule(pattern6289, replacement6289) pattern6290 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons1200, cons150) rule6290 = ReplacementRule(pattern6290, replacement6290) pattern6291 = Pattern(Integral(RFx_*(d_ + x_**S(2)*WC('e', S(1)))**p_*asinh(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons29, cons50, cons1200, cons150, cons1780, cons349, CustomConstraint(With6291)) rule6291 = ReplacementRule(pattern6291, replacement6291) pattern6292 = Pattern(Integral(RFx_*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_*acosh(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons733, cons654, cons734, cons656, cons1200, cons150, cons1894, cons1895, cons349, CustomConstraint(With6292)) rule6292 = ReplacementRule(pattern6292, replacement6292) pattern6293 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons1200, cons150, cons1780, cons349) rule6293 = ReplacementRule(pattern6293, replacement6293) pattern6294 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))*(d1_ + x_*WC('e1', S(1)))**p_*(d2_ + x_*WC('e2', S(1)))**p_, x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons1200, cons150, cons1894, cons1895, cons349) rule6294 = ReplacementRule(pattern6294, replacement6294) pattern6295 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(x_*WC('c', S(1))))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule6295 = ReplacementRule(pattern6295, replacement6295) pattern6296 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_*WC('c', S(1))))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule6296 = ReplacementRule(pattern6296, replacement6296) pattern6297 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1275) rule6297 = ReplacementRule(pattern6297, replacement6297) pattern6298 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1275) rule6298 = ReplacementRule(pattern6298, replacement6298) pattern6299 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule6299 = ReplacementRule(pattern6299, replacement6299) pattern6300 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule6300 = ReplacementRule(pattern6300, replacement6300) pattern6301 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1832, cons1765) rule6301 = ReplacementRule(pattern6301, replacement6301) pattern6302 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1764, cons1765) rule6302 = ReplacementRule(pattern6302, replacement6302) pattern6303 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1832, cons1765) rule6303 = ReplacementRule(pattern6303, replacement6303) pattern6304 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1764, cons1765) rule6304 = ReplacementRule(pattern6304, replacement6304) pattern6305 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons1906) rule6305 = ReplacementRule(pattern6305, replacement6305) pattern6306 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1906, cons89, cons167) rule6306 = ReplacementRule(pattern6306, replacement6306) pattern6307 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons1906) rule6307 = ReplacementRule(pattern6307, replacement6307) pattern6308 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons1906) rule6308 = ReplacementRule(pattern6308, replacement6308) pattern6309 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_**S(2)*WC('d', S(1))))**(S(-3)/2), x_), cons2, cons3, cons8, cons29, cons1906) rule6309 = ReplacementRule(pattern6309, replacement6309) pattern6310 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_**S(2)*WC('d', S(1))))**(S(-2)), x_), cons2, cons3, cons8, cons29, cons1906) rule6310 = ReplacementRule(pattern6310, replacement6310) pattern6311 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asinh(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1906, cons89, cons91, cons1444) rule6311 = ReplacementRule(pattern6311, replacement6311) pattern6312 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(1))), x_), cons2, cons3, cons29, cons1767) rule6312 = ReplacementRule(pattern6312, replacement6312) pattern6313 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(-1))), x_), cons2, cons3, cons29, cons1767) rule6313 = ReplacementRule(pattern6313, replacement6313) pattern6314 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1766, cons89, cons167) rule6314 = ReplacementRule(pattern6314, replacement6314) pattern6315 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(1))), x_), cons2, cons3, cons29, cons1767) rule6315 = ReplacementRule(pattern6315, replacement6315) pattern6316 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(-1))), x_), cons2, cons3, cons29, cons1767) rule6316 = ReplacementRule(pattern6316, replacement6316) pattern6317 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(1))), x_), cons2, cons3, cons29, cons1767) rule6317 = ReplacementRule(pattern6317, replacement6317) pattern6318 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(-1))), x_), cons2, cons3, cons29, cons1767) rule6318 = ReplacementRule(pattern6318, replacement6318) pattern6319 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(1)))**(S(-3)/2), x_), cons2, cons3, cons29, cons1767) rule6319 = ReplacementRule(pattern6319, replacement6319) pattern6320 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(-1)))**(S(-3)/2), x_), cons2, cons3, cons29, cons1767) rule6320 = ReplacementRule(pattern6320, replacement6320) pattern6321 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(1)))**(S(-2)), x_), cons2, cons3, cons29, cons1767) rule6321 = ReplacementRule(pattern6321, replacement6321) pattern6322 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(x_**S(2)*WC('d', S(1)) + S(-1)))**(S(-2)), x_), cons2, cons3, cons29, cons1767) rule6322 = ReplacementRule(pattern6322, replacement6322) pattern6323 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acosh(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1766, cons89, cons91, cons1444) rule6323 = ReplacementRule(pattern6323, replacement6323) pattern6324 = Pattern(Integral(asinh(x_**p_*WC('a', S(1)))**WC('n', S(1))/x_, x_), cons2, cons5, cons150) rule6324 = ReplacementRule(pattern6324, replacement6324) pattern6325 = Pattern(Integral(acosh(x_**p_*WC('a', S(1)))**WC('n', S(1))/x_, x_), cons2, cons5, cons150) rule6325 = ReplacementRule(pattern6325, replacement6325) pattern6326 = Pattern(Integral(WC('u', S(1))*asinh(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule6326 = ReplacementRule(pattern6326, replacement6326) pattern6327 = Pattern(Integral(WC('u', S(1))*acosh(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule6327 = ReplacementRule(pattern6327, replacement6327) pattern6328 = Pattern(Integral(asinh(sqrt(x_**S(2)*WC('b', S(1)) + S(-1)))**WC('n', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + S(-1)), x_), cons3, cons4, cons1769) rule6328 = ReplacementRule(pattern6328, replacement6328) pattern6329 = Pattern(Integral(acosh(sqrt(x_**S(2)*WC('b', S(1)) + S(1)))**WC('n', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + S(1)), x_), cons3, cons4, cons1769) rule6329 = ReplacementRule(pattern6329, replacement6329) pattern6330 = Pattern(Integral(f_**(WC('c', S(1))*asinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))), x_), cons2, cons3, cons8, cons127, cons150) rule6330 = ReplacementRule(pattern6330, replacement6330) pattern6331 = Pattern(Integral(f_**(WC('c', S(1))*acosh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))), x_), cons2, cons3, cons8, cons127, cons150) rule6331 = ReplacementRule(pattern6331, replacement6331) pattern6332 = Pattern(Integral(f_**(WC('c', S(1))*asinh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)))*x_**WC('m', S(1)), x_), cons2, cons3, cons8, cons127, cons530) rule6332 = ReplacementRule(pattern6332, replacement6332) pattern6333 = Pattern(Integral(f_**(WC('c', S(1))*acosh(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)))*x_**WC('m', S(1)), x_), cons2, cons3, cons8, cons127, cons530) rule6333 = ReplacementRule(pattern6333, replacement6333) pattern6334 = Pattern(Integral(asinh(u_), x_), cons1232, cons1771) rule6334 = ReplacementRule(pattern6334, replacement6334) pattern6335 = Pattern(Integral(acosh(u_), x_), cons1232, cons1771) rule6335 = ReplacementRule(pattern6335, replacement6335) pattern6336 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asinh(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule6336 = ReplacementRule(pattern6336, replacement6336) pattern6337 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acosh(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule6337 = ReplacementRule(pattern6337, replacement6337) pattern6338 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*asinh(u_)), x_), cons2, cons3, cons1232, cons1907, CustomConstraint(With6338)) rule6338 = ReplacementRule(pattern6338, replacement6338) pattern6339 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*acosh(u_)), x_), cons2, cons3, cons1232, cons1908, CustomConstraint(With6339)) rule6339 = ReplacementRule(pattern6339, replacement6339) pattern6340 = Pattern(Integral(exp(WC('n', S(1))*asinh(u_)), x_), cons87, cons806) rule6340 = ReplacementRule(pattern6340, replacement6340) pattern6341 = Pattern(Integral(x_**WC('m', S(1))*exp(WC('n', S(1))*asinh(u_)), x_), cons33, cons87, cons806) rule6341 = ReplacementRule(pattern6341, replacement6341) pattern6342 = Pattern(Integral(exp(WC('n', S(1))*acosh(u_)), x_), cons87, cons806) rule6342 = ReplacementRule(pattern6342, replacement6342) pattern6343 = Pattern(Integral(x_**WC('m', S(1))*exp(WC('n', S(1))*acosh(u_)), x_), cons33, cons87, cons806) rule6343 = ReplacementRule(pattern6343, replacement6343) pattern6344 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons150) rule6344 = ReplacementRule(pattern6344, replacement6344) pattern6345 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons150) rule6345 = ReplacementRule(pattern6345, replacement6345) pattern6346 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons342) rule6346 = ReplacementRule(pattern6346, replacement6346) pattern6347 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons342) rule6347 = ReplacementRule(pattern6347, replacement6347) pattern6348 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150) rule6348 = ReplacementRule(pattern6348, replacement6348) pattern6349 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150) rule6349 = ReplacementRule(pattern6349, replacement6349) pattern6350 = Pattern(Integral(atanh(x_*WC('c', S(1)))/(d_ + x_*WC('e', S(1))), x_), cons8, cons29, cons50, cons1910, cons1911) rule6350 = ReplacementRule(pattern6350, replacement6350) pattern6351 = Pattern(Integral(atanh(x_*WC('c', S(1)))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule6351 = ReplacementRule(pattern6351, replacement6351) pattern6352 = Pattern(Integral(acoth(x_*WC('c', S(1)))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule6352 = ReplacementRule(pattern6352, replacement6352) pattern6353 = Pattern(Integral((a_ + WC('b', S(1))*atanh(x_*WC('c', S(1))))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule6353 = ReplacementRule(pattern6353, replacement6353) pattern6354 = Pattern(Integral((a_ + WC('b', S(1))*acoth(x_*WC('c', S(1))))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule6354 = ReplacementRule(pattern6354, replacement6354) pattern6355 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule6355 = ReplacementRule(pattern6355, replacement6355) pattern6356 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule6356 = ReplacementRule(pattern6356, replacement6356) pattern6357 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_/x_, x_), cons2, cons3, cons8, cons87, cons167) rule6357 = ReplacementRule(pattern6357, replacement6357) pattern6358 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_/x_, x_), cons2, cons3, cons8, cons87, cons167) rule6358 = ReplacementRule(pattern6358, replacement6358) pattern6359 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons19, cons87, cons167, cons68) rule6359 = ReplacementRule(pattern6359, replacement6359) pattern6360 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons19, cons87, cons167, cons68) rule6360 = ReplacementRule(pattern6360, replacement6360) pattern6361 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons466) rule6361 = ReplacementRule(pattern6361, replacement6361) pattern6362 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons466) rule6362 = ReplacementRule(pattern6362, replacement6362) pattern6363 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons342) rule6363 = ReplacementRule(pattern6363, replacement6363) pattern6364 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons342) rule6364 = ReplacementRule(pattern6364, replacement6364) pattern6365 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150, cons33, cons170) rule6365 = ReplacementRule(pattern6365, replacement6365) pattern6366 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150, cons33, cons170) rule6366 = ReplacementRule(pattern6366, replacement6366) pattern6367 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150) rule6367 = ReplacementRule(pattern6367, replacement6367) pattern6368 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150) rule6368 = ReplacementRule(pattern6368, replacement6368) pattern6369 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150, cons33, cons96) rule6369 = ReplacementRule(pattern6369, replacement6369) pattern6370 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1909, cons150, cons33, cons96) rule6370 = ReplacementRule(pattern6370, replacement6370) pattern6371 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1779) rule6371 = ReplacementRule(pattern6371, replacement6371) pattern6372 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1779) rule6372 = ReplacementRule(pattern6372, replacement6372) pattern6373 = Pattern(Integral(x_**WC('m', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule6373 = ReplacementRule(pattern6373, replacement6373) pattern6374 = Pattern(Integral(x_**WC('m', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule6374 = ReplacementRule(pattern6374, replacement6374) pattern6375 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons13, cons165) rule6375 = ReplacementRule(pattern6375, replacement6375) pattern6376 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons13, cons165) rule6376 = ReplacementRule(pattern6376, replacement6376) pattern6377 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons165, cons167) rule6377 = ReplacementRule(pattern6377, replacement6377) pattern6378 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons165, cons167) rule6378 = ReplacementRule(pattern6378, replacement6378) pattern6379 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1739) rule6379 = ReplacementRule(pattern6379, replacement6379) pattern6380 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1739) rule6380 = ReplacementRule(pattern6380, replacement6380) pattern6381 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons586) rule6381 = ReplacementRule(pattern6381, replacement6381) pattern6382 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons586) rule6382 = ReplacementRule(pattern6382, replacement6382) pattern6383 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270) rule6383 = ReplacementRule(pattern6383, replacement6383) pattern6384 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270) rule6384 = ReplacementRule(pattern6384, replacement6384) pattern6385 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons270) rule6385 = ReplacementRule(pattern6385, replacement6385) pattern6386 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons270) rule6386 = ReplacementRule(pattern6386, replacement6386) pattern6387 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons1740) rule6387 = ReplacementRule(pattern6387, replacement6387) pattern6388 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons1740) rule6388 = ReplacementRule(pattern6388, replacement6388) pattern6389 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6389 = ReplacementRule(pattern6389, replacement6389) pattern6390 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6390 = ReplacementRule(pattern6390, replacement6390) pattern6391 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739) rule6391 = ReplacementRule(pattern6391, replacement6391) pattern6392 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739) rule6392 = ReplacementRule(pattern6392, replacement6392) pattern6393 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons13, cons139, cons232) rule6393 = ReplacementRule(pattern6393, replacement6393) pattern6394 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons13, cons139, cons232) rule6394 = ReplacementRule(pattern6394, replacement6394) pattern6395 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons167) rule6395 = ReplacementRule(pattern6395, replacement6395) pattern6396 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons167) rule6396 = ReplacementRule(pattern6396, replacement6396) pattern6397 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons139, cons167, cons232) rule6397 = ReplacementRule(pattern6397, replacement6397) pattern6398 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons139, cons167, cons232) rule6398 = ReplacementRule(pattern6398, replacement6398) pattern6399 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons139, cons91) rule6399 = ReplacementRule(pattern6399, replacement6399) pattern6400 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons139, cons91) rule6400 = ReplacementRule(pattern6400, replacement6400) pattern6401 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1781, cons1742) rule6401 = ReplacementRule(pattern6401, replacement6401) pattern6402 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1781, cons1743) rule6402 = ReplacementRule(pattern6402, replacement6402) pattern6403 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1781, cons40) rule6403 = ReplacementRule(pattern6403, replacement6403) pattern6404 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1781, cons149) rule6404 = ReplacementRule(pattern6404, replacement6404) pattern6405 = Pattern(Integral(atanh(x_*WC('c', S(1)))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule6405 = ReplacementRule(pattern6405, replacement6405) pattern6406 = Pattern(Integral(acoth(x_*WC('c', S(1)))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule6406 = ReplacementRule(pattern6406, replacement6406) pattern6407 = Pattern(Integral((a_ + WC('b', S(1))*atanh(x_*WC('c', S(1))))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule6407 = ReplacementRule(pattern6407, replacement6407) pattern6408 = Pattern(Integral((a_ + WC('b', S(1))*acoth(x_*WC('c', S(1))))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule6408 = ReplacementRule(pattern6408, replacement6408) pattern6409 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1782) rule6409 = ReplacementRule(pattern6409, With6409) pattern6410 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1782) rule6410 = ReplacementRule(pattern6410, With6410) pattern6411 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150) rule6411 = ReplacementRule(pattern6411, replacement6411) pattern6412 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150) rule6412 = ReplacementRule(pattern6412, replacement6412) pattern6413 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule6413 = ReplacementRule(pattern6413, replacement6413) pattern6414 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule6414 = ReplacementRule(pattern6414, replacement6414) pattern6415 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons168) rule6415 = ReplacementRule(pattern6415, replacement6415) pattern6416 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons168) rule6416 = ReplacementRule(pattern6416, replacement6416) pattern6417 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons96) rule6417 = ReplacementRule(pattern6417, replacement6417) pattern6418 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons96) rule6418 = ReplacementRule(pattern6418, replacement6418) pattern6419 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule6419 = ReplacementRule(pattern6419, replacement6419) pattern6420 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule6420 = ReplacementRule(pattern6420, replacement6420) pattern6421 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons342, cons586) rule6421 = ReplacementRule(pattern6421, replacement6421) pattern6422 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons342, cons586) rule6422 = ReplacementRule(pattern6422, replacement6422) pattern6423 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons168) rule6423 = ReplacementRule(pattern6423, replacement6423) pattern6424 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons168) rule6424 = ReplacementRule(pattern6424, replacement6424) pattern6425 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6425 = ReplacementRule(pattern6425, replacement6425) pattern6426 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6426 = ReplacementRule(pattern6426, replacement6426) pattern6427 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons96) rule6427 = ReplacementRule(pattern6427, replacement6427) pattern6428 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons96) rule6428 = ReplacementRule(pattern6428, replacement6428) pattern6429 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons89, cons91) rule6429 = ReplacementRule(pattern6429, replacement6429) pattern6430 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons89, cons91) rule6430 = ReplacementRule(pattern6430, replacement6430) pattern6431 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons20, cons1783) rule6431 = ReplacementRule(pattern6431, replacement6431) pattern6432 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons20, cons1783) rule6432 = ReplacementRule(pattern6432, replacement6432) pattern6433 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons56) rule6433 = ReplacementRule(pattern6433, replacement6433) pattern6434 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons56) rule6434 = ReplacementRule(pattern6434, replacement6434) pattern6435 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons91, cons1444) rule6435 = ReplacementRule(pattern6435, replacement6435) pattern6436 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons91, cons1444) rule6436 = ReplacementRule(pattern6436, replacement6436) pattern6437 = Pattern(Integral(x_**S(2)*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons13, cons139, cons1784) rule6437 = ReplacementRule(pattern6437, replacement6437) pattern6438 = Pattern(Integral(x_**S(2)*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons13, cons139, cons1784) rule6438 = ReplacementRule(pattern6438, replacement6438) pattern6439 = Pattern(Integral(x_**S(2)*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6439 = ReplacementRule(pattern6439, replacement6439) pattern6440 = Pattern(Integral(x_**S(2)*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6440 = ReplacementRule(pattern6440, replacement6440) pattern6441 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons242, cons13, cons139) rule6441 = ReplacementRule(pattern6441, replacement6441) pattern6442 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons242, cons13, cons139) rule6442 = ReplacementRule(pattern6442, replacement6442) pattern6443 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons242, cons340, cons139, cons167) rule6443 = ReplacementRule(pattern6443, replacement6443) pattern6444 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons242, cons340, cons139, cons167) rule6444 = ReplacementRule(pattern6444, replacement6444) pattern6445 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1739, cons242, cons89, cons91) rule6445 = ReplacementRule(pattern6445, replacement6445) pattern6446 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1739, cons242, cons89, cons91) rule6446 = ReplacementRule(pattern6446, replacement6446) pattern6447 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1739, cons244, cons89, cons90, cons68) rule6447 = ReplacementRule(pattern6447, replacement6447) pattern6448 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1739, cons244, cons89, cons90, cons68) rule6448 = ReplacementRule(pattern6448, replacement6448) pattern6449 = Pattern(Integral(x_**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons243) rule6449 = ReplacementRule(pattern6449, replacement6449) pattern6450 = Pattern(Integral(x_**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons243) rule6450 = ReplacementRule(pattern6450, replacement6450) pattern6451 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons150, cons40, cons148) rule6451 = ReplacementRule(pattern6451, replacement6451) pattern6452 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons150, cons40, cons148) rule6452 = ReplacementRule(pattern6452, replacement6452) pattern6453 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons13, cons165, cons150, cons1785) rule6453 = ReplacementRule(pattern6453, replacement6453) pattern6454 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1739, cons13, cons165, cons150, cons1785) rule6454 = ReplacementRule(pattern6454, replacement6454) pattern6455 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons168) rule6455 = ReplacementRule(pattern6455, replacement6455) pattern6456 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons168) rule6456 = ReplacementRule(pattern6456, replacement6456) pattern6457 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270) rule6457 = ReplacementRule(pattern6457, replacement6457) pattern6458 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270) rule6458 = ReplacementRule(pattern6458, replacement6458) pattern6459 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**n_/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons270) rule6459 = ReplacementRule(pattern6459, replacement6459) pattern6460 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**n_/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons270) rule6460 = ReplacementRule(pattern6460, replacement6460) pattern6461 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons1740) rule6461 = ReplacementRule(pattern6461, replacement6461) pattern6462 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150, cons1740) rule6462 = ReplacementRule(pattern6462, replacement6462) pattern6463 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(x_**S(2)*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6463 = ReplacementRule(pattern6463, replacement6463) pattern6464 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/(x_**S(2)*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule6464 = ReplacementRule(pattern6464, replacement6464) pattern6465 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons96, cons1512) rule6465 = ReplacementRule(pattern6465, replacement6465) pattern6466 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons95, cons90, cons96, cons1512) rule6466 = ReplacementRule(pattern6466, replacement6466) pattern6467 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons1786, cons139, cons168, cons1154) rule6467 = ReplacementRule(pattern6467, replacement6467) pattern6468 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons1786, cons139, cons168, cons1154) rule6468 = ReplacementRule(pattern6468, replacement6468) pattern6469 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons1786, cons139, cons269, cons1154) rule6469 = ReplacementRule(pattern6469, replacement6469) pattern6470 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons1786, cons139, cons269, cons1154) rule6470 = ReplacementRule(pattern6470, replacement6470) pattern6471 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons164, cons139, cons91, cons321) rule6471 = ReplacementRule(pattern6471, replacement6471) pattern6472 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons164, cons139, cons91, cons321) rule6472 = ReplacementRule(pattern6472, replacement6472) pattern6473 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons64, cons1787, cons1742) rule6473 = ReplacementRule(pattern6473, replacement6473) pattern6474 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons64, cons1787, cons1743) rule6474 = ReplacementRule(pattern6474, replacement6474) pattern6475 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons64, cons1787, cons40) rule6475 = ReplacementRule(pattern6475, replacement6475) pattern6476 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons64, cons1787, cons149) rule6476 = ReplacementRule(pattern6476, replacement6476) pattern6477 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule6477 = ReplacementRule(pattern6477, replacement6477) pattern6478 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule6478 = ReplacementRule(pattern6478, replacement6478) pattern6479 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule6479 = ReplacementRule(pattern6479, With6479) pattern6480 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule6480 = ReplacementRule(pattern6480, With6480) pattern6481 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1789) rule6481 = ReplacementRule(pattern6481, replacement6481) pattern6482 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1789) rule6482 = ReplacementRule(pattern6482, replacement6482) pattern6483 = Pattern(Integral(x_**WC('m', S(1))*(a_ + WC('b', S(1))*atanh(x_*WC('c', S(1))))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1790) rule6483 = ReplacementRule(pattern6483, replacement6483) pattern6484 = Pattern(Integral(x_**WC('m', S(1))*(a_ + WC('b', S(1))*acoth(x_*WC('c', S(1))))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1790) rule6484 = ReplacementRule(pattern6484, replacement6484) pattern6485 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule6485 = ReplacementRule(pattern6485, replacement6485) pattern6486 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule6486 = ReplacementRule(pattern6486, replacement6486) pattern6487 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))*atanh(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1912) rule6487 = ReplacementRule(pattern6487, replacement6487) pattern6488 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))*acoth(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1912) rule6488 = ReplacementRule(pattern6488, replacement6488) pattern6489 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))*atanh(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1913) rule6489 = ReplacementRule(pattern6489, replacement6489) pattern6490 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))*acoth(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1913) rule6490 = ReplacementRule(pattern6490, replacement6490) pattern6491 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1914) rule6491 = ReplacementRule(pattern6491, replacement6491) pattern6492 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1914) rule6492 = ReplacementRule(pattern6492, replacement6492) pattern6493 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1915) rule6493 = ReplacementRule(pattern6493, replacement6493) pattern6494 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons1915) rule6494 = ReplacementRule(pattern6494, replacement6494) pattern6495 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons1912) rule6495 = ReplacementRule(pattern6495, replacement6495) pattern6496 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons1912) rule6496 = ReplacementRule(pattern6496, replacement6496) pattern6497 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons1913) rule6497 = ReplacementRule(pattern6497, replacement6497) pattern6498 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons1913) rule6498 = ReplacementRule(pattern6498, replacement6498) pattern6499 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1739) rule6499 = ReplacementRule(pattern6499, replacement6499) pattern6500 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons152, cons1795) rule6500 = ReplacementRule(pattern6500, replacement6500) pattern6501 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**WC('m', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons152, cons1796) rule6501 = ReplacementRule(pattern6501, replacement6501) pattern6502 = Pattern(Integral(atanh(x_*WC('a', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons8, cons29, cons87, cons1916) rule6502 = ReplacementRule(pattern6502, replacement6502) pattern6503 = Pattern(Integral(acoth(x_*WC('a', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons8, cons29, cons87, cons1916) rule6503 = ReplacementRule(pattern6503, replacement6503) pattern6504 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1798) rule6504 = ReplacementRule(pattern6504, replacement6504) pattern6505 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1798) rule6505 = ReplacementRule(pattern6505, replacement6505) pattern6506 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons603) rule6506 = ReplacementRule(pattern6506, replacement6506) pattern6507 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons603) rule6507 = ReplacementRule(pattern6507, replacement6507) pattern6508 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1799) rule6508 = ReplacementRule(pattern6508, With6508) pattern6509 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1799) rule6509 = ReplacementRule(pattern6509, With6509) pattern6510 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons20, cons263) rule6510 = ReplacementRule(pattern6510, With6510) pattern6511 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons20, cons263) rule6511 = ReplacementRule(pattern6511, With6511) pattern6512 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*atanh(x_*WC('c', S(1))))**S(2)*(WC('d', S(0)) + WC('e', S(1))*log(f_ + x_**S(2)*WC('g', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1917) rule6512 = ReplacementRule(pattern6512, replacement6512) pattern6513 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acoth(x_*WC('c', S(1))))**S(2)*(WC('d', S(0)) + WC('e', S(1))*log(f_ + x_**S(2)*WC('g', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1917) rule6513 = ReplacementRule(pattern6513, replacement6513) pattern6514 = Pattern(Integral(exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons1484) rule6514 = ReplacementRule(pattern6514, replacement6514) pattern6515 = Pattern(Integral(x_**WC('m', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons19, cons1484) rule6515 = ReplacementRule(pattern6515, replacement6515) pattern6516 = Pattern(Integral(exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons4, cons1443) rule6516 = ReplacementRule(pattern6516, replacement6516) pattern6517 = Pattern(Integral(x_**WC('m', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons19, cons4, cons1443) rule6517 = ReplacementRule(pattern6517, replacement6517) pattern6518 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1918, cons1252, cons248) rule6518 = ReplacementRule(pattern6518, replacement6518) pattern6519 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons5, cons1918, cons1252, cons1919, cons248) rule6519 = ReplacementRule(pattern6519, replacement6519) pattern6520 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1920, cons1804) rule6520 = ReplacementRule(pattern6520, replacement6520) pattern6521 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1920, cons1805) rule6521 = ReplacementRule(pattern6521, replacement6521) pattern6522 = Pattern(Integral((c_ + WC('d', S(1))/x_)**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1921, cons40) rule6522 = ReplacementRule(pattern6522, replacement6522) pattern6523 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1921, cons149, cons745, cons179) rule6523 = ReplacementRule(pattern6523, replacement6523) pattern6524 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1921, cons149, cons745, cons119) rule6524 = ReplacementRule(pattern6524, replacement6524) pattern6525 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1921, cons149) rule6525 = ReplacementRule(pattern6525, replacement6525) pattern6526 = Pattern(Integral(exp(n_*atanh(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1922, cons25) rule6526 = ReplacementRule(pattern6526, replacement6526) pattern6527 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons13, cons139, cons25, cons1923, cons248) rule6527 = ReplacementRule(pattern6527, replacement6527) pattern6528 = Pattern(Integral(exp(WC('n', S(1))*atanh(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924) rule6528 = ReplacementRule(pattern6528, replacement6528) pattern6529 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1922, cons40, cons1925, cons1926) rule6529 = ReplacementRule(pattern6529, replacement6529) pattern6530 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1922, cons40, cons1927, cons1926) rule6530 = ReplacementRule(pattern6530, replacement6530) pattern6531 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1922, cons1804) rule6531 = ReplacementRule(pattern6531, replacement6531) pattern6532 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1922, cons1805, cons676) rule6532 = ReplacementRule(pattern6532, replacement6532) pattern6533 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1922, cons1805, cons1928) rule6533 = ReplacementRule(pattern6533, replacement6533) pattern6534 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1922, cons1805) rule6534 = ReplacementRule(pattern6534, replacement6534) pattern6535 = Pattern(Integral(x_*exp(n_*atanh(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1922, cons25) rule6535 = ReplacementRule(pattern6535, replacement6535) pattern6536 = Pattern(Integral(x_*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons13, cons139, cons25, cons248) rule6536 = ReplacementRule(pattern6536, replacement6536) pattern6537 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons1929, cons25) rule6537 = ReplacementRule(pattern6537, replacement6537) pattern6538 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons13, cons139, cons25, cons1923, cons248) rule6538 = ReplacementRule(pattern6538, replacement6538) pattern6539 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons5, cons1922, cons1804, cons1925, cons1926) rule6539 = ReplacementRule(pattern6539, replacement6539) pattern6540 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons5, cons1922, cons1804, cons1927, cons1926) rule6540 = ReplacementRule(pattern6540, replacement6540) pattern6541 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1922, cons1804) rule6541 = ReplacementRule(pattern6541, replacement6541) pattern6542 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons5, cons1922, cons1805, cons676) rule6542 = ReplacementRule(pattern6542, replacement6542) pattern6543 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons5, cons1922, cons1805, cons1928) rule6543 = ReplacementRule(pattern6543, replacement6543) pattern6544 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1922, cons1805, cons1924) rule6544 = ReplacementRule(pattern6544, replacement6544) pattern6545 = Pattern(Integral(u_*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1922, cons1804) rule6545 = ReplacementRule(pattern6545, replacement6545) pattern6546 = Pattern(Integral(u_*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1922, cons1805, cons745) rule6546 = ReplacementRule(pattern6546, replacement6546) pattern6547 = Pattern(Integral(u_*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1922, cons1805, cons1924) rule6547 = ReplacementRule(pattern6547, replacement6547) pattern6548 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1930, cons40) rule6548 = ReplacementRule(pattern6548, replacement6548) pattern6549 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1930, cons149, cons745, cons179) rule6549 = ReplacementRule(pattern6549, replacement6549) pattern6550 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1930, cons149, cons745, cons119) rule6550 = ReplacementRule(pattern6550, replacement6550) pattern6551 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(WC('n', S(1))*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1930, cons149, cons1924) rule6551 = ReplacementRule(pattern6551, replacement6551) pattern6552 = Pattern(Integral(exp(WC('n', S(1))*atanh((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1581) rule6552 = ReplacementRule(pattern6552, replacement6552) pattern6553 = Pattern(Integral(x_**m_*exp(n_*atanh((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons86, cons89, cons996) rule6553 = ReplacementRule(pattern6553, replacement6553) pattern6554 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*exp(WC('n', S(1))*atanh((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule6554 = ReplacementRule(pattern6554, replacement6554) pattern6555 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*atanh(a_ + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1820, cons1931, cons1932) rule6555 = ReplacementRule(pattern6555, replacement6555) pattern6556 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*atanh(a_ + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1820, cons1931, cons1933) rule6556 = ReplacementRule(pattern6556, replacement6556) pattern6557 = Pattern(Integral(WC('u', S(1))*exp(WC('n', S(1))*atanh(WC('c', S(1))/(x_*WC('b', S(1)) + WC('a', S(0))))), x_), cons2, cons3, cons8, cons4, cons1581) rule6557 = ReplacementRule(pattern6557, replacement6557) pattern6558 = Pattern(Integral(WC('u', S(1))*exp(n_*acoth(x_*WC('a', S(1)))), x_), cons2, cons745) rule6558 = ReplacementRule(pattern6558, replacement6558) pattern6559 = Pattern(Integral(exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons1484) rule6559 = ReplacementRule(pattern6559, replacement6559) pattern6560 = Pattern(Integral(x_**WC('m', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons1484, cons20) rule6560 = ReplacementRule(pattern6560, replacement6560) pattern6561 = Pattern(Integral(exp(n_*acoth(x_*WC('a', S(1)))), x_), cons2, cons4, cons25) rule6561 = ReplacementRule(pattern6561, replacement6561) pattern6562 = Pattern(Integral(x_**WC('m', S(1))*exp(n_*acoth(x_*WC('a', S(1)))), x_), cons2, cons4, cons25, cons20) rule6562 = ReplacementRule(pattern6562, replacement6562) pattern6563 = Pattern(Integral(x_**m_*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons19, cons1484, cons21) rule6563 = ReplacementRule(pattern6563, replacement6563) pattern6564 = Pattern(Integral(x_**m_*exp(n_*acoth(x_*WC('a', S(1)))), x_), cons2, cons19, cons4, cons25, cons21) rule6564 = ReplacementRule(pattern6564, replacement6564) pattern6565 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1918, cons1934, cons1924) rule6565 = ReplacementRule(pattern6565, replacement6565) pattern6566 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1920, cons1924, cons40) rule6566 = ReplacementRule(pattern6566, replacement6566) pattern6567 = Pattern(Integral((c_ + x_*WC('d', S(1)))**p_*WC('u', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1920, cons1924, cons149) rule6567 = ReplacementRule(pattern6567, replacement6567) pattern6568 = Pattern(Integral((c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1935, cons1252, cons1919, cons248) rule6568 = ReplacementRule(pattern6568, replacement6568) pattern6569 = Pattern(Integral(x_**WC('m', S(1))*(c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1935, cons1252, cons20, cons1936, cons248) rule6569 = ReplacementRule(pattern6569, replacement6569) pattern6570 = Pattern(Integral((c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1921, cons1924, cons1804) rule6570 = ReplacementRule(pattern6570, replacement6570) pattern6571 = Pattern(Integral(x_**WC('m', S(1))*(c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1921, cons1924, cons1804, cons20) rule6571 = ReplacementRule(pattern6571, replacement6571) pattern6572 = Pattern(Integral(x_**m_*(c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1921, cons1924, cons1804, cons21) rule6572 = ReplacementRule(pattern6572, replacement6572) pattern6573 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1921, cons1924, cons1805) rule6573 = ReplacementRule(pattern6573, replacement6573) pattern6574 = Pattern(Integral(exp(WC('n', S(1))*acoth(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924) rule6574 = ReplacementRule(pattern6574, replacement6574) pattern6575 = Pattern(Integral(exp(n_*acoth(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1922, cons25) rule6575 = ReplacementRule(pattern6575, replacement6575) pattern6576 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924, cons13, cons139, cons232, cons1923, cons1937) rule6576 = ReplacementRule(pattern6576, replacement6576) pattern6577 = Pattern(Integral(x_*exp(n_*acoth(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1922, cons25) rule6577 = ReplacementRule(pattern6577, replacement6577) pattern6578 = Pattern(Integral(x_*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924, cons13, cons1826, cons232, cons1923, cons1937) rule6578 = ReplacementRule(pattern6578, replacement6578) pattern6579 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924, cons1929, cons975) rule6579 = ReplacementRule(pattern6579, replacement6579) pattern6580 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924, cons13, cons1826, cons1938, cons1923, cons1937) rule6580 = ReplacementRule(pattern6580, replacement6580) pattern6581 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924, cons20, cons13, cons1829, cons40) rule6581 = ReplacementRule(pattern6581, replacement6581) pattern6582 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1922, cons1924, cons40) rule6582 = ReplacementRule(pattern6582, replacement6582) pattern6583 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*WC('u', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1922, cons1924, cons149) rule6583 = ReplacementRule(pattern6583, replacement6583) pattern6584 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1930, cons1924, cons1804, cons1939) rule6584 = ReplacementRule(pattern6584, replacement6584) pattern6585 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1930, cons1924, cons1804, cons1940) rule6585 = ReplacementRule(pattern6585, replacement6585) pattern6586 = Pattern(Integral(x_**WC('m', S(1))*(c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1930, cons1924, cons1804, cons1940, cons20) rule6586 = ReplacementRule(pattern6586, replacement6586) pattern6587 = Pattern(Integral(x_**m_*(c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1930, cons1924, cons1804, cons1940, cons21) rule6587 = ReplacementRule(pattern6587, replacement6587) pattern6588 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(WC('n', S(1))*acoth(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1930, cons1924, cons1805) rule6588 = ReplacementRule(pattern6588, replacement6588) pattern6589 = Pattern(Integral(WC('u', S(1))*exp(n_*acoth((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons745) rule6589 = ReplacementRule(pattern6589, replacement6589) pattern6590 = Pattern(Integral(exp(WC('n', S(1))*acoth((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1924) rule6590 = ReplacementRule(pattern6590, replacement6590) pattern6591 = Pattern(Integral(x_**m_*exp(n_*acoth((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons86, cons89, cons996) rule6591 = ReplacementRule(pattern6591, replacement6591) pattern6592 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*exp(WC('n', S(1))*acoth((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1924) rule6592 = ReplacementRule(pattern6592, replacement6592) pattern6593 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acoth(a_ + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1924, cons1820, cons1931, cons1932) rule6593 = ReplacementRule(pattern6593, replacement6593) pattern6594 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acoth(a_ + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1924, cons1820, cons1931, cons1933) rule6594 = ReplacementRule(pattern6594, replacement6594) pattern6595 = Pattern(Integral(WC('u', S(1))*exp(WC('n', S(1))*acoth(WC('c', S(1))/(x_*WC('b', S(1)) + WC('a', S(0))))), x_), cons2, cons3, cons8, cons4, cons1581) rule6595 = ReplacementRule(pattern6595, replacement6595) pattern6596 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150) rule6596 = ReplacementRule(pattern6596, replacement6596) pattern6597 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150) rule6597 = ReplacementRule(pattern6597, replacement6597) pattern6598 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(c_ + x_*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons342) rule6598 = ReplacementRule(pattern6598, replacement6598) pattern6599 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(c_ + x_*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons342) rule6599 = ReplacementRule(pattern6599, replacement6599) pattern6600 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons150) rule6600 = ReplacementRule(pattern6600, replacement6600) pattern6601 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons150) rule6601 = ReplacementRule(pattern6601, replacement6601) pattern6602 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**m_*(WC('a', S(0)) + WC('b', S(1))*atanh(c_ + x_*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons342) rule6602 = ReplacementRule(pattern6602, replacement6602) pattern6603 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**m_*(WC('a', S(0)) + WC('b', S(1))*acoth(c_ + x_*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons342) rule6603 = ReplacementRule(pattern6603, replacement6603) pattern6604 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*atanh(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1764, cons1765) rule6604 = ReplacementRule(pattern6604, replacement6604) pattern6605 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acoth(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1764, cons1765) rule6605 = ReplacementRule(pattern6605, replacement6605) pattern6606 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1764, cons1765) rule6606 = ReplacementRule(pattern6606, replacement6606) pattern6607 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1764, cons1765) rule6607 = ReplacementRule(pattern6607, replacement6607) pattern6608 = Pattern(Integral(atanh(a_ + x_*WC('b', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons89) rule6608 = ReplacementRule(pattern6608, replacement6608) pattern6609 = Pattern(Integral(acoth(a_ + x_*WC('b', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons89) rule6609 = ReplacementRule(pattern6609, replacement6609) pattern6610 = Pattern(Integral(atanh(a_ + x_*WC('b', S(1)))/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons1096) rule6610 = ReplacementRule(pattern6610, replacement6610) pattern6611 = Pattern(Integral(acoth(a_ + x_*WC('b', S(1)))/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons1096) rule6611 = ReplacementRule(pattern6611, replacement6611) pattern6612 = Pattern(Integral(atanh(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons4, cons1833) rule6612 = ReplacementRule(pattern6612, replacement6612) pattern6613 = Pattern(Integral(acoth(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons4, cons1833) rule6613 = ReplacementRule(pattern6613, replacement6613) pattern6614 = Pattern(Integral(atanh(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))/x_, x_), cons2, cons3, cons4, cons1833) rule6614 = ReplacementRule(pattern6614, replacement6614) pattern6615 = Pattern(Integral(acoth(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))/x_, x_), cons2, cons3, cons4, cons1833) rule6615 = ReplacementRule(pattern6615, replacement6615) pattern6616 = Pattern(Integral(x_**WC('m', S(1))*atanh(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons95, cons1834, cons1835) rule6616 = ReplacementRule(pattern6616, replacement6616) pattern6617 = Pattern(Integral(x_**WC('m', S(1))*acoth(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons95, cons1834, cons1835) rule6617 = ReplacementRule(pattern6617, replacement6617) pattern6618 = Pattern(Integral(atanh(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons1836) rule6618 = ReplacementRule(pattern6618, replacement6618) pattern6619 = Pattern(Integral(acoth(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons1836) rule6619 = ReplacementRule(pattern6619, replacement6619) pattern6620 = Pattern(Integral(x_**WC('m', S(1))*atanh(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons20, cons170) rule6620 = ReplacementRule(pattern6620, replacement6620) pattern6621 = Pattern(Integral(x_**WC('m', S(1))*acoth(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons20, cons170) rule6621 = ReplacementRule(pattern6621, replacement6621) pattern6622 = Pattern(Integral(WC('u', S(1))*atanh(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule6622 = ReplacementRule(pattern6622, replacement6622) pattern6623 = Pattern(Integral(WC('u', S(1))*acoth(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule6623 = ReplacementRule(pattern6623, replacement6623) pattern6624 = Pattern(Integral(S(1)/(sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0)))*atanh(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))), x_), cons2, cons3, cons8, cons1941) rule6624 = ReplacementRule(pattern6624, replacement6624) pattern6625 = Pattern(Integral(S(1)/(sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0)))*acoth(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))), x_), cons2, cons3, cons8, cons1941) rule6625 = ReplacementRule(pattern6625, replacement6625) pattern6626 = Pattern(Integral(atanh(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons19, cons1941, cons68) rule6626 = ReplacementRule(pattern6626, replacement6626) pattern6627 = Pattern(Integral(acoth(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons19, cons1941, cons68) rule6627 = ReplacementRule(pattern6627, replacement6627) pattern6628 = Pattern(Integral(atanh(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1941, cons385) rule6628 = ReplacementRule(pattern6628, replacement6628) pattern6629 = Pattern(Integral(acoth(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1941, cons385) rule6629 = ReplacementRule(pattern6629, replacement6629) pattern6630 = Pattern(Integral((x_**S(2)*WC('d', S(1)) + WC('c', S(0)))**n_*atanh(x_*WC('a', S(1))), x_), cons2, cons8, cons29, cons810, cons1588) rule6630 = ReplacementRule(pattern6630, With6630) pattern6631 = Pattern(Integral((x_**S(2)*WC('d', S(1)) + WC('c', S(0)))**n_*acoth(x_*WC('a', S(1))), x_), cons2, cons8, cons29, cons810, cons1588) rule6631 = ReplacementRule(pattern6631, With6631) pattern6632 = Pattern(Integral(u_*v_**WC('n', S(1)), x_), cons820, cons87, cons465, cons1942, cons1943, CustomConstraint(With6632)) rule6632 = ReplacementRule(pattern6632, replacement6632) pattern6633 = Pattern(Integral(u_*v_**WC('n', S(1)), x_), cons820, cons87, cons465, cons1942, cons1944, CustomConstraint(With6633)) rule6633 = ReplacementRule(pattern6633, replacement6633) pattern6634 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1945) rule6634 = ReplacementRule(pattern6634, replacement6634) pattern6635 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1945) rule6635 = ReplacementRule(pattern6635, replacement6635) pattern6636 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1945) rule6636 = ReplacementRule(pattern6636, replacement6636) pattern6637 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1945) rule6637 = ReplacementRule(pattern6637, replacement6637) pattern6638 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1946) rule6638 = ReplacementRule(pattern6638, replacement6638) pattern6639 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1946) rule6639 = ReplacementRule(pattern6639, replacement6639) pattern6640 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1946) rule6640 = ReplacementRule(pattern6640, replacement6640) pattern6641 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1946) rule6641 = ReplacementRule(pattern6641, replacement6641) pattern6642 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1945) rule6642 = ReplacementRule(pattern6642, replacement6642) pattern6643 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1945) rule6643 = ReplacementRule(pattern6643, replacement6643) pattern6644 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1945) rule6644 = ReplacementRule(pattern6644, replacement6644) pattern6645 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1945) rule6645 = ReplacementRule(pattern6645, replacement6645) pattern6646 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1946) rule6646 = ReplacementRule(pattern6646, replacement6646) pattern6647 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1946) rule6647 = ReplacementRule(pattern6647, replacement6647) pattern6648 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1946) rule6648 = ReplacementRule(pattern6648, replacement6648) pattern6649 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1946) rule6649 = ReplacementRule(pattern6649, replacement6649) pattern6650 = Pattern(Integral(atanh(tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule6650 = ReplacementRule(pattern6650, replacement6650) pattern6651 = Pattern(Integral(acoth(tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule6651 = ReplacementRule(pattern6651, replacement6651) pattern6652 = Pattern(Integral(atanh(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule6652 = ReplacementRule(pattern6652, replacement6652) pattern6653 = Pattern(Integral(acoth(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule6653 = ReplacementRule(pattern6653, replacement6653) pattern6654 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule6654 = ReplacementRule(pattern6654, replacement6654) pattern6655 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule6655 = ReplacementRule(pattern6655, replacement6655) pattern6656 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule6656 = ReplacementRule(pattern6656, replacement6656) pattern6657 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule6657 = ReplacementRule(pattern6657, replacement6657) pattern6658 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1947) rule6658 = ReplacementRule(pattern6658, replacement6658) pattern6659 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1947) rule6659 = ReplacementRule(pattern6659, replacement6659) pattern6660 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1948) rule6660 = ReplacementRule(pattern6660, replacement6660) pattern6661 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1948) rule6661 = ReplacementRule(pattern6661, replacement6661) pattern6662 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1949) rule6662 = ReplacementRule(pattern6662, replacement6662) pattern6663 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1949) rule6663 = ReplacementRule(pattern6663, replacement6663) pattern6664 = Pattern(Integral(atanh(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1950) rule6664 = ReplacementRule(pattern6664, replacement6664) pattern6665 = Pattern(Integral(acoth(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1950) rule6665 = ReplacementRule(pattern6665, replacement6665) pattern6666 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1947) rule6666 = ReplacementRule(pattern6666, replacement6666) pattern6667 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1947) rule6667 = ReplacementRule(pattern6667, replacement6667) pattern6668 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1948) rule6668 = ReplacementRule(pattern6668, replacement6668) pattern6669 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1948) rule6669 = ReplacementRule(pattern6669, replacement6669) pattern6670 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1949) rule6670 = ReplacementRule(pattern6670, replacement6670) pattern6671 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1949) rule6671 = ReplacementRule(pattern6671, replacement6671) pattern6672 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*atanh(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1950) rule6672 = ReplacementRule(pattern6672, replacement6672) pattern6673 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acoth(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1950) rule6673 = ReplacementRule(pattern6673, replacement6673) pattern6674 = Pattern(Integral(atanh(u_), x_), cons1232) rule6674 = ReplacementRule(pattern6674, replacement6674) pattern6675 = Pattern(Integral(acoth(u_), x_), cons1232) rule6675 = ReplacementRule(pattern6675, replacement6675) pattern6676 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*atanh(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1849) rule6676 = ReplacementRule(pattern6676, replacement6676) pattern6677 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acoth(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1849) rule6677 = ReplacementRule(pattern6677, replacement6677) pattern6678 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*atanh(u_)), x_), cons2, cons3, cons1232, cons1951, cons1952, CustomConstraint(With6678)) rule6678 = ReplacementRule(pattern6678, replacement6678) pattern6679 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*acoth(u_)), x_), cons2, cons3, cons1232, cons1953, cons1954, CustomConstraint(With6679)) rule6679 = ReplacementRule(pattern6679, replacement6679) pattern6680 = Pattern(Integral(asech(x_*WC('c', S(1))), x_), cons8, cons8) rule6680 = ReplacementRule(pattern6680, replacement6680) pattern6681 = Pattern(Integral(acsch(x_*WC('c', S(1))), x_), cons8, cons8) rule6681 = ReplacementRule(pattern6681, replacement6681) pattern6682 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule6682 = ReplacementRule(pattern6682, replacement6682) pattern6683 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule6683 = ReplacementRule(pattern6683, replacement6683) pattern6684 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons14) rule6684 = ReplacementRule(pattern6684, replacement6684) pattern6685 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons14) rule6685 = ReplacementRule(pattern6685, replacement6685) pattern6686 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons68) rule6686 = ReplacementRule(pattern6686, replacement6686) pattern6687 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons68) rule6687 = ReplacementRule(pattern6687, replacement6687) pattern6688 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons20) rule6688 = ReplacementRule(pattern6688, replacement6688) pattern6689 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons20) rule6689 = ReplacementRule(pattern6689, replacement6689) pattern6690 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons1856) rule6690 = ReplacementRule(pattern6690, replacement6690) pattern6691 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons1856) rule6691 = ReplacementRule(pattern6691, replacement6691) pattern6692 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1745) rule6692 = ReplacementRule(pattern6692, With6692) pattern6693 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1745) rule6693 = ReplacementRule(pattern6693, With6693) pattern6694 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons40) rule6694 = ReplacementRule(pattern6694, replacement6694) pattern6695 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons40) rule6695 = ReplacementRule(pattern6695, replacement6695) pattern6696 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons669, cons180, cons1857) rule6696 = ReplacementRule(pattern6696, replacement6696) pattern6697 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons669, cons180, cons1857) rule6697 = ReplacementRule(pattern6697, replacement6697) pattern6698 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons669, cons1858) rule6698 = ReplacementRule(pattern6698, replacement6698) pattern6699 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons669, cons1858) rule6699 = ReplacementRule(pattern6699, replacement6699) pattern6700 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule6700 = ReplacementRule(pattern6700, replacement6700) pattern6701 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule6701 = ReplacementRule(pattern6701, replacement6701) pattern6702 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule6702 = ReplacementRule(pattern6702, replacement6702) pattern6703 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule6703 = ReplacementRule(pattern6703, replacement6703) pattern6704 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule6704 = ReplacementRule(pattern6704, With6704) pattern6705 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule6705 = ReplacementRule(pattern6705, With6705) pattern6706 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1301) rule6706 = ReplacementRule(pattern6706, replacement6706) pattern6707 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1301) rule6707 = ReplacementRule(pattern6707, replacement6707) pattern6708 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons20, cons669, cons180, cons1857) rule6708 = ReplacementRule(pattern6708, replacement6708) pattern6709 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons20, cons669, cons180, cons1857) rule6709 = ReplacementRule(pattern6709, replacement6709) pattern6710 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons20, cons669, cons1858) rule6710 = ReplacementRule(pattern6710, replacement6710) pattern6711 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons20, cons669, cons1858) rule6711 = ReplacementRule(pattern6711, replacement6711) pattern6712 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule6712 = ReplacementRule(pattern6712, replacement6712) pattern6713 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule6713 = ReplacementRule(pattern6713, replacement6713) pattern6714 = Pattern(Integral(asech(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons69) rule6714 = ReplacementRule(pattern6714, replacement6714) pattern6715 = Pattern(Integral(acsch(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons69) rule6715 = ReplacementRule(pattern6715, replacement6715) pattern6716 = Pattern(Integral(asech(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons1833) rule6716 = ReplacementRule(pattern6716, replacement6716) pattern6717 = Pattern(Integral(acsch(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons1833) rule6717 = ReplacementRule(pattern6717, replacement6717) pattern6718 = Pattern(Integral(asech(a_ + x_*WC('b', S(1)))/x_, x_), cons2, cons3, cons69) rule6718 = ReplacementRule(pattern6718, replacement6718) pattern6719 = Pattern(Integral(acsch(a_ + x_*WC('b', S(1)))/x_, x_), cons2, cons3, cons69) rule6719 = ReplacementRule(pattern6719, replacement6719) pattern6720 = Pattern(Integral(x_**WC('m', S(1))*asech(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons19, cons20, cons68) rule6720 = ReplacementRule(pattern6720, replacement6720) pattern6721 = Pattern(Integral(x_**WC('m', S(1))*acsch(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons19, cons20, cons68) rule6721 = ReplacementRule(pattern6721, replacement6721) pattern6722 = Pattern(Integral(x_**WC('m', S(1))*asech(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons64) rule6722 = ReplacementRule(pattern6722, replacement6722) pattern6723 = Pattern(Integral(x_**WC('m', S(1))*acsch(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons64) rule6723 = ReplacementRule(pattern6723, replacement6723) pattern6724 = Pattern(Integral(WC('u', S(1))*asech(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule6724 = ReplacementRule(pattern6724, replacement6724) pattern6725 = Pattern(Integral(WC('u', S(1))*acsch(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule6725 = ReplacementRule(pattern6725, replacement6725) pattern6726 = Pattern(Integral(exp(asech(x_*WC('a', S(1)))), x_), cons2, cons2) rule6726 = ReplacementRule(pattern6726, replacement6726) pattern6727 = Pattern(Integral(exp(asech(x_**p_*WC('a', S(1)))), x_), cons2, cons5, cons1955) rule6727 = ReplacementRule(pattern6727, replacement6727) pattern6728 = Pattern(Integral(exp(acsch(x_**WC('p', S(1))*WC('a', S(1)))), x_), cons2, cons5, cons1955) rule6728 = ReplacementRule(pattern6728, replacement6728) pattern6729 = Pattern(Integral(exp(WC('n', S(1))*asech(u_)), x_), cons87) rule6729 = ReplacementRule(pattern6729, replacement6729) pattern6730 = Pattern(Integral(exp(WC('n', S(1))*acsch(u_)), x_), cons87) rule6730 = ReplacementRule(pattern6730, replacement6730) pattern6731 = Pattern(Integral(exp(asech(x_**WC('p', S(1))*WC('a', S(1))))/x_, x_), cons2, cons5, cons1955) rule6731 = ReplacementRule(pattern6731, replacement6731) pattern6732 = Pattern(Integral(x_**WC('m', S(1))*exp(asech(x_**WC('p', S(1))*WC('a', S(1)))), x_), cons2, cons19, cons5, cons68) rule6732 = ReplacementRule(pattern6732, replacement6732) pattern6733 = Pattern(Integral(x_**WC('m', S(1))*exp(acsch(x_**WC('p', S(1))*WC('a', S(1)))), x_), cons2, cons19, cons5, cons1956) rule6733 = ReplacementRule(pattern6733, replacement6733) pattern6734 = Pattern(Integral(x_**WC('m', S(1))*exp(WC('n', S(1))*asech(u_)), x_), cons19, cons87) rule6734 = ReplacementRule(pattern6734, replacement6734) pattern6735 = Pattern(Integral(x_**WC('m', S(1))*exp(WC('n', S(1))*acsch(u_)), x_), cons19, cons87) rule6735 = ReplacementRule(pattern6735, replacement6735) pattern6736 = Pattern(Integral(asech(u_), x_), cons1232, cons1771) rule6736 = ReplacementRule(pattern6736, replacement6736) pattern6737 = Pattern(Integral(acsch(u_), x_), cons1232, cons1771) rule6737 = ReplacementRule(pattern6737, replacement6737) pattern6738 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asech(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule6738 = ReplacementRule(pattern6738, replacement6738) pattern6739 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsch(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule6739 = ReplacementRule(pattern6739, replacement6739) pattern6740 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*asech(u_)), x_), cons2, cons3, cons1232, cons1957, CustomConstraint(With6740)) rule6740 = ReplacementRule(pattern6740, replacement6740) pattern6741 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*acsch(u_)), x_), cons2, cons3, cons1232, cons1958, CustomConstraint(With6741)) rule6741 = ReplacementRule(pattern6741, replacement6741) return [rule6087, rule6088, rule6089, rule6090, rule6091, rule6092, rule6093, rule6094, rule6095, rule6096, rule6097, rule6098, rule6099, rule6100, rule6101, rule6102, rule6103, rule6104, rule6105, rule6106, rule6107, rule6108, rule6109, rule6110, rule6111, rule6112, rule6113, rule6114, rule6115, rule6116, rule6117, rule6118, rule6119, rule6120, rule6121, rule6122, rule6123, rule6124, rule6125, rule6126, rule6127, rule6128, rule6129, rule6130, rule6131, rule6132, rule6133, rule6134, rule6135, rule6136, rule6137, rule6138, rule6139, rule6140, rule6141, rule6142, rule6143, rule6144, rule6145, rule6146, rule6147, rule6148, rule6149, rule6150, rule6151, rule6152, rule6153, rule6154, rule6155, rule6156, rule6157, rule6158, rule6159, rule6160, rule6161, rule6162, rule6163, rule6164, rule6165, rule6166, rule6167, rule6168, rule6169, rule6170, rule6171, rule6172, rule6173, rule6174, rule6175, rule6176, rule6177, rule6178, rule6179, rule6180, rule6181, rule6182, rule6183, rule6184, rule6185, rule6186, rule6187, rule6188, rule6189, rule6190, rule6191, rule6192, rule6193, rule6194, rule6195, rule6196, rule6197, rule6198, rule6199, rule6200, rule6201, rule6202, rule6203, rule6204, rule6205, rule6206, rule6207, rule6208, rule6209, rule6210, rule6211, rule6212, rule6213, rule6214, rule6215, rule6216, rule6217, rule6218, rule6219, rule6220, rule6221, rule6222, rule6223, rule6224, rule6225, rule6226, rule6227, rule6228, rule6229, rule6230, rule6231, rule6232, rule6233, rule6234, rule6235, rule6236, rule6237, rule6238, rule6239, rule6240, rule6241, rule6242, rule6243, rule6244, rule6245, rule6246, rule6247, rule6248, rule6249, rule6250, rule6251, rule6252, rule6253, rule6254, rule6255, rule6256, rule6257, rule6258, rule6259, rule6260, rule6261, rule6262, rule6263, rule6264, rule6265, rule6266, rule6267, rule6268, rule6269, rule6270, rule6271, rule6272, rule6273, rule6274, rule6275, rule6276, rule6277, rule6278, rule6279, rule6280, rule6281, rule6282, rule6283, rule6284, rule6285, rule6286, rule6287, rule6288, rule6289, rule6290, rule6291, rule6292, rule6293, rule6294, rule6295, rule6296, rule6297, rule6298, rule6299, rule6300, rule6301, rule6302, rule6303, rule6304, rule6305, rule6306, rule6307, rule6308, rule6309, rule6310, rule6311, rule6312, rule6313, rule6314, rule6315, rule6316, rule6317, rule6318, rule6319, rule6320, rule6321, rule6322, rule6323, rule6324, rule6325, rule6326, rule6327, rule6328, rule6329, rule6330, rule6331, rule6332, rule6333, rule6334, rule6335, rule6336, rule6337, rule6338, rule6339, rule6340, rule6341, rule6342, rule6343, rule6344, rule6345, rule6346, rule6347, rule6348, rule6349, rule6350, rule6351, rule6352, rule6353, rule6354, rule6355, rule6356, rule6357, rule6358, rule6359, rule6360, rule6361, rule6362, rule6363, rule6364, rule6365, rule6366, rule6367, rule6368, rule6369, rule6370, rule6371, rule6372, rule6373, rule6374, rule6375, rule6376, rule6377, rule6378, rule6379, rule6380, rule6381, rule6382, rule6383, rule6384, rule6385, rule6386, rule6387, rule6388, rule6389, rule6390, rule6391, rule6392, rule6393, rule6394, rule6395, rule6396, rule6397, rule6398, rule6399, rule6400, rule6401, rule6402, rule6403, rule6404, rule6405, rule6406, rule6407, rule6408, rule6409, rule6410, rule6411, rule6412, rule6413, rule6414, rule6415, rule6416, rule6417, rule6418, rule6419, rule6420, rule6421, rule6422, rule6423, rule6424, rule6425, rule6426, rule6427, rule6428, rule6429, rule6430, rule6431, rule6432, rule6433, rule6434, rule6435, rule6436, rule6437, rule6438, rule6439, rule6440, rule6441, rule6442, rule6443, rule6444, rule6445, rule6446, rule6447, rule6448, rule6449, rule6450, rule6451, rule6452, rule6453, rule6454, rule6455, rule6456, rule6457, rule6458, rule6459, rule6460, rule6461, rule6462, rule6463, rule6464, rule6465, rule6466, rule6467, rule6468, rule6469, rule6470, rule6471, rule6472, rule6473, rule6474, rule6475, rule6476, rule6477, rule6478, rule6479, rule6480, rule6481, rule6482, rule6483, rule6484, rule6485, rule6486, rule6487, rule6488, rule6489, rule6490, rule6491, rule6492, rule6493, rule6494, rule6495, rule6496, rule6497, rule6498, rule6499, rule6500, rule6501, rule6502, rule6503, rule6504, rule6505, rule6506, rule6507, rule6508, rule6509, rule6510, rule6511, rule6512, rule6513, rule6514, rule6515, rule6516, rule6517, rule6518, rule6519, rule6520, rule6521, rule6522, rule6523, rule6524, rule6525, rule6526, rule6527, rule6528, rule6529, rule6530, rule6531, rule6532, rule6533, rule6534, rule6535, rule6536, rule6537, rule6538, rule6539, rule6540, rule6541, rule6542, rule6543, rule6544, rule6545, rule6546, rule6547, rule6548, rule6549, rule6550, rule6551, rule6552, rule6553, rule6554, rule6555, rule6556, rule6557, rule6558, rule6559, rule6560, rule6561, rule6562, rule6563, rule6564, rule6565, rule6566, rule6567, rule6568, rule6569, rule6570, rule6571, rule6572, rule6573, rule6574, rule6575, rule6576, rule6577, rule6578, rule6579, rule6580, rule6581, rule6582, rule6583, rule6584, rule6585, rule6586, rule6587, rule6588, rule6589, rule6590, rule6591, rule6592, rule6593, rule6594, rule6595, rule6596, rule6597, rule6598, rule6599, rule6600, rule6601, rule6602, rule6603, rule6604, rule6605, rule6606, rule6607, rule6608, rule6609, rule6610, rule6611, rule6612, rule6613, rule6614, rule6615, rule6616, rule6617, rule6618, rule6619, rule6620, rule6621, rule6622, rule6623, rule6624, rule6625, rule6626, rule6627, rule6628, rule6629, rule6630, rule6631, rule6632, rule6633, rule6634, rule6635, rule6636, rule6637, rule6638, rule6639, rule6640, rule6641, rule6642, rule6643, rule6644, rule6645, rule6646, rule6647, rule6648, rule6649, rule6650, rule6651, rule6652, rule6653, rule6654, rule6655, rule6656, rule6657, rule6658, rule6659, rule6660, rule6661, rule6662, rule6663, rule6664, rule6665, rule6666, rule6667, rule6668, rule6669, rule6670, rule6671, rule6672, rule6673, rule6674, rule6675, rule6676, rule6677, rule6678, rule6679, rule6680, rule6681, rule6682, rule6683, rule6684, rule6685, rule6686, rule6687, rule6688, rule6689, rule6690, rule6691, rule6692, rule6693, rule6694, rule6695, rule6696, rule6697, rule6698, rule6699, rule6700, rule6701, rule6702, rule6703, rule6704, rule6705, rule6706, rule6707, rule6708, rule6709, rule6710, rule6711, rule6712, rule6713, rule6714, rule6715, rule6716, rule6717, rule6718, rule6719, rule6720, rule6721, rule6722, rule6723, rule6724, rule6725, rule6726, rule6727, rule6728, rule6729, rule6730, rule6731, rule6732, rule6733, rule6734, rule6735, rule6736, rule6737, rule6738, rule6739, rule6740, rule6741, ] def replacement6087(a, b, c, n, x): return -Dist(b*c*n, Int(x*(a + b*asinh(c*x))**(n + S(-1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*asinh(c*x))**n, x) def replacement6088(a, b, c, n, x): return -Dist(b*c*n, Int(x*(a + b*acosh(c*x))**(n + S(-1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp(x*(a + b*acosh(c*x))**n, x) def replacement6089(a, b, c, n, x): return -Dist(c/(b*(n + S(1))), Int(x*(a + b*asinh(c*x))**(n + S(1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*asinh(c*x))**(n + S(1))*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement6090(a, b, c, n, x): return -Dist(c/(b*(n + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp((a + b*acosh(c*x))**(n + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6091(a, b, c, n, x): return Dist(S(1)/(b*c), Subst(Int(x**n*cosh(a/b - x/b), x), x, a + b*asinh(c*x)), x) def replacement6092(a, b, c, n, x): return -Dist(S(1)/(b*c), Subst(Int(x**n*sinh(a/b - x/b), x), x, a + b*acosh(c*x)), x) def replacement6093(a, b, c, n, x): return Subst(Int((a + b*x)**n/tanh(x), x), x, asinh(c*x)) def replacement6094(a, b, c, n, x): return Subst(Int((a + b*x)**n*tanh(x), x), x, acosh(c*x)) def replacement6095(a, b, c, d, m, n, x): return -Dist(b*c*n/(d*(m + S(1))), Int((d*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*asinh(c*x))**n/(d*(m + S(1))), x) def replacement6096(a, b, c, d, m, n, x): return -Dist(b*c*n/(d*(m + S(1))), Int((d*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp((d*x)**(m + S(1))*(a + b*acosh(c*x))**n/(d*(m + S(1))), x) def replacement6097(a, b, c, m, n, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**(m + S(1))*(a + b*asinh(c*x))**n/(m + S(1)), x) def replacement6098(a, b, c, m, n, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp(x**(m + S(1))*(a + b*acosh(c*x))**n/(m + S(1)), x) def replacement6099(a, b, c, m, n, x): return -Dist(c**(-m + S(-1))/(b*(n + S(1))), Subst(Int(ExpandTrigReduce((a + b*x)**(n + S(1)), (m + (m + S(1))*sinh(x)**S(2))*sinh(x)**(m + S(-1)), x), x), x, asinh(c*x)), x) + Simp(x**m*(a + b*asinh(c*x))**(n + S(1))*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement6100(a, b, c, m, n, x): return Dist(c**(-m + S(-1))/(b*(n + S(1))), Subst(Int(ExpandTrigReduce((a + b*x)**(n + S(1))*(m - (m + S(1))*cosh(x)**S(2))*cosh(x)**(m + S(-1)), x), x), x, acosh(c*x)), x) + Simp(x**m*(a + b*acosh(c*x))**(n + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6101(a, b, c, m, n, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*asinh(c*x))**(n + S(1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) - Dist(c*(m + S(1))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*asinh(c*x))**(n + S(1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**m*(a + b*asinh(c*x))**(n + S(1))*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement6102(a, b, c, m, n, x): return Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*acosh(c*x))**(n + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) - Dist(c*(m + S(1))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*acosh(c*x))**(n + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp(x**m*(a + b*acosh(c*x))**(n + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6103(a, b, c, m, n, x): return Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*sinh(x)**m*cosh(x), x), x, asinh(c*x)), x) def replacement6104(a, b, c, m, n, x): return Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*sinh(x)*cosh(x)**m, x), x, acosh(c*x)), x) def replacement6105(a, b, c, d, m, n, x): return Int((d*x)**m*(a + b*asinh(c*x))**n, x) def replacement6106(a, b, c, d, m, n, x): return Int((d*x)**m*(a + b*acosh(c*x))**n, x) def replacement6107(a, b, c, d, e, x): return Simp(log(a + b*asinh(c*x))/(b*c*sqrt(d)), x) def replacement6108(a, b, c, d1, d2, e1, e2, x): return Simp(log(a + b*acosh(c*x))/(b*c*sqrt(-d1*d2)), x) def replacement6109(a, b, c, d, e, n, x): return Simp((a + b*asinh(c*x))**(n + S(1))/(b*c*sqrt(d)*(n + S(1))), x) def replacement6110(a, b, c, d1, d2, e1, e2, n, x): return Simp((a + b*acosh(c*x))**(n + S(1))/(b*c*sqrt(-d1*d2)*(n + S(1))), x) def replacement6111(a, b, c, d, e, n, x): return Dist(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*asinh(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) def replacement6112(a, b, c, d1, d2, e1, e2, n, x): return Dist(sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), Int((a + b*acosh(c*x))**n/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) def With6113(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6114(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) + Dist(a + b*acosh(c*x), u, x) def replacement6115(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*n*(-d)**p/(S(2)*p + S(1)), Int(x*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp(x*(a + b*acosh(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) def replacement6116(a, b, c, d, e, n, x): return Dist(sqrt(d + e*x**S(2))/(S(2)*sqrt(c**S(2)*x**S(2) + S(1))), Int((a + b*asinh(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) - Dist(b*c*n*sqrt(d + e*x**S(2))/(S(2)*sqrt(c**S(2)*x**S(2) + S(1))), Int(x*(a + b*asinh(c*x))**(n + S(-1)), x), x) + Simp(x*(a + b*asinh(c*x))**n*sqrt(d + e*x**S(2))/S(2), x) def replacement6117(a, b, c, d1, d2, e1, e2, n, x): return -Dist(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(S(2)*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((a + b*acosh(c*x))**n/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) - Dist(b*c*n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(S(2)*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(-1)), x), x) + Simp(x*(a + b*acosh(c*x))**n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/S(2), x) def replacement6118(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*p + S(1)), Int(x*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp(x*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) def replacement6119(a, b, c, d1, d2, e1, e2, n, p, x): return Dist(S(2)*d1*d2*p/(S(2)*p + S(1)), Int((a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(-1))*(d2 + e2*x)**(p + S(-1)), x), x) - Dist(b*c*n*(-d1*d2)**(p + S(-1)/2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/((S(2)*p + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(-1)/2), x), x) + Simp(x*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p/(S(2)*p + S(1)), x) def replacement6120(a, b, c, d1, d2, e1, e2, n, p, x): return Dist(S(2)*d1*d2*p/(S(2)*p + S(1)), Int((a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(-1))*(d2 + e2*x)**(p + S(-1)), x), x) - Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*p + S(1)), Int(x*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp(x*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p/(S(2)*p + S(1)), x) def replacement6121(a, b, c, d, e, n, x): return -Dist(b*c*n*sqrt(c**S(2)*x**S(2) + S(1))/(d*sqrt(d + e*x**S(2))), Int(x*(a + b*asinh(c*x))**(n + S(-1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*asinh(c*x))**n/(d*sqrt(d + e*x**S(2))), x) def replacement6122(a, b, c, d1, d2, e1, e2, n, x): return Dist(b*c*n*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(d1*d2*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), Int(x*(a + b*acosh(c*x))**(n + S(-1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*acosh(c*x))**n/(d1*d2*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), x) def replacement6123(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b*c*n*(-d)**p/(S(2)*p + S(2)), Int(x*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) - Simp(x*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement6124(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*(p + S(1))), Int(x*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) - Simp(x*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement6125(a, b, c, d1, d2, e1, e2, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d1*d2*(p + S(1))), Int((a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1)), x), x) - Dist(b*c*n*(-d1*d2)**(p + S(1)/2)*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(S(2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)*(p + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(1)/2), x), x) - Simp(x*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*d1*d2*(p + S(1))), x) def replacement6126(a, b, c, d1, d2, e1, e2, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d1*d2*(p + S(1))), Int((a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1)), x), x) - Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*(p + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) - Simp(x*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*d1*d2*(p + S(1))), x) def replacement6127(a, b, c, d, e, n, x): return Dist(S(1)/(c*d), Subst(Int((a + b*x)**n/cosh(x), x), x, asinh(c*x)), x) def replacement6128(a, b, c, d, e, n, x): return -Dist(S(1)/(c*d), Subst(Int((a + b*x)**n/sinh(x), x), x, acosh(c*x)), x) def replacement6129(a, b, c, d, e, n, p, x): return -Dist(c*(-d)**p*(S(2)*p + S(1))/(b*(n + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((-d)**p*(a + b*acosh(c*x))**(n + S(1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2)/(b*c*(n + S(1))), x) def replacement6130(a, b, c, d, e, n, p, x): return -Dist(c*d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(S(2)*p + S(1))*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*(n + S(1))), Int(x*(a + b*asinh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((a + b*asinh(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement6131(a, b, c, d1, d2, e1, e2, n, p, x): return -Dist(c*(-d1*d2)**(p + S(-1)/2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)*(S(2)*p + S(1))/(b*(n + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(-1))**(p + S(-1)/2), x), x) + Simp((a + b*acosh(c*x))**(n + S(1))*(d1 + e1*x)**p*(d2 + e2*x)**p*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6132(a, b, c, d1, d2, e1, e2, n, p, x): return -Dist(c*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(S(2)*p + S(1))*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(b*(n + S(1))), Int(x*(a + b*acosh(c*x))**(n + S(1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((a + b*acosh(c*x))**(n + S(1))*(d1 + e1*x)**p*(d2 + e2*x)**p*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6133(a, b, c, d, e, n, p, x): return Dist(d**p/c, Subst(Int((a + b*x)**n*cosh(x)**(S(2)*p + S(1)), x), x, asinh(c*x)), x) def replacement6134(a, b, c, d, e, n, p, x): return Dist((-d)**p/c, Subst(Int((a + b*x)**n*sinh(x)**(S(2)*p + S(1)), x), x, acosh(c*x)), x) def replacement6135(a, b, c, d1, d2, e1, e2, n, p, x): return Dist((-d1*d2)**p/c, Subst(Int((a + b*x)**n*sinh(x)**(S(2)*p + S(1)), x), x, acosh(c*x)), x) def replacement6136(a, b, c, d, e, n, p, x): return Dist(d**(p + S(-1)/2)*sqrt(d + e*x**S(2))/sqrt(c**S(2)*x**S(2) + S(1)), Int((a + b*asinh(c*x))**n*(c**S(2)*x**S(2) + S(1))**p, x), x) def replacement6137(a, b, c, d1, d2, e1, e2, n, p, x): return Dist((-d1*d2)**(p + S(-1)/2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((a + b*acosh(c*x))**n*(c*x + S(-1))**p*(c*x + S(1))**p, x), x) def With6138(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6139(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) + Dist(a + b*acosh(c*x), u, x) def replacement6140(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n, (d + e*x**S(2))**p, x), x) def replacement6141(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n, (d + e*x**S(2))**p, x), x) def replacement6142(a, b, c, d, e, n, p, x): return Int((a + b*asinh(c*x))**n*(d + e*x**S(2))**p, x) def replacement6143(a, b, c, d, e, n, p, x): return Int((a + b*acosh(c*x))**n*(d + e*x**S(2))**p, x) def replacement6144(a, b, c, d1, d2, e1, e2, n, p, x): return Int((a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x) def replacement6145(a, b, c, d, e, f, g, n, p, x): return Dist((d + e*x)**FracPart(p)*(f + g*x)**FracPart(p)*(d*f + e*g*x**S(2))**(-FracPart(p)), Int((a + b*asinh(c*x))**n*(d*f + e*g*x**S(2))**p, x), x) def replacement6146(a, b, c, d, e, n, p, x): return Dist((-d)**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p)), Int((a + b*acosh(c*x))**n*(c*x + S(-1))**p*(c*x + S(1))**p, x), x) def replacement6147(a, b, c, d, e, n, x): return Dist(S(1)/e, Subst(Int((a + b*x)**n*tanh(x), x), x, asinh(c*x)), x) def replacement6148(a, b, c, d, e, n, x): return Dist(S(1)/e, Subst(Int((a + b*x)**n/tanh(x), x), x, acosh(c*x)), x) def replacement6149(a, b, c, d, e, n, p, x): return -Dist(b*n*(-d)**p/(S(2)*c*(p + S(1))), Int((a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp((a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6150(a, b, c, d, e, n, p, x): return -Dist(b*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6151(a, b, c, d1, d2, e1, e2, n, p, x): return -Dist(b*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(1)/2), x), x) + Simp((a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*e1*e2*(p + S(1))), x) def replacement6152(a, b, c, d1, d2, e1, e2, n, p, x): return -Dist(b*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp((a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*e1*e2*(p + S(1))), x) def replacement6153(a, b, c, d, e, n, x): return Dist(S(1)/d, Subst(Int((a + b*x)**n/(sinh(x)*cosh(x)), x), x, asinh(c*x)), x) def replacement6154(a, b, c, d, e, n, x): return -Dist(S(1)/d, Subst(Int((a + b*x)**n/(sinh(x)*cosh(x)), x), x, acosh(c*x)), x) def replacement6155(a, b, c, d, e, f, m, n, p, x): return Dist(b*c*n*(-d)**p/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement6156(a, b, c, d, e, f, m, n, p, x): return -Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement6157(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(d1*d2*f*(m + S(1))), x) def replacement6158(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(d1*d2*f*(m + S(1))), x) def replacement6159(a, b, c, d, e, p, x): return Dist(d, Int((a + b*asinh(c*x))*(d + e*x**S(2))**(p + S(-1))/x, x), x) - Dist(b*c*d**p/(S(2)*p), Int((c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((a + b*asinh(c*x))*(d + e*x**S(2))**p/(S(2)*p), x) def replacement6160(a, b, c, d, e, p, x): return Dist(d, Int((a + b*acosh(c*x))*(d + e*x**S(2))**(p + S(-1))/x, x), x) - Dist(b*c*(-d)**p/(S(2)*p), Int((c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((a + b*acosh(c*x))*(d + e*x**S(2))**p/(S(2)*p), x) def replacement6161(a, b, c, d, e, f, m, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*asinh(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**p/(f*(m + S(1))), Int((f*x)**(m + S(1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))*(d + e*x**S(2))**p/(f*(m + S(1))), x) def replacement6162(a, b, c, d, e, f, m, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acosh(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*(-d)**p/(f*(m + S(1))), Int((f*x)**(m + S(1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))*(d + e*x**S(2))**p/(f*(m + S(1))), x) def With6163(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6164(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) + Dist(a + b*acosh(c*x), u, x) def With6165(a, b, c, d, e, m, p, x): u = IntHide(x**m*(c**S(2)*x**S(2) + S(1))**p, x) return Dist(d**p*(a + b*asinh(c*x)), u, x) - Dist(b*c*d**p, Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) def With6166(a, b, c, d1, d2, e1, e2, m, p, x): u = IntHide(x**m*(c*x + S(-1))**p*(c*x + S(1))**p, x) return Dist((-d1*d2)**p*(a + b*acosh(c*x)), u, x) - Dist(b*c*(-d1*d2)**p, Int(SimplifyIntegrand(u/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) def With6167(a, b, c, d, e, m, p, x): u = IntHide(x**m*(c**S(2)*x**S(2) + S(1))**p, x) return -Dist(b*c*d**(p + S(-1)/2)*sqrt(d + e*x**S(2))/sqrt(c**S(2)*x**S(2) + S(1)), Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), Int(x**m*(d + e*x**S(2))**p, x), x) def With6168(a, b, c, d1, d2, e1, e2, m, p, x): u = IntHide(x**m*(c*x + S(-1))**p*(c*x + S(1))**p, x) return -Dist(b*c*(-d1*d2)**(p + S(-1)/2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int(SimplifyIntegrand(u/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) + Dist(a + b*acosh(c*x), Int(x**m*(d1 + e1*x)**p*(d2 + e2*x)**p, x), x) def replacement6169(a, b, c, d, e, f, m, n, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*n*(-d)**p/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(1))), x) def replacement6170(a, b, c, d, e, f, m, n, x): return -Dist(c**S(2)*sqrt(d + e*x**S(2))/(f**S(2)*(m + S(1))*sqrt(c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(2))*(a + b*asinh(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) - Dist(b*c*n*sqrt(d + e*x**S(2))/(f*(m + S(1))*sqrt(c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))**n*sqrt(d + e*x**S(2))/(f*(m + S(1))), x) def replacement6171(a, b, c, d1, d2, e1, e2, f, m, n, x): return -Dist(c**S(2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(f**S(2)*(m + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((f*x)**(m + S(2))*(a + b*acosh(c*x))**n/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) - Dist(b*c*n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(f*(m + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(f*(m + S(1))), x) def replacement6172(a, b, c, d, e, f, m, n, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(1))), x) def replacement6173(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return -Dist(S(2)*e1*e2*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(-1))*(d2 + e2*x)**(p + S(-1)), x), x) - Dist(b*c*n*(-d1*d2)**(p + S(-1)/2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(f*(m + S(1))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p/(f*(m + S(1))), x) def replacement6174(a, b, c, d, e, f, m, n, p, x): return Dist(S(2)*d*p/(m + S(2)*p + S(1)), Int((f*x)**m*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*n*(-d)**p/(f*(m + S(2)*p + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(2)*p + S(1))), x) def replacement6175(a, b, c, d, e, f, m, n, x): return Dist(sqrt(d + e*x**S(2))/((m + S(2))*sqrt(c**S(2)*x**S(2) + S(1))), Int((f*x)**m*(a + b*asinh(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) - Dist(b*c*n*sqrt(d + e*x**S(2))/(f*(m + S(2))*sqrt(c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))**n*sqrt(d + e*x**S(2))/(f*(m + S(2))), x) def replacement6176(a, b, c, d1, d2, e1, e2, f, m, n, x): return -Dist(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/((m + S(2))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((f*x)**m*(a + b*acosh(c*x))**n/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) - Dist(b*c*n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(f*(m + S(2))*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(f*(m + S(2))), x) def replacement6177(a, b, c, d, e, f, m, n, p, x): return Dist(S(2)*d*p/(m + S(2)*p + S(1)), Int((f*x)**m*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(2)*p + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(2)*p + S(1))), x) def replacement6178(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(S(2)*d1*d2*p/(m + S(2)*p + S(1)), Int((f*x)**m*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(-1))*(d2 + e2*x)**(p + S(-1)), x), x) - Dist(b*c*n*(-d1*d2)**(p + S(-1)/2)*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(f*sqrt(c*x + S(-1))*sqrt(c*x + S(1))*(m + S(2)*p + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p/(f*(m + S(2)*p + S(1))), x) def replacement6179(a, b, c, d, e, f, m, n, p, x): return Dist(c**S(2)*(m + S(2)*p + S(3))/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**p, x), x) + Dist(b*c*n*(-d)**p/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement6180(a, b, c, d, e, f, m, n, p, x): return -Dist(c**S(2)*(m + S(2)*p + S(3))/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p, x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement6181(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(c**S(2)*(m + S(2)*p + S(3))/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x), x) + Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(d1*d2*f*(m + S(1))), x) def replacement6182(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(c**S(2)*(m + S(2)*p + S(3))/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x), x) + Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(d1*d2*f*(m + S(1))), x) def replacement6183(a, b, c, d, e, f, m, n, p, x): return -Dist(f**S(2)*(m + S(-1))/(S(2)*e*(p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b*f*n*(-d)**p/(S(2)*c*(p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6184(a, b, c, d, e, f, m, n, p, x): return -Dist(f**S(2)*(m + S(-1))/(S(2)*e*(p + S(1))), Int((f*x)**(m + S(-2))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b*d**IntPart(p)*f*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((f*x)**(m + S(-1))*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6185(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return -Dist(f**S(2)*(m + S(-1))/(S(2)*e1*e2*(p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1)), x), x) - Dist(b*f*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*e1*e2*(p + S(1))), x) def replacement6186(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return -Dist(f**S(2)*(m + S(-1))/(S(2)*e1*e2*(p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1)), x), x) - Dist(b*f*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*e1*e2*(p + S(1))), x) def replacement6187(a, b, c, d, e, f, m, n, p, x): return Dist((m + S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((f*x)**m*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b*c*n*(-d)**p/(S(2)*f*(p + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) - Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*f*(p + S(1))), x) def replacement6188(a, b, c, d, e, f, m, n, p, x): return Dist((m + S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((f*x)**m*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*f*(p + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) - Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*f*(p + S(1))), x) def replacement6189(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist((m + S(2)*p + S(3))/(S(2)*d1*d2*(p + S(1))), Int((f*x)**m*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1)), x), x) - Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*f*(p + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(1)/2), x), x) - Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*d1*d2*f*(p + S(1))), x) def replacement6190(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist((m + S(2)*p + S(3))/(S(2)*d1*d2*(p + S(1))), Int((f*x)**m*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1)), x), x) - Dist(b*c*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(S(2)*f*(p + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) - Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(S(2)*d1*d2*f*(p + S(1))), x) def replacement6191(a, b, c, d, e, f, m, n, x): return -Dist(f**S(2)*(m + S(-1))/(c**S(2)*m), Int((f*x)**(m + S(-2))*(a + b*asinh(c*x))**n/sqrt(d + e*x**S(2)), x), x) - Dist(b*f*n*sqrt(c**S(2)*x**S(2) + S(1))/(c*m*sqrt(d + e*x**S(2))), Int((f*x)**(m + S(-1))*(a + b*asinh(c*x))**(n + S(-1)), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*asinh(c*x))**n*sqrt(d + e*x**S(2))/(e*m), x) def replacement6192(a, b, c, d1, d2, e1, e2, f, m, n, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*m), Int((f*x)**(m + S(-2))*(a + b*acosh(c*x))**n/(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), x), x) + Dist(b*f*n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(c*d1*d2*m*sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(-1)), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acosh(c*x))**n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)/(e1*e2*m), x) def replacement6193(a, b, c, d, e, m, n, x): return Dist(c**(-m + S(-1))/sqrt(d), Subst(Int((a + b*x)**n*sinh(x)**m, x), x, asinh(c*x)), x) def replacement6194(a, b, c, d1, d2, e1, e2, m, n, x): return Dist(c**(-m + S(-1))/sqrt(-d1*d2), Subst(Int((a + b*x)**n*cosh(x)**m, x), x, acosh(c*x)), x) def replacement6195(a, b, c, d, e, f, m, x): return Simp((f*x)**(m + S(1))*(a + b*asinh(c*x))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, -c**S(2)*x**S(2))/(sqrt(d)*f*(m + S(1))), x) - Simp(b*c*(f*x)**(m + S(2))*HypergeometricPFQ(List(S(1), m/S(2) + S(1), m/S(2) + S(1)), List(m/S(2) + S(3)/2, m/S(2) + S(2)), -c**S(2)*x**S(2))/(sqrt(d)*f**S(2)*(m + S(1))*(m + S(2))), x) def replacement6196(a, b, c, d1, d2, e1, e2, f, m, x): return Simp(b*c*(f*x)**(m + S(2))*HypergeometricPFQ(List(S(1), m/S(2) + S(1), m/S(2) + S(1)), List(m/S(2) + S(3)/2, m/S(2) + S(2)), c**S(2)*x**S(2))/(f**S(2)*sqrt(-d1*d2)*(m + S(1))*(m + S(2))), x) + Simp((f*x)**(m + S(1))*(a + b*acosh(c*x))*sqrt(-c**S(2)*x**S(2) + S(1))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, c**S(2)*x**S(2))/(f*sqrt(d1 + e1*x)*sqrt(d2 + e2*x)*(m + S(1))), x) def replacement6197(a, b, c, d, e, f, m, n, x): return Dist(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((f*x)**m*(a + b*asinh(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) def replacement6198(a, b, c, d1, d2, e1, e2, f, m, n, x): return Dist(sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), Int((f*x)**m*(a + b*acosh(c*x))**n/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) def replacement6199(a, b, c, d, e, f, m, n, p, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**p, x), x) - Dist(b*f*n*(-d)**p/(c*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acosh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(e*(m + S(2)*p + S(1))), x) def replacement6200(a, b, c, d, e, f, m, n, p, x): return -Dist(f**S(2)*(m + S(-1))/(c**S(2)*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-2))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p, x), x) - Dist(b*d**IntPart(p)*f*n*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(c*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-1))*(a + b*asinh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*asinh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(e*(m + S(2)*p + S(1))), x) def replacement6201(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x), x) - Dist(b*f*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(c*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(-1))*(c**S(2)*x**S(2) + S(-1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(e1*e2*(m + S(2)*p + S(1))), x) def replacement6202(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x), x) - Dist(b*f*n*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(c*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(-1))*(c*x + S(-1))**(p + S(1)/2)*(c*x + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acosh(c*x))**n*(d1 + e1*x)**(p + S(1))*(d2 + e2*x)**(p + S(1))/(e1*e2*(m + S(2)*p + S(1))), x) def replacement6203(a, b, c, d, e, f, m, n, p, x): return Dist(f*m*(-d)**p/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*acosh(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6204(a, b, c, d, e, f, m, n, p, x): return -Dist(d**IntPart(p)*f*m*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*asinh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*asinh(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement6205(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(f*m*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(-1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*acosh(c*x))**(n + S(1))*(d1 + e1*x)**p*(d2 + e2*x)**p*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6206(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(f*m*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*acosh(c*x))**(n + S(1))*(d1 + e1*x)**p*(d2 + e2*x)**p*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6207(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*c*sqrt(d)*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*asinh(c*x))**(n + S(1)), x), x) + Simp((f*x)**m*(a + b*asinh(c*x))**(n + S(1))/(b*c*sqrt(d)*(n + S(1))), x) def replacement6208(a, b, c, d1, d2, e1, e2, f, m, n, x): return -Dist(f*m/(b*c*sqrt(-d1*d2)*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(1)), x), x) + Simp((f*x)**m*(a + b*acosh(c*x))**(n + S(1))/(b*c*sqrt(-d1*d2)*(n + S(1))), x) def replacement6209(a, b, c, d, e, f, m, n, x): return Dist(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((f*x)**m*(a + b*asinh(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) def replacement6210(a, b, c, d1, d2, e1, e2, f, m, n, x): return Dist(sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), Int((f*x)**m*(a + b*acosh(c*x))**n/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) def replacement6211(a, b, c, d, e, f, m, n, p, x): return Dist(f*m*(-d)**p/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) - Dist(c*(-d)**p*(m + S(2)*p + S(1))/(b*f*(n + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(1))*(c*x + S(-1))**(p + S(-1)/2)*(c*x + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*acosh(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6212(a, b, c, d, e, f, m, n, p, x): return -Dist(d**IntPart(p)*f*m*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*asinh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) - Dist(c*d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p))*(m + S(2)*p + S(1))/(b*f*(n + S(1))), Int((f*x)**(m + S(1))*(a + b*asinh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*asinh(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement6213(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Dist(f*m*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acosh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(-1))**(p + S(-1)/2), x), x) - Dist(c*(-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p))*(m + S(2)*p + S(1))/(b*f*(n + S(1))), Int((f*x)**(m + S(1))*(a + b*acosh(c*x))**(n + S(1))*(c**S(2)*x**S(2) + S(-1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*acosh(c*x))**(n + S(1))*(d1 + e1*x)**p*(d2 + e2*x)**p*sqrt(c*x + S(-1))*sqrt(c*x + S(1))/(b*c*(n + S(1))), x) def replacement6214(a, b, c, d, e, m, n, p, x): return Dist(c**(-m + S(-1))*d**p, Subst(Int((a + b*x)**n*sinh(x)**m*cosh(x)**(S(2)*p + S(1)), x), x, asinh(c*x)), x) def replacement6215(a, b, c, d, e, m, n, p, x): return Dist(c**(-m + S(-1))*(-d)**p, Subst(Int((a + b*x)**n*sinh(x)**(S(2)*p + S(1))*cosh(x)**m, x), x, acosh(c*x)), x) def replacement6216(a, b, c, d1, d2, e1, e2, m, n, p, x): return Dist(c**(-m + S(-1))*(-d1*d2)**p, Subst(Int((a + b*x)**n*sinh(x)**(S(2)*p + S(1))*cosh(x)**m, x), x, acosh(c*x)), x) def replacement6217(a, b, c, d, e, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int(x**m*(a + b*asinh(c*x))**n*(c**S(2)*x**S(2) + S(1))**p, x), x) def replacement6218(a, b, c, d1, d2, e1, e2, m, n, p, x): return Dist((-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p)), Int(x**m*(a + b*acosh(c*x))**n*(c*x + S(-1))**p*(c*x + S(1))**p, x), x) def replacement6219(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n/sqrt(d + e*x**S(2)), (f*x)**m*(d + e*x**S(2))**(p + S(1)/2), x), x) def replacement6220(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n/(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), (f*x)**m*(d1 + e1*x)**(p + S(1)/2)*(d2 + e2*x)**(p + S(1)/2), x), x) def replacement6221(a, b, c, d, e, f, m, x): return -Dist(b*c/(f*(m + S(1))*(m + S(3))), Int((f*x)**(m + S(1))*(d*(m + S(3)) + e*x**S(2)*(m + S(1)))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp(d*(f*x)**(m + S(1))*(a + b*acosh(c*x))/(f*(m + S(1))), x) + Simp(e*(f*x)**(m + S(3))*(a + b*acosh(c*x))/(f**S(3)*(m + S(3))), x) def replacement6222(a, b, c, d, e, p, x): return -Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*asinh(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6223(a, b, c, d, e, p, x): return -Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp((a + b*acosh(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def With6224(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6225(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) + Dist(a + b*acosh(c*x), u, x) def replacement6226(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n, (f*x)**m*(d + e*x**S(2))**p, x), x) def replacement6227(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n, (f*x)**m*(d + e*x**S(2))**p, x), x) def replacement6228(a, b, c, d, e, f, m, n, p, x): return Int((f*x)**m*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p, x) def replacement6229(a, b, c, d, e, f, m, n, p, x): return Int((f*x)**m*(a + b*acosh(c*x))**n*(d + e*x**S(2))**p, x) def replacement6230(a, b, c, d1, d2, e1, e2, f, m, n, p, x): return Int((f*x)**m*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x) def replacement6231(a, b, c, d, e, f, g, h, m, n, p, x): return Dist((d + e*x)**FracPart(p)*(f + g*x)**FracPart(p)*(d*f + e*g*x**S(2))**(-FracPart(p)), Int((h*x)**m*(a + b*asinh(c*x))**n*(d*f + e*g*x**S(2))**p, x), x) def replacement6232(a, b, c, d, e, f, m, n, p, x): return Dist((-d)**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p)), Int((f*x)**m*(a + b*acosh(c*x))**n*(c*x + S(-1))**p*(c*x + S(1))**p, x), x) def replacement6233(a, b, c, d, e, n, x): return Subst(Int((a + b*x)**n*cosh(x)/(c*d + e*sinh(x)), x), x, asinh(c*x)) def replacement6234(a, b, c, d, e, n, x): return Subst(Int((a + b*x)**n*sinh(x)/(c*d + e*cosh(x)), x), x, acosh(c*x)) def replacement6235(a, b, c, d, e, m, n, x): return -Dist(b*c*n/(e*(m + S(1))), Int((a + b*asinh(c*x))**(n + S(-1))*(d + e*x)**(m + S(1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*asinh(c*x))**n*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def replacement6236(a, b, c, d, e, m, n, x): return -Dist(b*c*n/(e*(m + S(1))), Int((a + b*acosh(c*x))**(n + S(-1))*(d + e*x)**(m + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x) + Simp((a + b*acosh(c*x))**n*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def replacement6237(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n*(d + e*x)**m, x), x) def replacement6238(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n*(d + e*x)**m, x), x) def replacement6239(a, b, c, d, e, m, n, x): return Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(c*d + e*sinh(x))**m*cosh(x), x), x, asinh(c*x)), x) def replacement6240(a, b, c, d, e, m, n, x): return Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(c*d + e*cosh(x))**m*sinh(x), x), x, acosh(c*x)), x) def With6241(Px, a, b, c, x): u = IntHide(Px, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6242(Px, a, b, c, x): u = IntHide(Px, x) return -Dist(b*c*sqrt(-c**S(2)*x**S(2) + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acosh(c*x), u, x) def replacement6243(Px, a, b, c, n, x): return Int(ExpandIntegrand(Px*(a + b*asinh(c*x))**n, x), x) def replacement6244(Px, a, b, c, n, x): return Int(ExpandIntegrand(Px*(a + b*acosh(c*x))**n, x), x) def With6245(Px, a, b, c, d, e, m, x): u = IntHide(Px*(d + e*x)**m, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6246(Px, a, b, c, d, e, m, x): u = IntHide(Px*(d + e*x)**m, x) return -Dist(b*c*sqrt(-c**S(2)*x**S(2) + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acosh(c*x), u, x) def With6247(a, b, c, d, e, f, g, m, n, p, x): u = IntHide((d + e*x)**m*(f + g*x)**p, x) return -Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*asinh(c*x))**(n + S(-1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist((a + b*asinh(c*x))**n, u, x) def With6248(a, b, c, d, e, f, g, m, n, p, x): u = IntHide((d + e*x)**m*(f + g*x)**p, x) return -Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*acosh(c*x))**(n + S(-1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) + Dist((a + b*acosh(c*x))**n, u, x) def With6249(a, b, c, d, e, f, g, h, n, p, x): u = IntHide((f + g*x + h*x**S(2))**p/(d + e*x)**S(2), x) return -Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*asinh(c*x))**(n + S(-1))/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist((a + b*asinh(c*x))**n, u, x) def With6250(a, b, c, d, e, f, g, h, n, p, x): u = IntHide((f + g*x + h*x**S(2))**p/(d + e*x)**S(2), x) return -Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*acosh(c*x))**(n + S(-1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), x), x), x) + Dist((a + b*acosh(c*x))**n, u, x) def replacement6251(Px, a, b, c, d, e, m, n, x): return Int(ExpandIntegrand(Px*(a + b*asinh(c*x))**n*(d + e*x)**m, x), x) def replacement6252(Px, a, b, c, d, e, m, n, x): return Int(ExpandIntegrand(Px*(a + b*acosh(c*x))**n*(d + e*x)**m, x), x) def With6253(a, b, c, d, e, f, g, m, p, x): u = IntHide((d + e*x**S(2))**p*(f + g*x)**m, x) return -Dist(b*c, Int(Dist(S(1)/sqrt(c**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6254(a, b, c, d1, d2, e1, e2, f, g, m, p, x): u = IntHide((d1 + e1*x)**p*(d2 + e2*x)**p*(f + g*x)**m, x) return -Dist(b*c, Int(Dist(S(1)/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), u, x), x), x) + Dist(a + b*acosh(c*x), u, x) def replacement6255(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n*(d + e*x**S(2))**p, (f + g*x)**m, x), x) def replacement6256(a, b, c, d1, d2, e1, e2, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, (f + g*x)**m, x), x) def replacement6257(a, b, c, d, e, f, g, m, n, x): return -Dist(S(1)/(b*c*sqrt(d)*(n + S(1))), Int((a + b*asinh(c*x))**(n + S(1))*(f + g*x)**(m + S(-1))*(d*g*m + S(2)*e*f*x + e*g*x**S(2)*(m + S(2))), x), x) + Simp((a + b*asinh(c*x))**(n + S(1))*(d + e*x**S(2))*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement6258(a, b, c, d1, d2, e1, e2, f, g, m, n, x): return -Dist(S(1)/(b*c*sqrt(-d1*d2)*(n + S(1))), Int((a + b*acosh(c*x))**(n + S(1))*(f + g*x)**(m + S(-1))*(d1*d2*g*m + S(2)*e1*e2*f*x + e1*e2*g*x**S(2)*(m + S(2))), x), x) + Simp((a + b*acosh(c*x))**(n + S(1))*(f + g*x)**m*(d1*d2 + e1*e2*x**S(2))/(b*c*sqrt(-d1*d2)*(n + S(1))), x) def replacement6259(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n*sqrt(d + e*x**S(2)), (d + e*x**S(2))**(p + S(-1)/2)*(f + g*x)**m, x), x) def replacement6260(a, b, c, d1, d2, e1, e2, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n*sqrt(d1 + e1*x)*sqrt(d2 + e2*x), (d1 + e1*x)**(p + S(-1)/2)*(d2 + e2*x)**(p + S(-1)/2)*(f + g*x)**m, x), x) def replacement6261(a, b, c, d, e, f, g, m, n, p, x): return -Dist(S(1)/(b*c*sqrt(d)*(n + S(1))), Int(ExpandIntegrand((a + b*asinh(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), (d + e*x**S(2))**(p + S(-1)/2)*(d*g*m + e*f*x*(S(2)*p + S(1)) + e*g*x**S(2)*(m + S(2)*p + S(1))), x), x), x) + Simp((a + b*asinh(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1)/2)*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement6262(a, b, c, d1, d2, e1, e2, f, g, m, n, p, x): return -Dist(S(1)/(b*c*sqrt(-d1*d2)*(n + S(1))), Int(ExpandIntegrand((a + b*acosh(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), (d1 + e1*x)**(p + S(-1)/2)*(d2 + e2*x)**(p + S(-1)/2)*(d1*d2*g*m + e1*e2*f*x*(S(2)*p + S(1)) + e1*e2*g*x**S(2)*(m + S(2)*p + S(1))), x), x), x) + Simp((a + b*acosh(c*x))**(n + S(1))*(d1 + e1*x)**(p + S(1)/2)*(d2 + e2*x)**(p + S(1)/2)*(f + g*x)**m/(b*c*sqrt(-d1*d2)*(n + S(1))), x) def replacement6263(a, b, c, d, e, f, g, m, n, x): return -Dist(g*m/(b*c*sqrt(d)*(n + S(1))), Int((a + b*asinh(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), x), x) + Simp((a + b*asinh(c*x))**(n + S(1))*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement6264(a, b, c, d1, d2, e1, e2, f, g, m, n, x): return -Dist(g*m/(b*c*sqrt(-d1*d2)*(n + S(1))), Int((a + b*acosh(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), x), x) + Simp((a + b*acosh(c*x))**(n + S(1))*(f + g*x)**m/(b*c*sqrt(-d1*d2)*(n + S(1))), x) def replacement6265(a, b, c, d, e, f, g, m, n, x): return Dist(c**(-m + S(-1))/sqrt(d), Subst(Int((a + b*x)**n*(c*f + g*sinh(x))**m, x), x, asinh(c*x)), x) def replacement6266(a, b, c, d1, d2, e1, e2, f, g, m, n, x): return Dist(c**(-m + S(-1))/sqrt(-d1*d2), Subst(Int((a + b*x)**n*(c*f + g*cosh(x))**m, x), x, acosh(c*x)), x) def replacement6267(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n/sqrt(d + e*x**S(2)), (d + e*x**S(2))**(p + S(1)/2)*(f + g*x)**m, x), x) def replacement6268(a, b, c, d1, d2, e1, e2, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n/(sqrt(d1 + e1*x)*sqrt(d2 + e2*x)), (d1 + e1*x)**(p + S(1)/2)*(d2 + e2*x)**(p + S(1)/2)*(f + g*x)**m, x), x) def replacement6269(a, b, c, d, e, f, g, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a + b*asinh(c*x))**n*(f + g*x)**m*(c**S(2)*x**S(2) + S(1))**p, x), x) def replacement6270(a, b, c, d, e, f, g, m, n, p, x): return Dist((-d)**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p)), Int((a + b*acosh(c*x))**n*(f + g*x)**m*(c*x + S(-1))**p*(c*x + S(1))**p, x), x) def replacement6271(a, b, c, d1, d2, e1, e2, f, g, m, n, p, x): return Dist((-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a + b*acosh(c*x))**n*(f + g*x)**m*(c*x + S(-1))**p*(c*x + S(1))**p, x), x) def replacement6272(a, b, c, d, e, f, g, h, m, n, x): return -Dist(g*m/(b*c*sqrt(d)*(n + S(1))), Int((a + b*asinh(c*x))**(n + S(1))/(f + g*x), x), x) + Simp((a + b*asinh(c*x))**(n + S(1))*log(h*(f + g*x)**m)/(b*c*sqrt(d)*(n + S(1))), x) def replacement6273(a, b, c, d1, d2, e1, e2, f, g, h, m, n, x): return -Dist(g*m/(b*c*sqrt(-d1*d2)*(n + S(1))), Int((a + b*acosh(c*x))**(n + S(1))/(f + g*x), x), x) + Simp((a + b*acosh(c*x))**(n + S(1))*log(h*(f + g*x)**m)/(b*c*sqrt(-d1*d2)*(n + S(1))), x) def replacement6274(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a + b*asinh(c*x))**n*(c**S(2)*x**S(2) + S(1))**p*log(h*(f + g*x)**m), x), x) def replacement6275(a, b, c, d, e, f, g, h, m, n, p, x): return Dist((-d)**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p)), Int((a + b*acosh(c*x))**n*(c*x + S(-1))**p*(c*x + S(1))**p*log(h*(f + g*x)**m), x), x) def replacement6276(a, b, c, d1, d2, e1, e2, f, g, h, m, n, p, x): return Dist((-d1*d2)**IntPart(p)*(d1 + e1*x)**FracPart(p)*(d2 + e2*x)**FracPart(p)*(c*x + S(-1))**(-FracPart(p))*(c*x + S(1))**(-FracPart(p)), Int((a + b*acosh(c*x))**n*(c*x + S(-1))**p*(c*x + S(1))**p*log(h*(f + g*x)**m), x), x) def With6277(a, b, c, d, e, f, g, m, x): u = IntHide((d + e*x)**m*(f + g*x)**m, x) return -Dist(b*c, Int(Dist(S(1)/sqrt(c**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(a + b*asinh(c*x), u, x) def With6278(a, b, c, d, e, f, g, m, x): u = IntHide((d + e*x)**m*(f + g*x)**m, x) return -Dist(b*c, Int(Dist(S(1)/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), u, x), x), x) + Dist(a + b*acosh(c*x), u, x) def replacement6279(a, b, c, d, e, f, g, m, n, x): return Int(ExpandIntegrand((a + b*asinh(c*x))**n, (d + e*x)**m*(f + g*x)**m, x), x) def replacement6280(a, b, c, d, e, f, g, m, n, x): return Int(ExpandIntegrand((a + b*acosh(c*x))**n, (d + e*x)**m*(f + g*x)**m, x), x) def With6281(a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False v = IntHide(u, x) if InverseFunctionFreeQ(v, x): return True return False def replacement6281(a, b, c, u, x): v = IntHide(u, x) return -Dist(b*c, Int(SimplifyIntegrand(v/sqrt(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(c*x), v, x) def With6282(a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False v = IntHide(u, x) if InverseFunctionFreeQ(v, x): return True return False def replacement6282(a, b, c, u, x): v = IntHide(u, x) return -Dist(b*c*sqrt(-c**S(2)*x**S(2) + S(1))/(sqrt(c*x + S(-1))*sqrt(c*x + S(1))), Int(SimplifyIntegrand(v/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acosh(c*x), v, x) def With6283(Px, a, b, c, d, e, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p, x) if SumQ(u): return True return False def replacement6283(Px, a, b, c, d, e, n, p, x): u = ExpandIntegrand(Px*(a + b*asinh(c*x))**n*(d + e*x**S(2))**p, x) return Int(u, x) def With6284(Px, a, b, c, d1, d2, e1, e2, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x) if SumQ(u): return True return False def replacement6284(Px, a, b, c, d1, d2, e1, e2, n, p, x): u = ExpandIntegrand(Px*(a + b*acosh(c*x))**n*(d1 + e1*x)**p*(d2 + e2*x)**p, x) return Int(u, x) def With6285(Px, a, b, c, d, e, f, g, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*asinh(c*x))**n*(f + g*(d + e*x**S(2))**p)**m, x) if SumQ(u): return True return False def replacement6285(Px, a, b, c, d, e, f, g, m, n, p, x): u = ExpandIntegrand(Px*(a + b*asinh(c*x))**n*(f + g*(d + e*x**S(2))**p)**m, x) return Int(u, x) def With6286(Px, a, b, c, d1, d2, e1, e2, f, g, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*acosh(c*x))**n*(f + g*(d1 + e1*x)**p*(d2 + e2*x)**p)**m, x) if SumQ(u): return True return False def replacement6286(Px, a, b, c, d1, d2, e1, e2, f, g, m, n, p, x): u = ExpandIntegrand(Px*(a + b*acosh(c*x))**n*(f + g*(d1 + e1*x)**p*(d2 + e2*x)**p)**m, x) return Int(u, x) def With6287(RFx, c, n, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(asinh(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement6287(RFx, c, n, x): u = ExpandIntegrand(asinh(c*x)**n, RFx, x) return Int(u, x) def With6288(RFx, c, n, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(acosh(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement6288(RFx, c, n, x): u = ExpandIntegrand(acosh(c*x)**n, RFx, x) return Int(u, x) def replacement6289(RFx, a, b, c, n, x): return Int(ExpandIntegrand(RFx*(a + b*asinh(c*x))**n, x), x) def replacement6290(RFx, a, b, c, n, x): return Int(ExpandIntegrand(RFx*(a + b*acosh(c*x))**n, x), x) def With6291(RFx, c, d, e, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((d + e*x**S(2))**p*asinh(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement6291(RFx, c, d, e, n, p, x): u = ExpandIntegrand((d + e*x**S(2))**p*asinh(c*x)**n, RFx, x) return Int(u, x) def With6292(RFx, c, d1, d2, e1, e2, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((d1 + e1*x)**p*(d2 + e2*x)**p*acosh(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement6292(RFx, c, d1, d2, e1, e2, n, p, x): u = ExpandIntegrand((d1 + e1*x)**p*(d2 + e2*x)**p*acosh(c*x)**n, RFx, x) return Int(u, x) def replacement6293(RFx, a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((d + e*x**S(2))**p, RFx*(a + b*asinh(c*x))**n, x), x) def replacement6294(RFx, a, b, c, d1, d2, e1, e2, n, p, x): return Int(ExpandIntegrand((d1 + e1*x)**p*(d2 + e2*x)**p, RFx*(a + b*acosh(c*x))**n, x), x) def replacement6295(a, b, c, n, u, x): return Int(u*(a + b*asinh(c*x))**n, x) def replacement6296(a, b, c, n, u, x): return Int(u*(a + b*acosh(c*x))**n, x) def replacement6297(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*asinh(x))**n, x), x, c + d*x), x) def replacement6298(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*acosh(x))**n, x), x, c + d*x), x) def replacement6299(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*asinh(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6300(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*acosh(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6301(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*asinh(x))**n*(C*x**S(2)/d**S(2) + C/d**S(2))**p, x), x, c + d*x), x) def replacement6302(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acosh(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p, x), x, c + d*x), x) def replacement6303(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*asinh(x))**n*(C*x**S(2)/d**S(2) + C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6304(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acosh(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6305(a, b, c, d, x): return Simp(x*sqrt(a + b*asinh(c + d*x**S(2))), x) - Simp(sqrt(Pi)*x*(-c*sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*FresnelC(sqrt(-c/(Pi*b))*sqrt(a + b*asinh(c + d*x**S(2))))/(sqrt(-c/b)*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) + Simp(sqrt(Pi)*x*(c*sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*FresnelS(sqrt(-c/(Pi*b))*sqrt(a + b*asinh(c + d*x**S(2))))/(sqrt(-c/b)*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) def replacement6306(a, b, c, d, n, x): return Dist(S(4)*b**S(2)*n*(n + S(-1)), Int((a + b*asinh(c + d*x**S(2)))**(n + S(-2)), x), x) + Simp(x*(a + b*asinh(c + d*x**S(2)))**n, x) - Simp(S(2)*b*n*(a + b*asinh(c + d*x**S(2)))**(n + S(-1))*sqrt(S(2)*c*d*x**S(2) + d**S(2)*x**S(4))/(d*x), x) def replacement6307(a, b, c, d, x): return Simp(x*(-c*sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*SinhIntegral((a + b*asinh(c + d*x**S(2)))/(S(2)*b))/(S(2)*b*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) + Simp(x*(c*cosh(a/(S(2)*b)) - sinh(a/(S(2)*b)))*CoshIntegral((a + b*asinh(c + d*x**S(2)))/(S(2)*b))/(S(2)*b*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) def replacement6308(a, b, c, d, x): return Simp(sqrt(S(2))*sqrt(Pi)*x*(c + S(-1))*(sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erf(sqrt(S(2))*sqrt(a + b*asinh(c + d*x**S(2)))/(S(2)*sqrt(b)))/(S(4)*sqrt(b)*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) + Simp(sqrt(S(2))*sqrt(Pi)*x*(c + S(1))*(-sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erfi(sqrt(S(2))*sqrt(a + b*asinh(c + d*x**S(2)))/(S(2)*sqrt(b)))/(S(4)*sqrt(b)*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) def replacement6309(a, b, c, d, x): return -Simp(sqrt(S(2)*c*d*x**S(2) + d**S(2)*x**S(4))/(b*d*x*sqrt(a + b*asinh(c + d*x**S(2)))), x) - Simp(sqrt(Pi)*x*(-c/b)**(S(3)/2)*(-c*sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*FresnelC(sqrt(-c/(Pi*b))*sqrt(a + b*asinh(c + d*x**S(2))))/(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2))), x) + Simp(sqrt(Pi)*x*(-c/b)**(S(3)/2)*(c*sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*FresnelS(sqrt(-c/(Pi*b))*sqrt(a + b*asinh(c + d*x**S(2))))/(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2))), x) def replacement6310(a, b, c, d, x): return Simp(x*(-c*sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*CoshIntegral((a + b*asinh(c + d*x**S(2)))/(S(2)*b))/(S(4)*b**S(2)*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) + Simp(x*(c*cosh(a/(S(2)*b)) - sinh(a/(S(2)*b)))*SinhIntegral((a + b*asinh(c + d*x**S(2)))/(S(2)*b))/(S(4)*b**S(2)*(c*sinh(asinh(c + d*x**S(2))/S(2)) + cosh(asinh(c + d*x**S(2))/S(2)))), x) - Simp(sqrt(S(2)*c*d*x**S(2) + d**S(2)*x**S(4))/(S(2)*b*d*x*(a + b*asinh(c + d*x**S(2)))), x) def replacement6311(a, b, c, d, n, x): return Dist(S(1)/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), Int((a + b*asinh(c + d*x**S(2)))**(n + S(2)), x), x) - Simp(x*(a + b*asinh(c + d*x**S(2)))**(n + S(2))/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), x) + Simp((a + b*asinh(c + d*x**S(2)))**(n + S(1))*sqrt(S(2)*c*d*x**S(2) + d**S(2)*x**S(4))/(S(2)*b*d*x*(n + S(1))), x) def replacement6312(a, b, d, x): return Simp(S(2)*sqrt(a + b*acosh(d*x**S(2) + S(1)))*sinh(acosh(d*x**S(2) + S(1))/S(2))**S(2)/(d*x), x) - Simp(sqrt(S(2))*sqrt(Pi)*sqrt(b)*(-sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erfi(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(1)))/(S(2)*sqrt(b)))*sinh(acosh(d*x**S(2) + S(1))/S(2))/(S(2)*d*x), x) + Simp(sqrt(S(2))*sqrt(Pi)*sqrt(b)*(sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erf(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(1)))/(S(2)*sqrt(b)))*sinh(acosh(d*x**S(2) + S(1))/S(2))/(S(2)*d*x), x) def replacement6313(a, b, d, x): return Simp(S(2)*sqrt(a + b*acosh(d*x**S(2) + S(-1)))*cosh(acosh(d*x**S(2) + S(-1))/S(2))**S(2)/(d*x), x) - Simp(sqrt(S(2))*sqrt(Pi)*sqrt(b)*(-sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erfi(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*sqrt(b)))*cosh(acosh(d*x**S(2) + S(-1))/S(2))/(S(2)*d*x), x) - Simp(sqrt(S(2))*sqrt(Pi)*sqrt(b)*(sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erf(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*sqrt(b)))*cosh(acosh(d*x**S(2) + S(-1))/S(2))/(S(2)*d*x), x) def replacement6314(a, b, c, d, n, x): return Dist(S(4)*b**S(2)*n*(n + S(-1)), Int((a + b*acosh(c + d*x**S(2)))**(n + S(-2)), x), x) + Simp(x*(a + b*acosh(c + d*x**S(2)))**n, x) - Simp(S(2)*b*n*(a + b*acosh(c + d*x**S(2)))**(n + S(-1))*(S(2)*c*d*x**S(2) + d**S(2)*x**S(4))/(d*x*sqrt(c + d*x**S(2) + S(-1))*sqrt(c + d*x**S(2) + S(1))), x) def replacement6315(a, b, d, x): return Simp(sqrt(S(2))*x*CoshIntegral((a + b*acosh(d*x**S(2) + S(1)))/(S(2)*b))*cosh(a/(S(2)*b))/(S(2)*b*sqrt(d*x**S(2))), x) - Simp(sqrt(S(2))*x*SinhIntegral((a + b*acosh(d*x**S(2) + S(1)))/(S(2)*b))*sinh(a/(S(2)*b))/(S(2)*b*sqrt(d*x**S(2))), x) def replacement6316(a, b, d, x): return -Simp(sqrt(S(2))*x*CoshIntegral((a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*b))*sinh(a/(S(2)*b))/(S(2)*b*sqrt(d*x**S(2))), x) + Simp(sqrt(S(2))*x*SinhIntegral((a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*b))*cosh(a/(S(2)*b))/(S(2)*b*sqrt(d*x**S(2))), x) def replacement6317(a, b, d, x): return Simp(sqrt(S(2))*sqrt(Pi)*(-sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erfi(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(1)))/(S(2)*sqrt(b)))*sinh(acosh(d*x**S(2) + S(1))/S(2))/(S(2)*sqrt(b)*d*x), x) + Simp(sqrt(S(2))*sqrt(Pi)*(sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erf(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(1)))/(S(2)*sqrt(b)))*sinh(acosh(d*x**S(2) + S(1))/S(2))/(S(2)*sqrt(b)*d*x), x) def replacement6318(a, b, d, x): return Simp(sqrt(S(2))*sqrt(Pi)*(-sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erfi(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*sqrt(b)))*cosh(acosh(d*x**S(2) + S(-1))/S(2))/(S(2)*sqrt(b)*d*x), x) - Simp(sqrt(S(2))*sqrt(Pi)*(sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erf(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*sqrt(b)))*cosh(acosh(d*x**S(2) + S(-1))/S(2))/(S(2)*sqrt(b)*d*x), x) def replacement6319(a, b, d, x): return -Simp(sqrt(d*x**S(2))*sqrt(d*x**S(2) + S(2))/(b*d*x*sqrt(a + b*acosh(d*x**S(2) + S(1)))), x) + Simp(sqrt(S(2))*sqrt(Pi)*(-sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erfi(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(1)))/(S(2)*sqrt(b)))*sinh(acosh(d*x**S(2) + S(1))/S(2))/(S(2)*b**(S(3)/2)*d*x), x) - Simp(sqrt(S(2))*sqrt(Pi)*(sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erf(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(1)))/(S(2)*sqrt(b)))*sinh(acosh(d*x**S(2) + S(1))/S(2))/(S(2)*b**(S(3)/2)*d*x), x) def replacement6320(a, b, d, x): return -Simp(sqrt(d*x**S(2))*sqrt(d*x**S(2) + S(-2))/(b*d*x*sqrt(a + b*acosh(d*x**S(2) + S(-1)))), x) + Simp(sqrt(S(2))*sqrt(Pi)*(-sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erfi(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*sqrt(b)))*cosh(acosh(d*x**S(2) + S(-1))/S(2))/(S(2)*b**(S(3)/2)*d*x), x) + Simp(sqrt(S(2))*sqrt(Pi)*(sinh(a/(S(2)*b)) + cosh(a/(S(2)*b)))*Erf(sqrt(S(2))*sqrt(a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*sqrt(b)))*cosh(acosh(d*x**S(2) + S(-1))/S(2))/(S(2)*b**(S(3)/2)*d*x), x) def replacement6321(a, b, d, x): return -Simp(sqrt(S(2))*x*CoshIntegral((a + b*acosh(d*x**S(2) + S(1)))/(S(2)*b))*sinh(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(d*x**S(2))), x) + Simp(sqrt(S(2))*x*SinhIntegral((a + b*acosh(d*x**S(2) + S(1)))/(S(2)*b))*cosh(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(d*x**S(2))), x) - Simp(sqrt(d*x**S(2))*sqrt(d*x**S(2) + S(2))/(S(2)*b*d*x*(a + b*acosh(d*x**S(2) + S(1)))), x) def replacement6322(a, b, d, x): return Simp(sqrt(S(2))*x*CoshIntegral((a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*b))*cosh(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(d*x**S(2))), x) - Simp(sqrt(S(2))*x*SinhIntegral((a + b*acosh(d*x**S(2) + S(-1)))/(S(2)*b))*sinh(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(d*x**S(2))), x) - Simp(sqrt(d*x**S(2))*sqrt(d*x**S(2) + S(-2))/(S(2)*b*d*x*(a + b*acosh(d*x**S(2) + S(-1)))), x) def replacement6323(a, b, c, d, n, x): return Dist(S(1)/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), Int((a + b*acosh(c + d*x**S(2)))**(n + S(2)), x), x) - Simp(x*(a + b*acosh(c + d*x**S(2)))**(n + S(2))/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), x) + Simp((a + b*acosh(c + d*x**S(2)))**(n + S(1))*(S(2)*c*x**S(2) + d*x**S(4))/(S(2)*b*x*(n + S(1))*sqrt(c + d*x**S(2) + S(-1))*sqrt(c + d*x**S(2) + S(1))), x) def replacement6324(a, n, p, x): return Dist(S(1)/p, Subst(Int(x**n/tanh(x), x), x, asinh(a*x**p)), x) def replacement6325(a, n, p, x): return Dist(S(1)/p, Subst(Int(x**n*tanh(x), x), x, acosh(a*x**p)), x) def replacement6326(a, b, c, m, n, u, x): return Int(u*acsch(a/c + b*x**n/c)**m, x) def replacement6327(a, b, c, m, n, u, x): return Int(u*asech(a/c + b*x**n/c)**m, x) def replacement6328(b, n, x): return Dist(sqrt(b*x**S(2))/(b*x), Subst(Int(asinh(x)**n/sqrt(x**S(2) + S(1)), x), x, sqrt(b*x**S(2) + S(-1))), x) def replacement6329(b, n, x): return Dist(sqrt(sqrt(b*x**S(2) + S(1)) + S(-1))*sqrt(sqrt(b*x**S(2) + S(1)) + S(1))/(b*x), Subst(Int(acosh(x)**n/(sqrt(x + S(-1))*sqrt(x + S(1))), x), x, sqrt(b*x**S(2) + S(1))), x) def replacement6330(a, b, c, f, n, x): return Dist(S(1)/b, Subst(Int(f**(c*x**n)*cosh(x), x), x, asinh(a + b*x)), x) def replacement6331(a, b, c, f, n, x): return Dist(S(1)/b, Subst(Int(f**(c*x**n)*sinh(x), x), x, acosh(a + b*x)), x) def replacement6332(a, b, c, f, m, n, x): return Dist(S(1)/b, Subst(Int(f**(c*x**n)*(-a/b + sinh(x)/b)**m*cosh(x), x), x, asinh(a + b*x)), x) def replacement6333(a, b, c, f, m, n, x): return Dist(S(1)/b, Subst(Int(f**(c*x**n)*(-a/b + cosh(x)/b)**m*sinh(x), x), x, acosh(a + b*x)), x) def replacement6334(u, x): return -Int(SimplifyIntegrand(x*D(u, x)/sqrt(u**S(2) + S(1)), x), x) + Simp(x*asinh(u), x) def replacement6335(u, x): return -Int(SimplifyIntegrand(x*D(u, x)/(sqrt(u + S(-1))*sqrt(u + S(1))), x), x) + Simp(x*acosh(u), x) def replacement6336(a, b, c, d, m, u, x): return -Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/sqrt(u**S(2) + S(1)), x), x), x) + Simp((a + b*asinh(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement6337(a, b, c, d, m, u, x): return -Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(sqrt(u + S(-1))*sqrt(u + S(1))), x), x), x) + Simp((a + b*acosh(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def With6338(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement6338(a, b, u, v, x): w = IntHide(v, x) return -Dist(b, Int(SimplifyIntegrand(w*D(u, x)/sqrt(u**S(2) + S(1)), x), x), x) + Dist(a + b*asinh(u), w, x) def With6339(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement6339(a, b, u, v, x): w = IntHide(v, x) return -Dist(b, Int(SimplifyIntegrand(w*D(u, x)/(sqrt(u + S(-1))*sqrt(u + S(1))), x), x), x) + Dist(a + b*acosh(u), w, x) def replacement6340(n, u, x): return Int((u + sqrt(u**S(2) + S(1)))**n, x) def replacement6341(m, n, u, x): return Int(x**m*(u + sqrt(u**S(2) + S(1)))**n, x) def replacement6342(n, u, x): return Int((u + sqrt(u + S(-1))*sqrt(u + S(1)))**n, x) def replacement6343(m, n, u, x): return Int(x**m*(u + sqrt(u + S(-1))*sqrt(u + S(1)))**n, x) def replacement6344(a, b, c, n, x): return -Dist(b*c*n, Int(x*(a + b*atanh(c*x))**(n + S(-1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*atanh(c*x))**n, x) def replacement6345(a, b, c, n, x): return -Dist(b*c*n, Int(x*(a + b*acoth(c*x))**(n + S(-1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*acoth(c*x))**n, x) def replacement6346(a, b, c, n, x): return Int((a + b*atanh(c*x))**n, x) def replacement6347(a, b, c, n, x): return Int((a + b*acoth(c*x))**n, x) def replacement6348(a, b, c, d, e, n, x): return Dist(b*c*n/e, Int((a + b*atanh(c*x))**(n + S(-1))*log(S(2)*d/(d + e*x))/(-c**S(2)*x**S(2) + S(1)), x), x) - Simp((a + b*atanh(c*x))**n*log(S(2)*d/(d + e*x))/e, x) def replacement6349(a, b, c, d, e, n, x): return Dist(b*c*n/e, Int((a + b*acoth(c*x))**(n + S(-1))*log(S(2)*d/(d + e*x))/(-c**S(2)*x**S(2) + S(1)), x), x) - Simp((a + b*acoth(c*x))**n*log(S(2)*d/(d + e*x))/e, x) def replacement6350(c, d, e, x): return -Simp(PolyLog(S(2), Simp(c*(d + e*x)/(c*d - e), x))/(S(2)*e), x) + Simp(PolyLog(S(2), Simp(c*(d + e*x)/(c*d + e), x))/(S(2)*e), x) - Simp(log(d + e*x)*atanh(c*d/e)/e, x) def replacement6351(c, d, e, x): return -Dist(S(1)/2, Int(log(-c*x + S(1))/(d + e*x), x), x) + Dist(S(1)/2, Int(log(c*x + S(1))/(d + e*x), x), x) def replacement6352(c, d, e, x): return -Dist(S(1)/2, Int(log(S(1) - S(1)/(c*x))/(d + e*x), x), x) + Dist(S(1)/2, Int(log(S(1) + S(1)/(c*x))/(d + e*x), x), x) def replacement6353(a, b, c, d, e, x): return Dist(b, Int(atanh(c*x)/(d + e*x), x), x) + Simp(a*log(RemoveContent(d + e*x, x))/e, x) def replacement6354(a, b, c, d, e, x): return Dist(b, Int(acoth(c*x)/(d + e*x), x), x) + Simp(a*log(RemoveContent(d + e*x, x))/e, x) def replacement6355(a, b, c, d, e, p, x): return -Dist(b*c/(e*(p + S(1))), Int((d + e*x)**(p + S(1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*atanh(c*x))*(d + e*x)**(p + S(1))/(e*(p + S(1))), x) def replacement6356(a, b, c, d, e, p, x): return -Dist(b*c/(e*(p + S(1))), Int((d + e*x)**(p + S(1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acoth(c*x))*(d + e*x)**(p + S(1))/(e*(p + S(1))), x) def replacement6357(a, b, c, n, x): return -Dist(S(2)*b*c*n, Int((a + b*atanh(c*x))**(n + S(-1))*atanh(S(1) - S(2)/(-c*x + S(1)))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(S(2)*(a + b*atanh(c*x))**n*atanh(S(1) - S(2)/(-c*x + S(1))), x) def replacement6358(a, b, c, n, x): return -Dist(S(2)*b*c*n, Int((a + b*acoth(c*x))**(n + S(-1))*acoth(S(1) - S(2)/(-c*x + S(1)))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(S(2)*(a + b*acoth(c*x))**n*acoth(S(1) - S(2)/(-c*x + S(1))), x) def replacement6359(a, b, c, m, n, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*atanh(c*x))**(n + S(-1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**(m + S(1))*(a + b*atanh(c*x))**n/(m + S(1)), x) def replacement6360(a, b, c, m, n, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acoth(c*x))**(n + S(-1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**(m + S(1))*(a + b*acoth(c*x))**n/(m + S(1)), x) def replacement6361(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*atanh(c*x))**n*(d + e*x)**p, x), x) def replacement6362(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*acoth(c*x))**n*(d + e*x)**p, x), x) def replacement6363(a, b, c, d, e, n, p, x): return Int((a + b*atanh(c*x))**n*(d + e*x)**p, x) def replacement6364(a, b, c, d, e, n, p, x): return Int((a + b*acoth(c*x))**n*(d + e*x)**p, x) def replacement6365(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-1))*(a + b*atanh(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-1))*(a + b*atanh(c*x))**n/(d + e*x), x), x) def replacement6366(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-1))*(a + b*acoth(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-1))*(a + b*acoth(c*x))**n/(d + e*x), x), x) def replacement6367(a, b, c, d, e, n, x): return -Dist(b*c*n/d, Int((a + b*atanh(c*x))**(n + S(-1))*log(S(2)*e*x/(d + e*x))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*atanh(c*x))**n*log(S(2)*e*x/(d + e*x))/d, x) def replacement6368(a, b, c, d, e, n, x): return -Dist(b*c*n/d, Int((a + b*acoth(c*x))**(n + S(-1))*log(S(2)*e*x/(d + e*x))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acoth(c*x))**n*log(S(2)*e*x/(d + e*x))/d, x) def replacement6369(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*atanh(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(1))*(a + b*atanh(c*x))**n/(d + e*x), x), x) def replacement6370(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*acoth(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(1))*(a + b*acoth(c*x))**n/(d + e*x), x), x) def replacement6371(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*atanh(c*x))**n*(d + e*x)**p, x), x) def replacement6372(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*acoth(c*x))**n*(d + e*x)**p, x), x) def replacement6373(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*atanh(c*x))**n*(d + e*x)**p, x) def replacement6374(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*acoth(c*x))**n*(d + e*x)**p, x) def replacement6375(a, b, c, d, e, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*atanh(c*x))*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) + Simp(b*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement6376(a, b, c, d, e, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*acoth(c*x))*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) + Simp(b*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement6377(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b**S(2)*d*n*(n + S(-1))/(S(2)*p*(S(2)*p + S(1))), Int((a + b*atanh(c*x))**(n + S(-2))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*atanh(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) + Simp(b*n*(a + b*atanh(c*x))**(n + S(-1))*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement6378(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b**S(2)*d*n*(n + S(-1))/(S(2)*p*(S(2)*p + S(1))), Int((a + b*acoth(c*x))**(n + S(-2))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*acoth(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) + Simp(b*n*(a + b*acoth(c*x))**(n + S(-1))*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement6379(a, b, c, d, e, x): return Simp(log(RemoveContent(a + b*atanh(c*x), x))/(b*c*d), x) def replacement6380(a, b, c, d, e, x): return Simp(log(RemoveContent(a + b*acoth(c*x), x))/(b*c*d), x) def replacement6381(a, b, c, d, e, n, x): return Simp((a + b*atanh(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement6382(a, b, c, d, e, n, x): return Simp((a + b*acoth(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement6383(a, b, c, d, e, x): return Simp(-S(2)*(a + b*atanh(c*x))*ArcTan(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/(c*sqrt(d)), x) - Simp(I*b*PolyLog(S(2), -I*sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/(c*sqrt(d)), x) + Simp(I*b*PolyLog(S(2), I*sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/(c*sqrt(d)), x) def replacement6384(a, b, c, d, e, x): return Simp(-S(2)*(a + b*acoth(c*x))*ArcTan(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/(c*sqrt(d)), x) - Simp(I*b*PolyLog(S(2), -I*sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/(c*sqrt(d)), x) + Simp(I*b*PolyLog(S(2), I*sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/(c*sqrt(d)), x) def replacement6385(a, b, c, d, e, n, x): return Dist(S(1)/(c*sqrt(d)), Subst(Int((a + b*x)**n/cosh(x), x), x, atanh(c*x)), x) def replacement6386(a, b, c, d, e, n, x): return -Dist(x*sqrt(S(1) - S(1)/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n/sinh(x), x), x, acoth(c*x)), x) def replacement6387(a, b, c, d, e, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*atanh(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) def replacement6388(a, b, c, d, e, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*acoth(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) def replacement6389(a, b, c, d, e, n, x): return -Dist(b*c*n/S(2), Int(x*(a + b*atanh(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) + Simp(x*(a + b*atanh(c*x))**n/(S(2)*d*(d + e*x**S(2))), x) + Simp((a + b*atanh(c*x))**(n + S(1))/(S(2)*b*c*d**S(2)*(n + S(1))), x) def replacement6390(a, b, c, d, e, n, x): return -Dist(b*c*n/S(2), Int(x*(a + b*acoth(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) + Simp(x*(a + b*acoth(c*x))**n/(S(2)*d*(d + e*x**S(2))), x) + Simp((a + b*acoth(c*x))**(n + S(1))/(S(2)*b*c*d**S(2)*(n + S(1))), x) def replacement6391(a, b, c, d, e, x): return -Simp(b/(c*d*sqrt(d + e*x**S(2))), x) + Simp(x*(a + b*atanh(c*x))/(d*sqrt(d + e*x**S(2))), x) def replacement6392(a, b, c, d, e, x): return -Simp(b/(c*d*sqrt(d + e*x**S(2))), x) + Simp(x*(a + b*acoth(c*x))/(d*sqrt(d + e*x**S(2))), x) def replacement6393(a, b, c, d, e, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) - Simp(x*(a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement6394(a, b, c, d, e, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) - Simp(x*(a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement6395(a, b, c, d, e, n, x): return Dist(b**S(2)*n*(n + S(-1)), Int((a + b*atanh(c*x))**(n + S(-2))/(d + e*x**S(2))**(S(3)/2), x), x) + Simp(x*(a + b*atanh(c*x))**n/(d*sqrt(d + e*x**S(2))), x) - Simp(b*n*(a + b*atanh(c*x))**(n + S(-1))/(c*d*sqrt(d + e*x**S(2))), x) def replacement6396(a, b, c, d, e, n, x): return Dist(b**S(2)*n*(n + S(-1)), Int((a + b*acoth(c*x))**(n + S(-2))/(d + e*x**S(2))**(S(3)/2), x), x) + Simp(x*(a + b*acoth(c*x))**n/(d*sqrt(d + e*x**S(2))), x) - Simp(b*n*(a + b*acoth(c*x))**(n + S(-1))/(c*d*sqrt(d + e*x**S(2))), x) def replacement6397(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Dist(b**S(2)*n*(n + S(-1))/(S(4)*(p + S(1))**S(2)), Int((a + b*atanh(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) - Simp(x*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) - Simp(b*n*(a + b*atanh(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) def replacement6398(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Dist(b**S(2)*n*(n + S(-1))/(S(4)*(p + S(1))**S(2)), Int((a + b*acoth(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) - Simp(x*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) - Simp(b*n*(a + b*acoth(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) def replacement6399(a, b, c, d, e, n, p, x): return Dist(S(2)*c*(p + S(1))/(b*(n + S(1))), Int(x*(a + b*atanh(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp((a + b*atanh(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement6400(a, b, c, d, e, n, p, x): return Dist(S(2)*c*(p + S(1))/(b*(n + S(1))), Int(x*(a + b*acoth(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp((a + b*acoth(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement6401(a, b, c, d, e, n, p, x): return Dist(d**p/c, Subst(Int((a + b*x)**n*cosh(x)**(-S(2)*p + S(-2)), x), x, atanh(c*x)), x) def replacement6402(a, b, c, d, e, n, p, x): return Dist(d**(p + S(1)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*atanh(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p, x), x) def replacement6403(a, b, c, d, e, n, p, x): return -Dist((-d)**p/c, Subst(Int((a + b*x)**n*sinh(x)**(-S(2)*p + S(-2)), x), x, acoth(c*x)), x) def replacement6404(a, b, c, d, e, n, p, x): return -Dist(x*(-d)**(p + S(1)/2)*sqrt((c**S(2)*x**S(2) + S(-1))/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n*sinh(x)**(-S(2)*p + S(-2)), x), x, acoth(c*x)), x) def replacement6405(c, d, e, x): return -Dist(S(1)/2, Int(log(-c*x + S(1))/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int(log(c*x + S(1))/(d + e*x**S(2)), x), x) def replacement6406(c, d, e, x): return -Dist(S(1)/2, Int(log(S(1) - S(1)/(c*x))/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int(log(S(1) + S(1)/(c*x))/(d + e*x**S(2)), x), x) def replacement6407(a, b, c, d, e, x): return Dist(a, Int(S(1)/(d + e*x**S(2)), x), x) + Dist(b, Int(atanh(c*x)/(d + e*x**S(2)), x), x) def replacement6408(a, b, c, d, e, x): return Dist(a, Int(S(1)/(d + e*x**S(2)), x), x) + Dist(b, Int(acoth(c*x)/(d + e*x**S(2)), x), x) def With6409(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(ExpandIntegrand(u/(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*atanh(c*x), u, x) def With6410(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(ExpandIntegrand(u/(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acoth(c*x), u, x) def replacement6411(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*atanh(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6412(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*acoth(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6413(a, b, c, d, e, n, p, x): return Int((a + b*atanh(c*x))**n*(d + e*x**S(2))**p, x) def replacement6414(a, b, c, d, e, n, p, x): return Int((a + b*acoth(c*x))**n*(d + e*x**S(2))**p, x) def replacement6415(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*atanh(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*atanh(c*x))**n/(d + e*x**S(2)), x), x) def replacement6416(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*acoth(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*acoth(c*x))**n/(d + e*x**S(2)), x), x) def replacement6417(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*atanh(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*atanh(c*x))**n/(d + e*x**S(2)), x), x) def replacement6418(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*acoth(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*acoth(c*x))**n/(d + e*x**S(2)), x), x) def replacement6419(a, b, c, d, e, n, x): return Dist(S(1)/(c*d), Int((a + b*atanh(c*x))**n/(-c*x + S(1)), x), x) + Simp((a + b*atanh(c*x))**(n + S(1))/(b*e*(n + S(1))), x) def replacement6420(a, b, c, d, e, n, x): return Dist(S(1)/(c*d), Int((a + b*acoth(c*x))**n/(-c*x + S(1)), x), x) + Simp((a + b*acoth(c*x))**(n + S(1))/(b*e*(n + S(1))), x) def replacement6421(a, b, c, d, e, n, x): return -Dist(S(1)/(b*c*d*(n + S(1))), Int((a + b*atanh(c*x))**(n + S(1)), x), x) + Simp(x*(a + b*atanh(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement6422(a, b, c, d, e, n, x): return -Dist(S(1)/(b*c*d*(n + S(1))), Int((a + b*acoth(c*x))**(n + S(1)), x), x) - Simp(x*(a + b*acoth(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement6423(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*atanh(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*atanh(c*x))**n/(d + e*x**S(2)), x), x) def replacement6424(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*acoth(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*acoth(c*x))**n/(d + e*x**S(2)), x), x) def replacement6425(a, b, c, d, e, n, x): return Dist(S(1)/d, Int((a + b*atanh(c*x))**n/(x*(c*x + S(1))), x), x) + Simp((a + b*atanh(c*x))**(n + S(1))/(b*d*(n + S(1))), x) def replacement6426(a, b, c, d, e, n, x): return Dist(S(1)/d, Int((a + b*acoth(c*x))**n/(x*(c*x + S(1))), x), x) + Simp((a + b*acoth(c*x))**(n + S(1))/(b*d*(n + S(1))), x) def replacement6427(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*atanh(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*atanh(c*x))**n/(d + e*x**S(2)), x), x) def replacement6428(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*acoth(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*acoth(c*x))**n/(d + e*x**S(2)), x), x) def replacement6429(a, b, c, d, e, m, n, x): return -Dist(m/(b*c*d*(n + S(1))), Int(x**(m + S(-1))*(a + b*atanh(c*x))**(n + S(1)), x), x) + Simp(x**m*(a + b*atanh(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement6430(a, b, c, d, e, m, n, x): return -Dist(m/(b*c*d*(n + S(1))), Int(x**(m + S(-1))*(a + b*acoth(c*x))**(n + S(1)), x), x) + Simp(x**m*(a + b*acoth(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement6431(a, b, c, d, e, m, x): return Int(ExpandIntegrand(a + b*atanh(c*x), x**m/(d + e*x**S(2)), x), x) def replacement6432(a, b, c, d, e, m, x): return Int(ExpandIntegrand(a + b*acoth(c*x), x**m/(d + e*x**S(2)), x), x) def replacement6433(a, b, c, d, e, n, p, x): return Dist(b*n/(S(2)*c*(p + S(1))), Int((a + b*atanh(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp((a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6434(a, b, c, d, e, n, p, x): return Dist(b*n/(S(2)*c*(p + S(1))), Int((a + b*acoth(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp((a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6435(a, b, c, d, e, n, x): return Dist(S(4)/(b**S(2)*(n + S(1))*(n + S(2))), Int(x*(a + b*atanh(c*x))**(n + S(2))/(d + e*x**S(2))**S(2), x), x) + Simp((a + b*atanh(c*x))**(n + S(2))*(c**S(2)*x**S(2) + S(1))/(b**S(2)*e*(d + e*x**S(2))*(n + S(1))*(n + S(2))), x) + Simp(x*(a + b*atanh(c*x))**(n + S(1))/(b*c*d*(d + e*x**S(2))*(n + S(1))), x) def replacement6436(a, b, c, d, e, n, x): return Dist(S(4)/(b**S(2)*(n + S(1))*(n + S(2))), Int(x*(a + b*acoth(c*x))**(n + S(2))/(d + e*x**S(2))**S(2), x), x) + Simp((a + b*acoth(c*x))**(n + S(2))*(c**S(2)*x**S(2) + S(1))/(b**S(2)*e*(d + e*x**S(2))*(n + S(1))*(n + S(2))), x) + Simp(x*(a + b*acoth(c*x))**(n + S(1))/(b*c*d*(d + e*x**S(2))*(n + S(1))), x) def replacement6437(a, b, c, d, e, p, x): return Dist(S(1)/(S(2)*c**S(2)*d*(p + S(1))), Int((a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c**S(3)*d*(p + S(1))**S(2)), x) - Simp(x*(a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*c**S(2)*d*(p + S(1))), x) def replacement6438(a, b, c, d, e, p, x): return Dist(S(1)/(S(2)*c**S(2)*d*(p + S(1))), Int((a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c**S(3)*d*(p + S(1))**S(2)), x) - Simp(x*(a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*c**S(2)*d*(p + S(1))), x) def replacement6439(a, b, c, d, e, n, x): return -Dist(b*n/(S(2)*c), Int(x*(a + b*atanh(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) - Simp((a + b*atanh(c*x))**(n + S(1))/(S(2)*b*c**S(3)*d**S(2)*(n + S(1))), x) + Simp(x*(a + b*atanh(c*x))**n/(S(2)*c**S(2)*d*(d + e*x**S(2))), x) def replacement6440(a, b, c, d, e, n, x): return -Dist(b*n/(S(2)*c), Int(x*(a + b*acoth(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) - Simp((a + b*acoth(c*x))**(n + S(1))/(S(2)*b*c**S(3)*d**S(2)*(n + S(1))), x) + Simp(x*(a + b*acoth(c*x))**n/(S(2)*c**S(2)*d*(d + e*x**S(2))), x) def replacement6441(a, b, c, d, e, m, p, x): return -Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*x**m*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) + Simp(x**(m + S(-1))*(a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) def replacement6442(a, b, c, d, e, m, p, x): return -Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*x**m*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) + Simp(x**(m + S(-1))*(a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) def replacement6443(a, b, c, d, e, m, n, p, x): return Dist(b**S(2)*n*(n + S(-1))/m**S(2), Int(x**m*(a + b*atanh(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) - Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Simp(x**(m + S(-1))*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) - Simp(b*n*x**m*(a + b*atanh(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) def replacement6444(a, b, c, d, e, m, n, p, x): return Dist(b**S(2)*n*(n + S(-1))/m**S(2), Int(x**m*(a + b*acoth(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) - Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Simp(x**(m + S(-1))*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) - Simp(b*n*x**m*(a + b*acoth(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) def replacement6445(a, b, c, d, e, m, n, p, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*atanh(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp(x**m*(a + b*atanh(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement6446(a, b, c, d, e, m, n, p, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*acoth(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp(x**m*(a + b*acoth(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement6447(a, b, c, d, e, m, n, p, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*atanh(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp(x**(m + S(1))*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*(m + S(1))), x) def replacement6448(a, b, c, d, e, m, n, p, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acoth(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp(x**(m + S(1))*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*(m + S(1))), x) def replacement6449(a, b, c, d, e, m, x): return Dist(d/(m + S(2)), Int(x**m*(a + b*atanh(c*x))/sqrt(d + e*x**S(2)), x), x) - Dist(b*c*d/(m + S(2)), Int(x**(m + S(1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*atanh(c*x))*sqrt(d + e*x**S(2))/(m + S(2)), x) def replacement6450(a, b, c, d, e, m, x): return Dist(d/(m + S(2)), Int(x**m*(a + b*acoth(c*x))/sqrt(d + e*x**S(2)), x), x) - Dist(b*c*d/(m + S(2)), Int(x**(m + S(1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*acoth(c*x))*sqrt(d + e*x**S(2))/(m + S(2)), x) def replacement6451(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*atanh(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6452(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*acoth(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6453(a, b, c, d, e, m, n, p, x): return Dist(d, Int(x**m*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(c**S(2)*d, Int(x**(m + S(2))*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) def replacement6454(a, b, c, d, e, m, n, p, x): return Dist(d, Int(x**m*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(c**S(2)*d, Int(x**(m + S(2))*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) def replacement6455(a, b, c, d, e, m, n, x): return Dist((m + S(-1))/(c**S(2)*m), Int(x**(m + S(-2))*(a + b*atanh(c*x))**n/sqrt(d + e*x**S(2)), x), x) + Dist(b*n/(c*m), Int(x**(m + S(-1))*(a + b*atanh(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) - Simp(x**(m + S(-1))*(a + b*atanh(c*x))**n*sqrt(d + e*x**S(2))/(c**S(2)*d*m), x) def replacement6456(a, b, c, d, e, m, n, x): return Dist((m + S(-1))/(c**S(2)*m), Int(x**(m + S(-2))*(a + b*acoth(c*x))**n/sqrt(d + e*x**S(2)), x), x) + Dist(b*n/(c*m), Int(x**(m + S(-1))*(a + b*acoth(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) - Simp(x**(m + S(-1))*(a + b*acoth(c*x))**n*sqrt(d + e*x**S(2))/(c**S(2)*d*m), x) def replacement6457(a, b, c, d, e, x): return Simp(b*PolyLog(S(2), -sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/sqrt(d), x) - Simp(b*PolyLog(S(2), sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/sqrt(d), x) + Simp(-S(2)*(a + b*atanh(c*x))*atanh(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/sqrt(d), x) def replacement6458(a, b, c, d, e, x): return Simp(b*PolyLog(S(2), -sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/sqrt(d), x) - Simp(b*PolyLog(S(2), sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/sqrt(d), x) + Simp(-S(2)*(a + b*acoth(c*x))*atanh(sqrt(-c*x + S(1))/sqrt(c*x + S(1)))/sqrt(d), x) def replacement6459(a, b, c, d, e, n, x): return Dist(S(1)/sqrt(d), Subst(Int((a + b*x)**n/sinh(x), x), x, atanh(c*x)), x) def replacement6460(a, b, c, d, e, n, x): return -Dist(c*x*sqrt(S(1) - S(1)/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n/cosh(x), x), x, acoth(c*x)), x) def replacement6461(a, b, c, d, e, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*atanh(c*x))**n/(x*sqrt(-c**S(2)*x**S(2) + S(1))), x), x) def replacement6462(a, b, c, d, e, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*acoth(c*x))**n/(x*sqrt(-c**S(2)*x**S(2) + S(1))), x), x) def replacement6463(a, b, c, d, e, n, x): return Dist(b*c*n, Int((a + b*atanh(c*x))**(n + S(-1))/(x*sqrt(d + e*x**S(2))), x), x) - Simp((a + b*atanh(c*x))**n*sqrt(d + e*x**S(2))/(d*x), x) def replacement6464(a, b, c, d, e, n, x): return Dist(b*c*n, Int((a + b*acoth(c*x))**(n + S(-1))/(x*sqrt(d + e*x**S(2))), x), x) - Simp((a + b*acoth(c*x))**n*sqrt(d + e*x**S(2))/(d*x), x) def replacement6465(a, b, c, d, e, m, n, x): return Dist(c**S(2)*(m + S(2))/(m + S(1)), Int(x**(m + S(2))*(a + b*atanh(c*x))**n/sqrt(d + e*x**S(2)), x), x) - Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*atanh(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*atanh(c*x))**n*sqrt(d + e*x**S(2))/(d*(m + S(1))), x) def replacement6466(a, b, c, d, e, m, n, x): return Dist(c**S(2)*(m + S(2))/(m + S(1)), Int(x**(m + S(2))*(a + b*acoth(c*x))**n/sqrt(d + e*x**S(2)), x), x) - Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acoth(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*acoth(c*x))**n*sqrt(d + e*x**S(2))/(d*(m + S(1))), x) def replacement6467(a, b, c, d, e, m, n, p, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*atanh(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6468(a, b, c, d, e, m, n, p, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*acoth(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6469(a, b, c, d, e, m, n, p, x): return Dist(S(1)/d, Int(x**m*(a + b*atanh(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*atanh(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6470(a, b, c, d, e, m, n, p, x): return Dist(S(1)/d, Int(x**m*(a + b*acoth(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*acoth(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement6471(a, b, c, d, e, m, n, p, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*atanh(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Dist(c*(m + S(2)*p + S(2))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*atanh(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp(x**m*(a + b*atanh(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement6472(a, b, c, d, e, m, n, p, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*acoth(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Dist(c*(m + S(2)*p + S(2))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*acoth(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp(x**m*(a + b*acoth(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement6473(a, b, c, d, e, m, n, p, x): return Dist(c**(-m + S(-1))*d**p, Subst(Int((a + b*x)**n*sinh(x)**m*cosh(x)**(-m - S(2)*p + S(-2)), x), x, atanh(c*x)), x) def replacement6474(a, b, c, d, e, m, n, p, x): return Dist(d**(p + S(1)/2)*sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int(x**m*(a + b*atanh(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p, x), x) def replacement6475(a, b, c, d, e, m, n, p, x): return -Dist(c**(-m + S(-1))*(-d)**p, Subst(Int((a + b*x)**n*sinh(x)**(-m - S(2)*p + S(-2))*cosh(x)**m, x), x, acoth(c*x)), x) def replacement6476(a, b, c, d, e, m, n, p, x): return -Dist(c**(-m)*x*(-d)**(p + S(1)/2)*sqrt((c**S(2)*x**S(2) + S(-1))/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n*sinh(x)**(-m - S(2)*p + S(-2))*cosh(x)**m, x), x, acoth(c*x)), x) def replacement6477(a, b, c, d, e, p, x): return -Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*atanh(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6478(a, b, c, d, e, p, x): return -Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acoth(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def With6479(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*atanh(c*x), u, x) def With6480(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acoth(c*x), u, x) def replacement6481(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand((a + b*atanh(c*x))**n, x**m*(d + e*x**S(2))**p, x), x) def replacement6482(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand((a + b*acoth(c*x))**n, x**m*(d + e*x**S(2))**p, x), x) def replacement6483(a, b, c, d, e, m, p, x): return Dist(a, Int(x**m*(d + e*x**S(2))**p, x), x) + Dist(b, Int(x**m*(d + e*x**S(2))**p*atanh(c*x), x), x) def replacement6484(a, b, c, d, e, m, p, x): return Dist(a, Int(x**m*(d + e*x**S(2))**p, x), x) + Dist(b, Int(x**m*(d + e*x**S(2))**p*acoth(c*x), x), x) def replacement6485(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*atanh(c*x))**n*(d + e*x**S(2))**p, x) def replacement6486(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*acoth(c*x))**n*(d + e*x**S(2))**p, x) def replacement6487(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*atanh(c*x))**n*log(S(1) - u)/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*atanh(c*x))**n*log(u + S(1))/(d + e*x**S(2)), x), x) def replacement6488(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*acoth(c*x))**n*log(SimplifyIntegrand(S(1) - S(1)/u, x))/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*acoth(c*x))**n*log(SimplifyIntegrand(S(1) + S(1)/u, x))/(d + e*x**S(2)), x), x) def replacement6489(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*atanh(c*x))**n*log(S(1) - u)/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*atanh(c*x))**n*log(u + S(1))/(d + e*x**S(2)), x), x) def replacement6490(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*acoth(c*x))**n*log(SimplifyIntegrand(S(1) - S(1)/u, x))/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*acoth(c*x))**n*log(SimplifyIntegrand(S(1) + S(1)/u, x))/(d + e*x**S(2)), x), x) def replacement6491(a, b, c, d, e, n, u, x): return -Dist(b*n/S(2), Int((a + b*atanh(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) + Simp((a + b*atanh(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement6492(a, b, c, d, e, n, u, x): return -Dist(b*n/S(2), Int((a + b*acoth(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) + Simp((a + b*acoth(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement6493(a, b, c, d, e, n, u, x): return Dist(b*n/S(2), Int((a + b*atanh(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) - Simp((a + b*atanh(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement6494(a, b, c, d, e, n, u, x): return Dist(b*n/S(2), Int((a + b*acoth(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) - Simp((a + b*acoth(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement6495(a, b, c, d, e, n, p, u, x): return Dist(b*n/S(2), Int((a + b*atanh(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) - Simp((a + b*atanh(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement6496(a, b, c, d, e, n, p, u, x): return Dist(b*n/S(2), Int((a + b*acoth(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) - Simp((a + b*acoth(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement6497(a, b, c, d, e, n, p, u, x): return -Dist(b*n/S(2), Int((a + b*atanh(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) + Simp((a + b*atanh(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement6498(a, b, c, d, e, n, p, u, x): return -Dist(b*n/S(2), Int((a + b*acoth(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) + Simp((a + b*acoth(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement6499(a, b, c, d, e, x): return Simp((-log(a + b*acoth(c*x)) + log(a + b*atanh(c*x)))/(b**S(2)*c*d*(acoth(c*x) - atanh(c*x))), x) def replacement6500(a, b, c, d, e, m, n, x): return -Dist(n/(m + S(1)), Int((a + b*acoth(c*x))**(m + S(1))*(a + b*atanh(c*x))**(n + S(-1))/(d + e*x**S(2)), x), x) + Simp((a + b*acoth(c*x))**(m + S(1))*(a + b*atanh(c*x))**n/(b*c*d*(m + S(1))), x) def replacement6501(a, b, c, d, e, m, n, x): return -Dist(n/(m + S(1)), Int((a + b*acoth(c*x))**(n + S(-1))*(a + b*atanh(c*x))**(m + S(1))/(d + e*x**S(2)), x), x) + Simp((a + b*acoth(c*x))**n*(a + b*atanh(c*x))**(m + S(1))/(b*c*d*(m + S(1))), x) def replacement6502(a, c, d, n, x): return -Dist(S(1)/2, Int(log(-a*x + S(1))/(c + d*x**n), x), x) + Dist(S(1)/2, Int(log(a*x + S(1))/(c + d*x**n), x), x) def replacement6503(a, c, d, n, x): return -Dist(S(1)/2, Int(log(S(1) - S(1)/(a*x))/(c + d*x**n), x), x) + Dist(S(1)/2, Int(log(S(1) + S(1)/(a*x))/(c + d*x**n), x), x) def replacement6504(a, b, c, d, e, f, g, x): return -Dist(b*c, Int(x*(d + e*log(f + g*x**S(2)))/(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g, Int(x**S(2)*(a + b*atanh(c*x))/(f + g*x**S(2)), x), x) + Simp(x*(a + b*atanh(c*x))*(d + e*log(f + g*x**S(2))), x) def replacement6505(a, b, c, d, e, f, g, x): return -Dist(b*c, Int(x*(d + e*log(f + g*x**S(2)))/(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g, Int(x**S(2)*(a + b*acoth(c*x))/(f + g*x**S(2)), x), x) + Simp(x*(a + b*acoth(c*x))*(d + e*log(f + g*x**S(2))), x) def replacement6506(a, b, c, d, e, f, g, m, x): return -Dist(b*c/(m + S(1)), Int(x**(m + S(1))*(d + e*log(f + g*x**S(2)))/(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g/(m + S(1)), Int(x**(m + S(2))*(a + b*atanh(c*x))/(f + g*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*atanh(c*x))*(d + e*log(f + g*x**S(2)))/(m + S(1)), x) def replacement6507(a, b, c, d, e, f, g, m, x): return -Dist(b*c/(m + S(1)), Int(x**(m + S(1))*(d + e*log(f + g*x**S(2)))/(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g/(m + S(1)), Int(x**(m + S(2))*(a + b*acoth(c*x))/(f + g*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*acoth(c*x))*(d + e*log(f + g*x**S(2)))/(m + S(1)), x) def With6508(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(d + e*log(f + g*x**S(2))), x) return -Dist(b*c, Int(ExpandIntegrand(u/(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*atanh(c*x), u, x) def With6509(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(d + e*log(f + g*x**S(2))), x) return -Dist(b*c, Int(ExpandIntegrand(u/(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acoth(c*x), u, x) def With6510(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(a + b*atanh(c*x)), x) return -Dist(S(2)*e*g, Int(ExpandIntegrand(u*x/(f + g*x**S(2)), x), x), x) + Dist(d + e*log(f + g*x**S(2)), u, x) def With6511(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(a + b*acoth(c*x)), x) return -Dist(S(2)*e*g, Int(ExpandIntegrand(u*x/(f + g*x**S(2)), x), x), x) + Dist(d + e*log(f + g*x**S(2)), u, x) def replacement6512(a, b, c, d, e, f, g, x): return Dist(b/c, Int((a + b*atanh(c*x))*(d + e*log(f + g*x**S(2))), x), x) + Dist(b*c*e, Int(x**S(2)*(a + b*atanh(c*x))/(-c**S(2)*x**S(2) + S(1)), x), x) - Simp(e*x**S(2)*(a + b*atanh(c*x))**S(2)/S(2), x) + Simp((a + b*atanh(c*x))**S(2)*(d + e*log(f + g*x**S(2)))*(f + g*x**S(2))/(S(2)*g), x) def replacement6513(a, b, c, d, e, f, g, x): return Dist(b/c, Int((a + b*acoth(c*x))*(d + e*log(f + g*x**S(2))), x), x) + Dist(b*c*e, Int(x**S(2)*(a + b*acoth(c*x))/(-c**S(2)*x**S(2) + S(1)), x), x) - Simp(e*x**S(2)*(a + b*acoth(c*x))**S(2)/S(2), x) + Simp((a + b*acoth(c*x))**S(2)*(d + e*log(f + g*x**S(2)))*(f + g*x**S(2))/(S(2)*g), x) def replacement6514(a, n, x): return Int((-a*x + S(1))**(S(1)/2 - n/S(2))*(a*x + S(1))**(n/S(2) + S(1)/2)/sqrt(-a**S(2)*x**S(2) + S(1)), x) def replacement6515(a, m, n, x): return Int(x**m*(-a*x + S(1))**(S(1)/2 - n/S(2))*(a*x + S(1))**(n/S(2) + S(1)/2)/sqrt(-a**S(2)*x**S(2) + S(1)), x) def replacement6516(a, n, x): return Int((-a*x + S(1))**(-n/S(2))*(a*x + S(1))**(n/S(2)), x) def replacement6517(a, m, n, x): return Int(x**m*(-a*x + S(1))**(-n/S(2))*(a*x + S(1))**(n/S(2)), x) def replacement6518(a, c, d, n, p, x): return Dist(c**n, Int((c + d*x)**(-n + p)*(-a**S(2)*x**S(2) + S(1))**(n/S(2)), x), x) def replacement6519(a, c, d, e, f, m, n, p, x): return Dist(c**n, Int((c + d*x)**(-n + p)*(e + f*x)**m*(-a**S(2)*x**S(2) + S(1))**(n/S(2)), x), x) def replacement6520(a, c, d, n, p, u, x): return Dist(c**p, Int(u*(S(1) + d*x/c)**p*(-a*x + S(1))**(-n/S(2))*(a*x + S(1))**(n/S(2)), x), x) def replacement6521(a, c, d, n, p, u, x): return Int(u*(c + d*x)**p*(-a*x + S(1))**(-n/S(2))*(a*x + S(1))**(n/S(2)), x) def replacement6522(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**(-p)*(c*x/d + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6523(a, c, d, n, p, u, x): return Dist((S(-1))**(n/S(2))*c**p, Int(u*(S(1) - S(1)/(a*x))**(-n/S(2))*(S(1) + S(1)/(a*x))**(n/S(2))*(S(1) + d/(c*x))**p, x), x) def replacement6524(a, c, d, n, p, u, x): return Int(u*(c + d/x)**p*(-a*x + S(1))**(-n/S(2))*(a*x + S(1))**(n/S(2)), x) def replacement6525(a, c, d, n, p, u, x): return Dist(x**p*(c + d/x)**p*(c*x/d + S(1))**(-p), Int(u*x**(-p)*(c*x/d + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6526(a, c, d, n, x): return Simp((-a*x + n)*exp(n*atanh(a*x))/(a*c*sqrt(c + d*x**S(2))*(n**S(2) + S(-1))), x) def replacement6527(a, c, d, n, p, x): return -Dist(S(2)*(p + S(1))*(S(2)*p + S(3))/(c*(n**S(2) - S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*atanh(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*atanh(a*x))/(a*c*(n**S(2) - S(4)*(p + S(1))**S(2))), x) def replacement6528(a, c, d, n, x): return Simp(exp(n*atanh(a*x))/(a*c*n), x) def replacement6529(a, c, d, n, p, x): return Dist(c**p, Int((a*x + S(1))**n*(-a**S(2)*x**S(2) + S(1))**(-n/S(2) + p), x), x) def replacement6530(a, c, d, n, p, x): return Dist(c**p, Int((-a*x + S(1))**(-n)*(-a**S(2)*x**S(2) + S(1))**(n/S(2) + p), x), x) def replacement6531(a, c, d, n, p, x): return Dist(c**p, Int((-a*x + S(1))**(-n/S(2) + p)*(a*x + S(1))**(n/S(2) + p), x), x) def replacement6532(a, c, d, n, p, x): return Dist(c**(n/S(2)), Int((c + d*x**S(2))**(-n/S(2) + p)*(a*x + S(1))**n, x), x) def replacement6533(a, c, d, n, p, x): return Dist(c**(-n/S(2)), Int((c + d*x**S(2))**(n/S(2) + p)*(-a*x + S(1))**(-n), x), x) def replacement6534(a, c, d, n, p, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(-a**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((-a**S(2)*x**S(2) + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6535(a, c, d, n, x): return Simp((-a*n*x + S(1))*exp(n*atanh(a*x))/(d*sqrt(c + d*x**S(2))*(n**S(2) + S(-1))), x) def replacement6536(a, c, d, n, p, x): return -Dist(a*c*n/(S(2)*d*(p + S(1))), Int((c + d*x**S(2))**p*exp(n*atanh(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*exp(n*atanh(a*x))/(S(2)*d*(p + S(1))), x) def replacement6537(a, c, d, n, p, x): return Simp((c + d*x**S(2))**(p + S(1))*(-a*n*x + S(1))*exp(n*atanh(a*x))/(a*d*n*(n**S(2) + S(-1))), x) def replacement6538(a, c, d, n, p, x): return Dist((n**S(2) + S(2)*p + S(2))/(d*(n**S(2) - S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*atanh(a*x)), x), x) - Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*atanh(a*x))/(a*d*(n**S(2) - S(4)*(p + S(1))**S(2))), x) def replacement6539(a, c, d, m, n, p, x): return Dist(c**p, Int(x**m*(a*x + S(1))**n*(-a**S(2)*x**S(2) + S(1))**(-n/S(2) + p), x), x) def replacement6540(a, c, d, m, n, p, x): return Dist(c**p, Int(x**m*(-a*x + S(1))**(-n)*(-a**S(2)*x**S(2) + S(1))**(n/S(2) + p), x), x) def replacement6541(a, c, d, m, n, p, x): return Dist(c**p, Int(x**m*(-a*x + S(1))**(-n/S(2) + p)*(a*x + S(1))**(n/S(2) + p), x), x) def replacement6542(a, c, d, m, n, p, x): return Dist(c**(n/S(2)), Int(x**m*(c + d*x**S(2))**(-n/S(2) + p)*(a*x + S(1))**n, x), x) def replacement6543(a, c, d, m, n, p, x): return Dist(c**(-n/S(2)), Int(x**m*(c + d*x**S(2))**(n/S(2) + p)*(-a*x + S(1))**(-n), x), x) def replacement6544(a, c, d, m, n, p, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(-a**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int(x**m*(-a**S(2)*x**S(2) + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6545(a, c, d, n, p, u, x): return Dist(c**p, Int(u*(-a*x + S(1))**(-n/S(2) + p)*(a*x + S(1))**(n/S(2) + p), x), x) def replacement6546(a, c, d, n, p, u, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(-a*x + S(1))**(-FracPart(p))*(a*x + S(1))**(-FracPart(p)), Int(u*(-a*x + S(1))**(-n/S(2) + p)*(a*x + S(1))**(n/S(2) + p), x), x) def replacement6547(a, c, d, n, p, u, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(-a**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int(u*(-a**S(2)*x**S(2) + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6548(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**(-S(2)*p)*(-a**S(2)*x**S(2) + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6549(a, c, d, n, p, u, x): return Dist(c**p, Int(u*(S(1) - S(1)/(a*x))**p*(S(1) + S(1)/(a*x))**p*exp(n*atanh(a*x)), x), x) def replacement6550(a, c, d, n, p, u, x): return Dist(x**(S(2)*p)*(c + d/x**S(2))**p*(-a*x + S(1))**(-p)*(a*x + S(1))**(-p), Int(u*x**(-S(2)*p)*(-a*x + S(1))**p*(a*x + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6551(a, c, d, n, p, u, x): return Dist(x**(S(2)*p)*(c + d/x**S(2))**p*(c*x**S(2)/d + S(1))**(-p), Int(u*x**(-S(2)*p)*(c*x**S(2)/d + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6552(a, b, c, n, x): return Int((-a*c - b*c*x + S(1))**(-n/S(2))*(a*c + b*c*x + S(1))**(n/S(2)), x) def replacement6553(a, b, c, m, n, x): return Dist(S(4)*b**(-m + S(-1))*c**(-m + S(-1))/n, Subst(Int(x**(S(2)/n)*(x**(S(2)/n) + S(1))**(-m + S(-2))*(-a*c + x**(S(2)/n)*(-a*c + S(1)) + S(-1))**m, x), x, (-c*(a + b*x) + S(1))**(-n/S(2))*(c*(a + b*x) + S(1))**(n/S(2))), x) def replacement6554(a, b, c, d, e, m, n, x): return Int((d + e*x)**m*(-a*c - b*c*x + S(1))**(-n/S(2))*(a*c + b*c*x + S(1))**(n/S(2)), x) def replacement6555(a, b, c, d, e, n, p, u, x): return Dist((c/(S(1) - a**S(2)))**p, Int(u*(-a - b*x + S(1))**(-n/S(2) + p)*(a + b*x + S(1))**(n/S(2) + p), x), x) def replacement6556(a, b, c, d, e, n, p, u, x): return Dist((c + d*x + e*x**S(2))**p*(-a**S(2) - S(2)*a*b*x - b**S(2)*x**S(2) + S(1))**(-p), Int(u*(-a**S(2) - S(2)*a*b*x - b**S(2)*x**S(2) + S(1))**p*exp(n*atanh(a*x)), x), x) def replacement6557(a, b, c, n, u, x): return Int(u*exp(n*acoth(a/c + b*x/c)), x) def replacement6558(a, n, u, x): return Dist((S(-1))**(n/S(2)), Int(u*exp(n*atanh(a*x)), x), x) def replacement6559(a, n, x): return -Subst(Int((S(1) - x/a)**(S(1)/2 - n/S(2))*(S(1) + x/a)**(n/S(2) + S(1)/2)/(x**S(2)*sqrt(S(1) - x**S(2)/a**S(2))), x), x, S(1)/x) def replacement6560(a, m, n, x): return -Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(S(1)/2 - n/S(2))*(S(1) + x/a)**(n/S(2) + S(1)/2)/sqrt(S(1) - x**S(2)/a**S(2)), x), x, S(1)/x) def replacement6561(a, n, x): return -Subst(Int((S(1) - x/a)**(-n/S(2))*(S(1) + x/a)**(n/S(2))/x**S(2), x), x, S(1)/x) def replacement6562(a, m, n, x): return -Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(-n/S(2))*(S(1) + x/a)**(n/S(2)), x), x, S(1)/x) def replacement6563(a, m, n, x): return -Dist(x**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(S(1)/2 - n/S(2))*(S(1) + x/a)**(n/S(2) + S(1)/2)/sqrt(S(1) - x**S(2)/a**S(2)), x), x, S(1)/x), x) def replacement6564(a, m, n, x): return -Dist(x**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(-n/S(2))*(S(1) + x/a)**(n/S(2)), x), x, S(1)/x), x) def replacement6565(a, c, d, n, p, x): return Simp((c + d*x)**p*(a*x + S(1))*exp(n*acoth(a*x))/(a*(p + S(1))), x) def replacement6566(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**p*(c/(d*x) + S(1))**p*exp(n*acoth(a*x)), x), x) def replacement6567(a, c, d, n, p, u, x): return Dist(x**(-p)*(c + d*x)**p*(c/(d*x) + S(1))**(-p), Int(u*x**p*(c/(d*x) + S(1))**p*exp(n*acoth(a*x)), x), x) def replacement6568(a, c, d, n, p, x): return -Dist(c**n, Subst(Int((S(1) - x**S(2)/a**S(2))**(n/S(2))*(c + d*x)**(-n + p)/x**S(2), x), x, S(1)/x), x) def replacement6569(a, c, d, m, n, p, x): return -Dist(c**n, Subst(Int(x**(-m + S(-2))*(S(1) - x**S(2)/a**S(2))**(n/S(2))*(c + d*x)**(-n + p), x), x, S(1)/x), x) def replacement6570(a, c, d, n, p, x): return -Dist(c**p, Subst(Int((S(1) - x/a)**(-n/S(2))*(S(1) + x/a)**(n/S(2))*(S(1) + d*x/c)**p/x**S(2), x), x, S(1)/x), x) def replacement6571(a, c, d, m, n, p, x): return -Dist(c**p, Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(-n/S(2))*(S(1) + x/a)**(n/S(2))*(S(1) + d*x/c)**p, x), x, S(1)/x), x) def replacement6572(a, c, d, m, n, p, x): return -Dist(c**p*x**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(-n/S(2))*(S(1) + x/a)**(n/S(2))*(S(1) + d*x/c)**p, x), x, S(1)/x), x) def replacement6573(a, c, d, n, p, u, x): return Dist((S(1) + d/(c*x))**(-p)*(c + d/x)**p, Int(u*(S(1) + d/(c*x))**p*exp(n*acoth(a*x)), x), x) def replacement6574(a, c, d, n, x): return Simp(exp(n*acoth(a*x))/(a*c*n), x) def replacement6575(a, c, d, n, x): return Simp((-a*x + n)*exp(n*acoth(a*x))/(a*c*sqrt(c + d*x**S(2))*(n**S(2) + S(-1))), x) def replacement6576(a, c, d, n, p, x): return -Dist(S(2)*(p + S(1))*(S(2)*p + S(3))/(c*(n**S(2) - S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*acoth(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*acoth(a*x))/(a*c*(n**S(2) - S(4)*(p + S(1))**S(2))), x) def replacement6577(a, c, d, n, x): return -Simp((-a*n*x + S(1))*exp(n*acoth(a*x))/(a**S(2)*c*sqrt(c + d*x**S(2))*(n**S(2) + S(-1))), x) def replacement6578(a, c, d, n, p, x): return -Dist(n*(S(2)*p + S(3))/(a*c*(n**S(2) - S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*acoth(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*(a*n*x + S(2)*p + S(2))*exp(n*acoth(a*x))/(a**S(2)*c*(n**S(2) - S(4)*(p + S(1))**S(2))), x) def replacement6579(a, c, d, n, p, x): return -Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*acoth(a*x))/(a**S(3)*c*n**S(2)*(n**S(2) + S(-1))), x) def replacement6580(a, c, d, n, p, x): return -Dist((n**S(2) + S(2)*p + S(2))/(a**S(2)*c*(n**S(2) - S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*acoth(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*acoth(a*x))/(a**S(3)*c*(n**S(2) - S(4)*(p + S(1))**S(2))), x) def replacement6581(a, c, d, m, n, p, x): return -Dist(a**(-m + S(-1))*(-c)**p, Subst(Int((S(1)/tanh(x))**(m + S(2)*p + S(2))*exp(n*x)*cosh(x)**(-S(2)*p + S(-2)), x), x, acoth(a*x)), x) def replacement6582(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**(S(2)*p)*(S(1) - S(1)/(a**S(2)*x**S(2)))**p*exp(n*acoth(a*x)), x), x) def replacement6583(a, c, d, n, p, u, x): return Dist(x**(-S(2)*p)*(S(1) - S(1)/(a**S(2)*x**S(2)))**(-p)*(c + d*x**S(2))**p, Int(u*x**(S(2)*p)*(S(1) - S(1)/(a**S(2)*x**S(2)))**p*exp(n*acoth(a*x)), x), x) def replacement6584(a, c, d, n, p, u, x): return Dist(a**(-S(2)*p)*c**p, Int(u*x**(-S(2)*p)*(a*x + S(-1))**(-n/S(2) + p)*(a*x + S(1))**(n/S(2) + p), x), x) def replacement6585(a, c, d, n, p, x): return -Dist(c**p, Subst(Int((S(1) - x/a)**(-n/S(2) + p)*(S(1) + x/a)**(n/S(2) + p)/x**S(2), x), x, S(1)/x), x) def replacement6586(a, c, d, m, n, p, x): return -Dist(c**p, Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(-n/S(2) + p)*(S(1) + x/a)**(n/S(2) + p), x), x, S(1)/x), x) def replacement6587(a, c, d, m, n, p, x): return -Dist(c**p*x**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(S(1) - x/a)**(-n/S(2) + p)*(S(1) + x/a)**(n/S(2) + p), x), x, S(1)/x), x) def replacement6588(a, c, d, n, p, u, x): return Dist(c**IntPart(p)*(S(1) - S(1)/(a**S(2)*x**S(2)))**(-FracPart(p))*(c + d/x**S(2))**FracPart(p), Int(u*(S(1) - S(1)/(a**S(2)*x**S(2)))**p*exp(n*acoth(a*x)), x), x) def replacement6589(a, b, c, n, u, x): return Dist((S(-1))**(n/S(2)), Int(u*exp(n*atanh(c*(a + b*x))), x), x) def replacement6590(a, b, c, n, x): return Dist((c*(a + b*x))**(n/S(2))*(S(1) + S(1)/(c*(a + b*x)))**(n/S(2))*(a*c + b*c*x + S(1))**(-n/S(2)), Int((a*c + b*c*x + S(-1))**(-n/S(2))*(a*c + b*c*x + S(1))**(n/S(2)), x), x) def replacement6591(a, b, c, m, n, x): return Dist(-S(4)*b**(-m + S(-1))*c**(-m + S(-1))/n, Subst(Int(x**(S(2)/n)*(x**(S(2)/n) + S(-1))**(-m + S(-2))*(a*c + x**(S(2)/n)*(-a*c + S(1)) + S(1))**m, x), x, (S(1) - S(1)/(c*(a + b*x)))**(-n/S(2))*(S(1) + S(1)/(c*(a + b*x)))**(n/S(2))), x) def replacement6592(a, b, c, d, e, m, n, x): return Dist((c*(a + b*x))**(n/S(2))*(S(1) + S(1)/(c*(a + b*x)))**(n/S(2))*(a*c + b*c*x + S(1))**(-n/S(2)), Int((d + e*x)**m*(a*c + b*c*x + S(-1))**(-n/S(2))*(a*c + b*c*x + S(1))**(n/S(2)), x), x) def replacement6593(a, b, c, d, e, n, p, u, x): return Dist((c/(S(1) - a**S(2)))**p*((a + b*x + S(1))/(a + b*x))**(n/S(2))*((a + b*x)/(a + b*x + S(1)))**(n/S(2))*(-a - b*x + S(1))**(n/S(2))*(a + b*x + S(-1))**(-n/S(2)), Int(u*(-a - b*x + S(1))**(-n/S(2) + p)*(a + b*x + S(1))**(n/S(2) + p), x), x) def replacement6594(a, b, c, d, e, n, p, u, x): return Dist((c + d*x + e*x**S(2))**p*(-a**S(2) - S(2)*a*b*x - b**S(2)*x**S(2) + S(1))**(-p), Int(u*(-a**S(2) - S(2)*a*b*x - b**S(2)*x**S(2) + S(1))**p*exp(n*acoth(a*x)), x), x) def replacement6595(a, b, c, n, u, x): return Int(u*exp(n*atanh(a/c + b*x/c)), x) def replacement6596(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*atanh(x))**n, x), x, c + d*x), x) def replacement6597(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*acoth(x))**n, x), x, c + d*x), x) def replacement6598(a, b, c, d, n, x): return Int((a + b*atanh(c + d*x))**n, x) def replacement6599(a, b, c, d, n, x): return Int((a + b*acoth(c + d*x))**n, x) def replacement6600(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*atanh(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6601(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*acoth(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6602(a, b, c, d, e, f, m, n, x): return Int((a + b*atanh(c + d*x))**n*(e + f*x)**m, x) def replacement6603(a, b, c, d, e, f, m, n, x): return Int((a + b*acoth(c + d*x))**n*(e + f*x)**m, x) def replacement6604(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*atanh(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p, x), x, c + d*x), x) def replacement6605(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acoth(x))**n*(C*x**S(2)/d**S(2) + C/d**S(2))**p, x), x, c + d*x), x) def replacement6606(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*atanh(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6607(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acoth(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement6608(a, b, c, d, n, x): return -Dist(S(1)/2, Int(log(-a - b*x + S(1))/(c + d*x**n), x), x) + Dist(S(1)/2, Int(log(a + b*x + S(1))/(c + d*x**n), x), x) def replacement6609(a, b, c, d, n, x): return -Dist(S(1)/2, Int(log((a + b*x + S(-1))/(a + b*x))/(c + d*x**n), x), x) + Dist(S(1)/2, Int(log((a + b*x + S(1))/(a + b*x))/(c + d*x**n), x), x) def replacement6610(a, b, c, d, n, x): return Int(atanh(a + b*x)/(c + d*x**n), x) def replacement6611(a, b, c, d, n, x): return Int(acoth(a + b*x)/(c + d*x**n), x) def replacement6612(a, b, n, x): return -Dist(b*n, Int(x**n/(-a**S(2) - S(2)*a*b*x**n - b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x*atanh(a + b*x**n), x) def replacement6613(a, b, n, x): return -Dist(b*n, Int(x**n/(-a**S(2) - S(2)*a*b*x**n - b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x*acoth(a + b*x**n), x) def replacement6614(a, b, n, x): return -Dist(S(1)/2, Int(log(-a - b*x**n + S(1))/x, x), x) + Dist(S(1)/2, Int(log(a + b*x**n + S(1))/x, x), x) def replacement6615(a, b, n, x): return -Dist(S(1)/2, Int(log(S(1) - S(1)/(a + b*x**n))/x, x), x) + Dist(S(1)/2, Int(log(S(1) + S(1)/(a + b*x**n))/x, x), x) def replacement6616(a, b, m, n, x): return -Dist(b*n/(m + S(1)), Int(x**(m + n)/(-a**S(2) - S(2)*a*b*x**n - b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x**(m + S(1))*atanh(a + b*x**n)/(m + S(1)), x) def replacement6617(a, b, m, n, x): return -Dist(b*n/(m + S(1)), Int(x**(m + n)/(-a**S(2) - S(2)*a*b*x**n - b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x**(m + S(1))*acoth(a + b*x**n)/(m + S(1)), x) def replacement6618(a, b, c, d, f, x): return -Dist(S(1)/2, Int(log(-a - b*f**(c + d*x) + S(1)), x), x) + Dist(S(1)/2, Int(log(a + b*f**(c + d*x) + S(1)), x), x) def replacement6619(a, b, c, d, f, x): return -Dist(S(1)/2, Int(log(S(1) - S(1)/(a + b*f**(c + d*x))), x), x) + Dist(S(1)/2, Int(log(S(1) + S(1)/(a + b*f**(c + d*x))), x), x) def replacement6620(a, b, c, d, f, m, x): return -Dist(S(1)/2, Int(x**m*log(-a - b*f**(c + d*x) + S(1)), x), x) + Dist(S(1)/2, Int(x**m*log(a + b*f**(c + d*x) + S(1)), x), x) def replacement6621(a, b, c, d, f, m, x): return -Dist(S(1)/2, Int(x**m*log(S(1) - S(1)/(a + b*f**(c + d*x))), x), x) + Dist(S(1)/2, Int(x**m*log(S(1) + S(1)/(a + b*f**(c + d*x))), x), x) def replacement6622(a, b, c, m, n, u, x): return Int(u*acoth(a/c + b*x**n/c)**m, x) def replacement6623(a, b, c, m, n, u, x): return Int(u*atanh(a/c + b*x**n/c)**m, x) def replacement6624(a, b, c, x): return Simp(log(atanh(c*x/sqrt(a + b*x**S(2))))/c, x) def replacement6625(a, b, c, x): return -Simp(log(acoth(c*x/sqrt(a + b*x**S(2))))/c, x) def replacement6626(a, b, c, m, x): return Simp(atanh(c*x/sqrt(a + b*x**S(2)))**(m + S(1))/(c*(m + S(1))), x) def replacement6627(a, b, c, m, x): return -Simp(acoth(c*x/sqrt(a + b*x**S(2)))**(m + S(1))/(c*(m + S(1))), x) def replacement6628(a, b, c, d, e, m, x): return Dist(sqrt(a + b*x**S(2))/sqrt(d + e*x**S(2)), Int(atanh(c*x/sqrt(a + b*x**S(2)))**m/sqrt(a + b*x**S(2)), x), x) def replacement6629(a, b, c, d, e, m, x): return Dist(sqrt(a + b*x**S(2))/sqrt(d + e*x**S(2)), Int(acoth(c*x/sqrt(a + b*x**S(2)))**m/sqrt(a + b*x**S(2)), x), x) def With6630(a, c, d, n, x): u = IntHide((c + d*x**S(2))**n, x) return -Dist(a, Int(Dist(S(1)/(-a**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(atanh(a*x), u, x) def With6631(a, c, d, n, x): u = IntHide((c + d*x**S(2))**n, x) return -Dist(a, Int(Dist(S(1)/(-a**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(acoth(a*x), u, x) def With6632(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: tmp = InverseFunctionOfLinear(u, x) res = And(Not(FalseQ(tmp)), SameQ(Head(tmp), ArcTanh), ZeroQ(-D(v, x)**S(2) + Discriminant(v, x)*Part(tmp, S(1))**S(2))) except (TypeError, AttributeError): return False if res: return True return False def replacement6632(n, u, v, x): tmp = InverseFunctionOfLinear(u, x) return Dist((-Discriminant(v, x)/(S(4)*Coefficient(v, x, S(2))))**n/Coefficient(Part(tmp, S(1)), x, S(1)), Subst(Int(SimplifyIntegrand((S(1)/cosh(x))**(S(2)*n + S(2))*SubstForInverseFunction(u, tmp, x), x), x), x, tmp), x) def With6633(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: tmp = InverseFunctionOfLinear(u, x) res = And(Not(FalseQ(tmp)), SameQ(Head(tmp), ArcCoth), ZeroQ(-D(v, x)**S(2) + Discriminant(v, x)*Part(tmp, S(1))**S(2))) except (TypeError, AttributeError): return False if res: return True return False def replacement6633(n, u, v, x): tmp = InverseFunctionOfLinear(u, x) return Dist((-Discriminant(v, x)/(S(4)*Coefficient(v, x, S(2))))**n/Coefficient(Part(tmp, S(1)), x, S(1)), Subst(Int(SimplifyIntegrand((-S(1)/sinh(x)**S(2))**(n + S(1))*SubstForInverseFunction(u, tmp, x), x), x), x, tmp), x) def replacement6634(a, b, c, d, x): return Dist(b, Int(x/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*atanh(c + d*tanh(a + b*x)), x) def replacement6635(a, b, c, d, x): return Dist(b, Int(x/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*acoth(c + d*tanh(a + b*x)), x) def replacement6636(a, b, c, d, x): return Dist(b, Int(x/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*atanh(c + d/tanh(a + b*x)), x) def replacement6637(a, b, c, d, x): return Dist(b, Int(x/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*acoth(c + d/tanh(a + b*x)), x) def replacement6638(a, b, c, d, x): return Dist(b*(-c - d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) - Dist(b*(c + d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp(x*atanh(c + d*tanh(a + b*x)), x) def replacement6639(a, b, c, d, x): return Dist(b*(-c - d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) - Dist(b*(c + d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp(x*acoth(c + d*tanh(a + b*x)), x) def replacement6640(a, b, c, d, x): return -Dist(b*(-c - d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Dist(b*(c + d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp(x*atanh(c + d/tanh(a + b*x)), x) def replacement6641(a, b, c, d, x): return -Dist(b*(-c - d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Dist(b*(c + d + S(1)), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp(x*acoth(c + d/tanh(a + b*x)), x) def replacement6642(a, b, c, d, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement6643(a, b, c, d, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement6644(a, b, c, d, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement6645(a, b, c, d, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement6646(a, b, c, d, e, f, m, x): return Dist(b*(-c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) - Dist(b*(c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement6647(a, b, c, d, e, f, m, x): return Dist(b*(-c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) - Dist(b*(c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement6648(a, b, c, d, e, f, m, x): return -Dist(b*(-c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Dist(b*(c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement6649(a, b, c, d, e, f, m, x): return -Dist(b*(-c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Dist(b*(c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + S(1))*exp(S(2)*a + S(2)*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement6650(a, b, x): return -Dist(b, Int(x/cos(S(2)*a + S(2)*b*x), x), x) + Simp(x*atanh(tan(a + b*x)), x) def replacement6651(a, b, x): return -Dist(b, Int(x/cos(S(2)*a + S(2)*b*x), x), x) + Simp(x*acoth(tan(a + b*x)), x) def replacement6652(a, b, x): return -Dist(b, Int(x/cos(S(2)*a + S(2)*b*x), x), x) + Simp(x*atanh(S(1)/tan(a + b*x)), x) def replacement6653(a, b, x): return -Dist(b, Int(x/cos(S(2)*a + S(2)*b*x), x), x) + Simp(x*acoth(S(1)/tan(a + b*x)), x) def replacement6654(a, b, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cos(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*atanh(tan(a + b*x))/(f*(m + S(1))), x) def replacement6655(a, b, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cos(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*acoth(tan(a + b*x))/(f*(m + S(1))), x) def replacement6656(a, b, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cos(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*atanh(S(1)/tan(a + b*x))/(f*(m + S(1))), x) def replacement6657(a, b, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cos(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*acoth(S(1)/tan(a + b*x))/(f*(m + S(1))), x) def replacement6658(a, b, c, d, x): return Dist(I*b, Int(x/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp(x*atanh(c + d*tan(a + b*x)), x) def replacement6659(a, b, c, d, x): return Dist(I*b, Int(x/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp(x*acoth(c + d*tan(a + b*x)), x) def replacement6660(a, b, c, d, x): return Dist(I*b, Int(x/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp(x*atanh(c + d/tan(a + b*x)), x) def replacement6661(a, b, c, d, x): return Dist(I*b, Int(x/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp(x*acoth(c + d/tan(a + b*x)), x) def replacement6662(a, b, c, d, x): return Dist(I*b*(-c + I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-c - I*d + (-c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(I*b*(c - I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(c + I*d + (c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*atanh(c + d*tan(a + b*x)), x) def replacement6663(a, b, c, d, x): return Dist(I*b*(-c + I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-c - I*d + (-c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(I*b*(c - I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(c + I*d + (c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*acoth(c + d*tan(a + b*x)), x) def replacement6664(a, b, c, d, x): return -Dist(I*b*(-c - I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-c + I*d - (-c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(I*b*(c + I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(c - I*d - (c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*atanh(c + d/tan(a + b*x)), x) def replacement6665(a, b, c, d, x): return -Dist(I*b*(-c - I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-c + I*d - (-c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(I*b*(c + I*d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(c - I*d - (c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*acoth(c + d/tan(a + b*x)), x) def replacement6666(a, b, c, d, e, f, m, x): return Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement6667(a, b, c, d, e, f, m, x): return Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement6668(a, b, c, d, e, f, m, x): return Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement6669(a, b, c, d, e, f, m, x): return Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement6670(a, b, c, d, e, f, m, x): return Dist(I*b*(-c + I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-c - I*d + (-c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(I*b*(c - I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(c + I*d + (c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement6671(a, b, c, d, e, f, m, x): return Dist(I*b*(-c + I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-c - I*d + (-c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(I*b*(c - I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(c + I*d + (c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement6672(a, b, c, d, e, f, m, x): return -Dist(I*b*(-c - I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-c + I*d - (-c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(I*b*(c + I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(c - I*d - (c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*atanh(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement6673(a, b, c, d, e, f, m, x): return -Dist(I*b*(-c - I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-c + I*d - (-c - I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(I*b*(c + I*d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(c - I*d - (c + I*d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*acoth(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement6674(u, x): return -Int(SimplifyIntegrand(x*D(u, x)/(S(1) - u**S(2)), x), x) + Simp(x*atanh(u), x) def replacement6675(u, x): return -Int(SimplifyIntegrand(x*D(u, x)/(S(1) - u**S(2)), x), x) + Simp(x*acoth(u), x) def replacement6676(a, b, c, d, m, u, x): return -Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(S(1) - u**S(2)), x), x), x) + Simp((a + b*atanh(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement6677(a, b, c, d, m, u, x): return -Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(S(1) - u**S(2)), x), x), x) + Simp((a + b*acoth(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def With6678(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement6678(a, b, u, v, x): w = IntHide(v, x) return -Dist(b, Int(SimplifyIntegrand(w*D(u, x)/(S(1) - u**S(2)), x), x), x) + Dist(a + b*atanh(u), w, x) def With6679(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement6679(a, b, u, v, x): w = IntHide(v, x) return -Dist(b, Int(SimplifyIntegrand(w*D(u, x)/(S(1) - u**S(2)), x), x), x) + Dist(a + b*acoth(u), w, x) def replacement6680(c, x): return Dist(sqrt(c*x + S(1))*sqrt(S(1)/(c*x + S(1))), Int(S(1)/(sqrt(-c*x + S(1))*sqrt(c*x + S(1))), x), x) + Simp(x*asech(c*x), x) def replacement6681(c, x): return Dist(S(1)/c, Int(S(1)/(x*sqrt(S(1) + S(1)/(c**S(2)*x**S(2)))), x), x) + Simp(x*acsch(c*x), x) def replacement6682(a, b, c, n, x): return -Dist(S(1)/c, Subst(Int((a + b*x)**n*tanh(x)/cosh(x), x), x, asech(c*x)), x) def replacement6683(a, b, c, n, x): return -Dist(S(1)/c, Subst(Int((a + b*x)**n/(sinh(x)*tanh(x)), x), x, acsch(c*x)), x) def replacement6684(a, b, c, x): return -Subst(Int((a + b*acosh(x/c))/x, x), x, S(1)/x) def replacement6685(a, b, c, x): return -Subst(Int((a + b*asinh(x/c))/x, x), x, S(1)/x) def replacement6686(a, b, c, m, x): return Dist(b*sqrt(c*x + S(1))*sqrt(S(1)/(c*x + S(1)))/(m + S(1)), Int(x**m/(sqrt(-c*x + S(1))*sqrt(c*x + S(1))), x), x) + Simp(x**(m + S(1))*(a + b*asech(c*x))/(m + S(1)), x) def replacement6687(a, b, c, m, x): return Dist(b/(c*(m + S(1))), Int(x**(m + S(-1))/sqrt(S(1) + S(1)/(c**S(2)*x**S(2))), x), x) + Simp(x**(m + S(1))*(a + b*acsch(c*x))/(m + S(1)), x) def replacement6688(a, b, c, m, n, x): return -Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(S(1)/cosh(x))**(m + S(1))*tanh(x), x), x, asech(c*x)), x) def replacement6689(a, b, c, m, n, x): return -Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(S(1)/sinh(x))**(m + S(1))/tanh(x), x), x, acsch(c*x)), x) def replacement6690(a, b, c, m, n, x): return Int(x**m*(a + b*asech(c*x))**n, x) def replacement6691(a, b, c, m, n, x): return Int(x**m*(a + b*acsch(c*x))**n, x) def With6692(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return Dist(b*sqrt(c*x + S(1))*sqrt(S(1)/(c*x + S(1))), Int(SimplifyIntegrand(u/(x*sqrt(-c*x + S(1))*sqrt(c*x + S(1))), x), x), x) + Dist(a + b*asech(c*x), u, x) def With6693(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c*x/sqrt(-c**S(2)*x**S(2)), Int(SimplifyIntegrand(u/(x*sqrt(-c**S(2)*x**S(2) + S(-1))), x), x), x) + Dist(a + b*acsch(c*x), u, x) def replacement6694(a, b, c, d, e, n, p, x): return -Subst(Int(x**(-S(2)*p + S(-2))*(a + b*acosh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement6695(a, b, c, d, e, n, p, x): return -Subst(Int(x**(-S(2)*p + S(-2))*(a + b*asinh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement6696(a, b, c, d, e, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-S(2)*p + S(-2))*(a + b*acosh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6697(a, b, c, d, e, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-S(2)*p + S(-2))*(a + b*asinh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6698(a, b, c, d, e, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-S(2)*p + S(-2))*(a + b*acosh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6699(a, b, c, d, e, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-S(2)*p + S(-2))*(a + b*asinh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6700(a, b, c, d, e, n, p, x): return Int((a + b*asech(c*x))**n*(d + e*x**S(2))**p, x) def replacement6701(a, b, c, d, e, n, p, x): return Int((a + b*acsch(c*x))**n*(d + e*x**S(2))**p, x) def replacement6702(a, b, c, d, e, p, x): return Dist(b*sqrt(c*x + S(1))*sqrt(S(1)/(c*x + S(1)))/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(x*sqrt(-c*x + S(1))*sqrt(c*x + S(1))), x), x) + Simp((a + b*asech(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement6703(a, b, c, d, e, p, x): return -Dist(b*c*x/(S(2)*e*sqrt(-c**S(2)*x**S(2))*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(x*sqrt(-c**S(2)*x**S(2) + S(-1))), x), x) + Simp((a + b*acsch(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def With6704(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return Dist(b*sqrt(c*x + S(1))*sqrt(S(1)/(c*x + S(1))), Int(SimplifyIntegrand(u/(x*sqrt(-c*x + S(1))*sqrt(c*x + S(1))), x), x), x) + Dist(a + b*asech(c*x), u, x) def With6705(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return -Dist(b*c*x/sqrt(-c**S(2)*x**S(2)), Int(SimplifyIntegrand(u/(x*sqrt(-c**S(2)*x**S(2) + S(-1))), x), x), x) + Dist(a + b*acsch(c*x), u, x) def replacement6706(a, b, c, d, e, m, n, p, x): return -Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*acosh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement6707(a, b, c, d, e, m, n, p, x): return -Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*asinh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement6708(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*acosh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6709(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*asinh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6710(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*acosh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6711(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*asinh(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement6712(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*asech(c*x))**n*(d + e*x**S(2))**p, x) def replacement6713(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*acsch(c*x))**n*(d + e*x**S(2))**p, x) def replacement6714(a, b, x): return Int(sqrt((-a - b*x + S(1))/(a + b*x + S(1)))/(-a - b*x + S(1)), x) + Simp((a + b*x)*asech(a + b*x)/b, x) def replacement6715(a, b, x): return Int(S(1)/(sqrt(S(1) + (a + b*x)**(S(-2)))*(a + b*x)), x) + Simp((a + b*x)*acsch(a + b*x)/b, x) def replacement6716(a, b, n, x): return -Dist(S(1)/b, Subst(Int(x**n*tanh(x)/cosh(x), x), x, asech(a + b*x)), x) def replacement6717(a, b, n, x): return -Dist(S(1)/b, Subst(Int(x**n/(sinh(x)*tanh(x)), x), x, acsch(a + b*x)), x) def replacement6718(a, b, x): return Simp(log(S(1) - (S(1) - sqrt(S(1) - a**S(2)))*exp(-asech(a + b*x))/a)*asech(a + b*x), x) + Simp(log(S(1) - (sqrt(S(1) - a**S(2)) + S(1))*exp(-asech(a + b*x))/a)*asech(a + b*x), x) - Simp(log(S(1) + exp(-S(2)*asech(a + b*x)))*asech(a + b*x), x) - Simp(PolyLog(S(2), (S(1) - sqrt(S(1) - a**S(2)))*exp(-asech(a + b*x))/a), x) - Simp(PolyLog(S(2), (sqrt(S(1) - a**S(2)) + S(1))*exp(-asech(a + b*x))/a), x) + Simp(PolyLog(S(2), -exp(-S(2)*asech(a + b*x)))/S(2), x) def replacement6719(a, b, x): return Simp(log(S(1) + (S(1) - sqrt(a**S(2) + S(1)))*exp(acsch(a + b*x))/a)*acsch(a + b*x), x) + Simp(log(S(1) + (sqrt(a**S(2) + S(1)) + S(1))*exp(acsch(a + b*x))/a)*acsch(a + b*x), x) - Simp(log(S(1) - exp(-S(2)*acsch(a + b*x)))*acsch(a + b*x), x) + Simp(PolyLog(S(2), -(S(1) - sqrt(a**S(2) + S(1)))*exp(acsch(a + b*x))/a), x) + Simp(PolyLog(S(2), -(sqrt(a**S(2) + S(1)) + S(1))*exp(acsch(a + b*x))/a), x) + Simp(PolyLog(S(2), exp(-S(2)*acsch(a + b*x)))/S(2), x) - Simp(acsch(a + b*x)**S(2), x) def replacement6720(a, b, m, x): return Dist(b**(-m + S(-1))/(m + S(1)), Subst(Int(x**(-m + S(-1))*((-a*x)**(m + S(1)) - (-a*x + S(1))**(m + S(1)))/(sqrt(x + S(-1))*sqrt(x + S(1))), x), x, S(1)/(a + b*x)), x) - Simp(b**(-m + S(-1))*(-b**(m + S(1))*x**(m + S(1)) + (-a)**(m + S(1)))*asech(a + b*x)/(m + S(1)), x) def replacement6721(a, b, m, x): return Dist(b**(-m + S(-1))/(m + S(1)), Subst(Int(x**(-m + S(-1))*((-a*x)**(m + S(1)) - (-a*x + S(1))**(m + S(1)))/sqrt(x**S(2) + S(1)), x), x, S(1)/(a + b*x)), x) - Simp(b**(-m + S(-1))*(-b**(m + S(1))*x**(m + S(1)) + (-a)**(m + S(1)))*acsch(a + b*x)/(m + S(1)), x) def replacement6722(a, b, m, n, x): return -Dist(b**(-m + S(-1)), Subst(Int(x**n*(-a + S(1)/cosh(x))**m*tanh(x)/cosh(x), x), x, asech(a + b*x)), x) def replacement6723(a, b, m, n, x): return -Dist(b**(-m + S(-1)), Subst(Int(x**n*(-a + S(1)/sinh(x))**m/(sinh(x)*tanh(x)), x), x, acsch(a + b*x)), x) def replacement6724(a, b, c, m, n, u, x): return Int(u*acosh(a/c + b*x**n/c)**m, x) def replacement6725(a, b, c, m, n, u, x): return Int(u*asinh(a/c + b*x**n/c)**m, x) def replacement6726(a, x): return Dist(S(1)/a, Int(sqrt((-a*x + S(1))/(a*x + S(1)))/(x*(-a*x + S(1))), x), x) + Simp(log(x)/a, x) + Simp(x*exp(asech(a*x)), x) def replacement6727(a, p, x): return Dist(p/a, Int(x**(-p), x), x) + Dist(p*sqrt(a*x**p + S(1))*sqrt(S(1)/(a*x**p + S(1)))/a, Int(x**(-p)/(sqrt(-a*x**p + S(1))*sqrt(a*x**p + S(1))), x), x) + Simp(x*exp(asech(a*x**p)), x) def replacement6728(a, p, x): return Dist(S(1)/a, Int(x**(-p), x), x) + Int(sqrt(S(1) + x**(-S(2)*p)/a**S(2)), x) def replacement6729(n, u, x): return Int((sqrt((S(1) - u)/(u + S(1))) + sqrt((S(1) - u)/(u + S(1)))/u + S(1)/u)**n, x) def replacement6730(n, u, x): return Int((sqrt(S(1) + u**(S(-2))) + S(1)/u)**n, x) def replacement6731(a, p, x): return Dist(sqrt(a*x**p + S(1))*sqrt(S(1)/(a*x**p + S(1)))/a, Int(x**(-p + S(-1))*sqrt(-a*x**p + S(1))*sqrt(a*x**p + S(1)), x), x) - Simp(x**(-p)/(a*p), x) def replacement6732(a, m, p, x): return Dist(p/(a*(m + S(1))), Int(x**(m - p), x), x) + Dist(p*sqrt(a*x**p + S(1))*sqrt(S(1)/(a*x**p + S(1)))/(a*(m + S(1))), Int(x**(m - p)/(sqrt(-a*x**p + S(1))*sqrt(a*x**p + S(1))), x), x) + Simp(x**(m + S(1))*exp(asech(a*x**p))/(m + S(1)), x) def replacement6733(a, m, p, x): return Dist(S(1)/a, Int(x**(m - p), x), x) + Int(x**m*sqrt(S(1) + x**(-S(2)*p)/a**S(2)), x) def replacement6734(m, n, u, x): return Int(x**m*(sqrt((S(1) - u)/(u + S(1))) + sqrt((S(1) - u)/(u + S(1)))/u + S(1)/u)**n, x) def replacement6735(m, n, u, x): return Int(x**m*(sqrt(S(1) + u**(S(-2))) + S(1)/u)**n, x) def replacement6736(u, x): return Dist(sqrt(S(1) - u**S(2))/(u*sqrt(S(-1) + S(1)/u)*sqrt(S(1) + S(1)/u)), Int(SimplifyIntegrand(x*D(u, x)/(u*sqrt(S(1) - u**S(2))), x), x), x) + Simp(x*asech(u), x) def replacement6737(u, x): return -Dist(u/sqrt(-u**S(2)), Int(SimplifyIntegrand(x*D(u, x)/(u*sqrt(-u**S(2) + S(-1))), x), x), x) + Simp(x*acsch(u), x) def replacement6738(a, b, c, d, m, u, x): return Dist(b*sqrt(S(1) - u**S(2))/(d*u*sqrt(S(-1) + S(1)/u)*sqrt(S(1) + S(1)/u)*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(u*sqrt(S(1) - u**S(2))), x), x), x) + Simp((a + b*asech(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement6739(a, b, c, d, m, u, x): return -Dist(b*u/(d*sqrt(-u**S(2))*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(u*sqrt(-u**S(2) + S(-1))), x), x), x) + Simp((a + b*acsch(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def With6740(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement6740(a, b, u, v, x): w = IntHide(v, x) return Dist(b*sqrt(S(1) - u**S(2))/(u*sqrt(S(-1) + S(1)/u)*sqrt(S(1) + S(1)/u)), Int(SimplifyIntegrand(w*D(u, x)/(u*sqrt(S(1) - u**S(2))), x), x), x) + Dist(a + b*asech(u), w, x) def With6741(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement6741(a, b, u, v, x): w = IntHide(v, x) return -Dist(b*u/sqrt(-u**S(2)), Int(SimplifyIntegrand(w*D(u, x)/(u*sqrt(-u**S(2) + S(-1))), x), x), x) + Dist(a + b*acsch(u), w, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/inverse_trig.py000066400000000000000000011534011412543434000242460ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def inverse_trig(): from sympy.integrals.rubi.constraints import cons89, cons90, cons2, cons3, cons8, cons91, cons1581, cons4, cons150, cons68, cons29, cons19, cons64, cons1736, cons1737, cons1738, cons1739, cons270, cons50, cons586, cons1740, cons130, cons340, cons165, cons139, cons232, cons5, cons1741, cons1742, cons1743, cons1744, cons1745, cons40, cons1746, cons1572, cons338, cons1747, cons149, cons127, cons210, cons56, cons244, cons1748, cons349, cons1749, cons488, cons963, cons95, cons96, cons164, cons274, cons1750, cons20, cons168, cons276, cons1751, cons21, cons1752, cons240, cons239, cons1753, cons248, cons1754, cons1755, cons1756, cons1757, cons1758, cons211, cons927, cons466, cons86, cons1759, cons1760, cons721, cons170, cons1761, cons669, cons1762, cons269, cons719, cons1763, cons1610, cons14, cons152, cons1200, cons1275, cons1362, cons1764, cons1765, cons36, cons37, cons38, cons1766, cons1767, cons167, cons1444, cons1768, cons1769, cons1770, cons1232, cons1771, cons1772, cons1773, cons1774, cons342, cons1775, cons1776, cons1777, cons1778, cons1045, cons87, cons33, cons1779, cons1499, cons1780, cons13, cons1781, cons1782, cons1783, cons1784, cons242, cons243, cons148, cons1785, cons1512, cons1786, cons1154, cons321, cons1787, cons1788, cons1789, cons1790, cons1791, cons1792, cons1793, cons1794, cons1795, cons1796, cons1797, cons1798, cons603, cons1799, cons263, cons1800, cons1801, cons1802, cons1803, cons1804, cons1805, cons1806, cons1807, cons179, cons119, cons1808, cons1809, cons1810, cons1811, cons1812, cons1813, cons1814, cons1815, cons1816, cons1817, cons1818, cons1819, cons1582, cons1820, cons1821, cons1822, cons1823, cons1824, cons1825, cons1826, cons1827, cons1828, cons1829, cons1830, cons1831, cons1832, cons1096, cons1833, cons1834, cons1835, cons1836, cons1837, cons385, cons1838, cons1839, cons820, cons465, cons1840, cons1841, cons1842, cons1843, cons1844, cons1845, cons1846, cons69, cons1847, cons1848, cons1849, cons1850, cons1851, cons1852, cons1853, cons554, cons1148, cons1854, cons1855, cons1244, cons1245, cons1856, cons180, cons1857, cons1858, cons1301, cons1859, cons1860 pattern5034 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons89, cons90) rule5034 = ReplacementRule(pattern5034, replacement5034) pattern5035 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons89, cons90) rule5035 = ReplacementRule(pattern5035, replacement5035) pattern5036 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons89, cons91) rule5036 = ReplacementRule(pattern5036, replacement5036) pattern5037 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons89, cons91) rule5037 = ReplacementRule(pattern5037, replacement5037) pattern5038 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule5038 = ReplacementRule(pattern5038, replacement5038) pattern5039 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule5039 = ReplacementRule(pattern5039, replacement5039) pattern5040 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/x_, x_), cons2, cons3, cons8, cons150) rule5040 = ReplacementRule(pattern5040, replacement5040) pattern5041 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/x_, x_), cons2, cons3, cons8, cons150) rule5041 = ReplacementRule(pattern5041, replacement5041) pattern5042 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons150, cons68) rule5042 = ReplacementRule(pattern5042, replacement5042) pattern5043 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons150, cons68) rule5043 = ReplacementRule(pattern5043, replacement5043) pattern5044 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons90) rule5044 = ReplacementRule(pattern5044, replacement5044) pattern5045 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons90) rule5045 = ReplacementRule(pattern5045, replacement5045) pattern5046 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1736) rule5046 = ReplacementRule(pattern5046, replacement5046) pattern5047 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1736) rule5047 = ReplacementRule(pattern5047, replacement5047) pattern5048 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1737) rule5048 = ReplacementRule(pattern5048, replacement5048) pattern5049 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons64, cons89, cons1737) rule5049 = ReplacementRule(pattern5049, replacement5049) pattern5050 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons64) rule5050 = ReplacementRule(pattern5050, replacement5050) pattern5051 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons64) rule5051 = ReplacementRule(pattern5051, replacement5051) pattern5052 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1738) rule5052 = ReplacementRule(pattern5052, replacement5052) pattern5053 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1738) rule5053 = ReplacementRule(pattern5053, replacement5053) pattern5054 = Pattern(Integral(S(1)/(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270) rule5054 = ReplacementRule(pattern5054, replacement5054) pattern5055 = Pattern(Integral(S(1)/(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270) rule5055 = ReplacementRule(pattern5055, replacement5055) pattern5056 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons270, cons586) rule5056 = ReplacementRule(pattern5056, replacement5056) pattern5057 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons270, cons586) rule5057 = ReplacementRule(pattern5057, replacement5057) pattern5058 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1740) rule5058 = ReplacementRule(pattern5058, replacement5058) pattern5059 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1740) rule5059 = ReplacementRule(pattern5059, replacement5059) pattern5060 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons130) rule5060 = ReplacementRule(pattern5060, With5060) pattern5061 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons130) rule5061 = ReplacementRule(pattern5061, With5061) pattern5062 = Pattern(Integral(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule5062 = ReplacementRule(pattern5062, replacement5062) pattern5063 = Pattern(Integral(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule5063 = ReplacementRule(pattern5063, replacement5063) pattern5064 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons90, cons165) rule5064 = ReplacementRule(pattern5064, replacement5064) pattern5065 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons90, cons165) rule5065 = ReplacementRule(pattern5065, replacement5065) pattern5066 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons270) rule5066 = ReplacementRule(pattern5066, replacement5066) pattern5067 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90, cons270) rule5067 = ReplacementRule(pattern5067, replacement5067) pattern5068 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule5068 = ReplacementRule(pattern5068, replacement5068) pattern5069 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons89, cons90) rule5069 = ReplacementRule(pattern5069, replacement5069) pattern5070 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons90, cons139, cons232) rule5070 = ReplacementRule(pattern5070, replacement5070) pattern5071 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons340, cons90, cons139, cons232) rule5071 = ReplacementRule(pattern5071, replacement5071) pattern5072 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule5072 = ReplacementRule(pattern5072, replacement5072) pattern5073 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule5073 = ReplacementRule(pattern5073, replacement5073) pattern5074 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons91) rule5074 = ReplacementRule(pattern5074, replacement5074) pattern5075 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons91) rule5075 = ReplacementRule(pattern5075, replacement5075) pattern5076 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1741, cons1742) rule5076 = ReplacementRule(pattern5076, replacement5076) pattern5077 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1741, cons1742) rule5077 = ReplacementRule(pattern5077, replacement5077) pattern5078 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1741, cons1743) rule5078 = ReplacementRule(pattern5078, replacement5078) pattern5079 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons1741, cons1743) rule5079 = ReplacementRule(pattern5079, replacement5079) pattern5080 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1744, cons1745) rule5080 = ReplacementRule(pattern5080, With5080) pattern5081 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1744, cons1745) rule5081 = ReplacementRule(pattern5081, With5081) pattern5082 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1744, cons40, cons1746) rule5082 = ReplacementRule(pattern5082, replacement5082) pattern5083 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1744, cons40, cons1746) rule5083 = ReplacementRule(pattern5083, replacement5083) pattern5084 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5084 = ReplacementRule(pattern5084, replacement5084) pattern5085 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5085 = ReplacementRule(pattern5085, replacement5085) pattern5086 = Pattern(Integral((d_ + x_*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons338, cons1747, cons149) rule5086 = ReplacementRule(pattern5086, replacement5086) pattern5087 = Pattern(Integral((d_ + x_*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons338, cons1747, cons149) rule5087 = ReplacementRule(pattern5087, replacement5087) pattern5088 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule5088 = ReplacementRule(pattern5088, replacement5088) pattern5089 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule5089 = ReplacementRule(pattern5089, replacement5089) pattern5090 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons56) rule5090 = ReplacementRule(pattern5090, replacement5090) pattern5091 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1739, cons89, cons90, cons56) rule5091 = ReplacementRule(pattern5091, replacement5091) pattern5092 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule5092 = ReplacementRule(pattern5092, replacement5092) pattern5093 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons150) rule5093 = ReplacementRule(pattern5093, replacement5093) pattern5094 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1739, cons89, cons90, cons244, cons68) rule5094 = ReplacementRule(pattern5094, replacement5094) pattern5095 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1739, cons89, cons90, cons244, cons68) rule5095 = ReplacementRule(pattern5095, replacement5095) pattern5096 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons130) rule5096 = ReplacementRule(pattern5096, replacement5096) pattern5097 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons130) rule5097 = ReplacementRule(pattern5097, replacement5097) pattern5098 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons130, cons1748) rule5098 = ReplacementRule(pattern5098, replacement5098) pattern5099 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons130, cons1748) rule5099 = ReplacementRule(pattern5099, replacement5099) pattern5100 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons130) rule5100 = ReplacementRule(pattern5100, With5100) pattern5101 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons130) rule5101 = ReplacementRule(pattern5101, With5101) pattern5102 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons349, cons1749, cons488, cons270) rule5102 = ReplacementRule(pattern5102, With5102) pattern5103 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons349, cons1749, cons488, cons270) rule5103 = ReplacementRule(pattern5103, With5103) pattern5104 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons963, cons1749) rule5104 = ReplacementRule(pattern5104, With5104) pattern5105 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons963, cons1749) rule5105 = ReplacementRule(pattern5105, With5105) pattern5106 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons95, cons90, cons96) rule5106 = ReplacementRule(pattern5106, replacement5106) pattern5107 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons95, cons90, cons96) rule5107 = ReplacementRule(pattern5107, replacement5107) pattern5108 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons164, cons90, cons165, cons96) rule5108 = ReplacementRule(pattern5108, replacement5108) pattern5109 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons164, cons90, cons165, cons96) rule5109 = ReplacementRule(pattern5109, replacement5109) pattern5110 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons89, cons90, cons274, cons1750) rule5110 = ReplacementRule(pattern5110, replacement5110) pattern5111 = Pattern(Integral((x_*WC('f', S(1)))**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons89, cons90, cons274, cons1750) rule5111 = ReplacementRule(pattern5111, replacement5111) pattern5112 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons340, cons90, cons165, cons274, cons1750) rule5112 = ReplacementRule(pattern5112, replacement5112) pattern5113 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons340, cons90, cons165, cons274, cons1750) rule5113 = ReplacementRule(pattern5113, replacement5113) pattern5114 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1739, cons95, cons90, cons96, cons20) rule5114 = ReplacementRule(pattern5114, replacement5114) pattern5115 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1739, cons95, cons90, cons96, cons20) rule5115 = ReplacementRule(pattern5115, replacement5115) pattern5116 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons164, cons90, cons139, cons168) rule5116 = ReplacementRule(pattern5116, replacement5116) pattern5117 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons164, cons90, cons139, cons168) rule5117 = ReplacementRule(pattern5117, replacement5117) pattern5118 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons340, cons90, cons139, cons276, cons1751) rule5118 = ReplacementRule(pattern5118, replacement5118) pattern5119 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons340, cons90, cons139, cons276, cons1751) rule5119 = ReplacementRule(pattern5119, replacement5119) pattern5120 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons95, cons90, cons168, cons20) rule5120 = ReplacementRule(pattern5120, replacement5120) pattern5121 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons95, cons90, cons168, cons20) rule5121 = ReplacementRule(pattern5121, replacement5121) pattern5122 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270, cons150, cons20) rule5122 = ReplacementRule(pattern5122, replacement5122) pattern5123 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1739, cons270, cons150, cons20) rule5123 = ReplacementRule(pattern5123, replacement5123) pattern5124 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons270, cons21) rule5124 = ReplacementRule(pattern5124, replacement5124) pattern5125 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons270, cons21) rule5125 = ReplacementRule(pattern5125, replacement5125) pattern5126 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons89, cons90, cons1740, cons1752) rule5126 = ReplacementRule(pattern5126, replacement5126) pattern5127 = Pattern(Integral((x_*WC('f', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons89, cons90, cons1740, cons1752) rule5127 = ReplacementRule(pattern5127, replacement5127) pattern5128 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1739, cons95, cons90, cons168, cons240, cons20) rule5128 = ReplacementRule(pattern5128, replacement5128) pattern5129 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons1739, cons95, cons90, cons168, cons240, cons20) rule5129 = ReplacementRule(pattern5129, replacement5129) pattern5130 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1739, cons89, cons91, cons239) rule5130 = ReplacementRule(pattern5130, replacement5130) pattern5131 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1739, cons89, cons91, cons239) rule5131 = ReplacementRule(pattern5131, replacement5131) pattern5132 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons89, cons91, cons270) rule5132 = ReplacementRule(pattern5132, replacement5132) pattern5133 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1739, cons89, cons91, cons270) rule5133 = ReplacementRule(pattern5133, replacement5133) pattern5134 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons89, cons91, cons20, cons1753, cons1741) rule5134 = ReplacementRule(pattern5134, replacement5134) pattern5135 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1739, cons89, cons91, cons20, cons1753, cons1741) rule5135 = ReplacementRule(pattern5135, replacement5135) pattern5136 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons248, cons1754, cons64, cons1742) rule5136 = ReplacementRule(pattern5136, replacement5136) pattern5137 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons248, cons1754, cons64, cons1742) rule5137 = ReplacementRule(pattern5137, replacement5137) pattern5138 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons248, cons1754, cons64, cons1743) rule5138 = ReplacementRule(pattern5138, replacement5138) pattern5139 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons248, cons1754, cons64, cons1743) rule5139 = ReplacementRule(pattern5139, replacement5139) pattern5140 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1739, cons270, cons963, cons1755, cons20, cons1756) rule5140 = ReplacementRule(pattern5140, replacement5140) pattern5141 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1739, cons270, cons963, cons1755, cons20, cons1756) rule5141 = ReplacementRule(pattern5141, replacement5141) pattern5142 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1744, cons56) rule5142 = ReplacementRule(pattern5142, replacement5142) pattern5143 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1744, cons56) rule5143 = ReplacementRule(pattern5143, replacement5143) pattern5144 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1744, cons40, cons1757) rule5144 = ReplacementRule(pattern5144, With5144) pattern5145 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1744, cons40, cons1757) rule5145 = ReplacementRule(pattern5145, With5145) pattern5146 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1744, cons150, cons40, cons20) rule5146 = ReplacementRule(pattern5146, replacement5146) pattern5147 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1744, cons150, cons40, cons20) rule5147 = ReplacementRule(pattern5147, replacement5147) pattern5148 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons1758) rule5148 = ReplacementRule(pattern5148, replacement5148) pattern5149 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons1758) rule5149 = ReplacementRule(pattern5149, replacement5149) pattern5150 = Pattern(Integral((x_*WC('h', S(1)))**WC('m', S(1))*(d_ + x_*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons338, cons1747, cons149) rule5150 = ReplacementRule(pattern5150, replacement5150) pattern5151 = Pattern(Integral((x_*WC('h', S(1)))**WC('m', S(1))*(d_ + x_*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons338, cons1747, cons149) rule5151 = ReplacementRule(pattern5151, replacement5151) pattern5152 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons150) rule5152 = ReplacementRule(pattern5152, replacement5152) pattern5153 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons150) rule5153 = ReplacementRule(pattern5153, replacement5153) pattern5154 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons150, cons68) rule5154 = ReplacementRule(pattern5154, replacement5154) pattern5155 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons150, cons68) rule5155 = ReplacementRule(pattern5155, replacement5155) pattern5156 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons64, cons89, cons91) rule5156 = ReplacementRule(pattern5156, replacement5156) pattern5157 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons64, cons89, cons91) rule5157 = ReplacementRule(pattern5157, replacement5157) pattern5158 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons64) rule5158 = ReplacementRule(pattern5158, replacement5158) pattern5159 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons64) rule5159 = ReplacementRule(pattern5159, replacement5159) pattern5160 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons927) rule5160 = ReplacementRule(pattern5160, With5160) pattern5161 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons927) rule5161 = ReplacementRule(pattern5161, With5161) pattern5162 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons927) rule5162 = ReplacementRule(pattern5162, replacement5162) pattern5163 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons927) rule5163 = ReplacementRule(pattern5163, replacement5163) pattern5164 = Pattern(Integral(Px_*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons927) rule5164 = ReplacementRule(pattern5164, With5164) pattern5165 = Pattern(Integral(Px_*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons927) rule5165 = ReplacementRule(pattern5165, With5165) pattern5166 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons466, cons86, cons1759) rule5166 = ReplacementRule(pattern5166, With5166) pattern5167 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons466, cons86, cons1759) rule5167 = ReplacementRule(pattern5167, With5167) pattern5168 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_*(x_**S(2)*WC('h', S(1)) + x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))/(d_ + x_*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons466, cons1760) rule5168 = ReplacementRule(pattern5168, With5168) pattern5169 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_*(x_**S(2)*WC('h', S(1)) + x_*WC('g', S(1)) + WC('f', S(0)))**WC('p', S(1))/(d_ + x_*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons466, cons1760) rule5169 = ReplacementRule(pattern5169, With5169) pattern5170 = Pattern(Integral(Px_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons927, cons150, cons20) rule5170 = ReplacementRule(pattern5170, replacement5170) pattern5171 = Pattern(Integral(Px_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons927, cons150, cons20) rule5171 = ReplacementRule(pattern5171, replacement5171) pattern5172 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons721, cons270, cons170, cons1761) rule5172 = ReplacementRule(pattern5172, With5172) pattern5173 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons721, cons270, cons170, cons1761) rule5173 = ReplacementRule(pattern5173, With5173) pattern5174 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons669, cons270, cons150, cons170, cons1762) rule5174 = ReplacementRule(pattern5174, replacement5174) pattern5175 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons669, cons270, cons150, cons170, cons1762) rule5175 = ReplacementRule(pattern5175, replacement5175) pattern5176 = Pattern(Integral(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(f_ + x_*WC('g', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons270, cons150, cons269) rule5176 = ReplacementRule(pattern5176, replacement5176) pattern5177 = Pattern(Integral(sqrt(d_ + x_**S(2)*WC('e', S(1)))*(f_ + x_*WC('g', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons270, cons150, cons269) rule5177 = ReplacementRule(pattern5177, replacement5177) pattern5178 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons963, cons270, cons150) rule5178 = ReplacementRule(pattern5178, replacement5178) pattern5179 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons963, cons270, cons150) rule5179 = ReplacementRule(pattern5179, replacement5179) pattern5180 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons719, cons270, cons150, cons269) rule5180 = ReplacementRule(pattern5180, replacement5180) pattern5181 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons719, cons270, cons150, cons269) rule5181 = ReplacementRule(pattern5181, replacement5181) pattern5182 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**n_/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons270, cons170, cons89, cons91) rule5182 = ReplacementRule(pattern5182, replacement5182) pattern5183 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**n_/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons270, cons170, cons89, cons91) rule5183 = ReplacementRule(pattern5183, replacement5183) pattern5184 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1739, cons20, cons270, cons1763) rule5184 = ReplacementRule(pattern5184, replacement5184) pattern5185 = Pattern(Integral((f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1739, cons20, cons270, cons1763) rule5185 = ReplacementRule(pattern5185, replacement5185) pattern5186 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons721, cons270, cons150) rule5186 = ReplacementRule(pattern5186, replacement5186) pattern5187 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1739, cons20, cons721, cons270, cons150) rule5187 = ReplacementRule(pattern5187, replacement5187) pattern5188 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1739, cons20, cons349, cons1740) rule5188 = ReplacementRule(pattern5188, replacement5188) pattern5189 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1739, cons20, cons349, cons1740) rule5189 = ReplacementRule(pattern5189, replacement5189) pattern5190 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1)))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons1739, cons270, cons150) rule5190 = ReplacementRule(pattern5190, replacement5190) pattern5191 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1)))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons1739, cons270, cons150) rule5191 = ReplacementRule(pattern5191, replacement5191) pattern5192 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons1739, cons349, cons1740) rule5192 = ReplacementRule(pattern5192, replacement5192) pattern5193 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*WC('h', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons1739, cons349, cons1740) rule5193 = ReplacementRule(pattern5193, replacement5193) pattern5194 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(f_ + x_*WC('g', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1610) rule5194 = ReplacementRule(pattern5194, With5194) pattern5195 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(f_ + x_*WC('g', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1610) rule5195 = ReplacementRule(pattern5195, With5195) pattern5196 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons20) rule5196 = ReplacementRule(pattern5196, replacement5196) pattern5197 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(f_ + x_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons20) rule5197 = ReplacementRule(pattern5197, replacement5197) pattern5198 = Pattern(Integral(u_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons14, CustomConstraint(With5198)) rule5198 = ReplacementRule(pattern5198, replacement5198) pattern5199 = Pattern(Integral(u_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons14, CustomConstraint(With5199)) rule5199 = ReplacementRule(pattern5199, replacement5199) pattern5200 = Pattern(Integral(Px_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons927, cons1739, cons349, CustomConstraint(With5200)) rule5200 = ReplacementRule(pattern5200, replacement5200) pattern5201 = Pattern(Integral(Px_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons927, cons1739, cons349, CustomConstraint(With5201)) rule5201 = ReplacementRule(pattern5201, replacement5201) pattern5202 = Pattern(Integral((f_ + (d_ + x_**S(2)*WC('e', S(1)))**p_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))*WC('Px', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons927, cons1739, cons963, cons152, CustomConstraint(With5202)) rule5202 = ReplacementRule(pattern5202, replacement5202) pattern5203 = Pattern(Integral((f_ + (d_ + x_**S(2)*WC('e', S(1)))**p_*WC('g', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))*WC('Px', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons927, cons1739, cons963, cons152, CustomConstraint(With5203)) rule5203 = ReplacementRule(pattern5203, replacement5203) pattern5204 = Pattern(Integral(RFx_*asin(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons1200, cons150, CustomConstraint(With5204)) rule5204 = ReplacementRule(pattern5204, replacement5204) pattern5205 = Pattern(Integral(RFx_*acos(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons1200, cons150, CustomConstraint(With5205)) rule5205 = ReplacementRule(pattern5205, replacement5205) pattern5206 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons1200, cons150) rule5206 = ReplacementRule(pattern5206, replacement5206) pattern5207 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons1200, cons150) rule5207 = ReplacementRule(pattern5207, replacement5207) pattern5208 = Pattern(Integral(RFx_*(d_ + x_**S(2)*WC('e', S(1)))**p_*asin(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons29, cons50, cons1200, cons150, cons1739, cons349, CustomConstraint(With5208)) rule5208 = ReplacementRule(pattern5208, replacement5208) pattern5209 = Pattern(Integral(RFx_*(d_ + x_**S(2)*WC('e', S(1)))**p_*acos(x_*WC('c', S(1)))**WC('n', S(1)), x_), cons8, cons29, cons50, cons1200, cons150, cons1739, cons349, CustomConstraint(With5209)) rule5209 = ReplacementRule(pattern5209, replacement5209) pattern5210 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons1200, cons150, cons1739, cons349) rule5210 = ReplacementRule(pattern5210, replacement5210) pattern5211 = Pattern(Integral(RFx_*(a_ + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons1200, cons150, cons1739, cons349) rule5211 = ReplacementRule(pattern5211, replacement5211) pattern5212 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(x_*WC('c', S(1))))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule5212 = ReplacementRule(pattern5212, replacement5212) pattern5213 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_*WC('c', S(1))))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule5213 = ReplacementRule(pattern5213, replacement5213) pattern5214 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1275) rule5214 = ReplacementRule(pattern5214, replacement5214) pattern5215 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1275) rule5215 = ReplacementRule(pattern5215, replacement5215) pattern5216 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule5216 = ReplacementRule(pattern5216, replacement5216) pattern5217 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule5217 = ReplacementRule(pattern5217, replacement5217) pattern5218 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1764, cons1765) rule5218 = ReplacementRule(pattern5218, replacement5218) pattern5219 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1764, cons1765) rule5219 = ReplacementRule(pattern5219, replacement5219) pattern5220 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1764, cons1765) rule5220 = ReplacementRule(pattern5220, replacement5220) pattern5221 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1764, cons1765) rule5221 = ReplacementRule(pattern5221, replacement5221) pattern5222 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons1766) rule5222 = ReplacementRule(pattern5222, replacement5222) pattern5223 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(1))), x_), cons2, cons3, cons29, cons1767) rule5223 = ReplacementRule(pattern5223, replacement5223) pattern5224 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(-1))), x_), cons2, cons3, cons29, cons1767) rule5224 = ReplacementRule(pattern5224, replacement5224) pattern5225 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1766, cons89, cons167) rule5225 = ReplacementRule(pattern5225, replacement5225) pattern5226 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1766, cons89, cons167) rule5226 = ReplacementRule(pattern5226, replacement5226) pattern5227 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons1766) rule5227 = ReplacementRule(pattern5227, replacement5227) pattern5228 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(1))), x_), cons2, cons3, cons29, cons1767) rule5228 = ReplacementRule(pattern5228, replacement5228) pattern5229 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(-1))), x_), cons2, cons3, cons29, cons1767) rule5229 = ReplacementRule(pattern5229, replacement5229) pattern5230 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons1766) rule5230 = ReplacementRule(pattern5230, replacement5230) pattern5231 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(1))), x_), cons2, cons3, cons29, cons1767) rule5231 = ReplacementRule(pattern5231, replacement5231) pattern5232 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(-1))), x_), cons2, cons3, cons29, cons1767) rule5232 = ReplacementRule(pattern5232, replacement5232) pattern5233 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_**S(2)*WC('d', S(1))))**(S(-3)/2), x_), cons2, cons3, cons8, cons29, cons1766) rule5233 = ReplacementRule(pattern5233, replacement5233) pattern5234 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(1)))**(S(-3)/2), x_), cons2, cons3, cons29, cons1767) rule5234 = ReplacementRule(pattern5234, replacement5234) pattern5235 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(-1)))**(S(-3)/2), x_), cons2, cons3, cons29, cons1767) rule5235 = ReplacementRule(pattern5235, replacement5235) pattern5236 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_**S(2)*WC('d', S(1))))**(S(-2)), x_), cons2, cons3, cons8, cons29, cons1766) rule5236 = ReplacementRule(pattern5236, replacement5236) pattern5237 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(1)))**(S(-2)), x_), cons2, cons3, cons29, cons1767) rule5237 = ReplacementRule(pattern5237, replacement5237) pattern5238 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(x_**S(2)*WC('d', S(1)) + S(-1)))**(S(-2)), x_), cons2, cons3, cons29, cons1767) rule5238 = ReplacementRule(pattern5238, replacement5238) pattern5239 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asin(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1766, cons89, cons91, cons1444) rule5239 = ReplacementRule(pattern5239, replacement5239) pattern5240 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acos(c_ + x_**S(2)*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons1766, cons89, cons91, cons1444) rule5240 = ReplacementRule(pattern5240, replacement5240) pattern5241 = Pattern(Integral(asin(x_**p_*WC('a', S(1)))**WC('n', S(1))/x_, x_), cons2, cons5, cons150) rule5241 = ReplacementRule(pattern5241, replacement5241) pattern5242 = Pattern(Integral(acos(x_**p_*WC('a', S(1)))**WC('n', S(1))/x_, x_), cons2, cons5, cons150) rule5242 = ReplacementRule(pattern5242, replacement5242) pattern5243 = Pattern(Integral(WC('u', S(1))*asin(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule5243 = ReplacementRule(pattern5243, replacement5243) pattern5244 = Pattern(Integral(WC('u', S(1))*acos(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule5244 = ReplacementRule(pattern5244, replacement5244) pattern5245 = Pattern(Integral(asin(sqrt(x_**S(2)*WC('b', S(1)) + S(1)))**WC('n', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + S(1)), x_), cons3, cons4, cons1769) rule5245 = ReplacementRule(pattern5245, replacement5245) pattern5246 = Pattern(Integral(acos(sqrt(x_**S(2)*WC('b', S(1)) + S(1)))**WC('n', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + S(1)), x_), cons3, cons4, cons1769) rule5246 = ReplacementRule(pattern5246, replacement5246) pattern5247 = Pattern(Integral(f_**(WC('c', S(1))*asin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)))*WC('u', S(1)), x_), cons2, cons3, cons8, cons127, cons150) rule5247 = ReplacementRule(pattern5247, replacement5247) pattern5248 = Pattern(Integral(f_**(WC('c', S(1))*acos(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)))*WC('u', S(1)), x_), cons2, cons3, cons8, cons127, cons150) rule5248 = ReplacementRule(pattern5248, replacement5248) pattern5249 = Pattern(Integral(asin(x_**S(2)*WC('a', S(1)) + sqrt(c_ + x_**S(2)*WC('d', S(1)))*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons1770) rule5249 = ReplacementRule(pattern5249, replacement5249) pattern5250 = Pattern(Integral(acos(x_**S(2)*WC('a', S(1)) + sqrt(c_ + x_**S(2)*WC('d', S(1)))*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons1770) rule5250 = ReplacementRule(pattern5250, replacement5250) pattern5251 = Pattern(Integral(asin(u_), x_), cons1232, cons1771) rule5251 = ReplacementRule(pattern5251, replacement5251) pattern5252 = Pattern(Integral(acos(u_), x_), cons1232, cons1771) rule5252 = ReplacementRule(pattern5252, replacement5252) pattern5253 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asin(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule5253 = ReplacementRule(pattern5253, replacement5253) pattern5254 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acos(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule5254 = ReplacementRule(pattern5254, replacement5254) pattern5255 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*asin(u_)), x_), cons2, cons3, cons1232, cons1773, CustomConstraint(With5255)) rule5255 = ReplacementRule(pattern5255, replacement5255) pattern5256 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*acos(u_)), x_), cons2, cons3, cons1232, cons1774, CustomConstraint(With5256)) rule5256 = ReplacementRule(pattern5256, replacement5256) pattern5257 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons150) rule5257 = ReplacementRule(pattern5257, replacement5257) pattern5258 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons150) rule5258 = ReplacementRule(pattern5258, replacement5258) pattern5259 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons4, cons342) rule5259 = ReplacementRule(pattern5259, replacement5259) pattern5260 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons342) rule5260 = ReplacementRule(pattern5260, replacement5260) pattern5261 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150) rule5261 = ReplacementRule(pattern5261, replacement5261) pattern5262 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150) rule5262 = ReplacementRule(pattern5262, replacement5262) pattern5263 = Pattern(Integral(ArcTan(x_*WC('c', S(1)))/(d_ + x_*WC('e', S(1))), x_), cons8, cons29, cons50, cons1776, cons1777) rule5263 = ReplacementRule(pattern5263, replacement5263) pattern5264 = Pattern(Integral(ArcTan(x_*WC('c', S(1)))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule5264 = ReplacementRule(pattern5264, replacement5264) pattern5265 = Pattern(Integral(acot(x_*WC('c', S(1)))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule5265 = ReplacementRule(pattern5265, replacement5265) pattern5266 = Pattern(Integral((a_ + ArcTan(x_*WC('c', S(1)))*WC('b', S(1)))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule5266 = ReplacementRule(pattern5266, replacement5266) pattern5267 = Pattern(Integral((a_ + WC('b', S(1))*acot(x_*WC('c', S(1))))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule5267 = ReplacementRule(pattern5267, replacement5267) pattern5268 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule5268 = ReplacementRule(pattern5268, replacement5268) pattern5269 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule5269 = ReplacementRule(pattern5269, replacement5269) pattern5270 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_/x_, x_), cons2, cons3, cons8, cons87, cons167) rule5270 = ReplacementRule(pattern5270, replacement5270) pattern5271 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_/x_, x_), cons2, cons3, cons8, cons87, cons167) rule5271 = ReplacementRule(pattern5271, replacement5271) pattern5272 = Pattern(Integral(x_**WC('m', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons19, cons87, cons167, cons68) rule5272 = ReplacementRule(pattern5272, replacement5272) pattern5273 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons19, cons87, cons167, cons68) rule5273 = ReplacementRule(pattern5273, replacement5273) pattern5274 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons466) rule5274 = ReplacementRule(pattern5274, replacement5274) pattern5275 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons466) rule5275 = ReplacementRule(pattern5275, replacement5275) pattern5276 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5276 = ReplacementRule(pattern5276, replacement5276) pattern5277 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5277 = ReplacementRule(pattern5277, replacement5277) pattern5278 = Pattern(Integral(x_**WC('m', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150, cons33, cons170) rule5278 = ReplacementRule(pattern5278, replacement5278) pattern5279 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150, cons33, cons170) rule5279 = ReplacementRule(pattern5279, replacement5279) pattern5280 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(x_*(d_ + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150) rule5280 = ReplacementRule(pattern5280, replacement5280) pattern5281 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150) rule5281 = ReplacementRule(pattern5281, replacement5281) pattern5282 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150, cons33, cons96) rule5282 = ReplacementRule(pattern5282, replacement5282) pattern5283 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1775, cons150, cons33, cons96) rule5283 = ReplacementRule(pattern5283, replacement5283) pattern5284 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1779) rule5284 = ReplacementRule(pattern5284, replacement5284) pattern5285 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1779) rule5285 = ReplacementRule(pattern5285, replacement5285) pattern5286 = Pattern(Integral(x_**WC('m', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5286 = ReplacementRule(pattern5286, replacement5286) pattern5287 = Pattern(Integral(x_**WC('m', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5287 = ReplacementRule(pattern5287, replacement5287) pattern5288 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons13, cons165) rule5288 = ReplacementRule(pattern5288, replacement5288) pattern5289 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons13, cons165) rule5289 = ReplacementRule(pattern5289, replacement5289) pattern5290 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons165, cons167) rule5290 = ReplacementRule(pattern5290, replacement5290) pattern5291 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons165, cons167) rule5291 = ReplacementRule(pattern5291, replacement5291) pattern5292 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780) rule5292 = ReplacementRule(pattern5292, replacement5292) pattern5293 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1780) rule5293 = ReplacementRule(pattern5293, replacement5293) pattern5294 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons586) rule5294 = ReplacementRule(pattern5294, replacement5294) pattern5295 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons586) rule5295 = ReplacementRule(pattern5295, replacement5295) pattern5296 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons270) rule5296 = ReplacementRule(pattern5296, replacement5296) pattern5297 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons270) rule5297 = ReplacementRule(pattern5297, replacement5297) pattern5298 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons270) rule5298 = ReplacementRule(pattern5298, replacement5298) pattern5299 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons270) rule5299 = ReplacementRule(pattern5299, replacement5299) pattern5300 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons1740) rule5300 = ReplacementRule(pattern5300, replacement5300) pattern5301 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons1740) rule5301 = ReplacementRule(pattern5301, replacement5301) pattern5302 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5302 = ReplacementRule(pattern5302, replacement5302) pattern5303 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5303 = ReplacementRule(pattern5303, replacement5303) pattern5304 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1780) rule5304 = ReplacementRule(pattern5304, replacement5304) pattern5305 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1780) rule5305 = ReplacementRule(pattern5305, replacement5305) pattern5306 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons13, cons139, cons232) rule5306 = ReplacementRule(pattern5306, replacement5306) pattern5307 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons13, cons139, cons232) rule5307 = ReplacementRule(pattern5307, replacement5307) pattern5308 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons167) rule5308 = ReplacementRule(pattern5308, replacement5308) pattern5309 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons167) rule5309 = ReplacementRule(pattern5309, replacement5309) pattern5310 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons139, cons167, cons232) rule5310 = ReplacementRule(pattern5310, replacement5310) pattern5311 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons139, cons167, cons232) rule5311 = ReplacementRule(pattern5311, replacement5311) pattern5312 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons139, cons91) rule5312 = ReplacementRule(pattern5312, replacement5312) pattern5313 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons340, cons139, cons91) rule5313 = ReplacementRule(pattern5313, replacement5313) pattern5314 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons1781, cons1742) rule5314 = ReplacementRule(pattern5314, replacement5314) pattern5315 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons1781, cons1743) rule5315 = ReplacementRule(pattern5315, replacement5315) pattern5316 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons1781, cons40) rule5316 = ReplacementRule(pattern5316, replacement5316) pattern5317 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons1781, cons149) rule5317 = ReplacementRule(pattern5317, replacement5317) pattern5318 = Pattern(Integral(ArcTan(x_*WC('c', S(1)))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule5318 = ReplacementRule(pattern5318, replacement5318) pattern5319 = Pattern(Integral(acot(x_*WC('c', S(1)))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons8, cons29, cons50, cons1778) rule5319 = ReplacementRule(pattern5319, replacement5319) pattern5320 = Pattern(Integral((a_ + ArcTan(x_*WC('c', S(1)))*WC('b', S(1)))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule5320 = ReplacementRule(pattern5320, replacement5320) pattern5321 = Pattern(Integral((a_ + WC('b', S(1))*acot(x_*WC('c', S(1))))/(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule5321 = ReplacementRule(pattern5321, replacement5321) pattern5322 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1782) rule5322 = ReplacementRule(pattern5322, With5322) pattern5323 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1782) rule5323 = ReplacementRule(pattern5323, With5323) pattern5324 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150) rule5324 = ReplacementRule(pattern5324, replacement5324) pattern5325 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150) rule5325 = ReplacementRule(pattern5325, replacement5325) pattern5326 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5326 = ReplacementRule(pattern5326, replacement5326) pattern5327 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5327 = ReplacementRule(pattern5327, replacement5327) pattern5328 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons168) rule5328 = ReplacementRule(pattern5328, replacement5328) pattern5329 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons168) rule5329 = ReplacementRule(pattern5329, replacement5329) pattern5330 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons96) rule5330 = ReplacementRule(pattern5330, replacement5330) pattern5331 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons95, cons90, cons96) rule5331 = ReplacementRule(pattern5331, replacement5331) pattern5332 = Pattern(Integral(x_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150) rule5332 = ReplacementRule(pattern5332, replacement5332) pattern5333 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150) rule5333 = ReplacementRule(pattern5333, replacement5333) pattern5334 = Pattern(Integral(x_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons342, cons586) rule5334 = ReplacementRule(pattern5334, replacement5334) pattern5335 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons342, cons586) rule5335 = ReplacementRule(pattern5335, replacement5335) pattern5336 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons168) rule5336 = ReplacementRule(pattern5336, replacement5336) pattern5337 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons168) rule5337 = ReplacementRule(pattern5337, replacement5337) pattern5338 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5338 = ReplacementRule(pattern5338, replacement5338) pattern5339 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(x_*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5339 = ReplacementRule(pattern5339, replacement5339) pattern5340 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons96) rule5340 = ReplacementRule(pattern5340, replacement5340) pattern5341 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons96) rule5341 = ReplacementRule(pattern5341, replacement5341) pattern5342 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons89, cons91) rule5342 = ReplacementRule(pattern5342, replacement5342) pattern5343 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons89, cons91) rule5343 = ReplacementRule(pattern5343, replacement5343) pattern5344 = Pattern(Integral(x_**WC('m', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons20, cons1783) rule5344 = ReplacementRule(pattern5344, replacement5344) pattern5345 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons20, cons1783) rule5345 = ReplacementRule(pattern5345, replacement5345) pattern5346 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons90, cons56) rule5346 = ReplacementRule(pattern5346, replacement5346) pattern5347 = Pattern(Integral(x_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons90, cons56) rule5347 = ReplacementRule(pattern5347, replacement5347) pattern5348 = Pattern(Integral(x_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons91, cons1444) rule5348 = ReplacementRule(pattern5348, replacement5348) pattern5349 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons91, cons1444) rule5349 = ReplacementRule(pattern5349, replacement5349) pattern5350 = Pattern(Integral(x_**S(2)*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons13, cons139, cons1784) rule5350 = ReplacementRule(pattern5350, replacement5350) pattern5351 = Pattern(Integral(x_**S(2)*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons13, cons139, cons1784) rule5351 = ReplacementRule(pattern5351, replacement5351) pattern5352 = Pattern(Integral(x_**S(2)*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5352 = ReplacementRule(pattern5352, replacement5352) pattern5353 = Pattern(Integral(x_**S(2)*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5353 = ReplacementRule(pattern5353, replacement5353) pattern5354 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons242, cons13, cons139) rule5354 = ReplacementRule(pattern5354, replacement5354) pattern5355 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons242, cons13, cons139) rule5355 = ReplacementRule(pattern5355, replacement5355) pattern5356 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons242, cons340, cons139, cons167) rule5356 = ReplacementRule(pattern5356, replacement5356) pattern5357 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons242, cons340, cons139, cons167) rule5357 = ReplacementRule(pattern5357, replacement5357) pattern5358 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1780, cons242, cons89, cons91) rule5358 = ReplacementRule(pattern5358, replacement5358) pattern5359 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1780, cons242, cons89, cons91) rule5359 = ReplacementRule(pattern5359, replacement5359) pattern5360 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1780, cons244, cons89, cons90, cons68) rule5360 = ReplacementRule(pattern5360, replacement5360) pattern5361 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1780, cons244, cons89, cons90, cons68) rule5361 = ReplacementRule(pattern5361, replacement5361) pattern5362 = Pattern(Integral(x_**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons243) rule5362 = ReplacementRule(pattern5362, replacement5362) pattern5363 = Pattern(Integral(x_**m_*sqrt(d_ + x_**S(2)*WC('e', S(1)))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons243) rule5363 = ReplacementRule(pattern5363, replacement5363) pattern5364 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons150, cons40, cons148) rule5364 = ReplacementRule(pattern5364, replacement5364) pattern5365 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons150, cons40, cons148) rule5365 = ReplacementRule(pattern5365, replacement5365) pattern5366 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons13, cons165, cons150, cons1785) rule5366 = ReplacementRule(pattern5366, replacement5366) pattern5367 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1780, cons13, cons165, cons150, cons1785) rule5367 = ReplacementRule(pattern5367, replacement5367) pattern5368 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons168) rule5368 = ReplacementRule(pattern5368, replacement5368) pattern5369 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons168) rule5369 = ReplacementRule(pattern5369, replacement5369) pattern5370 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons270) rule5370 = ReplacementRule(pattern5370, replacement5370) pattern5371 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons270) rule5371 = ReplacementRule(pattern5371, replacement5371) pattern5372 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons270) rule5372 = ReplacementRule(pattern5372, replacement5372) pattern5373 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**n_/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons270) rule5373 = ReplacementRule(pattern5373, replacement5373) pattern5374 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons1740) rule5374 = ReplacementRule(pattern5374, replacement5374) pattern5375 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(x_*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons150, cons1740) rule5375 = ReplacementRule(pattern5375, replacement5375) pattern5376 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(x_**S(2)*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5376 = ReplacementRule(pattern5376, replacement5376) pattern5377 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(x_**S(2)*sqrt(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90) rule5377 = ReplacementRule(pattern5377, replacement5377) pattern5378 = Pattern(Integral(x_**m_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons96, cons1512) rule5378 = ReplacementRule(pattern5378, replacement5378) pattern5379 = Pattern(Integral(x_**m_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons95, cons90, cons96, cons1512) rule5379 = ReplacementRule(pattern5379, replacement5379) pattern5380 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons1786, cons139, cons168, cons1154) rule5380 = ReplacementRule(pattern5380, replacement5380) pattern5381 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons1786, cons139, cons168, cons1154) rule5381 = ReplacementRule(pattern5381, replacement5381) pattern5382 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons1786, cons139, cons269, cons1154) rule5382 = ReplacementRule(pattern5382, replacement5382) pattern5383 = Pattern(Integral(x_**m_*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons1786, cons139, cons269, cons1154) rule5383 = ReplacementRule(pattern5383, replacement5383) pattern5384 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons164, cons139, cons91, cons321) rule5384 = ReplacementRule(pattern5384, replacement5384) pattern5385 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons164, cons139, cons91, cons321) rule5385 = ReplacementRule(pattern5385, replacement5385) pattern5386 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons64, cons1787, cons1742) rule5386 = ReplacementRule(pattern5386, replacement5386) pattern5387 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons64, cons1787, cons1743) rule5387 = ReplacementRule(pattern5387, replacement5387) pattern5388 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons64, cons1787, cons40) rule5388 = ReplacementRule(pattern5388, replacement5388) pattern5389 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**p_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1780, cons64, cons1787, cons149) rule5389 = ReplacementRule(pattern5389, replacement5389) pattern5390 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule5390 = ReplacementRule(pattern5390, replacement5390) pattern5391 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule5391 = ReplacementRule(pattern5391, replacement5391) pattern5392 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule5392 = ReplacementRule(pattern5392, With5392) pattern5393 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule5393 = ReplacementRule(pattern5393, With5393) pattern5394 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1789) rule5394 = ReplacementRule(pattern5394, replacement5394) pattern5395 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons1789) rule5395 = ReplacementRule(pattern5395, replacement5395) pattern5396 = Pattern(Integral(x_**WC('m', S(1))*(a_ + ArcTan(x_*WC('c', S(1)))*WC('b', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1790) rule5396 = ReplacementRule(pattern5396, replacement5396) pattern5397 = Pattern(Integral(x_**WC('m', S(1))*(a_ + WC('b', S(1))*acot(x_*WC('c', S(1))))*(d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1790) rule5397 = ReplacementRule(pattern5397, replacement5397) pattern5398 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5398 = ReplacementRule(pattern5398, replacement5398) pattern5399 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5399 = ReplacementRule(pattern5399, replacement5399) pattern5400 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*atanh(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1791) rule5400 = ReplacementRule(pattern5400, replacement5400) pattern5401 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))*acoth(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1791) rule5401 = ReplacementRule(pattern5401, replacement5401) pattern5402 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*atanh(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1792) rule5402 = ReplacementRule(pattern5402, replacement5402) pattern5403 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))*acoth(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1792) rule5403 = ReplacementRule(pattern5403, replacement5403) pattern5404 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1793) rule5404 = ReplacementRule(pattern5404, replacement5404) pattern5405 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1793) rule5405 = ReplacementRule(pattern5405, replacement5405) pattern5406 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1794) rule5406 = ReplacementRule(pattern5406, replacement5406) pattern5407 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))*log(u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons89, cons90, cons1794) rule5407 = ReplacementRule(pattern5407, replacement5407) pattern5408 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons90, cons1791) rule5408 = ReplacementRule(pattern5408, replacement5408) pattern5409 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons90, cons1791) rule5409 = ReplacementRule(pattern5409, replacement5409) pattern5410 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons90, cons1792) rule5410 = ReplacementRule(pattern5410, replacement5410) pattern5411 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))*PolyLog(p_, u_)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1780, cons89, cons90, cons1792) rule5411 = ReplacementRule(pattern5411, replacement5411) pattern5412 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons1780) rule5412 = ReplacementRule(pattern5412, replacement5412) pattern5413 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('m', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons152, cons1795) rule5413 = ReplacementRule(pattern5413, replacement5413) pattern5414 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**WC('n', S(1))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1780, cons152, cons1796) rule5414 = ReplacementRule(pattern5414, replacement5414) pattern5415 = Pattern(Integral(ArcTan(x_*WC('a', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons8, cons29, cons87, cons1797) rule5415 = ReplacementRule(pattern5415, replacement5415) pattern5416 = Pattern(Integral(acot(x_*WC('a', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons8, cons29, cons87, cons1797) rule5416 = ReplacementRule(pattern5416, replacement5416) pattern5417 = Pattern(Integral((ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1798) rule5417 = ReplacementRule(pattern5417, replacement5417) pattern5418 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1798) rule5418 = ReplacementRule(pattern5418, replacement5418) pattern5419 = Pattern(Integral(x_**WC('m', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons603) rule5419 = ReplacementRule(pattern5419, replacement5419) pattern5420 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons603) rule5420 = ReplacementRule(pattern5420, replacement5420) pattern5421 = Pattern(Integral(x_**WC('m', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1799) rule5421 = ReplacementRule(pattern5421, With5421) pattern5422 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1799) rule5422 = ReplacementRule(pattern5422, With5422) pattern5423 = Pattern(Integral(x_**WC('m', S(1))*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons20, cons263) rule5423 = ReplacementRule(pattern5423, With5423) pattern5424 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))*(WC('d', S(0)) + WC('e', S(1))*log(x_**S(2)*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons20, cons263) rule5424 = ReplacementRule(pattern5424, With5424) pattern5425 = Pattern(Integral(x_*(ArcTan(x_*WC('c', S(1)))*WC('b', S(1)) + WC('a', S(0)))**S(2)*(WC('d', S(0)) + WC('e', S(1))*log(f_ + x_**S(2)*WC('g', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1800) rule5425 = ReplacementRule(pattern5425, replacement5425) pattern5426 = Pattern(Integral(x_*(WC('a', S(0)) + WC('b', S(1))*acot(x_*WC('c', S(1))))**S(2)*(WC('d', S(0)) + WC('e', S(1))*log(f_ + x_**S(2)*WC('g', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1800) rule5426 = ReplacementRule(pattern5426, replacement5426) pattern5427 = Pattern(Integral(exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons1801) rule5427 = ReplacementRule(pattern5427, replacement5427) pattern5428 = Pattern(Integral(x_**WC('m', S(1))*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons19, cons1801) rule5428 = ReplacementRule(pattern5428, replacement5428) pattern5429 = Pattern(Integral(exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons4, cons1802) rule5429 = ReplacementRule(pattern5429, replacement5429) pattern5430 = Pattern(Integral(x_**WC('m', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons19, cons4, cons1802) rule5430 = ReplacementRule(pattern5430, replacement5430) pattern5431 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1803, cons1804) rule5431 = ReplacementRule(pattern5431, replacement5431) pattern5432 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1803, cons1805) rule5432 = ReplacementRule(pattern5432, replacement5432) pattern5433 = Pattern(Integral((c_ + WC('d', S(1))/x_)**WC('p', S(1))*WC('u', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons1806, cons40) rule5433 = ReplacementRule(pattern5433, replacement5433) pattern5434 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(n_*atanh(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1806, cons149, cons1807, cons179) rule5434 = ReplacementRule(pattern5434, replacement5434) pattern5435 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1806, cons149, cons1807, cons119) rule5435 = ReplacementRule(pattern5435, replacement5435) pattern5436 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1806, cons149) rule5436 = ReplacementRule(pattern5436, replacement5436) pattern5437 = Pattern(Integral(exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1)))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1808, cons1809) rule5437 = ReplacementRule(pattern5437, replacement5437) pattern5438 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons1808, cons13, cons139, cons1809, cons1810, cons248) rule5438 = ReplacementRule(pattern5438, replacement5438) pattern5439 = Pattern(Integral(exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1)))/(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons8, cons29, cons4, cons1808) rule5439 = ReplacementRule(pattern5439, replacement5439) pattern5440 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1808, cons40, cons1811, cons1812) rule5440 = ReplacementRule(pattern5440, replacement5440) pattern5441 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1808, cons1804) rule5441 = ReplacementRule(pattern5441, replacement5441) pattern5442 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1808, cons1805, cons1813) rule5442 = ReplacementRule(pattern5442, replacement5442) pattern5443 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1808, cons1805, cons1814) rule5443 = ReplacementRule(pattern5443, replacement5443) pattern5444 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1808, cons1805) rule5444 = ReplacementRule(pattern5444, replacement5444) pattern5445 = Pattern(Integral(x_*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1)))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1808, cons1809) rule5445 = ReplacementRule(pattern5445, replacement5445) pattern5446 = Pattern(Integral(x_*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons1808, cons13, cons139, cons1809, cons248) rule5446 = ReplacementRule(pattern5446, replacement5446) pattern5447 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons1808, cons1815, cons1809) rule5447 = ReplacementRule(pattern5447, replacement5447) pattern5448 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons1808, cons13, cons139, cons1809, cons1810, cons248) rule5448 = ReplacementRule(pattern5448, replacement5448) pattern5449 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons5, cons1808, cons1804, cons1811, cons1812) rule5449 = ReplacementRule(pattern5449, replacement5449) pattern5450 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1808, cons1804) rule5450 = ReplacementRule(pattern5450, replacement5450) pattern5451 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons5, cons1808, cons1805, cons1813) rule5451 = ReplacementRule(pattern5451, replacement5451) pattern5452 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons5, cons1808, cons1805, cons1814) rule5452 = ReplacementRule(pattern5452, replacement5452) pattern5453 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1808, cons1805) rule5453 = ReplacementRule(pattern5453, replacement5453) pattern5454 = Pattern(Integral(u_*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1808, cons1804) rule5454 = ReplacementRule(pattern5454, replacement5454) pattern5455 = Pattern(Integral(u_*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1808, cons1804, cons1807) rule5455 = ReplacementRule(pattern5455, replacement5455) pattern5456 = Pattern(Integral(u_*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1808, cons1805, cons1816) rule5456 = ReplacementRule(pattern5456, replacement5456) pattern5457 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*WC('u', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons1817, cons40) rule5457 = ReplacementRule(pattern5457, replacement5457) pattern5458 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons5, cons1817, cons149, cons1807, cons179) rule5458 = ReplacementRule(pattern5458, replacement5458) pattern5459 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(n_*ArcTan(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1817, cons149, cons1807, cons119) rule5459 = ReplacementRule(pattern5459, replacement5459) pattern5460 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(ArcTan(x_*WC('a', S(1)))*WC('n', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1817, cons149, cons1816) rule5460 = ReplacementRule(pattern5460, replacement5460) pattern5461 = Pattern(Integral(exp(ArcTan((a_ + x_*WC('b', S(1)))*WC('c', S(1)))*WC('n', S(1))), x_), cons2, cons3, cons8, cons4, cons1581) rule5461 = ReplacementRule(pattern5461, replacement5461) pattern5462 = Pattern(Integral(x_**m_*exp(n_*ArcTan((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons86, cons1818, cons1819) rule5462 = ReplacementRule(pattern5462, replacement5462) pattern5463 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*exp(ArcTan((a_ + x_*WC('b', S(1)))*WC('c', S(1)))*WC('n', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule5463 = ReplacementRule(pattern5463, replacement5463) pattern5464 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(ArcTan(a_ + x_*WC('b', S(1)))*WC('n', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1820, cons1821, cons1822) rule5464 = ReplacementRule(pattern5464, replacement5464) pattern5465 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(ArcTan(a_ + x_*WC('b', S(1)))*WC('n', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1820, cons1821, cons1823) rule5465 = ReplacementRule(pattern5465, replacement5465) pattern5466 = Pattern(Integral(WC('u', S(1))*exp(ArcTan(WC('c', S(1))/(x_*WC('b', S(1)) + WC('a', S(0))))*WC('n', S(1))), x_), cons2, cons3, cons8, cons4, cons1581) rule5466 = ReplacementRule(pattern5466, replacement5466) pattern5467 = Pattern(Integral(WC('u', S(1))*exp(n_*acot(x_*WC('a', S(1)))), x_), cons2, cons1807) rule5467 = ReplacementRule(pattern5467, replacement5467) pattern5468 = Pattern(Integral(exp(n_*acot(x_*WC('a', S(1)))), x_), cons2, cons1801) rule5468 = ReplacementRule(pattern5468, replacement5468) pattern5469 = Pattern(Integral(x_**WC('m', S(1))*exp(n_*acot(x_*WC('a', S(1)))), x_), cons2, cons1801, cons20) rule5469 = ReplacementRule(pattern5469, replacement5469) pattern5470 = Pattern(Integral(exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons4, cons1809) rule5470 = ReplacementRule(pattern5470, replacement5470) pattern5471 = Pattern(Integral(x_**WC('m', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons4, cons1809, cons20) rule5471 = ReplacementRule(pattern5471, replacement5471) pattern5472 = Pattern(Integral(x_**m_*exp(n_*acot(x_*WC('a', S(1)))), x_), cons2, cons19, cons1801, cons21) rule5472 = ReplacementRule(pattern5472, replacement5472) pattern5473 = Pattern(Integral(x_**m_*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons19, cons4, cons1816, cons21) rule5473 = ReplacementRule(pattern5473, replacement5473) pattern5474 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1803, cons1816, cons40) rule5474 = ReplacementRule(pattern5474, replacement5474) pattern5475 = Pattern(Integral((c_ + x_*WC('d', S(1)))**p_*WC('u', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1803, cons1816, cons149) rule5475 = ReplacementRule(pattern5475, replacement5475) pattern5476 = Pattern(Integral((c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1806, cons1816, cons1804) rule5476 = ReplacementRule(pattern5476, replacement5476) pattern5477 = Pattern(Integral(x_**WC('m', S(1))*(c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1806, cons1816, cons1804, cons20) rule5477 = ReplacementRule(pattern5477, replacement5477) pattern5478 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1806, cons1816, cons1805) rule5478 = ReplacementRule(pattern5478, replacement5478) pattern5479 = Pattern(Integral(x_**m_*(c_ + WC('d', S(1))/x_)**WC('p', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1806, cons1816, cons1804, cons21) rule5479 = ReplacementRule(pattern5479, replacement5479) pattern5480 = Pattern(Integral((c_ + WC('d', S(1))/x_)**p_*WC('u', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1806, cons1816, cons1805) rule5480 = ReplacementRule(pattern5480, replacement5480) pattern5481 = Pattern(Integral(exp(WC('n', S(1))*acot(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1))), x_), cons2, cons8, cons29, cons4, cons1808) rule5481 = ReplacementRule(pattern5481, replacement5481) pattern5482 = Pattern(Integral(exp(WC('n', S(1))*acot(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1808, cons1802) rule5482 = ReplacementRule(pattern5482, replacement5482) pattern5483 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1808, cons13, cons139, cons232, cons1810, cons1824, cons1825) rule5483 = ReplacementRule(pattern5483, replacement5483) pattern5484 = Pattern(Integral(x_*exp(WC('n', S(1))*acot(x_*WC('a', S(1))))/(c_ + x_**S(2)*WC('d', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons4, cons1808, cons1802) rule5484 = ReplacementRule(pattern5484, replacement5484) pattern5485 = Pattern(Integral(x_*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1808, cons13, cons1826, cons232, cons1810, cons1824, cons1825) rule5485 = ReplacementRule(pattern5485, replacement5485) pattern5486 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1808, cons1815, cons1827) rule5486 = ReplacementRule(pattern5486, replacement5486) pattern5487 = Pattern(Integral(x_**S(2)*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1808, cons13, cons1826, cons1828, cons1810, cons1824, cons1825) rule5487 = ReplacementRule(pattern5487, replacement5487) pattern5488 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**S(2)*WC('d', S(1)))**p_*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1808, cons20, cons1829, cons40) rule5488 = ReplacementRule(pattern5488, replacement5488) pattern5489 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons1808, cons1816, cons40) rule5489 = ReplacementRule(pattern5489, replacement5489) pattern5490 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))**p_*WC('u', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1808, cons1816, cons149) rule5490 = ReplacementRule(pattern5490, replacement5490) pattern5491 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1817, cons1816, cons1804, cons1830) rule5491 = ReplacementRule(pattern5491, replacement5491) pattern5492 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1817, cons1816, cons1804, cons1831) rule5492 = ReplacementRule(pattern5492, replacement5492) pattern5493 = Pattern(Integral(x_**WC('m', S(1))*(c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1817, cons1816, cons1804, cons1831, cons20) rule5493 = ReplacementRule(pattern5493, replacement5493) pattern5494 = Pattern(Integral(x_**m_*(c_ + WC('d', S(1))/x_**S(2))**WC('p', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons1817, cons1816, cons1804, cons1831, cons21) rule5494 = ReplacementRule(pattern5494, replacement5494) pattern5495 = Pattern(Integral((c_ + WC('d', S(1))/x_**S(2))**p_*WC('u', S(1))*exp(WC('n', S(1))*acot(x_*WC('a', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1817, cons1816, cons1805) rule5495 = ReplacementRule(pattern5495, replacement5495) pattern5496 = Pattern(Integral(WC('u', S(1))*exp(n_*acot((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons1807) rule5496 = ReplacementRule(pattern5496, replacement5496) pattern5497 = Pattern(Integral(exp(WC('n', S(1))*acot((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1816) rule5497 = ReplacementRule(pattern5497, replacement5497) pattern5498 = Pattern(Integral(x_**m_*exp(n_*acoth((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons86, cons1818, cons1819) rule5498 = ReplacementRule(pattern5498, replacement5498) pattern5499 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*exp(WC('n', S(1))*acoth((a_ + x_*WC('b', S(1)))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1816) rule5499 = ReplacementRule(pattern5499, replacement5499) pattern5500 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acot(a_ + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1816, cons1820, cons1821, cons1822) rule5500 = ReplacementRule(pattern5500, replacement5500) pattern5501 = Pattern(Integral((c_ + x_**S(2)*WC('e', S(1)) + x_*WC('d', S(1)))**WC('p', S(1))*WC('u', S(1))*exp(WC('n', S(1))*acot(a_ + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1816, cons1820, cons1821, cons1823) rule5501 = ReplacementRule(pattern5501, replacement5501) pattern5502 = Pattern(Integral(WC('u', S(1))*exp(WC('n', S(1))*acot(WC('c', S(1))/(x_*WC('b', S(1)) + WC('a', S(0))))), x_), cons2, cons3, cons8, cons4, cons1581) rule5502 = ReplacementRule(pattern5502, replacement5502) pattern5503 = Pattern(Integral((ArcTan(c_ + x_*WC('d', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150) rule5503 = ReplacementRule(pattern5503, replacement5503) pattern5504 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150) rule5504 = ReplacementRule(pattern5504, replacement5504) pattern5505 = Pattern(Integral((ArcTan(c_ + x_*WC('d', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons342) rule5505 = ReplacementRule(pattern5505, replacement5505) pattern5506 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(c_ + x_*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons342) rule5506 = ReplacementRule(pattern5506, replacement5506) pattern5507 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(ArcTan(c_ + x_*WC('d', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons150) rule5507 = ReplacementRule(pattern5507, replacement5507) pattern5508 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(c_ + x_*WC('d', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons150) rule5508 = ReplacementRule(pattern5508, replacement5508) pattern5509 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**m_*(ArcTan(c_ + x_*WC('d', S(1)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons342) rule5509 = ReplacementRule(pattern5509, replacement5509) pattern5510 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**m_*(WC('a', S(0)) + WC('b', S(1))*acot(c_ + x_*WC('d', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons342) rule5510 = ReplacementRule(pattern5510, replacement5510) pattern5511 = Pattern(Integral((ArcTan(c_ + x_*WC('d', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1832, cons1765) rule5511 = ReplacementRule(pattern5511, replacement5511) pattern5512 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acot(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons38, cons4, cons5, cons1832, cons1765) rule5512 = ReplacementRule(pattern5512, replacement5512) pattern5513 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(ArcTan(c_ + x_*WC('d', S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1832, cons1765) rule5513 = ReplacementRule(pattern5513, replacement5513) pattern5514 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(c_ + x_*WC('d', S(1))))**WC('n', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons1832, cons1765) rule5514 = ReplacementRule(pattern5514, replacement5514) pattern5515 = Pattern(Integral(ArcTan(a_ + x_*WC('b', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons89) rule5515 = ReplacementRule(pattern5515, replacement5515) pattern5516 = Pattern(Integral(acot(a_ + x_*WC('b', S(1)))/(c_ + x_**WC('n', S(1))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons89) rule5516 = ReplacementRule(pattern5516, replacement5516) pattern5517 = Pattern(Integral(ArcTan(a_ + x_*WC('b', S(1)))/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons1096) rule5517 = ReplacementRule(pattern5517, replacement5517) pattern5518 = Pattern(Integral(acot(a_ + x_*WC('b', S(1)))/(c_ + x_**n_*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons1096) rule5518 = ReplacementRule(pattern5518, replacement5518) pattern5519 = Pattern(Integral(ArcTan(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons4, cons1833) rule5519 = ReplacementRule(pattern5519, replacement5519) pattern5520 = Pattern(Integral(acot(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons4, cons1833) rule5520 = ReplacementRule(pattern5520, replacement5520) pattern5521 = Pattern(Integral(ArcTan(x_**n_*WC('b', S(1)) + WC('a', S(0)))/x_, x_), cons2, cons3, cons4, cons1833) rule5521 = ReplacementRule(pattern5521, replacement5521) pattern5522 = Pattern(Integral(acot(x_**n_*WC('b', S(1)) + WC('a', S(0)))/x_, x_), cons2, cons3, cons4, cons1833) rule5522 = ReplacementRule(pattern5522, replacement5522) pattern5523 = Pattern(Integral(x_**WC('m', S(1))*ArcTan(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons95, cons1834, cons1835) rule5523 = ReplacementRule(pattern5523, replacement5523) pattern5524 = Pattern(Integral(x_**WC('m', S(1))*acot(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons95, cons1834, cons1835) rule5524 = ReplacementRule(pattern5524, replacement5524) pattern5525 = Pattern(Integral(ArcTan(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons1836) rule5525 = ReplacementRule(pattern5525, replacement5525) pattern5526 = Pattern(Integral(acot(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons1836) rule5526 = ReplacementRule(pattern5526, replacement5526) pattern5527 = Pattern(Integral(x_**WC('m', S(1))*ArcTan(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons20, cons170) rule5527 = ReplacementRule(pattern5527, replacement5527) pattern5528 = Pattern(Integral(x_**WC('m', S(1))*acot(f_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons20, cons170) rule5528 = ReplacementRule(pattern5528, replacement5528) pattern5529 = Pattern(Integral(ArcTan(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule5529 = ReplacementRule(pattern5529, replacement5529) pattern5530 = Pattern(Integral(WC('u', S(1))*acot(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule5530 = ReplacementRule(pattern5530, replacement5530) pattern5531 = Pattern(Integral(S(1)/(sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0)))*ArcTan(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))), x_), cons2, cons3, cons8, cons1837) rule5531 = ReplacementRule(pattern5531, replacement5531) pattern5532 = Pattern(Integral(S(1)/(sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0)))*acot(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))), x_), cons2, cons3, cons8, cons1837) rule5532 = ReplacementRule(pattern5532, replacement5532) pattern5533 = Pattern(Integral(ArcTan(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons19, cons1837, cons68) rule5533 = ReplacementRule(pattern5533, replacement5533) pattern5534 = Pattern(Integral(acot(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons19, cons1837, cons68) rule5534 = ReplacementRule(pattern5534, replacement5534) pattern5535 = Pattern(Integral(ArcTan(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1837, cons385) rule5535 = ReplacementRule(pattern5535, replacement5535) pattern5536 = Pattern(Integral(acot(x_*WC('c', S(1))/sqrt(x_**S(2)*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))/sqrt(x_**S(2)*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1837, cons385) rule5536 = ReplacementRule(pattern5536, replacement5536) pattern5537 = Pattern(Integral(ArcTan(v_ + sqrt(w_)*WC('s', S(1)))*WC('u', S(1)), x_), cons1838, cons1839) rule5537 = ReplacementRule(pattern5537, replacement5537) pattern5538 = Pattern(Integral(WC('u', S(1))*acot(v_ + sqrt(w_)*WC('s', S(1))), x_), cons1838, cons1839) rule5538 = ReplacementRule(pattern5538, replacement5538) pattern5539 = Pattern(Integral(u_*v_**WC('n', S(1)), x_), cons820, cons87, cons465, cons1840, cons1841, CustomConstraint(With5539)) rule5539 = ReplacementRule(pattern5539, replacement5539) pattern5540 = Pattern(Integral(u_*v_**WC('n', S(1)), x_), cons820, cons87, cons465, cons1840, cons1842, CustomConstraint(With5540)) rule5540 = ReplacementRule(pattern5540, replacement5540) pattern5541 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1843) rule5541 = ReplacementRule(pattern5541, replacement5541) pattern5542 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1843) rule5542 = ReplacementRule(pattern5542, replacement5542) pattern5543 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1844) rule5543 = ReplacementRule(pattern5543, replacement5543) pattern5544 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1844) rule5544 = ReplacementRule(pattern5544, replacement5544) pattern5545 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1845) rule5545 = ReplacementRule(pattern5545, replacement5545) pattern5546 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1845) rule5546 = ReplacementRule(pattern5546, replacement5546) pattern5547 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1845) rule5547 = ReplacementRule(pattern5547, replacement5547) pattern5548 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1846) rule5548 = ReplacementRule(pattern5548, replacement5548) pattern5549 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1843) rule5549 = ReplacementRule(pattern5549, replacement5549) pattern5550 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1843) rule5550 = ReplacementRule(pattern5550, replacement5550) pattern5551 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1844) rule5551 = ReplacementRule(pattern5551, replacement5551) pattern5552 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1844) rule5552 = ReplacementRule(pattern5552, replacement5552) pattern5553 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1845) rule5553 = ReplacementRule(pattern5553, replacement5553) pattern5554 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1845) rule5554 = ReplacementRule(pattern5554, replacement5554) pattern5555 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1846) rule5555 = ReplacementRule(pattern5555, replacement5555) pattern5556 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1846) rule5556 = ReplacementRule(pattern5556, replacement5556) pattern5557 = Pattern(Integral(ArcTan(tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule5557 = ReplacementRule(pattern5557, replacement5557) pattern5558 = Pattern(Integral(acot(tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule5558 = ReplacementRule(pattern5558, replacement5558) pattern5559 = Pattern(Integral(ArcTan(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule5559 = ReplacementRule(pattern5559, replacement5559) pattern5560 = Pattern(Integral(acot(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons69) rule5560 = ReplacementRule(pattern5560, replacement5560) pattern5561 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule5561 = ReplacementRule(pattern5561, replacement5561) pattern5562 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule5562 = ReplacementRule(pattern5562, replacement5562) pattern5563 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule5563 = ReplacementRule(pattern5563, replacement5563) pattern5564 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(S(1)/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons50, cons127, cons64) rule5564 = ReplacementRule(pattern5564, replacement5564) pattern5565 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1847) rule5565 = ReplacementRule(pattern5565, replacement5565) pattern5566 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1847) rule5566 = ReplacementRule(pattern5566, replacement5566) pattern5567 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1847) rule5567 = ReplacementRule(pattern5567, replacement5567) pattern5568 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1847) rule5568 = ReplacementRule(pattern5568, replacement5568) pattern5569 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1848) rule5569 = ReplacementRule(pattern5569, replacement5569) pattern5570 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1848) rule5570 = ReplacementRule(pattern5570, replacement5570) pattern5571 = Pattern(Integral(ArcTan(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1848) rule5571 = ReplacementRule(pattern5571, replacement5571) pattern5572 = Pattern(Integral(acot(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1848) rule5572 = ReplacementRule(pattern5572, replacement5572) pattern5573 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1847) rule5573 = ReplacementRule(pattern5573, replacement5573) pattern5574 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1847) rule5574 = ReplacementRule(pattern5574, replacement5574) pattern5575 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1847) rule5575 = ReplacementRule(pattern5575, replacement5575) pattern5576 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1847) rule5576 = ReplacementRule(pattern5576, replacement5576) pattern5577 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1848) rule5577 = ReplacementRule(pattern5577, replacement5577) pattern5578 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))*tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1848) rule5578 = ReplacementRule(pattern5578, replacement5578) pattern5579 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*ArcTan(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1848) rule5579 = ReplacementRule(pattern5579, replacement5579) pattern5580 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*acot(WC('c', S(0)) + WC('d', S(1))/tanh(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1848) rule5580 = ReplacementRule(pattern5580, replacement5580) pattern5581 = Pattern(Integral(ArcTan(u_), x_), cons1232) rule5581 = ReplacementRule(pattern5581, replacement5581) pattern5582 = Pattern(Integral(acot(u_), x_), cons1232) rule5582 = ReplacementRule(pattern5582, replacement5582) pattern5583 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(ArcTan(u_)*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1849) rule5583 = ReplacementRule(pattern5583, replacement5583) pattern5584 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acot(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1849) rule5584 = ReplacementRule(pattern5584, replacement5584) pattern5585 = Pattern(Integral(v_*(ArcTan(u_)*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons1232, cons1850, cons1851, CustomConstraint(With5585)) rule5585 = ReplacementRule(pattern5585, replacement5585) pattern5586 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*acot(u_)), x_), cons2, cons3, cons1232, cons1852, cons1853, CustomConstraint(With5586)) rule5586 = ReplacementRule(pattern5586, replacement5586) pattern5587 = Pattern(Integral(ArcTan(v_)*log(w_)/(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons554, cons1148, cons1854, cons1855) rule5587 = ReplacementRule(pattern5587, replacement5587) pattern5588 = Pattern(Integral(ArcTan(v_)*log(w_), x_), cons1244, cons1245) rule5588 = ReplacementRule(pattern5588, replacement5588) pattern5589 = Pattern(Integral(log(w_)*acot(v_), x_), cons1244, cons1245) rule5589 = ReplacementRule(pattern5589, replacement5589) pattern5590 = Pattern(Integral(u_*ArcTan(v_)*log(w_), x_), cons1244, cons1245, CustomConstraint(With5590)) rule5590 = ReplacementRule(pattern5590, replacement5590) pattern5591 = Pattern(Integral(u_*log(w_)*acot(v_), x_), cons1244, cons1245, CustomConstraint(With5591)) rule5591 = ReplacementRule(pattern5591, replacement5591) pattern5592 = Pattern(Integral(asec(x_*WC('c', S(1))), x_), cons8, cons8) rule5592 = ReplacementRule(pattern5592, replacement5592) pattern5593 = Pattern(Integral(acsc(x_*WC('c', S(1))), x_), cons8, cons8) rule5593 = ReplacementRule(pattern5593, replacement5593) pattern5594 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule5594 = ReplacementRule(pattern5594, replacement5594) pattern5595 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons1581) rule5595 = ReplacementRule(pattern5595, replacement5595) pattern5596 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons14) rule5596 = ReplacementRule(pattern5596, replacement5596) pattern5597 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))/x_, x_), cons2, cons3, cons8, cons14) rule5597 = ReplacementRule(pattern5597, replacement5597) pattern5598 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons68) rule5598 = ReplacementRule(pattern5598, replacement5598) pattern5599 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons68) rule5599 = ReplacementRule(pattern5599, replacement5599) pattern5600 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons20) rule5600 = ReplacementRule(pattern5600, replacement5600) pattern5601 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons4, cons20) rule5601 = ReplacementRule(pattern5601, replacement5601) pattern5602 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons1856) rule5602 = ReplacementRule(pattern5602, replacement5602) pattern5603 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons1856) rule5603 = ReplacementRule(pattern5603, replacement5603) pattern5604 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1745) rule5604 = ReplacementRule(pattern5604, With5604) pattern5605 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1745) rule5605 = ReplacementRule(pattern5605, With5605) pattern5606 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons40) rule5606 = ReplacementRule(pattern5606, replacement5606) pattern5607 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons40) rule5607 = ReplacementRule(pattern5607, replacement5607) pattern5608 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons669, cons180, cons1857) rule5608 = ReplacementRule(pattern5608, replacement5608) pattern5609 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons669, cons180, cons1857) rule5609 = ReplacementRule(pattern5609, replacement5609) pattern5610 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons669, cons1858) rule5610 = ReplacementRule(pattern5610, replacement5610) pattern5611 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons669, cons1858) rule5611 = ReplacementRule(pattern5611, replacement5611) pattern5612 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5612 = ReplacementRule(pattern5612, replacement5612) pattern5613 = Pattern(Integral((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule5613 = ReplacementRule(pattern5613, replacement5613) pattern5614 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule5614 = ReplacementRule(pattern5614, replacement5614) pattern5615 = Pattern(Integral(x_*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons56) rule5615 = ReplacementRule(pattern5615, replacement5615) pattern5616 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule5616 = ReplacementRule(pattern5616, With5616) pattern5617 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1788) rule5617 = ReplacementRule(pattern5617, With5617) pattern5618 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1301) rule5618 = ReplacementRule(pattern5618, replacement5618) pattern5619 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1301) rule5619 = ReplacementRule(pattern5619, replacement5619) pattern5620 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons20, cons669, cons180, cons1857) rule5620 = ReplacementRule(pattern5620, replacement5620) pattern5621 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons20, cons669, cons180, cons1857) rule5621 = ReplacementRule(pattern5621, replacement5621) pattern5622 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons20, cons669, cons1858) rule5622 = ReplacementRule(pattern5622, replacement5622) pattern5623 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**p_*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1739, cons20, cons669, cons1858) rule5623 = ReplacementRule(pattern5623, replacement5623) pattern5624 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5624 = ReplacementRule(pattern5624, replacement5624) pattern5625 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(x_*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule5625 = ReplacementRule(pattern5625, replacement5625) pattern5626 = Pattern(Integral(asec(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons69) rule5626 = ReplacementRule(pattern5626, replacement5626) pattern5627 = Pattern(Integral(acsc(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons69) rule5627 = ReplacementRule(pattern5627, replacement5627) pattern5628 = Pattern(Integral(asec(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons1833) rule5628 = ReplacementRule(pattern5628, replacement5628) pattern5629 = Pattern(Integral(acsc(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons1833) rule5629 = ReplacementRule(pattern5629, replacement5629) pattern5630 = Pattern(Integral(asec(a_ + x_*WC('b', S(1)))/x_, x_), cons2, cons3, cons69) rule5630 = ReplacementRule(pattern5630, replacement5630) pattern5631 = Pattern(Integral(acsc(a_ + x_*WC('b', S(1)))/x_, x_), cons2, cons3, cons69) rule5631 = ReplacementRule(pattern5631, replacement5631) pattern5632 = Pattern(Integral(x_**WC('m', S(1))*asec(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons19, cons20, cons68) rule5632 = ReplacementRule(pattern5632, replacement5632) pattern5633 = Pattern(Integral(x_**WC('m', S(1))*acsc(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons19, cons20, cons68) rule5633 = ReplacementRule(pattern5633, replacement5633) pattern5634 = Pattern(Integral(x_**WC('m', S(1))*asec(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons64) rule5634 = ReplacementRule(pattern5634, replacement5634) pattern5635 = Pattern(Integral(x_**WC('m', S(1))*acsc(a_ + x_*WC('b', S(1)))**n_, x_), cons2, cons3, cons4, cons64) rule5635 = ReplacementRule(pattern5635, replacement5635) pattern5636 = Pattern(Integral(WC('u', S(1))*asec(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule5636 = ReplacementRule(pattern5636, replacement5636) pattern5637 = Pattern(Integral(WC('u', S(1))*acsc(WC('c', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons4, cons19, cons1768) rule5637 = ReplacementRule(pattern5637, replacement5637) pattern5638 = Pattern(Integral(f_**(WC('c', S(1))*asec(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)))*WC('u', S(1)), x_), cons2, cons3, cons8, cons127, cons150) rule5638 = ReplacementRule(pattern5638, replacement5638) pattern5639 = Pattern(Integral(f_**(WC('c', S(1))*acsc(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)))*WC('u', S(1)), x_), cons2, cons3, cons8, cons127, cons150) rule5639 = ReplacementRule(pattern5639, replacement5639) pattern5640 = Pattern(Integral(asec(u_), x_), cons1232, cons1771) rule5640 = ReplacementRule(pattern5640, replacement5640) pattern5641 = Pattern(Integral(acsc(u_), x_), cons1232, cons1771) rule5641 = ReplacementRule(pattern5641, replacement5641) pattern5642 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*asec(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule5642 = ReplacementRule(pattern5642, replacement5642) pattern5643 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*acsc(u_)), x_), cons2, cons3, cons8, cons29, cons19, cons68, cons1232, cons1772, cons1771) rule5643 = ReplacementRule(pattern5643, replacement5643) pattern5644 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*asec(u_)), x_), cons2, cons3, cons1232, cons1859, CustomConstraint(With5644)) rule5644 = ReplacementRule(pattern5644, replacement5644) pattern5645 = Pattern(Integral(v_*(WC('a', S(0)) + WC('b', S(1))*acsc(u_)), x_), cons2, cons3, cons1232, cons1860, CustomConstraint(With5645)) rule5645 = ReplacementRule(pattern5645, replacement5645) return [rule5034, rule5035, rule5036, rule5037, rule5038, rule5039, rule5040, rule5041, rule5042, rule5043, rule5044, rule5045, rule5046, rule5047, rule5048, rule5049, rule5050, rule5051, rule5052, rule5053, rule5054, rule5055, rule5056, rule5057, rule5058, rule5059, rule5060, rule5061, rule5062, rule5063, rule5064, rule5065, rule5066, rule5067, rule5068, rule5069, rule5070, rule5071, rule5072, rule5073, rule5074, rule5075, rule5076, rule5077, rule5078, rule5079, rule5080, rule5081, rule5082, rule5083, rule5084, rule5085, rule5086, rule5087, rule5088, rule5089, rule5090, rule5091, rule5092, rule5093, rule5094, rule5095, rule5096, rule5097, rule5098, rule5099, rule5100, rule5101, rule5102, rule5103, rule5104, rule5105, rule5106, rule5107, rule5108, rule5109, rule5110, rule5111, rule5112, rule5113, rule5114, rule5115, rule5116, rule5117, rule5118, rule5119, rule5120, rule5121, rule5122, rule5123, rule5124, rule5125, rule5126, rule5127, rule5128, rule5129, rule5130, rule5131, rule5132, rule5133, rule5134, rule5135, rule5136, rule5137, rule5138, rule5139, rule5140, rule5141, rule5142, rule5143, rule5144, rule5145, rule5146, rule5147, rule5148, rule5149, rule5150, rule5151, rule5152, rule5153, rule5154, rule5155, rule5156, rule5157, rule5158, rule5159, rule5160, rule5161, rule5162, rule5163, rule5164, rule5165, rule5166, rule5167, rule5168, rule5169, rule5170, rule5171, rule5172, rule5173, rule5174, rule5175, rule5176, rule5177, rule5178, rule5179, rule5180, rule5181, rule5182, rule5183, rule5184, rule5185, rule5186, rule5187, rule5188, rule5189, rule5190, rule5191, rule5192, rule5193, rule5194, rule5195, rule5196, rule5197, rule5198, rule5199, rule5200, rule5201, rule5202, rule5203, rule5204, rule5205, rule5206, rule5207, rule5208, rule5209, rule5210, rule5211, rule5212, rule5213, rule5214, rule5215, rule5216, rule5217, rule5218, rule5219, rule5220, rule5221, rule5222, rule5223, rule5224, rule5225, rule5226, rule5227, rule5228, rule5229, rule5230, rule5231, rule5232, rule5233, rule5234, rule5235, rule5236, rule5237, rule5238, rule5239, rule5240, rule5241, rule5242, rule5243, rule5244, rule5245, rule5246, rule5247, rule5248, rule5249, rule5250, rule5251, rule5252, rule5253, rule5254, rule5255, rule5256, rule5257, rule5258, rule5259, rule5260, rule5261, rule5262, rule5263, rule5264, rule5265, rule5266, rule5267, rule5268, rule5269, rule5270, rule5271, rule5272, rule5273, rule5274, rule5275, rule5276, rule5277, rule5278, rule5279, rule5280, rule5281, rule5282, rule5283, rule5284, rule5285, rule5286, rule5287, rule5288, rule5289, rule5290, rule5291, rule5292, rule5293, rule5294, rule5295, rule5296, rule5297, rule5298, rule5299, rule5300, rule5301, rule5302, rule5303, rule5304, rule5305, rule5306, rule5307, rule5308, rule5309, rule5310, rule5311, rule5312, rule5313, rule5314, rule5315, rule5316, rule5317, rule5318, rule5319, rule5320, rule5321, rule5322, rule5323, rule5324, rule5325, rule5326, rule5327, rule5328, rule5329, rule5330, rule5331, rule5332, rule5333, rule5334, rule5335, rule5336, rule5337, rule5338, rule5339, rule5340, rule5341, rule5342, rule5343, rule5344, rule5345, rule5346, rule5347, rule5348, rule5349, rule5350, rule5351, rule5352, rule5353, rule5354, rule5355, rule5356, rule5357, rule5358, rule5359, rule5360, rule5361, rule5362, rule5363, rule5364, rule5365, rule5366, rule5367, rule5368, rule5369, rule5370, rule5371, rule5372, rule5373, rule5374, rule5375, rule5376, rule5377, rule5378, rule5379, rule5380, rule5381, rule5382, rule5383, rule5384, rule5385, rule5386, rule5387, rule5388, rule5389, rule5390, rule5391, rule5392, rule5393, rule5394, rule5395, rule5396, rule5397, rule5398, rule5399, rule5400, rule5401, rule5402, rule5403, rule5404, rule5405, rule5406, rule5407, rule5408, rule5409, rule5410, rule5411, rule5412, rule5413, rule5414, rule5415, rule5416, rule5417, rule5418, rule5419, rule5420, rule5421, rule5422, rule5423, rule5424, rule5425, rule5426, rule5427, rule5428, rule5429, rule5430, rule5431, rule5432, rule5433, rule5434, rule5435, rule5436, rule5437, rule5438, rule5439, rule5440, rule5441, rule5442, rule5443, rule5444, rule5445, rule5446, rule5447, rule5448, rule5449, rule5450, rule5451, rule5452, rule5453, rule5454, rule5455, rule5456, rule5457, rule5458, rule5459, rule5460, rule5461, rule5462, rule5463, rule5464, rule5465, rule5466, rule5467, rule5468, rule5469, rule5470, rule5471, rule5472, rule5473, rule5474, rule5475, rule5476, rule5477, rule5478, rule5479, rule5480, rule5481, rule5482, rule5483, rule5484, rule5485, rule5486, rule5487, rule5488, rule5489, rule5490, rule5491, rule5492, rule5493, rule5494, rule5495, rule5496, rule5497, rule5498, rule5499, rule5500, rule5501, rule5502, rule5503, rule5504, rule5505, rule5506, rule5507, rule5508, rule5509, rule5510, rule5511, rule5512, rule5513, rule5514, rule5515, rule5516, rule5517, rule5518, rule5519, rule5520, rule5521, rule5522, rule5523, rule5524, rule5525, rule5526, rule5527, rule5528, rule5529, rule5530, rule5531, rule5532, rule5533, rule5534, rule5535, rule5536, rule5537, rule5538, rule5539, rule5540, rule5541, rule5542, rule5543, rule5544, rule5545, rule5546, rule5547, rule5548, rule5549, rule5550, rule5551, rule5552, rule5553, rule5554, rule5555, rule5556, rule5557, rule5558, rule5559, rule5560, rule5561, rule5562, rule5563, rule5564, rule5565, rule5566, rule5567, rule5568, rule5569, rule5570, rule5571, rule5572, rule5573, rule5574, rule5575, rule5576, rule5577, rule5578, rule5579, rule5580, rule5581, rule5582, rule5583, rule5584, rule5585, rule5586, rule5587, rule5588, rule5589, rule5590, rule5591, rule5592, rule5593, rule5594, rule5595, rule5596, rule5597, rule5598, rule5599, rule5600, rule5601, rule5602, rule5603, rule5604, rule5605, rule5606, rule5607, rule5608, rule5609, rule5610, rule5611, rule5612, rule5613, rule5614, rule5615, rule5616, rule5617, rule5618, rule5619, rule5620, rule5621, rule5622, rule5623, rule5624, rule5625, rule5626, rule5627, rule5628, rule5629, rule5630, rule5631, rule5632, rule5633, rule5634, rule5635, rule5636, rule5637, rule5638, rule5639, rule5640, rule5641, rule5642, rule5643, rule5644, rule5645, ] def replacement5034(a, b, c, n, x): return -Dist(b*c*n, Int(x*(a + b*asin(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*asin(c*x))**n, x) def replacement5035(a, b, c, n, x): return Dist(b*c*n, Int(x*(a + b*acos(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*acos(c*x))**n, x) def replacement5036(a, b, c, n, x): return Dist(c/(b*(n + S(1))), Int(x*(a + b*asin(c*x))**(n + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*asin(c*x))**(n + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5037(a, b, c, n, x): return -Dist(c/(b*(n + S(1))), Int(x*(a + b*acos(c*x))**(n + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) - Simp((a + b*acos(c*x))**(n + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5038(a, b, c, n, x): return Dist(S(1)/(b*c), Subst(Int(x**n*cos(a/b - x/b), x), x, a + b*asin(c*x)), x) def replacement5039(a, b, c, n, x): return Dist(S(1)/(b*c), Subst(Int(x**n*sin(a/b - x/b), x), x, a + b*acos(c*x)), x) def replacement5040(a, b, c, n, x): return Subst(Int((a + b*x)**n/tan(x), x), x, asin(c*x)) def replacement5041(a, b, c, n, x): return -Subst(Int((a + b*x)**n*tan(x), x), x, acos(c*x)) def replacement5042(a, b, c, d, m, n, x): return -Dist(b*c*n/(d*(m + S(1))), Int((d*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*asin(c*x))**n/(d*(m + S(1))), x) def replacement5043(a, b, c, d, m, n, x): return Dist(b*c*n/(d*(m + S(1))), Int((d*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*acos(c*x))**n/(d*(m + S(1))), x) def replacement5044(a, b, c, m, n, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*asin(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**(m + S(1))*(a + b*asin(c*x))**n/(m + S(1)), x) def replacement5045(a, b, c, m, n, x): return Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acos(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**(m + S(1))*(a + b*acos(c*x))**n/(m + S(1)), x) def replacement5046(a, b, c, m, n, x): return -Dist(c**(-m + S(-1))/(b*(n + S(1))), Subst(Int(ExpandTrigReduce((a + b*x)**(n + S(1)), (m - (m + S(1))*sin(x)**S(2))*sin(x)**(m + S(-1)), x), x), x, asin(c*x)), x) + Simp(x**m*(a + b*asin(c*x))**(n + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5047(a, b, c, m, n, x): return -Dist(c**(-m + S(-1))/(b*(n + S(1))), Subst(Int(ExpandTrigReduce((a + b*x)**(n + S(1)), (m - (m + S(1))*cos(x)**S(2))*cos(x)**(m + S(-1)), x), x), x, acos(c*x)), x) - Simp(x**m*(a + b*acos(c*x))**(n + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5048(a, b, c, m, n, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*asin(c*x))**(n + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Dist(c*(m + S(1))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*asin(c*x))**(n + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**m*(a + b*asin(c*x))**(n + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5049(a, b, c, m, n, x): return Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*acos(c*x))**(n + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(c*(m + S(1))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*acos(c*x))**(n + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) - Simp(x**m*(a + b*acos(c*x))**(n + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5050(a, b, c, m, n, x): return Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*sin(x)**m*cos(x), x), x, asin(c*x)), x) def replacement5051(a, b, c, m, n, x): return -Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*sin(x)*cos(x)**m, x), x, acos(c*x)), x) def replacement5052(a, b, c, d, m, n, x): return Int((d*x)**m*(a + b*asin(c*x))**n, x) def replacement5053(a, b, c, d, m, n, x): return Int((d*x)**m*(a + b*acos(c*x))**n, x) def replacement5054(a, b, c, d, e, x): return Simp(log(a + b*asin(c*x))/(b*c*sqrt(d)), x) def replacement5055(a, b, c, d, e, x): return -Simp(log(a + b*acos(c*x))/(b*c*sqrt(d)), x) def replacement5056(a, b, c, d, e, n, x): return Simp((a + b*asin(c*x))**(n + S(1))/(b*c*sqrt(d)*(n + S(1))), x) def replacement5057(a, b, c, d, e, n, x): return -Simp((a + b*acos(c*x))**(n + S(1))/(b*c*sqrt(d)*(n + S(1))), x) def replacement5058(a, b, c, d, e, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*asin(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) def replacement5059(a, b, c, d, e, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*acos(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) def With5060(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), u, x) def With5061(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), u, x) def replacement5062(a, b, c, d, e, n, x): return Dist(sqrt(d + e*x**S(2))/(S(2)*sqrt(-c**S(2)*x**S(2) + S(1))), Int((a + b*asin(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(b*c*n*sqrt(d + e*x**S(2))/(S(2)*sqrt(-c**S(2)*x**S(2) + S(1))), Int(x*(a + b*asin(c*x))**(n + S(-1)), x), x) + Simp(x*(a + b*asin(c*x))**n*sqrt(d + e*x**S(2))/S(2), x) def replacement5063(a, b, c, d, e, n, x): return Dist(sqrt(d + e*x**S(2))/(S(2)*sqrt(-c**S(2)*x**S(2) + S(1))), Int((a + b*acos(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Dist(b*c*n*sqrt(d + e*x**S(2))/(S(2)*sqrt(-c**S(2)*x**S(2) + S(1))), Int(x*(a + b*acos(c*x))**(n + S(-1)), x), x) + Simp(x*(a + b*acos(c*x))**n*sqrt(d + e*x**S(2))/S(2), x) def replacement5064(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*p + S(1)), Int(x*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp(x*(a + b*asin(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) def replacement5065(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*p + S(1)), Int(x*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp(x*(a + b*acos(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) def replacement5066(a, b, c, d, e, n, x): return -Dist(b*c*n/sqrt(d), Int(x*(a + b*asin(c*x))**(n + S(-1))/(d + e*x**S(2)), x), x) + Simp(x*(a + b*asin(c*x))**n/(d*sqrt(d + e*x**S(2))), x) def replacement5067(a, b, c, d, e, n, x): return Dist(b*c*n/sqrt(d), Int(x*(a + b*acos(c*x))**(n + S(-1))/(d + e*x**S(2)), x), x) + Simp(x*(a + b*acos(c*x))**n/(d*sqrt(d + e*x**S(2))), x) def replacement5068(a, b, c, d, e, n, x): return -Dist(b*c*n*sqrt(-c**S(2)*x**S(2) + S(1))/(d*sqrt(d + e*x**S(2))), Int(x*(a + b*asin(c*x))**(n + S(-1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*asin(c*x))**n/(d*sqrt(d + e*x**S(2))), x) def replacement5069(a, b, c, d, e, n, x): return Dist(b*c*n*sqrt(-c**S(2)*x**S(2) + S(1))/(d*sqrt(d + e*x**S(2))), Int(x*(a + b*acos(c*x))**(n + S(-1))/(-c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*acos(c*x))**n/(d*sqrt(d + e*x**S(2))), x) def replacement5070(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*(p + S(1))), Int(x*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) - Simp(x*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement5071(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*(p + S(1))), Int(x*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) - Simp(x*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement5072(a, b, c, d, e, n, x): return Dist(S(1)/(c*d), Subst(Int((a + b*x)**n/cos(x), x), x, asin(c*x)), x) def replacement5073(a, b, c, d, e, n, x): return -Dist(S(1)/(c*d), Subst(Int((a + b*x)**n/sin(x), x), x, acos(c*x)), x) def replacement5074(a, b, c, d, e, n, p, x): return Dist(c*d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(S(2)*p + S(1))*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*(n + S(1))), Int(x*(a + b*asin(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((a + b*asin(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5075(a, b, c, d, e, n, p, x): return -Dist(c*d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(S(2)*p + S(1))*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*(n + S(1))), Int(x*(a + b*acos(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) - Simp((a + b*acos(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5076(a, b, c, d, e, n, p, x): return Dist(d**p/c, Subst(Int((a + b*x)**n*cos(x)**(S(2)*p + S(1)), x), x, asin(c*x)), x) def replacement5077(a, b, c, d, e, n, p, x): return -Dist(d**p/c, Subst(Int((a + b*x)**n*sin(x)**(S(2)*p + S(1)), x), x, acos(c*x)), x) def replacement5078(a, b, c, d, e, n, p, x): return Dist(d**(p + S(-1)/2)*sqrt(d + e*x**S(2))/sqrt(-c**S(2)*x**S(2) + S(1)), Int((a + b*asin(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p, x), x) def replacement5079(a, b, c, d, e, n, p, x): return Dist(d**(p + S(-1)/2)*sqrt(d + e*x**S(2))/sqrt(-c**S(2)*x**S(2) + S(1)), Int((a + b*acos(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p, x), x) def With5080(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), u, x) def With5081(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), u, x) def replacement5082(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n, (d + e*x**S(2))**p, x), x) def replacement5083(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n, (d + e*x**S(2))**p, x), x) def replacement5084(a, b, c, d, e, n, p, x): return Int((a + b*asin(c*x))**n*(d + e*x**S(2))**p, x) def replacement5085(a, b, c, d, e, n, p, x): return Int((a + b*acos(c*x))**n*(d + e*x**S(2))**p, x) def replacement5086(a, b, c, d, e, f, g, n, p, x): return Dist((d + e*x)**FracPart(p)*(f + g*x)**FracPart(p)*(d*f + e*g*x**S(2))**(-FracPart(p)), Int((a + b*asin(c*x))**n*(d*f + e*g*x**S(2))**p, x), x) def replacement5087(a, b, c, d, e, f, g, n, p, x): return Dist((d + e*x)**FracPart(p)*(f + g*x)**FracPart(p)*(d*f + e*g*x**S(2))**(-FracPart(p)), Int((a + b*acos(c*x))**n*(d*f + e*g*x**S(2))**p, x), x) def replacement5088(a, b, c, d, e, n, x): return -Dist(S(1)/e, Subst(Int((a + b*x)**n*tan(x), x), x, asin(c*x)), x) def replacement5089(a, b, c, d, e, n, x): return Dist(S(1)/e, Subst(Int((a + b*x)**n/tan(x), x), x, acos(c*x)), x) def replacement5090(a, b, c, d, e, n, p, x): return Dist(b*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5091(a, b, c, d, e, n, p, x): return -Dist(b*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5092(a, b, c, d, e, n, x): return Dist(S(1)/d, Subst(Int((a + b*x)**n/(sin(x)*cos(x)), x), x, asin(c*x)), x) def replacement5093(a, b, c, d, e, n, x): return -Dist(S(1)/d, Subst(Int((a + b*x)**n/(sin(x)*cos(x)), x), x, acos(c*x)), x) def replacement5094(a, b, c, d, e, f, m, n, p, x): return -Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement5095(a, b, c, d, e, f, m, n, p, x): return Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement5096(a, b, c, d, e, p, x): return Dist(d, Int((a + b*asin(c*x))*(d + e*x**S(2))**(p + S(-1))/x, x), x) - Dist(b*c*d**p/(S(2)*p), Int((-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((a + b*asin(c*x))*(d + e*x**S(2))**p/(S(2)*p), x) def replacement5097(a, b, c, d, e, p, x): return Dist(d, Int((a + b*acos(c*x))*(d + e*x**S(2))**(p + S(-1))/x, x), x) + Dist(b*c*d**p/(S(2)*p), Int((-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((a + b*acos(c*x))*(d + e*x**S(2))**p/(S(2)*p), x) def replacement5098(a, b, c, d, e, f, m, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*asin(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**p/(f*(m + S(1))), Int((f*x)**(m + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asin(c*x))*(d + e*x**S(2))**p/(f*(m + S(1))), x) def replacement5099(a, b, c, d, e, f, m, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acos(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(b*c*d**p/(f*(m + S(1))), Int((f*x)**(m + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acos(c*x))*(d + e*x**S(2))**p/(f*(m + S(1))), x) def With5100(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), u, x) def With5101(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), u, x) def With5102(a, b, c, d, e, m, p, x): u = IntHide(x**m*(-c**S(2)*x**S(2) + S(1))**p, x) return Dist(d**p*(a + b*asin(c*x)), u, x) - Dist(b*c*d**p, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) def With5103(a, b, c, d, e, m, p, x): u = IntHide(x**m*(-c**S(2)*x**S(2) + S(1))**p, x) return Dist(d**p*(a + b*acos(c*x)), u, x) + Dist(b*c*d**p, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) def With5104(a, b, c, d, e, m, p, x): u = IntHide(x**m*(-c**S(2)*x**S(2) + S(1))**p, x) return -Dist(b*c*d**(p + S(-1)/2)*sqrt(d + e*x**S(2))/sqrt(-c**S(2)*x**S(2) + S(1)), Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), Int(x**m*(d + e*x**S(2))**p, x), x) def With5105(a, b, c, d, e, m, p, x): u = IntHide(x**m*(-c**S(2)*x**S(2) + S(1))**p, x) return Dist(b*c*d**(p + S(-1)/2)*sqrt(d + e*x**S(2))/sqrt(-c**S(2)*x**S(2) + S(1)), Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), Int(x**m*(d + e*x**S(2))**p, x), x) def replacement5106(a, b, c, d, e, f, m, n, x): return Dist(c**S(2)*sqrt(d + e*x**S(2))/(f**S(2)*(m + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(2))*(a + b*asin(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(b*c*n*sqrt(d + e*x**S(2))/(f*(m + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*asin(c*x))**n*sqrt(d + e*x**S(2))/(f*(m + S(1))), x) def replacement5107(a, b, c, d, e, f, m, n, x): return Dist(c**S(2)*sqrt(d + e*x**S(2))/(f**S(2)*(m + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(2))*(a + b*acos(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Dist(b*c*n*sqrt(d + e*x**S(2))/(f*(m + S(1))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*acos(c*x))**n*sqrt(d + e*x**S(2))/(f*(m + S(1))), x) def replacement5108(a, b, c, d, e, f, m, n, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asin(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(1))), x) def replacement5109(a, b, c, d, e, f, m, n, p, x): return -Dist(S(2)*e*p/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acos(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(1))), x) def replacement5110(a, b, c, d, e, f, m, n, x): return Dist(sqrt(d + e*x**S(2))/((m + S(2))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**m*(a + b*asin(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) - Dist(b*c*n*sqrt(d + e*x**S(2))/(f*(m + S(2))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*asin(c*x))**n*sqrt(d + e*x**S(2))/(f*(m + S(2))), x) def replacement5111(a, b, c, d, e, f, m, n, x): return Dist(sqrt(d + e*x**S(2))/((m + S(2))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**m*(a + b*acos(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Dist(b*c*n*sqrt(d + e*x**S(2))/(f*(m + S(2))*sqrt(-c**S(2)*x**S(2) + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1)), x), x) + Simp((f*x)**(m + S(1))*(a + b*acos(c*x))**n*sqrt(d + e*x**S(2))/(f*(m + S(2))), x) def replacement5112(a, b, c, d, e, f, m, n, p, x): return Dist(S(2)*d*p/(m + S(2)*p + S(1)), Int((f*x)**m*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(2)*p + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asin(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(2)*p + S(1))), x) def replacement5113(a, b, c, d, e, f, m, n, p, x): return Dist(S(2)*d*p/(m + S(2)*p + S(1)), Int((f*x)**m*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(2)*p + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acos(c*x))**n*(d + e*x**S(2))**p/(f*(m + S(2)*p + S(1))), x) def replacement5114(a, b, c, d, e, f, m, n, p, x): return Dist(c**S(2)*(m + S(2)*p + S(3))/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*asin(c*x))**n*(d + e*x**S(2))**p, x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement5115(a, b, c, d, e, f, m, n, p, x): return Dist(c**S(2)*(m + S(2)*p + S(3))/(f**S(2)*(m + S(1))), Int((f*x)**(m + S(2))*(a + b*acos(c*x))**n*(d + e*x**S(2))**p, x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(f*(m + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp((f*x)**(m + S(1))*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*f*(m + S(1))), x) def replacement5116(a, b, c, d, e, f, m, n, p, x): return -Dist(f**S(2)*(m + S(-1))/(S(2)*e*(p + S(1))), Int((f*x)**(m + S(-2))*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Dist(b*d**IntPart(p)*f*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((f*x)**(m + S(-1))*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5117(a, b, c, d, e, f, m, n, p, x): return -Dist(f**S(2)*(m + S(-1))/(S(2)*e*(p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b*d**IntPart(p)*f*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*c*(p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5118(a, b, c, d, e, f, m, n, p, x): return Dist((m + S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((f*x)**m*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) + Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*f*(p + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) - Simp((f*x)**(m + S(1))*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*f*(p + S(1))), x) def replacement5119(a, b, c, d, e, f, m, n, p, x): return Dist((m + S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((f*x)**m*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b*c*d**IntPart(p)*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(S(2)*f*(p + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) - Simp((f*x)**(m + S(1))*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*f*(p + S(1))), x) def replacement5120(a, b, c, d, e, f, m, n, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*m), Int((f*x)**(m + S(-2))*(a + b*asin(c*x))**n/sqrt(d + e*x**S(2)), x), x) + Dist(b*f*n*sqrt(-c**S(2)*x**S(2) + S(1))/(c*m*sqrt(d + e*x**S(2))), Int((f*x)**(m + S(-1))*(a + b*asin(c*x))**(n + S(-1)), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*asin(c*x))**n*sqrt(d + e*x**S(2))/(e*m), x) def replacement5121(a, b, c, d, e, f, m, n, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*m), Int((f*x)**(m + S(-2))*(a + b*acos(c*x))**n/sqrt(d + e*x**S(2)), x), x) - Dist(b*f*n*sqrt(-c**S(2)*x**S(2) + S(1))/(c*m*sqrt(d + e*x**S(2))), Int((f*x)**(m + S(-1))*(a + b*acos(c*x))**(n + S(-1)), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acos(c*x))**n*sqrt(d + e*x**S(2))/(e*m), x) def replacement5122(a, b, c, d, e, m, n, x): return Dist(c**(-m + S(-1))/sqrt(d), Subst(Int((a + b*x)**n*sin(x)**m, x), x, asin(c*x)), x) def replacement5123(a, b, c, d, e, m, n, x): return -Dist(c**(-m + S(-1))/sqrt(d), Subst(Int((a + b*x)**n*cos(x)**m, x), x, acos(c*x)), x) def replacement5124(a, b, c, d, e, f, m, x): return Simp((f*x)**(m + S(1))*(a + b*asin(c*x))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, c**S(2)*x**S(2))/(sqrt(d)*f*(m + S(1))), x) - Simp(b*c*(f*x)**(m + S(2))*HypergeometricPFQ(List(S(1), m/S(2) + S(1), m/S(2) + S(1)), List(m/S(2) + S(3)/2, m/S(2) + S(2)), c**S(2)*x**S(2))/(sqrt(d)*f**S(2)*(m + S(1))*(m + S(2))), x) def replacement5125(a, b, c, d, e, f, m, x): return Simp((f*x)**(m + S(1))*(a + b*acos(c*x))*Hypergeometric2F1(S(1)/2, m/S(2) + S(1)/2, m/S(2) + S(3)/2, c**S(2)*x**S(2))/(sqrt(d)*f*(m + S(1))), x) + Simp(b*c*(f*x)**(m + S(2))*HypergeometricPFQ(List(S(1), m/S(2) + S(1), m/S(2) + S(1)), List(m/S(2) + S(3)/2, m/S(2) + S(2)), c**S(2)*x**S(2))/(sqrt(d)*f**S(2)*(m + S(1))*(m + S(2))), x) def replacement5126(a, b, c, d, e, f, m, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((f*x)**m*(a + b*asin(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) def replacement5127(a, b, c, d, e, f, m, n, x): return Dist(sqrt(-c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((f*x)**m*(a + b*acos(c*x))**n/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) def replacement5128(a, b, c, d, e, f, m, n, p, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-2))*(a + b*asin(c*x))**n*(d + e*x**S(2))**p, x), x) + Dist(b*d**IntPart(p)*f*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(c*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-1))*(a + b*asin(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*asin(c*x))**n*(d + e*x**S(2))**(p + S(1))/(e*(m + S(2)*p + S(1))), x) def replacement5129(a, b, c, d, e, f, m, n, p, x): return Dist(f**S(2)*(m + S(-1))/(c**S(2)*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-2))*(a + b*acos(c*x))**n*(d + e*x**S(2))**p, x), x) - Dist(b*d**IntPart(p)*f*n*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(c*(m + S(2)*p + S(1))), Int((f*x)**(m + S(-1))*(a + b*acos(c*x))**(n + S(-1))*(-c**S(2)*x**S(2) + S(1))**(p + S(1)/2), x), x) + Simp(f*(f*x)**(m + S(-1))*(a + b*acos(c*x))**n*(d + e*x**S(2))**(p + S(1))/(e*(m + S(2)*p + S(1))), x) def replacement5130(a, b, c, d, e, f, m, n, p, x): return -Dist(d**IntPart(p)*f*m*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*asin(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*asin(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5131(a, b, c, d, e, f, m, n, p, x): return Dist(d**IntPart(p)*f*m*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acos(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) - Simp((f*x)**m*(a + b*acos(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5132(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*c*sqrt(d)*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*asin(c*x))**(n + S(1)), x), x) + Simp((f*x)**m*(a + b*asin(c*x))**(n + S(1))/(b*c*sqrt(d)*(n + S(1))), x) def replacement5133(a, b, c, d, e, f, m, n, x): return Dist(f*m/(b*c*sqrt(d)*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acos(c*x))**(n + S(1)), x), x) - Simp((f*x)**m*(a + b*acos(c*x))**(n + S(1))/(b*c*sqrt(d)*(n + S(1))), x) def replacement5134(a, b, c, d, e, f, m, n, p, x): return -Dist(d**IntPart(p)*f*m*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*asin(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Dist(c*d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))*(m + S(2)*p + S(1))/(b*f*(n + S(1))), Int((f*x)**(m + S(1))*(a + b*asin(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) + Simp((f*x)**m*(a + b*asin(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5135(a, b, c, d, e, f, m, n, p, x): return Dist(d**IntPart(p)*f*m*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))/(b*c*(n + S(1))), Int((f*x)**(m + S(-1))*(a + b*acos(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) - Dist(c*d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p))*(m + S(2)*p + S(1))/(b*f*(n + S(1))), Int((f*x)**(m + S(1))*(a + b*acos(c*x))**(n + S(1))*(-c**S(2)*x**S(2) + S(1))**(p + S(-1)/2), x), x) - Simp((f*x)**m*(a + b*acos(c*x))**(n + S(1))*(d + e*x**S(2))**p*sqrt(-c**S(2)*x**S(2) + S(1))/(b*c*(n + S(1))), x) def replacement5136(a, b, c, d, e, m, n, p, x): return Dist(c**(-m + S(-1))*d**p, Subst(Int((a + b*x)**n*sin(x)**m*cos(x)**(S(2)*p + S(1)), x), x, asin(c*x)), x) def replacement5137(a, b, c, d, e, m, n, p, x): return -Dist(c**(-m + S(-1))*d**p, Subst(Int((a + b*x)**n*sin(x)**(S(2)*p + S(1))*cos(x)**m, x), x, acos(c*x)), x) def replacement5138(a, b, c, d, e, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int(x**m*(a + b*asin(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p, x), x) def replacement5139(a, b, c, d, e, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int(x**m*(a + b*acos(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p, x), x) def replacement5140(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n/sqrt(d + e*x**S(2)), (f*x)**m*(d + e*x**S(2))**(p + S(1)/2), x), x) def replacement5141(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n/sqrt(d + e*x**S(2)), (f*x)**m*(d + e*x**S(2))**(p + S(1)/2), x), x) def replacement5142(a, b, c, d, e, p, x): return -Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*asin(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5143(a, b, c, d, e, p, x): return Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acos(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def With5144(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), u, x) def With5145(a, b, c, d, e, f, m, p, x): u = IntHide((f*x)**m*(d + e*x**S(2))**p, x) return Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), u, x) def replacement5146(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n, (f*x)**m*(d + e*x**S(2))**p, x), x) def replacement5147(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n, (f*x)**m*(d + e*x**S(2))**p, x), x) def replacement5148(a, b, c, d, e, f, m, n, p, x): return Int((f*x)**m*(a + b*asin(c*x))**n*(d + e*x**S(2))**p, x) def replacement5149(a, b, c, d, e, f, m, n, p, x): return Int((f*x)**m*(a + b*acos(c*x))**n*(d + e*x**S(2))**p, x) def replacement5150(a, b, c, d, e, f, g, h, m, n, p, x): return Dist((d + e*x)**FracPart(p)*(f + g*x)**FracPart(p)*(d*f + e*g*x**S(2))**(-FracPart(p)), Int((h*x)**m*(a + b*asin(c*x))**n*(d*f + e*g*x**S(2))**p, x), x) def replacement5151(a, b, c, d, e, f, g, h, m, n, p, x): return Dist((d + e*x)**FracPart(p)*(f + g*x)**FracPart(p)*(d*f + e*g*x**S(2))**(-FracPart(p)), Int((h*x)**m*(a + b*acos(c*x))**n*(d*f + e*g*x**S(2))**p, x), x) def replacement5152(a, b, c, d, e, n, x): return Subst(Int((a + b*x)**n*cos(x)/(c*d + e*sin(x)), x), x, asin(c*x)) def replacement5153(a, b, c, d, e, n, x): return -Subst(Int((a + b*x)**n*sin(x)/(c*d + e*cos(x)), x), x, acos(c*x)) def replacement5154(a, b, c, d, e, m, n, x): return -Dist(b*c*n/(e*(m + S(1))), Int((a + b*asin(c*x))**(n + S(-1))*(d + e*x)**(m + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*asin(c*x))**n*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def replacement5155(a, b, c, d, e, m, n, x): return Dist(b*c*n/(e*(m + S(1))), Int((a + b*acos(c*x))**(n + S(-1))*(d + e*x)**(m + S(1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acos(c*x))**n*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def replacement5156(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n*(d + e*x)**m, x), x) def replacement5157(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n*(d + e*x)**m, x), x) def replacement5158(a, b, c, d, e, m, n, x): return Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(c*d + e*sin(x))**m*cos(x), x), x, asin(c*x)), x) def replacement5159(a, b, c, d, e, m, n, x): return -Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(c*d + e*cos(x))**m*sin(x), x), x, acos(c*x)), x) def With5160(Px, a, b, c, x): u = IntHide(Px, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), u, x) def With5161(Px, a, b, c, x): u = IntHide(Px, x) return Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), u, x) def replacement5162(Px, a, b, c, n, x): return Int(ExpandIntegrand(Px*(a + b*asin(c*x))**n, x), x) def replacement5163(Px, a, b, c, n, x): return Int(ExpandIntegrand(Px*(a + b*acos(c*x))**n, x), x) def With5164(Px, a, b, c, d, e, m, x): u = IntHide(Px*(d + e*x)**m, x) return -Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), u, x) def With5165(Px, a, b, c, d, e, m, x): u = IntHide(Px*(d + e*x)**m, x) return Dist(b*c, Int(SimplifyIntegrand(u/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), u, x) def With5166(a, b, c, d, e, f, g, m, n, p, x): u = IntHide((d + e*x)**m*(f + g*x)**p, x) return -Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*asin(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist((a + b*asin(c*x))**n, u, x) def With5167(a, b, c, d, e, f, g, m, n, p, x): u = IntHide((d + e*x)**m*(f + g*x)**p, x) return Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*acos(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist((a + b*acos(c*x))**n, u, x) def With5168(a, b, c, d, e, f, g, h, n, p, x): u = IntHide((f + g*x + h*x**S(2))**p/(d + e*x)**S(2), x) return -Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*asin(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist((a + b*asin(c*x))**n, u, x) def With5169(a, b, c, d, e, f, g, h, n, p, x): u = IntHide((f + g*x + h*x**S(2))**p/(d + e*x)**S(2), x) return Dist(b*c*n, Int(SimplifyIntegrand(u*(a + b*acos(c*x))**(n + S(-1))/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist((a + b*acos(c*x))**n, u, x) def replacement5170(Px, a, b, c, d, e, m, n, x): return Int(ExpandIntegrand(Px*(a + b*asin(c*x))**n*(d + e*x)**m, x), x) def replacement5171(Px, a, b, c, d, e, m, n, x): return Int(ExpandIntegrand(Px*(a + b*acos(c*x))**n*(d + e*x)**m, x), x) def With5172(a, b, c, d, e, f, g, m, p, x): u = IntHide((d + e*x**S(2))**p*(f + g*x)**m, x) return -Dist(b*c, Int(Dist(S(1)/sqrt(-c**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(a + b*asin(c*x), u, x) def With5173(a, b, c, d, e, f, g, m, p, x): u = IntHide((d + e*x**S(2))**p*(f + g*x)**m, x) return Dist(b*c, Int(Dist(S(1)/sqrt(-c**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(a + b*acos(c*x), u, x) def replacement5174(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n*(d + e*x**S(2))**p, (f + g*x)**m, x), x) def replacement5175(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n*(d + e*x**S(2))**p, (f + g*x)**m, x), x) def replacement5176(a, b, c, d, e, f, g, m, n, x): return -Dist(S(1)/(b*c*sqrt(d)*(n + S(1))), Int((a + b*asin(c*x))**(n + S(1))*(f + g*x)**(m + S(-1))*(d*g*m + S(2)*e*f*x + e*g*x**S(2)*(m + S(2))), x), x) + Simp((a + b*asin(c*x))**(n + S(1))*(d + e*x**S(2))*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement5177(a, b, c, d, e, f, g, m, n, x): return Dist(S(1)/(b*c*sqrt(d)*(n + S(1))), Int((a + b*acos(c*x))**(n + S(1))*(f + g*x)**(m + S(-1))*(d*g*m + S(2)*e*f*x + e*g*x**S(2)*(m + S(2))), x), x) - Simp((a + b*acos(c*x))**(n + S(1))*(d + e*x**S(2))*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement5178(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n*sqrt(d + e*x**S(2)), (d + e*x**S(2))**(p + S(-1)/2)*(f + g*x)**m, x), x) def replacement5179(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n*sqrt(d + e*x**S(2)), (d + e*x**S(2))**(p + S(-1)/2)*(f + g*x)**m, x), x) def replacement5180(a, b, c, d, e, f, g, m, n, p, x): return -Dist(S(1)/(b*c*sqrt(d)*(n + S(1))), Int(ExpandIntegrand((a + b*asin(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), (d + e*x**S(2))**(p + S(-1)/2)*(d*g*m + e*f*x*(S(2)*p + S(1)) + e*g*x**S(2)*(m + S(2)*p + S(1))), x), x), x) + Simp((a + b*asin(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1)/2)*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement5181(a, b, c, d, e, f, g, m, n, p, x): return Dist(S(1)/(b*c*sqrt(d)*(n + S(1))), Int(ExpandIntegrand((a + b*acos(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), (d + e*x**S(2))**(p + S(-1)/2)*(d*g*m + e*f*x*(S(2)*p + S(1)) + e*g*x**S(2)*(m + S(2)*p + S(1))), x), x), x) - Simp((a + b*acos(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1)/2)*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement5182(a, b, c, d, e, f, g, m, n, x): return -Dist(g*m/(b*c*sqrt(d)*(n + S(1))), Int((a + b*asin(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), x), x) + Simp((a + b*asin(c*x))**(n + S(1))*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement5183(a, b, c, d, e, f, g, m, n, x): return Dist(g*m/(b*c*sqrt(d)*(n + S(1))), Int((a + b*acos(c*x))**(n + S(1))*(f + g*x)**(m + S(-1)), x), x) - Simp((a + b*acos(c*x))**(n + S(1))*(f + g*x)**m/(b*c*sqrt(d)*(n + S(1))), x) def replacement5184(a, b, c, d, e, f, g, m, n, x): return Dist(c**(-m + S(-1))/sqrt(d), Subst(Int((a + b*x)**n*(c*f + g*sin(x))**m, x), x, asin(c*x)), x) def replacement5185(a, b, c, d, e, f, g, m, n, x): return -Dist(c**(-m + S(-1))/sqrt(d), Subst(Int((a + b*x)**n*(c*f + g*cos(x))**m, x), x, acos(c*x)), x) def replacement5186(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n/sqrt(d + e*x**S(2)), (d + e*x**S(2))**(p + S(1)/2)*(f + g*x)**m, x), x) def replacement5187(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n/sqrt(d + e*x**S(2)), (d + e*x**S(2))**(p + S(1)/2)*(f + g*x)**m, x), x) def replacement5188(a, b, c, d, e, f, g, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a + b*asin(c*x))**n*(f + g*x)**m*(-c**S(2)*x**S(2) + S(1))**p, x), x) def replacement5189(a, b, c, d, e, f, g, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a + b*acos(c*x))**n*(f + g*x)**m*(-c**S(2)*x**S(2) + S(1))**p, x), x) def replacement5190(a, b, c, d, e, f, g, h, m, n, x): return -Dist(g*m/(b*c*sqrt(d)*(n + S(1))), Int((a + b*asin(c*x))**(n + S(1))/(f + g*x), x), x) + Simp((a + b*asin(c*x))**(n + S(1))*log(h*(f + g*x)**m)/(b*c*sqrt(d)*(n + S(1))), x) def replacement5191(a, b, c, d, e, f, g, h, m, n, x): return Dist(g*m/(b*c*sqrt(d)*(n + S(1))), Int((a + b*acos(c*x))**(n + S(1))/(f + g*x), x), x) - Simp((a + b*acos(c*x))**(n + S(1))*log(h*(f + g*x)**m)/(b*c*sqrt(d)*(n + S(1))), x) def replacement5192(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a + b*asin(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p*log(h*(f + g*x)**m), x), x) def replacement5193(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(d**IntPart(p)*(d + e*x**S(2))**FracPart(p)*(-c**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a + b*acos(c*x))**n*(-c**S(2)*x**S(2) + S(1))**p*log(h*(f + g*x)**m), x), x) def With5194(a, b, c, d, e, f, g, m, x): u = IntHide((d + e*x)**m*(f + g*x)**m, x) return -Dist(b*c, Int(Dist(S(1)/sqrt(-c**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(a + b*asin(c*x), u, x) def With5195(a, b, c, d, e, f, g, m, x): u = IntHide((d + e*x)**m*(f + g*x)**m, x) return Dist(b*c, Int(Dist(S(1)/sqrt(-c**S(2)*x**S(2) + S(1)), u, x), x), x) + Dist(a + b*acos(c*x), u, x) def replacement5196(a, b, c, d, e, f, g, m, n, x): return Int(ExpandIntegrand((a + b*asin(c*x))**n*(d + e*x)**m*(f + g*x)**m, x), x) def replacement5197(a, b, c, d, e, f, g, m, n, x): return Int(ExpandIntegrand((a + b*acos(c*x))**n*(d + e*x)**m*(f + g*x)**m, x), x) def With5198(a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False v = IntHide(u, x) if InverseFunctionFreeQ(v, x): return True return False def replacement5198(a, b, c, u, x): v = IntHide(u, x) return -Dist(b*c, Int(SimplifyIntegrand(v/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*asin(c*x), v, x) def With5199(a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False v = IntHide(u, x) if InverseFunctionFreeQ(v, x): return True return False def replacement5199(a, b, c, u, x): v = IntHide(u, x) return Dist(b*c, Int(SimplifyIntegrand(v/sqrt(-c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acos(c*x), v, x) def With5200(Px, a, b, c, d, e, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*asin(c*x))**n*(d + e*x**S(2))**p, x) if SumQ(u): return True return False def replacement5200(Px, a, b, c, d, e, n, p, x): u = ExpandIntegrand(Px*(a + b*asin(c*x))**n*(d + e*x**S(2))**p, x) return Int(u, x) def With5201(Px, a, b, c, d, e, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*acos(c*x))**n*(d + e*x**S(2))**p, x) if SumQ(u): return True return False def replacement5201(Px, a, b, c, d, e, n, p, x): u = ExpandIntegrand(Px*(a + b*acos(c*x))**n*(d + e*x**S(2))**p, x) return Int(u, x) def With5202(Px, a, b, c, d, e, f, g, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*asin(c*x))**n*(f + g*(d + e*x**S(2))**p)**m, x) if SumQ(u): return True return False def replacement5202(Px, a, b, c, d, e, f, g, m, n, p, x): u = ExpandIntegrand(Px*(a + b*asin(c*x))**n*(f + g*(d + e*x**S(2))**p)**m, x) return Int(u, x) def With5203(Px, a, b, c, d, e, f, g, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(Px*(a + b*acos(c*x))**n*(f + g*(d + e*x**S(2))**p)**m, x) if SumQ(u): return True return False def replacement5203(Px, a, b, c, d, e, f, g, m, n, p, x): u = ExpandIntegrand(Px*(a + b*acos(c*x))**n*(f + g*(d + e*x**S(2))**p)**m, x) return Int(u, x) def With5204(RFx, c, n, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(asin(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement5204(RFx, c, n, x): u = ExpandIntegrand(asin(c*x)**n, RFx, x) return Int(u, x) def With5205(RFx, c, n, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(acos(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement5205(RFx, c, n, x): u = ExpandIntegrand(acos(c*x)**n, RFx, x) return Int(u, x) def replacement5206(RFx, a, b, c, n, x): return Int(ExpandIntegrand(RFx*(a + b*asin(c*x))**n, x), x) def replacement5207(RFx, a, b, c, n, x): return Int(ExpandIntegrand(RFx*(a + b*acos(c*x))**n, x), x) def With5208(RFx, c, d, e, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((d + e*x**S(2))**p*asin(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement5208(RFx, c, d, e, n, p, x): u = ExpandIntegrand((d + e*x**S(2))**p*asin(c*x)**n, RFx, x) return Int(u, x) def With5209(RFx, c, d, e, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((d + e*x**S(2))**p*acos(c*x)**n, RFx, x) if SumQ(u): return True return False def replacement5209(RFx, c, d, e, n, p, x): u = ExpandIntegrand((d + e*x**S(2))**p*acos(c*x)**n, RFx, x) return Int(u, x) def replacement5210(RFx, a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((d + e*x**S(2))**p, RFx*(a + b*asin(c*x))**n, x), x) def replacement5211(RFx, a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((d + e*x**S(2))**p, RFx*(a + b*acos(c*x))**n, x), x) def replacement5212(a, b, c, n, u, x): return Int(u*(a + b*asin(c*x))**n, x) def replacement5213(a, b, c, n, u, x): return Int(u*(a + b*acos(c*x))**n, x) def replacement5214(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*asin(x))**n, x), x, c + d*x), x) def replacement5215(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*acos(x))**n, x), x, c + d*x), x) def replacement5216(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*asin(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5217(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*acos(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5218(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*asin(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p, x), x, c + d*x), x) def replacement5219(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acos(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p, x), x, c + d*x), x) def replacement5220(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*asin(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5221(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acos(x))**n*(C*x**S(2)/d**S(2) - C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5222(a, b, c, d, x): return Simp(x*sqrt(a + b*asin(c + d*x**S(2))), x) + Simp(sqrt(Pi)*x*(-c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*FresnelS(sqrt(c/(Pi*b))*sqrt(a + b*asin(c + d*x**S(2))))/(sqrt(c/b)*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) - Simp(sqrt(Pi)*x*(c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*FresnelC(sqrt(c/(Pi*b))*sqrt(a + b*asin(c + d*x**S(2))))/(sqrt(c/b)*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) def replacement5223(a, b, d, x): return Simp(-S(2)*sqrt(a + b*acos(d*x**S(2) + S(1)))*sin(acos(d*x**S(2) + S(1))/S(2))**S(2)/(d*x), x) - Simp(S(2)*sqrt(Pi)*FresnelC(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(1))))*sin(a/(S(2)*b))*sin(acos(d*x**S(2) + S(1))/S(2))/(d*x*sqrt(S(1)/b)), x) + Simp(S(2)*sqrt(Pi)*FresnelS(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(1))))*sin(acos(d*x**S(2) + S(1))/S(2))*cos(a/(S(2)*b))/(d*x*sqrt(S(1)/b)), x) def replacement5224(a, b, d, x): return Simp(S(2)*sqrt(a + b*acos(d*x**S(2) + S(-1)))*cos(acos(d*x**S(2) + S(-1))/S(2))**S(2)/(d*x), x) - Simp(S(2)*sqrt(Pi)*FresnelC(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(-1))))*cos(a/(S(2)*b))*cos(acos(d*x**S(2) + S(-1))/S(2))/(d*x*sqrt(S(1)/b)), x) - Simp(S(2)*sqrt(Pi)*FresnelS(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(-1))))*sin(a/(S(2)*b))*cos(acos(d*x**S(2) + S(-1))/S(2))/(d*x*sqrt(S(1)/b)), x) def replacement5225(a, b, c, d, n, x): return -Dist(S(4)*b**S(2)*n*(n + S(-1)), Int((a + b*asin(c + d*x**S(2)))**(n + S(-2)), x), x) + Simp(x*(a + b*asin(c + d*x**S(2)))**n, x) + Simp(S(2)*b*n*(a + b*asin(c + d*x**S(2)))**(n + S(-1))*sqrt(-S(2)*c*d*x**S(2) - d**S(2)*x**S(4))/(d*x), x) def replacement5226(a, b, c, d, n, x): return -Dist(S(4)*b**S(2)*n*(n + S(-1)), Int((a + b*acos(c + d*x**S(2)))**(n + S(-2)), x), x) + Simp(x*(a + b*acos(c + d*x**S(2)))**n, x) - Simp(S(2)*b*n*(a + b*acos(c + d*x**S(2)))**(n + S(-1))*sqrt(-S(2)*c*d*x**S(2) - d**S(2)*x**S(4))/(d*x), x) def replacement5227(a, b, c, d, x): return -Simp(x*(c*cos(a/(S(2)*b)) - sin(a/(S(2)*b)))*CosIntegral(c*(a + b*asin(c + d*x**S(2)))/(S(2)*b))/(S(2)*b*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) - Simp(x*(c*cos(a/(S(2)*b)) + sin(a/(S(2)*b)))*SinIntegral(c*(a + b*asin(c + d*x**S(2)))/(S(2)*b))/(S(2)*b*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) def replacement5228(a, b, d, x): return Simp(sqrt(S(2))*x*CosIntegral((a + b*acos(d*x**S(2) + S(1)))/(S(2)*b))*cos(a/(S(2)*b))/(S(2)*b*sqrt(-d*x**S(2))), x) + Simp(sqrt(S(2))*x*SinIntegral((a + b*acos(d*x**S(2) + S(1)))/(S(2)*b))*sin(a/(S(2)*b))/(S(2)*b*sqrt(-d*x**S(2))), x) def replacement5229(a, b, d, x): return Simp(sqrt(S(2))*x*CosIntegral((a + b*acos(d*x**S(2) + S(-1)))/(S(2)*b))*sin(a/(S(2)*b))/(S(2)*b*sqrt(d*x**S(2))), x) - Simp(sqrt(S(2))*x*SinIntegral((a + b*acos(d*x**S(2) + S(-1)))/(S(2)*b))*cos(a/(S(2)*b))/(S(2)*b*sqrt(d*x**S(2))), x) def replacement5230(a, b, c, d, x): return -Simp(sqrt(Pi)*x*(-c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*FresnelC(sqrt(a + b*asin(c + d*x**S(2)))/(sqrt(Pi)*sqrt(b*c)))/(sqrt(b*c)*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) - Simp(sqrt(Pi)*x*(c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*FresnelS(sqrt(a + b*asin(c + d*x**S(2)))/(sqrt(Pi)*sqrt(b*c)))/(sqrt(b*c)*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) def replacement5231(a, b, d, x): return Simp(-S(2)*sqrt(Pi/b)*FresnelC(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(1))))*sin(acos(d*x**S(2) + S(1))/S(2))*cos(a/(S(2)*b))/(d*x), x) - Simp(S(2)*sqrt(Pi/b)*FresnelS(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(1))))*sin(a/(S(2)*b))*sin(acos(d*x**S(2) + S(1))/S(2))/(d*x), x) def replacement5232(a, b, d, x): return Simp(S(2)*sqrt(Pi/b)*FresnelC(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(-1))))*sin(a/(S(2)*b))*cos(acos(d*x**S(2) + S(-1))/S(2))/(d*x), x) - Simp(S(2)*sqrt(Pi/b)*FresnelS(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(-1))))*cos(a/(S(2)*b))*cos(acos(d*x**S(2) + S(-1))/S(2))/(d*x), x) def replacement5233(a, b, c, d, x): return -Simp(sqrt(-S(2)*c*d*x**S(2) - d**S(2)*x**S(4))/(b*d*x*sqrt(a + b*asin(c + d*x**S(2)))), x) + Simp(sqrt(Pi)*x*(c/b)**(S(3)/2)*(-c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*FresnelS(sqrt(c/(Pi*b))*sqrt(a + b*asin(c + d*x**S(2))))/(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2))), x) - Simp(sqrt(Pi)*x*(c/b)**(S(3)/2)*(c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*FresnelC(sqrt(c/(Pi*b))*sqrt(a + b*asin(c + d*x**S(2))))/(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2))), x) def replacement5234(a, b, d, x): return Simp(sqrt(-d**S(2)*x**S(4) - S(2)*d*x**S(2))/(b*d*x*sqrt(a + b*acos(d*x**S(2) + S(1)))), x) - Simp(S(2)*sqrt(Pi)*(S(1)/b)**(S(3)/2)*FresnelC(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(1))))*sin(a/(S(2)*b))*sin(acos(d*x**S(2) + S(1))/S(2))/(d*x), x) + Simp(S(2)*sqrt(Pi)*(S(1)/b)**(S(3)/2)*FresnelS(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(1))))*sin(acos(d*x**S(2) + S(1))/S(2))*cos(a/(S(2)*b))/(d*x), x) def replacement5235(a, b, d, x): return Simp(sqrt(-d**S(2)*x**S(4) + S(2)*d*x**S(2))/(b*d*x*sqrt(a + b*acos(d*x**S(2) + S(-1)))), x) - Simp(S(2)*sqrt(Pi)*(S(1)/b)**(S(3)/2)*FresnelC(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(-1))))*cos(a/(S(2)*b))*cos(acos(d*x**S(2) + S(-1))/S(2))/(d*x), x) - Simp(S(2)*sqrt(Pi)*(S(1)/b)**(S(3)/2)*FresnelS(sqrt(S(1)/(Pi*b))*sqrt(a + b*acos(d*x**S(2) + S(-1))))*sin(a/(S(2)*b))*cos(acos(d*x**S(2) + S(-1))/S(2))/(d*x), x) def replacement5236(a, b, c, d, x): return Simp(x*(-c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*SinIntegral(c*(a + b*asin(c + d*x**S(2)))/(S(2)*b))/(S(4)*b**S(2)*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) - Simp(x*(c*sin(a/(S(2)*b)) + cos(a/(S(2)*b)))*CosIntegral(c*(a + b*asin(c + d*x**S(2)))/(S(2)*b))/(S(4)*b**S(2)*(-c*sin(asin(c + d*x**S(2))/S(2)) + cos(asin(c + d*x**S(2))/S(2)))), x) - Simp(sqrt(-S(2)*c*d*x**S(2) - d**S(2)*x**S(4))/(S(2)*b*d*x*(a + b*asin(c + d*x**S(2)))), x) def replacement5237(a, b, d, x): return Simp(sqrt(-d**S(2)*x**S(4) - S(2)*d*x**S(2))/(S(2)*b*d*x*(a + b*acos(d*x**S(2) + S(1)))), x) + Simp(sqrt(S(2))*x*CosIntegral((a + b*acos(d*x**S(2) + S(1)))/(S(2)*b))*sin(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(-d*x**S(2))), x) - Simp(sqrt(S(2))*x*SinIntegral((a + b*acos(d*x**S(2) + S(1)))/(S(2)*b))*cos(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(-d*x**S(2))), x) def replacement5238(a, b, d, x): return Simp(sqrt(-d**S(2)*x**S(4) + S(2)*d*x**S(2))/(S(2)*b*d*x*(a + b*acos(d*x**S(2) + S(-1)))), x) - Simp(sqrt(S(2))*x*CosIntegral((a + b*acos(d*x**S(2) + S(-1)))/(S(2)*b))*cos(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(d*x**S(2))), x) - Simp(sqrt(S(2))*x*SinIntegral((a + b*acos(d*x**S(2) + S(-1)))/(S(2)*b))*sin(a/(S(2)*b))/(S(4)*b**S(2)*sqrt(d*x**S(2))), x) def replacement5239(a, b, c, d, n, x): return -Dist(S(1)/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), Int((a + b*asin(c + d*x**S(2)))**(n + S(2)), x), x) + Simp(x*(a + b*asin(c + d*x**S(2)))**(n + S(2))/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), x) + Simp((a + b*asin(c + d*x**S(2)))**(n + S(1))*sqrt(-S(2)*c*d*x**S(2) - d**S(2)*x**S(4))/(S(2)*b*d*x*(n + S(1))), x) def replacement5240(a, b, c, d, n, x): return -Dist(S(1)/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), Int((a + b*acos(c + d*x**S(2)))**(n + S(2)), x), x) + Simp(x*(a + b*acos(c + d*x**S(2)))**(n + S(2))/(S(4)*b**S(2)*(n + S(1))*(n + S(2))), x) - Simp((a + b*acos(c + d*x**S(2)))**(n + S(1))*sqrt(-S(2)*c*d*x**S(2) - d**S(2)*x**S(4))/(S(2)*b*d*x*(n + S(1))), x) def replacement5241(a, n, p, x): return Dist(S(1)/p, Subst(Int(x**n/tan(x), x), x, asin(a*x**p)), x) def replacement5242(a, n, p, x): return -Dist(S(1)/p, Subst(Int(x**n*tan(x), x), x, acos(a*x**p)), x) def replacement5243(a, b, c, m, n, u, x): return Int(u*acsc(a/c + b*x**n/c)**m, x) def replacement5244(a, b, c, m, n, u, x): return Int(u*asec(a/c + b*x**n/c)**m, x) def replacement5245(b, n, x): return Dist(sqrt(-b*x**S(2))/(b*x), Subst(Int(asin(x)**n/sqrt(S(1) - x**S(2)), x), x, sqrt(b*x**S(2) + S(1))), x) def replacement5246(b, n, x): return Dist(sqrt(-b*x**S(2))/(b*x), Subst(Int(acos(x)**n/sqrt(S(1) - x**S(2)), x), x, sqrt(b*x**S(2) + S(1))), x) def replacement5247(a, b, c, f, n, u, x): return Dist(S(1)/b, Subst(Int(f**(c*x**n)*ReplaceAll(u, Rule(x, -a/b + sin(x)/b))*cos(x), x), x, asin(a + b*x)), x) def replacement5248(a, b, c, f, n, u, x): return -Dist(S(1)/b, Subst(Int(f**(c*x**n)*ReplaceAll(u, Rule(x, -a/b + cos(x)/b))*sin(x), x), x, acos(a + b*x)), x) def replacement5249(a, b, c, d, x): return -Dist(x*sqrt(a**S(2)*x**S(2) + S(2)*a*b*sqrt(c + d*x**S(2)) + b**S(2)*d)/sqrt(-x**S(2)*(a**S(2)*x**S(2) + S(2)*a*b*sqrt(c + d*x**S(2)) + b**S(2)*d)), Int(x*(S(2)*a*sqrt(c + d*x**S(2)) + b*d)/(sqrt(c + d*x**S(2))*sqrt(a**S(2)*x**S(2) + S(2)*a*b*sqrt(c + d*x**S(2)) + b**S(2)*d)), x), x) + Simp(x*asin(a*x**S(2) + b*sqrt(c + d*x**S(2))), x) def replacement5250(a, b, c, d, x): return Dist(x*sqrt(a**S(2)*x**S(2) + S(2)*a*b*sqrt(c + d*x**S(2)) + b**S(2)*d)/sqrt(-x**S(2)*(a**S(2)*x**S(2) + S(2)*a*b*sqrt(c + d*x**S(2)) + b**S(2)*d)), Int(x*(S(2)*a*sqrt(c + d*x**S(2)) + b*d)/(sqrt(c + d*x**S(2))*sqrt(a**S(2)*x**S(2) + S(2)*a*b*sqrt(c + d*x**S(2)) + b**S(2)*d)), x), x) + Simp(x*acos(a*x**S(2) + b*sqrt(c + d*x**S(2))), x) def replacement5251(u, x): return -Int(SimplifyIntegrand(x*D(u, x)/sqrt(S(1) - u**S(2)), x), x) + Simp(x*asin(u), x) def replacement5252(u, x): return Int(SimplifyIntegrand(x*D(u, x)/sqrt(S(1) - u**S(2)), x), x) + Simp(x*acos(u), x) def replacement5253(a, b, c, d, m, u, x): return -Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/sqrt(S(1) - u**S(2)), x), x), x) + Simp((a + b*asin(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement5254(a, b, c, d, m, u, x): return Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/sqrt(S(1) - u**S(2)), x), x), x) + Simp((a + b*acos(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def With5255(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement5255(a, b, u, v, x): w = IntHide(v, x) return -Dist(b, Int(SimplifyIntegrand(w*D(u, x)/sqrt(S(1) - u**S(2)), x), x), x) + Dist(a + b*asin(u), w, x) def With5256(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement5256(a, b, u, v, x): w = IntHide(v, x) return Dist(b, Int(SimplifyIntegrand(w*D(u, x)/sqrt(S(1) - u**S(2)), x), x), x) + Dist(a + b*acos(u), w, x) def replacement5257(a, b, c, n, x): return -Dist(b*c*n, Int(x*(a + b*ArcTan(c*x))**(n + S(-1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*ArcTan(c*x))**n, x) def replacement5258(a, b, c, n, x): return Dist(b*c*n, Int(x*(a + b*acot(c*x))**(n + S(-1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x*(a + b*acot(c*x))**n, x) def replacement5259(a, b, c, n, x): return Int((a + b*ArcTan(c*x))**n, x) def replacement5260(a, b, c, n, x): return Int((a + b*acot(c*x))**n, x) def replacement5261(a, b, c, d, e, n, x): return Dist(b*c*n/e, Int((a + b*ArcTan(c*x))**(n + S(-1))*log(S(2)*d/(d + e*x))/(c**S(2)*x**S(2) + S(1)), x), x) - Simp((a + b*ArcTan(c*x))**n*log(S(2)*d/(d + e*x))/e, x) def replacement5262(a, b, c, d, e, n, x): return -Dist(b*c*n/e, Int((a + b*acot(c*x))**(n + S(-1))*log(S(2)*d/(d + e*x))/(c**S(2)*x**S(2) + S(1)), x), x) - Simp((a + b*acot(c*x))**n*log(S(2)*d/(d + e*x))/e, x) def replacement5263(c, d, e, x): return Simp(I*PolyLog(S(2), Simp(I*c*(d + e*x)/(I*c*d - e), x))/(S(2)*e), x) - Simp(I*PolyLog(S(2), Simp(I*c*(d + e*x)/(I*c*d + e), x))/(S(2)*e), x) - Simp(ArcTan(c*d/e)*log(d + e*x)/e, x) def replacement5264(c, d, e, x): return Dist(I/S(2), Int(log(-I*c*x + S(1))/(d + e*x), x), x) - Dist(I/S(2), Int(log(I*c*x + S(1))/(d + e*x), x), x) def replacement5265(c, d, e, x): return Dist(I/S(2), Int(log(S(1) - I/(c*x))/(d + e*x), x), x) - Dist(I/S(2), Int(log(S(1) + I/(c*x))/(d + e*x), x), x) def replacement5266(a, b, c, d, e, x): return Dist(b, Int(ArcTan(c*x)/(d + e*x), x), x) + Simp(a*log(RemoveContent(d + e*x, x))/e, x) def replacement5267(a, b, c, d, e, x): return Dist(b, Int(acot(c*x)/(d + e*x), x), x) + Simp(a*log(RemoveContent(d + e*x, x))/e, x) def replacement5268(a, b, c, d, e, p, x): return -Dist(b*c/(e*(p + S(1))), Int((d + e*x)**(p + S(1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*ArcTan(c*x))*(d + e*x)**(p + S(1))/(e*(p + S(1))), x) def replacement5269(a, b, c, d, e, p, x): return Dist(b*c/(e*(p + S(1))), Int((d + e*x)**(p + S(1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acot(c*x))*(d + e*x)**(p + S(1))/(e*(p + S(1))), x) def replacement5270(a, b, c, n, x): return -Dist(S(2)*b*c*n, Int((a + b*ArcTan(c*x))**(n + S(-1))*atanh(S(1) - S(2)*I/(-c*x + I))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp(S(2)*(a + b*ArcTan(c*x))**n*atanh(S(1) - S(2)*I/(-c*x + I)), x) def replacement5271(a, b, c, n, x): return Dist(S(2)*b*c*n, Int((a + b*acot(c*x))**(n + S(-1))*acoth(S(1) - S(2)*I/(-c*x + I))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp(S(2)*(a + b*acot(c*x))**n*acoth(S(1) - S(2)*I/(-c*x + I)), x) def replacement5272(a, b, c, m, n, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*ArcTan(c*x))**(n + S(-1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**(m + S(1))*(a + b*ArcTan(c*x))**n/(m + S(1)), x) def replacement5273(a, b, c, m, n, x): return Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acot(c*x))**(n + S(-1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp(x**(m + S(1))*(a + b*acot(c*x))**n/(m + S(1)), x) def replacement5274(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*ArcTan(c*x))**n*(d + e*x)**p, x), x) def replacement5275(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*acot(c*x))**n*(d + e*x)**p, x), x) def replacement5276(a, b, c, d, e, n, p, x): return Int((a + b*ArcTan(c*x))**n*(d + e*x)**p, x) def replacement5277(a, b, c, d, e, n, p, x): return Int((a + b*acot(c*x))**n*(d + e*x)**p, x) def replacement5278(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-1))*(a + b*ArcTan(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-1))*(a + b*ArcTan(c*x))**n/(d + e*x), x), x) def replacement5279(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-1))*(a + b*acot(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-1))*(a + b*acot(c*x))**n/(d + e*x), x), x) def replacement5280(a, b, c, d, e, n, x): return -Dist(b*c*n/d, Int((a + b*ArcTan(c*x))**(n + S(-1))*log(S(2)*e*x/(d + e*x))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*ArcTan(c*x))**n*log(S(2)*e*x/(d + e*x))/d, x) def replacement5281(a, b, c, d, e, n, x): return Dist(b*c*n/d, Int((a + b*acot(c*x))**(n + S(-1))*log(S(2)*e*x/(d + e*x))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acot(c*x))**n*log(S(2)*e*x/(d + e*x))/d, x) def replacement5282(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*ArcTan(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(1))*(a + b*ArcTan(c*x))**n/(d + e*x), x), x) def replacement5283(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*acot(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(1))*(a + b*acot(c*x))**n/(d + e*x), x), x) def replacement5284(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*ArcTan(c*x))**n*(d + e*x)**p, x), x) def replacement5285(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*acot(c*x))**n*(d + e*x)**p, x), x) def replacement5286(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*ArcTan(c*x))**n*(d + e*x)**p, x) def replacement5287(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*acot(c*x))**n*(d + e*x)**p, x) def replacement5288(a, b, c, d, e, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*ArcTan(c*x))*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) - Simp(b*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement5289(a, b, c, d, e, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*acot(c*x))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*acot(c*x))*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) + Simp(b*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement5290(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(b**S(2)*d*n*(n + S(-1))/(S(2)*p*(S(2)*p + S(1))), Int((a + b*ArcTan(c*x))**(n + S(-2))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) - Simp(b*n*(a + b*ArcTan(c*x))**(n + S(-1))*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement5291(a, b, c, d, e, n, p, x): return Dist(S(2)*d*p/(S(2)*p + S(1)), Int((a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(b**S(2)*d*n*(n + S(-1))/(S(2)*p*(S(2)*p + S(1))), Int((a + b*acot(c*x))**(n + S(-2))*(d + e*x**S(2))**(p + S(-1)), x), x) + Simp(x*(a + b*acot(c*x))**n*(d + e*x**S(2))**p/(S(2)*p + S(1)), x) + Simp(b*n*(a + b*acot(c*x))**(n + S(-1))*(d + e*x**S(2))**p/(S(2)*c*p*(S(2)*p + S(1))), x) def replacement5292(a, b, c, d, e, x): return Simp(log(RemoveContent(a + b*ArcTan(c*x), x))/(b*c*d), x) def replacement5293(a, b, c, d, e, x): return -Simp(log(RemoveContent(a + b*acot(c*x), x))/(b*c*d), x) def replacement5294(a, b, c, d, e, n, x): return Simp((a + b*ArcTan(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement5295(a, b, c, d, e, n, x): return -Simp((a + b*acot(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement5296(a, b, c, d, e, x): return Simp(I*b*PolyLog(S(2), -I*sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/(c*sqrt(d)), x) - Simp(I*b*PolyLog(S(2), I*sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/(c*sqrt(d)), x) + Simp(-S(2)*I*(a + b*ArcTan(c*x))*ArcTan(sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/(c*sqrt(d)), x) def replacement5297(a, b, c, d, e, x): return -Simp(I*b*PolyLog(S(2), -I*sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/(c*sqrt(d)), x) + Simp(I*b*PolyLog(S(2), I*sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/(c*sqrt(d)), x) + Simp(-S(2)*I*(a + b*acot(c*x))*ArcTan(sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/(c*sqrt(d)), x) def replacement5298(a, b, c, d, e, n, x): return Dist(S(1)/(c*sqrt(d)), Subst(Int((a + b*x)**n/cos(x), x), x, ArcTan(c*x)), x) def replacement5299(a, b, c, d, e, n, x): return -Dist(x*sqrt(S(1) + S(1)/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n/sin(x), x), x, acot(c*x)), x) def replacement5300(a, b, c, d, e, n, x): return Dist(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*ArcTan(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) def replacement5301(a, b, c, d, e, n, x): return Dist(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*acot(c*x))**n/sqrt(c**S(2)*x**S(2) + S(1)), x), x) def replacement5302(a, b, c, d, e, n, x): return -Dist(b*c*n/S(2), Int(x*(a + b*ArcTan(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) + Simp(x*(a + b*ArcTan(c*x))**n/(S(2)*d*(d + e*x**S(2))), x) + Simp((a + b*ArcTan(c*x))**(n + S(1))/(S(2)*b*c*d**S(2)*(n + S(1))), x) def replacement5303(a, b, c, d, e, n, x): return Dist(b*c*n/S(2), Int(x*(a + b*acot(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) + Simp(x*(a + b*acot(c*x))**n/(S(2)*d*(d + e*x**S(2))), x) - Simp((a + b*acot(c*x))**(n + S(1))/(S(2)*b*c*d**S(2)*(n + S(1))), x) def replacement5304(a, b, c, d, e, x): return Simp(b/(c*d*sqrt(d + e*x**S(2))), x) + Simp(x*(a + b*ArcTan(c*x))/(d*sqrt(d + e*x**S(2))), x) def replacement5305(a, b, c, d, e, x): return -Simp(b/(c*d*sqrt(d + e*x**S(2))), x) + Simp(x*(a + b*acot(c*x))/(d*sqrt(d + e*x**S(2))), x) def replacement5306(a, b, c, d, e, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) + Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) - Simp(x*(a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement5307(a, b, c, d, e, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*acot(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) - Simp(x*(a + b*acot(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) def replacement5308(a, b, c, d, e, n, x): return -Dist(b**S(2)*n*(n + S(-1)), Int((a + b*ArcTan(c*x))**(n + S(-2))/(d + e*x**S(2))**(S(3)/2), x), x) + Simp(x*(a + b*ArcTan(c*x))**n/(d*sqrt(d + e*x**S(2))), x) + Simp(b*n*(a + b*ArcTan(c*x))**(n + S(-1))/(c*d*sqrt(d + e*x**S(2))), x) def replacement5309(a, b, c, d, e, n, x): return -Dist(b**S(2)*n*(n + S(-1)), Int((a + b*acot(c*x))**(n + S(-2))/(d + e*x**S(2))**(S(3)/2), x), x) + Simp(x*(a + b*acot(c*x))**n/(d*sqrt(d + e*x**S(2))), x) - Simp(b*n*(a + b*acot(c*x))**(n + S(-1))/(c*d*sqrt(d + e*x**S(2))), x) def replacement5310(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b**S(2)*n*(n + S(-1))/(S(4)*(p + S(1))**S(2)), Int((a + b*ArcTan(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) - Simp(x*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) + Simp(b*n*(a + b*ArcTan(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) def replacement5311(a, b, c, d, e, n, p, x): return Dist((S(2)*p + S(3))/(S(2)*d*(p + S(1))), Int((a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(b**S(2)*n*(n + S(-1))/(S(4)*(p + S(1))**S(2)), Int((a + b*acot(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) - Simp(x*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*d*(p + S(1))), x) - Simp(b*n*(a + b*acot(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(S(4)*c*d*(p + S(1))**S(2)), x) def replacement5312(a, b, c, d, e, n, p, x): return -Dist(S(2)*c*(p + S(1))/(b*(n + S(1))), Int(x*(a + b*ArcTan(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp((a + b*ArcTan(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement5313(a, b, c, d, e, n, p, x): return Dist(S(2)*c*(p + S(1))/(b*(n + S(1))), Int(x*(a + b*acot(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) - Simp((a + b*acot(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement5314(a, b, c, d, e, n, p, x): return Dist(d**p/c, Subst(Int((a + b*x)**n*cos(x)**(-S(2)*p + S(-2)), x), x, ArcTan(c*x)), x) def replacement5315(a, b, c, d, e, n, p, x): return Dist(d**(p + S(1)/2)*sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*ArcTan(c*x))**n*(c**S(2)*x**S(2) + S(1))**p, x), x) def replacement5316(a, b, c, d, e, n, p, x): return -Dist(d**p/c, Subst(Int((a + b*x)**n*sin(x)**(-S(2)*p + S(-2)), x), x, acot(c*x)), x) def replacement5317(a, b, c, d, e, n, p, x): return -Dist(d**(p + S(1)/2)*x*sqrt((c**S(2)*x**S(2) + S(1))/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n*sin(x)**(-S(2)*p + S(-2)), x), x, acot(c*x)), x) def replacement5318(c, d, e, x): return Dist(I/S(2), Int(log(-I*c*x + S(1))/(d + e*x**S(2)), x), x) - Dist(I/S(2), Int(log(I*c*x + S(1))/(d + e*x**S(2)), x), x) def replacement5319(c, d, e, x): return Dist(I/S(2), Int(log(S(1) - I/(c*x))/(d + e*x**S(2)), x), x) - Dist(I/S(2), Int(log(S(1) + I/(c*x))/(d + e*x**S(2)), x), x) def replacement5320(a, b, c, d, e, x): return Dist(a, Int(S(1)/(d + e*x**S(2)), x), x) + Dist(b, Int(ArcTan(c*x)/(d + e*x**S(2)), x), x) def replacement5321(a, b, c, d, e, x): return Dist(a, Int(S(1)/(d + e*x**S(2)), x), x) + Dist(b, Int(acot(c*x)/(d + e*x**S(2)), x), x) def With5322(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c, Int(ExpandIntegrand(u/(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*ArcTan(c*x), u, x) def With5323(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return Dist(b*c, Int(ExpandIntegrand(u/(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acot(c*x), u, x) def replacement5324(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*ArcTan(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5325(a, b, c, d, e, n, p, x): return Int(ExpandIntegrand((a + b*acot(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5326(a, b, c, d, e, n, p, x): return Int((a + b*ArcTan(c*x))**n*(d + e*x**S(2))**p, x) def replacement5327(a, b, c, d, e, n, p, x): return Int((a + b*acot(c*x))**n*(d + e*x**S(2))**p, x) def replacement5328(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n/(d + e*x**S(2)), x), x) def replacement5329(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*acot(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*acot(c*x))**n/(d + e*x**S(2)), x), x) def replacement5330(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*ArcTan(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*ArcTan(c*x))**n/(d + e*x**S(2)), x), x) def replacement5331(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*acot(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*acot(c*x))**n/(d + e*x**S(2)), x), x) def replacement5332(a, b, c, d, e, n, x): return -Dist(S(1)/(c*d), Int((a + b*ArcTan(c*x))**n/(-c*x + I), x), x) - Simp(I*(a + b*ArcTan(c*x))**(n + S(1))/(b*e*(n + S(1))), x) def replacement5333(a, b, c, d, e, n, x): return -Dist(S(1)/(c*d), Int((a + b*acot(c*x))**n/(-c*x + I), x), x) + Simp(I*(a + b*acot(c*x))**(n + S(1))/(b*e*(n + S(1))), x) def replacement5334(a, b, c, d, e, n, x): return -Dist(S(1)/(b*c*d*(n + S(1))), Int((a + b*ArcTan(c*x))**(n + S(1)), x), x) + Simp(x*(a + b*ArcTan(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement5335(a, b, c, d, e, n, x): return Dist(S(1)/(b*c*d*(n + S(1))), Int((a + b*acot(c*x))**(n + S(1)), x), x) - Simp(x*(a + b*acot(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement5336(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n/(d + e*x**S(2)), x), x) def replacement5337(a, b, c, d, e, m, n, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*acot(c*x))**n, x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*acot(c*x))**n/(d + e*x**S(2)), x), x) def replacement5338(a, b, c, d, e, n, x): return Dist(I/d, Int((a + b*ArcTan(c*x))**n/(x*(c*x + I)), x), x) - Simp(I*(a + b*ArcTan(c*x))**(n + S(1))/(b*d*(n + S(1))), x) def replacement5339(a, b, c, d, e, n, x): return Dist(I/d, Int((a + b*acot(c*x))**n/(x*(c*x + I)), x), x) + Simp(I*(a + b*acot(c*x))**(n + S(1))/(b*d*(n + S(1))), x) def replacement5340(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*ArcTan(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*ArcTan(c*x))**n/(d + e*x**S(2)), x), x) def replacement5341(a, b, c, d, e, m, n, x): return Dist(S(1)/d, Int(x**m*(a + b*acot(c*x))**n, x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*acot(c*x))**n/(d + e*x**S(2)), x), x) def replacement5342(a, b, c, d, e, m, n, x): return -Dist(m/(b*c*d*(n + S(1))), Int(x**(m + S(-1))*(a + b*ArcTan(c*x))**(n + S(1)), x), x) + Simp(x**m*(a + b*ArcTan(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement5343(a, b, c, d, e, m, n, x): return Dist(m/(b*c*d*(n + S(1))), Int(x**(m + S(-1))*(a + b*acot(c*x))**(n + S(1)), x), x) - Simp(x**m*(a + b*acot(c*x))**(n + S(1))/(b*c*d*(n + S(1))), x) def replacement5344(a, b, c, d, e, m, x): return Int(ExpandIntegrand(a + b*ArcTan(c*x), x**m/(d + e*x**S(2)), x), x) def replacement5345(a, b, c, d, e, m, x): return Int(ExpandIntegrand(a + b*acot(c*x), x**m/(d + e*x**S(2)), x), x) def replacement5346(a, b, c, d, e, n, p, x): return -Dist(b*n/(S(2)*c*(p + S(1))), Int((a + b*ArcTan(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp((a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5347(a, b, c, d, e, n, p, x): return Dist(b*n/(S(2)*c*(p + S(1))), Int((a + b*acot(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp((a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5348(a, b, c, d, e, n, x): return -Dist(S(4)/(b**S(2)*(n + S(1))*(n + S(2))), Int(x*(a + b*ArcTan(c*x))**(n + S(2))/(d + e*x**S(2))**S(2), x), x) - Simp((a + b*ArcTan(c*x))**(n + S(2))*(-c**S(2)*x**S(2) + S(1))/(b**S(2)*e*(d + e*x**S(2))*(n + S(1))*(n + S(2))), x) + Simp(x*(a + b*ArcTan(c*x))**(n + S(1))/(b*c*d*(d + e*x**S(2))*(n + S(1))), x) def replacement5349(a, b, c, d, e, n, x): return -Dist(S(4)/(b**S(2)*(n + S(1))*(n + S(2))), Int(x*(a + b*acot(c*x))**(n + S(2))/(d + e*x**S(2))**S(2), x), x) - Simp((a + b*acot(c*x))**(n + S(2))*(-c**S(2)*x**S(2) + S(1))/(b**S(2)*e*(d + e*x**S(2))*(n + S(1))*(n + S(2))), x) - Simp(x*(a + b*acot(c*x))**(n + S(1))/(b*c*d*(d + e*x**S(2))*(n + S(1))), x) def replacement5350(a, b, c, d, e, p, x): return -Dist(S(1)/(S(2)*c**S(2)*d*(p + S(1))), Int((a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c**S(3)*d*(p + S(1))**S(2)), x) + Simp(x*(a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*c**S(2)*d*(p + S(1))), x) def replacement5351(a, b, c, d, e, p, x): return -Dist(S(1)/(S(2)*c**S(2)*d*(p + S(1))), Int((a + b*acot(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) + Simp(b*(d + e*x**S(2))**(p + S(1))/(S(4)*c**S(3)*d*(p + S(1))**S(2)), x) + Simp(x*(a + b*acot(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*c**S(2)*d*(p + S(1))), x) def replacement5352(a, b, c, d, e, n, x): return Dist(b*n/(S(2)*c), Int(x*(a + b*ArcTan(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) + Simp((a + b*ArcTan(c*x))**(n + S(1))/(S(2)*b*c**S(3)*d**S(2)*(n + S(1))), x) - Simp(x*(a + b*ArcTan(c*x))**n/(S(2)*c**S(2)*d*(d + e*x**S(2))), x) def replacement5353(a, b, c, d, e, n, x): return -Dist(b*n/(S(2)*c), Int(x*(a + b*acot(c*x))**(n + S(-1))/(d + e*x**S(2))**S(2), x), x) - Simp((a + b*acot(c*x))**(n + S(1))/(S(2)*b*c**S(3)*d**S(2)*(n + S(1))), x) - Simp(x*(a + b*acot(c*x))**n/(S(2)*c**S(2)*d*(d + e*x**S(2))), x) def replacement5354(a, b, c, d, e, m, p, x): return Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) + Simp(b*x**m*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) - Simp(x**(m + S(-1))*(a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) def replacement5355(a, b, c, d, e, m, p, x): return Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*acot(c*x))*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(b*x**m*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) - Simp(x**(m + S(-1))*(a + b*acot(c*x))*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) def replacement5356(a, b, c, d, e, m, n, p, x): return -Dist(b**S(2)*n*(n + S(-1))/m**S(2), Int(x**m*(a + b*ArcTan(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) + Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(x**(m + S(-1))*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) + Simp(b*n*x**m*(a + b*ArcTan(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) def replacement5357(a, b, c, d, e, m, n, p, x): return -Dist(b**S(2)*n*(n + S(-1))/m**S(2), Int(x**m*(a + b*acot(c*x))**(n + S(-2))*(d + e*x**S(2))**p, x), x) + Dist((m + S(-1))/(c**S(2)*d*m), Int(x**(m + S(-2))*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Simp(x**(m + S(-1))*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1))/(c**S(2)*d*m), x) - Simp(b*n*x**m*(a + b*acot(c*x))**(n + S(-1))*(d + e*x**S(2))**(p + S(1))/(c*d*m**S(2)), x) def replacement5358(a, b, c, d, e, m, n, p, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*ArcTan(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp(x**m*(a + b*ArcTan(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement5359(a, b, c, d, e, m, n, p, x): return Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*acot(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) - Simp(x**m*(a + b*acot(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement5360(a, b, c, d, e, m, n, p, x): return -Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*ArcTan(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp(x**(m + S(1))*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*(m + S(1))), x) def replacement5361(a, b, c, d, e, m, n, p, x): return Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acot(c*x))**(n + S(-1))*(d + e*x**S(2))**p, x), x) + Simp(x**(m + S(1))*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1))/(d*(m + S(1))), x) def replacement5362(a, b, c, d, e, m, x): return Dist(d/(m + S(2)), Int(x**m*(a + b*ArcTan(c*x))/sqrt(d + e*x**S(2)), x), x) - Dist(b*c*d/(m + S(2)), Int(x**(m + S(1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*ArcTan(c*x))*sqrt(d + e*x**S(2))/(m + S(2)), x) def replacement5363(a, b, c, d, e, m, x): return Dist(d/(m + S(2)), Int(x**m*(a + b*acot(c*x))/sqrt(d + e*x**S(2)), x), x) + Dist(b*c*d/(m + S(2)), Int(x**(m + S(1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*acot(c*x))*sqrt(d + e*x**S(2))/(m + S(2)), x) def replacement5364(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5365(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(x**m*(a + b*acot(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5366(a, b, c, d, e, m, n, p, x): return Dist(d, Int(x**m*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(c**S(2)*d, Int(x**(m + S(2))*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) def replacement5367(a, b, c, d, e, m, n, p, x): return Dist(d, Int(x**m*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) + Dist(c**S(2)*d, Int(x**(m + S(2))*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(-1)), x), x) def replacement5368(a, b, c, d, e, m, n, x): return -Dist((m + S(-1))/(c**S(2)*m), Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n/sqrt(d + e*x**S(2)), x), x) - Dist(b*n/(c*m), Int(x**(m + S(-1))*(a + b*ArcTan(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(-1))*(a + b*ArcTan(c*x))**n*sqrt(d + e*x**S(2))/(c**S(2)*d*m), x) def replacement5369(a, b, c, d, e, m, n, x): return -Dist((m + S(-1))/(c**S(2)*m), Int(x**(m + S(-2))*(a + b*acot(c*x))**n/sqrt(d + e*x**S(2)), x), x) + Dist(b*n/(c*m), Int(x**(m + S(-1))*(a + b*acot(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(-1))*(a + b*acot(c*x))**n*sqrt(d + e*x**S(2))/(c**S(2)*d*m), x) def replacement5370(a, b, c, d, e, x): return Simp(-S(2)*(a + b*ArcTan(c*x))*atanh(sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/sqrt(d), x) + Simp(I*b*PolyLog(S(2), -sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/sqrt(d), x) - Simp(I*b*PolyLog(S(2), sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/sqrt(d), x) def replacement5371(a, b, c, d, e, x): return Simp(-S(2)*(a + b*acot(c*x))*atanh(sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/sqrt(d), x) - Simp(I*b*PolyLog(S(2), -sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/sqrt(d), x) + Simp(I*b*PolyLog(S(2), sqrt(I*c*x + S(1))/sqrt(-I*c*x + S(1)))/sqrt(d), x) def replacement5372(a, b, c, d, e, n, x): return Dist(S(1)/sqrt(d), Subst(Int((a + b*x)**n/sin(x), x), x, ArcTan(c*x)), x) def replacement5373(a, b, c, d, e, n, x): return -Dist(c*x*sqrt(S(1) + S(1)/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n/cos(x), x), x, acot(c*x)), x) def replacement5374(a, b, c, d, e, n, x): return Dist(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*ArcTan(c*x))**n/(x*sqrt(c**S(2)*x**S(2) + S(1))), x), x) def replacement5375(a, b, c, d, e, n, x): return Dist(sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int((a + b*acot(c*x))**n/(x*sqrt(c**S(2)*x**S(2) + S(1))), x), x) def replacement5376(a, b, c, d, e, n, x): return Dist(b*c*n, Int((a + b*ArcTan(c*x))**(n + S(-1))/(x*sqrt(d + e*x**S(2))), x), x) - Simp((a + b*ArcTan(c*x))**n*sqrt(d + e*x**S(2))/(d*x), x) def replacement5377(a, b, c, d, e, n, x): return -Dist(b*c*n, Int((a + b*acot(c*x))**(n + S(-1))/(x*sqrt(d + e*x**S(2))), x), x) - Simp((a + b*acot(c*x))**n*sqrt(d + e*x**S(2))/(d*x), x) def replacement5378(a, b, c, d, e, m, n, x): return -Dist(c**S(2)*(m + S(2))/(m + S(1)), Int(x**(m + S(2))*(a + b*ArcTan(c*x))**n/sqrt(d + e*x**S(2)), x), x) - Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*ArcTan(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*ArcTan(c*x))**n*sqrt(d + e*x**S(2))/(d*(m + S(1))), x) def replacement5379(a, b, c, d, e, m, n, x): return -Dist(c**S(2)*(m + S(2))/(m + S(1)), Int(x**(m + S(2))*(a + b*acot(c*x))**n/sqrt(d + e*x**S(2)), x), x) + Dist(b*c*n/(m + S(1)), Int(x**(m + S(1))*(a + b*acot(c*x))**(n + S(-1))/sqrt(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*acot(c*x))**n*sqrt(d + e*x**S(2))/(d*(m + S(1))), x) def replacement5380(a, b, c, d, e, m, n, p, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5381(a, b, c, d, e, m, n, p, x): return Dist(S(1)/e, Int(x**(m + S(-2))*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(d/e, Int(x**(m + S(-2))*(a + b*acot(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5382(a, b, c, d, e, m, n, p, x): return Dist(S(1)/d, Int(x**m*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5383(a, b, c, d, e, m, n, p, x): return Dist(S(1)/d, Int(x**m*(a + b*acot(c*x))**n*(d + e*x**S(2))**(p + S(1)), x), x) - Dist(e/d, Int(x**(m + S(2))*(a + b*acot(c*x))**n*(d + e*x**S(2))**p, x), x) def replacement5384(a, b, c, d, e, m, n, p, x): return -Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*ArcTan(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) - Dist(c*(m + S(2)*p + S(2))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*ArcTan(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Simp(x**m*(a + b*ArcTan(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement5385(a, b, c, d, e, m, n, p, x): return Dist(m/(b*c*(n + S(1))), Int(x**(m + S(-1))*(a + b*acot(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) + Dist(c*(m + S(2)*p + S(2))/(b*(n + S(1))), Int(x**(m + S(1))*(a + b*acot(c*x))**(n + S(1))*(d + e*x**S(2))**p, x), x) - Simp(x**m*(a + b*acot(c*x))**(n + S(1))*(d + e*x**S(2))**(p + S(1))/(b*c*d*(n + S(1))), x) def replacement5386(a, b, c, d, e, m, n, p, x): return Dist(c**(-m + S(-1))*d**p, Subst(Int((a + b*x)**n*sin(x)**m*cos(x)**(-m - S(2)*p + S(-2)), x), x, ArcTan(c*x)), x) def replacement5387(a, b, c, d, e, m, n, p, x): return Dist(d**(p + S(1)/2)*sqrt(c**S(2)*x**S(2) + S(1))/sqrt(d + e*x**S(2)), Int(x**m*(a + b*ArcTan(c*x))**n*(c**S(2)*x**S(2) + S(1))**p, x), x) def replacement5388(a, b, c, d, e, m, n, p, x): return -Dist(c**(-m + S(-1))*d**p, Subst(Int((a + b*x)**n*sin(x)**(-m - S(2)*p + S(-2))*cos(x)**m, x), x, acot(c*x)), x) def replacement5389(a, b, c, d, e, m, n, p, x): return -Dist(c**(-m)*d**(p + S(1)/2)*x*sqrt((c**S(2)*x**S(2) + S(1))/(c**S(2)*x**S(2)))/sqrt(d + e*x**S(2)), Subst(Int((a + b*x)**n*sin(x)**(-m - S(2)*p + S(-2))*cos(x)**m, x), x, acot(c*x)), x) def replacement5390(a, b, c, d, e, p, x): return -Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*ArcTan(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5391(a, b, c, d, e, p, x): return Dist(b*c/(S(2)*e*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(c**S(2)*x**S(2) + S(1)), x), x) + Simp((a + b*acot(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def With5392(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return -Dist(b*c, Int(SimplifyIntegrand(u/(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*ArcTan(c*x), u, x) def With5393(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return Dist(b*c, Int(SimplifyIntegrand(u/(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acot(c*x), u, x) def replacement5394(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand((a + b*ArcTan(c*x))**n, x**m*(d + e*x**S(2))**p, x), x) def replacement5395(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand((a + b*acot(c*x))**n, x**m*(d + e*x**S(2))**p, x), x) def replacement5396(a, b, c, d, e, m, p, x): return Dist(a, Int(x**m*(d + e*x**S(2))**p, x), x) + Dist(b, Int(x**m*(d + e*x**S(2))**p*ArcTan(c*x), x), x) def replacement5397(a, b, c, d, e, m, p, x): return Dist(a, Int(x**m*(d + e*x**S(2))**p, x), x) + Dist(b, Int(x**m*(d + e*x**S(2))**p*acot(c*x), x), x) def replacement5398(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*ArcTan(c*x))**n*(d + e*x**S(2))**p, x) def replacement5399(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*acot(c*x))**n*(d + e*x**S(2))**p, x) def replacement5400(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*ArcTan(c*x))**n*log(S(1) - u)/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*ArcTan(c*x))**n*log(u + S(1))/(d + e*x**S(2)), x), x) def replacement5401(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*acot(c*x))**n*log(SimplifyIntegrand(S(1) - S(1)/u, x))/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*acot(c*x))**n*log(SimplifyIntegrand(S(1) + S(1)/u, x))/(d + e*x**S(2)), x), x) def replacement5402(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*ArcTan(c*x))**n*log(S(1) - u)/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*ArcTan(c*x))**n*log(u + S(1))/(d + e*x**S(2)), x), x) def replacement5403(a, b, c, d, e, n, u, x): return -Dist(S(1)/2, Int((a + b*acot(c*x))**n*log(SimplifyIntegrand(S(1) - S(1)/u, x))/(d + e*x**S(2)), x), x) + Dist(S(1)/2, Int((a + b*acot(c*x))**n*log(SimplifyIntegrand(S(1) + S(1)/u, x))/(d + e*x**S(2)), x), x) def replacement5404(a, b, c, d, e, n, u, x): return -Dist(I*b*n/S(2), Int((a + b*ArcTan(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) + Simp(I*(a + b*ArcTan(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement5405(a, b, c, d, e, n, u, x): return Dist(I*b*n/S(2), Int((a + b*acot(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) + Simp(I*(a + b*acot(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement5406(a, b, c, d, e, n, u, x): return Dist(I*b*n/S(2), Int((a + b*ArcTan(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) - Simp(I*(a + b*ArcTan(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement5407(a, b, c, d, e, n, u, x): return -Dist(I*b*n/S(2), Int((a + b*acot(c*x))**(n + S(-1))*PolyLog(S(2), Together(S(1) - u))/(d + e*x**S(2)), x), x) - Simp(I*(a + b*acot(c*x))**n*PolyLog(S(2), Together(S(1) - u))/(S(2)*c*d), x) def replacement5408(a, b, c, d, e, n, p, u, x): return Dist(I*b*n/S(2), Int((a + b*ArcTan(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) - Simp(I*(a + b*ArcTan(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement5409(a, b, c, d, e, n, p, u, x): return -Dist(I*b*n/S(2), Int((a + b*acot(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) - Simp(I*(a + b*acot(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement5410(a, b, c, d, e, n, p, u, x): return -Dist(I*b*n/S(2), Int((a + b*ArcTan(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) + Simp(I*(a + b*ArcTan(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement5411(a, b, c, d, e, n, p, u, x): return Dist(I*b*n/S(2), Int((a + b*acot(c*x))**(n + S(-1))*PolyLog(p + S(1), u)/(d + e*x**S(2)), x), x) + Simp(I*(a + b*acot(c*x))**n*PolyLog(p + S(1), u)/(S(2)*c*d), x) def replacement5412(a, b, c, d, e, x): return Simp((log(a + b*ArcTan(c*x)) - log(a + b*acot(c*x)))/(b*c*d*(S(2)*a + b*ArcTan(c*x) + b*acot(c*x))), x) def replacement5413(a, b, c, d, e, m, n, x): return Dist(n/(m + S(1)), Int((a + b*ArcTan(c*x))**(n + S(-1))*(a + b*acot(c*x))**(m + S(1))/(d + e*x**S(2)), x), x) - Simp((a + b*ArcTan(c*x))**n*(a + b*acot(c*x))**(m + S(1))/(b*c*d*(m + S(1))), x) def replacement5414(a, b, c, d, e, m, n, x): return Dist(n/(m + S(1)), Int((a + b*ArcTan(c*x))**(m + S(1))*(a + b*acot(c*x))**(n + S(-1))/(d + e*x**S(2)), x), x) + Simp((a + b*ArcTan(c*x))**(m + S(1))*(a + b*acot(c*x))**n/(b*c*d*(m + S(1))), x) def replacement5415(a, c, d, n, x): return Dist(I/S(2), Int(log(-I*a*x + S(1))/(c + d*x**n), x), x) - Dist(I/S(2), Int(log(I*a*x + S(1))/(c + d*x**n), x), x) def replacement5416(a, c, d, n, x): return Dist(I/S(2), Int(log(S(1) - I/(a*x))/(c + d*x**n), x), x) - Dist(I/S(2), Int(log(S(1) + I/(a*x))/(c + d*x**n), x), x) def replacement5417(a, b, c, d, e, f, g, x): return -Dist(b*c, Int(x*(d + e*log(f + g*x**S(2)))/(c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g, Int(x**S(2)*(a + b*ArcTan(c*x))/(f + g*x**S(2)), x), x) + Simp(x*(a + b*ArcTan(c*x))*(d + e*log(f + g*x**S(2))), x) def replacement5418(a, b, c, d, e, f, g, x): return Dist(b*c, Int(x*(d + e*log(f + g*x**S(2)))/(c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g, Int(x**S(2)*(a + b*acot(c*x))/(f + g*x**S(2)), x), x) + Simp(x*(a + b*acot(c*x))*(d + e*log(f + g*x**S(2))), x) def replacement5419(a, b, c, d, e, f, g, m, x): return -Dist(b*c/(m + S(1)), Int(x**(m + S(1))*(d + e*log(f + g*x**S(2)))/(c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g/(m + S(1)), Int(x**(m + S(2))*(a + b*ArcTan(c*x))/(f + g*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*ArcTan(c*x))*(d + e*log(f + g*x**S(2)))/(m + S(1)), x) def replacement5420(a, b, c, d, e, f, g, m, x): return Dist(b*c/(m + S(1)), Int(x**(m + S(1))*(d + e*log(f + g*x**S(2)))/(c**S(2)*x**S(2) + S(1)), x), x) - Dist(S(2)*e*g/(m + S(1)), Int(x**(m + S(2))*(a + b*acot(c*x))/(f + g*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*acot(c*x))*(d + e*log(f + g*x**S(2)))/(m + S(1)), x) def With5421(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(d + e*log(f + g*x**S(2))), x) return -Dist(b*c, Int(ExpandIntegrand(u/(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*ArcTan(c*x), u, x) def With5422(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(d + e*log(f + g*x**S(2))), x) return Dist(b*c, Int(ExpandIntegrand(u/(c**S(2)*x**S(2) + S(1)), x), x), x) + Dist(a + b*acot(c*x), u, x) def With5423(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(a + b*ArcTan(c*x)), x) return -Dist(S(2)*e*g, Int(ExpandIntegrand(u*x/(f + g*x**S(2)), x), x), x) + Dist(d + e*log(f + g*x**S(2)), u, x) def With5424(a, b, c, d, e, f, g, m, x): u = IntHide(x**m*(a + b*acot(c*x)), x) return -Dist(S(2)*e*g, Int(ExpandIntegrand(u*x/(f + g*x**S(2)), x), x), x) + Dist(d + e*log(f + g*x**S(2)), u, x) def replacement5425(a, b, c, d, e, f, g, x): return -Dist(b/c, Int((a + b*ArcTan(c*x))*(d + e*log(f + g*x**S(2))), x), x) + Dist(b*c*e, Int(x**S(2)*(a + b*ArcTan(c*x))/(c**S(2)*x**S(2) + S(1)), x), x) - Simp(e*x**S(2)*(a + b*ArcTan(c*x))**S(2)/S(2), x) + Simp((a + b*ArcTan(c*x))**S(2)*(d + e*log(f + g*x**S(2)))*(f + g*x**S(2))/(S(2)*g), x) def replacement5426(a, b, c, d, e, f, g, x): return Dist(b/c, Int((a + b*acot(c*x))*(d + e*log(f + g*x**S(2))), x), x) - Dist(b*c*e, Int(x**S(2)*(a + b*acot(c*x))/(c**S(2)*x**S(2) + S(1)), x), x) - Simp(e*x**S(2)*(a + b*acot(c*x))**S(2)/S(2), x) + Simp((a + b*acot(c*x))**S(2)*(d + e*log(f + g*x**S(2)))*(f + g*x**S(2))/(S(2)*g), x) def replacement5427(a, n, x): return Int((-I*a*x + S(1))**(I*n/S(2) + S(1)/2)*(I*a*x + S(1))**(-I*n/S(2) + S(1)/2)/sqrt(a**S(2)*x**S(2) + S(1)), x) def replacement5428(a, m, n, x): return Int(x**m*(-I*a*x + S(1))**(I*n/S(2) + S(1)/2)*(I*a*x + S(1))**(-I*n/S(2) + S(1)/2)/sqrt(a**S(2)*x**S(2) + S(1)), x) def replacement5429(a, n, x): return Int((-I*a*x + S(1))**(I*n/S(2))*(I*a*x + S(1))**(-I*n/S(2)), x) def replacement5430(a, m, n, x): return Int(x**m*(-I*a*x + S(1))**(I*n/S(2))*(I*a*x + S(1))**(-I*n/S(2)), x) def replacement5431(a, c, d, n, p, u, x): return Dist(c**p, Int(u*(S(1) + d*x/c)**p*(-I*a*x + S(1))**(I*n/S(2))*(I*a*x + S(1))**(-I*n/S(2)), x), x) def replacement5432(a, c, d, n, p, u, x): return Int(u*(c + d*x)**p*(-I*a*x + S(1))**(I*n/S(2))*(I*a*x + S(1))**(-I*n/S(2)), x) def replacement5433(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**(-p)*(c*x/d + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5434(a, c, d, n, p, u, x): return Dist((S(-1))**(n/S(2))*c**p, Int(u*(S(1) - I/(a*x))**(-I*n/S(2))*(S(1) + I/(a*x))**(I*n/S(2))*(S(1) + d/(c*x))**p, x), x) def replacement5435(a, c, d, n, p, u, x): return Int(u*(c + d/x)**p*(-I*a*x + S(1))**(I*n/S(2))*(I*a*x + S(1))**(-I*n/S(2)), x) def replacement5436(a, c, d, n, p, u, x): return Dist(x**p*(c + d/x)**p*(c*x/d + S(1))**(-p), Int(u*x**(-p)*(c*x/d + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5437(a, c, d, n, x): return Simp((a*x + n)*exp(n*ArcTan(a*x))/(a*c*sqrt(c + d*x**S(2))*(n**S(2) + S(1))), x) def replacement5438(a, c, d, n, p, x): return Dist(S(2)*(p + S(1))*(S(2)*p + S(3))/(c*(n**S(2) + S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*ArcTan(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*(-S(2)*a*x*(p + S(1)) + n)*exp(n*ArcTan(a*x))/(a*c*(n**S(2) + S(4)*(p + S(1))**S(2))), x) def replacement5439(a, c, d, n, x): return Simp(exp(n*ArcTan(a*x))/(a*c*n), x) def replacement5440(a, c, d, n, p, x): return Dist(c**p, Int((a**S(2)*x**S(2) + S(1))**(-I*n/S(2) + p)*(-I*a*x + S(1))**(I*n), x), x) def replacement5441(a, c, d, n, p, x): return Dist(c**p, Int((-I*a*x + S(1))**(I*n/S(2) + p)*(I*a*x + S(1))**(-I*n/S(2) + p), x), x) def replacement5442(a, c, d, n, p, x): return Dist(c**(I*n/S(2)), Int((c + d*x**S(2))**(-I*n/S(2) + p)*(-I*a*x + S(1))**(I*n), x), x) def replacement5443(a, c, d, n, p, x): return Dist(c**(-I*n/S(2)), Int((c + d*x**S(2))**(I*n/S(2) + p)*(I*a*x + S(1))**(-I*n), x), x) def replacement5444(a, c, d, n, p, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(a**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int((a**S(2)*x**S(2) + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5445(a, c, d, n, x): return -Simp((-a*n*x + S(1))*exp(n*ArcTan(a*x))/(d*sqrt(c + d*x**S(2))*(n**S(2) + S(1))), x) def replacement5446(a, c, d, n, p, x): return -Dist(a*c*n/(S(2)*d*(p + S(1))), Int((c + d*x**S(2))**p*exp(n*ArcTan(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*exp(n*ArcTan(a*x))/(S(2)*d*(p + S(1))), x) def replacement5447(a, c, d, n, p, x): return -Simp((c + d*x**S(2))**(p + S(1))*(-a*n*x + S(1))*exp(n*ArcTan(a*x))/(a*d*n*(n**S(2) + S(1))), x) def replacement5448(a, c, d, n, p, x): return Dist((n**S(2) - S(2)*p + S(-2))/(d*(n**S(2) + S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*ArcTan(a*x)), x), x) - Simp((c + d*x**S(2))**(p + S(1))*(-S(2)*a*x*(p + S(1)) + n)*exp(n*ArcTan(a*x))/(a*d*(n**S(2) + S(4)*(p + S(1))**S(2))), x) def replacement5449(a, c, d, m, n, p, x): return Dist(c**p, Int(x**m*(a**S(2)*x**S(2) + S(1))**(-I*n/S(2) + p)*(-I*a*x + S(1))**(I*n), x), x) def replacement5450(a, c, d, m, n, p, x): return Dist(c**p, Int(x**m*(-I*a*x + S(1))**(I*n/S(2) + p)*(I*a*x + S(1))**(-I*n/S(2) + p), x), x) def replacement5451(a, c, d, m, n, p, x): return Dist(c**(I*n/S(2)), Int(x**m*(c + d*x**S(2))**(-I*n/S(2) + p)*(-I*a*x + S(1))**(I*n), x), x) def replacement5452(a, c, d, m, n, p, x): return Dist(c**(-I*n/S(2)), Int(x**m*(c + d*x**S(2))**(I*n/S(2) + p)*(I*a*x + S(1))**(-I*n), x), x) def replacement5453(a, c, d, m, n, p, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(a**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int(x**m*(a**S(2)*x**S(2) + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5454(a, c, d, n, p, u, x): return Dist(c**p, Int(u*(-I*a*x + S(1))**(I*n/S(2) + p)*(I*a*x + S(1))**(-I*n/S(2) + p), x), x) def replacement5455(a, c, d, n, p, u, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(-I*a*x + S(1))**(-FracPart(p))*(I*a*x + S(1))**(-FracPart(p)), Int(u*(-I*a*x + S(1))**(I*n/S(2) + p)*(I*a*x + S(1))**(-I*n/S(2) + p), x), x) def replacement5456(a, c, d, n, p, u, x): return Dist(c**IntPart(p)*(c + d*x**S(2))**FracPart(p)*(a**S(2)*x**S(2) + S(1))**(-FracPart(p)), Int(u*(a**S(2)*x**S(2) + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5457(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**(-S(2)*p)*(a**S(2)*x**S(2) + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5458(a, c, d, n, p, u, x): return Dist(c**p, Int(u*(S(1) - I/(a*x))**p*(S(1) + I/(a*x))**p*exp(n*ArcTan(a*x)), x), x) def replacement5459(a, c, d, n, p, u, x): return Dist(x**(S(2)*p)*(c + d/x**S(2))**p*(-I*a*x + S(1))**(-p)*(I*a*x + S(1))**(-p), Int(u*x**(-S(2)*p)*(-I*a*x + S(1))**p*(I*a*x + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5460(a, c, d, n, p, u, x): return Dist(x**(S(2)*p)*(c + d/x**S(2))**p*(a**S(2)*x**S(2) + S(1))**(-p), Int(u*x**(-S(2)*p)*(a**S(2)*x**S(2) + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5461(a, b, c, n, x): return Int((-I*a*c - I*b*c*x + S(1))**(I*n/S(2))*(I*a*c + I*b*c*x + S(1))**(-I*n/S(2)), x) def replacement5462(a, b, c, m, n, x): return Dist(S(4)*I**(-m)*b**(-m + S(-1))*c**(-m + S(-1))/n, Subst(Int(x**(-S(2)*I/n)*(S(1) + x**(-S(2)*I/n))**(-m + S(-2))*(-I*a*c + S(1) - x**(-S(2)*I/n)*(I*a*c + S(1)))**m, x), x, (-I*c*(a + b*x) + S(1))**(I*n/S(2))*(I*c*(a + b*x) + S(1))**(-I*n/S(2))), x) def replacement5463(a, b, c, d, e, m, n, x): return Int((d + e*x)**m*(-I*a*c - I*b*c*x + S(1))**(I*n/S(2))*(I*a*c + I*b*c*x + S(1))**(-I*n/S(2)), x) def replacement5464(a, b, c, d, e, n, p, u, x): return Dist((c/(a**S(2) + S(1)))**p, Int(u*(-I*a - I*b*x + S(1))**(I*n/S(2) + p)*(I*a + I*b*x + S(1))**(-I*n/S(2) + p), x), x) def replacement5465(a, b, c, d, e, n, p, u, x): return Dist((c + d*x + e*x**S(2))**p*(a**S(2) + S(2)*a*b*x + b**S(2)*x**S(2) + S(1))**(-p), Int(u*(a**S(2) + S(2)*a*b*x + b**S(2)*x**S(2) + S(1))**p*exp(n*ArcTan(a*x)), x), x) def replacement5466(a, b, c, n, u, x): return Int(u*exp(n*acot(a/c + b*x/c)), x) def replacement5467(a, n, u, x): return Dist((S(-1))**(I*n/S(2)), Int(u*exp(-n*ArcTan(a*x)), x), x) def replacement5468(a, n, x): return -Subst(Int((S(1) - I*x/a)**(I*n/S(2) + S(1)/2)*(S(1) + I*x/a)**(-I*n/S(2) + S(1)/2)/(x**S(2)*sqrt(S(1) + x**S(2)/a**S(2))), x), x, S(1)/x) def replacement5469(a, m, n, x): return -Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(I*n/S(2) + S(1)/2)*(S(1) + I*x/a)**(-I*n/S(2) + S(1)/2)/sqrt(S(1) + x**S(2)/a**S(2)), x), x, S(1)/x) def replacement5470(a, n, x): return -Subst(Int((S(1) - I*x/a)**(I*n/S(2))*(S(1) + I*x/a)**(-I*n/S(2))/x**S(2), x), x, S(1)/x) def replacement5471(a, m, n, x): return -Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(n/S(2))*(S(1) + I*x/a)**(-n/S(2)), x), x, S(1)/x) def replacement5472(a, m, n, x): return -Dist(x**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(I*n/S(2) + S(1)/2)*(S(1) + I*x/a)**(-I*n/S(2) + S(1)/2)/sqrt(S(1) + x**S(2)/a**S(2)), x), x, S(1)/x), x) def replacement5473(a, m, n, x): return -Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(n/S(2))*(S(1) + I*x/a)**(-n/S(2)), x), x, S(1)/x) def replacement5474(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**p*(c/(d*x) + S(1))**p*exp(n*acot(a*x)), x), x) def replacement5475(a, c, d, n, p, u, x): return Dist(x**(-p)*(c + d*x)**p*(c/(d*x) + S(1))**(-p), Int(u*x**p*(c/(d*x) + S(1))**p*exp(n*acot(a*x)), x), x) def replacement5476(a, c, d, n, p, x): return -Dist(c**p, Subst(Int((S(1) - I*x/a)**(I*n/S(2))*(S(1) + I*x/a)**(-I*n/S(2))*(S(1) + d*x/c)**p/x**S(2), x), x, S(1)/x), x) def replacement5477(a, c, d, m, n, p, x): return -Dist(c**p, Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(I*n/S(2))*(S(1) + I*x/a)**(-I*n/S(2))*(S(1) + d*x/c)**p, x), x, S(1)/x), x) def replacement5478(a, c, d, n, p, x): return Dist((S(1) + d/(c*x))**(-p)*(c + d/x)**p, Int((S(1) + d/(c*x))**p*exp(n*acot(a*x)), x), x) def replacement5479(a, c, d, m, n, p, x): return -Dist(c**p*x**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(I*n/S(2))*(S(1) + I*x/a)**(-I*n/S(2))*(S(1) + d*x/c)**p, x), x, S(1)/x), x) def replacement5480(a, c, d, n, p, u, x): return Dist((S(1) + d/(c*x))**(-p)*(c + d/x)**p, Int(u*(S(1) + d/(c*x))**p*exp(n*acot(a*x)), x), x) def replacement5481(a, c, d, n, x): return -Simp(exp(n*acot(a*x))/(a*c*n), x) def replacement5482(a, c, d, n, x): return -Simp((-a*x + n)*exp(n*acot(a*x))/(a*c*sqrt(c + d*x**S(2))*(n**S(2) + S(1))), x) def replacement5483(a, c, d, n, p, x): return Dist(S(2)*(p + S(1))*(S(2)*p + S(3))/(c*(n**S(2) + S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*acot(a*x)), x), x) - Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*acot(a*x))/(a*c*(n**S(2) + S(4)*(p + S(1))**S(2))), x) def replacement5484(a, c, d, n, x): return -Simp((a*n*x + S(1))*exp(n*acot(a*x))/(a**S(2)*c*sqrt(c + d*x**S(2))*(n**S(2) + S(1))), x) def replacement5485(a, c, d, n, p, x): return Dist(n*(S(2)*p + S(3))/(a*c*(n**S(2) + S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*acot(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*(-a*n*x + S(2)*p + S(2))*exp(n*acot(a*x))/(a**S(2)*c*(n**S(2) + S(4)*(p + S(1))**S(2))), x) def replacement5486(a, c, d, n, p, x): return Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*acot(a*x))/(a**S(3)*c*n**S(2)*(n**S(2) + S(1))), x) def replacement5487(a, c, d, n, p, x): return Dist((n**S(2) - S(2)*p + S(-2))/(a**S(2)*c*(n**S(2) + S(4)*(p + S(1))**S(2))), Int((c + d*x**S(2))**(p + S(1))*exp(n*acot(a*x)), x), x) + Simp((c + d*x**S(2))**(p + S(1))*(S(2)*a*x*(p + S(1)) + n)*exp(n*acot(a*x))/(a**S(3)*c*(n**S(2) + S(4)*(p + S(1))**S(2))), x) def replacement5488(a, c, d, m, n, p, x): return -Dist(a**(-m + S(-1))*c**p, Subst(Int((S(1)/tan(x))**(m + S(2)*p + S(2))*exp(n*x)*cos(x)**(-S(2)*p + S(-2)), x), x, acot(a*x)), x) def replacement5489(a, c, d, n, p, u, x): return Dist(d**p, Int(u*x**(S(2)*p)*(S(1) + S(1)/(a**S(2)*x**S(2)))**p*exp(n*acot(a*x)), x), x) def replacement5490(a, c, d, n, p, u, x): return Dist(x**(-S(2)*p)*(S(1) + S(1)/(a**S(2)*x**S(2)))**(-p)*(c + d*x**S(2))**p, Int(u*x**(S(2)*p)*(S(1) + S(1)/(a**S(2)*x**S(2)))**p*exp(n*acot(a*x)), x), x) def replacement5491(a, c, d, n, p, u, x): return Dist(c**p*(I*a)**(-S(2)*p), Int(u*x**(-S(2)*p)*(I*a*x + S(-1))**(-I*n/S(2) + p)*(I*a*x + S(1))**(I*n/S(2) + p), x), x) def replacement5492(a, c, d, n, p, x): return -Dist(c**p, Subst(Int((S(1) - I*x/a)**(I*n/S(2) + p)*(S(1) + I*x/a)**(-I*n/S(2) + p)/x**S(2), x), x, S(1)/x), x) def replacement5493(a, c, d, m, n, p, x): return -Dist(c**p, Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(I*n/S(2) + p)*(S(1) + I*x/a)**(-I*n/S(2) + p), x), x, S(1)/x), x) def replacement5494(a, c, d, m, n, p, x): return -Dist(c**p*x**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(S(1) - I*x/a)**(I*n/S(2) + p)*(S(1) + I*x/a)**(-I*n/S(2) + p), x), x, S(1)/x), x) def replacement5495(a, c, d, n, p, u, x): return Dist((S(1) + S(1)/(a**S(2)*x**S(2)))**(-p)*(c + d/x**S(2))**p, Int(u*(S(1) + S(1)/(a**S(2)*x**S(2)))**p*exp(n*acot(a*x)), x), x) def replacement5496(a, b, c, n, u, x): return Dist((S(-1))**(I*n/S(2)), Int(u*exp(-n*ArcTan(c*(a + b*x))), x), x) def replacement5497(a, b, c, n, x): return Dist((I*c*(a + b*x))**(I*n/S(2))*(S(1) - I/(c*(a + b*x)))**(I*n/S(2))*(I*a*c + I*b*c*x + S(1))**(-I*n/S(2)), Int((I*a*c + I*b*c*x + S(-1))**(-I*n/S(2))*(I*a*c + I*b*c*x + S(1))**(I*n/S(2)), x), x) def replacement5498(a, b, c, m, n, x): return Dist(S(4)*I**(-m)*b**(-m + S(-1))*c**(-m + S(-1))/n, Subst(Int(x**(-S(2)*I/n)*(S(-1) + x**(-S(2)*I/n))**(-m + S(-2))*(I*a*c + S(1) + x**(-S(2)*I/n)*(-I*a*c + S(1)))**m, x), x, (S(1) - I/(c*(a + b*x)))**(I*n/S(2))*(S(1) + I/(c*(a + b*x)))**(-I*n/S(2))), x) def replacement5499(a, b, c, d, e, m, n, x): return Dist((I*c*(a + b*x))**(I*n/S(2))*(S(1) - I/(c*(a + b*x)))**(I*n/S(2))*(I*a*c + I*b*c*x + S(1))**(-I*n/S(2)), Int((d + e*x)**m*(I*a*c + I*b*c*x + S(-1))**(-I*n/S(2))*(I*a*c + I*b*c*x + S(1))**(I*n/S(2)), x), x) def replacement5500(a, b, c, d, e, n, p, u, x): return Dist((c/(a**S(2) + S(1)))**p*((I*a + I*b*x + S(1))/(I*a + I*b*x))**(I*n/S(2))*((I*a + I*b*x)/(I*a + I*b*x + S(1)))**(I*n/S(2))*(-I*a - I*b*x + S(1))**(I*n/S(2))*(I*a + I*b*x + S(-1))**(-I*n/S(2)), Int(u*(-I*a - I*b*x + S(1))**(-I*n/S(2) + p)*(I*a + I*b*x + S(1))**(I*n/S(2) + p), x), x) def replacement5501(a, b, c, d, e, n, p, u, x): return Dist((c + d*x + e*x**S(2))**p*(a**S(2) + S(2)*a*b*x + b**S(2)*x**S(2) + S(1))**(-p), Int(u*(a**S(2) + S(2)*a*b*x + b**S(2)*x**S(2) + S(1))**p*exp(n*acot(a*x)), x), x) def replacement5502(a, b, c, n, u, x): return Int(u*exp(n*ArcTan(a/c + b*x/c)), x) def replacement5503(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*ArcTan(x))**n, x), x, c + d*x), x) def replacement5504(a, b, c, d, n, x): return Dist(S(1)/d, Subst(Int((a + b*acot(x))**n, x), x, c + d*x), x) def replacement5505(a, b, c, d, n, x): return Int((a + b*ArcTan(c + d*x))**n, x) def replacement5506(a, b, c, d, n, x): return Int((a + b*acot(c + d*x))**n, x) def replacement5507(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*ArcTan(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5508(a, b, c, d, e, f, m, n, x): return Dist(S(1)/d, Subst(Int((a + b*acot(x))**n*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5509(a, b, c, d, e, f, m, n, x): return Int((a + b*ArcTan(c + d*x))**n*(e + f*x)**m, x) def replacement5510(a, b, c, d, e, f, m, n, x): return Int((a + b*acot(c + d*x))**n*(e + f*x)**m, x) def replacement5511(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*ArcTan(x))**n*(C*x**S(2)/d**S(2) + C/d**S(2))**p, x), x, c + d*x), x) def replacement5512(A, B, C, a, b, c, d, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acot(x))**n*(C*x**S(2)/d**S(2) + C/d**S(2))**p, x), x, c + d*x), x) def replacement5513(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*ArcTan(x))**n*(C*x**S(2)/d**S(2) + C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5514(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/d, Subst(Int((a + b*acot(x))**n*(C*x**S(2)/d**S(2) + C/d**S(2))**p*(f*x/d + (-c*f + d*e)/d)**m, x), x, c + d*x), x) def replacement5515(a, b, c, d, n, x): return Dist(I/S(2), Int(log(-I*a - I*b*x + S(1))/(c + d*x**n), x), x) - Dist(I/S(2), Int(log(I*a + I*b*x + S(1))/(c + d*x**n), x), x) def replacement5516(a, b, c, d, n, x): return Dist(I/S(2), Int(log((a + b*x - I)/(a + b*x))/(c + d*x**n), x), x) - Dist(I/S(2), Int(log((a + b*x + I)/(a + b*x))/(c + d*x**n), x), x) def replacement5517(a, b, c, d, n, x): return Int(ArcTan(a + b*x)/(c + d*x**n), x) def replacement5518(a, b, c, d, n, x): return Int(acot(a + b*x)/(c + d*x**n), x) def replacement5519(a, b, n, x): return -Dist(b*n, Int(x**n/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x*ArcTan(a + b*x**n), x) def replacement5520(a, b, n, x): return Dist(b*n, Int(x**n/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x*acot(a + b*x**n), x) def replacement5521(a, b, n, x): return Dist(I/S(2), Int(log(-I*a - I*b*x**n + S(1))/x, x), x) - Dist(I/S(2), Int(log(I*a + I*b*x**n + S(1))/x, x), x) def replacement5522(a, b, n, x): return Dist(I/S(2), Int(log(S(1) - I/(a + b*x**n))/x, x), x) - Dist(I/S(2), Int(log(S(1) + I/(a + b*x**n))/x, x), x) def replacement5523(a, b, m, n, x): return -Dist(b*n/(m + S(1)), Int(x**(m + n)/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x**(m + S(1))*ArcTan(a + b*x**n)/(m + S(1)), x) def replacement5524(a, b, m, n, x): return Dist(b*n/(m + S(1)), Int(x**(m + n)/(a**S(2) + S(2)*a*b*x**n + b**S(2)*x**(S(2)*n) + S(1)), x), x) + Simp(x**(m + S(1))*acot(a + b*x**n)/(m + S(1)), x) def replacement5525(a, b, c, d, f, x): return Dist(I/S(2), Int(log(-I*a - I*b*f**(c + d*x) + S(1)), x), x) - Dist(I/S(2), Int(log(I*a + I*b*f**(c + d*x) + S(1)), x), x) def replacement5526(a, b, c, d, f, x): return Dist(I/S(2), Int(log(S(1) - I/(a + b*f**(c + d*x))), x), x) - Dist(I/S(2), Int(log(S(1) + I/(a + b*f**(c + d*x))), x), x) def replacement5527(a, b, c, d, f, m, x): return Dist(I/S(2), Int(x**m*log(-I*a - I*b*f**(c + d*x) + S(1)), x), x) - Dist(I/S(2), Int(x**m*log(I*a + I*b*f**(c + d*x) + S(1)), x), x) def replacement5528(a, b, c, d, f, m, x): return Dist(I/S(2), Int(x**m*log(S(1) - I/(a + b*f**(c + d*x))), x), x) - Dist(I/S(2), Int(x**m*log(S(1) + I/(a + b*f**(c + d*x))), x), x) def replacement5529(a, b, c, m, n, u, x): return Int(u*acot(a/c + b*x**n/c)**m, x) def replacement5530(a, b, c, m, n, u, x): return Int(u*ArcTan(a/c + b*x**n/c)**m, x) def replacement5531(a, b, c, x): return Simp(log(ArcTan(c*x/sqrt(a + b*x**S(2))))/c, x) def replacement5532(a, b, c, x): return -Simp(log(acot(c*x/sqrt(a + b*x**S(2))))/c, x) def replacement5533(a, b, c, m, x): return Simp(ArcTan(c*x/sqrt(a + b*x**S(2)))**(m + S(1))/(c*(m + S(1))), x) def replacement5534(a, b, c, m, x): return -Simp(acot(c*x/sqrt(a + b*x**S(2)))**(m + S(1))/(c*(m + S(1))), x) def replacement5535(a, b, c, d, e, m, x): return Dist(sqrt(a + b*x**S(2))/sqrt(d + e*x**S(2)), Int(ArcTan(c*x/sqrt(a + b*x**S(2)))**m/sqrt(a + b*x**S(2)), x), x) def replacement5536(a, b, c, d, e, m, x): return Dist(sqrt(a + b*x**S(2))/sqrt(d + e*x**S(2)), Int(acot(c*x/sqrt(a + b*x**S(2)))**m/sqrt(a + b*x**S(2)), x), x) def replacement5537(s, u, v, w, x): return Dist(S(1)/2, Int(u*ArcTan(v), x), x) + Dist(Pi*s/S(4), Int(u, x), x) def replacement5538(s, u, v, w, x): return -Dist(S(1)/2, Int(u*ArcTan(v), x), x) + Dist(Pi*s/S(4), Int(u, x), x) def With5539(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: tmp = InverseFunctionOfLinear(u, x) res = And(Not(FalseQ(tmp)), SameQ(Head(tmp), ArcTan), ZeroQ(D(v, x)**S(2) + Discriminant(v, x)*Part(tmp, S(1))**S(2))) except (TypeError, AttributeError): return False if res: return True return False def replacement5539(n, u, v, x): tmp = InverseFunctionOfLinear(u, x) return Dist((-Discriminant(v, x)/(S(4)*Coefficient(v, x, S(2))))**n/Coefficient(Part(tmp, S(1)), x, S(1)), Subst(Int(SimplifyIntegrand((S(1)/cos(x))**(S(2)*n + S(2))*SubstForInverseFunction(u, tmp, x), x), x), x, tmp), x) def With5540(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: tmp = InverseFunctionOfLinear(u, x) res = And(Not(FalseQ(tmp)), SameQ(Head(tmp), ArcCot), ZeroQ(D(v, x)**S(2) + Discriminant(v, x)*Part(tmp, S(1))**S(2))) except (TypeError, AttributeError): return False if res: return True return False def replacement5540(n, u, v, x): tmp = InverseFunctionOfLinear(u, x) return -Dist((-Discriminant(v, x)/(S(4)*Coefficient(v, x, S(2))))**n/Coefficient(Part(tmp, S(1)), x, S(1)), Subst(Int(SimplifyIntegrand((S(1)/sin(x))**(S(2)*n + S(2))*SubstForInverseFunction(u, tmp, x), x), x), x, tmp), x) def replacement5541(a, b, c, d, x): return -Dist(I*b, Int(x/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp(x*ArcTan(c + d*tan(a + b*x)), x) def replacement5542(a, b, c, d, x): return Dist(I*b, Int(x/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp(x*acot(c + d*tan(a + b*x)), x) def replacement5543(a, b, c, d, x): return -Dist(I*b, Int(x/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp(x*ArcTan(c + d/tan(a + b*x)), x) def replacement5544(a, b, c, d, x): return Dist(I*b, Int(x/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp(x*acot(c + d/tan(a + b*x)), x) def replacement5545(a, b, c, d, x): return Dist(b*(-I*c - d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c + d + (-I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(b*(I*c + d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(I*c - d + (I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*ArcTan(c + d*tan(a + b*x)), x) def replacement5546(a, b, c, d, x): return -Dist(b*(-I*c - d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c + d + (-I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(b*(I*c + d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(I*c - d + (I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*acot(c + d*tan(a + b*x)), x) def replacement5547(a, b, c, d, x): return -Dist(b*(-I*c + d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c - d - (-I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(b*(I*c - d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(I*c + d - (I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*ArcTan(c + d/tan(a + b*x)), x) def replacement5548(a, b, c, d, x): return Dist(b*(-I*c + d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c - d - (-I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(b*(I*c - d + S(1)), Int(x*exp(S(2)*I*a + S(2)*I*b*x)/(I*c + d - (I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp(x*acot(c + d/tan(a + b*x)), x) def replacement5549(a, b, c, d, e, f, m, x): return -Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement5550(a, b, c, d, e, f, m, x): return Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*I*a + S(2)*I*b*x) + c + I*d), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement5551(a, b, c, d, e, f, m, x): return -Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement5552(a, b, c, d, e, f, m, x): return Dist(I*b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*I*a + S(2)*I*b*x) + c - I*d), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement5553(a, b, c, d, e, f, m, x): return Dist(b*(-I*c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c + d + (-I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(b*(I*c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(I*c - d + (I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement5554(a, b, c, d, e, f, m, x): return -Dist(b*(-I*c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c + d + (-I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(b*(I*c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(I*c - d + (I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d*tan(a + b*x))/(f*(m + S(1))), x) def replacement5555(a, b, c, d, e, f, m, x): return -Dist(b*(-I*c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c - d - (-I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Dist(b*(I*c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(I*c + d - (I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement5556(a, b, c, d, e, f, m, x): return Dist(b*(-I*c + d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(-I*c - d - (-I*c + d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) - Dist(b*(I*c - d + S(1))/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*I*a + S(2)*I*b*x)/(I*c + d - (I*c - d + S(1))*exp(S(2)*I*a + S(2)*I*b*x) + S(1)), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d/tan(a + b*x))/(f*(m + S(1))), x) def replacement5557(a, b, x): return -Dist(b, Int(x/cosh(S(2)*a + S(2)*b*x), x), x) + Simp(x*ArcTan(tanh(a + b*x)), x) def replacement5558(a, b, x): return Dist(b, Int(x/cosh(S(2)*a + S(2)*b*x), x), x) + Simp(x*acot(tanh(a + b*x)), x) def replacement5559(a, b, x): return Dist(b, Int(x/cosh(S(2)*a + S(2)*b*x), x), x) + Simp(x*ArcTan(S(1)/tanh(a + b*x)), x) def replacement5560(a, b, x): return -Dist(b, Int(x/cosh(S(2)*a + S(2)*b*x), x), x) + Simp(x*acot(S(1)/tanh(a + b*x)), x) def replacement5561(a, b, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cosh(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(tanh(a + b*x))/(f*(m + S(1))), x) def replacement5562(a, b, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cosh(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*acot(tanh(a + b*x))/(f*(m + S(1))), x) def replacement5563(a, b, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cosh(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(S(1)/tanh(a + b*x))/(f*(m + S(1))), x) def replacement5564(a, b, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/cosh(S(2)*a + S(2)*b*x), x), x) + Simp((e + f*x)**(m + S(1))*acot(S(1)/tanh(a + b*x))/(f*(m + S(1))), x) def replacement5565(a, b, c, d, x): return -Dist(b, Int(x/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*ArcTan(c + d*tanh(a + b*x)), x) def replacement5566(a, b, c, d, x): return Dist(b, Int(x/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*acot(c + d*tanh(a + b*x)), x) def replacement5567(a, b, c, d, x): return -Dist(b, Int(x/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*ArcTan(c + d/tanh(a + b*x)), x) def replacement5568(a, b, c, d, x): return Dist(b, Int(x/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp(x*acot(c + d/tanh(a + b*x)), x) def replacement5569(a, b, c, d, x): return Dist(I*b*(-c - d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) - Dist(I*b*(c + d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp(x*ArcTan(c + d*tanh(a + b*x)), x) def replacement5570(a, b, c, d, x): return -Dist(I*b*(-c - d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Dist(I*b*(c + d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp(x*acot(c + d*tanh(a + b*x)), x) def replacement5571(a, b, c, d, x): return -Dist(I*b*(-c - d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Dist(I*b*(c + d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp(x*ArcTan(c + d/tanh(a + b*x)), x) def replacement5572(a, b, c, d, x): return Dist(I*b*(-c - d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) - Dist(I*b*(c + d + I), Int(x*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp(x*acot(c + d/tanh(a + b*x)), x) def replacement5573(a, b, c, d, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement5574(a, b, c, d, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement5575(a, b, c, d, e, f, m, x): return -Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement5576(a, b, c, d, e, f, m, x): return Dist(b/(f*(m + S(1))), Int((e + f*x)**(m + S(1))/(-c*exp(S(2)*a + S(2)*b*x) + c - d), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement5577(a, b, c, d, e, f, m, x): return Dist(I*b*(-c - d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) - Dist(I*b*(c + d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement5578(a, b, c, d, e, f, m, x): return -Dist(I*b*(-c - d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d + (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Dist(I*b*(c + d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d + (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d*tanh(a + b*x))/(f*(m + S(1))), x) def replacement5579(a, b, c, d, e, f, m, x): return -Dist(I*b*(-c - d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Dist(I*b*(c + d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp((e + f*x)**(m + S(1))*ArcTan(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement5580(a, b, c, d, e, f, m, x): return Dist(I*b*(-c - d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(-c + d - (-c - d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) - Dist(I*b*(c + d + I)/(f*(m + S(1))), Int((e + f*x)**(m + S(1))*exp(S(2)*a + S(2)*b*x)/(c - d - (c + d + I)*exp(S(2)*a + S(2)*b*x) + I), x), x) + Simp((e + f*x)**(m + S(1))*acot(c + d/tanh(a + b*x))/(f*(m + S(1))), x) def replacement5581(u, x): return -Int(SimplifyIntegrand(x*D(u, x)/(u**S(2) + S(1)), x), x) + Simp(x*ArcTan(u), x) def replacement5582(u, x): return Int(SimplifyIntegrand(x*D(u, x)/(u**S(2) + S(1)), x), x) + Simp(x*acot(u), x) def replacement5583(a, b, c, d, m, u, x): return -Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(u**S(2) + S(1)), x), x), x) + Simp((a + b*ArcTan(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement5584(a, b, c, d, m, u, x): return Dist(b/(d*(m + S(1))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(u**S(2) + S(1)), x), x), x) + Simp((a + b*acot(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def With5585(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement5585(a, b, u, v, x): w = IntHide(v, x) return -Dist(b, Int(SimplifyIntegrand(w*D(u, x)/(u**S(2) + S(1)), x), x), x) + Dist(a + b*ArcTan(u), w, x) def With5586(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement5586(a, b, u, v, x): w = IntHide(v, x) return Dist(b, Int(SimplifyIntegrand(w*D(u, x)/(u**S(2) + S(1)), x), x), x) + Dist(a + b*acot(u), w, x) def replacement5587(a, b, v, w, x): return Dist(I/S(2), Int(log(w)*log(-I*v + S(1))/(a + b*x), x), x) - Dist(I/S(2), Int(log(w)*log(I*v + S(1))/(a + b*x), x), x) def replacement5588(v, w, x): return -Int(SimplifyIntegrand(x*ArcTan(v)*D(w, x)/w, x), x) - Int(SimplifyIntegrand(x*D(v, x)*log(w)/(v**S(2) + S(1)), x), x) + Simp(x*ArcTan(v)*log(w), x) def replacement5589(v, w, x): return -Int(SimplifyIntegrand(x*D(w, x)*acot(v)/w, x), x) + Int(SimplifyIntegrand(x*D(v, x)*log(w)/(v**S(2) + S(1)), x), x) + Simp(x*log(w)*acot(v), x) def With5590(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False z = IntHide(u, x) if InverseFunctionFreeQ(z, x): return True return False def replacement5590(u, v, w, x): z = IntHide(u, x) return Dist(ArcTan(v)*log(w), z, x) - Int(SimplifyIntegrand(z*ArcTan(v)*D(w, x)/w, x), x) - Int(SimplifyIntegrand(z*D(v, x)*log(w)/(v**S(2) + S(1)), x), x) def With5591(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False z = IntHide(u, x) if InverseFunctionFreeQ(z, x): return True return False def replacement5591(u, v, w, x): z = IntHide(u, x) return Dist(log(w)*acot(v), z, x) - Int(SimplifyIntegrand(z*D(w, x)*acot(v)/w, x), x) + Int(SimplifyIntegrand(z*D(v, x)*log(w)/(v**S(2) + S(1)), x), x) def replacement5592(c, x): return -Dist(S(1)/c, Int(S(1)/(x*sqrt(S(1) - S(1)/(c**S(2)*x**S(2)))), x), x) + Simp(x*asec(c*x), x) def replacement5593(c, x): return Dist(S(1)/c, Int(S(1)/(x*sqrt(S(1) - S(1)/(c**S(2)*x**S(2)))), x), x) + Simp(x*acsc(c*x), x) def replacement5594(a, b, c, n, x): return Dist(S(1)/c, Subst(Int((a + b*x)**n*tan(x)/cos(x), x), x, asec(c*x)), x) def replacement5595(a, b, c, n, x): return -Dist(S(1)/c, Subst(Int((a + b*x)**n/(sin(x)*tan(x)), x), x, acsc(c*x)), x) def replacement5596(a, b, c, x): return -Subst(Int((a + b*acos(x/c))/x, x), x, S(1)/x) def replacement5597(a, b, c, x): return -Subst(Int((a + b*asin(x/c))/x, x), x, S(1)/x) def replacement5598(a, b, c, m, x): return -Dist(b/(c*(m + S(1))), Int(x**(m + S(-1))/sqrt(S(1) - S(1)/(c**S(2)*x**S(2))), x), x) + Simp(x**(m + S(1))*(a + b*asec(c*x))/(m + S(1)), x) def replacement5599(a, b, c, m, x): return Dist(b/(c*(m + S(1))), Int(x**(m + S(-1))/sqrt(S(1) - S(1)/(c**S(2)*x**S(2))), x), x) + Simp(x**(m + S(1))*(a + b*acsc(c*x))/(m + S(1)), x) def replacement5600(a, b, c, m, n, x): return Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(S(1)/cos(x))**(m + S(1))*tan(x), x), x, asec(c*x)), x) def replacement5601(a, b, c, m, n, x): return -Dist(c**(-m + S(-1)), Subst(Int((a + b*x)**n*(S(1)/sin(x))**(m + S(1))/tan(x), x), x, acsc(c*x)), x) def replacement5602(a, b, c, m, n, x): return Int(x**m*(a + b*asec(c*x))**n, x) def replacement5603(a, b, c, m, n, x): return Int(x**m*(a + b*acsc(c*x))**n, x) def With5604(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return -Dist(b*c*x/sqrt(c**S(2)*x**S(2)), Int(SimplifyIntegrand(u/(x*sqrt(c**S(2)*x**S(2) + S(-1))), x), x), x) + Dist(a + b*asec(c*x), u, x) def With5605(a, b, c, d, e, p, x): u = IntHide((d + e*x**S(2))**p, x) return Dist(b*c*x/sqrt(c**S(2)*x**S(2)), Int(SimplifyIntegrand(u/(x*sqrt(c**S(2)*x**S(2) + S(-1))), x), x), x) + Dist(a + b*acsc(c*x), u, x) def replacement5606(a, b, c, d, e, n, p, x): return -Subst(Int(x**(-S(2)*p + S(-2))*(a + b*acos(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement5607(a, b, c, d, e, n, p, x): return -Subst(Int(x**(-S(2)*p + S(-2))*(a + b*asin(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement5608(a, b, c, d, e, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-S(2)*p + S(-2))*(a + b*acos(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5609(a, b, c, d, e, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-S(2)*p + S(-2))*(a + b*asin(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5610(a, b, c, d, e, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-S(2)*p + S(-2))*(a + b*acos(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5611(a, b, c, d, e, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-S(2)*p + S(-2))*(a + b*asin(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5612(a, b, c, d, e, n, p, x): return Int((a + b*asec(c*x))**n*(d + e*x**S(2))**p, x) def replacement5613(a, b, c, d, e, n, p, x): return Int((a + b*acsc(c*x))**n*(d + e*x**S(2))**p, x) def replacement5614(a, b, c, d, e, p, x): return -Dist(b*c*x/(S(2)*e*sqrt(c**S(2)*x**S(2))*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(x*sqrt(c**S(2)*x**S(2) + S(-1))), x), x) + Simp((a + b*asec(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def replacement5615(a, b, c, d, e, p, x): return Dist(b*c*x/(S(2)*e*sqrt(c**S(2)*x**S(2))*(p + S(1))), Int((d + e*x**S(2))**(p + S(1))/(x*sqrt(c**S(2)*x**S(2) + S(-1))), x), x) + Simp((a + b*acsc(c*x))*(d + e*x**S(2))**(p + S(1))/(S(2)*e*(p + S(1))), x) def With5616(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return -Dist(b*c*x/sqrt(c**S(2)*x**S(2)), Int(SimplifyIntegrand(u/(x*sqrt(c**S(2)*x**S(2) + S(-1))), x), x), x) + Dist(a + b*asec(c*x), u, x) def With5617(a, b, c, d, e, m, p, x): u = IntHide(x**m*(d + e*x**S(2))**p, x) return Dist(b*c*x/sqrt(c**S(2)*x**S(2)), Int(SimplifyIntegrand(u/(x*sqrt(c**S(2)*x**S(2) + S(-1))), x), x), x) + Dist(a + b*acsc(c*x), u, x) def replacement5618(a, b, c, d, e, m, n, p, x): return -Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*acos(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement5619(a, b, c, d, e, m, n, p, x): return -Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*asin(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x) def replacement5620(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*acos(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5621(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(x**S(2))/x, Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*asin(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5622(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*acos(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5623(a, b, c, d, e, m, n, p, x): return -Dist(sqrt(d + e*x**S(2))/(x*sqrt(d/x**S(2) + e)), Subst(Int(x**(-m - S(2)*p + S(-2))*(a + b*asin(x/c))**n*(d*x**S(2) + e)**p, x), x, S(1)/x), x) def replacement5624(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*asec(c*x))**n*(d + e*x**S(2))**p, x) def replacement5625(a, b, c, d, e, m, n, p, x): return Int(x**m*(a + b*acsc(c*x))**n*(d + e*x**S(2))**p, x) def replacement5626(a, b, x): return -Int(S(1)/(sqrt(S(1) - S(1)/(a + b*x)**S(2))*(a + b*x)), x) + Simp((a + b*x)*asec(a + b*x)/b, x) def replacement5627(a, b, x): return Int(S(1)/(sqrt(S(1) - S(1)/(a + b*x)**S(2))*(a + b*x)), x) + Simp((a + b*x)*acsc(a + b*x)/b, x) def replacement5628(a, b, n, x): return Dist(S(1)/b, Subst(Int(x**n*tan(x)/cos(x), x), x, asec(a + b*x)), x) def replacement5629(a, b, n, x): return -Dist(S(1)/b, Subst(Int(x**n/(sin(x)*tan(x)), x), x, acsc(a + b*x)), x) def replacement5630(a, b, x): return -Simp(I*PolyLog(S(2), (S(1) - sqrt(S(1) - a**S(2)))*exp(I*asec(a + b*x))/a), x) - Simp(I*PolyLog(S(2), (sqrt(S(1) - a**S(2)) + S(1))*exp(I*asec(a + b*x))/a), x) + Simp(I*PolyLog(S(2), -exp(S(2)*I*asec(a + b*x)))/S(2), x) + Simp(log(S(1) - (S(1) - sqrt(S(1) - a**S(2)))*exp(I*asec(a + b*x))/a)*asec(a + b*x), x) + Simp(log(S(1) - (sqrt(S(1) - a**S(2)) + S(1))*exp(I*asec(a + b*x))/a)*asec(a + b*x), x) - Simp(log(exp(S(2)*I*asec(a + b*x)) + S(1))*asec(a + b*x), x) def replacement5631(a, b, x): return Simp(I*PolyLog(S(2), I*(S(1) - sqrt(S(1) - a**S(2)))*exp(-I*acsc(a + b*x))/a), x) + Simp(I*PolyLog(S(2), I*(sqrt(S(1) - a**S(2)) + S(1))*exp(-I*acsc(a + b*x))/a), x) + Simp(I*PolyLog(S(2), exp(S(2)*I*acsc(a + b*x)))/S(2), x) + Simp(I*acsc(a + b*x)**S(2), x) + Simp(log(S(1) - I*(S(1) - sqrt(S(1) - a**S(2)))*exp(-I*acsc(a + b*x))/a)*acsc(a + b*x), x) + Simp(log(S(1) - I*(sqrt(S(1) - a**S(2)) + S(1))*exp(-I*acsc(a + b*x))/a)*acsc(a + b*x), x) - Simp(log(S(1) - exp(S(2)*I*acsc(a + b*x)))*acsc(a + b*x), x) def replacement5632(a, b, m, x): return -Dist(b**(-m + S(-1))/(m + S(1)), Subst(Int(x**(-m + S(-1))*((-a*x)**(m + S(1)) - (-a*x + S(1))**(m + S(1)))/sqrt(S(1) - x**S(2)), x), x, S(1)/(a + b*x)), x) - Simp(b**(-m + S(-1))*(-b**(m + S(1))*x**(m + S(1)) + (-a)**(m + S(1)))*asec(a + b*x)/(m + S(1)), x) def replacement5633(a, b, m, x): return Dist(b**(-m + S(-1))/(m + S(1)), Subst(Int(x**(-m + S(-1))*((-a*x)**(m + S(1)) - (-a*x + S(1))**(m + S(1)))/sqrt(S(1) - x**S(2)), x), x, S(1)/(a + b*x)), x) - Simp(b**(-m + S(-1))*(-b**(m + S(1))*x**(m + S(1)) + (-a)**(m + S(1)))*acsc(a + b*x)/(m + S(1)), x) def replacement5634(a, b, m, n, x): return Dist(b**(-m + S(-1)), Subst(Int(x**n*(-a + S(1)/cos(x))**m*tan(x)/cos(x), x), x, asec(a + b*x)), x) def replacement5635(a, b, m, n, x): return -Dist(b**(-m + S(-1)), Subst(Int(x**n*(-a + S(1)/sin(x))**m/(sin(x)*tan(x)), x), x, acsc(a + b*x)), x) def replacement5636(a, b, c, m, n, u, x): return Int(u*acos(a/c + b*x**n/c)**m, x) def replacement5637(a, b, c, m, n, u, x): return Int(u*asin(a/c + b*x**n/c)**m, x) def replacement5638(a, b, c, f, n, u, x): return Dist(S(1)/b, Subst(Int(f**(c*x**n)*ReplaceAll(u, Rule(x, -a/b + S(1)/(b*cos(x))))*tan(x)/cos(x), x), x, asec(a + b*x)), x) def replacement5639(a, b, c, f, n, u, x): return -Dist(S(1)/b, Subst(Int(f**(c*x**n)*ReplaceAll(u, Rule(x, -a/b + S(1)/(b*sin(x))))/(sin(x)*tan(x)), x), x, acsc(a + b*x)), x) def replacement5640(u, x): return -Dist(u/sqrt(u**S(2)), Int(SimplifyIntegrand(x*D(u, x)/(u*sqrt(u**S(2) + S(-1))), x), x), x) + Simp(x*asec(u), x) def replacement5641(u, x): return Dist(u/sqrt(u**S(2)), Int(SimplifyIntegrand(x*D(u, x)/(u*sqrt(u**S(2) + S(-1))), x), x), x) + Simp(x*acsc(u), x) def replacement5642(a, b, c, d, m, u, x): return -Dist(b*u/(d*(m + S(1))*sqrt(u**S(2))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(u*sqrt(u**S(2) + S(-1))), x), x), x) + Simp((a + b*asec(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement5643(a, b, c, d, m, u, x): return Dist(b*u/(d*(m + S(1))*sqrt(u**S(2))), Int(SimplifyIntegrand((c + d*x)**(m + S(1))*D(u, x)/(u*sqrt(u**S(2) + S(-1))), x), x), x) + Simp((a + b*acsc(u))*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def With5644(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement5644(a, b, u, v, x): w = IntHide(v, x) return -Dist(b*u/sqrt(u**S(2)), Int(SimplifyIntegrand(w*D(u, x)/(u*sqrt(u**S(2) + S(-1))), x), x), x) + Dist(a + b*asec(u), w, x) def With5645(a, b, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement5645(a, b, u, v, x): w = IntHide(v, x) return Dist(b*u/sqrt(u**S(2)), Int(SimplifyIntegrand(w*D(u, x)/(u*sqrt(u**S(2) + S(-1))), x), x), x) + Dist(a + b*acsc(u), w, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/linear_products.py000066400000000000000000002626401412543434000247500ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def linear_products(): from sympy.integrals.rubi.constraints import cons2, cons68, cons19, cons69, cons3, cons70, cons71, cons72, cons8, cons29, cons73, cons74, cons4, cons75, cons76, cons77, cons45, cons78, cons79, cons80, cons81, cons82, cons83, cons84, cons64, cons85, cons86, cons87, cons88, cons89, cons90, cons91, cons92, cons93, cons94, cons25, cons95, cons96, cons97, cons98, cons99, cons100, cons101, cons102, cons103, cons104, cons105, cons106, cons107, cons108, cons33, cons109, cons110, cons111, cons112, cons113, cons114, cons115, cons116, cons21, cons117, cons118, cons119, cons120, cons121, cons122, cons123, cons124, cons125, cons126, cons20, cons50, cons127, cons5, cons128, cons129, cons130, cons131, cons132, cons133, cons134, cons135, cons136, cons137, cons56, cons138, cons13, cons139, cons140, cons12, cons141, cons142, cons143, cons144, cons145, cons146, cons40, cons147, cons148, cons149, cons150, cons151, cons152, cons153, cons154, cons155, cons156, cons157, cons158, cons159, cons160, cons161, cons162, cons163, cons164, cons165, cons166, cons167, cons168, cons169, cons170, cons171, cons172, cons173, cons174, cons175, cons176, cons177, cons178, cons179, cons180, cons181, cons182, cons183, cons184, cons185, cons186, cons187, cons188, cons189, cons190, cons191, cons192, cons193, cons194, cons195, cons196, cons197, cons198, cons199, cons200, cons201, cons202, cons203, cons204, cons205, cons206, cons207, cons208, cons209, cons210, cons211, cons212, cons213, cons214, cons215, cons216, cons217, cons218, cons219, cons220, cons221, cons52, cons222, cons223, cons224, cons225, cons226, cons54 pattern39 = Pattern(Integral(a_, x_), cons2, cons2) rule39 = ReplacementRule(pattern39, replacement39) pattern40 = Pattern(Integral(S(1)/x_, x_)) rule40 = ReplacementRule(pattern40, replacement40) pattern41 = Pattern(Integral(x_**WC('m', S(1)), x_), cons19, cons68) rule41 = ReplacementRule(pattern41, replacement41) pattern42 = Pattern(Integral(S(1)/(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons69) rule42 = ReplacementRule(pattern42, replacement42) pattern43 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_, x_), cons2, cons3, cons19, cons68) rule43 = ReplacementRule(pattern43, replacement43) pattern44 = Pattern(Integral((u_*WC('b', S(1)) + WC('a', S(0)))**m_, x_), cons2, cons3, cons19, cons70, cons71) rule44 = ReplacementRule(pattern44, replacement44) pattern45 = Pattern(Integral(S(1)/((a_ + x_*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons72) rule45 = ReplacementRule(pattern45, replacement45) pattern46 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons73) rule46 = ReplacementRule(pattern46, replacement46) pattern47 = Pattern(Integral((c_ + x_*WC('d', S(1)))**n_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons73, cons74, cons68) rule47 = ReplacementRule(pattern47, replacement47) pattern48 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**m_, x_), cons2, cons3, cons8, cons29, cons72, cons75) rule48 = ReplacementRule(pattern48, replacement48) pattern49 = Pattern(Integral(S(1)/((a_ + x_*WC('b', S(1)))**(S(3)/2)*(c_ + x_*WC('d', S(1)))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons72) rule49 = ReplacementRule(pattern49, replacement49) pattern50 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**m_, x_), cons2, cons3, cons8, cons29, cons72, cons76) rule50 = ReplacementRule(pattern50, replacement50) pattern51 = Pattern(Integral((a_ + x_*WC('b', S(1)))**WC('m', S(1))*(c_ + x_*WC('d', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons72, cons77) rule51 = ReplacementRule(pattern51, replacement51) pattern52 = Pattern(Integral(S(1)/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons72, cons45, cons78) rule52 = ReplacementRule(pattern52, replacement52) pattern53 = Pattern(Integral(S(1)/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons72) rule53 = ReplacementRule(pattern53, replacement53) pattern54 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**m_, x_), cons2, cons3, cons8, cons29, cons19, cons72, cons79) rule54 = ReplacementRule(pattern54, replacement54) pattern55 = Pattern(Integral(S(1)/((a_ + x_*WC('b', S(1)))**(S(5)/4)*(c_ + x_*WC('d', S(1)))**(S(1)/4)), x_), cons2, cons3, cons8, cons29, cons72, cons80) rule55 = ReplacementRule(pattern55, replacement55) pattern56 = Pattern(Integral(S(1)/((a_ + x_*WC('b', S(1)))**(S(9)/4)*(c_ + x_*WC('d', S(1)))**(S(1)/4)), x_), cons2, cons3, cons8, cons29, cons72, cons80) rule56 = ReplacementRule(pattern56, replacement56) pattern57 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons2, cons3, cons8, cons29, cons72, cons81, cons82, cons83) rule57 = ReplacementRule(pattern57, replacement57) pattern58 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons2, cons3, cons8, cons29, cons72, cons81, cons82, cons84) rule58 = ReplacementRule(pattern58, replacement58) pattern59 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons73, cons64, cons85) rule59 = ReplacementRule(pattern59, replacement59) pattern60 = Pattern(Integral((a_ + x_*WC('b', S(1)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons73, cons86, cons87, cons88) rule60 = ReplacementRule(pattern60, replacement60) pattern61 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**n_/(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons73, cons89, cons90) rule61 = ReplacementRule(pattern61, replacement61) pattern62 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**n_/(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons73, cons89, cons91) rule62 = ReplacementRule(pattern62, replacement62) pattern63 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(1)/3)), x_), cons2, cons3, cons8, cons29, cons92) rule63 = ReplacementRule(pattern63, With63) pattern64 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(1)/3)), x_), cons2, cons3, cons8, cons29, cons93) rule64 = ReplacementRule(pattern64, With64) pattern65 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(2)/3)), x_), cons2, cons3, cons8, cons29, cons92) rule65 = ReplacementRule(pattern65, With65) pattern66 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(2)/3)), x_), cons2, cons3, cons8, cons29, cons93) rule66 = ReplacementRule(pattern66, With66) pattern67 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**n_/(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons73, cons89, cons94) rule67 = ReplacementRule(pattern67, With67) pattern68 = Pattern(Integral((c_ + x_*WC('d', S(1)))**n_/x_, x_), cons8, cons29, cons4, cons25) rule68 = ReplacementRule(pattern68, replacement68) pattern69 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons73, cons25) rule69 = ReplacementRule(pattern69, replacement69) pattern70 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons73, cons95, cons96, cons90, cons97, cons98, cons99) rule70 = ReplacementRule(pattern70, replacement70) pattern71 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons73, cons95, cons96, cons100, cons99) rule71 = ReplacementRule(pattern71, replacement71) pattern72 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons73, cons95, cons90, cons101, cons102, cons103, cons99) rule72 = ReplacementRule(pattern72, replacement72) pattern73 = Pattern(Integral(S(1)/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons104, cons105) rule73 = ReplacementRule(pattern73, replacement73) pattern74 = Pattern(Integral(S(1)/(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons106, cons107) rule74 = ReplacementRule(pattern74, replacement74) pattern75 = Pattern(Integral(S(1)/(sqrt(c_ + x_*WC('d', S(1)))*sqrt(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons73, cons108) rule75 = ReplacementRule(pattern75, replacement75) pattern76 = Pattern(Integral(S(1)/(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons73) rule76 = ReplacementRule(pattern76, replacement76) pattern77 = Pattern(Integral((c_ + x_*WC('d', S(1)))**m_*(x_*WC('b', S(1)) + WC('a', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons73, cons33, cons109, cons110) rule77 = ReplacementRule(pattern77, replacement77) pattern78 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))**(S(1)/3)*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(2)/3)), x_), cons2, cons3, cons8, cons29, cons73, cons111) rule78 = ReplacementRule(pattern78, With78) pattern79 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))**(S(1)/3)*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(2)/3)), x_), cons2, cons3, cons8, cons29, cons73, cons112) rule79 = ReplacementRule(pattern79, With79) pattern80 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons73, cons95, cons109, cons113) rule80 = ReplacementRule(pattern80, With80) pattern81 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons73, cons95, cons109, cons94, cons114, cons99) rule81 = ReplacementRule(pattern81, With81) pattern82 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons73, cons115, cons68, cons116) rule82 = ReplacementRule(pattern82, replacement82) pattern83 = Pattern(Integral((x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons3, cons8, cons29, cons19, cons4, cons21, cons117) rule83 = ReplacementRule(pattern83, replacement83) pattern84 = Pattern(Integral((x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons3, cons8, cons29, cons19, cons4, cons25, cons118) rule84 = ReplacementRule(pattern84, replacement84) pattern85 = Pattern(Integral((x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons3, cons8, cons29, cons19, cons4, cons21, cons25, cons119, cons120, cons121) rule85 = ReplacementRule(pattern85, replacement85) pattern86 = Pattern(Integral((x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons3, cons8, cons29, cons19, cons4, cons21, cons25, cons119, cons120) rule86 = ReplacementRule(pattern86, replacement86) pattern87 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons2, cons3, cons8, cons29, cons19, cons73, cons21, cons87) rule87 = ReplacementRule(pattern87, replacement87) pattern88 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons73, cons21, cons25, cons122, cons123) rule88 = ReplacementRule(pattern88, replacement88) pattern89 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons73, cons21, cons25, cons124) rule89 = ReplacementRule(pattern89, replacement89) pattern90 = Pattern(Integral((u_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(u_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons70, cons125) rule90 = ReplacementRule(pattern90, replacement90) pattern91 = Pattern(Integral((a_ + x_*WC('b', S(1)))**WC('m', S(1))*(c_ + x_*WC('d', S(1)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons72, cons126, cons20) rule91 = ReplacementRule(pattern91, replacement91) pattern92 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons128, cons129) rule92 = ReplacementRule(pattern92, replacement92) pattern93 = Pattern(Integral((x_*WC('d', S(1)))**WC('n', S(1))*(a_ + x_*WC('b', S(1)))*(e_ + x_*WC('f', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons130, cons131, cons132) rule93 = ReplacementRule(pattern93, replacement93) pattern94 = Pattern(Integral((x_*WC('d', S(1)))**WC('n', S(1))*(a_ + x_*WC('b', S(1)))*(e_ + x_*WC('f', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons130, cons133, cons134, cons135) rule94 = ReplacementRule(pattern94, replacement94) pattern95 = Pattern(Integral((c_ + x_*WC('d', S(1)))**WC('n', S(1))*(x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons136) rule95 = ReplacementRule(pattern95, replacement95) pattern96 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons137, cons56, cons138) rule96 = ReplacementRule(pattern96, replacement96) pattern97 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons128, cons13, cons139, cons140) rule97 = ReplacementRule(pattern97, replacement97) pattern98 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons128, cons12, cons141) rule98 = ReplacementRule(pattern98, replacement98) pattern99 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons128) rule99 = ReplacementRule(pattern99, replacement99) pattern100 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**S(2)*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons128, cons142, cons143) rule100 = ReplacementRule(pattern100, replacement100) pattern101 = Pattern(Integral((x_*WC('f', S(1)))**WC('p', S(1))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons19, cons4, cons5, cons72, cons144, cons12, cons145, cons146) rule101 = ReplacementRule(pattern101, replacement101) pattern102 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons40) rule102 = ReplacementRule(pattern102, replacement102) pattern103 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons13, cons147) rule103 = ReplacementRule(pattern103, replacement103) pattern104 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons13, cons148) rule104 = ReplacementRule(pattern104, replacement104) pattern105 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons13, cons139) rule105 = ReplacementRule(pattern105, replacement105) pattern106 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons149) rule106 = ReplacementRule(pattern106, replacement106) pattern107 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**p_/(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons150, cons151, cons139) rule107 = ReplacementRule(pattern107, replacement107) pattern108 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons152, cons153) rule108 = ReplacementRule(pattern108, replacement108) pattern109 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**S(2)*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons154) rule109 = ReplacementRule(pattern109, replacement109) pattern110 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**S(2)*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons142) rule110 = ReplacementRule(pattern110, replacement110) pattern111 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))**(S(1)/3)*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(2)/3)*(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule111 = ReplacementRule(pattern111, With111) pattern112 = Pattern(Integral(S(1)/(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons156) rule112 = ReplacementRule(pattern112, replacement112) pattern113 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons157, cons95, cons109, cons158) rule113 = ReplacementRule(pattern113, With113) pattern114 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons159, cons89, cons90, cons160) rule114 = ReplacementRule(pattern114, replacement114) pattern115 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons161, cons162, cons68) rule115 = ReplacementRule(pattern115, replacement115) pattern116 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons161, cons163) rule116 = ReplacementRule(pattern116, replacement116) pattern117 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons164, cons96, cons90, cons165, cons166) rule117 = ReplacementRule(pattern117, replacement117) pattern118 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons164, cons96, cons167, cons166) rule118 = ReplacementRule(pattern118, replacement118) pattern119 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons164, cons96, cons90, cons166) rule119 = ReplacementRule(pattern119, replacement119) pattern120 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons33, cons168, cons169, cons20) rule120 = ReplacementRule(pattern120, replacement120) pattern121 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons164, cons170, cons90, cons169, cons171) rule121 = ReplacementRule(pattern121, replacement121) pattern122 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons33, cons168, cons169, cons172) rule122 = ReplacementRule(pattern122, replacement122) pattern123 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons33, cons96, cons20, cons173) rule123 = ReplacementRule(pattern123, replacement123) pattern124 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons33, cons96, cons172) rule124 = ReplacementRule(pattern124, replacement124) pattern125 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons174, cons175) rule125 = ReplacementRule(pattern125, replacement125) pattern126 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**(S(1)/4)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons176) rule126 = ReplacementRule(pattern126, replacement126) pattern127 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**(S(1)/4)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons177) rule127 = ReplacementRule(pattern127, replacement127) pattern128 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**(S(3)/4)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons176) rule128 = ReplacementRule(pattern128, replacement128) pattern129 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**(S(3)/4)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons177) rule129 = ReplacementRule(pattern129, replacement129) pattern130 = Pattern(Integral(sqrt(e_ + x_*WC('f', S(1)))/(sqrt(x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))), x_), cons3, cons8, cons29, cons50, cons127, cons178, cons179, cons180, cons181) rule130 = ReplacementRule(pattern130, replacement130) pattern131 = Pattern(Integral(sqrt(e_ + x_*WC('f', S(1)))/(sqrt(x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))), x_), cons3, cons8, cons29, cons50, cons127, cons178, cons179, cons180, cons182) rule131 = ReplacementRule(pattern131, replacement131) pattern132 = Pattern(Integral(sqrt(e_ + x_*WC('f', S(1)))/(sqrt(x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))), x_), cons3, cons8, cons29, cons50, cons127, cons178, cons183) rule132 = ReplacementRule(pattern132, replacement132) pattern133 = Pattern(Integral(sqrt(x_*WC('f', S(1)) + WC('e', S(0)))/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons122, cons184, cons185, cons186) rule133 = ReplacementRule(pattern133, replacement133) pattern134 = Pattern(Integral(sqrt(x_*WC('f', S(1)) + WC('e', S(0)))/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons187, cons185) rule134 = ReplacementRule(pattern134, replacement134) pattern135 = Pattern(Integral(S(1)/(sqrt(x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))*sqrt(e_ + x_*WC('f', S(1)))), x_), cons3, cons8, cons29, cons50, cons127, cons179, cons180, cons188) rule135 = ReplacementRule(pattern135, replacement135) pattern136 = Pattern(Integral(S(1)/(sqrt(x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))*sqrt(e_ + x_*WC('f', S(1)))), x_), cons3, cons8, cons29, cons50, cons127, cons179, cons180, cons189) rule136 = ReplacementRule(pattern136, replacement136) pattern137 = Pattern(Integral(S(1)/(sqrt(x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))*sqrt(e_ + x_*WC('f', S(1)))), x_), cons3, cons8, cons29, cons50, cons127, cons183) rule137 = ReplacementRule(pattern137, replacement137) pattern138 = Pattern(Integral(S(1)/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))*sqrt(e_ + x_*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons122, cons184, cons158, cons190, cons191) rule138 = ReplacementRule(pattern138, replacement138) pattern139 = Pattern(Integral(S(1)/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))*sqrt(e_ + x_*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons122, cons184, cons158, cons190, cons192) rule139 = ReplacementRule(pattern139, replacement139) pattern140 = Pattern(Integral(S(1)/(sqrt(a_ + x_*WC('b', S(1)))*sqrt(c_ + x_*WC('d', S(1)))*sqrt(e_ + x_*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons187, cons158, cons190) rule140 = ReplacementRule(pattern140, replacement140) pattern141 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))**(S(1)/3)*(x_*WC('f', S(1)) + WC('e', S(0)))**(S(1)/3)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons193) rule141 = ReplacementRule(pattern141, With141) pattern142 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_/((x_*WC('d', S(1)) + WC('c', S(0)))**(S(1)/3)*(x_*WC('f', S(1)) + WC('e', S(0)))**(S(1)/3)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons193, cons20, cons96) rule142 = ReplacementRule(pattern142, replacement142) pattern143 = Pattern(Integral((x_*WC('f', S(1)))**WC('p', S(1))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons19, cons4, cons5, cons72, cons126, cons45, cons179) rule143 = ReplacementRule(pattern143, replacement143) pattern144 = Pattern(Integral((x_*WC('f', S(1)))**WC('p', S(1))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons19, cons4, cons5, cons72, cons126) rule144 = ReplacementRule(pattern144, replacement144) pattern145 = Pattern(Integral((x_*WC('f', S(1)))**WC('p', S(1))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons19, cons4, cons5, cons72, cons194, cons146) rule145 = ReplacementRule(pattern145, replacement145) pattern146 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons195) rule146 = ReplacementRule(pattern146, replacement146) pattern147 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons196, cons68, cons197) rule147 = ReplacementRule(pattern147, replacement147) pattern148 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons159, cons198) rule148 = ReplacementRule(pattern148, replacement148) pattern149 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons159, cons25) rule149 = ReplacementRule(pattern149, replacement149) pattern150 = Pattern(Integral((x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_*(e_ + x_*WC('f', S(1)))**p_, x_), cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons21, cons25, cons179, cons199) rule150 = ReplacementRule(pattern150, replacement150) pattern151 = Pattern(Integral((x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_*(e_ + x_*WC('f', S(1)))**p_, x_), cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons21, cons25, cons200, cons201) rule151 = ReplacementRule(pattern151, replacement151) pattern152 = Pattern(Integral((x_*WC('b', S(1)))**m_*(c_ + x_*WC('d', S(1)))**n_*(e_ + x_*WC('f', S(1)))**p_, x_), cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons21, cons25, cons119) rule152 = ReplacementRule(pattern152, replacement152) pattern153 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons21, cons25, cons40, cons122, cons202) rule153 = ReplacementRule(pattern153, replacement153) pattern154 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons21, cons25, cons40, cons203, cons204) rule154 = ReplacementRule(pattern154, replacement154) pattern155 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons21, cons25, cons149, cons122, cons184, cons205, cons206) rule155 = ReplacementRule(pattern155, replacement155) pattern156 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons21, cons25, cons149, cons122, cons207) rule156 = ReplacementRule(pattern156, replacement156) pattern157 = Pattern(Integral((a_ + x_*WC('b', S(1)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons21, cons25, cons149, cons203, cons204, cons208) rule157 = ReplacementRule(pattern157, replacement157) pattern158 = Pattern(Integral((e_ + u_*WC('f', S(1)))**WC('p', S(1))*(u_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(u_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons70, cons71) rule158 = ReplacementRule(pattern158, replacement158) pattern159 = Pattern(Integral((e_ + x_*WC('f', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons209) rule159 = ReplacementRule(pattern159, replacement159) pattern160 = Pattern(Integral((e_ + x_*WC('f', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons74, cons68, cons212) rule160 = ReplacementRule(pattern160, replacement160) pattern161 = Pattern(Integral((e_ + x_*WC('f', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons95, cons96, cons91) rule161 = ReplacementRule(pattern161, replacement161) pattern162 = Pattern(Integral((e_ + x_*WC('f', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons213) rule162 = ReplacementRule(pattern162, replacement162) pattern163 = Pattern(Integral((e_ + x_*WC('f', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons214, cons68, cons215) rule163 = ReplacementRule(pattern163, replacement163) pattern164 = Pattern(Integral((e_ + x_*WC('f', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons216, cons215) rule164 = ReplacementRule(pattern164, replacement164) pattern165 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons217) rule165 = ReplacementRule(pattern165, replacement165) pattern166 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons95, cons96, cons90, cons20) rule166 = ReplacementRule(pattern166, replacement166) pattern167 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons95, cons96, cons90, cons172) rule167 = ReplacementRule(pattern167, replacement167) pattern168 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons33, cons96, cons20) rule168 = ReplacementRule(pattern168, replacement168) pattern169 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons33, cons96, cons172) rule169 = ReplacementRule(pattern169, replacement169) pattern170 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons33, cons170, cons146, cons20) rule170 = ReplacementRule(pattern170, replacement170) pattern171 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons33, cons170, cons146, cons172) rule171 = ReplacementRule(pattern171, replacement171) pattern172 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons196, cons68, cons197) rule172 = ReplacementRule(pattern172, replacement172) pattern173 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule173 = ReplacementRule(pattern173, replacement173) pattern174 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))/(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons219) rule174 = ReplacementRule(pattern174, replacement174) pattern175 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/(sqrt(c_ + x_*WC('d', S(1)))*sqrt(e_ + x_*WC('f', S(1)))*sqrt(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons190, cons220) rule175 = ReplacementRule(pattern175, replacement175) pattern176 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons221) rule176 = ReplacementRule(pattern176, replacement176) pattern177 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))**q_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons52, cons13, cons147) rule177 = ReplacementRule(pattern177, replacement177) pattern178 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule178 = ReplacementRule(pattern178, replacement178) pattern179 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**n_/((x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons82) rule179 = ReplacementRule(pattern179, replacement179) pattern180 = Pattern(Integral(sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))/((x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule180 = ReplacementRule(pattern180, replacement180) pattern181 = Pattern(Integral(S(1)/(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule181 = ReplacementRule(pattern181, replacement181) pattern182 = Pattern(Integral(sqrt(x_*WC('d', S(1)) + WC('c', S(0)))/((x_*WC('b', S(1)) + WC('a', S(0)))**(S(3)/2)*sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule182 = ReplacementRule(pattern182, replacement182) pattern183 = Pattern(Integral(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))/(sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule183 = ReplacementRule(pattern183, replacement183) pattern184 = Pattern(Integral(S(1)/((x_*WC('b', S(1)) + WC('a', S(0)))**(S(3)/2)*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule184 = ReplacementRule(pattern184, replacement184) pattern185 = Pattern(Integral(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_*WC('d', S(1)) + WC('c', S(0)))/(sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule185 = ReplacementRule(pattern185, replacement185) pattern186 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**(S(3)/2)/(sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*sqrt(x_*WC('f', S(1)) + WC('e', S(0)))*sqrt(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons218) rule186 = ReplacementRule(pattern186, replacement186) pattern187 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons222) rule187 = ReplacementRule(pattern187, replacement187) pattern188 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons223, cons221) rule188 = ReplacementRule(pattern188, replacement188) pattern189 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons52, cons224) rule189 = ReplacementRule(pattern189, replacement189) pattern190 = Pattern(Integral((u_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(u_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(u_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*(u_*WC('h', S(1)) + WC('g', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons52, cons70, cons71) rule190 = ReplacementRule(pattern190, replacement190) pattern191 = Pattern(Integral(((x_*WC('b', S(1)) + WC('a', S(0)))**m_*(x_*WC('d', S(1)) + WC('c', S(0)))**n_*(x_*WC('f', S(1)) + WC('e', S(0)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))**q_*WC('i', S(1)))**r_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons19, cons4, cons5, cons52, cons54, cons225) rule191 = ReplacementRule(pattern191, replacement191) return [rule39, rule40, rule41, rule42, rule43, rule44, rule45, rule46, rule47, rule48, rule49, rule50, rule51, rule52, rule53, rule54, rule55, rule56, rule57, rule58, rule59, rule60, rule61, rule62, rule63, rule64, rule65, rule66, rule67, rule68, rule69, rule70, rule71, rule72, rule73, rule74, rule75, rule76, rule77, rule78, rule79, rule80, rule81, rule82, rule83, rule84, rule85, rule86, rule87, rule88, rule89, rule90, rule91, rule92, rule93, rule94, rule95, rule96, rule97, rule98, rule99, rule100, rule101, rule102, rule103, rule104, rule105, rule106, rule107, rule108, rule109, rule110, rule111, rule112, rule113, rule114, rule115, rule116, rule117, rule118, rule119, rule120, rule121, rule122, rule123, rule124, rule125, rule126, rule127, rule128, rule129, rule130, rule131, rule132, rule133, rule134, rule135, rule136, rule137, rule138, rule139, rule140, rule141, rule142, rule143, rule144, rule145, rule146, rule147, rule148, rule149, rule150, rule151, rule152, rule153, rule154, rule155, rule156, rule157, rule158, rule159, rule160, rule161, rule162, rule163, rule164, rule165, rule166, rule167, rule168, rule169, rule170, rule171, rule172, rule173, rule174, rule175, rule176, rule177, rule178, rule179, rule180, rule181, rule182, rule183, rule184, rule185, rule186, rule187, rule188, rule189, rule190, rule191, ] def replacement39(x): return Simp(a_*x, x) def replacement40(x): return Simp(log(x), x) def replacement41(m, x): return Simp(x**(m + S(1))/(m + S(1)), x) def replacement42(a, b, x): return Simp(log(RemoveContent(a + b*x, x))/b, x) def replacement43(a, b, m, x): return Simp((a + b*x)**(m + S(1))/(b*(m + S(1))), x) def replacement44(a, b, m, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x)**m, x), x, u), x) def replacement45(a, b, c, d, x): return Int(S(1)/(a*c + b*d*x**S(2)), x) def replacement46(a, b, c, d, x): return Dist(b/(-a*d + b*c), Int(S(1)/(a + b*x), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/(c + d*x), x), x) def replacement47(a, b, c, d, m, n, x): return Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))/((m + S(1))*(-a*d + b*c)), x) def replacement48(a, b, c, d, m, x): return Dist(S(2)*a*c*m/(S(2)*m + S(1)), Int((a + b*x)**(m + S(-1))*(c + d*x)**(m + S(-1)), x), x) + Simp(x*(a + b*x)**m*(c + d*x)**m/(S(2)*m + S(1)), x) def replacement49(a, b, c, d, x): return Simp(x/(a*c*sqrt(a + b*x)*sqrt(c + d*x)), x) def replacement50(a, b, c, d, m, x): return Dist((S(2)*m + S(3))/(S(2)*a*c*(m + S(1))), Int((a + b*x)**(m + S(1))*(c + d*x)**(m + S(1)), x), x) - Simp(x*(a + b*x)**(m + S(1))*(c + d*x)**(m + S(1))/(S(2)*a*c*(m + S(1))), x) def replacement51(a, b, c, d, m, x): return Int((a*c + b*d*x**S(2))**m, x) def replacement52(a, b, c, d, x): return Simp(acosh(b*x/a)/b, x) def replacement53(a, b, c, d, x): return Dist(S(2), Subst(Int(S(1)/(b - d*x**S(2)), x), x, sqrt(a + b*x)/sqrt(c + d*x)), x) def replacement54(a, b, c, d, m, x): return Dist((a + b*x)**FracPart(m)*(c + d*x)**FracPart(m)*(a*c + b*d*x**S(2))**(-FracPart(m)), Int((a*c + b*d*x**S(2))**m, x), x) def replacement55(a, b, c, d, x): return Dist((-a*d + b*c)/(S(2)*b), Int(S(1)/((a + b*x)**(S(5)/4)*(c + d*x)**(S(5)/4)), x), x) + Simp(-S(2)/(b*(a + b*x)**(S(1)/4)*(c + d*x)**(S(1)/4)), x) def replacement56(a, b, c, d, x): return -Dist(d/(S(5)*b), Int(S(1)/((a + b*x)**(S(5)/4)*(c + d*x)**(S(5)/4)), x), x) + Simp(-S(4)/(S(5)*b*(a + b*x)**(S(5)/4)*(c + d*x)**(S(1)/4)), x) def replacement57(a, b, c, d, m, n, x): return Dist(S(2)*c*n/(m + n + S(1)), Int((a + b*x)**m*(c + d*x)**(n + S(-1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n/(b*(m + n + S(1))), x) def replacement58(a, b, c, d, m, n, x): return Dist((m + n + S(2))/(S(2)*a*(m + S(1))), Int((a + b*x)**(m + S(1))*(c + d*x)**n, x), x) - Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))/(S(2)*a*d*(m + S(1))), x) def replacement59(a, b, c, d, m, n, x): return Int(ExpandIntegrand((a + b*x)**m*(c + d*x)**n, x), x) def replacement60(a, b, c, d, m, n, x): return Int(ExpandIntegrand((a + b*x)**m*(c + d*x)**n, x), x) def replacement61(a, b, c, d, n, x): return Dist((-a*d + b*c)/b, Int((c + d*x)**(n + S(-1))/(a + b*x), x), x) + Simp((c + d*x)**n/(b*n), x) def replacement62(a, b, c, d, n, x): return Dist(b/(-a*d + b*c), Int((c + d*x)**(n + S(1))/(a + b*x), x), x) - Simp((c + d*x)**(n + S(1))/((n + S(1))*(-a*d + b*c)), x) def With63(a, b, c, d, x): q = Rt((-a*d + b*c)/b, S(3)) return Dist(S(3)/(S(2)*b), Subst(Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x, (c + d*x)**(S(1)/3)), x) - Dist(S(3)/(S(2)*b*q), Subst(Int(S(1)/(q - x), x), x, (c + d*x)**(S(1)/3)), x) - Simp(log(RemoveContent(a + b*x, x))/(S(2)*b*q), x) def With64(a, b, c, d, x): q = Rt(-(-a*d + b*c)/b, S(3)) return Dist(S(3)/(S(2)*b), Subst(Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x, (c + d*x)**(S(1)/3)), x) - Dist(S(3)/(S(2)*b*q), Subst(Int(S(1)/(q + x), x), x, (c + d*x)**(S(1)/3)), x) + Simp(log(RemoveContent(a + b*x, x))/(S(2)*b*q), x) def With65(a, b, c, d, x): q = Rt((-a*d + b*c)/b, S(3)) return -Dist(S(3)/(S(2)*b*q**S(2)), Subst(Int(S(1)/(q - x), x), x, (c + d*x)**(S(1)/3)), x) - Dist(S(3)/(S(2)*b*q), Subst(Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x, (c + d*x)**(S(1)/3)), x) - Simp(log(RemoveContent(a + b*x, x))/(S(2)*b*q**S(2)), x) def With66(a, b, c, d, x): q = Rt(-(-a*d + b*c)/b, S(3)) return Dist(S(3)/(S(2)*b*q**S(2)), Subst(Int(S(1)/(q + x), x), x, (c + d*x)**(S(1)/3)), x) + Dist(S(3)/(S(2)*b*q), Subst(Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x, (c + d*x)**(S(1)/3)), x) - Simp(log(RemoveContent(a + b*x, x))/(S(2)*b*q**S(2)), x) def With67(a, b, c, d, n, x): p = Denominator(n) return Dist(p, Subst(Int(x**(p*(n + S(1)) + S(-1))/(a*d - b*c + b*x**p), x), x, (c + d*x)**(S(1)/p)), x) def replacement68(c, d, n, x): return -Simp((c + d*x)**(n + S(1))*Hypergeometric2F1(S(1), n + S(1), n + S(2), S(1) + d*x/c)/(c*(n + S(1))), x) def replacement69(a, b, c, d, n, x): return -Simp((c + d*x)**(n + S(1))*Hypergeometric2F1(S(1), n + S(1), n + S(2), TogetherSimplify(b*(c + d*x)/(-a*d + b*c)))/((n + S(1))*(-a*d + b*c)), x) def replacement70(a, b, c, d, m, n, x): return -Dist(d*n/(b*(m + S(1))), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n/(b*(m + S(1))), x) def replacement71(a, b, c, d, m, n, x): return -Dist(d*(m + n + S(2))/((m + S(1))*(-a*d + b*c)), Int((a + b*x)**(m + S(1))*(c + d*x)**n, x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))/((m + S(1))*(-a*d + b*c)), x) def replacement72(a, b, c, d, m, n, x): return Dist(n*(-a*d + b*c)/(b*(m + n + S(1))), Int((a + b*x)**m*(c + d*x)**(n + S(-1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n/(b*(m + n + S(1))), x) def replacement73(a, b, c, d, x): return Int(S(1)/sqrt(a*c - b**S(2)*x**S(2) - b*x*(a - c)), x) def replacement74(a, b, c, d, x): return Dist(S(2)/sqrt(b), Subst(Int(S(1)/sqrt(-a*d + b*c + d*x**S(2)), x), x, sqrt(a + b*x)), x) def replacement75(a, b, c, d, x): return Dist(S(2)/b, Subst(Int(S(1)/sqrt(-a + c + x**S(2)), x), x, sqrt(a + b*x)), x) def replacement76(a, b, c, d, x): return Dist(S(2), Subst(Int(S(1)/(b - d*x**S(2)), x), x, sqrt(a + b*x)/sqrt(c + d*x)), x) def replacement77(a, b, c, d, m, x): return Dist((a + b*x)**m*(c + d*x)**m*(a*c + b*d*x**S(2) + x*(a*d + b*c))**(-m), Int((a*c + b*d*x**S(2) + x*(a*d + b*c))**m, x), x) def With78(a, b, c, d, x): q = Rt(d/b, S(3)) return -Simp(q*log(c + d*x)/(S(2)*d), x) - Simp(S(3)*q*log(q*(a + b*x)**(S(1)/3)/(c + d*x)**(S(1)/3) + S(-1))/(S(2)*d), x) - Simp(sqrt(S(3))*q*ArcTan(S(2)*sqrt(S(3))*q*(a + b*x)**(S(1)/3)/(S(3)*(c + d*x)**(S(1)/3)) + sqrt(S(3))/S(3))/d, x) def With79(a, b, c, d, x): q = Rt(-d/b, S(3)) return Simp(q*log(c + d*x)/(S(2)*d), x) + Simp(S(3)*q*log(q*(a + b*x)**(S(1)/3)/(c + d*x)**(S(1)/3) + S(1))/(S(2)*d), x) + Simp(sqrt(S(3))*q*ArcTan(-S(2)*sqrt(S(3))*q*(a + b*x)**(S(1)/3)/(S(3)*(c + d*x)**(S(1)/3)) + sqrt(S(3))/S(3))/d, x) def With80(a, b, c, d, m, n, x): p = Denominator(m) return Dist(p, Subst(Int(x**(p*(m + S(1)) + S(-1))/(b - d*x**p), x), x, (a + b*x)**(S(1)/p)*(c + d*x)**(-S(1)/p)), x) def With81(a, b, c, d, m, n, x): p = Denominator(m) return Dist(p/b, Subst(Int(x**(p*(m + S(1)) + S(-1))*(-a*d/b + c + d*x**p/b)**n, x), x, (a + b*x)**(S(1)/p)), x) def replacement82(a, b, c, d, m, n, x): return -Dist(d*(m + n + S(2))/((m + S(1))*(-a*d + b*c)), Int((a + b*x)**(m + S(1))*(c + d*x)**n, x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))/((m + S(1))*(-a*d + b*c)), x) def replacement83(b, c, d, m, n, x): return Simp(c**n*(b*x)**(m + S(1))*Hypergeometric2F1(-n, m + S(1), m + S(2), -d*x/c)/(b*(m + S(1))), x) def replacement84(b, c, d, m, n, x): return Simp((-d/(b*c))**(-m)*(c + d*x)**(n + S(1))*Hypergeometric2F1(-m, n + S(1), n + S(2), S(1) + d*x/c)/(d*(n + S(1))), x) def replacement85(b, c, d, m, n, x): return Dist(c**IntPart(n)*(S(1) + d*x/c)**(-FracPart(n))*(c + d*x)**FracPart(n), Int((b*x)**m*(S(1) + d*x/c)**n, x), x) def replacement86(b, c, d, m, n, x): return Dist((b*x)**FracPart(m)*(-b*c/d)**IntPart(m)*(-d*x/c)**(-FracPart(m)), Int((-d*x/c)**m*(c + d*x)**n, x), x) def replacement87(a, b, c, d, m, n, x): return Simp(b**(-n + S(-1))*(a + b*x)**(m + S(1))*(-a*d + b*c)**n*Hypergeometric2F1(-n, m + S(1), m + S(2), -d*(a + b*x)/(-a*d + b*c))/(m + S(1)), x) def replacement88(a, b, c, d, m, n, x): return Simp((b/(-a*d + b*c))**(-n)*(a + b*x)**(m + S(1))*Hypergeometric2F1(-n, m + S(1), m + S(2), -d*(a + b*x)/(-a*d + b*c))/(b*(m + S(1))), x) def replacement89(a, b, c, d, m, n, x): return Dist((b/(-a*d + b*c))**(-IntPart(n))*(b*(c + d*x)/(-a*d + b*c))**(-FracPart(n))*(c + d*x)**FracPart(n), Int((a + b*x)**m*(b*c/(-a*d + b*c) + b*d*x/(-a*d + b*c))**n, x), x) def replacement90(a, b, c, d, m, n, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x)**m*(c + d*x)**n, x), x, u), x) def replacement91(a, b, c, d, e, f, m, n, p, x): return Int((e + f*x)**p*(a*c + b*d*x**S(2))**m, x) def replacement92(a, b, c, d, e, f, n, p, x): return Simp(b*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/(d*f*(n + p + S(2))), x) def replacement93(a, b, d, e, f, n, p, x): return Int(ExpandIntegrand((d*x)**n*(a + b*x)*(e + f*x)**p, x), x) def replacement94(a, b, d, e, f, n, p, x): return Int(ExpandIntegrand((d*x)**n*(a + b*x)*(e + f*x)**p, x), x) def replacement95(a, b, c, d, e, f, n, p, x): return Int(ExpandIntegrand((a + b*x)*(c + d*x)**n*(e + f*x)**p, x), x) def replacement96(a, b, c, d, e, f, n, p, x): return Dist(b/f, Int((c + d*x)**n*(e + f*x)**(p + S(1)), x), x) - Simp((c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(-a*f + b*e)/(f*(p + S(1))*(c*f - d*e)), x) def replacement97(a, b, c, d, e, f, n, p, x): return -Dist((a*d*f*(n + p + S(2)) - b*(c*f*(p + S(1)) + d*e*(n + S(1))))/(f*(p + S(1))*(c*f - d*e)), Int((c + d*x)**n*(e + f*x)**(p + S(1)), x), x) - Simp((c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(-a*f + b*e)/(f*(p + S(1))*(c*f - d*e)), x) def replacement98(a, b, c, d, e, f, n, p, x): return -Dist((a*d*f*(n + p + S(2)) - b*(c*f*(p + S(1)) + d*e*(n + S(1))))/(f*(p + S(1))*(c*f - d*e)), Int((c + d*x)**n*(e + f*x)**(p + S(1)), x), x) - Simp((c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(-a*f + b*e)/(f*(p + S(1))*(c*f - d*e)), x) def replacement99(a, b, c, d, e, f, n, p, x): return Dist((a*d*f*(n + p + S(2)) - b*(c*f*(p + S(1)) + d*e*(n + S(1))))/(d*f*(n + p + S(2))), Int((c + d*x)**n*(e + f*x)**p, x), x) + Simp(b*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/(d*f*(n + p + S(2))), x) def replacement100(a, b, c, d, e, f, n, p, x): return Simp(b*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(S(2)*a*d*f*(n + p + S(3)) + b*d*f*x*(n + p + S(2)) - b*(c*f*(p + S(2)) + d*e*(n + S(2))))/(d**S(2)*f**S(2)*(n + p + S(2))*(n + p + S(3))), x) def replacement101(a, b, c, d, f, m, n, p, x): return Dist(a, Int((f*x)**p*(a + b*x)**n*(c + d*x)**n, x), x) + Dist(b/f, Int((f*x)**(p + S(1))*(a + b*x)**n*(c + d*x)**n, x), x) def replacement102(a, b, c, d, e, f, p, x): return Int(ExpandIntegrand((e + f*x)**p/((a + b*x)*(c + d*x)), x), x) def replacement103(a, b, c, d, e, f, p, x): return Dist((-a*f + b*e)/(-a*d + b*c), Int((e + f*x)**(p + S(-1))/(a + b*x), x), x) - Dist((-c*f + d*e)/(-a*d + b*c), Int((e + f*x)**(p + S(-1))/(c + d*x), x), x) def replacement104(a, b, c, d, e, f, p, x): return Dist(S(1)/(b*d), Int((e + f*x)**(p + S(-2))*(-a*c*f**S(2) + b*d*e**S(2) + f*x*(-a*d*f - b*c*f + S(2)*b*d*e))/((a + b*x)*(c + d*x)), x), x) + Simp(f*(e + f*x)**(p + S(-1))/(b*d*(p + S(-1))), x) def replacement105(a, b, c, d, e, f, p, x): return Dist(S(1)/((-a*f + b*e)*(-c*f + d*e)), Int((e + f*x)**(p + S(1))*(-a*d*f - b*c*f + b*d*e - b*d*f*x)/((a + b*x)*(c + d*x)), x), x) + Simp(f*(e + f*x)**(p + S(1))/((p + S(1))*(-a*f + b*e)*(-c*f + d*e)), x) def replacement106(a, b, c, d, e, f, p, x): return Dist(b/(-a*d + b*c), Int((e + f*x)**p/(a + b*x), x), x) - Dist(d/(-a*d + b*c), Int((e + f*x)**p/(c + d*x), x), x) def replacement107(a, b, c, d, e, f, n, p, x): return Int(ExpandIntegrand((e + f*x)**FractionalPart(p), (c + d*x)**n*(e + f*x)**IntegerPart(p)/(a + b*x), x), x) def replacement108(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*x)**m*(c + d*x)**n*(e + f*x)**p, x), x) def replacement109(a, b, c, d, e, f, n, p, x): return -Dist(S(1)/(d**S(2)*(n + S(1))*(-c*f + d*e)), Int((c + d*x)**(n + S(1))*(e + f*x)**p*Simp(a**S(2)*d**S(2)*f*(n + p + S(2)) - S(2)*a*b*d*(c*f*(p + S(1)) + d*e*(n + S(1))) + b**S(2)*c*(c*f*(p + S(1)) + d*e*(n + S(1))) - b**S(2)*d*x*(n + S(1))*(-c*f + d*e), x), x), x) + Simp((c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(-a*d + b*c)**S(2)/(d**S(2)*(n + S(1))*(-c*f + d*e)), x) def replacement110(a, b, c, d, e, f, n, p, x): return Dist(S(1)/(d*f*(n + p + S(3))), Int((c + d*x)**n*(e + f*x)**p*Simp(a**S(2)*d*f*(n + p + S(3)) + b*x*(a*d*f*(n + p + S(4)) - b*(c*f*(p + S(2)) + d*e*(n + S(2)))) - b*(a*(c*f*(p + S(1)) + d*e*(n + S(1))) + b*c*e), x), x), x) + Simp(b*(a + b*x)*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/(d*f*(n + p + S(3))), x) def With111(a, b, c, d, e, f, x): q = Rt((-c*f + d*e)/(-a*f + b*e), S(3)) return Simp(q*log(e + f*x)/(-S(2)*c*f + S(2)*d*e), x) - Simp(S(3)*q*log(q*(a + b*x)**(S(1)/3) - (c + d*x)**(S(1)/3))/(-S(2)*c*f + S(2)*d*e), x) - Simp(sqrt(S(3))*q*ArcTan(S(2)*sqrt(S(3))*q*(a + b*x)**(S(1)/3)/(S(3)*(c + d*x)**(S(1)/3)) + sqrt(S(3))/S(3))/(-c*f + d*e), x) def replacement112(a, b, c, d, e, f, x): return Dist(b*f, Subst(Int(S(1)/(b*f**S(2)*x**S(2) + d*(-a*f + b*e)**S(2)), x), x, sqrt(a + b*x)*sqrt(c + d*x)), x) def With113(a, b, c, d, e, f, m, n, x): q = Denominator(m) return Dist(q, Subst(Int(x**(q*(m + S(1)) + S(-1))/(-a*f + b*e - x**q*(-c*f + d*e)), x), x, (a + b*x)**(S(1)/q)*(c + d*x)**(-S(1)/q)), x) def replacement114(a, b, c, d, e, f, m, n, p, x): return -Dist(n*(-c*f + d*e)/((m + S(1))*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-1))*(e + f*x)**p, x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**(p + S(1))/((m + S(1))*(-a*f + b*e)), x) def replacement115(a, b, c, d, e, f, m, n, p, x): return Simp(b*(a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement116(a, b, c, d, e, f, m, n, p, x): return Dist((a*d*f*(m + S(1)) + b*c*f*(n + S(1)) + b*d*e*(p + S(1)))/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p, x), x) + Simp(b*(a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement117(a, b, c, d, e, f, m, n, p, x): return -Dist(S(1)/(b*(m + S(1))), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-1))*(e + f*x)**(p + S(-1))*Simp(c*f*p + d*e*n + d*f*x*(n + p), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p/(b*(m + S(1))), x) def replacement118(a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/(b*(m + S(1))*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-2))*(e + f*x)**p*Simp(a*d*(c*f*(p + S(1)) + d*e*(n + S(-1))) + b*c*(-c*f*(m + p + S(2)) + d*e*(m - n + S(2))) + d*x*(a*d*f*(n + p) + b*(-c*f*(m + n + p + S(1)) + d*e*(m + S(1)))), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-1))*(e + f*x)**(p + S(1))*(-a*d + b*c)/(b*(m + S(1))*(-a*f + b*e)), x) def replacement119(a, b, c, d, e, f, m, n, p, x): return -Dist(S(1)/((m + S(1))*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-1))*(e + f*x)**p*Simp(c*f*(m + p + S(2)) + d*e*n + d*f*x*(m + n + p + S(2)), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**(p + S(1))/((m + S(1))*(-a*f + b*e)), x) def replacement120(a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/(d*f*(m + n + p + S(1))), Int((a + b*x)**(m + S(-2))*(c + d*x)**n*(e + f*x)**p*Simp(a**S(2)*d*f*(m + n + p + S(1)) + b*x*(a*d*f*(S(2)*m + n + p) - b*(c*f*(m + p) + d*e*(m + n))) - b*(a*(c*f*(p + S(1)) + d*e*(n + S(1))) + b*c*e*(m + S(-1))), x), x), x) + Simp(b*(a + b*x)**(m + S(-1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/(d*f*(m + n + p + S(1))), x) def replacement121(a, b, c, d, e, f, m, n, p, x): return -Dist(S(1)/(f*(m + n + p + S(1))), Int((a + b*x)**(m + S(-1))*(c + d*x)**(n + S(-1))*(e + f*x)**p*Simp(a*n*(-c*f + d*e) + c*m*(-a*f + b*e) + x*(b*n*(-c*f + d*e) + d*m*(-a*f + b*e)), x), x), x) + Simp((a + b*x)**m*(c + d*x)**n*(e + f*x)**(p + S(1))/(f*(m + n + p + S(1))), x) def replacement122(a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/(d*f*(m + n + p + S(1))), Int((a + b*x)**(m + S(-2))*(c + d*x)**n*(e + f*x)**p*Simp(a**S(2)*d*f*(m + n + p + S(1)) + b*x*(a*d*f*(S(2)*m + n + p) - b*(c*f*(m + p) + d*e*(m + n))) - b*(a*(c*f*(p + S(1)) + d*e*(n + S(1))) + b*c*e*(m + S(-1))), x), x), x) + Simp(b*(a + b*x)**(m + S(-1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/(d*f*(m + n + p + S(1))), x) def replacement123(a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p*Simp(a*d*f*(m + S(1)) - b*d*f*x*(m + n + p + S(3)) - b*(c*f*(m + p + S(2)) + d*e*(m + n + S(2))), x), x), x) + Simp(b*(a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement124(a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p*Simp(a*d*f*(m + S(1)) - b*d*f*x*(m + n + p + S(3)) - b*(c*f*(m + p + S(2)) + d*e*(m + n + S(2))), x), x), x) + Simp(b*(a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement125(a, b, c, d, e, f, m, n, x): return Dist(b/f, Int((a + b*x)**(m + S(-1))*(c + d*x)**n, x), x) - Dist((-a*f + b*e)/f, Int((a + b*x)**(m + S(-1))*(c + d*x)**n/(e + f*x), x), x) def replacement126(a, b, c, d, e, f, x): return Dist(S(-4), Subst(Int(x**S(2)/(sqrt(c - d*e/f + d*x**S(4)/f)*(-a*f + b*e - b*x**S(4))), x), x, (e + f*x)**(S(1)/4)), x) def replacement127(a, b, c, d, e, f, x): return Dist(sqrt(-f*(c + d*x)/(-c*f + d*e))/sqrt(c + d*x), Int(S(1)/((a + b*x)*(e + f*x)**(S(1)/4)*sqrt(-c*f/(-c*f + d*e) - d*f*x/(-c*f + d*e))), x), x) def replacement128(a, b, c, d, e, f, x): return Dist(S(-4), Subst(Int(S(1)/(sqrt(c - d*e/f + d*x**S(4)/f)*(-a*f + b*e - b*x**S(4))), x), x, (e + f*x)**(S(1)/4)), x) def replacement129(a, b, c, d, e, f, x): return Dist(sqrt(-f*(c + d*x)/(-c*f + d*e))/sqrt(c + d*x), Int(S(1)/((a + b*x)*(e + f*x)**(S(3)/4)*sqrt(-c*f/(-c*f + d*e) - d*f*x/(-c*f + d*e))), x), x) def replacement130(b, c, d, e, f, x): return Simp(S(2)*sqrt(e)*EllipticE(asin(sqrt(b*x)/(sqrt(c)*Rt(-b/d, S(2)))), c*f/(d*e))*Rt(-b/d, S(2))/b, x) def replacement131(b, c, d, e, f, x): return Dist(sqrt(-b*x)/sqrt(b*x), Int(sqrt(e + f*x)/(sqrt(-b*x)*sqrt(c + d*x)), x), x) def replacement132(b, c, d, e, f, x): return Dist(sqrt(S(1) + d*x/c)*sqrt(e + f*x)/(sqrt(S(1) + f*x/e)*sqrt(c + d*x)), Int(sqrt(S(1) + f*x/e)/(sqrt(b*x)*sqrt(S(1) + d*x/c)), x), x) def replacement133(a, b, c, d, e, f, x): return Simp(S(2)*EllipticE(asin(sqrt(a + b*x)/Rt(-(-a*d + b*c)/d, S(2))), f*(-a*d + b*c)/(d*(-a*f + b*e)))*Rt(-(-a*f + b*e)/d, S(2))/b, x) def replacement134(a, b, c, d, e, f, x): return Dist(sqrt(b*(c + d*x)/(-a*d + b*c))*sqrt(e + f*x)/(sqrt(b*(e + f*x)/(-a*f + b*e))*sqrt(c + d*x)), Int(sqrt(b*e/(-a*f + b*e) + b*f*x/(-a*f + b*e))/(sqrt(a + b*x)*sqrt(b*c/(-a*d + b*c) + b*d*x/(-a*d + b*c))), x), x) def replacement135(b, c, d, e, f, x): return Simp(S(2)*EllipticF(asin(sqrt(b*x)/(sqrt(c)*Rt(-b/d, S(2)))), c*f/(d*e))*Rt(-b/d, S(2))/(b*sqrt(e)), x) def replacement136(b, c, d, e, f, x): return Simp(S(2)*EllipticF(asin(sqrt(b*x)/(sqrt(c)*Rt(-b/d, S(2)))), c*f/(d*e))*Rt(-b/d, S(2))/(b*sqrt(e)), x) def replacement137(b, c, d, e, f, x): return Dist(sqrt(S(1) + d*x/c)*sqrt(S(1) + f*x/e)/(sqrt(c + d*x)*sqrt(e + f*x)), Int(S(1)/(sqrt(b*x)*sqrt(S(1) + d*x/c)*sqrt(S(1) + f*x/e)), x), x) def replacement138(a, b, c, d, e, f, x): return Simp(S(2)*sqrt(b**S(2)/((-a*d + b*c)*(-a*f + b*e)))*EllipticF(asin(sqrt(a + b*x)/Rt(-(-a*d + b*c)/d, S(2))), f*(-a*d + b*c)/(d*(-a*f + b*e)))*Rt(-(-a*d + b*c)/d, S(2))/b, x) def replacement139(a, b, c, d, e, f, x): return Simp(S(2)*sqrt(b**S(2)/((-a*d + b*c)*(-a*f + b*e)))*EllipticF(asin(sqrt(a + b*x)/Rt(-(-a*d + b*c)/d, S(2))), f*(-a*d + b*c)/(d*(-a*f + b*e)))*Rt(-(-a*d + b*c)/d, S(2))/b, x) def replacement140(a, b, c, d, e, f, x): return Dist(sqrt(b*(c + d*x)/(-a*d + b*c))*sqrt(b*(e + f*x)/(-a*f + b*e))/(sqrt(c + d*x)*sqrt(e + f*x)), Int(S(1)/(sqrt(a + b*x)*sqrt(b*c/(-a*d + b*c) + b*d*x/(-a*d + b*c))*sqrt(b*e/(-a*f + b*e) + b*f*x/(-a*f + b*e))), x), x) def With141(a, b, c, d, e, f, x): q = Rt(b*(-a*f + b*e)/(-a*d + b*c)**S(2), S(3)) return -Simp(log(a + b*x)/(S(2)*q*(-a*d + b*c)), x) + Simp(S(3)*log(q*(c + d*x)**(S(2)/3) - (e + f*x)**(S(1)/3))/(S(4)*q*(-a*d + b*c)), x) - Simp(sqrt(S(3))*ArcTan(S(2)*sqrt(S(3))*q*(c + d*x)**(S(2)/3)/(S(3)*(e + f*x)**(S(1)/3)) + sqrt(S(3))/S(3))/(S(2)*q*(-a*d + b*c)), x) def replacement142(a, b, c, d, e, f, m, x): return Dist(f/(S(6)*(m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(a*d*(S(3)*m + S(1)) - S(3)*b*c*(S(3)*m + S(5)) - S(2)*b*d*x*(S(3)*m + S(7)))/((c + d*x)**(S(1)/3)*(e + f*x)**(S(1)/3)), x), x) + Simp(b*(a + b*x)**(m + S(1))*(c + d*x)**(S(2)/3)*(e + f*x)**(S(2)/3)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement143(a, b, c, d, f, m, n, p, x): return Int((f*x)**p*(a*c + b*d*x**S(2))**m, x) def replacement144(a, b, c, d, f, m, n, p, x): return Dist((a + b*x)**FracPart(m)*(c + d*x)**FracPart(m)*(a*c + b*d*x**S(2))**(-FracPart(m)), Int((f*x)**p*(a*c + b*d*x**S(2))**m, x), x) def replacement145(a, b, c, d, f, m, n, p, x): return Int(ExpandIntegrand((f*x)**p*(a + b*x)**n*(c + d*x)**n, (a + b*x)**(m - n), x), x) def replacement146(a, b, c, d, e, f, m, n, p, x): return Int(ExpandIntegrand((a + b*x)**m*(c + d*x)**n*(e + f*x)**p, x), x) def replacement147(a, b, c, d, e, f, m, n, p, x): return Dist(S(1)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p*Simp(a*d*f*(m + S(1)) - b*d*f*x*(m + n + p + S(3)) - b*(c*f*(m + p + S(2)) + d*e*(m + n + S(2))), x), x), x) + Simp(b*(a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement148(a, b, c, d, e, f, m, n, p, x): return Simp((a + b*x)**(m + S(1))*(e + f*x)**(-m + S(-1))*(-a*d + b*c)**n*(-a*f + b*e)**(-n + S(-1))*Hypergeometric2F1(m + S(1), -n, m + S(2), -(a + b*x)*(-c*f + d*e)/((e + f*x)*(-a*d + b*c)))/(m + S(1)), x) def replacement149(a, b, c, d, e, f, m, n, p, x): return Simp(((c + d*x)*(-a*f + b*e)/((e + f*x)*(-a*d + b*c)))**(-n)*(a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**(p + S(1))*Hypergeometric2F1(m + S(1), -n, m + S(2), -(a + b*x)*(-c*f + d*e)/((e + f*x)*(-a*d + b*c)))/((m + S(1))*(-a*f + b*e)), x) def replacement150(b, c, d, e, f, m, n, p, x): return Simp(c**n*e**p*(b*x)**(m + S(1))*AppellF1(m + S(1), -n, -p, m + S(2), -d*x/c, -f*x/e)/(b*(m + S(1))), x) def replacement151(b, c, d, e, f, m, n, p, x): return Simp((d/(-c*f + d*e))**(-p)*(-d/(b*c))**(-m)*(c + d*x)**(n + S(1))*AppellF1(n + S(1), -m, -p, n + S(2), S(1) + d*x/c, -f*(c + d*x)/(-c*f + d*e))/(d*(n + S(1))), x) def replacement152(b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(S(1) + d*x/c)**(-FracPart(n))*(c + d*x)**FracPart(n), Int((b*x)**m*(S(1) + d*x/c)**n*(e + f*x)**p, x), x) def replacement153(a, b, c, d, e, f, m, n, p, x): return Simp(b**(-p + S(-1))*(b/(-a*d + b*c))**(-n)*(a + b*x)**(m + S(1))*(-a*f + b*e)**p*AppellF1(m + S(1), -n, -p, m + S(2), -d*(a + b*x)/(-a*d + b*c), -f*(a + b*x)/(-a*f + b*e))/(m + S(1)), x) def replacement154(a, b, c, d, e, f, m, n, p, x): return Dist((b/(-a*d + b*c))**(-IntPart(n))*(b*(c + d*x)/(-a*d + b*c))**(-FracPart(n))*(c + d*x)**FracPart(n), Int((a + b*x)**m*(e + f*x)**p*(b*c/(-a*d + b*c) + b*d*x/(-a*d + b*c))**n, x), x) def replacement155(a, b, c, d, e, f, m, n, p, x): return Simp((b/(-a*d + b*c))**(-n)*(b/(-a*f + b*e))**(-p)*(a + b*x)**(m + S(1))*AppellF1(m + S(1), -n, -p, m + S(2), -d*(a + b*x)/(-a*d + b*c), -f*(a + b*x)/(-a*f + b*e))/(b*(m + S(1))), x) def replacement156(a, b, c, d, e, f, m, n, p, x): return Dist((b/(-a*f + b*e))**(-IntPart(p))*(b*(e + f*x)/(-a*f + b*e))**(-FracPart(p))*(e + f*x)**FracPart(p), Int((a + b*x)**m*(c + d*x)**n*(b*e/(-a*f + b*e) + b*f*x/(-a*f + b*e))**p, x), x) def replacement157(a, b, c, d, e, f, m, n, p, x): return Dist((b/(-a*d + b*c))**(-IntPart(n))*(b*(c + d*x)/(-a*d + b*c))**(-FracPart(n))*(c + d*x)**FracPart(n), Int((a + b*x)**m*(e + f*x)**p*(b*c/(-a*d + b*c) + b*d*x/(-a*d + b*c))**n, x), x) def replacement158(a, b, c, d, e, f, m, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x)**m*(c + d*x)**n*(e + f*x)**p, x), x, u), x) def replacement159(a, b, c, d, e, f, g, h, m, n, x): return Int(ExpandIntegrand((a + b*x)**m*(c + d*x)**n*(e + f*x)*(g + h*x), x), x) def replacement160(a, b, c, d, e, f, g, h, m, n, x): return Dist((a*d*f*h*m + b*(-c*f*h*(m + S(2)) + d*(e*h + f*g)))/(b**S(2)*d), Int((a + b*x)**(m + S(1))*(c + d*x)**n, x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(-a**S(2)*d*f*h*m - a*b*(-c*f*h*(m + S(1)) + d*(e*h + f*g)) + b**S(2)*d*e*g + b*f*h*x*(m + S(1))*(-a*d + b*c))/(b**S(2)*d*(m + S(1))*(-a*d + b*c)), x) def replacement161(a, b, c, d, e, f, g, h, m, n, x): return -Dist((a**S(2)*d**S(2)*f*h*(n**S(2) + S(3)*n + S(2)) + a*b*d*(n + S(1))*(S(2)*c*f*h*(m + S(1)) - d*(e*h + f*g)*(m + n + S(3))) + b**S(2)*(c**S(2)*f*h*(m**S(2) + S(3)*m + S(2)) - c*d*(m + S(1))*(e*h + f*g)*(m + n + S(3)) + d**S(2)*e*g*(m**S(2) + m*(S(2)*n + S(5)) + n**S(2) + S(5)*n + S(6))))/(b*d*(m + S(1))*(n + S(1))*(-a*d + b*c)**S(2)), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(a**S(2)*c*d*f*h*(n + S(1)) + a*b*(c**S(2)*f*h*(m + S(1)) - c*d*(e*h + f*g)*(m + n + S(2)) + d**S(2)*e*g*(m + S(1))) + b**S(2)*c*d*e*g*(n + S(1)) + x*(a**S(2)*d**S(2)*f*h*(n + S(1)) - a*b*d**S(2)*(n + S(1))*(e*h + f*g) + b**S(2)*(c**S(2)*f*h*(m + S(1)) - c*d*(m + S(1))*(e*h + f*g) + d**S(2)*e*g*(m + n + S(2)))))/(b*d*(m + S(1))*(n + S(1))*(-a*d + b*c)**S(2)), x) def replacement162(a, b, c, d, e, f, g, h, m, n, x): return Dist(-d*(m + n + S(3))*(a**S(2)*d*f*h*(m - n) - a*b*(S(2)*c*f*h*(m + S(1)) - d*(n + S(1))*(e*h + f*g)) + b**S(2)*(c*(m + S(1))*(e*h + f*g) - d*e*g*(m + n + S(2))))/(b**S(2)*(m + S(1))*(m + S(2))*(-a*d + b*c)**S(2)) + f*h/b**S(2), Int((a + b*x)**(m + S(2))*(c + d*x)**n, x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(-a**S(3)*d*f*h*(n + S(2)) - a**S(2)*b*(c*f*h*m - d*(e*h + f*g)*(m + n + S(3))) - a*b**S(2)*(c*(e*h + f*g) + d*e*g*(S(2)*m + n + S(4))) + b**S(3)*c*e*g*(m + S(2)) + b*x*(a**S(2)*d*f*h*(m - n) - a*b*(S(2)*c*f*h*(m + S(1)) - d*(n + S(1))*(e*h + f*g)) + b**S(2)*(c*(m + S(1))*(e*h + f*g) - d*e*g*(m + n + S(2)))))/(b**S(2)*(m + S(1))*(m + S(2))*(-a*d + b*c)**S(2)), x) def replacement163(a, b, c, d, e, f, g, h, m, n, x): return -Dist((a**S(2)*d**S(2)*f*h*(n + S(1))*(n + S(2)) + a*b*d*(n + S(1))*(S(2)*c*f*h*(m + S(1)) - d*(e*h + f*g)*(m + n + S(3))) + b**S(2)*(c**S(2)*f*h*(m + S(1))*(m + S(2)) - c*d*(m + S(1))*(e*h + f*g)*(m + n + S(3)) + d**S(2)*e*g*(m + n + S(2))*(m + n + S(3))))/(b**S(2)*d*(m + S(1))*(-a*d + b*c)*(m + n + S(3))), Int((a + b*x)**(m + S(1))*(c + d*x)**n, x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(a**S(2)*d*f*h*(n + S(2)) + a*b*(c*f*h*(m + S(1)) - d*(e*h + f*g)*(m + n + S(3))) + b**S(2)*d*e*g*(m + n + S(3)) + b*f*h*x*(m + S(1))*(-a*d + b*c))/(b**S(2)*d*(m + S(1))*(-a*d + b*c)*(m + n + S(3))), x) def replacement164(a, b, c, d, e, f, g, h, m, n, x): return Dist((a**S(2)*d**S(2)*f*h*(n + S(1))*(n + S(2)) + a*b*d*(n + S(1))*(S(2)*c*f*h*(m + S(1)) - d*(e*h + f*g)*(m + n + S(3))) + b**S(2)*(c**S(2)*f*h*(m + S(1))*(m + S(2)) - c*d*(m + S(1))*(e*h + f*g)*(m + n + S(3)) + d**S(2)*e*g*(m + n + S(2))*(m + n + S(3))))/(b**S(2)*d**S(2)*(m + n + S(2))*(m + n + S(3))), Int((a + b*x)**m*(c + d*x)**n, x), x) - Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(a*d*f*h*(n + S(2)) + b*c*f*h*(m + S(2)) - b*d*f*h*x*(m + n + S(2)) - b*d*(e*h + f*g)*(m + n + S(3)))/(b**S(2)*d**S(2)*(m + n + S(2))*(m + n + S(3))), x) def replacement165(a, b, c, d, e, f, g, h, m, n, p, x): return Int(ExpandIntegrand((a + b*x)**m*(c + d*x)**n*(e + f*x)**p*(g + h*x), x), x) def replacement166(a, b, c, d, e, f, g, h, m, n, p, x): return -Dist(S(1)/(b*(m + S(1))*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-1))*(e + f*x)**p*Simp(b*c*(m + S(1))*(-e*h + f*g) + d*x*(b*(m + S(1))*(-e*h + f*g) + f*(-a*h + b*g)*(n + p + S(1))) + (-a*h + b*g)*(c*f*(p + S(1)) + d*e*n), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**(p + S(1))*(-a*h + b*g)/(b*(m + S(1))*(-a*f + b*e)), x) def replacement167(a, b, c, d, e, f, g, h, m, n, p, x): return -Dist(S(1)/(b*(m + S(1))*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**(n + S(-1))*(e + f*x)**p*Simp(b*c*(m + S(1))*(-e*h + f*g) + d*x*(b*(m + S(1))*(-e*h + f*g) + f*(-a*h + b*g)*(n + p + S(1))) + (-a*h + b*g)*(c*f*(p + S(1)) + d*e*n), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**(p + S(1))*(-a*h + b*g)/(b*(m + S(1))*(-a*f + b*e)), x) def replacement168(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(S(1)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p*Simp(-d*f*x*(-a*h + b*g)*(m + n + p + S(3)) + (m + S(1))*(a*d*f*g + b*c*e*h - b*g*(c*f + d*e)) - (-a*h + b*g)*(c*f*(p + S(1)) + d*e*(n + S(1))), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(-a*h + b*g)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement169(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(S(1)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p*Simp(-d*f*x*(-a*h + b*g)*(m + n + p + S(3)) + (m + S(1))*(a*d*f*g + b*c*e*h - b*g*(c*f + d*e)) - (-a*h + b*g)*(c*f*(p + S(1)) + d*e*(n + S(1))), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(-a*h + b*g)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement170(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(S(1)/(d*f*(m + n + p + S(2))), Int((a + b*x)**(m + S(-1))*(c + d*x)**n*(e + f*x)**p*Simp(a*d*f*g*(m + n + p + S(2)) - h*(a*(c*f*(p + S(1)) + d*e*(n + S(1))) + b*c*e*m) + x*(b*d*f*g*(m + n + p + S(2)) + h*(a*d*f*m - b*(c*f*(m + p + S(1)) + d*e*(m + n + S(1))))), x), x), x) + Simp(h*(a + b*x)**m*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/(d*f*(m + n + p + S(2))), x) def replacement171(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(S(1)/(d*f*(m + n + p + S(2))), Int((a + b*x)**(m + S(-1))*(c + d*x)**n*(e + f*x)**p*Simp(a*d*f*g*(m + n + p + S(2)) - h*(a*(c*f*(p + S(1)) + d*e*(n + S(1))) + b*c*e*m) + x*(b*d*f*g*(m + n + p + S(2)) + h*(a*d*f*m - b*(c*f*(m + p + S(1)) + d*e*(m + n + S(1))))), x), x), x) + Simp(h*(a + b*x)**m*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))/(d*f*(m + n + p + S(2))), x) def replacement172(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(S(1)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p*Simp(-d*f*x*(-a*h + b*g)*(m + n + p + S(3)) + (m + S(1))*(a*d*f*g + b*c*e*h - b*g*(c*f + d*e)) - (-a*h + b*g)*(c*f*(p + S(1)) + d*e*(n + S(1))), x), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(n + S(1))*(e + f*x)**(p + S(1))*(-a*h + b*g)/((m + S(1))*(-a*d + b*c)*(-a*f + b*e)), x) def replacement173(a, b, c, d, e, f, g, h, p, x): return Dist((-a*h + b*g)/(-a*d + b*c), Int((e + f*x)**p/(a + b*x), x), x) - Dist((-c*h + d*g)/(-a*d + b*c), Int((e + f*x)**p/(c + d*x), x), x) def replacement174(a, b, c, d, e, f, g, h, n, p, x): return Dist(h/b, Int((c + d*x)**n*(e + f*x)**p, x), x) + Dist((-a*h + b*g)/b, Int((c + d*x)**n*(e + f*x)**p/(a + b*x), x), x) def replacement175(a, b, c, d, e, f, g, h, x): return Dist(h/f, Int(sqrt(e + f*x)/(sqrt(a + b*x)*sqrt(c + d*x)), x), x) + Dist((-e*h + f*g)/f, Int(S(1)/(sqrt(a + b*x)*sqrt(c + d*x)*sqrt(e + f*x)), x), x) def replacement176(a, b, c, d, e, f, g, h, m, n, p, x): return Dist(h/b, Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p, x), x) + Dist((-a*h + b*g)/b, Int((a + b*x)**m*(c + d*x)**n*(e + f*x)**p, x), x) def replacement177(a, b, c, d, e, f, g, h, p, q, x): return Dist((-a*f + b*e)/(-a*d + b*c), Int((e + f*x)**(p + S(-1))*(g + h*x)**q/(a + b*x), x), x) - Dist((-c*f + d*e)/(-a*d + b*c), Int((e + f*x)**(p + S(-1))*(g + h*x)**q/(c + d*x), x), x) def replacement178(a, b, c, d, e, f, g, h, x): return Simp(-S(2)*sqrt(d*(e + f*x)/(-c*f + d*e))*sqrt(d*(g + h*x)/(-c*h + d*g))*EllipticPi(-b*(-c*f + d*e)/(f*(-a*d + b*c)), asin(sqrt(-f/(-c*f + d*e))*sqrt(c + d*x)), h*(-c*f + d*e)/(f*(-c*h + d*g)))/(sqrt(-f/(-c*f + d*e))*sqrt(e + f*x)*sqrt(g + h*x)*(-a*d + b*c)), x) def replacement179(a, b, c, d, e, f, g, h, n, x): return Int(ExpandIntegrand(S(1)/(sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), (c + d*x)**(n + S(1)/2)/(a + b*x), x), x) def replacement180(a, b, c, d, e, f, g, h, x): return Dist(b**(S(-2)), Int((-a*f*h + b*e*h + b*f*g + b*f*h*x)/(sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x), x) + Dist((-a*f + b*e)*(-a*h + b*g)/b**S(2), Int(S(1)/((a + b*x)*sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x), x) def replacement181(a, b, c, d, e, f, g, h, x): return Dist(-S(2)*sqrt((c + d*x)*(-a*h + b*g)/((a + b*x)*(-c*h + d*g)))*sqrt((e + f*x)*(-a*h + b*g)/((a + b*x)*(-e*h + f*g)))*(a + b*x)/(sqrt(c + d*x)*sqrt(e + f*x)*(-a*h + b*g)), Subst(Int(S(1)/(sqrt(x**S(2)*(-a*d + b*c)/(-c*h + d*g) + S(1))*sqrt(x**S(2)*(-a*f + b*e)/(-e*h + f*g) + S(1))), x), x, sqrt(g + h*x)/sqrt(a + b*x)), x) def replacement182(a, b, c, d, e, f, g, h, x): return Dist(-S(2)*sqrt((c + d*x)*(-a*h + b*g)/((a + b*x)*(-c*h + d*g)))*sqrt((e + f*x)*(-a*h + b*g)/((a + b*x)*(-e*h + f*g)))*(a + b*x)*(-c*h + d*g)/(sqrt(c + d*x)*sqrt(e + f*x)*(-a*h + b*g)**S(2)), Subst(Int(sqrt(x**S(2)*(-a*d + b*c)/(-c*h + d*g) + S(1))/sqrt(x**S(2)*(-a*f + b*e)/(-e*h + f*g) + S(1)), x), x, sqrt(g + h*x)/sqrt(a + b*x)), x) def replacement183(a, b, c, d, e, f, g, h, x): return Dist(S(2)*sqrt((c + d*x)*(-a*h + b*g)/((a + b*x)*(-c*h + d*g)))*sqrt((e + f*x)*(-a*h + b*g)/((a + b*x)*(-e*h + f*g)))*(a + b*x)/(sqrt(c + d*x)*sqrt(e + f*x)), Subst(Int(S(1)/((-b*x**S(2) + h)*sqrt(x**S(2)*(-a*d + b*c)/(-c*h + d*g) + S(1))*sqrt(x**S(2)*(-a*f + b*e)/(-e*h + f*g) + S(1))), x), x, sqrt(g + h*x)/sqrt(a + b*x)), x) def replacement184(a, b, c, d, e, f, g, h, x): return Dist(b/(-a*d + b*c), Int(sqrt(c + d*x)/((a + b*x)**(S(3)/2)*sqrt(e + f*x)*sqrt(g + h*x)), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/(sqrt(a + b*x)*sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x), x) def replacement185(a, b, c, d, e, f, g, h, x): return Dist((a*d*f*h - b*(-c*f*h + d*e*h + d*f*g))/(S(2)*f**S(2)*h), Int(sqrt(e + f*x)/(sqrt(a + b*x)*sqrt(c + d*x)*sqrt(g + h*x)), x), x) + Dist((-c*f + d*e)*(-S(2)*a*f*h + b*e*h + b*f*g)/(S(2)*f**S(2)*h), Int(S(1)/(sqrt(a + b*x)*sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x), x) - Dist((-c*f + d*e)*(-e*h + f*g)/(S(2)*f*h), Int(sqrt(a + b*x)/(sqrt(c + d*x)*(e + f*x)**(S(3)/2)*sqrt(g + h*x)), x), x) + Simp(sqrt(a + b*x)*sqrt(c + d*x)*sqrt(g + h*x)/(h*sqrt(e + f*x)), x) def replacement186(a, b, c, d, e, f, g, h, x): return Dist(b/d, Int(sqrt(a + b*x)*sqrt(c + d*x)/(sqrt(e + f*x)*sqrt(g + h*x)), x), x) - Dist((-a*d + b*c)/d, Int(sqrt(a + b*x)/(sqrt(c + d*x)*sqrt(e + f*x)*sqrt(g + h*x)), x), x) def replacement187(a, b, c, d, e, f, g, h, m, n, p, q, x): return Int(ExpandIntegrand((a + b*x)**m*(c + d*x)**n*(e + f*x)**p*(g + h*x)**q, x), x) def replacement188(a, b, c, d, e, f, g, h, m, n, p, q, x): return Dist(h/b, Int((a + b*x)**(m + S(1))*(c + d*x)**n*(e + f*x)**p*(g + h*x)**(q + S(-1)), x), x) + Dist((-a*h + b*g)/b, Int((a + b*x)**m*(c + d*x)**n*(e + f*x)**p*(g + h*x)**(q + S(-1)), x), x) def replacement189(a, b, c, d, e, f, g, h, m, n, p, q, x): return Int((a + b*x)**m*(c + d*x)**n*(e + f*x)**p*(g + h*x)**q, x) def replacement190(a, b, c, d, e, f, g, h, m, n, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x)**m*(c + d*x)**n*(e + f*x)**p*(g + h*x)**q, x), x, u), x) def replacement191(a, b, c, d, e, f, g, h, i, m, n, p, q, r, x): return Dist((i*(a + b*x)**m*(c + d*x)**n*(e + f*x)**p*(g + h*x)**q)**r*(a + b*x)**(-m*r)*(c + d*x)**(-n*r)*(e + f*x)**(-p*r)*(g + h*x)**(-q*r), Int((a + b*x)**(m*r)*(c + d*x)**(n*r)*(e + f*x)**(p*r)*(g + h*x)**(q*r), x), x) sympy-sympy-1.9/sympy/integrals/rubi/rules/logarithms.py000066400000000000000000002770561412543434000237330ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def logarithms(): from sympy.integrals.rubi.constraints import cons1158, cons8, cons29, cons50, cons127, cons5, cons52, cons89, cons90, cons2, cons3, cons1159, cons417, cons1160, cons1161, cons91, cons545, cons1162, cons210, cons211, cons586, cons4, cons68, cons19, cons1163, cons1164, cons1165, cons1166, cons1167, cons1168, cons1169, cons1170, cons1171, cons150, cons1172, cons1173, cons64, cons95, cons170, cons812, cons813, cons224, cons1174, cons226, cons798, cons81, cons1175, cons20, cons1176, cons1177, cons1178, cons1179, cons1180, cons1181, cons1182, cons1183, cons1184, cons1185, cons1186, cons1187, cons1188, cons1189, cons1190, cons1191, cons1192, cons799, cons1193, cons54, cons927, cons1194, cons1195, cons1196, cons1197, cons1198, cons1199, cons1200, cons1201, cons40, cons554, cons1202, cons1203, cons1204, cons27, cons654, cons1205, cons73, cons130, cons1206, cons1207, cons1208, cons1209, cons1210, cons148, cons1211, cons1212, cons13, cons165, cons1213, cons139, cons1214, cons1215, cons1216, cons1217, cons1218, cons1219, cons1220, cons1221, cons1222, cons1223, cons1224, cons72, cons1225, cons1226, cons808, cons842, cons1227, cons1228, cons70, cons1127, cons1229, cons1230, cons1231, cons1232, cons465, cons1233, cons1234, cons1235, cons1236, cons1237, cons1238, cons33, cons1101, cons1239, cons1057, cons517, cons818, cons819, cons1240, cons1241, cons1242, cons1243, cons1244, cons1245, cons1246, cons1247, cons36, cons37, cons1248, cons1249, cons1250 pattern2009 = Pattern(Integral(log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))), x_), cons8, cons29, cons50, cons127, cons5, cons52, cons1158) rule2009 = ReplacementRule(pattern2009, replacement2009) pattern2010 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons89, cons90) rule2010 = ReplacementRule(pattern2010, replacement2010) pattern2011 = Pattern(Integral(S(1)/log((x_*WC('f', S(1)) + WC('e', S(0)))*WC('d', S(1))), x_), cons29, cons50, cons127, cons1159) rule2011 = ReplacementRule(pattern2011, replacement2011) pattern2012 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons417) rule2012 = ReplacementRule(pattern2012, replacement2012) pattern2013 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons1160) rule2013 = ReplacementRule(pattern2013, replacement2013) pattern2014 = Pattern(Integral(S(1)/sqrt(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons1161) rule2014 = ReplacementRule(pattern2014, replacement2014) pattern2015 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons89, cons91) rule2015 = ReplacementRule(pattern2015, replacement2015) pattern2016 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons545) rule2016 = ReplacementRule(pattern2016, replacement2016) pattern2017 = Pattern(Integral(S(1)/((x_*WC('h', S(1)) + WC('g', S(0)))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons1162) rule2017 = ReplacementRule(pattern2017, replacement2017) pattern2018 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons52, cons1162, cons586) rule2018 = ReplacementRule(pattern2018, replacement2018) pattern2019 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons1162, cons68, cons89, cons90) rule2019 = ReplacementRule(pattern2019, replacement2019) pattern2020 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))/log((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1))), x_), cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons1163, cons1162, cons1164) rule2020 = ReplacementRule(pattern2020, replacement2020) pattern2021 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**m_/log((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1))), x_), cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons1163, cons1162, cons1165) rule2021 = ReplacementRule(pattern2021, replacement2021) pattern2022 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))/(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons1162, cons68) rule2022 = ReplacementRule(pattern2022, replacement2022) pattern2023 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))/sqrt(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons1162, cons68, cons1166) rule2023 = ReplacementRule(pattern2023, replacement2023) pattern2024 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))/sqrt(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons1162, cons68, cons1167) rule2024 = ReplacementRule(pattern2024, replacement2024) pattern2025 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons1162, cons68, cons89, cons91) rule2025 = ReplacementRule(pattern2025, replacement2025) pattern2026 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons1162, cons68) rule2026 = ReplacementRule(pattern2026, replacement2026) pattern2027 = Pattern(Integral(log((x_*WC('f', S(1)) + WC('e', S(0)))*WC('c', S(1)))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons8, cons50, cons127, cons210, cons211, cons1168) rule2027 = ReplacementRule(pattern2027, replacement2027) pattern2028 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log((x_*WC('f', S(1)) + WC('e', S(0)))*WC('c', S(1))))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons50, cons127, cons210, cons211, cons1169, cons1170) rule2028 = ReplacementRule(pattern2028, replacement2028) pattern2029 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons1171, cons150) rule2029 = ReplacementRule(pattern2029, replacement2029) pattern2030 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons1171, cons68) rule2030 = ReplacementRule(pattern2030, replacement2030) pattern2031 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_/(x_*WC('h', S(1)) + WC('g', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons1171, cons89, cons90) rule2031 = ReplacementRule(pattern2031, replacement2031) pattern2032 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons1171, cons89, cons90, cons68, cons1172, cons1173) rule2032 = ReplacementRule(pattern2032, replacement2032) pattern2033 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))/(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons1171, cons64) rule2033 = ReplacementRule(pattern2033, replacement2033) pattern2034 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons1171, cons95, cons91, cons170) rule2034 = ReplacementRule(pattern2034, replacement2034) pattern2035 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons52, cons1171, cons64) rule2035 = ReplacementRule(pattern2035, replacement2035) pattern2036 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log((v_**p_*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons52, cons812, cons813) rule2036 = ReplacementRule(pattern2036, replacement2036) pattern2037 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons52, cons224) rule2037 = ReplacementRule(pattern2037, replacement2037) pattern2038 = Pattern(Integral(log(WC('c', S(1))/(x_*WC('f', S(1)) + WC('e', S(0))))/((x_*WC('h', S(1)) + WC('g', S(0)))*(x_*WC('j', S(1)) + WC('i', S(0)))), x_), cons8, cons50, cons127, cons210, cons211, cons226, cons798, cons1162, cons1174) rule2038 = ReplacementRule(pattern2038, replacement2038) pattern2039 = Pattern(Integral((a_ + WC('b', S(1))*log(WC('c', S(1))/(x_*WC('f', S(1)) + WC('e', S(0)))))/((x_*WC('h', S(1)) + WC('g', S(0)))*(x_*WC('j', S(1)) + WC('i', S(0)))), x_), cons2, cons3, cons8, cons50, cons127, cons210, cons211, cons226, cons798, cons1162, cons1174) rule2039 = ReplacementRule(pattern2039, replacement2039) pattern2040 = Pattern(Integral((x_*WC('j', S(1)) + WC('i', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons798, cons5, cons52, cons1162, cons81) rule2040 = ReplacementRule(pattern2040, With2040) pattern2041 = Pattern(Integral((x_*WC('j', S(1)) + WC('i', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log((x_*WC('f', S(1)) + WC('e', S(0)))*WC('c', S(1))))**WC('n', S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons50, cons127, cons210, cons211, cons226, cons798, cons4, cons1162, cons64, cons1175) rule2041 = ReplacementRule(pattern2041, replacement2041) pattern2042 = Pattern(Integral((x_*WC('j', S(1)) + WC('i', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons798, cons5, cons52, cons20, cons150, CustomConstraint(With2042)) rule2042 = ReplacementRule(pattern2042, replacement2042) pattern2043 = Pattern(Integral((x_*WC('j', S(1)) + WC('i', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons798, cons19, cons4, cons5, cons52, cons1176) rule2043 = ReplacementRule(pattern2043, replacement2043) pattern2044 = Pattern(Integral(log(WC('c', S(1))/(x_*WC('f', S(1)) + WC('e', S(0))))/(g_ + x_**S(2)*WC('h', S(1))), x_), cons8, cons50, cons127, cons210, cons211, cons1177, cons1178) rule2044 = ReplacementRule(pattern2044, replacement2044) pattern2045 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(WC('c', S(1))/(x_*WC('f', S(1)) + WC('e', S(0)))))/(g_ + x_**S(2)*WC('h', S(1))), x_), cons8, cons50, cons127, cons210, cons211, cons1177, cons1179, cons1180) rule2045 = ReplacementRule(pattern2045, replacement2045) pattern2046 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))/(x_**S(2)*WC('i', S(1)) + x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons5, cons52, cons1181) rule2046 = ReplacementRule(pattern2046, replacement2046) pattern2047 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((e_ + x_*WC('f', S(1)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))/(g_ + x_**S(2)*WC('i', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons226, cons5, cons52, cons1182) rule2047 = ReplacementRule(pattern2047, replacement2047) pattern2048 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))/sqrt(g_ + x_**S(2)*WC('h', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons1183) rule2048 = ReplacementRule(pattern2048, With2048) pattern2049 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))/(sqrt(g1_ + x_*WC('h1', S(1)))*sqrt(g2_ + x_*WC('h2', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1187, cons1188, cons1189, cons1190, cons5, cons52, cons1184, cons1185, cons1186) rule2049 = ReplacementRule(pattern2049, With2049) pattern2050 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))/sqrt(g_ + x_**S(2)*WC('h', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons1191) rule2050 = ReplacementRule(pattern2050, replacement2050) pattern2051 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))/(sqrt(g1_ + x_*WC('h1', S(1)))*sqrt(g2_ + x_*WC('h2', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1187, cons1188, cons1189, cons1190, cons5, cons52, cons1184) rule2051 = ReplacementRule(pattern2051, replacement2051) pattern2052 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('k', S(1)) + WC('j', S(0)))*WC('i', S(1)))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons798, cons799, cons5, cons52, cons89, cons90, cons1192) rule2052 = ReplacementRule(pattern2052, replacement2052) pattern2053 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))*log((x_*WC('k', S(1)) + WC('j', S(0)))**WC('m', S(1))*WC('i', S(1)) + S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons798, cons799, cons19, cons5, cons52, cons89, cons90, cons1193) rule2053 = ReplacementRule(pattern2053, replacement2053) pattern2054 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))*PolyLog(r_, (x_*WC('k', S(1)) + WC('j', S(0)))**WC('m', S(1))*WC('i', S(1)))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons798, cons799, cons19, cons5, cons52, cons54, cons89, cons90, cons1193) rule2054 = ReplacementRule(pattern2054, replacement2054) pattern2055 = Pattern(Integral(F_**(x_*WC('h', S(1)) + WC('g', S(0)))*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))*WC('Px', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons927, cons64, cons1194) rule2055 = ReplacementRule(pattern2055, With2055) pattern2056 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((e_ + x_**m_*WC('f', S(1)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))/x_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons150) rule2056 = ReplacementRule(pattern2056, replacement2056) pattern2057 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_**m_*(f_ + x_**WC('r', S(1))*WC('e', S(1))))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))/x_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons1195, cons150) rule2057 = ReplacementRule(pattern2057, replacement2057) pattern2058 = Pattern(Integral(x_**WC('r1', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_**r_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons52, cons54, cons1196) rule2058 = ReplacementRule(pattern2058, replacement2058) pattern2059 = Pattern(Integral(x_**WC('r1', S(1))*(x_**r_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(((x_**r_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons52, cons54, cons1196) rule2059 = ReplacementRule(pattern2059, replacement2059) pattern2060 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1197) rule2060 = ReplacementRule(pattern2060, With2060) pattern2061 = Pattern(Integral(log((x_**mn_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))/(x_*(d_ + x_**WC('n', S(1))*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1198, cons1199) rule2061 = ReplacementRule(pattern2061, replacement2061) pattern2062 = Pattern(Integral(log(x_**mn_*(x_**WC('n', S(1))*WC('a', S(1)) + WC('b', S(0)))*WC('c', S(1)))/(x_*(d_ + x_**WC('n', S(1))*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1198, cons1199) rule2062 = ReplacementRule(pattern2062, replacement2062) pattern2063 = Pattern(Integral(Px_*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons52, cons927) rule2063 = ReplacementRule(pattern2063, replacement2063) pattern2064 = Pattern(Integral(RFx_*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons1200, cons150, CustomConstraint(With2064)) rule2064 = ReplacementRule(pattern2064, replacement2064) pattern2065 = Pattern(Integral(RFx_*(WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons1200, cons150, CustomConstraint(With2065)) rule2065 = ReplacementRule(pattern2065, replacement2065) pattern2066 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_**S(2)*WC('g', S(1)) + x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons52, cons4, cons1201, cons40) rule2066 = ReplacementRule(pattern2066, replacement2066) pattern2067 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log((v_**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons554, cons1202) rule2067 = ReplacementRule(pattern2067, replacement2067) pattern2068 = Pattern(Integral(log(((x_**WC('n', S(1))*WC('c', S(1)))**p_*WC('b', S(1)))**q_*WC('a', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons52, cons54, cons1203) rule2068 = ReplacementRule(pattern2068, replacement2068) pattern2069 = Pattern(Integral(x_**WC('m', S(1))*log(((x_**WC('n', S(1))*WC('c', S(1)))**p_*WC('b', S(1)))**q_*WC('a', S(1)))**WC('r', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons52, cons54, cons68, cons1204) rule2069 = ReplacementRule(pattern2069, replacement2069) pattern2070 = Pattern(Integral(WC('u', S(1))*log(((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e1', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons654, cons27) rule2070 = ReplacementRule(pattern2070, replacement2070) pattern2071 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons654, cons1206, cons1205, cons73, cons130) rule2071 = ReplacementRule(pattern2071, replacement2071) pattern2072 = Pattern(Integral(log((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))/(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1207, cons1208) rule2072 = ReplacementRule(pattern2072, replacement2072) pattern2073 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1207, cons130) rule2073 = ReplacementRule(pattern2073, replacement2073) pattern2074 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1209, cons130) rule2074 = ReplacementRule(pattern2074, replacement2074) pattern2075 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))/(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1210) rule2075 = ReplacementRule(pattern2075, replacement2075) pattern2076 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**p_/(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1210, cons40, cons148) rule2076 = ReplacementRule(pattern2076, replacement2076) pattern2077 = Pattern(Integral(S(1)/((x_*WC('g', S(1)) + WC('f', S(0)))**S(2)*log((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1207) rule2077 = ReplacementRule(pattern2077, replacement2077) pattern2078 = Pattern(Integral(S(1)/((x_*WC('g', S(1)) + WC('f', S(0)))**S(2)*log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1207) rule2078 = ReplacementRule(pattern2078, replacement2078) pattern2079 = Pattern(Integral(S(1)/((x_*WC('g', S(1)) + WC('f', S(0)))**S(2)*log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1209) rule2079 = ReplacementRule(pattern2079, replacement2079) pattern2080 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_*WC('g', S(1)) + WC('f', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1211, cons130) rule2080 = ReplacementRule(pattern2080, replacement2080) pattern2081 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_*WC('g', S(1)) + WC('f', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1210, cons130) rule2081 = ReplacementRule(pattern2081, replacement2081) pattern2082 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**p_/(x_*WC('g', S(1)) + WC('f', S(0)))**S(3), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons654, cons1206, cons1205, cons73, cons1211, cons1207) rule2082 = ReplacementRule(pattern2082, replacement2082) pattern2083 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**p_/(x_*WC('g', S(1)) + WC('f', S(0)))**S(3), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons654, cons1206, cons1205, cons73, cons1210, cons1209) rule2083 = ReplacementRule(pattern2083, replacement2083) pattern2084 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons130, cons20, cons68) rule2084 = ReplacementRule(pattern2084, replacement2084) pattern2085 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m2', S(1))*log(u_**n_*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1213, cons1212, cons73, cons68, cons13, cons165) rule2085 = ReplacementRule(pattern2085, replacement2085) pattern2086 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m2', S(1))*log(u_)**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons1213, cons1212, cons73, cons68, cons13, cons165) rule2086 = ReplacementRule(pattern2086, replacement2086) pattern2087 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m2', S(1))/log(u_**n_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1213, cons1212, cons73, cons68) rule2087 = ReplacementRule(pattern2087, replacement2087) pattern2088 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m2', S(1))/log(u_), x_), cons2, cons3, cons8, cons29, cons1213, cons1212, cons73, cons68) rule2088 = ReplacementRule(pattern2088, replacement2088) pattern2089 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m2', S(1))*log(u_**n_*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1213, cons1212, cons73, cons68, cons13, cons139) rule2089 = ReplacementRule(pattern2089, replacement2089) pattern2090 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m2', S(1))*log(u_)**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons1213, cons1212, cons73, cons68, cons13, cons139) rule2090 = ReplacementRule(pattern2090, replacement2090) pattern2091 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/((x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1211, cons1207) rule2091 = ReplacementRule(pattern2091, replacement2091) pattern2092 = Pattern(Integral(log((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))/((x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1211, cons1210, cons1214) rule2092 = ReplacementRule(pattern2092, replacement2092) pattern2093 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/((x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons654, cons1206, cons1205, cons73, cons1211, cons1210, cons130) rule2093 = ReplacementRule(pattern2093, replacement2093) pattern2094 = Pattern(Integral(log((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))/(f_ + x_**S(2)*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1215, cons1216) rule2094 = ReplacementRule(pattern2094, replacement2094) pattern2095 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_**S(2)*WC('h', S(1)) + x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons654, cons1206, cons1205, cons73, cons1217) rule2095 = ReplacementRule(pattern2095, replacement2095) pattern2096 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_**S(2)*WC('h', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons211, cons4, cons5, cons654, cons1206, cons1205, cons73, cons1218) rule2096 = ReplacementRule(pattern2096, replacement2096) pattern2097 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/((x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons654, cons1206, cons1205, cons73, cons1210, cons1209) rule2097 = ReplacementRule(pattern2097, replacement2097) pattern2098 = Pattern(Integral(log(v_)*log(u_**n_*WC('e', S(1)))**WC('p', S(1))/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1219, cons1213, cons73, cons13, cons165) rule2098 = ReplacementRule(pattern2098, replacement2098) pattern2099 = Pattern(Integral(log(u_)**WC('p', S(1))*log(v_)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1219, cons1213, cons73, cons13, cons165) rule2099 = ReplacementRule(pattern2099, replacement2099) pattern2100 = Pattern(Integral(log(v_)*log(u_**n_*WC('e', S(1)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1219, cons1213, cons73, cons13, cons139) rule2100 = ReplacementRule(pattern2100, With2100) pattern2101 = Pattern(Integral(log(u_)**p_*log(v_)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1219, cons1213, cons73, cons13, cons139) rule2101 = ReplacementRule(pattern2101, With2101) pattern2102 = Pattern(Integral(log(v_)*log(u_**n_*WC('e', S(1)))**WC('p', S(1))/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1220, cons1213, cons73, cons13, cons165) rule2102 = ReplacementRule(pattern2102, replacement2102) pattern2103 = Pattern(Integral(log(u_)**WC('p', S(1))*log(v_)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1220, cons1213, cons73, cons13, cons165) rule2103 = ReplacementRule(pattern2103, replacement2103) pattern2104 = Pattern(Integral(log(v_)*log(u_**n_*WC('e', S(1)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1220, cons1213, cons73, cons13, cons139) rule2104 = ReplacementRule(pattern2104, With2104) pattern2105 = Pattern(Integral(log(u_)**p_*log(v_)/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1220, cons1213, cons73, cons13, cons139) rule2105 = ReplacementRule(pattern2105, With2105) pattern2106 = Pattern(Integral(PolyLog(q_, v_)*log(u_**n_*WC('e', S(1)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons1221, cons1213, cons73, cons13, cons148) rule2106 = ReplacementRule(pattern2106, replacement2106) pattern2107 = Pattern(Integral(PolyLog(q_, v_)*log(u_)**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons52, cons1221, cons1213, cons73, cons13, cons148) rule2107 = ReplacementRule(pattern2107, replacement2107) pattern2108 = Pattern(Integral(PolyLog(q_, v_)*log(u_**n_*WC('e', S(1)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons1221, cons1213, cons73, cons13, cons139) rule2108 = ReplacementRule(pattern2108, replacement2108) pattern2109 = Pattern(Integral(PolyLog(q_, v_)*log(u_)**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons52, cons1221, cons1213, cons73, cons13, cons139) rule2109 = ReplacementRule(pattern2109, replacement2109) pattern2110 = Pattern(Integral(PolyLog(q_, v_)*log(u_**n_*WC('e', S(1)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons1222, cons1213, cons73, cons13, cons148) rule2110 = ReplacementRule(pattern2110, replacement2110) pattern2111 = Pattern(Integral(PolyLog(q_, v_)*log(u_)**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons52, cons1222, cons1213, cons73, cons13, cons148) rule2111 = ReplacementRule(pattern2111, replacement2111) pattern2112 = Pattern(Integral(PolyLog(q_, v_)*log(u_**n_*WC('e', S(1)))**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons1222, cons1213, cons73, cons13, cons139) rule2112 = ReplacementRule(pattern2112, replacement2112) pattern2113 = Pattern(Integral(PolyLog(q_, v_)*log(u_)**p_/((x_*WC('b', S(1)) + WC('a', S(0)))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons52, cons1222, cons1213, cons73, cons13, cons139) rule2113 = ReplacementRule(pattern2113, replacement2113) pattern2114 = Pattern(Integral(WC('u', S(1))*log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_**S(2)*WC('h', S(1)) + x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons5, cons654, cons1206, cons1205, cons73, cons1223, cons1224) rule2114 = ReplacementRule(pattern2114, replacement2114) pattern2115 = Pattern(Integral(WC('u', S(1))*log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1))/(x_**S(2)*WC('h', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons211, cons4, cons5, cons654, cons1206, cons1205, cons73, cons1223, cons72) rule2115 = ReplacementRule(pattern2115, replacement2115) pattern2116 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))/(f_ + x_**S(2)*WC('h', S(1)) + x_*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons654, cons127, cons210, cons211, cons4, cons1206, cons1205) rule2116 = ReplacementRule(pattern2116, With2116) pattern2117 = Pattern(Integral(log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))/(f_ + x_**S(2)*WC('h', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons654, cons127, cons211, cons4, cons1206, cons1205) rule2117 = ReplacementRule(pattern2117, With2117) pattern2118 = Pattern(Integral(RFx_*log(((x_*WC('b', S(1)) + WC('a', S(0)))**WC('n1', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**n2_*WC('e1', S(1)))**WC('n', S(1))*WC('e', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons654, cons1206, cons1205, cons1200, cons130, CustomConstraint(With2118)) rule2118 = ReplacementRule(pattern2118, replacement2118) pattern2119 = Pattern(Integral(WC('u', S(1))*log(v_)**WC('p', S(1)), x_), cons5, cons1225, cons1226, CustomConstraint(With2119)) rule2119 = ReplacementRule(pattern2119, replacement2119) pattern2120 = Pattern(Integral(log((x_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons4, cons5, cons808) rule2120 = ReplacementRule(pattern2120, replacement2120) pattern2121 = Pattern(Integral(log(v_**WC('p', S(1))*WC('c', S(1))), x_), cons8, cons5, cons842, cons1227) rule2121 = ReplacementRule(pattern2121, replacement2121) pattern2122 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log((x_**n_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*WC('c', S(1))))/(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons1228) rule2122 = ReplacementRule(pattern2122, replacement2122) pattern2123 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log((x_**n_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons68) rule2123 = ReplacementRule(pattern2123, replacement2123) pattern2124 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(v_**WC('p', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons5, cons70, cons842, cons1127) rule2124 = ReplacementRule(pattern2124, replacement2124) pattern2125 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log((x_**n_*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*WC('c', S(1))))*asin(x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons64) rule2125 = ReplacementRule(pattern2125, With2125) pattern2126 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log((x_**S(2)*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*WC('c', S(1))))/(x_**S(2)*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons1229) rule2126 = ReplacementRule(pattern2126, With2126) pattern2127 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons150) rule2127 = ReplacementRule(pattern2127, replacement2127) pattern2128 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons150, cons1230) rule2128 = ReplacementRule(pattern2128, replacement2128) pattern2129 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log((d_ + x_**S(2)*WC('e', S(1)))**WC('p', S(1))*WC('c', S(1))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons150, cons1231) rule2129 = ReplacementRule(pattern2129, replacement2129) pattern2130 = Pattern(Integral(u_*log(v_), x_), CustomConstraint(With2130)) rule2130 = ReplacementRule(pattern2130, replacement2130) pattern2131 = Pattern(Integral(w_*(WC('a', S(0)) + WC('b', S(1))*log(u_))*log(v_), x_), cons2, cons3, cons1232, CustomConstraint(With2131)) rule2131 = ReplacementRule(pattern2131, replacement2131) pattern2132 = Pattern(Integral(log((a_ + (x_*WC('e', S(1)) + WC('d', S(0)))**n_*WC('b', S(1)))**WC('p', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons89, cons465) rule2132 = ReplacementRule(pattern2132, replacement2132) pattern2133 = Pattern(Integral(log((a_ + (x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1233) rule2133 = ReplacementRule(pattern2133, replacement2133) pattern2134 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log((d_ + WC('e', S(1))/(x_*WC('g', S(1)) + WC('f', S(0))))**WC('p', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons150) rule2134 = ReplacementRule(pattern2134, replacement2134) pattern2135 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(RFx_**WC('p', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons5, cons1200, cons150) rule2135 = ReplacementRule(pattern2135, replacement2135) pattern2136 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(RFx_**WC('p', S(1))*WC('c', S(1))))**WC('n', S(1))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1200, cons150) rule2136 = ReplacementRule(pattern2136, replacement2136) pattern2137 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*log(RFx_**WC('p', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons1200, cons150, cons1234, cons68) rule2137 = ReplacementRule(pattern2137, replacement2137) pattern2138 = Pattern(Integral(log(RFx_**WC('n', S(1))*WC('c', S(1)))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons8, cons29, cons50, cons4, cons1200, cons1235) rule2138 = ReplacementRule(pattern2138, With2138) pattern2139 = Pattern(Integral(log(Px_**WC('n', S(1))*WC('c', S(1)))/Qx_, x_), cons8, cons4, cons1236, cons1237) rule2139 = ReplacementRule(pattern2139, With2139) pattern2140 = Pattern(Integral(RGx_*(WC('a', S(0)) + WC('b', S(1))*log(RFx_**WC('p', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons5, cons1200, cons1238, cons150, CustomConstraint(With2140)) rule2140 = ReplacementRule(pattern2140, replacement2140) pattern2141 = Pattern(Integral(RGx_*(WC('a', S(0)) + WC('b', S(1))*log(RFx_**WC('p', S(1))*WC('c', S(1))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons5, cons1200, cons1238, cons150, CustomConstraint(With2141)) rule2141 = ReplacementRule(pattern2141, replacement2141) pattern2142 = Pattern(Integral(RFx_*(WC('a', S(0)) + WC('b', S(1))*log(u_)), x_), cons2, cons3, cons1200, CustomConstraint(With2142)) rule2142 = ReplacementRule(pattern2142, replacement2142) pattern2143 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*log((F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1))))**WC('n', S(1))*WC('e', S(1)) + S(1)), x_), cons1101, cons2, cons3, cons8, cons50, cons127, cons210, cons4, cons33, cons170) rule2143 = ReplacementRule(pattern2143, replacement2143) pattern2144 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))*log(d_ + (F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1))))**WC('n', S(1))*WC('e', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons33, cons170, cons1239) rule2144 = ReplacementRule(pattern2144, replacement2144) pattern2145 = Pattern(Integral(log(x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1057) rule2145 = ReplacementRule(pattern2145, replacement2145) pattern2146 = Pattern(Integral(log(x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons1057) rule2146 = ReplacementRule(pattern2146, replacement2146) pattern2147 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*log(x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons1057, cons68, cons517) rule2147 = ReplacementRule(pattern2147, replacement2147) pattern2148 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*log(x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons1057, cons68, cons517) rule2148 = ReplacementRule(pattern2148, replacement2148) pattern2149 = Pattern(Integral(WC('v', S(1))*log(sqrt(u_)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons29, cons50, cons127, cons818, cons819, cons1240) rule2149 = ReplacementRule(pattern2149, replacement2149) pattern2150 = Pattern(Integral(log(u_), x_), cons1232) rule2150 = ReplacementRule(pattern2150, replacement2150) pattern2151 = Pattern(Integral(log(u_)/(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons1241, cons1242) rule2151 = ReplacementRule(pattern2151, replacement2151) pattern2152 = Pattern(Integral((x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*log(u_), x_), cons2, cons3, cons19, cons1232, cons68) rule2152 = ReplacementRule(pattern2152, replacement2152) pattern2153 = Pattern(Integral(log(u_)/Qx_, x_), cons1243, cons1232) rule2153 = ReplacementRule(pattern2153, With2153) pattern2154 = Pattern(Integral(u_**(x_*WC('a', S(1)))*log(u_), x_), cons2, cons1232) rule2154 = ReplacementRule(pattern2154, replacement2154) pattern2155 = Pattern(Integral(v_*log(u_), x_), cons1232, CustomConstraint(With2155)) rule2155 = ReplacementRule(pattern2155, replacement2155) pattern2156 = Pattern(Integral(log(v_)*log(w_), x_), cons1244, cons1245) rule2156 = ReplacementRule(pattern2156, replacement2156) pattern2157 = Pattern(Integral(u_*log(v_)*log(w_), x_), cons1244, cons1245, CustomConstraint(With2157)) rule2157 = ReplacementRule(pattern2157, replacement2157) pattern2158 = Pattern(Integral(log(WC('a', S(1))*log(x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons4, cons5, cons1246) rule2158 = ReplacementRule(pattern2158, replacement2158) pattern2159 = Pattern(Integral(log(WC('a', S(1))*log(x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1)))/x_, x_), cons2, cons3, cons4, cons5, cons1246) rule2159 = ReplacementRule(pattern2159, replacement2159) pattern2160 = Pattern(Integral(x_**WC('m', S(1))*log(WC('a', S(1))*log(x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons19, cons4, cons5, cons68) rule2160 = ReplacementRule(pattern2160, replacement2160) pattern2161 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*log(x_*WC('d', S(1)) + WC('c', S(0))))/sqrt(a_ + WC('b', S(1))*log(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons1247) rule2161 = ReplacementRule(pattern2161, replacement2161) pattern2162 = Pattern(Integral(f_**(WC('a', S(1))*log(u_)), x_), cons2, cons127, cons1248) rule2162 = ReplacementRule(pattern2162, replacement2162) pattern2163 = Pattern(Integral(u_, x_), cons1249, CustomConstraint(With2163)) rule2163 = ReplacementRule(pattern2163, replacement2163) pattern2164 = Pattern(Integral(WC('u', S(1))*log(Gamma(v_)), x_)) rule2164 = ReplacementRule(pattern2164, replacement2164) pattern2165 = Pattern(Integral((w_*WC('a', S(1)) + w_*WC('b', S(1))*log(v_)**WC('n', S(1)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons4, cons40) rule2165 = ReplacementRule(pattern2165, replacement2165) pattern2166 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons52, cons1250) rule2166 = ReplacementRule(pattern2166, replacement2166) return [rule2009, rule2010, rule2011, rule2012, rule2013, rule2014, rule2015, rule2016, rule2017, rule2018, rule2019, rule2020, rule2021, rule2022, rule2023, rule2024, rule2025, rule2026, rule2027, rule2028, rule2029, rule2030, rule2031, rule2032, rule2033, rule2034, rule2035, rule2036, rule2037, rule2038, rule2039, rule2040, rule2041, rule2042, rule2043, rule2044, rule2045, rule2046, rule2047, rule2048, rule2049, rule2050, rule2051, rule2052, rule2053, rule2054, rule2055, rule2056, rule2057, rule2058, rule2059, rule2060, rule2061, rule2062, rule2063, rule2064, rule2065, rule2066, rule2067, rule2068, rule2069, rule2070, rule2071, rule2072, rule2073, rule2074, rule2075, rule2076, rule2077, rule2078, rule2079, rule2080, rule2081, rule2082, rule2083, rule2084, rule2085, rule2086, rule2087, rule2088, rule2089, rule2090, rule2091, rule2092, rule2093, rule2094, rule2095, rule2096, rule2097, rule2098, rule2099, rule2100, rule2101, rule2102, rule2103, rule2104, rule2105, rule2106, rule2107, rule2108, rule2109, rule2110, rule2111, rule2112, rule2113, rule2114, rule2115, rule2116, rule2117, rule2118, rule2119, rule2120, rule2121, rule2122, rule2123, rule2124, rule2125, rule2126, rule2127, rule2128, rule2129, rule2130, rule2131, rule2132, rule2133, rule2134, rule2135, rule2136, rule2137, rule2138, rule2139, rule2140, rule2141, rule2142, rule2143, rule2144, rule2145, rule2146, rule2147, rule2148, rule2149, rule2150, rule2151, rule2152, rule2153, rule2154, rule2155, rule2156, rule2157, rule2158, rule2159, rule2160, rule2161, rule2162, rule2163, rule2164, rule2165, rule2166, ] def replacement2009(c, d, e, f, p, q, x): return Simp((e + f*x)*log(c*(d*(e + f*x)**p)**q)/f, x) - Simp(p*q*x, x) def replacement2010(a, b, c, d, e, f, n, p, q, x): return -Dist(b*n*p*q, Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1)), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)/f, x) def replacement2011(d, e, f, x): return Simp(LogIntegral(d*(e + f*x))/(d*f), x) def replacement2012(a, b, c, d, e, f, p, q, x): return Simp((c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*ExpIntegralEi((a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-a/(b*p*q))/(b*f*p*q), x) def replacement2013(a, b, c, d, e, f, p, q, x): return Simp(sqrt(Pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*Erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/Rt(b*p*q, S(2)))*Rt(b*p*q, S(2))*exp(-a/(b*p*q))/(b*f*p*q), x) def replacement2014(a, b, c, d, e, f, p, q, x): return Simp(sqrt(Pi)*(c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(e + f*x)*Erf(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))/Rt(-b*p*q, S(2)))*Rt(-b*p*q, S(2))*exp(-a/(b*p*q))/(b*f*p*q), x) def replacement2015(a, b, c, d, e, f, n, p, q, x): return -Dist(S(1)/(b*p*q*(n + S(1))), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1)), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1))*(e + f*x)/(b*f*p*q*(n + S(1))), x) def replacement2016(a, b, c, d, e, f, n, p, q, x): return Simp((c*(d*(e + f*x)**p)**q)**(-S(1)/(p*q))*(-(a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)*Gamma(n + S(1), -(a + b*log(c*(d*(e + f*x)**p)**q))/(b*p*q))*exp(-a/(b*p*q))/f, x) def replacement2017(a, b, c, d, e, f, g, h, p, q, x): return Simp(log(RemoveContent(a + b*log(c*(d*(e + f*x)**p)**q), x))/(b*h*p*q), x) def replacement2018(a, b, c, d, e, f, g, h, n, p, q, x): return Simp((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1))/(b*h*p*q*(n + S(1))), x) def replacement2019(a, b, c, d, e, f, g, h, m, n, p, q, x): return -Dist(b*n*p*q/(m + S(1)), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1))*(g + h*x)**m, x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**(m + S(1))/(h*(m + S(1))), x) def replacement2020(d, e, f, g, h, m, p, x): return Simp((h/f)**(p + S(-1))*LogIntegral(d*(e + f*x)**p)/(d*f*p), x) def replacement2021(d, e, f, g, h, m, p, x): return Dist((e + f*x)**(S(1) - p)*(g + h*x)**(p + S(-1)), Int((e + f*x)**(p + S(-1))/log(d*(e + f*x)**p), x), x) def replacement2022(a, b, c, d, e, f, g, h, m, p, q, x): return Simp((c*(d*(e + f*x)**p)**q)**(-(m + S(1))/(p*q))*(g + h*x)**(m + S(1))*ExpIntegralEi((a + b*log(c*(d*(e + f*x)**p)**q))*(m + S(1))/(b*p*q))*exp(-a*(m + S(1))/(b*p*q))/(b*h*p*q), x) def replacement2023(a, b, c, d, e, f, g, h, m, p, q, x): return Simp(sqrt(Pi)*(c*(d*(e + f*x)**p)**q)**(-(m + S(1))/(p*q))*(g + h*x)**(m + S(1))*Erfi(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*Rt((m + S(1))/(b*p*q), S(2)))*exp(-a*(m + S(1))/(b*p*q))/(b*h*p*q*Rt((m + S(1))/(b*p*q), S(2))), x) def replacement2024(a, b, c, d, e, f, g, h, m, p, q, x): return Simp(sqrt(Pi)*(c*(d*(e + f*x)**p)**q)**(-(m + S(1))/(p*q))*(g + h*x)**(m + S(1))*Erf(sqrt(a + b*log(c*(d*(e + f*x)**p)**q))*Rt(-(m + S(1))/(b*p*q), S(2)))*exp(-a*(m + S(1))/(b*p*q))/(b*h*p*q*Rt(-(m + S(1))/(b*p*q), S(2))), x) def replacement2025(a, b, c, d, e, f, g, h, m, n, p, q, x): return -Dist((m + S(1))/(b*p*q*(n + S(1))), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1))*(g + h*x)**m, x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1))*(g + h*x)**(m + S(1))/(b*h*p*q*(n + S(1))), x) def replacement2026(a, b, c, d, e, f, g, h, m, n, p, q, x): return Simp((c*(d*(e + f*x)**p)**q)**(-(m + S(1))/(p*q))*(-(a + b*log(c*(d*(e + f*x)**p)**q))*(m + S(1))/(b*p*q))**(-n)*(a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**(m + S(1))*Gamma(n + S(1), -(a + b*log(c*(d*(e + f*x)**p)**q))*(m + S(1))/(b*p*q))*exp(-a*(m + S(1))/(b*p*q))/(h*(m + S(1))), x) def replacement2027(c, e, f, g, h, x): return -Simp(PolyLog(S(2), -(g + h*x)*Together(c*f/h))/h, x) def replacement2028(a, b, c, e, f, g, h, x): return Dist(b, Int(log(-h*(e + f*x)/(-e*h + f*g))/(g + h*x), x), x) + Simp((a + b*log(c*(e - f*g/h)))*log(g + h*x)/h, x) def replacement2029(a, b, c, d, e, f, g, h, n, p, q, x): return -Dist(b*f*n*p*q/h, Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1))*log(f*(g + h*x)/(-e*h + f*g))/(e + f*x), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*log(f*(g + h*x)/(-e*h + f*g))/h, x) def replacement2030(a, b, c, d, e, f, g, h, m, p, q, x): return -Dist(b*f*p*q/(h*(m + S(1))), Int((g + h*x)**(m + S(1))/(e + f*x), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))*(g + h*x)**(m + S(1))/(h*(m + S(1))), x) def replacement2031(a, b, c, d, e, f, g, h, n, p, q, x): return -Dist(b*f*n*p*q/(-e*h + f*g), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1))/(g + h*x), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)/((g + h*x)*(-e*h + f*g)), x) def replacement2032(a, b, c, d, e, f, g, h, m, n, p, q, x): return -Dist(b*f*n*p*q/(h*(m + S(1))), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1))*(g + h*x)**(m + S(1))/(e + f*x), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**(m + S(1))/(h*(m + S(1))), x) def replacement2033(a, b, c, d, e, f, g, h, m, p, q, x): return Int(ExpandIntegrand((g + h*x)**m/(a + b*log(c*(d*(e + f*x)**p)**q)), x), x) def replacement2034(a, b, c, d, e, f, g, h, m, n, p, q, x): return -Dist((m + S(1))/(b*p*q*(n + S(1))), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1))*(g + h*x)**m, x), x) + Dist(m*(-e*h + f*g)/(b*f*p*q*(n + S(1))), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1))*(g + h*x)**(m + S(-1)), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(1))*(e + f*x)*(g + h*x)**m/(b*f*p*q*(n + S(1))), x) def replacement2035(a, b, c, d, e, f, g, h, m, n, p, q, x): return Int(ExpandIntegrand((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**m, x), x) def replacement2036(a, b, c, d, m, n, p, q, u, v, x): return Int((a + b*log(c*(d*ExpandToSum(v, x)**p)**q))**n*ExpandToSum(u, x)**m, x) def replacement2037(a, b, c, d, e, f, g, h, m, n, p, q, x): return Int((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**m, x) def replacement2038(c, e, f, g, h, i, j, x): return Simp(f*PolyLog(S(2), f*(i + j*x)/(j*(e + f*x)))/(h*(-e*j + f*i)), x) def replacement2039(a, b, c, e, f, g, h, i, j, x): return Dist(a, Int(S(1)/((g + h*x)*(i + j*x)), x), x) + Dist(b, Int(log(c/(e + f*x))/((g + h*x)*(i + j*x)), x), x) def With2040(a, b, c, d, e, f, g, h, i, j, m, p, q, x): u = IntHide((i + j*x)**m/(g + h*x), x) return -Dist(b*h*p*q, Int(SimplifyIntegrand(u/(g + h*x), x), x), x) + Dist(a + b*log(c*(d*(e + f*x)**p)**q), u, x) def replacement2041(a, b, c, e, f, g, h, i, j, m, n, x): return Dist(c**(-m)*f**(-m)/h, Subst(Int((a + b*x)**n*(-c*e*j + c*f*i + j*exp(x))**m, x), x, log(c*(e + f*x))), x) def With2042(a, b, c, d, e, f, g, h, i, j, m, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((a + b*log(c*(d*(e + f*x)**p)**q))**n, (i + j*x)**m/(g + h*x), x) if SumQ(u): return True return False def replacement2042(a, b, c, d, e, f, g, h, i, j, m, n, p, q, x): u = ExpandIntegrand((a + b*log(c*(d*(e + f*x)**p)**q))**n, (i + j*x)**m/(g + h*x), x) return Int(u, x) def replacement2043(a, b, c, d, e, f, g, h, i, j, m, n, p, q, x): return Int((a + b*log(c*(d*(e + f*x)**p)**q))**n*(i + j*x)**m/(g + h*x), x) def replacement2044(c, e, f, g, h, x): return -Simp(f*PolyLog(S(2), (-e + f*x)/(e + f*x))/(S(2)*e*h), x) def replacement2045(a, b, c, e, f, g, h, x): return Dist(b, Int(log(S(2)*e/(e + f*x))/(g + h*x**S(2)), x), x) + Dist(a + b*log(c/(S(2)*e)), Int(S(1)/(g + h*x**S(2)), x), x) def replacement2046(a, b, c, d, e, f, g, h, i, p, q, x): return Dist(e*f, Int((a + b*log(c*(d*(e + f*x)**p)**q))/((e + f*x)*(e*i*x + f*g)), x), x) def replacement2047(a, b, c, d, e, f, g, i, p, q, x): return Dist(e*f, Int((a + b*log(c*(d*(e + f*x)**p)**q))/((e + f*x)*(e*i*x + f*g)), x), x) def With2048(a, b, c, d, e, f, g, h, p, q, x): u = IntHide(S(1)/sqrt(g + h*x**S(2)), x) return -Dist(b*f*p*q, Int(SimplifyIntegrand(u/(e + f*x), x), x), x) + Simp(u*(a + b*log(c*(d*(e + f*x)**p)**q)), x) def With2049(a, b, c, d, e, f, g1, g2, h1, h2, p, q, x): u = IntHide(S(1)/sqrt(g1*g2 + h1*h2*x**S(2)), x) return -Dist(b*f*p*q, Int(SimplifyIntegrand(u/(e + f*x), x), x), x) + Simp(u*(a + b*log(c*(d*(e + f*x)**p)**q)), x) def replacement2050(a, b, c, d, e, f, g, h, p, q, x): return Dist(sqrt(S(1) + h*x**S(2)/g)/sqrt(g + h*x**S(2)), Int((a + b*log(c*(d*(e + f*x)**p)**q))/sqrt(S(1) + h*x**S(2)/g), x), x) def replacement2051(a, b, c, d, e, f, g1, g2, h1, h2, p, q, x): return Dist(sqrt(S(1) + h1*h2*x**S(2)/(g1*g2))/(sqrt(g1 + h1*x)*sqrt(g2 + h2*x)), Int((a + b*log(c*(d*(e + f*x)**p)**q))/sqrt(S(1) + h1*h2*x**S(2)/(g1*g2)), x), x) def replacement2052(a, b, c, d, e, f, g, h, i, j, k, n, p, q, x): return Dist(b*f*n*p*q/h, Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1))*PolyLog(S(2), Together(-i*(j + k*x) + S(1)))/(e + f*x), x), x) - Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*PolyLog(S(2), Together(-i*(j + k*x) + S(1)))/h, x) def replacement2053(a, b, c, d, e, f, g, h, i, j, k, m, n, p, q, x): return Dist(b*f*n*p*q/(h*m), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1))*PolyLog(S(2), -i*(j + k*x)**m)/(e + f*x), x), x) - Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*PolyLog(S(2), -i*(j + k*x)**m)/(h*m), x) def replacement2054(a, b, c, d, e, f, g, h, i, j, k, m, n, p, q, r, x): return -Dist(b*f*n*p*q/(h*m), Int((a + b*log(c*(d*(e + f*x)**p)**q))**(n + S(-1))*PolyLog(r + S(1), i*(j + k*x)**m)/(e + f*x), x), x) + Simp((a + b*log(c*(d*(e + f*x)**p)**q))**n*PolyLog(r + S(1), i*(j + k*x)**m)/(h*m), x) def With2055(F, Px, a, b, c, d, e, f, g, h, m, p, q, x): u = IntHide(Px*F(g + h*x)**m, x) return -Dist(b*f*p*q, Int(SimplifyIntegrand(u/(e + f*x), x), x), x) + Dist(a + b*log(c*(d*(e + f*x)**p)**q), u, x) def replacement2056(a, b, c, d, e, f, m, n, p, q, x): return Dist(S(1)/m, Subst(Int((a + b*log(c*(d*(e + f*x)**p)**q))**n/x, x), x, x**m), x) def replacement2057(a, b, c, d, e, f, m, n, p, q, r, x): return Dist(S(1)/m, Subst(Int((a + b*log(c*(d*(e + f*x)**p)**q))**n/x, x), x, x**m), x) def replacement2058(a, b, c, d, e, f, n, p, q, r, r1, x): return Dist(S(1)/r, Subst(Int((a + b*log(c*(d*(e + f*x)**p)**q))**n, x), x, x**r), x) def replacement2059(a, b, c, d, e, f, g, h, m, n, p, q, r, r1, x): return Dist(S(1)/r, Subst(Int((a + b*log(c*(d*(e + f*x)**p)**q))**n*(g + h*x)**m, x), x, x**r), x) def With2060(a, b, c, d, e, n, x): u = IntHide(S(1)/(d + e*x**S(2)), x) return -Dist(b*n, Int(u/x, x), x) + Dist(a + b*log(c*x**n), u, x) def replacement2061(a, b, c, d, e, mn, n, x): return Simp(PolyLog(S(2), -Together(b*c*x**(-n)*(d + e*x**n)/d))/(d*n), x) def replacement2062(a, b, c, d, e, mn, n, x): return Simp(PolyLog(S(2), -Together(b*c*x**(-n)*(d + e*x**n)/d))/(d*n), x) def replacement2063(Px, a, b, c, d, e, f, n, p, q, x): return Int(ExpandIntegrand(Px*(a + b*log(c*(d*(e + f*x)**p)**q))**n, x), x) def With2064(RFx, a, b, c, d, e, f, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((a + b*log(c*(d*(e + f*x)**p)**q))**n, RFx, x) if SumQ(u): return True return False def replacement2064(RFx, a, b, c, d, e, f, n, p, q, x): u = ExpandIntegrand((a + b*log(c*(d*(e + f*x)**p)**q))**n, RFx, x) return Int(u, x) def With2065(RFx, a, b, c, d, e, f, n, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(RFx*(a + b*log(c*(d*(e + f*x)**p)**q))**n, x) if SumQ(u): return True return False def replacement2065(RFx, a, b, c, d, e, f, n, p, q, x): u = ExpandIntegrand(RFx*(a + b*log(c*(d*(e + f*x)**p)**q))**n, x) return Int(u, x) def replacement2066(a, b, c, d, e, f, g, n, p, q, u, x): return Int(u*(a + b*log(c*(S(4)**(-p)*d*g**(-p)*(f + S(2)*g*x)**(S(2)*p))**q))**n, x) def replacement2067(a, b, c, d, n, p, q, u, v, x): return Int(u*(a + b*log(c*(d*ExpandToSum(v, x)**p)**q))**n, x) def replacement2068(a, b, c, n, p, q, r, x): return Subst(Int(log(x**(n*p*q))**r, x), x**(n*p*q), a*(b*(c*x**n)**p)**q) def replacement2069(a, b, c, m, n, p, q, r, x): return Subst(Int(x**m*log(x**(n*p*q))**r, x), x**(n*p*q), a*(b*(c*x**n)**p)**q) def replacement2070(a, b, c, d, e, e1, n, p, u, x): return Dist(log(e*(b*e1/d)**n)**p, Int(u, x), x) def replacement2071(a, b, c, d, e, e1, n, n1, n2, p, x): return -Dist(n*n1*p*(-a*d + b*c)/b, Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**(p + S(-1))/(c + d*x), x), x) + Simp((a + b*x)*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/b, x) def replacement2072(a, b, c, d, e, f, g, x): return Simp(PolyLog(S(2), Together(-a*e + c)/(c + d*x))/g, x) def replacement2073(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(n*n1*p*(-a*d + b*c)/g, Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**(p + S(-1))*log((-a*d + b*c)/(b*(c + d*x)))/((a + b*x)*(c + d*x)), x), x) - Simp(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p*log((-a*d + b*c)/(b*(c + d*x)))/g, x) def replacement2074(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(n*n1*p*(-a*d + b*c)/g, Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**(p + S(-1))*log(-(-a*d + b*c)/(d*(a + b*x)))/((a + b*x)*(c + d*x)), x), x) - Simp(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p*log(-(-a*d + b*c)/(d*(a + b*x)))/g, x) def replacement2075(a, b, c, d, e, e1, f, g, n, n1, n2, x): return -Dist(n*n1*(-a*d + b*c)/g, Int(log(f + g*x)/((a + b*x)*(c + d*x)), x), x) + Simp(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)*log(f + g*x)/g, x) def replacement2076(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(d/g, Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/(c + d*x), x), x) - Dist((-c*g + d*f)/g, Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/((c + d*x)*(f + g*x)), x), x) def replacement2077(a, b, c, d, e, f, g, x): return Simp(d**S(2)*LogIntegral(e*(a + b*x)/(c + d*x))/(e*g**S(2)*(-a*d + b*c)), x) def replacement2078(a, b, c, d, e, e1, f, g, n, n1, n2, x): return Simp(d**S(2)*(e*(e1*(a + b*x)**n1*(c + d*x)**n2)**n)**(-S(1)/(n*n1))*(a + b*x)*ExpIntegralEi(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)/(n*n1))/(g**S(2)*n*n1*(c + d*x)*(-a*d + b*c)), x) def replacement2079(a, b, c, d, e, e1, f, g, n, n1, n2, x): return Simp(b**S(2)*(e*(e1*(a + b*x)**n1*(c + d*x)**n2)**n)**(S(1)/(n*n1))*(c + d*x)*ExpIntegralEi(-log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)/(n*n1))/(g**S(2)*n*n1*(a + b*x)*(-a*d + b*c)), x) def replacement2080(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return -Dist(n*n1*p*(-a*d + b*c)/(-a*g + b*f), Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**(p + S(-1))/((c + d*x)*(f + g*x)), x), x) + Simp((a + b*x)*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/((f + g*x)*(-a*g + b*f)), x) def replacement2081(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return -Dist(n*n1*p*(-a*d + b*c)/(-c*g + d*f), Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**(p + S(-1))/((a + b*x)*(f + g*x)), x), x) + Simp((c + d*x)*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/((f + g*x)*(-c*g + d*f)), x) def replacement2082(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(b/(-a*g + b*f), Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/(f + g*x)**S(2), x), x) - Dist(g/(-a*g + b*f), Int((a + b*x)*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/(f + g*x)**S(3), x), x) def replacement2083(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(d/(-c*g + d*f), Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/(f + g*x)**S(2), x), x) - Dist(g/(-c*g + d*f), Int((c + d*x)*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/(f + g*x)**S(3), x), x) def replacement2084(a, b, c, d, e, e1, f, g, m, n, n1, n2, p, x): return -Dist(n*n1*p*(-a*d + b*c)/(g*(m + S(1))), Int((f + g*x)**(m + S(1))*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) + Simp((f + g*x)**(m + S(1))*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/(g*(m + S(1))), x) def replacement2085(a, b, c, d, e, m, m2, n, p, u, x): return -Dist(n*p/(m + S(1)), Int((a + b*x)**m*(c + d*x)**(-m + S(-2))*log(e*u**n)**(p + S(-1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(-m + S(-1))*log(e*u**n)**p/((m + S(1))*(-a*d + b*c)), x) def replacement2086(a, b, c, d, m, m2, p, u, x): return -Dist(p/(m + S(1)), Int((a + b*x)**m*(c + d*x)**(-m + S(-2))*log(u)**(p + S(-1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(-m + S(-1))*log(u)**p/((m + S(1))*(-a*d + b*c)), x) def replacement2087(a, b, c, d, e, m, m2, n, u, x): return Simp((e*u**n)**(-(m + S(1))/n)*(a + b*x)**(m + S(1))*(c + d*x)**(-m + S(-1))*ExpIntegralEi((m + S(1))*log(e*u**n)/n)/(n*(-a*d + b*c)), x) def replacement2088(a, b, c, d, m, m2, u, x): return Simp(u**(-m + S(-1))*(a + b*x)**(m + S(1))*(c + d*x)**(-m + S(-1))*ExpIntegralEi((m + S(1))*log(u))/(-a*d + b*c), x) def replacement2089(a, b, c, d, e, m, m2, n, p, u, x): return -Dist((m + S(1))/(n*(p + S(1))), Int((a + b*x)**m*(c + d*x)**(-m + S(-2))*log(e*u**n)**(p + S(1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(-m + S(-1))*log(e*u**n)**(p + S(1))/(n*(p + S(1))*(-a*d + b*c)), x) def replacement2090(a, b, c, d, m, m2, p, u, x): return -Dist((m + S(1))/(p + S(1)), Int((a + b*x)**m*(c + d*x)**(-m + S(-2))*log(u)**(p + S(1)), x), x) + Simp((a + b*x)**(m + S(1))*(c + d*x)**(-m + S(-1))*log(u)**(p + S(1))/((p + S(1))*(-a*d + b*c)), x) def replacement2091(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(d/g, Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/(c + d*x)**S(2), x), x) def replacement2092(a, b, c, d, e, f, g, x): return Simp(PolyLog(S(2), -(f + g*x)*(a*e - c)/(f*(c + d*x)))/(-c*g + d*f), x) def replacement2093(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(n*n1*p*(-a*d + b*c)/(-c*g + d*f), Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**(p + S(-1))*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/((a + b*x)*(c + d*x)), x), x) - Simp(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p*log((f + g*x)*(-a*d + b*c)/((c + d*x)*(-a*g + b*f)))/(-c*g + d*f), x) def replacement2094(a, b, c, d, e, f, g, x): return Simp(c*PolyLog(S(2), -(c - d*x)*(a*e - c)/(c*(c + d*x)))/(S(2)*d*f), x) def replacement2095(a, b, c, d, e, e1, f, g, h, n, n1, n2, p, x): return Dist(d**S(2), Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/((c + d*x)*(-c*h + d*g + d*h*x)), x), x) def replacement2096(a, b, c, d, e, e1, f, h, n, n1, n2, p, x): return -Dist(d**S(2)/h, Int(log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/((c - d*x)*(c + d*x)), x), x) def replacement2097(a, b, c, d, e, e1, f, g, n, n1, n2, p, x): return Dist(b/(g*n*n1*(-a*d + b*c)), Subst(Int(x**p, x), x, log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)), x) def replacement2098(a, b, c, d, e, n, p, u, v, x): return Dist(n*p, Int(PolyLog(S(2), Together(S(1) - v))*log(e*u**n)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) - Simp(PolyLog(S(2), Together(S(1) - v))*log(e*u**n)**p/(-a*d + b*c), x) def replacement2099(a, b, c, d, p, u, v, x): return Dist(p, Int(PolyLog(S(2), Together(S(1) - v))*log(u)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) - Simp(PolyLog(S(2), Together(S(1) - v))*log(u)**p/(-a*d + b*c), x) def With2100(a, b, c, d, e, n, p, u, v, x): f = (S(1) - v)/u return Dist(f/(n*(p + S(1))), Int(log(e*u**n)**(p + S(1))/((c + d*x)*(-a*f - b*f + c + d)), x), x) + Simp(log(v)*log(e*u**n)**(p + S(1))/(n*(p + S(1))*(-a*d + b*c)), x) def With2101(a, b, c, d, p, u, v, x): f = (S(1) - v)/u return Dist(f/(p + S(1)), Int(log(u)**(p + S(1))/((c + d*x)*(-a*f - b*f + c + d)), x), x) + Simp(log(u)**(p + S(1))*log(v)/((p + S(1))*(-a*d + b*c)), x) def replacement2102(a, b, c, d, e, n, p, u, v, x): return -Dist(n*p, Int(PolyLog(S(2), Together(S(1) - v))*log(e*u**n)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(S(2), Together(S(1) - v))*log(e*u**n)**p/(-a*d + b*c), x) def replacement2103(a, b, c, d, p, u, v, x): return -Dist(p, Int(PolyLog(S(2), Together(S(1) - v))*log(u)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(S(2), Together(S(1) - v))*log(u)**p/(-a*d + b*c), x) def With2104(a, b, c, d, e, n, p, u, v, x): f = u*(S(1) - v) return -Dist(f/(n*(p + S(1))), Int(log(e*u**n)**(p + S(1))/((a + b*x)*(a + b - c*f - d*f)), x), x) + Simp(log(v)*log(e*u**n)**(p + S(1))/(n*(p + S(1))*(-a*d + b*c)), x) def With2105(a, b, c, d, p, u, v, x): f = u*(S(1) - v) return -Dist(f/(p + S(1)), Int(log(u)**(p + S(1))/((a + b*x)*(a + b - c*f - d*f)), x), x) + Simp(log(u)**(p + S(1))*log(v)/((p + S(1))*(-a*d + b*c)), x) def replacement2106(a, b, c, d, e, n, p, q, u, v, x): return -Dist(n*p, Int(PolyLog(q + S(1), v)*log(e*u**n)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(q + S(1), v)*log(e*u**n)**p/(-a*d + b*c), x) def replacement2107(a, b, c, d, p, q, u, v, x): return -Dist(p, Int(PolyLog(q + S(1), v)*log(u)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(q + S(1), v)*log(u)**p/(-a*d + b*c), x) def replacement2108(a, b, c, d, e, n, p, q, u, v, x): return -Dist(S(1)/(n*(p + S(1))), Int(PolyLog(q + S(-1), v)*log(e*u**n)**(p + S(1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(q, v)*log(e*u**n)**(p + S(1))/(n*(p + S(1))*(-a*d + b*c)), x) def replacement2109(a, b, c, d, p, q, u, v, x): return -Dist(S(1)/(p + S(1)), Int(PolyLog(q + S(-1), v)*log(u)**(p + S(1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(q, v)*log(u)**(p + S(1))/((p + S(1))*(-a*d + b*c)), x) def replacement2110(a, b, c, d, e, n, p, q, u, v, x): return Dist(n*p, Int(PolyLog(q + S(1), v)*log(e*u**n)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) - Simp(PolyLog(q + S(1), v)*log(e*u**n)**p/(-a*d + b*c), x) def replacement2111(a, b, c, d, p, q, u, v, x): return Dist(p, Int(PolyLog(q + S(1), v)*log(u)**(p + S(-1))/((a + b*x)*(c + d*x)), x), x) - Simp(PolyLog(q + S(1), v)*log(u)**p/(-a*d + b*c), x) def replacement2112(a, b, c, d, e, n, p, q, u, v, x): return Dist(S(1)/(n*(p + S(1))), Int(PolyLog(q + S(-1), v)*log(e*u**n)**(p + S(1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(q, v)*log(e*u**n)**(p + S(1))/(n*(p + S(1))*(-a*d + b*c)), x) def replacement2113(a, b, c, d, p, q, u, v, x): return Dist(S(1)/(p + S(1)), Int(PolyLog(q + S(-1), v)*log(u)**(p + S(1))/((a + b*x)*(c + d*x)), x), x) + Simp(PolyLog(q, v)*log(u)**(p + S(1))/((p + S(1))*(-a*d + b*c)), x) def replacement2114(a, b, c, d, e, e1, f, g, h, n, n1, n2, p, u, x): return Dist(b*d/h, Int(u*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/((a + b*x)*(c + d*x)), x), x) def replacement2115(a, b, c, d, e, e1, f, h, n, n1, n2, p, u, x): return Dist(b*d/h, Int(u*log(e*(e1*(a + b*x)**n1*(c + d*x)**(-n1))**n)**p/((a + b*x)*(c + d*x)), x), x) def With2116(a, b, c, d, e, e1, f, g, h, n, n1, n2, x): u = IntHide(S(1)/(f + g*x + h*x**S(2)), x) return -Dist(n*(-a*d + b*c), Int(u/((a + b*x)*(c + d*x)), x), x) + Simp(u*log(e*(e1*(a + b*x)**n1*(c + d*x)**n2)**n), x) def With2117(a, b, c, d, e, e1, f, h, n, n1, n2, x): u = IntHide(S(1)/(f + h*x**S(2)), x) return -Dist(n*(-a*d + b*c), Int(u/((a + b*x)*(c + d*x)), x), x) + Simp(u*log(e*(e1*(a + b*x)**n1*(c + d*x)**n2)**n), x) def With2118(RFx, a, b, c, d, e, e1, n, n1, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(log(e*(e1*(a + b*x)**n1*(c + d*x)**n2)**n)**p, RFx, x) if SumQ(u): return True return False def replacement2118(RFx, a, b, c, d, e, e1, n, n1, n2, p, x): u = ExpandIntegrand(log(e*(e1*(a + b*x)**n1*(c + d*x)**n2)**n)**p, RFx, x) return Int(u, x) def With2119(p, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False lst = QuotientOfLinearsParts(v, x) if Not(And(OneQ(p), ZeroQ(Part(lst, S(3))))): return True return False def replacement2119(p, u, v, x): lst = QuotientOfLinearsParts(v, x) return Int(u*log((x*Part(lst, S(2)) + Part(lst, S(1)))/(x*Part(lst, S(4)) + Part(lst, S(3))))**p, x) def replacement2120(a, b, c, n, p, x): return -Dist(b*n*p, Int(x**n/(a + b*x**n), x), x) + Simp(x*log(c*(a + b*x**n)**p), x) def replacement2121(c, p, v, x): return Int(log(c*ExpandToSum(v, x)**p), x) def replacement2122(a, b, c, d, e, f, g, n, p, x): return -Dist(b*e*n*p/g, Int(x**(n + S(-1))*log(f + g*x)/(d + e*x**n), x), x) + Simp((a + b*log(c*(d + e*x**n)**p))*log(f + g*x)/g, x) def replacement2123(a, b, c, d, e, f, g, m, n, p, x): return -Dist(b*e*n*p/(g*(m + S(1))), Int(x**(n + S(-1))*(f + g*x)**(m + S(1))/(d + e*x**n), x), x) + Simp((a + b*log(c*(d + e*x**n)**p))*(f + g*x)**(m + S(1))/(g*(m + S(1))), x) def replacement2124(a, b, c, m, p, u, v, x): return Int((a + b*log(c*ExpandToSum(v, x)**p))*ExpandToSum(u, x)**m, x) def With2125(a, b, c, d, e, f, g, m, n, p, x): w = IntHide(asin(f + g*x)**m, x) return -Dist(b*e*n*p, Int(SimplifyIntegrand(w*x**(n + S(-1))/(d + e*x**n), x), x), x) + Dist(a + b*log(c*(d + e*x**n)**p), w, x) def With2126(a, b, c, d, e, f, g, p, x): u = IntHide(S(1)/(f + g*x**S(2)), x) return -Dist(S(2)*b*e*p, Int(u*x/(d + e*x**S(2)), x), x) + Simp(u*(a + b*log(c*(d + e*x**S(2))**p)), x) def replacement2127(a, b, c, d, e, n, p, x): return -Dist(S(2)*b*e*n*p, Int(x**S(2)*(a + b*log(c*(d + e*x**S(2))**p))**(n + S(-1))/(d + e*x**S(2)), x), x) + Simp(x*(a + b*log(c*(d + e*x**S(2))**p))**n, x) def replacement2128(a, b, c, d, e, m, n, p, x): return Dist(S(1)/2, Subst(Int(x**(m/S(2) + S(-1)/2)*(a + b*log(c*(d + e*x)**p))**n, x), x, x**S(2)), x) def replacement2129(a, b, c, d, e, m, n, p, x): return -Dist(S(2)*b*e*n*p/(m + S(1)), Int(x**(m + S(2))*(a + b*log(c*(d + e*x**S(2))**p))**(n + S(-1))/(d + e*x**S(2)), x), x) + Simp(x**(m + S(1))*(a + b*log(c*(d + e*x**S(2))**p))**n/(m + S(1)), x) def With2130(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: w = DerivativeDivides(v, u*(S(1) - v), x) res = Not(FalseQ(w)) except (TypeError, AttributeError): return False if res: return True return False def replacement2130(u, v, x): w = DerivativeDivides(v, u*(S(1) - v), x) return Simp(w*PolyLog(S(2), Together(S(1) - v)), x) def With2131(a, b, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False try: z = DerivativeDivides(v, w*(S(1) - v), x) res = Not(FalseQ(z)) except (TypeError, AttributeError): return False if res: return True return False def replacement2131(a, b, u, v, w, x): z = DerivativeDivides(v, w*(S(1) - v), x) return -Dist(b, Int(SimplifyIntegrand(z*D(u, x)*PolyLog(S(2), Together(S(1) - v))/u, x), x), x) + Simp(z*(a + b*log(u))*PolyLog(S(2), Together(S(1) - v)), x) def replacement2132(a, b, c, d, e, n, p, x): return -Dist(b*n*p, Int(S(1)/(a*(d + e*x)**(-n) + b), x), x) + Simp((d + e*x)*log(c*(a + b*(d + e*x)**n)**p)/e, x) def replacement2133(a, b, c, d, e, n, p, x): return Dist(a*n*p, Int(S(1)/(a + b*(d + e*x)**n), x), x) + Simp((d + e*x)*log(c*(a + b*(d + e*x)**n)**p)/e, x) - Simp(n*p*x, x) def replacement2134(a, b, c, d, e, f, g, n, p, x): return -Dist(b*e*n*p/(d*g), Subst(Int((a + b*log(c*(d + e*x)**p))**(n + S(-1))/x, x), x, S(1)/(f + g*x)), x) + Simp((a + b*log(c*(d + e/(f + g*x))**p))**n*(d*(f + g*x) + e)/(d*g), x) def replacement2135(RFx, a, b, c, n, p, x): return -Dist(b*n*p, Int(SimplifyIntegrand(x*(a + b*log(RFx**p*c))**(n + S(-1))*D(RFx, x)/RFx, x), x), x) + Simp(x*(a + b*log(RFx**p*c))**n, x) def replacement2136(RFx, a, b, c, d, e, n, p, x): return -Dist(b*n*p/e, Int((a + b*log(RFx**p*c))**(n + S(-1))*D(RFx, x)*log(d + e*x)/RFx, x), x) + Simp((a + b*log(RFx**p*c))**n*log(d + e*x)/e, x) def replacement2137(RFx, a, b, c, d, e, m, n, p, x): return -Dist(b*n*p/(e*(m + S(1))), Int(SimplifyIntegrand((a + b*log(RFx**p*c))**(n + S(-1))*(d + e*x)**(m + S(1))*D(RFx, x)/RFx, x), x), x) + Simp((a + b*log(RFx**p*c))**n*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def With2138(RFx, c, d, e, n, x): u = IntHide(S(1)/(d + e*x**S(2)), x) return -Dist(n, Int(SimplifyIntegrand(u*D(RFx, x)/RFx, x), x), x) + Simp(u*log(RFx**n*c), x) def With2139(Px, Qx, c, n, x): u = IntHide(S(1)/Qx, x) return -Dist(n, Int(SimplifyIntegrand(u*D(Px, x)/Px, x), x), x) + Simp(u*log(Px**n*c), x) def With2140(RFx, RGx, a, b, c, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand((a + b*log(RFx**p*c))**n, RGx, x) if SumQ(u): return True return False def replacement2140(RFx, RGx, a, b, c, n, p, x): u = ExpandIntegrand((a + b*log(RFx**p*c))**n, RGx, x) return Int(u, x) def With2141(RFx, RGx, a, b, c, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = ExpandIntegrand(RGx*(a + b*log(RFx**p*c))**n, x) if SumQ(u): return True return False def replacement2141(RFx, RGx, a, b, c, n, p, x): u = ExpandIntegrand(RGx*(a + b*log(RFx**p*c))**n, x) return Int(u, x) def With2142(RFx, a, b, u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = SubstForFractionalPowerOfLinear(RFx*(a + b*log(u)), x) res = Not(FalseQ(lst)) except (TypeError, AttributeError): return False if res: return True return False def replacement2142(RFx, a, b, u, x): lst = SubstForFractionalPowerOfLinear(RFx*(a + b*log(u)), x) return Dist(Part(lst, S(2))*Part(lst, S(4)), Subst(Int(Part(lst, S(1)), x), x, Part(lst, S(3))**(S(1)/Part(lst, S(2)))), x) def replacement2143(F, a, b, c, e, f, g, m, n, x): return Dist(g*m/(b*c*n*log(F)), Int((f + g*x)**(m + S(-1))*PolyLog(S(2), -e*(F**(c*(a + b*x)))**n), x), x) - Simp((f + g*x)**m*PolyLog(S(2), -e*(F**(c*(a + b*x)))**n)/(b*c*n*log(F)), x) def replacement2144(F, a, b, c, d, e, f, g, m, n, x): return Int((f + g*x)**m*log(S(1) + e*(F**(c*(a + b*x)))**n/d), x) - Simp((f + g*x)**(m + S(1))*log(S(1) + e*(F**(c*(a + b*x)))**n/d)/(g*(m + S(1))), x) + Simp((f + g*x)**(m + S(1))*log(d + e*(F**(c*(a + b*x)))**n)/(g*(m + S(1))), x) def replacement2145(a, b, c, d, e, f, x): return Dist(f**S(2)*(-S(4)*a*c + b**S(2))/S(2), Int(x/(-f*sqrt(a + b*x + c*x**S(2))*(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d)) + (-b*f**S(2) + S(2)*d*e)*(a + b*x + c*x**S(2))), x), x) + Simp(x*log(d + e*x + f*sqrt(a + b*x + c*x**S(2))), x) def replacement2146(a, c, d, e, f, x): return -Dist(a*c*f**S(2), Int(x/(d*e*(a + c*x**S(2)) + f*sqrt(a + c*x**S(2))*(a*e - c*d*x)), x), x) + Simp(x*log(d + e*x + f*sqrt(a + c*x**S(2))), x) def replacement2147(a, b, c, d, e, f, g, m, x): return Dist(f**S(2)*(-S(4)*a*c + b**S(2))/(S(2)*g*(m + S(1))), Int((g*x)**(m + S(1))/(-f*sqrt(a + b*x + c*x**S(2))*(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d)) + (-b*f**S(2) + S(2)*d*e)*(a + b*x + c*x**S(2))), x), x) + Simp((g*x)**(m + S(1))*log(d + e*x + f*sqrt(a + b*x + c*x**S(2)))/(g*(m + S(1))), x) def replacement2148(a, c, d, e, f, g, m, x): return -Dist(a*c*f**S(2)/(g*(m + S(1))), Int((g*x)**(m + S(1))/(d*e*(a + c*x**S(2)) + f*sqrt(a + c*x**S(2))*(a*e - c*d*x)), x), x) + Simp((g*x)**(m + S(1))*log(d + e*x + f*sqrt(a + c*x**S(2)))/(g*(m + S(1))), x) def replacement2149(d, e, f, u, v, x): return Int(v*log(d + e*x + f*sqrt(ExpandToSum(u, x))), x) def replacement2150(u, x): return -Int(SimplifyIntegrand(x*D(u, x)/u, x), x) + Simp(x*log(u), x) def replacement2151(a, b, u, x): return -Dist(S(1)/b, Int(SimplifyIntegrand(D(u, x)*log(a + b*x)/u, x), x), x) + Simp(log(u)*log(a + b*x)/b, x) def replacement2152(a, b, m, u, x): return -Dist(S(1)/(b*(m + S(1))), Int(SimplifyIntegrand((a + b*x)**(m + S(1))*D(u, x)/u, x), x), x) + Simp((a + b*x)**(m + S(1))*log(u)/(b*(m + S(1))), x) def With2153(Qx, u, x): v = IntHide(S(1)/Qx, x) return -Int(SimplifyIntegrand(v*D(u, x)/u, x), x) + Simp(v*log(u), x) def replacement2154(a, u, x): return -Int(SimplifyIntegrand(u**(a*x + S(-1))*x*D(u, x), x), x) + Simp(u**(a*x)/a, x) def With2155(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False w = IntHide(v, x) if InverseFunctionFreeQ(w, x): return True return False def replacement2155(u, v, x): w = IntHide(v, x) return Dist(log(u), w, x) - Int(SimplifyIntegrand(w*D(u, x)/u, x), x) def replacement2156(v, w, x): return -Int(SimplifyIntegrand(x*D(v, x)*log(w)/v, x), x) - Int(SimplifyIntegrand(x*D(w, x)*log(v)/w, x), x) + Simp(x*log(v)*log(w), x) def With2157(u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False z = IntHide(u, x) if InverseFunctionFreeQ(z, x): return True return False def replacement2157(u, v, w, x): z = IntHide(u, x) return Dist(log(v)*log(w), z, x) - Int(SimplifyIntegrand(z*D(v, x)*log(w)/v, x), x) - Int(SimplifyIntegrand(z*D(w, x)*log(v)/w, x), x) def replacement2158(a, b, n, p, x): return -Dist(n*p, Int(S(1)/log(b*x**n), x), x) + Simp(x*log(a*log(b*x**n)**p), x) def replacement2159(a, b, n, p, x): return Simp((-p + log(a*log(b*x**n)**p))*log(b*x**n)/n, x) def replacement2160(a, b, m, n, p, x): return -Dist(n*p/(m + S(1)), Int(x**m/log(b*x**n), x), x) + Simp(x**(m + S(1))*log(a*log(b*x**n)**p)/(m + S(1)), x) def replacement2161(A, B, a, b, c, d, x): return Dist(B/b, Int(sqrt(a + b*log(c + d*x)), x), x) + Dist((A*b - B*a)/b, Int(S(1)/sqrt(a + b*log(c + d*x)), x), x) def replacement2162(a, f, u, x): return Int(u**(a*log(f)), x) def With2163(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = FunctionOfLog(u*x, x) res = Not(FalseQ(lst)) except (TypeError, AttributeError): return False if res: return True return False def replacement2163(u, x): lst = FunctionOfLog(u*x, x) return Dist(S(1)/Part(lst, S(3)), Subst(Int(Part(lst, S(1)), x), x, log(Part(lst, S(2)))), x) def replacement2164(u, v, x): return Dist(-LogGamma(v) + log(Gamma(v)), Int(u, x), x) + Int(u*LogGamma(v), x) def replacement2165(a, b, n, p, u, v, w, x): return Int(u*w**p*(a + b*log(v)**n)**p, x) def replacement2166(a, b, c, d, e, f, n, p, q, u, x): return Int(u*(a + b*log(c*(d*(e + f*x)**p)**q))**n, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/miscellaneous_algebraic.py000066400000000000000000007062611412543434000264110ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def miscellaneous_algebraic(): from sympy.integrals.rubi.constraints import cons800, cons2, cons3, cons8, cons52, cons4, cons5, cons20, cons19, cons801, cons29, cons50, cons127, cons54, cons802, cons27, cons803, cons804, cons151, cons805, cons502, cons806, cons650, cons807, cons808, cons21, cons48, cons809, cons810, cons70, cons811, cons812, cons813, cons814, cons815, cons816, cons817, cons818, cons819, cons820, cons821, cons822, cons823, cons454, cons824, cons825, cons826, cons827, cons828, cons829, cons830, cons831, cons832, cons833, cons834, cons835, cons836, cons837, cons838, cons839, cons840, cons841, cons842, cons843, cons844, cons845, cons846, cons847, cons848, cons849, cons850, cons851, cons852, cons853, cons854, cons210, cons211, cons66, cons855, cons68, cons856, cons857, cons466, cons858, cons859, cons860, cons55, cons13, cons139, cons861, cons862, cons150, cons246, cons165, cons863, cons523, cons864, cons865, cons866, cons86, cons867, cons36, cons37, cons868, cons470, cons471, cons869, cons870, cons38, cons871, cons872, cons873, cons874, cons875, cons876, cons877, cons878, cons879, cons880, cons881, cons882, cons883, cons884, cons885, cons886, cons887, cons888, cons889, cons890, cons891, cons892, cons893, cons894, cons895, cons896, cons897, cons898, cons899, cons900, cons901, cons902, cons903, cons904, cons905, cons906, cons676, cons907, cons483, cons908, cons909, cons484, cons910, cons911, cons912, cons913, cons914, cons915, cons916, cons917, cons918, cons87, cons33, cons96, cons919, cons198, cons369, cons358, cons491, cons543, cons25, cons920, cons556, cons921, cons554, cons57, cons496, cons59, cons60, cons61, cons62, cons922, cons923, cons924, cons925, cons926, cons597, cons73, cons927, cons588, cons89, cons130, cons928, cons929, cons930, cons931, cons932, cons47, cons316, cons228, cons933, cons934, cons935, cons936, cons937, cons938, cons939, cons940, cons941, cons942, cons943, cons944, cons945, cons946, cons947, cons948, cons284, cons949, cons65, cons721, cons950, cons951, cons952, cons75, cons953, cons704, cons149, cons954, cons955, cons798, cons956, cons957, cons958, cons959, cons960, cons961, cons962, cons963, cons964, cons965, cons966, cons967, cons968, cons71, cons969, cons970, cons971, cons972, cons973, cons974, cons975, cons976, cons977, cons514, cons978, cons979, cons980, cons981, cons982, cons669, cons983, cons984, cons799, cons985, cons986, cons987, cons988, cons989, cons990, cons95, cons90, cons991, cons992, cons993, cons994, cons995, cons996, cons997, cons998, cons999, cons1000, cons40, cons1001, cons1002, cons1003, cons1004, cons1005, cons1006, cons1007, cons1008, cons1009, cons1010, cons1011, cons1012, cons385, cons1013, cons1014, cons1015, cons1016, cons1017, cons1018, cons1019, cons1020, cons359, cons1021, cons248, cons1022, cons1023, cons1024, cons1025, cons1026, cons1027, cons1028, cons1029, cons1030, cons1031, cons1032, cons1033, cons1034, cons1035, cons1036, cons1037, cons1038, cons1039, cons1040, cons1041, cons1042, cons1043, cons1044, cons1045, cons299, cons1046, cons1047, cons1048, cons1049, cons1050, cons707, cons384, cons1051, cons1052, cons699, cons711, cons155, cons1053, cons1054, cons1055, cons1056, cons1057, cons1058, cons1059, cons1060, cons1061, cons226, cons1062, cons517, cons1063, cons1064, cons1065, cons1066, cons1067, cons1068, cons1069, cons1070, cons1071, cons1072, cons1073, cons45, cons481, cons482, cons1074, cons1075, cons1076, cons1077, cons1078, cons1079, cons1080, cons1081, cons1082, cons1083, cons1084, cons1085, cons1086, cons1087, cons1088, cons1089, cons1090, cons1091 pattern1476 = Pattern(Integral(((x_**n_*WC('c', S(1)))**q_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons52, cons4, cons5, cons800) rule1476 = ReplacementRule(pattern1476, replacement1476) pattern1477 = Pattern(Integral(x_**WC('m', S(1))*((x_**n_*WC('c', S(1)))**q_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons52, cons800, cons20) rule1477 = ReplacementRule(pattern1477, replacement1477) pattern1478 = Pattern(Integral(x_**WC('m', S(1))*((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('r', S(1))*WC('e', S(1)))**p_*((c_ + x_**WC('n', S(1))*WC('d', S(1)))**s_*WC('f', S(1)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons54, cons802, cons801) rule1478 = ReplacementRule(pattern1478, replacement1478) pattern1479 = Pattern(Integral(((x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(c_ + x_**WC('n', S(1))*WC('d', S(1))))**p_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons27) rule1479 = ReplacementRule(pattern1479, replacement1479) pattern1480 = Pattern(Integral(((x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(c_ + x_**WC('n', S(1))*WC('d', S(1))))**p_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons803, cons804) rule1480 = ReplacementRule(pattern1480, replacement1480) pattern1481 = Pattern(Integral(((x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(c_ + x_**WC('n', S(1))*WC('d', S(1))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons151, cons805) rule1481 = ReplacementRule(pattern1481, With1481) pattern1482 = Pattern(Integral(x_**WC('m', S(1))*((x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(c_ + x_**WC('n', S(1))*WC('d', S(1))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons151, cons502) rule1482 = ReplacementRule(pattern1482, With1482) pattern1483 = Pattern(Integral(u_**WC('r', S(1))*((x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(c_ + x_**WC('n', S(1))*WC('d', S(1))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons806, cons151, cons805, cons650) rule1483 = ReplacementRule(pattern1483, With1483) pattern1484 = Pattern(Integral(u_**WC('r', S(1))*x_**WC('m', S(1))*((x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(c_ + x_**WC('n', S(1))*WC('d', S(1))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons806, cons151, cons805, cons807) rule1484 = ReplacementRule(pattern1484, With1484) pattern1485 = Pattern(Integral(((WC('c', S(1))/x_)**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons808) rule1485 = ReplacementRule(pattern1485, replacement1485) pattern1486 = Pattern(Integral(x_**WC('m', S(1))*((WC('c', S(1))/x_)**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons20) rule1486 = ReplacementRule(pattern1486, replacement1486) pattern1487 = Pattern(Integral((x_*WC('d', S(1)))**m_*((WC('c', S(1))/x_)**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons21) rule1487 = ReplacementRule(pattern1487, replacement1487) pattern1488 = Pattern(Integral(((WC('d', S(1))/x_)**n_*WC('b', S(1)) + (WC('d', S(1))/x_)**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons48) rule1488 = ReplacementRule(pattern1488, replacement1488) pattern1489 = Pattern(Integral(x_**WC('m', S(1))*(a_ + (WC('d', S(1))/x_)**n_*WC('b', S(1)) + (WC('d', S(1))/x_)**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons48, cons20) rule1489 = ReplacementRule(pattern1489, replacement1489) pattern1490 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + (WC('d', S(1))/x_)**n_*WC('b', S(1)) + (WC('d', S(1))/x_)**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons21) rule1490 = ReplacementRule(pattern1490, replacement1490) pattern1491 = Pattern(Integral((x_**WC('n2', S(1))*WC('c', S(1)) + (WC('d', S(1))/x_)**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons809, cons810) rule1491 = ReplacementRule(pattern1491, replacement1491) pattern1492 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)) + (WC('d', S(1))/x_)**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons809, cons810, cons20) rule1492 = ReplacementRule(pattern1492, replacement1492) pattern1493 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)) + (WC('d', S(1))/x_)**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons809, cons21, cons810) rule1493 = ReplacementRule(pattern1493, replacement1493) pattern1494 = Pattern(Integral(u_**m_, x_), cons19, cons70, cons811) rule1494 = ReplacementRule(pattern1494, replacement1494) pattern1495 = Pattern(Integral(u_**WC('m', S(1))*v_**WC('n', S(1)), x_), cons19, cons4, cons812, cons813) rule1495 = ReplacementRule(pattern1495, replacement1495) pattern1496 = Pattern(Integral(u_**WC('m', S(1))*v_**WC('n', S(1))*w_**WC('p', S(1)), x_), cons19, cons4, cons5, cons814, cons815) rule1496 = ReplacementRule(pattern1496, replacement1496) pattern1497 = Pattern(Integral(u_**WC('m', S(1))*v_**WC('n', S(1))*w_**WC('p', S(1))*z_**WC('q', S(1)), x_), cons19, cons4, cons5, cons52, cons816, cons817) rule1497 = ReplacementRule(pattern1497, replacement1497) pattern1498 = Pattern(Integral(u_**p_, x_), cons5, cons818, cons819) rule1498 = ReplacementRule(pattern1498, replacement1498) pattern1499 = Pattern(Integral(u_**WC('m', S(1))*v_**WC('p', S(1)), x_), cons19, cons5, cons70, cons820, cons821) rule1499 = ReplacementRule(pattern1499, replacement1499) pattern1500 = Pattern(Integral(u_**WC('m', S(1))*v_**WC('n', S(1))*w_**WC('p', S(1)), x_), cons19, cons4, cons5, cons812, cons822, cons823) rule1500 = ReplacementRule(pattern1500, replacement1500) pattern1501 = Pattern(Integral(u_**WC('p', S(1))*v_**WC('q', S(1)), x_), cons5, cons52, cons454, cons824) rule1501 = ReplacementRule(pattern1501, replacement1501) pattern1502 = Pattern(Integral(u_**p_, x_), cons5, cons825, cons826) rule1502 = ReplacementRule(pattern1502, replacement1502) pattern1503 = Pattern(Integral(u_**WC('p', S(1))*(x_*WC('c', S(1)))**WC('m', S(1)), x_), cons8, cons19, cons5, cons825, cons826) rule1503 = ReplacementRule(pattern1503, replacement1503) pattern1504 = Pattern(Integral(u_**WC('p', S(1))*v_**WC('q', S(1)), x_), cons5, cons52, cons827, cons828, cons829) rule1504 = ReplacementRule(pattern1504, replacement1504) pattern1505 = Pattern(Integral(u_**WC('p', S(1))*v_**WC('q', S(1))*x_**WC('m', S(1)), x_), cons19, cons5, cons52, cons827, cons828, cons829) rule1505 = ReplacementRule(pattern1505, replacement1505) pattern1506 = Pattern(Integral(u_**WC('m', S(1))*v_**WC('p', S(1))*w_**WC('q', S(1)), x_), cons19, cons5, cons52, cons830, cons828, cons831, cons832) rule1506 = ReplacementRule(pattern1506, replacement1506) pattern1507 = Pattern(Integral(u_**WC('p', S(1))*v_**WC('q', S(1))*x_**WC('m', S(1))*z_**WC('r', S(1)), x_), cons19, cons5, cons52, cons54, cons833, cons828, cons834, cons835) rule1507 = ReplacementRule(pattern1507, replacement1507) pattern1508 = Pattern(Integral(u_**p_, x_), cons5, cons836, cons837) rule1508 = ReplacementRule(pattern1508, replacement1508) pattern1509 = Pattern(Integral(u_**WC('p', S(1))*x_**WC('m', S(1)), x_), cons19, cons5, cons836, cons837) rule1509 = ReplacementRule(pattern1509, replacement1509) pattern1510 = Pattern(Integral(u_**p_, x_), cons5, cons838, cons839) rule1510 = ReplacementRule(pattern1510, replacement1510) pattern1511 = Pattern(Integral(u_**WC('p', S(1))*(x_*WC('d', S(1)))**WC('m', S(1)), x_), cons29, cons19, cons5, cons838, cons839) rule1511 = ReplacementRule(pattern1511, replacement1511) pattern1512 = Pattern(Integral(u_**WC('q', S(1))*v_**WC('p', S(1)), x_), cons5, cons52, cons825, cons840, cons841) rule1512 = ReplacementRule(pattern1512, replacement1512) pattern1513 = Pattern(Integral(u_**WC('q', S(1))*v_**WC('p', S(1)), x_), cons5, cons52, cons825, cons842, cons843) rule1513 = ReplacementRule(pattern1513, replacement1513) pattern1514 = Pattern(Integral(u_**WC('p', S(1))*x_**WC('m', S(1))*z_**WC('q', S(1)), x_), cons19, cons5, cons52, cons844, cons838, cons845) rule1514 = ReplacementRule(pattern1514, replacement1514) pattern1515 = Pattern(Integral(u_**WC('p', S(1))*x_**WC('m', S(1))*z_**WC('q', S(1)), x_), cons19, cons5, cons52, cons844, cons825, cons846) rule1515 = ReplacementRule(pattern1515, replacement1515) pattern1516 = Pattern(Integral(u_**p_, x_), cons5, cons847, cons848) rule1516 = ReplacementRule(pattern1516, replacement1516) pattern1517 = Pattern(Integral(u_**WC('p', S(1))*x_**WC('m', S(1)), x_), cons19, cons5, cons847, cons848) rule1517 = ReplacementRule(pattern1517, replacement1517) pattern1518 = Pattern(Integral(u_**WC('p', S(1))*z_, x_), cons5, cons844, cons847, cons849, cons850) rule1518 = ReplacementRule(pattern1518, replacement1518) pattern1519 = Pattern(Integral(u_**WC('p', S(1))*x_**WC('m', S(1))*z_, x_), cons19, cons5, cons844, cons847, cons849, cons850) rule1519 = ReplacementRule(pattern1519, replacement1519) pattern1520 = Pattern(Integral(x_**WC('m', S(1))*(e_ + x_**WC('n', S(1))*WC('h', S(1)) + x_**WC('q', S(1))*WC('f', S(1)) + x_**WC('r', S(1))*WC('g', S(1)))/(a_ + x_**WC('n', S(1))*WC('c', S(1)))**(S(3)/2), x_), cons2, cons8, cons50, cons127, cons210, cons211, cons19, cons4, cons851, cons852, cons853, cons854) rule1520 = ReplacementRule(pattern1520, replacement1520) pattern1521 = Pattern(Integral((d_*x_)**WC('m', S(1))*(e_ + x_**WC('n', S(1))*WC('h', S(1)) + x_**WC('q', S(1))*WC('f', S(1)) + x_**WC('r', S(1))*WC('g', S(1)))/(a_ + x_**WC('n', S(1))*WC('c', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons853, cons851, cons852, cons854) rule1521 = ReplacementRule(pattern1521, replacement1521) pattern1522 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**m_*(a_ + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons66, cons151, cons855) rule1522 = ReplacementRule(pattern1522, With1522) pattern1523 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons19, cons4, cons5, cons68, cons856, cons857) rule1523 = ReplacementRule(pattern1523, replacement1523) pattern1524 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons66, cons466, cons858) rule1524 = ReplacementRule(pattern1524, replacement1524) pattern1525 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons66, cons859) rule1525 = ReplacementRule(pattern1525, replacement1525) pattern1526 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons4, cons66, cons859) rule1526 = ReplacementRule(pattern1526, replacement1526) pattern1527 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons19, cons4, cons5, cons860, cons502) rule1527 = ReplacementRule(pattern1527, replacement1527) pattern1528 = Pattern(Integral(Pq_*(c_*x_)**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons860, cons502) rule1528 = ReplacementRule(pattern1528, replacement1528) pattern1529 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons66, cons55, cons13, cons139) rule1529 = ReplacementRule(pattern1529, replacement1529) pattern1530 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons29, cons19, cons4, cons5, cons66, cons861) rule1530 = ReplacementRule(pattern1530, replacement1530) pattern1531 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons4, cons5, cons66, cons861, cons862) rule1531 = ReplacementRule(pattern1531, replacement1531) pattern1532 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons66, cons150, cons246, cons165, cons863) rule1532 = ReplacementRule(pattern1532, With1532) pattern1533 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons66, cons523, cons13, cons165) rule1533 = ReplacementRule(pattern1533, With1533) pattern1534 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons66, cons523, cons13, cons165) rule1534 = ReplacementRule(pattern1534, With1534) pattern1535 = Pattern(Integral(Pq_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons66, cons150, cons13, cons139, CustomConstraint(With1535)) rule1535 = ReplacementRule(pattern1535, replacement1535) pattern1536 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons66, cons150, cons13, cons139, cons864) rule1536 = ReplacementRule(pattern1536, replacement1536) pattern1537 = Pattern(Integral((d_ + x_**S(4)*WC('g', S(1)) + x_**S(3)*WC('f', S(1)) + x_*WC('e', S(1)))/(a_ + x_**S(4)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons865) rule1537 = ReplacementRule(pattern1537, replacement1537) pattern1538 = Pattern(Integral((d_ + x_**S(4)*WC('g', S(1)) + x_**S(3)*WC('f', S(1)))/(a_ + x_**S(4)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons29, cons127, cons210, cons865) rule1538 = ReplacementRule(pattern1538, replacement1538) pattern1539 = Pattern(Integral((d_ + x_**S(4)*WC('g', S(1)) + x_*WC('e', S(1)))/(a_ + x_**S(4)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons210, cons865) rule1539 = ReplacementRule(pattern1539, replacement1539) pattern1540 = Pattern(Integral(x_**S(2)*(x_**S(4)*WC('h', S(1)) + x_*WC('f', S(1)) + WC('e', S(0)))/(a_ + x_**S(4)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons50, cons127, cons211, cons866) rule1540 = ReplacementRule(pattern1540, replacement1540) pattern1541 = Pattern(Integral(x_**S(2)*(x_**S(4)*WC('h', S(1)) + WC('e', S(0)))/(a_ + x_**S(4)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons50, cons211, cons866) rule1541 = ReplacementRule(pattern1541, replacement1541) pattern1542 = Pattern(Integral((d_ + x_**S(6)*WC('h', S(1)) + x_**S(4)*WC('g', S(1)) + x_**S(3)*WC('f', S(1)) + x_**S(2)*WC('e', S(1)))/(a_ + x_**S(4)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons211, cons866, cons865) rule1542 = ReplacementRule(pattern1542, replacement1542) pattern1543 = Pattern(Integral((d_ + x_**S(6)*WC('h', S(1)) + x_**S(4)*WC('g', S(1)) + x_**S(2)*WC('e', S(1)))/(a_ + x_**S(4)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons210, cons211, cons866, cons865) rule1543 = ReplacementRule(pattern1543, replacement1543) pattern1544 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons66, cons150, cons13, cons139, CustomConstraint(With1544)) rule1544 = ReplacementRule(pattern1544, replacement1544) pattern1545 = Pattern(Integral(Pq_*x_**m_*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons66, cons150, cons13, cons139, cons86) rule1545 = ReplacementRule(pattern1545, With1545) pattern1546 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons860, cons150, cons20, CustomConstraint(With1546)) rule1546 = ReplacementRule(pattern1546, replacement1546) pattern1547 = Pattern(Integral((A_ + x_*WC('B', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons867) rule1547 = ReplacementRule(pattern1547, replacement1547) pattern1548 = Pattern(Integral((A_ + x_*WC('B', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons868, cons470) rule1548 = ReplacementRule(pattern1548, With1548) pattern1549 = Pattern(Integral((A_ + x_*WC('B', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons868, cons471) rule1549 = ReplacementRule(pattern1549, With1549) pattern1550 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons869, cons870) rule1550 = ReplacementRule(pattern1550, replacement1550) pattern1551 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons871) rule1551 = ReplacementRule(pattern1551, With1551) pattern1552 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons872) rule1552 = ReplacementRule(pattern1552, With1552) pattern1553 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons873) rule1553 = ReplacementRule(pattern1553, With1553) pattern1554 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons874) rule1554 = ReplacementRule(pattern1554, With1554) pattern1555 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons875) rule1555 = ReplacementRule(pattern1555, With1555) pattern1556 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons876) rule1556 = ReplacementRule(pattern1556, With1556) pattern1557 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons877) rule1557 = ReplacementRule(pattern1557, With1557) pattern1558 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons878) rule1558 = ReplacementRule(pattern1558, With1558) pattern1559 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons879) rule1559 = ReplacementRule(pattern1559, With1559) pattern1560 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons880) rule1560 = ReplacementRule(pattern1560, With1560) pattern1561 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons881) rule1561 = ReplacementRule(pattern1561, With1561) pattern1562 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons882) rule1562 = ReplacementRule(pattern1562, With1562) pattern1563 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons883) rule1563 = ReplacementRule(pattern1563, With1563) pattern1564 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons884) rule1564 = ReplacementRule(pattern1564, With1564) pattern1565 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons885) rule1565 = ReplacementRule(pattern1565, With1565) pattern1566 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons886) rule1566 = ReplacementRule(pattern1566, With1566) pattern1567 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons887) rule1567 = ReplacementRule(pattern1567, With1567) pattern1568 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons888) rule1568 = ReplacementRule(pattern1568, With1568) pattern1569 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons889) rule1569 = ReplacementRule(pattern1569, With1569) pattern1570 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons890) rule1570 = ReplacementRule(pattern1570, With1570) pattern1571 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons891) rule1571 = ReplacementRule(pattern1571, With1571) pattern1572 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons892) rule1572 = ReplacementRule(pattern1572, With1572) pattern1573 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons893) rule1573 = ReplacementRule(pattern1573, With1573) pattern1574 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons894) rule1574 = ReplacementRule(pattern1574, With1574) pattern1575 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons895) rule1575 = ReplacementRule(pattern1575, replacement1575) pattern1576 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons896) rule1576 = ReplacementRule(pattern1576, replacement1576) pattern1577 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons897) rule1577 = ReplacementRule(pattern1577, replacement1577) pattern1578 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons898) rule1578 = ReplacementRule(pattern1578, With1578) pattern1579 = Pattern(Integral(x_*(x_*WC('C', S(1)) + WC('B', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons899) rule1579 = ReplacementRule(pattern1579, With1579) pattern1580 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons900) rule1580 = ReplacementRule(pattern1580, With1580) pattern1581 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons901) rule1581 = ReplacementRule(pattern1581, With1581) pattern1582 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons902) rule1582 = ReplacementRule(pattern1582, With1582) pattern1583 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons903) rule1583 = ReplacementRule(pattern1583, With1583) pattern1584 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons868, cons904, cons905, CustomConstraint(With1584)) rule1584 = ReplacementRule(pattern1584, replacement1584) pattern1585 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons904, cons905, CustomConstraint(With1585)) rule1585 = ReplacementRule(pattern1585, replacement1585) pattern1586 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons904, cons905, CustomConstraint(With1586)) rule1586 = ReplacementRule(pattern1586, replacement1586) pattern1587 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons868, cons904, cons906, CustomConstraint(With1587)) rule1587 = ReplacementRule(pattern1587, replacement1587) pattern1588 = Pattern(Integral(x_*(B_ + x_*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons37, cons38, cons904, cons906, CustomConstraint(With1588)) rule1588 = ReplacementRule(pattern1588, replacement1588) pattern1589 = Pattern(Integral((A_ + x_**S(2)*WC('C', S(1)))/(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons36, cons38, cons904, cons906, CustomConstraint(With1589)) rule1589 = ReplacementRule(pattern1589, replacement1589) pattern1590 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons19, cons66, cons676, cons907, CustomConstraint(With1590)) rule1590 = ReplacementRule(pattern1590, replacement1590) pattern1591 = Pattern(Integral(Pq_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons66, cons676, cons907, CustomConstraint(With1591)) rule1591 = ReplacementRule(pattern1591, replacement1591) pattern1592 = Pattern(Integral((c_ + x_*WC('d', S(1)))/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons483, cons908) rule1592 = ReplacementRule(pattern1592, With1592) pattern1593 = Pattern(Integral((c_ + x_*WC('d', S(1)))/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons483, cons909) rule1593 = ReplacementRule(pattern1593, With1593) pattern1594 = Pattern(Integral((c_ + x_*WC('d', S(1)))/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons484, cons910) rule1594 = ReplacementRule(pattern1594, With1594) pattern1595 = Pattern(Integral((c_ + x_*WC('d', S(1)))/sqrt(a_ + x_**S(3)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons484, cons911) rule1595 = ReplacementRule(pattern1595, With1595) pattern1596 = Pattern(Integral((c_ + x_**S(4)*WC('d', S(1)))/sqrt(a_ + x_**S(6)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons912) rule1596 = ReplacementRule(pattern1596, With1596) pattern1597 = Pattern(Integral((c_ + x_**S(4)*WC('d', S(1)))/sqrt(a_ + x_**S(6)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons913) rule1597 = ReplacementRule(pattern1597, With1597) pattern1598 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))/sqrt(a_ + x_**S(8)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons914) rule1598 = ReplacementRule(pattern1598, replacement1598) pattern1599 = Pattern(Integral((c_ + x_**S(2)*WC('d', S(1)))/sqrt(a_ + x_**S(8)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons915) rule1599 = ReplacementRule(pattern1599, replacement1599) pattern1600 = Pattern(Integral(Pq_/(x_*sqrt(a_ + x_**n_*WC('b', S(1)))), x_), cons2, cons3, cons66, cons150, cons916) rule1600 = ReplacementRule(pattern1600, replacement1600) pattern1601 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons66, cons676, cons917) rule1601 = ReplacementRule(pattern1601, With1601) pattern1602 = Pattern(Integral(Pq_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons66, cons676, cons917) rule1602 = ReplacementRule(pattern1602, With1602) pattern1603 = Pattern(Integral(Pq_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons66, cons150, cons918) rule1603 = ReplacementRule(pattern1603, replacement1603) pattern1604 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons19, cons66, cons87) rule1604 = ReplacementRule(pattern1604, replacement1604) pattern1605 = Pattern(Integral(Pq_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons66, cons87) rule1605 = ReplacementRule(pattern1605, replacement1605) pattern1606 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons66, cons150, cons33, cons96, cons919, CustomConstraint(With1606)) rule1606 = ReplacementRule(pattern1606, replacement1606) pattern1607 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons66, cons150, CustomConstraint(With1607)) rule1607 = ReplacementRule(pattern1607, replacement1607) pattern1608 = Pattern(Integral(Pq_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons66, cons150, CustomConstraint(With1608)) rule1608 = ReplacementRule(pattern1608, replacement1608) pattern1609 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons66, cons198, cons20) rule1609 = ReplacementRule(pattern1609, With1609) pattern1610 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons66, cons198, cons369) rule1610 = ReplacementRule(pattern1610, With1610) pattern1611 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons66, cons198, cons358) rule1611 = ReplacementRule(pattern1611, With1611) pattern1612 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons5, cons66, cons491) rule1612 = ReplacementRule(pattern1612, With1612) pattern1613 = Pattern(Integral(Pq_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons5, cons66, cons491) rule1613 = ReplacementRule(pattern1613, With1613) pattern1614 = Pattern(Integral(Pq_*(c_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons66, cons491) rule1614 = ReplacementRule(pattern1614, replacement1614) pattern1615 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons5, cons860, cons543, cons25) rule1615 = ReplacementRule(pattern1615, replacement1615) pattern1616 = Pattern(Integral(Pq_*(c_*x_)**m_*(a_ + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons860, cons543, cons25) rule1616 = ReplacementRule(pattern1616, replacement1616) pattern1617 = Pattern(Integral((A_ + x_**WC('m', S(1))*WC('B', S(1)))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons36, cons37, cons19, cons4, cons5, cons55) rule1617 = ReplacementRule(pattern1617, replacement1617) pattern1618 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons920) rule1618 = ReplacementRule(pattern1618, replacement1618) pattern1619 = Pattern(Integral(Pq_*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons4, cons5, cons920) rule1619 = ReplacementRule(pattern1619, replacement1619) pattern1620 = Pattern(Integral(Pq_*u_**WC('m', S(1))*(a_ + v_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons19, cons4, cons5, cons556, cons921) rule1620 = ReplacementRule(pattern1620, replacement1620) pattern1621 = Pattern(Integral(Pq_*(a_ + v_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons4, cons5, cons554, cons921) rule1621 = ReplacementRule(pattern1621, replacement1621) pattern1622 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**WC('p', S(1)), x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons66, cons57, cons496) rule1622 = ReplacementRule(pattern1622, replacement1622) pattern1623 = Pattern(Integral(Pq_*(a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**WC('p', S(1)), x_), cons59, cons60, cons61, cons62, cons4, cons5, cons66, cons57, cons496) rule1623 = ReplacementRule(pattern1623, replacement1623) pattern1624 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**WC('p', S(1)), x_), cons59, cons60, cons61, cons62, cons8, cons19, cons4, cons5, cons66, cons57) rule1624 = ReplacementRule(pattern1624, replacement1624) pattern1625 = Pattern(Integral(Pq_*(a1_ + x_**WC('n', S(1))*WC('b1', S(1)))**WC('p', S(1))*(a2_ + x_**WC('n', S(1))*WC('b2', S(1)))**WC('p', S(1)), x_), cons59, cons60, cons61, cons62, cons4, cons5, cons66, cons57) rule1625 = ReplacementRule(pattern1625, replacement1625) pattern1626 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('p', S(1))*(e_ + x_**WC('n', S(1))*WC('f', S(1)) + x_**WC('n2', S(1))*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons48, cons922, cons923) rule1626 = ReplacementRule(pattern1626, replacement1626) pattern1627 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('p', S(1))*(e_ + x_**WC('n2', S(1))*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons210, cons4, cons5, cons48, cons924, cons923) rule1627 = ReplacementRule(pattern1627, replacement1627) pattern1628 = Pattern(Integral((x_*WC('h', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('p', S(1))*(e_ + x_**WC('n', S(1))*WC('f', S(1)) + x_**WC('n2', S(1))*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons48, cons925, cons926, cons68) rule1628 = ReplacementRule(pattern1628, replacement1628) pattern1629 = Pattern(Integral((x_*WC('h', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('p', S(1))*(e_ + x_**WC('n2', S(1))*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons210, cons211, cons19, cons4, cons5, cons48, cons597, cons926, cons68) rule1629 = ReplacementRule(pattern1629, replacement1629) pattern1630 = Pattern(Integral((A_ + x_**WC('m', S(1))*WC('B', S(1)))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(x_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons19, cons4, cons5, cons52, cons73, cons55) rule1630 = ReplacementRule(pattern1630, replacement1630) pattern1631 = Pattern(Integral(Px_**WC('q', S(1))*((c_ + x_*WC('d', S(1)))**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons927, cons588, cons89) rule1631 = ReplacementRule(pattern1631, With1631) pattern1632 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons48, cons860, cons55) rule1632 = ReplacementRule(pattern1632, replacement1632) pattern1633 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons48, cons66, cons130) rule1633 = ReplacementRule(pattern1633, replacement1633) pattern1634 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons48, cons66, cons130) rule1634 = ReplacementRule(pattern1634, replacement1634) pattern1635 = Pattern(Integral((a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**WC('n', S(1))*WC('e', S(1)) + x_**WC('n2', S(1))*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons48, cons928, cons929) rule1635 = ReplacementRule(pattern1635, replacement1635) pattern1636 = Pattern(Integral((d_ + x_**WC('n2', S(1))*WC('f', S(1)))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons4, cons5, cons48, cons924, cons930) rule1636 = ReplacementRule(pattern1636, replacement1636) pattern1637 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**WC('n', S(1))*WC('e', S(1)) + x_**WC('n2', S(1))*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons48, cons931, cons932, cons68) rule1637 = ReplacementRule(pattern1637, replacement1637) pattern1638 = Pattern(Integral((x_*WC('g', S(1)))**WC('m', S(1))*(d_ + x_**WC('n2', S(1))*WC('f', S(1)))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons19, cons4, cons5, cons48, cons597, cons930, cons68) rule1638 = ReplacementRule(pattern1638, replacement1638) pattern1639 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons48, cons66, cons47, cons316) rule1639 = ReplacementRule(pattern1639, replacement1639) pattern1640 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons66, cons47, cons316) rule1640 = ReplacementRule(pattern1640, replacement1640) pattern1641 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons48, cons860, cons228, cons502) rule1641 = ReplacementRule(pattern1641, replacement1641) pattern1642 = Pattern(Integral(Pq_*(d_*x_)**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons48, cons860, cons228, cons502) rule1642 = ReplacementRule(pattern1642, replacement1642) pattern1643 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons48, cons66, cons861) rule1643 = ReplacementRule(pattern1643, replacement1643) pattern1644 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons66, cons861, cons862) rule1644 = ReplacementRule(pattern1644, replacement1644) pattern1645 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)) + x_**WC('n2', S(1))*WC('f', S(1)) + x_**WC('n3', S(1))*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons48, cons933, cons228, cons934, cons935) rule1645 = ReplacementRule(pattern1645, replacement1645) pattern1646 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**WC('n2', S(1))*WC('f', S(1)) + x_**WC('n3', S(1))*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons4, cons5, cons48, cons933, cons228, cons936, cons937) rule1646 = ReplacementRule(pattern1646, replacement1646) pattern1647 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)) + x_**WC('n3', S(1))*WC('g', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons210, cons4, cons5, cons48, cons933, cons228, cons934, cons938) rule1647 = ReplacementRule(pattern1647, replacement1647) pattern1648 = Pattern(Integral((d_ + x_**WC('n3', S(1))*WC('g', S(1)))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons210, cons4, cons5, cons48, cons933, cons228, cons936, cons939) rule1648 = ReplacementRule(pattern1648, replacement1648) pattern1649 = Pattern(Integral(x_**WC('m', S(1))*(e_ + x_**WC('q', S(1))*WC('f', S(1)) + x_**WC('r', S(1))*WC('g', S(1)) + x_**WC('s', S(1))*WC('h', S(1)))/(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons50, cons127, cons210, cons211, cons19, cons4, cons48, cons940, cons941, cons942, cons228, cons943, cons854) rule1649 = ReplacementRule(pattern1649, replacement1649) pattern1650 = Pattern(Integral((d_*x_)**WC('m', S(1))*(e_ + x_**WC('q', S(1))*WC('f', S(1)) + x_**WC('r', S(1))*WC('g', S(1)) + x_**WC('s', S(1))*WC('h', S(1)))/(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons48, cons940, cons941, cons942, cons228, cons943, cons854) rule1650 = ReplacementRule(pattern1650, replacement1650) pattern1651 = Pattern(Integral(Pq_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons48, cons66, cons228, cons150, cons13, cons139, CustomConstraint(With1651)) rule1651 = ReplacementRule(pattern1651, replacement1651) pattern1652 = Pattern(Integral((d_ + x_**S(4)*WC('g', S(1)) + x_**S(3)*WC('f', S(1)) + x_*WC('e', S(1)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons228, cons944) rule1652 = ReplacementRule(pattern1652, replacement1652) pattern1653 = Pattern(Integral((d_ + x_**S(4)*WC('g', S(1)) + x_**S(3)*WC('f', S(1)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons228, cons944) rule1653 = ReplacementRule(pattern1653, replacement1653) pattern1654 = Pattern(Integral((d_ + x_**S(4)*WC('g', S(1)) + x_*WC('e', S(1)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons210, cons228, cons944) rule1654 = ReplacementRule(pattern1654, replacement1654) pattern1655 = Pattern(Integral(x_**S(2)*(x_**S(4)*WC('h', S(1)) + x_**S(2)*WC('g', S(1)) + x_*WC('f', S(1)) + WC('e', S(0)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons50, cons127, cons210, cons211, cons228, cons945, cons946) rule1655 = ReplacementRule(pattern1655, replacement1655) pattern1656 = Pattern(Integral(x_**S(2)*(x_**S(4)*WC('h', S(1)) + x_**S(2)*WC('g', S(1)) + WC('e', S(0)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons50, cons210, cons211, cons228, cons945, cons946) rule1656 = ReplacementRule(pattern1656, replacement1656) pattern1657 = Pattern(Integral((d_ + x_**S(6)*WC('h', S(1)) + x_**S(4)*WC('g', S(1)) + x_**S(3)*WC('f', S(1)) + x_**S(2)*WC('e', S(1)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons945, cons947) rule1657 = ReplacementRule(pattern1657, replacement1657) pattern1658 = Pattern(Integral((d_ + x_**S(6)*WC('h', S(1)) + x_**S(3)*WC('f', S(1)) + x_**S(2)*WC('e', S(1)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons211, cons228, cons945, cons948) rule1658 = ReplacementRule(pattern1658, replacement1658) pattern1659 = Pattern(Integral(Pq_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons48, cons66, cons228, cons150, cons13, cons139, CustomConstraint(With1659)) rule1659 = ReplacementRule(pattern1659, replacement1659) pattern1660 = Pattern(Integral(Pq_*x_**m_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons48, cons66, cons228, cons150, cons13, cons139, cons86, CustomConstraint(With1660)) rule1660 = ReplacementRule(pattern1660, replacement1660) pattern1661 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons860, cons228, cons150, cons20, CustomConstraint(With1661)) rule1661 = ReplacementRule(pattern1661, replacement1661) pattern1662 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))/(a_ + x_**n2_*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons48, cons860, cons228, cons150, cons284) rule1662 = ReplacementRule(pattern1662, replacement1662) pattern1663 = Pattern(Integral(Pq_/(a_ + x_**n2_*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1))), x_), cons2, cons3, cons8, cons48, cons860, cons228, cons150, cons949) rule1663 = ReplacementRule(pattern1663, replacement1663) pattern1664 = Pattern(Integral(Pq_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons66, cons228, cons65, CustomConstraint(With1664)) rule1664 = ReplacementRule(pattern1664, replacement1664) pattern1665 = Pattern(Integral(Pq_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons66, cons228, cons721, cons950, CustomConstraint(With1665)) rule1665 = ReplacementRule(pattern1665, replacement1665) pattern1666 = Pattern(Integral(Pq_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons66, cons228, cons721, cons951, CustomConstraint(With1666)) rule1666 = ReplacementRule(pattern1666, replacement1666) pattern1667 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons48, cons860, cons228, cons150, CustomConstraint(With1667)) rule1667 = ReplacementRule(pattern1667, replacement1667) pattern1668 = Pattern(Integral(Pq_*(a_ + x_**n2_*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons860, cons228, cons150, CustomConstraint(With1668)) rule1668 = ReplacementRule(pattern1668, replacement1668) pattern1669 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons48, cons66, cons228, cons150, cons952) rule1669 = ReplacementRule(pattern1669, With1669) pattern1670 = Pattern(Integral(Pq_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons66, cons228, cons150, cons952) rule1670 = ReplacementRule(pattern1670, With1670) pattern1671 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))/(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons48, cons66, cons228, cons150) rule1671 = ReplacementRule(pattern1671, replacement1671) pattern1672 = Pattern(Integral(Pq_/(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons48, cons66, cons228, cons150) rule1672 = ReplacementRule(pattern1672, replacement1672) pattern1673 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons66, cons228, cons198, cons20) rule1673 = ReplacementRule(pattern1673, With1673) pattern1674 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons48, cons66, cons228, cons198, cons369) rule1674 = ReplacementRule(pattern1674, With1674) pattern1675 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons48, cons66, cons228, cons198, cons358) rule1675 = ReplacementRule(pattern1675, With1675) pattern1676 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons48, cons66, cons228, cons491) rule1676 = ReplacementRule(pattern1676, With1676) pattern1677 = Pattern(Integral(Pq_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons66, cons228, cons491) rule1677 = ReplacementRule(pattern1677, With1677) pattern1678 = Pattern(Integral(Pq_*(d_*x_)**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons48, cons66, cons228, cons491, cons75) rule1678 = ReplacementRule(pattern1678, replacement1678) pattern1679 = Pattern(Integral(Pq_*(d_*x_)**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons48, cons66, cons228, cons491, cons953) rule1679 = ReplacementRule(pattern1679, replacement1679) pattern1680 = Pattern(Integral(Pq_*(d_*x_)**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons48, cons66, cons228, cons491) rule1680 = ReplacementRule(pattern1680, replacement1680) pattern1681 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons48, cons860, cons228, cons543, cons25) rule1681 = ReplacementRule(pattern1681, replacement1681) pattern1682 = Pattern(Integral(Pq_*(d_*x_)**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons48, cons860, cons228, cons543, cons25) rule1682 = ReplacementRule(pattern1682, replacement1682) pattern1683 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))/(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons48, cons66, cons228) rule1683 = ReplacementRule(pattern1683, With1683) pattern1684 = Pattern(Integral(Pq_/(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons4, cons48, cons66, cons228) rule1684 = ReplacementRule(pattern1684, With1684) pattern1685 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons48, cons66, cons704) rule1685 = ReplacementRule(pattern1685, replacement1685) pattern1686 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons66, cons704) rule1686 = ReplacementRule(pattern1686, replacement1686) pattern1687 = Pattern(Integral(Pq_*(x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons48, cons920) rule1687 = ReplacementRule(pattern1687, replacement1687) pattern1688 = Pattern(Integral(Pq_*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons48, cons920) rule1688 = ReplacementRule(pattern1688, replacement1688) pattern1689 = Pattern(Integral(Pq_*u_**WC('m', S(1))*(a_ + v_**n_*WC('b', S(1)) + v_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons48, cons556, cons921) rule1689 = ReplacementRule(pattern1689, replacement1689) pattern1690 = Pattern(Integral(Pq_*(a_ + v_**n_*WC('b', S(1)) + v_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons48, cons554, cons921) rule1690 = ReplacementRule(pattern1690, replacement1690) pattern1691 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons5, cons149, cons954, cons955) rule1691 = ReplacementRule(pattern1691, replacement1691) pattern1692 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons149, cons954, cons956, cons13, cons139) rule1692 = ReplacementRule(pattern1692, replacement1692) pattern1693 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons5, cons149, cons954, cons956, cons957) rule1693 = ReplacementRule(pattern1693, replacement1693) pattern1694 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons149, cons958, cons959, cons165, cons960) rule1694 = ReplacementRule(pattern1694, replacement1694) pattern1695 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons149, cons958, cons959, cons165, cons961) rule1695 = ReplacementRule(pattern1695, replacement1695) pattern1696 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons149, cons958, cons959, cons139, cons962) rule1696 = ReplacementRule(pattern1696, replacement1696) pattern1697 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons149, cons958, cons959, cons139) rule1697 = ReplacementRule(pattern1697, replacement1697) pattern1698 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons963, cons954, cons964) rule1698 = ReplacementRule(pattern1698, replacement1698) pattern1699 = Pattern(Integral(S(1)/sqrt(x_**S(2)*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1))), x_), cons2, cons3, cons4, cons965) rule1699 = ReplacementRule(pattern1699, replacement1699) pattern1700 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons721, cons954, cons964) rule1700 = ReplacementRule(pattern1700, replacement1700) pattern1701 = Pattern(Integral(S(1)/sqrt(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1))), x_), cons2, cons3, cons966, cons967) rule1701 = ReplacementRule(pattern1701, replacement1701) pattern1702 = Pattern(Integral((x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons5, cons149, cons954, cons968) rule1702 = ReplacementRule(pattern1702, replacement1702) pattern1703 = Pattern(Integral((u_**WC('j', S(1))*WC('a', S(1)) + u_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons5, cons70, cons71) rule1703 = ReplacementRule(pattern1703, replacement1703) pattern1704 = Pattern(Integral(x_**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons798, cons19, cons4, cons5, cons149, cons954, cons969, cons55) rule1704 = ReplacementRule(pattern1704, replacement1704) pattern1705 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons149, cons954, cons970, cons971) rule1705 = ReplacementRule(pattern1705, replacement1705) pattern1706 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons149, cons954, cons972, cons13, cons139, cons971) rule1706 = ReplacementRule(pattern1706, replacement1706) pattern1707 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons149, cons954, cons972, cons973, cons974) rule1707 = ReplacementRule(pattern1707, replacement1707) pattern1708 = Pattern(Integral((c_*x_)**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons149, cons954, cons972) rule1708 = ReplacementRule(pattern1708, replacement1708) pattern1709 = Pattern(Integral(x_**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons798, cons19, cons4, cons5, cons149, cons954, cons969, cons502, cons975) rule1709 = ReplacementRule(pattern1709, replacement1709) pattern1710 = Pattern(Integral((c_*x_)**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons149, cons954, cons969, cons502, cons975) rule1710 = ReplacementRule(pattern1710, replacement1710) pattern1711 = Pattern(Integral((x_*WC('c', S(1)))**m_*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons149, cons976, cons959, cons974, cons165, cons977) rule1711 = ReplacementRule(pattern1711, replacement1711) pattern1712 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons149, cons958, cons959, cons974, cons165, cons514) rule1712 = ReplacementRule(pattern1712, replacement1712) pattern1713 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons149, cons976, cons959, cons974, cons139, cons978) rule1713 = ReplacementRule(pattern1713, replacement1713) pattern1714 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons149, cons958, cons959, cons974, cons139) rule1714 = ReplacementRule(pattern1714, replacement1714) pattern1715 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons149, cons966, cons959, cons974, cons979, cons514) rule1715 = ReplacementRule(pattern1715, replacement1715) pattern1716 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons149, cons966, cons959, cons974, cons980) rule1716 = ReplacementRule(pattern1716, replacement1716) pattern1717 = Pattern(Integral(x_**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons798, cons19, cons4, cons5, cons149, cons954, cons969, cons68, cons543, cons25) rule1717 = ReplacementRule(pattern1717, replacement1717) pattern1718 = Pattern(Integral((c_*x_)**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons149, cons954, cons969, cons68, cons543, cons25) rule1718 = ReplacementRule(pattern1718, replacement1718) pattern1719 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons963, cons954, cons981, cons971) rule1719 = ReplacementRule(pattern1719, replacement1719) pattern1720 = Pattern(Integral(x_**WC('m', S(1))/sqrt(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1))), x_), cons2, cons3, cons798, cons4, cons982, cons954) rule1720 = ReplacementRule(pattern1720, replacement1720) pattern1721 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons721, cons954, cons981, cons971) rule1721 = ReplacementRule(pattern1721, replacement1721) pattern1722 = Pattern(Integral((c_*x_)**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons669, cons954, cons981) rule1722 = ReplacementRule(pattern1722, replacement1722) pattern1723 = Pattern(Integral((x_*WC('c', S(1)))**WC('m', S(1))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('n', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons149, cons954, cons968) rule1723 = ReplacementRule(pattern1723, replacement1723) pattern1724 = Pattern(Integral(u_**WC('m', S(1))*(v_**WC('j', S(1))*WC('a', S(1)) + v_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons798, cons19, cons4, cons5, cons556) rule1724 = ReplacementRule(pattern1724, replacement1724) pattern1725 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**n_*WC('d', S(1)))**WC('q', S(1))*(x_**j_*WC('a', S(1)) + x_**WC('k', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons798, cons799, cons19, cons4, cons5, cons52, cons149, cons983, cons969, cons984, cons502, cons975) rule1725 = ReplacementRule(pattern1725, replacement1725) pattern1726 = Pattern(Integral((e_*x_)**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('q', S(1))*(x_**j_*WC('a', S(1)) + x_**WC('k', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons798, cons799, cons19, cons4, cons5, cons52, cons149, cons983, cons969, cons984, cons502, cons975) rule1726 = ReplacementRule(pattern1726, replacement1726) pattern1727 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))*(x_**WC('jn', S(1))*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons798, cons19, cons4, cons5, cons985, cons149, cons73, cons986, cons987, cons973) rule1727 = ReplacementRule(pattern1727, replacement1727) pattern1728 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))*(x_**WC('jn', S(1))*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons798, cons19, cons4, cons985, cons149, cons73, cons988, cons139, cons989, cons990) rule1728 = ReplacementRule(pattern1728, replacement1728) pattern1729 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))*(x_**WC('jn', S(1))*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons798, cons5, cons985, cons149, cons73, cons95, cons90, cons991, cons992, cons973, cons993) rule1729 = ReplacementRule(pattern1729, replacement1729) pattern1730 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))*(x_**WC('jn', S(1))*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons798, cons19, cons4, cons5, cons985, cons149, cons73, cons994, cons990) rule1730 = ReplacementRule(pattern1730, replacement1730) pattern1731 = Pattern(Integral(x_**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('q', S(1))*(x_**j_*WC('a', S(1)) + x_**WC('k', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons798, cons799, cons19, cons4, cons5, cons52, cons149, cons983, cons969, cons984, cons68, cons543, cons25) rule1731 = ReplacementRule(pattern1731, replacement1731) pattern1732 = Pattern(Integral((e_*x_)**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('q', S(1))*(x_**j_*WC('a', S(1)) + x_**WC('k', S(1))*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons798, cons799, cons19, cons4, cons5, cons52, cons149, cons983, cons969, cons984, cons68, cons543, cons25) rule1732 = ReplacementRule(pattern1732, replacement1732) pattern1733 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(c_ + x_**WC('n', S(1))*WC('d', S(1)))**WC('q', S(1))*(x_**WC('jn', S(1))*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons798, cons19, cons4, cons5, cons52, cons985, cons149, cons73, cons995) rule1733 = ReplacementRule(pattern1733, replacement1733) pattern1734 = Pattern(Integral(Pq_*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons5, cons860, cons149, cons954, cons966, cons969, cons996) rule1734 = ReplacementRule(pattern1734, With1734) pattern1735 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons798, cons19, cons4, cons5, cons860, cons149, cons954, cons969, cons502) rule1735 = ReplacementRule(pattern1735, replacement1735) pattern1736 = Pattern(Integral(Pq_*(c_*x_)**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons4, cons5, cons860, cons149, cons954, cons969, cons502, cons33, cons997) rule1736 = ReplacementRule(pattern1736, replacement1736) pattern1737 = Pattern(Integral(Pq_*(c_*x_)**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons860, cons149, cons954, cons969, cons502) rule1737 = ReplacementRule(pattern1737, replacement1737) pattern1738 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons5, cons860, cons149, cons998, cons20, CustomConstraint(With1738)) rule1738 = ReplacementRule(pattern1738, replacement1738) pattern1739 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons66, cons149, cons999, cons1000, CustomConstraint(With1739)) rule1739 = ReplacementRule(pattern1739, replacement1739) pattern1740 = Pattern(Integral(Pq_*x_**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons798, cons19, cons4, cons5, cons860, cons149, cons954, cons969, cons543, cons25) rule1740 = ReplacementRule(pattern1740, replacement1740) pattern1741 = Pattern(Integral(Pq_*(c_*x_)**m_*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons4, cons5, cons860, cons149, cons954, cons969, cons543, cons25, cons33, cons997) rule1741 = ReplacementRule(pattern1741, replacement1741) pattern1742 = Pattern(Integral(Pq_*(c_*x_)**m_*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons860, cons149, cons954, cons969, cons543, cons25) rule1742 = ReplacementRule(pattern1742, replacement1742) pattern1743 = Pattern(Integral(Pq_*(x_*WC('c', S(1)))**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons798, cons19, cons4, cons5, cons920, cons149, cons954) rule1743 = ReplacementRule(pattern1743, replacement1743) pattern1744 = Pattern(Integral(Pq_*(x_**n_*WC('b', S(1)) + x_**WC('j', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons798, cons4, cons5, cons920, cons149, cons954) rule1744 = ReplacementRule(pattern1744, replacement1744) pattern1745 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons40, cons1001) rule1745 = ReplacementRule(pattern1745, replacement1745) pattern1746 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons130, cons1002) rule1746 = ReplacementRule(pattern1746, replacement1746) pattern1747 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons65, cons1002, CustomConstraint(With1747)) rule1747 = ReplacementRule(pattern1747, replacement1747) pattern1748 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons65, cons1002) rule1748 = ReplacementRule(pattern1748, With1748) pattern1749 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons5, cons149, cons1001) rule1749 = ReplacementRule(pattern1749, replacement1749) pattern1750 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons5, cons149, cons1002, CustomConstraint(With1750)) rule1750 = ReplacementRule(pattern1750, replacement1750) pattern1751 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons5, cons149, cons1002) rule1751 = ReplacementRule(pattern1751, With1751) pattern1752 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons40, cons1001) rule1752 = ReplacementRule(pattern1752, replacement1752) pattern1753 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons130, cons1002) rule1753 = ReplacementRule(pattern1753, replacement1753) pattern1754 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons65, cons1002, CustomConstraint(With1754)) rule1754 = ReplacementRule(pattern1754, replacement1754) pattern1755 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons65, cons1002) rule1755 = ReplacementRule(pattern1755, With1755) pattern1756 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons5, cons149, cons1001) rule1756 = ReplacementRule(pattern1756, replacement1756) pattern1757 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons5, cons149, cons1002, CustomConstraint(With1757)) rule1757 = ReplacementRule(pattern1757, replacement1757) pattern1758 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons5, cons149, cons1002) rule1758 = ReplacementRule(pattern1758, With1758) pattern1759 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons40, cons1003) rule1759 = ReplacementRule(pattern1759, replacement1759) pattern1760 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons130, cons1004) rule1760 = ReplacementRule(pattern1760, replacement1760) pattern1761 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons65, cons1004, CustomConstraint(With1761)) rule1761 = ReplacementRule(pattern1761, replacement1761) pattern1762 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons65, cons1004) rule1762 = ReplacementRule(pattern1762, With1762) pattern1763 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons5, cons149, cons1003) rule1763 = ReplacementRule(pattern1763, replacement1763) pattern1764 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons5, cons149, cons1004, CustomConstraint(With1764)) rule1764 = ReplacementRule(pattern1764, replacement1764) pattern1765 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons5, cons149, cons1004) rule1765 = ReplacementRule(pattern1765, With1765) pattern1766 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons40, cons1003) rule1766 = ReplacementRule(pattern1766, replacement1766) pattern1767 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons130, cons1004) rule1767 = ReplacementRule(pattern1767, replacement1767) pattern1768 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons65, cons1004, CustomConstraint(With1768)) rule1768 = ReplacementRule(pattern1768, replacement1768) pattern1769 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons65, cons1004) rule1769 = ReplacementRule(pattern1769, With1769) pattern1770 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1003) rule1770 = ReplacementRule(pattern1770, replacement1770) pattern1771 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1004, CustomConstraint(With1771)) rule1771 = ReplacementRule(pattern1771, replacement1771) pattern1772 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1004) rule1772 = ReplacementRule(pattern1772, With1772) pattern1773 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons40, cons1005, cons1006) rule1773 = ReplacementRule(pattern1773, replacement1773) pattern1774 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons40, cons1005, cons1007) rule1774 = ReplacementRule(pattern1774, replacement1774) pattern1775 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons40, cons1008, cons1006) rule1775 = ReplacementRule(pattern1775, With1775) pattern1776 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons130, cons1008, cons1007) rule1776 = ReplacementRule(pattern1776, replacement1776) pattern1777 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons65, cons1008, cons1007, CustomConstraint(With1777)) rule1777 = ReplacementRule(pattern1777, replacement1777) pattern1778 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons65, cons1008, cons1007) rule1778 = ReplacementRule(pattern1778, replacement1778) pattern1779 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons149, cons1005, cons1006) rule1779 = ReplacementRule(pattern1779, replacement1779) pattern1780 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons149, cons1005, cons1007) rule1780 = ReplacementRule(pattern1780, With1780) pattern1781 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons149, cons1008, cons1006) rule1781 = ReplacementRule(pattern1781, With1781) pattern1782 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons149, cons1008, cons1007, CustomConstraint(With1782)) rule1782 = ReplacementRule(pattern1782, replacement1782) pattern1783 = Pattern(Integral((x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons149, cons1008, cons1007) rule1783 = ReplacementRule(pattern1783, With1783) pattern1784 = Pattern(Integral(u_**p_, x_), cons5, cons1009, cons1010) rule1784 = ReplacementRule(pattern1784, replacement1784) pattern1785 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons40, cons1005, cons1006) rule1785 = ReplacementRule(pattern1785, replacement1785) pattern1786 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons40, cons1005, cons1007) rule1786 = ReplacementRule(pattern1786, With1786) pattern1787 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons40, cons1008, cons1006) rule1787 = ReplacementRule(pattern1787, With1787) pattern1788 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons130, cons1008, cons1007) rule1788 = ReplacementRule(pattern1788, replacement1788) pattern1789 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons65, cons1008, cons1007, CustomConstraint(With1789)) rule1789 = ReplacementRule(pattern1789, replacement1789) pattern1790 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons65, cons1008, cons1007) rule1790 = ReplacementRule(pattern1790, replacement1790) pattern1791 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1005, cons1006) rule1791 = ReplacementRule(pattern1791, replacement1791) pattern1792 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1005, cons1007) rule1792 = ReplacementRule(pattern1792, With1792) pattern1793 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1008, cons1006) rule1793 = ReplacementRule(pattern1793, With1793) pattern1794 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1008, cons1007, CustomConstraint(With1794)) rule1794 = ReplacementRule(pattern1794, replacement1794) pattern1795 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*(x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons149, cons1008, cons1007) rule1795 = ReplacementRule(pattern1795, With1795) pattern1796 = Pattern(Integral(u_**WC('m', S(1))*v_**WC('p', S(1)), x_), cons19, cons5, cons70, cons1011, cons1012) rule1796 = ReplacementRule(pattern1796, replacement1796) pattern1797 = Pattern(Integral((f_ + x_**S(2)*WC('g', S(1)))/((d_ + x_**S(2)*WC('d', S(1)) + x_*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('a', S(1)) + x_**S(3)*WC('b', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons385, cons1013, cons1014) rule1797 = ReplacementRule(pattern1797, replacement1797) pattern1798 = Pattern(Integral((f_ + x_**S(2)*WC('g', S(1)))/((d_ + x_**S(2)*WC('d', S(1)) + x_*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('a', S(1)) + x_**S(3)*WC('b', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons385, cons1013, cons1015) rule1798 = ReplacementRule(pattern1798, replacement1798) pattern1799 = Pattern(Integral((x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1016, cons1017, cons1018) rule1799 = ReplacementRule(pattern1799, replacement1799) pattern1800 = Pattern(Integral(v_**p_, x_), cons5, cons1019, cons1020, cons1017, cons1018, CustomConstraint(With1800)) rule1800 = ReplacementRule(pattern1800, replacement1800) pattern1801 = Pattern(Integral(u_*(x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons806, cons1016, cons359) rule1801 = ReplacementRule(pattern1801, replacement1801) pattern1802 = Pattern(Integral(u_*v_**p_, x_), cons5, cons806, cons1019, cons1020, cons359, CustomConstraint(With1802)) rule1802 = ReplacementRule(pattern1802, replacement1802) pattern1803 = Pattern(Integral((a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons1021, cons248) rule1803 = ReplacementRule(pattern1803, replacement1803) pattern1804 = Pattern(Integral(v_**p_, x_), cons5, cons1019, cons1020, cons248, CustomConstraint(With1804)) rule1804 = ReplacementRule(pattern1804, replacement1804) pattern1805 = Pattern(Integral((x_**S(3)*WC('D', S(1)) + x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons1025, cons1022, cons1023, cons1024) rule1805 = ReplacementRule(pattern1805, With1805) pattern1806 = Pattern(Integral((x_**S(3)*WC('D', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons36, cons37, cons1025, cons1022, cons1023, cons1024) rule1806 = ReplacementRule(pattern1806, With1806) pattern1807 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(3)*WC('D', S(1)) + x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons1025, cons19, cons1022, cons1023, cons1024) rule1807 = ReplacementRule(pattern1807, With1807) pattern1808 = Pattern(Integral(x_**WC('m', S(1))*(x_**S(3)*WC('D', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons36, cons37, cons1025, cons19, cons1022, cons1023, cons1024) rule1808 = ReplacementRule(pattern1808, With1808) pattern1809 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1026, cons1027, cons1028) rule1809 = ReplacementRule(pattern1809, With1809) pattern1810 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons1029, cons1030, cons1031) rule1810 = ReplacementRule(pattern1810, With1810) pattern1811 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1026, cons1027, cons1032) rule1811 = ReplacementRule(pattern1811, With1811) pattern1812 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons1029, cons1030, cons1033) rule1812 = ReplacementRule(pattern1812, With1812) pattern1813 = Pattern(Integral((x_**S(3)*WC('D', S(1)) + x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1025, cons1034, cons1035) rule1813 = ReplacementRule(pattern1813, replacement1813) pattern1814 = Pattern(Integral((x_**S(3)*WC('D', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(a_ + x_**S(4)*WC('e', S(1)) + x_**S(3)*WC('d', S(1)) + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons1025, cons1036, cons1037) rule1814 = ReplacementRule(pattern1814, replacement1814) pattern1815 = Pattern(Integral(u_/(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1)) + sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1038) rule1815 = ReplacementRule(pattern1815, replacement1815) pattern1816 = Pattern(Integral(u_/(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1)) + sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1039) rule1816 = ReplacementRule(pattern1816, replacement1816) pattern1817 = Pattern(Integral(u_/(sqrt(x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1)) + sqrt(x_*WC('d', S(1)) + WC('c', S(0)))*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1040, cons1041) rule1817 = ReplacementRule(pattern1817, replacement1817) pattern1818 = Pattern(Integral(WC('u', S(1))/(x_**WC('n', S(1))*WC('d', S(1)) + sqrt(x_**WC('p', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons4, cons1042, cons1043) rule1818 = ReplacementRule(pattern1818, replacement1818) pattern1819 = Pattern(Integral(x_**WC('m', S(1))/(x_**WC('n', S(1))*WC('d', S(1)) + sqrt(x_**WC('p', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1042, cons1044) rule1819 = ReplacementRule(pattern1819, replacement1819) pattern1820 = Pattern(Integral(S(1)/((a_ + x_**S(3)*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons470) rule1820 = ReplacementRule(pattern1820, With1820) pattern1821 = Pattern(Integral(S(1)/((a_ + x_**S(3)*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons29, cons127, cons470) rule1821 = ReplacementRule(pattern1821, With1821) pattern1822 = Pattern(Integral(S(1)/((a_ + x_**S(3)*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons471) rule1822 = ReplacementRule(pattern1822, With1822) pattern1823 = Pattern(Integral(S(1)/((a_ + x_**S(3)*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons29, cons127, cons471) rule1823 = ReplacementRule(pattern1823, With1823) pattern1824 = Pattern(Integral(S(1)/((d_ + x_*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule1824 = ReplacementRule(pattern1824, replacement1824) pattern1825 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons299) rule1825 = ReplacementRule(pattern1825, replacement1825) pattern1826 = Pattern(Integral(S(1)/((d_ + x_*WC('e', S(1)))**S(2)*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1046, cons1047) rule1826 = ReplacementRule(pattern1826, replacement1826) pattern1827 = Pattern(Integral(S(1)/((d_ + x_*WC('e', S(1)))**S(2)*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1046, cons1048) rule1827 = ReplacementRule(pattern1827, replacement1827) pattern1828 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_*WC('e', S(1)))**S(2)), x_), cons2, cons8, cons29, cons50, cons1049) rule1828 = ReplacementRule(pattern1828, replacement1828) pattern1829 = Pattern(Integral((A_ + x_**S(2)*WC('B', S(1)))/((d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons1050, cons707) rule1829 = ReplacementRule(pattern1829, replacement1829) pattern1830 = Pattern(Integral((A_ + x_**S(2)*WC('B', S(1)))/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons36, cons37, cons1050, cons707) rule1830 = ReplacementRule(pattern1830, replacement1830) pattern1831 = Pattern(Integral((A_ + x_**S(4)*WC('B', S(1)))/(sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))*(d_ + x_**S(4)*WC('f', S(1)) + x_**S(2)*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons384, cons1051) rule1831 = ReplacementRule(pattern1831, replacement1831) pattern1832 = Pattern(Integral((A_ + x_**S(4)*WC('B', S(1)))/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(4)*WC('f', S(1)) + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons384, cons1051) rule1832 = ReplacementRule(pattern1832, replacement1832) pattern1833 = Pattern(Integral((A_ + x_**S(4)*WC('B', S(1)))/((d_ + x_**S(4)*WC('f', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons37, cons384, cons1051) rule1833 = ReplacementRule(pattern1833, replacement1833) pattern1834 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))/(d_ + x_**S(4)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1052, cons699) rule1834 = ReplacementRule(pattern1834, replacement1834) pattern1835 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))/(d_ + x_**S(4)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons1052, cons711) rule1835 = ReplacementRule(pattern1835, With1835) pattern1836 = Pattern(Integral(S(1)/((a_ + x_*WC('b', S(1)))*sqrt(c_ + x_**S(2)*WC('d', S(1)))*sqrt(e_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons155) rule1836 = ReplacementRule(pattern1836, replacement1836) pattern1837 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))*sqrt(x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons1053, cons1054) rule1837 = ReplacementRule(pattern1837, replacement1837) pattern1838 = Pattern(Integral((u_ + (sqrt(v_)*WC('k', S(1)) + WC('j', S(0)))*WC('f', S(1)))**WC('n', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1)), x_), cons127, cons210, cons211, cons798, cons799, cons19, cons4, cons70, cons820, cons1055, cons1056) rule1838 = ReplacementRule(pattern1838, replacement1838) pattern1839 = Pattern(Integral(((x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0)))**n_*WC('h', S(1)) + WC('g', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons1057, cons40) rule1839 = ReplacementRule(pattern1839, replacement1839) pattern1840 = Pattern(Integral(((x_*WC('e', S(1)) + sqrt(a_ + x_**S(2)*WC('c', S(1)))*WC('f', S(1)) + WC('d', S(0)))**n_*WC('h', S(1)) + WC('g', S(0)))**WC('p', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons4, cons1057, cons40) rule1840 = ReplacementRule(pattern1840, replacement1840) pattern1841 = Pattern(Integral(((u_ + sqrt(v_)*WC('f', S(1)))**n_*WC('h', S(1)) + WC('g', S(0)))**WC('p', S(1)), x_), cons127, cons210, cons211, cons4, cons70, cons820, cons821, cons1058, cons40) rule1841 = ReplacementRule(pattern1841, replacement1841) pattern1842 = Pattern(Integral((x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))*WC('f', S(1)))**WC('n', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1)), x_), cons2, cons8, cons50, cons127, cons210, cons211, cons4, cons1057, cons20) rule1842 = ReplacementRule(pattern1842, replacement1842) pattern1843 = Pattern(Integral(x_**WC('p', S(1))*(g_ + x_**S(2)*WC('i', S(1)))**WC('m', S(1))*(x_*WC('e', S(1)) + sqrt(a_ + x_**S(2)*WC('c', S(1)))*WC('f', S(1)))**WC('n', S(1)), x_), cons2, cons8, cons50, cons127, cons210, cons226, cons4, cons1057, cons1059, cons1060, cons1061) rule1843 = ReplacementRule(pattern1843, replacement1843) pattern1844 = Pattern(Integral((x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0)))**WC('n', S(1))*(x_**S(2)*WC('i', S(1)) + x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons4, cons1057, cons1059, cons1062, cons517, cons1061) rule1844 = ReplacementRule(pattern1844, replacement1844) pattern1845 = Pattern(Integral((g_ + x_**S(2)*WC('i', S(1)))**WC('m', S(1))*(x_*WC('e', S(1)) + sqrt(a_ + x_**S(2)*WC('c', S(1)))*WC('f', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons226, cons4, cons1057, cons1059, cons517, cons1061) rule1845 = ReplacementRule(pattern1845, replacement1845) pattern1846 = Pattern(Integral((x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0)))**WC('n', S(1))*(x_**S(2)*WC('i', S(1)) + x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons4, cons1057, cons1059, cons1062, cons75, cons1063) rule1846 = ReplacementRule(pattern1846, replacement1846) pattern1847 = Pattern(Integral((g_ + x_**S(2)*WC('i', S(1)))**WC('m', S(1))*(x_*WC('e', S(1)) + sqrt(a_ + x_**S(2)*WC('c', S(1)))*WC('f', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons226, cons4, cons1057, cons1059, cons75, cons1063) rule1847 = ReplacementRule(pattern1847, replacement1847) pattern1848 = Pattern(Integral((x_*WC('e', S(1)) + sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*WC('f', S(1)) + WC('d', S(0)))**WC('n', S(1))*(x_**S(2)*WC('i', S(1)) + x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons4, cons1057, cons1059, cons1062, cons953, cons1063) rule1848 = ReplacementRule(pattern1848, replacement1848) pattern1849 = Pattern(Integral((g_ + x_**S(2)*WC('i', S(1)))**WC('m', S(1))*(x_*WC('e', S(1)) + sqrt(a_ + x_**S(2)*WC('c', S(1)))*WC('f', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons226, cons4, cons1057, cons1059, cons953, cons1063) rule1849 = ReplacementRule(pattern1849, replacement1849) pattern1850 = Pattern(Integral(w_**WC('m', S(1))*(u_ + (sqrt(v_)*WC('k', S(1)) + WC('j', S(0)))*WC('f', S(1)))**WC('n', S(1)), x_), cons127, cons798, cons799, cons19, cons4, cons70, cons1064, cons1065, cons1066) rule1850 = ReplacementRule(pattern1850, replacement1850) pattern1851 = Pattern(Integral(S(1)/((a_ + x_**WC('n', S(1))*WC('b', S(1)))*sqrt(x_**S(2)*WC('c', S(1)) + (a_ + x_**WC('n', S(1))*WC('b', S(1)))**WC('p', S(1))*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons4, cons1067) rule1851 = ReplacementRule(pattern1851, replacement1851) pattern1852 = Pattern(Integral(sqrt(a_ + sqrt(c_ + x_**S(2)*WC('d', S(1)))*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons1068) rule1852 = ReplacementRule(pattern1852, replacement1852) pattern1853 = Pattern(Integral(sqrt(x_**S(2)*WC('a', S(1)) + x_*sqrt(c_ + x_**S(2)*WC('d', S(1)))*WC('b', S(1)))/(x_*sqrt(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons1069, cons1070) rule1853 = ReplacementRule(pattern1853, replacement1853) pattern1854 = Pattern(Integral(sqrt(x_*(x_*WC('a', S(1)) + sqrt(c_ + x_**S(2)*WC('d', S(1)))*WC('b', S(1)))*WC('e', S(1)))/(x_*sqrt(c_ + x_**S(2)*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons1069, cons1071) rule1854 = ReplacementRule(pattern1854, replacement1854) pattern1855 = Pattern(Integral(sqrt(x_**S(2)*WC('c', S(1)) + sqrt(a_ + x_**S(4)*WC('b', S(1)))*WC('d', S(1)))/sqrt(a_ + x_**S(4)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons1072) rule1855 = ReplacementRule(pattern1855, replacement1855) pattern1856 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sqrt(x_**S(2)*WC('b', S(1)) + sqrt(a_ + x_**S(4)*WC('e', S(1))))/sqrt(a_ + x_**S(4)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons1073, cons45) rule1856 = ReplacementRule(pattern1856, replacement1856) pattern1857 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons483, cons481) rule1857 = ReplacementRule(pattern1857, With1857) pattern1858 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons483, cons482) rule1858 = ReplacementRule(pattern1858, With1858) pattern1859 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons484, cons481) rule1859 = ReplacementRule(pattern1859, With1859) pattern1860 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons484, cons482) rule1860 = ReplacementRule(pattern1860, With1860) pattern1861 = Pattern(Integral((e_ + x_*WC('f', S(1)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons483, cons481, CustomConstraint(With1861)) rule1861 = ReplacementRule(pattern1861, replacement1861) pattern1862 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons483, cons481, CustomConstraint(With1862)) rule1862 = ReplacementRule(pattern1862, replacement1862) pattern1863 = Pattern(Integral((e_ + x_*WC('f', S(1)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons483, cons482, CustomConstraint(With1863)) rule1863 = ReplacementRule(pattern1863, replacement1863) pattern1864 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons483, cons482, CustomConstraint(With1864)) rule1864 = ReplacementRule(pattern1864, replacement1864) pattern1865 = Pattern(Integral((e_ + x_*WC('f', S(1)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons484, cons481, CustomConstraint(With1865)) rule1865 = ReplacementRule(pattern1865, replacement1865) pattern1866 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons484, cons481, CustomConstraint(With1866)) rule1866 = ReplacementRule(pattern1866, replacement1866) pattern1867 = Pattern(Integral((e_ + x_*WC('f', S(1)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons484, cons482, CustomConstraint(With1867)) rule1867 = ReplacementRule(pattern1867, replacement1867) pattern1868 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))/(sqrt(a_ + x_**S(3)*WC('b', S(1)))*(c_ + x_*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons484, cons482, CustomConstraint(With1868)) rule1868 = ReplacementRule(pattern1868, replacement1868) pattern1869 = Pattern(Integral(x_**WC('m', S(1))/(c_ + x_**n_*WC('d', S(1)) + sqrt(a_ + x_**n_*WC('b', S(1)))*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1074, cons502) rule1869 = ReplacementRule(pattern1869, replacement1869) pattern1870 = Pattern(Integral(WC('u', S(1))/(c_ + x_**n_*WC('d', S(1)) + sqrt(a_ + x_**n_*WC('b', S(1)))*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1074) rule1870 = ReplacementRule(pattern1870, replacement1870) pattern1871 = Pattern(Integral((A_ + x_**n_*WC('B', S(1)))/(a_ + x_**S(2)*WC('b', S(1)) + x_**n2_*WC('d', S(1)) + x_**n_*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons4, cons48, cons965, cons1075, cons1076) rule1871 = ReplacementRule(pattern1871, replacement1871) pattern1872 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('n', S(1))*WC('B', S(1)))/(a_ + x_**n2_*WC('d', S(1)) + x_**WC('k', S(1))*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons36, cons37, cons19, cons4, cons48, cons1077, cons1078, cons1079) rule1872 = ReplacementRule(pattern1872, replacement1872) pattern1873 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_*(d_ + g_*x_**n3_ + x_**n2_*WC('f', S(1)) + x_**n_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons48, cons933, cons228, cons704) rule1873 = ReplacementRule(pattern1873, replacement1873) pattern1874 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_*(d_ + x_**n2_*WC('f', S(1)) + x_**n_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons48, cons228, cons704) rule1874 = ReplacementRule(pattern1874, replacement1874) pattern1875 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_*(d_ + g_*x_**n3_ + x_**n_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons210, cons4, cons48, cons933, cons228, cons704) rule1875 = ReplacementRule(pattern1875, replacement1875) pattern1876 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_*(d_ + g_*x_**n3_ + x_**n2_*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons4, cons48, cons933, cons228, cons704) rule1876 = ReplacementRule(pattern1876, replacement1876) pattern1877 = Pattern(Integral((d_ + x_**n2_*WC('f', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons4, cons48, cons228, cons704) rule1877 = ReplacementRule(pattern1877, replacement1877) pattern1878 = Pattern(Integral((d_ + g_*x_**n3_)*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons210, cons4, cons48, cons933, cons228, cons704) rule1878 = ReplacementRule(pattern1878, replacement1878) pattern1879 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + g_*x_**n3_ + x_**n2_*WC('f', S(1)) + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons48, cons933, cons704) rule1879 = ReplacementRule(pattern1879, replacement1879) pattern1880 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n2_*WC('f', S(1)) + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons4, cons48, cons704) rule1880 = ReplacementRule(pattern1880, replacement1880) pattern1881 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + g_*x_**n3_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons210, cons4, cons48, cons933, cons704) rule1881 = ReplacementRule(pattern1881, replacement1881) pattern1882 = Pattern(Integral((x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)) + WC('a', S(0)))/(d_ + x_**S(6)*WC('g', S(1)) + x_**S(4)*WC('f', S(1)) + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1080, cons1081, cons1082, cons1083, cons1084, cons1085) rule1882 = ReplacementRule(pattern1882, With1882) pattern1883 = Pattern(Integral((x_**S(4)*WC('c', S(1)) + WC('a', S(0)))/(d_ + x_**S(6)*WC('g', S(1)) + x_**S(4)*WC('f', S(1)) + x_**S(2)*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons1086, cons1087, cons1082, cons1088) rule1883 = ReplacementRule(pattern1883, With1883) pattern1884 = Pattern(Integral(u_*v_**p_, x_), cons13, cons139, cons806, cons1019, cons1089, cons1090, cons1091, CustomConstraint(With1884)) rule1884 = ReplacementRule(pattern1884, replacement1884) return [rule1476, rule1477, rule1478, rule1479, rule1480, rule1481, rule1482, rule1483, rule1484, rule1485, rule1486, rule1487, rule1488, rule1489, rule1490, rule1491, rule1492, rule1493, rule1494, rule1495, rule1496, rule1497, rule1498, rule1499, rule1500, rule1501, rule1502, rule1503, rule1504, rule1505, rule1506, rule1507, rule1508, rule1509, rule1510, rule1511, rule1512, rule1513, rule1514, rule1515, rule1516, rule1517, rule1518, rule1519, rule1520, rule1521, rule1522, rule1523, rule1524, rule1525, rule1526, rule1527, rule1528, rule1529, rule1530, rule1531, rule1532, rule1533, rule1534, rule1535, rule1536, rule1537, rule1538, rule1539, rule1540, rule1541, rule1542, rule1543, rule1544, rule1545, rule1546, rule1547, rule1548, rule1549, rule1550, rule1551, rule1552, rule1553, rule1554, rule1555, rule1556, rule1557, rule1558, rule1559, rule1560, rule1561, rule1562, rule1563, rule1564, rule1565, rule1566, rule1567, rule1568, rule1569, rule1570, rule1571, rule1572, rule1573, rule1574, rule1575, rule1576, rule1577, rule1578, rule1579, rule1580, rule1581, rule1582, rule1583, rule1584, rule1585, rule1586, rule1587, rule1588, rule1589, rule1590, rule1591, rule1592, rule1593, rule1594, rule1595, rule1596, rule1597, rule1598, rule1599, rule1600, rule1601, rule1602, rule1603, rule1604, rule1605, rule1606, rule1607, rule1608, rule1609, rule1610, rule1611, rule1612, rule1613, rule1614, rule1615, rule1616, rule1617, rule1618, rule1619, rule1620, rule1621, rule1622, rule1623, rule1624, rule1625, rule1626, rule1627, rule1628, rule1629, rule1630, rule1631, rule1632, rule1633, rule1634, rule1635, rule1636, rule1637, rule1638, rule1639, rule1640, rule1641, rule1642, rule1643, rule1644, rule1645, rule1646, rule1647, rule1648, rule1649, rule1650, rule1651, rule1652, rule1653, rule1654, rule1655, rule1656, rule1657, rule1658, rule1659, rule1660, rule1661, rule1662, rule1663, rule1664, rule1665, rule1666, rule1667, rule1668, rule1669, rule1670, rule1671, rule1672, rule1673, rule1674, rule1675, rule1676, rule1677, rule1678, rule1679, rule1680, rule1681, rule1682, rule1683, rule1684, rule1685, rule1686, rule1687, rule1688, rule1689, rule1690, rule1691, rule1692, rule1693, rule1694, rule1695, rule1696, rule1697, rule1698, rule1699, rule1700, rule1701, rule1702, rule1703, rule1704, rule1705, rule1706, rule1707, rule1708, rule1709, rule1710, rule1711, rule1712, rule1713, rule1714, rule1715, rule1716, rule1717, rule1718, rule1719, rule1720, rule1721, rule1722, rule1723, rule1724, rule1725, rule1726, rule1727, rule1728, rule1729, rule1730, rule1731, rule1732, rule1733, rule1734, rule1735, rule1736, rule1737, rule1738, rule1739, rule1740, rule1741, rule1742, rule1743, rule1744, rule1745, rule1746, rule1747, rule1748, rule1749, rule1750, rule1751, rule1752, rule1753, rule1754, rule1755, rule1756, rule1757, rule1758, rule1759, rule1760, rule1761, rule1762, rule1763, rule1764, rule1765, rule1766, rule1767, rule1768, rule1769, rule1770, rule1771, rule1772, rule1773, rule1774, rule1775, rule1776, rule1777, rule1778, rule1779, rule1780, rule1781, rule1782, rule1783, rule1784, rule1785, rule1786, rule1787, rule1788, rule1789, rule1790, rule1791, rule1792, rule1793, rule1794, rule1795, rule1796, rule1797, rule1798, rule1799, rule1800, rule1801, rule1802, rule1803, rule1804, rule1805, rule1806, rule1807, rule1808, rule1809, rule1810, rule1811, rule1812, rule1813, rule1814, rule1815, rule1816, rule1817, rule1818, rule1819, rule1820, rule1821, rule1822, rule1823, rule1824, rule1825, rule1826, rule1827, rule1828, rule1829, rule1830, rule1831, rule1832, rule1833, rule1834, rule1835, rule1836, rule1837, rule1838, rule1839, rule1840, rule1841, rule1842, rule1843, rule1844, rule1845, rule1846, rule1847, rule1848, rule1849, rule1850, rule1851, rule1852, rule1853, rule1854, rule1855, rule1856, rule1857, rule1858, rule1859, rule1860, rule1861, rule1862, rule1863, rule1864, rule1865, rule1866, rule1867, rule1868, rule1869, rule1870, rule1871, rule1872, rule1873, rule1874, rule1875, rule1876, rule1877, rule1878, rule1879, rule1880, rule1881, rule1882, rule1883, rule1884, ] def replacement1476(a, b, c, n, p, q, x): return Dist(x*(c*x**n)**(-S(1)/n), Subst(Int((a + b*x**(n*q))**p, x), x, (c*x**n)**(S(1)/n)), x) def replacement1477(a, b, c, m, n, p, q, x): return Dist(x**(m + S(1))*(c*x**n)**(-(m + S(1))/n), Subst(Int(x**m*(a + b*x**(n*q))**p, x), x, (c*x**n)**(S(1)/n)), x) def replacement1478(a, b, c, d, e, f, m, n, p, q, r, s, x): return Dist((e*(a + b*x**n)**r)**p*(f*(c + d*x**n)**s)**q*(a + b*x**n)**(-p*r)*(c + d*x**n)**(-q*s), Int(x**m*(a + b*x**n)**(p*r)*(c + d*x**n)**(q*s), x), x) def replacement1479(a, b, c, d, e, n, p, u, x): return Dist((b*e/d)**p, Int(u, x), x) def replacement1480(a, b, c, d, e, n, p, u, x): return Int(u*(e*(a + b*x**n))**p*(c + d*x**n)**(-p), x) def With1481(a, b, c, d, e, n, p, x): q = Denominator(p) return Dist(e*q*(-a*d + b*c)/n, Subst(Int(x**(q*(p + S(1)) + S(-1))*(-a*e + c*x**q)**(S(-1) + S(1)/n)*(b*e - d*x**q)**(S(-1) - S(1)/n), x), x, (e*(a + b*x**n)/(c + d*x**n))**(S(1)/q)), x) def With1482(a, b, c, d, e, m, n, p, x): q = Denominator(p) return Dist(e*q*(-a*d + b*c)/n, Subst(Int(x**(q*(p + S(1)) + S(-1))*(-a*e + c*x**q)**(S(-1) + (m + S(1))/n)*(b*e - d*x**q)**(S(-1) - (m + S(1))/n), x), x, (e*(a + b*x**n)/(c + d*x**n))**(S(1)/q)), x) def With1483(a, b, c, d, e, n, p, r, u, x): q = Denominator(p) return Dist(e*q*(-a*d + b*c)/n, Subst(Int(SimplifyIntegrand(x**(q*(p + S(1)) + S(-1))*(-a*e + c*x**q)**(S(-1) + S(1)/n)*(b*e - d*x**q)**(S(-1) - S(1)/n)*ReplaceAll(u, Rule(x, (-a*e + c*x**q)**(S(1)/n)*(b*e - d*x**q)**(-S(1)/n)))**r, x), x), x, (e*(a + b*x**n)/(c + d*x**n))**(S(1)/q)), x) def With1484(a, b, c, d, e, m, n, p, r, u, x): q = Denominator(p) return Dist(e*q*(-a*d + b*c)/n, Subst(Int(SimplifyIntegrand(x**(q*(p + S(1)) + S(-1))*(-a*e + c*x**q)**(S(-1) + (m + S(1))/n)*(b*e - d*x**q)**(S(-1) - (m + S(1))/n)*ReplaceAll(u, Rule(x, (-a*e + c*x**q)**(S(1)/n)*(b*e - d*x**q)**(-S(1)/n)))**r, x), x), x, (e*(a + b*x**n)/(c + d*x**n))**(S(1)/q)), x) def replacement1485(a, b, c, n, p, x): return -Dist(c, Subst(Int((a + b*x**n)**p/x**S(2), x), x, c/x), x) def replacement1486(a, b, c, m, n, p, x): return -Dist(c**(m + S(1)), Subst(Int(x**(-m + S(-2))*(a + b*x**n)**p, x), x, c/x), x) def replacement1487(a, b, c, d, m, n, p, x): return -Dist(c*(c/x)**m*(d*x)**m, Subst(Int(x**(-m + S(-2))*(a + b*x**n)**p, x), x, c/x), x) def replacement1488(a, b, c, d, n, n2, p, x): return -Dist(d, Subst(Int((a + b*x**n + c*x**(S(2)*n))**p/x**S(2), x), x, d/x), x) def replacement1489(a, b, c, d, m, n, n2, p, x): return -Dist(d**(m + S(1)), Subst(Int(x**(-m + S(-2))*(a + b*x**n + c*x**(S(2)*n))**p, x), x, d/x), x) def replacement1490(a, b, c, d, e, m, n, n2, p, x): return -Dist(d*(d/x)**m*(e*x)**m, Subst(Int(x**(-m + S(-2))*(a + b*x**n + c*x**(S(2)*n))**p, x), x, d/x), x) def replacement1491(a, b, c, d, n, n2, p, x): return -Dist(d, Subst(Int((a + b*x**n + c*d**(-S(2)*n)*x**(S(2)*n))**p/x**S(2), x), x, d/x), x) def replacement1492(a, b, c, d, m, n, n2, p, x): return -Dist(d**(m + S(1)), Subst(Int(x**(-m + S(-2))*(a + b*x**n + c*d**(-S(2)*n)*x**(S(2)*n))**p, x), x, d/x), x) def replacement1493(a, b, c, d, e, m, n, n2, p, x): return -Dist(d*(d/x)**m*(e*x)**m, Subst(Int(x**(-m + S(-2))*(a + b*x**n + c*d**(-S(2)*n)*x**(S(2)*n))**p, x), x, d/x), x) def replacement1494(m, u, x): return Int(ExpandToSum(u, x)**m, x) def replacement1495(m, n, u, v, x): return Int(ExpandToSum(u, x)**m*ExpandToSum(v, x)**n, x) def replacement1496(m, n, p, u, v, w, x): return Int(ExpandToSum(u, x)**m*ExpandToSum(v, x)**n*ExpandToSum(w, x)**p, x) def replacement1497(m, n, p, q, u, v, w, x, z): return Int(ExpandToSum(u, x)**m*ExpandToSum(v, x)**n*ExpandToSum(w, x)**p*ExpandToSum(z, x)**q, x) def replacement1498(p, u, x): return Int(ExpandToSum(u, x)**p, x) def replacement1499(m, p, u, v, x): return Int(ExpandToSum(u, x)**m*ExpandToSum(v, x)**p, x) def replacement1500(m, n, p, u, v, w, x): return Int(ExpandToSum(u, x)**m*ExpandToSum(v, x)**n*ExpandToSum(w, x)**p, x) def replacement1501(p, q, u, v, x): return Int(ExpandToSum(u, x)**p*ExpandToSum(v, x)**q, x) def replacement1502(p, u, x): return Int(ExpandToSum(u, x)**p, x) def replacement1503(c, m, p, u, x): return Int((c*x)**m*ExpandToSum(u, x)**p, x) def replacement1504(p, q, u, v, x): return Int(ExpandToSum(u, x)**p*ExpandToSum(v, x)**q, x) def replacement1505(m, p, q, u, v, x): return Int(x**m*ExpandToSum(u, x)**p*ExpandToSum(v, x)**q, x) def replacement1506(m, p, q, u, v, w, x): return Int(ExpandToSum(u, x)**m*ExpandToSum(v, x)**p*ExpandToSum(w, x)**q, x) def replacement1507(m, p, q, r, u, v, x, z): return Int(x**m*ExpandToSum(u, x)**p*ExpandToSum(v, x)**q*ExpandToSum(z, x)**r, x) def replacement1508(p, u, x): return Int(ExpandToSum(u, x)**p, x) def replacement1509(m, p, u, x): return Int(x**m*ExpandToSum(u, x)**p, x) def replacement1510(p, u, x): return Int(ExpandToSum(u, x)**p, x) def replacement1511(d, m, p, u, x): return Int((d*x)**m*ExpandToSum(u, x)**p, x) def replacement1512(p, q, u, v, x): return Int(ExpandToSum(u, x)**q*ExpandToSum(v, x)**p, x) def replacement1513(p, q, u, v, x): return Int(ExpandToSum(u, x)**q*ExpandToSum(v, x)**p, x) def replacement1514(m, p, q, u, x, z): return Int(x**m*ExpandToSum(u, x)**p*ExpandToSum(z, x)**q, x) def replacement1515(m, p, q, u, x, z): return Int(x**m*ExpandToSum(u, x)**p*ExpandToSum(z, x)**q, x) def replacement1516(p, u, x): return Int(ExpandToSum(u, x)**p, x) def replacement1517(m, p, u, x): return Int(x**m*ExpandToSum(u, x)**p, x) def replacement1518(p, u, x, z): return Int(ExpandToSum(u, x)**p*ExpandToSum(z, x), x) def replacement1519(m, p, u, x, z): return Int(x**m*ExpandToSum(u, x)**p*ExpandToSum(z, x), x) def replacement1520(a, c, e, f, g, h, m, n, q, r, x): return -Simp((S(2)*a*g + S(4)*a*h*x**(n/S(4)) - S(2)*c*f*x**(n/S(2)))/(a*c*n*sqrt(a + c*x**n)), x) def replacement1521(a, c, d, e, f, g, h, m, n, q, r, x): return Dist(x**(-m)*(d*x)**m, Int(x**m*(e + f*x**(n/S(4)) + g*x**(S(3)*n/S(4)) + h*x**n)/(a + c*x**n)**(S(3)/2), x), x) def With1522(Pq, a, b, c, m, p, x): n = Denominator(p) return Dist(n/b, Subst(Int(x**(n*p + n + S(-1))*(-a*c/b + c*x**n/b)**m*ReplaceAll(Pq, Rule(x, -a/b + x**n/b)), x), x, (a + b*x)**(S(1)/n)), x) def replacement1523(Pq, a, b, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*x**(n/(m + S(1))))**p*SubstFor(x**(m + S(1)), Pq, x), x), x, x**(m + S(1))), x) def replacement1524(Pq, a, b, n, p, x): return Int((a + b*x**n)**p*ExpandToSum(Pq - x**(n + S(-1))*Coeff(Pq, x, n + S(-1)), x), x) + Simp((a + b*x**n)**(p + S(1))*Coeff(Pq, x, n + S(-1))/(b*n*(p + S(1))), x) def replacement1525(Pq, a, b, c, m, n, p, x): return Int(ExpandIntegrand(Pq*(c*x)**m*(a + b*x**n)**p, x), x) def replacement1526(Pq, a, b, n, p, x): return Int(ExpandIntegrand(Pq*(a + b*x**n)**p, x), x) def replacement1527(Pq, a, b, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*x)**p*SubstFor(x**n, Pq, x), x), x, x**n), x) def replacement1528(Pq, a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(Pq*x**m*(a + b*x**n)**p, x), x) def replacement1529(Pq, a, b, m, n, p, x): return -Dist(S(1)/(b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*D(Pq, x), x), x) + Simp(Pq*(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement1530(Pq, a, b, d, m, n, p, x): return Dist(S(1)/d, Int((d*x)**(m + S(1))*(a + b*x**n)**p*ExpandToSum(Pq/x, x), x), x) def replacement1531(Pq, a, b, n, p, x): return Int(x*(a + b*x**n)**p*ExpandToSum(Pq/x, x), x) def With1532(Pq, a, b, m, n, p, x): u = IntHide(Pq*x**m, x) return -Dist(b*n*p, Int(x**(m + n)*(a + b*x**n)**(p + S(-1))*ExpandToSum(u*x**(-m + S(-1)), x), x), x) + Simp(u*(a + b*x**n)**p, x) def With1533(Pq, a, b, c, m, n, p, x): q = Expon(Pq, x) i = Symbol('i') return Dist(a*n*p, Int((c*x)**m*(a + b*x**n)**(p + S(-1))*Sum_doit(x**i*Coeff(Pq, x, i)/(i + m + n*p + S(1)), List(i, S(0), q)), x), x) + Simp((c*x)**m*(a + b*x**n)**p*Sum_doit(x**(i + S(1))*Coeff(Pq, x, i)/(i + m + n*p + S(1)), List(i, S(0), q)), x) def With1534(Pq, a, b, n, p, x): q = Expon(Pq, x) i = Symbol('i') return Dist(a*n*p, Int((a + b*x**n)**(p + S(-1))*Sum_doit(x**i*Coeff(Pq, x, i)/(i + n*p + S(1)), List(i, S(0), q)), x), x) + Simp((a + b*x**n)**p*Sum_doit(x**(i + S(1))*Coeff(Pq, x, i)/(i + n*p + S(1)), List(i, S(0), q)), x) def With1535(Pq, a, b, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) i = Symbol('i') if Equal(q, n + S(-1)): return True return False def replacement1535(Pq, a, b, n, p, x): q = Expon(Pq, x) i = Symbol('i') return Dist(S(1)/(a*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*Sum_doit(x**i*(i + n*(p + S(1)) + S(1))*Coeff(Pq, x, i), List(i, S(0), q + S(-1))), x), x) + Simp((a + b*x**n)**(p + S(1))*(a*Coeff(Pq, x, q) - b*x*ExpandToSum(Pq - x**q*Coeff(Pq, x, q), x))/(a*b*n*(p + S(1))), x) def replacement1536(Pq, a, b, n, p, x): return Dist(S(1)/(a*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*ExpandToSum(Pq*n*(p + S(1)) + D(Pq*x, x), x), x), x) - Simp(Pq*x*(a + b*x**n)**(p + S(1))/(a*n*(p + S(1))), x) def replacement1537(a, b, d, e, f, g, x): return -Simp((S(2)*a*f + S(4)*a*g*x - S(2)*b*e*x**S(2))/(S(4)*a*b*sqrt(a + b*x**S(4))), x) def replacement1538(a, b, d, f, g, x): return -Simp((f + S(2)*g*x)/(S(2)*b*sqrt(a + b*x**S(4))), x) def replacement1539(a, b, d, e, g, x): return -Simp(x*(S(2)*a*g - b*e*x)/(S(2)*a*b*sqrt(a + b*x**S(4))), x) def replacement1540(a, b, e, f, h, x): return -Simp((f - S(2)*h*x**S(3))/(S(2)*b*sqrt(a + b*x**S(4))), x) def replacement1541(a, b, e, h, x): return Simp(h*x**S(3)/(b*sqrt(a + b*x**S(4))), x) def replacement1542(a, b, d, e, f, g, h, x): return -Simp((a*f - S(2)*a*h*x**S(3) - S(2)*b*d*x)/(S(2)*a*b*sqrt(a + b*x**S(4))), x) def replacement1543(a, b, d, e, g, h, x): return Simp(x*(a*h*x**S(2) + b*d)/(a*b*sqrt(a + b*x**S(4))), x) def With1544(Pq, a, b, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Q = PolynomialQuotient(Pq*b**(Floor((q + S(-1))/n) + S(1)), a + b*x**n, x) R = PolynomialRemainder(Pq*b**(Floor((q + S(-1))/n) + S(1)), a + b*x**n, x) if GreaterEqual(q, n): return True return False def replacement1544(Pq, a, b, n, p, x): q = Expon(Pq, x) Q = PolynomialQuotient(Pq*b**(Floor((q + S(-1))/n) + S(1)), a + b*x**n, x) R = PolynomialRemainder(Pq*b**(Floor((q + S(-1))/n) + S(1)), a + b*x**n, x) return Dist(b**(-Floor((q - 1)/n) - 1)/(a*n*(p + 1)), Int((a + b*x**n)**(p + 1)*ExpandToSum(Q*a*n*(p + 1) + R*n*(p + 1) + D(R*x, x), x), x), x) - Simp(R*b**(-Floor((q - 1)/n) - 1)*x*(a + b*x**n)**(p + 1)/(a*n*(p + 1)), x) def With1545(Pq, a, b, m, n, p, x): q = Expon(Pq, x) Q = PolynomialQuotient(Pq*a*b**(Floor((q + S(-1))/n) + S(1))*x**m, a + b*x**n, x) R = PolynomialRemainder(Pq*a*b**(Floor((q + S(-1))/n) + S(1))*x**m, a + b*x**n, x) return Dist(b**(-Floor((q - 1)/n) - 1)/(a*n*(p + 1)), Int(x**m*(a + b*x**n)**(p + 1)*ExpandToSum(Q*n*x**(-m)*(p + 1) + Sum_doit(x**(i - m)*(i + n*(p + 1) + 1)*Coeff(R, x, i)/a, List(i, 0, n - 1)), x), x), x) - Simp(R*b**(-Floor((q - 1)/n) - 1)*x*(a + b*x**n)**(p + 1)/(a**2*n*(p + 1)), x) def With1546(Pq, a, b, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False g = GCD(m + S(1), n) if Unequal(g, S(1)): return True return False def replacement1546(Pq, a, b, m, n, p, x): g = GCD(m + S(1), n) return Dist(S(1)/g, Subst(Int(x**(S(-1) + (m + S(1))/g)*(a + b*x**(n/g))**p*ReplaceAll(Pq, Rule(x, x**(S(1)/g))), x), x, x**g), x) def replacement1547(A, B, a, b, x): return Dist(B**S(3)/b, Int(S(1)/(A**S(2) - A*B*x + B**S(2)*x**S(2)), x), x) def With1548(A, B, a, b, x): r = Numerator(Rt(a/b, S(3))) s = Denominator(Rt(a/b, S(3))) return Dist(r/(S(3)*a*s), Int((r*(S(2)*A*s + B*r) + s*x*(-A*s + B*r))/(r**S(2) - r*s*x + s**S(2)*x**S(2)), x), x) - Dist(r*(-A*s + B*r)/(S(3)*a*s), Int(S(1)/(r + s*x), x), x) def With1549(A, B, a, b, x): r = Numerator(Rt(-a/b, S(3))) s = Denominator(Rt(-a/b, S(3))) return -Dist(r/(S(3)*a*s), Int((r*(-S(2)*A*s + B*r) - s*x*(A*s + B*r))/(r**S(2) + r*s*x + s**S(2)*x**S(2)), x), x) + Dist(r*(A*s + B*r)/(S(3)*a*s), Int(S(1)/(r - s*x), x), x) def replacement1550(A, B, C, a, b, x): return -Dist(C**S(2)/b, Int(S(1)/(B - C*x), x), x) def With1551(A, B, C, a, b, x): q = a**(S(1)/3)/b**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1552(B, C, a, b, x): q = a**(S(1)/3)/b**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1553(A, C, a, b, x): q = a**(S(1)/3)/b**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist(C*q/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1554(A, B, C, a, b, x): q = (-a)**(S(1)/3)/(-b)**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1555(B, C, a, b, x): q = (-a)**(S(1)/3)/(-b)**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1556(A, C, a, b, x): q = (-a)**(S(1)/3)/(-b)**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist(C*q/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1557(A, B, C, a, b, x): q = (-a)**(S(1)/3)/b**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1558(B, C, a, b, x): q = (-a)**(S(1)/3)/b**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1559(A, C, a, b, x): q = (-a)**(S(1)/3)/b**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) - Dist(C*q/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1560(A, B, C, a, b, x): q = a**(S(1)/3)/(-b)**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1561(B, C, a, b, x): q = a**(S(1)/3)/(-b)**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1562(A, C, a, b, x): q = a**(S(1)/3)/(-b)**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) - Dist(C*q/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1563(A, B, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1564(B, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1565(A, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist(C*q/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1566(A, B, C, a, b, x): q = Rt(a/b, S(3)) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1567(B, C, a, b, x): q = Rt(a/b, S(3)) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist((B + C*q)/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1568(A, C, a, b, x): q = Rt(a/b, S(3)) return Dist(C/b, Int(S(1)/(q + x), x), x) + Dist(C*q/b, Int(S(1)/(q**S(2) - q*x + x**S(2)), x), x) def With1569(A, B, C, a, b, x): q = (-a/b)**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1570(B, C, a, b, x): q = (-a/b)**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1571(A, C, a, b, x): q = (-a/b)**(S(1)/3) return -Dist(C/b, Int(S(1)/(q - x), x), x) - Dist(C*q/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1572(A, B, C, a, b, x): q = Rt(-a/b, S(3)) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1573(B, C, a, b, x): q = Rt(-a/b, S(3)) return -Dist(C/b, Int(S(1)/(q - x), x), x) + Dist((B - C*q)/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def With1574(A, C, a, b, x): q = Rt(-a/b, S(3)) return -Dist(C/b, Int(S(1)/(q - x), x), x) - Dist(C*q/b, Int(S(1)/(q**S(2) + q*x + x**S(2)), x), x) def replacement1575(A, B, C, a, b, x): return Dist(C, Int(x**S(2)/(a + b*x**S(3)), x), x) + Int((A + B*x)/(a + b*x**S(3)), x) def replacement1576(B, C, a, b, x): return Dist(B, Int(x/(a + b*x**S(3)), x), x) + Dist(C, Int(x**S(2)/(a + b*x**S(3)), x), x) def replacement1577(A, C, a, b, x): return Dist(A, Int(S(1)/(a + b*x**S(3)), x), x) + Dist(C, Int(x**S(2)/(a + b*x**S(3)), x), x) def With1578(A, B, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(q**S(2)/a, Int((A + C*q*x)/(q**S(2) - q*x + x**S(2)), x), x) def With1579(B, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(C*q**S(3)/a, Int(x/(q**S(2) - q*x + x**S(2)), x), x) def With1580(A, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(q**S(2)/a, Int((A + C*q*x)/(q**S(2) - q*x + x**S(2)), x), x) def With1581(A, B, C, a, b, x): q = (-a/b)**(S(1)/3) return Dist(q/a, Int((A*q + x*(A + B*q))/(q**S(2) + q*x + x**S(2)), x), x) def With1582(B, C, a, b, x): q = (-a/b)**(S(1)/3) return Dist(B*q**S(2)/a, Int(x/(q**S(2) + q*x + x**S(2)), x), x) def With1583(A, C, a, b, x): q = (-a/b)**(S(1)/3) return Dist(A*q/a, Int((q + x)/(q**S(2) + q*x + x**S(2)), x), x) def With1584(A, B, C, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False q = (a/b)**(S(1)/3) if NonzeroQ(A - B*q + C*q**S(2)): return True return False def replacement1584(A, B, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(q/(S(3)*a), Int((q*(S(2)*A + B*q - C*q**S(2)) - x*(A - B*q - S(2)*C*q**S(2)))/(q**S(2) - q*x + x**S(2)), x), x) + Dist(q*(A - B*q + C*q**S(2))/(S(3)*a), Int(S(1)/(q + x), x), x) def With1585(B, C, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False q = (a/b)**(S(1)/3) if NonzeroQ(B*q - C*q**S(2)): return True return False def replacement1585(B, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(q/(S(3)*a), Int((q*(B*q - C*q**S(2)) + x*(B*q + S(2)*C*q**S(2)))/(q**S(2) - q*x + x**S(2)), x), x) - Dist(q*(B*q - C*q**S(2))/(S(3)*a), Int(S(1)/(q + x), x), x) def With1586(A, C, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False q = (a/b)**(S(1)/3) if NonzeroQ(A + C*q**S(2)): return True return False def replacement1586(A, C, a, b, x): q = (a/b)**(S(1)/3) return Dist(q/(S(3)*a), Int((q*(S(2)*A - C*q**S(2)) - x*(A - S(2)*C*q**S(2)))/(q**S(2) - q*x + x**S(2)), x), x) + Dist(q*(A + C*q**S(2))/(S(3)*a), Int(S(1)/(q + x), x), x) def With1587(A, B, C, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False q = (-a/b)**(S(1)/3) if NonzeroQ(A + B*q + C*q**S(2)): return True return False def replacement1587(A, B, C, a, b, x): q = (-a/b)**(S(1)/3) return Dist(q/(S(3)*a), Int((q*(S(2)*A - B*q - C*q**S(2)) + x*(A + B*q - S(2)*C*q**S(2)))/(q**S(2) + q*x + x**S(2)), x), x) + Dist(q*(A + B*q + C*q**S(2))/(S(3)*a), Int(S(1)/(q - x), x), x) def With1588(B, C, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False q = (-a/b)**(S(1)/3) if NonzeroQ(B*q + C*q**S(2)): return True return False def replacement1588(B, C, a, b, x): q = (-a/b)**(S(1)/3) return Dist(q/(S(3)*a), Int((-q*(B*q + C*q**S(2)) + x*(B*q - S(2)*C*q**S(2)))/(q**S(2) + q*x + x**S(2)), x), x) + Dist(q*(B*q + C*q**S(2))/(S(3)*a), Int(S(1)/(q - x), x), x) def With1589(A, C, a, b, x): if isinstance(x, (int, Integer, float, Float)): return False q = (-a/b)**(S(1)/3) if NonzeroQ(A + C*q**S(2)): return True return False def replacement1589(A, C, a, b, x): q = (-a/b)**(S(1)/3) return Dist(q/(S(3)*a), Int((q*(S(2)*A - C*q**S(2)) + x*(A - S(2)*C*q**S(2)))/(q**S(2) + q*x + x**S(2)), x), x) + Dist(q*(A + C*q**S(2))/(S(3)*a), Int(S(1)/(q - x), x), x) def With1590(Pq, a, b, c, m, n, x): if isinstance(x, (int, Integer, float, Float)): return False v = Sum_doit(c**(-ii)*(c*x)**(ii + m)*(x**(n/S(2))*Coeff(Pq, x, ii + n/S(2)) + Coeff(Pq, x, ii))/(a + b*x**n), List(ii, S(0), n/S(2) + S(-1))) if SumQ(v): return True return False def replacement1590(Pq, a, b, c, m, n, x): v = Sum_doit(c**(-ii)*(c*x)**(ii + m)*(x**(n/S(2))*Coeff(Pq, x, ii + n/S(2)) + Coeff(Pq, x, ii))/(a + b*x**n), List(ii, S(0), n/S(2) + S(-1))) return Int(v, x) def With1591(Pq, a, b, n, x): if isinstance(x, (int, Integer, float, Float)): return False v = Sum_doit(x**ii*(x**(n/S(2))*Coeff(Pq, x, ii + n/S(2)) + Coeff(Pq, x, ii))/(a + b*x**n), List(ii, S(0), n/S(2) + S(-1))) if SumQ(v): return True return False def replacement1591(Pq, a, b, n, x): v = Sum_doit(x**ii*(x**(n/S(2))*Coeff(Pq, x, ii + n/S(2)) + Coeff(Pq, x, ii))/(a + b*x**n), List(ii, S(0), n/S(2) + S(-1))) return Int(v, x) def With1592(a, b, c, d, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Simp(S(2)*d*s**S(3)*sqrt(a + b*x**S(3))/(a*r**S(2)*(r*x + s*(S(1) + sqrt(S(3))))), x) - Simp(S(3)**(S(1)/4)*d*s*sqrt((r**S(2)*x**S(2) - r*s*x + s**S(2))/(r*x + s*(S(1) + sqrt(S(3))))**S(2))*sqrt(S(2) - sqrt(S(3)))*(r*x + s)*EllipticE(asin((r*x + s*(S(1) - sqrt(S(3))))/(r*x + s*(S(1) + sqrt(S(3))))), S(-7) - S(4)*sqrt(S(3)))/(r**S(2)*sqrt(s*(r*x + s)/(r*x + s*(S(1) + sqrt(S(3))))**S(2))*sqrt(a + b*x**S(3))), x) def With1593(a, b, c, d, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Dist(d/r, Int((r*x + s*(S(1) - sqrt(S(3))))/sqrt(a + b*x**S(3)), x), x) + Dist((c*r - d*s*(S(1) - sqrt(S(3))))/r, Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1594(a, b, c, d, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Simp(S(2)*d*s**S(3)*sqrt(a + b*x**S(3))/(a*r**S(2)*(r*x + s*(S(1) - sqrt(S(3))))), x) + Simp(S(3)**(S(1)/4)*d*s*sqrt((r**S(2)*x**S(2) - r*s*x + s**S(2))/(r*x + s*(S(1) - sqrt(S(3))))**S(2))*sqrt(sqrt(S(3)) + S(2))*(r*x + s)*EllipticE(asin((r*x + s*(S(1) + sqrt(S(3))))/(r*x + s*(S(1) - sqrt(S(3))))), S(-7) + S(4)*sqrt(S(3)))/(r**S(2)*sqrt(-s*(r*x + s)/(r*x + s*(S(1) - sqrt(S(3))))**S(2))*sqrt(a + b*x**S(3))), x) def With1595(a, b, c, d, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Dist(d/r, Int((r*x + s*(S(1) + sqrt(S(3))))/sqrt(a + b*x**S(3)), x), x) + Dist((c*r - d*s*(S(1) + sqrt(S(3))))/r, Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1596(a, b, c, d, x): r = Numer(Rt(b/a, S(3))) s = Denom(Rt(b/a, S(3))) return Simp(d*s**S(3)*x*(S(1) + sqrt(S(3)))*sqrt(a + b*x**S(6))/(S(2)*a*r**S(2)*(r*x**S(2)*(S(1) + sqrt(S(3))) + s)), x) - Simp(S(3)**(S(1)/4)*d*s*x*sqrt((r**S(2)*x**S(4) - r*s*x**S(2) + s**S(2))/(r*x**S(2)*(S(1) + sqrt(S(3))) + s)**S(2))*(r*x**S(2) + s)*EllipticE(acos((r*x**S(2)*(S(1) - sqrt(S(3))) + s)/(r*x**S(2)*(S(1) + sqrt(S(3))) + s)), sqrt(S(3))/S(4) + S(1)/2)/(S(2)*r**S(2)*sqrt(r*x**S(2)*(r*x**S(2) + s)/(r*x**S(2)*(S(1) + sqrt(S(3))) + s)**S(2))*sqrt(a + b*x**S(6))), x) def With1597(a, b, c, d, x): q = Rt(b/a, S(3)) return Dist(d/(S(2)*q**S(2)), Int((S(2)*q**S(2)*x**S(4) - sqrt(S(3)) + S(1))/sqrt(a + b*x**S(6)), x), x) + Dist((S(2)*c*q**S(2) - d*(S(1) - sqrt(S(3))))/(S(2)*q**S(2)), Int(S(1)/sqrt(a + b*x**S(6)), x), x) def replacement1598(a, b, c, d, x): return -Simp(c*d*x**S(3)*sqrt(-(c - d*x**S(2))**S(2)/(c*d*x**S(2)))*sqrt(-d**S(2)*(a + b*x**S(8))/(b*c**S(2)*x**S(4)))*EllipticF(asin(sqrt((sqrt(S(2))*c**S(2) + S(2)*c*d*x**S(2) + sqrt(S(2))*d**S(2)*x**S(4))/(c*d*x**S(2)))/S(2)), S(-2) + S(2)*sqrt(S(2)))/(sqrt(sqrt(S(2)) + S(2))*sqrt(a + b*x**S(8))*(c - d*x**S(2))), x) def replacement1599(a, b, c, d, x): return -Dist((-c*Rt(b/a, S(4)) + d)/(S(2)*Rt(b/a, S(4))), Int((-x**S(2)*Rt(b/a, S(4)) + S(1))/sqrt(a + b*x**S(8)), x), x) + Dist((c*Rt(b/a, S(4)) + d)/(S(2)*Rt(b/a, S(4))), Int((x**S(2)*Rt(b/a, S(4)) + S(1))/sqrt(a + b*x**S(8)), x), x) def replacement1600(Pq, a, b, n, x): return Dist(Coeff(Pq, x, S(0)), Int(S(1)/(x*sqrt(a + b*x**n)), x), x) + Int(ExpandToSum((Pq - Coeff(Pq, x, S(0)))/x, x)/sqrt(a + b*x**n), x) def With1601(Pq, a, b, c, m, n, p, x): q = Expon(Pq, x) j = Symbol('j') k = Symbol('k') return Int(Sum_doit(c**(-j)*(c*x)**(j + m)*(a + b*x**n)**p*Sum_doit(x**(k*n/S(2))*Coeff(Pq, x, j + k*n/S(2)), List(k, S(0), S(1) + S(2)*(-j + q)/n)), List(j, S(0), n/S(2) + S(-1))), x) def With1602(Pq, a, b, n, p, x): q = Expon(Pq, x) j = Symbol('j') k = Symbol('k') return Int(Sum_doit(x**j*(a + b*x**n)**p*Sum_doit(x**(k*n/S(2))*Coeff(Pq, x, j + k*n/S(2)), List(k, S(0), S(1) + S(2)*(-j + q)/n)), List(j, S(0), n/S(2) + S(-1))), x) def replacement1603(Pq, a, b, n, p, x): return Dist(Coeff(Pq, x, n + S(-1)), Int(x**(n + S(-1))*(a + b*x**n)**p, x), x) + Int((a + b*x**n)**p*ExpandToSum(Pq - x**(n + S(-1))*Coeff(Pq, x, n + S(-1)), x), x) def replacement1604(Pq, a, b, c, m, n, x): return Int(ExpandIntegrand(Pq*(c*x)**m/(a + b*x**n), x), x) def replacement1605(Pq, a, b, n, x): return Int(ExpandIntegrand(Pq/(a + b*x**n), x), x) def With1606(Pq, a, b, c, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False Pq0 = Coeff(Pq, x, S(0)) if NonzeroQ(Pq0): return True return False def replacement1606(Pq, a, b, c, m, n, p, x): Pq0 = Coeff(Pq, x, S(0)) return Dist(S(1)/(S(2)*a*c*(m + S(1))), Int((c*x)**(m + S(1))*(a + b*x**n)**p*ExpandToSum(-S(2)*Pq0*b*x**(n + S(-1))*(m + n*(p + S(1)) + S(1)) + S(2)*a*(Pq - Pq0)*(m + S(1))/x, x), x), x) + Simp(Pq0*(c*x)**(m + S(1))*(a + b*x**n)**(p + S(1))/(a*c*(m + S(1))), x) def With1607(Pq, a, b, c, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if And(NonzeroQ(m + n*p + q + S(1)), GreaterEqual(-n + q, S(0)), Or(IntegerQ(S(2)*p), IntegerQ(p + (q + S(1))/(S(2)*n)))): return True return False def replacement1607(Pq, a, b, c, m, n, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Dist(1/(b*(m + n*p + q + 1)), Int((c*x)**m*(a + b*x**n)**p*ExpandToSum(-Pqq*a*x**(-n + q)*(m - n + q + 1) + b*(Pq - Pqq*x**q)*(m + n*p + q + 1), x), x), x) + Simp(Pqq*c**(n - q - 1)*(c*x)**(m - n + q + 1)*(a + b*x**n)**(p + 1)/(b*(m + n*p + q + 1)), x) def With1608(Pq, a, b, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if And(NonzeroQ(n*p + q + S(1)), GreaterEqual(-n + q, S(0)), Or(IntegerQ(S(2)*p), IntegerQ(p + (q + S(1))/(S(2)*n)))): return True return False def replacement1608(Pq, a, b, n, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Dist(1/(b*(n*p + q + 1)), Int((a + b*x**n)**p*ExpandToSum(-Pqq*a*x**(-n + q)*(-n + q + 1) + b*(Pq - Pqq*x**q)*(n*p + q + 1), x), x), x) + Simp(Pqq*x**(-n + q + 1)*(a + b*x**n)**(p + 1)/(b*(n*p + q + 1)), x) def With1609(Pq, a, b, m, n, p, x): q = Expon(Pq, x) return -Subst(Int(x**(-m - q + S(-2))*(a + b*x**(-n))**p*ExpandToSum(x**q*ReplaceAll(Pq, Rule(x, S(1)/x)), x), x), x, S(1)/x) def With1610(Pq, a, b, c, m, n, p, x): g = Denominator(m) q = Expon(Pq, x) return -Dist(g/c, Subst(Int(x**(-g*(m + q + S(1)) + S(-1))*(a + b*c**(-n)*x**(-g*n))**p*ExpandToSum(x**(g*q)*ReplaceAll(Pq, Rule(x, x**(-g)/c)), x), x), x, (c*x)**(-S(1)/g)), x) def With1611(Pq, a, b, c, m, n, p, x): q = Expon(Pq, x) return -Dist((c*x)**m*(S(1)/x)**m, Subst(Int(x**(-m - q + S(-2))*(a + b*x**(-n))**p*ExpandToSum(x**q*ReplaceAll(Pq, Rule(x, S(1)/x)), x), x), x, S(1)/x), x) def With1612(Pq, a, b, m, n, p, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g*(m + S(1)) + S(-1))*(a + b*x**(g*n))**p*ReplaceAll(Pq, Rule(x, x**g)), x), x, x**(S(1)/g)), x) def With1613(Pq, a, b, n, p, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g + S(-1))*(a + b*x**(g*n))**p*ReplaceAll(Pq, Rule(x, x**g)), x), x, x**(S(1)/g)), x) def replacement1614(Pq, a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(Pq*x**m*(a + b*x**n)**p, x), x) def replacement1615(Pq, a, b, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*x**(n/(m + S(1))))**p*ReplaceAll(SubstFor(x**n, Pq, x), Rule(x, x**(n/(m + S(1))))), x), x, x**(m + S(1))), x) def replacement1616(Pq, a, b, c, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(Pq*x**m*(a + b*x**n)**p, x), x) def replacement1617(A, B, a, b, m, n, p, x): return Dist(A, Int((a + b*x**n)**p, x), x) + Dist(B, Int(x**m*(a + b*x**n)**p, x), x) def replacement1618(Pq, a, b, c, m, n, p, x): return Int(ExpandIntegrand(Pq*(c*x)**m*(a + b*x**n)**p, x), x) def replacement1619(Pq, a, b, n, p, x): return Int(ExpandIntegrand(Pq*(a + b*x**n)**p, x), x) def replacement1620(Pq, a, b, m, n, p, u, v, x): return Dist(u**m*v**(-m)/Coeff(v, x, S(1)), Subst(Int(x**m*(a + b*x**n)**p*SubstFor(v, Pq, x), x), x, v), x) def replacement1621(Pq, a, b, n, p, v, x): return Dist(S(1)/Coeff(v, x, S(1)), Subst(Int((a + b*x**n)**p*SubstFor(v, Pq, x), x), x, v), x) def replacement1622(Pq, a1, a2, b1, b2, c, m, n, p, x): return Int(Pq*(c*x)**m*(a1*a2 + b1*b2*x**(S(2)*n))**p, x) def replacement1623(Pq, a1, a2, b1, b2, n, p, x): return Int(Pq*(a1*a2 + b1*b2*x**(S(2)*n))**p, x) def replacement1624(Pq, a1, a2, b1, b2, c, m, n, p, x): return Dist((a1 + b1*x**n)**FracPart(p)*(a2 + b2*x**n)**FracPart(p)*(a1*a2 + b1*b2*x**(S(2)*n))**(-FracPart(p)), Int(Pq*(c*x)**m*(a1*a2 + b1*b2*x**(S(2)*n))**p, x), x) def replacement1625(Pq, a1, a2, b1, b2, n, p, x): return Dist((a1 + b1*x**n)**FracPart(p)*(a2 + b2*x**n)**FracPart(p)*(a1*a2 + b1*b2*x**(S(2)*n))**(-FracPart(p)), Int(Pq*(a1*a2 + b1*b2*x**(S(2)*n))**p, x), x) def replacement1626(a, b, c, d, e, f, g, n, n2, p, x): return Simp(e*x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(p + S(1))/(a*c), x) def replacement1627(a, b, c, d, e, g, n, n2, p, x): return Simp(e*x*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(p + S(1))/(a*c), x) def replacement1628(a, b, c, d, e, f, g, h, m, n, n2, p, x): return Simp(e*(h*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(p + S(1))/(a*c*h*(m + S(1))), x) def replacement1629(a, b, c, d, e, g, h, m, n, n2, p, x): return Simp(e*(h*x)**(m + S(1))*(a + b*x**n)**(p + S(1))*(c + d*x**n)**(p + S(1))/(a*c*h*(m + S(1))), x) def replacement1630(A, B, a, b, c, d, m, n, p, q, x): return Dist(A, Int((a + b*x**n)**p*(c + d*x**n)**q, x), x) + Dist(B, Int(x**m*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def With1631(Px, a, b, c, d, n, p, q, x): k = Denominator(n) return Dist(k/d, Subst(Int(SimplifyIntegrand(x**(k + S(-1))*(a + b*x**(k*n))**p*ReplaceAll(Px, Rule(x, -c/d + x**k/d))**q, x), x), x, (c + d*x)**(S(1)/k)), x) def replacement1632(Pq, a, b, c, m, n, n2, p, x): return Dist(S(1)/n, Subst(Int((a + b*x + c*x**S(2))**p*SubstFor(x**n, Pq, x), x), x, x**n), x) def replacement1633(Pq, a, b, c, d, m, n, n2, p, x): return Int(ExpandIntegrand(Pq*(d*x)**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1634(Pq, a, b, c, n, n2, p, x): return Int(ExpandIntegrand(Pq*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1635(a, b, c, d, e, f, n, n2, p, x): return Simp(d*x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/a, x) def replacement1636(a, b, c, d, f, n, n2, p, x): return Simp(d*x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/a, x) def replacement1637(a, b, c, d, e, f, g, m, n, n2, p, x): return Simp(d*(g*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(a*g*(m + S(1))), x) def replacement1638(a, b, c, d, f, g, m, n, n2, p, x): return Simp(d*(g*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(a*g*(m + S(1))), x) def replacement1639(Pq, a, b, c, d, m, n, n2, p, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int(Pq*(d*x)**m*(b + S(2)*c*x**n)**(S(2)*p), x), x) def replacement1640(Pq, a, b, c, n, n2, p, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int(Pq*(b + S(2)*c*x**n)**(S(2)*p), x), x) def replacement1641(Pq, a, b, c, m, n, n2, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*x + c*x**S(2))**p*SubstFor(x**n, Pq, x), x), x, x**n), x) def replacement1642(Pq, a, b, c, d, m, n, n2, p, x): return Dist(x**(-m)*(d*x)**m, Int(Pq*x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1643(Pq, a, b, c, d, m, n, n2, p, x): return Dist(S(1)/d, Int((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**p*ExpandToSum(Pq/x, x), x), x) def replacement1644(Pq, a, b, c, n, n2, p, x): return Int(x*(a + b*x**n + c*x**(S(2)*n))**p*ExpandToSum(Pq/x, x), x) def replacement1645(a, b, c, d, e, f, g, n, n2, n3, p, x): return Simp(x*(S(3)*a*d - x**S(2)*(-a*e + S(2)*b*d*p + S(3)*b*d))*(a + b*x**S(2) + c*x**S(4))**(p + S(1))/(S(3)*a**S(2)), x) def replacement1646(a, b, c, d, f, g, n, n2, n3, p, x): return Simp(x*(S(3)*a*d - x**S(2)*(S(2)*b*d*p + S(3)*b*d))*(a + b*x**S(2) + c*x**S(4))**(p + S(1))/(S(3)*a**S(2)), x) def replacement1647(a, b, c, d, e, g, n, n2, n3, p, x): return Simp(x*(S(3)*a*d - x**S(2)*(-a*e + S(2)*b*d*p + S(3)*b*d))*(a + b*x**S(2) + c*x**S(4))**(p + S(1))/(S(3)*a**S(2)), x) def replacement1648(a, b, c, d, g, n, n2, n3, p, x): return Simp(x*(S(3)*a*d - x**S(2)*(S(2)*b*d*p + S(3)*b*d))*(a + b*x**S(2) + c*x**S(4))**(p + S(1))/(S(3)*a**S(2)), x) def replacement1649(a, b, c, e, f, g, h, m, n, n2, q, r, s, x): return -Simp((S(2)*c*x**n*(-b*g + S(2)*c*f) + S(2)*c*(-S(2)*a*g + b*f) + S(2)*h*x**(n/S(2))*(-S(4)*a*c + b**S(2)))/(c*n*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**n + c*x**(S(2)*n))), x) def replacement1650(a, b, c, d, e, f, g, h, m, n, n2, q, r, s, x): return Dist(x**(-m)*(d*x)**m, Int(x**m*(e + f*x**(n/S(2)) + g*x**(S(3)*n/S(2)) + h*x**(S(2)*n))/(a + b*x**n + c*x**(S(2)*n))**(S(3)/2), x), x) def With1651(Pq, a, b, c, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) i = Symbol('i') if Less(q, S(2)*n): return True return False def replacement1651(Pq, a, b, c, n, n2, p, x): q = Expon(Pq, x) i = Symbol('i') return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Sum_doit(c*x**(i + n)*(-S(2)*a*Coeff(Pq, x, i + n) + b*Coeff(Pq, x, i))*(i + n*(S(2)*p + S(3)) + S(1)) + x**i*(-a*b*(i + S(1))*Coeff(Pq, x, i + n) + (-S(2)*a*c*(i + S(2)*n*(p + S(1)) + S(1)) + b**S(2)*(i + n*(p + S(1)) + S(1)))*Coeff(Pq, x, i)), List(i, S(0), n + S(-1))), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Sum_doit(c*x**(i + n)*(-S(2)*a*Coeff(Pq, x, i + n) + b*Coeff(Pq, x, i)) + x**i*(-a*b*Coeff(Pq, x, i + n) + (-S(2)*a*c + b**S(2))*Coeff(Pq, x, i)), List(i, S(0), n + S(-1)))/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1652(a, b, c, d, e, f, g, x): return -Simp((c*x**S(2)*(-b*f + S(2)*c*e) + c*(-S(2)*a*f + b*e) + g*x*(-S(4)*a*c + b**S(2)))/(c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1653(a, b, c, d, f, g, x): return Simp((S(2)*a*c*f + b*c*f*x**S(2) - g*x*(-S(4)*a*c + b**S(2)))/(c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1654(a, b, c, d, e, g, x): return -Simp((b*c*e + S(2)*c**S(2)*e*x**S(2) + g*x*(-S(4)*a*c + b**S(2)))/(c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1655(a, b, c, e, f, g, h, x): return Simp((S(2)*a**S(2)*c*f + a*b*c*f*x**S(2) + a*h*x**S(3)*(-S(4)*a*c + b**S(2)))/(a*c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1656(a, b, c, e, g, h, x): return Simp(h*x**S(3)/(c*sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1657(a, b, c, d, e, f, g, h, x): return Simp((S(2)*a**S(2)*c*f + a*b*c*f*x**S(2) + a*h*x**S(3)*(-S(4)*a*c + b**S(2)) + c*d*x*(-S(4)*a*c + b**S(2)))/(a*c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1658(a, b, c, d, e, f, h, x): return Simp((S(2)*a**S(2)*c*f + a*b*c*f*x**S(2) + a*h*x**S(3)*(-S(4)*a*c + b**S(2)) + c*d*x*(-S(4)*a*c + b**S(2)))/(a*c*(-S(4)*a*c + b**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1659(Pq, a, b, c, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Q = PolynomialQuotient(Pq*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) R = PolynomialRemainder(Pq*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) if GreaterEqual(q, S(2)*n): return True return False def replacement1659(Pq, a, b, c, n, n2, p, x): q = Expon(Pq, x) Q = PolynomialQuotient(Pq*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) R = PolynomialRemainder(Pq*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) return Dist((b*c)**(-Floor((q - 1)/n) - 1)/(a*n*(p + 1)*(-4*a*c + b**2)), Int((a + b*x**n + c*x**(2*n))**(p + 1)*ExpandToSum(Q*a*n*(p + 1)*(-4*a*c + b**2) + Sum_doit(c*x**(i + n)*(-2*a*Coeff(R, x, i + n) + b*Coeff(R, x, i))*(i + n*(2*p + 3) + 1) + x**i*(-a*b*(i + 1)*Coeff(R, x, i + n) + (-2*a*c*(i + 2*n*(p + 1) + 1) + b**2*(i + n*(p + 1) + 1))*Coeff(R, x, i)), List(i, 0, n - 1)), x), x), x) - Simp(x*(b*c)**(-Floor((q - 1)/n) - 1)*(a + b*x**n + c*x**(2*n))**(p + 1)*Sum_doit(c*x**(i + n)*(-2*a*Coeff(R, x, i + n) + b*Coeff(R, x, i)) + x**i*(-a*b*Coeff(R, x, i + n) + (-2*a*c + b**2)*Coeff(R, x, i)), List(i, 0, n - 1))/(a*n*(p + 1)*(-4*a*c + b**2)), x) def With1660(Pq, a, b, c, m, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Q = PolynomialQuotient(Pq*a*x**m*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) R = PolynomialRemainder(Pq*a*x**m*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) if GreaterEqual(q, S(2)*n): return True return False def replacement1660(Pq, a, b, c, m, n, n2, p, x): q = Expon(Pq, x) Q = PolynomialQuotient(Pq*a*x**m*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) R = PolynomialRemainder(Pq*a*x**m*(b*c)**(Floor((q + S(-1))/n) + S(1)), a + b*x**n + c*x**(S(2)*n), x) return Dist((b*c)**(-Floor((q - 1)/n) - 1)/(a*n*(p + 1)*(-4*a*c + b**2)), Int(x**m*(a + b*x**n + c*x**(2*n))**(p + 1)*ExpandToSum(Q*n*x**(-m)*(p + 1)*(-4*a*c + b**2) + Sum_doit(c*x**(i - m + n)*(-2*Coeff(R, x, i + n) + b*Coeff(R, x, i)/a)*(i + n*(2*p + 3) + 1) + x**(i - m)*(-b*(i + 1)*Coeff(R, x, i + n) + (-2*c*(i + 2*n*(p + 1) + 1) + b**2*(i + n*(p + 1) + 1)/a)*Coeff(R, x, i)), List(i, 0, n - 1)), x), x), x) - Simp(x*(b*c)**(-Floor((q - 1)/n) - 1)*(a + b*x**n + c*x**(2*n))**(p + 1)*Sum_doit(c*x**(i + n)*(-2*a*Coeff(R, x, i + n) + b*Coeff(R, x, i)) + x**i*(-a*b*Coeff(R, x, i + n) + (-2*a*c + b**2)*Coeff(R, x, i)), List(i, 0, n - 1))/(a**2*n*(p + 1)*(-4*a*c + b**2)), x) def With1661(Pq, a, b, c, m, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False g = GCD(m + S(1), n) if Unequal(g, S(1)): return True return False def replacement1661(Pq, a, b, c, m, n, n2, p, x): g = GCD(m + S(1), n) return Dist(S(1)/g, Subst(Int(x**(S(-1) + (m + S(1))/g)*(a + b*x**(n/g) + c*x**(S(2)*n/g))**p*ReplaceAll(Pq, Rule(x, x**(S(1)/g))), x), x, x**g), x) def replacement1662(Pq, a, b, c, d, m, n, n2, x): return Int(ExpandIntegrand(Pq*(d*x)**m/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1663(Pq, a, b, c, n, n2, x): return Int(ExpandIntegrand(Pq/(a + b*x**n + c*x**(S(2)*n)), x), x) def With1664(Pq, a, b, c, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if Equal(S(2)*p + q + S(1), S(0)): return True return False def replacement1664(Pq, a, b, c, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Dist(1/2, Int((a + b*x + c*x**2)**p*ExpandToSum(2*Pq - Pqq*c**p*(b + 2*c*x)*(a + b*x + c*x**2)**(-p - 1), x), x), x) + Simp(Pqq*c**p*log(a + b*x + c*x**2)/2, x) def With1665(Pq, a, b, c, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if Equal(S(2)*p + q + S(1), S(0)): return True return False def replacement1665(Pq, a, b, c, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Int((a + b*x + c*x**2)**p*ExpandToSum(Pq - Pqq*c**(p + 1/2)*(a + b*x + c*x**2)**(-p - 1/2), x), x) + Simp(Pqq*c**p*atanh((b + 2*c*x)/(2*sqrt(a + b*x + c*x**2)*Rt(c, 2))), x) def With1666(Pq, a, b, c, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if Equal(S(2)*p + q + S(1), S(0)): return True return False def replacement1666(Pq, a, b, c, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Int((a + b*x + c*x**2)**p*ExpandToSum(Pq - Pqq*(-c)**(p + 1/2)*(a + b*x + c*x**2)**(-p - 1/2), x), x) - Simp(Pqq*(-c)**p*ArcTan((b + 2*c*x)/(2*sqrt(a + b*x + c*x**2)*Rt(-c, 2))), x) def With1667(Pq, a, b, c, d, m, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if And(GreaterEqual(q, S(2)*n), Unequal(m + S(2)*n*p + q + S(1), S(0)), Or(IntegerQ(S(2)*p), And(Equal(n, S(1)), IntegerQ(S(4)*p)), IntegerQ(p + (q + S(1))/(S(2)*n)))): return True return False def replacement1667(Pq, a, b, c, d, m, n, n2, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Int((d*x)**m*(a + b*x**n + c*x**(2*n))**p*ExpandToSum(Pq - Pqq*x**q - Pqq*(a*x**(-2*n + q)*(m - 2*n + q + 1) + b*x**(-n + q)*(m + n*(p - 1) + q + 1))/(c*(m + 2*n*p + q + 1)), x), x) + Simp(Pqq*d**(2*n - q - 1)*(d*x)**(m - 2*n + q + 1)*(a + b*x**n + c*x**(2*n))**(p + 1)/(c*(m + 2*n*p + q + 1)), x) def With1668(Pq, a, b, c, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if And(GreaterEqual(q, S(2)*n), Unequal(S(2)*n*p + q + S(1), S(0)), Or(IntegerQ(S(2)*p), And(Equal(n, S(1)), IntegerQ(S(4)*p)), IntegerQ(p + (q + S(1))/(S(2)*n)))): return True return False def replacement1668(Pq, a, b, c, n, n2, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Int((a + b*x**n + c*x**(2*n))**p*ExpandToSum(Pq - Pqq*x**q - Pqq*(a*x**(-2*n + q)*(-2*n + q + 1) + b*x**(-n + q)*(n*(p - 1) + q + 1))/(c*(2*n*p + q + 1)), x), x) + Simp(Pqq*x**(-2*n + q + 1)*(a + b*x**n + c*x**(2*n))**(p + 1)/(c*(2*n*p + q + 1)), x) def With1669(Pq, a, b, c, d, m, n, n2, p, x): q = Expon(Pq, x) j = Symbol('j') k = Symbol('k') return Int(Sum_doit(d**(-j)*(d*x)**(j + m)*(a + b*x**n + c*x**(S(2)*n))**p*Sum_doit(x**(k*n)*Coeff(Pq, x, j + k*n), List(k, S(0), S(1) + (-j + q)/n)), List(j, S(0), n + S(-1))), x) def With1670(Pq, a, b, c, n, n2, p, x): q = Expon(Pq, x) j = Symbol('j') k = Symbol('k') return Int(Sum_doit(x**j*(a + b*x**n + c*x**(S(2)*n))**p*Sum_doit(x**(k*n)*Coeff(Pq, x, j + k*n), List(k, S(0), S(1) + (-j + q)/n)), List(j, S(0), n + S(-1))), x) def replacement1671(Pq, a, b, c, d, m, n, n2, x): return Int(RationalFunctionExpand(Pq*(d*x)**m/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1672(Pq, a, b, c, n, n2, x): return Int(RationalFunctionExpand(Pq/(a + b*x**n + c*x**(S(2)*n)), x), x) def With1673(Pq, a, b, c, m, n, n2, p, x): q = Expon(Pq, x) return -Subst(Int(x**(-m - q + S(-2))*(a + b*x**(-n) + c*x**(-S(2)*n))**p*ExpandToSum(x**q*ReplaceAll(Pq, Rule(x, S(1)/x)), x), x), x, S(1)/x) def With1674(Pq, a, b, c, d, m, n, n2, p, x): g = Denominator(m) q = Expon(Pq, x) return -Dist(g/d, Subst(Int(x**(-g*(m + q + S(1)) + S(-1))*(a + b*d**(-n)*x**(-g*n) + c*d**(-S(2)*n)*x**(-S(2)*g*n))**p*ExpandToSum(x**(g*q)*ReplaceAll(Pq, Rule(x, x**(-g)/d)), x), x), x, (d*x)**(-S(1)/g)), x) def With1675(Pq, a, b, c, d, m, n, n2, p, x): q = Expon(Pq, x) return -Dist((d*x)**m*(S(1)/x)**m, Subst(Int(x**(-m - q + S(-2))*(a + b*x**(-n) + c*x**(-S(2)*n))**p*ExpandToSum(x**q*ReplaceAll(Pq, Rule(x, S(1)/x)), x), x), x, S(1)/x), x) def With1676(Pq, a, b, c, m, n, n2, p, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g*(m + S(1)) + S(-1))*(a + b*x**(g*n) + c*x**(S(2)*g*n))**p*ReplaceAll(Pq, Rule(x, x**g)), x), x, x**(S(1)/g)), x) def With1677(Pq, a, b, c, n, n2, p, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g + S(-1))*(a + b*x**(g*n) + c*x**(S(2)*g*n))**p*ReplaceAll(Pq, Rule(x, x**g)), x), x, x**(S(1)/g)), x) def replacement1678(Pq, a, b, c, d, m, n, n2, p, x): return Dist(d**(m + S(-1)/2)*sqrt(d*x)/sqrt(x), Int(Pq*x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1679(Pq, a, b, c, d, m, n, n2, p, x): return Dist(d**(m + S(1)/2)*sqrt(x)/sqrt(d*x), Int(Pq*x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1680(Pq, a, b, c, d, m, n, n2, p, x): return Dist(x**(-m)*(d*x)**m, Int(Pq*x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1681(Pq, a, b, c, m, n, n2, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*x**(n/(m + S(1))) + c*x**(S(2)*n/(m + S(1))))**p*ReplaceAll(SubstFor(x**n, Pq, x), Rule(x, x**(n/(m + S(1))))), x), x, x**(m + S(1))), x) def replacement1682(Pq, a, b, c, d, m, n, n2, p, x): return Dist(x**(-m)*(d*x)**m, Int(Pq*x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def With1683(Pq, a, b, c, d, m, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(Pq*(d*x)**m/(b + S(2)*c*x**n - q), x), x) - Dist(S(2)*c/q, Int(Pq*(d*x)**m/(b + S(2)*c*x**n + q), x), x) def With1684(Pq, a, b, c, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(Pq/(b + S(2)*c*x**n - q), x), x) - Dist(S(2)*c/q, Int(Pq/(b + S(2)*c*x**n + q), x), x) def replacement1685(Pq, a, b, c, d, m, n, n2, p, x): return Int(ExpandIntegrand(Pq*(d*x)**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1686(Pq, a, b, c, n, n2, p, x): return Int(ExpandIntegrand(Pq*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1687(Pq, a, b, c, d, m, n, n2, p, x): return Int(Pq*(d*x)**m*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1688(Pq, a, b, c, n, n2, p, x): return Int(Pq*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1689(Pq, a, b, c, m, n, n2, p, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(a + b*x**n + c*x**(S(2)*n))**p*SubstFor(v, Pq, x), x), x, v), x) def replacement1690(Pq, a, b, c, n, n2, p, v, x): return Dist(S(1)/Coefficient(v, x, S(1)), Subst(Int((a + b*x**n + c*x**(S(2)*n))**p*SubstFor(v, Pq, x), x), x, v), x) def replacement1691(a, b, j, n, p, x): return Simp(x**(S(1) - n)*(a*x**j + b*x**n)**(p + S(1))/(b*(-j + n)*(p + S(1))), x) def replacement1692(a, b, j, n, p, x): return Dist((-j + n*p + n + S(1))/(a*(-j + n)*(p + S(1))), Int(x**(-j)*(a*x**j + b*x**n)**(p + S(1)), x), x) - Simp(x**(S(1) - j)*(a*x**j + b*x**n)**(p + S(1))/(a*(-j + n)*(p + S(1))), x) def replacement1693(a, b, j, n, p, x): return -Dist(b*(-j + n*p + n + S(1))/(a*(j*p + S(1))), Int(x**(-j + n)*(a*x**j + b*x**n)**p, x), x) + Simp(x**(S(1) - j)*(a*x**j + b*x**n)**(p + S(1))/(a*(j*p + S(1))), x) def replacement1694(a, b, j, n, p, x): return -Dist(b*p*(-j + n)/(j*p + S(1)), Int(x**n*(a*x**j + b*x**n)**(p + S(-1)), x), x) + Simp(x*(a*x**j + b*x**n)**p/(j*p + S(1)), x) def replacement1695(a, b, j, n, p, x): return Dist(a*p*(-j + n)/(n*p + S(1)), Int(x**j*(a*x**j + b*x**n)**(p + S(-1)), x), x) + Simp(x*(a*x**j + b*x**n)**p/(n*p + S(1)), x) def replacement1696(a, b, j, n, p, x): return -Dist((j*p + j - n + S(1))/(b*(-j + n)*(p + S(1))), Int(x**(-n)*(a*x**j + b*x**n)**(p + S(1)), x), x) + Simp(x**(S(1) - n)*(a*x**j + b*x**n)**(p + S(1))/(b*(-j + n)*(p + S(1))), x) def replacement1697(a, b, j, n, p, x): return Dist((-j + n*p + n + S(1))/(a*(-j + n)*(p + S(1))), Int(x**(-j)*(a*x**j + b*x**n)**(p + S(1)), x), x) - Simp(x**(S(1) - j)*(a*x**j + b*x**n)**(p + S(1))/(a*(-j + n)*(p + S(1))), x) def replacement1698(a, b, j, n, p, x): return Dist(a, Int(x**j*(a*x**j + b*x**n)**(p + S(-1)), x), x) + Simp(x*(a*x**j + b*x**n)**p/(p*(-j + n)), x) def replacement1699(a, b, n, x): return Dist(S(2)/(S(2) - n), Subst(Int(S(1)/(-a*x**S(2) + S(1)), x), x, x/sqrt(a*x**S(2) + b*x**n)), x) def replacement1700(a, b, j, n, p, x): return Dist((-j + n*p + n + S(1))/(a*(-j + n)*(p + S(1))), Int(x**(-j)*(a*x**j + b*x**n)**(p + S(1)), x), x) - Simp(x**(S(1) - j)*(a*x**j + b*x**n)**(p + S(1))/(a*(-j + n)*(p + S(1))), x) def replacement1701(a, b, j, n, x): return -Dist(a*(-j + S(2)*n + S(-2))/(b*(n + S(-2))), Int(x**(j - n)/sqrt(a*x**j + b*x**n), x), x) + Simp(-S(2)*x**(S(1) - n)*sqrt(a*x**j + b*x**n)/(b*(n + S(-2))), x) def replacement1702(a, b, j, n, p, x): return Dist(x**(-j*FracPart(p))*(a + b*x**(-j + n))**(-FracPart(p))*(a*x**j + b*x**n)**FracPart(p), Int(x**(j*p)*(a + b*x**(-j + n))**p, x), x) def replacement1703(a, b, j, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a*x**j + b*x**n)**p, x), x, u), x) def replacement1704(a, b, j, m, n, p, x): return Dist(S(1)/n, Subst(Int((a*x**(j/n) + b*x)**p, x), x, x**n), x) def replacement1705(a, b, c, j, m, n, p, x): return -Simp(c**(j + S(-1))*(c*x)**(-j + m + S(1))*(a*x**j + b*x**n)**(p + S(1))/(a*(-j + n)*(p + S(1))), x) def replacement1706(a, b, c, j, m, n, p, x): return Dist(c**j*(-j + m + n*p + n + S(1))/(a*(-j + n)*(p + S(1))), Int((c*x)**(-j + m)*(a*x**j + b*x**n)**(p + S(1)), x), x) - Simp(c**(j + S(-1))*(c*x)**(-j + m + S(1))*(a*x**j + b*x**n)**(p + S(1))/(a*(-j + n)*(p + S(1))), x) def replacement1707(a, b, c, j, m, n, p, x): return -Dist(b*c**(j - n)*(-j + m + n*p + n + S(1))/(a*(j*p + m + S(1))), Int((c*x)**(-j + m + n)*(a*x**j + b*x**n)**p, x), x) + Simp(c**(j + S(-1))*(c*x)**(-j + m + S(1))*(a*x**j + b*x**n)**(p + S(1))/(a*(j*p + m + S(1))), x) def replacement1708(a, b, c, j, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a*x**j + b*x**n)**p, x), x) def replacement1709(a, b, j, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a*x**(j/n) + b*x)**p, x), x, x**n), x) def replacement1710(a, b, c, j, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a*x**j + b*x**n)**p, x), x) def replacement1711(a, b, c, j, m, n, p, x): return -Dist(b*c**(-n)*p*(-j + n)/(j*p + m + S(1)), Int((c*x)**(m + n)*(a*x**j + b*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a*x**j + b*x**n)**p/(c*(j*p + m + S(1))), x) def replacement1712(a, b, c, j, m, n, p, x): return Dist(a*c**(-j)*p*(-j + n)/(m + n*p + S(1)), Int((c*x)**(j + m)*(a*x**j + b*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a*x**j + b*x**n)**p/(c*(m + n*p + S(1))), x) def replacement1713(a, b, c, j, m, n, p, x): return -Dist(c**n*(j*p + j + m - n + S(1))/(b*(-j + n)*(p + S(1))), Int((c*x)**(m - n)*(a*x**j + b*x**n)**(p + S(1)), x), x) + Simp(c**(n + S(-1))*(c*x)**(m - n + S(1))*(a*x**j + b*x**n)**(p + S(1))/(b*(-j + n)*(p + S(1))), x) def replacement1714(a, b, c, j, m, n, p, x): return Dist(c**j*(-j + m + n*p + n + S(1))/(a*(-j + n)*(p + S(1))), Int((c*x)**(-j + m)*(a*x**j + b*x**n)**(p + S(1)), x), x) - Simp(c**(j + S(-1))*(c*x)**(-j + m + S(1))*(a*x**j + b*x**n)**(p + S(1))/(a*(-j + n)*(p + S(1))), x) def replacement1715(a, b, c, j, m, n, p, x): return -Dist(a*c**(-j + n)*(j*p + j + m - n + S(1))/(b*(m + n*p + S(1))), Int((c*x)**(j + m - n)*(a*x**j + b*x**n)**p, x), x) + Simp(c**(n + S(-1))*(c*x)**(m - n + S(1))*(a*x**j + b*x**n)**(p + S(1))/(b*(m + n*p + S(1))), x) def replacement1716(a, b, c, j, m, n, p, x): return -Dist(b*c**(j - n)*(-j + m + n*p + n + S(1))/(a*(j*p + m + S(1))), Int((c*x)**(-j + m + n)*(a*x**j + b*x**n)**p, x), x) + Simp(c**(j + S(-1))*(c*x)**(-j + m + S(1))*(a*x**j + b*x**n)**(p + S(1))/(a*(j*p + m + S(1))), x) def replacement1717(a, b, j, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a*x**(j/(m + S(1))) + b*x**(n/(m + S(1))))**p, x), x, x**(m + S(1))), x) def replacement1718(a, b, c, j, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a*x**j + b*x**n)**p, x), x) def replacement1719(a, b, c, j, m, n, p, x): return Dist(a*c**(-j), Int((c*x)**(j + m)*(a*x**j + b*x**n)**(p + S(-1)), x), x) + Simp((c*x)**(m + S(1))*(a*x**j + b*x**n)**p/(c*p*(-j + n)), x) def replacement1720(a, b, j, m, n, x): return Dist(-S(2)/(-j + n), Subst(Int(S(1)/(-a*x**S(2) + S(1)), x), x, x**(j/S(2))/sqrt(a*x**j + b*x**n)), x) def replacement1721(a, b, c, j, m, n, p, x): return Dist(c**j*(-j + m + n*p + n + S(1))/(a*(-j + n)*(p + S(1))), Int((c*x)**(-j + m)*(a*x**j + b*x**n)**(p + S(1)), x), x) - Simp(c**(j + S(-1))*(c*x)**(-j + m + S(1))*(a*x**j + b*x**n)**(p + S(1))/(a*(-j + n)*(p + S(1))), x) def replacement1722(a, b, c, j, m, n, p, x): return Dist(c**IntPart(m)*x**(-FracPart(m))*(c*x)**FracPart(m), Int(x**m*(a*x**j + b*x**n)**p, x), x) def replacement1723(a, b, c, j, m, n, p, x): return Dist(c**IntPart(m)*x**(-j*FracPart(p) - FracPart(m))*(c*x)**FracPart(m)*(a + b*x**(-j + n))**(-FracPart(p))*(a*x**j + b*x**n)**FracPart(p), Int(x**(j*p + m)*(a + b*x**(-j + n))**p, x), x) def replacement1724(a, b, j, m, n, p, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(a*x**j + b*x**n)**p, x), x, v), x) def replacement1725(a, b, c, d, j, k, m, n, p, q, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(c + d*x)**q*(a*x**(j/n) + b*x**(k/n))**p, x), x, x**n), x) def replacement1726(a, b, c, d, e, j, k, m, n, p, q, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(c + d*x**n)**q*(a*x**j + b*x**k)**p, x), x) def replacement1727(jn, a, b, c, d, e, j, m, n, p, x): return Simp(c*e**(j + S(-1))*(e*x)**(-j + m + S(1))*(a*x**j + b*x**(j + n))**(p + S(1))/(a*(j*p + m + S(1))), x) def replacement1728(jn, a, b, c, d, e, j, m, n, p, x): return -Dist(e**j*(a*d*(j*p + m + S(1)) - b*c*(m + n + p*(j + n) + S(1)))/(a*b*n*(p + S(1))), Int((e*x)**(-j + m)*(a*x**j + b*x**(j + n))**(p + S(1)), x), x) - Simp(e**(j + S(-1))*(e*x)**(-j + m + S(1))*(-a*d + b*c)*(a*x**j + b*x**(j + n))**(p + S(1))/(a*b*n*(p + S(1))), x) def replacement1729(jn, a, b, c, d, e, j, m, n, p, x): return Dist(e**(-n)*(a*d*(j*p + m + S(1)) - b*c*(m + n + p*(j + n) + S(1)))/(a*(j*p + m + S(1))), Int((e*x)**(m + n)*(a*x**j + b*x**(j + n))**p, x), x) + Simp(c*e**(j + S(-1))*(e*x)**(-j + m + S(1))*(a*x**j + b*x**(j + n))**(p + S(1))/(a*(j*p + m + S(1))), x) def replacement1730(jn, a, b, c, d, e, j, m, n, p, x): return -Dist((a*d*(j*p + m + S(1)) - b*c*(m + n + p*(j + n) + S(1)))/(b*(m + n + p*(j + n) + S(1))), Int((e*x)**m*(a*x**j + b*x**(j + n))**p, x), x) + Simp(d*e**(j + S(-1))*(e*x)**(-j + m + S(1))*(a*x**j + b*x**(j + n))**(p + S(1))/(b*(m + n + p*(j + n) + S(1))), x) def replacement1731(a, b, c, d, j, k, m, n, p, q, x): return Dist(S(1)/(m + S(1)), Subst(Int((c + d*x**(n/(m + S(1))))**q*(a*x**(j/(m + S(1))) + b*x**(k/(m + S(1))))**p, x), x, x**(m + S(1))), x) def replacement1732(a, b, c, d, e, j, k, m, n, p, q, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(c + d*x**n)**q*(a*x**j + b*x**k)**p, x), x) def replacement1733(jn, a, b, c, d, e, j, m, n, p, q, x): return Dist(e**IntPart(m)*x**(-j*FracPart(p) - FracPart(m))*(e*x)**FracPart(m)*(a + b*x**n)**(-FracPart(p))*(a*x**j + b*x**(j + n))**FracPart(p), Int(x**(j*p + m)*(a + b*x**n)**p*(c + d*x**n)**q, x), x) def With1734(Pq, a, b, j, n, p, x): d = Denominator(n) return Dist(d, Subst(Int(x**(d + S(-1))*(a*x**(d*j) + b*x**(d*n))**p*ReplaceAll(SubstFor(x**n, Pq, x), Rule(x, x**(d*n))), x), x, x**(S(1)/d)), x) def replacement1735(Pq, a, b, j, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a*x**(j/n) + b*x)**p*SubstFor(x**n, Pq, x), x), x, x**n), x) def replacement1736(Pq, a, b, c, j, m, n, p, x): return Dist(c**(Quotient(m, sign(m))*sign(m))*x**(-Mod(m, sign(m)))*(c*x)**Mod(m, sign(m)), Int(Pq*x**m*(a*x**j + b*x**n)**p, x), x) def replacement1737(Pq, a, b, c, j, m, n, p, x): return Dist(x**(-m)*(c*x)**m, Int(Pq*x**m*(a*x**j + b*x**n)**p, x), x) def With1738(Pq, a, b, j, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False g = GCD(m + S(1), n) if Unequal(g, S(1)): return True return False def replacement1738(Pq, a, b, j, m, n, p, x): g = GCD(m + S(1), n) return Dist(S(1)/g, Subst(Int(x**(S(-1) + (m + S(1))/g)*(a*x**(j/g) + b*x**(n/g))**p*ReplaceAll(Pq, Rule(x, x**(S(1)/g))), x), x, x**g), x) def With1739(Pq, a, b, c, j, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) if And(Greater(q, n + S(-1)), Unequal(m + n*p + q + S(1), S(0)), Or(IntegerQ(S(2)*p), IntegerQ(p + (q + S(1))/(S(2)*n)))): return True return False def replacement1739(Pq, a, b, c, j, m, n, p, x): q = Expon(Pq, x) Pqq = Coeff(Pq, x, q) return Int((c*x)**m*(a*x**j + b*x**n)**p*ExpandToSum(Pq - Pqq*a*x**(-n + q)*(m - n + q + 1)/(b*(m + n*p + q + 1)) - Pqq*x**q, x), x) + Simp(Pqq*c**(n - q - 1)*(c*x)**(m - n + q + 1)*(a*x**j + b*x**n)**(p + 1)/(b*(m + n*p + q + 1)), x) def replacement1740(Pq, a, b, j, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a*x**(j/(m + S(1))) + b*x**(n/(m + S(1))))**p*ReplaceAll(SubstFor(x**n, Pq, x), Rule(x, x**(n/(m + S(1))))), x), x, x**(m + S(1))), x) def replacement1741(Pq, a, b, c, j, m, n, p, x): return Dist(c**(Quotient(m, sign(m))*sign(m))*x**(-Mod(m, sign(m)))*(c*x)**Mod(m, sign(m)), Int(Pq*x**m*(a*x**j + b*x**n)**p, x), x) def replacement1742(Pq, a, b, c, j, m, n, p, x): return Dist(x**(-m)*(c*x)**m, Int(Pq*x**m*(a*x**j + b*x**n)**p, x), x) def replacement1743(Pq, a, b, c, j, m, n, p, x): return Int(ExpandIntegrand(Pq*(c*x)**m*(a*x**j + b*x**n)**p, x), x) def replacement1744(Pq, a, b, j, n, p, x): return Int(ExpandIntegrand(Pq*(a*x**j + b*x**n)**p, x), x) def replacement1745(a, b, d, p, x): return Dist(S(3)**(-S(3)*p)*a**(-S(2)*p), Int((S(3)*a - b*x)**p*(S(3)*a + S(2)*b*x)**(S(2)*p), x), x) def replacement1746(a, b, d, p, x): return Int(ExpandToSum((a + b*x + d*x**S(3))**p, x), x) def With1747(a, b, d, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = Factor(a + b*x + d*x**S(3)) if ProductQ(NonfreeFactors(u, x)): return True return False def replacement1747(a, b, d, p, x): u = Factor(a + b*x + d*x**S(3)) return Dist(FreeFactors(u, x)**p, Int(DistributeDegree(NonfreeFactors(u, x), p), x), x) def With1748(a, b, d, p, x): r = Rt(-S(27)*a*d**S(2) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*b**S(3)*d), S(3)) return Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Int((-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) - sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p*(S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d - S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p, x), x) def replacement1749(a, b, d, p, x): return Dist((S(3)*a - b*x)**(-p)*(S(3)*a + S(2)*b*x)**(-S(2)*p)*(a + b*x + d*x**S(3))**p, Int((S(3)*a - b*x)**p*(S(3)*a + S(2)*b*x)**(S(2)*p), x), x) def With1750(a, b, d, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = NonfreeFactors(Factor(a + b*x + d*x**S(3)), x) if ProductQ(u): return True return False def replacement1750(a, b, d, p, x): u = NonfreeFactors(Factor(a + b*x + d*x**S(3)), x) return Dist((a + b*x + d*x**S(3))**p/DistributeDegree(u, p), Int(DistributeDegree(u, p), x), x) def With1751(a, b, d, p, x): r = Rt(-S(27)*a*d**S(2) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*b**S(3)*d), S(3)) return Dist((-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) - sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**(-p)*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**(-p)*(S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d - S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**(-p)*(a + b*x + d*x**S(3))**p, Int((-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) - sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p*(S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d - S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p, x), x) def replacement1752(a, b, d, e, f, m, p, x): return Dist(S(3)**(-S(3)*p)*a**(-S(2)*p), Int((S(3)*a - b*x)**p*(S(3)*a + S(2)*b*x)**(S(2)*p)*(e + f*x)**m, x), x) def replacement1753(a, b, d, e, f, m, p, x): return Int(ExpandIntegrand((e + f*x)**m*(a + b*x + d*x**S(3))**p, x), x) def With1754(a, b, d, e, f, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = Factor(a + b*x + d*x**S(3)) if ProductQ(NonfreeFactors(u, x)): return True return False def replacement1754(a, b, d, e, f, m, p, x): u = Factor(a + b*x + d*x**S(3)) return Dist(FreeFactors(u, x)**p, Int((e + f*x)**m*DistributeDegree(NonfreeFactors(u, x), p), x), x) def With1755(a, b, d, e, f, m, p, x): r = Rt(-S(27)*a*d**S(2) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*b**S(3)*d), S(3)) return Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Int((e + f*x)**m*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) - sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p*(S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d - S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p, x), x) def replacement1756(a, b, d, e, f, m, p, x): return Dist((S(3)*a - b*x)**(-p)*(S(3)*a + S(2)*b*x)**(-S(2)*p)*(a + b*x + d*x**S(3))**p, Int((S(3)*a - b*x)**p*(S(3)*a + S(2)*b*x)**(S(2)*p)*(e + f*x)**m, x), x) def With1757(a, b, d, e, f, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = NonfreeFactors(Factor(a + b*x + d*x**S(3)), x) if ProductQ(u): return True return False def replacement1757(a, b, d, e, f, m, p, x): u = NonfreeFactors(Factor(a + b*x + d*x**S(3)), x) return Dist((a + b*x + d*x**S(3))**p/DistributeDegree(u, p), Int((e + f*x)**m*DistributeDegree(u, p), x), x) def With1758(a, b, d, e, f, m, p, x): r = Rt(-S(27)*a*d**S(2) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*b**S(3)*d), S(3)) return Dist((-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) - sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**(-p)*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**(-p)*(S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d - S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**(-p)*(a + b*x + d*x**S(3))**p, Int((e + f*x)**m*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) - sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(-S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p*(S(3)*d*x + S(2)**(S(1)/3)*(S(6)*b*d - S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p, x), x) def replacement1759(a, c, d, p, x): return -Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Int((c - S(3)*d*x)**p*(S(2)*c + S(3)*d*x)**(S(2)*p), x), x) def replacement1760(a, c, d, p, x): return Int(ExpandToSum((a + c*x**S(2) + d*x**S(3))**p, x), x) def With1761(a, c, d, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = Factor(a + c*x**S(2) + d*x**S(3)) if ProductQ(NonfreeFactors(u, x)): return True return False def replacement1761(a, c, d, p, x): u = Factor(a + c*x**S(2) + d*x**S(3)) return Dist(FreeFactors(u, x)**p, Int(DistributeDegree(NonfreeFactors(u, x), p), x), x) def With1762(a, c, d, p, x): r = Rt(-S(27)*a*d**S(2) - S(2)*c**S(3) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*a*c**S(3)), S(3)) return Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Int((c + S(3)*d*x - S(2)**(S(1)/3)*(S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p, x), x) def replacement1763(a, c, d, p, x): return Dist((c - S(3)*d*x)**(-p)*(S(2)*c + S(3)*d*x)**(-S(2)*p)*(a + c*x**S(2) + d*x**S(3))**p, Int((c - S(3)*d*x)**p*(S(2)*c + S(3)*d*x)**(S(2)*p), x), x) def With1764(a, c, d, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = NonfreeFactors(Factor(a + c*x**S(2) + d*x**S(3)), x) if ProductQ(u): return True return False def replacement1764(a, c, d, p, x): u = NonfreeFactors(Factor(a + c*x**S(2) + d*x**S(3)), x) return Dist((a + c*x**S(2) + d*x**S(3))**p/DistributeDegree(u, p), Int(DistributeDegree(u, p), x), x) def With1765(a, c, d, p, x): r = Rt(-S(27)*a*d**S(2) - S(2)*c**S(3) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*a*c**S(3)), S(3)) return Dist((a + c*x**S(2) + d*x**S(3))**p*(c + S(3)*d*x - S(2)**(S(1)/3)*(S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**(-p), Int((c + S(3)*d*x - S(2)**(S(1)/3)*(S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p, x), x) def replacement1766(a, c, d, e, f, m, p, x): return -Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Int((c - S(3)*d*x)**p*(S(2)*c + S(3)*d*x)**(S(2)*p)*(e + f*x)**m, x), x) def replacement1767(a, c, d, e, f, m, p, x): return Int(ExpandIntegrand((e + f*x)**m*(a + c*x**S(2) + d*x**S(3))**p, x), x) def With1768(a, c, d, e, f, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = Factor(a + c*x**S(2) + d*x**S(3)) if ProductQ(NonfreeFactors(u, x)): return True return False def replacement1768(a, c, d, e, f, m, p, x): u = Factor(a + c*x**S(2) + d*x**S(3)) return Dist(FreeFactors(u, x)**p, Int((e + f*x)**m*DistributeDegree(NonfreeFactors(u, x), p), x), x) def With1769(a, c, d, e, f, m, p, x): r = Rt(-S(27)*a*d**S(2) - S(2)*c**S(3) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*a*c**S(3)), S(3)) return Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Int((e + f*x)**m*(c + S(3)*d*x - S(2)**(S(1)/3)*(S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p, x), x) def replacement1770(a, c, d, e, f, m, p, x): return Dist((c - S(3)*d*x)**(-p)*(S(2)*c + S(3)*d*x)**(-S(2)*p)*(a + c*x**S(2) + d*x**S(3))**p, Int((c - S(3)*d*x)**p*(S(2)*c + S(3)*d*x)**(S(2)*p)*(e + f*x)**m, x), x) def With1771(a, c, d, e, f, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = NonfreeFactors(Factor(a + c*x**S(2) + d*x**S(3)), x) if ProductQ(u): return True return False def replacement1771(a, c, d, e, f, m, p, x): u = NonfreeFactors(Factor(a + c*x**S(2) + d*x**S(3)), x) return Dist((a + c*x**S(2) + d*x**S(3))**p/DistributeDegree(u, p), Int((e + f*x)**m*DistributeDegree(u, p), x), x) def With1772(a, c, d, e, f, m, p, x): r = Rt(-S(27)*a*d**S(2) - S(2)*c**S(3) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) + S(4)*a*c**S(3)), S(3)) return Dist((a + c*x**S(2) + d*x**S(3))**p*(c + S(3)*d*x - S(2)**(S(1)/3)*(S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**(-p), Int((e + f*x)**m*(c + S(3)*d*x - S(2)**(S(1)/3)*(S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) + sqrt(S(3))*I))/(S(4)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) + S(2)**(S(1)/3)*r**S(2)*(S(1) - sqrt(S(3))*I))/(S(4)*r))**p, x), x) def replacement1773(a, b, c, d, p, x): return Dist(S(3)**(-p)*b**(-p)*c**(-p), Int((b + c*x)**(S(3)*p), x), x) def replacement1774(a, b, c, d, p, x): return Dist(S(3)**(-p)*b**(-p)*c**(-p), Subst(Int((S(3)*a*b*c - b**S(3) + c**S(3)*x**S(3))**p, x), x, c/(S(3)*d) + x), x) def With1775(a, b, c, d, p, x): r = Rt(-S(3)*b*c*d + c**S(3), S(3)) return Dist(S(3)**(-p)*b**(-p)*c**(-p), Int((b + x*(c - r))**p*(b + x*(c + r*(S(1) - sqrt(S(3))*I)/S(2)))**p*(b + x*(c + r*(S(1) + sqrt(S(3))*I)/S(2)))**p, x), x) def replacement1776(a, b, c, d, p, x): return Int(ExpandToSum((a + b*x + c*x**S(2) + d*x**S(3))**p, x), x) def With1777(a, b, c, d, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = Factor(a + b*x + c*x**S(2) + d*x**S(3)) if ProductQ(NonfreeFactors(u, x)): return True return False def replacement1777(a, b, c, d, p, x): u = Factor(a + b*x + c*x**S(2) + d*x**S(3)) return Dist(FreeFactors(u, x)**p, Int(DistributeDegree(NonfreeFactors(u, x), p), x), x) def replacement1778(a, b, c, d, p, x): return Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Subst(Int((S(27)*a*d**S(2) - S(9)*b*c*d + S(2)*c**S(3) + S(27)*d**S(3)*x**S(3) - S(9)*d*x*(-S(3)*b*d + c**S(2)))**p, x), x, c/(S(3)*d) + x), x) def replacement1779(a, b, c, d, p, x): return Dist((b + c*x)**(-S(3)*p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((b + c*x)**(S(3)*p), x), x) def With1780(a, b, c, d, p, x): r = Rt(-S(3)*a*b*c + b**S(3), S(3)) return Dist((b + c*x - r)**(-p)*(b + c*x + r*(S(1) - sqrt(S(3))*I)/S(2))**(-p)*(b + c*x + r*(S(1) + sqrt(S(3))*I)/S(2))**(-p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((b + c*x - r)**p*(b + c*x + r*(S(1) - sqrt(S(3))*I)/S(2))**p*(b + c*x + r*(S(1) + sqrt(S(3))*I)/S(2))**p, x), x) def With1781(a, b, c, d, p, x): r = Rt(-S(3)*b*c*d + c**S(3), S(3)) return Dist((b + x*(c - r))**(-p)*(b + x*(c + r*(S(1) - sqrt(S(3))*I)/S(2)))**(-p)*(b + x*(c + r*(S(1) + sqrt(S(3))*I)/S(2)))**(-p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((b + x*(c - r))**p*(b + x*(c + r*(S(1) - sqrt(S(3))*I)/S(2)))**p*(b + x*(c + r*(S(1) + sqrt(S(3))*I)/S(2)))**p, x), x) def With1782(a, b, c, d, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = NonfreeFactors(Factor(a + b*x + c*x**S(2) + d*x**S(3)), x) if ProductQ(u): return True return False def replacement1782(a, b, c, d, p, x): u = NonfreeFactors(Factor(a + b*x + c*x**S(2) + d*x**S(3)), x) return Dist((a + b*x + c*x**S(2) + d*x**S(3))**p/DistributeDegree(u, p), Int(DistributeDegree(u, p), x), x) def With1783(a, b, c, d, p, x): r = Rt(-S(27)*a*d**S(2) + S(9)*b*c*d - S(2)*c**S(3) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) - S(18)*a*b*c*d + S(4)*a*c**S(3) + S(4)*b**S(3)*d - b**S(2)*c**S(2)), S(3)) return Dist((c + S(3)*d*x - S(2)**(S(1)/3)*(-S(6)*b*d + S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) - sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) - I))/(S(4)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) + sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) + I))/(S(4)*r))**(-p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((c + S(3)*d*x - S(2)**(S(1)/3)*(-S(6)*b*d + S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) - sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) - I))/(S(4)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) + sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) + I))/(S(4)*r))**p, x), x) def replacement1784(p, u, x): return Int(ExpandToSum(u, x)**p, x) def replacement1785(a, b, c, d, e, f, m, p, x): return Dist(S(3)**(-p)*b**(-p)*c**(-p), Int((b + c*x)**(S(3)*p)*(e + f*x)**m, x), x) def With1786(a, b, c, d, e, f, m, p, x): r = Rt(-S(3)*a*b*c + b**S(3), S(3)) return Dist(S(3)**(-p)*b**(-p)*c**(-p), Int((e + f*x)**m*(b + c*x - r)**p*(b + c*x + r*(S(1) - sqrt(S(3))*I)/S(2))**p*(b + c*x + r*(S(1) + sqrt(S(3))*I)/S(2))**p, x), x) def With1787(a, b, c, d, e, f, m, p, x): r = Rt(-S(3)*b*c*d + c**S(3), S(3)) return Dist(S(3)**(-p)*b**(-p)*c**(-p), Int((b + x*(c - r))**p*(b + x*(c + r*(S(1) - sqrt(S(3))*I)/S(2)))**p*(b + x*(c + r*(S(1) + sqrt(S(3))*I)/S(2)))**p*(e + f*x)**m, x), x) def replacement1788(a, b, c, d, e, f, m, p, x): return Int(ExpandIntegrand((e + f*x)**m*(a + b*x + c*x**S(2) + d*x**S(3))**p, x), x) def With1789(a, b, c, d, e, f, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = Factor(a + b*x + c*x**S(2) + d*x**S(3)) if ProductQ(NonfreeFactors(u, x)): return True return False def replacement1789(a, b, c, d, e, f, m, p, x): u = Factor(a + b*x + c*x**S(2) + d*x**S(3)) return Dist(FreeFactors(u, x)**p, Int((e + f*x)**m*DistributeDegree(NonfreeFactors(u, x), p), x), x) def replacement1790(a, b, c, d, e, f, m, p, x): return Dist(S(3)**(-S(3)*p)*d**(-S(2)*p), Subst(Int((S(27)*a*d**S(2) - S(9)*b*c*d + S(2)*c**S(3) + S(27)*d**S(3)*x**S(3) - S(9)*d*x*(-S(3)*b*d + c**S(2)))**p, x), x, c/(S(3)*d) + x), x) def replacement1791(a, b, c, d, e, f, m, p, x): return Dist((b + c*x)**(-S(3)*p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((b + c*x)**(S(3)*p)*(e + f*x)**m, x), x) def With1792(a, b, c, d, e, f, m, p, x): r = Rt(-S(3)*a*b*c + b**S(3), S(3)) return Dist((b + c*x - r)**(-p)*(b + c*x + r*(S(1) - sqrt(S(3))*I)/S(2))**(-p)*(b + c*x + r*(S(1) + sqrt(S(3))*I)/S(2))**(-p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((e + f*x)**m*(b + c*x - r)**p*(b + c*x + r*(S(1) - sqrt(S(3))*I)/S(2))**p*(b + c*x + r*(S(1) + sqrt(S(3))*I)/S(2))**p, x), x) def With1793(a, b, c, d, e, f, m, p, x): r = Rt(-S(3)*b*c*d + c**S(3), S(3)) return Dist((b + x*(c - r))**(-p)*(b + x*(c + r*(S(1) - sqrt(S(3))*I)/S(2)))**(-p)*(b + x*(c + r*(S(1) + sqrt(S(3))*I)/S(2)))**(-p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((b + x*(c - r))**p*(b + x*(c + r*(S(1) - sqrt(S(3))*I)/S(2)))**p*(b + x*(c + r*(S(1) + sqrt(S(3))*I)/S(2)))**p*(e + f*x)**m, x), x) def With1794(a, b, c, d, e, f, m, p, x): if isinstance(x, (int, Integer, float, Float)): return False u = NonfreeFactors(Factor(a + b*x + c*x**S(2) + d*x**S(3)), x) if ProductQ(u): return True return False def replacement1794(a, b, c, d, e, f, m, p, x): u = NonfreeFactors(Factor(a + b*x + c*x**S(2) + d*x**S(3)), x) return Dist((a + b*x + c*x**S(2) + d*x**S(3))**p/DistributeDegree(u, p), Int((e + f*x)**m*DistributeDegree(u, p), x), x) def With1795(a, b, c, d, e, f, m, p, x): r = Rt(-S(27)*a*d**S(2) + S(9)*b*c*d - S(2)*c**S(3) + S(3)*sqrt(S(3))*d*sqrt(S(27)*a**S(2)*d**S(2) - S(18)*a*b*c*d + S(4)*a*c**S(3) + S(4)*b**S(3)*d - b**S(2)*c**S(2)), S(3)) return Dist((c + S(3)*d*x - S(2)**(S(1)/3)*(-S(6)*b*d + S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) - sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) - I))/(S(4)*r))**(-p)*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) + sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) + I))/(S(4)*r))**(-p)*(a + b*x + c*x**S(2) + d*x**S(3))**p, Int((e + f*x)**m*(c + S(3)*d*x - S(2)**(S(1)/3)*(-S(6)*b*d + S(2)*c**S(2) + S(2)**(S(1)/3)*r**S(2))/(S(2)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) - sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) - sqrt(S(3))*I) + S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) - I))/(S(4)*r))**p*(c + S(3)*d*x + S(2)**(S(1)/3)*(-S(6)*b*d*(S(1) + sqrt(S(3))*I) + S(2)*c**S(2)*(S(1) + sqrt(S(3))*I) - S(2)**(S(1)/3)*I*r**S(2)*(sqrt(S(3)) + I))/(S(4)*r))**p, x), x) def replacement1796(m, p, u, v, x): return Int(ExpandToSum(u, x)**m*ExpandToSum(v, x)**p, x) def replacement1797(a, b, c, d, e, f, g, x): return Simp(a*f*ArcTan((a*b*x**S(2) + a*b + x*(S(4)*a**S(2) - S(2)*a*c + b**S(2)))/(S(2)*sqrt(a*x**S(4) + a + b*x**S(3) + b*x + c*x**S(2))*Rt(a**S(2)*(S(2)*a - c), S(2))))/(d*Rt(a**S(2)*(S(2)*a - c), S(2))), x) def replacement1798(a, b, c, d, e, f, g, x): return -Simp(a*f*atanh((a*b*x**S(2) + a*b + x*(S(4)*a**S(2) - S(2)*a*c + b**S(2)))/(S(2)*sqrt(a*x**S(4) + a + b*x**S(3) + b*x + c*x**S(2))*Rt(-a**S(2)*(S(2)*a - c), S(2))))/(d*Rt(-a**S(2)*(S(2)*a - c), S(2))), x) def replacement1799(a, b, c, d, e, p, x): return Subst(Int(SimplifyIntegrand((a - b*d/(S(8)*e) + d**S(4)/(S(256)*e**S(3)) + e*x**S(4) + x**S(2)*(c - S(3)*d**S(2)/(S(8)*e)))**p, x), x), x, d/(S(4)*e) + x) def With1800(p, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = Coefficient(v, x, S(0)) b = Coefficient(v, x, S(1)) c = Coefficient(v, x, S(2)) d = Coefficient(v, x, S(3)) e = Coefficient(v, x, S(4)) if And(ZeroQ(S(8)*b*e**S(2) - S(4)*c*d*e + d**S(3)), NonzeroQ(d)): return True return False def replacement1800(p, v, x): a = Coefficient(v, x, S(0)) b = Coefficient(v, x, S(1)) c = Coefficient(v, x, S(2)) d = Coefficient(v, x, S(3)) e = Coefficient(v, x, S(4)) return Subst(Int(SimplifyIntegrand((a - b*d/(S(8)*e) + d**S(4)/(S(256)*e**S(3)) + e*x**S(4) + x**S(2)*(c - S(3)*d**S(2)/(S(8)*e)))**p, x), x), x, d/(S(4)*e) + x) def replacement1801(a, b, c, d, e, p, u, x): return Subst(Int(SimplifyIntegrand((a - b*d/(S(8)*e) + d**S(4)/(S(256)*e**S(3)) + e*x**S(4) + x**S(2)*(c - S(3)*d**S(2)/(S(8)*e)))**p*ReplaceAll(u, Rule(x, -d/(S(4)*e) + x)), x), x), x, d/(S(4)*e) + x) def With1802(p, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = Coefficient(v, x, S(0)) b = Coefficient(v, x, S(1)) c = Coefficient(v, x, S(2)) d = Coefficient(v, x, S(3)) e = Coefficient(v, x, S(4)) if And(ZeroQ(S(8)*b*e**S(2) - S(4)*c*d*e + d**S(3)), NonzeroQ(d)): return True return False def replacement1802(p, u, v, x): a = Coefficient(v, x, S(0)) b = Coefficient(v, x, S(1)) c = Coefficient(v, x, S(2)) d = Coefficient(v, x, S(3)) e = Coefficient(v, x, S(4)) return Subst(Int(SimplifyIntegrand((a - b*d/(S(8)*e) + d**S(4)/(S(256)*e**S(3)) + e*x**S(4) + x**S(2)*(c - S(3)*d**S(2)/(S(8)*e)))**p*ReplaceAll(u, Rule(x, -d/(S(4)*e) + x)), x), x), x, d/(S(4)*e) + x) def replacement1803(a, b, c, d, e, p, x): return Dist(-S(16)*a**S(2), Subst(Int((a*(S(256)*a**S(4)*x**S(4) + S(256)*a**S(3)*e - S(64)*a**S(2)*b*d - S(32)*a**S(2)*x**S(2)*(-S(8)*a*c + S(3)*b**S(2)) + S(16)*a*b**S(2)*c - S(3)*b**S(4))/(-S(4)*a*x + b)**S(4))**p/(-S(4)*a*x + b)**S(2), x), x, S(1)/x + b/(S(4)*a)), x) def With1804(p, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = Coefficient(v, x, S(0)) b = Coefficient(v, x, S(1)) c = Coefficient(v, x, S(2)) d = Coefficient(v, x, S(3)) e = Coefficient(v, x, S(4)) if And(NonzeroQ(a), NonzeroQ(b), ZeroQ(S(8)*a**S(2)*d - S(4)*a*b*c + b**S(3))): return True return False def replacement1804(p, v, x): a = Coefficient(v, x, S(0)) b = Coefficient(v, x, S(1)) c = Coefficient(v, x, S(2)) d = Coefficient(v, x, S(3)) e = Coefficient(v, x, S(4)) return Dist(-S(16)*a**S(2), Subst(Int((a*(S(256)*a**S(4)*x**S(4) + S(256)*a**S(3)*e - S(64)*a**S(2)*b*d - S(32)*a**S(2)*x**S(2)*(-S(8)*a*c + S(3)*b**S(2)) + S(16)*a*b**S(2)*c - S(3)*b**S(4))/(-S(4)*a*x + b)**S(4))**p/(-S(4)*a*x + b)**S(2), x), x, S(1)/x + b/(S(4)*a)), x) def With1805(A, B, C, D, a, b, c, d, e, x): q = sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)) return -Dist(S(1)/q, Int((A*b - A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a - S(2)*C*a + D*b - D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b - q)), x), x) + Dist(S(1)/q, Int((A*b + A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a - S(2)*C*a + D*b + D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b + q)), x), x) def With1806(A, B, D, a, b, c, d, e, x): q = sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)) return -Dist(S(1)/q, Int((A*b - A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a + D*b - D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b - q)), x), x) + Dist(S(1)/q, Int((A*b + A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a + D*b + D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b + q)), x), x) def With1807(A, B, C, D, a, b, c, d, e, m, x): q = sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)) return -Dist(S(1)/q, Int(x**m*(A*b - A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a - S(2)*C*a + D*b - D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b - q)), x), x) + Dist(S(1)/q, Int(x**m*(A*b + A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a - S(2)*C*a + D*b + D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b + q)), x), x) def With1808(A, B, D, a, b, c, d, e, m, x): q = sqrt(S(8)*a**S(2) - S(4)*a*c + b**S(2)) return -Dist(S(1)/q, Int(x**m*(A*b - A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a + D*b - D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b - q)), x), x) + Dist(S(1)/q, Int(x**m*(A*b + A*q - S(2)*B*a + S(2)*D*a + x*(S(2)*A*a + D*b + D*q))/(S(2)*a*x**S(2) + S(2)*a + x*(b + q)), x), x) def With1809(A, B, C, a, b, c, d, e, x): q = Rt(C*(C*(-S(4)*c*e + d**S(2)) + S(2)*e*(-S(4)*A*e + B*d)), S(2)) return Simp(-S(2)*C**S(2)*atanh((-B*e + C*d + S(2)*C*e*x)/q)/q, x) + Simp(S(2)*C**S(2)*atanh(C*(S(12)*A*B*e - S(4)*A*C*d - S(3)*B**S(2)*d + S(4)*B*C*c + S(8)*C**S(2)*e*x**S(3) + S(4)*C*x**S(2)*(-B*e + S(2)*C*d) + S(4)*C*x*(S(2)*A*e - B*d + S(2)*C*c))/(q*(-S(4)*A*C + B**S(2))))/q, x) def With1810(A, C, a, b, c, d, e, x): q = Rt(C*(-S(8)*A*e**S(2) + C*(-S(4)*c*e + d**S(2))), S(2)) return Simp(-S(2)*C**S(2)*atanh(C*(d + S(2)*e*x)/q)/q, x) + Simp(S(2)*C**S(2)*atanh(C*(A*d - S(2)*C*d*x**S(2) - S(2)*C*e*x**S(3) - S(2)*x*(A*e + C*c))/(A*q))/q, x) def With1811(A, B, C, a, b, c, d, e, x): q = Rt(-C*(C*(-S(4)*c*e + d**S(2)) + S(2)*e*(-S(4)*A*e + B*d)), S(2)) return Simp(S(2)*C**S(2)*ArcTan((-B*e + C*d + S(2)*C*e*x)/q)/q, x) - Simp(S(2)*C**S(2)*ArcTan(C*(S(12)*A*B*e - S(4)*A*C*d - S(3)*B**S(2)*d + S(4)*B*C*c + S(8)*C**S(2)*e*x**S(3) + S(4)*C*x**S(2)*(-B*e + S(2)*C*d) + S(4)*C*x*(S(2)*A*e - B*d + S(2)*C*c))/(q*(-S(4)*A*C + B**S(2))))/q, x) def With1812(A, C, a, b, c, d, e, x): q = Rt(-C*(-S(8)*A*e**S(2) + C*(-S(4)*c*e + d**S(2))), S(2)) return Simp(S(2)*C**S(2)*ArcTan((C*d + S(2)*C*e*x)/q)/q, x) - Simp(S(2)*C**S(2)*ArcTan(-C*(-A*d + S(2)*C*d*x**S(2) + S(2)*C*e*x**S(3) + S(2)*x*(A*e + C*c))/(A*q))/q, x) def replacement1813(A, B, C, D, a, b, c, d, e, x): return -Dist(S(1)/(S(4)*e), Int((-S(4)*A*e + D*b + x**S(2)*(-S(4)*C*e + S(3)*D*d) + S(2)*x*(-S(2)*B*e + D*c))/(a + b*x + c*x**S(2) + d*x**S(3) + e*x**S(4)), x), x) + Simp(D*log(a + b*x + c*x**S(2) + d*x**S(3) + e*x**S(4))/(S(4)*e), x) def replacement1814(A, B, D, a, b, c, d, e, x): return -Dist(S(1)/(S(4)*e), Int((-S(4)*A*e + D*b + S(3)*D*d*x**S(2) + S(2)*x*(-S(2)*B*e + D*c))/(a + b*x + c*x**S(2) + d*x**S(3) + e*x**S(4)), x), x) + Simp(D*log(a + b*x + c*x**S(2) + d*x**S(3) + e*x**S(4))/(S(4)*e), x) def replacement1815(a, b, c, d, e, f, u, x): return -Dist(a/(f*(-a*d + b*c)), Int(u*sqrt(c + d*x)/x, x), x) + Dist(c/(e*(-a*d + b*c)), Int(u*sqrt(a + b*x)/x, x), x) def replacement1816(a, b, c, d, e, f, u, x): return Dist(b/(f*(-a*d + b*c)), Int(u*sqrt(c + d*x), x), x) - Dist(d/(e*(-a*d + b*c)), Int(u*sqrt(a + b*x), x), x) def replacement1817(a, b, c, d, e, f, u, x): return Dist(e, Int(u*sqrt(a + b*x)/(a*e**S(2) - c*f**S(2) + x*(b*e**S(2) - d*f**S(2))), x), x) - Dist(f, Int(u*sqrt(c + d*x)/(a*e**S(2) - c*f**S(2) + x*(b*e**S(2) - d*f**S(2))), x), x) def replacement1818(a, b, c, d, n, p, u, x): return Dist(S(1)/(a*c), Int(u*sqrt(a + b*x**(S(2)*n)), x), x) - Dist(b/(a*d), Int(u*x**n, x), x) def replacement1819(a, b, c, d, m, n, p, x): return Dist(c, Int(x**m*sqrt(a + b*x**(S(2)*n))/(a*c**S(2) + x**(S(2)*n)*(b*c**S(2) - d**S(2))), x), x) - Dist(d, Int(x**(m + n)/(a*c**S(2) + x**(S(2)*n)*(b*c**S(2) - d**S(2))), x), x) def With1820(a, b, d, e, f, x): r = Numerator(Rt(a/b, S(3))) s = Denominator(Rt(a/b, S(3))) return Dist(r/(S(3)*a), Int(S(1)/((r + s*x)*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(r/(S(3)*a), Int((S(2)*r - s*x)/(sqrt(d + e*x + f*x**S(2))*(r**S(2) - r*s*x + s**S(2)*x**S(2))), x), x) def With1821(a, b, d, f, x): r = Numerator(Rt(a/b, S(3))) s = Denominator(Rt(a/b, S(3))) return Dist(r/(S(3)*a), Int(S(1)/(sqrt(d + f*x**S(2))*(r + s*x)), x), x) + Dist(r/(S(3)*a), Int((S(2)*r - s*x)/(sqrt(d + f*x**S(2))*(r**S(2) - r*s*x + s**S(2)*x**S(2))), x), x) def With1822(a, b, d, e, f, x): r = Numerator(Rt(-a/b, S(3))) s = Denominator(Rt(-a/b, S(3))) return Dist(r/(S(3)*a), Int(S(1)/((r - s*x)*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(r/(S(3)*a), Int((S(2)*r + s*x)/(sqrt(d + e*x + f*x**S(2))*(r**S(2) + r*s*x + s**S(2)*x**S(2))), x), x) def With1823(a, b, d, f, x): r = Numerator(Rt(-a/b, S(3))) s = Denominator(Rt(-a/b, S(3))) return Dist(r/(S(3)*a), Int(S(1)/(sqrt(d + f*x**S(2))*(r - s*x)), x), x) + Dist(r/(S(3)*a), Int((S(2)*r + s*x)/(sqrt(d + f*x**S(2))*(r**S(2) + r*s*x + s**S(2)*x**S(2))), x), x) def replacement1824(a, b, c, d, e, x): return Dist(d, Int(S(1)/((d**S(2) - e**S(2)*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) - Dist(e, Int(x/((d**S(2) - e**S(2)*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) def replacement1825(a, c, d, e, x): return Dist(d, Int(S(1)/(sqrt(a + c*x**S(4))*(d**S(2) - e**S(2)*x**S(2))), x), x) - Dist(e, Int(x/(sqrt(a + c*x**S(4))*(d**S(2) - e**S(2)*x**S(2))), x), x) def replacement1826(a, b, c, d, e, x): return -Dist(c/(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4)), Int((d**S(2) - e**S(2)*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) - Simp(e**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))/((d + e*x)*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))), x) def replacement1827(a, b, c, d, e, x): return -Dist(c/(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4)), Int((d**S(2) - e**S(2)*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((b*d*e**S(2) + S(2)*c*d**S(3))/(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4)), Int(S(1)/((d + e*x)*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) - Simp(e**S(3)*sqrt(a + b*x**S(2) + c*x**S(4))/((d + e*x)*(a*e**S(4) + b*d**S(2)*e**S(2) + c*d**S(4))), x) def replacement1828(a, c, d, e, x): return -Dist(c/(a*e**S(4) + c*d**S(4)), Int((d**S(2) - e**S(2)*x**S(2))/sqrt(a + c*x**S(4)), x), x) + Dist(S(2)*c*d**S(3)/(a*e**S(4) + c*d**S(4)), Int(S(1)/(sqrt(a + c*x**S(4))*(d + e*x)), x), x) - Simp(e**S(3)*sqrt(a + c*x**S(4))/((d + e*x)*(a*e**S(4) + c*d**S(4))), x) def replacement1829(A, B, a, b, c, d, e, x): return Dist(A, Subst(Int(S(1)/(d - x**S(2)*(-S(2)*a*e + b*d)), x), x, x/sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1830(A, B, a, c, d, e, x): return Dist(A, Subst(Int(S(1)/(S(2)*a*e*x**S(2) + d), x), x, x/sqrt(a + c*x**S(4))), x) def replacement1831(A, B, a, b, c, d, e, f, x): return Dist(A, Subst(Int(S(1)/(d - x**S(2)*(-a*e + b*d)), x), x, x/sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1832(A, B, a, c, d, e, f, x): return Dist(A, Subst(Int(S(1)/(a*e*x**S(2) + d), x), x, x/sqrt(a + c*x**S(4))), x) def replacement1833(A, B, a, b, c, d, f, x): return Dist(A, Subst(Int(S(1)/(-b*d*x**S(2) + d), x), x, x/sqrt(a + b*x**S(2) + c*x**S(4))), x) def replacement1834(a, b, c, d, e, x): return Dist(a/d, Subst(Int(S(1)/(-S(2)*b*x**S(2) + x**S(4)*(-S(4)*a*c + b**S(2)) + S(1)), x), x, x/sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1835(a, b, c, d, e, x): q = sqrt(-S(4)*a*c + b**S(2)) return Simp(sqrt(S(2))*a*sqrt(-b + q)*atanh(sqrt(S(2))*x*sqrt(-b + q)*(b + S(2)*c*x**S(2) + q)/(S(4)*sqrt(a + b*x**S(2) + c*x**S(4))*Rt(-a*c, S(2))))/(S(4)*d*Rt(-a*c, S(2))), x) - Simp(sqrt(S(2))*a*sqrt(b + q)*ArcTan(sqrt(S(2))*x*sqrt(b + q)*(b + S(2)*c*x**S(2) - q)/(S(4)*sqrt(a + b*x**S(2) + c*x**S(4))*Rt(-a*c, S(2))))/(S(4)*d*Rt(-a*c, S(2))), x) def replacement1836(a, b, c, d, e, f, x): return Dist(a, Int(S(1)/((a**S(2) - b**S(2)*x**S(2))*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) - Dist(b, Int(x/((a**S(2) - b**S(2)*x**S(2))*sqrt(c + d*x**S(2))*sqrt(e + f*x**S(2))), x), x) def replacement1837(a, b, c, d, e, f, g, h, x): return Simp(S(2)*sqrt(d + e*x + f*sqrt(a + b*x + c*x**S(2)))*(S(9)*c**S(2)*f*g*h*x**S(2) + S(3)*c**S(2)*f*h**S(2)*x**S(3) + c*f*x*(a*h**S(2) - b*g*h + S(10)*c*g**S(2)) + f*(S(2)*a*b*h**S(2) - S(3)*a*c*g*h - S(2)*b**S(2)*g*h + S(5)*b*c*g**S(2)) - (-d*h + e*g)*sqrt(a + b*x + c*x**S(2))*(-S(2)*b*h + S(5)*c*g + c*h*x))/(S(15)*c**S(2)*f*(g + h*x)), x) def replacement1838(f, g, h, j, k, m, n, u, v, x): return Int((g + h*x)**m*(f*k*sqrt(ExpandToSum(v, x)) + ExpandToSum(f*j + u, x))**n, x) def replacement1839(a, b, c, d, e, f, g, h, n, p, x): return Dist(S(2), Subst(Int((g + h*x**n)**p*(d**S(2)*e + e*x**S(2) - f**S(2)*(-a*e + b*d) - x*(-b*f**S(2) + S(2)*d*e))/(b*f**S(2) - S(2)*d*e + S(2)*e*x)**S(2), x), x, d + e*x + f*sqrt(a + b*x + c*x**S(2))), x) def replacement1840(a, c, d, e, f, g, h, n, p, x): return Dist(S(1)/(S(2)*e), Subst(Int((g + h*x**n)**p*(a*f**S(2) + d**S(2) - S(2)*d*x + x**S(2))/(d - x)**S(2), x), x, d + e*x + f*sqrt(a + c*x**S(2))), x) def replacement1841(f, g, h, n, p, u, v, x): return Int((g + h*(f*sqrt(ExpandToSum(v, x)) + ExpandToSum(u, x))**n)**p, x) def replacement1842(a, c, e, f, g, h, m, n, x): return Dist(S(2)**(-m + S(-1))*e**(-m + S(-1)), Subst(Int(x**(-m + n + S(-2))*(a*f**S(2) + x**S(2))*(-a*f**S(2)*h + S(2)*e*g*x + h*x**S(2))**m, x), x, e*x + f*sqrt(a + c*x**S(2))), x) def replacement1843(a, c, e, f, g, i, m, n, p, x): return Dist(S(2)**(-S(2)*m - p + S(-1))*e**(-p + S(-1))*f**(-S(2)*m)*(i/c)**m, Subst(Int(x**(-S(2)*m + n - p + S(-2))*(-a*f**S(2) + x**S(2))**p*(a*f**S(2) + x**S(2))**(S(2)*m + S(1)), x), x, e*x + f*sqrt(a + c*x**S(2))), x) def replacement1844(a, b, c, d, e, f, g, h, i, m, n, x): return Dist(S(2)*f**(-S(2)*m)*(i/c)**m, Subst(Int(x**n*(b*f**S(2) - S(2)*d*e + S(2)*e*x)**(-S(2)*m + S(-2))*(d**S(2)*e + e*x**S(2) - f**S(2)*(-a*e + b*d) - x*(-b*f**S(2) + S(2)*d*e))**(S(2)*m + S(1)), x), x, d + e*x + f*sqrt(a + b*x + c*x**S(2))), x) def replacement1845(a, c, d, e, f, g, i, m, n, x): return Dist(S(2)**(-S(2)*m + S(-1))*f**(-S(2)*m)*(i/c)**m/e, Subst(Int(x**n*(-d + x)**(-S(2)*m + S(-2))*(a*f**S(2) + d**S(2) - S(2)*d*x + x**S(2))**(S(2)*m + S(1)), x), x, d + e*x + f*sqrt(a + c*x**S(2))), x) def replacement1846(a, b, c, d, e, f, g, h, i, m, n, x): return Dist((i/c)**(m + S(-1)/2)*sqrt(g + h*x + i*x**S(2))/sqrt(a + b*x + c*x**S(2)), Int((a + b*x + c*x**S(2))**m*(d + e*x + f*sqrt(a + b*x + c*x**S(2)))**n, x), x) def replacement1847(a, c, d, e, f, g, i, m, n, x): return Dist((i/c)**(m + S(-1)/2)*sqrt(g + i*x**S(2))/sqrt(a + c*x**S(2)), Int((a + c*x**S(2))**m*(d + e*x + f*sqrt(a + c*x**S(2)))**n, x), x) def replacement1848(a, b, c, d, e, f, g, h, i, m, n, x): return Dist((i/c)**(m + S(1)/2)*sqrt(a + b*x + c*x**S(2))/sqrt(g + h*x + i*x**S(2)), Int((a + b*x + c*x**S(2))**m*(d + e*x + f*sqrt(a + b*x + c*x**S(2)))**n, x), x) def replacement1849(a, c, d, e, f, g, i, m, n, x): return Dist((i/c)**(m + S(1)/2)*sqrt(a + c*x**S(2))/sqrt(g + i*x**S(2)), Int((a + c*x**S(2))**m*(d + e*x + f*sqrt(a + c*x**S(2)))**n, x), x) def replacement1850(f, j, k, m, n, u, v, w, x): return Int((f*k*sqrt(ExpandToSum(v, x)) + ExpandToSum(f*j + u, x))**n*ExpandToSum(w, x)**m, x) def replacement1851(a, b, c, d, n, p, x): return Dist(S(1)/a, Subst(Int(S(1)/(-c*x**S(2) + S(1)), x), x, x/sqrt(c*x**S(2) + d*(a + b*x**n)**(S(2)/n))), x) def replacement1852(a, b, c, d, x): return Simp(S(2)*a*x/sqrt(a + b*sqrt(c + d*x**S(2))), x) + Simp(S(2)*b**S(2)*d*x**S(3)/(S(3)*(a + b*sqrt(c + d*x**S(2)))**(S(3)/2)), x) def replacement1853(a, b, c, d, x): return Dist(sqrt(S(2))*b/a, Subst(Int(S(1)/sqrt(S(1) + x**S(2)/a), x), x, a*x + b*sqrt(c + d*x**S(2))), x) def replacement1854(a, b, c, d, e, x): return Int(sqrt(a*e*x**S(2) + b*e*x*sqrt(c + d*x**S(2)))/(x*sqrt(c + d*x**S(2))), x) def replacement1855(a, b, c, d, x): return Dist(d, Subst(Int(S(1)/(-S(2)*c*x**S(2) + S(1)), x), x, x/sqrt(c*x**S(2) + d*sqrt(a + b*x**S(4)))), x) def replacement1856(a, b, c, d, e, m, x): return Dist(S(1)/2 - I/S(2), Int((c + d*x)**m/sqrt(sqrt(a) - I*b*x**S(2)), x), x) + Dist(S(1)/2 + I/S(2), Int((c + d*x)**m/sqrt(sqrt(a) + I*b*x**S(2)), x), x) def With1857(a, b, c, d, x): q = Rt(b/a, S(3)) return Dist(d/(-c*q + d*(S(1) + sqrt(S(3)))), Int((q*x + S(1) + sqrt(S(3)))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) - Dist(q/(-c*q + d*(S(1) + sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1858(a, b, c, d, x): q = Rt(-b/a, S(3)) return Dist(d/(c*q + d*(S(1) + sqrt(S(3)))), Int((-q*x + S(1) + sqrt(S(3)))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) + Dist(q/(c*q + d*(S(1) + sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1859(a, b, c, d, x): q = Rt(-b/a, S(3)) return Dist(d/(c*q + d*(S(1) - sqrt(S(3)))), Int((-q*x - sqrt(S(3)) + S(1))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) + Dist(q/(c*q + d*(S(1) - sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1860(a, b, c, d, x): q = Rt(b/a, S(3)) return Dist(d/(-c*q + d*(S(1) - sqrt(S(3)))), Int((q*x - sqrt(S(3)) + S(1))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) - Dist(q/(-c*q + d*(S(1) - sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1861(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(b/a, S(3)) if ZeroQ(-e*q + f*(S(1) + sqrt(S(3)))): return True return False def replacement1861(a, b, c, d, e, f, x): q = Rt(b/a, S(3)) return Dist(S(4)*S(3)**(S(1)/4)*f*sqrt((q**S(2)*x**S(2) - q*x + S(1))/(q*x + S(1) + sqrt(S(3)))**S(2))*sqrt(S(2) - sqrt(S(3)))*(q*x + S(1))/(q*sqrt((q*x + S(1))/(q*x + S(1) + sqrt(S(3)))**S(2))*sqrt(a + b*x**S(3))), Subst(Int(S(1)/(sqrt(S(1) - x**S(2))*sqrt(x**S(2) - S(4)*sqrt(S(3)) + S(7))*(-c*q + d*(S(1) - sqrt(S(3))) + x*(-c*q + d*(S(1) + sqrt(S(3)))))), x), x, (-q*x + S(-1) + sqrt(S(3)))/(q*x + S(1) + sqrt(S(3)))), x) def With1862(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(b/a, S(3)) if NonzeroQ(-e*q + f*(S(1) + sqrt(S(3)))): return True return False def replacement1862(a, b, c, d, e, f, x): q = Rt(b/a, S(3)) return Dist((-c*f + d*e)/(-c*q + d*(S(1) + sqrt(S(3)))), Int((q*x + S(1) + sqrt(S(3)))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) + Dist((-e*q + f*(S(1) + sqrt(S(3))))/(-c*q + d*(S(1) + sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1863(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-b/a, S(3)) if ZeroQ(e*q + f*(S(1) + sqrt(S(3)))): return True return False def replacement1863(a, b, c, d, e, f, x): q = Rt(-b/a, S(3)) return Dist(-S(4)*S(3)**(S(1)/4)*f*sqrt((q**S(2)*x**S(2) + q*x + S(1))/(-q*x + S(1) + sqrt(S(3)))**S(2))*sqrt(S(2) - sqrt(S(3)))*(-q*x + S(1))/(q*sqrt((-q*x + S(1))/(-q*x + S(1) + sqrt(S(3)))**S(2))*sqrt(a + b*x**S(3))), Subst(Int(S(1)/(sqrt(S(1) - x**S(2))*sqrt(x**S(2) - S(4)*sqrt(S(3)) + S(7))*(c*q + d*(S(1) - sqrt(S(3))) + x*(c*q + d*(S(1) + sqrt(S(3)))))), x), x, (q*x + S(-1) + sqrt(S(3)))/(-q*x + S(1) + sqrt(S(3)))), x) def With1864(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-b/a, S(3)) if NonzeroQ(e*q + f*(S(1) + sqrt(S(3)))): return True return False def replacement1864(a, b, c, d, e, f, x): q = Rt(-b/a, S(3)) return Dist((-c*f + d*e)/(c*q + d*(S(1) + sqrt(S(3)))), Int((-q*x + S(1) + sqrt(S(3)))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) + Dist((e*q + f*(S(1) + sqrt(S(3))))/(c*q + d*(S(1) + sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1865(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-b/a, S(3)) if ZeroQ(e*q + f*(S(1) - sqrt(S(3)))): return True return False def replacement1865(a, b, c, d, e, f, x): q = Rt(-b/a, S(3)) return Dist(S(4)*S(3)**(S(1)/4)*f*sqrt((q**S(2)*x**S(2) + q*x + S(1))/(-q*x - sqrt(S(3)) + S(1))**S(2))*sqrt(sqrt(S(3)) + S(2))*(-q*x + S(1))/(q*sqrt(-(-q*x + S(1))/(-q*x - sqrt(S(3)) + S(1))**S(2))*sqrt(a + b*x**S(3))), Subst(Int(S(1)/(sqrt(S(1) - x**S(2))*sqrt(x**S(2) + S(4)*sqrt(S(3)) + S(7))*(c*q + d*(S(1) + sqrt(S(3))) + x*(c*q + d*(S(1) - sqrt(S(3)))))), x), x, (-q*x + S(1) + sqrt(S(3)))/(q*x + S(-1) + sqrt(S(3)))), x) def With1866(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-b/a, S(3)) if NonzeroQ(e*q + f*(S(1) - sqrt(S(3)))): return True return False def replacement1866(a, b, c, d, e, f, x): q = Rt(-b/a, S(3)) return Dist((-c*f + d*e)/(c*q + d*(S(1) - sqrt(S(3)))), Int((-q*x - sqrt(S(3)) + S(1))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) + Dist((e*q + f*(S(1) - sqrt(S(3))))/(c*q + d*(S(1) - sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def With1867(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(b/a, S(3)) if ZeroQ(-e*q + f*(S(1) - sqrt(S(3)))): return True return False def replacement1867(a, b, c, d, e, f, x): q = Rt(b/a, S(3)) return Dist(-S(4)*S(3)**(S(1)/4)*f*sqrt((q**S(2)*x**S(2) - q*x + S(1))/(q*x - sqrt(S(3)) + S(1))**S(2))*sqrt(sqrt(S(3)) + S(2))*(q*x + S(1))/(q*sqrt(-(q*x + S(1))/(q*x - sqrt(S(3)) + S(1))**S(2))*sqrt(a + b*x**S(3))), Subst(Int(S(1)/(sqrt(S(1) - x**S(2))*sqrt(x**S(2) + S(4)*sqrt(S(3)) + S(7))*(-c*q + d*(S(1) + sqrt(S(3))) + x*(-c*q + d*(S(1) - sqrt(S(3)))))), x), x, (q*x + S(1) + sqrt(S(3)))/(-q*x + S(-1) + sqrt(S(3)))), x) def With1868(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(b/a, S(3)) if NonzeroQ(-e*q + f*(S(1) - sqrt(S(3)))): return True return False def replacement1868(a, b, c, d, e, f, x): q = Rt(b/a, S(3)) return Dist((-c*f + d*e)/(-c*q + d*(S(1) - sqrt(S(3)))), Int((q*x - sqrt(S(3)) + S(1))/(sqrt(a + b*x**S(3))*(c + d*x)), x), x) + Dist((-e*q + f*(S(1) - sqrt(S(3))))/(-c*q + d*(S(1) - sqrt(S(3)))), Int(S(1)/sqrt(a + b*x**S(3)), x), x) def replacement1869(a, b, c, d, e, m, n, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)/(c + d*x + e*sqrt(a + b*x)), x), x, x**n), x) def replacement1870(a, b, c, d, e, n, u, x): return Dist(c, Int(u/(-a*e**S(2) + c**S(2) + c*d*x**n), x), x) - Dist(a*e, Int(u/(sqrt(a + b*x**n)*(-a*e**S(2) + c**S(2) + c*d*x**n)), x), x) def replacement1871(A, B, a, b, c, d, n, n2, x): return Dist(A**S(2)*(n + S(-1)), Subst(Int(S(1)/(A**S(2)*b*x**S(2)*(n + S(-1))**S(2) + a), x), x, x/(A*(n + S(-1)) - B*x**n)), x) def replacement1872(A, B, a, b, c, d, k, m, n, n2, x): return Dist(A**S(2)*(m - n + S(1))/(m + S(1)), Subst(Int(S(1)/(A**S(2)*b*x**S(2)*(m - n + S(1))**S(2) + a), x), x, x**(m + S(1))/(A*(m - n + S(1)) + B*x**n*(m + S(1)))), x) def replacement1873(a, b, c, d, e, f, g, n, n2, n3, p, x): return -Dist(S(1)/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(a*b*(a*g + c*e) - S(2)*a*c*(a*f - c*d*(S(2)*n*(p + S(1)) + S(1))) - b**S(2)*c*d*(n*p + n + S(1)) + x**n*(a*b**S(2)*g*(n*(p + S(2)) + S(1)) - S(2)*a*c*(a*g*(n + S(1)) - c*e*(n*(S(2)*p + S(3)) + S(1))) - b*c*(a*f + c*d)*(n*(S(2)*p + S(3)) + S(1))), x), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a*b*(a*g + c*e) - S(2)*a*c*(-a*f + c*d) + b**S(2)*c*d + x**n*(-a*b**S(2)*g - S(2)*a*c*(-a*g + c*e) + b*c*(a*f + c*d)))/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1874(a, b, c, d, e, f, n, n2, p, x): return -Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(a*b*e - S(2)*a*(a*f - c*d*(S(2)*n*(p + S(1)) + S(1))) - b**S(2)*d*(n*p + n + S(1)) - x**n*(-S(2)*a*c*e*(n*(S(2)*p + S(3)) + S(1)) + b*(a*f + c*d)*(n*(S(2)*p + S(3)) + S(1))), x), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a*b*e - S(2)*a*(-a*f + c*d) + b**S(2)*d + x**n*(-S(2)*a*c*e + b*(a*f + c*d)))/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1875(a, b, c, d, e, g, n, n2, n3, p, x): return -Dist(S(1)/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(a*b*(a*g + c*e) + S(2)*a*c**S(2)*d*(S(2)*n*(p + S(1)) + S(1)) - b**S(2)*c*d*(n*p + n + S(1)) + x**n*(a*b**S(2)*g*(n*(p + S(2)) + S(1)) - S(2)*a*c*(a*g*(n + S(1)) - c*e*(n*(S(2)*p + S(3)) + S(1))) - b*c**S(2)*d*(n*(S(2)*p + S(3)) + S(1))), x), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a*b*(a*g + c*e) - S(2)*a*c**S(2)*d + b**S(2)*c*d + x**n*(-a*b**S(2)*g - S(2)*a*c*(-a*g + c*e) + b*c**S(2)*d))/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1876(a, b, c, d, f, g, n, n2, n3, p, x): return -Dist(S(1)/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(a**S(2)*b*g - S(2)*a*c*(a*f - c*d*(S(2)*n*(p + S(1)) + S(1))) - b**S(2)*c*d*(n*p + n + S(1)) + x**n*(-S(2)*a**S(2)*c*g*(n + S(1)) + a*b**S(2)*g*(n*(p + S(2)) + S(1)) - b*c*(a*f + c*d)*(n*(S(2)*p + S(3)) + S(1))), x), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a**S(2)*b*g - S(2)*a*c*(-a*f + c*d) + b**S(2)*c*d + x**n*(S(2)*a**S(2)*c*g - a*b**S(2)*g + b*c*(a*f + c*d)))/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1877(a, b, c, d, f, n, n2, p, x): return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(S(2)*a*(a*f - c*d*(S(2)*n*(p + S(1)) + S(1))) + b**S(2)*d*(n*p + n + S(1)) + b*x**n*(a*f + c*d)*(n*(S(2)*p + S(3)) + S(1)), x), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*(-a*f + c*d) + b**S(2)*d + b*x**n*(a*f + c*d))/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1878(a, b, c, d, g, n, n2, n3, p, x): return -Dist(S(1)/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(a**S(2)*b*g + S(2)*a*c**S(2)*d*(S(2)*n*(p + S(1)) + S(1)) - b**S(2)*c*d*(n*p + n + S(1)) + x**n*(-S(2)*a**S(2)*c*g*(n + S(1)) + a*b**S(2)*g*(n*(p + S(2)) + S(1)) - b*c**S(2)*d*(n*(S(2)*p + S(3)) + S(1))), x), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a**S(2)*b*g - S(2)*a*c**S(2)*d + b**S(2)*c*d + x**n*(S(2)*a**S(2)*c*g - a*b**S(2)*g + b*c**S(2)*d))/(a*c*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1879(a, c, d, e, f, g, n, n2, n3, p, x): return -Dist(-S(1)/(S(4)*a**S(2)*c**S(2)*n*(p + S(1))), Int((a + c*x**(S(2)*n))**(p + S(1))*Simp(-S(2)*a*c*x**n*(a*g*(n + S(1)) - c*e*(n*(S(2)*p + S(3)) + S(1))) - S(2)*a*c*(a*f - c*d*(S(2)*n*(p + S(1)) + S(1))), x), x), x) - Simp(-x*(a + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*c*x**n*(-a*g + c*e) - S(2)*a*c*(-a*f + c*d))/(S(4)*a**S(2)*c**S(2)*n*(p + S(1))), x) def replacement1880(a, c, d, e, f, n, n2, p, x): return -Dist(-S(1)/(S(4)*a**S(2)*c*n*(p + S(1))), Int((a + c*x**(S(2)*n))**(p + S(1))*Simp(S(2)*a*c*e*x**n*(n*(S(2)*p + S(3)) + S(1)) - S(2)*a*(a*f - c*d*(S(2)*n*(p + S(1)) + S(1))), x), x), x) - Simp(-x*(a + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*c*e*x**n - S(2)*a*(-a*f + c*d))/(S(4)*a**S(2)*c*n*(p + S(1))), x) def replacement1881(a, c, d, e, g, n, n2, n3, p, x): return -Dist(-S(1)/(S(4)*a**S(2)*c**S(2)*n*(p + S(1))), Int((a + c*x**(S(2)*n))**(p + S(1))*Simp(S(2)*a*c**S(2)*d*(S(2)*n*(p + S(1)) + S(1)) - S(2)*a*c*x**n*(a*g*(n + S(1)) - c*e*(n*(S(2)*p + S(3)) + S(1))), x), x), x) - Simp(-x*(a + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*c**S(2)*d - S(2)*a*c*x**n*(-a*g + c*e))/(S(4)*a**S(2)*c**S(2)*n*(p + S(1))), x) def With1882(a, b, c, d, e, f, g, x): q = Rt((S(12)*a**S(2)*g**S(2) - a*c*f**S(2) + f*(-S(2)*a*b*g + S(3)*c**S(2)*d))/(c*g*(-a*f + S(3)*c*d)), S(2)) r = Rt((a*c*f**S(2) - f*(S(2)*a*b*g + S(3)*c**S(2)*d) + S(4)*g*(a**S(2)*g + b*c*d))/(c*g*(-a*f + S(3)*c*d)), S(2)) return -Simp(c*ArcTan((r - S(2)*x)/q)/(g*q), x) + Simp(c*ArcTan((r + S(2)*x)/q)/(g*q), x) - Simp(c*ArcTan(x*(-a*f + S(3)*c*d)*(S(6)*a**S(2)*b*g**S(2) - S(2)*a**S(2)*c*f*g - a*b**S(2)*f*g + b*c**S(2)*d*f + c**S(2)*g*x**S(4)*(-a*f + S(3)*c*d) + c*x**S(2)*(S(2)*a**S(2)*g**S(2) - a*c*f**S(2) - b*c*d*g + S(3)*c**S(2)*d*f))/(g*q*(-S(2)*a**S(2)*g + b*c*d)*(S(4)*a**S(2)*g - a*b*f + b*c*d)))/(g*q), x) def With1883(a, c, d, e, f, g, x): q = Rt((S(12)*a**S(2)*g**S(2) - a*c*f**S(2) + S(3)*c**S(2)*d*f)/(c*g*(-a*f + S(3)*c*d)), S(2)) r = Rt((S(4)*a**S(2)*g**S(2) + a*c*f**S(2) - S(3)*c**S(2)*d*f)/(c*g*(-a*f + S(3)*c*d)), S(2)) return -Simp(c*ArcTan((r - S(2)*x)/q)/(g*q), x) + Simp(c*ArcTan((r + S(2)*x)/q)/(g*q), x) - Simp(c*ArcTan(c*x*(-a*f + S(3)*c*d)*(S(2)*a**S(2)*f*g - c*g*x**S(4)*(-a*f + S(3)*c*d) - x**S(2)*(S(2)*a**S(2)*g**S(2) - a*c*f**S(2) + S(3)*c**S(2)*d*f))/(S(8)*a**S(4)*g**S(3)*q))/(g*q), x) def With1884(p, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: m = Exponent(u, x) n = Exponent(v, x) c = Coefficient(u, x, m)/((m + n*p + S(1))*Coefficient(v, x, n)) c = Coefficient(u, x, m)/((m + n*p + S(1))*Coefficient(v, x, n)) w = Apart(-c*x**(m - n)*(v*(m - n + S(1)) + x*(p + S(1))*D(v, x)) + u, x) res = And(Inequality(S(1), Less, n, LessEqual, m + S(1)), Less(m + n*p, S(-1)), FalseQ(DerivativeDivides(v, u, x))) except (TypeError, AttributeError): return False if res: return True return False def replacement1884(p, u, v, x): m = Exponent(u, x) n = Exponent(v, x) c = Coefficient(u, x, m)/((m + n*p + S(1))*Coefficient(v, x, n)) c = Coefficient(u, x, m)/((m + n*p + S(1))*Coefficient(v, x, n)) w = Apart(-c*x**(m - n)*(v*(m - n + S(1)) + x*(p + S(1))*D(v, x)) + u, x) return Simp(If(ZeroQ(w), c*v**(p + 1)*x**(m - n + 1), c*v**(p + 1)*x**(m - n + 1) + Int(v**p*w, x)), x) sympy-sympy-1.9/sympy/integrals/rubi/rules/miscellaneous_integration.py000066400000000000000000001426071412543434000270210ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def miscellaneous_integration(): from sympy.integrals.rubi.constraints import cons149, cons2004, cons2, cons3, cons8, cons4, cons5, cons388, cons29, cons52, cons2005, cons2006, cons2007, cons2008, cons50, cons127, cons210, cons36, cons37, cons38, cons1101, cons2009, cons68, cons19, cons86, cons1039, cons1038, cons40, cons2010, cons10, cons2011, cons2012, cons2013, cons211, cons1833, cons1246, cons2014, cons48, cons2015, cons2016, cons2017, cons2018, cons54, cons2019, cons802, cons2020, cons20, cons2021, cons588, cons2022, cons2023, cons2024, cons2025, cons2026, cons2027, cons2028, cons2029, cons2030, cons669, cons198, cons2031, cons842, cons2032, cons21, cons2033, cons150, cons47, cons2034, cons1856, cons1249, cons263, cons2035, cons369, cons2036, cons69, cons1481, cons746, cons1484, cons167, cons2037, cons2038, cons1678, cons1257, cons2039, cons349 pattern6934 = Pattern(Integral(u_*((x_*WC('b', S(1)) + WC('a', S(0)))**n_*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons149, cons2004) rule6934 = ReplacementRule(pattern6934, replacement6934) pattern6935 = Pattern(Integral(((d_*(x_*WC('b', S(1)) + WC('a', S(0))))**p_*WC('c', S(1)))**q_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons52, cons149, cons388) rule6935 = ReplacementRule(pattern6935, replacement6935) pattern6936 = Pattern(Integral((((x_*WC('b', S(1)) + WC('a', S(0)))**n_*WC('d', S(1)))**p_*WC('c', S(1)))**q_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons52, cons149, cons388) rule6936 = ReplacementRule(pattern6936, replacement6936) pattern6937 = Pattern(Integral((F_*sqrt(x_*WC('e', S(1)) + WC('d', S(0)))*WC('b', S(1))*WC('c', S(1))/sqrt(x_*WC('g', S(1)) + WC('f', S(0))) + WC('a', S(0)))**WC('n', S(1))/(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons36, cons37, cons38, cons1101, cons2005, cons2006, cons2007, cons2008) rule6937 = ReplacementRule(pattern6937, replacement6937) pattern6938 = Pattern(Integral((F_*sqrt(x_*WC('e', S(1)) + S(1))*WC('b', S(1))*WC('c', S(1))/sqrt(x_*WC('g', S(1)) + S(1)) + WC('a', S(0)))**WC('n', S(1))/(x_**S(2)*WC('C', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons50, cons210, cons36, cons38, cons1101, cons2005, cons2009) rule6938 = ReplacementRule(pattern6938, replacement6938) pattern6939 = Pattern(Integral((F_**(sqrt(x_*WC('e', S(1)) + WC('d', S(0)))*WC('c', S(1))/sqrt(x_*WC('g', S(1)) + WC('f', S(0))))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons36, cons37, cons38, cons1101, cons2005, cons2006, cons2007, cons2008) rule6939 = ReplacementRule(pattern6939, replacement6939) pattern6940 = Pattern(Integral((F_**(sqrt(x_*WC('e', S(1)) + S(1))*WC('c', S(1))/sqrt(x_*WC('g', S(1)) + S(1)))*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/(x_**S(2)*WC('C', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons50, cons210, cons36, cons38, cons1101, cons2005, cons2009) rule6940 = ReplacementRule(pattern6940, replacement6940) pattern6941 = Pattern(Integral(u_/y_, x_), CustomConstraint(With6941)) rule6941 = ReplacementRule(pattern6941, replacement6941) pattern6942 = Pattern(Integral(u_/(w_*y_), x_), CustomConstraint(With6942)) rule6942 = ReplacementRule(pattern6942, replacement6942) pattern6943 = Pattern(Integral(u_*y_**WC('m', S(1)), x_), cons19, cons68, CustomConstraint(With6943)) rule6943 = ReplacementRule(pattern6943, replacement6943) pattern6944 = Pattern(Integral(u_*y_**WC('m', S(1))*z_**WC('n', S(1)), x_), cons19, cons4, cons68, CustomConstraint(With6944)) rule6944 = ReplacementRule(pattern6944, replacement6944) pattern6945 = Pattern(Integral(u_, x_), CustomConstraint(With6945)) rule6945 = ReplacementRule(pattern6945, replacement6945) pattern6946 = Pattern(Integral((sqrt(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1)) + sqrt(x_**WC('n', S(1))*WC('d', S(1)) + WC('c', S(0)))*WC('f', S(1)))**m_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons86, cons1039) rule6946 = ReplacementRule(pattern6946, replacement6946) pattern6947 = Pattern(Integral((sqrt(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1)) + sqrt(x_**WC('n', S(1))*WC('d', S(1)) + WC('c', S(0)))*WC('f', S(1)))**m_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons86, cons1038) rule6947 = ReplacementRule(pattern6947, replacement6947) pattern6948 = Pattern(Integral(u_**WC('m', S(1))*w_*(u_**n_*WC('a', S(1)) + v_)**WC('p', S(1)), x_), cons2, cons19, cons4, cons40, cons2010, cons10) rule6948 = ReplacementRule(pattern6948, replacement6948) pattern6949 = Pattern(Integral(u_*(v_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(y_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons2011, CustomConstraint(With6949)) rule6949 = ReplacementRule(pattern6949, replacement6949) pattern6950 = Pattern(Integral(u_*(v_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(w_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*(y_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons2011, cons2012, CustomConstraint(With6950)) rule6950 = ReplacementRule(pattern6950, replacement6950) pattern6951 = Pattern(Integral(u_*(v_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*(w_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*(y_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*(z_*WC('h', S(1)) + WC('g', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons4, cons5, cons52, cons2011, cons2012, cons2013, CustomConstraint(With6951)) rule6951 = ReplacementRule(pattern6951, replacement6951) pattern6952 = Pattern(Integral((a_ + y_**n_*WC('b', S(1)))*WC('u', S(1)), x_), cons2, cons3, cons4, cons1833, CustomConstraint(With6952)) rule6952 = ReplacementRule(pattern6952, replacement6952) pattern6953 = Pattern(Integral((y_**n_*WC('b', S(1)) + WC('a', S(0)))**p_*WC('u', S(1)), x_), cons2, cons3, cons4, cons5, cons1246, CustomConstraint(With6953)) rule6953 = ReplacementRule(pattern6953, replacement6953) pattern6954 = Pattern(Integral(v_**WC('m', S(1))*(y_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons19, cons4, cons5, cons2014, CustomConstraint(With6954)) rule6954 = ReplacementRule(pattern6954, replacement6954) pattern6955 = Pattern(Integral((v_**WC('n2', S(1))*WC('c', S(1)) + y_**n_*WC('b', S(1)) + WC('a', S(0)))**p_*WC('u', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons48, cons2011, CustomConstraint(With6955)) rule6955 = ReplacementRule(pattern6955, replacement6955) pattern6956 = Pattern(Integral((A_ + y_**n_*WC('B', S(1)))*(v_**n_*WC('b', S(1)) + w_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons5, cons48, cons2011, cons2012, CustomConstraint(With6956)) rule6956 = ReplacementRule(pattern6956, replacement6956) pattern6957 = Pattern(Integral((A_ + y_**n_*WC('B', S(1)))*(w_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons8, cons36, cons37, cons4, cons5, cons48, cons2012, CustomConstraint(With6957)) rule6957 = ReplacementRule(pattern6957, replacement6957) pattern6958 = Pattern(Integral(v_**WC('m', S(1))*(w_**WC('n2', S(1))*WC('c', S(1)) + y_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons48, cons2012, CustomConstraint(With6958)) rule6958 = ReplacementRule(pattern6958, replacement6958) pattern6959 = Pattern(Integral(z_**WC('m', S(1))*(A_ + y_**n_*WC('B', S(1)))*(v_**n_*WC('b', S(1)) + w_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons19, cons4, cons5, cons48, cons2011, cons2012, CustomConstraint(With6959)) rule6959 = ReplacementRule(pattern6959, replacement6959) pattern6960 = Pattern(Integral(z_**WC('m', S(1))*(A_ + y_**n_*WC('B', S(1)))*(w_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons8, cons36, cons37, cons19, cons4, cons5, cons48, cons2012, CustomConstraint(With6960)) rule6960 = ReplacementRule(pattern6960, replacement6960) pattern6961 = Pattern(Integral((v_**n_*WC('d', S(1)) + WC('c', S(0)))**WC('p', S(1))*(y_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons2011, CustomConstraint(With6961)) rule6961 = ReplacementRule(pattern6961, replacement6961) pattern6962 = Pattern(Integral((v_**n_*WC('d', S(1)) + WC('c', S(0)))**WC('p', S(1))*(w_**n_*WC('f', S(1)) + WC('e', S(0)))**WC('q', S(1))*(y_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons2011, cons2012, CustomConstraint(With6962)) rule6962 = ReplacementRule(pattern6962, replacement6962) pattern6963 = Pattern(Integral(F_**v_*u_, x_), cons1101, cons1101, CustomConstraint(With6963)) rule6963 = ReplacementRule(pattern6963, replacement6963) pattern6964 = Pattern(Integral(F_**v_*u_*w_**WC('m', S(1)), x_), cons1101, cons19, cons2015, CustomConstraint(With6964)) rule6964 = ReplacementRule(pattern6964, replacement6964) pattern6965 = Pattern(Integral(u_*(a_ + v_**WC('p', S(1))*w_**WC('p', S(1))*WC('b', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons19, cons5, cons40, CustomConstraint(With6965)) rule6965 = ReplacementRule(pattern6965, replacement6965) pattern6966 = Pattern(Integral(u_*v_**WC('r', S(1))*(a_ + v_**WC('p', S(1))*w_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons19, cons5, cons52, cons54, cons2016, cons2017, cons2018, CustomConstraint(With6966)) rule6966 = ReplacementRule(pattern6966, replacement6966) pattern6967 = Pattern(Integral(u_*v_**WC('r', S(1))*w_**WC('s', S(1))*(a_ + v_**WC('p', S(1))*w_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons19, cons5, cons52, cons54, cons802, cons2019, cons2017, cons2018, CustomConstraint(With6967)) rule6967 = ReplacementRule(pattern6967, replacement6967) pattern6968 = Pattern(Integral(u_*(v_**WC('p', S(1))*WC('a', S(1)) + w_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons19, cons5, cons52, cons2020, cons40, cons20, CustomConstraint(With6968)) rule6968 = ReplacementRule(pattern6968, replacement6968) pattern6969 = Pattern(Integral(u_*v_**WC('r', S(1))*(v_**WC('p', S(1))*WC('a', S(1)) + w_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons19, cons5, cons52, cons54, cons2021, cons588, cons20, CustomConstraint(With6969)) rule6969 = ReplacementRule(pattern6969, replacement6969) pattern6970 = Pattern(Integral(u_*w_**WC('s', S(1))*(v_**WC('p', S(1))*WC('a', S(1)) + w_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons19, cons5, cons52, cons802, cons2022, cons2023, cons2024, cons20, CustomConstraint(With6970)) rule6970 = ReplacementRule(pattern6970, replacement6970) pattern6971 = Pattern(Integral(u_*v_**WC('r', S(1))*w_**WC('s', S(1))*(v_**WC('p', S(1))*WC('a', S(1)) + w_**WC('q', S(1))*WC('b', S(1)))**WC('m', S(1)), x_), cons2, cons3, cons19, cons5, cons52, cons54, cons802, cons2025, cons2023, cons2024, cons20, CustomConstraint(With6971)) rule6971 = ReplacementRule(pattern6971, replacement6971) pattern6972 = Pattern(Integral(u_*x_**WC('m', S(1)), x_), cons19, cons68, cons2026) rule6972 = ReplacementRule(pattern6972, replacement6972) pattern6973 = Pattern(Integral(u_, x_), CustomConstraint(With6973)) rule6973 = ReplacementRule(pattern6973, replacement6973) pattern6974 = Pattern(Integral(u_, x_), CustomConstraint(With6974)) rule6974 = ReplacementRule(pattern6974, replacement6974) pattern6975 = Pattern(Integral((v_**WC('m', S(1))*w_**WC('n', S(1))*z_**WC('q', S(1))*WC('a', S(1)))**p_*WC('u', S(1)), x_), cons2, cons19, cons4, cons5, cons52, cons149, cons10, cons2027, cons2028) rule6975 = ReplacementRule(pattern6975, replacement6975) pattern6976 = Pattern(Integral((v_**WC('m', S(1))*w_**WC('n', S(1))*WC('a', S(1)))**p_*WC('u', S(1)), x_), cons2, cons19, cons4, cons5, cons149, cons10, cons2027) rule6976 = ReplacementRule(pattern6976, replacement6976) pattern6977 = Pattern(Integral((v_**WC('m', S(1))*WC('a', S(1)))**p_*WC('u', S(1)), x_), cons2, cons19, cons5, cons149, cons10, cons2029, cons2030) rule6977 = ReplacementRule(pattern6977, replacement6977) pattern6978 = Pattern(Integral((x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_*WC('u', S(1)), x_), cons2, cons3, cons5, cons669, cons198, cons2031) rule6978 = ReplacementRule(pattern6978, replacement6978) pattern6979 = Pattern(Integral((v_**n_*WC('b', S(1)) + WC('a', S(0)))**p_*WC('u', S(1)), x_), cons2, cons3, cons5, cons149, cons198, cons842, cons2032) rule6979 = ReplacementRule(pattern6979, replacement6979) pattern6980 = Pattern(Integral((v_**n_*x_**WC('m', S(1))*WC('b', S(1)) + WC('a', S(0)))**p_*WC('u', S(1)), x_), cons2, cons3, cons19, cons5, cons149, cons198, cons842) rule6980 = ReplacementRule(pattern6980, replacement6980) pattern6981 = Pattern(Integral((x_**WC('r', S(1))*WC('a', S(1)) + x_**WC('s', S(1))*WC('b', S(1)))**m_*WC('u', S(1)), x_), cons2, cons3, cons19, cons54, cons802, cons21, cons2033, CustomConstraint(With6981)) rule6981 = ReplacementRule(pattern6981, replacement6981) pattern6982 = Pattern(Integral(u_/(a_ + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons150, CustomConstraint(With6982)) rule6982 = ReplacementRule(pattern6982, replacement6982) pattern6983 = Pattern(Integral(u_*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons48, cons47, cons40, cons2034) rule6983 = ReplacementRule(pattern6983, replacement6983) pattern6984 = Pattern(Integral(u_*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons47, cons149, cons2034) rule6984 = ReplacementRule(pattern6984, replacement6984) pattern6985 = Pattern(Integral(u_/(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons48, cons150, CustomConstraint(With6985)) rule6985 = ReplacementRule(pattern6985, replacement6985) pattern6986 = Pattern(Integral(WC('u', S(1))/(x_**WC('m', S(1))*WC('a', S(1)) + sqrt(x_**n_*WC('c', S(1)))*WC('b', S(1))), x_), cons2, cons3, cons8, cons19, cons4, cons1856) rule6986 = ReplacementRule(pattern6986, replacement6986) pattern6987 = Pattern(Integral(u_, x_), CustomConstraint(With6987)) rule6987 = ReplacementRule(pattern6987, replacement6987) pattern6988 = Pattern(Integral(u_/x_, x_), cons1249, cons2031, CustomConstraint(With6988)) rule6988 = ReplacementRule(pattern6988, replacement6988) pattern6989 = Pattern(Integral(u_*x_**WC('m', S(1)), x_), cons20, cons263, cons1249, cons2035, CustomConstraint(With6989)) rule6989 = ReplacementRule(pattern6989, replacement6989) pattern6990 = Pattern(Integral(u_*x_**m_, x_), cons369) rule6990 = ReplacementRule(pattern6990, With6990) pattern6991 = Pattern(Integral(u_, x_), cons2036, CustomConstraint(With6991)) rule6991 = ReplacementRule(pattern6991, replacement6991) pattern6992 = Pattern(Integral(S(1)/(a_ + v_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons69) rule6992 = ReplacementRule(pattern6992, replacement6992) pattern6993 = Pattern(Integral(S(1)/(a_ + v_**n_*WC('b', S(1))), x_), cons2, cons3, cons1481, cons746) rule6993 = ReplacementRule(pattern6993, replacement6993) pattern6994 = Pattern(Integral(S(1)/(a_ + v_**n_*WC('b', S(1))), x_), cons2, cons3, cons1484, cons167) rule6994 = ReplacementRule(pattern6994, replacement6994) pattern6995 = Pattern(Integral(v_/(a_ + u_**WC('n', S(1))*WC('b', S(1))), x_), cons2, cons3, cons150, cons2037) rule6995 = ReplacementRule(pattern6995, replacement6995) pattern6996 = Pattern(Integral(u_, x_), CustomConstraint(With6996)) rule6996 = ReplacementRule(pattern6996, replacement6996) pattern6997 = Pattern(Integral(u_, x_), CustomConstraint(With6997)) rule6997 = ReplacementRule(pattern6997, replacement6997) pattern6998 = Pattern(Integral((x_**WC('m', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(x_**WC('n', S(1))*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons52, cons2038, cons1678, cons1257, cons2039) rule6998 = ReplacementRule(pattern6998, replacement6998) pattern6999 = Pattern(Integral(u_*(a_ + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons47, cons349) rule6999 = ReplacementRule(pattern6999, replacement6999) pattern7000 = Pattern(Integral(u_, x_), CustomConstraint(With7000)) rule7000 = ReplacementRule(pattern7000, replacement7000) pattern7001 = Pattern(Integral(u_, x_)) rule7001 = ReplacementRule(pattern7001, replacement7001) return [rule6934, rule6935, rule6936, rule6937, rule6938, rule6939, rule6940, rule6941, rule6942, rule6943, rule6944, rule6945, rule6946, rule6947, rule6948, rule6949, rule6950, rule6951, rule6952, rule6953, rule6954, rule6955, rule6956, rule6957, rule6958, rule6959, rule6960, rule6961, rule6962, rule6963, rule6964, rule6965, rule6966, rule6967, rule6968, rule6969, rule6970, rule6971, rule6972, rule6973, rule6974, rule6975, rule6976, rule6977, rule6978, rule6979, rule6980, rule6981, rule6982, rule6983, rule6984, rule6985, rule6986, rule6987, rule6988, rule6989, rule6990, rule6991, rule6992, rule6993, rule6994, rule6995, rule6996, rule6997, rule6998, rule6999, rule7000, rule7001, ] def replacement6934(a, b, c, n, p, u, x): return Dist(c**IntPart(p)*(c*(a + b*x)**n)**FracPart(p)*(a + b*x)**(-n*FracPart(p)), Int(u*(a + b*x)**(n*p), x), x) def replacement6935(a, b, c, d, p, q, u, x): return Dist((c*(d*(a + b*x))**p)**q*(a + b*x)**(-p*q), Int(u*(a + b*x)**(p*q), x), x) def replacement6936(a, b, c, d, n, p, q, u, x): return Dist((c*(d*(a + b*x)**n)**p)**q*(a + b*x)**(-n*p*q), Int(u*(a + b*x)**(n*p*q), x), x) def replacement6937(A, B, C, F, a, b, c, d, e, f, g, n, x): return Dist(g/C, Subst(Int((a + b*F(c*x))**n/x, x), x, sqrt(d + e*x)/sqrt(f + g*x)), x) def replacement6938(A, C, F, a, b, c, e, g, n, x): return Dist(g/C, Subst(Int((a + b*F(c*x))**n/x, x), x, sqrt(e*x + S(1))/sqrt(g*x + S(1))), x) def replacement6939(A, B, C, F, a, b, c, d, e, f, g, n, x): return Dist(g/C, Subst(Int((F**(c*x)*b + a)**n/x, x), x, sqrt(d + e*x)/sqrt(f + g*x)), x) def replacement6940(A, C, F, a, b, c, e, g, n, x): return Dist(g/C, Subst(Int((F**(c*x)*b + a)**n/x, x), x, sqrt(e*x + S(1))/sqrt(g*x + S(1))), x) def With6941(u, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6941(u, x, y): q = DerivativeDivides(y, u, x) return Simp(q*log(RemoveContent(y, x)), x) def With6942(u, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(w*y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6942(u, w, x, y): q = DerivativeDivides(w*y, u, x) return Simp(q*log(RemoveContent(w*y, x)), x) def With6943(m, u, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6943(m, u, x, y): q = DerivativeDivides(y, u, x) return Simp(q*y**(m + S(1))/(m + S(1)), x) def With6944(m, n, u, x, y, z): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y*z, u*z**(-m + n), x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6944(m, n, u, x, y, z): q = DerivativeDivides(y*z, u*z**(-m + n), x) return Simp(q*y**(m + S(1))*z**(m + S(1))/(m + S(1)), x) def With6945(u, x): if isinstance(x, (int, Integer, float, Float)): return False v = SimplifyIntegrand(u, x) if SimplerIntegrandQ(v, u, x): return True return False def replacement6945(u, x): v = SimplifyIntegrand(u, x) return Int(v, x) def replacement6946(a, b, c, d, e, f, m, n, u, x): return Dist((a*e**S(2) - c*f**S(2))**m, Int(ExpandIntegrand(u*(e*sqrt(a + b*x**n) - f*sqrt(c + d*x**n))**(-m), x), x), x) def replacement6947(a, b, c, d, e, f, m, n, u, x): return Dist((b*e**S(2) - d*f**S(2))**m, Int(ExpandIntegrand(u*x**(m*n)*(e*sqrt(a + b*x**n) - f*sqrt(c + d*x**n))**(-m), x), x), x) def replacement6948(a, m, n, p, u, v, w, x): return Int(u**(m + n*p)*w*(a + u**(-n)*v)**p, x) def With6949(a, b, c, d, m, n, u, v, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6949(a, b, c, d, m, n, u, v, x, y): q = DerivativeDivides(y, u, x) return Dist(q, Subst(Int((a + b*x)**m*(c + d*x)**n, x), x, y), x) def With6950(a, b, c, d, e, f, m, n, p, u, v, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6950(a, b, c, d, e, f, m, n, p, u, v, w, x, y): q = DerivativeDivides(y, u, x) return Dist(q, Subst(Int((a + b*x)**m*(c + d*x)**n*(e + f*x)**p, x), x, y), x) def With6951(a, b, c, d, e, f, g, h, m, n, p, q, u, v, w, x, y, z): if isinstance(x, (int, Integer, float, Float)): return False try: r = DerivativeDivides(y, u, x) res = Not(FalseQ(r)) except (TypeError, AttributeError): return False if res: return True return False def replacement6951(a, b, c, d, e, f, g, h, m, n, p, q, u, v, w, x, y, z): r = DerivativeDivides(y, u, x) return Dist(r, Subst(Int((a + b*x)**m*(c + d*x)**n*(e + f*x)**p*(g + h*x)**q, x), x, y), x) def With6952(a, b, n, u, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6952(a, b, n, u, x, y): q = DerivativeDivides(y, u, x) return Dist(a, Int(u, x), x) + Dist(b*q, Subst(Int(x**n, x), x, y), x) def With6953(a, b, n, p, u, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6953(a, b, n, p, u, x, y): q = DerivativeDivides(y, u, x) return Dist(q, Subst(Int((a + b*x**n)**p, x), x, y), x) def With6954(a, b, m, n, p, u, v, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = Symbol('q') r = Symbol('r') r = Divides(y**m, v**m, x) q = DerivativeDivides(y, u, x) res = And(Not(FalseQ(Set(r, Divides(y**m, v**m, x)))), Not(FalseQ(Set(q, DerivativeDivides(y, u, x))))) except (TypeError, AttributeError): return False if res: return True return False def replacement6954(a, b, m, n, p, u, v, x, y): q = Symbol('q') r = Symbol('r') r = Divides(y**m, v**m, x) q = DerivativeDivides(y, u, x) return Dist(q*r, Subst(Int(x**m*(a + b*x**n)**p, x), x, y), x) def With6955(a, b, c, n, n2, p, u, v, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6955(a, b, c, n, n2, p, u, v, x, y): q = DerivativeDivides(y, u, x) return Dist(q, Subst(Int((a + b*x**n + c*x**(S(2)*n))**p, x), x, y), x) def With6956(A, B, a, b, c, n, n2, p, u, v, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6956(A, B, a, b, c, n, n2, p, u, v, w, x, y): q = DerivativeDivides(y, u, x) return Dist(q, Subst(Int((A + B*x**n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, y), x) def With6957(A, B, a, c, n, n2, p, u, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6957(A, B, a, c, n, n2, p, u, w, x, y): q = DerivativeDivides(y, u, x) return Dist(q, Subst(Int((A + B*x**n)*(a + c*x**(S(2)*n))**p, x), x, y), x) def With6958(a, b, c, m, n, n2, p, u, v, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = Symbol('q') r = Symbol('r') r = Divides(y**m, v**m, x) q = DerivativeDivides(y, u, x) res = And(Not(FalseQ(Set(r, Divides(y**m, v**m, x)))), Not(FalseQ(Set(q, DerivativeDivides(y, u, x))))) except (TypeError, AttributeError): return False if res: return True return False def replacement6958(a, b, c, m, n, n2, p, u, v, w, x, y): q = Symbol('q') r = Symbol('r') r = Divides(y**m, v**m, x) q = DerivativeDivides(y, u, x) return Dist(q*r, Subst(Int(x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x, y), x) def With6959(A, B, a, b, c, m, n, n2, p, u, v, w, x, y, z): if isinstance(x, (int, Integer, float, Float)): return False try: q = Symbol('q') r = Symbol('r') r = Divides(y**m, z**m, x) q = DerivativeDivides(y, u, x) res = And(Not(FalseQ(Set(r, Divides(y**m, z**m, x)))), Not(FalseQ(Set(q, DerivativeDivides(y, u, x))))) except (TypeError, AttributeError): return False if res: return True return False def replacement6959(A, B, a, b, c, m, n, n2, p, u, v, w, x, y, z): q = Symbol('q') r = Symbol('r') r = Divides(y**m, z**m, x) q = DerivativeDivides(y, u, x) return Dist(q*r, Subst(Int(x**m*(A + B*x**n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x, y), x) def With6960(A, B, a, c, m, n, n2, p, u, w, x, y, z): if isinstance(x, (int, Integer, float, Float)): return False try: q = Symbol('q') r = Symbol('r') r = Divides(y**m, z**m, x) q = DerivativeDivides(y, u, x) res = And(Not(FalseQ(Set(r, Divides(y**m, z**m, x)))), Not(FalseQ(Set(q, DerivativeDivides(y, u, x))))) except (TypeError, AttributeError): return False if res: return True return False def replacement6960(A, B, a, c, m, n, n2, p, u, w, x, y, z): q = Symbol('q') r = Symbol('r') r = Divides(y**m, z**m, x) q = DerivativeDivides(y, u, x) return Dist(q*r, Subst(Int(x**m*(A + B*x**n)*(a + c*x**(S(2)*n))**p, x), x, y), x) def With6961(a, b, c, d, m, n, p, u, v, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(y, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6961(a, b, c, d, m, n, p, u, v, x, y): q = DerivativeDivides(y, u, x) return Dist(q, Subst(Int((a + b*x**n)**m*(c + d*x**n)**p, x), x, y), x) def With6962(a, b, c, d, e, f, m, n, p, q, u, v, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: r = DerivativeDivides(y, u, x) res = Not(FalseQ(r)) except (TypeError, AttributeError): return False if res: return True return False def replacement6962(a, b, c, d, e, f, m, n, p, q, u, v, w, x, y): r = DerivativeDivides(y, u, x) return Dist(r, Subst(Int((a + b*x**n)**m*(c + d*x**n)**p*(e + f*x**n)**q, x), x, y), x) def With6963(F, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(v, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6963(F, u, v, x): q = DerivativeDivides(v, u, x) return Simp(F**v*q/log(F), x) def With6964(F, m, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(v, u, x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement6964(F, m, u, v, w, x): q = DerivativeDivides(v, u, x) return Dist(q, Subst(Int(F**x*x**m, x), x, v), x) def With6965(a, b, m, p, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False c = u/(v*D(w, x) + w*D(v, x)) if FreeQ(c, x): return True return False def replacement6965(a, b, m, p, u, v, w, x): c = u/(v*D(w, x) + w*D(v, x)) return Dist(c, Subst(Int((a + b*x**p)**m, x), x, v*w), x) def With6966(a, b, m, p, q, r, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False c = u/(p*w*D(v, x) + q*v*D(w, x)) if FreeQ(c, x): return True return False def replacement6966(a, b, m, p, q, r, u, v, w, x): c = u/(p*w*D(v, x) + q*v*D(w, x)) return Dist(c*p/(r + S(1)), Subst(Int((a + b*x**(p/(r + S(1))))**m, x), x, v**(r + S(1))*w), x) def With6967(a, b, m, p, q, r, s, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False c = u/(p*w*D(v, x) + q*v*D(w, x)) if FreeQ(c, x): return True return False def replacement6967(a, b, m, p, q, r, s, u, v, w, x): c = u/(p*w*D(v, x) + q*v*D(w, x)) return Dist(c*p/(r + S(1)), Subst(Int((a + b*x**(p/(r + S(1))))**m, x), x, v**(r + S(1))*w**(s + S(1))), x) def With6968(a, b, m, p, q, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False c = u/(p*w*D(v, x) - q*v*D(w, x)) if FreeQ(c, x): return True return False def replacement6968(a, b, m, p, q, u, v, w, x): c = u/(p*w*D(v, x) - q*v*D(w, x)) return Dist(c*p, Subst(Int((a*x**p + b)**m, x), x, v*w**(m*q + S(1))), x) def With6969(a, b, m, p, q, r, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False c = u/(p*w*D(v, x) - q*v*D(w, x)) if FreeQ(c, x): return True return False def replacement6969(a, b, m, p, q, r, u, v, w, x): c = u/(p*w*D(v, x) - q*v*D(w, x)) return -Dist(c*q, Subst(Int((a + b*x**q)**m, x), x, v**(m*p + r + S(1))*w), x) def With6970(a, b, m, p, q, s, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False c = u/(p*w*D(v, x) - q*v*D(w, x)) if FreeQ(c, x): return True return False def replacement6970(a, b, m, p, q, s, u, v, w, x): c = u/(p*w*D(v, x) - q*v*D(w, x)) return -Dist(c*q/(s + S(1)), Subst(Int((a + b*x**(q/(s + S(1))))**m, x), x, v**(m*p + S(1))*w**(s + S(1))), x) def With6971(a, b, m, p, q, r, s, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False c = u/(p*w*D(v, x) - q*v*D(w, x)) if FreeQ(c, x): return True return False def replacement6971(a, b, m, p, q, r, s, u, v, w, x): c = u/(p*w*D(v, x) - q*v*D(w, x)) return -Dist(c*q/(s + S(1)), Subst(Int((a + b*x**(q/(s + S(1))))**m, x), x, v**(m*p + r + S(1))*w**(s + S(1))), x) def replacement6972(m, u, x): return Dist(S(1)/(m + S(1)), Subst(Int(SubstFor(x**(m + S(1)), u, x), x), x, x**(m + S(1))), x) def With6973(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = SubstForFractionalPowerOfLinear(u, x) res = And(Not(FalseQ(lst)), SubstForFractionalPowerQ(u, Part(lst, S(3)), x)) except (TypeError, AttributeError): return False if res: return True return False def replacement6973(u, x): lst = SubstForFractionalPowerOfLinear(u, x) return Dist(Part(lst, S(2))*Part(lst, S(4)), Subst(Int(Part(lst, S(1)), x), x, Part(lst, S(3))**(S(1)/Part(lst, S(2)))), x) def With6974(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = SubstForFractionalPowerOfQuotientOfLinears(u, x) res = Not(FalseQ(lst)) except (TypeError, AttributeError): return False if res: return True return False def replacement6974(u, x): lst = SubstForFractionalPowerOfQuotientOfLinears(u, x) return Dist(Part(lst, S(2))*Part(lst, S(4)), Subst(Int(Part(lst, S(1)), x), x, Part(lst, S(3))**(S(1)/Part(lst, S(2)))), x) def replacement6975(a, m, n, p, q, u, v, w, x, z): return Dist(a**IntPart(p)*v**(-m*FracPart(p))*w**(-n*FracPart(p))*z**(-q*FracPart(p))*(a*v**m*w**n*z**q)**FracPart(p), Int(u*v**(m*p)*w**(n*p)*z**(p*q), x), x) def replacement6976(a, m, n, p, u, v, w, x): return Dist(a**IntPart(p)*v**(-m*FracPart(p))*w**(-n*FracPart(p))*(a*v**m*w**n)**FracPart(p), Int(u*v**(m*p)*w**(n*p), x), x) def replacement6977(a, m, p, u, v, x): return Dist(a**IntPart(p)*v**(-m*FracPart(p))*(a*v**m)**FracPart(p), Int(u*v**(m*p), x), x) def replacement6978(a, b, n, p, u, x): return Dist(FullSimplify(x**(-n/S(2))*sqrt(a + b*x**n)/sqrt(a*x**(-n) + b)), Int(u*x**(n*p)*(a*x**(-n) + b)**p, x), x) def replacement6979(a, b, n, p, u, v, x): return Dist(v**(-n*FracPart(p))*(a + b*v**n)**FracPart(p)*(a*v**(-n) + b)**(-FracPart(p)), Int(u*v**(n*p)*(a*v**(-n) + b)**p, x), x) def replacement6980(a, b, m, n, p, u, v, x): return Dist(v**(-n*FracPart(p))*(a + b*v**n*x**m)**FracPart(p)*(a*v**(-n) + b*x**m)**(-FracPart(p)), Int(u*v**(n*p)*(a*v**(-n) + b*x**m)**p, x), x) def With6981(a, b, m, r, s, u, x): if isinstance(x, (int, Integer, float, Float)): return False v = x**(-r*FracPart(m))*(a + b*x**(-r + s))**(-FracPart(m))*(a*x**r + b*x**s)**FracPart(m) if Not(EqQ(v, S(1))): return True return False def replacement6981(a, b, m, r, s, u, x): v = x**(-r*FracPart(m))*(a + b*x**(-r + s))**(-FracPart(m))*(a*x**r + b*x**s)**FracPart(m) return Dist(v, Int(u*x**(m*r)*(a + b*x**(-r + s))**m, x), x) def With6982(a, b, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False v = RationalFunctionExpand(u/(a + b*x**n), x) if SumQ(v): return True return False def replacement6982(a, b, n, u, x): v = RationalFunctionExpand(u/(a + b*x**n), x) return Int(v, x) def replacement6983(a, b, c, n, n2, p, u, x): return Dist(S(4)**(-p)*c**(-p), Int(u*(b + S(2)*c*x**n)**(S(2)*p), x), x) def replacement6984(a, b, c, n, n2, p, u, x): return Dist((b + S(2)*c*x**n)**(-S(2)*p)*(a + b*x**n + c*x**(S(2)*n))**p, Int(u*(b + S(2)*c*x**n)**(S(2)*p), x), x) def With6985(a, b, c, n, n2, u, x): if isinstance(x, (int, Integer, float, Float)): return False v = RationalFunctionExpand(u/(a + b*x**n + c*x**(S(2)*n)), x) if SumQ(v): return True return False def replacement6985(a, b, c, n, n2, u, x): v = RationalFunctionExpand(u/(a + b*x**n + c*x**(S(2)*n)), x) return Int(v, x) def replacement6986(a, b, c, m, n, u, x): return Int(u*(a*x**m - b*sqrt(c*x**n))/(a**S(2)*x**(S(2)*m) - b**S(2)*c*x**n), x) def With6987(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = FunctionOfLinear(u, x) res = Not(FalseQ(lst)) except (TypeError, AttributeError): return False if res: return True return False def replacement6987(u, x): lst = FunctionOfLinear(u, x) return Dist(S(1)/Part(lst, S(3)), Subst(Int(Part(lst, S(1)), x), x, x*Part(lst, S(3)) + Part(lst, S(2))), x) def With6988(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = PowerVariableExpn(u, S(0), x) res = And(Not(FalseQ(lst)), NonzeroQ(Part(lst, S(2)))) except (TypeError, AttributeError): return False if res: return True return False def replacement6988(u, x): lst = PowerVariableExpn(u, S(0), x) return Dist(S(1)/Part(lst, S(2)), Subst(Int(NormalizeIntegrand(Part(lst, S(1))/x, x), x), x, (x*Part(lst, S(3)))**Part(lst, S(2))), x) def With6989(m, u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = PowerVariableExpn(u, m + S(1), x) res = And(Not(FalseQ(lst)), NonzeroQ(-m + Part(lst, S(2)) + S(-1))) except (TypeError, AttributeError): return False if res: return True return False def replacement6989(m, u, x): lst = PowerVariableExpn(u, m + S(1), x) return Dist(S(1)/Part(lst, S(2)), Subst(Int(NormalizeIntegrand(Part(lst, S(1))/x, x), x), x, (x*Part(lst, S(3)))**Part(lst, S(2))), x) def With6990(m, u, x): k = Denominator(m) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*ReplaceAll(u, Rule(x, x**k)), x), x, x**(S(1)/k)), x) def With6991(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = FunctionOfSquareRootOfQuadratic(u, x) res = Not(FalseQ(lst)) except (TypeError, AttributeError): return False if res: return True return False def replacement6991(u, x): lst = FunctionOfSquareRootOfQuadratic(u, x) return Dist(S(2), Subst(Int(Part(lst, S(1)), x), x, Part(lst, S(2))), x) def replacement6992(a, b, v, x): return Dist(S(1)/(S(2)*a), Int(Together(S(1)/(-v/Rt(-a/b, S(2)) + S(1))), x), x) + Dist(S(1)/(S(2)*a), Int(Together(S(1)/(v/Rt(-a/b, S(2)) + S(1))), x), x) def replacement6993(a, b, n, v, x): return Dist(S(2)/(a*n), Sum_doit(Int(Together(S(1)/(S(1) - (S(-1))**(-S(4)*k/n)*v**S(2)/Rt(-a/b, n/S(2)))), x), List(k, S(1), n/S(2))), x) def replacement6994(a, b, n, v, x): return Dist(S(1)/(a*n), Sum_doit(Int(Together(S(1)/(S(1) - (S(-1))**(-S(2)*k/n)*v/Rt(-a/b, n))), x), List(k, S(1), n)), x) def replacement6995(a, b, n, u, v, x): return Int(ReplaceAll(ExpandIntegrand(PolynomialInSubst(v, u, x)/(a + b*x**n), x), Rule(x, u)), x) def With6996(u, x): if isinstance(x, (int, Integer, float, Float)): return False v = NormalizeIntegrand(u, x) if UnsameQ(v, u): return True return False def replacement6996(u, x): v = NormalizeIntegrand(u, x) return Int(v, x) def With6997(u, x): if isinstance(x, (int, Integer, float, Float)): return False v = ExpandIntegrand(u, x) if SumQ(v): return True return False def replacement6997(u, x): v = ExpandIntegrand(u, x) return Int(v, x) def replacement6998(a, b, c, d, m, n, p, q, u, x): return Dist(x**(-m*p)*(a + b*x**m)**p*(c + d*x**n)**q, Int(u*x**(m*p), x), x) def replacement6999(a, b, c, n, n2, p, u, x): return Dist((S(4)*c)**(S(1)/2 - p)*sqrt(a + b*x**n + c*x**(S(2)*n))/(b + S(2)*c*x**n), Int(u*(b + S(2)*c*x**n)**(S(2)*p), x), x) def With7000(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: lst = SubstForFractionalPowerOfLinear(u, x) res = Not(FalseQ(lst)) except (TypeError, AttributeError): return False if res: return True return False def replacement7000(u, x): lst = SubstForFractionalPowerOfLinear(u, x) return Dist(Part(lst, S(2))*Part(lst, S(4)), Subst(Int(Part(lst, S(1)), x), x, Part(lst, S(3))**(S(1)/Part(lst, S(2)))), x) def replacement7001(u, x): return Int(u, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/miscellaneous_trig.py000066400000000000000000005615211412543434000254430ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def miscellaneous_trig(): from sympy.integrals.rubi.constraints import cons1648, cons21, cons2, cons3, cons8, cons29, cons19, cons4, cons36, cons37, cons38, cons1649, cons1650, cons1651, cons1652, cons1653, cons1654, cons1655, cons27, cons1656, cons1410, cons210, cons40, cons50, cons127, cons149, cons345, cons5, cons242, cons246, cons1335, cons139, cons1657, cons1290, cons168, cons321, cons1658, cons33, cons251, cons96, cons255, cons13, cons165, cons248, cons1280, cons1659, cons1660, cons1661, cons172, cons1662, cons1663, cons95, cons91, cons1664, cons164, cons90, cons1665, cons1666, cons87, cons130, cons1481, cons746, cons1484, cons1667, cons25, cons1668, cons1669, cons1670, cons1671, cons1249, cons1672, cons1673, cons1674, cons1675, cons557, cons1676, cons630, cons10, cons1677, cons1678, cons1679, cons68, cons1232, cons378, cons51, cons52, cons53, cons54, cons1680, cons1441, cons1681, cons1682, cons1683, cons1684, cons64, cons586, cons466, cons1685, cons170, cons1686, cons1687, cons1688, cons1689, cons1690, cons814, cons815, cons20, cons1691, cons1692, cons1693, cons1694, cons1101, cons1695, cons89, cons167, cons1696, cons1697, cons1397, cons1698, cons1444, cons1699, cons1504, cons965, cons1700, cons1646, cons1701, cons198, cons1702, cons1013, cons152, cons1553, cons1703, cons1704, cons211, cons226, cons1705, cons812, cons813, cons150, cons530, cons1706, cons1707, cons1708, cons1709, cons1710, cons56, cons1711, cons1712, cons148, cons1713, cons1507, cons1714, cons1715, cons1716, cons1717, cons1718, cons1719, cons1720, cons1721, cons1647, cons1722, cons1723, cons1724, cons1725, cons1726, cons340, cons55, cons629, cons73, cons1727, cons1728, cons1729, cons1730, cons1362, cons1480, cons465, cons1731, cons1732, cons1733, cons1734, cons1267, cons1269, cons1476, cons1483, cons1735 pattern4688 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1648, cons21) rule4688 = ReplacementRule(pattern4688, replacement4688) pattern4689 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1648, cons21) rule4689 = ReplacementRule(pattern4689, replacement4689) pattern4690 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1648, cons21) rule4690 = ReplacementRule(pattern4690, replacement4690) pattern4691 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1648, cons21) rule4691 = ReplacementRule(pattern4691, replacement4691) pattern4692 = Pattern(Integral(u_*(WC('c', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1648) rule4692 = ReplacementRule(pattern4692, replacement4692) pattern4693 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1648) rule4693 = ReplacementRule(pattern4693, replacement4693) pattern4694 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1648) rule4694 = ReplacementRule(pattern4694, replacement4694) pattern4695 = Pattern(Integral(u_*(WC('c', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1648) rule4695 = ReplacementRule(pattern4695, replacement4695) pattern4696 = Pattern(Integral(u_*(WC('c', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1648) rule4696 = ReplacementRule(pattern4696, replacement4696) pattern4697 = Pattern(Integral(u_*(WC('c', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons1648) rule4697 = ReplacementRule(pattern4697, replacement4697) pattern4698 = Pattern(Integral(u_*(WC('c', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons1648) rule4698 = ReplacementRule(pattern4698, replacement4698) pattern4699 = Pattern(Integral(u_*(A_ + WC('B', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons1648) rule4699 = ReplacementRule(pattern4699, replacement4699) pattern4700 = Pattern(Integral(u_*(A_ + WC('B', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons1648) rule4700 = ReplacementRule(pattern4700, replacement4700) pattern4701 = Pattern(Integral((WC('c', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons4, cons1648) rule4701 = ReplacementRule(pattern4701, replacement4701) pattern4702 = Pattern(Integral((WC('c', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons4, cons1648) rule4702 = ReplacementRule(pattern4702, replacement4702) pattern4703 = Pattern(Integral((WC('c', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('C', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons38, cons4, cons1648) rule4703 = ReplacementRule(pattern4703, replacement4703) pattern4704 = Pattern(Integral((WC('c', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('C', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons38, cons4, cons1648) rule4704 = ReplacementRule(pattern4704, replacement4704) pattern4705 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons37, cons38, cons1648) rule4705 = ReplacementRule(pattern4705, replacement4705) pattern4706 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons37, cons38, cons1648) rule4706 = ReplacementRule(pattern4706, replacement4706) pattern4707 = Pattern(Integral(u_*(A_ + WC('C', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons38, cons1648) rule4707 = ReplacementRule(pattern4707, replacement4707) pattern4708 = Pattern(Integral(u_*(A_ + WC('C', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons38, cons1648) rule4708 = ReplacementRule(pattern4708, replacement4708) pattern4709 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons38, cons1649) rule4709 = ReplacementRule(pattern4709, replacement4709) pattern4710 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons38, cons1649) rule4710 = ReplacementRule(pattern4710, replacement4710) pattern4711 = Pattern(Integral(u_*(WC('A', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)) + WC('B', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**n1_ + WC('C', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**n2_), x_), cons2, cons3, cons36, cons37, cons38, cons4, cons1650, cons1651) rule4711 = ReplacementRule(pattern4711, replacement4711) pattern4712 = Pattern(Integral(u_*(WC('A', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)) + WC('B', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**n1_ + WC('C', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**n2_), x_), cons2, cons3, cons36, cons37, cons38, cons4, cons1650, cons1651) rule4712 = ReplacementRule(pattern4712, replacement4712) pattern4713 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1652) rule4713 = ReplacementRule(pattern4713, replacement4713) pattern4714 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1653) rule4714 = ReplacementRule(pattern4714, replacement4714) pattern4715 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1652) rule4715 = ReplacementRule(pattern4715, replacement4715) pattern4716 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1653) rule4716 = ReplacementRule(pattern4716, replacement4716) pattern4717 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons1652) rule4717 = ReplacementRule(pattern4717, replacement4717) pattern4718 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons1653) rule4718 = ReplacementRule(pattern4718, replacement4718) pattern4719 = Pattern(Integral(u_*(A_ + WC('B', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons1652) rule4719 = ReplacementRule(pattern4719, replacement4719) pattern4720 = Pattern(Integral(u_*(A_ + WC('B', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons1653) rule4720 = ReplacementRule(pattern4720, replacement4720) pattern4721 = Pattern(Integral((WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons4, cons1652) rule4721 = ReplacementRule(pattern4721, replacement4721) pattern4722 = Pattern(Integral((WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons4, cons1653) rule4722 = ReplacementRule(pattern4722, replacement4722) pattern4723 = Pattern(Integral((WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('C', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons38, cons4, cons1652) rule4723 = ReplacementRule(pattern4723, replacement4723) pattern4724 = Pattern(Integral((WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('C', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons38, cons4, cons1653) rule4724 = ReplacementRule(pattern4724, replacement4724) pattern4725 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons37, cons38, cons1652) rule4725 = ReplacementRule(pattern4725, replacement4725) pattern4726 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons37, cons38, cons1653) rule4726 = ReplacementRule(pattern4726, replacement4726) pattern4727 = Pattern(Integral(u_*(A_ + WC('C', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons38, cons1652) rule4727 = ReplacementRule(pattern4727, replacement4727) pattern4728 = Pattern(Integral(u_*(A_ + WC('C', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons38, cons1653) rule4728 = ReplacementRule(pattern4728, replacement4728) pattern4729 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons38, cons1649) rule4729 = ReplacementRule(pattern4729, replacement4729) pattern4730 = Pattern(Integral(u_*(WC('A', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)) + WC('B', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**n1_ + WC('C', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**n2_), x_), cons2, cons3, cons36, cons37, cons38, cons4, cons1650, cons1651) rule4730 = ReplacementRule(pattern4730, replacement4730) pattern4731 = Pattern(Integral(u_*((S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**n1_*WC('B', S(1)) + (S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**n2_*WC('C', S(1)) + (S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*WC('A', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons4, cons1650, cons1651) rule4731 = ReplacementRule(pattern4731, replacement4731) pattern4732 = Pattern(Integral(u_*(WC('c', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1654) rule4732 = ReplacementRule(pattern4732, replacement4732) pattern4733 = Pattern(Integral(u_*(WC('c', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1654) rule4733 = ReplacementRule(pattern4733, replacement4733) pattern4734 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1654, cons21) rule4734 = ReplacementRule(pattern4734, replacement4734) pattern4735 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1654, cons21) rule4735 = ReplacementRule(pattern4735, replacement4735) pattern4736 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1654, cons21) rule4736 = ReplacementRule(pattern4736, replacement4736) pattern4737 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('d', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1654, cons21) rule4737 = ReplacementRule(pattern4737, replacement4737) pattern4738 = Pattern(Integral(u_*(WC('c', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1654) rule4738 = ReplacementRule(pattern4738, replacement4738) pattern4739 = Pattern(Integral(u_*(WC('c', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1654) rule4739 = ReplacementRule(pattern4739, replacement4739) pattern4740 = Pattern(Integral(u_*(WC('c', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1654) rule4740 = ReplacementRule(pattern4740, replacement4740) pattern4741 = Pattern(Integral(u_*(WC('c', S(1))/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons19, cons21, cons1654) rule4741 = ReplacementRule(pattern4741, replacement4741) pattern4742 = Pattern(Integral(u_*(WC('c', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons1654) rule4742 = ReplacementRule(pattern4742, replacement4742) pattern4743 = Pattern(Integral(u_*(WC('c', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons1654) rule4743 = ReplacementRule(pattern4743, replacement4743) pattern4744 = Pattern(Integral(u_*(A_ + WC('B', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons1654) rule4744 = ReplacementRule(pattern4744, replacement4744) pattern4745 = Pattern(Integral(u_*(A_ + WC('B', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons36, cons37, cons1654) rule4745 = ReplacementRule(pattern4745, replacement4745) pattern4746 = Pattern(Integral((WC('c', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons4, cons1654) rule4746 = ReplacementRule(pattern4746, replacement4746) pattern4747 = Pattern(Integral((WC('c', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons38, cons4, cons1654) rule4747 = ReplacementRule(pattern4747, replacement4747) pattern4748 = Pattern(Integral((WC('c', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('C', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons38, cons4, cons1654) rule4748 = ReplacementRule(pattern4748, replacement4748) pattern4749 = Pattern(Integral((WC('c', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(A_ + WC('C', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2))*WC('u', S(1)), x_), cons2, cons3, cons8, cons36, cons38, cons4, cons1654) rule4749 = ReplacementRule(pattern4749, replacement4749) pattern4750 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons37, cons38, cons1654) rule4750 = ReplacementRule(pattern4750, replacement4750) pattern4751 = Pattern(Integral(u_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))) + WC('C', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons37, cons38, cons1654) rule4751 = ReplacementRule(pattern4751, replacement4751) pattern4752 = Pattern(Integral(u_*(A_ + WC('C', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons38, cons1654) rule4752 = ReplacementRule(pattern4752, replacement4752) pattern4753 = Pattern(Integral(u_*(A_ + WC('C', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)), x_), cons2, cons3, cons36, cons38, cons1654) rule4753 = ReplacementRule(pattern4753, replacement4753) pattern4754 = Pattern(Integral(u_*((S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**n1_*WC('B', S(1)) + (S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**n2_*WC('C', S(1)) + (S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*WC('A', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons4, cons1650, cons1651) rule4754 = ReplacementRule(pattern4754, replacement4754) pattern4755 = Pattern(Integral(u_*((S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**n1_*WC('B', S(1)) + (S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**n2_*WC('C', S(1)) + (S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*WC('A', S(1))), x_), cons2, cons3, cons36, cons37, cons38, cons4, cons1650, cons1651) rule4755 = ReplacementRule(pattern4755, replacement4755) pattern4756 = Pattern(Integral(sin(x_*WC('b', S(1)) + WC('a', S(0)))*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1655) rule4756 = ReplacementRule(pattern4756, replacement4756) pattern4757 = Pattern(Integral(cos(x_*WC('b', S(1)) + WC('a', S(0)))*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1655) rule4757 = ReplacementRule(pattern4757, replacement4757) pattern4758 = Pattern(Integral(sin(x_*WC('b', S(1)) + WC('a', S(0)))*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1655) rule4758 = ReplacementRule(pattern4758, replacement4758) pattern4759 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons210, cons27, cons1656, cons1410) rule4759 = ReplacementRule(pattern4759, replacement4759) pattern4760 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons210, cons27, cons1656, cons1410) rule4760 = ReplacementRule(pattern4760, replacement4760) pattern4761 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons27, cons1656, cons40) rule4761 = ReplacementRule(pattern4761, replacement4761) pattern4762 = Pattern(Integral((WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons4, cons27, cons1656, cons40) rule4762 = ReplacementRule(pattern4762, replacement4762) pattern4763 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons19, cons5, cons27, cons1656, cons149, cons345) rule4763 = ReplacementRule(pattern4763, replacement4763) pattern4764 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons19, cons5, cons27, cons1656, cons149, cons345) rule4764 = ReplacementRule(pattern4764, replacement4764) pattern4765 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons19, cons5, cons27, cons1656, cons149, cons242) rule4765 = ReplacementRule(pattern4765, replacement4765) pattern4766 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons19, cons5, cons27, cons1656, cons149, cons242) rule4766 = ReplacementRule(pattern4766, replacement4766) pattern4767 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons27, cons1656, cons149, cons246, cons1335, cons139, cons1657, cons1290) rule4767 = ReplacementRule(pattern4767, replacement4767) pattern4768 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons27, cons1656, cons149, cons246, cons1335, cons139, cons1657, cons1290) rule4768 = ReplacementRule(pattern4768, replacement4768) pattern4769 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons27, cons1656, cons149, cons246, cons168, cons139, cons321, cons1658, cons1290) rule4769 = ReplacementRule(pattern4769, replacement4769) pattern4770 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons27, cons1656, cons149, cons246, cons168, cons139, cons321, cons1658, cons1290) rule4770 = ReplacementRule(pattern4770, replacement4770) pattern4771 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons5, cons27, cons1656, cons149, cons33, cons168, cons251, cons1290) rule4771 = ReplacementRule(pattern4771, replacement4771) pattern4772 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons5, cons27, cons1656, cons149, cons33, cons168, cons251, cons1290) rule4772 = ReplacementRule(pattern4772, replacement4772) pattern4773 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons5, cons27, cons1656, cons149, cons33, cons96, cons321, cons255, cons1290) rule4773 = ReplacementRule(pattern4773, replacement4773) pattern4774 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons5, cons27, cons1656, cons149, cons33, cons96, cons321, cons255, cons1290) rule4774 = ReplacementRule(pattern4774, replacement4774) pattern4775 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons210, cons27, cons1656, cons149, cons13, cons165, cons248) rule4775 = ReplacementRule(pattern4775, replacement4775) pattern4776 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons210, cons27, cons1656, cons149, cons13, cons165, cons248) rule4776 = ReplacementRule(pattern4776, replacement4776) pattern4777 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons210, cons27, cons1656, cons149, cons13, cons139, cons248) rule4777 = ReplacementRule(pattern4777, replacement4777) pattern4778 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons210, cons27, cons1656, cons149, cons13, cons139, cons248) rule4778 = ReplacementRule(pattern4778, replacement4778) pattern4779 = Pattern(Integral(cos(x_*WC('b', S(1)) + WC('a', S(0)))/sqrt(sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons27, cons1656) rule4779 = ReplacementRule(pattern4779, replacement4779) pattern4780 = Pattern(Integral(sin(x_*WC('b', S(1)) + WC('a', S(0)))/sqrt(sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons27, cons1656) rule4780 = ReplacementRule(pattern4780, replacement4780) pattern4781 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_/cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons210, cons5, cons27, cons1656, cons149, cons248) rule4781 = ReplacementRule(pattern4781, replacement4781) pattern4782 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_/sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons210, cons5, cons27, cons1656, cons149, cons248) rule4782 = ReplacementRule(pattern4782, replacement4782) pattern4783 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons19, cons5, cons27, cons1656, cons149) rule4783 = ReplacementRule(pattern4783, replacement4783) pattern4784 = Pattern(Integral((WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons210, cons4, cons5, cons27, cons1656, cons149) rule4784 = ReplacementRule(pattern4784, replacement4784) pattern4785 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2)*cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons210, cons27, cons1656, cons1410) rule4785 = ReplacementRule(pattern4785, replacement4785) pattern4786 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons27, cons1656, cons40) rule4786 = ReplacementRule(pattern4786, replacement4786) pattern4787 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons27, cons1656, cons149, cons1280) rule4787 = ReplacementRule(pattern4787, replacement4787) pattern4788 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons27, cons1656, cons149, cons1280) rule4788 = ReplacementRule(pattern4788, replacement4788) pattern4789 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons27, cons1656, cons149, cons1659, cons255) rule4789 = ReplacementRule(pattern4789, replacement4789) pattern4790 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons27, cons1656, cons149, cons246, cons1660, cons139, cons1661, cons172) rule4790 = ReplacementRule(pattern4790, replacement4790) pattern4791 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons27, cons1656, cons149, cons246, cons1660, cons139, cons1661, cons172) rule4791 = ReplacementRule(pattern4791, replacement4791) pattern4792 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons27, cons1656, cons149, cons246, cons168, cons139, cons1662, cons1661, cons172, cons1663) rule4792 = ReplacementRule(pattern4792, replacement4792) pattern4793 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons27, cons1656, cons149, cons246, cons168, cons139, cons1662, cons1661, cons172, cons1663) rule4793 = ReplacementRule(pattern4793, replacement4793) pattern4794 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons27, cons1656, cons149, cons95, cons168, cons91, cons1661, cons172) rule4794 = ReplacementRule(pattern4794, replacement4794) pattern4795 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons27, cons1656, cons149, cons95, cons168, cons91, cons1661, cons172) rule4795 = ReplacementRule(pattern4795, replacement4795) pattern4796 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons27, cons1656, cons149, cons33, cons168, cons1664, cons172) rule4796 = ReplacementRule(pattern4796, replacement4796) pattern4797 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons27, cons1656, cons149, cons33, cons168, cons1664, cons172) rule4797 = ReplacementRule(pattern4797, replacement4797) pattern4798 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons27, cons1656, cons149, cons164, cons96, cons90, cons165, cons1664, cons172) rule4798 = ReplacementRule(pattern4798, replacement4798) pattern4799 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons27, cons1656, cons149, cons164, cons96, cons90, cons165, cons1664, cons172) rule4799 = ReplacementRule(pattern4799, replacement4799) pattern4800 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons27, cons1656, cons149, cons164, cons96, cons90, cons139, cons1662, cons255, cons172) rule4800 = ReplacementRule(pattern4800, replacement4800) pattern4801 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons27, cons1656, cons149, cons164, cons96, cons90, cons139, cons1662, cons255, cons172) rule4801 = ReplacementRule(pattern4801, replacement4801) pattern4802 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons27, cons1656, cons149, cons33, cons96, cons1662, cons255, cons172) rule4802 = ReplacementRule(pattern4802, replacement4802) pattern4803 = Pattern(Integral((WC('e', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**m_*(WC('f', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons27, cons1656, cons149, cons33, cons96, cons1662, cons255, cons172) rule4803 = ReplacementRule(pattern4803, replacement4803) pattern4804 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*(WC('f', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons27, cons1656, cons149) rule4804 = ReplacementRule(pattern4804, replacement4804) pattern4805 = Pattern(Integral((WC('e', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons27, cons1665) rule4805 = ReplacementRule(pattern4805, replacement4805) pattern4806 = Pattern(Integral((F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + a_)**p_, x_), cons2, cons3, cons8, cons29, cons1666, cons87, cons130) rule4806 = ReplacementRule(pattern4806, replacement4806) pattern4807 = Pattern(Integral(S(1)/(F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + a_), x_), cons2, cons3, cons8, cons29, cons1666, cons1481, cons746) rule4807 = ReplacementRule(pattern4807, replacement4807) pattern4808 = Pattern(Integral(S(1)/(F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + a_), x_), cons2, cons3, cons8, cons29, cons1666, cons1484, cons746) rule4808 = ReplacementRule(pattern4808, replacement4808) pattern4809 = Pattern(Integral(G_**(x_*WC('d', S(1)) + WC('c', S(0)))/(F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + a_), x_), cons2, cons3, cons8, cons29, cons19, cons1667, cons87, cons746) rule4809 = ReplacementRule(pattern4809, replacement4809) pattern4810 = Pattern(Integral((F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('a', S(1)))**n_, x_), cons2, cons8, cons29, cons4, cons5, cons1666, cons25, cons40) rule4810 = ReplacementRule(pattern4810, With4810) pattern4811 = Pattern(Integral(((F_*(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)))**p_*WC('a', S(1)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1666, cons25, cons149) rule4811 = ReplacementRule(pattern4811, With4811) pattern4812 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1668, CustomConstraint(With4812)) rule4812 = ReplacementRule(pattern4812, replacement4812) pattern4813 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1669, CustomConstraint(With4813)) rule4813 = ReplacementRule(pattern4813, replacement4813) pattern4814 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1670, CustomConstraint(With4814)) rule4814 = ReplacementRule(pattern4814, replacement4814) pattern4815 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1671, CustomConstraint(With4815)) rule4815 = ReplacementRule(pattern4815, replacement4815) pattern4816 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1249, cons1672, CustomConstraint(With4816)) rule4816 = ReplacementRule(pattern4816, replacement4816) pattern4817 = Pattern(Integral(u_/cos((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))**S(2), x_), cons2, cons3, cons8, cons1249, CustomConstraint(With4817)) rule4817 = ReplacementRule(pattern4817, replacement4817) pattern4818 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1249, cons1673, CustomConstraint(With4818)) rule4818 = ReplacementRule(pattern4818, replacement4818) pattern4819 = Pattern(Integral(u_/sin((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))**S(2), x_), cons2, cons3, cons8, cons1249, CustomConstraint(With4819)) rule4819 = ReplacementRule(pattern4819, replacement4819) pattern4820 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons87, cons1670, CustomConstraint(With4820)) rule4820 = ReplacementRule(pattern4820, replacement4820) pattern4821 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons87, cons1671, CustomConstraint(With4821)) rule4821 = ReplacementRule(pattern4821, replacement4821) pattern4822 = Pattern(Integral(u_, x_), CustomConstraint(With4822)) rule4822 = ReplacementRule(pattern4822, replacement4822) pattern4823 = Pattern(Integral(u_, x_), CustomConstraint(With4823)) rule4823 = ReplacementRule(pattern4823, replacement4823) pattern4824 = Pattern(Integral(F_**(x_*WC('b', S(1)) + WC('a', S(0)))*G_**(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1674, cons1675, cons557) rule4824 = ReplacementRule(pattern4824, replacement4824) pattern4825 = Pattern(Integral(F_**(x_*WC('b', S(1)) + WC('a', S(0)))*G_**(x_*WC('d', S(1)) + WC('c', S(0)))*H_**(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1674, cons1675, cons1676, cons630) rule4825 = ReplacementRule(pattern4825, replacement4825) pattern4826 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1668, CustomConstraint(With4826)) rule4826 = ReplacementRule(pattern4826, replacement4826) pattern4827 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1669, CustomConstraint(With4827)) rule4827 = ReplacementRule(pattern4827, replacement4827) pattern4828 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1670, CustomConstraint(With4828)) rule4828 = ReplacementRule(pattern4828, replacement4828) pattern4829 = Pattern(Integral(F_*u_*(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)), x_), cons2, cons3, cons8, cons1671, CustomConstraint(With4829)) rule4829 = ReplacementRule(pattern4829, replacement4829) pattern4830 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1484, cons1249, cons1668, CustomConstraint(With4830)) rule4830 = ReplacementRule(pattern4830, replacement4830) pattern4831 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1484, cons1249, cons1672, CustomConstraint(With4831)) rule4831 = ReplacementRule(pattern4831, replacement4831) pattern4832 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1484, cons1249, cons1669, CustomConstraint(With4832)) rule4832 = ReplacementRule(pattern4832, replacement4832) pattern4833 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1484, cons1249, cons1673, CustomConstraint(With4833)) rule4833 = ReplacementRule(pattern4833, replacement4833) pattern4834 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1484, cons1249, cons1670, CustomConstraint(With4834)) rule4834 = ReplacementRule(pattern4834, replacement4834) pattern4835 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*u_, x_), cons2, cons3, cons8, cons1484, cons1249, cons1671, CustomConstraint(With4835)) rule4835 = ReplacementRule(pattern4835, replacement4835) pattern4836 = Pattern(Integral(u_*(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*WC('d', S(1)) + v_), x_), cons2, cons3, cons8, cons29, cons10, cons1484, cons1249, cons1668, CustomConstraint(With4836)) rule4836 = ReplacementRule(pattern4836, replacement4836) pattern4837 = Pattern(Integral(u_*(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*WC('d', S(1)) + v_), x_), cons2, cons3, cons8, cons29, cons10, cons1484, cons1249, cons1669, CustomConstraint(With4837)) rule4837 = ReplacementRule(pattern4837, replacement4837) pattern4838 = Pattern(Integral(u_, x_), CustomConstraint(With4838)) rule4838 = ReplacementRule(pattern4838, replacement4838) pattern4839 = Pattern(Integral(u_, x_), CustomConstraint(With4839)) rule4839 = ReplacementRule(pattern4839, replacement4839) pattern4840 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1677) rule4840 = ReplacementRule(pattern4840, replacement4840) pattern4841 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('c', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1678) rule4841 = ReplacementRule(pattern4841, replacement4841) pattern4842 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('c', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**WC('p', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons1678) rule4842 = ReplacementRule(pattern4842, replacement4842) pattern4843 = Pattern(Integral(u_/y_, x_), cons1679, CustomConstraint(With4843)) rule4843 = ReplacementRule(pattern4843, replacement4843) pattern4844 = Pattern(Integral(u_/(w_*y_), x_), cons1679, CustomConstraint(With4844)) rule4844 = ReplacementRule(pattern4844, replacement4844) pattern4845 = Pattern(Integral(u_*y_**WC('m', S(1)), x_), cons19, cons68, cons1679, CustomConstraint(With4845)) rule4845 = ReplacementRule(pattern4845, replacement4845) pattern4846 = Pattern(Integral(u_*y_**WC('m', S(1))*z_**WC('n', S(1)), x_), cons19, cons4, cons68, cons1679, CustomConstraint(With4846)) rule4846 = ReplacementRule(pattern4846, replacement4846) pattern4847 = Pattern(Integral((F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('a', S(1)))**n_*WC('u', S(1)), x_), cons2, cons8, cons29, cons4, cons5, cons1666, cons25, cons40) rule4847 = ReplacementRule(pattern4847, With4847) pattern4848 = Pattern(Integral(((F_*(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)))**p_*WC('a', S(1)))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1666, cons25, cons149) rule4848 = ReplacementRule(pattern4848, With4848) pattern4849 = Pattern(Integral(u_, x_), cons1232, CustomConstraint(With4849)) rule4849 = ReplacementRule(pattern4849, replacement4849) pattern4850 = Pattern(Integral(((S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)))**p_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons378) rule4850 = ReplacementRule(pattern4850, replacement4850) pattern4851 = Pattern(Integral(((S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*WC('a', S(1)))**p_*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons378) rule4851 = ReplacementRule(pattern4851, replacement4851) pattern4852 = Pattern(Integral(u_*(F_**(x_*WC('d', S(1)) + WC('c', S(0)))*a_ + F_**(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons52, cons1666, cons87, cons51) rule4852 = ReplacementRule(pattern4852, replacement4852) pattern4853 = Pattern(Integral(u_*(F_**(x_*WC('e', S(1)) + WC('d', S(0)))*a_ + F_**(x_*WC('e', S(1)) + WC('d', S(0)))*WC('b', S(1)) + F_**(x_*WC('e', S(1)) + WC('d', S(0)))*WC('c', S(1)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons54, cons1666, cons87, cons51, cons53) rule4853 = ReplacementRule(pattern4853, replacement4853) pattern4854 = Pattern(Integral(u_*(F_**(x_*WC('e', S(1)) + WC('d', S(0)))*WC('b', S(1)) + F_**(x_*WC('e', S(1)) + WC('d', S(0)))*WC('c', S(1)) + a_)**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons1666, cons87, cons1680) rule4854 = ReplacementRule(pattern4854, replacement4854) pattern4855 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1441) rule4855 = ReplacementRule(pattern4855, replacement4855) pattern4856 = Pattern(Integral(u_, x_), cons1681) rule4856 = ReplacementRule(pattern4856, replacement4856) pattern4857 = Pattern(Integral((a_*v_)**p_*WC('u', S(1)), x_), cons2, cons5, cons149, cons1682) rule4857 = ReplacementRule(pattern4857, With4857) pattern4858 = Pattern(Integral((v_**m_)**p_*WC('u', S(1)), x_), cons19, cons5, cons149, cons1682) rule4858 = ReplacementRule(pattern4858, With4858) pattern4859 = Pattern(Integral((v_**WC('m', S(1))*w_**WC('n', S(1)))**p_*WC('u', S(1)), x_), cons19, cons4, cons5, cons149, cons1683) rule4859 = ReplacementRule(pattern4859, With4859) pattern4860 = Pattern(Integral(u_, x_), cons1679, CustomConstraint(With4860)) rule4860 = ReplacementRule(pattern4860, replacement4860) pattern4861 = Pattern(Integral(u_, x_), cons1232, cons1684, CustomConstraint(With4861)) rule4861 = ReplacementRule(pattern4861, replacement4861) pattern4862 = Pattern(Integral(u_, x_), cons1679) rule4862 = ReplacementRule(pattern4862, With4862) pattern4863 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule4863 = ReplacementRule(pattern4863, replacement4863) pattern4864 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule4864 = ReplacementRule(pattern4864, replacement4864) pattern4865 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons466) rule4865 = ReplacementRule(pattern4865, replacement4865) pattern4866 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons466) rule4866 = ReplacementRule(pattern4866, replacement4866) pattern4867 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons466) rule4867 = ReplacementRule(pattern4867, replacement4867) pattern4868 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1685, cons33, cons170) rule4868 = ReplacementRule(pattern4868, replacement4868) pattern4869 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1685, cons33, cons170) rule4869 = ReplacementRule(pattern4869, replacement4869) pattern4870 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))/cos(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule4870 = ReplacementRule(pattern4870, replacement4870) pattern4871 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))/sin(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons4, cons64, cons586) rule4871 = ReplacementRule(pattern4871, replacement4871) pattern4872 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**p_/cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons1410) rule4872 = ReplacementRule(pattern4872, replacement4872) pattern4873 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1410) rule4873 = ReplacementRule(pattern4873, replacement4873) pattern4874 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**p_/sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons1410) rule4874 = ReplacementRule(pattern4874, replacement4874) pattern4875 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1410) rule4875 = ReplacementRule(pattern4875, replacement4875) pattern4876 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*tan(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons64, cons1686) rule4876 = ReplacementRule(pattern4876, With4876) pattern4877 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/tan(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons64, cons1686) rule4877 = ReplacementRule(pattern4877, With4877) pattern4878 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons33, cons87) rule4878 = ReplacementRule(pattern4878, replacement4878) pattern4879 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(S(1)/sin(x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1))*(S(1)/cos(x_*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons378, cons33, cons170, cons1687) rule4879 = ReplacementRule(pattern4879, With4879) pattern4880 = Pattern(Integral(F_**v_*G_**w_*u_**WC('m', S(1)), x_), cons19, cons4, cons5, cons1688, cons1689, cons1690, cons814, cons815) rule4880 = ReplacementRule(pattern4880, replacement4880) pattern4881 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule4881 = ReplacementRule(pattern4881, replacement4881) pattern4882 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule4882 = ReplacementRule(pattern4882, replacement4882) pattern4883 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule4883 = ReplacementRule(pattern4883, replacement4883) pattern4884 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule4884 = ReplacementRule(pattern4884, replacement4884) pattern4885 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))/cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule4885 = ReplacementRule(pattern4885, replacement4885) pattern4886 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))/(sin(x_*WC('d', S(1)) + WC('c', S(0)))*tan(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons586) rule4886 = ReplacementRule(pattern4886, replacement4886) pattern4887 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons557, cons20) rule4887 = ReplacementRule(pattern4887, replacement4887) pattern4888 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons557, cons20) rule4888 = ReplacementRule(pattern4888, replacement4888) pattern4889 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons557) rule4889 = ReplacementRule(pattern4889, replacement4889) pattern4890 = Pattern(Integral(F_**(x_*WC('b', S(1)) + WC('a', S(0)))*G_**(x_*WC('d', S(1)) + WC('c', S(0)))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1691, cons1692, cons557, cons27, cons1693) rule4890 = ReplacementRule(pattern4890, replacement4890) pattern4891 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sin(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1694) rule4891 = ReplacementRule(pattern4891, replacement4891) pattern4892 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cos(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1694) rule4892 = ReplacementRule(pattern4892, replacement4892) pattern4893 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1695, cons89, cons167) rule4893 = ReplacementRule(pattern4893, replacement4893) pattern4894 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1696, cons33, cons168) rule4894 = ReplacementRule(pattern4894, replacement4894) pattern4895 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1697, cons586, cons1397) rule4895 = ReplacementRule(pattern4895, replacement4895) pattern4896 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1697, cons586, cons1397) rule4896 = ReplacementRule(pattern4896, replacement4896) pattern4897 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1698, cons89, cons91, cons1444) rule4897 = ReplacementRule(pattern4897, replacement4897) pattern4898 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1698, cons89, cons91, cons1444) rule4898 = ReplacementRule(pattern4898, replacement4898) pattern4899 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons25) rule4899 = ReplacementRule(pattern4899, replacement4899) pattern4900 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons25) rule4900 = ReplacementRule(pattern4900, replacement4900) pattern4901 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule4901 = ReplacementRule(pattern4901, replacement4901) pattern4902 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule4902 = ReplacementRule(pattern4902, replacement4902) pattern4903 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1695, cons89, cons91) rule4903 = ReplacementRule(pattern4903, replacement4903) pattern4904 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1695, cons89, cons91) rule4904 = ReplacementRule(pattern4904, replacement4904) pattern4905 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1699, cons1504, cons965) rule4905 = ReplacementRule(pattern4905, replacement4905) pattern4906 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons4, cons1699, cons1504, cons965) rule4906 = ReplacementRule(pattern4906, replacement4906) pattern4907 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1700, cons89, cons167, cons1646) rule4907 = ReplacementRule(pattern4907, replacement4907) pattern4908 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons1700, cons89, cons167, cons1646) rule4908 = ReplacementRule(pattern4908, replacement4908) pattern4909 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule4909 = ReplacementRule(pattern4909, replacement4909) pattern4910 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons87) rule4910 = ReplacementRule(pattern4910, replacement4910) pattern4911 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons25) rule4911 = ReplacementRule(pattern4911, replacement4911) pattern4912 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons25) rule4912 = ReplacementRule(pattern4912, replacement4912) pattern4913 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1701, cons198) rule4913 = ReplacementRule(pattern4913, replacement4913) pattern4914 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1702, cons198) rule4914 = ReplacementRule(pattern4914, replacement4914) pattern4915 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1013, cons198) rule4915 = ReplacementRule(pattern4915, replacement4915) pattern4916 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1701, cons152, cons1553) rule4916 = ReplacementRule(pattern4916, replacement4916) pattern4917 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1702, cons152, cons1553) rule4917 = ReplacementRule(pattern4917, replacement4917) pattern4918 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(f_ + WC('g', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1013, cons152, cons1553) rule4918 = ReplacementRule(pattern4918, replacement4918) pattern4919 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(h_ + WC('i', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))/(f_ + WC('g', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons1701, cons1703, cons1704) rule4919 = ReplacementRule(pattern4919, replacement4919) pattern4920 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(h_ + WC('i', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(f_ + WC('g', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons1701, cons1703, cons1705) rule4920 = ReplacementRule(pattern4920, replacement4920) pattern4921 = Pattern(Integral(F_**(u_*WC('c', S(1)))*G_**v_, x_), cons1101, cons8, cons4, cons1689, cons812, cons813) rule4921 = ReplacementRule(pattern4921, replacement4921) pattern4922 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*x_**WC('m', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons33, cons170, cons150) rule4922 = ReplacementRule(pattern4922, With4922) pattern4923 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*x_**WC('m', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons33, cons170, cons150) rule4923 = ReplacementRule(pattern4923, With4923) pattern4924 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cos(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons530) rule4924 = ReplacementRule(pattern4924, replacement4924) pattern4925 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*x_**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cos(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1706) rule4925 = ReplacementRule(pattern4925, replacement4925) pattern4926 = Pattern(Integral(F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*G_**(x_*WC('e', S(1)) + WC('d', S(0)))*H_**(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons530, cons1689, cons1707) rule4926 = ReplacementRule(pattern4926, replacement4926) pattern4927 = Pattern(Integral(F_**u_*sin(v_)**WC('n', S(1)), x_), cons1101, cons1708, cons1709, cons150) rule4927 = ReplacementRule(pattern4927, replacement4927) pattern4928 = Pattern(Integral(F_**u_*cos(v_)**WC('n', S(1)), x_), cons1101, cons1708, cons1709, cons150) rule4928 = ReplacementRule(pattern4928, replacement4928) pattern4929 = Pattern(Integral(F_**u_*sin(v_)**WC('m', S(1))*cos(v_)**WC('n', S(1)), x_), cons1101, cons1708, cons1709, cons530) rule4929 = ReplacementRule(pattern4929, replacement4929) pattern4930 = Pattern(Integral(sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1710, cons56) rule4930 = ReplacementRule(pattern4930, replacement4930) pattern4931 = Pattern(Integral(cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1710, cons56) rule4931 = ReplacementRule(pattern4931, replacement4931) pattern4932 = Pattern(Integral(sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons130, cons1711) rule4932 = ReplacementRule(pattern4932, replacement4932) pattern4933 = Pattern(Integral(cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons130, cons1711) rule4933 = ReplacementRule(pattern4933, replacement4933) pattern4934 = Pattern(Integral(sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1712) rule4934 = ReplacementRule(pattern4934, replacement4934) pattern4935 = Pattern(Integral(cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1712) rule4935 = ReplacementRule(pattern4935, replacement4935) pattern4936 = Pattern(Integral(sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1713) rule4936 = ReplacementRule(pattern4936, replacement4936) pattern4937 = Pattern(Integral(cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1713) rule4937 = ReplacementRule(pattern4937, replacement4937) pattern4938 = Pattern(Integral(sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1507, cons1714) rule4938 = ReplacementRule(pattern4938, replacement4938) pattern4939 = Pattern(Integral(cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1507, cons1714) rule4939 = ReplacementRule(pattern4939, replacement4939) pattern4940 = Pattern(Integral(sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1713) rule4940 = ReplacementRule(pattern4940, replacement4940) pattern4941 = Pattern(Integral(cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1713) rule4941 = ReplacementRule(pattern4941, replacement4941) pattern4942 = Pattern(Integral(x_**WC('m', S(1))*sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1715, cons56, cons68) rule4942 = ReplacementRule(pattern4942, replacement4942) pattern4943 = Pattern(Integral(x_**WC('m', S(1))*cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1715, cons56, cons68) rule4943 = ReplacementRule(pattern4943, replacement4943) pattern4944 = Pattern(Integral(x_**WC('m', S(1))*sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons130, cons1716) rule4944 = ReplacementRule(pattern4944, replacement4944) pattern4945 = Pattern(Integral(x_**WC('m', S(1))*cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons130, cons1716) rule4945 = ReplacementRule(pattern4945, replacement4945) pattern4946 = Pattern(Integral(x_**WC('m', S(1))*sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1717) rule4946 = ReplacementRule(pattern4946, replacement4946) pattern4947 = Pattern(Integral(x_**WC('m', S(1))*cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1717) rule4947 = ReplacementRule(pattern4947, replacement4947) pattern4948 = Pattern(Integral(x_**WC('m', S(1))*sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons148, cons1718) rule4948 = ReplacementRule(pattern4948, replacement4948) pattern4949 = Pattern(Integral(x_**WC('m', S(1))*cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons148, cons1718) rule4949 = ReplacementRule(pattern4949, replacement4949) pattern4950 = Pattern(Integral(x_**WC('m', S(1))*sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons139, cons1507, cons1719) rule4950 = ReplacementRule(pattern4950, replacement4950) pattern4951 = Pattern(Integral(x_**WC('m', S(1))*cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons139, cons1507, cons1719) rule4951 = ReplacementRule(pattern4951, replacement4951) pattern4952 = Pattern(Integral(x_**WC('m', S(1))*sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1718) rule4952 = ReplacementRule(pattern4952, replacement4952) pattern4953 = Pattern(Integral(x_**WC('m', S(1))*cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1718) rule4953 = ReplacementRule(pattern4953, replacement4953) pattern4954 = Pattern(Integral(S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1720) rule4954 = ReplacementRule(pattern4954, replacement4954) pattern4955 = Pattern(Integral(S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons4, cons1720) rule4955 = ReplacementRule(pattern4955, replacement4955) pattern4956 = Pattern(Integral((S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1721, cons1647) rule4956 = ReplacementRule(pattern4956, replacement4956) pattern4957 = Pattern(Integral((S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons1721, cons1647) rule4957 = ReplacementRule(pattern4957, replacement4957) pattern4958 = Pattern(Integral((S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1722, cons1723) rule4958 = ReplacementRule(pattern4958, replacement4958) pattern4959 = Pattern(Integral((S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons148, cons1722, cons1723) rule4959 = ReplacementRule(pattern4959, replacement4959) pattern4960 = Pattern(Integral((S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1713) rule4960 = ReplacementRule(pattern4960, replacement4960) pattern4961 = Pattern(Integral((S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons4, cons13, cons139, cons1713) rule4961 = ReplacementRule(pattern4961, replacement4961) pattern4962 = Pattern(Integral((S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons1713) rule4962 = ReplacementRule(pattern4962, replacement4962) pattern4963 = Pattern(Integral((S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons1713) rule4963 = ReplacementRule(pattern4963, replacement4963) pattern4964 = Pattern(Integral(x_**WC('m', S(1))/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1724) rule4964 = ReplacementRule(pattern4964, replacement4964) pattern4965 = Pattern(Integral(x_**WC('m', S(1))/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))), x_), cons2, cons3, cons8, cons19, cons4, cons1724) rule4965 = ReplacementRule(pattern4965, replacement4965) pattern4966 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1725, cons68, cons1647) rule4966 = ReplacementRule(pattern4966, replacement4966) pattern4967 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1725, cons68, cons1647) rule4967 = ReplacementRule(pattern4967, replacement4967) pattern4968 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons148, cons1722, cons1726) rule4968 = ReplacementRule(pattern4968, replacement4968) pattern4969 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons148, cons1722, cons1726) rule4969 = ReplacementRule(pattern4969, replacement4969) pattern4970 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons139, cons1718) rule4970 = ReplacementRule(pattern4970, replacement4970) pattern4971 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons13, cons139, cons1718) rule4971 = ReplacementRule(pattern4971, replacement4971) pattern4972 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cos(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1718) rule4972 = ReplacementRule(pattern4972, replacement4972) pattern4973 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sin(WC('a', S(0)) + WC('b', S(1))*log(x_**WC('n', S(1))*WC('c', S(1)))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons1718) rule4973 = ReplacementRule(pattern4973, replacement4973) pattern4974 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*sin(x_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons13, cons165) rule4974 = ReplacementRule(pattern4974, replacement4974) pattern4975 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*cos(x_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons13, cons165) rule4975 = ReplacementRule(pattern4975, replacement4975) pattern4976 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*sin(x_**n_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons340, cons165) rule4976 = ReplacementRule(pattern4976, replacement4976) pattern4977 = Pattern(Integral(log(x_*WC('b', S(1)))**WC('p', S(1))*cos(x_**n_*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons340, cons165) rule4977 = ReplacementRule(pattern4977, replacement4977) pattern4978 = Pattern(Integral(x_**WC('m', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))*sin(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons19, cons4, cons55, cons13, cons165) rule4978 = ReplacementRule(pattern4978, replacement4978) pattern4979 = Pattern(Integral(x_**WC('m', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))*cos(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons19, cons4, cons55, cons13, cons165) rule4979 = ReplacementRule(pattern4979, replacement4979) pattern4980 = Pattern(Integral(x_**WC('m', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))*sin(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons19, cons4, cons13, cons165, cons629) rule4980 = ReplacementRule(pattern4980, replacement4980) pattern4981 = Pattern(Integral(x_**m_*log(x_*WC('b', S(1)))**WC('p', S(1))*cos(x_**WC('n', S(1))*WC('a', S(1))*log(x_*WC('b', S(1)))**WC('p', S(1))), x_), cons2, cons3, cons19, cons4, cons13, cons165, cons629) rule4981 = ReplacementRule(pattern4981, replacement4981) pattern4982 = Pattern(Integral(sin(WC('a', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons8, cons29, cons150) rule4982 = ReplacementRule(pattern4982, replacement4982) pattern4983 = Pattern(Integral(cos(WC('a', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons8, cons29, cons150) rule4983 = ReplacementRule(pattern4983, replacement4983) pattern4984 = Pattern(Integral(sin((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150, cons73) rule4984 = ReplacementRule(pattern4984, replacement4984) pattern4985 = Pattern(Integral(cos((x_*WC('b', S(1)) + WC('a', S(0)))*WC('e', S(1))/(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons150, cons73) rule4985 = ReplacementRule(pattern4985, replacement4985) pattern4986 = Pattern(Integral(sin(u_)**WC('n', S(1)), x_), cons150, cons1727) rule4986 = ReplacementRule(pattern4986, With4986) pattern4987 = Pattern(Integral(cos(u_)**WC('n', S(1)), x_), cons150, cons1727) rule4987 = ReplacementRule(pattern4987, With4987) pattern4988 = Pattern(Integral(WC('u', S(1))*sin(v_)**WC('p', S(1))*sin(w_)**WC('q', S(1)), x_), cons1690) rule4988 = ReplacementRule(pattern4988, replacement4988) pattern4989 = Pattern(Integral(WC('u', S(1))*cos(v_)**WC('p', S(1))*cos(w_)**WC('q', S(1)), x_), cons1690) rule4989 = ReplacementRule(pattern4989, replacement4989) pattern4990 = Pattern(Integral(sin(v_)**WC('p', S(1))*sin(w_)**WC('q', S(1)), x_), cons1728, cons557) rule4990 = ReplacementRule(pattern4990, replacement4990) pattern4991 = Pattern(Integral(cos(v_)**WC('p', S(1))*cos(w_)**WC('q', S(1)), x_), cons1728, cons557) rule4991 = ReplacementRule(pattern4991, replacement4991) pattern4992 = Pattern(Integral(x_**WC('m', S(1))*sin(v_)**WC('p', S(1))*sin(w_)**WC('q', S(1)), x_), cons1729, cons1728) rule4992 = ReplacementRule(pattern4992, replacement4992) pattern4993 = Pattern(Integral(x_**WC('m', S(1))*cos(v_)**WC('p', S(1))*cos(w_)**WC('q', S(1)), x_), cons1729, cons1728) rule4993 = ReplacementRule(pattern4993, replacement4993) pattern4994 = Pattern(Integral(WC('u', S(1))*sin(v_)**WC('p', S(1))*cos(w_)**WC('p', S(1)), x_), cons1690, cons40) rule4994 = ReplacementRule(pattern4994, replacement4994) pattern4995 = Pattern(Integral(sin(v_)**WC('p', S(1))*cos(w_)**WC('q', S(1)), x_), cons557, cons1728) rule4995 = ReplacementRule(pattern4995, replacement4995) pattern4996 = Pattern(Integral(x_**WC('m', S(1))*sin(v_)**WC('p', S(1))*cos(w_)**WC('q', S(1)), x_), cons1729, cons1728) rule4996 = ReplacementRule(pattern4996, replacement4996) pattern4997 = Pattern(Integral(sin(v_)*tan(w_)**WC('n', S(1)), x_), cons89, cons90, cons1730) rule4997 = ReplacementRule(pattern4997, replacement4997) pattern4998 = Pattern(Integral((S(1)/tan(w_))**WC('n', S(1))*cos(v_), x_), cons89, cons90, cons1730) rule4998 = ReplacementRule(pattern4998, replacement4998) pattern4999 = Pattern(Integral((S(1)/tan(w_))**WC('n', S(1))*sin(v_), x_), cons89, cons90, cons1730) rule4999 = ReplacementRule(pattern4999, replacement4999) pattern5000 = Pattern(Integral(cos(v_)*tan(w_)**WC('n', S(1)), x_), cons89, cons90, cons1730) rule5000 = ReplacementRule(pattern5000, replacement5000) pattern5001 = Pattern(Integral((S(1)/cos(w_))**WC('n', S(1))*sin(v_), x_), cons89, cons90, cons1730) rule5001 = ReplacementRule(pattern5001, replacement5001) pattern5002 = Pattern(Integral((S(1)/sin(w_))**WC('n', S(1))*cos(v_), x_), cons89, cons90, cons1730) rule5002 = ReplacementRule(pattern5002, replacement5002) pattern5003 = Pattern(Integral((S(1)/sin(w_))**WC('n', S(1))*sin(v_), x_), cons89, cons90, cons1730) rule5003 = ReplacementRule(pattern5003, replacement5003) pattern5004 = Pattern(Integral((S(1)/cos(w_))**WC('n', S(1))*cos(v_), x_), cons89, cons90, cons1730) rule5004 = ReplacementRule(pattern5004, replacement5004) pattern5005 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule5005 = ReplacementRule(pattern5005, replacement5005) pattern5006 = Pattern(Integral(x_**WC('m', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons1480, cons152, cons170, cons465, cons1731) rule5006 = ReplacementRule(pattern5006, replacement5006) pattern5007 = Pattern(Integral(x_**WC('m', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons1480, cons152, cons170, cons465, cons1731) rule5007 = ReplacementRule(pattern5007, replacement5007) pattern5008 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin((c_ + x_*WC('d', S(1)))**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons13) rule5008 = ReplacementRule(pattern5008, replacement5008) pattern5009 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos((c_ + x_*WC('d', S(1)))**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons64, cons13) rule5009 = ReplacementRule(pattern5009, replacement5009) pattern5010 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons64, cons1480, cons1732) rule5010 = ReplacementRule(pattern5010, replacement5010) pattern5011 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((b_ + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons3, cons8, cons29, cons50, cons127, cons210, cons64) rule5011 = ReplacementRule(pattern5011, replacement5011) pattern5012 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((WC('a', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('b', S(0)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons64, cons1480, cons1732) rule5012 = ReplacementRule(pattern5012, replacement5012) pattern5013 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((c_ + WC('b', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons3, cons8, cons29, cons50, cons127, cons210, cons64) rule5013 = ReplacementRule(pattern5013, replacement5013) pattern5014 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('m', S(1))/((WC('a', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('b', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2) + WC('c', S(0)))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons64, cons1480, cons1732) rule5014 = ReplacementRule(pattern5014, replacement5014) pattern5015 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1733) rule5015 = ReplacementRule(pattern5015, replacement5015) pattern5016 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1733) rule5016 = ReplacementRule(pattern5016, replacement5016) pattern5017 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1734) rule5017 = ReplacementRule(pattern5017, replacement5017) pattern5018 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons1734) rule5018 = ReplacementRule(pattern5018, replacement5018) pattern5019 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1267) rule5019 = ReplacementRule(pattern5019, replacement5019) pattern5020 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1267) rule5020 = ReplacementRule(pattern5020, replacement5020) pattern5021 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1269) rule5021 = ReplacementRule(pattern5021, replacement5021) pattern5022 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons64, cons87, cons167, cons1269) rule5022 = ReplacementRule(pattern5022, replacement5022) pattern5023 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))*(x_*WC('f', S(1)) + WC('e', S(0)))/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1476) rule5023 = ReplacementRule(pattern5023, replacement5023) pattern5024 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))*(x_*WC('f', S(1)) + WC('e', S(0)))/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1476) rule5024 = ReplacementRule(pattern5024, replacement5024) pattern5025 = Pattern(Integral((a_ + WC('b', S(1))*tan(v_))**WC('n', S(1))*(S(1)/cos(v_))**WC('m', S(1)), x_), cons2, cons3, cons152, cons1553, cons1483) rule5025 = ReplacementRule(pattern5025, replacement5025) pattern5026 = Pattern(Integral((a_ + WC('b', S(1))/tan(v_))**WC('n', S(1))*(S(1)/sin(v_))**WC('m', S(1)), x_), cons2, cons3, cons152, cons1553, cons1483) rule5026 = ReplacementRule(pattern5026, replacement5026) pattern5027 = Pattern(Integral(WC('u', S(1))*sin(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons530) rule5027 = ReplacementRule(pattern5027, replacement5027) pattern5028 = Pattern(Integral(WC('u', S(1))*cos(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons530) rule5028 = ReplacementRule(pattern5028, replacement5028) pattern5029 = Pattern(Integral(S(1)/(cos(c_ + x_*WC('d', S(1)))*cos(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule5029 = ReplacementRule(pattern5029, replacement5029) pattern5030 = Pattern(Integral(S(1)/(sin(c_ + x_*WC('d', S(1)))*sin(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule5030 = ReplacementRule(pattern5030, replacement5030) pattern5031 = Pattern(Integral(tan(c_ + x_*WC('d', S(1)))*tan(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule5031 = ReplacementRule(pattern5031, replacement5031) pattern5032 = Pattern(Integral(S(1)/(tan(c_ + x_*WC('d', S(1)))*tan(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons1735, cons73) rule5032 = ReplacementRule(pattern5032, replacement5032) pattern5033 = Pattern(Integral((WC('a', S(1))*cos(v_) + WC('b', S(1))*sin(v_))**WC('n', S(1))*WC('u', S(1)), x_), cons2, cons3, cons4, cons1441) rule5033 = ReplacementRule(pattern5033, replacement5033) return [rule4688, rule4689, rule4690, rule4691, rule4692, rule4693, rule4694, rule4695, rule4696, rule4697, rule4698, rule4699, rule4700, rule4701, rule4702, rule4703, rule4704, rule4705, rule4706, rule4707, rule4708, rule4709, rule4710, rule4711, rule4712, rule4713, rule4714, rule4715, rule4716, rule4717, rule4718, rule4719, rule4720, rule4721, rule4722, rule4723, rule4724, rule4725, rule4726, rule4727, rule4728, rule4729, rule4730, rule4731, rule4732, rule4733, rule4734, rule4735, rule4736, rule4737, rule4738, rule4739, rule4740, rule4741, rule4742, rule4743, rule4744, rule4745, rule4746, rule4747, rule4748, rule4749, rule4750, rule4751, rule4752, rule4753, rule4754, rule4755, rule4756, rule4757, rule4758, rule4759, rule4760, rule4761, rule4762, rule4763, rule4764, rule4765, rule4766, rule4767, rule4768, rule4769, rule4770, rule4771, rule4772, rule4773, rule4774, rule4775, rule4776, rule4777, rule4778, rule4779, rule4780, rule4781, rule4782, rule4783, rule4784, rule4785, rule4786, rule4787, rule4788, rule4789, rule4790, rule4791, rule4792, rule4793, rule4794, rule4795, rule4796, rule4797, rule4798, rule4799, rule4800, rule4801, rule4802, rule4803, rule4804, rule4805, rule4806, rule4807, rule4808, rule4809, rule4810, rule4811, rule4812, rule4813, rule4814, rule4815, rule4816, rule4817, rule4818, rule4819, rule4820, rule4821, rule4822, rule4823, rule4824, rule4825, rule4826, rule4827, rule4828, rule4829, rule4830, rule4831, rule4832, rule4833, rule4834, rule4835, rule4836, rule4837, rule4838, rule4839, rule4840, rule4841, rule4842, rule4843, rule4844, rule4845, rule4846, rule4847, rule4848, rule4849, rule4850, rule4851, rule4852, rule4853, rule4854, rule4855, rule4856, rule4857, rule4858, rule4859, rule4860, rule4861, rule4862, rule4863, rule4864, rule4865, rule4866, rule4867, rule4868, rule4869, rule4870, rule4871, rule4872, rule4873, rule4874, rule4875, rule4876, rule4877, rule4878, rule4879, rule4880, rule4881, rule4882, rule4883, rule4884, rule4885, rule4886, rule4887, rule4888, rule4889, rule4890, rule4891, rule4892, rule4893, rule4894, rule4895, rule4896, rule4897, rule4898, rule4899, rule4900, rule4901, rule4902, rule4903, rule4904, rule4905, rule4906, rule4907, rule4908, rule4909, rule4910, rule4911, rule4912, rule4913, rule4914, rule4915, rule4916, rule4917, rule4918, rule4919, rule4920, rule4921, rule4922, rule4923, rule4924, rule4925, rule4926, rule4927, rule4928, rule4929, rule4930, rule4931, rule4932, rule4933, rule4934, rule4935, rule4936, rule4937, rule4938, rule4939, rule4940, rule4941, rule4942, rule4943, rule4944, rule4945, rule4946, rule4947, rule4948, rule4949, rule4950, rule4951, rule4952, rule4953, rule4954, rule4955, rule4956, rule4957, rule4958, rule4959, rule4960, rule4961, rule4962, rule4963, rule4964, rule4965, rule4966, rule4967, rule4968, rule4969, rule4970, rule4971, rule4972, rule4973, rule4974, rule4975, rule4976, rule4977, rule4978, rule4979, rule4980, rule4981, rule4982, rule4983, rule4984, rule4985, rule4986, rule4987, rule4988, rule4989, rule4990, rule4991, rule4992, rule4993, rule4994, rule4995, rule4996, rule4997, rule4998, rule4999, rule5000, rule5001, rule5002, rule5003, rule5004, rule5005, rule5006, rule5007, rule5008, rule5009, rule5010, rule5011, rule5012, rule5013, rule5014, rule5015, rule5016, rule5017, rule5018, rule5019, rule5020, rule5021, rule5022, rule5023, rule5024, rule5025, rule5026, rule5027, rule5028, rule5029, rule5030, rule5031, rule5032, rule5033, ] def replacement4688(a, b, c, d, m, n, u, x): return Dist((c*tan(a + b*x))**m*(d*sin(a + b*x))**(-m)*(d*cos(a + b*x))**m, Int((d*sin(a + b*x))**(m + n)*(d*cos(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4689(a, b, c, d, m, n, u, x): return Dist((c*tan(a + b*x))**m*(d*sin(a + b*x))**(-m)*(d*cos(a + b*x))**m, Int((d*sin(a + b*x))**m*(d*cos(a + b*x))**(-m + n)*ActivateTrig(u), x), x) def replacement4690(a, b, c, d, m, n, u, x): return Dist((c/tan(a + b*x))**m*(d*sin(a + b*x))**m*(d*cos(a + b*x))**(-m), Int((d*sin(a + b*x))**(-m + n)*(d*cos(a + b*x))**m*ActivateTrig(u), x), x) def replacement4691(a, b, c, d, m, n, u, x): return Dist((c/tan(a + b*x))**m*(d*sin(a + b*x))**m*(d*cos(a + b*x))**(-m), Int((d*sin(a + b*x))**(-m)*(d*cos(a + b*x))**(m + n)*ActivateTrig(u), x), x) def replacement4692(a, b, c, d, m, n, u, x): return Dist((c/sin(a + b*x))**m*(d*sin(a + b*x))**m, Int((d*sin(a + b*x))**(-m + n)*ActivateTrig(u), x), x) def replacement4693(a, b, c, m, u, x): return Dist((c*sin(a + b*x))**(-m)*(c*cos(a + b*x))**m*(c*tan(a + b*x))**m, Int((c*sin(a + b*x))**m*(c*cos(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4694(a, b, c, m, u, x): return Dist((c*sin(a + b*x))**m*(c*cos(a + b*x))**(-m)*(c/tan(a + b*x))**m, Int((c*sin(a + b*x))**(-m)*(c*cos(a + b*x))**m*ActivateTrig(u), x), x) def replacement4695(a, b, c, m, u, x): return Dist((c/cos(a + b*x))**m*(c*cos(a + b*x))**m, Int((c*cos(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4696(a, b, c, m, u, x): return Dist((c/sin(a + b*x))**m*(c*sin(a + b*x))**m, Int((c*sin(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4697(A, B, a, b, c, n, u, x): return Dist(c, Int((c*sin(a + b*x))**(n + S(-1))*(A*sin(a + b*x) + B)*ActivateTrig(u), x), x) def replacement4698(A, B, a, b, c, n, u, x): return Dist(c, Int((c*cos(a + b*x))**(n + S(-1))*(A*cos(a + b*x) + B)*ActivateTrig(u), x), x) def replacement4699(A, B, a, b, u, x): return Int((A*sin(a + b*x) + B)*ActivateTrig(u)/sin(a + b*x), x) def replacement4700(A, B, a, b, u, x): return Int((A*cos(a + b*x) + B)*ActivateTrig(u)/cos(a + b*x), x) def replacement4701(A, B, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c*sin(a + b*x))**(n + S(-2))*(A*sin(a + b*x)**S(2) + B*sin(a + b*x) + C)*ActivateTrig(u), x), x) def replacement4702(A, B, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c*cos(a + b*x))**(n + S(-2))*(A*cos(a + b*x)**S(2) + B*cos(a + b*x) + C)*ActivateTrig(u), x), x) def replacement4703(A, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c*sin(a + b*x))**(n + S(-2))*(A*sin(a + b*x)**S(2) + C)*ActivateTrig(u), x), x) def replacement4704(A, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c*cos(a + b*x))**(n + S(-2))*(A*cos(a + b*x)**S(2) + C)*ActivateTrig(u), x), x) def replacement4705(A, B, C, a, b, u, x): return Int((A*sin(a + b*x)**S(2) + B*sin(a + b*x) + C)*ActivateTrig(u)/sin(a + b*x)**S(2), x) def replacement4706(A, B, C, a, b, u, x): return Int((A*cos(a + b*x)**S(2) + B*cos(a + b*x) + C)*ActivateTrig(u)/cos(a + b*x)**S(2), x) def replacement4707(A, C, a, b, u, x): return Int((A*sin(a + b*x)**S(2) + C)*ActivateTrig(u)/sin(a + b*x)**S(2), x) def replacement4708(A, C, a, b, u, x): return Int((A*cos(a + b*x)**S(2) + C)*ActivateTrig(u)/cos(a + b*x)**S(2), x) def replacement4709(A, B, C, a, b, u, x): return Int((A*sin(a + b*x) + B*sin(a + b*x)**S(2) + C)*ActivateTrig(u)/sin(a + b*x), x) def replacement4710(A, B, C, a, b, u, x): return Int((A*cos(a + b*x) + B*cos(a + b*x)**S(2) + C)*ActivateTrig(u)/cos(a + b*x), x) def replacement4711(A, B, C, a, b, n, n1, n2, u, x): return Int((A + B*sin(a + b*x) + C*sin(a + b*x)**S(2))*ActivateTrig(u)*sin(a + b*x)**n, x) def replacement4712(A, B, C, a, b, n, n1, n2, u, x): return Int((A + B*cos(a + b*x) + C*cos(a + b*x)**S(2))*ActivateTrig(u)*cos(a + b*x)**n, x) def replacement4713(a, b, c, d, m, n, u, x): return Dist((c/tan(a + b*x))**m*(d*tan(a + b*x))**m, Int((d*tan(a + b*x))**(-m + n)*ActivateTrig(u), x), x) def replacement4714(a, b, c, d, m, n, u, x): return Dist((c*tan(a + b*x))**m*(d*sin(a + b*x))**(-m)*(d*cos(a + b*x))**m, Int((d*sin(a + b*x))**m*(d*cos(a + b*x))**(-m + n)*ActivateTrig(u), x), x) def replacement4715(a, b, c, m, u, x): return Dist((c/tan(a + b*x))**m*(c*tan(a + b*x))**m, Int((c*tan(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4716(a, b, c, m, u, x): return Dist((c/tan(a + b*x))**m*(c*tan(a + b*x))**m, Int((c/tan(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4717(A, B, a, b, c, n, u, x): return Dist(c, Int((c*tan(a + b*x))**(n + S(-1))*(A*tan(a + b*x) + B)*ActivateTrig(u), x), x) def replacement4718(A, B, a, b, c, n, u, x): return Dist(c, Int((c/tan(a + b*x))**(n + S(-1))*(A/tan(a + b*x) + B)*ActivateTrig(u), x), x) def replacement4719(A, B, a, b, u, x): return Int((A*tan(a + b*x) + B)*ActivateTrig(u)/tan(a + b*x), x) def replacement4720(A, B, a, b, u, x): return Int((A/tan(a + b*x) + B)*ActivateTrig(u)*tan(a + b*x), x) def replacement4721(A, B, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c*tan(a + b*x))**(n + S(-2))*(A*tan(a + b*x)**S(2) + B*tan(a + b*x) + C)*ActivateTrig(u), x), x) def replacement4722(A, B, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c/tan(a + b*x))**(n + S(-2))*(A/tan(a + b*x)**S(2) + B/tan(a + b*x) + C)*ActivateTrig(u), x), x) def replacement4723(A, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c*tan(a + b*x))**(n + S(-2))*(A*tan(a + b*x)**S(2) + C)*ActivateTrig(u), x), x) def replacement4724(A, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c/tan(a + b*x))**(n + S(-2))*(A/tan(a + b*x)**S(2) + C)*ActivateTrig(u), x), x) def replacement4725(A, B, C, a, b, u, x): return Int((A*tan(a + b*x)**S(2) + B*tan(a + b*x) + C)*ActivateTrig(u)/tan(a + b*x)**S(2), x) def replacement4726(A, B, C, a, b, u, x): return Int((A/tan(a + b*x)**S(2) + B/tan(a + b*x) + C)*ActivateTrig(u)*tan(a + b*x)**S(2), x) def replacement4727(A, C, a, b, u, x): return Int((A*tan(a + b*x)**S(2) + C)*ActivateTrig(u)/tan(a + b*x)**S(2), x) def replacement4728(A, C, a, b, u, x): return Int((A/tan(a + b*x)**S(2) + C)*ActivateTrig(u)*tan(a + b*x)**S(2), x) def replacement4729(A, B, C, a, b, u, x): return Int((A*tan(a + b*x) + B*tan(a + b*x)**S(2) + C)*ActivateTrig(u)/tan(a + b*x), x) def replacement4730(A, B, C, a, b, n, n1, n2, u, x): return Int((A + B*tan(a + b*x) + C*tan(a + b*x)**S(2))*ActivateTrig(u)*tan(a + b*x)**n, x) def replacement4731(A, B, C, a, b, n, n1, n2, u, x): return Int((A + B/tan(a + b*x) + C/tan(a + b*x)**S(2))*(S(1)/tan(a + b*x))**n*ActivateTrig(u), x) def replacement4732(a, b, c, d, m, n, u, x): return Dist((c*sin(a + b*x))**m*(d/sin(a + b*x))**m, Int((d/sin(a + b*x))**(-m + n)*ActivateTrig(u), x), x) def replacement4733(a, b, c, d, m, n, u, x): return Dist((c*cos(a + b*x))**m*(d/cos(a + b*x))**m, Int((d/cos(a + b*x))**(-m + n)*ActivateTrig(u), x), x) def replacement4734(a, b, c, d, m, n, u, x): return Dist((c*tan(a + b*x))**m*(d/sin(a + b*x))**m*(d/cos(a + b*x))**(-m), Int((d/sin(a + b*x))**(-m)*(d/cos(a + b*x))**(m + n)*ActivateTrig(u), x), x) def replacement4735(a, b, c, d, m, n, u, x): return Dist((c*tan(a + b*x))**m*(d/sin(a + b*x))**m*(d/cos(a + b*x))**(-m), Int((d/sin(a + b*x))**(-m + n)*(d/cos(a + b*x))**m*ActivateTrig(u), x), x) def replacement4736(a, b, c, d, m, n, u, x): return Dist((c/tan(a + b*x))**m*(d/sin(a + b*x))**(-m)*(d/cos(a + b*x))**m, Int((d/sin(a + b*x))**m*(d/cos(a + b*x))**(-m + n)*ActivateTrig(u), x), x) def replacement4737(a, b, c, d, m, n, u, x): return Dist((c/tan(a + b*x))**m*(d/sin(a + b*x))**(-m)*(d/cos(a + b*x))**m, Int((d/sin(a + b*x))**(m + n)*(d/cos(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4738(a, b, c, m, u, x): return Dist((c/sin(a + b*x))**m*(c*sin(a + b*x))**m, Int((c/sin(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4739(a, b, c, m, u, x): return Dist((c/cos(a + b*x))**m*(c*cos(a + b*x))**m, Int((c/cos(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4740(a, b, c, m, u, x): return Dist((c/sin(a + b*x))**m*(c/cos(a + b*x))**(-m)*(c*tan(a + b*x))**m, Int((c/sin(a + b*x))**(-m)*(c/cos(a + b*x))**m*ActivateTrig(u), x), x) def replacement4741(a, b, c, m, u, x): return Dist((c/sin(a + b*x))**(-m)*(c/cos(a + b*x))**m*(c/tan(a + b*x))**m, Int((c/sin(a + b*x))**m*(c/cos(a + b*x))**(-m)*ActivateTrig(u), x), x) def replacement4742(A, B, a, b, c, n, u, x): return Dist(c, Int((c/cos(a + b*x))**(n + S(-1))*(A/cos(a + b*x) + B)*ActivateTrig(u), x), x) def replacement4743(A, B, a, b, c, n, u, x): return Dist(c, Int((c/sin(a + b*x))**(n + S(-1))*(A/sin(a + b*x) + B)*ActivateTrig(u), x), x) def replacement4744(A, B, a, b, u, x): return Int((A/cos(a + b*x) + B)*ActivateTrig(u)*cos(a + b*x), x) def replacement4745(A, B, a, b, u, x): return Int((A/sin(a + b*x) + B)*ActivateTrig(u)*sin(a + b*x), x) def replacement4746(A, B, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c/cos(a + b*x))**(n + S(-2))*(A/cos(a + b*x)**S(2) + B/cos(a + b*x) + C)*ActivateTrig(u), x), x) def replacement4747(A, B, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c/sin(a + b*x))**(n + S(-2))*(A/sin(a + b*x)**S(2) + B/sin(a + b*x) + C)*ActivateTrig(u), x), x) def replacement4748(A, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c/cos(a + b*x))**(n + S(-2))*(A/cos(a + b*x)**S(2) + C)*ActivateTrig(u), x), x) def replacement4749(A, C, a, b, c, n, u, x): return Dist(c**S(2), Int((c/sin(a + b*x))**(n + S(-2))*(A/sin(a + b*x)**S(2) + C)*ActivateTrig(u), x), x) def replacement4750(A, B, C, a, b, u, x): return Int((A/cos(a + b*x)**S(2) + B/cos(a + b*x) + C)*ActivateTrig(u)*cos(a + b*x)**S(2), x) def replacement4751(A, B, C, a, b, u, x): return Int((A/sin(a + b*x)**S(2) + B/sin(a + b*x) + C)*ActivateTrig(u)*sin(a + b*x)**S(2), x) def replacement4752(A, C, a, b, u, x): return Int((A/cos(a + b*x)**S(2) + C)*ActivateTrig(u)*cos(a + b*x)**S(2), x) def replacement4753(A, C, a, b, u, x): return Int((A/sin(a + b*x)**S(2) + C)*ActivateTrig(u)*sin(a + b*x)**S(2), x) def replacement4754(A, B, C, a, b, n, n1, n2, u, x): return Int((A + B/cos(a + b*x) + C/cos(a + b*x)**S(2))*(S(1)/cos(a + b*x))**n*ActivateTrig(u), x) def replacement4755(A, B, C, a, b, n, n1, n2, u, x): return Int((A + B/sin(a + b*x) + C/sin(a + b*x)**S(2))*(S(1)/sin(a + b*x))**n*ActivateTrig(u), x) def replacement4756(a, b, c, d, x): return Simp(sin(a - c + x*(b - d))/(S(2)*b - S(2)*d), x) - Simp(sin(a + c + x*(b + d))/(S(2)*b + S(2)*d), x) def replacement4757(a, b, c, d, x): return Simp(sin(a - c + x*(b - d))/(S(2)*b - S(2)*d), x) + Simp(sin(a + c + x*(b + d))/(S(2)*b + S(2)*d), x) def replacement4758(a, b, c, d, x): return -Simp(cos(a - c + x*(b - d))/(S(2)*b - S(2)*d), x) - Simp(cos(a + c + x*(b + d))/(S(2)*b + S(2)*d), x) def replacement4759(a, b, c, d, g, p, x): return Dist(S(1)/2, Int((g*sin(c + d*x))**p, x), x) + Dist(S(1)/2, Int((g*sin(c + d*x))**p*cos(c + d*x), x), x) def replacement4760(a, b, c, d, g, p, x): return Dist(S(1)/2, Int((g*sin(c + d*x))**p, x), x) - Dist(S(1)/2, Int((g*sin(c + d*x))**p*cos(c + d*x), x), x) def replacement4761(a, b, c, d, e, m, p, x): return Dist(S(2)**p*e**(-p), Int((e*cos(a + b*x))**(m + p)*sin(a + b*x)**p, x), x) def replacement4762(a, b, c, d, f, n, p, x): return Dist(S(2)**p*f**(-p), Int((f*sin(a + b*x))**(n + p)*cos(a + b*x)**p, x), x) def replacement4763(a, b, c, d, e, g, m, p, x): return Simp(e**S(2)*(e*cos(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(p + S(1))), x) def replacement4764(a, b, c, d, e, g, m, p, x): return -Simp(e**S(2)*(e*sin(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(p + S(1))), x) def replacement4765(a, b, c, d, e, g, m, p, x): return -Simp((e*cos(a + b*x))**m*(g*sin(c + d*x))**(p + S(1))/(b*g*m), x) def replacement4766(a, b, c, d, e, g, m, p, x): return Simp((e*sin(a + b*x))**m*(g*sin(c + d*x))**(p + S(1))/(b*g*m), x) def replacement4767(a, b, c, d, e, g, m, p, x): return Dist(e**S(4)*(m + p + S(-1))/(S(4)*g**S(2)*(p + S(1))), Int((e*cos(a + b*x))**(m + S(-4))*(g*sin(c + d*x))**(p + S(2)), x), x) + Simp(e**S(2)*(e*cos(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(p + S(1))), x) def replacement4768(a, b, c, d, e, g, m, p, x): return Dist(e**S(4)*(m + p + S(-1))/(S(4)*g**S(2)*(p + S(1))), Int((e*sin(a + b*x))**(m + S(-4))*(g*sin(c + d*x))**(p + S(2)), x), x) - Simp(e**S(2)*(e*sin(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(p + S(1))), x) def replacement4769(a, b, c, d, e, g, m, p, x): return Dist(e**S(2)*(m + S(2)*p + S(2))/(S(4)*g**S(2)*(p + S(1))), Int((e*cos(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(2)), x), x) + Simp((e*cos(a + b*x))**m*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(p + S(1))), x) def replacement4770(a, b, c, d, e, g, m, p, x): return Dist(e**S(2)*(m + S(2)*p + S(2))/(S(4)*g**S(2)*(p + S(1))), Int((e*sin(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(2)), x), x) - Simp((e*sin(a + b*x))**m*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(p + S(1))), x) def replacement4771(a, b, c, d, e, g, m, p, x): return Dist(e**S(2)*(m + p + S(-1))/(m + S(2)*p), Int((e*cos(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**p, x), x) + Simp(e**S(2)*(e*cos(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(m + S(2)*p)), x) def replacement4772(a, b, c, d, e, g, m, p, x): return Dist(e**S(2)*(m + p + S(-1))/(m + S(2)*p), Int((e*sin(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**p, x), x) - Simp(e**S(2)*(e*sin(a + b*x))**(m + S(-2))*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(m + S(2)*p)), x) def replacement4773(a, b, c, d, e, g, m, p, x): return Dist((m + S(2)*p + S(2))/(e**S(2)*(m + p + S(1))), Int((e*cos(a + b*x))**(m + S(2))*(g*sin(c + d*x))**p, x), x) - Simp((e*cos(a + b*x))**m*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(m + p + S(1))), x) def replacement4774(a, b, c, d, e, g, m, p, x): return Dist((m + S(2)*p + S(2))/(e**S(2)*(m + p + S(1))), Int((e*sin(a + b*x))**(m + S(2))*(g*sin(c + d*x))**p, x), x) + Simp((e*sin(a + b*x))**m*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(m + p + S(1))), x) def replacement4775(a, b, c, d, g, p, x): return Dist(S(2)*g*p/(S(2)*p + S(1)), Int((g*sin(c + d*x))**(p + S(-1))*sin(a + b*x), x), x) + Simp(S(2)*(g*sin(c + d*x))**p*sin(a + b*x)/(d*(S(2)*p + S(1))), x) def replacement4776(a, b, c, d, g, p, x): return Dist(S(2)*g*p/(S(2)*p + S(1)), Int((g*sin(c + d*x))**(p + S(-1))*cos(a + b*x), x), x) + Simp(-S(2)*(g*sin(c + d*x))**p*cos(a + b*x)/(d*(S(2)*p + S(1))), x) def replacement4777(a, b, c, d, g, p, x): return Dist((S(2)*p + S(3))/(S(2)*g*(p + S(1))), Int((g*sin(c + d*x))**(p + S(1))*sin(a + b*x), x), x) + Simp((g*sin(c + d*x))**(p + S(1))*cos(a + b*x)/(S(2)*b*g*(p + S(1))), x) def replacement4778(a, b, c, d, g, p, x): return Dist((S(2)*p + S(3))/(S(2)*g*(p + S(1))), Int((g*sin(c + d*x))**(p + S(1))*cos(a + b*x), x), x) - Simp((g*sin(c + d*x))**(p + S(1))*sin(a + b*x)/(S(2)*b*g*(p + S(1))), x) def replacement4779(a, b, c, d, x): return Simp(log(sin(a + b*x) + sqrt(sin(c + d*x)) + cos(a + b*x))/d, x) - Simp(-asin(sin(a + b*x) - cos(a + b*x))/d, x) def replacement4780(a, b, c, d, x): return -Simp(log(sin(a + b*x) + sqrt(sin(c + d*x)) + cos(a + b*x))/d, x) - Simp(-asin(sin(a + b*x) - cos(a + b*x))/d, x) def replacement4781(a, b, c, d, g, p, x): return Dist(S(2)*g, Int((g*sin(c + d*x))**(p + S(-1))*sin(a + b*x), x), x) def replacement4782(a, b, c, d, g, p, x): return Dist(S(2)*g, Int((g*sin(c + d*x))**(p + S(-1))*cos(a + b*x), x), x) def replacement4783(a, b, c, d, e, g, m, p, x): return Dist((e*cos(a + b*x))**(-p)*(g*sin(c + d*x))**p*sin(a + b*x)**(-p), Int((e*cos(a + b*x))**(m + p)*sin(a + b*x)**p, x), x) def replacement4784(a, b, c, d, f, g, n, p, x): return Dist((f*sin(a + b*x))**(-p)*(g*sin(c + d*x))**p*cos(a + b*x)**(-p), Int((f*sin(a + b*x))**(n + p)*cos(a + b*x)**p, x), x) def replacement4785(a, b, c, d, g, p, x): return Dist(S(1)/4, Int((g*sin(c + d*x))**p, x), x) - Dist(S(1)/4, Int((g*sin(c + d*x))**p*cos(c + d*x)**S(2), x), x) def replacement4786(a, b, c, d, e, f, m, n, p, x): return Dist(S(2)**p*e**(-p)*f**(-p), Int((e*cos(a + b*x))**(m + p)*(f*sin(a + b*x))**(n + p), x), x) def replacement4787(a, b, c, d, e, f, g, m, n, p, x): return Simp(e*(e*cos(a + b*x))**(m + S(-1))*(f*sin(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*f*(n + p + S(1))), x) def replacement4788(a, b, c, d, e, f, g, m, n, p, x): return -Simp(e*(e*sin(a + b*x))**(m + S(-1))*(f*cos(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*f*(n + p + S(1))), x) def replacement4789(a, b, c, d, e, f, g, m, n, p, x): return -Simp((e*cos(a + b*x))**(m + S(1))*(f*sin(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*e*f*(m + p + S(1))), x) def replacement4790(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(4)*(m + p + S(-1))/(S(4)*g**S(2)*(n + p + S(1))), Int((e*cos(a + b*x))**(m + S(-4))*(f*sin(a + b*x))**n*(g*sin(c + d*x))**(p + S(2)), x), x) + Simp(e**S(2)*(e*cos(a + b*x))**(m + S(-2))*(f*sin(a + b*x))**n*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(n + p + S(1))), x) def replacement4791(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(4)*(m + p + S(-1))/(S(4)*g**S(2)*(n + p + S(1))), Int((e*sin(a + b*x))**(m + S(-4))*(f*cos(a + b*x))**n*(g*sin(c + d*x))**(p + S(2)), x), x) - Simp(e**S(2)*(e*sin(a + b*x))**(m + S(-2))*(f*cos(a + b*x))**n*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(n + p + S(1))), x) def replacement4792(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*(m + n + S(2)*p + S(2))/(S(4)*g**S(2)*(n + p + S(1))), Int((e*cos(a + b*x))**(m + S(-2))*(f*sin(a + b*x))**n*(g*sin(c + d*x))**(p + S(2)), x), x) + Simp((e*cos(a + b*x))**m*(f*sin(a + b*x))**n*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(n + p + S(1))), x) def replacement4793(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*(m + n + S(2)*p + S(2))/(S(4)*g**S(2)*(n + p + S(1))), Int((e*sin(a + b*x))**(m + S(-2))*(f*cos(a + b*x))**n*(g*sin(c + d*x))**(p + S(2)), x), x) - Simp((e*sin(a + b*x))**m*(f*cos(a + b*x))**n*(g*sin(c + d*x))**(p + S(1))/(S(2)*b*g*(n + p + S(1))), x) def replacement4794(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*(m + p + S(-1))/(f**S(2)*(n + p + S(1))), Int((e*cos(a + b*x))**(m + S(-2))*(f*sin(a + b*x))**(n + S(2))*(g*sin(c + d*x))**p, x), x) + Simp(e*(e*cos(a + b*x))**(m + S(-1))*(f*sin(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*f*(n + p + S(1))), x) def replacement4795(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*(m + p + S(-1))/(f**S(2)*(n + p + S(1))), Int((e*sin(a + b*x))**(m + S(-2))*(f*cos(a + b*x))**(n + S(2))*(g*sin(c + d*x))**p, x), x) - Simp(e*(e*sin(a + b*x))**(m + S(-1))*(f*cos(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*f*(n + p + S(1))), x) def replacement4796(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*(m + p + S(-1))/(m + n + S(2)*p), Int((e*cos(a + b*x))**(m + S(-2))*(f*sin(a + b*x))**n*(g*sin(c + d*x))**p, x), x) + Simp(e*(e*cos(a + b*x))**(m + S(-1))*(f*sin(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*f*(m + n + S(2)*p)), x) def replacement4797(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*(m + p + S(-1))/(m + n + S(2)*p), Int((e*sin(a + b*x))**(m + S(-2))*(f*cos(a + b*x))**n*(g*sin(c + d*x))**p, x), x) - Simp(e*(e*sin(a + b*x))**(m + S(-1))*(f*cos(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*f*(m + n + S(2)*p)), x) def replacement4798(a, b, c, d, e, f, g, m, n, p, x): return Dist(S(2)*f*g*(n + p + S(-1))/(e*(m + n + S(2)*p)), Int((e*cos(a + b*x))**(m + S(1))*(f*sin(a + b*x))**(n + S(-1))*(g*sin(c + d*x))**(p + S(-1)), x), x) - Simp(f*(e*cos(a + b*x))**(m + S(1))*(f*sin(a + b*x))**(n + S(-1))*(g*sin(c + d*x))**p/(b*e*(m + n + S(2)*p)), x) def replacement4799(a, b, c, d, e, f, g, m, n, p, x): return Dist(S(2)*f*g*(n + p + S(-1))/(e*(m + n + S(2)*p)), Int((e*sin(a + b*x))**(m + S(1))*(f*cos(a + b*x))**(n + S(-1))*(g*sin(c + d*x))**(p + S(-1)), x), x) + Simp(f*(e*sin(a + b*x))**(m + S(1))*(f*cos(a + b*x))**(n + S(-1))*(g*sin(c + d*x))**p/(b*e*(m + n + S(2)*p)), x) def replacement4800(a, b, c, d, e, f, g, m, n, p, x): return Dist(f*(m + n + S(2)*p + S(2))/(S(2)*e*g*(m + p + S(1))), Int((e*cos(a + b*x))**(m + S(1))*(f*sin(a + b*x))**(n + S(-1))*(g*sin(c + d*x))**(p + S(1)), x), x) - Simp((e*cos(a + b*x))**(m + S(1))*(f*sin(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*e*f*(m + p + S(1))), x) def replacement4801(a, b, c, d, e, f, g, m, n, p, x): return Dist(f*(m + n + S(2)*p + S(2))/(S(2)*e*g*(m + p + S(1))), Int((e*sin(a + b*x))**(m + S(1))*(f*cos(a + b*x))**(n + S(-1))*(g*sin(c + d*x))**(p + S(1)), x), x) + Simp((e*sin(a + b*x))**(m + S(1))*(f*cos(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*e*f*(m + p + S(1))), x) def replacement4802(a, b, c, d, e, f, g, m, n, p, x): return Dist((m + n + S(2)*p + S(2))/(e**S(2)*(m + p + S(1))), Int((e*cos(a + b*x))**(m + S(2))*(f*sin(a + b*x))**n*(g*sin(c + d*x))**p, x), x) - Simp((e*cos(a + b*x))**(m + S(1))*(f*sin(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*e*f*(m + p + S(1))), x) def replacement4803(a, b, c, d, e, f, g, m, n, p, x): return Dist((m + n + S(2)*p + S(2))/(e**S(2)*(m + p + S(1))), Int((e*sin(a + b*x))**(m + S(2))*(f*cos(a + b*x))**n*(g*sin(c + d*x))**p, x), x) + Simp((e*sin(a + b*x))**(m + S(1))*(f*cos(a + b*x))**(n + S(1))*(g*sin(c + d*x))**p/(b*e*f*(m + p + S(1))), x) def replacement4804(a, b, c, d, e, f, g, m, n, p, x): return Dist((e*cos(a + b*x))**(-p)*(f*sin(a + b*x))**(-p)*(g*sin(c + d*x))**p, Int((e*cos(a + b*x))**(m + p)*(f*sin(a + b*x))**(n + p), x), x) def replacement4805(a, b, c, d, e, m, x): return -Simp((e*cos(a + b*x))**(m + S(1))*(m + S(2))*cos((a + b*x)*(m + S(1)))/(d*e*(m + S(1))), x) def replacement4806(F, a, b, c, d, n, p, x): return Int((a + b*F(c + d*x)**n)**p, x) def replacement4807(F, a, b, c, d, n, x): return Dist(S(2)/(a*n), Sum_doit(Int(S(1)/(S(1) - (S(-1))**(-S(4)*k/n)*F(c + d*x)**S(2)/Rt(-a/b, n/S(2))), x), List(k, S(1), n/S(2))), x) def replacement4808(F, a, b, c, d, n, x): return Int(ExpandTrig(S(1)/(a + b*F(c + d*x)**n), x), x) def replacement4809(F, G, a, b, c, d, m, n, x): return Int(ExpandTrig(G(c + d*x)**m, S(1)/(a + b*F(c + d*x)**n), x), x) def With4810(F, a, c, d, n, p, x): v = ActivateTrig(F(c + d*x)) return Dist(a**IntPart(n)*(a*v**p)**FracPart(n)*(v/NonfreeFactors(v, x))**(p*IntPart(n))*NonfreeFactors(v, x)**(-p*FracPart(n)), Int(NonfreeFactors(v, x)**(n*p), x), x) def With4811(F, a, b, c, d, n, p, x): v = ActivateTrig(F(c + d*x)) return Dist(a**IntPart(n)*(a*(b*v)**p)**FracPart(n)*(b*v)**(-p*FracPart(n)), Int((b*v)**(n*p), x), x) def With4812(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/d, u, x, True): return True return False def replacement4812(F, a, b, c, u, x): d = FreeFactors(sin(c*(a + b*x)), x) return Dist(d/(b*c), Subst(Int(SubstFor(S(1), sin(c*(a + b*x))/d, u, x), x), x, sin(c*(a + b*x))/d), x) def With4813(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/d, u, x, True): return True return False def replacement4813(F, a, b, c, u, x): d = FreeFactors(cos(c*(a + b*x)), x) return -Dist(d/(b*c), Subst(Int(SubstFor(S(1), cos(c*(a + b*x))/d, u, x), x), x, cos(c*(a + b*x))/d), x) def With4814(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/d, u, x, True): return True return False def replacement4814(F, a, b, c, u, x): d = FreeFactors(sin(c*(a + b*x)), x) return Dist(S(1)/(b*c), Subst(Int(SubstFor(S(1)/x, sin(c*(a + b*x))/d, u, x), x), x, sin(c*(a + b*x))/d), x) def With4815(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/d, u, x, True): return True return False def replacement4815(F, a, b, c, u, x): d = FreeFactors(cos(c*(a + b*x)), x) return -Dist(S(1)/(b*c), Subst(Int(SubstFor(S(1)/x, cos(c*(a + b*x))/d, u, x), x), x, cos(c*(a + b*x))/d), x) def With4816(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(tan(c*(a + b*x)), x) if FunctionOfQ(tan(c*(a + b*x))/d, u, x, True): return True return False def replacement4816(F, a, b, c, u, x): d = FreeFactors(tan(c*(a + b*x)), x) return Dist(d/(b*c), Subst(Int(SubstFor(S(1), tan(c*(a + b*x))/d, u, x), x), x, tan(c*(a + b*x))/d), x) def With4817(a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(tan(c*(a + b*x)), x) if FunctionOfQ(tan(c*(a + b*x))/d, u, x, True): return True return False def replacement4817(a, b, c, u, x): d = FreeFactors(tan(c*(a + b*x)), x) return Dist(d/(b*c), Subst(Int(SubstFor(S(1), tan(c*(a + b*x))/d, u, x), x), x, tan(c*(a + b*x))/d), x) def With4818(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(S(1)/tan(c*(a + b*x)), x) if FunctionOfQ(S(1)/(d*tan(c*(a + b*x))), u, x, True): return True return False def replacement4818(F, a, b, c, u, x): d = FreeFactors(S(1)/tan(c*(a + b*x)), x) return -Dist(d/(b*c), Subst(Int(SubstFor(S(1), S(1)/(d*tan(c*(a + b*x))), u, x), x), x, S(1)/(d*tan(c*(a + b*x)))), x) def With4819(a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(S(1)/tan(c*(a + b*x)), x) if FunctionOfQ(S(1)/(d*tan(c*(a + b*x))), u, x, True): return True return False def replacement4819(a, b, c, u, x): d = FreeFactors(S(1)/tan(c*(a + b*x)), x) return -Dist(d/(b*c), Subst(Int(SubstFor(S(1), S(1)/(d*tan(c*(a + b*x))), u, x), x), x, S(1)/(d*tan(c*(a + b*x)))), x) def With4820(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(tan(c*(a + b*x)), x) if And(FunctionOfQ(tan(c*(a + b*x))/d, u, x, True), TryPureTanSubst((S(1)/tan(c*(a + b*x)))**n*ActivateTrig(u), x)): return True return False def replacement4820(F, a, b, c, n, u, x): d = FreeFactors(tan(c*(a + b*x)), x) return Dist(d**(S(1) - n)/(b*c), Subst(Int(SubstFor(x**(-n)/(d**S(2)*x**S(2) + S(1)), tan(c*(a + b*x))/d, u, x), x), x, tan(c*(a + b*x))/d), x) def With4821(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(S(1)/tan(c*(a + b*x)), x) if And(FunctionOfQ(S(1)/(d*tan(c*(a + b*x))), u, x, True), TryPureTanSubst(ActivateTrig(u)*tan(c*(a + b*x))**n, x)): return True return False def replacement4821(F, a, b, c, n, u, x): d = FreeFactors(S(1)/tan(c*(a + b*x)), x) return -Dist(d**(S(1) - n)/(b*c), Subst(Int(SubstFor(x**(-n)/(d**S(2)*x**S(2) + S(1)), S(1)/(d*tan(c*(a + b*x))), u, x), x), x, S(1)/(d*tan(c*(a + b*x)))), x) def With4822(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: v = FunctionOfTrig(u, x) d = FreeFactors(S(1)/tan(v), x) res = And(Not(FalseQ(v)), FunctionOfQ(NonfreeFactors(S(1)/tan(v), x), u, x, True), TryPureTanSubst(ActivateTrig(u), x)) except (TypeError, AttributeError): return False if res: return True return False def replacement4822(u, x): v = FunctionOfTrig(u, x) d = FreeFactors(S(1)/tan(v), x) return Simp(With(List(Set(d, FreeFactors(S(1)/tan(v), x))), Dist(-d/Coefficient(v, x, S(1)), Subst(Int(SubstFor(S(1)/(d**S(2)*x**S(2) + S(1)), S(1)/(d*tan(v)), u, x), x), x, S(1)/(d*tan(v))), x)), x) def With4823(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: v = FunctionOfTrig(u, x) d = FreeFactors(tan(v), x) res = And(Not(FalseQ(v)), FunctionOfQ(NonfreeFactors(tan(v), x), u, x, True), TryPureTanSubst(ActivateTrig(u), x)) except (TypeError, AttributeError): return False if res: return True return False def replacement4823(u, x): v = FunctionOfTrig(u, x) d = FreeFactors(tan(v), x) return Simp(With(List(Set(d, FreeFactors(tan(v), x))), Dist(d/Coefficient(v, x, S(1)), Subst(Int(SubstFor(S(1)/(d**S(2)*x**S(2) + S(1)), tan(v)/d, u, x), x), x, tan(v)/d), x)), x) def replacement4824(F, G, a, b, c, d, p, q, x): return Int(ExpandTrigReduce(ActivateTrig(F(a + b*x)**p*G(c + d*x)**q), x), x) def replacement4825(F, G, H, a, b, c, d, e, f, p, q, r, x): return Int(ExpandTrigReduce(ActivateTrig(F(a + b*x)**p*G(c + d*x)**q*H(e + f*x)**r), x), x) def With4826(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/d, u, x): return True return False def replacement4826(F, a, b, c, u, x): d = FreeFactors(sin(c*(a + b*x)), x) return Dist(d/(b*c), Subst(Int(SubstFor(S(1), sin(c*(a + b*x))/d, u, x), x), x, sin(c*(a + b*x))/d), x) def With4827(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/d, u, x): return True return False def replacement4827(F, a, b, c, u, x): d = FreeFactors(cos(c*(a + b*x)), x) return -Dist(d/(b*c), Subst(Int(SubstFor(S(1), cos(c*(a + b*x))/d, u, x), x), x, cos(c*(a + b*x))/d), x) def With4828(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/d, u, x): return True return False def replacement4828(F, a, b, c, u, x): d = FreeFactors(sin(c*(a + b*x)), x) return Dist(S(1)/(b*c), Subst(Int(SubstFor(S(1)/x, sin(c*(a + b*x))/d, u, x), x), x, sin(c*(a + b*x))/d), x) def With4829(F, a, b, c, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/d, u, x): return True return False def replacement4829(F, a, b, c, u, x): d = FreeFactors(cos(c*(a + b*x)), x) return -Dist(S(1)/(b*c), Subst(Int(SubstFor(S(1)/x, cos(c*(a + b*x))/d, u, x), x), x, cos(c*(a + b*x))/d), x) def With4830(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/d, u, x): return True return False def replacement4830(F, a, b, c, n, u, x): d = FreeFactors(sin(c*(a + b*x)), x) return Dist(d/(b*c), Subst(Int(SubstFor((-d**S(2)*x**S(2) + S(1))**(n/S(2) + S(-1)/2), sin(c*(a + b*x))/d, u, x), x), x, sin(c*(a + b*x))/d), x) def With4831(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/d, u, x): return True return False def replacement4831(F, a, b, c, n, u, x): d = FreeFactors(sin(c*(a + b*x)), x) return Dist(d/(b*c), Subst(Int(SubstFor((-d**S(2)*x**S(2) + S(1))**(-n/S(2) + S(-1)/2), sin(c*(a + b*x))/d, u, x), x), x, sin(c*(a + b*x))/d), x) def With4832(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/d, u, x): return True return False def replacement4832(F, a, b, c, n, u, x): d = FreeFactors(cos(c*(a + b*x)), x) return -Dist(d/(b*c), Subst(Int(SubstFor((-d**S(2)*x**S(2) + S(1))**(n/S(2) + S(-1)/2), cos(c*(a + b*x))/d, u, x), x), x, cos(c*(a + b*x))/d), x) def With4833(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/d, u, x): return True return False def replacement4833(F, a, b, c, n, u, x): d = FreeFactors(cos(c*(a + b*x)), x) return -Dist(d/(b*c), Subst(Int(SubstFor((-d**S(2)*x**S(2) + S(1))**(-n/S(2) + S(-1)/2), cos(c*(a + b*x))/d, u, x), x), x, cos(c*(a + b*x))/d), x) def With4834(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/d, u, x): return True return False def replacement4834(F, a, b, c, n, u, x): d = FreeFactors(sin(c*(a + b*x)), x) return Dist(d**(S(1) - n)/(b*c), Subst(Int(SubstFor(x**(-n)*(-d**S(2)*x**S(2) + S(1))**(n/S(2) + S(-1)/2), sin(c*(a + b*x))/d, u, x), x), x, sin(c*(a + b*x))/d), x) def With4835(F, a, b, c, n, u, x): if isinstance(x, (int, Integer, float, Float)): return False d = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/d, u, x): return True return False def replacement4835(F, a, b, c, n, u, x): d = FreeFactors(cos(c*(a + b*x)), x) return -Dist(d**(S(1) - n)/(b*c), Subst(Int(SubstFor(x**(-n)*(-d**S(2)*x**S(2) + S(1))**(n/S(2) + S(-1)/2), cos(c*(a + b*x))/d, u, x), x), x, cos(c*(a + b*x))/d), x) def With4836(F, a, b, c, d, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False e = FreeFactors(sin(c*(a + b*x)), x) if FunctionOfQ(sin(c*(a + b*x))/e, u, x): return True return False def replacement4836(F, a, b, c, d, n, u, v, x): e = FreeFactors(sin(c*(a + b*x)), x) return Dist(d, Int(ActivateTrig(u)*cos(c*(a + b*x))**n, x), x) + Int(ActivateTrig(u*v), x) def With4837(F, a, b, c, d, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False e = FreeFactors(cos(c*(a + b*x)), x) if FunctionOfQ(cos(c*(a + b*x))/e, u, x): return True return False def replacement4837(F, a, b, c, d, n, u, v, x): e = FreeFactors(cos(c*(a + b*x)), x) return Dist(d, Int(ActivateTrig(u)*sin(c*(a + b*x))**n, x), x) + Int(ActivateTrig(u*v), x) def With4838(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: v = FunctionOfTrig(u, x) d = FreeFactors(sin(v), x) res = And(Not(FalseQ(v)), FunctionOfQ(NonfreeFactors(sin(v), x), u/cos(v), x)) except (TypeError, AttributeError): return False if res: return True return False def replacement4838(u, x): v = FunctionOfTrig(u, x) d = FreeFactors(sin(v), x) return Simp(With(List(Set(d, FreeFactors(sin(v), x))), Dist(d/Coefficient(v, x, S(1)), Subst(Int(SubstFor(S(1), sin(v)/d, u/cos(v), x), x), x, sin(v)/d), x)), x) def With4839(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: v = FunctionOfTrig(u, x) d = FreeFactors(cos(v), x) res = And(Not(FalseQ(v)), FunctionOfQ(NonfreeFactors(cos(v), x), u/sin(v), x)) except (TypeError, AttributeError): return False if res: return True return False def replacement4839(u, x): v = FunctionOfTrig(u, x) d = FreeFactors(cos(v), x) return Simp(With(List(Set(d, FreeFactors(cos(v), x))), Dist(-d/Coefficient(v, x, S(1)), Subst(Int(SubstFor(S(1), cos(v)/d, u/sin(v), x), x), x, cos(v)/d), x)), x) def replacement4840(a, b, c, d, e, p, u, x): return Dist((a + c)**p, Int(ActivateTrig(u), x), x) def replacement4841(a, b, c, d, e, p, u, x): return Dist((a + c)**p, Int(ActivateTrig(u), x), x) def replacement4842(a, b, c, d, e, p, u, x): return Dist((a + c)**p, Int(ActivateTrig(u), x), x) def With4843(u, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(ActivateTrig(y), ActivateTrig(u), x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement4843(u, x, y): q = DerivativeDivides(ActivateTrig(y), ActivateTrig(u), x) return Simp(q*log(RemoveContent(ActivateTrig(y), x)), x) def With4844(u, w, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(ActivateTrig(w*y), ActivateTrig(u), x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement4844(u, w, x, y): q = DerivativeDivides(ActivateTrig(w*y), ActivateTrig(u), x) return Simp(q*log(RemoveContent(ActivateTrig(w*y), x)), x) def With4845(m, u, x, y): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(ActivateTrig(y), ActivateTrig(u), x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement4845(m, u, x, y): q = DerivativeDivides(ActivateTrig(y), ActivateTrig(u), x) return Simp(q*ActivateTrig(y**(m + S(1)))/(m + S(1)), x) def With4846(m, n, u, x, y, z): if isinstance(x, (int, Integer, float, Float)): return False try: q = DerivativeDivides(ActivateTrig(y*z), ActivateTrig(u*z**(-m + n)), x) res = Not(FalseQ(q)) except (TypeError, AttributeError): return False if res: return True return False def replacement4846(m, n, u, x, y, z): q = DerivativeDivides(ActivateTrig(y*z), ActivateTrig(u*z**(-m + n)), x) return Simp(q*ActivateTrig(y**(m + S(1))*z**(m + S(1)))/(m + S(1)), x) def With4847(F, a, c, d, n, p, u, x): v = ActivateTrig(F(c + d*x)) return Dist(a**IntPart(n)*(a*v**p)**FracPart(n)*(v/NonfreeFactors(v, x))**(p*IntPart(n))*NonfreeFactors(v, x)**(-p*FracPart(n)), Int(ActivateTrig(u)*NonfreeFactors(v, x)**(n*p), x), x) def With4848(F, a, b, c, d, n, p, u, x): v = ActivateTrig(F(c + d*x)) return Dist(a**IntPart(n)*(a*(b*v)**p)**FracPart(n)*(b*v)**(-p*FracPart(n)), Int((b*v)**(n*p)*ActivateTrig(u), x), x) def With4849(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: v = FunctionOfTrig(u, x) d = FreeFactors(tan(v), x) res = And(Not(FalseQ(v)), FunctionOfQ(NonfreeFactors(tan(v), x), u, x)) except (TypeError, AttributeError): return False if res: return True return False def replacement4849(u, x): v = FunctionOfTrig(u, x) d = FreeFactors(tan(v), x) return Dist(d/Coefficient(v, x, 1), Subst(Int(SubstFor(1/(d**2*x**2 + 1), tan(v)/d, u, x), x), x, tan(v)/d), x) def replacement4850(a, b, c, d, n, p, u, x): return Int((a*sin(c + d*x)**n + b)**p*(S(1)/cos(c + d*x))**(n*p)*ActivateTrig(u), x) def replacement4851(a, b, c, d, n, p, u, x): return Int((a*cos(c + d*x)**n + b)**p*(S(1)/sin(c + d*x))**(n*p)*ActivateTrig(u), x) def replacement4852(F, a, b, c, d, n, p, q, u, x): return Int(ActivateTrig(u*(a + b*F(c + d*x)**(-p + q))**n*F(c + d*x)**(n*p)), x) def replacement4853(F, a, b, c, d, e, n, p, q, r, u, x): return Int(ActivateTrig(u*(a + b*F(d + e*x)**(-p + q) + c*F(d + e*x)**(-p + r))**n*F(d + e*x)**(n*p)), x) def replacement4854(F, a, b, c, d, e, n, p, q, u, x): return Int(ActivateTrig(u*(a*F(d + e*x)**(-p) + b + c*F(d + e*x)**(-p + q))**n*F(d + e*x)**(n*p)), x) def replacement4855(a, b, c, d, n, u, x): return Int((a*exp(-a*(c + d*x)/b))**n*ActivateTrig(u), x) def replacement4856(u, x): return Int(TrigSimplify(u), x) def With4857(a, p, u, v, x): uu = ActivateTrig(u) vv = ActivateTrig(v) return Dist(a**IntPart(p)*vv**(-FracPart(p))*(a*vv)**FracPart(p), Int(uu*vv**p, x), x) def With4858(m, p, u, v, x): uu = ActivateTrig(u) vv = ActivateTrig(v) return Dist(vv**(-m*FracPart(p))*(vv**m)**FracPart(p), Int(uu*vv**(m*p), x), x) def With4859(m, n, p, u, v, w, x): uu = ActivateTrig(u) vv = ActivateTrig(v) ww = ActivateTrig(w) return Dist(vv**(-m*FracPart(p))*ww**(-n*FracPart(p))*(vv**m*ww**n)**FracPart(p), Int(uu*vv**(m*p)*ww**(n*p), x), x) def With4860(u, x): if isinstance(x, (int, Integer, float, Float)): return False v = ExpandTrig(u, x) if SumQ(v): return True return False def replacement4860(u, x): v = ExpandTrig(u, x) return Int(v, x) def With4861(u, x): if isinstance(x, (int, Integer, float, Float)): return False try: w = With(List(Set(ShowSteps, False), Set(StepCounter, Null)), Int(SubstFor(S(1)/(x**S(2)*FreeFactors(tan(FunctionOfTrig(u, x)/S(2)), x)**S(2) + S(1)), tan(FunctionOfTrig(u, x)/S(2))/FreeFactors(tan(FunctionOfTrig(u, x)/S(2)), x), u, x), x)) v = FunctionOfTrig(u, x) d = FreeFactors(tan(v/S(2)), x) res = FreeQ(w, Int) except (TypeError, AttributeError): return False if res: return True return False def replacement4861(u, x): w = With(List(Set(ShowSteps, False), Set(StepCounter, Null)), Int(SubstFor(S(1)/(x**S(2)*FreeFactors(tan(FunctionOfTrig(u, x)/S(2)), x)**S(2) + S(1)), tan(FunctionOfTrig(u, x)/S(2))/FreeFactors(tan(FunctionOfTrig(u, x)/S(2)), x), u, x), x)) v = FunctionOfTrig(u, x) d = FreeFactors(tan(v/S(2)), x) return Simp(Dist(2*d/Coefficient(v, x, 1), Subst(Int(SubstFor(1/(d**2*x**2 + 1), tan(v/2)/d, u, x), x), x, tan(v/2)/d), x), x) def With4862(u, x): v = ActivateTrig(u) return Int(v, x) def replacement4863(a, b, c, d, m, n, x): return -Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*sin(a + b*x)**(n + S(1)), x), x) + Simp((c + d*x)**m*sin(a + b*x)**(n + S(1))/(b*(n + S(1))), x) def replacement4864(a, b, c, d, m, n, x): return Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*cos(a + b*x)**(n + S(1)), x), x) - Simp((c + d*x)**m*cos(a + b*x)**(n + S(1))/(b*(n + S(1))), x) def replacement4865(a, b, c, d, m, n, p, x): return Int(ExpandTrigReduce((c + d*x)**m, sin(a + b*x)**n*cos(a + b*x)**p, x), x) def replacement4866(a, b, c, d, m, n, p, x): return -Int((c + d*x)**m*sin(a + b*x)**n*tan(a + b*x)**(p + S(-2)), x) + Int((c + d*x)**m*sin(a + b*x)**(n + S(-2))*tan(a + b*x)**p, x) def replacement4867(a, b, c, d, m, n, p, x): return Int((c + d*x)**m*(S(1)/tan(a + b*x))**p*cos(a + b*x)**(n + S(-2)), x) - Int((c + d*x)**m*(S(1)/tan(a + b*x))**(p + S(-2))*cos(a + b*x)**n, x) def replacement4868(a, b, c, d, m, n, p, x): return -Dist(d*m/(b*n), Int((c + d*x)**(m + S(-1))*(S(1)/cos(a + b*x))**n, x), x) + Simp((c + d*x)**m*(S(1)/cos(a + b*x))**n/(b*n), x) def replacement4869(a, b, c, d, m, n, p, x): return Dist(d*m/(b*n), Int((c + d*x)**(m + S(-1))*(S(1)/sin(a + b*x))**n, x), x) - Simp((c + d*x)**m*(S(1)/sin(a + b*x))**n/(b*n), x) def replacement4870(a, b, c, d, m, n, x): return -Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*tan(a + b*x)**(n + S(1)), x), x) + Simp((c + d*x)**m*tan(a + b*x)**(n + S(1))/(b*(n + S(1))), x) def replacement4871(a, b, c, d, m, n, x): return Dist(d*m/(b*(n + S(1))), Int((c + d*x)**(m + S(-1))*(S(1)/tan(a + b*x))**(n + S(1)), x), x) - Simp((c + d*x)**m*(S(1)/tan(a + b*x))**(n + S(1))/(b*(n + S(1))), x) def replacement4872(a, b, c, d, m, p, x): return Int((c + d*x)**m*tan(a + b*x)**(p + S(-2))/cos(a + b*x)**S(3), x) - Int((c + d*x)**m*tan(a + b*x)**(p + S(-2))/cos(a + b*x), x) def replacement4873(a, b, c, d, m, n, p, x): return -Int((c + d*x)**m*(S(1)/cos(a + b*x))**n*tan(a + b*x)**(p + S(-2)), x) + Int((c + d*x)**m*(S(1)/cos(a + b*x))**(n + S(2))*tan(a + b*x)**(p + S(-2)), x) def replacement4874(a, b, c, d, m, p, x): return Int((c + d*x)**m*(S(1)/tan(a + b*x))**(p + S(-2))/sin(a + b*x)**S(3), x) - Int((c + d*x)**m*(S(1)/tan(a + b*x))**(p + S(-2))/sin(a + b*x), x) def replacement4875(a, b, c, d, m, n, p, x): return -Int((c + d*x)**m*(S(1)/sin(a + b*x))**n*(S(1)/tan(a + b*x))**(p + S(-2)), x) + Int((c + d*x)**m*(S(1)/sin(a + b*x))**(n + S(2))*(S(1)/tan(a + b*x))**(p + S(-2)), x) def With4876(a, b, c, d, m, n, p, x): u = IntHide((S(1)/cos(a + b*x))**n*tan(a + b*x)**p, x) return -Dist(d*m, Int(u*(c + d*x)**(m + S(-1)), x), x) + Dist((c + d*x)**m, u, x) def With4877(a, b, c, d, m, n, p, x): u = IntHide((S(1)/sin(a + b*x))**n*(S(1)/tan(a + b*x))**p, x) return -Dist(d*m, Int(u*(c + d*x)**(m + S(-1)), x), x) + Dist((c + d*x)**m, u, x) def replacement4878(a, b, c, d, m, n, x): return Dist(S(2)**n, Int((c + d*x)**m*(S(1)/sin(S(2)*a + S(2)*b*x))**n, x), x) def With4879(a, b, c, d, m, n, p, x): u = IntHide((S(1)/sin(a + b*x))**n*(S(1)/cos(a + b*x))**p, x) return -Dist(d*m, Int(u*(c + d*x)**(m + S(-1)), x), x) + Dist((c + d*x)**m, u, x) def replacement4880(F, G, m, n, p, u, v, w, x): return Int(ExpandToSum(u, x)**m*F(ExpandToSum(v, x))**n*G(ExpandToSum(v, x))**p, x) def replacement4881(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*d*(n + S(1))), Int((a + b*sin(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) + Simp((a + b*sin(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement4882(a, b, c, d, e, f, m, n, x): return Dist(f*m/(b*d*(n + S(1))), Int((a + b*cos(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) - Simp((a + b*cos(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement4883(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*d*(n + S(1))), Int((a + b*tan(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) + Simp((a + b*tan(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement4884(a, b, c, d, e, f, m, n, x): return Dist(f*m/(b*d*(n + S(1))), Int((a + b/tan(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) - Simp((a + b/tan(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement4885(a, b, c, d, e, f, m, n, x): return -Dist(f*m/(b*d*(n + S(1))), Int((a + b/cos(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) + Simp((a + b/cos(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement4886(a, b, c, d, e, f, m, n, x): return Dist(f*m/(b*d*(n + S(1))), Int((a + b/sin(c + d*x))**(n + S(1))*(e + f*x)**(m + S(-1)), x), x) - Simp((a + b/sin(c + d*x))**(n + S(1))*(e + f*x)**m/(b*d*(n + S(1))), x) def replacement4887(a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigReduce((e + f*x)**m, sin(a + b*x)**p*sin(c + d*x)**q, x), x) def replacement4888(a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigReduce((e + f*x)**m, cos(a + b*x)**p*cos(c + d*x)**q, x), x) def replacement4889(a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigReduce((e + f*x)**m, sin(a + b*x)**p*cos(c + d*x)**q, x), x) def replacement4890(F, G, a, b, c, d, e, f, m, p, q, x): return Int(ExpandTrigExpand((e + f*x)**m*G(c + d*x)**q, F, c + d*x, p, b/d, x), x) def replacement4891(F, a, b, c, d, e, x): return -Simp(F**(c*(a + b*x))*e*cos(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) + Simp(F**(c*(a + b*x))*b*c*log(F)*sin(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) def replacement4892(F, a, b, c, d, e, x): return Simp(F**(c*(a + b*x))*e*sin(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) + Simp(F**(c*(a + b*x))*b*c*log(F)*cos(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)), x) def replacement4893(F, a, b, c, d, e, n, x): return Dist(e**S(2)*n*(n + S(-1))/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), Int(F**(c*(a + b*x))*sin(d + e*x)**(n + S(-2)), x), x) + Simp(F**(c*(a + b*x))*b*c*log(F)*sin(d + e*x)**n/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) - Simp(F**(c*(a + b*x))*e*n*sin(d + e*x)**(n + S(-1))*cos(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) def replacement4894(F, a, b, c, d, e, m, x): return Dist(e**S(2)*m*(m + S(-1))/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*m**S(2)), Int(F**(c*(a + b*x))*cos(d + e*x)**(m + S(-2)), x), x) + Simp(F**(c*(a + b*x))*b*c*log(F)*cos(d + e*x)**m/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*m**S(2)), x) + Simp(F**(c*(a + b*x))*e*m*sin(d + e*x)*cos(d + e*x)**(m + S(-1))/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*m**S(2)), x) def replacement4895(F, a, b, c, d, e, n, x): return Simp(F**(c*(a + b*x))*sin(d + e*x)**(n + S(1))*cos(d + e*x)/(e*(n + S(1))), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*sin(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement4896(F, a, b, c, d, e, n, x): return -Simp(F**(c*(a + b*x))*sin(d + e*x)*cos(d + e*x)**(n + S(1))/(e*(n + S(1))), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*cos(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement4897(F, a, b, c, d, e, n, x): return Dist((b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2))/(e**S(2)*(n + S(1))*(n + S(2))), Int(F**(c*(a + b*x))*sin(d + e*x)**(n + S(2)), x), x) + Simp(F**(c*(a + b*x))*sin(d + e*x)**(n + S(1))*cos(d + e*x)/(e*(n + S(1))), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*sin(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement4898(F, a, b, c, d, e, n, x): return Dist((b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(2))**S(2))/(e**S(2)*(n + S(1))*(n + S(2))), Int(F**(c*(a + b*x))*cos(d + e*x)**(n + S(2)), x), x) - Simp(F**(c*(a + b*x))*sin(d + e*x)*cos(d + e*x)**(n + S(1))/(e*(n + S(1))), x) - Simp(F**(c*(a + b*x))*b*c*log(F)*cos(d + e*x)**(n + S(2))/(e**S(2)*(n + S(1))*(n + S(2))), x) def replacement4899(F, a, b, c, d, e, n, x): return Dist((exp(S(2)*I*(d + e*x)) + S(-1))**(-n)*exp(I*n*(d + e*x))*sin(d + e*x)**n, Int(F**(c*(a + b*x))*(exp(S(2)*I*(d + e*x)) + S(-1))**n*exp(-I*n*(d + e*x)), x), x) def replacement4900(F, a, b, c, d, e, n, x): return Dist((exp(S(2)*I*(d + e*x)) + S(1))**(-n)*exp(I*n*(d + e*x))*cos(d + e*x)**n, Int(F**(c*(a + b*x))*(exp(S(2)*I*(d + e*x)) + S(1))**n*exp(-I*n*(d + e*x)), x), x) def replacement4901(F, a, b, c, d, e, n, x): return Dist(I**n, Int(ExpandIntegrand(F**(c*(a + b*x))*(S(1) - exp(S(2)*I*(d + e*x)))**n*(exp(S(2)*I*(d + e*x)) + S(1))**(-n), x), x), x) def replacement4902(F, a, b, c, d, e, n, x): return Dist((-I)**n, Int(ExpandIntegrand(F**(c*(a + b*x))*(S(1) - exp(S(2)*I*(d + e*x)))**(-n)*(exp(S(2)*I*(d + e*x)) + S(1))**n, x), x), x) def replacement4903(F, a, b, c, d, e, n, x): return Dist(e**S(2)*n*(n + S(1))/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), Int(F**(c*(a + b*x))*(S(1)/cos(d + e*x))**(n + S(2)), x), x) + Simp(F**(c*(a + b*x))*b*c*(S(1)/cos(d + e*x))**n*log(F)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) - Simp(F**(c*(a + b*x))*e*n*(S(1)/cos(d + e*x))**(n + S(1))*sin(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) def replacement4904(F, a, b, c, d, e, n, x): return Dist(e**S(2)*n*(n + S(1))/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), Int(F**(c*(a + b*x))*(S(1)/sin(d + e*x))**(n + S(2)), x), x) + Simp(F**(c*(a + b*x))*b*c*(S(1)/sin(d + e*x))**n*log(F)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) + Simp(F**(c*(a + b*x))*e*n*(S(1)/sin(d + e*x))**(n + S(1))*cos(d + e*x)/(b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*n**S(2)), x) def replacement4905(F, a, b, c, d, e, n, x): return Simp(F**(c*(a + b*x))*(S(1)/cos(d + e*x))**(n + S(-1))*sin(d + e*x)/(e*(n + S(-1))), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/cos(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement4906(F, a, b, c, d, e, n, x): return Simp(F**(c*(a + b*x))*(S(1)/sin(d + e*x))**(n + S(-1))*cos(d + e*x)/(e*(n + S(-1))), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/sin(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement4907(F, a, b, c, d, e, n, x): return Dist((b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2))/(e**S(2)*(n + S(-2))*(n + S(-1))), Int(F**(c*(a + b*x))*(S(1)/cos(d + e*x))**(n + S(-2)), x), x) + Simp(F**(c*(a + b*x))*(S(1)/cos(d + e*x))**(n + S(-1))*sin(d + e*x)/(e*(n + S(-1))), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/cos(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement4908(F, a, b, c, d, e, n, x): return Dist((b**S(2)*c**S(2)*log(F)**S(2) + e**S(2)*(n + S(-2))**S(2))/(e**S(2)*(n + S(-2))*(n + S(-1))), Int(F**(c*(a + b*x))*(S(1)/sin(d + e*x))**(n + S(-2)), x), x) - Simp(F**(c*(a + b*x))*(S(1)/sin(d + e*x))**(n + S(-1))*cos(d + e*x)/(e*(n + S(-1))), x) - Simp(F**(c*(a + b*x))*b*c*(S(1)/sin(d + e*x))**(n + S(-2))*log(F)/(e**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement4909(F, a, b, c, d, e, n, x): return Simp(S(2)**n*F**(c*(a + b*x))*Hypergeometric2F1(n, -I*b*c*log(F)/(S(2)*e) + n/S(2), -I*b*c*log(F)/(S(2)*e) + n/S(2) + S(1), -exp(S(2)*I*(d + e*x)))*exp(I*n*(d + e*x))/(b*c*log(F) + I*e*n), x) def replacement4910(F, a, b, c, d, e, n, x): return Simp(F**(c*(a + b*x))*(-S(2)*I)**n*Hypergeometric2F1(n, -I*b*c*log(F)/(S(2)*e) + n/S(2), -I*b*c*log(F)/(S(2)*e) + n/S(2) + S(1), exp(S(2)*I*(d + e*x)))*exp(I*n*(d + e*x))/(b*c*log(F) + I*e*n), x) def replacement4911(F, a, b, c, d, e, n, x): return Dist((exp(S(2)*I*(d + e*x)) + S(1))**n*(S(1)/cos(d + e*x))**n*exp(-I*n*(d + e*x)), Int(SimplifyIntegrand(F**(c*(a + b*x))*(exp(S(2)*I*(d + e*x)) + S(1))**(-n)*exp(I*n*(d + e*x)), x), x), x) def replacement4912(F, a, b, c, d, e, n, x): return Dist((S(1) - exp(-S(2)*I*(d + e*x)))**n*(S(1)/sin(d + e*x))**n*exp(I*n*(d + e*x)), Int(SimplifyIntegrand(F**(c*(a + b*x))*(S(1) - exp(-S(2)*I*(d + e*x)))**(-n)*exp(-I*n*(d + e*x)), x), x), x) def replacement4913(F, a, b, c, d, e, f, g, n, x): return Dist(S(2)**n*f**n, Int(F**(c*(a + b*x))*cos(-Pi*f/(S(4)*g) + d/S(2) + e*x/S(2))**(S(2)*n), x), x) def replacement4914(F, a, b, c, d, e, f, g, n, x): return Dist(S(2)**n*f**n, Int(F**(c*(a + b*x))*cos(d/S(2) + e*x/S(2))**(S(2)*n), x), x) def replacement4915(F, a, b, c, d, e, f, g, n, x): return Dist(S(2)**n*f**n, Int(F**(c*(a + b*x))*sin(d/S(2) + e*x/S(2))**(S(2)*n), x), x) def replacement4916(F, a, b, c, d, e, f, g, m, n, x): return Dist(g**n, Int(F**(c*(a + b*x))*(-tan(-Pi*f/(S(4)*g) + d/S(2) + e*x/S(2)))**m, x), x) def replacement4917(F, a, b, c, d, e, f, g, m, n, x): return Dist(f**n, Int(F**(c*(a + b*x))*tan(d/S(2) + e*x/S(2))**m, x), x) def replacement4918(F, a, b, c, d, e, f, g, m, n, x): return Dist(f**n, Int(F**(c*(a + b*x))*(S(1)/tan(d/S(2) + e*x/S(2)))**m, x), x) def replacement4919(F, a, b, c, d, e, f, g, h, i, x): return Dist(S(2)*i, Int(F**(c*(a + b*x))*cos(d + e*x)/(f + g*sin(d + e*x)), x), x) + Int(F**(c*(a + b*x))*(h - i*cos(d + e*x))/(f + g*sin(d + e*x)), x) def replacement4920(F, a, b, c, d, e, f, g, h, i, x): return Dist(S(2)*i, Int(F**(c*(a + b*x))*sin(d + e*x)/(f + g*cos(d + e*x)), x), x) + Int(F**(c*(a + b*x))*(h - i*sin(d + e*x))/(f + g*cos(d + e*x)), x) def replacement4921(F, G, c, n, u, v, x): return Int(F**(c*ExpandToSum(u, x))*G(ExpandToSum(v, x))**n, x) def With4922(F, a, b, c, d, e, m, n, x): u = IntHide(F**(c*(a + b*x))*sin(d + e*x)**n, x) return -Dist(m, Int(u*x**(m + S(-1)), x), x) + Dist(x**m, u, x) def With4923(F, a, b, c, d, e, m, n, x): u = IntHide(F**(c*(a + b*x))*cos(d + e*x)**n, x) return -Dist(m, Int(u*x**(m + S(-1)), x), x) + Dist(x**m, u, x) def replacement4924(F, a, b, c, d, e, f, g, m, n, x): return Int(ExpandTrigReduce(F**(c*(a + b*x)), sin(d + e*x)**m*cos(f + g*x)**n, x), x) def replacement4925(F, a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrigReduce(F**(c*(a + b*x))*x**p, sin(d + e*x)**m*cos(f + g*x)**n, x), x) def replacement4926(F, G, H, a, b, c, d, e, m, n, x): return Int(ExpandTrigToExp(F**(c*(a + b*x)), G(d + e*x)**m*H(d + e*x)**n, x), x) def replacement4927(F, n, u, v, x): return Int(ExpandTrigToExp(F**u, sin(v)**n, x), x) def replacement4928(F, n, u, v, x): return Int(ExpandTrigToExp(F**u, cos(v)**n, x), x) def replacement4929(F, m, n, u, v, x): return Int(ExpandTrigToExp(F**u, sin(v)**m*cos(v)**n, x), x) def replacement4930(a, b, c, n, p, x): return Simp(x*(p + S(2))*sin(a + b*log(c*x**n))**(p + S(2))/(p + S(1)), x) + Simp(x*sin(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tan(a + b*log(c*x**n))), x) def replacement4931(a, b, c, n, p, x): return Simp(x*(p + S(2))*cos(a + b*log(c*x**n))**(p + S(2))/(p + S(1)), x) - Simp(x*cos(a + b*log(c*x**n))**(p + S(2))*tan(a + b*log(c*x**n))/(b*n*(p + S(1))), x) def replacement4932(a, b, c, n, p, x): return Int(ExpandIntegrand((-(c*x**n)**(S(1)/(n*p))*exp(-a*b*n*p)/(S(2)*b*n*p) + (c*x**n)**(-S(1)/(n*p))*exp(a*b*n*p)/(S(2)*b*n*p))**p, x), x) def replacement4933(a, b, c, n, p, x): return Int(ExpandIntegrand((-(c*x**n)**(S(1)/(n*p))*exp(-a*b*n*p)/S(2) + (c*x**n)**(-S(1)/(n*p))*exp(a*b*n*p)/S(2))**p, x), x) def replacement4934(a, b, c, n, x): return Simp(x*sin(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(1)), x) - Simp(b*n*x*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(1)), x) def replacement4935(a, b, c, n, x): return Simp(x*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(1)), x) + Simp(b*n*x*sin(a + b*log(c*x**n))/(b**S(2)*n**S(2) + S(1)), x) def replacement4936(a, b, c, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + S(1)), Int(sin(a + b*log(c*x**n))**(p + S(-2)), x), x) + Simp(x*sin(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) - Simp(b*n*p*x*sin(a + b*log(c*x**n))**(p + S(-1))*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) def replacement4937(a, b, c, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + S(1)), Int(cos(a + b*log(c*x**n))**(p + S(-2)), x), x) + Simp(x*cos(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) + Simp(b*n*p*x*sin(a + b*log(c*x**n))*cos(a + b*log(c*x**n))**(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) def replacement4938(a, b, c, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) + S(1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(sin(a + b*log(c*x**n))**(p + S(2)), x), x) - Simp(x*sin(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) + Simp(x*sin(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tan(a + b*log(c*x**n))), x) def replacement4939(a, b, c, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) + S(1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(cos(a + b*log(c*x**n))**(p + S(2)), x), x) - Simp(x*cos(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) - Simp(x*cos(a + b*log(c*x**n))**(p + S(2))*tan(a + b*log(c*x**n))/(b*n*(p + S(1))), x) def replacement4940(a, b, c, n, p, x): return Simp(x*(-S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**(-p)*(-I*(c*x**n)**(I*b)*exp(I*a) + I*(c*x**n)**(-I*b)*exp(-I*a))**p*Hypergeometric2F1(-p, -I*(-I*b*n*p + S(1))/(S(2)*b*n), S(1) - I*(-I*b*n*p + S(1))/(S(2)*b*n), (c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(-I*b*n*p + S(1)), x) def replacement4941(a, b, c, n, p, x): return Simp(x*((c*x**n)**(I*b)*exp(I*a) + (c*x**n)**(-I*b)*exp(-I*a))**p*(S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**(-p)*Hypergeometric2F1(-p, -I*(-I*b*n*p + S(1))/(S(2)*b*n), S(1) - I*(-I*b*n*p + S(1))/(S(2)*b*n), -(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(-I*b*n*p + S(1)), x) def replacement4942(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(p + S(2))*sin(a + b*log(c*x**n))**(p + S(2))/((m + S(1))*(p + S(1))), x) + Simp(x**(m + S(1))*sin(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tan(a + b*log(c*x**n))), x) def replacement4943(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(p + S(2))*cos(a + b*log(c*x**n))**(p + S(2))/((m + S(1))*(p + S(1))), x) - Simp(x**(m + S(1))*cos(a + b*log(c*x**n))**(p + S(2))*tan(a + b*log(c*x**n))/(b*n*(p + S(1))), x) def replacement4944(a, b, c, m, n, p, x): return Dist(S(2)**(-p), Int(ExpandIntegrand(x**m*(-(c*x**n)**((m + S(1))/(n*p))*(m + S(1))*exp(-a*b*n*p/(m + S(1)))/(b*n*p) + (c*x**n)**(-(m + S(1))/(n*p))*(m + S(1))*exp(a*b*n*p/(m + S(1)))/(b*n*p))**p, x), x), x) def replacement4945(a, b, c, m, n, p, x): return Dist(S(2)**(-p), Int(ExpandIntegrand(x**m*(-(c*x**n)**((m + S(1))/(n*p))*exp(-a*b*n*p/(m + S(1))) + (c*x**n)**(-(m + S(1))/(n*p))*exp(a*b*n*p/(m + S(1))))**p, x), x), x) def replacement4946(a, b, c, m, n, x): return Simp(x**(m + S(1))*(m + S(1))*sin(a + b*log(c*x**n))/(b**S(2)*n**S(2) + (m + S(1))**S(2)), x) - Simp(b*n*x**(m + S(1))*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2) + (m + S(1))**S(2)), x) def replacement4947(a, b, c, m, n, x): return Simp(x**(m + S(1))*(m + S(1))*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2) + (m + S(1))**S(2)), x) + Simp(b*n*x**(m + S(1))*sin(a + b*log(c*x**n))/(b**S(2)*n**S(2) + (m + S(1))**S(2)), x) def replacement4948(a, b, c, m, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), Int(x**m*sin(a + b*log(c*x**n))**(p + S(-2)), x), x) + Simp(x**(m + S(1))*(m + S(1))*sin(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) - Simp(b*n*p*x**(m + S(1))*sin(a + b*log(c*x**n))**(p + S(-1))*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) def replacement4949(a, b, c, m, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), Int(x**m*cos(a + b*log(c*x**n))**(p + S(-2)), x), x) + Simp(x**(m + S(1))*(m + S(1))*cos(a + b*log(c*x**n))**p/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) + Simp(b*n*p*x**(m + S(1))*sin(a + b*log(c*x**n))*cos(a + b*log(c*x**n))**(p + S(-1))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) def replacement4950(a, b, c, m, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) + (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**m*sin(a + b*log(c*x**n))**(p + S(2)), x), x) + Simp(x**(m + S(1))*sin(a + b*log(c*x**n))**(p + S(2))/(b*n*(p + S(1))*tan(a + b*log(c*x**n))), x) - Simp(x**(m + S(1))*(m + S(1))*sin(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement4951(a, b, c, m, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(2))**S(2) + (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**m*cos(a + b*log(c*x**n))**(p + S(2)), x), x) - Simp(x**(m + S(1))*cos(a + b*log(c*x**n))**(p + S(2))*tan(a + b*log(c*x**n))/(b*n*(p + S(1))), x) - Simp(x**(m + S(1))*(m + S(1))*cos(a + b*log(c*x**n))**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement4952(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(-S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**(-p)*(-I*(c*x**n)**(I*b)*exp(I*a) + I*(c*x**n)**(-I*b)*exp(-I*a))**p*Hypergeometric2F1(-p, -I*(-I*b*n*p + m + S(1))/(S(2)*b*n), S(1) - I*(-I*b*n*p + m + S(1))/(S(2)*b*n), (c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(-I*b*n*p + m + S(1)), x) def replacement4953(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*((c*x**n)**(I*b)*exp(I*a) + (c*x**n)**(-I*b)*exp(-I*a))**p*(S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**(-p)*Hypergeometric2F1(-p, -I*(-I*b*n*p + m + S(1))/(S(2)*b*n), S(1) - I*(-I*b*n*p + m + S(1))/(S(2)*b*n), -(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(-I*b*n*p + m + S(1)), x) def replacement4954(a, b, c, n, x): return Dist(S(2)*exp(a*b*n), Int((c*x**n)**(S(1)/n)/((c*x**n)**(S(2)/n) + exp(S(2)*a*b*n)), x), x) def replacement4955(a, b, c, n, x): return Dist(S(2)*b*n*exp(a*b*n), Int((c*x**n)**(S(1)/n)/(-(c*x**n)**(S(2)/n) + exp(S(2)*a*b*n)), x), x) def replacement4956(a, b, c, n, p, x): return Simp(x*(p + S(-2))*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))/(p + S(-1)), x) + Simp(x*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))*tan(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) def replacement4957(a, b, c, n, p, x): return Simp(x*(p + S(-2))*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/(p + S(-1)), x) - Simp(x*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tan(a + b*log(c*x**n))), x) def replacement4958(a, b, c, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(1))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int((S(1)/cos(a + b*log(c*x**n)))**(p + S(-2)), x), x) - Simp(x*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) + Simp(x*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))*tan(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) def replacement4959(a, b, c, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) + S(1))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int((S(1)/sin(a + b*log(c*x**n)))**(p + S(-2)), x), x) - Simp(x*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) - Simp(x*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tan(a + b*log(c*x**n))), x) def replacement4960(a, b, c, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) + S(1)), Int((S(1)/cos(a + b*log(c*x**n)))**(p + S(2)), x), x) + Simp(x*(S(1)/cos(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) - Simp(b*n*p*x*(S(1)/cos(a + b*log(c*x**n)))**(p + S(1))*sin(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) def replacement4961(a, b, c, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) + S(1)), Int((S(1)/sin(a + b*log(c*x**n)))**(p + S(2)), x), x) + Simp(x*(S(1)/sin(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) + Simp(b*n*p*x*(S(1)/sin(a + b*log(c*x**n)))**(p + S(1))*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + S(1)), x) def replacement4962(a, b, c, n, p, x): return Simp(x*((c*x**n)**(I*b)*exp(I*a)/((c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(1)))**p*(S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**p*Hypergeometric2F1(p, -I*(I*b*n*p + S(1))/(S(2)*b*n), S(1) - I*(I*b*n*p + S(1))/(S(2)*b*n), -(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(I*b*n*p + S(1)), x) def replacement4963(a, b, c, n, p, x): return Simp(x*(-I*(c*x**n)**(I*b)*exp(I*a)/(-(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(1)))**p*(-S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**p*Hypergeometric2F1(p, -I*(I*b*n*p + S(1))/(S(2)*b*n), S(1) - I*(I*b*n*p + S(1))/(S(2)*b*n), (c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(I*b*n*p + S(1)), x) def replacement4964(a, b, c, m, n, x): return Dist(S(2)*exp(a*b*n/(m + S(1))), Int(x**m*(c*x**n)**((m + S(1))/n)/((c*x**n)**(S(2)*(m + S(1))/n) + exp(S(2)*a*b*n/(m + S(1)))), x), x) def replacement4965(a, b, c, m, n, x): return Dist(S(2)*b*n*exp(a*b*n/(m + S(1)))/(m + S(1)), Int(x**m*(c*x**n)**((m + S(1))/n)/(-(c*x**n)**(S(2)*(m + S(1))/n) + exp(S(2)*a*b*n/(m + S(1)))), x), x) def replacement4966(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(p + S(-2))*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))/((m + S(1))*(p + S(-1))), x) + Simp(x**(m + S(1))*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))*tan(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) def replacement4967(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(p + S(-2))*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/((m + S(1))*(p + S(-1))), x) - Simp(x**(m + S(1))*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tan(a + b*log(c*x**n))), x) def replacement4968(a, b, c, m, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) + (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int(x**m*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2)), x), x) + Simp(x**(m + S(1))*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))*tan(a + b*log(c*x**n))/(b*n*(p + S(-1))), x) - Simp(x**(m + S(1))*(m + S(1))*(S(1)/cos(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) def replacement4969(a, b, c, m, n, p, x): return Dist((b**S(2)*n**S(2)*(p + S(-2))**S(2) + (m + S(1))**S(2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), Int(x**m*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2)), x), x) - Simp(x**(m + S(1))*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/(b*n*(p + S(-1))*tan(a + b*log(c*x**n))), x) - Simp(x**(m + S(1))*(m + S(1))*(S(1)/sin(a + b*log(c*x**n)))**(p + S(-2))/(b**S(2)*n**S(2)*(p + S(-2))*(p + S(-1))), x) def replacement4970(a, b, c, m, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), Int(x**m*(S(1)/cos(a + b*log(c*x**n)))**(p + S(2)), x), x) + Simp(x**(m + S(1))*(m + S(1))*(S(1)/cos(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) - Simp(b*n*p*x**(m + S(1))*(S(1)/cos(a + b*log(c*x**n)))**(p + S(1))*sin(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) def replacement4971(a, b, c, m, n, p, x): return Dist(b**S(2)*n**S(2)*p*(p + S(1))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), Int(x**m*(S(1)/sin(a + b*log(c*x**n)))**(p + S(2)), x), x) + Simp(x**(m + S(1))*(m + S(1))*(S(1)/sin(a + b*log(c*x**n)))**p/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) + Simp(b*n*p*x**(m + S(1))*(S(1)/sin(a + b*log(c*x**n)))**(p + S(1))*cos(a + b*log(c*x**n))/(b**S(2)*n**S(2)*p**S(2) + (m + S(1))**S(2)), x) def replacement4972(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*((c*x**n)**(I*b)*exp(I*a)/((c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(1)))**p*(S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**p*Hypergeometric2F1(p, -I*(I*b*n*p + m + S(1))/(S(2)*b*n), S(1) - I*(I*b*n*p + m + S(1))/(S(2)*b*n), -(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(I*b*n*p + m + S(1)), x) def replacement4973(a, b, c, m, n, p, x): return Simp(x**(m + S(1))*(-I*(c*x**n)**(I*b)*exp(I*a)/(-(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(1)))**p*(-S(2)*(c*x**n)**(S(2)*I*b)*exp(S(2)*I*a) + S(2))**p*Hypergeometric2F1(p, -I*(I*b*n*p + m + S(1))/(S(2)*b*n), S(1) - I*(I*b*n*p + m + S(1))/(S(2)*b*n), (c*x**n)**(S(2)*I*b)*exp(S(2)*I*a))/(I*b*n*p + m + S(1)), x) def replacement4974(a, b, p, x): return -Dist(p, Int(log(b*x)**(p + S(-1))*sin(a*x*log(b*x)**p), x), x) - Simp(cos(a*x*log(b*x)**p)/a, x) def replacement4975(a, b, p, x): return -Dist(p, Int(log(b*x)**(p + S(-1))*cos(a*x*log(b*x)**p), x), x) + Simp(sin(a*x*log(b*x)**p)/a, x) def replacement4976(a, b, n, p, x): return -Dist(p/n, Int(log(b*x)**(p + S(-1))*sin(a*x**n*log(b*x)**p), x), x) - Dist((n + S(-1))/(a*n), Int(x**(-n)*cos(a*x**n*log(b*x)**p), x), x) - Simp(x**(S(1) - n)*cos(a*x**n*log(b*x)**p)/(a*n), x) def replacement4977(a, b, n, p, x): return -Dist(p/n, Int(log(b*x)**(p + S(-1))*cos(a*x**n*log(b*x)**p), x), x) + Dist((n + S(-1))/(a*n), Int(x**(-n)*sin(a*x**n*log(b*x)**p), x), x) + Simp(x**(S(1) - n)*sin(a*x**n*log(b*x)**p)/(a*n), x) def replacement4978(a, b, m, n, p, x): return -Dist(p/n, Int(x**m*log(b*x)**(p + S(-1))*sin(a*x**n*log(b*x)**p), x), x) - Simp(cos(a*x**n*log(b*x)**p)/(a*n), x) def replacement4979(a, b, m, n, p, x): return -Dist(p/n, Int(x**m*log(b*x)**(p + S(-1))*cos(a*x**n*log(b*x)**p), x), x) + Simp(sin(a*x**n*log(b*x)**p)/(a*n), x) def replacement4980(a, b, m, n, p, x): return -Dist(p/n, Int(x**m*log(b*x)**(p + S(-1))*sin(a*x**n*log(b*x)**p), x), x) + Dist((m - n + S(1))/(a*n), Int(x**(m - n)*cos(a*x**n*log(b*x)**p), x), x) - Simp(x**(m - n + S(1))*cos(a*x**n*log(b*x)**p)/(a*n), x) def replacement4981(a, b, m, n, p, x): return -Dist(p/n, Int(x**m*log(b*x)**(p + S(-1))*cos(a*x**n*log(b*x)**p), x), x) - Dist((m - n + S(1))/(a*n), Int(x**(m - n)*sin(a*x**n*log(b*x)**p), x), x) + Simp(x**(m - n + S(1))*sin(a*x**n*log(b*x)**p)/(a*n), x) def replacement4982(a, c, d, n, x): return -Dist(S(1)/d, Subst(Int(sin(a*x)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def replacement4983(a, c, d, n, x): return -Dist(S(1)/d, Subst(Int(cos(a*x)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def replacement4984(a, b, c, d, e, n, x): return -Dist(S(1)/d, Subst(Int(sin(b*e/d - e*x*(-a*d + b*c)/d)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def replacement4985(a, b, c, d, e, n, x): return -Dist(S(1)/d, Subst(Int(cos(b*e/d - e*x*(-a*d + b*c)/d)**n/x**S(2), x), x, S(1)/(c + d*x)), x) def With4986(n, u, x): lst = QuotientOfLinearsParts(u, x) return Int(sin((x*Part(lst, S(2)) + Part(lst, S(1)))/(x*Part(lst, S(4)) + Part(lst, S(3))))**n, x) def With4987(n, u, x): lst = QuotientOfLinearsParts(u, x) return Int(cos((x*Part(lst, S(2)) + Part(lst, S(1)))/(x*Part(lst, S(4)) + Part(lst, S(3))))**n, x) def replacement4988(p, q, u, v, w, x): return Int(u*sin(v)**(p + q), x) def replacement4989(p, q, u, v, w, x): return Int(u*cos(v)**(p + q), x) def replacement4990(p, q, v, w, x): return Int(ExpandTrigReduce(sin(v)**p*sin(w)**q, x), x) def replacement4991(p, q, v, w, x): return Int(ExpandTrigReduce(cos(v)**p*cos(w)**q, x), x) def replacement4992(m, p, q, v, w, x): return Int(ExpandTrigReduce(x**m, sin(v)**p*sin(w)**q, x), x) def replacement4993(m, p, q, v, w, x): return Int(ExpandTrigReduce(x**m, cos(v)**p*cos(w)**q, x), x) def replacement4994(p, u, v, w, x): return Dist(S(2)**(-p), Int(u*sin(S(2)*v)**p, x), x) def replacement4995(p, q, v, w, x): return Int(ExpandTrigReduce(sin(v)**p*cos(w)**q, x), x) def replacement4996(m, p, q, v, w, x): return Int(ExpandTrigReduce(x**m, sin(v)**p*cos(w)**q, x), x) def replacement4997(n, v, w, x): return Dist(cos(v - w), Int(tan(w)**(n + S(-1))/cos(w), x), x) - Int(cos(v)*tan(w)**(n + S(-1)), x) def replacement4998(n, v, w, x): return Dist(cos(v - w), Int((S(1)/tan(w))**(n + S(-1))/sin(w), x), x) - Int((S(1)/tan(w))**(n + S(-1))*sin(v), x) def replacement4999(n, v, w, x): return Dist(sin(v - w), Int((S(1)/tan(w))**(n + S(-1))/sin(w), x), x) + Int((S(1)/tan(w))**(n + S(-1))*cos(v), x) def replacement5000(n, v, w, x): return -Dist(sin(v - w), Int(tan(w)**(n + S(-1))/cos(w), x), x) + Int(sin(v)*tan(w)**(n + S(-1)), x) def replacement5001(n, v, w, x): return Dist(sin(v - w), Int((S(1)/cos(w))**(n + S(-1)), x), x) + Dist(cos(v - w), Int((S(1)/cos(w))**(n + S(-1))*tan(w), x), x) def replacement5002(n, v, w, x): return -Dist(sin(v - w), Int((S(1)/sin(w))**(n + S(-1)), x), x) + Dist(cos(v - w), Int((S(1)/sin(w))**(n + S(-1))/tan(w), x), x) def replacement5003(n, v, w, x): return Dist(sin(v - w), Int((S(1)/sin(w))**(n + S(-1))/tan(w), x), x) + Dist(cos(v - w), Int((S(1)/sin(w))**(n + S(-1)), x), x) def replacement5004(n, v, w, x): return -Dist(sin(v - w), Int((S(1)/cos(w))**(n + S(-1))*tan(w), x), x) + Dist(cos(v - w), Int((S(1)/cos(w))**(n + S(-1)), x), x) def replacement5005(a, b, c, d, e, f, m, n, x): return Int((a + b*sin(S(2)*c + S(2)*d*x)/S(2))**n*(e + f*x)**m, x) def replacement5006(a, b, c, d, m, n, x): return Dist(S(2)**(-n), Int(x**m*(S(2)*a - b*cos(S(2)*c + S(2)*d*x) + b)**n, x), x) def replacement5007(a, b, c, d, m, n, x): return Dist(S(2)**(-n), Int(x**m*(S(2)*a + b*cos(S(2)*c + S(2)*d*x) + b)**n, x), x) def replacement5008(a, b, c, d, e, f, m, n, p, x): return Dist(d**(-m + S(-1)), Subst(Int((-c*f + d*e + f*x)**m*sin(a + b*x**n)**p, x), x, c + d*x), x) def replacement5009(a, b, c, d, e, f, m, n, p, x): return Dist(d**(-m + S(-1)), Subst(Int((-c*f + d*e + f*x)**m*cos(a + b*x**n)**p, x), x, c + d*x), x) def replacement5010(a, b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(S(2)*a + b + c + (b - c)*cos(S(2)*d + S(2)*e*x)), x), x) def replacement5011(b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(b + c + (b - c)*cos(S(2)*d + S(2)*e*x)), x), x) def replacement5012(a, b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(S(2)*a + b + c + (b - c)*cos(S(2)*d + S(2)*e*x)), x), x) def replacement5013(b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(b + c + (b - c)*cos(S(2)*d + S(2)*e*x)), x), x) def replacement5014(a, b, c, d, e, f, g, m, x): return Dist(S(2), Int((f + g*x)**m/(S(2)*a + b + c + (b - c)*cos(S(2)*d + S(2)*e*x)), x), x) def replacement5015(a, b, c, d, e, f, m, x): return Int((e + f*x)**m*exp(I*(c + d*x))/(a - I*b*exp(I*(c + d*x)) - Rt(a**S(2) - b**S(2), S(2))), x) + Int((e + f*x)**m*exp(I*(c + d*x))/(a - I*b*exp(I*(c + d*x)) + Rt(a**S(2) - b**S(2), S(2))), x) - Simp(I*(e + f*x)**(m + S(1))/(b*f*(m + S(1))), x) def replacement5016(a, b, c, d, e, f, m, x): return -Dist(I, Int((e + f*x)**m*exp(I*(c + d*x))/(a + b*exp(I*(c + d*x)) - Rt(a**S(2) - b**S(2), S(2))), x), x) - Dist(I, Int((e + f*x)**m*exp(I*(c + d*x))/(a + b*exp(I*(c + d*x)) + Rt(a**S(2) - b**S(2), S(2))), x), x) + Simp(I*(e + f*x)**(m + S(1))/(b*f*(m + S(1))), x) def replacement5017(a, b, c, d, e, f, m, x): return Dist(I, Int((e + f*x)**m*exp(I*(c + d*x))/(I*a + b*exp(I*(c + d*x)) - Rt(-a**S(2) + b**S(2), S(2))), x), x) + Dist(I, Int((e + f*x)**m*exp(I*(c + d*x))/(I*a + b*exp(I*(c + d*x)) + Rt(-a**S(2) + b**S(2), S(2))), x), x) - Simp(I*(e + f*x)**(m + S(1))/(b*f*(m + S(1))), x) def replacement5018(a, b, c, d, e, f, m, x): return Int((e + f*x)**m*exp(I*(c + d*x))/(I*a + I*b*exp(I*(c + d*x)) - Rt(-a**S(2) + b**S(2), S(2))), x) + Int((e + f*x)**m*exp(I*(c + d*x))/(I*a + I*b*exp(I*(c + d*x)) + Rt(-a**S(2) + b**S(2), S(2))), x) + Simp(I*(e + f*x)**(m + S(1))/(b*f*(m + S(1))), x) def replacement5019(a, b, c, d, e, f, m, n, x): return Dist(S(1)/a, Int((e + f*x)**m*cos(c + d*x)**(n + S(-2)), x), x) - Dist(S(1)/b, Int((e + f*x)**m*sin(c + d*x)*cos(c + d*x)**(n + S(-2)), x), x) def replacement5020(a, b, c, d, e, f, m, n, x): return Dist(S(1)/a, Int((e + f*x)**m*sin(c + d*x)**(n + S(-2)), x), x) - Dist(S(1)/b, Int((e + f*x)**m*sin(c + d*x)**(n + S(-2))*cos(c + d*x), x), x) def replacement5021(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/b, Int((e + f*x)**m*sin(c + d*x)*cos(c + d*x)**(n + S(-2)), x), x) + Dist(a/b**S(2), Int((e + f*x)**m*cos(c + d*x)**(n + S(-2)), x), x) - Dist((a**S(2) - b**S(2))/b**S(2), Int((e + f*x)**m*cos(c + d*x)**(n + S(-2))/(a + b*sin(c + d*x)), x), x) def replacement5022(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/b, Int((e + f*x)**m*sin(c + d*x)**(n + S(-2))*cos(c + d*x), x), x) + Dist(a/b**S(2), Int((e + f*x)**m*sin(c + d*x)**(n + S(-2)), x), x) - Dist((a**S(2) - b**S(2))/b**S(2), Int((e + f*x)**m*sin(c + d*x)**(n + S(-2))/(a + b*cos(c + d*x)), x), x) def replacement5023(A, B, a, b, c, d, e, f, x): return Dist(B*f/(a*d), Int(cos(c + d*x)/(a + b*sin(c + d*x)), x), x) - Simp(B*(e + f*x)*cos(c + d*x)/(a*d*(a + b*sin(c + d*x))), x) def replacement5024(A, B, a, b, c, d, e, f, x): return -Dist(B*f/(a*d), Int(sin(c + d*x)/(a + b*cos(c + d*x)), x), x) + Simp(B*(e + f*x)*sin(c + d*x)/(a*d*(a + b*cos(c + d*x))), x) def replacement5025(a, b, m, n, v, x): return Int((a*cos(v) + b*sin(v))**n, x) def replacement5026(a, b, m, n, v, x): return Int((a*sin(v) + b*cos(v))**n, x) def replacement5027(a, b, c, d, m, n, u, x): return Int(ExpandTrigReduce(u, sin(a + b*x)**m*sin(c + d*x)**n, x), x) def replacement5028(a, b, c, d, m, n, u, x): return Int(ExpandTrigReduce(u, cos(a + b*x)**m*cos(c + d*x)**n, x), x) def replacement5029(a, b, c, d, x): return Dist(S(1)/sin((-a*d + b*c)/b), Int(tan(c + d*x), x), x) - Dist(S(1)/sin((-a*d + b*c)/d), Int(tan(a + b*x), x), x) def replacement5030(a, b, c, d, x): return Dist(S(1)/sin((-a*d + b*c)/b), Int(S(1)/tan(a + b*x), x), x) - Dist(S(1)/sin((-a*d + b*c)/d), Int(S(1)/tan(c + d*x), x), x) def replacement5031(a, b, c, d, x): return Dist(b*cos((-a*d + b*c)/d)/d, Int(S(1)/(cos(a + b*x)*cos(c + d*x)), x), x) - Simp(b*x/d, x) def replacement5032(a, b, c, d, x): return Dist(cos((-a*d + b*c)/d), Int(S(1)/(sin(a + b*x)*sin(c + d*x)), x), x) - Simp(b*x/d, x) def replacement5033(a, b, n, u, v, x): return Int(u*(a*exp(-a*v/b))**n, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/piecewise_linear.py000066400000000000000000000466721412543434000250670ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def piecewise_linear(): from sympy.integrals.rubi.constraints import cons1092, cons19, cons1093, cons89, cons90, cons1094, cons91, cons25, cons74, cons68, cons4, cons1095, cons216, cons685, cons102, cons103, cons1096, cons1097, cons33, cons96, cons358, cons1098, cons21, cons1099, cons2, cons3 pattern1885 = Pattern(Integral(u_**WC('m', S(1)), x_), cons19, cons1092) rule1885 = ReplacementRule(pattern1885, With1885) pattern1886 = Pattern(Integral(v_/u_, x_), cons1093, CustomConstraint(With1886)) rule1886 = ReplacementRule(pattern1886, replacement1886) pattern1887 = Pattern(Integral(v_**n_/u_, x_), cons1093, cons89, cons90, cons1094, CustomConstraint(With1887)) rule1887 = ReplacementRule(pattern1887, replacement1887) pattern1888 = Pattern(Integral(S(1)/(u_*v_), x_), cons1093, CustomConstraint(With1888)) rule1888 = ReplacementRule(pattern1888, replacement1888) pattern1889 = Pattern(Integral(S(1)/(u_*sqrt(v_)), x_), cons1093, CustomConstraint(With1889)) rule1889 = ReplacementRule(pattern1889, replacement1889) pattern1890 = Pattern(Integral(S(1)/(u_*sqrt(v_)), x_), cons1093, CustomConstraint(With1890)) rule1890 = ReplacementRule(pattern1890, replacement1890) pattern1891 = Pattern(Integral(v_**n_/u_, x_), cons1093, cons89, cons91, CustomConstraint(With1891)) rule1891 = ReplacementRule(pattern1891, replacement1891) pattern1892 = Pattern(Integral(v_**n_/u_, x_), cons1093, cons25, CustomConstraint(With1892)) rule1892 = ReplacementRule(pattern1892, replacement1892) pattern1893 = Pattern(Integral(S(1)/(sqrt(u_)*sqrt(v_)), x_), cons1093, CustomConstraint(With1893)) rule1893 = ReplacementRule(pattern1893, replacement1893) pattern1894 = Pattern(Integral(S(1)/(sqrt(u_)*sqrt(v_)), x_), cons1093, CustomConstraint(With1894)) rule1894 = ReplacementRule(pattern1894, replacement1894) pattern1895 = Pattern(Integral(u_**m_*v_**n_, x_), cons19, cons4, cons1093, cons74, cons68, CustomConstraint(With1895)) rule1895 = ReplacementRule(pattern1895, replacement1895) pattern1896 = Pattern(Integral(u_**m_*v_**WC('n', S(1)), x_), cons19, cons4, cons1093, cons68, cons1095, CustomConstraint(With1896)) rule1896 = ReplacementRule(pattern1896, replacement1896) pattern1897 = Pattern(Integral(u_**m_*v_**WC('n', S(1)), x_), cons1093, cons216, cons89, cons90, cons685, cons102, cons103, CustomConstraint(With1897)) rule1897 = ReplacementRule(pattern1897, replacement1897) pattern1898 = Pattern(Integral(u_**m_*v_**n_, x_), cons1093, cons685, cons1096, cons1097, CustomConstraint(With1898)) rule1898 = ReplacementRule(pattern1898, replacement1898) pattern1899 = Pattern(Integral(u_**m_*v_**n_, x_), cons1093, cons216, cons33, cons96, CustomConstraint(With1899)) rule1899 = ReplacementRule(pattern1899, replacement1899) pattern1900 = Pattern(Integral(u_**m_*v_**n_, x_), cons1093, cons358, cons1098, CustomConstraint(With1900)) rule1900 = ReplacementRule(pattern1900, replacement1900) pattern1901 = Pattern(Integral(u_**m_*v_**n_, x_), cons1093, cons21, cons25, CustomConstraint(With1901)) rule1901 = ReplacementRule(pattern1901, replacement1901) pattern1902 = Pattern(Integral(u_**WC('n', S(1))*log(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons1092, cons1099, cons89, cons90) rule1902 = ReplacementRule(pattern1902, With1902) pattern1903 = Pattern(Integral(u_**WC('n', S(1))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*log(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons1092, cons1099, cons89, cons90, cons68) rule1903 = ReplacementRule(pattern1903, With1903) return [rule1885, rule1886, rule1887, rule1888, rule1889, rule1890, rule1891, rule1892, rule1893, rule1894, rule1895, rule1896, rule1897, rule1898, rule1899, rule1900, rule1901, rule1902, rule1903, ] def With1885(m, u, x): c = D(u, x) return Dist(S(1)/c, Subst(Int(x**m, x), x, u), x) def With1886(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1886(u, v, x): a = D(u, x) b = D(v, x) return -Dist((-a*v + b*u)/a, Int(S(1)/u, x), x) + Simp(b*x/a, x) def With1887(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1887(n, u, v, x): a = D(u, x) b = D(v, x) return -Dist((-a*v + b*u)/a, Int(v**(n + S(-1))/u, x), x) + Simp(v**n/(a*n), x) def With1888(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1888(u, v, x): a = D(u, x) b = D(v, x) return -Dist(a/(-a*v + b*u), Int(S(1)/u, x), x) + Dist(b/(-a*v + b*u), Int(S(1)/v, x), x) def With1889(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if And(NonzeroQ(-a*v + b*u), PosQ((-a*v + b*u)/a)): return True return False def replacement1889(u, v, x): a = D(u, x) b = D(v, x) return Simp(S(2)*ArcTan(sqrt(v)/Rt((-a*v + b*u)/a, S(2)))/(a*Rt((-a*v + b*u)/a, S(2))), x) def With1890(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if And(NonzeroQ(-a*v + b*u), NegQ((-a*v + b*u)/a)): return True return False def replacement1890(u, v, x): a = D(u, x) b = D(v, x) return Simp(-S(2)*atanh(sqrt(v)/Rt(-(-a*v + b*u)/a, S(2)))/(a*Rt(-(-a*v + b*u)/a, S(2))), x) def With1891(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1891(n, u, v, x): a = D(u, x) b = D(v, x) return -Dist(a/(-a*v + b*u), Int(v**(n + S(1))/u, x), x) + Simp(v**(n + S(1))/((n + S(1))*(-a*v + b*u)), x) def With1892(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1892(n, u, v, x): a = D(u, x) b = D(v, x) return Simp(v**(n + S(1))*Hypergeometric2F1(S(1), n + S(1), n + S(2), -a*v/(-a*v + b*u))/((n + S(1))*(-a*v + b*u)), x) def With1893(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if And(NonzeroQ(-a*v + b*u), PosQ(a*b)): return True return False def replacement1893(u, v, x): a = D(u, x) b = D(v, x) return Simp(S(2)*atanh(sqrt(u)*Rt(a*b, S(2))/(a*sqrt(v)))/Rt(a*b, S(2)), x) def With1894(u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if And(NonzeroQ(-a*v + b*u), NegQ(a*b)): return True return False def replacement1894(u, v, x): a = D(u, x) b = D(v, x) return Simp(S(2)*ArcTan(sqrt(u)*Rt(-a*b, S(2))/(a*sqrt(v)))/Rt(-a*b, S(2)), x) def With1895(m, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1895(m, n, u, v, x): a = D(u, x) b = D(v, x) return -Simp(u**(m + S(1))*v**(n + S(1))/((m + S(1))*(-a*v + b*u)), x) def With1896(m, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1896(m, n, u, v, x): a = D(u, x) b = D(v, x) return -Dist(b*n/(a*(m + S(1))), Int(u**(m + S(1))*v**(n + S(-1)), x), x) + Simp(u**(m + S(1))*v**n/(a*(m + S(1))), x) def With1897(m, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1897(m, n, u, v, x): a = D(u, x) b = D(v, x) return -Dist(n*(-a*v + b*u)/(a*(m + n + S(1))), Int(u**m*v**(n + S(-1)), x), x) + Simp(u**(m + S(1))*v**n/(a*(m + n + S(1))), x) def With1898(m, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1898(m, n, u, v, x): a = D(u, x) b = D(v, x) return -Dist(n*(-a*v + b*u)/(a*(m + n + S(1))), Int(u**m*v**(n + S(-1)), x), x) + Simp(u**(m + S(1))*v**n/(a*(m + n + S(1))), x) def With1899(m, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1899(m, n, u, v, x): a = D(u, x) b = D(v, x) return Dist(b*(m + n + S(2))/((m + S(1))*(-a*v + b*u)), Int(u**(m + S(1))*v**n, x), x) - Simp(u**(m + S(1))*v**(n + S(1))/((m + S(1))*(-a*v + b*u)), x) def With1900(m, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1900(m, n, u, v, x): a = D(u, x) b = D(v, x) return Dist(b*(m + n + S(2))/((m + S(1))*(-a*v + b*u)), Int(u**(m + S(1))*v**n, x), x) - Simp(u**(m + S(1))*v**(n + S(1))/((m + S(1))*(-a*v + b*u)), x) def With1901(m, n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False a = D(u, x) b = D(v, x) if NonzeroQ(-a*v + b*u): return True return False def replacement1901(m, n, u, v, x): a = D(u, x) b = D(v, x) return Simp(u**m*v**(n + S(1))*(b*u/(-a*v + b*u))**(-m)*Hypergeometric2F1(-m, n + S(1), n + S(2), -a*v/(-a*v + b*u))/(b*(n + S(1))), x) def With1902(a, b, n, u, x): c = D(u, x) return -Dist(c*n/b, Int(u**(n + S(-1))*(a + b*x)*log(a + b*x), x), x) - Int(u**n, x) + Simp(u**n*(a + b*x)*log(a + b*x)/b, x) def With1903(a, b, m, n, u, x): c = D(u, x) return -Dist(c*n/(b*(m + S(1))), Int(u**(n + S(-1))*(a + b*x)**(m + S(1))*log(a + b*x), x), x) - Dist(S(1)/(m + S(1)), Int(u**n*(a + b*x)**m, x), x) + Simp(u**n*(a + b*x)**(m + S(1))*log(a + b*x)/(b*(m + S(1))), x) sympy-sympy-1.9/sympy/integrals/rubi/rules/quadratic_products.py000066400000000000000000011534361412543434000254560ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def quadratic_products(): from sympy.integrals.rubi.constraints import cons47, cons2, cons3, cons8, cons227, cons5, cons228, cons130, cons229, cons230, cons13, cons165, cons231, cons139, cons232, cons233, cons234, cons235, cons236, cons237, cons70, cons71, cons49, cons238, cons29, cons50, cons19, cons239, cons240, cons241, cons242, cons68, cons243, cons244, cons245, cons246, cons148, cons247, cons248, cons249, cons250, cons251, cons252, cons253, cons254, cons168, cons255, cons33, cons170, cons256, cons257, cons96, cons149, cons258, cons40, cons259, cons260, cons43, cons20, cons261, cons262, cons263, cons264, cons265, cons266, cons267, cons268, cons269, cons45, cons270, cons56, cons271, cons272, cons273, cons274, cons275, cons276, cons277, cons278, cons279, cons280, cons281, cons282, cons283, cons284, cons285, cons286, cons287, cons288, cons21, cons289, cons290, cons291, cons292, cons293, cons294, cons295, cons296, cons297, cons298, cons299, cons300, cons301, cons302, cons303, cons304, cons305, cons306, cons307, cons308, cons309, cons310, cons311, cons312, cons313, cons314, cons315, cons86, cons87, cons316, cons317, cons318, cons127, cons210, cons319, cons320, cons321, cons64, cons322, cons323, cons324, cons325, cons326, cons4, cons327, cons328, cons329, cons141, cons330, cons331, cons332, cons333, cons152, cons334, cons150, cons335, cons198, cons336, cons337, cons338, cons339, cons340, cons91, cons341, cons342, cons343, cons90, cons89, cons344, cons345, cons346, cons128, cons347, cons348, cons209, cons349, cons350, cons351, cons352, cons353, cons354, cons355, cons356, cons357, cons358, cons359, cons360, cons361, cons362, cons363, cons364, cons365, cons366, cons367, cons368, cons369, cons370, cons371, cons372, cons373, cons374, cons375, cons376, cons377, cons151, cons378, cons126, cons379, cons95, cons25, cons167, cons75, cons380, cons82, cons381, cons382, cons383, cons384, cons385, cons386, cons387, cons52, cons388, cons389, cons390, cons391, cons392, cons393, cons394, cons395, cons396, cons397, cons398, cons399, cons400, cons401, cons402, cons403, cons404, cons405, cons406, cons407, cons408, cons409, cons410, cons411, cons412, cons413, cons414, cons415, cons416, cons417, cons418, cons211, cons419, cons420, cons421, cons422, cons423, cons424, cons425, cons426, cons427, cons428, cons429, cons430, cons431, cons432, cons433, cons222, cons434, cons435, cons436, cons437, cons438, cons439, cons440, cons441, cons442, cons443, cons444, cons445, cons446, cons447, cons448, cons449, cons450, cons451, cons452, cons453, cons454, cons455, cons226, cons36, cons37, cons38, cons456, cons457, cons458, cons459, cons460 pattern192 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons47) rule192 = ReplacementRule(pattern192, replacement192) pattern193 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons47, cons227) rule193 = ReplacementRule(pattern193, replacement193) pattern194 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons228, cons130, cons229) rule194 = ReplacementRule(pattern194, With194) pattern195 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons228, cons130, cons230) rule195 = ReplacementRule(pattern195, replacement195) pattern196 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons228, cons13, cons165, cons231) rule196 = ReplacementRule(pattern196, replacement196) pattern197 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**(S(-3)/2), x_), cons2, cons3, cons8, cons228) rule197 = ReplacementRule(pattern197, replacement197) pattern198 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons228, cons13, cons139, cons232, cons231) rule198 = ReplacementRule(pattern198, replacement198) pattern199 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons228, cons233, cons229) rule199 = ReplacementRule(pattern199, With199) pattern200 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons228, CustomConstraint(With200)) rule200 = ReplacementRule(pattern200, replacement200) pattern201 = Pattern(Integral(S(1)/(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons228) rule201 = ReplacementRule(pattern201, replacement201) pattern202 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons5, cons234) rule202 = ReplacementRule(pattern202, replacement202) pattern203 = Pattern(Integral(S(1)/sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons3, cons8, cons235) rule203 = ReplacementRule(pattern203, replacement203) pattern204 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons228) rule204 = ReplacementRule(pattern204, replacement204) pattern205 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons3, cons8, cons13, cons236) rule205 = ReplacementRule(pattern205, replacement205) pattern206 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons228, cons13, CustomConstraint(With206)) rule206 = ReplacementRule(pattern206, replacement206) pattern207 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons5, cons228, cons237) rule207 = ReplacementRule(pattern207, With207) pattern208 = Pattern(Integral((u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons5, cons70, cons71) rule208 = ReplacementRule(pattern208, replacement208) pattern209 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons47, cons49, cons238) rule209 = ReplacementRule(pattern209, replacement209) pattern210 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons47, cons49, cons239) rule210 = ReplacementRule(pattern210, replacement210) pattern211 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons47, cons49, cons240) rule211 = ReplacementRule(pattern211, replacement211) pattern212 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons47, cons241, cons242, cons68) rule212 = ReplacementRule(pattern212, replacement212) pattern213 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))/(x_*WC('e', S(1)) + WC('d', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons47, cons241) rule213 = ReplacementRule(pattern213, replacement213) pattern214 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons47, cons241, cons243) rule214 = ReplacementRule(pattern214, replacement214) pattern215 = Pattern(Integral(S(1)/((x_*WC('e', S(1)) + WC('d', S(0)))**S(2)*sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons47, cons241) rule215 = ReplacementRule(pattern215, replacement215) pattern216 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons47, cons241, cons244, cons243) rule216 = ReplacementRule(pattern216, replacement216) pattern217 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons47, cons241, cons245) rule217 = ReplacementRule(pattern217, replacement217) pattern218 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons47, cons241, cons246, cons148, cons247, cons248) rule218 = ReplacementRule(pattern218, replacement218) pattern219 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons47, cons241, cons246, cons148, cons249, cons248, cons250) rule219 = ReplacementRule(pattern219, replacement219) pattern220 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons47, cons241, cons13, cons165, cons251, cons240, cons250, cons252, cons253, cons248) rule220 = ReplacementRule(pattern220, replacement220) pattern221 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons47, cons241, cons246, cons139, cons254, cons248) rule221 = ReplacementRule(pattern221, replacement221) pattern222 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons47, cons241, cons246, cons139, cons168, cons248) rule222 = ReplacementRule(pattern222, replacement222) pattern223 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons47, cons241, cons246, cons139, cons255, cons248) rule223 = ReplacementRule(pattern223, replacement223) pattern224 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons47, cons241, cons33, cons170, cons240, cons256, cons257) rule224 = ReplacementRule(pattern224, replacement224) pattern225 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons47, cons241, cons33, cons96, cons248) rule225 = ReplacementRule(pattern225, replacement225) pattern226 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons47, cons149, cons241) rule226 = ReplacementRule(pattern226, replacement226) pattern227 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons258, cons40) rule227 = ReplacementRule(pattern227, replacement227) pattern228 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons259, cons260) rule228 = ReplacementRule(pattern228, replacement228) pattern229 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons258, cons149, cons43) rule229 = ReplacementRule(pattern229, replacement229) pattern230 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons5, cons259, cons149, cons43) rule230 = ReplacementRule(pattern230, replacement230) pattern231 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons258, cons149, cons242) rule231 = ReplacementRule(pattern231, replacement231) pattern232 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons259, cons149, cons242) rule232 = ReplacementRule(pattern232, replacement232) pattern233 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**S(2)*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons258, cons149, cons13, cons139) rule233 = ReplacementRule(pattern233, replacement233) pattern234 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**S(2), x_), cons2, cons8, cons29, cons50, cons5, cons259, cons149, cons13, cons139) rule234 = ReplacementRule(pattern234, replacement234) pattern235 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons258, cons149, cons20, cons13, cons261, cons262, cons263) rule235 = ReplacementRule(pattern235, replacement235) pattern236 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons5, cons259, cons149, cons20, cons13, cons261, cons262, cons263) rule236 = ReplacementRule(pattern236, replacement236) pattern237 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons258, cons149, cons264) rule237 = ReplacementRule(pattern237, replacement237) pattern238 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons259, cons149, cons264) rule238 = ReplacementRule(pattern238, replacement238) pattern239 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons258, cons149, cons265) rule239 = ReplacementRule(pattern239, replacement239) pattern240 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons5, cons259, cons149, cons265) rule240 = ReplacementRule(pattern240, replacement240) pattern241 = Pattern(Integral(S(1)/(sqrt(x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons258) rule241 = ReplacementRule(pattern241, replacement241) pattern242 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('c', S(1)))*sqrt(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons259) rule242 = ReplacementRule(pattern242, replacement242) pattern243 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons258, cons246, cons165, cons266, cons255, cons248) rule243 = ReplacementRule(pattern243, replacement243) pattern244 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons259, cons246, cons165, cons266, cons255, cons248) rule244 = ReplacementRule(pattern244, replacement244) pattern245 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons258, cons246, cons165, cons267, cons240, cons248) rule245 = ReplacementRule(pattern245, replacement245) pattern246 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons259, cons246, cons165, cons267, cons240, cons248) rule246 = ReplacementRule(pattern246, replacement246) pattern247 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons258, cons246, cons139, cons254, cons248) rule247 = ReplacementRule(pattern247, replacement247) pattern248 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons259, cons246, cons139, cons254, cons248) rule248 = ReplacementRule(pattern248, replacement248) pattern249 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons258, cons246, cons139, cons168, cons248) rule249 = ReplacementRule(pattern249, replacement249) pattern250 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons259, cons246, cons139, cons168, cons248) rule250 = ReplacementRule(pattern250, replacement250) pattern251 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons258, cons33, cons268, cons240, cons248) rule251 = ReplacementRule(pattern251, replacement251) pattern252 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons5, cons259, cons33, cons268, cons240, cons248) rule252 = ReplacementRule(pattern252, replacement252) pattern253 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons258, cons33, cons269, cons255, cons248) rule253 = ReplacementRule(pattern253, replacement253) pattern254 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons5, cons259, cons33, cons269, cons255, cons248) rule254 = ReplacementRule(pattern254, replacement254) pattern255 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons3, cons8, cons50, cons19, cons149) rule255 = ReplacementRule(pattern255, replacement255) pattern256 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons259, cons149, cons45, cons270) rule256 = ReplacementRule(pattern256, replacement256) pattern257 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons258, cons149) rule257 = ReplacementRule(pattern257, replacement257) pattern258 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons259, cons149) rule258 = ReplacementRule(pattern258, replacement258) pattern259 = Pattern(Integral(S(1)/((d_ + x_*WC('e', S(1)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons49) rule259 = ReplacementRule(pattern259, replacement259) pattern260 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons49, cons244, cons56) rule260 = ReplacementRule(pattern260, replacement260) pattern261 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons49, cons130, cons271) rule261 = ReplacementRule(pattern261, replacement261) pattern262 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons49, cons272, cons246, cons165, cons96, cons273, cons248) rule262 = ReplacementRule(pattern262, replacement262) pattern263 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons49, cons272, cons13, cons165, cons274, cons275, cons33, cons248) rule263 = ReplacementRule(pattern263, replacement263) pattern264 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons49, cons272, cons246, cons139, cons168, cons248) rule264 = ReplacementRule(pattern264, replacement264) pattern265 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons49, cons272, cons13, cons139, cons276, cons33, cons248) rule265 = ReplacementRule(pattern265, replacement265) pattern266 = Pattern(Integral(S(1)/((d_ + x_*WC('e', S(1)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons49) rule266 = ReplacementRule(pattern266, replacement266) pattern267 = Pattern(Integral(S(1)/(sqrt(d_ + x_*WC('e', S(1)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons49, cons277) rule267 = ReplacementRule(pattern267, replacement267) pattern268 = Pattern(Integral(sqrt(d_ + x_*WC('e', S(1)))/sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons49, cons277) rule268 = ReplacementRule(pattern268, replacement268) pattern269 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_/sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons49, cons278) rule269 = ReplacementRule(pattern269, replacement269) pattern270 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons49, cons272, cons33, cons168, cons240, cons279) rule270 = ReplacementRule(pattern270, replacement270) pattern271 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons49, cons272, cons33, cons96, cons280) rule271 = ReplacementRule(pattern271, replacement271) pattern272 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons49) rule272 = ReplacementRule(pattern272, replacement272) pattern273 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons281, cons241, cons130) rule273 = ReplacementRule(pattern273, replacement273) pattern274 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons282, cons130, cons283) rule274 = ReplacementRule(pattern274, replacement274) pattern275 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))/(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons284) rule275 = ReplacementRule(pattern275, With275) pattern276 = Pattern(Integral((d_ + x_*WC('e', S(1)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons285) rule276 = ReplacementRule(pattern276, With276) pattern277 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))/(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons286) rule277 = ReplacementRule(pattern277, replacement277) pattern278 = Pattern(Integral((d_ + x_*WC('e', S(1)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons287) rule278 = ReplacementRule(pattern278, replacement278) pattern279 = Pattern(Integral(sqrt(x_*WC('e', S(1)) + WC('d', S(0)))/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241) rule279 = ReplacementRule(pattern279, replacement279) pattern280 = Pattern(Integral(sqrt(d_ + x_*WC('e', S(1)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282) rule280 = ReplacementRule(pattern280, replacement280) pattern281 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons20, cons168, cons288) rule281 = ReplacementRule(pattern281, replacement281) pattern282 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons20, cons168, cons288) rule282 = ReplacementRule(pattern282, replacement282) pattern283 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons33, cons168) rule283 = ReplacementRule(pattern283, replacement283) pattern284 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons33, cons168) rule284 = ReplacementRule(pattern284, replacement284) pattern285 = Pattern(Integral(S(1)/((x_*WC('e', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241) rule285 = ReplacementRule(pattern285, replacement285) pattern286 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)))*(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons282) rule286 = ReplacementRule(pattern286, replacement286) pattern287 = Pattern(Integral(S(1)/(sqrt(x_*WC('e', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241) rule287 = ReplacementRule(pattern287, replacement287) pattern288 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons282) rule288 = ReplacementRule(pattern288, replacement288) pattern289 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons281, cons241, cons33, cons96) rule289 = ReplacementRule(pattern289, replacement289) pattern290 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons19, cons282, cons33, cons96) rule290 = ReplacementRule(pattern290, replacement290) pattern291 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons281, cons241, cons21) rule291 = ReplacementRule(pattern291, replacement291) pattern292 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons19, cons282, cons21) rule292 = ReplacementRule(pattern292, replacement292) pattern293 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241) rule293 = ReplacementRule(pattern293, replacement293) pattern294 = Pattern(Integral((d_ + x_*WC('e', S(1)))/(a_ + x_**S(2)*WC('c', S(1)))**(S(3)/2), x_), cons2, cons8, cons29, cons50, cons282) rule294 = ReplacementRule(pattern294, replacement294) pattern295 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons13, cons139, cons232) rule295 = ReplacementRule(pattern295, replacement295) pattern296 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons13, cons139, cons232) rule296 = ReplacementRule(pattern296, replacement296) pattern297 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons281, cons241, cons289) rule297 = ReplacementRule(pattern297, replacement297) pattern298 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons5, cons282, cons289) rule298 = ReplacementRule(pattern298, replacement298) pattern299 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons290, cons291, cons292, cons149) rule299 = ReplacementRule(pattern299, replacement299) pattern300 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons3, cons8, cons29, cons50, cons293, cons241, cons33, cons294, cons295, cons296) rule300 = ReplacementRule(pattern300, replacement300) pattern301 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons3, cons8, cons29, cons50, cons293, cons241, cons33, cons294) rule301 = ReplacementRule(pattern301, replacement301) pattern302 = Pattern(Integral(x_**m_/sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons228, cons297) rule302 = ReplacementRule(pattern302, replacement302) pattern303 = Pattern(Integral((e_*x_)**m_/sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons50, cons228, cons297) rule303 = ReplacementRule(pattern303, replacement303) pattern304 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons297) rule304 = ReplacementRule(pattern304, replacement304) pattern305 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_/sqrt(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons297) rule305 = ReplacementRule(pattern305, replacement305) pattern306 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons246, cons298, cons165) rule306 = ReplacementRule(pattern306, replacement306) pattern307 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons282, cons246, cons298, cons165) rule307 = ReplacementRule(pattern307, replacement307) pattern308 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons246, cons298, cons139) rule308 = ReplacementRule(pattern308, replacement308) pattern309 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons282, cons246, cons298, cons139) rule309 = ReplacementRule(pattern309, replacement309) pattern310 = Pattern(Integral(S(1)/((x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons241) rule310 = ReplacementRule(pattern310, replacement310) pattern311 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('c', S(1)))*(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons299) rule311 = ReplacementRule(pattern311, replacement311) pattern312 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons281, cons241, cons149, cons242) rule312 = ReplacementRule(pattern312, replacement312) pattern313 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons282, cons149, cons242) rule313 = ReplacementRule(pattern313, replacement313) pattern314 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons281, cons241, cons244, cons13, cons139) rule314 = ReplacementRule(pattern314, replacement314) pattern315 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons5, cons282, cons244, cons13, cons139) rule315 = ReplacementRule(pattern315, replacement315) pattern316 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons281, cons241, cons244) rule316 = ReplacementRule(pattern316, replacement316) pattern317 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons5, cons282, cons244) rule317 = ReplacementRule(pattern317, replacement317) pattern318 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons281, cons241, cons13, cons165, cons300, cons68, cons301, cons302) rule318 = ReplacementRule(pattern318, replacement318) pattern319 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons282, cons13, cons165, cons300, cons68, cons301, cons303) rule319 = ReplacementRule(pattern319, replacement319) pattern320 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons281, cons241, cons13, cons165, cons240, cons304, cons305, cons302) rule320 = ReplacementRule(pattern320, replacement320) pattern321 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons282, cons13, cons165, cons240, cons304, cons305, cons303) rule321 = ReplacementRule(pattern321, replacement321) pattern322 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons246, cons139, cons170, cons306, cons302) rule322 = ReplacementRule(pattern322, replacement322) pattern323 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons282, cons246, cons139, cons170, cons306, cons303) rule323 = ReplacementRule(pattern323, replacement323) pattern324 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons241, cons246, cons139, cons168, cons302) rule324 = ReplacementRule(pattern324, replacement324) pattern325 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons282, cons246, cons139, cons168, cons303) rule325 = ReplacementRule(pattern325, replacement325) pattern326 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons228, cons281, cons241, cons13, cons139, cons302) rule326 = ReplacementRule(pattern326, replacement326) pattern327 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons282, cons13, cons139, cons303) rule327 = ReplacementRule(pattern327, replacement327) pattern328 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons281, cons241, cons307, cons240, cons302) rule328 = ReplacementRule(pattern328, replacement328) pattern329 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons5, cons282, cons307, cons240, cons303) rule329 = ReplacementRule(pattern329, replacement329) pattern330 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons281, cons241, cons308) rule330 = ReplacementRule(pattern330, replacement330) pattern331 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_, x_), cons2, cons8, cons29, cons50, cons19, cons5, cons282, cons309) rule331 = ReplacementRule(pattern331, replacement331) pattern332 = Pattern(Integral(S(1)/((x_*WC('e', S(1)) + WC('d', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**(S(1)/3)), x_), cons2, cons3, cons8, cons29, cons50, cons241, cons310, cons311) rule332 = ReplacementRule(pattern332, With332) pattern333 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)))**(S(1)/3)*(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons312) rule333 = ReplacementRule(pattern333, With333) pattern334 = Pattern(Integral(S(1)/((x_*WC('e', S(1)) + WC('d', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**(S(1)/3)), x_), cons2, cons3, cons8, cons29, cons50, cons241, cons310, cons313) rule334 = ReplacementRule(pattern334, With334) pattern335 = Pattern(Integral(S(1)/((x_*WC('e', S(1)) + WC('d', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**(S(1)/3)), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons314) rule335 = ReplacementRule(pattern335, With335) pattern336 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)))**(S(1)/4)*(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons282) rule336 = ReplacementRule(pattern336, replacement336) pattern337 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)))**(S(3)/4)*(d_ + x_*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons282) rule337 = ReplacementRule(pattern337, replacement337) pattern338 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons234, cons231) rule338 = ReplacementRule(pattern338, replacement338) pattern339 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons315, cons231) rule339 = ReplacementRule(pattern339, replacement339) pattern340 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons282, cons149, cons45, cons295) rule340 = ReplacementRule(pattern340, replacement340) pattern341 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons281, cons241, cons149, cons86) rule341 = ReplacementRule(pattern341, With341) pattern342 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons5, cons282, cons149, cons86) rule342 = ReplacementRule(pattern342, With342) pattern343 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons228, cons281, cons241, cons149) rule343 = ReplacementRule(pattern343, With343) pattern344 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons282, cons149) rule344 = ReplacementRule(pattern344, With344) pattern345 = Pattern(Integral((u_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons70, cons71) rule345 = ReplacementRule(pattern345, replacement345) pattern346 = Pattern(Integral((a_ + u_**S(2)*WC('c', S(1)))**WC('p', S(1))*(u_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons70, cons71) rule346 = ReplacementRule(pattern346, replacement346) pattern347 = Pattern(Integral(x_**WC('n', S(1))*(a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons5, cons87, cons316) rule347 = ReplacementRule(pattern347, replacement347) pattern348 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))/sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons47, cons318) rule348 = ReplacementRule(pattern348, replacement348) pattern349 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons47, cons318, cons149, cons244) rule349 = ReplacementRule(pattern349, replacement349) pattern350 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons47, cons318, cons149, cons246, cons139, cons170) rule350 = ReplacementRule(pattern350, replacement350) pattern351 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons47, cons318, cons149, cons13, cons139, cons319) rule351 = ReplacementRule(pattern351, replacement351) pattern352 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons47, cons318, cons149, cons33, cons96, cons227, cons320) rule352 = ReplacementRule(pattern352, replacement352) pattern353 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons47, cons318, cons149, cons33, cons96, cons321) rule353 = ReplacementRule(pattern353, replacement353) pattern354 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons47, cons318, cons149, cons64, cons321, cons322) rule354 = ReplacementRule(pattern354, replacement354) pattern355 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons47, cons318, cons149, cons321) rule355 = ReplacementRule(pattern355, replacement355) pattern356 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons47, cons323, cons149, cons241, cons13, cons324) rule356 = ReplacementRule(pattern356, replacement356) pattern357 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons47, cons323, cons149, cons325) rule357 = ReplacementRule(pattern357, replacement357) pattern358 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons47, cons323, cons149, cons241, cons244) rule358 = ReplacementRule(pattern358, replacement358) pattern359 = Pattern(Integral((f_ + x_*WC('g', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons47, cons323, cons149, cons241, cons321, cons272, cons33, cons96) rule359 = ReplacementRule(pattern359, replacement359) pattern360 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons47, cons323, cons149, cons241, cons321, cons272, cons274, cons326) rule360 = ReplacementRule(pattern360, replacement360) pattern361 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons317, cons47, cons149) rule361 = ReplacementRule(pattern361, replacement361) pattern362 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons317, cons228, cons258, cons40) rule362 = ReplacementRule(pattern362, replacement362) pattern363 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons317, cons259, cons327) rule363 = ReplacementRule(pattern363, replacement363) pattern364 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons258, cons86, cons316) rule364 = ReplacementRule(pattern364, replacement364) pattern365 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons259, cons86, cons316) rule365 = ReplacementRule(pattern365, replacement365) pattern366 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons328) rule366 = ReplacementRule(pattern366, replacement366) pattern367 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons329) rule367 = ReplacementRule(pattern367, replacement367) pattern368 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons258, cons246, cons139, cons170) rule368 = ReplacementRule(pattern368, replacement368) pattern369 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons259, cons246, cons139, cons170) rule369 = ReplacementRule(pattern369, replacement369) pattern370 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons141, cons330, cons56) rule370 = ReplacementRule(pattern370, replacement370) pattern371 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons141, cons330, cons56) rule371 = ReplacementRule(pattern371, replacement371) pattern372 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons331, cons255) rule372 = ReplacementRule(pattern372, replacement372) pattern373 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons331, cons255) rule373 = ReplacementRule(pattern373, replacement373) pattern374 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons321) rule374 = ReplacementRule(pattern374, replacement374) pattern375 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons321) rule375 = ReplacementRule(pattern375, replacement375) pattern376 = Pattern(Integral(x_**S(2)*(a_ + x_**S(2)*WC('c', S(1)))**p_*(f_ + x_*WC('g', S(1))), x_), cons2, cons8, cons127, cons210, cons332, cons13, cons333) rule376 = ReplacementRule(pattern376, replacement376) pattern377 = Pattern(Integral(x_**S(2)*(a_ + x_**S(2)*WC('c', S(1)))**p_*(f_ + x_*WC('g', S(1))), x_), cons2, cons8, cons127, cons210, cons5, cons332) rule377 = ReplacementRule(pattern377, replacement377) pattern378 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons258, cons149, cons152, cons13, cons334) rule378 = ReplacementRule(pattern378, replacement378) pattern379 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons259, cons149, cons152, cons13, cons334) rule379 = ReplacementRule(pattern379, replacement379) pattern380 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons258, cons149, cons150, cons335) rule380 = ReplacementRule(pattern380, replacement380) pattern381 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons259, cons149, cons150, cons335) rule381 = ReplacementRule(pattern381, replacement381) pattern382 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons258, cons149, cons198, cons335) rule382 = ReplacementRule(pattern382, replacement382) pattern383 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))/(d_ + x_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons259, cons149, cons198, cons335) rule383 = ReplacementRule(pattern383, replacement383) pattern384 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons228, cons258, cons149, cons43, cons336, cons337) rule384 = ReplacementRule(pattern384, replacement384) pattern385 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons259, cons149, cons43, cons338, cons337) rule385 = ReplacementRule(pattern385, replacement385) pattern386 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons228, cons258, cons149, cons43, cons339) rule386 = ReplacementRule(pattern386, replacement386) pattern387 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons259, cons149, cons43, cons339) rule387 = ReplacementRule(pattern387, replacement387) pattern388 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons258, cons149, cons43, cons340, cons165, cons91, cons341) rule388 = ReplacementRule(pattern388, replacement388) pattern389 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons259, cons149, cons43, cons340, cons165, cons91, cons341) rule389 = ReplacementRule(pattern389, replacement389) pattern390 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons317, cons228, cons258, cons149, cons43, cons340, cons165, cons337, cons342, cons343) rule390 = ReplacementRule(pattern390, replacement390) pattern391 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons317, cons259, cons149, cons43, cons340, cons165, cons337, cons342, cons343) rule391 = ReplacementRule(pattern391, replacement391) pattern392 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons258, cons149, cons43, cons340, cons139, cons90) rule392 = ReplacementRule(pattern392, replacement392) pattern393 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons259, cons149, cons43, cons340, cons139, cons90) rule393 = ReplacementRule(pattern393, replacement393) pattern394 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons317, cons228, cons258, cons149, cons43, cons340, cons139) rule394 = ReplacementRule(pattern394, replacement394) pattern395 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons317, cons259, cons149, cons43, cons340, cons139) rule395 = ReplacementRule(pattern395, replacement395) pattern396 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons149, cons43, cons89, cons90, cons337, cons344) rule396 = ReplacementRule(pattern396, replacement396) pattern397 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons149, cons43, cons89, cons90, cons337, cons344) rule397 = ReplacementRule(pattern397, replacement397) pattern398 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons149, cons43, cons89, cons91, cons248) rule398 = ReplacementRule(pattern398, replacement398) pattern399 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons149, cons43, cons89, cons91, cons248) rule399 = ReplacementRule(pattern399, replacement399) pattern400 = Pattern(Integral(sqrt(d_ + x_*WC('e', S(1)))/((x_*WC('g', S(1)) + WC('f', S(0)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons258) rule400 = ReplacementRule(pattern400, replacement400) pattern401 = Pattern(Integral(sqrt(d_ + x_*WC('e', S(1)))/(sqrt(a_ + x_**S(2)*WC('c', S(1)))*(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons259) rule401 = ReplacementRule(pattern401, replacement401) pattern402 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons228, cons258, cons149, cons345, cons346, cons128) rule402 = ReplacementRule(pattern402, replacement402) pattern403 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons259, cons149, cons345, cons347, cons128) rule403 = ReplacementRule(pattern403, replacement403) pattern404 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons149, cons345, cons89, cons91, cons248) rule404 = ReplacementRule(pattern404, replacement404) pattern405 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons149, cons345, cons89, cons91, cons248) rule405 = ReplacementRule(pattern405, replacement405) pattern406 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons228, cons258, cons149, cons345, cons348, cons248) rule406 = ReplacementRule(pattern406, replacement406) pattern407 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons317, cons259, cons149, cons345, cons348, cons248) rule407 = ReplacementRule(pattern407, replacement407) pattern408 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons317, cons228, cons258, cons149, cons209) rule408 = ReplacementRule(pattern408, replacement408) pattern409 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons317, cons259, cons349, cons152, cons350, cons351) rule409 = ReplacementRule(pattern409, replacement409) pattern410 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons317, cons259, cons149, cons209) rule410 = ReplacementRule(pattern410, replacement410) pattern411 = Pattern(Integral(x_**S(2)*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/(d_ + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons228, cons258) rule411 = ReplacementRule(pattern411, replacement411) pattern412 = Pattern(Integral(x_**S(2)*(a_ + x_**S(2)*WC('c', S(1)))**p_/(d_ + x_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons5, cons259) rule412 = ReplacementRule(pattern412, replacement412) pattern413 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**S(2)*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons258, cons149, cons272) rule413 = ReplacementRule(pattern413, replacement413) pattern414 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**S(2), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons259, cons149, cons272) rule414 = ReplacementRule(pattern414, replacement414) pattern415 = Pattern(Integral((x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons3, cons8, cons50, cons127, cons210, cons19, cons4, cons149) rule415 = ReplacementRule(pattern415, replacement415) pattern416 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons317, cons259, cons149, cons45, cons270) rule416 = ReplacementRule(pattern416, replacement416) pattern417 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons317, cons228, cons258, cons149) rule417 = ReplacementRule(pattern417, replacement417) pattern418 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(d_ + x_*WC('e', S(1)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons317, cons259, cons149) rule418 = ReplacementRule(pattern418, replacement418) pattern419 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons228, cons281, cons130) rule419 = ReplacementRule(pattern419, replacement419) pattern420 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons282, cons130) rule420 = ReplacementRule(pattern420, replacement420) pattern421 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))/((x_*WC('e', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281) rule421 = ReplacementRule(pattern421, replacement421) pattern422 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282) rule422 = ReplacementRule(pattern422, replacement422) pattern423 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons281, cons244, cons352) rule423 = ReplacementRule(pattern423, replacement423) pattern424 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons282, cons244, cons353) rule424 = ReplacementRule(pattern424, replacement424) pattern425 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons244, cons13, cons139, cons354) rule425 = ReplacementRule(pattern425, replacement425) pattern426 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons244, cons13, cons139, cons355) rule426 = ReplacementRule(pattern426, replacement426) pattern427 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons281, cons244) rule427 = ReplacementRule(pattern427, replacement427) pattern428 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons282, cons244) rule428 = ReplacementRule(pattern428, replacement428) pattern429 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons228, cons281, cons356) rule429 = ReplacementRule(pattern429, replacement429) pattern430 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons282, cons357) rule430 = ReplacementRule(pattern430, replacement430) pattern431 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons13, cons139) rule431 = ReplacementRule(pattern431, replacement431) pattern432 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons13, cons139) rule432 = ReplacementRule(pattern432, replacement432) pattern433 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons228, cons281, cons289) rule433 = ReplacementRule(pattern433, replacement433) pattern434 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons282, cons289) rule434 = ReplacementRule(pattern434, replacement434) pattern435 = Pattern(Integral((x_*WC('e', S(1)))**m_*(a_ + x_**S(2)*WC('c', S(1)))**p_*(f_ + x_*WC('g', S(1))), x_), cons2, cons8, cons50, cons127, cons210, cons5, cons358, cons359) rule435 = ReplacementRule(pattern435, replacement435) pattern436 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons360, cons290, cons291) rule436 = ReplacementRule(pattern436, replacement436) pattern437 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons246, cons165, cons249, cons361, cons362) rule437 = ReplacementRule(pattern437, replacement437) pattern438 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons246, cons165, cons249, cons361, cons362) rule438 = ReplacementRule(pattern438, replacement438) pattern439 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons228, cons281, cons13, cons165, cons363, cons68, cons301, cons364) rule439 = ReplacementRule(pattern439, replacement439) pattern440 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons282, cons13, cons165, cons363, cons68, cons301, cons364) rule440 = ReplacementRule(pattern440, replacement440) pattern441 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons228, cons281, cons13, cons165, cons365, cons305, cons364) rule441 = ReplacementRule(pattern441, replacement441) pattern442 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons282, cons13, cons165, cons365, cons305, cons364) rule442 = ReplacementRule(pattern442, replacement442) pattern443 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons246, cons139, cons168, cons366) rule443 = ReplacementRule(pattern443, replacement443) pattern444 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons246, cons139, cons168, cons367) rule444 = ReplacementRule(pattern444, replacement444) pattern445 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons246, cons139, cons170, cons368, cons364) rule445 = ReplacementRule(pattern445, replacement445) pattern446 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons246, cons139, cons170, cons368, cons364) rule446 = ReplacementRule(pattern446, replacement446) pattern447 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons228, cons281, cons13, cons139, cons364) rule447 = ReplacementRule(pattern447, replacement447) pattern448 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons13, cons139, cons364) rule448 = ReplacementRule(pattern448, replacement448) pattern449 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons20) rule449 = ReplacementRule(pattern449, replacement449) pattern450 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons20) rule450 = ReplacementRule(pattern450, replacement450) pattern451 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons369, cons170) rule451 = ReplacementRule(pattern451, replacement451) pattern452 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons369, cons170) rule452 = ReplacementRule(pattern452, replacement452) pattern453 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))/(sqrt(x_*WC('e', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281) rule453 = ReplacementRule(pattern453, replacement453) pattern454 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282) rule454 = ReplacementRule(pattern454, replacement454) pattern455 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons228, cons281, cons369, cons96) rule455 = ReplacementRule(pattern455, replacement455) pattern456 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons317, cons282, cons369, cons96) rule456 = ReplacementRule(pattern456, replacement456) pattern457 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons358) rule457 = ReplacementRule(pattern457, replacement457) pattern458 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons358) rule458 = ReplacementRule(pattern458, replacement458) pattern459 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons228, cons281, cons33, cons170, cons321, cons370, cons364) rule459 = ReplacementRule(pattern459, replacement459) pattern460 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons282, cons33, cons170, cons321, cons370, cons364) rule460 = ReplacementRule(pattern460, replacement460) pattern461 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons228, cons281, cons33, cons96, cons364) rule461 = ReplacementRule(pattern461, replacement461) pattern462 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons5, cons317, cons282, cons33, cons96, cons364) rule462 = ReplacementRule(pattern462, replacement462) pattern463 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons281, cons371, cons68) rule463 = ReplacementRule(pattern463, replacement463) pattern464 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons282, cons371, cons68) rule464 = ReplacementRule(pattern464, replacement464) pattern465 = Pattern(Integral((f_ + x_*WC('g', S(1)))/((x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons372, cons373, cons374) rule465 = ReplacementRule(pattern465, replacement465) pattern466 = Pattern(Integral((f_ + x_*WC('g', S(1)))/(sqrt(x_)*sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons127, cons210, cons228) rule466 = ReplacementRule(pattern466, replacement466) pattern467 = Pattern(Integral((f_ + x_*WC('g', S(1)))/(sqrt(x_)*sqrt(a_ + x_**S(2)*WC('c', S(1)))), x_), cons2, cons8, cons127, cons210, cons375) rule467 = ReplacementRule(pattern467, replacement467) pattern468 = Pattern(Integral((f_ + x_*WC('g', S(1)))/(sqrt(e_*x_)*sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons50, cons127, cons210, cons228) rule468 = ReplacementRule(pattern468, replacement468) pattern469 = Pattern(Integral((f_ + x_*WC('g', S(1)))/(sqrt(e_*x_)*sqrt(a_ + x_**S(2)*WC('c', S(1)))), x_), cons2, cons8, cons50, cons127, cons210, cons376) rule469 = ReplacementRule(pattern469, replacement469) pattern470 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons281) rule470 = ReplacementRule(pattern470, replacement470) pattern471 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons282) rule471 = ReplacementRule(pattern471, replacement471) pattern472 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons228, cons281, cons377) rule472 = ReplacementRule(pattern472, replacement472) pattern473 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons282, cons377) rule473 = ReplacementRule(pattern473, replacement473) pattern474 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/((x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons151, cons165) rule474 = ReplacementRule(pattern474, replacement474) pattern475 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_/((x_*WC('e', S(1)) + WC('d', S(0)))*(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons151, cons165) rule475 = ReplacementRule(pattern475, replacement475) pattern476 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons378, cons369) rule476 = ReplacementRule(pattern476, With476) pattern477 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons378, cons369) rule477 = ReplacementRule(pattern477, With477) pattern478 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(f_ + x_*WC('g', S(1)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons126, cons338, cons379) rule478 = ReplacementRule(pattern478, replacement478) pattern479 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(f_ + x_*WC('g', S(1)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons126, cons338, cons379) rule479 = ReplacementRule(pattern479, replacement479) pattern480 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(f_ + x_*WC('g', S(1)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons126, cons338) rule480 = ReplacementRule(pattern480, replacement480) pattern481 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(f_ + x_*WC('g', S(1)))**n_*(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons126, cons338) rule481 = ReplacementRule(pattern481, replacement481) pattern482 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons228, cons281, cons95) rule482 = ReplacementRule(pattern482, replacement482) pattern483 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons282, cons95) rule483 = ReplacementRule(pattern483, replacement483) pattern484 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons228, cons281, cons21, cons25, cons95, cons170, cons167) rule484 = ReplacementRule(pattern484, replacement484) pattern485 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons282, cons21, cons25, cons95, cons170, cons167) rule485 = ReplacementRule(pattern485, replacement485) pattern486 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons228, cons281, cons21, cons25, cons95, cons170, cons90) rule486 = ReplacementRule(pattern486, replacement486) pattern487 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons282, cons21, cons25, cons95, cons170, cons90) rule487 = ReplacementRule(pattern487, replacement487) pattern488 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons228, cons281, cons21, cons25, cons95, cons170, cons91) rule488 = ReplacementRule(pattern488, replacement488) pattern489 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons282, cons21, cons25, cons95, cons170, cons91) rule489 = ReplacementRule(pattern489, replacement489) pattern490 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/(sqrt(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons228, cons281, cons75) rule490 = ReplacementRule(pattern490, replacement490) pattern491 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_/(sqrt(x_*WC('g', S(1)) + WC('f', S(0)))*(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons282, cons75) rule491 = ReplacementRule(pattern491, replacement491) pattern492 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons228, cons281, cons21, cons25) rule492 = ReplacementRule(pattern492, replacement492) pattern493 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(a_ + x_**S(2)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons282, cons21, cons25) rule493 = ReplacementRule(pattern493, replacement493) pattern494 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons380) rule494 = ReplacementRule(pattern494, replacement494) pattern495 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons380) rule495 = ReplacementRule(pattern495, replacement495) pattern496 = Pattern(Integral((x_*WC('g', S(1)))**WC('n', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons210, cons19, cons4, cons5, cons360, cons290, cons291) rule496 = ReplacementRule(pattern496, replacement496) pattern497 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons25, cons149, cons340, cons165, cons91) rule497 = ReplacementRule(pattern497, replacement497) pattern498 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons25, cons149, cons340, cons165, cons91) rule498 = ReplacementRule(pattern498, replacement498) pattern499 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons25, cons149, cons340, cons139, cons90) rule499 = ReplacementRule(pattern499, replacement499) pattern500 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons25, cons149, cons340, cons139, cons90) rule500 = ReplacementRule(pattern500, replacement500) pattern501 = Pattern(Integral(S(1)/((x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_*WC('g', S(1)) + WC('f', S(0)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281) rule501 = ReplacementRule(pattern501, With501) pattern502 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('c', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282) rule502 = ReplacementRule(pattern502, With502) pattern503 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**n_/((x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281, cons82) rule503 = ReplacementRule(pattern503, replacement503) pattern504 = Pattern(Integral((x_*WC('g', S(1)) + WC('f', S(0)))**n_/(sqrt(a_ + x_**S(2)*WC('c', S(1)))*(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282, cons82) rule504 = ReplacementRule(pattern504, replacement504) pattern505 = Pattern(Integral(S(1)/(sqrt(x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_*WC('g', S(1)) + WC('f', S(0)))*sqrt(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons317, cons228, cons281) rule505 = ReplacementRule(pattern505, replacement505) pattern506 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_*WC('e', S(1)) + WC('d', S(0)))*sqrt(x_*WC('g', S(1)) + WC('f', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons317, cons282) rule506 = ReplacementRule(pattern506, replacement506) pattern507 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(f_ + x_*WC('g', S(1)))**S(2), x_), cons2, cons8, cons50, cons127, cons210, cons19, cons5, cons381) rule507 = ReplacementRule(pattern507, replacement507) pattern508 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(f_ + x_*WC('g', S(1)))**S(3), x_), cons2, cons8, cons50, cons127, cons210, cons19, cons5, cons381) rule508 = ReplacementRule(pattern508, replacement508) pattern509 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons228, cons281, cons150) rule509 = ReplacementRule(pattern509, replacement509) pattern510 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**m_*(x_*WC('g', S(1)) + WC('f', S(0)))**n_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons317, cons282, cons150) rule510 = ReplacementRule(pattern510, replacement510) pattern511 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons382) rule511 = ReplacementRule(pattern511, replacement511) pattern512 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons383) rule512 = ReplacementRule(pattern512, replacement512) pattern513 = Pattern(Integral((u_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(u_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(a_ + u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons70, cons71) rule513 = ReplacementRule(pattern513, replacement513) pattern514 = Pattern(Integral((a_ + u_**S(2)*WC('c', S(1)))**WC('p', S(1))*(u_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(u_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons70, cons71) rule514 = ReplacementRule(pattern514, replacement514) pattern515 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons384, cons385, cons386, cons387) rule515 = ReplacementRule(pattern515, replacement515) pattern516 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons384, cons385, cons149, cons388, cons389) rule516 = ReplacementRule(pattern516, replacement516) pattern517 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons47, cons149) rule517 = ReplacementRule(pattern517, replacement517) pattern518 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons5, cons52, cons47, cons149) rule518 = ReplacementRule(pattern518, replacement518) pattern519 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons52, cons390, cons391, cons392) rule519 = ReplacementRule(pattern519, replacement519) pattern520 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons52, cons393, cons391, cons392) rule520 = ReplacementRule(pattern520, replacement520) pattern521 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**q_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons127, cons52, cons391, cons394) rule521 = ReplacementRule(pattern521, replacement521) pattern522 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**q_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons127, cons52, cons395) rule522 = ReplacementRule(pattern522, replacement522) pattern523 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons396, cons395) rule523 = ReplacementRule(pattern523, replacement523) pattern524 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons396, cons395) rule524 = ReplacementRule(pattern524, replacement524) pattern525 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons396, cons397, cons398, cons399) rule525 = ReplacementRule(pattern525, replacement525) pattern526 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons396, cons397, cons398, cons400) rule526 = ReplacementRule(pattern526, replacement526) pattern527 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**q_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons127, cons397, cons398, cons401) rule527 = ReplacementRule(pattern527, replacement527) pattern528 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons29, cons50, cons127, cons2, cons3, cons8, cons52, cons396, cons402, cons403, cons399) rule528 = ReplacementRule(pattern528, replacement528) pattern529 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons29, cons50, cons127, cons2, cons8, cons52, cons396, cons402, cons403, cons400) rule529 = ReplacementRule(pattern529, replacement529) pattern530 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**q_*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1))), x_), cons29, cons127, cons2, cons3, cons8, cons52, cons402, cons403, cons401) rule530 = ReplacementRule(pattern530, replacement530) pattern531 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396, cons404, cons139, cons405) rule531 = ReplacementRule(pattern531, replacement531) pattern532 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + WC('d', S(0)))**WC('q', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons228, cons404, cons139, cons405) rule532 = ReplacementRule(pattern532, replacement532) pattern533 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons396, cons404, cons139, cons405) rule533 = ReplacementRule(pattern533, replacement533) pattern534 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons52, cons228, cons396, cons13, cons139, cons406, cons407) rule534 = ReplacementRule(pattern534, replacement534) pattern535 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + WC('d', S(0)))**WC('q', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons52, cons228, cons13, cons139, cons408, cons407) rule535 = ReplacementRule(pattern535, replacement535) pattern536 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons52, cons396, cons13, cons139, cons409, cons407) rule536 = ReplacementRule(pattern536, replacement536) pattern537 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons52, cons228, cons396, cons13, cons148, cons410, cons411) rule537 = ReplacementRule(pattern537, replacement537) pattern538 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + WC('d', S(0)))**WC('q', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons52, cons228, cons13, cons148, cons410, cons411) rule538 = ReplacementRule(pattern538, replacement538) pattern539 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons52, cons396, cons13, cons148, cons410, cons411) rule539 = ReplacementRule(pattern539, replacement539) pattern540 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396, CustomConstraint(With540)) rule540 = ReplacementRule(pattern540, replacement540) pattern541 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('f', S(1)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons228, CustomConstraint(With541)) rule541 = ReplacementRule(pattern541, replacement541) pattern542 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396, cons412) rule542 = ReplacementRule(pattern542, replacement542) pattern543 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396, cons413, cons233) rule543 = ReplacementRule(pattern543, With543) pattern544 = Pattern(Integral(S(1)/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons396, cons414) rule544 = ReplacementRule(pattern544, replacement544) pattern545 = Pattern(Integral(S(1)/(sqrt(d_ + x_**S(2)*WC('f', S(1)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons228, cons233) rule545 = ReplacementRule(pattern545, With545) pattern546 = Pattern(Integral(S(1)/((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396, cons413, cons415) rule546 = ReplacementRule(pattern546, With546) pattern547 = Pattern(Integral(S(1)/((x_**S(2)*WC('c', S(1)) + WC('a', S(0)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons396, cons416) rule547 = ReplacementRule(pattern547, With547) pattern548 = Pattern(Integral(S(1)/(sqrt(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons127, cons228, cons415) rule548 = ReplacementRule(pattern548, With548) pattern549 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))/(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396) rule549 = ReplacementRule(pattern549, replacement549) pattern550 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))/(d_ + x_**S(2)*WC('f', S(1))), x_), cons2, cons3, cons8, cons29, cons127, cons228) rule550 = ReplacementRule(pattern550, replacement550) pattern551 = Pattern(Integral(sqrt(a_ + x_**S(2)*WC('c', S(1)))/(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons396) rule551 = ReplacementRule(pattern551, replacement551) pattern552 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396) rule552 = ReplacementRule(pattern552, With552) pattern553 = Pattern(Integral(S(1)/(sqrt(d_ + x_**S(2)*WC('f', S(1)))*sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons228) rule553 = ReplacementRule(pattern553, With553) pattern554 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons417) rule554 = ReplacementRule(pattern554, replacement554) pattern555 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons5, cons52, cons418) rule555 = ReplacementRule(pattern555, replacement555) pattern556 = Pattern(Integral((u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons70, cons71) rule556 = ReplacementRule(pattern556, replacement556) pattern557 = Pattern(Integral((u_**S(2)*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons5, cons52, cons70, cons71) rule557 = ReplacementRule(pattern557, replacement557) pattern558 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons384, cons385, cons386, cons387) rule558 = ReplacementRule(pattern558, replacement558) pattern559 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons384, cons385, cons149, cons388, cons389) rule559 = ReplacementRule(pattern559, replacement559) pattern560 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons47) rule560 = ReplacementRule(pattern560, replacement560) pattern561 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons19, cons5, cons52, cons47) rule561 = ReplacementRule(pattern561, replacement561) pattern562 = Pattern(Integral((g_ + x_*WC('h', S(1)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons419, cons420, cons20) rule562 = ReplacementRule(pattern562, replacement562) pattern563 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(g_ + x_*WC('h', S(1)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons421, cons420, cons20) rule563 = ReplacementRule(pattern563, replacement563) pattern564 = Pattern(Integral((g_ + x_*WC('h', S(1)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))**WC('m', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons5, cons419, cons422, cons20) rule564 = ReplacementRule(pattern564, replacement564) pattern565 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(g_ + x_*WC('h', S(1)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons5, cons421, cons422, cons20) rule565 = ReplacementRule(pattern565, replacement565) pattern566 = Pattern(Integral(x_**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons52, cons228, cons423, cons40) rule566 = ReplacementRule(pattern566, replacement566) pattern567 = Pattern(Integral(x_**WC('p', S(1))*(a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons50, cons127, cons52, cons424, cons40) rule567 = ReplacementRule(pattern567, replacement567) pattern568 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons425, cons426, cons272) rule568 = ReplacementRule(pattern568, replacement568) pattern569 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons427, cons428, cons272) rule569 = ReplacementRule(pattern569, replacement569) pattern570 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons19, cons5, cons429, cons426, cons272) rule570 = ReplacementRule(pattern570, replacement570) pattern571 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons228, cons396, cons430) rule571 = ReplacementRule(pattern571, replacement571) pattern572 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons396, cons430) rule572 = ReplacementRule(pattern572, replacement572) pattern573 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons19, cons228, cons430) rule573 = ReplacementRule(pattern573, replacement573) pattern574 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(g_ + x_*WC('h', S(1)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons19, cons430) rule574 = ReplacementRule(pattern574, replacement574) pattern575 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons228, cons396, cons33, cons96, cons431) rule575 = ReplacementRule(pattern575, replacement575) pattern576 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**m_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons396, cons33, cons96, cons432) rule576 = ReplacementRule(pattern576, replacement576) pattern577 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**m_*(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons5, cons228, cons33, cons96, cons431) rule577 = ReplacementRule(pattern577, replacement577) pattern578 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(g_ + x_*WC('h', S(1)))**m_*(x_**S(2)*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons5, cons33, cons96, cons432) rule578 = ReplacementRule(pattern578, replacement578) pattern579 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))/((x_*WC('h', S(1)) + WC('g', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons431) rule579 = ReplacementRule(pattern579, replacement579) pattern580 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))**(S(3)/2)*(x_*WC('h', S(1)) + WC('g', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons396, cons432) rule580 = ReplacementRule(pattern580, replacement580) pattern581 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + WC('d', S(0)))/((x_*WC('h', S(1)) + WC('g', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228, cons431) rule581 = ReplacementRule(pattern581, replacement581) pattern582 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + WC('d', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))**(S(3)/2)*(g_ + x_*WC('h', S(1)))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons432) rule582 = ReplacementRule(pattern582, replacement582) pattern583 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**m_*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons246, cons139, cons168) rule583 = ReplacementRule(pattern583, replacement583) pattern584 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))**m_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons396, cons246, cons139, cons168) rule584 = ReplacementRule(pattern584, replacement584) pattern585 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**m_*(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228, cons246, cons139, cons168) rule585 = ReplacementRule(pattern585, replacement585) pattern586 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(g_ + x_*WC('h', S(1)))**m_*(x_**S(2)*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons246, cons139, cons168) rule586 = ReplacementRule(pattern586, replacement586) pattern587 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons228, cons396, cons13, cons139, cons433) rule587 = ReplacementRule(pattern587, replacement587) pattern588 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons396, cons13, cons139, cons432) rule588 = ReplacementRule(pattern588, replacement588) pattern589 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons19, cons228, cons13, cons139, cons433) rule589 = ReplacementRule(pattern589, replacement589) pattern590 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**p_*(g_ + x_*WC('h', S(1)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons19, cons13, cons139, cons432) rule590 = ReplacementRule(pattern590, replacement590) pattern591 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons228, cons396, cons244) rule591 = ReplacementRule(pattern591, replacement591) pattern592 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons396, cons244) rule592 = ReplacementRule(pattern592, replacement592) pattern593 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons19, cons5, cons228, cons244) rule593 = ReplacementRule(pattern593, replacement593) pattern594 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(g_ + x_*WC('h', S(1)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons19, cons5, cons244) rule594 = ReplacementRule(pattern594, replacement594) pattern595 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons228, cons396, cons272) rule595 = ReplacementRule(pattern595, replacement595) pattern596 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons396, cons272) rule596 = ReplacementRule(pattern596, replacement596) pattern597 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))*(x_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons19, cons5, cons228, cons272) rule597 = ReplacementRule(pattern597, replacement597) pattern598 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)))*(g_ + x_*WC('h', S(1)))**WC('m', S(1)), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons19, cons5, cons272) rule598 = ReplacementRule(pattern598, replacement598) pattern599 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons222, cons165) rule599 = ReplacementRule(pattern599, replacement599) pattern600 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons396, cons222, cons434) rule600 = ReplacementRule(pattern600, replacement600) pattern601 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons404, cons139, cons405) rule601 = ReplacementRule(pattern601, replacement601) pattern602 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons396, cons404, cons139, cons405) rule602 = ReplacementRule(pattern602, replacement602) pattern603 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228, cons404, cons139, cons405) rule603 = ReplacementRule(pattern603, replacement603) pattern604 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons52, cons228, cons396, cons13, cons139, cons406, cons407) rule604 = ReplacementRule(pattern604, replacement604) pattern605 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons52, cons396, cons13, cons139, cons409, cons407) rule605 = ReplacementRule(pattern605, replacement605) pattern606 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons52, cons228, cons13, cons139, cons408, cons407) rule606 = ReplacementRule(pattern606, replacement606) pattern607 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons52, cons228, cons396, cons13, cons165, cons435) rule607 = ReplacementRule(pattern607, replacement607) pattern608 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons52, cons396, cons13, cons165, cons435) rule608 = ReplacementRule(pattern608, replacement608) pattern609 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(x_*WC('h', S(1)) + WC('g', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons52, cons228, cons13, cons165, cons435) rule609 = ReplacementRule(pattern609, replacement609) pattern610 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, CustomConstraint(With610)) rule610 = ReplacementRule(pattern610, replacement610) pattern611 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((d_ + x_**S(2)*WC('f', S(1)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228, CustomConstraint(With611)) rule611 = ReplacementRule(pattern611, replacement611) pattern612 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(d_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons436) rule612 = ReplacementRule(pattern612, replacement612) pattern613 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(d_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons437) rule613 = ReplacementRule(pattern613, With613) pattern614 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons412, cons438) rule614 = ReplacementRule(pattern614, replacement614) pattern615 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons412, cons439) rule615 = ReplacementRule(pattern615, replacement615) pattern616 = Pattern(Integral(x_/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons228, cons396, cons385) rule616 = ReplacementRule(pattern616, replacement616) pattern617 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons385, cons440) rule617 = ReplacementRule(pattern617, replacement617) pattern618 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons385, cons441) rule618 = ReplacementRule(pattern618, replacement618) pattern619 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons374, cons442) rule619 = ReplacementRule(pattern619, replacement619) pattern620 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons443) rule620 = ReplacementRule(pattern620, replacement620) pattern621 = Pattern(Integral((g_ + x_*WC('h', S(1)))/(sqrt(d_ + x_**S(2)*WC('f', S(1)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228, cons444) rule621 = ReplacementRule(pattern621, replacement621) pattern622 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons233) rule622 = ReplacementRule(pattern622, With622) pattern623 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons396, cons414) rule623 = ReplacementRule(pattern623, With623) pattern624 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/(sqrt(d_ + x_**S(2)*WC('f', S(1)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228, cons233) rule624 = ReplacementRule(pattern624, With624) pattern625 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396, cons374, cons415) rule625 = ReplacementRule(pattern625, With625) pattern626 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons396, cons416) rule626 = ReplacementRule(pattern626, With626) pattern627 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/(sqrt(d_ + x_**S(2)*WC('f', S(1)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228, cons415) rule627 = ReplacementRule(pattern627, With627) pattern628 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/(sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons228, cons396) rule628 = ReplacementRule(pattern628, With628) pattern629 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/(sqrt(d_ + x_**S(2)*WC('f', S(1)))*sqrt(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons210, cons211, cons228) rule629 = ReplacementRule(pattern629, With629) pattern630 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**(S(1)/3)*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons412, cons445, cons446, cons447) rule630 = ReplacementRule(pattern630, With630) pattern631 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)))**(S(1)/3)*(d_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons448, cons449, cons45) rule631 = ReplacementRule(pattern631, replacement631) pattern632 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))/((x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**(S(1)/3)*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons412, cons445, cons446, cons315) rule632 = ReplacementRule(pattern632, With632) pattern633 = Pattern(Integral((g_ + x_*WC('h', S(1)))/((a_ + x_**S(2)*WC('c', S(1)))**(S(1)/3)*(d_ + x_**S(2)*WC('f', S(1)))), x_), cons2, cons8, cons29, cons127, cons210, cons211, cons448, cons449, cons450) rule633 = ReplacementRule(pattern633, replacement633) pattern634 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons451) rule634 = ReplacementRule(pattern634, replacement634) pattern635 = Pattern(Integral((x_*WC('h', S(1)) + WC('g', S(0)))*(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons5, cons52, cons452) rule635 = ReplacementRule(pattern635, replacement635) pattern636 = Pattern(Integral((u_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons70, cons71) rule636 = ReplacementRule(pattern636, replacement636) pattern637 = Pattern(Integral((u_*WC('h', S(1)) + WC('g', S(0)))**WC('m', S(1))*(u_**S(2)*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons211, cons19, cons5, cons52, cons70, cons71) rule637 = ReplacementRule(pattern637, replacement637) pattern638 = Pattern(Integral(u_**WC('p', S(1))*v_**WC('q', S(1))*z_**WC('m', S(1)), x_), cons19, cons5, cons52, cons453, cons454, cons455) rule638 = ReplacementRule(pattern638, replacement638) pattern639 = Pattern(Integral((d_ + x_*WC('e', S(1)))**WC('m', S(1))*(f_ + x_*WC('g', S(1)))**WC('n', S(1))*(x_*WC('i', S(1)) + WC('h', S(0)))**WC('q', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons19, cons4, cons5, cons52, cons338, cons126, cons379) rule639 = ReplacementRule(pattern639, replacement639) pattern640 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(x_*WC('g', S(1)) + WC('f', S(0)))**WC('n', S(1))*(x_*WC('i', S(1)) + WC('h', S(0)))**WC('q', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons19, cons4, cons5, cons52, cons130, cons86) rule640 = ReplacementRule(pattern640, replacement640) pattern641 = Pattern(Integral((d_ + x_*WC('e', S(1)))**m_*(f_ + x_*WC('g', S(1)))**n_*(x_*WC('i', S(1)) + WC('h', S(0)))**WC('q', S(1))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons211, cons226, cons19, cons4, cons5, cons52, cons338, cons126) rule641 = ReplacementRule(pattern641, replacement641) pattern642 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons384, cons385, cons386, cons387) rule642 = ReplacementRule(pattern642, replacement642) pattern643 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons5, cons52, cons384, cons385, cons386, cons387) rule643 = ReplacementRule(pattern643, replacement643) pattern644 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons384, cons385, cons149, cons388, cons389) rule644 = ReplacementRule(pattern644, replacement644) pattern645 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons5, cons52, cons384, cons385, cons149, cons388, cons389) rule645 = ReplacementRule(pattern645, replacement645) pattern646 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons47) rule646 = ReplacementRule(pattern646, replacement646) pattern647 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons5, cons52, cons47) rule647 = ReplacementRule(pattern647, replacement647) pattern648 = Pattern(Integral((x_**S(2)*WC('f', S(1)) + WC('d', S(0)))**WC('q', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons37, cons38, cons5, cons52, cons47) rule648 = ReplacementRule(pattern648, replacement648) pattern649 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))**WC('q', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons38, cons5, cons52, cons47) rule649 = ReplacementRule(pattern649, replacement649) pattern650 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons228, cons396, cons222, cons165) rule650 = ReplacementRule(pattern650, replacement650) pattern651 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons228, cons396, cons222, cons165) rule651 = ReplacementRule(pattern651, replacement651) pattern652 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons396, cons222, cons434) rule652 = ReplacementRule(pattern652, replacement652) pattern653 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons38, cons396, cons222, cons434) rule653 = ReplacementRule(pattern653, replacement653) pattern654 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons228, cons396, cons404, cons139, cons405) rule654 = ReplacementRule(pattern654, replacement654) pattern655 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons228, cons396, cons404, cons139, cons405) rule655 = ReplacementRule(pattern655, replacement655) pattern656 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons396, cons404, cons139, cons405) rule656 = ReplacementRule(pattern656, replacement656) pattern657 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons38, cons396, cons404, cons139, cons405) rule657 = ReplacementRule(pattern657, replacement657) pattern658 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons37, cons38, cons228, cons404, cons139, cons405) rule658 = ReplacementRule(pattern658, replacement658) pattern659 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons38, cons228, cons404, cons139, cons405) rule659 = ReplacementRule(pattern659, replacement659) pattern660 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons52, cons228, cons396, cons13, cons139, cons406, cons407) rule660 = ReplacementRule(pattern660, replacement660) pattern661 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons52, cons228, cons396, cons13, cons139, cons406, cons407) rule661 = ReplacementRule(pattern661, replacement661) pattern662 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons52, cons396, cons13, cons139, cons409, cons407) rule662 = ReplacementRule(pattern662, replacement662) pattern663 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons38, cons52, cons396, cons13, cons139, cons409, cons407) rule663 = ReplacementRule(pattern663, replacement663) pattern664 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons37, cons38, cons52, cons228, cons13, cons139, cons408, cons407) rule664 = ReplacementRule(pattern664, replacement664) pattern665 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons38, cons52, cons228, cons13, cons139, cons408, cons407) rule665 = ReplacementRule(pattern665, replacement665) pattern666 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons52, cons228, cons396, cons13, cons165, cons435, cons456) rule666 = ReplacementRule(pattern666, replacement666) pattern667 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons52, cons228, cons396, cons13, cons165, cons435, cons456) rule667 = ReplacementRule(pattern667, replacement667) pattern668 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons52, cons396, cons13, cons165, cons435, cons456) rule668 = ReplacementRule(pattern668, replacement668) pattern669 = Pattern(Integral((a_ + x_**S(2)*WC('c', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons38, cons52, cons396, cons13, cons165, cons435, cons456) rule669 = ReplacementRule(pattern669, replacement669) pattern670 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1))*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons37, cons38, cons52, cons228, cons13, cons165, cons435, cons456) rule670 = ReplacementRule(pattern670, replacement670) pattern671 = Pattern(Integral((d_ + x_**S(2)*WC('f', S(1)))**WC('q', S(1))*(x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons38, cons52, cons228, cons13, cons165, cons435, cons456) rule671 = ReplacementRule(pattern671, replacement671) pattern672 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons228, cons396, CustomConstraint(With672)) rule672 = ReplacementRule(pattern672, replacement672) pattern673 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*(d_ + x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons228, cons396, CustomConstraint(With673)) rule673 = ReplacementRule(pattern673, replacement673) pattern674 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/((d_ + x_**S(2)*WC('f', S(1)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons37, cons38, cons228, CustomConstraint(With674)) rule674 = ReplacementRule(pattern674, replacement674) pattern675 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/((d_ + x_**S(2)*WC('f', S(1)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons38, cons228, CustomConstraint(With675)) rule675 = ReplacementRule(pattern675, replacement675) pattern676 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons228, cons396) rule676 = ReplacementRule(pattern676, replacement676) pattern677 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/((a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons228, cons396) rule677 = ReplacementRule(pattern677, replacement677) pattern678 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons396) rule678 = ReplacementRule(pattern678, replacement678) pattern679 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/((a_ + x_**S(2)*WC('c', S(1)))*sqrt(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons38, cons396) rule679 = ReplacementRule(pattern679, replacement679) pattern680 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))/(sqrt(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons37, cons38, cons228) rule680 = ReplacementRule(pattern680, replacement680) pattern681 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))/(sqrt(x_**S(2)*WC('f', S(1)) + WC('d', S(0)))*(a_ + x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons127, cons36, cons38, cons228) rule681 = ReplacementRule(pattern681, replacement681) pattern682 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons457) rule682 = ReplacementRule(pattern682, replacement682) pattern683 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons5, cons52, cons458) rule683 = ReplacementRule(pattern683, replacement683) pattern684 = Pattern(Integral((x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('C', S(1)) + x_*WC('B', S(1)) + WC('A', S(0)))*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons459) rule684 = ReplacementRule(pattern684, replacement684) pattern685 = Pattern(Integral((x_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(x_**S(2)*WC('c', S(1)) + WC('a', S(0)))**p_*(x_**S(2)*WC('f', S(1)) + x_*WC('e', S(1)) + WC('d', S(0)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons36, cons38, cons5, cons52, cons460) rule685 = ReplacementRule(pattern685, replacement685) pattern686 = Pattern(Integral((u_**S(2)*WC('C', S(1)) + u_*WC('B', S(1)) + WC('A', S(0)))*(u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons70, cons71) rule686 = ReplacementRule(pattern686, replacement686) pattern687 = Pattern(Integral((u_*WC('B', S(1)) + WC('A', S(0)))*(u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons70, cons71) rule687 = ReplacementRule(pattern687, replacement687) pattern688 = Pattern(Integral((u_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(u_**S(2)*WC('c', S(1)) + u_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons5, cons52, cons70, cons71) rule688 = ReplacementRule(pattern688, replacement688) pattern689 = Pattern(Integral((u_**S(2)*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('C', S(1)) + u_*WC('B', S(1)) + WC('A', S(0)))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons70, cons71) rule689 = ReplacementRule(pattern689, replacement689) pattern690 = Pattern(Integral((u_*WC('B', S(1)) + WC('A', S(0)))*(u_**S(2)*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons5, cons52, cons70, cons71) rule690 = ReplacementRule(pattern690, replacement690) pattern691 = Pattern(Integral((u_**S(2)*WC('C', S(1)) + WC('A', S(0)))*(u_**S(2)*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*(u_**S(2)*WC('f', S(1)) + u_*WC('e', S(1)) + WC('d', S(0)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons36, cons38, cons5, cons52, cons70, cons71) rule691 = ReplacementRule(pattern691, replacement691) return [rule192, rule193, rule194, rule195, rule196, rule197, rule198, rule199, rule200, rule201, rule202, rule203, rule204, rule205, rule206, rule207, rule208, rule209, rule210, rule211, rule212, rule213, rule214, rule215, rule216, rule217, rule218, rule219, rule220, rule221, rule222, rule223, rule224, rule225, rule226, rule227, rule228, rule229, rule230, rule231, rule232, rule233, rule234, rule235, rule236, rule237, rule238, rule239, rule240, rule241, rule242, rule243, rule244, rule245, rule246, rule247, rule248, rule249, rule250, rule251, rule252, rule253, rule254, rule255, rule256, rule257, rule258, rule259, rule260, rule261, rule262, rule263, rule264, rule265, rule266, rule267, rule268, rule269, rule270, rule271, rule272, rule273, rule274, rule275, rule276, rule277, rule278, rule279, rule280, rule281, rule282, rule283, rule284, rule285, rule286, rule287, rule288, rule289, rule290, rule291, rule292, rule293, rule294, rule295, rule296, rule297, rule298, rule299, rule300, rule301, rule302, rule303, rule304, rule305, rule306, rule307, rule308, rule309, rule310, rule311, rule312, rule313, rule314, rule315, rule316, rule317, rule318, rule319, rule320, rule321, rule322, rule323, rule324, rule325, rule326, rule327, rule328, rule329, rule330, rule331, rule332, rule333, rule334, rule335, rule336, rule337, rule338, rule339, rule340, rule341, rule342, rule343, rule344, rule345, rule346, rule347, rule348, rule349, rule350, rule351, rule352, rule353, rule354, rule355, rule356, rule357, rule358, rule359, rule360, rule361, rule362, rule363, rule364, rule365, rule366, rule367, rule368, rule369, rule370, rule371, rule372, rule373, rule374, rule375, rule376, rule377, rule378, rule379, rule380, rule381, rule382, rule383, rule384, rule385, rule386, rule387, rule388, rule389, rule390, rule391, rule392, rule393, rule394, rule395, rule396, rule397, rule398, rule399, rule400, rule401, rule402, rule403, rule404, rule405, rule406, rule407, rule408, rule409, rule410, rule411, rule412, rule413, rule414, rule415, rule416, rule417, rule418, rule419, rule420, rule421, rule422, rule423, rule424, rule425, rule426, rule427, rule428, rule429, rule430, rule431, rule432, rule433, rule434, rule435, rule436, rule437, rule438, rule439, rule440, rule441, rule442, rule443, rule444, rule445, rule446, rule447, rule448, rule449, rule450, rule451, rule452, rule453, rule454, rule455, rule456, rule457, rule458, rule459, rule460, rule461, rule462, rule463, rule464, rule465, rule466, rule467, rule468, rule469, rule470, rule471, rule472, rule473, rule474, rule475, rule476, rule477, rule478, rule479, rule480, rule481, rule482, rule483, rule484, rule485, rule486, rule487, rule488, rule489, rule490, rule491, rule492, rule493, rule494, rule495, rule496, rule497, rule498, rule499, rule500, rule501, rule502, rule503, rule504, rule505, rule506, rule507, rule508, rule509, rule510, rule511, rule512, rule513, rule514, rule515, rule516, rule517, rule518, rule519, rule520, rule521, rule522, rule523, rule524, rule525, rule526, rule527, rule528, rule529, rule530, rule531, rule532, rule533, rule534, rule535, rule536, rule537, rule538, rule539, rule540, rule541, rule542, rule543, rule544, rule545, rule546, rule547, rule548, rule549, rule550, rule551, rule552, rule553, rule554, rule555, rule556, rule557, rule558, rule559, rule560, rule561, rule562, rule563, rule564, rule565, rule566, rule567, rule568, rule569, rule570, rule571, rule572, rule573, rule574, rule575, rule576, rule577, rule578, rule579, rule580, rule581, rule582, rule583, rule584, rule585, rule586, rule587, rule588, rule589, rule590, rule591, rule592, rule593, rule594, rule595, rule596, rule597, rule598, rule599, rule600, rule601, rule602, rule603, rule604, rule605, rule606, rule607, rule608, rule609, rule610, rule611, rule612, rule613, rule614, rule615, rule616, rule617, rule618, rule619, rule620, rule621, rule622, rule623, rule624, rule625, rule626, rule627, rule628, rule629, rule630, rule631, rule632, rule633, rule634, rule635, rule636, rule637, rule638, rule639, rule640, rule641, rule642, rule643, rule644, rule645, rule646, rule647, rule648, rule649, rule650, rule651, rule652, rule653, rule654, rule655, rule656, rule657, rule658, rule659, rule660, rule661, rule662, rule663, rule664, rule665, rule666, rule667, rule668, rule669, rule670, rule671, rule672, rule673, rule674, rule675, rule676, rule677, rule678, rule679, rule680, rule681, rule682, rule683, rule684, rule685, rule686, rule687, rule688, rule689, rule690, rule691, ] def replacement192(a, b, c, x): return Dist((b/S(2) + c*x)/sqrt(a + b*x + c*x**S(2)), Int(S(1)/(b/S(2) + c*x), x), x) def replacement193(a, b, c, p, x): return Simp((b + S(2)*c*x)*(a + b*x + c*x**S(2))**p/(S(2)*c*(S(2)*p + S(1))), x) def With194(a, b, c, p, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(c**(-p), Int(Simp(b/S(2) + c*x - q/S(2), x)**p*Simp(b/S(2) + c*x + q/S(2), x)**p, x), x) def replacement195(a, b, c, p, x): return Int(ExpandIntegrand((a + b*x + c*x**S(2))**p, x), x) def replacement196(a, b, c, p, x): return -Dist(p*(-S(4)*a*c + b**S(2))/(S(2)*c*(S(2)*p + S(1))), Int((a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((b + S(2)*c*x)*(a + b*x + c*x**S(2))**p/(S(2)*c*(S(2)*p + S(1))), x) def replacement197(a, b, c, x): return Simp(-S(2)*(b + S(2)*c*x)/((-S(4)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))), x) def replacement198(a, b, c, p, x): return -Dist(S(2)*c*(S(2)*p + S(3))/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((b + S(2)*c*x)*(a + b*x + c*x**S(2))**(p + S(1))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def With199(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(c/q, Int(S(1)/Simp(b/S(2) + c*x - q/S(2), x), x), x) - Dist(c/q, Int(S(1)/Simp(b/S(2) + c*x + q/S(2), x), x), x) def With200(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = -S(4)*a*c/b**S(2) + S(1) if And(RationalQ(q), Or(EqQ(q**S(2), S(1)), Not(RationalQ(-S(4)*a*c + b**S(2))))): return True return False def replacement200(a, b, c, x): q = -S(4)*a*c/b**S(2) + S(1) return Dist(-S(2)/b, Subst(Int(S(1)/(q - x**S(2)), x), x, S(1) + S(2)*c*x/b), x) def replacement201(a, b, c, x): return Dist(S(-2), Subst(Int(S(1)/Simp(-S(4)*a*c + b**S(2) - x**S(2), x), x), x, b + S(2)*c*x), x) def replacement202(a, b, c, p, x): return Dist((-S(4)*c/(-S(4)*a*c + b**S(2)))**(-p)/(S(2)*c), Subst(Int(Simp(-x**S(2)/(-S(4)*a*c + b**S(2)) + S(1), x)**p, x), x, b + S(2)*c*x), x) def replacement203(b, c, x): return Dist(S(2), Subst(Int(S(1)/(-c*x**S(2) + S(1)), x), x, x/sqrt(b*x + c*x**S(2))), x) def replacement204(a, b, c, x): return Dist(S(2), Subst(Int(S(1)/(S(4)*c - x**S(2)), x), x, (b + S(2)*c*x)/sqrt(a + b*x + c*x**S(2))), x) def replacement205(b, c, p, x): return Dist((-c*(b*x + c*x**S(2))/b**S(2))**(-p)*(b*x + c*x**S(2))**p, Int((-c*x/b - c**S(2)*x**S(2)/b**S(2))**p, x), x) def With206(a, b, c, p, x): if isinstance(x, (int, Integer, float, Float)): return False d = Denominator(p) if LessEqual(S(3), d, S(4)): return True return False def replacement206(a, b, c, p, x): d = Denominator(p) return Dist(d*sqrt((b + S(2)*c*x)**S(2))/(b + S(2)*c*x), Subst(Int(x**(d*(p + S(1)) + S(-1))/sqrt(-S(4)*a*c + b**S(2) + S(4)*c*x**d), x), x, (a + b*x + c*x**S(2))**(S(1)/d)), x) def With207(a, b, c, p, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return -Simp(((-b - S(2)*c*x + q)/(S(2)*q))**(-p + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Hypergeometric2F1(-p, p + S(1), p + S(2), (b + S(2)*c*x + q)/(S(2)*q))/(q*(p + S(1))), x) def replacement208(a, b, c, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x + c*x**S(2))**p, x), x, u), x) def replacement209(a, b, c, d, e, m, p, x): return Simp(c**(-m/S(2) + S(-1)/2)*e**m*(a + b*x + c*x**S(2))**(m/S(2) + p + S(1)/2)/(m + S(2)*p + S(1)), x) def replacement210(a, b, c, d, e, m, p, x): return Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*log(RemoveContent(d + e*x, x))/e, x) def replacement211(a, b, c, d, e, m, p, x): return Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(2)*p + S(1))), x) def replacement212(a, b, c, d, e, m, p, x): return -Simp((b + S(2)*c*x)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/((m + S(1))*(-b*e + S(2)*c*d)), x) def replacement213(a, b, c, d, e, x): return Dist(sqrt(a + b*x + c*x**S(2))/(b + S(2)*c*x), Int((b + S(2)*c*x)/(d + e*x)**S(2), x), x) def replacement214(a, b, c, d, e, m, x): return -Dist((-b*e + S(2)*c*d)*sqrt(a + b*x + c*x**S(2))/(e*(b + S(2)*c*x)*(m + S(2))), Int((d + e*x)**m, x), x) + Simp((d + e*x)**(m + S(1))*sqrt(a + b*x + c*x**S(2))/(e*(m + S(2))), x) def replacement215(a, b, c, d, e, x): return Dist(S(2)*c/(-b*e + S(2)*c*d), Int(S(1)/((d + e*x)*sqrt(a + b*x + c*x**S(2))), x), x) + Simp(-S(4)*c*e*sqrt(a + b*x + c*x**S(2))/((d + e*x)*(-b*e + S(2)*c*d)**S(2)), x) def replacement216(a, b, c, d, e, m, p, x): return -Simp((b + S(2)*c*x)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/((m + S(2))*(-b*e + S(2)*c*d)), x) + Simp(-S(2)*c*e*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/((-b*e + S(2)*c*d)**S(2)*(m*p + S(-1))), x) def replacement217(a, b, c, d, e, p, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int((a + b*x + c*x**S(2))**p, x), x) + Simp(e*(a + b*x + c*x**S(2))**(p + S(1))/(S(2)*c*(p + S(1))), x) def replacement218(a, b, c, d, e, m, p, x): return Dist(p*(S(2)*p + S(-1))*(-b*e + S(2)*c*d)/(e**S(2)*(m + S(1))*(m + S(2)*p + S(1))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(1))), x) - Simp(p*(b + S(2)*c*x)*(d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**(p + S(-1))/(e**S(2)*(m + S(1))*(m + S(2)*p + S(1))), x) def replacement219(a, b, c, d, e, m, p, x): return Dist(S(2)*c*p*(S(2)*p + S(-1))/(e**S(2)*(m + S(1))*(m + S(2))), Int((d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(1))), x) - Simp(p*(b + S(2)*c*x)*(d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**(p + S(-1))/(e**S(2)*(m + S(1))*(m + S(2))), x) def replacement220(a, b, c, d, e, m, p, x): return Dist(p*(S(2)*p + S(-1))*(-b*e + S(2)*c*d)**S(2)/(S(2)*c*e**S(2)*(m + S(2)*p)*(m + S(2)*p + S(1))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(2)*p + S(1))), x) - Simp(p*(b + S(2)*c*x)*(d + e*x)**(m + S(1))*(-b*e + S(2)*c*d)*(a + b*x + c*x**S(2))**(p + S(-1))/(S(2)*c*e**S(2)*(m + S(2)*p)*(m + S(2)*p + S(1))), x) def replacement221(a, b, c, d, e, m, p, x): return Dist(e**S(2)*m*(m + S(2)*p + S(2))/((p + S(1))*(S(2)*p + S(1))*(-b*e + S(2)*c*d)), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((b + S(2)*c*x)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/((S(2)*p + S(1))*(-b*e + S(2)*c*d)), x) - Simp(e*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*(m + S(2)*p + S(2))/((p + S(1))*(S(2)*p + S(1))*(-b*e + S(2)*c*d)), x) def replacement222(a, b, c, d, e, m, p, x): return Dist(e**S(2)*m*(m + S(-1))/(S(2)*c*(p + S(1))*(S(2)*p + S(1))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((b + S(2)*c*x)*(d + e*x)**m*(a + b*x + c*x**S(2))**p/(S(2)*c*(S(2)*p + S(1))), x) - Simp(e*m*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(S(2)*c*(p + S(1))*(S(2)*p + S(1))), x) def replacement223(a, b, c, d, e, m, p, x): return Dist(S(2)*c*e**S(2)*(m + S(2)*p + S(2))*(m + S(2)*p + S(3))/((p + S(1))*(S(2)*p + S(1))*(-b*e + S(2)*c*d)**S(2)), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((b + S(2)*c*x)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/((S(2)*p + S(1))*(-b*e + S(2)*c*d)), x) + Simp(-S(2)*c*e*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(m + S(2)*p + S(2))/((p + S(1))*(S(2)*p + S(1))*(-b*e + S(2)*c*d)**S(2)), x) def replacement224(a, b, c, d, e, m, p, x): return Dist(m*(-b*e + S(2)*c*d)/(S(2)*c*(m + S(2)*p + S(1))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**p, x), x) + Simp((b + S(2)*c*x)*(d + e*x)**m*(a + b*x + c*x**S(2))**p/(S(2)*c*(m + S(2)*p + S(1))), x) def replacement225(a, b, c, d, e, m, p, x): return Dist(S(2)*c*(m + S(2)*p + S(2))/((m + S(1))*(-b*e + S(2)*c*d)), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) - Simp((b + S(2)*c*x)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/((m + S(1))*(-b*e + S(2)*c*d)), x) def replacement226(a, b, c, d, e, m, p, x): return Dist(c**(-IntPart(p))*(b/S(2) + c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b/S(2) + c*x)**(S(2)*p)*(d + e*x)**m, x), x) def replacement227(a, b, c, d, e, m, p, x): return Int((d + e*x)**(m + p)*(a/d + c*x/e)**p, x) def replacement228(a, c, d, e, m, p, x): return Int((d + e*x)**(m + p)*(a/d + c*x/e)**p, x) def replacement229(a, b, c, d, e, m, p, x): return Simp(e*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*(p + S(1))), x) def replacement230(a, c, d, e, m, p, x): return Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))/(c*(p + S(1))), x) def replacement231(a, b, c, d, e, m, p, x): return Simp(e*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/((p + S(1))*(-b*e + S(2)*c*d)), x) def replacement232(a, c, d, e, m, p, x): return Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(S(2)*c*d*(p + S(1))), x) def replacement233(a, b, c, d, e, p, x): return -Dist(e**S(2)*(p + S(2))/(c*(p + S(1))), Int((a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp(e*(d + e*x)*(a + b*x + c*x**S(2))**(p + S(1))/(c*(p + S(1))), x) def replacement234(a, c, d, e, p, x): return -Dist(e**S(2)*(p + S(2))/(c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1)), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)/(c*(p + S(1))), x) def replacement235(a, b, c, d, e, m, p, x): return Int((a/d + c*x/e)**(-m)*(a + b*x + c*x**S(2))**(m + p), x) def replacement236(a, c, d, e, m, p, x): return Dist(a**(-m)*d**(S(2)*m), Int((a + c*x**S(2))**(m + p)*(d - e*x)**(-m), x), x) def replacement237(a, b, c, d, e, m, p, x): return Dist((m + p)*(-b*e + S(2)*c*d)/(c*(m + S(2)*p + S(1))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**p, x), x) + Simp(e*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(1))), x) def replacement238(a, c, d, e, m, p, x): return Dist(S(2)*d*(m + p)/(m + S(2)*p + S(1)), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(-1)), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))/(c*(m + S(2)*p + S(1))), x) def replacement239(a, b, c, d, e, m, p, x): return Dist(c*(m + S(2)*p + S(2))/((-b*e + S(2)*c*d)*(m + p + S(1))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) - Simp(e*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/((-b*e + S(2)*c*d)*(m + p + S(1))), x) def replacement240(a, c, d, e, m, p, x): return Dist((m + S(2)*p + S(2))/(S(2)*d*(m + p + S(1))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1)), x), x) - Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(S(2)*c*d*(m + p + S(1))), x) def replacement241(a, b, c, d, e, x): return Dist(S(2)*e, Subst(Int(S(1)/(-b*e + S(2)*c*d + e**S(2)*x**S(2)), x), x, sqrt(a + b*x + c*x**S(2))/sqrt(d + e*x)), x) def replacement242(a, c, d, e, x): return Dist(S(2)*e, Subst(Int(S(1)/(S(2)*c*d + e**S(2)*x**S(2)), x), x, sqrt(a + c*x**S(2))/sqrt(d + e*x)), x) def replacement243(a, b, c, d, e, m, p, x): return -Dist(c*p/(e**S(2)*(m + p + S(1))), Int((d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + p + S(1))), x) def replacement244(a, c, d, e, m, p, x): return -Dist(c*p/(e**S(2)*(m + p + S(1))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(2)), x), x) + Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))/(e*(m + p + S(1))), x) def replacement245(a, b, c, d, e, m, p, x): return -Dist(p*(-b*e + S(2)*c*d)/(e**S(2)*(m + S(2)*p + S(1))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(2)*p + S(1))), x) def replacement246(a, c, d, e, m, p, x): return -Dist(S(2)*c*d*p/(e**S(2)*(m + S(2)*p + S(1))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(1)), x), x) + Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))/(e*(m + S(2)*p + S(1))), x) def replacement247(a, b, c, d, e, m, p, x): return -Dist((-b*e + S(2)*c*d)*(m + S(2)*p + S(2))/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((d + e*x)**m*(-b*e + S(2)*c*d)*(a + b*x + c*x**S(2))**(p + S(1))/(e*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement248(a, c, d, e, m, p, x): return Dist(d*(m + S(2)*p + S(2))/(S(2)*a*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1)), x), x) - Simp(d*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(S(2)*a*e*(p + S(1))), x) def replacement249(a, b, c, d, e, m, p, x): return -Dist(e**S(2)*(m + p)/(c*(p + S(1))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*(p + S(1))), x) def replacement250(a, c, d, e, m, p, x): return -Dist(e**S(2)*(m + p)/(c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-2)), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))/(c*(p + S(1))), x) def replacement251(a, b, c, d, e, m, p, x): return Dist((m + p)*(-b*e + S(2)*c*d)/(c*(m + S(2)*p + S(1))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**p, x), x) + Simp(e*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(1))), x) def replacement252(a, c, d, e, m, p, x): return Dist(S(2)*d*(m + p)/(m + S(2)*p + S(1)), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(-1)), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))/(c*(m + S(2)*p + S(1))), x) def replacement253(a, b, c, d, e, m, p, x): return Dist(c*(m + S(2)*p + S(2))/((-b*e + S(2)*c*d)*(m + p + S(1))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) - Simp(e*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/((-b*e + S(2)*c*d)*(m + p + S(1))), x) def replacement254(a, c, d, e, m, p, x): return Dist((m + S(2)*p + S(2))/(S(2)*d*(m + p + S(1))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1)), x), x) - Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(S(2)*c*d*(m + p + S(1))), x) def replacement255(b, c, e, m, p, x): return Dist(x**(-m - p)*(e*x)**m*(b + c*x)**(-p)*(b*x + c*x**S(2))**p, Int(x**(m + p)*(b + c*x)**p, x), x) def replacement256(a, c, d, e, m, p, x): return Int((d + e*x)**(m + p)*(a/d + c*x/e)**p, x) def replacement257(a, b, c, d, e, m, p, x): return Dist((d + e*x)**(-FracPart(p))*(a/d + c*x/e)**(-FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((d + e*x)**(m + p)*(a/d + c*x/e)**p, x), x) def replacement258(a, c, d, e, m, p, x): return Dist((a + c*x**S(2))**FracPart(p)*(d + e*x)**(-FracPart(p))*(a/d + c*x/e)**(-FracPart(p)), Int((d + e*x)**(m + p)*(a/d + c*x/e)**p, x), x) def replacement259(a, b, c, d, e, x): return Dist(b**S(2)/(d**S(2)*(-S(4)*a*c + b**S(2))), Int((d + e*x)/(a + b*x + c*x**S(2)), x), x) + Dist(-S(4)*b*c/(d*(-S(4)*a*c + b**S(2))), Int(S(1)/(b + S(2)*c*x), x), x) def replacement260(a, b, c, d, e, m, p, x): return Simp(S(2)*c*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(e*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement261(a, b, c, d, e, m, p, x): return Int(ExpandIntegrand((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) def replacement262(a, b, c, d, e, m, p, x): return -Dist(b*p/(d*e*(m + S(1))), Int((d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(1))), x) def replacement263(a, b, c, d, e, m, p, x): return -Dist(d*p*(-S(4)*a*c + b**S(2))/(b*e*(m + S(2)*p + S(1))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(2)*p + S(1))), x) def replacement264(a, b, c, d, e, m, p, x): return -Dist(d*e*(m + S(-1))/(b*(p + S(1))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp(d*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(b*(p + S(1))), x) def replacement265(a, b, c, d, e, m, p, x): return -Dist(S(2)*c*(m + S(2)*p + S(3))/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp(S(2)*c*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(e*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement266(a, b, c, d, e, x): return Dist(S(4)*c, Subst(Int(S(1)/(-S(4)*a*c*e + b**S(2)*e + S(4)*c*e*x**S(2)), x), x, sqrt(a + b*x + c*x**S(2))), x) def replacement267(a, b, c, d, e, x): return Dist(S(4)*sqrt(-c/(-S(4)*a*c + b**S(2)))/e, Subst(Int(S(1)/sqrt(Simp(-b**S(2)*x**S(4)/(d**S(2)*(-S(4)*a*c + b**S(2))) + S(1), x)), x), x, sqrt(d + e*x)), x) def replacement268(a, b, c, d, e, x): return Dist(S(4)*sqrt(-c/(-S(4)*a*c + b**S(2)))/e, Subst(Int(x**S(2)/sqrt(Simp(-b**S(2)*x**S(4)/(d**S(2)*(-S(4)*a*c + b**S(2))) + S(1), x)), x), x, sqrt(d + e*x)), x) def replacement269(a, b, c, d, e, m, x): return Dist(sqrt(-c*(a + b*x + c*x**S(2))/(-S(4)*a*c + b**S(2)))/sqrt(a + b*x + c*x**S(2)), Int((d + e*x)**m/sqrt(-a*c/(-S(4)*a*c + b**S(2)) - b*c*x/(-S(4)*a*c + b**S(2)) - c**S(2)*x**S(2)/(-S(4)*a*c + b**S(2))), x), x) def replacement270(a, b, c, d, e, m, p, x): return Dist(d**S(2)*(m + S(-1))*(-S(4)*a*c + b**S(2))/(b**S(2)*(m + S(2)*p + S(1))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**p, x), x) + Simp(S(2)*d*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(b*(m + S(2)*p + S(1))), x) def replacement271(a, b, c, d, e, m, p, x): return Dist(b**S(2)*(m + S(2)*p + S(3))/(d**S(2)*(m + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**p, x), x) + Simp(-S(2)*b*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(d*(m + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement272(a, b, c, d, e, m, p, x): return Dist(S(1)/e, Subst(Int(x**m*(a - b**S(2)/(S(4)*c) + c*x**S(2)/e**S(2))**p, x), x, d + e*x), x) def replacement273(a, b, c, d, e, m, p, x): return Int(ExpandIntegrand((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) def replacement274(a, c, d, e, m, p, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(d + e*x)**m, x), x) def With275(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist((c*d - e*(b/S(2) - q/S(2)))/q, Int(S(1)/(b/S(2) + c*x - q/S(2)), x), x) - Dist((c*d - e*(b/S(2) + q/S(2)))/q, Int(S(1)/(b/S(2) + c*x + q/S(2)), x), x) def With276(a, c, d, e, x): q = Rt(-a*c, S(2)) return Dist(-c*d/(S(2)*q) + e/S(2), Int(S(1)/(c*x + q), x), x) + Dist(c*d/(S(2)*q) + e/S(2), Int(S(1)/(c*x - q), x), x) def replacement277(a, b, c, d, e, x): return Dist(e/(S(2)*c), Int((b + S(2)*c*x)/(a + b*x + c*x**S(2)), x), x) + Dist((-b*e + S(2)*c*d)/(S(2)*c), Int(S(1)/(a + b*x + c*x**S(2)), x), x) def replacement278(a, c, d, e, x): return Dist(d, Int(S(1)/(a + c*x**S(2)), x), x) + Dist(e, Int(x/(a + c*x**S(2)), x), x) def replacement279(a, b, c, d, e, x): return Dist(S(2)*e, Subst(Int(x**S(2)/(a*e**S(2) - b*d*e + c*d**S(2) + c*x**S(4) - x**S(2)*(-b*e + S(2)*c*d)), x), x, sqrt(d + e*x)), x) def replacement280(a, c, d, e, x): return Dist(S(2)*e, Subst(Int(x**S(2)/(a*e**S(2) + c*d**S(2) - S(2)*c*d*x**S(2) + c*x**S(4)), x), x, sqrt(d + e*x)), x) def replacement281(a, b, c, d, e, m, x): return Int(PolynomialDivide((d + e*x)**m, a + b*x + c*x**S(2), x), x) def replacement282(a, c, d, e, m, x): return Int(PolynomialDivide((d + e*x)**m, a + c*x**S(2), x), x) def replacement283(a, b, c, d, e, m, x): return Dist(S(1)/c, Int((d + e*x)**(m + S(-2))*Simp(-a*e**S(2) + c*d**S(2) + e*x*(-b*e + S(2)*c*d), x)/(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))/(c*(m + S(-1))), x) def replacement284(a, c, d, e, m, x): return Dist(S(1)/c, Int((d + e*x)**(m + S(-2))*Simp(-a*e**S(2) + c*d**S(2) + S(2)*c*d*e*x, x)/(a + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))/(c*(m + S(-1))), x) def replacement285(a, b, c, d, e, x): return Dist(e**S(2)/(a*e**S(2) - b*d*e + c*d**S(2)), Int(S(1)/(d + e*x), x), x) + Dist(S(1)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((-b*e + c*d - c*e*x)/(a + b*x + c*x**S(2)), x), x) def replacement286(a, c, d, e, x): return Dist(e**S(2)/(a*e**S(2) + c*d**S(2)), Int(S(1)/(d + e*x), x), x) + Dist(S(1)/(a*e**S(2) + c*d**S(2)), Int((c*d - c*e*x)/(a + c*x**S(2)), x), x) def replacement287(a, b, c, d, e, x): return Dist(S(2)*e, Subst(Int(S(1)/(a*e**S(2) - b*d*e + c*d**S(2) + c*x**S(4) - x**S(2)*(-b*e + S(2)*c*d)), x), x, sqrt(d + e*x)), x) def replacement288(a, c, d, e, x): return Dist(S(2)*e, Subst(Int(S(1)/(a*e**S(2) + c*d**S(2) - S(2)*c*d*x**S(2) + c*x**S(4)), x), x, sqrt(d + e*x)), x) def replacement289(a, b, c, d, e, m, x): return Dist(S(1)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((d + e*x)**(m + S(1))*Simp(-b*e + c*d - c*e*x, x)/(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(1))/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement290(a, c, d, e, m, x): return Dist(c/(a*e**S(2) + c*d**S(2)), Int((d - e*x)*(d + e*x)**(m + S(1))/(a + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(1))/((m + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement291(a, b, c, d, e, m, x): return Int(ExpandIntegrand((d + e*x)**m, S(1)/(a + b*x + c*x**S(2)), x), x) def replacement292(a, c, d, e, m, x): return Int(ExpandIntegrand((d + e*x)**m, S(1)/(a + c*x**S(2)), x), x) def replacement293(a, b, c, d, e, x): return Simp(-S(2)*(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d))/((-S(4)*a*c + b**S(2))*sqrt(a + b*x + c*x**S(2))), x) def replacement294(a, c, d, e, x): return Simp((-a*e + c*d*x)/(a*c*sqrt(a + c*x**S(2))), x) def replacement295(a, b, c, d, e, p, x): return -Dist((S(2)*p + S(3))*(-b*e + S(2)*c*d)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement296(a, c, d, e, p, x): return Dist(d*(S(2)*p + S(3))/(S(2)*a*(p + S(1))), Int((a + c*x**S(2))**(p + S(1)), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(a*e - c*d*x)/(S(2)*a*c*(p + S(1))), x) def replacement297(a, b, c, d, e, p, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int((a + b*x + c*x**S(2))**p, x), x) + Simp(e*(a + b*x + c*x**S(2))**(p + S(1))/(S(2)*c*(p + S(1))), x) def replacement298(a, c, d, e, p, x): return Dist(d, Int((a + c*x**S(2))**p, x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))/(S(2)*c*(p + S(1))), x) def replacement299(a, b, c, d, e, m, p, x): return Dist((d + e*x)**FracPart(p)*(a*d + c*e*x**S(3))**(-FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((d + e*x)**(m - p)*(a*d + c*e*x**S(3))**p, x), x) def replacement300(b, c, d, e, m, x): return Int((d + e*x)**m/(sqrt(b*x)*sqrt(S(1) + c*x/b)), x) def replacement301(b, c, d, e, m, x): return Dist(sqrt(x)*sqrt(b + c*x)/sqrt(b*x + c*x**S(2)), Int((d + e*x)**m/(sqrt(x)*sqrt(b + c*x)), x), x) def replacement302(a, b, c, m, x): return Dist(S(2), Subst(Int(x**(S(2)*m + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(x)), x) def replacement303(a, b, c, e, m, x): return Dist(x**(-m)*(e*x)**m, Int(x**m/sqrt(a + b*x + c*x**S(2)), x), x) def replacement304(a, b, c, d, e, m, x): return Dist(S(2)*sqrt(-c*(a + b*x + c*x**S(2))/(-S(4)*a*c + b**S(2)))*(S(2)*c*(d + e*x)/(-b*e + S(2)*c*d - e*Rt(-S(4)*a*c + b**S(2), S(2))))**(-m)*(d + e*x)**m*Rt(-S(4)*a*c + b**S(2), S(2))/(c*sqrt(a + b*x + c*x**S(2))), Subst(Int((S(2)*e*x**S(2)*Rt(-S(4)*a*c + b**S(2), S(2))/(-b*e + S(2)*c*d - e*Rt(-S(4)*a*c + b**S(2), S(2))) + S(1))**m/sqrt(S(1) - x**S(2)), x), x, sqrt(S(2))*sqrt((b + S(2)*c*x + Rt(-S(4)*a*c + b**S(2), S(2)))/Rt(-S(4)*a*c + b**S(2), S(2)))/S(2)), x) def replacement305(a, c, d, e, m, x): return Dist(S(2)*a*(c*(d + e*x)/(-a*e*Rt(-c/a, S(2)) + c*d))**(-m)*sqrt(S(1) + c*x**S(2)/a)*(d + e*x)**m*Rt(-c/a, S(2))/(c*sqrt(a + c*x**S(2))), Subst(Int((S(2)*a*e*x**S(2)*Rt(-c/a, S(2))/(-a*e*Rt(-c/a, S(2)) + c*d) + S(1))**m/sqrt(S(1) - x**S(2)), x), x, sqrt(-x*Rt(-c/a, S(2))/S(2) + S(1)/2)), x) def replacement306(a, b, c, d, e, m, p, x): return Dist(p*(-S(4)*a*c + b**S(2))/(S(2)*(m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) - Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d))/(S(2)*(m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement307(a, c, d, e, m, p, x): return -Dist(S(2)*a*c*p/((m + S(1))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(2)), x), x) - Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*(-S(2)*a*e + S(2)*c*d*x)/(S(2)*(m + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement308(a, b, c, d, e, m, p, x): return -Dist(S(2)*(S(2)*p + S(3))*(a*e**S(2) - b*d*e + c*d**S(2))/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement309(a, c, d, e, m, p, x): return Dist((S(2)*p + S(3))*(a*e**S(2) + c*d**S(2))/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-2)), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(a*e - c*d*x)/(S(2)*a*c*(p + S(1))), x) def replacement310(a, b, c, d, e, x): return Dist(S(-2), Subst(Int(S(1)/(S(4)*a*e**S(2) - S(4)*b*d*e + S(4)*c*d**S(2) - x**S(2)), x), x, (S(2)*a*e - b*d - x*(-b*e + S(2)*c*d))/sqrt(a + b*x + c*x**S(2))), x) def replacement311(a, c, d, e, x): return -Subst(Int(S(1)/(a*e**S(2) + c*d**S(2) - x**S(2)), x), x, (a*e - c*d*x)/sqrt(a + c*x**S(2))) def replacement312(a, b, c, d, e, m, p, x): return -Simp(((b + S(2)*c*x + Rt(-S(4)*a*c + b**S(2), S(2)))*(-b*e + S(2)*c*d + e*Rt(-S(4)*a*c + b**S(2), S(2)))/((b + S(2)*c*x - Rt(-S(4)*a*c + b**S(2), S(2)))*(-b*e + S(2)*c*d - e*Rt(-S(4)*a*c + b**S(2), S(2)))))**(-p)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*(b + S(2)*c*x - Rt(-S(4)*a*c + b**S(2), S(2)))*Hypergeometric2F1(m + S(1), -p, m + S(2), -S(4)*c*(d + e*x)*Rt(-S(4)*a*c + b**S(2), S(2))/((b + S(2)*c*x - Rt(-S(4)*a*c + b**S(2), S(2)))*(-b*e + S(2)*c*d - e*Rt(-S(4)*a*c + b**S(2), S(2)))))/((m + S(1))*(-b*e + S(2)*c*d + e*Rt(-S(4)*a*c + b**S(2), S(2)))), x) def replacement313(a, c, d, e, m, p, x): return Simp(((c*d + e*Rt(-a*c, S(2)))*(c*x + Rt(-a*c, S(2)))/((c*d - e*Rt(-a*c, S(2)))*(c*x - Rt(-a*c, S(2)))))**(-p)*(a + c*x**S(2))**p*(d + e*x)**(m + S(1))*(-c*x + Rt(-a*c, S(2)))*Hypergeometric2F1(m + S(1), -p, m + S(2), S(2)*c*(d + e*x)*Rt(-a*c, S(2))/((c*d - e*Rt(-a*c, S(2)))*(-c*x + Rt(-a*c, S(2)))))/((m + S(1))*(c*d + e*Rt(-a*c, S(2)))), x) def replacement314(a, b, c, d, e, m, p, x): return Dist(m*(-b*e + S(2)*c*d)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((b + S(2)*c*x)*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement315(a, c, d, e, m, p, x): return -Dist(d*m/(S(2)*a*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1)), x), x) - Simp(x*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(S(2)*a*(p + S(1))), x) def replacement316(a, b, c, d, e, m, p, x): return Dist((-b*e + S(2)*c*d)/(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2)), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) + Simp(e*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement317(a, c, d, e, m, p, x): return Dist(c*d/(a*e**S(2) + c*d**S(2)), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1)), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))/((m + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement318(a, b, c, d, e, m, p, x): return -Dist(p/(e*(m + S(1))), Int((b + S(2)*c*x)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(1))), x) def replacement319(a, c, d, e, m, p, x): return -Dist(S(2)*c*p/(e*(m + S(1))), Int(x*(a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(1)), x), x) + Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))/(e*(m + S(1))), x) def replacement320(a, b, c, d, e, m, p, x): return -Dist(p/(e*(m + S(2)*p + S(1))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(-1))*Simp(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d), x), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(e*(m + S(2)*p + S(1))), x) def replacement321(a, c, d, e, m, p, x): return Dist(S(2)*p/(e*(m + S(2)*p + S(1))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**m*Simp(a*e - c*d*x, x), x), x) + Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))/(e*(m + S(2)*p + S(1))), x) def replacement322(a, b, c, d, e, m, p, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*(b*e*m + S(2)*c*d*(S(2)*p + S(3)) + S(2)*c*e*x*(m + S(2)*p + S(3))), x), x) + Simp((b + S(2)*c*x)*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement323(a, c, d, e, m, p, x): return Dist(S(1)/(S(2)*a*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(d*(S(2)*p + S(3)) + e*x*(m + S(2)*p + S(3))), x), x) - Simp(x*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(S(2)*a*(p + S(1))), x) def replacement324(a, b, c, d, e, m, p, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-S(2)*c*d**S(2)*(S(2)*p + S(3)) + e*x*(b*e - S(2)*c*d)*(m + S(2)*p + S(2)) + e*(S(2)*a*e*(m + S(-1)) + b*d*(-m + S(2)*p + S(4))), x), x), x) + Simp((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*(-S(2)*a*e + b*d + x*(-b*e + S(2)*c*d))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement325(a, c, d, e, m, p, x): return Dist(-S(1)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-2))*Simp(a*e**S(2)*(m + S(-1)) - c*d**S(2)*(S(2)*p + S(3)) - c*d*e*x*(m + S(2)*p + S(2)), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(a*e - c*d*x)/(S(2)*a*c*(p + S(1))), x) def replacement326(a, b, c, d, e, m, p, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-S(2)*a*c*e**S(2)*(m + S(2)*p + S(3)) + b**S(2)*e**S(2)*(m + p + S(2)) + b*c*d*e*(-m + S(2)*p + S(2)) - S(2)*c**S(2)*d**S(2)*(S(2)*p + S(3)) - c*e*x*(-b*e + S(2)*c*d)*(m + S(2)*p + S(4)), x), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(S(2)*a*c*e - b**S(2)*e + b*c*d + c*x*(-b*e + S(2)*c*d))/((p + S(1))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement327(a, c, d, e, m, p, x): return Dist(S(1)/(S(2)*a*(p + S(1))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**m*Simp(a*e**S(2)*(m + S(2)*p + S(3)) + c*d**S(2)*(S(2)*p + S(3)) + c*d*e*x*(m + S(2)*p + S(4)), x), x), x) - Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))*(a*e + c*d*x)/(S(2)*a*(p + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement328(a, b, c, d, e, m, p, x): return Dist(S(1)/(c*(m + S(2)*p + S(1))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**p*Simp(c*d**S(2)*(m + S(2)*p + S(1)) + e*x*(m + p)*(-b*e + S(2)*c*d) - e*(a*e*(m + S(-1)) + b*d*(p + S(1))), x), x), x) + Simp(e*(d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(1))), x) def replacement329(a, c, d, e, m, p, x): return Dist(S(1)/(c*(m + S(2)*p + S(1))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(-2))*Simp(-a*e**S(2)*(m + S(-1)) + c*d**S(2)*(m + S(2)*p + S(1)) + S(2)*c*d*e*x*(m + p), x), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))/(c*(m + S(2)*p + S(1))), x) def replacement330(a, b, c, d, e, m, p, x): return Dist(S(1)/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*Simp(-b*e*(m + p + S(2)) + c*d*(m + S(1)) - c*e*x*(m + S(2)*p + S(3)), x), x), x) + Simp(e*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement331(a, c, d, e, m, p, x): return Dist(c/((m + S(1))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*Simp(d*(m + S(1)) - e*x*(m + S(2)*p + S(3)), x), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))/((m + S(1))*(a*e**S(2) + c*d**S(2))), x) def With332(a, b, c, d, e, x): q = Rt(S(3)*c*e**S(2)*(-b*e + S(2)*c*d), S(3)) return -Simp(S(3)*c*e*log(d + e*x)/(S(2)*q**S(2)), x) + Simp(S(3)*c*e*log(-b*e + c*d - c*e*x - q*(a + b*x + c*x**S(2))**(S(1)/3))/(S(2)*q**S(2)), x) - Simp(sqrt(S(3))*c*e*ArcTan(sqrt(S(3))/S(3) + S(2)*sqrt(S(3))*(-b*e + c*d - c*e*x)/(S(3)*q*(a + b*x + c*x**S(2))**(S(1)/3)))/q**S(2), x) def With333(a, c, d, e, x): q = Rt(S(6)*c**S(2)*e**S(2)/d**S(2), S(3)) return -Simp(S(3)*c*e*log(d + e*x)/(S(2)*d**S(2)*q**S(2)), x) + Simp(S(3)*c*e*log(c*d - c*e*x - d*q*(a + c*x**S(2))**(S(1)/3))/(S(2)*d**S(2)*q**S(2)), x) - Simp(sqrt(S(3))*c*e*ArcTan(S(2)*sqrt(S(3))*c*(d - e*x)/(S(3)*d*q*(a + c*x**S(2))**(S(1)/3)) + sqrt(S(3))/S(3))/(d**S(2)*q**S(2)), x) def With334(a, b, c, d, e, x): q = Rt(-S(3)*c*e**S(2)*(-b*e + S(2)*c*d), S(3)) return -Simp(S(3)*c*e*log(d + e*x)/(S(2)*q**S(2)), x) + Simp(S(3)*c*e*log(-b*e + c*d - c*e*x + q*(a + b*x + c*x**S(2))**(S(1)/3))/(S(2)*q**S(2)), x) - Simp(sqrt(S(3))*c*e*ArcTan(sqrt(S(3))/S(3) - S(2)*sqrt(S(3))*(-b*e + c*d - c*e*x)/(S(3)*q*(a + b*x + c*x**S(2))**(S(1)/3)))/q**S(2), x) def With335(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist((b + S(2)*c*x - q)**(S(1)/3)*(b + S(2)*c*x + q)**(S(1)/3)/(a + b*x + c*x**S(2))**(S(1)/3), Int(S(1)/((d + e*x)*(b + S(2)*c*x - q)**(S(1)/3)*(b + S(2)*c*x + q)**(S(1)/3)), x), x) def replacement336(a, c, d, e, x): return Dist(d, Int(S(1)/((a + c*x**S(2))**(S(1)/4)*(d**S(2) - e**S(2)*x**S(2))), x), x) - Dist(e, Int(x/((a + c*x**S(2))**(S(1)/4)*(d**S(2) - e**S(2)*x**S(2))), x), x) def replacement337(a, c, d, e, x): return Dist(d, Int(S(1)/((a + c*x**S(2))**(S(3)/4)*(d**S(2) - e**S(2)*x**S(2))), x), x) - Dist(e, Int(x/((a + c*x**S(2))**(S(3)/4)*(d**S(2) - e**S(2)*x**S(2))), x), x) def replacement338(a, b, c, d, e, p, x): return Dist((-S(4)*c/(-S(4)*a*c + b**S(2)))**(-p), Subst(Int(Simp(-x**S(2)/(-S(4)*a*c + b**S(2)) + S(1), x)**p/Simp(-b*e + S(2)*c*d + e*x, x), x), x, b + S(2)*c*x), x) def replacement339(a, b, c, d, e, p, x): return Dist((-c*(a + b*x + c*x**S(2))/(-S(4)*a*c + b**S(2)))**(-p)*(a + b*x + c*x**S(2))**p, Int((-a*c/(-S(4)*a*c + b**S(2)) - b*c*x/(-S(4)*a*c + b**S(2)) - c**S(2)*x**S(2)/(-S(4)*a*c + b**S(2)))**p/(d + e*x), x), x) def replacement340(a, c, d, e, m, p, x): return Int((d + e*x)**m*(-x*Rt(-c, S(2)) + Rt(a, S(2)))**p*(x*Rt(-c, S(2)) + Rt(a, S(2)))**p, x) def With341(a, b, c, d, e, m, p, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return -Dist((e*(b + S(2)*c*x - q)/(S(2)*c*(d + e*x)))**(-p)*(e*(b + S(2)*c*x + q)/(S(2)*c*(d + e*x)))**(-p)*(a + b*x + c*x**S(2))**p*(S(1)/(d + e*x))**(S(2)*p)/e, Subst(Int(x**(-m - S(2)*p + S(-2))*Simp(-x*(d - e*(b - q)/(S(2)*c)) + S(1), x)**p*Simp(-x*(d - e*(b + q)/(S(2)*c)) + S(1), x)**p, x), x, S(1)/(d + e*x)), x) def With342(a, c, d, e, m, p, x): q = Rt(-a*c, S(2)) return -Dist((e*(c*x + q)/(c*(d + e*x)))**(-p)*(-e*(-c*x + q)/(c*(d + e*x)))**(-p)*(a + c*x**S(2))**p*(S(1)/(d + e*x))**(S(2)*p)/e, Subst(Int(x**(-m - S(2)*p + S(-2))*Simp(-x*(d - e*q/c) + S(1), x)**p*Simp(-x*(d + e*q/c) + S(1), x)**p, x), x, S(1)/(d + e*x)), x) def With343(a, b, c, d, e, m, p, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist((-(d + e*x)/(d - e*(b - q)/(S(2)*c)) + S(1))**(-p)*(-(d + e*x)/(d - e*(b + q)/(S(2)*c)) + S(1))**(-p)*(a + b*x + c*x**S(2))**p/e, Subst(Int(x**m*Simp(-x/(d - e*(b - q)/(S(2)*c)) + S(1), x)**p*Simp(-x/(d - e*(b + q)/(S(2)*c)) + S(1), x)**p, x), x, d + e*x), x) def With344(a, c, d, e, m, p, x): q = Rt(-a*c, S(2)) return Dist((a + c*x**S(2))**p*(-(d + e*x)/(d - e*q/c) + S(1))**(-p)*(-(d + e*x)/(d + e*q/c) + S(1))**(-p)/e, Subst(Int(x**m*Simp(-x/(d - e*q/c) + S(1), x)**p*Simp(-x/(d + e*q/c) + S(1), x)**p, x), x, d + e*x), x) def replacement345(a, b, c, d, e, m, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x, u), x) def replacement346(a, c, d, e, m, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + c*x**S(2))**p*(d + e*x)**m, x), x, u), x) def replacement347(a, c, d, e, n, p, x): return Dist(d, Int(x**n*(a + c*x**S(2))**p, x), x) + Dist(e, Int(x**(n + S(1))*(a + c*x**S(2))**p, x), x) def replacement348(a, b, c, d, e, f, g, m, x): return Dist((f + g*x)/sqrt(a + b*x + c*x**S(2)), Int((d + e*x)**m, x), x) def replacement349(a, b, c, d, e, f, g, m, p, x): return -Simp(f*g*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(b*(p + S(1))*(-d*g + e*f)), x) def replacement350(a, b, c, d, e, f, g, m, p, x): return -Dist(e*g*m/(S(2)*c*(p + S(1))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp(g*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/(S(2)*c*(p + S(1))), x) def replacement351(a, b, c, d, e, f, g, m, p, x): return Dist(e*f*g*(m + S(2)*p + S(3))/(b*(p + S(1))*(-d*g + e*f)), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1)), x), x) - Simp(f*g*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(b*(p + S(1))*(-d*g + e*f)), x) def replacement352(a, b, c, d, e, f, g, m, p, x): return -Dist(g*(S(2)*p + S(1))/(e*(m + S(1))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) + Simp((d + e*x)**(m + S(1))*(f + g*x)*(a + b*x + c*x**S(2))**p/(e*(m + S(1))), x) def replacement353(a, b, c, d, e, f, g, m, p, x): return -Dist(g*(m + S(2)*p + S(3))/((m + S(1))*(-d*g + e*f)), Int((d + e*x)**(m + S(1))*(f + g*x)*(a + b*x + c*x**S(2))**p, x), x) + Simp(S(2)*f*g*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(b*(m + S(1))*(-d*g + e*f)), x) def replacement354(a, b, c, d, e, f, g, m, p, x): return -Dist(b*m*(-d*g + e*f)/(S(2)*c*f*(m + S(2)*p + S(2))), Int((d + e*x)**(m + S(-1))*(f + g*x)*(a + b*x + c*x**S(2))**p, x), x) + Simp(g*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(2))), x) def replacement355(a, b, c, d, e, f, g, m, p, x): return Dist((S(2)*p + S(1))*(-d*g + e*f)/(e*(m + S(2)*p + S(2))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) + Simp((d + e*x)**(m + S(1))*(f + g*x)*(a + b*x + c*x**S(2))**p/(e*(m + S(2)*p + S(2))), x) def replacement356(a, b, c, d, e, f, g, p, x): return Dist((-b*g + S(2)*c*f)/(-b*e + S(2)*c*d), Int((a + b*x + c*x**S(2))**p, x), x) - Dist((-d*g + e*f)/(-b*e + S(2)*c*d), Int((b + S(2)*c*x)*(a + b*x + c*x**S(2))**p/(d + e*x), x), x) def replacement357(a, b, c, d, e, f, g, m, p, x): return Dist(g/e, Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) + Dist((-d*g + e*f)/e, Int((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) def replacement358(a, b, c, d, e, f, g, m, p, x): return Dist((-b*g + S(2)*c*f)/(-b*e + S(2)*c*d), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) - Dist((-d*g + e*f)/(-b*e + S(2)*c*d), Int((b + S(2)*c*x)*(d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) def replacement359(a, b, c, d, e, f, g, m, p, x): return Dist((S(2)*c*e*f*(m + S(2)*p + S(2)) - g*(b*e*(m + S(1)) + S(2)*c*d*(S(2)*p + S(1))))/(e*(m + S(1))*(-b*e + S(2)*c*d)), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) - Simp((b + S(2)*c*x)*(d + e*x)**(m + S(1))*(-d*g + e*f)*(a + b*x + c*x**S(2))**p/(e*(m + S(1))*(-b*e + S(2)*c*d)), x) def replacement360(a, b, c, d, e, f, g, m, p, x): return Dist((S(2)*c*e*f*(m + S(2)*p + S(2)) - g*(b*e*(m + S(1)) + S(2)*c*(S(2)*d*p + d)))/(S(2)*c*e*(m + S(2)*p + S(2))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) + Simp(g*(b + S(2)*c*x)*(d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p/(S(2)*c*e*(m + S(2)*p + S(2))), x) def replacement361(a, b, c, d, e, f, g, m, n, p, x): return Dist(c**(-IntPart(p))*(b/S(2) + c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b/S(2) + c*x)**(S(2)*p)*(d + e*x)**m*(f + g*x)**n, x), x) def replacement362(a, b, c, d, e, f, g, m, n, p, x): return Int((d + e*x)**(m + p)*(f + g*x)**n*(a/d + c*x/e)**p, x) def replacement363(a, c, d, e, f, g, m, n, p, x): return Int((d + e*x)**(m + p)*(f + g*x)**n*(a/d + c*x/e)**p, x) def replacement364(a, b, c, d, e, f, g, m, n, p, x): return Dist(d**m*e**m, Int((f + g*x)**n*(a*e + c*d*x)**(-m)*(a + b*x + c*x**S(2))**(m + p), x), x) def replacement365(a, c, d, e, f, g, m, n, p, x): return Dist(d**m*e**m, Int((a + c*x**S(2))**(m + p)*(f + g*x)**n*(a*e + c*d*x)**(-m), x), x) def replacement366(a, b, c, d, e, f, g, m, p, x): return Simp(g*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(2))), x) def replacement367(a, c, d, e, f, g, m, p, x): return Simp(g*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(c*(m + S(2)*p + S(2))), x) def replacement368(a, b, c, d, e, f, g, m, p, x): return -Dist(e*(e*(p + S(1))*(-b*g + S(2)*c*f) + m*(c*e*f + g*(-b*e + c*d)))/(c*(p + S(1))*(-b*e + S(2)*c*d)), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((d + e*x)**m*(c*e*f + g*(-b*e + c*d))*(a + b*x + c*x**S(2))**(p + S(1))/(c*(p + S(1))*(-b*e + S(2)*c*d)), x) def replacement369(a, c, d, e, f, g, m, p, x): return -Dist(e*(S(2)*e*f*(p + S(1)) + m*(d*g + e*f))/(S(2)*c*d*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1)), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**m*(d*g + e*f)/(S(2)*c*d*(p + S(1))), x) def replacement370(a, b, c, d, e, f, g, m, p, x): return -Dist(e*(e*(p + S(1))*(-b*g + S(2)*c*f) + m*(c*e*f + g*(-b*e + c*d)))/(c*(p + S(1))*(-b*e + S(2)*c*d)), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((d + e*x)**m*(c*e*f + g*(-b*e + c*d))*(a + b*x + c*x**S(2))**(p + S(1))/(c*(p + S(1))*(-b*e + S(2)*c*d)), x) def replacement371(a, c, d, e, f, g, m, p, x): return -Dist(e*(S(2)*e*f*(p + S(1)) + m*(d*g + e*f))/(S(2)*c*d*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1)), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**m*(d*g + e*f)/(S(2)*c*d*(p + S(1))), x) def replacement372(a, b, c, d, e, f, g, m, p, x): return Dist((e*(p + S(1))*(-b*g + S(2)*c*f) + m*(c*e*f + g*(-b*e + c*d)))/(e*(-b*e + S(2)*c*d)*(m + p + S(1))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) + Simp((d + e*x)**m*(d*g - e*f)*(a + b*x + c*x**S(2))**(p + S(1))/((-b*e + S(2)*c*d)*(m + p + S(1))), x) def replacement373(a, c, d, e, f, g, m, p, x): return Dist((S(2)*c*e*f*(p + S(1)) + m*(c*d*g + c*e*f))/(S(2)*c*d*e*(m + p + S(1))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1)), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**m*(d*g - e*f)/(S(2)*c*d*(m + p + S(1))), x) def replacement374(a, b, c, d, e, f, g, m, p, x): return Dist((e*(p + S(1))*(-b*g + S(2)*c*f) + m*(c*e*f + g*(-b*e + c*d)))/(c*e*(m + S(2)*p + S(2))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) + Simp(g*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(2))), x) def replacement375(a, c, d, e, f, g, m, p, x): return Dist((S(2)*e*f*(p + S(1)) + m*(d*g + e*f))/(e*(m + S(2)*p + S(2))), Int((a + c*x**S(2))**p*(d + e*x)**m, x), x) + Simp(g*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(c*(m + S(2)*p + S(2))), x) def replacement376(a, c, f, g, p, x): return -Dist(S(1)/(S(2)*a*c*(p + S(1))), Int(x*(a + c*x**S(2))**(p + S(1))*Simp(S(2)*a*g - c*f*x*(S(2)*p + S(5)), x), x), x) + Simp(x**S(2)*(a + c*x**S(2))**(p + S(1))*(a*g - c*f*x)/(S(2)*a*c*(p + S(1))), x) def replacement377(a, c, f, g, p, x): return Dist(S(1)/c, Int((a + c*x**S(2))**(p + S(1))*(f + g*x), x), x) - Dist(f**S(2)/c, Int((a + c*x**S(2))**(p + S(1))/(f - g*x), x), x) def replacement378(a, b, c, d, e, f, g, m, n, p, x): return Int((f + g*x)**n*(a/d + c*x/e)**(-m)*(a + b*x + c*x**S(2))**(m + p), x) def replacement379(a, c, d, e, f, g, m, n, p, x): return Dist(a**(-m)*d**(S(2)*m), Int((a + c*x**S(2))**(m + p)*(d - e*x)**(-m)*(f + g*x)**n, x), x) def replacement380(a, b, c, d, e, f, g, n, p, x): return -Dist(S(1)/(d*e*p*(-S(4)*a*c + b**S(2))), Int((f + g*x)**(n + S(-1))*(a + b*x + c*x**S(2))**p*Simp(-S(2)*a*c*(d*g*n - e*f*(S(2)*p + S(1))) + b*(a*e*g*n - c*d*f*(S(2)*p + S(1))) - c*g*x*(-S(2)*a*e + b*d)*(n + S(2)*p + S(1)), x), x), x) - Simp((f + g*x)**n*(a*(-b*e + S(2)*c*d) + c*x*(-S(2)*a*e + b*d))*(a + b*x + c*x**S(2))**p/(d*e*p*(-S(4)*a*c + b**S(2))), x) def replacement381(a, c, d, e, f, g, n, p, x): return -Dist(S(1)/(S(2)*d*e*p), Int((a + c*x**S(2))**p*(f + g*x)**(n + S(-1))*Simp(d*g*n - e*f*(S(2)*p + S(1)) - e*g*x*(n + S(2)*p + S(1)), x), x), x) + Simp((a + c*x**S(2))**p*(d - e*x)*(f + g*x)**n/(S(2)*d*e*p), x) def replacement382(a, b, c, d, e, f, g, n, p, x): return -Dist(S(1)/(d*e*p*(-S(4)*a*c + b**S(2))*(a*g**S(2) - b*f*g + c*f**S(2))), Int((f + g*x)**n*(a + b*x + c*x**S(2))**p*Simp(S(2)*a*c*(a*e*g**S(2)*(n + S(2)*p + S(1)) + c*f*(-d*g*n + S(2)*e*f*p + e*f)) + b**S(2)*g*(-a*e*g*(n + p + S(1)) + c*d*f*p) + b*c*(a*g*(d*g*(n + S(1)) + e*f*(n - S(2)*p)) - c*d*f**S(2)*(S(2)*p + S(1))) + c*g*x*(S(2)*a*c*(d*g + e*f) - b*(a*e*g + c*d*f))*(n + S(2)*p + S(2)), x), x), x) - Simp((f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**p*(a*c*d*(-b*g + S(2)*c*f) - a*e*(S(2)*a*c*g - b**S(2)*g + b*c*f) + c*x*(-a*e*(-b*g + S(2)*c*f) + c*d*(-S(2)*a*g + b*f)))/(d*e*p*(-S(4)*a*c + b**S(2))*(a*g**S(2) - b*f*g + c*f**S(2))), x) def replacement383(a, c, d, e, f, g, n, p, x): return Dist(S(1)/(S(2)*d*e*p*(a*g**S(2) + c*f**S(2))), Int((a + c*x**S(2))**p*(f + g*x)**n*Simp(a*e*g**S(2)*(n + S(2)*p + S(1)) - c*f*(d*g*n - e*(S(2)*f*p + f)) + c*g*x*(d*g + e*f)*(n + S(2)*p + S(2)), x), x), x) + Simp((a + c*x**S(2))**p*(f + g*x)**(n + S(1))*(-a*e*g + c*d*f - c*x*(d*g + e*f))/(S(2)*d*e*p*(a*g**S(2) + c*f**S(2))), x) def replacement384(a, b, c, d, e, f, g, m, n, p, x): return -Simp(e*(d + e*x)**(m + S(-1))*(f + g*x)**n*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m - n + S(-1))), x) def replacement385(a, c, d, e, f, g, m, n, p, x): return -Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**n/(c*(m - n + S(-1))), x) def replacement386(a, b, c, d, e, f, g, m, n, p, x): return -Simp(e**S(2)*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/((n + S(1))*(-b*e*g + c*d*g + c*e*f)), x) def replacement387(a, c, d, e, f, g, m, n, p, x): return -Simp(e**S(2)*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))/(c*(n + S(1))*(d*g + e*f)), x) def replacement388(a, b, c, d, e, f, g, m, n, p, x): return Dist(c*m/(e*g*(n + S(1))), Int((d + e*x)**(m + S(1))*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) + Simp((d + e*x)**m*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**p/(g*(n + S(1))), x) def replacement389(a, c, d, e, f, g, m, n, p, x): return Dist(c*m/(e*g*(n + S(1))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(1))*(f + g*x)**(n + S(1)), x), x) + Simp((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**(n + S(1))/(g*(n + S(1))), x) def replacement390(a, b, c, d, e, f, g, m, n, p, x): return -Dist(m*(-b*e*g + c*d*g + c*e*f)/(e**S(2)*g*(m - n + S(-1))), Int((d + e*x)**(m + S(1))*(f + g*x)**n*(a + b*x + c*x**S(2))**(p + S(-1)), x), x) - Simp((d + e*x)**m*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**p/(g*(m - n + S(-1))), x) def replacement391(a, c, d, e, f, g, m, n, p, x): return -Dist(c*m*(d*g + e*f)/(e**S(2)*g*(m - n + S(-1))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(1))*(f + g*x)**n, x), x) - Simp((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**(n + S(1))/(g*(m - n + S(-1))), x) def replacement392(a, b, c, d, e, f, g, m, n, p, x): return -Dist(e*g*n/(c*(p + S(1))), Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*(f + g*x)**n*(a + b*x + c*x**S(2))**(p + S(1))/(c*(p + S(1))), x) def replacement393(a, c, d, e, f, g, m, n, p, x): return -Dist(e*g*n/(c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-1)), x), x) + Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**n/(c*(p + S(1))), x) def replacement394(a, b, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*g*(m - n + S(-2))/((p + S(1))*(-b*e*g + c*d*g + c*e*f)), Int((d + e*x)**(m + S(-1))*(f + g*x)**n*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp(e**S(2)*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/((p + S(1))*(-b*e*g + c*d*g + c*e*f)), x) def replacement395(a, c, d, e, f, g, m, n, p, x): return Dist(e**S(2)*g*(m - n + S(-2))/(c*(p + S(1))*(d*g + e*f)), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**n, x), x) + Simp(e**S(2)*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))/(c*(p + S(1))*(d*g + e*f)), x) def replacement396(a, b, c, d, e, f, g, m, n, p, x): return -Dist(n*(-b*e*g + c*d*g + c*e*f)/(c*e*(m - n + S(-1))), Int((d + e*x)**m*(f + g*x)**(n + S(-1))*(a + b*x + c*x**S(2))**p, x), x) - Simp(e*(d + e*x)**(m + S(-1))*(f + g*x)**n*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m - n + S(-1))), x) def replacement397(a, c, d, e, f, g, m, n, p, x): return -Dist(n*(d*g + e*f)/(e*(m - n + S(-1))), Int((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**(n + S(-1)), x), x) - Simp(e*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**n/(c*(m - n + S(-1))), x) def replacement398(a, b, c, d, e, f, g, m, n, p, x): return -Dist(c*e*(m - n + S(-2))/((n + S(1))*(-b*e*g + c*d*g + c*e*f)), Int((d + e*x)**m*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**p, x), x) - Simp(e**S(2)*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/((n + S(1))*(-b*e*g + c*d*g + c*e*f)), x) def replacement399(a, c, d, e, f, g, m, n, p, x): return -Dist(e*(m - n + S(-2))/((n + S(1))*(d*g + e*f)), Int((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**(n + S(1)), x), x) - Simp(e**S(2)*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))/((n + S(1))*(c*d*g + c*e*f)), x) def replacement400(a, b, c, d, e, f, g, x): return Dist(S(2)*e**S(2), Subst(Int(S(1)/(-b*e*g + c*(d*g + e*f) + e**S(2)*g*x**S(2)), x), x, sqrt(a + b*x + c*x**S(2))/sqrt(d + e*x)), x) def replacement401(a, c, d, e, f, g, x): return Dist(S(2)*e**S(2), Subst(Int(S(1)/(c*(d*g + e*f) + e**S(2)*g*x**S(2)), x), x, sqrt(a + c*x**S(2))/sqrt(d + e*x)), x) def replacement402(a, b, c, d, e, f, g, m, n, p, x): return Simp(e**S(2)*(d + e*x)**(m + S(-2))*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*g*(n + p + S(2))), x) def replacement403(a, c, d, e, f, g, m, n, p, x): return Simp(e**S(2)*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-2))*(f + g*x)**(n + S(1))/(c*g*(n + p + S(2))), x) def replacement404(a, b, c, d, e, f, g, m, n, p, x): return -Dist(e*(b*e*g*(n + S(1)) - c*d*g*(S(2)*n + p + S(3)) + c*e*f*(p + S(1)))/(g*(n + S(1))*(-b*e*g + c*d*g + c*e*f)), Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**p, x), x) + Simp(e**S(2)*(d + e*x)**(m + S(-2))*(f + g*x)**(n + S(1))*(-d*g + e*f)*(a + b*x + c*x**S(2))**(p + S(1))/(g*(n + S(1))*(-b*e*g + c*d*g + c*e*f)), x) def replacement405(a, c, d, e, f, g, m, n, p, x): return -Dist(e*(-d*g*(S(2)*n + p + S(3)) + e*f*(p + S(1)))/(g*(n + S(1))*(d*g + e*f)), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1)), x), x) + Simp(e**S(2)*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-2))*(f + g*x)**(n + S(1))*(-d*g + e*f)/(c*g*(n + S(1))*(d*g + e*f)), x) def replacement406(a, b, c, d, e, f, g, m, n, p, x): return -Dist((b*e*g*(n + S(1)) - c*d*g*(S(2)*n + p + S(3)) + c*e*f*(p + S(1)))/(c*g*(n + p + S(2))), Int((d + e*x)**(m + S(-1))*(f + g*x)**n*(a + b*x + c*x**S(2))**p, x), x) + Simp(e**S(2)*(d + e*x)**(m + S(-2))*(f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*g*(n + p + S(2))), x) def replacement407(a, c, d, e, f, g, m, n, p, x): return -Dist((-d*g*(S(2)*n + p + S(3)) + e*f*(p + S(1)))/(g*(n + p + S(2))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(-1))*(f + g*x)**n, x), x) + Simp(e**S(2)*(a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-2))*(f + g*x)**(n + S(1))/(c*g*(n + p + S(2))), x) def replacement408(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)**n*(a + b*x + c*x**S(2))**p, x), x) def replacement409(a, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand(S(1)/sqrt(a + c*x**S(2)), (a + c*x**S(2))**(p + S(1)/2)*(d + e*x)**m*(f + g*x)**n, x), x) def replacement410(a, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**n, x), x) def replacement411(a, b, c, d, e, p, x): return -Dist(e**(S(-2)), Int((d - e*x)*(a + b*x + c*x**S(2))**p, x), x) + Dist(d**S(2)/e**S(2), Int((a + b*x + c*x**S(2))**p/(d + e*x), x), x) def replacement412(a, c, d, e, p, x): return -Dist(e**(S(-2)), Int((a + c*x**S(2))**p*(d - e*x), x), x) + Dist(d**S(2)/e**S(2), Int((a + c*x**S(2))**p/(d + e*x), x), x) def replacement413(a, b, c, d, e, f, g, m, p, x): return -Dist(S(1)/(c*e**S(2)*(m + S(2)*p + S(3))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**p*Simp(b*e*g*(d*g + e*f*(m + p + S(1))) - c*(d**S(2)*g**S(2) + d*e*f*g*m + e**S(2)*f**S(2)*(m + S(2)*p + S(3))) + e*g*x*(b*e*g*(m + p + S(2)) - c*(d*g*m + e*f*(m + S(2)*p + S(4)))), x), x), x) + Simp(g*(d + e*x)**m*(f + g*x)*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(3))), x) def replacement414(a, c, d, e, f, g, m, p, x): return -Dist(S(1)/(c*e**S(2)*(m + S(2)*p + S(3))), Int((a + c*x**S(2))**p*(d + e*x)**m*Simp(-c*e*g*x*(d*g*m + e*f*(m + S(2)*p + S(4))) - c*(d**S(2)*g**S(2) + d*e*f*g*m + e**S(2)*f**S(2)*(m + S(2)*p + S(3))), x), x), x) + Simp(g*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m*(f + g*x)/(c*(m + S(2)*p + S(3))), x) def replacement415(b, c, e, f, g, m, n, p, x): return Dist(x**(-m - p)*(e*x)**m*(b + c*x)**(-p)*(b*x + c*x**S(2))**p, Int(x**(m + p)*(b + c*x)**p*(f + g*x)**n, x), x) def replacement416(a, c, d, e, f, g, m, n, p, x): return Int((d + e*x)**(m + p)*(f + g*x)**n*(a/d + c*x/e)**p, x) def replacement417(a, b, c, d, e, f, g, m, n, p, x): return Dist((d + e*x)**(-FracPart(p))*(a/d + c*x/e)**(-FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((d + e*x)**(m + p)*(f + g*x)**n*(a/d + c*x/e)**p, x), x) def replacement418(a, c, d, e, f, g, m, n, p, x): return Dist((a + c*x**S(2))**FracPart(p)*(d + e*x)**(-FracPart(p))*(a/d + c*x/e)**(-FracPart(p)), Int((d + e*x)**(m + p)*(f + g*x)**n*(a/d + c*x/e)**p, x), x) def replacement419(a, b, c, d, e, f, g, m, p, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)*(a + b*x + c*x**S(2))**p, x), x) def replacement420(a, c, d, e, f, g, m, p, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x), x), x) def replacement421(a, b, c, d, e, f, g, x): return Dist(e*(-d*g + e*f)/(a*e**S(2) - b*d*e + c*d**S(2)), Int(S(1)/(d + e*x), x), x) + Dist(S(1)/(a*e**S(2) - b*d*e + c*d**S(2)), Int(Simp(a*e*g - b*e*f + c*d*f - c*x*(-d*g + e*f), x)/(a + b*x + c*x**S(2)), x), x) def replacement422(a, c, d, e, f, g, x): return Dist(e*(-d*g + e*f)/(a*e**S(2) + c*d**S(2)), Int(S(1)/(d + e*x), x), x) + Dist(S(1)/(a*e**S(2) + c*d**S(2)), Int(Simp(a*e*g + c*d*f - c*x*(-d*g + e*f), x)/(a + c*x**S(2)), x), x) def replacement423(a, b, c, d, e, f, g, m, p, x): return -Simp((d + e*x)**(m + S(1))*(-d*g + e*f)*(a + b*x + c*x**S(2))**(p + S(1))/(S(2)*(p + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement424(a, c, d, e, f, g, m, p, x): return -Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))*(-d*g + e*f)/(S(2)*(p + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement425(a, b, c, d, e, f, g, m, p, x): return -Dist(m*(-S(2)*a*e*g + b*(d*g + e*f) - S(2)*c*d*f)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1)), x), x) + Simp((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*(-S(2)*a*g + b*f + x*(-b*g + S(2)*c*f))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement426(a, c, d, e, f, g, m, p, x): return -Dist(m*(a*e*g + c*d*f)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1)), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**m*(a*g - c*f*x)/(S(2)*a*c*(p + S(1))), x) def replacement427(a, b, c, d, e, f, g, m, p, x): return -Dist((-S(2)*a*e*g + b*(d*g + e*f) - S(2)*c*d*f)/(S(2)*a*e**S(2) - S(2)*b*d*e + S(2)*c*d**S(2)), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) - Simp((d + e*x)**(m + S(1))*(-d*g + e*f)*(a + b*x + c*x**S(2))**(p + S(1))/(S(2)*(p + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement428(a, c, d, e, f, g, m, p, x): return Dist((a*e*g + c*d*f)/(a*e**S(2) + c*d**S(2)), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1)), x), x) - Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))*(-d*g + e*f)/(S(2)*(p + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement429(a, b, c, d, e, f, g, p, x): return -Simp((a + b*x + c*x**S(2))**(p + S(1))*(b*e*g*(p + S(2)) - S(2)*c*e*g*x*(p + S(1)) - c*(S(2)*p + S(3))*(d*g + e*f))/(S(2)*c**S(2)*(p + S(1))*(S(2)*p + S(3))), x) def replacement430(a, c, d, e, f, g, p, x): return Simp((a + c*x**S(2))**(p + S(1))*(S(2)*e*g*x*(p + S(1)) + (S(2)*p + S(3))*(d*g + e*f))/(S(2)*c*(p + S(1))*(S(2)*p + S(3))), x) def replacement431(a, b, c, d, e, f, g, p, x): return -Dist((-S(2)*a*c*e*g + b**S(2)*e*g*(p + S(2)) + c*(S(2)*p + S(3))*(-b*(d*g + e*f) + S(2)*c*d*f))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1)), x), x) - Simp((a + b*x + c*x**S(2))**(p + S(1))*(S(2)*a*c*(d*g + e*f) - b*(a*e*g + c*d*f) - x*(b**S(2)*e*g - b*c*(d*g + e*f) + S(2)*c*(-a*e*g + c*d*f)))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement432(a, c, d, e, f, g, p, x): return -Dist((a*e*g - c*d*f*(S(2)*p + S(3)))/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1)), x), x) - Simp((a + c*x**S(2))**(p + S(1))*(-a*(d*g + e*(f + g*x)) + c*d*f*x)/(S(2)*a*c*(p + S(1))), x) def replacement433(a, b, c, d, e, f, g, p, x): return Dist((-S(2)*a*c*e*g + b**S(2)*e*g*(p + S(2)) + c*(S(2)*p + S(3))*(-b*(d*g + e*f) + S(2)*c*d*f))/(S(2)*c**S(2)*(S(2)*p + S(3))), Int((a + b*x + c*x**S(2))**p, x), x) - Simp((a + b*x + c*x**S(2))**(p + S(1))*(b*e*g*(p + S(2)) - S(2)*c*e*g*x*(p + S(1)) - c*(S(2)*p + S(3))*(d*g + e*f))/(S(2)*c**S(2)*(p + S(1))*(S(2)*p + S(3))), x) def replacement434(a, c, d, e, f, g, p, x): return -Dist((a*e*g - c*d*f*(S(2)*p + S(3)))/(c*(S(2)*p + S(3))), Int((a + c*x**S(2))**p, x), x) + Simp((a + c*x**S(2))**(p + S(1))*(S(2)*e*g*x*(p + S(1)) + (S(2)*p + S(3))*(d*g + e*f))/(S(2)*c*(p + S(1))*(S(2)*p + S(3))), x) def replacement435(a, c, e, f, g, m, p, x): return Dist(f, Int((e*x)**m*(a + c*x**S(2))**p, x), x) + Dist(g/e, Int((e*x)**(m + S(1))*(a + c*x**S(2))**p, x), x) def replacement436(a, b, c, d, e, f, g, m, p, x): return Dist((d + e*x)**FracPart(p)*(a*d + c*e*x**S(3))**(-FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((f + g*x)*(a*d + c*e*x**S(3))**p, x), x) def replacement437(a, b, c, d, e, f, g, m, p, x): return -Dist(p/(e**S(2)*(m + S(1))*(m + S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x)**(m + S(2))*(a + b*x + c*x**S(2))**(p + S(-1))*Simp(S(2)*a*c*e*(m + S(2))*(-d*g + e*f) + b**S(2)*e*(d*g*(p + S(1)) - e*f*(m + p + S(2))) + b*(a*e**S(2)*g*(m + S(1)) - c*d*(d*g*(S(2)*p + S(1)) - e*f*(m + S(2)*p + S(2)))) - c*x*(S(2)*c*d*(d*g*(S(2)*p + S(1)) - e*f*(m + S(2)*p + S(2))) - e*(S(2)*a*e*g*(m + S(1)) - b*(d*g*(m - S(2)*p) + e*f*(m + S(2)*p + S(2))))), x), x), x) - Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*(-d*p*(-b*e + S(2)*c*d)*(-d*g + e*f) - e*x*(g*(m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2)) + p*(-b*e + S(2)*c*d)*(-d*g + e*f)) + (d*g - e*f*(m + S(2)))*(a*e**S(2) - b*d*e + c*d**S(2)))/(e**S(2)*(m + S(1))*(m + S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement438(a, c, d, e, f, g, m, p, x): return -Dist(p/(e**S(2)*(m + S(1))*(m + S(2))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(2))*Simp(S(2)*a*c*e*(m + S(2))*(-d*g + e*f) - c*x*(-S(2)*a*e**S(2)*g*(m + S(1)) + S(2)*c*d*(d*g*(S(2)*p + S(1)) - e*f*(m + S(2)*p + S(2)))), x), x), x) - Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*(-S(2)*c*d**S(2)*p*(-d*g + e*f) - e*x*(S(2)*c*d*p*(-d*g + e*f) + g*(m + S(1))*(a*e**S(2) + c*d**S(2))) + (a*e**S(2) + c*d**S(2))*(d*g - e*f*(m + S(2))))/(e**S(2)*(m + S(1))*(m + S(2))*(a*e**S(2) + c*d**S(2))), x) def replacement439(a, b, c, d, e, f, g, m, p, x): return Dist(p/(e**S(2)*(m + S(1))*(m + S(2)*p + S(2))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(-1))*Simp(-b*e*f*(m + S(2)*p + S(2)) + g*(S(2)*a*e*m + S(2)*a*e + S(2)*b*d*p + b*d) + x*(-S(2)*c*e*f*(m + S(2)*p + S(2)) + g*(b*e*m + b*e + S(4)*c*d*p + S(2)*c*d)), x), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*(-d*g*(S(2)*p + S(1)) + e*f*(m + S(2)*p + S(2)) + e*g*x*(m + S(1)))/(e**S(2)*(m + S(1))*(m + S(2)*p + S(2))), x) def replacement440(a, c, d, e, f, g, m, p, x): return Dist(p/(e**S(2)*(m + S(1))*(m + S(2)*p + S(2))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**(m + S(1))*Simp(g*(S(2)*a*e*m + S(2)*a*e) + x*(-S(2)*c*e*f*(m + S(2)*p + S(2)) + g*(S(4)*c*d*p + S(2)*c*d)), x), x), x) + Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*(-d*g*(S(2)*p + S(1)) + e*f*(m + S(2)*p + S(2)) + e*g*x*(m + S(1)))/(e**S(2)*(m + S(1))*(m + S(2)*p + S(2))), x) def replacement441(a, b, c, d, e, f, g, m, p, x): return -Dist(p/(c*e**S(2)*(m + S(2)*p + S(1))*(m + S(2)*p + S(2))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(-1))*Simp(c*e*f*(-S(2)*a*e + b*d)*(m + S(2)*p + S(2)) + g*(a*e*(b*e*m + b*e - S(2)*c*d*m) + b*d*(b*e*p - S(2)*c*d*p - c*d)) + x*(c*e*f*(-b*e + S(2)*c*d)*(m + S(2)*p + S(2)) + g*(b**S(2)*e**S(2)*(m + p + S(1)) - S(2)*c**S(2)*d**S(2)*(S(2)*p + S(1)) - c*e*(S(2)*a*e*(m + S(2)*p + S(1)) + b*d*(m - S(2)*p)))), x), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*(c*e*f*(m + S(2)*p + S(2)) + c*e*g*x*(m + S(2)*p + S(1)) - g*(-b*e*p + S(2)*c*d*p + c*d))/(c*e**S(2)*(m + S(2)*p + S(1))*(m + S(2)*p + S(2))), x) def replacement442(a, c, d, e, f, g, m, p, x): return Dist(S(2)*p/(c*e**S(2)*(m + S(2)*p + S(1))*(m + S(2)*p + S(2))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x)**m*Simp(a*c*d*e*g*m + a*c*e**S(2)*f*(m + S(2)*p + S(2)) - x*(c**S(2)*d*e*f*(m + S(2)*p + S(2)) - g*(a*c*e**S(2)*(m + S(2)*p + S(1)) + c**S(2)*d**S(2)*(S(2)*p + S(1)))), x), x), x) + Simp((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*(-c*d*g*(S(2)*p + S(1)) + c*e*f*(m + S(2)*p + S(2)) + c*e*g*x*(m + S(2)*p + S(1)))/(c*e**S(2)*(m + S(2)*p + S(1))*(m + S(2)*p + S(2))), x) def replacement443(a, b, c, d, e, f, g, m, p, x): return -Dist(S(1)/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-2))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(b*e*g*(a*e*(m + S(-1)) + b*d*(p + S(2))) + S(2)*c**S(2)*d**S(2)*f*(S(2)*p + S(3)) - c*(S(2)*a*e*(d*g*m + e*f*(m + S(-1))) + b*d*(d*g*(S(2)*p + S(3)) - e*f*(m - S(2)*p + S(-4)))) + e*x*(b**S(2)*e*g*(m + p + S(1)) + S(2)*c**S(2)*d*f*(m + S(2)*p + S(2)) - c*(S(2)*a*e*g*m + b*(d*g + e*f)*(m + S(2)*p + S(2)))), x), x), x) - Simp((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*(S(2)*a*c*(d*g + e*f) - b*(a*e*g + c*d*f) - x*(b**S(2)*e*g + S(2)*c**S(2)*d*f - c*(S(2)*a*e*g + b*d*g + b*e*f)))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement444(a, c, d, e, f, g, m, p, x): return -Dist(S(1)/(S(4)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-2))*Simp(S(2)*a*e*(d*g*m + e*f*(m + S(-1))) - S(2)*c*d**S(2)*f*(S(2)*p + S(3)) + e*x*(S(2)*a*e*g*m - S(2)*c*d*f*(m + S(2)*p + S(2))), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*(S(2)*a*(d*g + e*f) - x*(-S(2)*a*e*g + S(2)*c*d*f))/(S(4)*a*c*(p + S(1))), x) def replacement445(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-e*x*(-b*g + S(2)*c*f)*(m + S(2)*p + S(3)) - f*(b*e*m + S(2)*c*d*(S(2)*p + S(3))) + g*(S(2)*a*e*m + b*d*(S(2)*p + S(3))), x), x), x) + Simp((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*(-S(2)*a*g + b*f + x*(-b*g + S(2)*c*f))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement446(a, c, d, e, f, g, m, p, x): return -Dist(S(1)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(-1))*Simp(a*e*g*m - c*d*f*(S(2)*p + S(3)) - c*e*f*x*(m + S(2)*p + S(3)), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**m*(a*g - c*f*x)/(S(2)*a*c*(p + S(1))), x) def replacement447(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*Simp(c*e*x*(-f*(-b*e + S(2)*c*d) + g*(-S(2)*a*e + b*d))*(m + S(2)*p + S(4)) + f*(-S(2)*a*c*e**S(2)*(m + S(2)*p + S(3)) + b**S(2)*e**S(2)*(m + p + S(2)) + b*c*d*e*(-m + S(2)*p + S(2)) - S(2)*c**S(2)*d**S(2)*(S(2)*p + S(3))) - g*(a*e*(b*e*m + b*e - S(2)*c*d*m) - b*d*(-b*e*p - b*e + S(2)*c*d*p + S(3)*c*d)), x), x), x) + Simp((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(-a*g*(-b*e + S(2)*c*d) + c*x*(f*(-b*e + S(2)*c*d) - g*(-S(2)*a*e + b*d)) + f*(S(2)*a*c*e - b**S(2)*e + b*c*d))/((p + S(1))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement448(a, c, d, e, f, g, m, p, x): return Dist(S(1)/(S(2)*a*c*(p + S(1))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x)**m*Simp(-a*c*d*e*g*m + c*e*x*(a*e*g + c*d*f)*(m + S(2)*p + S(4)) + f*(a*c*e**S(2)*(m + S(2)*p + S(3)) + c**S(2)*d**S(2)*(S(2)*p + S(3))), x), x), x) - Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))*(-a*c*d*g + a*c*e*f + c*x*(a*e*g + c*d*f))/(S(2)*a*c*(p + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement449(a, b, c, d, e, f, g, m, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)/(a + b*x + c*x**S(2)), x), x) def replacement450(a, c, d, e, f, g, m, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)/(a + c*x**S(2)), x), x) def replacement451(a, b, c, d, e, f, g, m, x): return Dist(S(1)/c, Int((d + e*x)**(m + S(-1))*Simp(-a*e*g + c*d*f + x*(-b*e*g + c*d*g + c*e*f), x)/(a + b*x + c*x**S(2)), x), x) + Simp(g*(d + e*x)**m/(c*m), x) def replacement452(a, c, d, e, f, g, m, x): return Dist(S(1)/c, Int((d + e*x)**(m + S(-1))*Simp(-a*e*g + c*d*f + x*(c*d*g + c*e*f), x)/(a + c*x**S(2)), x), x) + Simp(g*(d + e*x)**m/(c*m), x) def replacement453(a, b, c, d, e, f, g, x): return Dist(S(2), Subst(Int((-d*g + e*f + g*x**S(2))/(a*e**S(2) - b*d*e + c*d**S(2) + c*x**S(4) - x**S(2)*(-b*e + S(2)*c*d)), x), x, sqrt(d + e*x)), x) def replacement454(a, c, d, e, f, g, x): return Dist(S(2), Subst(Int((-d*g + e*f + g*x**S(2))/(a*e**S(2) + c*d**S(2) - S(2)*c*d*x**S(2) + c*x**S(4)), x), x, sqrt(d + e*x)), x) def replacement455(a, b, c, d, e, f, g, m, x): return Dist(S(1)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((d + e*x)**(m + S(1))*Simp(a*e*g - b*e*f + c*d*f - c*x*(-d*g + e*f), x)/(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*(-d*g + e*f)/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement456(a, c, d, e, f, g, m, x): return Dist(S(1)/(a*e**S(2) + c*d**S(2)), Int((d + e*x)**(m + S(1))*Simp(a*e*g + c*d*f - c*x*(-d*g + e*f), x)/(a + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*(-d*g + e*f)/((m + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement457(a, b, c, d, e, f, g, m, x): return Int(ExpandIntegrand((d + e*x)**m, (f + g*x)/(a + b*x + c*x**S(2)), x), x) def replacement458(a, c, d, e, f, g, m, x): return Int(ExpandIntegrand((d + e*x)**m, (f + g*x)/(a + c*x**S(2)), x), x) def replacement459(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/(c*(m + S(2)*p + S(2))), Int((d + e*x)**(m + S(-1))*(a + b*x + c*x**S(2))**p*Simp(d*(p + S(1))*(-b*g + S(2)*c*f) + m*(-a*e*g + c*d*f) + x*(e*(p + S(1))*(-b*g + S(2)*c*f) + m*(-b*e*g + c*d*g + c*e*f)), x), x), x) + Simp(g*(d + e*x)**m*(a + b*x + c*x**S(2))**(p + S(1))/(c*(m + S(2)*p + S(2))), x) def replacement460(a, c, d, e, f, g, m, p, x): return Dist(S(1)/(c*(m + S(2)*p + S(2))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(-1))*Simp(-a*e*g*m + c*d*f*(m + S(2)*p + S(2)) + c*x*(d*g*m + e*f*(m + S(2)*p + S(2))), x), x), x) + Simp(g*(a + c*x**S(2))**(p + S(1))*(d + e*x)**m/(c*(m + S(2)*p + S(2))), x) def replacement461(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*Simp(b*(p + S(1))*(d*g - e*f) - c*x*(-d*g + e*f)*(m + S(2)*p + S(3)) + (m + S(1))*(a*e*g - b*e*f + c*d*f), x), x), x) + Simp((d + e*x)**(m + S(1))*(-d*g + e*f)*(a + b*x + c*x**S(2))**(p + S(1))/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement462(a, c, d, e, f, g, m, p, x): return Dist(S(1)/((m + S(1))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*Simp(-c*x*(-d*g + e*f)*(m + S(2)*p + S(3)) + (m + S(1))*(a*e*g + c*d*f), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))*(-d*g + e*f)/((m + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement463(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*Simp(b*(p + S(1))*(d*g - e*f) - c*x*(-d*g + e*f)*(m + S(2)*p + S(3)) + (m + S(1))*(a*e*g - b*e*f + c*d*f), x), x), x) + Simp((d + e*x)**(m + S(1))*(-d*g + e*f)*(a + b*x + c*x**S(2))**(p + S(1))/((m + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement464(a, c, d, e, f, g, m, p, x): return Dist(S(1)/((m + S(1))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*Simp(-c*x*(-d*g + e*f)*(m + S(2)*p + S(3)) + (m + S(1))*(a*e*g + c*d*f), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(d + e*x)**(m + S(1))*(-d*g + e*f)/((m + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement465(a, b, c, d, e, f, g, x): return Dist(S(4)*f*(a - d)/(-a*e + b*d), Subst(Int(S(1)/(S(4)*a - S(4)*d - x**S(2)), x), x, (S(2)*a - S(2)*d + x*(b - e))/sqrt(a + b*x + c*x**S(2))), x) def replacement466(a, b, c, f, g, x): return Dist(S(2), Subst(Int((f + g*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x, sqrt(x)), x) def replacement467(a, c, f, g, x): return Dist(S(2), Subst(Int((f + g*x**S(2))/sqrt(a + c*x**S(4)), x), x, sqrt(x)), x) def replacement468(a, b, c, e, f, g, x): return Dist(sqrt(x)/sqrt(e*x), Int((f + g*x)/(sqrt(x)*sqrt(a + b*x + c*x**S(2))), x), x) def replacement469(a, c, e, f, g, x): return Dist(sqrt(x)/sqrt(e*x), Int((f + g*x)/(sqrt(x)*sqrt(a + c*x**S(2))), x), x) def replacement470(a, b, c, d, e, f, g, m, p, x): return Dist(g/e, Int((d + e*x)**(m + S(1))*(a + b*x + c*x**S(2))**p, x), x) + Dist((-d*g + e*f)/e, Int((d + e*x)**m*(a + b*x + c*x**S(2))**p, x), x) def replacement471(a, c, d, e, f, g, m, p, x): return Dist(g/e, Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1)), x), x) + Dist((-d*g + e*f)/e, Int((a + c*x**S(2))**p*(d + e*x)**m, x), x) def replacement472(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)**n*(a + b*x + c*x**S(2))**p, x), x) def replacement473(a, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**n, x), x) def replacement474(a, b, c, d, e, f, g, p, x): return -Dist(S(1)/(e*(-d*g + e*f)), Int((a + b*x + c*x**S(2))**(p + S(-1))*Simp(a*e*g - b*e*f + c*d*f - c*x*(-d*g + e*f), x)/(f + g*x), x), x) + Dist((a*e**S(2) - b*d*e + c*d**S(2))/(e*(-d*g + e*f)), Int((a + b*x + c*x**S(2))**(p + S(-1))/(d + e*x), x), x) def replacement475(a, c, d, e, f, g, p, x): return -Dist(S(1)/(e*(-d*g + e*f)), Int((a + c*x**S(2))**(p + S(-1))*Simp(a*e*g + c*d*f - c*x*(-d*g + e*f), x)/(f + g*x), x), x) + Dist((a*e**S(2) + c*d**S(2))/(e*(-d*g + e*f)), Int((a + c*x**S(2))**(p + S(-1))/(d + e*x), x), x) def With476(a, b, c, d, e, f, g, m, n, p, x): q = Denominator(m) return Dist(q/e, Subst(Int(x**(q*(m + S(1)) + S(-1))*(g*x**q/e + (-d*g + e*f)/e)**n*(c*x**(S(2)*q)/e**S(2) - x**q*(-b*e + S(2)*c*d)/e**S(2) + (a*e**S(2) - b*d*e + c*d**S(2))/e**S(2))**p, x), x, (d + e*x)**(S(1)/q)), x) def With477(a, c, d, e, f, g, m, n, p, x): q = Denominator(m) return Dist(q/e, Subst(Int(x**(q*(m + S(1)) + S(-1))*(g*x**q/e + (-d*g + e*f)/e)**n*(-S(2)*c*d*x**q/e**S(2) + c*x**(S(2)*q)/e**S(2) + (a*e**S(2) + c*d**S(2))/e**S(2))**p, x), x, (d + e*x)**(S(1)/q)), x) def replacement478(a, b, c, d, e, f, g, m, n, p, x): return Int((d*f + e*g*x**S(2))**m*(a + b*x + c*x**S(2))**p, x) def replacement479(a, c, d, e, f, g, m, n, p, x): return Int((a + c*x**S(2))**p*(d*f + e*g*x**S(2))**m, x) def replacement480(a, b, c, d, e, f, g, m, n, p, x): return Dist((d + e*x)**FracPart(m)*(f + g*x)**FracPart(m)*(d*f + e*g*x**S(2))**(-FracPart(m)), Int((d*f + e*g*x**S(2))**m*(a + b*x + c*x**S(2))**p, x), x) def replacement481(a, c, d, e, f, g, m, n, p, x): return Dist((d + e*x)**FracPart(m)*(f + g*x)**FracPart(m)*(d*f + e*g*x**S(2))**(-FracPart(m)), Int((a + c*x**S(2))**p*(d*f + e*g*x**S(2))**m, x), x) def replacement482(a, b, c, d, e, f, g, m, n, x): return Dist(c, Int(x**S(2)*(d + e*x)**m*(f + g*x)**n, x), x) + Int((a + b*x)*(d + e*x)**m*(f + g*x)**n, x) def replacement483(a, c, d, e, f, g, m, n, x): return Dist(a, Int((d + e*x)**m*(f + g*x)**n, x), x) + Dist(c, Int(x**S(2)*(d + e*x)**m*(f + g*x)**n, x), x) def replacement484(a, b, c, d, e, f, g, m, n, x): return Dist(c**(S(-2)), Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-2))*Simp(a*b*e*g**S(2) - a*c*d*g**S(2) - S(2)*a*c*e*f*g + c**S(2)*d*f**S(2) + x*(-a*c*e*g**S(2) + b**S(2)*e*g**S(2) - b*c*d*g**S(2) - S(2)*b*c*e*f*g + S(2)*c**S(2)*d*f*g + c**S(2)*e*f**S(2)), x)/(a + b*x + c*x**S(2)), x), x) + Dist(g/c**S(2), Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-2))*Simp(-b*e*g + c*d*g + S(2)*c*e*f + c*e*g*x, x), x), x) def replacement485(a, c, d, e, f, g, m, n, x): return Dist(S(1)/c, Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-2))*Simp(-a*d*g**S(2) - S(2)*a*e*f*g + c*d*f**S(2) + x*(-a*e*g**S(2) + S(2)*c*d*f*g + c*e*f**S(2)), x)/(a + c*x**S(2)), x), x) + Dist(g/c, Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-2))*Simp(d*g + S(2)*e*f + e*g*x, x), x), x) def replacement486(a, b, c, d, e, f, g, m, n, x): return Dist(S(1)/c, Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-1))*Simp(-a*e*g + c*d*f + x*(-b*e*g + c*d*g + c*e*f), x)/(a + b*x + c*x**S(2)), x), x) + Dist(e*g/c, Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-1)), x), x) def replacement487(a, c, d, e, f, g, m, n, x): return Dist(S(1)/c, Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-1))*Simp(-a*e*g + c*d*f + x*(c*d*g + c*e*f), x)/(a + c*x**S(2)), x), x) + Dist(e*g/c, Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(-1)), x), x) def replacement488(a, b, c, d, e, f, g, m, n, x): return -Dist(g*(-d*g + e*f)/(a*g**S(2) - b*f*g + c*f**S(2)), Int((d + e*x)**(m + S(-1))*(f + g*x)**n, x), x) + Dist(S(1)/(a*g**S(2) - b*f*g + c*f**S(2)), Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))*Simp(a*e*g - b*d*g + c*d*f + c*x*(-d*g + e*f), x)/(a + b*x + c*x**S(2)), x), x) def replacement489(a, c, d, e, f, g, m, n, x): return -Dist(g*(-d*g + e*f)/(a*g**S(2) + c*f**S(2)), Int((d + e*x)**(m + S(-1))*(f + g*x)**n, x), x) + Dist(S(1)/(a*g**S(2) + c*f**S(2)), Int((d + e*x)**(m + S(-1))*(f + g*x)**(n + S(1))*Simp(a*e*g + c*d*f + c*x*(-d*g + e*f), x)/(a + c*x**S(2)), x), x) def replacement490(a, b, c, d, e, f, g, m, x): return Int(ExpandIntegrand(S(1)/(sqrt(d + e*x)*sqrt(f + g*x)), (d + e*x)**(m + S(1)/2)/(a + b*x + c*x**S(2)), x), x) def replacement491(a, c, d, e, f, g, m, x): return Int(ExpandIntegrand(S(1)/(sqrt(d + e*x)*sqrt(f + g*x)), (d + e*x)**(m + S(1)/2)/(a + c*x**S(2)), x), x) def replacement492(a, b, c, d, e, f, g, m, n, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)**n, S(1)/(a + b*x + c*x**S(2)), x), x) def replacement493(a, c, d, e, f, g, m, n, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)**n, S(1)/(a + c*x**S(2)), x), x) def replacement494(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)**n*(a + b*x + c*x**S(2))**p, x), x) def replacement495(a, c, d, e, f, g, m, n, p, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**n, x), x) def replacement496(a, b, c, d, e, g, m, n, p, x): return Dist((d + e*x)**FracPart(p)*(a*d + c*e*x**S(3))**(-FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((g*x)**n*(a*d + c*e*x**S(3))**p, x), x) def replacement497(a, b, c, d, e, f, g, n, p, x): return -Dist(S(1)/(e*(-d*g + e*f)), Int((f + g*x)**n*(a + b*x + c*x**S(2))**(p + S(-1))*(a*e*g - b*e*f + c*d*f - c*x*(-d*g + e*f)), x), x) + Dist((a*e**S(2) - b*d*e + c*d**S(2))/(e*(-d*g + e*f)), Int((f + g*x)**(n + S(1))*(a + b*x + c*x**S(2))**(p + S(-1))/(d + e*x), x), x) def replacement498(a, c, d, e, f, g, n, p, x): return -Dist(S(1)/(e*(-d*g + e*f)), Int((a + c*x**S(2))**(p + S(-1))*(f + g*x)**n*(a*e*g + c*d*f - c*x*(-d*g + e*f)), x), x) + Dist((a*e**S(2) + c*d**S(2))/(e*(-d*g + e*f)), Int((a + c*x**S(2))**(p + S(-1))*(f + g*x)**(n + S(1))/(d + e*x), x), x) def replacement499(a, b, c, d, e, f, g, n, p, x): return Dist(e*(-d*g + e*f)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f + g*x)**(n + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))/(d + e*x), x), x) + Dist(S(1)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f + g*x)**(n + S(-1))*(a + b*x + c*x**S(2))**p*(a*e*g - b*e*f + c*d*f - c*x*(-d*g + e*f)), x), x) def replacement500(a, c, d, e, f, g, n, p, x): return Dist(e*(-d*g + e*f)/(a*e**S(2) + c*d**S(2)), Int((a + c*x**S(2))**(p + S(1))*(f + g*x)**(n + S(-1))/(d + e*x), x), x) + Dist(S(1)/(a*e**S(2) + c*d**S(2)), Int((a + c*x**S(2))**p*(f + g*x)**(n + S(-1))*(a*e*g + c*d*f - c*x*(-d*g + e*f)), x), x) def With501(a, b, c, d, e, f, g, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(-sqrt(S(2))*sqrt(-g*(b + S(2)*c*x - q)/(-b*g + S(2)*c*f + g*q))*sqrt(-g*(b + S(2)*c*x + q)/(-b*g + S(2)*c*f - g*q))*EllipticPi(e*(-b*g + S(2)*c*f + g*q)/(S(2)*c*(-d*g + e*f)), asin(sqrt(S(2))*sqrt(c/(-b*g + S(2)*c*f + g*q))*sqrt(f + g*x)), (-b*g + S(2)*c*f + g*q)/(-b*g + S(2)*c*f - g*q))/(sqrt(c/(-b*g + S(2)*c*f + g*q))*(-d*g + e*f)*sqrt(a + b*x + c*x**S(2))), x) def With502(a, c, d, e, f, g, x): q = Rt(-a*c, S(2)) return Simp(-S(2)*sqrt(g*(-c*x + q)/(c*f + g*q))*sqrt(-g*(c*x + q)/(c*f - g*q))*EllipticPi(e*(c*f + g*q)/(c*(-d*g + e*f)), asin(sqrt(c/(c*f + g*q))*sqrt(f + g*x)), (c*f + g*q)/(c*f - g*q))/(sqrt(c/(c*f + g*q))*sqrt(a + c*x**S(2))*(-d*g + e*f)), x) def replacement503(a, b, c, d, e, f, g, n, x): return Int(ExpandIntegrand(S(1)/(sqrt(f + g*x)*sqrt(a + b*x + c*x**S(2))), (f + g*x)**(n + S(1)/2)/(d + e*x), x), x) def replacement504(a, c, d, e, f, g, n, x): return Int(ExpandIntegrand(S(1)/(sqrt(a + c*x**S(2))*sqrt(f + g*x)), (f + g*x)**(n + S(1)/2)/(d + e*x), x), x) def replacement505(a, b, c, d, e, f, g, x): return Dist(-S(2)*sqrt((-d*g + e*f)**S(2)*(a + b*x + c*x**S(2))/((d + e*x)**S(2)*(a*g**S(2) - b*f*g + c*f**S(2))))*(d + e*x)/((-d*g + e*f)*sqrt(a + b*x + c*x**S(2))), Subst(Int(S(1)/sqrt(x**S(4)*(a*e**S(2) - b*d*e + c*d**S(2))/(a*g**S(2) - b*f*g + c*f**S(2)) - x**S(2)*(S(2)*a*e*g - b*d*g - b*e*f + S(2)*c*d*f)/(a*g**S(2) - b*f*g + c*f**S(2)) + S(1)), x), x, sqrt(f + g*x)/sqrt(d + e*x)), x) def replacement506(a, c, d, e, f, g, x): return Dist(-S(2)*sqrt((a + c*x**S(2))*(-d*g + e*f)**S(2)/((d + e*x)**S(2)*(a*g**S(2) + c*f**S(2))))*(d + e*x)/(sqrt(a + c*x**S(2))*(-d*g + e*f)), Subst(Int(S(1)/sqrt(x**S(4)*(a*e**S(2) + c*d**S(2))/(a*g**S(2) + c*f**S(2)) - x**S(2)*(S(2)*a*e*g + S(2)*c*d*f)/(a*g**S(2) + c*f**S(2)) + S(1)), x), x, sqrt(f + g*x)/sqrt(d + e*x)), x) def replacement507(a, c, e, f, g, m, p, x): return Dist(S(2)*f*g/e, Int((e*x)**(m + S(1))*(a + c*x**S(2))**p, x), x) + Int((e*x)**m*(a + c*x**S(2))**p*(f**S(2) + g**S(2)*x**S(2)), x) def replacement508(a, c, e, f, g, m, p, x): return Dist(f, Int((e*x)**m*(a + c*x**S(2))**p*(f**S(2) + S(3)*g**S(2)*x**S(2)), x), x) + Dist(g/e, Int((e*x)**(m + S(1))*(a + c*x**S(2))**p*(S(3)*f**S(2) + g**S(2)*x**S(2)), x), x) def replacement509(a, b, c, d, e, f, g, m, n, p, x): return Dist(g/e, Int((d + e*x)**(m + S(1))*(f + g*x)**(n + S(-1))*(a + b*x + c*x**S(2))**p, x), x) + Dist((-d*g + e*f)/e, Int((d + e*x)**m*(f + g*x)**(n + S(-1))*(a + b*x + c*x**S(2))**p, x), x) def replacement510(a, c, d, e, f, g, m, n, p, x): return Dist(g/e, Int((a + c*x**S(2))**p*(d + e*x)**(m + S(1))*(f + g*x)**(n + S(-1)), x), x) + Dist((-d*g + e*f)/e, Int((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**(n + S(-1)), x), x) def replacement511(a, b, c, d, e, f, g, m, n, p, x): return Int((d + e*x)**m*(f + g*x)**n*(a + b*x + c*x**S(2))**p, x) def replacement512(a, c, d, e, f, g, m, n, p, x): return Int((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**n, x) def replacement513(a, b, c, d, e, f, g, m, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((d + e*x)**m*(f + g*x)**n*(a + b*x + c*x**S(2))**p, x), x, u), x) def replacement514(a, c, d, e, f, g, m, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + c*x**S(2))**p*(d + e*x)**m*(f + g*x)**n, x), x, u), x) def replacement515(a, b, c, d, e, f, p, q, x): return Dist((c/f)**p, Int((d + e*x + f*x**S(2))**(p + q), x), x) def replacement516(a, b, c, d, e, f, p, q, x): return Dist(a**IntPart(p)*d**(-IntPart(p))*(a + b*x + c*x**S(2))**FracPart(p)*(d + e*x + f*x**S(2))**(-FracPart(p)), Int((d + e*x + f*x**S(2))**(p + q), x), x) def replacement517(a, b, c, d, e, f, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b + S(2)*c*x)**(S(2)*p)*(d + e*x + f*x**S(2))**q, x), x) def replacement518(a, b, c, d, f, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b + S(2)*c*x)**(S(2)*p)*(d + f*x**S(2))**q, x), x) def replacement519(a, b, c, d, e, f, q, x): return Simp((d + e*x + f*x**S(2))**(q + S(1))*(b*f*(S(2)*q + S(3)) - c*e*(q + S(2)) + S(2)*c*f*x*(q + S(1)))/(S(2)*f**S(2)*(q + S(1))*(S(2)*q + S(3))), x) def replacement520(a, c, d, e, f, q, x): return Simp((-c*e*(q + S(2)) + S(2)*c*f*x*(q + S(1)))*(d + e*x + f*x**S(2))**(q + S(1))/(S(2)*f**S(2)*(q + S(1))*(S(2)*q + S(3))), x) def replacement521(a, b, c, d, f, q, x): return Simp((d + f*x**S(2))**(q + S(1))*(S(2)*a*f*x*(q + S(1)) + b*d)/(S(2)*d*f*(q + S(1))), x) def replacement522(a, b, c, d, f, q, x): return Dist(b, Int(x*(d + f*x**S(2))**q, x), x) + Int((a + c*x**S(2))*(d + f*x**S(2))**q, x) def replacement523(a, b, c, d, e, f, q, x): return Int(ExpandIntegrand((a + b*x + c*x**S(2))*(d + e*x + f*x**S(2))**q, x), x) def replacement524(a, c, d, e, f, q, x): return Int(ExpandIntegrand((a + c*x**S(2))*(d + e*x + f*x**S(2))**q, x), x) def replacement525(a, b, c, d, e, f, q, x): return -Dist((c*(-S(2)*d*f + e**S(2)*(q + S(2))) + f*(S(2)*q + S(3))*(S(2)*a*f - b*e))/(f*(q + S(1))*(-S(4)*d*f + e**S(2))), Int((d + e*x + f*x**S(2))**(q + S(1)), x), x) + Simp((d + e*x + f*x**S(2))**(q + S(1))*(a*e*f - S(2)*b*d*f + c*d*e + x*(c*(-S(2)*d*f + e**S(2)) + f*(S(2)*a*f - b*e)))/(f*(q + S(1))*(-S(4)*d*f + e**S(2))), x) def replacement526(a, c, d, e, f, q, x): return -Dist((S(2)*a*f**S(2)*(S(2)*q + S(3)) + c*(-S(2)*d*f + e**S(2)*(q + S(2))))/(f*(q + S(1))*(-S(4)*d*f + e**S(2))), Int((d + e*x + f*x**S(2))**(q + S(1)), x), x) + Simp((d + e*x + f*x**S(2))**(q + S(1))*(a*e*f + c*d*e + x*(S(2)*a*f**S(2) + c*(-S(2)*d*f + e**S(2))))/(f*(q + S(1))*(-S(4)*d*f + e**S(2))), x) def replacement527(a, b, c, d, f, q, x): return Dist((S(2)*a*f*q + S(3)*a*f - c*d)/(S(2)*d*f*(q + S(1))), Int((d + f*x**S(2))**(q + S(1)), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(b*d - x*(a*f - c*d))/(S(2)*d*f*(q + S(1))), x) def replacement528(a, b, c, d, e, f, q, x): return Dist((c*(-S(2)*d*f + e**S(2)*(q + S(2))) + f*(S(2)*q + S(3))*(S(2)*a*f - b*e))/(S(2)*f**S(2)*(S(2)*q + S(3))), Int((d + e*x + f*x**S(2))**q, x), x) + Simp((d + e*x + f*x**S(2))**(q + S(1))*(b*f*(S(2)*q + S(3)) - c*e*(q + S(2)) + S(2)*c*f*x*(q + S(1)))/(S(2)*f**S(2)*(q + S(1))*(S(2)*q + S(3))), x) def replacement529(a, c, d, e, f, q, x): return Dist((S(2)*a*f**S(2)*(S(2)*q + S(3)) + c*(-S(2)*d*f + e**S(2)*(q + S(2))))/(S(2)*f**S(2)*(S(2)*q + S(3))), Int((d + e*x + f*x**S(2))**q, x), x) + Simp((-c*e*(q + S(2)) + S(2)*c*f*x*(q + S(1)))*(d + e*x + f*x**S(2))**(q + S(1))/(S(2)*f**S(2)*(q + S(1))*(S(2)*q + S(3))), x) def replacement530(a, b, c, d, f, q, x): return Dist((S(2)*a*f*q + S(3)*a*f - c*d)/(f*(S(2)*q + S(3))), Int((d + f*x**S(2))**q, x), x) + Simp((d + f*x**S(2))**(q + S(1))*(b*f*(S(2)*q + S(3)) + S(2)*c*f*x*(q + S(1)))/(S(2)*f**S(2)*(q + S(1))*(S(2)*q + S(3))), x) def replacement531(a, b, c, d, e, f, p, q, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(b*e*q + S(2)*c*d*(S(2)*p + S(3)) + S(2)*c*f*x**S(2)*(S(2)*p + S(2)*q + S(3)) + x*(S(2)*b*f*q + S(2)*c*e*(S(2)*p + q + S(3))), x), x), x) + Simp((b + S(2)*c*x)*(a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement532(a, b, c, d, f, p, q, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + f*x**S(2))**(q + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(S(2)*b*f*q*x + S(2)*c*d*(S(2)*p + S(3)) + S(2)*c*f*x**S(2)*(S(2)*p + S(2)*q + S(3)), x), x), x) + Simp((b + S(2)*c*x)*(d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement533(a, c, d, e, f, p, q, x): return -Dist(-S(1)/(S(4)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(S(2)*c*d*(S(2)*p + S(3)) + S(2)*c*e*x*(S(2)*p + q + S(3)) + S(2)*c*f*x**S(2)*(S(2)*p + S(2)*q + S(3)), x), x), x) + Simp(-x*(a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q/(S(2)*a*(p + S(1))), x) def replacement534(a, b, c, d, e, f, p, q, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + S(2)*c*(p + S(1))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2)) - e*(p + q + S(2))*(-S(2)*a*c**S(2)*e - b**S(3)*f + b**S(2)*c*e - b*c*(-S(3)*a*f + c*d)) + x*(S(2)*f*(p + q + S(2))*(S(2)*a*c**S(2)*e + b**S(3)*f - b**S(2)*c*e + b*c*(-S(3)*a*f + c*d)) - (b*f*(p + S(1)) - c*e*(S(2)*p + q + S(4)))*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e))) - (a*f*(p + S(1)) - c*d*(p + S(2)))*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(1))*(S(2)*a*c**S(2)*e + b**S(3)*f - b**S(2)*c*e + b*c*(-S(3)*a*f + c*d) + c*x*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)))/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), x) def replacement535(a, b, c, d, f, p, q, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))*Simp(c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d) + S(2)*c*(p + S(1))*(b**S(2)*d*f + (-a*f + c*d)**S(2)) + x*(-b*f*(p + S(1))*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d) + S(2)*f*(b**S(3)*f + b*c*(-S(3)*a*f + c*d))*(p + q + S(2))) - (a*f*(p + S(1)) - c*d*(p + S(2)))*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d), x), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(b**S(3)*f + b*c*(-S(3)*a*f + c*d) + c*x*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d))/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), x) def replacement536(a, c, d, e, f, p, q, x): return -Dist(-S(1)/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(S(2)*a*c**S(2)*e**S(2)*(p + q + S(2)) + c*f*x**S(2)*(-S(2)*a*c*f + S(2)*c**S(2)*d)*(S(2)*p + S(2)*q + S(5)) + S(2)*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2)) + x*(S(4)*a*c**S(2)*e*f*(p + q + S(2)) + c*e*(-S(2)*a*c*f + S(2)*c**S(2)*d)*(S(2)*p + q + S(4))) - (-S(2)*a*c*f + S(2)*c**S(2)*d)*(a*f*(p + S(1)) - c*d*(p + S(2))), x), x), x) + Simp(-(a + c*x**S(2))**(p + S(1))*(S(2)*a*c**S(2)*e + c*x*(-S(2)*a*c*f + S(2)*c**S(2)*d))*(d + e*x + f*x**S(2))**(q + S(1))/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), x) def replacement537(a, b, c, d, e, f, p, q, x): return -Dist(S(1)/(S(2)*f**S(2)*(p + q)*(S(2)*p + S(2)*q + S(1))), Int((a + b*x + c*x**S(2))**(p + S(-2))*(d + e*x + f*x**S(2))**q*Simp(x**S(2)*(c*(p + q)*(-c*(S(2)*d*f*(S(1) - S(2)*p) + e**S(2)*(S(3)*p + q + S(-1))) + f*(-S(2)*a*f + b*e)*(S(4)*p + S(2)*q + S(-1))) + p*(S(1) - p)*(-b*f + c*e)**S(2)) + x*(S(2)*(S(1) - p)*(S(2)*p + q)*(-a*f + c*d)*(-b*f + c*e) - (p + q)*(b*(c*(S(2)*p + q)*(-S(4)*d*f + e**S(2)) + f*(S(2)*p + S(2)*q + S(1))*(S(2)*a*f - b*e + S(2)*c*d)) + e*f*(S(1) - p)*(-S(4)*a*c + b**S(2)))) + (S(1) - p)*(S(2)*p + q)*(-a*e + b*d)*(-b*f + c*e) - (p + q)*(-a*(c*(S(2)*d*f - e**S(2)*(S(2)*p + q)) + f*(-S(2)*a*f + b*e)*(S(2)*p + S(2)*q + S(1))) + b**S(2)*d*f*(S(1) - p)), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(-1))*(d + e*x + f*x**S(2))**(q + S(1))*(b*f*(S(3)*p + S(2)*q) - c*e*(S(2)*p + q) + S(2)*c*f*x*(p + q))/(S(2)*f**S(2)*(p + q)*(S(2)*p + S(2)*q + S(1))), x) def replacement538(a, b, c, d, f, p, q, x): return -Dist(S(1)/(S(2)*f*(p + q)*(S(2)*p + S(2)*q + S(1))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(-2))*Simp(b**S(2)*d*(p + S(-1))*(S(2)*p + q) + x**S(2)*(b**S(2)*f*p*(S(1) - p) + S(2)*c*(p + q)*(-a*f*(S(4)*p + S(2)*q + S(-1)) + c*d*(S(2)*p + S(-1)))) - x*(S(2)*b*(S(1) - p)*(S(2)*p + q)*(-a*f + c*d) - S(2)*b*(p + q)*(S(2)*c*d*(S(2)*p + q) - (a*f + c*d)*(S(2)*p + S(2)*q + S(1)))) - (p + q)*(-S(2)*a*(-a*f*(S(2)*p + S(2)*q + S(1)) + c*d) + b**S(2)*d*(S(1) - p)), x), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(b*(S(3)*p + S(2)*q) + S(2)*c*x*(p + q))*(a + b*x + c*x**S(2))**(p + S(-1))/(S(2)*f*(p + q)*(S(2)*p + S(2)*q + S(1))), x) def replacement539(a, c, d, e, f, p, q, x): return -Dist(S(1)/(S(2)*f**S(2)*(p + q)*(S(2)*p + S(2)*q + S(1))), Int((a + c*x**S(2))**(p + S(-2))*(d + e*x + f*x**S(2))**q*Simp(-a*c*e**S(2)*(S(1) - p)*(S(2)*p + q) + a*(p + q)*(-S(2)*a*f**S(2)*(S(2)*p + S(2)*q + S(1)) + c*(S(2)*d*f - e**S(2)*(S(2)*p + q))) + x**S(2)*(c**S(2)*e**S(2)*p*(S(1) - p) - c*(p + q)*(S(2)*a*f**S(2)*(S(4)*p + S(2)*q + S(-1)) + c*(S(2)*d*f*(S(1) - S(2)*p) + e**S(2)*(S(3)*p + q + S(-1))))) + x*(S(4)*a*c*e*f*(S(1) - p)*(p + q) + S(2)*c*e*(S(1) - p)*(S(2)*p + q)*(-a*f + c*d)), x), x), x) - Simp(c*(a + c*x**S(2))**(p + S(-1))*(e*(S(2)*p + q) - S(2)*f*x*(p + q))*(d + e*x + f*x**S(2))**(q + S(1))/(S(2)*f**S(2)*(p + q)*(S(2)*p + S(2)*q + S(1))), x) def With540(a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement540(a, b, c, d, e, f, x): q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) return Dist(S(1)/q, Int((-a*c*f + b**S(2)*f - b*c*e + c**S(2)*d - x*(-b*c*f + c**S(2)*e))/(a + b*x + c*x**S(2)), x), x) + Dist(S(1)/q, Int((a*f**S(2) - b*e*f - c*d*f + c*e**S(2) + x*(-b*f**S(2) + c*e*f))/(d + e*x + f*x**S(2)), x), x) def With541(a, b, c, d, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement541(a, b, c, d, f, x): q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) return -Dist(S(1)/q, Int((-a*f**S(2) + b*f**S(2)*x + c*d*f)/(d + f*x**S(2)), x), x) + Dist(S(1)/q, Int((-a*c*f + b**S(2)*f + b*c*f*x + c**S(2)*d)/(a + b*x + c*x**S(2)), x), x) def replacement542(a, b, c, d, e, f, x): return Dist(-S(2)*e, Subst(Int(S(1)/(e*(-S(4)*a*f + b*e) - x**S(2)*(-a*e + b*d)), x), x, (e + S(2)*f*x)/sqrt(d + e*x + f*x**S(2))), x) def With543(a, b, c, d, e, f, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/((b + S(2)*c*x - q)*sqrt(d + e*x + f*x**S(2))), x), x) - Dist(S(2)*c/q, Int(S(1)/((b + S(2)*c*x + q)*sqrt(d + e*x + f*x**S(2))), x), x) def replacement544(a, c, d, e, f, x): return Dist(S(1)/2, Int(S(1)/((a - x*Rt(-a*c, S(2)))*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(S(1)/2, Int(S(1)/((a + x*Rt(-a*c, S(2)))*sqrt(d + e*x + f*x**S(2))), x), x) def With545(a, b, c, d, f, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/(sqrt(d + f*x**S(2))*(b + S(2)*c*x - q)), x), x) - Dist(S(2)*c/q, Int(S(1)/(sqrt(d + f*x**S(2))*(b + S(2)*c*x + q)), x), x) def With546(a, b, c, d, e, f, x): q = Rt(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2), S(2)) return -Dist(S(1)/(S(2)*q), Int((-a*f + c*d - q + x*(-b*f + c*e))/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(S(1)/(S(2)*q), Int((-a*f + c*d + q + x*(-b*f + c*e))/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) def With547(a, c, d, e, f, x): q = Rt(a*c*e**S(2) + (-a*f + c*d)**S(2), S(2)) return -Dist(S(1)/(S(2)*q), Int((-a*f + c*d + c*e*x - q)/((a + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(S(1)/(S(2)*q), Int((-a*f + c*d + c*e*x + q)/((a + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) def With548(a, b, c, d, f, x): q = Rt(b**S(2)*d*f + (-a*f + c*d)**S(2), S(2)) return -Dist(S(1)/(S(2)*q), Int((-a*f - b*f*x + c*d - q)/(sqrt(d + f*x**S(2))*(a + b*x + c*x**S(2))), x), x) + Dist(S(1)/(S(2)*q), Int((-a*f - b*f*x + c*d + q)/(sqrt(d + f*x**S(2))*(a + b*x + c*x**S(2))), x), x) def replacement549(a, b, c, d, e, f, x): return -Dist(S(1)/f, Int((-a*f + c*d + x*(-b*f + c*e))/(sqrt(a + b*x + c*x**S(2))*(d + e*x + f*x**S(2))), x), x) + Dist(c/f, Int(S(1)/sqrt(a + b*x + c*x**S(2)), x), x) def replacement550(a, b, c, d, f, x): return -Dist(S(1)/f, Int((-a*f - b*f*x + c*d)/((d + f*x**S(2))*sqrt(a + b*x + c*x**S(2))), x), x) + Dist(c/f, Int(S(1)/sqrt(a + b*x + c*x**S(2)), x), x) def replacement551(a, c, d, e, f, x): return -Dist(S(1)/f, Int((-a*f + c*d + c*e*x)/(sqrt(a + c*x**S(2))*(d + e*x + f*x**S(2))), x), x) + Dist(c/f, Int(S(1)/sqrt(a + c*x**S(2)), x), x) def With552(a, b, c, d, e, f, x): r = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(sqrt(S(2)*a + x*(b + r))*sqrt(b + S(2)*c*x + r)/sqrt(a + b*x + c*x**S(2)), Int(S(1)/(sqrt(S(2)*a + x*(b + r))*sqrt(b + S(2)*c*x + r)*sqrt(d + e*x + f*x**S(2))), x), x) def With553(a, b, c, d, f, x): r = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(sqrt(S(2)*a + x*(b + r))*sqrt(b + S(2)*c*x + r)/sqrt(a + b*x + c*x**S(2)), Int(S(1)/(sqrt(S(2)*a + x*(b + r))*sqrt(d + f*x**S(2))*sqrt(b + S(2)*c*x + r)), x), x) def replacement554(a, b, c, d, e, f, p, q, x): return Int((a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x) def replacement555(a, c, d, e, f, p, q, x): return Int((a + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x) def replacement556(a, b, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement557(a, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement558(a, b, c, d, e, f, g, h, m, p, q, x): return Dist((c/f)**p, Int((g + h*x)**m*(d + e*x + f*x**S(2))**(p + q), x), x) def replacement559(a, b, c, d, e, f, g, h, m, p, q, x): return Dist(a**IntPart(p)*d**(-IntPart(p))*(a + b*x + c*x**S(2))**FracPart(p)*(d + e*x + f*x**S(2))**(-FracPart(p)), Int((g + h*x)**m*(d + e*x + f*x**S(2))**(p + q), x), x) def replacement560(a, b, c, d, e, f, g, h, m, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b + S(2)*c*x)**(S(2)*p)*(g + h*x)**m*(d + e*x + f*x**S(2))**q, x), x) def replacement561(a, b, c, d, f, g, h, m, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b + S(2)*c*x)**(S(2)*p)*(d + f*x**S(2))**q*(g + h*x)**m, x), x) def replacement562(a, b, c, d, e, f, g, h, m, p, x): return Int((f*h*x/c + d*g/a)**m*(a + b*x + c*x**S(2))**(m + p), x) def replacement563(a, c, d, e, f, g, h, m, p, x): return Int((a + c*x**S(2))**(m + p)*(f*h*x/c + d*g/a)**m, x) def replacement564(a, b, c, d, f, g, h, m, p, x): return Int((f*h*x/c + d*g/a)**m*(a + b*x + c*x**S(2))**(m + p), x) def replacement565(a, c, d, f, g, h, m, p, x): return Int((a + c*x**S(2))**(m + p)*(f*h*x/c + d*g/a)**m, x) def replacement566(a, b, c, e, f, p, q, x): return Int((a/e + c*x/f)**p*(e*x + f*x**S(2))**(p + q), x) def replacement567(a, c, e, f, p, q, x): return Int((a/e + c*x/f)**p*(e*x + f*x**S(2))**(p + q), x) def replacement568(a, b, c, d, e, f, g, h, m, p, x): return Simp(f*(g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*h*(m + S(2)*p + S(3))), x) def replacement569(a, c, d, e, f, g, h, m, p, x): return Simp(f*(a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(1))/(c*h*(m + S(2)*p + S(3))), x) def replacement570(a, b, c, d, f, g, h, m, p, x): return Simp(f*(g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*h*(m + S(2)*p + S(3))), x) def replacement571(a, b, c, d, e, f, g, h, m, p, x): return Int(ExpandIntegrand((g + h*x)**m*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2)), x), x) def replacement572(a, c, d, e, f, g, h, m, p, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(g + h*x)**m*(d + e*x + f*x**S(2)), x), x) def replacement573(a, b, c, d, f, g, h, m, p, x): return Int(ExpandIntegrand((d + f*x**S(2))*(g + h*x)**m*(a + b*x + c*x**S(2))**p, x), x) def replacement574(a, c, d, f, g, h, m, p, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(d + f*x**S(2))*(g + h*x)**m, x), x) def replacement575(a, b, c, d, e, f, g, h, m, p, x): return Dist(S(1)/(h*(m + S(1))*(a*h**S(2) - b*g*h + c*g**S(2))), Int((g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*Simp(-b*(f*g**S(2)*(p + S(1)) - h*(-d*h*(m + p + S(2)) + e*g*(p + S(1)))) + h*(m + S(1))*(a*e*h - a*f*g + c*d*g) - x*(c*(S(2)*f*g**S(2)*(p + S(1)) - h*(-d*h + e*g)*(m + S(2)*p + S(3))) + f*h*(m + S(1))*(-a*h + b*g)), x), x), x) + Simp((g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(d*h**S(2) - e*g*h + f*g**S(2))/(h*(m + S(1))*(a*h**S(2) - b*g*h + c*g**S(2))), x) def replacement576(a, c, d, e, f, g, h, m, p, x): return Dist(S(1)/(h*(m + S(1))*(a*h**S(2) + c*g**S(2))), Int((a + c*x**S(2))**p*(g + h*x)**(m + S(1))*Simp(h*(m + S(1))*(a*e*h - a*f*g + c*d*g) + x*(a*f*h**S(2)*(m + S(1)) - c*(S(2)*f*g**S(2)*(p + S(1)) - h*(-d*h + e*g)*(m + S(2)*p + S(3)))), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(1))*(d*h**S(2) - e*g*h + f*g**S(2))/(h*(m + S(1))*(a*h**S(2) + c*g**S(2))), x) def replacement577(a, b, c, d, f, g, h, m, p, x): return Dist(S(1)/(h*(m + S(1))*(a*h**S(2) - b*g*h + c*g**S(2))), Int((g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**p*Simp(-b*(d*h**S(2)*(m + p + S(2)) + f*g**S(2)*(p + S(1))) + h*(m + S(1))*(-a*f*g + c*d*g) - x*(c*(d*h**S(2)*(m + S(2)*p + S(3)) + S(2)*f*g**S(2)*(p + S(1))) + f*h*(m + S(1))*(-a*h + b*g)), x), x), x) + Simp((g + h*x)**(m + S(1))*(d*h**S(2) + f*g**S(2))*(a + b*x + c*x**S(2))**(p + S(1))/(h*(m + S(1))*(a*h**S(2) - b*g*h + c*g**S(2))), x) def replacement578(a, c, d, f, g, h, m, p, x): return Dist(S(1)/(h*(m + S(1))*(a*h**S(2) + c*g**S(2))), Int((a + c*x**S(2))**p*(g + h*x)**(m + S(1))*Simp(h*(m + S(1))*(-a*f*g + c*d*g) + x*(a*f*h**S(2)*(m + S(1)) - c*(d*h**S(2)*(m + S(2)*p + S(3)) + S(2)*f*g**S(2)*(p + S(1)))), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(1))*(d*h**S(2) + f*g**S(2))/(h*(m + S(1))*(a*h**S(2) + c*g**S(2))), x) def replacement579(a, b, c, d, e, f, g, h, x): return Dist((d*h**S(2) - e*g*h + f*g**S(2))/(a*h**S(2) - b*g*h + c*g**S(2)), Int(S(1)/((g + h*x)*sqrt(a + b*x + c*x**S(2))), x), x) + Dist(S(1)/(a*h**S(2) - b*g*h + c*g**S(2)), Int((a*e*h - a*f*g - b*d*h + c*d*g + x*(a*f*h - b*f*g - c*d*h + c*e*g))/(a + b*x + c*x**S(2))**(S(3)/2), x), x) def replacement580(a, c, d, e, f, g, h, x): return Dist((d*h**S(2) - e*g*h + f*g**S(2))/(a*h**S(2) + c*g**S(2)), Int(S(1)/(sqrt(a + c*x**S(2))*(g + h*x)), x), x) + Dist(S(1)/(a*h**S(2) + c*g**S(2)), Int((a*e*h - a*f*g + c*d*g + x*(a*f*h - c*d*h + c*e*g))/(a + c*x**S(2))**(S(3)/2), x), x) def replacement581(a, b, c, d, f, g, h, x): return Dist((d*h**S(2) + f*g**S(2))/(a*h**S(2) - b*g*h + c*g**S(2)), Int(S(1)/((g + h*x)*sqrt(a + b*x + c*x**S(2))), x), x) + Dist(S(1)/(a*h**S(2) - b*g*h + c*g**S(2)), Int((-a*f*g - b*d*h + c*d*g - x*(-a*f*h + b*f*g + c*d*h))/(a + b*x + c*x**S(2))**(S(3)/2), x), x) def replacement582(a, c, d, f, g, h, x): return Dist((d*h**S(2) + f*g**S(2))/(a*h**S(2) + c*g**S(2)), Int(S(1)/(sqrt(a + c*x**S(2))*(g + h*x)), x), x) + Dist(S(1)/(a*h**S(2) + c*g**S(2)), Int((-a*f*g + c*d*g - x*(-a*f*h + c*d*h))/(a + c*x**S(2))**(S(3)/2), x), x) def replacement583(a, b, c, d, e, f, g, h, m, p, x): return -Dist(S(1)/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((g + h*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(g*(c*(S(2)*p + S(3))*(-b*e + S(2)*c*d) - f*(S(2)*a*c - b**S(2)*(p + S(2)))) + h*m*(a*b*f - S(2)*a*c*e + b*c*d) + h*x*(c*(-b*e + S(2)*c*d)*(m + S(2)*p + S(3)) - f*(S(2)*a*c*(m + S(1)) - b**S(2)*(m + p + S(2)))), x), x), x) + Simp((g + h*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*(a*b*f - S(2)*a*c*e + b*c*d + x*(c*(-b*e + S(2)*c*d) + f*(-S(2)*a*c + b**S(2))))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement584(a, c, d, e, f, g, h, m, p, x): return -Dist(S(1)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(-1))*Simp(a*(e*h*m + f*g) - c*d*g*(S(2)*p + S(3)) + h*x*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3))), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(g + h*x)**m*(a*e - x*(-a*f + c*d))/(S(2)*a*c*(p + S(1))), x) def replacement585(a, b, c, d, f, g, h, m, p, x): return -Dist(S(1)/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((g + h*x)**(m + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(g*(S(2)*c**S(2)*d*(S(2)*p + S(3)) - f*(S(2)*a*c - b**S(2)*(p + S(2)))) + h*m*(a*b*f + b*c*d) + h*x*(S(2)*c**S(2)*d*(m + S(2)*p + S(3)) - f*(S(2)*a*c*(m + S(1)) - b**S(2)*(m + p + S(2)))), x), x), x) + Simp((g + h*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*(a*b*f + b*c*d + x*(S(2)*c**S(2)*d + f*(-S(2)*a*c + b**S(2))))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement586(a, c, d, f, g, h, m, p, x): return -Dist(S(1)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(-1))*Simp(a*f*g - c*d*g*(S(2)*p + S(3)) + h*x*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3))), x), x), x) - Simp(x*(a + c*x**S(2))**(p + S(1))*(g + h*x)**m*(-a*f + c*d)/(S(2)*a*c*(p + S(1))), x) def replacement587(a, b, c, d, e, f, g, h, m, p, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(c*g**S(2) - h*(-a*h + b*g))), Int((g + h*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*Simp(g*(p + S(2))*(-S(2)*a*(-c*e*h + c*f*g) + b**S(2)*f*g - b*(a*f*h + c*d*h + c*e*g) + S(2)*c**S(2)*d*g) + h*x*(m + S(2)*p + S(4))*(-S(2)*a*(-c*e*h + c*f*g) + b**S(2)*f*g - b*(a*f*h + c*d*h + c*e*g) + S(2)*c**S(2)*d*g) - h*(-(-a*e + b*d)*(-b*h + S(2)*c*g) + (-a*f + c*d)*(-S(2)*a*h + b*g))*(m + p + S(2)) + (p + S(1))*(c*g**S(2) - h*(-a*h + b*g))*(S(2)*a*f - b*e + S(2)*c*d), x), x), x) - Simp((g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(-x*(b*f*(-a*h + b*g) + S(2)*c**S(2)*d*g - c*(-S(2)*a*e*h + S(2)*a*f*g + b*d*h + b*e*g)) - (-a*e + b*d)*(-b*h + S(2)*c*g) + (-a*f + c*d)*(-S(2)*a*h + b*g))/((p + S(1))*(-S(4)*a*c + b**S(2))*(c*g**S(2) - h*(-a*h + b*g))), x) def replacement588(a, c, d, e, f, g, h, m, p, x): return Dist(S(1)/(S(2)*a*c*(p + S(1))*(a*h**S(2) + c*g**S(2))), Int((a + c*x**S(2))**(p + S(1))*(g + h*x)**m*Simp(g*(p + S(2))*(-a*(-c*e*h + c*f*g) + c**S(2)*d*g) + h*x*(-a*(-c*e*h + c*f*g) + c**S(2)*d*g)*(m + S(2)*p + S(4)) - h*(a*c*e*g - a*h*(-a*f + c*d))*(m + p + S(2)) + (p + S(1))*(a*f + c*d)*(a*h**S(2) + c*g**S(2)), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(1))*(a*c*e*g - a*h*(-a*f + c*d) - c*x*(a*e*h - a*f*g + c*d*g))/(S(2)*a*c*(p + S(1))*(a*h**S(2) + c*g**S(2))), x) def replacement589(a, b, c, d, f, g, h, m, p, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(c*g**S(2) - h*(-a*h + b*g))), Int((g + h*x)**m*(a + b*x + c*x**S(2))**(p + S(1))*Simp(g*(p + S(2))*(-S(2)*a*c*f*g + b**S(2)*f*g - b*(a*f*h + c*d*h) + S(2)*c**S(2)*d*g) + h*x*(m + S(2)*p + S(4))*(-S(2)*a*c*f*g + b**S(2)*f*g - b*(a*f*h + c*d*h) + S(2)*c**S(2)*d*g) - h*(-b*d*(-b*h + S(2)*c*g) + (-a*f + c*d)*(-S(2)*a*h + b*g))*(m + p + S(2)) + S(2)*(p + S(1))*(a*f + c*d)*(c*g**S(2) - h*(-a*h + b*g)), x), x), x) - Simp((g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(-b*d*(-b*h + S(2)*c*g) - x*(b*f*(-a*h + b*g) + S(2)*c**S(2)*d*g - c*(S(2)*a*f*g + b*d*h)) + (-a*f + c*d)*(-S(2)*a*h + b*g))/((p + S(1))*(-S(4)*a*c + b**S(2))*(c*g**S(2) - h*(-a*h + b*g))), x) def replacement590(a, c, d, f, g, h, m, p, x): return Dist(S(1)/(S(2)*a*c*(p + S(1))*(a*h**S(2) + c*g**S(2))), Int((a + c*x**S(2))**(p + S(1))*(g + h*x)**m*Simp(a*h**S(2)*(-a*f + c*d)*(m + p + S(2)) + g*(p + S(2))*(-a*c*f*g + c**S(2)*d*g) + h*x*(-a*c*f*g + c**S(2)*d*g)*(m + S(2)*p + S(4)) + (p + S(1))*(a*f + c*d)*(a*h**S(2) + c*g**S(2)), x), x), x) - Simp((a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(1))*(a*h*(-a*f + c*d) + c*x*(-a*f*g + c*d*g))/(S(2)*a*c*(p + S(1))*(a*h**S(2) + c*g**S(2))), x) def replacement591(a, b, c, d, e, f, g, h, m, p, x): return -Dist(h**(S(-2)), Int((g + h*x)**m*(a + b*x + c*x**S(2))**p*(-d*h**S(2) + f*g**S(2) + h*x*(-e*h + S(2)*f*g)), x), x) + Dist(f/h**S(2), Int((g + h*x)**(m + S(2))*(a + b*x + c*x**S(2))**p, x), x) def replacement592(a, c, d, e, f, g, h, m, p, x): return -Dist(h**(S(-2)), Int((a + c*x**S(2))**p*(g + h*x)**m*(-d*h**S(2) + f*g**S(2) + h*x*(-e*h + S(2)*f*g)), x), x) + Dist(f/h**S(2), Int((a + c*x**S(2))**p*(g + h*x)**(m + S(2)), x), x) def replacement593(a, b, c, d, f, g, h, m, p, x): return -Dist(h**(S(-2)), Int((g + h*x)**m*(a + b*x + c*x**S(2))**p*(-d*h**S(2) + f*g**S(2) + S(2)*f*g*h*x), x), x) + Dist(f/h**S(2), Int((g + h*x)**(m + S(2))*(a + b*x + c*x**S(2))**p, x), x) def replacement594(a, c, d, f, g, h, m, p, x): return -Dist(h**(S(-2)), Int((a + c*x**S(2))**p*(g + h*x)**m*(-d*h**S(2) + f*g**S(2) + S(2)*f*g*h*x), x), x) + Dist(f/h**S(2), Int((a + c*x**S(2))**p*(g + h*x)**(m + S(2)), x), x) def replacement595(a, b, c, d, e, f, g, h, m, p, x): return -Dist(S(1)/(c*h*(m + S(2)*p + S(3))), Int((g + h*x)**m*(a + b*x + c*x**S(2))**p*Simp(b*f*g*(p + S(1)) + h*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3))) + x*(b*f*h*(m + p + S(2)) + c*(-e*h*(m + S(2)*p + S(3)) + S(2)*f*g*(p + S(1)))), x), x), x) + Simp(f*(g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*h*(m + S(2)*p + S(3))), x) def replacement596(a, c, d, e, f, g, h, m, p, x): return -Dist(S(1)/(c*h*(m + S(2)*p + S(3))), Int((a + c*x**S(2))**p*(g + h*x)**m*Simp(c*x*(-e*h*(m + S(2)*p + S(3)) + S(2)*f*g*(p + S(1))) + h*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3))), x), x), x) + Simp(f*(a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(1))/(c*h*(m + S(2)*p + S(3))), x) def replacement597(a, b, c, d, f, g, h, m, p, x): return -Dist(S(1)/(c*h*(m + S(2)*p + S(3))), Int((g + h*x)**m*(a + b*x + c*x**S(2))**p*Simp(b*f*g*(p + S(1)) + f*x*(b*h*(m + p + S(2)) + S(2)*c*g*(p + S(1))) + h*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3))), x), x), x) + Simp(f*(g + h*x)**(m + S(1))*(a + b*x + c*x**S(2))**(p + S(1))/(c*h*(m + S(2)*p + S(3))), x) def replacement598(a, c, d, f, g, h, m, p, x): return -Dist(S(1)/(c*h*(m + S(2)*p + S(3))), Int((a + c*x**S(2))**p*(g + h*x)**m*Simp(S(2)*c*f*g*x*(p + S(1)) + h*(a*f*(m + S(1)) - c*d*(m + S(2)*p + S(3))), x), x), x) + Simp(f*(a + c*x**S(2))**(p + S(1))*(g + h*x)**(m + S(1))/(c*h*(m + S(2)*p + S(3))), x) def replacement599(a, b, c, d, e, f, g, h, p, q, x): return Int(ExpandIntegrand((g + h*x)*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x) def replacement600(a, c, d, e, f, g, h, p, q, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(g + h*x)*(d + e*x + f*x**S(2))**q, x), x) def replacement601(a, b, c, d, e, f, g, h, p, q, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(-d*(S(2)*p + S(3))*(b*h - S(2)*c*g) + e*q*(-S(2)*a*h + b*g) - f*x**S(2)*(b*h - S(2)*c*g)*(S(2)*p + S(2)*q + S(3)) + x*(-e*(b*h - S(2)*c*g)*(S(2)*p + q + S(3)) + S(2)*f*q*(-S(2)*a*h + b*g)), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*(-S(2)*a*h + b*g - x*(b*h - S(2)*c*g))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement602(a, c, d, e, f, g, h, p, q, x): return Dist(S(1)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(-a*e*h*q + c*d*g*(S(2)*p + S(3)) + c*f*g*x**S(2)*(S(2)*p + S(2)*q + S(3)) + x*(-S(2)*a*f*h*q + c*e*g*(S(2)*p + q + S(3))), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(a*h - c*g*x)*(d + e*x + f*x**S(2))**q/(S(2)*a*c*(p + S(1))), x) def replacement603(a, b, c, d, f, g, h, p, q, x): return -Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + f*x**S(2))**(q + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-d*(S(2)*p + S(3))*(b*h - S(2)*c*g) + S(2)*f*q*x*(-S(2)*a*h + b*g) - f*x**S(2)*(b*h - S(2)*c*g)*(S(2)*p + S(2)*q + S(3)), x), x), x) + Simp((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))*(-S(2)*a*h + b*g - x*(b*h - S(2)*c*g))/((p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement604(a, b, c, d, e, f, g, h, p, q, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(-c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(S(2)*a*c*e*h + b**S(2)*f*g - b*(a*f*h + c*d*h + c*e*g) + S(2)*c*g*(-a*f + c*d)) - e*(c*g*(S(2)*a*c*e - b*(a*f + c*d)) + (-a*h + b*g)*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)))*(p + q + S(2)) - x*(S(2)*f*(c*g*(S(2)*a*c*e - b*(a*f + c*d)) + (-a*h + b*g)*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)))*(p + q + S(2)) - (b*f*(p + S(1)) - c*e*(S(2)*p + q + S(4)))*(S(2)*a*c*e*h + b**S(2)*f*g - b*(a*f*h + c*d*h + c*e*g) + S(2)*c*g*(-a*f + c*d))) + (p + S(1))*(b*h - S(2)*c*g)*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2)) + (a*f*(p + S(1)) - c*d*(p + S(2)))*(S(2)*a*c*e*h + b**S(2)*f*g - b*(a*f*h + c*d*h + c*e*g) + S(2)*c*g*(-a*f + c*d)), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(1))*(c*g*(S(2)*a*c*e - b*(a*f + c*d)) + c*x*(g*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) - h*(a*b*f - S(2)*a*c*e + b*c*d)) + (-a*h + b*g)*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)))/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), x) def replacement605(a, c, d, e, f, g, h, p, q, x): return Dist(-S(1)/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(-c*f*x**S(2)*(S(2)*a*c*e*h + S(2)*c*g*(-a*f + c*d))*(S(2)*p + S(2)*q + S(5)) - S(2)*c*g*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2)) - e*(S(2)*a*c**S(2)*e*g - a*h*(-S(2)*a*c*f + S(2)*c**S(2)*d))*(p + q + S(2)) - x*(c*e*(S(2)*a*c*e*h + S(2)*c*g*(-a*f + c*d))*(S(2)*p + q + S(4)) + S(2)*f*(S(2)*a*c**S(2)*e*g - a*h*(-S(2)*a*c*f + S(2)*c**S(2)*d))*(p + q + S(2))) + (a*f*(p + S(1)) - c*d*(p + S(2)))*(S(2)*a*c*e*h + S(2)*c*g*(-a*f + c*d)), x), x), x) + Simp(-(a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(1))*(S(2)*a*c**S(2)*e*g - a*h*(-S(2)*a*c*f + S(2)*c**S(2)*d) + c*x*(S(2)*a*c*e*h + g*(-S(2)*a*c*f + S(2)*c**S(2)*d)))/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), x) def replacement606(a, b, c, d, f, g, h, p, q, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(b**S(2)*f*g - b*(a*f*h + c*d*h) + S(2)*c*g*(-a*f + c*d)) - x*(-b*f*(p + S(1))*(b**S(2)*f*g - b*(a*f*h + c*d*h) + S(2)*c*g*(-a*f + c*d)) + S(2)*f*(-b*c*g*(a*f + c*d) + (-a*h + b*g)*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d))*(p + q + S(2))) + (p + S(1))*(b*h - S(2)*c*g)*(b**S(2)*d*f + (-a*f + c*d)**S(2)) + (a*f*(p + S(1)) - c*d*(p + S(2)))*(b**S(2)*f*g - b*(a*f*h + c*d*h) + S(2)*c*g*(-a*f + c*d)), x), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(-b*c*g*(a*f + c*d) + c*x*(g*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d) - h*(a*b*f + b*c*d)) + (-a*h + b*g)*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d))/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), x) def replacement607(a, b, c, d, e, f, g, h, p, q, x): return -Dist(S(1)/(S(2)*f*(p + q + S(1))), Int((a + b*x + c*x**S(2))**(p + S(-1))*(d + e*x + f*x**S(2))**q*Simp(a*(e*h - S(2)*f*g)*(p + q + S(1)) + h*p*(-a*e + b*d) + x**S(2)*(c*(e*h - S(2)*f*g)*(p + q + S(1)) + h*p*(-b*f + c*e)) + x*(b*(e*h - S(2)*f*g)*(p + q + S(1)) + S(2)*h*p*(-a*f + c*d)), x), x), x) + Simp(h*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**(q + S(1))/(S(2)*f*(p + q + S(1))), x) def replacement608(a, c, d, e, f, g, h, p, q, x): return Dist(S(1)/(S(2)*f*(p + q + S(1))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x + f*x**S(2))**q*Simp(a*e*h*p - a*(e*h - S(2)*f*g)*(p + q + S(1)) - S(2)*h*p*x*(-a*f + c*d) - x**S(2)*(c*e*h*p + c*(e*h - S(2)*f*g)*(p + q + S(1))), x), x), x) + Simp(h*(a + c*x**S(2))**p*(d + e*x + f*x**S(2))**(q + S(1))/(S(2)*f*(p + q + S(1))), x) def replacement609(a, b, c, d, f, g, h, p, q, x): return -Dist(S(1)/(S(2)*f*(p + q + S(1))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(-1))*Simp(-S(2)*a*f*g*(p + q + S(1)) + b*d*h*p + x**S(2)*(-b*f*h*p - S(2)*c*f*g*(p + q + S(1))) + x*(-S(2)*b*f*g*(p + q + S(1)) + S(2)*h*p*(-a*f + c*d)), x), x), x) + Simp(h*(d + f*x**S(2))**(q + S(1))*(a + b*x + c*x**S(2))**p/(S(2)*f*(p + q + S(1))), x) def With610(a, b, c, d, e, f, g, h, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement610(a, b, c, d, e, f, g, h, x): q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) return Dist(S(1)/q, Int(Simp(-a*b*f*h + a*c*e*h - a*c*f*g + b**S(2)*f*g - b*c*e*g + c**S(2)*d*g + c*x*(-a*f*h + b*f*g + c*d*h - c*e*g), x)/(a + b*x + c*x**S(2)), x), x) + Dist(S(1)/q, Int(Simp(a*f**S(2)*g + b*d*f*h - b*e*f*g - c*d*e*h - c*d*f*g + c*e**S(2)*g - f*x*(-a*f*h + b*f*g + c*d*h - c*e*g), x)/(d + e*x + f*x**S(2)), x), x) def With611(a, b, c, d, f, g, h, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement611(a, b, c, d, f, g, h, x): q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) return Dist(S(1)/q, Int(Simp(a*f**S(2)*g + b*d*f*h - c*d*f*g - f*x*(-a*f*h + b*f*g + c*d*h), x)/(d + f*x**S(2)), x), x) + Dist(S(1)/q, Int(Simp(-a*b*f*h - a*c*f*g + b**S(2)*f*g + c**S(2)*d*g + c*x*(-a*f*h + b*f*g + c*d*h), x)/(a + b*x + c*x**S(2)), x), x) def replacement612(a, c, d, f, g, h, x): return Dist(g, Int(S(1)/((a + c*x**S(2))*sqrt(d + f*x**S(2))), x), x) + Dist(h, Int(x/((a + c*x**S(2))*sqrt(d + f*x**S(2))), x), x) def With613(a, c, d, f, g, h, x): q = Rt(-a*c, S(2)) return -Dist((c*g - h*q)/(S(2)*q), Int(S(1)/(sqrt(d + f*x**S(2))*(c*x + q)), x), x) - Dist((c*g + h*q)/(S(2)*q), Int(S(1)/(sqrt(d + f*x**S(2))*(-c*x + q)), x), x) def replacement614(a, b, c, d, e, f, g, h, x): return Dist(-S(2)*g, Subst(Int(S(1)/(-a*e + b*d - b*x**S(2)), x), x, sqrt(d + e*x + f*x**S(2))), x) def replacement615(a, b, c, d, e, f, g, h, x): return Dist(h/(S(2)*f), Int((e + S(2)*f*x)/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) - Dist((e*h - S(2)*f*g)/(S(2)*f), Int(S(1)/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) def replacement616(a, b, c, d, e, f, x): return Dist(-S(2)*e, Subst(Int((-d*x**S(2) + S(1))/(-b*f + c*e + d**S(2)*x**S(4)*(-b*f + c*e) - e*x**S(2)*(S(2)*a*f - b*e + S(2)*c*d)), x), x, (S(1) + x*(e + sqrt(-S(4)*d*f + e**S(2)))/(S(2)*d))/sqrt(d + e*x + f*x**S(2))), x) def replacement617(a, b, c, d, e, f, g, h, x): return Dist(g, Subst(Int(S(1)/(a + x**S(2)*(-a*f + c*d)), x), x, x/sqrt(d + e*x + f*x**S(2))), x) def replacement618(a, b, c, d, e, f, g, h, x): return Dist(h/e, Int((S(2)*d + e*x)/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) - Dist((S(2)*d*h - e*g)/e, Int(S(1)/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) def replacement619(a, b, c, d, e, f, g, h, x): return Dist(-S(2)*g*(-S(2)*a*h + b*g), Subst(Int(S(1)/Simp(g*(-S(4)*a*c + b**S(2))*(-S(2)*a*h + b*g) - x**S(2)*(-a*e + b*d), x), x), x, Simp(-S(2)*a*h + b*g - x*(b*h - S(2)*c*g), x)/sqrt(d + e*x + f*x**S(2))), x) def replacement620(a, c, d, e, f, g, h, x): return Dist(-S(2)*a*g*h, Subst(Int(S(1)/Simp(S(2)*a**S(2)*c*g*h + a*e*x**S(2), x), x), x, Simp(a*h - c*g*x, x)/sqrt(d + e*x + f*x**S(2))), x) def replacement621(a, b, c, d, f, g, h, x): return Dist(-S(2)*g*(-S(2)*a*h + b*g), Subst(Int(S(1)/Simp(-b*d*x**S(2) + g*(-S(4)*a*c + b**S(2))*(-S(2)*a*h + b*g), x), x), x, Simp(-S(2)*a*h + b*g - x*(b*h - S(2)*c*g), x)/sqrt(d + f*x**S(2))), x) def With622(a, b, c, d, e, f, g, h, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist((S(2)*c*g - h*(b - q))/q, Int(S(1)/((b + S(2)*c*x - q)*sqrt(d + e*x + f*x**S(2))), x), x) - Dist((S(2)*c*g - h*(b + q))/q, Int(S(1)/((b + S(2)*c*x + q)*sqrt(d + e*x + f*x**S(2))), x), x) def With623(a, c, d, e, f, g, h, x): q = Rt(-a*c, S(2)) return Dist(-c*g/(S(2)*q) + h/S(2), Int(S(1)/((c*x + q)*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(c*g/(S(2)*q) + h/S(2), Int(S(1)/((c*x - q)*sqrt(d + e*x + f*x**S(2))), x), x) def With624(a, b, c, d, f, g, h, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist((S(2)*c*g - h*(b - q))/q, Int(S(1)/(sqrt(d + f*x**S(2))*(b + S(2)*c*x - q)), x), x) - Dist((S(2)*c*g - h*(b + q))/q, Int(S(1)/(sqrt(d + f*x**S(2))*(b + S(2)*c*x + q)), x), x) def With625(a, b, c, d, e, f, g, h, x): q = Rt(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2), S(2)) return Dist(S(1)/(S(2)*q), Int(Simp(-g*(-a*f + c*d - q) + h*(-a*e + b*d) - x*(g*(-b*f + c*e) - h*(-a*f + c*d + q)), x)/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) - Dist(S(1)/(S(2)*q), Int(Simp(-g*(-a*f + c*d + q) + h*(-a*e + b*d) - x*(g*(-b*f + c*e) - h*(-a*f + c*d - q)), x)/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) def With626(a, c, d, e, f, g, h, x): q = Rt(a*c*e**S(2) + (-a*f + c*d)**S(2), S(2)) return Dist(S(1)/(S(2)*q), Int(Simp(-a*e*h - g*(-a*f + c*d - q) + x*(-c*e*g + h*(-a*f + c*d + q)), x)/((a + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) - Dist(S(1)/(S(2)*q), Int(Simp(-a*e*h - g*(-a*f + c*d + q) + x*(-c*e*g + h*(-a*f + c*d - q)), x)/((a + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) def With627(a, b, c, d, f, g, h, x): q = Rt(b**S(2)*d*f + (-a*f + c*d)**S(2), S(2)) return Dist(S(1)/(S(2)*q), Int(Simp(b*d*h - g*(-a*f + c*d - q) + x*(b*f*g + h*(-a*f + c*d + q)), x)/(sqrt(d + f*x**S(2))*(a + b*x + c*x**S(2))), x), x) - Dist(S(1)/(S(2)*q), Int(Simp(b*d*h - g*(-a*f + c*d + q) + x*(b*f*g + h*(-a*f + c*d - q)), x)/(sqrt(d + f*x**S(2))*(a + b*x + c*x**S(2))), x), x) def With628(a, b, c, d, e, f, g, h, x): s = Rt(-S(4)*a*c + b**S(2), S(2)) t = Rt(-S(4)*d*f + e**S(2), S(2)) return Dist(sqrt(S(2)*a + x*(b + s))*sqrt(S(2)*d + x*(e + t))*sqrt(b + S(2)*c*x + s)*sqrt(e + S(2)*f*x + t)/(sqrt(a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), Int((g + h*x)/(sqrt(S(2)*a + x*(b + s))*sqrt(S(2)*d + x*(e + t))*sqrt(b + S(2)*c*x + s)*sqrt(e + S(2)*f*x + t)), x), x) def With629(a, b, c, d, f, g, h, x): s = Rt(-S(4)*a*c + b**S(2), S(2)) t = Rt(-S(4)*d*f, S(2)) return Dist(sqrt(S(2)*a + x*(b + s))*sqrt(S(2)*d + t*x)*sqrt(S(2)*f*x + t)*sqrt(b + S(2)*c*x + s)/(sqrt(d + f*x**S(2))*sqrt(a + b*x + c*x**S(2))), Int((g + h*x)/(sqrt(S(2)*a + x*(b + s))*sqrt(S(2)*d + t*x)*sqrt(S(2)*f*x + t)*sqrt(b + S(2)*c*x + s)), x), x) def With630(a, b, c, d, e, f, g, h, x): q = S(3)**(S(2)/3)*(-c*h**S(2)/(-b*h + S(2)*c*g)**S(2))**(S(1)/3) return -Simp(S(3)*h*q*log((-S(3)*h*(b + S(2)*c*x)/(-b*h + S(2)*c*g) + S(1))**(S(2)/3) + S(2)**(S(1)/3)*(S(3)*h*(b + S(2)*c*x)/(-b*h + S(2)*c*g) + S(1))**(S(1)/3))/(S(2)*f), x) + Simp(h*q*log(d + e*x + f*x**S(2))/(S(2)*f), x) + Simp(sqrt(S(3))*h*q*ArcTan(-S(2)**(S(2)/3)*sqrt(S(3))*(-S(3)*h*(b + S(2)*c*x)/(-b*h + S(2)*c*g) + S(1))**(S(2)/3)/(S(3)*(S(3)*h*(b + S(2)*c*x)/(-b*h + S(2)*c*g) + S(1))**(S(1)/3)) + sqrt(S(3))/S(3))/f, x) def replacement631(a, c, d, f, g, h, x): return Simp(S(2)**(S(1)/3)*h*log(d + f*x**S(2))/(S(4)*a**(S(1)/3)*f), x) - Simp(S(3)*S(2)**(S(1)/3)*h*log((S(1) - S(3)*h*x/g)**(S(2)/3) + S(2)**(S(1)/3)*(S(1) + S(3)*h*x/g)**(S(1)/3))/(S(4)*a**(S(1)/3)*f), x) + Simp(S(2)**(S(1)/3)*sqrt(S(3))*h*ArcTan(-S(2)**(S(2)/3)*sqrt(S(3))*(S(1) - S(3)*h*x/g)**(S(2)/3)/(S(3)*(S(1) + S(3)*h*x/g)**(S(1)/3)) + sqrt(S(3))/S(3))/(S(2)*a**(S(1)/3)*f), x) def With632(a, b, c, d, e, f, g, h, x): q = -c/(-S(4)*a*c + b**S(2)) return Dist((q*(a + b*x + c*x**S(2)))**(S(1)/3)/(a + b*x + c*x**S(2))**(S(1)/3), Int((g + h*x)/((d + e*x + f*x**S(2))*(a*q + b*q*x + c*q*x**S(2))**(S(1)/3)), x), x) def replacement633(a, c, d, f, g, h, x): return Dist((S(1) + c*x**S(2)/a)**(S(1)/3)/(a + c*x**S(2))**(S(1)/3), Int((g + h*x)/((S(1) + c*x**S(2)/a)**(S(1)/3)*(d + f*x**S(2))), x), x) def replacement634(a, b, c, d, e, f, g, h, p, q, x): return Int((g + h*x)*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x) def replacement635(a, c, d, e, f, g, h, p, q, x): return Int((a + c*x**S(2))**p*(g + h*x)*(d + e*x + f*x**S(2))**q, x) def replacement636(a, b, c, d, e, f, g, h, m, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((g + h*x)**m*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement637(a, c, d, e, f, g, h, m, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + c*x**S(2))**p*(g + h*x)**m*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement638(m, p, q, u, v, x, z): return Int(ExpandToSum(u, x)**p*ExpandToSum(v, x)**q*ExpandToSum(z, x)**m, x) def replacement639(a, b, c, d, e, f, g, h, i, m, n, p, q, x): return Int((h + i*x)**q*(d*f + e*g*x**S(2))**m*(a + b*x + c*x**S(2))**p, x) def replacement640(a, b, c, d, e, f, g, h, i, m, n, p, q, x): return Int(ExpandIntegrand((d + e*x)**m*(f + g*x)**n*(h + i*x)**q*(a + b*x + c*x**S(2))**p, x), x) def replacement641(a, b, c, d, e, f, g, h, i, m, n, p, q, x): return Dist((d + e*x)**FracPart(m)*(f + g*x)**FracPart(m)*(d*f + e*g*x**S(2))**(-FracPart(m)), Int((h + i*x)**q*(d*f + e*g*x**S(2))**m*(a + b*x + c*x**S(2))**p, x), x) def replacement642(A, B, C, a, b, c, d, e, f, p, q, x): return Dist((c/f)**p, Int((A + B*x + C*x**S(2))*(d + e*x + f*x**S(2))**(p + q), x), x) def replacement643(A, C, a, b, c, d, e, f, p, q, x): return Dist((c/f)**p, Int((A + C*x**S(2))*(d + e*x + f*x**S(2))**(p + q), x), x) def replacement644(A, B, C, a, b, c, d, e, f, p, q, x): return Dist(a**IntPart(p)*d**(-IntPart(p))*(a + b*x + c*x**S(2))**FracPart(p)*(d + e*x + f*x**S(2))**(-FracPart(p)), Int((A + B*x + C*x**S(2))*(d + e*x + f*x**S(2))**(p + q), x), x) def replacement645(A, C, a, b, c, d, e, f, p, q, x): return Dist(a**IntPart(p)*d**(-IntPart(p))*(a + b*x + c*x**S(2))**FracPart(p)*(d + e*x + f*x**S(2))**(-FracPart(p)), Int((A + C*x**S(2))*(d + e*x + f*x**S(2))**(p + q), x), x) def replacement646(A, B, C, a, b, c, d, e, f, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b + S(2)*c*x)**(S(2)*p)*(A + B*x + C*x**S(2))*(d + e*x + f*x**S(2))**q, x), x) def replacement647(A, C, a, b, c, d, e, f, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((A + C*x**S(2))*(b + S(2)*c*x)**(S(2)*p)*(d + e*x + f*x**S(2))**q, x), x) def replacement648(A, B, C, a, b, c, d, f, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((b + S(2)*c*x)**(S(2)*p)*(d + f*x**S(2))**q*(A + B*x + C*x**S(2)), x), x) def replacement649(A, C, a, b, c, d, f, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x)**(-S(2)*FracPart(p))*(a + b*x + c*x**S(2))**FracPart(p), Int((A + C*x**S(2))*(b + S(2)*c*x)**(S(2)*p)*(d + f*x**S(2))**q, x), x) def replacement650(A, B, C, a, b, c, d, e, f, p, q, x): return Int(ExpandIntegrand((A + B*x + C*x**S(2))*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x) def replacement651(A, C, a, b, c, d, e, f, p, q, x): return Int(ExpandIntegrand((A + C*x**S(2))*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x) def replacement652(A, B, C, a, c, d, e, f, p, q, x): return Int(ExpandIntegrand((a + c*x**S(2))**p*(A + B*x + C*x**S(2))*(d + e*x + f*x**S(2))**q, x), x) def replacement653(A, C, a, c, d, e, f, p, q, x): return Int(ExpandIntegrand((A + C*x**S(2))*(a + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x) def replacement654(A, B, C, a, b, c, d, e, f, p, q, x): return -Dist(S(1)/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(-d*(C*(S(2)*a*c - b**S(2)*(p + S(2))) + c*(S(2)*p + S(3))*(-S(2)*A*c + B*b)) + e*q*(A*b*c - S(2)*B*a*c + C*a*b) - f*x**S(2)*(C*(S(2)*a*c*(S(2)*q + S(1)) - b**S(2)*(p + S(2)*q + S(2))) + c*(-S(2)*A*c + B*b)*(S(2)*p + S(2)*q + S(3))) + x*(-e*(C*(S(2)*a*c*(q + S(1)) - b**S(2)*(p + q + S(2))) + c*(-S(2)*A*c + B*b)*(S(2)*p + q + S(3))) + S(2)*f*q*(A*b*c - S(2)*B*a*c + C*a*b)), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*(A*b*c - S(2)*B*a*c + C*a*b - x*(-C*(-S(2)*a*c + b**S(2)) + c*(-S(2)*A*c + B*b)))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement655(A, C, a, b, c, d, e, f, p, q, x): return -Dist(S(1)/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(A*c*(b*e*q + S(2)*c*d*(S(2)*p + S(3))) - C*(-a*b*e*q + S(2)*a*c*d - b**S(2)*d*(p + S(2))) - f*x**S(2)*(-S(2)*A*c**S(2)*(S(2)*p + S(2)*q + S(3)) + C*(S(2)*a*c*(S(2)*q + S(1)) - b**S(2)*(p + S(2)*q + S(2)))) + x*(S(2)*A*c*(b*f*q + c*e*(S(2)*p + q + S(3))) + C*(S(2)*a*b*f*q - S(2)*a*c*e*(q + S(1)) + b**S(2)*e*(p + q + S(2)))), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*(A*b*c + C*a*b + x*(S(2)*A*c**S(2) + C*(-S(2)*a*c + b**S(2))))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement656(A, B, C, a, c, d, e, f, p, q, x): return -Dist(-S(1)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(A*c*d*(S(2)*p + S(3)) - a*(B*e*q + C*d) - f*x**S(2)*(-A*c*(S(2)*p + S(2)*q + S(3)) + C*a*(S(2)*q + S(1))) + x*(A*c*e*(S(2)*p + q + S(3)) - a*(S(2)*B*f*q + C*e*(q + S(1)))), x), x), x) + Simp((a + c*x**S(2))**(p + S(1))*(B*a - x*(A*c - C*a))*(d + e*x + f*x**S(2))**q/(S(2)*a*c*(p + S(1))), x) def replacement657(A, C, a, c, d, e, f, p, q, x): return Dist(S(1)/(S(2)*a*c*(p + S(1))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(-1))*Simp(A*c*d*(S(2)*p + S(3)) - C*a*d - f*x**S(2)*(-A*c*(S(2)*p + S(2)*q + S(3)) + C*a*(S(2)*q + S(1))) + x*(A*c*e*(S(2)*p + q + S(3)) - C*a*e*(q + S(1))), x), x), x) - Simp(x*(a + c*x**S(2))**(p + S(1))*(A*c - C*a)*(d + e*x + f*x**S(2))**q/(S(2)*a*c*(p + S(1))), x) def replacement658(A, B, C, a, b, c, d, f, p, q, x): return -Dist(S(1)/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + f*x**S(2))**(q + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-d*(C*(S(2)*a*c - b**S(2)*(p + S(2))) + c*(S(2)*p + S(3))*(-S(2)*A*c + B*b)) + S(2)*f*q*x*(A*b*c - S(2)*B*a*c + C*a*b) - f*x**S(2)*(C*(S(2)*a*c*(S(2)*q + S(1)) - b**S(2)*(p + S(2)*q + S(2))) + c*(-S(2)*A*c + B*b)*(S(2)*p + S(2)*q + S(3))), x), x), x) + Simp((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))*(A*b*c - S(2)*B*a*c + C*a*b - x*(-C*(-S(2)*a*c + b**S(2)) + c*(-S(2)*A*c + B*b)))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement659(A, C, a, b, c, d, f, p, q, x): return -Dist(S(1)/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((d + f*x**S(2))**(q + S(-1))*(a + b*x + c*x**S(2))**(p + S(1))*Simp(S(2)*A*c**S(2)*d*(S(2)*p + S(3)) - C*(S(2)*a*c*d - b**S(2)*d*(p + S(2))) - f*x**S(2)*(-S(2)*A*c**S(2)*(S(2)*p + S(2)*q + S(3)) + C*(S(2)*a*c*(S(2)*q + S(1)) - b**S(2)*(p + S(2)*q + S(2)))) + x*(S(2)*A*b*c*f*q + S(2)*C*a*b*f*q), x), x), x) + Simp((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))*(A*b*c + C*a*b + x*(S(2)*A*c**S(2) + C*(-S(2)*a*c + b**S(2))))/(c*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement660(A, B, C, a, b, c, d, e, f, p, q, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(-c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-B*c*e - C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(A*c*e + B*a*f + B*c*d + C*a*e)) - e*((A*b - B*a)*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + (A*c - C*a)*(S(2)*a*c*e - b*(a*f + c*d)))*(p + q + S(2)) - x*(S(2)*f*((A*b - B*a)*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + (A*c - C*a)*(S(2)*a*c*e - b*(a*f + c*d)))*(p + q + S(2)) - (b*f*(p + S(1)) - c*e*(S(2)*p + q + S(4)))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-B*c*e - C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(A*c*e + B*a*f + B*c*d + C*a*e))) + (p + S(1))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))*(-S(2)*A*c + B*b - S(2)*C*a) + (a*f*(p + S(1)) - c*d*(p + S(2)))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-B*c*e - C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(A*c*e + B*a*f + B*c*d + C*a*e)), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(1))*(c*x*(A*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) - B*(a*b*f - S(2)*a*c*e + b*c*d) + C*(-a*b*e - S(2)*a*(-a*f + c*d) + b**S(2)*d)) + (A*b - B*a)*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + (A*c - C*a)*(S(2)*a*c*e - b*(a*f + c*d)))/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), x) def replacement661(A, C, a, b, c, d, e, f, p, q, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), Int((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(-c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(A*c*e + C*a*e)) - e*(A*b*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + (A*c - C*a)*(S(2)*a*c*e - b*(a*f + c*d)))*(p + q + S(2)) - x*(S(2)*f*(A*b*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + (A*c - C*a)*(S(2)*a*c*e - b*(a*f + c*d)))*(p + q + S(2)) - (b*f*(p + S(1)) - c*e*(S(2)*p + q + S(4)))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(A*c*e + C*a*e))) + (p + S(1))*(-S(2)*A*c - S(2)*C*a)*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2)) + (a*f*(p + S(1)) - c*d*(p + S(2)))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(A*c*e + C*a*e)), x), x), x) + Simp((a + b*x + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(1))*(A*b*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + c*x*(A*(b**S(2)*f + S(2)*c**S(2)*d - c*(S(2)*a*f + b*e)) + C*(-a*b*e - S(2)*a*(-a*f + c*d) + b**S(2)*d)) + (A*c - C*a)*(S(2)*a*c*e - b*(a*f + c*d)))/((p + S(1))*(-S(4)*a*c + b**S(2))*(-(-a*e + b*d)*(-b*f + c*e) + (-a*f + c*d)**S(2))), x) def replacement662(A, B, C, a, c, d, e, f, p, q, x): return Dist(-S(1)/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(-c*f*x**S(2)*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-B*c*e - C*a*f + C*c*d))*(S(2)*p + S(2)*q + S(5)) - e*(-B*a*(-S(2)*a*c*f + S(2)*c**S(2)*d) + S(2)*a*c*e*(A*c - C*a))*(p + q + S(2)) - x*(c*e*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-B*c*e - C*a*f + C*c*d))*(S(2)*p + q + S(4)) + S(2)*f*(-B*a*(-S(2)*a*c*f + S(2)*c**S(2)*d) + S(2)*a*c*e*(A*c - C*a))*(p + q + S(2))) + (p + S(1))*(-S(2)*A*c - S(2)*C*a)*(a*c*e**S(2) + (-a*f + c*d)**S(2)) + (S(2)*A*c*(-a*f + c*d) - S(2)*a*(-B*c*e - C*a*f + C*c*d))*(a*f*(p + S(1)) - c*d*(p + S(2))), x), x), x) + Simp(-(a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**(q + S(1))*(-B*a*(-S(2)*a*c*f + S(2)*c**S(2)*d) + S(2)*a*c*e*(A*c - C*a) + c*x*(A*(-S(2)*a*c*f + S(2)*c**S(2)*d) + S(2)*B*a*c*e - S(2)*C*a*(-a*f + c*d)))/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), x) def replacement663(A, C, a, c, d, e, f, p, q, x): return Dist(-S(1)/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), Int((a + c*x**S(2))**(p + S(1))*(d + e*x + f*x**S(2))**q*Simp(-S(2)*a*c*e**S(2)*(A*c - C*a)*(p + q + S(2)) - c*f*x**S(2)*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d))*(S(2)*p + S(2)*q + S(5)) - x*(S(4)*a*c*e*f*(A*c - C*a)*(p + q + S(2)) + c*e*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d))*(S(2)*p + q + S(4))) + (p + S(1))*(-S(2)*A*c - S(2)*C*a)*(a*c*e**S(2) + (-a*f + c*d)**S(2)) + (S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d))*(a*f*(p + S(1)) - c*d*(p + S(2))), x), x), x) + Simp(-(a + c*x**S(2))**(p + S(1))*(S(2)*a*c*e*(A*c - C*a) + c*x*(A*(-S(2)*a*c*f + S(2)*c**S(2)*d) - S(2)*C*a*(-a*f + c*d)))*(d + e*x + f*x**S(2))**(q + S(1))/(S(4)*a*c*(p + S(1))*(a*c*e**S(2) + (-a*f + c*d)**S(2))), x) def replacement664(A, B, C, a, b, c, d, f, p, q, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(B*a*f + B*c*d)) - x*(-b*f*(p + S(1))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(B*a*f + B*c*d)) + S(2)*f*(-b*(A*c - C*a)*(a*f + c*d) + (A*b - B*a)*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d))*(p + q + S(2))) + (p + S(1))*(b**S(2)*d*f + (-a*f + c*d)**S(2))*(-S(2)*A*c + B*b - S(2)*C*a) + (a*f*(p + S(1)) - c*d*(p + S(2)))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d) - b*(B*a*f + B*c*d)), x), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(-b*(A*c - C*a)*(a*f + c*d) + c*x*(A*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d) - B*(a*b*f + b*c*d) + C*(-S(2)*a*(-a*f + c*d) + b**S(2)*d)) + (A*b - B*a)*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d))/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), x) def replacement665(A, C, a, b, c, d, f, p, q, x): return Dist(S(1)/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(1))*Simp(-c*f*x**S(2)*(S(2)*p + S(2)*q + S(5))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d)) - x*(-b*f*(p + S(1))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d)) + S(2)*f*(A*b*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d) - b*(A*c - C*a)*(a*f + c*d))*(p + q + S(2))) + (p + S(1))*(-S(2)*A*c - S(2)*C*a)*(b**S(2)*d*f + (-a*f + c*d)**S(2)) + (a*f*(p + S(1)) - c*d*(p + S(2)))*(S(2)*A*c*(-a*f + c*d) - S(2)*a*(-C*a*f + C*c*d) + b**S(2)*(A*f + C*d)), x), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(a + b*x + c*x**S(2))**(p + S(1))*(A*b*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d) - b*(A*c - C*a)*(a*f + c*d) + c*x*(A*(-S(2)*a*c*f + b**S(2)*f + S(2)*c**S(2)*d) + C*(-S(2)*a*(-a*f + c*d) + b**S(2)*d)))/((p + S(1))*(-S(4)*a*c + b**S(2))*(b**S(2)*d*f + (-a*f + c*d)**S(2))), x) def replacement666(A, B, C, a, b, c, d, e, f, p, q, x): return -Dist(S(1)/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), Int((a + b*x + c*x**S(2))**(p + S(-1))*(d + e*x + f*x**S(2))**q*Simp(p*(-a*e + b*d)*(C*(q + S(1))*(-b*f + c*e) - c*(-B*f + C*e)*(S(2)*p + S(2)*q + S(3))) + x**S(2)*(p*(-b*f + c*e)*(C*(q + S(1))*(-b*f + c*e) - c*(-B*f + C*e)*(S(2)*p + S(2)*q + S(3))) + (C*f**S(2)*p*(-S(4)*a*c + b**S(2)) - c**S(2)*(C*(-S(4)*d*f + e**S(2))*(S(2)*p + q + S(2)) + f*(S(2)*p + S(2)*q + S(3))*(S(2)*A*f - B*e + S(2)*C*d)))*(p + q + S(1))) + x*(S(2)*p*(-a*f + c*d)*(C*(q + S(1))*(-b*f + c*e) - c*(-B*f + C*e)*(S(2)*p + S(2)*q + S(3))) + (C*e*f*p*(-S(4)*a*c + b**S(2)) - b*c*(C*(-S(4)*d*f + e**S(2))*(S(2)*p + q + S(2)) + f*(S(2)*p + S(2)*q + S(3))*(S(2)*A*f - B*e + S(2)*C*d)))*(p + q + S(1))) + (C*b**S(2)*d*f*p + a*c*(C*(S(2)*d*f - e**S(2)*(S(2)*p + q + S(2))) + f*(-S(2)*A*f + B*e)*(S(2)*p + S(2)*q + S(3))))*(p + q + S(1)), x), x), x) + Simp((a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**(q + S(1))*(B*c*f*(S(2)*p + S(2)*q + S(3)) + S(2)*C*c*f*x*(p + q + S(1)) + C*(b*f*p - c*e*(S(2)*p + q + S(2))))/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), x) def replacement667(A, C, a, b, c, d, e, f, p, q, x): return -Dist(S(1)/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), Int((a + b*x + c*x**S(2))**(p + S(-1))*(d + e*x + f*x**S(2))**q*Simp(p*(-a*e + b*d)*(-C*c*e*(S(2)*p + S(2)*q + S(3)) + C*(q + S(1))*(-b*f + c*e)) + x**S(2)*(p*(-b*f + c*e)*(-C*c*e*(S(2)*p + S(2)*q + S(3)) + C*(q + S(1))*(-b*f + c*e)) + (C*f**S(2)*p*(-S(4)*a*c + b**S(2)) - c**S(2)*(C*(-S(4)*d*f + e**S(2))*(S(2)*p + q + S(2)) + f*(S(2)*A*f + S(2)*C*d)*(S(2)*p + S(2)*q + S(3))))*(p + q + S(1))) + x*(S(2)*p*(-a*f + c*d)*(-C*c*e*(S(2)*p + S(2)*q + S(3)) + C*(q + S(1))*(-b*f + c*e)) + (C*e*f*p*(-S(4)*a*c + b**S(2)) - b*c*(C*(-S(4)*d*f + e**S(2))*(S(2)*p + q + S(2)) + f*(S(2)*A*f + S(2)*C*d)*(S(2)*p + S(2)*q + S(3))))*(p + q + S(1))) + (C*b**S(2)*d*f*p + a*c*(-S(2)*A*f**S(2)*(S(2)*p + S(2)*q + S(3)) + C*(S(2)*d*f - e**S(2)*(S(2)*p + q + S(2)))))*(p + q + S(1)), x), x), x) + Simp((S(2)*C*c*f*x*(p + q + S(1)) + C*(b*f*p - c*e*(S(2)*p + q + S(2))))*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**(q + S(1))/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), x) def replacement668(A, B, C, a, c, d, e, f, p, q, x): return -Dist(S(1)/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x + f*x**S(2))**q*Simp(a*c*(C*(S(2)*d*f - e**S(2)*(S(2)*p + q + S(2))) + f*(-S(2)*A*f + B*e)*(S(2)*p + S(2)*q + S(3)))*(p + q + S(1)) - a*e*p*(C*c*e*(q + S(1)) - c*(-B*f + C*e)*(S(2)*p + S(2)*q + S(3))) + x**S(2)*(c*e*p*(C*c*e*(q + S(1)) - c*(-B*f + C*e)*(S(2)*p + S(2)*q + S(3))) + (-S(4)*C*a*c*f**S(2)*p - c**S(2)*(C*(-S(4)*d*f + e**S(2))*(S(2)*p + q + S(2)) + f*(S(2)*p + S(2)*q + S(3))*(S(2)*A*f - B*e + S(2)*C*d)))*(p + q + S(1))) + x*(-S(4)*C*a*c*e*f*p*(p + q + S(1)) + S(2)*p*(-a*f + c*d)*(C*c*e*(q + S(1)) - c*(-B*f + C*e)*(S(2)*p + S(2)*q + S(3)))), x), x), x) + Simp((a + c*x**S(2))**p*(d + e*x + f*x**S(2))**(q + S(1))*(B*c*f*(S(2)*p + S(2)*q + S(3)) - C*c*e*(S(2)*p + q + S(2)) + S(2)*C*c*f*x*(p + q + S(1)))/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), x) def replacement669(A, C, a, c, d, e, f, p, q, x): return -Dist(S(1)/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), Int((a + c*x**S(2))**(p + S(-1))*(d + e*x + f*x**S(2))**q*Simp(a*c*(-S(2)*A*f**S(2)*(S(2)*p + S(2)*q + S(3)) + C*(S(2)*d*f - e**S(2)*(S(2)*p + q + S(2))))*(p + q + S(1)) - a*e*p*(C*c*e*(q + S(1)) - C*c*e*(S(2)*p + S(2)*q + S(3))) + x**S(2)*(c*e*p*(C*c*e*(q + S(1)) - C*c*e*(S(2)*p + S(2)*q + S(3))) + (-S(4)*C*a*c*f**S(2)*p - c**S(2)*(C*(-S(4)*d*f + e**S(2))*(S(2)*p + q + S(2)) + f*(S(2)*A*f + S(2)*C*d)*(S(2)*p + S(2)*q + S(3))))*(p + q + S(1))) + x*(-S(4)*C*a*c*e*f*p*(p + q + S(1)) + S(2)*p*(-a*f + c*d)*(C*c*e*(q + S(1)) - C*c*e*(S(2)*p + S(2)*q + S(3)))), x), x), x) + Simp((a + c*x**S(2))**p*(-C*c*e*(S(2)*p + q + S(2)) + S(2)*C*c*f*x*(p + q + S(1)))*(d + e*x + f*x**S(2))**(q + S(1))/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), x) def replacement670(A, B, C, a, b, c, d, f, p, q, x): return -Dist(S(1)/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(-1))*Simp(b*d*p*(B*c*f*(S(2)*p + S(2)*q + S(3)) - C*b*f*(q + S(1))) + x**S(2)*(-b*f*p*(B*c*f*(S(2)*p + S(2)*q + S(3)) - C*b*f*(q + S(1))) + (C*f**S(2)*p*(-S(4)*a*c + b**S(2)) - c**S(2)*(-S(4)*C*d*f*(S(2)*p + q + S(2)) + f*(S(2)*A*f + S(2)*C*d)*(S(2)*p + S(2)*q + S(3))))*(p + q + S(1))) + x*(-b*c*(-S(4)*C*d*f*(S(2)*p + q + S(2)) + f*(S(2)*A*f + S(2)*C*d)*(S(2)*p + S(2)*q + S(3)))*(p + q + S(1)) + S(2)*p*(-a*f + c*d)*(B*c*f*(S(2)*p + S(2)*q + S(3)) - C*b*f*(q + S(1)))) + (C*b**S(2)*d*f*p + a*c*(-S(2)*A*f**S(2)*(S(2)*p + S(2)*q + S(3)) + S(2)*C*d*f))*(p + q + S(1)), x), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(a + b*x + c*x**S(2))**p*(B*c*f*(S(2)*p + S(2)*q + S(3)) + C*b*f*p + S(2)*C*c*f*x*(p + q + S(1)))/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), x) def replacement671(A, C, a, b, c, d, f, p, q, x): return -Dist(S(1)/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), Int((d + f*x**S(2))**q*(a + b*x + c*x**S(2))**(p + S(-1))*Simp(-C*b**S(2)*d*f*p*(q + S(1)) + x**S(2)*(C*b**S(2)*f**S(2)*p*(q + S(1)) + (C*f**S(2)*p*(-S(4)*a*c + b**S(2)) - c**S(2)*(-S(4)*C*d*f*(S(2)*p + q + S(2)) + f*(S(2)*A*f + S(2)*C*d)*(S(2)*p + S(2)*q + S(3))))*(p + q + S(1))) + x*(-S(2)*C*b*f*p*(q + S(1))*(-a*f + c*d) - b*c*(-S(4)*C*d*f*(S(2)*p + q + S(2)) + f*(S(2)*A*f + S(2)*C*d)*(S(2)*p + S(2)*q + S(3)))*(p + q + S(1))) + (C*b**S(2)*d*f*p + a*c*(-S(2)*A*f**S(2)*(S(2)*p + S(2)*q + S(3)) + S(2)*C*d*f))*(p + q + S(1)), x), x), x) + Simp((d + f*x**S(2))**(q + S(1))*(C*b*f*p + S(2)*C*c*f*x*(p + q + S(1)))*(a + b*x + c*x**S(2))**p/(S(2)*c*f**S(2)*(p + q + S(1))*(S(2)*p + S(2)*q + S(3))), x) def With672(A, B, C, a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement672(A, B, C, a, b, c, d, e, f, x): q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) return Dist(S(1)/q, Int((-A*a*c*f + A*b**S(2)*f - A*b*c*e + A*c**S(2)*d - B*a*b*f + B*a*c*e + C*a**S(2)*f - C*a*c*d + c*x*(A*b*f - A*c*e - B*a*f + B*c*d + C*a*e - C*b*d))/(a + b*x + c*x**S(2)), x), x) + Dist(S(1)/q, Int((A*a*f**S(2) - A*b*e*f - A*c*d*f + A*c*e**S(2) + B*b*d*f - B*c*d*e - C*a*d*f + C*c*d**S(2) - f*x*(A*b*f - A*c*e - B*a*f + B*c*d + C*a*e - C*b*d))/(d + e*x + f*x**S(2)), x), x) def With673(A, C, a, b, c, d, e, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement673(A, C, a, b, c, d, e, f, x): q = a**S(2)*f**S(2) - a*b*e*f - S(2)*a*c*d*f + a*c*e**S(2) + b**S(2)*d*f - b*c*d*e + c**S(2)*d**S(2) return Dist(S(1)/q, Int((-A*a*c*f + A*b**S(2)*f - A*b*c*e + A*c**S(2)*d + C*a**S(2)*f - C*a*c*d + c*x*(A*b*f - A*c*e + C*a*e - C*b*d))/(a + b*x + c*x**S(2)), x), x) + Dist(S(1)/q, Int((A*a*f**S(2) - A*b*e*f - A*c*d*f + A*c*e**S(2) - C*a*d*f + C*c*d**S(2) - f*x*(A*b*f - A*c*e + C*a*e - C*b*d))/(d + e*x + f*x**S(2)), x), x) def With674(A, B, C, a, b, c, d, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement674(A, B, C, a, b, c, d, f, x): q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) return Dist(S(1)/q, Int((A*a*f**S(2) - A*c*d*f + B*b*d*f - C*a*d*f + C*c*d**S(2) - f*x*(A*b*f - B*a*f + B*c*d - C*b*d))/(d + f*x**S(2)), x), x) + Dist(S(1)/q, Int((-A*a*c*f + A*b**S(2)*f + A*c**S(2)*d - B*a*b*f + C*a**S(2)*f - C*a*c*d + c*x*(A*b*f - B*a*f + B*c*d - C*b*d))/(a + b*x + c*x**S(2)), x), x) def With675(A, C, a, b, c, d, f, x): if isinstance(x, (int, Integer, float, Float)): return False q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) if NonzeroQ(q): return True return False def replacement675(A, C, a, b, c, d, f, x): q = a**S(2)*f**S(2) - S(2)*a*c*d*f + b**S(2)*d*f + c**S(2)*d**S(2) return Dist(S(1)/q, Int((A*a*f**S(2) - A*c*d*f - C*a*d*f + C*c*d**S(2) - f*x*(A*b*f - C*b*d))/(d + f*x**S(2)), x), x) + Dist(S(1)/q, Int((-A*a*c*f + A*b**S(2)*f + A*c**S(2)*d + C*a**S(2)*f - C*a*c*d + c*x*(A*b*f - C*b*d))/(a + b*x + c*x**S(2)), x), x) def replacement676(A, B, C, a, b, c, d, e, f, x): return Dist(S(1)/c, Int((A*c - C*a + x*(B*c - C*b))/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(C/c, Int(S(1)/sqrt(d + e*x + f*x**S(2)), x), x) def replacement677(A, C, a, b, c, d, e, f, x): return Dist(S(1)/c, Int((A*c - C*a - C*b*x)/((a + b*x + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(C/c, Int(S(1)/sqrt(d + e*x + f*x**S(2)), x), x) def replacement678(A, B, C, a, c, d, e, f, x): return Dist(S(1)/c, Int((A*c + B*c*x - C*a)/((a + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) + Dist(C/c, Int(S(1)/sqrt(d + e*x + f*x**S(2)), x), x) def replacement679(A, C, a, c, d, e, f, x): return Dist(C/c, Int(S(1)/sqrt(d + e*x + f*x**S(2)), x), x) + Dist((A*c - C*a)/c, Int(S(1)/((a + c*x**S(2))*sqrt(d + e*x + f*x**S(2))), x), x) def replacement680(A, B, C, a, b, c, d, f, x): return Dist(S(1)/c, Int((A*c - C*a + x*(B*c - C*b))/(sqrt(d + f*x**S(2))*(a + b*x + c*x**S(2))), x), x) + Dist(C/c, Int(S(1)/sqrt(d + f*x**S(2)), x), x) def replacement681(A, C, a, b, c, d, f, x): return Dist(S(1)/c, Int((A*c - C*a - C*b*x)/(sqrt(d + f*x**S(2))*(a + b*x + c*x**S(2))), x), x) + Dist(C/c, Int(S(1)/sqrt(d + f*x**S(2)), x), x) def replacement682(A, B, C, a, b, c, d, e, f, p, q, x): return Int((A + B*x + C*x**S(2))*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x) def replacement683(A, C, a, b, c, d, e, f, p, q, x): return Int((A + C*x**S(2))*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x) def replacement684(A, B, C, a, c, d, e, f, p, q, x): return Int((a + c*x**S(2))**p*(A + B*x + C*x**S(2))*(d + e*x + f*x**S(2))**q, x) def replacement685(A, C, a, c, d, e, f, p, q, x): return Int((A + C*x**S(2))*(a + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x) def replacement686(A, B, C, a, b, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((A + B*x + C*x**S(2))*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement687(A, B, a, b, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((A + B*x)*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement688(A, C, a, b, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((A + C*x**S(2))*(a + b*x + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement689(A, B, C, a, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + c*x**S(2))**p*(A + B*x + C*x**S(2))*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement690(A, B, a, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((A + B*x)*(a + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) def replacement691(A, C, a, c, d, e, f, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((A + C*x**S(2))*(a + c*x**S(2))**p*(d + e*x + f*x**S(2))**q, x), x, u), x) sympy-sympy-1.9/sympy/integrals/rubi/rules/secant.py000066400000000000000000015600521412543434000230270ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def secant(): from sympy.integrals.rubi.constraints import cons1583, cons1504, cons2, cons3, cons50, cons127, cons19, cons4, cons1584, cons1514, cons1585, cons21, cons95, cons168, cons91, cons1172, cons96, cons167, cons33, cons1586, cons89, cons1361, cons25, cons1257, cons1260, cons676, cons8, cons29, cons810, cons1263, cons1587, cons1266, cons1267, cons1588, cons545, cons45, cons450, cons1269, cons746, cons1589, cons1256, cons64, cons1425, cons517, cons1322, cons1323, cons1590, cons1591, cons1592, cons1332, cons113, cons157, cons1593, cons1521, cons1338, cons1594, cons465, cons87, cons1595, cons79, cons170, cons274, cons1335, cons1596, cons1336, cons1597, cons1327, cons1598, cons1599, cons1600, cons1601, cons1555, cons1602, cons1359, cons1603, cons1604, cons1605, cons1606, cons20, cons210, cons5, cons1276, cons1607, cons1608, cons1310, cons149, cons1230, cons1509, cons150, cons1517, cons1609, cons198, cons1313, cons1610, cons1611, cons1582, cons72, cons1612, cons1613, cons81, cons1614, cons1615, cons1306, cons73, cons1414, cons1411, cons1325, cons1324, cons1616, cons82, cons1362, cons1423, cons1317, cons1233, cons1617, cons1316, cons1268, cons1618, cons152, cons1619, cons1620, cons1621, cons1622, cons1623, cons40, cons1624, cons1417, cons382, cons1430, cons36, cons37, cons1247, cons1571, cons1625, cons1626, cons1627, cons1628, cons1629, cons34, cons1551, cons1630, cons1631, cons348, cons90, cons1329, cons1632, cons1633, cons1258, cons1634, cons377, cons35, cons38, cons1435, cons1635, cons1636, cons1433, cons1637, cons1638, cons1639, cons1640, cons1641, cons1642, cons685, cons1643, cons1644, cons1645, cons1456, cons1480, cons56, cons1482, cons1481, cons1483, cons378, cons48, cons47, cons228, cons1646, cons530, cons812, cons813, cons1575, cons1497, cons70, cons71, cons825, cons826, cons1576, cons1578, cons1499, cons1579, cons1647 pattern3920 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1583, cons1504) rule3920 = ReplacementRule(pattern3920, replacement3920) pattern3921 = Pattern(Integral((S(1)/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(S(1)/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons50, cons127, cons1584) rule3921 = ReplacementRule(pattern3921, replacement3921) pattern3922 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(S(1)/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1514, cons1585, cons21) rule3922 = ReplacementRule(pattern3922, replacement3922) pattern3923 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(S(1)/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1514, cons1585, cons21) rule3923 = ReplacementRule(pattern3923, replacement3923) pattern3924 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons168, cons91, cons1172) rule3924 = ReplacementRule(pattern3924, replacement3924) pattern3925 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons96, cons167, cons1172) rule3925 = ReplacementRule(pattern3925, replacement3925) pattern3926 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons4, cons33, cons168, cons1172, cons1586) rule3926 = ReplacementRule(pattern3926, replacement3926) pattern3927 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons167, cons1172) rule3927 = ReplacementRule(pattern3927, replacement3927) pattern3928 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons4, cons33, cons96, cons1361, cons1172) rule3928 = ReplacementRule(pattern3928, replacement3928) pattern3929 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons91, cons1361, cons1172) rule3929 = ReplacementRule(pattern3929, replacement3929) pattern3930 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons25, cons1257) rule3930 = ReplacementRule(pattern3930, replacement3930) pattern3931 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1260) rule3931 = ReplacementRule(pattern3931, replacement3931) pattern3932 = Pattern(Integral((S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons8, cons29, cons676) rule3932 = ReplacementRule(pattern3932, replacement3932) pattern3933 = Pattern(Integral((S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons8, cons29, cons676) rule3933 = ReplacementRule(pattern3933, replacement3933) pattern3934 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons167, cons810) rule3934 = ReplacementRule(pattern3934, replacement3934) pattern3935 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons167, cons810) rule3935 = ReplacementRule(pattern3935, replacement3935) pattern3936 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons91, cons810) rule3936 = ReplacementRule(pattern3936, replacement3936) pattern3937 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons91, cons810) rule3937 = ReplacementRule(pattern3937, replacement3937) pattern3938 = Pattern(Integral(S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons1263) rule3938 = ReplacementRule(pattern3938, replacement3938) pattern3939 = Pattern(Integral(S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons1263) rule3939 = ReplacementRule(pattern3939, replacement3939) pattern3940 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons1587) rule3940 = ReplacementRule(pattern3940, replacement3940) pattern3941 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons1587) rule3941 = ReplacementRule(pattern3941, replacement3941) pattern3942 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons4, cons25) rule3942 = ReplacementRule(pattern3942, replacement3942) pattern3943 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons4, cons25) rule3943 = ReplacementRule(pattern3943, replacement3943) pattern3944 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons1266) rule3944 = ReplacementRule(pattern3944, replacement3944) pattern3945 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons1266) rule3945 = ReplacementRule(pattern3945, replacement3945) pattern3946 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule3946 = ReplacementRule(pattern3946, replacement3946) pattern3947 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule3947 = ReplacementRule(pattern3947, replacement3947) pattern3948 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons89, cons167, cons810) rule3948 = ReplacementRule(pattern3948, replacement3948) pattern3949 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons89, cons167, cons810) rule3949 = ReplacementRule(pattern3949, replacement3949) pattern3950 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule3950 = ReplacementRule(pattern3950, replacement3950) pattern3951 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule3951 = ReplacementRule(pattern3951, replacement3951) pattern3952 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons89, cons1588, cons810) rule3952 = ReplacementRule(pattern3952, replacement3952) pattern3953 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons89, cons1588, cons810) rule3953 = ReplacementRule(pattern3953, replacement3953) pattern3954 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons45) rule3954 = ReplacementRule(pattern3954, replacement3954) pattern3955 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons45) rule3955 = ReplacementRule(pattern3955, replacement3955) pattern3956 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons450) rule3956 = ReplacementRule(pattern3956, replacement3956) pattern3957 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons450) rule3957 = ReplacementRule(pattern3957, replacement3957) pattern3958 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule3958 = ReplacementRule(pattern3958, replacement3958) pattern3959 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule3959 = ReplacementRule(pattern3959, replacement3959) pattern3960 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons1269) rule3960 = ReplacementRule(pattern3960, replacement3960) pattern3961 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons1269) rule3961 = ReplacementRule(pattern3961, replacement3961) pattern3962 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons746, cons810) rule3962 = ReplacementRule(pattern3962, replacement3962) pattern3963 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons746, cons810) rule3963 = ReplacementRule(pattern3963, replacement3963) pattern3964 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule3964 = ReplacementRule(pattern3964, replacement3964) pattern3965 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule3965 = ReplacementRule(pattern3965, replacement3965) pattern3966 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule3966 = ReplacementRule(pattern3966, replacement3966) pattern3967 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule3967 = ReplacementRule(pattern3967, replacement3967) pattern3968 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons91, cons810) rule3968 = ReplacementRule(pattern3968, replacement3968) pattern3969 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons91, cons810) rule3969 = ReplacementRule(pattern3969, replacement3969) pattern3970 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1269, cons545) rule3970 = ReplacementRule(pattern3970, replacement3970) pattern3971 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1269, cons545) rule3971 = ReplacementRule(pattern3971, replacement3971) pattern3972 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1589) rule3972 = ReplacementRule(pattern3972, replacement3972) pattern3973 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1589) rule3973 = ReplacementRule(pattern3973, replacement3973) pattern3974 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1589) rule3974 = ReplacementRule(pattern3974, replacement3974) pattern3975 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1589) rule3975 = ReplacementRule(pattern3975, replacement3975) pattern3976 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons1256) rule3976 = ReplacementRule(pattern3976, replacement3976) pattern3977 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons1256) rule3977 = ReplacementRule(pattern3977, replacement3977) pattern3978 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(3)), x_), cons2, cons3, cons50, cons127, cons1256) rule3978 = ReplacementRule(pattern3978, replacement3978) pattern3979 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(3)), x_), cons2, cons3, cons50, cons127, cons1256) rule3979 = ReplacementRule(pattern3979, replacement3979) pattern3980 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons64, cons89) rule3980 = ReplacementRule(pattern3980, replacement3980) pattern3981 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons64, cons89) rule3981 = ReplacementRule(pattern3981, replacement3981) pattern3982 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1267) rule3982 = ReplacementRule(pattern3982, replacement3982) pattern3983 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1267) rule3983 = ReplacementRule(pattern3983, replacement3983) pattern3984 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1425, cons517) rule3984 = ReplacementRule(pattern3984, replacement3984) pattern3985 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1425, cons517) rule3985 = ReplacementRule(pattern3985, replacement3985) pattern3986 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1267) rule3986 = ReplacementRule(pattern3986, replacement3986) pattern3987 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1267) rule3987 = ReplacementRule(pattern3987, replacement3987) pattern3988 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1267) rule3988 = ReplacementRule(pattern3988, replacement3988) pattern3989 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1267) rule3989 = ReplacementRule(pattern3989, replacement3989) pattern3990 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322, cons517) rule3990 = ReplacementRule(pattern3990, replacement3990) pattern3991 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322, cons517) rule3991 = ReplacementRule(pattern3991, replacement3991) pattern3992 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322) rule3992 = ReplacementRule(pattern3992, replacement3992) pattern3993 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322) rule3993 = ReplacementRule(pattern3993, replacement3993) pattern3994 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1323) rule3994 = ReplacementRule(pattern3994, replacement3994) pattern3995 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1323) rule3995 = ReplacementRule(pattern3995, replacement3995) pattern3996 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322) rule3996 = ReplacementRule(pattern3996, replacement3996) pattern3997 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322) rule3997 = ReplacementRule(pattern3997, replacement3997) pattern3998 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1323) rule3998 = ReplacementRule(pattern3998, replacement3998) pattern3999 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1323) rule3999 = ReplacementRule(pattern3999, replacement3999) pattern4000 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1590) rule4000 = ReplacementRule(pattern4000, replacement4000) pattern4001 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1590) rule4001 = ReplacementRule(pattern4001, replacement4001) pattern4002 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1591) rule4002 = ReplacementRule(pattern4002, replacement4002) pattern4003 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1591) rule4003 = ReplacementRule(pattern4003, replacement4003) pattern4004 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons167, cons810) rule4004 = ReplacementRule(pattern4004, replacement4004) pattern4005 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons167, cons810) rule4005 = ReplacementRule(pattern4005, replacement4005) pattern4006 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267) rule4006 = ReplacementRule(pattern4006, replacement4006) pattern4007 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267) rule4007 = ReplacementRule(pattern4007, replacement4007) pattern4008 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons1592, cons810) rule4008 = ReplacementRule(pattern4008, replacement4008) pattern4009 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons1592, cons810) rule4009 = ReplacementRule(pattern4009, replacement4009) pattern4010 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267) rule4010 = ReplacementRule(pattern4010, replacement4010) pattern4011 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267) rule4011 = ReplacementRule(pattern4011, replacement4011) pattern4012 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1332, cons45) rule4012 = ReplacementRule(pattern4012, replacement4012) pattern4013 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1332, cons45) rule4013 = ReplacementRule(pattern4013, replacement4013) pattern4014 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267) rule4014 = ReplacementRule(pattern4014, replacement4014) pattern4015 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267) rule4015 = ReplacementRule(pattern4015, replacement4015) pattern4016 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1257, cons33, cons1425, cons517) rule4016 = ReplacementRule(pattern4016, replacement4016) pattern4017 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1257, cons33, cons1425, cons517) rule4017 = ReplacementRule(pattern4017, replacement4017) pattern4018 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1257, cons33, cons1322, cons517) rule4018 = ReplacementRule(pattern4018, replacement4018) pattern4019 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1257, cons33, cons1322, cons517) rule4019 = ReplacementRule(pattern4019, replacement4019) pattern4020 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons113, cons1322) rule4020 = ReplacementRule(pattern4020, replacement4020) pattern4021 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons113, cons1322) rule4021 = ReplacementRule(pattern4021, replacement4021) pattern4022 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons157, cons1323) rule4022 = ReplacementRule(pattern4022, replacement4022) pattern4023 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons157, cons1323) rule4023 = ReplacementRule(pattern4023, replacement4023) pattern4024 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons168, cons1593, cons517) rule4024 = ReplacementRule(pattern4024, replacement4024) pattern4025 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons168, cons1593, cons517) rule4025 = ReplacementRule(pattern4025, replacement4025) pattern4026 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons33, cons168, cons1521, cons517) rule4026 = ReplacementRule(pattern4026, replacement4026) pattern4027 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons33, cons168, cons1521, cons517) rule4027 = ReplacementRule(pattern4027, replacement4027) pattern4028 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons96, cons1338, cons1594) rule4028 = ReplacementRule(pattern4028, replacement4028) pattern4029 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons96, cons1338, cons1594) rule4029 = ReplacementRule(pattern4029, replacement4029) pattern4030 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons96, cons746, cons1594) rule4030 = ReplacementRule(pattern4030, replacement4030) pattern4031 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons95, cons96, cons746, cons1594) rule4031 = ReplacementRule(pattern4031, replacement4031) pattern4032 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons33, cons96, cons1594) rule4032 = ReplacementRule(pattern4032, replacement4032) pattern4033 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons33, cons96, cons1594) rule4033 = ReplacementRule(pattern4033, replacement4033) pattern4034 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons167) rule4034 = ReplacementRule(pattern4034, replacement4034) pattern4035 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons167) rule4035 = ReplacementRule(pattern4035, replacement4035) pattern4036 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons465) rule4036 = ReplacementRule(pattern4036, replacement4036) pattern4037 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons465) rule4037 = ReplacementRule(pattern4037, replacement4037) pattern4038 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267) rule4038 = ReplacementRule(pattern4038, replacement4038) pattern4039 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267) rule4039 = ReplacementRule(pattern4039, replacement4039) pattern4040 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267) rule4040 = ReplacementRule(pattern4040, replacement4040) pattern4041 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267) rule4041 = ReplacementRule(pattern4041, replacement4041) pattern4042 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons746, cons810) rule4042 = ReplacementRule(pattern4042, replacement4042) pattern4043 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons746, cons810) rule4043 = ReplacementRule(pattern4043, replacement4043) pattern4044 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons465, cons810) rule4044 = ReplacementRule(pattern4044, replacement4044) pattern4045 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons89, cons465, cons810) rule4045 = ReplacementRule(pattern4045, replacement4045) pattern4046 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1267, cons89, cons746, cons1521, cons87) rule4046 = ReplacementRule(pattern4046, replacement4046) pattern4047 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1267, cons89, cons746, cons1521, cons87) rule4047 = ReplacementRule(pattern4047, replacement4047) pattern4048 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons25, cons1590) rule4048 = ReplacementRule(pattern4048, replacement4048) pattern4049 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons25, cons1590) rule4049 = ReplacementRule(pattern4049, replacement4049) pattern4050 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons25, cons1595) rule4050 = ReplacementRule(pattern4050, replacement4050) pattern4051 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons25, cons1595) rule4051 = ReplacementRule(pattern4051, replacement4051) pattern4052 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45) rule4052 = ReplacementRule(pattern4052, replacement4052) pattern4053 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45) rule4053 = ReplacementRule(pattern4053, replacement4053) pattern4054 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons450) rule4054 = ReplacementRule(pattern4054, replacement4054) pattern4055 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons450) rule4055 = ReplacementRule(pattern4055, replacement4055) pattern4056 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1269) rule4056 = ReplacementRule(pattern4056, replacement4056) pattern4057 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1269) rule4057 = ReplacementRule(pattern4057, replacement4057) pattern4058 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons168, cons517) rule4058 = ReplacementRule(pattern4058, replacement4058) pattern4059 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons168, cons517) rule4059 = ReplacementRule(pattern4059, replacement4059) pattern4060 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1269) rule4060 = ReplacementRule(pattern4060, replacement4060) pattern4061 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1269) rule4061 = ReplacementRule(pattern4061, replacement4061) pattern4062 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1269) rule4062 = ReplacementRule(pattern4062, replacement4062) pattern4063 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1269) rule4063 = ReplacementRule(pattern4063, replacement4063) pattern4064 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96, cons517) rule4064 = ReplacementRule(pattern4064, replacement4064) pattern4065 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96, cons517) rule4065 = ReplacementRule(pattern4065, replacement4065) pattern4066 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons79) rule4066 = ReplacementRule(pattern4066, replacement4066) pattern4067 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons79) rule4067 = ReplacementRule(pattern4067, replacement4067) pattern4068 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons170) rule4068 = ReplacementRule(pattern4068, replacement4068) pattern4069 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons170) rule4069 = ReplacementRule(pattern4069, replacement4069) pattern4070 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96) rule4070 = ReplacementRule(pattern4070, replacement4070) pattern4071 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96) rule4071 = ReplacementRule(pattern4071, replacement4071) pattern4072 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons1269) rule4072 = ReplacementRule(pattern4072, replacement4072) pattern4073 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons1269) rule4073 = ReplacementRule(pattern4073, replacement4073) pattern4074 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1269) rule4074 = ReplacementRule(pattern4074, replacement4074) pattern4075 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1269) rule4075 = ReplacementRule(pattern4075, replacement4075) pattern4076 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96) rule4076 = ReplacementRule(pattern4076, replacement4076) pattern4077 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96) rule4077 = ReplacementRule(pattern4077, replacement4077) pattern4078 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons274) rule4078 = ReplacementRule(pattern4078, replacement4078) pattern4079 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(3), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons274) rule4079 = ReplacementRule(pattern4079, replacement4079) pattern4080 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons1335, cons1596) rule4080 = ReplacementRule(pattern4080, replacement4080) pattern4081 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons1335, cons1596) rule4081 = ReplacementRule(pattern4081, replacement4081) pattern4082 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons33, cons1335, cons1336, cons1597) rule4082 = ReplacementRule(pattern4082, replacement4082) pattern4083 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons33, cons1335, cons1336, cons1597) rule4083 = ReplacementRule(pattern4083, replacement4083) pattern4084 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons96, cons1327, cons1172) rule4084 = ReplacementRule(pattern4084, replacement4084) pattern4085 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons96, cons1327, cons1172) rule4085 = ReplacementRule(pattern4085, replacement4085) pattern4086 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons96, cons1338, cons1172) rule4086 = ReplacementRule(pattern4086, replacement4086) pattern4087 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons96, cons1338, cons1172) rule4087 = ReplacementRule(pattern4087, replacement4087) pattern4088 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons96, cons1598) rule4088 = ReplacementRule(pattern4088, replacement4088) pattern4089 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons96, cons1598) rule4089 = ReplacementRule(pattern4089, replacement4089) pattern4090 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1599) rule4090 = ReplacementRule(pattern4090, replacement4090) pattern4091 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1599) rule4091 = ReplacementRule(pattern4091, replacement4091) pattern4092 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons33, cons96, cons1172) rule4092 = ReplacementRule(pattern4092, replacement4092) pattern4093 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons33, cons96, cons1172) rule4093 = ReplacementRule(pattern4093, replacement4093) pattern4094 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4094 = ReplacementRule(pattern4094, replacement4094) pattern4095 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4095 = ReplacementRule(pattern4095, replacement4095) pattern4096 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4096 = ReplacementRule(pattern4096, replacement4096) pattern4097 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4097 = ReplacementRule(pattern4097, replacement4097) pattern4098 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4098 = ReplacementRule(pattern4098, replacement4098) pattern4099 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4099 = ReplacementRule(pattern4099, replacement4099) pattern4100 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1600) rule4100 = ReplacementRule(pattern4100, replacement4100) pattern4101 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1600) rule4101 = ReplacementRule(pattern4101, replacement4101) pattern4102 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4102 = ReplacementRule(pattern4102, replacement4102) pattern4103 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4103 = ReplacementRule(pattern4103, replacement4103) pattern4104 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1588, cons810) rule4104 = ReplacementRule(pattern4104, replacement4104) pattern4105 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1588, cons810) rule4105 = ReplacementRule(pattern4105, replacement4105) pattern4106 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4106 = ReplacementRule(pattern4106, replacement4106) pattern4107 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4107 = ReplacementRule(pattern4107, replacement4107) pattern4108 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons167, cons810) rule4108 = ReplacementRule(pattern4108, replacement4108) pattern4109 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons167, cons810) rule4109 = ReplacementRule(pattern4109, replacement4109) pattern4110 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4110 = ReplacementRule(pattern4110, replacement4110) pattern4111 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4111 = ReplacementRule(pattern4111, replacement4111) pattern4112 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1588, cons810) rule4112 = ReplacementRule(pattern4112, replacement4112) pattern4113 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1588, cons810) rule4113 = ReplacementRule(pattern4113, replacement4113) pattern4114 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4114 = ReplacementRule(pattern4114, replacement4114) pattern4115 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4115 = ReplacementRule(pattern4115, replacement4115) pattern4116 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4116 = ReplacementRule(pattern4116, replacement4116) pattern4117 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4117 = ReplacementRule(pattern4117, replacement4117) pattern4118 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons746, cons810) rule4118 = ReplacementRule(pattern4118, replacement4118) pattern4119 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons746, cons810) rule4119 = ReplacementRule(pattern4119, replacement4119) pattern4120 = Pattern(Integral(cos(x_*WC('f', S(1)) + WC('e', S(0)))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1269) rule4120 = ReplacementRule(pattern4120, replacement4120) pattern4121 = Pattern(Integral(sin(x_*WC('f', S(1)) + WC('e', S(0)))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1269) rule4121 = ReplacementRule(pattern4121, replacement4121) pattern4122 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4122 = ReplacementRule(pattern4122, replacement4122) pattern4123 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4123 = ReplacementRule(pattern4123, replacement4123) pattern4124 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons91, cons810) rule4124 = ReplacementRule(pattern4124, replacement4124) pattern4125 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons91, cons810) rule4125 = ReplacementRule(pattern4125, replacement4125) pattern4126 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1588, cons1601) rule4126 = ReplacementRule(pattern4126, replacement4126) pattern4127 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons89, cons1588, cons1601) rule4127 = ReplacementRule(pattern4127, replacement4127) pattern4128 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1269, cons89, cons1600, cons1555, cons1602) rule4128 = ReplacementRule(pattern4128, replacement4128) pattern4129 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1269, cons89, cons1600, cons1555, cons1602) rule4129 = ReplacementRule(pattern4129, replacement4129) pattern4130 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons1359, cons1603, cons1521, cons1336) rule4130 = ReplacementRule(pattern4130, replacement4130) pattern4131 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons1359, cons1603, cons1521, cons1336) rule4131 = ReplacementRule(pattern4131, replacement4131) pattern4132 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons1604, cons1605, cons1521, cons1555) rule4132 = ReplacementRule(pattern4132, replacement4132) pattern4133 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons95, cons1604, cons1605, cons1521, cons1555) rule4133 = ReplacementRule(pattern4133, replacement4133) pattern4134 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4134 = ReplacementRule(pattern4134, replacement4134) pattern4135 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule4135 = ReplacementRule(pattern4135, replacement4135) pattern4136 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons64) rule4136 = ReplacementRule(pattern4136, replacement4136) pattern4137 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons64) rule4137 = ReplacementRule(pattern4137, replacement4137) pattern4138 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1606) rule4138 = ReplacementRule(pattern4138, replacement4138) pattern4139 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1606) rule4139 = ReplacementRule(pattern4139, replacement4139) pattern4140 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons20) rule4140 = ReplacementRule(pattern4140, replacement4140) pattern4141 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons20) rule4141 = ReplacementRule(pattern4141, replacement4141) pattern4142 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1267) rule4142 = ReplacementRule(pattern4142, replacement4142) pattern4143 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1267) rule4143 = ReplacementRule(pattern4143, replacement4143) pattern4144 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1269) rule4144 = ReplacementRule(pattern4144, replacement4144) pattern4145 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1269) rule4145 = ReplacementRule(pattern4145, replacement4145) pattern4146 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1607) rule4146 = ReplacementRule(pattern4146, replacement4146) pattern4147 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1607) rule4147 = ReplacementRule(pattern4147, replacement4147) pattern4148 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1608) rule4148 = ReplacementRule(pattern4148, replacement4148) pattern4149 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1608) rule4149 = ReplacementRule(pattern4149, replacement4149) pattern4150 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1310) rule4150 = ReplacementRule(pattern4150, replacement4150) pattern4151 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1310) rule4151 = ReplacementRule(pattern4151, replacement4151) pattern4152 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons149) rule4152 = ReplacementRule(pattern4152, replacement4152) pattern4153 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons149) rule4153 = ReplacementRule(pattern4153, replacement4153) pattern4154 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1230, cons1267, cons87) rule4154 = ReplacementRule(pattern4154, replacement4154) pattern4155 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1230, cons1267, cons87) rule4155 = ReplacementRule(pattern4155, replacement4155) pattern4156 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1230, cons1267, cons25) rule4156 = ReplacementRule(pattern4156, replacement4156) pattern4157 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1230, cons1267, cons25) rule4157 = ReplacementRule(pattern4157, replacement4157) pattern4158 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168) rule4158 = ReplacementRule(pattern4158, replacement4158) pattern4159 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168) rule4159 = ReplacementRule(pattern4159, replacement4159) pattern4160 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96) rule4160 = ReplacementRule(pattern4160, replacement4160) pattern4161 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96) rule4161 = ReplacementRule(pattern4161, replacement4161) pattern4162 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))/tan(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule4162 = ReplacementRule(pattern4162, replacement4162) pattern4163 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))*tan(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule4163 = ReplacementRule(pattern4163, replacement4163) pattern4164 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1509) rule4164 = ReplacementRule(pattern4164, replacement4164) pattern4165 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1509) rule4165 = ReplacementRule(pattern4165, replacement4165) pattern4166 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1230, cons1269) rule4166 = ReplacementRule(pattern4166, replacement4166) pattern4167 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1230, cons1269) rule4167 = ReplacementRule(pattern4167, replacement4167) pattern4168 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons150) rule4168 = ReplacementRule(pattern4168, replacement4168) pattern4169 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons150) rule4169 = ReplacementRule(pattern4169, replacement4169) pattern4170 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1267, cons1517, cons1609) rule4170 = ReplacementRule(pattern4170, replacement4170) pattern4171 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1267, cons1517, cons1609) rule4171 = ReplacementRule(pattern4171, replacement4171) pattern4172 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1267, cons198) rule4172 = ReplacementRule(pattern4172, replacement4172) pattern4173 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1267, cons198) rule4173 = ReplacementRule(pattern4173, replacement4173) pattern4174 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1267, cons25) rule4174 = ReplacementRule(pattern4174, replacement4174) pattern4175 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1267, cons25) rule4175 = ReplacementRule(pattern4175, replacement4175) pattern4176 = Pattern(Integral(sqrt(WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))/(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1269) rule4176 = ReplacementRule(pattern4176, replacement4176) pattern4177 = Pattern(Integral(sqrt(WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))/(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1269) rule4177 = ReplacementRule(pattern4177, replacement4177) pattern4178 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_/(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1269, cons1313) rule4178 = ReplacementRule(pattern4178, replacement4178) pattern4179 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_/(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1269, cons1313) rule4179 = ReplacementRule(pattern4179, replacement4179) pattern4180 = Pattern(Integral(S(1)/(sqrt(WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons1269) rule4180 = ReplacementRule(pattern4180, replacement4180) pattern4181 = Pattern(Integral(S(1)/(sqrt(WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons1269) rule4181 = ReplacementRule(pattern4181, replacement4181) pattern4182 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_/(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1269, cons1610) rule4182 = ReplacementRule(pattern4182, replacement4182) pattern4183 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_/(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1269, cons1610) rule4183 = ReplacementRule(pattern4183, replacement4183) pattern4184 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*tan(x_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons1269) rule4184 = ReplacementRule(pattern4184, replacement4184) pattern4185 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_/tan(x_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons1269) rule4185 = ReplacementRule(pattern4185, replacement4185) pattern4186 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1269, cons150) rule4186 = ReplacementRule(pattern4186, replacement4186) pattern4187 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1269, cons150) rule4187 = ReplacementRule(pattern4187, replacement4187) pattern4188 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1269, cons87, cons20, cons1611) rule4188 = ReplacementRule(pattern4188, replacement4188) pattern4189 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1269, cons87, cons20, cons1611) rule4189 = ReplacementRule(pattern4189, replacement4189) pattern4190 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule4190 = ReplacementRule(pattern4190, replacement4190) pattern4191 = Pattern(Integral((WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule4191 = ReplacementRule(pattern4191, replacement4191) pattern4192 = Pattern(Integral((WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**p_)**m_*(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons21) rule4192 = ReplacementRule(pattern4192, replacement4192) pattern4193 = Pattern(Integral(((S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**p_*WC('e', S(1)))**m_*(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons21) rule4193 = ReplacementRule(pattern4193, replacement4193) pattern4194 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons64, cons198, cons1612) rule4194 = ReplacementRule(pattern4194, replacement4194) pattern4195 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons64, cons198, cons1612) rule4195 = ReplacementRule(pattern4195, replacement4195) pattern4196 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons20, cons89, cons1613) rule4196 = ReplacementRule(pattern4196, replacement4196) pattern4197 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons20, cons89, cons1613) rule4197 = ReplacementRule(pattern4197, replacement4197) pattern4198 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons81) rule4198 = ReplacementRule(pattern4198, replacement4198) pattern4199 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons81) rule4199 = ReplacementRule(pattern4199, replacement4199) pattern4200 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1614) rule4200 = ReplacementRule(pattern4200, replacement4200) pattern4201 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1614) rule4201 = ReplacementRule(pattern4201, replacement4201) pattern4202 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1592) rule4202 = ReplacementRule(pattern4202, replacement4202) pattern4203 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1592) rule4203 = ReplacementRule(pattern4203, replacement4203) pattern4204 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1592) rule4204 = ReplacementRule(pattern4204, replacement4204) pattern4205 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1592) rule4205 = ReplacementRule(pattern4205, replacement4205) pattern4206 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1615) rule4206 = ReplacementRule(pattern4206, replacement4206) pattern4207 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1615) rule4207 = ReplacementRule(pattern4207, replacement4207) pattern4208 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1592) rule4208 = ReplacementRule(pattern4208, replacement4208) pattern4209 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons89, cons1592) rule4209 = ReplacementRule(pattern4209, replacement4209) pattern4210 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons1306, cons1257) rule4210 = ReplacementRule(pattern4210, replacement4210) pattern4211 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons1306, cons1257) rule4211 = ReplacementRule(pattern4211, replacement4211) pattern4212 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267) rule4212 = ReplacementRule(pattern4212, replacement4212) pattern4213 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267) rule4213 = ReplacementRule(pattern4213, replacement4213) pattern4214 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72) rule4214 = ReplacementRule(pattern4214, replacement4214) pattern4215 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72) rule4215 = ReplacementRule(pattern4215, replacement4215) pattern4216 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1414) rule4216 = ReplacementRule(pattern4216, replacement4216) pattern4217 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1414) rule4217 = ReplacementRule(pattern4217, replacement4217) pattern4218 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule4218 = ReplacementRule(pattern4218, replacement4218) pattern4219 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule4219 = ReplacementRule(pattern4219, replacement4219) pattern4220 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule4220 = ReplacementRule(pattern4220, replacement4220) pattern4221 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule4221 = ReplacementRule(pattern4221, replacement4221) pattern4222 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons168, cons1267, cons517) rule4222 = ReplacementRule(pattern4222, replacement4222) pattern4223 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons168, cons1267, cons517) rule4223 = ReplacementRule(pattern4223, replacement4223) pattern4224 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons168, cons1269, cons517) rule4224 = ReplacementRule(pattern4224, replacement4224) pattern4225 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons168, cons1269, cons517) rule4225 = ReplacementRule(pattern4225, replacement4225) pattern4226 = Pattern(Integral((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4226 = ReplacementRule(pattern4226, replacement4226) pattern4227 = Pattern(Integral((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4227 = ReplacementRule(pattern4227, replacement4227) pattern4228 = Pattern(Integral((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule4228 = ReplacementRule(pattern4228, replacement4228) pattern4229 = Pattern(Integral((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule4229 = ReplacementRule(pattern4229, replacement4229) pattern4230 = Pattern(Integral((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule4230 = ReplacementRule(pattern4230, replacement4230) pattern4231 = Pattern(Integral((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule4231 = ReplacementRule(pattern4231, replacement4231) pattern4232 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons96, cons1267, cons517) rule4232 = ReplacementRule(pattern4232, replacement4232) pattern4233 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons96, cons1267, cons517) rule4233 = ReplacementRule(pattern4233, replacement4233) pattern4234 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons96, cons1269, cons517) rule4234 = ReplacementRule(pattern4234, replacement4234) pattern4235 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons96, cons1269, cons517) rule4235 = ReplacementRule(pattern4235, replacement4235) pattern4236 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons79) rule4236 = ReplacementRule(pattern4236, replacement4236) pattern4237 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons79) rule4237 = ReplacementRule(pattern4237, replacement4237) pattern4238 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4238 = ReplacementRule(pattern4238, replacement4238) pattern4239 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4239 = ReplacementRule(pattern4239, replacement4239) pattern4240 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4240 = ReplacementRule(pattern4240, replacement4240) pattern4241 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4241 = ReplacementRule(pattern4241, replacement4241) pattern4242 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4242 = ReplacementRule(pattern4242, replacement4242) pattern4243 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4243 = ReplacementRule(pattern4243, replacement4243) pattern4244 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4244 = ReplacementRule(pattern4244, replacement4244) pattern4245 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4245 = ReplacementRule(pattern4245, replacement4245) pattern4246 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4246 = ReplacementRule(pattern4246, replacement4246) pattern4247 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4247 = ReplacementRule(pattern4247, replacement4247) pattern4248 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule4248 = ReplacementRule(pattern4248, replacement4248) pattern4249 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule4249 = ReplacementRule(pattern4249, replacement4249) pattern4250 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule4250 = ReplacementRule(pattern4250, replacement4250) pattern4251 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule4251 = ReplacementRule(pattern4251, replacement4251) pattern4252 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4252 = ReplacementRule(pattern4252, replacement4252) pattern4253 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4253 = ReplacementRule(pattern4253, replacement4253) pattern4254 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule4254 = ReplacementRule(pattern4254, replacement4254) pattern4255 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule4255 = ReplacementRule(pattern4255, replacement4255) pattern4256 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule4256 = ReplacementRule(pattern4256, replacement4256) pattern4257 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule4257 = ReplacementRule(pattern4257, replacement4257) pattern4258 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule4258 = ReplacementRule(pattern4258, replacement4258) pattern4259 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule4259 = ReplacementRule(pattern4259, replacement4259) pattern4260 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4260 = ReplacementRule(pattern4260, replacement4260) pattern4261 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4261 = ReplacementRule(pattern4261, replacement4261) pattern4262 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule4262 = ReplacementRule(pattern4262, replacement4262) pattern4263 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule4263 = ReplacementRule(pattern4263, replacement4263) pattern4264 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4264 = ReplacementRule(pattern4264, replacement4264) pattern4265 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4265 = ReplacementRule(pattern4265, replacement4265) pattern4266 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1325) rule4266 = ReplacementRule(pattern4266, replacement4266) pattern4267 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1325) rule4267 = ReplacementRule(pattern4267, replacement4267) pattern4268 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1267, cons1325, cons1306) rule4268 = ReplacementRule(pattern4268, replacement4268) pattern4269 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1267, cons1325, cons1306) rule4269 = ReplacementRule(pattern4269, replacement4269) pattern4270 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons20, cons87, cons1616) rule4270 = ReplacementRule(pattern4270, replacement4270) pattern4271 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons20, cons87, cons1616) rule4271 = ReplacementRule(pattern4271, replacement4271) pattern4272 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons81, cons82, cons1616) rule4272 = ReplacementRule(pattern4272, replacement4272) pattern4273 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons81, cons82, cons1616) rule4273 = ReplacementRule(pattern4273, replacement4273) pattern4274 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1257, cons79) rule4274 = ReplacementRule(pattern4274, replacement4274) pattern4275 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1257, cons79) rule4275 = ReplacementRule(pattern4275, replacement4275) pattern4276 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons150) rule4276 = ReplacementRule(pattern4276, replacement4276) pattern4277 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons150) rule4277 = ReplacementRule(pattern4277, replacement4277) pattern4278 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule4278 = ReplacementRule(pattern4278, replacement4278) pattern4279 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule4279 = ReplacementRule(pattern4279, replacement4279) pattern4280 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons25, cons20) rule4280 = ReplacementRule(pattern4280, replacement4280) pattern4281 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons25, cons20) rule4281 = ReplacementRule(pattern4281, replacement4281) pattern4282 = Pattern(Integral(((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons25) rule4282 = ReplacementRule(pattern4282, replacement4282) pattern4283 = Pattern(Integral(((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons25) rule4283 = ReplacementRule(pattern4283, replacement4283) pattern4284 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons157, cons1423) rule4284 = ReplacementRule(pattern4284, replacement4284) pattern4285 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons157, cons1423) rule4285 = ReplacementRule(pattern4285, replacement4285) pattern4286 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons1317, cons1423, cons1233, cons1617) rule4286 = ReplacementRule(pattern4286, replacement4286) pattern4287 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons1317, cons1423, cons1233, cons1617) rule4287 = ReplacementRule(pattern4287, replacement4287) pattern4288 = Pattern(Integral(sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267) rule4288 = ReplacementRule(pattern4288, replacement4288) pattern4289 = Pattern(Integral(sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267) rule4289 = ReplacementRule(pattern4289, replacement4289) pattern4290 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons1316) rule4290 = ReplacementRule(pattern4290, replacement4290) pattern4291 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons1316) rule4291 = ReplacementRule(pattern4291, replacement4291) pattern4292 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons1268, cons33, cons1322) rule4292 = ReplacementRule(pattern4292, replacement4292) pattern4293 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons1268, cons33, cons1322) rule4293 = ReplacementRule(pattern4293, replacement4293) pattern4294 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons1268, cons1323, cons1618) rule4294 = ReplacementRule(pattern4294, replacement4294) pattern4295 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons1268, cons1323, cons1618) rule4295 = ReplacementRule(pattern4295, replacement4295) pattern4296 = Pattern(Integral((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons150) rule4296 = ReplacementRule(pattern4296, replacement4296) pattern4297 = Pattern(Integral((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons150) rule4297 = ReplacementRule(pattern4297, replacement4297) pattern4298 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons150, cons1322, cons517) rule4298 = ReplacementRule(pattern4298, replacement4298) pattern4299 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons150, cons1322, cons517) rule4299 = ReplacementRule(pattern4299, replacement4299) pattern4300 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons152, cons1619, cons1620) rule4300 = ReplacementRule(pattern4300, replacement4300) pattern4301 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons152, cons1619, cons1620) rule4301 = ReplacementRule(pattern4301, replacement4301) pattern4302 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons81) rule4302 = ReplacementRule(pattern4302, replacement4302) pattern4303 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons81) rule4303 = ReplacementRule(pattern4303, replacement4303) pattern4304 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1621) rule4304 = ReplacementRule(pattern4304, replacement4304) pattern4305 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1621) rule4305 = ReplacementRule(pattern4305, replacement4305) pattern4306 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267) rule4306 = ReplacementRule(pattern4306, replacement4306) pattern4307 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267) rule4307 = ReplacementRule(pattern4307, replacement4307) pattern4308 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons152, cons1619, cons1620) rule4308 = ReplacementRule(pattern4308, replacement4308) pattern4309 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons152, cons1619, cons1620) rule4309 = ReplacementRule(pattern4309, replacement4309) pattern4310 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267, cons81) rule4310 = ReplacementRule(pattern4310, replacement4310) pattern4311 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267, cons81) rule4311 = ReplacementRule(pattern4311, replacement4311) pattern4312 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267) rule4312 = ReplacementRule(pattern4312, replacement4312) pattern4313 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267) rule4313 = ReplacementRule(pattern4313, replacement4313) pattern4314 = Pattern(Integral(sqrt(WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4314 = ReplacementRule(pattern4314, replacement4314) pattern4315 = Pattern(Integral(sqrt(WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4315 = ReplacementRule(pattern4315, replacement4315) pattern4316 = Pattern(Integral(sqrt(WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4316 = ReplacementRule(pattern4316, replacement4316) pattern4317 = Pattern(Integral(sqrt(WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4317 = ReplacementRule(pattern4317, replacement4317) pattern4318 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule4318 = ReplacementRule(pattern4318, replacement4318) pattern4319 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule4319 = ReplacementRule(pattern4319, replacement4319) pattern4320 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule4320 = ReplacementRule(pattern4320, replacement4320) pattern4321 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule4321 = ReplacementRule(pattern4321, replacement4321) pattern4322 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4322 = ReplacementRule(pattern4322, replacement4322) pattern4323 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4323 = ReplacementRule(pattern4323, replacement4323) pattern4324 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4324 = ReplacementRule(pattern4324, replacement4324) pattern4325 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4325 = ReplacementRule(pattern4325, replacement4325) pattern4326 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4326 = ReplacementRule(pattern4326, replacement4326) pattern4327 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4327 = ReplacementRule(pattern4327, replacement4327) pattern4328 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4328 = ReplacementRule(pattern4328, replacement4328) pattern4329 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4329 = ReplacementRule(pattern4329, replacement4329) pattern4330 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4330 = ReplacementRule(pattern4330, replacement4330) pattern4331 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4331 = ReplacementRule(pattern4331, replacement4331) pattern4332 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4332 = ReplacementRule(pattern4332, replacement4332) pattern4333 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4333 = ReplacementRule(pattern4333, replacement4333) pattern4334 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4334 = ReplacementRule(pattern4334, replacement4334) pattern4335 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4335 = ReplacementRule(pattern4335, replacement4335) pattern4336 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4336 = ReplacementRule(pattern4336, replacement4336) pattern4337 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1411) rule4337 = ReplacementRule(pattern4337, replacement4337) pattern4338 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4338 = ReplacementRule(pattern4338, replacement4338) pattern4339 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4339 = ReplacementRule(pattern4339, replacement4339) pattern4340 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4340 = ReplacementRule(pattern4340, replacement4340) pattern4341 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule4341 = ReplacementRule(pattern4341, replacement4341) pattern4342 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4342 = ReplacementRule(pattern4342, replacement4342) pattern4343 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(5)/2)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269) rule4343 = ReplacementRule(pattern4343, replacement4343) pattern4344 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule4344 = ReplacementRule(pattern4344, replacement4344) pattern4345 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule4345 = ReplacementRule(pattern4345, replacement4345) pattern4346 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule4346 = ReplacementRule(pattern4346, replacement4346) pattern4347 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule4347 = ReplacementRule(pattern4347, replacement4347) pattern4348 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4348 = ReplacementRule(pattern4348, replacement4348) pattern4349 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4349 = ReplacementRule(pattern4349, replacement4349) pattern4350 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule4350 = ReplacementRule(pattern4350, replacement4350) pattern4351 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule4351 = ReplacementRule(pattern4351, replacement4351) pattern4352 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4352 = ReplacementRule(pattern4352, replacement4352) pattern4353 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4353 = ReplacementRule(pattern4353, replacement4353) pattern4354 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4354 = ReplacementRule(pattern4354, replacement4354) pattern4355 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule4355 = ReplacementRule(pattern4355, replacement4355) pattern4356 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4356 = ReplacementRule(pattern4356, replacement4356) pattern4357 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule4357 = ReplacementRule(pattern4357, replacement4357) pattern4358 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1267, cons1325, cons1622) rule4358 = ReplacementRule(pattern4358, replacement4358) pattern4359 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1267, cons1325, cons1622) rule4359 = ReplacementRule(pattern4359, replacement4359) pattern4360 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons73, cons20, cons87) rule4360 = ReplacementRule(pattern4360, replacement4360) pattern4361 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons73, cons20, cons87) rule4361 = ReplacementRule(pattern4361, replacement4361) pattern4362 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons73, cons1623, cons20) rule4362 = ReplacementRule(pattern4362, replacement4362) pattern4363 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons73, cons1623, cons20) rule4363 = ReplacementRule(pattern4363, replacement4363) pattern4364 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1623, cons21) rule4364 = ReplacementRule(pattern4364, replacement4364) pattern4365 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1623, cons21) rule4365 = ReplacementRule(pattern4365, replacement4365) pattern4366 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(S(1)/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1306, cons1609, cons40, cons1624) rule4366 = ReplacementRule(pattern4366, replacement4366) pattern4367 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(S(1)/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1306, cons1609, cons40, cons1624) rule4367 = ReplacementRule(pattern4367, replacement4367) pattern4368 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1417) rule4368 = ReplacementRule(pattern4368, replacement4368) pattern4369 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1417) rule4369 = ReplacementRule(pattern4369, replacement4369) pattern4370 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons382) rule4370 = ReplacementRule(pattern4370, replacement4370) pattern4371 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons382) rule4371 = ReplacementRule(pattern4371, replacement4371) pattern4372 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1430) rule4372 = ReplacementRule(pattern4372, replacement4372) pattern4373 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1430) rule4373 = ReplacementRule(pattern4373, replacement4373) pattern4374 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons89, cons1588) rule4374 = ReplacementRule(pattern4374, replacement4374) pattern4375 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons89, cons1588) rule4375 = ReplacementRule(pattern4375, replacement4375) pattern4376 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1571) rule4376 = ReplacementRule(pattern4376, replacement4376) pattern4377 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1571) rule4377 = ReplacementRule(pattern4377, replacement4377) pattern4378 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1247) rule4378 = ReplacementRule(pattern4378, replacement4378) pattern4379 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1247) rule4379 = ReplacementRule(pattern4379, replacement4379) pattern4380 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons19, cons1247, cons1267, cons1625) rule4380 = ReplacementRule(pattern4380, replacement4380) pattern4381 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons19, cons1247, cons1267, cons1625) rule4381 = ReplacementRule(pattern4381, replacement4381) pattern4382 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1267, cons1626, cons33, cons1322) rule4382 = ReplacementRule(pattern4382, replacement4382) pattern4383 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1267, cons1626, cons33, cons1322) rule4383 = ReplacementRule(pattern4383, replacement4383) pattern4384 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons19, cons1247, cons1267, cons1626, cons1323) rule4384 = ReplacementRule(pattern4384, replacement4384) pattern4385 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons19, cons1247, cons1267, cons1626, cons1323) rule4385 = ReplacementRule(pattern4385, replacement4385) pattern4386 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1269, cons33, cons170) rule4386 = ReplacementRule(pattern4386, replacement4386) pattern4387 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1269, cons33, cons170) rule4387 = ReplacementRule(pattern4387, replacement4387) pattern4388 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1269, cons33, cons96) rule4388 = ReplacementRule(pattern4388, replacement4388) pattern4389 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1269, cons33, cons96) rule4389 = ReplacementRule(pattern4389, replacement4389) pattern4390 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1269, cons1627) rule4390 = ReplacementRule(pattern4390, replacement4390) pattern4391 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1269, cons1627) rule4391 = ReplacementRule(pattern4391, replacement4391) pattern4392 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1269, cons1628) rule4392 = ReplacementRule(pattern4392, replacement4392) pattern4393 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1269, cons1628) rule4393 = ReplacementRule(pattern4393, replacement4393) pattern4394 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1269, cons1627, cons79) rule4394 = ReplacementRule(pattern4394, replacement4394) pattern4395 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons1247, cons1269, cons1627, cons79) rule4395 = ReplacementRule(pattern4395, replacement4395) pattern4396 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons19, cons1247, cons1269) rule4396 = ReplacementRule(pattern4396, replacement4396) pattern4397 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons36, cons37, cons50, cons127, cons19, cons1247, cons1269) rule4397 = ReplacementRule(pattern4397, replacement4397) pattern4398 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1247, cons1267, cons33, cons1322) rule4398 = ReplacementRule(pattern4398, replacement4398) pattern4399 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1247, cons1267, cons33, cons1322) rule4399 = ReplacementRule(pattern4399, replacement4399) pattern4400 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1247, cons1269, cons33, cons96) rule4400 = ReplacementRule(pattern4400, replacement4400) pattern4401 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1247, cons1269, cons33, cons96) rule4401 = ReplacementRule(pattern4401, replacement4401) pattern4402 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons19, cons1247, cons274) rule4402 = ReplacementRule(pattern4402, replacement4402) pattern4403 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons19, cons1247, cons274) rule4403 = ReplacementRule(pattern4403, replacement4403) pattern4404 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons1247, cons1267, cons157, cons1629) rule4404 = ReplacementRule(pattern4404, replacement4404) pattern4405 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons1247, cons1267, cons157, cons1629) rule4405 = ReplacementRule(pattern4405, replacement4405) pattern4406 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons157, cons33, cons34) rule4406 = ReplacementRule(pattern4406, replacement4406) pattern4407 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons157, cons33, cons34) rule4407 = ReplacementRule(pattern4407, replacement4407) pattern4408 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons1247, cons1267, cons157, cons1551) rule4408 = ReplacementRule(pattern4408, replacement4408) pattern4409 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons1247, cons1267, cons157, cons1551) rule4409 = ReplacementRule(pattern4409, replacement4409) pattern4410 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons1630) rule4410 = ReplacementRule(pattern4410, replacement4410) pattern4411 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons1630) rule4411 = ReplacementRule(pattern4411, replacement4411) pattern4412 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1267, cons1631, cons89, cons465) rule4412 = ReplacementRule(pattern4412, replacement4412) pattern4413 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1267, cons1631, cons89, cons465) rule4413 = ReplacementRule(pattern4413, replacement4413) pattern4414 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons1631, cons1233) rule4414 = ReplacementRule(pattern4414, replacement4414) pattern4415 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons1631, cons1233) rule4415 = ReplacementRule(pattern4415, replacement4415) pattern4416 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1267, cons95, cons1425, cons91) rule4416 = ReplacementRule(pattern4416, replacement4416) pattern4417 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1267, cons95, cons1425, cons91) rule4417 = ReplacementRule(pattern4417, replacement4417) pattern4418 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons33, cons1425, cons348) rule4418 = ReplacementRule(pattern4418, replacement4418) pattern4419 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons33, cons1425, cons348) rule4419 = ReplacementRule(pattern4419, replacement4419) pattern4420 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1267, cons95, cons1322, cons90) rule4420 = ReplacementRule(pattern4420, replacement4420) pattern4421 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1267, cons95, cons1322, cons90) rule4421 = ReplacementRule(pattern4421, replacement4421) pattern4422 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons33, cons1322, cons1329) rule4422 = ReplacementRule(pattern4422, replacement4422) pattern4423 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1267, cons33, cons1322, cons1329) rule4423 = ReplacementRule(pattern4423, replacement4423) pattern4424 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1267, cons89, cons167) rule4424 = ReplacementRule(pattern4424, replacement4424) pattern4425 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1267, cons89, cons167) rule4425 = ReplacementRule(pattern4425, replacement4425) pattern4426 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1267, cons89, cons465) rule4426 = ReplacementRule(pattern4426, replacement4426) pattern4427 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1267, cons89, cons465) rule4427 = ReplacementRule(pattern4427, replacement4427) pattern4428 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1267) rule4428 = ReplacementRule(pattern4428, replacement4428) pattern4429 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1267) rule4429 = ReplacementRule(pattern4429, replacement4429) pattern4430 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons168, cons1588) rule4430 = ReplacementRule(pattern4430, replacement4430) pattern4431 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons168, cons1588) rule4431 = ReplacementRule(pattern4431, replacement4431) pattern4432 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1269, cons33, cons168, cons1632) rule4432 = ReplacementRule(pattern4432, replacement4432) pattern4433 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1269, cons33, cons168, cons1632) rule4433 = ReplacementRule(pattern4433, replacement4433) pattern4434 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons96, cons1327) rule4434 = ReplacementRule(pattern4434, replacement4434) pattern4435 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons96, cons1327) rule4435 = ReplacementRule(pattern4435, replacement4435) pattern4436 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons96, cons167) rule4436 = ReplacementRule(pattern4436, replacement4436) pattern4437 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons96, cons167) rule4437 = ReplacementRule(pattern4437, replacement4437) pattern4438 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1269, cons33, cons96, cons1633) rule4438 = ReplacementRule(pattern4438, replacement4438) pattern4439 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1269, cons33, cons96, cons1633) rule4439 = ReplacementRule(pattern4439, replacement4439) pattern4440 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons1258, cons90) rule4440 = ReplacementRule(pattern4440, replacement4440) pattern4441 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons1258, cons90) rule4441 = ReplacementRule(pattern4441, replacement4441) pattern4442 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons1258, cons1588) rule4442 = ReplacementRule(pattern4442, replacement4442) pattern4443 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269, cons95, cons1258, cons1588) rule4443 = ReplacementRule(pattern4443, replacement4443) pattern4444 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1269, cons89, cons167, cons1361, cons1634) rule4444 = ReplacementRule(pattern4444, replacement4444) pattern4445 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1269, cons89, cons167, cons1361, cons1634) rule4445 = ReplacementRule(pattern4445, replacement4445) pattern4446 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1269, cons89, cons1588) rule4446 = ReplacementRule(pattern4446, replacement4446) pattern4447 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons1247, cons1269, cons89, cons1588) rule4447 = ReplacementRule(pattern4447, replacement4447) pattern4448 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269) rule4448 = ReplacementRule(pattern4448, replacement4448) pattern4449 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269) rule4449 = ReplacementRule(pattern4449, replacement4449) pattern4450 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269) rule4450 = ReplacementRule(pattern4450, replacement4450) pattern4451 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269) rule4451 = ReplacementRule(pattern4451, replacement4451) pattern4452 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269) rule4452 = ReplacementRule(pattern4452, replacement4452) pattern4453 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1247, cons1269) rule4453 = ReplacementRule(pattern4453, replacement4453) pattern4454 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1269) rule4454 = ReplacementRule(pattern4454, replacement4454) pattern4455 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons4, cons1247, cons1269) rule4455 = ReplacementRule(pattern4455, replacement4455) pattern4456 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons1247, cons1269) rule4456 = ReplacementRule(pattern4456, replacement4456) pattern4457 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons1247, cons1269) rule4457 = ReplacementRule(pattern4457, replacement4457) pattern4458 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons5, cons72, cons1267, cons377) rule4458 = ReplacementRule(pattern4458, replacement4458) pattern4459 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons5, cons72, cons1267, cons377) rule4459 = ReplacementRule(pattern4459, replacement4459) pattern4460 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons35) rule4460 = ReplacementRule(pattern4460, replacement4460) pattern4461 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons35) rule4461 = ReplacementRule(pattern4461, replacement4461) pattern4462 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1435) rule4462 = ReplacementRule(pattern4462, replacement4462) pattern4463 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1435) rule4463 = ReplacementRule(pattern4463, replacement4463) pattern4464 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons1635) rule4464 = ReplacementRule(pattern4464, replacement4464) pattern4465 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons1635) rule4465 = ReplacementRule(pattern4465, replacement4465) pattern4466 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons1636, cons33, cons34) rule4466 = ReplacementRule(pattern4466, replacement4466) pattern4467 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons1636, cons33, cons34) rule4467 = ReplacementRule(pattern4467, replacement4467) pattern4468 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons1636, cons1551) rule4468 = ReplacementRule(pattern4468, replacement4468) pattern4469 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons1636, cons1551) rule4469 = ReplacementRule(pattern4469, replacement4469) pattern4470 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons37, cons38, cons19, cons1433) rule4470 = ReplacementRule(pattern4470, replacement4470) pattern4471 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons37, cons38, cons19, cons1433) rule4471 = ReplacementRule(pattern4471, replacement4471) pattern4472 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1637) rule4472 = ReplacementRule(pattern4472, replacement4472) pattern4473 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1637) rule4473 = ReplacementRule(pattern4473, replacement4473) pattern4474 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1638) rule4474 = ReplacementRule(pattern4474, replacement4474) pattern4475 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1638) rule4475 = ReplacementRule(pattern4475, replacement4475) pattern4476 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1639) rule4476 = ReplacementRule(pattern4476, replacement4476) pattern4477 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1639) rule4477 = ReplacementRule(pattern4477, replacement4477) pattern4478 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1638) rule4478 = ReplacementRule(pattern4478, replacement4478) pattern4479 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1638) rule4479 = ReplacementRule(pattern4479, replacement4479) pattern4480 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1639) rule4480 = ReplacementRule(pattern4480, replacement4480) pattern4481 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1639) rule4481 = ReplacementRule(pattern4481, replacement4481) pattern4482 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1267, cons33, cons1322) rule4482 = ReplacementRule(pattern4482, replacement4482) pattern4483 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1267, cons33, cons1322) rule4483 = ReplacementRule(pattern4483, replacement4483) pattern4484 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1267, cons33, cons1322) rule4484 = ReplacementRule(pattern4484, replacement4484) pattern4485 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1267, cons33, cons1322) rule4485 = ReplacementRule(pattern4485, replacement4485) pattern4486 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1267, cons1323) rule4486 = ReplacementRule(pattern4486, replacement4486) pattern4487 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1267, cons1323) rule4487 = ReplacementRule(pattern4487, replacement4487) pattern4488 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1267, cons1323) rule4488 = ReplacementRule(pattern4488, replacement4488) pattern4489 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1267, cons1323) rule4489 = ReplacementRule(pattern4489, replacement4489) pattern4490 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269, cons1640) rule4490 = ReplacementRule(pattern4490, replacement4490) pattern4491 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269, cons1640) rule4491 = ReplacementRule(pattern4491, replacement4491) pattern4492 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269, cons1640) rule4492 = ReplacementRule(pattern4492, replacement4492) pattern4493 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269, cons1640) rule4493 = ReplacementRule(pattern4493, replacement4493) pattern4494 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269) rule4494 = ReplacementRule(pattern4494, replacement4494) pattern4495 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269) rule4495 = ReplacementRule(pattern4495, replacement4495) pattern4496 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269) rule4496 = ReplacementRule(pattern4496, replacement4496) pattern4497 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269) rule4497 = ReplacementRule(pattern4497, replacement4497) pattern4498 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269, cons517, cons96) rule4498 = ReplacementRule(pattern4498, replacement4498) pattern4499 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269, cons33, cons96) rule4499 = ReplacementRule(pattern4499, replacement4499) pattern4500 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269, cons517, cons96) rule4500 = ReplacementRule(pattern4500, replacement4500) pattern4501 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269, cons517, cons96) rule4501 = ReplacementRule(pattern4501, replacement4501) pattern4502 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons79) rule4502 = ReplacementRule(pattern4502, replacement4502) pattern4503 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons79) rule4503 = ReplacementRule(pattern4503, replacement4503) pattern4504 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1269, cons79) rule4504 = ReplacementRule(pattern4504, replacement4504) pattern4505 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1269, cons79) rule4505 = ReplacementRule(pattern4505, replacement4505) pattern4506 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons21) rule4506 = ReplacementRule(pattern4506, replacement4506) pattern4507 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons21) rule4507 = ReplacementRule(pattern4507, replacement4507) pattern4508 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons21) rule4508 = ReplacementRule(pattern4508, replacement4508) pattern4509 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons21) rule4509 = ReplacementRule(pattern4509, replacement4509) pattern4510 = Pattern(Integral(((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons5, cons21) rule4510 = ReplacementRule(pattern4510, replacement4510) pattern4511 = Pattern(Integral(((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons5, cons21) rule4511 = ReplacementRule(pattern4511, replacement4511) pattern4512 = Pattern(Integral(((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons5, cons21) rule4512 = ReplacementRule(pattern4512, replacement4512) pattern4513 = Pattern(Integral(((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons5, cons21) rule4513 = ReplacementRule(pattern4513, replacement4513) pattern4514 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons89, cons91) rule4514 = ReplacementRule(pattern4514, replacement4514) pattern4515 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons89, cons91) rule4515 = ReplacementRule(pattern4515, replacement4515) pattern4516 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons89, cons91) rule4516 = ReplacementRule(pattern4516, replacement4516) pattern4517 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons89, cons91) rule4517 = ReplacementRule(pattern4517, replacement4517) pattern4518 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons348) rule4518 = ReplacementRule(pattern4518, replacement4518) pattern4519 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons348) rule4519 = ReplacementRule(pattern4519, replacement4519) pattern4520 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons348) rule4520 = ReplacementRule(pattern4520, replacement4520) pattern4521 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons348) rule4521 = ReplacementRule(pattern4521, replacement4521) pattern4522 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1267) rule4522 = ReplacementRule(pattern4522, replacement4522) pattern4523 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1267) rule4523 = ReplacementRule(pattern4523, replacement4523) pattern4524 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1267) rule4524 = ReplacementRule(pattern4524, replacement4524) pattern4525 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1267) rule4525 = ReplacementRule(pattern4525, replacement4525) pattern4526 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1269) rule4526 = ReplacementRule(pattern4526, replacement4526) pattern4527 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1269) rule4527 = ReplacementRule(pattern4527, replacement4527) pattern4528 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1269) rule4528 = ReplacementRule(pattern4528, replacement4528) pattern4529 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1269) rule4529 = ReplacementRule(pattern4529, replacement4529) pattern4530 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons274) rule4530 = ReplacementRule(pattern4530, replacement4530) pattern4531 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons274) rule4531 = ReplacementRule(pattern4531, replacement4531) pattern4532 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons274) rule4532 = ReplacementRule(pattern4532, replacement4532) pattern4533 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons274) rule4533 = ReplacementRule(pattern4533, replacement4533) pattern4534 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons1267, cons33, cons1322) rule4534 = ReplacementRule(pattern4534, replacement4534) pattern4535 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons1267, cons33, cons1322) rule4535 = ReplacementRule(pattern4535, replacement4535) pattern4536 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons1267, cons33, cons1322) rule4536 = ReplacementRule(pattern4536, replacement4536) pattern4537 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons1267, cons33, cons1322) rule4537 = ReplacementRule(pattern4537, replacement4537) pattern4538 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons1267, cons1323, cons1641) rule4538 = ReplacementRule(pattern4538, replacement4538) pattern4539 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons1267, cons1323, cons1641) rule4539 = ReplacementRule(pattern4539, replacement4539) pattern4540 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons1267, cons1323, cons1641) rule4540 = ReplacementRule(pattern4540, replacement4540) pattern4541 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons1267, cons1323, cons1641) rule4541 = ReplacementRule(pattern4541, replacement4541) pattern4542 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons1267, cons1323, cons1642, cons685) rule4542 = ReplacementRule(pattern4542, replacement4542) pattern4543 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons1267, cons1323, cons1642, cons685) rule4543 = ReplacementRule(pattern4543, replacement4543) pattern4544 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons1267, cons1323, cons1642, cons685) rule4544 = ReplacementRule(pattern4544, replacement4544) pattern4545 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons1267, cons1323, cons1642, cons685) rule4545 = ReplacementRule(pattern4545, replacement4545) pattern4546 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269, cons33, cons96) rule4546 = ReplacementRule(pattern4546, replacement4546) pattern4547 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1269, cons33, cons96) rule4547 = ReplacementRule(pattern4547, replacement4547) pattern4548 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269, cons33, cons96) rule4548 = ReplacementRule(pattern4548, replacement4548) pattern4549 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1269, cons33, cons96) rule4549 = ReplacementRule(pattern4549, replacement4549) pattern4550 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons274) rule4550 = ReplacementRule(pattern4550, replacement4550) pattern4551 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons274) rule4551 = ReplacementRule(pattern4551, replacement4551) pattern4552 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1269, cons274) rule4552 = ReplacementRule(pattern4552, replacement4552) pattern4553 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1269, cons274) rule4553 = ReplacementRule(pattern4553, replacement4553) pattern4554 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269, cons95, cons170, cons1588) rule4554 = ReplacementRule(pattern4554, replacement4554) pattern4555 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269, cons95, cons170, cons1588) rule4555 = ReplacementRule(pattern4555, replacement4555) pattern4556 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269, cons95, cons170, cons1588) rule4556 = ReplacementRule(pattern4556, replacement4556) pattern4557 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269, cons95, cons170, cons1588) rule4557 = ReplacementRule(pattern4557, replacement4557) pattern4558 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons1269, cons33, cons170, cons1571) rule4558 = ReplacementRule(pattern4558, replacement4558) pattern4559 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons1269, cons33, cons170, cons1571) rule4559 = ReplacementRule(pattern4559, replacement4559) pattern4560 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons1269, cons33, cons170, cons1571) rule4560 = ReplacementRule(pattern4560, replacement4560) pattern4561 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons1269, cons33, cons170, cons1571) rule4561 = ReplacementRule(pattern4561, replacement4561) pattern4562 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269, cons95, cons96, cons90) rule4562 = ReplacementRule(pattern4562, replacement4562) pattern4563 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269, cons95, cons96, cons90) rule4563 = ReplacementRule(pattern4563, replacement4563) pattern4564 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269, cons95, cons96, cons90) rule4564 = ReplacementRule(pattern4564, replacement4564) pattern4565 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269, cons95, cons96, cons90) rule4565 = ReplacementRule(pattern4565, replacement4565) pattern4566 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons1269, cons33, cons96, cons1633) rule4566 = ReplacementRule(pattern4566, replacement4566) pattern4567 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons1269, cons33, cons96, cons1633) rule4567 = ReplacementRule(pattern4567, replacement4567) pattern4568 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons1269, cons33, cons96, cons1633) rule4568 = ReplacementRule(pattern4568, replacement4568) pattern4569 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons1269, cons33, cons96, cons1633) rule4569 = ReplacementRule(pattern4569, replacement4569) pattern4570 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons89, cons90) rule4570 = ReplacementRule(pattern4570, replacement4570) pattern4571 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons89, cons90) rule4571 = ReplacementRule(pattern4571, replacement4571) pattern4572 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons1269, cons89, cons90) rule4572 = ReplacementRule(pattern4572, replacement4572) pattern4573 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons1269, cons89, cons90) rule4573 = ReplacementRule(pattern4573, replacement4573) pattern4574 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons89, cons1588) rule4574 = ReplacementRule(pattern4574, replacement4574) pattern4575 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons1269, cons89, cons1588) rule4575 = ReplacementRule(pattern4575, replacement4575) pattern4576 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons1269, cons89, cons1588) rule4576 = ReplacementRule(pattern4576, replacement4576) pattern4577 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons1269, cons89, cons1588) rule4577 = ReplacementRule(pattern4577, replacement4577) pattern4578 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269) rule4578 = ReplacementRule(pattern4578, replacement4578) pattern4579 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269) rule4579 = ReplacementRule(pattern4579, replacement4579) pattern4580 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269) rule4580 = ReplacementRule(pattern4580, replacement4580) pattern4581 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269) rule4581 = ReplacementRule(pattern4581, replacement4581) pattern4582 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269) rule4582 = ReplacementRule(pattern4582, replacement4582) pattern4583 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269) rule4583 = ReplacementRule(pattern4583, replacement4583) pattern4584 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269) rule4584 = ReplacementRule(pattern4584, replacement4584) pattern4585 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269) rule4585 = ReplacementRule(pattern4585, replacement4585) pattern4586 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons1643) rule4586 = ReplacementRule(pattern4586, replacement4586) pattern4587 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons1643) rule4587 = ReplacementRule(pattern4587, replacement4587) pattern4588 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons1644) rule4588 = ReplacementRule(pattern4588, replacement4588) pattern4589 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons1644) rule4589 = ReplacementRule(pattern4589, replacement4589) pattern4590 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons25, cons20) rule4590 = ReplacementRule(pattern4590, replacement4590) pattern4591 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons25, cons20) rule4591 = ReplacementRule(pattern4591, replacement4591) pattern4592 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons25, cons20) rule4592 = ReplacementRule(pattern4592, replacement4592) pattern4593 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons4, cons25, cons20) rule4593 = ReplacementRule(pattern4593, replacement4593) pattern4594 = Pattern(Integral(((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons25) rule4594 = ReplacementRule(pattern4594, replacement4594) pattern4595 = Pattern(Integral(((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons25) rule4595 = ReplacementRule(pattern4595, replacement4595) pattern4596 = Pattern(Integral(((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons5, cons25) rule4596 = ReplacementRule(pattern4596, replacement4596) pattern4597 = Pattern(Integral(((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons5, cons25) rule4597 = ReplacementRule(pattern4597, replacement4597) pattern4598 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**n_, x_), cons3, cons8, cons29, cons4, cons1645) rule4598 = ReplacementRule(pattern4598, replacement4598) pattern4599 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**n_, x_), cons3, cons8, cons29, cons4, cons1645) rule4599 = ReplacementRule(pattern4599, replacement4599) pattern4600 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1456) rule4600 = ReplacementRule(pattern4600, replacement4600) pattern4601 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1456) rule4601 = ReplacementRule(pattern4601, replacement4601) pattern4602 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons1480) rule4602 = ReplacementRule(pattern4602, replacement4602) pattern4603 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons1480) rule4603 = ReplacementRule(pattern4603, replacement4603) pattern4604 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1480, cons56) rule4604 = ReplacementRule(pattern4604, replacement4604) pattern4605 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1480, cons56) rule4605 = ReplacementRule(pattern4605, replacement4605) pattern4606 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons5, cons1482, cons1481) rule4606 = ReplacementRule(pattern4606, With4606) pattern4607 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons5, cons1482, cons1481) rule4607 = ReplacementRule(pattern4607, With4607) pattern4608 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1483, cons378) rule4608 = ReplacementRule(pattern4608, With4608) pattern4609 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1483, cons378) rule4609 = ReplacementRule(pattern4609, With4609) pattern4610 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*(S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons5, cons1482, cons1481) rule4610 = ReplacementRule(pattern4610, With4610) pattern4611 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*(S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons5, cons1482, cons1481) rule4611 = ReplacementRule(pattern4611, With4611) pattern4612 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*(S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1483, cons1481, cons40) rule4612 = ReplacementRule(pattern4612, With4612) pattern4613 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*(S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1483, cons1481, cons40) rule4613 = ReplacementRule(pattern4613, With4613) pattern4614 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*(S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons377) rule4614 = ReplacementRule(pattern4614, replacement4614) pattern4615 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*(S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons377) rule4615 = ReplacementRule(pattern4615, replacement4615) pattern4616 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1483, cons87, cons40) rule4616 = ReplacementRule(pattern4616, With4616) pattern4617 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1483, cons87, cons40) rule4617 = ReplacementRule(pattern4617, With4617) pattern4618 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1482, cons1481) rule4618 = ReplacementRule(pattern4618, With4618) pattern4619 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1482, cons1481) rule4619 = ReplacementRule(pattern4619, With4619) pattern4620 = Pattern(Integral(((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons40) rule4620 = ReplacementRule(pattern4620, replacement4620) pattern4621 = Pattern(Integral(((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons40) rule4621 = ReplacementRule(pattern4621, replacement4621) pattern4622 = Pattern(Integral(((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons48, cons47, cons149) rule4622 = ReplacementRule(pattern4622, replacement4622) pattern4623 = Pattern(Integral(((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons48, cons47, cons149) rule4623 = ReplacementRule(pattern4623, replacement4623) pattern4624 = Pattern(Integral(S(1)/((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228) rule4624 = ReplacementRule(pattern4624, With4624) pattern4625 = Pattern(Integral(S(1)/((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228) rule4625 = ReplacementRule(pattern4625, With4625) pattern4626 = Pattern(Integral(((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**n2_*WC('c', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1483, cons378) rule4626 = ReplacementRule(pattern4626, With4626) pattern4627 = Pattern(Integral(((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**n2_*WC('c', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1483, cons378) rule4627 = ReplacementRule(pattern4627, With4627) pattern4628 = Pattern(Integral(((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**n2_*WC('c', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons48, cons1482, cons1481) rule4628 = ReplacementRule(pattern4628, With4628) pattern4629 = Pattern(Integral(((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**n2_*WC('c', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons48, cons1482, cons1481) rule4629 = ReplacementRule(pattern4629, With4629) pattern4630 = Pattern(Integral(((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule4630 = ReplacementRule(pattern4630, replacement4630) pattern4631 = Pattern(Integral(((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule4631 = ReplacementRule(pattern4631, replacement4631) pattern4632 = Pattern(Integral(((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule4632 = ReplacementRule(pattern4632, replacement4632) pattern4633 = Pattern(Integral(((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule4633 = ReplacementRule(pattern4633, replacement4633) pattern4634 = Pattern(Integral(((S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons377) rule4634 = ReplacementRule(pattern4634, replacement4634) pattern4635 = Pattern(Integral(((S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons377) rule4635 = ReplacementRule(pattern4635, replacement4635) pattern4636 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons1483, cons87, cons40) rule4636 = ReplacementRule(pattern4636, With4636) pattern4637 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons1483, cons87, cons40) rule4637 = ReplacementRule(pattern4637, With4637) pattern4638 = Pattern(Integral((a_ + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons1481) rule4638 = ReplacementRule(pattern4638, With4638) pattern4639 = Pattern(Integral((a_ + (S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + (S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons1481) rule4639 = ReplacementRule(pattern4639, With4639) pattern4640 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons87) rule4640 = ReplacementRule(pattern4640, replacement4640) pattern4641 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons87) rule4641 = ReplacementRule(pattern4641, replacement4641) pattern4642 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons25) rule4642 = ReplacementRule(pattern4642, replacement4642) pattern4643 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons25) rule4643 = ReplacementRule(pattern4643, replacement4643) pattern4644 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228) rule4644 = ReplacementRule(pattern4644, With4644) pattern4645 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228) rule4645 = ReplacementRule(pattern4645, With4645) pattern4646 = Pattern(Integral((A_ + WC('B', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228, cons87) rule4646 = ReplacementRule(pattern4646, replacement4646) pattern4647 = Pattern(Integral((A_ + WC('B', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228, cons87) rule4647 = ReplacementRule(pattern4647, replacement4647) pattern4648 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons64) rule4648 = ReplacementRule(pattern4648, replacement4648) pattern4649 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons64) rule4649 = ReplacementRule(pattern4649, replacement4649) pattern4650 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons8, cons29, cons50, cons127, cons33, cons170) rule4650 = ReplacementRule(pattern4650, replacement4650) pattern4651 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons8, cons29, cons50, cons127, cons33, cons170) rule4651 = ReplacementRule(pattern4651, replacement4651) pattern4652 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons167, cons1646) rule4652 = ReplacementRule(pattern4652, replacement4652) pattern4653 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons167, cons1646) rule4653 = ReplacementRule(pattern4653, replacement4653) pattern4654 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons1646, cons168) rule4654 = ReplacementRule(pattern4654, replacement4654) pattern4655 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons1646, cons168) rule4655 = ReplacementRule(pattern4655, replacement4655) pattern4656 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons91) rule4656 = ReplacementRule(pattern4656, replacement4656) pattern4657 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons91) rule4657 = ReplacementRule(pattern4657, replacement4657) pattern4658 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons168) rule4658 = ReplacementRule(pattern4658, replacement4658) pattern4659 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons168) rule4659 = ReplacementRule(pattern4659, replacement4659) pattern4660 = Pattern(Integral((WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons25) rule4660 = ReplacementRule(pattern4660, replacement4660) pattern4661 = Pattern(Integral((WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons25) rule4661 = ReplacementRule(pattern4661, replacement4661) pattern4662 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule4662 = ReplacementRule(pattern4662, replacement4662) pattern4663 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule4663 = ReplacementRule(pattern4663, replacement4663) pattern4664 = Pattern(Integral((a_ + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons198, cons64) rule4664 = ReplacementRule(pattern4664, replacement4664) pattern4665 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons198, cons64) rule4665 = ReplacementRule(pattern4665, replacement4665) pattern4666 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule4666 = ReplacementRule(pattern4666, replacement4666) pattern4667 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule4667 = ReplacementRule(pattern4667, replacement4667) pattern4668 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule4668 = ReplacementRule(pattern4668, replacement4668) pattern4669 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule4669 = ReplacementRule(pattern4669, replacement4669) pattern4670 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule4670 = ReplacementRule(pattern4670, replacement4670) pattern4671 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule4671 = ReplacementRule(pattern4671, replacement4671) pattern4672 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule4672 = ReplacementRule(pattern4672, replacement4672) pattern4673 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule4673 = ReplacementRule(pattern4673, replacement4673) pattern4674 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule4674 = ReplacementRule(pattern4674, replacement4674) pattern4675 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule4675 = ReplacementRule(pattern4675, replacement4675) pattern4676 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule4676 = ReplacementRule(pattern4676, replacement4676) pattern4677 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule4677 = ReplacementRule(pattern4677, replacement4677) pattern4678 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule4678 = ReplacementRule(pattern4678, replacement4678) pattern4679 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule4679 = ReplacementRule(pattern4679, replacement4679) pattern4680 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule4680 = ReplacementRule(pattern4680, replacement4680) pattern4681 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule4681 = ReplacementRule(pattern4681, replacement4681) pattern4682 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule4682 = ReplacementRule(pattern4682, replacement4682) pattern4683 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule4683 = ReplacementRule(pattern4683, replacement4683) pattern4684 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule4684 = ReplacementRule(pattern4684, replacement4684) pattern4685 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule4685 = ReplacementRule(pattern4685, replacement4685) pattern4686 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cos(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**p_*sin(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1647) rule4686 = ReplacementRule(pattern4686, replacement4686) pattern4687 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sin(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**p_*cos(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1647) rule4687 = ReplacementRule(pattern4687, replacement4687) return [rule3920, rule3921, rule3922, rule3923, rule3924, rule3925, rule3926, rule3927, rule3928, rule3929, rule3930, rule3931, rule3932, rule3933, rule3934, rule3935, rule3936, rule3937, rule3938, rule3939, rule3940, rule3941, rule3942, rule3943, rule3944, rule3945, rule3946, rule3947, rule3948, rule3949, rule3950, rule3951, rule3952, rule3953, rule3954, rule3955, rule3956, rule3957, rule3958, rule3959, rule3960, rule3961, rule3962, rule3963, rule3964, rule3965, rule3966, rule3967, rule3968, rule3969, rule3970, rule3971, rule3972, rule3973, rule3974, rule3975, rule3976, rule3977, rule3978, rule3979, rule3980, rule3981, rule3982, rule3983, rule3984, rule3985, rule3986, rule3987, rule3988, rule3989, rule3990, rule3991, rule3992, rule3993, rule3994, rule3995, rule3996, rule3997, rule3998, rule3999, rule4000, rule4001, rule4002, rule4003, rule4004, rule4005, rule4006, rule4007, rule4008, rule4009, rule4010, rule4011, rule4012, rule4013, rule4014, rule4015, rule4016, rule4017, rule4018, rule4019, rule4020, rule4021, rule4022, rule4023, rule4024, rule4025, rule4026, rule4027, rule4028, rule4029, rule4030, rule4031, rule4032, rule4033, rule4034, rule4035, rule4036, rule4037, rule4038, rule4039, rule4040, rule4041, rule4042, rule4043, rule4044, rule4045, rule4046, rule4047, rule4048, rule4049, rule4050, rule4051, rule4052, rule4053, rule4054, rule4055, rule4056, rule4057, rule4058, rule4059, rule4060, rule4061, rule4062, rule4063, rule4064, rule4065, rule4066, rule4067, rule4068, rule4069, rule4070, rule4071, rule4072, rule4073, rule4074, rule4075, rule4076, rule4077, rule4078, rule4079, rule4080, rule4081, rule4082, rule4083, rule4084, rule4085, rule4086, rule4087, rule4088, rule4089, rule4090, rule4091, rule4092, rule4093, rule4094, rule4095, rule4096, rule4097, rule4098, rule4099, rule4100, rule4101, rule4102, rule4103, rule4104, rule4105, rule4106, rule4107, rule4108, rule4109, rule4110, rule4111, rule4112, rule4113, rule4114, rule4115, rule4116, rule4117, rule4118, rule4119, rule4120, rule4121, rule4122, rule4123, rule4124, rule4125, rule4126, rule4127, rule4128, rule4129, rule4130, rule4131, rule4132, rule4133, rule4134, rule4135, rule4136, rule4137, rule4138, rule4139, rule4140, rule4141, rule4142, rule4143, rule4144, rule4145, rule4146, rule4147, rule4148, rule4149, rule4150, rule4151, rule4152, rule4153, rule4154, rule4155, rule4156, rule4157, rule4158, rule4159, rule4160, rule4161, rule4162, rule4163, rule4164, rule4165, rule4166, rule4167, rule4168, rule4169, rule4170, rule4171, rule4172, rule4173, rule4174, rule4175, rule4176, rule4177, rule4178, rule4179, rule4180, rule4181, rule4182, rule4183, rule4184, rule4185, rule4186, rule4187, rule4188, rule4189, rule4190, rule4191, rule4192, rule4193, rule4194, rule4195, rule4196, rule4197, rule4198, rule4199, rule4200, rule4201, rule4202, rule4203, rule4204, rule4205, rule4206, rule4207, rule4208, rule4209, rule4210, rule4211, rule4212, rule4213, rule4214, rule4215, rule4216, rule4217, rule4218, rule4219, rule4220, rule4221, rule4222, rule4223, rule4224, rule4225, rule4226, rule4227, rule4228, rule4229, rule4230, rule4231, rule4232, rule4233, rule4234, rule4235, rule4236, rule4237, rule4238, rule4239, rule4240, rule4241, rule4242, rule4243, rule4244, rule4245, rule4246, rule4247, rule4248, rule4249, rule4250, rule4251, rule4252, rule4253, rule4254, rule4255, rule4256, rule4257, rule4258, rule4259, rule4260, rule4261, rule4262, rule4263, rule4264, rule4265, rule4266, rule4267, rule4268, rule4269, rule4270, rule4271, rule4272, rule4273, rule4274, rule4275, rule4276, rule4277, rule4278, rule4279, rule4280, rule4281, rule4282, rule4283, rule4284, rule4285, rule4286, rule4287, rule4288, rule4289, rule4290, rule4291, rule4292, rule4293, rule4294, rule4295, rule4296, rule4297, rule4298, rule4299, rule4300, rule4301, rule4302, rule4303, rule4304, rule4305, rule4306, rule4307, rule4308, rule4309, rule4310, rule4311, rule4312, rule4313, rule4314, rule4315, rule4316, rule4317, rule4318, rule4319, rule4320, rule4321, rule4322, rule4323, rule4324, rule4325, rule4326, rule4327, rule4328, rule4329, rule4330, rule4331, rule4332, rule4333, rule4334, rule4335, rule4336, rule4337, rule4338, rule4339, rule4340, rule4341, rule4342, rule4343, rule4344, rule4345, rule4346, rule4347, rule4348, rule4349, rule4350, rule4351, rule4352, rule4353, rule4354, rule4355, rule4356, rule4357, rule4358, rule4359, rule4360, rule4361, rule4362, rule4363, rule4364, rule4365, rule4366, rule4367, rule4368, rule4369, rule4370, rule4371, rule4372, rule4373, rule4374, rule4375, rule4376, rule4377, rule4378, rule4379, rule4380, rule4381, rule4382, rule4383, rule4384, rule4385, rule4386, rule4387, rule4388, rule4389, rule4390, rule4391, rule4392, rule4393, rule4394, rule4395, rule4396, rule4397, rule4398, rule4399, rule4400, rule4401, rule4402, rule4403, rule4404, rule4405, rule4406, rule4407, rule4408, rule4409, rule4410, rule4411, rule4412, rule4413, rule4414, rule4415, rule4416, rule4417, rule4418, rule4419, rule4420, rule4421, rule4422, rule4423, rule4424, rule4425, rule4426, rule4427, rule4428, rule4429, rule4430, rule4431, rule4432, rule4433, rule4434, rule4435, rule4436, rule4437, rule4438, rule4439, rule4440, rule4441, rule4442, rule4443, rule4444, rule4445, rule4446, rule4447, rule4448, rule4449, rule4450, rule4451, rule4452, rule4453, rule4454, rule4455, rule4456, rule4457, rule4458, rule4459, rule4460, rule4461, rule4462, rule4463, rule4464, rule4465, rule4466, rule4467, rule4468, rule4469, rule4470, rule4471, rule4472, rule4473, rule4474, rule4475, rule4476, rule4477, rule4478, rule4479, rule4480, rule4481, rule4482, rule4483, rule4484, rule4485, rule4486, rule4487, rule4488, rule4489, rule4490, rule4491, rule4492, rule4493, rule4494, rule4495, rule4496, rule4497, rule4498, rule4499, rule4500, rule4501, rule4502, rule4503, rule4504, rule4505, rule4506, rule4507, rule4508, rule4509, rule4510, rule4511, rule4512, rule4513, rule4514, rule4515, rule4516, rule4517, rule4518, rule4519, rule4520, rule4521, rule4522, rule4523, rule4524, rule4525, rule4526, rule4527, rule4528, rule4529, rule4530, rule4531, rule4532, rule4533, rule4534, rule4535, rule4536, rule4537, rule4538, rule4539, rule4540, rule4541, rule4542, rule4543, rule4544, rule4545, rule4546, rule4547, rule4548, rule4549, rule4550, rule4551, rule4552, rule4553, rule4554, rule4555, rule4556, rule4557, rule4558, rule4559, rule4560, rule4561, rule4562, rule4563, rule4564, rule4565, rule4566, rule4567, rule4568, rule4569, rule4570, rule4571, rule4572, rule4573, rule4574, rule4575, rule4576, rule4577, rule4578, rule4579, rule4580, rule4581, rule4582, rule4583, rule4584, rule4585, rule4586, rule4587, rule4588, rule4589, rule4590, rule4591, rule4592, rule4593, rule4594, rule4595, rule4596, rule4597, rule4598, rule4599, rule4600, rule4601, rule4602, rule4603, rule4604, rule4605, rule4606, rule4607, rule4608, rule4609, rule4610, rule4611, rule4612, rule4613, rule4614, rule4615, rule4616, rule4617, rule4618, rule4619, rule4620, rule4621, rule4622, rule4623, rule4624, rule4625, rule4626, rule4627, rule4628, rule4629, rule4630, rule4631, rule4632, rule4633, rule4634, rule4635, rule4636, rule4637, rule4638, rule4639, rule4640, rule4641, rule4642, rule4643, rule4644, rule4645, rule4646, rule4647, rule4648, rule4649, rule4650, rule4651, rule4652, rule4653, rule4654, rule4655, rule4656, rule4657, rule4658, rule4659, rule4660, rule4661, rule4662, rule4663, rule4664, rule4665, rule4666, rule4667, rule4668, rule4669, rule4670, rule4671, rule4672, rule4673, rule4674, rule4675, rule4676, rule4677, rule4678, rule4679, rule4680, rule4681, rule4682, rule4683, rule4684, rule4685, rule4686, rule4687, ] def replacement3920(a, b, e, f, m, n, x): return Simp(a*b*(a/sin(e + f*x))**(m + S(-1))*(b/cos(e + f*x))**(n + S(-1))/(f*(n + S(-1))), x) def replacement3921(e, f, m, n, x): return Dist(S(1)/f, Subst(Int(x**(-m)*(x**S(2) + S(1))**(m/S(2) + n/S(2) + S(-1)), x), x, tan(e + f*x)), x) def replacement3922(a, e, f, m, n, x): return -Dist(a**(S(1) - n)/f, Subst(Int((a*x)**(m + n + S(-1))*(x**S(2) + S(-1))**(-n/S(2) + S(-1)/2), x), x, S(1)/sin(e + f*x)), x) def replacement3923(a, e, f, m, n, x): return Dist(a**(S(1) - n)/f, Subst(Int((a*x)**(m + n + S(-1))*(x**S(2) + S(-1))**(-n/S(2) + S(-1)/2), x), x, S(1)/cos(e + f*x)), x) def replacement3924(a, b, e, f, m, n, x): return Dist(a**S(2)*(n + S(1))/(b**S(2)*(m + S(-1))), Int((a/sin(e + f*x))**(m + S(-2))*(b/cos(e + f*x))**(n + S(2)), x), x) - Simp(a*(a/sin(e + f*x))**(m + S(-1))*(b/cos(e + f*x))**(n + S(1))/(b*f*(m + S(-1))), x) def replacement3925(a, b, e, f, m, n, x): return Dist(b**S(2)*(m + S(1))/(a**S(2)*(n + S(-1))), Int((a/sin(e + f*x))**(m + S(2))*(b/cos(e + f*x))**(n + S(-2)), x), x) + Simp(b*(a/sin(e + f*x))**(m + S(1))*(b/cos(e + f*x))**(n + S(-1))/(a*f*(n + S(-1))), x) def replacement3926(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + n + S(-2))/(m + S(-1)), Int((a/sin(e + f*x))**(m + S(-2))*(b/cos(e + f*x))**n, x), x) - Simp(a*b*(a/sin(e + f*x))**(m + S(-1))*(b/cos(e + f*x))**(n + S(-1))/(f*(m + S(-1))), x) def replacement3927(a, b, e, f, m, n, x): return Dist(b**S(2)*(m + n + S(-2))/(n + S(-1)), Int((a/sin(e + f*x))**m*(b/cos(e + f*x))**(n + S(-2)), x), x) + Simp(a*b*(a/sin(e + f*x))**(m + S(-1))*(b/cos(e + f*x))**(n + S(-1))/(f*(n + S(-1))), x) def replacement3928(a, b, e, f, m, n, x): return Dist((m + S(1))/(a**S(2)*(m + n)), Int((a/sin(e + f*x))**(m + S(2))*(b/cos(e + f*x))**n, x), x) + Simp(b*(a/sin(e + f*x))**(m + S(1))*(b/cos(e + f*x))**(n + S(-1))/(a*f*(m + n)), x) def replacement3929(a, b, e, f, m, n, x): return Dist((n + S(1))/(b**S(2)*(m + n)), Int((a/sin(e + f*x))**m*(b/cos(e + f*x))**(n + S(2)), x), x) - Simp(a*(a/sin(e + f*x))**(m + S(-1))*(b/cos(e + f*x))**(n + S(1))/(b*f*(m + n)), x) def replacement3930(a, b, e, f, m, n, x): return Dist((a/sin(e + f*x))**m*(b/cos(e + f*x))**n*tan(e + f*x)**(-n), Int(tan(e + f*x)**n, x), x) def replacement3931(a, b, e, f, m, n, x): return Dist((a/sin(e + f*x))**m*(a*sin(e + f*x))**m*(b/cos(e + f*x))**n*(b*cos(e + f*x))**n, Int((a*sin(e + f*x))**(-m)*(b*cos(e + f*x))**(-n), x), x) def replacement3932(c, d, n, x): return Dist(S(1)/d, Subst(Int(ExpandIntegrand((x**S(2) + S(1))**(n/S(2) + S(-1)), x), x), x, tan(c + d*x)), x) def replacement3933(c, d, n, x): return -Dist(S(1)/d, Subst(Int(ExpandIntegrand((x**S(2) + S(1))**(n/S(2) + S(-1)), x), x), x, S(1)/tan(c + d*x)), x) def replacement3934(b, c, d, n, x): return Dist(b**S(2)*(n + S(-2))/(n + S(-1)), Int((b/cos(c + d*x))**(n + S(-2)), x), x) + Simp(b*(b/cos(c + d*x))**(n + S(-1))*sin(c + d*x)/(d*(n + S(-1))), x) def replacement3935(b, c, d, n, x): return Dist(b**S(2)*(n + S(-2))/(n + S(-1)), Int((b/sin(c + d*x))**(n + S(-2)), x), x) - Simp(b*(b/sin(c + d*x))**(n + S(-1))*cos(c + d*x)/(d*(n + S(-1))), x) def replacement3936(b, c, d, n, x): return Dist((n + S(1))/(b**S(2)*n), Int((b/cos(c + d*x))**(n + S(2)), x), x) - Simp((b/cos(c + d*x))**(n + S(1))*sin(c + d*x)/(b*d*n), x) def replacement3937(b, c, d, n, x): return Dist((n + S(1))/(b**S(2)*n), Int((b/sin(c + d*x))**(n + S(2)), x), x) + Simp((b/sin(c + d*x))**(n + S(1))*cos(c + d*x)/(b*d*n), x) def replacement3938(c, d, x): return Simp(atanh(sin(c + d*x))/d, x) def replacement3939(c, d, x): return -Simp(atanh(cos(c + d*x))/d, x) def replacement3940(b, c, d, n, x): return Dist((b/cos(c + d*x))**n*cos(c + d*x)**n, Int(cos(c + d*x)**(-n), x), x) def replacement3941(b, c, d, n, x): return Dist((b/sin(c + d*x))**n*sin(c + d*x)**n, Int(sin(c + d*x)**(-n), x), x) def replacement3942(b, c, d, n, x): return Simp((cos(c + d*x)/b)**(n + S(-1))*(b/cos(c + d*x))**(n + S(-1))*Int((cos(c + d*x)/b)**(-n), x), x) def replacement3943(b, c, d, n, x): return Simp((sin(c + d*x)/b)**(n + S(-1))*(b/sin(c + d*x))**(n + S(-1))*Int((sin(c + d*x)/b)**(-n), x), x) def replacement3944(a, b, c, d, x): return Dist(b**S(2), Int(cos(c + d*x)**(S(-2)), x), x) + Dist(S(2)*a*b, Int(S(1)/cos(c + d*x), x), x) + Simp(a**S(2)*x, x) def replacement3945(a, b, c, d, x): return Dist(b**S(2), Int(sin(c + d*x)**(S(-2)), x), x) + Dist(S(2)*a*b, Int(S(1)/sin(c + d*x), x), x) + Simp(a**S(2)*x, x) def replacement3946(a, b, c, d, x): return Dist(S(2)*b/d, Subst(Int(S(1)/(a + x**S(2)), x), x, b*tan(c + d*x)/sqrt(a + b/cos(c + d*x))), x) def replacement3947(a, b, c, d, x): return Dist(-S(2)*b/d, Subst(Int(S(1)/(a + x**S(2)), x), x, b/(sqrt(a + b/sin(c + d*x))*tan(c + d*x))), x) def replacement3948(a, b, c, d, n, x): return Dist(a/(n + S(-1)), Int((a + b/cos(c + d*x))**(n + S(-2))*(a*(n + S(-1)) + b*(S(3)*n + S(-4))/cos(c + d*x)), x), x) + Simp(b**S(2)*(a + b/cos(c + d*x))**(n + S(-2))*tan(c + d*x)/(d*(n + S(-1))), x) def replacement3949(a, b, c, d, n, x): return Dist(a/(n + S(-1)), Int((a + b/sin(c + d*x))**(n + S(-2))*(a*(n + S(-1)) + b*(S(3)*n + S(-4))/sin(c + d*x)), x), x) - Simp(b**S(2)*(a + b/sin(c + d*x))**(n + S(-2))/(d*(n + S(-1))*tan(c + d*x)), x) def replacement3950(a, b, c, d, x): return Dist(S(1)/a, Int(sqrt(a + b/cos(c + d*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(a + b/cos(c + d*x))*cos(c + d*x)), x), x) def replacement3951(a, b, c, d, x): return Dist(S(1)/a, Int(sqrt(a + b/sin(c + d*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(a + b/sin(c + d*x))*sin(c + d*x)), x), x) def replacement3952(a, b, c, d, n, x): return Dist(S(1)/(a**S(2)*(S(2)*n + S(1))), Int((a + b/cos(c + d*x))**(n + S(1))*(a*(S(2)*n + S(1)) - b*(n + S(1))/cos(c + d*x)), x), x) + Simp((a + b/cos(c + d*x))**n*tan(c + d*x)/(d*(S(2)*n + S(1))), x) def replacement3953(a, b, c, d, n, x): return Dist(S(1)/(a**S(2)*(S(2)*n + S(1))), Int((a + b/sin(c + d*x))**(n + S(1))*(a*(S(2)*n + S(1)) - b*(n + S(1))/sin(c + d*x)), x), x) - Simp((a + b/sin(c + d*x))**n/(d*(S(2)*n + S(1))*tan(c + d*x)), x) def replacement3954(a, b, c, d, n, x): return -Dist(a**n*tan(c + d*x)/(d*sqrt(S(1) - S(1)/cos(c + d*x))*sqrt(S(1) + S(1)/cos(c + d*x))), Subst(Int((S(1) + b*x/a)**(n + S(-1)/2)/(x*sqrt(S(1) - b*x/a)), x), x, S(1)/cos(c + d*x)), x) def replacement3955(a, b, c, d, n, x): return Dist(a**n/(d*sqrt(S(1) - S(1)/sin(c + d*x))*sqrt(S(1) + S(1)/sin(c + d*x))*tan(c + d*x)), Subst(Int((S(1) + b*x/a)**(n + S(-1)/2)/(x*sqrt(S(1) - b*x/a)), x), x, S(1)/sin(c + d*x)), x) def replacement3956(a, b, c, d, n, x): return Dist(a**IntPart(n)*(S(1) + b/(a*cos(c + d*x)))**(-FracPart(n))*(a + b/cos(c + d*x))**FracPart(n), Int((S(1) + b/(a*cos(c + d*x)))**n, x), x) def replacement3957(a, b, c, d, n, x): return Dist(a**IntPart(n)*(S(1) + b/(a*sin(c + d*x)))**(-FracPart(n))*(a + b/sin(c + d*x))**FracPart(n), Int((S(1) + b/(a*sin(c + d*x)))**n, x), x) def replacement3958(a, b, c, d, x): return Simp(-S(2)*sqrt(b*(S(1) + S(1)/cos(c + d*x))/(a + b/cos(c + d*x)))*sqrt(-b*(S(1) - S(1)/cos(c + d*x))/(a + b/cos(c + d*x)))*(a + b/cos(c + d*x))*EllipticPi(a/(a + b), asin(Rt(a + b, S(2))/sqrt(a + b/cos(c + d*x))), (a - b)/(a + b))/(d*Rt(a + b, S(2))*tan(c + d*x)), x) def replacement3959(a, b, c, d, x): return Simp(S(2)*sqrt(b*(S(1) + S(1)/sin(c + d*x))/(a + b/sin(c + d*x)))*sqrt(-b*(S(1) - S(1)/sin(c + d*x))/(a + b/sin(c + d*x)))*(a + b/sin(c + d*x))*EllipticPi(a/(a + b), asin(Rt(a + b, S(2))/sqrt(a + b/sin(c + d*x))), (a - b)/(a + b))*tan(c + d*x)/(d*Rt(a + b, S(2))), x) def replacement3960(a, b, c, d, x): return Dist(b**S(2), Int((S(1) + S(1)/cos(c + d*x))/(sqrt(a + b/cos(c + d*x))*cos(c + d*x)), x), x) + Int((a**S(2) + b*(S(2)*a - b)/cos(c + d*x))/sqrt(a + b/cos(c + d*x)), x) def replacement3961(a, b, c, d, x): return Dist(b**S(2), Int((S(1) + S(1)/sin(c + d*x))/(sqrt(a + b/sin(c + d*x))*sin(c + d*x)), x), x) + Int((a**S(2) + b*(S(2)*a - b)/sin(c + d*x))/sqrt(a + b/sin(c + d*x)), x) def replacement3962(a, b, c, d, n, x): return Dist(S(1)/(n + S(-1)), Int((a + b/cos(c + d*x))**(n + S(-3))*Simp(a**S(3)*(n + S(-1)) + a*b**S(2)*(S(3)*n + S(-4))/cos(c + d*x)**S(2) + b*(S(3)*a**S(2)*(n + S(-1)) + b**S(2)*(n + S(-2)))/cos(c + d*x), x), x), x) + Simp(b**S(2)*(a + b/cos(c + d*x))**(n + S(-2))*tan(c + d*x)/(d*(n + S(-1))), x) def replacement3963(a, b, c, d, n, x): return Dist(S(1)/(n + S(-1)), Int((a + b/sin(c + d*x))**(n + S(-3))*Simp(a**S(3)*(n + S(-1)) + a*b**S(2)*(S(3)*n + S(-4))/sin(c + d*x)**S(2) + b*(S(3)*a**S(2)*(n + S(-1)) + b**S(2)*(n + S(-2)))/sin(c + d*x), x), x), x) - Simp(b**S(2)*(a + b/sin(c + d*x))**(n + S(-2))/(d*(n + S(-1))*tan(c + d*x)), x) def replacement3964(a, b, c, d, x): return -Dist(S(1)/a, Int(S(1)/(a*cos(c + d*x)/b + S(1)), x), x) + Simp(x/a, x) def replacement3965(a, b, c, d, x): return -Dist(S(1)/a, Int(S(1)/(a*sin(c + d*x)/b + S(1)), x), x) + Simp(x/a, x) def replacement3966(a, b, c, d, x): return Simp(-S(2)*sqrt(b*(S(1) - S(1)/cos(c + d*x))/(a + b))*sqrt(-b*(S(1) + S(1)/cos(c + d*x))/(a - b))*EllipticPi((a + b)/a, asin(sqrt(a + b/cos(c + d*x))/Rt(a + b, S(2))), (a + b)/(a - b))*Rt(a + b, S(2))/(a*d*tan(c + d*x)), x) def replacement3967(a, b, c, d, x): return Simp(S(2)*sqrt(b*(S(1) - S(1)/sin(c + d*x))/(a + b))*sqrt(-b*(S(1) + S(1)/sin(c + d*x))/(a - b))*EllipticPi((a + b)/a, asin(sqrt(a + b/sin(c + d*x))/Rt(a + b, S(2))), (a + b)/(a - b))*Rt(a + b, S(2))*tan(c + d*x)/(a*d), x) def replacement3968(a, b, c, d, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(n + S(1))), Int((a + b/cos(c + d*x))**(n + S(1))*Simp(-a*b*(n + S(1))/cos(c + d*x) + b**S(2)*(n + S(2))/cos(c + d*x)**S(2) + (a**S(2) - b**S(2))*(n + S(1)), x), x), x) - Simp(b**S(2)*(a + b/cos(c + d*x))**(n + S(1))*tan(c + d*x)/(a*d*(a**S(2) - b**S(2))*(n + S(1))), x) def replacement3969(a, b, c, d, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(n + S(1))), Int((a + b/sin(c + d*x))**(n + S(1))*Simp(-a*b*(n + S(1))/sin(c + d*x) + b**S(2)*(n + S(2))/sin(c + d*x)**S(2) + (a**S(2) - b**S(2))*(n + S(1)), x), x), x) + Simp(b**S(2)*(a + b/sin(c + d*x))**(n + S(1))/(a*d*(a**S(2) - b**S(2))*(n + S(1))*tan(c + d*x)), x) def replacement3970(a, b, c, d, n, x): return Int((a + b/cos(c + d*x))**n, x) def replacement3971(a, b, c, d, n, x): return Int((a + b/sin(c + d*x))**n, x) def replacement3972(a, b, d, e, f, n, x): return Dist(a, Int((d/cos(e + f*x))**n, x), x) + Dist(b/d, Int((d/cos(e + f*x))**(n + S(1)), x), x) def replacement3973(a, b, d, e, f, n, x): return Dist(a, Int((d/sin(e + f*x))**n, x), x) + Dist(b/d, Int((d/sin(e + f*x))**(n + S(1)), x), x) def replacement3974(a, b, d, e, f, n, x): return Dist(S(2)*a*b/d, Int((d/cos(e + f*x))**(n + S(1)), x), x) + Int((d/cos(e + f*x))**n*(a**S(2) + b**S(2)/cos(e + f*x)**S(2)), x) def replacement3975(a, b, d, e, f, n, x): return Dist(S(2)*a*b/d, Int((d/sin(e + f*x))**(n + S(1)), x), x) + Int((d/sin(e + f*x))**n*(a**S(2) + b**S(2)/sin(e + f*x)**S(2)), x) def replacement3976(a, b, e, f, x): return Dist(S(1)/b, Int(S(1)/cos(e + f*x), x), x) - Dist(a/b, Int(S(1)/((a + b/cos(e + f*x))*cos(e + f*x)), x), x) def replacement3977(a, b, e, f, x): return Dist(S(1)/b, Int(S(1)/sin(e + f*x), x), x) - Dist(a/b, Int(S(1)/((a + b/sin(e + f*x))*sin(e + f*x)), x), x) def replacement3978(a, b, e, f, x): return -Dist(a/b, Int(S(1)/((a + b/cos(e + f*x))*cos(e + f*x)**S(2)), x), x) + Simp(tan(e + f*x)/(b*f), x) def replacement3979(a, b, e, f, x): return -Dist(a/b, Int(S(1)/((a + b/sin(e + f*x))*sin(e + f*x)**S(2)), x), x) - Simp(S(1)/(b*f*tan(e + f*x)), x) def replacement3980(a, b, d, e, f, m, n, x): return Int(ExpandTrig((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m, x), x) def replacement3981(a, b, d, e, f, m, n, x): return Int(ExpandTrig((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m, x), x) def replacement3982(a, b, e, f, x): return Simp(S(2)*b*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))), x) def replacement3983(a, b, e, f, x): return Simp(-S(2)*b/(f*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement3984(a, b, e, f, m, x): return Dist(a*(S(2)*m + S(-1))/m, Int((a + b/cos(e + f*x))**(m + S(-1))/cos(e + f*x), x), x) + Simp(b*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*m), x) def replacement3985(a, b, e, f, m, x): return Dist(a*(S(2)*m + S(-1))/m, Int((a + b/sin(e + f*x))**(m + S(-1))/sin(e + f*x), x), x) - Simp(b*(a + b/sin(e + f*x))**(m + S(-1))/(f*m*tan(e + f*x)), x) def replacement3986(a, b, e, f, x): return Simp(tan(e + f*x)/(f*(a/cos(e + f*x) + b)), x) def replacement3987(a, b, e, f, x): return -Simp(S(1)/(f*(a/sin(e + f*x) + b)*tan(e + f*x)), x) def replacement3988(a, b, e, f, x): return Dist(S(2)/f, Subst(Int(S(1)/(S(2)*a + x**S(2)), x), x, b*tan(e + f*x)/sqrt(a + b/cos(e + f*x))), x) def replacement3989(a, b, e, f, x): return Dist(-S(2)/f, Subst(Int(S(1)/(S(2)*a + x**S(2)), x), x, b/(sqrt(a + b/sin(e + f*x))*tan(e + f*x))), x) def replacement3990(a, b, e, f, m, x): return Dist((m + S(1))/(a*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))/cos(e + f*x), x), x) - Simp(b*(a + b/cos(e + f*x))**m*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement3991(a, b, e, f, m, x): return Dist((m + S(1))/(a*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))/sin(e + f*x), x), x) + Simp(b*(a + b/sin(e + f*x))**m/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement3992(a, b, e, f, m, x): return Dist(m/(b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(S(2)*m + S(1))), x) def replacement3993(a, b, e, f, m, x): return Dist(m/(b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**m/(f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement3994(a, b, e, f, m, x): return Dist(a*m/(b*(m + S(1))), Int((a + b/cos(e + f*x))**m/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement3995(a, b, e, f, m, x): return Dist(a*m/(b*(m + S(1))), Int((a + b/sin(e + f*x))**m/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement3996(a, b, e, f, m, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + S(1))/cos(e + f*x))/cos(e + f*x), x), x) - Simp(b*(a + b/cos(e + f*x))**m*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement3997(a, b, e, f, m, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + S(1))/sin(e + f*x))/sin(e + f*x), x), x) + Simp(b*(a + b/sin(e + f*x))**m/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement3998(a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/cos(e + f*x))**m*(-a/cos(e + f*x) + b*(m + S(1)))/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + S(2))), x) def replacement3999(a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/sin(e + f*x))**m*(-a/sin(e + f*x) + b*(m + S(1)))/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + S(2))*tan(e + f*x)), x) def replacement4000(a, b, d, e, f, x): return Dist(S(2)*a*sqrt(a*d/b)/(b*f), Subst(Int(S(1)/sqrt(S(1) + x**S(2)/a), x), x, b*tan(e + f*x)/sqrt(a + b/cos(e + f*x))), x) def replacement4001(a, b, d, e, f, x): return Dist(-S(2)*a*sqrt(a*d/b)/(b*f), Subst(Int(S(1)/sqrt(S(1) + x**S(2)/a), x), x, b/(sqrt(a + b/sin(e + f*x))*tan(e + f*x))), x) def replacement4002(a, b, d, e, f, x): return Dist(S(2)*b*d/f, Subst(Int(S(1)/(b - d*x**S(2)), x), x, b*tan(e + f*x)/(sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x)))), x) def replacement4003(a, b, d, e, f, x): return Dist(-S(2)*b*d/f, Subst(Int(S(1)/(b - d*x**S(2)), x), x, b/(sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x))), x) def replacement4004(a, b, d, e, f, n, x): return Dist(S(2)*a*d*(n + S(-1))/(b*(S(2)*n + S(-1))), Int((d/cos(e + f*x))**(n + S(-1))*sqrt(a + b/cos(e + f*x)), x), x) + Simp(S(2)*b*d*(d/cos(e + f*x))**(n + S(-1))*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(-1))), x) def replacement4005(a, b, d, e, f, n, x): return Dist(S(2)*a*d*(n + S(-1))/(b*(S(2)*n + S(-1))), Int((d/sin(e + f*x))**(n + S(-1))*sqrt(a + b/sin(e + f*x)), x), x) + Simp(-S(2)*b*d*(d/sin(e + f*x))**(n + S(-1))/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(-1))*tan(e + f*x)), x) def replacement4006(a, b, d, e, f, x): return Simp(S(2)*a*tan(e + f*x)/(f*sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), x) def replacement4007(a, b, d, e, f, x): return Simp(-S(2)*a/(f*sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement4008(a, b, d, e, f, n, x): return Dist(a*(S(2)*n + S(1))/(S(2)*b*d*n), Int((d/cos(e + f*x))**(n + S(1))*sqrt(a + b/cos(e + f*x)), x), x) - Simp(a*(d/cos(e + f*x))**n*tan(e + f*x)/(f*n*sqrt(a + b/cos(e + f*x))), x) def replacement4009(a, b, d, e, f, n, x): return Dist(a*(S(2)*n + S(1))/(S(2)*b*d*n), Int((d/sin(e + f*x))**(n + S(1))*sqrt(a + b/sin(e + f*x)), x), x) + Simp(a*(d/sin(e + f*x))**n/(f*n*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement4010(a, b, d, e, f, n, x): return -Dist(a**S(2)*d*tan(e + f*x)/(f*sqrt(a - b/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), Subst(Int((d*x)**(n + S(-1))/sqrt(a - b*x), x), x, S(1)/cos(e + f*x)), x) def replacement4011(a, b, d, e, f, n, x): return Dist(a**S(2)*d/(f*sqrt(a - b/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), Subst(Int((d*x)**(n + S(-1))/sqrt(a - b*x), x), x, S(1)/sin(e + f*x)), x) def replacement4012(a, b, d, e, f, x): return Dist(sqrt(S(2))*sqrt(a)/(b*f), Subst(Int(S(1)/sqrt(x**S(2) + S(1)), x), x, b*tan(e + f*x)/(a + b/cos(e + f*x))), x) def replacement4013(a, b, d, e, f, x): return -Dist(sqrt(S(2))*sqrt(a)/(b*f), Subst(Int(S(1)/sqrt(x**S(2) + S(1)), x), x, b/((a + b/sin(e + f*x))*tan(e + f*x))), x) def replacement4014(a, b, d, e, f, x): return Dist(S(2)*b*d/(a*f), Subst(Int(S(1)/(S(2)*b - d*x**S(2)), x), x, b*tan(e + f*x)/(sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x)))), x) def replacement4015(a, b, d, e, f, x): return Dist(-S(2)*b*d/(a*f), Subst(Int(S(1)/(S(2)*b - d*x**S(2)), x), x, b/(sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x))), x) def replacement4016(a, b, d, e, f, m, n, x): return Dist(b*(S(2)*m + S(-1))/(d*m), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-1)), x), x) + Simp(a*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*m), x) def replacement4017(a, b, d, e, f, m, n, x): return Dist(b*(S(2)*m + S(-1))/(d*m), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-1)), x), x) - Simp(a*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))/(f*m*tan(e + f*x)), x) def replacement4018(a, b, d, e, f, m, n, x): return Dist(d*(m + S(1))/(b*(S(2)*m + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1)), x), x) - Simp(b*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4019(a, b, d, e, f, m, n, x): return Dist(d*(m + S(1))/(b*(S(2)*m + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1)), x), x) + Simp(b*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4020(a, b, d, e, f, m, n, x): return Dist(m/(a*(S(2)*m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1)), x), x) + Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(S(2)*m + S(1))), x) def replacement4021(a, b, d, e, f, m, n, x): return Dist(m/(a*(S(2)*m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1)), x), x) - Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4022(a, b, d, e, f, m, n, x): return Dist(a*m/(b*d*(m + S(1))), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m, x), x) + Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4023(a, b, d, e, f, m, n, x): return Dist(a*m/(b*d*(m + S(1))), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m, x), x) - Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4024(a, b, d, e, f, m, n, x): return -Dist(a/(d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-2))*(-a*(m + S(2)*n + S(-1))/cos(e + f*x) + b*(m - S(2)*n + S(-2))), x), x) - Simp(b**S(2)*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-2))*tan(e + f*x)/(f*n), x) def replacement4025(a, b, d, e, f, m, n, x): return -Dist(a/(d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-2))*(-a*(m + S(2)*n + S(-1))/sin(e + f*x) + b*(m - S(2)*n + S(-2))), x), x) + Simp(b**S(2)*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-2))/(f*n*tan(e + f*x)), x) def replacement4026(a, b, d, e, f, m, n, x): return Dist(b/(m + n + S(-1)), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-2))*(a*(S(3)*m + S(2)*n + S(-4))/cos(e + f*x) + b*(m + S(2)*n + S(-1))), x), x) + Simp(b**S(2)*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-2))*tan(e + f*x)/(f*(m + n + S(-1))), x) def replacement4027(a, b, d, e, f, m, n, x): return Dist(b/(m + n + S(-1)), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-2))*(a*(S(3)*m + S(2)*n + S(-4))/sin(e + f*x) + b*(m + S(2)*n + S(-1))), x), x) - Simp(b**S(2)*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-2))/(f*(m + n + S(-1))*tan(e + f*x)), x) def replacement4028(a, b, d, e, f, m, n, x): return -Dist(d/(a*b*(S(2)*m + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*(a*(n + S(-1)) - b*(m + n)/cos(e + f*x)), x), x) - Simp(b*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4029(a, b, d, e, f, m, n, x): return -Dist(d/(a*b*(S(2)*m + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*(a*(n + S(-1)) - b*(m + n)/sin(e + f*x)), x), x) + Simp(b*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4030(a, b, d, e, f, m, n, x): return Dist(d**S(2)/(a*b*(S(2)*m + S(1))), Int((d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**(m + S(1))*(a*(m - n + S(2))/cos(e + f*x) + b*(n + S(-2))), x), x) + Simp(d**S(2)*(d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(S(2)*m + S(1))), x) def replacement4031(a, b, d, e, f, m, n, x): return Dist(d**S(2)/(a*b*(S(2)*m + S(1))), Int((d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**(m + S(1))*(a*(m - n + S(2))/sin(e + f*x) + b*(n + S(-2))), x), x) - Simp(d**S(2)*(d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**m/(f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4032(a, b, d, e, f, m, n, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*(a*(S(2)*m + n + S(1)) - b*(m + n + S(1))/cos(e + f*x)), x), x) + Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(S(2)*m + S(1))), x) def replacement4033(a, b, d, e, f, m, n, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*(a*(S(2)*m + n + S(1)) - b*(m + n + S(1))/sin(e + f*x)), x), x) - Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4034(a, b, d, e, f, n, x): return -Dist(d**S(2)/(a*b), Int((d/cos(e + f*x))**(n + S(-2))*(-a*(n + S(-1))/cos(e + f*x) + b*(n + S(-2))), x), x) - Simp(d**S(2)*(d/cos(e + f*x))**(n + S(-2))*tan(e + f*x)/(f*(a + b/cos(e + f*x))), x) def replacement4035(a, b, d, e, f, n, x): return -Dist(d**S(2)/(a*b), Int((d/sin(e + f*x))**(n + S(-2))*(-a*(n + S(-1))/sin(e + f*x) + b*(n + S(-2))), x), x) + Simp(d**S(2)*(d/sin(e + f*x))**(n + S(-2))/(f*(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement4036(a, b, d, e, f, n, x): return -Dist(a**(S(-2)), Int((d/cos(e + f*x))**n*(a*(n + S(-1)) - b*n/cos(e + f*x)), x), x) - Simp((d/cos(e + f*x))**n*tan(e + f*x)/(f*(a + b/cos(e + f*x))), x) def replacement4037(a, b, d, e, f, n, x): return -Dist(a**(S(-2)), Int((d/sin(e + f*x))**n*(a*(n + S(-1)) - b*n/sin(e + f*x)), x), x) + Simp((d/sin(e + f*x))**n/(f*(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement4038(a, b, d, e, f, n, x): return Dist(d*(n + S(-1))/(a*b), Int((d/cos(e + f*x))**(n + S(-1))*(a - b/cos(e + f*x)), x), x) + Simp(b*d*(d/cos(e + f*x))**(n + S(-1))*tan(e + f*x)/(a*f*(a + b/cos(e + f*x))), x) def replacement4039(a, b, d, e, f, n, x): return Dist(d*(n + S(-1))/(a*b), Int((d/sin(e + f*x))**(n + S(-1))*(a - b/sin(e + f*x)), x), x) - Simp(b*d*(d/sin(e + f*x))**(n + S(-1))/(a*f*(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement4040(a, b, d, e, f, x): return Dist(d/b, Int(sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x)), x), x) - Dist(a*d/b, Int(sqrt(d/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) def replacement4041(a, b, d, e, f, x): return Dist(d/b, Int(sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x)), x), x) - Dist(a*d/b, Int(sqrt(d/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) def replacement4042(a, b, d, e, f, n, x): return Dist(d**S(2)/(b*(S(2)*n + S(-3))), Int((d/cos(e + f*x))**(n + S(-2))*(-a/cos(e + f*x) + S(2)*b*(n + S(-2)))/sqrt(a + b/cos(e + f*x)), x), x) + Simp(S(2)*d**S(2)*(d/cos(e + f*x))**(n + S(-2))*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(-3))), x) def replacement4043(a, b, d, e, f, n, x): return Dist(d**S(2)/(b*(S(2)*n + S(-3))), Int((d/sin(e + f*x))**(n + S(-2))*(-a/sin(e + f*x) + S(2)*b*(n + S(-2)))/sqrt(a + b/sin(e + f*x)), x), x) + Simp(-S(2)*d**S(2)*(d/sin(e + f*x))**(n + S(-2))/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(-3))*tan(e + f*x)), x) def replacement4044(a, b, d, e, f, n, x): return Dist(S(1)/(S(2)*b*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b*(S(2)*n + S(1))/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) - Simp((d/cos(e + f*x))**n*tan(e + f*x)/(f*n*sqrt(a + b/cos(e + f*x))), x) def replacement4045(a, b, d, e, f, n, x): return Dist(S(1)/(S(2)*b*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b*(S(2)*n + S(1))/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) + Simp((d/sin(e + f*x))**n/(f*n*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement4046(a, b, d, e, f, m, n, x): return Dist(d**S(2)/(b*(m + n + S(-1))), Int((d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**m*(a*m/cos(e + f*x) + b*(n + S(-2))), x), x) + Simp(d**S(2)*(d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n + S(-1))), x) def replacement4047(a, b, d, e, f, m, n, x): return Dist(d**S(2)/(b*(m + n + S(-1))), Int((d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**m*(a*m/sin(e + f*x) + b*(n + S(-2))), x), x) - Simp(d**S(2)*(d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**m/(f*(m + n + S(-1))*tan(e + f*x)), x) def replacement4048(a, b, d, e, f, m, n, x): return Dist(a**(S(2) - n)*(a*d/b)**n*tan(e + f*x)/(f*sqrt(a - b/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), Subst(Int((a - x)**(n + S(-1))*(S(2)*a - x)**(m + S(-1)/2)/sqrt(x), x), x, a - b/cos(e + f*x)), x) def replacement4049(a, b, d, e, f, m, n, x): return -Dist(a**(S(2) - n)*(a*d/b)**n/(f*sqrt(a - b/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), Subst(Int((a - x)**(n + S(-1))*(S(2)*a - x)**(m + S(-1)/2)/sqrt(x), x), x, a - b/sin(e + f*x)), x) def replacement4050(a, b, d, e, f, m, n, x): return Dist(a**(S(1) - n)*(-a*d/b)**n*tan(e + f*x)/(f*sqrt(a - b/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), Subst(Int(x**(m + S(-1)/2)*(a - x)**(n + S(-1))/sqrt(S(2)*a - x), x), x, a + b/cos(e + f*x)), x) def replacement4051(a, b, d, e, f, m, n, x): return -Dist(a**(S(1) - n)*(-a*d/b)**n/(f*sqrt(a - b/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), Subst(Int(x**(m + S(-1)/2)*(a - x)**(n + S(-1))/sqrt(S(2)*a - x), x), x, a + b/sin(e + f*x)), x) def replacement4052(a, b, d, e, f, m, n, x): return -Dist(a**S(2)*d*tan(e + f*x)/(f*sqrt(a - b/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), Subst(Int((d*x)**(n + S(-1))*(a + b*x)**(m + S(-1)/2)/sqrt(a - b*x), x), x, S(1)/cos(e + f*x)), x) def replacement4053(a, b, d, e, f, m, n, x): return Dist(a**S(2)*d/(f*sqrt(a - b/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), Subst(Int((d*x)**(n + S(-1))*(a + b*x)**(m + S(-1)/2)/sqrt(a - b*x), x), x, S(1)/sin(e + f*x)), x) def replacement4054(a, b, d, e, f, m, n, x): return Dist(a**IntPart(m)*(S(1) + b/(a*cos(e + f*x)))**(-FracPart(m))*(a + b/cos(e + f*x))**FracPart(m), Int((d/cos(e + f*x))**n*(S(1) + b/(a*cos(e + f*x)))**m, x), x) def replacement4055(a, b, d, e, f, m, n, x): return Dist(a**IntPart(m)*(S(1) + b/(a*sin(e + f*x)))**(-FracPart(m))*(a + b/sin(e + f*x))**FracPart(m), Int((d/sin(e + f*x))**n*(S(1) + b/(a*sin(e + f*x)))**m, x), x) def replacement4056(a, b, e, f, x): return Dist(b, Int((S(1) + S(1)/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) + Dist(a - b, Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4057(a, b, e, f, x): return Dist(b, Int((S(1) + S(1)/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) + Dist(a - b, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4058(a, b, e, f, m, x): return Dist(S(1)/m, Int((a + b/cos(e + f*x))**(m + S(-2))*(a**S(2)*m + a*b*(S(2)*m + S(-1))/cos(e + f*x) + b**S(2)*(m + S(-1)))/cos(e + f*x), x), x) + Simp(b*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*m), x) def replacement4059(a, b, e, f, m, x): return Dist(S(1)/m, Int((a + b/sin(e + f*x))**(m + S(-2))*(a**S(2)*m + a*b*(S(2)*m + S(-1))/sin(e + f*x) + b**S(2)*(m + S(-1)))/sin(e + f*x), x), x) - Simp(b*(a + b/sin(e + f*x))**(m + S(-1))/(f*m*tan(e + f*x)), x) def replacement4060(a, b, e, f, x): return Dist(S(1)/b, Int(S(1)/(a*cos(e + f*x)/b + S(1)), x), x) def replacement4061(a, b, e, f, x): return Dist(S(1)/b, Int(S(1)/(a*sin(e + f*x)/b + S(1)), x), x) def replacement4062(a, b, e, f, x): return Simp(S(2)*sqrt(b*(S(1) - S(1)/cos(e + f*x))/(a + b))*sqrt(-b*(S(1) + S(1)/cos(e + f*x))/(a - b))*EllipticF(asin(sqrt(a + b/cos(e + f*x))/Rt(a + b, S(2))), (a + b)/(a - b))*Rt(a + b, S(2))/(b*f*tan(e + f*x)), x) def replacement4063(a, b, e, f, x): return Simp(-S(2)*sqrt(b*(S(1) - S(1)/sin(e + f*x))/(a + b))*sqrt(-b*(S(1) + S(1)/sin(e + f*x))/(a - b))*EllipticF(asin(sqrt(a + b/sin(e + f*x))/Rt(a + b, S(2))), (a + b)/(a - b))*Rt(a + b, S(2))*tan(e + f*x)/(b*f), x) def replacement4064(a, b, e, f, m, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*(a*(m + S(1)) - b*(m + S(2))/cos(e + f*x))/cos(e + f*x), x), x) + Simp(b*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4065(a, b, e, f, m, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*(a*(m + S(1)) - b*(m + S(2))/sin(e + f*x))/sin(e + f*x), x), x) - Simp(b*(a + b/sin(e + f*x))**(m + S(1))/(f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4066(a, b, e, f, m, x): return -Dist(tan(e + f*x)/(f*sqrt(S(1) - S(1)/cos(e + f*x))*sqrt(S(1) + S(1)/cos(e + f*x))), Subst(Int((a + b*x)**m/(sqrt(S(1) - x)*sqrt(x + S(1))), x), x, S(1)/cos(e + f*x)), x) def replacement4067(a, b, e, f, m, x): return Dist(S(1)/(f*sqrt(S(1) - S(1)/sin(e + f*x))*sqrt(S(1) + S(1)/sin(e + f*x))*tan(e + f*x)), Subst(Int((a + b*x)**m/(sqrt(S(1) - x)*sqrt(x + S(1))), x), x, S(1)/sin(e + f*x)), x) def replacement4068(a, b, e, f, m, x): return Dist(m/(m + S(1)), Int((a + b/cos(e + f*x))**(m + S(-1))*(a/cos(e + f*x) + b)/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4069(a, b, e, f, m, x): return Dist(m/(m + S(1)), Int((a + b/sin(e + f*x))**(m + S(-1))*(a/sin(e + f*x) + b)/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4070(a, b, e, f, m, x): return -Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*(-a*(m + S(2))/cos(e + f*x) + b*(m + S(1)))/cos(e + f*x), x), x) - Simp(a*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4071(a, b, e, f, m, x): return -Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*(-a*(m + S(2))/sin(e + f*x) + b*(m + S(1)))/sin(e + f*x), x), x) + Simp(a*(a + b/sin(e + f*x))**(m + S(1))/(f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4072(a, b, e, f, x): return -Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x) + Int((S(1) + S(1)/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x) def replacement4073(a, b, e, f, x): return -Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x) + Int((S(1) + S(1)/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x) def replacement4074(a, b, e, f, m, x): return Dist(S(1)/b, Int((a + b/cos(e + f*x))**(m + S(1))/cos(e + f*x), x), x) - Dist(a/b, Int((a + b/cos(e + f*x))**m/cos(e + f*x), x), x) def replacement4075(a, b, e, f, m, x): return Dist(S(1)/b, Int((a + b/sin(e + f*x))**(m + S(1))/sin(e + f*x), x), x) - Dist(a/b, Int((a + b/sin(e + f*x))**m/sin(e + f*x), x), x) def replacement4076(a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(a*b*(m + S(1)) - (a**S(2) + b**S(2)*(m + S(1)))/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp(a**S(2)*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4077(a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(a*b*(m + S(1)) - (a**S(2) + b**S(2)*(m + S(1)))/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp(a**S(2)*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4078(a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/cos(e + f*x))**m*(-a/cos(e + f*x) + b*(m + S(1)))/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + S(2))), x) def replacement4079(a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/sin(e + f*x))**m*(-a/sin(e + f*x) + b*(m + S(1)))/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + S(2))*tan(e + f*x)), x) def replacement4080(a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-3))*Simp(a**S(2)*b*(m - S(2)*n + S(-2)) - a*(a**S(2)*(n + S(1)) + S(3)*b**S(2)*n)/cos(e + f*x) - b*(a**S(2)*(m + n + S(-1)) + b**S(2)*n)/cos(e + f*x)**S(2), x), x), x) - Simp(a**S(2)*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-2))*tan(e + f*x)/(f*n), x) def replacement4081(a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-3))*Simp(a**S(2)*b*(m - S(2)*n + S(-2)) - a*(a**S(2)*(n + S(1)) + S(3)*b**S(2)*n)/sin(e + f*x) - b*(a**S(2)*(m + n + S(-1)) + b**S(2)*n)/sin(e + f*x)**S(2), x), x), x) + Simp(a**S(2)*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-2))/(f*n*tan(e + f*x)), x) def replacement4082(a, b, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(-1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-3))*Simp(a**S(3)*d*(m + n + S(-1)) + a*b**S(2)*d*n + a*b**S(2)*d*(S(3)*m + S(2)*n + S(-4))/cos(e + f*x)**S(2) + b*(S(3)*a**S(2)*d*(m + n + S(-1)) + b**S(2)*d*(m + n + S(-2)))/cos(e + f*x), x), x), x) + Simp(b**S(2)*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-2))*tan(e + f*x)/(f*(m + n + S(-1))), x) def replacement4083(a, b, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(-1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-3))*Simp(a**S(3)*d*(m + n + S(-1)) + a*b**S(2)*d*n + a*b**S(2)*d*(S(3)*m + S(2)*n + S(-4))/sin(e + f*x)**S(2) + b*(S(3)*a**S(2)*d*(m + n + S(-1)) + b**S(2)*d*(m + n + S(-2)))/sin(e + f*x), x), x), x) - Simp(b**S(2)*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-2))/(f*(m + n + S(-1))*tan(e + f*x)), x) def replacement4084(a, b, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*Simp(a*d*(m + S(1))/cos(e + f*x) + b*d*(n + S(-1)) - b*d*(m + n + S(1))/cos(e + f*x)**S(2), x), x), x) + Simp(b*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4085(a, b, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*Simp(a*d*(m + S(1))/sin(e + f*x) + b*d*(n + S(-1)) - b*d*(m + n + S(1))/sin(e + f*x)**S(2), x), x), x) - Simp(b*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))/(f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4086(a, b, d, e, f, m, n, x): return -Dist(d**S(2)/((a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**(m + S(1))*(-a*(m + n)/cos(e + f*x)**S(2) + a*(n + S(-2)) + b*(m + S(1))/cos(e + f*x)), x), x) - Simp(a*d**S(2)*(d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4087(a, b, d, e, f, m, n, x): return -Dist(d**S(2)/((a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**(m + S(1))*(-a*(m + n)/sin(e + f*x)**S(2) + a*(n + S(-2)) + b*(m + S(1))/sin(e + f*x)), x), x) + Simp(a*d**S(2)*(d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**(m + S(1))/(f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4088(a, b, d, e, f, m, n, x): return Dist(d**S(3)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**(n + S(-3))*(a + b/cos(e + f*x))**(m + S(1))*Simp(a**S(2)*(n + S(-3)) + a*b*(m + S(1))/cos(e + f*x) - (a**S(2)*(n + S(-2)) + b**S(2)*(m + S(1)))/cos(e + f*x)**S(2), x), x), x) + Simp(a**S(2)*d**S(3)*(d/cos(e + f*x))**(n + S(-3))*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4089(a, b, d, e, f, m, n, x): return Dist(d**S(3)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**(n + S(-3))*(a + b/sin(e + f*x))**(m + S(1))*Simp(a**S(2)*(n + S(-3)) + a*b*(m + S(1))/sin(e + f*x) - (a**S(2)*(n + S(-2)) + b**S(2)*(m + S(1)))/sin(e + f*x)**S(2), x), x), x) - Simp(a**S(2)*d**S(3)*(d/sin(e + f*x))**(n + S(-3))*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4090(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m*Simp(-a*(n + S(1))/cos(e + f*x) + b*(m + n + S(1)) - b*(m + n + S(2))/cos(e + f*x)**S(2), x), x), x) - Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(a*f*n), x) def replacement4091(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m*Simp(-a*(n + S(1))/sin(e + f*x) + b*(m + n + S(1)) - b*(m + n + S(2))/sin(e + f*x)**S(2), x), x), x) + Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))/(a*f*n*tan(e + f*x)), x) def replacement4092(a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*(a**S(2)*(m + S(1)) - a*b*(m + S(1))/cos(e + f*x) - b**S(2)*(m + n + S(1)) + b**S(2)*(m + n + S(2))/cos(e + f*x)**S(2)), x), x) - Simp(b**S(2)*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(a*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4093(a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*(a**S(2)*(m + S(1)) - a*b*(m + S(1))/sin(e + f*x) - b**S(2)*(m + n + S(1)) + b**S(2)*(m + n + S(2))/sin(e + f*x)**S(2)), x), x) + Simp(b**S(2)*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))/(a*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4094(a, b, d, e, f, x): return Dist(sqrt(d/cos(e + f*x))*sqrt(d*cos(e + f*x))/d, Int(sqrt(d*cos(e + f*x))/(a*cos(e + f*x) + b), x), x) def replacement4095(a, b, d, e, f, x): return Dist(sqrt(d/sin(e + f*x))*sqrt(d*sin(e + f*x))/d, Int(sqrt(d*sin(e + f*x))/(a*sin(e + f*x) + b), x), x) def replacement4096(a, b, d, e, f, x): return Dist(d*sqrt(d/cos(e + f*x))*sqrt(d*cos(e + f*x)), Int(S(1)/(sqrt(d*cos(e + f*x))*(a*cos(e + f*x) + b)), x), x) def replacement4097(a, b, d, e, f, x): return Dist(d*sqrt(d/sin(e + f*x))*sqrt(d*sin(e + f*x)), Int(S(1)/(sqrt(d*sin(e + f*x))*(a*sin(e + f*x) + b)), x), x) def replacement4098(a, b, d, e, f, x): return Dist(d/b, Int((d/cos(e + f*x))**(S(3)/2), x), x) - Dist(a*d/b, Int((d/cos(e + f*x))**(S(3)/2)/(a + b/cos(e + f*x)), x), x) def replacement4099(a, b, d, e, f, x): return Dist(d/b, Int((d/sin(e + f*x))**(S(3)/2), x), x) - Dist(a*d/b, Int((d/sin(e + f*x))**(S(3)/2)/(a + b/sin(e + f*x)), x), x) def replacement4100(a, b, d, e, f, n, x): return Dist(d**S(3)/(b*(n + S(-2))), Int((d/cos(e + f*x))**(n + S(-3))*Simp(a*(n + S(-3)) - a*(n + S(-2))/cos(e + f*x)**S(2) + b*(n + S(-3))/cos(e + f*x), x)/(a + b/cos(e + f*x)), x), x) + Simp(d**S(3)*(d/cos(e + f*x))**(n + S(-3))*tan(e + f*x)/(b*f*(n + S(-2))), x) def replacement4101(a, b, d, e, f, n, x): return Dist(d**S(3)/(b*(n + S(-2))), Int((d/sin(e + f*x))**(n + S(-3))*Simp(a*(n + S(-3)) - a*(n + S(-2))/sin(e + f*x)**S(2) + b*(n + S(-3))/sin(e + f*x), x)/(a + b/sin(e + f*x)), x), x) - Simp(d**S(3)*(d/sin(e + f*x))**(n + S(-3))/(b*f*(n + S(-2))*tan(e + f*x)), x) def replacement4102(a, b, d, e, f, x): return Dist(a**(S(-2)), Int((a - b/cos(e + f*x))/sqrt(d/cos(e + f*x)), x), x) + Dist(b**S(2)/(a**S(2)*d**S(2)), Int((d/cos(e + f*x))**(S(3)/2)/(a + b/cos(e + f*x)), x), x) def replacement4103(a, b, d, e, f, x): return Dist(a**(S(-2)), Int((a - b/sin(e + f*x))/sqrt(d/sin(e + f*x)), x), x) + Dist(b**S(2)/(a**S(2)*d**S(2)), Int((d/sin(e + f*x))**(S(3)/2)/(a + b/sin(e + f*x)), x), x) def replacement4104(a, b, d, e, f, n, x): return -Dist(S(1)/(a*d*n), Int((d/cos(e + f*x))**(n + S(1))*Simp(-a*(n + S(1))/cos(e + f*x) + b*n - b*(n + S(1))/cos(e + f*x)**S(2), x)/(a + b/cos(e + f*x)), x), x) - Simp((d/cos(e + f*x))**n*tan(e + f*x)/(a*f*n), x) def replacement4105(a, b, d, e, f, n, x): return -Dist(S(1)/(a*d*n), Int((d/sin(e + f*x))**(n + S(1))*Simp(-a*(n + S(1))/sin(e + f*x) + b*n - b*(n + S(1))/sin(e + f*x)**S(2), x)/(a + b/sin(e + f*x)), x), x) + Simp((d/sin(e + f*x))**n/(a*f*n*tan(e + f*x)), x) def replacement4106(a, b, d, e, f, x): return Dist(a, Int(sqrt(d/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) + Dist(b/d, Int((d/cos(e + f*x))**(S(3)/2)/sqrt(a + b/cos(e + f*x)), x), x) def replacement4107(a, b, d, e, f, x): return Dist(a, Int(sqrt(d/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) + Dist(b/d, Int((d/sin(e + f*x))**(S(3)/2)/sqrt(a + b/sin(e + f*x)), x), x) def replacement4108(a, b, d, e, f, n, x): return Dist(d**S(2)/(S(2)*n + S(-1)), Int((d/cos(e + f*x))**(n + S(-2))*Simp(S(2)*a*(n + S(-2)) + a/cos(e + f*x)**S(2) + b*(S(2)*n + S(-3))/cos(e + f*x), x)/sqrt(a + b/cos(e + f*x)), x), x) + Simp(S(2)*d*(d/cos(e + f*x))**(n + S(-1))*sqrt(a + b/cos(e + f*x))*sin(e + f*x)/(f*(S(2)*n + S(-1))), x) def replacement4109(a, b, d, e, f, n, x): return Dist(d**S(2)/(S(2)*n + S(-1)), Int((d/sin(e + f*x))**(n + S(-2))*Simp(S(2)*a*(n + S(-2)) + a/sin(e + f*x)**S(2) + b*(S(2)*n + S(-3))/sin(e + f*x), x)/sqrt(a + b/sin(e + f*x)), x), x) + Simp(-S(2)*d*(d/sin(e + f*x))**(n + S(-1))*sqrt(a + b/sin(e + f*x))*cos(e + f*x)/(f*(S(2)*n + S(-1))), x) def replacement4110(a, b, d, e, f, x): return Dist(sqrt(a + b/cos(e + f*x))/(sqrt(d/cos(e + f*x))*sqrt(a*cos(e + f*x) + b)), Int(sqrt(a*cos(e + f*x) + b), x), x) def replacement4111(a, b, d, e, f, x): return Dist(sqrt(a + b/sin(e + f*x))/(sqrt(d/sin(e + f*x))*sqrt(a*sin(e + f*x) + b)), Int(sqrt(a*sin(e + f*x) + b), x), x) def replacement4112(a, b, d, e, f, n, x): return -Dist(S(1)/(S(2)*d*n), Int((d/cos(e + f*x))**(n + S(1))*Simp(-S(2)*a*(n + S(1))/cos(e + f*x) - b*(S(2)*n + S(3))/cos(e + f*x)**S(2) + b, x)/sqrt(a + b/cos(e + f*x)), x), x) - Simp((d/cos(e + f*x))**n*sqrt(a + b/cos(e + f*x))*tan(e + f*x)/(f*n), x) def replacement4113(a, b, d, e, f, n, x): return -Dist(S(1)/(S(2)*d*n), Int((d/sin(e + f*x))**(n + S(1))*Simp(-S(2)*a*(n + S(1))/sin(e + f*x) - b*(S(2)*n + S(3))/sin(e + f*x)**S(2) + b, x)/sqrt(a + b/sin(e + f*x)), x), x) + Simp((d/sin(e + f*x))**n*sqrt(a + b/sin(e + f*x))/(f*n*tan(e + f*x)), x) def replacement4114(a, b, d, e, f, x): return Dist(sqrt(d/cos(e + f*x))*sqrt(a*cos(e + f*x) + b)/sqrt(a + b/cos(e + f*x)), Int(S(1)/sqrt(a*cos(e + f*x) + b), x), x) def replacement4115(a, b, d, e, f, x): return Dist(sqrt(d/sin(e + f*x))*sqrt(a*sin(e + f*x) + b)/sqrt(a + b/sin(e + f*x)), Int(S(1)/sqrt(a*sin(e + f*x) + b), x), x) def replacement4116(a, b, d, e, f, x): return Dist(d*sqrt(d/cos(e + f*x))*sqrt(a*cos(e + f*x) + b)/sqrt(a + b/cos(e + f*x)), Int(S(1)/(sqrt(a*cos(e + f*x) + b)*cos(e + f*x)), x), x) def replacement4117(a, b, d, e, f, x): return Dist(d*sqrt(d/sin(e + f*x))*sqrt(a*sin(e + f*x) + b)/sqrt(a + b/sin(e + f*x)), Int(S(1)/(sqrt(a*sin(e + f*x) + b)*sin(e + f*x)), x), x) def replacement4118(a, b, d, e, f, n, x): return Dist(d**S(3)/(b*(S(2)*n + S(-3))), Int((d/cos(e + f*x))**(n + S(-3))*Simp(S(2)*a*(n + S(-3)) - S(2)*a*(n + S(-2))/cos(e + f*x)**S(2) + b*(S(2)*n + S(-5))/cos(e + f*x), x)/sqrt(a + b/cos(e + f*x)), x), x) + Simp(S(2)*d**S(2)*(d/cos(e + f*x))**(n + S(-2))*sqrt(a + b/cos(e + f*x))*sin(e + f*x)/(b*f*(S(2)*n + S(-3))), x) def replacement4119(a, b, d, e, f, n, x): return Dist(d**S(3)/(b*(S(2)*n + S(-3))), Int((d/sin(e + f*x))**(n + S(-3))*Simp(S(2)*a*(n + S(-3)) - S(2)*a*(n + S(-2))/sin(e + f*x)**S(2) + b*(S(2)*n + S(-5))/sin(e + f*x), x)/sqrt(a + b/sin(e + f*x)), x), x) + Simp(-S(2)*d**S(2)*(d/sin(e + f*x))**(n + S(-2))*sqrt(a + b/sin(e + f*x))*cos(e + f*x)/(b*f*(S(2)*n + S(-3))), x) def replacement4120(a, b, e, f, x): return -Dist(b/(S(2)*a), Int((S(1) + cos(e + f*x)**(S(-2)))/sqrt(a + b/cos(e + f*x)), x), x) + Simp(sqrt(a + b/cos(e + f*x))*sin(e + f*x)/(a*f), x) def replacement4121(a, b, e, f, x): return -Dist(b/(S(2)*a), Int((S(1) + sin(e + f*x)**(S(-2)))/sqrt(a + b/sin(e + f*x)), x), x) - Simp(sqrt(a + b/sin(e + f*x))*cos(e + f*x)/(a*f), x) def replacement4122(a, b, d, e, f, x): return Dist(S(1)/a, Int(sqrt(a + b/cos(e + f*x))/sqrt(d/cos(e + f*x)), x), x) - Dist(b/(a*d), Int(sqrt(d/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) def replacement4123(a, b, d, e, f, x): return Dist(S(1)/a, Int(sqrt(a + b/sin(e + f*x))/sqrt(d/sin(e + f*x)), x), x) - Dist(b/(a*d), Int(sqrt(d/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) def replacement4124(a, b, d, e, f, n, x): return Dist(S(1)/(S(2)*a*d*n), Int((d/cos(e + f*x))**(n + S(1))*Simp(S(2)*a*(n + S(1))/cos(e + f*x) - b*(S(2)*n + S(1)) + b*(S(2)*n + S(3))/cos(e + f*x)**S(2), x)/sqrt(a + b/cos(e + f*x)), x), x) - Simp((d/cos(e + f*x))**(n + S(1))*sqrt(a + b/cos(e + f*x))*sin(e + f*x)/(a*d*f*n), x) def replacement4125(a, b, d, e, f, n, x): return Dist(S(1)/(S(2)*a*d*n), Int((d/sin(e + f*x))**(n + S(1))*Simp(S(2)*a*(n + S(1))/sin(e + f*x) - b*(S(2)*n + S(1)) + b*(S(2)*n + S(3))/sin(e + f*x)**S(2), x)/sqrt(a + b/sin(e + f*x)), x), x) + Simp((d/sin(e + f*x))**(n + S(1))*sqrt(a + b/sin(e + f*x))*cos(e + f*x)/(a*d*f*n), x) def replacement4126(a, b, d, e, f, n, x): return Dist(S(1)/(S(2)*d*n), Int((d/cos(e + f*x))**(n + S(1))*Simp(a*b*(S(2)*n + S(-1)) + a*b*(S(2)*n + S(3))/cos(e + f*x)**S(2) + S(2)*(a**S(2)*(n + S(1)) + b**S(2)*n)/cos(e + f*x), x)/sqrt(a + b/cos(e + f*x)), x), x) - Simp(a*(d/cos(e + f*x))**n*sqrt(a + b/cos(e + f*x))*tan(e + f*x)/(f*n), x) def replacement4127(a, b, d, e, f, n, x): return Dist(S(1)/(S(2)*d*n), Int((d/sin(e + f*x))**(n + S(1))*Simp(a*b*(S(2)*n + S(-1)) + a*b*(S(2)*n + S(3))/sin(e + f*x)**S(2) + S(2)*(a**S(2)*(n + S(1)) + b**S(2)*n)/sin(e + f*x), x)/sqrt(a + b/sin(e + f*x)), x), x) + Simp(a*(d/sin(e + f*x))**n*sqrt(a + b/sin(e + f*x))/(f*n*tan(e + f*x)), x) def replacement4128(a, b, d, e, f, m, n, x): return Dist(d**S(3)/(b*(m + n + S(-1))), Int((d/cos(e + f*x))**(n + S(-3))*(a + b/cos(e + f*x))**m*Simp(a*(n + S(-3)) - a*(n + S(-2))/cos(e + f*x)**S(2) + b*(m + n + S(-2))/cos(e + f*x), x), x), x) + Simp(d**S(3)*(d/cos(e + f*x))**(n + S(-3))*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + n + S(-1))), x) def replacement4129(a, b, d, e, f, m, n, x): return Dist(d**S(3)/(b*(m + n + S(-1))), Int((d/sin(e + f*x))**(n + S(-3))*(a + b/sin(e + f*x))**m*Simp(a*(n + S(-3)) - a*(n + S(-2))/sin(e + f*x)**S(2) + b*(m + n + S(-2))/sin(e + f*x), x), x), x) - Simp(d**S(3)*(d/sin(e + f*x))**(n + S(-3))*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + n + S(-1))*tan(e + f*x)), x) def replacement4130(a, b, d, e, f, m, n, x): return Dist(d/(m + n + S(-1)), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(-2))*Simp(a*b*(n + S(-1)) + a*b*(S(2)*m + n + S(-2))/cos(e + f*x)**S(2) + (a**S(2)*(m + n + S(-1)) + b**S(2)*(m + n + S(-2)))/cos(e + f*x), x), x), x) + Simp(b*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*(m + n + S(-1))), x) def replacement4131(a, b, d, e, f, m, n, x): return Dist(d/(m + n + S(-1)), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(-2))*Simp(a*b*(n + S(-1)) + a*b*(S(2)*m + n + S(-2))/sin(e + f*x)**S(2) + (a**S(2)*(m + n + S(-1)) + b**S(2)*(m + n + S(-2)))/sin(e + f*x), x), x), x) - Simp(b*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(-1))/(f*(m + n + S(-1))*tan(e + f*x)), x) def replacement4132(a, b, d, e, f, m, n, x): return Dist(d**S(2)/(b*(m + n + S(-1))), Int((d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**(m + S(-1))*Simp(a*b*m/cos(e + f*x)**S(2) + a*b*(n + S(-2)) + b**S(2)*(m + n + S(-2))/cos(e + f*x), x), x), x) + Simp(d**S(2)*(d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n + S(-1))), x) def replacement4133(a, b, d, e, f, m, n, x): return Dist(d**S(2)/(b*(m + n + S(-1))), Int((d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**(m + S(-1))*Simp(a*b*m/sin(e + f*x)**S(2) + a*b*(n + S(-2)) + b**S(2)*(m + n + S(-2))/sin(e + f*x), x), x), x) - Simp(d**S(2)*(d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**m/(f*(m + n + S(-1))*tan(e + f*x)), x) def replacement4134(a, b, d, e, f, x): return Dist(a, Int(sqrt(a + b/cos(e + f*x))/sqrt(d/cos(e + f*x)), x), x) + Dist(b/d, Int(sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x)), x), x) def replacement4135(a, b, d, e, f, x): return Dist(a, Int(sqrt(a + b/sin(e + f*x))/sqrt(d/sin(e + f*x)), x), x) + Dist(b/d, Int(sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x)), x), x) def replacement4136(a, b, d, e, f, m, n, x): return Dist(a, Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1)), x), x) + Dist(b/d, Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-1)), x), x) def replacement4137(a, b, d, e, f, m, n, x): return Dist(a, Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1)), x), x) + Dist(b/d, Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-1)), x), x) def replacement4138(a, b, d, e, f, m, n, x): return Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m, x) def replacement4139(a, b, d, e, f, m, n, x): return Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m, x) def replacement4140(a, b, e, f, g, m, p, x): return Int((g*sin(e + f*x))**p*(a*cos(e + f*x) + b)**m*cos(e + f*x)**(-m), x) def replacement4141(a, b, e, f, g, m, p, x): return Int((g*cos(e + f*x))**p*(a*sin(e + f*x) + b)**m*sin(e + f*x)**(-m), x) def replacement4142(a, b, e, f, m, p, x): return Dist(b**(S(1) - p)/f, Subst(Int(x**(-p + S(-1))*(-a + b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, S(1)/cos(e + f*x)), x) def replacement4143(a, b, e, f, m, p, x): return -Dist(b**(S(1) - p)/f, Subst(Int(x**(-p + S(-1))*(-a + b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, S(1)/sin(e + f*x)), x) def replacement4144(a, b, e, f, m, p, x): return Dist(S(1)/f, Subst(Int(x**(-p + S(-1))*(a + b*x)**m*(x + S(-1))**(p/S(2) + S(-1)/2)*(x + S(1))**(p/S(2) + S(-1)/2), x), x, S(1)/cos(e + f*x)), x) def replacement4145(a, b, e, f, m, p, x): return -Dist(S(1)/f, Subst(Int(x**(-p + S(-1))*(a + b*x)**m*(x + S(-1))**(p/S(2) + S(-1)/2)*(x + S(1))**(p/S(2) + S(-1)/2), x), x, S(1)/sin(e + f*x)), x) def replacement4146(a, b, e, f, m, x): return Dist(b*m, Int((a + b/cos(e + f*x))**(m + S(-1))/cos(e + f*x), x), x) - Simp((a + b/cos(e + f*x))**m/(f*tan(e + f*x)), x) def replacement4147(a, b, e, f, m, x): return Dist(b*m, Int((a + b/sin(e + f*x))**(m + S(-1))/sin(e + f*x), x), x) + Simp((a + b/sin(e + f*x))**m*tan(e + f*x)/f, x) def replacement4148(a, b, e, f, g, m, p, x): return Dist((a + b/cos(e + f*x))**FracPart(m)*(a*cos(e + f*x) + b)**(-FracPart(m))*cos(e + f*x)**FracPart(m), Int((g*sin(e + f*x))**p*(a*cos(e + f*x) + b)**m*cos(e + f*x)**(-m), x), x) def replacement4149(a, b, e, f, g, m, p, x): return Dist((a + b/sin(e + f*x))**FracPart(m)*(a*sin(e + f*x) + b)**(-FracPart(m))*sin(e + f*x)**FracPart(m), Int((g*cos(e + f*x))**p*(a*sin(e + f*x) + b)**m*sin(e + f*x)**(-m), x), x) def replacement4150(a, b, e, f, g, m, p, x): return Int((g*sin(e + f*x))**p*(a + b/cos(e + f*x))**m, x) def replacement4151(a, b, e, f, g, m, p, x): return Int((g*cos(e + f*x))**p*(a + b/sin(e + f*x))**m, x) def replacement4152(a, b, e, f, g, m, p, x): return Dist((g/sin(e + f*x))**p*(g*sin(e + f*x))**p, Int((g*sin(e + f*x))**(-p)*(a + b/cos(e + f*x))**m, x), x) def replacement4153(a, b, e, f, g, m, p, x): return Dist((g/cos(e + f*x))**p*(g*cos(e + f*x))**p, Int((g*cos(e + f*x))**(-p)*(a + b/sin(e + f*x))**m, x), x) def replacement4154(a, b, c, d, m, n, x): return -Dist(a**(-m + n + S(1))*b**(-n)/d, Subst(Int(x**(-m - n)*(a - b*x)**(m/S(2) + S(-1)/2)*(a + b*x)**(m/S(2) + n + S(-1)/2), x), x, cos(c + d*x)), x) def replacement4155(a, b, c, d, m, n, x): return Dist(a**(-m + n + S(1))*b**(-n)/d, Subst(Int(x**(-m - n)*(a - b*x)**(m/S(2) + S(-1)/2)*(a + b*x)**(m/S(2) + n + S(-1)/2), x), x, sin(c + d*x)), x) def replacement4156(a, b, c, d, m, n, x): return Dist(b**(S(1) - m)/d, Subst(Int((-a + b*x)**(m/S(2) + S(-1)/2)*(a + b*x)**(m/S(2) + n + S(-1)/2)/x, x), x, S(1)/cos(c + d*x)), x) def replacement4157(a, b, c, d, m, n, x): return -Dist(b**(S(1) - m)/d, Subst(Int((-a + b*x)**(m/S(2) + S(-1)/2)*(a + b*x)**(m/S(2) + n + S(-1)/2)/x, x), x, S(1)/sin(c + d*x)), x) def replacement4158(a, b, c, d, e, m, x): return -Dist(e**S(2)/m, Int((e*tan(c + d*x))**(m + S(-2))*(a*m + b*(m + S(-1))/cos(c + d*x)), x), x) + Simp(e*(e*tan(c + d*x))**(m + S(-1))*(a*m + b*(m + S(-1))/cos(c + d*x))/(d*m*(m + S(-1))), x) def replacement4159(a, b, c, d, e, m, x): return -Dist(e**S(2)/m, Int((e/tan(c + d*x))**(m + S(-2))*(a*m + b*(m + S(-1))/sin(c + d*x)), x), x) - Simp(e*(e/tan(c + d*x))**(m + S(-1))*(a*m + b*(m + S(-1))/sin(c + d*x))/(d*m*(m + S(-1))), x) def replacement4160(a, b, c, d, e, m, x): return -Dist(S(1)/(e**S(2)*(m + S(1))), Int((e*tan(c + d*x))**(m + S(2))*(a*(m + S(1)) + b*(m + S(2))/cos(c + d*x)), x), x) + Simp((e*tan(c + d*x))**(m + S(1))*(a + b/cos(c + d*x))/(d*e*(m + S(1))), x) def replacement4161(a, b, c, d, e, m, x): return -Dist(S(1)/(e**S(2)*(m + S(1))), Int((e/tan(c + d*x))**(m + S(2))*(a*(m + S(1)) + b*(m + S(2))/sin(c + d*x)), x), x) - Simp((e/tan(c + d*x))**(m + S(1))*(a + b/sin(c + d*x))/(d*e*(m + S(1))), x) def replacement4162(a, b, c, d, x): return Int((a*cos(c + d*x) + b)/sin(c + d*x), x) def replacement4163(a, b, c, d, x): return Int((a*sin(c + d*x) + b)/cos(c + d*x), x) def replacement4164(a, b, c, d, e, m, x): return Dist(a, Int((e*tan(c + d*x))**m, x), x) + Dist(b, Int((e*tan(c + d*x))**m/cos(c + d*x), x), x) def replacement4165(a, b, c, d, e, m, x): return Dist(a, Int((e/tan(c + d*x))**m, x), x) + Dist(b, Int((e/tan(c + d*x))**m/sin(c + d*x), x), x) def replacement4166(a, b, c, d, m, n, x): return Dist((S(-1))**(m/S(2) + S(-1)/2)*b**(S(1) - m)/d, Subst(Int((a + x)**n*(b**S(2) - x**S(2))**(m/S(2) + S(-1)/2)/x, x), x, b/cos(c + d*x)), x) def replacement4167(a, b, c, d, m, n, x): return -Dist((S(-1))**(m/S(2) + S(-1)/2)*b**(S(1) - m)/d, Subst(Int((a + x)**n*(b**S(2) - x**S(2))**(m/S(2) + S(-1)/2)/x, x), x, b/sin(c + d*x)), x) def replacement4168(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((e*tan(c + d*x))**m, (a + b/cos(c + d*x))**n, x), x) def replacement4169(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((e/tan(c + d*x))**m, (a + b/sin(c + d*x))**n, x), x) def replacement4170(a, b, c, d, m, n, x): return Dist(S(2)*a**(m/S(2) + n + S(1)/2)/d, Subst(Int(x**m*(a*x**S(2) + S(2))**(m/S(2) + n + S(-1)/2)/(a*x**S(2) + S(1)), x), x, tan(c + d*x)/sqrt(a + b/cos(c + d*x))), x) def replacement4171(a, b, c, d, m, n, x): return Dist(-S(2)*a**(m/S(2) + n + S(1)/2)/d, Subst(Int(x**m*(a*x**S(2) + S(2))**(m/S(2) + n + S(-1)/2)/(a*x**S(2) + S(1)), x), x, S(1)/(sqrt(a + b/sin(c + d*x))*tan(c + d*x))), x) def replacement4172(a, b, c, d, e, m, n, x): return Dist(a**(S(2)*n)*e**(-S(2)*n), Int((e*tan(c + d*x))**(m + S(2)*n)*(-a + b/cos(c + d*x))**(-n), x), x) def replacement4173(a, b, c, d, e, m, n, x): return Dist(a**(S(2)*n)*e**(-S(2)*n), Int((e/tan(c + d*x))**(m + S(2)*n)*(-a + b/sin(c + d*x))**(-n), x), x) def replacement4174(a, b, c, d, e, m, n, x): return Simp(S(2)**(m + n + S(1))*(a/(a + b/cos(c + d*x)))**(m + n + S(1))*(e*tan(c + d*x))**(m + S(1))*(a + b/cos(c + d*x))**n*AppellF1(m/S(2) + S(1)/2, m + n, S(1), m/S(2) + S(3)/2, -(a - b/cos(c + d*x))/(a + b/cos(c + d*x)), (a - b/cos(c + d*x))/(a + b/cos(c + d*x)))/(d*e*(m + S(1))), x) def replacement4175(a, b, c, d, e, m, n, x): return -Simp(S(2)**(m + n + S(1))*(a/(a + b/sin(c + d*x)))**(m + n + S(1))*(e/tan(c + d*x))**(m + S(1))*(a + b/sin(c + d*x))**n*AppellF1(m/S(2) + S(1)/2, m + n, S(1), m/S(2) + S(3)/2, -(a - b/sin(c + d*x))/(a + b/sin(c + d*x)), (a - b/sin(c + d*x))/(a + b/sin(c + d*x)))/(d*e*(m + S(1))), x) def replacement4176(a, b, c, d, e, x): return Dist(S(1)/a, Int(sqrt(e*tan(c + d*x)), x), x) - Dist(b/a, Int(sqrt(e*tan(c + d*x))/(a*cos(c + d*x) + b), x), x) def replacement4177(a, b, c, d, e, x): return Dist(S(1)/a, Int(sqrt(e/tan(c + d*x)), x), x) - Dist(b/a, Int(sqrt(e/tan(c + d*x))/(a*sin(c + d*x) + b), x), x) def replacement4178(a, b, c, d, e, m, x): return -Dist(e**S(2)/b**S(2), Int((e*tan(c + d*x))**(m + S(-2))*(a - b/cos(c + d*x)), x), x) + Dist(e**S(2)*(a**S(2) - b**S(2))/b**S(2), Int((e*tan(c + d*x))**(m + S(-2))/(a + b/cos(c + d*x)), x), x) def replacement4179(a, b, c, d, e, m, x): return -Dist(e**S(2)/b**S(2), Int((e/tan(c + d*x))**(m + S(-2))*(a - b/sin(c + d*x)), x), x) + Dist(e**S(2)*(a**S(2) - b**S(2))/b**S(2), Int((e/tan(c + d*x))**(m + S(-2))/(a + b/sin(c + d*x)), x), x) def replacement4180(a, b, c, d, e, x): return Dist(S(1)/a, Int(S(1)/sqrt(e*tan(c + d*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(e*tan(c + d*x))*(a*cos(c + d*x) + b)), x), x) def replacement4181(a, b, c, d, e, x): return Dist(S(1)/a, Int(S(1)/sqrt(e/tan(c + d*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(e/tan(c + d*x))*(a*sin(c + d*x) + b)), x), x) def replacement4182(a, b, c, d, e, m, x): return Dist(b**S(2)/(e**S(2)*(a**S(2) - b**S(2))), Int((e*tan(c + d*x))**(m + S(2))/(a + b/cos(c + d*x)), x), x) + Dist(S(1)/(a**S(2) - b**S(2)), Int((e*tan(c + d*x))**m*(a - b/cos(c + d*x)), x), x) def replacement4183(a, b, c, d, e, m, x): return Dist(b**S(2)/(e**S(2)*(a**S(2) - b**S(2))), Int((e/tan(c + d*x))**(m + S(2))/(a + b/sin(c + d*x)), x), x) + Dist(S(1)/(a**S(2) - b**S(2)), Int((e/tan(c + d*x))**m*(a - b/sin(c + d*x)), x), x) def replacement4184(a, b, c, d, n, x): return Int((S(-1) + cos(c + d*x)**(S(-2)))*(a + b/cos(c + d*x))**n, x) def replacement4185(a, b, c, d, n, x): return Int((S(-1) + sin(c + d*x)**(S(-2)))*(a + b/sin(c + d*x))**n, x) def replacement4186(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((e*tan(c + d*x))**m, (a + b/cos(c + d*x))**n, x), x) def replacement4187(a, b, c, d, e, m, n, x): return Int(ExpandIntegrand((e/tan(c + d*x))**m, (a + b/sin(c + d*x))**n, x), x) def replacement4188(a, b, c, d, m, n, x): return Int((a*cos(c + d*x) + b)**n*sin(c + d*x)**m*cos(c + d*x)**(-m - n), x) def replacement4189(a, b, c, d, m, n, x): return Int((a*sin(c + d*x) + b)**n*sin(c + d*x)**(-m - n)*cos(c + d*x)**m, x) def replacement4190(a, b, c, d, e, m, n, x): return Int((e*tan(c + d*x))**m*(a + b/cos(c + d*x))**n, x) def replacement4191(a, b, c, d, e, m, n, x): return Int((e/tan(c + d*x))**m*(a + b/sin(c + d*x))**n, x) def replacement4192(a, b, c, d, e, m, n, p, x): return Dist((e*tan(c + d*x))**(-m*p)*(e*tan(c + d*x)**p)**m, Int((e*tan(c + d*x))**(m*p)*(a + b/cos(c + d*x))**n, x), x) def replacement4193(a, b, c, d, e, m, n, p, x): return Dist((e*(S(1)/tan(c + d*x))**p)**m*(e/tan(c + d*x))**(-m*p), Int((e/tan(c + d*x))**(m*p)*(a + b/sin(c + d*x))**n, x), x) def replacement4194(a, b, c, d, e, f, m, n, x): return Dist(c**n, Int(ExpandTrig((S(1) + d/(c*cos(e + f*x)))**n, (a + b/cos(e + f*x))**m, x), x), x) def replacement4195(a, b, c, d, e, f, m, n, x): return Dist(c**n, Int(ExpandTrig((S(1) + d/(c*sin(e + f*x)))**n, (a + b/sin(e + f*x))**m, x), x), x) def replacement4196(a, b, c, d, e, f, m, n, x): return Dist((-a*c)**m, Int((c + d/cos(e + f*x))**(-m + n)*tan(e + f*x)**(S(2)*m), x), x) def replacement4197(a, b, c, d, e, f, m, n, x): return Dist((-a*c)**m, Int((c + d/sin(e + f*x))**(-m + n)*(S(1)/tan(e + f*x))**(S(2)*m), x), x) def replacement4198(a, b, c, d, e, f, m, x): return Dist((-a*c)**(m + S(1)/2)*tan(e + f*x)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Int(tan(e + f*x)**(S(2)*m), x), x) def replacement4199(a, b, c, d, e, f, m, x): return Dist((-a*c)**(m + S(1)/2)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Int((S(1)/tan(e + f*x))**(S(2)*m), x), x) def replacement4200(a, b, c, d, e, f, n, x): return Dist(c, Int(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))**(n + S(-1)), x), x) + Simp(-S(2)*a*c*(c + d/cos(e + f*x))**(n + S(-1))*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(-1))), x) def replacement4201(a, b, c, d, e, f, n, x): return Dist(c, Int(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))**(n + S(-1)), x), x) + Simp(S(2)*a*c*(c + d/sin(e + f*x))**(n + S(-1))/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(-1))*tan(e + f*x)), x) def replacement4202(a, b, c, d, e, f, n, x): return Dist(S(1)/c, Int(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))**(n + S(1)), x), x) + Simp(S(2)*a*(c + d/cos(e + f*x))**n*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(1))), x) def replacement4203(a, b, c, d, e, f, n, x): return Dist(S(1)/c, Int(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))**(n + S(1)), x), x) + Simp(-S(2)*a*(c + d/sin(e + f*x))**n/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(1))*tan(e + f*x)), x) def replacement4204(a, b, c, d, e, f, n, x): return Dist(a/c, Int(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))**(n + S(1)), x), x) + Simp(S(4)*a**S(2)*(c + d/cos(e + f*x))**n*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(1))), x) def replacement4205(a, b, c, d, e, f, n, x): return Dist(a/c, Int(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))**(n + S(1)), x), x) + Simp(-S(4)*a**S(2)*(c + d/sin(e + f*x))**n/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(1))*tan(e + f*x)), x) def replacement4206(a, b, c, d, e, f, n, x): return Dist(a, Int(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))**n, x), x) + Simp(S(2)*a**S(2)*(c + d/cos(e + f*x))**n*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(1))), x) def replacement4207(a, b, c, d, e, f, n, x): return Dist(a, Int(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))**n, x), x) + Simp(-S(2)*a**S(2)*(c + d/sin(e + f*x))**n/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(1))*tan(e + f*x)), x) def replacement4208(a, b, c, d, e, f, n, x): return Dist(a**S(2)/c**S(2), Int(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))**(n + S(2)), x), x) + Simp(S(8)*a**S(3)*(c + d/cos(e + f*x))**n*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(1))), x) def replacement4209(a, b, c, d, e, f, n, x): return Dist(a**S(2)/c**S(2), Int(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))**(n + S(2)), x), x) + Simp(-S(8)*a**S(3)*(c + d/sin(e + f*x))**n/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(1))*tan(e + f*x)), x) def replacement4210(a, b, c, d, e, f, m, n, x): return Dist(a*c*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Subst(Int(x**(-m - n)*(a*x + b)**(m + S(-1)/2)*(c*x + d)**(n + S(-1)/2), x), x, cos(e + f*x)), x) def replacement4211(a, b, c, d, e, f, m, n, x): return -Dist(a*c/(f*sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Subst(Int(x**(-m - n)*(a*x + b)**(m + S(-1)/2)*(c*x + d)**(n + S(-1)/2), x), x, sin(e + f*x)), x) def replacement4212(a, b, c, d, e, f, m, n, x): return -Dist(a*c*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2)/x, x), x, S(1)/cos(e + f*x)), x) def replacement4213(a, b, c, d, e, f, m, n, x): return Dist(a*c/(f*sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2)/x, x), x, S(1)/sin(e + f*x)), x) def replacement4214(a, b, c, d, e, f, x): return Dist(b*d, Int(cos(e + f*x)**(S(-2)), x), x) + Simp(a*c*x, x) def replacement4215(a, b, c, d, e, f, x): return Dist(b*d, Int(sin(e + f*x)**(S(-2)), x), x) + Simp(a*c*x, x) def replacement4216(a, b, c, d, e, f, x): return Dist(b*d, Int(cos(e + f*x)**(S(-2)), x), x) + Dist(a*d + b*c, Int(S(1)/cos(e + f*x), x), x) + Simp(a*c*x, x) def replacement4217(a, b, c, d, e, f, x): return Dist(b*d, Int(sin(e + f*x)**(S(-2)), x), x) + Dist(a*d + b*c, Int(S(1)/sin(e + f*x), x), x) + Simp(a*c*x, x) def replacement4218(a, b, c, d, e, f, x): return Dist(c, Int(sqrt(a + b/cos(e + f*x)), x), x) + Dist(d, Int(sqrt(a + b/cos(e + f*x))/cos(e + f*x), x), x) def replacement4219(a, b, c, d, e, f, x): return Dist(c, Int(sqrt(a + b/sin(e + f*x)), x), x) + Dist(d, Int(sqrt(a + b/sin(e + f*x))/sin(e + f*x), x), x) def replacement4220(a, b, c, d, e, f, x): return Dist(a*c, Int(S(1)/sqrt(a + b/cos(e + f*x)), x), x) + Int((a*d + b*c + b*d/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x) def replacement4221(a, b, c, d, e, f, x): return Dist(a*c, Int(S(1)/sqrt(a + b/sin(e + f*x)), x), x) + Int((a*d + b*c + b*d/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x) def replacement4222(a, b, c, d, e, f, m, x): return Dist(S(1)/m, Int((a + b/cos(e + f*x))**(m + S(-1))*Simp(a*c*m + (a*d*(S(2)*m + S(-1)) + b*c*m)/cos(e + f*x), x), x), x) + Simp(b*d*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*m), x) def replacement4223(a, b, c, d, e, f, m, x): return Dist(S(1)/m, Int((a + b/sin(e + f*x))**(m + S(-1))*Simp(a*c*m + (a*d*(S(2)*m + S(-1)) + b*c*m)/sin(e + f*x), x), x), x) - Simp(b*d*(a + b/sin(e + f*x))**(m + S(-1))/(f*m*tan(e + f*x)), x) def replacement4224(a, b, c, d, e, f, m, x): return Dist(S(1)/m, Int((a + b/cos(e + f*x))**(m + S(-2))*Simp(a**S(2)*c*m + b*(a*d*(S(2)*m + S(-1)) + b*c*m)/cos(e + f*x)**S(2) + (a**S(2)*d*m + S(2)*a*b*c*m + b**S(2)*d*(m + S(-1)))/cos(e + f*x), x), x), x) + Simp(b*d*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*m), x) def replacement4225(a, b, c, d, e, f, m, x): return Dist(S(1)/m, Int((a + b/sin(e + f*x))**(m + S(-2))*Simp(a**S(2)*c*m + b*(a*d*(S(2)*m + S(-1)) + b*c*m)/sin(e + f*x)**S(2) + (a**S(2)*d*m + S(2)*a*b*c*m + b**S(2)*d*(m + S(-1)))/sin(e + f*x), x), x), x) - Simp(b*d*(a + b/sin(e + f*x))**(m + S(-1))/(f*m*tan(e + f*x)), x) def replacement4226(a, b, c, d, e, f, x): return -Dist((-a*d + b*c)/a, Int(S(1)/((a + b/cos(e + f*x))*cos(e + f*x)), x), x) + Simp(c*x/a, x) def replacement4227(a, b, c, d, e, f, x): return -Dist((-a*d + b*c)/a, Int(S(1)/((a + b/sin(e + f*x))*sin(e + f*x)), x), x) + Simp(c*x/a, x) def replacement4228(a, b, c, d, e, f, x): return Dist(c/a, Int(sqrt(a + b/cos(e + f*x)), x), x) - Dist((-a*d + b*c)/a, Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4229(a, b, c, d, e, f, x): return Dist(c/a, Int(sqrt(a + b/sin(e + f*x)), x), x) - Dist((-a*d + b*c)/a, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4230(a, b, c, d, e, f, x): return Dist(c, Int(S(1)/sqrt(a + b/cos(e + f*x)), x), x) + Dist(d, Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4231(a, b, c, d, e, f, x): return Dist(c, Int(S(1)/sqrt(a + b/sin(e + f*x)), x), x) + Dist(d, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4232(a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(a*c*(S(2)*m + S(1)) - (m + S(1))*(-a*d + b*c)/cos(e + f*x), x), x), x) + Simp((a + b/cos(e + f*x))**m*(-a*d + b*c)*tan(e + f*x)/(b*f*(S(2)*m + S(1))), x) def replacement4233(a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(a*c*(S(2)*m + S(1)) - (m + S(1))*(-a*d + b*c)/sin(e + f*x), x), x), x) - Simp((a + b/sin(e + f*x))**m*(-a*d + b*c)/(b*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4234(a, b, c, d, e, f, m, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(-a*(m + S(1))*(-a*d + b*c)/cos(e + f*x) + b*(m + S(2))*(-a*d + b*c)/cos(e + f*x)**S(2) + c*(a**S(2) - b**S(2))*(m + S(1)), x), x), x) - Simp(b*(a + b/cos(e + f*x))**(m + S(1))*(-a*d + b*c)*tan(e + f*x)/(a*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4235(a, b, c, d, e, f, m, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(-a*(m + S(1))*(-a*d + b*c)/sin(e + f*x) + b*(m + S(2))*(-a*d + b*c)/sin(e + f*x)**S(2) + c*(a**S(2) - b**S(2))*(m + S(1)), x), x), x) + Simp(b*(a + b/sin(e + f*x))**(m + S(1))*(-a*d + b*c)/(a*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4236(a, b, c, d, e, f, m, x): return Dist(c, Int((a + b/cos(e + f*x))**m, x), x) + Dist(d, Int((a + b/cos(e + f*x))**m/cos(e + f*x), x), x) def replacement4237(a, b, c, d, e, f, m, x): return Dist(c, Int((a + b/sin(e + f*x))**m, x), x) + Dist(d, Int((a + b/sin(e + f*x))**m/sin(e + f*x), x), x) def replacement4238(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b/cos(e + f*x)), x), x) - Dist(d/c, Int(sqrt(a + b/cos(e + f*x))/((c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4239(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b/sin(e + f*x)), x), x) - Dist(d/c, Int(sqrt(a + b/sin(e + f*x))/((c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4240(a, b, c, d, e, f, x): return Dist(a/c, Int(S(1)/sqrt(a + b/cos(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4241(a, b, c, d, e, f, x): return Dist(a/c, Int(S(1)/sqrt(a + b/sin(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4242(a, b, c, d, e, f, x): return Dist(a/c, Int(sqrt(a + b/cos(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(sqrt(a + b/cos(e + f*x))/((c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4243(a, b, c, d, e, f, x): return Dist(a/c, Int(sqrt(a + b/sin(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(sqrt(a + b/sin(e + f*x))/((c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4244(a, b, c, d, e, f, x): return Dist(S(1)/(c*d), Int((a**S(2)*d + b**S(2)*c/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) - Dist((-a*d + b*c)**S(2)/(c*d), Int(S(1)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4245(a, b, c, d, e, f, x): return Dist(S(1)/(c*d), Int((a**S(2)*d + b**S(2)*c/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) - Dist((-a*d + b*c)**S(2)/(c*d), Int(S(1)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4246(a, b, c, d, e, f, x): return Dist(S(1)/(c*(-a*d + b*c)), Int((-a*d + b*c - b*d/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) + Dist(d**S(2)/(c*(-a*d + b*c)), Int(sqrt(a + b/cos(e + f*x))/((c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4247(a, b, c, d, e, f, x): return Dist(S(1)/(c*(-a*d + b*c)), Int((-a*d + b*c - b*d/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) + Dist(d**S(2)/(c*(-a*d + b*c)), Int(sqrt(a + b/sin(e + f*x))/((c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4248(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(S(1)/sqrt(a + b/cos(e + f*x)), x), x) - Dist(d/c, Int(S(1)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4249(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(S(1)/sqrt(a + b/sin(e + f*x)), x), x) - Dist(d/c, Int(S(1)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4250(a, b, c, d, e, f, x): return Dist(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))/tan(e + f*x), Int(tan(e + f*x), x), x) def replacement4251(a, b, c, d, e, f, x): return Dist(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x), Int(S(1)/tan(e + f*x), x), x) def replacement4252(a, b, c, d, e, f, x): return Dist(c, Int(sqrt(a + b/cos(e + f*x))/sqrt(c + d/cos(e + f*x)), x), x) + Dist(d, Int(sqrt(a + b/cos(e + f*x))/(sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4253(a, b, c, d, e, f, x): return Dist(c, Int(sqrt(a + b/sin(e + f*x))/sqrt(c + d/sin(e + f*x)), x), x) + Dist(d, Int(sqrt(a + b/sin(e + f*x))/(sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4254(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x)), x), x) - Dist(d/c, Int(sqrt(a + b/cos(e + f*x))/(sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4255(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x)), x), x) - Dist(d/c, Int(sqrt(a + b/sin(e + f*x))/(sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4256(a, b, c, d, e, f, x): return Dist(S(2)*a/f, Subst(Int(S(1)/(a*c*x**S(2) + S(1)), x), x, tan(e + f*x)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x)))), x) def replacement4257(a, b, c, d, e, f, x): return Dist(-S(2)*a/f, Subst(Int(S(1)/(a*c*x**S(2) + S(1)), x), x, S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x))), x) def replacement4258(a, b, c, d, e, f, x): return Dist(a/c, Int(sqrt(c + d/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4259(a, b, c, d, e, f, x): return Dist(a/c, Int(sqrt(c + d/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4260(a, b, c, d, e, f, x): return Simp(-S(2)*sqrt((S(1) + S(1)/cos(e + f*x))*(-a*d + b*c)/((a + b/cos(e + f*x))*(c - d)))*sqrt(-(S(1) - S(1)/cos(e + f*x))*(-a*d + b*c)/((a + b/cos(e + f*x))*(c + d)))*(a + b/cos(e + f*x))*EllipticPi(a*(c + d)/(c*(a + b)), asin(sqrt(c + d/cos(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b/cos(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(c*f*Rt((a + b)/(c + d), S(2))*tan(e + f*x)), x) def replacement4261(a, b, c, d, e, f, x): return Simp(S(2)*sqrt((S(1) + S(1)/sin(e + f*x))*(-a*d + b*c)/((a + b/sin(e + f*x))*(c - d)))*sqrt(-(S(1) - S(1)/sin(e + f*x))*(-a*d + b*c)/((a + b/sin(e + f*x))*(c + d)))*(a + b/sin(e + f*x))*EllipticPi(a*(c + d)/(c*(a + b)), asin(sqrt(c + d/sin(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b/sin(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))*tan(e + f*x)/(c*f*Rt((a + b)/(c + d), S(2))), x) def replacement4262(a, b, c, d, e, f, x): return Dist(tan(e + f*x)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Int(S(1)/tan(e + f*x), x), x) def replacement4263(a, b, c, d, e, f, x): return Dist(S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Int(tan(e + f*x), x), x) def replacement4264(a, b, c, d, e, f, x): return Dist(S(1)/a, Int(sqrt(a + b/cos(e + f*x))/sqrt(c + d/cos(e + f*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4265(a, b, c, d, e, f, x): return Dist(S(1)/a, Int(sqrt(a + b/sin(e + f*x))/sqrt(c + d/sin(e + f*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4266(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b/cos(e + f*x))/sqrt(c + d/cos(e + f*x)), x), x) - Dist(d/c, Int(sqrt(a + b/cos(e + f*x))/((c + d/cos(e + f*x))**(S(3)/2)*cos(e + f*x)), x), x) def replacement4267(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b/sin(e + f*x))/sqrt(c + d/sin(e + f*x)), x), x) - Dist(d/c, Int(sqrt(a + b/sin(e + f*x))/((c + d/sin(e + f*x))**(S(3)/2)*sin(e + f*x)), x), x) def replacement4268(a, b, c, d, e, f, m, n, x): return -Dist(a**S(2)*tan(e + f*x)/(f*sqrt(a - b/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**n/(x*sqrt(a - b*x)), x), x, S(1)/cos(e + f*x)), x) def replacement4269(a, b, c, d, e, f, m, n, x): return Dist(a**S(2)*cos(e + f*x)/(f*sqrt(a - b/sin(e + f*x))*sqrt(a + b/sin(e + f*x))), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**n/(x*sqrt(a - b*x)), x), x, S(1)/sin(e + f*x)), x) def replacement4270(a, b, c, d, e, f, m, n, x): return Int((a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-m - n), x) def replacement4271(a, b, c, d, e, f, m, n, x): return Int((a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-m - n), x) def replacement4272(a, b, c, d, e, f, m, n, x): return Dist(sqrt(a + b/cos(e + f*x))*sqrt(c*cos(e + f*x) + d)/(sqrt(c + d/cos(e + f*x))*sqrt(a*cos(e + f*x) + b)), Int((a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-m - n), x), x) def replacement4273(a, b, c, d, e, f, m, n, x): return Dist(sqrt(a + b/sin(e + f*x))*sqrt(c*sin(e + f*x) + d)/(sqrt(c + d/sin(e + f*x))*sqrt(a*sin(e + f*x) + b)), Int((a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-m - n), x), x) def replacement4274(a, b, c, d, e, f, m, n, x): return Dist((a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n*(a*cos(e + f*x) + b)**(-m)*(c*cos(e + f*x) + d)**(-n)*cos(e + f*x)**(m + n), Int((a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-m - n), x), x) def replacement4275(a, b, c, d, e, f, m, n, x): return Dist((a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n*(a*sin(e + f*x) + b)**(-m)*(c*sin(e + f*x) + d)**(-n)*sin(e + f*x)**(m + n), Int((a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-m - n), x), x) def replacement4276(a, b, c, d, e, f, m, n, x): return Int(ExpandTrig((a + b/cos(e + f*x))**m, (c + d/cos(e + f*x))**n, x), x) def replacement4277(a, b, c, d, e, f, m, n, x): return Int(ExpandTrig((a + b/sin(e + f*x))**m, (c + d/sin(e + f*x))**n, x), x) def replacement4278(a, b, c, d, e, f, m, n, x): return Int((a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n, x) def replacement4279(a, b, c, d, e, f, m, n, x): return Int((a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n, x) def replacement4280(a, b, d, e, f, m, n, x): return Dist(d**m, Int((d*cos(e + f*x))**(-m + n)*(a*cos(e + f*x) + b)**m, x), x) def replacement4281(a, b, d, e, f, m, n, x): return Dist(d**m, Int((d*sin(e + f*x))**(-m + n)*(a*sin(e + f*x) + b)**m, x), x) def replacement4282(a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d/cos(e + f*x))**p)**FracPart(n)*(d/cos(e + f*x))**(-p*FracPart(n)), Int((d/cos(e + f*x))**(n*p)*(a + b/cos(e + f*x))**m, x), x) def replacement4283(a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d/sin(e + f*x))**p)**FracPart(n)*(d/sin(e + f*x))**(-p*FracPart(n)), Int((d*cos(e + f*x))**(n*p)*(a + b*cos(e + f*x))**m, x), x) def replacement4284(a, b, c, d, e, f, m, n, x): return -Simp(b*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4285(a, b, c, d, e, f, m, n, x): return Simp(b*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4286(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*(c + d/cos(e + f*x))**n/cos(e + f*x), x), x) - Simp(b*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4287(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*(c + d/sin(e + f*x))**n/sin(e + f*x), x), x) + Simp(b*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4288(a, b, c, d, e, f, x): return -Simp(a*c*log(S(1) + b/(a*cos(e + f*x)))*tan(e + f*x)/(b*f*sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), x) def replacement4289(a, b, c, d, e, f, x): return Simp(a*c*log(S(1) + b/(a*sin(e + f*x)))/(b*f*sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), x) def replacement4290(a, b, c, d, e, f, m, x): return Simp(-S(2)*a*c*(a + b/cos(e + f*x))**m*tan(e + f*x)/(b*f*sqrt(c + d/cos(e + f*x))*(S(2)*m + S(1))), x) def replacement4291(a, b, c, d, e, f, m, x): return Simp(S(2)*a*c*(a + b/sin(e + f*x))**m/(b*f*sqrt(c + d/sin(e + f*x))*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4292(a, b, c, d, e, f, m, n, x): return -Dist(d*(S(2)*n + S(-1))/(b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*(c + d/cos(e + f*x))**(n + S(-1))/cos(e + f*x), x), x) + Simp(-S(2)*a*c*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**(n + S(-1))*tan(e + f*x)/(b*f*(S(2)*m + S(1))), x) def replacement4293(a, b, c, d, e, f, m, n, x): return -Dist(d*(S(2)*n + S(-1))/(b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*(c + d/sin(e + f*x))**(n + S(-1))/sin(e + f*x), x), x) + Simp(S(2)*a*c*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**(n + S(-1))/(b*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4294(a, b, c, d, e, f, m, n, x): return Dist(c*(S(2)*n + S(-1))/(m + n), Int((a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**(n + S(-1))/cos(e + f*x), x), x) + Simp(d*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**(n + S(-1))*tan(e + f*x)/(f*(m + n)), x) def replacement4295(a, b, c, d, e, f, m, n, x): return Dist(c*(S(2)*n + S(-1))/(m + n), Int((a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**(n + S(-1))/sin(e + f*x), x), x) - Simp(d*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**(n + S(-1))/(f*(m + n)*tan(e + f*x)), x) def replacement4296(a, b, c, d, e, f, n, x): return Dist(S(2)*c, Int((c + d/cos(e + f*x))**(n + S(-1))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) + Simp(S(2)*d*(c + d/cos(e + f*x))**(n + S(-1))*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(-1))), x) def replacement4297(a, b, c, d, e, f, n, x): return Dist(S(2)*c, Int((c + d/sin(e + f*x))**(n + S(-1))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) + Simp(-S(2)*d*(c + d/sin(e + f*x))**(n + S(-1))/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(-1))*tan(e + f*x)), x) def replacement4298(a, b, c, d, e, f, m, n, x): return -Dist(d*(S(2)*n + S(-1))/(b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*(c + d/cos(e + f*x))**(n + S(-1))/cos(e + f*x), x), x) + Simp(-S(2)*a*c*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**(n + S(-1))*tan(e + f*x)/(b*f*(S(2)*m + S(1))), x) def replacement4299(a, b, c, d, e, f, m, n, x): return -Dist(d*(S(2)*n + S(-1))/(b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*(c + d/sin(e + f*x))**(n + S(-1))/sin(e + f*x), x), x) + Simp(S(2)*a*c*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**(n + S(-1))/(b*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4300(a, b, c, d, e, f, m, n, x): return Dist((-a*c)**m, Int(ExpandTrig(tan(e + f*x)**(S(2)*m)/cos(e + f*x), (c + d/cos(e + f*x))**(-m + n), x), x), x) def replacement4301(a, b, c, d, e, f, m, n, x): return Dist((-a*c)**m, Int(ExpandTrig((S(1)/tan(e + f*x))**(S(2)*m)/sin(e + f*x), (c + d/sin(e + f*x))**(-m + n), x), x), x) def replacement4302(a, b, c, d, e, f, m, x): return Dist((-a*c)**(m + S(1)/2)*tan(e + f*x)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Int(tan(e + f*x)**(S(2)*m)/cos(e + f*x), x), x) def replacement4303(a, b, c, d, e, f, m, x): return Dist((-a*c)**(m + S(1)/2)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Int((S(1)/tan(e + f*x))**(S(2)*m)/sin(e + f*x), x), x) def replacement4304(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*(c + d/cos(e + f*x))**n/cos(e + f*x), x), x) - Simp(b*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4305(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*(c + d/sin(e + f*x))**n/sin(e + f*x), x), x) + Simp(b*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4306(a, b, c, d, e, f, m, n, x): return -Dist(a*c*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2), x), x, S(1)/cos(e + f*x)), x) def replacement4307(a, b, c, d, e, f, m, n, x): return Dist(a*c/(f*sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2), x), x, S(1)/sin(e + f*x)), x) def replacement4308(a, b, c, d, e, f, g, m, n, p, x): return Dist((-a*c)**m, Int(ExpandTrig((g/cos(e + f*x))**p*tan(e + f*x)**(S(2)*m), (c + d/cos(e + f*x))**(-m + n), x), x), x) def replacement4309(a, b, c, d, e, f, g, m, n, p, x): return Dist((-a*c)**m, Int(ExpandTrig((g/sin(e + f*x))**p*(S(1)/tan(e + f*x))**(S(2)*m), (c + d/sin(e + f*x))**(-m + n), x), x), x) def replacement4310(a, b, c, d, e, f, g, m, p, x): return Dist((-a*c)**(m + S(1)/2)*tan(e + f*x)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Int((g/cos(e + f*x))**p*tan(e + f*x)**(S(2)*m), x), x) def replacement4311(a, b, c, d, e, f, g, m, p, x): return Dist((-a*c)**(m + S(1)/2)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Int((g/sin(e + f*x))**p*(S(1)/tan(e + f*x))**(S(2)*m), x), x) def replacement4312(a, b, c, d, e, f, g, m, n, p, x): return -Dist(a*c*g*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))), Subst(Int((g*x)**(p + S(-1))*(a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2), x), x, S(1)/cos(e + f*x)), x) def replacement4313(a, b, c, d, e, f, g, m, n, p, x): return Dist(a*c*g/(f*sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x)), Subst(Int((g*x)**(p + S(-1))*(a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2), x), x, S(1)/sin(e + f*x)), x) def replacement4314(a, b, c, d, e, f, g, x): return Dist(S(2)*b*g/f, Subst(Int(S(1)/(a*d + b*c - c*g*x**S(2)), x), x, b*tan(e + f*x)/(sqrt(g/cos(e + f*x))*sqrt(a + b/cos(e + f*x)))), x) def replacement4315(a, b, c, d, e, f, g, x): return Dist(-S(2)*b*g/f, Subst(Int(S(1)/(a*d + b*c - c*g*x**S(2)), x), x, b/(sqrt(g/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x))), x) def replacement4316(a, b, c, d, e, f, g, x): return Dist(a/c, Int(sqrt(g/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) + Dist((-a*d + b*c)/(c*g), Int((g/cos(e + f*x))**(S(3)/2)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))), x), x) def replacement4317(a, b, c, d, e, f, g, x): return Dist(a/c, Int(sqrt(g/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) + Dist((-a*d + b*c)/(c*g), Int((g/sin(e + f*x))**(S(3)/2)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))), x), x) def replacement4318(a, b, c, d, e, f, x): return Dist(S(2)*b/f, Subst(Int(S(1)/(a*d + b*c + d*x**S(2)), x), x, b*tan(e + f*x)/sqrt(a + b/cos(e + f*x))), x) def replacement4319(a, b, c, d, e, f, x): return Dist(-S(2)*b/f, Subst(Int(S(1)/(a*d + b*c + d*x**S(2)), x), x, b/(sqrt(a + b/sin(e + f*x))*tan(e + f*x))), x) def replacement4320(a, b, c, d, e, f, x): return Simp(sqrt(c/(c + d/cos(e + f*x)))*sqrt(a + b/cos(e + f*x))*EllipticE(asin(c*tan(e + f*x)/(c + d/cos(e + f*x))), -(-a*d + b*c)/(a*d + b*c))/(d*f*sqrt(c*d*(a + b/cos(e + f*x))/((c + d/cos(e + f*x))*(a*d + b*c)))), x) def replacement4321(a, b, c, d, e, f, x): return -Simp(sqrt(c/(c + d/sin(e + f*x)))*sqrt(a + b/sin(e + f*x))*EllipticE(asin(c/((c + d/sin(e + f*x))*tan(e + f*x))), -(-a*d + b*c)/(a*d + b*c))/(d*f*sqrt(c*d*(a + b/sin(e + f*x))/((c + d/sin(e + f*x))*(a*d + b*c)))), x) def replacement4322(a, b, c, d, e, f, x): return Dist(b/d, Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(S(1)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4323(a, b, c, d, e, f, x): return Dist(b/d, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(S(1)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4324(a, b, c, d, e, f, g, x): return Dist(g/d, Int(sqrt(g/cos(e + f*x))*sqrt(a + b/cos(e + f*x)), x), x) - Dist(c*g/d, Int(sqrt(g/cos(e + f*x))*sqrt(a + b/cos(e + f*x))/(c + d/cos(e + f*x)), x), x) def replacement4325(a, b, c, d, e, f, g, x): return Dist(g/d, Int(sqrt(g/sin(e + f*x))*sqrt(a + b/sin(e + f*x)), x), x) - Dist(c*g/d, Int(sqrt(g/sin(e + f*x))*sqrt(a + b/sin(e + f*x))/(c + d/sin(e + f*x)), x), x) def replacement4326(a, b, c, d, e, f, g, x): return Dist(b/d, Int((g/cos(e + f*x))**(S(3)/2)/sqrt(a + b/cos(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int((g/cos(e + f*x))**(S(3)/2)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))), x), x) def replacement4327(a, b, c, d, e, f, g, x): return Dist(b/d, Int((g/sin(e + f*x))**(S(3)/2)/sqrt(a + b/sin(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int((g/sin(e + f*x))**(S(3)/2)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))), x), x) def replacement4328(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(sqrt(a + b/cos(e + f*x))/((c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4329(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(sqrt(a + b/sin(e + f*x))/((c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4330(a, b, c, d, e, f, x): return Simp(S(2)*sqrt((a + b/cos(e + f*x))/(a + b))*EllipticPi(S(2)*d/(c + d), asin(sqrt(S(2))*sqrt(S(1) - S(1)/cos(e + f*x))/S(2)), S(2)*b/(a + b))*tan(e + f*x)/(f*sqrt(-tan(e + f*x)**S(2))*sqrt(a + b/cos(e + f*x))*(c + d)), x) def replacement4331(a, b, c, d, e, f, x): return Simp(-S(2)*sqrt((a + b/sin(e + f*x))/(a + b))*EllipticPi(S(2)*d/(c + d), asin(sqrt(S(2))*sqrt(S(1) - S(1)/sin(e + f*x))/S(2)), S(2)*b/(a + b))/(f*sqrt(-S(1)/tan(e + f*x)**S(2))*sqrt(a + b/sin(e + f*x))*(c + d)*tan(e + f*x)), x) def replacement4332(a, b, c, d, e, f, g, x): return -Dist(a*g/(-a*d + b*c), Int(sqrt(g/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) + Dist(c*g/(-a*d + b*c), Int(sqrt(g/cos(e + f*x))*sqrt(a + b/cos(e + f*x))/(c + d/cos(e + f*x)), x), x) def replacement4333(a, b, c, d, e, f, g, x): return -Dist(a*g/(-a*d + b*c), Int(sqrt(g/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) + Dist(c*g/(-a*d + b*c), Int(sqrt(g/sin(e + f*x))*sqrt(a + b/sin(e + f*x))/(c + d/sin(e + f*x)), x), x) def replacement4334(a, b, c, d, e, f, g, x): return Dist(g*sqrt(g/cos(e + f*x))*sqrt(a*cos(e + f*x) + b)/sqrt(a + b/cos(e + f*x)), Int(S(1)/(sqrt(a*cos(e + f*x) + b)*(c*cos(e + f*x) + d)), x), x) def replacement4335(a, b, c, d, e, f, g, x): return Dist(g*sqrt(g/sin(e + f*x))*sqrt(a*sin(e + f*x) + b)/sqrt(a + b/sin(e + f*x)), Int(S(1)/(sqrt(a*sin(e + f*x) + b)*(c*sin(e + f*x) + d)), x), x) def replacement4336(a, b, c, d, e, f, x): return -Dist(a/(-a*d + b*c), Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) + Dist(c/(-a*d + b*c), Int(sqrt(a + b/cos(e + f*x))/((c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4337(a, b, c, d, e, f, x): return -Dist(a/(-a*d + b*c), Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) + Dist(c/(-a*d + b*c), Int(sqrt(a + b/sin(e + f*x))/((c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4338(a, b, c, d, e, f, x): return Dist(S(1)/d, Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) - Dist(c/d, Int(S(1)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4339(a, b, c, d, e, f, x): return Dist(S(1)/d, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) - Dist(c/d, Int(S(1)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4340(a, b, c, d, e, f, g, x): return Dist(g**S(2)/(d*(-a*d + b*c)), Int(sqrt(g/cos(e + f*x))*(a*c + (-a*d + b*c)/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) - Dist(c**S(2)*g**S(2)/(d*(-a*d + b*c)), Int(sqrt(g/cos(e + f*x))*sqrt(a + b/cos(e + f*x))/(c + d/cos(e + f*x)), x), x) def replacement4341(a, b, c, d, e, f, g, x): return Dist(g**S(2)/(d*(-a*d + b*c)), Int(sqrt(g/sin(e + f*x))*(a*c + (-a*d + b*c)/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) - Dist(c**S(2)*g**S(2)/(d*(-a*d + b*c)), Int(sqrt(g/sin(e + f*x))*sqrt(a + b/sin(e + f*x))/(c + d/sin(e + f*x)), x), x) def replacement4342(a, b, c, d, e, f, g, x): return Dist(g/d, Int((g/cos(e + f*x))**(S(3)/2)/sqrt(a + b/cos(e + f*x)), x), x) - Dist(c*g/d, Int((g/cos(e + f*x))**(S(3)/2)/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))), x), x) def replacement4343(a, b, c, d, e, f, g, x): return Dist(g/d, Int((g/sin(e + f*x))**(S(3)/2)/sqrt(a + b/sin(e + f*x)), x), x) - Dist(c*g/d, Int((g/sin(e + f*x))**(S(3)/2)/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))), x), x) def replacement4344(a, b, c, d, e, f, x): return Dist(S(2)*b/f, Subst(Int(S(1)/(-b*d*x**S(2) + S(1)), x), x, tan(e + f*x)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x)))), x) def replacement4345(a, b, c, d, e, f, x): return Dist(-S(2)*b/f, Subst(Int(S(1)/(-b*d*x**S(2) + S(1)), x), x, S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x))), x) def replacement4346(a, b, c, d, e, f, x): return Dist(b/d, Int(sqrt(c + d/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(S(1)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4347(a, b, c, d, e, f, x): return Dist(b/d, Int(sqrt(c + d/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4348(a, b, c, d, e, f, x): return Simp(S(2)*sqrt((S(1) + S(1)/cos(e + f*x))*(-a*d + b*c)/((a + b/cos(e + f*x))*(c - d)))*sqrt(-(S(1) - S(1)/cos(e + f*x))*(-a*d + b*c)/((a + b/cos(e + f*x))*(c + d)))*(a + b/cos(e + f*x))*EllipticPi(b*(c + d)/(d*(a + b)), asin(sqrt((a + b)/(c + d))*sqrt(c + d/cos(e + f*x))/sqrt(a + b/cos(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(d*f*sqrt((a + b)/(c + d))*tan(e + f*x)), x) def replacement4349(a, b, c, d, e, f, x): return Simp(-S(2)*sqrt((S(1) + S(1)/sin(e + f*x))*(-a*d + b*c)/((a + b/sin(e + f*x))*(c - d)))*sqrt(-(S(1) - S(1)/sin(e + f*x))*(-a*d + b*c)/((a + b/sin(e + f*x))*(c + d)))*(a + b/sin(e + f*x))*EllipticPi(b*(c + d)/(d*(a + b)), asin(sqrt((a + b)/(c + d))*sqrt(c + d/sin(e + f*x))/sqrt(a + b/sin(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))*tan(e + f*x)/(d*f*sqrt((a + b)/(c + d))), x) def replacement4350(a, b, c, d, e, f, x): return Dist(S(2)*a/(b*f), Subst(Int(S(1)/(x**S(2)*(a*c - b*d) + S(2)), x), x, tan(e + f*x)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x)))), x) def replacement4351(a, b, c, d, e, f, x): return Dist(-S(2)*a/(b*f), Subst(Int(S(1)/(x**S(2)*(a*c - b*d) + S(2)), x), x, S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*tan(e + f*x))), x) def replacement4352(a, b, c, d, e, f, x): return Simp(S(2)*sqrt((S(1) - S(1)/cos(e + f*x))*(-a*d + b*c)/((a + b)*(c + d/cos(e + f*x))))*sqrt(-(S(1) + S(1)/cos(e + f*x))*(-a*d + b*c)/((a - b)*(c + d/cos(e + f*x))))*(c + d/cos(e + f*x))*EllipticF(asin(sqrt(a + b/cos(e + f*x))*Rt((c + d)/(a + b), S(2))/sqrt(c + d/cos(e + f*x))), (a + b)*(c - d)/((a - b)*(c + d)))/(f*(-a*d + b*c)*Rt((c + d)/(a + b), S(2))*tan(e + f*x)), x) def replacement4353(a, b, c, d, e, f, x): return Simp(-S(2)*sqrt((S(1) - S(1)/sin(e + f*x))*(-a*d + b*c)/((a + b)*(c + d/sin(e + f*x))))*sqrt(-(S(1) + S(1)/sin(e + f*x))*(-a*d + b*c)/((a - b)*(c + d/sin(e + f*x))))*(c + d/sin(e + f*x))*EllipticF(asin(sqrt(a + b/sin(e + f*x))*Rt((c + d)/(a + b), S(2))/sqrt(c + d/sin(e + f*x))), (a + b)*(c - d)/((a - b)*(c + d)))*tan(e + f*x)/(f*(-a*d + b*c)*Rt((c + d)/(a + b), S(2))), x) def replacement4354(a, b, c, d, e, f, x): return Dist(S(1)/b, Int(sqrt(a + b/cos(e + f*x))/(sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) - Dist(a/b, Int(S(1)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4355(a, b, c, d, e, f, x): return Dist(S(1)/b, Int(sqrt(a + b/sin(e + f*x))/(sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) - Dist(a/b, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4356(a, b, c, d, e, f, x): return Dist((a - b)/(c - d), Int(S(1)/(sqrt(a + b/cos(e + f*x))*sqrt(c + d/cos(e + f*x))*cos(e + f*x)), x), x) + Dist((-a*d + b*c)/(c - d), Int((S(1) + S(1)/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*(c + d/cos(e + f*x))**(S(3)/2)*cos(e + f*x)), x), x) def replacement4357(a, b, c, d, e, f, x): return Dist((a - b)/(c - d), Int(S(1)/(sqrt(a + b/sin(e + f*x))*sqrt(c + d/sin(e + f*x))*sin(e + f*x)), x), x) + Dist((-a*d + b*c)/(c - d), Int((S(1) + S(1)/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*(c + d/sin(e + f*x))**(S(3)/2)*sin(e + f*x)), x), x) def replacement4358(a, b, c, d, e, f, g, m, n, p, x): return -Dist(a**S(2)*g*tan(e + f*x)/(f*sqrt(a - b/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), Subst(Int((g*x)**(p + S(-1))*(a + b*x)**(m + S(-1)/2)*(c + d*x)**n/sqrt(a - b*x), x), x, S(1)/cos(e + f*x)), x) def replacement4359(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**S(2)*g/(f*sqrt(a - b/sin(e + f*x))*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), Subst(Int((g*x)**(p + S(-1))*(a + b*x)**(m + S(-1)/2)*(c + d*x)**n/sqrt(a - b*x), x), x, S(1)/sin(e + f*x)), x) def replacement4360(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(-m - n), Int((g/cos(e + f*x))**(m + n + p)*(a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n, x), x) def replacement4361(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(-m - n), Int((g/sin(e + f*x))**(m + n + p)*(a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n, x), x) def replacement4362(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(-m)*(g/cos(e + f*x))**(m + p)*(c + d/cos(e + f*x))**n*(c*cos(e + f*x) + d)**(-n), Int((a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n, x), x) def replacement4363(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(-m)*(g/sin(e + f*x))**(m + p)*(c + d/sin(e + f*x))**n*(c*sin(e + f*x) + d)**(-n), Int((a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n, x), x) def replacement4364(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/cos(e + f*x))**p*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n*(a*cos(e + f*x) + b)**(-m)*(c*cos(e + f*x) + d)**(-n), Int((a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n, x), x) def replacement4365(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/sin(e + f*x))**p*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n*(a*sin(e + f*x) + b)**(-m)*(c*sin(e + f*x) + d)**(-n), Int((a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n, x), x) def replacement4366(a, b, c, d, e, f, m, n, p, x): return Dist(sqrt(a + b/cos(e + f*x))*sqrt(c*cos(e + f*x) + d)/(sqrt(c + d/cos(e + f*x))*sqrt(a*cos(e + f*x) + b)), Int((a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-m - n - p), x), x) def replacement4367(a, b, c, d, e, f, m, n, p, x): return Dist(sqrt(a + b/sin(e + f*x))*sqrt(c*sin(e + f*x) + d)/(sqrt(c + d/sin(e + f*x))*sqrt(a*sin(e + f*x) + b)), Int((a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-m - n - p), x), x) def replacement4368(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g/cos(e + f*x))**p*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n, x), x) def replacement4369(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g/sin(e + f*x))**p*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n, x), x) def replacement4370(a, b, c, d, e, f, g, m, n, p, x): return Int((g/cos(e + f*x))**p*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n, x) def replacement4371(a, b, c, d, e, f, g, m, n, p, x): return Int((g/sin(e + f*x))**p*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n, x) def replacement4372(A, B, a, b, c, d, e, f, x): return Simp(S(2)*A*sqrt((S(1) - S(1)/cos(e + f*x))*(-a*d + b*c)/((a + b)*(c + d/cos(e + f*x))))*(S(1) + S(1)/cos(e + f*x))*EllipticE(asin(sqrt(a + b/cos(e + f*x))*Rt((c + d)/(a + b), S(2))/sqrt(c + d/cos(e + f*x))), (a + b)*(c - d)/((a - b)*(c + d)))/(f*sqrt(-(S(1) + S(1)/cos(e + f*x))*(-a*d + b*c)/((a - b)*(c + d/cos(e + f*x))))*(-a*d + b*c)*Rt((c + d)/(a + b), S(2))*tan(e + f*x)), x) def replacement4373(A, B, a, b, c, d, e, f, x): return Simp(-S(2)*A*sqrt((S(1) - S(1)/sin(e + f*x))*(-a*d + b*c)/((a + b)*(c + d/sin(e + f*x))))*(S(1) + S(1)/sin(e + f*x))*EllipticE(asin(sqrt(a + b/sin(e + f*x))*Rt((c + d)/(a + b), S(2))/sqrt(c + d/sin(e + f*x))), (a + b)*(c - d)/((a - b)*(c + d)))*tan(e + f*x)/(f*sqrt(-(S(1) + S(1)/sin(e + f*x))*(-a*d + b*c)/((a - b)*(c + d/sin(e + f*x))))*(-a*d + b*c)*Rt((c + d)/(a + b), S(2))), x) def replacement4374(A, B, a, b, d, e, f, n, x): return Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*Simp(n*(A*b + B*a) + (A*a*(n + S(1)) + B*b*n)/cos(e + f*x), x), x), x) - Simp(A*a*(d/cos(e + f*x))**n*tan(e + f*x)/(f*n), x) def replacement4375(A, B, a, b, d, e, f, n, x): return Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*Simp(n*(A*b + B*a) + (A*a*(n + S(1)) + B*b*n)/sin(e + f*x), x), x), x) + Simp(A*a*(d/sin(e + f*x))**n/(f*n*tan(e + f*x)), x) def replacement4376(A, B, a, b, d, e, f, n, x): return Dist(S(1)/(n + S(1)), Int((d/cos(e + f*x))**n*Simp(A*a*(n + S(1)) + B*b*n + (n + S(1))*(A*b + B*a)/cos(e + f*x), x), x), x) + Simp(B*b*(d/cos(e + f*x))**n*tan(e + f*x)/(f*(n + S(1))), x) def replacement4377(A, B, a, b, d, e, f, n, x): return Dist(S(1)/(n + S(1)), Int((d/sin(e + f*x))**n*Simp(A*a*(n + S(1)) + B*b*n + (n + S(1))*(A*b + B*a)/sin(e + f*x), x), x), x) - Simp(B*b*(d/sin(e + f*x))**n/(f*(n + S(1))*tan(e + f*x)), x) def replacement4378(A, B, a, b, e, f, x): return Dist(B/b, Int(S(1)/cos(e + f*x), x), x) + Dist((A*b - B*a)/b, Int(S(1)/((a + b/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4379(A, B, a, b, e, f, x): return Dist(B/b, Int(S(1)/sin(e + f*x), x), x) + Dist((A*b - B*a)/b, Int(S(1)/((a + b/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4380(A, B, a, b, e, f, m, x): return Simp(B*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4381(A, B, a, b, e, f, m, x): return -Simp(B*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4382(A, B, a, b, e, f, m, x): return Dist((A*b*(m + S(1)) + B*a*m)/(a*b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))/cos(e + f*x), x), x) - Simp((a + b/cos(e + f*x))**m*(A*b - B*a)*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4383(A, B, a, b, e, f, m, x): return Dist((A*b*(m + S(1)) + B*a*m)/(a*b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))/sin(e + f*x), x), x) + Simp((a + b/sin(e + f*x))**m*(A*b - B*a)/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4384(A, B, a, b, e, f, m, x): return Dist((A*b*(m + S(1)) + B*a*m)/(b*(m + S(1))), Int((a + b/cos(e + f*x))**m/cos(e + f*x), x), x) + Simp(B*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4385(A, B, a, b, e, f, m, x): return Dist((A*b*(m + S(1)) + B*a*m)/(b*(m + S(1))), Int((a + b/sin(e + f*x))**m/sin(e + f*x), x), x) - Simp(B*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4386(A, B, a, b, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b/cos(e + f*x))**(m + S(-1))*Simp(A*a*(m + S(1)) + B*b*m + (A*b*(m + S(1)) + B*a*m)/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp(B*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4387(A, B, a, b, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b/sin(e + f*x))**(m + S(-1))*Simp(A*a*(m + S(1)) + B*b*m + (A*b*(m + S(1)) + B*a*m)/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp(B*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4388(A, B, a, b, e, f, m, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp((m + S(1))*(A*a - B*b) - (m + S(2))*(A*b - B*a)/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**(m + S(1))*(A*b - B*a)*tan(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4389(A, B, a, b, e, f, m, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp((m + S(1))*(A*a - B*b) - (m + S(2))*(A*b - B*a)/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**(m + S(1))*(A*b - B*a)/(f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4390(A, B, a, b, e, f, x): return Simp(S(2)*sqrt(b*(S(1) - S(1)/cos(e + f*x))/(a + b))*sqrt(-b*(S(1) + S(1)/cos(e + f*x))/(a - b))*(A*b - B*a)*EllipticE(asin(sqrt(a + b/cos(e + f*x))/Rt(a + B*b/A, S(2))), (A*a + B*b)/(A*a - B*b))*Rt(a + B*b/A, S(2))/(b**S(2)*f*tan(e + f*x)), x) def replacement4391(A, B, a, b, e, f, x): return Simp(-S(2)*sqrt(b*(S(1) - S(1)/sin(e + f*x))/(a + b))*sqrt(-b*(S(1) + S(1)/sin(e + f*x))/(a - b))*(A*b - B*a)*EllipticE(asin(sqrt(a + b/sin(e + f*x))/Rt(a + B*b/A, S(2))), (A*a + B*b)/(A*a - B*b))*Rt(a + B*b/A, S(2))*tan(e + f*x)/(b**S(2)*f), x) def replacement4392(A, B, a, b, e, f, x): return Dist(B, Int((S(1) + S(1)/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) + Dist(A - B, Int(S(1)/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) def replacement4393(A, B, a, b, e, f, x): return Dist(B, Int((S(1) + S(1)/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) + Dist(A - B, Int(S(1)/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) def replacement4394(A, B, a, b, e, f, m, x): return Simp(-S(2)*sqrt(S(2))*A*sqrt((A + B/cos(e + f*x))/A)*(A*(a + b/cos(e + f*x))/(A*a + B*b))**(-m)*(A - B/cos(e + f*x))*(a + b/cos(e + f*x))**m*AppellF1(S(1)/2, S(-1)/2, -m, S(3)/2, (A - B/cos(e + f*x))/(S(2)*A), b*(A - B/cos(e + f*x))/(A*b + B*a))/(B*f*tan(e + f*x)), x) def replacement4395(A, B, a, b, e, f, m, x): return Simp(S(2)*sqrt(S(2))*A*sqrt((A + B/sin(e + f*x))/A)*(A*(a + b/sin(e + f*x))/(A*a + B*b))**(-m)*(A - B/sin(e + f*x))*(a + b/sin(e + f*x))**m*AppellF1(S(1)/2, S(-1)/2, -m, S(3)/2, (A - B/sin(e + f*x))/(S(2)*A), b*(A - B/sin(e + f*x))/(A*b + B*a))*tan(e + f*x)/(B*f), x) def replacement4396(A, B, a, b, e, f, m, x): return Dist(B/b, Int((a + b/cos(e + f*x))**(m + S(1))/cos(e + f*x), x), x) + Dist((A*b - B*a)/b, Int((a + b/cos(e + f*x))**m/cos(e + f*x), x), x) def replacement4397(A, B, a, b, e, f, m, x): return Dist(B/b, Int((a + b/sin(e + f*x))**(m + S(1))/sin(e + f*x), x), x) + Dist((A*b - B*a)/b, Int((a + b/sin(e + f*x))**m/sin(e + f*x), x), x) def replacement4398(A, B, a, b, e, f, m, x): return Dist(S(1)/(b**S(2)*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(A*b*m - B*a*m + B*b*(S(2)*m + S(1))/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**m*(A*b - B*a)*tan(e + f*x)/(b*f*(S(2)*m + S(1))), x) def replacement4399(A, B, a, b, e, f, m, x): return Dist(S(1)/(b**S(2)*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(A*b*m - B*a*m + B*b*(S(2)*m + S(1))/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**m*(A*b - B*a)/(b*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4400(A, B, a, b, e, f, m, x): return -Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(A*b - B*a) - (A*a*b*(m + S(2)) - B*(a**S(2) + b**S(2)*(m + S(1))))/cos(e + f*x), x)/cos(e + f*x), x), x) - Simp(a*(a + b/cos(e + f*x))**(m + S(1))*(A*b - B*a)*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4401(A, B, a, b, e, f, m, x): return -Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(A*b - B*a) - (A*a*b*(m + S(2)) - B*(a**S(2) + b**S(2)*(m + S(1))))/sin(e + f*x), x)/sin(e + f*x), x), x) + Simp(a*(a + b/sin(e + f*x))**(m + S(1))*(A*b - B*a)/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4402(A, B, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/cos(e + f*x))**m*Simp(B*b*(m + S(1)) + (A*b*(m + S(2)) - B*a)/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp(B*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + S(2))), x) def replacement4403(A, B, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/sin(e + f*x))**m*Simp(B*b*(m + S(1)) + (A*b*(m + S(2)) - B*a)/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp(B*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + S(2))*tan(e + f*x)), x) def replacement4404(A, B, a, b, d, e, f, m, n, x): return -Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4405(A, B, a, b, d, e, f, m, n, x): return Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4406(A, B, a, b, d, e, f, m, n, x): return Dist((A*a*m + B*b*(m + S(1)))/(a**S(2)*(S(2)*m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1)), x), x) + Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*(A*b - B*a)*tan(e + f*x)/(b*f*(S(2)*m + S(1))), x) def replacement4407(A, B, a, b, d, e, f, m, n, x): return Dist((A*a*m + B*b*(m + S(1)))/(a**S(2)*(S(2)*m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1)), x), x) - Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m*(A*b - B*a)/(b*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4408(A, B, a, b, d, e, f, m, n, x): return -Dist((A*a*m - B*b*n)/(b*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m, x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4409(A, B, a, b, d, e, f, m, n, x): return -Dist((A*a*m - B*b*n)/(b*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m, x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4410(A, B, a, b, d, e, f, n, x): return Simp(S(2)*B*b*(d/cos(e + f*x))**n*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(1))), x) def replacement4411(A, B, a, b, d, e, f, n, x): return Simp(-S(2)*B*b*(d/sin(e + f*x))**n/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(1))*tan(e + f*x)), x) def replacement4412(A, B, a, b, d, e, f, n, x): return Dist((A*b*(S(2)*n + S(1)) + S(2)*B*a*n)/(S(2)*a*d*n), Int((d/cos(e + f*x))**(n + S(1))*sqrt(a + b/cos(e + f*x)), x), x) - Simp(A*b**S(2)*(d/cos(e + f*x))**n*tan(e + f*x)/(a*f*n*sqrt(a + b/cos(e + f*x))), x) def replacement4413(A, B, a, b, d, e, f, n, x): return Dist((A*b*(S(2)*n + S(1)) + S(2)*B*a*n)/(S(2)*a*d*n), Int((d/sin(e + f*x))**(n + S(1))*sqrt(a + b/sin(e + f*x)), x), x) + Simp(A*b**S(2)*(d/sin(e + f*x))**n/(a*f*n*sqrt(a + b/sin(e + f*x))*tan(e + f*x)), x) def replacement4414(A, B, a, b, d, e, f, n, x): return Dist((A*b*(S(2)*n + S(1)) + S(2)*B*a*n)/(b*(S(2)*n + S(1))), Int((d/cos(e + f*x))**n*sqrt(a + b/cos(e + f*x)), x), x) + Simp(S(2)*B*b*(d/cos(e + f*x))**n*tan(e + f*x)/(f*sqrt(a + b/cos(e + f*x))*(S(2)*n + S(1))), x) def replacement4415(A, B, a, b, d, e, f, n, x): return Dist((A*b*(S(2)*n + S(1)) + S(2)*B*a*n)/(b*(S(2)*n + S(1))), Int((d/sin(e + f*x))**n*sqrt(a + b/sin(e + f*x)), x), x) + Simp(-S(2)*B*b*(d/sin(e + f*x))**n/(f*sqrt(a + b/sin(e + f*x))*(S(2)*n + S(1))*tan(e + f*x)), x) def replacement4416(A, B, a, b, d, e, f, m, n, x): return -Dist(b/(a*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-1))*Simp(A*a*(m - n + S(-1)) - B*b*n - (A*b*(m + n) + B*a*n)/cos(e + f*x), x), x), x) - Simp(A*a*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*n), x) def replacement4417(A, B, a, b, d, e, f, m, n, x): return -Dist(b/(a*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-1))*Simp(A*a*(m - n + S(-1)) - B*b*n - (A*b*(m + n) + B*a*n)/sin(e + f*x), x), x), x) + Simp(A*a*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))/(f*n*tan(e + f*x)), x) def replacement4418(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*Simp(A*a*d*(m + n) + B*b*d*n + (A*b*d*(m + n) + B*a*d*(S(2)*m + n + S(-1)))/cos(e + f*x), x), x), x) + Simp(B*b*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*(m + n)), x) def replacement4419(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))*Simp(A*a*d*(m + n) + B*b*d*n + (A*b*d*(m + n) + B*a*d*(S(2)*m + n + S(-1)))/sin(e + f*x), x), x), x) - Simp(B*b*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))/(f*(m + n)*tan(e + f*x)), x) def replacement4420(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*Simp(A*a*d*(n + S(-1)) - B*b*d*(n + S(-1)) - d*(A*b*(m + n) + B*a*(m - n + S(1)))/cos(e + f*x), x), x), x) - Simp(d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*(A*b - B*a)*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4421(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*Simp(A*a*d*(n + S(-1)) - B*b*d*(n + S(-1)) - d*(A*b*(m + n) + B*a*(m - n + S(1)))/sin(e + f*x), x), x), x) + Simp(d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m*(A*b - B*a)/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4422(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*Simp(-A*a*(S(2)*m + n + S(1)) + B*b*n + (A*b - B*a)*(m + n + S(1))/cos(e + f*x), x), x), x) + Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*(A*b - B*a)*tan(e + f*x)/(b*f*(S(2)*m + S(1))), x) def replacement4423(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*Simp(-A*a*(S(2)*m + n + S(1)) + B*b*n + (A*b - B*a)*(m + n + S(1))/sin(e + f*x), x), x), x) - Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m*(A*b - B*a)/(b*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4424(A, B, a, b, d, e, f, m, n, x): return Dist(d/(b*(m + n)), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*Simp(B*b*(n + S(-1)) + (A*b*(m + n) + B*a*m)/cos(e + f*x), x), x), x) + Simp(B*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n)), x) def replacement4425(A, B, a, b, d, e, f, m, n, x): return Dist(d/(b*(m + n)), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m*Simp(B*b*(n + S(-1)) + (A*b*(m + n) + B*a*m)/sin(e + f*x), x), x), x) - Simp(B*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m/(f*(m + n)*tan(e + f*x)), x) def replacement4426(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(b*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m*Simp(A*a*m - A*b*(m + n + S(1))/cos(e + f*x) - B*b*n, x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4427(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(b*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m*Simp(A*a*m - A*b*(m + n + S(1))/sin(e + f*x) - B*b*n, x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4428(A, B, a, b, d, e, f, m, n, x): return Dist(B/b, Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1)), x), x) + Dist((A*b - B*a)/b, Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m, x), x) def replacement4429(A, B, a, b, d, e, f, m, n, x): return Dist(B/b, Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1)), x), x) + Dist((A*b - B*a)/b, Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m, x), x) def replacement4430(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-2))*Simp(a*(-A*b*(m - n + S(-1)) + B*a*n) + b*(A*a*(m + n) + B*b*n)/cos(e + f*x)**S(2) + (A*(a**S(2)*(n + S(1)) + b**S(2)*n) + S(2)*B*a*b*n)/cos(e + f*x), x), x), x) - Simp(A*a*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*n), x) def replacement4431(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-2))*Simp(a*(-A*b*(m - n + S(-1)) + B*a*n) + b*(A*a*(m + n) + B*b*n)/sin(e + f*x)**S(2) + (A*(a**S(2)*(n + S(1)) + b**S(2)*n) + S(2)*B*a*b*n)/sin(e + f*x), x), x), x) + Simp(A*a*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))/(f*n*tan(e + f*x)), x) def replacement4432(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(m + n), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-2))*Simp(A*a**S(2)*(m + n) + B*a*b*n + b*(A*b*(m + n) + B*a*(S(2)*m + n + S(-1)))/cos(e + f*x)**S(2) + (B*b**S(2)*(m + n + S(-1)) + a*(m + n)*(S(2)*A*b + B*a))/cos(e + f*x), x), x), x) + Simp(B*b*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*tan(e + f*x)/(f*(m + n)), x) def replacement4433(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(m + n), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-2))*Simp(A*a**S(2)*(m + n) + B*a*b*n + b*(A*b*(m + n) + B*a*(S(2)*m + n + S(-1)))/sin(e + f*x)**S(2) + (B*b**S(2)*(m + n + S(-1)) + a*(m + n)*(S(2)*A*b + B*a))/sin(e + f*x), x), x), x) - Simp(B*b*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))/(f*(m + n)*tan(e + f*x)), x) def replacement4434(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*Simp(d*(m + S(1))*(A*a - B*b)/cos(e + f*x) + d*(n + S(-1))*(A*b - B*a) - d*(A*b - B*a)*(m + n + S(1))/cos(e + f*x)**S(2), x), x), x) + Simp(d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*(A*b - B*a)*tan(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4435(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*Simp(d*(m + S(1))*(A*a - B*b)/sin(e + f*x) + d*(n + S(-1))*(A*b - B*a) - d*(A*b - B*a)*(m + n + S(1))/sin(e + f*x)**S(2), x), x), x) - Simp(d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*(A*b - B*a)/(f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4436(A, B, a, b, d, e, f, m, n, x): return -Dist(d/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**(m + S(1))*Simp(a*d*(n + S(-2))*(A*b - B*a) + b*d*(m + S(1))*(A*b - B*a)/cos(e + f*x) - (A*a*b*d*(m + n) - B*d*(a**S(2)*(n + S(-1)) + b**S(2)*(m + S(1))))/cos(e + f*x)**S(2), x), x), x) - Simp(a*d**S(2)*(d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**(m + S(1))*(A*b - B*a)*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4437(A, B, a, b, d, e, f, m, n, x): return -Dist(d/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**(m + S(1))*Simp(a*d*(n + S(-2))*(A*b - B*a) + b*d*(m + S(1))*(A*b - B*a)/sin(e + f*x) - (A*a*b*d*(m + n) - B*d*(a**S(2)*(n + S(-1)) + b**S(2)*(m + S(1))))/sin(e + f*x)**S(2), x), x), x) + Simp(a*d**S(2)*(d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**(m + S(1))*(A*b - B*a)/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4438(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*Simp(A*(a**S(2)*(m + S(1)) - b**S(2)*(m + n + S(1))) + B*a*b*n - a*(m + S(1))*(A*b - B*a)/cos(e + f*x) + b*(A*b - B*a)*(m + n + S(2))/cos(e + f*x)**S(2), x), x), x) - Simp(b*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*(A*b - B*a)*tan(e + f*x)/(a*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4439(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*Simp(A*(a**S(2)*(m + S(1)) - b**S(2)*(m + n + S(1))) + B*a*b*n - a*(m + S(1))*(A*b - B*a)/sin(e + f*x) + b*(A*b - B*a)*(m + n + S(2))/sin(e + f*x)**S(2), x), x), x) + Simp(b*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*(A*b - B*a)/(a*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4440(A, B, a, b, d, e, f, m, n, x): return Dist(d/(m + n), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(-1))*Simp(B*a*(n + S(-1)) + (A*a*(m + n) + B*b*(m + n + S(-1)))/cos(e + f*x) + (A*b*(m + n) + B*a*m)/cos(e + f*x)**S(2), x), x), x) + Simp(B*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n)), x) def replacement4441(A, B, a, b, d, e, f, m, n, x): return Dist(d/(m + n), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(-1))*Simp(B*a*(n + S(-1)) + (A*a*(m + n) + B*b*(m + n + S(-1)))/sin(e + f*x) + (A*b*(m + n) + B*a*m)/sin(e + f*x)**S(2), x), x), x) - Simp(B*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m/(f*(m + n)*tan(e + f*x)), x) def replacement4442(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-1))*Simp(A*b*m - A*b*(m + n + S(1))/cos(e + f*x)**S(2) - B*a*n - (A*a*(n + S(1)) + B*b*n)/cos(e + f*x), x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4443(A, B, a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-1))*Simp(A*b*m - A*b*(m + n + S(1))/sin(e + f*x)**S(2) - B*a*n - (A*a*(n + S(1)) + B*b*n)/sin(e + f*x), x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4444(A, B, a, b, d, e, f, m, n, x): return Dist(d**S(2)/(b*(m + n)), Int((d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**m*Simp(B*a*(n + S(-2)) + B*b*(m + n + S(-1))/cos(e + f*x) + (A*b*(m + n) - B*a*(n + S(-1)))/cos(e + f*x)**S(2), x), x), x) + Simp(B*d**S(2)*(d/cos(e + f*x))**(n + S(-2))*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + n)), x) def replacement4445(A, B, a, b, d, e, f, m, n, x): return Dist(d**S(2)/(b*(m + n)), Int((d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**m*Simp(B*a*(n + S(-2)) + B*b*(m + n + S(-1))/sin(e + f*x) + (A*b*(m + n) - B*a*(n + S(-1)))/sin(e + f*x)**S(2), x), x), x) - Simp(B*d**S(2)*(d/sin(e + f*x))**(n + S(-2))*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + n)*tan(e + f*x)), x) def replacement4446(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m*Simp(A*a*(n + S(1))/cos(e + f*x) - A*b*(m + n + S(1)) + A*b*(m + n + S(2))/cos(e + f*x)**S(2) + B*a*n, x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(a*f*n), x) def replacement4447(A, B, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m*Simp(A*a*(n + S(1))/sin(e + f*x) - A*b*(m + n + S(1)) + A*b*(m + n + S(2))/sin(e + f*x)**S(2) + B*a*n, x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))/(a*f*n*tan(e + f*x)), x) def replacement4448(A, B, a, b, d, e, f, x): return Dist(A/a, Int(sqrt(a + b/cos(e + f*x))/sqrt(d/cos(e + f*x)), x), x) - Dist((A*b - B*a)/(a*d), Int(sqrt(d/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) def replacement4449(A, B, a, b, d, e, f, x): return Dist(A/a, Int(sqrt(a + b/sin(e + f*x))/sqrt(d/sin(e + f*x)), x), x) - Dist((A*b - B*a)/(a*d), Int(sqrt(d/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) def replacement4450(A, B, a, b, d, e, f, x): return Dist(A, Int(sqrt(d/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x), x) + Dist(B/d, Int((d/cos(e + f*x))**(S(3)/2)/sqrt(a + b/cos(e + f*x)), x), x) def replacement4451(A, B, a, b, d, e, f, x): return Dist(A, Int(sqrt(d/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x), x) + Dist(B/d, Int((d/sin(e + f*x))**(S(3)/2)/sqrt(a + b/sin(e + f*x)), x), x) def replacement4452(A, B, a, b, d, e, f, x): return Dist(A, Int(sqrt(a + b/cos(e + f*x))/sqrt(d/cos(e + f*x)), x), x) + Dist(B/d, Int(sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x)), x), x) def replacement4453(A, B, a, b, d, e, f, x): return Dist(A, Int(sqrt(a + b/sin(e + f*x))/sqrt(d/sin(e + f*x)), x), x) + Dist(B/d, Int(sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x)), x), x) def replacement4454(A, B, a, b, d, e, f, n, x): return Dist(A/a, Int((d/cos(e + f*x))**n, x), x) - Dist((A*b - B*a)/(a*d), Int((d/cos(e + f*x))**(n + S(1))/(a + b/cos(e + f*x)), x), x) def replacement4455(A, B, a, b, d, e, f, n, x): return Dist(A/a, Int((d/sin(e + f*x))**n, x), x) - Dist((A*b - B*a)/(a*d), Int((d/sin(e + f*x))**(n + S(1))/(a + b/sin(e + f*x)), x), x) def replacement4456(A, B, a, b, d, e, f, m, n, x): return Int((d/cos(e + f*x))**n*(A + B/cos(e + f*x))*(a + b/cos(e + f*x))**m, x) def replacement4457(A, B, a, b, d, e, f, m, n, x): return Int((d/sin(e + f*x))**n*(A + B/sin(e + f*x))*(a + b/sin(e + f*x))**m, x) def replacement4458(A, B, a, b, c, d, e, f, m, n, p, x): return Dist((-a*c)**m, Int((A*cos(e + f*x) + B)**p*(c*cos(e + f*x) + d)**(-m + n)*sin(e + f*x)**(S(2)*m)*cos(e + f*x)**(-m - n - p), x), x) def replacement4459(A, B, a, b, c, d, e, f, m, n, p, x): return Dist((-a*c)**m, Int((A*sin(e + f*x) + B)**p*(c*sin(e + f*x) + d)**(-m + n)*sin(e + f*x)**(-m - n - p)*cos(e + f*x)**(S(2)*m), x), x) def replacement4460(A, B, C, a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(B*b - C*a + C*b/cos(e + f*x), x), x), x) def replacement4461(A, B, C, a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(B*b - C*a + C*b/sin(e + f*x), x), x), x) def replacement4462(A, C, a, b, e, f, m, x): return Dist(C/b**S(2), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(-a + b/cos(e + f*x), x), x), x) def replacement4463(A, C, a, b, e, f, m, x): return Dist(C/b**S(2), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(-a + b/sin(e + f*x), x), x), x) def replacement4464(A, C, b, e, f, m, x): return -Simp(A*(b/cos(e + f*x))**m*tan(e + f*x)/(f*m), x) def replacement4465(A, C, b, e, f, m, x): return Simp(A*(b/sin(e + f*x))**m/(f*m*tan(e + f*x)), x) def replacement4466(A, C, b, e, f, m, x): return Dist((A*(m + S(1)) + C*m)/(b**S(2)*m), Int((b/cos(e + f*x))**(m + S(2)), x), x) - Simp(A*(b/cos(e + f*x))**m*tan(e + f*x)/(f*m), x) def replacement4467(A, C, b, e, f, m, x): return Dist((A*(m + S(1)) + C*m)/(b**S(2)*m), Int((b/sin(e + f*x))**(m + S(2)), x), x) + Simp(A*(b/sin(e + f*x))**m/(f*m*tan(e + f*x)), x) def replacement4468(A, C, b, e, f, m, x): return Dist((A*(m + S(1)) + C*m)/(m + S(1)), Int((b/cos(e + f*x))**m, x), x) + Simp(C*(b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4469(A, C, b, e, f, m, x): return Dist((A*(m + S(1)) + C*m)/(m + S(1)), Int((b/sin(e + f*x))**m, x), x) - Simp(C*(b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4470(B, C, b, e, f, m, x): return Dist(B/b, Int((b/cos(e + f*x))**(m + S(1)), x), x) + Dist(C/b**S(2), Int((b/cos(e + f*x))**(m + S(2)), x), x) def replacement4471(B, C, b, e, f, m, x): return Dist(B/b, Int((b/sin(e + f*x))**(m + S(1)), x), x) + Dist(C/b**S(2), Int((b/sin(e + f*x))**(m + S(2)), x), x) def replacement4472(A, B, C, b, e, f, m, x): return Dist(B/b, Int((b/cos(e + f*x))**(m + S(1)), x), x) + Int((b/cos(e + f*x))**m*(A + C/cos(e + f*x)**S(2)), x) def replacement4473(A, B, C, b, e, f, m, x): return Dist(B/b, Int((b/sin(e + f*x))**(m + S(1)), x), x) + Int((b/sin(e + f*x))**m*(A + C/sin(e + f*x)**S(2)), x) def replacement4474(A, B, C, a, b, e, f, x): return Dist(S(1)/2, Int(Simp(S(2)*A*a + (S(2)*B*a + b*(S(2)*A + C))/cos(e + f*x) + S(2)*(B*b + C*a)/cos(e + f*x)**S(2), x), x), x) + Simp(C*b*tan(e + f*x)/(S(2)*f*cos(e + f*x)), x) def replacement4475(A, B, C, a, b, e, f, x): return Dist(S(1)/2, Int(Simp(S(2)*A*a + (S(2)*B*a + b*(S(2)*A + C))/sin(e + f*x) + S(2)*(B*b + C*a)/sin(e + f*x)**S(2), x), x), x) - Simp(C*b/(S(2)*f*sin(e + f*x)*tan(e + f*x)), x) def replacement4476(A, C, a, b, e, f, x): return Dist(S(1)/2, Int(Simp(S(2)*A*a + S(2)*C*a/cos(e + f*x)**S(2) + b*(S(2)*A + C)/cos(e + f*x), x), x), x) + Simp(C*b*tan(e + f*x)/(S(2)*f*cos(e + f*x)), x) def replacement4477(A, C, a, b, e, f, x): return Dist(S(1)/2, Int(Simp(S(2)*A*a + S(2)*C*a/sin(e + f*x)**S(2) + b*(S(2)*A + C)/sin(e + f*x), x), x), x) - Simp(C*b/(S(2)*f*sin(e + f*x)*tan(e + f*x)), x) def replacement4478(A, B, C, a, b, e, f, x): return Dist(S(1)/b, Int((A*b + (B*b - C*a)/cos(e + f*x))/(a + b/cos(e + f*x)), x), x) + Dist(C/b, Int(S(1)/cos(e + f*x), x), x) def replacement4479(A, B, C, a, b, e, f, x): return Dist(S(1)/b, Int((A*b + (B*b - C*a)/sin(e + f*x))/(a + b/sin(e + f*x)), x), x) + Dist(C/b, Int(S(1)/sin(e + f*x), x), x) def replacement4480(A, C, a, b, e, f, x): return Dist(S(1)/b, Int((A*b - C*a/cos(e + f*x))/(a + b/cos(e + f*x)), x), x) + Dist(C/b, Int(S(1)/cos(e + f*x), x), x) def replacement4481(A, C, a, b, e, f, x): return Dist(S(1)/b, Int((A*b - C*a/sin(e + f*x))/(a + b/sin(e + f*x)), x), x) + Dist(C/b, Int(S(1)/sin(e + f*x), x), x) def replacement4482(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(A*b*(S(2)*m + S(1)) + (B*b*(m + S(1)) - a*(A*(m + S(1)) - C*m))/cos(e + f*x), x), x), x) + Simp((a + b/cos(e + f*x))**m*(A*a - B*b + C*a)*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4483(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(A*b*(S(2)*m + S(1)) + (B*b*(m + S(1)) - a*(A*(m + S(1)) - C*m))/sin(e + f*x), x), x), x) - Simp((a + b/sin(e + f*x))**m*(A*a - B*b + C*a)/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4484(A, C, a, b, e, f, m, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(A*b*(S(2)*m + S(1)) - a*(A*(m + S(1)) - C*m)/cos(e + f*x), x), x), x) + Simp((A + C)*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(S(2)*m + S(1))), x) def replacement4485(A, C, a, b, e, f, m, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(A*b*(S(2)*m + S(1)) - a*(A*(m + S(1)) - C*m)/sin(e + f*x), x), x), x) - Simp((A + C)*(a + b/sin(e + f*x))**m/(f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4486(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(1))), Int((a + b/cos(e + f*x))**m*Simp(A*b*(m + S(1)) + (B*b*(m + S(1)) + C*a*m)/cos(e + f*x), x), x), x) + Simp(C*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4487(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(1))), Int((a + b/sin(e + f*x))**m*Simp(A*b*(m + S(1)) + (B*b*(m + S(1)) + C*a*m)/sin(e + f*x), x), x), x) - Simp(C*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4488(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(1))), Int((a + b/cos(e + f*x))**m*Simp(A*b*(m + S(1)) + C*a*m/cos(e + f*x), x), x), x) + Simp(C*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4489(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(1))), Int((a + b/sin(e + f*x))**m*Simp(A*b*(m + S(1)) + C*a*m/sin(e + f*x), x), x), x) - Simp(C*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4490(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b/cos(e + f*x))**(m + S(-1))*Simp(A*a*(m + S(1)) + (B*b*(m + S(1)) + C*a*m)/cos(e + f*x)**S(2) + (C*b*m + (m + S(1))*(A*b + B*a))/cos(e + f*x), x), x), x) + Simp(C*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4491(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b/sin(e + f*x))**(m + S(-1))*Simp(A*a*(m + S(1)) + (B*b*(m + S(1)) + C*a*m)/sin(e + f*x)**S(2) + (C*b*m + (m + S(1))*(A*b + B*a))/sin(e + f*x), x), x), x) - Simp(C*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4492(A, C, a, b, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b/cos(e + f*x))**(m + S(-1))*Simp(A*a*(m + S(1)) + C*a*m/cos(e + f*x)**S(2) + (A*b*(m + S(1)) + C*b*m)/cos(e + f*x), x), x), x) + Simp(C*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + S(1))), x) def replacement4493(A, C, a, b, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b/sin(e + f*x))**(m + S(-1))*Simp(A*a*(m + S(1)) + C*a*m/sin(e + f*x)**S(2) + (A*b*(m + S(1)) + C*b*m)/sin(e + f*x), x), x), x) - Simp(C*(a + b/sin(e + f*x))**m/(f*(m + S(1))*tan(e + f*x)), x) def replacement4494(A, B, C, a, b, e, f, x): return Dist(C, Int((S(1) + S(1)/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) + Int((A + (B - C)/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x) def replacement4495(A, B, C, a, b, e, f, x): return Dist(C, Int((S(1) + S(1)/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) + Int((A + (B - C)/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x) def replacement4496(A, C, a, b, e, f, x): return Dist(C, Int((S(1) + S(1)/cos(e + f*x))/(sqrt(a + b/cos(e + f*x))*cos(e + f*x)), x), x) + Int((A - C/cos(e + f*x))/sqrt(a + b/cos(e + f*x)), x) def replacement4497(A, C, a, b, e, f, x): return Dist(C, Int((S(1) + S(1)/sin(e + f*x))/(sqrt(a + b/sin(e + f*x))*sin(e + f*x)), x), x) + Int((A - C/sin(e + f*x))/sqrt(a + b/sin(e + f*x)), x) def replacement4498(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(A*(a**S(2) - b**S(2))*(m + S(1)) - a*(m + S(1))*(A*b - B*a + C*b)/cos(e + f*x) + (m + S(2))*(A*b**S(2) - B*a*b + C*a**S(2))/cos(e + f*x)**S(2), x), x), x) - Simp((a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*tan(e + f*x)/(a*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4499(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(A*(a**S(2) - b**S(2))*(m + S(1)) - a*(m + S(1))*(A*b - B*a + C*b)/sin(e + f*x) + (m + S(2))*(A*b**S(2) - B*a*b + C*a**S(2))/sin(e + f*x)**S(2), x), x), x) + Simp((a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))/(a*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4500(A, C, a, b, e, f, m, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(A*(a**S(2) - b**S(2))*(m + S(1)) - a*b*(A + C)*(m + S(1))/cos(e + f*x) + (m + S(2))*(A*b**S(2) + C*a**S(2))/cos(e + f*x)**S(2), x), x), x) - Simp((a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*tan(e + f*x)/(a*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4501(A, C, a, b, e, f, m, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(A*(a**S(2) - b**S(2))*(m + S(1)) - a*b*(A + C)*(m + S(1))/sin(e + f*x) + (m + S(2))*(A*b**S(2) + C*a**S(2))/sin(e + f*x)**S(2), x), x), x) + Simp((a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))/(a*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4502(A, B, C, a, b, e, f, m, x): return Dist(S(1)/b, Int((a + b/cos(e + f*x))**m*(A*b + (B*b - C*a)/cos(e + f*x)), x), x) + Dist(C/b, Int((a + b/cos(e + f*x))**(m + S(1))/cos(e + f*x), x), x) def replacement4503(A, B, C, a, b, e, f, m, x): return Dist(S(1)/b, Int((a + b/sin(e + f*x))**m*(A*b + (B*b - C*a)/sin(e + f*x)), x), x) + Dist(C/b, Int((a + b/sin(e + f*x))**(m + S(1))/sin(e + f*x), x), x) def replacement4504(A, C, a, b, e, f, m, x): return Dist(S(1)/b, Int((a + b/cos(e + f*x))**m*(A*b - C*a/cos(e + f*x)), x), x) + Dist(C/b, Int((a + b/cos(e + f*x))**(m + S(1))/cos(e + f*x), x), x) def replacement4505(A, C, a, b, e, f, m, x): return Dist(S(1)/b, Int((a + b/sin(e + f*x))**m*(A*b - C*a/sin(e + f*x)), x), x) + Dist(C/b, Int((a + b/sin(e + f*x))**(m + S(1))/sin(e + f*x), x), x) def replacement4506(A, B, C, b, e, f, m, x): return Dist(b**S(2), Int((b*cos(e + f*x))**(m + S(-2))*(A*cos(e + f*x)**S(2) + B*cos(e + f*x) + C), x), x) def replacement4507(A, B, C, b, e, f, m, x): return Dist(b**S(2), Int((b*sin(e + f*x))**(m + S(-2))*(A*sin(e + f*x)**S(2) + B*sin(e + f*x) + C), x), x) def replacement4508(A, C, b, e, f, m, x): return Dist(b**S(2), Int((b*cos(e + f*x))**(m + S(-2))*(A*cos(e + f*x)**S(2) + C), x), x) def replacement4509(A, C, b, e, f, m, x): return Dist(b**S(2), Int((b*sin(e + f*x))**(m + S(-2))*(A*sin(e + f*x)**S(2) + C), x), x) def replacement4510(A, B, C, a, b, e, f, m, p, x): return Dist(a**IntPart(m)*(a*(b/cos(e + f*x))**p)**FracPart(m)*(b/cos(e + f*x))**(-p*FracPart(m)), Int((b/cos(e + f*x))**(m*p)*(A + B/cos(e + f*x) + C/cos(e + f*x)**S(2)), x), x) def replacement4511(A, B, C, a, b, e, f, m, p, x): return Dist(a**IntPart(m)*(a*(b/sin(e + f*x))**p)**FracPart(m)*(b/sin(e + f*x))**(-p*FracPart(m)), Int((b/sin(e + f*x))**(m*p)*(A + B/sin(e + f*x) + C/sin(e + f*x)**S(2)), x), x) def replacement4512(A, C, a, b, e, f, m, p, x): return Dist(a**IntPart(m)*(a*(b/cos(e + f*x))**p)**FracPart(m)*(b/cos(e + f*x))**(-p*FracPart(m)), Int((b/cos(e + f*x))**(m*p)*(A + C/cos(e + f*x)**S(2)), x), x) def replacement4513(A, C, a, b, e, f, m, p, x): return Dist(a**IntPart(m)*(a*(b/sin(e + f*x))**p)**FracPart(m)*(b/sin(e + f*x))**(-p*FracPart(m)), Int((b/sin(e + f*x))**(m*p)*(A + C/sin(e + f*x)**S(2)), x), x) def replacement4514(A, B, C, a, b, d, e, f, n, x): return Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*Simp(C*b*n/cos(e + f*x)**S(2) + n*(A*b + B*a) + (A*a*(n + S(1)) + n*(B*b + C*a))/cos(e + f*x), x), x), x) - Simp(A*a*(d/cos(e + f*x))**n*tan(e + f*x)/(f*n), x) def replacement4515(A, B, C, a, b, d, e, f, n, x): return Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*Simp(C*b*n/sin(e + f*x)**S(2) + n*(A*b + B*a) + (A*a*(n + S(1)) + n*(B*b + C*a))/sin(e + f*x), x), x), x) + Simp(A*a*(d/sin(e + f*x))**n/(f*n*tan(e + f*x)), x) def replacement4516(A, C, a, b, d, e, f, n, x): return Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*Simp(A*b*n + C*b*n/cos(e + f*x)**S(2) + a*(A*(n + S(1)) + C*n)/cos(e + f*x), x), x), x) - Simp(A*a*(d/cos(e + f*x))**n*tan(e + f*x)/(f*n), x) def replacement4517(A, C, a, b, d, e, f, n, x): return Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*Simp(A*b*n + C*b*n/sin(e + f*x)**S(2) + a*(A*(n + S(1)) + C*n)/sin(e + f*x), x), x), x) + Simp(A*a*(d/sin(e + f*x))**n/(f*n*tan(e + f*x)), x) def replacement4518(A, B, C, a, b, d, e, f, n, x): return Dist(S(1)/(n + S(2)), Int((d/cos(e + f*x))**n*Simp(A*a*(n + S(2)) + (n + S(2))*(B*b + C*a)/cos(e + f*x)**S(2) + (B*a*(n + S(2)) + b*(A*(n + S(2)) + C*(n + S(1))))/cos(e + f*x), x), x), x) + Simp(C*b*(d/cos(e + f*x))**n*tan(e + f*x)/(f*(n + S(2))*cos(e + f*x)), x) def replacement4519(A, B, C, a, b, d, e, f, n, x): return Dist(S(1)/(n + S(2)), Int((d/sin(e + f*x))**n*Simp(A*a*(n + S(2)) + (n + S(2))*(B*b + C*a)/sin(e + f*x)**S(2) + (B*a*(n + S(2)) + b*(A*(n + S(2)) + C*(n + S(1))))/sin(e + f*x), x), x), x) - Simp(C*b*(d/sin(e + f*x))**n/(f*(n + S(2))*sin(e + f*x)*tan(e + f*x)), x) def replacement4520(A, C, a, b, d, e, f, n, x): return Dist(S(1)/(n + S(2)), Int((d/cos(e + f*x))**n*Simp(A*a*(n + S(2)) + C*a*(n + S(2))/cos(e + f*x)**S(2) + b*(A*(n + S(2)) + C*(n + S(1)))/cos(e + f*x), x), x), x) + Simp(C*b*(d/cos(e + f*x))**n*tan(e + f*x)/(f*(n + S(2))*cos(e + f*x)), x) def replacement4521(A, C, a, b, d, e, f, n, x): return Dist(S(1)/(n + S(2)), Int((d/sin(e + f*x))**n*Simp(A*a*(n + S(2)) + C*a*(n + S(2))/sin(e + f*x)**S(2) + b*(A*(n + S(2)) + C*(n + S(1)))/sin(e + f*x), x), x), x) - Simp(C*b*(d/sin(e + f*x))**n/(f*(n + S(2))*sin(e + f*x)*tan(e + f*x)), x) def replacement4522(A, B, C, a, b, e, f, m, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(-S(2)*A*b*(m + S(1)) + B*a - C*b - (B*b*(m + S(2)) - a*(A*(m + S(2)) - C*(m + S(-1))))/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**m*(A*a - B*b + C*a)*tan(e + f*x)/(a*f*(S(2)*m + S(1))*cos(e + f*x)), x) def replacement4523(A, B, C, a, b, e, f, m, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(-S(2)*A*b*(m + S(1)) + B*a - C*b - (B*b*(m + S(2)) - a*(A*(m + S(2)) - C*(m + S(-1))))/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**m*(A*a - B*b + C*a)/(a*f*(S(2)*m + S(1))*sin(e + f*x)*tan(e + f*x)), x) def replacement4524(A, C, a, b, e, f, m, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(-S(2)*A*b*(m + S(1)) - C*b + a*(A*(m + S(2)) - C*(m + S(-1)))/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp((A + C)*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(S(2)*m + S(1))*cos(e + f*x)), x) def replacement4525(A, C, a, b, e, f, m, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(-S(2)*A*b*(m + S(1)) - C*b + a*(A*(m + S(2)) - C*(m + S(-1)))/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp((A + C)*(a + b/sin(e + f*x))**m/(f*(S(2)*m + S(1))*sin(e + f*x)*tan(e + f*x)), x) def replacement4526(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(A*a - B*b + C*a) - (A*b**S(2) - B*a*b + C*a**S(2) + b*(m + S(1))*(A*b - B*a + C*b))/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4527(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(A*a - B*b + C*a) - (A*b**S(2) - B*a*b + C*a**S(2) + b*(m + S(1))*(A*b - B*a + C*b))/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4528(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(a*b*(A + C)*(m + S(1)) - (A*b**S(2) + C*a**S(2) + b*(m + S(1))*(A*b + C*b))/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp((a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4529(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(a*b*(A + C)*(m + S(1)) - (A*b**S(2) + C*a**S(2) + b*(m + S(1))*(A*b + C*b))/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp((a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4530(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/cos(e + f*x))**m*Simp(A*b*(m + S(2)) + C*b*(m + S(1)) + (B*b*(m + S(2)) - C*a)/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp(C*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + S(2))), x) def replacement4531(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/sin(e + f*x))**m*Simp(A*b*(m + S(2)) + C*b*(m + S(1)) + (B*b*(m + S(2)) - C*a)/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp(C*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + S(2))*tan(e + f*x)), x) def replacement4532(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/cos(e + f*x))**m*Simp(A*b*(m + S(2)) - C*a/cos(e + f*x) + C*b*(m + S(1)), x)/cos(e + f*x), x), x) + Simp(C*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + S(2))), x) def replacement4533(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b/sin(e + f*x))**m*Simp(A*b*(m + S(2)) - C*a/sin(e + f*x) + C*b*(m + S(1)), x)/sin(e + f*x), x), x) - Simp(C*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + S(2))*tan(e + f*x)), x) def replacement4534(A, B, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*Simp(-A*b*(S(2)*m + n + S(1)) + B*a*n - C*b*n - (B*b*(m + n + S(1)) - a*(A*(m + n + S(1)) - C*(m - n)))/cos(e + f*x), x), x), x) + Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*(A*a - B*b + C*a)*tan(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement4535(A, B, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*Simp(-A*b*(S(2)*m + n + S(1)) + B*a*n - C*b*n - (B*b*(m + n + S(1)) - a*(A*(m + n + S(1)) - C*(m - n)))/sin(e + f*x), x), x), x) - Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m*(A*a - B*b + C*a)/(a*f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4536(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*Simp(A*b*(S(2)*m + n + S(1)) + C*b*n - a*(A*(m + n + S(1)) - C*(m - n))/cos(e + f*x), x), x), x) + Simp((d/cos(e + f*x))**n*(A + C)*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(S(2)*m + S(1))), x) def replacement4537(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*Simp(A*b*(S(2)*m + n + S(1)) + C*b*n - a*(A*(m + n + S(1)) - C*(m - n))/sin(e + f*x), x), x), x) - Simp((d/sin(e + f*x))**n*(A + C)*(a + b/sin(e + f*x))**m/(f*(S(2)*m + S(1))*tan(e + f*x)), x) def replacement4538(A, B, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(b*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m*Simp(A*a*m - B*b*n - b*(A*(m + n + S(1)) + C*n)/cos(e + f*x), x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4539(A, B, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(b*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m*Simp(A*a*m - B*b*n - b*(A*(m + n + S(1)) + C*n)/sin(e + f*x), x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4540(A, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(b*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m*Simp(A*a*m - b*(A*(m + n + S(1)) + C*n)/cos(e + f*x), x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4541(A, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(b*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m*Simp(A*a*m - b*(A*(m + n + S(1)) + C*n)/sin(e + f*x), x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4542(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*Simp(A*b*(m + n + S(1)) + C*b*n + (B*b*(m + n + S(1)) + C*a*m)/cos(e + f*x), x), x), x) + Simp(C*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n + S(1))), x) def replacement4543(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m*Simp(A*b*(m + n + S(1)) + C*b*n + (B*b*(m + n + S(1)) + C*a*m)/sin(e + f*x), x), x), x) - Simp(C*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*(m + n + S(1))*tan(e + f*x)), x) def replacement4544(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*Simp(A*b*(m + n + S(1)) + C*a*m/cos(e + f*x) + C*b*n, x), x), x) + Simp(C*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n + S(1))), x) def replacement4545(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m*Simp(A*b*(m + n + S(1)) + C*a*m/sin(e + f*x) + C*b*n, x), x), x) - Simp(C*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*(m + n + S(1))*tan(e + f*x)), x) def replacement4546(A, B, C, a, b, e, f, m, x): return -Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(-C*b*(a**S(2) - b**S(2))*(m + S(1))/cos(e + f*x)**S(2) + b*(m + S(1))*(A*b**S(2) - a*(B*b - C*a)) + (B*b*(a**S(2) + b**S(2)*(m + S(1))) - a*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1)))))/cos(e + f*x), x)/cos(e + f*x), x), x) - Simp(a*(a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*tan(e + f*x)/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4547(A, B, C, a, b, e, f, m, x): return -Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(-C*b*(a**S(2) - b**S(2))*(m + S(1))/sin(e + f*x)**S(2) + b*(m + S(1))*(A*b**S(2) - a*(B*b - C*a)) + (B*b*(a**S(2) + b**S(2)*(m + S(1))) - a*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1)))))/sin(e + f*x), x)/sin(e + f*x), x), x) + Simp(a*(a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4548(A, C, a, b, e, f, m, x): return -Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/cos(e + f*x))**(m + S(1))*Simp(-C*b*(a**S(2) - b**S(2))*(m + S(1))/cos(e + f*x)**S(2) - a*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1))))/cos(e + f*x) + b*(m + S(1))*(A*b**S(2) + C*a**S(2)), x)/cos(e + f*x), x), x) - Simp(a*(a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*tan(e + f*x)/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4549(A, C, a, b, e, f, m, x): return -Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b/sin(e + f*x))**(m + S(1))*Simp(-C*b*(a**S(2) - b**S(2))*(m + S(1))/sin(e + f*x)**S(2) - a*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1))))/sin(e + f*x) + b*(m + S(1))*(A*b**S(2) + C*a**S(2)), x)/sin(e + f*x), x), x) + Simp(a*(a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4550(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b/cos(e + f*x))**m*Simp(C*a + b*(A*(m + S(3)) + C*(m + S(2)))/cos(e + f*x) - (-B*b*(m + S(3)) + S(2)*C*a)/cos(e + f*x)**S(2), x)/cos(e + f*x), x), x) + Simp(C*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + S(3))*cos(e + f*x)), x) def replacement4551(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b/sin(e + f*x))**m*Simp(C*a + b*(A*(m + S(3)) + C*(m + S(2)))/sin(e + f*x) - (-B*b*(m + S(3)) + S(2)*C*a)/sin(e + f*x)**S(2), x)/sin(e + f*x), x), x) - Simp(C*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + S(3))*sin(e + f*x)*tan(e + f*x)), x) def replacement4552(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b/cos(e + f*x))**m*Simp(C*a - S(2)*C*a/cos(e + f*x)**S(2) + b*(A*(m + S(3)) + C*(m + S(2)))/cos(e + f*x), x)/cos(e + f*x), x), x) + Simp(C*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + S(3))*cos(e + f*x)), x) def replacement4553(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b/sin(e + f*x))**m*Simp(C*a - S(2)*C*a/sin(e + f*x)**S(2) + b*(A*(m + S(3)) + C*(m + S(2)))/sin(e + f*x), x)/sin(e + f*x), x), x) - Simp(C*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + S(3))*sin(e + f*x)*tan(e + f*x)), x) def replacement4554(A, B, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-1))*Simp(A*b*m - B*a*n - b*(A*(m + n + S(1)) + C*n)/cos(e + f*x)**S(2) - (B*b*n + a*(A*(n + S(1)) + C*n))/cos(e + f*x), x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4555(A, B, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-1))*Simp(A*b*m - B*a*n - b*(A*(m + n + S(1)) + C*n)/sin(e + f*x)**S(2) - (B*b*n + a*(A*(n + S(1)) + C*n))/sin(e + f*x), x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4556(A, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**(m + S(-1))*Simp(A*b*m - a*(A*(n + S(1)) + C*n)/cos(e + f*x) - b*(A*(m + n + S(1)) + C*n)/cos(e + f*x)**S(2), x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*n), x) def replacement4557(A, C, a, b, d, e, f, m, n, x): return -Dist(S(1)/(d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**(m + S(-1))*Simp(A*b*m - a*(A*(n + S(1)) + C*n)/sin(e + f*x) - b*(A*(m + n + S(1)) + C*n)/sin(e + f*x)**S(2), x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*n*tan(e + f*x)), x) def replacement4558(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(m + n + S(1)), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*Simp(A*a*(m + n + S(1)) + C*a*n + (B*b*(m + n + S(1)) + C*a*m)/cos(e + f*x)**S(2) + (C*b*(m + n) + (A*b + B*a)*(m + n + S(1)))/cos(e + f*x), x), x), x) + Simp(C*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n + S(1))), x) def replacement4559(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(m + n + S(1)), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))*Simp(A*a*(m + n + S(1)) + C*a*n + (B*b*(m + n + S(1)) + C*a*m)/sin(e + f*x)**S(2) + (C*b*(m + n) + (A*b + B*a)*(m + n + S(1)))/sin(e + f*x), x), x), x) - Simp(C*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*(m + n + S(1))*tan(e + f*x)), x) def replacement4560(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(m + n + S(1)), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(-1))*Simp(A*a*(m + n + S(1)) + C*a*m/cos(e + f*x)**S(2) + C*a*n + b*(A*(m + n + S(1)) + C*(m + n))/cos(e + f*x), x), x), x) + Simp(C*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*tan(e + f*x)/(f*(m + n + S(1))), x) def replacement4561(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(m + n + S(1)), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(-1))*Simp(A*a*(m + n + S(1)) + C*a*m/sin(e + f*x)**S(2) + C*a*n + b*(A*(m + n + S(1)) + C*(m + n))/sin(e + f*x), x), x), x) - Simp(C*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m/(f*(m + n + S(1))*tan(e + f*x)), x) def replacement4562(A, B, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*Simp(A*b**S(2)*(n + S(-1)) - a*(n + S(-1))*(B*b - C*a) + b*(m + S(1))*(A*a - B*b + C*a)/cos(e + f*x) - (C*(a**S(2)*n + b**S(2)*(m + S(1))) + b*(A*b - B*a)*(m + n + S(1)))/cos(e + f*x)**S(2), x), x), x) + Simp(d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4563(A, B, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*Simp(A*b**S(2)*(n + S(-1)) - a*(n + S(-1))*(B*b - C*a) + b*(m + S(1))*(A*a - B*b + C*a)/sin(e + f*x) - (C*(a**S(2)*n + b**S(2)*(m + S(1))) + b*(A*b - B*a)*(m + n + S(1)))/sin(e + f*x)**S(2), x), x), x) - Simp(d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4564(A, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*Simp(A*b**S(2)*(n + S(-1)) + C*a**S(2)*(n + S(-1)) + a*b*(A + C)*(m + S(1))/cos(e + f*x) - (A*b**S(2)*(m + n + S(1)) + C*(a**S(2)*n + b**S(2)*(m + S(1))))/cos(e + f*x)**S(2), x), x), x) + Simp(d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*tan(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4565(A, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*Simp(A*b**S(2)*(n + S(-1)) + C*a**S(2)*(n + S(-1)) + a*b*(A + C)*(m + S(1))/sin(e + f*x) - (A*b**S(2)*(m + n + S(1)) + C*(a**S(2)*n + b**S(2)*(m + S(1))))/sin(e + f*x)**S(2), x), x), x) - Simp(d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))/(b*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4566(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*Simp(a*(m + S(1))*(A*a - B*b + C*a) - a*(m + S(1))*(A*b - B*a + C*b)/cos(e + f*x) - (m + n + S(1))*(A*b**S(2) - B*a*b + C*a**S(2)) + (m + n + S(2))*(A*b**S(2) - B*a*b + C*a**S(2))/cos(e + f*x)**S(2), x), x), x) - Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*tan(e + f*x)/(a*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4567(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*Simp(a*(m + S(1))*(A*a - B*b + C*a) - a*(m + S(1))*(A*b - B*a + C*b)/sin(e + f*x) - (m + n + S(1))*(A*b**S(2) - B*a*b + C*a**S(2)) + (m + n + S(2))*(A*b**S(2) - B*a*b + C*a**S(2))/sin(e + f*x)**S(2), x), x), x) + Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))/(a*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4568(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*Simp(a**S(2)*(A + C)*(m + S(1)) - a*b*(A + C)*(m + S(1))/cos(e + f*x) - (A*b**S(2) + C*a**S(2))*(m + n + S(1)) + (A*b**S(2) + C*a**S(2))*(m + n + S(2))/cos(e + f*x)**S(2), x), x), x) - Simp((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*tan(e + f*x)/(a*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement4569(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*(a**S(2) - b**S(2))*(m + S(1))), Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*Simp(a**S(2)*(A + C)*(m + S(1)) - a*b*(A + C)*(m + S(1))/sin(e + f*x) - (A*b**S(2) + C*a**S(2))*(m + n + S(1)) + (A*b**S(2) + C*a**S(2))*(m + n + S(2))/sin(e + f*x)**S(2), x), x), x) + Simp((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))/(a*f*(a**S(2) - b**S(2))*(m + S(1))*tan(e + f*x)), x) def replacement4570(A, B, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(m + n + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*Simp(C*a*(n + S(-1)) + (A*b*(m + n + S(1)) + C*b*(m + n))/cos(e + f*x) + (B*b*(m + n + S(1)) - C*a*n)/cos(e + f*x)**S(2), x), x), x) + Simp(C*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + n + S(1))), x) def replacement4571(A, B, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(m + n + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m*Simp(C*a*(n + S(-1)) + (A*b*(m + n + S(1)) + C*b*(m + n))/sin(e + f*x) + (B*b*(m + n + S(1)) - C*a*n)/sin(e + f*x)**S(2), x), x), x) - Simp(C*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + n + S(1))*tan(e + f*x)), x) def replacement4572(A, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(m + n + S(1))), Int((d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**m*Simp(-C*a*n/cos(e + f*x)**S(2) + C*a*(n + S(-1)) + (A*b*(m + n + S(1)) + C*b*(m + n))/cos(e + f*x), x), x), x) + Simp(C*d*(d/cos(e + f*x))**(n + S(-1))*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(b*f*(m + n + S(1))), x) def replacement4573(A, C, a, b, d, e, f, m, n, x): return Dist(d/(b*(m + n + S(1))), Int((d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**m*Simp(-C*a*n/sin(e + f*x)**S(2) + C*a*(n + S(-1)) + (A*b*(m + n + S(1)) + C*b*(m + n))/sin(e + f*x), x), x), x) - Simp(C*d*(d/sin(e + f*x))**(n + S(-1))*(a + b/sin(e + f*x))**(m + S(1))/(b*f*(m + n + S(1))*tan(e + f*x)), x) def replacement4574(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m*Simp(-A*b*(m + n + S(1)) + A*b*(m + n + S(2))/cos(e + f*x)**S(2) + B*a*n + a*(A*n + A + C*n)/cos(e + f*x), x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(a*f*n), x) def replacement4575(A, B, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m*Simp(-A*b*(m + n + S(1)) + A*b*(m + n + S(2))/sin(e + f*x)**S(2) + B*a*n + a*(A*n + A + C*n)/sin(e + f*x), x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))/(a*f*n*tan(e + f*x)), x) def replacement4576(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*d*n), Int((d/cos(e + f*x))**(n + S(1))*(a + b/cos(e + f*x))**m*Simp(-A*b*(m + n + S(1)) + A*b*(m + n + S(2))/cos(e + f*x)**S(2) + a*(A*n + A + C*n)/cos(e + f*x), x), x), x) - Simp(A*(d/cos(e + f*x))**n*(a + b/cos(e + f*x))**(m + S(1))*tan(e + f*x)/(a*f*n), x) def replacement4577(A, C, a, b, d, e, f, m, n, x): return Dist(S(1)/(a*d*n), Int((d/sin(e + f*x))**(n + S(1))*(a + b/sin(e + f*x))**m*Simp(-A*b*(m + n + S(1)) + A*b*(m + n + S(2))/sin(e + f*x)**S(2) + a*(A*n + A + C*n)/sin(e + f*x), x), x), x) + Simp(A*(d/sin(e + f*x))**n*(a + b/sin(e + f*x))**(m + S(1))/(a*f*n*tan(e + f*x)), x) def replacement4578(A, B, C, a, b, d, e, f, x): return Dist(a**(S(-2)), Int((A*a - (A*b - B*a)/cos(e + f*x))/sqrt(d/cos(e + f*x)), x), x) + Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2)*d**S(2)), Int((d/cos(e + f*x))**(S(3)/2)/(a + b/cos(e + f*x)), x), x) def replacement4579(A, B, C, a, b, d, e, f, x): return Dist(a**(S(-2)), Int((A*a - (A*b - B*a)/sin(e + f*x))/sqrt(d/sin(e + f*x)), x), x) + Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2)*d**S(2)), Int((d/sin(e + f*x))**(S(3)/2)/(a + b/sin(e + f*x)), x), x) def replacement4580(A, C, a, b, d, e, f, x): return Dist(a**(S(-2)), Int((A*a - A*b/cos(e + f*x))/sqrt(d/cos(e + f*x)), x), x) + Dist((A*b**S(2) + C*a**S(2))/(a**S(2)*d**S(2)), Int((d/cos(e + f*x))**(S(3)/2)/(a + b/cos(e + f*x)), x), x) def replacement4581(A, C, a, b, d, e, f, x): return Dist(a**(S(-2)), Int((A*a - A*b/sin(e + f*x))/sqrt(d/sin(e + f*x)), x), x) + Dist((A*b**S(2) + C*a**S(2))/(a**S(2)*d**S(2)), Int((d/sin(e + f*x))**(S(3)/2)/(a + b/sin(e + f*x)), x), x) def replacement4582(A, B, C, a, b, d, e, f, x): return Dist(C/d**S(2), Int((d/cos(e + f*x))**(S(3)/2)/sqrt(a + b/cos(e + f*x)), x), x) + Int((A + B/cos(e + f*x))/(sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), x) def replacement4583(A, B, C, a, b, d, e, f, x): return Dist(C/d**S(2), Int((d/sin(e + f*x))**(S(3)/2)/sqrt(a + b/sin(e + f*x)), x), x) + Int((A + B/sin(e + f*x))/(sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x))), x) def replacement4584(A, C, a, b, d, e, f, x): return Dist(A, Int(S(1)/(sqrt(d/cos(e + f*x))*sqrt(a + b/cos(e + f*x))), x), x) + Dist(C/d**S(2), Int((d/cos(e + f*x))**(S(3)/2)/sqrt(a + b/cos(e + f*x)), x), x) def replacement4585(A, C, a, b, d, e, f, x): return Dist(A, Int(S(1)/(sqrt(d/sin(e + f*x))*sqrt(a + b/sin(e + f*x))), x), x) + Dist(C/d**S(2), Int((d/sin(e + f*x))**(S(3)/2)/sqrt(a + b/sin(e + f*x)), x), x) def replacement4586(A, B, C, a, b, d, e, f, m, n, x): return Int((d/cos(e + f*x))**n*(a + b/cos(e + f*x))**m*(A + B/cos(e + f*x) + C/cos(e + f*x)**S(2)), x) def replacement4587(A, B, C, a, b, d, e, f, m, n, x): return Int((d/sin(e + f*x))**n*(a + b/sin(e + f*x))**m*(A + B/sin(e + f*x) + C/sin(e + f*x)**S(2)), x) def replacement4588(A, C, a, b, d, e, f, m, n, x): return Int((d/cos(e + f*x))**n*(A + C/cos(e + f*x)**S(2))*(a + b/cos(e + f*x))**m, x) def replacement4589(A, C, a, b, d, e, f, m, n, x): return Int((d/sin(e + f*x))**n*(A + C/sin(e + f*x)**S(2))*(a + b/sin(e + f*x))**m, x) def replacement4590(A, B, C, a, b, d, e, f, m, n, x): return Dist(d**(m + S(2)), Int((d*cos(e + f*x))**(-m + n + S(-2))*(a*cos(e + f*x) + b)**m*(A*cos(e + f*x)**S(2) + B*cos(e + f*x) + C), x), x) def replacement4591(A, B, C, a, b, d, e, f, m, n, x): return Dist(d**(m + S(2)), Int((d*sin(e + f*x))**(-m + n + S(-2))*(a*sin(e + f*x) + b)**m*(A*sin(e + f*x)**S(2) + B*sin(e + f*x) + C), x), x) def replacement4592(A, C, a, b, d, e, f, m, n, x): return Dist(d**(m + S(2)), Int((d*cos(e + f*x))**(-m + n + S(-2))*(A*cos(e + f*x)**S(2) + C)*(a*cos(e + f*x) + b)**m, x), x) def replacement4593(A, C, a, b, d, e, f, m, n, x): return Dist(d**(m + S(2)), Int((d*sin(e + f*x))**(-m + n + S(-2))*(A*sin(e + f*x)**S(2) + C)*(a*sin(e + f*x) + b)**m, x), x) def replacement4594(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d/cos(e + f*x))**p)**FracPart(n)*(d/cos(e + f*x))**(-p*FracPart(n)), Int((d/cos(e + f*x))**(n*p)*(a + b/cos(e + f*x))**m*(A + B/cos(e + f*x) + C/cos(e + f*x)**S(2)), x), x) def replacement4595(A, B, C, a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d/sin(e + f*x))**p)**FracPart(n)*(d/sin(e + f*x))**(-p*FracPart(n)), Int((d/sin(e + f*x))**(n*p)*(a + b/sin(e + f*x))**m*(A + B/sin(e + f*x) + C/sin(e + f*x)**S(2)), x), x) def replacement4596(A, C, a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d/cos(e + f*x))**p)**FracPart(n)*(d/cos(e + f*x))**(-p*FracPart(n)), Int((d/cos(e + f*x))**(n*p)*(A + C/cos(e + f*x)**S(2))*(a + b/cos(e + f*x))**m, x), x) def replacement4597(A, C, a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d/sin(e + f*x))**p)**FracPart(n)*(d/sin(e + f*x))**(-p*FracPart(n)), Int((d/sin(e + f*x))**(n*p)*(A + C/sin(e + f*x)**S(2))*(a + b/sin(e + f*x))**m, x), x) def replacement4598(b, c, d, n, x): return Dist(b/d, Subst(Int((b*x**S(2) + b)**(n + S(-1)), x), x, tan(c + d*x)), x) def replacement4599(b, c, d, n, x): return -Dist(b/d, Subst(Int((b*x**S(2) + b)**(n + S(-1)), x), x, S(1)/tan(c + d*x)), x) def replacement4600(a, b, c, d, p, x): return Int((-a*tan(c + d*x)**S(2))**p, x) def replacement4601(a, b, c, d, p, x): return Int((-a/tan(c + d*x)**S(2))**p, x) def replacement4602(a, b, c, d, x): return -Dist(b/a, Int(S(1)/(a*cos(c + d*x)**S(2) + b), x), x) + Simp(x/a, x) def replacement4603(a, b, c, d, x): return -Dist(b/a, Int(S(1)/(a*sin(c + d*x)**S(2) + b), x), x) + Simp(x/a, x) def replacement4604(a, b, c, d, p, x): return Dist(S(1)/d, Subst(Int((a + b*x**S(2) + b)**p/(x**S(2) + S(1)), x), x, tan(c + d*x)), x) def replacement4605(a, b, c, d, p, x): return -Dist(S(1)/d, Subst(Int((a + b*x**S(2) + b)**p/(x**S(2) + S(1)), x), x, S(1)/tan(c + d*x)), x) def With4606(a, b, c, d, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f**(m + S(1))/d, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1))*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, tan(c + d*x)/f), x) def With4607(a, b, c, d, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f**(m + S(1))/d, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1))*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, S(1)/(f*tan(c + d*x))), x) def With4608(a, b, c, d, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f/d, Subst(Int((f*x)**(-n*p)*(a*(f*x)**n + b)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, cos(c + d*x)/f), x) def With4609(a, b, c, d, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f/d, Subst(Int((f*x)**(-n*p)*(a*(f*x)**n + b)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, sin(c + d*x)/f), x) def With4610(a, b, c, d, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1))*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, tan(c + d*x)/f), x) def With4611(a, b, c, d, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1))*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, S(1)/(f*tan(c + d*x))), x) def With4612(a, b, c, d, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f/d, Subst(Int((-f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1)/2)*ExpandToSum(a*(-f**S(2)*x**S(2) + S(1))**(n/S(2)) + b, x)**p, x), x, sin(c + d*x)/f), x) def With4613(a, b, c, d, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f/d, Subst(Int((-f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1)/2)*ExpandToSum(a*(-f**S(2)*x**S(2) + S(1))**(n/S(2)) + b, x)**p, x), x, cos(c + d*x)/f), x) def replacement4614(a, b, c, d, m, n, p, x): return Int(ExpandTrig((a + b*(S(1)/cos(c + d*x))**n)**p*(S(1)/cos(c + d*x))**m, x), x) def replacement4615(a, b, c, d, m, n, p, x): return Int(ExpandTrig((a + b*(S(1)/sin(c + d*x))**n)**p*(S(1)/sin(c + d*x))**m, x), x) def With4616(a, b, c, d, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f**(-m - n*p + S(1))/d, Subst(Int(x**(-m - n*p)*(a*(f*x)**n + b)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, cos(c + d*x)/f), x) def With4617(a, b, c, d, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f**(-m - n*p + S(1))/d, Subst(Int(x**(-m - n*p)*(a*(f*x)**n + b)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, sin(c + d*x)/f), x) def With4618(a, b, c, d, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f**(m + S(1))/d, Subst(Int(x**m*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p/(f**S(2)*x**S(2) + S(1)), x), x, tan(c + d*x)/f), x) def With4619(a, b, c, d, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f**(m + S(1))/d, Subst(Int(x**m*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p/(f**S(2)*x**S(2) + S(1)), x), x, S(1)/(f*tan(c + d*x))), x) def replacement4620(a, b, c, d, e, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*(S(1)/cos(d + e*x))**n)**(S(2)*p), x), x) def replacement4621(a, b, c, d, e, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*(S(1)/sin(d + e*x))**n)**(S(2)*p), x), x) def replacement4622(a, b, c, d, e, n, n2, p, x): return Dist((b + S(2)*c*(S(1)/cos(d + e*x))**n)**(-S(2)*p)*(a + b*(S(1)/cos(d + e*x))**n + c*(S(1)/cos(d + e*x))**(S(2)*n))**p, Int(u*(b + S(2)*c*(S(1)/cos(d + e*x))**n)**(S(2)*p), x), x) def replacement4623(a, b, c, d, e, n, n2, p, x): return Dist((b + S(2)*c*(S(1)/sin(d + e*x))**n)**(-S(2)*p)*(a + b*(S(1)/sin(d + e*x))**n + c*(S(1)/sin(d + e*x))**(S(2)*n))**p, Int(u*(b + S(2)*c*(S(1)/sin(d + e*x))**n)**(S(2)*p), x), x) def With4624(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*(S(1)/cos(d + e*x))**n - q), x), x) - Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*(S(1)/cos(d + e*x))**n + q), x), x) def With4625(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*(S(1)/sin(d + e*x))**n - q), x), x) - Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*(S(1)/sin(d + e*x))**n + q), x), x) def With4626(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(cos(d + e*x), x) return -Dist(f/e, Subst(Int((f*x)**(-n*p)*(a*(f*x)**n + b)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, cos(d + e*x)/f), x) def With4627(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(sin(d + e*x), x) return Dist(f/e, Subst(Int((f*x)**(-n*p)*(a*(f*x)**n + b)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, sin(d + e*x)/f), x) def With4628(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(tan(d + e*x), x) return Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1))*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + c*(f**S(2)*x**S(2) + S(1))**n, x)**p, x), x, tan(d + e*x)/f), x) def With4629(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1))*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + c*(f**S(2)*x**S(2) + S(1))**n, x)**p, x), x, S(1)/(f*tan(d + e*x))), x) def replacement4630(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*(S(1)/cos(d + e*x))**n)**(S(2)*p)*(S(1)/cos(d + e*x))**m, x), x) def replacement4631(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*(S(1)/sin(d + e*x))**n)**(S(2)*p)*(S(1)/sin(d + e*x))**m, x), x) def replacement4632(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*(S(1)/cos(d + e*x))**n)**(-S(2)*p)*(a + b*(S(1)/cos(d + e*x))**n + c*(S(1)/cos(d + e*x))**(S(2)*n))**p, Int((b + S(2)*c*(S(1)/cos(d + e*x))**n)**(S(2)*p)*(S(1)/cos(d + e*x))**m, x), x) def replacement4633(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*(S(1)/sin(d + e*x))**n)**(-S(2)*p)*(a + b*(S(1)/sin(d + e*x))**n + c*(S(1)/sin(d + e*x))**(S(2)*n))**p, Int((b + S(2)*c*(S(1)/sin(d + e*x))**n)**(S(2)*p)*(S(1)/sin(d + e*x))**m, x), x) def replacement4634(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((a + b*(S(1)/cos(d + e*x))**n + c*(S(1)/cos(d + e*x))**(S(2)*n))**p*(S(1)/cos(d + e*x))**m, x), x) def replacement4635(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((a + b*(S(1)/sin(d + e*x))**n + c*(S(1)/sin(d + e*x))**(S(2)*n))**p*(S(1)/sin(d + e*x))**m, x), x) def With4636(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(cos(d + e*x), x) return -Dist(f**(-m - n*p + S(1))/e, Subst(Int(x**(-m - S(2)*n*p)*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*(b*(f*x)**n + c*(f*x)**(S(2)*n) + c)**p, x), x, cos(d + e*x)/f), x) def With4637(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(sin(d + e*x), x) return Dist(f**(-m - n*p + S(1))/e, Subst(Int(x**(-m - S(2)*n*p)*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*(b*(f*x)**n + c*(f*x)**(S(2)*n) + c)**p, x), x, sin(d + e*x)/f), x) def With4638(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(tan(d + e*x), x) return Dist(f**(m + S(1))/e, Subst(Int(x**m*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + c*(f**S(2)*x**S(2) + S(1))**n, x)**p/(f**S(2)*x**S(2) + S(1)), x), x, tan(d + e*x)/f), x) def With4639(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f**(m + S(1))/e, Subst(Int(x**m*ExpandToSum(a + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + c*(f**S(2)*x**S(2) + S(1))**n, x)**p/(f**S(2)*x**S(2) + S(1)), x), x, S(1)/(f*tan(d + e*x))), x) def replacement4640(A, B, a, b, c, d, e, n, x): return Dist(S(4)**(-n)*c**(-n), Int((A + B/cos(d + e*x))*(b + S(2)*c/cos(d + e*x))**(S(2)*n), x), x) def replacement4641(A, B, a, b, c, d, e, n, x): return Dist(S(4)**(-n)*c**(-n), Int((A + B/sin(d + e*x))*(b + S(2)*c/sin(d + e*x))**(S(2)*n), x), x) def replacement4642(A, B, a, b, c, d, e, n, x): return Dist((b + S(2)*c/cos(d + e*x))**(-S(2)*n)*(a + b/cos(d + e*x) + c/cos(d + e*x)**S(2))**n, Int((A + B/cos(d + e*x))*(b + S(2)*c/cos(d + e*x))**(S(2)*n), x), x) def replacement4643(A, B, a, b, c, d, e, n, x): return Dist((b + S(2)*c/sin(d + e*x))**(-S(2)*n)*(a + b/sin(d + e*x) + c/sin(d + e*x)**S(2))**n, Int((A + B/sin(d + e*x))*(b + S(2)*c/sin(d + e*x))**(S(2)*n), x), x) def With4644(A, B, a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(B - (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c/cos(d + e*x) - q), x), x) + Dist(B + (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c/cos(d + e*x) + q), x), x) def With4645(A, B, a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(B - (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c/sin(d + e*x) - q), x), x) + Dist(B + (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c/sin(d + e*x) + q), x), x) def replacement4646(A, B, a, b, c, d, e, n, x): return Int(ExpandTrig((A + B/cos(d + e*x))*(a + b/cos(d + e*x) + c/cos(d + e*x)**S(2))**n, x), x) def replacement4647(A, B, a, b, c, d, e, n, x): return Int(ExpandTrig((A + B/sin(d + e*x))*(a + b/sin(d + e*x) + c/sin(d + e*x)**S(2))**n, x), x) def replacement4648(c, d, e, f, m, x): return -Dist(d*m/f, Int((c + d*x)**(m + S(-1))*log(-I*exp(I*(e + f*x)) + S(1)), x), x) + Dist(d*m/f, Int((c + d*x)**(m + S(-1))*log(I*exp(I*(e + f*x)) + S(1)), x), x) + Simp(-S(2)*I*(c + d*x)**m*ArcTan(exp(I*e + I*f*x))/f, x) def replacement4649(c, d, e, f, m, x): return -Dist(d*m/f, Int((c + d*x)**(m + S(-1))*log(S(1) - exp(I*(e + f*x))), x), x) + Dist(d*m/f, Int((c + d*x)**(m + S(-1))*log(exp(I*(e + f*x)) + S(1)), x), x) + Simp(-S(2)*(c + d*x)**m*atanh(exp(I*e + I*f*x))/f, x) def replacement4650(c, d, e, f, m, x): return -Dist(d*m/f, Int((c + d*x)**(m + S(-1))*tan(e + f*x), x), x) + Simp((c + d*x)**m*tan(e + f*x)/f, x) def replacement4651(c, d, e, f, m, x): return Dist(d*m/f, Int((c + d*x)**(m + S(-1))/tan(e + f*x), x), x) - Simp((c + d*x)**m/(f*tan(e + f*x)), x) def replacement4652(b, c, d, e, f, n, x): return Dist(b**S(2)*(n + S(-2))/(n + S(-1)), Int((b/cos(e + f*x))**(n + S(-2))*(c + d*x), x), x) - Simp(b**S(2)*d*(b/cos(e + f*x))**(n + S(-2))/(f**S(2)*(n + S(-2))*(n + S(-1))), x) + Simp(b**S(2)*(b/cos(e + f*x))**(n + S(-2))*(c + d*x)*tan(e + f*x)/(f*(n + S(-1))), x) def replacement4653(b, c, d, e, f, n, x): return Dist(b**S(2)*(n + S(-2))/(n + S(-1)), Int((b/sin(e + f*x))**(n + S(-2))*(c + d*x), x), x) - Simp(b**S(2)*d*(b/sin(e + f*x))**(n + S(-2))/(f**S(2)*(n + S(-2))*(n + S(-1))), x) - Simp(b**S(2)*(b/sin(e + f*x))**(n + S(-2))*(c + d*x)/(f*(n + S(-1))*tan(e + f*x)), x) def replacement4654(b, c, d, e, f, m, n, x): return Dist(b**S(2)*(n + S(-2))/(n + S(-1)), Int((b/cos(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) + Dist(b**S(2)*d**S(2)*m*(m + S(-1))/(f**S(2)*(n + S(-2))*(n + S(-1))), Int((b/cos(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(-2)), x), x) + Simp(b**S(2)*(b/cos(e + f*x))**(n + S(-2))*(c + d*x)**m*tan(e + f*x)/(f*(n + S(-1))), x) - Simp(b**S(2)*d*m*(b/cos(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(-1))/(f**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement4655(b, c, d, e, f, m, n, x): return Dist(b**S(2)*(n + S(-2))/(n + S(-1)), Int((b/sin(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) + Dist(b**S(2)*d**S(2)*m*(m + S(-1))/(f**S(2)*(n + S(-2))*(n + S(-1))), Int((b/sin(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(-2)), x), x) - Simp(b**S(2)*(b/sin(e + f*x))**(n + S(-2))*(c + d*x)**m/(f*(n + S(-1))*tan(e + f*x)), x) - Simp(b**S(2)*d*m*(b/sin(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(-1))/(f**S(2)*(n + S(-2))*(n + S(-1))), x) def replacement4656(b, c, d, e, f, n, x): return Dist((n + S(1))/(b**S(2)*n), Int((b/cos(e + f*x))**(n + S(2))*(c + d*x), x), x) + Simp(d*(b/cos(e + f*x))**n/(f**S(2)*n**S(2)), x) - Simp((b/cos(e + f*x))**(n + S(1))*(c + d*x)*sin(e + f*x)/(b*f*n), x) def replacement4657(b, c, d, e, f, n, x): return Dist((n + S(1))/(b**S(2)*n), Int((b/sin(e + f*x))**(n + S(2))*(c + d*x), x), x) + Simp(d*(b/sin(e + f*x))**n/(f**S(2)*n**S(2)), x) + Simp((b/sin(e + f*x))**(n + S(1))*(c + d*x)*cos(e + f*x)/(b*f*n), x) def replacement4658(b, c, d, e, f, m, n, x): return Dist((n + S(1))/(b**S(2)*n), Int((b/cos(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) - Dist(d**S(2)*m*(m + S(-1))/(f**S(2)*n**S(2)), Int((b/cos(e + f*x))**n*(c + d*x)**(m + S(-2)), x), x) - Simp((b/cos(e + f*x))**(n + S(1))*(c + d*x)**m*sin(e + f*x)/(b*f*n), x) + Simp(d*m*(b/cos(e + f*x))**n*(c + d*x)**(m + S(-1))/(f**S(2)*n**S(2)), x) def replacement4659(b, c, d, e, f, m, n, x): return Dist((n + S(1))/(b**S(2)*n), Int((b/sin(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) - Dist(d**S(2)*m*(m + S(-1))/(f**S(2)*n**S(2)), Int((b/sin(e + f*x))**n*(c + d*x)**(m + S(-2)), x), x) + Simp((b/sin(e + f*x))**(n + S(1))*(c + d*x)**m*cos(e + f*x)/(b*f*n), x) + Simp(d*m*(b/sin(e + f*x))**n*(c + d*x)**(m + S(-1))/(f**S(2)*n**S(2)), x) def replacement4660(b, c, d, e, f, m, n, x): return Dist((b/cos(e + f*x))**n*(b*cos(e + f*x))**n, Int((b*cos(e + f*x))**(-n)*(c + d*x)**m, x), x) def replacement4661(b, c, d, e, f, m, n, x): return Dist((b/sin(e + f*x))**n*(b*sin(e + f*x))**n, Int((b*sin(e + f*x))**(-n)*(c + d*x)**m, x), x) def replacement4662(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b/cos(e + f*x))**n, x), x) def replacement4663(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b/sin(e + f*x))**n, x), x) def replacement4664(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a*cos(e + f*x) + b)**n*cos(e + f*x)**(-n), x), x) def replacement4665(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a*sin(e + f*x) + b)**n*sin(e + f*x)**(-n), x), x) def replacement4666(a, b, m, n, u, v, x): return Int((a + b/cos(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement4667(a, b, m, n, u, v, x): return Int((a + b/sin(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement4668(a, b, c, d, e, f, m, n, x): return Int((a + b/cos(e + f*x))**n*(c + d*x)**m, x) def replacement4669(a, b, c, d, e, f, m, n, x): return Int((a + b/sin(e + f*x))**n*(c + d*x)**m, x) def replacement4670(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b/cos(c + d*x))**p, x), x, x**n), x) def replacement4671(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b/sin(c + d*x))**p, x), x, x**n), x) def replacement4672(a, b, c, d, n, p, x): return Int((a + b/cos(c + d*x**n))**p, x) def replacement4673(a, b, c, d, n, p, x): return Int((a + b/sin(c + d*x**n))**p, x) def replacement4674(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b/cos(c + d*x**n))**p, x), x, u), x) def replacement4675(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b/sin(c + d*x**n))**p, x), x, u), x) def replacement4676(a, b, p, u, x): return Int((a + b/cos(ExpandToSum(u, x)))**p, x) def replacement4677(a, b, p, u, x): return Int((a + b/sin(ExpandToSum(u, x)))**p, x) def replacement4678(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b/cos(c + d*x))**p, x), x, x**n), x) def replacement4679(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b/sin(c + d*x))**p, x), x, x**n), x) def replacement4680(a, b, c, d, m, n, p, x): return Int(x**m*(a + b/cos(c + d*x**n))**p, x) def replacement4681(a, b, c, d, m, n, p, x): return Int(x**m*(a + b/sin(c + d*x**n))**p, x) def replacement4682(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b/cos(c + d*x**n))**p, x), x) def replacement4683(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b/sin(c + d*x**n))**p, x), x) def replacement4684(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b/cos(ExpandToSum(u, x)))**p, x) def replacement4685(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b/sin(ExpandToSum(u, x)))**p, x) def replacement4686(a, b, m, n, p, x): return -Dist((m - n + S(1))/(b*n*(p + S(-1))), Int(x**(m - n)*(S(1)/cos(a + b*x**n))**(p + S(-1)), x), x) + Simp(x**(m - n + S(1))*(S(1)/cos(a + b*x**n))**(p + S(-1))/(b*n*(p + S(-1))), x) def replacement4687(a, b, m, n, p, x): return Dist((m - n + S(1))/(b*n*(p + S(-1))), Int(x**(m - n)*(S(1)/sin(a + b*x**n))**(p + S(-1)), x), x) - Simp(x**(m - n + S(1))*(S(1)/sin(a + b*x**n))**(p + S(-1))/(b*n*(p + S(-1))), x) sympy-sympy-1.9/sympy/integrals/rubi/rules/sine.py000066400000000000000000026277741412543434000225300ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def sine(): from sympy.integrals.rubi.constraints import cons1251, cons74, cons68, cons2, cons3, cons50, cons127, cons19, cons4, cons1252, cons1253, cons1254, cons95, cons168, cons91, cons1255, cons33, cons1172, cons96, cons1256, cons1257, cons1258, cons1259, cons1260, cons1261, cons167, cons1262, cons21, cons25, cons523, cons8, cons29, cons810, cons1263, cons1264, cons1265, cons545, cons1266, cons1267, cons150, cons1268, cons89, cons45, cons450, cons1269, cons1270, cons1271, cons1272, cons1273, cons483, cons484, cons1274, cons1275, cons1276, cons1277, cons1278, cons210, cons5, cons20, cons13, cons139, cons1279, cons1280, cons1281, cons1282, cons1283, cons145, cons1284, cons1285, cons1286, cons1287, cons246, cons170, cons1288, cons1289, cons1290, cons148, cons1291, cons1292, cons1293, cons248, cons1294, cons1295, cons1296, cons1297, cons1298, cons86, cons1299, cons149, cons56, cons1300, cons1301, cons1302, cons1303, cons1304, cons64, cons269, cons1305, cons1306, cons1307, cons1308, cons517, cons274, cons1309, cons1310, cons73, cons72, cons1311, cons1312, cons1313, cons1314, cons348, cons1315, cons157, cons1316, cons1317, cons116, cons1318, cons1319, cons1320, cons1321, cons1322, cons1323, cons79, cons1324, cons1325, cons1326, cons1327, cons1328, cons1329, cons1330, cons465, cons90, cons1331, cons1332, cons87, cons1333, cons1334, cons1335, cons1336, cons1337, cons1338, cons1339, cons1340, cons1341, cons1342, cons1343, cons1344, cons1345, cons1346, cons1347, cons1348, cons1349, cons1350, cons1351, cons1352, cons1353, cons1354, cons1355, cons1356, cons1357, cons1358, cons1359, cons1360, cons1361, cons1362, cons1363, cons1364, cons1365, cons1366, cons144, cons337, cons1367, cons1368, cons1369, cons1370, cons1371, cons1372, cons172, cons1373, cons1374, cons1375, cons1376, cons1377, cons255, cons1378, cons1379, cons1380, cons1381, cons1382, cons360, cons1383, cons1384, cons1385, cons1386, cons1387, cons1388, cons1389, cons1390, cons1391, cons1392, cons1393, cons1394, cons1395, cons1396, cons215, cons586, cons1397, cons1398, cons1399, cons1400, cons1401, cons1402, cons1403, cons1404, cons1405, cons1406, cons1407, cons1408, cons1409, cons1410, cons1411, cons1412, cons1413, cons107, cons1414, cons1415, cons1416, cons1417, cons1418, cons1419, cons40, cons1420, cons36, cons37, cons1421, cons1422, cons1423, cons685, cons1424, cons1425, cons1426, cons1427, cons1428, cons1429, cons1430, cons1431, cons1432, cons1433, cons38, cons1230, cons1434, cons35, cons1435, cons1436, cons1437, cons1438, cons216, cons1439, cons1440, cons1441, cons1442, cons1443, cons1444, cons1445, cons1446, cons1447, cons1448, cons1154, cons1449, cons198, cons130, cons65, cons152, cons377, cons324, cons1450, cons1451, cons1452, cons1453, cons1454, cons1455, cons1456, cons78, cons1457, cons1458, cons1459, cons1460, cons1461, cons1462, cons1463, cons1464, cons1465, cons1466, cons1467, cons1468, cons1469, cons1470, cons1471, cons1472, cons1473, cons1247, cons1474, cons1475, cons1476, cons1477, cons1478, cons1479, cons1045, cons1480, cons1481, cons1482, cons1483, cons1484, cons1485, cons1486, cons1487, cons1488, cons1489, cons48, cons47, cons228, cons378, cons1118, cons178, cons1490, cons1491, cons247, cons249, cons1492, cons1493, cons1494, cons1495, cons812, cons813, cons746, cons1496, cons1497, cons55, cons598, cons1498, cons1499, cons491, cons1500, cons70, cons71, cons825, cons826, cons1501, cons1502, cons1503, cons1504, cons58, cons1505, cons1506, cons369, cons1507, cons358, cons856, cons1508, cons820, cons1133, cons49, cons241, cons1134, cons1135, cons1509, cons821 pattern2167 = Pattern(Integral(u_, x_), cons1251) rule2167 = ReplacementRule(pattern2167, replacement2167) pattern2168 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons4, cons74, cons68) rule2168 = ReplacementRule(pattern2168, replacement2168) pattern2169 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1252, cons1253) rule2169 = ReplacementRule(pattern2169, replacement2169) pattern2170 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1252, cons1254) rule2170 = ReplacementRule(pattern2170, replacement2170) pattern2171 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons168, cons91, cons1255) rule2171 = ReplacementRule(pattern2171, replacement2171) pattern2172 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons168, cons91, cons1255) rule2172 = ReplacementRule(pattern2172, replacement2172) pattern2173 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons168, cons1172) rule2173 = ReplacementRule(pattern2173, replacement2173) pattern2174 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons168, cons1172) rule2174 = ReplacementRule(pattern2174, replacement2174) pattern2175 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons96, cons1172) rule2175 = ReplacementRule(pattern2175, replacement2175) pattern2176 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons96, cons1172) rule2176 = ReplacementRule(pattern2176, replacement2176) pattern2177 = Pattern(Integral(sqrt(WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1256) rule2177 = ReplacementRule(pattern2177, replacement2177) pattern2178 = Pattern(Integral(S(1)/(sqrt(WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons1256) rule2178 = ReplacementRule(pattern2178, replacement2178) pattern2179 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons1257, cons33, cons1258) rule2179 = ReplacementRule(pattern2179, With2179) pattern2180 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons1257, cons33, cons1258) rule2180 = ReplacementRule(pattern2180, With2180) pattern2181 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1259) rule2181 = ReplacementRule(pattern2181, replacement2181) pattern2182 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1260) rule2182 = ReplacementRule(pattern2182, replacement2182) pattern2183 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1261, cons68) rule2183 = ReplacementRule(pattern2183, replacement2183) pattern2184 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1261, cons68) rule2184 = ReplacementRule(pattern2184, replacement2184) pattern2185 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons168, cons167, cons1172) rule2185 = ReplacementRule(pattern2185, replacement2185) pattern2186 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons168, cons167, cons1172) rule2186 = ReplacementRule(pattern2186, replacement2186) pattern2187 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons168, cons1262, cons1172) rule2187 = ReplacementRule(pattern2187, replacement2187) pattern2188 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons168, cons1262, cons1172) rule2188 = ReplacementRule(pattern2188, replacement2188) pattern2189 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons96, cons1172) rule2189 = ReplacementRule(pattern2189, replacement2189) pattern2190 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons96, cons1172) rule2190 = ReplacementRule(pattern2190, replacement2190) pattern2191 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule2191 = ReplacementRule(pattern2191, replacement2191) pattern2192 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule2192 = ReplacementRule(pattern2192, replacement2192) pattern2193 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule2193 = ReplacementRule(pattern2193, replacement2193) pattern2194 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule2194 = ReplacementRule(pattern2194, replacement2194) pattern2195 = Pattern(Integral(sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons8, cons29, cons523) rule2195 = ReplacementRule(pattern2195, replacement2195) pattern2196 = Pattern(Integral(cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_, x_), cons8, cons29, cons523) rule2196 = ReplacementRule(pattern2196, replacement2196) pattern2197 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons810, cons167) rule2197 = ReplacementRule(pattern2197, replacement2197) pattern2198 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons810, cons167) rule2198 = ReplacementRule(pattern2198, replacement2198) pattern2199 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons810, cons91) rule2199 = ReplacementRule(pattern2199, replacement2199) pattern2200 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons810, cons91) rule2200 = ReplacementRule(pattern2200, replacement2200) pattern2201 = Pattern(Integral(sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons1263) rule2201 = ReplacementRule(pattern2201, replacement2201) pattern2202 = Pattern(Integral(cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons8, cons1264) rule2202 = ReplacementRule(pattern2202, replacement2202) pattern2203 = Pattern(Integral(sqrt(sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons8, cons29, cons1263) rule2203 = ReplacementRule(pattern2203, replacement2203) pattern2204 = Pattern(Integral(sqrt(cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons8, cons29, cons1263) rule2204 = ReplacementRule(pattern2204, replacement2204) pattern2205 = Pattern(Integral(sqrt(b_*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons3, cons8, cons29, cons1265) rule2205 = ReplacementRule(pattern2205, replacement2205) pattern2206 = Pattern(Integral(sqrt(b_*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons3, cons8, cons29, cons1265) rule2206 = ReplacementRule(pattern2206, replacement2206) pattern2207 = Pattern(Integral(S(1)/sqrt(sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons8, cons29, cons1263) rule2207 = ReplacementRule(pattern2207, replacement2207) pattern2208 = Pattern(Integral(S(1)/sqrt(cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons8, cons29, cons1263) rule2208 = ReplacementRule(pattern2208, replacement2208) pattern2209 = Pattern(Integral(S(1)/sqrt(b_*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons3, cons8, cons29, cons1265) rule2209 = ReplacementRule(pattern2209, replacement2209) pattern2210 = Pattern(Integral(S(1)/sqrt(b_*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons3, cons8, cons29, cons1265) rule2210 = ReplacementRule(pattern2210, replacement2210) pattern2211 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons4, cons545) rule2211 = ReplacementRule(pattern2211, replacement2211) pattern2212 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons4, cons545) rule2212 = ReplacementRule(pattern2212, replacement2212) pattern2213 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons1266) rule2213 = ReplacementRule(pattern2213, replacement2213) pattern2214 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons1266) rule2214 = ReplacementRule(pattern2214, replacement2214) pattern2215 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons150) rule2215 = ReplacementRule(pattern2215, replacement2215) pattern2216 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons150) rule2216 = ReplacementRule(pattern2216, replacement2216) pattern2217 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule2217 = ReplacementRule(pattern2217, replacement2217) pattern2218 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule2218 = ReplacementRule(pattern2218, replacement2218) pattern2219 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons1268) rule2219 = ReplacementRule(pattern2219, replacement2219) pattern2220 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons1268) rule2220 = ReplacementRule(pattern2220, replacement2220) pattern2221 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule2221 = ReplacementRule(pattern2221, replacement2221) pattern2222 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule2222 = ReplacementRule(pattern2222, replacement2222) pattern2223 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule2223 = ReplacementRule(pattern2223, replacement2223) pattern2224 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1267) rule2224 = ReplacementRule(pattern2224, replacement2224) pattern2225 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons89, cons91, cons810) rule2225 = ReplacementRule(pattern2225, replacement2225) pattern2226 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1267, cons89, cons91, cons810) rule2226 = ReplacementRule(pattern2226, replacement2226) pattern2227 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons45) rule2227 = ReplacementRule(pattern2227, replacement2227) pattern2228 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons45) rule2228 = ReplacementRule(pattern2228, replacement2228) pattern2229 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons450) rule2229 = ReplacementRule(pattern2229, replacement2229) pattern2230 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1267, cons545, cons450) rule2230 = ReplacementRule(pattern2230, replacement2230) pattern2231 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1270) rule2231 = ReplacementRule(pattern2231, replacement2231) pattern2232 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1270) rule2232 = ReplacementRule(pattern2232, replacement2232) pattern2233 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1271) rule2233 = ReplacementRule(pattern2233, replacement2233) pattern2234 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1271) rule2234 = ReplacementRule(pattern2234, replacement2234) pattern2235 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1272) rule2235 = ReplacementRule(pattern2235, replacement2235) pattern2236 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1272) rule2236 = ReplacementRule(pattern2236, replacement2236) pattern2237 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons167, cons810) rule2237 = ReplacementRule(pattern2237, replacement2237) pattern2238 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons167, cons810) rule2238 = ReplacementRule(pattern2238, replacement2238) pattern2239 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1273, cons483) rule2239 = ReplacementRule(pattern2239, With2239) pattern2240 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1273, cons483) rule2240 = ReplacementRule(pattern2240, With2240) pattern2241 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1273, cons484) rule2241 = ReplacementRule(pattern2241, With2241) pattern2242 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1273, cons484) rule2242 = ReplacementRule(pattern2242, With2242) pattern2243 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1274) rule2243 = ReplacementRule(pattern2243, With2243) pattern2244 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule2244 = ReplacementRule(pattern2244, With2244) pattern2245 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269) rule2245 = ReplacementRule(pattern2245, With2245) pattern2246 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1270) rule2246 = ReplacementRule(pattern2246, replacement2246) pattern2247 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1270) rule2247 = ReplacementRule(pattern2247, replacement2247) pattern2248 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1271) rule2248 = ReplacementRule(pattern2248, replacement2248) pattern2249 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1271) rule2249 = ReplacementRule(pattern2249, replacement2249) pattern2250 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1272) rule2250 = ReplacementRule(pattern2250, replacement2250) pattern2251 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1269, cons1272) rule2251 = ReplacementRule(pattern2251, replacement2251) pattern2252 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons91, cons810) rule2252 = ReplacementRule(pattern2252, replacement2252) pattern2253 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1269, cons89, cons91, cons810) rule2253 = ReplacementRule(pattern2253, replacement2253) pattern2254 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1269, cons545) rule2254 = ReplacementRule(pattern2254, replacement2254) pattern2255 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1269, cons545) rule2255 = ReplacementRule(pattern2255, replacement2255) pattern2256 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1275) rule2256 = ReplacementRule(pattern2256, replacement2256) pattern2257 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1267, cons1277) rule2257 = ReplacementRule(pattern2257, replacement2257) pattern2258 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1267, cons1277) rule2258 = ReplacementRule(pattern2258, replacement2258) pattern2259 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1269) rule2259 = ReplacementRule(pattern2259, replacement2259) pattern2260 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1276, cons1269) rule2260 = ReplacementRule(pattern2260, replacement2260) pattern2261 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1278) rule2261 = ReplacementRule(pattern2261, replacement2261) pattern2262 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1278) rule2262 = ReplacementRule(pattern2262, replacement2262) pattern2263 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons20, cons13, cons139, cons1279) rule2263 = ReplacementRule(pattern2263, replacement2263) pattern2264 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons20, cons13, cons139, cons1279) rule2264 = ReplacementRule(pattern2264, replacement2264) pattern2265 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1280, cons1281) rule2265 = ReplacementRule(pattern2265, replacement2265) pattern2266 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1280, cons1281) rule2266 = ReplacementRule(pattern2266, replacement2266) pattern2267 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1282, cons1283, cons145) rule2267 = ReplacementRule(pattern2267, replacement2267) pattern2268 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1282, cons1283, cons145) rule2268 = ReplacementRule(pattern2268, replacement2268) pattern2269 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1284, cons1285) rule2269 = ReplacementRule(pattern2269, replacement2269) pattern2270 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1284, cons1285) rule2270 = ReplacementRule(pattern2270, replacement2270) pattern2271 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1286, cons1287) rule2271 = ReplacementRule(pattern2271, replacement2271) pattern2272 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1286, cons1287) rule2272 = ReplacementRule(pattern2272, replacement2272) pattern2273 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons170, cons1288, cons1289) rule2273 = ReplacementRule(pattern2273, replacement2273) pattern2274 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons170, cons1288, cons1289) rule2274 = ReplacementRule(pattern2274, replacement2274) pattern2275 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons168, cons139, cons1290) rule2275 = ReplacementRule(pattern2275, replacement2275) pattern2276 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons168, cons139, cons1290) rule2276 = ReplacementRule(pattern2276, replacement2276) pattern2277 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267) rule2277 = ReplacementRule(pattern2277, replacement2277) pattern2278 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267) rule2278 = ReplacementRule(pattern2278, replacement2278) pattern2279 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons33, cons170, cons1287, cons1290) rule2279 = ReplacementRule(pattern2279, replacement2279) pattern2280 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons33, cons170, cons1287, cons1290) rule2280 = ReplacementRule(pattern2280, replacement2280) pattern2281 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons96, cons148, cons1291, cons1287, cons1290) rule2281 = ReplacementRule(pattern2281, replacement2281) pattern2282 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons96, cons148, cons1291, cons1287, cons1290) rule2282 = ReplacementRule(pattern2282, replacement2282) pattern2283 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons1292, cons148, cons1283, cons1293, cons1290) rule2283 = ReplacementRule(pattern2283, replacement2283) pattern2284 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons246, cons1292, cons148, cons1283, cons1293, cons1290) rule2284 = ReplacementRule(pattern2284, replacement2284) pattern2285 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons33, cons96, cons1283, cons1290) rule2285 = ReplacementRule(pattern2285, replacement2285) pattern2286 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons33, cons96, cons1283, cons1290) rule2286 = ReplacementRule(pattern2286, replacement2286) pattern2287 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons13, cons148, cons248) rule2287 = ReplacementRule(pattern2287, replacement2287) pattern2288 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons13, cons148, cons248) rule2288 = ReplacementRule(pattern2288, replacement2288) pattern2289 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons1294, cons248) rule2289 = ReplacementRule(pattern2289, replacement2289) pattern2290 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons1294, cons248) rule2290 = ReplacementRule(pattern2290, replacement2290) pattern2291 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267) rule2291 = ReplacementRule(pattern2291, replacement2291) pattern2292 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267) rule2292 = ReplacementRule(pattern2292, replacement2292) pattern2293 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267) rule2293 = ReplacementRule(pattern2293, replacement2293) pattern2294 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267) rule2294 = ReplacementRule(pattern2294, replacement2294) pattern2295 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons13, cons1295, cons248) rule2295 = ReplacementRule(pattern2295, replacement2295) pattern2296 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons13, cons1295, cons248) rule2296 = ReplacementRule(pattern2296, replacement2296) pattern2297 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons13, cons139, cons248) rule2297 = ReplacementRule(pattern2297, replacement2297) pattern2298 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1267, cons13, cons139, cons248) rule2298 = ReplacementRule(pattern2298, replacement2298) pattern2299 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons20) rule2299 = ReplacementRule(pattern2299, replacement2299) pattern2300 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons20) rule2300 = ReplacementRule(pattern2300, replacement2300) pattern2301 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons21) rule2301 = ReplacementRule(pattern2301, replacement2301) pattern2302 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons21) rule2302 = ReplacementRule(pattern2302, replacement2302) pattern2303 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons246, cons1258, cons139, cons1296) rule2303 = ReplacementRule(pattern2303, replacement2303) pattern2304 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons246, cons1258, cons139, cons1296) rule2304 = ReplacementRule(pattern2304, replacement2304) pattern2305 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons246, cons168, cons139, cons1296) rule2305 = ReplacementRule(pattern2305, replacement2305) pattern2306 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons246, cons168, cons139, cons1296) rule2306 = ReplacementRule(pattern2306, replacement2306) pattern2307 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons33, cons168, cons1287, cons1296) rule2307 = ReplacementRule(pattern2307, replacement2307) pattern2308 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons33, cons168, cons1287, cons1296) rule2308 = ReplacementRule(pattern2308, replacement2308) pattern2309 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons246, cons96, cons148, cons1290) rule2309 = ReplacementRule(pattern2309, replacement2309) pattern2310 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons246, cons96, cons148, cons1290) rule2310 = ReplacementRule(pattern2310, replacement2310) pattern2311 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons33, cons96, cons1290) rule2311 = ReplacementRule(pattern2311, replacement2311) pattern2312 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons33, cons96, cons1290) rule2312 = ReplacementRule(pattern2312, replacement2312) pattern2313 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons1269, cons13, cons148, cons1287, cons1290) rule2313 = ReplacementRule(pattern2313, replacement2313) pattern2314 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons1269, cons13, cons148, cons1287, cons1290) rule2314 = ReplacementRule(pattern2314, replacement2314) pattern2315 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons1269, cons13, cons139, cons1290) rule2315 = ReplacementRule(pattern2315, replacement2315) pattern2316 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons1269, cons13, cons139, cons1290) rule2316 = ReplacementRule(pattern2316, replacement2316) pattern2317 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2317 = ReplacementRule(pattern2317, replacement2317) pattern2318 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2318 = ReplacementRule(pattern2318, replacement2318) pattern2319 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons1280) rule2319 = ReplacementRule(pattern2319, replacement2319) pattern2320 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons1280) rule2320 = ReplacementRule(pattern2320, replacement2320) pattern2321 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons1297) rule2321 = ReplacementRule(pattern2321, replacement2321) pattern2322 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons1297) rule2322 = ReplacementRule(pattern2322, replacement2322) pattern2323 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons1298) rule2323 = ReplacementRule(pattern2323, replacement2323) pattern2324 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons1298) rule2324 = ReplacementRule(pattern2324, replacement2324) pattern2325 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2325 = ReplacementRule(pattern2325, With2325) pattern2326 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2326 = ReplacementRule(pattern2326, With2326) pattern2327 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2327 = ReplacementRule(pattern2327, With2327) pattern2328 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2328 = ReplacementRule(pattern2328, With2328) pattern2329 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons86, cons1299) rule2329 = ReplacementRule(pattern2329, replacement2329) pattern2330 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons86, cons1299) rule2330 = ReplacementRule(pattern2330, replacement2330) pattern2331 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons145) rule2331 = ReplacementRule(pattern2331, replacement2331) pattern2332 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1269, cons145) rule2332 = ReplacementRule(pattern2332, replacement2332) pattern2333 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons149) rule2333 = ReplacementRule(pattern2333, replacement2333) pattern2334 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons149) rule2334 = ReplacementRule(pattern2334, replacement2334) pattern2335 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons56) rule2335 = ReplacementRule(pattern2335, replacement2335) pattern2336 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons56) rule2336 = ReplacementRule(pattern2336, replacement2336) pattern2337 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1300) rule2337 = ReplacementRule(pattern2337, replacement2337) pattern2338 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1300) rule2338 = ReplacementRule(pattern2338, replacement2338) pattern2339 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons50, cons127, cons1267, cons1301, cons1302) rule2339 = ReplacementRule(pattern2339, replacement2339) pattern2340 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_, x_), cons2, cons3, cons50, cons127, cons1267, cons1301, cons1302) rule2340 = ReplacementRule(pattern2340, replacement2340) pattern2341 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons50, cons127, cons1267, cons1303, cons1304) rule2341 = ReplacementRule(pattern2341, replacement2341) pattern2342 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_, x_), cons2, cons3, cons50, cons127, cons1267, cons1303, cons1304) rule2342 = ReplacementRule(pattern2342, replacement2342) pattern2343 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons64) rule2343 = ReplacementRule(pattern2343, replacement2343) pattern2344 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons64) rule2344 = ReplacementRule(pattern2344, replacement2344) pattern2345 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons86) rule2345 = ReplacementRule(pattern2345, replacement2345) pattern2346 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons86) rule2346 = ReplacementRule(pattern2346, replacement2346) pattern2347 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons21, cons33, cons269) rule2347 = ReplacementRule(pattern2347, replacement2347) pattern2348 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons21, cons33, cons269) rule2348 = ReplacementRule(pattern2348, replacement2348) pattern2349 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons21, cons1305) rule2349 = ReplacementRule(pattern2349, replacement2349) pattern2350 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons21, cons1305) rule2350 = ReplacementRule(pattern2350, replacement2350) pattern2351 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1306) rule2351 = ReplacementRule(pattern2351, replacement2351) pattern2352 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1306) rule2352 = ReplacementRule(pattern2352, replacement2352) pattern2353 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons1306, cons96) rule2353 = ReplacementRule(pattern2353, replacement2353) pattern2354 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons1306, cons96) rule2354 = ReplacementRule(pattern2354, replacement2354) pattern2355 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1306, cons1307) rule2355 = ReplacementRule(pattern2355, replacement2355) pattern2356 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1306, cons1307) rule2356 = ReplacementRule(pattern2356, replacement2356) pattern2357 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons1267, cons1306, cons96) rule2357 = ReplacementRule(pattern2357, replacement2357) pattern2358 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons1267, cons1306, cons96) rule2358 = ReplacementRule(pattern2358, replacement2358) pattern2359 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1306, cons1307) rule2359 = ReplacementRule(pattern2359, replacement2359) pattern2360 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1306, cons1307) rule2360 = ReplacementRule(pattern2360, replacement2360) pattern2361 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons21, cons1308) rule2361 = ReplacementRule(pattern2361, replacement2361) pattern2362 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_, x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons21, cons1308) rule2362 = ReplacementRule(pattern2362, replacement2362) pattern2363 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons21, cons149) rule2363 = ReplacementRule(pattern2363, replacement2363) pattern2364 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons21, cons149) rule2364 = ReplacementRule(pattern2364, replacement2364) pattern2365 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons1300) rule2365 = ReplacementRule(pattern2365, replacement2365) pattern2366 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons1300) rule2366 = ReplacementRule(pattern2366, replacement2366) pattern2367 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons64) rule2367 = ReplacementRule(pattern2367, replacement2367) pattern2368 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons64) rule2368 = ReplacementRule(pattern2368, replacement2368) pattern2369 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1269) rule2369 = ReplacementRule(pattern2369, replacement2369) pattern2370 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1269) rule2370 = ReplacementRule(pattern2370, replacement2370) pattern2371 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96, cons517) rule2371 = ReplacementRule(pattern2371, replacement2371) pattern2372 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons1269, cons33, cons96, cons517) rule2372 = ReplacementRule(pattern2372, replacement2372) pattern2373 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons274, cons517) rule2373 = ReplacementRule(pattern2373, replacement2373) pattern2374 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons274, cons517) rule2374 = ReplacementRule(pattern2374, replacement2374) pattern2375 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(6), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons1285, cons517) rule2375 = ReplacementRule(pattern2375, replacement2375) pattern2376 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(6), x_), cons2, cons3, cons50, cons127, cons19, cons1269, cons1285, cons517) rule2376 = ReplacementRule(pattern2376, replacement2376) pattern2377 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons1309, cons148) rule2377 = ReplacementRule(pattern2377, replacement2377) pattern2378 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons1309, cons148) rule2378 = ReplacementRule(pattern2378, replacement2378) pattern2379 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons1309, cons139) rule2379 = ReplacementRule(pattern2379, replacement2379) pattern2380 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons1309, cons139) rule2380 = ReplacementRule(pattern2380, replacement2380) pattern2381 = Pattern(Integral(sqrt(WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2381 = ReplacementRule(pattern2381, replacement2381) pattern2382 = Pattern(Integral(sqrt(WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2382 = ReplacementRule(pattern2382, replacement2382) pattern2383 = Pattern(Integral(S(1)/(sqrt(g_*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2383 = ReplacementRule(pattern2383, replacement2383) pattern2384 = Pattern(Integral(S(1)/(sqrt(g_/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2384 = ReplacementRule(pattern2384, replacement2384) pattern2385 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons50, cons127, cons1269, cons1303) rule2385 = ReplacementRule(pattern2385, replacement2385) pattern2386 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_, x_), cons2, cons3, cons50, cons127, cons1269, cons1303) rule2386 = ReplacementRule(pattern2386, replacement2386) pattern2387 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1310) rule2387 = ReplacementRule(pattern2387, replacement2387) pattern2388 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1310) rule2388 = ReplacementRule(pattern2388, replacement2388) pattern2389 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons149) rule2389 = ReplacementRule(pattern2389, replacement2389) pattern2390 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons149) rule2390 = ReplacementRule(pattern2390, replacement2390) pattern2391 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2391 = ReplacementRule(pattern2391, replacement2391) pattern2392 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2392 = ReplacementRule(pattern2392, replacement2392) pattern2393 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2393 = ReplacementRule(pattern2393, replacement2393) pattern2394 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2394 = ReplacementRule(pattern2394, replacement2394) pattern2395 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons20, cons1311) rule2395 = ReplacementRule(pattern2395, replacement2395) pattern2396 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons20, cons1311) rule2396 = ReplacementRule(pattern2396, replacement2396) pattern2397 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267) rule2397 = ReplacementRule(pattern2397, replacement2397) pattern2398 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267) rule2398 = ReplacementRule(pattern2398, replacement2398) pattern2399 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1312) rule2399 = ReplacementRule(pattern2399, replacement2399) pattern2400 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1312) rule2400 = ReplacementRule(pattern2400, replacement2400) pattern2401 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons1313, cons89, cons91, cons1314) rule2401 = ReplacementRule(pattern2401, replacement2401) pattern2402 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267, cons1313, cons89, cons91, cons1314) rule2402 = ReplacementRule(pattern2402, replacement2402) pattern2403 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1313, cons348, cons1315, cons1314) rule2403 = ReplacementRule(pattern2403, replacement2403) pattern2404 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons1313, cons348, cons1315, cons1314) rule2404 = ReplacementRule(pattern2404, replacement2404) pattern2405 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267) rule2405 = ReplacementRule(pattern2405, replacement2405) pattern2406 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons72, cons1267) rule2406 = ReplacementRule(pattern2406, replacement2406) pattern2407 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons157, cons1316) rule2407 = ReplacementRule(pattern2407, replacement2407) pattern2408 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons157, cons1316) rule2408 = ReplacementRule(pattern2408, replacement2408) pattern2409 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons1317, cons1316, cons116) rule2409 = ReplacementRule(pattern2409, replacement2409) pattern2410 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons1317, cons1316, cons116) rule2410 = ReplacementRule(pattern2410, replacement2410) pattern2411 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons33, cons96, cons1318, cons1172) rule2411 = ReplacementRule(pattern2411, replacement2411) pattern2412 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1267, cons33, cons96, cons1318, cons1172) rule2412 = ReplacementRule(pattern2412, replacement2412) pattern2413 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons1319) rule2413 = ReplacementRule(pattern2413, replacement2413) pattern2414 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1267, cons1319) rule2414 = ReplacementRule(pattern2414, replacement2414) pattern2415 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2)/(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2415 = ReplacementRule(pattern2415, replacement2415) pattern2416 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2)/(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2416 = ReplacementRule(pattern2416, replacement2416) pattern2417 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2417 = ReplacementRule(pattern2417, replacement2417) pattern2418 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73) rule2418 = ReplacementRule(pattern2418, replacement2418) pattern2419 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons1320) rule2419 = ReplacementRule(pattern2419, replacement2419) pattern2420 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons1320) rule2420 = ReplacementRule(pattern2420, replacement2420) pattern2421 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons1321) rule2421 = ReplacementRule(pattern2421, replacement2421) pattern2422 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons1321) rule2422 = ReplacementRule(pattern2422, replacement2422) pattern2423 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons33, cons1322) rule2423 = ReplacementRule(pattern2423, replacement2423) pattern2424 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons33, cons1322) rule2424 = ReplacementRule(pattern2424, replacement2424) pattern2425 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons1323) rule2425 = ReplacementRule(pattern2425, replacement2425) pattern2426 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons1323) rule2426 = ReplacementRule(pattern2426, replacement2426) pattern2427 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule2427 = ReplacementRule(pattern2427, replacement2427) pattern2428 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule2428 = ReplacementRule(pattern2428, replacement2428) pattern2429 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons33, cons170, cons517) rule2429 = ReplacementRule(pattern2429, replacement2429) pattern2430 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons33, cons170, cons517) rule2430 = ReplacementRule(pattern2430, replacement2430) pattern2431 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons33, cons96, cons517) rule2431 = ReplacementRule(pattern2431, replacement2431) pattern2432 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons33, cons96, cons517) rule2432 = ReplacementRule(pattern2432, replacement2432) pattern2433 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1269, cons79, cons1324) rule2433 = ReplacementRule(pattern2433, replacement2433) pattern2434 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1269, cons79, cons1324) rule2434 = ReplacementRule(pattern2434, replacement2434) pattern2435 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1269) rule2435 = ReplacementRule(pattern2435, replacement2435) pattern2436 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1269) rule2436 = ReplacementRule(pattern2436, replacement2436) pattern2437 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons64, cons89) rule2437 = ReplacementRule(pattern2437, replacement2437) pattern2438 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons64, cons89) rule2438 = ReplacementRule(pattern2438, replacement2438) pattern2439 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322) rule2439 = ReplacementRule(pattern2439, replacement2439) pattern2440 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons1267, cons33, cons1322) rule2440 = ReplacementRule(pattern2440, replacement2440) pattern2441 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1323) rule2441 = ReplacementRule(pattern2441, replacement2441) pattern2442 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons19, cons1267, cons1323) rule2442 = ReplacementRule(pattern2442, replacement2442) pattern2443 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons33, cons96) rule2443 = ReplacementRule(pattern2443, replacement2443) pattern2444 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons33, cons96) rule2444 = ReplacementRule(pattern2444, replacement2444) pattern2445 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons274) rule2445 = ReplacementRule(pattern2445, replacement2445) pattern2446 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons274) rule2446 = ReplacementRule(pattern2446, replacement2446) pattern2447 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons95, cons168, cons91, cons1326) rule2447 = ReplacementRule(pattern2447, replacement2447) pattern2448 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons95, cons168, cons91, cons1326) rule2448 = ReplacementRule(pattern2448, replacement2448) pattern2449 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons33, cons168, cons348, cons1326) rule2449 = ReplacementRule(pattern2449, replacement2449) pattern2450 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons33, cons168, cons348, cons1326) rule2450 = ReplacementRule(pattern2450, replacement2450) pattern2451 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons95, cons96, cons1327, cons1328) rule2451 = ReplacementRule(pattern2451, replacement2451) pattern2452 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons95, cons96, cons1327, cons1328) rule2452 = ReplacementRule(pattern2452, replacement2452) pattern2453 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons95, cons96, cons167, cons1328) rule2453 = ReplacementRule(pattern2453, replacement2453) pattern2454 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons95, cons96, cons167, cons1328) rule2454 = ReplacementRule(pattern2454, replacement2454) pattern2455 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons33, cons96, cons1329, cons1328) rule2455 = ReplacementRule(pattern2455, replacement2455) pattern2456 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons33, cons96, cons1329, cons1328) rule2456 = ReplacementRule(pattern2456, replacement2456) pattern2457 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons167, cons1330) rule2457 = ReplacementRule(pattern2457, replacement2457) pattern2458 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons167, cons1330) rule2458 = ReplacementRule(pattern2458, replacement2458) pattern2459 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons465, cons1330) rule2459 = ReplacementRule(pattern2459, replacement2459) pattern2460 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons465, cons1330) rule2460 = ReplacementRule(pattern2460, replacement2460) pattern2461 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons1330) rule2461 = ReplacementRule(pattern2461, replacement2461) pattern2462 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons1330) rule2462 = ReplacementRule(pattern2462, replacement2462) pattern2463 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons90, cons810) rule2463 = ReplacementRule(pattern2463, replacement2463) pattern2464 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons90, cons810) rule2464 = ReplacementRule(pattern2464, replacement2464) pattern2465 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2465 = ReplacementRule(pattern2465, replacement2465) pattern2466 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2466 = ReplacementRule(pattern2466, replacement2466) pattern2467 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons91, cons1331, cons810) rule2467 = ReplacementRule(pattern2467, replacement2467) pattern2468 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons91, cons810) rule2468 = ReplacementRule(pattern2468, replacement2468) pattern2469 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2469 = ReplacementRule(pattern2469, replacement2469) pattern2470 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2470 = ReplacementRule(pattern2470, replacement2470) pattern2471 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1332) rule2471 = ReplacementRule(pattern2471, replacement2471) pattern2472 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1332) rule2472 = ReplacementRule(pattern2472, replacement2472) pattern2473 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2473 = ReplacementRule(pattern2473, replacement2473) pattern2474 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2474 = ReplacementRule(pattern2474, replacement2474) pattern2475 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons545) rule2475 = ReplacementRule(pattern2475, replacement2475) pattern2476 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons545) rule2476 = ReplacementRule(pattern2476, replacement2476) pattern2477 = Pattern(Integral(sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2477 = ReplacementRule(pattern2477, replacement2477) pattern2478 = Pattern(Integral(sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2478 = ReplacementRule(pattern2478, replacement2478) pattern2479 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons167, cons810) rule2479 = ReplacementRule(pattern2479, replacement2479) pattern2480 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons167, cons810) rule2480 = ReplacementRule(pattern2480, replacement2480) pattern2481 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons91, cons810) rule2481 = ReplacementRule(pattern2481, replacement2481) pattern2482 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_/sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325, cons89, cons91, cons810) rule2482 = ReplacementRule(pattern2482, replacement2482) pattern2483 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2483 = ReplacementRule(pattern2483, replacement2483) pattern2484 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2484 = ReplacementRule(pattern2484, replacement2484) pattern2485 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1332, cons45) rule2485 = ReplacementRule(pattern2485, replacement2485) pattern2486 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1332, cons45) rule2486 = ReplacementRule(pattern2486, replacement2486) pattern2487 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2487 = ReplacementRule(pattern2487, replacement2487) pattern2488 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1325) rule2488 = ReplacementRule(pattern2488, replacement2488) pattern2489 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons1325, cons89, cons167, cons87) rule2489 = ReplacementRule(pattern2489, replacement2489) pattern2490 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1267, cons1325, cons89, cons167, cons87) rule2490 = ReplacementRule(pattern2490, replacement2490) pattern2491 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons20) rule2491 = ReplacementRule(pattern2491, replacement2491) pattern2492 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1267, cons1325, cons20) rule2492 = ReplacementRule(pattern2492, replacement2492) pattern2493 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons1333) rule2493 = ReplacementRule(pattern2493, replacement2493) pattern2494 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons1333) rule2494 = ReplacementRule(pattern2494, replacement2494) pattern2495 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons1334) rule2495 = ReplacementRule(pattern2495, replacement2495) pattern2496 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons45, cons1334) rule2496 = ReplacementRule(pattern2496, replacement2496) pattern2497 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons450) rule2497 = ReplacementRule(pattern2497, replacement2497) pattern2498 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons21, cons450) rule2498 = ReplacementRule(pattern2498, replacement2498) pattern2499 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1267, cons1325, cons21) rule2499 = ReplacementRule(pattern2499, replacement2499) pattern2500 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1267, cons1325, cons21) rule2500 = ReplacementRule(pattern2500, replacement2500) pattern2501 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons1320) rule2501 = ReplacementRule(pattern2501, replacement2501) pattern2502 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons1320) rule2502 = ReplacementRule(pattern2502, replacement2502) pattern2503 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons33, cons96) rule2503 = ReplacementRule(pattern2503, replacement2503) pattern2504 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons33, cons96) rule2504 = ReplacementRule(pattern2504, replacement2504) pattern2505 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1269, cons274) rule2505 = ReplacementRule(pattern2505, replacement2505) pattern2506 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1269, cons274) rule2506 = ReplacementRule(pattern2506, replacement2506) pattern2507 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons1335, cons91, cons1336) rule2507 = ReplacementRule(pattern2507, replacement2507) pattern2508 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons1335, cons91, cons1336) rule2508 = ReplacementRule(pattern2508, replacement2508) pattern2509 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1269, cons1325, cons33, cons1335, cons1336, cons1337) rule2509 = ReplacementRule(pattern2509, replacement2509) pattern2510 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1269, cons1325, cons33, cons1335, cons1336, cons1337) rule2510 = ReplacementRule(pattern2510, replacement2510) pattern2511 = Pattern(Integral(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2511 = ReplacementRule(pattern2511, replacement2511) pattern2512 = Pattern(Integral(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2512 = ReplacementRule(pattern2512, replacement2512) pattern2513 = Pattern(Integral(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2513 = ReplacementRule(pattern2513, replacement2513) pattern2514 = Pattern(Integral(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2514 = ReplacementRule(pattern2514, replacement2514) pattern2515 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons96, cons1327, cons1172) rule2515 = ReplacementRule(pattern2515, replacement2515) pattern2516 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons96, cons1327, cons1172) rule2516 = ReplacementRule(pattern2516, replacement2516) pattern2517 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2517 = ReplacementRule(pattern2517, replacement2517) pattern2518 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2518 = ReplacementRule(pattern2518, replacement2518) pattern2519 = Pattern(Integral((c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2519 = ReplacementRule(pattern2519, replacement2519) pattern2520 = Pattern(Integral((c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2520 = ReplacementRule(pattern2520, replacement2520) pattern2521 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons96, cons1338, cons1172) rule2521 = ReplacementRule(pattern2521, replacement2521) pattern2522 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons96, cons1338, cons1172) rule2522 = ReplacementRule(pattern2522, replacement2522) pattern2523 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2523 = ReplacementRule(pattern2523, replacement2523) pattern2524 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2524 = ReplacementRule(pattern2524, replacement2524) pattern2525 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2525 = ReplacementRule(pattern2525, replacement2525) pattern2526 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2526 = ReplacementRule(pattern2526, replacement2526) pattern2527 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1172, cons1339) rule2527 = ReplacementRule(pattern2527, replacement2527) pattern2528 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1172, cons1339) rule2528 = ReplacementRule(pattern2528, replacement2528) pattern2529 = Pattern(Integral(sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2529 = ReplacementRule(pattern2529, replacement2529) pattern2530 = Pattern(Integral(sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2530 = ReplacementRule(pattern2530, replacement2530) pattern2531 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2531 = ReplacementRule(pattern2531, replacement2531) pattern2532 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2532 = ReplacementRule(pattern2532, replacement2532) pattern2533 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1340) rule2533 = ReplacementRule(pattern2533, replacement2533) pattern2534 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1340) rule2534 = ReplacementRule(pattern2534, replacement2534) pattern2535 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1341) rule2535 = ReplacementRule(pattern2535, replacement2535) pattern2536 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1341) rule2536 = ReplacementRule(pattern2536, replacement2536) pattern2537 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1342) rule2537 = ReplacementRule(pattern2537, replacement2537) pattern2538 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1342) rule2538 = ReplacementRule(pattern2538, replacement2538) pattern2539 = Pattern(Integral(sqrt(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1343, cons1344, cons1345) rule2539 = ReplacementRule(pattern2539, replacement2539) pattern2540 = Pattern(Integral(sqrt(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1343, cons1344, cons1345) rule2540 = ReplacementRule(pattern2540, replacement2540) pattern2541 = Pattern(Integral(sqrt(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1325, cons1344) rule2541 = ReplacementRule(pattern2541, replacement2541) pattern2542 = Pattern(Integral(sqrt(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1325, cons1344) rule2542 = ReplacementRule(pattern2542, replacement2542) pattern2543 = Pattern(Integral(sqrt(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1325, cons1346) rule2543 = ReplacementRule(pattern2543, replacement2543) pattern2544 = Pattern(Integral(sqrt(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1325, cons1346) rule2544 = ReplacementRule(pattern2544, replacement2544) pattern2545 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1347) rule2545 = ReplacementRule(pattern2545, replacement2545) pattern2546 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1347) rule2546 = ReplacementRule(pattern2546, replacement2546) pattern2547 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1348) rule2547 = ReplacementRule(pattern2547, replacement2547) pattern2548 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1348) rule2548 = ReplacementRule(pattern2548, replacement2548) pattern2549 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1349, cons1350, cons1351) rule2549 = ReplacementRule(pattern2549, replacement2549) pattern2550 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1349, cons1350, cons1351) rule2550 = ReplacementRule(pattern2550, replacement2550) pattern2551 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1349, cons1352, cons1353) rule2551 = ReplacementRule(pattern2551, replacement2551) pattern2552 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1349, cons1352, cons1353) rule2552 = ReplacementRule(pattern2552, replacement2552) pattern2553 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1273, cons1354, cons1355) rule2553 = ReplacementRule(pattern2553, replacement2553) pattern2554 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1273, cons1354, cons1355) rule2554 = ReplacementRule(pattern2554, replacement2554) pattern2555 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1354) rule2555 = ReplacementRule(pattern2555, replacement2555) pattern2556 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1354) rule2556 = ReplacementRule(pattern2556, replacement2556) pattern2557 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1356) rule2557 = ReplacementRule(pattern2557, replacement2557) pattern2558 = Pattern(Integral(S(1)/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1356) rule2558 = ReplacementRule(pattern2558, replacement2558) pattern2559 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1357) rule2559 = ReplacementRule(pattern2559, replacement2559) pattern2560 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1357) rule2560 = ReplacementRule(pattern2560, replacement2560) pattern2561 = Pattern(Integral(S(1)/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1358) rule2561 = ReplacementRule(pattern2561, replacement2561) pattern2562 = Pattern(Integral(S(1)/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons1358) rule2562 = ReplacementRule(pattern2562, replacement2562) pattern2563 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2563 = ReplacementRule(pattern2563, replacement2563) pattern2564 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2564 = ReplacementRule(pattern2564, replacement2564) pattern2565 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons1359, cons1360, cons1361, cons1336) rule2565 = ReplacementRule(pattern2565, replacement2565) pattern2566 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325, cons95, cons1359, cons1360, cons1361, cons1336) rule2566 = ReplacementRule(pattern2566, replacement2566) pattern2567 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons64) rule2567 = ReplacementRule(pattern2567, replacement2567) pattern2568 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons64) rule2568 = ReplacementRule(pattern2568, replacement2568) pattern2569 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1269, cons1325) rule2569 = ReplacementRule(pattern2569, replacement2569) pattern2570 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1269, cons1325) rule2570 = ReplacementRule(pattern2570, replacement2570) pattern2571 = Pattern(Integral(((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons25) rule2571 = ReplacementRule(pattern2571, replacement2571) pattern2572 = Pattern(Integral(((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons25) rule2572 = ReplacementRule(pattern2572, replacement2572) pattern2573 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons87) rule2573 = ReplacementRule(pattern2573, replacement2573) pattern2574 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons87) rule2574 = ReplacementRule(pattern2574, replacement2574) pattern2575 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons25, cons20) rule2575 = ReplacementRule(pattern2575, replacement2575) pattern2576 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons25, cons20) rule2576 = ReplacementRule(pattern2576, replacement2576) pattern2577 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons25, cons21) rule2577 = ReplacementRule(pattern2577, replacement2577) pattern2578 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons25, cons21) rule2578 = ReplacementRule(pattern2578, replacement2578) pattern2579 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule2579 = ReplacementRule(pattern2579, replacement2579) pattern2580 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule2580 = ReplacementRule(pattern2580, replacement2580) pattern2581 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons5, cons1276, cons87, cons1363) rule2581 = ReplacementRule(pattern2581, replacement2581) pattern2582 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons5, cons1276, cons87, cons1363) rule2582 = ReplacementRule(pattern2582, replacement2582) pattern2583 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons5, cons1276, cons1267, cons87, cons1364) rule2583 = ReplacementRule(pattern2583, replacement2583) pattern2584 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons5, cons1276, cons1267, cons87, cons1364) rule2584 = ReplacementRule(pattern2584, replacement2584) pattern2585 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons50, cons127, cons8, cons29, cons19, cons4, cons1276, cons1267) rule2585 = ReplacementRule(pattern2585, replacement2585) pattern2586 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons50, cons127, cons8, cons29, cons19, cons4, cons1276, cons1267) rule2586 = ReplacementRule(pattern2586, replacement2586) pattern2587 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1276, cons1269) rule2587 = ReplacementRule(pattern2587, replacement2587) pattern2588 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1276, cons1269) rule2588 = ReplacementRule(pattern2588, replacement2588) pattern2589 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1365) rule2589 = ReplacementRule(pattern2589, replacement2589) pattern2590 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1365) rule2590 = ReplacementRule(pattern2590, replacement2590) pattern2591 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267) rule2591 = ReplacementRule(pattern2591, replacement2591) pattern2592 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267) rule2592 = ReplacementRule(pattern2592, replacement2592) pattern2593 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons20, cons1366) rule2593 = ReplacementRule(pattern2593, replacement2593) pattern2594 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons20, cons1366) rule2594 = ReplacementRule(pattern2594, replacement2594) pattern2595 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons72, cons1267, cons1308) rule2595 = ReplacementRule(pattern2595, replacement2595) pattern2596 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons72, cons1267, cons1308) rule2596 = ReplacementRule(pattern2596, replacement2596) pattern2597 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267) rule2597 = ReplacementRule(pattern2597, replacement2597) pattern2598 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267) rule2598 = ReplacementRule(pattern2598, replacement2598) pattern2599 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1284, cons144) rule2599 = ReplacementRule(pattern2599, replacement2599) pattern2600 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1284, cons144) rule2600 = ReplacementRule(pattern2600, replacement2600) pattern2601 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1284, cons337) rule2601 = ReplacementRule(pattern2601, replacement2601) pattern2602 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1284, cons337) rule2602 = ReplacementRule(pattern2602, replacement2602) pattern2603 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267, cons1286, cons89, cons91, cons1367, cons1368) rule2603 = ReplacementRule(pattern2603, replacement2603) pattern2604 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267, cons1286, cons89, cons91, cons1367, cons1368) rule2604 = ReplacementRule(pattern2604, replacement2604) pattern2605 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons1286, cons348, cons1369, cons1368) rule2605 = ReplacementRule(pattern2605, replacement2605) pattern2606 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons1286, cons348, cons1369, cons1368) rule2606 = ReplacementRule(pattern2606, replacement2606) pattern2607 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons72, cons1267, cons1370) rule2607 = ReplacementRule(pattern2607, replacement2607) pattern2608 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons72, cons1267, cons1370) rule2608 = ReplacementRule(pattern2608, replacement2608) pattern2609 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1371, cons1262) rule2609 = ReplacementRule(pattern2609, replacement2609) pattern2610 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1371, cons1262) rule2610 = ReplacementRule(pattern2610, replacement2610) pattern2611 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1372, cons1283, cons116) rule2611 = ReplacementRule(pattern2611, replacement2611) pattern2612 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1372, cons1283, cons116) rule2612 = ReplacementRule(pattern2612, replacement2612) pattern2613 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267, cons95, cons170, cons91, cons1367, cons172) rule2613 = ReplacementRule(pattern2613, replacement2613) pattern2614 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons72, cons1267, cons95, cons170, cons91, cons1367, cons172) rule2614 = ReplacementRule(pattern2614, replacement2614) pattern2615 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons33, cons170, cons1373, cons1374, cons172) rule2615 = ReplacementRule(pattern2615, replacement2615) pattern2616 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons33, cons170, cons1373, cons1374, cons172) rule2616 = ReplacementRule(pattern2616, replacement2616) pattern2617 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons33, cons96, cons1283, cons1318, cons172) rule2617 = ReplacementRule(pattern2617, replacement2617) pattern2618 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons72, cons1267, cons33, cons96, cons1283, cons1318, cons172) rule2618 = ReplacementRule(pattern2618, replacement2618) pattern2619 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1319) rule2619 = ReplacementRule(pattern2619, replacement2619) pattern2620 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons72, cons1267, cons1319) rule2620 = ReplacementRule(pattern2620, replacement2620) pattern2621 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons1375) rule2621 = ReplacementRule(pattern2621, replacement2621) pattern2622 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons1375) rule2622 = ReplacementRule(pattern2622, replacement2622) pattern2623 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1267, cons246, cons1376, cons139) rule2623 = ReplacementRule(pattern2623, replacement2623) pattern2624 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1267, cons246, cons1376, cons139) rule2624 = ReplacementRule(pattern2624, replacement2624) pattern2625 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons1377, cons255) rule2625 = ReplacementRule(pattern2625, replacement2625) pattern2626 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons1377, cons255) rule2626 = ReplacementRule(pattern2626, replacement2626) pattern2627 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons1378) rule2627 = ReplacementRule(pattern2627, replacement2627) pattern2628 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons1378) rule2628 = ReplacementRule(pattern2628, replacement2628) pattern2629 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons1379) rule2629 = ReplacementRule(pattern2629, replacement2629) pattern2630 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1267, cons33, cons1379) rule2630 = ReplacementRule(pattern2630, replacement2630) pattern2631 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons1380, cons1283) rule2631 = ReplacementRule(pattern2631, replacement2631) pattern2632 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons1380, cons1283) rule2632 = ReplacementRule(pattern2632, replacement2632) pattern2633 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons255) rule2633 = ReplacementRule(pattern2633, replacement2633) pattern2634 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons1267, cons255) rule2634 = ReplacementRule(pattern2634, replacement2634) pattern2635 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1269, cons246, cons170, cons139, cons517) rule2635 = ReplacementRule(pattern2635, replacement2635) pattern2636 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1269, cons246, cons170, cons139, cons517) rule2636 = ReplacementRule(pattern2636, replacement2636) pattern2637 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons1269, cons33, cons170, cons1381, cons517) rule2637 = ReplacementRule(pattern2637, replacement2637) pattern2638 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons1269, cons33, cons170, cons1381, cons517) rule2638 = ReplacementRule(pattern2638, replacement2638) pattern2639 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1269, cons246, cons96, cons148, cons255, cons517) rule2639 = ReplacementRule(pattern2639, replacement2639) pattern2640 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1269, cons246, cons96, cons148, cons255, cons517) rule2640 = ReplacementRule(pattern2640, replacement2640) pattern2641 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons1269, cons33, cons96, cons517) rule2641 = ReplacementRule(pattern2641, replacement2641) pattern2642 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons1269, cons33, cons96, cons517) rule2642 = ReplacementRule(pattern2642, replacement2642) pattern2643 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons1269, cons13, cons148, cons1287, cons255, cons517) rule2643 = ReplacementRule(pattern2643, replacement2643) pattern2644 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons1269, cons13, cons148, cons1287, cons255, cons517) rule2644 = ReplacementRule(pattern2644, replacement2644) pattern2645 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons1269, cons13, cons139, cons517) rule2645 = ReplacementRule(pattern2645, replacement2645) pattern2646 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons1269, cons13, cons139, cons517) rule2646 = ReplacementRule(pattern2646, replacement2646) pattern2647 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1269) rule2647 = ReplacementRule(pattern2647, replacement2647) pattern2648 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons1269) rule2648 = ReplacementRule(pattern2648, replacement2648) pattern2649 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1269, cons1324) rule2649 = ReplacementRule(pattern2649, replacement2649) pattern2650 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons1269, cons1324) rule2650 = ReplacementRule(pattern2650, replacement2650) pattern2651 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons1301, cons1382) rule2651 = ReplacementRule(pattern2651, replacement2651) pattern2652 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons1301, cons1382) rule2652 = ReplacementRule(pattern2652, replacement2652) pattern2653 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons360) rule2653 = ReplacementRule(pattern2653, replacement2653) pattern2654 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons360) rule2654 = ReplacementRule(pattern2654, replacement2654) pattern2655 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1280) rule2655 = ReplacementRule(pattern2655, replacement2655) pattern2656 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1280) rule2656 = ReplacementRule(pattern2656, replacement2656) pattern2657 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1383, cons1384) rule2657 = ReplacementRule(pattern2657, replacement2657) pattern2658 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons1267, cons1383, cons1384) rule2658 = ReplacementRule(pattern2658, replacement2658) pattern2659 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons64) rule2659 = ReplacementRule(pattern2659, replacement2659) pattern2660 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons64) rule2660 = ReplacementRule(pattern2660, replacement2660) pattern2661 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1385) rule2661 = ReplacementRule(pattern2661, replacement2661) pattern2662 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1385) rule2662 = ReplacementRule(pattern2662, replacement2662) pattern2663 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons86) rule2663 = ReplacementRule(pattern2663, replacement2663) pattern2664 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons86) rule2664 = ReplacementRule(pattern2664, replacement2664) pattern2665 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons1267, cons20, cons13, cons1386) rule2665 = ReplacementRule(pattern2665, replacement2665) pattern2666 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons1267, cons20, cons13, cons1386) rule2666 = ReplacementRule(pattern2666, replacement2666) pattern2667 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons33, cons1387, cons1283) rule2667 = ReplacementRule(pattern2667, replacement2667) pattern2668 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1267, cons33, cons1387, cons1283) rule2668 = ReplacementRule(pattern2668, replacement2668) pattern2669 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1388) rule2669 = ReplacementRule(pattern2669, replacement2669) pattern2670 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons50, cons127, cons210, cons19, cons5, cons1267, cons1388) rule2670 = ReplacementRule(pattern2670, replacement2670) pattern2671 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1172) rule2671 = ReplacementRule(pattern2671, replacement2671) pattern2672 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1172) rule2672 = ReplacementRule(pattern2672, replacement2672) pattern2673 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons33, cons96) rule2673 = ReplacementRule(pattern2673, replacement2673) pattern2674 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons33, cons96) rule2674 = ReplacementRule(pattern2674, replacement2674) pattern2675 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons145) rule2675 = ReplacementRule(pattern2675, replacement2675) pattern2676 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons145) rule2676 = ReplacementRule(pattern2676, replacement2676) pattern2677 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons1308, cons20) rule2677 = ReplacementRule(pattern2677, replacement2677) pattern2678 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1267, cons1308, cons20) rule2678 = ReplacementRule(pattern2678, replacement2678) pattern2679 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1308, cons21) rule2679 = ReplacementRule(pattern2679, replacement2679) pattern2680 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1267, cons1308, cons21) rule2680 = ReplacementRule(pattern2680, replacement2680) pattern2681 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons64, cons1389) rule2681 = ReplacementRule(pattern2681, replacement2681) pattern2682 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons64, cons1389) rule2682 = ReplacementRule(pattern2682, replacement2682) pattern2683 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons5, cons1267, cons20) rule2683 = ReplacementRule(pattern2683, replacement2683) pattern2684 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons4, cons5, cons1267, cons20) rule2684 = ReplacementRule(pattern2684, replacement2684) pattern2685 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons5, cons1267, cons21) rule2685 = ReplacementRule(pattern2685, replacement2685) pattern2686 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons5, cons1267, cons21) rule2686 = ReplacementRule(pattern2686, replacement2686) pattern2687 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons33, cons96, cons1390) rule2687 = ReplacementRule(pattern2687, replacement2687) pattern2688 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons33, cons96, cons1390) rule2688 = ReplacementRule(pattern2688, replacement2688) pattern2689 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons33, cons170, cons1391) rule2689 = ReplacementRule(pattern2689, replacement2689) pattern2690 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons1269, cons33, cons170, cons1391) rule2690 = ReplacementRule(pattern2690, replacement2690) pattern2691 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1269, cons1392) rule2691 = ReplacementRule(pattern2691, replacement2691) pattern2692 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1269, cons1392) rule2692 = ReplacementRule(pattern2692, replacement2692) pattern2693 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1172, cons96, cons91) rule2693 = ReplacementRule(pattern2693, replacement2693) pattern2694 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1172, cons96, cons91) rule2694 = ReplacementRule(pattern2694, replacement2694) pattern2695 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons1172, cons96, cons1393, cons1394) rule2695 = ReplacementRule(pattern2695, replacement2695) pattern2696 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons1172, cons96, cons1393, cons1394) rule2696 = ReplacementRule(pattern2696, replacement2696) pattern2697 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons1172, cons96, cons1393, cons1395) rule2697 = ReplacementRule(pattern2697, replacement2697) pattern2698 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons1269, cons1172, cons96, cons1393, cons1395) rule2698 = ReplacementRule(pattern2698, replacement2698) pattern2699 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1269, cons1392, cons1307, cons89, cons91, cons1396) rule2699 = ReplacementRule(pattern2699, replacement2699) pattern2700 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1269, cons1392, cons1307, cons89, cons91, cons1396) rule2700 = ReplacementRule(pattern2700, replacement2700) pattern2701 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1269, cons1392, cons1307, cons89, cons91, cons1395) rule2701 = ReplacementRule(pattern2701, replacement2701) pattern2702 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1269, cons1392, cons1307, cons89, cons91, cons1395) rule2702 = ReplacementRule(pattern2702, replacement2702) pattern2703 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1269, cons1392, cons1307, cons348, cons215, cons1395) rule2703 = ReplacementRule(pattern2703, replacement2703) pattern2704 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(4), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1269, cons1392, cons1307, cons348, cons215, cons1395) rule2704 = ReplacementRule(pattern2704, replacement2704) pattern2705 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(6), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1269, cons1172, cons586, cons1397, cons1398, cons1399, cons145) rule2705 = ReplacementRule(pattern2705, replacement2705) pattern2706 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(6), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1269, cons1172, cons586, cons1397, cons1398, cons1399, cons145) rule2706 = ReplacementRule(pattern2706, replacement2706) pattern2707 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1400, cons1401) rule2707 = ReplacementRule(pattern2707, replacement2707) pattern2708 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons29, cons50, cons127, cons1269, cons1400, cons1401) rule2708 = ReplacementRule(pattern2708, replacement2708) pattern2709 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**n_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons87, cons1402) rule2709 = ReplacementRule(pattern2709, replacement2709) pattern2710 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**n_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons210, cons5, cons1269, cons87, cons1402) rule2710 = ReplacementRule(pattern2710, replacement2710) pattern2711 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons148, cons1404) rule2711 = ReplacementRule(pattern2711, replacement2711) pattern2712 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons148, cons1404) rule2712 = ReplacementRule(pattern2712, replacement2712) pattern2713 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons148, cons1405) rule2713 = ReplacementRule(pattern2713, replacement2713) pattern2714 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons148, cons1405) rule2714 = ReplacementRule(pattern2714, replacement2714) pattern2715 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons148) rule2715 = ReplacementRule(pattern2715, replacement2715) pattern2716 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons148) rule2716 = ReplacementRule(pattern2716, replacement2716) pattern2717 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons139, cons167) rule2717 = ReplacementRule(pattern2717, replacement2717) pattern2718 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons139, cons167) rule2718 = ReplacementRule(pattern2718, replacement2718) pattern2719 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons139, cons90) rule2719 = ReplacementRule(pattern2719, replacement2719) pattern2720 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons139, cons90) rule2720 = ReplacementRule(pattern2720, replacement2720) pattern2721 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons139) rule2721 = ReplacementRule(pattern2721, replacement2721) pattern2722 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons139) rule2722 = ReplacementRule(pattern2722, replacement2722) pattern2723 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2723 = ReplacementRule(pattern2723, replacement2723) pattern2724 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons210, cons1269) rule2724 = ReplacementRule(pattern2724, replacement2724) pattern2725 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(d_*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269) rule2725 = ReplacementRule(pattern2725, replacement2725) pattern2726 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(d_*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269) rule2726 = ReplacementRule(pattern2726, replacement2726) pattern2727 = Pattern(Integral(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2727 = ReplacementRule(pattern2727, With2727) pattern2728 = Pattern(Integral(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1269) rule2728 = ReplacementRule(pattern2728, With2728) pattern2729 = Pattern(Integral(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269) rule2729 = ReplacementRule(pattern2729, replacement2729) pattern2730 = Pattern(Integral(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269) rule2730 = ReplacementRule(pattern2730, replacement2730) pattern2731 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons1406, cons90) rule2731 = ReplacementRule(pattern2731, replacement2731) pattern2732 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons1406, cons90) rule2732 = ReplacementRule(pattern2732, replacement2732) pattern2733 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons1406, cons465) rule2733 = ReplacementRule(pattern2733, replacement2733) pattern2734 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1403, cons1406, cons465) rule2734 = ReplacementRule(pattern2734, replacement2734) pattern2735 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1269, cons20, cons1407) rule2735 = ReplacementRule(pattern2735, replacement2735) pattern2736 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons4, cons5, cons1269, cons20, cons1407) rule2736 = ReplacementRule(pattern2736, replacement2736) pattern2737 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1408, cons269, cons148, cons1409) rule2737 = ReplacementRule(pattern2737, replacement2737) pattern2738 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons29, cons50, cons127, cons210, cons1269, cons1408, cons269, cons148, cons1409) rule2738 = ReplacementRule(pattern2738, replacement2738) pattern2739 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1267, cons1301, cons1382) rule2739 = ReplacementRule(pattern2739, replacement2739) pattern2740 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1267, cons1301, cons1382) rule2740 = ReplacementRule(pattern2740, replacement2740) pattern2741 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1267, cons20, cons13, cons1386) rule2741 = ReplacementRule(pattern2741, replacement2741) pattern2742 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons1267, cons20, cons13, cons1386) rule2742 = ReplacementRule(pattern2742, replacement2742) pattern2743 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1267, cons1172) rule2743 = ReplacementRule(pattern2743, replacement2743) pattern2744 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1267, cons1172) rule2744 = ReplacementRule(pattern2744, replacement2744) pattern2745 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1267, cons1308, cons20) rule2745 = ReplacementRule(pattern2745, replacement2745) pattern2746 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1267, cons1308, cons20) rule2746 = ReplacementRule(pattern2746, replacement2746) pattern2747 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1267, cons1308, cons21) rule2747 = ReplacementRule(pattern2747, replacement2747) pattern2748 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1267, cons1308, cons21) rule2748 = ReplacementRule(pattern2748, replacement2748) pattern2749 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons64, cons1389) rule2749 = ReplacementRule(pattern2749, replacement2749) pattern2750 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons1267, cons64, cons1389) rule2750 = ReplacementRule(pattern2750, replacement2750) pattern2751 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons1267, cons20) rule2751 = ReplacementRule(pattern2751, replacement2751) pattern2752 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons1267, cons20) rule2752 = ReplacementRule(pattern2752, replacement2752) pattern2753 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons1267, cons21) rule2753 = ReplacementRule(pattern2753, replacement2753) pattern2754 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons1267, cons21) rule2754 = ReplacementRule(pattern2754, replacement2754) pattern2755 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1269, cons1392) rule2755 = ReplacementRule(pattern2755, replacement2755) pattern2756 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1269, cons1392) rule2756 = ReplacementRule(pattern2756, replacement2756) pattern2757 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1269, cons1410, cons1392) rule2757 = ReplacementRule(pattern2757, replacement2757) pattern2758 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1269, cons1410, cons1392) rule2758 = ReplacementRule(pattern2758, replacement2758) pattern2759 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons1269, cons1172) rule2759 = ReplacementRule(pattern2759, replacement2759) pattern2760 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons1269, cons1172) rule2760 = ReplacementRule(pattern2760, replacement2760) pattern2761 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons1269) rule2761 = ReplacementRule(pattern2761, replacement2761) pattern2762 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons1269) rule2762 = ReplacementRule(pattern2762, replacement2762) pattern2763 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons149) rule2763 = ReplacementRule(pattern2763, replacement2763) pattern2764 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons149) rule2764 = ReplacementRule(pattern2764, replacement2764) pattern2765 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1411) rule2765 = ReplacementRule(pattern2765, replacement2765) pattern2766 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1411) rule2766 = ReplacementRule(pattern2766, replacement2766) pattern2767 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2767 = ReplacementRule(pattern2767, replacement2767) pattern2768 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2768 = ReplacementRule(pattern2768, replacement2768) pattern2769 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule2769 = ReplacementRule(pattern2769, replacement2769) pattern2770 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1267) rule2770 = ReplacementRule(pattern2770, replacement2770) pattern2771 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1412, cons1413, cons107) rule2771 = ReplacementRule(pattern2771, replacement2771) pattern2772 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1412, cons1413, cons107) rule2772 = ReplacementRule(pattern2772, replacement2772) pattern2773 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1324) rule2773 = ReplacementRule(pattern2773, replacement2773) pattern2774 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1324) rule2774 = ReplacementRule(pattern2774, replacement2774) pattern2775 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2775 = ReplacementRule(pattern2775, replacement2775) pattern2776 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2776 = ReplacementRule(pattern2776, replacement2776) pattern2777 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule2777 = ReplacementRule(pattern2777, replacement2777) pattern2778 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule2778 = ReplacementRule(pattern2778, replacement2778) pattern2779 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule2779 = ReplacementRule(pattern2779, replacement2779) pattern2780 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule2780 = ReplacementRule(pattern2780, replacement2780) pattern2781 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1411) rule2781 = ReplacementRule(pattern2781, replacement2781) pattern2782 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1411) rule2782 = ReplacementRule(pattern2782, replacement2782) pattern2783 = Pattern(Integral(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2783 = ReplacementRule(pattern2783, replacement2783) pattern2784 = Pattern(Integral(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2784 = ReplacementRule(pattern2784, replacement2784) pattern2785 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1411) rule2785 = ReplacementRule(pattern2785, replacement2785) pattern2786 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1411) rule2786 = ReplacementRule(pattern2786, replacement2786) pattern2787 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2787 = ReplacementRule(pattern2787, replacement2787) pattern2788 = Pattern(Integral(S(1)/(sqrt(WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons73, cons1269, cons1325) rule2788 = ReplacementRule(pattern2788, replacement2788) pattern2789 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule2789 = ReplacementRule(pattern2789, replacement2789) pattern2790 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267) rule2790 = ReplacementRule(pattern2790, replacement2790) pattern2791 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule2791 = ReplacementRule(pattern2791, replacement2791) pattern2792 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269) rule2792 = ReplacementRule(pattern2792, replacement2792) pattern2793 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons72) rule2793 = ReplacementRule(pattern2793, replacement2793) pattern2794 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons72) rule2794 = ReplacementRule(pattern2794, replacement2794) pattern2795 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1414) rule2795 = ReplacementRule(pattern2795, replacement2795) pattern2796 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1414) rule2796 = ReplacementRule(pattern2796, replacement2796) pattern2797 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule2797 = ReplacementRule(pattern2797, replacement2797) pattern2798 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1324) rule2798 = ReplacementRule(pattern2798, replacement2798) pattern2799 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2799 = ReplacementRule(pattern2799, replacement2799) pattern2800 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1269, cons1325) rule2800 = ReplacementRule(pattern2800, replacement2800) pattern2801 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule2801 = ReplacementRule(pattern2801, replacement2801) pattern2802 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule2802 = ReplacementRule(pattern2802, replacement2802) pattern2803 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1415) rule2803 = ReplacementRule(pattern2803, replacement2803) pattern2804 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1415) rule2804 = ReplacementRule(pattern2804, replacement2804) pattern2805 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule2805 = ReplacementRule(pattern2805, replacement2805) pattern2806 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1267, cons1324) rule2806 = ReplacementRule(pattern2806, replacement2806) pattern2807 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1415) rule2807 = ReplacementRule(pattern2807, replacement2807) pattern2808 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1415) rule2808 = ReplacementRule(pattern2808, replacement2808) pattern2809 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons1416, cons87) rule2809 = ReplacementRule(pattern2809, replacement2809) pattern2810 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons72, cons1267, cons1416, cons87) rule2810 = ReplacementRule(pattern2810, replacement2810) pattern2811 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1267, cons1325, cons1306) rule2811 = ReplacementRule(pattern2811, replacement2811) pattern2812 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons1267, cons1325, cons1306) rule2812 = ReplacementRule(pattern2812, replacement2812) pattern2813 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons73, cons1417, cons1418) rule2813 = ReplacementRule(pattern2813, replacement2813) pattern2814 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons73, cons1417, cons1418) rule2814 = ReplacementRule(pattern2814, replacement2814) pattern2815 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons1418) rule2815 = ReplacementRule(pattern2815, replacement2815) pattern2816 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons1418) rule2816 = ReplacementRule(pattern2816, replacement2816) pattern2817 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons73, cons149, cons20, cons87) rule2817 = ReplacementRule(pattern2817, replacement2817) pattern2818 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons73, cons149, cons20, cons87) rule2818 = ReplacementRule(pattern2818, replacement2818) pattern2819 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons149, cons1419) rule2819 = ReplacementRule(pattern2819, replacement2819) pattern2820 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons149, cons1419) rule2820 = ReplacementRule(pattern2820, replacement2820) pattern2821 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons87) rule2821 = ReplacementRule(pattern2821, replacement2821) pattern2822 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons87) rule2822 = ReplacementRule(pattern2822, replacement2822) pattern2823 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons25, cons20, cons40) rule2823 = ReplacementRule(pattern2823, replacement2823) pattern2824 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons25, cons20, cons40) rule2824 = ReplacementRule(pattern2824, replacement2824) pattern2825 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons25, cons20, cons149) rule2825 = ReplacementRule(pattern2825, replacement2825) pattern2826 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons25, cons20, cons149) rule2826 = ReplacementRule(pattern2826, replacement2826) pattern2827 = Pattern(Integral((WC('g', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons25, cons21) rule2827 = ReplacementRule(pattern2827, replacement2827) pattern2828 = Pattern(Integral((WC('g', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons25, cons21) rule2828 = ReplacementRule(pattern2828, replacement2828) pattern2829 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons73, cons149, cons20, cons87) rule2829 = ReplacementRule(pattern2829, replacement2829) pattern2830 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons73, cons149, cons20, cons87) rule2830 = ReplacementRule(pattern2830, replacement2830) pattern2831 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons149, cons1419) rule2831 = ReplacementRule(pattern2831, replacement2831) pattern2832 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons73, cons149, cons1419) rule2832 = ReplacementRule(pattern2832, replacement2832) pattern2833 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons20) rule2833 = ReplacementRule(pattern2833, replacement2833) pattern2834 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons20) rule2834 = ReplacementRule(pattern2834, replacement2834) pattern2835 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(S(1)/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons21, cons87, cons40) rule2835 = ReplacementRule(pattern2835, replacement2835) pattern2836 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(S(1)/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons21, cons87, cons40) rule2836 = ReplacementRule(pattern2836, replacement2836) pattern2837 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons21, cons87, cons149) rule2837 = ReplacementRule(pattern2837, replacement2837) pattern2838 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons21, cons87, cons149) rule2838 = ReplacementRule(pattern2838, replacement2838) pattern2839 = Pattern(Integral((WC('g', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons21, cons25) rule2839 = ReplacementRule(pattern2839, replacement2839) pattern2840 = Pattern(Integral((WC('g', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons21, cons25) rule2840 = ReplacementRule(pattern2840, replacement2840) pattern2841 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1420, cons1267, cons20, cons87) rule2841 = ReplacementRule(pattern2841, replacement2841) pattern2842 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons1420, cons1267, cons20, cons87) rule2842 = ReplacementRule(pattern2842, replacement2842) pattern2843 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons72, cons1267, cons20, cons1311) rule2843 = ReplacementRule(pattern2843, replacement2843) pattern2844 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons72, cons1267, cons20, cons1311) rule2844 = ReplacementRule(pattern2844, replacement2844) pattern2845 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73) rule2845 = ReplacementRule(pattern2845, replacement2845) pattern2846 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73) rule2846 = ReplacementRule(pattern2846, replacement2846) pattern2847 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons72, cons1267) rule2847 = ReplacementRule(pattern2847, replacement2847) pattern2848 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons72, cons1267) rule2848 = ReplacementRule(pattern2848, replacement2848) pattern2849 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1267, cons1421, cons1316) rule2849 = ReplacementRule(pattern2849, replacement2849) pattern2850 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1267, cons1421, cons1316) rule2850 = ReplacementRule(pattern2850, replacement2850) pattern2851 = Pattern(Integral((c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons72, cons1267) rule2851 = ReplacementRule(pattern2851, replacement2851) pattern2852 = Pattern(Integral((c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons72, cons1267) rule2852 = ReplacementRule(pattern2852, replacement2852) pattern2853 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1267, cons1422, cons1423) rule2853 = ReplacementRule(pattern2853, replacement2853) pattern2854 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1267, cons1422, cons1423) rule2854 = ReplacementRule(pattern2854, replacement2854) pattern2855 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1267, cons1323, cons685) rule2855 = ReplacementRule(pattern2855, replacement2855) pattern2856 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1267, cons1323, cons685) rule2856 = ReplacementRule(pattern2856, replacement2856) pattern2857 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1267, cons1325, cons74, cons1424) rule2857 = ReplacementRule(pattern2857, replacement2857) pattern2858 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1267, cons1325, cons74, cons1424) rule2858 = ReplacementRule(pattern2858, replacement2858) pattern2859 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325, cons95, cons1425, cons91, cons517, cons1330) rule2859 = ReplacementRule(pattern2859, replacement2859) pattern2860 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325, cons95, cons1425, cons91, cons517, cons1330) rule2860 = ReplacementRule(pattern2860, replacement2860) pattern2861 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons33, cons1425, cons348, cons517, cons1330) rule2861 = ReplacementRule(pattern2861, replacement2861) pattern2862 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons33, cons1425, cons348, cons517, cons1330) rule2862 = ReplacementRule(pattern2862, replacement2862) pattern2863 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325, cons95, cons1322, cons90, cons517, cons1330) rule2863 = ReplacementRule(pattern2863, replacement2863) pattern2864 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325, cons95, cons1322, cons90, cons517, cons1330) rule2864 = ReplacementRule(pattern2864, replacement2864) pattern2865 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons33, cons1322, cons1329, cons517, cons1330) rule2865 = ReplacementRule(pattern2865, replacement2865) pattern2866 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons33, cons1322, cons1329, cons517, cons1330) rule2866 = ReplacementRule(pattern2866, replacement2866) pattern2867 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons1426) rule2867 = ReplacementRule(pattern2867, replacement2867) pattern2868 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons1426) rule2868 = ReplacementRule(pattern2868, replacement2868) pattern2869 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325, cons89, cons91) rule2869 = ReplacementRule(pattern2869, replacement2869) pattern2870 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325, cons89, cons91) rule2870 = ReplacementRule(pattern2870, replacement2870) pattern2871 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons348) rule2871 = ReplacementRule(pattern2871, replacement2871) pattern2872 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1267, cons1325, cons348) rule2872 = ReplacementRule(pattern2872, replacement2872) pattern2873 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325) rule2873 = ReplacementRule(pattern2873, replacement2873) pattern2874 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325) rule2874 = ReplacementRule(pattern2874, replacement2874) pattern2875 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1267, cons1325, cons89, cons90, cons1427) rule2875 = ReplacementRule(pattern2875, replacement2875) pattern2876 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1267, cons1325, cons89, cons90, cons1427) rule2876 = ReplacementRule(pattern2876, replacement2876) pattern2877 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1267, cons1325, cons89, cons91, cons1427) rule2877 = ReplacementRule(pattern2877, replacement2877) pattern2878 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1267, cons1325, cons89, cons91, cons1427) rule2878 = ReplacementRule(pattern2878, replacement2878) pattern2879 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325) rule2879 = ReplacementRule(pattern2879, replacement2879) pattern2880 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1267, cons1325) rule2880 = ReplacementRule(pattern2880, replacement2880) pattern2881 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1267, cons1325, cons1316) rule2881 = ReplacementRule(pattern2881, replacement2881) pattern2882 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1267, cons1325, cons1316) rule2882 = ReplacementRule(pattern2882, replacement2882) pattern2883 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1267, cons1325, cons1428) rule2883 = ReplacementRule(pattern2883, replacement2883) pattern2884 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1267, cons1325, cons1428) rule2884 = ReplacementRule(pattern2884, replacement2884) pattern2885 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons95, cons168, cons91) rule2885 = ReplacementRule(pattern2885, replacement2885) pattern2886 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons95, cons168, cons91) rule2886 = ReplacementRule(pattern2886, replacement2886) pattern2887 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1269, cons1325, cons33, cons168, cons1429) rule2887 = ReplacementRule(pattern2887, replacement2887) pattern2888 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1269, cons1325, cons33, cons168, cons1429) rule2888 = ReplacementRule(pattern2888, replacement2888) pattern2889 = Pattern(Integral(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1325) rule2889 = ReplacementRule(pattern2889, replacement2889) pattern2890 = Pattern(Integral(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1325) rule2890 = ReplacementRule(pattern2890, replacement2890) pattern2891 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325) rule2891 = ReplacementRule(pattern2891, replacement2891) pattern2892 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325) rule2892 = ReplacementRule(pattern2892, replacement2892) pattern2893 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1269) rule2893 = ReplacementRule(pattern2893, replacement2893) pattern2894 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons1269) rule2894 = ReplacementRule(pattern2894, replacement2894) pattern2895 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1325, cons1430, cons1344) rule2895 = ReplacementRule(pattern2895, replacement2895) pattern2896 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1325, cons1430, cons1344) rule2896 = ReplacementRule(pattern2896, replacement2896) pattern2897 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1325, cons1430, cons1346) rule2897 = ReplacementRule(pattern2897, replacement2897) pattern2898 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons1325, cons1430, cons1346) rule2898 = ReplacementRule(pattern2898, replacement2898) pattern2899 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1430, cons1347) rule2899 = ReplacementRule(pattern2899, replacement2899) pattern2900 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1430, cons1347) rule2900 = ReplacementRule(pattern2900, replacement2900) pattern2901 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1430, cons1348) rule2901 = ReplacementRule(pattern2901, replacement2901) pattern2902 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1430, cons1348) rule2902 = ReplacementRule(pattern2902, replacement2902) pattern2903 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1431) rule2903 = ReplacementRule(pattern2903, replacement2903) pattern2904 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons1431) rule2904 = ReplacementRule(pattern2904, replacement2904) pattern2905 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons95, cons96, cons90) rule2905 = ReplacementRule(pattern2905, replacement2905) pattern2906 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons95, cons96, cons90) rule2906 = ReplacementRule(pattern2906, replacement2906) pattern2907 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1339) rule2907 = ReplacementRule(pattern2907, replacement2907) pattern2908 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1339) rule2908 = ReplacementRule(pattern2908, replacement2908) pattern2909 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325) rule2909 = ReplacementRule(pattern2909, replacement2909) pattern2910 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325) rule2910 = ReplacementRule(pattern2910, replacement2910) pattern2911 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1269, cons1325) rule2911 = ReplacementRule(pattern2911, replacement2911) pattern2912 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1269, cons1325) rule2912 = ReplacementRule(pattern2912, replacement2912) pattern2913 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons89, cons1432) rule2913 = ReplacementRule(pattern2913, replacement2913) pattern2914 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325, cons89, cons1432) rule2914 = ReplacementRule(pattern2914, replacement2914) pattern2915 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons107, cons1413, cons1430) rule2915 = ReplacementRule(pattern2915, replacement2915) pattern2916 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons107, cons1413, cons1430) rule2916 = ReplacementRule(pattern2916, replacement2916) pattern2917 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(d_*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons29, cons36, cons37, cons107, cons1413, cons1430) rule2917 = ReplacementRule(pattern2917, replacement2917) pattern2918 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(d_*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons50, cons127, cons29, cons36, cons37, cons107, cons1413, cons1430) rule2918 = ReplacementRule(pattern2918, replacement2918) pattern2919 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325) rule2919 = ReplacementRule(pattern2919, replacement2919) pattern2920 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))/(sqrt(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1269, cons1325) rule2920 = ReplacementRule(pattern2920, replacement2920) pattern2921 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1269, cons1325) rule2921 = ReplacementRule(pattern2921, replacement2921) pattern2922 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1269, cons1325) rule2922 = ReplacementRule(pattern2922, replacement2922) pattern2923 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons5, cons72, cons1267) rule2923 = ReplacementRule(pattern2923, replacement2923) pattern2924 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons5, cons72, cons1267) rule2924 = ReplacementRule(pattern2924, replacement2924) pattern2925 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons37, cons38, cons19, cons1433) rule2925 = ReplacementRule(pattern2925, replacement2925) pattern2926 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons37, cons38, cons19, cons1433) rule2926 = ReplacementRule(pattern2926, replacement2926) pattern2927 = Pattern(Integral((A_ + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons50, cons127, cons36, cons38, cons1230) rule2927 = ReplacementRule(pattern2927, replacement2927) pattern2928 = Pattern(Integral((A_ + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons50, cons127, cons36, cons38, cons1230) rule2928 = ReplacementRule(pattern2928, replacement2928) pattern2929 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(A_ + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons1434) rule2929 = ReplacementRule(pattern2929, replacement2929) pattern2930 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(A_ + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons1434) rule2930 = ReplacementRule(pattern2930, replacement2930) pattern2931 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(A_ + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons33, cons96) rule2931 = ReplacementRule(pattern2931, replacement2931) pattern2932 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(A_ + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons33, cons96) rule2932 = ReplacementRule(pattern2932, replacement2932) pattern2933 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons274) rule2933 = ReplacementRule(pattern2933, replacement2933) pattern2934 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(A_ + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons274) rule2934 = ReplacementRule(pattern2934, replacement2934) pattern2935 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons35) rule2935 = ReplacementRule(pattern2935, replacement2935) pattern2936 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons35) rule2936 = ReplacementRule(pattern2936, replacement2936) pattern2937 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1435) rule2937 = ReplacementRule(pattern2937, replacement2937) pattern2938 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1435) rule2938 = ReplacementRule(pattern2938, replacement2938) pattern2939 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1436, cons79) rule2939 = ReplacementRule(pattern2939, replacement2939) pattern2940 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1436, cons79) rule2940 = ReplacementRule(pattern2940, replacement2940) pattern2941 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1437, cons79) rule2941 = ReplacementRule(pattern2941, replacement2941) pattern2942 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1437, cons79) rule2942 = ReplacementRule(pattern2942, replacement2942) pattern2943 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1267) rule2943 = ReplacementRule(pattern2943, replacement2943) pattern2944 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1267) rule2944 = ReplacementRule(pattern2944, replacement2944) pattern2945 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1267) rule2945 = ReplacementRule(pattern2945, replacement2945) pattern2946 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1267) rule2946 = ReplacementRule(pattern2946, replacement2946) pattern2947 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1269) rule2947 = ReplacementRule(pattern2947, replacement2947) pattern2948 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons33, cons96, cons1269) rule2948 = ReplacementRule(pattern2948, replacement2948) pattern2949 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1269) rule2949 = ReplacementRule(pattern2949, replacement2949) pattern2950 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons33, cons96, cons1269) rule2950 = ReplacementRule(pattern2950, replacement2950) pattern2951 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons274) rule2951 = ReplacementRule(pattern2951, replacement2951) pattern2952 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons274) rule2952 = ReplacementRule(pattern2952, replacement2952) pattern2953 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons274) rule2953 = ReplacementRule(pattern2953, replacement2953) pattern2954 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons274) rule2954 = ReplacementRule(pattern2954, replacement2954) pattern2955 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons5, cons21) rule2955 = ReplacementRule(pattern2955, replacement2955) pattern2956 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons5, cons21) rule2956 = ReplacementRule(pattern2956, replacement2956) pattern2957 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons5, cons21) rule2957 = ReplacementRule(pattern2957, replacement2957) pattern2958 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons50, cons127, cons36, cons38, cons19, cons5, cons21) rule2958 = ReplacementRule(pattern2958, replacement2958) pattern2959 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons33, cons96) rule2959 = ReplacementRule(pattern2959, replacement2959) pattern2960 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons33, cons96) rule2960 = ReplacementRule(pattern2960, replacement2960) pattern2961 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons33, cons96) rule2961 = ReplacementRule(pattern2961, replacement2961) pattern2962 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons33, cons96) rule2962 = ReplacementRule(pattern2962, replacement2962) pattern2963 = Pattern(Integral((c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons73, cons1269, cons274) rule2963 = ReplacementRule(pattern2963, replacement2963) pattern2964 = Pattern(Integral((c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons73, cons1269, cons274) rule2964 = ReplacementRule(pattern2964, replacement2964) pattern2965 = Pattern(Integral((c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons73, cons1269, cons274) rule2965 = ReplacementRule(pattern2965, replacement2965) pattern2966 = Pattern(Integral((c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons73, cons1269, cons274) rule2966 = ReplacementRule(pattern2966, replacement2966) pattern2967 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons72, cons1267, cons1438) rule2967 = ReplacementRule(pattern2967, replacement2967) pattern2968 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons72, cons1267, cons1438) rule2968 = ReplacementRule(pattern2968, replacement2968) pattern2969 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons72, cons1267, cons1438) rule2969 = ReplacementRule(pattern2969, replacement2969) pattern2970 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons72, cons1267, cons1438) rule2970 = ReplacementRule(pattern2970, replacement2970) pattern2971 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons72, cons1267, cons1323) rule2971 = ReplacementRule(pattern2971, replacement2971) pattern2972 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons72, cons1267, cons1323) rule2972 = ReplacementRule(pattern2972, replacement2972) pattern2973 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))/sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons72, cons1267, cons1323) rule2973 = ReplacementRule(pattern2973, replacement2973) pattern2974 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))/sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons72, cons1267, cons1323) rule2974 = ReplacementRule(pattern2974, replacement2974) pattern2975 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons72, cons1267, cons1323, cons216) rule2975 = ReplacementRule(pattern2975, replacement2975) pattern2976 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons72, cons1267, cons1323, cons216) rule2976 = ReplacementRule(pattern2976, replacement2976) pattern2977 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons72, cons1267, cons1323, cons216) rule2977 = ReplacementRule(pattern2977, replacement2977) pattern2978 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons72, cons1267, cons1323, cons216) rule2978 = ReplacementRule(pattern2978, replacement2978) pattern2979 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1267, cons1325, cons33, cons1322) rule2979 = ReplacementRule(pattern2979, replacement2979) pattern2980 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1267, cons1325, cons33, cons1322) rule2980 = ReplacementRule(pattern2980, replacement2980) pattern2981 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1267, cons1325, cons33, cons1322) rule2981 = ReplacementRule(pattern2981, replacement2981) pattern2982 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1267, cons1325, cons33, cons1322) rule2982 = ReplacementRule(pattern2982, replacement2982) pattern2983 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons73, cons1267, cons1325, cons1323, cons1439) rule2983 = ReplacementRule(pattern2983, replacement2983) pattern2984 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons73, cons1267, cons1325, cons1323, cons1439) rule2984 = ReplacementRule(pattern2984, replacement2984) pattern2985 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons73, cons1267, cons1325, cons1323, cons1439) rule2985 = ReplacementRule(pattern2985, replacement2985) pattern2986 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons73, cons1267, cons1325, cons1323, cons1439) rule2986 = ReplacementRule(pattern2986, replacement2986) pattern2987 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1267, cons1325, cons1323, cons216) rule2987 = ReplacementRule(pattern2987, replacement2987) pattern2988 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1267, cons1325, cons1323, cons216) rule2988 = ReplacementRule(pattern2988, replacement2988) pattern2989 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1267, cons1325, cons1323, cons216) rule2989 = ReplacementRule(pattern2989, replacement2989) pattern2990 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1267, cons1325, cons1323, cons216) rule2990 = ReplacementRule(pattern2990, replacement2990) pattern2991 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325, cons95, cons170, cons91) rule2991 = ReplacementRule(pattern2991, replacement2991) pattern2992 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325, cons95, cons170, cons91) rule2992 = ReplacementRule(pattern2992, replacement2992) pattern2993 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325, cons95, cons170, cons91) rule2993 = ReplacementRule(pattern2993, replacement2993) pattern2994 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325, cons95, cons170, cons91) rule2994 = ReplacementRule(pattern2994, replacement2994) pattern2995 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1269, cons1325, cons33, cons170, cons1440) rule2995 = ReplacementRule(pattern2995, replacement2995) pattern2996 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1269, cons1325, cons33, cons170, cons1440) rule2996 = ReplacementRule(pattern2996, replacement2996) pattern2997 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1269, cons1325, cons33, cons170, cons1440) rule2997 = ReplacementRule(pattern2997, replacement2997) pattern2998 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1269, cons1325, cons33, cons170, cons1440) rule2998 = ReplacementRule(pattern2998, replacement2998) pattern2999 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269) rule2999 = ReplacementRule(pattern2999, replacement2999) pattern3000 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons37, cons38, cons1269) rule3000 = ReplacementRule(pattern3000, replacement3000) pattern3001 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269) rule3001 = ReplacementRule(pattern3001, replacement3001) pattern3002 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)), x_), cons2, cons3, cons29, cons50, cons127, cons36, cons38, cons1269) rule3002 = ReplacementRule(pattern3002, replacement3002) pattern3003 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3003 = ReplacementRule(pattern3003, replacement3003) pattern3004 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3004 = ReplacementRule(pattern3004, replacement3004) pattern3005 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3005 = ReplacementRule(pattern3005, replacement3005) pattern3006 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3006 = ReplacementRule(pattern3006, replacement3006) pattern3007 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1339) rule3007 = ReplacementRule(pattern3007, replacement3007) pattern3008 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1339) rule3008 = ReplacementRule(pattern3008, replacement3008) pattern3009 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1339) rule3009 = ReplacementRule(pattern3009, replacement3009) pattern3010 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1269, cons1325, cons33, cons96, cons1339) rule3010 = ReplacementRule(pattern3010, replacement3010) pattern3011 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3011 = ReplacementRule(pattern3011, replacement3011) pattern3012 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3012 = ReplacementRule(pattern3012, replacement3012) pattern3013 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3013 = ReplacementRule(pattern3013, replacement3013) pattern3014 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3014 = ReplacementRule(pattern3014, replacement3014) pattern3015 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3015 = ReplacementRule(pattern3015, replacement3015) pattern3016 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3016 = ReplacementRule(pattern3016, replacement3016) pattern3017 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3017 = ReplacementRule(pattern3017, replacement3017) pattern3018 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3018 = ReplacementRule(pattern3018, replacement3018) pattern3019 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3019 = ReplacementRule(pattern3019, replacement3019) pattern3020 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1269, cons1325) rule3020 = ReplacementRule(pattern3020, replacement3020) pattern3021 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(c_ + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3021 = ReplacementRule(pattern3021, replacement3021) pattern3022 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(sqrt(c_ + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1269, cons1325) rule3022 = ReplacementRule(pattern3022, replacement3022) pattern3023 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1269, cons1325) rule3023 = ReplacementRule(pattern3023, replacement3023) pattern3024 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1269, cons1325) rule3024 = ReplacementRule(pattern3024, replacement3024) pattern3025 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1269, cons1325) rule3025 = ReplacementRule(pattern3025, replacement3025) pattern3026 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1269, cons1325) rule3026 = ReplacementRule(pattern3026, replacement3026) pattern3027 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons21) rule3027 = ReplacementRule(pattern3027, replacement3027) pattern3028 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons5, cons21) rule3028 = ReplacementRule(pattern3028, replacement3028) pattern3029 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons5, cons21) rule3029 = ReplacementRule(pattern3029, replacement3029) pattern3030 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**p_)**m_*(WC('A', S(0)) + WC('C', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons5, cons21) rule3030 = ReplacementRule(pattern3030, replacement3030) pattern3031 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1441) rule3031 = ReplacementRule(pattern3031, replacement3031) pattern3032 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1442, cons523) rule3032 = ReplacementRule(pattern3032, replacement3032) pattern3033 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1442, cons1443, cons89, cons167) rule3033 = ReplacementRule(pattern3033, replacement3033) pattern3034 = Pattern(Integral(S(1)/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442) rule3034 = ReplacementRule(pattern3034, replacement3034) pattern3035 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**(S(-2)), x_), cons2, cons3, cons8, cons29, cons1442) rule3035 = ReplacementRule(pattern3035, replacement3035) pattern3036 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1442, cons89, cons91, cons1444) rule3036 = ReplacementRule(pattern3036, replacement3036) pattern3037 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1445, cons1446) rule3037 = ReplacementRule(pattern3037, replacement3037) pattern3038 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1445, cons1447) rule3038 = ReplacementRule(pattern3038, replacement3038) pattern3039 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1257, cons1441, cons89, cons167) rule3039 = ReplacementRule(pattern3039, replacement3039) pattern3040 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1257, cons1441, cons89, cons167) rule3040 = ReplacementRule(pattern3040, replacement3040) pattern3041 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1257, cons1441, cons89, cons465) rule3041 = ReplacementRule(pattern3041, replacement3041) pattern3042 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1257, cons1441, cons89, cons465) rule3042 = ReplacementRule(pattern3042, replacement3042) pattern3043 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1257, cons1441, cons25) rule3043 = ReplacementRule(pattern3043, replacement3043) pattern3044 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons1257, cons1441, cons25) rule3044 = ReplacementRule(pattern3044, replacement3044) pattern3045 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1257, cons87, cons1442) rule3045 = ReplacementRule(pattern3045, replacement3045) pattern3046 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1257, cons87, cons1442) rule3046 = ReplacementRule(pattern3046, replacement3046) pattern3047 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons87, cons1448, cons1154, cons1449) rule3047 = ReplacementRule(pattern3047, replacement3047) pattern3048 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons87, cons1448, cons1154, cons1449) rule3048 = ReplacementRule(pattern3048, replacement3048) pattern3049 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons20, cons150) rule3049 = ReplacementRule(pattern3049, replacement3049) pattern3050 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('n', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons20, cons150) rule3050 = ReplacementRule(pattern3050, replacement3050) pattern3051 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons1441, cons198) rule3051 = ReplacementRule(pattern3051, replacement3051) pattern3052 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons1441, cons198) rule3052 = ReplacementRule(pattern3052, replacement3052) pattern3053 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_/sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1442, cons89, cons91) rule3053 = ReplacementRule(pattern3053, replacement3053) pattern3054 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_/cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1442, cons89, cons91) rule3054 = ReplacementRule(pattern3054, replacement3054) pattern3055 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1442, cons95, cons167, cons96) rule3055 = ReplacementRule(pattern3055, replacement3055) pattern3056 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1442, cons95, cons167, cons96) rule3056 = ReplacementRule(pattern3056, replacement3056) pattern3057 = Pattern(Integral(sin(x_*WC('d', S(1)) + WC('c', S(0)))/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442) rule3057 = ReplacementRule(pattern3057, replacement3057) pattern3058 = Pattern(Integral(cos(x_*WC('d', S(1)) + WC('c', S(0)))/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442) rule3058 = ReplacementRule(pattern3058, replacement3058) pattern3059 = Pattern(Integral(sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442, cons33, cons168) rule3059 = ReplacementRule(pattern3059, replacement3059) pattern3060 = Pattern(Integral(cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442, cons33, cons168) rule3060 = ReplacementRule(pattern3060, replacement3060) pattern3061 = Pattern(Integral(S(1)/((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442) rule3061 = ReplacementRule(pattern3061, replacement3061) pattern3062 = Pattern(Integral(S(1)/((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))*cos(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442) rule3062 = ReplacementRule(pattern3062, replacement3062) pattern3063 = Pattern(Integral(sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442, cons33, cons96) rule3063 = ReplacementRule(pattern3063, replacement3063) pattern3064 = Pattern(Integral(cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442, cons33, cons96) rule3064 = ReplacementRule(pattern3064, replacement3064) pattern3065 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1442, cons95, cons91, cons96) rule3065 = ReplacementRule(pattern3065, replacement3065) pattern3066 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1442, cons95, cons91, cons96) rule3066 = ReplacementRule(pattern3066, replacement3066) pattern3067 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons130) rule3067 = ReplacementRule(pattern3067, replacement3067) pattern3068 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons1441, cons65) rule3068 = ReplacementRule(pattern3068, replacement3068) pattern3069 = Pattern(Integral(sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442, cons152, cons170, cons90) rule3069 = ReplacementRule(pattern3069, replacement3069) pattern3070 = Pattern(Integral(sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons152) rule3070 = ReplacementRule(pattern3070, replacement3070) pattern3071 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))) + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1442, cons377, cons170, cons90, cons324) rule3071 = ReplacementRule(pattern3071, replacement3071) pattern3072 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1450) rule3072 = ReplacementRule(pattern3072, replacement3072) pattern3073 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1450, cons89, cons90) rule3073 = ReplacementRule(pattern3073, replacement3073) pattern3074 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1450) rule3074 = ReplacementRule(pattern3074, replacement3074) pattern3075 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1450) rule3075 = ReplacementRule(pattern3075, replacement3075) pattern3076 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1450, cons89, cons91) rule3076 = ReplacementRule(pattern3076, replacement3076) pattern3077 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1451) rule3077 = ReplacementRule(pattern3077, replacement3077) pattern3078 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1452, cons1453) rule3078 = ReplacementRule(pattern3078, replacement3078) pattern3079 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1454, cons1452, cons1455) rule3079 = ReplacementRule(pattern3079, replacement3079) pattern3080 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1454, cons89, cons167) rule3080 = ReplacementRule(pattern3080, replacement3080) pattern3081 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1456) rule3081 = ReplacementRule(pattern3081, With3081) pattern3082 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons78) rule3082 = ReplacementRule(pattern3082, With3082) pattern3083 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1457, cons1458) rule3083 = ReplacementRule(pattern3083, With3083) pattern3084 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1454) rule3084 = ReplacementRule(pattern3084, With3084) pattern3085 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1451) rule3085 = ReplacementRule(pattern3085, replacement3085) pattern3086 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1452, cons1453) rule3086 = ReplacementRule(pattern3086, replacement3086) pattern3087 = Pattern(Integral(S(1)/sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1454, cons1452, cons1455) rule3087 = ReplacementRule(pattern3087, replacement3087) pattern3088 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**(S(-3)/2), x_), cons2, cons3, cons8, cons29, cons50, cons1454) rule3088 = ReplacementRule(pattern3088, replacement3088) pattern3089 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons1454, cons89, cons91, cons1459) rule3089 = ReplacementRule(pattern3089, replacement3089) pattern3090 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1451) rule3090 = ReplacementRule(pattern3090, replacement3090) pattern3091 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons1451) rule3091 = ReplacementRule(pattern3091, replacement3091) pattern3092 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))/(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons1451) rule3092 = ReplacementRule(pattern3092, replacement3092) pattern3093 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1452, cons1460) rule3093 = ReplacementRule(pattern3093, replacement3093) pattern3094 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons1452, cons1461) rule3094 = ReplacementRule(pattern3094, replacement3094) pattern3095 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons1452, cons1462) rule3095 = ReplacementRule(pattern3095, replacement3095) pattern3096 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1452, cons1463) rule3096 = ReplacementRule(pattern3096, replacement3096) pattern3097 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons1452, cons1464) rule3097 = ReplacementRule(pattern3097, replacement3097) pattern3098 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons1452, cons1465) rule3098 = ReplacementRule(pattern3098, replacement3098) pattern3099 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons4, cons586, cons1450, cons1466) rule3099 = ReplacementRule(pattern3099, replacement3099) pattern3100 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons4, cons586, cons1450, cons1467) rule3100 = ReplacementRule(pattern3100, replacement3100) pattern3101 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons4, cons586, cons1450, cons1468) rule3101 = ReplacementRule(pattern3101, replacement3101) pattern3102 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons4, cons586, cons1450, cons1469) rule3102 = ReplacementRule(pattern3102, replacement3102) pattern3103 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons4, cons586, cons1450, cons1470) rule3103 = ReplacementRule(pattern3103, replacement3103) pattern3104 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons4, cons586, cons1450, cons1471) rule3104 = ReplacementRule(pattern3104, replacement3104) pattern3105 = Pattern(Integral((WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons3, cons8, cons29, cons50, cons37, cons38, cons586, cons1452, cons1472) rule3105 = ReplacementRule(pattern3105, replacement3105) pattern3106 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons89, cons90, cons1454) rule3106 = ReplacementRule(pattern3106, replacement3106) pattern3107 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons89, cons90, cons1454) rule3107 = ReplacementRule(pattern3107, replacement3107) pattern3108 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons89, cons90, cons1454) rule3108 = ReplacementRule(pattern3108, replacement3108) pattern3109 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/sqrt(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1473, cons1247) rule3109 = ReplacementRule(pattern3109, replacement3109) pattern3110 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1454, cons1474) rule3110 = ReplacementRule(pattern3110, replacement3110) pattern3111 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons1454, cons1475) rule3111 = ReplacementRule(pattern3111, replacement3111) pattern3112 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons1454, cons1476) rule3112 = ReplacementRule(pattern3112, replacement3112) pattern3113 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons1454, cons1477) rule3113 = ReplacementRule(pattern3113, replacement3113) pattern3114 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons1454, cons1478) rule3114 = ReplacementRule(pattern3114, replacement3114) pattern3115 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons1454, cons1479) rule3115 = ReplacementRule(pattern3115, replacement3115) pattern3116 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons38, cons89, cons91, cons1454, cons1444) rule3116 = ReplacementRule(pattern3116, replacement3116) pattern3117 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons38, cons89, cons91, cons1454, cons1444) rule3117 = ReplacementRule(pattern3117, replacement3117) pattern3118 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons89, cons91, cons1454, cons1444) rule3118 = ReplacementRule(pattern3118, replacement3118) pattern3119 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule3119 = ReplacementRule(pattern3119, replacement3119) pattern3120 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons1045) rule3120 = ReplacementRule(pattern3120, replacement3120) pattern3121 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons87) rule3121 = ReplacementRule(pattern3121, replacement3121) pattern3122 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons87) rule3122 = ReplacementRule(pattern3122, replacement3122) pattern3123 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**n_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons25) rule3123 = ReplacementRule(pattern3123, replacement3123) pattern3124 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**n_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons25) rule3124 = ReplacementRule(pattern3124, replacement3124) pattern3125 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1257, cons87) rule3125 = ReplacementRule(pattern3125, replacement3125) pattern3126 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1257, cons87) rule3126 = ReplacementRule(pattern3126, replacement3126) pattern3127 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_*(S(1)/cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1257, cons25) rule3127 = ReplacementRule(pattern3127, replacement3127) pattern3128 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_*(S(1)/sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons1257, cons25) rule3128 = ReplacementRule(pattern3128, replacement3128) pattern3129 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons3, cons8, cons29, cons13, cons148) rule3129 = ReplacementRule(pattern3129, replacement3129) pattern3130 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons3, cons8, cons29, cons13, cons148) rule3130 = ReplacementRule(pattern3130, replacement3130) pattern3131 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons3, cons8, cons29, cons13, cons139) rule3131 = ReplacementRule(pattern3131, replacement3131) pattern3132 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons3, cons8, cons29, cons13, cons139) rule3132 = ReplacementRule(pattern3132, replacement3132) pattern3133 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons1456, cons40) rule3133 = ReplacementRule(pattern3133, replacement3133) pattern3134 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons1456, cons40) rule3134 = ReplacementRule(pattern3134, replacement3134) pattern3135 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1456, cons149) rule3135 = ReplacementRule(pattern3135, replacement3135) pattern3136 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1456, cons149) rule3136 = ReplacementRule(pattern3136, replacement3136) pattern3137 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons40) rule3137 = ReplacementRule(pattern3137, With3137) pattern3138 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons40) rule3138 = ReplacementRule(pattern3138, With3138) pattern3139 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1480, cons149) rule3139 = ReplacementRule(pattern3139, replacement3139) pattern3140 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1480, cons149) rule3140 = ReplacementRule(pattern3140, replacement3140) pattern3141 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_, x_), cons2, cons3, cons8, cons29, cons87, cons130) rule3141 = ReplacementRule(pattern3141, replacement3141) pattern3142 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_, x_), cons2, cons3, cons8, cons29, cons87, cons130) rule3142 = ReplacementRule(pattern3142, replacement3142) pattern3143 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_, x_), cons2, cons3, cons8, cons29, cons1481, cons40, cons139) rule3143 = ReplacementRule(pattern3143, With3143) pattern3144 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_, x_), cons2, cons3, cons8, cons29, cons1481, cons40, cons139) rule3144 = ReplacementRule(pattern3144, With3144) pattern3145 = Pattern(Integral(u_*(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons1456, cons40) rule3145 = ReplacementRule(pattern3145, replacement3145) pattern3146 = Pattern(Integral(u_*(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons1456, cons40) rule3146 = ReplacementRule(pattern3146, replacement3146) pattern3147 = Pattern(Integral(u_*(a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1456, cons149) rule3147 = ReplacementRule(pattern3147, replacement3147) pattern3148 = Pattern(Integral(u_*(a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**S(2))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons1456, cons149) rule3148 = ReplacementRule(pattern3148, replacement3148) pattern3149 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1481, cons1482, cons40) rule3149 = ReplacementRule(pattern3149, With3149) pattern3150 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1481, cons1482, cons40) rule3150 = ReplacementRule(pattern3150, With3150) pattern3151 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1481, cons1483) rule3151 = ReplacementRule(pattern3151, With3151) pattern3152 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1481, cons1483) rule3152 = ReplacementRule(pattern3152, With3152) pattern3153 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons377) rule3153 = ReplacementRule(pattern3153, replacement3153) pattern3154 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons377) rule3154 = ReplacementRule(pattern3154, replacement3154) pattern3155 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1482, cons1481, cons40) rule3155 = ReplacementRule(pattern3155, With3155) pattern3156 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1482, cons1481, cons40) rule3156 = ReplacementRule(pattern3156, With3156) pattern3157 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1482, cons1484, cons40, cons170) rule3157 = ReplacementRule(pattern3157, replacement3157) pattern3158 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1482, cons1484, cons40, cons170) rule3158 = ReplacementRule(pattern3158, replacement3158) pattern3159 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1482, cons1484, cons40, cons269, cons139) rule3159 = ReplacementRule(pattern3159, replacement3159) pattern3160 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons1482, cons1484, cons40, cons269, cons139) rule3160 = ReplacementRule(pattern3160, replacement3160) pattern3161 = Pattern(Integral((a_ + (WC('e', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1483) rule3161 = ReplacementRule(pattern3161, With3161) pattern3162 = Pattern(Integral((a_ + (WC('e', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1483) rule3162 = ReplacementRule(pattern3162, With3162) pattern3163 = Pattern(Integral((a_ + (WC('e', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1483, cons248) rule3163 = ReplacementRule(pattern3163, With3163) pattern3164 = Pattern(Integral((a_ + (WC('e', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons1483, cons248) rule3164 = ReplacementRule(pattern3164, With3164) pattern3165 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**WC('p', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons19, cons1485, cons1481, cons40) rule3165 = ReplacementRule(pattern3165, With3165) pattern3166 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**WC('p', S(1))*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons19, cons1485, cons1481, cons40) rule3166 = ReplacementRule(pattern3166, With3166) pattern3167 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**WC('p', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons1485, cons1481, cons149) rule3167 = ReplacementRule(pattern3167, With3167) pattern3168 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**WC('p', S(1))*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons1485, cons1481, cons149) rule3168 = ReplacementRule(pattern3168, With3168) pattern3169 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**p_ + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**q_)**n_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons1482, cons1486, cons1487, cons87, cons1488) rule3169 = ReplacementRule(pattern3169, With3169) pattern3170 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**p_ + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**q_)**n_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons1482, cons1486, cons1487, cons87, cons1488) rule3170 = ReplacementRule(pattern3170, With3170) pattern3171 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**p_ + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**q_)**n_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons1482, cons1486, cons1487, cons87, cons1489) rule3171 = ReplacementRule(pattern3171, With3171) pattern3172 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**p_ + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**q_)**n_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons1482, cons1486, cons1487, cons87, cons1489) rule3172 = ReplacementRule(pattern3172, With3172) pattern3173 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons40) rule3173 = ReplacementRule(pattern3173, replacement3173) pattern3174 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons40) rule3174 = ReplacementRule(pattern3174, replacement3174) pattern3175 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons48, cons47, cons149) rule3175 = ReplacementRule(pattern3175, replacement3175) pattern3176 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons48, cons47, cons149) rule3176 = ReplacementRule(pattern3176, replacement3176) pattern3177 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228) rule3177 = ReplacementRule(pattern3177, With3177) pattern3178 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228) rule3178 = ReplacementRule(pattern3178, With3178) pattern3179 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule3179 = ReplacementRule(pattern3179, replacement3179) pattern3180 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule3180 = ReplacementRule(pattern3180, replacement3180) pattern3181 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule3181 = ReplacementRule(pattern3181, replacement3181) pattern3182 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule3182 = ReplacementRule(pattern3182, replacement3182) pattern3183 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**p_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons1481, cons40) rule3183 = ReplacementRule(pattern3183, With3183) pattern3184 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**p_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons1481, cons40) rule3184 = ReplacementRule(pattern3184, With3184) pattern3185 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons228, cons377) rule3185 = ReplacementRule(pattern3185, replacement3185) pattern3186 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons228, cons377) rule3186 = ReplacementRule(pattern3186, replacement3186) pattern3187 = Pattern(Integral(((WC('f', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons48, cons1483) rule3187 = ReplacementRule(pattern3187, With3187) pattern3188 = Pattern(Integral(((WC('f', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons48, cons1483) rule3188 = ReplacementRule(pattern3188, With3188) pattern3189 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons1485, cons47, cons40) rule3189 = ReplacementRule(pattern3189, replacement3189) pattern3190 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons1485, cons47, cons40) rule3190 = ReplacementRule(pattern3190, replacement3190) pattern3191 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons1485, cons47, cons149) rule3191 = ReplacementRule(pattern3191, replacement3191) pattern3192 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons1485, cons47, cons149) rule3192 = ReplacementRule(pattern3192, replacement3192) pattern3193 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons1481, cons40) rule3193 = ReplacementRule(pattern3193, With3193) pattern3194 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons1481, cons40) rule3194 = ReplacementRule(pattern3194, With3194) pattern3195 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons378) rule3195 = ReplacementRule(pattern3195, replacement3195) pattern3196 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons378) rule3196 = ReplacementRule(pattern3196, replacement3196) pattern3197 = Pattern(Integral((a_ + (WC('f', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + (WC('f', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1483, cons248) rule3197 = ReplacementRule(pattern3197, With3197) pattern3198 = Pattern(Integral((a_ + (WC('f', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + (WC('f', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1483, cons248) rule3198 = ReplacementRule(pattern3198, With3198) pattern3199 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons1485, cons47, cons40) rule3199 = ReplacementRule(pattern3199, replacement3199) pattern3200 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons1485, cons47, cons40) rule3200 = ReplacementRule(pattern3200, replacement3200) pattern3201 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*tan(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons1485, cons47, cons149) rule3201 = ReplacementRule(pattern3201, replacement3201) pattern3202 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons1485, cons47, cons149) rule3202 = ReplacementRule(pattern3202, replacement3202) pattern3203 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons48, cons1485, cons228, cons1481, cons40) rule3203 = ReplacementRule(pattern3203, With3203) pattern3204 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons48, cons1485, cons228, cons1481, cons40) rule3204 = ReplacementRule(pattern3204, With3204) pattern3205 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons378) rule3205 = ReplacementRule(pattern3205, replacement3205) pattern3206 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons378) rule3206 = ReplacementRule(pattern3206, replacement3206) pattern3207 = Pattern(Integral((a_ + (WC('f', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + (WC('f', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1483, cons248) rule3207 = ReplacementRule(pattern3207, With3207) pattern3208 = Pattern(Integral((a_ + (WC('f', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + (WC('f', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons1483, cons248) rule3208 = ReplacementRule(pattern3208, With3208) pattern3209 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons1485, cons47, cons40) rule3209 = ReplacementRule(pattern3209, replacement3209) pattern3210 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons1485, cons47, cons40) rule3210 = ReplacementRule(pattern3210, replacement3210) pattern3211 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons1485, cons47, cons149) rule3211 = ReplacementRule(pattern3211, replacement3211) pattern3212 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*tan(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons1485, cons47, cons149) rule3212 = ReplacementRule(pattern3212, replacement3212) pattern3213 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons48, cons1481, cons40) rule3213 = ReplacementRule(pattern3213, With3213) pattern3214 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons48, cons1481, cons40) rule3214 = ReplacementRule(pattern3214, With3214) pattern3215 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons378) rule3215 = ReplacementRule(pattern3215, replacement3215) pattern3216 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1482, cons228, cons378) rule3216 = ReplacementRule(pattern3216, replacement3216) pattern3217 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons87) rule3217 = ReplacementRule(pattern3217, replacement3217) pattern3218 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons87) rule3218 = ReplacementRule(pattern3218, replacement3218) pattern3219 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons25) rule3219 = ReplacementRule(pattern3219, replacement3219) pattern3220 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons25) rule3220 = ReplacementRule(pattern3220, replacement3220) pattern3221 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228) rule3221 = ReplacementRule(pattern3221, With3221) pattern3222 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228) rule3222 = ReplacementRule(pattern3222, With3222) pattern3223 = Pattern(Integral((A_ + WC('B', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228, cons87) rule3223 = ReplacementRule(pattern3223, replacement3223) pattern3224 = Pattern(Integral((A_ + WC('B', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228, cons87) rule3224 = ReplacementRule(pattern3224, replacement3224) pattern3225 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons170) rule3225 = ReplacementRule(pattern3225, replacement3225) pattern3226 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons170) rule3226 = ReplacementRule(pattern3226, replacement3226) pattern3227 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons96) rule3227 = ReplacementRule(pattern3227, replacement3227) pattern3228 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons33, cons96) rule3228 = ReplacementRule(pattern3228, replacement3228) pattern3229 = Pattern(Integral(sin(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons1118) rule3229 = ReplacementRule(pattern3229, replacement3229) pattern3230 = Pattern(Integral(cos(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons1118) rule3230 = ReplacementRule(pattern3230, replacement3230) pattern3231 = Pattern(Integral(sin(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons178) rule3231 = ReplacementRule(pattern3231, replacement3231) pattern3232 = Pattern(Integral(cos(x_*WC('f', S(1)) + WC('e', S(0)))/(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons178) rule3232 = ReplacementRule(pattern3232, replacement3232) pattern3233 = Pattern(Integral(sin(x_*WC('f', S(1)) + WC('e', S(0)))/sqrt(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons1118) rule3233 = ReplacementRule(pattern3233, replacement3233) pattern3234 = Pattern(Integral(cos(x_*WC('f', S(1)) + WC('e', S(0)))/sqrt(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons1118) rule3234 = ReplacementRule(pattern3234, replacement3234) pattern3235 = Pattern(Integral(sin(x_*WC('f', S(1)) + WC('e', S(0)))/sqrt(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons178) rule3235 = ReplacementRule(pattern3235, replacement3235) pattern3236 = Pattern(Integral(cos(x_*WC('f', S(1)) + WC('e', S(0)))/sqrt(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons127, cons178) rule3236 = ReplacementRule(pattern3236, replacement3236) pattern3237 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons19, cons1490) rule3237 = ReplacementRule(pattern3237, replacement3237) pattern3238 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons19, cons1490) rule3238 = ReplacementRule(pattern3238, replacement3238) pattern3239 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons167) rule3239 = ReplacementRule(pattern3239, replacement3239) pattern3240 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons167) rule3240 = ReplacementRule(pattern3240, replacement3240) pattern3241 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons168) rule3241 = ReplacementRule(pattern3241, replacement3241) pattern3242 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons168) rule3242 = ReplacementRule(pattern3242, replacement3242) pattern3243 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons1491) rule3243 = ReplacementRule(pattern3243, replacement3243) pattern3244 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons1491) rule3244 = ReplacementRule(pattern3244, replacement3244) pattern3245 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons33, cons247) rule3245 = ReplacementRule(pattern3245, replacement3245) pattern3246 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**n_, x_), cons8, cons29, cons50, cons127, cons19, cons87, cons167, cons33, cons247) rule3246 = ReplacementRule(pattern3246, replacement3246) pattern3247 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons249) rule3247 = ReplacementRule(pattern3247, replacement3247) pattern3248 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons249) rule3248 = ReplacementRule(pattern3248, replacement3248) pattern3249 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons91, cons1444) rule3249 = ReplacementRule(pattern3249, replacement3249) pattern3250 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons3, cons8, cons29, cons50, cons127, cons89, cons91, cons1444) rule3250 = ReplacementRule(pattern3250, replacement3250) pattern3251 = Pattern(Integral((WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons1444, cons168) rule3251 = ReplacementRule(pattern3251, replacement3251) pattern3252 = Pattern(Integral((WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons1444, cons168) rule3252 = ReplacementRule(pattern3252, replacement3252) pattern3253 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons150, cons1492) rule3253 = ReplacementRule(pattern3253, replacement3253) pattern3254 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons150, cons1492) rule3254 = ReplacementRule(pattern3254, replacement3254) pattern3255 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1267, cons87) rule3255 = ReplacementRule(pattern3255, replacement3255) pattern3256 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1267, cons810, cons1493) rule3256 = ReplacementRule(pattern3256, replacement3256) pattern3257 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1494, cons87) rule3257 = ReplacementRule(pattern3257, replacement3257) pattern3258 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1456, cons87) rule3258 = ReplacementRule(pattern3258, replacement3258) pattern3259 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1494, cons810, cons1493) rule3259 = ReplacementRule(pattern3259, replacement3259) pattern3260 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1456, cons810, cons1493) rule3260 = ReplacementRule(pattern3260, replacement3260) pattern3261 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule3261 = ReplacementRule(pattern3261, replacement3261) pattern3262 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule3262 = ReplacementRule(pattern3262, replacement3262) pattern3263 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule3263 = ReplacementRule(pattern3263, replacement3263) pattern3264 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons64) rule3264 = ReplacementRule(pattern3264, replacement3264) pattern3265 = Pattern(Integral((a_ + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons1495, cons64) rule3265 = ReplacementRule(pattern3265, replacement3265) pattern3266 = Pattern(Integral((a_ + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1269, cons1495, cons64) rule3266 = ReplacementRule(pattern3266, replacement3266) pattern3267 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule3267 = ReplacementRule(pattern3267, replacement3267) pattern3268 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule3268 = ReplacementRule(pattern3268, replacement3268) pattern3269 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule3269 = ReplacementRule(pattern3269, replacement3269) pattern3270 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule3270 = ReplacementRule(pattern3270, replacement3270) pattern3271 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons130) rule3271 = ReplacementRule(pattern3271, replacement3271) pattern3272 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons130) rule3272 = ReplacementRule(pattern3272, replacement3272) pattern3273 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons139, cons746) rule3273 = ReplacementRule(pattern3273, replacement3273) pattern3274 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons139, cons746) rule3274 = ReplacementRule(pattern3274, replacement3274) pattern3275 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons150, cons1496) rule3275 = ReplacementRule(pattern3275, replacement3275) pattern3276 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons150, cons1496) rule3276 = ReplacementRule(pattern3276, replacement3276) pattern3277 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons198) rule3277 = ReplacementRule(pattern3277, replacement3277) pattern3278 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons198) rule3278 = ReplacementRule(pattern3278, replacement3278) pattern3279 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule3279 = ReplacementRule(pattern3279, replacement3279) pattern3280 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule3280 = ReplacementRule(pattern3280, replacement3280) pattern3281 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule3281 = ReplacementRule(pattern3281, replacement3281) pattern3282 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule3282 = ReplacementRule(pattern3282, replacement3282) pattern3283 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons55, cons13, cons139, cons598) rule3283 = ReplacementRule(pattern3283, replacement3283) pattern3284 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons55, cons13, cons139, cons598) rule3284 = ReplacementRule(pattern3284, replacement3284) pattern3285 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons33, cons139, cons1498) rule3285 = ReplacementRule(pattern3285, replacement3285) pattern3286 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons40, cons150, cons33, cons139, cons1498) rule3286 = ReplacementRule(pattern3286, replacement3286) pattern3287 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons20, cons150, cons1496) rule3287 = ReplacementRule(pattern3287, replacement3287) pattern3288 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons65, cons20, cons150, cons1496) rule3288 = ReplacementRule(pattern3288, replacement3288) pattern3289 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons65, cons198) rule3289 = ReplacementRule(pattern3289, replacement3289) pattern3290 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons19, cons65, cons198) rule3290 = ReplacementRule(pattern3290, replacement3290) pattern3291 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule3291 = ReplacementRule(pattern3291, replacement3291) pattern3292 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule3292 = ReplacementRule(pattern3292, replacement3292) pattern3293 = Pattern(Integral(sin(x_**S(2)*WC('d', S(1))), x_), cons29, cons29) rule3293 = ReplacementRule(pattern3293, replacement3293) pattern3294 = Pattern(Integral(cos(x_**S(2)*WC('d', S(1))), x_), cons29, cons29) rule3294 = ReplacementRule(pattern3294, replacement3294) pattern3295 = Pattern(Integral(sin(c_ + x_**S(2)*WC('d', S(1))), x_), cons8, cons29, cons1263) rule3295 = ReplacementRule(pattern3295, replacement3295) pattern3296 = Pattern(Integral(cos(c_ + x_**S(2)*WC('d', S(1))), x_), cons8, cons29, cons1263) rule3296 = ReplacementRule(pattern3296, replacement3296) pattern3297 = Pattern(Integral(sin(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons87, cons746) rule3297 = ReplacementRule(pattern3297, replacement3297) pattern3298 = Pattern(Integral(cos(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons87, cons746) rule3298 = ReplacementRule(pattern3298, replacement3298) pattern3299 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons378, cons167, cons148) rule3299 = ReplacementRule(pattern3299, replacement3299) pattern3300 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons378, cons167, cons148) rule3300 = ReplacementRule(pattern3300, replacement3300) pattern3301 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198) rule3301 = ReplacementRule(pattern3301, replacement3301) pattern3302 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198) rule3302 = ReplacementRule(pattern3302, replacement3302) pattern3303 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons491) rule3303 = ReplacementRule(pattern3303, With3303) pattern3304 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons491) rule3304 = ReplacementRule(pattern3304, With3304) pattern3305 = Pattern(Integral(sin(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons4, cons1500) rule3305 = ReplacementRule(pattern3305, replacement3305) pattern3306 = Pattern(Integral(cos(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons4, cons1500) rule3306 = ReplacementRule(pattern3306, replacement3306) pattern3307 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons130) rule3307 = ReplacementRule(pattern3307, replacement3307) pattern3308 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons130) rule3308 = ReplacementRule(pattern3308, replacement3308) pattern3309 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons40, cons70, cons71) rule3309 = ReplacementRule(pattern3309, replacement3309) pattern3310 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons40, cons70, cons71) rule3310 = ReplacementRule(pattern3310, replacement3310) pattern3311 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(u_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70) rule3311 = ReplacementRule(pattern3311, replacement3311) pattern3312 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(u_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70) rule3312 = ReplacementRule(pattern3312, replacement3312) pattern3313 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*sin(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule3313 = ReplacementRule(pattern3313, replacement3313) pattern3314 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*cos(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule3314 = ReplacementRule(pattern3314, replacement3314) pattern3315 = Pattern(Integral(sin(x_**n_*WC('d', S(1)))/x_, x_), cons29, cons4, cons1501) rule3315 = ReplacementRule(pattern3315, replacement3315) pattern3316 = Pattern(Integral(cos(x_**n_*WC('d', S(1)))/x_, x_), cons29, cons4, cons1501) rule3316 = ReplacementRule(pattern3316, replacement3316) pattern3317 = Pattern(Integral(sin(c_ + x_**n_*WC('d', S(1)))/x_, x_), cons8, cons29, cons4, cons1500) rule3317 = ReplacementRule(pattern3317, replacement3317) pattern3318 = Pattern(Integral(cos(c_ + x_**n_*WC('d', S(1)))/x_, x_), cons8, cons29, cons4, cons1500) rule3318 = ReplacementRule(pattern3318, replacement3318) pattern3319 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, CustomConstraint(With3319)) rule3319 = ReplacementRule(pattern3319, replacement3319) pattern3320 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, CustomConstraint(With3320)) rule3320 = ReplacementRule(pattern3320, replacement3320) pattern3321 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, CustomConstraint(With3321)) rule3321 = ReplacementRule(pattern3321, replacement3321) pattern3322 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, CustomConstraint(With3322)) rule3322 = ReplacementRule(pattern3322, replacement3322) pattern3323 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**n_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons4, cons1502) rule3323 = ReplacementRule(pattern3323, replacement3323) pattern3324 = Pattern(Integral(x_**WC('m', S(1))*cos(x_**n_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons4, cons1502) rule3324 = ReplacementRule(pattern3324, replacement3324) pattern3325 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons1503) rule3325 = ReplacementRule(pattern3325, replacement3325) pattern3326 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons1503) rule3326 = ReplacementRule(pattern3326, replacement3326) pattern3327 = Pattern(Integral((x_*WC('e', S(1)))**m_*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons96) rule3327 = ReplacementRule(pattern3327, replacement3327) pattern3328 = Pattern(Integral((x_*WC('e', S(1)))**m_*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons150, cons33, cons96) rule3328 = ReplacementRule(pattern3328, replacement3328) pattern3329 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons150) rule3329 = ReplacementRule(pattern3329, replacement3329) pattern3330 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons150) rule3330 = ReplacementRule(pattern3330, replacement3330) pattern3331 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons378, cons1257, cons148, cons1504) rule3331 = ReplacementRule(pattern3331, replacement3331) pattern3332 = Pattern(Integral(x_**WC('m', S(1))*cos(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons378, cons1257, cons148, cons1504) rule3332 = ReplacementRule(pattern3332, replacement3332) pattern3333 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons148) rule3333 = ReplacementRule(pattern3333, replacement3333) pattern3334 = Pattern(Integral(x_**WC('m', S(1))*cos(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons148) rule3334 = ReplacementRule(pattern3334, replacement3334) pattern3335 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1505) rule3335 = ReplacementRule(pattern3335, replacement3335) pattern3336 = Pattern(Integral(x_**WC('m', S(1))*cos(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1505) rule3336 = ReplacementRule(pattern3336, replacement3336) pattern3337 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1506, cons685) rule3337 = ReplacementRule(pattern3337, replacement3337) pattern3338 = Pattern(Integral(x_**WC('m', S(1))*cos(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons148, cons1506, cons685) rule3338 = ReplacementRule(pattern3338, replacement3338) pattern3339 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150, cons369) rule3339 = ReplacementRule(pattern3339, With3339) pattern3340 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons150, cons369) rule3340 = ReplacementRule(pattern3340, With3340) pattern3341 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons148) rule3341 = ReplacementRule(pattern3341, replacement3341) pattern3342 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons150, cons148) rule3342 = ReplacementRule(pattern3342, replacement3342) pattern3343 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons139, cons1507) rule3343 = ReplacementRule(pattern3343, replacement3343) pattern3344 = Pattern(Integral(x_**WC('m', S(1))*cos(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons19, cons4, cons58, cons13, cons139, cons1507) rule3344 = ReplacementRule(pattern3344, replacement3344) pattern3345 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons139, cons1507, cons1505) rule3345 = ReplacementRule(pattern3345, replacement3345) pattern3346 = Pattern(Integral(x_**WC('m', S(1))*cos(x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons152, cons13, cons139, cons1507, cons1505) rule3346 = ReplacementRule(pattern3346, replacement3346) pattern3347 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198, cons20) rule3347 = ReplacementRule(pattern3347, replacement3347) pattern3348 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons40, cons198, cons20) rule3348 = ReplacementRule(pattern3348, replacement3348) pattern3349 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons198, cons369) rule3349 = ReplacementRule(pattern3349, With3349) pattern3350 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons40, cons198, cons369) rule3350 = ReplacementRule(pattern3350, With3350) pattern3351 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons198, cons358) rule3351 = ReplacementRule(pattern3351, replacement3351) pattern3352 = Pattern(Integral((x_*WC('e', S(1)))**m_*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons198, cons358) rule3352 = ReplacementRule(pattern3352, replacement3352) pattern3353 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons40, cons491) rule3353 = ReplacementRule(pattern3353, With3353) pattern3354 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons40, cons491) rule3354 = ReplacementRule(pattern3354, With3354) pattern3355 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons491) rule3355 = ReplacementRule(pattern3355, replacement3355) pattern3356 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons40, cons491) rule3356 = ReplacementRule(pattern3356, replacement3356) pattern3357 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, cons68, cons856, cons25) rule3357 = ReplacementRule(pattern3357, replacement3357) pattern3358 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons40, cons68, cons856, cons25) rule3358 = ReplacementRule(pattern3358, replacement3358) pattern3359 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons68, cons856, cons25) rule3359 = ReplacementRule(pattern3359, replacement3359) pattern3360 = Pattern(Integral((e_*x_)**m_*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons40, cons68, cons856, cons25) rule3360 = ReplacementRule(pattern3360, replacement3360) pattern3361 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons4, cons1508) rule3361 = ReplacementRule(pattern3361, replacement3361) pattern3362 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons50, cons19, cons4, cons1508) rule3362 = ReplacementRule(pattern3362, replacement3362) pattern3363 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule3363 = ReplacementRule(pattern3363, replacement3363) pattern3364 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(x_**n_*WC('d', S(1)) + WC('c', S(0))))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons130) rule3364 = ReplacementRule(pattern3364, replacement3364) pattern3365 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71, cons20) rule3365 = ReplacementRule(pattern3365, replacement3365) pattern3366 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71, cons20) rule3366 = ReplacementRule(pattern3366, replacement3366) pattern3367 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons70) rule3367 = ReplacementRule(pattern3367, replacement3367) pattern3368 = Pattern(Integral((x_*WC('e', S(1)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons70) rule3368 = ReplacementRule(pattern3368, replacement3368) pattern3369 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*sin(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule3369 = ReplacementRule(pattern3369, replacement3369) pattern3370 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*cos(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule3370 = ReplacementRule(pattern3370, replacement3370) pattern3371 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons4, cons5, cons55, cons56) rule3371 = ReplacementRule(pattern3371, replacement3371) pattern3372 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*cos(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons19, cons4, cons5, cons55, cons56) rule3372 = ReplacementRule(pattern3372, replacement3372) pattern3373 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons5, cons95, cons1503, cons56) rule3373 = ReplacementRule(pattern3373, replacement3373) pattern3374 = Pattern(Integral(x_**WC('m', S(1))*sin(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*cos(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons5, cons95, cons1503, cons56) rule3374 = ReplacementRule(pattern3374, replacement3374) pattern3375 = Pattern(Integral(sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons47) rule3375 = ReplacementRule(pattern3375, replacement3375) pattern3376 = Pattern(Integral(cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons47) rule3376 = ReplacementRule(pattern3376, replacement3376) pattern3377 = Pattern(Integral(sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons228) rule3377 = ReplacementRule(pattern3377, replacement3377) pattern3378 = Pattern(Integral(cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons228) rule3378 = ReplacementRule(pattern3378, replacement3378) pattern3379 = Pattern(Integral(sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons87, cons167) rule3379 = ReplacementRule(pattern3379, replacement3379) pattern3380 = Pattern(Integral(cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons87, cons167) rule3380 = ReplacementRule(pattern3380, replacement3380) pattern3381 = Pattern(Integral(sin(v_)**WC('n', S(1)), x_), cons150, cons820, cons1133) rule3381 = ReplacementRule(pattern3381, replacement3381) pattern3382 = Pattern(Integral(cos(v_)**WC('n', S(1)), x_), cons150, cons820, cons1133) rule3382 = ReplacementRule(pattern3382, replacement3382) pattern3383 = Pattern(Integral((d_ + x_*WC('e', S(1)))*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons49) rule3383 = ReplacementRule(pattern3383, replacement3383) pattern3384 = Pattern(Integral((d_ + x_*WC('e', S(1)))*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons49) rule3384 = ReplacementRule(pattern3384, replacement3384) pattern3385 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons241) rule3385 = ReplacementRule(pattern3385, replacement3385) pattern3386 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons241) rule3386 = ReplacementRule(pattern3386, replacement3386) pattern3387 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1134) rule3387 = ReplacementRule(pattern3387, replacement3387) pattern3388 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1134) rule3388 = ReplacementRule(pattern3388, replacement3388) pattern3389 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1135) rule3389 = ReplacementRule(pattern3389, replacement3389) pattern3390 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons168, cons1135) rule3390 = ReplacementRule(pattern3390, replacement3390) pattern3391 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1134) rule3391 = ReplacementRule(pattern3391, replacement3391) pattern3392 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1134) rule3392 = ReplacementRule(pattern3392, replacement3392) pattern3393 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1135) rule3393 = ReplacementRule(pattern3393, replacement3393) pattern3394 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**m_*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons33, cons96, cons1135) rule3394 = ReplacementRule(pattern3394, replacement3394) pattern3395 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1509) rule3395 = ReplacementRule(pattern3395, replacement3395) pattern3396 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons1509) rule3396 = ReplacementRule(pattern3396, replacement3396) pattern3397 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*sin(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons87, cons167) rule3397 = ReplacementRule(pattern3397, replacement3397) pattern3398 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*cos(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons87, cons167) rule3398 = ReplacementRule(pattern3398, replacement3398) pattern3399 = Pattern(Integral(u_**WC('m', S(1))*sin(v_)**WC('n', S(1)), x_), cons19, cons150, cons70, cons820, cons821) rule3399 = ReplacementRule(pattern3399, replacement3399) pattern3400 = Pattern(Integral(u_**WC('m', S(1))*cos(v_)**WC('n', S(1)), x_), cons19, cons150, cons70, cons820, cons821) rule3400 = ReplacementRule(pattern3400, replacement3400) return [rule2167, rule2168, rule2169, rule2170, rule2171, rule2172, rule2173, rule2174, rule2175, rule2176, rule2177, rule2178, rule2179, rule2180, rule2181, rule2182, rule2183, rule2184, rule2185, rule2186, rule2187, rule2188, rule2189, rule2190, rule2191, rule2192, rule2193, rule2194, rule2195, rule2196, rule2197, rule2198, rule2199, rule2200, rule2201, rule2202, rule2203, rule2204, rule2205, rule2206, rule2207, rule2208, rule2209, rule2210, rule2211, rule2212, rule2213, rule2214, rule2215, rule2216, rule2217, rule2218, rule2219, rule2220, rule2221, rule2222, rule2223, rule2224, rule2225, rule2226, rule2227, rule2228, rule2229, rule2230, rule2231, rule2232, rule2233, rule2234, rule2235, rule2236, rule2237, rule2238, rule2239, rule2240, rule2241, rule2242, rule2243, rule2244, rule2245, rule2246, rule2247, rule2248, rule2249, rule2250, rule2251, rule2252, rule2253, rule2254, rule2255, rule2256, rule2257, rule2258, rule2259, rule2260, rule2261, rule2262, rule2263, rule2264, rule2265, rule2266, rule2267, rule2268, rule2269, rule2270, rule2271, rule2272, rule2273, rule2274, rule2275, rule2276, rule2277, rule2278, rule2279, rule2280, rule2281, rule2282, rule2283, rule2284, rule2285, rule2286, rule2287, rule2288, rule2289, rule2290, rule2291, rule2292, rule2293, rule2294, rule2295, rule2296, rule2297, rule2298, rule2299, rule2300, rule2301, rule2302, rule2303, rule2304, rule2305, rule2306, rule2307, rule2308, rule2309, rule2310, rule2311, rule2312, rule2313, rule2314, rule2315, rule2316, rule2317, rule2318, rule2319, rule2320, rule2321, rule2322, rule2323, rule2324, rule2325, rule2326, rule2327, rule2328, rule2329, rule2330, rule2331, rule2332, rule2333, rule2334, rule2335, rule2336, rule2337, rule2338, rule2339, rule2340, rule2341, rule2342, rule2343, rule2344, rule2345, rule2346, rule2347, rule2348, rule2349, rule2350, rule2351, rule2352, rule2353, rule2354, rule2355, rule2356, rule2357, rule2358, rule2359, rule2360, rule2361, rule2362, rule2363, rule2364, rule2365, rule2366, rule2367, rule2368, rule2369, rule2370, rule2371, rule2372, rule2373, rule2374, rule2375, rule2376, rule2377, rule2378, rule2379, rule2380, rule2381, rule2382, rule2383, rule2384, rule2385, rule2386, rule2387, rule2388, rule2389, rule2390, rule2391, rule2392, rule2393, rule2394, rule2395, rule2396, rule2397, rule2398, rule2399, rule2400, rule2401, rule2402, rule2403, rule2404, rule2405, rule2406, rule2407, rule2408, rule2409, rule2410, rule2411, rule2412, rule2413, rule2414, rule2415, rule2416, rule2417, rule2418, rule2419, rule2420, rule2421, rule2422, rule2423, rule2424, rule2425, rule2426, rule2427, rule2428, rule2429, rule2430, rule2431, rule2432, rule2433, rule2434, rule2435, rule2436, rule2437, rule2438, rule2439, rule2440, rule2441, rule2442, rule2443, rule2444, rule2445, rule2446, rule2447, rule2448, rule2449, rule2450, rule2451, rule2452, rule2453, rule2454, rule2455, rule2456, rule2457, rule2458, rule2459, rule2460, rule2461, rule2462, rule2463, rule2464, rule2465, rule2466, rule2467, rule2468, rule2469, rule2470, rule2471, rule2472, rule2473, rule2474, rule2475, rule2476, rule2477, rule2478, rule2479, rule2480, rule2481, rule2482, rule2483, rule2484, rule2485, rule2486, rule2487, rule2488, rule2489, rule2490, rule2491, rule2492, rule2493, rule2494, rule2495, rule2496, rule2497, rule2498, rule2499, rule2500, rule2501, rule2502, rule2503, rule2504, rule2505, rule2506, rule2507, rule2508, rule2509, rule2510, rule2511, rule2512, rule2513, rule2514, rule2515, rule2516, rule2517, rule2518, rule2519, rule2520, rule2521, rule2522, rule2523, rule2524, rule2525, rule2526, rule2527, rule2528, rule2529, rule2530, rule2531, rule2532, rule2533, rule2534, rule2535, rule2536, rule2537, rule2538, rule2539, rule2540, rule2541, rule2542, rule2543, rule2544, rule2545, rule2546, rule2547, rule2548, rule2549, rule2550, rule2551, rule2552, rule2553, rule2554, rule2555, rule2556, rule2557, rule2558, rule2559, rule2560, rule2561, rule2562, rule2563, rule2564, rule2565, rule2566, rule2567, rule2568, rule2569, rule2570, rule2571, rule2572, rule2573, rule2574, rule2575, rule2576, rule2577, rule2578, rule2579, rule2580, rule2581, rule2582, rule2583, rule2584, rule2585, rule2586, rule2587, rule2588, rule2589, rule2590, rule2591, rule2592, rule2593, rule2594, rule2595, rule2596, rule2597, rule2598, rule2599, rule2600, rule2601, rule2602, rule2603, rule2604, rule2605, rule2606, rule2607, rule2608, rule2609, rule2610, rule2611, rule2612, rule2613, rule2614, rule2615, rule2616, rule2617, rule2618, rule2619, rule2620, rule2621, rule2622, rule2623, rule2624, rule2625, rule2626, rule2627, rule2628, rule2629, rule2630, rule2631, rule2632, rule2633, rule2634, rule2635, rule2636, rule2637, rule2638, rule2639, rule2640, rule2641, rule2642, rule2643, rule2644, rule2645, rule2646, rule2647, rule2648, rule2649, rule2650, rule2651, rule2652, rule2653, rule2654, rule2655, rule2656, rule2657, rule2658, rule2659, rule2660, rule2661, rule2662, rule2663, rule2664, rule2665, rule2666, rule2667, rule2668, rule2669, rule2670, rule2671, rule2672, rule2673, rule2674, rule2675, rule2676, rule2677, rule2678, rule2679, rule2680, rule2681, rule2682, rule2683, rule2684, rule2685, rule2686, rule2687, rule2688, rule2689, rule2690, rule2691, rule2692, rule2693, rule2694, rule2695, rule2696, rule2697, rule2698, rule2699, rule2700, rule2701, rule2702, rule2703, rule2704, rule2705, rule2706, rule2707, rule2708, rule2709, rule2710, rule2711, rule2712, rule2713, rule2714, rule2715, rule2716, rule2717, rule2718, rule2719, rule2720, rule2721, rule2722, rule2723, rule2724, rule2725, rule2726, rule2727, rule2728, rule2729, rule2730, rule2731, rule2732, rule2733, rule2734, rule2735, rule2736, rule2737, rule2738, rule2739, rule2740, rule2741, rule2742, rule2743, rule2744, rule2745, rule2746, rule2747, rule2748, rule2749, rule2750, rule2751, rule2752, rule2753, rule2754, rule2755, rule2756, rule2757, rule2758, rule2759, rule2760, rule2761, rule2762, rule2763, rule2764, rule2765, rule2766, rule2767, rule2768, rule2769, rule2770, rule2771, rule2772, rule2773, rule2774, rule2775, rule2776, rule2777, rule2778, rule2779, rule2780, rule2781, rule2782, rule2783, rule2784, rule2785, rule2786, rule2787, rule2788, rule2789, rule2790, rule2791, rule2792, rule2793, rule2794, rule2795, rule2796, rule2797, rule2798, rule2799, rule2800, rule2801, rule2802, rule2803, rule2804, rule2805, rule2806, rule2807, rule2808, rule2809, rule2810, rule2811, rule2812, rule2813, rule2814, rule2815, rule2816, rule2817, rule2818, rule2819, rule2820, rule2821, rule2822, rule2823, rule2824, rule2825, rule2826, rule2827, rule2828, rule2829, rule2830, rule2831, rule2832, rule2833, rule2834, rule2835, rule2836, rule2837, rule2838, rule2839, rule2840, rule2841, rule2842, rule2843, rule2844, rule2845, rule2846, rule2847, rule2848, rule2849, rule2850, rule2851, rule2852, rule2853, rule2854, rule2855, rule2856, rule2857, rule2858, rule2859, rule2860, rule2861, rule2862, rule2863, rule2864, rule2865, rule2866, rule2867, rule2868, rule2869, rule2870, rule2871, rule2872, rule2873, rule2874, rule2875, rule2876, rule2877, rule2878, rule2879, rule2880, rule2881, rule2882, rule2883, rule2884, rule2885, rule2886, rule2887, rule2888, rule2889, rule2890, rule2891, rule2892, rule2893, rule2894, rule2895, rule2896, rule2897, rule2898, rule2899, rule2900, rule2901, rule2902, rule2903, rule2904, rule2905, rule2906, rule2907, rule2908, rule2909, rule2910, rule2911, rule2912, rule2913, rule2914, rule2915, rule2916, rule2917, rule2918, rule2919, rule2920, rule2921, rule2922, rule2923, rule2924, rule2925, rule2926, rule2927, rule2928, rule2929, rule2930, rule2931, rule2932, rule2933, rule2934, rule2935, rule2936, rule2937, rule2938, rule2939, rule2940, rule2941, rule2942, rule2943, rule2944, rule2945, rule2946, rule2947, rule2948, rule2949, rule2950, rule2951, rule2952, rule2953, rule2954, rule2955, rule2956, rule2957, rule2958, rule2959, rule2960, rule2961, rule2962, rule2963, rule2964, rule2965, rule2966, rule2967, rule2968, rule2969, rule2970, rule2971, rule2972, rule2973, rule2974, rule2975, rule2976, rule2977, rule2978, rule2979, rule2980, rule2981, rule2982, rule2983, rule2984, rule2985, rule2986, rule2987, rule2988, rule2989, rule2990, rule2991, rule2992, rule2993, rule2994, rule2995, rule2996, rule2997, rule2998, rule2999, rule3000, rule3001, rule3002, rule3003, rule3004, rule3005, rule3006, rule3007, rule3008, rule3009, rule3010, rule3011, rule3012, rule3013, rule3014, rule3015, rule3016, rule3017, rule3018, rule3019, rule3020, rule3021, rule3022, rule3023, rule3024, rule3025, rule3026, rule3027, rule3028, rule3029, rule3030, rule3031, rule3032, rule3033, rule3034, rule3035, rule3036, rule3037, rule3038, rule3039, rule3040, rule3041, rule3042, rule3043, rule3044, rule3045, rule3046, rule3047, rule3048, rule3049, rule3050, rule3051, rule3052, rule3053, rule3054, rule3055, rule3056, rule3057, rule3058, rule3059, rule3060, rule3061, rule3062, rule3063, rule3064, rule3065, rule3066, rule3067, rule3068, rule3069, rule3070, rule3071, rule3072, rule3073, rule3074, rule3075, rule3076, rule3077, rule3078, rule3079, rule3080, rule3081, rule3082, rule3083, rule3084, rule3085, rule3086, rule3087, rule3088, rule3089, rule3090, rule3091, rule3092, rule3093, rule3094, rule3095, rule3096, rule3097, rule3098, rule3099, rule3100, rule3101, rule3102, rule3103, rule3104, rule3105, rule3106, rule3107, rule3108, rule3109, rule3110, rule3111, rule3112, rule3113, rule3114, rule3115, rule3116, rule3117, rule3118, rule3119, rule3120, rule3121, rule3122, rule3123, rule3124, rule3125, rule3126, rule3127, rule3128, rule3129, rule3130, rule3131, rule3132, rule3133, rule3134, rule3135, rule3136, rule3137, rule3138, rule3139, rule3140, rule3141, rule3142, rule3143, rule3144, rule3145, rule3146, rule3147, rule3148, rule3149, rule3150, rule3151, rule3152, rule3153, rule3154, rule3155, rule3156, rule3157, rule3158, rule3159, rule3160, rule3161, rule3162, rule3163, rule3164, rule3165, rule3166, rule3167, rule3168, rule3169, rule3170, rule3171, rule3172, rule3173, rule3174, rule3175, rule3176, rule3177, rule3178, rule3179, rule3180, rule3181, rule3182, rule3183, rule3184, rule3185, rule3186, rule3187, rule3188, rule3189, rule3190, rule3191, rule3192, rule3193, rule3194, rule3195, rule3196, rule3197, rule3198, rule3199, rule3200, rule3201, rule3202, rule3203, rule3204, rule3205, rule3206, rule3207, rule3208, rule3209, rule3210, rule3211, rule3212, rule3213, rule3214, rule3215, rule3216, rule3217, rule3218, rule3219, rule3220, rule3221, rule3222, rule3223, rule3224, rule3225, rule3226, rule3227, rule3228, rule3229, rule3230, rule3231, rule3232, rule3233, rule3234, rule3235, rule3236, rule3237, rule3238, rule3239, rule3240, rule3241, rule3242, rule3243, rule3244, rule3245, rule3246, rule3247, rule3248, rule3249, rule3250, rule3251, rule3252, rule3253, rule3254, rule3255, rule3256, rule3257, rule3258, rule3259, rule3260, rule3261, rule3262, rule3263, rule3264, rule3265, rule3266, rule3267, rule3268, rule3269, rule3270, rule3271, rule3272, rule3273, rule3274, rule3275, rule3276, rule3277, rule3278, rule3279, rule3280, rule3281, rule3282, rule3283, rule3284, rule3285, rule3286, rule3287, rule3288, rule3289, rule3290, rule3291, rule3292, rule3293, rule3294, rule3295, rule3296, rule3297, rule3298, rule3299, rule3300, rule3301, rule3302, rule3303, rule3304, rule3305, rule3306, rule3307, rule3308, rule3309, rule3310, rule3311, rule3312, rule3313, rule3314, rule3315, rule3316, rule3317, rule3318, rule3319, rule3320, rule3321, rule3322, rule3323, rule3324, rule3325, rule3326, rule3327, rule3328, rule3329, rule3330, rule3331, rule3332, rule3333, rule3334, rule3335, rule3336, rule3337, rule3338, rule3339, rule3340, rule3341, rule3342, rule3343, rule3344, rule3345, rule3346, rule3347, rule3348, rule3349, rule3350, rule3351, rule3352, rule3353, rule3354, rule3355, rule3356, rule3357, rule3358, rule3359, rule3360, rule3361, rule3362, rule3363, rule3364, rule3365, rule3366, rule3367, rule3368, rule3369, rule3370, rule3371, rule3372, rule3373, rule3374, rule3375, rule3376, rule3377, rule3378, rule3379, rule3380, rule3381, rule3382, rule3383, rule3384, rule3385, rule3386, rule3387, rule3388, rule3389, rule3390, rule3391, rule3392, rule3393, rule3394, rule3395, rule3396, rule3397, rule3398, rule3399, rule3400, ] def replacement2167(u, x): return Int(DeactivateTrig(u, x), x) def replacement2168(a, b, e, f, m, n, x): return Simp((a*sin(e + f*x))**(m + S(1))*(b*cos(e + f*x))**(n + S(1))/(a*b*f*(m + S(1))), x) def replacement2169(a, e, f, m, n, x): return Dist(S(1)/(a*f), Subst(Int(x**m*(S(1) - x**S(2)/a**S(2))**(n/S(2) + S(-1)/2), x), x, a*sin(e + f*x)), x) def replacement2170(a, e, f, m, n, x): return -Dist(S(1)/(a*f), Subst(Int(x**m*(S(1) - x**S(2)/a**S(2))**(n/S(2) + S(-1)/2), x), x, a*cos(e + f*x)), x) def replacement2171(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-1))/(b**S(2)*(n + S(1))), Int((a*sin(e + f*x))**(m + S(-2))*(b*cos(e + f*x))**(n + S(2)), x), x) - Simp(a*(a*sin(e + f*x))**(m + S(-1))*(b*cos(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement2172(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-1))/(b**S(2)*(n + S(1))), Int((a*cos(e + f*x))**(m + S(-2))*(b*sin(e + f*x))**(n + S(2)), x), x) + Simp(a*(a*cos(e + f*x))**(m + S(-1))*(b*sin(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement2173(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-1))/(m + n), Int((a*sin(e + f*x))**(m + S(-2))*(b*cos(e + f*x))**n, x), x) - Simp(a*(a*sin(e + f*x))**(m + S(-1))*(b*cos(e + f*x))**(n + S(1))/(b*f*(m + n)), x) def replacement2174(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-1))/(m + n), Int((a*cos(e + f*x))**(m + S(-2))*(b*sin(e + f*x))**n, x), x) + Simp(a*(a*cos(e + f*x))**(m + S(-1))*(b*sin(e + f*x))**(n + S(1))/(b*f*(m + n)), x) def replacement2175(a, b, e, f, m, n, x): return Dist((m + n + S(2))/(a**S(2)*(m + S(1))), Int((a*sin(e + f*x))**(m + S(2))*(b*cos(e + f*x))**n, x), x) + Simp((a*sin(e + f*x))**(m + S(1))*(b*cos(e + f*x))**(n + S(1))/(a*b*f*(m + S(1))), x) def replacement2176(a, b, e, f, m, n, x): return Dist((m + n + S(2))/(a**S(2)*(m + S(1))), Int((a*cos(e + f*x))**(m + S(2))*(b*sin(e + f*x))**n, x), x) - Simp((a*cos(e + f*x))**(m + S(1))*(b*sin(e + f*x))**(n + S(1))/(a*b*f*(m + S(1))), x) def replacement2177(a, b, e, f, x): return Dist(sqrt(a*sin(e + f*x))*sqrt(b*cos(e + f*x))/sqrt(sin(S(2)*e + S(2)*f*x)), Int(sqrt(sin(S(2)*e + S(2)*f*x)), x), x) def replacement2178(a, b, e, f, x): return Dist(sqrt(sin(S(2)*e + S(2)*f*x))/(sqrt(a*sin(e + f*x))*sqrt(b*cos(e + f*x))), Int(S(1)/sqrt(sin(S(2)*e + S(2)*f*x)), x), x) def With2179(a, b, e, f, m, n, x): k = Denominator(m) return Dist(a*b*k/f, Subst(Int(x**(k*(m + S(1)) + S(-1))/(a**S(2) + b**S(2)*x**(S(2)*k)), x), x, (a*sin(e + f*x))**(S(1)/k)*(b*cos(e + f*x))**(-S(1)/k)), x) def With2180(a, b, e, f, m, n, x): k = Denominator(m) return -Dist(a*b*k/f, Subst(Int(x**(k*(m + S(1)) + S(-1))/(a**S(2) + b**S(2)*x**(S(2)*k)), x), x, (a*cos(e + f*x))**(S(1)/k)*(b*sin(e + f*x))**(-S(1)/k)), x) def replacement2181(a, b, e, f, m, n, x): return Simp(b**(S(2)*IntPart(n/S(2) + S(-1)/2) + S(1))*(a*sin(e + f*x))**(m + S(1))*(b*cos(e + f*x))**(S(2)*FracPart(n/S(2) + S(-1)/2))*(cos(e + f*x)**S(2))**(-FracPart(n/S(2) + S(-1)/2))*Hypergeometric2F1(m/S(2) + S(1)/2, S(1)/2 - n/S(2), m/S(2) + S(3)/2, sin(e + f*x)**S(2))/(a*f*(m + S(1))), x) def replacement2182(a, b, e, f, m, n, x): return -Simp(b**(S(2)*IntPart(n/S(2) + S(-1)/2) + S(1))*(a*cos(e + f*x))**(m + S(1))*(b*sin(e + f*x))**(S(2)*FracPart(n/S(2) + S(-1)/2))*(sin(e + f*x)**S(2))**(-FracPart(n/S(2) + S(-1)/2))*Hypergeometric2F1(m/S(2) + S(1)/2, S(1)/2 - n/S(2), m/S(2) + S(3)/2, cos(e + f*x)**S(2))/(a*f*(m + S(1))), x) def replacement2183(a, b, e, f, m, n, x): return Simp(b*(a*sin(e + f*x))**(m + S(1))*(b/cos(e + f*x))**(n + S(-1))/(a*f*(m + S(1))), x) def replacement2184(a, b, e, f, m, n, x): return -Simp(b*(a*cos(e + f*x))**(m + S(1))*(b/sin(e + f*x))**(n + S(-1))/(a*f*(m + S(1))), x) def replacement2185(a, b, e, f, m, n, x): return -Dist(a**S(2)*b**S(2)*(m + S(-1))/(n + S(-1)), Int((a*sin(e + f*x))**(m + S(-2))*(b/cos(e + f*x))**(n + S(-2)), x), x) + Simp(a*b*(a*sin(e + f*x))**(m + S(-1))*(b/cos(e + f*x))**(n + S(-1))/(f*(n + S(-1))), x) def replacement2186(a, b, e, f, m, n, x): return -Dist(a**S(2)*b**S(2)*(m + S(-1))/(n + S(-1)), Int((a*cos(e + f*x))**(m + S(-2))*(b/sin(e + f*x))**(n + S(-2)), x), x) - Simp(a*b*(a*cos(e + f*x))**(m + S(-1))*(b/sin(e + f*x))**(n + S(-1))/(f*(n + S(-1))), x) def replacement2187(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-1))/(m - n), Int((a*sin(e + f*x))**(m + S(-2))*(b/cos(e + f*x))**n, x), x) - Simp(a*b*(a*sin(e + f*x))**(m + S(-1))*(b/cos(e + f*x))**(n + S(-1))/(f*(m - n)), x) def replacement2188(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-1))/(m - n), Int((a*cos(e + f*x))**(m + S(-2))*(b/sin(e + f*x))**n, x), x) + Simp(a*b*(a*cos(e + f*x))**(m + S(-1))*(b/sin(e + f*x))**(n + S(-1))/(f*(m - n)), x) def replacement2189(a, b, e, f, m, n, x): return Dist((m - n + S(2))/(a**S(2)*(m + S(1))), Int((a*sin(e + f*x))**(m + S(2))*(b/cos(e + f*x))**n, x), x) + Simp(b*(a*sin(e + f*x))**(m + S(1))*(b/cos(e + f*x))**(n + S(-1))/(a*f*(m + S(1))), x) def replacement2190(a, b, e, f, m, n, x): return Dist((m - n + S(2))/(a**S(2)*(m + S(1))), Int((a*cos(e + f*x))**(m + S(2))*(b/sin(e + f*x))**n, x), x) - Simp(b*(a*cos(e + f*x))**(m + S(1))*(b/sin(e + f*x))**(n + S(-1))/(a*f*(m + S(1))), x) def replacement2191(a, b, e, f, m, n, x): return Dist((cos(e + f*x)/b)**(FracPart(n) + S(1))*(b/cos(e + f*x))**(FracPart(n) + S(1)), Int((a*sin(e + f*x))**m*(cos(e + f*x)/b)**(-n), x), x) def replacement2192(a, b, e, f, m, n, x): return Dist((sin(e + f*x)/b)**(FracPart(n) + S(1))*(b/sin(e + f*x))**(FracPart(n) + S(1)), Int((a*cos(e + f*x))**m*(sin(e + f*x)/b)**(-n), x), x) def replacement2193(a, b, e, f, m, n, x): return Dist((a*b)**IntPart(n)*(a*sin(e + f*x))**FracPart(n)*(b/sin(e + f*x))**FracPart(n), Int((a*sin(e + f*x))**(m - n), x), x) def replacement2194(a, b, e, f, m, n, x): return Dist((a*b)**IntPart(n)*(a*cos(e + f*x))**FracPart(n)*(b/cos(e + f*x))**FracPart(n), Int((a*cos(e + f*x))**(m - n), x), x) def replacement2195(c, d, n, x): return -Dist(S(1)/d, Subst(Int((S(1) - x**S(2))**(n/S(2))/sqrt(S(1) - x**S(2)), x), x, cos(c + d*x)), x) def replacement2196(c, d, n, x): return Dist(S(1)/d, Subst(Int((S(1) - x**S(2))**(n/S(2))/sqrt(S(1) - x**S(2)), x), x, sin(c + d*x)), x) def replacement2197(b, c, d, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*sin(c + d*x))**(n + S(-2)), x), x) - Simp(b*(b*sin(c + d*x))**(n + S(-1))*cos(c + d*x)/(d*n), x) def replacement2198(b, c, d, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*cos(c + d*x))**(n + S(-2)), x), x) + Simp(b*(b*cos(c + d*x))**(n + S(-1))*sin(c + d*x)/(d*n), x) def replacement2199(b, c, d, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*sin(c + d*x))**(n + S(2)), x), x) + Simp((b*sin(c + d*x))**(n + S(1))*cos(c + d*x)/(b*d*(n + S(1))), x) def replacement2200(b, c, d, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*cos(c + d*x))**(n + S(2)), x), x) - Simp((b*cos(c + d*x))**(n + S(1))*sin(c + d*x)/(b*d*(n + S(1))), x) def replacement2201(c, d, x): return -Simp(cos(c + d*x)/d, x) def replacement2202(c, d, x): return Simp(sin(c + d*x)/d, x) def replacement2203(c, d, x): return Simp(S(2)*EllipticE(-Pi/S(4) + c/S(2) + d*x/S(2), S(2))/d, x) def replacement2204(c, d, x): return Simp(S(2)*EllipticE(c/S(2) + d*x/S(2), S(2))/d, x) def replacement2205(b, c, d, x): return Dist(sqrt(b*sin(c + d*x))/sqrt(sin(c + d*x)), Int(sqrt(sin(c + d*x)), x), x) def replacement2206(b, c, d, x): return Dist(sqrt(b*cos(c + d*x))/sqrt(cos(c + d*x)), Int(sqrt(cos(c + d*x)), x), x) def replacement2207(c, d, x): return Simp(S(2)*EllipticF(-Pi/S(4) + c/S(2) + d*x/S(2), S(2))/d, x) def replacement2208(c, d, x): return Simp(S(2)*EllipticF(c/S(2) + d*x/S(2), S(2))/d, x) def replacement2209(b, c, d, x): return Dist(sqrt(sin(c + d*x))/sqrt(b*sin(c + d*x)), Int(S(1)/sqrt(sin(c + d*x)), x), x) def replacement2210(b, c, d, x): return Dist(sqrt(cos(c + d*x))/sqrt(b*cos(c + d*x)), Int(S(1)/sqrt(cos(c + d*x)), x), x) def replacement2211(b, c, d, n, x): return Simp((b*sin(c + d*x))**(n + S(1))*Hypergeometric2F1(S(1)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(c + d*x)**S(2))*cos(c + d*x)/(b*d*(n + S(1))*sqrt(cos(c + d*x)**S(2))), x) def replacement2212(b, c, d, n, x): return -Simp((b*cos(c + d*x))**(n + S(1))*Hypergeometric2F1(S(1)/2, n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(c + d*x)**S(2))*sin(c + d*x)/(b*d*(n + S(1))*sqrt(sin(c + d*x)**S(2))), x) def replacement2213(a, b, c, d, x): return Dist(S(2)*a*b, Int(sin(c + d*x), x), x) + Simp(x*(S(2)*a**S(2) + b**S(2))/S(2), x) - Simp(b**S(2)*sin(c + d*x)*cos(c + d*x)/(S(2)*d), x) def replacement2214(a, b, c, d, x): return Dist(S(2)*a*b, Int(cos(c + d*x), x), x) + Simp(x*(S(2)*a**S(2) + b**S(2))/S(2), x) + Simp(b**S(2)*sin(c + d*x)*cos(c + d*x)/(S(2)*d), x) def replacement2215(a, b, c, d, n, x): return Int(ExpandTrig((a + b*sin(c + d*x))**n, x), x) def replacement2216(a, b, c, d, n, x): return Int(ExpandTrig((a + b*cos(c + d*x))**n, x), x) def replacement2217(a, b, c, d, x): return Simp(-S(2)*b*cos(c + d*x)/(d*sqrt(a + b*sin(c + d*x))), x) def replacement2218(a, b, c, d, x): return Simp(S(2)*b*sin(c + d*x)/(d*sqrt(a + b*cos(c + d*x))), x) def replacement2219(a, b, c, d, n, x): return Dist(a*(S(2)*n + S(-1))/n, Int((a + b*sin(c + d*x))**(n + S(-1)), x), x) - Simp(b*(a + b*sin(c + d*x))**(n + S(-1))*cos(c + d*x)/(d*n), x) def replacement2220(a, b, c, d, n, x): return Dist(a*(S(2)*n + S(-1))/n, Int((a + b*cos(c + d*x))**(n + S(-1)), x), x) + Simp(b*(a + b*cos(c + d*x))**(n + S(-1))*sin(c + d*x)/(d*n), x) def replacement2221(a, b, c, d, x): return -Simp(cos(c + d*x)/(d*(a*sin(c + d*x) + b)), x) def replacement2222(a, b, c, d, x): return Simp(sin(c + d*x)/(d*(a*cos(c + d*x) + b)), x) def replacement2223(a, b, c, d, x): return Dist(-S(2)/d, Subst(Int(S(1)/(S(2)*a - x**S(2)), x), x, b*cos(c + d*x)/sqrt(a + b*sin(c + d*x))), x) def replacement2224(a, b, c, d, x): return Dist(S(2)/d, Subst(Int(S(1)/(S(2)*a - x**S(2)), x), x, b*sin(c + d*x)/sqrt(a + b*cos(c + d*x))), x) def replacement2225(a, b, c, d, n, x): return Dist((n + S(1))/(a*(S(2)*n + S(1))), Int((a + b*sin(c + d*x))**(n + S(1)), x), x) + Simp(b*(a + b*sin(c + d*x))**n*cos(c + d*x)/(a*d*(S(2)*n + S(1))), x) def replacement2226(a, b, c, d, n, x): return Dist((n + S(1))/(a*(S(2)*n + S(1))), Int((a + b*cos(c + d*x))**(n + S(1)), x), x) - Simp(b*(a + b*cos(c + d*x))**n*sin(c + d*x)/(a*d*(S(2)*n + S(1))), x) def replacement2227(a, b, c, d, n, x): return -Simp(S(2)**(n + S(1)/2)*a**(n + S(-1)/2)*b*Hypergeometric2F1(S(1)/2, S(1)/2 - n, S(3)/2, S(1)/2 - b*sin(c + d*x)/(S(2)*a))*cos(c + d*x)/(d*sqrt(a + b*sin(c + d*x))), x) def replacement2228(a, b, c, d, n, x): return Simp(S(2)**(n + S(1)/2)*a**(n + S(-1)/2)*b*Hypergeometric2F1(S(1)/2, S(1)/2 - n, S(3)/2, S(1)/2 - b*cos(c + d*x)/(S(2)*a))*sin(c + d*x)/(d*sqrt(a + b*cos(c + d*x))), x) def replacement2229(a, b, c, d, n, x): return Dist(a**IntPart(n)*(S(1) + b*sin(c + d*x)/a)**(-FracPart(n))*(a + b*sin(c + d*x))**FracPart(n), Int((S(1) + b*sin(c + d*x)/a)**n, x), x) def replacement2230(a, b, c, d, n, x): return Dist(a**IntPart(n)*(S(1) + b*cos(c + d*x)/a)**(-FracPart(n))*(a + b*cos(c + d*x))**FracPart(n), Int((S(1) + b*cos(c + d*x)/a)**n, x), x) def replacement2231(a, b, c, d, x): return Simp(S(2)*sqrt(a + b)*EllipticE(-Pi/S(4) + c/S(2) + d*x/S(2), S(2)*b/(a + b))/d, x) def replacement2232(a, b, c, d, x): return Simp(S(2)*sqrt(a + b)*EllipticE(c/S(2) + d*x/S(2), S(2)*b/(a + b))/d, x) def replacement2233(a, b, c, d, x): return Simp(S(2)*sqrt(a - b)*EllipticE(Pi/S(4) + c/S(2) + d*x/S(2), -S(2)*b/(a - b))/d, x) def replacement2234(a, b, c, d, x): return Simp(S(2)*sqrt(a - b)*EllipticE(Pi/S(2) + c/S(2) + d*x/S(2), -S(2)*b/(a - b))/d, x) def replacement2235(a, b, c, d, x): return Dist(sqrt(a + b*sin(c + d*x))/sqrt((a + b*sin(c + d*x))/(a + b)), Int(sqrt(a/(a + b) + b*sin(c + d*x)/(a + b)), x), x) def replacement2236(a, b, c, d, x): return Dist(sqrt(a + b*cos(c + d*x))/sqrt((a + b*cos(c + d*x))/(a + b)), Int(sqrt(a/(a + b) + b*cos(c + d*x)/(a + b)), x), x) def replacement2237(a, b, c, d, n, x): return Dist(S(1)/n, Int((a + b*sin(c + d*x))**(n + S(-2))*Simp(a**S(2)*n + a*b*(S(2)*n + S(-1))*sin(c + d*x) + b**S(2)*(n + S(-1)), x), x), x) - Simp(b*(a + b*sin(c + d*x))**(n + S(-1))*cos(c + d*x)/(d*n), x) def replacement2238(a, b, c, d, n, x): return Dist(S(1)/n, Int((a + b*cos(c + d*x))**(n + S(-2))*Simp(a**S(2)*n + a*b*(S(2)*n + S(-1))*cos(c + d*x) + b**S(2)*(n + S(-1)), x), x), x) + Simp(b*(a + b*cos(c + d*x))**(n + S(-1))*sin(c + d*x)/(d*n), x) def With2239(a, b, c, d, x): q = Rt(a**S(2) - b**S(2), S(2)) return Simp(x/q, x) + Simp(S(2)*ArcTan(b*cos(c + d*x)/(a + b*sin(c + d*x) + q))/(d*q), x) def With2240(a, b, c, d, x): q = Rt(a**S(2) - b**S(2), S(2)) return Simp(x/q, x) - Simp(S(2)*ArcTan(b*sin(c + d*x)/(a + b*cos(c + d*x) + q))/(d*q), x) def With2241(a, b, c, d, x): q = Rt(a**S(2) - b**S(2), S(2)) return -Simp(x/q, x) - Simp(S(2)*ArcTan(b*cos(c + d*x)/(a + b*sin(c + d*x) - q))/(d*q), x) def With2242(a, b, c, d, x): q = Rt(a**S(2) - b**S(2), S(2)) return -Simp(x/q, x) + Simp(S(2)*ArcTan(b*sin(c + d*x)/(a + b*cos(c + d*x) - q))/(d*q), x) def With2243(a, b, c, d, x): e = FreeFactors(tan(-Pi/S(4) + c/S(2) + d*x/S(2)), x) return Dist(S(2)*e/d, Subst(Int(S(1)/(a + b + e**S(2)*x**S(2)*(a - b)), x), x, tan(-Pi/S(4) + c/S(2) + d*x/S(2))/e), x) def With2244(a, b, c, d, x): e = FreeFactors(tan(c/S(2) + d*x/S(2)), x) return Dist(S(2)*e/d, Subst(Int(S(1)/(a*e**S(2)*x**S(2) + a + S(2)*b*e*x), x), x, tan(c/S(2) + d*x/S(2))/e), x) def With2245(a, b, c, d, x): e = FreeFactors(tan(c/S(2) + d*x/S(2)), x) return Dist(S(2)*e/d, Subst(Int(S(1)/(a + b + e**S(2)*x**S(2)*(a - b)), x), x, tan(c/S(2) + d*x/S(2))/e), x) def replacement2246(a, b, c, d, x): return Simp(S(2)*EllipticF(-Pi/S(4) + c/S(2) + d*x/S(2), S(2)*b/(a + b))/(d*sqrt(a + b)), x) def replacement2247(a, b, c, d, x): return Simp(S(2)*EllipticF(c/S(2) + d*x/S(2), S(2)*b/(a + b))/(d*sqrt(a + b)), x) def replacement2248(a, b, c, d, x): return Simp(S(2)*EllipticF(Pi/S(4) + c/S(2) + d*x/S(2), -S(2)*b/(a - b))/(d*sqrt(a - b)), x) def replacement2249(a, b, c, d, x): return Simp(S(2)*EllipticF(Pi/S(2) + c/S(2) + d*x/S(2), -S(2)*b/(a - b))/(d*sqrt(a - b)), x) def replacement2250(a, b, c, d, x): return Dist(sqrt((a + b*sin(c + d*x))/(a + b))/sqrt(a + b*sin(c + d*x)), Int(S(1)/sqrt(a/(a + b) + b*sin(c + d*x)/(a + b)), x), x) def replacement2251(a, b, c, d, x): return Dist(sqrt((a + b*cos(c + d*x))/(a + b))/sqrt(a + b*cos(c + d*x)), Int(S(1)/sqrt(a/(a + b) + b*cos(c + d*x)/(a + b)), x), x) def replacement2252(a, b, c, d, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(n + S(1))), Int((a + b*sin(c + d*x))**(n + S(1))*Simp(a*(n + S(1)) - b*(n + S(2))*sin(c + d*x), x), x), x) - Simp(b*(a + b*sin(c + d*x))**(n + S(1))*cos(c + d*x)/(d*(a**S(2) - b**S(2))*(n + S(1))), x) def replacement2253(a, b, c, d, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(n + S(1))), Int((a + b*cos(c + d*x))**(n + S(1))*Simp(a*(n + S(1)) - b*(n + S(2))*cos(c + d*x), x), x), x) + Simp(b*(a + b*cos(c + d*x))**(n + S(1))*sin(c + d*x)/(d*(a**S(2) - b**S(2))*(n + S(1))), x) def replacement2254(a, b, c, d, n, x): return Dist(cos(c + d*x)/(d*sqrt(S(1) - sin(c + d*x))*sqrt(sin(c + d*x) + S(1))), Subst(Int((a + b*x)**n/(sqrt(S(1) - x)*sqrt(x + S(1))), x), x, sin(c + d*x)), x) def replacement2255(a, b, c, d, n, x): return -Dist(sin(c + d*x)/(d*sqrt(S(1) - cos(c + d*x))*sqrt(cos(c + d*x) + S(1))), Subst(Int((a + b*x)**n/(sqrt(S(1) - x)*sqrt(x + S(1))), x), x, cos(c + d*x)), x) def replacement2256(a, b, c, d, n, x): return Int((a + b*sin(S(2)*c + S(2)*d*x)/S(2))**n, x) def replacement2257(a, b, e, f, m, p, x): return Dist(b**(-p)/f, Subst(Int((a - x)**(p/S(2) + S(-1)/2)*(a + x)**(m + p/S(2) + S(-1)/2), x), x, b*sin(e + f*x)), x) def replacement2258(a, b, e, f, m, p, x): return -Dist(b**(-p)/f, Subst(Int((a - x)**(p/S(2) + S(-1)/2)*(a + x)**(m + p/S(2) + S(-1)/2), x), x, b*cos(e + f*x)), x) def replacement2259(a, b, e, f, m, p, x): return Dist(b**(-p)/f, Subst(Int((a + x)**m*(b**S(2) - x**S(2))**(p/S(2) + S(-1)/2), x), x, b*sin(e + f*x)), x) def replacement2260(a, b, e, f, m, p, x): return -Dist(b**(-p)/f, Subst(Int((a + x)**m*(b**S(2) - x**S(2))**(p/S(2) + S(-1)/2), x), x, b*cos(e + f*x)), x) def replacement2261(a, b, e, f, g, p, x): return Dist(a, Int((g*cos(e + f*x))**p, x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))/(f*g*(p + S(1))), x) def replacement2262(a, b, e, f, g, p, x): return Dist(a, Int((g*sin(e + f*x))**p, x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))/(f*g*(p + S(1))), x) def replacement2263(a, b, e, f, g, m, p, x): return Dist((a/g)**(S(2)*m), Int((g*cos(e + f*x))**(S(2)*m + p)*(a - b*sin(e + f*x))**(-m), x), x) def replacement2264(a, b, e, f, g, m, p, x): return Dist((a/g)**(S(2)*m), Int((g*sin(e + f*x))**(S(2)*m + p)*(a - b*cos(e + f*x))**(-m), x), x) def replacement2265(a, b, e, f, g, m, p, x): return Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(a*f*g*m), x) def replacement2266(a, b, e, f, g, m, p, x): return -Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(a*f*g*m), x) def replacement2267(a, b, e, f, g, m, p, x): return Dist((m + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1)), x), x) + Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2268(a, b, e, f, g, m, p, x): return Dist((m + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1)), x), x) - Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2269(a, b, e, f, g, m, p, x): return Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))/(f*g*(m + S(-1))), x) def replacement2270(a, b, e, f, g, m, p, x): return -Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))/(f*g*(m + S(-1))), x) def replacement2271(a, b, e, f, g, m, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + p), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-1)), x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))/(f*g*(m + p)), x) def replacement2272(a, b, e, f, g, m, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + p), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-1)), x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))/(f*g*(m + p)), x) def replacement2273(a, b, e, f, g, m, p, x): return Dist(a*(m + p + S(1))/(g**S(2)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-1)), x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(a*f*g*(p + S(1))), x) def replacement2274(a, b, e, f, g, m, p, x): return Dist(a*(m + p + S(1))/(g**S(2)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-1)), x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(a*f*g*(p + S(1))), x) def replacement2275(a, b, e, f, g, m, p, x): return Dist(b**S(2)*(S(2)*m + p + S(-1))/(g**S(2)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-2)), x), x) + Simp(-S(2)*b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))/(f*g*(p + S(1))), x) def replacement2276(a, b, e, f, g, m, p, x): return Dist(b**S(2)*(S(2)*m + p + S(-1))/(g**S(2)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-2)), x), x) + Simp(S(2)*b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))/(f*g*(p + S(1))), x) def replacement2277(a, b, e, f, g, x): return Dist(a*sqrt(a + b*sin(e + f*x))*sqrt(cos(e + f*x) + S(1))/(a*cos(e + f*x) + a + b*sin(e + f*x)), Int(sqrt(cos(e + f*x) + S(1))/sqrt(g*cos(e + f*x)), x), x) + Dist(b*sqrt(a + b*sin(e + f*x))*sqrt(cos(e + f*x) + S(1))/(a*cos(e + f*x) + a + b*sin(e + f*x)), Int(sin(e + f*x)/(sqrt(g*cos(e + f*x))*sqrt(cos(e + f*x) + S(1))), x), x) def replacement2278(a, b, e, f, g, x): return Dist(a*sqrt(a + b*cos(e + f*x))*sqrt(sin(e + f*x) + S(1))/(a*sin(e + f*x) + a + b*cos(e + f*x)), Int(sqrt(sin(e + f*x) + S(1))/sqrt(g*sin(e + f*x)), x), x) + Dist(b*sqrt(a + b*cos(e + f*x))*sqrt(sin(e + f*x) + S(1))/(a*sin(e + f*x) + a + b*cos(e + f*x)), Int(cos(e + f*x)/(sqrt(g*sin(e + f*x))*sqrt(sin(e + f*x) + S(1))), x), x) def replacement2279(a, b, e, f, g, m, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + p), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-1)), x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))/(f*g*(m + p)), x) def replacement2280(a, b, e, f, g, m, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + p), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-1)), x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))/(f*g*(m + p)), x) def replacement2281(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(a*(m + p)), Int((g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**(m + S(1)), x), x) + Simp(g*(g*cos(e + f*x))**(p + S(-1))*(a + b*sin(e + f*x))**(m + S(1))/(b*f*(m + p)), x) def replacement2282(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(a*(m + p)), Int((g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**(m + S(1)), x), x) - Simp(g*(g*sin(e + f*x))**(p + S(-1))*(a + b*cos(e + f*x))**(m + S(1))/(b*f*(m + p)), x) def replacement2283(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b**S(2)*(S(2)*m + p + S(1))), Int((g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**(m + S(2)), x), x) + Simp(S(2)*g*(g*cos(e + f*x))**(p + S(-1))*(a + b*sin(e + f*x))**(m + S(1))/(b*f*(S(2)*m + p + S(1))), x) def replacement2284(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b**S(2)*(S(2)*m + p + S(1))), Int((g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**(m + S(2)), x), x) + Simp(-S(2)*g*(g*sin(e + f*x))**(p + S(-1))*(a + b*cos(e + f*x))**(m + S(1))/(b*f*(S(2)*m + p + S(1))), x) def replacement2285(a, b, e, f, g, m, p, x): return Dist((m + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1)), x), x) + Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2286(a, b, e, f, g, m, p, x): return Dist((m + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1)), x), x) - Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2287(a, b, e, f, g, p, x): return Dist(g**S(2)/a, Int((g*cos(e + f*x))**(p + S(-2)), x), x) + Simp(g*(g*cos(e + f*x))**(p + S(-1))/(b*f*(p + S(-1))), x) def replacement2288(a, b, e, f, g, p, x): return Dist(g**S(2)/a, Int((g*sin(e + f*x))**(p + S(-2)), x), x) - Simp(g*(g*sin(e + f*x))**(p + S(-1))/(b*f*(p + S(-1))), x) def replacement2289(a, b, e, f, g, p, x): return Dist(p/(a*(p + S(-1))), Int((g*cos(e + f*x))**p, x), x) + Simp(b*(g*cos(e + f*x))**(p + S(1))/(a*f*g*(a + b*sin(e + f*x))*(p + S(-1))), x) def replacement2290(a, b, e, f, g, p, x): return Dist(p/(a*(p + S(-1))), Int((g*sin(e + f*x))**p, x), x) - Simp(b*(g*sin(e + f*x))**(p + S(1))/(a*f*g*(a + b*cos(e + f*x))*(p + S(-1))), x) def replacement2291(a, b, e, f, g, x): return -Dist(g*sqrt(a + b*sin(e + f*x))*sqrt(cos(e + f*x) + S(1))/(a*sin(e + f*x) + b*cos(e + f*x) + b), Int(sin(e + f*x)/(sqrt(g*cos(e + f*x))*sqrt(cos(e + f*x) + S(1))), x), x) + Dist(g*sqrt(a + b*sin(e + f*x))*sqrt(cos(e + f*x) + S(1))/(a*cos(e + f*x) + a + b*sin(e + f*x)), Int(sqrt(cos(e + f*x) + S(1))/sqrt(g*cos(e + f*x)), x), x) def replacement2292(a, b, e, f, g, x): return Dist(g*sqrt(a + b*cos(e + f*x))*sqrt(sin(e + f*x) + S(1))/(a*sin(e + f*x) + a + b*cos(e + f*x)), Int(sqrt(sin(e + f*x) + S(1))/sqrt(g*sin(e + f*x)), x), x) - Dist(g*sqrt(a + b*cos(e + f*x))*sqrt(sin(e + f*x) + S(1))/(a*cos(e + f*x) + b*sin(e + f*x) + b), Int(cos(e + f*x)/(sqrt(g*sin(e + f*x))*sqrt(sin(e + f*x) + S(1))), x), x) def replacement2293(a, b, e, f, g, x): return Dist(g**S(2)/(S(2)*a), Int(sqrt(a + b*sin(e + f*x))/sqrt(g*cos(e + f*x)), x), x) + Simp(g*sqrt(g*cos(e + f*x))*sqrt(a + b*sin(e + f*x))/(b*f), x) def replacement2294(a, b, e, f, g, x): return Dist(g**S(2)/(S(2)*a), Int(sqrt(a + b*cos(e + f*x))/sqrt(g*sin(e + f*x)), x), x) - Simp(g*sqrt(g*sin(e + f*x))*sqrt(a + b*cos(e + f*x))/(b*f), x) def replacement2295(a, b, e, f, g, p, x): return Dist(S(2)*a*(p + S(-2))/(S(2)*p + S(-1)), Int((g*cos(e + f*x))**p/(a + b*sin(e + f*x))**(S(3)/2), x), x) + Simp(-S(2)*b*(g*cos(e + f*x))**(p + S(1))/(f*g*(a + b*sin(e + f*x))**(S(3)/2)*(S(2)*p + S(-1))), x) def replacement2296(a, b, e, f, g, p, x): return Dist(S(2)*a*(p + S(-2))/(S(2)*p + S(-1)), Int((g*sin(e + f*x))**p/(a + b*cos(e + f*x))**(S(3)/2), x), x) + Simp(S(2)*b*(g*sin(e + f*x))**(p + S(1))/(f*g*(a + b*cos(e + f*x))**(S(3)/2)*(S(2)*p + S(-1))), x) def replacement2297(a, b, e, f, g, p, x): return Dist(a*(S(2)*p + S(1))/(S(2)*g**S(2)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))/(a + b*sin(e + f*x))**(S(3)/2), x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))/(a*f*g*sqrt(a + b*sin(e + f*x))*(p + S(1))), x) def replacement2298(a, b, e, f, g, p, x): return Dist(a*(S(2)*p + S(1))/(S(2)*g**S(2)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))/(a + b*cos(e + f*x))**(S(3)/2), x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))/(a*f*g*sqrt(a + b*cos(e + f*x))*(p + S(1))), x) def replacement2299(a, b, e, f, g, m, p, x): return Dist(a**m*(g*cos(e + f*x))**(p + S(1))*(S(1) - sin(e + f*x))**(-p/S(2) + S(-1)/2)*(sin(e + f*x) + S(1))**(-p/S(2) + S(-1)/2)/(f*g), Subst(Int((S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2300(a, b, e, f, g, m, p, x): return -Dist(a**m*(g*sin(e + f*x))**(p + S(1))*(S(1) - cos(e + f*x))**(-p/S(2) + S(-1)/2)*(cos(e + f*x) + S(1))**(-p/S(2) + S(-1)/2)/(f*g), Subst(Int((S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2301(a, b, e, f, g, m, p, x): return Dist(a**S(2)*(g*cos(e + f*x))**(p + S(1))*(a - b*sin(e + f*x))**(-p/S(2) + S(-1)/2)*(a + b*sin(e + f*x))**(-p/S(2) + S(-1)/2)/(f*g), Subst(Int((a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2302(a, b, e, f, g, m, p, x): return -Dist(a**S(2)*(g*sin(e + f*x))**(p + S(1))*(a - b*cos(e + f*x))**(-p/S(2) + S(-1)/2)*(a + b*cos(e + f*x))**(-p/S(2) + S(-1)/2)/(f*g), Subst(Int((a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2303(a, b, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-1))*(a*(p + S(2)) + b*(m + p + S(2))*sin(e + f*x)), x), x) - Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m*sin(e + f*x)/(f*g*(p + S(1))), x) def replacement2304(a, b, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-1))*(a*(p + S(2)) + b*(m + p + S(2))*cos(e + f*x)), x), x) + Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m*cos(e + f*x)/(f*g*(p + S(1))), x) def replacement2305(a, b, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-2))*(a**S(2)*(p + S(2)) + a*b*(m + p + S(1))*sin(e + f*x) + b**S(2)*(m + S(-1))), x), x) - Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))*(a*sin(e + f*x) + b)/(f*g*(p + S(1))), x) def replacement2306(a, b, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-2))*(a**S(2)*(p + S(2)) + a*b*(m + p + S(1))*cos(e + f*x) + b**S(2)*(m + S(-1))), x), x) + Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))*(a*cos(e + f*x) + b)/(f*g*(p + S(1))), x) def replacement2307(a, b, e, f, g, m, p, x): return Dist(S(1)/(m + p), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-2))*(a**S(2)*(m + p) + a*b*(S(2)*m + p + S(-1))*sin(e + f*x) + b**S(2)*(m + S(-1))), x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))/(f*g*(m + p)), x) def replacement2308(a, b, e, f, g, m, p, x): return Dist(S(1)/(m + p), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-2))*(a**S(2)*(m + p) + a*b*(S(2)*m + p + S(-1))*cos(e + f*x) + b**S(2)*(m + S(-1))), x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))/(f*g*(m + p)), x) def replacement2309(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b*(m + S(1))), Int((g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**(m + S(1))*sin(e + f*x), x), x) + Simp(g*(g*cos(e + f*x))**(p + S(-1))*(a + b*sin(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement2310(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b*(m + S(1))), Int((g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**(m + S(1))*cos(e + f*x), x), x) - Simp(g*(g*sin(e + f*x))**(p + S(-1))*(a + b*cos(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement2311(a, b, e, f, g, m, p, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1))*(a*(m + S(1)) - b*(m + p + S(2))*sin(e + f*x)), x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))/(f*g*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2312(a, b, e, f, g, m, p, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1))*(a*(m + S(1)) - b*(m + p + S(2))*cos(e + f*x)), x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))/(f*g*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2313(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b*(m + p)), Int((g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**m*(a*sin(e + f*x) + b), x), x) + Simp(g*(g*cos(e + f*x))**(p + S(-1))*(a + b*sin(e + f*x))**(m + S(1))/(b*f*(m + p)), x) def replacement2314(a, b, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b*(m + p)), Int((g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**m*(a*cos(e + f*x) + b), x), x) - Simp(g*(g*sin(e + f*x))**(p + S(-1))*(a + b*cos(e + f*x))**(m + S(1))/(b*f*(m + p)), x) def replacement2315(a, b, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(a**S(2) - b**S(2))*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**m*(a**S(2)*(p + S(2)) + a*b*(m + p + S(3))*sin(e + f*x) - b**S(2)*(m + p + S(2))), x), x) + Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))*(-a*sin(e + f*x) + b)/(f*g*(a**S(2) - b**S(2))*(p + S(1))), x) def replacement2316(a, b, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(a**S(2) - b**S(2))*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**m*(a**S(2)*(p + S(2)) + a*b*(m + p + S(3))*cos(e + f*x) - b**S(2)*(m + p + S(2))), x), x) - Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))*(-a*cos(e + f*x) + b)/(f*g*(a**S(2) - b**S(2))*(p + S(1))), x) def replacement2317(a, b, e, f, g, x): return Dist(S(2)*sqrt(S(2))*sqrt(g*cos(e + f*x))*sqrt((a + b*sin(e + f*x))/((S(1) - sin(e + f*x))*(a - b)))/(f*g*sqrt((sin(e + f*x) + cos(e + f*x) + S(1))/(-sin(e + f*x) + cos(e + f*x) + S(1)))*sqrt(a + b*sin(e + f*x))), Subst(Int(S(1)/sqrt(x**S(4)*(a + b)/(a - b) + S(1)), x), x, sqrt((sin(e + f*x) + cos(e + f*x) + S(1))/(-sin(e + f*x) + cos(e + f*x) + S(1)))), x) def replacement2318(a, b, e, f, g, x): return Dist(-S(2)*sqrt(S(2))*sqrt(g*sin(e + f*x))*sqrt((a + b*cos(e + f*x))/((S(1) - cos(e + f*x))*(a - b)))/(f*g*sqrt((sin(e + f*x) + cos(e + f*x) + S(1))/(sin(e + f*x) - cos(e + f*x) + S(1)))*sqrt(a + b*cos(e + f*x))), Subst(Int(S(1)/sqrt(x**S(4)*(a + b)/(a - b) + S(1)), x), x, sqrt((sin(e + f*x) + cos(e + f*x) + S(1))/(sin(e + f*x) - cos(e + f*x) + S(1)))), x) def replacement2319(a, b, e, f, g, m, p, x): return Simp(g*(g*cos(e + f*x))**(p + S(-1))*(-(S(1) - sin(e + f*x))*(a - b)/((a + b)*(sin(e + f*x) + S(1))))**(m/S(2))*(S(1) - sin(e + f*x))*(a + b*sin(e + f*x))**(m + S(1))*Hypergeometric2F1(m + S(1), m/S(2) + S(1), m + S(2), S(2)*(a + b*sin(e + f*x))/((a + b)*(sin(e + f*x) + S(1))))/(f*(a + b)*(m + S(1))), x) def replacement2320(a, b, e, f, g, m, p, x): return -Simp(g*(g*sin(e + f*x))**(p + S(-1))*(-(S(1) - cos(e + f*x))*(a - b)/((a + b)*(cos(e + f*x) + S(1))))**(m/S(2))*(S(1) - cos(e + f*x))*(a + b*cos(e + f*x))**(m + S(1))*Hypergeometric2F1(m + S(1), m/S(2) + S(1), m + S(2), S(2)*(a + b*cos(e + f*x))/((a + b)*(cos(e + f*x) + S(1))))/(f*(a + b)*(m + S(1))), x) def replacement2321(a, b, e, f, g, m, p, x): return Dist(a/(g**S(2)*(a - b)), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**m/(S(1) - sin(e + f*x)), x), x) + Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))/(f*g*(a - b)*(p + S(1))), x) def replacement2322(a, b, e, f, g, m, p, x): return Dist(a/(g**S(2)*(a - b)), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**m/(S(1) - cos(e + f*x)), x), x) - Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))/(f*g*(a - b)*(p + S(1))), x) def replacement2323(a, b, e, f, g, m, p, x): return Dist(a/(g**S(2)*(a - b)), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**m/(S(1) - sin(e + f*x)), x), x) - Dist(b*(m + p + S(2))/(g**S(2)*(a - b)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**m, x), x) + Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))/(f*g*(a - b)*(p + S(1))), x) def replacement2324(a, b, e, f, g, m, p, x): return Dist(a/(g**S(2)*(a - b)), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**m/(S(1) - cos(e + f*x)), x), x) - Dist(b*(m + p + S(2))/(g**S(2)*(a - b)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**m, x), x) - Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))/(f*g*(a - b)*(p + S(1))), x) def With2325(a, b, e, f, g, x): q = Rt(-a**S(2) + b**S(2), S(2)) return -Dist(a*g/(S(2)*b), Int(S(1)/(sqrt(g*cos(e + f*x))*(-b*cos(e + f*x) + q)), x), x) + Dist(a*g/(S(2)*b), Int(S(1)/(sqrt(g*cos(e + f*x))*(b*cos(e + f*x) + q)), x), x) + Dist(b*g/f, Subst(Int(sqrt(x)/(b**S(2)*x**S(2) + g**S(2)*(a**S(2) - b**S(2))), x), x, g*cos(e + f*x)), x) def With2326(a, b, e, f, g, x): q = Rt(-a**S(2) + b**S(2), S(2)) return -Dist(a*g/(S(2)*b), Int(S(1)/(sqrt(g*sin(e + f*x))*(-b*sin(e + f*x) + q)), x), x) + Dist(a*g/(S(2)*b), Int(S(1)/(sqrt(g*sin(e + f*x))*(b*sin(e + f*x) + q)), x), x) - Dist(b*g/f, Subst(Int(sqrt(x)/(b**S(2)*x**S(2) + g**S(2)*(a**S(2) - b**S(2))), x), x, g*sin(e + f*x)), x) def With2327(a, b, e, f, g, x): q = Rt(-a**S(2) + b**S(2), S(2)) return -Dist(a/(S(2)*q), Int(S(1)/(sqrt(g*cos(e + f*x))*(-b*cos(e + f*x) + q)), x), x) - Dist(a/(S(2)*q), Int(S(1)/(sqrt(g*cos(e + f*x))*(b*cos(e + f*x) + q)), x), x) + Dist(b*g/f, Subst(Int(S(1)/(sqrt(x)*(b**S(2)*x**S(2) + g**S(2)*(a**S(2) - b**S(2)))), x), x, g*cos(e + f*x)), x) def With2328(a, b, e, f, g, x): q = Rt(-a**S(2) + b**S(2), S(2)) return -Dist(a/(S(2)*q), Int(S(1)/(sqrt(g*sin(e + f*x))*(-b*sin(e + f*x) + q)), x), x) - Dist(a/(S(2)*q), Int(S(1)/(sqrt(g*sin(e + f*x))*(b*sin(e + f*x) + q)), x), x) - Dist(b*g/f, Subst(Int(S(1)/(sqrt(x)*(b**S(2)*x**S(2) + g**S(2)*(a**S(2) - b**S(2)))), x), x, g*sin(e + f*x)), x) def replacement2329(a, b, e, f, g, m, p, x): return Simp(g*(g*cos(e + f*x))**(p + S(-1))*(b*(sin(e + f*x) + S(1))/(a + b*sin(e + f*x)))**(S(1)/2 - p/S(2))*(-b*(S(1) - sin(e + f*x))/(a + b*sin(e + f*x)))**(S(1)/2 - p/S(2))*(a + b*sin(e + f*x))**(m + S(1))*AppellF1(-m - p, S(1)/2 - p/S(2), S(1)/2 - p/S(2), -m - p + S(1), (a + b)/(a + b*sin(e + f*x)), (a - b)/(a + b*sin(e + f*x)))/(b*f*(m + p)), x) def replacement2330(a, b, e, f, g, m, p, x): return -Simp(g*(g*sin(e + f*x))**(p + S(-1))*(b*(cos(e + f*x) + S(1))/(a + b*cos(e + f*x)))**(S(1)/2 - p/S(2))*(-b*(S(1) - cos(e + f*x))/(a + b*cos(e + f*x)))**(S(1)/2 - p/S(2))*(a + b*cos(e + f*x))**(m + S(1))*AppellF1(-m - p, S(1)/2 - p/S(2), S(1)/2 - p/S(2), -m - p + S(1), (a + b)/(a + b*cos(e + f*x)), (a - b)/(a + b*cos(e + f*x)))/(b*f*(m + p)), x) def replacement2331(a, b, e, f, g, m, p, x): return Dist(g*(g*cos(e + f*x))**(p + S(-1))*(S(1) - (a + b*sin(e + f*x))/(a - b))**(S(1)/2 - p/S(2))*(S(1) - (a + b*sin(e + f*x))/(a + b))**(S(1)/2 - p/S(2))/f, Subst(Int((a + b*x)**m*(-b*x/(a - b) - b/(a - b))**(p/S(2) + S(-1)/2)*(-b*x/(a + b) + b/(a + b))**(p/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2332(a, b, e, f, g, m, p, x): return -Dist(g*(g*sin(e + f*x))**(p + S(-1))*(S(1) - (a + b*cos(e + f*x))/(a - b))**(S(1)/2 - p/S(2))*(S(1) - (a + b*cos(e + f*x))/(a + b))**(S(1)/2 - p/S(2))/f, Subst(Int((a + b*x)**m*(-b*x/(a - b) - b/(a - b))**(p/S(2) + S(-1)/2)*(-b*x/(a + b) + b/(a + b))**(p/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2333(a, b, e, f, g, m, p, x): return Dist(g**(S(2)*IntPart(p))*(g/cos(e + f*x))**FracPart(p)*(g*cos(e + f*x))**FracPart(p), Int((g*cos(e + f*x))**(-p)*(a + b*sin(e + f*x))**m, x), x) def replacement2334(a, b, e, f, g, m, p, x): return Dist(g**(S(2)*IntPart(p))*(g/sin(e + f*x))**FracPart(p)*(g*sin(e + f*x))**FracPart(p), Int((g*sin(e + f*x))**(-p)*(a + b*cos(e + f*x))**m, x), x) def replacement2335(a, b, e, f, g, p, x): return Dist(S(1)/a, Int((g*tan(e + f*x))**p/cos(e + f*x)**S(2), x), x) - Dist(S(1)/(b*g), Int((g*tan(e + f*x))**(p + S(1))/cos(e + f*x), x), x) def replacement2336(a, b, e, f, g, p, x): return Dist(S(1)/a, Int((g/tan(e + f*x))**p/sin(e + f*x)**S(2), x), x) - Dist(S(1)/(b*g), Int((g/tan(e + f*x))**(p + S(1))/sin(e + f*x), x), x) def replacement2337(a, b, e, f, m, p, x): return Dist(S(1)/f, Subst(Int(x**p*(a - x)**(-p/S(2) + S(-1)/2)*(a + x)**(m - p/S(2) + S(-1)/2), x), x, b*sin(e + f*x)), x) def replacement2338(a, b, e, f, m, p, x): return -Dist(S(1)/f, Subst(Int(x**p*(a - x)**(-p/S(2) + S(-1)/2)*(a + x)**(m - p/S(2) + S(-1)/2), x), x, b*cos(e + f*x)), x) def replacement2339(a, b, e, f, m, p, x): return Dist(a**p, Int((a - b*sin(e + f*x))**(-m)*sin(e + f*x)**p, x), x) def replacement2340(a, b, e, f, m, p, x): return Dist(a**p, Int((a - b*cos(e + f*x))**(-m)*cos(e + f*x)**p, x), x) def replacement2341(a, b, e, f, m, p, x): return Dist(a**p, Int(ExpandIntegrand((a - b*sin(e + f*x))**(-p/S(2))*(a + b*sin(e + f*x))**(m - p/S(2))*sin(e + f*x)**p, x), x), x) def replacement2342(a, b, e, f, m, p, x): return Dist(a**p, Int(ExpandIntegrand((a - b*cos(e + f*x))**(-p/S(2))*(a + b*cos(e + f*x))**(m - p/S(2))*cos(e + f*x)**p, x), x), x) def replacement2343(a, b, e, f, g, m, p, x): return Int(ExpandIntegrand((g*tan(e + f*x))**p, (a + b*sin(e + f*x))**m, x), x) def replacement2344(a, b, e, f, g, m, p, x): return Int(ExpandIntegrand((g/tan(e + f*x))**p, (a + b*cos(e + f*x))**m, x), x) def replacement2345(a, b, e, f, g, m, p, x): return Dist(a**(S(2)*m), Int(ExpandIntegrand((g*tan(e + f*x))**p*(S(1)/cos(e + f*x))**(-m), (a/cos(e + f*x) - b*tan(e + f*x))**(-m), x), x), x) def replacement2346(a, b, e, f, g, m, p, x): return Dist(a**(S(2)*m), Int(ExpandIntegrand((g/tan(e + f*x))**p*(S(1)/sin(e + f*x))**(-m), (a/sin(e + f*x) - b/tan(e + f*x))**(-m), x), x), x) def replacement2347(a, b, e, f, m, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(-1))), Int((a + b*sin(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + S(-1))*sin(e + f*x))/cos(e + f*x)**S(2), x), x) + Simp(b*(a + b*sin(e + f*x))**m/(a*f*(S(2)*m + S(-1))*cos(e + f*x)), x) def replacement2348(a, b, e, f, m, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(-1))), Int((a + b*cos(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + S(-1))*cos(e + f*x))/sin(e + f*x)**S(2), x), x) - Simp(b*(a + b*cos(e + f*x))**m/(a*f*(S(2)*m + S(-1))*sin(e + f*x)), x) def replacement2349(a, b, e, f, m, x): return Dist(S(1)/(b*m), Int((a + b*sin(e + f*x))**m*(a*sin(e + f*x) + b*(m + S(1)))/cos(e + f*x)**S(2), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))/(b*f*m*cos(e + f*x)), x) def replacement2350(a, b, e, f, m, x): return Dist(S(1)/(b*m), Int((a + b*cos(e + f*x))**m*(a*cos(e + f*x) + b*(m + S(1)))/sin(e + f*x)**S(2), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))/(b*f*m*sin(e + f*x)), x) def replacement2351(a, b, e, f, m, x): return -Int((S(1) - S(2)*sin(e + f*x)**S(2))*(a + b*sin(e + f*x))**m/cos(e + f*x)**S(4), x) + Int((a + b*sin(e + f*x))**m, x) def replacement2352(a, b, e, f, m, x): return -Int((S(1) - S(2)*cos(e + f*x)**S(2))*(a + b*cos(e + f*x))**m/sin(e + f*x)**S(4), x) + Int((a + b*cos(e + f*x))**m, x) def replacement2353(a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b*sin(e + f*x))**(m + S(1))*(-a*(m + S(1))*sin(e + f*x) + b*m)/sin(e + f*x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))/(a*f*tan(e + f*x)), x) def replacement2354(a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b*cos(e + f*x))**(m + S(1))*(-a*(m + S(1))*cos(e + f*x) + b*m)/cos(e + f*x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*tan(e + f*x)/(a*f), x) def replacement2355(a, b, e, f, m, x): return Dist(S(1)/a, Int((a + b*sin(e + f*x))**m*(-a*(m + S(1))*sin(e + f*x) + b*m)/sin(e + f*x), x), x) - Simp((a + b*sin(e + f*x))**m/(f*tan(e + f*x)), x) def replacement2356(a, b, e, f, m, x): return Dist(S(1)/a, Int((a + b*cos(e + f*x))**m*(-a*(m + S(1))*cos(e + f*x) + b*m)/cos(e + f*x), x), x) + Simp((a + b*cos(e + f*x))**m*tan(e + f*x)/f, x) def replacement2357(a, b, e, f, m, x): return Dist(a**(S(-2)), Int((a + b*sin(e + f*x))**(m + S(2))*(sin(e + f*x)**S(2) + S(1))/sin(e + f*x)**S(4), x), x) + Dist(-S(2)/(a*b), Int((a + b*sin(e + f*x))**(m + S(2))/sin(e + f*x)**S(3), x), x) def replacement2358(a, b, e, f, m, x): return Dist(a**(S(-2)), Int((a + b*cos(e + f*x))**(m + S(2))*(cos(e + f*x)**S(2) + S(1))/cos(e + f*x)**S(4), x), x) + Dist(-S(2)/(a*b), Int((a + b*cos(e + f*x))**(m + S(2))/cos(e + f*x)**S(3), x), x) def replacement2359(a, b, e, f, m, x): return Int((S(1) - S(2)*sin(e + f*x)**S(2))*(a + b*sin(e + f*x))**m/sin(e + f*x)**S(4), x) + Int((a + b*sin(e + f*x))**m, x) def replacement2360(a, b, e, f, m, x): return Int((S(1) - S(2)*cos(e + f*x)**S(2))*(a + b*cos(e + f*x))**m/cos(e + f*x)**S(4), x) + Int((a + b*cos(e + f*x))**m, x) def replacement2361(a, b, e, f, m, p, x): return Dist(sqrt(a - b*sin(e + f*x))*sqrt(a + b*sin(e + f*x))/(b*f*cos(e + f*x)), Subst(Int(x**p*(a - x)**(-p/S(2) + S(-1)/2)*(a + x)**(m - p/S(2) + S(-1)/2), x), x, b*sin(e + f*x)), x) def replacement2362(a, b, e, f, m, p, x): return -Dist(sqrt(a - b*cos(e + f*x))*sqrt(a + b*cos(e + f*x))/(b*f*sin(e + f*x)), Subst(Int(x**p*(a - x)**(-p/S(2) + S(-1)/2)*(a + x)**(m - p/S(2) + S(-1)/2), x), x, b*cos(e + f*x)), x) def replacement2363(a, b, e, f, g, m, p, x): return Dist((b*sin(e + f*x))**(-p + S(-1))*(g*tan(e + f*x))**(p + S(1))*(a - b*sin(e + f*x))**(p/S(2) + S(1)/2)*(a + b*sin(e + f*x))**(p/S(2) + S(1)/2)/(f*g), Subst(Int(x**p*(a - x)**(-p/S(2) + S(-1)/2)*(a + x)**(m - p/S(2) + S(-1)/2), x), x, b*sin(e + f*x)), x) def replacement2364(a, b, e, f, g, m, p, x): return -Dist((b*cos(e + f*x))**(-p + S(-1))*(g/tan(e + f*x))**(p + S(1))*(a - b*cos(e + f*x))**(p/S(2) + S(1)/2)*(a + b*cos(e + f*x))**(p/S(2) + S(1)/2)/(f*g), Subst(Int(x**p*(a - x)**(-p/S(2) + S(-1)/2)*(a + x)**(m - p/S(2) + S(-1)/2), x), x, b*cos(e + f*x)), x) def replacement2365(a, b, e, f, m, p, x): return Dist(S(1)/f, Subst(Int(x**p*(a + x)**m*(b**S(2) - x**S(2))**(-p/S(2) + S(-1)/2), x), x, b*sin(e + f*x)), x) def replacement2366(a, b, e, f, m, p, x): return -Dist(S(1)/f, Subst(Int(x**p*(a + x)**m*(b**S(2) - x**S(2))**(-p/S(2) + S(-1)/2), x), x, b*cos(e + f*x)), x) def replacement2367(a, b, e, f, g, m, p, x): return Int(ExpandIntegrand((g*tan(e + f*x))**p, (a + b*sin(e + f*x))**m, x), x) def replacement2368(a, b, e, f, g, m, p, x): return Int(ExpandIntegrand((g/tan(e + f*x))**p, (a + b*cos(e + f*x))**m, x), x) def replacement2369(a, b, e, f, m, x): return Int((S(1) - sin(e + f*x)**S(2))*(a + b*sin(e + f*x))**m/sin(e + f*x)**S(2), x) def replacement2370(a, b, e, f, m, x): return Int((S(1) - cos(e + f*x)**S(2))*(a + b*cos(e + f*x))**m/cos(e + f*x)**S(2), x) def replacement2371(a, b, e, f, m, x): return -Dist(S(1)/(S(3)*a**S(2)*b*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(S(6)*a**S(2) + a*b*(m + S(1))*sin(e + f*x) - b**S(2)*(m + S(-2))*(m + S(-1)) - (S(3)*a**S(2) - b**S(2)*m*(m + S(-2)))*sin(e + f*x)**S(2), x)/sin(e + f*x)**S(3), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(S(3)*a*f*sin(e + f*x)**S(3)), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(S(3)*a**S(2) + b**S(2)*(m + S(-2)))*cos(e + f*x)/(S(3)*a**S(2)*b*f*(m + S(1))*sin(e + f*x)**S(2)), x) def replacement2372(a, b, e, f, m, x): return -Dist(S(1)/(S(3)*a**S(2)*b*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(S(6)*a**S(2) + a*b*(m + S(1))*cos(e + f*x) - b**S(2)*(m + S(-2))*(m + S(-1)) - (S(3)*a**S(2) - b**S(2)*m*(m + S(-2)))*cos(e + f*x)**S(2), x)/cos(e + f*x)**S(3), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(S(3)*a*f*cos(e + f*x)**S(3)), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(S(3)*a**S(2) + b**S(2)*(m + S(-2)))*sin(e + f*x)/(S(3)*a**S(2)*b*f*(m + S(1))*cos(e + f*x)**S(2)), x) def replacement2373(a, b, e, f, m, x): return -Dist(S(1)/(S(6)*a**S(2)), Int((a + b*sin(e + f*x))**m*Simp(S(8)*a**S(2) + a*b*m*sin(e + f*x) - b**S(2)*(m + S(-2))*(m + S(-1)) - (S(6)*a**S(2) - b**S(2)*m*(m + S(-2)))*sin(e + f*x)**S(2), x)/sin(e + f*x)**S(2), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(S(3)*a*f*sin(e + f*x)**S(3)), x) - Simp(b*(a + b*sin(e + f*x))**(m + S(1))*(m + S(-2))*cos(e + f*x)/(S(6)*a**S(2)*f*sin(e + f*x)**S(2)), x) def replacement2374(a, b, e, f, m, x): return -Dist(S(1)/(S(6)*a**S(2)), Int((a + b*cos(e + f*x))**m*Simp(S(8)*a**S(2) + a*b*m*cos(e + f*x) - b**S(2)*(m + S(-2))*(m + S(-1)) - (S(6)*a**S(2) - b**S(2)*m*(m + S(-2)))*cos(e + f*x)**S(2), x)/cos(e + f*x)**S(2), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(S(3)*a*f*cos(e + f*x)**S(3)), x) + Simp(b*(a + b*cos(e + f*x))**(m + S(1))*(m + S(-2))*sin(e + f*x)/(S(6)*a**S(2)*f*cos(e + f*x)**S(2)), x) def replacement2375(a, b, e, f, m, x): return Dist(S(1)/(S(20)*a**S(2)*b**S(2)*m*(m + S(-1))), Int((a + b*sin(e + f*x))**m*Simp(S(60)*a**S(4) - S(44)*a**S(2)*b**S(2)*m*(m + S(-1)) + a*b*m*(S(20)*a**S(2) - b**S(2)*m*(m + S(-1)))*sin(e + f*x) + b**S(4)*m*(m + S(-4))*(m + S(-3))*(m + S(-1)) - (S(40)*a**S(4) - S(20)*a**S(2)*b**S(2)*(m + S(-1))*(S(2)*m + S(1)) + b**S(4)*m*(m + S(-4))*(m + S(-2))*(m + S(-1)))*sin(e + f*x)**S(2), x)/sin(e + f*x)**S(4), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(S(5)*a*f*sin(e + f*x)**S(5)), x) + Simp((a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*m*sin(e + f*x)**S(2)), x) - Simp(b*(a + b*sin(e + f*x))**(m + S(1))*(m + S(-4))*cos(e + f*x)/(S(20)*a**S(2)*f*sin(e + f*x)**S(4)), x) + Simp(a*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b**S(2)*f*m*(m + S(-1))*sin(e + f*x)**S(3)), x) def replacement2376(a, b, e, f, m, x): return Dist(S(1)/(S(20)*a**S(2)*b**S(2)*m*(m + S(-1))), Int((a + b*cos(e + f*x))**m*Simp(S(60)*a**S(4) - S(44)*a**S(2)*b**S(2)*m*(m + S(-1)) + a*b*m*(S(20)*a**S(2) - b**S(2)*m*(m + S(-1)))*cos(e + f*x) + b**S(4)*m*(m + S(-4))*(m + S(-3))*(m + S(-1)) - (S(40)*a**S(4) - S(20)*a**S(2)*b**S(2)*(m + S(-1))*(S(2)*m + S(1)) + b**S(4)*m*(m + S(-4))*(m + S(-2))*(m + S(-1)))*cos(e + f*x)**S(2), x)/cos(e + f*x)**S(4), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(S(5)*a*f*cos(e + f*x)**S(5)), x) - Simp((a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*m*cos(e + f*x)**S(2)), x) + Simp(b*(a + b*cos(e + f*x))**(m + S(1))*(m + S(-4))*sin(e + f*x)/(S(20)*a**S(2)*f*cos(e + f*x)**S(4)), x) - Simp(a*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b**S(2)*f*m*(m + S(-1))*cos(e + f*x)**S(3)), x) def replacement2377(a, b, e, f, g, p, x): return Dist(a/(a**S(2) - b**S(2)), Int((g*tan(e + f*x))**p/sin(e + f*x)**S(2), x), x) - Dist(a**S(2)*g**S(2)/(a**S(2) - b**S(2)), Int((g*tan(e + f*x))**(p + S(-2))/(a + b*sin(e + f*x)), x), x) - Dist(b*g/(a**S(2) - b**S(2)), Int((g*tan(e + f*x))**(p + S(-1))/cos(e + f*x), x), x) def replacement2378(a, b, e, f, g, p, x): return Dist(a/(a**S(2) - b**S(2)), Int((g/tan(e + f*x))**p/cos(e + f*x)**S(2), x), x) - Dist(a**S(2)*g**S(2)/(a**S(2) - b**S(2)), Int((g/tan(e + f*x))**(p + S(-2))/(a + b*cos(e + f*x)), x), x) - Dist(b*g/(a**S(2) - b**S(2)), Int((g/tan(e + f*x))**(p + S(-1))/sin(e + f*x), x), x) def replacement2379(a, b, e, f, g, p, x): return Dist(S(1)/a, Int((g*tan(e + f*x))**p/cos(e + f*x)**S(2), x), x) - Dist(b/(a**S(2)*g), Int((g*tan(e + f*x))**(p + S(1))/cos(e + f*x), x), x) - Dist((a**S(2) - b**S(2))/(a**S(2)*g**S(2)), Int((g*tan(e + f*x))**(p + S(2))/(a + b*sin(e + f*x)), x), x) def replacement2380(a, b, e, f, g, p, x): return Dist(S(1)/a, Int((g/tan(e + f*x))**p/sin(e + f*x)**S(2), x), x) - Dist(b/(a**S(2)*g), Int((g/tan(e + f*x))**(p + S(1))/sin(e + f*x), x), x) - Dist((a**S(2) - b**S(2))/(a**S(2)*g**S(2)), Int((g/tan(e + f*x))**(p + S(2))/(a + b*cos(e + f*x)), x), x) def replacement2381(a, b, e, f, g, x): return Dist(sqrt(g*tan(e + f*x))*sqrt(cos(e + f*x))/sqrt(sin(e + f*x)), Int(sqrt(sin(e + f*x))/((a + b*sin(e + f*x))*sqrt(cos(e + f*x))), x), x) def replacement2382(a, b, e, f, g, x): return Dist(sqrt(g/tan(e + f*x))*sqrt(sin(e + f*x))/sqrt(cos(e + f*x)), Int(sqrt(cos(e + f*x))/((a + b*cos(e + f*x))*sqrt(sin(e + f*x))), x), x) def replacement2383(a, b, e, f, g, x): return Dist(sqrt(sin(e + f*x))/(sqrt(g*tan(e + f*x))*sqrt(cos(e + f*x))), Int(sqrt(cos(e + f*x))/((a + b*sin(e + f*x))*sqrt(sin(e + f*x))), x), x) def replacement2384(a, b, e, f, g, x): return Dist(sqrt(cos(e + f*x))/(sqrt(g/tan(e + f*x))*sqrt(sin(e + f*x))), Int(sqrt(sin(e + f*x))/((a + b*cos(e + f*x))*sqrt(cos(e + f*x))), x), x) def replacement2385(a, b, e, f, m, p, x): return Int(ExpandIntegrand((S(1) - sin(e + f*x)**S(2))**(-p/S(2))*(a + b*sin(e + f*x))**m*sin(e + f*x)**p, x), x) def replacement2386(a, b, e, f, m, p, x): return Int(ExpandIntegrand((S(1) - cos(e + f*x)**S(2))**(-p/S(2))*(a + b*cos(e + f*x))**m*cos(e + f*x)**p, x), x) def replacement2387(a, b, e, f, g, m, p, x): return Int((g*tan(e + f*x))**p*(a + b*sin(e + f*x))**m, x) def replacement2388(a, b, e, f, g, m, p, x): return Int((g/tan(e + f*x))**p*(a + b*cos(e + f*x))**m, x) def replacement2389(a, b, e, f, g, m, p, x): return Dist(g**(S(2)*IntPart(p))*(g/tan(e + f*x))**FracPart(p)*(g*tan(e + f*x))**FracPart(p), Int((g*tan(e + f*x))**(-p)*(a + b*sin(e + f*x))**m, x), x) def replacement2390(a, b, e, f, g, m, p, x): return Dist(g**(S(2)*IntPart(p))*(g/tan(e + f*x))**FracPart(p)*(g*tan(e + f*x))**FracPart(p), Int((g/tan(e + f*x))**(-p)*(a + b*cos(e + f*x))**m, x), x) def replacement2391(a, b, c, d, e, f, x): return Simp(x*(S(2)*a*c + b*d)/S(2), x) - Simp((a*d + b*c)*cos(e + f*x)/f, x) - Simp(b*d*sin(e + f*x)*cos(e + f*x)/(S(2)*f), x) def replacement2392(a, b, c, d, e, f, x): return Simp(x*(S(2)*a*c + b*d)/S(2), x) + Simp((a*d + b*c)*sin(e + f*x)/f, x) + Simp(b*d*sin(e + f*x)*cos(e + f*x)/(S(2)*f), x) def replacement2393(a, b, c, d, e, f, x): return -Dist((-a*d + b*c)/d, Int(S(1)/(c + d*sin(e + f*x)), x), x) + Simp(b*x/d, x) def replacement2394(a, b, c, d, e, f, x): return -Dist((-a*d + b*c)/d, Int(S(1)/(c + d*cos(e + f*x)), x), x) + Simp(b*x/d, x) def replacement2395(a, b, c, d, e, f, m, n, x): return Dist(a**m*c**m, Int((c + d*sin(e + f*x))**(-m + n)*cos(e + f*x)**(S(2)*m), x), x) def replacement2396(a, b, c, d, e, f, m, n, x): return Dist(a**m*c**m, Int((c + d*cos(e + f*x))**(-m + n)*sin(e + f*x)**(S(2)*m), x), x) def replacement2397(a, b, c, d, e, f, x): return Dist(a*c*cos(e + f*x)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), Int(cos(e + f*x)/(c + d*sin(e + f*x)), x), x) def replacement2398(a, b, c, d, e, f, x): return Dist(a*c*sin(e + f*x)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), Int(sin(e + f*x)/(c + d*cos(e + f*x)), x), x) def replacement2399(a, b, c, d, e, f, n, x): return Simp(-S(2)*b*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*sqrt(a + b*sin(e + f*x))*(S(2)*n + S(1))), x) def replacement2400(a, b, c, d, e, f, n, x): return Simp(S(2)*b*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*sqrt(a + b*cos(e + f*x))*(S(2)*n + S(1))), x) def replacement2401(a, b, c, d, e, f, m, n, x): return -Dist(b*(S(2)*m + S(-1))/(d*(S(2)*n + S(1))), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1)), x), x) + Simp(-S(2)*b*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(S(2)*n + S(1))), x) def replacement2402(a, b, c, d, e, f, m, n, x): return -Dist(b*(S(2)*m + S(-1))/(d*(S(2)*n + S(1))), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1)), x), x) + Simp(S(2)*b*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(S(2)*n + S(1))), x) def replacement2403(a, b, c, d, e, f, m, n, x): return Dist(a*(S(2)*m + S(-1))/(m + n), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n, x), x) - Simp(b*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(m + n)), x) def replacement2404(a, b, c, d, e, f, m, n, x): return Dist(a*(S(2)*m + S(-1))/(m + n), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n, x), x) + Simp(b*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(m + n)), x) def replacement2405(a, b, c, d, e, f, x): return Dist(cos(e + f*x)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), Int(S(1)/cos(e + f*x), x), x) def replacement2406(a, b, c, d, e, f, x): return Dist(sin(e + f*x)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), Int(S(1)/sin(e + f*x), x), x) def replacement2407(a, b, c, d, e, f, m, n, x): return Simp(b*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2408(a, b, c, d, e, f, m, n, x): return -Simp(b*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2409(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n, x), x) + Simp(b*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2410(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n, x), x) - Simp(b*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2411(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n, x), x) + Simp(b*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2412(a, b, c, d, e, f, m, n, x): return Dist((m + n + S(1))/(a*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n, x), x) - Simp(b*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2413(a, b, c, d, e, f, m, n, x): return Dist(a**IntPart(m)*c**IntPart(m)*(a + b*sin(e + f*x))**FracPart(m)*(c + d*sin(e + f*x))**FracPart(m)*cos(e + f*x)**(-S(2)*FracPart(m)), Int((c + d*sin(e + f*x))**(-m + n)*cos(e + f*x)**(S(2)*m), x), x) def replacement2414(a, b, c, d, e, f, m, n, x): return Dist(a**IntPart(m)*c**IntPart(m)*(a + b*cos(e + f*x))**FracPart(m)*(c + d*cos(e + f*x))**FracPart(m)*sin(e + f*x)**(-S(2)*FracPart(m)), Int((c + d*cos(e + f*x))**(-m + n)*sin(e + f*x)**(S(2)*m), x), x) def replacement2415(a, b, c, d, e, f, x): return Dist(S(1)/d, Int(Simp(a**S(2)*d - b*(-S(2)*a*d + b*c)*sin(e + f*x), x)/(c + d*sin(e + f*x)), x), x) - Simp(b**S(2)*cos(e + f*x)/(d*f), x) def replacement2416(a, b, c, d, e, f, x): return Dist(S(1)/d, Int(Simp(a**S(2)*d - b*(-S(2)*a*d + b*c)*cos(e + f*x), x)/(c + d*cos(e + f*x)), x), x) + Simp(b**S(2)*sin(e + f*x)/(d*f), x) def replacement2417(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/(a + b*sin(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/(c + d*sin(e + f*x)), x), x) def replacement2418(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/(a + b*cos(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/(c + d*cos(e + f*x)), x), x) def replacement2419(b, c, d, e, f, m, x): return Dist(c, Int((b*sin(e + f*x))**m, x), x) + Dist(d/b, Int((b*sin(e + f*x))**(m + S(1)), x), x) def replacement2420(b, c, d, e, f, m, x): return Dist(c, Int((b*cos(e + f*x))**m, x), x) + Dist(d/b, Int((b*cos(e + f*x))**(m + S(1)), x), x) def replacement2421(a, b, c, d, e, f, m, x): return -Simp(d*(a + b*sin(e + f*x))**m*cos(e + f*x)/(f*(m + S(1))), x) def replacement2422(a, b, c, d, e, f, m, x): return Simp(d*(a + b*cos(e + f*x))**m*sin(e + f*x)/(f*(m + S(1))), x) def replacement2423(a, b, c, d, e, f, m, x): return Dist((a*d*m + b*c*(m + S(1)))/(a*b*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1)), x), x) + Simp((a + b*sin(e + f*x))**m*(-a*d + b*c)*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2424(a, b, c, d, e, f, m, x): return Dist((a*d*m + b*c*(m + S(1)))/(a*b*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1)), x), x) - Simp((a + b*cos(e + f*x))**m*(-a*d + b*c)*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2425(a, b, c, d, e, f, m, x): return Dist((a*d*m + b*c*(m + S(1)))/(b*(m + S(1))), Int((a + b*sin(e + f*x))**m, x), x) - Simp(d*(a + b*sin(e + f*x))**m*cos(e + f*x)/(f*(m + S(1))), x) def replacement2426(a, b, c, d, e, f, m, x): return Dist((a*d*m + b*c*(m + S(1)))/(b*(m + S(1))), Int((a + b*cos(e + f*x))**m, x), x) + Simp(d*(a + b*cos(e + f*x))**m*sin(e + f*x)/(f*(m + S(1))), x) def replacement2427(a, b, c, d, e, f, x): return Dist(d/b, Int(sqrt(a + b*sin(e + f*x)), x), x) + Dist((-a*d + b*c)/b, Int(S(1)/sqrt(a + b*sin(e + f*x)), x), x) def replacement2428(a, b, c, d, e, f, x): return Dist(d/b, Int(sqrt(a + b*cos(e + f*x)), x), x) + Dist((-a*d + b*c)/b, Int(S(1)/sqrt(a + b*cos(e + f*x)), x), x) def replacement2429(a, b, c, d, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b*sin(e + f*x))**(m + S(-1))*Simp(a*c*(m + S(1)) + b*d*m + (a*d*m + b*c*(m + S(1)))*sin(e + f*x), x), x), x) - Simp(d*(a + b*sin(e + f*x))**m*cos(e + f*x)/(f*(m + S(1))), x) def replacement2430(a, b, c, d, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((a + b*cos(e + f*x))**(m + S(-1))*Simp(a*c*(m + S(1)) + b*d*m + (a*d*m + b*c*(m + S(1)))*cos(e + f*x), x), x), x) + Simp(d*(a + b*cos(e + f*x))**m*sin(e + f*x)/(f*(m + S(1))), x) def replacement2431(a, b, c, d, e, f, m, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp((m + S(1))*(a*c - b*d) - (m + S(2))*(-a*d + b*c)*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(-a*d + b*c)*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2432(a, b, c, d, e, f, m, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp((m + S(1))*(a*c - b*d) - (m + S(2))*(-a*d + b*c)*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(-a*d + b*c)*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2433(a, b, c, d, e, f, m, x): return Dist(c*cos(e + f*x)/(f*sqrt(S(1) - sin(e + f*x))*sqrt(sin(e + f*x) + S(1))), Subst(Int(sqrt(S(1) + d*x/c)*(a + b*x)**m/sqrt(S(1) - d*x/c), x), x, sin(e + f*x)), x) def replacement2434(a, b, c, d, e, f, m, x): return -Dist(c*sin(e + f*x)/(f*sqrt(S(1) - cos(e + f*x))*sqrt(cos(e + f*x) + S(1))), Subst(Int(sqrt(S(1) + d*x/c)*(a + b*x)**m/sqrt(S(1) - d*x/c), x), x, cos(e + f*x)), x) def replacement2435(a, b, c, d, e, f, m, x): return Dist(d/b, Int((a + b*sin(e + f*x))**(m + S(1)), x), x) + Dist((-a*d + b*c)/b, Int((a + b*sin(e + f*x))**m, x), x) def replacement2436(a, b, c, d, e, f, m, x): return Dist(d/b, Int((a + b*cos(e + f*x))**(m + S(1)), x), x) + Dist((-a*d + b*c)/b, Int((a + b*cos(e + f*x))**m, x), x) def replacement2437(a, b, d, e, f, m, n, x): return Int(ExpandTrig((d*sin(e + f*x))**n*(a + b*sin(e + f*x))**m, x), x) def replacement2438(a, b, d, e, f, m, n, x): return Int(ExpandTrig((d*cos(e + f*x))**n*(a + b*cos(e + f*x))**m, x), x) def replacement2439(a, b, e, f, m, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + S(1))*sin(e + f*x)), x), x) + Simp(b*(a + b*sin(e + f*x))**m*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2440(a, b, e, f, m, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + S(1))*cos(e + f*x)), x), x) - Simp(b*(a + b*cos(e + f*x))**m*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2441(a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*sin(e + f*x))**m*(-a*sin(e + f*x) + b*(m + S(1))), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(2))), x) def replacement2442(a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*cos(e + f*x))**m*(-a*cos(e + f*x) + b*(m + S(1))), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(2))), x) def replacement2443(a, b, c, d, e, f, m, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(a*c*d*(m + S(-1)) + b*(c**S(2)*(m + S(1)) + d**S(2)) + d*(a*d*(m + S(-1)) + b*c*(m + S(2)))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))*(-a*d + b*c)*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2444(a, b, c, d, e, f, m, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(a*c*d*(m + S(-1)) + b*(c**S(2)*(m + S(1)) + d**S(2)) + d*(a*d*(m + S(-1)) + b*c*(m + S(2)))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))*(-a*d + b*c)*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2445(a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*sin(e + f*x))**m*Simp(b*(c**S(2)*(m + S(2)) + d**S(2)*(m + S(1))) - d*(a*d - S(2)*b*c*(m + S(2)))*sin(e + f*x), x), x), x) - Simp(d**S(2)*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(2))), x) def replacement2446(a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*cos(e + f*x))**m*Simp(b*(c**S(2)*(m + S(2)) + d**S(2)*(m + S(1))) - d*(a*d - S(2)*b*c*(m + S(2)))*cos(e + f*x), x), x), x) + Simp(d**S(2)*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(2))), x) def replacement2447(a, b, c, d, e, f, m, n, x): return Dist(b**S(2)/(d*(n + S(1))*(a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**(n + S(1))*Simp(a*c*(m + S(-2)) - b*d*(m - S(2)*n + S(-4)) - (-a*d*(m + S(2)*n + S(1)) + b*c*(m + S(-1)))*sin(e + f*x), x), x), x) - Simp(b**S(2)*(a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**(n + S(1))*(-a*d + b*c)*cos(e + f*x)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement2448(a, b, c, d, e, f, m, n, x): return Dist(b**S(2)/(d*(n + S(1))*(a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**(n + S(1))*Simp(a*c*(m + S(-2)) - b*d*(m - S(2)*n + S(-4)) - (-a*d*(m + S(2)*n + S(1)) + b*c*(m + S(-1)))*cos(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**(n + S(1))*(-a*d + b*c)*sin(e + f*x)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement2449(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**n*Simp(a**S(2)*d*(m + n) + a*b*c*(m + S(-2)) + b**S(2)*d*(n + S(1)) - b*(-a*d*(S(3)*m + S(2)*n + S(-2)) + b*c*(m + S(-1)))*sin(e + f*x), x), x), x) - Simp(b**S(2)*(a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n)), x) def replacement2450(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**n*Simp(a**S(2)*d*(m + n) + a*b*c*(m + S(-2)) + b**S(2)*d*(n + S(1)) - b*(-a*d*(S(3)*m + S(2)*n + S(-2)) + b*c*(m + S(-1)))*cos(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n)), x) def replacement2451(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(-1))*Simp(a*d*n - b*c*(m + S(1)) - b*d*(m + n + S(1))*sin(e + f*x), x), x), x) + Simp(b*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2452(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(-1))*Simp(a*d*n - b*c*(m + S(1)) - b*d*(m + n + S(1))*cos(e + f*x), x), x), x) - Simp(b*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2453(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(-2))*Simp(a*c*d*(m - n + S(1)) + b*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(-1))) + d*(a*d*(m - n + S(1)) + b*c*(m + n))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(-1))*(-a*d + b*c)*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2454(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(-2))*Simp(a*c*d*(m - n + S(1)) + b*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(-1))) + d*(a*d*(m - n + S(1)) + b*c*(m + n))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(-1))*(-a*d + b*c)*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2455(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(-a*d*(S(2)*m + n + S(2)) + b*c*(m + S(1)) + b*d*(m + n + S(2))*sin(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(a*f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2456(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(-a*d*(S(2)*m + n + S(2)) + b*c*(m + S(1)) + b*d*(m + n + S(2))*cos(e + f*x), x), x), x) - Simp(b**S(2)*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(a*f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2457(a, b, c, d, e, f, n, x): return -Dist(d/(a*b), Int((c + d*sin(e + f*x))**(n + S(-2))*Simp(-a*c*n + b*d*(n + S(-1)) + (-a*d*n + b*c*(n + S(-1)))*sin(e + f*x), x), x), x) - Simp((c + d*sin(e + f*x))**(n + S(-1))*(-a*d + b*c)*cos(e + f*x)/(a*f*(a + b*sin(e + f*x))), x) def replacement2458(a, b, c, d, e, f, n, x): return -Dist(d/(a*b), Int((c + d*cos(e + f*x))**(n + S(-2))*Simp(-a*c*n + b*d*(n + S(-1)) + (-a*d*n + b*c*(n + S(-1)))*cos(e + f*x), x), x), x) + Simp((c + d*cos(e + f*x))**(n + S(-1))*(-a*d + b*c)*sin(e + f*x)/(a*f*(a + b*cos(e + f*x))), x) def replacement2459(a, b, c, d, e, f, n, x): return Dist(d/(a*(-a*d + b*c)), Int((c + d*sin(e + f*x))**n*(a*n - b*(n + S(1))*sin(e + f*x)), x), x) - Simp(b**S(2)*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(a*f*(a + b*sin(e + f*x))*(-a*d + b*c)), x) def replacement2460(a, b, c, d, e, f, n, x): return Dist(d/(a*(-a*d + b*c)), Int((c + d*cos(e + f*x))**n*(a*n - b*(n + S(1))*cos(e + f*x)), x), x) + Simp(b**S(2)*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(a*f*(a + b*cos(e + f*x))*(-a*d + b*c)), x) def replacement2461(a, b, c, d, e, f, n, x): return Dist(d*n/(a*b), Int((a - b*sin(e + f*x))*(c + d*sin(e + f*x))**(n + S(-1)), x), x) - Simp(b*(c + d*sin(e + f*x))**n*cos(e + f*x)/(a*f*(a + b*sin(e + f*x))), x) def replacement2462(a, b, c, d, e, f, n, x): return Dist(d*n/(a*b), Int((a - b*cos(e + f*x))*(c + d*cos(e + f*x))**(n + S(-1)), x), x) + Simp(b*(c + d*cos(e + f*x))**n*sin(e + f*x)/(a*f*(a + b*cos(e + f*x))), x) def replacement2463(a, b, c, d, e, f, n, x): return Dist(S(2)*n*(a*d + b*c)/(b*(S(2)*n + S(1))), Int(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))**(n + S(-1)), x), x) + Simp(-S(2)*b*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*sqrt(a + b*sin(e + f*x))*(S(2)*n + S(1))), x) def replacement2464(a, b, c, d, e, f, n, x): return Dist(S(2)*n*(a*d + b*c)/(b*(S(2)*n + S(1))), Int(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))**(n + S(-1)), x), x) + Simp(S(2)*b*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*sqrt(a + b*cos(e + f*x))*(S(2)*n + S(1))), x) def replacement2465(a, b, c, d, e, f, x): return Simp(-S(2)*b**S(2)*cos(e + f*x)/(f*sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))*(a*d + b*c)), x) def replacement2466(a, b, c, d, e, f, x): return Simp(S(2)*b**S(2)*sin(e + f*x)/(f*sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))*(a*d + b*c)), x) def replacement2467(a, b, c, d, e, f, n, x): return Dist((S(2)*n + S(3))*(-a*d + b*c)/(S(2)*b*(c**S(2) - d**S(2))*(n + S(1))), Int(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))**(n + S(1)), x), x) + Simp((c + d*sin(e + f*x))**(n + S(1))*(-a*d + b*c)*cos(e + f*x)/(f*sqrt(a + b*sin(e + f*x))*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2468(a, b, c, d, e, f, n, x): return Dist((S(2)*n + S(3))*(-a*d + b*c)/(S(2)*b*(c**S(2) - d**S(2))*(n + S(1))), Int(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))**(n + S(1)), x), x) - Simp((c + d*cos(e + f*x))**(n + S(1))*(-a*d + b*c)*sin(e + f*x)/(f*sqrt(a + b*cos(e + f*x))*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2469(a, b, c, d, e, f, x): return Dist(-S(2)*b/f, Subst(Int(S(1)/(a*d + b*c - d*x**S(2)), x), x, b*cos(e + f*x)/sqrt(a + b*sin(e + f*x))), x) def replacement2470(a, b, c, d, e, f, x): return Dist(S(2)*b/f, Subst(Int(S(1)/(a*d + b*c - d*x**S(2)), x), x, b*sin(e + f*x)/sqrt(a + b*cos(e + f*x))), x) def replacement2471(a, b, d, e, f, x): return Dist(-S(2)/f, Subst(Int(S(1)/sqrt(S(1) - x**S(2)/a), x), x, b*cos(e + f*x)/sqrt(a + b*sin(e + f*x))), x) def replacement2472(a, b, d, e, f, x): return Dist(S(2)/f, Subst(Int(S(1)/sqrt(S(1) - x**S(2)/a), x), x, b*sin(e + f*x)/sqrt(a + b*cos(e + f*x))), x) def replacement2473(a, b, c, d, e, f, x): return Dist(-S(2)*b/f, Subst(Int(S(1)/(b + d*x**S(2)), x), x, b*cos(e + f*x)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x)))), x) def replacement2474(a, b, c, d, e, f, x): return Dist(S(2)*b/f, Subst(Int(S(1)/(b + d*x**S(2)), x), x, b*sin(e + f*x)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x)))), x) def replacement2475(a, b, c, d, e, f, n, x): return Dist(a**S(2)*cos(e + f*x)/(f*sqrt(a - b*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), Subst(Int((c + d*x)**n/sqrt(a - b*x), x), x, sin(e + f*x)), x) def replacement2476(a, b, c, d, e, f, n, x): return -Dist(a**S(2)*sin(e + f*x)/(f*sqrt(a - b*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), Subst(Int((c + d*x)**n/sqrt(a - b*x), x), x, cos(e + f*x)), x) def replacement2477(a, b, c, d, e, f, x): return Dist(d/b, Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) + Dist((-a*d + b*c)/b, Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2478(a, b, c, d, e, f, x): return Dist(d/b, Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) + Dist((-a*d + b*c)/b, Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2479(a, b, c, d, e, f, n, x): return -Dist(S(1)/(b*(S(2)*n + S(-1))), Int((c + d*sin(e + f*x))**(n + S(-2))*Simp(a*c*d - b*(c**S(2)*(S(2)*n + S(-1)) + S(2)*d**S(2)*(n + S(-1))) + d*(a*d - b*c*(S(4)*n + S(-3)))*sin(e + f*x), x)/sqrt(a + b*sin(e + f*x)), x), x) + Simp(-S(2)*d*(c + d*sin(e + f*x))**(n + S(-1))*cos(e + f*x)/(f*sqrt(a + b*sin(e + f*x))*(S(2)*n + S(-1))), x) def replacement2480(a, b, c, d, e, f, n, x): return -Dist(S(1)/(b*(S(2)*n + S(-1))), Int((c + d*cos(e + f*x))**(n + S(-2))*Simp(a*c*d - b*(c**S(2)*(S(2)*n + S(-1)) + S(2)*d**S(2)*(n + S(-1))) + d*(a*d - b*c*(S(4)*n + S(-3)))*cos(e + f*x), x)/sqrt(a + b*cos(e + f*x)), x), x) + Simp(S(2)*d*(c + d*cos(e + f*x))**(n + S(-1))*sin(e + f*x)/(f*sqrt(a + b*cos(e + f*x))*(S(2)*n + S(-1))), x) def replacement2481(a, b, c, d, e, f, n, x): return -Dist(S(1)/(S(2)*b*(c**S(2) - d**S(2))*(n + S(1))), Int((c + d*sin(e + f*x))**(n + S(1))*Simp(a*d - S(2)*b*c*(n + S(1)) + b*d*(S(2)*n + S(3))*sin(e + f*x), x)/sqrt(a + b*sin(e + f*x)), x), x) - Simp(d*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(f*sqrt(a + b*sin(e + f*x))*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2482(a, b, c, d, e, f, n, x): return -Dist(S(1)/(S(2)*b*(c**S(2) - d**S(2))*(n + S(1))), Int((c + d*cos(e + f*x))**(n + S(1))*Simp(a*d - S(2)*b*c*(n + S(1)) + b*d*(S(2)*n + S(3))*cos(e + f*x), x)/sqrt(a + b*cos(e + f*x)), x), x) + Simp(d*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(f*sqrt(a + b*cos(e + f*x))*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2483(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/sqrt(a + b*sin(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(sqrt(a + b*sin(e + f*x))/(c + d*sin(e + f*x)), x), x) def replacement2484(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/sqrt(a + b*cos(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(sqrt(a + b*cos(e + f*x))/(c + d*cos(e + f*x)), x), x) def replacement2485(a, b, d, e, f, x): return -Dist(sqrt(S(2))/(sqrt(a)*f), Subst(Int(S(1)/sqrt(S(1) - x**S(2)), x), x, b*cos(e + f*x)/(a + b*sin(e + f*x))), x) def replacement2486(a, b, d, e, f, x): return Dist(sqrt(S(2))/(sqrt(a)*f), Subst(Int(S(1)/sqrt(S(1) - x**S(2)), x), x, b*sin(e + f*x)/(a + b*cos(e + f*x))), x) def replacement2487(a, b, c, d, e, f, x): return Dist(-S(2)*a/f, Subst(Int(S(1)/(S(2)*b**S(2) - x**S(2)*(a*c - b*d)), x), x, b*cos(e + f*x)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x)))), x) def replacement2488(a, b, c, d, e, f, x): return Dist(S(2)*a/f, Subst(Int(S(1)/(S(2)*b**S(2) - x**S(2)*(a*c - b*d)), x), x, b*sin(e + f*x)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x)))), x) def replacement2489(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n)), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(-2))*Simp(b*c**S(2)*(m + n) + d*(a*c*m + b*d*(n + S(-1))) + d*(a*d*m + b*c*(m + S(2)*n + S(-1)))*sin(e + f*x), x), x), x) - Simp(d*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(-1))*cos(e + f*x)/(f*(m + n)), x) def replacement2490(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n)), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(-2))*Simp(b*c**S(2)*(m + n) + d*(a*c*m + b*d*(n + S(-1))) + d*(a*d*m + b*c*(m + S(2)*n + S(-1)))*cos(e + f*x), x), x), x) + Simp(d*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(-1))*sin(e + f*x)/(f*(m + n)), x) def replacement2491(a, b, c, d, e, f, m, n, x): return Dist(a**m*cos(e + f*x)/(f*sqrt(S(1) - sin(e + f*x))*sqrt(sin(e + f*x) + S(1))), Subst(Int((S(1) + b*x/a)**(m + S(-1)/2)*(c + d*x)**n/sqrt(S(1) - b*x/a), x), x, sin(e + f*x)), x) def replacement2492(a, b, c, d, e, f, m, n, x): return -Dist(a**m*sin(e + f*x)/(f*sqrt(S(1) - cos(e + f*x))*sqrt(cos(e + f*x) + S(1))), Subst(Int((S(1) + b*x/a)**(m + S(-1)/2)*(c + d*x)**n/sqrt(S(1) - b*x/a), x), x, cos(e + f*x)), x) def replacement2493(a, b, d, e, f, m, n, x): return -Dist(b*(d/b)**n*cos(e + f*x)/(f*sqrt(a - b*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), Subst(Int((a - x)**n*(S(2)*a - x)**(m + S(-1)/2)/sqrt(x), x), x, a - b*sin(e + f*x)), x) def replacement2494(a, b, d, e, f, m, n, x): return Dist(b*(d/b)**n*sin(e + f*x)/(f*sqrt(a - b*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), Subst(Int((a - x)**n*(S(2)*a - x)**(m + S(-1)/2)/sqrt(x), x), x, a - b*cos(e + f*x)), x) def replacement2495(a, b, d, e, f, m, n, x): return Dist((d/b)**IntPart(n)*(b*sin(e + f*x))**(-FracPart(n))*(d*sin(e + f*x))**FracPart(n), Int((b*sin(e + f*x))**n*(a + b*sin(e + f*x))**m, x), x) def replacement2496(a, b, d, e, f, m, n, x): return Dist((d/b)**IntPart(n)*(b*cos(e + f*x))**(-FracPart(n))*(d*cos(e + f*x))**FracPart(n), Int((b*cos(e + f*x))**n*(a + b*cos(e + f*x))**m, x), x) def replacement2497(a, b, d, e, f, m, n, x): return Dist(a**IntPart(m)*(S(1) + b*sin(e + f*x)/a)**(-FracPart(m))*(a + b*sin(e + f*x))**FracPart(m), Int((d*sin(e + f*x))**n*(S(1) + b*sin(e + f*x)/a)**m, x), x) def replacement2498(a, b, d, e, f, m, n, x): return Dist(a**IntPart(m)*(S(1) + b*cos(e + f*x)/a)**(-FracPart(m))*(a + b*cos(e + f*x))**FracPart(m), Int((d*cos(e + f*x))**n*(S(1) + b*cos(e + f*x)/a)**m, x), x) def replacement2499(a, b, c, d, e, f, m, n, x): return Dist(a**S(2)*cos(e + f*x)/(f*sqrt(a - b*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**n/sqrt(a - b*x), x), x, sin(e + f*x)), x) def replacement2500(a, b, c, d, e, f, m, n, x): return -Dist(a**S(2)*sin(e + f*x)/(f*sqrt(a - b*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), Subst(Int((a + b*x)**(m + S(-1)/2)*(c + d*x)**n/sqrt(a - b*x), x), x, cos(e + f*x)), x) def replacement2501(b, c, d, e, f, m, x): return Dist(S(2)*c*d/b, Int((b*sin(e + f*x))**(m + S(1)), x), x) + Int((b*sin(e + f*x))**m*(c**S(2) + d**S(2)*sin(e + f*x)**S(2)), x) def replacement2502(b, c, d, e, f, m, x): return Dist(S(2)*c*d/b, Int((b*cos(e + f*x))**(m + S(1)), x), x) + Int((b*cos(e + f*x))**m*(c**S(2) + d**S(2)*cos(e + f*x)**S(2)), x) def replacement2503(a, b, c, d, e, f, m, x): return -Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(-a*(c**S(2) + d**S(2)) + S(2)*b*c*d) + (a**S(2)*d**S(2) - S(2)*a*b*c*d*(m + S(2)) + b**S(2)*(c**S(2)*(m + S(2)) + d**S(2)*(m + S(1))))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(a**S(2)*d**S(2) - S(2)*a*b*c*d + b**S(2)*c**S(2))*cos(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2504(a, b, c, d, e, f, m, x): return -Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(-a*(c**S(2) + d**S(2)) + S(2)*b*c*d) + (a**S(2)*d**S(2) - S(2)*a*b*c*d*(m + S(2)) + b**S(2)*(c**S(2)*(m + S(2)) + d**S(2)*(m + S(1))))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(a**S(2)*d**S(2) - S(2)*a*b*c*d + b**S(2)*c**S(2))*sin(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2505(a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*sin(e + f*x))**m*Simp(b*(c**S(2)*(m + S(2)) + d**S(2)*(m + S(1))) - d*(a*d - S(2)*b*c*(m + S(2)))*sin(e + f*x), x), x), x) - Simp(d**S(2)*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(2))), x) def replacement2506(a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*cos(e + f*x))**m*Simp(b*(c**S(2)*(m + S(2)) + d**S(2)*(m + S(1))) - d*(a*d - S(2)*b*c*(m + S(2)))*cos(e + f*x), x), x), x) + Simp(d**S(2)*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(2))), x) def replacement2507(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**(m + S(-3))*(c + d*sin(e + f*x))**(n + S(1))*Simp(a*d*(n + S(1))*(-S(2)*a*b*d + c*(a**S(2) + b**S(2))) + b*(m + S(-2))*(-a*d + b*c)**S(2) + b*(b**S(2)*(c**S(2) - d**S(2)) + d*n*(S(2)*a*b*c - d*(a**S(2) + b**S(2))) - m*(-a*d + b*c)**S(2))*sin(e + f*x)**S(2) + (-a*(n + S(2))*(-a*d + b*c)**S(2) + b*(n + S(1))*(a*b*c**S(2) - S(3)*a*b*d**S(2) + c*d*(a**S(2) + b**S(2))))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**(n + S(1))*(a**S(2)*d**S(2) - S(2)*a*b*c*d + b**S(2)*c**S(2))*cos(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2508(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**(m + S(-3))*(c + d*cos(e + f*x))**(n + S(1))*Simp(a*d*(n + S(1))*(-S(2)*a*b*d + c*(a**S(2) + b**S(2))) + b*(m + S(-2))*(-a*d + b*c)**S(2) + b*(b**S(2)*(c**S(2) - d**S(2)) + d*n*(S(2)*a*b*c - d*(a**S(2) + b**S(2))) - m*(-a*d + b*c)**S(2))*cos(e + f*x)**S(2) + (-a*(n + S(2))*(-a*d + b*c)**S(2) + b*(n + S(1))*(a*b*c**S(2) - S(3)*a*b*d**S(2) + c*d*(a**S(2) + b**S(2))))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**(n + S(1))*(a**S(2)*d**S(2) - S(2)*a*b*c*d + b**S(2)*c**S(2))*sin(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2509(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*sin(e + f*x))**(m + S(-3))*(c + d*sin(e + f*x))**n*Simp(a**S(3)*d*(m + n) + b**S(2)*(a*d*(n + S(1)) + b*c*(m + S(-2))) - b**S(2)*(-a*d*(S(3)*m + S(2)*n + S(-2)) + b*c*(m + S(-1)))*sin(e + f*x)**S(2) - b*(-S(3)*a**S(2)*d*(m + n) + a*b*c - b**S(2)*d*(m + n + S(-1)))*sin(e + f*x), x), x), x) - Simp(b**S(2)*(a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n)), x) def replacement2510(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*cos(e + f*x))**(m + S(-3))*(c + d*cos(e + f*x))**n*Simp(a**S(3)*d*(m + n) + b**S(2)*(a*d*(n + S(1)) + b*c*(m + S(-2))) - b**S(2)*(-a*d*(S(3)*m + S(2)*n + S(-2)) + b*c*(m + S(-1)))*cos(e + f*x)**S(2) - b*(-S(3)*a**S(2)*d*(m + n) + a*b*c - b**S(2)*d*(m + n + S(-1)))*cos(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n)), x) def replacement2511(a, b, d, e, f, x): return -Dist(d**S(2)/(a**S(2) - b**S(2)), Int(sqrt(a + b*sin(e + f*x))/(d*sin(e + f*x))**(S(3)/2), x), x) + Simp(-S(2)*a*d*cos(e + f*x)/(f*sqrt(d*sin(e + f*x))*sqrt(a + b*sin(e + f*x))*(a**S(2) - b**S(2))), x) def replacement2512(a, b, d, e, f, x): return -Dist(d**S(2)/(a**S(2) - b**S(2)), Int(sqrt(a + b*cos(e + f*x))/(d*cos(e + f*x))**(S(3)/2), x), x) + Simp(S(2)*a*d*sin(e + f*x)/(f*sqrt(d*cos(e + f*x))*sqrt(a + b*cos(e + f*x))*(a**S(2) - b**S(2))), x) def replacement2513(a, b, c, d, e, f, x): return Dist((c - d)/(a - b), Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) - Dist((-a*d + b*c)/(a - b), Int((sin(e + f*x) + S(1))/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) def replacement2514(a, b, c, d, e, f, x): return Dist((c - d)/(a - b), Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) - Dist((-a*d + b*c)/(a - b), Int((cos(e + f*x) + S(1))/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) def replacement2515(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(-1))*Simp(a*c*(m + S(1)) + b*d*n - b*d*(m + n + S(2))*sin(e + f*x)**S(2) + (a*d*(m + S(1)) - b*c*(m + S(2)))*sin(e + f*x), x), x), x) - Simp(b*(a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2516(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(-1))*Simp(a*c*(m + S(1)) + b*d*n - b*d*(m + n + S(2))*cos(e + f*x)**S(2) + (a*d*(m + S(1)) - b*c*(m + S(2)))*cos(e + f*x), x), x), x) + Simp(b*(a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2517(a, b, d, e, f, x): return Dist(d/b, Int(sqrt(d*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) - Dist(a*d/b, Int(sqrt(d*sin(e + f*x))/(a + b*sin(e + f*x))**(S(3)/2), x), x) def replacement2518(a, b, d, e, f, x): return Dist(d/b, Int(sqrt(d*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) - Dist(a*d/b, Int(sqrt(d*cos(e + f*x))/(a + b*cos(e + f*x))**(S(3)/2), x), x) def replacement2519(a, b, c, d, e, f, x): return Dist(d**S(2)/b**S(2), Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) + Dist((-a*d + b*c)/b**S(2), Int(Simp(a*d + b*c + S(2)*b*d*sin(e + f*x), x)/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) def replacement2520(a, b, c, d, e, f, x): return Dist(d**S(2)/b**S(2), Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) + Dist((-a*d + b*c)/b**S(2), Int(Simp(a*d + b*c + S(2)*b*d*cos(e + f*x), x)/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) def replacement2521(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(-2))*Simp(c*(m + S(1))*(a*c - b*d) + d*(n + S(-1))*(-a*d + b*c) - d*(-a*d + b*c)*(m + n + S(1))*sin(e + f*x)**S(2) + (-c*(m + S(2))*(-a*d + b*c) + d*(m + S(1))*(a*c - b*d))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(-1))*(-a*d + b*c)*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2522(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(-2))*Simp(c*(m + S(1))*(a*c - b*d) + d*(n + S(-1))*(-a*d + b*c) - d*(-a*d + b*c)*(m + n + S(1))*cos(e + f*x)**S(2) + (-c*(m + S(2))*(-a*d + b*c) + d*(m + S(1))*(a*c - b*d))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(-1))*(-a*d + b*c)*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2523(a, b, d, e, f, x): return Dist(d/(a**S(2) - b**S(2)), Int((a*sin(e + f*x) + b)/((d*sin(e + f*x))**(S(3)/2)*sqrt(a + b*sin(e + f*x))), x), x) + Simp(S(2)*b*cos(e + f*x)/(f*sqrt(d*sin(e + f*x))*sqrt(a + b*sin(e + f*x))*(a**S(2) - b**S(2))), x) def replacement2524(a, b, d, e, f, x): return Dist(d/(a**S(2) - b**S(2)), Int((a*cos(e + f*x) + b)/((d*cos(e + f*x))**(S(3)/2)*sqrt(a + b*cos(e + f*x))), x), x) + Simp(-S(2)*b*sin(e + f*x)/(f*sqrt(d*cos(e + f*x))*sqrt(a + b*cos(e + f*x))*(a**S(2) - b**S(2))), x) def replacement2525(a, b, c, d, e, f, x): return -Dist(b/(a - b), Int((sin(e + f*x) + S(1))/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) + Dist(S(1)/(a - b), Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2526(a, b, c, d, e, f, x): return -Dist(b/(a - b), Int((cos(e + f*x) + S(1))/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) + Dist(S(1)/(a - b), Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2527(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(a*(m + S(1))*(-a*d + b*c) + b**S(2)*d*(m + n + S(2)) - b**S(2)*d*(m + n + S(3))*sin(e + f*x)**S(2) - (b**S(2)*c + b*(m + S(1))*(-a*d + b*c))*sin(e + f*x), x), x), x) - Simp(b**S(2)*(a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement2528(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(a*(m + S(1))*(-a*d + b*c) + b**S(2)*d*(m + n + S(2)) - b**S(2)*d*(m + n + S(3))*cos(e + f*x)**S(2) - (b**S(2)*c + b*(m + S(1))*(-a*d + b*c))*cos(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement2529(a, b, c, d, e, f, x): return Dist(d/b, Int(S(1)/sqrt(c + d*sin(e + f*x)), x), x) + Dist((-a*d + b*c)/b, Int(S(1)/((a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2530(a, b, c, d, e, f, x): return Dist(d/b, Int(S(1)/sqrt(c + d*cos(e + f*x)), x), x) + Dist((-a*d + b*c)/b, Int(S(1)/((a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2531(a, b, c, d, e, f, x): return Dist(b/d, Int(sqrt(a + b*sin(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(sqrt(a + b*sin(e + f*x))/(c + d*sin(e + f*x)), x), x) def replacement2532(a, b, c, d, e, f, x): return Dist(b/d, Int(sqrt(a + b*cos(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(sqrt(a + b*cos(e + f*x))/(c + d*cos(e + f*x)), x), x) def replacement2533(a, b, c, d, e, f, x): return Simp(S(2)*EllipticPi(S(2)*b/(a + b), -Pi/S(4) + e/S(2) + f*x/S(2), S(2)*d/(c + d))/(f*(a + b)*sqrt(c + d)), x) def replacement2534(a, b, c, d, e, f, x): return Simp(S(2)*EllipticPi(S(2)*b/(a + b), e/S(2) + f*x/S(2), S(2)*d/(c + d))/(f*(a + b)*sqrt(c + d)), x) def replacement2535(a, b, c, d, e, f, x): return Simp(S(2)*EllipticPi(-S(2)*b/(a - b), Pi/S(4) + e/S(2) + f*x/S(2), -S(2)*d/(c - d))/(f*(a - b)*sqrt(c - d)), x) def replacement2536(a, b, c, d, e, f, x): return Simp(S(2)*EllipticPi(-S(2)*b/(a - b), Pi/S(2) + e/S(2) + f*x/S(2), -S(2)*d/(c - d))/(f*(a - b)*sqrt(c - d)), x) def replacement2537(a, b, c, d, e, f, x): return Dist(sqrt((c + d*sin(e + f*x))/(c + d))/sqrt(c + d*sin(e + f*x)), Int(S(1)/((a + b*sin(e + f*x))*sqrt(c/(c + d) + d*sin(e + f*x)/(c + d))), x), x) def replacement2538(a, b, c, d, e, f, x): return Dist(sqrt((c + d*cos(e + f*x))/(c + d))/sqrt(c + d*cos(e + f*x)), Int(S(1)/((a + b*cos(e + f*x))*sqrt(c/(c + d) + d*cos(e + f*x)/(c + d))), x), x) def replacement2539(b, c, d, e, f, x): return Simp(S(2)*c*sqrt(S(1) - S(1)/sin(e + f*x))*sqrt(S(1) + S(1)/sin(e + f*x))*EllipticPi((c + d)/d, asin(sqrt(c + d*sin(e + f*x))/(sqrt(b*sin(e + f*x))*Rt((c + d)/b, S(2)))), -(c + d)/(c - d))*Rt(b*(c + d), S(2))*tan(e + f*x)/(d*f*sqrt(c**S(2) - d**S(2))), x) def replacement2540(b, c, d, e, f, x): return Simp(-S(2)*c*sqrt(S(1) - S(1)/cos(e + f*x))*sqrt(S(1) + S(1)/cos(e + f*x))*EllipticPi((c + d)/d, asin(sqrt(c + d*cos(e + f*x))/(sqrt(b*cos(e + f*x))*Rt((c + d)/b, S(2)))), -(c + d)/(c - d))*Rt(b*(c + d), S(2))/(d*f*sqrt(c**S(2) - d**S(2))*tan(e + f*x)), x) def replacement2541(b, c, d, e, f, x): return Simp(S(2)*b*sqrt(c*(S(1) - S(1)/sin(e + f*x))/(c + d))*sqrt(c*(S(1) + S(1)/sin(e + f*x))/(c - d))*EllipticPi((c + d)/d, asin(sqrt(c + d*sin(e + f*x))/(sqrt(b*sin(e + f*x))*Rt((c + d)/b, S(2)))), -(c + d)/(c - d))*Rt((c + d)/b, S(2))*tan(e + f*x)/(d*f), x) def replacement2542(b, c, d, e, f, x): return Simp(-S(2)*b*sqrt(c*(S(1) - S(1)/cos(e + f*x))/(c + d))*sqrt(c*(S(1) + S(1)/cos(e + f*x))/(c - d))*EllipticPi((c + d)/d, asin(sqrt(c + d*cos(e + f*x))/(sqrt(b*cos(e + f*x))*Rt((c + d)/b, S(2)))), -(c + d)/(c - d))*Rt((c + d)/b, S(2))/(d*f*tan(e + f*x)), x) def replacement2543(b, c, d, e, f, x): return Dist(sqrt(b*sin(e + f*x))/sqrt(-b*sin(e + f*x)), Int(sqrt(-b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) def replacement2544(b, c, d, e, f, x): return Dist(sqrt(b*cos(e + f*x))/sqrt(-b*cos(e + f*x)), Int(sqrt(-b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) def replacement2545(a, b, c, d, e, f, x): return Simp(S(2)*sqrt((-a*d + b*c)*(sin(e + f*x) + S(1))/((a + b*sin(e + f*x))*(c - d)))*sqrt(-(S(1) - sin(e + f*x))*(-a*d + b*c)/((a + b*sin(e + f*x))*(c + d)))*(a + b*sin(e + f*x))*EllipticPi(b*(c + d)/(d*(a + b)), asin(sqrt(c + d*sin(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b*sin(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(d*f*Rt((a + b)/(c + d), S(2))*cos(e + f*x)), x) def replacement2546(a, b, c, d, e, f, x): return Simp(-S(2)*sqrt((-a*d + b*c)*(cos(e + f*x) + S(1))/((a + b*cos(e + f*x))*(c - d)))*sqrt(-(S(1) - cos(e + f*x))*(-a*d + b*c)/((a + b*cos(e + f*x))*(c + d)))*(a + b*cos(e + f*x))*EllipticPi(b*(c + d)/(d*(a + b)), asin(sqrt(c + d*cos(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b*cos(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(d*f*Rt((a + b)/(c + d), S(2))*sin(e + f*x)), x) def replacement2547(a, b, c, d, e, f, x): return Dist(sqrt(-c - d*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), Int(sqrt(a + b*sin(e + f*x))/sqrt(-c - d*sin(e + f*x)), x), x) def replacement2548(a, b, c, d, e, f, x): return Dist(sqrt(-c - d*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), Int(sqrt(a + b*cos(e + f*x))/sqrt(-c - d*cos(e + f*x)), x), x) def replacement2549(a, b, d, e, f, x): return Simp(-S(2)*d*EllipticF(asin(cos(e + f*x)/(d*sin(e + f*x) + S(1))), -(a - b*d)/(a + b*d))/(f*sqrt(a + b*d)), x) def replacement2550(a, b, d, e, f, x): return Simp(S(2)*d*EllipticF(asin(sin(e + f*x)/(d*cos(e + f*x) + S(1))), -(a - b*d)/(a + b*d))/(f*sqrt(a + b*d)), x) def replacement2551(a, b, d, e, f, x): return Dist(sqrt(sin(e + f*x)*sign(b))/sqrt(d*sin(e + f*x)), Int(S(1)/(sqrt(sin(e + f*x)*sign(b))*sqrt(a + b*sin(e + f*x))), x), x) def replacement2552(a, b, d, e, f, x): return Dist(sqrt(cos(e + f*x)*sign(b))/sqrt(d*cos(e + f*x)), Int(S(1)/(sqrt(cos(e + f*x)*sign(b))*sqrt(a + b*cos(e + f*x))), x), x) def replacement2553(a, b, d, e, f, x): return Simp(-S(2)*sqrt(-S(1)/tan(e + f*x)**S(2))*sqrt(a**S(2))*EllipticF(asin(sqrt(a + b*sin(e + f*x))/(sqrt(d*sin(e + f*x))*Rt((a + b)/d, S(2)))), -(a + b)/(a - b))*Rt((a + b)/d, S(2))*tan(e + f*x)/(a*f*sqrt(a**S(2) - b**S(2))), x) def replacement2554(a, b, d, e, f, x): return Simp(S(2)*sqrt(-tan(e + f*x)**S(2))*sqrt(a**S(2))*EllipticF(asin(sqrt(a + b*cos(e + f*x))/(sqrt(d*cos(e + f*x))*Rt((a + b)/d, S(2)))), -(a + b)/(a - b))*Rt((a + b)/d, S(2))/(a*f*sqrt(a**S(2) - b**S(2))*tan(e + f*x)), x) def replacement2555(a, b, d, e, f, x): return Simp(-S(2)*sqrt(a*(S(1) - S(1)/sin(e + f*x))/(a + b))*sqrt(a*(S(1) + S(1)/sin(e + f*x))/(a - b))*EllipticF(asin(sqrt(a + b*sin(e + f*x))/(sqrt(d*sin(e + f*x))*Rt((a + b)/d, S(2)))), -(a + b)/(a - b))*Rt((a + b)/d, S(2))*tan(e + f*x)/(a*f), x) def replacement2556(a, b, d, e, f, x): return Simp(S(2)*sqrt(a*(S(1) - S(1)/cos(e + f*x))/(a + b))*sqrt(a*(S(1) + S(1)/cos(e + f*x))/(a - b))*EllipticF(asin(sqrt(a + b*cos(e + f*x))/(sqrt(d*cos(e + f*x))*Rt((a + b)/d, S(2)))), -(a + b)/(a - b))*Rt((a + b)/d, S(2))/(a*f*tan(e + f*x)), x) def replacement2557(a, b, d, e, f, x): return Dist(sqrt(-d*sin(e + f*x))/sqrt(d*sin(e + f*x)), Int(S(1)/(sqrt(-d*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), x), x) def replacement2558(a, b, d, e, f, x): return Dist(sqrt(-d*cos(e + f*x))/sqrt(d*cos(e + f*x)), Int(S(1)/(sqrt(-d*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), x), x) def replacement2559(a, b, c, d, e, f, x): return Simp(S(2)*sqrt((S(1) - sin(e + f*x))*(-a*d + b*c)/((a + b)*(c + d*sin(e + f*x))))*sqrt(-(-a*d + b*c)*(sin(e + f*x) + S(1))/((a - b)*(c + d*sin(e + f*x))))*(c + d*sin(e + f*x))*EllipticF(asin(sqrt(a + b*sin(e + f*x))*Rt((c + d)/(a + b), S(2))/sqrt(c + d*sin(e + f*x))), (a + b)*(c - d)/((a - b)*(c + d)))/(f*(-a*d + b*c)*Rt((c + d)/(a + b), S(2))*cos(e + f*x)), x) def replacement2560(a, b, c, d, e, f, x): return Simp(-S(2)*sqrt((S(1) - cos(e + f*x))*(-a*d + b*c)/((a + b)*(c + d*cos(e + f*x))))*sqrt(-(-a*d + b*c)*(cos(e + f*x) + S(1))/((a - b)*(c + d*cos(e + f*x))))*(c + d*cos(e + f*x))*EllipticF(asin(sqrt(a + b*cos(e + f*x))*Rt((c + d)/(a + b), S(2))/sqrt(c + d*cos(e + f*x))), (a + b)*(c - d)/((a - b)*(c + d)))/(f*(-a*d + b*c)*Rt((c + d)/(a + b), S(2))*sin(e + f*x)), x) def replacement2561(a, b, c, d, e, f, x): return Dist(sqrt(-a - b*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), Int(S(1)/(sqrt(-a - b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2562(a, b, c, d, e, f, x): return Dist(sqrt(-a - b*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), Int(S(1)/(sqrt(-a - b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2563(a, b, d, e, f, x): return Dist(d/(S(2)*b), Int(sqrt(d*sin(e + f*x))*(a + S(2)*b*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) - Dist(a*d/(S(2)*b), Int(sqrt(d*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) def replacement2564(a, b, d, e, f, x): return Dist(d/(S(2)*b), Int(sqrt(d*cos(e + f*x))*(a + S(2)*b*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) - Dist(a*d/(S(2)*b), Int(sqrt(d*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) def replacement2565(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**(n + S(-1))*Simp(a**S(2)*c*d*(m + n) + b*d*(a*d*n + b*c*(m + S(-1))) + b*d*(a*d*(S(2)*m + n + S(-1)) + b*c*n)*sin(e + f*x)**S(2) + (a*d*(m + n)*(a*d + S(2)*b*c) - b*d*(a*c - b*d*(m + n + S(-1))))*sin(e + f*x), x), x), x) - Simp(b*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(m + n)), x) def replacement2566(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**(n + S(-1))*Simp(a**S(2)*c*d*(m + n) + b*d*(a*d*n + b*c*(m + S(-1))) + b*d*(a*d*(S(2)*m + n + S(-1)) + b*c*n)*cos(e + f*x)**S(2) + (a*d*(m + n)*(a*d + S(2)*b*c) - b*d*(a*c - b*d*(m + n + S(-1))))*cos(e + f*x), x), x), x) + Simp(b*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(m + n)), x) def replacement2567(a, b, c, d, e, f, m, n, x): return Dist(b/d, Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1)), x), x) - Dist((-a*d + b*c)/d, Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n, x), x) def replacement2568(a, b, c, d, e, f, m, n, x): return Dist(b/d, Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1)), x), x) - Dist((-a*d + b*c)/d, Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n, x), x) def replacement2569(a, b, c, d, e, f, m, n, x): return Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x) def replacement2570(a, b, c, d, e, f, m, n, x): return Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x) def replacement2571(a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d*sin(e + f*x))**p)**FracPart(n)*(d*sin(e + f*x))**(-p*FracPart(n)), Int((d*sin(e + f*x))**(n*p)*(a + b*sin(e + f*x))**m, x), x) def replacement2572(a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d*cos(e + f*x))**p)**FracPart(n)*(d*cos(e + f*x))**(-p*FracPart(n)), Int((d*cos(e + f*x))**(n*p)*(a + b*cos(e + f*x))**m, x), x) def replacement2573(a, b, c, d, e, f, m, n, x): return Int((a + b*sin(e + f*x))**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-n), x) def replacement2574(a, b, c, d, e, f, m, n, x): return Int((a + b*cos(e + f*x))**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-n), x) def replacement2575(a, b, c, d, e, f, m, n, x): return Int((c + d/sin(e + f*x))**n*(a/sin(e + f*x) + b)**m*(S(1)/sin(e + f*x))**(-m), x) def replacement2576(a, b, c, d, e, f, m, n, x): return Int((c + d/cos(e + f*x))**n*(a/cos(e + f*x) + b)**m*(S(1)/cos(e + f*x))**(-m), x) def replacement2577(a, b, c, d, e, f, m, n, x): return Dist((c + d/sin(e + f*x))**n*(c*sin(e + f*x) + d)**(-n)*sin(e + f*x)**n, Int((a + b*sin(e + f*x))**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-n), x), x) def replacement2578(a, b, c, d, e, f, m, n, x): return Dist((c + d/cos(e + f*x))**n*(c*cos(e + f*x) + d)**(-n)*cos(e + f*x)**n, Int((a + b*cos(e + f*x))**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-n), x), x) def replacement2579(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*f), Subst(Int((a + x)**m*(c + d*x/b)**n, x), x, b*sin(e + f*x)), x) def replacement2580(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(b*f), Subst(Int((a + x)**m*(c + d*x/b)**n, x), x, b*cos(e + f*x)), x) def replacement2581(a, b, d, e, f, n, p, x): return Dist(a, Int((d*sin(e + f*x))**n*cos(e + f*x)**p, x), x) + Dist(b/d, Int((d*sin(e + f*x))**(n + S(1))*cos(e + f*x)**p, x), x) def replacement2582(a, b, d, e, f, n, p, x): return Dist(a, Int((d*cos(e + f*x))**n*sin(e + f*x)**p, x), x) + Dist(b/d, Int((d*cos(e + f*x))**(n + S(1))*sin(e + f*x)**p, x), x) def replacement2583(a, b, d, e, f, n, p, x): return Dist(S(1)/a, Int((d*sin(e + f*x))**n*cos(e + f*x)**(p + S(-2)), x), x) - Dist(S(1)/(b*d), Int((d*sin(e + f*x))**(n + S(1))*cos(e + f*x)**(p + S(-2)), x), x) def replacement2584(a, b, d, e, f, n, p, x): return Dist(S(1)/a, Int((d*cos(e + f*x))**n*sin(e + f*x)**(p + S(-2)), x), x) - Dist(S(1)/(b*d), Int((d*cos(e + f*x))**(n + S(1))*sin(e + f*x)**(p + S(-2)), x), x) def replacement2585(a, b, c, d, e, f, m, n, p, x): return Dist(b**(-p)/f, Subst(Int((a - x)**(p/S(2) + S(-1)/2)*(a + x)**(m + p/S(2) + S(-1)/2)*(c + d*x/b)**n, x), x, b*sin(e + f*x)), x) def replacement2586(a, b, c, d, e, f, m, n, p, x): return -Dist(b**(-p)/f, Subst(Int((a - x)**(p/S(2) + S(-1)/2)*(a + x)**(m + p/S(2) + S(-1)/2)*(c + d*x/b)**n, x), x, b*cos(e + f*x)), x) def replacement2587(a, b, c, d, e, f, m, n, p, x): return Dist(b**(-p)/f, Subst(Int((a + x)**m*(b**S(2) - x**S(2))**(p/S(2) + S(-1)/2)*(c + d*x/b)**n, x), x, b*sin(e + f*x)), x) def replacement2588(a, b, c, d, e, f, m, n, p, x): return -Dist(b**(-p)/f, Subst(Int((a + x)**m*(b**S(2) - x**S(2))**(p/S(2) + S(-1)/2)*(c + d*x/b)**n, x), x, b*cos(e + f*x)), x) def replacement2589(a, b, d, e, f, g, n, p, x): return Dist(a, Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**p, x), x) + Dist(b/d, Int((d*sin(e + f*x))**(n + S(1))*(g*cos(e + f*x))**p, x), x) def replacement2590(a, b, d, e, f, g, n, p, x): return Dist(a, Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**p, x), x) + Dist(b/d, Int((d*cos(e + f*x))**(n + S(1))*(g*sin(e + f*x))**p, x), x) def replacement2591(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/a, Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(p + S(-2)), x), x) - Dist(g**S(2)/(b*d), Int((d*sin(e + f*x))**(n + S(1))*(g*cos(e + f*x))**(p + S(-2)), x), x) def replacement2592(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/a, Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(p + S(-2)), x), x) - Dist(g**S(2)/(b*d), Int((d*cos(e + f*x))**(n + S(1))*(g*sin(e + f*x))**(p + S(-2)), x), x) def replacement2593(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**m*c**m*g**(-S(2)*m), Int((g*cos(e + f*x))**(S(2)*m + p)*(c + d*sin(e + f*x))**(-m + n), x), x) def replacement2594(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**m*c**m*g**(-S(2)*m), Int((g*sin(e + f*x))**(S(2)*m + p)*(c + d*cos(e + f*x))**(-m + n), x), x) def replacement2595(a, b, c, d, e, f, m, n, p, x): return Dist(a**(-p/S(2))*c**(-p/S(2)), Int((a + b*sin(e + f*x))**(m + p/S(2))*(c + d*sin(e + f*x))**(n + p/S(2)), x), x) def replacement2596(a, b, c, d, e, f, m, n, p, x): return Dist(a**(-p/S(2))*c**(-p/S(2)), Int((a + b*cos(e + f*x))**(m + p/S(2))*(c + d*cos(e + f*x))**(n + p/S(2)), x), x) def replacement2597(a, b, c, d, e, f, g, p, x): return Dist(g*cos(e + f*x)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), Int((g*cos(e + f*x))**(p + S(-1)), x), x) def replacement2598(a, b, c, d, e, f, g, p, x): return Dist(g*sin(e + f*x)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), Int((g*sin(e + f*x))**(p + S(-1)), x), x) def replacement2599(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**IntPart(m)*c**IntPart(m)*g**(-S(2)*IntPart(m))*(g*cos(e + f*x))**(-S(2)*FracPart(m))*(a + b*sin(e + f*x))**FracPart(m)*(c + d*sin(e + f*x))**FracPart(m), Int((g*cos(e + f*x))**(S(2)*m + p)/(c + d*sin(e + f*x)), x), x) def replacement2600(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**IntPart(m)*c**IntPart(m)*g**(-S(2)*IntPart(m))*(g*sin(e + f*x))**(-S(2)*FracPart(m))*(a + b*cos(e + f*x))**FracPart(m)*(c + d*cos(e + f*x))**FracPart(m), Int((g*sin(e + f*x))**(S(2)*m + p)/(c + d*cos(e + f*x)), x), x) def replacement2601(a, b, c, d, e, f, g, m, n, p, x): return Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n/(f*g*(m - n + S(-1))), x) def replacement2602(a, b, c, d, e, f, g, m, n, p, x): return -Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n/(f*g*(m - n + S(-1))), x) def replacement2603(a, b, c, d, e, f, g, m, n, p, x): return -Dist(b*(S(2)*m + p + S(-1))/(d*(S(2)*n + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1)), x), x) + Simp(-S(2)*b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n/(f*g*(S(2)*n + p + S(1))), x) def replacement2604(a, b, c, d, e, f, g, m, n, p, x): return -Dist(b*(S(2)*m + p + S(-1))/(d*(S(2)*n + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1)), x), x) + Simp(S(2)*b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n/(f*g*(S(2)*n + p + S(1))), x) def replacement2605(a, b, c, d, e, f, g, m, n, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + n + p), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n, x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n/(f*g*(m + n + p)), x) def replacement2606(a, b, c, d, e, f, g, m, n, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + n + p), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n, x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n/(f*g*(m + n + p)), x) def replacement2607(a, b, c, d, e, f, g, m, p, x): return Dist(a**IntPart(m)*c**IntPart(m)*g**(-S(2)*IntPart(m))*(g*cos(e + f*x))**(-S(2)*FracPart(m))*(a + b*sin(e + f*x))**FracPart(m)*(c + d*sin(e + f*x))**FracPart(m), Int((g*cos(e + f*x))**(S(2)*m + p), x), x) def replacement2608(a, b, c, d, e, f, g, m, p, x): return Dist(a**IntPart(m)*c**IntPart(m)*g**(-S(2)*IntPart(m))*(g*sin(e + f*x))**(-S(2)*FracPart(m))*(a + b*cos(e + f*x))**FracPart(m)*(c + d*cos(e + f*x))**FracPart(m), Int((g*sin(e + f*x))**(S(2)*m + p), x), x) def replacement2609(a, b, c, d, e, f, g, m, n, p, x): return Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n/(a*f*g*(m - n)), x) def replacement2610(a, b, c, d, e, f, g, m, n, p, x): return -Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n/(a*f*g*(m - n)), x) def replacement2611(a, b, c, d, e, f, g, m, n, p, x): return Dist((m + n + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n, x), x) + Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2612(a, b, c, d, e, f, g, m, n, p, x): return Dist((m + n + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n, x), x) - Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2613(a, b, c, d, e, f, g, m, n, p, x): return -Dist(b*(S(2)*m + p + S(-1))/(d*(S(2)*n + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1)), x), x) + Simp(-S(2)*b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n/(f*g*(S(2)*n + p + S(1))), x) def replacement2614(a, b, c, d, e, f, g, m, n, p, x): return -Dist(b*(S(2)*m + p + S(-1))/(d*(S(2)*n + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1)), x), x) + Simp(S(2)*b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n/(f*g*(S(2)*n + p + S(1))), x) def replacement2615(a, b, c, d, e, f, g, m, n, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + n + p), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n, x), x) - Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n/(f*g*(m + n + p)), x) def replacement2616(a, b, c, d, e, f, g, m, n, p, x): return Dist(a*(S(2)*m + p + S(-1))/(m + n + p), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n, x), x) + Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n/(f*g*(m + n + p)), x) def replacement2617(a, b, c, d, e, f, g, m, n, p, x): return Dist((m + n + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n, x), x) + Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2618(a, b, c, d, e, f, g, m, n, p, x): return Dist((m + n + p + S(1))/(a*(S(2)*m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n, x), x) - Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2619(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**IntPart(m)*c**IntPart(m)*g**(-S(2)*IntPart(m))*(g*cos(e + f*x))**(-S(2)*FracPart(m))*(a + b*sin(e + f*x))**FracPart(m)*(c + d*sin(e + f*x))**FracPart(m), Int((g*cos(e + f*x))**(S(2)*m + p)*(c + d*sin(e + f*x))**(-m + n), x), x) def replacement2620(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**IntPart(m)*c**IntPart(m)*g**(-S(2)*IntPart(m))*(g*sin(e + f*x))**(-S(2)*FracPart(m))*(a + b*cos(e + f*x))**FracPart(m)*(c + d*cos(e + f*x))**FracPart(m), Int((g*sin(e + f*x))**(S(2)*m + p)*(c + d*cos(e + f*x))**(-m + n), x), x) def replacement2621(a, b, c, d, e, f, g, m, p, x): return -Simp(d*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2622(a, b, c, d, e, f, g, m, p, x): return Simp(d*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2623(a, b, c, d, e, f, g, m, p, x): return Dist(b*(a*d*m + b*c*(m + p + S(1)))/(a*g**S(2)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-1)), x), x) - Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m*(a*d + b*c)/(a*f*g*(p + S(1))), x) def replacement2624(a, b, c, d, e, f, g, m, p, x): return Dist(b*(a*d*m + b*c*(m + p + S(1)))/(a*g**S(2)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-1)), x), x) + Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m*(a*d + b*c)/(a*f*g*(p + S(1))), x) def replacement2625(a, b, c, d, e, f, g, m, p, x): return Dist((a*d*m + b*c*(m + p + S(1)))/(b*(m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**m, x), x) - Simp(d*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2626(a, b, c, d, e, f, g, m, p, x): return Dist((a*d*m + b*c*(m + p + S(1)))/(b*(m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**m, x), x) + Simp(d*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2627(a, b, c, d, e, f, m, x): return Dist(S(1)/(b**S(3)*(S(2)*m + S(3))), Int((a + b*sin(e + f*x))**(m + S(2))*(S(2)*a*d*(m + S(1)) + b*c - b*d*(S(2)*m + S(3))*sin(e + f*x)), x), x) + Simp(S(2)*(a + b*sin(e + f*x))**(m + S(1))*(-a*d + b*c)*cos(e + f*x)/(b**S(2)*f*(S(2)*m + S(3))), x) def replacement2628(a, b, c, d, e, f, m, x): return Dist(S(1)/(b**S(3)*(S(2)*m + S(3))), Int((a + b*cos(e + f*x))**(m + S(2))*(S(2)*a*d*(m + S(1)) + b*c - b*d*(S(2)*m + S(3))*cos(e + f*x)), x), x) + Simp(-S(2)*(a + b*cos(e + f*x))**(m + S(1))*(-a*d + b*c)*sin(e + f*x)/(b**S(2)*f*(S(2)*m + S(3))), x) def replacement2629(a, b, c, d, e, f, m, x): return -Dist(S(1)/(b**S(2)*(m + S(3))), Int((a + b*sin(e + f*x))**(m + S(1))*(-a*c*(m + S(3)) + b*d*(m + S(2)) + (-a*d*(m + S(4)) + b*c*(m + S(3)))*sin(e + f*x)), x), x) + Simp(d*(a + b*sin(e + f*x))**(m + S(2))*cos(e + f*x)/(b**S(2)*f*(m + S(3))), x) def replacement2630(a, b, c, d, e, f, m, x): return -Dist(S(1)/(b**S(2)*(m + S(3))), Int((a + b*cos(e + f*x))**(m + S(1))*(-a*c*(m + S(3)) + b*d*(m + S(2)) + (-a*d*(m + S(4)) + b*c*(m + S(3)))*cos(e + f*x)), x), x) - Simp(d*(a + b*cos(e + f*x))**(m + S(2))*sin(e + f*x)/(b**S(2)*f*(m + S(3))), x) def replacement2631(a, b, c, d, e, f, g, m, p, x): return Dist((a*d*m + b*c*(m + p + S(1)))/(a*b*(S(2)*m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1)), x), x) + Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m*(-a*d + b*c)/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2632(a, b, c, d, e, f, g, m, p, x): return Dist((a*d*m + b*c*(m + p + S(1)))/(a*b*(S(2)*m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1)), x), x) - Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m*(-a*d + b*c)/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2633(a, b, c, d, e, f, g, m, p, x): return Dist((a*d*m + b*c*(m + p + S(1)))/(b*(m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**m, x), x) - Simp(d*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2634(a, b, c, d, e, f, g, m, p, x): return Dist((a*d*m + b*c*(m + p + S(1)))/(b*(m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**m, x), x) + Simp(d*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2635(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-1))*Simp(a*c*(p + S(2)) + b*c*(m + p + S(2))*sin(e + f*x) + b*d*m, x), x), x) - Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m*(c*sin(e + f*x) + d)/(f*g*(p + S(1))), x) def replacement2636(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-1))*Simp(a*c*(p + S(2)) + b*c*(m + p + S(2))*cos(e + f*x) + b*d*m, x), x), x) + Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m*(c*cos(e + f*x) + d)/(f*g*(p + S(1))), x) def replacement2637(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/(m + p + S(1)), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(-1))*Simp(a*c*(m + p + S(1)) + b*d*m + (a*d*m + b*c*(m + p + S(1)))*sin(e + f*x), x), x), x) - Simp(d*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2638(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/(m + p + S(1)), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(-1))*Simp(a*c*(m + p + S(1)) + b*d*m + (a*d*m + b*c*(m + p + S(1)))*cos(e + f*x), x), x), x) + Simp(d*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(f*g*(m + p + S(1))), x) def replacement2639(a, b, c, d, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b**S(2)*(m + S(1))*(m + p + S(1))), Int((g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**(m + S(1))*Simp(b*d*(m + S(1)) + (-a*d*p + b*c*(m + p + S(1)))*sin(e + f*x), x), x), x) + Simp(g*(g*cos(e + f*x))**(p + S(-1))*(a + b*sin(e + f*x))**(m + S(1))*(-a*d*p + b*c*(m + p + S(1)) + b*d*(m + S(1))*sin(e + f*x))/(b**S(2)*f*(m + S(1))*(m + p + S(1))), x) def replacement2640(a, b, c, d, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b**S(2)*(m + S(1))*(m + p + S(1))), Int((g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**(m + S(1))*Simp(b*d*(m + S(1)) + (-a*d*p + b*c*(m + p + S(1)))*cos(e + f*x), x), x), x) - Simp(g*(g*sin(e + f*x))**(p + S(-1))*(a + b*cos(e + f*x))**(m + S(1))*(-a*d*p + b*c*(m + p + S(1)) + b*d*(m + S(1))*cos(e + f*x))/(b**S(2)*f*(m + S(1))*(m + p + S(1))), x) def replacement2641(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1))*Simp((m + S(1))*(a*c - b*d) - (-a*d + b*c)*(m + p + S(2))*sin(e + f*x), x), x), x) - Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))*(-a*d + b*c)/(f*g*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2642(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1))*Simp((m + S(1))*(a*c - b*d) - (-a*d + b*c)*(m + p + S(2))*cos(e + f*x), x), x), x) + Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))*(-a*d + b*c)/(f*g*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2643(a, b, c, d, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b**S(2)*(m + p)*(m + p + S(1))), Int((g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**m*Simp(b*(a*d*m + b*c*(m + p + S(1))) + (a*b*c*(m + p + S(1)) - d*(a**S(2)*p - b**S(2)*(m + p)))*sin(e + f*x), x), x), x) + Simp(g*(g*cos(e + f*x))**(p + S(-1))*(a + b*sin(e + f*x))**(m + S(1))*(-a*d*p + b*c*(m + p + S(1)) + b*d*(m + p)*sin(e + f*x))/(b**S(2)*f*(m + p)*(m + p + S(1))), x) def replacement2644(a, b, c, d, e, f, g, m, p, x): return Dist(g**S(2)*(p + S(-1))/(b**S(2)*(m + p)*(m + p + S(1))), Int((g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**m*Simp(b*(a*d*m + b*c*(m + p + S(1))) + (a*b*c*(m + p + S(1)) - d*(a**S(2)*p - b**S(2)*(m + p)))*cos(e + f*x), x), x), x) - Simp(g*(g*sin(e + f*x))**(p + S(-1))*(a + b*cos(e + f*x))**(m + S(1))*(-a*d*p + b*c*(m + p + S(1)) + b*d*(m + p)*cos(e + f*x))/(b**S(2)*f*(m + p)*(m + p + S(1))), x) def replacement2645(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(a**S(2) - b**S(2))*(p + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**m*Simp(a*b*d*m + b*(a*c - b*d)*(m + p + S(3))*sin(e + f*x) + c*(a**S(2)*(p + S(2)) - b**S(2)*(m + p + S(2))), x), x), x) + Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))*(-a*d + b*c - (a*c - b*d)*sin(e + f*x))/(f*g*(a**S(2) - b**S(2))*(p + S(1))), x) def replacement2646(a, b, c, d, e, f, g, m, p, x): return Dist(S(1)/(g**S(2)*(a**S(2) - b**S(2))*(p + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**m*Simp(a*b*d*m + b*(a*c - b*d)*(m + p + S(3))*cos(e + f*x) + c*(a**S(2)*(p + S(2)) - b**S(2)*(m + p + S(2))), x), x), x) - Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))*(-a*d + b*c - (a*c - b*d)*cos(e + f*x))/(f*g*(a**S(2) - b**S(2))*(p + S(1))), x) def replacement2647(a, b, c, d, e, f, g, p, x): return Dist(d/b, Int((g*cos(e + f*x))**p, x), x) + Dist((-a*d + b*c)/b, Int((g*cos(e + f*x))**p/(a + b*sin(e + f*x)), x), x) def replacement2648(a, b, c, d, e, f, g, p, x): return Dist(d/b, Int((g*sin(e + f*x))**p, x), x) + Dist((-a*d + b*c)/b, Int((g*sin(e + f*x))**p/(a + b*cos(e + f*x)), x), x) def replacement2649(a, b, c, d, e, f, g, m, p, x): return Dist(c*g*(g*cos(e + f*x))**(p + S(-1))*(S(1) - sin(e + f*x))**(S(1)/2 - p/S(2))*(sin(e + f*x) + S(1))**(S(1)/2 - p/S(2))/f, Subst(Int((S(1) - d*x/c)**(p/S(2) + S(-1)/2)*(S(1) + d*x/c)**(p/S(2) + S(1)/2)*(a + b*x)**m, x), x, sin(e + f*x)), x) def replacement2650(a, b, c, d, e, f, g, m, p, x): return -Dist(c*g*(g*sin(e + f*x))**(p + S(-1))*(S(1) - cos(e + f*x))**(S(1)/2 - p/S(2))*(cos(e + f*x) + S(1))**(S(1)/2 - p/S(2))/f, Subst(Int((S(1) - d*x/c)**(p/S(2) + S(-1)/2)*(S(1) + d*x/c)**(p/S(2) + S(1)/2)*(a + b*x)**m, x), x, cos(e + f*x)), x) def replacement2651(a, b, d, e, f, m, n, p, x): return Dist(a**(S(2)*m), Int((d*sin(e + f*x))**n*(a - b*sin(e + f*x))**(-m), x), x) def replacement2652(a, b, d, e, f, m, n, p, x): return Dist(a**(S(2)*m), Int((d*cos(e + f*x))**n*(a - b*cos(e + f*x))**(-m), x), x) def replacement2653(a, b, e, f, g, m, p, x): return Dist(a/(S(2)*g**S(2)), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-1)), x), x) - Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))/(S(2)*b*f*g*(m + S(1))), x) def replacement2654(a, b, e, f, g, m, p, x): return Dist(a/(S(2)*g**S(2)), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-1)), x), x) + Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))/(S(2)*b*f*g*(m + S(1))), x) def replacement2655(a, b, e, f, g, m, p, x): return -Dist(g**(S(-2)), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**m, x), x) + Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(a*f*g*m), x) def replacement2656(a, b, e, f, g, m, p, x): return -Dist(g**(S(-2)), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**m, x), x) - Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(a*f*g*m), x) def replacement2657(a, b, d, e, f, m, n, p, x): return Dist(a**(-p), Int(ExpandTrig((d*sin(e + f*x))**n*(a - b*sin(e + f*x))**(p/S(2))*(a + b*sin(e + f*x))**(m + p/S(2)), x), x), x) def replacement2658(a, b, d, e, f, m, n, p, x): return Dist(a**(-p), Int(ExpandTrig((d*cos(e + f*x))**n*(a - b*cos(e + f*x))**(p/S(2))*(a + b*cos(e + f*x))**(m + p/S(2)), x), x), x) def replacement2659(a, b, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*cos(e + f*x))**p, (d*sin(e + f*x))**n*(a + b*sin(e + f*x))**m, x), x) def replacement2660(a, b, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*sin(e + f*x))**p, (d*cos(e + f*x))**n*(a + b*cos(e + f*x))**m, x), x) def replacement2661(a, b, d, e, f, m, n, x): return Dist(b**(S(-2)), Int((d*sin(e + f*x))**n*(a - b*sin(e + f*x))*(a + b*sin(e + f*x))**(m + S(1)), x), x) def replacement2662(a, b, d, e, f, m, n, x): return Dist(b**(S(-2)), Int((d*cos(e + f*x))**n*(a - b*cos(e + f*x))*(a + b*cos(e + f*x))**(m + S(1)), x), x) def replacement2663(a, b, d, e, f, g, m, n, p, x): return Dist((a/g)**(S(2)*m), Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(S(2)*m + p)*(a - b*sin(e + f*x))**(-m), x), x) def replacement2664(a, b, d, e, f, g, m, n, p, x): return Dist((a/g)**(S(2)*m), Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(S(2)*m + p)*(a - b*cos(e + f*x))**(-m), x), x) def replacement2665(a, b, d, e, f, g, m, n, p, x): return Dist((a/g)**(S(2)*m), Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(S(2)*m + p)*(a - b*sin(e + f*x))**(-m), x), x) def replacement2666(a, b, d, e, f, g, m, n, p, x): return Dist((a/g)**(S(2)*m), Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(S(2)*m + p)*(a - b*cos(e + f*x))**(-m), x), x) def replacement2667(a, b, e, f, g, m, p, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + p + S(1))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + p + S(1))*sin(e + f*x)), x), x) + Simp(b*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2668(a, b, e, f, g, m, p, x): return -Dist(S(1)/(a**S(2)*(S(2)*m + p + S(1))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**(m + S(1))*(a*m - b*(S(2)*m + p + S(1))*cos(e + f*x)), x), x) - Simp(b*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(a*f*g*(S(2)*m + p + S(1))), x) def replacement2669(a, b, e, f, g, m, p, x): return Dist(S(1)/(b*(m + p + S(2))), Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**m*(-a*(p + S(1))*sin(e + f*x) + b*(m + S(1))), x), x) - Simp((g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**(m + S(1))/(b*f*g*(m + p + S(2))), x) def replacement2670(a, b, e, f, g, m, p, x): return Dist(S(1)/(b*(m + p + S(2))), Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**m*(-a*(p + S(1))*cos(e + f*x) + b*(m + S(1))), x), x) + Simp((g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**(m + S(1))/(b*f*g*(m + p + S(2))), x) def replacement2671(a, b, d, e, f, m, n, x): return Dist(b**(S(-2)), Int((d*sin(e + f*x))**n*(a - b*sin(e + f*x))*(a + b*sin(e + f*x))**(m + S(1)), x), x) def replacement2672(a, b, d, e, f, m, n, x): return Dist(b**(S(-2)), Int((d*cos(e + f*x))**n*(a - b*cos(e + f*x))*(a + b*cos(e + f*x))**(m + S(1)), x), x) def replacement2673(a, b, d, e, f, m, n, x): return Dist(a**(S(-2)), Int((d*sin(e + f*x))**n*(a + b*sin(e + f*x))**(m + S(2))*(sin(e + f*x)**S(2) + S(1)), x), x) + Dist(-S(2)/(a*b*d), Int((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(2)), x), x) def replacement2674(a, b, d, e, f, m, n, x): return Dist(a**(S(-2)), Int((d*cos(e + f*x))**n*(a + b*cos(e + f*x))**(m + S(2))*(cos(e + f*x)**S(2) + S(1)), x), x) + Dist(-S(2)/(a*b*d), Int((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(2)), x), x) def replacement2675(a, b, d, e, f, m, n, x): return Dist(d**(S(-4)), Int((d*sin(e + f*x))**(n + S(4))*(a + b*sin(e + f*x))**m, x), x) + Int((d*sin(e + f*x))**n*(S(1) - S(2)*sin(e + f*x)**S(2))*(a + b*sin(e + f*x))**m, x) def replacement2676(a, b, d, e, f, m, n, x): return Dist(d**(S(-4)), Int((d*cos(e + f*x))**(n + S(4))*(a + b*cos(e + f*x))**m, x), x) + Int((d*cos(e + f*x))**n*(S(1) - S(2)*cos(e + f*x)**S(2))*(a + b*cos(e + f*x))**m, x) def replacement2677(a, b, d, e, f, m, n, p, x): return Dist(a**m*cos(e + f*x)/(f*sqrt(S(1) - sin(e + f*x))*sqrt(sin(e + f*x) + S(1))), Subst(Int((d*x)**n*(S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2678(a, b, d, e, f, m, n, p, x): return -Dist(a**m*sin(e + f*x)/(f*sqrt(S(1) - cos(e + f*x))*sqrt(cos(e + f*x) + S(1))), Subst(Int((d*x)**n*(S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2679(a, b, d, e, f, m, n, p, x): return Dist(a**(S(2) - p)*cos(e + f*x)/(f*sqrt(a - b*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), Subst(Int((d*x)**n*(a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2680(a, b, d, e, f, m, n, p, x): return -Dist(a**(S(2) - p)*sin(e + f*x)/(f*sqrt(a - b*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), Subst(Int((d*x)**n*(a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2681(a, b, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*cos(e + f*x))**p, (d*sin(e + f*x))**n*(a + b*sin(e + f*x))**m, x), x) def replacement2682(a, b, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*sin(e + f*x))**p, (d*cos(e + f*x))**n*(a + b*cos(e + f*x))**m, x), x) def replacement2683(a, b, d, e, f, g, m, n, p, x): return Dist(a**m*g*(g*cos(e + f*x))**(p + S(-1))*(S(1) - sin(e + f*x))**(S(1)/2 - p/S(2))*(sin(e + f*x) + S(1))**(S(1)/2 - p/S(2))/f, Subst(Int((d*x)**n*(S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2684(a, b, d, e, f, g, m, n, p, x): return -Dist(a**m*g*(g*sin(e + f*x))**(p + S(-1))*(S(1) - cos(e + f*x))**(S(1)/2 - p/S(2))*(cos(e + f*x) + S(1))**(S(1)/2 - p/S(2))/f, Subst(Int((d*x)**n*(S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2685(a, b, d, e, f, g, m, n, p, x): return Dist(g*(g*cos(e + f*x))**(p + S(-1))*(a - b*sin(e + f*x))**(S(1)/2 - p/S(2))*(a + b*sin(e + f*x))**(S(1)/2 - p/S(2))/f, Subst(Int((d*x)**n*(a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2686(a, b, d, e, f, g, m, n, p, x): return -Dist(g*(g*sin(e + f*x))**(p + S(-1))*(a - b*cos(e + f*x))**(S(1)/2 - p/S(2))*(a + b*cos(e + f*x))**(S(1)/2 - p/S(2))/f, Subst(Int((d*x)**n*(a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2687(a, b, d, e, f, g, m, p, x): return Dist(g**S(2)*(S(2)*m + S(3))/(S(2)*a*(m + S(1))), Int((g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**(m + S(1))/sqrt(d*sin(e + f*x)), x), x) - Simp(g*sqrt(d*sin(e + f*x))*(g*cos(e + f*x))**(p + S(-1))*(a + b*sin(e + f*x))**(m + S(1))/(a*d*f*(m + S(1))), x) def replacement2688(a, b, d, e, f, g, m, p, x): return Dist(g**S(2)*(S(2)*m + S(3))/(S(2)*a*(m + S(1))), Int((g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**(m + S(1))/sqrt(d*cos(e + f*x)), x), x) + Simp(g*sqrt(d*cos(e + f*x))*(g*sin(e + f*x))**(p + S(-1))*(a + b*cos(e + f*x))**(m + S(1))/(a*d*f*(m + S(1))), x) def replacement2689(a, b, d, e, f, g, m, p, x): return Dist(S(2)*a*m/(g**S(2)*(S(2)*m + S(1))), Int((g*cos(e + f*x))**(p + S(2))*(a + b*sin(e + f*x))**(m + S(-1))/sqrt(d*sin(e + f*x)), x), x) + Simp(S(2)*sqrt(d*sin(e + f*x))*(g*cos(e + f*x))**(p + S(1))*(a + b*sin(e + f*x))**m/(d*f*g*(S(2)*m + S(1))), x) def replacement2690(a, b, d, e, f, g, m, p, x): return Dist(S(2)*a*m/(g**S(2)*(S(2)*m + S(1))), Int((g*sin(e + f*x))**(p + S(2))*(a + b*cos(e + f*x))**(m + S(-1))/sqrt(d*cos(e + f*x)), x), x) + Simp(-S(2)*sqrt(d*cos(e + f*x))*(g*sin(e + f*x))**(p + S(1))*(a + b*cos(e + f*x))**m/(d*f*g*(S(2)*m + S(1))), x) def replacement2691(a, b, d, e, f, m, n, x): return Int((d*sin(e + f*x))**n*(S(1) - sin(e + f*x)**S(2))*(a + b*sin(e + f*x))**m, x) def replacement2692(a, b, d, e, f, m, n, x): return Int((d*cos(e + f*x))**n*(S(1) - cos(e + f*x)**S(2))*(a + b*cos(e + f*x))**m, x) def replacement2693(a, b, d, e, f, m, n, x): return Dist(S(1)/(a**S(2)*b*d*(m + S(1))*(n + S(1))), Int((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*Simp(a**S(2)*(n + S(1))*(n + S(2)) + a*b*(m + S(1))*sin(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(3)) - (a**S(2)*(n + S(1))*(n + S(3)) - b**S(2)*(m + n + S(2))*(m + n + S(4)))*sin(e + f*x)**S(2), x), x), x) + Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(a*d*f*(n + S(1))), x) - Simp((d*sin(e + f*x))**(n + S(2))*(a + b*sin(e + f*x))**(m + S(1))*(a**S(2)*(n + S(1)) - b**S(2)*(m + n + S(2)))*cos(e + f*x)/(a**S(2)*b*d**S(2)*f*(m + S(1))*(n + S(1))), x) def replacement2694(a, b, d, e, f, m, n, x): return Dist(S(1)/(a**S(2)*b*d*(m + S(1))*(n + S(1))), Int((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*Simp(a**S(2)*(n + S(1))*(n + S(2)) + a*b*(m + S(1))*cos(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(3)) - (a**S(2)*(n + S(1))*(n + S(3)) - b**S(2)*(m + n + S(2))*(m + n + S(4)))*cos(e + f*x)**S(2), x), x), x) - Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(a*d*f*(n + S(1))), x) + Simp((d*cos(e + f*x))**(n + S(2))*(a + b*cos(e + f*x))**(m + S(1))*(a**S(2)*(n + S(1)) - b**S(2)*(m + n + S(2)))*sin(e + f*x)/(a**S(2)*b*d**S(2)*f*(m + S(1))*(n + S(1))), x) def replacement2695(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a**S(2)*b**S(2)*(m + S(1))*(m + S(2))), Int((d*sin(e + f*x))**n*(a + b*sin(e + f*x))**(m + S(2))*Simp(a**S(2)*(n + S(1))*(n + S(3)) + a*b*(m + S(2))*sin(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(3)) - (a**S(2)*(n + S(2))*(n + S(3)) - b**S(2)*(m + n + S(2))*(m + n + S(4)))*sin(e + f*x)**S(2), x), x), x) + Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*(a**S(2) - b**S(2))*cos(e + f*x)/(a*b**S(2)*d*f*(m + S(1))), x) + Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(2))*(a**S(2)*(-m + n + S(1)) - b**S(2)*(m + n + S(2)))*cos(e + f*x)/(a**S(2)*b**S(2)*d*f*(m + S(1))*(m + S(2))), x) def replacement2696(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a**S(2)*b**S(2)*(m + S(1))*(m + S(2))), Int((d*cos(e + f*x))**n*(a + b*cos(e + f*x))**(m + S(2))*Simp(a**S(2)*(n + S(1))*(n + S(3)) + a*b*(m + S(2))*cos(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(3)) - (a**S(2)*(n + S(2))*(n + S(3)) - b**S(2)*(m + n + S(2))*(m + n + S(4)))*cos(e + f*x)**S(2), x), x), x) - Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*(a**S(2) - b**S(2))*sin(e + f*x)/(a*b**S(2)*d*f*(m + S(1))), x) - Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(2))*(a**S(2)*(-m + n + S(1)) - b**S(2)*(m + n + S(2)))*sin(e + f*x)/(a**S(2)*b**S(2)*d*f*(m + S(1))*(m + S(2))), x) def replacement2697(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*b**S(2)*(m + S(1))*(m + n + S(4))), Int((d*sin(e + f*x))**n*(a + b*sin(e + f*x))**(m + S(1))*Simp(a**S(2)*(n + S(1))*(n + S(3)) + a*b*(m + S(1))*sin(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(4)) - (a**S(2)*(n + S(2))*(n + S(3)) - b**S(2)*(m + n + S(3))*(m + n + S(4)))*sin(e + f*x)**S(2), x), x), x) - Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(2))*cos(e + f*x)/(b**S(2)*d*f*(m + n + S(4))), x) + Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*(a**S(2) - b**S(2))*cos(e + f*x)/(a*b**S(2)*d*f*(m + S(1))), x) def replacement2698(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a*b**S(2)*(m + S(1))*(m + n + S(4))), Int((d*cos(e + f*x))**n*(a + b*cos(e + f*x))**(m + S(1))*Simp(a**S(2)*(n + S(1))*(n + S(3)) + a*b*(m + S(1))*cos(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(4)) - (a**S(2)*(n + S(2))*(n + S(3)) - b**S(2)*(m + n + S(3))*(m + n + S(4)))*cos(e + f*x)**S(2), x), x), x) + Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(2))*sin(e + f*x)/(b**S(2)*d*f*(m + n + S(4))), x) - Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*(a**S(2) - b**S(2))*sin(e + f*x)/(a*b**S(2)*d*f*(m + S(1))), x) def replacement2699(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a**S(2)*d**S(2)*(n + S(1))*(n + S(2))), Int((d*sin(e + f*x))**(n + S(2))*(a + b*sin(e + f*x))**m*Simp(a**S(2)*n*(n + S(2)) + a*b*m*sin(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(3)) - (a**S(2)*(n + S(1))*(n + S(2)) - b**S(2)*(m + n + S(2))*(m + n + S(4)))*sin(e + f*x)**S(2), x), x), x) + Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(a*d*f*(n + S(1))), x) - Simp(b*(d*sin(e + f*x))**(n + S(2))*(a + b*sin(e + f*x))**(m + S(1))*(m + n + S(2))*cos(e + f*x)/(a**S(2)*d**S(2)*f*(n + S(1))*(n + S(2))), x) def replacement2700(a, b, d, e, f, m, n, x): return -Dist(S(1)/(a**S(2)*d**S(2)*(n + S(1))*(n + S(2))), Int((d*cos(e + f*x))**(n + S(2))*(a + b*cos(e + f*x))**m*Simp(a**S(2)*n*(n + S(2)) + a*b*m*cos(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(3)) - (a**S(2)*(n + S(1))*(n + S(2)) - b**S(2)*(m + n + S(2))*(m + n + S(4)))*cos(e + f*x)**S(2), x), x), x) - Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(a*d*f*(n + S(1))), x) + Simp(b*(d*cos(e + f*x))**(n + S(2))*(a + b*cos(e + f*x))**(m + S(1))*(m + n + S(2))*sin(e + f*x)/(a**S(2)*d**S(2)*f*(n + S(1))*(n + S(2))), x) def replacement2701(a, b, d, e, f, m, n, x): return Dist(S(1)/(a*b*d*(n + S(1))*(m + n + S(4))), Int((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**m*Simp(a**S(2)*(n + S(1))*(n + S(2)) + a*b*(m + S(3))*sin(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(4)) - (a**S(2)*(n + S(1))*(n + S(3)) - b**S(2)*(m + n + S(3))*(m + n + S(4)))*sin(e + f*x)**S(2), x), x), x) + Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(a*d*f*(n + S(1))), x) - Simp((d*sin(e + f*x))**(n + S(2))*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*d**S(2)*f*(m + n + S(4))), x) def replacement2702(a, b, d, e, f, m, n, x): return Dist(S(1)/(a*b*d*(n + S(1))*(m + n + S(4))), Int((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**m*Simp(a**S(2)*(n + S(1))*(n + S(2)) + a*b*(m + S(3))*cos(e + f*x) - b**S(2)*(m + n + S(2))*(m + n + S(4)) - (a**S(2)*(n + S(1))*(n + S(3)) - b**S(2)*(m + n + S(3))*(m + n + S(4)))*cos(e + f*x)**S(2), x), x), x) - Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(a*d*f*(n + S(1))), x) + Simp((d*cos(e + f*x))**(n + S(2))*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*d**S(2)*f*(m + n + S(4))), x) def replacement2703(a, b, d, e, f, m, n, x): return -Dist(S(1)/(b**S(2)*(m + n + S(3))*(m + n + S(4))), Int((d*sin(e + f*x))**n*(a + b*sin(e + f*x))**m*Simp(a**S(2)*(n + S(1))*(n + S(3)) + a*b*m*sin(e + f*x) - b**S(2)*(m + n + S(3))*(m + n + S(4)) - (a**S(2)*(n + S(2))*(n + S(3)) - b**S(2)*(m + n + S(3))*(m + n + S(5)))*sin(e + f*x)**S(2), x), x), x) - Simp((d*sin(e + f*x))**(n + S(2))*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*d**S(2)*f*(m + n + S(4))), x) + Simp(a*(d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*(n + S(3))*cos(e + f*x)/(b**S(2)*d*f*(m + n + S(3))*(m + n + S(4))), x) def replacement2704(a, b, d, e, f, m, n, x): return -Dist(S(1)/(b**S(2)*(m + n + S(3))*(m + n + S(4))), Int((d*cos(e + f*x))**n*(a + b*cos(e + f*x))**m*Simp(a**S(2)*(n + S(1))*(n + S(3)) + a*b*m*cos(e + f*x) - b**S(2)*(m + n + S(3))*(m + n + S(4)) - (a**S(2)*(n + S(2))*(n + S(3)) - b**S(2)*(m + n + S(3))*(m + n + S(5)))*cos(e + f*x)**S(2), x), x), x) + Simp((d*cos(e + f*x))**(n + S(2))*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*d**S(2)*f*(m + n + S(4))), x) - Simp(a*(d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*(n + S(3))*sin(e + f*x)/(b**S(2)*d*f*(m + n + S(3))*(m + n + S(4))), x) def replacement2705(a, b, d, e, f, m, n, x): return Dist(S(1)/(a**S(2)*b**S(2)*d**S(2)*(n + S(1))*(n + S(2))*(m + n + S(5))*(m + n + S(6))), Int((d*sin(e + f*x))**(n + S(2))*(a + b*sin(e + f*x))**m*Simp(a**S(4)*(n + S(1))*(n + S(2))*(n + S(3))*(n + S(5)) - a**S(2)*b**S(2)*(n + S(2))*(S(2)*n + S(1))*(m + n + S(5))*(m + n + S(6)) + a*b*m*(a**S(2)*(n + S(1))*(n + S(2)) - b**S(2)*(m + n + S(5))*(m + n + S(6)))*sin(e + f*x) + b**S(4)*(m + n + S(2))*(m + n + S(3))*(m + n + S(5))*(m + n + S(6)) - (a**S(4)*(n + S(1))*(n + S(2))*(n + S(4))*(n + S(5)) - a**S(2)*b**S(2)*(n + S(1))*(n + S(2))*(m + n + S(5))*(S(2)*m + S(2)*n + S(13)) + b**S(4)*(m + n + S(2))*(m + n + S(4))*(m + n + S(5))*(m + n + S(6)))*sin(e + f*x)**S(2), x), x), x) + Simp((d*sin(e + f*x))**(n + S(1))*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(a*d*f*(n + S(1))), x) + Simp((d*sin(e + f*x))**(n + S(4))*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*d**S(4)*f*(m + n + S(6))), x) - Simp(b*(d*sin(e + f*x))**(n + S(2))*(a + b*sin(e + f*x))**(m + S(1))*(m + n + S(2))*cos(e + f*x)/(a**S(2)*d**S(2)*f*(n + S(1))*(n + S(2))), x) - Simp(a*(d*sin(e + f*x))**(n + S(3))*(a + b*sin(e + f*x))**(m + S(1))*(n + S(5))*cos(e + f*x)/(b**S(2)*d**S(3)*f*(m + n + S(5))*(m + n + S(6))), x) def replacement2706(a, b, d, e, f, m, n, x): return Dist(S(1)/(a**S(2)*b**S(2)*d**S(2)*(n + S(1))*(n + S(2))*(m + n + S(5))*(m + n + S(6))), Int((d*cos(e + f*x))**(n + S(2))*(a + b*cos(e + f*x))**m*Simp(a**S(4)*(n + S(1))*(n + S(2))*(n + S(3))*(n + S(5)) - a**S(2)*b**S(2)*(n + S(2))*(S(2)*n + S(1))*(m + n + S(5))*(m + n + S(6)) + a*b*m*(a**S(2)*(n + S(1))*(n + S(2)) - b**S(2)*(m + n + S(5))*(m + n + S(6)))*cos(e + f*x) + b**S(4)*(m + n + S(2))*(m + n + S(3))*(m + n + S(5))*(m + n + S(6)) - (a**S(4)*(n + S(1))*(n + S(2))*(n + S(4))*(n + S(5)) - a**S(2)*b**S(2)*(n + S(1))*(n + S(2))*(m + n + S(5))*(S(2)*m + S(2)*n + S(13)) + b**S(4)*(m + n + S(2))*(m + n + S(4))*(m + n + S(5))*(m + n + S(6)))*cos(e + f*x)**S(2), x), x), x) - Simp((d*cos(e + f*x))**(n + S(1))*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(a*d*f*(n + S(1))), x) - Simp((d*cos(e + f*x))**(n + S(4))*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*d**S(4)*f*(m + n + S(6))), x) + Simp(b*(d*cos(e + f*x))**(n + S(2))*(a + b*cos(e + f*x))**(m + S(1))*(m + n + S(2))*sin(e + f*x)/(a**S(2)*d**S(2)*f*(n + S(1))*(n + S(2))), x) + Simp(a*(d*cos(e + f*x))**(n + S(3))*(a + b*cos(e + f*x))**(m + S(1))*(n + S(5))*sin(e + f*x)/(b**S(2)*d**S(3)*f*(m + n + S(5))*(m + n + S(6))), x) def replacement2707(a, b, d, e, f, m, n, p, x): return Int(ExpandTrig((d*sin(e + f*x))**n*(S(1) - sin(e + f*x)**S(2))**(p/S(2))*(a + b*sin(e + f*x))**m, x), x) def replacement2708(a, b, d, e, f, m, n, p, x): return Int(ExpandTrig((d*cos(e + f*x))**n*(S(1) - cos(e + f*x)**S(2))**(p/S(2))*(a + b*cos(e + f*x))**m, x), x) def replacement2709(a, b, e, f, g, n, p, x): return Int(ExpandTrig((g*cos(e + f*x))**p, sin(e + f*x)**n/(a + b*sin(e + f*x)), x), x) def replacement2710(a, b, e, f, g, n, p, x): return Int(ExpandTrig((g*sin(e + f*x))**p, cos(e + f*x)**n/(a + b*cos(e + f*x)), x), x) def replacement2711(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/a, Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(p + S(-2)), x), x) - Dist(b*g**S(2)/(a**S(2)*d), Int((d*sin(e + f*x))**(n + S(1))*(g*cos(e + f*x))**(p + S(-2)), x), x) - Dist(g**S(2)*(a**S(2) - b**S(2))/(a**S(2)*d**S(2)), Int((d*sin(e + f*x))**(n + S(2))*(g*cos(e + f*x))**(p + S(-2))/(a + b*sin(e + f*x)), x), x) def replacement2712(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/a, Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(p + S(-2)), x), x) - Dist(b*g**S(2)/(a**S(2)*d), Int((d*cos(e + f*x))**(n + S(1))*(g*sin(e + f*x))**(p + S(-2)), x), x) - Dist(g**S(2)*(a**S(2) - b**S(2))/(a**S(2)*d**S(2)), Int((d*cos(e + f*x))**(n + S(2))*(g*sin(e + f*x))**(p + S(-2))/(a + b*cos(e + f*x)), x), x) def replacement2713(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/(a*b), Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(p + S(-2))*(-a*sin(e + f*x) + b), x), x) + Dist(g**S(2)*(a**S(2) - b**S(2))/(a*b*d), Int((d*sin(e + f*x))**(n + S(1))*(g*cos(e + f*x))**(p + S(-2))/(a + b*sin(e + f*x)), x), x) def replacement2714(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/(a*b), Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(p + S(-2))*(-a*cos(e + f*x) + b), x), x) + Dist(g**S(2)*(a**S(2) - b**S(2))/(a*b*d), Int((d*cos(e + f*x))**(n + S(1))*(g*sin(e + f*x))**(p + S(-2))/(a + b*cos(e + f*x)), x), x) def replacement2715(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/b**S(2), Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(p + S(-2))*(a - b*sin(e + f*x)), x), x) - Dist(g**S(2)*(a**S(2) - b**S(2))/b**S(2), Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(p + S(-2))/(a + b*sin(e + f*x)), x), x) def replacement2716(a, b, d, e, f, g, n, p, x): return Dist(g**S(2)/b**S(2), Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(p + S(-2))*(a - b*cos(e + f*x)), x), x) - Dist(g**S(2)*(a**S(2) - b**S(2))/b**S(2), Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(p + S(-2))/(a + b*cos(e + f*x)), x), x) def replacement2717(a, b, d, e, f, g, n, p, x): return Dist(a*d**S(2)/(a**S(2) - b**S(2)), Int((d*sin(e + f*x))**(n + S(-2))*(g*cos(e + f*x))**p, x), x) - Dist(b*d/(a**S(2) - b**S(2)), Int((d*sin(e + f*x))**(n + S(-1))*(g*cos(e + f*x))**p, x), x) - Dist(a**S(2)*d**S(2)/(g**S(2)*(a**S(2) - b**S(2))), Int((d*sin(e + f*x))**(n + S(-2))*(g*cos(e + f*x))**(p + S(2))/(a + b*sin(e + f*x)), x), x) def replacement2718(a, b, d, e, f, g, n, p, x): return Dist(a*d**S(2)/(a**S(2) - b**S(2)), Int((d*cos(e + f*x))**(n + S(-2))*(g*sin(e + f*x))**p, x), x) - Dist(b*d/(a**S(2) - b**S(2)), Int((d*cos(e + f*x))**(n + S(-1))*(g*sin(e + f*x))**p, x), x) - Dist(a**S(2)*d**S(2)/(g**S(2)*(a**S(2) - b**S(2))), Int((d*cos(e + f*x))**(n + S(-2))*(g*sin(e + f*x))**(p + S(2))/(a + b*cos(e + f*x)), x), x) def replacement2719(a, b, d, e, f, g, n, p, x): return -Dist(d/(a**S(2) - b**S(2)), Int((d*sin(e + f*x))**(n + S(-1))*(g*cos(e + f*x))**p*(-a*sin(e + f*x) + b), x), x) + Dist(a*b*d/(g**S(2)*(a**S(2) - b**S(2))), Int((d*sin(e + f*x))**(n + S(-1))*(g*cos(e + f*x))**(p + S(2))/(a + b*sin(e + f*x)), x), x) def replacement2720(a, b, d, e, f, g, n, p, x): return -Dist(d/(a**S(2) - b**S(2)), Int((d*cos(e + f*x))**(n + S(-1))*(g*sin(e + f*x))**p*(-a*cos(e + f*x) + b), x), x) + Dist(a*b*d/(g**S(2)*(a**S(2) - b**S(2))), Int((d*cos(e + f*x))**(n + S(-1))*(g*sin(e + f*x))**(p + S(2))/(a + b*cos(e + f*x)), x), x) def replacement2721(a, b, d, e, f, g, n, p, x): return -Dist(b**S(2)/(g**S(2)*(a**S(2) - b**S(2))), Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(p + S(2))/(a + b*sin(e + f*x)), x), x) + Dist(S(1)/(a**S(2) - b**S(2)), Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**p*(a - b*sin(e + f*x)), x), x) def replacement2722(a, b, d, e, f, g, n, p, x): return -Dist(b**S(2)/(g**S(2)*(a**S(2) - b**S(2))), Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(p + S(2))/(a + b*cos(e + f*x)), x), x) + Dist(S(1)/(a**S(2) - b**S(2)), Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**p*(a - b*cos(e + f*x)), x), x) def replacement2723(a, b, e, f, g, x): return Dist(-S(4)*sqrt(S(2))*g/f, Subst(Int(x**S(2)/(sqrt(S(1) - x**S(4)/g**S(2))*(g**S(2)*(a + b) + x**S(4)*(a - b))), x), x, sqrt(g*cos(e + f*x))/sqrt(sin(e + f*x) + S(1))), x) def replacement2724(a, b, e, f, g, x): return Dist(S(4)*sqrt(S(2))*g/f, Subst(Int(x**S(2)/(sqrt(S(1) - x**S(4)/g**S(2))*(g**S(2)*(a + b) + x**S(4)*(a - b))), x), x, sqrt(g*sin(e + f*x))/sqrt(cos(e + f*x) + S(1))), x) def replacement2725(a, b, d, e, f, g, x): return Dist(sqrt(sin(e + f*x))/sqrt(d*sin(e + f*x)), Int(sqrt(g*cos(e + f*x))/((a + b*sin(e + f*x))*sqrt(sin(e + f*x))), x), x) def replacement2726(a, b, d, e, f, g, x): return Dist(sqrt(cos(e + f*x))/sqrt(d*cos(e + f*x)), Int(sqrt(g*sin(e + f*x))/((a + b*cos(e + f*x))*sqrt(cos(e + f*x))), x), x) def With2727(a, b, d, e, f, x): q = Rt(-a**S(2) + b**S(2), S(2)) return -Dist(S(2)*sqrt(S(2))*d*(b - q)/(f*q), Subst(Int(S(1)/(sqrt(S(1) - x**S(4)/d**S(2))*(a*x**S(2) + d*(b - q))), x), x, sqrt(d*sin(e + f*x))/sqrt(cos(e + f*x) + S(1))), x) + Dist(S(2)*sqrt(S(2))*d*(b + q)/(f*q), Subst(Int(S(1)/(sqrt(S(1) - x**S(4)/d**S(2))*(a*x**S(2) + d*(b + q))), x), x, sqrt(d*sin(e + f*x))/sqrt(cos(e + f*x) + S(1))), x) def With2728(a, b, d, e, f, x): q = Rt(-a**S(2) + b**S(2), S(2)) return Dist(S(2)*sqrt(S(2))*d*(b - q)/(f*q), Subst(Int(S(1)/(sqrt(S(1) - x**S(4)/d**S(2))*(a*x**S(2) + d*(b - q))), x), x, sqrt(d*cos(e + f*x))/sqrt(sin(e + f*x) + S(1))), x) + Dist(-S(2)*sqrt(S(2))*d*(b + q)/(f*q), Subst(Int(S(1)/(sqrt(S(1) - x**S(4)/d**S(2))*(a*x**S(2) + d*(b + q))), x), x, sqrt(d*cos(e + f*x))/sqrt(sin(e + f*x) + S(1))), x) def replacement2729(a, b, d, e, f, g, x): return Dist(sqrt(cos(e + f*x))/sqrt(g*cos(e + f*x)), Int(sqrt(d*sin(e + f*x))/((a + b*sin(e + f*x))*sqrt(cos(e + f*x))), x), x) def replacement2730(a, b, d, e, f, g, x): return Dist(sqrt(sin(e + f*x))/sqrt(g*sin(e + f*x)), Int(sqrt(d*cos(e + f*x))/((a + b*cos(e + f*x))*sqrt(sin(e + f*x))), x), x) def replacement2731(a, b, d, e, f, g, n, p, x): return Dist(d/b, Int((d*sin(e + f*x))**(n + S(-1))*(g*cos(e + f*x))**p, x), x) - Dist(a*d/b, Int((d*sin(e + f*x))**(n + S(-1))*(g*cos(e + f*x))**p/(a + b*sin(e + f*x)), x), x) def replacement2732(a, b, d, e, f, g, n, p, x): return Dist(d/b, Int((d*cos(e + f*x))**(n + S(-1))*(g*sin(e + f*x))**p, x), x) - Dist(a*d/b, Int((d*cos(e + f*x))**(n + S(-1))*(g*sin(e + f*x))**p/(a + b*cos(e + f*x)), x), x) def replacement2733(a, b, d, e, f, g, n, p, x): return Dist(S(1)/a, Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**p, x), x) - Dist(b/(a*d), Int((d*sin(e + f*x))**(n + S(1))*(g*cos(e + f*x))**p/(a + b*sin(e + f*x)), x), x) def replacement2734(a, b, d, e, f, g, n, p, x): return Dist(S(1)/a, Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**p, x), x) - Dist(b/(a*d), Int((d*cos(e + f*x))**(n + S(1))*(g*sin(e + f*x))**p/(a + b*cos(e + f*x)), x), x) def replacement2735(a, b, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*cos(e + f*x))**p, (d*sin(e + f*x))**n*(a + b*sin(e + f*x))**m, x), x) def replacement2736(a, b, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*sin(e + f*x))**p, (d*cos(e + f*x))**n*(a + b*cos(e + f*x))**m, x), x) def replacement2737(a, b, d, e, f, g, m, n, p, x): return Dist(g**S(2)/a, Int((d*sin(e + f*x))**n*(g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**(m + S(1)), x), x) - Dist(b*g**S(2)/(a**S(2)*d), Int((d*sin(e + f*x))**(n + S(1))*(g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**(m + S(1)), x), x) - Dist(g**S(2)*(a**S(2) - b**S(2))/(a**S(2)*d**S(2)), Int((d*sin(e + f*x))**(n + S(2))*(g*cos(e + f*x))**(p + S(-2))*(a + b*sin(e + f*x))**m, x), x) def replacement2738(a, b, d, e, f, g, m, n, p, x): return Dist(g**S(2)/a, Int((d*cos(e + f*x))**n*(g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**(m + S(1)), x), x) - Dist(b*g**S(2)/(a**S(2)*d), Int((d*cos(e + f*x))**(n + S(1))*(g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**(m + S(1)), x), x) - Dist(g**S(2)*(a**S(2) - b**S(2))/(a**S(2)*d**S(2)), Int((d*cos(e + f*x))**(n + S(2))*(g*sin(e + f*x))**(p + S(-2))*(a + b*cos(e + f*x))**m, x), x) def replacement2739(a, b, c, d, e, f, m, n, p, x): return Dist(a**(S(2)*m), Int((a - b*sin(e + f*x))**(-m)*(c + d*sin(e + f*x))**n, x), x) def replacement2740(a, b, c, d, e, f, m, n, p, x): return Dist(a**(S(2)*m), Int((a - b*cos(e + f*x))**(-m)*(c + d*cos(e + f*x))**n, x), x) def replacement2741(a, b, c, d, e, f, g, m, n, p, x): return Dist((a/g)**(S(2)*m), Int((g*cos(e + f*x))**(S(2)*m + p)*(a - b*sin(e + f*x))**(-m)*(c + d*sin(e + f*x))**n, x), x) def replacement2742(a, b, c, d, e, f, g, m, n, p, x): return Dist((a/g)**(S(2)*m), Int((g*sin(e + f*x))**(S(2)*m + p)*(a - b*cos(e + f*x))**(-m)*(c + d*cos(e + f*x))**n, x), x) def replacement2743(a, b, c, d, e, f, m, n, x): return Dist(b**(S(-2)), Int((a - b*sin(e + f*x))*(a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n, x), x) def replacement2744(a, b, c, d, e, f, m, n, x): return Dist(b**(S(-2)), Int((a - b*cos(e + f*x))*(a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n, x), x) def replacement2745(a, b, c, d, e, f, m, n, p, x): return Dist(a**m*cos(e + f*x)/(f*sqrt(S(1) - sin(e + f*x))*sqrt(sin(e + f*x) + S(1))), Subst(Int((S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, sin(e + f*x)), x) def replacement2746(a, b, c, d, e, f, m, n, p, x): return -Dist(a**m*sin(e + f*x)/(f*sqrt(S(1) - cos(e + f*x))*sqrt(cos(e + f*x) + S(1))), Subst(Int((S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, cos(e + f*x)), x) def replacement2747(a, b, c, d, e, f, m, n, p, x): return Dist(a**(S(2) - p)*cos(e + f*x)/(f*sqrt(a - b*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), Subst(Int((a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, sin(e + f*x)), x) def replacement2748(a, b, c, d, e, f, m, n, p, x): return -Dist(a**(S(2) - p)*sin(e + f*x)/(f*sqrt(a - b*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), Subst(Int((a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, cos(e + f*x)), x) def replacement2749(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*cos(e + f*x))**p, (a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) def replacement2750(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*sin(e + f*x))**p, (a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) def replacement2751(a, b, c, d, e, f, g, m, n, p, x): return Dist(a**m*g*(g*cos(e + f*x))**(p + S(-1))*(S(1) - sin(e + f*x))**(S(1)/2 - p/S(2))*(sin(e + f*x) + S(1))**(S(1)/2 - p/S(2))/f, Subst(Int((S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, sin(e + f*x)), x) def replacement2752(a, b, c, d, e, f, g, m, n, p, x): return -Dist(a**m*g*(g*sin(e + f*x))**(p + S(-1))*(S(1) - cos(e + f*x))**(S(1)/2 - p/S(2))*(cos(e + f*x) + S(1))**(S(1)/2 - p/S(2))/f, Subst(Int((S(1) - b*x/a)**(p/S(2) + S(-1)/2)*(S(1) + b*x/a)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, cos(e + f*x)), x) def replacement2753(a, b, c, d, e, f, g, m, n, p, x): return Dist(g*(g*cos(e + f*x))**(p + S(-1))*(a - b*sin(e + f*x))**(S(1)/2 - p/S(2))*(a + b*sin(e + f*x))**(S(1)/2 - p/S(2))/f, Subst(Int((a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, sin(e + f*x)), x) def replacement2754(a, b, c, d, e, f, g, m, n, p, x): return -Dist(g*(g*sin(e + f*x))**(p + S(-1))*(a - b*cos(e + f*x))**(S(1)/2 - p/S(2))*(a + b*cos(e + f*x))**(S(1)/2 - p/S(2))/f, Subst(Int((a - b*x)**(p/S(2) + S(-1)/2)*(a + b*x)**(m + p/S(2) + S(-1)/2)*(c + d*x)**n, x), x, cos(e + f*x)), x) def replacement2755(a, b, c, d, e, f, m, n, x): return Int((S(1) - sin(e + f*x)**S(2))*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x) def replacement2756(a, b, c, d, e, f, m, n, x): return Int((S(1) - cos(e + f*x)**S(2))*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x) def replacement2757(a, b, c, d, e, f, m, n, p, x): return Int(ExpandTrig((S(1) - sin(e + f*x)**S(2))**(p/S(2))*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) def replacement2758(a, b, c, d, e, f, m, n, p, x): return Int(ExpandTrig((S(1) - cos(e + f*x)**S(2))**(p/S(2))*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) def replacement2759(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) def replacement2760(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) def replacement2761(a, b, c, d, e, f, g, m, n, p, x): return Int((g*cos(e + f*x))**p*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x) def replacement2762(a, b, c, d, e, f, g, m, n, p, x): return Int((g*sin(e + f*x))**p*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x) def replacement2763(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(S(2)*IntPart(p))*(g/cos(e + f*x))**FracPart(p)*(g*cos(e + f*x))**FracPart(p), Int((g*cos(e + f*x))**(-p)*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) def replacement2764(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(S(2)*IntPart(p))*(g/sin(e + f*x))**FracPart(p)*(g*sin(e + f*x))**FracPart(p), Int((g*sin(e + f*x))**(-p)*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) def replacement2765(a, b, c, d, e, f, g, x): return Dist(g/d, Int(sqrt(a + b*sin(e + f*x))/sqrt(g*sin(e + f*x)), x), x) - Dist(c*g/d, Int(sqrt(a + b*sin(e + f*x))/(sqrt(g*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2766(a, b, c, d, e, f, g, x): return Dist(g/d, Int(sqrt(a + b*cos(e + f*x))/sqrt(g*cos(e + f*x)), x), x) - Dist(c*g/d, Int(sqrt(a + b*cos(e + f*x))/(sqrt(g*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2767(a, b, c, d, e, f, g, x): return Dist(b/d, Int(sqrt(g*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(sqrt(g*sin(e + f*x))/(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2768(a, b, c, d, e, f, g, x): return Dist(b/d, Int(sqrt(g*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) - Dist((-a*d + b*c)/d, Int(sqrt(g*cos(e + f*x))/(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2769(a, b, c, d, e, f, g, x): return Dist(-S(2)*b/f, Subst(Int(S(1)/(a*d + b*c + c*g*x**S(2)), x), x, b*cos(e + f*x)/(sqrt(g*sin(e + f*x))*sqrt(a + b*sin(e + f*x)))), x) def replacement2770(a, b, c, d, e, f, g, x): return Dist(S(2)*b/f, Subst(Int(S(1)/(a*d + b*c + c*g*x**S(2)), x), x, b*sin(e + f*x)/(sqrt(g*cos(e + f*x))*sqrt(a + b*cos(e + f*x)))), x) def replacement2771(a, b, c, d, e, f, x): return -Simp(sqrt(a + b)*EllipticE(asin(cos(e + f*x)/(sin(e + f*x) + S(1))), -(a - b)/(a + b))/(c*f), x) def replacement2772(a, b, c, d, e, f, x): return Simp(sqrt(a + b)*EllipticE(asin(sin(e + f*x)/(cos(e + f*x) + S(1))), -(a - b)/(a + b))/(c*f), x) def replacement2773(a, b, c, d, e, f, g, x): return -Simp(sqrt(d*sin(e + f*x)/(c + d*sin(e + f*x)))*sqrt(a + b*sin(e + f*x))*EllipticE(asin(c*cos(e + f*x)/(c + d*sin(e + f*x))), (-a*d + b*c)/(a*d + b*c))/(d*f*sqrt(g*sin(e + f*x))*sqrt(c**S(2)*(a + b*sin(e + f*x))/((c + d*sin(e + f*x))*(a*c + b*d)))), x) def replacement2774(a, b, c, d, e, f, g, x): return Simp(sqrt(d*cos(e + f*x)/(c + d*cos(e + f*x)))*sqrt(a + b*cos(e + f*x))*EllipticE(asin(c*sin(e + f*x)/(c + d*cos(e + f*x))), (-a*d + b*c)/(a*d + b*c))/(d*f*sqrt(g*cos(e + f*x))*sqrt(c**S(2)*(a + b*cos(e + f*x))/((c + d*cos(e + f*x))*(a*c + b*d)))), x) def replacement2775(a, b, c, d, e, f, g, x): return Dist(a/c, Int(S(1)/(sqrt(g*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), x), x) + Dist((-a*d + b*c)/(c*g), Int(sqrt(g*sin(e + f*x))/(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2776(a, b, c, d, e, f, g, x): return Dist(a/c, Int(S(1)/(sqrt(g*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), x), x) + Dist((-a*d + b*c)/(c*g), Int(sqrt(g*cos(e + f*x))/(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2777(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b*sin(e + f*x))/sin(e + f*x), x), x) - Dist(d/c, Int(sqrt(a + b*sin(e + f*x))/(c + d*sin(e + f*x)), x), x) def replacement2778(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b*cos(e + f*x))/cos(e + f*x), x), x) - Dist(d/c, Int(sqrt(a + b*cos(e + f*x))/(c + d*cos(e + f*x)), x), x) def replacement2779(a, b, c, d, e, f, x): return Dist(a/c, Int(S(1)/(sqrt(a + b*sin(e + f*x))*sin(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2780(a, b, c, d, e, f, x): return Dist(a/c, Int(S(1)/(sqrt(a + b*cos(e + f*x))*cos(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2781(a, b, c, d, e, f, g, x): return -Dist(a*g/(-a*d + b*c), Int(S(1)/(sqrt(g*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), x), x) + Dist(c*g/(-a*d + b*c), Int(sqrt(a + b*sin(e + f*x))/(sqrt(g*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2782(a, b, c, d, e, f, g, x): return -Dist(a*g/(-a*d + b*c), Int(S(1)/(sqrt(g*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), x), x) + Dist(c*g/(-a*d + b*c), Int(sqrt(a + b*cos(e + f*x))/(sqrt(g*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2783(a, b, c, d, e, f, g, x): return Simp(S(2)*sqrt(-S(1)/tan(e + f*x)**S(2))*sqrt(g*sin(e + f*x))*sqrt((a/sin(e + f*x) + b)/(a + b))*EllipticPi(S(2)*c/(c + d), asin(sqrt(S(2))*sqrt(S(1) - S(1)/sin(e + f*x))/S(2)), S(2)*a/(a + b))*tan(e + f*x)/(f*sqrt(a + b*sin(e + f*x))*(c + d)), x) def replacement2784(a, b, c, d, e, f, g, x): return Simp(-S(2)*sqrt(-tan(e + f*x)**S(2))*sqrt(g*cos(e + f*x))*sqrt((a/cos(e + f*x) + b)/(a + b))*EllipticPi(S(2)*c/(c + d), asin(sqrt(S(2))*sqrt(S(1) - S(1)/cos(e + f*x))/S(2)), S(2)*a/(a + b))/(f*sqrt(a + b*cos(e + f*x))*(c + d)*tan(e + f*x)), x) def replacement2785(a, b, c, d, e, f, g, x): return Dist(b/(-a*d + b*c), Int(S(1)/(sqrt(g*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), x), x) - Dist(d/(-a*d + b*c), Int(sqrt(a + b*sin(e + f*x))/(sqrt(g*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2786(a, b, c, d, e, f, g, x): return Dist(b/(-a*d + b*c), Int(S(1)/(sqrt(g*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), x), x) - Dist(d/(-a*d + b*c), Int(sqrt(a + b*cos(e + f*x))/(sqrt(g*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2787(a, b, c, d, e, f, g, x): return Dist(S(1)/c, Int(S(1)/(sqrt(g*sin(e + f*x))*sqrt(a + b*sin(e + f*x))), x), x) - Dist(d/(c*g), Int(sqrt(g*sin(e + f*x))/(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2788(a, b, c, d, e, f, g, x): return Dist(S(1)/c, Int(S(1)/(sqrt(g*cos(e + f*x))*sqrt(a + b*cos(e + f*x))), x), x) - Dist(d/(c*g), Int(sqrt(g*cos(e + f*x))/(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2789(a, b, c, d, e, f, x): return Dist(S(1)/(c*(-a*d + b*c)), Int((-a*d + b*c - b*d*sin(e + f*x))/(sqrt(a + b*sin(e + f*x))*sin(e + f*x)), x), x) + Dist(d**S(2)/(c*(-a*d + b*c)), Int(sqrt(a + b*sin(e + f*x))/(c + d*sin(e + f*x)), x), x) def replacement2790(a, b, c, d, e, f, x): return Dist(S(1)/(c*(-a*d + b*c)), Int((-a*d + b*c - b*d*cos(e + f*x))/(sqrt(a + b*cos(e + f*x))*cos(e + f*x)), x), x) + Dist(d**S(2)/(c*(-a*d + b*c)), Int(sqrt(a + b*cos(e + f*x))/(c + d*cos(e + f*x)), x), x) def replacement2791(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(S(1)/(sqrt(a + b*sin(e + f*x))*sin(e + f*x)), x), x) - Dist(d/c, Int(S(1)/(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) def replacement2792(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(S(1)/(sqrt(a + b*cos(e + f*x))*cos(e + f*x)), x), x) - Dist(d/c, Int(S(1)/(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) def replacement2793(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))/sin(e + f*x), x), x) - Dist(d/c, Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) def replacement2794(a, b, c, d, e, f, x): return Dist(S(1)/c, Int(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))/cos(e + f*x), x), x) - Dist(d/c, Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) def replacement2795(a, b, c, d, e, f, x): return Dist(-S(2)*a/f, Subst(Int(S(1)/(-a*c*x**S(2) + S(1)), x), x, cos(e + f*x)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x)))), x) def replacement2796(a, b, c, d, e, f, x): return Dist(S(2)*a/f, Subst(Int(S(1)/(-a*c*x**S(2) + S(1)), x), x, sin(e + f*x)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x)))), x) def replacement2797(a, b, c, d, e, f, x): return Dist(a/c, Int(sqrt(c + d*sin(e + f*x))/(sqrt(a + b*sin(e + f*x))*sin(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2798(a, b, c, d, e, f, x): return Dist(a/c, Int(sqrt(c + d*cos(e + f*x))/(sqrt(a + b*cos(e + f*x))*cos(e + f*x)), x), x) + Dist((-a*d + b*c)/c, Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2799(a, b, c, d, e, f, x): return Simp(-S(2)*sqrt((-a*d + b*c)*(sin(e + f*x) + S(1))/((a + b*sin(e + f*x))*(c - d)))*sqrt(-(S(1) - sin(e + f*x))*(-a*d + b*c)/((a + b*sin(e + f*x))*(c + d)))*(a + b*sin(e + f*x))*EllipticPi(a*(c + d)/(c*(a + b)), asin(sqrt(c + d*sin(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b*sin(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(c*f*Rt((a + b)/(c + d), S(2))*cos(e + f*x)), x) def replacement2800(a, b, c, d, e, f, x): return Simp(S(2)*sqrt((-a*d + b*c)*(cos(e + f*x) + S(1))/((a + b*cos(e + f*x))*(c - d)))*sqrt(-(S(1) - cos(e + f*x))*(-a*d + b*c)/((a + b*cos(e + f*x))*(c + d)))*(a + b*cos(e + f*x))*EllipticPi(a*(c + d)/(c*(a + b)), asin(sqrt(c + d*cos(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b*cos(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(c*f*Rt((a + b)/(c + d), S(2))*sin(e + f*x)), x) def replacement2801(a, b, c, d, e, f, x): return Dist(cos(e + f*x)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), Int(S(1)/(sin(e + f*x)*cos(e + f*x)), x), x) def replacement2802(a, b, c, d, e, f, x): return Dist(sin(e + f*x)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), Int(S(1)/(sin(e + f*x)*cos(e + f*x)), x), x) def replacement2803(a, b, c, d, e, f, x): return Dist(S(1)/a, Int(sqrt(a + b*sin(e + f*x))/(sqrt(c + d*sin(e + f*x))*sin(e + f*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2804(a, b, c, d, e, f, x): return Dist(S(1)/a, Int(sqrt(a + b*cos(e + f*x))/(sqrt(c + d*cos(e + f*x))*cos(e + f*x)), x), x) - Dist(b/a, Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2805(a, b, c, d, e, f, x): return Dist(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))/cos(e + f*x), Int(S(1)/tan(e + f*x), x), x) def replacement2806(a, b, c, d, e, f, x): return Dist(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))/sin(e + f*x), Int(tan(e + f*x), x), x) def replacement2807(a, b, c, d, e, f, x): return Dist(c, Int(sqrt(a + b*sin(e + f*x))/(sqrt(c + d*sin(e + f*x))*sin(e + f*x)), x), x) + Dist(d, Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) def replacement2808(a, b, c, d, e, f, x): return Dist(c, Int(sqrt(a + b*cos(e + f*x))/(sqrt(c + d*cos(e + f*x))*cos(e + f*x)), x), x) + Dist(d, Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) def replacement2809(a, b, c, d, e, f, m, n, p, x): return Dist(a**n*c**n, Int((a + b*sin(e + f*x))**(m - n)*tan(e + f*x)**p, x), x) def replacement2810(a, b, c, d, e, f, m, n, p, x): return Dist(a**n*c**n, Int((a + b*cos(e + f*x))**(m - n)*(S(1)/tan(e + f*x))**p, x), x) def replacement2811(a, b, c, d, e, f, g, m, n, p, x): return Dist(sqrt(a - b*sin(e + f*x))*sqrt(a + b*sin(e + f*x))/(f*cos(e + f*x)), Subst(Int((g*x)**p*(a + b*x)**(m + S(-1)/2)*(c + d*x)**n/sqrt(a - b*x), x), x, sin(e + f*x)), x) def replacement2812(a, b, c, d, e, f, g, m, n, p, x): return -Dist(sqrt(a - b*cos(e + f*x))*sqrt(a + b*cos(e + f*x))/(f*sin(e + f*x)), Subst(Int((g*x)**p*(a + b*x)**(m + S(-1)/2)*(c + d*x)**n/sqrt(a - b*x), x), x, cos(e + f*x)), x) def replacement2813(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*sin(e + f*x))**p*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) def replacement2814(a, b, c, d, e, f, g, m, n, p, x): return Int(ExpandTrig((g*cos(e + f*x))**p*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) def replacement2815(a, b, c, d, e, f, g, m, n, p, x): return Int((g*sin(e + f*x))**p*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x) def replacement2816(a, b, c, d, e, f, g, m, n, p, x): return Int((g*cos(e + f*x))**p*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x) def replacement2817(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(m + n), Int((g*sin(e + f*x))**(-m - n + p)*(a*sin(e + f*x) + b)**m*(c*sin(e + f*x) + d)**n, x), x) def replacement2818(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(m + n), Int((g*cos(e + f*x))**(-m - n + p)*(a*cos(e + f*x) + b)**m*(c*cos(e + f*x) + d)**n, x), x) def replacement2819(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/sin(e + f*x))**p*(g*sin(e + f*x))**p, Int((g/sin(e + f*x))**(-p)*(a + b/sin(e + f*x))**m*(c + d/sin(e + f*x))**n, x), x) def replacement2820(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/cos(e + f*x))**p*(g*cos(e + f*x))**p, Int((g/cos(e + f*x))**(-p)*(a + b/cos(e + f*x))**m*(c + d/cos(e + f*x))**n, x), x) def replacement2821(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**n, Int((g*sin(e + f*x))**(-n + p)*(a + b*sin(e + f*x))**m*(c*sin(e + f*x) + d)**n, x), x) def replacement2822(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**n, Int((g*cos(e + f*x))**(-n + p)*(a + b*cos(e + f*x))**m*(c*cos(e + f*x) + d)**n, x), x) def replacement2823(a, b, c, d, e, f, m, n, p, x): return Int((c + d/sin(e + f*x))**n*(a/sin(e + f*x) + b)**m*(S(1)/sin(e + f*x))**(-m - p), x) def replacement2824(a, b, c, d, e, f, m, n, p, x): return Int((c + d/cos(e + f*x))**n*(a/cos(e + f*x) + b)**m*(S(1)/cos(e + f*x))**(-m - p), x) def replacement2825(a, b, c, d, e, f, g, m, n, p, x): return Dist((g*sin(e + f*x))**p*(S(1)/sin(e + f*x))**p, Int((c + d/sin(e + f*x))**n*(a/sin(e + f*x) + b)**m*(S(1)/sin(e + f*x))**(-m - p), x), x) def replacement2826(a, b, c, d, e, f, g, m, n, p, x): return Dist((g*cos(e + f*x))**p*(S(1)/cos(e + f*x))**p, Int((c + d/cos(e + f*x))**n*(a/cos(e + f*x) + b)**m*(S(1)/cos(e + f*x))**(-m - p), x), x) def replacement2827(a, b, c, d, e, f, g, m, n, p, x): return Dist((g*sin(e + f*x))**n*(c + d/sin(e + f*x))**n*(c*sin(e + f*x) + d)**(-n), Int((g*sin(e + f*x))**(-n + p)*(a + b*sin(e + f*x))**m*(c*sin(e + f*x) + d)**n, x), x) def replacement2828(a, b, c, d, e, f, g, m, n, p, x): return Dist((g*cos(e + f*x))**n*(c + d/cos(e + f*x))**n*(c*cos(e + f*x) + d)**(-n), Int((g*cos(e + f*x))**(-n + p)*(a + b*cos(e + f*x))**m*(c*cos(e + f*x) + d)**n, x), x) def replacement2829(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(m + n), Int((g/sin(e + f*x))**(-m - n + p)*(a/sin(e + f*x) + b)**m*(c/sin(e + f*x) + d)**n, x), x) def replacement2830(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(m + n), Int((g/cos(e + f*x))**(-m - n + p)*(a/cos(e + f*x) + b)**m*(c/cos(e + f*x) + d)**n, x), x) def replacement2831(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/sin(e + f*x))**p*(g*sin(e + f*x))**p, Int((g*sin(e + f*x))**(-p)*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) def replacement2832(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/cos(e + f*x))**p*(g*cos(e + f*x))**p, Int((g*cos(e + f*x))**(-p)*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) def replacement2833(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**m, Int((g/sin(e + f*x))**(-m + p)*(c + d/sin(e + f*x))**n*(a/sin(e + f*x) + b)**m, x), x) def replacement2834(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**m, Int((g/cos(e + f*x))**(-m + p)*(c + d/cos(e + f*x))**n*(a/cos(e + f*x) + b)**m, x), x) def replacement2835(a, b, c, d, e, f, m, n, p, x): return Int((a + b*sin(e + f*x))**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-n - p), x) def replacement2836(a, b, c, d, e, f, m, n, p, x): return Int((a + b*cos(e + f*x))**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-n - p), x) def replacement2837(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/sin(e + f*x))**p*sin(e + f*x)**p, Int((a + b*sin(e + f*x))**m*(c*sin(e + f*x) + d)**n*sin(e + f*x)**(-n - p), x), x) def replacement2838(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/cos(e + f*x))**p*cos(e + f*x)**p, Int((a + b*cos(e + f*x))**m*(c*cos(e + f*x) + d)**n*cos(e + f*x)**(-n - p), x), x) def replacement2839(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/sin(e + f*x))**m*(a + b*sin(e + f*x))**m*(a/sin(e + f*x) + b)**(-m), Int((g/sin(e + f*x))**(-m + p)*(c + d/sin(e + f*x))**n*(a/sin(e + f*x) + b)**m, x), x) def replacement2840(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/cos(e + f*x))**m*(a + b*cos(e + f*x))**m*(a/cos(e + f*x) + b)**(-m), Int((g/cos(e + f*x))**(-m + p)*(c + d/cos(e + f*x))**n*(a/cos(e + f*x) + b)**m, x), x) def replacement2841(A, B, a, b, e, f, m, n, x): return Int(ExpandTrig((A + B*sin(e + f*x))*(a + b*sin(e + f*x))**m*sin(e + f*x)**n, x), x) def replacement2842(A, B, a, b, e, f, m, n, x): return Int(ExpandTrig((A + B*cos(e + f*x))*(a + b*cos(e + f*x))**m*cos(e + f*x)**n, x), x) def replacement2843(A, B, a, b, c, d, e, f, m, n, x): return Dist(a**m*c**m, Int((A + B*sin(e + f*x))*(c + d*sin(e + f*x))**(-m + n)*cos(e + f*x)**(S(2)*m), x), x) def replacement2844(A, B, a, b, c, d, e, f, m, n, x): return Dist(a**m*c**m, Int((A + B*cos(e + f*x))*(c + d*cos(e + f*x))**(-m + n)*sin(e + f*x)**(S(2)*m), x), x) def replacement2845(A, B, a, b, c, d, e, f, m, x): return Int((a + b*sin(e + f*x))**m*(A*c + B*d*sin(e + f*x)**S(2) + (A*d + B*c)*sin(e + f*x)), x) def replacement2846(A, B, a, b, c, d, e, f, m, x): return Int((a + b*cos(e + f*x))**m*(A*c + B*d*cos(e + f*x)**S(2) + (A*d + B*c)*cos(e + f*x)), x) def replacement2847(A, B, a, b, c, d, e, f, x): return Dist((A*b + B*a)/(S(2)*a*b), Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) + Dist((A*d + B*c)/(S(2)*c*d), Int(sqrt(c + d*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) def replacement2848(A, B, a, b, c, d, e, f, x): return Dist((A*b + B*a)/(S(2)*a*b), Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) + Dist((A*d + B*c)/(S(2)*c*d), Int(sqrt(c + d*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) def replacement2849(A, B, a, b, c, d, e, f, m, n, x): return -Simp(B*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(m + n + S(1))), x) def replacement2850(A, B, a, b, c, d, e, f, m, n, x): return Simp(B*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(m + n + S(1))), x) def replacement2851(A, B, a, b, c, d, e, f, n, x): return Dist(B/d, Int(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))**(n + S(1)), x), x) - Dist((-A*d + B*c)/d, Int(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))**n, x), x) def replacement2852(A, B, a, b, c, d, e, f, n, x): return Dist(B/d, Int(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))**(n + S(1)), x), x) - Dist((-A*d + B*c)/d, Int(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))**n, x), x) def replacement2853(A, B, a, b, c, d, e, f, m, n, x): return Dist((A*b*(m + n + S(1)) + B*a*(m - n))/(a*b*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n, x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*(A*b - B*a)*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2854(A, B, a, b, c, d, e, f, m, n, x): return Dist((A*b*(m + n + S(1)) + B*a*(m - n))/(a*b*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n, x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*(A*b - B*a)*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2855(A, B, a, b, c, d, e, f, m, n, x): return -Dist((-A*d*(m + n + S(1)) + B*c*(m - n))/(d*(m + n + S(1))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) - Simp(B*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(m + n + S(1))), x) def replacement2856(A, B, a, b, c, d, e, f, m, n, x): return -Dist((-A*d*(m + n + S(1)) + B*c*(m - n))/(d*(m + n + S(1))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) + Simp(B*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(m + n + S(1))), x) def replacement2857(A, B, a, b, c, d, e, f, m, n, x): return Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(-A*d + B*c)*cos(e + f*x)/(f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2858(A, B, a, b, c, d, e, f, m, n, x): return -Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(-A*d + B*c)*sin(e + f*x)/(f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2859(A, B, a, b, c, d, e, f, m, n, x): return -Dist(b/(d*(n + S(1))*(a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1))*Simp(A*a*d*(m - n + S(-2)) - B*(a*c*(m + S(-1)) + b*d*(n + S(1))) - (A*b*d*(m + n + S(1)) - B*(-a*d*(n + S(1)) + b*c*m))*sin(e + f*x), x), x), x) - Simp(b**S(2)*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1))*(-A*d + B*c)*cos(e + f*x)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement2860(A, B, a, b, c, d, e, f, m, n, x): return -Dist(b/(d*(n + S(1))*(a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1))*Simp(A*a*d*(m - n + S(-2)) - B*(a*c*(m + S(-1)) + b*d*(n + S(1))) - (A*b*d*(m + n + S(1)) - B*(-a*d*(n + S(1)) + b*c*m))*cos(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1))*(-A*d + B*c)*sin(e + f*x)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement2861(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n*Simp(A*a*d*(m + n + S(1)) + B*(a*c*(m + S(-1)) + b*d*(n + S(1))) + (A*b*d*(m + n + S(1)) - B*(-a*d*(S(2)*m + n) + b*c*m))*sin(e + f*x), x), x), x) - Simp(B*b*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(1))), x) def replacement2862(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n*Simp(A*a*d*(m + n + S(1)) + B*(a*c*(m + S(-1)) + b*d*(n + S(1))) + (A*b*d*(m + n + S(1)) - B*(-a*d*(S(2)*m + n) + b*c*m))*cos(e + f*x), x), x), x) + Simp(B*b*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(1))), x) def replacement2863(A, B, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(-1))*Simp(A*(a*d*n - b*c*(m + S(1))) - B*(a*c*m + b*d*n) - d*(A*b*(m + n + S(1)) + B*a*(m - n))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*(A*b - B*a)*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2864(A, B, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*b*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(-1))*Simp(A*(a*d*n - b*c*(m + S(1))) - B*(a*c*m + b*d*n) - d*(A*b*(m + n + S(1)) + B*a*(m - n))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*(A*b - B*a)*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2865(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(A*(-a*d*(S(2)*m + n + S(2)) + b*c*(m + S(1))) + B*(a*c*m + b*d*(n + S(1))) + d*(A*b - B*a)*(m + n + S(2))*sin(e + f*x), x), x), x) + Simp(b*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*b - B*a)*cos(e + f*x)/(a*f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2866(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(A*(-a*d*(S(2)*m + n + S(2)) + b*c*(m + S(1))) + B*(a*c*m + b*d*(n + S(1))) + d*(A*b - B*a)*(m + n + S(2))*cos(e + f*x), x), x), x) - Simp(b*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*b - B*a)*sin(e + f*x)/(a*f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2867(A, B, a, b, c, d, e, f, n, x): return Simp(-S(2)*B*b*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*sqrt(a + b*sin(e + f*x))*(S(2)*n + S(3))), x) def replacement2868(A, B, a, b, c, d, e, f, n, x): return Simp(S(2)*B*b*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*sqrt(a + b*cos(e + f*x))*(S(2)*n + S(3))), x) def replacement2869(A, B, a, b, c, d, e, f, n, x): return Dist((A*b*d*(S(2)*n + S(3)) - B*(-S(2)*a*d*(n + S(1)) + b*c))/(S(2)*d*(n + S(1))*(a*d + b*c)), Int(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))**(n + S(1)), x), x) - Simp(b**S(2)*(c + d*sin(e + f*x))**(n + S(1))*(-A*d + B*c)*cos(e + f*x)/(d*f*sqrt(a + b*sin(e + f*x))*(n + S(1))*(a*d + b*c)), x) def replacement2870(A, B, a, b, c, d, e, f, n, x): return Dist((A*b*d*(S(2)*n + S(3)) - B*(-S(2)*a*d*(n + S(1)) + b*c))/(S(2)*d*(n + S(1))*(a*d + b*c)), Int(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))**(n + S(1)), x), x) + Simp(b**S(2)*(c + d*cos(e + f*x))**(n + S(1))*(-A*d + B*c)*sin(e + f*x)/(d*f*sqrt(a + b*cos(e + f*x))*(n + S(1))*(a*d + b*c)), x) def replacement2871(A, B, a, b, c, d, e, f, n, x): return Dist((A*b*d*(S(2)*n + S(3)) - B*(-S(2)*a*d*(n + S(1)) + b*c))/(b*d*(S(2)*n + S(3))), Int(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))**n, x), x) + Simp(-S(2)*B*b*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*sqrt(a + b*sin(e + f*x))*(S(2)*n + S(3))), x) def replacement2872(A, B, a, b, c, d, e, f, n, x): return Dist((A*b*d*(S(2)*n + S(3)) - B*(-S(2)*a*d*(n + S(1)) + b*c))/(b*d*(S(2)*n + S(3))), Int(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))**n, x), x) + Simp(S(2)*B*b*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*sqrt(a + b*cos(e + f*x))*(S(2)*n + S(3))), x) def replacement2873(A, B, a, b, c, d, e, f, x): return Dist(B/b, Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) + Dist((A*b - B*a)/b, Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2874(A, B, a, b, c, d, e, f, x): return Dist(B/b, Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) + Dist((A*b - B*a)/b, Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2875(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n + S(1))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(-1))*Simp(A*b*c*(m + n + S(1)) + B*(a*c*m + b*d*n) + (A*b*d*(m + n + S(1)) + B*(a*d*m + b*c*n))*sin(e + f*x), x), x), x) - Simp(B*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(m + n + S(1))), x) def replacement2876(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(m + n + S(1))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(-1))*Simp(A*b*c*(m + n + S(1)) + B*(a*c*m + b*d*n) + (A*b*d*(m + n + S(1)) + B*(a*d*m + b*c*n))*cos(e + f*x), x), x), x) + Simp(B*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(m + n + S(1))), x) def replacement2877(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*Simp(A*(a*d*m + b*c*(n + S(1))) - B*(a*c*m + b*d*(n + S(1))) + b*(-A*d + B*c)*(m + n + S(2))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(-A*d + B*c)*cos(e + f*x)/(f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2878(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*Simp(A*(a*d*m + b*c*(n + S(1))) - B*(a*c*m + b*d*(n + S(1))) + b*(-A*d + B*c)*(m + n + S(2))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(-A*d + B*c)*sin(e + f*x)/(f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2879(A, B, a, b, c, d, e, f, x): return Dist((A*b - B*a)/(-a*d + b*c), Int(S(1)/sqrt(a + b*sin(e + f*x)), x), x) + Dist((-A*d + B*c)/(-a*d + b*c), Int(sqrt(a + b*sin(e + f*x))/(c + d*sin(e + f*x)), x), x) def replacement2880(A, B, a, b, c, d, e, f, x): return Dist((A*b - B*a)/(-a*d + b*c), Int(S(1)/sqrt(a + b*cos(e + f*x)), x), x) + Dist((-A*d + B*c)/(-a*d + b*c), Int(sqrt(a + b*cos(e + f*x))/(c + d*cos(e + f*x)), x), x) def replacement2881(A, B, a, b, c, d, e, f, m, x): return Dist(B/d, Int((a + b*sin(e + f*x))**m, x), x) - Dist((-A*d + B*c)/d, Int((a + b*sin(e + f*x))**m/(c + d*sin(e + f*x)), x), x) def replacement2882(A, B, a, b, c, d, e, f, m, x): return Dist(B/d, Int((a + b*cos(e + f*x))**m, x), x) - Dist((-A*d + B*c)/d, Int((a + b*cos(e + f*x))**m/(c + d*cos(e + f*x)), x), x) def replacement2883(A, B, a, b, c, d, e, f, m, n, x): return Dist(B/b, Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n, x), x) + Dist((A*b - B*a)/b, Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x), x) def replacement2884(A, B, a, b, c, d, e, f, m, n, x): return Dist(B/b, Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n, x), x) + Dist((A*b - B*a)/b, Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x), x) def replacement2885(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**(n + S(1))*Simp(a*d*(n + S(1))*(A*a*c + B*b*c - d*(A*b + B*a)) + b*(m + S(-1))*(-A*d + B*c)*(-a*d + b*c) + b*(-B*b*(c**S(2)*m + d**S(2)*(n + S(1))) + d*(m + n + S(1))*(-A*a*d + A*b*c + B*a*c))*sin(e + f*x)**S(2) + (-a*(n + S(2))*(-A*d + B*c)*(-a*d + b*c) + b*(n + S(1))*(a*(A*c*d + B*(c**S(2) - S(2)*d**S(2))) + b*d*(-A*d + B*c)))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1))*(-A*d + B*c)*(-a*d + b*c)*cos(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2886(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**(n + S(1))*Simp(a*d*(n + S(1))*(A*a*c + B*b*c - d*(A*b + B*a)) + b*(m + S(-1))*(-A*d + B*c)*(-a*d + b*c) + b*(-B*b*(c**S(2)*m + d**S(2)*(n + S(1))) + d*(m + n + S(1))*(-A*a*d + A*b*c + B*a*c))*cos(e + f*x)**S(2) + (-a*(n + S(2))*(-A*d + B*c)*(-a*d + b*c) + b*(n + S(1))*(a*(A*c*d + B*(c**S(2) - S(2)*d**S(2))) + b*d*(-A*d + B*c)))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1))*(-A*d + B*c)*(-a*d + b*c)*sin(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2887(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b*sin(e + f*x))**(m + S(-2))*(c + d*sin(e + f*x))**n*Simp(A*a**S(2)*d*(m + n + S(1)) + B*b*(a*d*(n + S(1)) + b*c*(m + S(-1))) + b*(A*b*d*(m + n + S(1)) - B*(-a*d*(S(2)*m + n) + b*c*m))*sin(e + f*x)**S(2) + (-B*b*(a*c - b*d*(m + n)) + a*d*(S(2)*A*b + B*a)*(m + n + S(1)))*sin(e + f*x), x), x), x) - Simp(B*b*(a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(1))), x) def replacement2888(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b*cos(e + f*x))**(m + S(-2))*(c + d*cos(e + f*x))**n*Simp(A*a**S(2)*d*(m + n + S(1)) + B*b*(a*d*(n + S(1)) + b*c*(m + S(-1))) + b*(A*b*d*(m + n + S(1)) - B*(-a*d*(S(2)*m + n) + b*c*m))*cos(e + f*x)**S(2) + (-B*b*(a*c - b*d*(m + n)) + a*d*(S(2)*A*b + B*a)*(m + n + S(1)))*cos(e + f*x), x), x), x) + Simp(B*b*(a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(1))), x) def replacement2889(A, B, b, c, d, e, f, x): return Dist(B*d/b**S(2), Int(sqrt(b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) + Int((A*c + (A*d + B*c)*sin(e + f*x))/((b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x) def replacement2890(A, B, b, c, d, e, f, x): return Dist(B*d/b**S(2), Int(sqrt(b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) + Int((A*c + (A*d + B*c)*cos(e + f*x))/((b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x) def replacement2891(A, B, a, b, c, d, e, f, x): return Dist(B/b, Int(sqrt(c + d*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) + Dist((A*b - B*a)/b, Int(sqrt(c + d*sin(e + f*x))/(a + b*sin(e + f*x))**(S(3)/2), x), x) def replacement2892(A, B, a, b, c, d, e, f, x): return Dist(B/b, Int(sqrt(c + d*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) + Dist((A*b - B*a)/b, Int(sqrt(c + d*cos(e + f*x))/(a + b*cos(e + f*x))**(S(3)/2), x), x) def replacement2893(A, B, a, b, d, e, f, x): return Dist(d/(a**S(2) - b**S(2)), Int((A*b - B*a + (A*a - B*b)*sin(e + f*x))/((d*sin(e + f*x))**(S(3)/2)*sqrt(a + b*sin(e + f*x))), x), x) + Simp(S(2)*(A*b - B*a)*cos(e + f*x)/(f*sqrt(d*sin(e + f*x))*sqrt(a + b*sin(e + f*x))*(a**S(2) - b**S(2))), x) def replacement2894(A, B, a, b, d, e, f, x): return Dist(d/(a**S(2) - b**S(2)), Int((A*b - B*a + (A*a - B*b)*cos(e + f*x))/((d*cos(e + f*x))**(S(3)/2)*sqrt(a + b*cos(e + f*x))), x), x) + Simp(-S(2)*(A*b - B*a)*sin(e + f*x)/(f*sqrt(d*cos(e + f*x))*sqrt(a + b*cos(e + f*x))*(a**S(2) - b**S(2))), x) def replacement2895(A, B, b, c, d, e, f, x): return Simp(-S(2)*A*sqrt(c*(S(1) - S(1)/sin(e + f*x))/(c + d))*sqrt(c*(S(1) + S(1)/sin(e + f*x))/(c - d))*(c - d)*EllipticE(asin(sqrt(c + d*sin(e + f*x))/(sqrt(b*sin(e + f*x))*Rt((c + d)/b, S(2)))), -(c + d)/(c - d))*Rt((c + d)/b, S(2))*tan(e + f*x)/(b*c**S(2)*f), x) def replacement2896(A, B, b, c, d, e, f, x): return Simp(S(2)*A*sqrt(c*(S(1) - S(1)/cos(e + f*x))/(c + d))*sqrt(c*(S(1) + S(1)/cos(e + f*x))/(c - d))*(c - d)*EllipticE(asin(sqrt(c + d*cos(e + f*x))/(sqrt(b*cos(e + f*x))*Rt((c + d)/b, S(2)))), -(c + d)/(c - d))*Rt((c + d)/b, S(2))/(b*c**S(2)*f*tan(e + f*x)), x) def replacement2897(A, B, b, c, d, e, f, x): return -Dist(sqrt(-b*sin(e + f*x))/sqrt(b*sin(e + f*x)), Int((A + B*sin(e + f*x))/((-b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) def replacement2898(A, B, b, c, d, e, f, x): return -Dist(sqrt(-b*cos(e + f*x))/sqrt(b*cos(e + f*x)), Int((A + B*cos(e + f*x))/((-b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) def replacement2899(A, B, a, b, c, d, e, f, x): return Simp(-S(2)*A*sqrt((-a*d + b*c)*(sin(e + f*x) + S(1))/((a + b*sin(e + f*x))*(c - d)))*sqrt(-(S(1) - sin(e + f*x))*(-a*d + b*c)/((a + b*sin(e + f*x))*(c + d)))*(a + b*sin(e + f*x))*(c - d)*EllipticE(asin(sqrt(c + d*sin(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b*sin(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(f*(-a*d + b*c)**S(2)*Rt((a + b)/(c + d), S(2))*cos(e + f*x)), x) def replacement2900(A, B, a, b, c, d, e, f, x): return Simp(S(2)*A*sqrt((-a*d + b*c)*(cos(e + f*x) + S(1))/((a + b*cos(e + f*x))*(c - d)))*sqrt(-(S(1) - cos(e + f*x))*(-a*d + b*c)/((a + b*cos(e + f*x))*(c + d)))*(a + b*cos(e + f*x))*(c - d)*EllipticE(asin(sqrt(c + d*cos(e + f*x))*Rt((a + b)/(c + d), S(2))/sqrt(a + b*cos(e + f*x))), (a - b)*(c + d)/((a + b)*(c - d)))/(f*(-a*d + b*c)**S(2)*Rt((a + b)/(c + d), S(2))*sin(e + f*x)), x) def replacement2901(A, B, a, b, c, d, e, f, x): return Dist(sqrt(-c - d*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), Int((A + B*sin(e + f*x))/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(-c - d*sin(e + f*x))), x), x) def replacement2902(A, B, a, b, c, d, e, f, x): return Dist(sqrt(-c - d*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), Int((A + B*cos(e + f*x))/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(-c - d*cos(e + f*x))), x), x) def replacement2903(A, B, a, b, c, d, e, f, x): return Dist((A - B)/(a - b), Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) - Dist((A*b - B*a)/(a - b), Int((sin(e + f*x) + S(1))/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) def replacement2904(A, B, a, b, c, d, e, f, x): return Dist((A - B)/(a - b), Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) - Dist((A*b - B*a)/(a - b), Int((cos(e + f*x) + S(1))/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) def replacement2905(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(-1))*Simp(c*(m + S(1))*(A*a - B*b) + d*n*(A*b - B*a) - d*(A*b - B*a)*(m + n + S(2))*sin(e + f*x)**S(2) + (-c*(m + S(2))*(A*b - B*a) + d*(m + S(1))*(A*a - B*b))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*(-A*b + B*a)*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2906(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(-1))*Simp(c*(m + S(1))*(A*a - B*b) + d*n*(A*b - B*a) - d*(A*b - B*a)*(m + n + S(2))*cos(e + f*x)**S(2) + (-c*(m + S(2))*(A*b - B*a) + d*(m + S(1))*(A*a - B*b))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*(-A*b + B*a)*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2907(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(b*d*(A*b - B*a)*(m + n + S(2)) - b*d*(A*b - B*a)*(m + n + S(3))*sin(e + f*x)**S(2) + (m + S(1))*(A*a - B*b)*(-a*d + b*c) + (A*b - B*a)*(a*d*(m + S(1)) - b*c*(m + S(2)))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(1))*(A*b**S(2) - B*a*b)*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement2908(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(b*d*(A*b - B*a)*(m + n + S(2)) - b*d*(A*b - B*a)*(m + n + S(3))*cos(e + f*x)**S(2) + (m + S(1))*(A*a - B*b)*(-a*d + b*c) + (A*b - B*a)*(a*d*(m + S(1)) - b*c*(m + S(2)))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(1))*(A*b**S(2) - B*a*b)*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement2909(A, B, a, b, c, d, e, f, x): return Dist((A*b - B*a)/(-a*d + b*c), Int(S(1)/(a + b*sin(e + f*x)), x), x) + Dist((-A*d + B*c)/(-a*d + b*c), Int(S(1)/(c + d*sin(e + f*x)), x), x) def replacement2910(A, B, a, b, c, d, e, f, x): return Dist((A*b - B*a)/(-a*d + b*c), Int(S(1)/(a + b*cos(e + f*x)), x), x) + Dist((-A*d + B*c)/(-a*d + b*c), Int(S(1)/(c + d*cos(e + f*x)), x), x) def replacement2911(A, B, a, b, c, d, e, f, m, x): return Dist(B/d, Int((a + b*sin(e + f*x))**m, x), x) - Dist((-A*d + B*c)/d, Int((a + b*sin(e + f*x))**m/(c + d*sin(e + f*x)), x), x) def replacement2912(A, B, a, b, c, d, e, f, m, x): return Dist(B/d, Int((a + b*cos(e + f*x))**m, x), x) - Dist((-A*d + B*c)/d, Int((a + b*cos(e + f*x))**m/(c + d*cos(e + f*x)), x), x) def replacement2913(A, B, a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*n + S(3)), Int((c + d*sin(e + f*x))**(n + S(-1))*Simp(A*a*c*(S(2)*n + S(3)) + B*(S(2)*a*d*n + b*c) + (A*(S(2)*n + S(3))*(a*d + b*c) + B*(S(2)*n + S(1))*(a*c + b*d))*sin(e + f*x) + (A*b*d*(S(2)*n + S(3)) + B*(a*d + S(2)*b*c*n))*sin(e + f*x)**S(2), x)/sqrt(a + b*sin(e + f*x)), x), x) + Simp(-S(2)*B*sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))**n*cos(e + f*x)/(f*(S(2)*n + S(3))), x) def replacement2914(A, B, a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*n + S(3)), Int((c + d*cos(e + f*x))**(n + S(-1))*Simp(A*a*c*(S(2)*n + S(3)) + B*(S(2)*a*d*n + b*c) + (A*(S(2)*n + S(3))*(a*d + b*c) + B*(S(2)*n + S(1))*(a*c + b*d))*cos(e + f*x) + (A*b*d*(S(2)*n + S(3)) + B*(a*d + S(2)*b*c*n))*cos(e + f*x)**S(2), x)/sqrt(a + b*cos(e + f*x)), x), x) + Simp(S(2)*B*sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))**n*sin(e + f*x)/(f*(S(2)*n + S(3))), x) def replacement2915(A, B, a, b, e, f, x): return Simp(S(4)*A*EllipticPi(S(-1), -asin(cos(e + f*x)/(sin(e + f*x) + S(1))), -(a - b)/(a + b))/(f*sqrt(a + b)), x) def replacement2916(A, B, a, b, e, f, x): return Simp(S(4)*A*EllipticPi(S(-1), asin(sin(e + f*x)/(cos(e + f*x) + S(1))), -(a - b)/(a + b))/(f*sqrt(a + b)), x) def replacement2917(A, B, a, b, d, e, f, x): return Dist(sqrt(sin(e + f*x))/sqrt(d*sin(e + f*x)), Int((A + B*sin(e + f*x))/(sqrt(a + b*sin(e + f*x))*sqrt(sin(e + f*x))), x), x) def replacement2918(A, B, a, b, d, e, f, x): return Dist(sqrt(cos(e + f*x))/sqrt(d*cos(e + f*x)), Int((A + B*cos(e + f*x))/(sqrt(a + b*cos(e + f*x))*sqrt(cos(e + f*x))), x), x) def replacement2919(A, B, a, b, c, d, e, f, x): return Dist(B/d, Int(sqrt(c + d*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) - Dist((-A*d + B*c)/d, Int(S(1)/(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))), x), x) def replacement2920(A, B, a, b, c, d, e, f, x): return Dist(B/d, Int(sqrt(c + d*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) - Dist((-A*d + B*c)/d, Int(S(1)/(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))), x), x) def replacement2921(A, B, a, b, c, d, e, f, m, n, x): return Int((A + B*sin(e + f*x))*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x) def replacement2922(A, B, a, b, c, d, e, f, m, n, x): return Int((A + B*cos(e + f*x))*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x) def replacement2923(A, B, a, b, c, d, e, f, m, n, p, x): return Dist(sqrt(a + b*sin(e + f*x))*sqrt(c + d*sin(e + f*x))/(f*cos(e + f*x)), Subst(Int((A + B*x)**p*(a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2), x), x, sin(e + f*x)), x) def replacement2924(A, B, a, b, c, d, e, f, m, n, p, x): return -Dist(sqrt(a + b*cos(e + f*x))*sqrt(c + d*cos(e + f*x))/(f*sin(e + f*x)), Subst(Int((A + B*x)**p*(a + b*x)**(m + S(-1)/2)*(c + d*x)**(n + S(-1)/2), x), x, cos(e + f*x)), x) def replacement2925(B, C, b, e, f, m, x): return Dist(S(1)/b, Int((b*sin(e + f*x))**(m + S(1))*(B + C*sin(e + f*x)), x), x) def replacement2926(B, C, b, e, f, m, x): return Dist(S(1)/b, Int((b*cos(e + f*x))**(m + S(1))*(B + C*cos(e + f*x)), x), x) def replacement2927(A, C, e, f, m, x): return -Dist(S(1)/f, Subst(Int((S(1) - x**S(2))**(m/S(2) + S(-1)/2)*(A - C*x**S(2) + C), x), x, cos(e + f*x)), x) def replacement2928(A, C, e, f, m, x): return Dist(S(1)/f, Subst(Int((S(1) - x**S(2))**(m/S(2) + S(-1)/2)*(A - C*x**S(2) + C), x), x, sin(e + f*x)), x) def replacement2929(A, C, b, e, f, m, x): return Simp(A*(b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(1))), x) def replacement2930(A, C, b, e, f, m, x): return -Simp(A*(b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(1))), x) def replacement2931(A, C, b, e, f, m, x): return Dist((A*(m + S(2)) + C*(m + S(1)))/(b**S(2)*(m + S(1))), Int((b*sin(e + f*x))**(m + S(2)), x), x) + Simp(A*(b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(1))), x) def replacement2932(A, C, b, e, f, m, x): return Dist((A*(m + S(2)) + C*(m + S(1)))/(b**S(2)*(m + S(1))), Int((b*cos(e + f*x))**(m + S(2)), x), x) - Simp(A*(b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(1))), x) def replacement2933(A, C, b, e, f, m, x): return Dist((A*(m + S(2)) + C*(m + S(1)))/(m + S(2)), Int((b*sin(e + f*x))**m, x), x) - Simp(C*(b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(2))), x) def replacement2934(A, C, b, e, f, m, x): return Dist((A*(m + S(2)) + C*(m + S(1)))/(m + S(2)), Int((b*cos(e + f*x))**m, x), x) + Simp(C*(b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(2))), x) def replacement2935(A, B, C, a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(B*b - C*a + C*b*sin(e + f*x), x), x), x) def replacement2936(A, B, C, a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(B*b - C*a + C*b*cos(e + f*x), x), x), x) def replacement2937(A, C, a, b, e, f, m, x): return Dist(C/b**S(2), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(-a + b*sin(e + f*x), x), x), x) def replacement2938(A, C, a, b, e, f, m, x): return Dist(C/b**S(2), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(-a + b*cos(e + f*x), x), x), x) def replacement2939(A, B, C, a, b, e, f, m, x): return Dist(C, Int((a + b*sin(e + f*x))**m*(sin(e + f*x) + S(1))**S(2), x), x) + Dist(A - C, Int((a + b*sin(e + f*x))**m*(sin(e + f*x) + S(1)), x), x) def replacement2940(A, B, C, a, b, e, f, m, x): return Dist(C, Int((a + b*cos(e + f*x))**m*(cos(e + f*x) + S(1))**S(2), x), x) + Dist(A - C, Int((a + b*cos(e + f*x))**m*(cos(e + f*x) + S(1)), x), x) def replacement2941(A, C, a, b, e, f, m, x): return Dist(C, Int((a + b*sin(e + f*x))**m*(sin(e + f*x) + S(1))**S(2), x), x) + Dist(A - C, Int((a + b*sin(e + f*x))**m*(sin(e + f*x) + S(1)), x), x) def replacement2942(A, C, a, b, e, f, m, x): return Dist(C, Int((a + b*cos(e + f*x))**m*(cos(e + f*x) + S(1))**S(2), x), x) + Dist(A - C, Int((a + b*cos(e + f*x))**m*(cos(e + f*x) + S(1)), x), x) def replacement2943(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(A*a*(m + S(1)) + C*b*(S(2)*m + S(1))*sin(e + f*x) + m*(B*b - C*a), x), x), x) + Simp((a + b*sin(e + f*x))**m*(A*b - B*a + C*b)*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2944(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(A*a*(m + S(1)) + C*b*(S(2)*m + S(1))*cos(e + f*x) + m*(B*b - C*a), x), x), x) - Simp((a + b*cos(e + f*x))**m*(A*b - B*a + C*b)*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2945(A, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(A*a*(m + S(1)) - C*a*m + C*b*(S(2)*m + S(1))*sin(e + f*x), x), x), x) + Simp(b*(A + C)*(a + b*sin(e + f*x))**m*cos(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2946(A, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2)*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(A*a*(m + S(1)) - C*a*m + C*b*(S(2)*m + S(1))*cos(e + f*x), x), x), x) - Simp(b*(A + C)*(a + b*cos(e + f*x))**m*sin(e + f*x)/(a*f*(S(2)*m + S(1))), x) def replacement2947(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(A*a - B*b + C*a) - (A*b**S(2) - B*a*b + C*a**S(2) + b*(m + S(1))*(A*b - B*a + C*b))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*cos(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2948(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(b*(m + S(1))*(A*a - B*b + C*a) - (A*b**S(2) - B*a*b + C*a**S(2) + b*(m + S(1))*(A*b - B*a + C*b))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*sin(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2949(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(a*b*(A + C)*(m + S(1)) - (A*b**S(2) + C*a**S(2) + b**S(2)*(A + C)*(m + S(1)))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*cos(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2950(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(a*b*(A + C)*(m + S(1)) - (A*b**S(2) + C*a**S(2) + b**S(2)*(A + C)*(m + S(1)))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*sin(e + f*x)/(b*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2951(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*sin(e + f*x))**m*Simp(A*b*(m + S(2)) + C*b*(m + S(1)) + (B*b*(m + S(2)) - C*a)*sin(e + f*x), x), x), x) - Simp(C*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(2))), x) def replacement2952(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*cos(e + f*x))**m*Simp(A*b*(m + S(2)) + C*b*(m + S(1)) + (B*b*(m + S(2)) - C*a)*cos(e + f*x), x), x), x) + Simp(C*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(2))), x) def replacement2953(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*sin(e + f*x))**m*Simp(A*b*(m + S(2)) - C*a*sin(e + f*x) + C*b*(m + S(1)), x), x), x) - Simp(C*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*(m + S(2))), x) def replacement2954(A, C, a, b, e, f, m, x): return Dist(S(1)/(b*(m + S(2))), Int((a + b*cos(e + f*x))**m*Simp(A*b*(m + S(2)) - C*a*cos(e + f*x) + C*b*(m + S(1)), x), x), x) + Simp(C*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*(m + S(2))), x) def replacement2955(A, B, C, b, e, f, m, p, x): return Dist((b*sin(e + f*x))**(-m*p)*(b*sin(e + f*x)**p)**m, Int((b*sin(e + f*x))**(m*p)*(A + B*sin(e + f*x) + C*sin(e + f*x)**S(2)), x), x) def replacement2956(A, B, C, b, e, f, m, p, x): return Dist((b*cos(e + f*x))**(-m*p)*(b*cos(e + f*x)**p)**m, Int((b*cos(e + f*x))**(m*p)*(A + B*cos(e + f*x) + C*cos(e + f*x)**S(2)), x), x) def replacement2957(A, C, b, e, f, m, p, x): return Dist((b*sin(e + f*x))**(-m*p)*(b*sin(e + f*x)**p)**m, Int((b*sin(e + f*x))**(m*p)*(A + C*sin(e + f*x)**S(2)), x), x) def replacement2958(A, C, b, e, f, m, p, x): return Dist((b*cos(e + f*x))**(-m*p)*(b*cos(e + f*x)**p)**m, Int((b*cos(e + f*x))**(m*p)*(A + C*cos(e + f*x)**S(2)), x), x) def replacement2959(A, B, C, a, b, c, d, e, f, m, x): return -Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(-C*b*d*(a**S(2) - b**S(2))*(m + S(1))*sin(e + f*x)**S(2) + b*(m + S(1))*(-A*b*(a*c - b*d) + (B*b - C*a)*(-a*d + b*c)) + (B*b*(a**S(2)*d - a*b*c*(m + S(2)) + b**S(2)*d*(m + S(1))) + (-a*d + b*c)*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1)))))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(-a*d + b*c)*(A*b**S(2) - B*a*b + C*a**S(2))*cos(e + f*x)/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2960(A, B, C, a, b, c, d, e, f, m, x): return -Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(-C*b*d*(a**S(2) - b**S(2))*(m + S(1))*cos(e + f*x)**S(2) + b*(m + S(1))*(-A*b*(a*c - b*d) + (B*b - C*a)*(-a*d + b*c)) + (B*b*(a**S(2)*d - a*b*c*(m + S(2)) + b**S(2)*d*(m + S(1))) + (-a*d + b*c)*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1)))))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(-a*d + b*c)*(A*b**S(2) - B*a*b + C*a**S(2))*sin(e + f*x)/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2961(A, C, a, b, c, d, e, f, m, x): return Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*Simp(C*b*d*(a**S(2) - b**S(2))*(m + S(1))*sin(e + f*x)**S(2) + b*(m + S(1))*(A*b*(a*c - b*d) + C*a*(-a*d + b*c)) - (-a*d + b*c)*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1))))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*(-a*d + b*c)*cos(e + f*x)/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2962(A, C, a, b, c, d, e, f, m, x): return Dist(S(1)/(b**S(2)*(a**S(2) - b**S(2))*(m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*Simp(C*b*d*(a**S(2) - b**S(2))*(m + S(1))*cos(e + f*x)**S(2) + b*(m + S(1))*(A*b*(a*c - b*d) + C*a*(-a*d + b*c)) - (-a*d + b*c)*(A*b**S(2)*(m + S(2)) + C*(a**S(2) + b**S(2)*(m + S(1))))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))*(-a*d + b*c)*sin(e + f*x)/(b**S(2)*f*(a**S(2) - b**S(2))*(m + S(1))), x) def replacement2963(A, B, C, a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b*sin(e + f*x))**m*Simp(A*b*c*(m + S(3)) + C*a*d + b*(B*c*(m + S(3)) + d*(A*(m + S(3)) + C*(m + S(2))))*sin(e + f*x) - (S(2)*C*a*d - b*(m + S(3))*(B*d + C*c))*sin(e + f*x)**S(2), x), x), x) - Simp(C*d*(a + b*sin(e + f*x))**(m + S(1))*sin(e + f*x)*cos(e + f*x)/(b*f*(m + S(3))), x) def replacement2964(A, B, C, a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b*cos(e + f*x))**m*Simp(A*b*c*(m + S(3)) + C*a*d + b*(B*c*(m + S(3)) + d*(A*(m + S(3)) + C*(m + S(2))))*cos(e + f*x) - (S(2)*C*a*d - b*(m + S(3))*(B*d + C*c))*cos(e + f*x)**S(2), x), x), x) + Simp(C*d*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)*cos(e + f*x)/(b*f*(m + S(3))), x) def replacement2965(A, C, a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b*sin(e + f*x))**m*Simp(A*b*c*(m + S(3)) + C*a*d + b*d*(A*(m + S(3)) + C*(m + S(2)))*sin(e + f*x) - (S(2)*C*a*d - C*b*c*(m + S(3)))*sin(e + f*x)**S(2), x), x), x) - Simp(C*d*(a + b*sin(e + f*x))**(m + S(1))*sin(e + f*x)*cos(e + f*x)/(b*f*(m + S(3))), x) def replacement2966(A, C, a, b, c, d, e, f, m, x): return Dist(S(1)/(b*(m + S(3))), Int((a + b*cos(e + f*x))**m*Simp(A*b*c*(m + S(3)) + C*a*d + b*d*(A*(m + S(3)) + C*(m + S(2)))*cos(e + f*x) - (S(2)*C*a*d - C*b*c*(m + S(3)))*cos(e + f*x)**S(2), x), x), x) + Simp(C*d*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)*cos(e + f*x)/(b*f*(m + S(3))), x) def replacement2967(A, B, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(S(2)*b*c*d*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(A*(c**S(2)*(m + S(1)) + d**S(2)*(S(2)*m + n + S(2))) - B*c*d*(m - n + S(-1)) - C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(-C*c*(S(3)*m - n) + (A*c + B*d)*(m + n + S(2)))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*a - B*b + C*a)*cos(e + f*x)/(S(2)*b*c*f*(S(2)*m + S(1))), x) def replacement2968(A, B, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(S(2)*b*c*d*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(A*(c**S(2)*(m + S(1)) + d**S(2)*(S(2)*m + n + S(2))) - B*c*d*(m - n + S(-1)) - C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(-C*c*(S(3)*m - n) + (A*c + B*d)*(m + n + S(2)))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*a - B*b + C*a)*sin(e + f*x)/(S(2)*b*c*f*(S(2)*m + S(1))), x) def replacement2969(A, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(S(2)*b*c*d*(S(2)*m + S(1))), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(A*(c**S(2)*(m + S(1)) + d**S(2)*(S(2)*m + n + S(2))) - C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(A*c*(m + n + S(2)) - C*c*(S(3)*m - n))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*a + C*a)*cos(e + f*x)/(S(2)*b*c*f*(S(2)*m + S(1))), x) def replacement2970(A, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(S(2)*b*c*d*(S(2)*m + S(1))), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(A*(c**S(2)*(m + S(1)) + d**S(2)*(S(2)*m + n + S(2))) - C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(A*c*(m + n + S(2)) - C*c*(S(3)*m - n))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*a + C*a)*sin(e + f*x)/(S(2)*b*c*f*(S(2)*m + S(1))), x) def replacement2971(A, B, C, a, b, c, d, e, f, m, x): return Int((a + b*sin(e + f*x))**m*Simp(A + B*sin(e + f*x) + C, x)/sqrt(c + d*sin(e + f*x)), x) + Simp(-S(2)*C*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*sqrt(c + d*sin(e + f*x))*(S(2)*m + S(3))), x) def replacement2972(A, B, C, a, b, c, d, e, f, m, x): return Int((a + b*cos(e + f*x))**m*Simp(A + B*cos(e + f*x) + C, x)/sqrt(c + d*cos(e + f*x)), x) + Simp(S(2)*C*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*sqrt(c + d*cos(e + f*x))*(S(2)*m + S(3))), x) def replacement2973(A, C, a, b, c, d, e, f, m, x): return Dist(A + C, Int((a + b*sin(e + f*x))**m/sqrt(c + d*sin(e + f*x)), x), x) + Simp(-S(2)*C*(a + b*sin(e + f*x))**(m + S(1))*cos(e + f*x)/(b*f*sqrt(c + d*sin(e + f*x))*(S(2)*m + S(3))), x) def replacement2974(A, C, a, b, c, d, e, f, m, x): return Dist(A + C, Int((a + b*cos(e + f*x))**m/sqrt(c + d*cos(e + f*x)), x), x) + Simp(S(2)*C*(a + b*cos(e + f*x))**(m + S(1))*sin(e + f*x)/(b*f*sqrt(c + d*cos(e + f*x))*(S(2)*m + S(3))), x) def replacement2975(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) + C*(a*c*m + b*d*(n + S(1))) + (B*b*d*(m + n + S(2)) - C*b*c*(S(2)*m + S(1)))*sin(e + f*x), x), x), x) - Simp(C*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2976(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) + C*(a*c*m + b*d*(n + S(1))) + (B*b*d*(m + n + S(2)) - C*b*c*(S(2)*m + S(1)))*cos(e + f*x), x), x), x) + Simp(C*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2977(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) - C*b*c*(S(2)*m + S(1))*sin(e + f*x) + C*(a*c*m + b*d*(n + S(1))), x), x), x) - Simp(C*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2978(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) - C*b*c*(S(2)*m + S(1))*cos(e + f*x) + C*(a*c*m + b*d*(n + S(1))), x), x), x) + Simp(C*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2979(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(A*(a*c*(m + S(1)) - b*d*(S(2)*m + n + S(2))) + B*(a*d*(n + S(1)) + b*c*m) - C*(a*c*m + b*d*(n + S(1))) + (C*(-a*d*(m - n + S(-1)) + b*c*(S(2)*m + S(1))) + d*(A*a - B*b)*(m + n + S(2)))*sin(e + f*x), x), x), x) + Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*a - B*b + C*a)*cos(e + f*x)/(f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2980(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(A*(a*c*(m + S(1)) - b*d*(S(2)*m + n + S(2))) + B*(a*d*(n + S(1)) + b*c*m) - C*(a*c*m + b*d*(n + S(1))) + (C*(-a*d*(m - n + S(-1)) + b*c*(S(2)*m + S(1))) + d*(A*a - B*b)*(m + n + S(2)))*cos(e + f*x), x), x), x) - Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*a - B*b + C*a)*sin(e + f*x)/(f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2981(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(A*(a*c*(m + S(1)) - b*d*(S(2)*m + n + S(2))) - C*(a*c*m + b*d*(n + S(1))) + (A*a*d*(m + n + S(2)) + C*(-a*d*(m - n + S(-1)) + b*c*(S(2)*m + S(1))))*sin(e + f*x), x), x), x) + Simp(a*(A + C)*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2982(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(S(2)*m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(A*(a*c*(m + S(1)) - b*d*(S(2)*m + n + S(2))) - C*(a*c*m + b*d*(n + S(1))) + (A*a*d*(m + n + S(2)) + C*(-a*d*(m - n + S(-1)) + b*c*(S(2)*m + S(1))))*cos(e + f*x), x), x), x) - Simp(a*(A + C)*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(f*(S(2)*m + S(1))*(-a*d + b*c)), x) def replacement2983(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*Simp(A*d*(a*d*m + b*c*(n + S(1))) + b*(-C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(2)))*sin(e + f*x) + (-B*d + C*c)*(a*c*m + b*d*(n + S(1))), x), x), x) - Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*d**S(2) - B*c*d + C*c**S(2))*cos(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2984(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*Simp(A*d*(a*d*m + b*c*(n + S(1))) + b*(-C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(2)))*cos(e + f*x) + (-B*d + C*c)*(a*c*m + b*d*(n + S(1))), x), x), x) + Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*d**S(2) - B*c*d + C*c**S(2))*sin(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2985(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*Simp(A*d*(a*d*m + b*c*(n + S(1))) + C*c*(a*c*m + b*d*(n + S(1))) - b*(A*d**S(2)*(m + n + S(2)) + C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))*cos(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2986(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*Simp(A*d*(a*d*m + b*c*(n + S(1))) + C*c*(a*c*m + b*d*(n + S(1))) - b*(A*d**S(2)*(m + n + S(2)) + C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))*sin(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2987(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) + C*(a*c*m + b*d*(n + S(1))) + (B*b*d*(m + n + S(2)) + C*(a*d*m - b*c*(m + S(1))))*sin(e + f*x), x), x), x) - Simp(C*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2988(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) + C*(a*c*m + b*d*(n + S(1))) + (B*b*d*(m + n + S(2)) + C*(a*d*m - b*c*(m + S(1))))*cos(e + f*x), x), x), x) + Simp(C*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2989(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) + C*(a*c*m + b*d*(n + S(1))) + C*(a*d*m - b*c*(m + S(1)))*sin(e + f*x), x), x), x) - Simp(C*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2990(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(2))), Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*Simp(A*b*d*(m + n + S(2)) + C*(a*c*m + b*d*(n + S(1))) + C*(a*d*m - b*c*(m + S(1)))*cos(e + f*x), x), x), x) + Simp(C*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2991(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1))*Simp(A*d*(a*c*(n + S(1)) + b*d*m) + b*(-C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(2)))*sin(e + f*x)**S(2) + (-B*d + C*c)*(a*d*(n + S(1)) + b*c*m) - (-C*(-a*(c**S(2) + d**S(2)*(n + S(1))) + b*c*d*(n + S(1))) + d*(A*(a*d*(n + S(2)) - b*c*(n + S(1))) + B*(-a*c*(n + S(2)) + b*d*(n + S(1)))))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*d**S(2) - B*c*d + C*c**S(2))*cos(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2992(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1))*Simp(A*d*(a*c*(n + S(1)) + b*d*m) + b*(-C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(2)))*cos(e + f*x)**S(2) + (-B*d + C*c)*(a*d*(n + S(1)) + b*c*m) - (-C*(-a*(c**S(2) + d**S(2)*(n + S(1))) + b*c*d*(n + S(1))) + d*(A*(a*d*(n + S(2)) - b*c*(n + S(1))) + B*(-a*c*(n + S(2)) + b*d*(n + S(1)))))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*d**S(2) - B*c*d + C*c**S(2))*sin(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2993(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**(n + S(1))*Simp(A*d*(a*c*(n + S(1)) + b*d*m) + C*c*(a*d*(n + S(1)) + b*c*m) - b*(A*d**S(2)*(m + n + S(2)) + C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))))*sin(e + f*x)**S(2) - (A*d*(a*d*(n + S(2)) - b*c*(n + S(1))) - C*(-a*(c**S(2) + d**S(2)*(n + S(1))) + b*c*d*(n + S(1))))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))*cos(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2994(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(c**S(2) - d**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**(n + S(1))*Simp(A*d*(a*c*(n + S(1)) + b*d*m) + C*c*(a*d*(n + S(1)) + b*c*m) - b*(A*d**S(2)*(m + n + S(2)) + C*(c**S(2)*(m + S(1)) + d**S(2)*(n + S(1))))*cos(e + f*x)**S(2) - (A*d*(a*d*(n + S(2)) - b*c*(n + S(1))) - C*(-a*(c**S(2) + d**S(2)*(n + S(1))) + b*c*d*(n + S(1))))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))*sin(e + f*x)/(d*f*(c**S(2) - d**S(2))*(n + S(1))), x) def replacement2995(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(2))), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n*Simp(A*a*d*(m + n + S(2)) + C*(a*d*(n + S(1)) + b*c*m) + (-C*(a*c - b*d*(m + n + S(1))) + d*(A*b + B*a)*(m + n + S(2)))*sin(e + f*x) + (B*b*d*(m + n + S(2)) + C*(a*d*m - b*c*(m + S(1))))*sin(e + f*x)**S(2), x), x), x) - Simp(C*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2996(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(2))), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n*Simp(A*a*d*(m + n + S(2)) + C*(a*d*(n + S(1)) + b*c*m) + (-C*(a*c - b*d*(m + n + S(1))) + d*(A*b + B*a)*(m + n + S(2)))*cos(e + f*x) + (B*b*d*(m + n + S(2)) + C*(a*d*m - b*c*(m + S(1))))*cos(e + f*x)**S(2), x), x), x) + Simp(C*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2997(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(2))), Int((a + b*sin(e + f*x))**(m + S(-1))*(c + d*sin(e + f*x))**n*Simp(A*a*d*(m + n + S(2)) + C*(a*d*m - b*c*(m + S(1)))*sin(e + f*x)**S(2) + C*(a*d*(n + S(1)) + b*c*m) + (A*b*d*(m + n + S(2)) - C*(a*c - b*d*(m + n + S(1))))*sin(e + f*x), x), x), x) - Simp(C*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**(n + S(1))*cos(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2998(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(2))), Int((a + b*cos(e + f*x))**(m + S(-1))*(c + d*cos(e + f*x))**n*Simp(A*a*d*(m + n + S(2)) + C*(a*d*m - b*c*(m + S(1)))*cos(e + f*x)**S(2) + C*(a*d*(n + S(1)) + b*c*m) + (A*b*d*(m + n + S(2)) - C*(a*c - b*d*(m + n + S(1))))*cos(e + f*x), x), x), x) + Simp(C*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**(n + S(1))*sin(e + f*x)/(d*f*(m + n + S(2))), x) def replacement2999(A, B, C, a, b, d, e, f, x): return Dist(S(1)/b, Int((A*b + (B*b - C*a)*sin(e + f*x))/(sqrt(d*sin(e + f*x))*(a + b*sin(e + f*x))**(S(3)/2)), x), x) + Dist(C/(b*d), Int(sqrt(d*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) def replacement3000(A, B, C, a, b, d, e, f, x): return Dist(S(1)/b, Int((A*b + (B*b - C*a)*cos(e + f*x))/(sqrt(d*cos(e + f*x))*(a + b*cos(e + f*x))**(S(3)/2)), x), x) + Dist(C/(b*d), Int(sqrt(d*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) def replacement3001(A, C, a, b, d, e, f, x): return Dist(S(1)/b, Int((A*b - C*a*sin(e + f*x))/(sqrt(d*sin(e + f*x))*(a + b*sin(e + f*x))**(S(3)/2)), x), x) + Dist(C/(b*d), Int(sqrt(d*sin(e + f*x))/sqrt(a + b*sin(e + f*x)), x), x) def replacement3002(A, C, a, b, d, e, f, x): return Dist(S(1)/b, Int((A*b - C*a*cos(e + f*x))/(sqrt(d*cos(e + f*x))*(a + b*cos(e + f*x))**(S(3)/2)), x), x) + Dist(C/(b*d), Int(sqrt(d*cos(e + f*x))/sqrt(a + b*cos(e + f*x)), x), x) def replacement3003(A, B, C, a, b, c, d, e, f, x): return Dist(b**(S(-2)), Int((A*b**S(2) - C*a**S(2) + b*(B*b - S(2)*C*a)*sin(e + f*x))/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) + Dist(C/b**S(2), Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) def replacement3004(A, B, C, a, b, c, d, e, f, x): return Dist(b**(S(-2)), Int((A*b**S(2) - C*a**S(2) + b*(B*b - S(2)*C*a)*cos(e + f*x))/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) + Dist(C/b**S(2), Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) def replacement3005(A, C, a, b, c, d, e, f, x): return Dist(b**(S(-2)), Int((A*b**S(2) - C*a**S(2) - S(2)*C*a*b*sin(e + f*x))/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) + Dist(C/b**S(2), Int(sqrt(a + b*sin(e + f*x))/sqrt(c + d*sin(e + f*x)), x), x) def replacement3006(A, C, a, b, c, d, e, f, x): return Dist(b**(S(-2)), Int((A*b**S(2) - C*a**S(2) - S(2)*C*a*b*cos(e + f*x))/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) + Dist(C/b**S(2), Int(sqrt(a + b*cos(e + f*x))/sqrt(c + d*cos(e + f*x)), x), x) def replacement3007(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(d*(m + n + S(2))*(A*b**S(2) - B*a*b + C*a**S(2)) - d*(m + n + S(3))*(A*b**S(2) - B*a*b + C*a**S(2))*sin(e + f*x)**S(2) + (m + S(1))*(-a*d + b*c)*(A*a - B*b + C*a) - (c*(A*b**S(2) - B*a*b + C*a**S(2)) + (m + S(1))*(-a*d + b*c)*(A*b - B*a + C*b))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3008(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(d*(m + n + S(2))*(A*b**S(2) - B*a*b + C*a**S(2)) - d*(m + n + S(3))*(A*b**S(2) - B*a*b + C*a**S(2))*cos(e + f*x)**S(2) + (m + S(1))*(-a*d + b*c)*(A*a - B*b + C*a) - (c*(A*b**S(2) - B*a*b + C*a**S(2)) + (m + S(1))*(-a*d + b*c)*(A*b - B*a + C*b))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3009(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**n*Simp(a*(A + C)*(m + S(1))*(-a*d + b*c) + d*(A*b**S(2) + C*a**S(2))*(m + n + S(2)) - d*(A*b**S(2) + C*a**S(2))*(m + n + S(3))*sin(e + f*x)**S(2) - (b*(A + C)*(m + S(1))*(-a*d + b*c) + c*(A*b**S(2) + C*a**S(2)))*sin(e + f*x), x), x), x) - Simp((a + b*sin(e + f*x))**(m + S(1))*(c + d*sin(e + f*x))**(n + S(1))*(A*b**S(2) + C*a**S(2))*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3010(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**n*Simp(a*(A + C)*(m + S(1))*(-a*d + b*c) + d*(A*b**S(2) + C*a**S(2))*(m + n + S(2)) - d*(A*b**S(2) + C*a**S(2))*(m + n + S(3))*cos(e + f*x)**S(2) - (b*(A + C)*(m + S(1))*(-a*d + b*c) + c*(A*b**S(2) + C*a**S(2)))*cos(e + f*x), x), x), x) + Simp((a + b*cos(e + f*x))**(m + S(1))*(c + d*cos(e + f*x))**(n + S(1))*(A*b**S(2) + C*a**S(2))*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3011(A, B, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/(b*(-a*d + b*c)), Int(S(1)/(a + b*sin(e + f*x)), x), x) - Dist((A*d**S(2) - B*c*d + C*c**S(2))/(d*(-a*d + b*c)), Int(S(1)/(c + d*sin(e + f*x)), x), x) + Simp(C*x/(b*d), x) def replacement3012(A, B, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/(b*(-a*d + b*c)), Int(S(1)/(a + b*cos(e + f*x)), x), x) - Dist((A*d**S(2) - B*c*d + C*c**S(2))/(d*(-a*d + b*c)), Int(S(1)/(c + d*cos(e + f*x)), x), x) + Simp(C*x/(b*d), x) def replacement3013(A, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) + C*a**S(2))/(b*(-a*d + b*c)), Int(S(1)/(a + b*sin(e + f*x)), x), x) - Dist((A*d**S(2) + C*c**S(2))/(d*(-a*d + b*c)), Int(S(1)/(c + d*sin(e + f*x)), x), x) + Simp(C*x/(b*d), x) def replacement3014(A, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) + C*a**S(2))/(b*(-a*d + b*c)), Int(S(1)/(a + b*cos(e + f*x)), x), x) - Dist((A*d**S(2) + C*c**S(2))/(d*(-a*d + b*c)), Int(S(1)/(c + d*cos(e + f*x)), x), x) + Simp(C*x/(b*d), x) def replacement3015(A, B, C, a, b, c, d, e, f, x): return -Dist(S(1)/(b*d), Int(Simp(-A*b*d + C*a*c + (-B*b*d + C*a*d + C*b*c)*sin(e + f*x), x)/(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) + Dist(C/(b*d), Int(sqrt(a + b*sin(e + f*x)), x), x) def replacement3016(A, B, C, a, b, c, d, e, f, x): return -Dist(S(1)/(b*d), Int(Simp(-A*b*d + C*a*c + (-B*b*d + C*a*d + C*b*c)*cos(e + f*x), x)/(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) + Dist(C/(b*d), Int(sqrt(a + b*cos(e + f*x)), x), x) def replacement3017(A, C, a, b, c, d, e, f, x): return -Dist(S(1)/(b*d), Int(Simp(-A*b*d + C*a*c + (C*a*d + C*b*c)*sin(e + f*x), x)/(sqrt(a + b*sin(e + f*x))*(c + d*sin(e + f*x))), x), x) + Dist(C/(b*d), Int(sqrt(a + b*sin(e + f*x)), x), x) def replacement3018(A, C, a, b, c, d, e, f, x): return -Dist(S(1)/(b*d), Int(Simp(-A*b*d + C*a*c + (C*a*d + C*b*c)*cos(e + f*x), x)/(sqrt(a + b*cos(e + f*x))*(c + d*cos(e + f*x))), x), x) + Dist(C/(b*d), Int(sqrt(a + b*cos(e + f*x)), x), x) def replacement3019(A, B, C, a, b, c, d, e, f, x): return Dist(S(1)/(S(2)*d), Int(Simp(S(2)*A*a*d - C*(-a*d + b*c) + (S(2)*B*b*d - C*(a*d + b*c))*sin(e + f*x)**S(2) - S(2)*(C*a*c - d*(A*b + B*a))*sin(e + f*x), x)/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) - Simp(C*sqrt(c + d*sin(e + f*x))*cos(e + f*x)/(d*f*sqrt(a + b*sin(e + f*x))), x) def replacement3020(A, B, C, a, b, c, d, e, f, x): return Dist(S(1)/(S(2)*d), Int(Simp(S(2)*A*a*d - C*(-a*d + b*c) + (S(2)*B*b*d - C*(a*d + b*c))*cos(e + f*x)**S(2) - S(2)*(C*a*c - d*(A*b + B*a))*cos(e + f*x), x)/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) + Simp(C*sqrt(c + d*cos(e + f*x))*sin(e + f*x)/(d*f*sqrt(a + b*cos(e + f*x))), x) def replacement3021(A, C, a, b, c, d, e, f, x): return Dist(S(1)/(S(2)*d), Int(Simp(S(2)*A*a*d - C*(-a*d + b*c) - C*(a*d + b*c)*sin(e + f*x)**S(2) - S(2)*(-A*b*d + C*a*c)*sin(e + f*x), x)/((a + b*sin(e + f*x))**(S(3)/2)*sqrt(c + d*sin(e + f*x))), x), x) - Simp(C*sqrt(c + d*sin(e + f*x))*cos(e + f*x)/(d*f*sqrt(a + b*sin(e + f*x))), x) def replacement3022(A, C, a, b, c, d, e, f, x): return Dist(S(1)/(S(2)*d), Int(Simp(S(2)*A*a*d - C*(-a*d + b*c) - C*(a*d + b*c)*cos(e + f*x)**S(2) - S(2)*(-A*b*d + C*a*c)*cos(e + f*x), x)/((a + b*cos(e + f*x))**(S(3)/2)*sqrt(c + d*cos(e + f*x))), x), x) + Simp(C*sqrt(c + d*cos(e + f*x))*sin(e + f*x)/(d*f*sqrt(a + b*cos(e + f*x))), x) def replacement3023(A, B, C, a, b, c, d, e, f, m, n, x): return Int((a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n*(A + B*sin(e + f*x) + C*sin(e + f*x)**S(2)), x) def replacement3024(A, B, C, a, b, c, d, e, f, m, n, x): return Int((a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n*(A + B*cos(e + f*x) + C*cos(e + f*x)**S(2)), x) def replacement3025(A, C, a, b, c, d, e, f, m, n, x): return Int((A + C*sin(e + f*x)**S(2))*(a + b*sin(e + f*x))**m*(c + d*sin(e + f*x))**n, x) def replacement3026(A, C, a, b, c, d, e, f, m, n, x): return Int((A + C*cos(e + f*x)**S(2))*(a + b*cos(e + f*x))**m*(c + d*cos(e + f*x))**n, x) def replacement3027(A, B, C, b, c, d, e, f, m, n, p, x): return Dist((b*sin(e + f*x))**(-m*p)*(b*sin(e + f*x)**p)**m, Int((b*sin(e + f*x))**(m*p)*(c + d*sin(e + f*x))**n*(A + B*sin(e + f*x) + C*sin(e + f*x)**S(2)), x), x) def replacement3028(A, B, C, b, c, d, e, f, m, n, p, x): return Dist((b*cos(e + f*x))**(-m*p)*(b*cos(e + f*x)**p)**m, Int((b*cos(e + f*x))**(m*p)*(c + d*cos(e + f*x))**n*(A + B*cos(e + f*x) + C*cos(e + f*x)**S(2)), x), x) def replacement3029(A, C, b, c, d, e, f, m, n, p, x): return Dist((b*sin(e + f*x))**(-m*p)*(b*sin(e + f*x)**p)**m, Int((b*sin(e + f*x))**(m*p)*(A + C*sin(e + f*x)**S(2))*(c + d*sin(e + f*x))**n, x), x) def replacement3030(A, C, b, c, d, e, f, m, n, p, x): return Dist((b*cos(e + f*x))**(-m*p)*(b*cos(e + f*x)**p)**m, Int((b*cos(e + f*x))**(m*p)*(A + C*cos(e + f*x)**S(2))*(c + d*cos(e + f*x))**n, x), x) def replacement3031(a, b, c, d, n, x): return Simp(a*(a*cos(c + d*x) + b*sin(c + d*x))**n/(b*d*n), x) def replacement3032(a, b, c, d, n, x): return -Dist(S(1)/d, Subst(Int((a**S(2) + b**S(2) - x**S(2))**(n/S(2) + S(-1)/2), x), x, -a*sin(c + d*x) + b*cos(c + d*x)), x) def replacement3033(a, b, c, d, n, x): return Dist((a**S(2) + b**S(2))*(n + S(-1))/n, Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-2)), x), x) - Simp((-a*sin(c + d*x) + b*cos(c + d*x))*(a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-1))/(d*n), x) def replacement3034(a, b, c, d, x): return -Dist(S(1)/d, Subst(Int(S(1)/(a**S(2) + b**S(2) - x**S(2)), x), x, -a*sin(c + d*x) + b*cos(c + d*x)), x) def replacement3035(a, b, c, d, x): return Simp(sin(c + d*x)/(a*d*(a*cos(c + d*x) + b*sin(c + d*x))), x) def replacement3036(a, b, c, d, n, x): return Dist((n + S(2))/((a**S(2) + b**S(2))*(n + S(1))), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(2)), x), x) + Simp((-a*sin(c + d*x) + b*cos(c + d*x))*(a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1))/(d*(a**S(2) + b**S(2))*(n + S(1))), x) def replacement3037(a, b, c, d, n, x): return Dist((a**S(2) + b**S(2))**(n/S(2)), Int(cos(c + d*x - ArcTan(a, b))**n, x), x) def replacement3038(a, b, c, d, n, x): return Dist(((a*cos(c + d*x) + b*sin(c + d*x))/sqrt(a**S(2) + b**S(2)))**(-n)*(a*cos(c + d*x) + b*sin(c + d*x))**n, Int(cos(c + d*x - ArcTan(a, b))**n, x), x) def replacement3039(a, b, c, d, m, n, x): return Dist(S(2)*b, Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-1))*sin(c + d*x)**(S(1) - n), x), x) - Simp(a*(a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-1))*sin(c + d*x)**(S(1) - n)/(d*(n + S(-1))), x) def replacement3040(a, b, c, d, m, n, x): return Dist(S(2)*a, Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-1))*cos(c + d*x)**(S(1) - n), x), x) + Simp(b*(a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-1))*cos(c + d*x)**(S(1) - n)/(d*(n + S(-1))), x) def replacement3041(a, b, c, d, m, n, x): return Dist(S(1)/(S(2)*b), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1))*sin(c + d*x)**(-n + S(-1)), x), x) + Simp(a*(a*cos(c + d*x) + b*sin(c + d*x))**n*sin(c + d*x)**(-n)/(S(2)*b*d*n), x) def replacement3042(a, b, c, d, m, n, x): return Dist(S(1)/(S(2)*a), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1))*cos(c + d*x)**(-n + S(-1)), x), x) - Simp(b*(a*cos(c + d*x) + b*sin(c + d*x))**n*cos(c + d*x)**(-n)/(S(2)*a*d*n), x) def replacement3043(a, b, c, d, m, n, x): return Simp(a*(a*cos(c + d*x) + b*sin(c + d*x))**n*Hypergeometric2F1(S(1), n, n + S(1), (a/tan(c + d*x) + b)/(S(2)*b))*sin(c + d*x)**(-n)/(S(2)*b*d*n), x) def replacement3044(a, b, c, d, m, n, x): return -Simp(b*(a*cos(c + d*x) + b*sin(c + d*x))**n*Hypergeometric2F1(S(1), n, n + S(1), (a + b*tan(c + d*x))/(S(2)*a))*cos(c + d*x)**(-n)/(S(2)*a*d*n), x) def replacement3045(a, b, c, d, m, n, x): return Int((a/tan(c + d*x) + b)**n, x) def replacement3046(a, b, c, d, m, n, x): return Int((a + b*tan(c + d*x))**n, x) def replacement3047(a, b, c, d, m, n, x): return Dist(S(1)/d, Subst(Int(x**m*(a + b*x)**n*(x**S(2) + S(1))**(-m/S(2) - n/S(2) + S(-1)), x), x, tan(c + d*x)), x) def replacement3048(a, b, c, d, m, n, x): return -Dist(S(1)/d, Subst(Int(x**m*(x**S(2) + S(1))**(-m/S(2) - n/S(2) + S(-1))*(a*x + b)**n, x), x, S(1)/tan(c + d*x)), x) def replacement3049(a, b, c, d, m, n, x): return Int(ExpandTrig((a*cos(c + d*x) + b*sin(c + d*x))**n*sin(c + d*x)**m, x), x) def replacement3050(a, b, c, d, m, n, x): return Int(ExpandTrig((a*cos(c + d*x) + b*sin(c + d*x))**n*cos(c + d*x)**m, x), x) def replacement3051(a, b, c, d, m, n, x): return Dist(a**n*b**n, Int((a*sin(c + d*x) + b*cos(c + d*x))**(-n)*sin(c + d*x)**m, x), x) def replacement3052(a, b, c, d, m, n, x): return Dist(a**n*b**n, Int((a*sin(c + d*x) + b*cos(c + d*x))**(-n)*cos(c + d*x)**m, x), x) def replacement3053(a, b, c, d, n, x): return Dist(a**(S(-2)), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(2))/sin(c + d*x), x), x) - Dist(b/a**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1)), x), x) - Simp((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1))/(a*d*(n + S(1))), x) def replacement3054(a, b, c, d, n, x): return Dist(b**(S(-2)), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(2))/cos(c + d*x), x), x) - Dist(a/b**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1)), x), x) + Simp((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1))/(b*d*(n + S(1))), x) def replacement3055(a, b, c, d, m, n, x): return Dist(a**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-2))*sin(c + d*x)**m, x), x) + Dist(S(2)*b, Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-1))*sin(c + d*x)**(m + S(1)), x), x) - Dist(a**S(2) + b**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-2))*sin(c + d*x)**(m + S(2)), x), x) def replacement3056(a, b, c, d, m, n, x): return Dist(S(2)*a, Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-1))*cos(c + d*x)**(m + S(1)), x), x) + Dist(b**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-2))*cos(c + d*x)**m, x), x) - Dist(a**S(2) + b**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(-2))*cos(c + d*x)**(m + S(2)), x), x) def replacement3057(a, b, c, d, x): return -Dist(a/(a**S(2) + b**S(2)), Int((-a*sin(c + d*x) + b*cos(c + d*x))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) + Simp(b*x/(a**S(2) + b**S(2)), x) def replacement3058(a, b, c, d, x): return Dist(b/(a**S(2) + b**S(2)), Int((-a*sin(c + d*x) + b*cos(c + d*x))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) + Simp(a*x/(a**S(2) + b**S(2)), x) def replacement3059(a, b, c, d, m, x): return Dist(a**S(2)/(a**S(2) + b**S(2)), Int(sin(c + d*x)**(m + S(-2))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) + Dist(b/(a**S(2) + b**S(2)), Int(sin(c + d*x)**(m + S(-1)), x), x) - Simp(a*sin(c + d*x)**(m + S(-1))/(d*(a**S(2) + b**S(2))*(m + S(-1))), x) def replacement3060(a, b, c, d, m, x): return Dist(a/(a**S(2) + b**S(2)), Int(cos(c + d*x)**(m + S(-1)), x), x) + Dist(b**S(2)/(a**S(2) + b**S(2)), Int(cos(c + d*x)**(m + S(-2))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) + Simp(b*cos(c + d*x)**(m + S(-1))/(d*(a**S(2) + b**S(2))*(m + S(-1))), x) def replacement3061(a, b, c, d, x): return -Dist(S(1)/a, Int((-a*sin(c + d*x) + b*cos(c + d*x))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) + Dist(S(1)/a, Int(S(1)/tan(c + d*x), x), x) def replacement3062(a, b, c, d, x): return Dist(S(1)/b, Int((-a*sin(c + d*x) + b*cos(c + d*x))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) + Dist(S(1)/b, Int(tan(c + d*x), x), x) def replacement3063(a, b, c, d, m, x): return -Dist(b/a**S(2), Int(sin(c + d*x)**(m + S(1)), x), x) + Dist((a**S(2) + b**S(2))/a**S(2), Int(sin(c + d*x)**(m + S(2))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) + Simp(sin(c + d*x)**(m + S(1))/(a*d*(m + S(1))), x) def replacement3064(a, b, c, d, m, x): return -Dist(a/b**S(2), Int(cos(c + d*x)**(m + S(1)), x), x) + Dist((a**S(2) + b**S(2))/b**S(2), Int(cos(c + d*x)**(m + S(2))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) - Simp(cos(c + d*x)**(m + S(1))/(b*d*(m + S(1))), x) def replacement3065(a, b, c, d, m, n, x): return Dist(a**(S(-2)), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(2))*sin(c + d*x)**m, x), x) - Dist(S(2)*b/a**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1))*sin(c + d*x)**(m + S(1)), x), x) + Dist((a**S(2) + b**S(2))/a**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**n*sin(c + d*x)**(m + S(2)), x), x) def replacement3066(a, b, c, d, m, n, x): return Dist(b**(S(-2)), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(2))*cos(c + d*x)**m, x), x) - Dist(S(2)*a/b**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**(n + S(1))*cos(c + d*x)**(m + S(1)), x), x) + Dist((a**S(2) + b**S(2))/b**S(2), Int((a*cos(c + d*x) + b*sin(c + d*x))**n*cos(c + d*x)**(m + S(2)), x), x) def replacement3067(a, b, c, d, m, n, p, x): return Int(ExpandTrig((a*cos(c + d*x) + b*sin(c + d*x))**p*sin(c + d*x)**n*cos(c + d*x)**m, x), x) def replacement3068(a, b, c, d, m, n, p, x): return Dist(a**p*b**p, Int((a*sin(c + d*x) + b*cos(c + d*x))**(-p)*sin(c + d*x)**n*cos(c + d*x)**m, x), x) def replacement3069(a, b, c, d, m, n, x): return Dist(a/(a**S(2) + b**S(2)), Int(sin(c + d*x)**n*cos(c + d*x)**(m + S(-1)), x), x) + Dist(b/(a**S(2) + b**S(2)), Int(sin(c + d*x)**(n + S(-1))*cos(c + d*x)**m, x), x) - Dist(a*b/(a**S(2) + b**S(2)), Int(sin(c + d*x)**(n + S(-1))*cos(c + d*x)**(m + S(-1))/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) def replacement3070(a, b, c, d, m, n, x): return Int(ExpandTrig(sin(c + d*x)**n*cos(c + d*x)**m/(a*cos(c + d*x) + b*sin(c + d*x)), x), x) def replacement3071(a, b, c, d, m, n, p, x): return Dist(a/(a**S(2) + b**S(2)), Int((a*cos(c + d*x) + b*sin(c + d*x))**(p + S(1))*sin(c + d*x)**n*cos(c + d*x)**(m + S(-1)), x), x) + Dist(b/(a**S(2) + b**S(2)), Int((a*cos(c + d*x) + b*sin(c + d*x))**(p + S(1))*sin(c + d*x)**(n + S(-1))*cos(c + d*x)**m, x), x) - Dist(a*b/(a**S(2) + b**S(2)), Int((a*cos(c + d*x) + b*sin(c + d*x))**p*sin(c + d*x)**(n + S(-1))*cos(c + d*x)**(m + S(-1)), x), x) def replacement3072(a, b, c, d, e, x): return Simp(-S(2)*(-b*sin(d + e*x) + c*cos(d + e*x))/(e*sqrt(a + b*cos(d + e*x) + c*sin(d + e*x))), x) def replacement3073(a, b, c, d, e, n, x): return Dist(a*(S(2)*n + S(-1))/n, Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(-1)), x), x) - Simp((-b*sin(d + e*x) + c*cos(d + e*x))*(a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(-1))/(e*n), x) def replacement3074(a, b, c, d, e, x): return -Simp((-a*sin(d + e*x) + c)/(c*e*(-b*sin(d + e*x) + c*cos(d + e*x))), x) def replacement3075(a, b, c, d, e, x): return Int(S(1)/sqrt(a + sqrt(b**S(2) + c**S(2))*cos(d + e*x - ArcTan(b, c))), x) def replacement3076(a, b, c, d, e, n, x): return Dist((n + S(1))/(a*(S(2)*n + S(1))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1)), x), x) + Simp((-b*sin(d + e*x) + c*cos(d + e*x))*(a + b*cos(d + e*x) + c*sin(d + e*x))**n/(a*e*(S(2)*n + S(1))), x) def replacement3077(a, b, c, d, e, x): return Dist(b/(c*e), Subst(Int(sqrt(a + x)/x, x), x, b*cos(d + e*x) + c*sin(d + e*x)), x) def replacement3078(a, b, c, d, e, x): return Int(sqrt(a + sqrt(b**S(2) + c**S(2))*cos(d + e*x - ArcTan(b, c))), x) def replacement3079(a, b, c, d, e, x): return Dist(sqrt(a + b*cos(d + e*x) + c*sin(d + e*x))/sqrt((a + b*cos(d + e*x) + c*sin(d + e*x))/(a + sqrt(b**S(2) + c**S(2)))), Int(sqrt(a/(a + sqrt(b**S(2) + c**S(2))) + sqrt(b**S(2) + c**S(2))*cos(d + e*x - ArcTan(b, c))/(a + sqrt(b**S(2) + c**S(2)))), x), x) def replacement3080(a, b, c, d, e, n, x): return Dist(S(1)/n, Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(-2))*Simp(a**S(2)*n + a*b*(S(2)*n + S(-1))*cos(d + e*x) + a*c*(S(2)*n + S(-1))*sin(d + e*x) + (b**S(2) + c**S(2))*(n + S(-1)), x), x), x) - Simp((-b*sin(d + e*x) + c*cos(d + e*x))*(a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(-1))/(e*n), x) def With3081(a, b, c, d, e, x): f = FreeFactors(S(1)/tan(d/S(2) + e*x/S(2)), x) return -Dist(f/e, Subst(Int(S(1)/(a + c*f*x), x), x, S(1)/(f*tan(d/S(2) + e*x/S(2)))), x) def With3082(a, b, c, d, e, x): f = FreeFactors(tan(Pi/S(4) + d/S(2) + e*x/S(2)), x) return Dist(f/e, Subst(Int(S(1)/(a + b*f*x), x), x, tan(Pi/S(4) + d/S(2) + e*x/S(2))/f), x) def With3083(a, b, c, d, e, x): f = FreeFactors(S(1)/tan(Pi/S(4) + d/S(2) + e*x/S(2)), x) return -Dist(f/e, Subst(Int(S(1)/(a + b*f*x), x), x, S(1)/(f*tan(Pi/S(4) + d/S(2) + e*x/S(2)))), x) def With3084(a, b, c, d, e, x): f = FreeFactors(tan(d/S(2) + e*x/S(2)), x) return Dist(S(2)*f/e, Subst(Int(S(1)/(a + b + S(2)*c*f*x + f**S(2)*x**S(2)*(a - b)), x), x, tan(d/S(2) + e*x/S(2))/f), x) def replacement3085(a, b, c, d, e, x): return Dist(b/(c*e), Subst(Int(S(1)/(x*sqrt(a + x)), x), x, b*cos(d + e*x) + c*sin(d + e*x)), x) def replacement3086(a, b, c, d, e, x): return Int(S(1)/sqrt(a + sqrt(b**S(2) + c**S(2))*cos(d + e*x - ArcTan(b, c))), x) def replacement3087(a, b, c, d, e, x): return Dist(sqrt((a + b*cos(d + e*x) + c*sin(d + e*x))/(a + sqrt(b**S(2) + c**S(2))))/sqrt(a + b*cos(d + e*x) + c*sin(d + e*x)), Int(S(1)/sqrt(a/(a + sqrt(b**S(2) + c**S(2))) + sqrt(b**S(2) + c**S(2))*cos(d + e*x - ArcTan(b, c))/(a + sqrt(b**S(2) + c**S(2)))), x), x) def replacement3088(a, b, c, d, e, x): return Dist(S(1)/(a**S(2) - b**S(2) - c**S(2)), Int(sqrt(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) + Simp(S(2)*(-b*sin(d + e*x) + c*cos(d + e*x))/(e*sqrt(a + b*cos(d + e*x) + c*sin(d + e*x))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3089(a, b, c, d, e, n, x): return Dist(S(1)/((n + S(1))*(a**S(2) - b**S(2) - c**S(2))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))*(a*(n + S(1)) - b*(n + S(2))*cos(d + e*x) - c*(n + S(2))*sin(d + e*x)), x), x) + Simp((b*sin(d + e*x) - c*cos(d + e*x))*(a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))/(e*(n + S(1))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3090(A, B, C, a, b, c, d, e, x): return Simp(x*(S(2)*A*a - B*b - C*c)/(S(2)*a**S(2)), x) + Simp((-S(2)*A*a*b**S(2) + a**S(2)*(B*b - C*c) + b**S(2)*(B*b + C*c))*log(RemoveContent(a + b*cos(d + e*x) + c*sin(d + e*x), x))/(S(2)*a**S(2)*b*c*e), x) - Simp((B*b + C*c)*(b*cos(d + e*x) - c*sin(d + e*x))/(S(2)*a*b*c*e), x) def replacement3091(A, C, a, b, c, d, e, x): return Simp(x*(S(2)*A*a - C*c)/(S(2)*a**S(2)), x) - Simp(C*cos(d + e*x)/(S(2)*a*e), x) + Simp((S(2)*A*a*c - C*a**S(2) + C*b**S(2))*log(RemoveContent(a + b*cos(d + e*x) + c*sin(d + e*x), x))/(S(2)*a**S(2)*b*e), x) + Simp(C*c*sin(d + e*x)/(S(2)*a*b*e), x) def replacement3092(A, B, a, b, c, d, e, x): return Simp(x*(S(2)*A*a - B*b)/(S(2)*a**S(2)), x) + Simp(B*sin(d + e*x)/(S(2)*a*e), x) + Simp((-S(2)*A*a*b + B*a**S(2) + B*b**S(2))*log(RemoveContent(a + b*cos(d + e*x) + c*sin(d + e*x), x))/(S(2)*a**S(2)*c*e), x) - Simp(B*b*cos(d + e*x)/(S(2)*a*c*e), x) def replacement3093(A, B, C, a, b, c, d, e, x): return Simp(x*(B*b + C*c)/(b**S(2) + c**S(2)), x) + Simp((B*c - C*b)*log(a + b*cos(d + e*x) + c*sin(d + e*x))/(e*(b**S(2) + c**S(2))), x) def replacement3094(A, C, a, b, c, d, e, x): return Simp(C*c*x/(b**S(2) + c**S(2)), x) - Simp(C*b*log(a + b*cos(d + e*x) + c*sin(d + e*x))/(e*(b**S(2) + c**S(2))), x) def replacement3095(A, B, a, b, c, d, e, x): return Simp(B*b*x/(b**S(2) + c**S(2)), x) + Simp(B*c*log(a + b*cos(d + e*x) + c*sin(d + e*x))/(e*(b**S(2) + c**S(2))), x) def replacement3096(A, B, C, a, b, c, d, e, x): return Dist((A*(b**S(2) + c**S(2)) - a*(B*b + C*c))/(b**S(2) + c**S(2)), Int(S(1)/(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) + Simp(x*(B*b + C*c)/(b**S(2) + c**S(2)), x) + Simp((B*c - C*b)*log(a + b*cos(d + e*x) + c*sin(d + e*x))/(e*(b**S(2) + c**S(2))), x) def replacement3097(A, C, a, b, c, d, e, x): return Dist((A*(b**S(2) + c**S(2)) - C*a*c)/(b**S(2) + c**S(2)), Int(S(1)/(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) - Simp(C*b*log(a + b*cos(d + e*x) + c*sin(d + e*x))/(e*(b**S(2) + c**S(2))), x) + Simp(C*c*(d + e*x)/(e*(b**S(2) + c**S(2))), x) def replacement3098(A, B, a, b, c, d, e, x): return Dist((A*(b**S(2) + c**S(2)) - B*a*b)/(b**S(2) + c**S(2)), Int(S(1)/(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) + Simp(B*b*(d + e*x)/(e*(b**S(2) + c**S(2))), x) + Simp(B*c*log(a + b*cos(d + e*x) + c*sin(d + e*x))/(e*(b**S(2) + c**S(2))), x) def replacement3099(A, B, C, a, b, c, d, e, n, x): return Simp((a + b*cos(d + e*x) + c*sin(d + e*x))**n*(B*a*sin(d + e*x) + B*c - C*a*cos(d + e*x) - C*b)/(a*e*(n + S(1))), x) def replacement3100(A, C, a, b, c, d, e, n, x): return -Simp((C*a*cos(d + e*x) + C*b)*(a + b*cos(d + e*x) + c*sin(d + e*x))**n/(a*e*(n + S(1))), x) def replacement3101(A, B, a, b, c, d, e, n, x): return Simp((B*a*sin(d + e*x) + B*c)*(a + b*cos(d + e*x) + c*sin(d + e*x))**n/(a*e*(n + S(1))), x) def replacement3102(A, B, C, a, b, c, d, e, n, x): return Dist((A*a*(n + S(1)) + n*(B*b + C*c))/(a*(n + S(1))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**n, x), x) + Simp((a + b*cos(d + e*x) + c*sin(d + e*x))**n*(B*a*sin(d + e*x) + B*c - C*a*cos(d + e*x) - C*b)/(a*e*(n + S(1))), x) def replacement3103(A, C, a, b, c, d, e, n, x): return Dist((A*a*(n + S(1)) + C*c*n)/(a*(n + S(1))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**n, x), x) - Simp((C*a*cos(d + e*x) + C*b)*(a + b*cos(d + e*x) + c*sin(d + e*x))**n/(a*e*(n + S(1))), x) def replacement3104(A, B, a, b, c, d, e, n, x): return Dist((A*a*(n + S(1)) + B*b*n)/(a*(n + S(1))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**n, x), x) + Simp((B*a*sin(d + e*x) + B*c)*(a + b*cos(d + e*x) + c*sin(d + e*x))**n/(a*e*(n + S(1))), x) def replacement3105(B, C, b, c, d, e, n, x): return Simp((B*c - C*b)*(b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))/(e*(b**S(2) + c**S(2))*(n + S(1))), x) def replacement3106(A, B, C, a, b, c, d, e, n, x): return Dist(S(1)/(a*(n + S(1))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(-1))*Simp(A*a**S(2)*(n + S(1)) + a*n*(B*b + C*c) + (A*a*b*(n + S(1)) + n*(B*a**S(2) - B*c**S(2) + C*b*c))*cos(d + e*x) + (A*a*c*(n + S(1)) + n*(B*b*c + C*a**S(2) - C*b**S(2)))*sin(d + e*x), x), x), x) + Simp((a + b*cos(d + e*x) + c*sin(d + e*x))**n*(B*a*sin(d + e*x) + B*c - C*a*cos(d + e*x) - C*b)/(a*e*(n + S(1))), x) def replacement3107(A, C, a, b, c, d, e, n, x): return Dist(S(1)/(a*(n + S(1))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(-1))*Simp(A*a**S(2)*(n + S(1)) + C*a*c*n + (A*a*b*(n + S(1)) + C*b*c*n)*cos(d + e*x) + (A*a*c*(n + S(1)) + C*a**S(2)*n - C*b**S(2)*n)*sin(d + e*x), x), x), x) - Simp((C*a*cos(d + e*x) + C*b)*(a + b*cos(d + e*x) + c*sin(d + e*x))**n/(a*e*(n + S(1))), x) def replacement3108(A, B, a, b, c, d, e, n, x): return Dist(S(1)/(a*(n + S(1))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(-1))*Simp(A*a**S(2)*(n + S(1)) + B*a*b*n + (A*a*c*(n + S(1)) + B*b*c*n)*sin(d + e*x) + (A*a*b*(n + S(1)) + B*a**S(2)*n - B*c**S(2)*n)*cos(d + e*x), x), x), x) + Simp((B*a*sin(d + e*x) + B*c)*(a + b*cos(d + e*x) + c*sin(d + e*x))**n/(a*e*(n + S(1))), x) def replacement3109(A, B, C, a, b, c, d, e, x): return Dist(B/b, Int(sqrt(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) + Dist((A*b - B*a)/b, Int(S(1)/sqrt(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) def replacement3110(A, B, C, a, b, c, d, e, x): return Simp((B*c - C*b + (-A*b + B*a)*sin(d + e*x) - (-A*c + C*a)*cos(d + e*x))/(e*(a + b*cos(d + e*x) + c*sin(d + e*x))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3111(A, C, a, b, c, d, e, x): return -Simp((A*b*sin(d + e*x) + C*b + (-A*c + C*a)*cos(d + e*x))/(e*(a + b*cos(d + e*x) + c*sin(d + e*x))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3112(A, B, a, b, c, d, e, x): return Simp((A*c*cos(d + e*x) + B*c + (-A*b + B*a)*sin(d + e*x))/(e*(a + b*cos(d + e*x) + c*sin(d + e*x))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3113(A, B, C, a, b, c, d, e, x): return Dist((A*a - B*b - C*c)/(a**S(2) - b**S(2) - c**S(2)), Int(S(1)/(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) + Simp((B*c - C*b + (-A*b + B*a)*sin(d + e*x) - (-A*c + C*a)*cos(d + e*x))/(e*(a + b*cos(d + e*x) + c*sin(d + e*x))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3114(A, C, a, b, c, d, e, x): return Dist((A*a - C*c)/(a**S(2) - b**S(2) - c**S(2)), Int(S(1)/(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) - Simp((A*b*sin(d + e*x) + C*b + (-A*c + C*a)*cos(d + e*x))/(e*(a + b*cos(d + e*x) + c*sin(d + e*x))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3115(A, B, a, b, c, d, e, x): return Dist((A*a - B*b)/(a**S(2) - b**S(2) - c**S(2)), Int(S(1)/(a + b*cos(d + e*x) + c*sin(d + e*x)), x), x) + Simp((A*c*cos(d + e*x) + B*c + (-A*b + B*a)*sin(d + e*x))/(e*(a + b*cos(d + e*x) + c*sin(d + e*x))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3116(A, B, C, a, b, c, d, e, n, x): return Dist(S(1)/((n + S(1))*(a**S(2) - b**S(2) - c**S(2))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))*Simp((n + S(1))*(A*a - B*b - C*c) + (n + S(2))*(-A*b + B*a)*cos(d + e*x) + (n + S(2))*(-A*c + C*a)*sin(d + e*x), x), x), x) - Simp((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))*(B*c - C*b + (-A*b + B*a)*sin(d + e*x) - (-A*c + C*a)*cos(d + e*x))/(e*(n + S(1))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3117(A, C, a, b, c, d, e, n, x): return Dist(S(1)/((n + S(1))*(a**S(2) - b**S(2) - c**S(2))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))*Simp(-A*b*(n + S(2))*cos(d + e*x) + (n + S(1))*(A*a - C*c) + (n + S(2))*(-A*c + C*a)*sin(d + e*x), x), x), x) + Simp((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))*(A*b*sin(d + e*x) + C*b + (-A*c + C*a)*cos(d + e*x))/(e*(n + S(1))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3118(A, B, a, b, c, d, e, n, x): return Dist(S(1)/((n + S(1))*(a**S(2) - b**S(2) - c**S(2))), Int((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))*Simp(-A*c*(n + S(2))*sin(d + e*x) + (n + S(1))*(A*a - B*b) + (n + S(2))*(-A*b + B*a)*cos(d + e*x), x), x), x) - Simp((a + b*cos(d + e*x) + c*sin(d + e*x))**(n + S(1))*(A*c*cos(d + e*x) + B*c + (-A*b + B*a)*sin(d + e*x))/(e*(n + S(1))*(a**S(2) - b**S(2) - c**S(2))), x) def replacement3119(a, b, c, d, e, x): return Int(cos(d + e*x)/(a*cos(d + e*x) + b + c*sin(d + e*x)), x) def replacement3120(a, b, c, d, e, x): return Int(sin(d + e*x)/(a*sin(d + e*x) + b + c*cos(d + e*x)), x) def replacement3121(a, b, c, d, e, n, x): return Int((a*cos(d + e*x) + b + c*sin(d + e*x))**n, x) def replacement3122(a, b, c, d, e, n, x): return Int((a*sin(d + e*x) + b + c*cos(d + e*x))**n, x) def replacement3123(a, b, c, d, e, n, x): return Dist((a + b/cos(d + e*x) + c*tan(d + e*x))**n*(a*cos(d + e*x) + b + c*sin(d + e*x))**(-n)*cos(d + e*x)**n, Int((a*cos(d + e*x) + b + c*sin(d + e*x))**n, x), x) def replacement3124(a, b, c, d, e, n, x): return Dist((a + b/sin(d + e*x) + c/tan(d + e*x))**n*(a*sin(d + e*x) + b + c*cos(d + e*x))**(-n)*sin(d + e*x)**n, Int((a*sin(d + e*x) + b + c*cos(d + e*x))**n, x), x) def replacement3125(a, b, c, d, e, m, n, x): return Int((a*cos(d + e*x) + b + c*sin(d + e*x))**(-n), x) def replacement3126(a, b, c, d, e, m, n, x): return Int((a*sin(d + e*x) + b + c*cos(d + e*x))**(-n), x) def replacement3127(a, b, c, d, e, m, n, x): return Dist((a + b/cos(d + e*x) + c*tan(d + e*x))**(-n)*(a*cos(d + e*x) + b + c*sin(d + e*x))**n*(S(1)/cos(d + e*x))**n, Int((a*cos(d + e*x) + b + c*sin(d + e*x))**(-n), x), x) def replacement3128(a, b, c, d, e, m, n, x): return Dist((a + b/sin(d + e*x) + c/tan(d + e*x))**(-n)*(a*sin(d + e*x) + b + c*cos(d + e*x))**n*(S(1)/sin(d + e*x))**n, Int((a*sin(d + e*x) + b + c*cos(d + e*x))**(-n), x), x) def replacement3129(b, c, d, p, x): return Dist(b*(S(2)*p + S(-1))/(S(2)*p), Int((b*sin(c + d*x)**S(2))**(p + S(-1)), x), x) - Simp((b*sin(c + d*x)**S(2))**p/(S(2)*d*p*tan(c + d*x)), x) def replacement3130(b, c, d, p, x): return Dist(b*(S(2)*p + S(-1))/(S(2)*p), Int((b*cos(c + d*x)**S(2))**(p + S(-1)), x), x) + Simp((b*cos(c + d*x)**S(2))**p*tan(c + d*x)/(S(2)*d*p), x) def replacement3131(b, c, d, p, x): return Dist(S(2)*(p + S(1))/(b*(S(2)*p + S(1))), Int((b*sin(c + d*x)**S(2))**(p + S(1)), x), x) + Simp((b*sin(c + d*x)**S(2))**(p + S(1))/(b*d*(S(2)*p + S(1))*tan(c + d*x)), x) def replacement3132(b, c, d, p, x): return Dist(S(2)*(p + S(1))/(b*(S(2)*p + S(1))), Int((b*cos(c + d*x)**S(2))**(p + S(1)), x), x) - Simp((b*cos(c + d*x)**S(2))**(p + S(1))*tan(c + d*x)/(b*d*(S(2)*p + S(1))), x) def replacement3133(a, b, c, d, p, x): return Dist(a**p, Int(cos(c + d*x)**(S(2)*p), x), x) def replacement3134(a, b, c, d, p, x): return Dist(a**p, Int(sin(c + d*x)**(S(2)*p), x), x) def replacement3135(a, b, c, d, p, x): return Int((a*cos(c + d*x)**S(2))**p, x) def replacement3136(a, b, c, d, p, x): return Int((a*sin(c + d*x)**S(2))**p, x) def With3137(a, b, c, d, p, x): e = FreeFactors(tan(c + d*x), x) return Dist(e/d, Subst(Int((a + e**S(2)*x**S(2)*(a + b))**p*(e**S(2)*x**S(2) + S(1))**(-p + S(-1)), x), x, tan(c + d*x)/e), x) def With3138(a, b, c, d, p, x): e = FreeFactors(tan(c + d*x), x) return Dist(e/d, Subst(Int((e**S(2)*x**S(2) + S(1))**(-p + S(-1))*(a*e**S(2)*x**S(2) + a + b)**p, x), x, tan(c + d*x)/e), x) def replacement3139(a, b, c, d, p, x): return Dist(S(2)**(-p), Int((S(2)*a - b*cos(S(2)*c + S(2)*d*x) + b)**p, x), x) def replacement3140(a, b, c, d, p, x): return Dist(S(2)**(-p), Int((S(2)*a + b*cos(S(2)*c + S(2)*d*x) + b)**p, x), x) def replacement3141(a, b, c, d, n, p, x): return Int((a + b*sin(c + d*x)**n)**p, x) def replacement3142(a, b, c, d, n, p, x): return Int((a + b*cos(c + d*x)**n)**p, x) def With3143(a, b, c, d, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(-n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b, x)**p, x), x, S(1)/(f*tan(c + d*x))), x) def With3144(a, b, c, d, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(-n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b, x)**p, x), x, tan(c + d*x)/f), x) def replacement3145(a, b, c, d, p, u, x): return Dist(a**p, Int(ActivateTrig(u)*cos(c + d*x)**(S(2)*p), x), x) def replacement3146(a, b, c, d, p, u, x): return Dist(a**p, Int(ActivateTrig(u)*sin(c + d*x)**(S(2)*p), x), x) def replacement3147(a, b, c, d, p, u, x): return Dist((a*cos(c + d*x)**S(2))**p*cos(c + d*x)**(-S(2)*p), Int(ActivateTrig(u)*cos(c + d*x)**(S(2)*p), x), x) def replacement3148(a, b, c, d, p, u, x): return Dist((a*sin(c + d*x)**S(2))**p*sin(c + d*x)**(-S(2)*p), Int(ActivateTrig(u)*sin(c + d*x)**(S(2)*p), x), x) def With3149(a, b, c, d, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b, x)**p, x), x, S(1)/(f*tan(c + d*x))), x) def With3150(a, b, c, d, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b, x)**p, x), x, tan(c + d*x)/f), x) def With3151(a, b, c, d, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f/d, Subst(Int((-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*ExpandToSum(a + b*(-f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, cos(c + d*x)/f), x) def With3152(a, b, c, d, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f/d, Subst(Int((-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*ExpandToSum(a + b*(-f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, sin(c + d*x)/f), x) def replacement3153(a, b, c, d, m, n, p, x): return Int(ExpandTrig((a + b*sin(c + d*x)**n)**p*sin(c + d*x)**m, x), x) def replacement3154(a, b, c, d, m, n, p, x): return Int(ExpandTrig((a + b*cos(c + d*x)**n)**p*cos(c + d*x)**m, x), x) def With3155(a, b, c, d, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*f**n*x**n, x)**p, x), x, tan(c + d*x)/f), x) def With3156(a, b, c, d, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f/d, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*f**n*x**n, x)**p, x), x, S(1)/(f*tan(c + d*x))), x) def replacement3157(a, b, c, d, m, n, p, x): return Int((S(1) - sin(c + d*x)**S(2))**(m/S(2))*(a + b*sin(c + d*x)**n)**p, x) def replacement3158(a, b, c, d, m, n, p, x): return Int((S(1) - cos(c + d*x)**S(2))**(m/S(2))*(a + b*cos(c + d*x)**n)**p, x) def replacement3159(a, b, c, d, m, n, p, x): return Int(ExpandTrig((S(1) - sin(c + d*x)**S(2))**(m/S(2))*(a + b*sin(c + d*x)**n)**p, x), x) def replacement3160(a, b, c, d, m, n, p, x): return Int(ExpandTrig((S(1) - cos(c + d*x)**S(2))**(m/S(2))*(a + b*cos(c + d*x)**n)**p, x), x) def With3161(a, b, c, d, e, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f/d, Subst(Int((a + b*(e*f*x)**n)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, sin(c + d*x)/f), x) def With3162(a, b, c, d, e, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f/d, Subst(Int((a + b*(e*f*x)**n)**p*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2), x), x, cos(c + d*x)/f), x) def With3163(a, b, c, d, e, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f**(m + S(1))/d, Subst(Int(x**m*(a + b*(e*f*x)**n)**p*(-f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1)/2), x), x, sin(c + d*x)/f), x) def With3164(a, b, c, d, e, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f**(m + S(1))/d, Subst(Int(x**m*(a + b*(e*f*x)**n)**p*(-f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1)/2), x), x, cos(c + d*x)/f), x) def With3165(a, b, c, d, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f**(m + S(1))/d, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*f**n*x**n, x)**p, x), x, tan(c + d*x)/f), x) def With3166(a, b, c, d, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f**(m + S(1))/d, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*f**n*x**n, x)**p, x), x, S(1)/(f*tan(c + d*x))), x) def With3167(a, b, c, d, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f**(m + S(1))/d, Subst(Int(x**m*((f**S(2)*x**S(2) + S(1))**(-n/S(2))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*f**n*x**n, x))**p/(f**S(2)*x**S(2) + S(1)), x), x, tan(c + d*x)/f), x) def With3168(a, b, c, d, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f**(m + S(1))/d, Subst(Int(x**m*((f**S(2)*x**S(2) + S(1))**(-n/S(2))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*f**n*x**n, x))**p/(f**S(2)*x**S(2) + S(1)), x), x, S(1)/(f*tan(c + d*x))), x) def With3169(a, b, c, d, e, m, n, p, q, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f/e, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*q/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(q/S(2)) + b*(f**S(2)*x**S(2) + S(1))**(-p/S(2) + q/S(2)) + c, x)**n, x), x, S(1)/(f*tan(d + e*x))), x) def With3170(a, b, c, d, e, m, n, p, q, x): f = FreeFactors(tan(d + e*x), x) return Dist(f/e, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*q/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(q/S(2)) + b*(f**S(2)*x**S(2) + S(1))**(-p/S(2) + q/S(2)) + c, x)**n, x), x, tan(d + e*x)/f), x) def With3171(a, b, c, d, e, m, n, p, q, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f/e, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(p/S(2)) + b*f**p*x**p + c*(f**S(2)*x**S(2) + S(1))**(p/S(2) - q/S(2)), x)**n, x), x, S(1)/(f*tan(d + e*x))), x) def With3172(a, b, c, d, e, m, n, p, q, x): f = FreeFactors(tan(d + e*x), x) return Dist(f/e, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**(p/S(2)) + b*f**p*x**p + c*(f**S(2)*x**S(2) + S(1))**(p/S(2) - q/S(2)), x)**n, x), x, tan(d + e*x)/f), x) def replacement3173(a, b, c, d, e, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p), x), x) def replacement3174(a, b, c, d, e, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p), x), x) def replacement3175(a, b, c, d, e, n, n2, p, x): return Dist((b + S(2)*c*sin(d + e*x)**n)**(-S(2)*p)*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p, Int(u*(b + S(2)*c*sin(d + e*x)**n)**(S(2)*p), x), x) def replacement3176(a, b, c, d, e, n, n2, p, x): return Dist((b + S(2)*c*cos(d + e*x)**n)**(-S(2)*p)*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p, Int(u*(b + S(2)*c*cos(d + e*x)**n)**(S(2)*p), x), x) def With3177(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*sin(d + e*x)**n - q), x), x) - Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*sin(d + e*x)**n + q), x), x) def With3178(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*cos(d + e*x)**n - q), x), x) - Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*cos(d + e*x)**n + q), x), x) def replacement3179(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*sin(d + e*x)**m, x), x) def replacement3180(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*cos(d + e*x)**m, x), x) def replacement3181(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*sin(d + e*x)**n)**(-S(2)*p)*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*sin(d + e*x)**m, x), x) def replacement3182(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*cos(d + e*x)**n)**(-S(2)*p)*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*cos(d + e*x)**m, x), x) def With3183(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f/e, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p + S(-1))*ExpandToSum(a*(x**S(2) + S(1))**n + b*(x**S(2) + S(1))**(n/S(2)) + c, x)**p, x), x, S(1)/(f*tan(d + e*x))), x) def With3184(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(tan(d + e*x), x) return Dist(f/e, Subst(Int((f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p + S(-1))*ExpandToSum(a*(x**S(2) + S(1))**n + b*(x**S(2) + S(1))**(n/S(2)) + c, x)**p, x), x, tan(d + e*x)/f), x) def replacement3185(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p*sin(d + e*x)**m, x), x) def replacement3186(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p*cos(d + e*x)**m, x), x) def With3187(a, b, c, d, e, f, m, n, n2, p, x): g = FreeFactors(sin(d + e*x), x) return Dist(g/e, Subst(Int((-g**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*(a + b*(f*g*x)**n + c*(f*g*x)**(S(2)*n))**p, x), x, sin(d + e*x)/g), x) def With3188(a, b, c, d, e, f, m, n, n2, p, x): g = FreeFactors(cos(d + e*x), x) return -Dist(g/e, Subst(Int((-g**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*(a + b*(f*g*x)**n + c*(f*g*x)**(S(2)*n))**p, x), x, cos(d + e*x)/g), x) def replacement3189(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*cos(d + e*x)**m, x), x) def replacement3190(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*sin(d + e*x)**m, x), x) def replacement3191(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*sin(d + e*x)**n)**(-S(2)*p)*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*cos(d + e*x)**m, x), x) def replacement3192(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*cos(d + e*x)**n)**(-S(2)*p)*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*sin(d + e*x)**m, x), x) def With3193(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p + S(-1))*ExpandToSum(a*(x**S(2) + S(1))**n + b*(x**S(2) + S(1))**(n/S(2)) + c, x)**p, x), x, S(1)/(f*tan(d + e*x))), x) def With3194(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(tan(d + e*x), x) return Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p + S(-1))*ExpandToSum(a*(x**S(2) + S(1))**n + b*(x**S(2) + S(1))**(n/S(2)) + c, x)**p, x), x, tan(d + e*x)/f), x) def replacement3195(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((S(1) - sin(d + e*x)**S(2))**(m/S(2))*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p, x), x) def replacement3196(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((S(1) - cos(d + e*x)**S(2))**(m/S(2))*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p, x), x) def With3197(a, b, c, d, e, f, m, n, n2, p, x): g = FreeFactors(sin(d + e*x), x) return Dist(g**(m + S(1))/e, Subst(Int(x**m*(-g**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1)/2)*(a + b*(f*g*x)**n + c*(f*g*x)**(S(2)*n))**p, x), x, sin(d + e*x)/g), x) def With3198(a, b, c, d, e, f, m, n, n2, p, x): g = FreeFactors(cos(d + e*x), x) return -Dist(g**(m + S(1))/e, Subst(Int(x**m*(-g**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1)/2)*(a + b*(f*g*x)**n + c*(f*g*x)**(S(2)*n))**p, x), x, cos(d + e*x)/g), x) def replacement3199(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def replacement3200(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def replacement3201(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*sin(d + e*x)**n)**(-S(2)*p)*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def replacement3202(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*cos(d + e*x)**n)**(-S(2)*p)*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def With3203(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(tan(d + e*x), x) return Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-n*p + S(-1))*ExpandToSum(a*(x**S(2) + S(1))**n + b*x**n*(x**S(2) + S(1))**(n/S(2)) + c*x**(S(2)*n), x)**p, x), x, tan(d + e*x)/f), x) def With3204(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-n*p + S(-1))*ExpandToSum(a*(x**S(2) + S(1))**n + b*x**n*(x**S(2) + S(1))**(n/S(2)) + c*x**(S(2)*n), x)**p, x), x, S(1)/(f*tan(d + e*x))), x) def replacement3205(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((S(1) - sin(d + e*x)**S(2))**(-m/S(2))*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p*sin(d + e*x)**m, x), x) def replacement3206(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((S(1) - cos(d + e*x)**S(2))**(-m/S(2))*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p*cos(d + e*x)**m, x), x) def With3207(a, b, c, d, e, f, m, n, n2, p, x): g = FreeFactors(sin(d + e*x), x) return Dist(g**(m + S(1))/e, Subst(Int(x**(-m)*(-g**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*(a + b*(f*g*x)**n + c*(f*g*x)**(S(2)*n))**p, x), x, sin(d + e*x)/g), x) def With3208(a, b, c, d, e, f, m, n, n2, p, x): g = FreeFactors(cos(d + e*x), x) return -Dist(g**(m + S(1))/e, Subst(Int(x**(-m)*(-g**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*(a + b*(f*g*x)**n + c*(f*g*x)**(S(2)*n))**p, x), x, cos(d + e*x)/g), x) def replacement3209(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def replacement3210(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def replacement3211(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*sin(d + e*x)**n)**(-S(2)*p)*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*sin(d + e*x)**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def replacement3212(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*cos(d + e*x)**n)**(-S(2)*p)*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*cos(d + e*x)**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def With3213(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(S(1)/tan(d + e*x), x) return -Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-n*p + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**n + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + c, x)**p, x), x, S(1)/(f*tan(d + e*x))), x) def With3214(a, b, c, d, e, m, n, n2, p, x): f = FreeFactors(tan(d + e*x), x) return Dist(f**(m + S(1))/e, Subst(Int(x**m*(f**S(2)*x**S(2) + S(1))**(-n*p + S(-1))*ExpandToSum(a*(f**S(2)*x**S(2) + S(1))**n + b*(f**S(2)*x**S(2) + S(1))**(n/S(2)) + c, x)**p, x), x, tan(d + e*x)/f), x) def replacement3215(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((S(1) - sin(d + e*x)**S(2))**(m/S(2))*(a + b*sin(d + e*x)**n + c*sin(d + e*x)**(S(2)*n))**p*sin(d + e*x)**(-m), x), x) def replacement3216(a, b, c, d, e, m, n, n2, p, x): return Int(ExpandTrig((S(1) - cos(d + e*x)**S(2))**(m/S(2))*(a + b*cos(d + e*x)**n + c*cos(d + e*x)**(S(2)*n))**p*cos(d + e*x)**(-m), x), x) def replacement3217(A, B, a, b, c, d, e, n, x): return Dist(S(4)**(-n)*c**(-n), Int((A + B*sin(d + e*x))*(b + S(2)*c*sin(d + e*x))**(S(2)*n), x), x) def replacement3218(A, B, a, b, c, d, e, n, x): return Dist(S(4)**(-n)*c**(-n), Int((A + B*cos(d + e*x))*(b + S(2)*c*cos(d + e*x))**(S(2)*n), x), x) def replacement3219(A, B, a, b, c, d, e, n, x): return Dist((b + S(2)*c*sin(d + e*x))**(-S(2)*n)*(a + b*sin(d + e*x) + c*sin(d + e*x)**S(2))**n, Int((A + B*sin(d + e*x))*(b + S(2)*c*sin(d + e*x))**(S(2)*n), x), x) def replacement3220(A, B, a, b, c, d, e, n, x): return Dist((b + S(2)*c*cos(d + e*x))**(-S(2)*n)*(a + b*cos(d + e*x) + c*cos(d + e*x)**S(2))**n, Int((A + B*cos(d + e*x))*(b + S(2)*c*cos(d + e*x))**(S(2)*n), x), x) def With3221(A, B, a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(B - (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c*sin(d + e*x) - q), x), x) + Dist(B + (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c*sin(d + e*x) + q), x), x) def With3222(A, B, a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(B - (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c*cos(d + e*x) - q), x), x) + Dist(B + (-S(2)*A*c + B*b)/q, Int(S(1)/(b + S(2)*c*cos(d + e*x) + q), x), x) def replacement3223(A, B, a, b, c, d, e, n, x): return Int(ExpandTrig((A + B*sin(d + e*x))*(a + b*sin(d + e*x) + c*sin(d + e*x)**S(2))**n, x), x) def replacement3224(A, B, a, b, c, d, e, n, x): return Int(ExpandTrig((A + B*cos(d + e*x))*(a + b*cos(d + e*x) + c*cos(d + e*x)**S(2))**n, x), x) def replacement3225(c, d, e, f, m, x): return Dist(d*m/f, Int((c + d*x)**(m + S(-1))*cos(e + f*x), x), x) - Simp((c + d*x)**m*cos(e + f*x)/f, x) def replacement3226(c, d, e, f, m, x): return -Dist(d*m/f, Int((c + d*x)**(m + S(-1))*sin(e + f*x), x), x) + Simp((c + d*x)**m*sin(e + f*x)/f, x) def replacement3227(c, d, e, f, m, x): return -Dist(f/(d*(m + S(1))), Int((c + d*x)**(m + S(1))*cos(e + f*x), x), x) + Simp((c + d*x)**(m + S(1))*sin(e + f*x)/(d*(m + S(1))), x) def replacement3228(c, d, e, f, m, x): return Dist(f/(d*(m + S(1))), Int((c + d*x)**(m + S(1))*sin(e + f*x), x), x) + Simp((c + d*x)**(m + S(1))*cos(e + f*x)/(d*(m + S(1))), x) def replacement3229(c, d, e, f, x): return Simp(SinIntegral(e + f*x)/d, x) def replacement3230(c, d, e, f, x): return Simp(CosIntegral(e + f*x)/d, x) def replacement3231(c, d, e, f, x): return Dist(sin((-c*f + d*e)/d), Int(cos(c*f/d + f*x)/(c + d*x), x), x) + Dist(cos((-c*f + d*e)/d), Int(sin(c*f/d + f*x)/(c + d*x), x), x) def replacement3232(c, d, e, f, x): return -Dist(sin((-c*f + d*e)/d), Int(sin(c*f/d + f*x)/(c + d*x), x), x) + Dist(cos((-c*f + d*e)/d), Int(cos(c*f/d + f*x)/(c + d*x), x), x) def replacement3233(c, d, e, f, x): return Dist(S(2)/d, Subst(Int(sin(f*x**S(2)/d), x), x, sqrt(c + d*x)), x) def replacement3234(c, d, e, f, x): return Dist(S(2)/d, Subst(Int(cos(f*x**S(2)/d), x), x, sqrt(c + d*x)), x) def replacement3235(c, d, e, f, x): return Dist(sin((-c*f + d*e)/d), Int(cos(c*f/d + f*x)/sqrt(c + d*x), x), x) + Dist(cos((-c*f + d*e)/d), Int(sin(c*f/d + f*x)/sqrt(c + d*x), x), x) def replacement3236(c, d, e, f, x): return -Dist(sin((-c*f + d*e)/d), Int(sin(c*f/d + f*x)/sqrt(c + d*x), x), x) + Dist(cos((-c*f + d*e)/d), Int(cos(c*f/d + f*x)/sqrt(c + d*x), x), x) def replacement3237(c, d, e, f, m, x): return Dist(I/S(2), Int((c + d*x)**m*exp(-I*(e + f*x)), x), x) - Dist(I/S(2), Int((c + d*x)**m*exp(I*(e + f*x)), x), x) def replacement3238(c, d, e, f, m, x): return Dist(S(1)/2, Int((c + d*x)**m*exp(-I*(e + f*x)), x), x) + Dist(S(1)/2, Int((c + d*x)**m*exp(I*(e + f*x)), x), x) def replacement3239(b, c, d, e, f, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*sin(e + f*x))**(n + S(-2))*(c + d*x), x), x) + Simp(d*(b*sin(e + f*x))**n/(f**S(2)*n**S(2)), x) - Simp(b*(b*sin(e + f*x))**(n + S(-1))*(c + d*x)*cos(e + f*x)/(f*n), x) def replacement3240(b, c, d, e, f, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*cos(e + f*x))**(n + S(-2))*(c + d*x), x), x) + Simp(d*(b*cos(e + f*x))**n/(f**S(2)*n**S(2)), x) + Simp(b*(b*cos(e + f*x))**(n + S(-1))*(c + d*x)*sin(e + f*x)/(f*n), x) def replacement3241(b, c, d, e, f, m, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*sin(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) - Dist(d**S(2)*m*(m + S(-1))/(f**S(2)*n**S(2)), Int((b*sin(e + f*x))**n*(c + d*x)**(m + S(-2)), x), x) - Simp(b*(b*sin(e + f*x))**(n + S(-1))*(c + d*x)**m*cos(e + f*x)/(f*n), x) + Simp(d*m*(b*sin(e + f*x))**n*(c + d*x)**(m + S(-1))/(f**S(2)*n**S(2)), x) def replacement3242(b, c, d, e, f, m, n, x): return Dist(b**S(2)*(n + S(-1))/n, Int((b*cos(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) - Dist(d**S(2)*m*(m + S(-1))/(f**S(2)*n**S(2)), Int((b*cos(e + f*x))**n*(c + d*x)**(m + S(-2)), x), x) + Simp(b*(b*cos(e + f*x))**(n + S(-1))*(c + d*x)**m*sin(e + f*x)/(f*n), x) + Simp(d*m*(b*cos(e + f*x))**n*(c + d*x)**(m + S(-1))/(f**S(2)*n**S(2)), x) def replacement3243(c, d, e, f, m, n, x): return Int(ExpandTrigReduce((c + d*x)**m, sin(e + f*x)**n, x), x) def replacement3244(c, d, e, f, m, n, x): return Int(ExpandTrigReduce((c + d*x)**m, cos(e + f*x)**n, x), x) def replacement3245(c, d, e, f, m, n, x): return -Dist(f*n/(d*(m + S(1))), Int(ExpandTrigReduce((c + d*x)**(m + S(1)), sin(e + f*x)**(n + S(-1))*cos(e + f*x), x), x), x) + Simp((c + d*x)**(m + S(1))*sin(e + f*x)**n/(d*(m + S(1))), x) def replacement3246(c, d, e, f, m, n, x): return Dist(f*n/(d*(m + S(1))), Int(ExpandTrigReduce((c + d*x)**(m + S(1)), sin(e + f*x)*cos(e + f*x)**(n + S(-1)), x), x), x) + Simp((c + d*x)**(m + S(1))*cos(e + f*x)**n/(d*(m + S(1))), x) def replacement3247(b, c, d, e, f, m, n, x): return -Dist(f**S(2)*n**S(2)/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*sin(e + f*x))**n*(c + d*x)**(m + S(2)), x), x) + Dist(b**S(2)*f**S(2)*n*(n + S(-1))/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*sin(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(2)), x), x) + Simp((b*sin(e + f*x))**n*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) - Simp(b*f*n*(b*sin(e + f*x))**(n + S(-1))*(c + d*x)**(m + S(2))*cos(e + f*x)/(d**S(2)*(m + S(1))*(m + S(2))), x) def replacement3248(b, c, d, e, f, m, n, x): return -Dist(f**S(2)*n**S(2)/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*cos(e + f*x))**n*(c + d*x)**(m + S(2)), x), x) + Dist(b**S(2)*f**S(2)*n*(n + S(-1))/(d**S(2)*(m + S(1))*(m + S(2))), Int((b*cos(e + f*x))**(n + S(-2))*(c + d*x)**(m + S(2)), x), x) + Simp((b*cos(e + f*x))**n*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) + Simp(b*f*n*(b*cos(e + f*x))**(n + S(-1))*(c + d*x)**(m + S(2))*sin(e + f*x)/(d**S(2)*(m + S(1))*(m + S(2))), x) def replacement3249(b, c, d, e, f, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*sin(e + f*x))**(n + S(2))*(c + d*x), x), x) - Simp(d*(b*sin(e + f*x))**(n + S(2))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) + Simp((b*sin(e + f*x))**(n + S(1))*(c + d*x)*cos(e + f*x)/(b*f*(n + S(1))), x) def replacement3250(b, c, d, e, f, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*cos(e + f*x))**(n + S(2))*(c + d*x), x), x) - Simp(d*(b*cos(e + f*x))**(n + S(2))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) - Simp((b*cos(e + f*x))**(n + S(1))*(c + d*x)*sin(e + f*x)/(b*f*(n + S(1))), x) def replacement3251(b, c, d, e, f, m, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*sin(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) + Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), Int((b*sin(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-2)), x), x) + Simp((b*sin(e + f*x))**(n + S(1))*(c + d*x)**m*cos(e + f*x)/(b*f*(n + S(1))), x) - Simp(d*m*(b*sin(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) def replacement3252(b, c, d, e, f, m, n, x): return Dist((n + S(2))/(b**S(2)*(n + S(1))), Int((b*cos(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) + Dist(d**S(2)*m*(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), Int((b*cos(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-2)), x), x) - Simp((b*cos(e + f*x))**(n + S(1))*(c + d*x)**m*sin(e + f*x)/(b*f*(n + S(1))), x) - Simp(d*m*(b*cos(e + f*x))**(n + S(2))*(c + d*x)**(m + S(-1))/(b**S(2)*f**S(2)*(n + S(1))*(n + S(2))), x) def replacement3253(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b*sin(e + f*x))**n, x), x) def replacement3254(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b*cos(e + f*x))**n, x), x) def replacement3255(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**n, Int((c + d*x)**m*cos(-Pi*a/(S(4)*b) + e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement3256(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**IntPart(n)*(a + b*sin(e + f*x))**FracPart(n)*cos(-Pi*a/(S(4)*b) + e/S(2) + f*x/S(2))**(-S(2)*FracPart(n)), Int((c + d*x)**m*cos(-Pi*a/(S(4)*b) + e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement3257(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**n, Int((c + d*x)**m*cos(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement3258(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**n, Int((c + d*x)**m*sin(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement3259(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**IntPart(n)*(a + b*cos(e + f*x))**FracPart(n)*cos(e/S(2) + f*x/S(2))**(-S(2)*FracPart(n)), Int((c + d*x)**m*cos(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement3260(a, b, c, d, e, f, m, n, x): return Dist((S(2)*a)**IntPart(n)*(a + b*cos(e + f*x))**FracPart(n)*sin(e/S(2) + f*x/S(2))**(-S(2)*FracPart(n)), Int((c + d*x)**m*sin(e/S(2) + f*x/S(2))**(S(2)*n), x), x) def replacement3261(a, b, c, d, e, f, m, x): return Dist(S(2), Int((c + d*x)**m*exp(I*(e + f*x))/(S(2)*a*exp(I*(e + f*x)) - I*b*exp(S(2)*I*(e + f*x)) + I*b), x), x) def replacement3262(a, b, c, d, e, f, m, x): return Dist(S(2), Int((c + d*x)**m*exp(I*(e + f*x))/(S(2)*a*exp(I*(e + f*x)) + b*exp(S(2)*I*(e + f*x)) + b), x), x) def replacement3263(a, b, c, d, e, f, m, x): return Dist(a/(a**S(2) - b**S(2)), Int((c + d*x)**m/(a + b*sin(e + f*x)), x), x) - Dist(b*d*m/(f*(a**S(2) - b**S(2))), Int((c + d*x)**(m + S(-1))*cos(e + f*x)/(a + b*sin(e + f*x)), x), x) + Simp(b*(c + d*x)**m*cos(e + f*x)/(f*(a + b*sin(e + f*x))*(a**S(2) - b**S(2))), x) def replacement3264(a, b, c, d, e, f, m, x): return Dist(a/(a**S(2) - b**S(2)), Int((c + d*x)**m/(a + b*cos(e + f*x)), x), x) + Dist(b*d*m/(f*(a**S(2) - b**S(2))), Int((c + d*x)**(m + S(-1))*sin(e + f*x)/(a + b*cos(e + f*x)), x), x) - Simp(b*(c + d*x)**m*sin(e + f*x)/(f*(a + b*cos(e + f*x))*(a**S(2) - b**S(2))), x) def replacement3265(a, b, c, d, e, f, m, n, x): return Dist(a/(a**S(2) - b**S(2)), Int((a + b*sin(e + f*x))**(n + S(1))*(c + d*x)**m, x), x) - Dist(b*(n + S(2))/((a**S(2) - b**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**(n + S(1))*(c + d*x)**m*sin(e + f*x), x), x) + Dist(b*d*m/(f*(a**S(2) - b**S(2))*(n + S(1))), Int((a + b*sin(e + f*x))**(n + S(1))*(c + d*x)**(m + S(-1))*cos(e + f*x), x), x) - Simp(b*(a + b*sin(e + f*x))**(n + S(1))*(c + d*x)**m*cos(e + f*x)/(f*(a**S(2) - b**S(2))*(n + S(1))), x) def replacement3266(a, b, c, d, e, f, m, n, x): return Dist(a/(a**S(2) - b**S(2)), Int((a + b*cos(e + f*x))**(n + S(1))*(c + d*x)**m, x), x) - Dist(b*(n + S(2))/((a**S(2) - b**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**(n + S(1))*(c + d*x)**m*cos(e + f*x), x), x) - Dist(b*d*m/(f*(a**S(2) - b**S(2))*(n + S(1))), Int((a + b*cos(e + f*x))**(n + S(1))*(c + d*x)**(m + S(-1))*sin(e + f*x), x), x) + Simp(b*(a + b*cos(e + f*x))**(n + S(1))*(c + d*x)**m*sin(e + f*x)/(f*(a**S(2) - b**S(2))*(n + S(1))), x) def replacement3267(a, b, m, n, u, v, x): return Int((a + b*sin(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement3268(a, b, m, n, u, v, x): return Int((a + b*cos(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement3269(a, b, c, d, e, f, m, n, x): return Int((a + b*sin(e + f*x))**n*(c + d*x)**m, x) def replacement3270(a, b, c, d, e, f, m, n, x): return Int((a + b*cos(e + f*x))**n*(c + d*x)**m, x) def replacement3271(a, b, c, d, n, p, x): return Int(ExpandIntegrand(sin(c + d*x), (a + b*x**n)**p, x), x) def replacement3272(a, b, c, d, n, p, x): return Int(ExpandIntegrand(cos(c + d*x), (a + b*x**n)**p, x), x) def replacement3273(a, b, c, d, n, p, x): return -Dist(d/(b*n*(p + S(1))), Int(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*cos(c + d*x), x), x) - Dist((S(1) - n)/(b*n*(p + S(1))), Int(x**(-n)*(a + b*x**n)**(p + S(1))*sin(c + d*x), x), x) + Simp(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*sin(c + d*x)/(b*n*(p + S(1))), x) def replacement3274(a, b, c, d, n, p, x): return Dist(d/(b*n*(p + S(1))), Int(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*sin(c + d*x), x), x) - Dist((S(1) - n)/(b*n*(p + S(1))), Int(x**(-n)*(a + b*x**n)**(p + S(1))*cos(c + d*x), x), x) + Simp(x**(S(1) - n)*(a + b*x**n)**(p + S(1))*cos(c + d*x)/(b*n*(p + S(1))), x) def replacement3275(a, b, c, d, n, p, x): return Int(ExpandIntegrand(sin(c + d*x), (a + b*x**n)**p, x), x) def replacement3276(a, b, c, d, n, p, x): return Int(ExpandIntegrand(cos(c + d*x), (a + b*x**n)**p, x), x) def replacement3277(a, b, c, d, n, p, x): return Int(x**(n*p)*(a*x**(-n) + b)**p*sin(c + d*x), x) def replacement3278(a, b, c, d, n, p, x): return Int(x**(n*p)*(a*x**(-n) + b)**p*cos(c + d*x), x) def replacement3279(a, b, c, d, n, p, x): return Int((a + b*x**n)**p*sin(c + d*x), x) def replacement3280(a, b, c, d, n, p, x): return Int((a + b*x**n)**p*cos(c + d*x), x) def replacement3281(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(sin(c + d*x), (e*x)**m*(a + b*x**n)**p, x), x) def replacement3282(a, b, c, d, e, m, n, p, x): return Int(ExpandIntegrand(cos(c + d*x), (e*x)**m*(a + b*x**n)**p, x), x) def replacement3283(a, b, c, d, e, m, n, p, x): return -Dist(d*e**m/(b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*cos(c + d*x), x), x) + Simp(e**m*(a + b*x**n)**(p + S(1))*sin(c + d*x)/(b*n*(p + S(1))), x) def replacement3284(a, b, c, d, e, m, n, p, x): return Dist(d*e**m/(b*n*(p + S(1))), Int((a + b*x**n)**(p + S(1))*sin(c + d*x), x), x) + Simp(e**m*(a + b*x**n)**(p + S(1))*cos(c + d*x)/(b*n*(p + S(1))), x) def replacement3285(a, b, c, d, m, n, p, x): return -Dist(d/(b*n*(p + S(1))), Int(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*cos(c + d*x), x), x) - Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*(a + b*x**n)**(p + S(1))*sin(c + d*x), x), x) + Simp(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*sin(c + d*x)/(b*n*(p + S(1))), x) def replacement3286(a, b, c, d, m, n, p, x): return Dist(d/(b*n*(p + S(1))), Int(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*sin(c + d*x), x), x) - Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*(a + b*x**n)**(p + S(1))*cos(c + d*x), x), x) + Simp(x**(m - n + S(1))*(a + b*x**n)**(p + S(1))*cos(c + d*x)/(b*n*(p + S(1))), x) def replacement3287(a, b, c, d, m, n, p, x): return Int(ExpandIntegrand(sin(c + d*x), x**m*(a + b*x**n)**p, x), x) def replacement3288(a, b, c, d, m, n, p, x): return Int(ExpandIntegrand(cos(c + d*x), x**m*(a + b*x**n)**p, x), x) def replacement3289(a, b, c, d, m, n, p, x): return Int(x**(m + n*p)*(a*x**(-n) + b)**p*sin(c + d*x), x) def replacement3290(a, b, c, d, m, n, p, x): return Int(x**(m + n*p)*(a*x**(-n) + b)**p*cos(c + d*x), x) def replacement3291(a, b, c, d, e, m, n, p, x): return Int((e*x)**m*(a + b*x**n)**p*sin(c + d*x), x) def replacement3292(a, b, c, d, e, m, n, p, x): return Int((e*x)**m*(a + b*x**n)**p*cos(c + d*x), x) def replacement3293(d, x): return Simp(sqrt(S(2))*sqrt(Pi)*FresnelS(sqrt(S(2))*x*sqrt(S(1)/Pi)*Rt(d, S(2)))/(S(2)*Rt(d, S(2))), x) def replacement3294(d, x): return Simp(sqrt(S(2))*sqrt(Pi)*FresnelC(sqrt(S(2))*x*sqrt(S(1)/Pi)*Rt(d, S(2)))/(S(2)*Rt(d, S(2))), x) def replacement3295(c, d, x): return Dist(sin(c), Int(cos(d*x**S(2)), x), x) + Dist(cos(c), Int(sin(d*x**S(2)), x), x) def replacement3296(c, d, x): return -Dist(sin(c), Int(sin(d*x**S(2)), x), x) + Dist(cos(c), Int(cos(d*x**S(2)), x), x) def replacement3297(c, d, n, x): return Dist(I/S(2), Int(exp(-I*c - I*d*x**n), x), x) - Dist(I/S(2), Int(exp(I*c + I*d*x**n), x), x) def replacement3298(c, d, n, x): return Dist(S(1)/2, Int(exp(-I*c - I*d*x**n), x), x) + Dist(S(1)/2, Int(exp(I*c + I*d*x**n), x), x) def replacement3299(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*sin(c + d*x**n))**p, x), x) def replacement3300(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*cos(c + d*x**n))**p, x), x) def replacement3301(a, b, c, d, n, p, x): return -Subst(Int((a + b*sin(c + d*x**(-n)))**p/x**S(2), x), x, S(1)/x) def replacement3302(a, b, c, d, n, p, x): return -Subst(Int((a + b*cos(c + d*x**(-n)))**p/x**S(2), x), x, S(1)/x) def With3303(a, b, c, d, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k + S(-1))*(a + b*sin(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def With3304(a, b, c, d, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k + S(-1))*(a + b*cos(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def replacement3305(c, d, n, x): return Dist(I/S(2), Int(exp(-I*c - I*d*x**n), x), x) - Dist(I/S(2), Int(exp(I*c + I*d*x**n), x), x) def replacement3306(c, d, n, x): return Dist(S(1)/2, Int(exp(-I*c - I*d*x**n), x), x) + Dist(S(1)/2, Int(exp(I*c + I*d*x**n), x), x) def replacement3307(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*sin(c + d*x**n))**p, x), x) def replacement3308(a, b, c, d, n, p, x): return Int(ExpandTrigReduce((a + b*cos(c + d*x**n))**p, x), x) def replacement3309(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*sin(c + d*x**n))**p, x), x, u), x) def replacement3310(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*cos(c + d*x**n))**p, x), x, u), x) def replacement3311(a, b, c, d, n, p, u, x): return Int((a + b*sin(c + d*u**n))**p, x) def replacement3312(a, b, c, d, n, p, u, x): return Int((a + b*cos(c + d*u**n))**p, x) def replacement3313(a, b, p, u, x): return Int((a + b*sin(ExpandToSum(u, x)))**p, x) def replacement3314(a, b, p, u, x): return Int((a + b*cos(ExpandToSum(u, x)))**p, x) def replacement3315(d, n, x): return Simp(SinIntegral(d*x**n)/n, x) def replacement3316(d, n, x): return Simp(CosIntegral(d*x**n)/n, x) def replacement3317(c, d, n, x): return Dist(sin(c), Int(cos(d*x**n)/x, x), x) + Dist(cos(c), Int(sin(d*x**n)/x, x), x) def replacement3318(c, d, n, x): return -Dist(sin(c), Int(sin(d*x**n)/x, x), x) + Dist(cos(c), Int(cos(d*x**n)/x, x), x) def With3319(a, b, c, d, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement3319(a, b, c, d, m, n, p, x): mn = (m + S(1))/n return Dist(S(1)/n, Subst(Int(x**(mn + S(-1))*(a + b*sin(c + d*x))**p, x), x, x**n), x) def With3320(a, b, c, d, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement3320(a, b, c, d, m, n, p, x): mn = (m + S(1))/n return Dist(S(1)/n, Subst(Int(x**(mn + S(-1))*(a + b*cos(c + d*x))**p, x), x, x**n), x) def With3321(a, b, c, d, e, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement3321(a, b, c, d, e, m, n, p, x): mn = (m + S(1))/n return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*sin(c + d*x**n))**p, x), x) def With3322(a, b, c, d, e, m, n, p, x): if isinstance(x, (int, Integer, float, Float)): return False mn = (m + S(1))/n if And(IntegerQ(mn), Or(Equal(p, S(1)), Greater(mn, S(0)))): return True return False def replacement3322(a, b, c, d, e, m, n, p, x): mn = (m + S(1))/n return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*cos(c + d*x**n))**p, x), x) def replacement3323(a, b, m, n, x): return Dist(S(2)/n, Subst(Int(sin(a + b*x**S(2)), x), x, x**(n/S(2))), x) def replacement3324(a, b, m, n, x): return Dist(S(2)/n, Subst(Int(cos(a + b*x**S(2)), x), x, x**(n/S(2))), x) def replacement3325(c, d, e, m, n, x): return Dist(e**n*(m - n + S(1))/(d*n), Int((e*x)**(m - n)*cos(c + d*x**n), x), x) - Simp(e**(n + S(-1))*(e*x)**(m - n + S(1))*cos(c + d*x**n)/(d*n), x) def replacement3326(c, d, e, m, n, x): return -Dist(e**n*(m - n + S(1))/(d*n), Int((e*x)**(m - n)*sin(c + d*x**n), x), x) + Simp(e**(n + S(-1))*(e*x)**(m - n + S(1))*sin(c + d*x**n)/(d*n), x) def replacement3327(c, d, e, m, n, x): return -Dist(d*e**(-n)*n/(m + S(1)), Int((e*x)**(m + n)*cos(c + d*x**n), x), x) + Simp((e*x)**(m + S(1))*sin(c + d*x**n)/(e*(m + S(1))), x) def replacement3328(c, d, e, m, n, x): return Dist(d*e**(-n)*n/(m + S(1)), Int((e*x)**(m + n)*sin(c + d*x**n), x), x) + Simp((e*x)**(m + S(1))*cos(c + d*x**n)/(e*(m + S(1))), x) def replacement3329(c, d, e, m, n, x): return Dist(I/S(2), Int((e*x)**m*exp(-I*c - I*d*x**n), x), x) - Dist(I/S(2), Int((e*x)**m*exp(I*c + I*d*x**n), x), x) def replacement3330(c, d, e, m, n, x): return Dist(S(1)/2, Int((e*x)**m*exp(-I*c - I*d*x**n), x), x) + Dist(S(1)/2, Int((e*x)**m*exp(I*c + I*d*x**n), x), x) def replacement3331(a, b, m, n, p, x): return Dist(b*n*p/(n + S(-1)), Int(sin(a + b*x**n)**(p + S(-1))*cos(a + b*x**n), x), x) - Simp(x**(S(1) - n)*sin(a + b*x**n)**p/(n + S(-1)), x) def replacement3332(a, b, m, n, p, x): return -Dist(b*n*p/(n + S(-1)), Int(sin(a + b*x**n)*cos(a + b*x**n)**(p + S(-1)), x), x) - Simp(x**(S(1) - n)*cos(a + b*x**n)**p/(n + S(-1)), x) def replacement3333(a, b, m, n, p, x): return Dist((p + S(-1))/p, Int(x**m*sin(a + b*x**n)**(p + S(-2)), x), x) + Simp(sin(a + b*x**n)**p/(b**S(2)*n*p**S(2)), x) - Simp(x**n*sin(a + b*x**n)**(p + S(-1))*cos(a + b*x**n)/(b*n*p), x) def replacement3334(a, b, m, n, p, x): return Dist((p + S(-1))/p, Int(x**m*cos(a + b*x**n)**(p + S(-2)), x), x) + Simp(cos(a + b*x**n)**p/(b**S(2)*n*p**S(2)), x) + Simp(x**n*sin(a + b*x**n)*cos(a + b*x**n)**(p + S(-1))/(b*n*p), x) def replacement3335(a, b, m, n, p, x): return Dist((p + S(-1))/p, Int(x**m*sin(a + b*x**n)**(p + S(-2)), x), x) - Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*p**S(2)), Int(x**(m - S(2)*n)*sin(a + b*x**n)**p, x), x) + Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*sin(a + b*x**n)**p/(b**S(2)*n**S(2)*p**S(2)), x) - Simp(x**(m - n + S(1))*sin(a + b*x**n)**(p + S(-1))*cos(a + b*x**n)/(b*n*p), x) def replacement3336(a, b, m, n, p, x): return Dist((p + S(-1))/p, Int(x**m*cos(a + b*x**n)**(p + S(-2)), x), x) - Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*p**S(2)), Int(x**(m - S(2)*n)*cos(a + b*x**n)**p, x), x) + Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*cos(a + b*x**n)**p/(b**S(2)*n**S(2)*p**S(2)), x) + Simp(x**(m - n + S(1))*sin(a + b*x**n)*cos(a + b*x**n)**(p + S(-1))/(b*n*p), x) def replacement3337(a, b, m, n, p, x): return -Dist(b**S(2)*n**S(2)*p**S(2)/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*sin(a + b*x**n)**p, x), x) + Dist(b**S(2)*n**S(2)*p*(p + S(-1))/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*sin(a + b*x**n)**(p + S(-2)), x), x) + Simp(x**(m + S(1))*sin(a + b*x**n)**p/(m + S(1)), x) - Simp(b*n*p*x**(m + n + S(1))*sin(a + b*x**n)**(p + S(-1))*cos(a + b*x**n)/((m + S(1))*(m + n + S(1))), x) def replacement3338(a, b, m, n, p, x): return -Dist(b**S(2)*n**S(2)*p**S(2)/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*cos(a + b*x**n)**p, x), x) + Dist(b**S(2)*n**S(2)*p*(p + S(-1))/((m + S(1))*(m + n + S(1))), Int(x**(m + S(2)*n)*cos(a + b*x**n)**(p + S(-2)), x), x) + Simp(x**(m + S(1))*cos(a + b*x**n)**p/(m + S(1)), x) + Simp(b*n*p*x**(m + n + S(1))*sin(a + b*x**n)*cos(a + b*x**n)**(p + S(-1))/((m + S(1))*(m + n + S(1))), x) def With3339(a, b, c, d, e, m, n, p, x): k = Denominator(m) return Dist(k/e, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*sin(c + d*e**(-n)*x**(k*n)))**p, x), x, (e*x)**(S(1)/k)), x) def With3340(a, b, c, d, e, m, n, p, x): k = Denominator(m) return Dist(k/e, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*cos(c + d*e**(-n)*x**(k*n)))**p, x), x, (e*x)**(S(1)/k)), x) def replacement3341(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*sin(c + d*x**n))**p, x), x) def replacement3342(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*cos(c + d*x**n))**p, x), x) def replacement3343(a, b, m, n, p, x): return Dist((p + S(2))/(p + S(1)), Int(x**m*sin(a + b*x**n)**(p + S(2)), x), x) - Simp(sin(a + b*x**n)**(p + S(2))/(b**S(2)*n*(p + S(1))*(p + S(2))), x) + Simp(x**n*sin(a + b*x**n)**(p + S(1))*cos(a + b*x**n)/(b*n*(p + S(1))), x) def replacement3344(a, b, m, n, p, x): return Dist((p + S(2))/(p + S(1)), Int(x**m*cos(a + b*x**n)**(p + S(2)), x), x) - Simp(cos(a + b*x**n)**(p + S(2))/(b**S(2)*n*(p + S(1))*(p + S(2))), x) - Simp(x**n*sin(a + b*x**n)*cos(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement3345(a, b, m, n, p, x): return Dist((p + S(2))/(p + S(1)), Int(x**m*sin(a + b*x**n)**(p + S(2)), x), x) + Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**(m - S(2)*n)*sin(a + b*x**n)**(p + S(2)), x), x) + Simp(x**(m - n + S(1))*sin(a + b*x**n)**(p + S(1))*cos(a + b*x**n)/(b*n*(p + S(1))), x) - Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*sin(a + b*x**n)**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement3346(a, b, m, n, p, x): return Dist((p + S(2))/(p + S(1)), Int(x**m*cos(a + b*x**n)**(p + S(2)), x), x) + Dist((m - S(2)*n + S(1))*(m - n + S(1))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), Int(x**(m - S(2)*n)*cos(a + b*x**n)**(p + S(2)), x), x) - Simp(x**(m - n + S(1))*sin(a + b*x**n)*cos(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) - Simp(x**(m - S(2)*n + S(1))*(m - n + S(1))*cos(a + b*x**n)**(p + S(2))/(b**S(2)*n**S(2)*(p + S(1))*(p + S(2))), x) def replacement3347(a, b, c, d, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(a + b*sin(c + d*x**(-n)))**p, x), x, S(1)/x) def replacement3348(a, b, c, d, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(a + b*cos(c + d*x**(-n)))**p, x), x, S(1)/x) def With3349(a, b, c, d, e, m, n, p, x): k = Denominator(m) return -Dist(k/e, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*sin(c + d*e**(-n)*x**(-k*n)))**p, x), x, (e*x)**(-S(1)/k)), x) def With3350(a, b, c, d, e, m, n, p, x): k = Denominator(m) return -Dist(k/e, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*cos(c + d*e**(-n)*x**(-k*n)))**p, x), x, (e*x)**(-S(1)/k)), x) def replacement3351(a, b, c, d, e, m, n, p, x): return -Dist((e*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a + b*sin(c + d*x**(-n)))**p, x), x, S(1)/x), x) def replacement3352(a, b, c, d, e, m, n, p, x): return -Dist((e*x)**m*(S(1)/x)**m, Subst(Int(x**(-m + S(-2))*(a + b*cos(c + d*x**(-n)))**p, x), x, S(1)/x), x) def With3353(a, b, c, d, m, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*sin(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def With3354(a, b, c, d, m, n, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*cos(c + d*x**(k*n)))**p, x), x, x**(S(1)/k)), x) def replacement3355(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*sin(c + d*x**n))**p, x), x) def replacement3356(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*cos(c + d*x**n))**p, x), x) def replacement3357(a, b, c, d, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*sin(c + d*x**(n/(m + S(1)))))**p, x), x, x**(m + S(1))), x) def replacement3358(a, b, c, d, m, n, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*cos(c + d*x**(n/(m + S(1)))))**p, x), x, x**(m + S(1))), x) def replacement3359(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*sin(c + d*x**n))**p, x), x) def replacement3360(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*cos(c + d*x**n))**p, x), x) def replacement3361(c, d, e, m, n, x): return Dist(I/S(2), Int((e*x)**m*exp(-I*c - I*d*x**n), x), x) - Dist(I/S(2), Int((e*x)**m*exp(I*c + I*d*x**n), x), x) def replacement3362(c, d, e, m, n, x): return Dist(S(1)/2, Int((e*x)**m*exp(-I*c - I*d*x**n), x), x) + Dist(S(1)/2, Int((e*x)**m*exp(I*c + I*d*x**n), x), x) def replacement3363(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*sin(c + d*x**n))**p, x), x) def replacement3364(a, b, c, d, e, m, n, p, x): return Int(ExpandTrigReduce((e*x)**m, (a + b*cos(c + d*x**n))**p, x), x) def replacement3365(a, b, c, d, m, n, p, u, x): return Dist(Coefficient(u, x, S(1))**(-m + S(-1)), Subst(Int((a + b*sin(c + d*x**n))**p*(x - Coefficient(u, x, S(0)))**m, x), x, u), x) def replacement3366(a, b, c, d, m, n, p, u, x): return Dist(Coefficient(u, x, S(1))**(-m + S(-1)), Subst(Int((a + b*cos(c + d*x**n))**p*(x - Coefficient(u, x, S(0)))**m, x), x, u), x) def replacement3367(a, b, c, d, e, m, n, p, u, x): return Int((e*x)**m*(a + b*sin(c + d*u**n))**p, x) def replacement3368(a, b, c, d, e, m, n, p, u, x): return Int((e*x)**m*(a + b*cos(c + d*u**n))**p, x) def replacement3369(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b*sin(ExpandToSum(u, x)))**p, x) def replacement3370(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b*cos(ExpandToSum(u, x)))**p, x) def replacement3371(a, b, m, n, p, x): return Simp(sin(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement3372(a, b, m, n, p, x): return -Simp(cos(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement3373(a, b, m, n, p, x): return -Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*sin(a + b*x**n)**(p + S(1)), x), x) + Simp(x**(m - n + S(1))*sin(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement3374(a, b, m, n, p, x): return Dist((m - n + S(1))/(b*n*(p + S(1))), Int(x**(m - n)*cos(a + b*x**n)**(p + S(1)), x), x) - Simp(x**(m - n + S(1))*cos(a + b*x**n)**(p + S(1))/(b*n*(p + S(1))), x) def replacement3375(a, b, c, x): return Int(sin((b + S(2)*c*x)**S(2)/(S(4)*c)), x) def replacement3376(a, b, c, x): return Int(cos((b + S(2)*c*x)**S(2)/(S(4)*c)), x) def replacement3377(a, b, c, x): return -Dist(sin((-S(4)*a*c + b**S(2))/(S(4)*c)), Int(cos((b + S(2)*c*x)**S(2)/(S(4)*c)), x), x) + Dist(cos((-S(4)*a*c + b**S(2))/(S(4)*c)), Int(sin((b + S(2)*c*x)**S(2)/(S(4)*c)), x), x) def replacement3378(a, b, c, x): return Dist(sin((-S(4)*a*c + b**S(2))/(S(4)*c)), Int(sin((b + S(2)*c*x)**S(2)/(S(4)*c)), x), x) + Dist(cos((-S(4)*a*c + b**S(2))/(S(4)*c)), Int(cos((b + S(2)*c*x)**S(2)/(S(4)*c)), x), x) def replacement3379(a, b, c, n, x): return Int(ExpandTrigReduce(sin(a + b*x + c*x**S(2))**n, x), x) def replacement3380(a, b, c, n, x): return Int(ExpandTrigReduce(cos(a + b*x + c*x**S(2))**n, x), x) def replacement3381(n, v, x): return Int(sin(ExpandToSum(v, x))**n, x) def replacement3382(n, v, x): return Int(cos(ExpandToSum(v, x))**n, x) def replacement3383(a, b, c, d, e, x): return -Simp(e*cos(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3384(a, b, c, d, e, x): return Simp(e*sin(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3385(a, b, c, d, e, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int(sin(a + b*x + c*x**S(2)), x), x) - Simp(e*cos(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3386(a, b, c, d, e, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int(cos(a + b*x + c*x**S(2)), x), x) + Simp(e*sin(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3387(a, b, c, d, e, m, x): return Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*cos(a + b*x + c*x**S(2)), x), x) - Simp(e*(d + e*x)**(m + S(-1))*cos(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3388(a, b, c, d, e, m, x): return -Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*sin(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*sin(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3389(a, b, c, d, e, m, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int((d + e*x)**(m + S(-1))*sin(a + b*x + c*x**S(2)), x), x) + Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*cos(a + b*x + c*x**S(2)), x), x) - Simp(e*(d + e*x)**(m + S(-1))*cos(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3390(a, b, c, d, e, m, x): return -Dist((b*e - S(2)*c*d)/(S(2)*c), Int((d + e*x)**(m + S(-1))*cos(a + b*x + c*x**S(2)), x), x) - Dist(e**S(2)*(m + S(-1))/(S(2)*c), Int((d + e*x)**(m + S(-2))*sin(a + b*x + c*x**S(2)), x), x) + Simp(e*(d + e*x)**(m + S(-1))*sin(a + b*x + c*x**S(2))/(S(2)*c), x) def replacement3391(a, b, c, d, e, m, x): return -Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*cos(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*sin(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement3392(a, b, c, d, e, m, x): return Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*sin(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*cos(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement3393(a, b, c, d, e, m, x): return -Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*cos(a + b*x + c*x**S(2)), x), x) - Dist((b*e - S(2)*c*d)/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(1))*cos(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*sin(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement3394(a, b, c, d, e, m, x): return Dist(S(2)*c/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(2))*sin(a + b*x + c*x**S(2)), x), x) + Dist((b*e - S(2)*c*d)/(e**S(2)*(m + S(1))), Int((d + e*x)**(m + S(1))*sin(a + b*x + c*x**S(2)), x), x) + Simp((d + e*x)**(m + S(1))*cos(a + b*x + c*x**S(2))/(e*(m + S(1))), x) def replacement3395(a, b, c, d, e, m, x): return Int((d + e*x)**m*sin(a + b*x + c*x**S(2)), x) def replacement3396(a, b, c, d, e, m, x): return Int((d + e*x)**m*cos(a + b*x + c*x**S(2)), x) def replacement3397(a, b, c, d, e, m, n, x): return Int(ExpandTrigReduce((d + e*x)**m, sin(a + b*x + c*x**S(2))**n, x), x) def replacement3398(a, b, c, d, e, m, n, x): return Int(ExpandTrigReduce((d + e*x)**m, cos(a + b*x + c*x**S(2))**n, x), x) def replacement3399(m, n, u, v, x): return Int(ExpandToSum(u, x)**m*sin(ExpandToSum(v, x))**n, x) def replacement3400(m, n, u, v, x): return Int(ExpandToSum(u, x)**m*cos(ExpandToSum(v, x))**n, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/special_functions.py000066400000000000000000002565121412543434000252640ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def special_functions(): from sympy.integrals.rubi.constraints import cons69, cons2, cons3, cons68, cons19, cons1266, cons8, cons29, cons20, cons168, cons1959, cons1960, cons96, cons263, cons1961, cons1834, cons64, cons1962, cons1963, cons1964, cons249, cons1965, cons1966, cons1967, cons1833, cons4, cons1257, cons21, cons1361, cons1968, cons1969, cons170, cons1970, cons1971, cons33, cons1972, cons1973, cons1974, cons802, cons89, cons90, cons5, cons52, cons91, cons385, cons50, cons1975, cons1976, cons1977, cons54, cons1978, cons1101, cons127, cons1245, cons13, cons139, cons1381, cons1979, cons1980, cons198, cons1981, cons1982, cons1983, cons152, cons465, cons1767, cons165, cons950, cons951, cons1984, cons1985, cons805, cons1986, cons1987, cons1988, cons1989, cons340, cons1990, cons1991, cons1992, cons1993, cons1994, cons1995, cons40, cons1996, cons349, cons1997, cons1998, cons1999, cons2000, cons2001, cons2002, cons2003 pattern6742 = Pattern(Integral(Erf(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6742 = ReplacementRule(pattern6742, replacement6742) pattern6743 = Pattern(Integral(Erfc(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6743 = ReplacementRule(pattern6743, replacement6743) pattern6744 = Pattern(Integral(Erfi(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6744 = ReplacementRule(pattern6744, replacement6744) pattern6745 = Pattern(Integral(Erf(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6745 = ReplacementRule(pattern6745, replacement6745) pattern6746 = Pattern(Integral(Erfc(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6746 = ReplacementRule(pattern6746, replacement6746) pattern6747 = Pattern(Integral(Erfi(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6747 = ReplacementRule(pattern6747, replacement6747) pattern6748 = Pattern(Integral(x_**WC('m', S(1))*Erf(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6748 = ReplacementRule(pattern6748, replacement6748) pattern6749 = Pattern(Integral(x_**WC('m', S(1))*Erfc(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6749 = ReplacementRule(pattern6749, replacement6749) pattern6750 = Pattern(Integral(x_**WC('m', S(1))*Erfi(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6750 = ReplacementRule(pattern6750, replacement6750) pattern6751 = Pattern(Integral(x_*Erf(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6751 = ReplacementRule(pattern6751, replacement6751) pattern6752 = Pattern(Integral(x_*Erfc(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6752 = ReplacementRule(pattern6752, replacement6752) pattern6753 = Pattern(Integral(x_*Erfi(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6753 = ReplacementRule(pattern6753, replacement6753) pattern6754 = Pattern(Integral(x_**m_*Erf(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons168) rule6754 = ReplacementRule(pattern6754, replacement6754) pattern6755 = Pattern(Integral(x_**m_*Erfc(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons168) rule6755 = ReplacementRule(pattern6755, replacement6755) pattern6756 = Pattern(Integral(x_**m_*Erfi(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons168) rule6756 = ReplacementRule(pattern6756, replacement6756) pattern6757 = Pattern(Integral(Erf(x_*WC('b', S(1)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0)))/x_, x_), cons3, cons1959) rule6757 = ReplacementRule(pattern6757, replacement6757) pattern6758 = Pattern(Integral(Erfc(x_*WC('b', S(1)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0)))/x_, x_), cons3, cons1959) rule6758 = ReplacementRule(pattern6758, replacement6758) pattern6759 = Pattern(Integral(Erfi(x_*WC('b', S(1)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0)))/x_, x_), cons3, cons1960) rule6759 = ReplacementRule(pattern6759, replacement6759) pattern6760 = Pattern(Integral(x_**m_*Erf(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6760 = ReplacementRule(pattern6760, replacement6760) pattern6761 = Pattern(Integral(x_**m_*Erfc(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6761 = ReplacementRule(pattern6761, replacement6761) pattern6762 = Pattern(Integral(x_**m_*Erfi(x_*WC('b', S(1)) + WC('a', S(0)))*exp(x_**S(2)*WC('d', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6762 = ReplacementRule(pattern6762, replacement6762) pattern6763 = Pattern(Integral(Erf(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6763 = ReplacementRule(pattern6763, replacement6763) pattern6764 = Pattern(Integral(Erfc(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6764 = ReplacementRule(pattern6764, replacement6764) pattern6765 = Pattern(Integral(Erfi(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6765 = ReplacementRule(pattern6765, replacement6765) pattern6766 = Pattern(Integral(x_**WC('m', S(1))*Erf(x_*WC('b', S(1)))**S(2), x_), cons3, cons20, cons263, cons1961) rule6766 = ReplacementRule(pattern6766, replacement6766) pattern6767 = Pattern(Integral(x_**WC('m', S(1))*Erfc(x_*WC('b', S(1)))**S(2), x_), cons3, cons20, cons1834, cons1961) rule6767 = ReplacementRule(pattern6767, replacement6767) pattern6768 = Pattern(Integral(x_**WC('m', S(1))*Erfi(x_*WC('b', S(1)))**S(2), x_), cons3, cons20, cons1834, cons1961) rule6768 = ReplacementRule(pattern6768, replacement6768) pattern6769 = Pattern(Integral(x_**WC('m', S(1))*Erf(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6769 = ReplacementRule(pattern6769, replacement6769) pattern6770 = Pattern(Integral(x_**WC('m', S(1))*Erfc(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6770 = ReplacementRule(pattern6770, replacement6770) pattern6771 = Pattern(Integral(x_**WC('m', S(1))*Erfi(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6771 = ReplacementRule(pattern6771, replacement6771) pattern6772 = Pattern(Integral(FresnelS(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6772 = ReplacementRule(pattern6772, replacement6772) pattern6773 = Pattern(Integral(FresnelC(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6773 = ReplacementRule(pattern6773, replacement6773) pattern6774 = Pattern(Integral(FresnelS(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6774 = ReplacementRule(pattern6774, replacement6774) pattern6775 = Pattern(Integral(FresnelC(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6775 = ReplacementRule(pattern6775, replacement6775) pattern6776 = Pattern(Integral(x_**WC('m', S(1))*FresnelS(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6776 = ReplacementRule(pattern6776, replacement6776) pattern6777 = Pattern(Integral(x_**WC('m', S(1))*FresnelC(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6777 = ReplacementRule(pattern6777, replacement6777) pattern6778 = Pattern(Integral(FresnelS(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6778 = ReplacementRule(pattern6778, replacement6778) pattern6779 = Pattern(Integral(FresnelC(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6779 = ReplacementRule(pattern6779, replacement6779) pattern6780 = Pattern(Integral(x_**m_*FresnelS(x_*WC('b', S(1)))**S(2), x_), cons3, cons20, cons1834, cons1962) rule6780 = ReplacementRule(pattern6780, replacement6780) pattern6781 = Pattern(Integral(x_**m_*FresnelC(x_*WC('b', S(1)))**S(2), x_), cons3, cons20, cons1834, cons1962) rule6781 = ReplacementRule(pattern6781, replacement6781) pattern6782 = Pattern(Integral(x_*FresnelS(x_*WC('b', S(1)))*sin(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963) rule6782 = ReplacementRule(pattern6782, replacement6782) pattern6783 = Pattern(Integral(x_*FresnelC(x_*WC('b', S(1)))*cos(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963) rule6783 = ReplacementRule(pattern6783, replacement6783) pattern6784 = Pattern(Integral(x_**m_*FresnelS(x_*WC('b', S(1)))*sin(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons168, cons1964) rule6784 = ReplacementRule(pattern6784, replacement6784) pattern6785 = Pattern(Integral(x_**m_*FresnelC(x_*WC('b', S(1)))*cos(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons168, cons1964) rule6785 = ReplacementRule(pattern6785, replacement6785) pattern6786 = Pattern(Integral(x_**m_*FresnelS(x_*WC('b', S(1)))*sin(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons249, cons1965) rule6786 = ReplacementRule(pattern6786, replacement6786) pattern6787 = Pattern(Integral(x_**m_*FresnelC(x_*WC('b', S(1)))*cos(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons249, cons1965) rule6787 = ReplacementRule(pattern6787, replacement6787) pattern6788 = Pattern(Integral(x_*FresnelS(x_*WC('b', S(1)))*cos(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963) rule6788 = ReplacementRule(pattern6788, replacement6788) pattern6789 = Pattern(Integral(x_*FresnelC(x_*WC('b', S(1)))*sin(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963) rule6789 = ReplacementRule(pattern6789, replacement6789) pattern6790 = Pattern(Integral(x_**m_*FresnelS(x_*WC('b', S(1)))*cos(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons168, cons1966) rule6790 = ReplacementRule(pattern6790, replacement6790) pattern6791 = Pattern(Integral(x_**m_*FresnelC(x_*WC('b', S(1)))*sin(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons168, cons1966) rule6791 = ReplacementRule(pattern6791, replacement6791) pattern6792 = Pattern(Integral(x_**m_*FresnelS(x_*WC('b', S(1)))*cos(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons96, cons1967) rule6792 = ReplacementRule(pattern6792, replacement6792) pattern6793 = Pattern(Integral(x_**m_*FresnelC(x_*WC('b', S(1)))*sin(x_**S(2)*WC('c', S(1))), x_), cons3, cons8, cons1963, cons20, cons96, cons1967) rule6793 = ReplacementRule(pattern6793, replacement6793) pattern6794 = Pattern(Integral(ExpIntegralE(n_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons4, cons1833) rule6794 = ReplacementRule(pattern6794, replacement6794) pattern6795 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralE(n_, x_*WC('b', S(1))), x_), cons3, cons1257, cons64) rule6795 = ReplacementRule(pattern6795, replacement6795) pattern6796 = Pattern(Integral(ExpIntegralE(S(1), x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6796 = ReplacementRule(pattern6796, replacement6796) pattern6797 = Pattern(Integral(x_**m_*ExpIntegralE(n_, x_*WC('b', S(1))), x_), cons3, cons1257, cons20, cons96) rule6797 = ReplacementRule(pattern6797, replacement6797) pattern6798 = Pattern(Integral(x_**m_*ExpIntegralE(n_, x_*WC('b', S(1))), x_), cons3, cons19, cons4, cons1257, cons21) rule6798 = ReplacementRule(pattern6798, replacement6798) pattern6799 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralE(n_, x_*WC('b', S(1))), x_), cons3, cons19, cons4, cons1361) rule6799 = ReplacementRule(pattern6799, replacement6799) pattern6800 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralE(n_, a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons19, cons4, cons1968) rule6800 = ReplacementRule(pattern6800, replacement6800) pattern6801 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralE(n_, a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons19, cons1969, cons68) rule6801 = ReplacementRule(pattern6801, replacement6801) pattern6802 = Pattern(Integral(ExpIntegralEi(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6802 = ReplacementRule(pattern6802, replacement6802) pattern6803 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralEi(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6803 = ReplacementRule(pattern6803, replacement6803) pattern6804 = Pattern(Integral(ExpIntegralEi(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6804 = ReplacementRule(pattern6804, replacement6804) pattern6805 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralEi(x_*WC('b', S(1)))**S(2), x_), cons3, cons64) rule6805 = ReplacementRule(pattern6805, replacement6805) pattern6806 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralEi(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6806 = ReplacementRule(pattern6806, replacement6806) pattern6807 = Pattern(Integral(ExpIntegralEi(x_*WC('d', S(1)) + WC('c', S(0)))*exp(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6807 = ReplacementRule(pattern6807, replacement6807) pattern6808 = Pattern(Integral(x_**WC('m', S(1))*ExpIntegralEi(x_*WC('d', S(1)) + WC('c', S(0)))*exp(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule6808 = ReplacementRule(pattern6808, replacement6808) pattern6809 = Pattern(Integral(x_**m_*ExpIntegralEi(x_*WC('d', S(1)) + WC('c', S(0)))*exp(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6809 = ReplacementRule(pattern6809, replacement6809) pattern6810 = Pattern(Integral(LogIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6810 = ReplacementRule(pattern6810, replacement6810) pattern6811 = Pattern(Integral(LogIntegral(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6811 = ReplacementRule(pattern6811, replacement6811) pattern6812 = Pattern(Integral(x_**WC('m', S(1))*LogIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6812 = ReplacementRule(pattern6812, replacement6812) pattern6813 = Pattern(Integral(SinIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6813 = ReplacementRule(pattern6813, replacement6813) pattern6814 = Pattern(Integral(CosIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6814 = ReplacementRule(pattern6814, replacement6814) pattern6815 = Pattern(Integral(SinIntegral(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6815 = ReplacementRule(pattern6815, replacement6815) pattern6816 = Pattern(Integral(CosIntegral(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6816 = ReplacementRule(pattern6816, replacement6816) pattern6817 = Pattern(Integral(x_**WC('m', S(1))*SinIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6817 = ReplacementRule(pattern6817, replacement6817) pattern6818 = Pattern(Integral(x_**WC('m', S(1))*CosIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6818 = ReplacementRule(pattern6818, replacement6818) pattern6819 = Pattern(Integral(SinIntegral(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6819 = ReplacementRule(pattern6819, replacement6819) pattern6820 = Pattern(Integral(CosIntegral(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6820 = ReplacementRule(pattern6820, replacement6820) pattern6821 = Pattern(Integral(x_**WC('m', S(1))*SinIntegral(x_*WC('b', S(1)))**S(2), x_), cons3, cons64) rule6821 = ReplacementRule(pattern6821, replacement6821) pattern6822 = Pattern(Integral(x_**WC('m', S(1))*CosIntegral(x_*WC('b', S(1)))**S(2), x_), cons3, cons64) rule6822 = ReplacementRule(pattern6822, replacement6822) pattern6823 = Pattern(Integral(x_**WC('m', S(1))*SinIntegral(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6823 = ReplacementRule(pattern6823, replacement6823) pattern6824 = Pattern(Integral(x_**WC('m', S(1))*CosIntegral(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6824 = ReplacementRule(pattern6824, replacement6824) pattern6825 = Pattern(Integral(SinIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6825 = ReplacementRule(pattern6825, replacement6825) pattern6826 = Pattern(Integral(CosIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6826 = ReplacementRule(pattern6826, replacement6826) pattern6827 = Pattern(Integral(x_**WC('m', S(1))*SinIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule6827 = ReplacementRule(pattern6827, replacement6827) pattern6828 = Pattern(Integral(x_**WC('m', S(1))*CosIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule6828 = ReplacementRule(pattern6828, replacement6828) pattern6829 = Pattern(Integral(x_**m_*SinIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6829 = ReplacementRule(pattern6829, replacement6829) pattern6830 = Pattern(Integral(x_**WC('m', S(1))*CosIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6830 = ReplacementRule(pattern6830, replacement6830) pattern6831 = Pattern(Integral(SinIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6831 = ReplacementRule(pattern6831, replacement6831) pattern6832 = Pattern(Integral(CosIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6832 = ReplacementRule(pattern6832, replacement6832) pattern6833 = Pattern(Integral(x_**WC('m', S(1))*SinIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule6833 = ReplacementRule(pattern6833, replacement6833) pattern6834 = Pattern(Integral(x_**WC('m', S(1))*CosIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule6834 = ReplacementRule(pattern6834, replacement6834) pattern6835 = Pattern(Integral(x_**WC('m', S(1))*SinIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cos(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6835 = ReplacementRule(pattern6835, replacement6835) pattern6836 = Pattern(Integral(x_**m_*CosIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sin(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6836 = ReplacementRule(pattern6836, replacement6836) pattern6837 = Pattern(Integral(SinhIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6837 = ReplacementRule(pattern6837, replacement6837) pattern6838 = Pattern(Integral(CoshIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6838 = ReplacementRule(pattern6838, replacement6838) pattern6839 = Pattern(Integral(SinhIntegral(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6839 = ReplacementRule(pattern6839, replacement6839) pattern6840 = Pattern(Integral(CoshIntegral(x_*WC('b', S(1)))/x_, x_), cons3, cons3) rule6840 = ReplacementRule(pattern6840, replacement6840) pattern6841 = Pattern(Integral(x_**WC('m', S(1))*SinhIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6841 = ReplacementRule(pattern6841, replacement6841) pattern6842 = Pattern(Integral(x_**WC('m', S(1))*CoshIntegral(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons19, cons68) rule6842 = ReplacementRule(pattern6842, replacement6842) pattern6843 = Pattern(Integral(SinhIntegral(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6843 = ReplacementRule(pattern6843, replacement6843) pattern6844 = Pattern(Integral(CoshIntegral(x_*WC('b', S(1)) + WC('a', S(0)))**S(2), x_), cons2, cons3, cons69) rule6844 = ReplacementRule(pattern6844, replacement6844) pattern6845 = Pattern(Integral(x_**WC('m', S(1))*SinhIntegral(x_*WC('b', S(1)))**S(2), x_), cons3, cons64) rule6845 = ReplacementRule(pattern6845, replacement6845) pattern6846 = Pattern(Integral(x_**WC('m', S(1))*CoshIntegral(x_*WC('b', S(1)))**S(2), x_), cons3, cons64) rule6846 = ReplacementRule(pattern6846, replacement6846) pattern6847 = Pattern(Integral(x_**WC('m', S(1))*SinhIntegral(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6847 = ReplacementRule(pattern6847, replacement6847) pattern6848 = Pattern(Integral(x_**WC('m', S(1))*CoshIntegral(a_ + x_*WC('b', S(1)))**S(2), x_), cons2, cons3, cons64) rule6848 = ReplacementRule(pattern6848, replacement6848) pattern6849 = Pattern(Integral(SinhIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6849 = ReplacementRule(pattern6849, replacement6849) pattern6850 = Pattern(Integral(CoshIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6850 = ReplacementRule(pattern6850, replacement6850) pattern6851 = Pattern(Integral(x_**WC('m', S(1))*SinhIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons170) rule6851 = ReplacementRule(pattern6851, replacement6851) pattern6852 = Pattern(Integral(x_**WC('m', S(1))*CoshIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons170) rule6852 = ReplacementRule(pattern6852, replacement6852) pattern6853 = Pattern(Integral(x_**m_*SinhIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6853 = ReplacementRule(pattern6853, replacement6853) pattern6854 = Pattern(Integral(x_**WC('m', S(1))*CoshIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6854 = ReplacementRule(pattern6854, replacement6854) pattern6855 = Pattern(Integral(SinhIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6855 = ReplacementRule(pattern6855, replacement6855) pattern6856 = Pattern(Integral(CoshIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons1266) rule6856 = ReplacementRule(pattern6856, replacement6856) pattern6857 = Pattern(Integral(x_**WC('m', S(1))*SinhIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule6857 = ReplacementRule(pattern6857, replacement6857) pattern6858 = Pattern(Integral(x_**WC('m', S(1))*CoshIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons64) rule6858 = ReplacementRule(pattern6858, replacement6858) pattern6859 = Pattern(Integral(x_**WC('m', S(1))*SinhIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*cosh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6859 = ReplacementRule(pattern6859, replacement6859) pattern6860 = Pattern(Integral(x_**m_*CoshIntegral(x_*WC('d', S(1)) + WC('c', S(0)))*sinh(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons20, cons96) rule6860 = ReplacementRule(pattern6860, replacement6860) pattern6861 = Pattern(Integral(Gamma(n_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6861 = ReplacementRule(pattern6861, replacement6861) pattern6862 = Pattern(Integral(Gamma(n_, b_*x_)/x_, x_), cons3, cons4, cons1970) rule6862 = ReplacementRule(pattern6862, replacement6862) pattern6863 = Pattern(Integral(x_**WC('m', S(1))*Gamma(n_, b_*x_), x_), cons3, cons19, cons4, cons68) rule6863 = ReplacementRule(pattern6863, replacement6863) pattern6864 = Pattern(Integral(x_**WC('m', S(1))*Gamma(n_, a_ + x_*WC('b', S(1))), x_), cons2, cons3, cons19, cons4, cons1971, cons68) rule6864 = ReplacementRule(pattern6864, With6864) pattern6865 = Pattern(Integral(LogGamma(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6865 = ReplacementRule(pattern6865, replacement6865) pattern6866 = Pattern(Integral(x_**WC('m', S(1))*LogGamma(x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons33, cons170) rule6866 = ReplacementRule(pattern6866, replacement6866) pattern6867 = Pattern(Integral(PolyGamma(n_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons4, cons1833) rule6867 = ReplacementRule(pattern6867, replacement6867) pattern6868 = Pattern(Integral(x_**WC('m', S(1))*PolyGamma(n_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons4, cons33, cons170) rule6868 = ReplacementRule(pattern6868, replacement6868) pattern6869 = Pattern(Integral(x_**WC('m', S(1))*PolyGamma(n_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons4, cons33, cons96) rule6869 = ReplacementRule(pattern6869, replacement6869) pattern6870 = Pattern(Integral(Gamma(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*PolyGamma(S(0), x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons4, cons1833) rule6870 = ReplacementRule(pattern6870, replacement6870) pattern6871 = Pattern(Integral(Factorial(x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1))*PolyGamma(S(0), x_*WC('b', S(1)) + WC('c', S(0))), x_), cons2, cons3, cons8, cons4, cons1972) rule6871 = ReplacementRule(pattern6871, replacement6871) pattern6872 = Pattern(Integral(Zeta(S(2), x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons69) rule6872 = ReplacementRule(pattern6872, replacement6872) pattern6873 = Pattern(Integral(Zeta(s_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons802, cons1973, cons1974) rule6873 = ReplacementRule(pattern6873, replacement6873) pattern6874 = Pattern(Integral(x_**WC('m', S(1))*Zeta(S(2), x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons33) rule6874 = ReplacementRule(pattern6874, replacement6874) pattern6875 = Pattern(Integral(x_**WC('m', S(1))*Zeta(s_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons802, cons1973, cons1974, cons33, cons170) rule6875 = ReplacementRule(pattern6875, replacement6875) pattern6876 = Pattern(Integral(x_**WC('m', S(1))*Zeta(s_, x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons802, cons1973, cons1974, cons33, cons96) rule6876 = ReplacementRule(pattern6876, replacement6876) pattern6877 = Pattern(Integral(PolyLog(n_, (x_**WC('p', S(1))*WC('b', S(1)))**WC('q', S(1))*WC('a', S(1))), x_), cons2, cons3, cons5, cons52, cons89, cons90) rule6877 = ReplacementRule(pattern6877, replacement6877) pattern6878 = Pattern(Integral(PolyLog(n_, (x_**WC('p', S(1))*WC('b', S(1)))**WC('q', S(1))*WC('a', S(1))), x_), cons2, cons3, cons5, cons52, cons89, cons91) rule6878 = ReplacementRule(pattern6878, replacement6878) pattern6879 = Pattern(Integral(PolyLog(n_, (x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('c', S(1)))/(x_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons385) rule6879 = ReplacementRule(pattern6879, replacement6879) pattern6880 = Pattern(Integral(PolyLog(n_, (x_**WC('p', S(1))*WC('b', S(1)))**WC('q', S(1))*WC('a', S(1)))/x_, x_), cons2, cons3, cons4, cons5, cons52, cons1975) rule6880 = ReplacementRule(pattern6880, replacement6880) pattern6881 = Pattern(Integral(x_**WC('m', S(1))*PolyLog(n_, (x_**WC('p', S(1))*WC('b', S(1)))**WC('q', S(1))*WC('a', S(1))), x_), cons2, cons3, cons19, cons5, cons52, cons68, cons89, cons90) rule6881 = ReplacementRule(pattern6881, replacement6881) pattern6882 = Pattern(Integral(x_**WC('m', S(1))*PolyLog(n_, (x_**WC('p', S(1))*WC('b', S(1)))**WC('q', S(1))*WC('a', S(1))), x_), cons2, cons3, cons19, cons5, cons52, cons68, cons89, cons91) rule6882 = ReplacementRule(pattern6882, replacement6882) pattern6883 = Pattern(Integral(PolyLog(n_, (x_**WC('p', S(1))*WC('b', S(1)))**WC('q', S(1))*WC('a', S(1)))*log(x_**WC('m', S(1))*WC('c', S(1)))**WC('r', S(1))/x_, x_), cons2, cons3, cons8, cons19, cons4, cons52, cons54, cons1976, cons1977) rule6883 = ReplacementRule(pattern6883, replacement6883) pattern6884 = Pattern(Integral(PolyLog(n_, (x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons5, cons89, cons90) rule6884 = ReplacementRule(pattern6884, replacement6884) pattern6885 = Pattern(Integral(x_**WC('m', S(1))*PolyLog(n_, (x_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons19, cons5, cons89, cons90, cons64) rule6885 = ReplacementRule(pattern6885, replacement6885) pattern6886 = Pattern(Integral(PolyLog(n_, (F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1))))**WC('p', S(1))*WC('d', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons4, cons5, cons1978) rule6886 = ReplacementRule(pattern6886, replacement6886) pattern6887 = Pattern(Integral((x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*PolyLog(n_, (F_**((x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1))))**WC('p', S(1))*WC('d', S(1))), x_), cons1101, cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons33, cons170) rule6887 = ReplacementRule(pattern6887, replacement6887) pattern6888 = Pattern(Integral(u_*PolyLog(n_, v_), x_), cons4, cons4, CustomConstraint(With6888)) rule6888 = ReplacementRule(pattern6888, replacement6888) pattern6889 = Pattern(Integral(u_*PolyLog(n_, v_)*log(w_), x_), cons4, cons1245, CustomConstraint(With6889)) rule6889 = ReplacementRule(pattern6889, replacement6889) pattern6890 = Pattern(Integral((ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons13, cons139) rule6890 = ReplacementRule(pattern6890, replacement6890) pattern6891 = Pattern(Integral((ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons1381) rule6891 = ReplacementRule(pattern6891, replacement6891) pattern6892 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(a_ + x_*WC('b', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons5, cons64) rule6892 = ReplacementRule(pattern6892, replacement6892) pattern6893 = Pattern(Integral((ProductLog(x_**n_*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons4, cons5, cons1979) rule6893 = ReplacementRule(pattern6893, replacement6893) pattern6894 = Pattern(Integral((ProductLog(x_**n_*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons4, cons1980) rule6894 = ReplacementRule(pattern6894, replacement6894) pattern6895 = Pattern(Integral((ProductLog(x_**n_*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons5, cons198) rule6895 = ReplacementRule(pattern6895, replacement6895) pattern6896 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons19, cons4, cons5, cons68, cons1981) rule6896 = ReplacementRule(pattern6896, replacement6896) pattern6897 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons19, cons4, cons5, cons1982) rule6897 = ReplacementRule(pattern6897, replacement6897) pattern6898 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons19, cons1983) rule6898 = ReplacementRule(pattern6898, replacement6898) pattern6899 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**n_*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons5, cons152, cons465, cons68) rule6899 = ReplacementRule(pattern6899, replacement6899) pattern6900 = Pattern(Integral(S(1)/(d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1))), x_), cons2, cons3, cons29, cons1767) rule6900 = ReplacementRule(pattern6900, replacement6900) pattern6901 = Pattern(Integral(ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))/(d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1))), x_), cons2, cons3, cons29, cons1767) rule6901 = ReplacementRule(pattern6901, replacement6901) pattern6902 = Pattern(Integral((ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))**p_/(d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons13, cons165) rule6902 = ReplacementRule(pattern6902, replacement6902) pattern6903 = Pattern(Integral(S(1)/((d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1)))*ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))), x_), cons2, cons3, cons29, cons1767) rule6903 = ReplacementRule(pattern6903, replacement6903) pattern6904 = Pattern(Integral(S(1)/(sqrt(ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons950) rule6904 = ReplacementRule(pattern6904, replacement6904) pattern6905 = Pattern(Integral(S(1)/(sqrt(ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))*(d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1)))), x_), cons2, cons3, cons8, cons29, cons951) rule6905 = ReplacementRule(pattern6905, replacement6905) pattern6906 = Pattern(Integral((ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))**p_/(d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons13, cons139) rule6906 = ReplacementRule(pattern6906, replacement6906) pattern6907 = Pattern(Integral((ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_*WC('b', S(1)) + WC('a', S(0)))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons5, cons1984) rule6907 = ReplacementRule(pattern6907, replacement6907) pattern6908 = Pattern(Integral(x_**WC('m', S(1))/(d_ + ProductLog(a_ + x_*WC('b', S(1)))*WC('d', S(1))), x_), cons2, cons3, cons29, cons64) rule6908 = ReplacementRule(pattern6908, replacement6908) pattern6909 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(a_ + x_*WC('b', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(a_ + x_*WC('b', S(1)))*WC('d', S(1))), x_), cons2, cons3, cons8, cons29, cons5, cons64) rule6909 = ReplacementRule(pattern6909, replacement6909) pattern6910 = Pattern(Integral(S(1)/(d_ + ProductLog(x_**n_*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons29, cons198) rule6910 = ReplacementRule(pattern6910, replacement6910) pattern6911 = Pattern(Integral((ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons4, cons5, cons1985) rule6911 = ReplacementRule(pattern6911, replacement6911) pattern6912 = Pattern(Integral(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons29, cons805, cons1986) rule6912 = ReplacementRule(pattern6912, replacement6912) pattern6913 = Pattern(Integral((ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**p_/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons805, cons1987, cons1988) rule6913 = ReplacementRule(pattern6913, replacement6913) pattern6914 = Pattern(Integral((ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**p_/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons805, cons1987, cons1989) rule6914 = ReplacementRule(pattern6914, replacement6914) pattern6915 = Pattern(Integral((ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons340, cons90, cons1990) rule6915 = ReplacementRule(pattern6915, replacement6915) pattern6916 = Pattern(Integral((ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons340, cons90, cons1991) rule6916 = ReplacementRule(pattern6916, replacement6916) pattern6917 = Pattern(Integral((ProductLog(x_**n_*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**n_*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons5, cons198) rule6917 = ReplacementRule(pattern6917, replacement6917) pattern6918 = Pattern(Integral(x_**WC('m', S(1))/(d_ + ProductLog(x_*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons29, cons33, cons170) rule6918 = ReplacementRule(pattern6918, replacement6918) pattern6919 = Pattern(Integral(S(1)/(x_*(d_ + ProductLog(x_*WC('a', S(1)))*WC('d', S(1)))), x_), cons2, cons29, cons1992) rule6919 = ReplacementRule(pattern6919, replacement6919) pattern6920 = Pattern(Integral(x_**WC('m', S(1))/(d_ + ProductLog(x_*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons29, cons33, cons96) rule6920 = ReplacementRule(pattern6920, replacement6920) pattern6921 = Pattern(Integral(x_**WC('m', S(1))/(d_ + ProductLog(x_*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons29, cons19, cons21) rule6921 = ReplacementRule(pattern6921, replacement6921) pattern6922 = Pattern(Integral(S(1)/(x_*(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1)))), x_), cons2, cons29, cons4, cons1993) rule6922 = ReplacementRule(pattern6922, replacement6922) pattern6923 = Pattern(Integral(x_**WC('m', S(1))/(d_ + ProductLog(x_**n_*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons29, cons152, cons465, cons68) rule6923 = ReplacementRule(pattern6923, replacement6923) pattern6924 = Pattern(Integral((ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(x_*(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1)))), x_), cons2, cons8, cons29, cons4, cons5, cons1994) rule6924 = ReplacementRule(pattern6924, replacement6924) pattern6925 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons68, cons1995) rule6925 = ReplacementRule(pattern6925, replacement6925) pattern6926 = Pattern(Integral(x_**WC('m', S(1))*ProductLog(x_**WC('n', S(1))*WC('a', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons29, cons19, cons4, cons40, cons1996) rule6926 = ReplacementRule(pattern6926, replacement6926) pattern6927 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**p_/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons19, cons4, cons68, cons349, cons1997, cons1998) rule6927 = ReplacementRule(pattern6927, replacement6927) pattern6928 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**p_/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons19, cons4, cons68, cons349, cons1997, cons1999) rule6928 = ReplacementRule(pattern6928, replacement6928) pattern6929 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons68, cons2000, cons2001) rule6929 = ReplacementRule(pattern6929, replacement6929) pattern6930 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons19, cons4, cons5, cons68, cons2000, cons2002) rule6930 = ReplacementRule(pattern6930, replacement6930) pattern6931 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons19, cons5, cons68) rule6931 = ReplacementRule(pattern6931, replacement6931) pattern6932 = Pattern(Integral(x_**WC('m', S(1))*(ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('c', S(1)))**WC('p', S(1))/(d_ + ProductLog(x_**WC('n', S(1))*WC('a', S(1)))*WC('d', S(1))), x_), cons2, cons8, cons29, cons5, cons68, cons152, cons465) rule6932 = ReplacementRule(pattern6932, replacement6932) pattern6933 = Pattern(Integral(u_, x_), cons2003) rule6933 = ReplacementRule(pattern6933, replacement6933) return [rule6742, rule6743, rule6744, rule6745, rule6746, rule6747, rule6748, rule6749, rule6750, rule6751, rule6752, rule6753, rule6754, rule6755, rule6756, rule6757, rule6758, rule6759, rule6760, rule6761, rule6762, rule6763, rule6764, rule6765, rule6766, rule6767, rule6768, rule6769, rule6770, rule6771, rule6772, rule6773, rule6774, rule6775, rule6776, rule6777, rule6778, rule6779, rule6780, rule6781, rule6782, rule6783, rule6784, rule6785, rule6786, rule6787, rule6788, rule6789, rule6790, rule6791, rule6792, rule6793, rule6794, rule6795, rule6796, rule6797, rule6798, rule6799, rule6800, rule6801, rule6802, rule6803, rule6804, rule6805, rule6806, rule6807, rule6808, rule6809, rule6810, rule6811, rule6812, rule6813, rule6814, rule6815, rule6816, rule6817, rule6818, rule6819, rule6820, rule6821, rule6822, rule6823, rule6824, rule6825, rule6826, rule6827, rule6828, rule6829, rule6830, rule6831, rule6832, rule6833, rule6834, rule6835, rule6836, rule6837, rule6838, rule6839, rule6840, rule6841, rule6842, rule6843, rule6844, rule6845, rule6846, rule6847, rule6848, rule6849, rule6850, rule6851, rule6852, rule6853, rule6854, rule6855, rule6856, rule6857, rule6858, rule6859, rule6860, rule6861, rule6862, rule6863, rule6864, rule6865, rule6866, rule6867, rule6868, rule6869, rule6870, rule6871, rule6872, rule6873, rule6874, rule6875, rule6876, rule6877, rule6878, rule6879, rule6880, rule6881, rule6882, rule6883, rule6884, rule6885, rule6886, rule6887, rule6888, rule6889, rule6890, rule6891, rule6892, rule6893, rule6894, rule6895, rule6896, rule6897, rule6898, rule6899, rule6900, rule6901, rule6902, rule6903, rule6904, rule6905, rule6906, rule6907, rule6908, rule6909, rule6910, rule6911, rule6912, rule6913, rule6914, rule6915, rule6916, rule6917, rule6918, rule6919, rule6920, rule6921, rule6922, rule6923, rule6924, rule6925, rule6926, rule6927, rule6928, rule6929, rule6930, rule6931, rule6932, rule6933, ] def replacement6742(a, b, x): return Simp(exp(-(a + b*x)**S(2))/(sqrt(Pi)*b), x) + Simp((a + b*x)*Erf(a + b*x)/b, x) def replacement6743(a, b, x): return -Simp(exp(-(a + b*x)**S(2))/(sqrt(Pi)*b), x) + Simp((a + b*x)*Erfc(a + b*x)/b, x) def replacement6744(a, b, x): return -Simp(exp((a + b*x)**S(2))/(sqrt(Pi)*b), x) + Simp((a + b*x)*Erfi(a + b*x)/b, x) def replacement6745(b, x): return Simp(S(2)*b*x*HypergeometricPFQ(List(S(1)/2, S(1)/2), List(S(3)/2, S(3)/2), -b**S(2)*x**S(2))/sqrt(Pi), x) def replacement6746(b, x): return -Int(Erf(b*x)/x, x) + Simp(log(x), x) def replacement6747(b, x): return Simp(S(2)*b*x*HypergeometricPFQ(List(S(1)/2, S(1)/2), List(S(3)/2, S(3)/2), b**S(2)*x**S(2))/sqrt(Pi), x) def replacement6748(a, b, m, x): return -Dist(S(2)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*exp(-(a + b*x)**S(2)), x), x) + Simp(x**(m + S(1))*Erf(a + b*x)/(m + S(1)), x) def replacement6749(a, b, m, x): return Dist(S(2)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*exp(-(a + b*x)**S(2)), x), x) + Simp(x**(m + S(1))*Erfc(a + b*x)/(m + S(1)), x) def replacement6750(a, b, m, x): return -Dist(S(2)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*exp((a + b*x)**S(2)), x), x) + Simp(x**(m + S(1))*Erfi(a + b*x)/(m + S(1)), x) def replacement6751(a, b, c, d, x): return -Dist(b/(sqrt(Pi)*d), Int(exp(-a**S(2) - S(2)*a*b*x + c - x**S(2)*(b**S(2) - d)), x), x) + Simp(Erf(a + b*x)*exp(c + d*x**S(2))/(S(2)*d), x) def replacement6752(a, b, c, d, x): return Dist(b/(sqrt(Pi)*d), Int(exp(-a**S(2) - S(2)*a*b*x + c - x**S(2)*(b**S(2) - d)), x), x) + Simp(Erfc(a + b*x)*exp(c + d*x**S(2))/(S(2)*d), x) def replacement6753(a, b, c, d, x): return -Dist(b/(sqrt(Pi)*d), Int(exp(a**S(2) + S(2)*a*b*x + c + x**S(2)*(b**S(2) + d)), x), x) + Simp(Erfi(a + b*x)*exp(c + d*x**S(2))/(S(2)*d), x) def replacement6754(a, b, c, d, m, x): return -Dist((m + S(-1))/(S(2)*d), Int(x**(m + S(-2))*Erf(a + b*x)*exp(c + d*x**S(2)), x), x) - Dist(b/(sqrt(Pi)*d), Int(x**(m + S(-1))*exp(-a**S(2) - S(2)*a*b*x + c - x**S(2)*(b**S(2) - d)), x), x) + Simp(x**(m + S(-1))*Erf(a + b*x)*exp(c + d*x**S(2))/(S(2)*d), x) def replacement6755(a, b, c, d, m, x): return -Dist((m + S(-1))/(S(2)*d), Int(x**(m + S(-2))*Erfc(a + b*x)*exp(c + d*x**S(2)), x), x) + Dist(b/(sqrt(Pi)*d), Int(x**(m + S(-1))*exp(-a**S(2) - S(2)*a*b*x + c - x**S(2)*(b**S(2) - d)), x), x) + Simp(x**(m + S(-1))*Erfc(a + b*x)*exp(c + d*x**S(2))/(S(2)*d), x) def replacement6756(a, b, c, d, m, x): return -Dist((m + S(-1))/(S(2)*d), Int(x**(m + S(-2))*Erfi(a + b*x)*exp(c + d*x**S(2)), x), x) - Dist(b/(sqrt(Pi)*d), Int(x**(m + S(-1))*exp(a**S(2) + S(2)*a*b*x + c + x**S(2)*(b**S(2) + d)), x), x) + Simp(x**(m + S(-1))*Erfi(a + b*x)*exp(c + d*x**S(2))/(S(2)*d), x) def replacement6757(b, c, d, x): return Simp(S(2)*b*x*HypergeometricPFQ(List(S(1)/2, S(1)), List(S(3)/2, S(3)/2), d*x**S(2))*exp(c)/sqrt(Pi), x) def replacement6758(b, c, d, x): return Int(exp(c + d*x**S(2))/x, x) - Int(Erf(b*x)*exp(c + d*x**S(2))/x, x) def replacement6759(b, c, d, x): return Simp(S(2)*b*x*HypergeometricPFQ(List(S(1)/2, S(1)), List(S(3)/2, S(3)/2), d*x**S(2))*exp(c)/sqrt(Pi), x) def replacement6760(a, b, c, d, m, x): return -Dist(S(2)*d/(m + S(1)), Int(x**(m + S(2))*Erf(a + b*x)*exp(c + d*x**S(2)), x), x) - Dist(S(2)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*exp(-a**S(2) - S(2)*a*b*x + c - x**S(2)*(b**S(2) - d)), x), x) + Simp(x**(m + S(1))*Erf(a + b*x)*exp(c + d*x**S(2))/(m + S(1)), x) def replacement6761(a, b, c, d, m, x): return -Dist(S(2)*d/(m + S(1)), Int(x**(m + S(2))*Erfc(a + b*x)*exp(c + d*x**S(2)), x), x) + Dist(S(2)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*exp(-a**S(2) - S(2)*a*b*x + c - x**S(2)*(b**S(2) - d)), x), x) + Simp(x**(m + S(1))*Erfc(a + b*x)*exp(c + d*x**S(2))/(m + S(1)), x) def replacement6762(a, b, c, d, m, x): return -Dist(S(2)*d/(m + S(1)), Int(x**(m + S(2))*Erfi(a + b*x)*exp(c + d*x**S(2)), x), x) - Dist(S(2)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*exp(a**S(2) + S(2)*a*b*x + c + x**S(2)*(b**S(2) + d)), x), x) + Simp(x**(m + S(1))*Erfi(a + b*x)*exp(c + d*x**S(2))/(m + S(1)), x) def replacement6763(a, b, x): return -Dist(S(4)/sqrt(Pi), Int((a + b*x)*Erf(a + b*x)*exp(-(a + b*x)**S(2)), x), x) + Simp((a + b*x)*Erf(a + b*x)**S(2)/b, x) def replacement6764(a, b, x): return Dist(S(4)/sqrt(Pi), Int((a + b*x)*Erfc(a + b*x)*exp(-(a + b*x)**S(2)), x), x) + Simp((a + b*x)*Erfc(a + b*x)**S(2)/b, x) def replacement6765(a, b, x): return -Dist(S(4)/sqrt(Pi), Int((a + b*x)*Erfi(a + b*x)*exp((a + b*x)**S(2)), x), x) + Simp((a + b*x)*Erfi(a + b*x)**S(2)/b, x) def replacement6766(b, m, x): return -Dist(S(4)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*Erf(b*x)*exp(-b**S(2)*x**S(2)), x), x) + Simp(x**(m + S(1))*Erf(b*x)**S(2)/(m + S(1)), x) def replacement6767(b, m, x): return Dist(S(4)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*Erfc(b*x)*exp(-b**S(2)*x**S(2)), x), x) + Simp(x**(m + S(1))*Erfc(b*x)**S(2)/(m + S(1)), x) def replacement6768(b, m, x): return -Dist(S(4)*b/(sqrt(Pi)*(m + S(1))), Int(x**(m + S(1))*Erfi(b*x)*exp(b**S(2)*x**S(2)), x), x) + Simp(x**(m + S(1))*Erfi(b*x)**S(2)/(m + S(1)), x) def replacement6769(a, b, m, x): return Dist(S(1)/b, Subst(Int((-a/b + x/b)**m*Erf(x)**S(2), x), x, a + b*x), x) def replacement6770(a, b, m, x): return Dist(S(1)/b, Subst(Int((-a/b + x/b)**m*Erfc(x)**S(2), x), x, a + b*x), x) def replacement6771(a, b, m, x): return Dist(S(1)/b, Subst(Int((-a/b + x/b)**m*Erfi(x)**S(2), x), x, a + b*x), x) def replacement6772(a, b, x): return Simp(cos(Pi*(a + b*x)**S(2)/S(2))/(Pi*b), x) + Simp((a + b*x)*FresnelS(a + b*x)/b, x) def replacement6773(a, b, x): return -Simp(sin(Pi*(a + b*x)**S(2)/S(2))/(Pi*b), x) + Simp((a + b*x)*FresnelC(a + b*x)/b, x) def replacement6774(b, x): return Simp(I*b*x*HypergeometricPFQ(List(S(1)/2, S(1)/2), List(S(3)/2, S(3)/2), -I*Pi*b**S(2)*x**S(2)/S(2))/S(2), x) - Simp(I*b*x*HypergeometricPFQ(List(S(1)/2, S(1)/2), List(S(3)/2, S(3)/2), I*Pi*b**S(2)*x**S(2)/S(2))/S(2), x) def replacement6775(b, x): return Simp(b*x*HypergeometricPFQ(List(S(1)/2, S(1)/2), List(S(3)/2, S(3)/2), -I*Pi*b**S(2)*x**S(2)/S(2))/S(2), x) + Simp(b*x*HypergeometricPFQ(List(S(1)/2, S(1)/2), List(S(3)/2, S(3)/2), I*Pi*b**S(2)*x**S(2)/S(2))/S(2), x) def replacement6776(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*sin(Pi*(a + b*x)**S(2)/S(2)), x), x) + Simp(x**(m + S(1))*FresnelS(a + b*x)/(m + S(1)), x) def replacement6777(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*cos(Pi*(a + b*x)**S(2)/S(2)), x), x) + Simp(x**(m + S(1))*FresnelC(a + b*x)/(m + S(1)), x) def replacement6778(a, b, x): return -Dist(S(2), Int((a + b*x)*FresnelS(a + b*x)*sin(Pi*(a + b*x)**S(2)/S(2)), x), x) + Simp((a + b*x)*FresnelS(a + b*x)**S(2)/b, x) def replacement6779(a, b, x): return -Dist(S(2), Int((a + b*x)*FresnelC(a + b*x)*cos(Pi*(a + b*x)**S(2)/S(2)), x), x) + Simp((a + b*x)*FresnelC(a + b*x)**S(2)/b, x) def replacement6780(b, m, x): return -Dist(S(2)*b/(m + S(1)), Int(x**(m + S(1))*FresnelS(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2)), x), x) + Simp(x**(m + S(1))*FresnelS(b*x)**S(2)/(m + S(1)), x) def replacement6781(b, m, x): return -Dist(S(2)*b/(m + S(1)), Int(x**(m + S(1))*FresnelC(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2)), x), x) + Simp(x**(m + S(1))*FresnelC(b*x)**S(2)/(m + S(1)), x) def replacement6782(b, c, x): return Dist(S(1)/(S(2)*Pi*b), Int(sin(Pi*b**S(2)*x**S(2)), x), x) - Simp(FresnelS(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6783(b, c, x): return -Dist(S(1)/(S(2)*Pi*b), Int(sin(Pi*b**S(2)*x**S(2)), x), x) + Simp(FresnelC(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6784(b, c, m, x): return Dist(S(1)/(S(2)*Pi*b), Int(x**(m + S(-1))*sin(Pi*b**S(2)*x**S(2)), x), x) + Dist((m + S(-1))/(Pi*b**S(2)), Int(x**(m + S(-2))*FresnelS(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2)), x), x) - Simp(x**(m + S(-1))*FresnelS(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6785(b, c, m, x): return -Dist(S(1)/(S(2)*Pi*b), Int(x**(m + S(-1))*sin(Pi*b**S(2)*x**S(2)), x), x) - Dist((m + S(-1))/(Pi*b**S(2)), Int(x**(m + S(-2))*FresnelC(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2)), x), x) + Simp(x**(m + S(-1))*FresnelC(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6786(b, c, m, x): return Dist(b/(S(2)*m + S(2)), Int(x**(m + S(1))*cos(Pi*b**S(2)*x**S(2)), x), x) - Dist(Pi*b**S(2)/(m + S(1)), Int(x**(m + S(2))*FresnelS(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2)), x), x) - Simp(b*x**(m + S(2))/(S(2)*(m + S(1))*(m + S(2))), x) + Simp(x**(m + S(1))*FresnelS(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2))/(m + S(1)), x) def replacement6787(b, c, m, x): return -Dist(b/(S(2)*m + S(2)), Int(x**(m + S(1))*cos(Pi*b**S(2)*x**S(2)), x), x) + Dist(Pi*b**S(2)/(m + S(1)), Int(x**(m + S(2))*FresnelC(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2)), x), x) - Simp(b*x**(m + S(2))/(S(2)*(m + S(1))*(m + S(2))), x) + Simp(x**(m + S(1))*FresnelC(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2))/(m + S(1)), x) def replacement6788(b, c, x): return Dist(S(1)/(S(2)*Pi*b), Int(cos(Pi*b**S(2)*x**S(2)), x), x) - Simp(x/(S(2)*Pi*b), x) + Simp(FresnelS(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6789(b, c, x): return Dist(S(1)/(S(2)*Pi*b), Int(cos(Pi*b**S(2)*x**S(2)), x), x) + Simp(x/(S(2)*Pi*b), x) - Simp(FresnelC(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6790(b, c, m, x): return Dist(S(1)/(S(2)*Pi*b), Int(x**(m + S(-1))*cos(Pi*b**S(2)*x**S(2)), x), x) - Dist((m + S(-1))/(Pi*b**S(2)), Int(x**(m + S(-2))*FresnelS(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2)), x), x) - Simp(x**m/(S(2)*Pi*b*m), x) + Simp(x**(m + S(-1))*FresnelS(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6791(b, c, m, x): return Dist(S(1)/(S(2)*Pi*b), Int(x**(m + S(-1))*cos(Pi*b**S(2)*x**S(2)), x), x) + Dist((m + S(-1))/(Pi*b**S(2)), Int(x**(m + S(-2))*FresnelC(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2)), x), x) + Simp(x**m/(S(2)*Pi*b*m), x) - Simp(x**(m + S(-1))*FresnelC(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2))/(Pi*b**S(2)), x) def replacement6792(b, c, m, x): return -Dist(b/(S(2)*m + S(2)), Int(x**(m + S(1))*sin(Pi*b**S(2)*x**S(2)), x), x) + Dist(Pi*b**S(2)/(m + S(1)), Int(x**(m + S(2))*FresnelS(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2)), x), x) + Simp(x**(m + S(1))*FresnelS(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2))/(m + S(1)), x) def replacement6793(b, c, m, x): return -Dist(b/(S(2)*m + S(2)), Int(x**(m + S(1))*sin(Pi*b**S(2)*x**S(2)), x), x) - Dist(Pi*b**S(2)/(m + S(1)), Int(x**(m + S(2))*FresnelC(b*x)*cos(Pi*b**S(2)*x**S(2)/S(2)), x), x) + Simp(x**(m + S(1))*FresnelC(b*x)*sin(Pi*b**S(2)*x**S(2)/S(2))/(m + S(1)), x) def replacement6794(a, b, n, x): return -Simp(ExpIntegralE(n + S(1), a + b*x)/b, x) def replacement6795(b, m, n, x): return Dist(m/b, Int(x**(m + S(-1))*ExpIntegralE(n + S(1), b*x), x), x) - Simp(x**m*ExpIntegralE(n + S(1), b*x)/b, x) def replacement6796(b, x): return -Simp(EulerGamma*log(x), x) + Simp(b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), -b*x), x) - Simp(log(b*x)**S(2)/S(2), x) def replacement6797(b, m, n, x): return Dist(b/(m + S(1)), Int(x**(m + S(1))*ExpIntegralE(n + S(-1), b*x), x), x) + Simp(x**(m + S(1))*ExpIntegralE(n, b*x)/(m + S(1)), x) def replacement6798(b, m, n, x): return -Simp(x**(m + S(1))*HypergeometricPFQ(List(m + S(1), m + S(1)), List(m + S(2), m + S(2)), -b*x)/(m + S(1))**S(2), x) + Simp(x**m*(b*x)**(-m)*Gamma(m + S(1))*log(x)/b, x) def replacement6799(b, m, n, x): return -Simp(x**(m + S(1))*ExpIntegralE(-m, b*x)/(m + n), x) + Simp(x**(m + S(1))*ExpIntegralE(n, b*x)/(m + n), x) def replacement6800(a, b, m, n, x): return Dist(m/b, Int(x**(m + S(-1))*ExpIntegralE(n + S(1), a + b*x), x), x) - Simp(x**m*ExpIntegralE(n + S(1), a + b*x)/b, x) def replacement6801(a, b, m, n, x): return Dist(b/(m + S(1)), Int(x**(m + S(1))*ExpIntegralE(n + S(-1), a + b*x), x), x) + Simp(x**(m + S(1))*ExpIntegralE(n, a + b*x)/(m + S(1)), x) def replacement6802(a, b, x): return -Simp(exp(a + b*x)/b, x) + Simp((a + b*x)*ExpIntegralEi(a + b*x)/b, x) def replacement6803(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*exp(a + b*x)/(a + b*x), x), x) + Simp(x**(m + S(1))*ExpIntegralEi(a + b*x)/(m + S(1)), x) def replacement6804(a, b, x): return -Dist(S(2), Int(ExpIntegralEi(a + b*x)*exp(a + b*x), x), x) + Simp((a + b*x)*ExpIntegralEi(a + b*x)**S(2)/b, x) def replacement6805(b, m, x): return -Dist(S(2)/(m + S(1)), Int(x**m*ExpIntegralEi(b*x)*exp(b*x), x), x) + Simp(x**(m + S(1))*ExpIntegralEi(b*x)**S(2)/(m + S(1)), x) def replacement6806(a, b, m, x): return -Dist(a*m/(b*(m + S(1))), Int(x**(m + S(-1))*ExpIntegralEi(a + b*x)**S(2), x), x) - Dist(S(2)/(m + S(1)), Int(x**m*ExpIntegralEi(a + b*x)*exp(a + b*x), x), x) + Simp(x**(m + S(1))*ExpIntegralEi(a + b*x)**S(2)/(m + S(1)), x) + Simp(a*x**m*ExpIntegralEi(a + b*x)**S(2)/(b*(m + S(1))), x) def replacement6807(a, b, c, d, x): return -Dist(d/b, Int(exp(a + c + x*(b + d))/(c + d*x), x), x) + Simp(ExpIntegralEi(c + d*x)*exp(a + b*x)/b, x) def replacement6808(a, b, c, d, m, x): return -Dist(d/b, Int(x**m*exp(a + c + x*(b + d))/(c + d*x), x), x) - Dist(m/b, Int(x**(m + S(-1))*ExpIntegralEi(c + d*x)*exp(a + b*x), x), x) + Simp(x**m*ExpIntegralEi(c + d*x)*exp(a + b*x)/b, x) def replacement6809(a, b, c, d, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*ExpIntegralEi(c + d*x)*exp(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*exp(a + c + x*(b + d))/(c + d*x), x), x) + Simp(x**(m + S(1))*ExpIntegralEi(c + d*x)*exp(a + b*x)/(m + S(1)), x) def replacement6810(a, b, x): return -Simp(ExpIntegralEi(S(2)*log(a + b*x))/b, x) + Simp((a + b*x)*LogIntegral(a + b*x)/b, x) def replacement6811(b, x): return -Simp(b*x, x) + Simp(LogIntegral(b*x)*log(b*x), x) def replacement6812(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))/log(a + b*x), x), x) + Simp(x**(m + S(1))*LogIntegral(a + b*x)/(m + S(1)), x) def replacement6813(a, b, x): return Simp(cos(a + b*x)/b, x) + Simp((a + b*x)*SinIntegral(a + b*x)/b, x) def replacement6814(a, b, x): return -Simp(sin(a + b*x)/b, x) + Simp((a + b*x)*CosIntegral(a + b*x)/b, x) def replacement6815(b, x): return Simp(b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), -I*b*x)/S(2), x) + Simp(b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), I*b*x)/S(2), x) def replacement6816(b, x): return Simp(EulerGamma*log(x), x) - Simp(I*b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), -I*b*x)/S(2), x) + Simp(I*b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), I*b*x)/S(2), x) + Simp(log(b*x)**S(2)/S(2), x) def replacement6817(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*sin(a + b*x)/(a + b*x), x), x) + Simp(x**(m + S(1))*SinIntegral(a + b*x)/(m + S(1)), x) def replacement6818(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*cos(a + b*x)/(a + b*x), x), x) + Simp(x**(m + S(1))*CosIntegral(a + b*x)/(m + S(1)), x) def replacement6819(a, b, x): return -Dist(S(2), Int(SinIntegral(a + b*x)*sin(a + b*x), x), x) + Simp((a + b*x)*SinIntegral(a + b*x)**S(2)/b, x) def replacement6820(a, b, x): return -Dist(S(2), Int(CosIntegral(a + b*x)*cos(a + b*x), x), x) + Simp((a + b*x)*CosIntegral(a + b*x)**S(2)/b, x) def replacement6821(b, m, x): return -Dist(S(2)/(m + S(1)), Int(x**m*SinIntegral(b*x)*sin(b*x), x), x) + Simp(x**(m + S(1))*SinIntegral(b*x)**S(2)/(m + S(1)), x) def replacement6822(b, m, x): return -Dist(S(2)/(m + S(1)), Int(x**m*CosIntegral(b*x)*cos(b*x), x), x) + Simp(x**(m + S(1))*CosIntegral(b*x)**S(2)/(m + S(1)), x) def replacement6823(a, b, m, x): return -Dist(a*m/(b*(m + S(1))), Int(x**(m + S(-1))*SinIntegral(a + b*x)**S(2), x), x) - Dist(S(2)/(m + S(1)), Int(x**m*SinIntegral(a + b*x)*sin(a + b*x), x), x) + Simp(x**(m + S(1))*SinIntegral(a + b*x)**S(2)/(m + S(1)), x) + Simp(a*x**m*SinIntegral(a + b*x)**S(2)/(b*(m + S(1))), x) def replacement6824(a, b, m, x): return -Dist(a*m/(b*(m + S(1))), Int(x**(m + S(-1))*CosIntegral(a + b*x)**S(2), x), x) - Dist(S(2)/(m + S(1)), Int(x**m*CosIntegral(a + b*x)*cos(a + b*x), x), x) + Simp(x**(m + S(1))*CosIntegral(a + b*x)**S(2)/(m + S(1)), x) + Simp(a*x**m*CosIntegral(a + b*x)**S(2)/(b*(m + S(1))), x) def replacement6825(a, b, c, d, x): return Dist(d/b, Int(sin(c + d*x)*cos(a + b*x)/(c + d*x), x), x) - Simp(SinIntegral(c + d*x)*cos(a + b*x)/b, x) def replacement6826(a, b, c, d, x): return -Dist(d/b, Int(sin(a + b*x)*cos(c + d*x)/(c + d*x), x), x) + Simp(CosIntegral(c + d*x)*sin(a + b*x)/b, x) def replacement6827(a, b, c, d, m, x): return Dist(d/b, Int(x**m*sin(c + d*x)*cos(a + b*x)/(c + d*x), x), x) + Dist(m/b, Int(x**(m + S(-1))*SinIntegral(c + d*x)*cos(a + b*x), x), x) - Simp(x**m*SinIntegral(c + d*x)*cos(a + b*x)/b, x) def replacement6828(a, b, c, d, m, x): return -Dist(d/b, Int(x**m*sin(a + b*x)*cos(c + d*x)/(c + d*x), x), x) - Dist(m/b, Int(x**(m + S(-1))*CosIntegral(c + d*x)*sin(a + b*x), x), x) + Simp(x**m*CosIntegral(c + d*x)*sin(a + b*x)/b, x) def replacement6829(a, b, c, d, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*SinIntegral(c + d*x)*cos(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*sin(a + b*x)*sin(c + d*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*SinIntegral(c + d*x)*sin(a + b*x)/(m + S(1)), x) def replacement6830(a, b, c, d, m, x): return Dist(b/(m + S(1)), Int(x**(m + S(1))*CosIntegral(c + d*x)*sin(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*cos(a + b*x)*cos(c + d*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*CosIntegral(c + d*x)*cos(a + b*x)/(m + S(1)), x) def replacement6831(a, b, c, d, x): return -Dist(d/b, Int(sin(a + b*x)*sin(c + d*x)/(c + d*x), x), x) + Simp(SinIntegral(c + d*x)*sin(a + b*x)/b, x) def replacement6832(a, b, c, d, x): return Dist(d/b, Int(cos(a + b*x)*cos(c + d*x)/(c + d*x), x), x) - Simp(CosIntegral(c + d*x)*cos(a + b*x)/b, x) def replacement6833(a, b, c, d, m, x): return -Dist(d/b, Int(x**m*sin(a + b*x)*sin(c + d*x)/(c + d*x), x), x) - Dist(m/b, Int(x**(m + S(-1))*SinIntegral(c + d*x)*sin(a + b*x), x), x) + Simp(x**m*SinIntegral(c + d*x)*sin(a + b*x)/b, x) def replacement6834(a, b, c, d, m, x): return Dist(d/b, Int(x**m*cos(a + b*x)*cos(c + d*x)/(c + d*x), x), x) + Dist(m/b, Int(x**(m + S(-1))*CosIntegral(c + d*x)*cos(a + b*x), x), x) - Simp(x**m*CosIntegral(c + d*x)*cos(a + b*x)/b, x) def replacement6835(a, b, c, d, m, x): return Dist(b/(m + S(1)), Int(x**(m + S(1))*SinIntegral(c + d*x)*sin(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*sin(c + d*x)*cos(a + b*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*SinIntegral(c + d*x)*cos(a + b*x)/(m + S(1)), x) def replacement6836(a, b, c, d, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*CosIntegral(c + d*x)*cos(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*sin(a + b*x)*cos(c + d*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*CosIntegral(c + d*x)*sin(a + b*x)/(m + S(1)), x) def replacement6837(a, b, x): return -Simp(cosh(a + b*x)/b, x) + Simp((a + b*x)*SinhIntegral(a + b*x)/b, x) def replacement6838(a, b, x): return -Simp(sinh(a + b*x)/b, x) + Simp((a + b*x)*CoshIntegral(a + b*x)/b, x) def replacement6839(b, x): return Simp(b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), -b*x)/S(2), x) + Simp(b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), b*x)/S(2), x) def replacement6840(b, x): return Simp(EulerGamma*log(x), x) - Simp(b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), -b*x)/S(2), x) + Simp(b*x*HypergeometricPFQ(List(S(1), S(1), S(1)), List(S(2), S(2), S(2)), b*x)/S(2), x) + Simp(log(b*x)**S(2)/S(2), x) def replacement6841(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*sinh(a + b*x)/(a + b*x), x), x) + Simp(x**(m + S(1))*SinhIntegral(a + b*x)/(m + S(1)), x) def replacement6842(a, b, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*cosh(a + b*x)/(a + b*x), x), x) + Simp(x**(m + S(1))*CoshIntegral(a + b*x)/(m + S(1)), x) def replacement6843(a, b, x): return -Dist(S(2), Int(SinhIntegral(a + b*x)*sinh(a + b*x), x), x) + Simp((a + b*x)*SinhIntegral(a + b*x)**S(2)/b, x) def replacement6844(a, b, x): return -Dist(S(2), Int(CoshIntegral(a + b*x)*cosh(a + b*x), x), x) + Simp((a + b*x)*CoshIntegral(a + b*x)**S(2)/b, x) def replacement6845(b, m, x): return -Dist(S(2)/(m + S(1)), Int(x**m*SinhIntegral(b*x)*sinh(b*x), x), x) + Simp(x**(m + S(1))*SinhIntegral(b*x)**S(2)/(m + S(1)), x) def replacement6846(b, m, x): return -Dist(S(2)/(m + S(1)), Int(x**m*CoshIntegral(b*x)*cosh(b*x), x), x) + Simp(x**(m + S(1))*CoshIntegral(b*x)**S(2)/(m + S(1)), x) def replacement6847(a, b, m, x): return -Dist(a*m/(b*(m + S(1))), Int(x**(m + S(-1))*SinhIntegral(a + b*x)**S(2), x), x) - Dist(S(2)/(m + S(1)), Int(x**m*SinhIntegral(a + b*x)*sinh(a + b*x), x), x) + Simp(x**(m + S(1))*SinhIntegral(a + b*x)**S(2)/(m + S(1)), x) + Simp(a*x**m*SinhIntegral(a + b*x)**S(2)/(b*(m + S(1))), x) def replacement6848(a, b, m, x): return -Dist(a*m/(b*(m + S(1))), Int(x**(m + S(-1))*CoshIntegral(a + b*x)**S(2), x), x) - Dist(S(2)/(m + S(1)), Int(x**m*CoshIntegral(a + b*x)*cosh(a + b*x), x), x) + Simp(x**(m + S(1))*CoshIntegral(a + b*x)**S(2)/(m + S(1)), x) + Simp(a*x**m*CoshIntegral(a + b*x)**S(2)/(b*(m + S(1))), x) def replacement6849(a, b, c, d, x): return -Dist(d/b, Int(sinh(c + d*x)*cosh(a + b*x)/(c + d*x), x), x) + Simp(SinhIntegral(c + d*x)*cosh(a + b*x)/b, x) def replacement6850(a, b, c, d, x): return -Dist(d/b, Int(sinh(a + b*x)*cosh(c + d*x)/(c + d*x), x), x) + Simp(CoshIntegral(c + d*x)*sinh(a + b*x)/b, x) def replacement6851(a, b, c, d, m, x): return -Dist(d/b, Int(x**m*sinh(c + d*x)*cosh(a + b*x)/(c + d*x), x), x) - Dist(m/b, Int(x**(m + S(-1))*SinhIntegral(c + d*x)*cosh(a + b*x), x), x) + Simp(x**m*SinhIntegral(c + d*x)*cosh(a + b*x)/b, x) def replacement6852(a, b, c, d, m, x): return -Dist(d/b, Int(x**m*sinh(a + b*x)*cosh(c + d*x)/(c + d*x), x), x) - Dist(m/b, Int(x**(m + S(-1))*CoshIntegral(c + d*x)*sinh(a + b*x), x), x) + Simp(x**m*CoshIntegral(c + d*x)*sinh(a + b*x)/b, x) def replacement6853(a, b, c, d, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*SinhIntegral(c + d*x)*cosh(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*sinh(a + b*x)*sinh(c + d*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*SinhIntegral(c + d*x)*sinh(a + b*x)/(m + S(1)), x) def replacement6854(a, b, c, d, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*CoshIntegral(c + d*x)*sinh(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*cosh(a + b*x)*cosh(c + d*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*CoshIntegral(c + d*x)*cosh(a + b*x)/(m + S(1)), x) def replacement6855(a, b, c, d, x): return -Dist(d/b, Int(sinh(a + b*x)*sinh(c + d*x)/(c + d*x), x), x) + Simp(SinhIntegral(c + d*x)*sinh(a + b*x)/b, x) def replacement6856(a, b, c, d, x): return -Dist(d/b, Int(cosh(a + b*x)*cosh(c + d*x)/(c + d*x), x), x) + Simp(CoshIntegral(c + d*x)*cosh(a + b*x)/b, x) def replacement6857(a, b, c, d, m, x): return -Dist(d/b, Int(x**m*sinh(a + b*x)*sinh(c + d*x)/(c + d*x), x), x) - Dist(m/b, Int(x**(m + S(-1))*SinhIntegral(c + d*x)*sinh(a + b*x), x), x) + Simp(x**m*SinhIntegral(c + d*x)*sinh(a + b*x)/b, x) def replacement6858(a, b, c, d, m, x): return -Dist(d/b, Int(x**m*cosh(a + b*x)*cosh(c + d*x)/(c + d*x), x), x) - Dist(m/b, Int(x**(m + S(-1))*CoshIntegral(c + d*x)*cosh(a + b*x), x), x) + Simp(x**m*CoshIntegral(c + d*x)*cosh(a + b*x)/b, x) def replacement6859(a, b, c, d, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*SinhIntegral(c + d*x)*sinh(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*sinh(c + d*x)*cosh(a + b*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*SinhIntegral(c + d*x)*cosh(a + b*x)/(m + S(1)), x) def replacement6860(a, b, c, d, m, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*CoshIntegral(c + d*x)*cosh(a + b*x), x), x) - Dist(d/(m + S(1)), Int(x**(m + S(1))*sinh(a + b*x)*cosh(c + d*x)/(c + d*x), x), x) + Simp(x**(m + S(1))*CoshIntegral(c + d*x)*sinh(a + b*x)/(m + S(1)), x) def replacement6861(a, b, n, x): return -Simp(Gamma(n + S(1), a + b*x)/b, x) + Simp((a + b*x)*Gamma(n, a + b*x)/b, x) def replacement6862(b, n, x): return Simp(Gamma(n)*log(x), x) - Simp((b*x)**n*HypergeometricPFQ(List(n, n), List(n + S(1), n + S(1)), -b*x)/n**S(2), x) def replacement6863(b, m, n, x): return Simp(x**(m + S(1))*Gamma(n, b*x)/(m + S(1)), x) - Simp(x**m*(b*x)**(-m)*Gamma(m + n + S(1), b*x)/(b*(m + S(1))), x) def With6864(a, b, m, n, x): _UseGamma = True return Dist(b/(m + S(1)), Int(x**(m + S(1))*(a + b*x)**(n + S(-1))*exp(-a - b*x), x), x) + Simp(x**(m + S(1))*Gamma(n, a + b*x)/(m + S(1)), x) def replacement6865(a, b, x): return Simp(PolyGamma(S(-2), a + b*x)/b, x) def replacement6866(a, b, m, x): return -Dist(m/b, Int(x**(m + S(-1))*PolyGamma(S(-2), a + b*x), x), x) + Simp(x**m*PolyGamma(S(-2), a + b*x)/b, x) def replacement6867(a, b, n, x): return Simp(PolyGamma(n + S(-1), a + b*x)/b, x) def replacement6868(a, b, m, n, x): return -Dist(m/b, Int(x**(m + S(-1))*PolyGamma(n + S(-1), a + b*x), x), x) + Simp(x**m*PolyGamma(n + S(-1), a + b*x)/b, x) def replacement6869(a, b, m, n, x): return -Dist(b/(m + S(1)), Int(x**(m + S(1))*PolyGamma(n + S(1), a + b*x), x), x) + Simp(x**(m + S(1))*PolyGamma(n, a + b*x)/(m + S(1)), x) def replacement6870(a, b, n, x): return Simp(Gamma(a + b*x)**n/(b*n), x) def replacement6871(a, b, c, n, x): return Simp(Factorial(a + b*x)**n/(b*n), x) def replacement6872(a, b, x): return Int(PolyGamma(S(1), a + b*x), x) def replacement6873(a, b, s, x): return -Simp(Zeta(s + S(-1), a + b*x)/(b*(s + S(-1))), x) def replacement6874(a, b, m, x): return Int(x**m*PolyGamma(S(1), a + b*x), x) def replacement6875(a, b, m, s, x): return Dist(m/(b*(s + S(-1))), Int(x**(m + S(-1))*Zeta(s + S(-1), a + b*x), x), x) - Simp(x**m*Zeta(s + S(-1), a + b*x)/(b*(s + S(-1))), x) def replacement6876(a, b, m, s, x): return Dist(b*s/(m + S(1)), Int(x**(m + S(1))*Zeta(s + S(1), a + b*x), x), x) + Simp(x**(m + S(1))*Zeta(s, a + b*x)/(m + S(1)), x) def replacement6877(a, b, n, p, q, x): return -Dist(p*q, Int(PolyLog(n + S(-1), a*(b*x**p)**q), x), x) + Simp(x*PolyLog(n, a*(b*x**p)**q), x) def replacement6878(a, b, n, p, q, x): return -Dist(S(1)/(p*q), Int(PolyLog(n + S(1), a*(b*x**p)**q), x), x) + Simp(x*PolyLog(n + S(1), a*(b*x**p)**q)/(p*q), x) def replacement6879(a, b, c, d, e, n, p, x): return Simp(PolyLog(n + S(1), c*(a + b*x)**p)/(e*p), x) def replacement6880(a, b, n, p, q, x): return Simp(PolyLog(n + S(1), a*(b*x**p)**q)/(p*q), x) def replacement6881(a, b, m, n, p, q, x): return -Dist(p*q/(m + S(1)), Int(x**m*PolyLog(n + S(-1), a*(b*x**p)**q), x), x) + Simp(x**(m + S(1))*PolyLog(n, a*(b*x**p)**q)/(m + S(1)), x) def replacement6882(a, b, m, n, p, q, x): return -Dist((m + S(1))/(p*q), Int(x**m*PolyLog(n + S(1), a*(b*x**p)**q), x), x) + Simp(x**(m + S(1))*PolyLog(n + S(1), a*(b*x**p)**q)/(p*q), x) def replacement6883(a, b, c, m, n, p, q, r, x): return -Dist(m*r/(p*q), Int(PolyLog(n + S(1), a*(b*x**p)**q)*log(c*x**m)**(r + S(-1))/x, x), x) + Simp(PolyLog(n + S(1), a*(b*x**p)**q)*log(c*x**m)**r/(p*q), x) def replacement6884(a, b, c, n, p, x): return -Dist(p, Int(PolyLog(n + S(-1), c*(a + b*x)**p), x), x) + Dist(a*p, Int(PolyLog(n + S(-1), c*(a + b*x)**p)/(a + b*x), x), x) + Simp(x*PolyLog(n, c*(a + b*x)**p), x) def replacement6885(a, b, c, m, n, p, x): return -Dist(b*p/(m + S(1)), Int(x**(m + S(1))*PolyLog(n + S(-1), c*(a + b*x)**p)/(a + b*x), x), x) + Simp(x**(m + S(1))*PolyLog(n, c*(a + b*x)**p)/(m + S(1)), x) def replacement6886(F, a, b, c, d, n, p, x): return Simp(PolyLog(n + S(1), d*(F**(c*(a + b*x)))**p)/(b*c*p*log(F)), x) def replacement6887(F, a, b, c, d, e, f, m, n, p, x): return -Dist(f*m/(b*c*p*log(F)), Int((e + f*x)**(m + S(-1))*PolyLog(n + S(1), d*(F**(c*(a + b*x)))**p), x), x) + Simp((e + f*x)**m*PolyLog(n + S(1), d*(F**(c*(a + b*x)))**p)/(b*c*p*log(F)), x) def With6888(n, u, v, x): if isinstance(x, (int, Integer, float, Float)): return False try: w = DerivativeDivides(v, u*v, x) res = Not(FalseQ(w)) except (TypeError, AttributeError): return False if res: return True return False def replacement6888(n, u, v, x): w = DerivativeDivides(v, u*v, x) return Simp(w*PolyLog(n + S(1), v), x) def With6889(n, u, v, w, x): if isinstance(x, (int, Integer, float, Float)): return False try: z = DerivativeDivides(v, u*v, x) res = Not(FalseQ(z)) except (TypeError, AttributeError): return False if res: return True return False def replacement6889(n, u, v, w, x): z = DerivativeDivides(v, u*v, x) return -Int(SimplifyIntegrand(z*D(w, x)*PolyLog(n + S(1), v)/w, x), x) + Simp(z*PolyLog(n + S(1), v)*log(w), x) def replacement6890(a, b, c, p, x): return Dist(p/(c*(p + S(1))), Int((c*ProductLog(a + b*x))**(p + S(1))/(ProductLog(a + b*x) + S(1)), x), x) + Simp((c*ProductLog(a + b*x))**p*(a + b*x)/(b*(p + S(1))), x) def replacement6891(a, b, c, p, x): return -Dist(p, Int((c*ProductLog(a + b*x))**p/(ProductLog(a + b*x) + S(1)), x), x) + Simp((c*ProductLog(a + b*x))**p*(a + b*x)/b, x) def replacement6892(a, b, c, m, p, x): return Dist(S(1)/b, Subst(Int(ExpandIntegrand((c*ProductLog(x))**p, (-a/b + x/b)**m, x), x), x, a + b*x), x) def replacement6893(a, c, n, p, x): return -Dist(n*p, Int((c*ProductLog(a*x**n))**p/(ProductLog(a*x**n) + S(1)), x), x) + Simp(x*(c*ProductLog(a*x**n))**p, x) def replacement6894(a, c, n, p, x): return Dist(n*p/(c*(n*p + S(1))), Int((c*ProductLog(a*x**n))**(p + S(1))/(ProductLog(a*x**n) + S(1)), x), x) + Simp(x*(c*ProductLog(a*x**n))**p/(n*p + S(1)), x) def replacement6895(a, c, n, p, x): return -Subst(Int((c*ProductLog(a*x**(-n)))**p/x**S(2), x), x, S(1)/x) def replacement6896(a, c, m, n, p, x): return -Dist(n*p/(m + S(1)), Int(x**m*(c*ProductLog(a*x**n))**p/(ProductLog(a*x**n) + S(1)), x), x) + Simp(x**(m + S(1))*(c*ProductLog(a*x**n))**p/(m + S(1)), x) def replacement6897(a, c, m, n, p, x): return Dist(n*p/(c*(m + n*p + S(1))), Int(x**m*(c*ProductLog(a*x**n))**(p + S(1))/(ProductLog(a*x**n) + S(1)), x), x) + Simp(x**(m + S(1))*(c*ProductLog(a*x**n))**p/(m + n*p + S(1)), x) def replacement6898(a, c, m, p, x): return Dist(S(1)/c, Int(x**m*(c*ProductLog(a*x))**(p + S(1))/(ProductLog(a*x) + S(1)), x), x) + Int(x**m*(c*ProductLog(a*x))**p/(ProductLog(a*x) + S(1)), x) def replacement6899(a, c, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(c*ProductLog(a*x**(-n)))**p, x), x, S(1)/x) def replacement6900(a, b, d, x): return Simp((a + b*x)/(b*d*ProductLog(a + b*x)), x) def replacement6901(a, b, d, x): return -Int(S(1)/(d*ProductLog(a + b*x) + d), x) + Simp(d*x, x) def replacement6902(a, b, c, d, p, x): return -Dist(c*p, Int((c*ProductLog(a + b*x))**(p + S(-1))/(d*ProductLog(a + b*x) + d), x), x) + Simp(c*(c*ProductLog(a + b*x))**(p + S(-1))*(a + b*x)/(b*d), x) def replacement6903(a, b, d, x): return Simp(ExpIntegralEi(ProductLog(a + b*x))/(b*d), x) def replacement6904(a, b, c, d, x): return Simp(Erfi(sqrt(c*ProductLog(a + b*x))/Rt(c, S(2)))*Rt(Pi*c, S(2))/(b*c*d), x) def replacement6905(a, b, c, d, x): return Simp(Erf(sqrt(c*ProductLog(a + b*x))/Rt(-c, S(2)))*Rt(-Pi*c, S(2))/(b*c*d), x) def replacement6906(a, b, c, d, p, x): return -Dist(S(1)/(c*(p + S(1))), Int((c*ProductLog(a + b*x))**(p + S(1))/(d*ProductLog(a + b*x) + d), x), x) + Simp((c*ProductLog(a + b*x))**p*(a + b*x)/(b*d*(p + S(1))), x) def replacement6907(a, b, c, d, p, x): return Simp((-ProductLog(a + b*x))**(-p)*(c*ProductLog(a + b*x))**p*Gamma(p + S(1), -ProductLog(a + b*x))/(b*d), x) def replacement6908(a, b, d, m, x): return Dist(S(1)/b, Subst(Int(ExpandIntegrand(S(1)/(d*ProductLog(x) + d), (-a/b + x/b)**m, x), x), x, a + b*x), x) def replacement6909(a, b, c, d, m, p, x): return Dist(S(1)/b, Subst(Int(ExpandIntegrand((c*ProductLog(x))**p/(d*ProductLog(x) + d), (-a/b + x/b)**m, x), x), x, a + b*x), x) def replacement6910(a, d, n, x): return -Subst(Int(S(1)/(x**S(2)*(d*ProductLog(a*x**(-n)) + d)), x), x, S(1)/x) def replacement6911(a, c, d, n, p, x): return Simp(c*x*(c*ProductLog(a*x**n))**(p + S(-1))/d, x) def replacement6912(a, d, n, p, x): return Simp(a**p*ExpIntegralEi(-p*ProductLog(a*x**n))/(d*n), x) def replacement6913(a, c, d, n, p, x): return Simp(a**(-S(1)/n)*c**(-S(1)/n)*Erfi(sqrt(c*ProductLog(a*x**n))/Rt(c*n, S(2)))*Rt(Pi*c*n, S(2))/(d*n), x) def replacement6914(a, c, d, n, p, x): return Simp(a**(-S(1)/n)*c**(-S(1)/n)*Erf(sqrt(c*ProductLog(a*x**n))/Rt(-c*n, S(2)))*Rt(-Pi*c*n, S(2))/(d*n), x) def replacement6915(a, c, d, n, p, x): return -Dist(c*(n*(p + S(-1)) + S(1)), Int((c*ProductLog(a*x**n))**(p + S(-1))/(d*ProductLog(a*x**n) + d), x), x) + Simp(c*x*(c*ProductLog(a*x**n))**(p + S(-1))/d, x) def replacement6916(a, c, d, n, p, x): return -Dist(S(1)/(c*(n*p + S(1))), Int((c*ProductLog(a*x**n))**(p + S(1))/(d*ProductLog(a*x**n) + d), x), x) + Simp(x*(c*ProductLog(a*x**n))**p/(d*(n*p + S(1))), x) def replacement6917(a, c, d, n, p, x): return -Subst(Int((c*ProductLog(a*x**(-n)))**p/(x**S(2)*(d*ProductLog(a*x**(-n)) + d)), x), x, S(1)/x) def replacement6918(a, d, m, x): return -Dist(m/(m + S(1)), Int(x**m/((d*ProductLog(a*x) + d)*ProductLog(a*x)), x), x) + Simp(x**(m + S(1))/(d*(m + S(1))*ProductLog(a*x)), x) def replacement6919(a, d, x): return Simp(log(ProductLog(a*x))/d, x) def replacement6920(a, d, m, x): return -Int(x**m*ProductLog(a*x)/(d*ProductLog(a*x) + d), x) + Simp(x**(m + S(1))/(d*(m + S(1))), x) def replacement6921(a, d, m, x): return Simp(x**m*(-(m + S(1))*ProductLog(a*x))**(-m)*Gamma(m + S(1), -(m + S(1))*ProductLog(a*x))*exp(-m*ProductLog(a*x))/(a*d*(m + S(1))), x) def replacement6922(a, d, n, x): return Simp(log(ProductLog(a*x**n))/(d*n), x) def replacement6923(a, d, m, n, x): return -Subst(Int(x**(-m + S(-2))/(d*ProductLog(a*x**(-n)) + d), x), x, S(1)/x) def replacement6924(a, c, d, n, p, x): return Simp((c*ProductLog(a*x**n))**p/(d*n*p), x) def replacement6925(a, c, d, m, n, p, x): return Simp(c*x**(m + S(1))*(c*ProductLog(a*x**n))**(p + S(-1))/(d*(m + S(1))), x) def replacement6926(a, d, m, n, p, x): return Simp(a**p*ExpIntegralEi(-p*ProductLog(a*x**n))/(d*n), x) def replacement6927(a, c, d, m, n, p, x): return Simp(a**(p + S(-1)/2)*c**(p + S(-1)/2)*Erf(sqrt(c*ProductLog(a*x**n))/Rt(c/(p + S(-1)/2), S(2)))*Rt(Pi*c/(p + S(-1)/2), S(2))/(d*n), x) def replacement6928(a, c, d, m, n, p, x): return Simp(a**(p + S(-1)/2)*c**(p + S(-1)/2)*Erfi(sqrt(c*ProductLog(a*x**n))/Rt(-c/(p + S(-1)/2), S(2)))*Rt(-Pi*c/(p + S(-1)/2), S(2))/(d*n), x) def replacement6929(a, c, d, m, n, p, x): return -Dist(c*(m + n*(p + S(-1)) + S(1))/(m + S(1)), Int(x**m*(c*ProductLog(a*x**n))**(p + S(-1))/(d*ProductLog(a*x**n) + d), x), x) + Simp(c*x**(m + S(1))*(c*ProductLog(a*x**n))**(p + S(-1))/(d*(m + S(1))), x) def replacement6930(a, c, d, m, n, p, x): return -Dist((m + S(1))/(c*(m + n*p + S(1))), Int(x**m*(c*ProductLog(a*x**n))**(p + S(1))/(d*ProductLog(a*x**n) + d), x), x) + Simp(x**(m + S(1))*(c*ProductLog(a*x**n))**p/(d*(m + n*p + S(1))), x) def replacement6931(a, c, d, m, p, x): return Simp(x**m*(c*ProductLog(a*x))**p*(-(m + S(1))*ProductLog(a*x))**(-m - p)*Gamma(m + p + S(1), -(m + S(1))*ProductLog(a*x))*exp(-m*ProductLog(a*x))/(a*d*(m + S(1))), x) def replacement6932(a, c, d, m, n, p, x): return -Subst(Int(x**(-m + S(-2))*(c*ProductLog(a*x**(-n)))**p/(d*ProductLog(a*x**(-n)) + d), x), x, S(1)/x) def replacement6933(u, x): return Subst(Int(SimplifyIntegrand((x + S(1))*SubstFor(ProductLog(x), u, x)*exp(x), x), x), x, ProductLog(x)) sympy-sympy-1.9/sympy/integrals/rubi/rules/tangent.py000066400000000000000000011457601412543434000232170ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def tangent(): from sympy.integrals.rubi.constraints import cons1510, cons2, cons3, cons50, cons127, cons19, cons4, cons1511, cons20, cons25, cons95, cons167, cons96, cons1512, cons1172, cons89, cons1513, cons91, cons168, cons685, cons33, cons268, cons34, cons1514, cons1515, cons21, cons157, cons1252, cons1516, cons1517, cons1518, cons1519, cons1520, cons1521, cons1522, cons1523, cons1524, cons82, cons81, cons1525, cons1526, cons1527, cons1528, cons29, cons5, cons1529, cons8, cons1263, cons1266, cons1441, cons465, cons1442, cons1530, cons1257, cons1531, cons90, cons1532, cons1533, cons1534, cons517, cons1535, cons1536, cons1537, cons1538, cons1539, cons1540, cons68, cons1541, cons86, cons1230, cons150, cons198, cons1542, cons87, cons72, cons1543, cons73, cons1414, cons269, cons1305, cons170, cons1544, cons1545, cons1324, cons1546, cons1325, cons1547, cons1548, cons1549, cons1550, cons79, cons1551, cons1552, cons1553, cons1425, cons1387, cons113, cons274, cons1327, cons1329, cons1336, cons1554, cons1555, cons1335, cons1556, cons1557, cons1338, cons1558, cons1559, cons810, cons382, cons210, cons149, cons1419, cons52, cons40, cons36, cons37, cons348, cons1420, cons1428, cons1560, cons1561, cons1562, cons1258, cons1563, cons38, cons35, cons1435, cons1564, cons1565, cons1566, cons1567, cons1568, cons1569, cons1570, cons1571, cons1494, cons1458, cons1572, cons1483, cons1481, cons745, cons1499, cons48, cons47, cons228, cons1482, cons64, cons530, cons1573, cons1574, cons812, cons813, cons1362, cons1575, cons1497, cons70, cons71, cons825, cons826, cons1576, cons1577, cons1578, cons1579, cons1580, cons1581, cons49, cons241, cons1582 pattern3401 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1510) rule3401 = ReplacementRule(pattern3401, replacement3401) pattern3402 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1510) rule3402 = ReplacementRule(pattern3402, replacement3402) pattern3403 = Pattern(Integral(sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**WC('n', S(1)), x_), cons50, cons127, cons1511) rule3403 = ReplacementRule(pattern3403, replacement3403) pattern3404 = Pattern(Integral((S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons50, cons127, cons1511) rule3404 = ReplacementRule(pattern3404, replacement3404) pattern3405 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons3, cons50, cons127, cons4, cons20, cons25) rule3405 = ReplacementRule(pattern3405, replacement3405) pattern3406 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons3, cons50, cons127, cons4, cons20, cons25) rule3406 = ReplacementRule(pattern3406, replacement3406) pattern3407 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons167, cons96, cons1512, cons1172) rule3407 = ReplacementRule(pattern3407, replacement3407) pattern3408 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons167, cons96, cons1512, cons1172) rule3408 = ReplacementRule(pattern3408, replacement3408) pattern3409 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons167, cons1172, cons1513) rule3409 = ReplacementRule(pattern3409, replacement3409) pattern3410 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons167, cons1172, cons1513) rule3410 = ReplacementRule(pattern3410, replacement3410) pattern3411 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons91, cons168, cons1172) rule3411 = ReplacementRule(pattern3411, replacement3411) pattern3412 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons91, cons168, cons1172) rule3412 = ReplacementRule(pattern3412, replacement3412) pattern3413 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons91, cons685, cons1172) rule3413 = ReplacementRule(pattern3413, replacement3413) pattern3414 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons91, cons685, cons1172) rule3414 = ReplacementRule(pattern3414, replacement3414) pattern3415 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons4, cons33, cons268, cons1172) rule3415 = ReplacementRule(pattern3415, replacement3415) pattern3416 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons4, cons33, cons268, cons1172) rule3416 = ReplacementRule(pattern3416, replacement3416) pattern3417 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons4, cons33, cons34, cons685, cons1172) rule3417 = ReplacementRule(pattern3417, replacement3417) pattern3418 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons4, cons33, cons34, cons685, cons1172) rule3418 = ReplacementRule(pattern3418, replacement3418) pattern3419 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1514) rule3419 = ReplacementRule(pattern3419, replacement3419) pattern3420 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1514) rule3420 = ReplacementRule(pattern3420, replacement3420) pattern3421 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1515) rule3421 = ReplacementRule(pattern3421, replacement3421) pattern3422 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1515) rule3422 = ReplacementRule(pattern3422, replacement3422) pattern3423 = Pattern(Integral((WC('a', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule3423 = ReplacementRule(pattern3423, replacement3423) pattern3424 = Pattern(Integral((WC('a', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule3424 = ReplacementRule(pattern3424, replacement3424) pattern3425 = Pattern(Integral((WC('a', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule3425 = ReplacementRule(pattern3425, replacement3425) pattern3426 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons4, cons157) rule3426 = ReplacementRule(pattern3426, replacement3426) pattern3427 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons4, cons157) rule3427 = ReplacementRule(pattern3427, replacement3427) pattern3428 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1252, cons1516) rule3428 = ReplacementRule(pattern3428, replacement3428) pattern3429 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons50, cons127, cons19, cons1252, cons1516) rule3429 = ReplacementRule(pattern3429, replacement3429) pattern3430 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(S(1)/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons3, cons50, cons127, cons4, cons1517, cons1518) rule3430 = ReplacementRule(pattern3430, replacement3430) pattern3431 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(S(1)/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons3, cons50, cons127, cons4, cons1517, cons1518) rule3431 = ReplacementRule(pattern3431, replacement3431) pattern3432 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons91, cons1519, cons1172) rule3432 = ReplacementRule(pattern3432, replacement3432) pattern3433 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons91, cons1519, cons1172) rule3433 = ReplacementRule(pattern3433, replacement3433) pattern3434 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons91, cons1172) rule3434 = ReplacementRule(pattern3434, replacement3434) pattern3435 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons91, cons1172) rule3435 = ReplacementRule(pattern3435, replacement3435) pattern3436 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons167, cons1520, cons1172) rule3436 = ReplacementRule(pattern3436, replacement3436) pattern3437 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons95, cons167, cons1520, cons1172) rule3437 = ReplacementRule(pattern3437, replacement3437) pattern3438 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons167, cons1521, cons1172) rule3438 = ReplacementRule(pattern3438, replacement3438) pattern3439 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons89, cons167, cons1521, cons1172) rule3439 = ReplacementRule(pattern3439, replacement3439) pattern3440 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons1522, cons1172) rule3440 = ReplacementRule(pattern3440, replacement3440) pattern3441 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons1522, cons1172) rule3441 = ReplacementRule(pattern3441, replacement3441) pattern3442 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons1523, cons1521, cons1172) rule3442 = ReplacementRule(pattern3442, replacement3442) pattern3443 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons4, cons33, cons1523, cons1521, cons1172) rule3443 = ReplacementRule(pattern3443, replacement3443) pattern3444 = Pattern(Integral(S(1)/(sqrt(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons50, cons127, cons1524) rule3444 = ReplacementRule(pattern3444, replacement3444) pattern3445 = Pattern(Integral(S(1)/(sqrt(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons50, cons127, cons1524) rule3445 = ReplacementRule(pattern3445, replacement3445) pattern3446 = Pattern(Integral(sqrt(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons3, cons50, cons127, cons1524) rule3446 = ReplacementRule(pattern3446, replacement3446) pattern3447 = Pattern(Integral(sqrt(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons3, cons50, cons127, cons1524) rule3447 = ReplacementRule(pattern3447, replacement3447) pattern3448 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons82, cons81) rule3448 = ReplacementRule(pattern3448, replacement3448) pattern3449 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons82, cons81) rule3449 = ReplacementRule(pattern3449, replacement3449) pattern3450 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1525, cons1526) rule3450 = ReplacementRule(pattern3450, replacement3450) pattern3451 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons1525, cons1526) rule3451 = ReplacementRule(pattern3451, replacement3451) pattern3452 = Pattern(Integral((WC('a', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule3452 = ReplacementRule(pattern3452, replacement3452) pattern3453 = Pattern(Integral((WC('a', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons50, cons127, cons19, cons4, cons21, cons25) rule3453 = ReplacementRule(pattern3453, replacement3453) pattern3454 = Pattern(Integral(((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons5, cons89, cons167, cons1527, cons1528) rule3454 = ReplacementRule(pattern3454, replacement3454) pattern3455 = Pattern(Integral(((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons5, cons89, cons167, cons1527, cons1528) rule3455 = ReplacementRule(pattern3455, replacement3455) pattern3456 = Pattern(Integral(((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**WC('m', S(1))*(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons5, cons89, cons91, cons1529, cons1528) rule3456 = ReplacementRule(pattern3456, replacement3456) pattern3457 = Pattern(Integral(((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('a', S(1)))**WC('m', S(1))*(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons5, cons89, cons91, cons1529, cons1528) rule3457 = ReplacementRule(pattern3457, replacement3457) pattern3458 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons89, cons167) rule3458 = ReplacementRule(pattern3458, replacement3458) pattern3459 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons89, cons167) rule3459 = ReplacementRule(pattern3459, replacement3459) pattern3460 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons89, cons91) rule3460 = ReplacementRule(pattern3460, replacement3460) pattern3461 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons89, cons91) rule3461 = ReplacementRule(pattern3461, replacement3461) pattern3462 = Pattern(Integral(tan(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons1263) rule3462 = ReplacementRule(pattern3462, replacement3462) pattern3463 = Pattern(Integral(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))), x_), cons8, cons29, cons1263) rule3463 = ReplacementRule(pattern3463, replacement3463) pattern3464 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons4, cons25) rule3464 = ReplacementRule(pattern3464, replacement3464) pattern3465 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons3, cons8, cons29, cons4, cons25) rule3465 = ReplacementRule(pattern3465, replacement3465) pattern3466 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons1266) rule3466 = ReplacementRule(pattern3466, replacement3466) pattern3467 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons1266) rule3467 = ReplacementRule(pattern3467, replacement3467) pattern3468 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1441, cons89, cons167) rule3468 = ReplacementRule(pattern3468, replacement3468) pattern3469 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1441, cons89, cons167) rule3469 = ReplacementRule(pattern3469, replacement3469) pattern3470 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1441, cons89, cons465) rule3470 = ReplacementRule(pattern3470, replacement3470) pattern3471 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1441, cons89, cons465) rule3471 = ReplacementRule(pattern3471, replacement3471) pattern3472 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1441) rule3472 = ReplacementRule(pattern3472, replacement3472) pattern3473 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1441) rule3473 = ReplacementRule(pattern3473, replacement3473) pattern3474 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1441) rule3474 = ReplacementRule(pattern3474, replacement3474) pattern3475 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1441) rule3475 = ReplacementRule(pattern3475, replacement3475) pattern3476 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1442, cons89, cons167) rule3476 = ReplacementRule(pattern3476, replacement3476) pattern3477 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1442, cons89, cons167) rule3477 = ReplacementRule(pattern3477, replacement3477) pattern3478 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1442, cons89, cons91) rule3478 = ReplacementRule(pattern3478, replacement3478) pattern3479 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons1442, cons89, cons91) rule3479 = ReplacementRule(pattern3479, replacement3479) pattern3480 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442) rule3480 = ReplacementRule(pattern3480, replacement3480) pattern3481 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons1442) rule3481 = ReplacementRule(pattern3481, replacement3481) pattern3482 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1442) rule3482 = ReplacementRule(pattern3482, replacement3482) pattern3483 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons4, cons1442) rule3483 = ReplacementRule(pattern3483, replacement3483) pattern3484 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1530) rule3484 = ReplacementRule(pattern3484, replacement3484) pattern3485 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1530) rule3485 = ReplacementRule(pattern3485, replacement3485) pattern3486 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(S(1)/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons4, cons1441, cons1517) rule3486 = ReplacementRule(pattern3486, replacement3486) pattern3487 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(S(1)/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons4, cons1441, cons1517) rule3487 = ReplacementRule(pattern3487, replacement3487) pattern3488 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1257) rule3488 = ReplacementRule(pattern3488, replacement3488) pattern3489 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1257) rule3489 = ReplacementRule(pattern3489, replacement3489) pattern3490 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1441) rule3490 = ReplacementRule(pattern3490, replacement3490) pattern3491 = Pattern(Integral(S(1)/(sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1441) rule3491 = ReplacementRule(pattern3491, replacement3491) pattern3492 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons1531, cons95, cons90) rule3492 = ReplacementRule(pattern3492, replacement3492) pattern3493 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons1531, cons95, cons90) rule3493 = ReplacementRule(pattern3493, replacement3493) pattern3494 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons1531, cons95, cons91) rule3494 = ReplacementRule(pattern3494, replacement3494) pattern3495 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons1531, cons95, cons91) rule3495 = ReplacementRule(pattern3495, replacement3495) pattern3496 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1531) rule3496 = ReplacementRule(pattern3496, replacement3496) pattern3497 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1531) rule3497 = ReplacementRule(pattern3497, replacement3497) pattern3498 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1532) rule3498 = ReplacementRule(pattern3498, replacement3498) pattern3499 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1532) rule3499 = ReplacementRule(pattern3499, replacement3499) pattern3500 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1533, cons25) rule3500 = ReplacementRule(pattern3500, replacement3500) pattern3501 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1533, cons25) rule3501 = ReplacementRule(pattern3501, replacement3501) pattern3502 = Pattern(Integral(sqrt(WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3502 = ReplacementRule(pattern3502, replacement3502) pattern3503 = Pattern(Integral(sqrt(WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3503 = ReplacementRule(pattern3503, replacement3503) pattern3504 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons95, cons167, cons1534, cons517) rule3504 = ReplacementRule(pattern3504, replacement3504) pattern3505 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons95, cons167, cons1535, cons517) rule3505 = ReplacementRule(pattern3505, replacement3505) pattern3506 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons95, cons90, cons96, cons1172) rule3506 = ReplacementRule(pattern3506, replacement3506) pattern3507 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons95, cons90, cons96, cons1172) rule3507 = ReplacementRule(pattern3507, replacement3507) pattern3508 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1441, cons89, cons90, cons1521, cons1172) rule3508 = ReplacementRule(pattern3508, replacement3508) pattern3509 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1441, cons89, cons90, cons1521, cons1172) rule3509 = ReplacementRule(pattern3509, replacement3509) pattern3510 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3510 = ReplacementRule(pattern3510, replacement3510) pattern3511 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3511 = ReplacementRule(pattern3511, replacement3511) pattern3512 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1441, cons89, cons91, cons1536, cons517) rule3512 = ReplacementRule(pattern3512, replacement3512) pattern3513 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1441, cons89, cons91, cons1536, cons517) rule3513 = ReplacementRule(pattern3513, replacement3513) pattern3514 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons95, cons465, cons168, cons1537, cons1521, cons1172) rule3514 = ReplacementRule(pattern3514, replacement3514) pattern3515 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons1441, cons95, cons465, cons168, cons1537, cons1521, cons1172) rule3515 = ReplacementRule(pattern3515, replacement3515) pattern3516 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1441, cons89, cons465, cons1538, cons1172) rule3516 = ReplacementRule(pattern3516, replacement3516) pattern3517 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1441, cons89, cons465, cons1538, cons1172) rule3517 = ReplacementRule(pattern3517, replacement3517) pattern3518 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1539, cons89) rule3518 = ReplacementRule(pattern3518, replacement3518) pattern3519 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1539, cons89) rule3519 = ReplacementRule(pattern3519, replacement3519) pattern3520 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1540, cons1538) rule3520 = ReplacementRule(pattern3520, replacement3520) pattern3521 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441, cons1540, cons1538) rule3521 = ReplacementRule(pattern3521, replacement3521) pattern3522 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441) rule3522 = ReplacementRule(pattern3522, replacement3522) pattern3523 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1441) rule3523 = ReplacementRule(pattern3523, replacement3523) pattern3524 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(S(1)/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons4, cons1442, cons1517) rule3524 = ReplacementRule(pattern3524, replacement3524) pattern3525 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(S(1)/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons4, cons1442, cons1517) rule3525 = ReplacementRule(pattern3525, replacement3525) pattern3526 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2)*cos(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1442) rule3526 = ReplacementRule(pattern3526, replacement3526) pattern3527 = Pattern(Integral((a_ + WC('b', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**S(2)*tan(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons2, cons3, cons50, cons127, cons1442) rule3527 = ReplacementRule(pattern3527, replacement3527) pattern3528 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1442, cons68) rule3528 = ReplacementRule(pattern3528, replacement3528) pattern3529 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons1442, cons68) rule3529 = ReplacementRule(pattern3529, replacement3529) pattern3530 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1442) rule3530 = ReplacementRule(pattern3530, replacement3530) pattern3531 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons1442) rule3531 = ReplacementRule(pattern3531, replacement3531) pattern3532 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1442, cons1541) rule3532 = ReplacementRule(pattern3532, replacement3532) pattern3533 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1442, cons1541) rule3533 = ReplacementRule(pattern3533, replacement3533) pattern3534 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1442, cons86) rule3534 = ReplacementRule(pattern3534, replacement3534) pattern3535 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1442, cons86) rule3535 = ReplacementRule(pattern3535, replacement3535) pattern3536 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1442, cons1526) rule3536 = ReplacementRule(pattern3536, replacement3536) pattern3537 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons1442, cons1526) rule3537 = ReplacementRule(pattern3537, replacement3537) pattern3538 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3538 = ReplacementRule(pattern3538, replacement3538) pattern3539 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3539 = ReplacementRule(pattern3539, replacement3539) pattern3540 = Pattern(Integral(S(1)/((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3540 = ReplacementRule(pattern3540, replacement3540) pattern3541 = Pattern(Integral(S(1)/((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)*sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons29, cons50, cons127, cons1441) rule3541 = ReplacementRule(pattern3541, replacement3541) pattern3542 = Pattern(Integral((WC('d', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons21) rule3542 = ReplacementRule(pattern3542, replacement3542) pattern3543 = Pattern(Integral((WC('d', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons21) rule3543 = ReplacementRule(pattern3543, replacement3543) pattern3544 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*sin(x_*WC('f', S(1)) + WC('e', S(0)))**m_, x_), cons2, cons3, cons50, cons127, cons4, cons1517) rule3544 = ReplacementRule(pattern3544, replacement3544) pattern3545 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*cos(x_*WC('f', S(1)) + WC('e', S(0)))**m_, x_), cons2, cons3, cons50, cons127, cons4, cons1517) rule3545 = ReplacementRule(pattern3545, replacement3545) pattern3546 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons1230, cons150) rule3546 = ReplacementRule(pattern3546, replacement3546) pattern3547 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons1230, cons150) rule3547 = ReplacementRule(pattern3547, replacement3547) pattern3548 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons1230, cons198, cons1542) rule3548 = ReplacementRule(pattern3548, replacement3548) pattern3549 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons1230, cons198, cons1542) rule3549 = ReplacementRule(pattern3549, replacement3549) pattern3550 = Pattern(Integral((WC('d', S(1))/sin(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons21) rule3550 = ReplacementRule(pattern3550, replacement3550) pattern3551 = Pattern(Integral((WC('d', S(1))/cos(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons19, cons4, cons21) rule3551 = ReplacementRule(pattern3551, replacement3551) pattern3552 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons5, cons87) rule3552 = ReplacementRule(pattern3552, replacement3552) pattern3553 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*sin(x_*WC('f', S(1)) + WC('e', S(0)))**WC('m', S(1))*cos(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons50, cons127, cons19, cons5, cons87) rule3553 = ReplacementRule(pattern3553, replacement3553) pattern3554 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1441, cons20, cons1543) rule3554 = ReplacementRule(pattern3554, replacement3554) pattern3555 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons72, cons1441, cons20, cons1543) rule3555 = ReplacementRule(pattern3555, replacement3555) pattern3556 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1441) rule3556 = ReplacementRule(pattern3556, replacement3556) pattern3557 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons72, cons1441) rule3557 = ReplacementRule(pattern3557, replacement3557) pattern3558 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons72) rule3558 = ReplacementRule(pattern3558, replacement3558) pattern3559 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons72) rule3559 = ReplacementRule(pattern3559, replacement3559) pattern3560 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1414) rule3560 = ReplacementRule(pattern3560, replacement3560) pattern3561 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1414) rule3561 = ReplacementRule(pattern3561, replacement3561) pattern3562 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons33, cons269) rule3562 = ReplacementRule(pattern3562, replacement3562) pattern3563 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons33, cons269) rule3563 = ReplacementRule(pattern3563, replacement3563) pattern3564 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1305) rule3564 = ReplacementRule(pattern3564, replacement3564) pattern3565 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1305) rule3565 = ReplacementRule(pattern3565, replacement3565) pattern3566 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons33, cons170) rule3566 = ReplacementRule(pattern3566, replacement3566) pattern3567 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons33, cons170) rule3567 = ReplacementRule(pattern3567, replacement3567) pattern3568 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons33, cons96) rule3568 = ReplacementRule(pattern3568, replacement3568) pattern3569 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons33, cons96) rule3569 = ReplacementRule(pattern3569, replacement3569) pattern3570 = Pattern(Integral((c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1544) rule3570 = ReplacementRule(pattern3570, replacement3570) pattern3571 = Pattern(Integral((c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1544) rule3571 = ReplacementRule(pattern3571, replacement3571) pattern3572 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1545) rule3572 = ReplacementRule(pattern3572, replacement3572) pattern3573 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1545) rule3573 = ReplacementRule(pattern3573, replacement3573) pattern3574 = Pattern(Integral((c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1324) rule3574 = ReplacementRule(pattern3574, replacement3574) pattern3575 = Pattern(Integral((c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1324) rule3575 = ReplacementRule(pattern3575, replacement3575) pattern3576 = Pattern(Integral((c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1546) rule3576 = ReplacementRule(pattern3576, replacement3576) pattern3577 = Pattern(Integral((c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1546) rule3577 = ReplacementRule(pattern3577, replacement3577) pattern3578 = Pattern(Integral((c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1325, cons1547) rule3578 = ReplacementRule(pattern3578, replacement3578) pattern3579 = Pattern(Integral((c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons1325, cons1547) rule3579 = ReplacementRule(pattern3579, replacement3579) pattern3580 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons1548) rule3580 = ReplacementRule(pattern3580, replacement3580) pattern3581 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons1548) rule3581 = ReplacementRule(pattern3581, replacement3581) pattern3582 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons1549, cons1550) rule3582 = ReplacementRule(pattern3582, With3582) pattern3583 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons1549, cons1550) rule3583 = ReplacementRule(pattern3583, With3583) pattern3584 = Pattern(Integral((c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1442, cons1546) rule3584 = ReplacementRule(pattern3584, replacement3584) pattern3585 = Pattern(Integral((c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1442, cons1546) rule3585 = ReplacementRule(pattern3585, replacement3585) pattern3586 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons1547, cons79) rule3586 = ReplacementRule(pattern3586, replacement3586) pattern3587 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons3, cons8, cons29, cons50, cons127, cons19, cons1547, cons79) rule3587 = ReplacementRule(pattern3587, replacement3587) pattern3588 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1442, cons1547, cons21) rule3588 = ReplacementRule(pattern3588, replacement3588) pattern3589 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1442, cons1547, cons21) rule3589 = ReplacementRule(pattern3589, replacement3589) pattern3590 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons34, cons1441) rule3590 = ReplacementRule(pattern3590, replacement3590) pattern3591 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons34, cons1441) rule3591 = ReplacementRule(pattern3591, replacement3591) pattern3592 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2)/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442) rule3592 = ReplacementRule(pattern3592, replacement3592) pattern3593 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2)/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442) rule3593 = ReplacementRule(pattern3593, replacement3593) pattern3594 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons96, cons1442) rule3594 = ReplacementRule(pattern3594, replacement3594) pattern3595 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons33, cons96, cons1442) rule3595 = ReplacementRule(pattern3595, replacement3595) pattern3596 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1551, cons1552) rule3596 = ReplacementRule(pattern3596, replacement3596) pattern3597 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1551, cons1552) rule3597 = ReplacementRule(pattern3597, replacement3597) pattern3598 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3598 = ReplacementRule(pattern3598, replacement3598) pattern3599 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3599 = ReplacementRule(pattern3599, replacement3599) pattern3600 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons1553, cons1425) rule3600 = ReplacementRule(pattern3600, replacement3600) pattern3601 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons1553, cons1425) rule3601 = ReplacementRule(pattern3601, replacement3601) pattern3602 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons1553, cons1387) rule3602 = ReplacementRule(pattern3602, replacement3602) pattern3603 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons1553, cons1387) rule3603 = ReplacementRule(pattern3603, replacement3603) pattern3604 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons113, cons96) rule3604 = ReplacementRule(pattern3604, replacement3604) pattern3605 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons113, cons96) rule3605 = ReplacementRule(pattern3605, replacement3605) pattern3606 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1441, cons1547, cons157, cons274) rule3606 = ReplacementRule(pattern3606, replacement3606) pattern3607 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1441, cons1547, cons157, cons274) rule3607 = ReplacementRule(pattern3607, replacement3607) pattern3608 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons89, cons1327) rule3608 = ReplacementRule(pattern3608, replacement3608) pattern3609 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons89, cons1327) rule3609 = ReplacementRule(pattern3609, replacement3609) pattern3610 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons89, cons167) rule3610 = ReplacementRule(pattern3610, replacement3610) pattern3611 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons89, cons167) rule3611 = ReplacementRule(pattern3611, replacement3611) pattern3612 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3612 = ReplacementRule(pattern3612, replacement3612) pattern3613 = Pattern(Integral(S(1)/((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3613 = ReplacementRule(pattern3613, replacement3613) pattern3614 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1441, cons1547, cons1329) rule3614 = ReplacementRule(pattern3614, replacement3614) pattern3615 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1441, cons1547, cons1329) rule3615 = ReplacementRule(pattern3615, replacement3615) pattern3616 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons168, cons91, cons1336) rule3616 = ReplacementRule(pattern3616, replacement3616) pattern3617 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons168, cons91, cons1336) rule3617 = ReplacementRule(pattern3617, replacement3617) pattern3618 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3618 = ReplacementRule(pattern3618, replacement3618) pattern3619 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3619 = ReplacementRule(pattern3619, replacement3619) pattern3620 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3620 = ReplacementRule(pattern3620, replacement3620) pattern3621 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/sqrt(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3621 = ReplacementRule(pattern3621, replacement3621) pattern3622 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1441, cons1547, cons517, cons168, cons1521, cons1336) rule3622 = ReplacementRule(pattern3622, replacement3622) pattern3623 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1441, cons1547, cons517, cons168, cons1521, cons1336) rule3623 = ReplacementRule(pattern3623, replacement3623) pattern3624 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sqrt(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons33, cons269, cons1554) rule3624 = ReplacementRule(pattern3624, replacement3624) pattern3625 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*sqrt(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons33, cons269, cons1554) rule3625 = ReplacementRule(pattern3625, replacement3625) pattern3626 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons269, cons167, cons1336) rule3626 = ReplacementRule(pattern3626, replacement3626) pattern3627 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547, cons95, cons269, cons167, cons1336) rule3627 = ReplacementRule(pattern3627, replacement3627) pattern3628 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1441, cons1547, cons33, cons269, cons1336) rule3628 = ReplacementRule(pattern3628, replacement3628) pattern3629 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1441, cons1547, cons33, cons269, cons1336) rule3629 = ReplacementRule(pattern3629, replacement3629) pattern3630 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1547, cons89, cons167, cons1521, cons1555) rule3630 = ReplacementRule(pattern3630, replacement3630) pattern3631 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1547, cons89, cons167, cons1521, cons1555) rule3631 = ReplacementRule(pattern3631, replacement3631) pattern3632 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1547, cons89, cons91, cons1555) rule3632 = ReplacementRule(pattern3632, replacement3632) pattern3633 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1547, cons89, cons91, cons1555) rule3633 = ReplacementRule(pattern3633, replacement3633) pattern3634 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1547) rule3634 = ReplacementRule(pattern3634, replacement3634) pattern3635 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1441, cons1547) rule3635 = ReplacementRule(pattern3635, replacement3635) pattern3636 = Pattern(Integral(sqrt(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3636 = ReplacementRule(pattern3636, replacement3636) pattern3637 = Pattern(Integral(sqrt(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1441, cons1547) rule3637 = ReplacementRule(pattern3637, replacement3637) pattern3638 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1441, cons1547) rule3638 = ReplacementRule(pattern3638, replacement3638) pattern3639 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1441, cons1547) rule3639 = ReplacementRule(pattern3639, replacement3639) pattern3640 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons1335, cons91, cons517) rule3640 = ReplacementRule(pattern3640, replacement3640) pattern3641 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons1335, cons91, cons517) rule3641 = ReplacementRule(pattern3641, replacement3641) pattern3642 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1442, cons1547, cons517, cons1335, cons1556, cons1557) rule3642 = ReplacementRule(pattern3642, replacement3642) pattern3643 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1442, cons1547, cons517, cons1335, cons1556, cons1557) rule3643 = ReplacementRule(pattern3643, replacement3643) pattern3644 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons96, cons1338, cons517) rule3644 = ReplacementRule(pattern3644, replacement3644) pattern3645 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons96, cons1338, cons517) rule3645 = ReplacementRule(pattern3645, replacement3645) pattern3646 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons96, cons90, cons517) rule3646 = ReplacementRule(pattern3646, replacement3646) pattern3647 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons96, cons90, cons517) rule3647 = ReplacementRule(pattern3647, replacement3647) pattern3648 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1442, cons1547, cons517, cons96, cons1558, cons1559) rule3648 = ReplacementRule(pattern3648, replacement3648) pattern3649 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons73, cons1442, cons1547, cons517, cons96, cons1558, cons1559) rule3649 = ReplacementRule(pattern3649, replacement3649) pattern3650 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons168, cons90, cons810) rule3650 = ReplacementRule(pattern3650, replacement3650) pattern3651 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547, cons95, cons168, cons90, cons810) rule3651 = ReplacementRule(pattern3651, replacement3651) pattern3652 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547) rule3652 = ReplacementRule(pattern3652, replacement3652) pattern3653 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547) rule3653 = ReplacementRule(pattern3653, replacement3653) pattern3654 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons73, cons1442, cons1547) rule3654 = ReplacementRule(pattern3654, replacement3654) pattern3655 = Pattern(Integral(sqrt(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons73, cons1442, cons1547) rule3655 = ReplacementRule(pattern3655, replacement3655) pattern3656 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547) rule3656 = ReplacementRule(pattern3656, replacement3656) pattern3657 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**(S(3)/2)/(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons73, cons1442, cons1547) rule3657 = ReplacementRule(pattern3657, replacement3657) pattern3658 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1442, cons1547, cons21) rule3658 = ReplacementRule(pattern3658, replacement3658) pattern3659 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_/(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons73, cons1442, cons1547, cons21) rule3659 = ReplacementRule(pattern3659, replacement3659) pattern3660 = Pattern(Integral((c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1442, cons1547) rule3660 = ReplacementRule(pattern3660, replacement3660) pattern3661 = Pattern(Integral((c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons73, cons1442, cons1547) rule3661 = ReplacementRule(pattern3661, replacement3661) pattern3662 = Pattern(Integral((WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons25, cons20) rule3662 = ReplacementRule(pattern3662, replacement3662) pattern3663 = Pattern(Integral((WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons29, cons50, cons127, cons4, cons25, cons20) rule3663 = ReplacementRule(pattern3663, replacement3663) pattern3664 = Pattern(Integral(((WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons25, cons21) rule3664 = ReplacementRule(pattern3664, replacement3664) pattern3665 = Pattern(Integral(((WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*WC('c', S(1)))**n_*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons25, cons21) rule3665 = ReplacementRule(pattern3665, replacement3665) pattern3666 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons382) rule3666 = ReplacementRule(pattern3666, replacement3666) pattern3667 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons382) rule3667 = ReplacementRule(pattern3667, replacement3667) pattern3668 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons149, cons20, cons87) rule3668 = ReplacementRule(pattern3668, replacement3668) pattern3669 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons5, cons149, cons20, cons87) rule3669 = ReplacementRule(pattern3669, replacement3669) pattern3670 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**q_)**p_*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons149, cons1419) rule3670 = ReplacementRule(pattern3670, replacement3670) pattern3671 = Pattern(Integral(((S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**q_*WC('g', S(1)))**p_*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons52, cons149, cons1419) rule3671 = ReplacementRule(pattern3671, replacement3671) pattern3672 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons87) rule3672 = ReplacementRule(pattern3672, replacement3672) pattern3673 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons5, cons87) rule3673 = ReplacementRule(pattern3673, replacement3673) pattern3674 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*tan(x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons25, cons20, cons40) rule3674 = ReplacementRule(pattern3674, replacement3674) pattern3675 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(S(1)/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons25, cons20, cons40) rule3675 = ReplacementRule(pattern3675, replacement3675) pattern3676 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons25, cons20, cons149) rule3676 = ReplacementRule(pattern3676, replacement3676) pattern3677 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**p_*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons25, cons20, cons149) rule3677 = ReplacementRule(pattern3677, replacement3677) pattern3678 = Pattern(Integral((WC('g', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons25, cons21) rule3678 = ReplacementRule(pattern3678, replacement3678) pattern3679 = Pattern(Integral((WC('g', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('p', S(1))*(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons19, cons4, cons5, cons25, cons21) rule3679 = ReplacementRule(pattern3679, replacement3679) pattern3680 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1441) rule3680 = ReplacementRule(pattern3680, replacement3680) pattern3681 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(c_ + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons72, cons1441) rule3681 = ReplacementRule(pattern3681, replacement3681) pattern3682 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73) rule3682 = ReplacementRule(pattern3682, replacement3682) pattern3683 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73) rule3683 = ReplacementRule(pattern3683, replacement3683) pattern3684 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons33, cons96, cons1441) rule3684 = ReplacementRule(pattern3684, replacement3684) pattern3685 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons33, cons96, cons1441) rule3685 = ReplacementRule(pattern3685, replacement3685) pattern3686 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons33, cons96, cons1442) rule3686 = ReplacementRule(pattern3686, replacement3686) pattern3687 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons33, cons96, cons1442) rule3687 = ReplacementRule(pattern3687, replacement3687) pattern3688 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1551) rule3688 = ReplacementRule(pattern3688, replacement3688) pattern3689 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1551) rule3689 = ReplacementRule(pattern3689, replacement3689) pattern3690 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1441, cons95, cons168, cons91) rule3690 = ReplacementRule(pattern3690, replacement3690) pattern3691 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1441, cons95, cons168, cons91) rule3691 = ReplacementRule(pattern3691, replacement3691) pattern3692 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1441, cons33, cons168, cons348) rule3692 = ReplacementRule(pattern3692, replacement3692) pattern3693 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1441, cons33, cons168, cons348) rule3693 = ReplacementRule(pattern3693, replacement3693) pattern3694 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1441, cons95, cons269, cons90) rule3694 = ReplacementRule(pattern3694, replacement3694) pattern3695 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1441, cons95, cons269, cons90) rule3695 = ReplacementRule(pattern3695, replacement3695) pattern3696 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1441, cons33, cons269, cons1329) rule3696 = ReplacementRule(pattern3696, replacement3696) pattern3697 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1441, cons33, cons269, cons1329) rule3697 = ReplacementRule(pattern3697, replacement3697) pattern3698 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1441, cons89, cons90) rule3698 = ReplacementRule(pattern3698, replacement3698) pattern3699 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1441, cons89, cons90) rule3699 = ReplacementRule(pattern3699, replacement3699) pattern3700 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1441, cons89, cons91) rule3700 = ReplacementRule(pattern3700, replacement3700) pattern3701 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1441, cons89, cons91) rule3701 = ReplacementRule(pattern3701, replacement3701) pattern3702 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1441, cons1420) rule3702 = ReplacementRule(pattern3702, replacement3702) pattern3703 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1441, cons1420) rule3703 = ReplacementRule(pattern3703, replacement3703) pattern3704 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1441, cons1428) rule3704 = ReplacementRule(pattern3704, replacement3704) pattern3705 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons73, cons1441, cons1428) rule3705 = ReplacementRule(pattern3705, replacement3705) pattern3706 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1441, cons1428) rule3706 = ReplacementRule(pattern3706, replacement3706) pattern3707 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1441, cons1428) rule3707 = ReplacementRule(pattern3707, replacement3707) pattern3708 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons21, cons25, cons1515, cons1560) rule3708 = ReplacementRule(pattern3708, replacement3708) pattern3709 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons21, cons25, cons1515, cons1560) rule3709 = ReplacementRule(pattern3709, replacement3709) pattern3710 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons21, cons25, cons1515, cons1561) rule3710 = ReplacementRule(pattern3710, replacement3710) pattern3711 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons21, cons25, cons1515, cons1561) rule3711 = ReplacementRule(pattern3711, replacement3711) pattern3712 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547, cons95, cons168, cons91, cons1336) rule3712 = ReplacementRule(pattern3712, replacement3712) pattern3713 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547, cons95, cons168, cons91, cons1336) rule3713 = ReplacementRule(pattern3713, replacement3713) pattern3714 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1442, cons1547, cons33, cons168, cons1336, cons1562) rule3714 = ReplacementRule(pattern3714, replacement3714) pattern3715 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1442, cons1547, cons33, cons168, cons1336, cons1562) rule3715 = ReplacementRule(pattern3715, replacement3715) pattern3716 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547, cons95, cons96, cons1327, cons1336) rule3716 = ReplacementRule(pattern3716, replacement3716) pattern3717 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547, cons95, cons96, cons1327, cons1336) rule3717 = ReplacementRule(pattern3717, replacement3717) pattern3718 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1442, cons1547, cons33, cons96, cons1336, cons1559) rule3718 = ReplacementRule(pattern3718, replacement3718) pattern3719 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1442, cons1547, cons33, cons96, cons1336, cons1559) rule3719 = ReplacementRule(pattern3719, replacement3719) pattern3720 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547, cons95, cons1258, cons1327) rule3720 = ReplacementRule(pattern3720, replacement3720) pattern3721 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547, cons95, cons1258, cons1327) rule3721 = ReplacementRule(pattern3721, replacement3721) pattern3722 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547) rule3722 = ReplacementRule(pattern3722, replacement3722) pattern3723 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547) rule3723 = ReplacementRule(pattern3723, replacement3723) pattern3724 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547) rule3724 = ReplacementRule(pattern3724, replacement3724) pattern3725 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547) rule3725 = ReplacementRule(pattern3725, replacement3725) pattern3726 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1442, cons1547) rule3726 = ReplacementRule(pattern3726, replacement3726) pattern3727 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons4, cons73, cons1442, cons1547) rule3727 = ReplacementRule(pattern3727, replacement3727) pattern3728 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547) rule3728 = ReplacementRule(pattern3728, replacement3728) pattern3729 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*sqrt(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))/sqrt(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons73, cons1442, cons1547) rule3729 = ReplacementRule(pattern3729, replacement3729) pattern3730 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons1560) rule3730 = ReplacementRule(pattern3730, replacement3730) pattern3731 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons1560) rule3731 = ReplacementRule(pattern3731, replacement3731) pattern3732 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons1561) rule3732 = ReplacementRule(pattern3732, replacement3732) pattern3733 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons19, cons4, cons73, cons1442, cons1561) rule3733 = ReplacementRule(pattern3733, replacement3733) pattern3734 = Pattern(Integral((A_ + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1563) rule3734 = ReplacementRule(pattern3734, replacement3734) pattern3735 = Pattern(Integral((A_ + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1563) rule3735 = ReplacementRule(pattern3735, replacement3735) pattern3736 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons35) rule3736 = ReplacementRule(pattern3736, replacement3736) pattern3737 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons35) rule3737 = ReplacementRule(pattern3737, replacement3737) pattern3738 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1435) rule3738 = ReplacementRule(pattern3738, replacement3738) pattern3739 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1435) rule3739 = ReplacementRule(pattern3739, replacement3739) pattern3740 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1564, cons33, cons34, cons1441) rule3740 = ReplacementRule(pattern3740, replacement3740) pattern3741 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1564, cons33, cons34, cons1441) rule3741 = ReplacementRule(pattern3741, replacement3741) pattern3742 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1565, cons33, cons34, cons1441) rule3742 = ReplacementRule(pattern3742, replacement3742) pattern3743 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1565, cons33, cons34, cons1441) rule3743 = ReplacementRule(pattern3743, replacement3743) pattern3744 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1442, cons1566) rule3744 = ReplacementRule(pattern3744, replacement3744) pattern3745 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1442, cons1566) rule3745 = ReplacementRule(pattern3745, replacement3745) pattern3746 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/tan(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons50, cons127, cons36, cons37, cons38, cons1567) rule3746 = ReplacementRule(pattern3746, replacement3746) pattern3747 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*tan(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons50, cons127, cons36, cons37, cons38, cons1567) rule3747 = ReplacementRule(pattern3747, replacement3747) pattern3748 = Pattern(Integral((A_ + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/tan(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons50, cons127, cons36, cons38, cons1567) rule3748 = ReplacementRule(pattern3748, replacement3748) pattern3749 = Pattern(Integral((A_ + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*tan(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons50, cons127, cons36, cons38, cons1567) rule3749 = ReplacementRule(pattern3749, replacement3749) pattern3750 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1564, cons1442, cons1568) rule3750 = ReplacementRule(pattern3750, replacement3750) pattern3751 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1564, cons1442, cons1568) rule3751 = ReplacementRule(pattern3751, replacement3751) pattern3752 = Pattern(Integral((A_ + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1565, cons1442, cons1567) rule3752 = ReplacementRule(pattern3752, replacement3752) pattern3753 = Pattern(Integral((A_ + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1565, cons1442, cons1567) rule3753 = ReplacementRule(pattern3753, replacement3753) pattern3754 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1564, cons33, cons96, cons1442) rule3754 = ReplacementRule(pattern3754, replacement3754) pattern3755 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons1564, cons33, cons96, cons1442) rule3755 = ReplacementRule(pattern3755, replacement3755) pattern3756 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1565, cons33, cons96, cons1442) rule3756 = ReplacementRule(pattern3756, replacement3756) pattern3757 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_, x_), cons2, cons3, cons50, cons127, cons36, cons38, cons1565, cons33, cons96, cons1442) rule3757 = ReplacementRule(pattern3757, replacement3757) pattern3758 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1564, cons1551) rule3758 = ReplacementRule(pattern3758, replacement3758) pattern3759 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons50, cons127, cons36, cons37, cons38, cons19, cons1564, cons1551) rule3759 = ReplacementRule(pattern3759, replacement3759) pattern3760 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1565, cons1551) rule3760 = ReplacementRule(pattern3760, replacement3760) pattern3761 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons50, cons127, cons36, cons38, cons19, cons1565, cons1551) rule3761 = ReplacementRule(pattern3761, replacement3761) pattern3762 = Pattern(Integral((A_ + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons1563) rule3762 = ReplacementRule(pattern3762, replacement3762) pattern3763 = Pattern(Integral((A_ + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons1563) rule3763 = ReplacementRule(pattern3763, replacement3763) pattern3764 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1547, cons89, cons91) rule3764 = ReplacementRule(pattern3764, replacement3764) pattern3765 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1547, cons89, cons91) rule3765 = ReplacementRule(pattern3765, replacement3765) pattern3766 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1547, cons89, cons91) rule3766 = ReplacementRule(pattern3766, replacement3766) pattern3767 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1547, cons89, cons91) rule3767 = ReplacementRule(pattern3767, replacement3767) pattern3768 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1547, cons348) rule3768 = ReplacementRule(pattern3768, replacement3768) pattern3769 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1547, cons348) rule3769 = ReplacementRule(pattern3769, replacement3769) pattern3770 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1547, cons348) rule3770 = ReplacementRule(pattern3770, replacement3770) pattern3771 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1547, cons348) rule3771 = ReplacementRule(pattern3771, replacement3771) pattern3772 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1441, cons1569) rule3772 = ReplacementRule(pattern3772, replacement3772) pattern3773 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1441, cons1569) rule3773 = ReplacementRule(pattern3773, replacement3773) pattern3774 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1441, cons1569) rule3774 = ReplacementRule(pattern3774, replacement3774) pattern3775 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1441, cons1569) rule3775 = ReplacementRule(pattern3775, replacement3775) pattern3776 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons73, cons1441, cons1305, cons89, cons91, cons1547) rule3776 = ReplacementRule(pattern3776, replacement3776) pattern3777 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons73, cons1441, cons1305, cons89, cons91, cons1547) rule3777 = ReplacementRule(pattern3777, replacement3777) pattern3778 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons73, cons1441, cons1305, cons89, cons91, cons1547) rule3778 = ReplacementRule(pattern3778, replacement3778) pattern3779 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons73, cons1441, cons1305, cons89, cons91, cons1547) rule3779 = ReplacementRule(pattern3779, replacement3779) pattern3780 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1441, cons1305, cons685) rule3780 = ReplacementRule(pattern3780, replacement3780) pattern3781 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1441, cons1305, cons685) rule3781 = ReplacementRule(pattern3781, replacement3781) pattern3782 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1441, cons1305, cons685) rule3782 = ReplacementRule(pattern3782, replacement3782) pattern3783 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1441, cons1305, cons685) rule3783 = ReplacementRule(pattern3783, replacement3783) pattern3784 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1442, cons1547, cons95, cons170, cons91) rule3784 = ReplacementRule(pattern3784, replacement3784) pattern3785 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1442, cons1547, cons95, cons170, cons91) rule3785 = ReplacementRule(pattern3785, replacement3785) pattern3786 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1442, cons1547, cons95, cons170, cons91) rule3786 = ReplacementRule(pattern3786, replacement3786) pattern3787 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1442, cons1547, cons95, cons170, cons91) rule3787 = ReplacementRule(pattern3787, replacement3787) pattern3788 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1442, cons1547, cons33, cons170, cons1570) rule3788 = ReplacementRule(pattern3788, replacement3788) pattern3789 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1442, cons1547, cons33, cons170, cons1570) rule3789 = ReplacementRule(pattern3789, replacement3789) pattern3790 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1442, cons1547, cons33, cons170, cons1570) rule3790 = ReplacementRule(pattern3790, replacement3790) pattern3791 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('m', S(1))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1442, cons1547, cons33, cons170, cons1570) rule3791 = ReplacementRule(pattern3791, replacement3791) pattern3792 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1442, cons1547, cons33, cons96, cons1559) rule3792 = ReplacementRule(pattern3792, replacement3792) pattern3793 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1442, cons1547, cons33, cons96, cons1559) rule3793 = ReplacementRule(pattern3793, replacement3793) pattern3794 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1442, cons1547, cons33, cons96, cons1559) rule3794 = ReplacementRule(pattern3794, replacement3794) pattern3795 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1442, cons1547, cons33, cons96, cons1559) rule3795 = ReplacementRule(pattern3795, replacement3795) pattern3796 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1442, cons1547) rule3796 = ReplacementRule(pattern3796, replacement3796) pattern3797 = Pattern(Integral((WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons73, cons1442, cons1547) rule3797 = ReplacementRule(pattern3797, replacement3797) pattern3798 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1442, cons1547) rule3798 = ReplacementRule(pattern3798, replacement3798) pattern3799 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons73, cons1442, cons1547) rule3799 = ReplacementRule(pattern3799, replacement3799) pattern3800 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1442, cons1547, cons1329, cons1571) rule3800 = ReplacementRule(pattern3800, replacement3800) pattern3801 = Pattern(Integral((WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons4, cons73, cons1442, cons1547, cons1329, cons1571) rule3801 = ReplacementRule(pattern3801, replacement3801) pattern3802 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1442, cons1547, cons1329, cons1571) rule3802 = ReplacementRule(pattern3802, replacement3802) pattern3803 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons4, cons73, cons1442, cons1547, cons1329, cons1571) rule3803 = ReplacementRule(pattern3803, replacement3803) pattern3804 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1442, cons1547) rule3804 = ReplacementRule(pattern3804, replacement3804) pattern3805 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(WC('A', S(0)) + WC('B', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons37, cons38, cons19, cons4, cons73, cons1442, cons1547) rule3805 = ReplacementRule(pattern3805, replacement3805) pattern3806 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1442, cons1547) rule3806 = ReplacementRule(pattern3806, replacement3806) pattern3807 = Pattern(Integral((WC('A', S(0)) + WC('C', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))**S(2))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**m_*(WC('c', S(0)) + WC('d', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons36, cons38, cons19, cons4, cons73, cons1442, cons1547) rule3807 = ReplacementRule(pattern3807, replacement3807) pattern3808 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons1494) rule3808 = ReplacementRule(pattern3808, replacement3808) pattern3809 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons1494) rule3809 = ReplacementRule(pattern3809, replacement3809) pattern3810 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons1458) rule3810 = ReplacementRule(pattern3810, replacement3810) pattern3811 = Pattern(Integral(S(1)/(a_ + WC('b', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons1458) rule3811 = ReplacementRule(pattern3811, replacement3811) pattern3812 = Pattern(Integral((a_ + (WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule3812 = ReplacementRule(pattern3812, replacement3812) pattern3813 = Pattern(Integral((a_ + (WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1572) rule3813 = ReplacementRule(pattern3813, replacement3813) pattern3814 = Pattern(Integral((a_ + (WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*sin(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1517) rule3814 = ReplacementRule(pattern3814, With3814) pattern3815 = Pattern(Integral((a_ + (WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*cos(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1517) rule3815 = ReplacementRule(pattern3815, With3815) pattern3816 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**WC('p', S(1))*sin(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1483, cons1481, cons40) rule3816 = ReplacementRule(pattern3816, With3816) pattern3817 = Pattern(Integral((a_ + (S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*cos(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1483, cons1481, cons40) rule3817 = ReplacementRule(pattern3817, With3817) pattern3818 = Pattern(Integral((a_ + (WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*(S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1517) rule3818 = ReplacementRule(pattern3818, With3818) pattern3819 = Pattern(Integral((a_ + (WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*(S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons1517) rule3819 = ReplacementRule(pattern3819, With3819) pattern3820 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0)))**n_)**WC('p', S(1))*(S(1)/cos(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1230, cons745, cons40) rule3820 = ReplacementRule(pattern3820, With3820) pattern3821 = Pattern(Integral((a_ + (S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**WC('p', S(1))*(S(1)/sin(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons1230, cons745, cons40) rule3821 = ReplacementRule(pattern3821, With3821) pattern3822 = Pattern(Integral((a_ + (WC('e', S(1))*tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*tan(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule3822 = ReplacementRule(pattern3822, replacement3822) pattern3823 = Pattern(Integral((a_ + (WC('e', S(1))/tan(x_*WC('d', S(1)) + WC('c', S(0))))**n_*WC('b', S(1)))**p_*(S(1)/tan(x_*WC('d', S(1)) + WC('c', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule3823 = ReplacementRule(pattern3823, replacement3823) pattern3824 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons40) rule3824 = ReplacementRule(pattern3824, replacement3824) pattern3825 = Pattern(Integral((a_ + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons40) rule3825 = ReplacementRule(pattern3825, replacement3825) pattern3826 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons149) rule3826 = ReplacementRule(pattern3826, replacement3826) pattern3827 = Pattern(Integral((a_ + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons47, cons149) rule3827 = ReplacementRule(pattern3827, replacement3827) pattern3828 = Pattern(Integral(S(1)/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228) rule3828 = ReplacementRule(pattern3828, With3828) pattern3829 = Pattern(Integral(S(1)/((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228) rule3829 = ReplacementRule(pattern3829, With3829) pattern3830 = Pattern(Integral(((WC('f', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons48, cons1517) rule3830 = ReplacementRule(pattern3830, replacement3830) pattern3831 = Pattern(Integral(((WC('f', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons48, cons1517) rule3831 = ReplacementRule(pattern3831, replacement3831) pattern3832 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1483, cons1481, cons40) rule3832 = ReplacementRule(pattern3832, With3832) pattern3833 = Pattern(Integral(((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1483, cons1481, cons40) rule3833 = ReplacementRule(pattern3833, With3833) pattern3834 = Pattern(Integral(((WC('f', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons48, cons1482) rule3834 = ReplacementRule(pattern3834, replacement3834) pattern3835 = Pattern(Integral(((WC('f', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons4, cons5, cons48, cons1482) rule3835 = ReplacementRule(pattern3835, replacement3835) pattern3836 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*cos(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1483, cons1481, cons40) rule3836 = ReplacementRule(pattern3836, With3836) pattern3837 = Pattern(Integral(((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*sin(x_*WC('e', S(1)) + WC('d', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons48, cons1483, cons1481, cons40) rule3837 = ReplacementRule(pattern3837, With3837) pattern3838 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule3838 = ReplacementRule(pattern3838, replacement3838) pattern3839 = Pattern(Integral(((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule3839 = ReplacementRule(pattern3839, replacement3839) pattern3840 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule3840 = ReplacementRule(pattern3840, replacement3840) pattern3841 = Pattern(Integral(((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule3841 = ReplacementRule(pattern3841, replacement3841) pattern3842 = Pattern(Integral(((WC('f', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons48, cons228) rule3842 = ReplacementRule(pattern3842, replacement3842) pattern3843 = Pattern(Integral(((WC('f', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (WC('f', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons48, cons228) rule3843 = ReplacementRule(pattern3843, replacement3843) pattern3844 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule3844 = ReplacementRule(pattern3844, replacement3844) pattern3845 = Pattern(Integral(((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons47, cons40) rule3845 = ReplacementRule(pattern3845, replacement3845) pattern3846 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n', S(1)) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('n2', S(1)))**p_*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule3846 = ReplacementRule(pattern3846, replacement3846) pattern3847 = Pattern(Integral(((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n', S(1))*WC('b', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons47, cons149) rule3847 = ReplacementRule(pattern3847, replacement3847) pattern3848 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**n_ + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**n2_)**WC('p', S(1))*(S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons48, cons228, cons1481) rule3848 = ReplacementRule(pattern3848, With3848) pattern3849 = Pattern(Integral(((S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**n2_*WC('c', S(1)) + (S(1)/tan(x_*WC('e', S(1)) + WC('d', S(0))))**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons48, cons228, cons1481) rule3849 = ReplacementRule(pattern3849, With3849) pattern3850 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons87) rule3850 = ReplacementRule(pattern3850, replacement3850) pattern3851 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons87) rule3851 = ReplacementRule(pattern3851, replacement3851) pattern3852 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons25) rule3852 = ReplacementRule(pattern3852, replacement3852) pattern3853 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))*(a_ + WC('b', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons47, cons25) rule3853 = ReplacementRule(pattern3853, replacement3853) pattern3854 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228) rule3854 = ReplacementRule(pattern3854, With3854) pattern3855 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))/(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228) rule3855 = ReplacementRule(pattern3855, With3855) pattern3856 = Pattern(Integral((A_ + WC('B', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))*tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228, cons87) rule3856 = ReplacementRule(pattern3856, replacement3856) pattern3857 = Pattern(Integral((A_ + WC('B', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0))) + WC('c', S(1))/tan(x_*WC('e', S(1)) + WC('d', S(0)))**S(2))**n_, x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons228, cons87) rule3857 = ReplacementRule(pattern3857, replacement3857) pattern3858 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons64) rule3858 = ReplacementRule(pattern3858, replacement3858) pattern3859 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))), x_), cons8, cons29, cons50, cons127, cons64) rule3859 = ReplacementRule(pattern3859, replacement3859) pattern3860 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons170) rule3860 = ReplacementRule(pattern3860, replacement3860) pattern3861 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons167, cons170) rule3861 = ReplacementRule(pattern3861, replacement3861) pattern3862 = Pattern(Integral((WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons170) rule3862 = ReplacementRule(pattern3862, replacement3862) pattern3863 = Pattern(Integral((WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons3, cons8, cons29, cons50, cons127, cons95, cons91, cons170) rule3863 = ReplacementRule(pattern3863, replacement3863) pattern3864 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule3864 = ReplacementRule(pattern3864, replacement3864) pattern3865 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1))*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons530) rule3865 = ReplacementRule(pattern3865, replacement3865) pattern3866 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons33, cons170) rule3866 = ReplacementRule(pattern3866, replacement3866) pattern3867 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons33, cons170) rule3867 = ReplacementRule(pattern3867, replacement3867) pattern3868 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441) rule3868 = ReplacementRule(pattern3868, replacement3868) pattern3869 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))**S(2)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441) rule3869 = ReplacementRule(pattern3869, replacement3869) pattern3870 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons33, cons96, cons1512) rule3870 = ReplacementRule(pattern3870, replacement3870) pattern3871 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons33, cons96, cons1512) rule3871 = ReplacementRule(pattern3871, replacement3871) pattern3872 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441) rule3872 = ReplacementRule(pattern3872, replacement3872) pattern3873 = Pattern(Integral(S(1)/((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))*(x_*WC('d', S(1)) + WC('c', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441) rule3873 = ReplacementRule(pattern3873, replacement3873) pattern3874 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1441, cons21) rule3874 = ReplacementRule(pattern3874, replacement3874) pattern3875 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**m_/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1441, cons21) rule3875 = ReplacementRule(pattern3875, replacement3875) pattern3876 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons1573) rule3876 = ReplacementRule(pattern3876, replacement3876) pattern3877 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons1573) rule3877 = ReplacementRule(pattern3877, replacement3877) pattern3878 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1441, cons198) rule3878 = ReplacementRule(pattern3878, replacement3878) pattern3879 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**m_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons1441, cons198) rule3879 = ReplacementRule(pattern3879, replacement3879) pattern3880 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons1574, cons33, cons170) rule3880 = ReplacementRule(pattern3880, With3880) pattern3881 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1441, cons1574, cons33, cons170) rule3881 = ReplacementRule(pattern3881, With3881) pattern3882 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442, cons64) rule3882 = ReplacementRule(pattern3882, replacement3882) pattern3883 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442, cons64) rule3883 = ReplacementRule(pattern3883, replacement3883) pattern3884 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442) rule3884 = ReplacementRule(pattern3884, replacement3884) pattern3885 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))/(a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**S(2), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442) rule3885 = ReplacementRule(pattern3885, replacement3885) pattern3886 = Pattern(Integral((a_ + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442, cons198, cons64) rule3886 = ReplacementRule(pattern3886, replacement3886) pattern3887 = Pattern(Integral((a_ + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**n_*(x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons1442, cons198, cons64) rule3887 = ReplacementRule(pattern3887, replacement3887) pattern3888 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule3888 = ReplacementRule(pattern3888, replacement3888) pattern3889 = Pattern(Integral(u_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(v_))**WC('n', S(1)), x_), cons2, cons3, cons19, cons4, cons812, cons813) rule3889 = ReplacementRule(pattern3889, replacement3889) pattern3890 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule3890 = ReplacementRule(pattern3890, replacement3890) pattern3891 = Pattern(Integral((x_*WC('d', S(1)) + WC('c', S(0)))**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(x_*WC('f', S(1)) + WC('e', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons1362) rule3891 = ReplacementRule(pattern3891, replacement3891) pattern3892 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule3892 = ReplacementRule(pattern3892, replacement3892) pattern3893 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons5, cons1575, cons40) rule3893 = ReplacementRule(pattern3893, replacement3893) pattern3894 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule3894 = ReplacementRule(pattern3894, replacement3894) pattern3895 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons1497) rule3895 = ReplacementRule(pattern3895, replacement3895) pattern3896 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule3896 = ReplacementRule(pattern3896, replacement3896) pattern3897 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(u_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons4, cons5, cons70, cons71) rule3897 = ReplacementRule(pattern3897, replacement3897) pattern3898 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))*tan(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule3898 = ReplacementRule(pattern3898, replacement3898) pattern3899 = Pattern(Integral((WC('a', S(0)) + WC('b', S(1))/tan(u_))**WC('p', S(1)), x_), cons2, cons3, cons5, cons825, cons826) rule3899 = ReplacementRule(pattern3899, replacement3899) pattern3900 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule3900 = ReplacementRule(pattern3900, replacement3900) pattern3901 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1576, cons40) rule3901 = ReplacementRule(pattern3901, replacement3901) pattern3902 = Pattern(Integral(x_**WC('m', S(1))*tan(x_**n_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons8, cons29, cons19, cons4, cons1577) rule3902 = ReplacementRule(pattern3902, replacement3902) pattern3903 = Pattern(Integral(x_**WC('m', S(1))/tan(x_**n_*WC('d', S(1)) + WC('c', S(0)))**S(2), x_), cons8, cons29, cons19, cons4, cons1577) rule3903 = ReplacementRule(pattern3903, replacement3903) pattern3904 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule3904 = ReplacementRule(pattern3904, replacement3904) pattern3905 = Pattern(Integral(x_**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons1578) rule3905 = ReplacementRule(pattern3905, replacement3905) pattern3906 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule3906 = ReplacementRule(pattern3906, replacement3906) pattern3907 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(x_**n_*WC('d', S(1)) + WC('c', S(0))))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons1499) rule3907 = ReplacementRule(pattern3907, replacement3907) pattern3908 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))*tan(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule3908 = ReplacementRule(pattern3908, replacement3908) pattern3909 = Pattern(Integral((e_*x_)**WC('m', S(1))*(WC('a', S(0)) + WC('b', S(1))/tan(u_))**WC('p', S(1)), x_), cons2, cons3, cons50, cons19, cons5, cons825, cons826) rule3909 = ReplacementRule(pattern3909, replacement3909) pattern3910 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/cos(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1))*tan(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**WC('q', S(1)), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1580) rule3910 = ReplacementRule(pattern3910, replacement3910) pattern3911 = Pattern(Integral(x_**WC('m', S(1))*(S(1)/sin(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('p', S(1))*(S(1)/tan(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))))**WC('q', S(1)), x_), cons2, cons3, cons5, cons33, cons87, cons1579, cons1580) rule3911 = ReplacementRule(pattern3911, replacement3911) pattern3912 = Pattern(Integral(tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule3912 = ReplacementRule(pattern3912, replacement3912) pattern3913 = Pattern(Integral((S(1)/tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons4, cons1581) rule3913 = ReplacementRule(pattern3913, replacement3913) pattern3914 = Pattern(Integral((d_ + x_*WC('e', S(1)))*tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons49) rule3914 = ReplacementRule(pattern3914, replacement3914) pattern3915 = Pattern(Integral((d_ + x_*WC('e', S(1)))/tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons49) rule3915 = ReplacementRule(pattern3915, replacement3915) pattern3916 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))*tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons241) rule3916 = ReplacementRule(pattern3916, replacement3916) pattern3917 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))/tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons241) rule3917 = ReplacementRule(pattern3917, replacement3917) pattern3918 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0)))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule3918 = ReplacementRule(pattern3918, replacement3918) pattern3919 = Pattern(Integral((x_*WC('e', S(1)) + WC('d', S(0)))**WC('m', S(1))*(S(1)/tan(x_**S(2)*WC('c', S(1)) + x_*WC('b', S(1)) + WC('a', S(0))))**WC('n', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons1582) rule3919 = ReplacementRule(pattern3919, replacement3919) return [rule3401, rule3402, rule3403, rule3404, rule3405, rule3406, rule3407, rule3408, rule3409, rule3410, rule3411, rule3412, rule3413, rule3414, rule3415, rule3416, rule3417, rule3418, rule3419, rule3420, rule3421, rule3422, rule3423, rule3424, rule3425, rule3426, rule3427, rule3428, rule3429, rule3430, rule3431, rule3432, rule3433, rule3434, rule3435, rule3436, rule3437, rule3438, rule3439, rule3440, rule3441, rule3442, rule3443, rule3444, rule3445, rule3446, rule3447, rule3448, rule3449, rule3450, rule3451, rule3452, rule3453, rule3454, rule3455, rule3456, rule3457, rule3458, rule3459, rule3460, rule3461, rule3462, rule3463, rule3464, rule3465, rule3466, rule3467, rule3468, rule3469, rule3470, rule3471, rule3472, rule3473, rule3474, rule3475, rule3476, rule3477, rule3478, rule3479, rule3480, rule3481, rule3482, rule3483, rule3484, rule3485, rule3486, rule3487, rule3488, rule3489, rule3490, rule3491, rule3492, rule3493, rule3494, rule3495, rule3496, rule3497, rule3498, rule3499, rule3500, rule3501, rule3502, rule3503, rule3504, rule3505, rule3506, rule3507, rule3508, rule3509, rule3510, rule3511, rule3512, rule3513, rule3514, rule3515, rule3516, rule3517, rule3518, rule3519, rule3520, rule3521, rule3522, rule3523, rule3524, rule3525, rule3526, rule3527, rule3528, rule3529, rule3530, rule3531, rule3532, rule3533, rule3534, rule3535, rule3536, rule3537, rule3538, rule3539, rule3540, rule3541, rule3542, rule3543, rule3544, rule3545, rule3546, rule3547, rule3548, rule3549, rule3550, rule3551, rule3552, rule3553, rule3554, rule3555, rule3556, rule3557, rule3558, rule3559, rule3560, rule3561, rule3562, rule3563, rule3564, rule3565, rule3566, rule3567, rule3568, rule3569, rule3570, rule3571, rule3572, rule3573, rule3574, rule3575, rule3576, rule3577, rule3578, rule3579, rule3580, rule3581, rule3582, rule3583, rule3584, rule3585, rule3586, rule3587, rule3588, rule3589, rule3590, rule3591, rule3592, rule3593, rule3594, rule3595, rule3596, rule3597, rule3598, rule3599, rule3600, rule3601, rule3602, rule3603, rule3604, rule3605, rule3606, rule3607, rule3608, rule3609, rule3610, rule3611, rule3612, rule3613, rule3614, rule3615, rule3616, rule3617, rule3618, rule3619, rule3620, rule3621, rule3622, rule3623, rule3624, rule3625, rule3626, rule3627, rule3628, rule3629, rule3630, rule3631, rule3632, rule3633, rule3634, rule3635, rule3636, rule3637, rule3638, rule3639, rule3640, rule3641, rule3642, rule3643, rule3644, rule3645, rule3646, rule3647, rule3648, rule3649, rule3650, rule3651, rule3652, rule3653, rule3654, rule3655, rule3656, rule3657, rule3658, rule3659, rule3660, rule3661, rule3662, rule3663, rule3664, rule3665, rule3666, rule3667, rule3668, rule3669, rule3670, rule3671, rule3672, rule3673, rule3674, rule3675, rule3676, rule3677, rule3678, rule3679, rule3680, rule3681, rule3682, rule3683, rule3684, rule3685, rule3686, rule3687, rule3688, rule3689, rule3690, rule3691, rule3692, rule3693, rule3694, rule3695, rule3696, rule3697, rule3698, rule3699, rule3700, rule3701, rule3702, rule3703, rule3704, rule3705, rule3706, rule3707, rule3708, rule3709, rule3710, rule3711, rule3712, rule3713, rule3714, rule3715, rule3716, rule3717, rule3718, rule3719, rule3720, rule3721, rule3722, rule3723, rule3724, rule3725, rule3726, rule3727, rule3728, rule3729, rule3730, rule3731, rule3732, rule3733, rule3734, rule3735, rule3736, rule3737, rule3738, rule3739, rule3740, rule3741, rule3742, rule3743, rule3744, rule3745, rule3746, rule3747, rule3748, rule3749, rule3750, rule3751, rule3752, rule3753, rule3754, rule3755, rule3756, rule3757, rule3758, rule3759, rule3760, rule3761, rule3762, rule3763, rule3764, rule3765, rule3766, rule3767, rule3768, rule3769, rule3770, rule3771, rule3772, rule3773, rule3774, rule3775, rule3776, rule3777, rule3778, rule3779, rule3780, rule3781, rule3782, rule3783, rule3784, rule3785, rule3786, rule3787, rule3788, rule3789, rule3790, rule3791, rule3792, rule3793, rule3794, rule3795, rule3796, rule3797, rule3798, rule3799, rule3800, rule3801, rule3802, rule3803, rule3804, rule3805, rule3806, rule3807, rule3808, rule3809, rule3810, rule3811, rule3812, rule3813, rule3814, rule3815, rule3816, rule3817, rule3818, rule3819, rule3820, rule3821, rule3822, rule3823, rule3824, rule3825, rule3826, rule3827, rule3828, rule3829, rule3830, rule3831, rule3832, rule3833, rule3834, rule3835, rule3836, rule3837, rule3838, rule3839, rule3840, rule3841, rule3842, rule3843, rule3844, rule3845, rule3846, rule3847, rule3848, rule3849, rule3850, rule3851, rule3852, rule3853, rule3854, rule3855, rule3856, rule3857, rule3858, rule3859, rule3860, rule3861, rule3862, rule3863, rule3864, rule3865, rule3866, rule3867, rule3868, rule3869, rule3870, rule3871, rule3872, rule3873, rule3874, rule3875, rule3876, rule3877, rule3878, rule3879, rule3880, rule3881, rule3882, rule3883, rule3884, rule3885, rule3886, rule3887, rule3888, rule3889, rule3890, rule3891, rule3892, rule3893, rule3894, rule3895, rule3896, rule3897, rule3898, rule3899, rule3900, rule3901, rule3902, rule3903, rule3904, rule3905, rule3906, rule3907, rule3908, rule3909, rule3910, rule3911, rule3912, rule3913, rule3914, rule3915, rule3916, rule3917, rule3918, rule3919, ] def replacement3401(a, b, e, f, m, n, x): return -Simp(b*(a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3402(a, b, e, f, m, n, x): return Simp(b*(a*cos(e + f*x))**m*(b/tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3403(e, f, m, n, x): return -Dist(S(1)/f, Subst(Int(x**(-n)*(S(1) - x**S(2))**(m/S(2) + n/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement3404(e, f, m, n, x): return Dist(S(1)/f, Subst(Int(x**(-n)*(S(1) - x**S(2))**(m/S(2) + n/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement3405(b, e, f, m, n, x): return Dist(b**(-m), Int((b*tan(e + f*x))**(m + n)*(S(1)/cos(e + f*x))**(-m), x), x) def replacement3406(b, e, f, m, n, x): return Dist(b**(-m), Int((b/tan(e + f*x))**(m + n)*(S(1)/sin(e + f*x))**(-m), x), x) def replacement3407(a, b, e, f, m, n, x): return -Dist(b**S(2)*(m + S(2))/(a**S(2)*(n + S(-1))), Int((a*sin(e + f*x))**(m + S(2))*(b*tan(e + f*x))**(n + S(-2)), x), x) + Simp(b*(a*sin(e + f*x))**(m + S(2))*(b*tan(e + f*x))**(n + S(-1))/(a**S(2)*f*(n + S(-1))), x) def replacement3408(a, b, e, f, m, n, x): return -Dist(b**S(2)*(m + S(2))/(a**S(2)*(n + S(-1))), Int((a*cos(e + f*x))**(m + S(2))*(b/tan(e + f*x))**(n + S(-2)), x), x) - Simp(b*(a*cos(e + f*x))**(m + S(2))*(b/tan(e + f*x))**(n + S(-1))/(a**S(2)*f*(n + S(-1))), x) def replacement3409(a, b, e, f, m, n, x): return -Dist(b**S(2)*(m + n + S(-1))/(n + S(-1)), Int((a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(-2)), x), x) + Simp(b*(a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(-1))/(f*(n + S(-1))), x) def replacement3410(a, b, e, f, m, n, x): return -Dist(b**S(2)*(m + n + S(-1))/(n + S(-1)), Int((a*cos(e + f*x))**m*(b/tan(e + f*x))**(n + S(-2)), x), x) - Simp(b*(a*cos(e + f*x))**m*(b/tan(e + f*x))**(n + S(-1))/(f*(n + S(-1))), x) def replacement3411(a, b, e, f, m, n, x): return -Dist(a**S(2)*(n + S(1))/(b**S(2)*m), Int((a*sin(e + f*x))**(m + S(-2))*(b*tan(e + f*x))**(n + S(2)), x), x) + Simp((a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))/(b*f*m), x) def replacement3412(a, b, e, f, m, n, x): return -Dist(a**S(2)*(n + S(1))/(b**S(2)*m), Int((a*cos(e + f*x))**(m + S(-2))*(b/tan(e + f*x))**(n + S(2)), x), x) - Simp((a*cos(e + f*x))**m*(b/tan(e + f*x))**(n + S(1))/(b*f*m), x) def replacement3413(a, b, e, f, m, n, x): return -Dist((n + S(1))/(b**S(2)*(m + n + S(1))), Int((a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(2)), x), x) + Simp((a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))/(b*f*(m + n + S(1))), x) def replacement3414(a, b, e, f, m, n, x): return -Dist((n + S(1))/(b**S(2)*(m + n + S(1))), Int((a*cos(e + f*x))**m*(b/tan(e + f*x))**(n + S(2)), x), x) - Simp((a*cos(e + f*x))**m*(b/tan(e + f*x))**(n + S(1))/(b*f*(m + n + S(1))), x) def replacement3415(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + n + S(-1))/m, Int((a*sin(e + f*x))**(m + S(-2))*(b*tan(e + f*x))**n, x), x) - Simp(b*(a*sin(e + f*x))**m*(b*tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3416(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + n + S(-1))/m, Int((a*cos(e + f*x))**(m + S(-2))*(b/tan(e + f*x))**n, x), x) + Simp(b*(a*cos(e + f*x))**m*(b/tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3417(a, b, e, f, m, n, x): return Dist((m + S(2))/(a**S(2)*(m + n + S(1))), Int((a*sin(e + f*x))**(m + S(2))*(b*tan(e + f*x))**n, x), x) + Simp(b*(a*sin(e + f*x))**(m + S(2))*(b*tan(e + f*x))**(n + S(-1))/(a**S(2)*f*(m + n + S(1))), x) def replacement3418(a, b, e, f, m, n, x): return Dist((m + S(2))/(a**S(2)*(m + n + S(1))), Int((a*cos(e + f*x))**(m + S(2))*(b/tan(e + f*x))**n, x), x) - Simp(b*(a*cos(e + f*x))**(m + S(2))*(b/tan(e + f*x))**(n + S(-1))/(a**S(2)*f*(m + n + S(1))), x) def replacement3419(a, e, f, m, n, x): return Dist(S(1)/f, Subst(Int(x**(m + n)*(a**S(2) - x**S(2))**(-n/S(2) + S(-1)/2), x), x, a*sin(e + f*x)), x) def replacement3420(a, e, f, m, n, x): return -Dist(S(1)/f, Subst(Int(x**(m + n)*(a**S(2) - x**S(2))**(-n/S(2) + S(-1)/2), x), x, a*cos(e + f*x)), x) def replacement3421(a, b, e, f, m, n, x): return Dist(a**(S(1) - S(2)*IntPart(n/S(2) + S(1)/2))*b**(S(2)*IntPart(n/S(2) + S(1)/2) + S(-1))*(a*sin(e + f*x))**(-S(2)*FracPart(n/S(2) + S(1)/2))*(b*tan(e + f*x))**(S(2)*FracPart(n/S(2) + S(1)/2))*(cos(e + f*x)**S(2))**FracPart(n/S(2) + S(1)/2)/f, Subst(Int((a*x)**(m + n)*(S(1) - x**S(2))**(-n/S(2) + S(-1)/2), x), x, sin(e + f*x)), x) def replacement3422(a, b, e, f, m, n, x): return -Dist(a**(S(1) - S(2)*IntPart(n/S(2) + S(1)/2))*b**(S(2)*IntPart(n/S(2) + S(1)/2) + S(-1))*(a*cos(e + f*x))**(-S(2)*FracPart(n/S(2) + S(1)/2))*(b/tan(e + f*x))**(S(2)*FracPart(n/S(2) + S(1)/2))*(sin(e + f*x)**S(2))**FracPart(n/S(2) + S(1)/2)/f, Subst(Int((a*x)**(m + n)*(S(1) - x**S(2))**(-n/S(2) + S(-1)/2), x), x, cos(e + f*x)), x) def replacement3423(a, b, e, f, m, n, x): return Dist((S(1)/(a*cos(e + f*x)))**FracPart(m)*(a*cos(e + f*x))**FracPart(m), Int((S(1)/(a*cos(e + f*x)))**(-m)*(b*tan(e + f*x))**n, x), x) def replacement3424(a, b, e, f, m, n, x): return Dist((S(1)/(a*sin(e + f*x)))**FracPart(m)*(a*sin(e + f*x))**FracPart(m), Int((S(1)/(a*sin(e + f*x)))**(-m)*(b/tan(e + f*x))**n, x), x) def replacement3425(a, b, e, f, m, n, x): return Dist((a/tan(e + f*x))**m*(b*tan(e + f*x))**m, Int((b*tan(e + f*x))**(-m + n), x), x) def replacement3426(a, b, e, f, m, n, x): return -Simp((a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))/(b*f*m), x) def replacement3427(a, b, e, f, m, n, x): return Simp((a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(1))/(b*f*m), x) def replacement3428(a, b, e, f, m, n, x): return Dist(a/f, Subst(Int((a*x)**(m + S(-1))*(x**S(2) + S(-1))**(n/S(2) + S(-1)/2), x), x, S(1)/cos(e + f*x)), x) def replacement3429(a, b, e, f, m, n, x): return -Dist(a/f, Subst(Int((a*x)**(m + S(-1))*(x**S(2) + S(-1))**(n/S(2) + S(-1)/2), x), x, S(1)/sin(e + f*x)), x) def replacement3430(b, e, f, m, n, x): return Dist(S(1)/f, Subst(Int((b*x)**n*(x**S(2) + S(1))**(m/S(2) + S(-1)), x), x, tan(e + f*x)), x) def replacement3431(b, e, f, m, n, x): return -Dist(S(1)/f, Subst(Int((b*x)**n*(x**S(2) + S(1))**(m/S(2) + S(-1)), x), x, S(1)/tan(e + f*x)), x) def replacement3432(a, b, e, f, m, n, x): return -Dist(a**S(2)*(m + S(-2))/(b**S(2)*(n + S(1))), Int((a/cos(e + f*x))**(m + S(-2))*(b*tan(e + f*x))**(n + S(2)), x), x) + Simp(a**S(2)*(a/cos(e + f*x))**(m + S(-2))*(b*tan(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement3433(a, b, e, f, m, n, x): return -Dist(a**S(2)*(m + S(-2))/(b**S(2)*(n + S(1))), Int((a/sin(e + f*x))**(m + S(-2))*(b/tan(e + f*x))**(n + S(2)), x), x) - Simp(a**S(2)*(a/sin(e + f*x))**(m + S(-2))*(b/tan(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement3434(a, b, e, f, m, n, x): return -Dist((m + n + S(1))/(b**S(2)*(n + S(1))), Int((a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(2)), x), x) + Simp((a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement3435(a, b, e, f, m, n, x): return -Dist((m + n + S(1))/(b**S(2)*(n + S(1))), Int((a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(2)), x), x) - Simp((a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement3436(a, b, e, f, m, n, x): return -Dist(b**S(2)*(n + S(-1))/(a**S(2)*m), Int((a/cos(e + f*x))**(m + S(2))*(b*tan(e + f*x))**(n + S(-2)), x), x) + Simp(b*(a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3437(a, b, e, f, m, n, x): return -Dist(b**S(2)*(n + S(-1))/(a**S(2)*m), Int((a/sin(e + f*x))**(m + S(2))*(b/tan(e + f*x))**(n + S(-2)), x), x) - Simp(b*(a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3438(a, b, e, f, m, n, x): return -Dist(b**S(2)*(n + S(-1))/(m + n + S(-1)), Int((a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(-2)), x), x) + Simp(b*(a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3439(a, b, e, f, m, n, x): return -Dist(b**S(2)*(n + S(-1))/(m + n + S(-1)), Int((a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(-2)), x), x) - Simp(b*(a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3440(a, b, e, f, m, n, x): return Dist((m + n + S(1))/(a**S(2)*m), Int((a/cos(e + f*x))**(m + S(2))*(b*tan(e + f*x))**n, x), x) - Simp((a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))/(b*f*m), x) def replacement3441(a, b, e, f, m, n, x): return Dist((m + n + S(1))/(a**S(2)*m), Int((a/sin(e + f*x))**(m + S(2))*(b/tan(e + f*x))**n, x), x) + Simp((a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(1))/(b*f*m), x) def replacement3442(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-2))/(m + n + S(-1)), Int((a/cos(e + f*x))**(m + S(-2))*(b*tan(e + f*x))**n, x), x) + Simp(a**S(2)*(a/cos(e + f*x))**(m + S(-2))*(b*tan(e + f*x))**(n + S(1))/(b*f*(m + n + S(-1))), x) def replacement3443(a, b, e, f, m, n, x): return Dist(a**S(2)*(m + S(-2))/(m + n + S(-1)), Int((a/sin(e + f*x))**(m + S(-2))*(b/tan(e + f*x))**n, x), x) - Simp(a**S(2)*(a/sin(e + f*x))**(m + S(-2))*(b/tan(e + f*x))**(n + S(1))/(b*f*(m + n + S(-1))), x) def replacement3444(b, e, f, x): return Dist(sqrt(sin(e + f*x))/(sqrt(b*tan(e + f*x))*sqrt(cos(e + f*x))), Int(S(1)/(sqrt(sin(e + f*x))*sqrt(cos(e + f*x))), x), x) def replacement3445(b, e, f, x): return Dist(sqrt(cos(e + f*x))/(sqrt(b/tan(e + f*x))*sqrt(sin(e + f*x))), Int(S(1)/(sqrt(sin(e + f*x))*sqrt(cos(e + f*x))), x), x) def replacement3446(b, e, f, x): return Dist(sqrt(b*tan(e + f*x))*sqrt(cos(e + f*x))/sqrt(sin(e + f*x)), Int(sqrt(sin(e + f*x))*sqrt(cos(e + f*x)), x), x) def replacement3447(b, e, f, x): return Dist(sqrt(b/tan(e + f*x))*sqrt(sin(e + f*x))/sqrt(cos(e + f*x)), Int(sqrt(sin(e + f*x))*sqrt(cos(e + f*x)), x), x) def replacement3448(a, b, e, f, m, n, x): return Dist(a**(m + n)*(a/cos(e + f*x))**(-n)*(b*sin(e + f*x))**(-n)*(b*tan(e + f*x))**n, Int((b*sin(e + f*x))**n*cos(e + f*x)**(-m - n), x), x) def replacement3449(a, b, e, f, m, n, x): return Dist(a**(m + n)*(a/sin(e + f*x))**(-n)*(b*cos(e + f*x))**(-n)*(b/tan(e + f*x))**n, Int((b*cos(e + f*x))**n*sin(e + f*x)**(-m - n), x), x) def replacement3450(a, b, e, f, m, n, x): return Simp((a/cos(e + f*x))**m*(b*tan(e + f*x))**(n + S(1))*(cos(e + f*x)**S(2))**(m/S(2) + n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, m/S(2) + n/S(2) + S(1)/2, n/S(2) + S(3)/2, sin(e + f*x)**S(2))/(b*f*(n + S(1))), x) def replacement3451(a, b, e, f, m, n, x): return -Simp((a/sin(e + f*x))**m*(b/tan(e + f*x))**(n + S(1))*(sin(e + f*x)**S(2))**(m/S(2) + n/S(2) + S(1)/2)*Hypergeometric2F1(n/S(2) + S(1)/2, m/S(2) + n/S(2) + S(1)/2, n/S(2) + S(3)/2, cos(e + f*x)**S(2))/(b*f*(n + S(1))), x) def replacement3452(a, b, e, f, m, n, x): return Dist((sin(e + f*x)/a)**FracPart(m)*(a/sin(e + f*x))**FracPart(m), Int((sin(e + f*x)/a)**(-m)*(b*tan(e + f*x))**n, x), x) def replacement3453(a, b, e, f, m, n, x): return Dist((cos(e + f*x)/a)**FracPart(m)*(a/cos(e + f*x))**FracPart(m), Int((cos(e + f*x)/a)**(-m)*(b/tan(e + f*x))**n, x), x) def replacement3454(a, b, d, e, f, m, n, p, x): return -Dist(b**S(2)*(n + S(-1))/(m*p + n + S(-1)), Int((a*(d/cos(e + f*x))**p)**m*(b*tan(e + f*x))**(n + S(-2)), x), x) + Simp(b*(a*(d/cos(e + f*x))**p)**m*(b*tan(e + f*x))**(n + S(-1))/(f*(m*p + n + S(-1))), x) def replacement3455(a, b, d, e, f, m, n, p, x): return -Dist(b**S(2)*(n + S(-1))/(m*p + n + S(-1)), Int((a*(d/sin(e + f*x))**p)**m*(b/tan(e + f*x))**(n + S(-2)), x), x) - Simp(b*(a*(d/sin(e + f*x))**p)**m*(b/tan(e + f*x))**(n + S(-1))/(f*(m*p + n + S(-1))), x) def replacement3456(a, b, d, e, f, m, n, p, x): return -Dist((m*p + n + S(1))/(b**S(2)*(n + S(1))), Int((a*(d/cos(e + f*x))**p)**m*(b*tan(e + f*x))**(n + S(2)), x), x) + Simp((a*(d/cos(e + f*x))**p)**m*(b*tan(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement3457(a, b, d, e, f, m, n, p, x): return -Dist((m*p + n + S(1))/(b**S(2)*(n + S(1))), Int((a*(d/sin(e + f*x))**p)**m*(b/tan(e + f*x))**(n + S(2)), x), x) + Simp((a*(d/sin(e + f*x))**p)**m*(b/tan(e + f*x))**(n + S(1))/(b*f*(n + S(1))), x) def replacement3458(b, c, d, n, x): return -Dist(b**S(2), Int((b*tan(c + d*x))**(n + S(-2)), x), x) + Simp(b*(b*tan(c + d*x))**(n + S(-1))/(d*(n + S(-1))), x) def replacement3459(b, c, d, n, x): return -Dist(b**S(2), Int((b/tan(c + d*x))**(n + S(-2)), x), x) - Simp(b*(b/tan(c + d*x))**(n + S(-1))/(d*(n + S(-1))), x) def replacement3460(b, c, d, n, x): return -Dist(b**(S(-2)), Int((b*tan(c + d*x))**(n + S(2)), x), x) + Simp((b*tan(c + d*x))**(n + S(1))/(b*d*(n + S(1))), x) def replacement3461(b, c, d, n, x): return -Dist(b**(S(-2)), Int((b/tan(c + d*x))**(n + S(2)), x), x) - Simp((b/tan(c + d*x))**(n + S(1))/(b*d*(n + S(1))), x) def replacement3462(c, d, x): return -Simp(log(RemoveContent(cos(c + d*x), x))/d, x) def replacement3463(c, d, x): return Simp(log(RemoveContent(sin(c + d*x), x))/d, x) def replacement3464(b, c, d, n, x): return Dist(b/d, Subst(Int(x**n/(b**S(2) + x**S(2)), x), x, b*tan(c + d*x)), x) def replacement3465(b, c, d, n, x): return -Dist(b/d, Subst(Int(x**n/(b**S(2) + x**S(2)), x), x, b/tan(c + d*x)), x) def replacement3466(a, b, c, d, x): return Dist(S(2)*a*b, Int(tan(c + d*x), x), x) + Simp(x*(a**S(2) - b**S(2)), x) + Simp(b**S(2)*tan(c + d*x)/d, x) def replacement3467(a, b, c, d, x): return Dist(S(2)*a*b, Int(S(1)/tan(c + d*x), x), x) + Simp(x*(a**S(2) - b**S(2)), x) - Simp(b**S(2)/(d*tan(c + d*x)), x) def replacement3468(a, b, c, d, n, x): return Dist(S(2)*a, Int((a + b*tan(c + d*x))**(n + S(-1)), x), x) + Simp(b*(a + b*tan(c + d*x))**(n + S(-1))/(d*(n + S(-1))), x) def replacement3469(a, b, c, d, n, x): return Dist(S(2)*a, Int((a + b/tan(c + d*x))**(n + S(-1)), x), x) - Simp(b*(a + b/tan(c + d*x))**(n + S(-1))/(d*(n + S(-1))), x) def replacement3470(a, b, c, d, n, x): return Dist(S(1)/(S(2)*a), Int((a + b*tan(c + d*x))**(n + S(1)), x), x) + Simp(a*(a + b*tan(c + d*x))**n/(S(2)*b*d*n), x) def replacement3471(a, b, c, d, n, x): return Dist(S(1)/(S(2)*a), Int((a + b/tan(c + d*x))**(n + S(1)), x), x) - Simp(a*(a + b/tan(c + d*x))**n/(S(2)*b*d*n), x) def replacement3472(a, b, c, d, x): return Dist(-S(2)*b/d, Subst(Int(S(1)/(S(2)*a - x**S(2)), x), x, sqrt(a + b*tan(c + d*x))), x) def replacement3473(a, b, c, d, x): return Dist(S(2)*b/d, Subst(Int(S(1)/(S(2)*a - x**S(2)), x), x, sqrt(a + b/tan(c + d*x))), x) def replacement3474(a, b, c, d, n, x): return -Dist(b/d, Subst(Int((a + x)**(n + S(-1))/(a - x), x), x, b*tan(c + d*x)), x) def replacement3475(a, b, c, d, n, x): return Dist(b/d, Subst(Int((a + x)**(n + S(-1))/(a - x), x), x, b/tan(c + d*x)), x) def replacement3476(a, b, c, d, n, x): return Int((a + b*tan(c + d*x))**(n + S(-2))*(a**S(2) + S(2)*a*b*tan(c + d*x) - b**S(2)), x) + Simp(b*(a + b*tan(c + d*x))**(n + S(-1))/(d*(n + S(-1))), x) def replacement3477(a, b, c, d, n, x): return Int((a + b/tan(c + d*x))**(n + S(-2))*(a**S(2) + S(2)*a*b/tan(c + d*x) - b**S(2)), x) - Simp(b*(a + b/tan(c + d*x))**(n + S(-1))/(d*(n + S(-1))), x) def replacement3478(a, b, c, d, n, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a - b*tan(c + d*x))*(a + b*tan(c + d*x))**(n + S(1)), x), x) + Simp(b*(a + b*tan(c + d*x))**(n + S(1))/(d*(a**S(2) + b**S(2))*(n + S(1))), x) def replacement3479(a, b, c, d, n, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a - b/tan(c + d*x))*(a + b/tan(c + d*x))**(n + S(1)), x), x) - Simp(b*(a + b/tan(c + d*x))**(n + S(1))/(d*(a**S(2) + b**S(2))*(n + S(1))), x) def replacement3480(a, b, c, d, x): return Dist(b/(a**S(2) + b**S(2)), Int((-a*tan(c + d*x) + b)/(a + b*tan(c + d*x)), x), x) + Simp(a*x/(a**S(2) + b**S(2)), x) def replacement3481(a, b, c, d, x): return Dist(b/(a**S(2) + b**S(2)), Int((-a/tan(c + d*x) + b)/(a + b/tan(c + d*x)), x), x) + Simp(a*x/(a**S(2) + b**S(2)), x) def replacement3482(a, b, c, d, n, x): return Dist(b/d, Subst(Int((a + x)**n/(b**S(2) + x**S(2)), x), x, b*tan(c + d*x)), x) def replacement3483(a, b, c, d, n, x): return -Dist(b/d, Subst(Int((a + x)**n/(b**S(2) + x**S(2)), x), x, b/tan(c + d*x)), x) def replacement3484(a, b, d, e, f, m, x): return Dist(a, Int((d/cos(e + f*x))**m, x), x) + Simp(b*(d/cos(e + f*x))**m/(f*m), x) def replacement3485(a, b, d, e, f, m, x): return Dist(a, Int((d/sin(e + f*x))**m, x), x) - Simp(b*(d/sin(e + f*x))**m/(f*m), x) def replacement3486(a, b, e, f, m, n, x): return Dist(a**(S(2) - m)/(b*f), Subst(Int((a - x)**(m/S(2) + S(-1))*(a + x)**(m/S(2) + n + S(-1)), x), x, b*tan(e + f*x)), x) def replacement3487(a, b, e, f, m, n, x): return -Dist(a**(S(2) - m)/(b*f), Subst(Int((a - x)**(m/S(2) + S(-1))*(a + x)**(m/S(2) + n + S(-1)), x), x, b/tan(e + f*x)), x) def replacement3488(a, b, d, e, f, m, n, x): return Simp(b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**n/(a*f*m), x) def replacement3489(a, b, d, e, f, m, n, x): return -Simp(b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**n/(a*f*m), x) def replacement3490(a, b, e, f, x): return Dist(-S(2)*a/(b*f), Subst(Int(S(1)/(-a*x**S(2) + S(2)), x), x, S(1)/(sqrt(a + b*tan(e + f*x))*cos(e + f*x))), x) def replacement3491(a, b, e, f, x): return Dist(S(2)*a/(b*f), Subst(Int(S(1)/(-a*x**S(2) + S(2)), x), x, S(1)/(sqrt(a + b/tan(e + f*x))*sin(e + f*x))), x) def replacement3492(a, b, d, e, f, m, n, x): return Dist(a/(S(2)*d**S(2)), Int((d/cos(e + f*x))**(m + S(2))*(a + b*tan(e + f*x))**(n + S(-1)), x), x) + Simp(b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**n/(a*f*m), x) def replacement3493(a, b, d, e, f, m, n, x): return Dist(a/(S(2)*d**S(2)), Int((d/sin(e + f*x))**(m + S(2))*(a + b/tan(e + f*x))**(n + S(-1)), x), x) - Simp(b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**n/(a*f*m), x) def replacement3494(a, b, d, e, f, m, n, x): return Dist(S(2)*d**S(2)/a, Int((d/cos(e + f*x))**(m + S(-2))*(a + b*tan(e + f*x))**(n + S(1)), x), x) + Simp(S(2)*d**S(2)*(d/cos(e + f*x))**(m + S(-2))*(a + b*tan(e + f*x))**(n + S(1))/(b*f*(m + S(-2))), x) def replacement3495(a, b, d, e, f, m, n, x): return Dist(S(2)*d**S(2)/a, Int((d/sin(e + f*x))**(m + S(-2))*(a + b/tan(e + f*x))**(n + S(1)), x), x) + Simp(-S(2)*d**S(2)*(d/sin(e + f*x))**(m + S(-2))*(a + b/tan(e + f*x))**(n + S(1))/(b*f*(m + S(-2))), x) def replacement3496(a, b, d, e, f, m, n, x): return Dist((a/d)**(S(2)*IntPart(n))*(d/cos(e + f*x))**(-S(2)*FracPart(n))*(a - b*tan(e + f*x))**FracPart(n)*(a + b*tan(e + f*x))**FracPart(n), Int((a - b*tan(e + f*x))**(-n), x), x) def replacement3497(a, b, d, e, f, m, n, x): return Dist((a/d)**(S(2)*IntPart(n))*(d/sin(e + f*x))**(-S(2)*FracPart(n))*(a - b/tan(e + f*x))**FracPart(n)*(a + b/tan(e + f*x))**FracPart(n), Int((a - b/tan(e + f*x))**(-n), x), x) def replacement3498(a, b, d, e, f, m, n, x): return Simp(S(2)*b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3499(a, b, d, e, f, m, n, x): return Simp(-S(2)*b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3500(a, b, d, e, f, m, n, x): return Dist(a*(m + S(2)*n + S(-2))/(m + n + S(-1)), Int((d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1)), x), x) + Simp(b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3501(a, b, d, e, f, m, n, x): return Dist(a*(m + S(2)*n + S(-2))/(m + n + S(-1)), Int((d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1)), x), x) - Simp(b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3502(a, b, d, e, f, x): return Dist(-S(4)*b*d**S(2)/f, Subst(Int(x**S(2)/(a**S(2) + d**S(2)*x**S(4)), x), x, sqrt(a + b*tan(e + f*x))/sqrt(d/cos(e + f*x))), x) def replacement3503(a, b, d, e, f, x): return Dist(S(4)*b*d**S(2)/f, Subst(Int(x**S(2)/(a**S(2) + d**S(2)*x**S(4)), x), x, sqrt(a + b/tan(e + f*x))/sqrt(d/sin(e + f*x))), x) def replacement3504(a, b, d, e, f, m, n, x): return -Dist(b**S(2)*(m + S(2)*n + S(-2))/(d**S(2)*m), Int((d/cos(e + f*x))**(m + S(2))*(a + b*tan(e + f*x))**(n + S(-2)), x), x) + Simp(S(2)*b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3505(a, b, d, e, f, m, n, x): return -Dist(b**S(2)*(m + S(2)*n + S(-2))/(d**S(2)*m), Int((d/sin(e + f*x))**(m + S(2))*(a + b/tan(e + f*x))**(n + S(-2)), x), x) + Simp(-S(2)*b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1))/(f*m), x) def replacement3506(a, b, d, e, f, m, n, x): return Dist(a*(m + n)/(d**S(2)*m), Int((d/cos(e + f*x))**(m + S(2))*(a + b*tan(e + f*x))**(n + S(-1)), x), x) + Simp(b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**n/(a*f*m), x) def replacement3507(a, b, d, e, f, m, n, x): return Dist(a*(m + n)/(d**S(2)*m), Int((d/sin(e + f*x))**(m + S(2))*(a + b/tan(e + f*x))**(n + S(-1)), x), x) - Simp(b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**n/(a*f*m), x) def replacement3508(a, b, d, e, f, m, n, x): return Dist(a*(m + S(2)*n + S(-2))/(m + n + S(-1)), Int((d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1)), x), x) + Simp(b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3509(a, b, d, e, f, m, n, x): return Dist(a*(m + S(2)*n + S(-2))/(m + n + S(-1)), Int((d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1)), x), x) - Simp(b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3510(a, b, d, e, f, x): return Dist(d/(sqrt(a - b*tan(e + f*x))*sqrt(a + b*tan(e + f*x))*cos(e + f*x)), Int(sqrt(d/cos(e + f*x))*sqrt(a - b*tan(e + f*x)), x), x) def replacement3511(a, b, d, e, f, x): return Dist(d/(sqrt(a - b/tan(e + f*x))*sqrt(a + b/tan(e + f*x))*sin(e + f*x)), Int(sqrt(d/sin(e + f*x))*sqrt(a - b/tan(e + f*x)), x), x) def replacement3512(a, b, d, e, f, m, n, x): return -Dist(d**S(2)*(m + S(-2))/(b**S(2)*(m + S(2)*n)), Int((d/cos(e + f*x))**(m + S(-2))*(a + b*tan(e + f*x))**(n + S(2)), x), x) + Simp(S(2)*d**S(2)*(d/cos(e + f*x))**(m + S(-2))*(a + b*tan(e + f*x))**(n + S(1))/(b*f*(m + S(2)*n)), x) def replacement3513(a, b, d, e, f, m, n, x): return -Dist(d**S(2)*(m + S(-2))/(b**S(2)*(m + S(2)*n)), Int((d/sin(e + f*x))**(m + S(-2))*(a + b/tan(e + f*x))**(n + S(2)), x), x) + Simp(-S(2)*d**S(2)*(d/sin(e + f*x))**(m + S(-2))*(a + b/tan(e + f*x))**(n + S(1))/(b*f*(m + S(2)*n)), x) def replacement3514(a, b, d, e, f, m, n, x): return Dist(d**S(2)*(m + S(-2))/(a*(m + n + S(-1))), Int((d/cos(e + f*x))**(m + S(-2))*(a + b*tan(e + f*x))**(n + S(1)), x), x) + Simp(d**S(2)*(d/cos(e + f*x))**(m + S(-2))*(a + b*tan(e + f*x))**(n + S(1))/(b*f*(m + n + S(-1))), x) def replacement3515(a, b, d, e, f, m, n, x): return Dist(d**S(2)*(m + S(-2))/(a*(m + n + S(-1))), Int((d/sin(e + f*x))**(m + S(-2))*(a + b/tan(e + f*x))**(n + S(1)), x), x) - Simp(d**S(2)*(d/sin(e + f*x))**(m + S(-2))*(a + b/tan(e + f*x))**(n + S(1))/(b*f*(m + n + S(-1))), x) def replacement3516(a, b, d, e, f, m, n, x): return Dist((m + n)/(a*(m + S(2)*n)), Int((d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(1)), x), x) + Simp(a*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**n/(b*f*(m + S(2)*n)), x) def replacement3517(a, b, d, e, f, m, n, x): return Dist((m + n)/(a*(m + S(2)*n)), Int((d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(1)), x), x) - Simp(a*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**n/(b*f*(m + S(2)*n)), x) def replacement3518(a, b, d, e, f, m, n, x): return Dist(a*(m + S(2)*n + S(-2))/(m + n + S(-1)), Int((d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1)), x), x) + Simp(b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3519(a, b, d, e, f, m, n, x): return Dist(a*(m + S(2)*n + S(-2))/(m + n + S(-1)), Int((d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1)), x), x) - Simp(b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3520(a, b, d, e, f, m, n, x): return Dist((m + n)/(a*(m + S(2)*n)), Int((d/cos(e + f*x))**m*(a + b*tan(e + f*x))**(n + S(1)), x), x) + Simp(a*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))**n/(b*f*(m + S(2)*n)), x) def replacement3521(a, b, d, e, f, m, n, x): return Dist((m + n)/(a*(m + S(2)*n)), Int((d/sin(e + f*x))**m*(a + b/tan(e + f*x))**(n + S(1)), x), x) - Simp(a*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))**n/(b*f*(m + S(2)*n)), x) def replacement3522(a, b, d, e, f, m, n, x): return Dist((d/cos(e + f*x))**m*(a - b*tan(e + f*x))**(-m/S(2))*(a + b*tan(e + f*x))**(-m/S(2)), Int((a - b*tan(e + f*x))**(m/S(2))*(a + b*tan(e + f*x))**(m/S(2) + n), x), x) def replacement3523(a, b, d, e, f, m, n, x): return Dist((d/sin(e + f*x))**m*(a - b/tan(e + f*x))**(-m/S(2))*(a + b/tan(e + f*x))**(-m/S(2)), Int((a - b/tan(e + f*x))**(m/S(2))*(a + b/tan(e + f*x))**(m/S(2) + n), x), x) def replacement3524(a, b, e, f, m, n, x): return Dist(S(1)/(b*f), Subst(Int((S(1) + x**S(2)/b**S(2))**(m/S(2) + S(-1))*(a + x)**n, x), x, b*tan(e + f*x)), x) def replacement3525(a, b, e, f, m, n, x): return -Dist(S(1)/(b*f), Subst(Int((S(1) + x**S(2)/b**S(2))**(m/S(2) + S(-1))*(a + x)**n, x), x, b/tan(e + f*x)), x) def replacement3526(a, b, e, f, x): return Simp(b**S(2)*atanh(sin(e + f*x))/f, x) + Simp((a**S(2) - b**S(2))*sin(e + f*x)/f, x) - Simp(S(2)*a*b*cos(e + f*x)/f, x) def replacement3527(a, b, e, f, x): return -Simp(b**S(2)*atanh(cos(e + f*x))/f, x) - Simp((a**S(2) - b**S(2))*cos(e + f*x)/f, x) + Simp(S(2)*a*b*sin(e + f*x)/f, x) def replacement3528(a, b, d, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((d/cos(e + f*x))**m*(a**S(2)*(m + S(1)) + a*b*(m + S(2))*tan(e + f*x) - b**S(2)), x), x) + Simp(b*(d/cos(e + f*x))**m*(a + b*tan(e + f*x))/(f*(m + S(1))), x) def replacement3529(a, b, d, e, f, m, x): return Dist(S(1)/(m + S(1)), Int((d/sin(e + f*x))**m*(a**S(2)*(m + S(1)) + a*b*(m + S(2))/tan(e + f*x) - b**S(2)), x), x) - Simp(b*(d/sin(e + f*x))**m*(a + b/tan(e + f*x))/(f*(m + S(1))), x) def replacement3530(a, b, e, f, x): return -Dist(S(1)/f, Subst(Int(S(1)/(a**S(2) + b**S(2) - x**S(2)), x), x, (-a*tan(e + f*x) + b)*cos(e + f*x)), x) def replacement3531(a, b, e, f, x): return Dist(S(1)/f, Subst(Int(S(1)/(a**S(2) + b**S(2) - x**S(2)), x), x, (-a/tan(e + f*x) + b)*sin(e + f*x)), x) def replacement3532(a, b, d, e, f, m, x): return -Dist(d**S(2)/b**S(2), Int((d/cos(e + f*x))**(m + S(-2))*(a - b*tan(e + f*x)), x), x) + Dist(d**S(2)*(a**S(2) + b**S(2))/b**S(2), Int((d/cos(e + f*x))**(m + S(-2))/(a + b*tan(e + f*x)), x), x) def replacement3533(a, b, d, e, f, m, x): return -Dist(d**S(2)/b**S(2), Int((d/sin(e + f*x))**(m + S(-2))*(a - b/tan(e + f*x)), x), x) + Dist(d**S(2)*(a**S(2) + b**S(2))/b**S(2), Int((d/sin(e + f*x))**(m + S(-2))/(a + b/tan(e + f*x)), x), x) def replacement3534(a, b, d, e, f, m, x): return Dist(b**S(2)/(d**S(2)*(a**S(2) + b**S(2))), Int((d/cos(e + f*x))**(m + S(2))/(a + b*tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((d/cos(e + f*x))**m*(a - b*tan(e + f*x)), x), x) def replacement3535(a, b, d, e, f, m, x): return Dist(b**S(2)/(d**S(2)*(a**S(2) + b**S(2))), Int((d/sin(e + f*x))**(m + S(2))/(a + b/tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((d/sin(e + f*x))**m*(a - b/tan(e + f*x)), x), x) def replacement3536(a, b, d, e, f, m, n, x): return Dist(d**(S(2)*IntPart(m/S(2)))*(d/cos(e + f*x))**(S(2)*FracPart(m/S(2)))*(cos(e + f*x)**(S(-2)))**(-FracPart(m/S(2)))/(b*f), Subst(Int((S(1) + x**S(2)/b**S(2))**(m/S(2) + S(-1))*(a + x)**n, x), x, b*tan(e + f*x)), x) def replacement3537(a, b, d, e, f, m, n, x): return -Dist(d**(S(2)*IntPart(m/S(2)))*(d/sin(e + f*x))**(S(2)*FracPart(m/S(2)))*(sin(e + f*x)**(S(-2)))**(-FracPart(m/S(2)))/(b*f), Subst(Int((S(1) + x**S(2)/b**S(2))**(m/S(2) + S(-1))*(a + x)**n, x), x, b/tan(e + f*x)), x) def replacement3538(a, b, d, e, f, x): return Dist(-S(4)*b/f, Subst(Int(x**S(2)/(a**S(2)*d**S(2) + x**S(4)), x), x, sqrt(d*cos(e + f*x))*sqrt(a + b*tan(e + f*x))), x) def replacement3539(a, b, d, e, f, x): return Dist(S(4)*b/f, Subst(Int(x**S(2)/(a**S(2)*d**S(2) + x**S(4)), x), x, sqrt(d*sin(e + f*x))*sqrt(a + b/tan(e + f*x))), x) def replacement3540(a, b, d, e, f, x): return Dist(S(1)/(d*sqrt(a - b*tan(e + f*x))*sqrt(a + b*tan(e + f*x))*cos(e + f*x)), Int(sqrt(a - b*tan(e + f*x))/sqrt(d*cos(e + f*x)), x), x) def replacement3541(a, b, d, e, f, x): return Dist(S(1)/(d*sqrt(a - b/tan(e + f*x))*sqrt(a + b/tan(e + f*x))*sin(e + f*x)), Int(sqrt(a - b/tan(e + f*x))/sqrt(d*sin(e + f*x)), x), x) def replacement3542(a, b, d, e, f, m, n, x): return Dist((d/cos(e + f*x))**m*(d*cos(e + f*x))**m, Int((d/cos(e + f*x))**(-m)*(a + b*tan(e + f*x))**n, x), x) def replacement3543(a, b, d, e, f, m, n, x): return Dist((d/sin(e + f*x))**m*(d*sin(e + f*x))**m, Int((d/sin(e + f*x))**(-m)*(a + b/tan(e + f*x))**n, x), x) def replacement3544(a, b, e, f, m, n, x): return Dist(b/f, Subst(Int(x**m*(a + x)**n*(b**S(2) + x**S(2))**(-m/S(2) + S(-1)), x), x, b*tan(e + f*x)), x) def replacement3545(a, b, e, f, m, n, x): return -Dist(b/f, Subst(Int(x**m*(a + x)**n*(b**S(2) + x**S(2))**(-m/S(2) + S(-1)), x), x, b/tan(e + f*x)), x) def replacement3546(a, b, e, f, m, n, x): return Int((a + b*tan(e + f*x))**n*sin(e + f*x)**m, x) def replacement3547(a, b, e, f, m, n, x): return Int((a + b/tan(e + f*x))**n*cos(e + f*x)**m, x) def replacement3548(a, b, e, f, m, n, x): return Int((a*cos(e + f*x) + b*sin(e + f*x))**n*sin(e + f*x)**m*cos(e + f*x)**(-n), x) def replacement3549(a, b, e, f, m, n, x): return Int((a*sin(e + f*x) + b*cos(e + f*x))**n*sin(e + f*x)**(-n)*cos(e + f*x)**m, x) def replacement3550(a, b, d, e, f, m, n, x): return Dist((sin(e + f*x)/d)**FracPart(m)*(d/sin(e + f*x))**FracPart(m), Int((sin(e + f*x)/d)**(-m)*(a + b*tan(e + f*x))**n, x), x) def replacement3551(a, b, d, e, f, m, n, x): return Dist((cos(e + f*x)/d)**FracPart(m)*(d/cos(e + f*x))**FracPart(m), Int((cos(e + f*x)/d)**(-m)*(a + b/tan(e + f*x))**n, x), x) def replacement3552(a, b, e, f, m, n, p, x): return Int((a*cos(e + f*x) + b*sin(e + f*x))**n*sin(e + f*x)**p*cos(e + f*x)**(m - n), x) def replacement3553(a, b, e, f, m, n, p, x): return Int((a*sin(e + f*x) + b*cos(e + f*x))**n*sin(e + f*x)**(m - n)*cos(e + f*x)**p, x) def replacement3554(a, b, c, d, e, f, m, n, x): return Dist(a**m*c**m, Int((c + d*tan(e + f*x))**(-m + n)*(S(1)/cos(e + f*x))**(S(2)*m), x), x) def replacement3555(a, b, c, d, e, f, m, n, x): return Dist(a**m*c**m, Int((c + d/tan(e + f*x))**(-m + n)*(S(1)/sin(e + f*x))**(S(2)*m), x), x) def replacement3556(a, b, c, d, e, f, m, n, x): return Dist(a*c/f, Subst(Int((a + b*x)**(m + S(-1))*(c + d*x)**(n + S(-1)), x), x, tan(e + f*x)), x) def replacement3557(a, b, c, d, e, f, m, n, x): return -Dist(a*c/f, Subst(Int((a + b*x)**(m + S(-1))*(c + d*x)**(n + S(-1)), x), x, S(1)/tan(e + f*x)), x) def replacement3558(a, b, c, d, e, f, x): return Simp(x*(a*c - b*d), x) + Simp(b*d*tan(e + f*x)/f, x) def replacement3559(a, b, c, d, e, f, x): return Simp(x*(a*c - b*d), x) - Simp(b*d/(f*tan(e + f*x)), x) def replacement3560(a, b, c, d, e, f, x): return Dist(a*d + b*c, Int(tan(e + f*x), x), x) + Simp(x*(a*c - b*d), x) + Simp(b*d*tan(e + f*x)/f, x) def replacement3561(a, b, c, d, e, f, x): return Dist(a*d + b*c, Int(S(1)/tan(e + f*x), x), x) + Simp(x*(a*c - b*d), x) - Simp(b*d/(f*tan(e + f*x)), x) def replacement3562(a, b, c, d, e, f, m, x): return Dist((a*d + b*c)/(S(2)*a*b), Int((a + b*tan(e + f*x))**(m + S(1)), x), x) - Simp((a + b*tan(e + f*x))**m*(-a*d + b*c)/(S(2)*a*f*m), x) def replacement3563(a, b, c, d, e, f, m, x): return Dist((a*d + b*c)/(S(2)*a*b), Int((a + b/tan(e + f*x))**(m + S(1)), x), x) + Simp((a + b/tan(e + f*x))**m*(-a*d + b*c)/(S(2)*a*f*m), x) def replacement3564(a, b, c, d, e, f, m, x): return Dist((a*d + b*c)/b, Int((a + b*tan(e + f*x))**m, x), x) + Simp(d*(a + b*tan(e + f*x))**m/(f*m), x) def replacement3565(a, b, c, d, e, f, m, x): return Dist((a*d + b*c)/b, Int((a + b/tan(e + f*x))**m, x), x) - Simp(d*(a + b/tan(e + f*x))**m/(f*m), x) def replacement3566(a, b, c, d, e, f, m, x): return Int((a + b*tan(e + f*x))**(m + S(-1))*Simp(a*c - b*d + (a*d + b*c)*tan(e + f*x), x), x) + Simp(d*(a + b*tan(e + f*x))**m/(f*m), x) def replacement3567(a, b, c, d, e, f, m, x): return Int((a + b/tan(e + f*x))**(m + S(-1))*Simp(a*c - b*d + (a*d + b*c)/tan(e + f*x), x), x) - Simp(d*(a + b/tan(e + f*x))**m/(f*m), x) def replacement3568(a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(a*c + b*d - (-a*d + b*c)*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(-a*d + b*c)/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3569(a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(a*c + b*d - (-a*d + b*c)/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(-a*d + b*c)/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3570(a, b, c, d, e, f, x): return Simp(c*log(RemoveContent(a*cos(e + f*x) + b*sin(e + f*x), x))/(b*f), x) def replacement3571(a, b, c, d, e, f, x): return -Simp(c*log(RemoveContent(a*sin(e + f*x) + b*cos(e + f*x), x))/(b*f), x) def replacement3572(a, b, c, d, e, f, x): return Dist((-a*d + b*c)/(a**S(2) + b**S(2)), Int((-a*tan(e + f*x) + b)/(a + b*tan(e + f*x)), x), x) + Simp(x*(a*c + b*d)/(a**S(2) + b**S(2)), x) def replacement3573(a, b, c, d, e, f, x): return Dist((-a*d + b*c)/(a**S(2) + b**S(2)), Int((-a/tan(e + f*x) + b)/(a + b/tan(e + f*x)), x), x) + Simp(x*(a*c + b*d)/(a**S(2) + b**S(2)), x) def replacement3574(b, c, d, e, f, x): return Dist(-S(2)*d**S(2)/f, Subst(Int(S(1)/(b*x**S(2) + S(2)*c*d), x), x, (c - d*tan(e + f*x))/sqrt(b*tan(e + f*x))), x) def replacement3575(b, c, d, e, f, x): return Dist(S(2)*d**S(2)/f, Subst(Int(S(1)/(b*x**S(2) + S(2)*c*d), x), x, (c - d/tan(e + f*x))/sqrt(b/tan(e + f*x))), x) def replacement3576(b, c, d, e, f, x): return Dist(S(2)*c**S(2)/f, Subst(Int(S(1)/(b*c - d*x**S(2)), x), x, sqrt(b*tan(e + f*x))), x) def replacement3577(b, c, d, e, f, x): return Dist(-S(2)*c**S(2)/f, Subst(Int(S(1)/(b*c - d*x**S(2)), x), x, sqrt(b/tan(e + f*x))), x) def replacement3578(b, c, d, e, f, x): return Dist(S(2)/f, Subst(Int((b*c + d*x**S(2))/(b**S(2) + x**S(4)), x), x, sqrt(b*tan(e + f*x))), x) def replacement3579(b, c, d, e, f, x): return Dist(-S(2)/f, Subst(Int((b*c + d*x**S(2))/(b**S(2) + x**S(4)), x), x, sqrt(b/tan(e + f*x))), x) def replacement3580(a, b, c, d, e, f, x): return Dist(-S(2)*d**S(2)/f, Subst(Int(S(1)/(-S(4)*a*d**S(2) + S(2)*b*c*d + x**S(2)), x), x, (-S(2)*a*d + b*c - b*d*tan(e + f*x))/sqrt(a + b*tan(e + f*x))), x) def replacement3581(a, b, c, d, e, f, x): return Dist(S(2)*d**S(2)/f, Subst(Int(S(1)/(-S(4)*a*d**S(2) + S(2)*b*c*d + x**S(2)), x), x, (-S(2)*a*d + b*c - b*d/tan(e + f*x))/sqrt(a + b/tan(e + f*x))), x) def With3582(a, b, c, d, e, f, x): q = Rt(a**S(2) + b**S(2), S(2)) return -Dist(S(1)/(S(2)*q), Int((a*c + b*d - c*q + (-a*d + b*c - d*q)*tan(e + f*x))/sqrt(a + b*tan(e + f*x)), x), x) + Dist(S(1)/(S(2)*q), Int((a*c + b*d + c*q + (-a*d + b*c + d*q)*tan(e + f*x))/sqrt(a + b*tan(e + f*x)), x), x) def With3583(a, b, c, d, e, f, x): q = Rt(a**S(2) + b**S(2), S(2)) return -Dist(S(1)/(S(2)*q), Int((a*c + b*d - c*q + (-a*d + b*c - d*q)/tan(e + f*x))/sqrt(a + b/tan(e + f*x)), x), x) + Dist(S(1)/(S(2)*q), Int((a*c + b*d + c*q + (-a*d + b*c + d*q)/tan(e + f*x))/sqrt(a + b/tan(e + f*x)), x), x) def replacement3584(a, b, c, d, e, f, m, x): return Dist(c*d/f, Subst(Int((a + b*x/d)**m/(c*x + d**S(2)), x), x, d*tan(e + f*x)), x) def replacement3585(a, b, c, d, e, f, m, x): return -Dist(c*d/f, Subst(Int((a + b*x/d)**m/(c*x + d**S(2)), x), x, d/tan(e + f*x)), x) def replacement3586(b, c, d, e, f, m, x): return Dist(c, Int((b*tan(e + f*x))**m, x), x) + Dist(d/b, Int((b*tan(e + f*x))**(m + S(1)), x), x) def replacement3587(b, c, d, e, f, m, x): return Dist(c, Int((b/tan(e + f*x))**m, x), x) + Dist(d/b, Int((b/tan(e + f*x))**(m + S(1)), x), x) def replacement3588(a, b, c, d, e, f, m, x): return Dist(c/S(2) - I*d/S(2), Int((a + b*tan(e + f*x))**m*(I*tan(e + f*x) + S(1)), x), x) + Dist(c/S(2) + I*d/S(2), Int((a + b*tan(e + f*x))**m*(-I*tan(e + f*x) + S(1)), x), x) def replacement3589(a, b, c, d, e, f, m, x): return Dist(c/S(2) - I*d/S(2), Int((S(1) + I/tan(e + f*x))*(a + b/tan(e + f*x))**m, x), x) + Dist(c/S(2) + I*d/S(2), Int((S(1) - I/tan(e + f*x))*(a + b/tan(e + f*x))**m, x), x) def replacement3590(a, b, c, d, e, f, m, x): return Dist(S(1)/(S(2)*a**S(2)), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(a*c**S(2) + a*d**S(2) - S(2)*b*c*d - S(2)*b*d**S(2)*tan(e + f*x), x), x), x) - Simp(b*(a + b*tan(e + f*x))**m*(a*c + b*d)**S(2)/(S(2)*a**S(3)*f*m), x) def replacement3591(a, b, c, d, e, f, m, x): return Dist(S(1)/(S(2)*a**S(2)), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(a*c**S(2) + a*d**S(2) - S(2)*b*c*d - S(2)*b*d**S(2)/tan(e + f*x), x), x), x) + Simp(b*(a + b/tan(e + f*x))**m*(a*c + b*d)**S(2)/(S(2)*a**S(3)*f*m), x) def replacement3592(a, b, c, d, e, f, x): return Dist((-a*d + b*c)**S(2)/b**S(2), Int(S(1)/(a + b*tan(e + f*x)), x), x) + Dist(d**S(2)/b, Int(tan(e + f*x), x), x) + Simp(d*x*(-a*d + S(2)*b*c)/b**S(2), x) def replacement3593(a, b, c, d, e, f, x): return Dist((-a*d + b*c)**S(2)/b**S(2), Int(S(1)/(a + b/tan(e + f*x)), x), x) + Dist(d**S(2)/b, Int(S(1)/tan(e + f*x), x), x) + Simp(d*x*(-a*d + S(2)*b*c)/b**S(2), x) def replacement3594(a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(a*c**S(2) - a*d**S(2) + S(2)*b*c*d - (-S(2)*a*c*d + b*c**S(2) - b*d**S(2))*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(-a*d + b*c)**S(2)/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3595(a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(a*c**S(2) - a*d**S(2) + S(2)*b*c*d - (-S(2)*a*c*d + b*c**S(2) - b*d**S(2))/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(-a*d + b*c)**S(2)/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3596(a, b, c, d, e, f, m, x): return Int((a + b*tan(e + f*x))**m*Simp(c**S(2) + S(2)*c*d*tan(e + f*x) - d**S(2), x), x) + Simp(d**S(2)*(a + b*tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3597(a, b, c, d, e, f, m, x): return Int((a + b/tan(e + f*x))**m*Simp(c**S(2) + S(2)*c*d/tan(e + f*x) - d**S(2), x), x) - Simp(d**S(2)*(a + b/tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3598(a, b, c, d, e, f, x): return Dist(-S(2)*a*b/f, Subst(Int(S(1)/(-S(2)*a**S(2)*x**S(2) + a*c - b*d), x), x, sqrt(c + d*tan(e + f*x))/sqrt(a + b*tan(e + f*x))), x) def replacement3599(a, b, c, d, e, f, x): return Dist(S(2)*a*b/f, Subst(Int(S(1)/(-S(2)*a**S(2)*x**S(2) + a*c - b*d), x), x, sqrt(c + d/tan(e + f*x))/sqrt(a + b/tan(e + f*x))), x) def replacement3600(a, b, c, d, e, f, m, n, x): return Dist(S(2)*a**S(2)/(a*c - b*d), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1)), x), x) + Simp(a*b*(a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))/(f*(m + S(-1))*(a*c - b*d)), x) def replacement3601(a, b, c, d, e, f, m, n, x): return Dist(S(2)*a**S(2)/(a*c - b*d), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1)), x), x) - Simp(a*b*(a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))/(f*(m + S(-1))*(a*c - b*d)), x) def replacement3602(a, b, c, d, e, f, m, n, x): return -Dist((a*c - b*d)/(S(2)*b**S(2)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(-1)), x), x) + Simp(a*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n/(S(2)*b*f*m), x) def replacement3603(a, b, c, d, e, f, m, n, x): return -Dist((a*c - b*d)/(S(2)*b**S(2)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(-1)), x), x) - Simp(a*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n/(S(2)*b*f*m), x) def replacement3604(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n, x), x) + Simp(a*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(S(2)*f*m*(-a*d + b*c)), x) def replacement3605(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n, x), x) - Simp(a*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(S(2)*f*m*(-a*d + b*c)), x) def replacement3606(a, b, c, d, e, f, m, n, x): return Dist(a/(a*c - b*d), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1)), x), x) - Simp(d*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(f*m*(c**S(2) + d**S(2))), x) def replacement3607(a, b, c, d, e, f, m, n, x): return Dist(a/(a*c - b*d), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1)), x), x) + Simp(d*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(f*m*(c**S(2) + d**S(2))), x) def replacement3608(a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*a*(-a*d + b*c)), Int((c + d*tan(e + f*x))**(n + S(-1))*Simp(a*c*d*(n + S(-1)) + b*c**S(2) + b*d**S(2)*n - d*(n + S(-1))*(-a*d + b*c)*tan(e + f*x), x), x), x) - Simp((c + d*tan(e + f*x))**n*(a*c + b*d)/(S(2)*f*(a + b*tan(e + f*x))*(-a*d + b*c)), x) def replacement3609(a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*a*(-a*d + b*c)), Int((c + d/tan(e + f*x))**(n + S(-1))*Simp(a*c*d*(n + S(-1)) + b*c**S(2) + b*d**S(2)*n - d*(n + S(-1))*(-a*d + b*c)/tan(e + f*x), x), x), x) + Simp((c + d/tan(e + f*x))**n*(a*c + b*d)/(S(2)*f*(a + b/tan(e + f*x))*(-a*d + b*c)), x) def replacement3610(a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*a**S(2)), Int((c + d*tan(e + f*x))**(n + S(-2))*Simp(a*c**S(2) + a*d**S(2)*(n + S(-1)) - b*c*d*n - d*(a*c*(n + S(-2)) + b*d*n)*tan(e + f*x), x), x), x) + Simp((c + d*tan(e + f*x))**(n + S(-1))*(-a*d + b*c)/(S(2)*a*f*(a + b*tan(e + f*x))), x) def replacement3611(a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*a**S(2)), Int((c + d/tan(e + f*x))**(n + S(-2))*Simp(a*c**S(2) + a*d**S(2)*(n + S(-1)) - b*c*d*n - d*(a*c*(n + S(-2)) + b*d*n)/tan(e + f*x), x), x), x) - Simp((c + d/tan(e + f*x))**(n + S(-1))*(-a*d + b*c)/(S(2)*a*f*(a + b/tan(e + f*x))), x) def replacement3612(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/(a + b*tan(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/(c + d*tan(e + f*x)), x), x) def replacement3613(a, b, c, d, e, f, x): return Dist(b/(-a*d + b*c), Int(S(1)/(a + b/tan(e + f*x)), x), x) - Dist(d/(-a*d + b*c), Int(S(1)/(c + d/tan(e + f*x)), x), x) def replacement3614(a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*a*(-a*d + b*c)), Int((c + d*tan(e + f*x))**n*Simp(a*d*(n + S(-1)) + b*c - b*d*n*tan(e + f*x), x), x), x) - Simp(a*(c + d*tan(e + f*x))**(n + S(1))/(S(2)*f*(a + b*tan(e + f*x))*(-a*d + b*c)), x) def replacement3615(a, b, c, d, e, f, n, x): return Dist(S(1)/(S(2)*a*(-a*d + b*c)), Int((c + d/tan(e + f*x))**n*Simp(a*d*(n + S(-1)) + b*c - b*d*n/tan(e + f*x), x), x), x) + Simp(a*(c + d/tan(e + f*x))**(n + S(1))/(S(2)*f*(a + b/tan(e + f*x))*(-a*d + b*c)), x) def replacement3616(a, b, c, d, e, f, m, n, x): return Dist(a/(d*(n + S(1))*(a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**(n + S(1))*Simp(b*(-a*d*(m - S(2)*n + S(-4)) + b*c*(m + S(-2))) + (-a**S(2)*d*(m + n + S(-1)) + a*b*c*(m + S(-2)) + b**S(2)*d*(n + S(1)))*tan(e + f*x), x), x), x) - Simp(a**S(2)*(a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**(n + S(1))*(-a*d + b*c)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement3617(a, b, c, d, e, f, m, n, x): return Dist(a/(d*(n + S(1))*(a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**(n + S(1))*Simp(b*(-a*d*(m - S(2)*n + S(-4)) + b*c*(m + S(-2))) + (-a**S(2)*d*(m + n + S(-1)) + a*b*c*(m + S(-2)) + b**S(2)*d*(n + S(1)))/tan(e + f*x), x), x), x) + Simp(a**S(2)*(a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**(n + S(1))*(-a*d + b*c)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement3618(a, b, c, d, e, f, x): return Dist(S(2)*a**S(2)/(a*c - b*d), Int(sqrt(a + b*tan(e + f*x)), x), x) - Dist((a*(c**S(2) - d**S(2)) + S(2)*b*c*d)/(a*(c**S(2) + d**S(2))), Int((a - b*tan(e + f*x))*sqrt(a + b*tan(e + f*x))/(c + d*tan(e + f*x)), x), x) def replacement3619(a, b, c, d, e, f, x): return Dist(S(2)*a**S(2)/(a*c - b*d), Int(sqrt(a + b/tan(e + f*x)), x), x) - Dist((a*(c**S(2) - d**S(2)) + S(2)*b*c*d)/(a*(c**S(2) + d**S(2))), Int((a - b/tan(e + f*x))*sqrt(a + b/tan(e + f*x))/(c + d/tan(e + f*x)), x), x) def replacement3620(a, b, c, d, e, f, x): return Dist(S(2)*a, Int(sqrt(a + b*tan(e + f*x))/sqrt(c + d*tan(e + f*x)), x), x) + Dist(b/a, Int(sqrt(a + b*tan(e + f*x))*(a*tan(e + f*x) + b)/sqrt(c + d*tan(e + f*x)), x), x) def replacement3621(a, b, c, d, e, f, x): return Dist(S(2)*a, Int(sqrt(a + b/tan(e + f*x))/sqrt(c + d/tan(e + f*x)), x), x) + Dist(b/a, Int(sqrt(a + b/tan(e + f*x))*(a/tan(e + f*x) + b)/sqrt(c + d/tan(e + f*x)), x), x) def replacement3622(a, b, c, d, e, f, m, n, x): return Dist(a/(d*(m + n + S(-1))), Int((a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**n*Simp(a*d*(m + S(2)*n) + b*c*(m + S(-2)) + (a*c*(m + S(-2)) + b*d*(S(3)*m + S(2)*n + S(-4)))*tan(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(-1))), x) def replacement3623(a, b, c, d, e, f, m, n, x): return Dist(a/(d*(m + n + S(-1))), Int((a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**n*Simp(a*d*(m + S(2)*n) + b*c*(m + S(-2)) + (a*c*(m + S(-2)) + b*d*(S(3)*m + S(2)*n + S(-4)))/tan(e + f*x), x), x), x) - Simp(b**S(2)*(a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(-1))), x) def replacement3624(a, b, c, d, e, f, m, x): return Dist(S(1)/(S(4)*a**S(2)*m), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(S(2)*a*c*m + a*d*(S(2)*m + S(1))*tan(e + f*x) + b*d, x)/sqrt(c + d*tan(e + f*x)), x), x) - Simp(b*(a + b*tan(e + f*x))**m*sqrt(c + d*tan(e + f*x))/(S(2)*a*f*m), x) def replacement3625(a, b, c, d, e, f, m, x): return Dist(S(1)/(S(4)*a**S(2)*m), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(S(2)*a*c*m + a*d*(S(2)*m + S(1))/tan(e + f*x) + b*d, x)/sqrt(c + d/tan(e + f*x)), x), x) + Simp(b*(a + b/tan(e + f*x))**m*sqrt(c + d/tan(e + f*x))/(S(2)*a*f*m), x) def replacement3626(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(-2))*Simp(c*(a*c*m + b*d*(n + S(-1))) - d*(-a*c*(m + n + S(-1)) + b*d*(m - n + S(1)))*tan(e + f*x) - d*(a*d*(n + S(-1)) + b*c*m), x), x), x) - Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(-1))*(-a*d + b*c)/(S(2)*a*f*m), x) def replacement3627(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(-2))*Simp(c*(a*c*m + b*d*(n + S(-1))) - d*(-a*c*(m + n + S(-1)) + b*d*(m - n + S(1)))/tan(e + f*x) - d*(a*d*(n + S(-1)) + b*c*m), x), x), x) + Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(-1))*(-a*d + b*c)/(S(2)*a*f*m), x) def replacement3628(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(-a*d*(S(2)*m + n + S(1)) + b*c*m + b*d*(m + n + S(1))*tan(e + f*x), x), x), x) + Simp(a*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(S(2)*f*m*(-a*d + b*c)), x) def replacement3629(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(-a*d*(S(2)*m + n + S(1)) + b*c*m + b*d*(m + n + S(1))/tan(e + f*x), x), x), x) - Simp(a*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(S(2)*f*m*(-a*d + b*c)), x) def replacement3630(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*(m + n + S(-1))), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(-2))*Simp(-a*c**S(2)*(m + n + S(-1)) + d*(-a*c*(m + S(2)*n + S(-2)) + b*d*m)*tan(e + f*x) + d*(a*d*(n + S(-1)) + b*c*m), x), x), x) + Simp(d*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3631(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*(m + n + S(-1))), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(-2))*Simp(-a*c**S(2)*(m + n + S(-1)) + d*(-a*c*(m + S(2)*n + S(-2)) + b*d*m)/tan(e + f*x) + d*(a*d*(n + S(-1)) + b*c*m), x), x), x) - Simp(d*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(-1))/(f*(m + n + S(-1))), x) def replacement3632(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*Simp(-a*c*(n + S(1)) + a*d*(m + n + S(1))*tan(e + f*x) + b*d*m, x), x), x) + Simp(d*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3633(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*Simp(-a*c*(n + S(1)) + a*d*(m + n + S(1))/tan(e + f*x) + b*d*m, x), x), x) - Simp(d*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3634(a, b, c, d, e, f, m, x): return Dist(a/(a*c - b*d), Int((a + b*tan(e + f*x))**m, x), x) - Dist(d/(a*c - b*d), Int((a + b*tan(e + f*x))**m*(a*tan(e + f*x) + b)/(c + d*tan(e + f*x)), x), x) def replacement3635(a, b, c, d, e, f, m, x): return Dist(a/(a*c - b*d), Int((a + b/tan(e + f*x))**m, x), x) - Dist(d/(a*c - b*d), Int((a + b/tan(e + f*x))**m*(a/tan(e + f*x) + b)/(c + d/tan(e + f*x)), x), x) def replacement3636(a, b, c, d, e, f, x): return Dist(d/a, Int(sqrt(a + b*tan(e + f*x))*(a*tan(e + f*x) + b)/sqrt(c + d*tan(e + f*x)), x), x) + Dist((a*c - b*d)/a, Int(sqrt(a + b*tan(e + f*x))/sqrt(c + d*tan(e + f*x)), x), x) def replacement3637(a, b, c, d, e, f, x): return Dist(d/a, Int(sqrt(a + b/tan(e + f*x))*(a/tan(e + f*x) + b)/sqrt(c + d/tan(e + f*x)), x), x) + Dist((a*c - b*d)/a, Int(sqrt(a + b/tan(e + f*x))/sqrt(c + d/tan(e + f*x)), x), x) def replacement3638(a, b, c, d, e, f, m, n, x): return Dist(a*b/f, Subst(Int((a + x)**(m + S(-1))*(c + d*x/b)**n/(a*x + b**S(2)), x), x, b*tan(e + f*x)), x) def replacement3639(a, b, c, d, e, f, m, n, x): return -Dist(a*b/f, Subst(Int((a + x)**(m + S(-1))*(c + d*x/b)**n/(a*x + b**S(2)), x), x, b/tan(e + f*x)), x) def replacement3640(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**(m + S(-3))*(c + d*tan(e + f*x))**(n + S(1))*Simp(a**S(2)*d*(-a*c*(n + S(1)) + b*d*(m + S(-2))) + b*(-S(2)*a*d + b*c)*(a*d*(n + S(1)) + b*c*(m + S(-2))) - b*(a*d*(-a*d + S(2)*b*c)*(m + n + S(-1)) - b**S(2)*(c**S(2)*(m + S(-2)) - d**S(2)*(n + S(1))))*tan(e + f*x)**S(2) - d*(n + S(1))*(-a**S(3)*d + S(3)*a**S(2)*b*c + S(3)*a*b**S(2)*d - b**S(3)*c)*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**(n + S(1))*(-a*d + b*c)**S(2)/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3641(a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**(m + S(-3))*(c + d/tan(e + f*x))**(n + S(1))*Simp(a**S(2)*d*(-a*c*(n + S(1)) + b*d*(m + S(-2))) + b*(-S(2)*a*d + b*c)*(a*d*(n + S(1)) + b*c*(m + S(-2))) - b*(a*d*(-a*d + S(2)*b*c)*(m + n + S(-1)) - b**S(2)*(c**S(2)*(m + S(-2)) - d**S(2)*(n + S(1))))/tan(e + f*x)**S(2) - d*(n + S(1))*(-a**S(3)*d + S(3)*a**S(2)*b*c + S(3)*a*b**S(2)*d - b**S(3)*c)/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**(n + S(1))*(-a*d + b*c)**S(2)/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3642(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(-1))), Int((a + b*tan(e + f*x))**(m + S(-3))*(c + d*tan(e + f*x))**n*Simp(a**S(3)*d*(m + n + S(-1)) - b**S(2)*(a*d*(n + S(1)) + b*c*(m + S(-2))) - b**S(2)*(-a*d*(S(3)*m + S(2)*n + S(-4)) + b*c*(m + S(-2)))*tan(e + f*x)**S(2) + b*d*(S(3)*a**S(2) - b**S(2))*(m + n + S(-1))*tan(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(-1))), x) def replacement3643(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(-1))), Int((a + b/tan(e + f*x))**(m + S(-3))*(c + d/tan(e + f*x))**n*Simp(a**S(3)*d*(m + n + S(-1)) - b**S(2)*(a*d*(n + S(1)) + b*c*(m + S(-2))) - b**S(2)*(-a*d*(S(3)*m + S(2)*n + S(-4)) + b*c*(m + S(-2)))/tan(e + f*x)**S(2) + b*d*(S(3)*a**S(2) - b**S(2))*(m + n + S(-1))/tan(e + f*x), x), x), x) - Simp(b**S(2)*(a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(-1))), x) def replacement3644(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(-2))*Simp(a*c**S(2)*(m + S(1)) + a*d**S(2)*(n + S(-1)) + b*c*d*(m - n + S(2)) - d*(m + n)*(-a*d + b*c)*tan(e + f*x)**S(2) - (m + S(1))*(-S(2)*a*c*d + b*c**S(2) - b*d**S(2))*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(-1))*(-a*d + b*c)/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3645(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(-2))*Simp(a*c**S(2)*(m + S(1)) + a*d**S(2)*(n + S(-1)) + b*c*d*(m - n + S(2)) - d*(m + n)*(-a*d + b*c)/tan(e + f*x)**S(2) - (m + S(1))*(-S(2)*a*c*d + b*c**S(2) - b*d**S(2))/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(-1))*(-a*d + b*c)/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3646(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(-1))*Simp(a*c*(m + S(1)) - b*d*n - b*d*(m + n + S(1))*tan(e + f*x)**S(2) - (m + S(1))*(-a*d + b*c)*tan(e + f*x), x), x), x) + Simp(b*(a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3647(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(-1))*Simp(a*c*(m + S(1)) - b*d*n - b*d*(m + n + S(1))/tan(e + f*x)**S(2) - (m + S(1))*(-a*d + b*c)/tan(e + f*x), x), x), x) - Simp(b*(a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3648(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2))*tan(e + f*x)**S(2) - b**S(2)*d*(m + n + S(2)) - b*(m + S(1))*(-a*d + b*c)*tan(e + f*x), x), x), x) + Simp(b**S(2)*(a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(1))/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3649(a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2)) - b**S(2)*d*(m + n + S(2))/tan(e + f*x)**S(2) - b*(m + S(1))*(-a*d + b*c)/tan(e + f*x), x), x), x) - Simp(b**S(2)*(a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(1))/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3650(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(m + n + S(-1)), Int((a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**(n + S(-1))*Simp(a**S(2)*c*(m + n + S(-1)) - b*(a*d*n + b*c*(m + S(-1))) + b*(a*d*(S(2)*m + n + S(-2)) + b*c*n)*tan(e + f*x)**S(2) + (m + n + S(-1))*(a**S(2)*d + S(2)*a*b*c - b**S(2)*d)*tan(e + f*x), x), x), x) + Simp(b*(a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**n/(f*(m + n + S(-1))), x) def replacement3651(a, b, c, d, e, f, m, n, x): return Dist(S(1)/(m + n + S(-1)), Int((a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**(n + S(-1))*Simp(a**S(2)*c*(m + n + S(-1)) - b*(a*d*n + b*c*(m + S(-1))) + b*(a*d*(S(2)*m + n + S(-2)) + b*c*n)/tan(e + f*x)**S(2) + (m + n + S(-1))*(a**S(2)*d + S(2)*a*b*c - b**S(2)*d)/tan(e + f*x), x), x), x) - Simp(b*(a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**n/(f*(m + n + S(-1))), x) def replacement3652(a, b, c, d, e, f, x): return Dist(b**S(2)/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a*tan(e + f*x) + b)/(a + b*tan(e + f*x)), x), x) - Dist(d**S(2)/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c*tan(e + f*x) + d)/(c + d*tan(e + f*x)), x), x) + Simp(x*(a*c - b*d)/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3653(a, b, c, d, e, f, x): return Dist(b**S(2)/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a/tan(e + f*x) + b)/(a + b/tan(e + f*x)), x), x) - Dist(d**S(2)/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c/tan(e + f*x) + d)/(c + d/tan(e + f*x)), x), x) + Simp(x*(a*c - b*d)/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3654(a, b, c, d, e, f, x): return -Dist(d*(-a*d + b*c)/(c**S(2) + d**S(2)), Int((tan(e + f*x)**S(2) + S(1))/(sqrt(a + b*tan(e + f*x))*(c + d*tan(e + f*x))), x), x) + Dist(S(1)/(c**S(2) + d**S(2)), Int(Simp(a*c + b*d + (-a*d + b*c)*tan(e + f*x), x)/sqrt(a + b*tan(e + f*x)), x), x) def replacement3655(a, b, c, d, e, f, x): return -Dist(d*(-a*d + b*c)/(c**S(2) + d**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))/(sqrt(a + b/tan(e + f*x))*(c + d/tan(e + f*x))), x), x) + Dist(S(1)/(c**S(2) + d**S(2)), Int(Simp(a*c + b*d + (-a*d + b*c)/tan(e + f*x), x)/sqrt(a + b/tan(e + f*x)), x), x) def replacement3656(a, b, c, d, e, f, x): return Dist((-a*d + b*c)**S(2)/(c**S(2) + d**S(2)), Int((tan(e + f*x)**S(2) + S(1))/(sqrt(a + b*tan(e + f*x))*(c + d*tan(e + f*x))), x), x) + Dist(S(1)/(c**S(2) + d**S(2)), Int(Simp(a**S(2)*c + S(2)*a*b*d - b**S(2)*c + (-a**S(2)*d + S(2)*a*b*c + b**S(2)*d)*tan(e + f*x), x)/sqrt(a + b*tan(e + f*x)), x), x) def replacement3657(a, b, c, d, e, f, x): return Dist((-a*d + b*c)**S(2)/(c**S(2) + d**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))/(sqrt(a + b/tan(e + f*x))*(c + d/tan(e + f*x))), x), x) + Dist(S(1)/(c**S(2) + d**S(2)), Int(Simp(a**S(2)*c + S(2)*a*b*d - b**S(2)*c + (-a**S(2)*d + S(2)*a*b*c + b**S(2)*d)/tan(e + f*x), x)/sqrt(a + b/tan(e + f*x)), x), x) def replacement3658(a, b, c, d, e, f, m, x): return Dist(d**S(2)/(c**S(2) + d**S(2)), Int((a + b*tan(e + f*x))**m*(tan(e + f*x)**S(2) + S(1))/(c + d*tan(e + f*x)), x), x) + Dist(S(1)/(c**S(2) + d**S(2)), Int((a + b*tan(e + f*x))**m*(c - d*tan(e + f*x)), x), x) def replacement3659(a, b, c, d, e, f, m, x): return Dist(d**S(2)/(c**S(2) + d**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))*(a + b/tan(e + f*x))**m/(c + d/tan(e + f*x)), x), x) + Dist(S(1)/(c**S(2) + d**S(2)), Int((a + b/tan(e + f*x))**m*(c - d/tan(e + f*x)), x), x) def replacement3660(a, b, c, d, e, f, m, n, x): return Dist(b/f, Subst(Int((a + x)**m*(c + d*x/b)**n/(b**S(2) + x**S(2)), x), x, b*tan(e + f*x)), x) def replacement3661(a, b, c, d, e, f, m, n, x): return -Dist(b/f, Subst(Int((a + x)**m*(c + d*x/b)**n/(b**S(2) + x**S(2)), x), x, b/tan(e + f*x)), x) def replacement3662(a, b, d, e, f, m, n, x): return Dist(d**m, Int((d/tan(e + f*x))**(-m + n)*(a/tan(e + f*x) + b)**m, x), x) def replacement3663(a, b, d, e, f, m, n, x): return Dist(d**m, Int((d*tan(e + f*x))**(-m + n)*(a*tan(e + f*x) + b)**m, x), x) def replacement3664(a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d*tan(e + f*x))**p)**FracPart(n)*(d*tan(e + f*x))**(-p*FracPart(n)), Int((d*tan(e + f*x))**(n*p)*(a + b*tan(e + f*x))**m, x), x) def replacement3665(a, b, c, d, e, f, m, n, p, x): return Dist(c**IntPart(n)*(c*(d/tan(e + f*x))**p)**FracPart(n)*(d/tan(e + f*x))**(-p*FracPart(n)), Int((d/tan(e + f*x))**(n*p)*(a + b/tan(e + f*x))**m, x), x) def replacement3666(a, b, c, d, e, f, g, m, n, p, x): return Int((g*tan(e + f*x))**p*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n, x) def replacement3667(a, b, c, d, e, f, g, m, n, p, x): return Int((g/tan(e + f*x))**p*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x) def replacement3668(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(m + n), Int((g/tan(e + f*x))**(-m - n + p)*(a/tan(e + f*x) + b)**m*(c/tan(e + f*x) + d)**n, x), x) def replacement3669(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**(m + n), Int((g*tan(e + f*x))**(-m - n + p)*(a*tan(e + f*x) + b)**m*(c*tan(e + f*x) + d)**n, x), x) def replacement3670(a, b, c, d, e, f, g, m, n, p, q, x): return Dist((g*tan(e + f*x))**(-p*q)*(g*tan(e + f*x)**q)**p, Int((g*tan(e + f*x))**(p*q)*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n, x), x) def replacement3671(a, b, c, d, e, f, g, m, n, p, q, x): return Dist((g*(S(1)/tan(e + f*x))**q)**p*(g/tan(e + f*x))**(-p*q), Int((g/tan(e + f*x))**(p*q)*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x), x) def replacement3672(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**n, Int((g*tan(e + f*x))**(-n + p)*(a + b*tan(e + f*x))**m*(c*tan(e + f*x) + d)**n, x), x) def replacement3673(a, b, c, d, e, f, g, m, n, p, x): return Dist(g**n, Int((g/tan(e + f*x))**(-n + p)*(a + b/tan(e + f*x))**m*(c/tan(e + f*x) + d)**n, x), x) def replacement3674(a, b, c, d, e, f, m, n, p, x): return Int((c + d/tan(e + f*x))**n*(a/tan(e + f*x) + b)**m*(S(1)/tan(e + f*x))**(-m - p), x) def replacement3675(a, b, c, d, e, f, m, n, p, x): return Int((c + d*tan(e + f*x))**n*(a*tan(e + f*x) + b)**m*tan(e + f*x)**(-m - p), x) def replacement3676(a, b, c, d, e, f, g, m, n, p, x): return Dist((g*tan(e + f*x))**p*(S(1)/tan(e + f*x))**p, Int((c + d/tan(e + f*x))**n*(a/tan(e + f*x) + b)**m*(S(1)/tan(e + f*x))**(-m - p), x), x) def replacement3677(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/tan(e + f*x))**p*tan(e + f*x)**p, Int((c + d*tan(e + f*x))**n*(a*tan(e + f*x) + b)**m*tan(e + f*x)**(-m - p), x), x) def replacement3678(a, b, c, d, e, f, g, m, n, p, x): return Dist((g*tan(e + f*x))**n*(c + d/tan(e + f*x))**n*(c*tan(e + f*x) + d)**(-n), Int((g*tan(e + f*x))**(-n + p)*(a + b*tan(e + f*x))**m*(c*tan(e + f*x) + d)**n, x), x) def replacement3679(a, b, c, d, e, f, g, m, n, p, x): return Dist((g/tan(e + f*x))**n*(c + d*tan(e + f*x))**n*(c/tan(e + f*x) + d)**(-n), Int((g/tan(e + f*x))**(-n + p)*(a + b/tan(e + f*x))**m*(c/tan(e + f*x) + d)**n, x), x) def replacement3680(A, B, a, b, c, d, e, f, m, n, x): return Dist(a*c/f, Subst(Int((A + B*x)*(a + b*x)**(m + S(-1))*(c + d*x)**(n + S(-1)), x), x, tan(e + f*x)), x) def replacement3681(A, B, a, b, c, d, e, f, m, n, x): return -Dist(a*c/f, Subst(Int((A + B*x)*(a + b*x)**(m + S(-1))*(c + d*x)**(n + S(-1)), x), x, S(1)/tan(e + f*x)), x) def replacement3682(A, B, a, b, c, d, e, f, x): return Dist(S(1)/b, Int(Simp(A*b*c + (A*b*d + B*(-a*d + b*c))*tan(e + f*x), x)/(a + b*tan(e + f*x)), x), x) + Dist(B*d/b, Int(tan(e + f*x), x), x) def replacement3683(A, B, a, b, c, d, e, f, x): return Dist(S(1)/b, Int(Simp(A*b*c + (A*b*d + B*(-a*d + b*c))/tan(e + f*x), x)/(a + b/tan(e + f*x)), x), x) + Dist(B*d/b, Int(S(1)/tan(e + f*x), x), x) def replacement3684(A, B, a, b, c, d, e, f, m, x): return Dist(S(1)/(S(2)*a*b), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(A*a*d + A*b*c + B*a*c + S(2)*B*a*d*tan(e + f*x) + B*b*d, x), x), x) - Simp((a + b*tan(e + f*x))**m*(A*b - B*a)*(a*c + b*d)/(S(2)*a**S(2)*f*m), x) def replacement3685(A, B, a, b, c, d, e, f, m, x): return Dist(S(1)/(S(2)*a*b), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(A*a*d + A*b*c + B*a*c + S(2)*B*a*d/tan(e + f*x) + B*b*d, x), x), x) + Simp((a + b/tan(e + f*x))**m*(A*b - B*a)*(a*c + b*d)/(S(2)*a**S(2)*f*m), x) def replacement3686(A, B, a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(A*a*c + A*b*d - B*a*d + B*b*c - (-A*a*d + A*b*c - B*a*c - B*b*d)*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(A*b - B*a)*(-a*d + b*c)/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3687(A, B, a, b, c, d, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(A*a*c + A*b*d - B*a*d + B*b*c - (-A*a*d + A*b*c - B*a*c - B*b*d)/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(A*b - B*a)*(-a*d + b*c)/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3688(A, B, a, b, c, d, e, f, m, x): return Int((a + b*tan(e + f*x))**m*Simp(A*c - B*d + (A*d + B*c)*tan(e + f*x), x), x) + Simp(B*d*(a + b*tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3689(A, B, a, b, c, d, e, f, m, x): return Int((a + b/tan(e + f*x))**m*Simp(A*c - B*d + (A*d + B*c)/tan(e + f*x), x), x) - Simp(B*d*(a + b/tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3690(A, B, a, b, c, d, e, f, m, n, x): return -Dist(a/(d*(n + S(1))*(a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))*Simp(A*b*d*(m - n + S(-2)) - B*(a*d*(n + S(1)) + b*c*(m + S(-1))) + (A*a*d*(m + n) - B*(a*c*(m + S(-1)) + b*d*(n + S(1))))*tan(e + f*x), x), x), x) - Simp(a**S(2)*(a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))*(-A*d + B*c)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement3691(A, B, a, b, c, d, e, f, m, n, x): return -Dist(a/(d*(n + S(1))*(a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))*Simp(A*b*d*(m - n + S(-2)) - B*(a*d*(n + S(1)) + b*c*(m + S(-1))) + (A*a*d*(m + n) - B*(a*c*(m + S(-1)) + b*d*(n + S(1))))/tan(e + f*x), x), x), x) + Simp(a**S(2)*(a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))*(-A*d + B*c)/(d*f*(n + S(1))*(a*d + b*c)), x) def replacement3692(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**n*Simp(A*a*d*(m + n) + B*(a*c*(m + S(-1)) - b*d*(n + S(1))) - (B*(m + S(-1))*(-a*d + b*c) - d*(m + n)*(A*b + B*a))*tan(e + f*x), x), x), x) + Simp(B*b*(a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n)), x) def replacement3693(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**n*Simp(A*a*d*(m + n) + B*(a*c*(m + S(-1)) - b*d*(n + S(1))) - (B*(m + S(-1))*(-a*d + b*c) - d*(m + n)*(A*b + B*a))/tan(e + f*x), x), x), x) - Simp(B*b*(a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n)), x) def replacement3694(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(-1))*Simp(A*(a*c*m + b*d*n) - B*(a*d*n + b*c*m) - d*(-A*a*(m + n) + B*b*(m - n))*tan(e + f*x), x), x), x) - Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n*(A*b - B*a)/(S(2)*a*f*m), x) def replacement3695(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(-1))*Simp(A*(a*c*m + b*d*n) - B*(a*d*n + b*c*m) - d*(-A*a*(m + n) + B*b*(m - n))/tan(e + f*x), x), x), x) + Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n*(A*b - B*a)/(S(2)*a*f*m), x) def replacement3696(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(A*(-a*d*(S(2)*m + n + S(1)) + b*c*m) + B*(a*c*m - b*d*(n + S(1))) + d*(A*b - B*a)*(m + n + S(1))*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*(A*a + B*b)/(S(2)*f*m*(-a*d + b*c)), x) def replacement3697(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(A*(-a*d*(S(2)*m + n + S(1)) + b*c*m) + B*(a*c*m - b*d*(n + S(1))) + d*(A*b - B*a)*(m + n + S(1))/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*(A*a + B*b)/(S(2)*f*m*(-a*d + b*c)), x) def replacement3698(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*(m + n)), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(-1))*Simp(A*a*c*(m + n) - B*(a*d*n + b*c*m) + (A*a*d*(m + n) - B*(-a*c*n + b*d*m))*tan(e + f*x), x), x), x) + Simp(B*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n/(f*(m + n)), x) def replacement3699(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(a*(m + n)), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(-1))*Simp(A*a*c*(m + n) - B*(a*d*n + b*c*m) + (A*a*d*(m + n) - B*(-a*c*n + b*d*m))/tan(e + f*x), x), x), x) - Simp(B*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n/(f*(m + n)), x) def replacement3700(A, B, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*Simp(A*(-a*c*(n + S(1)) + b*d*m) - B*(a*d*(n + S(1)) + b*c*m) - a*(-A*d + B*c)*(m + n + S(1))*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*(A*d - B*c)/(f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3701(A, B, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*Simp(A*(-a*c*(n + S(1)) + b*d*m) - B*(a*d*(n + S(1)) + b*c*m) - a*(-A*d + B*c)*(m + n + S(1))/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*(A*d - B*c)/(f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3702(A, B, a, b, c, d, e, f, m, n, x): return Dist(B*b/f, Subst(Int((a + b*x)**(m + S(-1))*(c + d*x)**n, x), x, tan(e + f*x)), x) def replacement3703(A, B, a, b, c, d, e, f, m, n, x): return -Dist(B*b/f, Subst(Int((a + b*x)**(m + S(-1))*(c + d*x)**n, x), x, S(1)/tan(e + f*x)), x) def replacement3704(A, B, a, b, c, d, e, f, m, x): return Dist((A*b + B*a)/(a*d + b*c), Int((a + b*tan(e + f*x))**m, x), x) - Dist((-A*d + B*c)/(a*d + b*c), Int((a - b*tan(e + f*x))*(a + b*tan(e + f*x))**m/(c + d*tan(e + f*x)), x), x) def replacement3705(A, B, a, b, c, d, e, f, m, x): return Dist((A*b + B*a)/(a*d + b*c), Int((a + b/tan(e + f*x))**m, x), x) - Dist((-A*d + B*c)/(a*d + b*c), Int((a - b/tan(e + f*x))*(a + b/tan(e + f*x))**m/(c + d/tan(e + f*x)), x), x) def replacement3706(A, B, a, b, c, d, e, f, m, n, x): return -Dist(B/b, Int((a - b*tan(e + f*x))*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n, x), x) + Dist((A*b + B*a)/b, Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n, x), x) def replacement3707(A, B, a, b, c, d, e, f, m, n, x): return -Dist(B/b, Int((a - b/tan(e + f*x))*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x), x) + Dist((A*b + B*a)/b, Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x), x) def replacement3708(A, B, a, b, c, d, e, f, m, n, x): return Dist(A**S(2)/f, Subst(Int((a + b*x)**m*(c + d*x)**n/(A - B*x), x), x, tan(e + f*x)), x) def replacement3709(A, B, a, b, c, d, e, f, m, n, x): return -Dist(A**S(2)/f, Subst(Int((a + b*x)**m*(c + d*x)**n/(A - B*x), x), x, S(1)/tan(e + f*x)), x) def replacement3710(A, B, a, b, c, d, e, f, m, n, x): return Dist(A/S(2) - I*B/S(2), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n*(I*tan(e + f*x) + S(1)), x), x) + Dist(A/S(2) + I*B/S(2), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n*(-I*tan(e + f*x) + S(1)), x), x) def replacement3711(A, B, a, b, c, d, e, f, m, n, x): return Dist(A/S(2) - I*B/S(2), Int((S(1) + I/tan(e + f*x))*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x), x) + Dist(A/S(2) + I*B/S(2), Int((S(1) - I/tan(e + f*x))*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x), x) def replacement3712(A, B, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**(n + S(1))*Simp(A*a*d*(-a*c*(n + S(1)) + b*d*(m + S(-1))) - b*(-B*b*(c**S(2)*(m + S(-1)) - d**S(2)*(n + S(1))) + d*(m + n)*(-A*a*d + A*b*c + B*a*c))*tan(e + f*x)**S(2) - d*(n + S(1))*((A*a - B*b)*(-a*d + b*c) + (A*b + B*a)*(a*c + b*d))*tan(e + f*x) + (B*b*c - d*(A*b + B*a))*(a*d*(n + S(1)) + b*c*(m + S(-1))), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))*(-A*d + B*c)*(-a*d + b*c)/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3713(A, B, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**(n + S(1))*Simp(A*a*d*(-a*c*(n + S(1)) + b*d*(m + S(-1))) - b*(-B*b*(c**S(2)*(m + S(-1)) - d**S(2)*(n + S(1))) + d*(m + n)*(-A*a*d + A*b*c + B*a*c))/tan(e + f*x)**S(2) - d*(n + S(1))*((A*a - B*b)*(-a*d + b*c) + (A*b + B*a)*(a*c + b*d))/tan(e + f*x) + (B*b*c - d*(A*b + B*a))*(a*d*(n + S(1)) + b*c*(m + S(-1))), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))*(-A*d + B*c)*(-a*d + b*c)/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3714(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b*tan(e + f*x))**(m + S(-2))*(c + d*tan(e + f*x))**n*Simp(A*a**S(2)*d*(m + n) - B*b*(a*d*(n + S(1)) + b*c*(m + S(-1))) + d*(m + n)*(S(2)*A*a*b + B*(a**S(2) - b**S(2)))*tan(e + f*x) - (B*b*(m + S(-1))*(-a*d + b*c) - b*d*(m + n)*(A*b + B*a))*tan(e + f*x)**S(2), x), x), x) + Simp(B*b*(a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n)), x) def replacement3715(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n)), Int((a + b/tan(e + f*x))**(m + S(-2))*(c + d/tan(e + f*x))**n*Simp(A*a**S(2)*d*(m + n) - B*b*(a*d*(n + S(1)) + b*c*(m + S(-1))) + d*(m + n)*(S(2)*A*a*b + B*(a**S(2) - b**S(2)))/tan(e + f*x) - (B*b*(m + S(-1))*(-a*d + b*c) - b*d*(m + n)*(A*b + B*a))/tan(e + f*x)**S(2), x), x), x) - Simp(B*b*(a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n)), x) def replacement3716(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(a**S(2) + b**S(2))*(m + S(1))), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(-1))*Simp(A*b*(a*c*(m + S(1)) - b*d*n) + B*b*(a*d*n + b*c*(m + S(1))) - b*d*(A*b - B*a)*(m + n + S(1))*tan(e + f*x)**S(2) - b*(m + S(1))*(A*(-a*d + b*c) - B*(a*c + b*d))*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*(A*b - B*a)/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3717(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*(a**S(2) + b**S(2))*(m + S(1))), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(-1))*Simp(A*b*(a*c*(m + S(1)) - b*d*n) + B*b*(a*d*n + b*c*(m + S(1))) - b*d*(A*b - B*a)*(m + n + S(1))/tan(e + f*x)**S(2) - b*(m + S(1))*(A*(-a*d + b*c) - B*(a*c + b*d))/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*(A*b - B*a)/(f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3718(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(A*(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2))) + B*b*(a*d*(n + S(1)) + b*c*(m + S(1))) - b*d*(A*b - B*a)*(m + n + S(2))*tan(e + f*x)**S(2) - (m + S(1))*(A*b - B*a)*(-a*d + b*c)*tan(e + f*x), x), x), x) + Simp(b*(a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(1))*(A*b - B*a)/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3719(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(A*(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2))) + B*b*(a*d*(n + S(1)) + b*c*(m + S(1))) - b*d*(A*b - B*a)*(m + n + S(2))/tan(e + f*x)**S(2) - (m + S(1))*(A*b - B*a)*(-a*d + b*c)/tan(e + f*x), x), x), x) - Simp(b*(a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(1))*(A*b - B*a)/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3720(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(m + n), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(-1))*Simp(A*a*c*(m + n) - B*(a*d*n + b*c*m) + (m + n)*(A*a*d + A*b*c + B*a*c - B*b*d)*tan(e + f*x) + (A*b*d*(m + n) + B*(a*d*m + b*c*n))*tan(e + f*x)**S(2), x), x), x) + Simp(B*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n/(f*(m + n)), x) def replacement3721(A, B, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(m + n), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(-1))*Simp(A*a*c*(m + n) - B*(a*d*n + b*c*m) + (m + n)*(A*a*d + A*b*c + B*a*c - B*b*d)/tan(e + f*x) + (A*b*d*(m + n) + B*(a*d*m + b*c*n))/tan(e + f*x)**S(2), x), x), x) - Simp(B*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n/(f*(m + n)), x) def replacement3722(A, B, a, b, c, d, e, f, x): return Dist(b*(A*b - B*a)/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a*tan(e + f*x) + b)/(a + b*tan(e + f*x)), x), x) + Dist(d*(-A*d + B*c)/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c*tan(e + f*x) + d)/(c + d*tan(e + f*x)), x), x) + Simp(x*(A*(a*c - b*d) + B*(a*d + b*c))/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3723(A, B, a, b, c, d, e, f, x): return Dist(b*(A*b - B*a)/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a/tan(e + f*x) + b)/(a + b/tan(e + f*x)), x), x) + Dist(d*(-A*d + B*c)/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c/tan(e + f*x) + d)/(c + d/tan(e + f*x)), x), x) + Simp(x*(A*(a*c - b*d) + B*(a*d + b*c))/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3724(A, B, a, b, c, d, e, f, x): return -Dist((-A*b + B*a)*(-a*d + b*c)/(a**S(2) + b**S(2)), Int((tan(e + f*x)**S(2) + S(1))/((a + b*tan(e + f*x))*sqrt(c + d*tan(e + f*x))), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int(Simp(A*(a*c + b*d) + B*(-a*d + b*c) - (A*(-a*d + b*c) - B*(a*c + b*d))*tan(e + f*x), x)/sqrt(c + d*tan(e + f*x)), x), x) def replacement3725(A, B, a, b, c, d, e, f, x): return -Dist((-A*b + B*a)*(-a*d + b*c)/(a**S(2) + b**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))/((a + b/tan(e + f*x))*sqrt(c + d/tan(e + f*x))), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int(Simp(A*(a*c + b*d) + B*(-a*d + b*c) - (A*(-a*d + b*c) - B*(a*c + b*d))/tan(e + f*x), x)/sqrt(c + d/tan(e + f*x)), x), x) def replacement3726(A, B, a, b, c, d, e, f, n, x): return Dist(b*(A*b - B*a)/(a**S(2) + b**S(2)), Int((c + d*tan(e + f*x))**n*(tan(e + f*x)**S(2) + S(1))/(a + b*tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((c + d*tan(e + f*x))**n*Simp(A*a + B*b - (A*b - B*a)*tan(e + f*x), x), x), x) def replacement3727(A, B, a, b, c, d, e, f, n, x): return Dist(b*(A*b - B*a)/(a**S(2) + b**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))*(c + d/tan(e + f*x))**n/(a + b/tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((c + d/tan(e + f*x))**n*Simp(A*a + B*b - (A*b - B*a)/tan(e + f*x), x), x), x) def replacement3728(A, B, a, b, c, d, e, f, x): return Dist(B*b, Int((tan(e + f*x)**S(2) + S(1))/(sqrt(a + b*tan(e + f*x))*sqrt(c + d*tan(e + f*x))), x), x) + Int(Simp(A*a - B*b + (A*b + B*a)*tan(e + f*x), x)/(sqrt(a + b*tan(e + f*x))*sqrt(c + d*tan(e + f*x))), x) def replacement3729(A, B, a, b, c, d, e, f, x): return Dist(B*b, Int((S(1) + tan(e + f*x)**(S(-2)))/(sqrt(a + b/tan(e + f*x))*sqrt(c + d/tan(e + f*x))), x), x) + Int(Simp(A*a - B*b + (A*b + B*a)/tan(e + f*x), x)/(sqrt(a + b/tan(e + f*x))*sqrt(c + d/tan(e + f*x))), x) def replacement3730(A, B, a, b, c, d, e, f, m, n, x): return Dist(A**S(2)/f, Subst(Int((a + b*x)**m*(c + d*x)**n/(A - B*x), x), x, tan(e + f*x)), x) def replacement3731(A, B, a, b, c, d, e, f, m, n, x): return -Dist(A**S(2)/f, Subst(Int((a + b*x)**m*(c + d*x)**n/(A - B*x), x), x, S(1)/tan(e + f*x)), x) def replacement3732(A, B, a, b, c, d, e, f, m, n, x): return Dist(A/S(2) - I*B/S(2), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n*(I*tan(e + f*x) + S(1)), x), x) + Dist(A/S(2) + I*B/S(2), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n*(-I*tan(e + f*x) + S(1)), x), x) def replacement3733(A, B, a, b, c, d, e, f, m, n, x): return Dist(A/S(2) - I*B/S(2), Int((S(1) + I/tan(e + f*x))*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x), x) + Dist(A/S(2) + I*B/S(2), Int((S(1) - I/tan(e + f*x))*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n, x), x) def replacement3734(A, C, a, b, e, f, m, x): return Dist(A/(b*f), Subst(Int((a + x)**m, x), x, b*tan(e + f*x)), x) def replacement3735(A, C, a, b, e, f, m, x): return -Dist(A/(b*f), Subst(Int((a + x)**m, x), x, b/tan(e + f*x)), x) def replacement3736(A, B, C, a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(B*b - C*a + C*b*tan(e + f*x), x), x), x) def replacement3737(A, B, C, a, b, e, f, m, x): return Dist(b**(S(-2)), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(B*b - C*a + C*b/tan(e + f*x), x), x), x) def replacement3738(A, C, a, b, e, f, m, x): return -Dist(C/b**S(2), Int((a - b*tan(e + f*x))*(a + b*tan(e + f*x))**(m + S(1)), x), x) def replacement3739(A, C, a, b, e, f, m, x): return -Dist(C/b**S(2), Int((a - b/tan(e + f*x))*(a + b/tan(e + f*x))**(m + S(1)), x), x) def replacement3740(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(A*a*(S(2)*m + S(1)) + B*b - C*a - (C*b*(m + S(-1)) + (m + S(1))*(A*b - B*a))*tan(e + f*x), x), x), x) - Simp((a + b*tan(e + f*x))**m*(A*a + B*b - C*a)*tan(e + f*x)/(S(2)*a*f*m), x) def replacement3741(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(A*a*(S(2)*m + S(1)) + B*b - C*a - (C*b*(m + S(-1)) + (m + S(1))*(A*b - B*a))/tan(e + f*x), x), x), x) + Simp((a + b/tan(e + f*x))**m*(A*a + B*b - C*a)/(S(2)*a*f*m*tan(e + f*x)), x) def replacement3742(A, C, a, b, e, f, m, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(A*a*(S(2)*m + S(1)) - C*a - (A*b*(m + S(1)) + C*b*(m + S(-1)))*tan(e + f*x), x), x), x) - Simp((a + b*tan(e + f*x))**m*(A*a - C*a)*tan(e + f*x)/(S(2)*a*f*m), x) def replacement3743(A, C, a, b, e, f, m, x): return Dist(S(1)/(S(2)*a**S(2)*m), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(A*a*(S(2)*m + S(1)) - C*a - (A*b*(m + S(1)) + C*b*(m + S(-1)))/tan(e + f*x), x), x), x) + Simp((a + b/tan(e + f*x))**m*(A*a - C*a)/(S(2)*a*f*m*tan(e + f*x)), x) def replacement3744(A, B, C, a, b, e, f, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2) + b**S(2)), Int((tan(e + f*x)**S(2) + S(1))/(a + b*tan(e + f*x)), x), x) + Simp(x*(A*a + B*b - C*a)/(a**S(2) + b**S(2)), x) def replacement3745(A, B, C, a, b, e, f, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2) + b**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))/(a + b/tan(e + f*x)), x), x) + Simp(x*(A*a + B*b - C*a)/(a**S(2) + b**S(2)), x) def replacement3746(A, B, C, e, f, x): return Dist(A, Int(S(1)/tan(e + f*x), x), x) + Dist(C, Int(tan(e + f*x), x), x) + Simp(B*x, x) def replacement3747(A, B, C, e, f, x): return Dist(A, Int(tan(e + f*x), x), x) + Dist(C, Int(S(1)/tan(e + f*x), x), x) + Simp(B*x, x) def replacement3748(A, C, e, f, x): return Dist(A, Int(S(1)/tan(e + f*x), x), x) + Dist(C, Int(tan(e + f*x), x), x) def replacement3749(A, C, e, f, x): return Dist(A, Int(tan(e + f*x), x), x) + Dist(C, Int(S(1)/tan(e + f*x), x), x) def replacement3750(A, B, C, a, b, e, f, x): return -Dist((A*b - B*a - C*b)/(a**S(2) + b**S(2)), Int(tan(e + f*x), x), x) + Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2) + b**S(2)), Int((tan(e + f*x)**S(2) + S(1))/(a + b*tan(e + f*x)), x), x) + Simp(x*(A*a + B*b - C*a)/(a**S(2) + b**S(2)), x) def replacement3751(A, B, C, a, b, e, f, x): return -Dist((A*b - B*a - C*b)/(a**S(2) + b**S(2)), Int(S(1)/tan(e + f*x), x), x) + Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2) + b**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))/(a + b/tan(e + f*x)), x), x) + Simp(x*(A*a + B*b - C*a)/(a**S(2) + b**S(2)), x) def replacement3752(A, C, a, b, e, f, x): return Dist((A*b**S(2) + C*a**S(2))/(a**S(2) + b**S(2)), Int((tan(e + f*x)**S(2) + S(1))/(a + b*tan(e + f*x)), x), x) - Dist(b*(A - C)/(a**S(2) + b**S(2)), Int(tan(e + f*x), x), x) + Simp(a*x*(A - C)/(a**S(2) + b**S(2)), x) def replacement3753(A, C, a, b, e, f, x): return Dist((A*b**S(2) + C*a**S(2))/(a**S(2) + b**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))/(a + b/tan(e + f*x)), x), x) - Dist(b*(A - C)/(a**S(2) + b**S(2)), Int(S(1)/tan(e + f*x), x), x) + Simp(a*x*(A - C)/(a**S(2) + b**S(2)), x) def replacement3754(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(B*b + a*(A - C) - (A*b - B*a - C*b)*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3755(A, B, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(B*b + a*(A - C) - (A*b - B*a - C*b)/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(A*b**S(2) - B*a*b + C*a**S(2))/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3756(A, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b*tan(e + f*x))**(m + S(1))*Simp(a*(A - C) - (A*b - C*b)*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3757(A, C, a, b, e, f, m, x): return Dist(S(1)/(a**S(2) + b**S(2)), Int((a + b/tan(e + f*x))**(m + S(1))*Simp(a*(A - C) - (A*b - C*b)/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(A*b**S(2) + C*a**S(2))/(b*f*(a**S(2) + b**S(2))*(m + S(1))), x) def replacement3758(A, B, C, a, b, e, f, m, x): return Int((a + b*tan(e + f*x))**m*Simp(A + B*tan(e + f*x) - C, x), x) + Simp(C*(a + b*tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3759(A, B, C, a, b, e, f, m, x): return Int((a + b/tan(e + f*x))**m*Simp(A + B/tan(e + f*x) - C, x), x) - Simp(C*(a + b/tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3760(A, C, a, b, e, f, m, x): return Dist(A - C, Int((a + b*tan(e + f*x))**m, x), x) + Simp(C*(a + b*tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3761(A, C, a, b, e, f, m, x): return Dist(A - C, Int((a + b/tan(e + f*x))**m, x), x) - Simp(C*(a + b/tan(e + f*x))**(m + S(1))/(b*f*(m + S(1))), x) def replacement3762(A, C, a, b, c, d, e, f, m, n, x): return Dist(A/f, Subst(Int((a + b*x)**m*(c + d*x)**n, x), x, tan(e + f*x)), x) def replacement3763(A, C, a, b, c, d, e, f, m, n, x): return -Dist(A/f, Subst(Int((a + b*x)**m*(c + d*x)**n, x), x, S(1)/tan(e + f*x)), x) def replacement3764(A, B, C, a, b, c, d, e, f, n, x): return Dist(S(1)/(d*(c**S(2) + d**S(2))), Int((c + d*tan(e + f*x))**(n + S(1))*Simp(C*b*(c**S(2) + d**S(2))*tan(e + f*x)**S(2) + a*d*(A*c + B*d - C*c) + b*(A*d**S(2) - B*c*d + C*c**S(2)) + d*(-A*a*d + A*b*c + B*a*c + B*b*d + C*a*d - C*b*c)*tan(e + f*x), x), x), x) - Simp((c + d*tan(e + f*x))**(n + S(1))*(-a*d + b*c)*(A*d**S(2) - B*c*d + C*c**S(2))/(d**S(2)*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3765(A, B, C, a, b, c, d, e, f, n, x): return Dist(S(1)/(d*(c**S(2) + d**S(2))), Int((c + d/tan(e + f*x))**(n + S(1))*Simp(C*b*(c**S(2) + d**S(2))/tan(e + f*x)**S(2) + a*d*(A*c + B*d - C*c) + b*(A*d**S(2) - B*c*d + C*c**S(2)) + d*(-A*a*d + A*b*c + B*a*c + B*b*d + C*a*d - C*b*c)/tan(e + f*x), x), x), x) + Simp((c + d/tan(e + f*x))**(n + S(1))*(-a*d + b*c)*(A*d**S(2) - B*c*d + C*c**S(2))/(d**S(2)*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3766(A, C, a, b, c, d, e, f, n, x): return Dist(S(1)/(d*(c**S(2) + d**S(2))), Int((c + d*tan(e + f*x))**(n + S(1))*Simp(C*b*(c**S(2) + d**S(2))*tan(e + f*x)**S(2) + a*d*(A*c - C*c) + b*(A*d**S(2) + C*c**S(2)) + d*(-A*a*d + A*b*c + C*a*d - C*b*c)*tan(e + f*x), x), x), x) - Simp((c + d*tan(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))*(-a*d + b*c)/(d**S(2)*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3767(A, C, a, b, c, d, e, f, n, x): return Dist(S(1)/(d*(c**S(2) + d**S(2))), Int((c + d/tan(e + f*x))**(n + S(1))*Simp(C*b*(c**S(2) + d**S(2))/tan(e + f*x)**S(2) + a*d*(A*c - C*c) + b*(A*d**S(2) + C*c**S(2)) + d*(-A*a*d + A*b*c + C*a*d - C*b*c)/tan(e + f*x), x), x), x) + Simp((c + d/tan(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))*(-a*d + b*c)/(d**S(2)*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3768(A, B, C, a, b, c, d, e, f, n, x): return -Dist(S(1)/(d*(n + S(2))), Int((c + d*tan(e + f*x))**n*Simp(-A*a*d*(n + S(2)) + C*b*c - d*(n + S(2))*(A*b + B*a - C*b)*tan(e + f*x) - (C*a*d*(n + S(2)) - b*(-B*d*(n + S(2)) + C*c))*tan(e + f*x)**S(2), x), x), x) + Simp(C*b*(c + d*tan(e + f*x))**(n + S(1))*tan(e + f*x)/(d*f*(n + S(2))), x) def replacement3769(A, B, C, a, b, c, d, e, f, n, x): return -Dist(S(1)/(d*(n + S(2))), Int((c + d/tan(e + f*x))**n*Simp(-A*a*d*(n + S(2)) + C*b*c - d*(n + S(2))*(A*b + B*a - C*b)/tan(e + f*x) - (C*a*d*(n + S(2)) - b*(-B*d*(n + S(2)) + C*c))/tan(e + f*x)**S(2), x), x), x) - Simp(C*b*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(n + S(2))*tan(e + f*x)), x) def replacement3770(A, C, a, b, c, d, e, f, n, x): return -Dist(S(1)/(d*(n + S(2))), Int((c + d*tan(e + f*x))**n*Simp(-A*a*d*(n + S(2)) + C*b*c - d*(n + S(2))*(A*b - C*b)*tan(e + f*x) - (C*a*d*(n + S(2)) - C*b*c)*tan(e + f*x)**S(2), x), x), x) + Simp(C*b*(c + d*tan(e + f*x))**(n + S(1))*tan(e + f*x)/(d*f*(n + S(2))), x) def replacement3771(A, C, a, b, c, d, e, f, n, x): return -Dist(S(1)/(d*(n + S(2))), Int((c + d/tan(e + f*x))**n*Simp(-A*a*d*(n + S(2)) + C*b*c - d*(n + S(2))*(A*b - C*b)/tan(e + f*x) - (C*a*d*(n + S(2)) - C*b*c)/tan(e + f*x)**S(2), x), x), x) - Simp(C*b*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(n + S(2))*tan(e + f*x)), x) def replacement3772(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(a*(-A*d*(S(2)*m + n + S(1)) + B*c*m + C*d*(n + S(1))) + b*(-B*d*(n + S(1)) + c*m*(A + C)) + (A*b*d*(m + n + S(1)) + C*b*d*(m - n + S(-1)) + a*(-B*d*(m + n + S(1)) + S(2)*C*c*m))*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*(A*a + B*b - C*a)/(S(2)*f*m*(-a*d + b*c)), x) def replacement3773(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(a*(-A*d*(S(2)*m + n + S(1)) + B*c*m + C*d*(n + S(1))) + b*(-B*d*(n + S(1)) + c*m*(A + C)) + (A*b*d*(m + n + S(1)) + C*b*d*(m - n + S(-1)) + a*(-B*d*(m + n + S(1)) + S(2)*C*c*m))/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*(A*a + B*b - C*a)/(S(2)*f*m*(-a*d + b*c)), x) def replacement3774(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(a*(-A*d*(S(2)*m + n + S(1)) + C*d*(n + S(1))) + b*c*m*(A + C) + (A*b*d*(m + n + S(1)) + S(2)*C*a*c*m + C*b*d*(m - n + S(-1)))*tan(e + f*x), x), x), x) + Simp(a*(A - C)*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(S(2)*f*m*(-a*d + b*c)), x) def replacement3775(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(S(2)*a*m*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(a*(-A*d*(S(2)*m + n + S(1)) + C*d*(n + S(1))) + b*c*m*(A + C) + (A*b*d*(m + n + S(1)) + S(2)*C*a*c*m + C*b*d*(m - n + S(-1)))/tan(e + f*x), x), x), x) - Simp(a*(A - C)*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(S(2)*f*m*(-a*d + b*c)), x) def replacement3776(A, B, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*Simp(-a*d*(n + S(1))*(A*c + B*d - C*c) - a*(-C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(1)))*tan(e + f*x) + b*m*(A*d**S(2) - B*c*d + C*c**S(2)), x), x), x) + Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*(A*d**S(2) - B*c*d + C*c**S(2))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3777(A, B, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*Simp(-a*d*(n + S(1))*(A*c + B*d - C*c) - a*(-C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(1)))/tan(e + f*x) + b*m*(A*d**S(2) - B*c*d + C*c**S(2)), x), x), x) - Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*(A*d**S(2) - B*c*d + C*c**S(2))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3778(A, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*Simp(-a*d*(n + S(1))*(A*c - C*c) - a*(-A*d**S(2)*(m + n + S(1)) - C*(c**S(2)*m - d**S(2)*(n + S(1))))*tan(e + f*x) + b*m*(A*d**S(2) + C*c**S(2)), x), x), x) + Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3779(A, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(a*d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*Simp(-a*d*(n + S(1))*(A*c - C*c) - a*(-A*d**S(2)*(m + n + S(1)) - C*(c**S(2)*m - d**S(2)*(n + S(1))))/tan(e + f*x) + b*m*(A*d**S(2) + C*c**S(2)), x), x), x) - Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3780(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(1))), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n*Simp(A*b*d*(m + n + S(1)) + C*(a*c*m - b*d*(n + S(1))) - (-B*b*d*(m + n + S(1)) + C*m*(-a*d + b*c))*tan(e + f*x), x), x), x) + Simp(C*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3781(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(1))), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n*Simp(A*b*d*(m + n + S(1)) + C*(a*c*m - b*d*(n + S(1))) - (-B*b*d*(m + n + S(1)) + C*m*(-a*d + b*c))/tan(e + f*x), x), x), x) - Simp(C*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3782(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(1))), Int((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**n*Simp(A*b*d*(m + n + S(1)) - C*m*(-a*d + b*c)*tan(e + f*x) + C*(a*c*m - b*d*(n + S(1))), x), x), x) + Simp(C*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3783(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*d*(m + n + S(1))), Int((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**n*Simp(A*b*d*(m + n + S(1)) - C*m*(-a*d + b*c)/tan(e + f*x) + C*(a*c*m - b*d*(n + S(1))), x), x), x) - Simp(C*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3784(A, B, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))*Simp(A*d*(-a*c*(n + S(1)) + b*d*m) - b*(-C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(1)))*tan(e + f*x)**S(2) - d*(n + S(1))*(B*(a*c + b*d) + (A - C)*(-a*d + b*c))*tan(e + f*x) + (-B*d + C*c)*(a*d*(n + S(1)) + b*c*m), x), x), x) + Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*(A*d**S(2) + c*(-B*d + C*c))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3785(A, B, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))*Simp(A*d*(-a*c*(n + S(1)) + b*d*m) - b*(-C*(c**S(2)*m - d**S(2)*(n + S(1))) + d*(-A*d + B*c)*(m + n + S(1)))/tan(e + f*x)**S(2) - d*(n + S(1))*(B*(a*c + b*d) + (A - C)*(-a*d + b*c))/tan(e + f*x) + (-B*d + C*c)*(a*d*(n + S(1)) + b*c*m), x), x), x) - Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*(A*d**S(2) + c*(-B*d + C*c))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3786(A, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**(n + S(1))*Simp(A*d*(-a*c*(n + S(1)) + b*d*m) + C*c*(a*d*(n + S(1)) + b*c*m) + b*(A*d**S(2)*(m + n + S(1)) + C*(c**S(2)*m - d**S(2)*(n + S(1))))*tan(e + f*x)**S(2) - d*(A - C)*(n + S(1))*(-a*d + b*c)*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3787(A, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(d*(c**S(2) + d**S(2))*(n + S(1))), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**(n + S(1))*Simp(A*d*(-a*c*(n + S(1)) + b*d*m) + C*c*(a*d*(n + S(1)) + b*c*m) + b*(A*d**S(2)*(m + n + S(1)) + C*(c**S(2)*m - d**S(2)*(n + S(1))))/tan(e + f*x)**S(2) - d*(A - C)*(n + S(1))*(-a*d + b*c)/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))*(A*d**S(2) + C*c**S(2))/(d*f*(c**S(2) + d**S(2))*(n + S(1))), x) def replacement3788(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**n*Simp(A*a*d*(m + n + S(1)) - C*(a*d*(n + S(1)) + b*c*m) + d*(m + n + S(1))*(A*b + B*a - C*b)*tan(e + f*x) - (-B*b*d*(m + n + S(1)) + C*m*(-a*d + b*c))*tan(e + f*x)**S(2), x), x), x) + Simp(C*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3789(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**n*Simp(A*a*d*(m + n + S(1)) - C*(a*d*(n + S(1)) + b*c*m) + d*(m + n + S(1))*(A*b + B*a - C*b)/tan(e + f*x) - (-B*b*d*(m + n + S(1)) + C*m*(-a*d + b*c))/tan(e + f*x)**S(2), x), x), x) - Simp(C*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3790(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b*tan(e + f*x))**(m + S(-1))*(c + d*tan(e + f*x))**n*Simp(A*a*d*(m + n + S(1)) - C*m*(-a*d + b*c)*tan(e + f*x)**S(2) - C*(a*d*(n + S(1)) + b*c*m) + d*(A*b - C*b)*(m + n + S(1))*tan(e + f*x), x), x), x) + Simp(C*(a + b*tan(e + f*x))**m*(c + d*tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3791(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(d*(m + n + S(1))), Int((a + b/tan(e + f*x))**(m + S(-1))*(c + d/tan(e + f*x))**n*Simp(A*a*d*(m + n + S(1)) - C*m*(-a*d + b*c)/tan(e + f*x)**S(2) - C*(a*d*(n + S(1)) + b*c*m) + d*(A*b - C*b)*(m + n + S(1))/tan(e + f*x), x), x), x) - Simp(C*(a + b/tan(e + f*x))**m*(c + d/tan(e + f*x))**(n + S(1))/(d*f*(m + n + S(1))), x) def replacement3792(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(A*(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2))) - d*(A*b**S(2) - a*(B*b - C*a))*(m + n + S(2))*tan(e + f*x)**S(2) - (m + S(1))*(-a*d + b*c)*(A*b - B*a - C*b)*tan(e + f*x) + (B*b - C*a)*(a*d*(n + S(1)) + b*c*(m + S(1))), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(1))*(A*b**S(2) - a*(B*b - C*a))/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3793(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(A*(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2))) - d*(A*b**S(2) - a*(B*b - C*a))*(m + n + S(2))/tan(e + f*x)**S(2) - (m + S(1))*(-a*d + b*c)*(A*b - B*a - C*b)/tan(e + f*x) + (B*b - C*a)*(a*d*(n + S(1)) + b*c*(m + S(1))), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(1))*(A*b**S(2) - a*(B*b - C*a))/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3794(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**n*Simp(A*(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2))) - C*a*(a*d*(n + S(1)) + b*c*(m + S(1))) - d*(A*b**S(2) + C*a**S(2))*(m + n + S(2))*tan(e + f*x)**S(2) - (m + S(1))*(A*b - C*b)*(-a*d + b*c)*tan(e + f*x), x), x), x) + Simp((a + b*tan(e + f*x))**(m + S(1))*(c + d*tan(e + f*x))**(n + S(1))*(A*b**S(2) + C*a**S(2))/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3795(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/((a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), Int((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**n*Simp(A*(a*(m + S(1))*(-a*d + b*c) - b**S(2)*d*(m + n + S(2))) - C*a*(a*d*(n + S(1)) + b*c*(m + S(1))) - d*(A*b**S(2) + C*a**S(2))*(m + n + S(2))/tan(e + f*x)**S(2) - (m + S(1))*(A*b - C*b)*(-a*d + b*c)/tan(e + f*x), x), x), x) - Simp((a + b/tan(e + f*x))**(m + S(1))*(c + d/tan(e + f*x))**(n + S(1))*(A*b**S(2) + C*a**S(2))/(f*(a**S(2) + b**S(2))*(m + S(1))*(-a*d + b*c)), x) def replacement3796(A, B, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a*tan(e + f*x) + b)/(a + b*tan(e + f*x)), x), x) - Dist((A*d**S(2) - B*c*d + C*c**S(2))/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c*tan(e + f*x) + d)/(c + d*tan(e + f*x)), x), x) + Simp(x*(a*(A*c + B*d - C*c) + b*(-A*d + B*c + C*d))/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3797(A, B, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a/tan(e + f*x) + b)/(a + b/tan(e + f*x)), x), x) - Dist((A*d**S(2) - B*c*d + C*c**S(2))/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c/tan(e + f*x) + d)/(c + d/tan(e + f*x)), x), x) + Simp(x*(a*(A*c + B*d - C*c) + b*(-A*d + B*c + C*d))/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3798(A, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) + C*a**S(2))/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a*tan(e + f*x) + b)/(a + b*tan(e + f*x)), x), x) - Dist((A*d**S(2) + C*c**S(2))/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c*tan(e + f*x) + d)/(c + d*tan(e + f*x)), x), x) + Simp(x*(a*(A*c - C*c) - b*(A*d - C*d))/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3799(A, C, a, b, c, d, e, f, x): return Dist((A*b**S(2) + C*a**S(2))/((a**S(2) + b**S(2))*(-a*d + b*c)), Int((-a/tan(e + f*x) + b)/(a + b/tan(e + f*x)), x), x) - Dist((A*d**S(2) + C*c**S(2))/((c**S(2) + d**S(2))*(-a*d + b*c)), Int((-c/tan(e + f*x) + d)/(c + d/tan(e + f*x)), x), x) + Simp(x*(a*(A*c - C*c) - b*(A*d - C*d))/((a**S(2) + b**S(2))*(c**S(2) + d**S(2))), x) def replacement3800(A, B, C, a, b, c, d, e, f, n, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2) + b**S(2)), Int((c + d*tan(e + f*x))**n*(tan(e + f*x)**S(2) + S(1))/(a + b*tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((c + d*tan(e + f*x))**n*Simp(B*b + a*(A - C) + (B*a - b*(A - C))*tan(e + f*x), x), x), x) def replacement3801(A, B, C, a, b, c, d, e, f, n, x): return Dist((A*b**S(2) - B*a*b + C*a**S(2))/(a**S(2) + b**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))*(c + d/tan(e + f*x))**n/(a + b/tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((c + d/tan(e + f*x))**n*Simp(B*b + a*(A - C) + (B*a - b*(A - C))/tan(e + f*x), x), x), x) def replacement3802(A, C, a, b, c, d, e, f, n, x): return Dist((A*b**S(2) + C*a**S(2))/(a**S(2) + b**S(2)), Int((c + d*tan(e + f*x))**n*(tan(e + f*x)**S(2) + S(1))/(a + b*tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((c + d*tan(e + f*x))**n*Simp(a*(A - C) - (A*b - C*b)*tan(e + f*x), x), x), x) def replacement3803(A, C, a, b, c, d, e, f, n, x): return Dist((A*b**S(2) + C*a**S(2))/(a**S(2) + b**S(2)), Int((S(1) + tan(e + f*x)**(S(-2)))*(c + d/tan(e + f*x))**n/(a + b/tan(e + f*x)), x), x) + Dist(S(1)/(a**S(2) + b**S(2)), Int((c + d/tan(e + f*x))**n*Simp(a*(A - C) - (A*b - C*b)/tan(e + f*x), x), x), x) def replacement3804(A, B, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*f), Subst(Int((a + x)**m*(c + d*x/b)**n*(A*b**S(2) + B*b*x + C*x**S(2))/(b**S(2) + x**S(2)), x), x, b*tan(e + f*x)), x) def replacement3805(A, B, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(b*f), Subst(Int((a + x)**m*(c + d*x/b)**n*(A*b**S(2) + B*b*x + C*x**S(2))/(b**S(2) + x**S(2)), x), x, b/tan(e + f*x)), x) def replacement3806(A, C, a, b, c, d, e, f, m, n, x): return Dist(S(1)/(b*f), Subst(Int((a + x)**m*(c + d*x/b)**n*(A*b**S(2) + C*x**S(2))/(b**S(2) + x**S(2)), x), x, b*tan(e + f*x)), x) def replacement3807(A, C, a, b, c, d, e, f, m, n, x): return -Dist(S(1)/(b*f), Subst(Int((a + x)**m*(c + d*x/b)**n*(A*b**S(2) + C*x**S(2))/(b**S(2) + x**S(2)), x), x, b/tan(e + f*x)), x) def replacement3808(a, b, c, d, x): return Dist(S(1)/a, Int(cos(c + d*x)**S(2), x), x) def replacement3809(a, b, c, d, x): return Dist(S(1)/a, Int(sin(c + d*x)**S(2), x), x) def replacement3810(a, b, c, d, x): return -Dist(b/(a - b), Int(S(1)/((a + b*tan(c + d*x)**S(2))*cos(c + d*x)**S(2)), x), x) + Simp(x/(a - b), x) def replacement3811(a, b, c, d, x): return -Dist(b/(a - b), Int(S(1)/((a + b/tan(c + d*x)**S(2))*sin(c + d*x)**S(2)), x), x) + Simp(x/(a - b), x) def replacement3812(a, b, c, d, e, n, p, x): return Dist(e/d, Subst(Int((a + b*x**n)**p/(e**S(2) + x**S(2)), x), x, e*tan(c + d*x)), x) def replacement3813(a, b, c, d, e, n, p, x): return -Dist(e/d, Subst(Int((a + b*x**n)**p/(e**S(2) + x**S(2)), x), x, e/tan(c + d*x)), x) def With3814(a, b, c, d, e, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f**(m + S(1))/d, Subst(Int(x**m*(a + b*(e*f*x)**n)**p*(f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1)), x), x, tan(c + d*x)/f), x) def With3815(a, b, c, d, e, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f**(m + S(1))/d, Subst(Int(x**m*(a + b*(e*f*x)**n)**p*(f**S(2)*x**S(2) + S(1))**(-m/S(2) + S(-1)), x), x, S(1)/(f*tan(c + d*x))), x) def With3816(a, b, c, d, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f/d, Subst(Int((f*x)**(-n*p)*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*ExpandToSum(a*(f*x)**n + b*(-f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, cos(c + d*x)/f), x) def With3817(a, b, c, d, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f/d, Subst(Int((f*x)**(-n*p)*(-f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*ExpandToSum(a*(f*x)**n + b*(-f**S(2)*x**S(2) + S(1))**(n/S(2)), x)**p, x), x, sin(c + d*x)/f), x) def With3818(a, b, c, d, e, m, n, p, x): f = FreeFactors(tan(c + d*x), x) return Dist(f/d, Subst(Int((a + b*(e*f*x)**n)**p*(f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)), x), x, tan(c + d*x)/f), x) def With3819(a, b, c, d, e, m, n, p, x): f = FreeFactors(S(1)/tan(c + d*x), x) return -Dist(f/d, Subst(Int((a + b*(e*f*x)**n)**p*(f**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)), x), x, S(1)/(f*tan(c + d*x))), x) def With3820(a, b, c, d, m, n, p, x): f = FreeFactors(sin(c + d*x), x) return Dist(f/d, Subst(Int((-f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1)/2)*ExpandToSum(a*(-f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*(f*x)**n, x)**p, x), x, sin(c + d*x)/f), x) def With3821(a, b, c, d, m, n, p, x): f = FreeFactors(cos(c + d*x), x) return -Dist(f/d, Subst(Int((-f**S(2)*x**S(2) + S(1))**(-m/S(2) - n*p/S(2) + S(-1)/2)*ExpandToSum(a*(-f**S(2)*x**S(2) + S(1))**(n/S(2)) + b*(f*x)**n, x)**p, x), x, cos(c + d*x)/f), x) def replacement3822(a, b, c, d, e, m, n, p, x): return Dist(e/d, Subst(Int((x/e)**m*(a + b*x**n)**p/(e**S(2) + x**S(2)), x), x, e*tan(c + d*x)), x) def replacement3823(a, b, c, d, e, m, n, p, x): return -Dist(e/d, Subst(Int((x/e)**m*(a + b*x**n)**p/(e**S(2) + x**S(2)), x), x, e/tan(c + d*x)), x) def replacement3824(a, b, c, d, e, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*tan(d + e*x)**n)**(S(2)*p), x), x) def replacement3825(a, b, c, d, e, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(S(2)*p), x), x) def replacement3826(a, b, c, d, e, n, n2, p, x): return Dist((b + S(2)*c*tan(d + e*x)**n)**(-S(2)*p)*(a + b*tan(d + e*x)**n + c*tan(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*tan(d + e*x)**n)**(S(2)*p), x), x) def replacement3827(a, b, c, d, e, n, n2, p, x): return Dist((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(-S(2)*p)*(a + b*(S(1)/tan(d + e*x))**n + c*(S(1)/tan(d + e*x))**(S(2)*n))**p, Int((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(S(2)*p), x), x) def With3828(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*tan(d + e*x)**n - q), x), x) - Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*tan(d + e*x)**n + q), x), x) def With3829(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*(S(1)/tan(d + e*x))**n - q), x), x) - Dist(S(2)*c/q, Int(S(1)/(b + S(2)*c*(S(1)/tan(d + e*x))**n + q), x), x) def replacement3830(a, b, c, d, e, f, m, n, n2, p, x): return Dist(f/e, Subst(Int(x**m*(f**S(2) + x**S(2))**(-m/S(2) + S(-1))*(a + b*x**n + c*x**(S(2)*n))**p, x), x, f*tan(d + e*x)), x) def replacement3831(a, b, c, d, e, f, m, n, n2, p, x): return -Dist(f/e, Subst(Int(x**m*(f**S(2) + x**S(2))**(-m/S(2) + S(-1))*(a + b*x**n + c*x**(S(2)*n))**p, x), x, f/tan(d + e*x)), x) def With3832(a, b, c, d, e, m, n, n2, p, x): g = FreeFactors(cos(d + e*x), x) return -Dist(g/e, Subst(Int((g*x)**(-S(2)*n*p)*(-g**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*ExpandToSum(a*(g*x)**(S(2)*n) + b*(g*x)**n*(-g**S(2)*x**S(2) + S(1))**(n/S(2)) + c*(-g**S(2)*x**S(2) + S(1))**n, x)**p, x), x, cos(d + e*x)/g), x) def With3833(a, b, c, d, e, m, n, n2, p, x): g = FreeFactors(sin(d + e*x), x) return Dist(g/e, Subst(Int((g*x)**(-S(2)*n*p)*(-g**S(2)*x**S(2) + S(1))**(m/S(2) + S(-1)/2)*ExpandToSum(a*(g*x)**(S(2)*n) + b*(g*x)**n*(-g**S(2)*x**S(2) + S(1))**(n/S(2)) + c*(-g**S(2)*x**S(2) + S(1))**n, x)**p, x), x, sin(d + e*x)/g), x) def replacement3834(a, b, c, d, e, f, m, n, n2, p, x): return Dist(f**(m + S(1))/e, Subst(Int((f**S(2) + x**S(2))**(-m/S(2) + S(-1))*(a + b*x**n + c*x**(S(2)*n))**p, x), x, f*tan(d + e*x)), x) def replacement3835(a, b, c, d, e, f, m, n, n2, p, x): return -Dist(f**(m + S(1))/e, Subst(Int((f**S(2) + x**S(2))**(-m/S(2) + S(-1))*(a + b*x**n + c*x**(S(2)*n))**p, x), x, f/tan(d + e*x)), x) def With3836(a, b, c, d, e, m, n, n2, p, x): g = FreeFactors(sin(d + e*x), x) return Dist(g/e, Subst(Int((-g**S(2)*x**S(2) + S(1))**(m/S(2) - n*p + S(-1)/2)*ExpandToSum(a*(S(1) - x**S(2))**n + b*x**n*(S(1) - x**S(2))**(n/S(2)) + c*x**(S(2)*n), x)**p, x), x, sin(d + e*x)/g), x) def With3837(a, b, c, d, e, m, n, n2, p, x): g = FreeFactors(cos(d + e*x), x) return -Dist(g/e, Subst(Int((-g**S(2)*x**S(2) + S(1))**(m/S(2) - n*p + S(-1)/2)*ExpandToSum(a*(S(1) - x**S(2))**n + b*x**n*(S(1) - x**S(2))**(n/S(2)) + c*x**(S(2)*n), x)**p, x), x, cos(d + e*x)/g), x) def replacement3838(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*tan(d + e*x)**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def replacement3839(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def replacement3840(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*tan(d + e*x)**n)**(-S(2)*p)*(a + b*tan(d + e*x)**n + c*tan(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*tan(d + e*x)**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def replacement3841(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(-S(2)*p)*(a + b*(S(1)/tan(d + e*x))**n + c*(S(1)/tan(d + e*x))**(S(2)*n))**p, Int((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def replacement3842(a, b, c, d, e, f, m, n, n2, p, x): return Dist(f/e, Subst(Int((x/f)**m*(a + b*x**n + c*x**(S(2)*n))**p/(f**S(2) + x**S(2)), x), x, f*tan(d + e*x)), x) def replacement3843(a, b, c, d, e, f, m, n, n2, p, x): return -Dist(f/e, Subst(Int((x/f)**m*(a + b*x**n + c*x**(S(2)*n))**p/(f**S(2) + x**S(2)), x), x, f/tan(d + e*x)), x) def replacement3844(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*tan(d + e*x)**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def replacement3845(a, b, c, d, e, m, n, n2, p, x): return Dist(S(4)**(-p)*c**(-p), Int((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def replacement3846(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*tan(d + e*x)**n)**(-S(2)*p)*(a + b*tan(d + e*x)**n + c*tan(d + e*x)**(S(2)*n))**p, Int((b + S(2)*c*tan(d + e*x)**n)**(S(2)*p)*(S(1)/tan(d + e*x))**m, x), x) def replacement3847(a, b, c, d, e, m, n, n2, p, x): return Dist((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(-S(2)*p)*(a + b*(S(1)/tan(d + e*x))**n + c*(S(1)/tan(d + e*x))**(S(2)*n))**p, Int((b + S(2)*c*(S(1)/tan(d + e*x))**n)**(S(2)*p)*tan(d + e*x)**m, x), x) def With3848(a, b, c, d, e, m, n, n2, p, x): g = FreeFactors(S(1)/tan(d + e*x), x) return Dist(g/e, Subst(Int((g*x)**(m - S(2)*n*p)*(a*(g*x)**(S(2)*n) + b*(g*x)**n + c)**p/(g**S(2)*x**S(2) + S(1)), x), x, S(1)/(g*tan(d + e*x))), x) def With3849(a, b, c, d, e, m, n, n2, p, x): g = FreeFactors(tan(d + e*x), x) return -Dist(g/e, Subst(Int((g*x)**(m - S(2)*n*p)*(a*(g*x)**(S(2)*n) + b*(g*x)**n + c)**p/(g**S(2)*x**S(2) + S(1)), x), x, tan(d + e*x)/g), x) def replacement3850(A, B, a, b, c, d, e, n, x): return Dist(S(4)**(-n)*c**(-n), Int((A + B*tan(d + e*x))*(b + S(2)*c*tan(d + e*x))**(S(2)*n), x), x) def replacement3851(A, B, a, b, c, d, e, n, x): return Dist(S(4)**(-n)*c**(-n), Int((A + B/tan(d + e*x))*(b + S(2)*c/tan(d + e*x))**(S(2)*n), x), x) def replacement3852(A, B, a, b, c, d, e, n, x): return Dist((b + S(2)*c*tan(d + e*x))**(-S(2)*n)*(a + b*tan(d + e*x) + c*tan(d + e*x)**S(2))**n, Int((A + B*tan(d + e*x))*(b + S(2)*c*tan(d + e*x))**(S(2)*n), x), x) def replacement3853(A, B, a, b, c, d, e, n, x): return Dist((b + S(2)*c/tan(d + e*x))**(-S(2)*n)*(a + b/tan(d + e*x) + c/tan(d + e*x)**S(2))**n, Int((A + B/tan(d + e*x))*(b + S(2)*c/tan(d + e*x))**(S(2)*n), x), x) def With3854(A, B, a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(B - (-S(2)*A*c + B*b)/q, Int(S(1)/Simp(b + S(2)*c*tan(d + e*x) - q, x), x), x) + Dist(B + (-S(2)*A*c + B*b)/q, Int(S(1)/Simp(b + S(2)*c*tan(d + e*x) + q, x), x), x) def With3855(A, B, a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(B - (-S(2)*A*c + B*b)/q, Int(S(1)/Simp(b + S(2)*c/tan(d + e*x) - q, x), x), x) + Dist(B + (-S(2)*A*c + B*b)/q, Int(S(1)/Simp(b + S(2)*c/tan(d + e*x) + q, x), x), x) def replacement3856(A, B, a, b, c, d, e, n, x): return Int(ExpandTrig((A + B*tan(d + e*x))*(a + b*tan(d + e*x) + c*tan(d + e*x)**S(2))**n, x), x) def replacement3857(A, B, a, b, c, d, e, n, x): return Int(ExpandTrig((A + B/tan(d + e*x))*(a + b/tan(d + e*x) + c/tan(d + e*x)**S(2))**n, x), x) def replacement3858(c, d, e, f, m, x): return -Dist(S(2)*I, Int((c + d*x)**m*exp(S(2)*I*(e + f*x))/(exp(S(2)*I*(e + f*x)) + S(1)), x), x) + Simp(I*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement3859(c, d, e, f, m, x): return -Dist(S(2)*I, Int((c + d*x)**m*exp(S(2)*I*(e + f*x))/(S(1) - exp(S(2)*I*(e + f*x))), x), x) - Simp(I*(c + d*x)**(m + S(1))/(d*(m + S(1))), x) def replacement3860(b, c, d, e, f, m, n, x): return -Dist(b**S(2), Int((b*tan(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) - Dist(b*d*m/(f*(n + S(-1))), Int((b*tan(e + f*x))**(n + S(-1))*(c + d*x)**(m + S(-1)), x), x) + Simp(b*(b*tan(e + f*x))**(n + S(-1))*(c + d*x)**m/(f*(n + S(-1))), x) def replacement3861(b, c, d, e, f, m, n, x): return -Dist(b**S(2), Int((b/tan(e + f*x))**(n + S(-2))*(c + d*x)**m, x), x) + Dist(b*d*m/(f*(n + S(-1))), Int((b/tan(e + f*x))**(n + S(-1))*(c + d*x)**(m + S(-1)), x), x) - Simp(b*(b/tan(e + f*x))**(n + S(-1))*(c + d*x)**m/(f*(n + S(-1))), x) def replacement3862(b, c, d, e, f, m, n, x): return -Dist(b**(S(-2)), Int((b*tan(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) - Dist(d*m/(b*f*(n + S(1))), Int((b*tan(e + f*x))**(n + S(1))*(c + d*x)**(m + S(-1)), x), x) + Simp((b*tan(e + f*x))**(n + S(1))*(c + d*x)**m/(b*f*(n + S(1))), x) def replacement3863(b, c, d, e, f, m, n, x): return -Dist(b**(S(-2)), Int((b/tan(e + f*x))**(n + S(2))*(c + d*x)**m, x), x) + Dist(d*m/(b*f*(n + S(1))), Int((b/tan(e + f*x))**(n + S(1))*(c + d*x)**(m + S(-1)), x), x) - Simp((b/tan(e + f*x))**(n + S(1))*(c + d*x)**m/(b*f*(n + S(1))), x) def replacement3864(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b*tan(e + f*x))**n, x), x) def replacement3865(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (a + b/tan(e + f*x))**n, x), x) def replacement3866(a, b, c, d, e, f, m, x): return Dist(a*d*m/(S(2)*b*f), Int((c + d*x)**(m + S(-1))/(a + b*tan(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) - Simp(a*(c + d*x)**m/(S(2)*b*f*(a + b*tan(e + f*x))), x) def replacement3867(a, b, c, d, e, f, m, x): return -Dist(a*d*m/(S(2)*b*f), Int((c + d*x)**(m + S(-1))/(a + b/tan(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) + Simp(a*(c + d*x)**m/(S(2)*b*f*(a + b/tan(e + f*x))), x) def replacement3868(a, b, c, d, e, f, x): return -Dist(f/(a*d), Int(sin(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Dist(f/(b*d), Int(cos(S(2)*e + S(2)*f*x)/(c + d*x), x), x) - Simp(S(1)/(d*(a + b*tan(e + f*x))*(c + d*x)), x) def replacement3869(a, b, c, d, e, f, x): return Dist(f/(a*d), Int(sin(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Dist(f/(b*d), Int(cos(S(2)*e + S(2)*f*x)/(c + d*x), x), x) - Simp(S(1)/(d*(a + b/tan(e + f*x))*(c + d*x)), x) def replacement3870(a, b, c, d, e, f, m, x): return Dist(S(2)*b*f/(a*d*(m + S(1))), Int((c + d*x)**(m + S(1))/(a + b*tan(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a + b*tan(e + f*x))*(m + S(1))), x) + Simp(f*(c + d*x)**(m + S(2))/(b*d**S(2)*(m + S(1))*(m + S(2))), x) def replacement3871(a, b, c, d, e, f, m, x): return -Dist(S(2)*b*f/(a*d*(m + S(1))), Int((c + d*x)**(m + S(1))/(a + b/tan(e + f*x)), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a + b/tan(e + f*x))*(m + S(1))), x) - Simp(f*(c + d*x)**(m + S(2))/(b*d**S(2)*(m + S(1))*(m + S(2))), x) def replacement3872(a, b, c, d, e, f, x): return Dist(S(1)/(S(2)*a), Int(cos(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Dist(S(1)/(S(2)*b), Int(sin(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Simp(log(c + d*x)/(S(2)*a*d), x) def replacement3873(a, b, c, d, e, f, x): return -Dist(S(1)/(S(2)*a), Int(cos(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Dist(S(1)/(S(2)*b), Int(sin(S(2)*e + S(2)*f*x)/(c + d*x), x), x) + Simp(log(c + d*x)/(S(2)*a*d), x) def replacement3874(a, b, c, d, e, f, m, x): return Dist(S(1)/(S(2)*a), Int((c + d*x)**m*exp(S(2)*a*(e + f*x)/b), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) def replacement3875(a, b, c, d, e, f, m, x): return -Dist(S(1)/(S(2)*a), Int((c + d*x)**m*exp(-S(2)*a*(e + f*x)/b), x), x) + Simp((c + d*x)**(m + S(1))/(S(2)*a*d*(m + S(1))), x) def replacement3876(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (sin(S(2)*e + S(2)*f*x)/(S(2)*b) + cos(S(2)*e + S(2)*f*x)/(S(2)*a) + S(1)/(S(2)*a))**(-n), x), x) def replacement3877(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (sin(S(2)*e + S(2)*f*x)/(S(2)*b) - cos(S(2)*e + S(2)*f*x)/(S(2)*a) + S(1)/(S(2)*a))**(-n), x), x) def replacement3878(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (exp(S(2)*a*(e + f*x)/b)/(S(2)*a) + S(1)/(S(2)*a))**(-n), x), x) def replacement3879(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (S(1)/(S(2)*a) - exp(-S(2)*a*(e + f*x)/b)/(S(2)*a))**(-n), x), x) def With3880(a, b, c, d, e, f, m, n, x): u = IntHide((a + b*tan(e + f*x))**n, x) return -Dist(d*m, Int(Dist((c + d*x)**(m + S(-1)), u, x), x), x) + Dist((c + d*x)**m, u, x) def With3881(a, b, c, d, e, f, m, n, x): u = IntHide((a + b/tan(e + f*x))**n, x) return -Dist(d*m, Int(Dist((c + d*x)**(m + S(-1)), u, x), x), x) + Dist((c + d*x)**m, u, x) def replacement3882(a, b, c, d, e, f, m, x): return -Dist(S(2)*I*b, Int((c + d*x)**m/(a**S(2) + b**S(2) + (a - I*b)**S(2)*exp(S(2)*I*(e + f*x))), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a - I*b)*(m + S(1))), x) def replacement3883(a, b, c, d, e, f, m, x): return Dist(S(2)*I*b, Int((c + d*x)**m/(a**S(2) + b**S(2) - (a + I*b)**S(2)*exp(S(2)*I*(e + f*x))), x), x) + Simp((c + d*x)**(m + S(1))/(d*(a + I*b)*(m + S(1))), x) def replacement3884(a, b, c, d, e, f, x): return Dist(S(1)/(f*(a**S(2) + b**S(2))), Int((S(2)*a*c*f + S(2)*a*d*f*x + b*d)/(a + b*tan(e + f*x)), x), x) - Simp((c + d*x)**S(2)/(S(2)*d*(a**S(2) + b**S(2))), x) - Simp(b*(c + d*x)/(f*(a + b*tan(e + f*x))*(a**S(2) + b**S(2))), x) def replacement3885(a, b, c, d, e, f, x): return -Dist(S(1)/(f*(a**S(2) + b**S(2))), Int((-S(2)*a*c*f - S(2)*a*d*f*x + b*d)/(a + b/tan(e + f*x)), x), x) - Simp((c + d*x)**S(2)/(S(2)*d*(a**S(2) + b**S(2))), x) + Simp(b*(c + d*x)/(f*(a + b/tan(e + f*x))*(a**S(2) + b**S(2))), x) def replacement3886(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (-S(2)*I*b/(a**S(2) + b**S(2) + (a - I*b)**S(2)*exp(S(2)*I*(e + f*x))) + S(1)/(a - I*b))**(-n), x), x) def replacement3887(a, b, c, d, e, f, m, n, x): return Int(ExpandIntegrand((c + d*x)**m, (S(2)*I*b/(a**S(2) + b**S(2) - (a + I*b)**S(2)*exp(S(2)*I*(e + f*x))) + S(1)/(a + I*b))**(-n), x), x) def replacement3888(a, b, m, n, u, v, x): return Int((a + b*tan(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement3889(a, b, m, n, u, v, x): return Int((a + b/tan(ExpandToSum(v, x)))**n*ExpandToSum(u, x)**m, x) def replacement3890(a, b, c, d, e, f, m, n, x): return Int((a + b*tan(e + f*x))**n*(c + d*x)**m, x) def replacement3891(a, b, c, d, e, f, m, n, x): return Int((a + b/tan(e + f*x))**n*(c + d*x)**m, x) def replacement3892(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b*tan(c + d*x))**p, x), x, x**n), x) def replacement3893(a, b, c, d, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + S(1)/n)*(a + b/tan(c + d*x))**p, x), x, x**n), x) def replacement3894(a, b, c, d, n, p, x): return Int((a + b*tan(c + d*x**n))**p, x) def replacement3895(a, b, c, d, n, p, x): return Int((a + b/tan(c + d*x**n))**p, x) def replacement3896(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*tan(c + d*x**n))**p, x), x, u), x) def replacement3897(a, b, c, d, n, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b/tan(c + d*x**n))**p, x), x, u), x) def replacement3898(a, b, p, u, x): return Int((a + b*tan(ExpandToSum(u, x)))**p, x) def replacement3899(a, b, p, u, x): return Int((a + b/tan(ExpandToSum(u, x)))**p, x) def replacement3900(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*tan(c + d*x))**p, x), x, x**n), x) def replacement3901(a, b, c, d, m, n, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b/tan(c + d*x))**p, x), x, x**n), x) def replacement3902(c, d, m, n, x): return -Dist((m - n + S(1))/(d*n), Int(x**(m - n)*tan(c + d*x**n), x), x) - Int(x**m, x) + Simp(x**(m - n + S(1))*tan(c + d*x**n)/(d*n), x) def replacement3903(c, d, m, n, x): return Dist((m - n + S(1))/(d*n), Int(x**(m - n)/tan(c + d*x**n), x), x) - Int(x**m, x) - Simp(x**(m - n + S(1))/(d*n*tan(c + d*x**n)), x) def replacement3904(a, b, c, d, m, n, p, x): return Int(x**m*(a + b*tan(c + d*x**n))**p, x) def replacement3905(a, b, c, d, m, n, p, x): return Int(x**m*(a + b/tan(c + d*x**n))**p, x) def replacement3906(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b*tan(c + d*x**n))**p, x), x) def replacement3907(a, b, c, d, e, m, n, p, x): return Dist(e**IntPart(m)*x**(-FracPart(m))*(e*x)**FracPart(m), Int(x**m*(a + b/tan(c + d*x**n))**p, x), x) def replacement3908(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b*tan(ExpandToSum(u, x)))**p, x) def replacement3909(a, b, e, m, p, u, x): return Int((e*x)**m*(a + b/tan(ExpandToSum(u, x)))**p, x) def replacement3910(a, b, m, n, p, q, x): return -Dist((m - n + S(1))/(b*n*p), Int(x**(m - n)*(S(1)/cos(a + b*x**n))**p, x), x) + Simp(x**(m - n + S(1))*(S(1)/cos(a + b*x**n))**p/(b*n*p), x) def replacement3911(a, b, m, n, p, q, x): return Dist((m - n + S(1))/(b*n*p), Int(x**(m - n)*(S(1)/sin(a + b*x**n))**p, x), x) - Simp(x**(m - n + S(1))*(S(1)/sin(a + b*x**n))**p/(b*n*p), x) def replacement3912(a, b, c, n, x): return Int(tan(a + b*x + c*x**S(2))**n, x) def replacement3913(a, b, c, n, x): return Int((S(1)/tan(a + b*x + c*x**S(2)))**n, x) def replacement3914(a, b, c, d, e, x): return -Simp(e*log(cos(a + b*x + c*x**S(2)))/(S(2)*c), x) def replacement3915(a, b, c, d, e, x): return Simp(e*log(sin(a + b*x + c*x**S(2)))/(S(2)*c), x) def replacement3916(a, b, c, d, e, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int(tan(a + b*x + c*x**S(2)), x), x) - Simp(e*log(cos(a + b*x + c*x**S(2)))/(S(2)*c), x) def replacement3917(a, b, c, d, e, x): return Dist((-b*e + S(2)*c*d)/(S(2)*c), Int(S(1)/tan(a + b*x + c*x**S(2)), x), x) + Simp(e*log(sin(a + b*x + c*x**S(2)))/(S(2)*c), x) def replacement3918(a, b, c, d, e, m, n, x): return Int((d + e*x)**m*tan(a + b*x + c*x**S(2))**n, x) def replacement3919(a, b, c, d, e, m, n, x): return Int((d + e*x)**m*(S(1)/tan(a + b*x + c*x**S(2)))**n, x) sympy-sympy-1.9/sympy/integrals/rubi/rules/trinomial_products.py000066400000000000000000007316241412543434000254770ustar00rootroot00000000000000""" This code is automatically generated. Never edit it manually. For details of generating the code see `rubi_parsing_guide.md` in `parsetools`. """ from sympy.external import import_module matchpy = import_module("matchpy") if matchpy: from matchpy import Pattern, ReplacementRule, CustomConstraint, is_match from sympy.integrals.rubi.utility_function import ( Int, Sum, Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, NFreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, PureComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, Subst, First, Rest, SqrtNumberQ, SqrtNumberSumQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, EllipticPi, EllipticE, EllipticF, ArcTan, ArcCot, ArcCoth, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcSec, ArcCsch, ArcSech, Sinh, Tanh, Cosh, Sech, Csch, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, Sin, Cos, Tan, Cot, Sec, Csc, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, TrigHyperbolicFreeQ, InverseFunctionFreeQ, RealQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, SubstForAux, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, Sum_doit, PolynomialQuotient, Floor, PolynomialRemainder, Factor, PolyLog, CosIntegral, SinIntegral, LogIntegral, SinhIntegral, CoshIntegral, Rule, Erf, PolyGamma, ExpIntegralEi, ExpIntegralE, LogGamma , UtilityOperator, Factorial, Zeta, ProductLog, DerivativeDivides, HypergeometricPFQ, IntHide, OneQ, Null, rubi_exp as exp, rubi_log as log, Discriminant, Negative, Quotient ) from sympy import (Integral, S, sqrt, And, Or, Integer, Float, Mod, I, Abs, simplify, Mul, Add, Pow, sign, EulerGamma) from sympy.integrals.rubi.symbol import WC from sympy.core.symbol import symbols, Symbol from sympy.functions import (sin, cos, tan, cot, csc, sec, sqrt, erf) from sympy.functions.elementary.hyperbolic import (acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch) from sympy.functions.elementary.trigonometric import (atan, acsc, asin, acot, acos, asec, atan2) from sympy import pi as Pi A_, B_, C_, F_, G_, H_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, y_, z_ = [WC(i) for i in 'ABCFGHabcdefghijklmnpqrtuvswxyz'] a1_, a2_, b1_, b2_, c1_, c2_, d1_, d2_, n1_, n2_, e1_, e2_, f1_, f2_, g1_, g2_, n1_, n2_, n3_, Pq_, Pm_, Px_, Qm_, Qr_, Qx_, jn_, mn_, non2_, RFx_, RGx_ = [WC(i) for i in ['a1', 'a2', 'b1', 'b2', 'c1', 'c2', 'd1', 'd2', 'n1', 'n2', 'e1', 'e2', 'f1', 'f2', 'g1', 'g2', 'n1', 'n2', 'n3', 'Pq', 'Pm', 'Px', 'Qm', 'Qr', 'Qx', 'jn', 'mn', 'non2', 'RFx', 'RGx']] i, ii, Pqq, Q, R, r, C, k, u = symbols('i ii Pqq Q R r C k u') _UseGamma = False ShowSteps = False StepCounter = None def trinomial_products(): from sympy.integrals.rubi.constraints import cons48, cons89, cons465, cons40, cons2, cons3, cons8, cons491, cons5, cons47, cons149, cons666, cons4, cons667, cons586, cons668, cons13, cons165, cons669, cons316, cons670, cons464, cons198, cons671, cons672, cons148, cons673, cons674, cons340, cons139, cons228, cons130, cons248, cons675, cons676, cons415, cons677, cons295, cons678, cons679, cons486, cons179, cons680, cons681, cons682, cons587, cons683, cons70, cons71, cons55, cons19, cons503, cons29, cons65, cons504, cons684, cons157, cons685, cons686, cons227, cons58, cons245, cons150, cons246, cons687, cons20, cons688, cons689, cons512, cons690, cons691, cons692, cons531, cons33, cons532, cons693, cons96, cons369, cons358, cons502, cons694, cons695, cons696, cons697, cons698, cons699, cons700, cons701, cons702, cons703, cons543, cons25, cons704, cons554, cons555, cons556, cons222, cons50, cons52, cons705, cons706, cons258, cons259, cons281, cons223, cons282, cons397, cons398, cons707, cons708, cons709, cons710, cons711, cons87, cons712, cons713, cons714, cons715, cons588, cons388, cons151, cons716, cons45, cons717, cons450, cons718, cons402, cons719, cons720, cons721, cons349, cons566, cons722, cons270, cons723, cons724, cons725, cons726, cons727, cons728, cons729, cons730, cons127, cons210, cons54, cons595, cons731, cons732, cons733, cons654, cons734, cons656, cons36, cons37, cons735, cons21, cons736, cons466, cons737, cons170, cons269, cons738, cons739, cons740, cons741, cons742, cons83, cons436, cons743, cons744, cons745, cons746, cons613, cons405, cons747, cons748, cons749, cons750, cons751, cons752, cons753, cons754, cons755, cons756, cons757, cons758, cons759, cons760, cons761, cons762, cons608, cons763, cons764, cons765, cons766, cons767, cons768, cons769, cons770, cons771, cons772, cons773, cons774, cons775, cons776, cons777, cons778, cons779, cons780, cons781, cons782, cons783, cons784, cons785, cons786, cons787, cons788, cons789, cons790, cons791, cons792, cons793, cons794, cons795, cons796, cons797, cons798, cons799 pattern1079 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons48, cons89, cons465, cons40) rule1079 = ReplacementRule(pattern1079, replacement1079) pattern1080 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons491) rule1080 = ReplacementRule(pattern1080, With1080) pattern1081 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons47, cons149, cons666) rule1081 = ReplacementRule(pattern1081, replacement1081) pattern1082 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons47, cons149, cons667, cons586) rule1082 = ReplacementRule(pattern1082, replacement1082) pattern1083 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons47, cons668, cons13, cons165, cons669) rule1083 = ReplacementRule(pattern1083, replacement1083) pattern1084 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons47, cons668, cons13, cons165, cons316) rule1084 = ReplacementRule(pattern1084, replacement1084) pattern1085 = Pattern(Integral(sqrt(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons4, cons48, cons47, cons586, cons670, cons464) rule1085 = ReplacementRule(pattern1085, replacement1085) pattern1086 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons47, cons149, cons198) rule1086 = ReplacementRule(pattern1086, replacement1086) pattern1087 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons47, cons149, cons671, cons672, cons13, cons148) rule1087 = ReplacementRule(pattern1087, replacement1087) pattern1088 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons47, cons149, cons673, cons674, cons340, cons139) rule1088 = ReplacementRule(pattern1088, replacement1088) pattern1089 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons47, cons149) rule1089 = ReplacementRule(pattern1089, replacement1089) pattern1090 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons48, cons198) rule1090 = ReplacementRule(pattern1090, replacement1090) pattern1091 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons228, cons130) rule1091 = ReplacementRule(pattern1091, replacement1091) pattern1092 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons228, cons13, cons165, cons671, cons248, cons675) rule1092 = ReplacementRule(pattern1092, replacement1092) pattern1093 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons48, cons228, cons13, cons139, cons248, cons675) rule1093 = ReplacementRule(pattern1093, replacement1093) pattern1094 = Pattern(Integral(S(1)/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons48, cons228, cons676, cons415) rule1094 = ReplacementRule(pattern1094, With1094) pattern1095 = Pattern(Integral(S(1)/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons48, cons228) rule1095 = ReplacementRule(pattern1095, With1095) pattern1096 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, cons295) rule1096 = ReplacementRule(pattern1096, With1096) pattern1097 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, cons678, cons679) rule1097 = ReplacementRule(pattern1097, With1097) pattern1098 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, cons486, cons179, CustomConstraint(With1098)) rule1098 = ReplacementRule(pattern1098, replacement1098) pattern1099 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, cons486, cons179) rule1099 = ReplacementRule(pattern1099, With1099) pattern1100 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1100)) rule1100 = ReplacementRule(pattern1100, replacement1100) pattern1101 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1101)) rule1101 = ReplacementRule(pattern1101, replacement1101) pattern1102 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1102)) rule1102 = ReplacementRule(pattern1102, replacement1102) pattern1103 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1103)) rule1103 = ReplacementRule(pattern1103, replacement1103) pattern1104 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons228, cons680) rule1104 = ReplacementRule(pattern1104, With1104) pattern1105 = Pattern(Integral(S(1)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons228, cons681) rule1105 = ReplacementRule(pattern1105, With1105) pattern1106 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons682) rule1106 = ReplacementRule(pattern1106, replacement1106) pattern1107 = Pattern(Integral((a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons587, cons40, cons683) rule1107 = ReplacementRule(pattern1107, replacement1107) pattern1108 = Pattern(Integral((a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons587, cons149, cons683) rule1108 = ReplacementRule(pattern1108, replacement1108) pattern1109 = Pattern(Integral((a_ + u_**n_*WC('b', S(1)) + u_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons48, cons70, cons71) rule1109 = ReplacementRule(pattern1109, replacement1109) pattern1110 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons682, cons55) rule1110 = ReplacementRule(pattern1110, replacement1110) pattern1111 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons682, cons130, cons503) rule1111 = ReplacementRule(pattern1111, replacement1111) pattern1112 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons682, cons65, cons504) rule1112 = ReplacementRule(pattern1112, replacement1112) pattern1113 = Pattern(Integral(sqrt(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))/x_, x_), cons2, cons3, cons8, cons4, cons682, cons47) rule1113 = ReplacementRule(pattern1113, replacement1113) pattern1114 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_/x_, x_), cons2, cons3, cons8, cons4, cons682, cons47, cons13, cons148) rule1114 = ReplacementRule(pattern1114, replacement1114) pattern1115 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_/x_, x_), cons2, cons3, cons8, cons4, cons682, cons47, cons13, cons139) rule1115 = ReplacementRule(pattern1115, replacement1115) pattern1116 = Pattern(Integral((a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_/x_, x_), cons2, cons3, cons8, cons4, cons5, cons682, cons47, cons149) rule1116 = ReplacementRule(pattern1116, replacement1116) pattern1117 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons682, cons47, cons684) rule1117 = ReplacementRule(pattern1117, replacement1117) pattern1118 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*sqrt(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons682, cons47, cons157) rule1118 = ReplacementRule(pattern1118, replacement1118) pattern1119 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*sqrt(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons682, cons47, cons685) rule1119 = ReplacementRule(pattern1119, replacement1119) pattern1120 = Pattern(Integral(x_**WC('m', S(1))/sqrt(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons19, cons4, cons682, cons47, cons157) rule1120 = ReplacementRule(pattern1120, replacement1120) pattern1121 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons682, cons47, cons686, cons227) rule1121 = ReplacementRule(pattern1121, replacement1121) pattern1122 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons682, cons47, cons58, cons245) rule1122 = ReplacementRule(pattern1122, replacement1122) pattern1123 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons47, cons150, cons246, cons148, cons687, cons248, cons20) rule1123 = ReplacementRule(pattern1123, replacement1123) pattern1124 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons47, cons150, cons246, cons148, cons688, cons689, cons248, cons20) rule1124 = ReplacementRule(pattern1124, replacement1124) pattern1125 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons682, cons47, cons150, cons13, cons148, cons512, cons690, cons689, cons691, cons248) rule1125 = ReplacementRule(pattern1125, replacement1125) pattern1126 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons47, cons150, cons246, cons139, cons692, cons248) rule1126 = ReplacementRule(pattern1126, replacement1126) pattern1127 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons47, cons150, cons246, cons139, cons531, cons248) rule1127 = ReplacementRule(pattern1127, replacement1127) pattern1128 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons682, cons47, cons150, cons246, cons139, cons248) rule1128 = ReplacementRule(pattern1128, replacement1128) pattern1129 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons682, cons47, cons150, cons33, cons532, cons512, cons693) rule1129 = ReplacementRule(pattern1129, replacement1129) pattern1130 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons682, cons47, cons150, cons33, cons96, cons693) rule1130 = ReplacementRule(pattern1130, replacement1130) pattern1131 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons682, cons47, cons198, cons20) rule1131 = ReplacementRule(pattern1131, replacement1131) pattern1132 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons682, cons47, cons198, cons369) rule1132 = ReplacementRule(pattern1132, With1132) pattern1133 = Pattern(Integral((x_*WC('d', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons682, cons47, cons198, cons358) rule1133 = ReplacementRule(pattern1133, replacement1133) pattern1134 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons682, cons47, cons149) rule1134 = ReplacementRule(pattern1134, replacement1134) pattern1135 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons682, cons228, cons502) rule1135 = ReplacementRule(pattern1135, replacement1135) pattern1136 = Pattern(Integral((d_*x_)**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons682, cons228, cons502) rule1136 = ReplacementRule(pattern1136, replacement1136) pattern1137 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons682, cons228, cons150, cons20, CustomConstraint(With1137)) rule1137 = ReplacementRule(pattern1137, replacement1137) pattern1138 = Pattern(Integral((x_*WC('d', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons682, cons228, cons150, cons369, cons40) rule1138 = ReplacementRule(pattern1138, With1138) pattern1139 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons228, cons150, cons246, cons165, cons532, cons694, cons695, cons696) rule1139 = ReplacementRule(pattern1139, replacement1139) pattern1140 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons228, cons150, cons246, cons165, cons96, cons696) rule1140 = ReplacementRule(pattern1140, replacement1140) pattern1141 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons682, cons228, cons150, cons13, cons165, cons512, cons696) rule1141 = ReplacementRule(pattern1141, replacement1141) pattern1142 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons228, cons150, cons246, cons139, cons692, cons696) rule1142 = ReplacementRule(pattern1142, replacement1142) pattern1143 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons682, cons228, cons150, cons246, cons139, cons531, cons696) rule1143 = ReplacementRule(pattern1143, replacement1143) pattern1144 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons682, cons228, cons150, cons13, cons139, cons696) rule1144 = ReplacementRule(pattern1144, replacement1144) pattern1145 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons682, cons228, cons150, cons33, cons531, cons512, cons696) rule1145 = ReplacementRule(pattern1145, replacement1145) pattern1146 = Pattern(Integral((x_*WC('d', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons682, cons228, cons150, cons33, cons96, cons696) rule1146 = ReplacementRule(pattern1146, replacement1146) pattern1147 = Pattern(Integral((x_*WC('d', S(1)))**m_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons682, cons228, cons150, cons33, cons96) rule1147 = ReplacementRule(pattern1147, replacement1147) pattern1148 = Pattern(Integral(x_**m_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons682, cons228, cons150, cons20, cons697) rule1148 = ReplacementRule(pattern1148, replacement1148) pattern1149 = Pattern(Integral((x_*WC('d', S(1)))**m_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons682, cons228, cons150, cons33, cons531) rule1149 = ReplacementRule(pattern1149, replacement1149) pattern1150 = Pattern(Integral(x_**S(2)/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons698, cons699) rule1150 = ReplacementRule(pattern1150, With1150) pattern1151 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons48, cons228, cons700, cons701, cons415) rule1151 = ReplacementRule(pattern1151, With1151) pattern1152 = Pattern(Integral(x_**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons48, cons228, cons700, cons702, cons415) rule1152 = ReplacementRule(pattern1152, With1152) pattern1153 = Pattern(Integral((x_*WC('d', S(1)))**m_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons682, cons228, cons150, cons33, cons703) rule1153 = ReplacementRule(pattern1153, With1153) pattern1154 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons682, cons228, cons150) rule1154 = ReplacementRule(pattern1154, With1154) pattern1155 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, cons295) rule1155 = ReplacementRule(pattern1155, With1155) pattern1156 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, cons678, cons679) rule1156 = ReplacementRule(pattern1156, With1156) pattern1157 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, cons486, cons179) rule1157 = ReplacementRule(pattern1157, With1157) pattern1158 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1158)) rule1158 = ReplacementRule(pattern1158, replacement1158) pattern1159 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1159)) rule1159 = ReplacementRule(pattern1159, replacement1159) pattern1160 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1160)) rule1160 = ReplacementRule(pattern1160, replacement1160) pattern1161 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons677, CustomConstraint(With1161)) rule1161 = ReplacementRule(pattern1161, replacement1161) pattern1162 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons228, cons680) rule1162 = ReplacementRule(pattern1162, With1162) pattern1163 = Pattern(Integral(x_**S(2)/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons228, cons681) rule1163 = ReplacementRule(pattern1163, With1163) pattern1164 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons5, cons682, cons228, cons198, cons20) rule1164 = ReplacementRule(pattern1164, replacement1164) pattern1165 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons5, cons682, cons228, cons198, cons369) rule1165 = ReplacementRule(pattern1165, With1165) pattern1166 = Pattern(Integral((x_*WC('d', S(1)))**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons682, cons228, cons198, cons358) rule1166 = ReplacementRule(pattern1166, replacement1166) pattern1167 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons5, cons682, cons228, cons491) rule1167 = ReplacementRule(pattern1167, With1167) pattern1168 = Pattern(Integral((d_*x_)**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons5, cons682, cons228, cons491) rule1168 = ReplacementRule(pattern1168, replacement1168) pattern1169 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons682, cons228, cons543, cons25) rule1169 = ReplacementRule(pattern1169, replacement1169) pattern1170 = Pattern(Integral((d_*x_)**m_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons682, cons228, cons543, cons25) rule1170 = ReplacementRule(pattern1170, replacement1170) pattern1171 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons682, cons228) rule1171 = ReplacementRule(pattern1171, With1171) pattern1172 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons682, cons228, cons704) rule1172 = ReplacementRule(pattern1172, replacement1172) pattern1173 = Pattern(Integral((x_*WC('d', S(1)))**WC('m', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons682) rule1173 = ReplacementRule(pattern1173, replacement1173) pattern1174 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons587, cons40, cons683) rule1174 = ReplacementRule(pattern1174, replacement1174) pattern1175 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons587, cons149, cons683) rule1175 = ReplacementRule(pattern1175, replacement1175) pattern1176 = Pattern(Integral((d_*x_)**WC('m', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons19, cons4, cons5, cons587) rule1176 = ReplacementRule(pattern1176, replacement1176) pattern1177 = Pattern(Integral(x_**WC('m', S(1))*(v_**n_*WC('b', S(1)) + v_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons4, cons5, cons682, cons554, cons20, cons555) rule1177 = ReplacementRule(pattern1177, replacement1177) pattern1178 = Pattern(Integral(u_**WC('m', S(1))*(v_**n_*WC('b', S(1)) + v_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons682, cons556) rule1178 = ReplacementRule(pattern1178, replacement1178) pattern1179 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons222, cons504) rule1179 = ReplacementRule(pattern1179, replacement1179) pattern1180 = Pattern(Integral((a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons222, cons504) rule1180 = ReplacementRule(pattern1180, replacement1180) pattern1181 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons48, cons198) rule1181 = ReplacementRule(pattern1181, replacement1181) pattern1182 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons5, cons52, cons48, cons198) rule1182 = ReplacementRule(pattern1182, replacement1182) pattern1183 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons48, cons491) rule1183 = ReplacementRule(pattern1183, With1183) pattern1184 = Pattern(Integral((a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons5, cons52, cons48, cons491) rule1184 = ReplacementRule(pattern1184, With1184) pattern1185 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons3, cons8, cons29, cons50, cons4, cons5, cons48, cons149, cons666) rule1185 = ReplacementRule(pattern1185, replacement1185) pattern1186 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons3, cons8, cons29, cons50, cons4, cons5, cons48, cons149, cons673, cons705) rule1186 = ReplacementRule(pattern1186, replacement1186) pattern1187 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons3, cons8, cons29, cons50, cons4, cons5, cons48, cons149, cons673, cons706) rule1187 = ReplacementRule(pattern1187, replacement1187) pattern1188 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons149) rule1188 = ReplacementRule(pattern1188, replacement1188) pattern1189 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons47, cons149) rule1189 = ReplacementRule(pattern1189, replacement1189) pattern1190 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons48, cons228, cons258, cons40) rule1190 = ReplacementRule(pattern1190, replacement1190) pattern1191 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons4, cons52, cons48, cons259, cons40) rule1191 = ReplacementRule(pattern1191, replacement1191) pattern1192 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons228, cons258, cons149) rule1192 = ReplacementRule(pattern1192, replacement1192) pattern1193 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons259, cons149) rule1193 = ReplacementRule(pattern1193, replacement1193) pattern1194 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons281, cons223) rule1194 = ReplacementRule(pattern1194, replacement1194) pattern1195 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons282, cons223) rule1195 = ReplacementRule(pattern1195, replacement1195) pattern1196 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons281, cons397, cons398) rule1196 = ReplacementRule(pattern1196, replacement1196) pattern1197 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons4, cons48, cons282, cons397, cons398) rule1197 = ReplacementRule(pattern1197, replacement1197) pattern1198 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons48, cons228, cons281) rule1198 = ReplacementRule(pattern1198, replacement1198) pattern1199 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons4, cons52, cons48, cons282) rule1199 = ReplacementRule(pattern1199, replacement1199) pattern1200 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons48, cons707, cons676, cons708) rule1200 = ReplacementRule(pattern1200, With1200) pattern1201 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons48, cons707, cons676, cons709) rule1201 = ReplacementRule(pattern1201, With1201) pattern1202 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons710, cons699) rule1202 = ReplacementRule(pattern1202, With1202) pattern1203 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons48, cons282, cons710, cons676, cons699) rule1203 = ReplacementRule(pattern1203, With1203) pattern1204 = Pattern(Integral((d_ + x_**S(3)*WC('e', S(1)))/(a_ + x_**S(6)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons680) rule1204 = ReplacementRule(pattern1204, With1204) pattern1205 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons282, cons711, cons87) rule1205 = ReplacementRule(pattern1205, With1205) pattern1206 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons282, cons712) rule1206 = ReplacementRule(pattern1206, replacement1206) pattern1207 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons228, cons707, cons676, cons713) rule1207 = ReplacementRule(pattern1207, With1207) pattern1208 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons707, cons676, cons677) rule1208 = ReplacementRule(pattern1208, With1208) pattern1209 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons228, cons707, cons676, cons714) rule1209 = ReplacementRule(pattern1209, With1209) pattern1210 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons281, cons715) rule1210 = ReplacementRule(pattern1210, With1210) pattern1211 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons228, cons281, cons676, cons415) rule1211 = ReplacementRule(pattern1211, With1211) pattern1212 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons281, cons588) rule1212 = ReplacementRule(pattern1212, replacement1212) pattern1213 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons282, cons588) rule1213 = ReplacementRule(pattern1213, replacement1213) pattern1214 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons281, cons388, cons397, cons398) rule1214 = ReplacementRule(pattern1214, replacement1214) pattern1215 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons282, cons388, cons397, cons398) rule1215 = ReplacementRule(pattern1215, replacement1215) pattern1216 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons48, cons228, cons281, cons388) rule1216 = ReplacementRule(pattern1216, With1216) pattern1217 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons52, cons48, cons282, cons388) rule1217 = ReplacementRule(pattern1217, With1217) pattern1218 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons151, cons165, cons671, cons716, cons248, cons675) rule1218 = ReplacementRule(pattern1218, replacement1218) pattern1219 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons151, cons165, cons671, cons716, cons248, cons675) rule1219 = ReplacementRule(pattern1219, replacement1219) pattern1220 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228, cons13, cons139, cons248, cons675) rule1220 = ReplacementRule(pattern1220, replacement1220) pattern1221 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons48, cons13, cons139, cons248, cons675) rule1221 = ReplacementRule(pattern1221, replacement1221) pattern1222 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, cons295) rule1222 = ReplacementRule(pattern1222, With1222) pattern1223 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons45, cons295) rule1223 = ReplacementRule(pattern1223, With1223) pattern1224 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, cons678, cons679, CustomConstraint(With1224)) rule1224 = ReplacementRule(pattern1224, replacement1224) pattern1225 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, cons678, cons679, CustomConstraint(With1225)) rule1225 = ReplacementRule(pattern1225, replacement1225) pattern1226 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, cons486, cons179, CustomConstraint(With1226)) rule1226 = ReplacementRule(pattern1226, replacement1226) pattern1227 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons486, cons179, CustomConstraint(With1227)) rule1227 = ReplacementRule(pattern1227, replacement1227) pattern1228 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons486, cons179, CustomConstraint(With1228)) rule1228 = ReplacementRule(pattern1228, replacement1228) pattern1229 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, cons486, cons179, CustomConstraint(With1229)) rule1229 = ReplacementRule(pattern1229, replacement1229) pattern1230 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons486, cons179, CustomConstraint(With1230)) rule1230 = ReplacementRule(pattern1230, replacement1230) pattern1231 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, CustomConstraint(With1231)) rule1231 = ReplacementRule(pattern1231, replacement1231) pattern1232 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons717) rule1232 = ReplacementRule(pattern1232, replacement1232) pattern1233 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, CustomConstraint(With1233)) rule1233 = ReplacementRule(pattern1233, replacement1233) pattern1234 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, CustomConstraint(With1234)) rule1234 = ReplacementRule(pattern1234, replacement1234) pattern1235 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, CustomConstraint(With1235)) rule1235 = ReplacementRule(pattern1235, replacement1235) pattern1236 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons677, CustomConstraint(With1236)) rule1236 = ReplacementRule(pattern1236, replacement1236) pattern1237 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons680, CustomConstraint(With1237)) rule1237 = ReplacementRule(pattern1237, replacement1237) pattern1238 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons680, CustomConstraint(With1238)) rule1238 = ReplacementRule(pattern1238, replacement1238) pattern1239 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons680, CustomConstraint(With1239)) rule1239 = ReplacementRule(pattern1239, replacement1239) pattern1240 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons680, CustomConstraint(With1240)) rule1240 = ReplacementRule(pattern1240, replacement1240) pattern1241 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons681, cons259, cons45) rule1241 = ReplacementRule(pattern1241, replacement1241) pattern1242 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons681, cons259, cons450) rule1242 = ReplacementRule(pattern1242, replacement1242) pattern1243 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons681, cons282) rule1243 = ReplacementRule(pattern1243, With1243) pattern1244 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))/sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons681) rule1244 = ReplacementRule(pattern1244, With1244) pattern1245 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons48, cons228) rule1245 = ReplacementRule(pattern1245, replacement1245) pattern1246 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons4, cons48) rule1246 = ReplacementRule(pattern1246, replacement1246) pattern1247 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons48, cons228, cons130, cons718, cons150, cons402) rule1247 = ReplacementRule(pattern1247, replacement1247) pattern1248 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons4, cons52, cons48, cons130, cons718, cons150, cons402) rule1248 = ReplacementRule(pattern1248, replacement1248) pattern1249 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281) rule1249 = ReplacementRule(pattern1249, replacement1249) pattern1250 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('c', S(1)))/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons282) rule1250 = ReplacementRule(pattern1250, replacement1250) pattern1251 = Pattern(Integral((a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**(S(3)/2)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons677) rule1251 = ReplacementRule(pattern1251, With1251) pattern1252 = Pattern(Integral((a_ + x_**S(4)*WC('c', S(1)))**(S(3)/2)/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons717) rule1252 = ReplacementRule(pattern1252, With1252) pattern1253 = Pattern(Integral((a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**p_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons719) rule1253 = ReplacementRule(pattern1253, replacement1253) pattern1254 = Pattern(Integral((a_ + x_**S(4)*WC('c', S(1)))**p_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons719) rule1254 = ReplacementRule(pattern1254, replacement1254) pattern1255 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons677, cons295) rule1255 = ReplacementRule(pattern1255, With1255) pattern1256 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons45, cons295) rule1256 = ReplacementRule(pattern1256, With1256) pattern1257 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons677, cons720) rule1257 = ReplacementRule(pattern1257, With1257) pattern1258 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons717, cons720) rule1258 = ReplacementRule(pattern1258, With1258) pattern1259 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons680, CustomConstraint(With1259)) rule1259 = ReplacementRule(pattern1259, replacement1259) pattern1260 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons282, cons680, CustomConstraint(With1260)) rule1260 = ReplacementRule(pattern1260, replacement1260) pattern1261 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons681, cons45) rule1261 = ReplacementRule(pattern1261, With1261) pattern1262 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons681, cons450) rule1262 = ReplacementRule(pattern1262, replacement1262) pattern1263 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons681) rule1263 = ReplacementRule(pattern1263, With1263) pattern1264 = Pattern(Integral((a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**p_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281, cons721) rule1264 = ReplacementRule(pattern1264, replacement1264) pattern1265 = Pattern(Integral((a_ + x_**S(4)*WC('c', S(1)))**p_/(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons282, cons721) rule1265 = ReplacementRule(pattern1265, replacement1265) pattern1266 = Pattern(Integral(S(1)/((d_ + x_**S(2)*WC('e', S(1)))**S(2)*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons228, cons281) rule1266 = ReplacementRule(pattern1266, replacement1266) pattern1267 = Pattern(Integral(S(1)/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))**S(2)), x_), cons2, cons8, cons29, cons50, cons282) rule1267 = ReplacementRule(pattern1267, replacement1267) pattern1268 = Pattern(Integral((d_ + x_**S(2)*WC('e', S(1)))**q_*(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons52, cons228, cons281, cons349, cons566) rule1268 = ReplacementRule(pattern1268, With1268) pattern1269 = Pattern(Integral((a_ + x_**S(4)*WC('c', S(1)))**p_*(d_ + x_**S(2)*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons52, cons282, cons349, cons566) rule1269 = ReplacementRule(pattern1269, With1269) pattern1270 = Pattern(Integral(S(1)/(sqrt(d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons722, cons45, cons270) rule1270 = ReplacementRule(pattern1270, replacement1270) pattern1271 = Pattern(Integral(S(1)/(sqrt(d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons722, cons723) rule1271 = ReplacementRule(pattern1271, replacement1271) pattern1272 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons722, cons45, cons270) rule1272 = ReplacementRule(pattern1272, replacement1272) pattern1273 = Pattern(Integral(sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))/sqrt(d_ + x_**S(2)*WC('e', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons722, cons723) rule1273 = ReplacementRule(pattern1273, replacement1273) pattern1274 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons228, cons281, cons724) rule1274 = ReplacementRule(pattern1274, replacement1274) pattern1275 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons282, cons724) rule1275 = ReplacementRule(pattern1275, replacement1275) pattern1276 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons4, cons5, cons48, cons282, cons566, cons725) rule1276 = ReplacementRule(pattern1276, replacement1276) pattern1277 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons726) rule1277 = ReplacementRule(pattern1277, replacement1277) pattern1278 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons726) rule1278 = ReplacementRule(pattern1278, replacement1278) pattern1279 = Pattern(Integral((d_ + u_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + u_**n2_*WC('c', S(1)) + u_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons70, cons71) rule1279 = ReplacementRule(pattern1279, replacement1279) pattern1280 = Pattern(Integral((a_ + u_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + u_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons4, cons5, cons52, cons48, cons70, cons71) rule1280 = ReplacementRule(pattern1280, replacement1280) pattern1281 = Pattern(Integral((d_ + x_**WC('mn', S(1))*WC('e', S(1)))**WC('q', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons682, cons587, cons588) rule1281 = ReplacementRule(pattern1281, replacement1281) pattern1282 = Pattern(Integral((a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons728, cons5, cons727, cons588) rule1282 = ReplacementRule(pattern1282, replacement1282) pattern1283 = Pattern(Integral((d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons682, cons587, cons388, cons40) rule1283 = ReplacementRule(pattern1283, replacement1283) pattern1284 = Pattern(Integral((a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons728, cons52, cons727, cons388, cons40) rule1284 = ReplacementRule(pattern1284, replacement1284) pattern1285 = Pattern(Integral((d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons682, cons587, cons388, cons149, cons683) rule1285 = ReplacementRule(pattern1285, replacement1285) pattern1286 = Pattern(Integral((a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons728, cons5, cons52, cons727, cons388, cons149, cons729) rule1286 = ReplacementRule(pattern1286, replacement1286) pattern1287 = Pattern(Integral((d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons682, cons587, cons388, cons149, cons504) rule1287 = ReplacementRule(pattern1287, replacement1287) pattern1288 = Pattern(Integral((a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons728, cons52, cons727, cons388, cons149, cons730) rule1288 = ReplacementRule(pattern1288, replacement1288) pattern1289 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons52, cons587, cons40) rule1289 = ReplacementRule(pattern1289, replacement1289) pattern1290 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons4, cons5, cons52, cons587, cons149) rule1290 = ReplacementRule(pattern1290, replacement1290) pattern1291 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(f_ + x_**n_*WC('g', S(1)))**WC('r', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons52, cons54, cons48, cons47, cons149) rule1291 = ReplacementRule(pattern1291, replacement1291) pattern1292 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(f_ + x_**n_*WC('g', S(1)))**WC('r', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons52, cons54, cons48, cons228, cons258, cons40) rule1292 = ReplacementRule(pattern1292, replacement1292) pattern1293 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(f_ + x_**n_*WC('g', S(1)))**WC('r', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons52, cons54, cons48, cons259, cons40) rule1293 = ReplacementRule(pattern1293, replacement1293) pattern1294 = Pattern(Integral((d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(f_ + x_**n_*WC('g', S(1)))**WC('r', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons52, cons54, cons48, cons228, cons258, cons149) rule1294 = ReplacementRule(pattern1294, replacement1294) pattern1295 = Pattern(Integral((a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(f_ + x_**n_*WC('g', S(1)))**WC('r', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons4, cons5, cons52, cons54, cons48, cons259, cons149) rule1295 = ReplacementRule(pattern1295, replacement1295) pattern1296 = Pattern(Integral((x_**S(2)*WC('g', S(1)) + WC('f', S(0)))/((d_ + x_**S(2)*WC('e', S(1)))*sqrt(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1)))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons210, cons677, cons281, cons720, CustomConstraint(With1296)) rule1296 = ReplacementRule(pattern1296, replacement1296) pattern1297 = Pattern(Integral((f_ + x_**S(2)*WC('g', S(1)))/(sqrt(a_ + x_**S(4)*WC('c', S(1)))*(d_ + x_**S(2)*WC('e', S(1)))), x_), cons2, cons8, cons29, cons50, cons127, cons210, cons717, cons282, cons720, CustomConstraint(With1297)) rule1297 = ReplacementRule(pattern1297, replacement1297) pattern1298 = Pattern(Integral((d1_ + x_**WC('non2', S(1))*WC('e1', S(1)))**WC('q', S(1))*(d2_ + x_**WC('non2', S(1))*WC('e2', S(1)))**WC('q', S(1))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons5, cons52, cons48, cons595, cons731, cons732) rule1298 = ReplacementRule(pattern1298, replacement1298) pattern1299 = Pattern(Integral((d1_ + x_**WC('non2', S(1))*WC('e1', S(1)))**WC('q', S(1))*(d2_ + x_**WC('non2', S(1))*WC('e2', S(1)))**WC('q', S(1))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons4, cons5, cons52, cons48, cons595, cons731) rule1299 = ReplacementRule(pattern1299, replacement1299) pattern1300 = Pattern(Integral((A_ + x_**WC('m', S(1))*WC('B', S(1)))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons36, cons37, cons19, cons4, cons5, cons52, cons48, cons55) rule1300 = ReplacementRule(pattern1300, replacement1300) pattern1301 = Pattern(Integral((A_ + x_**WC('m', S(1))*WC('B', S(1)))*(a_ + x_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons36, cons37, cons19, cons4, cons5, cons52, cons48, cons55) rule1301 = ReplacementRule(pattern1301, replacement1301) pattern1302 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)))**q_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons735, cons502) rule1302 = ReplacementRule(pattern1302, replacement1302) pattern1303 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)))**q_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons735, cons502) rule1303 = ReplacementRule(pattern1303, replacement1303) pattern1304 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)))**q_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons735, cons503) rule1304 = ReplacementRule(pattern1304, replacement1304) pattern1305 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)))**q_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons735, cons503) rule1305 = ReplacementRule(pattern1305, replacement1305) pattern1306 = Pattern(Integral((f_*x_)**WC('m', S(1))*(x_**n_*WC('e', S(1)))**q_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons21) rule1306 = ReplacementRule(pattern1306, replacement1306) pattern1307 = Pattern(Integral((f_*x_)**WC('m', S(1))*(x_**n_*WC('e', S(1)))**q_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons21) rule1307 = ReplacementRule(pattern1307, replacement1307) pattern1308 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons48, cons55) rule1308 = ReplacementRule(pattern1308, replacement1308) pattern1309 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons48, cons55) rule1309 = ReplacementRule(pattern1309, replacement1309) pattern1310 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons48, cons222, cons504) rule1310 = ReplacementRule(pattern1310, replacement1310) pattern1311 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons4, cons48, cons222, cons504) rule1311 = ReplacementRule(pattern1311, replacement1311) pattern1312 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons48, cons47, cons149, cons736) rule1312 = ReplacementRule(pattern1312, replacement1312) pattern1313 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons47, cons149) rule1313 = ReplacementRule(pattern1313, replacement1313) pattern1314 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons48, cons502) rule1314 = ReplacementRule(pattern1314, replacement1314) pattern1315 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons48, cons502) rule1315 = ReplacementRule(pattern1315, replacement1315) pattern1316 = Pattern(Integral((f_*x_)**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons502) rule1316 = ReplacementRule(pattern1316, replacement1316) pattern1317 = Pattern(Integral((f_*x_)**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons502) rule1317 = ReplacementRule(pattern1317, replacement1317) pattern1318 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons52, cons48, cons228, cons258, cons40) rule1318 = ReplacementRule(pattern1318, replacement1318) pattern1319 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons52, cons19, cons4, cons52, cons48, cons259, cons40) rule1319 = ReplacementRule(pattern1319, replacement1319) pattern1320 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons228, cons258, cons149) rule1320 = ReplacementRule(pattern1320, replacement1320) pattern1321 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons259, cons149) rule1321 = ReplacementRule(pattern1321, replacement1321) pattern1322 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons228, cons466, cons737, cons398, cons170) rule1322 = ReplacementRule(pattern1322, replacement1322) pattern1323 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons48, cons466, cons737, cons398, cons170) rule1323 = ReplacementRule(pattern1323, replacement1323) pattern1324 = Pattern(Integral(x_**m_*(d_ + x_**n_*WC('e', S(1)))**q_*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons48, cons228, cons466, cons737, cons398, cons269) rule1324 = ReplacementRule(pattern1324, replacement1324) pattern1325 = Pattern(Integral(x_**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons48, cons466, cons737, cons398, cons269) rule1325 = ReplacementRule(pattern1325, replacement1325) pattern1326 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons52, cons48, cons228, cons466, cons738, cons388, cons739) rule1326 = ReplacementRule(pattern1326, replacement1326) pattern1327 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons52, cons48, cons466, cons738, cons388, cons739) rule1327 = ReplacementRule(pattern1327, replacement1327) pattern1328 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons52, cons48, cons466) rule1328 = ReplacementRule(pattern1328, replacement1328) pattern1329 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons52, cons48, cons48, cons466) rule1329 = ReplacementRule(pattern1329, replacement1329) pattern1330 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons48, cons228, cons150, cons20, CustomConstraint(With1330)) rule1330 = ReplacementRule(pattern1330, replacement1330) pattern1331 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons5, cons52, cons48, cons150, cons20, CustomConstraint(With1331)) rule1331 = ReplacementRule(pattern1331, replacement1331) pattern1332 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons48, cons228, cons150, cons369, cons40) rule1332 = ReplacementRule(pattern1332, With1332) pattern1333 = Pattern(Integral((x_*WC('f', S(1)))**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons5, cons52, cons48, cons150, cons369, cons40) rule1333 = ReplacementRule(pattern1333, With1333) pattern1334 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons246, cons165, cons96, cons740, cons696) rule1334 = ReplacementRule(pattern1334, replacement1334) pattern1335 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons246, cons165, cons96, cons740, cons696) rule1335 = ReplacementRule(pattern1335, replacement1335) pattern1336 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons48, cons228, cons150, cons13, cons165, cons512, cons741, cons696) rule1336 = ReplacementRule(pattern1336, replacement1336) pattern1337 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons48, cons150, cons13, cons165, cons512, cons741, cons696) rule1337 = ReplacementRule(pattern1337, replacement1337) pattern1338 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons246, cons139, cons532, cons696) rule1338 = ReplacementRule(pattern1338, replacement1338) pattern1339 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons246, cons139, cons532, cons696) rule1339 = ReplacementRule(pattern1339, replacement1339) pattern1340 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons48, cons228, cons150, cons13, cons139, cons696) rule1340 = ReplacementRule(pattern1340, replacement1340) pattern1341 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons48, cons150, cons13, cons139, cons696) rule1341 = ReplacementRule(pattern1341, replacement1341) pattern1342 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons48, cons228, cons150, cons33, cons532, cons741, cons696) rule1342 = ReplacementRule(pattern1342, replacement1342) pattern1343 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons5, cons48, cons150, cons33, cons532, cons741, cons696) rule1343 = ReplacementRule(pattern1343, replacement1343) pattern1344 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons48, cons228, cons150, cons33, cons96, cons696) rule1344 = ReplacementRule(pattern1344, replacement1344) pattern1345 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons5, cons48, cons150, cons33, cons96, cons696) rule1345 = ReplacementRule(pattern1345, replacement1345) pattern1346 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons698, cons742, cons83, cons699, CustomConstraint(With1346)) rule1346 = ReplacementRule(pattern1346, replacement1346) pattern1347 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons436, cons742, cons83, CustomConstraint(With1347)) rule1347 = ReplacementRule(pattern1347, replacement1347) pattern1348 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))/(a_ + x_**S(4)*WC('c', S(1)) + x_**S(2)*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons228, cons707, cons743, cons744) rule1348 = ReplacementRule(pattern1348, With1348) pattern1349 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**S(2)*WC('e', S(1)))/(a_ + x_**S(4)*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons707, cons743) rule1349 = ReplacementRule(pattern1349, With1349) pattern1350 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons48, cons698, cons745, cons746, cons699, CustomConstraint(With1350)) rule1350 = ReplacementRule(pattern1350, replacement1350) pattern1351 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons48, cons745, cons746, cons436, CustomConstraint(With1351)) rule1351 = ReplacementRule(pattern1351, replacement1351) pattern1352 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons48, cons228, cons150) rule1352 = ReplacementRule(pattern1352, With1352) pattern1353 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons48, cons150) rule1353 = ReplacementRule(pattern1353, With1353) pattern1354 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons48, cons228, cons150, cons588, cons20) rule1354 = ReplacementRule(pattern1354, replacement1354) pattern1355 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons48, cons150, cons588, cons20) rule1355 = ReplacementRule(pattern1355, replacement1355) pattern1356 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons48, cons228, cons150, cons588, cons21) rule1356 = ReplacementRule(pattern1356, replacement1356) pattern1357 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons48, cons150, cons588, cons21) rule1357 = ReplacementRule(pattern1357, replacement1357) pattern1358 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons388, cons613, cons405, cons531) rule1358 = ReplacementRule(pattern1358, replacement1358) pattern1359 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons52, cons48, cons150, cons388, cons33, cons531) rule1359 = ReplacementRule(pattern1359, replacement1359) pattern1360 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons388, cons613, cons405, cons692) rule1360 = ReplacementRule(pattern1360, replacement1360) pattern1361 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons388, cons613, cons405, cons692) rule1361 = ReplacementRule(pattern1361, replacement1361) pattern1362 = Pattern(Integral((x_*WC('f', S(1)))**m_*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons388, cons613, cons405, cons269) rule1362 = ReplacementRule(pattern1362, replacement1362) pattern1363 = Pattern(Integral((x_*WC('f', S(1)))**m_*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons388, cons613, cons405, cons269) rule1363 = ReplacementRule(pattern1363, replacement1363) pattern1364 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons388, cons613, cons398, cons531) rule1364 = ReplacementRule(pattern1364, replacement1364) pattern1365 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons388, cons613, cons398, cons531) rule1365 = ReplacementRule(pattern1365, replacement1365) pattern1366 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons388, cons613, cons398, cons692) rule1366 = ReplacementRule(pattern1366, replacement1366) pattern1367 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('e', S(1)) + WC('d', S(0)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons388, cons613, cons398, cons692) rule1367 = ReplacementRule(pattern1367, replacement1367) pattern1368 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons48, cons228, cons150, cons388, cons397, cons398) rule1368 = ReplacementRule(pattern1368, replacement1368) pattern1369 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n2_*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons48, cons150, cons388, cons397, cons398) rule1369 = ReplacementRule(pattern1369, replacement1369) pattern1370 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons52, cons4, cons48, cons228, cons150, cons388, cons20) rule1370 = ReplacementRule(pattern1370, replacement1370) pattern1371 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons52, cons4, cons48, cons150, cons388, cons20) rule1371 = ReplacementRule(pattern1371, replacement1371) pattern1372 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons52, cons4, cons48, cons228, cons150, cons388, cons21) rule1372 = ReplacementRule(pattern1372, replacement1372) pattern1373 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons52, cons4, cons48, cons150, cons388, cons21) rule1373 = ReplacementRule(pattern1373, replacement1373) pattern1374 = Pattern(Integral((x_*WC('f', S(1)))**m_*(x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons246, cons165, cons747) rule1374 = ReplacementRule(pattern1374, replacement1374) pattern1375 = Pattern(Integral((x_*WC('f', S(1)))**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons246, cons165, cons747) rule1375 = ReplacementRule(pattern1375, replacement1375) pattern1376 = Pattern(Integral((x_*WC('f', S(1)))**m_*(x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1))/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons246, cons165, cons269) rule1376 = ReplacementRule(pattern1376, replacement1376) pattern1377 = Pattern(Integral((x_*WC('f', S(1)))**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons246, cons165, cons269) rule1377 = ReplacementRule(pattern1377, replacement1377) pattern1378 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons246, cons139, cons748) rule1378 = ReplacementRule(pattern1378, replacement1378) pattern1379 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons246, cons139, cons748) rule1379 = ReplacementRule(pattern1379, replacement1379) pattern1380 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons48, cons228, cons150, cons246, cons139, cons170) rule1380 = ReplacementRule(pattern1380, replacement1380) pattern1381 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_/(x_**n_*WC('e', S(1)) + WC('d', S(0))), x_), cons2, cons8, cons29, cons50, cons127, cons48, cons150, cons246, cons139, cons170) rule1381 = ReplacementRule(pattern1381, replacement1381) pattern1382 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons52, cons48, cons228, cons150, cons749) rule1382 = ReplacementRule(pattern1382, replacement1382) pattern1383 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons52, cons48, cons150, cons749) rule1383 = ReplacementRule(pattern1383, replacement1383) pattern1384 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons5, cons52, cons48, cons228, cons198, cons20) rule1384 = ReplacementRule(pattern1384, replacement1384) pattern1385 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons5, cons52, cons48, cons198, cons20) rule1385 = ReplacementRule(pattern1385, replacement1385) pattern1386 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons5, cons52, cons48, cons228, cons198, cons369) rule1386 = ReplacementRule(pattern1386, With1386) pattern1387 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons5, cons52, cons48, cons198, cons369) rule1387 = ReplacementRule(pattern1387, With1387) pattern1388 = Pattern(Integral((x_*WC('f', S(1)))**m_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons52, cons48, cons228, cons198, cons358) rule1388 = ReplacementRule(pattern1388, replacement1388) pattern1389 = Pattern(Integral((x_*WC('f', S(1)))**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons5, cons52, cons48, cons198, cons358) rule1389 = ReplacementRule(pattern1389, replacement1389) pattern1390 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons5, cons52, cons48, cons228, cons491) rule1390 = ReplacementRule(pattern1390, With1390) pattern1391 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons5, cons52, cons48, cons491) rule1391 = ReplacementRule(pattern1391, With1391) pattern1392 = Pattern(Integral((f_*x_)**m_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons52, cons48, cons228, cons491) rule1392 = ReplacementRule(pattern1392, replacement1392) pattern1393 = Pattern(Integral((f_*x_)**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons5, cons52, cons48, cons491) rule1393 = ReplacementRule(pattern1393, replacement1393) pattern1394 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons48, cons228, cons543, cons25) rule1394 = ReplacementRule(pattern1394, replacement1394) pattern1395 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons48, cons543, cons25) rule1395 = ReplacementRule(pattern1395, replacement1395) pattern1396 = Pattern(Integral((f_*x_)**m_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons5, cons52, cons48, cons228, cons543, cons25) rule1396 = ReplacementRule(pattern1396, replacement1396) pattern1397 = Pattern(Integral((f_*x_)**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons5, cons52, cons48, cons543, cons25) rule1397 = ReplacementRule(pattern1397, replacement1397) pattern1398 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons52, cons48, cons228) rule1398 = ReplacementRule(pattern1398, With1398) pattern1399 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**q_/(a_ + x_**WC('n2', S(1))*WC('c', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons52, cons48) rule1399 = ReplacementRule(pattern1399, With1399) pattern1400 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))*(a_ + x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons48, cons228, cons704) rule1400 = ReplacementRule(pattern1400, replacement1400) pattern1401 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1))), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons48, cons704) rule1401 = ReplacementRule(pattern1401, replacement1401) pattern1402 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons228, cons750) rule1402 = ReplacementRule(pattern1402, replacement1402) pattern1403 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons750) rule1403 = ReplacementRule(pattern1403, replacement1403) pattern1404 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons566, cons735) rule1404 = ReplacementRule(pattern1404, replacement1404) pattern1405 = Pattern(Integral((x_*WC('f', S(1)))**m_*(a_ + x_**n2_*WC('c', S(1)))**p_*(d_ + x_**n_*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48, cons566, cons751) rule1405 = ReplacementRule(pattern1405, replacement1405) pattern1406 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**n_*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48) rule1406 = ReplacementRule(pattern1406, replacement1406) pattern1407 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons48) rule1407 = ReplacementRule(pattern1407, replacement1407) pattern1408 = Pattern(Integral(u_**WC('m', S(1))*(d_ + v_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + v_**n_*WC('b', S(1)) + v_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons48, cons556) rule1408 = ReplacementRule(pattern1408, replacement1408) pattern1409 = Pattern(Integral(u_**WC('m', S(1))*(a_ + v_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + v_**n_*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons4, cons5, cons48, cons556) rule1409 = ReplacementRule(pattern1409, replacement1409) pattern1410 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**WC('q', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons682, cons587, cons588) rule1410 = ReplacementRule(pattern1410, replacement1410) pattern1411 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons19, cons728, cons5, cons727, cons588) rule1411 = ReplacementRule(pattern1411, replacement1411) pattern1412 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons52, cons682, cons587, cons388, cons40) rule1412 = ReplacementRule(pattern1412, replacement1412) pattern1413 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**WC('p', S(1))*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons19, cons728, cons52, cons727, cons388, cons40) rule1413 = ReplacementRule(pattern1413, replacement1413) pattern1414 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons682, cons587, cons388, cons149) rule1414 = ReplacementRule(pattern1414, replacement1414) pattern1415 = Pattern(Integral(x_**WC('m', S(1))*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**q_, x_), cons2, cons8, cons29, cons50, cons19, cons728, cons5, cons52, cons727, cons388, cons149) rule1415 = ReplacementRule(pattern1415, replacement1415) pattern1416 = Pattern(Integral((f_*x_)**m_*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**WC('q', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('n2', S(1))*WC('c', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons682, cons587) rule1416 = ReplacementRule(pattern1416, replacement1416) pattern1417 = Pattern(Integral((f_*x_)**m_*(a_ + x_**WC('n2', S(1))*WC('c', S(1)))**p_*(d_ + x_**WC('mn', S(1))*WC('e', S(1)))**WC('q', S(1)), x_), cons2, cons8, cons29, cons50, cons127, cons19, cons728, cons5, cons52, cons727) rule1417 = ReplacementRule(pattern1417, replacement1417) pattern1418 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons52, cons587, cons40) rule1418 = ReplacementRule(pattern1418, replacement1418) pattern1419 = Pattern(Integral(x_**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons19, cons4, cons5, cons52, cons587, cons149) rule1419 = ReplacementRule(pattern1419, replacement1419) pattern1420 = Pattern(Integral((f_*x_)**WC('m', S(1))*(d_ + x_**n_*WC('e', S(1)))**WC('q', S(1))*(a_ + x_**mn_*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons29, cons50, cons127, cons19, cons4, cons5, cons52, cons587) rule1420 = ReplacementRule(pattern1420, replacement1420) pattern1421 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d1_ + x_**WC('non2', S(1))*WC('e1', S(1)))**WC('q', S(1))*(d2_ + x_**WC('non2', S(1))*WC('e2', S(1)))**WC('q', S(1))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons4, cons5, cons52, cons48, cons595, cons731, cons732) rule1421 = ReplacementRule(pattern1421, replacement1421) pattern1422 = Pattern(Integral((x_*WC('f', S(1)))**WC('m', S(1))*(d1_ + x_**WC('non2', S(1))*WC('e1', S(1)))**WC('q', S(1))*(d2_ + x_**WC('non2', S(1))*WC('e2', S(1)))**WC('q', S(1))*(x_**n2_*WC('c', S(1)) + x_**n_*WC('b', S(1)) + WC('a', S(0)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons733, cons654, cons734, cons656, cons127, cons4, cons5, cons52, cons48, cons595, cons731) rule1422 = ReplacementRule(pattern1422, replacement1422) pattern1423 = Pattern(Integral((x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons752, cons753) rule1423 = ReplacementRule(pattern1423, replacement1423) pattern1424 = Pattern(Integral((x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons52, cons754, cons755, cons40) rule1424 = ReplacementRule(pattern1424, replacement1424) pattern1425 = Pattern(Integral(sqrt(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons4, cons52, cons754, cons755) rule1425 = ReplacementRule(pattern1425, replacement1425) pattern1426 = Pattern(Integral(S(1)/sqrt(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons4, cons52, cons754, cons755) rule1426 = ReplacementRule(pattern1426, replacement1426) pattern1427 = Pattern(Integral((x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons52, cons754, cons755, cons149, cons228, cons13, cons165, cons756) rule1427 = ReplacementRule(pattern1427, replacement1427) pattern1428 = Pattern(Integral((x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons52, cons754, cons755, cons149, cons228, cons13, cons139) rule1428 = ReplacementRule(pattern1428, replacement1428) pattern1429 = Pattern(Integral((x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons52, cons754, cons755, cons149) rule1429 = ReplacementRule(pattern1429, replacement1429) pattern1430 = Pattern(Integral((x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons52, cons754) rule1430 = ReplacementRule(pattern1430, replacement1430) pattern1431 = Pattern(Integral((u_**WC('n', S(1))*WC('b', S(1)) + u_**WC('q', S(1))*WC('a', S(1)) + u_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons4, cons5, cons52, cons754, cons70, cons71) rule1431 = ReplacementRule(pattern1431, replacement1431) pattern1432 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons757, cons753) rule1432 = ReplacementRule(pattern1432, replacement1432) pattern1433 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons52, cons754, cons40, cons755) rule1433 = ReplacementRule(pattern1433, replacement1433) pattern1434 = Pattern(Integral(x_**WC('m', S(1))/sqrt(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons19, cons4, cons52, cons754, cons755, cons758) rule1434 = ReplacementRule(pattern1434, replacement1434) pattern1435 = Pattern(Integral(x_**WC('m', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons4, cons759, cons760, cons761, cons228) rule1435 = ReplacementRule(pattern1435, replacement1435) pattern1436 = Pattern(Integral(x_**WC('m', S(1))/(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**(S(3)/2), x_), cons2, cons3, cons8, cons4, cons762, cons760, cons761, cons228) rule1436 = ReplacementRule(pattern1436, replacement1436) pattern1437 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons763) rule1437 = ReplacementRule(pattern1437, replacement1437) pattern1438 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons165, cons764) rule1438 = ReplacementRule(pattern1438, replacement1438) pattern1439 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons165, cons765, cons766, cons767) rule1439 = ReplacementRule(pattern1439, replacement1439) pattern1440 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons165, cons768, cons769) rule1440 = ReplacementRule(pattern1440, replacement1440) pattern1441 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons165, cons770, cons766) rule1441 = ReplacementRule(pattern1441, replacement1441) pattern1442 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons139, cons771) rule1442 = ReplacementRule(pattern1442, replacement1442) pattern1443 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons139, cons772) rule1443 = ReplacementRule(pattern1443, replacement1443) pattern1444 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons139, cons773) rule1444 = ReplacementRule(pattern1444, replacement1444) pattern1445 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons139, cons774) rule1445 = ReplacementRule(pattern1445, replacement1445) pattern1446 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons775, cons776) rule1446 = ReplacementRule(pattern1446, replacement1446) pattern1447 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons775, cons777) rule1447 = ReplacementRule(pattern1447, replacement1447) pattern1448 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons775, cons772) rule1448 = ReplacementRule(pattern1448, replacement1448) pattern1449 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons754, cons755, cons149, cons228, cons150, cons608, cons775, cons778) rule1449 = ReplacementRule(pattern1449, replacement1449) pattern1450 = Pattern(Integral(x_**WC('m', S(1))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons19, cons4, cons5, cons52, cons754, cons149, cons755) rule1450 = ReplacementRule(pattern1450, replacement1450) pattern1451 = Pattern(Integral(u_**WC('m', S(1))*(u_**WC('n', S(1))*WC('b', S(1)) + u_**WC('q', S(1))*WC('a', S(1)) + u_**WC('r', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons19, cons4, cons5, cons52, cons754, cons70, cons71) rule1451 = ReplacementRule(pattern1451, replacement1451) pattern1452 = Pattern(Integral((A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons52, cons779, cons780, cons40, cons755) rule1452 = ReplacementRule(pattern1452, replacement1452) pattern1453 = Pattern(Integral((A_ + x_**WC('j', S(1))*WC('B', S(1)))/sqrt(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons52, cons781, cons754, cons755, cons782, cons783) rule1453 = ReplacementRule(pattern1453, replacement1453) pattern1454 = Pattern(Integral((A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons36, cons37, cons4, cons52, cons779, cons780, cons149, cons228, cons13, cons165, cons756, cons784) rule1454 = ReplacementRule(pattern1454, replacement1454) pattern1455 = Pattern(Integral((A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**p_, x_), cons2, cons8, cons36, cons37, cons52, cons149, cons13, cons165, CustomConstraint(With1455)) rule1455 = ReplacementRule(pattern1455, replacement1455) pattern1456 = Pattern(Integral((A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**p_, x_), cons2, cons3, cons8, cons36, cons37, cons4, cons52, cons779, cons780, cons149, cons228, cons13, cons139) rule1456 = ReplacementRule(pattern1456, replacement1456) pattern1457 = Pattern(Integral((A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**p_, x_), cons2, cons8, cons36, cons37, cons52, cons149, cons13, cons139, CustomConstraint(With1457)) rule1457 = ReplacementRule(pattern1457, replacement1457) pattern1458 = Pattern(Integral((A_ + x_**WC('j', S(1))*WC('B', S(1)))*(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons5, cons52, cons781, cons754) rule1458 = ReplacementRule(pattern1458, replacement1458) pattern1459 = Pattern(Integral((A_ + u_**WC('j', S(1))*WC('B', S(1)))*(u_**WC('n', S(1))*WC('b', S(1)) + u_**WC('q', S(1))*WC('a', S(1)) + u_**WC('r', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons4, cons5, cons52, cons781, cons754, cons70, cons71) rule1459 = ReplacementRule(pattern1459, replacement1459) pattern1460 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons19, cons4, cons52, cons779, cons780, cons40, cons755) rule1460 = ReplacementRule(pattern1460, replacement1460) pattern1461 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons779, cons780, cons149, cons228, cons150, cons608, cons165, cons785, cons786, cons787) rule1461 = ReplacementRule(pattern1461, replacement1461) pattern1462 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons36, cons37, cons149, cons608, cons165, CustomConstraint(With1462)) rule1462 = ReplacementRule(pattern1462, replacement1462) pattern1463 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons779, cons780, cons149, cons228, cons150, cons608, cons139, cons788) rule1463 = ReplacementRule(pattern1463, replacement1463) pattern1464 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons36, cons37, cons149, cons608, cons139, CustomConstraint(With1464)) rule1464 = ReplacementRule(pattern1464, replacement1464) pattern1465 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons779, cons780, cons149, cons228, cons150, cons608, cons165, cons789, cons766, cons787) rule1465 = ReplacementRule(pattern1465, replacement1465) pattern1466 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons36, cons37, cons149, cons608, cons165, CustomConstraint(With1466)) rule1466 = ReplacementRule(pattern1466, replacement1466) pattern1467 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons779, cons780, cons149, cons228, cons150, cons608, cons139, cons790) rule1467 = ReplacementRule(pattern1467, replacement1467) pattern1468 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons36, cons37, cons149, cons608, cons139, CustomConstraint(With1468)) rule1468 = ReplacementRule(pattern1468, replacement1468) pattern1469 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons779, cons780, cons149, cons228, cons150, cons608, cons775, cons791, cons787) rule1469 = ReplacementRule(pattern1469, replacement1469) pattern1470 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons36, cons37, cons149, cons608, cons775, CustomConstraint(With1470)) rule1470 = ReplacementRule(pattern1470, replacement1470) pattern1471 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons779, cons780, cons149, cons228, cons150, cons608, cons792, cons785, cons786) rule1471 = ReplacementRule(pattern1471, replacement1471) pattern1472 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('r', S(1))*WC('B', S(1)))*(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('q', S(1))*WC('a', S(1)))**WC('p', S(1)), x_), cons2, cons8, cons36, cons37, cons149, cons608, CustomConstraint(With1472)) rule1472 = ReplacementRule(pattern1472, replacement1472) pattern1473 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**WC('j', S(1))*WC('B', S(1)))/sqrt(x_**WC('n', S(1))*WC('b', S(1)) + x_**WC('q', S(1))*WC('a', S(1)) + x_**WC('r', S(1))*WC('c', S(1))), x_), cons2, cons3, cons8, cons36, cons37, cons19, cons4, cons52, cons781, cons754, cons755, cons793, cons782, cons794) rule1473 = ReplacementRule(pattern1473, replacement1473) pattern1474 = Pattern(Integral(x_**WC('m', S(1))*(A_ + x_**q_*WC('B', S(1)))*(x_**WC('j', S(1))*WC('a', S(1)) + x_**WC('k', S(1))*WC('b', S(1)) + x_**WC('n', S(1))*WC('c', S(1)))**p_, x_), cons2, cons3, cons8, cons36, cons37, cons798, cons799, cons19, cons5, cons795, cons796, cons149, cons797) rule1474 = ReplacementRule(pattern1474, replacement1474) pattern1475 = Pattern(Integral(u_**WC('m', S(1))*(A_ + u_**WC('j', S(1))*WC('B', S(1)))*(u_**WC('n', S(1))*WC('b', S(1)) + u_**WC('q', S(1))*WC('a', S(1)) + u_**WC('r', S(1))*WC('c', S(1)))**WC('p', S(1)), x_), cons2, cons3, cons8, cons36, cons37, cons19, cons4, cons5, cons52, cons781, cons754, cons70, cons71) rule1475 = ReplacementRule(pattern1475, replacement1475) return [rule1079, rule1080, rule1081, rule1082, rule1083, rule1084, rule1085, rule1086, rule1087, rule1088, rule1089, rule1090, rule1091, rule1092, rule1093, rule1094, rule1095, rule1096, rule1097, rule1098, rule1099, rule1100, rule1101, rule1102, rule1103, rule1104, rule1105, rule1106, rule1107, rule1108, rule1109, rule1110, rule1111, rule1112, rule1113, rule1114, rule1115, rule1116, rule1117, rule1118, rule1119, rule1120, rule1121, rule1122, rule1123, rule1124, rule1125, rule1126, rule1127, rule1128, rule1129, rule1130, rule1131, rule1132, rule1133, rule1134, rule1135, rule1136, rule1137, rule1138, rule1139, rule1140, rule1141, rule1142, rule1143, rule1144, rule1145, rule1146, rule1147, rule1148, rule1149, rule1150, rule1151, rule1152, rule1153, rule1154, rule1155, rule1156, rule1157, rule1158, rule1159, rule1160, rule1161, rule1162, rule1163, rule1164, rule1165, rule1166, rule1167, rule1168, rule1169, rule1170, rule1171, rule1172, rule1173, rule1174, rule1175, rule1176, rule1177, rule1178, rule1179, rule1180, rule1181, rule1182, rule1183, rule1184, rule1185, rule1186, rule1187, rule1188, rule1189, rule1190, rule1191, rule1192, rule1193, rule1194, rule1195, rule1196, rule1197, rule1198, rule1199, rule1200, rule1201, rule1202, rule1203, rule1204, rule1205, rule1206, rule1207, rule1208, rule1209, rule1210, rule1211, rule1212, rule1213, rule1214, rule1215, rule1216, rule1217, rule1218, rule1219, rule1220, rule1221, rule1222, rule1223, rule1224, rule1225, rule1226, rule1227, rule1228, rule1229, rule1230, rule1231, rule1232, rule1233, rule1234, rule1235, rule1236, rule1237, rule1238, rule1239, rule1240, rule1241, rule1242, rule1243, rule1244, rule1245, rule1246, rule1247, rule1248, rule1249, rule1250, rule1251, rule1252, rule1253, rule1254, rule1255, rule1256, rule1257, rule1258, rule1259, rule1260, rule1261, rule1262, rule1263, rule1264, rule1265, rule1266, rule1267, rule1268, rule1269, rule1270, rule1271, rule1272, rule1273, rule1274, rule1275, rule1276, rule1277, rule1278, rule1279, rule1280, rule1281, rule1282, rule1283, rule1284, rule1285, rule1286, rule1287, rule1288, rule1289, rule1290, rule1291, rule1292, rule1293, rule1294, rule1295, rule1296, rule1297, rule1298, rule1299, rule1300, rule1301, rule1302, rule1303, rule1304, rule1305, rule1306, rule1307, rule1308, rule1309, rule1310, rule1311, rule1312, rule1313, rule1314, rule1315, rule1316, rule1317, rule1318, rule1319, rule1320, rule1321, rule1322, rule1323, rule1324, rule1325, rule1326, rule1327, rule1328, rule1329, rule1330, rule1331, rule1332, rule1333, rule1334, rule1335, rule1336, rule1337, rule1338, rule1339, rule1340, rule1341, rule1342, rule1343, rule1344, rule1345, rule1346, rule1347, rule1348, rule1349, rule1350, rule1351, rule1352, rule1353, rule1354, rule1355, rule1356, rule1357, rule1358, rule1359, rule1360, rule1361, rule1362, rule1363, rule1364, rule1365, rule1366, rule1367, rule1368, rule1369, rule1370, rule1371, rule1372, rule1373, rule1374, rule1375, rule1376, rule1377, rule1378, rule1379, rule1380, rule1381, rule1382, rule1383, rule1384, rule1385, rule1386, rule1387, rule1388, rule1389, rule1390, rule1391, rule1392, rule1393, rule1394, rule1395, rule1396, rule1397, rule1398, rule1399, rule1400, rule1401, rule1402, rule1403, rule1404, rule1405, rule1406, rule1407, rule1408, rule1409, rule1410, rule1411, rule1412, rule1413, rule1414, rule1415, rule1416, rule1417, rule1418, rule1419, rule1420, rule1421, rule1422, rule1423, rule1424, rule1425, rule1426, rule1427, rule1428, rule1429, rule1430, rule1431, rule1432, rule1433, rule1434, rule1435, rule1436, rule1437, rule1438, rule1439, rule1440, rule1441, rule1442, rule1443, rule1444, rule1445, rule1446, rule1447, rule1448, rule1449, rule1450, rule1451, rule1452, rule1453, rule1454, rule1455, rule1456, rule1457, rule1458, rule1459, rule1460, rule1461, rule1462, rule1463, rule1464, rule1465, rule1466, rule1467, rule1468, rule1469, rule1470, rule1471, rule1472, rule1473, rule1474, rule1475, ] def replacement1079(a, b, c, n, n2, p, x): return Int(x**(S(2)*n*p)*(a*x**(-S(2)*n) + b*x**(-n) + c)**p, x) def With1080(a, b, c, n, n2, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k + S(-1))*(a + b*x**(k*n) + c*x**(S(2)*k*n))**p, x), x, x**(S(1)/k)), x) def replacement1081(a, b, c, n, n2, p, x): return Simp(x*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*a), x) def replacement1082(a, b, c, n, n2, p, x): return -Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(a*(S(2)*p + S(1))), x) + Simp(x*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*a*(n + S(1))), x) def replacement1083(a, b, c, n, n2, p, x): return Dist(sqrt(a + b*x**n + c*x**(S(2)*n))/(b + S(2)*c*x**n), Int((b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)/2), x), x) def replacement1084(a, b, c, n, n2, p, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((b + S(2)*c*x**n)**(S(2)*p), x), x) def replacement1085(a, b, c, n, n2, x): return Simp(x*sqrt(a + b*x**n + c*x**(S(2)*n))/(n + S(1)), x) + Simp(b*n*x*sqrt(a + b*x**n + c*x**(S(2)*n))/((b + S(2)*c*x**n)*(n + S(1))), x) def replacement1086(a, b, c, n, n2, p, x): return -Subst(Int((a + b*x**(-n) + c*x**(-S(2)*n))**p/x**S(2), x), x, S(1)/x) def replacement1087(a, b, c, n, n2, p, x): return Dist(S(2)*a*n**S(2)*p*(S(2)*p + S(-1))/((S(2)*n*p + S(1))*(n*(S(2)*p + S(-1)) + S(1))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Simp(x*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*n*p + S(1)), x) + Simp(n*p*x*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/((S(2)*n*p + S(1))*(n*(S(2)*p + S(-1)) + S(1))), x) def replacement1088(a, b, c, n, n2, p, x): return Dist((S(2)*n*(p + S(1)) + S(1))*(n*(S(2)*p + S(1)) + S(1))/(S(2)*a*n**S(2)*(p + S(1))*(S(2)*p + S(1))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1)), x), x) - Simp(x*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*a*n*(S(2)*p + S(1))), x) - Simp(x*(n*(S(2)*p + S(1)) + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(S(2)*a*n**S(2)*(p + S(1))*(S(2)*p + S(1))), x) def replacement1089(a, b, c, n, n2, p, x): return Dist(c**(-IntPart(p))*(b/S(2) + c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((b/S(2) + c*x**n)**(S(2)*p), x), x) def replacement1090(a, b, c, n, n2, p, x): return -Subst(Int((a + b*x**(-n) + c*x**(-S(2)*n))**p/x**S(2), x), x, S(1)/x) def replacement1091(a, b, c, n, n2, p, x): return Int(ExpandIntegrand((a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1092(a, b, c, n, n2, p, x): return Dist(n*p/(S(2)*n*p + S(1)), Int((S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Simp(x*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*n*p + S(1)), x) def replacement1093(a, b, c, n, n2, p, x): return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**n*(n*(S(2)*p + S(3)) + S(1)) + n*(p + S(1))*(-S(4)*a*c + b**S(2))), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def With1094(a, b, c, n, n2, x): q = Rt(a/c, S(2)) r = Rt(-b/c + S(2)*q, S(2)) return Dist(1/(2*c*q*r), Int((r - x**(n/2))/(q - r*x**(n/2) + x**n), x), x) + Dist(1/(2*c*q*r), Int((r + x**(n/2))/(q + r*x**(n/2) + x**n), x), x) def With1095(a, b, c, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(c/q, Int(S(1)/(b/S(2) + c*x**n - q/S(2)), x), x) - Dist(c/q, Int(S(1)/(b/S(2) + c*x**n + q/S(2)), x), x) def With1096(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*sqrt(-c), Int(S(1)/(sqrt(-b - S(2)*c*x**S(2) + q)*sqrt(b + S(2)*c*x**S(2) + q)), x), x) def With1097(a, b, c, x): q = Rt(c/a, S(4)) return Simp(sqrt((a + b*x**S(2) + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(q**S(2)*x**S(2) + S(1))*EllipticF(S(2)*ArcTan(q*x), -b*q**S(2)/(S(4)*c) + S(1)/2)/(S(2)*q*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1098(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if IntegerQ(q): return True return False def replacement1098(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(sqrt((S(2)*a + x**S(2)*(b + q))/q)*sqrt(-S(2)*a - x**S(2)*(b - q))*EllipticF(asin(sqrt(S(2))*x/sqrt((S(2)*a + x**S(2)*(b + q))/q)), (b + q)/(S(2)*q))/(S(2)*sqrt(-a)*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1099(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(sqrt((S(2)*a + x**S(2)*(b + q))/q)*sqrt((S(2)*a + x**S(2)*(b - q))/(S(2)*a + x**S(2)*(b + q)))*EllipticF(asin(sqrt(S(2))*x/sqrt((S(2)*a + x**S(2)*(b + q))/q)), (b + q)/(S(2)*q))/(S(2)*sqrt(a/(S(2)*a + x**S(2)*(b + q)))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1100(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(PosQ((b + q)/a), Not(And(PosQ((b - q)/a), SimplerSqrtQ((b - q)/(S(2)*a), (b + q)/(S(2)*a))))): return True return False def replacement1100(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(sqrt((S(2)*a + x**S(2)*(b - q))/(S(2)*a + x**S(2)*(b + q)))*(S(2)*a + x**S(2)*(b + q))*EllipticF(ArcTan(x*Rt((b + q)/(S(2)*a), S(2))), S(2)*q/(b + q))/(S(2)*a*sqrt(a + b*x**S(2) + c*x**S(4))*Rt((b + q)/(S(2)*a), S(2))), x) def With1101(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if PosQ((b - q)/a): return True return False def replacement1101(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(sqrt((S(2)*a + x**S(2)*(b + q))/(S(2)*a + x**S(2)*(b - q)))*(S(2)*a + x**S(2)*(b - q))*EllipticF(ArcTan(x*Rt((b - q)/(S(2)*a), S(2))), -S(2)*q/(b - q))/(S(2)*a*sqrt(a + b*x**S(2) + c*x**S(4))*Rt((b - q)/(S(2)*a), S(2))), x) def With1102(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(NegQ((b + q)/a), Not(And(NegQ((b - q)/a), SimplerSqrtQ(-(b - q)/(S(2)*a), -(b + q)/(S(2)*a))))): return True return False def replacement1102(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(sqrt(S(1) + x**S(2)*(b - q)/(S(2)*a))*sqrt(S(1) + x**S(2)*(b + q)/(S(2)*a))*EllipticF(asin(x*Rt(-(b + q)/(S(2)*a), S(2))), (b - q)/(b + q))/(sqrt(a + b*x**S(2) + c*x**S(4))*Rt(-(b + q)/(S(2)*a), S(2))), x) def With1103(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if NegQ((b - q)/a): return True return False def replacement1103(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(sqrt(S(1) + x**S(2)*(b - q)/(S(2)*a))*sqrt(S(1) + x**S(2)*(b + q)/(S(2)*a))*EllipticF(asin(x*Rt(-(b - q)/(S(2)*a), S(2))), (b + q)/(b - q))/(sqrt(a + b*x**S(2) + c*x**S(4))*Rt(-(b - q)/(S(2)*a), S(2))), x) def With1104(a, b, c, x): q = Rt(c/a, S(4)) return Simp(sqrt((a + b*x**S(2) + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(q**S(2)*x**S(2) + S(1))*EllipticF(S(2)*ArcTan(q*x), -b*q**S(2)/(S(4)*c) + S(1)/2)/(S(2)*q*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1105(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), Int(S(1)/(sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))), x), x) def replacement1106(a, b, c, n, n2, p, x): return Dist(a**IntPart(p)*(S(2)*c*x**n/(b - Rt(-S(4)*a*c + b**S(2), S(2))) + S(1))**(-FracPart(p))*(S(2)*c*x**n/(b + Rt(-S(4)*a*c + b**S(2), S(2))) + S(1))**(-FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**p*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**p, x), x) def replacement1107(a, b, c, mn, n, p, x): return Int(x**(-n*p)*(a*x**n + b + c*x**(S(2)*n))**p, x) def replacement1108(a, b, c, mn, n, p, x): return Dist(x**(n*FracPart(p))*(a + b*x**(-n) + c*x**n)**FracPart(p)*(a*x**n + b + c*x**(S(2)*n))**(-FracPart(p)), Int(x**(-n*p)*(a*x**n + b + c*x**(S(2)*n))**p, x), x) def replacement1109(a, b, c, n, n2, p, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + b*x**n + c*x**(S(2)*n))**p, x), x, u), x) def replacement1110(a, b, c, m, n, n2, p, x): return Dist(S(1)/n, Subst(Int((a + b*x + c*x**S(2))**p, x), x, x**n), x) def replacement1111(a, b, c, d, m, n, n2, p, x): return Int(ExpandIntegrand((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1112(a, b, c, m, n, n2, p, x): return Int(x**(m + S(2)*n*p)*(a*x**(-S(2)*n) + b*x**(-n) + c)**p, x) def replacement1113(a, b, c, n, n2, x): return Simp(sqrt(a + b*x**n + c*x**(S(2)*n))/n, x) + Simp(b*sqrt(a + b*x**n + c*x**(S(2)*n))*log(x)/(b + S(2)*c*x**n), x) def replacement1114(a, b, c, n, n2, p, x): return Dist(a, Int((a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/x, x), x) + Simp((a + b*x**n + c*x**(S(2)*n))**p/(S(2)*n*p), x) + Simp((S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/(S(2)*n*(S(2)*p + S(-1))), x) def replacement1115(a, b, c, n, n2, p, x): return Dist(S(1)/a, Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))/x, x), x) - Simp((a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(S(2)*a*n*(p + S(1))), x) - Simp((S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*a*n*(S(2)*p + S(1))), x) def replacement1116(a, b, c, n, n2, p, x): return Dist(c**(-IntPart(p))*(b/S(2) + c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((b/S(2) + c*x**n)**(S(2)*p)/x, x), x) def replacement1117(a, b, c, d, m, n, n2, p, x): return Simp((d*x)**(m + S(1))*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(b*d*(m + S(1))), x) def replacement1118(a, b, c, d, m, n, n2, x): return Dist(sqrt(a + b*x**n + c*x**(S(2)*n))/(b + S(2)*c*x**n), Int((d*x)**m*(b + S(2)*c*x**n), x), x) def replacement1119(a, b, c, d, m, n, n2, x): return Simp((d*x)**(m + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))/(d*(m + n + S(1))), x) + Simp(b*n*(d*x)**(m + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))/(d*(b + S(2)*c*x**n)*(m + S(1))*(m + n + S(1))), x) def replacement1120(a, b, c, m, n, n2, x): return -Dist(b/(S(2)*a), Int(S(1)/(x*sqrt(a + b*x**n + c*x**(S(2)*n))), x), x) - Simp(x**(m + S(1))*sqrt(a + b*x**n + c*x**(S(2)*n))/(a*n), x) def replacement1121(a, b, c, d, m, n, n2, p, x): return -Simp((d*x)**(m + S(1))*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*a*d*n*(S(2)*p + S(1))), x) + Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(S(2)*a*d*n*(p + S(1))*(S(2)*p + S(1))), x) def replacement1122(a, b, c, m, n, n2, p, x): return -Dist(b/(S(2)*c), Int(x**(n + S(-1))*(a + b*x**n + c*x**(S(2)*n))**p, x), x) + Simp((a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(S(2)*c*n*(p + S(1))), x) def replacement1123(a, b, c, d, m, n, n2, p, x): return -Dist(b*d**(-n)*n**S(2)*p*(S(2)*p + S(-1))/((m + S(1))*(m + S(2)*n*p + S(1))), Int((d*x)**(m + n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**p/(d*(m + S(2)*n*p + S(1))), x) + Simp(n*p*(d*x)**(m + S(1))*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/(d*(m + S(1))*(m + S(2)*n*p + S(1))), x) def replacement1124(a, b, c, d, m, n, n2, p, x): return Dist(S(2)*c*d**(-S(2)*n)*n**S(2)*p*(S(2)*p + S(-1))/((m + S(1))*(m + n + S(1))), Int((d*x)**(m + S(2)*n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**p*(m - n*(S(2)*p + S(-1)) + S(1))/(d*(m + S(1))*(m + n + S(1))), x) + Simp(n*p*(d*x)**(m + S(1))*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/(d*(m + S(1))*(m + n + S(1))), x) def replacement1125(a, b, c, d, m, n, n2, p, x): return Dist(S(2)*a*n**S(2)*p*(S(2)*p + S(-1))/((m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(-1)) + S(1))), Int((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**p/(d*(m + S(2)*n*p + S(1))), x) + Simp(n*p*(d*x)**(m + S(1))*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/(d*(m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(-1)) + S(1))), x) def replacement1126(a, b, c, d, m, n, n2, p, x): return -Dist(d**n*(m - n + S(1))*(m + n*(S(2)*p + S(1)) + S(1))/(b*n**S(2)*(p + S(1))*(S(2)*p + S(1))), Int((d*x)**(m - n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(1)), x), x) - Simp((d*x)**(m + S(1))*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(b*d*n*(S(2)*p + S(1))), x) + Simp(d**(n + S(-1))*(d*x)**(m - n + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(m + n*(S(2)*p + S(1)) + S(1))/(b*n**S(2)*(p + S(1))*(S(2)*p + S(1))), x) def replacement1127(a, b, c, d, m, n, n2, p, x): return Dist(d**(S(2)*n)*(m - S(2)*n + S(1))*(m - n + S(1))/(S(2)*c*n**S(2)*(p + S(1))*(S(2)*p + S(1))), Int((d*x)**(m - S(2)*n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(1)), x), x) - Simp(d**(S(2)*n + S(-1))*(d*x)**(m - S(2)*n + S(1))*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*c*n*(S(2)*p + S(1))), x) - Simp(d**(S(2)*n + S(-1))*(d*x)**(m - S(2)*n + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(m - S(2)*n*p - S(3)*n + S(1))/(S(2)*c*n**S(2)*(p + S(1))*(S(2)*p + S(1))), x) def replacement1128(a, b, c, d, m, n, n2, p, x): return Dist((m + S(2)*n*(p + S(1)) + S(1))*(m + n*(S(2)*p + S(1)) + S(1))/(S(2)*a*n**S(2)*(p + S(1))*(S(2)*p + S(1))), Int((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**(p + S(1)), x), x) - Simp((d*x)**(m + S(1))*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*a*d*n*(S(2)*p + S(1))), x) - Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(m + n*(S(2)*p + S(1)) + S(1))/(S(2)*a*d*n**S(2)*(p + S(1))*(S(2)*p + S(1))), x) def replacement1129(a, b, c, d, m, n, n2, p, x): return -Dist(b*d**n*(m - n + S(1))/(S(2)*c*(m + S(2)*n*p + S(1))), Int((d*x)**(m - n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x) + Simp(d**(n + S(-1))*(d*x)**(m - n + S(1))*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(S(2)*c*(m + S(2)*n*p + S(1))), x) def replacement1130(a, b, c, d, m, n, n2, p, x): return -Dist(S(2)*c*d**(-n)*(m + n*(S(2)*p + S(1)) + S(1))/(b*(m + S(1))), Int((d*x)**(m + n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x) + Simp((d*x)**(m + S(1))*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**p/(b*d*(m + S(1))), x) def replacement1131(a, b, c, m, n, n2, p, x): return -Subst(Int(x**(-m + S(-2))*(a + b*x**(-n) + c*x**(-S(2)*n))**p, x), x, S(1)/x) def With1132(a, b, c, d, m, n, n2, p, x): k = Denominator(m) return -Dist(k/d, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*d**(-n)*x**(-k*n) + c*d**(-S(2)*n)*x**(-S(2)*k*n))**p, x), x, (d*x)**(-S(1)/k)), x) def replacement1133(a, b, c, d, m, n, n2, p, x): return -Dist(d**IntPart(m)*(d*x)**FracPart(m)*(S(1)/x)**FracPart(m), Subst(Int(x**(-m + S(-2))*(a + b*x**(-n) + c*x**(-S(2)*n))**p, x), x, S(1)/x), x) def replacement1134(a, b, c, d, m, n, n2, p, x): return Dist(c**(-IntPart(p))*(b/S(2) + c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((d*x)**m*(b/S(2) + c*x**n)**(S(2)*p), x), x) def replacement1135(a, b, c, m, n, n2, p, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + b*x + c*x**S(2))**p, x), x, x**n), x) def replacement1136(a, b, c, d, m, n, n2, p, x): return Dist(d**IntPart(m)*x**(-FracPart(m))*(d*x)**FracPart(m), Int(x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def With1137(a, b, c, m, n, n2, p, x): if isinstance(x, (int, Integer, float, Float)): return False k = GCD(m + S(1), n) if Unequal(k, S(1)): return True return False def replacement1137(a, b, c, m, n, n2, p, x): k = GCD(m + S(1), n) return Dist(S(1)/k, Subst(Int(x**(S(-1) + (m + S(1))/k)*(a + b*x**(n/k) + c*x**(S(2)*n/k))**p, x), x, x**k), x) def With1138(a, b, c, d, m, n, n2, p, x): k = Denominator(m) return Dist(k/d, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*d**(-n)*x**(k*n) + c*d**(-S(2)*n)*x**(S(2)*k*n))**p, x), x, (d*x)**(S(1)/k)), x) def replacement1139(a, b, c, d, m, n, n2, p, x): return -Dist(d**n*n*p/(c*(m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(-1)) + S(1))), Int((d*x)**(m - n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))*Simp(a*b*(m - n + S(1)) - x**n*(S(2)*a*c*(m + n*(S(2)*p + S(-1)) + S(1)) - b**S(2)*(m + n*(p + S(-1)) + S(1))), x), x), x) + Simp(d**(n + S(-1))*(d*x)**(m - n + S(1))*(b*n*p + c*x**n*(m + n*(S(2)*p + S(-1)) + S(1)))*(a + b*x**n + c*x**(S(2)*n))**p/(c*(m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(-1)) + S(1))), x) def replacement1140(a, b, c, d, m, n, n2, p, x): return -Dist(d**(-n)*n*p/(m + S(1)), Int((d*x)**(m + n)*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**p/(d*(m + S(1))), x) def replacement1141(a, b, c, d, m, n, n2, p, x): return Dist(n*p/(m + S(2)*n*p + S(1)), Int((d*x)**m*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**p/(d*(m + S(2)*n*p + S(1))), x) def replacement1142(a, b, c, d, m, n, n2, p, x): return -Dist(d**n/(n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((d*x)**(m - n)*(b*(m - n + S(1)) + S(2)*c*x**n*(m + S(2)*n*(p + S(1)) + S(1)))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1)), x), x) + Simp(d**(n + S(-1))*(d*x)**(m - n + S(1))*(b + S(2)*c*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1143(a, b, c, d, m, n, n2, p, x): return Dist(d**(S(2)*n)/(n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((d*x)**(m - S(2)*n)*(S(2)*a*(m - S(2)*n + S(1)) + b*x**n*(m + n*(S(2)*p + S(1)) + S(1)))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1)), x), x) - Simp(d**(S(2)*n + S(-1))*(d*x)**(m - S(2)*n + S(1))*(S(2)*a + b*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1144(a, b, c, d, m, n, n2, p, x): return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(-S(2)*a*c*(m + S(2)*n*(p + S(1)) + S(1)) + b**S(2)*(m + n*(p + S(1)) + S(1)) + b*c*x**n*(m + S(2)*n*p + S(3)*n + S(1)), x), x), x) - Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*d*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1145(a, b, c, d, m, n, n2, p, x): return -Dist(d**(S(2)*n)/(c*(m + S(2)*n*p + S(1))), Int((d*x)**(m - S(2)*n)*(a + b*x**n + c*x**(S(2)*n))**p*Simp(a*(m - S(2)*n + S(1)) + b*x**n*(m + n*(p + S(-1)) + S(1)), x), x), x) + Simp(d**(S(2)*n + S(-1))*(d*x)**(m - S(2)*n + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(c*(m + S(2)*n*p + S(1))), x) def replacement1146(a, b, c, d, m, n, n2, p, x): return -Dist(d**(-n)/(a*(m + S(1))), Int((d*x)**(m + n)*(b*(m + n*(p + S(1)) + S(1)) + c*x**n*(m + S(2)*n*(p + S(1)) + S(1)))*(a + b*x**n + c*x**(S(2)*n))**p, x), x) + Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(a*d*(m + S(1))), x) def replacement1147(a, b, c, d, m, n, n2, x): return -Dist(d**(-n)/a, Int((d*x)**(m + n)*(b + c*x**n)/(a + b*x**n + c*x**(S(2)*n)), x), x) + Simp((d*x)**(m + S(1))/(a*d*(m + S(1))), x) def replacement1148(a, b, c, m, n, n2, x): return Int(PolynomialDivide(x**m, a + b*x**n + c*x**(S(2)*n), x), x) def replacement1149(a, b, c, d, m, n, n2, x): return -Dist(d**(S(2)*n)/c, Int((d*x)**(m - S(2)*n)*(a + b*x**n)/(a + b*x**n + c*x**(S(2)*n)), x), x) + Simp(d**(S(2)*n + S(-1))*(d*x)**(m - S(2)*n + S(1))/(c*(m - S(2)*n + S(1))), x) def With1150(a, b, c, x): q = Rt(a/c, S(2)) return -Dist(S(1)/2, Int((q - x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x) + Dist(S(1)/2, Int((q + x**S(2))/(a + b*x**S(2) + c*x**S(4)), x), x) def With1151(a, b, c, m, n, n2, x): q = Rt(a/c, S(2)) r = Rt(-b/c + S(2)*q, S(2)) return -Dist(1/(2*c*r), Int(x**(m - 3*n/2)*(q - r*x**(n/2))/(q - r*x**(n/2) + x**n), x), x) + Dist(1/(2*c*r), Int(x**(m - 3*n/2)*(q + r*x**(n/2))/(q + r*x**(n/2) + x**n), x), x) def With1152(a, b, c, m, n, n2, x): q = Rt(a/c, S(2)) r = Rt(-b/c + S(2)*q, S(2)) return Dist(1/(2*c*r), Int(x**(m - n/2)/(q - r*x**(n/2) + x**n), x), x) - Dist(1/(2*c*r), Int(x**(m - n/2)/(q + r*x**(n/2) + x**n), x), x) def With1153(a, b, c, d, m, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return -Dist(d**n*(b/q + S(-1))/S(2), Int((d*x)**(m - n)/(b/S(2) + c*x**n - q/S(2)), x), x) + Dist(d**n*(b/q + S(1))/S(2), Int((d*x)**(m - n)/(b/S(2) + c*x**n + q/S(2)), x), x) def With1154(a, b, c, d, m, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(c/q, Int((d*x)**m/(b/S(2) + c*x**n - q/S(2)), x), x) - Dist(c/q, Int((d*x)**m/(b/S(2) + c*x**n + q/S(2)), x), x) def With1155(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*sqrt(-c), Int(x**S(2)/(sqrt(-b - S(2)*c*x**S(2) + q)*sqrt(b + S(2)*c*x**S(2) + q)), x), x) def With1156(a, b, c, x): q = Rt(c/a, S(2)) return -Dist(S(1)/q, Int((-q*x**S(2) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist(S(1)/q, Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1157(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(1)/(S(2)*c), Int((b + S(2)*c*x**S(2) - q)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) - Dist((b - q)/(S(2)*c), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1158(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(PosQ((b + q)/a), Not(And(PosQ((b - q)/a), SimplerSqrtQ((b - q)/(S(2)*a), (b + q)/(S(2)*a))))): return True return False def replacement1158(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(x*(b + S(2)*c*x**S(2) + q)/(S(2)*c*sqrt(a + b*x**S(2) + c*x**S(4))), x) - Simp(sqrt((S(2)*a + x**S(2)*(b - q))/(S(2)*a + x**S(2)*(b + q)))*(S(2)*a + x**S(2)*(b + q))*EllipticE(ArcTan(x*Rt((b + q)/(S(2)*a), S(2))), S(2)*q/(b + q))*Rt((b + q)/(S(2)*a), S(2))/(S(2)*c*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1159(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if PosQ((b - q)/a): return True return False def replacement1159(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(x*(b + S(2)*c*x**S(2) - q)/(S(2)*c*sqrt(a + b*x**S(2) + c*x**S(4))), x) - Simp(sqrt((S(2)*a + x**S(2)*(b + q))/(S(2)*a + x**S(2)*(b - q)))*(S(2)*a + x**S(2)*(b - q))*EllipticE(ArcTan(x*Rt((b - q)/(S(2)*a), S(2))), -S(2)*q/(b - q))*Rt((b - q)/(S(2)*a), S(2))/(S(2)*c*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1160(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(NegQ((b + q)/a), Not(And(NegQ((b - q)/a), SimplerSqrtQ(-(b - q)/(S(2)*a), -(b + q)/(S(2)*a))))): return True return False def replacement1160(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(1)/(S(2)*c), Int((b + S(2)*c*x**S(2) + q)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) - Dist((b + q)/(S(2)*c), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1161(a, b, c, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if NegQ((b - q)/a): return True return False def replacement1161(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(1)/(S(2)*c), Int((b + S(2)*c*x**S(2) - q)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) - Dist((b - q)/(S(2)*c), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1162(a, b, c, x): q = Rt(c/a, S(2)) return -Dist(S(1)/q, Int((-q*x**S(2) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist(S(1)/q, Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1163(a, b, c, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), Int(x**S(2)/(sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))), x), x) def replacement1164(a, b, c, m, n, n2, p, x): return -Subst(Int(x**(-m + S(-2))*(a + b*x**(-n) + c*x**(-S(2)*n))**p, x), x, S(1)/x) def With1165(a, b, c, d, m, n, n2, p, x): k = Denominator(m) return -Dist(k/d, Subst(Int(x**(-k*(m + S(1)) + S(-1))*(a + b*d**(-n)*x**(-k*n) + c*d**(-S(2)*n)*x**(-S(2)*k*n))**p, x), x, (d*x)**(-S(1)/k)), x) def replacement1166(a, b, c, d, m, n, n2, p, x): return -Dist(d**IntPart(m)*(d*x)**FracPart(m)*(S(1)/x)**FracPart(m), Subst(Int(x**(-m + S(-2))*(a + b*x**(-n) + c*x**(-S(2)*n))**p, x), x, S(1)/x), x) def With1167(a, b, c, m, n, n2, p, x): k = Denominator(n) return Dist(k, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + b*x**(k*n) + c*x**(S(2)*k*n))**p, x), x, x**(S(1)/k)), x) def replacement1168(a, b, c, d, m, n, n2, p, x): return Dist(d**IntPart(m)*x**(-FracPart(m))*(d*x)**FracPart(m), Int(x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1169(a, b, c, m, n, n2, p, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + b*x**(n/(m + S(1))) + c*x**(S(2)*n/(m + S(1))))**p, x), x, x**(m + S(1))), x) def replacement1170(a, b, c, d, m, n, n2, p, x): return Dist(d**IntPart(m)*x**(-FracPart(m))*(d*x)**FracPart(m), Int(x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def With1171(a, b, c, d, m, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/q, Int((d*x)**m/(b + S(2)*c*x**n - q), x), x) - Dist(S(2)*c/q, Int((d*x)**m/(b + S(2)*c*x**n + q), x), x) def replacement1172(a, b, c, d, m, n, n2, p, x): return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((d*x)**m*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(-S(2)*a*c*(m + S(2)*n*(p + S(1)) + S(1)) + b**S(2)*(m + n*(p + S(1)) + S(1)) + b*c*x**n*(m + S(2)*n*p + S(3)*n + S(1)), x), x), x) - Simp((d*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**n)/(a*d*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1173(a, b, c, d, m, n, n2, p, x): return Dist(a**IntPart(p)*(S(2)*c*x**n/(b - Rt(-S(4)*a*c + b**S(2), S(2))) + S(1))**(-FracPart(p))*(S(2)*c*x**n/(b + Rt(-S(4)*a*c + b**S(2), S(2))) + S(1))**(-FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((d*x)**m*(S(2)*c*x**n/(b - sqrt(-S(4)*a*c + b**S(2))) + S(1))**p*(S(2)*c*x**n/(b + sqrt(-S(4)*a*c + b**S(2))) + S(1))**p, x), x) def replacement1174(a, b, c, m, mn, n, p, x): return Int(x**(m - n*p)*(a*x**n + b + c*x**(S(2)*n))**p, x) def replacement1175(a, b, c, m, mn, n, p, x): return Dist(x**(n*FracPart(p))*(a + b*x**(-n) + c*x**n)**FracPart(p)*(a*x**n + b + c*x**(S(2)*n))**(-FracPart(p)), Int(x**(m - n*p)*(a*x**n + b + c*x**(S(2)*n))**p, x), x) def replacement1176(a, b, c, d, m, mn, n, p, x): return Dist(d**IntPart(m)*x**(-FracPart(m))*(d*x)**FracPart(m), Int(x**m*(a + b*x**(-n) + c*x**n)**p, x), x) def replacement1177(a, b, c, m, n, n2, p, v, x): return Dist(Coefficient(v, x, S(1))**(-m + S(-1)), Subst(Int(SimplifyIntegrand((x - Coefficient(v, x, S(0)))**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x), x, v), x) def replacement1178(a, b, c, m, n, n2, p, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(a + b*x**n + c*x**(S(2)*n))**p, x), x, v), x) def replacement1179(a, b, c, d, e, n, n2, p, q, x): return Int(x**(n*(S(2)*p + q))*(d*x**(-n) + e)**q*(a*x**(-S(2)*n) + b*x**(-n) + c)**p, x) def replacement1180(a, c, d, e, n, n2, p, q, x): return Int(x**(n*(S(2)*p + q))*(a*x**(-S(2)*n) + c)**p*(d*x**(-n) + e)**q, x) def replacement1181(a, b, c, d, e, n, n2, p, q, x): return -Subst(Int((d + e*x**(-n))**q*(a + b*x**(-n) + c*x**(-S(2)*n))**p/x**S(2), x), x, S(1)/x) def replacement1182(a, c, d, e, n, n2, p, q, x): return -Subst(Int((a + c*x**(-S(2)*n))**p*(d + e*x**(-n))**q/x**S(2), x), x, S(1)/x) def With1183(a, b, c, d, e, n, n2, p, q, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g + S(-1))*(d + e*x**(g*n))**q*(a + b*x**(g*n) + c*x**(S(2)*g*n))**p, x), x, x**(S(1)/g)), x) def With1184(a, c, d, e, n, n2, p, q, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g + S(-1))*(a + c*x**(S(2)*g*n))**p*(d + e*x**(g*n))**q, x), x, x**(S(1)/g)), x) def replacement1185(b, c, d, e, n, n2, p, x): return Dist(e/c, Int(x**(-n)*(b*x**n + c*x**(S(2)*n))**(p + S(1)), x), x) + Simp(x**(-S(2)*n*(p + S(1)))*(b*e - c*d)*(b*x**n + c*x**(S(2)*n))**(p + S(1))/(b*c*n*(p + S(1))), x) def replacement1186(b, c, d, e, n, n2, p, x): return Simp(e*x**(S(1) - n)*(b*x**n + c*x**(S(2)*n))**(p + S(1))/(c*(n*(S(2)*p + S(1)) + S(1))), x) def replacement1187(b, c, d, e, n, n2, p, x): return -Dist((b*e*(n*p + S(1)) - c*d*(n*(S(2)*p + S(1)) + S(1)))/(c*(n*(S(2)*p + S(1)) + S(1))), Int((b*x**n + c*x**(S(2)*n))**p, x), x) + Simp(e*x**(S(1) - n)*(b*x**n + c*x**(S(2)*n))**(p + S(1))/(c*(n*(S(2)*p + S(1)) + S(1))), x) def replacement1188(b, c, d, e, n, n2, p, q, x): return Dist(x**(-n*FracPart(p))*(b + c*x**n)**(-FracPart(p))*(b*x**n + c*x**(S(2)*n))**FracPart(p), Int(x**(n*p)*(b + c*x**n)**p*(d + e*x**n)**q, x), x) def replacement1189(a, b, c, d, e, n, n2, p, q, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((b + S(2)*c*x**n)**(S(2)*p)*(d + e*x**n)**q, x), x) def replacement1190(a, b, c, d, e, n, n2, p, q, x): return Int((d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x) def replacement1191(a, c, d, e, n, n2, p, q, x): return Int((d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x) def replacement1192(a, b, c, d, e, n, n2, p, q, x): return Dist((d + e*x**n)**(-FracPart(p))*(a/d + c*x**n/e)**(-FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x), x) def replacement1193(a, c, d, e, n, n2, p, q, x): return Dist((a + c*x**(S(2)*n))**FracPart(p)*(d + e*x**n)**(-FracPart(p))*(a/d + c*x**n/e)**(-FracPart(p)), Int((d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x), x) def replacement1194(a, b, c, d, e, n, n2, q, x): return Int(ExpandIntegrand((d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1195(a, c, d, e, n, n2, q, x): return Int(ExpandIntegrand((a + c*x**(S(2)*n))*(d + e*x**n)**q, x), x) def replacement1196(a, b, c, d, e, n, n2, q, x): return Dist(S(1)/(d*e**S(2)*n*(q + S(1))), Int((d + e*x**n)**(q + S(1))*Simp(a*e**S(2)*(n*(q + S(1)) + S(1)) - b*d*e + c*d**S(2) + c*d*e*n*x**n*(q + S(1)), x), x), x) - Simp(x*(d + e*x**n)**(q + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))/(d*e**S(2)*n*(q + S(1))), x) def replacement1197(a, c, d, e, n, n2, q, x): return Dist(S(1)/(d*e**S(2)*n*(q + S(1))), Int((d + e*x**n)**(q + S(1))*Simp(a*e**S(2)*(n*(q + S(1)) + S(1)) + c*d**S(2) + c*d*e*n*x**n*(q + S(1)), x), x), x) - Simp(x*(d + e*x**n)**(q + S(1))*(a*e**S(2) + c*d**S(2))/(d*e**S(2)*n*(q + S(1))), x) def replacement1198(a, b, c, d, e, n, n2, q, x): return Dist(S(1)/(e*(n*(q + S(2)) + S(1))), Int((d + e*x**n)**q*(a*e*(n*(q + S(2)) + S(1)) - x**n*(-b*e*(n*(q + S(2)) + S(1)) + c*d*(n + S(1)))), x), x) + Simp(c*x**(n + S(1))*(d + e*x**n)**(q + S(1))/(e*(n*(q + S(2)) + S(1))), x) def replacement1199(a, c, d, e, n, n2, q, x): return Dist(S(1)/(e*(n*(q + S(2)) + S(1))), Int((d + e*x**n)**q*(a*e*(n*(q + S(2)) + S(1)) - c*d*x**n*(n + S(1))), x), x) + Simp(c*x**(n + S(1))*(d + e*x**n)**(q + S(1))/(e*(n*(q + S(2)) + S(1))), x) def With1200(a, c, d, e, n, n2, x): q = Rt(S(2)*d*e, S(2)) return Dist(e**S(2)/(S(2)*c), Int(S(1)/(d + e*x**n - q*x**(n/S(2))), x), x) + Dist(e**S(2)/(S(2)*c), Int(S(1)/(d + e*x**n + q*x**(n/S(2))), x), x) def With1201(a, c, d, e, n, n2, x): q = Rt(-S(2)*d*e, S(2)) return Dist(d/(S(2)*a), Int((d - q*x**(n/S(2)))/(d - e*x**n - q*x**(n/S(2))), x), x) + Dist(d/(S(2)*a), Int((d + q*x**(n/S(2)))/(d - e*x**n + q*x**(n/S(2))), x), x) def With1202(a, c, d, e, x): q = Rt(a*c, S(2)) return Dist((-a*e + d*q)/(S(2)*a*c), Int((-c*x**S(2) + q)/(a + c*x**S(4)), x), x) + Dist((a*e + d*q)/(S(2)*a*c), Int((c*x**S(2) + q)/(a + c*x**S(4)), x), x) def With1203(a, c, d, e, n, n2, x): q = Rt(a/c, S(4)) return Dist(sqrt(S(2))/(S(4)*c*q**S(3)), Int((sqrt(S(2))*d*q - x**(n/S(2))*(d - e*q**S(2)))/(q**S(2) - sqrt(S(2))*q*x**(n/S(2)) + x**n), x), x) + Dist(sqrt(S(2))/(S(4)*c*q**S(3)), Int((sqrt(S(2))*d*q + x**(n/S(2))*(d - e*q**S(2)))/(q**S(2) + sqrt(S(2))*q*x**(n/S(2)) + x**n), x), x) def With1204(a, c, d, e, x): q = Rt(c/a, S(6)) return Dist(S(1)/(S(6)*a*q**S(2)), Int((S(2)*d*q**S(2) - x*(sqrt(S(3))*d*q**S(3) - e))/(q**S(2)*x**S(2) - sqrt(S(3))*q*x + S(1)), x), x) + Dist(S(1)/(S(6)*a*q**S(2)), Int((S(2)*d*q**S(2) + x*(sqrt(S(3))*d*q**S(3) + e))/(q**S(2)*x**S(2) + sqrt(S(3))*q*x + S(1)), x), x) + Dist(S(1)/(S(3)*a*q**S(2)), Int((d*q**S(2) - e*x)/(q**S(2)*x**S(2) + S(1)), x), x) def With1205(a, c, d, e, n, n2, x): q = Rt(-a/c, S(2)) return Dist(d/S(2) - e*q/S(2), Int(S(1)/(a - c*q*x**n), x), x) + Dist(d/S(2) + e*q/S(2), Int(S(1)/(a + c*q*x**n), x), x) def replacement1206(a, c, d, e, n, n2, x): return Dist(d, Int(S(1)/(a + c*x**(S(2)*n)), x), x) + Dist(e, Int(x**n/(a + c*x**(S(2)*n)), x), x) def With1207(a, b, c, d, e, n, n2, x): q = Rt(-b/c + S(2)*d/e, S(2)) return Dist(e**S(2)/(S(2)*c), Int(S(1)/(d - e*q*x**(n/S(2)) + e*x**n), x), x) + Dist(e**S(2)/(S(2)*c), Int(S(1)/(d + e*q*x**(n/S(2)) + e*x**n), x), x) def With1208(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(e/S(2) - (-b*e + S(2)*c*d)/(S(2)*q), Int(S(1)/(b/S(2) + c*x**n + q/S(2)), x), x) + Dist(e/S(2) + (-b*e + S(2)*c*d)/(S(2)*q), Int(S(1)/(b/S(2) + c*x**n - q/S(2)), x), x) def With1209(a, b, c, d, e, n, n2, x): q = Rt(a/c, S(2)) r = Rt(-b/c + S(2)*q, S(2)) return Dist(1/(2*c*q*r), Int((d*r - x**(n/2)*(d - e*q))/(q - r*x**(n/2) + x**n), x), x) + Dist(1/(2*c*q*r), Int((d*r + x**(n/2)*(d - e*q))/(q + r*x**(n/2) + x**n), x), x) def With1210(a, b, c, d, e, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(e/S(2) - (-b*e + S(2)*c*d)/(S(2)*q), Int(S(1)/(b/S(2) + c*x**n + q/S(2)), x), x) + Dist(e/S(2) + (-b*e + S(2)*c*d)/(S(2)*q), Int(S(1)/(b/S(2) + c*x**n - q/S(2)), x), x) def With1211(a, b, c, d, e, n, n2, x): q = Rt(a/c, S(2)) r = Rt(-b/c + S(2)*q, S(2)) return Dist(1/(2*c*q*r), Int((d*r - x**(n/2)*(d - e*q))/(q - r*x**(n/2) + x**n), x), x) + Dist(1/(2*c*q*r), Int((d*r + x**(n/2)*(d - e*q))/(q + r*x**(n/2) + x**n), x), x) def replacement1212(a, b, c, d, e, n, n2, q, x): return Int(ExpandIntegrand((d + e*x**n)**q/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1213(a, c, d, e, n, n2, q, x): return Int(ExpandIntegrand((d + e*x**n)**q/(a + c*x**(S(2)*n)), x), x) def replacement1214(a, b, c, d, e, n, n2, q, x): return Dist(e**S(2)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((d + e*x**n)**q, x), x) + Dist(S(1)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((d + e*x**n)**(q + S(1))*(-b*e + c*d - c*e*x**n)/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1215(a, c, d, e, n, n2, q, x): return Dist(c/(a*e**S(2) + c*d**S(2)), Int((d - e*x**n)*(d + e*x**n)**(q + S(1))/(a + c*x**(S(2)*n)), x), x) + Dist(e**S(2)/(a*e**S(2) + c*d**S(2)), Int((d + e*x**n)**q, x), x) def With1216(a, b, c, d, e, n, n2, q, x): r = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/r, Int((d + e*x**n)**q/(b + S(2)*c*x**n - r), x), x) - Dist(S(2)*c/r, Int((d + e*x**n)**q/(b + S(2)*c*x**n + r), x), x) def With1217(a, c, d, e, n, n2, q, x): r = Rt(-a*c, S(2)) return -Dist(c/(S(2)*r), Int((d + e*x**n)**q/(-c*x**n + r), x), x) - Dist(c/(S(2)*r), Int((d + e*x**n)**q/(c*x**n + r), x), x) def replacement1218(a, b, c, d, e, n, n2, p, x): return Dist(n*p/(c*(S(2)*n*p + S(1))*(S(2)*n*p + n + S(1))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(-1))*Simp(-a*b*e + S(2)*a*c*d*(S(2)*n*p + n + S(1)) + x**n*(S(2)*a*c*e*(S(2)*n*p + S(1)) - b**S(2)*e*(n*p + S(1)) + b*c*d*(S(2)*n*p + n + S(1))), x), x), x) + Simp(x*(a + b*x**n + c*x**(S(2)*n))**p*(b*e*n*p + c*d*(S(2)*n*p + n + S(1)) + c*e*x**n*(S(2)*n*p + S(1)))/(c*(S(2)*n*p + S(1))*(S(2)*n*p + n + S(1))), x) def replacement1219(a, c, d, e, n, n2, p, x): return Dist(S(2)*a*n*p/((S(2)*n*p + S(1))*(S(2)*n*p + n + S(1))), Int((a + c*x**(S(2)*n))**(p + S(-1))*(d*(S(2)*n*p + n + S(1)) + e*x**n*(S(2)*n*p + S(1))), x), x) + Simp(x*(a + c*x**(S(2)*n))**p*(d*(S(2)*n*p + n + S(1)) + e*x**n*(S(2)*n*p + S(1)))/((S(2)*n*p + S(1))*(S(2)*n*p + n + S(1))), x) def replacement1220(a, b, c, d, e, n, n2, p, x): return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(-a*b*e - S(2)*a*c*d*(S(2)*n*p + S(2)*n + S(1)) + b**S(2)*d*(n*p + n + S(1)) + c*x**n*(-S(2)*a*e + b*d)*(S(2)*n*p + S(3)*n + S(1)), x), x), x) - Simp(x*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a*b*e - S(2)*a*c*d + b**S(2)*d + c*x**n*(-S(2)*a*e + b*d))/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1221(a, c, d, e, n, n2, p, x): return Dist(S(1)/(S(2)*a*n*(p + S(1))), Int((a + c*x**(S(2)*n))**(p + S(1))*(d*(S(2)*n*p + S(2)*n + S(1)) + e*x**n*(S(2)*n*p + S(3)*n + S(1))), x), x) - Simp(x*(a + c*x**(S(2)*n))**(p + S(1))*(d + e*x**n)/(S(2)*a*n*(p + S(1))), x) def With1222(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*sqrt(-c), Int((d + e*x**S(2))/(sqrt(-b - S(2)*c*x**S(2) + q)*sqrt(b + S(2)*c*x**S(2) + q)), x), x) def With1223(a, c, d, e, x): q = Rt(-a*c, S(2)) return Dist(sqrt(-c), Int((d + e*x**S(2))/(sqrt(-c*x**S(2) + q)*sqrt(c*x**S(2) + q)), x), x) def With1224(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(4)) if ZeroQ(d*q**S(2) + e): return True return False def replacement1224(a, b, c, d, e, x): q = Rt(c/a, S(4)) return -Simp(d*x*sqrt(a + b*x**S(2) + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))), x) + Simp(d*sqrt((a + b*x**S(2) + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(q**S(2)*x**S(2) + S(1))*EllipticE(S(2)*ArcTan(q*x), -b*q**S(2)/(S(4)*c) + S(1)/2)/(q*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1225(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(2)) if NonzeroQ(d*q + e): return True return False def replacement1225(a, b, c, d, e, x): q = Rt(c/a, S(2)) return -Dist(e/q, Int((-q*x**S(2) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((d*q + e)/q, Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1226(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if ZeroQ(S(2)*c*d - e*(b - q)): return True return False def replacement1226(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Simp(e*x*(b + S(2)*c*x**S(2) + q)/(S(2)*c*sqrt(a + b*x**S(2) + c*x**S(4))), x) - Simp(e*q*sqrt((S(2)*a + x**S(2)*(b + q))/q)*sqrt((S(2)*a + x**S(2)*(b - q))/(S(2)*a + x**S(2)*(b + q)))*EllipticE(asin(sqrt(S(2))*x/sqrt((S(2)*a + x**S(2)*(b + q))/q)), (b + q)/(S(2)*q))/(S(2)*c*sqrt(a/(S(2)*a + x**S(2)*(b + q)))*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1227(a, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-a*c, S(2)) if And(ZeroQ(c*d + e*q), IntegerQ(q)): return True return False def replacement1227(a, c, d, e, x): q = Rt(-a*c, S(2)) return Simp(e*x*(c*x**S(2) + q)/(c*sqrt(a + c*x**S(4))), x) - Simp(sqrt(S(2))*e*q*sqrt((a + q*x**S(2))/q)*sqrt(-a + q*x**S(2))*EllipticE(asin(sqrt(S(2))*x/sqrt((a + q*x**S(2))/q)), S(1)/2)/(c*sqrt(-a)*sqrt(a + c*x**S(4))), x) def With1228(a, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-a*c, S(2)) if ZeroQ(c*d + e*q): return True return False def replacement1228(a, c, d, e, x): q = Rt(-a*c, S(2)) return Simp(e*x*(c*x**S(2) + q)/(c*sqrt(a + c*x**S(4))), x) - Simp(sqrt(S(2))*e*q*sqrt((a + q*x**S(2))/q)*sqrt((a - q*x**S(2))/(a + q*x**S(2)))*EllipticE(asin(sqrt(S(2))*x/sqrt((a + q*x**S(2))/q)), S(1)/2)/(c*sqrt(a/(a + q*x**S(2)))*sqrt(a + c*x**S(4))), x) def With1229(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if NonzeroQ(S(2)*c*d - e*(b - q)): return True return False def replacement1229(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(e/(S(2)*c), Int((b + S(2)*c*x**S(2) - q)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((S(2)*c*d - e*(b - q))/(S(2)*c), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1230(a, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-a*c, S(2)) if NonzeroQ(c*d + e*q): return True return False def replacement1230(a, c, d, e, x): q = Rt(-a*c, S(2)) return -Dist(e/c, Int((-c*x**S(2) + q)/sqrt(a + c*x**S(4)), x), x) + Dist((c*d + e*q)/c, Int(S(1)/sqrt(a + c*x**S(4)), x), x) def With1231(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if Or(PosQ((b + q)/a), PosQ((b - q)/a)): return True return False def replacement1231(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(d, Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist(e, Int(x**S(2)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def replacement1232(a, c, d, e, x): return Dist(d, Int(S(1)/sqrt(a + c*x**S(4)), x), x) + Dist(e, Int(x**S(2)/sqrt(a + c*x**S(4)), x), x) def With1233(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(NegQ((b + q)/a), ZeroQ(S(2)*c*d - e*(b + q)), Not(SimplerSqrtQ(-(b - q)/(S(2)*a), -(b + q)/(S(2)*a)))): return True return False def replacement1233(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return -Simp(a*e*sqrt(S(1) + x**S(2)*(b - q)/(S(2)*a))*sqrt(S(1) + x**S(2)*(b + q)/(S(2)*a))*EllipticE(asin(x*Rt(-(b + q)/(S(2)*a), S(2))), (b - q)/(b + q))*Rt(-(b + q)/(S(2)*a), S(2))/(c*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1234(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(NegQ((b + q)/a), NonzeroQ(S(2)*c*d - e*(b + q)), Not(SimplerSqrtQ(-(b - q)/(S(2)*a), -(b + q)/(S(2)*a)))): return True return False def replacement1234(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(e/(S(2)*c), Int((b + S(2)*c*x**S(2) + q)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((S(2)*c*d - e*(b + q))/(S(2)*c), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1235(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(NegQ((b - q)/a), ZeroQ(S(2)*c*d - e*(b - q))): return True return False def replacement1235(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return -Simp(a*e*sqrt(S(1) + x**S(2)*(b - q)/(S(2)*a))*sqrt(S(1) + x**S(2)*(b + q)/(S(2)*a))*EllipticE(asin(x*Rt(-(b - q)/(S(2)*a), S(2))), (b + q)/(b - q))*Rt(-(b - q)/(S(2)*a), S(2))/(c*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1236(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if And(NegQ((b - q)/a), NonzeroQ(S(2)*c*d - e*(b - q))): return True return False def replacement1236(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(e/(S(2)*c), Int((b + S(2)*c*x**S(2) - q)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((S(2)*c*d - e*(b - q))/(S(2)*c), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1237(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(4)) if ZeroQ(d*q**S(2) + e): return True return False def replacement1237(a, b, c, d, e, x): q = Rt(c/a, S(4)) return -Simp(d*x*sqrt(a + b*x**S(2) + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))), x) + Simp(d*sqrt((a + b*x**S(2) + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(q**S(2)*x**S(2) + S(1))*EllipticE(S(2)*ArcTan(q*x), -b*q**S(2)/(S(4)*c) + S(1)/2)/(q*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1238(a, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(4)) if ZeroQ(d*q**S(2) + e): return True return False def replacement1238(a, c, d, e, x): q = Rt(c/a, S(4)) return -Simp(d*x*sqrt(a + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))), x) + Simp(d*sqrt((a + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(q**S(2)*x**S(2) + S(1))*EllipticE(S(2)*ArcTan(q*x), S(1)/2)/(q*sqrt(a + c*x**S(4))), x) def With1239(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(2)) if NonzeroQ(d*q + e): return True return False def replacement1239(a, b, c, d, e, x): q = Rt(c/a, S(2)) return -Dist(e/q, Int((-q*x**S(2) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((d*q + e)/q, Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) def With1240(a, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(2)) if NonzeroQ(d*q + e): return True return False def replacement1240(a, c, d, e, x): q = Rt(c/a, S(2)) return -Dist(e/q, Int((-q*x**S(2) + S(1))/sqrt(a + c*x**S(4)), x), x) + Dist((d*q + e)/q, Int(S(1)/sqrt(a + c*x**S(4)), x), x) def replacement1241(a, c, d, e, x): return Dist(d/sqrt(a), Int(sqrt(S(1) + e*x**S(2)/d)/sqrt(S(1) - e*x**S(2)/d), x), x) def replacement1242(a, c, d, e, x): return Dist(sqrt(S(1) + c*x**S(4)/a)/sqrt(a + c*x**S(4)), Int((d + e*x**S(2))/sqrt(S(1) + c*x**S(4)/a), x), x) def With1243(a, c, d, e, x): q = Rt(-c/a, S(2)) return Dist(e/q, Int((q*x**S(2) + S(1))/sqrt(a + c*x**S(4)), x), x) + Dist((d*q - e)/q, Int(S(1)/sqrt(a + c*x**S(4)), x), x) def With1244(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), Int((d + e*x**S(2))/(sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))), x), x) def replacement1245(a, b, c, d, e, n, n2, p, x): return Int(ExpandIntegrand((d + e*x**n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1246(a, c, d, e, n, n2, p, x): return Int(ExpandIntegrand((a + c*x**(S(2)*n))**p*(d + e*x**n), x), x) def replacement1247(a, b, c, d, e, n, n2, p, q, x): return Int((d + e*x**n)**q*ExpandToSum(-c**p*d*x**(S(2)*n*p - n)*(S(2)*n*p - n + S(1))/(e*(S(2)*n*p + n*q + S(1))) - c**p*x**(S(2)*n*p) + (a + b*x**n + c*x**(S(2)*n))**p, x), x) + Simp(c**p*x**(S(2)*n*p - n + S(1))*(d + e*x**n)**(q + S(1))/(e*(S(2)*n*p + n*q + S(1))), x) def replacement1248(a, c, d, e, n, n2, p, q, x): return Int((d + e*x**n)**q*ExpandToSum(-c**p*d*x**(S(2)*n*p - n)*(S(2)*n*p - n + S(1))/(e*(S(2)*n*p + n*q + S(1))) - c**p*x**(S(2)*n*p) + (a + c*x**(S(2)*n))**p, x), x) + Simp(c**p*x**(S(2)*n*p - n + S(1))*(d + e*x**n)**(q + S(1))/(e*(S(2)*n*p + n*q + S(1))), x) def replacement1249(a, b, c, d, e, x): return -Dist(e**(S(-2)), Int((-b*e + c*d - c*e*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((a*e**S(2) - b*d*e + c*d**S(2))/e**S(2), Int(S(1)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) def replacement1250(a, c, d, e, x): return -Dist(c/e**S(2), Int((d - e*x**S(2))/sqrt(a + c*x**S(4)), x), x) + Dist((a*e**S(2) + c*d**S(2))/e**S(2), Int(S(1)/(sqrt(a + c*x**S(4))*(d + e*x**S(2))), x), x) def With1251(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return -Dist(e**(S(-4)), Int(Simp(-c**S(2)*e**S(3)*x**S(6) + c*e**S(2)*x**S(4)*(-S(2)*b*e + c*d) - S(2)*c*(a*e**S(2) - b*d*e + c*d**S(2))**S(2)/(S(2)*c*d - e*(b + q)) - e*x**S(2)*(b**S(2)*e**S(2) + c**S(2)*d**S(2) - S(2)*c*e*(-a*e + b*d)) + (-b*e + c*d)*(S(2)*a*e**S(2) - b*d*e + c*d**S(2)), x)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) - Dist((a*e**S(2) - b*d*e + c*d**S(2))**S(2)/(e**S(3)*(S(2)*c*d - e*(b + q))), Int((b + S(2)*c*x**S(2) + q)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) def With1252(a, c, d, e, x): q = Rt(-a*c, S(2)) return -Dist(c/e**S(4), Int(Simp(c*d*e**S(2)*x**S(4) - c*e**S(3)*x**S(6) + d*(S(2)*a*e**S(2) + c*d**S(2)) - e*x**S(2)*(S(2)*a*e**S(2) + c*d**S(2)) - (a*e**S(2) + c*d**S(2))**S(2)/(c*d - e*q), x)/sqrt(a + c*x**S(4)), x), x) - Dist((a*e**S(2) + c*d**S(2))**S(2)/(e**S(3)*(c*d - e*q)), Int((c*x**S(2) + q)/(sqrt(a + c*x**S(4))*(d + e*x**S(2))), x), x) def replacement1253(a, b, c, d, e, p, x): return Dist(a, Int((a + b*x**S(2) + c*x**S(4))**(p + S(-1))/(d + e*x**S(2)), x), x) + Dist(b, Int(x**S(2)*(a + b*x**S(2) + c*x**S(4))**(p + S(-1))/(d + e*x**S(2)), x), x) + Dist(c, Int(x**S(4)*(a + b*x**S(2) + c*x**S(4))**(p + S(-1))/(d + e*x**S(2)), x), x) def replacement1254(a, c, d, e, p, x): return Dist(a, Int((a + c*x**S(4))**(p + S(-1))/(d + e*x**S(2)), x), x) + Dist(c, Int(x**S(4)*(a + c*x**S(4))**(p + S(-1))/(d + e*x**S(2)), x), x) def With1255(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*sqrt(-c), Int(S(1)/((d + e*x**S(2))*sqrt(-b - S(2)*c*x**S(2) + q)*sqrt(b + S(2)*c*x**S(2) + q)), x), x) def With1256(a, c, d, e, x): q = Rt(-a*c, S(2)) return Dist(sqrt(-c), Int(S(1)/((d + e*x**S(2))*sqrt(-c*x**S(2) + q)*sqrt(c*x**S(2) + q)), x), x) def With1257(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/(S(2)*c*d - e*(b - q)), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) - Dist(e/(S(2)*c*d - e*(b - q)), Int((b + S(2)*c*x**S(2) - q)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) def With1258(a, c, d, e, x): q = Rt(-a*c, S(2)) return Dist(c/(c*d + e*q), Int(S(1)/sqrt(a + c*x**S(4)), x), x) + Dist(e/(c*d + e*q), Int((-c*x**S(2) + q)/(sqrt(a + c*x**S(4))*(d + e*x**S(2))), x), x) def With1259(a, b, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(4)) if NonzeroQ(-d*q**S(2) + e): return True return False def replacement1259(a, b, c, d, e, x): q = Rt(c/a, S(4)) return -Dist(q**S(2)/(-d*q**S(2) + e), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Simp(ArcTan(x*sqrt((a*e**S(2) - b*d*e + c*d**S(2))/(d*e))/sqrt(a + b*x**S(2) + c*x**S(4)))/(S(2)*d*sqrt((a*e**S(2) - b*d*e + c*d**S(2))/(d*e))), x) + Simp(sqrt((a + b*x**S(2) + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(d*q**S(2) + e)*(q**S(2)*x**S(2) + S(1))*EllipticPi(-(-d*q**S(2) + e)**S(2)/(S(4)*d*e*q**S(2)), S(2)*ArcTan(q*x), -b*q**S(2)/(S(4)*c) + S(1)/2)/(S(4)*d*q*(-d*q**S(2) + e)*sqrt(a + b*x**S(2) + c*x**S(4))), x) def With1260(a, c, d, e, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(c/a, S(4)) if NonzeroQ(-d*q**S(2) + e): return True return False def replacement1260(a, c, d, e, x): q = Rt(c/a, S(4)) return -Dist(q**S(2)/(-d*q**S(2) + e), Int(S(1)/sqrt(a + c*x**S(4)), x), x) + Simp(ArcTan(x*sqrt((a*e**S(2) + c*d**S(2))/(d*e))/sqrt(a + c*x**S(4)))/(S(2)*d*sqrt((a*e**S(2) + c*d**S(2))/(d*e))), x) + Simp(sqrt((a + c*x**S(4))/(a*(q**S(2)*x**S(2) + S(1))**S(2)))*(d*q**S(2) + e)*(q**S(2)*x**S(2) + S(1))*EllipticPi(-(-d*q**S(2) + e)**S(2)/(S(4)*d*e*q**S(2)), S(2)*ArcTan(q*x), S(1)/2)/(S(4)*d*q*sqrt(a + c*x**S(4))*(-d*q**S(2) + e)), x) def With1261(a, c, d, e, x): q = Rt(-c/a, S(4)) return Simp(EllipticPi(-e/(d*q**S(2)), asin(q*x), S(-1))/(sqrt(a)*d*q), x) def replacement1262(a, c, d, e, x): return Dist(sqrt(S(1) + c*x**S(4)/a)/sqrt(a + c*x**S(4)), Int(S(1)/(sqrt(S(1) + c*x**S(4)/a)*(d + e*x**S(2))), x), x) def With1263(a, b, c, d, e, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))/sqrt(a + b*x**S(2) + c*x**S(4)), Int(S(1)/((d + e*x**S(2))*sqrt(S(2)*c*x**S(2)/(b - q) + S(1))*sqrt(S(2)*c*x**S(2)/(b + q) + S(1))), x), x) def replacement1264(a, b, c, d, e, p, x): return -Dist(S(1)/(S(2)*a*(p + S(1))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), Int((a + b*x**S(2) + c*x**S(4))**(p + S(1))*Simp(-a*b*c*d*e*(S(8)*p + S(11)) + S(2)*a*c*(S(4)*a*e**S(2)*(p + S(1)) + c*d**S(2)*(S(4)*p + S(5))) + b**S(3)*d*e*(S(2)*p + S(3)) - b**S(2)*(S(2)*a*e**S(2)*(p + S(1)) + c*d**S(2)*(S(2)*p + S(3))) - c*e*x**S(4)*(S(4)*p + S(7))*(S(2)*a*c*e - b**S(2)*e + b*c*d) - x**S(2)*(S(4)*a*c**S(2)*d*e - b**S(3)*e**S(2)*(S(2)*p + S(3)) - S(2)*b**S(2)*c*d*e*(p + S(2)) + b*c*(a*e**S(2)*(S(8)*p + S(11)) + c*d**S(2)*(S(4)*p + S(7)))), x)/(d + e*x**S(2)), x), x) - Simp(x*(a + b*x**S(2) + c*x**S(4))**(p + S(1))*(S(3)*a*b*c*e - S(2)*a*c**S(2)*d - b**S(3)*e + b**S(2)*c*d + c*x**S(2)*(S(2)*a*c*e - b**S(2)*e + b*c*d))/(S(2)*a*(p + S(1))*(-S(4)*a*c + b**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement1265(a, c, d, e, p, x): return -Dist(-S(1)/(S(8)*a**S(2)*c*(p + S(1))*(a*e**S(2) + c*d**S(2))), Int((a + c*x**S(4))**(p + S(1))*Simp(-S(4)*a*c**S(2)*d*e*x**S(2) - S(2)*a*c**S(2)*e**S(2)*x**S(4)*(S(4)*p + S(7)) + S(2)*a*c*(S(4)*a*e**S(2)*(p + S(1)) + c*d**S(2)*(S(4)*p + S(5))), x)/(d + e*x**S(2)), x), x) - Simp(-x*(a + c*x**S(4))**(p + S(1))*(-S(2)*a*c**S(2)*d + S(2)*a*c**S(2)*e*x**S(2))/(S(8)*a**S(2)*c*(p + S(1))*(a*e**S(2) + c*d**S(2))), x) def replacement1266(a, b, c, d, e, x): return -Dist(c/(S(2)*d*(a*e**S(2) - b*d*e + c*d**S(2))), Int((d + e*x**S(2))/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) + Dist((a*e**S(2) - S(2)*b*d*e + S(3)*c*d**S(2))/(S(2)*d*(a*e**S(2) - b*d*e + c*d**S(2))), Int(S(1)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) + Simp(e**S(2)*x*sqrt(a + b*x**S(2) + c*x**S(4))/(S(2)*d*(d + e*x**S(2))*(a*e**S(2) - b*d*e + c*d**S(2))), x) def replacement1267(a, c, d, e, x): return -Dist(c/(S(2)*d*(a*e**S(2) + c*d**S(2))), Int((d + e*x**S(2))/sqrt(a + c*x**S(4)), x), x) + Dist((a*e**S(2) + S(3)*c*d**S(2))/(S(2)*d*(a*e**S(2) + c*d**S(2))), Int(S(1)/(sqrt(a + c*x**S(4))*(d + e*x**S(2))), x), x) + Simp(e**S(2)*x*sqrt(a + c*x**S(4))/(S(2)*d*(d + e*x**S(2))*(a*e**S(2) + c*d**S(2))), x) def With1268(a, b, c, d, e, p, q, x): r = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(a**IntPart(p)*(S(2)*c*x**S(2)/(b - r) + S(1))**(-FracPart(p))*(S(2)*c*x**S(2)/(b + r) + S(1))**(-FracPart(p))*(a + b*x**S(2) + c*x**S(4))**FracPart(p), Int((d + e*x**S(2))**q*(S(2)*c*x**S(2)/(b - r) + S(1))**p*(S(2)*c*x**S(2)/(b + r) + S(1))**p, x), x) def With1269(a, c, d, e, p, q, x): r = Rt(-a*c, S(2)) return Dist(a**IntPart(p)*(a + c*x**S(4))**FracPart(p)*(-c*x**S(2)/r + S(1))**(-FracPart(p))*(c*x**S(2)/r + S(1))**(-FracPart(p)), Int((d + e*x**S(2))**q*(-c*x**S(2)/r + S(1))**p*(c*x**S(2)/r + S(1))**p, x), x) def replacement1270(a, b, c, d, e, x): return Simp(EllipticF(S(2)*asin(x*Rt(-e/d, S(2))), b*d/(S(4)*a*e))/(S(2)*sqrt(a)*sqrt(d)*Rt(-e/d, S(2))), x) def replacement1271(a, b, c, d, e, x): return Dist(sqrt((a + b*x**S(2) + c*x**S(4))/a)*sqrt((d + e*x**S(2))/d)/(sqrt(d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), Int(S(1)/(sqrt(S(1) + e*x**S(2)/d)*sqrt(S(1) + b*x**S(2)/a + c*x**S(4)/a)), x), x) def replacement1272(a, b, c, d, e, x): return Simp(sqrt(a)*EllipticE(S(2)*asin(x*Rt(-e/d, S(2))), b*d/(S(4)*a*e))/(S(2)*sqrt(d)*Rt(-e/d, S(2))), x) def replacement1273(a, b, c, d, e, x): return Dist(sqrt((d + e*x**S(2))/d)*sqrt(a + b*x**S(2) + c*x**S(4))/(sqrt((a + b*x**S(2) + c*x**S(4))/a)*sqrt(d + e*x**S(2))), Int(sqrt(S(1) + b*x**S(2)/a + c*x**S(4)/a)/sqrt(S(1) + e*x**S(2)/d), x), x) def replacement1274(a, b, c, d, e, n, n2, p, q, x): return Int(ExpandIntegrand((d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1275(a, c, d, e, n, n2, p, q, x): return Int(ExpandIntegrand((a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def replacement1276(a, c, d, e, n, n2, p, q, x): return Int(ExpandIntegrand((a + c*x**(S(2)*n))**p, (d/(d**S(2) - e**S(2)*x**(S(2)*n)) - e*x**n/(d**S(2) - e**S(2)*x**(S(2)*n)))**(-q), x), x) def replacement1277(a, b, c, d, e, n, n2, p, q, x): return Int((d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1278(a, c, d, e, n, n2, p, q, x): return Int((a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x) def replacement1279(a, b, c, d, e, n, n2, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x, u), x) def replacement1280(a, c, d, e, n, n2, p, q, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x, u), x) def replacement1281(a, b, c, d, e, mn, n, n2, p, q, x): return Int(x**(-n*q)*(d*x**n + e)**q*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1282(a, c, d, e, mn, n2, p, q, x): return Int(x**(mn*q)*(a + c*x**n2)**p*(d*x**(-mn) + e)**q, x) def replacement1283(a, b, c, d, e, mn, n, n2, p, q, x): return Int(x**(S(2)*n*p)*(d + e*x**(-n))**q*(a*x**(-S(2)*n) + b*x**(-n) + c)**p, x) def replacement1284(a, c, d, e, mn, n2, p, q, x): return Int(x**(-S(2)*mn*p)*(d + e*x**mn)**q*(a*x**(S(2)*mn) + c)**p, x) def replacement1285(a, b, c, d, e, mn, n, n2, p, q, x): return Dist(x**(n*FracPart(q))*(d + e*x**(-n))**FracPart(q)*(d*x**n + e)**(-FracPart(q)), Int(x**(-n*q)*(d*x**n + e)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1286(a, c, d, e, mn, n2, p, q, x): return Dist(x**(-mn*FracPart(q))*(d + e*x**mn)**FracPart(q)*(d*x**(-mn) + e)**(-FracPart(q)), Int(x**(mn*q)*(a + c*x**n2)**p*(d*x**(-mn) + e)**q, x), x) def replacement1287(a, b, c, d, e, mn, n, n2, p, q, x): return Dist(x**(-S(2)*n*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p)*(a*x**(-S(2)*n) + b*x**(-n) + c)**(-FracPart(p)), Int(x**(S(2)*n*p)*(d + e*x**(-n))**q*(a*x**(-S(2)*n) + b*x**(-n) + c)**p, x), x) def replacement1288(a, c, d, e, mn, n2, p, q, x): return Dist(x**(-n2*FracPart(p))*(a + c*x**n2)**FracPart(p)*(a*x**(S(2)*mn) + c)**(-FracPart(p)), Int(x**(n2*p)*(d + e*x**mn)**q*(a*x**(S(2)*mn) + c)**p, x), x) def replacement1289(a, b, c, d, e, mn, n, p, q, x): return Int(x**(-n*p)*(d + e*x**n)**q*(a*x**n + b + c*x**(S(2)*n))**p, x) def replacement1290(a, b, c, d, e, mn, n, p, q, x): return Dist(x**(n*FracPart(p))*(a + b*x**(-n) + c*x**n)**FracPart(p)*(a*x**n + b + c*x**(S(2)*n))**(-FracPart(p)), Int(x**(-n*p)*(d + e*x**n)**q*(a*x**n + b + c*x**(S(2)*n))**p, x), x) def replacement1291(a, b, c, d, e, f, g, n, n2, p, q, r, x): return Dist((S(4)*c)**(-IntPart(p))*(b + S(2)*c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((b + S(2)*c*x**n)**(S(2)*p)*(d + e*x**n)**q*(f + g*x**n)**r, x), x) def replacement1292(a, b, c, d, e, f, g, n, n2, p, q, r, x): return Int((d + e*x**n)**(p + q)*(f + g*x**n)**r*(a/d + c*x**n/e)**p, x) def replacement1293(a, c, d, e, f, g, n, n2, p, q, r, x): return Int((d + e*x**n)**(p + q)*(f + g*x**n)**r*(a/d + c*x**n/e)**p, x) def replacement1294(a, b, c, d, e, f, g, n, n2, p, q, r, x): return Dist((d + e*x**n)**(-FracPart(p))*(a/d + c*x**n/e)**(-FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((d + e*x**n)**(p + q)*(f + g*x**n)**r*(a/d + c*x**n/e)**p, x), x) def replacement1295(a, c, d, e, f, g, n, n2, p, q, r, x): return Dist((a + c*x**(S(2)*n))**FracPart(p)*(d + e*x**n)**(-FracPart(p))*(a/d + c*x**n/e)**(-FracPart(p)), Int((d + e*x**n)**(p + q)*(f + g*x**n)**r*(a/d + c*x**n/e)**p, x), x) def With1296(a, b, c, d, e, f, g, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-S(4)*a*c + b**S(2), S(2)) if NonzeroQ(S(2)*c*f - g*(b - q)): return True return False def replacement1296(a, b, c, d, e, f, g, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist((S(2)*c*f - g*(b - q))/(S(2)*c*d - e*(b - q)), Int(S(1)/sqrt(a + b*x**S(2) + c*x**S(4)), x), x) - Dist((-d*g + e*f)/(S(2)*c*d - e*(b - q)), Int((b + S(2)*c*x**S(2) - q)/((d + e*x**S(2))*sqrt(a + b*x**S(2) + c*x**S(4))), x), x) def With1297(a, c, d, e, f, g, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(-a*c, S(2)) if NonzeroQ(c*f + g*q): return True return False def replacement1297(a, c, d, e, f, g, x): q = Rt(-a*c, S(2)) return Dist((c*f + g*q)/(c*d + e*q), Int(S(1)/sqrt(a + c*x**S(4)), x), x) + Dist((-d*g + e*f)/(c*d + e*q), Int((-c*x**S(2) + q)/(sqrt(a + c*x**S(4))*(d + e*x**S(2))), x), x) def replacement1298(a, b, c, d1, d2, e1, e2, n, n2, non2, p, q, x): return Int((d1*d2 + e1*e2*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1299(a, b, c, d1, d2, e1, e2, n, n2, non2, p, q, x): return Dist((d1 + e1*x**(n/S(2)))**FracPart(q)*(d2 + e2*x**(n/S(2)))**FracPart(q)*(d1*d2 + e1*e2*x**n)**(-FracPart(q)), Int((d1*d2 + e1*e2*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1300(A, B, a, b, c, d, e, m, n, n2, p, q, x): return Dist(A, Int((d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) + Dist(B, Int(x**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1301(A, B, a, c, d, e, m, n, n2, p, q, x): return Dist(A, Int((a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) + Dist(B, Int(x**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def replacement1302(a, b, c, e, f, m, n, n2, p, q, x): return Dist(e**(S(1) - (m + S(1))/n)*f**m/n, Subst(Int((e*x)**(q + S(-1) + (m + S(1))/n)*(a + b*x + c*x**S(2))**p, x), x, x**n), x) def replacement1303(a, c, e, f, m, n, n2, p, q, x): return Dist(e**(S(1) - (m + S(1))/n)*f**m/n, Subst(Int((e*x)**(q + S(-1) + (m + S(1))/n)*(a + c*x**S(2))**p, x), x, x**n), x) def replacement1304(a, b, c, e, f, m, n, n2, p, q, x): return Dist(e**IntPart(q)*f**m*x**(-n*FracPart(q))*(e*x**n)**FracPart(q), Int(x**(m + n*q)*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1305(a, c, e, f, m, n, n2, p, q, x): return Dist(e**IntPart(q)*f**m*x**(-n*FracPart(q))*(e*x**n)**FracPart(q), Int(x**(m + n*q)*(a + c*x**(S(2)*n))**p, x), x) def replacement1306(a, b, c, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1307(a, c, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(e*x**n)**q*(a + c*x**(S(2)*n))**p, x), x) def replacement1308(a, b, c, d, e, m, n, n2, p, q, x): return Dist(S(1)/n, Subst(Int((d + e*x)**q*(a + b*x + c*x**S(2))**p, x), x, x**n), x) def replacement1309(a, c, d, e, m, n, n2, p, q, x): return Dist(S(1)/n, Subst(Int((a + c*x**S(2))**p*(d + e*x)**q, x), x, x**n), x) def replacement1310(a, b, c, d, e, m, n, n2, p, q, x): return Int(x**(m + n*(S(2)*p + q))*(d*x**(-n) + e)**q*(a*x**(-S(2)*n) + b*x**(-n) + c)**p, x) def replacement1311(a, c, d, e, m, n, n2, p, q, x): return Int(x**(m + n*(S(2)*p + q))*(a*x**(-S(2)*n) + c)**p*(d*x**(-n) + e)**q, x) def replacement1312(a, b, c, d, e, m, n, n2, p, q, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(d + e*x)**q*(a + b*x + c*x**S(2))**p, x), x, x**n), x) def replacement1313(a, b, c, d, e, f, m, n, n2, p, q, x): return Dist(c**(-IntPart(p))*(b/S(2) + c*x**n)**(-S(2)*FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((f*x)**m*(b/S(2) + c*x**n)**(S(2)*p)*(d + e*x**n)**q, x), x) def replacement1314(a, b, c, d, e, m, n, n2, p, q, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(d + e*x)**q*(a + b*x + c*x**S(2))**p, x), x, x**n), x) def replacement1315(a, c, d, e, m, n, n2, p, q, x): return Dist(S(1)/n, Subst(Int(x**(S(-1) + (m + S(1))/n)*(a + c*x**S(2))**p*(d + e*x)**q, x), x, x**n), x) def replacement1316(a, b, c, d, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1317(a, c, d, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def replacement1318(a, b, c, d, e, f, m, n, n2, p, q, x): return Int((f*x)**m*(d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x) def replacement1319(a, c, d, e, f, m, n, n2, p, q, x): return Int((f*x)**m*(d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x) def replacement1320(a, b, c, d, e, f, m, n, n2, p, q, x): return Dist((d + e*x**n)**(-FracPart(p))*(a/d + c*x**n/e)**(-FracPart(p))*(a + b*x**n + c*x**(S(2)*n))**FracPart(p), Int((f*x)**m*(d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x), x) def replacement1321(a, c, d, e, f, m, n, n2, p, q, x): return Dist((a + c*x**(S(2)*n))**FracPart(p)*(d + e*x**n)**(-FracPart(p))*(a/d + c*x**n/e)**(-FracPart(p)), Int((f*x)**m*(d + e*x**n)**(p + q)*(a/d + c*x**n/e)**p, x), x) def replacement1322(a, b, c, d, e, m, n, n2, p, q, x): return Dist(e**(-S(2)*p - (m - Mod(m, n))/n)/(n*(q + S(1))), Int(x**Mod(m, n)*(d + e*x**n)**(q + S(1))*ExpandToSum(Together((e**(S(2)*p + (m - Mod(m, n))/n)*n*x**(m - Mod(m, n))*(q + S(1))*(a + b*x**n + c*x**(S(2)*n))**p - (-d)**(S(-1) + (m - Mod(m, n))/n)*(d*(Mod(m, n) + S(1)) + e*x**n*(n*(q + S(1)) + Mod(m, n) + S(1)))*(a*e**S(2) - b*d*e + c*d**S(2))**p)/(d + e*x**n)), x), x), x) + Simp(e**(-S(2)*p - (m - Mod(m, n))/n)*x**(Mod(m, n) + S(1))*(-d)**(S(-1) + (m - Mod(m, n))/n)*(d + e*x**n)**(q + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))**p/(n*(q + S(1))), x) def replacement1323(a, c, d, e, m, n, n2, p, q, x): return Dist(e**(-S(2)*p - (m - Mod(m, n))/n)/(n*(q + S(1))), Int(x**Mod(m, n)*(d + e*x**n)**(q + S(1))*ExpandToSum(Together((e**(S(2)*p + (m - Mod(m, n))/n)*n*x**(m - Mod(m, n))*(a + c*x**(S(2)*n))**p*(q + S(1)) - (-d)**(S(-1) + (m - Mod(m, n))/n)*(a*e**S(2) + c*d**S(2))**p*(d*(Mod(m, n) + S(1)) + e*x**n*(n*(q + S(1)) + Mod(m, n) + S(1))))/(d + e*x**n)), x), x), x) + Simp(e**(-S(2)*p - (m - Mod(m, n))/n)*x**(Mod(m, n) + S(1))*(-d)**(S(-1) + (m - Mod(m, n))/n)*(d + e*x**n)**(q + S(1))*(a*e**S(2) + c*d**S(2))**p/(n*(q + S(1))), x) def replacement1324(a, b, c, d, e, m, n, n2, p, q, x): return Dist(e**(-S(2)*p)*(-d)**(S(-1) + (m - Mod(m, n))/n)/(n*(q + S(1))), Int(x**m*(d + e*x**n)**(q + S(1))*ExpandToSum(Together((e**(S(2)*p)*n*(-d)**(S(1) - (m - Mod(m, n))/n)*(q + S(1))*(a + b*x**n + c*x**(S(2)*n))**p - e**(-(m - Mod(m, n))/n)*x**(-m + Mod(m, n))*(d*(Mod(m, n) + S(1)) + e*x**n*(n*(q + S(1)) + Mod(m, n) + S(1)))*(a*e**S(2) - b*d*e + c*d**S(2))**p)/(d + e*x**n)), x), x), x) + Simp(e**(-S(2)*p - (m - Mod(m, n))/n)*x**(Mod(m, n) + S(1))*(-d)**(S(-1) + (m - Mod(m, n))/n)*(d + e*x**n)**(q + S(1))*(a*e**S(2) - b*d*e + c*d**S(2))**p/(n*(q + S(1))), x) def replacement1325(a, c, d, e, m, n, n2, p, q, x): return Dist(e**(-S(2)*p)*(-d)**(S(-1) + (m - Mod(m, n))/n)/(n*(q + S(1))), Int(x**m*(d + e*x**n)**(q + S(1))*ExpandToSum(Together((e**(S(2)*p)*n*(-d)**(S(1) - (m - Mod(m, n))/n)*(a + c*x**(S(2)*n))**p*(q + S(1)) - e**(-(m - Mod(m, n))/n)*x**(-m + Mod(m, n))*(a*e**S(2) + c*d**S(2))**p*(d*(Mod(m, n) + S(1)) + e*x**n*(n*(q + S(1)) + Mod(m, n) + S(1))))/(d + e*x**n)), x), x), x) + Simp(e**(-S(2)*p - (m - Mod(m, n))/n)*x**(Mod(m, n) + S(1))*(-d)**(S(-1) + (m - Mod(m, n))/n)*(d + e*x**n)**(q + S(1))*(a*e**S(2) + c*d**S(2))**p/(n*(q + S(1))), x) def replacement1326(a, b, c, d, e, f, m, n, n2, p, q, x): return Dist(S(1)/(e*(m + S(2)*n*p + n*q + S(1))), Int((f*x)**m*(d + e*x**n)**q*ExpandToSum(-c**p*d*x**(S(2)*n*p - n)*(m + S(2)*n*p - n + S(1)) + e*(-c**p*x**(S(2)*n*p) + (a + b*x**n + c*x**(S(2)*n))**p)*(m + S(2)*n*p + n*q + S(1)), x), x), x) + Simp(c**p*f**(-S(2)*n*p + n + S(-1))*(f*x)**(m + S(2)*n*p - n + S(1))*(d + e*x**n)**(q + S(1))/(e*(m + S(2)*n*p + n*q + S(1))), x) def replacement1327(a, c, d, e, f, m, n, n2, p, q, x): return Dist(S(1)/(e*(m + S(2)*n*p + n*q + S(1))), Int((f*x)**m*(d + e*x**n)**q*ExpandToSum(-c**p*d*x**(S(2)*n*p - n)*(m + S(2)*n*p - n + S(1)) + e*(-c**p*x**(S(2)*n*p) + (a + c*x**(S(2)*n))**p)*(m + S(2)*n*p + n*q + S(1)), x), x), x) + Simp(c**p*f**(-S(2)*n*p + n + S(-1))*(f*x)**(m + S(2)*n*p - n + S(1))*(d + e*x**n)**(q + S(1))/(e*(m + S(2)*n*p + n*q + S(1))), x) def replacement1328(a, b, c, d, e, f, m, n, n2, p, q, x): return Int(ExpandIntegrand((f*x)**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1329(a, c, d, e, f, m, n, n2, p, q, x): return Int(ExpandIntegrand((f*x)**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def With1330(a, b, c, d, e, m, n, n2, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False k = GCD(m + S(1), n) if Unequal(k, S(1)): return True return False def replacement1330(a, b, c, d, e, m, n, n2, p, q, x): k = GCD(m + S(1), n) return Dist(S(1)/k, Subst(Int(x**(S(-1) + (m + S(1))/k)*(d + e*x**(n/k))**q*(a + b*x**(n/k) + c*x**(S(2)*n/k))**p, x), x, x**k), x) def With1331(a, c, d, e, m, n, n2, p, q, x): if isinstance(x, (int, Integer, float, Float)): return False k = GCD(m + S(1), n) if Unequal(k, S(1)): return True return False def replacement1331(a, c, d, e, m, n, n2, p, q, x): k = GCD(m + S(1), n) return Dist(S(1)/k, Subst(Int(x**(S(-1) + (m + S(1))/k)*(a + c*x**(S(2)*n/k))**p*(d + e*x**(n/k))**q, x), x, x**k), x) def With1332(a, b, c, d, e, f, m, n, n2, p, q, x): k = Denominator(m) return Dist(k/f, Subst(Int(x**(k*(m + S(1)) + S(-1))*(d + e*f**(-n)*x**(k*n))**q*(a + b*f**(-n)*x**(k*n) + c*f**(-S(2)*n)*x**(S(2)*k*n))**p, x), x, (f*x)**(S(1)/k)), x) def With1333(a, c, d, e, f, m, n, n2, p, q, x): k = Denominator(m) return Dist(k/f, Subst(Int(x**(k*(m + S(1)) + S(-1))*(a + c*x**(S(2)*k*n)/f)**p*(d + e*x**(k*n)/f)**q, x), x, (f*x)**(S(1)/k)), x) def replacement1334(a, b, c, d, e, f, m, n, n2, p, x): return Dist(f**(-n)*n*p/((m + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), Int((f*x)**(m + n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))*Simp(S(2)*a*e*(m + S(1)) - b*d*(m + n*(S(2)*p + S(1)) + S(1)) + x**n*(b*e*(m + S(1)) - S(2)*c*d*(m + n*(S(2)*p + S(1)) + S(1))), x), x), x) + Simp((f*x)**(m + S(1))*(d*(m + n*(S(2)*p + S(1)) + S(1)) + e*x**n*(m + S(1)))*(a + b*x**n + c*x**(S(2)*n))**p/(f*(m + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), x) def replacement1335(a, c, d, e, f, m, n, n2, p, x): return Dist(S(2)*f**(-n)*n*p/((m + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), Int((f*x)**(m + n)*(a + c*x**(S(2)*n))**(p + S(-1))*(a*e*(m + S(1)) - c*d*x**n*(m + n*(S(2)*p + S(1)) + S(1))), x), x) + Simp((f*x)**(m + S(1))*(a + c*x**(S(2)*n))**p*(d*(m + n*(S(2)*p + S(1)) + S(1)) + e*x**n*(m + S(1)))/(f*(m + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), x) def replacement1336(a, b, c, d, e, f, m, n, n2, p, x): return Dist(n*p/(c*(m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), Int((f*x)**m*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))*Simp(-a*b*e*(m + S(1)) + S(2)*a*c*d*(m + n*(S(2)*p + S(1)) + S(1)) + x**n*(S(2)*a*c*e*(m + S(2)*n*p + S(1)) - b**S(2)*e*(m + n*p + S(1)) + b*c*d*(m + n*(S(2)*p + S(1)) + S(1))), x), x), x) + Simp((f*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**p*(b*e*n*p + c*d*(m + n*(S(2)*p + S(1)) + S(1)) + c*e*x**n*(m + S(2)*n*p + S(1)))/(c*f*(m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), x) def replacement1337(a, c, d, e, f, m, n, n2, p, x): return Dist(S(2)*a*n*p/((m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), Int((f*x)**m*(a + c*x**(S(2)*n))**(p + S(-1))*Simp(d*(m + n*(S(2)*p + S(1)) + S(1)) + e*x**n*(m + S(2)*n*p + S(1)), x), x), x) + Simp((f*x)**(m + S(1))*(a + c*x**(S(2)*n))**p*(c*d*(m + n*(S(2)*p + S(1)) + S(1)) + c*e*x**n*(m + S(2)*n*p + S(1)))/(c*f*(m + S(2)*n*p + S(1))*(m + n*(S(2)*p + S(1)) + S(1))), x) def replacement1338(a, b, c, d, e, f, m, n, n2, p, x): return Dist(f**n/(n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((f*x)**(m - n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(x**n*(b*e - S(2)*c*d)*(m + S(2)*n*p + S(2)*n + S(1)) + (-S(2)*a*e + b*d)*(-m + n + S(-1)), x), x), x) + Simp(f**(n + S(-1))*(f*x)**(m - n + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-S(2)*a*e + b*d - x**n*(b*e - S(2)*c*d))/(n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1339(a, c, d, e, f, m, n, n2, p, x): return Dist(f**n/(S(2)*a*c*n*(p + S(1))), Int((f*x)**(m - n)*(a + c*x**(S(2)*n))**(p + S(1))*(a*e*(-m + n + S(-1)) + c*d*x**n*(m + S(2)*n*p + S(2)*n + S(1))), x), x) + Simp(f**(n + S(-1))*(f*x)**(m - n + S(1))*(a + c*x**(S(2)*n))**(p + S(1))*(a*e - c*d*x**n)/(S(2)*a*c*n*(p + S(1))), x) def replacement1340(a, b, c, d, e, f, m, n, n2, p, x): return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((f*x)**m*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(-a*b*e*(m + S(1)) + c*x**n*(-S(2)*a*e + b*d)*(m + n*(S(2)*p + S(3)) + S(1)) + d*(-S(2)*a*c*(m + S(2)*n*(p + S(1)) + S(1)) + b**S(2)*(m + n*(p + S(1)) + S(1))), x), x), x) - Simp((f*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a*b*e + c*x**n*(-S(2)*a*e + b*d) + d*(-S(2)*a*c + b**S(2)))/(a*f*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1341(a, c, d, e, f, m, n, n2, p, x): return Dist(S(1)/(S(2)*a*n*(p + S(1))), Int((f*x)**m*(a + c*x**(S(2)*n))**(p + S(1))*Simp(d*(m + S(2)*n*(p + S(1)) + S(1)) + e*x**n*(m + n*(S(2)*p + S(3)) + S(1)), x), x), x) - Simp((f*x)**(m + S(1))*(a + c*x**(S(2)*n))**(p + S(1))*(d + e*x**n)/(S(2)*a*f*n*(p + S(1))), x) def replacement1342(a, b, c, d, e, f, m, n, n2, p, x): return -Dist(f**n/(c*(m + n*(S(2)*p + S(1)) + S(1))), Int((f*x)**(m - n)*(a + b*x**n + c*x**(S(2)*n))**p*Simp(a*e*(m - n + S(1)) + x**n*(b*e*(m + n*p + S(1)) - c*d*(m + n*(S(2)*p + S(1)) + S(1))), x), x), x) + Simp(e*f**(n + S(-1))*(f*x)**(m - n + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(c*(m + n*(S(2)*p + S(1)) + S(1))), x) def replacement1343(a, c, d, e, f, m, n, n2, p, x): return -Dist(f**n/(c*(m + n*(S(2)*p + S(1)) + S(1))), Int((f*x)**(m - n)*(a + c*x**(S(2)*n))**p*(a*e*(m - n + S(1)) - c*d*x**n*(m + n*(S(2)*p + S(1)) + S(1))), x), x) + Simp(e*f**(n + S(-1))*(f*x)**(m - n + S(1))*(a + c*x**(S(2)*n))**(p + S(1))/(c*(m + n*(S(2)*p + S(1)) + S(1))), x) def replacement1344(a, b, c, d, e, f, m, n, n2, p, x): return Dist(f**(-n)/(a*(m + S(1))), Int((f*x)**(m + n)*(a + b*x**n + c*x**(S(2)*n))**p*Simp(a*e*(m + S(1)) - b*d*(m + n*(p + S(1)) + S(1)) - c*d*x**n*(m + S(2)*n*(p + S(1)) + S(1)), x), x), x) + Simp(d*(f*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(a*f*(m + S(1))), x) def replacement1345(a, c, d, e, f, m, n, n2, p, x): return Dist(f**(-n)/(a*(m + S(1))), Int((f*x)**(m + n)*(a + c*x**(S(2)*n))**p*(a*e*(m + S(1)) - c*d*x**n*(m + S(2)*n*(p + S(1)) + S(1))), x), x) + Simp(d*(f*x)**(m + S(1))*(a + c*x**(S(2)*n))**(p + S(1))/(a*f*(m + S(1))), x) def With1346(a, b, c, d, e, f, m, n, n2, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(a*c, S(2)) r = Rt(-b*c + S(2)*c*q, S(2)) if Not(NegativeQ(-b*c + S(2)*c*q)): return True return False def replacement1346(a, b, c, d, e, f, m, n, n2, x): q = Rt(a*c, S(2)) r = Rt(-b*c + S(2)*c*q, S(2)) return Dist(c/(2*q*r), Int((f*x)**m*Simp(d*r - x**(n/2)*(c*d - e*q), x)/(c*x**n + q - r*x**(n/2)), x), x) + Dist(c/(2*q*r), Int((f*x)**m*Simp(d*r + x**(n/2)*(c*d - e*q), x)/(c*x**n + q + r*x**(n/2)), x), x) def With1347(a, c, d, e, f, m, n, n2, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(a*c, S(2)) r = Rt(S(2)*c*q, S(2)) if Not(NegativeQ(S(2)*c*q)): return True return False def replacement1347(a, c, d, e, f, m, n, n2, x): q = Rt(a*c, S(2)) r = Rt(S(2)*c*q, S(2)) return Dist(c/(2*q*r), Int((f*x)**m*Simp(d*r - x**(n/2)*(c*d - e*q), x)/(c*x**n + q - r*x**(n/2)), x), x) + Dist(c/(2*q*r), Int((f*x)**m*Simp(d*r + x**(n/2)*(c*d - e*q), x)/(c*x**n + q + r*x**(n/2)), x), x) def With1348(a, b, c, d, e, f, m, x): r = Rt(c*(-b*e + S(2)*c*d)/e, S(2)) return Dist(e/S(2), Int((f*x)**m/(c*d/e + c*x**S(2) - r*x), x), x) + Dist(e/S(2), Int((f*x)**m/(c*d/e + c*x**S(2) + r*x), x), x) def With1349(a, c, d, e, f, m, x): r = Rt(S(2)*c**S(2)*d/e, S(2)) return Dist(e/S(2), Int((f*x)**m/(c*d/e + c*x**S(2) - r*x), x), x) + Dist(e/S(2), Int((f*x)**m/(c*d/e + c*x**S(2) + r*x), x), x) def With1350(a, b, c, d, e, f, m, n, n2, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(a*c, S(2)) r = Rt(-b*c + S(2)*c*q, S(2)) if Not(NegativeQ(-b*c + S(2)*c*q)): return True return False def replacement1350(a, b, c, d, e, f, m, n, n2, x): q = Rt(a*c, S(2)) r = Rt(-b*c + S(2)*c*q, S(2)) return Dist(c/(2*q*r), Int((f*x)**m*(d*r - x**(n/2)*(c*d - e*q))/(c*x**n + q - r*x**(n/2)), x), x) + Dist(c/(2*q*r), Int((f*x)**m*(d*r + x**(n/2)*(c*d - e*q))/(c*x**n + q + r*x**(n/2)), x), x) def With1351(a, c, d, e, f, m, n, n2, x): if isinstance(x, (int, Integer, float, Float)): return False q = Rt(a*c, S(2)) r = Rt(S(2)*c*q, S(2)) if Not(NegativeQ(S(2)*c*q)): return True return False def replacement1351(a, c, d, e, f, m, n, n2, x): q = Rt(a*c, S(2)) r = Rt(S(2)*c*q, S(2)) return Dist(c/(2*q*r), Int((f*x)**m*(d*r - x**(n/2)*(c*d - e*q))/(c*x**n + q - r*x**(n/2)), x), x) + Dist(c/(2*q*r), Int((f*x)**m*(d*r + x**(n/2)*(c*d - e*q))/(c*x**n + q + r*x**(n/2)), x), x) def With1352(a, b, c, d, e, f, m, n, n2, x): q = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(e/S(2) - (-b*e + S(2)*c*d)/(S(2)*q), Int((f*x)**m/(b/S(2) + c*x**n + q/S(2)), x), x) + Dist(e/S(2) + (-b*e + S(2)*c*d)/(S(2)*q), Int((f*x)**m/(b/S(2) + c*x**n - q/S(2)), x), x) def With1353(a, c, d, e, f, m, n, n2, x): q = Rt(-a*c, S(2)) return Dist(-c*d/(S(2)*q) + e/S(2), Int((f*x)**m/(c*x**n + q), x), x) - Dist(c*d/(S(2)*q) + e/S(2), Int((f*x)**m/(-c*x**n + q), x), x) def replacement1354(a, b, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((f*x)**m*(d + e*x**n)**q/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1355(a, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((f*x)**m*(d + e*x**n)**q/(a + c*x**(S(2)*n)), x), x) def replacement1356(a, b, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((f*x)**m, (d + e*x**n)**q/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1357(a, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((f*x)**m, (d + e*x**n)**q/(a + c*x**(S(2)*n)), x), x) def replacement1358(a, b, c, d, e, f, m, n, n2, q, x): return Dist(f**(S(2)*n)/c**S(2), Int((f*x)**(m - S(2)*n)*(d + e*x**n)**(q + S(-1))*(-b*e + c*d + c*e*x**n), x), x) - Dist(f**(S(2)*n)/c**S(2), Int((f*x)**(m - S(2)*n)*(d + e*x**n)**(q + S(-1))*Simp(a*(-b*e + c*d) + x**n*(a*c*e - b**S(2)*e + b*c*d), x)/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1359(a, c, d, e, f, m, n, n2, q, x): return Dist(f**(S(2)*n)/c, Int((f*x)**(m - S(2)*n)*(d + e*x**n)**q, x), x) - Dist(a*f**(S(2)*n)/c, Int((f*x)**(m - S(2)*n)*(d + e*x**n)**q/(a + c*x**(S(2)*n)), x), x) def replacement1360(a, b, c, d, e, f, m, n, n2, q, x): return -Dist(f**n/c, Int((f*x)**(m - n)*(d + e*x**n)**(q + S(-1))*Simp(a*e - x**n*(-b*e + c*d), x)/(a + b*x**n + c*x**(S(2)*n)), x), x) + Dist(e*f**n/c, Int((f*x)**(m - n)*(d + e*x**n)**(q + S(-1)), x), x) def replacement1361(a, c, d, e, f, m, n, n2, q, x): return -Dist(f**n/c, Int((f*x)**(m - n)*(d + e*x**n)**(q + S(-1))*Simp(a*e - c*d*x**n, x)/(a + c*x**(S(2)*n)), x), x) + Dist(e*f**n/c, Int((f*x)**(m - n)*(d + e*x**n)**(q + S(-1)), x), x) def replacement1362(a, b, c, d, e, f, m, n, n2, q, x): return Dist(d/a, Int((f*x)**m*(d + e*x**n)**(q + S(-1)), x), x) - Dist(f**(-n)/a, Int((f*x)**(m + n)*(d + e*x**n)**(q + S(-1))*Simp(-a*e + b*d + c*d*x**n, x)/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1363(a, c, d, e, f, m, n, n2, q, x): return Dist(d/a, Int((f*x)**m*(d + e*x**n)**(q + S(-1)), x), x) + Dist(f**(-n)/a, Int((f*x)**(m + n)*(d + e*x**n)**(q + S(-1))*Simp(a*e - c*d*x**n, x)/(a + c*x**(S(2)*n)), x), x) def replacement1364(a, b, c, d, e, f, m, n, n2, q, x): return -Dist(f**(S(2)*n)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(d + e*x**n)**(q + S(1))*Simp(a*d + x**n*(-a*e + b*d), x)/(a + b*x**n + c*x**(S(2)*n)), x), x) + Dist(d**S(2)*f**(S(2)*n)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(d + e*x**n)**q, x), x) def replacement1365(a, c, d, e, f, m, n, n2, q, x): return -Dist(a*f**(S(2)*n)/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(d - e*x**n)*(d + e*x**n)**(q + S(1))/(a + c*x**(S(2)*n)), x), x) + Dist(d**S(2)*f**(S(2)*n)/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(d + e*x**n)**q, x), x) def replacement1366(a, b, c, d, e, f, m, n, n2, q, x): return Dist(f**n/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - n)*(d + e*x**n)**(q + S(1))*Simp(a*e + c*d*x**n, x)/(a + b*x**n + c*x**(S(2)*n)), x), x) - Dist(d*e*f**n/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - n)*(d + e*x**n)**q, x), x) def replacement1367(a, c, d, e, f, m, n, n2, q, x): return Dist(f**n/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - n)*(d + e*x**n)**(q + S(1))*Simp(a*e + c*d*x**n, x)/(a + c*x**(S(2)*n)), x), x) - Dist(d*e*f**n/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - n)*(d + e*x**n)**q, x), x) def replacement1368(a, b, c, d, e, f, m, n, n2, q, x): return Dist(e**S(2)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**m*(d + e*x**n)**q, x), x) + Dist(S(1)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**m*(d + e*x**n)**(q + S(1))*Simp(-b*e + c*d - c*e*x**n, x)/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1369(a, c, d, e, f, m, n, n2, q, x): return Dist(c/(a*e**S(2) + c*d**S(2)), Int((f*x)**m*(d - e*x**n)*(d + e*x**n)**(q + S(1))/(a + c*x**(S(2)*n)), x), x) + Dist(e**S(2)/(a*e**S(2) + c*d**S(2)), Int((f*x)**m*(d + e*x**n)**q, x), x) def replacement1370(a, b, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((d + e*x**n)**q, (f*x)**m/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1371(a, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((d + e*x**n)**q, (f*x)**m/(a + c*x**(S(2)*n)), x), x) def replacement1372(a, b, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((f*x)**m*(d + e*x**n)**q, S(1)/(a + b*x**n + c*x**(S(2)*n)), x), x) def replacement1373(a, c, d, e, f, m, n, n2, q, x): return Int(ExpandIntegrand((f*x)**m*(d + e*x**n)**q, S(1)/(a + c*x**(S(2)*n)), x), x) def replacement1374(a, b, c, d, e, f, m, n, n2, p, x): return Dist(d**(S(-2)), Int((f*x)**m*(a*d + x**n*(-a*e + b*d))*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) + Dist(f**(-S(2)*n)*(a*e**S(2) - b*d*e + c*d**S(2))/d**S(2), Int((f*x)**(m + S(2)*n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/(d + e*x**n), x), x) def replacement1375(a, c, d, e, f, m, n, n2, p, x): return Dist(a/d**S(2), Int((f*x)**m*(a + c*x**(S(2)*n))**(p + S(-1))*(d - e*x**n), x), x) + Dist(f**(-S(2)*n)*(a*e**S(2) + c*d**S(2))/d**S(2), Int((f*x)**(m + S(2)*n)*(a + c*x**(S(2)*n))**(p + S(-1))/(d + e*x**n), x), x) def replacement1376(a, b, c, d, e, f, m, n, n2, p, x): return Dist(S(1)/(d*e), Int((f*x)**m*(a*e + c*d*x**n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1)), x), x) - Dist(f**(-n)*(a*e**S(2) - b*d*e + c*d**S(2))/(d*e), Int((f*x)**(m + n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(-1))/(d + e*x**n), x), x) def replacement1377(a, c, d, e, f, m, n, n2, p, x): return Dist(S(1)/(d*e), Int((f*x)**m*(a + c*x**(S(2)*n))**(p + S(-1))*(a*e + c*d*x**n), x), x) - Dist(f**(-n)*(a*e**S(2) + c*d**S(2))/(d*e), Int((f*x)**(m + n)*(a + c*x**(S(2)*n))**(p + S(-1))/(d + e*x**n), x), x) def replacement1378(a, b, c, d, e, f, m, n, n2, p, x): return -Dist(f**(S(2)*n)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(a*d + x**n*(-a*e + b*d))*(a + b*x**n + c*x**(S(2)*n))**p, x), x) + Dist(d**S(2)*f**(S(2)*n)/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(d + e*x**n), x), x) def replacement1379(a, c, d, e, f, m, n, n2, p, x): return -Dist(a*f**(S(2)*n)/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(a + c*x**(S(2)*n))**p*(d - e*x**n), x), x) + Dist(d**S(2)*f**(S(2)*n)/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - S(2)*n)*(a + c*x**(S(2)*n))**(p + S(1))/(d + e*x**n), x), x) def replacement1380(a, b, c, d, e, f, m, n, n2, p, x): return Dist(f**n/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - n)*(a*e + c*d*x**n)*(a + b*x**n + c*x**(S(2)*n))**p, x), x) - Dist(d*e*f**n/(a*e**S(2) - b*d*e + c*d**S(2)), Int((f*x)**(m - n)*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))/(d + e*x**n), x), x) def replacement1381(a, c, d, e, f, m, n, n2, p, x): return Dist(f**n/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - n)*(a + c*x**(S(2)*n))**p*(a*e + c*d*x**n), x), x) - Dist(d*e*f**n/(a*e**S(2) + c*d**S(2)), Int((f*x)**(m - n)*(a + c*x**(S(2)*n))**(p + S(1))/(d + e*x**n), x), x) def replacement1382(a, b, c, d, e, f, m, n, n2, p, q, x): return Int(ExpandIntegrand((a + b*x**n + c*x**(S(2)*n))**p, (f*x)**m*(d + e*x**n)**q, x), x) def replacement1383(a, c, d, e, f, m, n, n2, p, q, x): return Int(ExpandIntegrand((a + c*x**(S(2)*n))**p, (f*x)**m*(d + e*x**n)**q, x), x) def replacement1384(a, b, c, d, e, m, n, n2, p, q, x): return -Subst(Int(x**(-m + S(-2))*(d + e*x**(-n))**q*(a + b*x**(-n) + c*x**(-S(2)*n))**p, x), x, S(1)/x) def replacement1385(a, c, d, e, m, n, n2, p, q, x): return -Subst(Int(x**(-m + S(-2))*(a + c*x**(-S(2)*n))**p*(d + e*x**(-n))**q, x), x, S(1)/x) def With1386(a, b, c, d, e, f, m, n, n2, p, q, x): g = Denominator(m) return -Dist(g/f, Subst(Int(x**(-g*(m + S(1)) + S(-1))*(d + e*f**(-n)*x**(-g*n))**q*(a + b*f**(-n)*x**(-g*n) + c*f**(-S(2)*n)*x**(-S(2)*g*n))**p, x), x, (f*x)**(-S(1)/g)), x) def With1387(a, c, d, e, f, m, n, n2, p, q, x): g = Denominator(m) return -Dist(g/f, Subst(Int(x**(-g*(m + S(1)) + S(-1))*(a + c*f**(-S(2)*n)*x**(-S(2)*g*n))**p*(d + e*f**(-n)*x**(-g*n))**q, x), x, (f*x)**(-S(1)/g)), x) def replacement1388(a, b, c, d, e, f, m, n, n2, p, q, x): return -Dist(f**IntPart(m)*(f*x)**FracPart(m)*(S(1)/x)**FracPart(m), Subst(Int(x**(-m + S(-2))*(d + e*x**(-n))**q*(a + b*x**(-n) + c*x**(-S(2)*n))**p, x), x, S(1)/x), x) def replacement1389(a, c, d, e, f, m, n, n2, p, q, x): return -Dist(f**IntPart(m)*(f*x)**FracPart(m)*(S(1)/x)**FracPart(m), Subst(Int(x**(-m + S(-2))*(a + c*x**(-S(2)*n))**p*(d + e*x**(-n))**q, x), x, S(1)/x), x) def With1390(a, b, c, d, e, m, n, n2, p, q, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g*(m + S(1)) + S(-1))*(d + e*x**(g*n))**q*(a + b*x**(g*n) + c*x**(S(2)*g*n))**p, x), x, x**(S(1)/g)), x) def With1391(a, c, d, e, m, n, n2, p, q, x): g = Denominator(n) return Dist(g, Subst(Int(x**(g*(m + S(1)) + S(-1))*(a + c*x**(S(2)*g*n))**p*(d + e*x**(g*n))**q, x), x, x**(S(1)/g)), x) def replacement1392(a, b, c, d, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1393(a, c, d, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def replacement1394(a, b, c, d, e, m, n, n2, p, q, x): return Dist(S(1)/(m + S(1)), Subst(Int((d + e*x**(n/(m + S(1))))**q*(a + b*x**(n/(m + S(1))) + c*x**(S(2)*n/(m + S(1))))**p, x), x, x**(m + S(1))), x) def replacement1395(a, c, d, e, m, n, n2, p, q, x): return Dist(S(1)/(m + S(1)), Subst(Int((a + c*x**(S(2)*n/(m + S(1))))**p*(d + e*x**(n/(m + S(1))))**q, x), x, x**(m + S(1))), x) def replacement1396(a, b, c, d, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1397(a, c, d, e, f, m, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def With1398(a, b, c, d, e, f, m, n, n2, q, x): r = Rt(-S(4)*a*c + b**S(2), S(2)) return Dist(S(2)*c/r, Int((f*x)**m*(d + e*x**n)**q/(b + S(2)*c*x**n - r), x), x) - Dist(S(2)*c/r, Int((f*x)**m*(d + e*x**n)**q/(b + S(2)*c*x**n + r), x), x) def With1399(a, c, d, e, f, m, n, n2, q, x): r = Rt(-a*c, S(2)) return -Dist(c/(S(2)*r), Int((f*x)**m*(d + e*x**n)**q/(-c*x**n + r), x), x) - Dist(c/(S(2)*r), Int((f*x)**m*(d + e*x**n)**q/(c*x**n + r), x), x) def replacement1400(a, b, c, d, e, f, m, n, n2, p, x): return Dist(S(1)/(a*n*(p + S(1))*(-S(4)*a*c + b**S(2))), Int((f*x)**m*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*Simp(-a*b*e*(m + S(1)) + c*x**n*(-S(2)*a*e + b*d)*(m + n*(S(2)*p + S(3)) + S(1)) + d*(-S(2)*a*c*(m + S(2)*n*(p + S(1)) + S(1)) + b**S(2)*(m + n*(p + S(1)) + S(1))), x), x), x) - Simp((f*x)**(m + S(1))*(a + b*x**n + c*x**(S(2)*n))**(p + S(1))*(-a*b*e + c*x**n*(-S(2)*a*e + b*d) + d*(-S(2)*a*c + b**S(2)))/(a*f*n*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1401(a, c, d, e, f, m, n, n2, p, x): return Dist(S(1)/(S(2)*a*n*(p + S(1))), Int((f*x)**m*(a + c*x**(S(2)*n))**(p + S(1))*Simp(d*(m + S(2)*n*(p + S(1)) + S(1)) + e*x**n*(m + n*(S(2)*p + S(3)) + S(1)), x), x), x) - Simp((f*x)**(m + S(1))*(a + c*x**(S(2)*n))**(p + S(1))*(d + e*x**n)/(S(2)*a*f*n*(p + S(1))), x) def replacement1402(a, b, c, d, e, f, m, n, n2, p, q, x): return Int(ExpandIntegrand((f*x)**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1403(a, c, d, e, f, m, n, n2, p, q, x): return Int(ExpandIntegrand((f*x)**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def replacement1404(a, c, d, e, f, m, n, n2, p, q, x): return Dist(f**m, Int(ExpandIntegrand(x**m*(a + c*x**(S(2)*n))**p, (d/(d**S(2) - e**S(2)*x**(S(2)*n)) - e*x**n/(d**S(2) - e**S(2)*x**(S(2)*n)))**(-q), x), x), x) def replacement1405(a, c, d, e, f, m, n, n2, p, q, x): return Dist(x**(-m)*(f*x)**m, Int(x**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x) def replacement1406(a, b, c, d, e, f, m, n, n2, p, q, x): return Int((f*x)**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1407(a, c, d, e, f, m, n, n2, p, q, x): return Int((f*x)**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x) def replacement1408(a, b, c, d, e, m, n, n2, p, q, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(d + e*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x, v), x) def replacement1409(a, c, d, e, m, n, n2, p, q, u, v, x): return Dist(u**m*v**(-m)/Coefficient(v, x, S(1)), Subst(Int(x**m*(a + c*x**(S(2)*n))**p*(d + e*x**n)**q, x), x, v), x) def replacement1410(a, b, c, d, e, m, mn, n, n2, p, q, x): return Int(x**(m - n*q)*(d*x**n + e)**q*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1411(a, c, d, e, m, mn, n2, p, q, x): return Int(x**(m + mn*q)*(a + c*x**n2)**p*(d*x**(-mn) + e)**q, x) def replacement1412(a, b, c, d, e, m, mn, n, n2, p, q, x): return Int(x**(m + S(2)*n*p)*(d + e*x**(-n))**q*(a*x**(-S(2)*n) + b*x**(-n) + c)**p, x) def replacement1413(a, c, d, e, m, mn, n2, p, q, x): return Int(x**(m - S(2)*mn*p)*(d + e*x**mn)**q*(a*x**(S(2)*mn) + c)**p, x) def replacement1414(a, b, c, d, e, m, mn, n, n2, p, q, x): return Dist(x**(n*FracPart(q))*(d + e*x**(-n))**FracPart(q)*(d*x**n + e)**(-FracPart(q)), Int(x**(m - n*q)*(d*x**n + e)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1415(a, c, d, e, m, mn, n2, p, q, x): return Dist(x**(-mn*FracPart(q))*(d + e*x**mn)**FracPart(q)*(d*x**(-mn) + e)**(-FracPart(q)), Int(x**(m + mn*q)*(a + c*x**n2)**p*(d*x**(-mn) + e)**q, x), x) def replacement1416(a, b, c, d, e, f, m, mn, n, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(d + e*x**mn)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1417(a, c, d, e, f, m, mn, n2, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(a + c*x**(S(2)*n))**p*(d + e*x**mn)**q, x), x) def replacement1418(a, b, c, d, e, m, mn, n, p, q, x): return Int(x**(m - n*p)*(d + e*x**n)**q*(a*x**n + b + c*x**(S(2)*n))**p, x) def replacement1419(a, b, c, d, e, m, mn, n, p, q, x): return Dist(x**(n*FracPart(p))*(a + b*x**(-n) + c*x**n)**FracPart(p)*(a*x**n + b + c*x**(S(2)*n))**(-FracPart(p)), Int(x**(m - n*p)*(d + e*x**n)**q*(a*x**n + b + c*x**(S(2)*n))**p, x), x) def replacement1420(a, b, c, d, e, f, m, mn, n, p, q, x): return Dist(f**IntPart(m)*x**(-FracPart(m))*(f*x)**FracPart(m), Int(x**m*(d + e*x**n)**q*(a + b*x**(-n) + c*x**n)**p, x), x) def replacement1421(a, b, c, d1, d2, e1, e2, f, m, n, n2, non2, p, q, x): return Int((f*x)**m*(d1*d2 + e1*e2*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x) def replacement1422(a, b, c, d1, d2, e1, e2, f, m, n, n2, non2, p, q, x): return Dist((d1 + e1*x**(n/S(2)))**FracPart(q)*(d2 + e2*x**(n/S(2)))**FracPart(q)*(d1*d2 + e1*e2*x**n)**(-FracPart(q)), Int((f*x)**m*(d1*d2 + e1*e2*x**n)**q*(a + b*x**n + c*x**(S(2)*n))**p, x), x) def replacement1423(a, b, c, n, p, q, r, x): return Int((x**n*(a + b + c))**p, x) def replacement1424(a, b, c, n, p, q, r, x): return Int(x**(p*q)*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**p, x) def replacement1425(a, b, c, n, q, r, x): return Dist(x**(-q/S(2))*sqrt(a*x**q + b*x**n + c*x**(S(2)*n - q))/sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q)), Int(x**(q/S(2))*sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q)), x), x) def replacement1426(a, b, c, n, q, r, x): return Dist(x**(q/S(2))*sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))/sqrt(a*x**q + b*x**n + c*x**(S(2)*n - q)), Int(x**(-q/S(2))/sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q)), x), x) def replacement1427(a, b, c, n, p, q, r, x): return Dist(p*(n - q)/(p*(S(2)*n - q) + S(1)), Int(x**q*(S(2)*a + b*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1)), x), x) + Simp(x*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p/(p*(S(2)*n - q) + S(1)), x) def replacement1428(a, b, c, n, p, q, r, x): return Dist(S(1)/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(-q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))*(b*c*x**(n - q)*(p*q + (n - q)*(S(2)*p + S(3)) + S(1)) + (n - q)*(p + S(1))*(-S(4)*a*c + b**S(2)) + (-S(2)*a*c + b**S(2))*(p*q + S(1))), x), x) - Simp(x**(S(1) - q)*(-S(2)*a*c + b**S(2) + b*c*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1429(a, b, c, n, p, q, r, x): return Dist(x**(-p*q)*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**(-p)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, Int(x**(p*q)*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**p, x), x) def replacement1430(a, b, c, n, p, q, r, x): return Int((a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x) def replacement1431(a, b, c, n, p, q, r, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x, u), x) def replacement1432(a, b, c, m, n, p, q, r, x): return Int(x**m*(x**n*(a + b + c))**p, x) def replacement1433(a, b, c, m, n, p, q, r, x): return Int(x**(m + p*q)*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**p, x) def replacement1434(a, b, c, m, n, q, r, x): return Dist(x**(q/S(2))*sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))/sqrt(a*x**q + b*x**n + c*x**(S(2)*n - q)), Int(x**(m - q/S(2))/sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q)), x), x) def replacement1435(a, b, c, m, n, q, r, x): return Simp(-S(2)*x**(n/S(2) + S(-1)/2)*(b + S(2)*c*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**(n + S(-1)) + b*x**n + c*x**(n + S(1)))), x) def replacement1436(a, b, c, m, n, q, r, x): return Simp(x**(n/S(2) + S(-1)/2)*(S(4)*a + S(2)*b*x)/((-S(4)*a*c + b**S(2))*sqrt(a*x**(n + S(-1)) + b*x**n + c*x**(n + S(1)))), x) def replacement1437(a, b, c, m, n, p, q, r, x): return -Dist(b/(S(2)*c), Int(x**(m + S(-1))*(a*x**(n + S(-1)) + b*x**n + c*x**(n + S(1)))**p, x), x) + Simp(x**(m - n)*(a*x**(n + S(-1)) + b*x**n + c*x**(n + S(1)))**(p + S(1))/(S(2)*c*(p + S(1))), x) def replacement1438(a, b, c, m, n, p, q, r, x): return -Dist(p*(-S(4)*a*c + b**S(2))/(S(2)*c*(S(2)*p + S(1))), Int(x**(m + q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1)), x), x) + Simp(x**(m - n + q + S(1))*(b + S(2)*c*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p/(S(2)*c*(n - q)*(S(2)*p + S(1))), x) def replacement1439(a, b, c, m, n, p, q, r, x): return Dist(p*(n - q)/(c*(m + p*(S(2)*n - q) + S(1))*(m + p*q + (n - q)*(S(2)*p + S(-1)) + S(1))), Int(x**(m - n + S(2)*q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1))*Simp(-a*b*(m - n + p*q + q + S(1)) + x**(n - q)*(S(2)*a*c*(m + p*q + (n - q)*(S(2)*p + S(-1)) + S(1)) - b**S(2)*(m + p*q + (n - q)*(p + S(-1)) + S(1))), x), x), x) + Simp(x**(m - n + q + S(1))*(b*p*(n - q) + c*x**(n - q)*(m + p*q + (n - q)*(S(2)*p + S(-1)) + S(1)))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p/(c*(m + p*(S(2)*n - q) + S(1))*(m + p*q + (n - q)*(S(2)*p + S(-1)) + S(1))), x) def replacement1440(a, b, c, m, n, p, q, r, x): return -Dist(p*(n - q)/(m + p*q + S(1)), Int(x**(m + n)*(b + S(2)*c*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1)), x), x) + Simp(x**(m + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p/(m + p*q + S(1)), x) def replacement1441(a, b, c, m, n, p, q, r, x): return Dist(p*(n - q)/(m + p*(S(2)*n - q) + S(1)), Int(x**(m + q)*(S(2)*a + b*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1)), x), x) + Simp(x**(m + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p/(m + p*(S(2)*n - q) + S(1)), x) def replacement1442(a, b, c, m, n, p, q, r, x): return Dist((S(2)*a*c - b**S(2)*(p + S(2)))/(a*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(m - q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1)), x), x) - Simp(x**(m - q + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1443(a, b, c, m, n, p, q, r, x): return Dist(S(1)/((n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(m - S(2)*n + q)*(S(2)*a*(m - S(2)*n + p*q + S(2)*q + S(1)) + b*x**(n - q)*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1)), x), x) - Simp(x**(m - S(2)*n + q + S(1))*(S(2)*a + b*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/((n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1444(a, b, c, m, n, p, q, r, x): return Dist(S(1)/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(m - q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))*(-S(2)*a*c*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + b**S(2)*(m + p*q + (n - q)*(p + S(1)) + S(1)) + b*c*x**(n - q)*(m + p*q + (n - q)*(S(2)*p + S(3)) + S(1))), x), x) - Simp(x**(m - q + S(1))*(-S(2)*a*c + b**S(2) + b*c*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1445(a, b, c, m, n, p, q, r, x): return -Dist(S(1)/((n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(m - n)*(b*(m - n + p*q + q + S(1)) + S(2)*c*x**(n - q)*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1)), x), x) + Simp(x**(m - n + S(1))*(b + S(2)*c*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/((n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def replacement1446(a, b, c, m, n, p, q, r, x): return -Dist(b/(S(2)*c), Int(x**(m - n + q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x) + Simp(x**(m - S(2)*n + q + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(S(2)*c*(n - q)*(p + S(1))), x) def replacement1447(a, b, c, m, n, p, q, r, x): return -Dist(b/(S(2)*a), Int(x**(m + n - q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x) - Simp(x**(m - q + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(S(2)*a*(n - q)*(p + S(1))), x) def replacement1448(a, b, c, m, n, p, q, r, x): return -Dist(S(1)/(c*(m + p*q + S(2)*p*(n - q) + S(1))), Int(x**(m - S(2)*n + S(2)*q)*(a*(m - S(2)*n + p*q + S(2)*q + S(1)) + b*x**(n - q)*(m + p*q + (n - q)*(p + S(-1)) + S(1)))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x) + Simp(x**(m - S(2)*n + q + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(c*(m + p*q + S(2)*p*(n - q) + S(1))), x) def replacement1449(a, b, c, m, n, p, q, r, x): return -Dist(S(1)/(a*(m + p*q + S(1))), Int(x**(m + n - q)*(b*(m + p*q + (n - q)*(p + S(1)) + S(1)) + c*x**(n - q)*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x) + Simp(x**(m - q + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(a*(m + p*q + S(1))), x) def replacement1450(a, b, c, m, n, p, q, r, x): return Dist(x**(-p*q)*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**(-p)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, Int(x**(m + p*q)*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**p, x), x) def replacement1451(a, b, c, m, n, p, q, r, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int(x**m*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x, u), x) def replacement1452(A, B, a, b, c, j, n, p, q, r, x): return Int(x**(p*q)*(A + B*x**(n - q))*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**p, x) def replacement1453(A, B, a, b, c, j, n, q, r, x): return Dist(x**(q/S(2))*sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))/sqrt(a*x**q + b*x**n + c*x**(S(2)*n - q)), Int(x**(-q/S(2))*(A + B*x**(n - q))/sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q)), x), x) def replacement1454(A, B, a, b, c, j, n, p, q, r, x): return Dist(p*(n - q)/(c*(p*(S(2)*n - q) + S(1))*(p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**q*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1))*(S(2)*A*a*c*(p*q + (n - q)*(S(2)*p + S(1)) + S(1)) - B*a*b*(p*q + S(1)) + x**(n - q)*(A*b*c*(p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + S(2)*B*a*c*(p*(S(2)*n - q) + S(1)) - B*b**S(2)*(p*q + p*(n - q) + S(1)))), x), x) + Simp(x*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p*(A*c*(p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*b*p*(n - q) + B*c*x**(n - q)*(p*(S(2)*n - q) + S(1)))/(c*(p*(S(2)*n - q) + S(1))*(p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def With1455(A, B, a, c, j, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if And(ZeroQ(j - S(2)*n + q), NonzeroQ(p*(S(2)*n - q) + S(1)), NonzeroQ(p*q + (n - q)*(S(2)*p + S(1)) + S(1))): return True return False def replacement1455(A, B, a, c, j, p, q, r, x): n = q + r return Dist(p*(n - q)/((p*(S(2)*n - q) + S(1))*(p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**q*(a*x**q + c*x**(S(2)*n - q))**(p + S(-1))*(S(2)*A*a*(p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + S(2)*B*a*x**(n - q)*(p*(S(2)*n - q) + S(1))), x), x) + Simp(x*(A*(p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*x**(n - q)*(p*(S(2)*n - q) + S(1)))*(a*x**q + c*x**(S(2)*n - q))**p/((p*(S(2)*n - q) + S(1))*(p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def replacement1456(A, B, a, b, c, j, n, p, q, r, x): return Dist(S(1)/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(-q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))*(-S(2)*A*a*c*(p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + A*b**S(2)*(p*q + (n - q)*(p + S(1)) + S(1)) - B*a*b*(p*q + S(1)) + c*x**(n - q)*(A*b - S(2)*B*a)*(p*q + (n - q)*(S(2)*p + S(3)) + S(1))), x), x) - Simp(x**(S(1) - q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))*(-S(2)*A*a*c + A*b**S(2) - B*a*b + c*x**(n - q)*(A*b - S(2)*B*a))/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def With1457(A, B, a, c, j, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if ZeroQ(j - S(2)*n + q): return True return False def replacement1457(A, B, a, c, j, p, q, r, x): n = q + r return Dist(S(1)/(S(2)*a**S(2)*c*(n - q)*(p + S(1))), Int(x**(-q)*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))*(A*a*c*(p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + B*a*c*x**(n - q)*(p*q + (n - q)*(S(2)*p + S(3)) + S(1))), x), x) - Simp(x**(S(1) - q)*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))*(A*a*c + B*a*c*x**(n - q))/(S(2)*a**S(2)*c*(n - q)*(p + S(1))), x) def replacement1458(A, B, a, b, c, j, n, p, q, r, x): return Int((A + B*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x) def replacement1459(A, B, a, b, c, j, n, p, q, r, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int((A + B*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x, u), x) def replacement1460(A, B, a, b, c, j, m, n, p, q, r, x): return Int(x**(m + p*q)*(A + B*x**(n - q))*(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))**p, x) def replacement1461(A, B, a, b, c, j, m, n, p, q, r, x): return Dist(p*(n - q)/((m + p*q + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**(m + n)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1))*Simp(-A*b*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + S(2)*B*a*(m + p*q + S(1)) + x**(n - q)*(-S(2)*A*c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*b*(m + p*q + S(1))), x), x), x) + Simp(x**(m + S(1))*(A*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*x**(n - q)*(m + p*q + S(1)))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p/((m + p*q + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def With1462(A, B, a, c, j, m, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if And(ZeroQ(j - S(2)*n + q), PositiveIntegerQ(n), LessEqual(m + p*q, -n + q), Unequal(m + p*q + S(1), S(0)), Unequal(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1), S(0))): return True return False def replacement1462(A, B, a, c, j, m, p, q, r, x): n = q + r return Dist(S(2)*p*(n - q)/((m + p*q + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**(m + n)*(a*x**q + c*x**(S(2)*n - q))**(p + S(-1))*Simp(-A*c*x**(n - q)*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*a*(m + p*q + S(1)), x), x), x) + Simp(x**(m + S(1))*(A*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*x**(n - q)*(m + p*q + S(1)))*(a*x**q + c*x**(S(2)*n - q))**p/((m + p*q + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def replacement1463(A, B, a, b, c, j, m, n, p, q, r, x): return Dist(S(1)/((n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(m - n)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))*Simp(x**(n - q)*(-S(2)*A*c + B*b)*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + (-A*b + S(2)*B*a)*(m - n + p*q + q + S(1)), x), x), x) + Simp(x**(m - n + S(1))*(A*b - S(2)*B*a - x**(n - q)*(-S(2)*A*c + B*b))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/((n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def With1464(A, B, a, c, j, m, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if And(ZeroQ(j - S(2)*n + q), PositiveIntegerQ(n), Greater(m + p*q, n - q + S(-1))): return True return False def replacement1464(A, B, a, c, j, m, p, q, r, x): n = q + r return -Dist(S(1)/(S(2)*a*c*(n - q)*(p + S(1))), Int(x**(m - n)*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))*Simp(-A*c*x**(n - q)*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + B*a*(m - n + p*q + q + S(1)), x), x), x) + Simp(x**(m - n + S(1))*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))*(-A*c*x**(n - q) + B*a)/(S(2)*a*c*(n - q)*(p + S(1))), x) def replacement1465(A, B, a, b, c, j, m, n, p, q, r, x): return Dist(p*(n - q)/(c*(m + p*(S(2)*n - q) + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**(m + q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(-1))*Simp(S(2)*A*a*c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) - B*a*b*(m + p*q + S(1)) + x**(n - q)*(A*b*c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + S(2)*B*a*c*(m + p*q + S(2)*p*(n - q) + S(1)) - B*b**S(2)*(m + p*q + p*(n - q) + S(1))), x), x), x) + Simp(x**(m + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p*(A*c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*b*p*(n - q) + B*c*x**(n - q)*(m + p*q + S(2)*p*(n - q) + S(1)))/(c*(m + p*(S(2)*n - q) + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def With1466(A, B, a, c, j, m, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if And(ZeroQ(j - S(2)*n + q), PositiveIntegerQ(n), Greater(m + p*q, -n + q), Unequal(m + p*q + S(2)*p*(n - q) + S(1), S(0)), Unequal(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1), S(0)), Unequal(m + S(1), n)): return True return False def replacement1466(A, B, a, c, j, m, p, q, r, x): n = q + r return Dist(p*(n - q)/((m + p*(S(2)*n - q) + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**(m + q)*(a*x**q + c*x**(S(2)*n - q))**(p + S(-1))*Simp(S(2)*A*a*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + S(2)*B*a*x**(n - q)*(m + p*q + S(2)*p*(n - q) + S(1)), x), x), x) + Simp(x**(m + S(1))*(A*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*x**(n - q)*(m + p*q + S(2)*p*(n - q) + S(1)))*(a*x**q + c*x**(S(2)*n - q))**p/((m + p*(S(2)*n - q) + S(1))*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def replacement1467(A, B, a, b, c, j, m, n, p, q, r, x): return Dist(S(1)/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), Int(x**(m - q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))*Simp(-S(2)*A*a*c*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + A*b**S(2)*(m + p*q + (n - q)*(p + S(1)) + S(1)) - B*a*b*(m + p*q + S(1)) + c*x**(n - q)*(A*b - S(2)*B*a)*(m + p*q + (n - q)*(S(2)*p + S(3)) + S(1)), x), x), x) - Simp(x**(m - q + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))*(-S(2)*A*a*c + A*b**S(2) - B*a*b + c*x**(n - q)*(A*b - S(2)*B*a))/(a*(n - q)*(p + S(1))*(-S(4)*a*c + b**S(2))), x) def With1468(A, B, a, c, j, m, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if And(ZeroQ(j - S(2)*n + q), PositiveIntegerQ(n), Less(m + p*q, n - q + S(-1))): return True return False def replacement1468(A, B, a, c, j, m, p, q, r, x): n = q + r return Dist(S(1)/(S(2)*a*c*(n - q)*(p + S(1))), Int(x**(m - q)*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))*Simp(A*c*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + B*c*x**(n - q)*(m + p*q + (n - q)*(S(2)*p + S(3)) + S(1)), x), x), x) - Simp(x**(m - q + S(1))*(A*c + B*c*x**(n - q))*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))/(S(2)*a*c*(n - q)*(p + S(1))), x) def replacement1469(A, B, a, b, c, j, m, n, p, q, r, x): return -Dist(S(1)/(c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**(m - n + q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p*Simp(B*a*(m - n + p*q + q + S(1)) + x**(n - q)*(-A*c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*b*(m + p*q + p*(n - q) + S(1))), x), x), x) + Simp(B*x**(m - n + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def With1470(A, B, a, c, j, m, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if And(ZeroQ(j - S(2)*n + q), PositiveIntegerQ(n), GreaterEqual(m + p*q, n - q + S(-1)), Unequal(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1), S(0))): return True return False def replacement1470(A, B, a, c, j, m, p, q, r, x): n = q + r return -Dist(S(1)/(c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), Int(x**(m - n + q)*(a*x**q + c*x**(S(2)*n - q))**p*Simp(-A*c*x**(n - q)*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1)) + B*a*(m - n + p*q + q + S(1)), x), x), x) + Simp(B*x**(m - n + S(1))*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))/(c*(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1))), x) def replacement1471(A, B, a, b, c, j, m, n, p, q, r, x): return Dist(S(1)/(a*(m + p*q + S(1))), Int(x**(m + n - q)*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p*Simp(-A*b*(m + p*q + (n - q)*(p + S(1)) + S(1)) - A*c*x**(n - q)*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + B*a*(m + p*q + S(1)), x), x), x) + Simp(A*x**(m - q + S(1))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**(p + S(1))/(a*(m + p*q + S(1))), x) def With1472(A, B, a, c, j, m, p, q, r, x): if isinstance(x, (int, Integer, float, Float)): return False n = q + r if And(ZeroQ(j - S(2)*n + q), PositiveIntegerQ(n), Or(Inequality(S(-1), LessEqual, p, Less, S(0)), Equal(m + p*q + (n - q)*(S(2)*p + S(1)) + S(1), S(0))), LessEqual(m + p*q, -n + q), Unequal(m + p*q + S(1), S(0))): return True return False def replacement1472(A, B, a, c, j, m, p, q, r, x): n = q + r return Dist(S(1)/(a*(m + p*q + S(1))), Int(x**(m + n - q)*(a*x**q + c*x**(S(2)*n - q))**p*Simp(-A*c*x**(n - q)*(m + p*q + S(2)*(n - q)*(p + S(1)) + S(1)) + B*a*(m + p*q + S(1)), x), x), x) + Simp(A*x**(m - q + S(1))*(a*x**q + c*x**(S(2)*n - q))**(p + S(1))/(a*(m + p*q + S(1))), x) def replacement1473(A, B, a, b, c, j, m, n, q, r, x): return Dist(x**(q/S(2))*sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q))/sqrt(a*x**q + b*x**n + c*x**(S(2)*n - q)), Int(x**(m - q/S(2))*(A + B*x**(n - q))/sqrt(a + b*x**(n - q) + c*x**(S(2)*n - S(2)*q)), x), x) def replacement1474(A, B, a, b, c, j, k, m, n, p, q, x): return Dist(x**(-j*p)*(a + b*x**(-j + k) + c*x**(-S(2)*j + S(2)*k))**(-p)*(a*x**j + b*x**k + c*x**n)**p, Int(x**(j*p + m)*(A + B*x**(-j + k))*(a + b*x**(-j + k) + c*x**(-S(2)*j + S(2)*k))**p, x), x) def replacement1475(A, B, a, b, c, j, m, n, p, q, r, u, x): return Dist(S(1)/Coefficient(u, x, S(1)), Subst(Int(x**m*(A + B*x**(n - q))*(a*x**q + b*x**n + c*x**(S(2)*n - q))**p, x), x, u), x) sympy-sympy-1.9/sympy/integrals/rubi/symbol.py000066400000000000000000000030711412543434000217150ustar00rootroot00000000000000from sympy.external import import_module matchpy = import_module("matchpy") from sympy.utilities.decorator import doctest_depends_on if matchpy: from matchpy import Wildcard else: class Wildcard: def __init__(self, min_length, fixed_size, variable_name, optional): pass from sympy import Symbol @doctest_depends_on(modules=('matchpy',)) class matchpyWC(Wildcard, Symbol): def __init__(self, min_length, fixed_size, variable_name=None, optional=None, **assumptions): Wildcard.__init__(self, min_length, fixed_size, str(variable_name), optional) def __new__(cls, min_length, fixed_size, variable_name=None, optional=None, **assumptions): cls._sanitize(assumptions, cls) return matchpyWC.__xnew__(cls, min_length, fixed_size, variable_name, optional, **assumptions) def __getnewargs__(self): return (self.min_count, self.fixed_size, self.variable_name, self.optional) @staticmethod def __xnew__(cls, min_length, fixed_size, variable_name=None, optional=None, **assumptions): obj = Symbol.__xnew__(cls, variable_name, **assumptions) return obj def _hashable_content(self): if self.optional: return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name, self.optional) else: return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name) @doctest_depends_on(modules=('matchpy',)) def WC(variable_name=None, optional=None, **assumptions): return matchpyWC(1, True, variable_name, optional) sympy-sympy-1.9/sympy/integrals/rubi/tests/000077500000000000000000000000001412543434000211775ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/tests/__init__.py000066400000000000000000000000001412543434000232760ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/rubi/tests/test_rubi_integrate.py000066400000000000000000000051741412543434000256220ustar00rootroot00000000000000import sys from sympy.external import import_module from sympy.integrals.rubi.rubimain import LoadRubiReplacer matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.core.symbol import symbols, Symbol from sympy.functions import log from sympy import (sqrt, simplify, S, atanh, hyper, I, atan, pi, Sum, cos, sin, log, atan) from sympy.integrals.rubi.utility_function import rubi_test from sympy.testing.pytest import SKIP a, b, c, d, e, f, x, m, n, p, k = symbols('a b c d e f x m n p k', real=True, imaginary=False) @SKIP def test_rubi_integrate(): from sympy.integrals.rubi.rubimain import rubi_integrate assert rubi_integrate(x, x) == x**2/2 assert rubi_integrate(x**2, x) == x**3/3 assert rubi_integrate(x**3, x) == x**4/4 assert rubi_integrate(x**a, x) == x**(a + S(1))/(a + S(1)) assert rubi_integrate(S(1)/x, x) == log(x) assert rubi_integrate(a*x, x) == a*(S(1)/S(2))*x**S(2) assert rubi_integrate(1/(x**2*(a + b*x)**2), x) == -b/(a**2*(a + b*x)) - 1/(a**2*x) - 2*b*log(x)/a**3 + 2*b*log(a + b*x)/a**3 assert rubi_integrate(x**6/(a + b*x)**2, x) == (-a**6/(b**7*(a + b*x)) - S(6)*a**5*log(a + b*x)/b**7 + 5*a**4*x/b**6 - S(2)*a**3*x**2/b**5 + a**2*x**3/b**4 - a*x**4/(S(2)*b**3) + x**5/(S(5)*b**2)) assert rubi_integrate(1/(x**2*(a + b*x)**2), x) == -b/(a**2*(a + b*x)) - 1/(a**2*x) - 2*b*log(x)/a**3 + 2*b*log(a + b*x)/a**3 assert rubi_integrate(a + S(1)/x, x) == a*x + log(x) assert rubi_integrate((a + b*x)**2/x**3, x) == -a**2/(2*x**2) - 2*a*b/x + b**2*log(x) assert rubi_integrate(a**3*x, x) == S(1)/S(2)*a**3*x**2 assert rubi_integrate((a + b*x)**3/x**3, x) == -a**3/(2*x**2) - 3*a**2*b/x + 3*a*b**2*log(x) + b**3*x assert rubi_integrate(x**3*(a + b*x), x) == a*x**4/4 + b*x**5/5 assert rubi_integrate((b*x)**m*(d*x + 2)**n, x) == 2**n*(b*x)**(m + 1)*hyper((-n, m + 1), (m + 2,), -d*x/2)/(b*(m + 1)) assert rubi_test(rubi_integrate(1/(1 + x**5), x), x, log(x + S(1))/S(5) + S(2)*Sum(-log((S(2)*x - S(2)*cos(pi*(S(2)*k/S(5) + S(-1)/5)))**S(2) - S(4)*sin(S(2)*pi*k/S(5) + S(3)*pi/S(10))**S(2) + S(4))*cos(pi*(S(2)*k/S(5) + S(-1)/5))/S(2) - (-S(2)*cos(pi*(S(2)*k/S(5) + S(-1)/5))**S(2) + S(2))*atan((-x/cos(pi*(S(2)*k/S(5) + S(-1)/5)) + S(1))/sqrt(-(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(-1))*(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(1))/cos(S(2)*pi*k/S(5) - pi/S(5))**S(2)))/(S(2)*sqrt(-(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(-1))*(cos(S(2)*pi*k/S(5) - pi/S(5)) + S(1))/cos(S(2)*pi*k/S(5) - pi/S(5))**S(2))*cos(pi*(S(2)*k/S(5) + S(-1)/5))), (k, S(1), S(2)))/S(5), _numerical=True) sympy-sympy-1.9/sympy/integrals/rubi/tests/test_utility_function.py000066400000000000000000002373201412543434000262270ustar00rootroot00000000000000import sys from sympy.external import import_module matchpy = import_module("matchpy") if not matchpy: #bin/test will not execute any tests now disabled = True if sys.version_info[:2] < (3, 6): disabled = True from sympy.integrals.rubi.utility_function import (Set, With, Module, Scan, MapAnd, FalseQ, ZeroQ, NegativeQ, NonzeroQ, FreeQ, List, Log, PositiveQ, PositiveIntegerQ, NegativeIntegerQ, IntegerQ, IntegersQ, ComplexNumberQ, RealNumericQ, PositiveOrZeroQ, NegativeOrZeroQ, FractionOrNegativeQ, NegQ, Equal, Unequal, IntPart, FracPart, RationalQ, ProductQ, SumQ, NonsumQ, First, Rest, SqrtNumberQ, LinearQ, Sqrt, ArcCosh, Coefficient, Denominator, Hypergeometric2F1, Not, Simplify, FractionalPart, IntegerPart, AppellF1, PolynomialQuotient, ArcTan, ArcTanh, ArcSin, ArcSinh, ArcCos, ArcCsc, ArcCsch, Sinh, Coth, LessEqual, Less, Greater, GreaterEqual, FractionQ, IntLinearcQ, Expand, IndependentQ, PowerQ, IntegerPowerQ, PositiveIntegerPowerQ, FractionalPowerQ, AtomQ, ExpQ, LogQ, Head, MemberQ, TrigQ, SinQ, CosQ, TanQ, CotQ, SecQ, CscQ, HyperbolicQ, SinhQ, CoshQ, TanhQ, CothQ, SechQ, CschQ, InverseTrigQ, SinCosQ, SinhCoshQ, LeafCount, Numerator, NumberQ, NumericQ, Length, ListQ, Im, Re, InverseHyperbolicQ, InverseFunctionQ, EqQ, FractionalPowerFreeQ, ComplexFreeQ, PolynomialQ, FactorSquareFree, PowerOfLinearQ, Exponent, QuadraticQ, LinearPairQ, BinomialParts, TrinomialParts, PolyQ, EvenQ, OddQ, PerfectSquareQ, NiceSqrtAuxQ, NiceSqrtQ, Together, PosAux, PosQ, CoefficientList, ReplaceAll, ExpandLinearProduct, GCD, ContentFactor, NumericFactor, NonnumericFactors, MakeAssocList, GensymSubst, KernelSubst, ExpandExpression, Apart, SmartApart, MatchQ, PolynomialQuotientRemainder, FreeFactors, NonfreeFactors, RemoveContentAux, RemoveContent, FreeTerms, NonfreeTerms, ExpandAlgebraicFunction, CollectReciprocals, ExpandCleanup, AlgebraicFunctionQ, Coeff, LeadTerm, RemainingTerms, LeadFactor, RemainingFactors, LeadBase, LeadDegree, Numer, Denom, hypergeom, Expon, MergeMonomials, PolynomialDivide, BinomialQ, TrinomialQ, GeneralizedBinomialQ, GeneralizedTrinomialQ, FactorSquareFreeList, PerfectPowerTest, SquareFreeFactorTest, RationalFunctionQ, RationalFunctionFactors, NonrationalFunctionFactors, Reverse, RationalFunctionExponents, RationalFunctionExpand, ExpandIntegrand, SimplerQ, SimplerSqrtQ, SumSimplerQ, BinomialDegree, TrinomialDegree, CancelCommonFactors, SimplerIntegrandQ, GeneralizedBinomialDegree, GeneralizedBinomialParts, GeneralizedTrinomialDegree, GeneralizedTrinomialParts, MonomialQ, MonomialSumQ, MinimumMonomialExponent, MonomialExponent, LinearMatchQ, PowerOfLinearMatchQ, QuadraticMatchQ, CubicMatchQ, BinomialMatchQ, TrinomialMatchQ, GeneralizedBinomialMatchQ, GeneralizedTrinomialMatchQ, QuotientOfLinearsMatchQ, PolynomialTermQ, PolynomialTerms, NonpolynomialTerms, PseudoBinomialParts, NormalizePseudoBinomial, PseudoBinomialPairQ, PseudoBinomialQ, PolynomialGCD, PolyGCD, AlgebraicFunctionFactors, NonalgebraicFunctionFactors, QuotientOfLinearsP, QuotientOfLinearsParts, QuotientOfLinearsQ, Flatten, Sort, AbsurdNumberQ, AbsurdNumberFactors, NonabsurdNumberFactors, SumSimplerAuxQ, Prepend, Drop, CombineExponents, FactorInteger, FactorAbsurdNumber, SubstForInverseFunction, SubstForFractionalPower, SubstForFractionalPowerOfQuotientOfLinears, FractionalPowerOfQuotientOfLinears, SubstForFractionalPowerQ, SubstForFractionalPowerAuxQ, FractionalPowerOfSquareQ, FractionalPowerSubexpressionQ, Apply, FactorNumericGcd, MergeableFactorQ, MergeFactor, MergeFactors, TrigSimplifyQ, TrigSimplify, TrigSimplifyRecur, Order, FactorOrder, Smallest, OrderedQ, MinimumDegree, PositiveFactors, Sign, NonpositiveFactors, PolynomialInAuxQ, PolynomialInQ, ExponentInAux, ExponentIn, PolynomialInSubstAux, PolynomialInSubst, Distrib, DistributeDegree, FunctionOfPower, DivideDegreesOfFactors, MonomialFactor, FullSimplify, FunctionOfLinearSubst, FunctionOfLinear, NormalizeIntegrand, NormalizeIntegrandAux, NormalizeIntegrandFactor, NormalizeIntegrandFactorBase, NormalizeTogether, NormalizeLeadTermSigns, AbsorbMinusSign, NormalizeSumFactors, SignOfFactor, NormalizePowerOfLinear, SimplifyIntegrand, SimplifyTerm, TogetherSimplify, SmartSimplify, SubstForExpn, ExpandToSum, UnifySum, UnifyTerms, UnifyTerm, CalculusQ, FunctionOfInverseLinear, PureFunctionOfSinhQ, PureFunctionOfTanhQ, PureFunctionOfCoshQ, IntegerQuotientQ, OddQuotientQ, EvenQuotientQ, FindTrigFactor, FunctionOfSinhQ, FunctionOfCoshQ, OddHyperbolicPowerQ, FunctionOfTanhQ, FunctionOfTanhWeight, FunctionOfHyperbolicQ, SmartNumerator, SmartDenominator, ActivateTrig, ExpandTrig, TrigExpand, SubstForTrig, SubstForHyperbolic, InertTrigFreeQ, LCM, SubstForFractionalPowerOfLinear, FractionalPowerOfLinear, InverseFunctionOfLinear, InertTrigQ, InertReciprocalQ, DeactivateTrig, FixInertTrigFunction, DeactivateTrigAux, PowerOfInertTrigSumQ, PiecewiseLinearQ, KnownTrigIntegrandQ, KnownSineIntegrandQ, KnownTangentIntegrandQ, KnownCotangentIntegrandQ, KnownSecantIntegrandQ, TryPureTanSubst, TryTanhSubst, TryPureTanhSubst, AbsurdNumberGCD, AbsurdNumberGCDList, ExpandTrigExpand, ExpandTrigReduce, ExpandTrigReduceAux, NormalizeTrig, TrigToExp, ExpandTrigToExp, TrigReduce, FunctionOfTrig, AlgebraicTrigFunctionQ, FunctionOfHyperbolic, FunctionOfQ, FunctionOfExpnQ, PureFunctionOfSinQ, PureFunctionOfCosQ, PureFunctionOfTanQ, PureFunctionOfCotQ, FunctionOfCosQ, FunctionOfSinQ, OddTrigPowerQ, FunctionOfTanQ, FunctionOfTanWeight, FunctionOfTrigQ, FunctionOfDensePolynomialsQ, FunctionOfLog, PowerVariableExpn, PowerVariableDegree, PowerVariableSubst, EulerIntegrandQ, FunctionOfSquareRootOfQuadratic, SquareRootOfQuadraticSubst, Divides, EasyDQ, ProductOfLinearPowersQ, Rt, NthRoot, AtomBaseQ, SumBaseQ, NegSumBaseQ, AllNegTermQ, SomeNegTermQ, TrigSquareQ, RtAux, TrigSquare, IntSum, IntTerm, Map2, ConstantFactor, SameQ, ReplacePart, CommonFactors, MostMainFactorPosition, FunctionOfExponentialQ, FunctionOfExponential, FunctionOfExponentialFunction, FunctionOfExponentialFunctionAux, FunctionOfExponentialTest, FunctionOfExponentialTestAux, stdev, rubi_test, If, IntQuadraticQ, IntBinomialQ, RectifyTangent, RectifyCotangent, Inequality, Condition, Simp, SimpHelp, SplitProduct, SplitSum, SubstFor, SubstForAux, FresnelS, FresnelC, Erfc, Erfi, Gamma, FunctionOfTrigOfLinearQ, ElementaryFunctionQ, Complex, UnsameQ, _SimpFixFactor, DerivativeDivides, SimpFixFactor, _FixSimplify, FixSimplify, _SimplifyAntiderivativeSum, SimplifyAntiderivativeSum, PureFunctionOfCothQ, _SimplifyAntiderivative, SimplifyAntiderivative, _TrigSimplifyAux, TrigSimplifyAux, Cancel, Part, PolyLog, D, Dist, IntegralFreeQ, Sum_doit, rubi_exp, rubi_log, PolynomialRemainder, CoprimeQ, Distribute, ProductLog, Floor, PolyGamma, process_trig, replace_pow_exp, ExponentList) # TODO - Add tests for: Int, NFreeQ, PureComplexNumberQ, EllipticPi, EllipticE, # EllipticF, ArcCot, ArcCoth, Tanh, Cosh, Sech, ArcSec, ArcSech, Subst, # SqrtNumberSumQ, Sin, Cos, Tan, Cot, Sec, Csc, Csch, TrigHyperbolicFreeQ, # InverseFunctionFreeQ, RealQ, from sympy.core.expr import unchanged from sympy.core.symbol import symbols, S from sympy.functions.elementary.trigonometric import atan, acsc, asin, acot, acos, asec, atan2 from sympy.functions.elementary.hyperbolic import acosh, asinh, atanh, acsch, cosh, sinh, tanh, coth, sech, csch, acoth from sympy.functions import (sin, cos, tan, cot, sec, csc, sqrt, log as sym_log) from sympy import (I, E, pi, hyper, Add, Wild, simplify, Symbol, exp, Pow, li, Ei, expint, Si, Ci, Shi, Chi, loggamma, zeta, zoo, gamma, polylog, oo, polygamma) from sympy import Integral, nsimplify, Min A, B, a, b, c, d, e, f, g, h, y, z, m, n, p, q, u, v, w, F = symbols('A B a b c d e f g h y z m n p q u v w F', real=True, imaginary=False) x = Symbol('x') def test_ZeroQ(): e = b*(n*p + n + 1) d = a assert ZeroQ(a*e - b*d*(n*(p + S(1)) + S(1))) assert ZeroQ(S(0)) assert not ZeroQ(S(10)) assert not ZeroQ(S(-2)) assert ZeroQ(0, 2-2) assert ZeroQ([S(2), (4), S(0), S(8)]) == [False, False, True, False] assert ZeroQ([S(2), S(4), S(8)]) == [False, False, False] def test_NonzeroQ(): assert NonzeroQ(S(1)) == True def test_FreeQ(): l = [a*b, x, a + b] assert FreeQ(l, x) == False l = [a*b, a + b] assert FreeQ(l, x) == True def test_List(): assert List(a, b, c) == [a, b, c] def test_Log(): assert Log(a) == rubi_log(a) def test_PositiveIntegerQ(): assert PositiveIntegerQ(S(1)) assert not PositiveIntegerQ(S(-3)) assert not PositiveIntegerQ(S(0)) def test_NegativeIntegerQ(): assert not NegativeIntegerQ(S(1)) assert NegativeIntegerQ(S(-3)) assert not NegativeIntegerQ(S(0)) def test_PositiveQ(): assert PositiveQ(S(1)) assert not PositiveQ(S(-3)) assert not PositiveQ(S(0)) assert not PositiveQ(zoo) assert not PositiveQ(I) assert PositiveQ(b/(b*(b*c/(-a*d + b*c)) - a*(b*d/(-a*d + b*c)))) def test_IntegerQ(): assert IntegerQ(S(1)) assert not IntegerQ(S(-1.9)) assert not IntegerQ(S(0.0)) assert IntegerQ(S(-1)) def test_IntegersQ(): assert IntegersQ([S(1), S(0)]) assert not IntegersQ([S(-1.9), S(1)]) assert not IntegersQ([S(0.0), S(0)]) assert IntegersQ([S(-1), S(0), S(2)]) def test_FracPart(): assert FracPart(S(10)) == 0 assert FracPart(S(10)+0.5) == 10.5 def test_IntPart(): assert IntPart(m*n) == 0 assert IntPart(S(10)) == 10 assert IntPart(1 + m) == 1 def test_NegQ(): assert NegQ(-S(3)) assert not NegQ(S(0)) assert not NegQ(S(0)) def test_RationalQ(): assert RationalQ(S(5)/6) assert RationalQ(S(5)/6, S(4)/5) assert not RationalQ(Sqrt(1.6)) assert not RationalQ(Sqrt(1.6), S(5)/6) assert not RationalQ(rubi_log(2)) def test_ArcCosh(): assert ArcCosh(x) == acosh(x) def test_LinearQ(): assert not LinearQ(a, x) assert LinearQ(3*x + y**2, x) assert not LinearQ(3*x + y**2, y) assert not LinearQ(S(3), x) def test_Sqrt(): assert Sqrt(x) == sqrt(x) assert Sqrt(25) == 5 def test_Util_Coefficient(): from sympy.integrals.rubi.utility_function import Util_Coefficient assert unchanged(Util_Coefficient, a + b*x + c*x**3, x, a) assert Util_Coefficient(a + b*x + c*x**3, x, 4).doit() == 0 def test_Coefficient(): assert Coefficient(7 + 2*x + 4*x**3, x, 1) == 2 assert Coefficient(a + b*x + c*x**3, x, 0) == a assert Coefficient(a + b*x + c*x**3, x, 4) == 0 assert Coefficient(b*x + c*x**3, x, 3) == c assert Coefficient(x, x, -1) == 0 def test_Denominator(): assert Denominator(-S(1)/S(2) + I/3) == 6 assert Denominator((-a/b)**3) == (b)**(3) assert Denominator(S(3)/2) == 2 assert Denominator(x/y) == y assert Denominator(S(4)/5) == 5 def test_Hypergeometric2F1(): assert Hypergeometric2F1(1, 2, 3, x) == hyper((1, 2), (3,), x) def test_ArcTan(): assert ArcTan(x) == atan(x) assert ArcTan(x, y) == atan2(x, y) def test_Not(): a = 10 assert Not(a == 2) def test_FractionalPart(): assert FractionalPart(S(3.0)) == 0.0 def test_IntegerPart(): assert IntegerPart(3.6) == 3 assert IntegerPart(-3.6) == -4 def test_AppellF1(): assert AppellF1(1,0,0.5,1,0.5,0.25).evalf() == 1.154700538379251529018298 assert unchanged(AppellF1, a, b, c, d, e, f) def test_Simplify(): assert Simplify(sin(x)**2 + cos(x)**2) == 1 assert Simplify((x**3 + x**2 - x - 1)/(x**2 + 2*x + 1)) == x - 1 def test_ArcTanh(): assert ArcTanh(a) == atanh(a) def test_ArcSin(): assert ArcSin(a) == asin(a) def test_ArcSinh(): assert ArcSinh(a) == asinh(a) def test_ArcCos(): assert ArcCos(a) == acos(a) def test_ArcCsc(): assert ArcCsc(a) == acsc(a) def test_ArcCsch(): assert ArcCsch(a) == acsch(a) def test_Equal(): assert Equal(a, a) assert not Equal(a, b) def test_LessEqual(): assert LessEqual(1, 2, 3) assert LessEqual(1, 1) assert not LessEqual(3, 2, 1) def test_With(): assert With(Set(x, 3), x + y) == 3 + y assert With(List(Set(x, 3), Set(y, c)), x + y) == 3 + c def test_Module(): # Same as With assert Module(Set(x, 3), x + y) == 3 + y assert Module(List(Set(x, 3), Set(y, c)), x + y) == 3 + c def test_Less(): assert Less(1, 2, 3) assert not Less(1, 1, 3) def test_Greater(): assert Greater(3, 2, 1) assert not Greater(3, 2, 2) def test_GreaterEqual(): assert GreaterEqual(3, 2, 1) assert GreaterEqual(3, 2, 2) assert not GreaterEqual(2, 3) def test_Unequal(): assert Unequal(1, 2) assert not Unequal(1, 1) def test_FractionQ(): assert not FractionQ(S('3')) assert FractionQ(S('3')/S('2')) def test_Expand(): assert Expand((1 + x)**10) == x**10 + 10*x**9 + 45*x**8 + 120*x**7 + 210*x**6 + 252*x**5 + 210*x**4 + 120*x**3 + 45*x**2 + 10*x + 1 def test_Scan(): assert list(Scan(sin, [a, b])) == [sin(a), sin(b)] def test_MapAnd(): assert MapAnd(PositiveQ, [S(1), S(2), S(3), S(0)]) == False assert MapAnd(PositiveQ, [S(1), S(2), S(3)]) == True def test_FalseQ(): assert FalseQ(True) == False assert FalseQ(False) == True def test_ComplexNumberQ(): assert ComplexNumberQ(1 + I*2, I) == True assert ComplexNumberQ(a + b, I) == False def test_Re(): assert Re(1 + I) == 1 def test_Im(): assert Im(1 + 2*I) == 2 assert Im(a*I) == a def test_PositiveOrZeroQ(): assert PositiveOrZeroQ(S(0)) == True assert PositiveOrZeroQ(S(1)) == True assert PositiveOrZeroQ(-S(1)) == False def test_RealNumericQ(): assert RealNumericQ(S(1)) == True assert RealNumericQ(-S(1)) == True def test_NegativeOrZeroQ(): assert NegativeOrZeroQ(S(0)) == True assert NegativeOrZeroQ(-S(1)) == True assert NegativeOrZeroQ(S(1)) == False def test_FractionOrNegativeQ(): assert FractionOrNegativeQ(S(1)/2) == True assert FractionOrNegativeQ(-S(1)) == True assert FractionOrNegativeQ(-S(1)/2) == True assert FractionOrNegativeQ(S(1)) == False def test_NegativeQ(): assert NegativeQ(-S(1)) == True assert NegativeQ(S(1)) == False assert NegativeQ(oo) == False def test_ProductQ(): assert ProductQ(a*b) == True assert ProductQ(a + b) == False def test_SumQ(): assert SumQ(a*b) == False assert SumQ(a + b) == True def test_NonsumQ(): assert NonsumQ(a*b) == True assert NonsumQ(a + b) == False def test_SqrtNumberQ(): assert SqrtNumberQ(sqrt(2)) == True def test_IntLinearcQ(): assert IntLinearcQ(1, 2, 3, 4, 5, 6, x) == True assert IntLinearcQ(S(1)/100, S(2)/100, S(3)/100, S(4)/100, S(5)/100, S(6)/100, x) == False def test_IndependentQ(): assert IndependentQ(a + b*x, x) == False assert IndependentQ(a + b, x) == True def test_PowerQ(): assert PowerQ(a**b) == True assert PowerQ(a + b) == False def test_IntegerPowerQ(): assert IntegerPowerQ(a**2) == True assert IntegerPowerQ(a**0.5) == False def test_PositiveIntegerPowerQ(): assert PositiveIntegerPowerQ(a**3) == True assert PositiveIntegerPowerQ(a**(-2)) == False def test_FractionalPowerQ(): assert FractionalPowerQ(a**(S(2)/S(3))) assert FractionalPowerQ(a**sqrt(2)) == False def test_AtomQ(): assert AtomQ(x) assert not AtomQ(x+1) assert not AtomQ([a, b]) def test_ExpQ(): assert ExpQ(E**2) assert not ExpQ(2**E) def test_LogQ(): assert LogQ(rubi_log(x)) assert not LogQ(sin(x) + rubi_log(x)) def test_Head(): assert Head(sin(x)) == sin assert Head(rubi_log(x**3 + 3)) in (sym_log, rubi_log) def test_MemberQ(): assert MemberQ([a, b, c], b) assert MemberQ([sin, cos, log, tan], Head(sin(x))) assert MemberQ([[sin, cos], [tan, cot]], [sin, cos]) assert not MemberQ([[sin, cos], [tan, cot]], [sin, tan]) def test_TrigQ(): assert TrigQ(sin(x)) assert TrigQ(tan(x**2 + 2)) assert not TrigQ(sin(x) + tan(x)) def test_SinQ(): assert SinQ(sin(x)) assert not SinQ(tan(x)) def test_CosQ(): assert CosQ(cos(x)) assert not CosQ(csc(x)) def test_TanQ(): assert TanQ(tan(x)) assert not TanQ(cot(x)) def test_CotQ(): assert not CotQ(tan(x)) assert CotQ(cot(x)) def test_SecQ(): assert SecQ(sec(x)) assert not SecQ(csc(x)) def test_CscQ(): assert not CscQ(sec(x)) assert CscQ(csc(x)) def test_HyperbolicQ(): assert HyperbolicQ(sinh(x)) assert HyperbolicQ(cosh(x)) assert HyperbolicQ(tanh(x)) assert not HyperbolicQ(sinh(x) + cosh(x) + tanh(x)) def test_SinhQ(): assert SinhQ(sinh(x)) assert not SinhQ(cosh(x)) def test_CoshQ(): assert not CoshQ(sinh(x)) assert CoshQ(cosh(x)) def test_TanhQ(): assert TanhQ(tanh(x)) assert not TanhQ(coth(x)) def test_CothQ(): assert not CothQ(tanh(x)) assert CothQ(coth(x)) def test_SechQ(): assert SechQ(sech(x)) assert not SechQ(csch(x)) def test_CschQ(): assert not CschQ(sech(x)) assert CschQ(csch(x)) def test_InverseTrigQ(): assert InverseTrigQ(acot(x)) assert InverseTrigQ(asec(x)) assert not InverseTrigQ(acsc(x) + asec(x)) def test_SinCosQ(): assert SinCosQ(sin(x)) assert SinCosQ(cos(x)) assert SinCosQ(sec(x)) assert not SinCosQ(acsc(x)) def test_SinhCoshQ(): assert not SinhCoshQ(sin(x)) assert SinhCoshQ(cosh(x)) assert SinhCoshQ(sech(x)) assert SinhCoshQ(csch(x)) def test_LeafCount(): assert LeafCount(1 + a + x**2) == 6 def test_Numerator(): assert Numerator(-S(1)/S(2) + I/3) == -3 + 2*I assert Numerator((-a/b)**3) == (-a)**(3) assert Numerator(S(3)/2) == 3 assert Numerator(x/y) == x def test_Length(): assert Length(a + b) == 2 assert Length(sin(a)*cos(a)) == 2 def test_ListQ(): assert ListQ([1, 2]) assert not ListQ(a) def test_InverseHyperbolicQ(): assert InverseHyperbolicQ(acosh(a)) def test_InverseFunctionQ(): assert InverseFunctionQ(rubi_log(a)) assert InverseFunctionQ(acos(a)) assert not InverseFunctionQ(a) assert InverseFunctionQ(acosh(a)) assert InverseFunctionQ(polylog(a, b)) def test_EqQ(): assert EqQ(a, a) assert not EqQ(a, b) def test_FactorSquareFree(): assert FactorSquareFree(x**5 - x**3 - x**2 + 1) == (x**3 + 2*x**2 + 2*x + 1)*(x - 1)**2 def test_FactorSquareFreeList(): assert FactorSquareFreeList(x**5-x**3-x**2 + 1) == [[1, 1], [x**3 + 2*x**2 + 2*x + 1, 1], [x - 1, 2]] assert FactorSquareFreeList(x**4 - 2*x**2 + 1) == [[1, 1], [x**2 - 1, 2]] def test_PerfectPowerTest(): assert not PerfectPowerTest(sqrt(x), x) assert not PerfectPowerTest(x**5-x**3-x**2 + 1, x) assert PerfectPowerTest(x**4 - 2*x**2 + 1, x) == (x**2 - 1)**2 def test_SquareFreeFactorTest(): assert not SquareFreeFactorTest(sqrt(x), x) assert SquareFreeFactorTest(x**5 - x**3 - x**2 + 1, x) == (x**3 + 2*x**2 + 2*x + 1)*(x - 1)**2 def test_Rest(): assert Rest([2, 3, 5, 7]) == [3, 5, 7] assert Rest(a + b + c) == b + c assert Rest(a*b*c) == b*c assert Rest(1/b) == -1 def test_First(): assert First([2, 3, 5, 7]) == 2 assert First(y**S(2)) == y assert First(a + b + c) == a assert First(a*b*c) == a def test_ComplexFreeQ(): assert ComplexFreeQ(a) assert not ComplexFreeQ(a + 2*I) def test_FractionalPowerFreeQ(): assert not FractionalPowerFreeQ(x**(S(2)/3)) assert FractionalPowerFreeQ(x) def test_Exponent(): assert Min(ExponentList(x**2 + x + 1 + 5, x)) == 0 assert ExponentList(x**2 + x + 1 + 5, x) == [0, 1, 2] assert ExponentList(x**2 + x + 1, x) == [0, 1, 2] assert ExponentList(x**2 + 2*x + 1, x) == [0, 1, 2] assert Exponent(x**3 + x + 1, x) == 3 assert Exponent(x**2 + 2*x + 1, x) == 2 assert ExponentList(x**3, x) == [3] assert Exponent(S(1), x) == 0 assert Exponent(x**(-3), x) == 0 def test_Expon(): assert Expon(x**2+2*x+1, x) == 2 def test_QuadraticQ(): assert not QuadraticQ([x**2+x+1, 5*x**2], x) assert QuadraticQ([x**2+x+1, 5*x**2+3*x+6], x) assert not QuadraticQ(x**2+1+x**3, x) assert QuadraticQ(x**2+1+x, x) assert not QuadraticQ(x**2, x) def test_BinomialQ(): assert BinomialQ(x**9, x) assert not BinomialQ((1 + x)**3, x) def test_BinomialParts(): assert BinomialParts(2 + x*(9*x), x) == [2, 9, 2] assert BinomialParts(x**9, x) == [0, 1, 9] assert BinomialParts(2*x**3, x) == [0, 2, 3] assert BinomialParts(2 + x, x) == [2, 1, 1] def test_BinomialDegree(): assert BinomialDegree(b + 2*c*x**n, x) == n assert BinomialDegree(2 + x*(9*x), x) == 2 assert BinomialDegree(x**9, x) == 9 def test_PolynomialQ(): assert not PolynomialQ(x*(-1 + x**2), (1 + x)**(S(1)/2)) assert not PolynomialQ((16*x + 1)/((x + 5)**2*(x**2 + x + 1)), 2*x) C = Symbol('C') assert not PolynomialQ(A + b*x + c*x**2, x**2) assert PolynomialQ(A + B*x + C*x**2) assert PolynomialQ(A + B*x**4 + C*x**2, x**2) assert PolynomialQ(x**3, x) assert not PolynomialQ(sqrt(x), x) def test_PolyQ(): assert PolyQ(-2*a*d**3*e**2 + x**6*(a*e**5 - b*d*e**4 + c*d**2*e**3)\ + x**4*(-2*a*d*e**4 + 2*b*d**2*e**3 - 2*c*d**3*e**2) + x**2*(2*a*d**2*e**3 - 2*b*d**3*e**2), x) assert not PolyQ(1/sqrt(a + b*x**2 - c*x**4), x**2) assert PolyQ(x, x, 1) assert PolyQ(x**2, x, 2) assert not PolyQ(x**3, x, 2) def test_EvenQ(): assert EvenQ(S(2)) assert not EvenQ(S(1)) def test_OddQ(): assert OddQ(S(1)) assert not OddQ(S(2)) def test_PerfectSquareQ(): assert PerfectSquareQ(S(4)) assert PerfectSquareQ(a**S(2)*b**S(4)) assert not PerfectSquareQ(S(1)/3) def test_NiceSqrtQ(): assert NiceSqrtQ(S(1)/3) assert not NiceSqrtQ(-S(1)) assert NiceSqrtQ(pi**2) assert NiceSqrtQ(pi**2*sin(4)**4) assert not NiceSqrtQ(pi**2*sin(4)**3) def test_Together(): assert Together(1/a + b/2) == (a*b + 2)/(2*a) def test_PosQ(): #assert not PosQ((b*e - c*d)/(c*e)) assert not PosQ(S(0)) assert PosQ(S(1)) assert PosQ(pi) assert PosQ(pi**3) assert PosQ((-pi)**4) assert PosQ(sin(1)**2*pi**4) def test_NumericQ(): assert NumericQ(sin(cos(2))) def test_NumberQ(): assert NumberQ(pi) def test_CoefficientList(): assert CoefficientList(1 + a*x, x) == [1, a] assert CoefficientList(1 + a*x**3, x) == [1, 0, 0, a] assert CoefficientList(sqrt(x), x) == [] def test_ReplaceAll(): assert ReplaceAll(x, {x: a}) == a assert ReplaceAll(a*x, {x: a + b}) == a*(a + b) assert ReplaceAll(a*x, {a: b, x: a + b}) == b*(a + b) def test_ExpandLinearProduct(): assert ExpandLinearProduct(rubi_log(x), x**2, a, b, x) == a**2*rubi_log(x)/b**2 - 2*a*(a + b*x)*rubi_log(x)/b**2 + (a + b*x)**2*rubi_log(x)/b**2 assert ExpandLinearProduct((a + b*x)**n, x**3, a, b, x) == -a**3*(a + b*x)**n/b**3 + 3*a**2*(a + b*x)**(n + 1)/b**3 - 3*a*(a + b*x)**(n + 2)/b**3 + (a + b*x)**(n + 3)/b**3 def test_PolynomialDivide(): assert PolynomialDivide((a*c - b*c*x)**2, (a + b*x)**2, x) == -4*a*b*c**2*x/(a + b*x)**2 + c**2 assert PolynomialDivide(x + x**2, x, x) == x + 1 assert PolynomialDivide((1 + x)**3, (1 + x)**2, x) == x + 1 assert PolynomialDivide((a + b*x)**3, x**3, x) == a*(a**2 + 3*a*b*x + 3*b**2*x**2)/x**3 + b**3 assert PolynomialDivide(x**3*(a + b*x), S(1), x) == b*x**4 + a*x**3 assert PolynomialDivide(x**6, (a + b*x)**2, x) == -a**5*(5*a + 6*b*x)/(b**6*(a + b*x)**2) + 5*a**4/b**6 - 4*a**3*x/b**5 + 3*a**2*x**2/b**4 - 2*a*x**3/b**3 + x**4/b**2 def test_MatchQ(): a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x]) c_ = Wild('c', exclude=[x]) assert MatchQ(a*b + c, a_*b_ + c_, a_, b_, c_) == (a, b, c) def test_PolynomialQuotientRemainder(): assert PolynomialQuotientRemainder(x**2, x+a, x) == [-a + x, a**2] def test_FreeFactors(): assert FreeFactors(a, x) == a assert FreeFactors(x + a, x) == 1 assert FreeFactors(a*b*x, x) == a*b def test_NonfreeFactors(): assert NonfreeFactors(a, x) == 1 assert NonfreeFactors(x + a, x) == x + a assert NonfreeFactors(a*b*x, x) == x def test_FreeTerms(): assert FreeTerms(a, x) == a assert FreeTerms(x*a, x) == 0 assert FreeTerms(a*x + b, x) == b def test_NonfreeTerms(): assert NonfreeTerms(a, x) == 0 assert NonfreeTerms(a*x, x) == a*x assert NonfreeTerms(a*x + b, x) == a*x def test_RemoveContent(): assert RemoveContent(a + b*x, x) == a + b*x def test_ExpandAlgebraicFunction(): assert ExpandAlgebraicFunction((a + b)*x, x) == a*x + b*x assert ExpandAlgebraicFunction((a + b)**2*x, x)== a**2*x + 2*a*b*x + b**2*x assert ExpandAlgebraicFunction((a + b)**2*x**2, x) == a**2*x**2 + 2*a*b*x**2 + b**2*x**2 def test_CollectReciprocals(): assert CollectReciprocals(-1/(1 + 1*x) - 1/(1 - 1*x), x) == -2/(-x**2 + 1) assert CollectReciprocals(1/(1 + 1*x) - 1/(1 - 1*x), x) == -2*x/(-x**2 + 1) def test_ExpandCleanup(): assert ExpandCleanup(a + b, x) == a*(1 + b/a) assert ExpandCleanup(b**2/(a**2*(a + b*x)**2) + 1/(a**2*x**2) + 2*b**2/(a**3*(a + b*x)) - 2*b/(a**3*x), x) == b**2/(a**2*(a + b*x)**2) + 1/(a**2*x**2) + 2*b**2/(a**3*(a + b*x)) - 2*b/(a**3*x) def test_AlgebraicFunctionQ(): assert not AlgebraicFunctionQ(1/(a + c*x**(2*n)), x) assert AlgebraicFunctionQ(a, x) == True assert AlgebraicFunctionQ(a*b, x) == True assert AlgebraicFunctionQ(x**2, x) == True assert AlgebraicFunctionQ(x**2*a, x) == True assert AlgebraicFunctionQ(x**2 + a, x) == True assert AlgebraicFunctionQ(sin(x), x) == False assert AlgebraicFunctionQ([], x) == True assert AlgebraicFunctionQ([a, a*b], x) == True assert AlgebraicFunctionQ([sin(x)], x) == False def test_MonomialQ(): assert not MonomialQ(2*x**7 + 6, x) assert MonomialQ(2*x**7, x) assert not MonomialQ(2*x**7 + 5*x**3, x) assert not MonomialQ([2*x**7 + 6, 2*x**7], x) assert MonomialQ([2*x**7, 5*x**3], x) def test_MonomialSumQ(): assert MonomialSumQ(2*x**7 + 6, x) == True assert MonomialSumQ(x**2 + x**3 + 5*x, x) == True def test_MinimumMonomialExponent(): assert MinimumMonomialExponent(x**2 + 5*x**2 + 3*x**5, x) == 2 assert MinimumMonomialExponent(x**2 + 5*x**2 + 1, x) == 0 def test_MonomialExponent(): assert MonomialExponent(3*x**7, x) == 7 assert not MonomialExponent(3+x**3, x) def test_LinearMatchQ(): assert LinearMatchQ(2 + 3*x, x) assert LinearMatchQ(3*x, x) assert not LinearMatchQ(3*x**2, x) def test_SimplerQ(): a1, b1 = symbols('a1 b1') assert SimplerQ(a1, b1) assert SimplerQ(2*a, a + 2) assert SimplerQ(2, x) assert not SimplerQ(x**2, x) assert SimplerQ(2*x, x + 2 + 6*x**3) def test_GeneralizedTrinomialParts(): assert not GeneralizedTrinomialParts((7 + 2*x**6 + 3*x**12), x) assert GeneralizedTrinomialParts(x**2 + x**3 + x**4, x) == [1, 1, 1, 3, 2] assert not GeneralizedTrinomialParts(2*x + 3*x + 4*x, x) def test_TrinomialQ(): assert TrinomialQ((7 + 2*x**6 + 3*x**12), x) assert not TrinomialQ(x**2, x) def test_GeneralizedTrinomialDegree(): assert not GeneralizedTrinomialDegree((7 + 2*x**6 + 3*x**12), x) assert GeneralizedTrinomialDegree(x**2 + x**3 + x**4, x) == 1 def test_GeneralizedBinomialParts(): assert GeneralizedBinomialParts(3*x*(3 + x**6), x) == [9, 3, 7, 1] assert GeneralizedBinomialParts((3*x + x**7), x) == [3, 1, 7, 1] def test_GeneralizedBinomialDegree(): assert GeneralizedBinomialDegree(3*x*(3 + x**6), x) == 6 assert GeneralizedBinomialDegree((3*x + x**7), x) == 6 def test_PowerOfLinearQ(): assert PowerOfLinearQ((6*x), x) assert not PowerOfLinearQ((3 + 6*x**3), x) assert PowerOfLinearQ((3 + 6*x)**3, x) def test_LinearPairQ(): assert not LinearPairQ(6*x**2 + 4, 3*x**2 + 2, x) assert LinearPairQ(6*x + 4, 3*x + 2, x) assert not LinearPairQ(6*x, 3*x + 2, x) assert LinearPairQ(6*x, 3*x, x) def test_LeadTerm(): assert LeadTerm(a*b*c) == a*b*c assert LeadTerm(a + b + c) == a def test_RemainingTerms(): assert RemainingTerms(a*b*c) == a*b*c assert RemainingTerms(a + b + c) == b + c def test_LeadFactor(): assert LeadFactor(a*b*c) == a assert LeadFactor(a + b + c) == a + b + c assert LeadFactor(b*I) == I assert LeadFactor(c*a**b) == a**b assert LeadFactor(S(2)) == S(2) def test_RemainingFactors(): assert RemainingFactors(a*b*c) == b*c assert RemainingFactors(a + b + c) == 1 assert RemainingFactors(a*I) == a def test_LeadBase(): assert LeadBase(a**b) == a assert LeadBase(a**b*c) == a def test_LeadDegree(): assert LeadDegree(a**b) == b assert LeadDegree(a**b*c) == b def test_Numer(): assert Numer(a/b) == a assert Numer(a**(-2)) == 1 assert Numer(a**(-2)*a/b) == 1 def test_Denom(): assert Denom(a/b) == b assert Denom(a**(-2)) == a**2 assert Denom(a**(-2)*a/b) == a*b def test_Coeff(): assert Coeff(7 + 2*x + 4*x**3, x, 1) == 2 assert Coeff(a + b*x + c*x**3, x, 0) == a assert Coeff(a + b*x + c*x**3, x, 4) == 0 assert Coeff(b*x + c*x**3, x, 3) == c def test_MergeMonomials(): assert MergeMonomials(x**2*(1 + 1*x)**3*(1 + 1*x)**n, x) == x**2*(x + 1)**(n + 3) assert MergeMonomials(x**2*(1 + 1*x)**2*(1*(1 + 1*x)**1)**2, x) == x**2*(x + 1)**4 assert MergeMonomials(b**2/a**3, x) == b**2/a**3 def test_RationalFunctionQ(): assert RationalFunctionQ(a, x) assert RationalFunctionQ(x**2, x) assert RationalFunctionQ(x**3 + x**4, x) assert RationalFunctionQ(x**3*S(2), x) assert not RationalFunctionQ(x**3 + x**(0.5), x) assert not RationalFunctionQ(x**(S(2)/3)*(a + b*x)**2, x) def test_Apart(): assert Apart(1/(x**2*(a + b*x)**2), x) == b**2/(a**2*(a + b*x)**2) + 1/(a**2*x**2) + 2*b**2/(a**3*(a + b*x)) - 2*b/(a**3*x) assert Apart(x**(S(2)/3)*(a + b*x)**2, x) == x**(S(2)/3)*(a + b*x)**2 def test_RationalFunctionFactors(): assert RationalFunctionFactors(a, x) == a assert RationalFunctionFactors(sqrt(x), x) == 1 assert RationalFunctionFactors(x*x**3, x) == x*x**3 assert RationalFunctionFactors(x*sqrt(x), x) == 1 def test_NonrationalFunctionFactors(): assert NonrationalFunctionFactors(x, x) == 1 assert NonrationalFunctionFactors(sqrt(x), x) == sqrt(x) assert NonrationalFunctionFactors(sqrt(x)*rubi_log(x), x) == sqrt(x)*rubi_log(x) def test_Reverse(): assert Reverse([1, 2, 3]) == [3, 2, 1] assert Reverse(a**b) == b**a def test_RationalFunctionExponents(): assert RationalFunctionExponents(sqrt(x), x) == [0, 0] assert RationalFunctionExponents(a, x) == [0, 0] assert RationalFunctionExponents(x, x) == [1, 0] assert RationalFunctionExponents(x**(-1), x)== [0, 1] assert RationalFunctionExponents(x**(-1)*a, x) == [0, 1] assert RationalFunctionExponents(x**(-1) + a, x) == [1, 1] def test_PolynomialGCD(): assert PolynomialGCD(x**2 - 1, x**2 - 3*x + 2) == x - 1 def test_PolyGCD(): assert PolyGCD(x**2 - 1, x**2 - 3*x + 2, x) == x - 1 def test_AlgebraicFunctionFactors(): assert AlgebraicFunctionFactors(sin(x)*x, x) == x assert AlgebraicFunctionFactors(sin(x), x) == 1 assert AlgebraicFunctionFactors(x, x) == x def test_NonalgebraicFunctionFactors(): assert NonalgebraicFunctionFactors(sin(x)*x, x) == sin(x) assert NonalgebraicFunctionFactors(sin(x), x) == sin(x) assert NonalgebraicFunctionFactors(x, x) == 1 def test_QuotientOfLinearsP(): assert QuotientOfLinearsP((a + b*x)/(x), x) assert QuotientOfLinearsP(x*a, x) assert not QuotientOfLinearsP(x**2*a, x) assert not QuotientOfLinearsP(x**2 + a, x) assert QuotientOfLinearsP(x + a, x) assert QuotientOfLinearsP(x, x) assert QuotientOfLinearsP(1 + x, x) def test_QuotientOfLinearsParts(): assert QuotientOfLinearsParts((b*x)/(c), x) == [0, b/c, 1, 0] assert QuotientOfLinearsParts((b*x)/(c + x), x) == [0, b, c, 1] assert QuotientOfLinearsParts((b*x)/(c + d*x), x) == [0, b, c, d] assert QuotientOfLinearsParts((a + b*x)/(c + d*x), x) == [a, b, c, d] assert QuotientOfLinearsParts(x**2 + a, x) == [a + x**2, 0, 1, 0] assert QuotientOfLinearsParts(a/x, x) == [a, 0, 0, 1] assert QuotientOfLinearsParts(1/x, x) == [1, 0, 0, 1] assert QuotientOfLinearsParts(a*x + 1, x) == [1, a, 1, 0] assert QuotientOfLinearsParts(x, x) == [0, 1, 1, 0] assert QuotientOfLinearsParts(a, x) == [a, 0, 1, 0] def test_QuotientOfLinearsQ(): assert not QuotientOfLinearsQ((a + x), x) assert QuotientOfLinearsQ((a + x)/(x), x) assert QuotientOfLinearsQ((a + b*x)/(x), x) def test_Flatten(): assert Flatten([a, b, [c, [d, e]]]) == [a, b, c, d, e] def test_Sort(): assert Sort([b, a, c]) == [a, b, c] assert Sort([b, a, c], True) == [c, b, a] def test_AbsurdNumberQ(): assert AbsurdNumberQ(S(1)) assert not AbsurdNumberQ(a*x) assert not AbsurdNumberQ(a**(S(1)/2)) assert AbsurdNumberQ((S(1)/3)**(S(1)/3)) def test_AbsurdNumberFactors(): assert AbsurdNumberFactors(S(1)) == S(1) assert AbsurdNumberFactors((S(1)/3)**(S(1)/3)) == S(3)**(S(2)/3)/S(3) assert AbsurdNumberFactors(a) == S(1) def test_NonabsurdNumberFactors(): assert NonabsurdNumberFactors(a) == a assert NonabsurdNumberFactors(S(1)) == S(1) assert NonabsurdNumberFactors(a*S(2)) == a def test_NumericFactor(): assert NumericFactor(S(1)) == S(1) assert NumericFactor(1*I) == S(1) assert NumericFactor(S(1) + I) == S(1) assert NumericFactor(a**(S(1)/3)) == S(1) assert NumericFactor(a*S(3)) == S(3) assert NumericFactor(a + b) == S(1) def test_NonnumericFactors(): assert NonnumericFactors(S(3)) == S(1) assert NonnumericFactors(I) == I assert NonnumericFactors(S(3) + I) == S(3) + I assert NonnumericFactors((S(1)/3)**(S(1)/3)) == S(1) assert NonnumericFactors(rubi_log(a)) == rubi_log(a) def test_Prepend(): assert Prepend([1, 2, 3], [4, 5]) == [4, 5, 1, 2, 3] def test_SumSimplerQ(): assert not SumSimplerQ(S(4 + x),S(3 + x**3)) assert SumSimplerQ(S(4 + x), S(3 - x)) def test_SumSimplerAuxQ(): assert SumSimplerAuxQ(S(4 + x), S(3 - x)) assert not SumSimplerAuxQ(S(4), S(3)) def test_SimplerSqrtQ(): assert SimplerSqrtQ(S(2), S(16*x**3)) assert not SimplerSqrtQ(S(x*2), S(16)) assert not SimplerSqrtQ(S(-4), S(16)) assert SimplerSqrtQ(S(4), S(16)) assert not SimplerSqrtQ(S(4), S(0)) def test_TrinomialParts(): assert TrinomialParts((1 + 5*x**3)**2, x) == [1, 10, 25, 3] assert TrinomialParts(1 + 5*x**3 + 2*x**6, x) == [1, 5, 2, 3] assert TrinomialParts(((1 + 5*x**3)**2) + 6, x) == [7, 10, 25, 3] assert not TrinomialParts(1 + 5*x**3 + 2*x**5, x) def test_TrinomialDegree(): assert TrinomialDegree((7 + 2*x**6)**2, x) == 6 assert TrinomialDegree(1 + 5*x**3 + 2*x**6, x) == 3 assert not TrinomialDegree(1 + 5*x**3 + 2*x**5, x) def test_CubicMatchQ(): assert not CubicMatchQ(S(3 + x**6), x) assert CubicMatchQ(S(x**3), x) assert not CubicMatchQ(S(3), x) assert CubicMatchQ(S(3 + x**3), x) assert CubicMatchQ(S(3 + x**3 + 2*x), x) def test_BinomialMatchQ(): assert BinomialMatchQ(x, x) assert BinomialMatchQ(2 + 3*x**5, x) assert BinomialMatchQ(3*x**5, x) assert BinomialMatchQ(3*x, x) assert not BinomialMatchQ(x + x**2 + x**3, x) def test_TrinomialMatchQ(): assert not TrinomialMatchQ((5 + 2*x**6)**2, x) assert not TrinomialMatchQ((7 + 8*x**6), x) assert TrinomialMatchQ((7 + 2*x**6 + 3*x**3), x) assert TrinomialMatchQ(b*x**2 + c*x**4, x) def test_GeneralizedBinomialMatchQ(): assert not GeneralizedBinomialMatchQ((1 + x**4), x) assert GeneralizedBinomialMatchQ((3*x + x**7), x) def test_QuadraticMatchQ(): assert not QuadraticMatchQ((a + b*x)*(c + d*x), x) assert QuadraticMatchQ(x**2 + x, x) assert QuadraticMatchQ(x**2+1+x, x) assert QuadraticMatchQ(x**2, x) def test_PowerOfLinearMatchQ(): assert PowerOfLinearMatchQ(x, x) assert not PowerOfLinearMatchQ(S(6)**3, x) assert not PowerOfLinearMatchQ(S(6 + 3*x**2)**3, x) assert PowerOfLinearMatchQ(S(6 + 3*x)**3, x) def test_GeneralizedTrinomialMatchQ(): assert not GeneralizedTrinomialMatchQ(7 + 2*x**6 + 3*x**12, x) assert not GeneralizedTrinomialMatchQ(7 + 2*x**6 + 3*x**3, x) assert not GeneralizedTrinomialMatchQ(7 + 2*x**6 + 3*x**5, x) assert GeneralizedTrinomialMatchQ(x**2 + x**3 + x**4, x) def test_QuotientOfLinearsMatchQ(): assert QuotientOfLinearsMatchQ((1 + x)*(3 + 4*x**2)/(2 + 4*x), x) assert not QuotientOfLinearsMatchQ(x*(3 + 4*x**2)/(2 + 4*x**3), x) assert QuotientOfLinearsMatchQ(x*(3 + 4*x)/(2 + 4*x), x) assert QuotientOfLinearsMatchQ(2*(3 + 4*x)/(2 + 4*x), x) def test_PolynomialTermQ(): assert not PolynomialTermQ(S(3), x) assert PolynomialTermQ(3*x**6, x) assert not PolynomialTermQ(3*x**6+5*x, x) def test_PolynomialTerms(): assert PolynomialTerms(x + 6*x**3 + rubi_log(x), x) == 6*x**3 + x assert PolynomialTerms(x + 6*x**3 + 6*x, x) == 6*x**3 + 7*x assert PolynomialTerms(x + 6*x**3 + 6, x) == 6*x**3 + x def test_NonpolynomialTerms(): assert NonpolynomialTerms(x + 6*x**3 + rubi_log(x), x) == rubi_log(x) assert NonpolynomialTerms(x + 6*x**3 + 6*x, x) == 0 assert NonpolynomialTerms(x + 6*x**3 + 6, x) == 6 def test_PseudoBinomialQ(): assert PseudoBinomialQ(3 + 5*(x)**6, x) assert PseudoBinomialQ(3 + 5*(2 + 5*x)**6, x) def test_PseudoBinomialParts(): assert PseudoBinomialParts(3 + 7*(1 + x)**6, x) == [3, 1, 7**(S(1)/S(6)), 7**(S(1)/S(6)), 6] assert PseudoBinomialParts(3 + 7*(1 + x)**3, x) == [3, 1, 7**(S(1)/S(3)), 7**(S(1)/S(3)), 3] assert not PseudoBinomialParts(3 + 7*(1 + x)**2, x) assert PseudoBinomialParts(3 + 7*(x)**5, x) == [3, 1, 0, 7**(S(1)/S(5)), 5] def test_PseudoBinomialPairQ(): assert not PseudoBinomialPairQ(3 + 5*(x)**6,3 + (x)**6, x) assert not PseudoBinomialPairQ(3 + 5*(1 + x)**6,3 + (1 + x)**6, x) def test_NormalizePseudoBinomial(): assert NormalizePseudoBinomial(3 + 5*(1 + x)**6, x) == 3+(5**(S(1)/S(6))+5**(S(1)/S(6))*x)**S(6) assert NormalizePseudoBinomial(3 + 5*(x)**6, x) == 3+5*x**6 def test_CancelCommonFactors(): assert CancelCommonFactors(S(x*y*S(6))**S(6), S(x*y*S(6))) == [46656*x**6*y**6, 6*x*y] assert CancelCommonFactors(S(y*6)**S(6), S(x*y*S(6))) == [46656*y**6, 6*x*y] assert CancelCommonFactors(S(6), S(3)) == [6, 3] def test_SimplerIntegrandQ(): assert SimplerIntegrandQ(S(5), 4*x, x) assert not SimplerIntegrandQ(S(x + 5*x**3), S(x**2 + 3*x), x) assert SimplerIntegrandQ(S(x + 8), S(x**2 + 3*x), x) def test_Drop(): assert Drop([1, 2, 3, 4, 5, 6], [2, 4]) == [1, 5, 6] assert Drop([1, 2, 3, 4, 5, 6], -3) == [1, 2, 3] assert Drop([1, 2, 3, 4, 5, 6], 2) == [3, 4, 5, 6] assert Drop(a*b*c, 1) == b*c def test_SubstForInverseFunction(): assert SubstForInverseFunction(x, a, b, x) == b assert SubstForInverseFunction(a, a, b, x) == a assert SubstForInverseFunction(x**a, x**a, b, x) == x assert SubstForInverseFunction(a*x**a, a, b, x) == a*b**a def test_SubstForFractionalPower(): assert SubstForFractionalPower(a, b, n, c, x) == a assert SubstForFractionalPower(x, b, n, c, x) == c assert SubstForFractionalPower(a**(S(1)/2), a, n, b, x) == x**(n/2) def test_CombineExponents(): assert True def test_FractionalPowerOfSquareQ(): assert not FractionalPowerOfSquareQ(x) assert not FractionalPowerOfSquareQ((a + b)**(S(2)/S(3))) assert not FractionalPowerOfSquareQ((a + b)**(S(2)/S(3))*c) assert FractionalPowerOfSquareQ(((a + b*x)**(S(2)))**(S(1)/3)) == (a + b*x)**S(2) def test_FractionalPowerSubexpressionQ(): assert not FractionalPowerSubexpressionQ(x, a, x) assert FractionalPowerSubexpressionQ(x**(S(2)/S(3)), a, x) assert not FractionalPowerSubexpressionQ(b*a, a, x) def test_FactorNumericGcd(): assert FactorNumericGcd(5*a**2*e**4 + 2*a*b*d*e**3 + 2*a*c*d**2*e**2 + b**2*d**2*e**2 - 6*b*c*d**3*e + 21*c**2*d**4) ==\ 5*a**2*e**4 + 2*a*b*d*e**3 + 2*a*c*d**2*e**2 + b**2*d**2*e**2 - 6*b*c*d**3*e + 21*c**2*d**4 assert FactorNumericGcd(x**(S(2))) == x**S(2) assert FactorNumericGcd(rubi_log(x)) == rubi_log(x) assert FactorNumericGcd(rubi_log(x)*x) == x*rubi_log(x) assert FactorNumericGcd(rubi_log(x) + x**S(2)) == rubi_log(x) + x**S(2) def test_Apply(): assert Apply(List, [a, b, c]) == [a, b, c] def test_TrigSimplify(): assert TrigSimplify(a*sin(x)**2 + a*cos(x)**2 + v) == a + v assert TrigSimplify(a*sec(x)**2 - a*tan(x)**2 + v) == a + v assert TrigSimplify(a*csc(x)**2 - a*cot(x)**2 + v) == a + v assert TrigSimplify(S(1) - sin(x)**2) == cos(x)**2 assert TrigSimplify(1 + tan(x)**2) == sec(x)**2 assert TrigSimplify(1 + cot(x)**2) == csc(x)**2 assert TrigSimplify(-S(1) + sec(x)**2) == tan(x)**2 assert TrigSimplify(-1 + csc(x)**2) == cot(x)**2 def test_MergeFactors(): assert simplify(MergeFactors(b/(a - c)**3 , 8*c**3*(b*x + c)**(3/2)/(3*b**4) - 24*c**2*(b*x + c)**(5/2)/(5*b**4) + \ 24*c*(b*x + c)**(7/2)/(7*b**4) - 8*(b*x + c)**(9/2)/(9*b**4)) - (8*c**3*(b*x + c)**1.5/(3*b**3) - 24*c**2*(b*x + c)**2.5/(5*b**3) + \ 24*c*(b*x + c)**3.5/(7*b**3) - 8*(b*x + c)**4.5/(9*b**3))/(a - c)**3) == 0 assert MergeFactors(x, x) == x**2 assert MergeFactors(x*y, x) == x**2*y def test_FactorInteger(): assert FactorInteger(2434500) == [(2, 2), (3, 2), (5, 3), (541, 1)] def test_ContentFactor(): assert ContentFactor(a*b + a*c) == a*(b + c) def test_Order(): assert Order(a, b) == 1 assert Order(b, a) == -1 assert Order(a, a) == 0 def test_FactorOrder(): assert FactorOrder(1, 1) == 0 assert FactorOrder(1, 2) == -1 assert FactorOrder(2, 1) == 1 assert FactorOrder(a, b) == 1 def test_Smallest(): assert Smallest([2, 1, 3, 4]) == 1 assert Smallest(1, 2) == 1 assert Smallest(-1, -2) == -2 def test_MostMainFactorPosition(): assert MostMainFactorPosition([S(1), S(2), S(3)]) == 1 assert MostMainFactorPosition([S(1), S(7), S(3), S(4), S(5)]) == 2 def test_OrderedQ(): assert OrderedQ([a, b]) assert not OrderedQ([b, a]) def test_MinimumDegree(): assert MinimumDegree(S(1), S(2)) == 1 assert MinimumDegree(S(1), sqrt(2)) == 1 assert MinimumDegree(sqrt(2), S(1)) == 1 assert MinimumDegree(sqrt(3), sqrt(2)) == sqrt(2) assert MinimumDegree(sqrt(2), sqrt(2)) == sqrt(2) def test_PositiveFactors(): assert PositiveFactors(S(0)) == 1 assert PositiveFactors(-S(1)) == S(1) assert PositiveFactors(sqrt(2)) == sqrt(2) assert PositiveFactors(-rubi_log(2)) == rubi_log(2) assert PositiveFactors(sqrt(2)*S(-1)) == sqrt(2) def test_NonpositiveFactors(): assert NonpositiveFactors(S(0)) == 0 assert NonpositiveFactors(-S(1)) == -1 assert NonpositiveFactors(sqrt(2)) == 1 assert NonpositiveFactors(-rubi_log(2)) == -1 def test_Sign(): assert Sign(S(0)) == 0 assert Sign(S(1)) == 1 assert Sign(-S(1)) == -1 def test_PolynomialInQ(): v = rubi_log(x) assert PolynomialInQ(S(1), v, x) assert PolynomialInQ(v, v, x) assert PolynomialInQ(1 + v**2, v, x) assert PolynomialInQ(1 + a*v**2, v, x) assert not PolynomialInQ(sqrt(v), v, x) def test_ExponentIn(): v = rubi_log(x) assert ExponentIn(S(1), rubi_log(x), x) == 0 assert ExponentIn(S(1) + v, rubi_log(x), x) == 1 assert ExponentIn(S(1) + v + v**3, rubi_log(x), x) == 3 assert ExponentIn(S(2)*sqrt(v)*v**3, rubi_log(x), x) == 3.5 def test_PolynomialInSubst(): v = rubi_log(x) assert PolynomialInSubst(S(1) + rubi_log(x)**3, rubi_log(x), x) == 1 + x**3 assert PolynomialInSubst(S(1) + rubi_log(x), rubi_log(x), x) == x + 1 def test_Distrib(): assert Distrib(x, a) == x*a assert Distrib(x, a + b) == a*x + b*x def test_DistributeDegree(): assert DistributeDegree(x, m) == x**m assert DistributeDegree(x**a, m) == x**(a*m) assert DistributeDegree(a*b, m) == a**m * b**m def test_FunctionOfPower(): assert FunctionOfPower(a, x) == None assert FunctionOfPower(x, x) == 1 assert FunctionOfPower(x**3, x) == 3 assert FunctionOfPower(x**3*cos(x**6), x) == 3 def test_DivideDegreesOfFactors(): assert DivideDegreesOfFactors(a**b, S(3)) == a**(b/3) assert DivideDegreesOfFactors(a**b*c, S(3)) == a**(b/3)*c**(c/3) def test_MonomialFactor(): assert MonomialFactor(a, x) == [0, a] assert MonomialFactor(x, x) == [1, 1] assert MonomialFactor(x + y, x) == [0, x + y] assert MonomialFactor(rubi_log(x), x) == [0, rubi_log(x)] assert MonomialFactor(rubi_log(x)*x, x) == [1, rubi_log(x)] def test_NormalizeIntegrand(): assert NormalizeIntegrand((x**2 + 8), x) == x**2 + 8 assert NormalizeIntegrand((x**2 + 3*x)**2, x) == x**2*(x + 3)**2 assert NormalizeIntegrand(a**2*(a + b*x)**2, x) == a**2*(a + b*x)**2 assert NormalizeIntegrand(b**2/(a**2*(a + b*x)**2), x) == b**2/(a**2*(a + b*x)**2) def test_NormalizeIntegrandAux(): v = (6*A*a*c - 2*A*b**2 + B*a*b)/(a*x**2) - (6*A*a**2*c**2 - 10*A*a*b**2*c - 8*A*a*b*c**2*x + 2*A*b**4 + 2*A*b**3*c*x + 5*B*a**2*b*c + 4*B*a**2*c**2*x - B*a*b**3 - B*a*b**2*c*x)/(a**2*(a + b*x + c*x**2)) + (-2*A*b + B*a)*(4*a*c - b**2)/(a**2*x) assert NormalizeIntegrandAux(v, x) == (6*A*a*c - 2*A*b**2 + B*a*b)/(a*x**2) - (6*A*a**2*c**2 - 10*A*a*b**2*c + 2*A*b**4 + 5*B*a**2*b*c - B*a*b**3 + x*(-8*A*a*b*c**2 + 2*A*b**3*c + 4*B*a**2*c**2 - B*a*b**2*c))/(a**2*(a + b*x + c*x**2)) + (-2*A*b + B*a)*(4*a*c - b**2)/(a**2*x) assert NormalizeIntegrandAux((x**2 + 3*x)**2, x) == x**2*(x + 3)**2 assert NormalizeIntegrandAux((x**2 + 8), x) == x**2 + 8 def test_NormalizeIntegrandFactor(): assert NormalizeIntegrandFactor((3*x + x**3)**2, x) == x**2*(x**2 + 3)**2 assert NormalizeIntegrandFactor((x**2 + 8), x) == x**2 + 8 def test_NormalizeIntegrandFactorBase(): assert NormalizeIntegrandFactorBase((x**2 + 8)**3, x) == (x**2 + 8)**3 assert NormalizeIntegrandFactorBase((x**2 + 8), x) == x**2 + 8 assert NormalizeIntegrandFactorBase(a**2*(a + b*x)**2, x) == a**2*(a + b*x)**2 def test_AbsorbMinusSign(): assert AbsorbMinusSign((x + 2)**5*(x + 3)**5) == (-x - 3)**5*(x + 2)**5 assert AbsorbMinusSign((x + 2)**5*(x + 3)**2) == -(x + 2)**5*(x + 3)**2 def test_NormalizeLeadTermSigns(): assert NormalizeLeadTermSigns((-x + 3)*(x**2 + 3)) == (-x + 3)*(x**2 + 3) assert NormalizeLeadTermSigns(x + 3) == x + 3 def test_SignOfFactor(): assert SignOfFactor(S(-x + 3)) == [1, -x + 3] assert SignOfFactor(S(-x)) == [-1, x] def test_NormalizePowerOfLinear(): assert NormalizePowerOfLinear((x + 3)**5, x) == (x + 3)**5 assert NormalizePowerOfLinear(((x + 3)**2) + 3, x) == x**2 + 6*x + 12 def test_SimplifyIntegrand(): assert SimplifyIntegrand((x**2 + 3)**2, x) == (x**2 + 3)**2 assert SimplifyIntegrand(x**2 + 3 + (x**6) + 6, x) == x**6 + x**2 + 9 def test_SimplifyTerm(): assert SimplifyTerm(a**2/b**2, x) == a**2/b**2 assert SimplifyTerm(-6*x/5 + (5*x + 3)**2/25 - 9/25, x) == x**2 def test_togetherSimplify(): assert TogetherSimplify(-6*x/5 + (5*x + 3)**2/25 - 9/25) == x**2 def test_ExpandToSum(): qq = 6 Pqq = e**3 Pq = (d+e*x**2)**3 aa = 2 nn = 2 cc = 1 pp = -1/2 bb = 3 assert nsimplify(ExpandToSum(Pq - Pqq*x**qq - Pqq*(aa*x**(-2*nn + qq)*(-2*nn + qq + 1) + bb*x**(-nn + qq)*(nn*(pp - 1) + qq + 1))/(cc*(2*nn*pp + qq + 1)), x) - \ (d**3 + x**4*(3*d*e**2 - 2.4*e**3) + x**2*(3*d**2*e - 1.2*e**3))) == 0 assert ExpandToSum(x**2 + 3*x + 3, x**3 + 3, x) == x**3*(x**2 + 3*x + 3) + 3*x**2 + 9*x + 9 assert ExpandToSum(x**3 + 6, x) == x**3 + 6 assert ExpandToSum(S(x**2 + 3*x + 3)*3, x) == 3*x**2 + 9*x + 9 assert ExpandToSum((a + b*x), x) == a + b*x def test_UnifySum(): assert UnifySum((3 + x + 6*x**3 + sin(x)), x) == 6*x**3 + x + sin(x) + 3 assert UnifySum((3 + x + 6*x**3)*3, x) == 18*x**3 + 3*x + 9 def test_FunctionOfInverseLinear(): assert FunctionOfInverseLinear((x)/(a + b*x), x) == [a, b] assert FunctionOfInverseLinear((c + d*x)/(a + b*x), x) == [a, b] assert not FunctionOfInverseLinear(1/(a + b*x), x) def test_PureFunctionOfSinhQ(): v = rubi_log(x) f = sinh(v) assert PureFunctionOfSinhQ(f, v, x) assert not PureFunctionOfSinhQ(cosh(v), v, x) assert PureFunctionOfSinhQ(f**2, v, x) def test_PureFunctionOfTanhQ(): v = rubi_log(x) f = tanh(v) assert PureFunctionOfTanhQ(f, v, x) assert not PureFunctionOfTanhQ(cosh(v), v, x) assert PureFunctionOfTanhQ(f**2, v, x) def test_PureFunctionOfCoshQ(): v = rubi_log(x) f = cosh(v) assert PureFunctionOfCoshQ(f, v, x) assert not PureFunctionOfCoshQ(sinh(v), v, x) assert PureFunctionOfCoshQ(f**2, v, x) def test_IntegerQuotientQ(): u = S(2)*sin(x) v = sin(x) assert IntegerQuotientQ(u, v) assert IntegerQuotientQ(u, u) assert not IntegerQuotientQ(S(1), S(2)) def test_OddQuotientQ(): u = S(3)*sin(x) v = sin(x) assert OddQuotientQ(u, v) assert OddQuotientQ(u, u) assert not OddQuotientQ(S(1), S(2)) def test_EvenQuotientQ(): u = S(2)*sin(x) v = sin(x) assert EvenQuotientQ(u, v) assert not EvenQuotientQ(u, u) assert not EvenQuotientQ(S(1), S(2)) def test_FunctionOfSinhQ(): v = rubi_log(x) assert FunctionOfSinhQ(cos(sinh(v)), v, x) assert FunctionOfSinhQ(sinh(v), v, x) assert FunctionOfSinhQ(sinh(v)*cos(sinh(v)), v, x) def test_FunctionOfCoshQ(): v = rubi_log(x) assert FunctionOfCoshQ(cos(cosh(v)), v, x) assert FunctionOfCoshQ(cosh(v), v, x) assert FunctionOfCoshQ(cosh(v)*cos(cosh(v)), v, x) def test_FunctionOfTanhQ(): v = rubi_log(x) t = Tanh(v) c = Coth(v) assert FunctionOfTanhQ(t, v, x) assert FunctionOfTanhQ(c, v, x) assert FunctionOfTanhQ(t + c, v, x) assert FunctionOfTanhQ(t*c, v, x) assert not FunctionOfTanhQ(sin(x), v, x) def test_FunctionOfTanhWeight(): v = rubi_log(x) t = Tanh(v) c = Coth(v) assert FunctionOfTanhWeight(x, v, x) == 0 assert FunctionOfTanhWeight(sinh(v), v, x) == 0 assert FunctionOfTanhWeight(tanh(v), v, x) == 1 assert FunctionOfTanhWeight(coth(v), v, x) == -1 assert FunctionOfTanhWeight(t**2, v, x) == 1 assert FunctionOfTanhWeight(sinh(v)**2, v, x) == -1 assert FunctionOfTanhWeight(coth(v)*sinh(v)**2, v, x) == -2 def test_FunctionOfHyperbolicQ(): v = rubi_log(x) s = Sinh(v) t = Tanh(v) assert not FunctionOfHyperbolicQ(x, v, x) assert FunctionOfHyperbolicQ(s + t, v, x) assert FunctionOfHyperbolicQ(sinh(t), v, x) def test_SmartNumerator(): assert SmartNumerator(x**(-2)) == 1 assert SmartNumerator(x**(2)*a) == x**2*a def test_SmartDenominator(): assert SmartDenominator(x**(-2)) == x**2 assert SmartDenominator(x**(-2)*1/S(3)) == x**2*3 def test_SubstForAux(): v = rubi_log(x) assert SubstForAux(v, v, x) == x assert SubstForAux(v**2, v, x) == x**2 assert SubstForAux(x, v, x) == x assert SubstForAux(v**2, v**4, x) == sqrt(x) assert SubstForAux(v**2*v, v, x) == x**3 def test_SubstForTrig(): v = rubi_log(x) s, c, t = sin(v), cos(v), tan(v) assert SubstForTrig(cos(a/2 + b*x/2), x/sqrt(x**2 + 1), 1/sqrt(x**2 + 1), a/2 + b*x/2, x) == 1/sqrt(x**2 + 1) assert SubstForTrig(s, sin, cos, v, x) == sin assert SubstForTrig(t, sin(v), cos(v), v, x) == sin(rubi_log(x))/cos(rubi_log(x)) assert SubstForTrig(sin(2*v), sin(x), cos(x), v, x) == 2*sin(x)*cos(x) assert SubstForTrig(s*t, sin(x), cos(x), v, x) == sin(x)**2/cos(x) def test_SubstForHyperbolic(): v = rubi_log(x) s, c, t = sinh(v), cosh(v), tanh(v) assert SubstForHyperbolic(s, sinh(x), cosh(x), v, x) == sinh(x) assert SubstForHyperbolic(t, sinh(x), cosh(x), v, x) == sinh(x)/cosh(x) assert SubstForHyperbolic(sinh(2*v), sinh(x), cosh(x), v, x) == 2*sinh(x)*cosh(x) assert SubstForHyperbolic(s*t, sinh(x), cosh(x), v, x) == sinh(x)**2/cosh(x) def test_SubstForFractionalPowerOfLinear(): u = a + b*x assert not SubstForFractionalPowerOfLinear(u, x) assert not SubstForFractionalPowerOfLinear(u**(S(2)), x) assert SubstForFractionalPowerOfLinear(u**(S(1)/2), x) == [x**2, 2, a + b*x, 1/b] def test_InverseFunctionOfLinear(): u = a + b*x assert InverseFunctionOfLinear(rubi_log(u)*sin(x), x) == rubi_log(u) assert InverseFunctionOfLinear(rubi_log(u), x) == rubi_log(u) def test_InertTrigQ(): s = sin(x) c = cos(x) assert not InertTrigQ(sin(x), csc(x), cos(h)) assert InertTrigQ(sin(x), csc(x)) assert not InertTrigQ(s, c) assert InertTrigQ(c) def test_PowerOfInertTrigSumQ(): func = sin assert PowerOfInertTrigSumQ((1 + S(2)*(S(3)*func(x**2))**S(5))**3, func, x) assert PowerOfInertTrigSumQ((1 + 2*(S(3)*func(x**2))**3 + 4*(S(5)*func(x**2))**S(3))**2, func, x) def test_PiecewiseLinearQ(): assert PiecewiseLinearQ(a + b*x, x) assert not PiecewiseLinearQ(Log(c*sin(a)**S(3)), x) assert not PiecewiseLinearQ(x**3, x) assert PiecewiseLinearQ(atanh(tanh(a + b*x)), x) assert PiecewiseLinearQ(tanh(atanh(a + b*x)), x) assert not PiecewiseLinearQ(coth(atanh(a + b*x)), x) def test_KnownTrigIntegrandQ(): func = sin(a + b*x) assert KnownTrigIntegrandQ([sin], S(1), x) assert KnownTrigIntegrandQ([sin], (a + b*func)**m, x) assert KnownTrigIntegrandQ([sin], (a + b*func)**m*(1 + 2*func), x) assert KnownTrigIntegrandQ([sin], a + c*func**2, x) assert KnownTrigIntegrandQ([sin], a + b*func + c*func**2, x) assert KnownTrigIntegrandQ([sin], (a + b*func)**m*(c + d*func**2), x) assert KnownTrigIntegrandQ([sin], (a + b*func)**m*(c + d*func + e*func**2), x) assert not KnownTrigIntegrandQ([cos], (a + b*func)**m, x) def test_KnownSineIntegrandQ(): assert KnownSineIntegrandQ((a + b*sin(a + b*x))**m, x) def test_KnownTangentIntegrandQ(): assert KnownTangentIntegrandQ((a + b*tan(a + b*x))**m, x) def test_KnownCotangentIntegrandQ(): assert KnownCotangentIntegrandQ((a + b*cot(a + b*x))**m, x) def test_KnownSecantIntegrandQ(): assert KnownSecantIntegrandQ((a + b*sec(a + b*x))**m, x) def test_TryPureTanSubst(): assert TryPureTanSubst(atan(c*(a + b*tan(a + b*x))), x) assert TryPureTanSubst(atanh(c*(a + b*cot(a + b*x))), x) assert not TryPureTanSubst(tan(c*(a + b*cot(a + b*x))), x) def test_TryPureTanhSubst(): assert not TryPureTanhSubst(rubi_log(x), x) assert TryPureTanhSubst(sin(x), x) assert not TryPureTanhSubst(atanh(a*tanh(x)), x) assert not TryPureTanhSubst((a + b*x)**S(2), x) def test_TryTanhSubst(): assert not TryTanhSubst(rubi_log(x), x) assert not TryTanhSubst(a*(b + c)**3, x) assert not TryTanhSubst(1/(a + b*sinh(x)**S(3)), x) assert not TryTanhSubst(sinh(S(3)*x)*cosh(S(4)*x), x) assert not TryTanhSubst(a*(b*sech(x)**3)**c, x) def test_GeneralizedBinomialQ(): assert GeneralizedBinomialQ(a*x**q + b*x**n, x) assert not GeneralizedBinomialQ(a*x**q, x) def test_GeneralizedTrinomialQ(): assert not GeneralizedTrinomialQ(7 + 2*x**6 + 3*x**12, x) assert not GeneralizedTrinomialQ(a*x**q + c*x**(2*n-q), x) def test_SubstForFractionalPowerOfQuotientOfLinears(): assert SubstForFractionalPowerOfQuotientOfLinears(((a + b*x)/(c + d*x))**(S(3)/2), x) == [x**4/(b - d*x**2)**2, 2, (a + b*x)/(c + d*x), -a*d + b*c] def test_SubstForFractionalPowerQ(): assert SubstForFractionalPowerQ(x, sin(x), x) assert SubstForFractionalPowerQ(x**2, sin(x), x) assert not SubstForFractionalPowerQ(x**(S(3)/2), sin(x), x) assert SubstForFractionalPowerQ(sin(x)**(S(3)/2), sin(x), x) def test_AbsurdNumberGCD(): assert AbsurdNumberGCD(S(4)) == 4 assert AbsurdNumberGCD(S(4), S(8), S(12)) == 4 assert AbsurdNumberGCD(S(2), S(3), S(12)) == 1 def test_TrigReduce(): assert TrigReduce(cos(x)**2) == cos(2*x)/2 + 1/2 assert TrigReduce(cos(x)**2*sin(x)) == sin(x)/4 + sin(3*x)/4 assert TrigReduce(cos(x)**2+sin(x)) == sin(x) + cos(2*x)/2 + 1/2 assert TrigReduce(cos(x)**2*sin(x)**5) == 5*sin(x)/64 + sin(3*x)/64 - 3*sin(5*x)/64 + sin(7*x)/64 assert TrigReduce(2*sin(x)*cos(x) + 2*cos(x)**2) == sin(2*x) + cos(2*x) + 1 assert TrigReduce(sinh(a + b*x)**2) == cosh(2*a + 2*b*x)/2 - 1/2 assert TrigReduce(sinh(a + b*x)*cosh(a + b*x)) == sinh(2*a + 2*b*x)/2 def test_FunctionOfDensePolynomialsQ(): assert FunctionOfDensePolynomialsQ(x**2 + 3, x) assert not FunctionOfDensePolynomialsQ(x**2, x) assert not FunctionOfDensePolynomialsQ(x, x) assert FunctionOfDensePolynomialsQ(S(2), x) def test_PureFunctionOfSinQ(): v = rubi_log(x) f = sin(v) assert PureFunctionOfSinQ(f, v, x) assert not PureFunctionOfSinQ(cos(v), v, x) assert PureFunctionOfSinQ(f**2, v, x) def test_PureFunctionOfTanQ(): v = rubi_log(x) f = tan(v) assert PureFunctionOfTanQ(f, v, x) assert not PureFunctionOfTanQ(cos(v), v, x) assert PureFunctionOfTanQ(f**2, v, x) def test_PowerVariableSubst(): assert PowerVariableSubst((2*x)**3, 2, x) == 8*x**(3/2) assert PowerVariableSubst((2*x)**3, 2, x) == 8*x**(3/2) assert PowerVariableSubst((2*x), 2, x) == 2*x assert PowerVariableSubst((2*x)**3, 2, x) == 8*x**(3/2) assert PowerVariableSubst((2*x)**7, 2, x) == 128*x**(7/2) assert PowerVariableSubst((6+2*x)**7, 2, x) == (2*x + 6)**7 assert PowerVariableSubst((2*x)**7+3, 2, x) == 128*x**(7/2) + 3 def test_PowerVariableDegree(): assert PowerVariableDegree(S(2), 0, 2*x, x) == [0, 2*x] assert PowerVariableDegree((2*x)**2, 0, 2*x, x) == [2, 1] assert PowerVariableDegree(x**2, 0, 2*x, x) == [2, 1] assert PowerVariableDegree(S(4), 0, 2*x, x) == [0, 2*x] def test_PowerVariableExpn(): assert not PowerVariableExpn((x)**3, 2, x) assert not PowerVariableExpn((2*x)**3, 2, x) assert PowerVariableExpn((2*x)**2, 4, x) == [4*x**3, 2, 1] def test_FunctionOfQ(): assert FunctionOfQ(x**2, sqrt(-exp(2*x**2) + 1)*exp(x**2),x) assert not FunctionOfQ(S(x**3), x*2, x) assert FunctionOfQ(S(a), x*2, x) assert FunctionOfQ(S(3*x), x*2, x) def test_ExpandTrigExpand(): assert ExpandTrigExpand(1, cos(x), x**2, 2, 2, x) == 4*cos(x**2)**4 - 4*cos(x**2)**2 + 1 assert ExpandTrigExpand(1, cos(x) + sin(x), x**2, 2, 2, x) == 4*sin(x**2)**2*cos(x**2)**2 + 8*sin(x**2)*cos(x**2)**3 - 4*sin(x**2)*cos(x**2) + 4*cos(x**2)**4 - 4*cos(x**2)**2 + 1 def test_TrigToExp(): from sympy.integrals.rubi.utility_function import rubi_exp as exp assert TrigToExp(sin(x)) == -I*(exp(I*x) - exp(-I*x))/2 assert TrigToExp(cos(x)) == exp(I*x)/2 + exp(-I*x)/2 assert TrigToExp(cos(x)*tan(x**2)) == I*(exp(I*x)/2 + exp(-I*x)/2)*(-exp(I*x**2) + exp(-I*x**2))/(exp(I*x**2) + exp(-I*x**2)) assert TrigToExp(cos(x) + sin(x)**2) == -(exp(I*x) - exp(-I*x))**2/4 + exp(I*x)/2 + exp(-I*x)/2 assert Simplify(TrigToExp(cos(x)*tan(x**S(2))*sin(x)**S(2))-(-I*(exp(I*x)/S(2) + exp(-I*x)/S(2))*(exp(I*x) - exp(-I*x))**S(2)*(-exp(I*x**S(2)) + exp(-I*x**S(2)))/(S(4)*(exp(I*x**S(2)) + exp(-I*x**S(2)))))) == 0 def test_ExpandTrigReduce(): assert ExpandTrigReduce(2*cos(3 + x)**3, x) == 3*cos(x + 3)/2 + cos(3*x + 9)/2 assert ExpandTrigReduce(2*sin(x)**3+cos(2 + x), x) == 3*sin(x)/2 - sin(3*x)/2 + cos(x + 2) assert ExpandTrigReduce(cos(x + 3)**2, x) == cos(2*x + 6)/2 + 1/2 def test_NormalizeTrig(): assert NormalizeTrig(S(2*sin(2 + x)), x) == 2*sin(x + 2) assert NormalizeTrig(S(2*sin(2 + x)**3), x) == 2*sin(x + 2)**3 assert NormalizeTrig(S(2*sin((2 + x)**2)**3), x) == 2*sin(x**2 + 4*x + 4)**3 def test_FunctionOfTrigQ(): v = rubi_log(x) s = sin(v) t = tan(v) assert not FunctionOfTrigQ(x, v, x) assert FunctionOfTrigQ(s + t, v, x) assert FunctionOfTrigQ(sin(t), v, x) def test_RationalFunctionExpand(): assert RationalFunctionExpand(x**S(5)*(e + f*x)**n/(a + b*x**S(3)), x) == -a*x**2*(e + f*x)**n/(b*(a + b*x**3)) +\ e**2*(e + f*x)**n/(b*f**2) - 2*e*(e + f*x)**(n + 1)/(b*f**2) + (e + f*x)**(n + 2)/(b*f**2) assert RationalFunctionExpand(x**S(3)*(S(2)*x + 2)**S(2)/(2*x**2 + 1), x) == 2*x**3 + 4*x**2 + x + (- x + 2)/(2*x**2 + 1) - 2 assert RationalFunctionExpand((a + b*x + c*x**4)*rubi_log(x)**3, x) == a*rubi_log(x)**3 + b*x*rubi_log(x)**3 + c*x**4*rubi_log(x)**3 assert RationalFunctionExpand(a + b*x + c*x**4, x) == a + b*x + c*x**4 def test_SameQ(): assert SameQ(1, 1, 1) assert not SameQ(1, 1, 2) def test_Map2(): assert Map2(Add, [a, b, c], [x, y, z]) == [a + x, b + y, c + z] def test_ConstantFactor(): assert ConstantFactor(a + a*x**3, x) == [a, x**3 + 1] assert ConstantFactor(a, x) == [a, 1] assert ConstantFactor(x, x) == [1, x] assert ConstantFactor(x**S(3), x) == [1, x**3] assert ConstantFactor(x**(S(3)/2), x) == [1, x**(3/2)] assert ConstantFactor(a*x**3, x) == [a, x**3] assert ConstantFactor(a + x**3, x) == [1, a + x**3] def test_CommonFactors(): assert CommonFactors([a, a, a]) == [a, 1, 1, 1] assert CommonFactors([x*S(2), x**S(3)*S(2), sin(x)*x*S(2)]) == [2, x, x**3, x*sin(x)] assert CommonFactors([x, x**S(3), sin(x)*x]) == [1, x, x**3, x*sin(x)] assert CommonFactors([S(2), S(4), S(6)]) == [2, 1, 2, 3] def test_FunctionOfLinear(): f = sin(a + b*x) assert FunctionOfLinear(f, x) == [sin(x), a, b] assert FunctionOfLinear(a + b*x, x) == [x, a, b] assert not FunctionOfLinear(a, x) def test_FunctionOfExponentialQ(): assert FunctionOfExponentialQ(exp(x + exp(x) + exp(exp(x))), x) assert FunctionOfExponentialQ(a**(a + b*x), x) assert FunctionOfExponentialQ(a**(b*x), x) assert not FunctionOfExponentialQ(a**sin(a + b*x), x) def test_FunctionOfExponential(): assert FunctionOfExponential(a**(a + b*x), x) def test_FunctionOfExponentialFunction(): assert FunctionOfExponentialFunction(a**(a + b*x), x) == x assert FunctionOfExponentialFunction(S(2)*a**(a + b*x), x) == 2*x def test_FunctionOfTrig(): assert FunctionOfTrig(sin(x + 1), x + 1, x) == x + 1 assert FunctionOfTrig(sin(x), x) == x assert not FunctionOfTrig(cos(x**2 + 1), x) assert FunctionOfTrig(sin(a+b*x)**3, x) == a+b*x def test_AlgebraicTrigFunctionQ(): assert AlgebraicTrigFunctionQ(sin(x + 3), x) assert AlgebraicTrigFunctionQ(x, x) assert AlgebraicTrigFunctionQ(x + 1, x) assert AlgebraicTrigFunctionQ(sinh(x + 1), x) assert AlgebraicTrigFunctionQ(sinh(x + 1)**2, x) assert not AlgebraicTrigFunctionQ(sinh(x**2 + 1)**2, x) def test_FunctionOfHyperbolic(): assert FunctionOfTrig(sin(x + 1), x + 1, x) == x + 1 assert FunctionOfTrig(sin(x), x) == x assert not FunctionOfTrig(cos(x**2 + 1), x) def test_FunctionOfExpnQ(): assert FunctionOfExpnQ(x, x, x) == 1 assert FunctionOfExpnQ(x**2, x, x) == 2 assert FunctionOfExpnQ(x**2.1, x, x) == 1 assert not FunctionOfExpnQ(x, x**2, x) assert not FunctionOfExpnQ(x + 1, (x + 5)**2, x) assert not FunctionOfExpnQ(x + 1, (x + 1)**2, x) def test_PureFunctionOfCosQ(): v = rubi_log(x) f = cos(v) assert PureFunctionOfCosQ(f, v, x) assert not PureFunctionOfCosQ(sin(v), v, x) assert PureFunctionOfCosQ(f**2, v, x) def test_PureFunctionOfCotQ(): v = rubi_log(x) f = cot(v) assert PureFunctionOfCotQ(f, v, x) assert not PureFunctionOfCotQ(sin(v), v, x) assert PureFunctionOfCotQ(f**2, v, x) def test_FunctionOfSinQ(): v = rubi_log(x) assert FunctionOfSinQ(cos(sin(v)), v, x) assert FunctionOfSinQ(sin(v), v, x) assert FunctionOfSinQ(sin(v)*cos(sin(v)), v, x) def test_FunctionOfCosQ(): v = rubi_log(x) assert FunctionOfCosQ(cos(cos(v)), v, x) assert FunctionOfCosQ(cos(v), v, x) assert FunctionOfCosQ(cos(v)*cos(cos(v)), v, x) def test_FunctionOfTanQ(): v = rubi_log(x) t = tan(v) c = cot(v) assert FunctionOfTanQ(t, v, x) assert FunctionOfTanQ(c, v, x) assert FunctionOfTanQ(t + c, v, x) assert FunctionOfTanQ(t*c, v, x) assert not FunctionOfTanQ(sin(x), v, x) def test_FunctionOfTanWeight(): v = rubi_log(x) t = tan(v) c = cot(v) assert FunctionOfTanWeight(x, v, x) == 0 assert FunctionOfTanWeight(sin(v), v, x) == 0 assert FunctionOfTanWeight(tan(v), v, x) == 1 assert FunctionOfTanWeight(cot(v), v, x) == -1 assert FunctionOfTanWeight(t**2, v, x) == 1 assert FunctionOfTanWeight(sin(v)**2, v, x) == -1 assert FunctionOfTanWeight(cot(v)*sin(v)**2, v, x) == -2 def test_OddTrigPowerQ(): assert not OddTrigPowerQ(sin(x)**3, 1, x) assert OddTrigPowerQ(sin(3),1,x) assert OddTrigPowerQ(sin(3*x),x,x) assert OddTrigPowerQ(sin(3*x)**3,x,x) def test_FunctionOfLog(): assert not FunctionOfLog(x**2*(a + b*x)**3*exp(-a - b*x) ,False, False, x) assert FunctionOfLog(rubi_log(2*x**8)*2 + rubi_log(2*x**8) + 1, x) == [3*x + 1, 2*x**8, 8] assert FunctionOfLog(rubi_log(2*x)**2,x) == [x**2, 2*x, 1] assert FunctionOfLog(rubi_log(3*x**3)**2 + 1,x) == [x**2 + 1, 3*x**3, 3] assert FunctionOfLog(rubi_log(2*x**8)*2,x) == [2*x, 2*x**8, 8] assert not FunctionOfLog(2*sin(x)*2,x) def test_EulerIntegrandQ(): assert EulerIntegrandQ((2*x + 3*((x + 1)**3)**1.5)**(-3), x) assert not EulerIntegrandQ((2*x + (2*x**2)**2)**3, x) assert not EulerIntegrandQ(3*x**2 + 5*x + 1, x) def test_Divides(): assert not Divides(x, a*x**2, x) assert Divides(x, a*x, x) == a def test_EasyDQ(): assert EasyDQ(3*x**2, x) assert EasyDQ(3*x**3 - 6, x) assert EasyDQ(x**3, x) assert EasyDQ(sin(x**rubi_log(3)), x) def test_ProductOfLinearPowersQ(): assert ProductOfLinearPowersQ(S(1), x) assert ProductOfLinearPowersQ((x + 1)**3, x) assert not ProductOfLinearPowersQ((x**2 + 1)**3, x) assert ProductOfLinearPowersQ(x + 1, x) def test_Rt(): b = symbols('b') assert Rt(-b**2, 4) == (-b**2)**(S(1)/S(4)) assert Rt(x**2, 2) == x assert Rt(S(2 + 3*I), S(8)) == (2 + 3*I)**(1/8) assert Rt(x**2 + 4 + 4*x, 2) == x + 2 assert Rt(S(8), S(3)) == 2 assert Rt(S(16807), S(5)) == 7 def test_NthRoot(): assert NthRoot(S(14580), S(3)) == 9*2**(S(2)/S(3))*5**(S(1)/S(3)) assert NthRoot(9, 2) == 3.0 assert NthRoot(81, 2) == 9.0 assert NthRoot(81, 4) == 3.0 def test_AtomBaseQ(): assert not AtomBaseQ(x**2) assert AtomBaseQ(x**3) assert AtomBaseQ(x) assert AtomBaseQ(S(2)**3) assert not AtomBaseQ(sin(x)) def test_SumBaseQ(): assert not SumBaseQ((x + 1)**2) assert SumBaseQ((x + 1)**3) assert SumBaseQ(3*x+3) assert not SumBaseQ(x) def test_NegSumBaseQ(): assert not NegSumBaseQ(-x + 1) assert NegSumBaseQ(x - 1) assert not NegSumBaseQ((x - 1)**2) assert NegSumBaseQ((x - 1)**3) def test_AllNegTermQ(): x = Symbol('x', negative=True) assert AllNegTermQ(x) assert not AllNegTermQ(x + 2) assert AllNegTermQ(x - 2) assert AllNegTermQ((x - 2)**3) assert not AllNegTermQ((x - 2)**2) def test_TrigSquareQ(): assert TrigSquareQ(sin(x)**2) assert TrigSquareQ(cos(x)**2) assert not TrigSquareQ(tan(x)**2) def test_Inequality(): assert not Inequality(S('0'), Less, m, LessEqual, S('1')) assert Inequality(S('0'), Less, S('1')) assert Inequality(S('0'), Less, S('1'), LessEqual, S('5')) def test_SplitProduct(): assert SplitProduct(OddQ, S(3)*x) == [3, x] assert not SplitProduct(OddQ, S(2)*x) def test_SplitSum(): assert SplitSum(FracPart, sin(x)) == [sin(x), 0] assert SplitSum(FracPart, sin(x) + S(2)) == [sin(x), S(2)] def test_Complex(): assert Complex(a, b) == a + I*b def test_SimpFixFactor(): assert SimpFixFactor((a*c + b*c)**S(4), x) == (a*c + b*c)**4 assert SimpFixFactor((a*Complex(0, c) + b*Complex(0, d))**S(3), x) == -I*(a*c + b*d)**3 assert SimpFixFactor((a*Complex(0, d) + b*Complex(0, e) + c*Complex(0, f))**S(2), x) == -(a*d + b*e + c*f)**2 assert SimpFixFactor((a + b*x**(-1/S(2))*x**S(3))**S(3), x) == (a + b*x**(5/2))**3 assert SimpFixFactor((a*c + b*c**S(2)*x**S(2))**S(3), x) == c**3*(a + b*c*x**2)**3 assert SimpFixFactor((a*c**S(2) + b*c**S(1)*x**S(2))**S(3), x) == c**3*(a*c + b*x**2)**3 assert SimpFixFactor(a*cos(x)**2 + a*sin(x)**2 + v, x) == a*cos(x)**2 + a*sin(x)**2 + v def test_SimplifyAntiderivative(): assert SimplifyAntiderivative(acoth(coth(x)), x) == x assert SimplifyAntiderivative(a*x, x) == a*x assert SimplifyAntiderivative(atanh(cot(x)), x) == atanh(2*sin(x)*cos(x))/2 assert SimplifyAntiderivative(a*cos(x)**2 + a*sin(x)**2 + v, x) == a*cos(x)**2 + a*sin(x)**2 def test_FixSimplify(): assert FixSimplify(x*Complex(0, a)*(v*Complex(0, b) + w)**S(3)) == a*x*(b*v - I*w)**3 def test_TrigSimplifyAux(): assert TrigSimplifyAux(a*cos(x)**2 + a*sin(x)**2 + v) == a + v assert TrigSimplifyAux(x**2) == x**2 def test_SubstFor(): assert SubstFor(x**2 + 1, tanh(x), x) == tanh(x) assert SubstFor(x**2, sinh(x), x) == sinh(sqrt(x)) def test_FresnelS(): assert FresnelS(oo) == 1/2 assert FresnelS(0) == 0 def test_FresnelC(): assert FresnelC(0) == 0 assert FresnelC(oo) == 1/2 def test_Erfc(): assert Erfc(0) == 1 assert Erfc(oo) == 0 def test_Erfi(): assert Erfi(oo) is oo assert Erfi(0) == 0 def test_Gamma(): assert Gamma(u) == gamma(u) def test_ElementaryFunctionQ(): assert ElementaryFunctionQ(x + y) assert ElementaryFunctionQ(sin(x + y)) assert ElementaryFunctionQ(E**(x*a)) def test_Util_Part(): from sympy.integrals.rubi.utility_function import Util_Part assert Util_Part(1, a + b).doit() == a assert Util_Part(c, a + b).doit() == Util_Part(c, a + b) def test_Part(): assert Part([1, 2, 3], 1) == 1 assert Part(a*b, 1) == a def test_PolyLog(): assert PolyLog(a, b) == polylog(a, b) def test_PureFunctionOfCothQ(): v = rubi_log(x) assert PureFunctionOfCothQ(coth(v), v, x) assert PureFunctionOfCothQ(a + coth(v), v, x) assert not PureFunctionOfCothQ(sin(v), v, x) def test_ExpandIntegrand(): assert ExpandIntegrand(sqrt(a + b*x**S(2) + c*x**S(4)), (f*x)**(S(3)/2)*(d + e*x**S(2)), x) == \ d*(f*x)**(3/2)*sqrt(a + b*x**2 + c*x**4) + e*(f*x)**(7/2)*sqrt(a + b*x**2 + c*x**4)/f**2 assert ExpandIntegrand((6*A*a*c - 2*A*b**2 + B*a*b - 2*c*x*(A*b - 2*B*a))/(x**2*(a + b*x + c*x**2)), x) == \ (6*A*a*c - 2*A*b**2 + B*a*b)/(a*x**2) + (-6*A*a**2*c**2 + 10*A*a*b**2*c - 2*A*b**4 - 5*B*a**2*b*c + B*a*b**3 + x*(8*A*a*b*c**2 - 2*A*b**3*c - 4*B*a**2*c**2 + B*a*b**2*c))/(a**2*(a + b*x + c*x**2)) + (-2*A*b + B*a)*(4*a*c - b**2)/(a**2*x) assert ExpandIntegrand(x**2*(e + f*x)**3*F**(a + b*(c + d*x)**1), x) == F**(a + b*(c + d*x))*e**2*(e + f*x)**3/f**2 - 2*F**(a + b*(c + d*x))*e*(e + f*x)**4/f**2 + F**(a + b*(c + d*x))*(e + f*x)**5/f**2 assert ExpandIntegrand((x)*(a + b*x)**2*f**(e*(c + d*x)**n), x) == a**2*f**(e*(c + d*x)**n)*x + 2*a*b*f**(e*(c + d*x)**n)*x**2 + b**2*f**(e*(c + d*x)**n)*x**3 assert ExpandIntegrand(sin(x)**3*(a + b*(1/sin(x)))**2, x) == a**2*sin(x)**3 + 2*a*b*sin(x)**2 + b**2*sin(x) assert ExpandIntegrand(x*(a + b*ArcSin(c + d*x))**n, x) == -c*(a + b*asin(c + d*x))**n/d + (a + b*asin(c + d*x))**n*(c + d*x)/d assert ExpandIntegrand((a + b*x)**S(3)*(A + B*x)/(c + d*x), x) == B*(a + b*x)**3/d + b*(a + b*x)**2*(A*d - B*c)/d**2 + b*(a + b*x)*(A*d - B*c)*(a*d - b*c)/d**3 + b*(A*d - B*c)*(a*d - b*c)**2/d**4 + (A*d - B*c)*(a*d - b*c)**3/(d**4*(c + d*x)) assert ExpandIntegrand((x**2)*(S(3)*x)**(S(1)/2), x) ==sqrt(3)*x**(5/2) assert ExpandIntegrand((x)*(sin(x))**(S(1)/2), x) == x*sqrt(sin(x)) assert ExpandIntegrand(x*(e + f*x)**2*F**(b*(c + d*x)), x) == -F**(b*(c + d*x))*e*(e + f*x)**2/f + F**(b*(c + d*x))*(e + f*x)**3/f assert ExpandIntegrand(x**m*(e + f*x)**2*F**(b*(c + d*x)**n), x) == F**(b*(c + d*x)**n)*e**2*x**m + 2*F**(b*(c + d*x)**n)*e*f*x*x**m + F**(b*(c + d*x)**n)*f**2*x**2*x**m assert simplify(ExpandIntegrand((S(1) - S(1)*x**S(2))**(-S(3)), x) - (-S(3)/(8*(x**2 - 1)) + S(3)/(16*(x + 1)**2) + S(1)/(S(8)*(x + 1)**3) + S(3)/(S(16)*(x - 1)**2) - S(1)/(S(8)*(x - 1)**3))) == 0 assert ExpandIntegrand(-S(1), 1/((-q - x)**3*(q - x)**3), x) == 1/(8*q**3*(q + x)**3) - 1/(8*q**3*(-q + x)**3) - 3/(8*q**4*(-q**2 + x**2)) + 3/(16*q**4*(q + x)**2) + 3/(16*q**4*(-q + x)**2) assert ExpandIntegrand((1 + 1*x)**(3)/(2 + 1*x), x) == x**2 + x + 1 - 1/(x + 2) assert ExpandIntegrand((c + d*x**1 + e*x**2)/(1 - x**3), x) == (c - (-1)**(S(1)/3)*d + (-1)**(S(2)/3)*e)/(-3*(-1)**(S(2)/3)*x + 3) + (c + (-1)**(S(2)/3)*d - (-1)**(S(1)/3)*e)/(3*(-1)**(S(1)/3)*x + 3) + (c + d + e)/(-3*x + 3) assert ExpandIntegrand((c + d*x**1 + e*x**2 + f*x**3)/(1 - x**4), x) == (c + I*d - e - I*f)/(4*I*x + 4) + (c - I*d - e + I*f)/(-4*I*x + 4) + (c - d + e - f)/(4*x + 4) + (c + d + e + f)/(-4*x + 4) assert ExpandIntegrand((d + e*(f + g*x))/(2 + 3*x + 1*x**2), x) == (-2*d - 2*e*f + 4*e*g)/(2*x + 4) + (2*d + 2*e*f - 2*e*g)/(2*x + 2) assert ExpandIntegrand(x/(a*x**3 + b*Sqrt(c + d*x**6)), x) == a*x**4/(-b**2*c + x**6*(a**2 - b**2*d)) + b*x*sqrt(c + d*x**6)/(b**2*c + x**6*(-a**2 + b**2*d)) assert simplify(ExpandIntegrand(x**1*(1 - x**4)**(-2), x) - (x/(S(4)*(x**2 + 1)) + x/(S(4)*(x**2 + 1)**2) - x/(S(4)*(x**2 - 1)) + x/(S(4)*(x**2 - 1)**2))) == 0 assert simplify(ExpandIntegrand((-1 + x**S(6))**(-3), x) - (S(3)/(S(8)*(x**6 - 1)) - S(3)/(S(16)*(x**S(3) + S(1))**S(2)) - S(1)/(S(8)*(x**S(3) + S(1))**S(3)) - S(3)/(S(16)*(x**S(3) - S(1))**S(2)) + S(1)/(S(8)*(x**S(3) - S(1))**S(3)))) == 0 assert simplify(ExpandIntegrand(u**1*(a + b*u**2 + c*u**4)**(-1), x)) == simplify(1/(2*b*(u + sqrt(-(a + c*u**4)/b))) - 1/(2*b*(-u + sqrt(-(a + c*u**4)/b)))) assert simplify(ExpandIntegrand((1 + 1*u + 1*u**2)**(-2), x) - (S(1)/(S(2)*(-u - 1)*(-u**2 - u - 1)) + S(1)/(S(4)*(-u - 1)*(u + sqrt(-u - 1))**2) + S(1)/(S(4)*(-u - 1)*(u - sqrt(-u - 1))**2))) == 0 assert ExpandIntegrand(x*(a + b*Log(c*(d*(e + f*x)**p)**q))**n, x) == -e*(a + b*rubi_log(c*(d*(e + f*x)**p)**q))**n/f + (a + b*rubi_log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)/f assert ExpandIntegrand(x*f**(e*(c + d*x)*S(1)), x) == f**(e*(c + d*x))*x assert simplify(ExpandIntegrand((x)*(a + b*x)**m*Log(c*(d + e*x**n)**p), x) - (-a*(a + b*x)**m*rubi_log(c*(d + e*x**n)**p)/b + (a + b*x)**(m + S(1))*rubi_log(c*(d + e*x**n)**p)/b)) == 0 assert simplify(ExpandIntegrand(u*(a + b*F**v)**S(2)*(c + d*F**v)**S(-3), x) - (b**2*u/(d**2*(F**v*d + c)) + 2*b*u*(a*d - b*c)/(d**2*(F**v*d + c)**2) + u*(a*d - b*c)**2/(d**2*(F**v*d + c)**3))) == 0 assert ExpandIntegrand((S(1) + 1*x)**S(2)*f**(e*(1 + S(1)*x)**n)/(g + h*x), x) == f**(e*(x + 1)**n)*(x + 1)/h + f**(e*(x + 1)**n)*(-g + h)/h**2 + f**(e*(x + 1)**n)*(g - h)**2/(h**2*(g + h*x)) assert ExpandIntegrand((a*c - b*c*x)**2/(a + b*x)**2, x) == 4*a**2*c**2/(a + b*x)**2 - 4*a*c**2/(a + b*x) + c**2 assert simplify(ExpandIntegrand(x**2*(1 - 1*x**2)**(-2), x) - (1/(S(2)*(x**2 - 1)) + 1/(S(4)*(x + 1)**2) + 1/(S(4)*(x - 1)**2))) == 0 assert ExpandIntegrand((a + x)**2, x) == a**2 + 2*a*x + x**2 assert ExpandIntegrand((a + b*x)**S(2)/x**3, x) == a**2/x**3 + 2*a*b/x**2 + b**2/x assert ExpandIntegrand(1/(x**2*(a + b*x)**2), x) == b**2/(a**2*(a + b*x)**2) + 1/(a**2*x**2) + 2*b**2/(a**3*(a + b*x)) - 2*b/(a**3*x) assert ExpandIntegrand((1 + x)**3/x, x) == x**2 + 3*x + 3 + 1/x assert ExpandIntegrand((1 + 2*(3 + 4*x**2))/(2 + 3*x**2 + 1*x**4), x) == 18/(2*x**2 + 4) - 2/(2*x**2 + 2) assert ExpandIntegrand((c + d*x**2 + e*x**3)/(1 - 1*x**4), x) == (c - d - I*e)/(4*I*x + 4) + (c - d + I*e)/(-4*I*x + 4) + (c + d - e)/(4*x + 4) + (c + d + e)/(-4*x + 4) assert ExpandIntegrand((a + b*x)**2/(c + d*x), x) == b*(a + b*x)/d + b*(a*d - b*c)/d**2 + (a*d - b*c)**2/(d**2*(c + d*x)) assert ExpandIntegrand(x**2*(a + b*Log(c*(d*(e + f*x)**p)**q))**n, x) == e**2*(a + b*rubi_log(c*(d*(e + f*x)**p)**q))**n/f**2 - 2*e*(a + b*rubi_log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)/f**2 + (a + b*rubi_log(c*(d*(e + f*x)**p)**q))**n*(e + f*x)**2/f**2 assert ExpandIntegrand(x*(1 + 2*x)**3*rubi_log(2*(1 + 1*x**2)**1), x) == 8*x**4*rubi_log(2*x**2 + 2) + 12*x**3*rubi_log(2*x**2 + 2) + 6*x**2*rubi_log(2*x**2 + 2) + x*rubi_log(2*x**2 + 2) assert ExpandIntegrand((1 + 1*x)**S(3)*f**(e*(1 + 1*x)**n)/(g + h*x), x) == f**(e*(x + 1)**n)*(x + 1)**2/h + f**(e*(x + 1)**n)*(-g + h)*(x + 1)/h**2 + f**(e*(x + 1)**n)*(-g + h)**2/h**3 - f**(e*(x + 1)**n)*(g - h)**3/(h**3*(g + h*x)) def test_Dist(): assert Dist(x, a + b, x) == a*x + b*x assert Dist(x, Integral(a + b , x), x) == x*Integral(a + b, x) assert Dist(3*x,(a+b), x) - Dist(2*x, (a+b), x) == a*x + b*x assert Dist(3*x,(a+b), x) + Dist(2*x, (a+b), x) == 5*a*x + 5*b*x assert Dist(x, c*Integral((a + b), x), x) == c*x*Integral(a + b, x) def test_IntegralFreeQ(): assert not IntegralFreeQ(Integral(a, x)) assert IntegralFreeQ(a + b) def test_OneQ(): from sympy.integrals.rubi.utility_function import OneQ assert OneQ(S(1)) assert not OneQ(S(2)) def test_DerivativeDivides(): assert not DerivativeDivides(x, x, x) assert not DerivativeDivides(a, x + y, b) assert DerivativeDivides(a + x, a, x) == a assert DerivativeDivides(a + b, x + y, b) == x + y def test_LogIntegral(): from sympy.integrals.rubi.utility_function import LogIntegral assert LogIntegral(a) == li(a) def test_SinIntegral(): from sympy.integrals.rubi.utility_function import SinIntegral assert SinIntegral(a) == Si(a) def test_CosIntegral(): from sympy.integrals.rubi.utility_function import CosIntegral assert CosIntegral(a) == Ci(a) def test_SinhIntegral(): from sympy.integrals.rubi.utility_function import SinhIntegral assert SinhIntegral(a) == Shi(a) def test_CoshIntegral(): from sympy.integrals.rubi.utility_function import CoshIntegral assert CoshIntegral(a) == Chi(a) def test_ExpIntegralEi(): from sympy.integrals.rubi.utility_function import ExpIntegralEi assert ExpIntegralEi(a) == Ei(a) def test_ExpIntegralE(): from sympy.integrals.rubi.utility_function import ExpIntegralE assert ExpIntegralE(a, z) == expint(a, z) def test_LogGamma(): from sympy.integrals.rubi.utility_function import LogGamma assert LogGamma(a) == loggamma(a) def test_Factorial(): from sympy.integrals.rubi.utility_function import Factorial assert Factorial(S(5)) == 120 def test_Zeta(): from sympy.integrals.rubi.utility_function import Zeta assert Zeta(a, z) == zeta(a, z) def test_HypergeometricPFQ(): from sympy.integrals.rubi.utility_function import HypergeometricPFQ assert HypergeometricPFQ([a, b], [c], z) == hyper([a, b], [c], z) def test_PolyGamma(): assert PolyGamma(S(2), S(3)) == polygamma(2, 3) def test_ProductLog(): from sympy import N assert N(ProductLog(S(5.0)), 5) == N(1.32672466524220, 5) assert N(ProductLog(S(2), S(3.5)), 5) == N(-1.14064876353898 + 10.8912237027092*I, 5) def test_PolynomialQuotient(): assert PolynomialQuotient(rubi_log((-a*d + b*c)/(b*(c + d*x)))/(c + d*x), a + b*x, e) == rubi_log((-a*d + b*c)/(b*(c + d*x)))/((a + b*x)*(c + d*x)) assert PolynomialQuotient(x**2, x + a, x) == -a + x def test_PolynomialRemainder(): assert PolynomialRemainder(rubi_log((-a*d + b*c)/(b*(c + d*x)))/(c + d*x), a + b*x, e) == 0 assert PolynomialRemainder(x**2, x + a, x) == a**2 def test_Floor(): assert Floor(S(7.5)) == 7 assert Floor(S(15.5), S(6)) == 12 def test_Factor(): from sympy.integrals.rubi.utility_function import Factor assert Factor(a*b + a*c) == a*(b + c) def test_Rule(): from sympy.integrals.rubi.utility_function import Rule assert Rule(x, S(5)) == {x: 5} def test_Distribute(): assert Distribute((a + b)*c + (a + b)*d, Add) == c*(a + b) + d*(a + b) assert Distribute((a + b)*(c + e), Add) == a*c + a*e + b*c + b*e def test_CoprimeQ(): assert CoprimeQ(S(7), S(5)) assert not CoprimeQ(S(6), S(3)) def test_Discriminant(): from sympy.integrals.rubi.utility_function import Discriminant assert Discriminant(a*x**2 + b*x + c, x) == b**2 - 4*a*c assert unchanged(Discriminant, 1/x, x) def test_Sum_doit(): assert Sum_doit(2*x + 2, [x, 0, 1.7]) == 6 def test_DeactivateTrig(): assert DeactivateTrig(sec(a + b*x), x) == sec(a + b*x) def test_Negative(): from sympy.integrals.rubi.utility_function import Negative assert Negative(S(-2)) assert not Negative(S(0)) def test_Quotient(): from sympy.integrals.rubi.utility_function import Quotient assert Quotient(17, 5) == 3 def test_process_trig(): assert process_trig(x*cot(x)) == x/tan(x) assert process_trig(coth(x)*csc(x)) == S(1)/(tanh(x)*sin(x)) def test_replace_pow_exp(): assert replace_pow_exp(rubi_exp(S(5))) == exp(S(5)) def test_rubi_unevaluated_expr(): from sympy.integrals.rubi.utility_function import rubi_unevaluated_expr assert rubi_unevaluated_expr(a)*rubi_unevaluated_expr(b) == rubi_unevaluated_expr(b)*rubi_unevaluated_expr(a) def test_rubi_exp(): # class name in utility_function is `exp`. To avoid confusion `rubi_exp` has been used here assert isinstance(rubi_exp(a), Pow) def test_rubi_log(): # class name in utility_function is `log`. To avoid confusion `rubi_log` has been used here assert rubi_log(rubi_exp(S(a))) == a sympy-sympy-1.9/sympy/integrals/rubi/utility_function.py000066400000000000000000010156101412543434000240230ustar00rootroot00000000000000""" Utility functions for Rubi integration. See: http://www.apmaths.uwo.ca/~arich/IntegrationRules/PortableDocumentFiles/Integration%20utility%20functions.pdf """ from sympy.external import import_module matchpy = import_module("matchpy") from sympy import (Basic, E, polylog, N, Wild, WildFunction, factor, gcd, Sum, S, I, Mul, Integer, Float, Dict, Symbol, Rational, Add, hyper, symbols, sqf_list, sqf, Max, factorint, factorrat, Min, sign, E, Function, collect, FiniteSet, nsimplify, expand_trig, expand, poly, apart, lcm, And, Pow, pi, zoo, oo, Integral, UnevaluatedExpr, PolynomialError, Dummy, exp as sym_exp, powdenest, PolynomialDivisionFailed, discriminant, UnificationFailed, appellf1) from sympy.core.exprtools import factor_terms from sympy.core.sympify import sympify from sympy.functions import (log as sym_log, sin, cos, tan, cot, csc, sec, sqrt, erf, gamma, uppergamma, polygamma, digamma, loggamma, factorial, zeta, LambertW) from sympy.functions.elementary.complexes import im, re, Abs from sympy.functions.elementary.hyperbolic import acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch from sympy.functions.elementary.integers import floor, frac from sympy.functions.elementary.trigonometric import atan, acsc, asin, acot, acos, asec, atan2 from sympy.functions.special.elliptic_integrals import elliptic_f, elliptic_e, elliptic_pi from sympy.functions.special.error_functions import fresnelc, fresnels, erfc, erfi, Ei, expint, li, Si, Ci, Shi, Chi from sympy.functions.special.hyper import TupleArg from sympy.logic.boolalg import Or from sympy.polys.polytools import Poly, quo, rem, total_degree, degree from sympy.simplify.simplify import fraction, simplify, cancel, powsimp from sympy.utilities.decorator import doctest_depends_on from sympy.utilities.iterables import flatten, postorder_traversal from random import randint class rubi_unevaluated_expr(UnevaluatedExpr): """ This is needed to convert `exp` as `Pow`. sympy's UnevaluatedExpr has an issue with `is_commutative`. """ @property def is_commutative(self): from sympy.core.logic import fuzzy_and return fuzzy_and(a.is_commutative for a in self.args) _E = rubi_unevaluated_expr(E) class rubi_exp(Function): """ sympy's exp is not identified as `Pow`. So it is not matched with `Pow`. Like `a = exp(2)` is not identified as `Pow(E, 2)`. Rubi rules need it. So, another exp has been created only for rubi module. Examples ======== >>> from sympy import Pow, exp as sym_exp >>> isinstance(sym_exp(2), Pow) False >>> from sympy.integrals.rubi.utility_function import rubi_exp >>> isinstance(rubi_exp(2), Pow) True """ @classmethod def eval(cls, *args): return Pow(_E, args[0]) class rubi_log(Function): """ For rule matching different `exp` has been used. So for proper results, `log` is modified little only for case when it encounters rubi's `exp`. For other cases it is same. Examples ======== >>> from sympy.integrals.rubi.utility_function import rubi_exp, rubi_log >>> a = rubi_exp(2) >>> rubi_log(a) 2 """ @classmethod def eval(cls, *args): if args[0].has(_E): return sym_log(args[0]).doit() else: return sym_log(args[0]) if matchpy: from matchpy import Arity, Operation, CustomConstraint, Pattern, ReplacementRule, ManyToOneReplacer from sympy.integrals.rubi.symbol import WC from matchpy import is_match, replace_all class UtilityOperator(Operation): name = 'UtilityOperator' arity = Arity.variadic commutative = False associative = True Operation.register(rubi_log) Operation.register(rubi_exp) A_, B_, C_, F_, G_, a_, b_, c_, d_, e_, f_, g_, h_, i_, j_, k_, l_, m_, \ n_, p_, q_, r_, t_, u_, v_, s_, w_, x_, z_ = [WC(i) for i in 'ABCFGabcdefghijklmnpqrtuvswxz'] a, b, c, d, e = symbols('a b c d e') Int = Integral def replace_pow_exp(z): """ This function converts back rubi's `exp` to general sympy's `exp`. Examples ======== >>> from sympy.integrals.rubi.utility_function import rubi_exp, replace_pow_exp >>> expr = rubi_exp(5) >>> expr E**5 >>> replace_pow_exp(expr) exp(5) """ z = S(z) if z.has(_E): z = z.replace(_E, E) return z def Simplify(expr): expr = simplify(expr) return expr def Set(expr, value): return {expr: value} def With(subs, expr): if isinstance(subs, dict): k = list(subs.keys())[0] expr = expr.xreplace({k: subs[k]}) else: for i in subs: k = list(i.keys())[0] expr = expr.xreplace({k: i[k]}) return expr def Module(subs, expr): return With(subs, expr) def Scan(f, expr): # evaluates f applied to each element of expr in turn. for i in expr: yield f(i) def MapAnd(f, l, x=None): # MapAnd[f,l] applies f to the elements of list l until False is returned; else returns True if x: for i in l: if f(i, x) == False: return False return True else: for i in l: if f(i) == False: return False return True def FalseQ(u): if isinstance(u, (Dict, dict)): return FalseQ(*list(u.values())) return u == False def ZeroQ(*expr): if len(expr) == 1: if isinstance(expr[0], list): return list(ZeroQ(i) for i in expr[0]) else: return Simplify(expr[0]) == 0 else: return all(ZeroQ(i) for i in expr) def OneQ(a): if a == S(1): return True return False def NegativeQ(u): u = Simplify(u) if u in (zoo, oo): return False if u.is_comparable: res = u < 0 if not res.is_Relational: return res return False def NonzeroQ(expr): return Simplify(expr) != 0 def FreeQ(nodes, var): if isinstance(nodes, list): return not any(S(expr).has(var) for expr in nodes) else: nodes = S(nodes) return not nodes.has(var) def NFreeQ(nodes, var): """ Note that in rubi 4.10.8 this function was not defined in `Integration Utility Functions.m`, but was used in rules. So explicitly its returning `False` """ return False # return not FreeQ(nodes, var) def List(*var): return list(var) def PositiveQ(var): var = Simplify(var) if var in (zoo, oo): return False if var.is_comparable: res = var > 0 if not res.is_Relational: return res return False def PositiveIntegerQ(*args): return all(var.is_Integer and PositiveQ(var) for var in args) def NegativeIntegerQ(*args): return all(var.is_Integer and NegativeQ(var) for var in args) def IntegerQ(var): var = Simplify(var) if isinstance(var, (int, Integer)): return True else: return var.is_Integer def IntegersQ(*var): return all(IntegerQ(i) for i in var) def _ComplexNumberQ(var): i = S(im(var)) if isinstance(i, (Integer, Float)): return i != 0 else: return False def ComplexNumberQ(*var): """ ComplexNumberQ(m, n,...) returns True if m, n, ... are all explicit complex numbers, else it returns False. Examples ======== >>> from sympy.integrals.rubi.utility_function import ComplexNumberQ >>> from sympy import I >>> ComplexNumberQ(1 + I*2, I) True >>> ComplexNumberQ(2, I) False """ return all(_ComplexNumberQ(i) for i in var) def PureComplexNumberQ(*var): return all((_ComplexNumberQ(i) and re(i)==0) for i in var) def RealNumericQ(u): return u.is_real def PositiveOrZeroQ(u): return u.is_real and u >= 0 def NegativeOrZeroQ(u): return u.is_real and u <= 0 def FractionOrNegativeQ(u): return FractionQ(u) or NegativeQ(u) def NegQ(var): return Not(PosQ(var)) and NonzeroQ(var) def Equal(a, b): return a == b def Unequal(a, b): return a != b def IntPart(u): # IntPart[u] returns the sum of the integer terms of u. if ProductQ(u): if IntegerQ(First(u)): return First(u)*IntPart(Rest(u)) elif IntegerQ(u): return u elif FractionQ(u): return IntegerPart(u) elif SumQ(u): res = 0 for i in u.args: res += IntPart(i) return res return 0 def FracPart(u): # FracPart[u] returns the sum of the non-integer terms of u. if ProductQ(u): if IntegerQ(First(u)): return First(u)*FracPart(Rest(u)) if IntegerQ(u): return 0 elif FractionQ(u): return FractionalPart(u) elif SumQ(u): res = 0 for i in u.args: res += FracPart(i) return res else: return u def RationalQ(*nodes): return all(var.is_Rational for var in nodes) def ProductQ(expr): return S(expr).is_Mul def SumQ(expr): return expr.is_Add def NonsumQ(expr): return not SumQ(expr) def Subst(a, x, y): if None in [a, x, y]: return None if a.has(Function('Integrate')): # substituting in `Function(Integrate)` won't take care of properties of Integral a = a.replace(Function('Integrate'), Integral) return a.subs(x, y) # return a.xreplace({x: y}) def First(expr, d=None): """ Gives the first element if it exists, or d otherwise. Examples ======== >>> from sympy.integrals.rubi.utility_function import First >>> from sympy.abc import a, b, c >>> First(a + b + c) a >>> First(a*b*c) a """ if isinstance(expr, list): return expr[0] if isinstance(expr, Symbol): return expr else: if SumQ(expr) or ProductQ(expr): l = Sort(expr.args) return l[0] else: return expr.args[0] def Rest(expr): """ Gives rest of the elements if it exists Examples ======== >>> from sympy.integrals.rubi.utility_function import Rest >>> from sympy.abc import a, b, c >>> Rest(a + b + c) b + c >>> Rest(a*b*c) b*c """ if isinstance(expr, list): return expr[1:] else: if SumQ(expr) or ProductQ(expr): l = Sort(expr.args) return expr.func(*l[1:]) else: return expr.args[1] def SqrtNumberQ(expr): # SqrtNumberQ[u] returns True if u^2 is a rational number; else it returns False. if PowerQ(expr): m = expr.base n = expr.exp return (IntegerQ(n) and SqrtNumberQ(m)) or (IntegerQ(n-S(1)/2) and RationalQ(m)) elif expr.is_Mul: return all(SqrtNumberQ(i) for i in expr.args) else: return RationalQ(expr) or expr == I def SqrtNumberSumQ(u): return SumQ(u) and SqrtNumberQ(First(u)) and SqrtNumberQ(Rest(u)) or ProductQ(u) and SqrtNumberQ(First(u)) and SqrtNumberSumQ(Rest(u)) def LinearQ(expr, x): """ LinearQ(expr, x) returns True iff u is a polynomial of degree 1. Examples ======== >>> from sympy.integrals.rubi.utility_function import LinearQ >>> from sympy.abc import x, y, a >>> LinearQ(a, x) False >>> LinearQ(3*x + y**2, x) True >>> LinearQ(3*x + y**2, y) False """ if isinstance(expr, list): return all(LinearQ(i, x) for i in expr) elif expr.is_polynomial(x): if degree(Poly(expr, x), gen=x) == 1: return True return False def Sqrt(a): return sqrt(a) def ArcCosh(a): return acosh(a) class Util_Coefficient(Function): def doit(self): if len(self.args) == 2: n = 1 else: n = Simplify(self.args[2]) if NumericQ(n): expr = expand(self.args[0]) if isinstance(n, (int, Integer)): return expr.coeff(self.args[1], n) else: return expr.coeff(self.args[1]**n) else: return self def Coefficient(expr, var, n=1): """ Coefficient(expr, var) gives the coefficient of form in the polynomial expr. Coefficient(expr, var, n) gives the coefficient of var**n in expr. Examples ======== >>> from sympy.integrals.rubi.utility_function import Coefficient >>> from sympy.abc import x, a, b, c >>> Coefficient(7 + 2*x + 4*x**3, x, 1) 2 >>> Coefficient(a + b*x + c*x**3, x, 0) a >>> Coefficient(a + b*x + c*x**3, x, 4) 0 >>> Coefficient(b*x + c*x**3, x, 3) c """ if NumericQ(n): if expr == 0 or n in (zoo, oo): return 0 expr = expand(expr) if isinstance(n, (int, Integer)): return expr.coeff(var, n) else: return expr.coeff(var**n) return Util_Coefficient(expr, var, n) def Denominator(var): var = Simplify(var) if isinstance(var, Pow): if isinstance(var.exp, Integer): if var.exp > 0: return Pow(Denominator(var.base), var.exp) elif var.exp < 0: return Pow(Numerator(var.base), -1*var.exp) elif isinstance(var, Add): var = factor(var) return fraction(var)[1] def Hypergeometric2F1(a, b, c, z): return hyper([a, b], [c], z) def Not(var): if isinstance(var, bool): return not var elif var.is_Relational: var = False return not var def FractionalPart(a): return frac(a) def IntegerPart(a): return floor(a) def AppellF1(a, b1, b2, c, x, y): return appellf1(a, b1, b2, c, x, y) def EllipticPi(*args): return elliptic_pi(*args) def EllipticE(*args): return elliptic_e(*args) def EllipticF(Phi, m): return elliptic_f(Phi, m) def ArcTan(a, b = None): if b is None: return atan(a) else: return atan2(a, b) def ArcCot(a): return acot(a) def ArcCoth(a): return acoth(a) def ArcTanh(a): return atanh(a) def ArcSin(a): return asin(a) def ArcSinh(a): return asinh(a) def ArcCos(a): return acos(a) def ArcCsc(a): return acsc(a) def ArcSec(a): return asec(a) def ArcCsch(a): return acsch(a) def ArcSech(a): return asech(a) def Sinh(u): return sinh(u) def Tanh(u): return tanh(u) def Cosh(u): return cosh(u) def Sech(u): return sech(u) def Csch(u): return csch(u) def Coth(u): return coth(u) def LessEqual(*args): for i in range(0, len(args) - 1): try: if args[i] > args[i + 1]: return False except (IndexError, NotImplementedError): return False return True def Less(*args): for i in range(0, len(args) - 1): try: if args[i] >= args[i + 1]: return False except (IndexError, NotImplementedError): return False return True def Greater(*args): for i in range(0, len(args) - 1): try: if args[i] <= args[i + 1]: return False except (IndexError, NotImplementedError): return False return True def GreaterEqual(*args): for i in range(0, len(args) - 1): try: if args[i] < args[i + 1]: return False except (IndexError, NotImplementedError): return False return True def FractionQ(*args): """ FractionQ(m, n,...) returns True if m, n, ... are all explicit fractions, else it returns False. Examples ======== >>> from sympy import S >>> from sympy.integrals.rubi.utility_function import FractionQ >>> FractionQ(S('3')) False >>> FractionQ(S('3')/S('2')) True """ return all(i.is_Rational for i in args) and all(Denominator(i) != S(1) for i in args) def IntLinearcQ(a, b, c, d, m, n, x): # returns True iff (a+b*x)^m*(c+d*x)^n is integrable wrt x in terms of non-hypergeometric functions. return IntegerQ(m) or IntegerQ(n) or IntegersQ(S(3)*m, S(3)*n) or IntegersQ(S(4)*m, S(4)*n) or IntegersQ(S(2)*m, S(6)*n) or IntegersQ(S(6)*m, S(2)*n) or IntegerQ(m + n) Defer = UnevaluatedExpr def Expand(expr): return expr.expand() def IndependentQ(u, x): """ If u is free from x IndependentQ(u, x) returns True else False. Examples ======== >>> from sympy.integrals.rubi.utility_function import IndependentQ >>> from sympy.abc import x, a, b >>> IndependentQ(a + b*x, x) False >>> IndependentQ(a + b, x) True """ return FreeQ(u, x) def PowerQ(expr): return expr.is_Pow or ExpQ(expr) def IntegerPowerQ(u): if isinstance(u, sym_exp): #special case for exp return IntegerQ(u.args[0]) return PowerQ(u) and IntegerQ(u.args[1]) def PositiveIntegerPowerQ(u): if isinstance(u, sym_exp): return IntegerQ(u.args[0]) and PositiveQ(u.args[0]) return PowerQ(u) and IntegerQ(u.args[1]) and PositiveQ(u.args[1]) def FractionalPowerQ(u): if isinstance(u, sym_exp): return FractionQ(u.args[0]) return PowerQ(u) and FractionQ(u.args[1]) def AtomQ(expr): expr = sympify(expr) if isinstance(expr, list): return False if expr in [None, True, False, _E]: # [None, True, False] are atoms in mathematica and _E is also an atom return True # elif isinstance(expr, list): # return all(AtomQ(i) for i in expr) else: return expr.is_Atom def ExpQ(u): u = replace_pow_exp(u) return Head(u) in (sym_exp, rubi_exp) def LogQ(u): return u.func in (sym_log, Log) def Head(u): return u.func def MemberQ(l, u): if isinstance(l, list): return u in l else: return u in l.args def TrigQ(u): if AtomQ(u): x = u else: x = Head(u) return MemberQ([sin, cos, tan, cot, sec, csc], x) def SinQ(u): return Head(u) == sin def CosQ(u): return Head(u) == cos def TanQ(u): return Head(u) == tan def CotQ(u): return Head(u) == cot def SecQ(u): return Head(u) == sec def CscQ(u): return Head(u) == csc def Sin(u): return sin(u) def Cos(u): return cos(u) def Tan(u): return tan(u) def Cot(u): return cot(u) def Sec(u): return sec(u) def Csc(u): return csc(u) def HyperbolicQ(u): if AtomQ(u): x = u else: x = Head(u) return MemberQ([sinh, cosh, tanh, coth, sech, csch], x) def SinhQ(u): return Head(u) == sinh def CoshQ(u): return Head(u) == cosh def TanhQ(u): return Head(u) == tanh def CothQ(u): return Head(u) == coth def SechQ(u): return Head(u) == sech def CschQ(u): return Head(u) == csch def InverseTrigQ(u): if AtomQ(u): x = u else: x = Head(u) return MemberQ([asin, acos, atan, acot, asec, acsc], x) def SinCosQ(f): return MemberQ([sin, cos, sec, csc], Head(f)) def SinhCoshQ(f): return MemberQ([sinh, cosh, sech, csch], Head(f)) def LeafCount(expr): return len(list(postorder_traversal(expr))) def Numerator(u): u = Simplify(u) if isinstance(u, Pow): if isinstance(u.exp, Integer): if u.exp > 0: return Pow(Numerator(u.base), u.exp) elif u.exp < 0: return Pow(Denominator(u.base), -1*u.exp) elif isinstance(u, Add): u = factor(u) return fraction(u)[0] def NumberQ(u): if isinstance(u, (int, float)): return True return u.is_number def NumericQ(u): return N(u).is_number def Length(expr): """ Returns number of elements in the expression just as sympy's len. Examples ======== >>> from sympy.integrals.rubi.utility_function import Length >>> from sympy.abc import x, a, b >>> from sympy import cos, sin >>> Length(a + b) 2 >>> Length(sin(a)*cos(a)) 2 """ if isinstance(expr, list): return len(expr) return len(expr.args) def ListQ(u): return isinstance(u, list) def Im(u): u = S(u) return im(u.doit()) def Re(u): u = S(u) return re(u.doit()) def InverseHyperbolicQ(u): if not u.is_Atom: u = Head(u) return u in [acosh, asinh, atanh, acoth, acsch, acsch] def InverseFunctionQ(u): # returns True if u is a call on an inverse function; else returns False. return LogQ(u) or InverseTrigQ(u) and Length(u) <= 1 or InverseHyperbolicQ(u) or u.func == polylog def TrigHyperbolicFreeQ(u, x): # If u is free of trig, hyperbolic and calculus functions involving x, TrigHyperbolicFreeQ[u,x] returns true; else it returns False. if AtomQ(u): return True else: if TrigQ(u) | HyperbolicQ(u) | CalculusQ(u): return FreeQ(u, x) else: for i in u.args: if not TrigHyperbolicFreeQ(i, x): return False return True def InverseFunctionFreeQ(u, x): # If u is free of inverse, calculus and hypergeometric functions involving x, InverseFunctionFreeQ[u,x] returns true; else it returns False. if AtomQ(u): return True else: if InverseFunctionQ(u) or CalculusQ(u) or u.func == hyper or u.func == appellf1: return FreeQ(u, x) else: for i in u.args: if not ElementaryFunctionQ(i): return False return True def RealQ(u): if ListQ(u): return MapAnd(RealQ, u) elif NumericQ(u): return ZeroQ(Im(N(u))) elif PowerQ(u): u = u.base v = u.exp return RealQ(u) & RealQ(v) & (IntegerQ(v) | PositiveOrZeroQ(u)) elif u.is_Mul: return all(RealQ(i) for i in u.args) elif u.is_Add: return all(RealQ(i) for i in u.args) elif u.is_Function: f = u.func u = u.args[0] if f in [sin, cos, tan, cot, sec, csc, atan, acot, erf]: return RealQ(u) else: if f in [asin, acos]: return LE(-1, u, 1) else: if f == sym_log: return PositiveOrZeroQ(u) else: return False else: return False def EqQ(u, v): return ZeroQ(u - v) def FractionalPowerFreeQ(u): if AtomQ(u): return True elif FractionalPowerQ(u): return False def ComplexFreeQ(u): if AtomQ(u) and Not(ComplexNumberQ(u)): return True else: return False def PolynomialQ(u, x = None): if x is None : return u.is_polynomial() if isinstance(x, Pow): if isinstance(x.exp, Integer): deg = degree(u, x.base) if u.is_polynomial(x): if deg % x.exp !=0 : return False try: p = Poly(u, x.base) except PolynomialError: return False c_list = p.all_coeffs() coeff_list = c_list[:-1:x.exp] coeff_list += [c_list[-1]] for i in coeff_list: if not i == 0: index = c_list.index(i) c_list[index] = 0 if all(i == 0 for i in c_list): return True else: return False else: return False elif isinstance(x.exp, (Float, Rational)): #not full - proof if FreeQ(simplify(u), x.base) and Exponent(u, x.base) == 0: if not all(FreeQ(u, i) for i in x.base.free_symbols): return False if isinstance(x, Mul): return all(PolynomialQ(u, i) for i in x.args) return u.is_polynomial(x) def FactorSquareFree(u): return sqf(u) def PowerOfLinearQ(expr, x): u = Wild('u') w = Wild('w') m = Wild('m') n = Wild('n') Match = expr.match(u**m) if PolynomialQ(Match[u], x) and FreeQ(Match[m], x): if IntegerQ(Match[m]): e = FactorSquareFree(Match[u]).match(w**n) if FreeQ(e[n], x) and LinearQ(e[w], x): return True else: return False else: return LinearQ(Match[u], x) else: return False def Exponent(expr, x): expr = Expand(S(expr)) if S(expr).is_number or (not expr.has(x)): return 0 if PolynomialQ(expr, x): if isinstance(x, Rational): return degree(Poly(expr, x), x) return degree(expr, gen = x) else: return 0 def ExponentList(expr, x): expr = Expand(S(expr)) if S(expr).is_number or (not expr.has(x)): return [0] if expr.is_Add: expr = collect(expr, x) lst = [] k = 1 for t in expr.args: if t.has(x): if isinstance(x, Rational): lst += [degree(Poly(t, x), x)] else: lst += [degree(t, gen = x)] else: if k == 1: lst += [0] k += 1 lst.sort() return lst else: if isinstance(x, Rational): return [degree(Poly(expr, x), x)] else: return [degree(expr, gen = x)] def QuadraticQ(u, x): # QuadraticQ(u, x) returns True iff u is a polynomial of degree 2 and not a monomial of the form a x^2 if ListQ(u): for expr in u: if Not(PolyQ(expr, x, 2) and Not(Coefficient(expr, x, 0) == 0 and Coefficient(expr, x, 1) == 0)): return False return True else: return PolyQ(u, x, 2) and Not(Coefficient(u, x, 0) == 0 and Coefficient(u, x, 1) == 0) def LinearPairQ(u, v, x): # LinearPairQ(u, v, x) returns True iff u and v are linear not equal x but u/v is a constant wrt x return LinearQ(u, x) and LinearQ(v, x) and NonzeroQ(u-x) and ZeroQ(Coefficient(u, x, 0)*Coefficient(v, x, 1)-Coefficient(u, x, 1)*Coefficient(v, x, 0)) def BinomialParts(u, x): if PolynomialQ(u, x): if Exponent(u, x) > 0: lst = ExponentList(u, x) if len(lst)==1: return [0, Coefficient(u, x, Exponent(u, x)), Exponent(u, x)] elif len(lst) == 2 and lst[0] == 0: return [Coefficient(u, x, 0), Coefficient(u, x, Exponent(u, x)), Exponent(u, x)] else: return False else: return False elif PowerQ(u): if u.base == x and FreeQ(u.exp, x): return [0, 1, u.exp] else: return False elif ProductQ(u): if FreeQ(First(u), x): lst2 = BinomialParts(Rest(u), x) if AtomQ(lst2): return False else: return [First(u)*lst2[0], First(u)*lst2[1], lst2[2]] elif FreeQ(Rest(u), x): lst1 = BinomialParts(First(u), x) if AtomQ(lst1): return False else: return [Rest(u)*lst1[0], Rest(u)*lst1[1], lst1[2]] lst1 = BinomialParts(First(u), x) if AtomQ(lst1): return False lst2 = BinomialParts(Rest(u), x) if AtomQ(lst2): return False a = lst1[0] b = lst1[1] m = lst1[2] c = lst2[0] d = lst2[1] n = lst2[2] if ZeroQ(a): if ZeroQ(c): return [0, b*d, m + n] elif ZeroQ(m + n): return [b*d, b*c, m] else: return False if ZeroQ(c): if ZeroQ(m + n): return [b*d, a*d, n] else: return False if EqQ(m, n) and ZeroQ(a*d + b*c): return [a*c, b*d, 2*m] else: return False elif SumQ(u): if FreeQ(First(u),x): lst2 = BinomialParts(Rest(u), x) if AtomQ(lst2): return False else: return [First(u) + lst2[0], lst2[1], lst2[2]] elif FreeQ(Rest(u), x): lst1 = BinomialParts(First(u), x) if AtomQ(lst1): return False else: return[Rest(u) + lst1[0], lst1[1], lst1[2]] lst1 = BinomialParts(First(u), x) if AtomQ(lst1): return False lst2 = BinomialParts(Rest(u),x) if AtomQ(lst2): return False if EqQ(lst1[2], lst2[2]): return [lst1[0] + lst2[0], lst1[1] + lst2[1], lst1[2]] else: return False else: return False def TrinomialParts(u, x): # If u is equivalent to a trinomial of the form a + b*x^n + c*x^(2*n) where n!=0, b!=0 and c!=0, TrinomialParts[u,x] returns the list {a,b,c,n}; else it returns False. u = sympify(u) if PolynomialQ(u, x): lst = CoefficientList(u, x) if len(lst)<3 or EvenQ(sympify(len(lst))) or ZeroQ((len(lst)+1)/2): return False #Catch( # Scan(Function(if ZeroQ(lst), Null, Throw(False), Drop(Drop(Drop(lst, [(len(lst)+1)/2]), 1), -1]; # [First(lst), lst[(len(lst)+1)/2], Last(lst), (len(lst)-1)/2]): if PowerQ(u): if EqQ(u.exp, 2): lst = BinomialParts(u.base, x) if not lst or ZeroQ(lst[0]): return False else: return [lst[0]**2, 2*lst[0]*lst[1], lst[1]**2, lst[2]] else: return False if ProductQ(u): if FreeQ(First(u), x): lst2 = TrinomialParts(Rest(u), x) if not lst2: return False else: return [First(u)*lst2[0], First(u)*lst2[1], First(u)*lst2[2], lst2[3]] if FreeQ(Rest(u), x): lst1 = TrinomialParts(First(u), x) if not lst1: return False else: return [Rest(u)*lst1[0], Rest(u)*lst1[1], Rest(u)*lst1[2], lst1[3]] lst1 = BinomialParts(First(u), x) if not lst1: return False lst2 = BinomialParts(Rest(u), x) if not lst2: return False a = lst1[0] b = lst1[1] m = lst1[2] c = lst2[0] d = lst2[1] n = lst2[2] if EqQ(m, n) and NonzeroQ(a*d+b*c): return [a*c, a*d + b*c, b*d, m] else: return False if SumQ(u): if FreeQ(First(u), x): lst2 = TrinomialParts(Rest(u), x) if not lst2: return False else: return [First(u)+lst2[0], lst2[1], lst2[2], lst2[3]] if FreeQ(Rest(u), x): lst1 = TrinomialParts(First(u), x) if not lst1: return False else: return [Rest(u)+lst1[0], lst1[1], lst1[2], lst1[3]] lst1 = TrinomialParts(First(u), x) if not lst1: lst3 = BinomialParts(First(u), x) if not lst3: return False lst2 = TrinomialParts(Rest(u), x) if not lst2: lst4 = BinomialParts(Rest(u), x) if not lst4: return False if EqQ(lst3[2], 2*lst4[2]): return [lst3[0]+lst4[0], lst4[1], lst3[1], lst4[2]] if EqQ(lst4[2], 2*lst3[2]): return [lst3[0]+lst4[0], lst3[1], lst4[1], lst3[2]] else: return False if EqQ(lst3[2], lst2[3]) and NonzeroQ(lst3[1]+lst2[1]): return [lst3[0]+lst2[0], lst3[1]+lst2[1], lst2[2], lst2[3]] if EqQ(lst3[2], 2*lst2[3]) and NonzeroQ(lst3[1]+lst2[2]): return [lst3[0]+lst2[0], lst2[1], lst3[1]+lst2[2], lst2[3]] else: return False lst2 = TrinomialParts(Rest(u), x) if AtomQ(lst2): lst4 = BinomialParts(Rest(u), x) if not lst4: return False if EqQ(lst4[2], lst1[3]) and NonzeroQ(lst1[1]+lst4[0]): return [lst1[0]+lst4[0], lst1[1]+lst4[1], lst1[2], lst1[3]] if EqQ(lst4[2], 2*lst1[3]) and NonzeroQ(lst1[2]+lst4[1]): return [lst1[0]+lst4[0], lst1[1], lst1[2]+lst4[1], lst1[3]] else: return False if EqQ(lst1[3], lst2[3]) and NonzeroQ(lst1[1]+lst2[1]) and NonzeroQ(lst1[2]+lst2[2]): return [lst1[0]+lst2[0], lst1[1]+lst2[1], lst1[2]+lst2[2], lst1[3]] else: return False else: return False def PolyQ(u, x, n=None): # returns True iff u is a polynomial of degree n. if ListQ(u): return all(PolyQ(i, x) for i in u) if n is None: if u == x: return False elif isinstance(x, Pow): n = x.exp x_base = x.base if FreeQ(n, x_base): if PositiveIntegerQ(n): return PolyQ(u, x_base) and (PolynomialQ(u, x) or PolynomialQ(Together(u), x)) elif AtomQ(n): return PolynomialQ(u, x) and FreeQ(CoefficientList(u, x), x_base) else: return False return PolynomialQ(u, x) or PolynomialQ(u, Together(x)) else: return PolynomialQ(u, x) and Coefficient(u, x, n) != 0 and Exponent(u, x) == n def EvenQ(u): # gives True if expr is an even integer, and False otherwise. return isinstance(u, (Integer, int)) and u%2 == 0 def OddQ(u): # gives True if expr is an odd integer, and False otherwise. return isinstance(u, (Integer, int)) and u%2 == 1 def PerfectSquareQ(u): # (* If u is a rational number whose squareroot is rational or if u is of the form u1^n1 u2^n2 ... # and n1, n2, ... are even, PerfectSquareQ[u] returns True; else it returns False. *) if RationalQ(u): return Greater(u, 0) and RationalQ(Sqrt(u)) elif PowerQ(u): return EvenQ(u.exp) elif ProductQ(u): return PerfectSquareQ(First(u)) and PerfectSquareQ(Rest(u)) elif SumQ(u): s = Simplify(u) if NonsumQ(s): return PerfectSquareQ(s) return False else: return False def NiceSqrtAuxQ(u): if RationalQ(u): return u > 0 elif PowerQ(u): return EvenQ(u.exp) elif ProductQ(u): return NiceSqrtAuxQ(First(u)) and NiceSqrtAuxQ(Rest(u)) elif SumQ(u): s = Simplify(u) return NonsumQ(s) and NiceSqrtAuxQ(s) else: return False def NiceSqrtQ(u): return Not(NegativeQ(u)) and NiceSqrtAuxQ(u) def Together(u): return factor(u) def PosAux(u): if RationalQ(u): return u>0 elif NumberQ(u): if ZeroQ(Re(u)): return Im(u) > 0 else: return Re(u) > 0 elif NumericQ(u): v = N(u) if ZeroQ(Re(v)): return Im(v) > 0 else: return Re(v) > 0 elif PowerQ(u): if OddQ(u.exp): return PosAux(u.base) else: return True elif ProductQ(u): if PosAux(First(u)): return PosAux(Rest(u)) else: return not PosAux(Rest(u)) elif SumQ(u): return PosAux(First(u)) else: res = u > 0 if res in(True, False): return res return True def PosQ(u): # If u is not 0 and has a positive form, PosQ[u] returns True, else it returns False. return PosAux(TogetherSimplify(u)) def CoefficientList(u, x): if PolynomialQ(u, x): return list(reversed(Poly(u, x).all_coeffs())) else: return [] def ReplaceAll(expr, args): if isinstance(args, list): n_args = {} for i in args: n_args.update(i) return expr.subs(n_args) return expr.subs(args) def ExpandLinearProduct(v, u, a, b, x): # If u is a polynomial in x, ExpandLinearProduct[v,u,a,b,x] expands v*u into a sum of terms of the form c*v*(a+b*x)^n. if FreeQ([a, b], x) and PolynomialQ(u, x): lst = CoefficientList(ReplaceAll(u, {x: (x - a)/b}), x) lst = [SimplifyTerm(i, x) for i in lst] res = 0 for k in range(1, len(lst)+1): res = res + Simplify(v*lst[k-1]*(a + b*x)**(k - 1)) return res return u*v def GCD(*args): args = S(args) if len(args) == 1: if isinstance(args[0], (int, Integer)): return args[0] else: return S(1) return gcd(*args) def ContentFactor(expn): return factor_terms(expn) def NumericFactor(u): # returns the real numeric factor of u. if NumberQ(u): if ZeroQ(Im(u)): return u elif ZeroQ(Re(u)): return Im(u) else: return S(1) elif PowerQ(u): if RationalQ(u.base) and RationalQ(u.exp): if u.exp > 0: return 1/Denominator(u.base) else: return 1/(1/Denominator(u.base)) else: return S(1) elif ProductQ(u): return Mul(*[NumericFactor(i) for i in u.args]) elif SumQ(u): if LeafCount(u) < 50: c = ContentFactor(u) if SumQ(c): return S(1) else: return NumericFactor(c) else: m = NumericFactor(First(u)) n = NumericFactor(Rest(u)) if m < 0 and n < 0: return -GCD(-m, -n) else: return GCD(m, n) return S(1) def NonnumericFactors(u): if NumberQ(u): if ZeroQ(Im(u)): return S(1) elif ZeroQ(Re(u)): return I return u elif PowerQ(u): if RationalQ(u.base) and FractionQ(u.exp): return u/NumericFactor(u) return u elif ProductQ(u): result = 1 for i in u.args: result *= NonnumericFactors(i) return result elif SumQ(u): if LeafCount(u) < 50: i = ContentFactor(u) if SumQ(i): return u else: return NonnumericFactors(i) n = NumericFactor(u) result = 0 for i in u.args: result += i/n return result return u def MakeAssocList(u, x, alst=None): # (* MakeAssocList[u,x,alst] returns an association list of gensymed symbols with the nonatomic # parameters of a u that are not integer powers, products or sums. *) if alst is None: alst = [] u = replace_pow_exp(u) x = replace_pow_exp(x) if AtomQ(u): return alst elif IntegerPowerQ(u): return MakeAssocList(u.base, x, alst) elif ProductQ(u) or SumQ(u): return MakeAssocList(Rest(u), x, MakeAssocList(First(u), x, alst)) elif FreeQ(u, x): tmp = [] for i in alst: if PowerQ(i): if i.exp == u: tmp.append(i) break elif len(i.args) > 1: # make sure args has length > 1, else causes index error some times if i.args[1] == u: tmp.append(i) break if tmp == []: alst.append(u) return alst return alst def GensymSubst(u, x, alst=None): # (* GensymSubst[u,x,alst] returns u with the kernels in alst free of x replaced by gensymed names. *) if alst is None: alst =[] u = replace_pow_exp(u) x = replace_pow_exp(x) if AtomQ(u): return u elif IntegerPowerQ(u): return GensymSubst(u.base, x, alst)**u.exp elif ProductQ(u) or SumQ(u): return u.func(*[GensymSubst(i, x, alst) for i in u.args]) elif FreeQ(u, x): tmp = [] for i in alst: if PowerQ(i): if i.exp == u: tmp.append(i) break elif len(i.args) > 1: # make sure args has length > 1, else causes index error some times if i.args[1] == u: tmp.append(i) break if tmp == []: return u return tmp[0][0] return u def KernelSubst(u, x, alst): # (* KernelSubst[u,x,alst] returns u with the gensymed names in alst replaced by kernels free of x. *) if AtomQ(u): tmp = [] for i in alst: if i.args[0] == u: tmp.append(i) break if tmp == []: return u elif len(tmp[0].args) > 1: # make sure args has length > 1, else causes index error some times return tmp[0].args[1] elif IntegerPowerQ(u): tmp = KernelSubst(u.base, x, alst) if u.exp < 0 and ZeroQ(tmp): return 'Indeterminate' return tmp**u.exp elif ProductQ(u) or SumQ(u): return u.func(*[KernelSubst(i, x, alst) for i in u.args]) return u def ExpandExpression(u, x): if AlgebraicFunctionQ(u, x) and Not(RationalFunctionQ(u, x)): v = ExpandAlgebraicFunction(u, x) else: v = S(0) if SumQ(v): return ExpandCleanup(v, x) v = SmartApart(u, x) if SumQ(v): return ExpandCleanup(v, x) v = SmartApart(RationalFunctionFactors(u, x), x, x) if SumQ(v): w = NonrationalFunctionFactors(u, x) return ExpandCleanup(v.func(*[i*w for i in v.args]), x) v = Expand(u) if SumQ(v): return ExpandCleanup(v, x) v = Expand(u) if SumQ(v): return ExpandCleanup(v, x) return SimplifyTerm(u, x) def Apart(u, x): if RationalFunctionQ(u, x): return apart(u, x) return u def SmartApart(*args): if len(args) == 2: u, x = args alst = MakeAssocList(u, x) tmp = KernelSubst(Apart(GensymSubst(u, x, alst), x), x, alst) if tmp == 'Indeterminate': return u return tmp u, v, x = args alst = MakeAssocList(u, x) tmp = KernelSubst(Apart(GensymSubst(u, x, alst), x), x, alst) if tmp == 'Indeterminate': return u return tmp def MatchQ(expr, pattern, *var): # returns the matched arguments after matching pattern with expression match = expr.match(pattern) if match: return tuple(match[i] for i in var) else: return None def PolynomialQuotientRemainder(p, q, x): return [PolynomialQuotient(p, q, x), PolynomialRemainder(p, q, x)] def FreeFactors(u, x): # returns the product of the factors of u free of x. if ProductQ(u): result = 1 for i in u.args: if FreeQ(i, x): result *= i return result elif FreeQ(u, x): return u else: return S(1) def NonfreeFactors(u, x): """ Returns the product of the factors of u not free of x. Examples ======== >>> from sympy.integrals.rubi.utility_function import NonfreeFactors >>> from sympy.abc import x, a, b >>> NonfreeFactors(a, x) 1 >>> NonfreeFactors(x + a, x) a + x >>> NonfreeFactors(a*b*x, x) x """ if ProductQ(u): result = 1 for i in u.args: if not FreeQ(i, x): result *= i return result elif FreeQ(u, x): return 1 else: return u def RemoveContentAux(expr, x): return RemoveContentAux_replacer.replace(UtilityOperator(expr, x)) def RemoveContent(u, x): v = NonfreeFactors(u, x) w = Together(v) if EqQ(FreeFactors(w, x), 1): return RemoveContentAux(v, x) else: return RemoveContentAux(NonfreeFactors(w, x), x) def FreeTerms(u, x): """ Returns the sum of the terms of u free of x. Examples ======== >>> from sympy.integrals.rubi.utility_function import FreeTerms >>> from sympy.abc import x, a, b >>> FreeTerms(a, x) a >>> FreeTerms(x*a, x) 0 >>> FreeTerms(a*x + b, x) b """ if SumQ(u): result = 0 for i in u.args: if FreeQ(i, x): result += i return result elif FreeQ(u, x): return u else: return 0 def NonfreeTerms(u, x): # returns the sum of the terms of u free of x. if SumQ(u): result = S(0) for i in u.args: if not FreeQ(i, x): result += i return result elif not FreeQ(u, x): return u else: return S(0) def ExpandAlgebraicFunction(expr, x): if ProductQ(expr): u_ = Wild('u', exclude=[x]) n_ = Wild('n', exclude=[x]) v_ = Wild('v') pattern = u_*v_ match = expr.match(pattern) if match: keys = [u_, v_] if len(keys) == len(match): u, v = tuple([match[i] for i in keys]) if SumQ(v): u, v = v, u if not FreeQ(u, x) and SumQ(u): result = 0 for i in u.args: result += i*v return result pattern = u_**n_*v_ match = expr.match(pattern) if match: keys = [u_, n_, v_] if len(keys) == len(match): u, n, v = tuple([match[i] for i in keys]) if PositiveIntegerQ(n) and SumQ(u): w = Expand(u**n) result = 0 for i in w.args: result += i*v return result return expr def CollectReciprocals(expr, x): # Basis: e/(a+b x)+f/(c+d x)==(c e+a f+(d e+b f) x)/(a c+(b c+a d) x+b d x^2) if SumQ(expr): u_ = Wild('u') a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x]) c_ = Wild('c', exclude=[x]) d_ = Wild('d', exclude=[x]) e_ = Wild('e', exclude=[x]) f_ = Wild('f', exclude=[x]) pattern = u_ + e_/(a_ + b_*x) + f_/(c_+d_*x) match = expr.match(pattern) if match: try: # .match() does not work peoperly always keys = [u_, a_, b_, c_, d_, e_, f_] u, a, b, c, d, e, f = tuple([match[i] for i in keys]) if ZeroQ(b*c + a*d) & ZeroQ(d*e + b*f): return CollectReciprocals(u + (c*e + a*f)/(a*c + b*d*x**2),x) elif ZeroQ(b*c + a*d) & ZeroQ(c*e + a*f): return CollectReciprocals(u + (d*e + b*f)*x/(a*c + b*d*x**2),x) except: pass return expr def ExpandCleanup(u, x): v = CollectReciprocals(u, x) if SumQ(v): res = 0 for i in v.args: res += SimplifyTerm(i, x) v = res if SumQ(v): return UnifySum(v, x) else: return v else: return v def AlgebraicFunctionQ(u, x, flag=False): if ListQ(u): if u == []: return True elif AlgebraicFunctionQ(First(u), x, flag): return AlgebraicFunctionQ(Rest(u), x, flag) else: return False elif AtomQ(u) or FreeQ(u, x): return True elif PowerQ(u): if RationalQ(u.exp) | flag & FreeQ(u.exp, x): return AlgebraicFunctionQ(u.base, x, flag) elif ProductQ(u) | SumQ(u): for i in u.args: if not AlgebraicFunctionQ(i, x, flag): return False return True return False def Coeff(expr, form, n=1): if n == 1: return Coefficient(Together(expr), form, n) else: coef1 = Coefficient(expr, form, n) coef2 = Coefficient(Together(expr), form, n) if Simplify(coef1 - coef2) == 0: return coef1 else: return coef2 def LeadTerm(u): if SumQ(u): return First(u) return u def RemainingTerms(u): if SumQ(u): return Rest(u) return u def LeadFactor(u): # returns the leading factor of u. if ComplexNumberQ(u) and Re(u) == 0: if Im(u) == S(1): return u else: return LeadFactor(Im(u)) elif ProductQ(u): return LeadFactor(First(u)) return u def RemainingFactors(u): # returns the remaining factors of u. if ComplexNumberQ(u) and Re(u) == 0: if Im(u) == 1: return S(1) else: return I*RemainingFactors(Im(u)) elif ProductQ(u): return RemainingFactors(First(u))*Rest(u) return S(1) def LeadBase(u): """ returns the base of the leading factor of u. Examples ======== >>> from sympy.integrals.rubi.utility_function import LeadBase >>> from sympy.abc import a, b, c >>> LeadBase(a**b) a >>> LeadBase(a**b*c) a """ v = LeadFactor(u) if PowerQ(v): return v.base return v def LeadDegree(u): # returns the degree of the leading factor of u. v = LeadFactor(u) if PowerQ(v): return v.exp return v def Numer(expr): # returns the numerator of u. if PowerQ(expr): if expr.exp < 0: return 1 if ProductQ(expr): return Mul(*[Numer(i) for i in expr.args]) return Numerator(expr) def Denom(u): # returns the denominator of u if PowerQ(u): if u.exp < 0: return u.args[0]**(-u.args[1]) elif ProductQ(u): return Mul(*[Denom(i) for i in u.args]) return Denominator(u) def hypergeom(n, d, z): return hyper(n, d, z) def Expon(expr, form): return Exponent(Together(expr), form) def MergeMonomials(expr, x): u_ = Wild('u') p_ = Wild('p', exclude=[x, 1, 0]) a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x, 0]) c_ = Wild('c', exclude=[x]) d_ = Wild('d', exclude=[x, 0]) n_ = Wild('n', exclude=[x]) m_ = Wild('m', exclude=[x]) # Basis: If m/n\[Element]\[DoubleStruckCapitalZ], then z^m (c z^n)^p==(c z^n)^(m/n+p)/c^(m/n) pattern = u_*(a_ + b_*x)**m_*(c_*(a_ + b_*x)**n_)**p_ match = expr.match(pattern) if match: keys = [u_, a_, b_, m_, c_, n_, p_] if len(keys) == len(match): u, a, b, m, c, n, p = tuple([match[i] for i in keys]) if IntegerQ(m/n): if u*(c*(a + b*x)**n)**(m/n + p)/c**(m/n) is S.NaN: return expr else: return u*(c*(a + b*x)**n)**(m/n + p)/c**(m/n) # Basis: If m\[Element]\[DoubleStruckCapitalZ] \[And] b c-a d==0, then (a+b z)^m==b^m/d^m (c+d z)^m pattern = u_*(a_ + b_*x)**m_*(c_ + d_*x)**n_ match = expr.match(pattern) if match: keys = [u_, a_, b_, m_, c_, d_, n_] if len(keys) == len(match): u, a, b, m, c, d, n = tuple([match[i] for i in keys]) if IntegerQ(m) and ZeroQ(b*c - a*d): if u*b**m/d**m*(c + d*x)**(m + n) is S.NaN: return expr else: return u*b**m/d**m*(c + d*x)**(m + n) return expr def PolynomialDivide(u, v, x): quo = PolynomialQuotient(u, v, x) rem = PolynomialRemainder(u, v, x) s = 0 for i in ExponentList(quo, x): s += Simp(Together(Coefficient(quo, x, i)*x**i), x) quo = s rem = Together(rem) free = FreeFactors(rem, x) rem = NonfreeFactors(rem, x) monomial = x**Min(ExponentList(rem, x)) if NegQ(Coefficient(rem, x, 0)): monomial = -monomial s = 0 for i in ExponentList(rem, x): s += Simp(Together(Coefficient(rem, x, i)*x**i/monomial), x) rem = s if BinomialQ(v, x): return quo + free*monomial*rem/ExpandToSum(v, x) else: return quo + free*monomial*rem/v def BinomialQ(u, x, n=None): """ If u is equivalent to an expression of the form a + b*x**n, BinomialQ(u, x, n) returns True, else it returns False. Examples ======== >>> from sympy.integrals.rubi.utility_function import BinomialQ >>> from sympy.abc import x >>> BinomialQ(x**9, x) True >>> BinomialQ((1 + x)**3, x) False """ if ListQ(u): for i in u: if Not(BinomialQ(i, x, n)): return False return True elif NumberQ(x): return False return ListQ(BinomialParts(u, x)) def TrinomialQ(u, x): """ If u is equivalent to an expression of the form a + b*x**n + c*x**(2*n) where n, b and c are not 0, TrinomialQ(u, x) returns True, else it returns False. Examples ======== >>> from sympy.integrals.rubi.utility_function import TrinomialQ >>> from sympy.abc import x >>> TrinomialQ((7 + 2*x**6 + 3*x**12), x) True >>> TrinomialQ(x**2, x) False """ if ListQ(u): for i in u.args: if Not(TrinomialQ(i, x)): return False return True check = False u = replace_pow_exp(u) if PowerQ(u): if u.exp == 2 and BinomialQ(u.base, x): check = True return ListQ(TrinomialParts(u,x)) and Not(QuadraticQ(u, x)) and Not(check) def GeneralizedBinomialQ(u, x): """ If u is equivalent to an expression of the form a*x**q+b*x**n where n, q and b are not 0, GeneralizedBinomialQ(u, x) returns True, else it returns False. Examples ======== >>> from sympy.integrals.rubi.utility_function import GeneralizedBinomialQ >>> from sympy.abc import a, x, q, b, n >>> GeneralizedBinomialQ(a*x**q, x) False """ if ListQ(u): return all(GeneralizedBinomialQ(i, x) for i in u) return ListQ(GeneralizedBinomialParts(u, x)) def GeneralizedTrinomialQ(u, x): """ If u is equivalent to an expression of the form a*x**q+b*x**n+c*x**(2*n-q) where n, q, b and c are not 0, GeneralizedTrinomialQ(u, x) returns True, else it returns False. Examples ======== >>> from sympy.integrals.rubi.utility_function import GeneralizedTrinomialQ >>> from sympy.abc import x >>> GeneralizedTrinomialQ(7 + 2*x**6 + 3*x**12, x) False """ if ListQ(u): return all(GeneralizedTrinomialQ(i, x) for i in u) return ListQ(GeneralizedTrinomialParts(u, x)) def FactorSquareFreeList(poly): r = sqf_list(poly) result = [[1, 1]] for i in r[1]: result.append(list(i)) return result def PerfectPowerTest(u, x): # If u (x) is equivalent to a polynomial raised to an integer power greater than 1, # PerfectPowerTest[u,x] returns u (x) as an expanded polynomial raised to the power; # else it returns False. if PolynomialQ(u, x): lst = FactorSquareFreeList(u) gcd = 0 v = 1 if lst[0] == [1, 1]: lst = Rest(lst) for i in lst: gcd = GCD(gcd, i[1]) if gcd > 1: for i in lst: v = v*i[0]**(i[1]/gcd) return Expand(v)**gcd else: return False return False def SquareFreeFactorTest(u, x): # If u (x) can be square free factored, SquareFreeFactorTest[u,x] returns u (x) in # factored form; else it returns False. if PolynomialQ(u, x): v = FactorSquareFree(u) if PowerQ(v) or ProductQ(v): return v return False return False def RationalFunctionQ(u, x): # If u is a rational function of x, RationalFunctionQ[u,x] returns True; else it returns False. if AtomQ(u) or FreeQ(u, x): return True elif IntegerPowerQ(u): return RationalFunctionQ(u.base, x) elif ProductQ(u) or SumQ(u): for i in u.args: if Not(RationalFunctionQ(i, x)): return False return True return False def RationalFunctionFactors(u, x): # RationalFunctionFactors[u,x] returns the product of the factors of u that are rational functions of x. if ProductQ(u): res = 1 for i in u.args: if RationalFunctionQ(i, x): res *= i return res elif RationalFunctionQ(u, x): return u return S(1) def NonrationalFunctionFactors(u, x): if ProductQ(u): res = 1 for i in u.args: if not RationalFunctionQ(i, x): res *= i return res elif RationalFunctionQ(u, x): return S(1) return u def Reverse(u): if isinstance(u, list): return list(reversed(u)) else: l = list(u.args) return u.func(*list(reversed(l))) def RationalFunctionExponents(u, x): """ u is a polynomial or rational function of x. RationalFunctionExponents(u, x) returns a list of the exponent of the numerator of u and the exponent of the denominator of u. Examples ======== >>> from sympy.integrals.rubi.utility_function import RationalFunctionExponents >>> from sympy.abc import x, a >>> RationalFunctionExponents(x, x) [1, 0] >>> RationalFunctionExponents(x**(-1), x) [0, 1] >>> RationalFunctionExponents(x**(-1)*a, x) [0, 1] """ if PolynomialQ(u, x): return [Exponent(u, x), 0] elif IntegerPowerQ(u): if PositiveQ(u.exp): return u.exp*RationalFunctionExponents(u.base, x) return (-u.exp)*Reverse(RationalFunctionExponents(u.base, x)) elif ProductQ(u): lst1 = RationalFunctionExponents(First(u), x) lst2 = RationalFunctionExponents(Rest(u), x) return [lst1[0] + lst2[0], lst1[1] + lst2[1]] elif SumQ(u): v = Together(u) if SumQ(v): lst1 = RationalFunctionExponents(First(u), x) lst2 = RationalFunctionExponents(Rest(u), x) return [Max(lst1[0] + lst2[1], lst2[0] + lst1[1]), lst1[1] + lst2[1]] else: return RationalFunctionExponents(v, x) return [0, 0] def RationalFunctionExpand(expr, x): # expr is a polynomial or rational function of x. # RationalFunctionExpand[u,x] returns the expansion of the factors of u that are rational functions times the other factors. def cons_f1(n): return FractionQ(n) cons1 = CustomConstraint(cons_f1) def cons_f2(x, v): if not isinstance(x, Symbol): return False return UnsameQ(v, x) cons2 = CustomConstraint(cons_f2) def With1(n, u, x, v): w = RationalFunctionExpand(u, x) return If(SumQ(w), Add(*[i*v**n for i in w.args]), v**n*w) pattern1 = Pattern(UtilityOperator(u_*v_**n_, x_), cons1, cons2) rule1 = ReplacementRule(pattern1, With1) def With2(u, x): v = ExpandIntegrand(u, x) def _consf_u(a, b, c, d, p, m, n, x): return And(FreeQ(List(a, b, c, d, p), x), IntegersQ(m, n), Equal(m, Add(n, S(-1)))) cons_u = CustomConstraint(_consf_u) pat = Pattern(UtilityOperator(x_**WC('m', S(1))*(x_*WC('d', S(1)) + c_)**p_/(x_**n_*WC('b', S(1)) + a_), x_), cons_u) result_matchq = is_match(UtilityOperator(u, x), pat) if UnsameQ(v, u) and not result_matchq: return v else: v = ExpandIntegrand(RationalFunctionFactors(u, x), x) w = NonrationalFunctionFactors(u, x) if SumQ(v): return Add(*[i*w for i in v.args]) else: return v*w pattern2 = Pattern(UtilityOperator(u_, x_)) rule2 = ReplacementRule(pattern2, With2) expr = expr.replace(sym_exp, rubi_exp) res = replace_all(UtilityOperator(expr, x), [rule1, rule2]) return replace_pow_exp(res) def ExpandIntegrand(expr, x, extra=None): expr = replace_pow_exp(expr) if not extra is None: extra, x = x, extra w = ExpandIntegrand(extra, x) r = NonfreeTerms(w, x) if SumQ(r): result = [expr*FreeTerms(w, x)] for i in r.args: result.append(MergeMonomials(expr*i, x)) return r.func(*result) else: return expr*FreeTerms(w, x) + MergeMonomials(expr*r, x) else: u_ = Wild('u', exclude=[0, 1]) a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x, 0]) F_ = Wild('F', exclude=[0]) c_ = Wild('c', exclude=[x]) d_ = Wild('d', exclude=[x, 0]) n_ = Wild('n', exclude=[0, 1]) pattern = u_*(a_ + b_*F_)**n_ match = expr.match(pattern) if match: if MemberQ([asin, acos, asinh, acosh], match[F_].func): keys = [u_, a_, b_, F_, n_] if len(match) == len(keys): u, a, b, F, n = tuple([match[i] for i in keys]) match = F.args[0].match(c_ + d_*x) if match: keys = c_, d_ if len(keys) == len(match): c, d = tuple([match[i] for i in keys]) if PolynomialQ(u, x): F = F.func return ExpandLinearProduct((a + b*F(c + d*x))**n, u, c, d, x) expr = expr.replace(sym_exp, rubi_exp) res = replace_all(UtilityOperator(expr, x), ExpandIntegrand_rules, max_count = 1) return replace_pow_exp(res) def SimplerQ(u, v): # If u is simpler than v, SimplerQ(u, v) returns True, else it returns False. SimplerQ(u, u) returns False if IntegerQ(u): if IntegerQ(v): if Abs(u)==Abs(v): return v<0 else: return Abs(u)>> from sympy.integrals.rubi.utility_function import SumSimplerQ >>> from sympy.abc import x >>> from sympy import S >>> SumSimplerQ(S(4 + x),S(3 + x**3)) False """ if RationalQ(u, v): if v == S(0): return False elif v > S(0): return u < -S(1) else: return u >= -v else: return SumSimplerAuxQ(Expand(u), Expand(v)) def BinomialDegree(u, x): # if u is a binomial. BinomialDegree[u,x] returns the degree of x in u. bp = BinomialParts(u, x) if bp == False: return bp return bp[2] def TrinomialDegree(u, x): # If u is equivalent to a trinomial of the form a + b*x^n + c*x^(2*n) where n!=0, b!=0 and c!=0, TrinomialDegree[u,x] returns n t = TrinomialParts(u, x) if t: return t[3] return t def CancelCommonFactors(u, v): def _delete_cases(a, b): # only for CancelCommonFactors lst = [] deleted = False for i in a.args: if i == b and not deleted: deleted = True continue lst.append(i) return a.func(*lst) # CancelCommonFactors[u,v] returns {u',v'} are the noncommon factors of u and v respectively. if ProductQ(u): if ProductQ(v): if MemberQ(v, First(u)): return CancelCommonFactors(Rest(u), _delete_cases(v, First(u))) else: lst = CancelCommonFactors(Rest(u), v) return [First(u)*lst[0], lst[1]] else: if MemberQ(u, v): return [_delete_cases(u, v), 1] else: return[u, v] elif ProductQ(v): if MemberQ(v, u): return [1, _delete_cases(v, u)] else: return [u, v] return[u, v] def SimplerIntegrandQ(u, v, x): lst = CancelCommonFactors(u, v) u1 = lst[0] v1 = lst[1] if Head(u1) == Head(v1) and Length(u1) == 1 and Length(v1) == 1: return SimplerIntegrandQ(u1.args[0], v1.args[0], x) if 4*LeafCount(u1) < 3*LeafCount(v1): return True if RationalFunctionQ(u1, x): if RationalFunctionQ(v1, x): t1 = 0 t2 = 0 for i in RationalFunctionExponents(u1, x): t1 += i for i in RationalFunctionExponents(v1, x): t2 += i return t1 < t2 else: return True else: return False def GeneralizedBinomialDegree(u, x): b = GeneralizedBinomialParts(u, x) if b: return b[2] - b[3] def GeneralizedBinomialParts(expr, x): expr = Expand(expr) if GeneralizedBinomialMatchQ(expr, x): a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) n = Wild('n', exclude=[x]) q = Wild('q', exclude=[x]) Match = expr.match(a*x**q + b*x**n) if Match and PosQ(Match[q] - Match[n]): return [Match[b], Match[a], Match[q], Match[n]] else: return False def GeneralizedTrinomialDegree(u, x): t = GeneralizedTrinomialParts(u, x) if t: return t[3] - t[4] def GeneralizedTrinomialParts(expr, x): expr = Expand(expr) if GeneralizedTrinomialMatchQ(expr, x): a = Wild('a', exclude=[x, 0]) b = Wild('b', exclude=[x, 0]) c = Wild('c', exclude=[x]) n = Wild('n', exclude=[x, 0]) q = Wild('q', exclude=[x]) Match = expr.match(a*x**q + b*x**n+c*x**(2*n-q)) if Match and expr.is_Add: return [Match[c], Match[b], Match[a], Match[n], 2*Match[n]-Match[q]] else: return False def MonomialQ(u, x): # If u is of the form a*x^n where n!=0 and a!=0, MonomialQ[u,x] returns True; else False if isinstance(u, list): return all(MonomialQ(i, x) for i in u) else: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) re = u.match(a*x**b) if re: return True return False def MonomialSumQ(u, x): # if u(x) is a sum and each term is free of x or an expression of the form a*x^n, MonomialSumQ(u, x) returns True; else it returns False if SumQ(u): for i in u.args: if Not(FreeQ(i, x) or MonomialQ(i, x)): return False return True @doctest_depends_on(modules=('matchpy',)) def MinimumMonomialExponent(u, x): """ u is sum whose terms are monomials. MinimumMonomialExponent(u, x) returns the exponent of the term having the smallest exponent Examples ======== >>> from sympy.integrals.rubi.utility_function import MinimumMonomialExponent >>> from sympy.abc import x >>> MinimumMonomialExponent(x**2 + 5*x**2 + 3*x**5, x) 2 >>> MinimumMonomialExponent(x**2 + 5*x**2 + 1, x) 0 """ n =MonomialExponent(First(u), x) for i in u.args: if PosQ(n - MonomialExponent(i, x)): n = MonomialExponent(i, x) return n def MonomialExponent(u, x): # u is a monomial. MonomialExponent(u, x) returns the exponent of x in u a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) re = u.match(a*x**b) if re: return re[b] def LinearMatchQ(u, x): # LinearMatchQ(u, x) returns True iff u matches patterns of the form a+b*x where a and b are free of x if isinstance(u, list): return all(LinearMatchQ(i, x) for i in u) else: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) re = u.match(a + b*x) if re: return True return False def PowerOfLinearMatchQ(u, x): if isinstance(u, list): for i in u: if not PowerOfLinearMatchQ(i, x): return False return True else: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x, 0]) m = Wild('m', exclude=[x, 0]) Match = u.match((a + b*x)**m) if Match: return True else: return False def QuadraticMatchQ(u, x): if ListQ(u): return all(QuadraticMatchQ(i, x) for i in u) pattern1 = Pattern(UtilityOperator(x_**2*WC('c', 1) + x_*WC('b', 1) + WC('a', 0), x_), CustomConstraint(lambda a, b, c, x: FreeQ([a, b, c], x))) pattern2 = Pattern(UtilityOperator(x_**2*WC('c', 1) + WC('a', 0), x_), CustomConstraint(lambda a, c, x: FreeQ([a, c], x))) u1 = UtilityOperator(u, x) return is_match(u1, pattern1) or is_match(u1, pattern2) def CubicMatchQ(u, x): if isinstance(u, list): return all(CubicMatchQ(i, x) for i in u) else: pattern1 = Pattern(UtilityOperator(x_**3*WC('d', 1) + x_**2*WC('c', 1) + x_*WC('b', 1) + WC('a', 0), x_), CustomConstraint(lambda a, b, c, d, x: FreeQ([a, b, c, d], x))) pattern2 = Pattern(UtilityOperator(x_**3*WC('d', 1) + x_*WC('b', 1) + WC('a', 0), x_), CustomConstraint(lambda a, b, d, x: FreeQ([a, b, d], x))) pattern3 = Pattern(UtilityOperator(x_**3*WC('d', 1) + x_**2*WC('c', 1) + WC('a', 0), x_), CustomConstraint(lambda a, c, d, x: FreeQ([a, c, d], x))) pattern4 = Pattern(UtilityOperator(x_**3*WC('d', 1) + WC('a', 0), x_), CustomConstraint(lambda a, d, x: FreeQ([a, d], x))) u1 = UtilityOperator(u, x) if is_match(u1, pattern1) or is_match(u1, pattern2) or is_match(u1, pattern3) or is_match(u1, pattern4): return True else: return False def BinomialMatchQ(u, x): if isinstance(u, list): return all(BinomialMatchQ(i, x) for i in u) else: pattern = Pattern(UtilityOperator(x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)), x_) , CustomConstraint(lambda a, b, n, x: FreeQ([a,b,n],x))) u = UtilityOperator(u, x) return is_match(u, pattern) def TrinomialMatchQ(u, x): if isinstance(u, list): return all(TrinomialMatchQ(i, x) for i in u) else: pattern = Pattern(UtilityOperator(x_**WC('j', S(1))*WC('c', S(1)) + x_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)), x_) , CustomConstraint(lambda a, b, c, n, x: FreeQ([a, b, c, n], x)), CustomConstraint(lambda j, n: ZeroQ(j-2*n) )) u = UtilityOperator(u, x) return is_match(u, pattern) def GeneralizedBinomialMatchQ(u, x): if isinstance(u, list): return all(GeneralizedBinomialMatchQ(i, x) for i in u) else: a = Wild('a', exclude=[x, 0]) b = Wild('b', exclude=[x, 0]) n = Wild('n', exclude=[x, 0]) q = Wild('q', exclude=[x, 0]) Match = u.match(a*x**q + b*x**n) if Match and len(Match) == 4 and Match[q] != 0 and Match[n] != 0: return True else: return False def GeneralizedTrinomialMatchQ(u, x): if isinstance(u, list): return all(GeneralizedTrinomialMatchQ(i, x) for i in u) else: a = Wild('a', exclude=[x, 0]) b = Wild('b', exclude=[x, 0]) n = Wild('n', exclude=[x, 0]) c = Wild('c', exclude=[x, 0]) q = Wild('q', exclude=[x, 0]) Match = u.match(a*x**q + b*x**n + c*x**(2*n - q)) if Match and len(Match) == 5 and 2*Match[n] - Match[q] != 0 and Match[n] != 0: return True else: return False def QuotientOfLinearsMatchQ(u, x): if isinstance(u, list): return all(QuotientOfLinearsMatchQ(i, x) for i in u) else: a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) d = Wild('d', exclude=[x]) c = Wild('c', exclude=[x]) e = Wild('e') Match = u.match(e*(a + b*x)/(c + d*x)) if Match and len(Match) == 5: return True else: return False def PolynomialTermQ(u, x): a = Wild('a', exclude=[x]) n = Wild('n', exclude=[x]) Match = u.match(a*x**n) if Match and IntegerQ(Match[n]) and Greater(Match[n], S(0)): return True else: return False def PolynomialTerms(u, x): s = 0 for i in u.args: if PolynomialTermQ(i, x): s = s + i return s def NonpolynomialTerms(u, x): s = 0 for i in u.args: if not PolynomialTermQ(i, x): s = s + i return s def PseudoBinomialParts(u, x): if PolynomialQ(u, x) and Greater(Expon(u, x), S(2)): n = Expon(u, x) d = Rt(Coefficient(u, x, n), n) c = d**(-n + S(1))*Coefficient(u, x, n + S(-1))/n a = Simplify(u - (c + d*x)**n) if NonzeroQ(a) and FreeQ(a, x): return [a, S(1), c, d, n] else: return False else: return False def NormalizePseudoBinomial(u, x): lst = PseudoBinomialParts(u, x) if lst: return (lst[0] + lst[1]*(lst[2] + lst[3]*x)**lst[4]) def PseudoBinomialPairQ(u, v, x): lst1 = PseudoBinomialParts(u, x) if AtomQ(lst1): return False else: lst2 = PseudoBinomialParts(v, x) if AtomQ(lst2): return False else: return Drop(lst1, 2) == Drop(lst2, 2) def PseudoBinomialQ(u, x): lst = PseudoBinomialParts(u, x) if lst: return True else: return False def PolynomialGCD(f, g): return gcd(f, g) def PolyGCD(u, v, x): # (* u and v are polynomials in x. *) # (* PolyGCD[u,v,x] returns the factors of the gcd of u and v dependent on x. *) return NonfreeFactors(PolynomialGCD(u, v), x) def AlgebraicFunctionFactors(u, x, flag=False): # (* AlgebraicFunctionFactors[u,x] returns the product of the factors of u that are algebraic functions of x. *) if ProductQ(u): result = 1 for i in u.args: if AlgebraicFunctionQ(i, x, flag): result *= i return result if AlgebraicFunctionQ(u, x, flag): return u return 1 def NonalgebraicFunctionFactors(u, x): """ NonalgebraicFunctionFactors[u,x] returns the product of the factors of u that are not algebraic functions of x. Examples ======== >>> from sympy.integrals.rubi.utility_function import NonalgebraicFunctionFactors >>> from sympy.abc import x >>> from sympy import sin >>> NonalgebraicFunctionFactors(sin(x), x) sin(x) >>> NonalgebraicFunctionFactors(x, x) 1 """ if ProductQ(u): result = 1 for i in u.args: if not AlgebraicFunctionQ(i, x): result *= i return result if AlgebraicFunctionQ(u, x): return 1 return u def QuotientOfLinearsP(u, x): if LinearQ(u, x): return True elif SumQ(u): if FreeQ(u.args[0], x): return QuotientOfLinearsP(Rest(u), x) elif LinearQ(Numerator(u), x) and LinearQ(Denominator(u), x): return True elif ProductQ(u): if FreeQ(First(u), x): return QuotientOfLinearsP(Rest(u), x) elif Numerator(u) == 1 and PowerQ(u): return QuotientOfLinearsP(Denominator(u), x) return u == x or FreeQ(u, x) def QuotientOfLinearsParts(u, x): # If u is equivalent to an expression of the form (a+b*x)/(c+d*x), QuotientOfLinearsParts[u,x] # returns the list {a, b, c, d}. if LinearQ(u, x): return [Coefficient(u, x, 0), Coefficient(u, x, 1), 1, 0] elif PowerQ(u): if Numerator(u) == 1: u = Denominator(u) r = QuotientOfLinearsParts(u, x) return [r[2], r[3], r[0], r[1]] elif SumQ(u): a = First(u) if FreeQ(a, x): u = Rest(u) r = QuotientOfLinearsParts(u, x) return [r[0] + a*r[2], r[1] + a*r[3], r[2], r[3]] elif ProductQ(u): a = First(u) if FreeQ(a, x): r = QuotientOfLinearsParts(Rest(u), x) return [a*r[0], a*r[1], r[2], r[3]] a = Numerator(u) d = Denominator(u) if LinearQ(a, x) and LinearQ(d, x): return [Coefficient(a, x, 0), Coefficient(a, x, 1), Coefficient(d, x, 0), Coefficient(d, x, 1)] elif u == x: return [0, 1, 1, 0] elif FreeQ(u, x): return [u, 0, 1, 0] return [u, 0, 1, 0] def QuotientOfLinearsQ(u, x): # (*QuotientOfLinearsQ[u,x] returns True iff u is equivalent to an expression of the form (a+b x)/(c+d x) where b!=0 and d!=0.*) if ListQ(u): for i in u: if not QuotientOfLinearsQ(i, x): return False return True q = QuotientOfLinearsParts(u, x) return QuotientOfLinearsP(u, x) and NonzeroQ(q[1]) and NonzeroQ(q[3]) def Flatten(l): return flatten(l) def Sort(u, r=False): return sorted(u, key=lambda x: x.sort_key(), reverse=r) # (*Definition: A number is absurd if it is a rational number, a positive rational number raised to a fractional power, or a product of absurd numbers.*) def AbsurdNumberQ(u): # (* AbsurdNumberQ[u] returns True if u is an absurd number, else it returns False. *) if PowerQ(u): v = u.exp u = u.base return RationalQ(u) and u > 0 and FractionQ(v) elif ProductQ(u): return all(AbsurdNumberQ(i) for i in u.args) return RationalQ(u) def AbsurdNumberFactors(u): # (* AbsurdNumberFactors[u] returns the product of the factors of u that are absurd numbers. *) if AbsurdNumberQ(u): return u elif ProductQ(u): result = S(1) for i in u.args: if AbsurdNumberQ(i): result *= i return result return NumericFactor(u) def NonabsurdNumberFactors(u): # (* NonabsurdNumberFactors[u] returns the product of the factors of u that are not absurd numbers. *) if AbsurdNumberQ(u): return S(1) elif ProductQ(u): result = 1 for i in u.args: result *= NonabsurdNumberFactors(i) return result return NonnumericFactors(u) def SumSimplerAuxQ(u, v): if SumQ(v): return (RationalQ(First(v)) or SumSimplerAuxQ(u,First(v))) and (RationalQ(Rest(v)) or SumSimplerAuxQ(u,Rest(v))) elif SumQ(u): return SumSimplerAuxQ(First(u), v) or SumSimplerAuxQ(Rest(u), v) else: return v!=0 and NonnumericFactors(u)==NonnumericFactors(v) and (NumericFactor(u)/NumericFactor(v)<-1/2 or NumericFactor(u)/NumericFactor(v)==-1/2 and NumericFactor(u)<0) def Prepend(l1, l2): if not isinstance(l2, list): return [l2] + l1 return l2 + l1 def Drop(lst, n): if isinstance(lst, list): if isinstance(n, list): lst = lst[:(n[0]-1)] + lst[n[1]:] elif n > 0: lst = lst[n:] elif n < 0: lst = lst[:-n] else: return lst return lst return lst.func(*[i for i in Drop(list(lst.args), n)]) def CombineExponents(lst): if Length(lst) < 2: return lst elif lst[0][0] == lst[1][0]: return CombineExponents(Prepend(Drop(lst,2),[lst[0][0], lst[0][1] + lst[1][1]])) return Prepend(CombineExponents(Rest(lst)), First(lst)) def FactorInteger(n, l=None): if isinstance(n, (int, Integer)): return sorted(factorint(n, limit=l).items()) else: return sorted(factorrat(n, limit=l).items()) def FactorAbsurdNumber(m): # (* m must be an absurd number. FactorAbsurdNumber[m] returns the prime factorization of m *) # (* as list of base-degree pairs where the bases are prime numbers and the degrees are rational. *) if RationalQ(m): return FactorInteger(m) elif PowerQ(m): r = FactorInteger(m.base) return [r[0], r[1]*m.exp] # CombineExponents[Sort[Flatten[Map[FactorAbsurdNumber,Apply[List,m]],1], Function[i1[[1]]>> from sympy.integrals.rubi.utility_function import SubstForInverseFunction >>> from sympy.abc import x, a, b >>> SubstForInverseFunction(a, a, b, x) a >>> SubstForInverseFunction(x**a, x**a, b, x) x >>> SubstForInverseFunction(a*x**a, a, b, x) a*b**a """ if len(args) == 3: u, v, x = args[0], args[1], args[2] return SubstForInverseFunction(u, v, (-Coefficient(v.args[0], x, 0) + InverseFunction(Head(v))(x))/Coefficient(v.args[0], x, 1), x) elif len(args) == 4: u, v, w, x = args[0], args[1], args[2], args[3] if AtomQ(u): if u == x: return w return u elif Head(u) == Head(v) and ZeroQ(u.args[0] - v.args[0]): return x res = [SubstForInverseFunction(i, v, w, x) for i in u.args] return u.func(*res) def SubstForFractionalPower(u, v, n, w, x): # (* SubstForFractionalPower[u,v,n,w,x] returns u with subexpressions equal to v^(m/n) replaced # by x^m and x replaced by w. *) if AtomQ(u): if u == x: return w return u elif FractionalPowerQ(u): if ZeroQ(u.base - v): return x**(n*u.exp) res = [SubstForFractionalPower(i, v, n, w, x) for i in u.args] return u.func(*res) def SubstForFractionalPowerOfQuotientOfLinears(u, x): # (* If u has a subexpression of the form ((a+b*x)/(c+d*x))^(m/n) where m and n>1 are integers, # SubstForFractionalPowerOfQuotientOfLinears[u,x] returns the list {v,n,(a+b*x)/(c+d*x),b*c-a*d} where v is u # with subexpressions of the form ((a+b*x)/(c+d*x))^(m/n) replaced by x^m and x replaced lst = FractionalPowerOfQuotientOfLinears(u, 1, False, x) if AtomQ(lst) or AtomQ(lst[1]): return False n = lst[0] tmp = lst[1] lst = QuotientOfLinearsParts(tmp, x) a, b, c, d = lst[0], lst[1], lst[2], lst[3] if ZeroQ(d): return False lst = Simplify(x**(n - 1)*SubstForFractionalPower(u, tmp, n, (-a + c*x**n)/(b - d*x**n), x)/(b - d*x**n)**2) return [NonfreeFactors(lst, x), n, tmp, FreeFactors(lst, x)*(b*c - a*d)] def FractionalPowerOfQuotientOfLinears(u, n, v, x): # (* If u has a subexpression of the form ((a+b*x)/(c+d*x))^(m/n), # FractionalPowerOfQuotientOfLinears[u,1,False,x] returns {n,(a+b*x)/(c+d*x)}; else it returns False. *) if AtomQ(u) or FreeQ(u, x): return [n, v] elif CalculusQ(u): return False elif FractionalPowerQ(u): if QuotientOfLinearsQ(u.base, x) and Not(LinearQ(u.base, x)) and (FalseQ(v) or ZeroQ(u.base - v)): return [LCM(Denominator(u.exp), n), u.base] lst = [n, v] for i in u.args: lst = FractionalPowerOfQuotientOfLinears(i, lst[0], lst[1],x) if AtomQ(lst): return False return lst def SubstForFractionalPowerQ(u, v, x): # (* If the substitution x=v^(1/n) will not complicate algebraic subexpressions of u, # SubstForFractionalPowerQ[u,v,x] returns True; else it returns False. *) if AtomQ(u) or FreeQ(u, x): return True elif FractionalPowerQ(u): return SubstForFractionalPowerAuxQ(u, v, x) return all(SubstForFractionalPowerQ(i, v, x) for i in u.args) def SubstForFractionalPowerAuxQ(u, v, x): if AtomQ(u): return False elif FractionalPowerQ(u): if ZeroQ(u.base - v): return True return any(SubstForFractionalPowerAuxQ(i, v, x) for i in u.args) def FractionalPowerOfSquareQ(u): # (* If a subexpression of u is of the form ((v+w)^2)^n where n is a fraction, *) # (* FractionalPowerOfSquareQ[u] returns (v+w)^2; else it returns False. *) if AtomQ(u): return False elif FractionalPowerQ(u): a_ = Wild('a', exclude=[0]) b_ = Wild('b', exclude=[0]) c_ = Wild('c', exclude=[0]) match = u.base.match(a_*(b_ + c_)**(S(2))) if match: keys = [a_, b_, c_] if len(keys) == len(match): a, b, c = tuple(match[i] for i in keys) if NonsumQ(a): return (b + c)**S(2) for i in u.args: tmp = FractionalPowerOfSquareQ(i) if Not(FalseQ(tmp)): return tmp return False def FractionalPowerSubexpressionQ(u, v, w): # (* If a subexpression of u is of the form w^n where n is a fraction but not equal to v, *) # (* FractionalPowerSubexpressionQ[u,v,w] returns True; else it returns False. *) if AtomQ(u): return False elif FractionalPowerQ(u): if PositiveQ(u.base/w): return Not(u.base == v) and LeafCount(w) < 3*LeafCount(v) for i in u.args: if FractionalPowerSubexpressionQ(i, v, w): return True return False def Apply(f, lst): return f(*lst) def FactorNumericGcd(u): # (* FactorNumericGcd[u] returns u with the gcd of the numeric coefficients of terms of sums factored out. *) if PowerQ(u): if RationalQ(u.exp): return FactorNumericGcd(u.base)**u.exp elif ProductQ(u): res = [FactorNumericGcd(i) for i in u.args] return Mul(*res) elif SumQ(u): g = GCD([NumericFactor(i) for i in u.args]) r = Add(*[i/g for i in u.args]) return g*r return u def MergeableFactorQ(bas, deg, v): # (* MergeableFactorQ[bas,deg,v] returns True iff bas equals the base of a factor of v or bas is a factor of every term of v. *) if bas == v: return RationalQ(deg + S(1)) and (deg + 1>=0 or RationalQ(deg) and deg>0) elif PowerQ(v): if bas == v.base: return RationalQ(deg+v.exp) and (deg+v.exp>=0 or RationalQ(deg) and deg>0) return SumQ(v.base) and IntegerQ(v.exp) and (Not(IntegerQ(deg) or IntegerQ(deg/v.exp))) and MergeableFactorQ(bas, deg/v.exp, v.base) elif ProductQ(v): return MergeableFactorQ(bas, deg, First(v)) or MergeableFactorQ(bas, deg, Rest(v)) return SumQ(v) and MergeableFactorQ(bas, deg, First(v)) and MergeableFactorQ(bas, deg, Rest(v)) def MergeFactor(bas, deg, v): # (* If MergeableFactorQ[bas,deg,v], MergeFactor[bas,deg,v] return the product of bas^deg and v, # but with bas^deg merged into the factor of v whose base equals bas. *) if bas == v: return bas**(deg + 1) elif PowerQ(v): if bas == v.base: return bas**(deg + v.exp) return MergeFactor(bas, deg/v.exp, v.base**v.exp) elif ProductQ(v): if MergeableFactorQ(bas, deg, First(v)): return MergeFactor(bas, deg, First(v))*Rest(v) return First(v)*MergeFactor(bas, deg, Rest(v)) return MergeFactor(bas, deg, First(v)) + MergeFactor(bas, deg, Rest(v)) def MergeFactors(u, v): # (* MergeFactors[u,v] returns the product of u and v, but with the mergeable factors of u merged into v. *) if ProductQ(u): return MergeFactors(Rest(u), MergeFactors(First(u), v)) elif PowerQ(u): if MergeableFactorQ(u.base, u.exp, v): return MergeFactor(u.base, u.exp, v) elif RationalQ(u.exp) and u.exp < -1 and MergeableFactorQ(u.base, -S(1), v): return MergeFactors(u.base**(u.exp + 1), MergeFactor(u.base, -S(1), v)) return u*v elif MergeableFactorQ(u, S(1), v): return MergeFactor(u, S(1), v) return u*v def TrigSimplifyQ(u): # (* TrigSimplifyQ[u] returns True if TrigSimplify[u] actually simplifies u; else False. *) return ActivateTrig(u) != TrigSimplify(u) def TrigSimplify(u): # (* TrigSimplify[u] returns a bottom-up trig simplification of u. *) return ActivateTrig(TrigSimplifyRecur(u)) def TrigSimplifyRecur(u): if AtomQ(u): return u return TrigSimplifyAux(u.func(*[TrigSimplifyRecur(i) for i in u.args])) def Order(expr1, expr2): if expr1 == expr2: return 0 elif expr1.sort_key() > expr2.sort_key(): return -1 return 1 def FactorOrder(u, v): if u == 1: if v == 1: return 0 return -1 elif v == 1: return 1 return Order(u, v) def Smallest(num1, num2=None): if num2 is None: lst = num1 num = lst[0] for i in Rest(lst): num = Smallest(num, i) return num return Min(num1, num2) def OrderedQ(l): return l == Sort(l) def MinimumDegree(deg1, deg2): if RationalQ(deg1): if RationalQ(deg2): return Min(deg1, deg2) return deg1 elif RationalQ(deg2): return deg2 deg = Simplify(deg1- deg2) if RationalQ(deg): if deg > 0: return deg2 return deg1 elif OrderedQ([deg1, deg2]): return deg1 return deg2 def PositiveFactors(u): # (* PositiveFactors[u] returns the positive factors of u *) if ZeroQ(u): return S(1) elif RationalQ(u): return Abs(u) elif PositiveQ(u): return u elif ProductQ(u): res = 1 for i in u.args: res *= PositiveFactors(i) return res return 1 def Sign(u): return sign(u) def NonpositiveFactors(u): # (* NonpositiveFactors[u] returns the nonpositive factors of u *) if ZeroQ(u): return u elif RationalQ(u): return Sign(u) elif PositiveQ(u): return S(1) elif ProductQ(u): res = S(1) for i in u.args: res *= NonpositiveFactors(i) return res return u def PolynomialInAuxQ(u, v, x): if u == v: return True elif AtomQ(u): return u != x elif PowerQ(u): if PowerQ(v): if u.base == v.base: return PositiveIntegerQ(u.exp/v.exp) return PositiveIntegerQ(u.exp) and PolynomialInAuxQ(u.base, v, x) elif SumQ(u) or ProductQ(u): for i in u.args: if Not(PolynomialInAuxQ(i, v, x)): return False return True return False def PolynomialInQ(u, v, x): """ If u is a polynomial in v(x), PolynomialInQ(u, v, x) returns True, else it returns False. Examples ======== >>> from sympy.integrals.rubi.utility_function import PolynomialInQ >>> from sympy.abc import x >>> from sympy import log, S >>> PolynomialInQ(S(1), log(x), x) True >>> PolynomialInQ(log(x), log(x), x) True >>> PolynomialInQ(1 + log(x)**2, log(x), x) True """ return PolynomialInAuxQ(u, NonfreeFactors(NonfreeTerms(v, x), x), x) def ExponentInAux(u, v, x): if u == v: return S(1) elif AtomQ(u): return S(0) elif PowerQ(u): if PowerQ(v): if u.base == v.base: return u.exp/v.exp return u.exp*ExponentInAux(u.base, v, x) elif ProductQ(u): return Add(*[ExponentInAux(i, v, x) for i in u.args]) return Max(*[ExponentInAux(i, v, x) for i in u.args]) def ExponentIn(u, v, x): return ExponentInAux(u, NonfreeFactors(NonfreeTerms(v, x), x), x) def PolynomialInSubstAux(u, v, x): if u == v: return x elif AtomQ(u): return u elif PowerQ(u): if PowerQ(v): if u.base == v.base: return x**(u.exp/v.exp) return PolynomialInSubstAux(u.base, v, x)**u.exp return u.func(*[PolynomialInSubstAux(i, v, x) for i in u.args]) def PolynomialInSubst(u, v, x): # If u is a polynomial in v[x], PolynomialInSubst[u,v,x] returns the polynomial u in x. w = NonfreeTerms(v, x) return ReplaceAll(PolynomialInSubstAux(u, NonfreeFactors(w, x), x), {x: x - FreeTerms(v, x)/FreeFactors(w, x)}) def Distrib(u, v): # Distrib[u,v] returns the sum of u times each term of v. if SumQ(v): return Add(*[u*i for i in v.args]) return u*v def DistributeDegree(u, m): # DistributeDegree[u,m] returns the product of the factors of u each raised to the mth degree. if AtomQ(u): return u**m elif PowerQ(u): return u.base**(u.exp*m) elif ProductQ(u): return Mul(*[DistributeDegree(i, m) for i in u.args]) return u**m def FunctionOfPower(*args): """ FunctionOfPower[u,x] returns the gcd of the integer degrees of x in u. Examples ======== >>> from sympy.integrals.rubi.utility_function import FunctionOfPower >>> from sympy.abc import x >>> FunctionOfPower(x, x) 1 >>> FunctionOfPower(x**3, x) 3 """ if len(args) == 2: return FunctionOfPower(args[0], None, args[1]) u, n, x = args if FreeQ(u, x): return n elif u == x: return S(1) elif PowerQ(u): if u.base == x and IntegerQ(u.exp): if n is None: return u.exp return GCD(n, u.exp) tmp = n for i in u.args: tmp = FunctionOfPower(i, tmp, x) return tmp def DivideDegreesOfFactors(u, n): """ DivideDegreesOfFactors[u,n] returns the product of the base of the factors of u raised to the degree of the factors divided by n. Examples ======== >>> from sympy import S >>> from sympy.integrals.rubi.utility_function import DivideDegreesOfFactors >>> from sympy.abc import a, b >>> DivideDegreesOfFactors(a**b, S(3)) a**(b/3) """ if ProductQ(u): return Mul(*[LeadBase(i)**(LeadDegree(i)/n) for i in u.args]) return LeadBase(u)**(LeadDegree(u)/n) def MonomialFactor(u, x): # MonomialFactor[u,x] returns the list {n,v} where x^n*v==u and n is free of x. if AtomQ(u): if u == x: return [S(1), S(1)] return [S(0), u] elif PowerQ(u): if IntegerQ(u.exp): lst = MonomialFactor(u.base, x) return [lst[0]*u.exp, lst[1]**u.exp] elif u.base == x and FreeQ(u.exp, x): return [u.exp, S(1)] return [S(0), u] elif ProductQ(u): lst1 = MonomialFactor(First(u), x) lst2 = MonomialFactor(Rest(u), x) return [lst1[0] + lst2[0], lst1[1]*lst2[1]] elif SumQ(u): lst = [MonomialFactor(i, x) for i in u.args] deg = lst[0][0] for i in Rest(lst): deg = MinimumDegree(deg, i[0]) if ZeroQ(deg) or RationalQ(deg) and deg < 0: return [S(0), u] return [deg, Add(*[x**(i[0] - deg)*i[1] for i in lst])] return [S(0), u] def FullSimplify(expr): return Simplify(expr) def FunctionOfLinearSubst(u, a, b, x): if FreeQ(u, x): return u elif LinearQ(u, x): tmp = Coefficient(u, x, 1) if tmp == b: tmp = S(1) else: tmp = tmp/b return Coefficient(u, x, S(0)) - a*tmp + tmp*x elif PowerQ(u): if FreeQ(u.base, x): return E**(FullSimplify(FunctionOfLinearSubst(Log(u.base)*u.exp, a, b, x))) lst = MonomialFactor(u, x) if ProductQ(u) and NonzeroQ(lst[0]): if RationalQ(LeadFactor(lst[1])) and LeadFactor(lst[1]) < 0: return -FunctionOfLinearSubst(DivideDegreesOfFactors(-lst[1], lst[0])*x, a, b, x)**lst[0] return FunctionOfLinearSubst(DivideDegreesOfFactors(lst[1], lst[0])*x, a, b, x)**lst[0] return u.func(*[FunctionOfLinearSubst(i, a, b, x) for i in u.args]) def FunctionOfLinear(*args): # (* If u (x) is equivalent to an expression of the form f (a+b*x) and not the case that a==0 and # b==1, FunctionOfLinear[u,x] returns the list {f (x),a,b}; else it returns False. *) if len(args) == 2: u, x = args lst = FunctionOfLinear(u, False, False, x, False) if AtomQ(lst) or FalseQ(lst[0]) or (lst[0] == 0 and lst[1] == 1): return False return [FunctionOfLinearSubst(u, lst[0], lst[1], x), lst[0], lst[1]] u, a, b, x, flag = args if FreeQ(u, x): return [a, b] elif CalculusQ(u): return False elif LinearQ(u, x): if FalseQ(a): return [Coefficient(u, x, 0), Coefficient(u, x, 1)] lst = CommonFactors([b, Coefficient(u, x, 1)]) if ZeroQ(Coefficient(u, x, 0)) and Not(flag): return [0, lst[0]] elif ZeroQ(b*Coefficient(u, x, 0) - a*Coefficient(u, x, 1)): return [a/lst[1], lst[0]] return [0, 1] elif PowerQ(u): if FreeQ(u.base, x): return FunctionOfLinear(Log(u.base)*u.exp, a, b, x, False) lst = MonomialFactor(u, x) if ProductQ(u) and NonzeroQ(lst[0]): if False and IntegerQ(lst[0]) and lst[0] != -1 and FreeQ(lst[1], x): if RationalQ(LeadFactor(lst[1])) and LeadFactor(lst[1]) < 0: return FunctionOfLinear(DivideDegreesOfFactors(-lst[1], lst[0])*x, a, b, x, False) return FunctionOfLinear(DivideDegreesOfFactors(lst[1], lst[0])*x, a, b, x, False) return False lst = [a, b] for i in u.args: lst = FunctionOfLinear(i, lst[0], lst[1], x, SumQ(u)) if AtomQ(lst): return False return lst def NormalizeIntegrand(u, x): v = NormalizeLeadTermSigns(NormalizeIntegrandAux(u, x)) if v == NormalizeLeadTermSigns(u): return u else: return v def NormalizeIntegrandAux(u, x): if SumQ(u): l = 0 for i in u.args: l += NormalizeIntegrandAux(i, x) return l if ProductQ(MergeMonomials(u, x)): l = 1 for i in MergeMonomials(u, x).args: l *= NormalizeIntegrandFactor(i, x) return l else: return NormalizeIntegrandFactor(MergeMonomials(u, x), x) def NormalizeIntegrandFactor(u, x): if PowerQ(u): if FreeQ(u.exp, x): bas = NormalizeIntegrandFactorBase(u.base, x) deg = u.exp if IntegerQ(deg) and SumQ(bas): if all(MonomialQ(i, x) for i in bas.args): mi = MinimumMonomialExponent(bas, x) q = 0 for i in bas.args: q += Simplify(i/x**mi) return x**(mi*deg)*q**deg else: return bas**deg else: return bas**deg if PowerQ(u): if FreeQ(u.base, x): return u.base**NormalizeIntegrandFactorBase(u.exp, x) bas = NormalizeIntegrandFactorBase(u, x) if SumQ(bas): if all(MonomialQ(i, x) for i in bas.args): mi = MinimumMonomialExponent(bas, x) z = 0 for j in bas.args: z += j/x**mi return x**mi*z else: return bas else: return bas def NormalizeIntegrandFactorBase(expr, x): m = Wild('m', exclude=[x]) u = Wild('u') match = expr.match(x**m*u) if match and SumQ(u): l = 0 for i in u.args: l += NormalizeIntegrandFactorBase((x**m*i), x) return l if BinomialQ(expr, x): if BinomialMatchQ(expr, x): return expr else: return ExpandToSum(expr, x) elif TrinomialQ(expr, x): if TrinomialMatchQ(expr, x): return expr else: return ExpandToSum(expr, x) elif ProductQ(expr): l = 1 for i in expr.args: l *= NormalizeIntegrandFactor(i, x) return l elif PolynomialQ(expr, x) and Exponent(expr, x) <= 4: return ExpandToSum(expr, x) elif SumQ(expr): w = Wild('w') m = Wild('m', exclude=[x]) v = TogetherSimplify(expr) if SumQ(v) or v.match(x**m*w) and SumQ(w) or LeafCount(v) > LeafCount(expr) + 2: return UnifySum(expr, x) else: return NormalizeIntegrandFactorBase(v, x) else: return expr def NormalizeTogether(u): return NormalizeLeadTermSigns(Together(u)) def NormalizeLeadTermSigns(u): if ProductQ(u): t = 1 for i in u.args: lst = SignOfFactor(i) if lst[0] == 1: t *= lst[1] else: t *= AbsorbMinusSign(lst[1]) return t else: lst = SignOfFactor(u) if lst[0] == 1: return lst[1] else: return AbsorbMinusSign(lst[1]) def AbsorbMinusSign(expr, *x): m = Wild('m', exclude=[x]) u = Wild('u') v = Wild('v') match = expr.match(u*v**m) if match: if len(match) == 3: if SumQ(match[v]) and OddQ(match[m]): return match[u]*(-match[v])**match[m] return -expr def NormalizeSumFactors(u): if AtomQ(u): return u elif ProductQ(u): k = 1 for i in u.args: k *= NormalizeSumFactors(i) return SignOfFactor(k)[0]*SignOfFactor(k)[1] elif SumQ(u): k = 0 for i in u.args: k += NormalizeSumFactors(i) return k else: return u def SignOfFactor(u): if RationalQ(u) and u < 0 or SumQ(u) and NumericFactor(First(u)) < 0: return [-1, -u] elif IntegerPowerQ(u): if SumQ(u.base) and NumericFactor(First(u.base)) < 0: return [(-1)**u.exp, (-u.base)**u.exp] elif ProductQ(u): k = 1 h = 1 for i in u.args: k *= SignOfFactor(i)[0] h *= SignOfFactor(i)[1] return [k, h] return [1, u] def NormalizePowerOfLinear(u, x): v = FactorSquareFree(u) if PowerQ(v): if LinearQ(v.base, x) and FreeQ(v.exp, x): return ExpandToSum(v.base, x)**v.exp return ExpandToSum(v, x) def SimplifyIntegrand(u, x): v = NormalizeLeadTermSigns(NormalizeIntegrandAux(Simplify(u), x)) if 5*LeafCount(v) < 4*LeafCount(u): return v if v != NormalizeLeadTermSigns(u): return v else: return u def SimplifyTerm(u, x): v = Simplify(u) w = Together(v) if LeafCount(v) < LeafCount(w): return NormalizeIntegrand(v, x) else: return NormalizeIntegrand(w, x) def TogetherSimplify(u): v = Together(Simplify(Together(u))) return FixSimplify(v) def SmartSimplify(u): v = Simplify(u) w = factor(v) if LeafCount(w) < LeafCount(v): v = w if Not(FalseQ(w == FractionalPowerOfSquareQ(v))) and FractionalPowerSubexpressionQ(u, w, Expand(w)): v = SubstForExpn(v, w, Expand(w)) else: v = FactorNumericGcd(v) return FixSimplify(v) def SubstForExpn(u, v, w): if u == v: return w if AtomQ(u): return u else: k = 0 for i in u.args: k += SubstForExpn(i, v, w) return k def ExpandToSum(u, *x): if len(x) == 1: x = x[0] expr = 0 if PolyQ(S(u), x): for t in ExponentList(u, x): expr += Coeff(u, x, t)*x**t return expr if BinomialQ(u, x): i = BinomialParts(u, x) expr += i[0] + i[1]*x**i[2] return expr if TrinomialQ(u, x): i = TrinomialParts(u, x) expr += i[0] + i[1]*x**i[3] + i[2]*x**(2*i[3]) return expr if GeneralizedBinomialMatchQ(u, x): i = GeneralizedBinomialParts(u, x) expr += i[0]*x**i[3] + i[1]*x**i[2] return expr if GeneralizedTrinomialMatchQ(u, x): i = GeneralizedTrinomialParts(u, x) expr += i[0]*x**i[4] + i[1]*x**i[3] + i[2]*x**(2*i[3]-i[4]) return expr else: return Expand(u) else: v = x[0] x = x[1] w = ExpandToSum(v, x) r = NonfreeTerms(w, x) if SumQ(r): k = u*FreeTerms(w, x) for i in r.args: k += MergeMonomials(u*i, x) return k else: return u*FreeTerms(w, x) + MergeMonomials(u*r, x) def UnifySum(u, x): if SumQ(u): t = 0 lst = [] for i in u.args: lst += [i] for j in UnifyTerms(lst, x): t += j return t else: return SimplifyTerm(u, x) def UnifyTerms(lst, x): if lst==[]: return lst else: return UnifyTerm(First(lst), UnifyTerms(Rest(lst), x), x) def UnifyTerm(term, lst, x): if lst==[]: return [term] tmp = Simplify(First(lst)/term) if FreeQ(tmp, x): return Prepend(Rest(lst), [(1+tmp)*term]) else: return Prepend(UnifyTerm(term, Rest(lst), x), [First(lst)]) def CalculusQ(u): return False def FunctionOfInverseLinear(*args): # (* If u is a function of an inverse linear binomial of the form 1/(a+b*x), # FunctionOfInverseLinear[u,x] returns the list {a,b}; else it returns False. *) if len(args) == 2: u, x = args return FunctionOfInverseLinear(u, None, x) u, lst, x = args if FreeQ(u, x): return lst elif u == x: return False elif QuotientOfLinearsQ(u, x): tmp = Drop(QuotientOfLinearsParts(u, x), 2) if tmp[1] == 0: return False elif lst is None: return tmp elif ZeroQ(lst[0]*tmp[1] - lst[1]*tmp[0]): return lst return False elif CalculusQ(u): return False tmp = lst for i in u.args: tmp = FunctionOfInverseLinear(i, tmp, x) if AtomQ(tmp): return False return tmp def PureFunctionOfSinhQ(u, v, x): # (* If u is a pure function of Sinh[v] and/or Csch[v], PureFunctionOfSinhQ[u,v,x] returns True; # else it returns False. *) if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and ZeroQ(u.args[0] - v): return SinhQ(u) or CschQ(u) for i in u.args: if Not(PureFunctionOfSinhQ(i, v, x)): return False return True def PureFunctionOfTanhQ(u, v , x): # (* If u is a pure function of Tanh[v] and/or Coth[v], PureFunctionOfTanhQ[u,v,x] returns True; # else it returns False. *) if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and ZeroQ(u.args[0] - v): return TanhQ(u) or CothQ(u) for i in u.args: if Not(PureFunctionOfTanhQ(i, v, x)): return False return True def PureFunctionOfCoshQ(u, v, x): # (* If u is a pure function of Cosh[v] and/or Sech[v], PureFunctionOfCoshQ[u,v,x] returns True; # else it returns False. *) if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and ZeroQ(u.args[0] - v): return CoshQ(u) or SechQ(u) for i in u.args: if Not(PureFunctionOfCoshQ(i, v, x)): return False return True def IntegerQuotientQ(u, v): # (* If u/v is an integer, IntegerQuotientQ[u,v] returns True; else it returns False. *) return IntegerQ(Simplify(u/v)) def OddQuotientQ(u, v): # (* If u/v is odd, OddQuotientQ[u,v] returns True; else it returns False. *) return OddQ(Simplify(u/v)) def EvenQuotientQ(u, v): # (* If u/v is even, EvenQuotientQ[u,v] returns True; else it returns False. *) return EvenQ(Simplify(u/v)) def FindTrigFactor(func1, func2, u, v, flag): # (* If func[w]^m is a factor of u where m is odd and w is an integer multiple of v, # FindTrigFactor[func1,func2,u,v,True] returns the list {w,u/func[w]^n}; else it returns False. *) # (* If func[w]^m is a factor of u where m is odd and w is an integer multiple of v not equal to v, # FindTrigFactor[func1,func2,u,v,False] returns the list {w,u/func[w]^n}; else it returns False. *) if u == 1: return False elif (Head(LeadBase(u)) == func1 or Head(LeadBase(u)) == func2) and OddQ(LeadDegree(u)) and IntegerQuotientQ(LeadBase(u).args[0], v) and (flag or NonzeroQ(LeadBase(u).args[0] - v)): return [LeadBase[u].args[0], RemainingFactors(u)] lst = FindTrigFactor(func1, func2, RemainingFactors(u), v, flag) if AtomQ(lst): return False return [lst[0], LeadFactor(u)*lst[1]] def FunctionOfSinhQ(u, v, x): # (* If u is a function of Sinh[v], FunctionOfSinhQ[u,v,x] returns True; else it returns False. *) if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v): if OddQuotientQ(u.args[0], v): # (* Basis: If m odd, Sinh[m*v]^n is a function of Sinh[v]. *) return SinhQ(u) or CschQ(u) # (* Basis: If m even, Cos[m*v]^n is a function of Sinh[v]. *) return CoshQ(u) or SechQ(u) elif IntegerPowerQ(u): if HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v): if EvenQ(u.exp): # (* Basis: If m integer and n even, Hyper[m*v]^n is a function of Sinh[v]. *) return True return FunctionOfSinhQ(u.base, v, x) elif ProductQ(u): if CoshQ(u.args[0]) and SinhQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2): return FunctionOfSinhQ(Drop(u, 2), v, x) lst = FindTrigFactor(Sinh, Csch, u, v, False) if ListQ(lst) and EvenQuotientQ(lst[0], v): # (* Basis: If m even and n odd, Sinh[m*v]^n == Cosh[v]*u where u is a function of Sinh[v]. *) return FunctionOfSinhQ(Cosh(v)*lst[1], v, x) lst = FindTrigFactor(Cosh, Sech, u, v, False) if ListQ(lst) and OddQuotientQ(lst[0], v): # (* Basis: If m odd and n odd, Cosh[m*v]^n == Cosh[v]*u where u is a function of Sinh[v]. *) return FunctionOfSinhQ(Cosh(v)*lst[1], v, x) lst = FindTrigFactor(Tanh, Coth, u, v, True) if ListQ(lst): # (* Basis: If m integer and n odd, Tanh[m*v]^n == Cosh[v]*u where u is a function of Sinh[v]. *) return FunctionOfSinhQ(Cosh(v)*lst[1], v, x) return all(FunctionOfSinhQ(i, v, x) for i in u.args) return all(FunctionOfSinhQ(i, v, x) for i in u.args) def FunctionOfCoshQ(u, v, x): #(* If u is a function of Cosh[v], FunctionOfCoshQ[u,v,x] returns True; else it returns False. *) if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v): # (* Basis: If m integer, Cosh[m*v]^n is a function of Cosh[v]. *) return CoshQ(u) or SechQ(u) elif IntegerPowerQ(u): if HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v): if EvenQ(u.exp): # (* Basis: If m integer and n even, Hyper[m*v]^n is a function of Cosh[v]. *) return True return FunctionOfCoshQ(u.base, v, x) elif ProductQ(u): lst = FindTrigFactor(Sinh, Csch, u, v, False) if ListQ(lst): # (* Basis: If m integer and n odd, Sinh[m*v]^n == Sinh[v]*u where u is a function of Cosh[v]. *) return FunctionOfCoshQ(Sinh(v)*lst[1], v, x) lst = FindTrigFactor(Tanh, Coth, u, v, True) if ListQ(lst): # (* Basis: If m integer and n odd, Tanh[m*v]^n == Sinh[v]*u where u is a function of Cosh[v]. *) return FunctionOfCoshQ(Sinh(v)*lst[1], v, x) return all(FunctionOfCoshQ(i, v, x) for i in u.args) return all(FunctionOfCoshQ(i, v, x) for i in u.args) def OddHyperbolicPowerQ(u, v, x): if SinhQ(u) or CoshQ(u) or SechQ(u) or CschQ(u): return OddQuotientQ(u.args[0], v) if PowerQ(u): return OddQ(u.exp) and OddHyperbolicPowerQ(u.base, v, x) if ProductQ(u): if Not(EqQ(FreeFactors(u, x), 1)): return OddHyperbolicPowerQ(NonfreeFactors(u, x), v, x) lst = [] for i in u.args: if Not(FunctionOfTanhQ(i, v, x)): lst.append(i) if lst == []: return True return Length(lst)==1 and OddHyperbolicPowerQ(lst[0], v, x) if SumQ(u): return all(OddHyperbolicPowerQ(i, v, x) for i in u.args) return False def FunctionOfTanhQ(u, v, x): #(* If u is a function of the form f[Tanh[v],Coth[v]] where f is independent of x, # FunctionOfTanhQ[u,v,x] returns True; else it returns False. *) if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v): return TanhQ(u) or CothQ(u) or EvenQuotientQ(u.args[0], v) elif PowerQ(u): if EvenQ(u.exp) and HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v): return True elif EvenQ(u.args[1]) and SumQ(u.args[0]): return FunctionOfTanhQ(Expand(u.args[0]**2, v, x)) if ProductQ(u): lst = [] for i in u.args: if Not(FunctionOfTanhQ(i, v, x)): lst.append(i) if lst == []: return True return Length(lst)==2 and OddHyperbolicPowerQ(lst[0], v, x) and OddHyperbolicPowerQ(lst[1], v, x) return all(FunctionOfTanhQ(i, v, x) for i in u.args) def FunctionOfTanhWeight(u, v, x): """ u is a function of the form f(tanh(v), coth(v)) where f is independent of x. FunctionOfTanhWeight(u, v, x) returns a nonnegative number if u is best considered a function of tanh(v), else it returns a negative number. Examples ======== >>> from sympy import sinh, log, tanh >>> from sympy.abc import x >>> from sympy.integrals.rubi.utility_function import FunctionOfTanhWeight >>> FunctionOfTanhWeight(x, log(x), x) 0 >>> FunctionOfTanhWeight(sinh(log(x)), log(x), x) 0 >>> FunctionOfTanhWeight(tanh(log(x)), log(x), x) 1 """ if AtomQ(u): return S(0) elif CalculusQ(u): return S(0) elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v): if TanhQ(u) and ZeroQ(u.args[0] - v): return S(1) elif CothQ(u) and ZeroQ(u.args[0] - v): return S(-1) return S(0) elif PowerQ(u): if EvenQ(u.exp) and HyperbolicQ(u.base) and IntegerQuotientQ(u.base.args[0], v): if TanhQ(u.base) or CoshQ(u.base) or SechQ(u.base): return S(1) return S(-1) if ProductQ(u): if all(FunctionOfTanhQ(i, v, x) for i in u.args): return Add(*[FunctionOfTanhWeight(i, v, x) for i in u.args]) return S(0) return Add(*[FunctionOfTanhWeight(i, v, x) for i in u.args]) def FunctionOfHyperbolicQ(u, v, x): # (* If u (x) is equivalent to a function of the form f (Sinh[v],Cosh[v],Tanh[v],Coth[v],Sech[v],Csch[v]) # where f is independent of x, FunctionOfHyperbolicQ[u,v,x] returns True; else it returns False. *) if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v): return True return all(FunctionOfHyperbolicQ(i, v, x) for i in u.args) def SmartNumerator(expr): if PowerQ(expr): n = expr.exp u = expr.base if RationalQ(n) and n < 0: return SmartDenominator(u**(-n)) elif ProductQ(expr): return Mul(*[SmartNumerator(i) for i in expr.args]) return Numerator(expr) def SmartDenominator(expr): if PowerQ(expr): u = expr.base n = expr.exp if RationalQ(n) and n < 0: return SmartNumerator(u**(-n)) elif ProductQ(expr): return Mul(*[SmartDenominator(i) for i in expr.args]) return Denominator(expr) def ActivateTrig(u): return u def ExpandTrig(*args): if len(args) == 2: u, x = args return ActivateTrig(ExpandIntegrand(u, x)) u, v, x = args w = ExpandTrig(v, x) z = ActivateTrig(u) if SumQ(w): return w.func(*[z*i for i in w.args]) return z*w def TrigExpand(u): return expand_trig(u) # SubstForTrig[u_,sin_,cos_,v_,x_] := # If[AtomQ[u], # u, # If[TrigQ[u] && IntegerQuotientQ[u[[1]],v], # If[u[[1]]===v || ZeroQ[u[[1]]-v], # If[SinQ[u], # sin, # If[CosQ[u], # cos, # If[TanQ[u], # sin/cos, # If[CotQ[u], # cos/sin, # If[SecQ[u], # 1/cos, # 1/sin]]]]], # Map[Function[SubstForTrig[#,sin,cos,v,x]], # ReplaceAll[TrigExpand[Head[u][Simplify[u[[1]]/v]*x]],x->v]]], # If[ProductQ[u] && CosQ[u[[1]]] && SinQ[u[[2]]] && ZeroQ[u[[1,1]]-v/2] && ZeroQ[u[[2,1]]-v/2], # sin/2*SubstForTrig[Drop[u,2],sin,cos,v,x], # Map[Function[SubstForTrig[#,sin,cos,v,x]],u]]]] def SubstForTrig(u, sin_ , cos_, v, x): # (* u (v) is an expression of the form f (Sin[v],Cos[v],Tan[v],Cot[v],Sec[v],Csc[v]). *) # (* SubstForTrig[u,sin,cos,v,x] returns the expression f (sin,cos,sin/cos,cos/sin,1/cos,1/sin). *) if AtomQ(u): return u elif TrigQ(u) and IntegerQuotientQ(u.args[0], v): if u.args[0] == v or ZeroQ(u.args[0] - v): if SinQ(u): return sin_ elif CosQ(u): return cos_ elif TanQ(u): return sin_/cos_ elif CotQ(u): return cos_/sin_ elif SecQ(u): return 1/cos_ return 1/sin_ r = ReplaceAll(TrigExpand(Head(u)(Simplify(u.args[0]/v*x))), {x: v}) return r.func(*[SubstForTrig(i, sin_, cos_, v, x) for i in r.args]) if ProductQ(u) and CosQ(u.args[0]) and SinQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2): return sin(x)/2*SubstForTrig(Drop(u, 2), sin_, cos_, v, x) return u.func(*[SubstForTrig(i, sin_, cos_, v, x) for i in u.args]) def SubstForHyperbolic(u, sinh_, cosh_, v, x): # (* u (v) is an expression of the form f (Sinh[v],Cosh[v],Tanh[v],Coth[v],Sech[v],Csch[v]). *) # (* SubstForHyperbolic[u,sinh,cosh,v,x] returns the expression # f (sinh,cosh,sinh/cosh,cosh/sinh,1/cosh,1/sinh). *) if AtomQ(u): return u elif HyperbolicQ(u) and IntegerQuotientQ(u.args[0], v): if u.args[0] == v or ZeroQ(u.args[0] - v): if SinhQ(u): return sinh_ elif CoshQ(u): return cosh_ elif TanhQ(u): return sinh_/cosh_ elif CothQ(u): return cosh_/sinh_ if SechQ(u): return 1/cosh_ return 1/sinh_ r = ReplaceAll(TrigExpand(Head(u)(Simplify(u.args[0]/v)*x)), {x: v}) return r.func(*[SubstForHyperbolic(i, sinh_, cosh_, v, x) for i in r.args]) elif ProductQ(u) and CoshQ(u.args[0]) and SinhQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2): return sinh(x)/2*SubstForHyperbolic(Drop(u, 2), sinh_, cosh_, v, x) return u.func(*[SubstForHyperbolic(i, sinh_, cosh_, v, x) for i in u.args]) def InertTrigFreeQ(u): return FreeQ(u, sin) and FreeQ(u, cos) and FreeQ(u, tan) and FreeQ(u, cot) and FreeQ(u, sec) and FreeQ(u, csc) def LCM(a, b): return lcm(a, b) def SubstForFractionalPowerOfLinear(u, x): # (* If u has a subexpression of the form (a+b*x)^(m/n) where m and n>1 are integers, # SubstForFractionalPowerOfLinear[u,x] returns the list {v,n,a+b*x,1/b} where v is u # with subexpressions of the form (a+b*x)^(m/n) replaced by x^m and x replaced # by -a/b+x^n/b, and all times x^(n-1); else it returns False. *) lst = FractionalPowerOfLinear(u, S(1), False, x) if AtomQ(lst) or FalseQ(lst[1]): return False n = lst[0] a = Coefficient(lst[1], x, 0) b = Coefficient(lst[1], x, 1) tmp = Simplify(x**(n-1)*SubstForFractionalPower(u, lst[1], n, -a/b + x**n/b, x)) return [NonfreeFactors(tmp, x), n, lst[1], FreeFactors(tmp, x)/b] def FractionalPowerOfLinear(u, n, v, x): # If u has a subexpression of the form (a + b*x)**(m/n), FractionalPowerOfLinear(u, 1, False, x) returns [n, a + b*x], else it returns False. if AtomQ(u) or FreeQ(u, x): return [n, v] elif CalculusQ(u): return False elif FractionalPowerQ(u): if LinearQ(u.base, x) and (FalseQ(v) or ZeroQ(u.base - v)): return [LCM(Denominator(u.exp), n), u.base] lst = [n, v] for i in u.args: lst = FractionalPowerOfLinear(i, lst[0], lst[1], x) if AtomQ(lst): return False return lst def InverseFunctionOfLinear(u, x): # (* If u has a subexpression of the form g[a+b*x] where g is an inverse function, # InverseFunctionOfLinear[u,x] returns g[a+b*x]; else it returns False. *) if AtomQ(u) or CalculusQ(u) or FreeQ(u, x): return False elif InverseFunctionQ(u) and LinearQ(u.args[0], x): return u for i in u.args: tmp = InverseFunctionOfLinear(i, x) if Not(AtomQ(tmp)): return tmp return False def InertTrigQ(*args): if len(args) == 1: f = args[0] l = [sin,cos,tan,cot,sec,csc] return any(Head(f) == i for i in l) elif len(args) == 2: f, g = args if f == g: return InertTrigQ(f) return InertReciprocalQ(f, g) or InertReciprocalQ(g, f) else: f, g, h = args return InertTrigQ(g, f) and InertTrigQ(g, h) def InertReciprocalQ(f, g): return (f.func == sin and g.func == csc) or (f.func == cos and g.func == sec) or (f.func == tan and g.func == cot) def DeactivateTrig(u, x): # (* u is a function of trig functions of a linear function of x. *) # (* DeactivateTrig[u,x] returns u with the trig functions replaced with inert trig functions. *) return FixInertTrigFunction(DeactivateTrigAux(u, x), x) def FixInertTrigFunction(u, x): return u def DeactivateTrigAux(u, x): if AtomQ(u): return u elif TrigQ(u) and LinearQ(u.args[0], x): v = ExpandToSum(u.args[0], x) if SinQ(u): return sin(v) elif CosQ(u): return cos(v) elif TanQ(u): return tan(u) elif CotQ(u): return cot(v) elif SecQ(u): return sec(v) return csc(v) elif HyperbolicQ(u) and LinearQ(u.args[0], x): v = ExpandToSum(I*u.args[0], x) if SinhQ(u): return -I*sin(v) elif CoshQ(u): return cos(v) elif TanhQ(u): return -I*tan(v) elif CothQ(u): I*cot(v) elif SechQ(u): return sec(v) return I*csc(v) return u.func(*[DeactivateTrigAux(i, x) for i in u.args]) def PowerOfInertTrigSumQ(u, func, x): p_ = Wild('p', exclude=[x]) q_ = Wild('q', exclude=[x]) a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x]) c_ = Wild('c', exclude=[x]) d_ = Wild('d', exclude=[x]) n_ = Wild('n', exclude=[x]) w_ = Wild('w') pattern = (a_ + b_*(c_*func(w_))**p_)**n_ match = u.match(pattern) if match: keys = [a_, b_, c_, n_, p_, w_] if len(keys) == len(match): return True pattern = (a_ + b_*(d_*func(w_))**p_ + c_*(d_*func(w_))**q_)**n_ match = u.match(pattern) if match: keys = [a_, b_, c_, d_, n_, p_, q_, w_] if len(keys) == len(match): return True return False def PiecewiseLinearQ(*args): # (* If the derivative of u wrt x is a constant wrt x, PiecewiseLinearQ[u,x] returns True; # else it returns False. *) if len(args) == 3: u, v, x = args return PiecewiseLinearQ(u, x) and PiecewiseLinearQ(v, x) u, x = args if LinearQ(u, x): return True c_ = Wild('c', exclude=[x]) F_ = Wild('F', exclude=[x]) v_ = Wild('v') match = u.match(Log(c_*F_**v_)) if match: if len(match) == 3: if LinearQ(match[v_], x): return True try: F = type(u) G = type(u.args[0]) v = u.args[0].args[0] if LinearQ(v, x): if MemberQ([[atanh, tanh], [atanh, coth], [acoth, coth], [acoth, tanh], [atan, tan], [atan, cot], [acot, cot], [acot, tan]], [F, G]): return True except: pass return False def KnownTrigIntegrandQ(lst, u, x): if u == 1: return True a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x, 0]) func_ = WildFunction('func') m_ = Wild('m', exclude=[x]) A_ = Wild('A', exclude=[x]) B_ = Wild('B', exclude=[x, 0]) C_ = Wild('C', exclude=[x, 0]) match = u.match((a_ + b_*func_)**m_) if match: func = match[func_] if LinearQ(func.args[0], x) and MemberQ(lst, func.func): return True match = u.match((a_ + b_*func_)**m_*(A_ + B_*func_)) if match: func = match[func_] if LinearQ(func.args[0], x) and MemberQ(lst, func.func): return True match = u.match(A_ + C_*func_**2) if match: func = match[func_] if LinearQ(func.args[0], x) and MemberQ(lst, func.func): return True match = u.match(A_ + B_*func_ + C_*func_**2) if match: func = match[func_] if LinearQ(func.args[0], x) and MemberQ(lst, func.func): return True match = u.match((a_ + b_*func_)**m_*(A_ + C_*func_**2)) if match: func = match[func_] if LinearQ(func.args[0], x) and MemberQ(lst, func.func): return True match = u.match((a_ + b_*func_)**m_*(A_ + B_*func_ + C_*func_**2)) if match: func = match[func_] if LinearQ(func.args[0], x) and MemberQ(lst, func.func): return True return False def KnownSineIntegrandQ(u, x): return KnownTrigIntegrandQ([sin, cos], u, x) def KnownTangentIntegrandQ(u, x): return KnownTrigIntegrandQ([tan], u, x) def KnownCotangentIntegrandQ(u, x): return KnownTrigIntegrandQ([cot], u, x) def KnownSecantIntegrandQ(u, x): return KnownTrigIntegrandQ([sec, csc], u, x) def TryPureTanSubst(u, x): a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x]) c_ = Wild('c', exclude=[x]) G_ = Wild('G') F = u.func try: if MemberQ([atan, acot, atanh, acoth], F): match = u.args[0].match(c_*(a_ + b_*G_)) if match: if len(match) == 4: G = match[G_] if MemberQ([tan, cot, tanh, coth], G.func): if LinearQ(G.args[0], x): return True except: pass return False def TryTanhSubst(u, x): if LogQ(u): return False elif not FalseQ(FunctionOfLinear(u, x)): return False a_ = Wild('a', exclude=[x]) m_ = Wild('m', exclude=[x]) p_ = Wild('p', exclude=[x]) r_, s_, t_, n_, b_, f_, g_ = map(Wild, 'rstnbfg') match = u.match(r_*(s_ + t_)**n_) if match: if len(match) == 4: r, s, t, n = [match[i] for i in [r_, s_, t_, n_]] if IntegerQ(n) and PositiveQ(n): return False match = u.match(1/(a_ + b_*f_**n_)) if match: if len(match) == 4: a, b, f, n = [match[i] for i in [a_, b_, f_, n_]] if SinhCoshQ(f) and IntegerQ(n) and n > 2: return False match = u.match(f_*g_) if match: if len(match) == 2: f, g = match[f_], match[g_] if SinhCoshQ(f) and SinhCoshQ(g): if IntegersQ(f.args[0]/x, g.args[0]/x): return False match = u.match(r_*(a_*s_**m_)**p_) if match: if len(match) == 5: r, a, s, m, p = [match[i] for i in [r_, a_, s_, m_, p_]] if Not(m==2 and (s == Sech(x) or s == Csch(x))): return False if u != ExpandIntegrand(u, x): return False return True def TryPureTanhSubst(u, x): F = u.func a_ = Wild('a', exclude=[x]) G_ = Wild('G') if F == sym_log: return False match = u.args[0].match(a_*G_) if match and len(match) == 2: G = match[G_].func if MemberQ([atanh, acoth], F) and MemberQ([tanh, coth], G): return False if u != ExpandIntegrand(u, x): return False return True def AbsurdNumberGCD(*seq): # (* m, n, ... must be absurd numbers. AbsurdNumberGCD[m,n,...] returns the gcd of m, n, ... *) lst = list(seq) if Length(lst) == 1: return First(lst) return AbsurdNumberGCDList(FactorAbsurdNumber(First(lst)), FactorAbsurdNumber(AbsurdNumberGCD(*Rest(lst)))) def AbsurdNumberGCDList(lst1, lst2): # (* lst1 and lst2 must be absurd number prime factorization lists. *) # (* AbsurdNumberGCDList[lst1,lst2] returns the gcd of the absurd numbers represented by lst1 and lst2. *) if lst1 == []: return Mul(*[i[0]**Min(i[1],0) for i in lst2]) elif lst2 == []: return Mul(*[i[0]**Min(i[1],0) for i in lst1]) elif lst1[0][0] == lst2[0][0]: if lst1[0][1] <= lst2[0][1]: return lst1[0][0]**lst1[0][1]*AbsurdNumberGCDList(Rest(lst1), Rest(lst2)) return lst1[0][0]**lst2[0][1]*AbsurdNumberGCDList(Rest(lst1), Rest(lst2)) elif lst1[0][0] < lst2[0][0]: if lst1[0][1] < 0: return lst1[0][0]**lst1[0][1]*AbsurdNumberGCDList(Rest(lst1), lst2) return AbsurdNumberGCDList(Rest(lst1), lst2) elif lst2[0][1] < 0: return lst2[0][0]**lst2[0][1]*AbsurdNumberGCDList(lst1, Rest(lst2)) return AbsurdNumberGCDList(lst1, Rest(lst2)) def ExpandTrigExpand(u, F, v, m, n, x): w = Expand(TrigExpand(F.xreplace({x: n*x}))**m).xreplace({x: v}) if SumQ(w): t = 0 for i in w.args: t += u*i return t else: return u*w def ExpandTrigReduce(*args): if len(args) == 3: u = args[0] v = args[1] x = args[2] w = ExpandTrigReduce(v, x) if SumQ(w): t = 0 for i in w.args: t += u*i return t else: return u*w else: u = args[0] x = args[1] return ExpandTrigReduceAux(u, x) def ExpandTrigReduceAux(u, x): v = TrigReduce(u).expand() if SumQ(v): t = 0 for i in v.args: t += NormalizeTrig(i, x) return t return NormalizeTrig(v, x) def NormalizeTrig(v, x): a = Wild('a', exclude=[x]) n = Wild('n', exclude=[x, 0]) F = Wild('F') expr = a*F**n M = v.match(expr) if M and len(M[F].args) == 1 and PolynomialQ(M[F].args[0], x) and Exponent(M[F].args[0], x) > 0: u = M[F].args[0] return M[a]*M[F].xreplace({u: ExpandToSum(u, x)})**M[n] else: return v #================================= def TrigToExp(expr): ex = expr.rewrite(sin, sym_exp).rewrite(cos, sym_exp).rewrite(tan, sym_exp).rewrite(sec, sym_exp).rewrite(csc, sym_exp).rewrite(cot, sym_exp) return ex.replace(sym_exp, rubi_exp) def ExpandTrigToExp(u, *args): if len(args) == 1: x = args[0] return ExpandTrigToExp(1, u, x) else: v = args[0] x = args[1] w = TrigToExp(v) k = 0 if SumQ(w): for i in w.args: k += SimplifyIntegrand(u*i, x) w = k else: w = SimplifyIntegrand(u*w, x) return ExpandIntegrand(FreeFactors(w, x), NonfreeFactors(w, x),x) #====================================== def TrigReduce(i): """ TrigReduce(expr) rewrites products and powers of trigonometric functions in expr in terms of trigonometric functions with combined arguments. Examples ======== >>> from sympy import sin, cos >>> from sympy.integrals.rubi.utility_function import TrigReduce >>> from sympy.abc import x >>> TrigReduce(cos(x)**2) cos(2*x)/2 + 1/2 >>> TrigReduce(cos(x)**2*sin(x)) sin(x)/4 + sin(3*x)/4 >>> TrigReduce(cos(x)**2+sin(x)) sin(x) + cos(2*x)/2 + 1/2 """ if SumQ(i): t = 0 for k in i.args: t += TrigReduce(k) return t if ProductQ(i): if any(PowerQ(k) for k in i.args): if (i.rewrite((sin, sinh), sym_exp).rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, sin)).has(I, cosh, sinh): return i.rewrite((sin, sinh), sym_exp).rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, sin).simplify() else: return i.rewrite((sin, sinh), sym_exp).rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, sin) else: a = Wild('a') b = Wild('b') v = Wild('v') Match = i.match(v*sin(a)*cos(b)) if Match: a = Match[a] b = Match[b] v = Match[v] return i.subs(v*sin(a)*cos(b), v*S(1)/2*(sin(a + b) + sin(a - b))) Match = i.match(v*sin(a)*sin(b)) if Match: a = Match[a] b = Match[b] v = Match[v] return i.subs(v*sin(a)*sin(b), v*S(1)/2*cos(a - b) - cos(a + b)) Match = i.match(v*cos(a)*cos(b)) if Match: a = Match[a] b = Match[b] v = Match[v] return i.subs(v*cos(a)*cos(b), v*S(1)/2*cos(a + b) + cos(a - b)) Match = i.match(v*sinh(a)*cosh(b)) if Match: a = Match[a] b = Match[b] v = Match[v] return i.subs(v*sinh(a)*cosh(b), v*S(1)/2*(sinh(a + b) + sinh(a - b))) Match = i.match(v*sinh(a)*sinh(b)) if Match: a = Match[a] b = Match[b] v = Match[v] return i.subs(v*sinh(a)*sinh(b), v*S(1)/2*cosh(a - b) - cosh(a + b)) Match = i.match(v*cosh(a)*cosh(b)) if Match: a = Match[a] b = Match[b] v = Match[v] return i.subs(v*cosh(a)*cosh(b), v*S(1)/2*cosh(a + b) + cosh(a - b)) if PowerQ(i): if i.has(sin, sinh): if (i.rewrite((sin, sinh), sym_exp).expand().rewrite(sym_exp, sin)).has(I, cosh, sinh): return i.rewrite((sin, sinh), sym_exp).expand().rewrite(sym_exp, sin).simplify() else: return i.rewrite((sin, sinh), sym_exp).expand().rewrite(sym_exp, sin) if i.has(cos, cosh): if (i.rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, cos)).has(I, cosh, sinh): return i.rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, cos).simplify() else: return i.rewrite((cos, cosh), sym_exp).expand().rewrite(sym_exp, cos) return i def FunctionOfTrig(u, *args): # If u is a function of trig functions of v where v is a linear function of x, # FunctionOfTrig[u,x] returns v; else it returns False. if len(args) == 1: x = args[0] v = FunctionOfTrig(u, None, x) if v: return v else: return False else: v, x = args if AtomQ(u): if u == x: return False else: return v if TrigQ(u) and LinearQ(u.args[0], x): if v is None: return u.args[0] else: a = Coefficient(v, x, 0) b = Coefficient(v, x, 1) c = Coefficient(u.args[0], x, 0) d = Coefficient(u.args[0], x, 1) if ZeroQ(a*d - b*c) and RationalQ(b/d): return a/Numerator(b/d) + b*x/Numerator(b/d) else: return False if HyperbolicQ(u) and LinearQ(u.args[0], x): if v is None: return I*u.args[0] a = Coefficient(v, x, 0) b = Coefficient(v, x, 1) c = I*Coefficient(u.args[0], x, 0) d = I*Coefficient(u.args[0], x, 1) if ZeroQ(a*d - b*c) and RationalQ(b/d): return a/Numerator(b/d) + b*x/Numerator(b/d) else: return False if CalculusQ(u): return False else: w = v for i in u.args: w = FunctionOfTrig(i, w, x) if FalseQ(w): return False return w def AlgebraicTrigFunctionQ(u, x): # If u is algebraic function of trig functions, AlgebraicTrigFunctionQ(u,x) returns True; else it returns False. if AtomQ(u): return True elif TrigQ(u) and LinearQ(u.args[0], x): return True elif HyperbolicQ(u) and LinearQ(u.args[0], x): return True elif PowerQ(u): if FreeQ(u.exp, x): return AlgebraicTrigFunctionQ(u.base, x) elif ProductQ(u) or SumQ(u): for i in u.args: if not AlgebraicTrigFunctionQ(i, x): return False return True return False def FunctionOfHyperbolic(u, *x): # If u is a function of hyperbolic trig functions of v where v is linear in x, # FunctionOfHyperbolic(u,x) returns v; else it returns False. if len(x) == 1: x = x[0] v = FunctionOfHyperbolic(u, None, x) if v is None: return False else: return v else: v = x[0] x = x[1] if AtomQ(u): if u == x: return False return v if HyperbolicQ(u) and LinearQ(u.args[0], x): if v is None: return u.args[0] a = Coefficient(v, x, 0) b = Coefficient(v, x, 1) c = Coefficient(u.args[0], x, 0) d = Coefficient(u.args[0], x, 1) if ZeroQ(a*d - b*c) and RationalQ(b/d): return a/Numerator(b/d) + b*x/Numerator(b/d) else: return False if CalculusQ(u): return False w = v for i in u.args: if w == FunctionOfHyperbolic(i, w, x): return False return w def FunctionOfQ(v, u, x, PureFlag=False): # v is a function of x. If u is a function of v, FunctionOfQ(v, u, x) returns True; else it returns False. *) if FreeQ(u, x): return False elif AtomQ(v): return True elif ProductQ(v) and Not(EqQ(FreeFactors(v, x), 1)): return FunctionOfQ(NonfreeFactors(v, x), u, x, PureFlag) elif PureFlag: if SinQ(v) or CscQ(v): return PureFunctionOfSinQ(u, v.args[0], x) elif CosQ(v) or SecQ(v): return PureFunctionOfCosQ(u, v.args[0], x) elif TanQ(v): return PureFunctionOfTanQ(u, v.args[0], x) elif CotQ(v): return PureFunctionOfCotQ(u, v.args[0], x) elif SinhQ(v) or CschQ(v): return PureFunctionOfSinhQ(u, v.args[0], x) elif CoshQ(v) or SechQ(v): return PureFunctionOfCoshQ(u, v.args[0], x) elif TanhQ(v): return PureFunctionOfTanhQ(u, v.args[0], x) elif CothQ(v): return PureFunctionOfCothQ(u, v.args[0], x) else: return FunctionOfExpnQ(u, v, x) != False elif SinQ(v) or CscQ(v): return FunctionOfSinQ(u, v.args[0], x) elif CosQ(v) or SecQ(v): return FunctionOfCosQ(u, v.args[0], x) elif TanQ(v) or CotQ(v): FunctionOfTanQ(u, v.args[0], x) elif SinhQ(v) or CschQ(v): return FunctionOfSinhQ(u, v.args[0], x) elif CoshQ(v) or SechQ(v): return FunctionOfCoshQ(u, v.args[0], x) elif TanhQ(v) or CothQ(v): return FunctionOfTanhQ(u, v.args[0], x) return FunctionOfExpnQ(u, v, x) != False def FunctionOfExpnQ(u, v, x): if u == v: return 1 if AtomQ(u): if u == x: return False else: return 0 if CalculusQ(u): return False if PowerQ(u): if FreeQ(u.exp, x): if ZeroQ(u.base - v): if IntegerQ(u.exp): return u.exp else: return 1 if PowerQ(v): if FreeQ(v.exp, x) and ZeroQ(u.base-v.base): if RationalQ(v.exp): if RationalQ(u.exp) and IntegerQ(u.exp/v.exp) and (v.exp>0 or u.exp<0): return u.exp/v.exp else: return False if IntegerQ(Simplify(u.exp/v.exp)): return Simplify(u.exp/v.exp) else: return False return FunctionOfExpnQ(u.base, v, x) if ProductQ(u) and Not(EqQ(FreeFactors(u, x), 1)): return FunctionOfExpnQ(NonfreeFactors(u, x), v, x) if ProductQ(u) and ProductQ(v): deg1 = FunctionOfExpnQ(First(u), First(v), x) if deg1==False: return False deg2 = FunctionOfExpnQ(Rest(u), Rest(v), x); if deg1==deg2 and FreeQ(Simplify(u/v^deg1), x): return deg1 else: return False lst = [] for i in u.args: if FunctionOfExpnQ(i, v, x) is False: return False lst.append(FunctionOfExpnQ(i, v, x)) return Apply(GCD, lst) def PureFunctionOfSinQ(u, v, x): # If u is a pure function of Sin(v) and/or Csc(v), PureFunctionOfSinQ(u, v, x) returns True; else it returns False. if AtomQ(u): return u!=x if CalculusQ(u): return False if TrigQ(u) and ZeroQ(u.args[0]-v): return SinQ(u) or CscQ(u) for i in u.args: if Not(PureFunctionOfSinQ(i, v, x)): return False return True def PureFunctionOfCosQ(u, v, x): # If u is a pure function of Cos(v) and/or Sec(v), PureFunctionOfCosQ(u, v, x) returns True; else it returns False. if AtomQ(u): return u!=x if CalculusQ(u): return False if TrigQ(u) and ZeroQ(u.args[0]-v): return CosQ(u) or SecQ(u) for i in u.args: if Not(PureFunctionOfCosQ(i, v, x)): return False return True def PureFunctionOfTanQ(u, v, x): # If u is a pure function of Tan(v) and/or Cot(v), PureFunctionOfTanQ(u, v, x) returns True; else it returns False. if AtomQ(u): return u!=x if CalculusQ(u): return False if TrigQ(u) and ZeroQ(u.args[0]-v): return TanQ(u) or CotQ(u) for i in u.args: if Not(PureFunctionOfTanQ(i, v, x)): return False return True def PureFunctionOfCotQ(u, v, x): # If u is a pure function of Cot(v), PureFunctionOfCotQ(u, v, x) returns True; else it returns False. if AtomQ(u): return u!=x if CalculusQ(u): return False if TrigQ(u) and ZeroQ(u.args[0]-v): return CotQ(u) for i in u.args: if Not(PureFunctionOfCotQ(i, v, x)): return False return True def FunctionOfCosQ(u, v, x): # If u is a function of Cos[v], FunctionOfCosQ[u,v,x] returns True; else it returns False. if AtomQ(u): return u != x elif CalculusQ(u): return False elif TrigQ(u) and IntegerQuotientQ(u.args[0], v): # Basis: If m integer, Cos[m*v]^n is a function of Cos[v]. *) return CosQ(u) or SecQ(u) elif IntegerPowerQ(u): if TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v): if EvenQ(u.exp): # Basis: If m integer and n even, Trig[m*v]^n is a function of Cos[v]. *) return True return FunctionOfCosQ(u.base, v, x) elif ProductQ(u): lst = FindTrigFactor(sin, csc, u, v, False) if ListQ(lst): # (* Basis: If m integer and n odd, Sin[m*v]^n == Sin[v]*u where u is a function of Cos[v]. *) return FunctionOfCosQ(Sin(v)*lst[1], v, x) lst = FindTrigFactor(tan, cot, u, v, True) if ListQ(lst): # (* Basis: If m integer and n odd, Tan[m*v]^n == Sin[v]*u where u is a function of Cos[v]. *) return FunctionOfCosQ(Sin(v)*lst[1], v, x) return all(FunctionOfCosQ(i, v, x) for i in u.args) return all(FunctionOfCosQ(i, v, x) for i in u.args) def FunctionOfSinQ(u, v, x): # If u is a function of Sin[v], FunctionOfSinQ[u,v,x] returns True; else it returns False. if AtomQ(u): return u != x elif CalculusQ(u): return False elif TrigQ(u) and IntegerQuotientQ(u.args[0], v): if OddQuotientQ(u.args[0], v): # Basis: If m odd, Sin[m*v]^n is a function of Sin[v]. return SinQ(u) or CscQ(u) # Basis: If m even, Cos[m*v]^n is a function of Sin[v]. return CosQ(u) or SecQ(u) elif IntegerPowerQ(u): if TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v): if EvenQ(u.exp): # Basis: If m integer and n even, Hyper[m*v]^n is a function of Sin[v]. return True return FunctionOfSinQ(u.base, v, x) elif ProductQ(u): if CosQ(u.args[0]) and SinQ(u.args[1]) and ZeroQ(u.args[0].args[0] - v/2) and ZeroQ(u.args[1].args[0] - v/2): return FunctionOfSinQ(Drop(u, 2), v, x) lst = FindTrigFactor(sin, csch, u, v, False) if ListQ(lst) and EvenQuotientQ(lst[0], v): # Basis: If m even and n odd, Sin[m*v]^n == Cos[v]*u where u is a function of Sin[v]. return FunctionOfSinQ(Cos(v)*lst[1], v, x) lst = FindTrigFactor(cos, sec, u, v, False) if ListQ(lst) and OddQuotientQ(lst[0], v): # Basis: If m odd and n odd, Cos[m*v]^n == Cos[v]*u where u is a function of Sin[v]. return FunctionOfSinQ(Cos(v)*lst[1], v, x) lst = FindTrigFactor(tan, cot, u, v, True) if ListQ(lst): # Basis: If m integer and n odd, Tan[m*v]^n == Cos[v]*u where u is a function of Sin[v]. return FunctionOfSinQ(Cos(v)*lst[1], v, x) return all(FunctionOfSinQ(i, v, x) for i in u.args) return all(FunctionOfSinQ(i, v, x) for i in u.args) def OddTrigPowerQ(u, v, x): if SinQ(u) or CosQ(u) or SecQ(u) or CscQ(u): return OddQuotientQ(u.args[0], v) if PowerQ(u): return OddQ(u.exp) and OddTrigPowerQ(u.base, v, x) if ProductQ(u): if not FreeFactors(u, x) == 1: return OddTrigPowerQ(NonfreeFactors(u, x), v, x) lst = [] for i in u.args: if Not(FunctionOfTanQ(i, v, x)): lst.append(i) if lst == []: return True return Length(lst)==1 and OddTrigPowerQ(lst[0], v, x) if SumQ(u): return all(OddTrigPowerQ(i, v, x) for i in u.args) return False def FunctionOfTanQ(u, v, x): # If u is a function of the form f[Tan[v],Cot[v]] where f is independent of x, # FunctionOfTanQ[u,v,x] returns True; else it returns False. if AtomQ(u): return u != x elif CalculusQ(u): return False elif TrigQ(u) and IntegerQuotientQ(u.args[0], v): return TanQ(u) or CotQ(u) or EvenQuotientQ(u.args[0], v) elif PowerQ(u): if EvenQ(u.exp) and TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v): return True elif EvenQ(u.exp) and SumQ(u.base): return FunctionOfTanQ(Expand(u.base**2, v, x)) if ProductQ(u): lst = [] for i in u.args: if Not(FunctionOfTanQ(i, v, x)): lst.append(i) if lst == []: return True return Length(lst)==2 and OddTrigPowerQ(lst[0], v, x) and OddTrigPowerQ(lst[1], v, x) return all(FunctionOfTanQ(i, v, x) for i in u.args) def FunctionOfTanWeight(u, v, x): # (* u is a function of the form f[Tan[v],Cot[v]] where f is independent of x. # FunctionOfTanWeight[u,v,x] returns a nonnegative number if u is best considered a function # of Tan[v]; else it returns a negative number. *) if AtomQ(u): return S(0) elif CalculusQ(u): return S(0) elif TrigQ(u) and IntegerQuotientQ(u.args[0], v): if TanQ(u) and ZeroQ(u.args[0] - v): return S(1) elif CotQ(u) and ZeroQ(u.args[0] - v): return S(-1) return S(0) elif PowerQ(u): if EvenQ(u.exp) and TrigQ(u.base) and IntegerQuotientQ(u.base.args[0], v): if TanQ(u.base) or CosQ(u.base) or SecQ(u.base): return S(1) return S(-1) if ProductQ(u): if all(FunctionOfTanQ(i, v, x) for i in u.args): return Add(*[FunctionOfTanWeight(i, v, x) for i in u.args]) return S(0) return Add(*[FunctionOfTanWeight(i, v, x) for i in u.args]) def FunctionOfTrigQ(u, v, x): # If u (x) is equivalent to a function of the form f (Sin[v],Cos[v],Tan[v],Cot[v],Sec[v],Csc[v]) where f is independent of x, FunctionOfTrigQ[u,v,x] returns True; else it returns False. if AtomQ(u): return u != x elif CalculusQ(u): return False elif TrigQ(u) and IntegerQuotientQ(u.args[0], v): return True return all(FunctionOfTrigQ(i, v, x) for i in u.args) def FunctionOfDensePolynomialsQ(u, x): # If all occurrences of x in u (x) are in dense polynomials, FunctionOfDensePolynomialsQ[u,x] returns True; else it returns False. if FreeQ(u, x): return True if PolynomialQ(u, x): return Length(ExponentList(u, x)) > 1 return all(FunctionOfDensePolynomialsQ(i, x) for i in u.args) def FunctionOfLog(u, *args): # If u (x) is equivalent to an expression of the form f (Log[a*x^n]), FunctionOfLog[u,x] returns # the list {f (x),a*x^n,n}; else it returns False. if len(args) == 1: x = args[0] lst = FunctionOfLog(u, False, False, x) if AtomQ(lst) or FalseQ(lst[1]) or not isinstance(x, Symbol): return False else: return lst else: v = args[0] n = args[1] x = args[2] if AtomQ(u): if u==x: return False else: return [u, v, n] if CalculusQ(u): return False lst = BinomialParts(u.args[0], x) if LogQ(u) and ListQ(lst) and ZeroQ(lst[0]): if FalseQ(v) or u.args[0] == v: return [x, u.args[0], lst[2]] else: return False lst = [0, v, n] l = [] for i in u.args: lst = FunctionOfLog(i, lst[1], lst[2], x) if AtomQ(lst): return False else: l.append(lst[0]) return [u.func(*l), lst[1], lst[2]] def PowerVariableExpn(u, m, x): # If m is an integer, u is an expression of the form f((c*x)**n) and g=GCD(m,n)>1, # PowerVariableExpn(u,m,x) returns the list {x**(m/g)*f((c*x)**(n/g)),g,c}; else it returns False. if IntegerQ(m): lst = PowerVariableDegree(u, m, 1, x) if not lst: return False else: return [x**(m/lst[0])*PowerVariableSubst(u, lst[0], x), lst[0], lst[1]] else: return False def PowerVariableDegree(u, m, c, x): if FreeQ(u, x): return [m, c] if AtomQ(u) or CalculusQ(u): return False if PowerQ(u): if FreeQ(u.base/x, x): if ZeroQ(m) or m == u.exp and c == u.base/x: return [u.exp, u.base/x] if IntegerQ(u.exp) and IntegerQ(m) and GCD(m, u.exp)>1 and c==u.base/x: return [GCD(m, u.exp), c] else: return False lst = [m, c] for i in u.args: if PowerVariableDegree(i, lst[0], lst[1], x) == False: return False lst1 = PowerVariableDegree(i, lst[0], lst[1], x) if not lst1: return False else: return lst1 def PowerVariableSubst(u, m, x): if FreeQ(u, x) or AtomQ(u) or CalculusQ(u): return u if PowerQ(u): if FreeQ(u.base/x, x): return x**(u.exp/m) if ProductQ(u): l = 1 for i in u.args: l *= (PowerVariableSubst(i, m, x)) return l if SumQ(u): l = 0 for i in u.args: l += (PowerVariableSubst(i, m, x)) return l return u def EulerIntegrandQ(expr, x): a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) n = Wild('n', exclude=[x, 0]) m = Wild('m', exclude=[x, 0]) p = Wild('p', exclude=[x, 0]) u = Wild('u') v = Wild('v') # Pattern 1 M = expr.match((a*x + b*u**n)**p) if M: if len(M) == 5 and FreeQ([M[a], M[b]], x) and IntegerQ(M[n] + 1/2) and QuadraticQ(M[u], x) and Not(RationalQ(M[p])) or NegativeIntegerQ(M[p]) and Not(BinomialQ(M[u], x)): return True # Pattern 2 M = expr.match(v**m*(a*x + b*u**n)**p) if M: if len(M) == 6 and FreeQ([M[a], M[b]], x) and ZeroQ(M[u] - M[v]) and IntegersQ(2*M[m], M[n] + 1/2) and QuadraticQ(M[u], x) and Not(RationalQ(M[p])) or NegativeIntegerQ(M[p]) and Not(BinomialQ(M[u], x)): return True # Pattern 3 M = expr.match(u**n*v**p) if M: if len(M) == 3 and NegativeIntegerQ(M[p]) and IntegerQ(M[n] + 1/2) and QuadraticQ(M[u], x) and QuadraticQ(M[v], x) and Not(BinomialQ(M[v], x)): return True else: return False def FunctionOfSquareRootOfQuadratic(u, *args): if len(args) == 1: x = args[0] pattern = Pattern(UtilityOperator(x_**WC('m', 1)*(a_ + x**WC('n', 1)*WC('b', 1))**p_, x), CustomConstraint(lambda a, b, m, n, p, x: FreeQ([a, b, m, n, p], x))) M = is_match(UtilityOperator(u, args[0]), pattern) if M: return False tmp = FunctionOfSquareRootOfQuadratic(u, False, x) if AtomQ(tmp) or FalseQ(tmp[0]): return False tmp = tmp[0] a = Coefficient(tmp, x, 0) b = Coefficient(tmp, x, 1) c = Coefficient(tmp, x, 2) if ZeroQ(a) and ZeroQ(b) or ZeroQ(b**2-4*a*c): return False if PosQ(c): sqrt = Rt(c, S(2)); q = a*sqrt + b*x + sqrt*x**2 r = b + 2*sqrt*x return [Simplify(SquareRootOfQuadraticSubst(u, q/r, (-a+x**2)/r, x)*q/r**2), Simplify(sqrt*x + Sqrt(tmp)), 2] if PosQ(a): sqrt = Rt(a, S(2)) q = c*sqrt - b*x + sqrt*x**2 r = c - x**2 return [Simplify(SquareRootOfQuadraticSubst(u, q/r, (-b+2*sqrt*x)/r, x)*q/r**2), Simplify((-sqrt+Sqrt(tmp))/x), 1] sqrt = Rt(b**2 - 4*a*c, S(2)) r = c - x**2 return[Simplify(-sqrt*SquareRootOfQuadraticSubst(u, -sqrt*x/r, -(b*c+c*sqrt+(-b+sqrt)*x**2)/(2*c*r), x)*x/r**2), FullSimplify(2*c*Sqrt(tmp)/(b-sqrt+2*c*x)), 3] else: v = args[0] x = args[1] if AtomQ(u) or FreeQ(u, x): return [v] if PowerQ(u): if FreeQ(u.exp, x): if FractionQ(u.exp) and Denominator(u.exp) == 2 and PolynomialQ(u.base, x) and Exponent(u.base, x) == 2: if FalseQ(v) or u.base == v: return [u.base] else: return False return FunctionOfSquareRootOfQuadratic(u.base, v, x) if ProductQ(u) or SumQ(u): lst = [v] lst1 = [] for i in u.args: if FunctionOfSquareRootOfQuadratic(i, lst[0], x) == False: return False lst1 = FunctionOfSquareRootOfQuadratic(i, lst[0], x) return lst1 else: return False def SquareRootOfQuadraticSubst(u, vv, xx, x): # SquareRootOfQuadraticSubst(u, vv, xx, x) returns u with fractional powers replaced by vv raised to the power and x replaced by xx. if AtomQ(u) or FreeQ(u, x): if u==x: return xx return u if PowerQ(u): if FreeQ(u.exp, x): if FractionQ(u.exp) and Denominator(u.exp)==2 and PolynomialQ(u.base, x) and Exponent(u.base, x)==2: return vv**Numerator(u.exp) return SquareRootOfQuadraticSubst(u.base, vv, xx, x)**u.exp elif SumQ(u): t = 0 for i in u.args: t += SquareRootOfQuadraticSubst(i, vv, xx, x) return t elif ProductQ(u): t = 1 for i in u.args: t *= SquareRootOfQuadraticSubst(i, vv, xx, x) return t def Divides(y, u, x): # If u divided by y is free of x, Divides[y,u,x] returns the quotient; else it returns False. v = Simplify(u/y) if FreeQ(v, x): return v else: return False def DerivativeDivides(y, u, x): """ If y not equal to x, y is easy to differentiate wrt x, and u divided by the derivative of y is free of x, DerivativeDivides[y,u,x] returns the quotient; else it returns False. """ from matchpy import is_match pattern0 = Pattern(Mul(a , b_), CustomConstraint(lambda a, b : FreeQ(a, b))) def f1(y, u, x): if PolynomialQ(y, x): return PolynomialQ(u, x) and Exponent(u, x) == Exponent(y, x) - 1 else: return EasyDQ(y, x) if is_match(y, pattern0): return False elif f1(y, u, x): v = D(y ,x) if EqQ(v, 0): return False else: v = Simplify(u/v) if FreeQ(v, x): return v else: return False else: return False def EasyDQ(expr, x): # If u is easy to differentiate wrt x, EasyDQ(u, x) returns True; else it returns False *) u = Wild('u',exclude=[1]) m = Wild('m',exclude=[x, 0]) M = expr.match(u*x**m) if M: return EasyDQ(M[u], x) if AtomQ(expr) or FreeQ(expr, x) or Length(expr)==0: return True elif CalculusQ(expr): return False elif Length(expr)==1: return EasyDQ(expr.args[0], x) elif BinomialQ(expr, x) or ProductOfLinearPowersQ(expr, x): return True elif RationalFunctionQ(expr, x) and RationalFunctionExponents(expr, x)==[1, 1]: return True elif ProductQ(expr): if FreeQ(First(expr), x): return EasyDQ(Rest(expr), x) elif FreeQ(Rest(expr), x): return EasyDQ(First(expr), x) else: return False elif SumQ(expr): return EasyDQ(First(expr), x) and EasyDQ(Rest(expr), x) elif Length(expr)==2: if FreeQ(expr.args[0], x): EasyDQ(expr.args[1], x) elif FreeQ(expr.args[1], x): return EasyDQ(expr.args[0], x) else: return False return False def ProductOfLinearPowersQ(u, x): # ProductOfLinearPowersQ(u, x) returns True iff u is a product of factors of the form v^n where v is linear in x v = Wild('v') n = Wild('n', exclude=[x]) M = u.match(v**n) return FreeQ(u, x) or M and LinearQ(M[v], x) or ProductQ(u) and ProductOfLinearPowersQ(First(u), x) and ProductOfLinearPowersQ(Rest(u), x) def Rt(u, n): return RtAux(TogetherSimplify(u), n) def NthRoot(u, n): return nsimplify(u**(S(1)/n)) def AtomBaseQ(u): # If u is an atom or an atom raised to an odd degree, AtomBaseQ(u) returns True; else it returns False return AtomQ(u) or PowerQ(u) and OddQ(u.args[1]) and AtomBaseQ(u.args[0]) def SumBaseQ(u): # If u is a sum or a sum raised to an odd degree, SumBaseQ(u) returns True; else it returns False return SumQ(u) or PowerQ(u) and OddQ(u.args[1]) and SumBaseQ(u.args[0]) def NegSumBaseQ(u): # If u is a sum or a sum raised to an odd degree whose lead term has a negative form, NegSumBaseQ(u) returns True; else it returns False return SumQ(u) and NegQ(First(u)) or PowerQ(u) and OddQ(u.args[1]) and NegSumBaseQ(u.args[0]) def AllNegTermQ(u): # If all terms of u have a negative form, AllNegTermQ(u) returns True; else it returns False if PowerQ(u): if OddQ(u.exp): return AllNegTermQ(u.base) if SumQ(u): return NegQ(First(u)) and AllNegTermQ(Rest(u)) return NegQ(u) def SomeNegTermQ(u): # If some term of u has a negative form, SomeNegTermQ(u) returns True; else it returns False if PowerQ(u): if OddQ(u.exp): return SomeNegTermQ(u.base) if SumQ(u): return NegQ(First(u)) or SomeNegTermQ(Rest(u)) return NegQ(u) def TrigSquareQ(u): # If u is an expression of the form Sin(z)^2 or Cos(z)^2, TrigSquareQ(u) returns True, else it returns False return PowerQ(u) and EqQ(u.args[1], 2) and MemberQ([sin, cos], Head(u.args[0])) def RtAux(u, n): if PowerQ(u): return u.base**(u.exp/n) if ComplexNumberQ(u): a = Re(u) b = Im(u) if Not(IntegerQ(a) and IntegerQ(b)) and IntegerQ(a/(a**2 + b**2)) and IntegerQ(b/(a**2 + b**2)): # Basis: a+b*I==1/(a/(a^2+b^2)-b/(a^2+b^2)*I) return S(1)/RtAux(a/(a**2 + b**2) - b/(a**2 + b**2)*I, n) else: return NthRoot(u, n) if ProductQ(u): lst = SplitProduct(PositiveQ, u) if ListQ(lst): return RtAux(lst[0], n)*RtAux(lst[1], n) lst = SplitProduct(NegativeQ, u) if ListQ(lst): if EqQ(lst[0], -1): v = lst[1] if PowerQ(v): if NegativeQ(v.exp): return 1/RtAux(-v.base**(-v.exp), n) if ProductQ(v): if ListQ(SplitProduct(SumBaseQ, v)): lst = SplitProduct(AllNegTermQ, v) if ListQ(lst): return RtAux(-lst[0], n)*RtAux(lst[1], n) lst = SplitProduct(NegSumBaseQ, v) if ListQ(lst): return RtAux(-lst[0], n)*RtAux(lst[1], n) lst = SplitProduct(SomeNegTermQ, v) if ListQ(lst): return RtAux(-lst[0], n)*RtAux(lst[1], n) lst = SplitProduct(SumBaseQ, v) return RtAux(-lst[0], n)*RtAux(lst[1], n) lst = SplitProduct(AtomBaseQ, v) if ListQ(lst): return RtAux(-lst[0], n)*RtAux(lst[1], n) else: return RtAux(-First(v), n)*RtAux(Rest(v), n) if OddQ(n): return -RtAux(v, n) else: return NthRoot(u, n) else: return RtAux(-lst[0], n)*RtAux(-lst[1], n) lst = SplitProduct(AllNegTermQ, u) if ListQ(lst) and ListQ(SplitProduct(SumBaseQ, lst[1])): return RtAux(-lst[0], n)*RtAux(-lst[1], n) lst = SplitProduct(NegSumBaseQ, u) if ListQ(lst) and ListQ(SplitProduct(NegSumBaseQ, lst[1])): return RtAux(-lst[0], n)*RtAux(-lst[1], n) return u.func(*[RtAux(i, n) for i in u.args]) v = TrigSquare(u) if Not(AtomQ(v)): return RtAux(v, n) if OddQ(n) and NegativeQ(u): return -RtAux(-u, n) if OddQ(n) and NegQ(u) and PosQ(-u): return -RtAux(-u, n) else: return NthRoot(u, n) def TrigSquare(u): # If u is an expression of the form a-a*Sin(z)^2 or a-a*Cos(z)^2, TrigSquare(u) returns Cos(z)^2 or Sin(z)^2 respectively, # else it returns False. if SumQ(u): for i in u.args: v = SplitProduct(TrigSquareQ, i) if v == False or SplitSum(v, u) == False: return False lst = SplitSum(SplitProduct(TrigSquareQ, i)) if lst and ZeroQ(lst[1][2] + lst[1]): if Head(lst[0][0].args[0]) == sin: return lst[1]*cos(lst[1][1][1][1])**2 return lst[1]*sin(lst[1][1][1][1])**2 else: return False else: return False def IntSum(u, x): # If u is free of x or of the form c*(a+b*x)^m, IntSum[u,x] returns the antiderivative of u wrt x; # else it returns d*Int[v,x] where d*v=u and d is free of x. return Add(*[Integral(i, x) for i in u.args]) def IntTerm(expr, x): # If u is of the form c*(a+b*x)**m, IntTerm(u,x) returns the antiderivative of u wrt x; # else it returns d*Int(v,x) where d*v=u and d is free of x. c = Wild('c', exclude=[x]) m = Wild('m', exclude=[x, 0]) v = Wild('v') M = expr.match(c/v) if M and len(M) == 2 and FreeQ(M[c], x) and LinearQ(M[v], x): return Simp(M[c]*Log(RemoveContent(M[v], x))/Coefficient(M[v], x, 1), x) M = expr.match(c*v**m) if M and len(M) == 3 and NonzeroQ(M[m] + 1) and LinearQ(M[v], x): return Simp(M[c]*M[v]**(M[m] + 1)/(Coefficient(M[v], x, 1)*(M[m] + 1)), x) if SumQ(expr): t = 0 for i in expr.args: t += IntTerm(i, x) return t else: u = expr return Dist(FreeFactors(u,x), Integral(NonfreeFactors(u, x), x), x) def Map2(f, lst1, lst2): result = [] for i in range(0, len(lst1)): result.append(f(lst1[i], lst2[i])) return result def ConstantFactor(u, x): # (* ConstantFactor[u,x] returns a 2-element list of the factors of u[x] free of x and the # factors not free of u[x]. Common constant factors of the terms of sums are also collected. *) if FreeQ(u, x): return [u, S(1)] elif AtomQ(u): return [S(1), u] elif PowerQ(u): if FreeQ(u.exp, x): lst = ConstantFactor(u.base, x) if IntegerQ(u.exp): return [lst[0]**u.exp, lst[1]**u.exp] tmp = PositiveFactors(lst[0]) if tmp == 1: return [S(1), u] return [tmp**u.exp, (NonpositiveFactors(lst[0])*lst[1])**u.exp] elif ProductQ(u): lst = [ConstantFactor(i, x) for i in u.args] return [Mul(*[First(i) for i in lst]), Mul(*[i[1] for i in lst])] elif SumQ(u): lst1 = [ConstantFactor(i, x) for i in u.args] if SameQ(*[i[1] for i in lst1]): return [Add(*[i[0] for i in lst]), lst1[0][1]] lst2 = CommonFactors([First(i) for i in lst1]) return [First(lst2), Add(*Map2(Mul, Rest(lst2), [i[1] for i in lst1]))] return [S(1), u] def SameQ(*args): for i in range(0, len(args) - 1): if args[i] != args[i+1]: return False return True def ReplacePart(lst, a, b): lst[b] = a return lst def CommonFactors(lst): # (* If lst is a list of n terms, CommonFactors[lst] returns a n+1-element list whose first # element is the product of the factors common to all terms of lst, and whose remaining # elements are quotients of each term divided by the common factor. *) lst1 = [NonabsurdNumberFactors(i) for i in lst] lst2 = [AbsurdNumberFactors(i) for i in lst] num = AbsurdNumberGCD(*lst2) common = num lst2 = [i/num for i in lst2] while (True): lst3 = [LeadFactor(i) for i in lst1] if SameQ(*lst3): common = common*lst3[0] lst1 = [RemainingFactors(i) for i in lst1] elif (all((LogQ(i) and IntegerQ(First(i)) and First(i) > 0) for i in lst3) and all(RationalQ(i) for i in [FullSimplify(j/First(lst3)) for j in lst3])): lst4 = [FullSimplify(j/First(lst3)) for j in lst3] num = GCD(*lst4) common = common*Log((First(lst3)[0])**num) lst2 = [lst2[i]*lst4[i]/num for i in range(0, len(lst2))] lst1 = [RemainingFactors(i) for i in lst1] lst4 = [LeadDegree(i) for i in lst1] if SameQ(*[LeadBase(i) for i in lst1]) and RationalQ(*lst4): num = Smallest(lst4) base = LeadBase(lst1[0]) if num != 0: common = common*base**num lst2 = [lst2[i]*base**(lst4[i] - num) for i in range(0, len(lst2))] lst1 = [RemainingFactors(i) for i in lst1] elif (Length(lst1) == 2 and ZeroQ(LeadBase(lst1[0]) + LeadBase(lst1[1])) and NonzeroQ(lst1[0] - 1) and IntegerQ(lst4[0]) and FractionQ(lst4[1])): num = Min(lst4) base = LeadBase(lst1[1]) if num != 0: common = common*base**num lst2 = [lst2[0]*(-1)**lst4[0], lst2[1]] lst2 = [lst2[i]*base**(lst4[i] - num) for i in range(0, len(lst2))] lst1 = [RemainingFactors(i) for i in lst1] elif (Length(lst1) == 2 and ZeroQ(lst1[0] + LeadBase(lst1[1])) and NonzeroQ(lst1[1] - 1) and IntegerQ(lst1[1]) and FractionQ(lst4[0])): num = Min(lst4) base = LeadBase(lst1[0]) if num != 0: common = common*base**num lst2 = [lst2[0], lst2[1]*(-1)**lst4[1]] lst2 = [lst2[i]*base**(lst4[i] - num) for i in range(0, len(lst2))] lst1 = [RemainingFactors(i) for i in lst1] else: num = MostMainFactorPosition(lst3) lst2 = ReplacePart(lst2, lst3[num]*lst2[num], num) lst1 = ReplacePart(lst1, RemainingFactors(lst1[num]), num) if all(i==1 for i in lst1): return Prepend(lst2, common) def MostMainFactorPosition(lst): factor = S(1) num = 0 for i in range(0, Length(lst)): if FactorOrder(lst[i], factor) > 0: factor = lst[i] num = i return num SbaseS, SexponS = None, None SexponFlagS = False def FunctionOfExponentialQ(u, x): # (* FunctionOfExponentialQ[u,x] returns True iff u is a function of F^v where F is a constant and v is linear in x, *) # (* and such an exponential explicitly occurs in u (i.e. not just implicitly in hyperbolic functions). *) global SbaseS, SexponS, SexponFlagS SbaseS, SexponS = None, None SexponFlagS = False res = FunctionOfExponentialTest(u, x) return res and SexponFlagS def FunctionOfExponential(u, x): global SbaseS, SexponS, SexponFlagS # (* u is a function of F^v where v is linear in x. FunctionOfExponential[u,x] returns F^v. *) SbaseS, SexponS = None, None SexponFlagS = False FunctionOfExponentialTest(u, x) return SbaseS**SexponS def FunctionOfExponentialFunction(u, x): global SbaseS, SexponS, SexponFlagS # (* u is a function of F^v where v is linear in x. FunctionOfExponentialFunction[u,x] returns u with F^v replaced by x. *) SbaseS, SexponS = None, None SexponFlagS = False FunctionOfExponentialTest(u, x) return SimplifyIntegrand(FunctionOfExponentialFunctionAux(u, x), x) def FunctionOfExponentialFunctionAux(u, x): # (* u is a function of F^v where v is linear in x, and the fluid variables $base$=F and $expon$=v. *) # (* FunctionOfExponentialFunctionAux[u,x] returns u with F^v replaced by x. *) global SbaseS, SexponS, SexponFlagS if AtomQ(u): return u elif PowerQ(u): if FreeQ(u.base, x) and LinearQ(u.exp, x): if ZeroQ(Coefficient(SexponS, x, 0)): return u.base**Coefficient(u.exp, x, 0)*x**FullSimplify(Log(u.base)*Coefficient(u.exp, x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1))) return x**FullSimplify(Log(u.base)*Coefficient(u.exp, x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1))) elif HyperbolicQ(u) and LinearQ(u.args[0], x): tmp = x**FullSimplify(Coefficient(u.args[0], x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1))) if SinhQ(u): return tmp/2 - 1/(2*tmp) elif CoshQ(u): return tmp/2 + 1/(2*tmp) elif TanhQ(u): return (tmp - 1/tmp)/(tmp + 1/tmp) elif CothQ(u): return (tmp + 1/tmp)/(tmp - 1/tmp) elif SechQ(u): return 2/(tmp + 1/tmp) return 2/(tmp - 1/tmp) if PowerQ(u): if FreeQ(u.base, x) and SumQ(u.exp): return FunctionOfExponentialFunctionAux(u.base**First(u.exp), x)*FunctionOfExponentialFunctionAux(u.base**Rest(u.exp), x) return u.func(*[FunctionOfExponentialFunctionAux(i, x) for i in u.args]) def FunctionOfExponentialTest(u, x): # (* FunctionOfExponentialTest[u,x] returns True iff u is a function of F^v where F is a constant and v is linear in x. *) # (* Before it is called, the fluid variables $base$ and $expon$ should be set to Null and $exponFlag$ to False. *) # (* If u is a function of F^v, $base$ and $expon$ are set to F and v, respectively. *) # (* If an explicit exponential occurs in u, $exponFlag$ is set to True. *) global SbaseS, SexponS, SexponFlagS if FreeQ(u, x): return True elif u == x or CalculusQ(u): return False elif PowerQ(u): if FreeQ(u.base, x) and LinearQ(u.exp, x): SexponFlagS = True return FunctionOfExponentialTestAux(u.base, u.exp, x) elif HyperbolicQ(u) and LinearQ(u.args[0], x): return FunctionOfExponentialTestAux(E, u.args[0], x) if PowerQ(u): if FreeQ(u.base, x) and SumQ(u.exp): return FunctionOfExponentialTest(u.base**First(u.exp), x) and FunctionOfExponentialTest(u.base**Rest(u.exp), x) return all(FunctionOfExponentialTest(i, x) for i in u.args) def FunctionOfExponentialTestAux(base, expon, x): global SbaseS, SexponS, SexponFlagS if SbaseS is None: SbaseS = base SexponS = expon return True tmp = FullSimplify(Log(base)*Coefficient(expon, x, 1)/(Log(SbaseS)*Coefficient(SexponS, x, 1))) if Not(RationalQ(tmp)): return False elif ZeroQ(Coefficient(SexponS, x, 0)) or NonzeroQ(tmp - FullSimplify(Log(base)*Coefficient(expon, x, 0)/(Log(SbaseS)*Coefficient(SexponS, x, 0)))): if PositiveIntegerQ(base, SbaseS) and base < SbaseS: SbaseS = base SexponS = expon tmp = 1/tmp SexponS = Coefficient(SexponS, x, 1)*x/Denominator(tmp) if tmp < 0 and NegQ(Coefficient(SexponS, x, 1)): SexponS = -SexponS return True SexponS = SexponS/Denominator(tmp) if tmp < 0 and NegQ(Coefficient(SexponS, x, 1)): SexponS = -SexponS return True def stdev(lst): """Calculates the standard deviation for a list of numbers.""" num_items = len(lst) mean = sum(lst) / num_items differences = [x - mean for x in lst] sq_differences = [d ** 2 for d in differences] ssd = sum(sq_differences) variance = ssd / num_items sd = sqrt(variance) return sd def rubi_test(expr, x, optimal_output, expand=False, _hyper_check=False, _diff=False, _numerical=False): #Returns True if (expr - optimal_output) is equal to 0 or a constant #expr: integrated expression #x: integration variable #expand=True equates `expr` with `optimal_output` in expanded form #_hyper_check=True evaluates numerically #_diff=True differentiates the expressions before equating #_numerical=True equates the expressions at random `x`. Normally used for large expressions. from sympy import nsimplify if not expr.has(csc, sec, cot, csch, sech, coth): optimal_output = process_trig(optimal_output) if expr == optimal_output: return True if simplify(expr) == simplify(optimal_output): return True if nsimplify(expr) == nsimplify(optimal_output): return True if expr.has(sym_exp): expr = powsimp(powdenest(expr), force=True) if simplify(expr) == simplify(powsimp(optimal_output, force=True)): return True res = expr - optimal_output if _numerical: args = res.free_symbols rand_val = [] try: for i in range(0, 5): # check at 5 random points rand_x = randint(1, 40) substitutions = {s: rand_x for s in args} rand_val.append(float(abs(res.subs(substitutions).n()))) if stdev(rand_val) < Pow(10, -3): return True except: pass # return False dres = res.diff(x) if _numerical: args = dres.free_symbols rand_val = [] try: for i in range(0, 5): # check at 5 random points rand_x = randint(1, 40) substitutions = {s: rand_x for s in args} rand_val.append(float(abs(dres.subs(substitutions).n()))) if stdev(rand_val) < Pow(10, -3): return True # return False except: pass # return False r = Simplify(nsimplify(res)) if r == 0 or (not r.has(x)): return True if _diff: if dres == 0: return True elif Simplify(dres) == 0: return True if expand: # expands the expression and equates e = res.expand() if Simplify(e) == 0 or (not e.has(x)): return True return False def If(cond, t, f): # returns t if condition is true else f if cond: return t return f def IntQuadraticQ(a, b, c, d, e, m, p, x): # (* IntQuadraticQ[a,b,c,d,e,m,p,x] returns True iff (d+e*x)^m*(a+b*x+c*x^2)^p is integrable wrt x in terms of non-Appell functions. *) return IntegerQ(p) or PositiveIntegerQ(m) or IntegersQ(2*m, 2*p) or IntegersQ(m, 4*p) or IntegersQ(m, p + S(1)/3) and (ZeroQ(c**2*d**2 - b*c*d*e + b**2*e**2 - 3*a*c*e**2) or ZeroQ(c**2*d**2 - b*c*d*e - 2*b**2*e**2 + 9*a*c*e**2)) def IntBinomialQ(*args): #(* IntBinomialQ(a,b,c,n,m,p,x) returns True iff (c*x)^m*(a+b*x^n)^p is integrable wrt x in terms of non-hypergeometric functions. *) if len(args) == 8: a, b, c, d, n, p, q, x = args return IntegersQ(p,q) or PositiveIntegerQ(p) or PositiveIntegerQ(q) or (ZeroQ(n-2) or ZeroQ(n-4)) and (IntegersQ(p,4*q) or IntegersQ(4*p,q)) or ZeroQ(n-2) and (IntegersQ(2*p,2*q) or IntegersQ(3*p,q) and ZeroQ(b*c+3*a*d) or IntegersQ(p,3*q) and ZeroQ(3*b*c+a*d)) elif len(args) == 7: a, b, c, n, m, p, x = args return IntegerQ(2*p) or IntegerQ((m+1)/n + p) or (ZeroQ(n - 2) or ZeroQ(n - 4)) and IntegersQ(2*m, 4*p) or ZeroQ(n - 2) and IntegerQ(6*p) and (IntegerQ(m) or IntegerQ(m - p)) elif len(args) == 10: a, b, c, d, e, m, n, p, q, x = args return IntegersQ(p,q) or PositiveIntegerQ(p) or PositiveIntegerQ(q) or ZeroQ(n-2) and IntegerQ(m) and IntegersQ(2*p,2*q) or ZeroQ(n-4) and (IntegersQ(m,p,2*q) or IntegersQ(m,2*p,q)) def RectifyTangent(*args): # (* RectifyTangent(u,a,b,r,x) returns an expression whose derivative equals the derivative of r*ArcTan(a+b*Tan(u)) wrt x. *) if len(args) == 5: u, a, b, r, x = args t1 = Together(a) t2 = Together(b) if (PureComplexNumberQ(t1) or (ProductQ(t1) and any(PureComplexNumberQ(i) for i in t1.args))) and (PureComplexNumberQ(t2) or ProductQ(t2) and any(PureComplexNumberQ(i) for i in t2.args)): c = a/I d = b/I if NegativeQ(d): return RectifyTangent(u, -a, -b, -r, x) e = SmartDenominator(Together(c + d*x)) c = c*e d = d*e if EvenQ(Denominator(NumericFactor(Together(u)))): return I*r*Log(RemoveContent(Simplify((c+e)**2+d**2)+Simplify((c+e)**2-d**2)*Cos(2*u)+Simplify(2*(c+e)*d)*Sin(2*u),x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2+d**2)+Simplify((c-e)**2-d**2)*Cos(2*u)+Simplify(2*(c-e)*d)*Sin(2*u),x))/4 return I*r*Log(RemoveContent(Simplify((c+e)**2)+Simplify(2*(c+e)*d)*Cos(u)*Sin(u)-Simplify((c+e)**2-d**2)*Sin(u)**2,x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2)+Simplify(2*(c-e)*d)*Cos(u)*Sin(u)-Simplify((c-e)**2-d**2)*Sin(u)**2,x))/4 elif NegativeQ(b): return RectifyTangent(u, -a, -b, -r, x) elif EvenQ(Denominator(NumericFactor(Together(u)))): return r*SimplifyAntiderivative(u,x) + r*ArcTan(Simplify((2*a*b*Cos(2*u)-(1+a**2-b**2)*Sin(2*u))/(a**2+(1+b)**2+(1+a**2-b**2)*Cos(2*u)+2*a*b*Sin(2*u)))) return r*SimplifyAntiderivative(u,x) - r*ArcTan(ActivateTrig(Simplify((a*b-2*a*b*cos(u)**2+(1+a**2-b**2)*cos(u)*sin(u))/(b*(1+b)+(1+a**2-b**2)*cos(u)**2+2*a*b*cos(u)*sin(u))))) u, a, b, x = args t = Together(a) if PureComplexNumberQ(t) or (ProductQ(t) and any(PureComplexNumberQ(i) for i in t.args)): c = a/I if NegativeQ(c): return RectifyTangent(u, -a, -b, x) if ZeroQ(c - 1): if EvenQ(Denominator(NumericFactor(Together(u)))): return I*b*ArcTanh(Sin(2*u))/2 return I*b*ArcTanh(2*cos(u)*sin(u))/2 e = SmartDenominator(c) c = c*e return I*b*Log(RemoveContent(e*Cos(u)+c*Sin(u),x))/2 - I*b*Log(RemoveContent(e*Cos(u)-c*Sin(u),x))/2 elif NegativeQ(a): return RectifyTangent(u, -a, -b, x) elif ZeroQ(a - 1): return b*SimplifyAntiderivative(u, x) elif EvenQ(Denominator(NumericFactor(Together(u)))): c = Simplify((1 + a)/(1 - a)) numr = SmartNumerator(c) denr = SmartDenominator(c) return b*SimplifyAntiderivative(u,x) - b*ArcTan(NormalizeLeadTermSigns(denr*Sin(2*u)/(numr+denr*Cos(2*u)))), elif PositiveQ(a - 1): c = Simplify(1/(a - 1)) numr = SmartNumerator(c) denr = SmartDenominator(c) return b*SimplifyAntiderivative(u,x) + b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Sin(u)**2))), c = Simplify(a/(1 - a)) numr = SmartNumerator(c) denr = SmartDenominator(c) return b*SimplifyAntiderivative(u,x) - b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Cos(u)**2))) def RectifyCotangent(*args): #(* RectifyCotangent[u,a,b,r,x] returns an expression whose derivative equals the derivative of r*ArcTan[a+b*Cot[u]] wrt x. *) if len(args) == 5: u, a, b, r, x = args t1 = Together(a) t2 = Together(b) if (PureComplexNumberQ(t1) or (ProductQ(t1) and any(PureComplexNumberQ(i) for i in t1.args))) and (PureComplexNumberQ(t2) or ProductQ(t2) and any(PureComplexNumberQ(i) for i in t2.args)): c = a/I d = b/I if NegativeQ(d): return RectifyTangent(u,-a,-b,-r,x) e = SmartDenominator(Together(c + d*x)) c = c*e d = d*e if EvenQ(Denominator(NumericFactor(Together(u)))): return I*r*Log(RemoveContent(Simplify((c+e)**2+d**2)-Simplify((c+e)**2-d**2)*Cos(2*u)+Simplify(2*(c+e)*d)*Sin(2*u),x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2+d**2)-Simplify((c-e)**2-d**2)*Cos(2*u)+Simplify(2*(c-e)*d)*Sin(2*u),x))/4 return I*r*Log(RemoveContent(Simplify((c+e)**2)-Simplify((c+e)**2-d**2)*Cos(u)**2+Simplify(2*(c+e)*d)*Cos(u)*Sin(u),x))/4 - I*r*Log(RemoveContent(Simplify((c-e)**2)-Simplify((c-e)**2-d**2)*Cos(u)**2+Simplify(2*(c-e)*d)*Cos(u)*Sin(u),x))/4 elif NegativeQ(b): return RectifyCotangent(u,-a,-b,-r,x) elif EvenQ(Denominator(NumericFactor(Together(u)))): return -r*SimplifyAntiderivative(u,x) - r*ArcTan(Simplify((2*a*b*Cos(2*u)+(1+a**2-b**2)*Sin(2*u))/(a**2+(1+b)**2-(1+a**2-b**2)*Cos(2*u)+2*a*b*Sin(2*u)))) return -r*SimplifyAntiderivative(u,x) - r*ArcTan(ActivateTrig(Simplify((a*b-2*a*b*sin(u)**2+(1+a**2-b**2)*cos(u)*sin(u))/(b*(1+b)+(1+a**2-b**2)*sin(u)**2+2*a*b*cos(u)*sin(u))))) u, a, b, x = args t = Together(a) if PureComplexNumberQ(t) or (ProductQ(t) and any(PureComplexNumberQ(i) for i in t.args)): c = a/I if NegativeQ(c): return RectifyCotangent(u,-a,-b,x) elif ZeroQ(c - 1): if EvenQ(Denominator(NumericFactor(Together(u)))): return -I*b*ArcTanh(Sin(2*u))/2 return -I*b*ArcTanh(2*Cos(u)*Sin(u))/2 e = SmartDenominator(c) c = c*e return -I*b*Log(RemoveContent(c*Cos(u)+e*Sin(u),x))/2 + I*b*Log(RemoveContent(c*Cos(u)-e*Sin(u),x))/2 elif NegativeQ(a): return RectifyCotangent(u,-a,-b,x) elif ZeroQ(a-1): return b*SimplifyAntiderivative(u,x) elif EvenQ(Denominator(NumericFactor(Together(u)))): c = Simplify(a - 1) numr = SmartNumerator(c) denr = SmartDenominator(c) return b*SimplifyAntiderivative(u,x) - b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Cos(u)**2))) c = Simplify(a/(1-a)) numr = SmartNumerator(c) denr = SmartDenominator(c) return b*SimplifyAntiderivative(u,x) + b*ArcTan(NormalizeLeadTermSigns(denr*Cos(u)*Sin(u)/(numr+denr*Sin(u)**2))) def Inequality(*args): f = args[1::2] e = args[0::2] r = [] for i in range(0, len(f)): r.append(f[i](e[i], e[i + 1])) return all(r) def Condition(r, c): # returns r if c is True if c: return r else: raise NotImplementedError('In Condition()') def Simp(u, x): u = replace_pow_exp(u) return NormalizeSumFactors(SimpHelp(u, x)) def SimpHelp(u, x): if AtomQ(u): return u elif FreeQ(u, x): v = SmartSimplify(u) if LeafCount(v) <= LeafCount(u): return v return u elif ProductQ(u): #m = MatchQ[Rest[u],a_.+n_*Pi+b_.*v_ /; FreeQ[{a,b},x] && Not[FreeQ[v,x]] && EqQ[n^2,1/4]] #if EqQ(First(u), S(1)/2) and m: # if #If[EqQ[First[u],1/2] && MatchQ[Rest[u],a_.+n_*Pi+b_.*v_ /; FreeQ[{a,b},x] && Not[FreeQ[v,x]] && EqQ[n^2,1/4]], # If[MatchQ[Rest[u],n_*Pi+b_.*v_ /; FreeQ[b,x] && Not[FreeQ[v,x]] && EqQ[n^2,1/4]], # Map[Function[1/2*#],Rest[u]], # If[MatchQ[Rest[u],m_*a_.+n_*Pi+p_*b_.*v_ /; FreeQ[{a,b},x] && Not[FreeQ[v,x]] && IntegersQ[m/2,p/2]], # Map[Function[1/2*#],Rest[u]], # u]], v = FreeFactors(u, x) w = NonfreeFactors(u, x) v = NumericFactor(v)*SmartSimplify(NonnumericFactors(v)*x**2)/x**2 if ProductQ(w): w = Mul(*[SimpHelp(i,x) for i in w.args]) else: w = SimpHelp(w, x) w = FactorNumericGcd(w) v = MergeFactors(v, w) if ProductQ(v): return Mul(*[SimpFixFactor(i, x) for i in v.args]) return v elif SumQ(u): Pi = pi a_ = Wild('a', exclude=[x]) b_ = Wild('b', exclude=[x, 0]) n_ = Wild('n', exclude=[x, 0, 0]) pattern = a_ + n_*Pi + b_*x match = u.match(pattern) m = False if match: if EqQ(match[n_]**3, S(1)/16): m = True if m: return u elif PolynomialQ(u, x) and Exponent(u, x) <= 0: return SimpHelp(Coefficient(u, x, 0), x) elif PolynomialQ(u, x) and Exponent(u, x) == 1 and Coefficient(u, x, 0) == 0: return SimpHelp(Coefficient(u, x, 1), x)*x v = 0 w = 0 for i in u.args: if FreeQ(i, x): v = i + v else: w = i + w v = SmartSimplify(v) if SumQ(w): w = Add(*[SimpHelp(i, x) for i in w.args]) else: w = SimpHelp(w, x) return v + w return u.func(*[SimpHelp(i, x) for i in u.args]) def SplitProduct(func, u): #(* If func[v] is True for a factor v of u, SplitProduct[func,u] returns {v, u/v} where v is the first such factor; else it returns False. *) if ProductQ(u): if func(First(u)): return [First(u), Rest(u)] lst = SplitProduct(func, Rest(u)) if AtomQ(lst): return False return [lst[0], First(u)*lst[1]] if func(u): return [u, 1] return False def SplitSum(func, u): # (* If func[v] is nonatomic for a term v of u, SplitSum[func,u] returns {func[v], u-v} where v is the first such term; else it returns False. *) if SumQ(u): if Not(AtomQ(func(First(u)))): return [func(First(u)), Rest(u)] lst = SplitSum(func, Rest(u)) if AtomQ(lst): return False return [lst[0], First(u) + lst[1]] elif Not(AtomQ(func(u))): return [func(u), 0] return False def SubstFor(*args): if len(args) == 4: w, v, u, x = args # u is a function of v. SubstFor(w,v,u,x) returns w times u with v replaced by x. return SimplifyIntegrand(w*SubstFor(v, u, x), x) v, u, x = args # u is a function of v. SubstFor(v, u, x) returns u with v replaced by x. if AtomQ(v): return Subst(u, v, x) elif Not(EqQ(FreeFactors(v, x), 1)): return SubstFor(NonfreeFactors(v, x), u, x/FreeFactors(v, x)) elif SinQ(v): return SubstForTrig(u, x, Sqrt(1 - x**2), v.args[0], x) elif CosQ(v): return SubstForTrig(u, Sqrt(1 - x**2), x, v.args[0], x) elif TanQ(v): return SubstForTrig(u, x/Sqrt(1 + x**2), 1/Sqrt(1 + x**2), v.args[0], x) elif CotQ(v): return SubstForTrig(u, 1/Sqrt(1 + x**2), x/Sqrt(1 + x**2), v.args[0], x) elif SecQ(v): return SubstForTrig(u, 1/Sqrt(1 - x**2), 1/x, v.args[0], x) elif CscQ(v): return SubstForTrig(u, 1/x, 1/Sqrt(1 - x**2), v.args[0], x) elif SinhQ(v): return SubstForHyperbolic(u, x, Sqrt(1 + x**2), v.args[0], x) elif CoshQ(v): return SubstForHyperbolic(u, Sqrt( - 1 + x**2), x, v.args[0], x) elif TanhQ(v): return SubstForHyperbolic(u, x/Sqrt(1 - x**2), 1/Sqrt(1 - x**2), v.args[0], x) elif CothQ(v): return SubstForHyperbolic(u, 1/Sqrt( - 1 + x**2), x/Sqrt( - 1 + x**2), v.args[0], x) elif SechQ(v): return SubstForHyperbolic(u, 1/Sqrt( - 1 + x**2), 1/x, v.args[0], x) elif CschQ(v): return SubstForHyperbolic(u, 1/x, 1/Sqrt(1 + x**2), v.args[0], x) else: return SubstForAux(u, v, x) def SubstForAux(u, v, x): # u is a function of v. SubstForAux(u, v, x) returns u with v replaced by x. if u==v: return x elif AtomQ(u): if PowerQ(v): if FreeQ(v.exp, x) and ZeroQ(u - v.base): return x**Simplify(1/v.exp) return u elif PowerQ(u): if FreeQ(u.exp, x): if ZeroQ(u.base - v): return x**u.exp if PowerQ(v): if FreeQ(v.exp, x) and ZeroQ(u.base - v.base): return x**Simplify(u.exp/v.exp) return SubstForAux(u.base, v, x)**u.exp elif ProductQ(u) and Not(EqQ(FreeFactors(u, x), 1)): return FreeFactors(u, x)*SubstForAux(NonfreeFactors(u, x), v, x) elif ProductQ(u) and ProductQ(v): return SubstForAux(First(u), First(v), x) return u.func(*[SubstForAux(i, v, x) for i in u.args]) def FresnelS(x): return fresnels(x) def FresnelC(x): return fresnelc(x) def Erf(x): return erf(x) def Erfc(x): return erfc(x) def Erfi(x): return erfi(x) class Gamma(Function): @classmethod def eval(cls,*args): a = args[0] if len(args) == 1: return gamma(a) else: b = args[1] if (NumericQ(a) and NumericQ(b)) or a == 1: return uppergamma(a, b) def FunctionOfTrigOfLinearQ(u, x): # If u is an algebraic function of trig functions of a linear function of x, # FunctionOfTrigOfLinearQ[u,x] returns True; else it returns False. if FunctionOfTrig(u, None, x) and AlgebraicTrigFunctionQ(u, x) and FunctionOfLinear(FunctionOfTrig(u, None, x), x): return True else: return False def ElementaryFunctionQ(u): # ElementaryExpressionQ[u] returns True if u is a sum, product, or power and all the operands # are elementary expressions; or if u is a call on a trig, hyperbolic, or inverse function # and all the arguments are elementary expressions; else it returns False. if AtomQ(u): return True elif SumQ(u) or ProductQ(u) or PowerQ(u) or TrigQ(u) or HyperbolicQ(u) or InverseFunctionQ(u): for i in u.args: if not ElementaryFunctionQ(i): return False return True return False def Complex(a, b): return a + I*b def UnsameQ(a, b): return a != b @doctest_depends_on(modules=('matchpy',)) def _SimpFixFactor(): replacer = ManyToOneReplacer() pattern1 = Pattern(UtilityOperator(Pow(Add(Mul(Complex(S(0), c_), WC('a', S(1))), Mul(Complex(S(0), d_), WC('b', S(1)))), WC('p', S(1))), x_), CustomConstraint(lambda p: IntegerQ(p))) rule1 = ReplacementRule(pattern1, lambda b, c, x, a, p, d : Mul(Pow(I, p), SimpFixFactor(Pow(Add(Mul(a, c), Mul(b, d)), p), x))) replacer.add(rule1) pattern2 = Pattern(UtilityOperator(Pow(Add(Mul(Complex(S(0), d_), WC('a', S(1))), Mul(Complex(S(0), e_), WC('b', S(1))), Mul(Complex(S(0), f_), WC('c', S(1)))), WC('p', S(1))), x_), CustomConstraint(lambda p: IntegerQ(p))) rule2 = ReplacementRule(pattern2, lambda b, c, x, f, a, p, e, d : Mul(Pow(I, p), SimpFixFactor(Pow(Add(Mul(a, d), Mul(b, e), Mul(c, f)), p), x))) replacer.add(rule2) pattern3 = Pattern(UtilityOperator(Pow(Add(Mul(WC('a', S(1)), Pow(c_, r_)), Mul(WC('b', S(1)), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda c: AtomQ(c)), CustomConstraint(lambda r: RationalQ(r)), CustomConstraint(lambda r: Less(r, S(0)))) rule3 = ReplacementRule(pattern3, lambda b, c, r, n, x, a, p : Mul(Pow(c, Mul(r, p)), SimpFixFactor(Pow(Add(a, Mul(Mul(b, Pow(Pow(c, r), S(-1))), Pow(x, n))), p), x))) replacer.add(rule3) pattern4 = Pattern(UtilityOperator(Pow(Add(WC('a', S(0)), Mul(WC('b', S(1)), Pow(c_, r_), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda c: AtomQ(c)), CustomConstraint(lambda r: RationalQ(r)), CustomConstraint(lambda r: Less(r, S(0)))) rule4 = ReplacementRule(pattern4, lambda b, c, r, n, x, a, p : Mul(Pow(c, Mul(r, p)), SimpFixFactor(Pow(Add(Mul(a, Pow(Pow(c, r), S(-1))), Mul(b, Pow(x, n))), p), x))) replacer.add(rule4) pattern5 = Pattern(UtilityOperator(Pow(Add(Mul(WC('a', S(1)), Pow(c_, WC('s', S(1)))), Mul(WC('b', S(1)), Pow(c_, WC('r', S(1))), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda r, s: RationalQ(s, r)), CustomConstraint(lambda r, s: Inequality(S(0), Less, s, LessEqual, r)), CustomConstraint(lambda p, c, s: UnsameQ(Pow(c, Mul(s, p)), S(-1)))) rule5 = ReplacementRule(pattern5, lambda b, c, r, n, x, a, p, s : Mul(Pow(c, Mul(s, p)), SimpFixFactor(Pow(Add(a, Mul(b, Pow(c, Add(r, Mul(S(-1), s))), Pow(x, n))), p), x))) replacer.add(rule5) pattern6 = Pattern(UtilityOperator(Pow(Add(Mul(WC('a', S(1)), Pow(c_, WC('s', S(1)))), Mul(WC('b', S(1)), Pow(c_, WC('r', S(1))), Pow(x_, WC('n', S(1))))), WC('p', S(1))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda n, p: IntegersQ(n, p)), CustomConstraint(lambda r, s: RationalQ(s, r)), CustomConstraint(lambda s, r: Less(S(0), r, s)), CustomConstraint(lambda p, c, r: UnsameQ(Pow(c, Mul(r, p)), S(-1)))) rule6 = ReplacementRule(pattern6, lambda b, c, r, n, x, a, p, s : Mul(Pow(c, Mul(r, p)), SimpFixFactor(Pow(Add(Mul(a, Pow(c, Add(s, Mul(S(-1), r)))), Mul(b, Pow(x, n))), p), x))) replacer.add(rule6) return replacer @doctest_depends_on(modules=('matchpy',)) def SimpFixFactor(expr, x): r = SimpFixFactor_replacer.replace(UtilityOperator(expr, x)) if isinstance(r, UtilityOperator): return expr return r @doctest_depends_on(modules=('matchpy',)) def _FixSimplify(): Plus = Add def cons_f1(n): return OddQ(n) cons1 = CustomConstraint(cons_f1) def cons_f2(m): return RationalQ(m) cons2 = CustomConstraint(cons_f2) def cons_f3(n): return FractionQ(n) cons3 = CustomConstraint(cons_f3) def cons_f4(u): return SqrtNumberSumQ(u) cons4 = CustomConstraint(cons_f4) def cons_f5(v): return SqrtNumberSumQ(v) cons5 = CustomConstraint(cons_f5) def cons_f6(u): return PositiveQ(u) cons6 = CustomConstraint(cons_f6) def cons_f7(v): return PositiveQ(v) cons7 = CustomConstraint(cons_f7) def cons_f8(v): return SqrtNumberSumQ(S(1)/v) cons8 = CustomConstraint(cons_f8) def cons_f9(m): return IntegerQ(m) cons9 = CustomConstraint(cons_f9) def cons_f10(u): return NegativeQ(u) cons10 = CustomConstraint(cons_f10) def cons_f11(n, m, a, b): return RationalQ(a, b, m, n) cons11 = CustomConstraint(cons_f11) def cons_f12(a): return Greater(a, S(0)) cons12 = CustomConstraint(cons_f12) def cons_f13(b): return Greater(b, S(0)) cons13 = CustomConstraint(cons_f13) def cons_f14(p): return PositiveIntegerQ(p) cons14 = CustomConstraint(cons_f14) def cons_f15(p): return IntegerQ(p) cons15 = CustomConstraint(cons_f15) def cons_f16(p, n): return Greater(-n + p, S(0)) cons16 = CustomConstraint(cons_f16) def cons_f17(a, b): return SameQ(a + b, S(0)) cons17 = CustomConstraint(cons_f17) def cons_f18(n): return Not(IntegerQ(n)) cons18 = CustomConstraint(cons_f18) def cons_f19(c, a, b, d): return ZeroQ(-a*d + b*c) cons19 = CustomConstraint(cons_f19) def cons_f20(a): return Not(RationalQ(a)) cons20 = CustomConstraint(cons_f20) def cons_f21(t): return IntegerQ(t) cons21 = CustomConstraint(cons_f21) def cons_f22(n, m): return RationalQ(m, n) cons22 = CustomConstraint(cons_f22) def cons_f23(n, m): return Inequality(S(0), Less, m, LessEqual, n) cons23 = CustomConstraint(cons_f23) def cons_f24(p, n, m): return RationalQ(m, n, p) cons24 = CustomConstraint(cons_f24) def cons_f25(p, n, m): return Inequality(S(0), Less, m, LessEqual, n, LessEqual, p) cons25 = CustomConstraint(cons_f25) def cons_f26(p, n, m, q): return Inequality(S(0), Less, m, LessEqual, n, LessEqual, p, LessEqual, q) cons26 = CustomConstraint(cons_f26) def cons_f27(w): return Not(RationalQ(w)) cons27 = CustomConstraint(cons_f27) def cons_f28(n): return Less(n, S(0)) cons28 = CustomConstraint(cons_f28) def cons_f29(n, w, v): return ZeroQ(v + w**(-n)) cons29 = CustomConstraint(cons_f29) def cons_f30(n): return IntegerQ(n) cons30 = CustomConstraint(cons_f30) def cons_f31(w, v): return ZeroQ(v + w) cons31 = CustomConstraint(cons_f31) def cons_f32(p, n): return IntegerQ(n/p) cons32 = CustomConstraint(cons_f32) def cons_f33(w, v): return ZeroQ(v - w) cons33 = CustomConstraint(cons_f33) def cons_f34(p, n): return IntegersQ(n, n/p) cons34 = CustomConstraint(cons_f34) def cons_f35(a): return AtomQ(a) cons35 = CustomConstraint(cons_f35) def cons_f36(b): return AtomQ(b) cons36 = CustomConstraint(cons_f36) pattern1 = Pattern(UtilityOperator((w_ + Complex(S(0), b_)*WC('v', S(1)))**WC('n', S(1))*Complex(S(0), a_)*WC('u', S(1))), cons1) def replacement1(n, u, w, v, a, b): return (S(-1))**(n/S(2) + S(1)/2)*a*u*FixSimplify((b*v - w*Complex(S(0), S(1)))**n) rule1 = ReplacementRule(pattern1, replacement1) def With2(m, n, u, w, v): z = u**(m/GCD(m, n))*v**(n/GCD(m, n)) if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)): return True return False pattern2 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons2, cons3, cons4, cons5, cons6, cons7, CustomConstraint(With2)) def replacement2(m, n, u, w, v): z = u**(m/GCD(m, n))*v**(n/GCD(m, n)) return FixSimplify(w*z**GCD(m, n)) rule2 = ReplacementRule(pattern2, replacement2) def With3(m, n, u, w, v): z = u**(m/GCD(m, -n))*v**(n/GCD(m, -n)) if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)): return True return False pattern3 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons2, cons3, cons4, cons8, cons6, cons7, CustomConstraint(With3)) def replacement3(m, n, u, w, v): z = u**(m/GCD(m, -n))*v**(n/GCD(m, -n)) return FixSimplify(w*z**GCD(m, -n)) rule3 = ReplacementRule(pattern3, replacement3) def With4(m, n, u, w, v): z = v**(n/GCD(m, n))*(-u)**(m/GCD(m, n)) if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)): return True return False pattern4 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons9, cons3, cons4, cons5, cons10, cons7, CustomConstraint(With4)) def replacement4(m, n, u, w, v): z = v**(n/GCD(m, n))*(-u)**(m/GCD(m, n)) return FixSimplify(-w*z**GCD(m, n)) rule4 = ReplacementRule(pattern4, replacement4) def With5(m, n, u, w, v): z = v**(n/GCD(m, -n))*(-u)**(m/GCD(m, -n)) if Or(AbsurdNumberQ(z), SqrtNumberSumQ(z)): return True return False pattern5 = Pattern(UtilityOperator(u_**WC('m', S(1))*v_**n_*WC('w', S(1))), cons9, cons3, cons4, cons8, cons10, cons7, CustomConstraint(With5)) def replacement5(m, n, u, w, v): z = v**(n/GCD(m, -n))*(-u)**(m/GCD(m, -n)) return FixSimplify(-w*z**GCD(m, -n)) rule5 = ReplacementRule(pattern5, replacement5) def With6(p, m, n, u, w, v, a, b): c = a**(m/p)*b**n if RationalQ(c): return True return False pattern6 = Pattern(UtilityOperator(a_**m_*(b_**n_*WC('v', S(1)) + u_)**WC('p', S(1))*WC('w', S(1))), cons11, cons12, cons13, cons14, CustomConstraint(With6)) def replacement6(p, m, n, u, w, v, a, b): c = a**(m/p)*b**n return FixSimplify(w*(a**(m/p)*u + c*v)**p) rule6 = ReplacementRule(pattern6, replacement6) pattern7 = Pattern(UtilityOperator(a_**WC('m', S(1))*(a_**n_*WC('u', S(1)) + b_**WC('p', S(1))*WC('v', S(1)))*WC('w', S(1))), cons2, cons3, cons15, cons16, cons17) def replacement7(p, m, n, u, w, v, a, b): return FixSimplify(a**(m + n)*w*((S(-1))**p*a**(-n + p)*v + u)) rule7 = ReplacementRule(pattern7, replacement7) def With8(m, d, n, w, c, a, b): q = b/d if FreeQ(q, Plus): return True return False pattern8 = Pattern(UtilityOperator((a_ + b_)**WC('m', S(1))*(c_ + d_)**n_*WC('w', S(1))), cons9, cons18, cons19, CustomConstraint(With8)) def replacement8(m, d, n, w, c, a, b): q = b/d return FixSimplify(q**m*w*(c + d)**(m + n)) rule8 = ReplacementRule(pattern8, replacement8) pattern9 = Pattern(UtilityOperator((a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)))**WC('t', S(1))*WC('w', S(1))), cons20, cons21, cons22, cons23) def replacement9(m, n, u, w, v, a, t): return FixSimplify(a**(m*t)*w*(a**(-m + n)*v + u)**t) rule9 = ReplacementRule(pattern9, replacement9) pattern10 = Pattern(UtilityOperator((a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)) + a_**WC('p', S(1))*WC('z', S(1)))**WC('t', S(1))*WC('w', S(1))), cons20, cons21, cons24, cons25) def replacement10(p, m, n, u, w, v, a, z, t): return FixSimplify(a**(m*t)*w*(a**(-m + n)*v + a**(-m + p)*z + u)**t) rule10 = ReplacementRule(pattern10, replacement10) pattern11 = Pattern(UtilityOperator((a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)) + a_**WC('p', S(1))*WC('z', S(1)) + a_**WC('q', S(1))*WC('y', S(1)))**WC('t', S(1))*WC('w', S(1))), cons20, cons21, cons24, cons26) def replacement11(p, m, n, u, q, w, v, a, z, y, t): return FixSimplify(a**(m*t)*w*(a**(-m + n)*v + a**(-m + p)*z + a**(-m + q)*y + u)**t) rule11 = ReplacementRule(pattern11, replacement11) pattern12 = Pattern(UtilityOperator((sqrt(v_)*WC('b', S(1)) + sqrt(v_)*WC('c', S(1)) + sqrt(v_)*WC('d', S(1)) + sqrt(v_)*WC('a', S(1)) + WC('u', S(0)))*WC('w', S(1)))) def replacement12(d, u, w, v, c, a, b): return FixSimplify(w*(u + sqrt(v)*FixSimplify(a + b + c + d))) rule12 = ReplacementRule(pattern12, replacement12) pattern13 = Pattern(UtilityOperator((sqrt(v_)*WC('b', S(1)) + sqrt(v_)*WC('c', S(1)) + sqrt(v_)*WC('a', S(1)) + WC('u', S(0)))*WC('w', S(1)))) def replacement13(u, w, v, c, a, b): return FixSimplify(w*(u + sqrt(v)*FixSimplify(a + b + c))) rule13 = ReplacementRule(pattern13, replacement13) pattern14 = Pattern(UtilityOperator((sqrt(v_)*WC('b', S(1)) + sqrt(v_)*WC('a', S(1)) + WC('u', S(0)))*WC('w', S(1)))) def replacement14(u, w, v, a, b): return FixSimplify(w*(u + sqrt(v)*FixSimplify(a + b))) rule14 = ReplacementRule(pattern14, replacement14) pattern15 = Pattern(UtilityOperator(v_**m_*w_**n_*WC('u', S(1))), cons2, cons27, cons3, cons28, cons29) def replacement15(m, n, u, w, v): return -FixSimplify(u*v**(m + S(-1))) rule15 = ReplacementRule(pattern15, replacement15) pattern16 = Pattern(UtilityOperator(v_**m_*w_**WC('n', S(1))*WC('u', S(1))), cons2, cons27, cons30, cons31) def replacement16(m, n, u, w, v): return (S(-1))**n*FixSimplify(u*v**(m + n)) rule16 = ReplacementRule(pattern16, replacement16) pattern17 = Pattern(UtilityOperator(w_**WC('n', S(1))*(-v_**WC('p', S(1)))**m_*WC('u', S(1))), cons2, cons27, cons32, cons33) def replacement17(p, m, n, u, w, v): return (S(-1))**(n/p)*FixSimplify(u*(-v**p)**(m + n/p)) rule17 = ReplacementRule(pattern17, replacement17) pattern18 = Pattern(UtilityOperator(w_**WC('n', S(1))*(-v_**WC('p', S(1)))**m_*WC('u', S(1))), cons2, cons27, cons34, cons31) def replacement18(p, m, n, u, w, v): return (S(-1))**(n + n/p)*FixSimplify(u*(-v**p)**(m + n/p)) rule18 = ReplacementRule(pattern18, replacement18) pattern19 = Pattern(UtilityOperator((a_ - b_)**WC('m', S(1))*(a_ + b_)**WC('m', S(1))*WC('u', S(1))), cons9, cons35, cons36) def replacement19(m, u, a, b): return u*(a**S(2) - b**S(2))**m rule19 = ReplacementRule(pattern19, replacement19) pattern20 = Pattern(UtilityOperator((S(729)*c - e*(-S(20)*e + S(540)))**WC('m', S(1))*WC('u', S(1))), cons2) def replacement20(m, u): return u*(a*e**S(2) - b*d*e + c*d**S(2))**m rule20 = ReplacementRule(pattern20, replacement20) pattern21 = Pattern(UtilityOperator((S(729)*c + e*(S(20)*e + S(-540)))**WC('m', S(1))*WC('u', S(1))), cons2) def replacement21(m, u): return u*(a*e**S(2) - b*d*e + c*d**S(2))**m rule21 = ReplacementRule(pattern21, replacement21) pattern22 = Pattern(UtilityOperator(u_)) def replacement22(u): return u rule22 = ReplacementRule(pattern22, replacement22) return [rule1, rule2, rule3, rule4, rule5, rule6, rule7, rule8, rule9, rule10, rule11, rule12, rule13, rule14, rule15, rule16, rule17, rule18, rule19, rule20, rule21, rule22, ] @doctest_depends_on(modules=('matchpy',)) def FixSimplify(expr): if isinstance(expr, (list, tuple, TupleArg)): return [replace_all(UtilityOperator(i), FixSimplify_rules) for i in expr] return replace_all(UtilityOperator(expr), FixSimplify_rules) @doctest_depends_on(modules=('matchpy',)) def _SimplifyAntiderivativeSum(): replacer = ManyToOneReplacer() pattern1 = Pattern(UtilityOperator(Add(Mul(Log(Add(a_, Mul(WC('b', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('A', S(1))), Mul(Log(Cos(u_)), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, n: ZeroQ(Add(Mul(n, A), Mul(S(1), B))))) rule1 = ReplacementRule(pattern1, lambda n, x, v, b, B, A, u, a : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Cos(u), n)), Mul(b, Pow(Sin(u), n))), x))))) replacer.add(rule1) pattern2 = Pattern(UtilityOperator(Add(Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('b', S(1))), a_)), WC('A', S(1))), Mul(Log(Sin(u_)), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, n: ZeroQ(Add(Mul(n, A), Mul(S(1), B))))) rule2 = ReplacementRule(pattern2, lambda n, x, v, b, B, A, a, u : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Sin(u), n)), Mul(b, Pow(Cos(u), n))), x))))) replacer.add(rule2) pattern3 = Pattern(UtilityOperator(Add(Mul(Log(Add(a_, Mul(WC('b', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('A', S(1))), Mul(Log(Add(c_, Mul(WC('d', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A: ZeroQ(Add(A, B)))) rule3 = ReplacementRule(pattern3, lambda n, x, v, b, A, B, u, c, d, a : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Cos(u), n)), Mul(b, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(c, Pow(Cos(u), n)), Mul(d, Pow(Sin(u), n))), x))))) replacer.add(rule3) pattern4 = Pattern(UtilityOperator(Add(Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('b', S(1))), a_)), WC('A', S(1))), Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('d', S(1))), c_)), WC('B', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A: ZeroQ(Add(A, B)))) rule4 = ReplacementRule(pattern4, lambda n, x, v, b, A, B, c, a, d, u : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(b, Pow(Cos(u), n)), Mul(a, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(d, Pow(Cos(u), n)), Mul(c, Pow(Sin(u), n))), x))))) replacer.add(rule4) pattern5 = Pattern(UtilityOperator(Add(Mul(Log(Add(a_, Mul(WC('b', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('A', S(1))), Mul(Log(Add(c_, Mul(WC('d', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('B', S(1))), Mul(Log(Add(e_, Mul(WC('f', S(1)), Pow(Tan(u_), WC('n', S(1)))))), WC('C', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda e, x: FreeQ(e, x)), CustomConstraint(lambda f, x: FreeQ(f, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda C, x: FreeQ(C, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, C: ZeroQ(Add(A, B, C)))) rule5 = ReplacementRule(pattern5, lambda n, e, x, v, b, A, B, u, c, f, d, a, C : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(a, Pow(Cos(u), n)), Mul(b, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(c, Pow(Cos(u), n)), Mul(d, Pow(Sin(u), n))), x))), Mul(C, Log(RemoveContent(Add(Mul(e, Pow(Cos(u), n)), Mul(f, Pow(Sin(u), n))), x))))) replacer.add(rule5) pattern6 = Pattern(UtilityOperator(Add(Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('b', S(1))), a_)), WC('A', S(1))), Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('d', S(1))), c_)), WC('B', S(1))), Mul(Log(Add(Mul(Pow(Cot(u_), WC('n', S(1))), WC('f', S(1))), e_)), WC('C', S(1))), WC('v', S(0))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda d, x: FreeQ(d, x)), CustomConstraint(lambda e, x: FreeQ(e, x)), CustomConstraint(lambda f, x: FreeQ(f, x)), CustomConstraint(lambda A, x: FreeQ(A, x)), CustomConstraint(lambda B, x: FreeQ(B, x)), CustomConstraint(lambda C, x: FreeQ(C, x)), CustomConstraint(lambda n: IntegerQ(n)), CustomConstraint(lambda B, A, C: ZeroQ(Add(A, B, C)))) rule6 = ReplacementRule(pattern6, lambda n, e, x, v, b, A, B, c, a, f, d, u, C : Add(SimplifyAntiderivativeSum(v, x), Mul(A, Log(RemoveContent(Add(Mul(b, Pow(Cos(u), n)), Mul(a, Pow(Sin(u), n))), x))), Mul(B, Log(RemoveContent(Add(Mul(d, Pow(Cos(u), n)), Mul(c, Pow(Sin(u), n))), x))), Mul(C, Log(RemoveContent(Add(Mul(f, Pow(Cos(u), n)), Mul(e, Pow(Sin(u), n))), x))))) replacer.add(rule6) return replacer @doctest_depends_on(modules=('matchpy',)) def SimplifyAntiderivativeSum(expr, x): r = SimplifyAntiderivativeSum_replacer.replace(UtilityOperator(expr, x)) if isinstance(r, UtilityOperator): return expr return r @doctest_depends_on(modules=('matchpy',)) def _SimplifyAntiderivative(): replacer = ManyToOneReplacer() pattern2 = Pattern(UtilityOperator(Log(Mul(c_, u_)), x_), CustomConstraint(lambda c, x: FreeQ(c, x))) rule2 = ReplacementRule(pattern2, lambda x, c, u : SimplifyAntiderivative(Log(u), x)) replacer.add(rule2) pattern3 = Pattern(UtilityOperator(Log(Pow(u_, n_)), x_), CustomConstraint(lambda n, x: FreeQ(n, x))) rule3 = ReplacementRule(pattern3, lambda x, n, u : Mul(n, SimplifyAntiderivative(Log(u), x))) replacer.add(rule3) pattern7 = Pattern(UtilityOperator(Log(Pow(f_, u_)), x_), CustomConstraint(lambda f, x: FreeQ(f, x))) rule7 = ReplacementRule(pattern7, lambda x, f, u : Mul(Log(f), SimplifyAntiderivative(u, x))) replacer.add(rule7) pattern8 = Pattern(UtilityOperator(Log(Add(a_, Mul(WC('b', S(1)), Tan(u_)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S(2)), Pow(b, S(2)))))) rule8 = ReplacementRule(pattern8, lambda x, b, u, a : Add(Mul(Mul(b, Pow(a, S(1))), SimplifyAntiderivative(u, x)), Mul(S(1), SimplifyAntiderivative(Log(Cos(u)), x)))) replacer.add(rule8) pattern9 = Pattern(UtilityOperator(Log(Add(Mul(Cot(u_), WC('b', S(1))), a_)), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S(2)), Pow(b, S(2)))))) rule9 = ReplacementRule(pattern9, lambda x, b, u, a : Add(Mul(Mul(Mul(S(1), b), Pow(a, S(1))), SimplifyAntiderivative(u, x)), Mul(S(1), SimplifyAntiderivative(Log(Sin(u)), x)))) replacer.add(rule9) pattern10 = Pattern(UtilityOperator(ArcTan(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule10 = ReplacementRule(pattern10, lambda x, u, a : RectifyTangent(u, a, S(1), x)) replacer.add(rule10) pattern11 = Pattern(UtilityOperator(ArcCot(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule11 = ReplacementRule(pattern11, lambda x, u, a : RectifyTangent(u, a, S(1), x)) replacer.add(rule11) pattern12 = Pattern(UtilityOperator(ArcCot(Mul(WC('a', S(1)), Tanh(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda u: ComplexFreeQ(u))) rule12 = ReplacementRule(pattern12, lambda x, u, a : Mul(S(1), SimplifyAntiderivative(ArcTan(Mul(a, Tanh(u))), x))) replacer.add(rule12) pattern13 = Pattern(UtilityOperator(ArcTanh(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule13 = ReplacementRule(pattern13, lambda x, u, a : RectifyTangent(u, Mul(I, a), Mul(S(1), I), x)) replacer.add(rule13) pattern14 = Pattern(UtilityOperator(ArcCoth(Mul(WC('a', S(1)), Tan(u_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule14 = ReplacementRule(pattern14, lambda x, u, a : RectifyTangent(u, Mul(I, a), Mul(S(1), I), x)) replacer.add(rule14) pattern15 = Pattern(UtilityOperator(ArcTanh(Tanh(u_)), x_)) rule15 = ReplacementRule(pattern15, lambda x, u : SimplifyAntiderivative(u, x)) replacer.add(rule15) pattern16 = Pattern(UtilityOperator(ArcCoth(Tanh(u_)), x_)) rule16 = ReplacementRule(pattern16, lambda x, u : SimplifyAntiderivative(u, x)) replacer.add(rule16) pattern17 = Pattern(UtilityOperator(ArcCot(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule17 = ReplacementRule(pattern17, lambda x, u, a : RectifyCotangent(u, a, S(1), x)) replacer.add(rule17) pattern18 = Pattern(UtilityOperator(ArcTan(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule18 = ReplacementRule(pattern18, lambda x, u, a : RectifyCotangent(u, a, S(1), x)) replacer.add(rule18) pattern19 = Pattern(UtilityOperator(ArcTan(Mul(Coth(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda u: ComplexFreeQ(u))) rule19 = ReplacementRule(pattern19, lambda x, u, a : Mul(S(1), SimplifyAntiderivative(ArcTan(Mul(Tanh(u), Pow(a, S(1)))), x))) replacer.add(rule19) pattern20 = Pattern(UtilityOperator(ArcCoth(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule20 = ReplacementRule(pattern20, lambda x, u, a : RectifyCotangent(u, Mul(I, a), I, x)) replacer.add(rule20) pattern21 = Pattern(UtilityOperator(ArcTanh(Mul(Cot(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda a: PositiveQ(Pow(a, S(2)))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule21 = ReplacementRule(pattern21, lambda x, u, a : RectifyCotangent(u, Mul(I, a), I, x)) replacer.add(rule21) pattern22 = Pattern(UtilityOperator(ArcCoth(Coth(u_)), x_)) rule22 = ReplacementRule(pattern22, lambda x, u : SimplifyAntiderivative(u, x)) replacer.add(rule22) pattern23 = Pattern(UtilityOperator(ArcTanh(Mul(Coth(u_), WC('a', S(1)))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda u: ComplexFreeQ(u))) rule23 = ReplacementRule(pattern23, lambda x, u, a : SimplifyAntiderivative(ArcTanh(Mul(Tanh(u), Pow(a, S(1)))), x)) replacer.add(rule23) pattern24 = Pattern(UtilityOperator(ArcTanh(Coth(u_)), x_)) rule24 = ReplacementRule(pattern24, lambda x, u : SimplifyAntiderivative(u, x)) replacer.add(rule24) pattern25 = Pattern(UtilityOperator(ArcTan(Mul(WC('c', S(1)), Add(a_, Mul(WC('b', S(1)), Tan(u_))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule25 = ReplacementRule(pattern25, lambda x, a, b, u, c : RectifyTangent(u, Mul(a, c), Mul(b, c), S(1), x)) replacer.add(rule25) pattern26 = Pattern(UtilityOperator(ArcTanh(Mul(WC('c', S(1)), Add(a_, Mul(WC('b', S(1)), Tan(u_))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule26 = ReplacementRule(pattern26, lambda x, a, b, u, c : RectifyTangent(u, Mul(I, a, c), Mul(I, b, c), Mul(S(1), I), x)) replacer.add(rule26) pattern27 = Pattern(UtilityOperator(ArcTan(Mul(WC('c', S(1)), Add(Mul(Cot(u_), WC('b', S(1))), a_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule27 = ReplacementRule(pattern27, lambda x, a, b, u, c : RectifyCotangent(u, Mul(a, c), Mul(b, c), S(1), x)) replacer.add(rule27) pattern28 = Pattern(UtilityOperator(ArcTanh(Mul(WC('c', S(1)), Add(Mul(Cot(u_), WC('b', S(1))), a_))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda c, a: PositiveQ(Mul(Pow(a, S(2)), Pow(c, S(2))))), CustomConstraint(lambda c, b: PositiveQ(Mul(Pow(b, S(2)), Pow(c, S(2))))), CustomConstraint(lambda u: ComplexFreeQ(u))) rule28 = ReplacementRule(pattern28, lambda x, a, b, u, c : RectifyCotangent(u, Mul(I, a, c), Mul(I, b, c), Mul(S(1), I), x)) replacer.add(rule28) pattern29 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('b', S(1)), Tan(u_)), Mul(WC('c', S(1)), Pow(Tan(u_), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u))) rule29 = ReplacementRule(pattern29, lambda x, a, b, u, c : If(EvenQ(Denominator(NumericFactor(Together(u)))), ArcTan(NormalizeTogether(Mul(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u))), Mul(b, Sin(Mul(S(2), u)))), Pow(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u))), Mul(b, Sin(Mul(S(2), u)))), S(1))))), ArcTan(NormalizeTogether(Mul(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2))), Mul(b, Cos(u), Sin(u))), Pow(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2))), Mul(b, Cos(u), Sin(u))), S(1))))))) replacer.add(rule29) pattern30 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('b', S(1)), Add(WC('d', S(0)), Mul(WC('e', S(1)), Tan(u_)))), Mul(WC('c', S(1)), Pow(Add(WC('f', S(0)), Mul(WC('g', S(1)), Tan(u_))), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda b, x: FreeQ(b, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u))) rule30 = ReplacementRule(pattern30, lambda x, d, a, e, f, b, u, c, g : SimplifyAntiderivative(ArcTan(Add(a, Mul(b, d), Mul(c, Pow(f, S(2))), Mul(Add(Mul(b, e), Mul(S(2), c, f, g)), Tan(u)), Mul(c, Pow(g, S(2)), Pow(Tan(u), S(2))))), x)) replacer.add(rule30) pattern31 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(Tan(u_), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u))) rule31 = ReplacementRule(pattern31, lambda x, c, u, a : If(EvenQ(Denominator(NumericFactor(Together(u)))), ArcTan(NormalizeTogether(Mul(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u)))), Pow(Add(a, c, S(1), Mul(Add(a, Mul(S(1), c), S(1)), Cos(Mul(S(2), u)))), S(1))))), ArcTan(NormalizeTogether(Mul(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2)))), Pow(Add(c, Mul(Add(a, Mul(S(1), c), S(1)), Pow(Cos(u), S(2)))), S(1))))))) replacer.add(rule31) pattern32 = Pattern(UtilityOperator(ArcTan(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(Add(WC('f', S(0)), Mul(WC('g', S(1)), Tan(u_))), S(2))))), x_), CustomConstraint(lambda a, x: FreeQ(a, x)), CustomConstraint(lambda c, x: FreeQ(c, x)), CustomConstraint(lambda u: ComplexFreeQ(u))) rule32 = ReplacementRule(pattern32, lambda x, a, f, u, c, g : SimplifyAntiderivative(ArcTan(Add(a, Mul(c, Pow(f, S(2))), Mul(Mul(S(2), c, f, g), Tan(u)), Mul(c, Pow(g, S(2)), Pow(Tan(u), S(2))))), x)) replacer.add(rule32) return replacer @doctest_depends_on(modules=('matchpy',)) def SimplifyAntiderivative(expr, x): r = SimplifyAntiderivative_replacer.replace(UtilityOperator(expr, x)) if isinstance(r, UtilityOperator): if ProductQ(expr): u, c = S(1), S(1) for i in expr.args: if FreeQ(i, x): c *= i else: u *= i if FreeQ(c, x) and c != S(1): v = SimplifyAntiderivative(u, x) if SumQ(v) and NonsumQ(u): return Add(*[c*i for i in v.args]) return c*v elif LogQ(expr): F = expr.args[0] if MemberQ([cot, sec, csc, coth, sech, csch], Head(F)): return -SimplifyAntiderivative(Log(1/F), x) if MemberQ([Log, atan, acot], Head(expr)): F = Head(expr) G = expr.args[0] if MemberQ([cot, sec, csc, coth, sech, csch], Head(G)): return -SimplifyAntiderivative(F(1/G), x) if MemberQ([atanh, acoth], Head(expr)): F = Head(expr) G = expr.args[0] if MemberQ([cot, sec, csc, coth, sech, csch], Head(G)): return SimplifyAntiderivative(F(1/G), x) u = expr if FreeQ(u, x): return S(0) elif LogQ(u): return Log(RemoveContent(u.args[0], x)) elif SumQ(u): return SimplifyAntiderivativeSum(Add(*[SimplifyAntiderivative(i, x) for i in u.args]), x) return u else: return r @doctest_depends_on(modules=('matchpy',)) def _TrigSimplifyAux(): replacer = ManyToOneReplacer() pattern1 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(WC('a', S(1)), Pow(v_, WC('m', S(1)))), Mul(WC('b', S(1)), Pow(v_, WC('n', S(1))))), p_))), CustomConstraint(lambda v: InertTrigQ(v)), CustomConstraint(lambda p: IntegerQ(p)), CustomConstraint(lambda n, m: RationalQ(m, n)), CustomConstraint(lambda n, m: Less(m, n))) rule1 = ReplacementRule(pattern1, lambda n, a, p, m, u, v, b : Mul(u, Pow(v, Mul(m, p)), Pow(TrigSimplifyAux(Add(a, Mul(b, Pow(v, Add(n, Mul(S(-1), m)))))), p))) replacer.add(rule1) pattern2 = Pattern(UtilityOperator(Add(Mul(Pow(cos(u_), S('2')), WC('a', S(1))), WC('v', S(0)), Mul(WC('b', S(1)), Pow(sin(u_), S('2'))))), CustomConstraint(lambda b, a: SameQ(a, b))) rule2 = ReplacementRule(pattern2, lambda u, v, b, a : Add(a, v)) replacer.add(rule2) pattern3 = Pattern(UtilityOperator(Add(WC('v', S(0)), Mul(WC('a', S(1)), Pow(sec(u_), S('2'))), Mul(WC('b', S(1)), Pow(tan(u_), S('2'))))), CustomConstraint(lambda b, a: SameQ(a, Mul(S(-1), b)))) rule3 = ReplacementRule(pattern3, lambda u, v, b, a : Add(a, v)) replacer.add(rule3) pattern4 = Pattern(UtilityOperator(Add(Mul(Pow(csc(u_), S('2')), WC('a', S(1))), Mul(Pow(cot(u_), S('2')), WC('b', S(1))), WC('v', S(0)))), CustomConstraint(lambda b, a: SameQ(a, Mul(S(-1), b)))) rule4 = ReplacementRule(pattern4, lambda u, v, b, a : Add(a, v)) replacer.add(rule4) pattern5 = Pattern(UtilityOperator(Pow(Add(Mul(Pow(cos(u_), S('2')), WC('a', S(1))), WC('v', S(0)), Mul(WC('b', S(1)), Pow(sin(u_), S('2')))), n_))) rule5 = ReplacementRule(pattern5, lambda n, a, u, v, b : Pow(Add(Mul(Add(b, Mul(S(-1), a)), Pow(Sin(u), S('2'))), a, v), n)) replacer.add(rule5) pattern6 = Pattern(UtilityOperator(Add(WC('w', S(0)), u_, Mul(WC('v', S(1)), Pow(sin(z_), S('2'))))), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v)))) rule6 = ReplacementRule(pattern6, lambda u, w, z, v : Add(Mul(u, Pow(Cos(z), S('2'))), w)) replacer.add(rule6) pattern7 = Pattern(UtilityOperator(Add(Mul(Pow(cos(z_), S('2')), WC('v', S(1))), WC('w', S(0)), u_)), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v)))) rule7 = ReplacementRule(pattern7, lambda z, w, v, u : Add(Mul(u, Pow(Sin(z), S('2'))), w)) replacer.add(rule7) pattern8 = Pattern(UtilityOperator(Add(WC('w', S(0)), u_, Mul(WC('v', S(1)), Pow(tan(z_), S('2'))))), CustomConstraint(lambda u, v: SameQ(u, v))) rule8 = ReplacementRule(pattern8, lambda u, w, z, v : Add(Mul(u, Pow(Sec(z), S('2'))), w)) replacer.add(rule8) pattern9 = Pattern(UtilityOperator(Add(Mul(Pow(cot(z_), S('2')), WC('v', S(1))), WC('w', S(0)), u_)), CustomConstraint(lambda u, v: SameQ(u, v))) rule9 = ReplacementRule(pattern9, lambda z, w, v, u : Add(Mul(u, Pow(Csc(z), S('2'))), w)) replacer.add(rule9) pattern10 = Pattern(UtilityOperator(Add(WC('w', S(0)), u_, Mul(WC('v', S(1)), Pow(sec(z_), S('2'))))), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v)))) rule10 = ReplacementRule(pattern10, lambda u, w, z, v : Add(Mul(v, Pow(Tan(z), S('2'))), w)) replacer.add(rule10) pattern11 = Pattern(UtilityOperator(Add(Mul(Pow(csc(z_), S('2')), WC('v', S(1))), WC('w', S(0)), u_)), CustomConstraint(lambda u, v: SameQ(u, Mul(S(-1), v)))) rule11 = ReplacementRule(pattern11, lambda z, w, v, u : Add(Mul(v, Pow(Cot(z), S('2'))), w)) replacer.add(rule11) pattern12 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(cos(v_), WC('b', S(1))), a_), S(-1)), Pow(sin(v_), S('2')))), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S('2')), Mul(S(-1), Pow(b, S('2'))))))) rule12 = ReplacementRule(pattern12, lambda u, v, b, a : Mul(u, Add(Mul(S(1), Pow(a, S(-1))), Mul(S(-1), Mul(Cos(v), Pow(b, S(-1))))))) replacer.add(rule12) pattern13 = Pattern(UtilityOperator(Mul(Pow(cos(v_), S('2')), WC('u', S(1)), Pow(Add(a_, Mul(WC('b', S(1)), sin(v_))), S(-1)))), CustomConstraint(lambda b, a: ZeroQ(Add(Pow(a, S('2')), Mul(S(-1), Pow(b, S('2'))))))) rule13 = ReplacementRule(pattern13, lambda u, v, b, a : Mul(u, Add(Mul(S(1), Pow(a, S(-1))), Mul(S(-1), Mul(Sin(v), Pow(b, S(-1))))))) replacer.add(rule13) pattern14 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(tan(v_), WC('n', S(1))), Pow(Add(a_, Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a))) rule14 = ReplacementRule(pattern14, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Cot(v), n))), S(-1)))) replacer.add(rule14) pattern15 = Pattern(UtilityOperator(Mul(Pow(cot(v_), WC('n', S(1))), WC('u', S(1)), Pow(Add(Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1))), a_), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a))) rule15 = ReplacementRule(pattern15, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Tan(v), n))), S(-1)))) replacer.add(rule15) pattern16 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(sec(v_), WC('n', S(1))), Pow(Add(a_, Mul(WC('b', S(1)), Pow(sec(v_), WC('n', S(1))))), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a))) rule16 = ReplacementRule(pattern16, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Cos(v), n))), S(-1)))) replacer.add(rule16) pattern17 = Pattern(UtilityOperator(Mul(Pow(csc(v_), WC('n', S(1))), WC('u', S(1)), Pow(Add(Mul(Pow(csc(v_), WC('n', S(1))), WC('b', S(1))), a_), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a))) rule17 = ReplacementRule(pattern17, lambda n, a, u, v, b : Mul(u, Pow(Add(b, Mul(a, Pow(Sin(v), n))), S(-1)))) replacer.add(rule17) pattern18 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(a_, Mul(WC('b', S(1)), Pow(sec(v_), WC('n', S(1))))), S(-1)), Pow(tan(v_), WC('n', S(1))))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a))) rule18 = ReplacementRule(pattern18, lambda n, a, u, v, b : Mul(u, Mul(Pow(Sin(v), n), Pow(Add(b, Mul(a, Pow(Cos(v), n))), S(-1))))) replacer.add(rule18) pattern19 = Pattern(UtilityOperator(Mul(Pow(cot(v_), WC('n', S(1))), WC('u', S(1)), Pow(Add(Mul(Pow(csc(v_), WC('n', S(1))), WC('b', S(1))), a_), S(-1)))), CustomConstraint(lambda n: PositiveIntegerQ(n)), CustomConstraint(lambda a: NonsumQ(a))) rule19 = ReplacementRule(pattern19, lambda n, a, u, v, b : Mul(u, Mul(Pow(Cos(v), n), Pow(Add(b, Mul(a, Pow(Sin(v), n))), S(-1))))) replacer.add(rule19) pattern20 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(WC('a', S(1)), Pow(sec(v_), WC('n', S(1)))), Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p: IntegersQ(n, p))) rule20 = ReplacementRule(pattern20, lambda n, a, p, u, v, b : Mul(u, Pow(Sec(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Sin(v), n))), p))) replacer.add(rule20) pattern21 = Pattern(UtilityOperator(Mul(Pow(Add(Mul(Pow(csc(v_), WC('n', S(1))), WC('a', S(1))), Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1)))), WC('p', S(1))), WC('u', S(1)))), CustomConstraint(lambda n, p: IntegersQ(n, p))) rule21 = ReplacementRule(pattern21, lambda n, a, p, u, v, b : Mul(u, Pow(Csc(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Cos(v), n))), p))) replacer.add(rule21) pattern22 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(WC('b', S(1)), Pow(sin(v_), WC('n', S(1)))), Mul(WC('a', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p: IntegersQ(n, p))) rule22 = ReplacementRule(pattern22, lambda n, a, p, u, v, b : Mul(u, Pow(Tan(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Cos(v), n))), p))) replacer.add(rule22) pattern23 = Pattern(UtilityOperator(Mul(Pow(Add(Mul(Pow(cot(v_), WC('n', S(1))), WC('a', S(1))), Mul(Pow(cos(v_), WC('n', S(1))), WC('b', S(1)))), WC('p', S(1))), WC('u', S(1)))), CustomConstraint(lambda n, p: IntegersQ(n, p))) rule23 = ReplacementRule(pattern23, lambda n, a, p, u, v, b : Mul(u, Pow(Cot(v), Mul(n, p)), Pow(Add(a, Mul(b, Pow(Sin(v), n))), p))) replacer.add(rule23) pattern24 = Pattern(UtilityOperator(Mul(Pow(cos(v_), WC('m', S(1))), WC('u', S(1)), Pow(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(sec(v_), WC('n', S(1)))), Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p))) rule24 = ReplacementRule(pattern24, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Cos(v), Add(m, Mul(S(-1), Mul(n, p)))), Pow(Add(c, Mul(b, Pow(Sin(v), n)), Mul(a, Pow(Cos(v), n))), p))) replacer.add(rule24) pattern25 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(sec(v_), WC('m', S(1))), Pow(Add(WC('a', S(0)), Mul(WC('c', S(1)), Pow(sec(v_), WC('n', S(1)))), Mul(WC('b', S(1)), Pow(tan(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p))) rule25 = ReplacementRule(pattern25, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Sec(v), Add(m, Mul(n, p))), Pow(Add(c, Mul(b, Pow(Sin(v), n)), Mul(a, Pow(Cos(v), n))), p))) replacer.add(rule25) pattern26 = Pattern(UtilityOperator(Mul(Pow(Add(WC('a', S(0)), Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1))), Mul(Pow(csc(v_), WC('n', S(1))), WC('c', S(1)))), WC('p', S(1))), WC('u', S(1)), Pow(sin(v_), WC('m', S(1))))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p))) rule26 = ReplacementRule(pattern26, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Sin(v), Add(m, Mul(S(-1), Mul(n, p)))), Pow(Add(c, Mul(b, Pow(Cos(v), n)), Mul(a, Pow(Sin(v), n))), p))) replacer.add(rule26) pattern27 = Pattern(UtilityOperator(Mul(Pow(csc(v_), WC('m', S(1))), Pow(Add(WC('a', S(0)), Mul(Pow(cot(v_), WC('n', S(1))), WC('b', S(1))), Mul(Pow(csc(v_), WC('n', S(1))), WC('c', S(1)))), WC('p', S(1))), WC('u', S(1)))), CustomConstraint(lambda n, p, m: IntegersQ(m, n, p))) rule27 = ReplacementRule(pattern27, lambda n, a, c, p, m, u, v, b : Mul(u, Pow(Csc(v), Add(m, Mul(n, p))), Pow(Add(c, Mul(b, Pow(Cos(v), n)), Mul(a, Pow(Sin(v), n))), p))) replacer.add(rule27) pattern28 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(Pow(csc(v_), WC('m', S(1))), WC('a', S(1))), Mul(WC('b', S(1)), Pow(sin(v_), WC('n', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, m: IntegersQ(m, n))) rule28 = ReplacementRule(pattern28, lambda n, a, p, m, u, v, b : If(And(ZeroQ(Add(m, n, S(-2))), ZeroQ(Add(a, b))), Mul(u, Pow(Mul(a, Mul(Pow(Cos(v), S('2')), Pow(Pow(Sin(v), m), S(-1)))), p)), Mul(u, Pow(Mul(Add(a, Mul(b, Pow(Sin(v), Add(m, n)))), Pow(Pow(Sin(v), m), S(-1))), p)))) replacer.add(rule28) pattern29 = Pattern(UtilityOperator(Mul(WC('u', S(1)), Pow(Add(Mul(Pow(cos(v_), WC('n', S(1))), WC('b', S(1))), Mul(WC('a', S(1)), Pow(sec(v_), WC('m', S(1))))), WC('p', S(1))))), CustomConstraint(lambda n, m: IntegersQ(m, n))) rule29 = ReplacementRule(pattern29, lambda n, a, p, m, u, v, b : If(And(ZeroQ(Add(m, n, S(-2))), ZeroQ(Add(a, b))), Mul(u, Pow(Mul(a, Mul(Pow(Sin(v), S('2')), Pow(Pow(Cos(v), m), S(-1)))), p)), Mul(u, Pow(Mul(Add(a, Mul(b, Pow(Cos(v), Add(m, n)))), Pow(Pow(Cos(v), m), S(-1))), p)))) replacer.add(rule29) pattern30 = Pattern(UtilityOperator(u_)) rule30 = ReplacementRule(pattern30, lambda u : u) replacer.add(rule30) return replacer @doctest_depends_on(modules=('matchpy',)) def TrigSimplifyAux(expr): return TrigSimplifyAux_replacer.replace(UtilityOperator(expr)) def Cancel(expr): return cancel(expr) class Util_Part(Function): def doit(self): i = Simplify(self.args[0]) if len(self.args) > 2 : lst = list(self.args[1:]) else: lst = self.args[1] if isinstance(i, (int, Integer)): if isinstance(lst, list): return lst[i - 1] elif AtomQ(lst): return lst return lst.args[i - 1] else: return self def Part(lst, i): #see i = -1 if isinstance(lst, list): return Util_Part(i, *lst).doit() return Util_Part(i, lst).doit() def PolyLog(n, p, z=None): return polylog(n, p) def D(f, x): try: return f.diff(x) except ValueError: return Function('D')(f, x) def IntegralFreeQ(u): return FreeQ(u, Integral) def Dist(u, v, x): #Dist(u,v) returns the sum of u times each term of v, provided v is free of Int u = replace_pow_exp(u) # to replace back to sympy's exp v = replace_pow_exp(v) w = Simp(u*x**2, x)/x**2 if u == 1: return v elif u == 0: return 0 elif NumericFactor(u) < 0 and NumericFactor(-u) > 0: return -Dist(-u, v, x) elif SumQ(v): return Add(*[Dist(u, i, x) for i in v.args]) elif IntegralFreeQ(v): return Simp(u*v, x) elif w != u and FreeQ(w, x) and w == Simp(w, x) and w == Simp(w*x**2, x)/x**2: return Dist(w, v, x) else: return Simp(u*v, x) def PureFunctionOfCothQ(u, v, x): # If u is a pure function of Coth[v], PureFunctionOfCothQ[u,v,x] returns True; if AtomQ(u): return u != x elif CalculusQ(u): return False elif HyperbolicQ(u) and ZeroQ(u.args[0] - v): return CothQ(u) return all(PureFunctionOfCothQ(i, v, x) for i in u.args) def LogIntegral(z): return li(z) def ExpIntegralEi(z): return Ei(z) def ExpIntegralE(a, b): return expint(a, b).evalf() def SinIntegral(z): return Si(z) def CosIntegral(z): return Ci(z) def SinhIntegral(z): return Shi(z) def CoshIntegral(z): return Chi(z) class PolyGamma(Function): @classmethod def eval(cls, *args): if len(args) == 2: return polygamma(args[0], args[1]) return digamma(args[0]) def LogGamma(z): return loggamma(z) class ProductLog(Function): @classmethod def eval(cls, *args): if len(args) == 2: return LambertW(args[1], args[0]).evalf() return LambertW(args[0]).evalf() def Factorial(a): return factorial(a) def Zeta(*args): return zeta(*args) def HypergeometricPFQ(a, b, c): return hyper(a, b, c) def Sum_doit(exp, args): """ This function perform summation using sympy's `Sum`. Examples ======== >>> from sympy.integrals.rubi.utility_function import Sum_doit >>> from sympy.abc import x >>> Sum_doit(2*x + 2, [x, 0, 1.7]) 6 """ exp = replace_pow_exp(exp) if not isinstance(args[2], (int, Integer)): new_args = [args[0], args[1], Floor(args[2])] return Sum(exp, new_args).doit() return Sum(exp, args).doit() def PolynomialQuotient(p, q, x): try: p = poly(p, x) q = poly(q, x) except: p = poly(p) q = poly(q) try: return quo(p, q).as_expr() except (PolynomialDivisionFailed, UnificationFailed): return p/q def PolynomialRemainder(p, q, x): try: p = poly(p, x) q = poly(q, x) except: p = poly(p) q = poly(q) try: return rem(p, q).as_expr() except (PolynomialDivisionFailed, UnificationFailed): return S(0) def Floor(x, a = None): if a is None: return floor(x) return a*floor(x/a) def Factor(var): return factor(var) def Rule(a, b): return {a: b} def Distribute(expr, *args): if len(args) == 1: if isinstance(expr, args[0]): return expr else: return expr.expand() if len(args) == 2: if isinstance(expr, args[1]): return expr.expand() else: return expr return expr.expand() def CoprimeQ(*args): args = S(args) g = gcd(*args) if g == 1: return True return False def Discriminant(a, b): try: return discriminant(a, b) except PolynomialError: return Function('Discriminant')(a, b) def Negative(x): return x < S(0) def Quotient(m, n): return Floor(m/n) def process_trig(expr): """ This function processes trigonometric expressions such that all `cot` is rewritten in terms of `tan`, `sec` in terms of `cos`, `csc` in terms of `sin` and similarly for `coth`, `sech` and `csch`. Examples ======== >>> from sympy.integrals.rubi.utility_function import process_trig >>> from sympy.abc import x >>> from sympy import coth, cot, csc >>> process_trig(x*cot(x)) x/tan(x) >>> process_trig(coth(x)*csc(x)) 1/(sin(x)*tanh(x)) """ expr = expr.replace(lambda x: isinstance(x, cot), lambda x: 1/tan(x.args[0])) expr = expr.replace(lambda x: isinstance(x, sec), lambda x: 1/cos(x.args[0])) expr = expr.replace(lambda x: isinstance(x, csc), lambda x: 1/sin(x.args[0])) expr = expr.replace(lambda x: isinstance(x, coth), lambda x: 1/tanh(x.args[0])) expr = expr.replace(lambda x: isinstance(x, sech), lambda x: 1/cosh(x.args[0])) expr = expr.replace(lambda x: isinstance(x, csch), lambda x: 1/sinh(x.args[0])) return expr def _ExpandIntegrand(): Plus = Add Times = Mul def cons_f1(m): return PositiveIntegerQ(m) cons1 = CustomConstraint(cons_f1) def cons_f2(d, c, b, a): return ZeroQ(-a*d + b*c) cons2 = CustomConstraint(cons_f2) def cons_f3(a, x): return FreeQ(a, x) cons3 = CustomConstraint(cons_f3) def cons_f4(b, x): return FreeQ(b, x) cons4 = CustomConstraint(cons_f4) def cons_f5(c, x): return FreeQ(c, x) cons5 = CustomConstraint(cons_f5) def cons_f6(d, x): return FreeQ(d, x) cons6 = CustomConstraint(cons_f6) def cons_f7(e, x): return FreeQ(e, x) cons7 = CustomConstraint(cons_f7) def cons_f8(f, x): return FreeQ(f, x) cons8 = CustomConstraint(cons_f8) def cons_f9(g, x): return FreeQ(g, x) cons9 = CustomConstraint(cons_f9) def cons_f10(h, x): return FreeQ(h, x) cons10 = CustomConstraint(cons_f10) def cons_f11(e, b, c, f, n, p, F, x, d, m): if not isinstance(x, Symbol): return False return FreeQ(List(F, b, c, d, e, f, m, n, p), x) cons11 = CustomConstraint(cons_f11) def cons_f12(F, x): return FreeQ(F, x) cons12 = CustomConstraint(cons_f12) def cons_f13(m, x): return FreeQ(m, x) cons13 = CustomConstraint(cons_f13) def cons_f14(n, x): return FreeQ(n, x) cons14 = CustomConstraint(cons_f14) def cons_f15(p, x): return FreeQ(p, x) cons15 = CustomConstraint(cons_f15) def cons_f16(e, b, c, f, n, a, p, F, x, d, m): if not isinstance(x, Symbol): return False return FreeQ(List(F, a, b, c, d, e, f, m, n, p), x) cons16 = CustomConstraint(cons_f16) def cons_f17(n, m): return IntegersQ(m, n) cons17 = CustomConstraint(cons_f17) def cons_f18(n): return Less(n, S(0)) cons18 = CustomConstraint(cons_f18) def cons_f19(x, u): if not isinstance(x, Symbol): return False return PolynomialQ(u, x) cons19 = CustomConstraint(cons_f19) def cons_f20(G, F, u): return SameQ(F(u)*G(u), S(1)) cons20 = CustomConstraint(cons_f20) def cons_f21(q, x): return FreeQ(q, x) cons21 = CustomConstraint(cons_f21) def cons_f22(F): return MemberQ(List(ArcSin, ArcCos, ArcSinh, ArcCosh), F) cons22 = CustomConstraint(cons_f22) def cons_f23(j, n): return ZeroQ(j - S(2)*n) cons23 = CustomConstraint(cons_f23) def cons_f24(A, x): return FreeQ(A, x) cons24 = CustomConstraint(cons_f24) def cons_f25(B, x): return FreeQ(B, x) cons25 = CustomConstraint(cons_f25) def cons_f26(m, u, x): if not isinstance(x, Symbol): return False def _cons_f_u(d, w, c, p, x): return And(FreeQ(List(c, d), x), IntegerQ(p), Greater(p, m)) cons_u = CustomConstraint(_cons_f_u) pat = Pattern(UtilityOperator((c_ + x_*WC('d', S(1)))**p_*WC('w', S(1)), x_), cons_u) result_matchq = is_match(UtilityOperator(u, x), pat) return Not(And(PositiveIntegerQ(m), result_matchq)) cons26 = CustomConstraint(cons_f26) def cons_f27(b, v, n, a, x, u, m): if not isinstance(x, Symbol): return False return And(FreeQ(List(a, b, m), x), NegativeIntegerQ(n), Not(IntegerQ(m)), PolynomialQ(u, x), PolynomialQ(v, x),\ RationalQ(m), Less(m, -1), GreaterEqual(Exponent(u, x), (-n - IntegerPart(m))*Exponent(v, x))) cons27 = CustomConstraint(cons_f27) def cons_f28(v, n, x, u, m): if not isinstance(x, Symbol): return False return And(FreeQ(List(a, b, m), x), NegativeIntegerQ(n), Not(IntegerQ(m)), PolynomialQ(u, x),\ PolynomialQ(v, x), GreaterEqual(Exponent(u, x), -n*Exponent(v, x))) cons28 = CustomConstraint(cons_f28) def cons_f29(n): return PositiveIntegerQ(n/S(4)) cons29 = CustomConstraint(cons_f29) def cons_f30(n): return IntegerQ(n) cons30 = CustomConstraint(cons_f30) def cons_f31(n): return Greater(n, S(1)) cons31 = CustomConstraint(cons_f31) def cons_f32(n, m): return Less(S(0), m, n) cons32 = CustomConstraint(cons_f32) def cons_f33(n, m): return OddQ(n/GCD(m, n)) cons33 = CustomConstraint(cons_f33) def cons_f34(a, b): return PosQ(a/b) cons34 = CustomConstraint(cons_f34) def cons_f35(n, m, p): return IntegersQ(m, n, p) cons35 = CustomConstraint(cons_f35) def cons_f36(n, m, p): return Less(S(0), m, p, n) cons36 = CustomConstraint(cons_f36) def cons_f37(q, n, m, p): return IntegersQ(m, n, p, q) cons37 = CustomConstraint(cons_f37) def cons_f38(n, q, m, p): return Less(S(0), m, p, q, n) cons38 = CustomConstraint(cons_f38) def cons_f39(n): return IntegerQ(n/S(2)) cons39 = CustomConstraint(cons_f39) def cons_f40(p): return NegativeIntegerQ(p) cons40 = CustomConstraint(cons_f40) def cons_f41(n, m): return IntegersQ(m, n/S(2)) cons41 = CustomConstraint(cons_f41) def cons_f42(n, m): return Unequal(m, n/S(2)) cons42 = CustomConstraint(cons_f42) def cons_f43(c, b, a): return NonzeroQ(-S(4)*a*c + b**S(2)) cons43 = CustomConstraint(cons_f43) def cons_f44(j, n, m): return IntegersQ(m, n, j) cons44 = CustomConstraint(cons_f44) def cons_f45(n, m): return Less(S(0), m, S(2)*n) cons45 = CustomConstraint(cons_f45) def cons_f46(n, m, p): return Not(And(Equal(m, n), Equal(p, S(-1)))) cons46 = CustomConstraint(cons_f46) def cons_f47(v, x): if not isinstance(x, Symbol): return False return PolynomialQ(v, x) cons47 = CustomConstraint(cons_f47) def cons_f48(v, x): if not isinstance(x, Symbol): return False return BinomialQ(v, x) cons48 = CustomConstraint(cons_f48) def cons_f49(v, x, u): if not isinstance(x, Symbol): return False return Inequality(Exponent(u, x), Equal, Exponent(v, x) + S(-1), GreaterEqual, S(2)) cons49 = CustomConstraint(cons_f49) def cons_f50(v, x, u): if not isinstance(x, Symbol): return False return GreaterEqual(Exponent(u, x), Exponent(v, x)) cons50 = CustomConstraint(cons_f50) def cons_f51(p): return Not(IntegerQ(p)) cons51 = CustomConstraint(cons_f51) def With2(e, b, c, f, n, a, g, h, x, d, m): tmp = a*h - b*g k = Symbol('k') return f**(e*(c + d*x)**n)*SimplifyTerm(h**(-m)*tmp**m, x)/(g + h*x) + Sum_doit(f**(e*(c + d*x)**n)*(a + b*x)**(-k + m)*SimplifyTerm(b*h**(-k)*tmp**(k - 1), x), List(k, 1, m)) pattern2 = Pattern(UtilityOperator(f_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('e', S(1)))*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))/(x_*WC('h', S(1)) + WC('g', S(0))), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons9, cons10, cons1, cons2) rule2 = ReplacementRule(pattern2, With2) pattern3 = Pattern(UtilityOperator(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('b', S(1)))*x_**WC('m', S(1))*(e_ + x_*WC('f', S(1)))**WC('p', S(1)), x_), cons12, cons4, cons5, cons6, cons7, cons8, cons13, cons14, cons15, cons11) def replacement3(e, b, c, f, n, p, F, x, d, m): return If(And(PositiveIntegerQ(m, p), LessEqual(m, p), Or(EqQ(n, S(1)), ZeroQ(-c*f + d*e))), ExpandLinearProduct(F**(b*(c + d*x)**n)*(e + f*x)**p, x**m, e, f, x), If(PositiveIntegerQ(p), Distribute(F**(b*(c + d*x)**n)*x**m*(e + f*x)**p, Plus, Times), ExpandIntegrand(F**(b*(c + d*x)**n), x**m*(e + f*x)**p, x))) rule3 = ReplacementRule(pattern3, replacement3) pattern4 = Pattern(UtilityOperator(F_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))*x_**WC('m', S(1))*(e_ + x_*WC('f', S(1)))**WC('p', S(1)), x_), cons12, cons3, cons4, cons5, cons6, cons7, cons8, cons13, cons14, cons15, cons16) def replacement4(e, b, c, f, n, a, p, F, x, d, m): return If(And(PositiveIntegerQ(m, p), LessEqual(m, p), Or(EqQ(n, S(1)), ZeroQ(-c*f + d*e))), ExpandLinearProduct(F**(a + b*(c + d*x)**n)*(e + f*x)**p, x**m, e, f, x), If(PositiveIntegerQ(p), Distribute(F**(a + b*(c + d*x)**n)*x**m*(e + f*x)**p, Plus, Times), ExpandIntegrand(F**(a + b*(c + d*x)**n), x**m*(e + f*x)**p, x))) rule4 = ReplacementRule(pattern4, replacement4) def With5(b, v, c, n, a, F, u, x, d, m): if not isinstance(x, Symbol) or not (FreeQ([F, a, b, c, d], x) and IntegersQ(m, n) and n < 0): return False w = ExpandIntegrand((a + b*x)**m*(c + d*x)**n, x) w = ReplaceAll(w, Rule(x, F**v)) if SumQ(w): return True return False pattern5 = Pattern(UtilityOperator((F_**v_*WC('b', S(1)) + a_)**WC('m', S(1))*(F_**v_*WC('d', S(1)) + c_)**n_*WC('u', S(1)), x_), cons12, cons3, cons4, cons5, cons6, cons17, cons18, CustomConstraint(With5)) def replacement5(b, v, c, n, a, F, u, x, d, m): w = ReplaceAll(ExpandIntegrand((a + b*x)**m*(c + d*x)**n, x), Rule(x, F**v)) return w.func(*[u*i for i in w.args]) rule5 = ReplacementRule(pattern5, replacement5) def With6(e, b, c, f, n, a, x, u, d, m): if not isinstance(x, Symbol) or not (FreeQ([a, b, c, d, e, f, m, n], x) and PolynomialQ(u,x)): return False v = ExpandIntegrand(u*(a + b*x)**m, x) if SumQ(v): return True return False pattern6 = Pattern(UtilityOperator(f_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('e', S(1)))*u_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1)), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons13, cons14, cons19, CustomConstraint(With6)) def replacement6(e, b, c, f, n, a, x, u, d, m): v = ExpandIntegrand(u*(a + b*x)**m, x) return Distribute(f**(e*(c + d*x)**n)*v, Plus, Times) rule6 = ReplacementRule(pattern6, replacement6) pattern7 = Pattern(UtilityOperator(u_*(x_*WC('b', S(1)) + WC('a', S(0)))**WC('m', S(1))*Log((x_**WC('n', S(1))*WC('e', S(1)) + WC('d', S(0)))**WC('p', S(1))*WC('c', S(1))), x_), cons3, cons4, cons5, cons6, cons7, cons13, cons14, cons15, cons19) def replacement7(e, b, c, n, a, p, x, u, d, m): return ExpandIntegrand(Log(c*(d + e*x**n)**p), u*(a + b*x)**m, x) rule7 = ReplacementRule(pattern7, replacement7) pattern8 = Pattern(UtilityOperator(f_**((x_*WC('d', S(1)) + WC('c', S(0)))**WC('n', S(1))*WC('e', S(1)))*u_, x_), cons5, cons6, cons7, cons8, cons14, cons19) def replacement8(e, c, f, n, x, u, d): return If(EqQ(n, S(1)), ExpandIntegrand(f**(e*(c + d*x)**n), u, x), ExpandLinearProduct(f**(e*(c + d*x)**n), u, c, d, x)) rule8 = ReplacementRule(pattern8, replacement8) # pattern9 = Pattern(UtilityOperator(F_**u_*(G_*u_*WC('b', S(1)) + a_)**WC('n', S(1)), x_), cons3, cons4, cons17, cons20) # def replacement9(b, G, n, a, F, u, x, m): # return ReplaceAll(ExpandIntegrand(x**(-m)*(a + b*x)**n, x), Rule(x, G(u))) # rule9 = ReplacementRule(pattern9, replacement9) pattern10 = Pattern(UtilityOperator(u_*(WC('a', S(0)) + WC('b', S(1))*Log(((x_*WC('f', S(1)) + WC('e', S(0)))**WC('p', S(1))*WC('d', S(1)))**WC('q', S(1))*WC('c', S(1))))**n_, x_), cons3, cons4, cons5, cons6, cons7, cons8, cons14, cons15, cons21, cons19) def replacement10(e, b, c, f, n, a, p, x, u, d, q): return ExpandLinearProduct((a + b*Log(c*(d*(e + f*x)**p)**q))**n, u, e, f, x) rule10 = ReplacementRule(pattern10, replacement10) # pattern11 = Pattern(UtilityOperator(u_*(F_*(x_*WC('d', S(1)) + WC('c', S(0)))*WC('b', S(1)) + WC('a', S(0)))**n_, x_), cons3, cons4, cons5, cons6, cons14, cons19, cons22) # def replacement11(b, c, n, a, F, u, x, d): # return ExpandLinearProduct((a + b*F(c + d*x))**n, u, c, d, x) # rule11 = ReplacementRule(pattern11, replacement11) pattern12 = Pattern(UtilityOperator(WC('u', S(1))/(x_**n_*WC('a', S(1)) + sqrt(c_ + x_**j_*WC('d', S(1)))*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons14, cons23) def replacement12(b, c, n, a, x, u, d, j): return ExpandIntegrand(u*(a*x**n - b*sqrt(c + d*x**(S(2)*n)))/(-b**S(2)*c + x**(S(2)*n)*(a**S(2) - b**S(2)*d)), x) rule12 = ReplacementRule(pattern12, replacement12) pattern13 = Pattern(UtilityOperator((a_ + x_*WC('b', S(1)))**m_/(c_ + x_*WC('d', S(1))), x_), cons3, cons4, cons5, cons6, cons1) def replacement13(b, c, a, x, d, m): if RationalQ(a, b, c, d): return ExpandExpression((a + b*x)**m/(c + d*x), x) else: tmp = a*d - b*c k = Symbol("k") return Sum_doit((a + b*x)**(-k + m)*SimplifyTerm(b*d**(-k)*tmp**(k + S(-1)), x), List(k, S(1), m)) + SimplifyTerm(d**(-m)*tmp**m, x)/(c + d*x) rule13 = ReplacementRule(pattern13, replacement13) pattern14 = Pattern(UtilityOperator((A_ + x_*WC('B', S(1)))*(a_ + x_*WC('b', S(1)))**WC('m', S(1))/(c_ + x_*WC('d', S(1))), x_), cons3, cons4, cons5, cons6, cons24, cons25, cons1) def replacement14(b, B, A, c, a, x, d, m): if RationalQ(a, b, c, d, A, B): return ExpandExpression((A + B*x)*(a + b*x)**m/(c + d*x), x) else: tmp1 = (A*d - B*c)/d tmp2 = ExpandIntegrand((a + b*x)**m/(c + d*x), x) tmp2 = If(SumQ(tmp2), tmp2.func(*[SimplifyTerm(tmp1*i, x) for i in tmp2.args]), SimplifyTerm(tmp1*tmp2, x)) return SimplifyTerm(B/d, x)*(a + b*x)**m + tmp2 rule14 = ReplacementRule(pattern14, replacement14) def With15(b, a, x, u, m): tmp1 = ExpandLinearProduct((a + b*x)**m, u, a, b, x) if not IntegerQ(m): return tmp1 else: tmp2 = ExpandExpression(u*(a + b*x)**m, x) if SumQ(tmp2) and LessEqual(LeafCount(tmp2), LeafCount(tmp1) + S(2)): return tmp2 else: return tmp1 pattern15 = Pattern(UtilityOperator(u_*(a_ + x_*WC('b', S(1)))**m_, x_), cons3, cons4, cons13, cons19, cons26) rule15 = ReplacementRule(pattern15, With15) pattern16 = Pattern(UtilityOperator(u_*v_**n_*(a_ + x_*WC('b', S(1)))**m_, x_), cons27) def replacement16(b, v, n, a, x, u, m): s = PolynomialQuotientRemainder(u, v**(-n)*(a+b*x)**(-IntegerPart(m)), x) return ExpandIntegrand((a + b*x)**FractionalPart(m)*s[0], x) + ExpandIntegrand(v**n*(a + b*x)**m*s[1], x) rule16 = ReplacementRule(pattern16, replacement16) pattern17 = Pattern(UtilityOperator(u_*v_**n_*(a_ + x_*WC('b', S(1)))**m_, x_), cons28) def replacement17(b, v, n, a, x, u, m): s = PolynomialQuotientRemainder(u, v**(-n),x) return ExpandIntegrand((a + b*x)**(m)*s[0], x) + ExpandIntegrand(v**n*(a + b*x)**m*s[1], x) rule17 = ReplacementRule(pattern17, replacement17) def With18(b, n, a, x, u): r = Numerator(Rt(-a/b, S(2))) s = Denominator(Rt(-a/b, S(2))) return r/(S(2)*a*(r + s*u**(n/S(2)))) + r/(S(2)*a*(r - s*u**(n/S(2)))) pattern18 = Pattern(UtilityOperator(S(1)/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons29) rule18 = ReplacementRule(pattern18, With18) def With19(b, n, a, x, u): k = Symbol("k") r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) return Sum_doit(r/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n)) pattern19 = Pattern(UtilityOperator(S(1)/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons30, cons31) rule19 = ReplacementRule(pattern19, With19) def With20(b, n, a, x, u, m): k = Symbol("k") g = GCD(m, n) r = Numerator(Rt(a/b, n/GCD(m, n))) s = Denominator(Rt(a/b, n/GCD(m, n))) return If(CoprimeQ(g + m, n), Sum_doit((-1)**(-2*k*m/n)*r*(-r/s)**(m/g)/(a*n*((-1)**(2*g*k/n)*s*u**g + r)), List(k, 1, n/g)), Sum_doit((-1)**(2*k*(g + m)/n)*r*(-r/s)**(m/g)/(a*n*((-1)**(2*g*k/n)*r + s*u**g)), List(k, 1, n/g))) pattern20 = Pattern(UtilityOperator(u_**WC('m', S(1))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons17, cons32, cons33, cons34) rule20 = ReplacementRule(pattern20, With20) def With21(b, n, a, x, u, m): k = Symbol("k") g = GCD(m, n) r = Numerator(Rt(-a/b, n/GCD(m, n))) s = Denominator(Rt(-a/b, n/GCD(m, n))) return If(Equal(n/g, S(2)), s/(S(2)*b*(r + s*u**g)) - s/(S(2)*b*(r - s*u**g)), If(CoprimeQ(g + m, n), Sum_doit((S(-1))**(-S(2)*k*m/n)*r*(r/s)**(m/g)/(a*n*(-(S(-1))**(S(2)*g*k/n)*s*u**g + r)), List(k, S(1), n/g)), Sum_doit((S(-1))**(S(2)*k*(g + m)/n)*r*(r/s)**(m/g)/(a*n*((S(-1))**(S(2)*g*k/n)*r - s*u**g)), List(k, S(1), n/g)))) pattern21 = Pattern(UtilityOperator(u_**WC('m', S(1))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons17, cons32) rule21 = ReplacementRule(pattern21, With21) def With22(b, c, n, a, x, u, d, m): k = Symbol("k") r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) return Sum_doit((c*r + (-1)**(-2*k*m/n)*d*r*(r/s)**m)/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n)) pattern22 = Pattern(UtilityOperator((c_ + u_**WC('m', S(1))*WC('d', S(1)))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons17, cons32) rule22 = ReplacementRule(pattern22, With22) def With23(e, b, c, n, a, p, x, u, d, m): k = Symbol("k") r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) return Sum_doit((c*r + (-1)**(-2*k*p/n)*e*r*(r/s)**p + (-1)**(-2*k*m/n)*d*r*(r/s)**m)/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n)) pattern23 = Pattern(UtilityOperator((u_**p_*WC('e', S(1)) + u_**WC('m', S(1))*WC('d', S(1)) + WC('c', S(0)))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons7, cons35, cons36) rule23 = ReplacementRule(pattern23, With23) def With24(e, b, c, f, n, a, p, x, u, d, q, m): k = Symbol("k") r = Numerator(Rt(-a/b, n)) s = Denominator(Rt(-a/b, n)) return Sum_doit((c*r + (-1)**(-2*k*q/n)*f*r*(r/s)**q + (-1)**(-2*k*p/n)*e*r*(r/s)**p + (-1)**(-2*k*m/n)*d*r*(r/s)**m)/(a*n*(-(-1)**(2*k/n)*s*u + r)), List(k, 1, n)) pattern24 = Pattern(UtilityOperator((u_**p_*WC('e', S(1)) + u_**q_*WC('f', S(1)) + u_**WC('m', S(1))*WC('d', S(1)) + WC('c', S(0)))/(a_ + u_**n_*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons37, cons38) rule24 = ReplacementRule(pattern24, With24) def With25(c, n, a, p, x, u): q = Symbol('q') return ReplaceAll(ExpandIntegrand(c**(-p), (c*x - q)**p*(c*x + q)**p, x), List(Rule(q, Rt(-a*c, S(2))), Rule(x, u**(n/S(2))))) pattern25 = Pattern(UtilityOperator((a_ + u_**WC('n', S(1))*WC('c', S(1)))**p_, x_), cons3, cons5, cons39, cons40) rule25 = ReplacementRule(pattern25, With25) def With26(c, n, a, p, x, u, m): q = Symbol('q') return ReplaceAll(ExpandIntegrand(c**(-p), x**m*(c*x**(n/S(2)) - q)**p*(c*x**(n/S(2)) + q)**p, x), List(Rule(q, Rt(-a*c, S(2))), Rule(x, u))) pattern26 = Pattern(UtilityOperator(u_**WC('m', S(1))*(u_**WC('n', S(1))*WC('c', S(1)) + WC('a', S(0)))**p_, x_), cons3, cons5, cons41, cons40, cons32, cons42) rule26 = ReplacementRule(pattern26, With26) def With27(b, c, n, a, p, x, u, j): q = Symbol('q') return ReplaceAll(ExpandIntegrand(S(4)**(-p)*c**(-p), (b + S(2)*c*x - q)**p*(b + S(2)*c*x + q)**p, x), List(Rule(q, Rt(-S(4)*a*c + b**S(2), S(2))), Rule(x, u**n))) pattern27 = Pattern(UtilityOperator((u_**WC('j', S(1))*WC('c', S(1)) + u_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons3, cons4, cons5, cons30, cons23, cons40, cons43) rule27 = ReplacementRule(pattern27, With27) def With28(b, c, n, a, p, x, u, j, m): q = Symbol('q') return ReplaceAll(ExpandIntegrand(S(4)**(-p)*c**(-p), x**m*(b + S(2)*c*x**n - q)**p*(b + S(2)*c*x**n + q)**p, x), List(Rule(q, Rt(-S(4)*a*c + b**S(2), S(2))), Rule(x, u))) pattern28 = Pattern(UtilityOperator(u_**WC('m', S(1))*(u_**WC('j', S(1))*WC('c', S(1)) + u_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0)))**p_, x_), cons3, cons4, cons5, cons44, cons23, cons40, cons45, cons46, cons43) rule28 = ReplacementRule(pattern28, With28) def With29(b, c, n, a, x, u, d, j): q = Rt(-a/b, S(2)) return -(c - d*q)/(S(2)*b*q*(q + u**n)) - (c + d*q)/(S(2)*b*q*(q - u**n)) pattern29 = Pattern(UtilityOperator((u_**WC('n', S(1))*WC('d', S(1)) + WC('c', S(0)))/(a_ + u_**WC('j', S(1))*WC('b', S(1))), x_), cons3, cons4, cons5, cons6, cons14, cons23) rule29 = ReplacementRule(pattern29, With29) def With30(e, b, c, f, n, a, g, x, u, d, j): q = Rt(-S(4)*a*c + b**S(2), S(2)) r = TogetherSimplify((-b*e*g + S(2)*c*(d + e*f))/q) return (e*g - r)/(b + 2*c*u**n + q) + (e*g + r)/(b + 2*c*u**n - q) pattern30 = Pattern(UtilityOperator(((u_**WC('n', S(1))*WC('g', S(1)) + WC('f', S(0)))*WC('e', S(1)) + WC('d', S(0)))/(u_**WC('j', S(1))*WC('c', S(1)) + u_**WC('n', S(1))*WC('b', S(1)) + WC('a', S(0))), x_), cons3, cons4, cons5, cons6, cons7, cons8, cons9, cons14, cons23, cons43) rule30 = ReplacementRule(pattern30, With30) def With31(v, x, u): lst = CoefficientList(u, x) i = Symbol('i') return x**Exponent(u, x)*lst[-1]/v + Sum_doit(x**(i - 1)*Part(lst, i), List(i, 1, Exponent(u, x)))/v pattern31 = Pattern(UtilityOperator(u_/v_, x_), cons19, cons47, cons48, cons49) rule31 = ReplacementRule(pattern31, With31) pattern32 = Pattern(UtilityOperator(u_/v_, x_), cons19, cons47, cons50) def replacement32(v, x, u): return PolynomialDivide(u, v, x) rule32 = ReplacementRule(pattern32, replacement32) pattern33 = Pattern(UtilityOperator(u_*(x_*WC('a', S(1)))**p_, x_), cons51, cons19) def replacement33(x, a, u, p): return ExpandToSum((a*x)**p, u, x) rule33 = ReplacementRule(pattern33, replacement33) pattern34 = Pattern(UtilityOperator(v_**p_*WC('u', S(1)), x_), cons51) def replacement34(v, x, u, p): return ExpandIntegrand(NormalizeIntegrand(v**p, x), u, x) rule34 = ReplacementRule(pattern34, replacement34) pattern35 = Pattern(UtilityOperator(u_, x_)) def replacement35(x, u): return ExpandExpression(u, x) rule35 = ReplacementRule(pattern35, replacement35) return [ rule2,rule3, rule4, rule5, rule6, rule7, rule8, rule10, rule12, rule13, rule14, rule15, rule16, rule17, rule18, rule19, rule20, rule21, rule22, rule23, rule24, rule25, rule26, rule27, rule28, rule29, rule30, rule31, rule32, rule33, rule34, rule35] def _RemoveContentAux(): def cons_f1(b, a): return IntegersQ(a, b) cons1 = CustomConstraint(cons_f1) def cons_f2(b, a): return Equal(a + b, S(0)) cons2 = CustomConstraint(cons_f2) def cons_f3(m): return RationalQ(m) cons3 = CustomConstraint(cons_f3) def cons_f4(m, n): return RationalQ(m, n) cons4 = CustomConstraint(cons_f4) def cons_f5(m, n): return GreaterEqual(-m + n, S(0)) cons5 = CustomConstraint(cons_f5) def cons_f6(a, x): return FreeQ(a, x) cons6 = CustomConstraint(cons_f6) def cons_f7(m, n, p): return RationalQ(m, n, p) cons7 = CustomConstraint(cons_f7) def cons_f8(m, p): return GreaterEqual(-m + p, S(0)) cons8 = CustomConstraint(cons_f8) pattern1 = Pattern(UtilityOperator(a_**m_*WC('u', S(1)) + b_*WC('v', S(1)), x_), cons1, cons2, cons3) def replacement1(v, x, a, u, m, b): return If(Greater(m, S(1)), RemoveContentAux(a**(m + S(-1))*u - v, x), RemoveContentAux(-a**(-m + S(1))*v + u, x)) rule1 = ReplacementRule(pattern1, replacement1) pattern2 = Pattern(UtilityOperator(a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)), x_), cons6, cons4, cons5) def replacement2(n, v, x, u, m, a): return RemoveContentAux(a**(-m + n)*v + u, x) rule2 = ReplacementRule(pattern2, replacement2) pattern3 = Pattern(UtilityOperator(a_**WC('m', S(1))*WC('u', S(1)) + a_**WC('n', S(1))*WC('v', S(1)) + a_**WC('p', S(1))*WC('w', S(1)), x_), cons6, cons7, cons5, cons8) def replacement3(n, v, x, p, u, w, m, a): return RemoveContentAux(a**(-m + n)*v + a**(-m + p)*w + u, x) rule3 = ReplacementRule(pattern3, replacement3) pattern4 = Pattern(UtilityOperator(u_, x_)) def replacement4(u, x): return If(And(SumQ(u), NegQ(First(u))), -u, u) rule4 = ReplacementRule(pattern4, replacement4) return [rule1, rule2, rule3, rule4, ] IntHide = Int Log = rubi_log Null = None if matchpy: RemoveContentAux_replacer = ManyToOneReplacer(* _RemoveContentAux()) ExpandIntegrand_rules = _ExpandIntegrand() TrigSimplifyAux_replacer = _TrigSimplifyAux() SimplifyAntiderivative_replacer = _SimplifyAntiderivative() SimplifyAntiderivativeSum_replacer = _SimplifyAntiderivativeSum() FixSimplify_rules = _FixSimplify() SimpFixFactor_replacer = _SimpFixFactor() sympy-sympy-1.9/sympy/integrals/singularityfunctions.py000066400000000000000000000044261412543434000237570ustar00rootroot00000000000000from sympy.functions import SingularityFunction, DiracDelta from sympy.core import sympify from sympy.integrals import integrate def singularityintegrate(f, x): """ This function handles the indefinite integrations of Singularity functions. The ``integrate`` function calls this function internally whenever an instance of SingularityFunction is passed as argument. Explanation =========== The idea for integration is the following: - If we are dealing with a SingularityFunction expression, i.e. ``SingularityFunction(x, a, n)``, we just return ``SingularityFunction(x, a, n + 1)/(n + 1)`` if ``n >= 0`` and ``SingularityFunction(x, a, n + 1)`` if ``n < 0``. - If the node is a multiplication or power node having a SingularityFunction term we rewrite the whole expression in terms of Heaviside and DiracDelta and then integrate the output. Lastly, we rewrite the output of integration back in terms of SingularityFunction. - If none of the above case arises, we return None. Examples ======== >>> from sympy.integrals.singularityfunctions import singularityintegrate >>> from sympy import SingularityFunction, symbols, Function >>> x, a, n, y = symbols('x a n y') >>> f = Function('f') >>> singularityintegrate(SingularityFunction(x, a, 3), x) SingularityFunction(x, a, 4)/4 >>> singularityintegrate(5*SingularityFunction(x, 5, -2), x) 5*SingularityFunction(x, 5, -1) >>> singularityintegrate(6*SingularityFunction(x, 5, -1), x) 6*SingularityFunction(x, 5, 0) >>> singularityintegrate(x*SingularityFunction(x, 0, -1), x) 0 >>> singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) f(1)*SingularityFunction(x, 1, 0) """ if not f.has(SingularityFunction): return None if f.func == SingularityFunction: x = sympify(f.args[0]) a = sympify(f.args[1]) n = sympify(f.args[2]) if n.is_positive or n.is_zero: return SingularityFunction(x, a, n + 1)/(n + 1) elif n == -1 or n == -2: return SingularityFunction(x, a, n + 1) if f.is_Mul or f.is_Pow: expr = f.rewrite(DiracDelta) expr = integrate(expr, x) return expr.rewrite(SingularityFunction) return None sympy-sympy-1.9/sympy/integrals/tests/000077500000000000000000000000001412543434000202365ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/tests/__init__.py000066400000000000000000000000001412543434000223350ustar00rootroot00000000000000sympy-sympy-1.9/sympy/integrals/tests/test_deltafunctions.py000066400000000000000000000066471412543434000247060ustar00rootroot00000000000000from sympy import cos, DiracDelta, Heaviside, Function, pi, S, sin, symbols, Rational from sympy.integrals.deltafunctions import change_mul, deltaintegrate f = Function("f") x_1, x_2, x, y, z = symbols("x_1 x_2 x y z") def test_change_mul(): assert change_mul(x, x) == (None, None) assert change_mul(x*y, x) == (None, None) assert change_mul(x*y*DiracDelta(x), x) == (DiracDelta(x), x*y) assert change_mul(x*y*DiracDelta(x)*DiracDelta(y), x) == \ (DiracDelta(x), x*y*DiracDelta(y)) assert change_mul(DiracDelta(x)**2, x) == \ (DiracDelta(x), DiracDelta(x)) assert change_mul(y*DiracDelta(x)**2, x) == \ (DiracDelta(x), y*DiracDelta(x)) def test_deltaintegrate(): assert deltaintegrate(x, x) is None assert deltaintegrate(x + DiracDelta(x), x) is None assert deltaintegrate(DiracDelta(x, 0), x) == Heaviside(x) for n in range(10): assert deltaintegrate(DiracDelta(x, n + 1), x) == DiracDelta(x, n) assert deltaintegrate(DiracDelta(x), x) == Heaviside(x) assert deltaintegrate(DiracDelta(-x), x) == Heaviside(x) assert deltaintegrate(DiracDelta(x - y), x) == Heaviside(x - y) assert deltaintegrate(DiracDelta(y - x), x) == Heaviside(x - y) assert deltaintegrate(x*DiracDelta(x), x) == 0 assert deltaintegrate((x - y)*DiracDelta(x - y), x) == 0 assert deltaintegrate(DiracDelta(x)**2, x) == DiracDelta(0)*Heaviside(x) assert deltaintegrate(y*DiracDelta(x)**2, x) == \ y*DiracDelta(0)*Heaviside(x) assert deltaintegrate(DiracDelta(x, 1), x) == DiracDelta(x, 0) assert deltaintegrate(y*DiracDelta(x, 1), x) == y*DiracDelta(x, 0) assert deltaintegrate(DiracDelta(x, 1)**2, x) == -DiracDelta(0, 2)*Heaviside(x) assert deltaintegrate(y*DiracDelta(x, 1)**2, x) == -y*DiracDelta(0, 2)*Heaviside(x) assert deltaintegrate(DiracDelta(x) * f(x), x) == f(0) * Heaviside(x) assert deltaintegrate(DiracDelta(-x) * f(x), x) == f(0) * Heaviside(x) assert deltaintegrate(DiracDelta(x - 1) * f(x), x) == f(1) * Heaviside(x - 1) assert deltaintegrate(DiracDelta(1 - x) * f(x), x) == f(1) * Heaviside(x - 1) assert deltaintegrate(DiracDelta(x**2 + x - 2), x) == \ Heaviside(x - 1)/3 + Heaviside(x + 2)/3 p = cos(x)*(DiracDelta(x) + DiracDelta(x**2 - 1))*sin(x)*(x - pi) assert deltaintegrate(p, x) - (-pi*(cos(1)*Heaviside(-1 + x)*sin(1)/2 - \ cos(1)*Heaviside(1 + x)*sin(1)/2) + \ cos(1)*Heaviside(1 + x)*sin(1)/2 + \ cos(1)*Heaviside(-1 + x)*sin(1)/2) == 0 p = x_2*DiracDelta(x - x_2)*DiracDelta(x_2 - x_1) assert deltaintegrate(p, x_2) == x*DiracDelta(x - x_1)*Heaviside(x_2 - x) p = x*y**2*z*DiracDelta(y - x)*DiracDelta(y - z)*DiracDelta(x - z) assert deltaintegrate(p, y) == x**3*z*DiracDelta(x - z)**2*Heaviside(y - x) assert deltaintegrate((x + 1)*DiracDelta(2*x), x) == S.Half * Heaviside(x) assert deltaintegrate((x + 1)*DiracDelta(x*Rational(2, 3) + Rational(4, 9)), x) == \ S.Half * Heaviside(x + Rational(2, 3)) a, b, c = symbols('a b c', commutative=False) assert deltaintegrate(DiracDelta(x - y)*f(x - b)*f(x - a), x) == \ f(y - b)*f(y - a)*Heaviside(x - y) p = f(x - a)*DiracDelta(x - y)*f(x - c)*f(x - b) assert deltaintegrate(p, x) == f(y - a)*f(y - c)*f(y - b)*Heaviside(x - y) p = DiracDelta(x - z)*f(x - b)*f(x - a)*DiracDelta(x - y) assert deltaintegrate(p, x) == DiracDelta(y - z)*f(y - b)*f(y - a) * \ Heaviside(x - y) sympy-sympy-1.9/sympy/integrals/tests/test_failing_integrals.py000066400000000000000000000155631412543434000253420ustar00rootroot00000000000000# A collection of failing integrals from the issues. from sympy import ( integrate, I, Integral, exp, oo, pi, sign, sqrt, sin, cos, Piecewise, tan, S, log, gamma, sinh, sec, acos, atan, sech, csch, DiracDelta, Rational, symbols ) from sympy.testing.pytest import XFAIL, SKIP, slow, skip, ON_TRAVIS from sympy.abc import x, k, c, y, b, h, a, m, z, n, t @SKIP("Too slow for @slow") @XFAIL def test_issue_3880(): # integrate_hyperexponential(Poly(t*2*(1 - t0**2)*t0*(x**3 + x**2), t), Poly((1 + t0**2)**2*2*(x**2 + x + 1), t), [Poly(1, x), Poly(1 + t0**2, t0), Poly(t, t)], [x, t0, t], [exp, tan]) assert not integrate(exp(x)*cos(2*x)*sin(2*x) * (x**3 + x**2)/(2*(x**2 + x + 1)), x).has(Integral) @XFAIL def test_issue_4212(): assert not integrate(sign(x), x).has(Integral) @XFAIL def test_issue_4491(): # Can be solved via variable transformation x = y - 1 assert not integrate(x*sqrt(x**2 + 2*x + 4), x).has(Integral) @XFAIL def test_issue_4511(): # This works, but gives a complicated answer. The correct answer is x - cos(x). # If current answer is simplified, 1 - cos(x) + x is obtained. # The last one is what Maple gives. It is also quite slow. assert integrate(cos(x)**2 / (1 - sin(x))) in [x - cos(x), 1 - cos(x) + x, -2/(tan((S.Half)*x)**2 + 1) + x] @XFAIL def test_integrate_DiracDelta_fails(): # issue 6427 assert integrate(integrate(integrate( DiracDelta(x - y - z), (z, 0, oo)), (y, 0, 1)), (x, 0, 1)) == S.Half @XFAIL @slow def test_issue_4525(): # Warning: takes a long time assert not integrate((x**m * (1 - x)**n * (a + b*x + c*x**2))/(1 + x**2), (x, 0, 1)).has(Integral) @XFAIL @slow def test_issue_4540(): if ON_TRAVIS: skip("Too slow for travis.") # Note, this integral is probably nonelementary assert not integrate( (sin(1/x) - x*exp(x)) / ((-sin(1/x) + x*exp(x))*x + x*sin(1/x)), x).has(Integral) @XFAIL @slow def test_issue_4891(): # Requires the hypergeometric function. assert not integrate(cos(x)**y, x).has(Integral) @XFAIL @slow def test_issue_1796a(): assert not integrate(exp(2*b*x)*exp(-a*x**2), x).has(Integral) @XFAIL def test_issue_4895b(): assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, 0)).has(Integral) @XFAIL def test_issue_4895c(): assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, -oo, oo)).has(Integral) @XFAIL def test_issue_4895d(): assert not integrate(exp(2*b*x)*exp(-a*x**2), (x, 0, oo)).has(Integral) @XFAIL @slow def test_issue_4941(): if ON_TRAVIS: skip("Too slow for travis.") assert not integrate(sqrt(1 + sinh(x/20)**2), (x, -25, 25)).has(Integral) @XFAIL def test_issue_4992(): # Nonelementary integral. Requires hypergeometric/Meijer-G handling. assert not integrate(log(x) * x**(k - 1) * exp(-x) / gamma(k), (x, 0, oo)).has(Integral) @XFAIL def test_issue_16396a(): i = integrate(1/(1+sqrt(tan(x))), (x, pi/3, pi/6)) assert not i.has(Integral) @XFAIL def test_issue_16396b(): i = integrate(x*sin(x)/(1+cos(x)**2), (x, 0, pi)) assert not i.has(Integral) @XFAIL def test_issue_16161(): i = integrate(x*sec(x)**2, x) assert not i.has(Integral) # assert i == x*tan(x) + log(cos(x)) @XFAIL def test_issue_16046(): assert integrate(exp(exp(I*x)), [x, 0, 2*pi]) == 2*pi @XFAIL def test_issue_15925a(): assert not integrate(sqrt((1+sin(x))**2+(cos(x))**2), (x, -pi/2, pi/2)).has(Integral) @XFAIL @slow def test_issue_15925b(): if ON_TRAVIS: skip("Too slow for travis.") assert not integrate(sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2), (x, 0, pi/6)).has(Integral) @XFAIL def test_issue_15925b_manual(): assert not integrate(sqrt((-12*cos(x)**2*sin(x))**2+(12*cos(x)*sin(x)**2)**2), (x, 0, pi/6), manual=True).has(Integral) @XFAIL @slow def test_issue_15227(): if ON_TRAVIS: skip("Too slow for travis.") i = integrate(log(1-x)*log((1+x)**2)/x, (x, 0, 1)) assert not i.has(Integral) # assert i == -5*zeta(3)/4 @XFAIL @slow def test_issue_14716(): i = integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1)) assert not i.has(Integral) # Mathematica can not solve it either, but # integrate(log(x + 5)*cos(pi*x),(x, S.Half, 1)).transform(x, y - 5).doit() # works # assert i == -log(Rational(11, 2))/pi - Si(pi*Rational(11, 2))/pi + Si(6*pi)/pi @XFAIL def test_issue_14709a(): i = integrate(x*acos(1 - 2*x/h), (x, 0, h)) assert not i.has(Integral) # assert i == 5*h**2*pi/16 @slow @XFAIL def test_issue_14398(): assert not integrate(exp(x**2)*cos(x), x).has(Integral) @XFAIL def test_issue_14074(): i = integrate(log(sin(x)), (x, 0, pi/2)) assert not i.has(Integral) # assert i == -pi*log(2)/2 @XFAIL @slow def test_issue_14078b(): i = integrate((atan(4*x)-atan(2*x))/x, (x, 0, oo)) assert not i.has(Integral) # assert i == pi*log(2)/2 @XFAIL def test_issue_13792(): i = integrate(log(1/x) / (1 - x), (x, 0, 1)) assert not i.has(Integral) # assert i in [polylog(2, -exp_polar(I*pi)), pi**2/6] @XFAIL def test_issue_11845a(): assert not integrate(exp(y - x**3), (x, 0, 1)).has(Integral) @XFAIL def test_issue_11845b(): assert not integrate(exp(-y - x**3), (x, 0, 1)).has(Integral) @XFAIL def test_issue_11813(): assert not integrate((a - x)**Rational(-1, 2)*x, (x, 0, a)).has(Integral) @XFAIL def test_issue_11742(): i = integrate(sqrt(-x**2 + 8*x + 48), (x, 4, 12)) assert not i.has(Integral) # assert i == 16*pi @XFAIL def test_issue_11254a(): assert not integrate(sech(x), (x, 0, 1)).has(Integral) @XFAIL def test_issue_11254b(): assert not integrate(csch(x), (x, 0, 1)).has(Integral) @XFAIL def test_issue_10584(): assert not integrate(sqrt(x**2 + 1/x**2), x).has(Integral) @XFAIL def test_issue_9723(): assert not integrate(sqrt(x + sqrt(x))).has(Integral) @XFAIL def test_issue_9101(): assert not integrate(log(x + sqrt(x**2 + y**2 + z**2)), z).has(Integral) @XFAIL def test_issue_7264(): assert not integrate(exp(x)*sqrt(1 + exp(2*x))).has(Integral) @XFAIL def test_issue_7147(): assert not integrate(x/sqrt(a*x**2 + b*x + c)**3, x).has(Integral) @XFAIL def test_issue_7109(): assert not integrate(sqrt(a**2/(a**2 - x**2)), x).has(Integral) @XFAIL def test_integrate_Piecewise_rational_over_reals(): f = Piecewise( (0, t - 478.515625*pi < 0), (13.2075145209219*pi/(0.000871222*t + 0.995)**2, t - 478.515625*pi >= 0)) assert abs((integrate(f, (t, 0, oo)) - 15235.9375*pi).evalf()) <= 1e-7 @XFAIL def test_issue_4311_slow(): # Not slow when bypassing heurish assert not integrate(x*abs(9-x**2), x).has(Integral) @XFAIL def test_issue_20370(): a = symbols('a', positive=True) assert integrate((1 + a * cos(x))**-1, (x, 0, 2 * pi)) == (2 * pi / sqrt(1 - a**2)) sympy-sympy-1.9/sympy/integrals/tests/test_heurisch.py000066400000000000000000000261361412543434000234710ustar00rootroot00000000000000from sympy import Rational, sqrt, symbols, sin, exp, log, sinh, cosh, cos, pi, \ I, erf, tan, asin, asinh, acos, atan, Function, Derivative, diff, simplify, \ LambertW, Ne, Piecewise, Symbol, Add, ratsimp, Integral, Sum, \ besselj, besselk, bessely, jn, tanh from sympy.integrals.heurisch import components, heurisch, heurisch_wrapper from sympy.testing.pytest import XFAIL, skip, slow, ON_TRAVIS from sympy.integrals.integrals import integrate x, y, z, nu = symbols('x,y,z,nu') f = Function('f') def test_components(): assert components(x*y, x) == {x} assert components(1/(x + y), x) == {x} assert components(sin(x), x) == {sin(x), x} assert components(sin(x)*sqrt(log(x)), x) == \ {log(x), sin(x), sqrt(log(x)), x} assert components(x*sin(exp(x)*y), x) == \ {sin(y*exp(x)), x, exp(x)} assert components(x**Rational(17, 54)/sqrt(sin(x)), x) == \ {sin(x), x**Rational(1, 54), sqrt(sin(x)), x} assert components(f(x), x) == \ {x, f(x)} assert components(Derivative(f(x), x), x) == \ {x, f(x), Derivative(f(x), x)} assert components(f(x)*diff(f(x), x), x) == \ {x, f(x), Derivative(f(x), x), Derivative(f(x), x)} def test_issue_10680(): assert isinstance(integrate(x**log(x**log(x**log(x))),x), Integral) def test_issue_21166(): assert integrate(sin(x/sqrt(abs(x))), (x, -1, 1)) == 0 def test_heurisch_polynomials(): assert heurisch(1, x) == x assert heurisch(x, x) == x**2/2 assert heurisch(x**17, x) == x**18/18 # For coverage assert heurisch_wrapper(y, x) == y*x def test_heurisch_fractions(): assert heurisch(1/x, x) == log(x) assert heurisch(1/(2 + x), x) == log(x + 2) assert heurisch(1/(x + sin(y)), x) == log(x + sin(y)) # Up to a constant, where C = pi*I*Rational(5, 12), Mathematica gives identical # result in the first case. The difference is because sympy changes # signs of expressions without any care. # XXX ^ ^ ^ is this still correct? assert heurisch(5*x**5/( 2*x**6 - 5), x) in [5*log(2*x**6 - 5) / 12, 5*log(-2*x**6 + 5) / 12] assert heurisch(5*x**5/(2*x**6 + 5), x) == 5*log(2*x**6 + 5) / 12 assert heurisch(1/x**2, x) == -1/x assert heurisch(-1/x**5, x) == 1/(4*x**4) def test_heurisch_log(): assert heurisch(log(x), x) == x*log(x) - x assert heurisch(log(3*x), x) == -x + x*log(3) + x*log(x) assert heurisch(log(x**2), x) in [x*log(x**2) - 2*x, 2*x*log(x) - 2*x] def test_heurisch_exp(): assert heurisch(exp(x), x) == exp(x) assert heurisch(exp(-x), x) == -exp(-x) assert heurisch(exp(17*x), x) == exp(17*x) / 17 assert heurisch(x*exp(x), x) == x*exp(x) - exp(x) assert heurisch(x*exp(x**2), x) == exp(x**2) / 2 assert heurisch(exp(-x**2), x) is None assert heurisch(2**x, x) == 2**x/log(2) assert heurisch(x*2**x, x) == x*2**x/log(2) - 2**x*log(2)**(-2) assert heurisch(Integral(x**z*y, (y, 1, 2), (z, 2, 3)).function, x) == (x*x**z*y)/(z+1) assert heurisch(Sum(x**z, (z, 1, 2)).function, z) == x**z/log(x) def test_heurisch_trigonometric(): assert heurisch(sin(x), x) == -cos(x) assert heurisch(pi*sin(x) + 1, x) == x - pi*cos(x) assert heurisch(cos(x), x) == sin(x) assert heurisch(tan(x), x) in [ log(1 + tan(x)**2)/2, log(tan(x) + I) + I*x, log(tan(x) - I) - I*x, ] assert heurisch(sin(x)*sin(y), x) == -cos(x)*sin(y) assert heurisch(sin(x)*sin(y), y) == -cos(y)*sin(x) # gives sin(x) in answer when run via setup.py and cos(x) when run via py.test assert heurisch(sin(x)*cos(x), x) in [sin(x)**2 / 2, -cos(x)**2 / 2] assert heurisch(cos(x)/sin(x), x) == log(sin(x)) assert heurisch(x*sin(7*x), x) == sin(7*x) / 49 - x*cos(7*x) / 7 assert heurisch(1/pi/4 * x**2*cos(x), x) == 1/pi/4*(x**2*sin(x) - 2*sin(x) + 2*x*cos(x)) assert heurisch(acos(x/4) * asin(x/4), x) == 2*x - (sqrt(16 - x**2))*asin(x/4) \ + (sqrt(16 - x**2))*acos(x/4) + x*asin(x/4)*acos(x/4) assert heurisch(sin(x)/(cos(x)**2+1), x) == -atan(cos(x)) #fixes issue 13723 assert heurisch(1/(cos(x)+2), x) == 2*sqrt(3)*atan(sqrt(3)*tan(x/2)/3)/3 assert heurisch(2*sin(x)*cos(x)/(sin(x)**4 + 1), x) == atan(sqrt(2)*sin(x) - 1) - atan(sqrt(2)*sin(x) + 1) assert heurisch(1/cosh(x), x) == 2*atan(tanh(x/2)) def test_heurisch_hyperbolic(): assert heurisch(sinh(x), x) == cosh(x) assert heurisch(cosh(x), x) == sinh(x) assert heurisch(x*sinh(x), x) == x*cosh(x) - sinh(x) assert heurisch(x*cosh(x), x) == x*sinh(x) - cosh(x) assert heurisch( x*asinh(x/2), x) == x**2*asinh(x/2)/2 + asinh(x/2) - x*sqrt(4 + x**2)/4 def test_heurisch_mixed(): assert heurisch(sin(x)*exp(x), x) == exp(x)*sin(x)/2 - exp(x)*cos(x)/2 assert heurisch(sin(x/sqrt(-x)), x) == 2*x*cos(x/sqrt(-x))/sqrt(-x) - 2*sin(x/sqrt(-x)) def test_heurisch_radicals(): assert heurisch(1/sqrt(x), x) == 2*sqrt(x) assert heurisch(1/sqrt(x)**3, x) == -2/sqrt(x) assert heurisch(sqrt(x)**3, x) == 2*sqrt(x)**5/5 assert heurisch(sin(x)*sqrt(cos(x)), x) == -2*sqrt(cos(x))**3/3 y = Symbol('y') assert heurisch(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \ 2*sqrt(x)*cos(y*sqrt(x))/y assert heurisch_wrapper(sin(y*sqrt(x)), x) == Piecewise( (-2*sqrt(x)*cos(sqrt(x)*y)/y + 2*sin(sqrt(x)*y)/y**2, Ne(y, 0)), (0, True)) y = Symbol('y', positive=True) assert heurisch_wrapper(sin(y*sqrt(x)), x) == 2/y**2*sin(y*sqrt(x)) - \ 2*sqrt(x)*cos(y*sqrt(x))/y def test_heurisch_special(): assert heurisch(erf(x), x) == x*erf(x) + exp(-x**2)/sqrt(pi) assert heurisch(exp(-x**2)*erf(x), x) == sqrt(pi)*erf(x)**2 / 4 def test_heurisch_symbolic_coeffs(): assert heurisch(1/(x + y), x) == log(x + y) assert heurisch(1/(x + sqrt(2)), x) == log(x + sqrt(2)) assert simplify(diff(heurisch(log(x + y + z), y), y)) == log(x + y + z) def test_heurisch_symbolic_coeffs_1130(): y = Symbol('y') assert heurisch_wrapper(1/(x**2 + y), x) == Piecewise( (log(x - sqrt(-y))/(2*sqrt(-y)) - log(x + sqrt(-y))/(2*sqrt(-y)), Ne(y, 0)), (-1/x, True)) y = Symbol('y', positive=True) assert heurisch_wrapper(1/(x**2 + y), x) == (atan(x/sqrt(y))/sqrt(y)) def test_heurisch_hacking(): assert heurisch(sqrt(1 + 7*x**2), x, hints=[]) == \ x*sqrt(1 + 7*x**2)/2 + sqrt(7)*asinh(sqrt(7)*x)/14 assert heurisch(sqrt(1 - 7*x**2), x, hints=[]) == \ x*sqrt(1 - 7*x**2)/2 + sqrt(7)*asin(sqrt(7)*x)/14 assert heurisch(1/sqrt(1 + 7*x**2), x, hints=[]) == \ sqrt(7)*asinh(sqrt(7)*x)/7 assert heurisch(1/sqrt(1 - 7*x**2), x, hints=[]) == \ sqrt(7)*asin(sqrt(7)*x)/7 assert heurisch(exp(-7*x**2), x, hints=[]) == \ sqrt(7*pi)*erf(sqrt(7)*x)/14 assert heurisch(1/sqrt(9 - 4*x**2), x, hints=[]) == \ asin(x*Rational(2, 3))/2 assert heurisch(1/sqrt(9 + 4*x**2), x, hints=[]) == \ asinh(x*Rational(2, 3))/2 def test_heurisch_function(): assert heurisch(f(x), x) is None @XFAIL def test_heurisch_function_derivative(): # TODO: it looks like this used to work just by coincindence and # thanks to sloppy implementation. Investigate why this used to # work at all and if support for this can be restored. df = diff(f(x), x) assert heurisch(f(x)*df, x) == f(x)**2/2 assert heurisch(f(x)**2*df, x) == f(x)**3/3 assert heurisch(df/f(x), x) == log(f(x)) def test_heurisch_wrapper(): f = 1/(y + x) assert heurisch_wrapper(f, x) == log(x + y) f = 1/(y - x) assert heurisch_wrapper(f, x) == -log(x - y) f = 1/((y - x)*(y + x)) assert heurisch_wrapper(f, x) == Piecewise( (-log(x - y)/(2*y) + log(x + y)/(2*y), Ne(y, 0)), (1/x, True)) # issue 6926 f = sqrt(x**2/((y - x)*(y + x))) assert heurisch_wrapper(f, x) == x*sqrt(x**2/(-x**2 + y**2)) \ - y**2*sqrt(x**2/(-x**2 + y**2))/x def test_issue_3609(): assert heurisch(1/(x * (1 + log(x)**2)), x) == atan(log(x)) ### These are examples from the Poor Man's Integrator ### http://www-sop.inria.fr/cafe/Manuel.Bronstein/pmint/examples/ def test_pmint_rat(): # TODO: heurisch() is off by a constant: -3/4. Possibly different permutation # would give the optimal result? def drop_const(expr, x): if expr.is_Add: return Add(*[ arg for arg in expr.args if arg.has(x) ]) else: return expr f = (x**7 - 24*x**4 - 4*x**2 + 8*x - 8)/(x**8 + 6*x**6 + 12*x**4 + 8*x**2) g = (4 + 8*x**2 + 6*x + 3*x**3)/(x**5 + 4*x**3 + 4*x) + log(x) assert drop_const(ratsimp(heurisch(f, x)), x) == g def test_pmint_trig(): f = (x - tan(x)) / tan(x)**2 + tan(x) g = -x**2/2 - x/tan(x) + log(tan(x)**2 + 1)/2 assert heurisch(f, x) == g @slow # 8 seconds on 3.4 GHz def test_pmint_logexp(): if ON_TRAVIS: # See https://github.com/sympy/sympy/pull/12795 skip("Too slow for travis.") f = (1 + x + x*exp(x))*(x + log(x) + exp(x) - 1)/(x + log(x) + exp(x))**2/x g = log(x + exp(x) + log(x)) + 1/(x + exp(x) + log(x)) assert ratsimp(heurisch(f, x)) == g def test_pmint_erf(): f = exp(-x**2)*erf(x)/(erf(x)**3 - erf(x)**2 - erf(x) + 1) g = sqrt(pi)*log(erf(x) - 1)/8 - sqrt(pi)*log(erf(x) + 1)/8 - sqrt(pi)/(4*erf(x) - 4) assert ratsimp(heurisch(f, x)) == g def test_pmint_LambertW(): f = LambertW(x) g = x*LambertW(x) - x + x/LambertW(x) assert heurisch(f, x) == g def test_pmint_besselj(): f = besselj(nu + 1, x)/besselj(nu, x) g = nu*log(x) - log(besselj(nu, x)) assert heurisch(f, x) == g f = (nu*besselj(nu, x) - x*besselj(nu + 1, x))/x g = besselj(nu, x) assert heurisch(f, x) == g f = jn(nu + 1, x)/jn(nu, x) g = nu*log(x) - log(jn(nu, x)) assert heurisch(f, x) == g @slow def test_pmint_bessel_products(): # Note: Derivatives of Bessel functions have many forms. # Recurrence relations are needed for comparisons. if ON_TRAVIS: skip("Too slow for travis.") f = x*besselj(nu, x)*bessely(nu, 2*x) g = -2*x*besselj(nu, x)*bessely(nu - 1, 2*x)/3 + x*besselj(nu - 1, x)*bessely(nu, 2*x)/3 assert heurisch(f, x) == g f = x*besselj(nu, x)*besselk(nu, 2*x) g = -2*x*besselj(nu, x)*besselk(nu - 1, 2*x)/5 - x*besselj(nu - 1, x)*besselk(nu, 2*x)/5 assert heurisch(f, x) == g @slow # 110 seconds on 3.4 GHz def test_pmint_WrightOmega(): if ON_TRAVIS: skip("Too slow for travis.") def omega(x): return LambertW(exp(x)) f = (1 + omega(x) * (2 + cos(omega(x)) * (x + omega(x))))/(1 + omega(x))/(x + omega(x)) g = log(x + LambertW(exp(x))) + sin(LambertW(exp(x))) assert heurisch(f, x) == g def test_RR(): # Make sure the algorithm does the right thing if the ring is RR. See # issue 8685. assert heurisch(sqrt(1 + 0.25*x**2), x, hints=[]) == \ 0.5*x*sqrt(0.25*x**2 + 1) + 1.0*asinh(0.5*x) # TODO: convert the rest of PMINT tests: # Airy functions # f = (x - AiryAi(x)*AiryAi(1, x)) / (x**2 - AiryAi(x)**2) # g = Rational(1,2)*ln(x + AiryAi(x)) + Rational(1,2)*ln(x - AiryAi(x)) # f = x**2 * AiryAi(x) # g = -AiryAi(x) + AiryAi(1, x)*x # Whittaker functions # f = WhittakerW(mu + 1, nu, x) / (WhittakerW(mu, nu, x) * x) # g = x/2 - mu*ln(x) - ln(WhittakerW(mu, nu, x)) sympy-sympy-1.9/sympy/integrals/tests/test_integrals.py000066400000000000000000002017601412543434000236450ustar00rootroot00000000000000from sympy import ( Abs, acos, acosh, Add, And, asin, asinh, atan, Ci, cos, sinh, cosh, tanh, Derivative, diff, DiracDelta, E, Ei, Eq, exp, erf, erfc, erfi, EulerGamma, Expr, factor, Function, gamma, gammasimp, I, Idx, im, IndexedBase, integrate, Interval, Lambda, LambertW, log, Matrix, Max, meijerg, Min, nan, Ne, O, oo, pi, Piecewise, polar_lift, Poly, polygamma, Rational, re, S, Si, sign, simplify, sin, sinc, SingularityFunction, sqrt, sstr, Sum, Symbol, summation, symbols, sympify, tan, trigsimp, Tuple, lerchphi, exp_polar, li, hyper, Float ) from sympy.core.expr import unchanged from sympy.functions.elementary.complexes import periodic_argument from sympy.functions.elementary.integers import floor from sympy.integrals.integrals import Integral from sympy.integrals.risch import NonElementaryIntegral from sympy.physics import units from sympy.testing.pytest import (raises, slow, skip, ON_TRAVIS, warns_deprecated_sympy) from sympy.testing.randtest import verify_numerically x, y, a, t, x_1, x_2, z, s, b = symbols('x y a t x_1 x_2 z s b') n = Symbol('n', integer=True) f = Function('f') def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) def test_poly_deprecated(): p = Poly(2*x, x) assert p.integrate(x) == Poly(x**2, x, domain='QQ') with warns_deprecated_sympy(): integrate(p, x) with warns_deprecated_sympy(): Integral(p, (x,)) @slow def test_principal_value(): g = 1 / x assert Integral(g, (x, -oo, oo)).principal_value() == 0 assert Integral(g, (y, -oo, oo)).principal_value() == oo * sign(1 / x) raises(ValueError, lambda: Integral(g, (x)).principal_value()) raises(ValueError, lambda: Integral(g).principal_value()) l = 1 / ((x ** 3) - 1) assert Integral(l, (x, -oo, oo)).principal_value().together() == -sqrt(3)*pi/3 raises(ValueError, lambda: Integral(l, (x, -oo, 1)).principal_value()) d = 1 / (x ** 2 - 1) assert Integral(d, (x, -oo, oo)).principal_value() == 0 assert Integral(d, (x, -2, 2)).principal_value() == -log(3) v = x / (x ** 2 - 1) assert Integral(v, (x, -oo, oo)).principal_value() == 0 assert Integral(v, (x, -2, 2)).principal_value() == 0 s = x ** 2 / (x ** 2 - 1) assert Integral(s, (x, -oo, oo)).principal_value() is oo assert Integral(s, (x, -2, 2)).principal_value() == -log(3) + 4 f = 1 / ((x ** 2 - 1) * (1 + x ** 2)) assert Integral(f, (x, -oo, oo)).principal_value() == -pi / 2 assert Integral(f, (x, -2, 2)).principal_value() == -atan(2) - log(3) / 2 def diff_test(i): """Return the set of symbols, s, which were used in testing that i.diff(s) agrees with i.doit().diff(s). If there is an error then the assertion will fail, causing the test to fail.""" syms = i.free_symbols for s in syms: assert (i.diff(s).doit() - i.doit().diff(s)).expand() == 0 return syms def test_improper_integral(): assert integrate(log(x), (x, 0, 1)) == -1 assert integrate(x**(-2), (x, 1, oo)) == 1 assert integrate(1/(1 + exp(x)), (x, 0, oo)) == log(2) def test_constructor(): # this is shared by Sum, so testing Integral's constructor # is equivalent to testing Sum's s1 = Integral(n, n) assert s1.limits == (Tuple(n),) s2 = Integral(n, (n,)) assert s2.limits == (Tuple(n),) s3 = Integral(Sum(x, (x, 1, y))) assert s3.limits == (Tuple(y),) s4 = Integral(n, Tuple(n,)) assert s4.limits == (Tuple(n),) s5 = Integral(n, (n, Interval(1, 2))) assert s5.limits == (Tuple(n, 1, 2),) # Testing constructor with inequalities: s6 = Integral(n, n > 10) assert s6.limits == (Tuple(n, 10, oo),) s7 = Integral(n, (n > 2) & (n < 5)) assert s7.limits == (Tuple(n, 2, 5),) def test_basics(): assert Integral(0, x) != 0 assert Integral(x, (x, 1, 1)) != 0 assert Integral(oo, x) != oo assert Integral(S.NaN, x) is S.NaN assert diff(Integral(y, y), x) == 0 assert diff(Integral(x, (x, 0, 1)), x) == 0 assert diff(Integral(x, x), x) == x assert diff(Integral(t, (t, 0, x)), x) == x e = (t + 1)**2 assert diff(integrate(e, (t, 0, x)), x) == \ diff(Integral(e, (t, 0, x)), x).doit().expand() == \ ((1 + x)**2).expand() assert diff(integrate(e, (t, 0, x)), t) == \ diff(Integral(e, (t, 0, x)), t) == 0 assert diff(integrate(e, (t, 0, x)), a) == \ diff(Integral(e, (t, 0, x)), a) == 0 assert diff(integrate(e, t), a) == diff(Integral(e, t), a) == 0 assert integrate(e, (t, a, x)).diff(x) == \ Integral(e, (t, a, x)).diff(x).doit().expand() assert Integral(e, (t, a, x)).diff(x).doit() == ((1 + x)**2) assert integrate(e, (t, x, a)).diff(x).doit() == (-(1 + x)**2).expand() assert integrate(t**2, (t, x, 2*x)).diff(x) == 7*x**2 assert Integral(x, x).atoms() == {x} assert Integral(f(x), (x, 0, 1)).atoms() == {S.Zero, S.One, x} assert diff_test(Integral(x, (x, 3*y))) == {y} assert diff_test(Integral(x, (a, 3*y))) == {x, y} assert integrate(x, (x, oo, oo)) == 0 #issue 8171 assert integrate(x, (x, -oo, -oo)) == 0 # sum integral of terms assert integrate(y + x + exp(x), x) == x*y + x**2/2 + exp(x) assert Integral(x).is_commutative n = Symbol('n', commutative=False) assert Integral(n + x, x).is_commutative is False def test_diff_wrt(): class Test(Expr): _diff_wrt = True is_commutative = True t = Test() assert integrate(t + 1, t) == t**2/2 + t assert integrate(t + 1, (t, 0, 1)) == Rational(3, 2) raises(ValueError, lambda: integrate(x + 1, x + 1)) raises(ValueError, lambda: integrate(x + 1, (x + 1, 0, 1))) def test_basics_multiple(): assert diff_test(Integral(x, (x, 3*x, 5*y), (y, x, 2*x))) == {x} assert diff_test(Integral(x, (x, 5*y), (y, x, 2*x))) == {x} assert diff_test(Integral(x, (x, 5*y), (y, y, 2*x))) == {x, y} assert diff_test(Integral(y, y, x)) == {x, y} assert diff_test(Integral(y*x, x, y)) == {x, y} assert diff_test(Integral(x + y, y, (y, 1, x))) == {x} assert diff_test(Integral(x + y, (x, x, y), (y, y, x))) == {x, y} def test_conjugate_transpose(): A, B = symbols("A B", commutative=False) x = Symbol("x", complex=True) p = Integral(A*B, (x,)) assert p.adjoint().doit() == p.doit().adjoint() assert p.conjugate().doit() == p.doit().conjugate() assert p.transpose().doit() == p.doit().transpose() x = Symbol("x", real=True) p = Integral(A*B, (x,)) assert p.adjoint().doit() == p.doit().adjoint() assert p.conjugate().doit() == p.doit().conjugate() assert p.transpose().doit() == p.doit().transpose() def test_integration(): assert integrate(0, (t, 0, x)) == 0 assert integrate(3, (t, 0, x)) == 3*x assert integrate(t, (t, 0, x)) == x**2/2 assert integrate(3*t, (t, 0, x)) == 3*x**2/2 assert integrate(3*t**2, (t, 0, x)) == x**3 assert integrate(1/t, (t, 1, x)) == log(x) assert integrate(-1/t**2, (t, 1, x)) == 1/x - 1 assert integrate(t**2 + 5*t - 8, (t, 0, x)) == x**3/3 + 5*x**2/2 - 8*x assert integrate(x**2, x) == x**3/3 assert integrate((3*t*x)**5, x) == (3*t)**5 * x**6 / 6 b = Symbol("b") c = Symbol("c") assert integrate(a*t, (t, 0, x)) == a*x**2/2 assert integrate(a*t**4, (t, 0, x)) == a*x**5/5 assert integrate(a*t**2 + b*t + c, (t, 0, x)) == a*x**3/3 + b*x**2/2 + c*x def test_multiple_integration(): assert integrate((x**2)*(y**2), (x, 0, 1), (y, -1, 2)) == Rational(1) assert integrate((y**2)*(x**2), x, y) == Rational(1, 9)*(x**3)*(y**3) assert integrate(1/(x + 3)/(1 + x)**3, x) == \ log(3 + x)*Rational(-1, 8) + log(1 + x)*Rational(1, 8) + x/(4 + 8*x + 4*x**2) assert integrate(sin(x*y)*y, (x, 0, 1), (y, 0, 1)) == -sin(1) + 1 def test_issue_3532(): assert integrate(exp(-x), (x, 0, oo)) == 1 def test_issue_3560(): assert integrate(sqrt(x)**3, x) == 2*sqrt(x)**5/5 assert integrate(sqrt(x), x) == 2*sqrt(x)**3/3 assert integrate(1/sqrt(x)**3, x) == -2/sqrt(x) def test_issue_18038(): raises(AttributeError, lambda: integrate((x, x))) def test_integrate_poly(): p = Poly(x + x**2*y + y**3, x, y) with warns_deprecated_sympy(): qx = integrate(p, x) with warns_deprecated_sympy(): qy = integrate(p, y) assert isinstance(qx, Poly) is True assert isinstance(qy, Poly) is True assert qx.gens == (x, y) assert qy.gens == (x, y) assert qx.as_expr() == x**2/2 + x**3*y/3 + x*y**3 assert qy.as_expr() == x*y + x**2*y**2/2 + y**4/4 def test_integrate_poly_defined(): p = Poly(x + x**2*y + y**3, x, y) with warns_deprecated_sympy(): Qx = integrate(p, (x, 0, 1)) with warns_deprecated_sympy(): Qy = integrate(p, (y, 0, pi)) assert isinstance(Qx, Poly) is True assert isinstance(Qy, Poly) is True assert Qx.gens == (y,) assert Qy.gens == (x,) assert Qx.as_expr() == S.Half + y/3 + y**3 assert Qy.as_expr() == pi**4/4 + pi*x + pi**2*x**2/2 def test_integrate_omit_var(): y = Symbol('y') assert integrate(x) == x**2/2 raises(ValueError, lambda: integrate(2)) raises(ValueError, lambda: integrate(x*y)) def test_integrate_poly_accurately(): y = Symbol('y') assert integrate(x*sin(y), x) == x**2*sin(y)/2 # when passed to risch_norman, this will be a CPU hog, so this really # checks, that integrated function is recognized as polynomial assert integrate(x**1000*sin(y), x) == x**1001*sin(y)/1001 def test_issue_3635(): y = Symbol('y') assert integrate(x**2, y) == x**2*y assert integrate(x**2, (y, -1, 1)) == 2*x**2 # works in sympy and py.test but hangs in `setup.py test` def test_integrate_linearterm_pow(): # check integrate((a*x+b)^c, x) -- issue 3499 y = Symbol('y', positive=True) # TODO: Remove conds='none' below, let the assumption take care of it. assert integrate(x**y, x, conds='none') == x**(y + 1)/(y + 1) assert integrate((exp(y)*x + 1/y)**(1 + sin(y)), x, conds='none') == \ exp(-y)*(exp(y)*x + 1/y)**(2 + sin(y)) / (2 + sin(y)) def test_issue_3618(): assert integrate(pi*sqrt(x), x) == 2*pi*sqrt(x)**3/3 assert integrate(pi*sqrt(x) + E*sqrt(x)**3, x) == \ 2*pi*sqrt(x)**3/3 + 2*E *sqrt(x)**5/5 def test_issue_3623(): assert integrate(cos((n + 1)*x), x) == Piecewise( (sin(x*(n + 1))/(n + 1), Ne(n + 1, 0)), (x, True)) assert integrate(cos((n - 1)*x), x) == Piecewise( (sin(x*(n - 1))/(n - 1), Ne(n - 1, 0)), (x, True)) assert integrate(cos((n + 1)*x) + cos((n - 1)*x), x) == \ Piecewise((sin(x*(n - 1))/(n - 1), Ne(n - 1, 0)), (x, True)) + \ Piecewise((sin(x*(n + 1))/(n + 1), Ne(n + 1, 0)), (x, True)) def test_issue_3664(): n = Symbol('n', integer=True, nonzero=True) assert integrate(-1./2 * x * sin(n * pi * x/2), [x, -2, 0]) == \ 2.0*cos(pi*n)/(pi*n) assert integrate(x * sin(n * pi * x/2) * Rational(-1, 2), [x, -2, 0]) == \ 2*cos(pi*n)/(pi*n) def test_issue_3679(): # definite integration of rational functions gives wrong answers assert NS(Integral(1/(x**2 - 8*x + 17), (x, 2, 4))) == '1.10714871779409' def test_issue_3686(): # remove this when fresnel itegrals are implemented from sympy import expand_func, fresnels assert expand_func(integrate(sin(x**2), x)) == \ sqrt(2)*sqrt(pi)*fresnels(sqrt(2)*x/sqrt(pi))/2 def test_integrate_units(): m = units.m s = units.s assert integrate(x * m/s, (x, 1*s, 5*s)) == 12*m*s def test_transcendental_functions(): assert integrate(LambertW(2*x), x) == \ -x + x*LambertW(2*x) + x/LambertW(2*x) def test_log_polylog(): assert integrate(log(1 - x)/x, (x, 0, 1)) == -pi**2/6 assert integrate(log(x)*(1 - x)**(-1), (x, 0, 1)) == -pi**2/6 def test_issue_3740(): f = 4*log(x) - 2*log(x)**2 fid = diff(integrate(f, x), x) assert abs(f.subs(x, 42).evalf() - fid.subs(x, 42).evalf()) < 1e-10 def test_issue_3788(): assert integrate(1/(1 + x**2), x) == atan(x) def test_issue_3952(): f = sin(x) assert integrate(f, x) == -cos(x) raises(ValueError, lambda: integrate(f, 2*x)) def test_issue_4516(): assert integrate(2**x - 2*x, x) == 2**x/log(2) - x**2 def test_issue_7450(): ans = integrate(exp(-(1 + I)*x), (x, 0, oo)) assert re(ans) == S.Half and im(ans) == Rational(-1, 2) def test_issue_8623(): assert integrate((1 + cos(2*x)) / (3 - 2*cos(2*x)), (x, 0, pi)) == -pi/2 + sqrt(5)*pi/2 assert integrate((1 + cos(2*x))/(3 - 2*cos(2*x))) == -x/2 + sqrt(5)*(atan(sqrt(5)*tan(x)) + \ pi*floor((x - pi/2)/pi))/2 def test_issue_9569(): assert integrate(1 / (2 - cos(x)), (x, 0, pi)) == pi/sqrt(3) assert integrate(1/(2 - cos(x))) == 2*sqrt(3)*(atan(sqrt(3)*tan(x/2)) + pi*floor((x/2 - pi/2)/pi))/3 def test_issue_13733(): s = Symbol('s', positive=True) pz = exp(-(z - y)**2/(2*s*s))/sqrt(2*pi*s*s) pzgx = integrate(pz, (z, x, oo)) assert integrate(pzgx, (x, 0, oo)) == sqrt(2)*s*exp(-y**2/(2*s**2))/(2*sqrt(pi)) + \ y*erf(sqrt(2)*y/(2*s))/2 + y/2 def test_issue_13749(): assert integrate(1 / (2 + cos(x)), (x, 0, pi)) == pi/sqrt(3) assert integrate(1/(2 + cos(x))) == 2*sqrt(3)*(atan(sqrt(3)*tan(x/2)/3) + pi*floor((x/2 - pi/2)/pi))/3 def test_issue_18133(): assert integrate(exp(x)/(1 + x)**2, x) == NonElementaryIntegral(exp(x)/(x + 1)**2, x) def test_issue_21741(): a = Float('3999999.9999999995', precision=53) b = Float('2.5000000000000004e-7', precision=53) r = Piecewise((b*I*exp(-a*I*pi*t*y)*exp(-a*I*pi*x*z)/(pi*x), Ne(1.0*pi*x*exp(a*I*pi*t*y), 0)), (z*exp(-a*I*pi*t*y), True)) fun = E**((-2*I*pi*(z*x+t*y))/(500*10**(-9))) assert integrate(fun, z) == r def test_matrices(): M = Matrix(2, 2, lambda i, j: (i + j + 1)*sin((i + j + 1)*x)) assert integrate(M, x) == Matrix([ [-cos(x), -cos(2*x)], [-cos(2*x), -cos(3*x)], ]) def test_integrate_functions(): # issue 4111 assert integrate(f(x), x) == Integral(f(x), x) assert integrate(f(x), (x, 0, 1)) == Integral(f(x), (x, 0, 1)) assert integrate(f(x)*diff(f(x), x), x) == f(x)**2/2 assert integrate(diff(f(x), x) / f(x), x) == log(f(x)) def test_integrate_derivatives(): assert integrate(Derivative(f(x), x), x) == f(x) assert integrate(Derivative(f(y), y), x) == x*Derivative(f(y), y) assert integrate(Derivative(f(x), x)**2, x) == \ Integral(Derivative(f(x), x)**2, x) def test_transform(): a = Integral(x**2 + 1, (x, -1, 2)) fx = x fy = 3*y + 1 assert a.doit() == a.transform(fx, fy).doit() assert a.transform(fx, fy).transform(fy, fx) == a fx = 3*x + 1 fy = y assert a.transform(fx, fy).transform(fy, fx) == a a = Integral(sin(1/x), (x, 0, 1)) assert a.transform(x, 1/y) == Integral(sin(y)/y**2, (y, 1, oo)) assert a.transform(x, 1/y).transform(y, 1/x) == a a = Integral(exp(-x**2), (x, -oo, oo)) assert a.transform(x, 2*y) == Integral(2*exp(-4*y**2), (y, -oo, oo)) # < 3 arg limit handled properly assert Integral(x, x).transform(x, a*y).doit() == \ Integral(y*a**2, y).doit() _3 = S(3) assert Integral(x, (x, 0, -_3)).transform(x, 1/y).doit() == \ Integral(-1/x**3, (x, -oo, -1/_3)).doit() assert Integral(x, (x, 0, _3)).transform(x, 1/y) == \ Integral(y**(-3), (y, 1/_3, oo)) # issue 8400 i = Integral(x + y, (x, 1, 2), (y, 1, 2)) assert i.transform(x, (x + 2*y, x)).doit() == \ i.transform(x, (x + 2*z, x)).doit() == 3 i = Integral(x, (x, a, b)) assert i.transform(x, 2*s) == Integral(4*s, (s, a/2, b/2)) raises(ValueError, lambda: i.transform(x, 1)) raises(ValueError, lambda: i.transform(x, s*t)) raises(ValueError, lambda: i.transform(x, -s)) raises(ValueError, lambda: i.transform(x, (s, t))) raises(ValueError, lambda: i.transform(2*x, 2*s)) i = Integral(x**2, (x, 1, 2)) raises(ValueError, lambda: i.transform(x**2, s)) am = Symbol('a', negative=True) bp = Symbol('b', positive=True) i = Integral(x, (x, bp, am)) i.transform(x, 2*s) assert i.transform(x, 2*s) == Integral(-4*s, (s, am/2, bp/2)) i = Integral(x, (x, a)) assert i.transform(x, 2*s) == Integral(4*s, (s, a/2)) def test_issue_4052(): f = S.Half*asin(x) + x*sqrt(1 - x**2)/2 assert integrate(cos(asin(x)), x) == f assert integrate(sin(acos(x)), x) == f @slow def test_evalf_integrals(): assert NS(Integral(x, (x, 2, 5)), 15) == '10.5000000000000' gauss = Integral(exp(-x**2), (x, -oo, oo)) assert NS(gauss, 15) == '1.77245385090552' assert NS(gauss**2 - pi + E*Rational( 1, 10**20), 15) in ('2.71828182845904e-20', '2.71828182845905e-20') # A monster of an integral from http://mathworld.wolfram.com/DefiniteIntegral.html t = Symbol('t') a = 8*sqrt(3)/(1 + 3*t**2) b = 16*sqrt(2)*(3*t + 1)*sqrt(4*t**2 + t + 1)**3 c = (3*t**2 + 1)*(11*t**2 + 2*t + 3)**2 d = sqrt(2)*(249*t**2 + 54*t + 65)/(11*t**2 + 2*t + 3)**2 f = a - b/c - d assert NS(Integral(f, (t, 0, 1)), 50) == \ NS((3*sqrt(2) - 49*pi + 162*atan(sqrt(2)))/12, 50) # http://mathworld.wolfram.com/VardisIntegral.html assert NS(Integral(log(log(1/x))/(1 + x + x**2), (x, 0, 1)), 15) == \ NS('pi/sqrt(3) * log(2*pi**(5/6) / gamma(1/6))', 15) # http://mathworld.wolfram.com/AhmedsIntegral.html assert NS(Integral(atan(sqrt(x**2 + 2))/(sqrt(x**2 + 2)*(x**2 + 1)), (x, 0, 1)), 15) == NS(5*pi**2/96, 15) # http://mathworld.wolfram.com/AbelsIntegral.html assert NS(Integral(x/((exp(pi*x) - exp( -pi*x))*(x**2 + 1)), (x, 0, oo)), 15) == NS('log(2)/2-1/4', 15) # Complex part trimming # http://mathworld.wolfram.com/VardisIntegral.html assert NS(Integral(log(log(sin(x)/cos(x))), (x, pi/4, pi/2)), 15, chop=True) == \ NS('pi/4*log(4*pi**3/gamma(1/4)**4)', 15) # # Endpoints causing trouble (rounding error in integration points -> complex log) assert NS( 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 17, chop=True) == NS(2, 17) assert NS( 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 20, chop=True) == NS(2, 20) assert NS( 2 + Integral(log(2*cos(x/2)), (x, -pi, pi)), 22, chop=True) == NS(2, 22) # Needs zero handling assert NS(pi - 4*Integral( 'sqrt(1-x**2)', (x, 0, 1)), 15, maxn=30, chop=True) in ('0.0', '0') # Oscillatory quadrature a = Integral(sin(x)/x**2, (x, 1, oo)).evalf(maxn=15) assert 0.49 < a < 0.51 assert NS( Integral(sin(x)/x**2, (x, 1, oo)), quad='osc') == '0.504067061906928' assert NS(Integral( cos(pi*x + 1)/x, (x, -oo, -1)), quad='osc') == '0.276374705640365' # indefinite integrals aren't evaluated assert NS(Integral(x, x)) == 'Integral(x, x)' assert NS(Integral(x, (x, y))) == 'Integral(x, (x, y))' def test_evalf_issue_939(): # https://github.com/sympy/sympy/issues/4038 # The output form of an integral may differ by a step function between # revisions, making this test a bit useless. This can't be said about # other two tests. For now, all values of this evaluation are used here, # but in future this should be reconsidered. assert NS(integrate(1/(x**5 + 1), x).subs(x, 4), chop=True) in \ ['-0.000976138910649103', '0.965906660135753', '1.93278945918216'] assert NS(Integral(1/(x**5 + 1), (x, 2, 4))) == '0.0144361088886740' assert NS( integrate(1/(x**5 + 1), (x, 2, 4)), chop=True) == '0.0144361088886740' def test_double_previously_failing_integrals(): # Double integrals not implemented <- Sure it is! res = integrate(sqrt(x) + x*y, (x, 1, 2), (y, -1, 1)) # Old numerical test assert NS(res, 15) == '2.43790283299492' # Symbolic test assert res == Rational(-4, 3) + 8*sqrt(2)/3 # double integral + zero detection assert integrate(sin(x + x*y), (x, -1, 1), (y, -1, 1)) is S.Zero def test_integrate_SingularityFunction(): in_1 = SingularityFunction(x, a, 3) + SingularityFunction(x, 5, -1) out_1 = SingularityFunction(x, a, 4)/4 + SingularityFunction(x, 5, 0) assert integrate(in_1, x) == out_1 in_2 = 10*SingularityFunction(x, 4, 0) - 5*SingularityFunction(x, -6, -2) out_2 = 10*SingularityFunction(x, 4, 1) - 5*SingularityFunction(x, -6, -1) assert integrate(in_2, x) == out_2 in_3 = 2*x**2*y -10*SingularityFunction(x, -4, 7) - 2*SingularityFunction(y, 10, -2) out_3_1 = 2*x**3*y/3 - 2*x*SingularityFunction(y, 10, -2) - 5*SingularityFunction(x, -4, 8)/4 out_3_2 = x**2*y**2 - 10*y*SingularityFunction(x, -4, 7) - 2*SingularityFunction(y, 10, -1) assert integrate(in_3, x) == out_3_1 assert integrate(in_3, y) == out_3_2 assert unchanged(Integral, in_3, (x,)) assert Integral(in_3, x) == Integral(in_3, (x,)) assert Integral(in_3, x).doit() == out_3_1 in_4 = 10*SingularityFunction(x, -4, 7) - 2*SingularityFunction(x, 10, -2) out_4 = 5*SingularityFunction(x, -4, 8)/4 - 2*SingularityFunction(x, 10, -1) assert integrate(in_4, (x, -oo, x)) == out_4 assert integrate(SingularityFunction(x, 5, -1), x) == SingularityFunction(x, 5, 0) assert integrate(SingularityFunction(x, 0, -1), (x, -oo, oo)) == 1 assert integrate(5*SingularityFunction(x, 5, -1), (x, -oo, oo)) == 5 assert integrate(SingularityFunction(x, 5, -1) * f(x), (x, -oo, oo)) == f(5) def test_integrate_DiracDelta(): # This is here to check that deltaintegrate is being called, but also # to test definite integrals. More tests are in test_deltafunctions.py assert integrate(DiracDelta(x) * f(x), (x, -oo, oo)) == f(0) assert integrate(DiracDelta(x)**2, (x, -oo, oo)) == DiracDelta(0) # issue 4522 assert integrate(integrate((4 - 4*x + x*y - 4*y) * \ DiracDelta(x)*DiracDelta(y - 1), (x, 0, 1)), (y, 0, 1)) == 0 # issue 5729 p = exp(-(x**2 + y**2))/pi assert integrate(p*DiracDelta(x - 10*y), (x, -oo, oo), (y, -oo, oo)) == \ integrate(p*DiracDelta(x - 10*y), (y, -oo, oo), (x, -oo, oo)) == \ integrate(p*DiracDelta(10*x - y), (x, -oo, oo), (y, -oo, oo)) == \ integrate(p*DiracDelta(10*x - y), (y, -oo, oo), (x, -oo, oo)) == \ 1/sqrt(101*pi) def test_integrate_returns_piecewise(): assert integrate(x**y, x) == Piecewise( (x**(y + 1)/(y + 1), Ne(y, -1)), (log(x), True)) assert integrate(x**y, y) == Piecewise( (x**y/log(x), Ne(log(x), 0)), (y, True)) assert integrate(exp(n*x), x) == Piecewise( (exp(n*x)/n, Ne(n, 0)), (x, True)) assert integrate(x*exp(n*x), x) == Piecewise( ((n*x - 1)*exp(n*x)/n**2, Ne(n**2, 0)), (x**2/2, True)) assert integrate(x**(n*y), x) == Piecewise( (x**(n*y + 1)/(n*y + 1), Ne(n*y, -1)), (log(x), True)) assert integrate(x**(n*y), y) == Piecewise( (x**(n*y)/(n*log(x)), Ne(n*log(x), 0)), (y, True)) assert integrate(cos(n*x), x) == Piecewise( (sin(n*x)/n, Ne(n, 0)), (x, True)) assert integrate(cos(n*x)**2, x) == Piecewise( ((n*x/2 + sin(n*x)*cos(n*x)/2)/n, Ne(n, 0)), (x, True)) assert integrate(x*cos(n*x), x) == Piecewise( (x*sin(n*x)/n + cos(n*x)/n**2, Ne(n, 0)), (x**2/2, True)) assert integrate(sin(n*x), x) == Piecewise( (-cos(n*x)/n, Ne(n, 0)), (0, True)) assert integrate(sin(n*x)**2, x) == Piecewise( ((n*x/2 - sin(n*x)*cos(n*x)/2)/n, Ne(n, 0)), (0, True)) assert integrate(x*sin(n*x), x) == Piecewise( (-x*cos(n*x)/n + sin(n*x)/n**2, Ne(n, 0)), (0, True)) assert integrate(exp(x*y), (x, 0, z)) == Piecewise( (exp(y*z)/y - 1/y, (y > -oo) & (y < oo) & Ne(y, 0)), (z, True)) def test_integrate_max_min(): x = symbols('x', real=True) assert integrate(Min(x, 2), (x, 0, 3)) == 4 assert integrate(Max(x**2, x**3), (x, 0, 2)) == Rational(49, 12) assert integrate(Min(exp(x), exp(-x))**2, x) == Piecewise( \ (exp(2*x)/2, x <= 0), (1 - exp(-2*x)/2, True)) # issue 7907 c = symbols('c', extended_real=True) int1 = integrate(Max(c, x)*exp(-x**2), (x, -oo, oo)) int2 = integrate(c*exp(-x**2), (x, -oo, c)) int3 = integrate(x*exp(-x**2), (x, c, oo)) assert int1 == int2 + int3 == sqrt(pi)*c*erf(c)/2 + \ sqrt(pi)*c/2 + exp(-c**2)/2 def test_integrate_Abs_sign(): assert integrate(Abs(x), (x, -2, 1)) == Rational(5, 2) assert integrate(Abs(x), (x, 0, 1)) == S.Half assert integrate(Abs(x + 1), (x, 0, 1)) == Rational(3, 2) assert integrate(Abs(x**2 - 1), (x, -2, 2)) == 4 assert integrate(Abs(x**2 - 3*x), (x, -15, 15)) == 2259 assert integrate(sign(x), (x, -1, 2)) == 1 assert integrate(sign(x)*sin(x), (x, -pi, pi)) == 4 assert integrate(sign(x - 2) * x**2, (x, 0, 3)) == Rational(11, 3) t, s = symbols('t s', real=True) assert integrate(Abs(t), t) == Piecewise( (-t**2/2, t <= 0), (t**2/2, True)) assert integrate(Abs(2*t - 6), t) == Piecewise( (-t**2 + 6*t, t <= 3), (t**2 - 6*t + 18, True)) assert (integrate(abs(t - s**2), (t, 0, 2)) == 2*s**2*Min(2, s**2) - 2*s**2 - Min(2, s**2)**2 + 2) assert integrate(exp(-Abs(t)), t) == Piecewise( (exp(t), t <= 0), (2 - exp(-t), True)) assert integrate(sign(2*t - 6), t) == Piecewise( (-t, t < 3), (t - 6, True)) assert integrate(2*t*sign(t**2 - 1), t) == Piecewise( (t**2, t < -1), (-t**2 + 2, t < 1), (t**2, True)) assert integrate(sign(t), (t, s + 1)) == Piecewise( (s + 1, s + 1 > 0), (-s - 1, s + 1 < 0), (0, True)) def test_subs1(): e = Integral(exp(x - y), x) assert e.subs(y, 3) == Integral(exp(x - 3), x) e = Integral(exp(x - y), (x, 0, 1)) assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 1)) f = Lambda(x, exp(-x**2)) conv = Integral(f(x - y)*f(y), (y, -oo, oo)) assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo)) def test_subs2(): e = Integral(exp(x - y), x, t) assert e.subs(y, 3) == Integral(exp(x - 3), x, t) e = Integral(exp(x - y), (x, 0, 1), (t, 0, 1)) assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 1), (t, 0, 1)) f = Lambda(x, exp(-x**2)) conv = Integral(f(x - y)*f(y), (y, -oo, oo), (t, 0, 1)) assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) def test_subs3(): e = Integral(exp(x - y), (x, 0, y), (t, y, 1)) assert e.subs(y, 3) == Integral(exp(x - 3), (x, 0, 3), (t, 3, 1)) f = Lambda(x, exp(-x**2)) conv = Integral(f(x - y)*f(y), (y, -oo, oo), (t, x, 1)) assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) def test_subs4(): e = Integral(exp(x), (x, 0, y), (t, y, 1)) assert e.subs(y, 3) == Integral(exp(x), (x, 0, 3), (t, 3, 1)) f = Lambda(x, exp(-x**2)) conv = Integral(f(y)*f(y), (y, -oo, oo), (t, x, 1)) assert conv.subs({x: 0}) == Integral(exp(-2*y**2), (y, -oo, oo), (t, 0, 1)) def test_subs5(): e = Integral(exp(-x**2), (x, -oo, oo)) assert e.subs(x, 5) == e e = Integral(exp(-x**2 + y), x) assert e.subs(y, 5) == Integral(exp(-x**2 + 5), x) e = Integral(exp(-x**2 + y), (x, x)) assert e.subs(x, 5) == Integral(exp(y - x**2), (x, 5)) assert e.subs(y, 5) == Integral(exp(-x**2 + 5), x) e = Integral(exp(-x**2 + y), (y, -oo, oo), (x, -oo, oo)) assert e.subs(x, 5) == e assert e.subs(y, 5) == e # Test evaluation of antiderivatives e = Integral(exp(-x**2), (x, x)) assert e.subs(x, 5) == Integral(exp(-x**2), (x, 5)) e = Integral(exp(x), x) assert (e.subs(x,1) - e.subs(x,0) - Integral(exp(x), (x, 0, 1)) ).doit().is_zero def test_subs6(): a, b = symbols('a b') e = Integral(x*y, (x, f(x), f(y))) assert e.subs(x, 1) == Integral(x*y, (x, f(1), f(y))) assert e.subs(y, 1) == Integral(x, (x, f(x), f(1))) e = Integral(x*y, (x, f(x), f(y)), (y, f(x), f(y))) assert e.subs(x, 1) == Integral(x*y, (x, f(1), f(y)), (y, f(1), f(y))) assert e.subs(y, 1) == Integral(x*y, (x, f(x), f(y)), (y, f(x), f(1))) e = Integral(x*y, (x, f(x), f(a)), (y, f(x), f(a))) assert e.subs(a, 1) == Integral(x*y, (x, f(x), f(1)), (y, f(x), f(1))) def test_subs7(): e = Integral(x, (x, 1, y), (y, 1, 2)) assert e.subs({x: 1, y: 2}) == e e = Integral(sin(x) + sin(y), (x, sin(x), sin(y)), (y, 1, 2)) assert e.subs(sin(y), 1) == e assert e.subs(sin(x), 1) == Integral(sin(x) + sin(y), (x, 1, sin(y)), (y, 1, 2)) def test_expand(): e = Integral(f(x)+f(x**2), (x, 1, y)) assert e.expand() == Integral(f(x), (x, 1, y)) + Integral(f(x**2), (x, 1, y)) def test_integration_variable(): raises(ValueError, lambda: Integral(exp(-x**2), 3)) raises(ValueError, lambda: Integral(exp(-x**2), (3, -oo, oo))) def test_expand_integral(): assert Integral(cos(x**2)*(sin(x**2) + 1), (x, 0, 1)).expand() == \ Integral(cos(x**2)*sin(x**2), (x, 0, 1)) + \ Integral(cos(x**2), (x, 0, 1)) assert Integral(cos(x**2)*(sin(x**2) + 1), x).expand() == \ Integral(cos(x**2)*sin(x**2), x) + \ Integral(cos(x**2), x) def test_as_sum_midpoint1(): e = Integral(sqrt(x**3 + 1), (x, 2, 10)) assert e.as_sum(1, method="midpoint") == 8*sqrt(217) assert e.as_sum(2, method="midpoint") == 4*sqrt(65) + 12*sqrt(57) assert e.as_sum(3, method="midpoint") == 8*sqrt(217)/3 + \ 8*sqrt(3081)/27 + 8*sqrt(52809)/27 assert e.as_sum(4, method="midpoint") == 2*sqrt(730) + \ 4*sqrt(7) + 4*sqrt(86) + 6*sqrt(14) assert abs(e.as_sum(4, method="midpoint").n() - e.n()) < 0.5 e = Integral(sqrt(x**3 + y**3), (x, 2, 10), (y, 0, 10)) raises(NotImplementedError, lambda: e.as_sum(4)) def test_as_sum_midpoint2(): e = Integral((x + y)**2, (x, 0, 1)) n = Symbol('n', positive=True, integer=True) assert e.as_sum(1, method="midpoint").expand() == Rational(1, 4) + y + y**2 assert e.as_sum(2, method="midpoint").expand() == Rational(5, 16) + y + y**2 assert e.as_sum(3, method="midpoint").expand() == Rational(35, 108) + y + y**2 assert e.as_sum(4, method="midpoint").expand() == Rational(21, 64) + y + y**2 assert e.as_sum(n, method="midpoint").expand() == \ y**2 + y + Rational(1, 3) - 1/(12*n**2) def test_as_sum_left(): e = Integral((x + y)**2, (x, 0, 1)) assert e.as_sum(1, method="left").expand() == y**2 assert e.as_sum(2, method="left").expand() == Rational(1, 8) + y/2 + y**2 assert e.as_sum(3, method="left").expand() == Rational(5, 27) + y*Rational(2, 3) + y**2 assert e.as_sum(4, method="left").expand() == Rational(7, 32) + y*Rational(3, 4) + y**2 assert e.as_sum(n, method="left").expand() == \ y**2 + y + Rational(1, 3) - y/n - 1/(2*n) + 1/(6*n**2) assert e.as_sum(10, method="left", evaluate=False).has(Sum) def test_as_sum_right(): e = Integral((x + y)**2, (x, 0, 1)) assert e.as_sum(1, method="right").expand() == 1 + 2*y + y**2 assert e.as_sum(2, method="right").expand() == Rational(5, 8) + y*Rational(3, 2) + y**2 assert e.as_sum(3, method="right").expand() == Rational(14, 27) + y*Rational(4, 3) + y**2 assert e.as_sum(4, method="right").expand() == Rational(15, 32) + y*Rational(5, 4) + y**2 assert e.as_sum(n, method="right").expand() == \ y**2 + y + Rational(1, 3) + y/n + 1/(2*n) + 1/(6*n**2) def test_as_sum_trapezoid(): e = Integral((x + y)**2, (x, 0, 1)) assert e.as_sum(1, method="trapezoid").expand() == y**2 + y + S.Half assert e.as_sum(2, method="trapezoid").expand() == y**2 + y + Rational(3, 8) assert e.as_sum(3, method="trapezoid").expand() == y**2 + y + Rational(19, 54) assert e.as_sum(4, method="trapezoid").expand() == y**2 + y + Rational(11, 32) assert e.as_sum(n, method="trapezoid").expand() == \ y**2 + y + Rational(1, 3) + 1/(6*n**2) assert Integral(sign(x), (x, 0, 1)).as_sum(1, 'trapezoid') == S.Half def test_as_sum_raises(): e = Integral((x + y)**2, (x, 0, 1)) raises(ValueError, lambda: e.as_sum(-1)) raises(ValueError, lambda: e.as_sum(0)) raises(ValueError, lambda: Integral(x).as_sum(3)) raises(ValueError, lambda: e.as_sum(oo)) raises(ValueError, lambda: e.as_sum(3, method='xxxx2')) def test_nested_doit(): e = Integral(Integral(x, x), x) f = Integral(x, x, x) assert e.doit() == f.doit() def test_issue_4665(): # Allow only upper or lower limit evaluation e = Integral(x**2, (x, None, 1)) f = Integral(x**2, (x, 1, None)) assert e.doit() == Rational(1, 3) assert f.doit() == Rational(-1, 3) assert Integral(x*y, (x, None, y)).subs(y, t) == Integral(x*t, (x, None, t)) assert Integral(x*y, (x, y, None)).subs(y, t) == Integral(x*t, (x, t, None)) assert integrate(x**2, (x, None, 1)) == Rational(1, 3) assert integrate(x**2, (x, 1, None)) == Rational(-1, 3) assert integrate("x**2", ("x", "1", None)) == Rational(-1, 3) def test_integral_reconstruct(): e = Integral(x**2, (x, -1, 1)) assert e == Integral(*e.args) def test_doit_integrals(): e = Integral(Integral(2*x), (x, 0, 1)) assert e.doit() == Rational(1, 3) assert e.doit(deep=False) == Rational(1, 3) f = Function('f') # doesn't matter if the integral can't be performed assert Integral(f(x), (x, 1, 1)).doit() == 0 # doesn't matter if the limits can't be evaluated assert Integral(0, (x, 1, Integral(f(x), x))).doit() == 0 assert Integral(x, (a, 0)).doit() == 0 limits = ((a, 1, exp(x)), (x, 0)) assert Integral(a, *limits).doit() == Rational(1, 4) assert Integral(a, *list(reversed(limits))).doit() == 0 def test_issue_4884(): assert integrate(sqrt(x)*(1 + x)) == \ Piecewise( (2*sqrt(x)*(x + 1)**2/5 - 2*sqrt(x)*(x + 1)/15 - 4*sqrt(x)/15, Abs(x + 1) > 1), (2*I*sqrt(-x)*(x + 1)**2/5 - 2*I*sqrt(-x)*(x + 1)/15 - 4*I*sqrt(-x)/15, True)) assert integrate(x**x*(1 + log(x))) == x**x def test_issue_18153(): assert integrate(x**n*log(x),x) == \ Piecewise( (n*x*x**n*log(x)/(n**2 + 2*n + 1) + x*x**n*log(x)/(n**2 + 2*n + 1) - x*x**n/(n**2 + 2*n + 1) , Ne(n, -1)), (log(x)**2/2, True) ) def test_is_number(): from sympy.abc import x, y, z from sympy import cos, sin assert Integral(x).is_number is False assert Integral(1, x).is_number is False assert Integral(1, (x, 1)).is_number is True assert Integral(1, (x, 1, 2)).is_number is True assert Integral(1, (x, 1, y)).is_number is False assert Integral(1, (x, y)).is_number is False assert Integral(x, y).is_number is False assert Integral(x, (y, 1, x)).is_number is False assert Integral(x, (y, 1, 2)).is_number is False assert Integral(x, (x, 1, 2)).is_number is True # `foo.is_number` should always be equivalent to `not foo.free_symbols` # in each of these cases, there are pseudo-free symbols i = Integral(x, (y, 1, 1)) assert i.is_number is False and i.n() == 0 i = Integral(x, (y, z, z)) assert i.is_number is False and i.n() == 0 i = Integral(1, (y, z, z + 2)) assert i.is_number is False and i.n() == 2 assert Integral(x*y, (x, 1, 2), (y, 1, 3)).is_number is True assert Integral(x*y, (x, 1, 2), (y, 1, z)).is_number is False assert Integral(x, (x, 1)).is_number is True assert Integral(x, (x, 1, Integral(y, (y, 1, 2)))).is_number is True assert Integral(Sum(z, (z, 1, 2)), (x, 1, 2)).is_number is True # it is possible to get a false negative if the integrand is # actually an unsimplified zero, but this is true of is_number in general. assert Integral(sin(x)**2 + cos(x)**2 - 1, x).is_number is False assert Integral(f(x), (x, 0, 1)).is_number is True def test_symbols(): from sympy.abc import x, y, z assert Integral(0, x).free_symbols == {x} assert Integral(x).free_symbols == {x} assert Integral(x, (x, None, y)).free_symbols == {y} assert Integral(x, (x, y, None)).free_symbols == {y} assert Integral(x, (x, 1, y)).free_symbols == {y} assert Integral(x, (x, y, 1)).free_symbols == {y} assert Integral(x, (x, x, y)).free_symbols == {x, y} assert Integral(x, x, y).free_symbols == {x, y} assert Integral(x, (x, 1, 2)).free_symbols == set() assert Integral(x, (y, 1, 2)).free_symbols == {x} # pseudo-free in this case assert Integral(x, (y, z, z)).free_symbols == {x, z} assert Integral(x, (y, 1, 2), (y, None, None)).free_symbols == {x, y} assert Integral(x, (y, 1, 2), (x, 1, y)).free_symbols == {y} assert Integral(2, (y, 1, 2), (y, 1, x), (x, 1, 2)).free_symbols == set() assert Integral(2, (y, x, 2), (y, 1, x), (x, 1, 2)).free_symbols == set() assert Integral(2, (x, 1, 2), (y, x, 2), (y, 1, 2)).free_symbols == \ {x} def test_is_zero(): from sympy.abc import x, m assert Integral(0, (x, 1, x)).is_zero assert Integral(1, (x, 1, 1)).is_zero assert Integral(1, (x, 1, 2), (y, 2)).is_zero is False assert Integral(x, (m, 0)).is_zero assert Integral(x + m, (m, 0)).is_zero is None i = Integral(m, (m, 1, exp(x)), (x, 0)) assert i.is_zero is None assert Integral(m, (x, 0), (m, 1, exp(x))).is_zero is True assert Integral(x, (x, oo, oo)).is_zero # issue 8171 assert Integral(x, (x, -oo, -oo)).is_zero # this is zero but is beyond the scope of what is_zero # should be doing assert Integral(sin(x), (x, 0, 2*pi)).is_zero is None def test_series(): from sympy.abc import x i = Integral(cos(x), (x, x)) e = i.lseries(x) assert i.nseries(x, n=8).removeO() == Add(*[next(e) for j in range(4)]) def test_trig_nonelementary_integrals(): x = Symbol('x') assert integrate((1 + sin(x))/x, x) == log(x) + Si(x) # next one comes out as log(x) + log(x**2)/2 + Ci(x) # so not hardcoding this log ugliness assert integrate((cos(x) + 2)/x, x).has(Ci) def test_issue_4403(): x = Symbol('x') y = Symbol('y') z = Symbol('z', positive=True) assert integrate(sqrt(x**2 + z**2), x) == \ z**2*asinh(x/z)/2 + x*sqrt(x**2 + z**2)/2 assert integrate(sqrt(x**2 - z**2), x) == \ -z**2*acosh(x/z)/2 + x*sqrt(x**2 - z**2)/2 x = Symbol('x', real=True) y = Symbol('y', positive=True) assert integrate(1/(x**2 + y**2)**S('3/2'), x) == \ x/(y**2*sqrt(x**2 + y**2)) # If y is real and nonzero, we get x*Abs(y)/(y**3*sqrt(x**2 + y**2)), # which results from sqrt(1 + x**2/y**2) = sqrt(x**2 + y**2)/|y|. def test_issue_4403_2(): assert integrate(sqrt(-x**2 - 4), x) == \ -2*atan(x/sqrt(-4 - x**2)) + x*sqrt(-4 - x**2)/2 def test_issue_4100(): R = Symbol('R', positive=True) assert integrate(sqrt(R**2 - x**2), (x, 0, R)) == pi*R**2/4 def test_issue_5167(): from sympy.abc import w, x, y, z f = Function('f') assert Integral(Integral(f(x), x), x) == Integral(f(x), x, x) assert Integral(f(x)).args == (f(x), Tuple(x)) assert Integral(Integral(f(x))).args == (f(x), Tuple(x), Tuple(x)) assert Integral(Integral(f(x)), y).args == (f(x), Tuple(x), Tuple(y)) assert Integral(Integral(f(x), z), y).args == (f(x), Tuple(z), Tuple(y)) assert Integral(Integral(Integral(f(x), x), y), z).args == \ (f(x), Tuple(x), Tuple(y), Tuple(z)) assert integrate(Integral(f(x), x), x) == Integral(f(x), x, x) assert integrate(Integral(f(x), y), x) == y*Integral(f(x), x) assert integrate(Integral(f(x), x), y) in [Integral(y*f(x), x), y*Integral(f(x), x)] assert integrate(Integral(2, x), x) == x**2 assert integrate(Integral(2, x), y) == 2*x*y # don't re-order given limits assert Integral(1, x, y).args != Integral(1, y, x).args # do as many as possible assert Integral(f(x), y, x, y, x).doit() == y**2*Integral(f(x), x, x)/2 assert Integral(f(x), (x, 1, 2), (w, 1, x), (z, 1, y)).doit() == \ y*(x - 1)*Integral(f(x), (x, 1, 2)) - (x - 1)*Integral(f(x), (x, 1, 2)) def test_issue_4890(): z = Symbol('z', positive=True) assert integrate(exp(-log(x)**2), x) == \ sqrt(pi)*exp(Rational(1, 4))*erf(log(x) - S.Half)/2 assert integrate(exp(log(x)**2), x) == \ sqrt(pi)*exp(Rational(-1, 4))*erfi(log(x)+S.Half)/2 assert integrate(exp(-z*log(x)**2), x) == \ sqrt(pi)*exp(1/(4*z))*erf(sqrt(z)*log(x) - 1/(2*sqrt(z)))/(2*sqrt(z)) def test_issue_4551(): assert not integrate(1/(x*sqrt(1 - x**2)), x).has(Integral) def test_issue_4376(): n = Symbol('n', integer=True, positive=True) assert simplify(integrate(n*(x**(1/n) - 1), (x, 0, S.Half)) - (n**2 - 2**(1/n)*n**2 - n*2**(1/n))/(2**(1 + 1/n) + n*2**(1 + 1/n))) == 0 def test_issue_4517(): assert integrate((sqrt(x) - x**3)/x**Rational(1, 3), x) == \ 6*x**Rational(7, 6)/7 - 3*x**Rational(11, 3)/11 def test_issue_4527(): k, m = symbols('k m', integer=True) assert integrate(sin(k*x)*sin(m*x), (x, 0, pi)).simplify() == \ Piecewise((0, Eq(k, 0) | Eq(m, 0)), (-pi/2, Eq(k, -m) | (Eq(k, 0) & Eq(m, 0))), (pi/2, Eq(k, m) | (Eq(k, 0) & Eq(m, 0))), (0, True)) # Should be possible to further simplify to: # Piecewise( # (0, Eq(k, 0) | Eq(m, 0)), # (-pi/2, Eq(k, -m)), # (pi/2, Eq(k, m)), # (0, True)) assert integrate(sin(k*x)*sin(m*x), (x,)) == Piecewise( (0, And(Eq(k, 0), Eq(m, 0))), (-x*sin(m*x)**2/2 - x*cos(m*x)**2/2 + sin(m*x)*cos(m*x)/(2*m), Eq(k, -m)), (x*sin(m*x)**2/2 + x*cos(m*x)**2/2 - sin(m*x)*cos(m*x)/(2*m), Eq(k, m)), (m*sin(k*x)*cos(m*x)/(k**2 - m**2) - k*sin(m*x)*cos(k*x)/(k**2 - m**2), True)) def test_issue_4199(): ypos = Symbol('y', positive=True) # TODO: Remove conds='none' below, let the assumption take care of it. assert integrate(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo), conds='none') == \ Integral(exp(-I*2*pi*ypos*x)*x, (x, -oo, oo)) def test_issue_3940(): a, b, c, d = symbols('a:d', positive=True, finite=True) assert integrate(exp(-x**2 + I*c*x), x) == \ -sqrt(pi)*exp(-c**2/4)*erf(I*c/2 - x)/2 assert integrate(exp(a*x**2 + b*x + c), x) == \ sqrt(pi)*exp(c)*exp(-b**2/(4*a))*erfi(sqrt(a)*x + b/(2*sqrt(a)))/(2*sqrt(a)) from sympy import expand_mul from sympy.abc import k assert expand_mul(integrate(exp(-x**2)*exp(I*k*x), (x, -oo, oo))) == \ sqrt(pi)*exp(-k**2/4) a, d = symbols('a d', positive=True) assert expand_mul(integrate(exp(-a*x**2 + 2*d*x), (x, -oo, oo))) == \ sqrt(pi)*exp(d**2/a)/sqrt(a) def test_issue_5413(): # Note that this is not the same as testing ratint() because integrate() # pulls out the coefficient. assert integrate(-a/(a**2 + x**2), x) == I*log(-I*a + x)/2 - I*log(I*a + x)/2 def test_issue_4892a(): A, z = symbols('A z') c = Symbol('c', nonzero=True) P1 = -A*exp(-z) P2 = -A/(c*t)*(sin(x)**2 + cos(y)**2) h1 = -sin(x)**2 - cos(y)**2 h2 = -sin(x)**2 + sin(y)**2 - 1 # there is still some non-deterministic behavior in integrate # or trigsimp which permits one of the following assert integrate(c*(P2 - P1), t) in [ c*(-A*(-h1)*log(c*t)/c + A*t*exp(-z)), c*(-A*(-h2)*log(c*t)/c + A*t*exp(-z)), c*( A* h1 *log(c*t)/c + A*t*exp(-z)), c*( A* h2 *log(c*t)/c + A*t*exp(-z)), (A*c*t - A*(-h1)*log(t)*exp(z))*exp(-z), (A*c*t - A*(-h2)*log(t)*exp(z))*exp(-z), ] def test_issue_4892b(): # Issues relating to issue 4596 are making the actual result of this hard # to test. The answer should be something like # # (-sin(y) + sqrt(-72 + 48*cos(y) - 8*cos(y)**2)/2)*log(x + sqrt(-72 + # 48*cos(y) - 8*cos(y)**2)/(2*(3 - cos(y)))) + (-sin(y) - sqrt(-72 + # 48*cos(y) - 8*cos(y)**2)/2)*log(x - sqrt(-72 + 48*cos(y) - # 8*cos(y)**2)/(2*(3 - cos(y)))) + x**2*sin(y)/2 + 2*x*cos(y) expr = (sin(y)*x**3 + 2*cos(y)*x**2 + 12)/(x**2 + 2) assert trigsimp(factor(integrate(expr, x).diff(x) - expr)) == 0 def test_issue_5178(): assert integrate(sin(x)*f(y, z), (x, 0, pi), (y, 0, pi), (z, 0, pi)) == \ 2*Integral(f(y, z), (y, 0, pi), (z, 0, pi)) def test_integrate_series(): f = sin(x).series(x, 0, 10) g = x**2/2 - x**4/24 + x**6/720 - x**8/40320 + x**10/3628800 + O(x**11) assert integrate(f, x) == g assert diff(integrate(f, x), x) == f assert integrate(O(x**5), x) == O(x**6) def test_atom_bug(): from sympy import meijerg from sympy.integrals.heurisch import heurisch assert heurisch(meijerg([], [], [1], [], x), x) is None def test_limit_bug(): z = Symbol('z', zero=False) assert integrate(sin(x*y*z), (x, 0, pi), (y, 0, pi)).together() == \ (log(z) - Ci(pi**2*z) + EulerGamma + 2*log(pi))/z def test_issue_4703(): g = Function('g') assert integrate(exp(x)*g(x), x).has(Integral) def test_issue_1888(): f = Function('f') assert integrate(f(x).diff(x)**2, x).has(Integral) # The following tests work using meijerint. def test_issue_3558(): from sympy import Si assert integrate(cos(x*y), (x, -pi/2, pi/2), (y, 0, pi)) == 2*Si(pi**2/2) def test_issue_4422(): assert integrate(1/sqrt(16 + 4*x**2), x) == asinh(x/2) / 2 def test_issue_4493(): from sympy import simplify assert simplify(integrate(x*sqrt(1 + 2*x), x)) == \ sqrt(2*x + 1)*(6*x**2 + x - 1)/15 def test_issue_4737(): assert integrate(sin(x)/x, (x, -oo, oo)) == pi assert integrate(sin(x)/x, (x, 0, oo)) == pi/2 assert integrate(sin(x)/x, x) == Si(x) def test_issue_4992(): # Note: psi in _check_antecedents becomes NaN. from sympy import simplify, expand_func, polygamma, gamma a = Symbol('a', positive=True) assert simplify(expand_func(integrate(exp(-x)*log(x)*x**a, (x, 0, oo)))) == \ (a*polygamma(0, a) + 1)*gamma(a) def test_issue_4487(): from sympy import lowergamma, simplify assert simplify(integrate(exp(-x)*x**y, x)) == lowergamma(y + 1, x) def test_issue_4215(): x = Symbol("x") assert integrate(1/(x**2), (x, -1, 1)) is oo def test_issue_4400(): n = Symbol('n', integer=True, positive=True) assert integrate((x**n)*log(x), x) == \ n*x*x**n*log(x)/(n**2 + 2*n + 1) + x*x**n*log(x)/(n**2 + 2*n + 1) - \ x*x**n/(n**2 + 2*n + 1) def test_issue_6253(): # Note: this used to raise NotImplementedError # Note: psi in _check_antecedents becomes NaN. assert integrate((sqrt(1 - x) + sqrt(1 + x))**2/x, x, meijerg=True) == \ Integral((sqrt(-x + 1) + sqrt(x + 1))**2/x, x) def test_issue_4153(): assert integrate(1/(1 + x + y + z), (x, 0, 1), (y, 0, 1), (z, 0, 1)) in [ -12*log(3) - 3*log(6)/2 + 3*log(8)/2 + 5*log(2) + 7*log(4), 6*log(2) + 8*log(4) - 27*log(3)/2, 22*log(2) - 27*log(3)/2, -12*log(3) - 3*log(6)/2 + 47*log(2)/2] def test_issue_4326(): R, b, h = symbols('R b h') # It doesn't matter if we can do the integral. Just make sure the result # doesn't contain nan. This is really a test against _eval_interval. e = integrate(((h*(x - R + b))/b)*sqrt(R**2 - x**2), (x, R - b, R)) assert not e.has(nan) # See that it evaluates assert not e.has(Integral) def test_powers(): assert integrate(2**x + 3**x, x) == 2**x/log(2) + 3**x/log(3) def test_manual_option(): raises(ValueError, lambda: integrate(1/x, x, manual=True, meijerg=True)) # an example of a function that manual integration cannot handle assert integrate(log(1+x)/x, (x, 0, 1), manual=True).has(Integral) def test_meijerg_option(): raises(ValueError, lambda: integrate(1/x, x, meijerg=True, risch=True)) # an example of a function that meijerg integration cannot handle assert integrate(tan(x), x, meijerg=True) == Integral(tan(x), x) def test_risch_option(): # risch=True only allowed on indefinite integrals raises(ValueError, lambda: integrate(1/log(x), (x, 0, oo), risch=True)) assert integrate(exp(-x**2), x, risch=True) == NonElementaryIntegral(exp(-x**2), x) assert integrate(log(1/x)*y, x, y, risch=True) == y**2*(x*log(1/x)/2 + x/2) assert integrate(erf(x), x, risch=True) == Integral(erf(x), x) # TODO: How to test risch=False? @slow def test_heurisch_option(): raises(ValueError, lambda: integrate(1/x, x, risch=True, heurisch=True)) # an integral that heurisch can handle assert integrate(exp(x**2), x, heurisch=True) == sqrt(pi)*erfi(x)/2 # an integral that heurisch currently cannot handle assert integrate(exp(x)/x, x, heurisch=True) == Integral(exp(x)/x, x) # an integral where heurisch currently hangs, issue 15471 assert integrate(log(x)*cos(log(x))/x**Rational(3, 4), x, heurisch=False) == ( -128*x**Rational(1, 4)*sin(log(x))/289 + 240*x**Rational(1, 4)*cos(log(x))/289 + (16*x**Rational(1, 4)*sin(log(x))/17 + 4*x**Rational(1, 4)*cos(log(x))/17)*log(x)) def test_issue_6828(): f = 1/(1.08*x**2 - 4.3) g = integrate(f, x).diff(x) assert verify_numerically(f, g, tol=1e-12) def test_issue_4803(): x_max = Symbol("x_max") assert integrate(y/pi*exp(-(x_max - x)/cos(a)), x) == \ y*exp((x - x_max)/cos(a))*cos(a)/pi def test_issue_4234(): assert integrate(1/sqrt(1 + tan(x)**2)) == tan(x)/sqrt(1 + tan(x)**2) def test_issue_4492(): assert simplify(integrate(x**2 * sqrt(5 - x**2), x)) == Piecewise( (I*(2*x**5 - 15*x**3 + 25*x - 25*sqrt(x**2 - 5)*acosh(sqrt(5)*x/5)) / (8*sqrt(x**2 - 5)), 1 < Abs(x**2)/5), ((-2*x**5 + 15*x**3 - 25*x + 25*sqrt(-x**2 + 5)*asin(sqrt(5)*x/5)) / (8*sqrt(-x**2 + 5)), True)) def test_issue_2708(): # This test needs to use an integration function that can # not be evaluated in closed form. Update as needed. f = 1/(a + z + log(z)) integral_f = NonElementaryIntegral(f, (z, 2, 3)) assert Integral(f, (z, 2, 3)).doit() == integral_f assert integrate(f + exp(z), (z, 2, 3)) == integral_f - exp(2) + exp(3) assert integrate(2*f + exp(z), (z, 2, 3)) == \ 2*integral_f - exp(2) + exp(3) assert integrate(exp(1.2*n*s*z*(-t + z)/t), (z, 0, x)) == \ NonElementaryIntegral(exp(-1.2*n*s*z)*exp(1.2*n*s*z**2/t), (z, 0, x)) def test_issue_2884(): f = (4.000002016020*x + 4.000002016020*y + 4.000006024032)*exp(10.0*x) e = integrate(f, (x, 0.1, 0.2)) assert str(e) == '1.86831064982608*y + 2.16387491480008' def test_issue_8368(): assert integrate(exp(-s*x)*cosh(x), (x, 0, oo)) == \ Piecewise( ( pi*Piecewise( ( -s/(pi*(-s**2 + 1)), Abs(s**2) < 1), ( 1/(pi*s*(1 - 1/s**2)), Abs(s**(-2)) < 1), ( meijerg( ((S.Half,), (0, 0)), ((0, S.Half), (0,)), polar_lift(s)**2), True) ), And( Abs(periodic_argument(polar_lift(s)**2, oo)) < pi, cos(Abs(periodic_argument(polar_lift(s)**2, oo))/2)*sqrt(Abs(s**2)) - 1 > 0, Ne(s**2, 1)) ), ( Integral(exp(-s*x)*cosh(x), (x, 0, oo)), True)) assert integrate(exp(-s*x)*sinh(x), (x, 0, oo)) == \ Piecewise( ( -1/(s + 1)/2 - 1/(-s + 1)/2, And( Ne(1/s, 1), Abs(periodic_argument(s, oo)) < pi/2, Abs(periodic_argument(s, oo)) <= pi/2, cos(Abs(periodic_argument(s, oo)))*Abs(s) - 1 > 0)), ( Integral(exp(-s*x)*sinh(x), (x, 0, oo)), True)) def test_issue_8901(): assert integrate(sinh(1.0*x)) == 1.0*cosh(1.0*x) assert integrate(tanh(1.0*x)) == 1.0*x - 1.0*log(tanh(1.0*x) + 1) assert integrate(tanh(x)) == x - log(tanh(x) + 1) @slow def test_issue_8945(): assert integrate(sin(x)**3/x, (x, 0, 1)) == -Si(3)/4 + 3*Si(1)/4 assert integrate(sin(x)**3/x, (x, 0, oo)) == pi/4 assert integrate(cos(x)**2/x**2, x) == -Si(2*x) - cos(2*x)/(2*x) - 1/(2*x) @slow def test_issue_7130(): if ON_TRAVIS: skip("Too slow for travis.") i, L, a, b = symbols('i L a b') integrand = (cos(pi*i*x/L)**2 / (a + b*x)).rewrite(exp) assert x not in integrate(integrand, (x, 0, L)).free_symbols def test_issue_10567(): a, b, c, t = symbols('a b c t') vt = Matrix([a*t, b, c]) assert integrate(vt, t) == Integral(vt, t).doit() assert integrate(vt, t) == Matrix([[a*t**2/2], [b*t], [c*t]]) def test_issue_11856(): t = symbols('t') assert integrate(sinc(pi*t), t) == Si(pi*t)/pi @slow def test_issue_11876(): assert integrate(sqrt(log(1/x)), (x, 0, 1)) == sqrt(pi)/2 def test_issue_4950(): assert integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) ==\ -2.4*exp(8*x) - 12.0*exp(5*x) def test_issue_4968(): assert integrate(sin(log(x**2))) == x*sin(log(x**2))/5 - 2*x*cos(log(x**2))/5 def test_singularities(): assert integrate(1/x**2, (x, -oo, oo)) is oo assert integrate(1/x**2, (x, -1, 1)) is oo assert integrate(1/(x - 1)**2, (x, -2, 2)) is oo assert integrate(1/x**2, (x, 1, -1)) is -oo assert integrate(1/(x - 1)**2, (x, 2, -2)) is -oo def test_issue_12645(): x, y = symbols('x y', real=True) assert (integrate(sin(x*x*x + y*y), (x, -sqrt(pi - y*y), sqrt(pi - y*y)), (y, -sqrt(pi), sqrt(pi))) == Integral(sin(x**3 + y**2), (x, -sqrt(-y**2 + pi), sqrt(-y**2 + pi)), (y, -sqrt(pi), sqrt(pi)))) def test_issue_12677(): assert integrate(sin(x) / (cos(x)**3) , (x, 0, pi/6)) == Rational(1,6) def test_issue_14078(): assert integrate((cos(3*x)-cos(x))/x, (x, 0, oo)) == -log(3) def test_issue_14064(): assert integrate(1/cosh(x), (x, 0, oo)) == pi/2 def test_issue_14027(): assert integrate(1/(1 + exp(x - S.Half)/(1 + exp(x))), x) == \ x - exp(S.Half)*log(exp(x) + exp(S.Half)/(1 + exp(S.Half)))/(exp(S.Half) + E) def test_issue_8170(): assert integrate(tan(x), (x, 0, pi/2)) is S.Infinity def test_issue_8440_14040(): assert integrate(1/x, (x, -1, 1)) is S.NaN assert integrate(1/(x + 1), (x, -2, 3)) is S.NaN def test_issue_14096(): assert integrate(1/(x + y)**2, (x, 0, 1)) == -1/(y + 1) + 1/y assert integrate(1/(1 + x + y + z)**2, (x, 0, 1), (y, 0, 1), (z, 0, 1)) == \ -4*log(4) - 6*log(2) + 9*log(3) def test_issue_14144(): assert Abs(integrate(1/sqrt(1 - x**3), (x, 0, 1)).n() - 1.402182) < 1e-6 assert Abs(integrate(sqrt(1 - x**3), (x, 0, 1)).n() - 0.841309) < 1e-6 def test_issue_14375(): # This raised a TypeError. The antiderivative has exp_polar, which # may be possible to unpolarify, so the exact output is not asserted here. assert integrate(exp(I*x)*log(x), x).has(Ei) def test_issue_14437(): f = Function('f')(x, y, z) assert integrate(f, (x, 0, 1), (y, 0, 2), (z, 0, 3)) == \ Integral(f, (x, 0, 1), (y, 0, 2), (z, 0, 3)) def test_issue_14470(): assert integrate(1/sqrt(exp(x) + 1), x) == \ log(-1 + 1/sqrt(exp(x) + 1)) - log(1 + 1/sqrt(exp(x) + 1)) def test_issue_14877(): f = exp(1 - exp(x**2)*x + 2*x**2)*(2*x**3 + x)/(1 - exp(x**2)*x)**2 assert integrate(f, x) == \ -exp(2*x**2 - x*exp(x**2) + 1)/(x*exp(3*x**2) - exp(2*x**2)) def test_issue_14782(): f = sqrt(-x**2 + 1)*(-x**2 + x) assert integrate(f, [x, -1, 1]) == - pi / 8 @slow def test_issue_14782_slow(): f = sqrt(-x**2 + 1)*(-x**2 + x) assert integrate(f, [x, 0, 1]) == S.One / 3 - pi / 16 def test_issue_12081(): f = x**(Rational(-3, 2))*exp(-x) assert integrate(f, [x, 0, oo]) is oo def test_issue_15285(): y = 1/x - 1 f = 4*y*exp(-2*y)/x**2 assert integrate(f, [x, 0, 1]) == 1 def test_issue_15432(): assert integrate(x**n * exp(-x) * log(x), (x, 0, oo)).gammasimp() == Piecewise( (gamma(n + 1)*polygamma(0, n) + gamma(n + 1)/n, re(n) + 1 > 0), (Integral(x**n*exp(-x)*log(x), (x, 0, oo)), True)) def test_issue_15124(): omega = IndexedBase('omega') m, p = symbols('m p', cls=Idx) assert integrate(exp(x*I*(omega[m] + omega[p])), x, conds='none') == \ -I*exp(I*x*omega[m])*exp(I*x*omega[p])/(omega[m] + omega[p]) def test_issue_15218(): with warns_deprecated_sympy(): Integral(Eq(x, y)) with warns_deprecated_sympy(): assert Integral(Eq(x, y), x) == Eq(Integral(x, x), Integral(y, x)) with warns_deprecated_sympy(): assert Integral(Eq(x, y), x).doit() == Eq(x**2/2, x*y) with warns_deprecated_sympy(): assert Eq(x, y).integrate(x) == Eq(x**2/2, x*y) # These are not deprecated because they are definite integrals assert integrate(Eq(x, y), (x, 0, 1)) == Eq(S.Half, y) assert Eq(x, y).integrate((x, 0, 1)) == Eq(S.Half, y) def test_issue_15292(): res = integrate(exp(-x**2*cos(2*t)) * cos(x**2*sin(2*t)), (x, 0, oo)) assert isinstance(res, Piecewise) assert gammasimp((res - sqrt(pi)/2 * cos(t)).subs(t, pi/6)) == 0 def test_issue_4514(): assert integrate(sin(2*x)/sin(x), x) == 2*sin(x) def test_issue_15457(): x, a, b = symbols('x a b', real=True) definite = integrate(exp(Abs(x-2)), (x, a, b)) indefinite = integrate(exp(Abs(x-2)), x) assert definite.subs({a: 1, b: 3}) == -2 + 2*E assert indefinite.subs(x, 3) - indefinite.subs(x, 1) == -2 + 2*E assert definite.subs({a: -3, b: -1}) == -exp(3) + exp(5) assert indefinite.subs(x, -1) - indefinite.subs(x, -3) == -exp(3) + exp(5) def test_issue_15431(): assert integrate(x*exp(x)*log(x), x) == \ (x*exp(x) - exp(x))*log(x) - exp(x) + Ei(x) def test_issue_15640_log_substitutions(): f = x/log(x) F = Ei(2*log(x)) assert integrate(f, x) == F and F.diff(x) == f f = x**3/log(x)**2 F = -x**4/log(x) + 4*Ei(4*log(x)) assert integrate(f, x) == F and F.diff(x) == f f = sqrt(log(x))/x**2 F = -sqrt(pi)*erfc(sqrt(log(x)))/2 - sqrt(log(x))/x assert integrate(f, x) == F and F.diff(x) == f def test_issue_15509(): from sympy.vector import CoordSys3D N = CoordSys3D('N') x = N.x assert integrate(cos(a*x + b), (x, x_1, x_2), heurisch=True) == Piecewise( (-sin(a*x_1 + b)/a + sin(a*x_2 + b)/a, (a > -oo) & (a < oo) & Ne(a, 0)), \ (-x_1*cos(b) + x_2*cos(b), True)) def test_issue_4311_fast(): x = symbols('x', real=True) assert integrate(x*abs(9-x**2), x) == Piecewise( (x**4/4 - 9*x**2/2, x <= -3), (-x**4/4 + 9*x**2/2 - Rational(81, 2), x <= 3), (x**4/4 - 9*x**2/2, True)) def test_integrate_with_complex_constants(): K = Symbol('K', real=True, positive=True) x = Symbol('x', real=True) m = Symbol('m', real=True) t = Symbol('t', real=True) assert integrate(exp(-I*K*x**2+m*x), x) == sqrt(I)*sqrt(pi)*exp(-I*m**2 /(4*K))*erfi((-2*I*K*x + m)/(2*sqrt(K)*sqrt(-I)))/(2*sqrt(K)) assert integrate(1/(1 + I*x**2), x) == (-I*(sqrt(-I)*log(x - I*sqrt(-I))/2 - sqrt(-I)*log(x + I*sqrt(-I))/2)) assert integrate(exp(-I*x**2), x) == sqrt(pi)*erf(sqrt(I)*x)/(2*sqrt(I)) assert integrate((1/(exp(I*t)-2)), t) == -t/2 - I*log(exp(I*t) - 2)/2 assert integrate((1/(exp(I*t)-2)), (t, 0, 2*pi)) == -pi def test_issue_14241(): x = Symbol('x') n = Symbol('n', positive=True, integer=True) assert integrate(n * x ** (n - 1) / (x + 1), x) == \ n**2*x**n*lerchphi(x*exp_polar(I*pi), 1, n)*gamma(n)/gamma(n + 1) def test_issue_13112(): assert integrate(sin(t)**2 / (5 - 4*cos(t)), [t, 0, 2*pi]) == pi / 4 @slow def test_issue_14709b(): h = Symbol('h', positive=True) i = integrate(x*acos(1 - 2*x/h), (x, 0, h)) assert i == 5*h**2*pi/16 def test_issue_8614(): x = Symbol('x') t = Symbol('t') assert integrate(exp(t)/t, (t, -oo, x)) == Ei(x) assert integrate((exp(-x) - exp(-2*x))/x, (x, 0, oo)) == log(2) @slow def test_issue_15494(): s = symbols('s', real=True, positive=True) integrand = (exp(s/2) - 2*exp(1.6*s) + exp(s))*exp(s) solution = integrate(integrand, s) assert solution != S.NaN # Not sure how to test this properly as it is a symbolic expression with floats # assert str(solution) == '0.666666666666667*exp(1.5*s) + 0.5*exp(2.0*s) - 0.769230769230769*exp(2.6*s)' # Maybe assert abs(solution.subs(s, 1) - (-3.67440080236188)) <= 1e-8 integrand = (exp(s/2) - 2*exp(S(8)/5*s) + exp(s))*exp(s) assert integrate(integrand, s) == -10*exp(13*s/5)/13 + 2*exp(3*s/2)/3 + exp(2*s)/2 def test_li_integral(): y = Symbol('y') assert Integral(li(y*x**2), x).doit() == Piecewise((x*li(x**2*y) - \ x*Ei(3*log(x**2*y)/2)/sqrt(x**2*y), Ne(y, 0)), (0, True)) def test_issue_17473(): x = Symbol('x') n = Symbol('n') assert integrate(sin(x**n), x) == \ x*x**n*gamma(S(1)/2 + 1/(2*n))*hyper((S(1)/2 + 1/(2*n),), (S(3)/2, S(3)/2 + 1/(2*n)), -x**(2*n)/4)/(2*n*gamma(S(3)/2 + 1/(2*n))) def test_issue_17671(): assert integrate(log(log(x)) / x**2, [x, 1, oo]) == -EulerGamma assert integrate(log(log(x)) / x**3, [x, 1, oo]) == -log(2)/2 - EulerGamma/2 assert integrate(log(log(x)) / x**10, [x, 1, oo]) == -2*log(3)/9 - EulerGamma/9 def test_issue_2975(): w = Symbol('w') C = Symbol('C') y = Symbol('y') assert integrate(1/(y**2+C)**(S(3)/2), (y, -w/2, w/2)) == w/(C**(S(3)/2)*sqrt(1 + w**2/(4*C))) def test_issue_7827(): x, n, M = symbols('x n M') N = Symbol('N', integer=True) assert integrate(summation(x*n, (n, 1, N)), x) == x**2*(N**2/4 + N/4) assert integrate(summation(x*sin(n), (n,1,N)), x) == \ Sum(x**2*sin(n)/2, (n, 1, N)) assert integrate(summation(sin(n*x), (n,1,N)), x) == \ Sum(Piecewise((-cos(n*x)/n, Ne(n, 0)), (0, True)), (n, 1, N)) assert integrate(integrate(summation(sin(n*x), (n,1,N)), x), x) == \ Piecewise((Sum(Piecewise((-sin(n*x)/n**2, Ne(n, 0)), (-x/n, True)), (n, 1, N)), (n > -oo) & (n < oo) & Ne(n, 0)), (0, True)) assert integrate(Sum(x, (n, 1, M)), x) == M*x**2/2 raises(ValueError, lambda: integrate(Sum(x, (x, y, n)), y)) raises(ValueError, lambda: integrate(Sum(x, (x, 1, n)), n)) raises(ValueError, lambda: integrate(Sum(x, (x, 1, y)), x)) def test_issue_4231(): f = (1 + 2*x + sqrt(x + log(x))*(1 + 3*x) + x**2)/(x*(x + sqrt(x + log(x)))*sqrt(x + log(x))) assert integrate(f, x) == 2*sqrt(x + log(x)) + 2*log(x + sqrt(x + log(x))) def test_issue_17841(): f = diff(1/(x**2+x+I), x) assert integrate(f, x) == 1/(x**2 + x + I) def test_issue_21034(): x = Symbol('x', real=True, nonzero=True) f1 = x*(-x**4/asin(5)**4 - x*sinh(x + log(asin(5))) + 5) f2 = (x + cosh(cos(4)))/(x*(x + 1/(12*x))) assert integrate(f1, x) == \ -x**6/(6*asin(5)**4) - x**2*cosh(x + log(asin(5))) + 5*x**2/2 + 2*x*sinh(x + log(asin(5))) - 2*cosh(x + log(asin(5))) assert integrate(f2, x) == \ log(x**2 + S(1)/12)/2 + 2*sqrt(3)*cosh(cos(4))*atan(2*sqrt(3)*x) def test_issue_4187(): assert integrate(log(x)*exp(-x), x) == Ei(-x) - exp(-x)*log(x) assert integrate(log(x)*exp(-x), (x, 0, oo)) == -EulerGamma def test_issue_21024(): x = Symbol('x', real=True, nonzero=True) f = log(x)*log(4*x) + log(3*x + exp(2)) F = x*log(x)**2 + x*(1 - 2*log(2)) + (-2*x + 2*x*log(2))*log(x) + \ (x + exp(2)/6)*log(3*x + exp(2)) + exp(2)*log(3*x + exp(2))/6 assert F == integrate(f, x) f = (x + exp(3))/x**2 F = log(x) - exp(3)/x assert F == integrate(f, x) f = (x**2 + exp(5))/x F = x**2/2 + exp(5)*log(x) assert F == integrate(f, x) f = x/(2*x + tanh(1)) F = x/2 - log(2*x + tanh(1))*tanh(1)/4 assert F == integrate(f, x) f = x - sinh(4)/x F = x**2/2 - log(x)*sinh(4) assert F == integrate(f, x) f = log(x + exp(5)/x) F = x*log(x + exp(5)/x) - x + 2*exp(Rational(5, 2))*atan(x*exp(Rational(-5, 2))) assert F == integrate(f, x) f = x**5/(x + E) F = x**5/5 - E*x**4/4 + x**3*exp(2)/3 - x**2*exp(3)/2 + x*exp(4) - exp(5)*log(x + E) assert F == integrate(f, x) f = 4*x/(x + sinh(5)) F = 4*x - 4*log(x + sinh(5))*sinh(5) assert F == integrate(f, x) f = x**2/(2*x + sinh(2)) F = x**2/4 - x*sinh(2)/4 + log(2*x + sinh(2))*sinh(2)**2/8 assert F == integrate(f, x) f = -x**2/(x + E) F = -x**2/2 + E*x - exp(2)*log(x + E) assert F == integrate(f, x) f = (2*x + 3)*exp(5)/x F = 2*x*exp(5) + 3*exp(5)*log(x) assert F == integrate(f, x) f = x + 2 + cosh(3)/x F = x**2/2 + 2*x + log(x)*cosh(3) assert F == integrate(f, x) f = x - tanh(1)/x**3 F = x**2/2 + tanh(1)/(2*x**2) assert F == integrate(f, x) f = (3*x - exp(6))/x F = 3*x - exp(6)*log(x) assert F == integrate(f, x) f = x**4/(x + exp(5))**2 + x F = x**3/3 + x**2*(Rational(1, 2) - exp(5)) + 3*x*exp(10) - 4*exp(15)*log(x + exp(5)) - exp(20)/(x + exp(5)) assert F == integrate(f, x) f = x*(x + exp(10)/x**2) + x F = x**3/3 + x**2/2 + exp(10)*log(x) assert F == integrate(f, x) f = x + x/(5*x + sinh(3)) F = x**2/2 + x/5 - log(5*x + sinh(3))*sinh(3)/25 assert F == integrate(f, x) f = (x + exp(3))/(2*x**2 + 2*x) F = exp(3)*log(x)/2 + (Rational(1, 2) - exp(3)/2)*log(x + 1) assert F == integrate(f, x) f = log(x + 4*sinh(4)) F = x*log(x + 4*sinh(4)) - x + 4*log(x + 4*sinh(4))*sinh(4) assert F == integrate(f, x) f = -x + 20*(exp(-5) - atan(4)/x)**3*sin(4)/x F = (-x**2*exp(15)/2 + 20*log(x)*sin(4) - (-180*x**2*exp(5)*sin(4)*atan(4) + 90*x*exp(10)*sin(4)*atan(4)**2 - \ 20*exp(15)*sin(4)*atan(4)**3)/(3*x**3))*exp(-15) assert F == integrate(f, x) f = 2*x**2*exp(-4) + 6/x F_true = (2*x**3/3 + 6*exp(4)*log(x))*exp(-4) assert F_true == integrate(f, x) def test_issue_21831(): theta = symbols('theta') assert integrate(cos(3*theta)/(5-4*cos(theta)), (theta, 0, 2*pi)) == pi/12 sympy-sympy-1.9/sympy/integrals/tests/test_intpoly.py000066400000000000000000001065111412543434000233510ustar00rootroot00000000000000from sympy import sqrt, Abs from sympy.core import S, Rational from sympy.integrals.intpoly import (decompose, best_origin, distance_to_side, polytope_integrate, point_sort, hyperplane_parameters, main_integrate3d, main_integrate, polygon_integrate, lineseg_integrate, integration_reduction, integration_reduction_dynamic, is_vertex) from sympy.geometry.line import Segment2D from sympy.geometry.polygon import Polygon from sympy.geometry.point import Point, Point2D from sympy.abc import x, y, z from sympy.testing.pytest import slow def test_decompose(): assert decompose(x) == {1: x} assert decompose(x**2) == {2: x**2} assert decompose(x*y) == {2: x*y} assert decompose(x + y) == {1: x + y} assert decompose(x**2 + y) == {1: y, 2: x**2} assert decompose(8*x**2 + 4*y + 7) == {0: 7, 1: 4*y, 2: 8*x**2} assert decompose(x**2 + 3*y*x) == {2: x**2 + 3*x*y} assert decompose(9*x**2 + y + 4*x + x**3 + y**2*x + 3) ==\ {0: 3, 1: 4*x + y, 2: 9*x**2, 3: x**3 + x*y**2} assert decompose(x, True) == {x} assert decompose(x ** 2, True) == {x**2} assert decompose(x * y, True) == {x * y} assert decompose(x + y, True) == {x, y} assert decompose(x ** 2 + y, True) == {y, x ** 2} assert decompose(8 * x ** 2 + 4 * y + 7, True) == {7, 4*y, 8*x**2} assert decompose(x ** 2 + 3 * y * x, True) == {x ** 2, 3 * x * y} assert decompose(9 * x ** 2 + y + 4 * x + x ** 3 + y ** 2 * x + 3, True) == \ {3, y, 4*x, 9*x**2, x*y**2, x**3} def test_best_origin(): expr1 = y ** 2 * x ** 5 + y ** 5 * x ** 7 + 7 * x + x ** 12 + y ** 7 * x l1 = Segment2D(Point(0, 3), Point(1, 1)) l2 = Segment2D(Point(S(3) / 2, 0), Point(S(3) / 2, 3)) l3 = Segment2D(Point(0, S(3) / 2), Point(3, S(3) / 2)) l4 = Segment2D(Point(0, 2), Point(2, 0)) l5 = Segment2D(Point(0, 2), Point(1, 1)) l6 = Segment2D(Point(2, 0), Point(1, 1)) assert best_origin((2, 1), 3, l1, expr1) == (0, 3) assert best_origin((2, 0), 3, l2, x ** 7) == (S(3) / 2, 0) assert best_origin((0, 2), 3, l3, x ** 7) == (0, S(3) / 2) assert best_origin((1, 1), 2, l4, x ** 7 * y ** 3) == (0, 2) assert best_origin((1, 1), 2, l4, x ** 3 * y ** 7) == (2, 0) assert best_origin((1, 1), 2, l5, x ** 2 * y ** 9) == (0, 2) assert best_origin((1, 1), 2, l6, x ** 9 * y ** 2) == (2, 0) @slow def test_polytope_integrate(): # Convex 2-Polytopes # Vertex representation assert polytope_integrate(Polygon(Point(0, 0), Point(0, 2), Point(4, 0)), 1) == 4 assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)), x * y) ==\ Rational(1, 4) assert polytope_integrate(Polygon(Point(0, 3), Point(5, 3), Point(1, 1)), 6*x**2 - 40*y) == Rational(-935, 3) assert polytope_integrate(Polygon(Point(0, 0), Point(0, sqrt(3)), Point(sqrt(3), sqrt(3)), Point(sqrt(3), 0)), 1) == 3 hexagon = Polygon(Point(0, 0), Point(-sqrt(3) / 2, S.Half), Point(-sqrt(3) / 2, S(3) / 2), Point(0, 2), Point(sqrt(3) / 2, S(3) / 2), Point(sqrt(3) / 2, S.Half)) assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2 # Hyperplane representation assert polytope_integrate([((-1, 0), 0), ((1, 2), 4), ((0, -1), 0)], 1) == 4 assert polytope_integrate([((-1, 0), 0), ((0, 1), 1), ((1, 0), 1), ((0, -1), 0)], x * y) == Rational(1, 4) assert polytope_integrate([((0, 1), 3), ((1, -2), -1), ((-2, -1), -3)], 6*x**2 - 40*y) == Rational(-935, 3) assert polytope_integrate([((-1, 0), 0), ((0, sqrt(3)), 3), ((sqrt(3), 0), 3), ((0, -1), 0)], 1) == 3 hexagon = [((Rational(-1, 2), -sqrt(3) / 2), 0), ((-1, 0), sqrt(3) / 2), ((Rational(-1, 2), sqrt(3) / 2), sqrt(3)), ((S.Half, sqrt(3) / 2), sqrt(3)), ((1, 0), sqrt(3) / 2), ((S.Half, -sqrt(3) / 2), 0)] assert polytope_integrate(hexagon, 1) == S(3*sqrt(3)) / 2 # Non-convex polytopes # Vertex representation assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1), Point(1, 1), Point(0, 0), Point(1, -1)), 1) == 3 assert polytope_integrate(Polygon(Point(-1, -1), Point(-1, 1), Point(0, 0), Point(1, 1), Point(1, -1), Point(0, 0)), 1) == 2 # Hyperplane representation assert polytope_integrate([((-1, 0), 1), ((0, 1), 1), ((1, -1), 0), ((1, 1), 0), ((0, -1), 1)], 1) == 3 assert polytope_integrate([((-1, 0), 1), ((1, 1), 0), ((-1, 1), 0), ((1, 0), 1), ((-1, -1), 0), ((1, -1), 0)], 1) == 2 # Tests for 2D polytopes mentioned in Chin et al(Page 10): # http://dilbert.engr.ucdavis.edu/~suku/quadrature/cls-integration.pdf fig1 = Polygon(Point(1.220, -0.827), Point(-1.490, -4.503), Point(-3.766, -1.622), Point(-4.240, -0.091), Point(-3.160, 4), Point(-0.981, 4.447), Point(0.132, 4.027)) assert polytope_integrate(fig1, x**2 + x*y + y**2) ==\ S(2031627344735367)/(8*10**12) fig2 = Polygon(Point(4.561, 2.317), Point(1.491, -1.315), Point(-3.310, -3.164), Point(-4.845, -3.110), Point(-4.569, 1.867)) assert polytope_integrate(fig2, x**2 + x*y + y**2) ==\ S(517091313866043)/(16*10**11) fig3 = Polygon(Point(-2.740, -1.888), Point(-3.292, 4.233), Point(-2.723, -0.697), Point(-0.643, -3.151)) assert polytope_integrate(fig3, x**2 + x*y + y**2) ==\ S(147449361647041)/(8*10**12) fig4 = Polygon(Point(0.211, -4.622), Point(-2.684, 3.851), Point(0.468, 4.879), Point(4.630, -1.325), Point(-0.411, -1.044)) assert polytope_integrate(fig4, x**2 + x*y + y**2) ==\ S(180742845225803)/(10**12) # Tests for many polynomials with maximum degree given(2D case). tri = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) polys = [] expr1 = x**9*y + x**7*y**3 + 2*x**2*y**8 expr2 = x**6*y**4 + x**5*y**5 + 2*y**10 expr3 = x**10 + x**9*y + x**8*y**2 + x**5*y**5 polys.extend((expr1, expr2, expr3)) result_dict = polytope_integrate(tri, polys, max_degree=10) assert result_dict[expr1] == Rational(615780107, 594) assert result_dict[expr2] == Rational(13062161, 27) assert result_dict[expr3] == Rational(1946257153, 924) # Tests when all integral of all monomials up to a max_degree is to be # calculated. assert polytope_integrate(Polygon(Point(0, 0), Point(0, 1), Point(1, 1), Point(1, 0)), max_degree=4) == {0: 0, 1: 1, x: S.Half, x ** 2 * y ** 2: S.One / 9, x ** 4: S.One / 5, y ** 4: S.One / 5, y: S.Half, x * y ** 2: S.One / 6, y ** 2: S.One / 3, x ** 3: S.One / 4, x ** 2 * y: S.One / 6, x ** 3 * y: S.One / 8, x * y: S.One / 4, y ** 3: S.One / 4, x ** 2: S.One / 3, x * y ** 3: S.One / 8} # Tests for 3D polytopes cube1 = [[(0, 0, 0), (0, 6, 6), (6, 6, 6), (3, 6, 0), (0, 6, 0), (6, 0, 6), (3, 0, 0), (0, 0, 6)], [1, 2, 3, 4], [3, 2, 5, 6], [1, 7, 5, 2], [0, 6, 5, 7], [1, 4, 0, 7], [0, 4, 3, 6]] assert polytope_integrate(cube1, 1) == S(162) # 3D Test cases in Chin et al(2015) cube2 = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0), (5, 0, 5), (5, 5, 0), (5, 5, 5)], [3, 7, 6, 2], [1, 5, 7, 3], [5, 4, 6, 7], [0, 4, 5, 1], [2, 0, 1, 3], [2, 6, 4, 0]] cube3 = [[(0, 0, 0), (5, 0, 0), (5, 4, 0), (3, 2, 0), (3, 5, 0), (0, 5, 0), (0, 0, 5), (5, 0, 5), (5, 4, 5), (3, 2, 5), (3, 5, 5), (0, 5, 5)], [6, 11, 5, 0], [1, 7, 6, 0], [5, 4, 3, 2, 1, 0], [11, 10, 4, 5], [10, 9, 3, 4], [9, 8, 2, 3], [8, 7, 1, 2], [7, 8, 9, 10, 11, 6]] cube4 = [[(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (S.One / 4, S.One / 4, S.One / 4)], [0, 2, 1], [1, 3, 0], [4, 2, 3], [4, 3, 1], [0, 1, 2], [2, 4, 1], [0, 3, 2]] assert polytope_integrate(cube2, x ** 2 + y ** 2 + x * y + z ** 2) ==\ Rational(15625, 4) assert polytope_integrate(cube3, x ** 2 + y ** 2 + x * y + z ** 2) ==\ S(33835) / 12 assert polytope_integrate(cube4, x ** 2 + y ** 2 + x * y + z ** 2) ==\ S(37) / 960 # Test cases from Mathematica's PolyhedronData library octahedron = [[(S.NegativeOne / sqrt(2), 0, 0), (0, S.One / sqrt(2), 0), (0, 0, S.NegativeOne / sqrt(2)), (0, 0, S.One / sqrt(2)), (0, S.NegativeOne / sqrt(2), 0), (S.One / sqrt(2), 0, 0)], [3, 4, 5], [3, 5, 1], [3, 1, 0], [3, 0, 4], [4, 0, 2], [4, 2, 5], [2, 0, 1], [5, 2, 1]] assert polytope_integrate(octahedron, 1) == sqrt(2) / 3 great_stellated_dodecahedron =\ [[(-0.32491969623290634095, 0, 0.42532540417601993887), (0.32491969623290634095, 0, -0.42532540417601993887), (-0.52573111211913359231, 0, 0.10040570794311363956), (0.52573111211913359231, 0, -0.10040570794311363956), (-0.10040570794311363956, -0.3090169943749474241, 0.42532540417601993887), (-0.10040570794311363956, 0.30901699437494742410, 0.42532540417601993887), (0.10040570794311363956, -0.3090169943749474241, -0.42532540417601993887), (0.10040570794311363956, 0.30901699437494742410, -0.42532540417601993887), (-0.16245984811645317047, -0.5, 0.10040570794311363956), (-0.16245984811645317047, 0.5, 0.10040570794311363956), (0.16245984811645317047, -0.5, -0.10040570794311363956), (0.16245984811645317047, 0.5, -0.10040570794311363956), (-0.42532540417601993887, -0.3090169943749474241, -0.10040570794311363956), (-0.42532540417601993887, 0.30901699437494742410, -0.10040570794311363956), (-0.26286555605956679615, 0.1909830056250525759, -0.42532540417601993887), (-0.26286555605956679615, -0.1909830056250525759, -0.42532540417601993887), (0.26286555605956679615, 0.1909830056250525759, 0.42532540417601993887), (0.26286555605956679615, -0.1909830056250525759, 0.42532540417601993887), (0.42532540417601993887, -0.3090169943749474241, 0.10040570794311363956), (0.42532540417601993887, 0.30901699437494742410, 0.10040570794311363956)], [12, 3, 0, 6, 16], [17, 7, 0, 3, 13], [9, 6, 0, 7, 8], [18, 2, 1, 4, 14], [15, 5, 1, 2, 19], [11, 4, 1, 5, 10], [8, 19, 2, 18, 9], [10, 13, 3, 12, 11], [16, 14, 4, 11, 12], [13, 10, 5, 15, 17], [14, 16, 6, 9, 18], [19, 8, 7, 17, 15]] # Actual volume is : 0.163118960624632 assert Abs(polytope_integrate(great_stellated_dodecahedron, 1) -\ 0.163118960624632) < 1e-12 expr = x **2 + y ** 2 + z ** 2 octahedron_five_compound = [[(0, -0.7071067811865475244, 0), (0, 0.70710678118654752440, 0), (0.1148764602736805918, -0.35355339059327376220, -0.60150095500754567366), (0.1148764602736805918, 0.35355339059327376220, -0.60150095500754567366), (0.18587401723009224507, -0.57206140281768429760, 0.37174803446018449013), (0.18587401723009224507, 0.57206140281768429760, 0.37174803446018449013), (0.30075047750377283683, -0.21850801222441053540, 0.60150095500754567366), (0.30075047750377283683, 0.21850801222441053540, 0.60150095500754567366), (0.48662449473386508189, -0.35355339059327376220, -0.37174803446018449013), (0.48662449473386508189, 0.35355339059327376220, -0.37174803446018449013), (-0.60150095500754567366, 0, -0.37174803446018449013), (-0.30075047750377283683, -0.21850801222441053540, -0.60150095500754567366), (-0.30075047750377283683, 0.21850801222441053540, -0.60150095500754567366), (0.60150095500754567366, 0, 0.37174803446018449013), (0.4156269377774534286, -0.57206140281768429760, 0), (0.4156269377774534286, 0.57206140281768429760, 0), (0.37174803446018449013, 0, -0.60150095500754567366), (-0.4156269377774534286, -0.57206140281768429760, 0), (-0.4156269377774534286, 0.57206140281768429760, 0), (-0.67249851196395732696, -0.21850801222441053540, 0), (-0.67249851196395732696, 0.21850801222441053540, 0), (0.67249851196395732696, -0.21850801222441053540, 0), (0.67249851196395732696, 0.21850801222441053540, 0), (-0.37174803446018449013, 0, 0.60150095500754567366), (-0.48662449473386508189, -0.35355339059327376220, 0.37174803446018449013), (-0.48662449473386508189, 0.35355339059327376220, 0.37174803446018449013), (-0.18587401723009224507, -0.57206140281768429760, -0.37174803446018449013), (-0.18587401723009224507, 0.57206140281768429760, -0.37174803446018449013), (-0.11487646027368059176, -0.35355339059327376220, 0.60150095500754567366), (-0.11487646027368059176, 0.35355339059327376220, 0.60150095500754567366)], [0, 10, 16], [23, 10, 0], [16, 13, 0], [0, 13, 23], [16, 10, 1], [1, 10, 23], [1, 13, 16], [23, 13, 1], [2, 4, 19], [22, 4, 2], [2, 19, 27], [27, 22, 2], [20, 5, 3], [3, 5, 21], [26, 20, 3], [3, 21, 26], [29, 19, 4], [4, 22, 29], [5, 20, 28], [28, 21, 5], [6, 8, 15], [17, 8, 6], [6, 15, 25], [25, 17, 6], [14, 9, 7], [7, 9, 18], [24, 14, 7], [7, 18, 24], [8, 12, 15], [17, 12, 8], [14, 11, 9], [9, 11, 18], [11, 14, 24], [24, 18, 11], [25, 15, 12], [12, 17, 25], [29, 27, 19], [20, 26, 28], [28, 26, 21], [22, 27, 29]] assert Abs(polytope_integrate(octahedron_five_compound, expr)) - 0.353553\ < 1e-6 cube_five_compound = [[(-0.1624598481164531631, -0.5, -0.6881909602355867691), (-0.1624598481164531631, 0.5, -0.6881909602355867691), (0.1624598481164531631, -0.5, 0.68819096023558676910), (0.1624598481164531631, 0.5, 0.68819096023558676910), (-0.52573111211913359231, 0, -0.6881909602355867691), (0.52573111211913359231, 0, 0.68819096023558676910), (-0.26286555605956679615, -0.8090169943749474241, -0.1624598481164531631), (-0.26286555605956679615, 0.8090169943749474241, -0.1624598481164531631), (0.26286555605956680301, -0.8090169943749474241, 0.1624598481164531631), (0.26286555605956680301, 0.8090169943749474241, 0.1624598481164531631), (-0.42532540417601993887, -0.3090169943749474241, 0.68819096023558676910), (-0.42532540417601993887, 0.30901699437494742410, 0.68819096023558676910), (0.42532540417601996609, -0.3090169943749474241, -0.6881909602355867691), (0.42532540417601996609, 0.30901699437494742410, -0.6881909602355867691), (-0.6881909602355867691, -0.5, 0.1624598481164531631), (-0.6881909602355867691, 0.5, 0.1624598481164531631), (0.68819096023558676910, -0.5, -0.1624598481164531631), (0.68819096023558676910, 0.5, -0.1624598481164531631), (-0.85065080835203998877, 0, -0.1624598481164531631), (0.85065080835203993218, 0, 0.1624598481164531631)], [18, 10, 3, 7], [13, 19, 8, 0], [18, 0, 8, 10], [3, 19, 13, 7], [18, 7, 13, 0], [8, 19, 3, 10], [6, 2, 11, 18], [1, 9, 19, 12], [11, 9, 1, 18], [6, 12, 19, 2], [1, 12, 6, 18], [11, 2, 19, 9], [4, 14, 11, 7], [17, 5, 8, 12], [4, 12, 8, 14], [11, 5, 17, 7], [4, 7, 17, 12], [8, 5, 11, 14], [6, 10, 15, 4], [13, 9, 5, 16], [15, 9, 13, 4], [6, 16, 5, 10], [13, 16, 6, 4], [15, 10, 5, 9], [14, 15, 1, 0], [16, 17, 3, 2], [14, 2, 3, 15], [1, 17, 16, 0], [14, 0, 16, 2], [3, 17, 1, 15]] assert Abs(polytope_integrate(cube_five_compound, expr) - 1.25) < 1e-12 echidnahedron = [[(0, 0, -2.4898982848827801995), (0, 0, 2.4898982848827802734), (0, -4.2360679774997896964, -2.4898982848827801995), (0, -4.2360679774997896964, 2.4898982848827802734), (0, 4.2360679774997896964, -2.4898982848827801995), (0, 4.2360679774997896964, 2.4898982848827802734), (-4.0287400534704067567, -1.3090169943749474241, -2.4898982848827801995), (-4.0287400534704067567, -1.3090169943749474241, 2.4898982848827802734), (-4.0287400534704067567, 1.3090169943749474241, -2.4898982848827801995), (-4.0287400534704067567, 1.3090169943749474241, 2.4898982848827802734), (4.0287400534704069747, -1.3090169943749474241, -2.4898982848827801995), (4.0287400534704069747, -1.3090169943749474241, 2.4898982848827802734), (4.0287400534704069747, 1.3090169943749474241, -2.4898982848827801995), (4.0287400534704069747, 1.3090169943749474241, 2.4898982848827802734), (-2.4898982848827801995, -3.4270509831248422723, -2.4898982848827801995), (-2.4898982848827801995, -3.4270509831248422723, 2.4898982848827802734), (-2.4898982848827801995, 3.4270509831248422723, -2.4898982848827801995), (-2.4898982848827801995, 3.4270509831248422723, 2.4898982848827802734), (2.4898982848827802734, -3.4270509831248422723, -2.4898982848827801995), (2.4898982848827802734, -3.4270509831248422723, 2.4898982848827802734), (2.4898982848827802734, 3.4270509831248422723, -2.4898982848827801995), (2.4898982848827802734, 3.4270509831248422723, 2.4898982848827802734), (-4.7169310137059934362, -0.8090169943749474241, -1.1135163644116066184), (-4.7169310137059934362, 0.8090169943749474241, -1.1135163644116066184), (4.7169310137059937438, -0.8090169943749474241, 1.11351636441160673519), (4.7169310137059937438, 0.8090169943749474241, 1.11351636441160673519), (-4.2916056095299737777, -2.1180339887498948482, 1.11351636441160673519), (-4.2916056095299737777, 2.1180339887498948482, 1.11351636441160673519), (4.2916056095299737777, -2.1180339887498948482, -1.1135163644116066184), (4.2916056095299737777, 2.1180339887498948482, -1.1135163644116066184), (-3.6034146492943870399, 0, -3.3405490932348205213), (3.6034146492943870399, 0, 3.3405490932348202056), (-3.3405490932348205213, -3.4270509831248422723, 1.11351636441160673519), (-3.3405490932348205213, 3.4270509831248422723, 1.11351636441160673519), (3.3405490932348202056, -3.4270509831248422723, -1.1135163644116066184), (3.3405490932348202056, 3.4270509831248422723, -1.1135163644116066184), (-2.9152236890588002395, -2.1180339887498948482, 3.3405490932348202056), (-2.9152236890588002395, 2.1180339887498948482, 3.3405490932348202056), (2.9152236890588002395, -2.1180339887498948482, -3.3405490932348205213), (2.9152236890588002395, 2.1180339887498948482, -3.3405490932348205213), (-2.2270327288232132368, 0, -1.1135163644116066184), (-2.2270327288232132368, -4.2360679774997896964, -1.1135163644116066184), (-2.2270327288232132368, 4.2360679774997896964, -1.1135163644116066184), (2.2270327288232134704, 0, 1.11351636441160673519), (2.2270327288232134704, -4.2360679774997896964, 1.11351636441160673519), (2.2270327288232134704, 4.2360679774997896964, 1.11351636441160673519), (-1.8017073246471935200, -1.3090169943749474241, 1.11351636441160673519), (-1.8017073246471935200, 1.3090169943749474241, 1.11351636441160673519), (1.8017073246471935043, -1.3090169943749474241, -1.1135163644116066184), (1.8017073246471935043, 1.3090169943749474241, -1.1135163644116066184), (-1.3763819204711735382, 0, -4.7169310137059934362), (-1.3763819204711735382, 0, 0.26286555605956679615), (1.37638192047117353821, 0, 4.7169310137059937438), (1.37638192047117353821, 0, -0.26286555605956679615), (-1.1135163644116066184, -3.4270509831248422723, -3.3405490932348205213), (-1.1135163644116066184, -0.8090169943749474241, 4.7169310137059937438), (-1.1135163644116066184, -0.8090169943749474241, -0.26286555605956679615), (-1.1135163644116066184, 0.8090169943749474241, 4.7169310137059937438), (-1.1135163644116066184, 0.8090169943749474241, -0.26286555605956679615), (-1.1135163644116066184, 3.4270509831248422723, -3.3405490932348205213), (1.11351636441160673519, -3.4270509831248422723, 3.3405490932348202056), (1.11351636441160673519, -0.8090169943749474241, -4.7169310137059934362), (1.11351636441160673519, -0.8090169943749474241, 0.26286555605956679615), (1.11351636441160673519, 0.8090169943749474241, -4.7169310137059934362), (1.11351636441160673519, 0.8090169943749474241, 0.26286555605956679615), (1.11351636441160673519, 3.4270509831248422723, 3.3405490932348202056), (-0.85065080835203998877, 0, 1.11351636441160673519), (0.85065080835203993218, 0, -1.1135163644116066184), (-0.6881909602355867691, -0.5, -1.1135163644116066184), (-0.6881909602355867691, 0.5, -1.1135163644116066184), (-0.6881909602355867691, -4.7360679774997896964, -1.1135163644116066184), (-0.6881909602355867691, -2.1180339887498948482, -1.1135163644116066184), (-0.6881909602355867691, 2.1180339887498948482, -1.1135163644116066184), (-0.6881909602355867691, 4.7360679774997896964, -1.1135163644116066184), (0.68819096023558676910, -0.5, 1.11351636441160673519), (0.68819096023558676910, 0.5, 1.11351636441160673519), (0.68819096023558676910, -4.7360679774997896964, 1.11351636441160673519), (0.68819096023558676910, -2.1180339887498948482, 1.11351636441160673519), (0.68819096023558676910, 2.1180339887498948482, 1.11351636441160673519), (0.68819096023558676910, 4.7360679774997896964, 1.11351636441160673519), (-0.42532540417601993887, -1.3090169943749474241, -4.7169310137059934362), (-0.42532540417601993887, -1.3090169943749474241, 0.26286555605956679615), (-0.42532540417601993887, 1.3090169943749474241, -4.7169310137059934362), (-0.42532540417601993887, 1.3090169943749474241, 0.26286555605956679615), (-0.26286555605956679615, -0.8090169943749474241, 1.11351636441160673519), (-0.26286555605956679615, 0.8090169943749474241, 1.11351636441160673519), (0.26286555605956679615, -0.8090169943749474241, -1.1135163644116066184), (0.26286555605956679615, 0.8090169943749474241, -1.1135163644116066184), (0.42532540417601996609, -1.3090169943749474241, 4.7169310137059937438), (0.42532540417601996609, -1.3090169943749474241, -0.26286555605956679615), (0.42532540417601996609, 1.3090169943749474241, 4.7169310137059937438), (0.42532540417601996609, 1.3090169943749474241, -0.26286555605956679615)], [9, 66, 47], [44, 62, 77], [20, 91, 49], [33, 47, 83], [3, 77, 84], [12, 49, 53], [36, 84, 66], [28, 53, 62], [73, 83, 91], [15, 84, 46], [25, 64, 43], [16, 58, 72], [26, 46, 51], [11, 43, 74], [4, 72, 91], [60, 74, 84], [35, 91, 64], [23, 51, 58], [19, 74, 77], [79, 83, 78], [6, 56, 40], [76, 77, 81], [21, 78, 75], [8, 40, 58], [31, 75, 74], [42, 58, 83], [41, 81, 56], [13, 75, 43], [27, 51, 47], [2, 89, 71], [24, 43, 62], [17, 47, 85], [14, 71, 56], [65, 85, 75], [22, 56, 51], [34, 62, 89], [5, 85, 78], [32, 81, 46], [10, 53, 48], [45, 78, 64], [7, 46, 66], [18, 48, 89], [37, 66, 85], [70, 89, 81], [29, 64, 53], [88, 74, 1], [38, 67, 48], [42, 83, 72], [57, 1, 85], [34, 48, 62], [59, 72, 87], [19, 62, 74], [63, 87, 67], [17, 85, 83], [52, 75, 1], [39, 87, 49], [22, 51, 40], [55, 1, 66], [29, 49, 64], [30, 40, 69], [13, 64, 75], [82, 69, 87], [7, 66, 51], [90, 85, 1], [59, 69, 72], [70, 81, 71], [88, 1, 84], [73, 72, 83], [54, 71, 68], [5, 83, 85], [50, 68, 69], [3, 84, 81], [57, 66, 1], [30, 68, 40], [28, 62, 48], [52, 1, 74], [23, 40, 51], [38, 48, 86], [9, 51, 66], [80, 86, 68], [11, 74, 62], [55, 84, 1], [54, 86, 71], [35, 64, 49], [90, 1, 75], [41, 71, 81], [39, 49, 67], [15, 81, 84], [61, 67, 86], [21, 75, 64], [24, 53, 43], [50, 69, 0], [37, 85, 47], [31, 43, 75], [61, 0, 67], [27, 47, 58], [10, 67, 53], [8, 58, 69], [90, 75, 85], [45, 91, 78], [80, 68, 0], [36, 66, 46], [65, 78, 85], [63, 0, 87], [32, 46, 56], [20, 87, 91], [14, 56, 68], [57, 85, 66], [33, 58, 47], [61, 86, 0], [60, 84, 77], [37, 47, 66], [82, 0, 69], [44, 77, 89], [16, 69, 58], [18, 89, 86], [55, 66, 84], [26, 56, 46], [63, 67, 0], [31, 74, 43], [36, 46, 84], [50, 0, 68], [25, 43, 53], [6, 68, 56], [12, 53, 67], [88, 84, 74], [76, 89, 77], [82, 87, 0], [65, 75, 78], [60, 77, 74], [80, 0, 86], [79, 78, 91], [2, 86, 89], [4, 91, 87], [52, 74, 75], [21, 64, 78], [18, 86, 48], [23, 58, 40], [5, 78, 83], [28, 48, 53], [6, 40, 68], [25, 53, 64], [54, 68, 86], [33, 83, 58], [17, 83, 47], [12, 67, 49], [41, 56, 71], [9, 47, 51], [35, 49, 91], [2, 71, 86], [79, 91, 83], [38, 86, 67], [26, 51, 56], [7, 51, 46], [4, 87, 72], [34, 89, 48], [15, 46, 81], [42, 72, 58], [10, 48, 67], [27, 58, 51], [39, 67, 87], [76, 81, 89], [3, 81, 77], [8, 69, 40], [29, 53, 49], [19, 77, 62], [22, 40, 56], [20, 49, 87], [32, 56, 81], [59, 87, 69], [24, 62, 53], [11, 62, 43], [14, 68, 71], [73, 91, 72], [13, 43, 64], [70, 71, 89], [16, 72, 69], [44, 89, 62], [30, 69, 68], [45, 64, 91]] # Actual volume is : 51.405764746872634 assert Abs(polytope_integrate(echidnahedron, 1) - 51.4057647468726) < 1e-12 assert Abs(polytope_integrate(echidnahedron, expr) - 253.569603474519) <\ 1e-12 # Tests for many polynomials with maximum degree given(2D case). assert polytope_integrate(cube2, [x**2, y*z], max_degree=2) == \ {y * z: 3125 / S(4), x ** 2: 3125 / S(3)} assert polytope_integrate(cube2, max_degree=2) == \ {1: 125, x: 625 / S(2), x * z: 3125 / S(4), y: 625 / S(2), y * z: 3125 / S(4), z ** 2: 3125 / S(3), y ** 2: 3125 / S(3), z: 625 / S(2), x * y: 3125 / S(4), x ** 2: 3125 / S(3)} def test_point_sort(): assert point_sort([Point(0, 0), Point(1, 0), Point(1, 1)]) == \ [Point2D(1, 1), Point2D(1, 0), Point2D(0, 0)] fig6 = Polygon((0, 0), (1, 0), (1, 1)) assert polytope_integrate(fig6, x*y) == Rational(-1, 8) assert polytope_integrate(fig6, x*y, clockwise = True) == Rational(1, 8) def test_polytopes_intersecting_sides(): fig5 = Polygon(Point(-4.165, -0.832), Point(-3.668, 1.568), Point(-3.266, 1.279), Point(-1.090, -2.080), Point(3.313, -0.683), Point(3.033, -4.845), Point(-4.395, 4.840), Point(-1.007, -3.328)) assert polytope_integrate(fig5, x**2 + x*y + y**2) ==\ S(1633405224899363)/(24*10**12) fig6 = Polygon(Point(-3.018, -4.473), Point(-0.103, 2.378), Point(-1.605, -2.308), Point(4.516, -0.771), Point(4.203, 0.478)) assert polytope_integrate(fig6, x**2 + x*y + y**2) ==\ S(88161333955921)/(3*10**12) def test_max_degree(): polygon = Polygon((0, 0), (0, 1), (1, 1), (1, 0)) polys = [1, x, y, x*y, x**2*y, x*y**2] assert polytope_integrate(polygon, polys, max_degree=3) == \ {1: 1, x: S.Half, y: S.Half, x*y: Rational(1, 4), x**2*y: Rational(1, 6), x*y**2: Rational(1, 6)} def test_main_integrate3d(): cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ [3, 1, 0, 2], [0, 4, 6, 2]] vertices = cube[0] faces = cube[1:] hp_params = hyperplane_parameters(faces, vertices) assert main_integrate3d(1, faces, vertices, hp_params) == -125 assert main_integrate3d(1, faces, vertices, hp_params, max_degree=1) == \ {1: -125, y: Rational(-625, 2), z: Rational(-625, 2), x: Rational(-625, 2)} def test_main_integrate(): triangle = Polygon((0, 3), (5, 3), (1, 1)) facets = triangle.sides hp_params = hyperplane_parameters(triangle) assert main_integrate(x**2 + y**2, facets, hp_params) == Rational(325, 6) assert main_integrate(x**2 + y**2, facets, hp_params, max_degree=1) == \ {0: 0, 1: 5, y: Rational(35, 3), x: 10} def test_polygon_integrate(): cube = [[(0, 0, 0), (0, 0, 5), (0, 5, 0), (0, 5, 5), (5, 0, 0),\ (5, 0, 5), (5, 5, 0), (5, 5, 5)],\ [2, 6, 7, 3], [3, 7, 5, 1], [7, 6, 4, 5], [1, 5, 4, 0],\ [3, 1, 0, 2], [0, 4, 6, 2]] facet = cube[1] facets = cube[1:] vertices = cube[0] assert polygon_integrate(facet, [(0, 1, 0), 5], 0, facets, vertices, 1, 0) == -25 def test_distance_to_side(): point = (0, 0, 0) assert distance_to_side(point, [(0, 0, 1), (0, 1, 0)], (1, 0, 0)) == -sqrt(2)/2 def test_lineseg_integrate(): polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)] line_seg = [(0, 5, 0), (5, 5, 0)] assert lineseg_integrate(polygon, 0, line_seg, 1, 0) == 5 assert lineseg_integrate(polygon, 0, line_seg, 0, 0) == 0 def test_integration_reduction(): triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) facets = triangle.sides a, b = hyperplane_parameters(triangle)[0] assert integration_reduction(facets, 0, a, b, 1, (x, y), 0) == 5 assert integration_reduction(facets, 0, a, b, 0, (x, y), 0) == 0 def test_integration_reduction_dynamic(): triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1)) facets = triangle.sides a, b = hyperplane_parameters(triangle)[0] x0 = facets[0].points[0] monomial_values = [[0, 0, 0, 0], [1, 0, 0, 5],\ [y, 0, 1, 15], [x, 1, 0, None]] assert integration_reduction_dynamic(facets, 0, a, b, x, 1, (x, y), 1,\ 0, 1, x0, monomial_values, 3) == Rational(25, 2) assert integration_reduction_dynamic(facets, 0, a, b, 0, 1, (x, y), 1,\ 0, 1, x0, monomial_values, 3) == 0 def test_is_vertex(): assert is_vertex(2) is False assert is_vertex((2, 3)) is True assert is_vertex(Point(2, 3)) is True assert is_vertex((2, 3, 4)) is True assert is_vertex((2, 3, 4, 5)) is False sympy-sympy-1.9/sympy/integrals/tests/test_lineintegrals.py000066400000000000000000000003531412543434000245100ustar00rootroot00000000000000from sympy import symbols, E, ln, Curve, line_integrate, sqrt s, t, x, y, z = symbols('s,t,x,y,z') def test_lineintegral(): c = Curve([E**t + 1, E**t - 1], (t, 0, ln(2))) assert line_integrate(x + y, c, [x, y]) == 3*sqrt(2) sympy-sympy-1.9/sympy/integrals/tests/test_manual.py000066400000000000000000000625361412543434000231400ustar00rootroot00000000000000from sympy import (sin, cos, tan, sec, csc, cot, log, exp, atan, asin, acos, Symbol, Integral, integrate, pi, Dummy, Derivative, diff, I, sqrt, erf, Piecewise, Ne, symbols, Rational, And, Heaviside, S, asinh, acosh, atanh, acoth, expand, Function, jacobi, gegenbauer, chebyshevt, chebyshevu, legendre, hermite, laguerre, assoc_laguerre, uppergamma, li, Ei, Ci, Si, Chi, Shi, fresnels, fresnelc, polylog, erfi, sinh, cosh, elliptic_f, elliptic_e ,asec, acsc, acot ) from sympy.integrals.manualintegrate import (manualintegrate, find_substitutions, _parts_rule, integral_steps, contains_dont_know, manual_subs) from sympy.testing.pytest import raises, slow x, y, z, u, n, a, b, c = symbols('x y z u n a b c') f = Function('f') def test_find_substitutions(): assert find_substitutions((cot(x)**2 + 1)**2*csc(x)**2*cot(x)**2, x, u) == \ [(cot(x), 1, -u**6 - 2*u**4 - u**2)] assert find_substitutions((sec(x)**2 + tan(x) * sec(x)) / (sec(x) + tan(x)), x, u) == [(sec(x) + tan(x), 1, 1/u)] assert find_substitutions(x * exp(-x**2), x, u) == [(-x**2, Rational(-1, 2), exp(u))] def test_manualintegrate_polynomials(): assert manualintegrate(y, x) == x*y assert manualintegrate(exp(2), x) == x * exp(2) assert manualintegrate(x**2, x) == x**3 / 3 assert manualintegrate(3 * x**2 + 4 * x**3, x) == x**3 + x**4 assert manualintegrate((x + 2)**3, x) == (x + 2)**4 / 4 assert manualintegrate((3*x + 4)**2, x) == (3*x + 4)**3 / 9 assert manualintegrate((u + 2)**3, u) == (u + 2)**4 / 4 assert manualintegrate((3*u + 4)**2, u) == (3*u + 4)**3 / 9 def test_manualintegrate_exponentials(): assert manualintegrate(exp(2*x), x) == exp(2*x) / 2 assert manualintegrate(2**x, x) == (2 ** x) / log(2) assert manualintegrate(1 / x, x) == log(x) assert manualintegrate(1 / (2*x + 3), x) == log(2*x + 3) / 2 assert manualintegrate(log(x)**2 / x, x) == log(x)**3 / 3 def test_manualintegrate_parts(): assert manualintegrate(exp(x) * sin(x), x) == \ (exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2 assert manualintegrate(2*x*cos(x), x) == 2*x*sin(x) + 2*cos(x) assert manualintegrate(x * log(x), x) == x**2*log(x)/2 - x**2/4 assert manualintegrate(log(x), x) == x * log(x) - x assert manualintegrate((3*x**2 + 5) * exp(x), x) == \ 3*x**2*exp(x) - 6*x*exp(x) + 11*exp(x) assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2 # Make sure _parts_rule does not go into an infinite loop here assert manualintegrate(log(1/x)/(x + 1), x).has(Integral) # Make sure _parts_rule doesn't pick u = constant but can pick dv = # constant if necessary, e.g. for integrate(atan(x)) assert _parts_rule(cos(x), x) == None assert _parts_rule(exp(x), x) == None assert _parts_rule(x**2, x) == None result = _parts_rule(atan(x), x) assert result[0] == atan(x) and result[1] == 1 def test_manualintegrate_trigonometry(): assert manualintegrate(sin(x), x) == -cos(x) assert manualintegrate(tan(x), x) == -log(cos(x)) assert manualintegrate(sec(x), x) == log(sec(x) + tan(x)) assert manualintegrate(csc(x), x) == -log(csc(x) + cot(x)) assert manualintegrate(sin(x) * cos(x), x) in [sin(x) ** 2 / 2, -cos(x)**2 / 2] assert manualintegrate(-sec(x) * tan(x), x) == -sec(x) assert manualintegrate(csc(x) * cot(x), x) == -csc(x) assert manualintegrate(sec(x)**2, x) == tan(x) assert manualintegrate(csc(x)**2, x) == -cot(x) assert manualintegrate(x * sec(x**2), x) == log(tan(x**2) + sec(x**2))/2 assert manualintegrate(cos(x)*csc(sin(x)), x) == -log(cot(sin(x)) + csc(sin(x))) assert manualintegrate(cos(3*x)*sec(x), x) == -x + sin(2*x) assert manualintegrate(sin(3*x)*sec(x), x) == \ -3*log(cos(x)) + 2*log(cos(x)**2) - 2*cos(x)**2 @slow def test_manualintegrate_trigpowers(): assert manualintegrate(sin(x)**2 * cos(x), x) == sin(x)**3 / 3 assert manualintegrate(sin(x)**2 * cos(x) **2, x) == \ x / 8 - sin(4*x) / 32 assert manualintegrate(sin(x) * cos(x)**3, x) == -cos(x)**4 / 4 assert manualintegrate(sin(x)**3 * cos(x)**2, x) == \ cos(x)**5 / 5 - cos(x)**3 / 3 assert manualintegrate(tan(x)**3 * sec(x), x) == sec(x)**3/3 - sec(x) assert manualintegrate(tan(x) * sec(x) **2, x) == sec(x)**2/2 assert manualintegrate(cot(x)**5 * csc(x), x) == \ -csc(x)**5/5 + 2*csc(x)**3/3 - csc(x) assert manualintegrate(cot(x)**2 * csc(x)**6, x) == \ -cot(x)**7/7 - 2*cot(x)**5/5 - cot(x)**3/3 @slow def test_manualintegrate_inversetrig(): # atan assert manualintegrate(exp(x) / (1 + exp(2*x)), x) == atan(exp(x)) assert manualintegrate(1 / (4 + 9 * x**2), x) == atan(3 * x/2) / 6 assert manualintegrate(1 / (16 + 16 * x**2), x) == atan(x) / 16 assert manualintegrate(1 / (4 + x**2), x) == atan(x / 2) / 2 assert manualintegrate(1 / (1 + 4 * x**2), x) == atan(2*x) / 2 ra = Symbol('a', real=True) rb = Symbol('b', real=True) assert manualintegrate(1/(ra + rb*x**2), x) == \ Piecewise((atan(x/sqrt(ra/rb))/(rb*sqrt(ra/rb)), ra/rb > 0), (-acoth(x/sqrt(-ra/rb))/(rb*sqrt(-ra/rb)), And(ra/rb < 0, x**2 > -ra/rb)), (-atanh(x/sqrt(-ra/rb))/(rb*sqrt(-ra/rb)), And(ra/rb < 0, x**2 < -ra/rb))) assert manualintegrate(1/(4 + rb*x**2), x) == \ Piecewise((atan(x/(2*sqrt(1/rb)))/(2*rb*sqrt(1/rb)), 4/rb > 0), (-acoth(x/(2*sqrt(-1/rb)))/(2*rb*sqrt(-1/rb)), And(4/rb < 0, x**2 > -4/rb)), (-atanh(x/(2*sqrt(-1/rb)))/(2*rb*sqrt(-1/rb)), And(4/rb < 0, x**2 < -4/rb))) assert manualintegrate(1/(ra + 4*x**2), x) == \ Piecewise((atan(2*x/sqrt(ra))/(2*sqrt(ra)), ra/4 > 0), (-acoth(2*x/sqrt(-ra))/(2*sqrt(-ra)), And(ra/4 < 0, x**2 > -ra/4)), (-atanh(2*x/sqrt(-ra))/(2*sqrt(-ra)), And(ra/4 < 0, x**2 < -ra/4))) assert manualintegrate(1/(4 + 4*x**2), x) == atan(x) / 4 assert manualintegrate(1/(a + b*x**2), x) == atan(x/sqrt(a/b))/(b*sqrt(a/b)) # asin assert manualintegrate(1/sqrt(1-x**2), x) == asin(x) assert manualintegrate(1/sqrt(4-4*x**2), x) == asin(x)/2 assert manualintegrate(3/sqrt(1-9*x**2), x) == asin(3*x) assert manualintegrate(1/sqrt(4-9*x**2), x) == asin(x*Rational(3, 2))/3 # asinh assert manualintegrate(1/sqrt(x**2 + 1), x) == \ asinh(x) assert manualintegrate(1/sqrt(x**2 + 4), x) == \ asinh(x/2) assert manualintegrate(1/sqrt(4*x**2 + 4), x) == \ asinh(x)/2 assert manualintegrate(1/sqrt(4*x**2 + 1), x) == \ asinh(2*x)/2 assert manualintegrate(1/sqrt(a*x**2 + 1), x) == \ Piecewise((sqrt(-1/a)*asin(x*sqrt(-a)), a < 0), (sqrt(1/a)*asinh(sqrt(a)*x), a > 0)) assert manualintegrate(1/sqrt(a + x**2), x) == \ Piecewise((asinh(x*sqrt(1/a)), a > 0), (acosh(x*sqrt(-1/a)), a < 0)) # acosh assert manualintegrate(1/sqrt(x**2 - 1), x) == \ acosh(x) assert manualintegrate(1/sqrt(x**2 - 4), x) == \ acosh(x/2) assert manualintegrate(1/sqrt(4*x**2 - 4), x) == \ acosh(x)/2 assert manualintegrate(1/sqrt(9*x**2 - 1), x) == \ acosh(3*x)/3 assert manualintegrate(1/sqrt(a*x**2 - 4), x) == \ Piecewise((sqrt(1/a)*acosh(sqrt(a)*x/2), a > 0)) assert manualintegrate(1/sqrt(-a + 4*x**2), x) == \ Piecewise((asinh(2*x*sqrt(-1/a))/2, -a > 0), (acosh(2*x*sqrt(1/a))/2, -a < 0)) # From https://www.wikiwand.com/en/List_of_integrals_of_inverse_trigonometric_functions # asin assert manualintegrate(asin(x), x) == x*asin(x) + sqrt(1 - x**2) assert manualintegrate(asin(a*x), x) == Piecewise(((a*x*asin(a*x) + sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (0, True)) assert manualintegrate(x*asin(a*x), x) == -a*Integral(x**2/sqrt(-a**2*x**2 + 1), x)/2 + x**2*asin(a*x)/2 # acos assert manualintegrate(acos(x), x) == x*acos(x) - sqrt(1 - x**2) assert manualintegrate(acos(a*x), x) == Piecewise(((a*x*acos(a*x) - sqrt(-a**2*x**2 + 1))/a, Ne(a, 0)), (pi*x/2, True)) assert manualintegrate(x*acos(a*x), x) == a*Integral(x**2/sqrt(-a**2*x**2 + 1), x)/2 + x**2*acos(a*x)/2 # atan assert manualintegrate(atan(x), x) == x*atan(x) - log(x**2 + 1)/2 assert manualintegrate(atan(a*x), x) == Piecewise(((a*x*atan(a*x) - log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (0, True)) assert manualintegrate(x*atan(a*x), x) == -a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*atan(a*x)/2 # acsc assert manualintegrate(acsc(x), x) == x*acsc(x) + Integral(1/(x*sqrt(1 - 1/x**2)), x) assert manualintegrate(acsc(a*x), x) == x*acsc(a*x) + Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a assert manualintegrate(x*acsc(a*x), x) == x**2*acsc(a*x)/2 + Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a) # asec assert manualintegrate(asec(x), x) == x*asec(x) - Integral(1/(x*sqrt(1 - 1/x**2)), x) assert manualintegrate(asec(a*x), x) == x*asec(a*x) - Integral(1/(x*sqrt(1 - 1/(a**2*x**2))), x)/a assert manualintegrate(x*asec(a*x), x) == x**2*asec(a*x)/2 - Integral(1/sqrt(1 - 1/(a**2*x**2)), x)/(2*a) # acot assert manualintegrate(acot(x), x) == x*acot(x) + log(x**2 + 1)/2 assert manualintegrate(acot(a*x), x) == Piecewise(((a*x*acot(a*x) + log(a**2*x**2 + 1)/2)/a, Ne(a, 0)), (pi*x/2, True)) assert manualintegrate(x*acot(a*x), x) == a*(x/a**2 - atan(x/sqrt(a**(-2)))/(a**4*sqrt(a**(-2))))/2 + x**2*acot(a*x)/2 # piecewise assert manualintegrate(1/sqrt(a-b*x**2), x) == \ Piecewise((sqrt(a/b)*asin(x*sqrt(b/a))/sqrt(a), And(-b < 0, a > 0)), (sqrt(-a/b)*asinh(x*sqrt(-b/a))/sqrt(a), And(-b > 0, a > 0)), (sqrt(a/b)*acosh(x*sqrt(b/a))/sqrt(-a), And(-b > 0, a < 0))) assert manualintegrate(1/sqrt(a + b*x**2), x) == \ Piecewise((sqrt(-a/b)*asin(x*sqrt(-b/a))/sqrt(a), And(a > 0, b < 0)), (sqrt(a/b)*asinh(x*sqrt(b/a))/sqrt(a), And(a > 0, b > 0)), (sqrt(-a/b)*acosh(x*sqrt(-b/a))/sqrt(-a), And(a < 0, b > 0))) def test_manualintegrate_trig_substitution(): assert manualintegrate(sqrt(16*x**2 - 9)/x, x) == \ Piecewise((sqrt(16*x**2 - 9) - 3*acos(3/(4*x)), And(x < Rational(3, 4), x > Rational(-3, 4)))) assert manualintegrate(1/(x**4 * sqrt(25-x**2)), x) == \ Piecewise((-sqrt(-x**2/25 + 1)/(125*x) - (-x**2/25 + 1)**(3*S.Half)/(15*x**3), And(x < 5, x > -5))) assert manualintegrate(x**7/(49*x**2 + 1)**(3 * S.Half), x) == \ ((49*x**2 + 1)**(5*S.Half)/28824005 - (49*x**2 + 1)**(3*S.Half)/5764801 + 3*sqrt(49*x**2 + 1)/5764801 + 1/(5764801*sqrt(49*x**2 + 1))) def test_manualintegrate_trivial_substitution(): assert manualintegrate((exp(x) - exp(-x))/x, x) == -Ei(-x) + Ei(x) f = Function('f') assert manualintegrate((f(x) - f(-x))/x, x) == \ -Integral(f(-x)/x, x) + Integral(f(x)/x, x) def test_manualintegrate_rational(): assert manualintegrate(1/(4 - x**2), x) == Piecewise((acoth(x/2)/2, x**2 > 4), (atanh(x/2)/2, x**2 < 4)) assert manualintegrate(1/(-1 + x**2), x) == Piecewise((-acoth(x), x**2 > 1), (-atanh(x), x**2 < 1)) def test_manualintegrate_special(): f, F = 4*exp(-x**2/3), 2*sqrt(3)*sqrt(pi)*erf(sqrt(3)*x/3) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = 3*exp(4*x**2), 3*sqrt(pi)*erfi(2*x)/4 assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = x**Rational(1, 3)*exp(-x/8), -16*uppergamma(Rational(4, 3), x/8) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = exp(2*x)/x, Ei(2*x) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = exp(1 + 2*x - x**2), sqrt(pi)*exp(2)*erf(x - 1)/2 assert manualintegrate(f, x) == F and F.diff(x).equals(f) f = sin(x**2 + 4*x + 1) F = (sqrt(2)*sqrt(pi)*(-sin(3)*fresnelc(sqrt(2)*(2*x + 4)/(2*sqrt(pi))) + cos(3)*fresnels(sqrt(2)*(2*x + 4)/(2*sqrt(pi))))/2) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = cos(4*x**2), sqrt(2)*sqrt(pi)*fresnelc(2*sqrt(2)*x/sqrt(pi))/4 assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = sin(3*x + 2)/x, sin(2)*Ci(3*x) + cos(2)*Si(3*x) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = sinh(3*x - 2)/x, -sinh(2)*Chi(3*x) + cosh(2)*Shi(3*x) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = 5*cos(2*x - 3)/x, 5*cos(3)*Ci(2*x) + 5*sin(3)*Si(2*x) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = cosh(x/2)/x, Chi(x/2) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = cos(x**2)/x, Ci(x**2)/2 assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = 1/log(2*x + 1), li(2*x + 1)/2 assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = polylog(2, 5*x)/x, polylog(3, 5*x) assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = 5/sqrt(3 - 2*sin(x)**2), 5*sqrt(3)*elliptic_f(x, Rational(2, 3))/3 assert manualintegrate(f, x) == F and F.diff(x).equals(f) f, F = sqrt(4 + 9*sin(x)**2), 2*elliptic_e(x, Rational(-9, 4)) assert manualintegrate(f, x) == F and F.diff(x).equals(f) def test_manualintegrate_derivative(): assert manualintegrate(pi * Derivative(x**2 + 2*x + 3), x) == \ pi * (x**2 + 2*x + 3) assert manualintegrate(Derivative(x**2 + 2*x + 3, y), x) == \ Integral(Derivative(x**2 + 2*x + 3, y)) assert manualintegrate(Derivative(sin(x), x, x, x, y), x) == \ Derivative(sin(x), x, x, y) def test_manualintegrate_Heaviside(): assert manualintegrate(Heaviside(x), x) == x*Heaviside(x) assert manualintegrate(x*Heaviside(2), x) == x**2/2 assert manualintegrate(x*Heaviside(-2), x) == 0 assert manualintegrate(x*Heaviside( x), x) == x**2*Heaviside( x)/2 assert manualintegrate(x*Heaviside(-x), x) == x**2*Heaviside(-x)/2 assert manualintegrate(Heaviside(2*x + 4), x) == (x+2)*Heaviside(2*x + 4) assert manualintegrate(x*Heaviside(x), x) == x**2*Heaviside(x)/2 assert manualintegrate(Heaviside(x + 1)*Heaviside(1 - x)*x**2, x) == \ ((x**3/3 + Rational(1, 3))*Heaviside(x + 1) - Rational(2, 3))*Heaviside(-x + 1) y = Symbol('y') assert manualintegrate(sin(7 + x)*Heaviside(3*x - 7), x) == \ (- cos(x + 7) + cos(Rational(28, 3)))*Heaviside(3*x - S(7)) assert manualintegrate(sin(y + x)*Heaviside(3*x - y), x) == \ (cos(y*Rational(4, 3)) - cos(x + y))*Heaviside(3*x - y) def test_manualintegrate_orthogonal_poly(): n = symbols('n') a, b = 7, Rational(5, 3) polys = [jacobi(n, a, b, x), gegenbauer(n, a, x), chebyshevt(n, x), chebyshevu(n, x), legendre(n, x), hermite(n, x), laguerre(n, x), assoc_laguerre(n, a, x)] for p in polys: integral = manualintegrate(p, x) for deg in [-2, -1, 0, 1, 3, 5, 8]: # some accept negative "degree", some do not try: p_subbed = p.subs(n, deg) except ValueError: continue assert (integral.subs(n, deg).diff(x) - p_subbed).expand() == 0 # can also integrate simple expressions with these polynomials q = x*p.subs(x, 2*x + 1) integral = manualintegrate(q, x) for deg in [2, 4, 7]: assert (integral.subs(n, deg).diff(x) - q.subs(n, deg)).expand() == 0 # cannot integrate with respect to any other parameter t = symbols('t') for i in range(len(p.args) - 1): new_args = list(p.args) new_args[i] = t assert isinstance(manualintegrate(p.func(*new_args), t), Integral) @slow def test_issue_6799(): r, x, phi = map(Symbol, 'r x phi'.split()) n = Symbol('n', integer=True, positive=True) integrand = (cos(n*(x-phi))*cos(n*x)) limits = (x, -pi, pi) assert manualintegrate(integrand, x) == \ ((n*x/2 + sin(2*n*x)/4)*cos(n*phi) - sin(n*phi)*cos(n*x)**2/2)/n assert r * integrate(integrand, limits).trigsimp() / pi == r * cos(n * phi) assert not integrate(integrand, limits).has(Dummy) def test_issue_12251(): assert manualintegrate(x**y, x) == Piecewise( (x**(y + 1)/(y + 1), Ne(y, -1)), (log(x), True)) def test_issue_3796(): assert manualintegrate(diff(exp(x + x**2)), x) == exp(x + x**2) assert integrate(x * exp(x**4), x, risch=False) == -I*sqrt(pi)*erf(I*x**2)/4 def test_manual_true(): assert integrate(exp(x) * sin(x), x, manual=True) == \ (exp(x) * sin(x)) / 2 - (exp(x) * cos(x)) / 2 assert integrate(sin(x) * cos(x), x, manual=True) in \ [sin(x) ** 2 / 2, -cos(x)**2 / 2] def test_issue_6746(): y = Symbol('y') n = Symbol('n') assert manualintegrate(y**x, x) == Piecewise( (y**x/log(y), Ne(log(y), 0)), (x, True)) assert manualintegrate(y**(n*x), x) == Piecewise( (Piecewise( (y**(n*x)/log(y), Ne(log(y), 0)), (n*x, True) )/n, Ne(n, 0)), (x, True)) assert manualintegrate(exp(n*x), x) == Piecewise( (exp(n*x)/n, Ne(n, 0)), (x, True)) y = Symbol('y', positive=True) assert manualintegrate((y + 1)**x, x) == (y + 1)**x/log(y + 1) y = Symbol('y', zero=True) assert manualintegrate((y + 1)**x, x) == x y = Symbol('y') n = Symbol('n', nonzero=True) assert manualintegrate(y**(n*x), x) == Piecewise( (y**(n*x)/log(y), Ne(log(y), 0)), (n*x, True))/n y = Symbol('y', positive=True) assert manualintegrate((y + 1)**(n*x), x) == \ (y + 1)**(n*x)/(n*log(y + 1)) a = Symbol('a', negative=True) b = Symbol('b') assert manualintegrate(1/(a + b*x**2), x) == atan(x/sqrt(a/b))/(b*sqrt(a/b)) b = Symbol('b', negative=True) assert manualintegrate(1/(a + b*x**2), x) == \ atan(x/(sqrt(-a)*sqrt(-1/b)))/(b*sqrt(-a)*sqrt(-1/b)) assert manualintegrate(1/((x**a + y**b + 4)*sqrt(a*x**2 + 1)), x) == \ y**(-b)*Integral(x**(-a)/(y**(-b)*sqrt(a*x**2 + 1) + x**(-a)*sqrt(a*x**2 + 1) + 4*x**(-a)*y**(-b)*sqrt(a*x**2 + 1)), x) assert manualintegrate(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x) == \ Integral(1/((x**2 + 4)*sqrt(4*x**2 + 1)), x) assert manualintegrate(1/(x - a**x + x*b**2), x) == \ Integral(1/(-a**x + b**2*x + x), x) @slow def test_issue_2850(): assert manualintegrate(asin(x)*log(x), x) == -x*asin(x) - sqrt(-x**2 + 1) \ + (x*asin(x) + sqrt(-x**2 + 1))*log(x) - Integral(sqrt(-x**2 + 1)/x, x) assert manualintegrate(acos(x)*log(x), x) == -x*acos(x) + sqrt(-x**2 + 1) + \ (x*acos(x) - sqrt(-x**2 + 1))*log(x) + Integral(sqrt(-x**2 + 1)/x, x) assert manualintegrate(atan(x)*log(x), x) == -x*atan(x) + (x*atan(x) - \ log(x**2 + 1)/2)*log(x) + log(x**2 + 1)/2 + Integral(log(x**2 + 1)/x, x)/2 def test_issue_9462(): assert manualintegrate(sin(2*x)*exp(x), x) == exp(x)*sin(2*x)/5 - 2*exp(x)*cos(2*x)/5 assert not contains_dont_know(integral_steps(sin(2*x)*exp(x), x)) assert manualintegrate((x - 3) / (x**2 - 2*x + 2)**2, x) == \ Integral(x/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x) \ - 3*Integral(1/(x**4 - 4*x**3 + 8*x**2 - 8*x + 4), x) def test_cyclic_parts(): f = cos(x)*exp(x/4) F = 16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17 assert manualintegrate(f, x) == F and F.diff(x) == f f = x*cos(x)*exp(x/4) F = (x*(16*exp(x/4)*sin(x)/17 + 4*exp(x/4)*cos(x)/17) - 128*exp(x/4)*sin(x)/289 + 240*exp(x/4)*cos(x)/289) assert manualintegrate(f, x) == F and F.diff(x) == f @slow def test_issue_10847_slow(): assert manualintegrate((4*x**4 + 4*x**3 + 16*x**2 + 12*x + 8) / (x**6 + 2*x**5 + 3*x**4 + 4*x**3 + 3*x**2 + 2*x + 1), x) == \ 2*x/(x**2 + 1) + 3*atan(x) - 1/(x**2 + 1) - 3/(x + 1) @slow def test_issue_10847(): assert manualintegrate(x**2 / (x**2 - c), x) == c*atan(x/sqrt(-c))/sqrt(-c) + x rc = Symbol('c', real=True) assert manualintegrate(x**2 / (x**2 - rc), x) == \ rc*Piecewise((atan(x/sqrt(-rc))/sqrt(-rc), -rc > 0), (-acoth(x/sqrt(rc))/sqrt(rc), And(-rc < 0, x**2 > rc)), (-atanh(x/sqrt(rc))/sqrt(rc), And(-rc < 0, x**2 < rc))) + x assert manualintegrate(sqrt(x - y) * log(z / x), x) == \ 4*y**Rational(3, 2)*atan(sqrt(x - y)/sqrt(y))/3 - 4*y*sqrt(x - y)/3 +\ 2*(x - y)**Rational(3, 2)*log(z/x)/3 + 4*(x - y)**Rational(3, 2)/9 ry = Symbol('y', real=True) rz = Symbol('z', real=True) assert manualintegrate(sqrt(x - ry) * log(rz / x), x) == \ 4*ry**2*Piecewise((atan(sqrt(x - ry)/sqrt(ry))/sqrt(ry), ry > 0), (-acoth(sqrt(x - ry)/sqrt(-ry))/sqrt(-ry), And(x - ry > -ry, ry < 0)), (-atanh(sqrt(x - ry)/sqrt(-ry))/sqrt(-ry), And(x - ry < -ry, ry < 0)))/3 \ - 4*ry*sqrt(x - ry)/3 + 2*(x - ry)**Rational(3, 2)*log(rz/x)/3 \ + 4*(x - ry)**Rational(3, 2)/9 assert manualintegrate(sqrt(x) * log(x), x) == 2*x**Rational(3, 2)*log(x)/3 - 4*x**Rational(3, 2)/9 assert manualintegrate(sqrt(a*x + b) / x, x) == \ 2*b*atan(sqrt(a*x + b)/sqrt(-b))/sqrt(-b) + 2*sqrt(a*x + b) ra = Symbol('a', real=True) rb = Symbol('b', real=True) assert manualintegrate(sqrt(ra*x + rb) / x, x) == \ -2*rb*Piecewise((-atan(sqrt(ra*x + rb)/sqrt(-rb))/sqrt(-rb), -rb > 0), (acoth(sqrt(ra*x + rb)/sqrt(rb))/sqrt(rb), And(-rb < 0, ra*x + rb > rb)), (atanh(sqrt(ra*x + rb)/sqrt(rb))/sqrt(rb), And(-rb < 0, ra*x + rb < rb))) \ + 2*sqrt(ra*x + rb) assert expand(manualintegrate(sqrt(ra*x + rb) / (x + rc), x)) == -2*ra*rc*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), \ ra*rc - rb > 0), (-acoth(sqrt(ra*x + rb)/sqrt(-ra*rc + rb))/sqrt(-ra*rc + rb), And(ra*rc - rb < 0, ra*x + rb > -ra*rc + rb)), \ (-atanh(sqrt(ra*x + rb)/sqrt(-ra*rc + rb))/sqrt(-ra*rc + rb), And(ra*rc - rb < 0, ra*x + rb < -ra*rc + rb))) \ + 2*rb*Piecewise((atan(sqrt(ra*x + rb)/sqrt(ra*rc - rb))/sqrt(ra*rc - rb), ra*rc - rb > 0), \ (-acoth(sqrt(ra*x + rb)/sqrt(-ra*rc + rb))/sqrt(-ra*rc + rb), And(ra*rc - rb < 0, ra*x + rb > -ra*rc + rb)), \ (-atanh(sqrt(ra*x + rb)/sqrt(-ra*rc + rb))/sqrt(-ra*rc + rb), And(ra*rc - rb < 0, ra*x + rb < -ra*rc + rb))) + 2*sqrt(ra*x + rb) assert manualintegrate(sqrt(2*x + 3) / (x + 1), x) == 2*sqrt(2*x + 3) - log(sqrt(2*x + 3) + 1) + log(sqrt(2*x + 3) - 1) assert manualintegrate(sqrt(2*x + 3) / 2 * x, x) == (2*x + 3)**Rational(5, 2)/20 - (2*x + 3)**Rational(3, 2)/4 assert manualintegrate(x**Rational(3,2) * log(x), x) == 2*x**Rational(5,2)*log(x)/5 - 4*x**Rational(5,2)/25 assert manualintegrate(x**(-3) * log(x), x) == -log(x)/(2*x**2) - 1/(4*x**2) assert manualintegrate(log(y)/(y**2*(1 - 1/y)), y) == \ log(y)*log(-1 + 1/y) - Integral(log(-1 + 1/y)/y, y) def test_issue_12899(): assert manualintegrate(f(x,y).diff(x),y) == Integral(Derivative(f(x,y),x),y) assert manualintegrate(f(x,y).diff(y).diff(x),y) == Derivative(f(x,y),x) def test_constant_independent_of_symbol(): assert manualintegrate(Integral(y, (x, 1, 2)), x) == \ x*Integral(y, (x, 1, 2)) def test_issue_12641(): assert manualintegrate(sin(2*x), x) == -cos(2*x)/2 assert manualintegrate(cos(x)*sin(2*x), x) == -2*cos(x)**3/3 assert manualintegrate((sin(2*x)*cos(x))/(1 + cos(x)), x) == \ -2*log(cos(x) + 1) - cos(x)**2 + 2*cos(x) @slow def test_issue_13297(): assert manualintegrate(sin(x) * cos(x)**5, x) == -cos(x)**6 / 6 def test_issue_14470(): assert manualintegrate(1/(x*sqrt(x + 1)), x) == \ log(-1 + 1/sqrt(x + 1)) - log(1 + 1/sqrt(x + 1)) @slow def test_issue_9858(): assert manualintegrate(exp(x)*cos(exp(x)), x) == sin(exp(x)) assert manualintegrate(exp(2*x)*cos(exp(x)), x) == \ exp(x)*sin(exp(x)) + cos(exp(x)) res = manualintegrate(exp(10*x)*sin(exp(x)), x) assert not res.has(Integral) assert res.diff(x) == exp(10*x)*sin(exp(x)) # an example with many similar integrations by parts assert manualintegrate(sum([x*exp(k*x) for k in range(1, 8)]), x) == ( x*exp(7*x)/7 + x*exp(6*x)/6 + x*exp(5*x)/5 + x*exp(4*x)/4 + x*exp(3*x)/3 + x*exp(2*x)/2 + x*exp(x) - exp(7*x)/49 -exp(6*x)/36 - exp(5*x)/25 - exp(4*x)/16 - exp(3*x)/9 - exp(2*x)/4 - exp(x)) def test_issue_8520(): assert manualintegrate(x/(x**4 + 1), x) == atan(x**2)/2 assert manualintegrate(x**2/(x**6 + 25), x) == atan(x**3/5)/15 f = x/(9*x**4 + 4)**2 assert manualintegrate(f, x).diff(x).factor() == f def test_manual_subs(): x, y = symbols('x y') expr = log(x) + exp(x) # if log(x) is y, then exp(y) is x assert manual_subs(expr, log(x), y) == y + exp(exp(y)) # if exp(x) is y, then log(y) need not be x assert manual_subs(expr, exp(x), y) == log(x) + y raises(ValueError, lambda: manual_subs(expr, x)) raises(ValueError, lambda: manual_subs(expr, exp(x), x, y)) @slow def test_issue_15471(): f = log(x)*cos(log(x))/x**Rational(3, 4) F = -128*x**Rational(1, 4)*sin(log(x))/289 + 240*x**Rational(1, 4)*cos(log(x))/289 + (16*x**Rational(1, 4)*sin(log(x))/17 + 4*x**Rational(1, 4)*cos(log(x))/17)*log(x) assert manualintegrate(f, x) == F and F.diff(x).equals(f) def test_quadratic_denom(): f = (5*x + 2)/(3*x**2 - 2*x + 8) assert manualintegrate(f, x) == 5*log(3*x**2 - 2*x + 8)/6 + 11*sqrt(23)*atan(3*sqrt(23)*(x - Rational(1, 3))/23)/69 g = 3/(2*x**2 + 3*x + 1) assert manualintegrate(g, x) == 3*log(4*x + 2) - 3*log(4*x + 4) sympy-sympy-1.9/sympy/integrals/tests/test_meijerint.py000066400000000000000000000727741412543434000236560ustar00rootroot00000000000000from sympy import (meijerg, I, S, integrate, Integral, oo, gamma, cosh, sinc, hyperexpand, exp, simplify, sqrt, pi, erf, erfc, sin, cos, exp_polar, polygamma, hyper, log, expand_func, Rational) from sympy.integrals.meijerint import (_rewrite_single, _rewrite1, meijerint_indefinite, _inflate_g, _create_lookup_table, meijerint_definite, meijerint_inversion) from sympy.utilities import default_sort_key from sympy.testing.pytest import slow from sympy.testing.randtest import (verify_numerically, random_complex_number as randcplx) from sympy.abc import x, y, a, b, c, d, s, t, z def test_rewrite_single(): def t(expr, c, m): e = _rewrite_single(meijerg([a], [b], [c], [d], expr), x) assert e is not None assert isinstance(e[0][0][2], meijerg) assert e[0][0][2].argument.as_coeff_mul(x) == (c, (m,)) def tn(expr): assert _rewrite_single(meijerg([a], [b], [c], [d], expr), x) is None t(x, 1, x) t(x**2, 1, x**2) t(x**2 + y*x**2, y + 1, x**2) tn(x**2 + x) tn(x**y) def u(expr, x): from sympy import Add, exp, exp_polar r = _rewrite_single(expr, x) e = Add(*[res[0]*res[2] for res in r[0]]).replace( exp_polar, exp) # XXX Hack? assert verify_numerically(e, expr, x) u(exp(-x)*sin(x), x) # The following has stopped working because hyperexpand changed slightly. # It is probably not worth fixing #u(exp(-x)*sin(x)*cos(x), x) # This one cannot be done numerically, since it comes out as a g-function # of argument 4*pi # NOTE This also tests a bug in inverse mellin transform (which used to # turn exp(4*pi*I*t) into a factor of exp(4*pi*I)**t instead of # exp_polar). #u(exp(x)*sin(x), x) assert _rewrite_single(exp(x)*sin(x), x) == \ ([(-sqrt(2)/(2*sqrt(pi)), 0, meijerg(((Rational(-1, 2), 0, Rational(1, 4), S.Half, Rational(3, 4)), (1,)), ((), (Rational(-1, 2), 0)), 64*exp_polar(-4*I*pi)/x**4))], True) def test_rewrite1(): assert _rewrite1(x**3*meijerg([a], [b], [c], [d], x**2 + y*x**2)*5, x) == \ (5, x**3, [(1, 0, meijerg([a], [b], [c], [d], x**2*(y + 1)))], True) def test_meijerint_indefinite_numerically(): def t(fac, arg): g = meijerg([a], [b], [c], [d], arg)*fac subs = {a: randcplx()/10, b: randcplx()/10 + I, c: randcplx(), d: randcplx()} integral = meijerint_indefinite(g, x) assert integral is not None assert verify_numerically(g.subs(subs), integral.diff(x).subs(subs), x) t(1, x) t(2, x) t(1, 2*x) t(1, x**2) t(5, x**S('3/2')) t(x**3, x) t(3*x**S('3/2'), 4*x**S('7/3')) def test_meijerint_definite(): v, b = meijerint_definite(x, x, 0, 0) assert v.is_zero and b is True v, b = meijerint_definite(x, x, oo, oo) assert v.is_zero and b is True def test_inflate(): subs = {a: randcplx()/10, b: randcplx()/10 + I, c: randcplx(), d: randcplx(), y: randcplx()/10} def t(a, b, arg, n): from sympy import Mul m1 = meijerg(a, b, arg) m2 = Mul(*_inflate_g(m1, n)) # NOTE: (the random number)**9 must still be on the principal sheet. # Thus make b&d small to create random numbers of small imaginary part. return verify_numerically(m1.subs(subs), m2.subs(subs), x, b=0.1, d=-0.1) assert t([[a], [b]], [[c], [d]], x, 3) assert t([[a, y], [b]], [[c], [d]], x, 3) assert t([[a], [b]], [[c, y], [d]], 2*x**3, 3) def test_recursive(): from sympy import symbols a, b, c = symbols('a b c', positive=True) r = exp(-(x - a)**2)*exp(-(x - b)**2) e = integrate(r, (x, 0, oo), meijerg=True) assert simplify(e.expand()) == ( sqrt(2)*sqrt(pi)*( (erf(sqrt(2)*(a + b)/2) + 1)*exp(-a**2/2 + a*b - b**2/2))/4) e = integrate(exp(-(x - a)**2)*exp(-(x - b)**2)*exp(c*x), (x, 0, oo), meijerg=True) assert simplify(e) == ( sqrt(2)*sqrt(pi)*(erf(sqrt(2)*(2*a + 2*b + c)/4) + 1)*exp(-a**2 - b**2 + (2*a + 2*b + c)**2/8)/4) assert simplify(integrate(exp(-(x - a - b - c)**2), (x, 0, oo), meijerg=True)) == \ sqrt(pi)/2*(1 + erf(a + b + c)) assert simplify(integrate(exp(-(x + a + b + c)**2), (x, 0, oo), meijerg=True)) == \ sqrt(pi)/2*(1 - erf(a + b + c)) @slow def test_meijerint(): from sympy import symbols, expand, arg s, t, mu = symbols('s t mu', real=True) assert integrate(meijerg([], [], [0], [], s*t) *meijerg([], [], [mu/2], [-mu/2], t**2/4), (t, 0, oo)).is_Piecewise s = symbols('s', positive=True) assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo)) == \ gamma(s + 1) assert integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo), meijerg=True) == gamma(s + 1) assert isinstance(integrate(x**s*meijerg([[], []], [[0], []], x), (x, 0, oo), meijerg=False), Integral) assert meijerint_indefinite(exp(x), x) == exp(x) # TODO what simplifications should be done automatically? # This tests "extra case" for antecedents_1. a, b = symbols('a b', positive=True) assert simplify(meijerint_definite(x**a, x, 0, b)[0]) == \ b**(a + 1)/(a + 1) # This tests various conditions and expansions: meijerint_definite((x + 1)**3*exp(-x), x, 0, oo) == (16, True) # Again, how about simplifications? sigma, mu = symbols('sigma mu', positive=True) i, c = meijerint_definite(exp(-((x - mu)/(2*sigma))**2), x, 0, oo) assert simplify(i) == sqrt(pi)*sigma*(2 - erfc(mu/(2*sigma))) assert c == True i, _ = meijerint_definite(exp(-mu*x)*exp(sigma*x), x, 0, oo) # TODO it would be nice to test the condition assert simplify(i) == 1/(mu - sigma) # Test substitutions to change limits assert meijerint_definite(exp(x), x, -oo, 2) == (exp(2), True) # Note: causes a NaN in _check_antecedents assert expand(meijerint_definite(exp(x), x, 0, I)[0]) == exp(I) - 1 assert expand(meijerint_definite(exp(-x), x, 0, x)[0]) == \ 1 - exp(-exp(I*arg(x))*abs(x)) # Test -oo to oo assert meijerint_definite(exp(-x**2), x, -oo, oo) == (sqrt(pi), True) assert meijerint_definite(exp(-abs(x)), x, -oo, oo) == (2, True) assert meijerint_definite(exp(-(2*x - 3)**2), x, -oo, oo) == \ (sqrt(pi)/2, True) assert meijerint_definite(exp(-abs(2*x - 3)), x, -oo, oo) == (1, True) assert meijerint_definite(exp(-((x - mu)/sigma)**2/2)/sqrt(2*pi*sigma**2), x, -oo, oo) == (1, True) assert meijerint_definite(sinc(x)**2, x, -oo, oo) == (pi, True) # Test one of the extra conditions for 2 g-functinos assert meijerint_definite(exp(-x)*sin(x), x, 0, oo) == (S.Half, True) # Test a bug def res(n): return (1/(1 + x**2)).diff(x, n).subs(x, 1)*(-1)**n for n in range(6): assert integrate(exp(-x)*sin(x)*x**n, (x, 0, oo), meijerg=True) == \ res(n) # This used to test trigexpand... now it is done by linear substitution assert simplify(integrate(exp(-x)*sin(x + a), (x, 0, oo), meijerg=True) ) == sqrt(2)*sin(a + pi/4)/2 # Test the condition 14 from prudnikov. # (This is besselj*besselj in disguise, to stop the product from being # recognised in the tables.) a, b, s = symbols('a b s') from sympy import And, re assert meijerint_definite(meijerg([], [], [a/2], [-a/2], x/4) *meijerg([], [], [b/2], [-b/2], x/4)*x**(s - 1), x, 0, oo) == \ (4*2**(2*s - 2)*gamma(-2*s + 1)*gamma(a/2 + b/2 + s) /(gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1) *gamma(a/2 + b/2 - s + 1)), And(0 < -2*re(4*s) + 8, 0 < re(a/2 + b/2 + s), re(2*s) < 1)) # test a bug assert integrate(sin(x**a)*sin(x**b), (x, 0, oo), meijerg=True) == \ Integral(sin(x**a)*sin(x**b), (x, 0, oo)) # test better hyperexpand assert integrate(exp(-x**2)*log(x), (x, 0, oo), meijerg=True) == \ (sqrt(pi)*polygamma(0, S.Half)/4).expand() # Test hyperexpand bug. from sympy import lowergamma n = symbols('n', integer=True) assert simplify(integrate(exp(-x)*x**n, x, meijerg=True)) == \ lowergamma(n + 1, x) # Test a bug with argument 1/x alpha = symbols('alpha', positive=True) assert meijerint_definite((2 - x)**alpha*sin(alpha/x), x, 0, 2) == \ (sqrt(pi)*alpha*gamma(alpha + 1)*meijerg(((), (alpha/2 + S.Half, alpha/2 + 1)), ((0, 0, S.Half), (Rational(-1, 2),)), alpha**2/16)/4, True) # test a bug related to 3016 a, s = symbols('a s', positive=True) assert simplify(integrate(x**s*exp(-a*x**2), (x, -oo, oo))) == \ a**(-s/2 - S.Half)*((-1)**s + 1)*gamma(s/2 + S.Half)/2 def test_bessel(): from sympy import besselj, besseli assert simplify(integrate(besselj(a, z)*besselj(b, z)/z, (z, 0, oo), meijerg=True, conds='none')) == \ 2*sin(pi*(a/2 - b/2))/(pi*(a - b)*(a + b)) assert simplify(integrate(besselj(a, z)*besselj(a, z)/z, (z, 0, oo), meijerg=True, conds='none')) == 1/(2*a) # TODO more orthogonality integrals assert simplify(integrate(sin(z*x)*(x**2 - 1)**(-(y + S.Half)), (x, 1, oo), meijerg=True, conds='none') *2/((z/2)**y*sqrt(pi)*gamma(S.Half - y))) == \ besselj(y, z) # Werner Rosenheinrich # SOME INDEFINITE INTEGRALS OF BESSEL FUNCTIONS assert integrate(x*besselj(0, x), x, meijerg=True) == x*besselj(1, x) assert integrate(x*besseli(0, x), x, meijerg=True) == x*besseli(1, x) # TODO can do higher powers, but come out as high order ... should they be # reduced to order 0, 1? assert integrate(besselj(1, x), x, meijerg=True) == -besselj(0, x) assert integrate(besselj(1, x)**2/x, x, meijerg=True) == \ -(besselj(0, x)**2 + besselj(1, x)**2)/2 # TODO more besseli when tables are extended or recursive mellin works assert integrate(besselj(0, x)**2/x**2, x, meijerg=True) == \ -2*x*besselj(0, x)**2 - 2*x*besselj(1, x)**2 \ + 2*besselj(0, x)*besselj(1, x) - besselj(0, x)**2/x assert integrate(besselj(0, x)*besselj(1, x), x, meijerg=True) == \ -besselj(0, x)**2/2 assert integrate(x**2*besselj(0, x)*besselj(1, x), x, meijerg=True) == \ x**2*besselj(1, x)**2/2 assert integrate(besselj(0, x)*besselj(1, x)/x, x, meijerg=True) == \ (x*besselj(0, x)**2 + x*besselj(1, x)**2 - besselj(0, x)*besselj(1, x)) # TODO how does besselj(0, a*x)*besselj(0, b*x) work? # TODO how does besselj(0, x)**2*besselj(1, x)**2 work? # TODO sin(x)*besselj(0, x) etc come out a mess # TODO can x*log(x)*besselj(0, x) be done? # TODO how does besselj(1, x)*besselj(0, x+a) work? # TODO more indefinite integrals when struve functions etc are implemented # test a substitution assert integrate(besselj(1, x**2)*x, x, meijerg=True) == \ -besselj(0, x**2)/2 def test_inversion(): from sympy import piecewise_fold, besselj, sqrt, sin, cos, Heaviside def inv(f): return piecewise_fold(meijerint_inversion(f, s, t)) assert inv(1/(s**2 + 1)) == sin(t)*Heaviside(t) assert inv(s/(s**2 + 1)) == cos(t)*Heaviside(t) assert inv(exp(-s)/s) == Heaviside(t - 1) assert inv(1/sqrt(1 + s**2)) == besselj(0, t)*Heaviside(t) # Test some antcedents checking. assert meijerint_inversion(sqrt(s)/sqrt(1 + s**2), s, t) is None assert inv(exp(s**2)) is None assert meijerint_inversion(exp(-s**2), s, t) is None def test_inversion_conditional_output(): from sympy import Symbol, InverseLaplaceTransform a = Symbol('a', positive=True) F = sqrt(pi/a)*exp(-2*sqrt(a)*sqrt(s)) f = meijerint_inversion(F, s, t) assert not f.is_Piecewise b = Symbol('b', real=True) F = F.subs(a, b) f2 = meijerint_inversion(F, s, t) assert f2.is_Piecewise # first piece is same as f assert f2.args[0][0] == f.subs(a, b) # last piece is an unevaluated transform assert f2.args[-1][1] ILT = InverseLaplaceTransform(F, s, t, None) assert f2.args[-1][0] == ILT or f2.args[-1][0] == ILT.as_integral def test_inversion_exp_real_nonreal_shift(): from sympy import Symbol, DiracDelta r = Symbol('r', real=True) c = Symbol('c', extended_real=False) a = 1 + 2*I z = Symbol('z') assert not meijerint_inversion(exp(r*s), s, t).is_Piecewise assert meijerint_inversion(exp(a*s), s, t) is None assert meijerint_inversion(exp(c*s), s, t) is None f = meijerint_inversion(exp(z*s), s, t) assert f.is_Piecewise assert isinstance(f.args[0][0], DiracDelta) @slow def test_lookup_table(): from random import uniform, randrange from sympy import Add from sympy.integrals.meijerint import z as z_dummy table = {} _create_lookup_table(table) for _, l in sorted(table.items()): for formula, terms, cond, hint in sorted(l, key=default_sort_key): subs = {} for ai in list(formula.free_symbols) + [z_dummy]: if hasattr(ai, 'properties') and ai.properties: # these Wilds match positive integers subs[ai] = randrange(1, 10) else: subs[ai] = uniform(1.5, 2.0) if not isinstance(terms, list): terms = terms(subs) # First test that hyperexpand can do this. expanded = [hyperexpand(g) for (_, g) in terms] assert all(x.is_Piecewise or not x.has(meijerg) for x in expanded) # Now test that the meijer g-function is indeed as advertised. expanded = Add(*[f*x for (f, x) in terms]) a, b = formula.n(subs=subs), expanded.n(subs=subs) r = min(abs(a), abs(b)) if r < 1: assert abs(a - b).n() <= 1e-10 else: assert (abs(a - b)/r).n() <= 1e-10 def test_branch_bug(): from sympy import powdenest, lowergamma # TODO gammasimp cannot prove that the factor is unity assert powdenest(integrate(erf(x**3), x, meijerg=True).diff(x), polar=True) == 2*erf(x**3)*gamma(Rational(2, 3))/3/gamma(Rational(5, 3)) assert integrate(erf(x**3), x, meijerg=True) == \ 2*x*erf(x**3)*gamma(Rational(2, 3))/(3*gamma(Rational(5, 3))) \ - 2*gamma(Rational(2, 3))*lowergamma(Rational(2, 3), x**6)/(3*sqrt(pi)*gamma(Rational(5, 3))) def test_linear_subs(): from sympy import besselj assert integrate(sin(x - 1), x, meijerg=True) == -cos(1 - x) assert integrate(besselj(1, x - 1), x, meijerg=True) == -besselj(0, 1 - x) @slow def test_probability(): # various integrals from probability theory from sympy.abc import x, y from sympy import symbols, Symbol, Abs, expand_mul, gammasimp, powsimp, sin mu1, mu2 = symbols('mu1 mu2', nonzero=True) sigma1, sigma2 = symbols('sigma1 sigma2', positive=True) rate = Symbol('lambda', positive=True) def normal(x, mu, sigma): return 1/sqrt(2*pi*sigma**2)*exp(-(x - mu)**2/2/sigma**2) def exponential(x, rate): return rate*exp(-rate*x) assert integrate(normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == 1 assert integrate(x*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) == \ mu1 assert integrate(x**2*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \ == mu1**2 + sigma1**2 assert integrate(x**3*normal(x, mu1, sigma1), (x, -oo, oo), meijerg=True) \ == mu1**3 + 3*mu1*sigma1**2 assert integrate(normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == 1 assert integrate(x*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1 assert integrate(y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu2 assert integrate(x*y*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == mu1*mu2 assert integrate((x + y + 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == 1 + mu1 + mu2 assert integrate((x + y - 1)*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == \ -1 + mu1 + mu2 i = integrate(x**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) assert not i.has(Abs) assert simplify(i) == mu1**2 + sigma1**2 assert integrate(y**2*normal(x, mu1, sigma1)*normal(y, mu2, sigma2), (x, -oo, oo), (y, -oo, oo), meijerg=True) == \ sigma2**2 + mu2**2 assert integrate(exponential(x, rate), (x, 0, oo), meijerg=True) == 1 assert integrate(x*exponential(x, rate), (x, 0, oo), meijerg=True) == \ 1/rate assert integrate(x**2*exponential(x, rate), (x, 0, oo), meijerg=True) == \ 2/rate**2 def E(expr): res1 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), (x, 0, oo), (y, -oo, oo), meijerg=True) res2 = integrate(expr*exponential(x, rate)*normal(y, mu1, sigma1), (y, -oo, oo), (x, 0, oo), meijerg=True) assert expand_mul(res1) == expand_mul(res2) return res1 assert E(1) == 1 assert E(x*y) == mu1/rate assert E(x*y**2) == mu1**2/rate + sigma1**2/rate ans = sigma1**2 + 1/rate**2 assert simplify(E((x + y + 1)**2) - E(x + y + 1)**2) == ans assert simplify(E((x + y - 1)**2) - E(x + y - 1)**2) == ans assert simplify(E((x + y)**2) - E(x + y)**2) == ans # Beta' distribution alpha, beta = symbols('alpha beta', positive=True) betadist = x**(alpha - 1)*(1 + x)**(-alpha - beta)*gamma(alpha + beta) \ /gamma(alpha)/gamma(beta) assert integrate(betadist, (x, 0, oo), meijerg=True) == 1 i = integrate(x*betadist, (x, 0, oo), meijerg=True, conds='separate') assert (gammasimp(i[0]), i[1]) == (alpha/(beta - 1), 1 < beta) j = integrate(x**2*betadist, (x, 0, oo), meijerg=True, conds='separate') assert j[1] == (1 < beta - 1) assert gammasimp(j[0] - i[0]**2) == (alpha + beta - 1)*alpha \ /(beta - 2)/(beta - 1)**2 # Beta distribution # NOTE: this is evaluated using antiderivatives. It also tests that # meijerint_indefinite returns the simplest possible answer. a, b = symbols('a b', positive=True) betadist = x**(a - 1)*(-x + 1)**(b - 1)*gamma(a + b)/(gamma(a)*gamma(b)) assert simplify(integrate(betadist, (x, 0, 1), meijerg=True)) == 1 assert simplify(integrate(x*betadist, (x, 0, 1), meijerg=True)) == \ a/(a + b) assert simplify(integrate(x**2*betadist, (x, 0, 1), meijerg=True)) == \ a*(a + 1)/(a + b)/(a + b + 1) assert simplify(integrate(x**y*betadist, (x, 0, 1), meijerg=True)) == \ gamma(a + b)*gamma(a + y)/gamma(a)/gamma(a + b + y) # Chi distribution k = Symbol('k', integer=True, positive=True) chi = 2**(1 - k/2)*x**(k - 1)*exp(-x**2/2)/gamma(k/2) assert powsimp(integrate(chi, (x, 0, oo), meijerg=True)) == 1 assert simplify(integrate(x*chi, (x, 0, oo), meijerg=True)) == \ sqrt(2)*gamma((k + 1)/2)/gamma(k/2) assert simplify(integrate(x**2*chi, (x, 0, oo), meijerg=True)) == k # Chi^2 distribution chisquared = 2**(-k/2)/gamma(k/2)*x**(k/2 - 1)*exp(-x/2) assert powsimp(integrate(chisquared, (x, 0, oo), meijerg=True)) == 1 assert simplify(integrate(x*chisquared, (x, 0, oo), meijerg=True)) == k assert simplify(integrate(x**2*chisquared, (x, 0, oo), meijerg=True)) == \ k*(k + 2) assert gammasimp(integrate(((x - k)/sqrt(2*k))**3*chisquared, (x, 0, oo), meijerg=True)) == 2*sqrt(2)/sqrt(k) # Dagum distribution a, b, p = symbols('a b p', positive=True) # XXX (x/b)**a does not work dagum = a*p/x*(x/b)**(a*p)/(1 + x**a/b**a)**(p + 1) assert simplify(integrate(dagum, (x, 0, oo), meijerg=True)) == 1 # XXX conditions are a mess arg = x*dagum assert simplify(integrate(arg, (x, 0, oo), meijerg=True, conds='none') ) == a*b*gamma(1 - 1/a)*gamma(p + 1 + 1/a)/( (a*p + 1)*gamma(p)) assert simplify(integrate(x*arg, (x, 0, oo), meijerg=True, conds='none') ) == a*b**2*gamma(1 - 2/a)*gamma(p + 1 + 2/a)/( (a*p + 2)*gamma(p)) # F-distribution d1, d2 = symbols('d1 d2', positive=True) f = sqrt(((d1*x)**d1 * d2**d2)/(d1*x + d2)**(d1 + d2))/x \ /gamma(d1/2)/gamma(d2/2)*gamma((d1 + d2)/2) assert simplify(integrate(f, (x, 0, oo), meijerg=True)) == 1 # TODO conditions are a mess assert simplify(integrate(x*f, (x, 0, oo), meijerg=True, conds='none') ) == d2/(d2 - 2) assert simplify(integrate(x**2*f, (x, 0, oo), meijerg=True, conds='none') ) == d2**2*(d1 + 2)/d1/(d2 - 4)/(d2 - 2) # TODO gamma, rayleigh # inverse gaussian lamda, mu = symbols('lamda mu', positive=True) dist = sqrt(lamda/2/pi)*x**(Rational(-3, 2))*exp(-lamda*(x - mu)**2/x/2/mu**2) mysimp = lambda expr: simplify(expr.rewrite(exp)) assert mysimp(integrate(dist, (x, 0, oo))) == 1 assert mysimp(integrate(x*dist, (x, 0, oo))) == mu assert mysimp(integrate((x - mu)**2*dist, (x, 0, oo))) == mu**3/lamda assert mysimp(integrate((x - mu)**3*dist, (x, 0, oo))) == 3*mu**5/lamda**2 # Levi c = Symbol('c', positive=True) assert integrate(sqrt(c/2/pi)*exp(-c/2/(x - mu))/(x - mu)**S('3/2'), (x, mu, oo)) == 1 # higher moments oo # log-logistic alpha, beta = symbols('alpha beta', positive=True) distn = (beta/alpha)*x**(beta - 1)/alpha**(beta - 1)/ \ (1 + x**beta/alpha**beta)**2 # FIXME: If alpha, beta are not declared as finite the line below hangs # after the changes in: # https://github.com/sympy/sympy/pull/16603 assert simplify(integrate(distn, (x, 0, oo))) == 1 # NOTE the conditions are a mess, but correctly state beta > 1 assert simplify(integrate(x*distn, (x, 0, oo), conds='none')) == \ pi*alpha/beta/sin(pi/beta) # (similar comment for conditions applies) assert simplify(integrate(x**y*distn, (x, 0, oo), conds='none')) == \ pi*alpha**y*y/beta/sin(pi*y/beta) # weibull k = Symbol('k', positive=True) n = Symbol('n', positive=True) distn = k/lamda*(x/lamda)**(k - 1)*exp(-(x/lamda)**k) assert simplify(integrate(distn, (x, 0, oo))) == 1 assert simplify(integrate(x**n*distn, (x, 0, oo))) == \ lamda**n*gamma(1 + n/k) # rice distribution from sympy import besseli nu, sigma = symbols('nu sigma', positive=True) rice = x/sigma**2*exp(-(x**2 + nu**2)/2/sigma**2)*besseli(0, x*nu/sigma**2) assert integrate(rice, (x, 0, oo), meijerg=True) == 1 # can someone verify higher moments? # Laplace distribution mu = Symbol('mu', real=True) b = Symbol('b', positive=True) laplace = exp(-abs(x - mu)/b)/2/b assert integrate(laplace, (x, -oo, oo), meijerg=True) == 1 assert integrate(x*laplace, (x, -oo, oo), meijerg=True) == mu assert integrate(x**2*laplace, (x, -oo, oo), meijerg=True) == \ 2*b**2 + mu**2 # TODO are there other distributions supported on (-oo, oo) that we can do? # misc tests k = Symbol('k', positive=True) assert gammasimp(expand_mul(integrate(log(x)*x**(k - 1)*exp(-x)/gamma(k), (x, 0, oo)))) == polygamma(0, k) @slow def test_expint(): """ Test various exponential integrals. """ from sympy import (expint, unpolarify, Symbol, Ci, Si, Shi, Chi, sin, cos, sinh, cosh, Ei) assert simplify(unpolarify(integrate(exp(-z*x)/x**y, (x, 1, oo), meijerg=True, conds='none' ).rewrite(expint).expand(func=True))) == expint(y, z) assert integrate(exp(-z*x)/x, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ expint(1, z) assert integrate(exp(-z*x)/x**2, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ expint(2, z).rewrite(Ei).rewrite(expint) assert integrate(exp(-z*x)/x**3, (x, 1, oo), meijerg=True, conds='none').rewrite(expint).expand() == \ expint(3, z).rewrite(Ei).rewrite(expint).expand() t = Symbol('t', positive=True) assert integrate(-cos(x)/x, (x, t, oo), meijerg=True).expand() == Ci(t) assert integrate(-sin(x)/x, (x, t, oo), meijerg=True).expand() == \ Si(t) - pi/2 assert integrate(sin(x)/x, (x, 0, z), meijerg=True) == Si(z) assert integrate(sinh(x)/x, (x, 0, z), meijerg=True) == Shi(z) assert integrate(exp(-x)/x, x, meijerg=True).expand().rewrite(expint) == \ I*pi - expint(1, x) assert integrate(exp(-x)/x**2, x, meijerg=True).rewrite(expint).expand() \ == expint(1, x) - exp(-x)/x - I*pi u = Symbol('u', polar=True) assert integrate(cos(u)/u, u, meijerg=True).expand().as_independent(u)[1] \ == Ci(u) assert integrate(cosh(u)/u, u, meijerg=True).expand().as_independent(u)[1] \ == Chi(u) assert integrate(expint(1, x), x, meijerg=True ).rewrite(expint).expand() == x*expint(1, x) - exp(-x) assert integrate(expint(2, x), x, meijerg=True ).rewrite(expint).expand() == \ -x**2*expint(1, x)/2 + x*exp(-x)/2 - exp(-x)/2 assert simplify(unpolarify(integrate(expint(y, x), x, meijerg=True).rewrite(expint).expand(func=True))) == \ -expint(y + 1, x) assert integrate(Si(x), x, meijerg=True) == x*Si(x) + cos(x) assert integrate(Ci(u), u, meijerg=True).expand() == u*Ci(u) - sin(u) assert integrate(Shi(x), x, meijerg=True) == x*Shi(x) - cosh(x) assert integrate(Chi(u), u, meijerg=True).expand() == u*Chi(u) - sinh(u) assert integrate(Si(x)*exp(-x), (x, 0, oo), meijerg=True) == pi/4 assert integrate(expint(1, x)*sin(x), (x, 0, oo), meijerg=True) == log(2)/2 def test_messy(): from sympy import (laplace_transform, Si, Shi, Chi, atan, Piecewise, acoth, E1, besselj, acosh, asin, And, re, fourier_transform, sqrt) assert laplace_transform(Si(x), x, s) == ((-atan(s) + pi/2)/s, 0, True) assert laplace_transform(Shi(x), x, s) == (acoth(s)/s, 1, s > 1) # where should the logs be simplified? assert laplace_transform(Chi(x), x, s) == \ ((log(s**(-2)) - log(1 - 1/s**2))/(2*s), 1, s > 1) # TODO maybe simplify the inequalities? assert laplace_transform(besselj(a, x), x, s)[1:] == \ (0, And(re(a/2) + S.Half > S.Zero, re(a/2) + 1 > S.Zero)) # NOTE s < 0 can be done, but argument reduction is not good enough yet assert fourier_transform(besselj(1, x)/x, x, s, noconds=False) == \ (Piecewise((0, 4*abs(pi**2*s**2) > 1), (2*sqrt(-4*pi**2*s**2 + 1), True)), s > 0) # TODO FT(besselj(0,x)) - conditions are messy (but for acceptable reasons) # - folding could be better assert integrate(E1(x)*besselj(0, x), (x, 0, oo), meijerg=True) == \ log(1 + sqrt(2)) assert integrate(E1(x)*besselj(1, x), (x, 0, oo), meijerg=True) == \ log(S.Half + sqrt(2)/2) assert integrate(1/x/sqrt(1 - x**2), x, meijerg=True) == \ Piecewise((-acosh(1/x), abs(x**(-2)) > 1), (I*asin(1/x), True)) def test_issue_6122(): assert integrate(exp(-I*x**2), (x, -oo, oo), meijerg=True) == \ -I*sqrt(pi)*exp(I*pi/4) def test_issue_6252(): expr = 1/x/(a + b*x)**Rational(1, 3) anti = integrate(expr, x, meijerg=True) assert not anti.has(hyper) # XXX the expression is a mess, but actually upon differentiation and # putting in numerical values seems to work... def test_issue_6348(): assert integrate(exp(I*x)/(1 + x**2), (x, -oo, oo)).simplify().rewrite(exp) \ == pi*exp(-1) def test_fresnel(): from sympy import fresnels, fresnelc assert expand_func(integrate(sin(pi*x**2/2), x)) == fresnels(x) assert expand_func(integrate(cos(pi*x**2/2), x)) == fresnelc(x) def test_issue_6860(): assert meijerint_indefinite(x**x**x, x) is None def test_issue_7337(): f = meijerint_indefinite(x*sqrt(2*x + 3), x).together() assert f == sqrt(2*x + 3)*(2*x**2 + x - 3)/5 assert f._eval_interval(x, S.NegativeOne, S.One) == Rational(2, 5) def test_issue_8368(): assert meijerint_indefinite(cosh(x)*exp(-x*t), x) == ( (-t - 1)*exp(x) + (-t + 1)*exp(-x))*exp(-t*x)/2/(t**2 - 1) def test_issue_10211(): from sympy.abc import h, w assert integrate((1/sqrt((y-x)**2 + h**2)**3), (x,0,w), (y,0,w)) == \ 2*sqrt(1 + w**2/h**2)/h - 2/h def test_issue_11806(): from sympy import symbols y, L = symbols('y L', positive=True) assert integrate(1/sqrt(x**2 + y**2)**3, (x, -L, L)) == \ 2*L/(y**2*sqrt(L**2 + y**2)) def test_issue_10681(): from sympy import RR from sympy.abc import R, r f = integrate(r**2*(R**2-r**2)**0.5, r, meijerg=True) g = (1.0/3)*R**1.0*r**3*hyper((-0.5, Rational(3, 2)), (Rational(5, 2),), r**2*exp_polar(2*I*pi)/R**2) assert RR.almosteq((f/g).n(), 1.0, 1e-12) def test_issue_13536(): from sympy import Symbol a = Symbol('a', real=True, positive=True) assert integrate(1/x**2, (x, oo, a)) == -1/a def test_issue_6462(): from sympy import Symbol x = Symbol('x') n = Symbol('n') # Not the actual issue, still wrong answer for n = 1, but that there is no # exception assert integrate(cos(x**n)/x**n, x, meijerg=True).subs(n, 2).equals( integrate(cos(x**2)/x**2, x, meijerg=True)) sympy-sympy-1.9/sympy/integrals/tests/test_prde.py000066400000000000000000000373651412543434000226170ustar00rootroot00000000000000"""Most of these tests come from the examples in Bronstein's book.""" from sympy.integrals.risch import DifferentialExtension, derivation from sympy.integrals.prde import (prde_normal_denom, prde_special_denom, prde_linear_constraints, constant_system, prde_spde, prde_no_cancel_b_large, prde_no_cancel_b_small, limited_integrate_reduce, limited_integrate, is_deriv_k, is_log_deriv_k_t_radical, parametric_log_deriv_heu, is_log_deriv_k_t_radical_in_field, param_poly_rischDE, param_rischDE, prde_cancel_liouvillian) from sympy.polys.polymatrix import PolyMatrix as Matrix from sympy import Poly, S, symbols, Rational, QQ from sympy.abc import x, t, n t0, t1, t2, t3, k = symbols('t:4 k') def test_prde_normal_denom(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) fa = Poly(1, t) fd = Poly(x, t) G = [(Poly(t, t), Poly(1 + t**2, t)), (Poly(1, t), Poly(x + x*t**2, t))] assert prde_normal_denom(fa, fd, G, DE) == \ (Poly(x, t, domain='ZZ(x)'), (Poly(1, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), [(Poly(x*t, t, domain='ZZ(x)'), Poly(t**2 + 1, t, domain='ZZ(x)')), (Poly(1, t, domain='ZZ(x)'), Poly(t**2 + 1, t, domain='ZZ(x)'))], Poly(1, t, domain='ZZ(x)')) G = [(Poly(t, t), Poly(t**2 + 2*t + 1, t)), (Poly(x*t, t), Poly(t**2 + 2*t + 1, t)), (Poly(x*t**2, t), Poly(t**2 + 2*t + 1, t))] DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert prde_normal_denom(Poly(x, t), Poly(1, t), G, DE) == \ (Poly(t + 1, t), (Poly((-1 + x)*t + x, t), Poly(1, t, domain='ZZ[x]')), [(Poly(t, t), Poly(1, t)), (Poly(x*t, t), Poly(1, t, domain='ZZ[x]')), (Poly(x*t**2, t), Poly(1, t, domain='ZZ[x]'))], Poly(t + 1, t)) def test_prde_special_denom(): a = Poly(t + 1, t) ba = Poly(t**2, t) bd = Poly(1, t) G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))] DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert prde_special_denom(a, ba, bd, G, DE) == \ (Poly(t + 1, t), Poly(t**2, t), [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))], Poly(1, t)) G = [(Poly(t, t), Poly(1, t)), (Poly(1, t), Poly(t, t))] assert prde_special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), G, DE) == \ (Poly(1, t), Poly(t**2 - 1, t), [(Poly(t**2, t), Poly(1, t)), (Poly(1, t), Poly(1, t))], Poly(t, t)) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0)]}) DE.decrement_level() G = [(Poly(t, t), Poly(t**2, t)), (Poly(2*t, t), Poly(t, t))] assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3 + 2, t), G, DE) == \ (Poly(5*x*t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t, t), Poly(t**2, t)), (Poly(2*t, t), Poly(t, t))], Poly(1, x)) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly((t**2 + 1)*2*x, t)]}) G = [(Poly(t + x, t), Poly(t*x, t)), (Poly(2*t, t), Poly(x**2, x))] assert prde_special_denom(Poly(5*x*t + 1, t), Poly(t**2 + 2*x**3*t, t), Poly(t**3, t), G, DE) == \ (Poly(5*x*t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t + x, t), Poly(x*t, t)), (Poly(2*t, t, x), Poly(x**2, t, x))], Poly(1, t)) assert prde_special_denom(Poly(t + 1, t), Poly(t**2, t), Poly(t**3, t), G, DE) == \ (Poly(t + 1, t), Poly(0, t, domain='ZZ[x]'), [(Poly(t + x, t), Poly(x*t, t)), (Poly(2*t, t, x), Poly(x**2, t, x))], Poly(1, t)) def test_prde_linear_constraints(): DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) G = [(Poly(2*x**3 + 3*x + 1, x), Poly(x**2 - 1, x)), (Poly(1, x), Poly(x - 1, x)), (Poly(1, x), Poly(x + 1, x))] assert prde_linear_constraints(Poly(1, x), Poly(0, x), G, DE) == \ ((Poly(2*x, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(0, x, domain='QQ')), Matrix([[1, 1, -1], [5, 1, 1]], x)) G = [(Poly(t, t), Poly(1, t)), (Poly(t**2, t), Poly(1, t)), (Poly(t**3, t), Poly(1, t))] DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert prde_linear_constraints(Poly(t + 1, t), Poly(t**2, t), G, DE) == \ ((Poly(t, t, domain='QQ'), Poly(t**2, t, domain='QQ'), Poly(t**3, t, domain='QQ')), Matrix(0, 3, [], t)) G = [(Poly(2*x, t), Poly(t, t)), (Poly(-x, t), Poly(t, t))] DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) assert prde_linear_constraints(Poly(1, t), Poly(0, t), G, DE) == \ ((Poly(0, t, domain='QQ[x]'), Poly(0, t, domain='QQ[x]')), Matrix([[2*x, -x]], t)) def test_constant_system(): A = Matrix([[-(x + 3)/(x - 1), (x + 1)/(x - 1), 1], [-x - 3, x + 1, x - 1], [2*(x + 3)/(x - 1), 0, 0]], t) u = Matrix([[(x + 1)/(x - 1)], [x + 1], [0]], t) DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) R = QQ.frac_field(x)[t] assert constant_system(A, u, DE) == \ (Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 0], [0, 0, 1]], ring=R), Matrix([0, 1, 0, 0], ring=R)) def test_prde_spde(): D = [Poly(x, t), Poly(-x*t, t)] DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) # TODO: when bound_degree() can handle this, test degree bound from that too assert prde_spde(Poly(t, t), Poly(-1/x, t), D, n, DE) == \ (Poly(t, t), Poly(0, t, domain='ZZ(x)'), [Poly(2*x, t, domain='ZZ(x)'), Poly(-x, t, domain='ZZ(x)')], [Poly(-x**2, t, domain='ZZ(x)'), Poly(0, t, domain='ZZ(x)')], n - 1) def test_prde_no_cancel(): # b large DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**2, x), Poly(1, x)], 2, DE) == \ ([Poly(x**2 - 2*x + 2, x), Poly(1, x)], Matrix([[1, 0, -1, 0], [0, 1, 0, -1]], x)) assert prde_no_cancel_b_large(Poly(1, x), [Poly(x**3, x), Poly(1, x)], 3, DE) == \ ([Poly(x**3 - 3*x**2 + 6*x - 6, x), Poly(1, x)], Matrix([[1, 0, -1, 0], [0, 1, 0, -1]], x)) assert prde_no_cancel_b_large(Poly(x, x), [Poly(x**2, x), Poly(1, x)], 1, DE) == \ ([Poly(x, x, domain='ZZ'), Poly(0, x, domain='ZZ')], Matrix([[1, -1, 0, 0], [1, 0, -1, 0], [0, 1, 0, -1]], x)) # b small # XXX: Is there a better example of a monomial with D.degree() > 2? DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**3 + 1, t)]}) # My original q was t**4 + t + 1, but this solution implies q == t**4 # (c1 = 4), with some of the ci for the original q equal to 0. G = [Poly(t**6, t), Poly(x*t**5, t), Poly(t**3, t), Poly(x*t**2, t), Poly(1 + x, t)] R = QQ.frac_field(x)[t] assert prde_no_cancel_b_small(Poly(x*t, t), G, 4, DE) == \ ([Poly(t**4/4 - x/12*t**3 + x**2/24*t**2 + (Rational(-11, 12) - x**3/24)*t + x/24, t), Poly(x/3*t**3 - x**2/6*t**2 + (Rational(-1, 3) + x**3/6)*t - x/6, t), Poly(t, t), Poly(0, t), Poly(0, t)], Matrix([[1, 0, -1, 0, 0, 0, 0, 0, 0, 0], [0, 1, Rational(-1, 4), 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, 1, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, -1, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, -1, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, -1, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0, -1, 0], [0, 0, 0, 0, 1, 0, 0, 0, 0, -1]], ring=R)) # TODO: Add test for deg(b) <= 0 with b small DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) b = Poly(-1/x**2, t, field=True) # deg(b) == 0 q = [Poly(x**i*t**j, t, field=True) for i in range(2) for j in range(3)] h, A = prde_no_cancel_b_small(b, q, 3, DE) V = A.nullspace() R = QQ.frac_field(x)[t] assert len(V) == 1 assert V[0] == Matrix([Rational(-1, 2), 0, 0, 1, 0, 0]*3, ring=R) assert (Matrix([h])*V[0][6:, :])[0] == Poly(x**2/2, t, domain='QQ(x)') assert (Matrix([q])*V[0][:6, :])[0] == Poly(x - S.Half, t, domain='QQ(x)') def test_prde_cancel_liouvillian(): ### 1. case == 'primitive' # used when integrating f = log(x) - log(x - 1) # Not taken from 'the' book DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) p0 = Poly(0, t, field=True) h, A = prde_cancel_liouvillian(Poly(-1/(x - 1), t), [Poly(-x + 1, t), Poly(1, t)], 1, DE) V = A.nullspace() h == [p0, p0, Poly((x - 1)*t, t), p0, p0, p0, p0, p0, p0, p0, Poly(x - 1, t), Poly(-x**2 + x, t), p0, p0, p0, p0] assert A.rank() == 16 assert (Matrix([h])*V[0][:16, :]) == Matrix([[Poly(0, t, domain='QQ(x)')]]) ### 2. case == 'exp' # used when integrating log(x/exp(x) + 1) # Not taken from book DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t, t)]}) assert prde_cancel_liouvillian(Poly(0, t, domain='QQ[x]'), [Poly(1, t, domain='QQ(x)')], 0, DE) == \ ([Poly(1, t, domain='QQ'), Poly(x, t, domain='ZZ(x)')], Matrix([[-1, 0, 1]], DE.t)) def test_param_poly_rischDE(): DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) a = Poly(x**2 - x, x, field=True) b = Poly(1, x, field=True) q = [Poly(x, x, field=True), Poly(x**2, x, field=True)] h, A = param_poly_rischDE(a, b, q, 3, DE) assert A.nullspace() == [Matrix([0, 1, 1, 1], DE.t)] # c1, c2, d1, d2 # Solution of a*Dp + b*p = c1*q1 + c2*q2 = q2 = x**2 # is d1*h1 + d2*h2 = h1 + h2 = x. assert h[0] + h[1] == Poly(x, x, domain='QQ') # a*Dp + b*p = q1 = x has no solution. a = Poly(x**2 - x, x, field=True) b = Poly(x**2 - 5*x + 3, x, field=True) q = [Poly(1, x, field=True), Poly(x, x, field=True), Poly(x**2, x, field=True)] h, A = param_poly_rischDE(a, b, q, 3, DE) assert A.nullspace() == [Matrix([3, -5, 1, -5, 1, 1], DE.t)] p = -Poly(5, DE.t)*h[0] + h[1] + h[2] # Poly(1, x) assert a*derivation(p, DE) + b*p == Poly(x**2 - 5*x + 3, x, domain='QQ') def test_param_rischDE(): DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) p1, px = Poly(1, x, field=True), Poly(x, x, field=True) G = [(p1, px), (p1, p1), (px, p1)] # [1/x, 1, x] h, A = param_rischDE(-p1, Poly(x**2, x, field=True), G, DE) assert len(h) == 3 p = [hi[0].as_expr()/hi[1].as_expr() for hi in h] V = A.nullspace() assert len(V) == 2 assert V[0] == Matrix([-1, 1, 0, -1, 1, 0], DE.t) y = -p[0] + p[1] + 0*p[2] # x assert y.diff(x) - y/x**2 == 1 - 1/x # Dy + f*y == -G0 + G1 + 0*G2 # the below test computation takes place while computing the integral # of 'f = log(log(x + exp(x)))' DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) G = [(Poly(t + x, t, domain='ZZ(x)'), Poly(1, t, domain='QQ')), (Poly(0, t, domain='QQ'), Poly(1, t, domain='QQ'))] h, A = param_rischDE(Poly(-t - 1, t, field=True), Poly(t + x, t, field=True), G, DE) assert len(h) == 5 p = [hi[0].as_expr()/hi[1].as_expr() for hi in h] V = A.nullspace() assert len(V) == 3 assert V[0] == Matrix([0, 0, 0, 0, 1, 0, 0], DE.t) y = 0*p[0] + 0*p[1] + 1*p[2] + 0*p[3] + 0*p[4] assert y.diff(t) - y/(t + x) == 0 # Dy + f*y = 0*G0 + 0*G1 def test_limited_integrate_reduce(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) assert limited_integrate_reduce(Poly(x, t), Poly(t**2, t), [(Poly(x, t), Poly(t, t))], DE) == \ (Poly(t, t), Poly(-1/x, t), Poly(t, t), 1, (Poly(x, t), Poly(1, t, domain='ZZ[x]')), [(Poly(-x*t, t), Poly(1, t, domain='ZZ[x]'))]) def test_limited_integrate(): DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) G = [(Poly(x, x), Poly(x + 1, x))] assert limited_integrate(Poly(-(1 + x + 5*x**2 - 3*x**3), x), Poly(1 - x - x**2 + x**3, x), G, DE) == \ ((Poly(x**2 - x + 2, x), Poly(x - 1, x, domain='QQ')), [2]) G = [(Poly(1, x), Poly(x, x))] assert limited_integrate(Poly(5*x**2, x), Poly(3, x), G, DE) == \ ((Poly(5*x**3/9, x), Poly(1, x, domain='QQ')), [0]) def test_is_log_deriv_k_t_radical(): DE = DifferentialExtension(extension={'D': [Poly(1, x)], 'exts': [None], 'extargs': [None]}) assert is_log_deriv_k_t_radical(Poly(2*x, x), Poly(1, x), DE) is None DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*t1, t1), Poly(1/x, t2)], 'exts': [None, 'exp', 'log'], 'extargs': [None, 2*x, x]}) assert is_log_deriv_k_t_radical(Poly(x + t2/2, t2), Poly(1, t2), DE) == \ ([(t1, 1), (x, 1)], t1*x, 2, 0) # TODO: Add more tests DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(1/x, t)], 'exts': [None, 'exp', 'log'], 'extargs': [None, x, x]}) assert is_log_deriv_k_t_radical(Poly(x + t/2 + 3, t), Poly(1, t), DE) == \ ([(t0, 2), (x, 1)], x*t0**2, 2, 3) def test_is_deriv_k(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)], 'exts': [None, 'log', 'log'], 'extargs': [None, x, x + 1]}) assert is_deriv_k(Poly(2*x**2 + 2*x, t2), Poly(1, t2), DE) == \ ([(t1, 1), (t2, 1)], t1 + t2, 2) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t2, t2)], 'exts': [None, 'log', 'exp'], 'extargs': [None, x, x]}) assert is_deriv_k(Poly(x**2*t2**3, t2), Poly(1, t2), DE) == \ ([(x, 3), (t1, 2)], 2*t1 + 3*x, 1) # TODO: Add more tests, including ones with exponentials DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/x, t1)], 'exts': [None, 'log'], 'extargs': [None, x**2]}) assert is_deriv_k(Poly(x, t1), Poly(1, t1), DE) == \ ([(t1, S.Half)], t1/2, 1) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2/(1 + x), t0)], 'exts': [None, 'log'], 'extargs': [None, x**2 + 2*x + 1]}) assert is_deriv_k(Poly(1 + x, t0), Poly(1, t0), DE) == \ ([(t0, S.Half)], t0/2, 1) # Issue 10798 # DE = DifferentialExtension(log(1/x), x) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-1/x, t)], 'exts': [None, 'log'], 'extargs': [None, 1/x]}) assert is_deriv_k(Poly(1, t), Poly(x, t), DE) == ([(t, 1)], t, 1) def test_is_log_deriv_k_t_radical_in_field(): # NOTE: any potential constant factor in the second element of the result # doesn't matter, because it cancels in Da/a. DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) assert is_log_deriv_k_t_radical_in_field(Poly(5*t + 1, t), Poly(2*t*x, t), DE) == \ (2, t*x**5) assert is_log_deriv_k_t_radical_in_field(Poly(2 + 3*t, t), Poly(5*x*t, t), DE) == \ (5, x**3*t**2) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t/x**2, t)]}) assert is_log_deriv_k_t_radical_in_field(Poly(-(1 + 2*t), t), Poly(2*x**2 + 2*x**2*t, t), DE) == \ (2, t + t**2) assert is_log_deriv_k_t_radical_in_field(Poly(-1, t), Poly(x**2, t), DE) == \ (1, t) assert is_log_deriv_k_t_radical_in_field(Poly(1, t), Poly(2*x**2, t), DE) == \ (2, 1/t) def test_parametric_log_deriv(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) assert parametric_log_deriv_heu(Poly(5*t**2 + t - 6, t), Poly(2*x*t**2, t), Poly(-1, t), Poly(x*t**2, t), DE) == \ (2, 6, t*x**5) sympy-sympy-1.9/sympy/integrals/tests/test_quadrature.py000066400000000000000000000467171412543434000240430ustar00rootroot00000000000000from sympy.core import S, Rational from sympy.integrals.quadrature import (gauss_legendre, gauss_laguerre, gauss_hermite, gauss_gen_laguerre, gauss_chebyshev_t, gauss_chebyshev_u, gauss_jacobi, gauss_lobatto) def test_legendre(): x, w = gauss_legendre(1, 17) assert [str(r) for r in x] == ['0'] assert [str(r) for r in w] == ['2.0000000000000000'] x, w = gauss_legendre(2, 17) assert [str(r) for r in x] == [ '-0.57735026918962576', '0.57735026918962576'] assert [str(r) for r in w] == [ '1.0000000000000000', '1.0000000000000000'] x, w = gauss_legendre(3, 17) assert [str(r) for r in x] == [ '-0.77459666924148338', '0', '0.77459666924148338'] assert [str(r) for r in w] == [ '0.55555555555555556', '0.88888888888888889', '0.55555555555555556'] x, w = gauss_legendre(4, 17) assert [str(r) for r in x] == [ '-0.86113631159405258', '-0.33998104358485626', '0.33998104358485626', '0.86113631159405258'] assert [str(r) for r in w] == [ '0.34785484513745386', '0.65214515486254614', '0.65214515486254614', '0.34785484513745386'] def test_legendre_precise(): x, w = gauss_legendre(3, 40) assert [str(r) for r in x] == [ '-0.7745966692414833770358530799564799221666', '0', '0.7745966692414833770358530799564799221666'] assert [str(r) for r in w] == [ '0.5555555555555555555555555555555555555556', '0.8888888888888888888888888888888888888889', '0.5555555555555555555555555555555555555556'] def test_laguerre(): x, w = gauss_laguerre(1, 17) assert [str(r) for r in x] == ['1.0000000000000000'] assert [str(r) for r in w] == ['1.0000000000000000'] x, w = gauss_laguerre(2, 17) assert [str(r) for r in x] == [ '0.58578643762690495', '3.4142135623730950'] assert [str(r) for r in w] == [ '0.85355339059327376', '0.14644660940672624'] x, w = gauss_laguerre(3, 17) assert [str(r) for r in x] == [ '0.41577455678347908', '2.2942803602790417', '6.2899450829374792', ] assert [str(r) for r in w] == [ '0.71109300992917302', '0.27851773356924085', '0.010389256501586136', ] x, w = gauss_laguerre(4, 17) assert [str(r) for r in x] == [ '0.32254768961939231', '1.7457611011583466', '4.5366202969211280', '9.3950709123011331'] assert [str(r) for r in w] == [ '0.60315410434163360', '0.35741869243779969', '0.038887908515005384', '0.00053929470556132745'] x, w = gauss_laguerre(5, 17) assert [str(r) for r in x] == [ '0.26356031971814091', '1.4134030591065168', '3.5964257710407221', '7.0858100058588376', '12.640800844275783'] assert [str(r) for r in w] == [ '0.52175561058280865', '0.39866681108317593', '0.075942449681707595', '0.0036117586799220485', '2.3369972385776228e-5'] def test_laguerre_precise(): x, w = gauss_laguerre(3, 40) assert [str(r) for r in x] == [ '0.4157745567834790833115338731282744735466', '2.294280360279041719822050361359593868960', '6.289945082937479196866415765512131657493'] assert [str(r) for r in w] == [ '0.7110930099291730154495901911425944313094', '0.2785177335692408488014448884567264810349', '0.01038925650158613574896492040067908765572'] def test_hermite(): x, w = gauss_hermite(1, 17) assert [str(r) for r in x] == ['0'] assert [str(r) for r in w] == ['1.7724538509055160'] x, w = gauss_hermite(2, 17) assert [str(r) for r in x] == [ '-0.70710678118654752', '0.70710678118654752'] assert [str(r) for r in w] == [ '0.88622692545275801', '0.88622692545275801'] x, w = gauss_hermite(3, 17) assert [str(r) for r in x] == [ '-1.2247448713915890', '0', '1.2247448713915890'] assert [str(r) for r in w] == [ '0.29540897515091934', '1.1816359006036774', '0.29540897515091934'] x, w = gauss_hermite(4, 17) assert [str(r) for r in x] == [ '-1.6506801238857846', '-0.52464762327529032', '0.52464762327529032', '1.6506801238857846'] assert [str(r) for r in w] == [ '0.081312835447245177', '0.80491409000551284', '0.80491409000551284', '0.081312835447245177'] x, w = gauss_hermite(5, 17) assert [str(r) for r in x] == [ '-2.0201828704560856', '-0.95857246461381851', '0', '0.95857246461381851', '2.0201828704560856'] assert [str(r) for r in w] == [ '0.019953242059045913', '0.39361932315224116', '0.94530872048294188', '0.39361932315224116', '0.019953242059045913'] def test_hermite_precise(): x, w = gauss_hermite(3, 40) assert [str(r) for r in x] == [ '-1.224744871391589049098642037352945695983', '0', '1.224744871391589049098642037352945695983'] assert [str(r) for r in w] == [ '0.2954089751509193378830279138901908637996', '1.181635900603677351532111655560763455198', '0.2954089751509193378830279138901908637996'] def test_gen_laguerre(): x, w = gauss_gen_laguerre(1, Rational(-1, 2), 17) assert [str(r) for r in x] == ['0.50000000000000000'] assert [str(r) for r in w] == ['1.7724538509055160'] x, w = gauss_gen_laguerre(2, Rational(-1, 2), 17) assert [str(r) for r in x] == [ '0.27525512860841095', '2.7247448713915890'] assert [str(r) for r in w] == [ '1.6098281800110257', '0.16262567089449035'] x, w = gauss_gen_laguerre(3, Rational(-1, 2), 17) assert [str(r) for r in x] == [ '0.19016350919348813', '1.7844927485432516', '5.5253437422632603'] assert [str(r) for r in w] == [ '1.4492591904487850', '0.31413464064571329', '0.0090600198110176913'] x, w = gauss_gen_laguerre(4, Rational(-1, 2), 17) assert [str(r) for r in x] == [ '0.14530352150331709', '1.3390972881263614', '3.9269635013582872', '8.5886356890120343'] assert [str(r) for r in w] == [ '1.3222940251164826', '0.41560465162978376', '0.034155966014826951', '0.00039920814442273524'] x, w = gauss_gen_laguerre(5, Rational(-1, 2), 17) assert [str(r) for r in x] == [ '0.11758132021177814', '1.0745620124369040', '3.0859374437175500', '6.4147297336620305', '11.807189489971737'] assert [str(r) for r in w] == [ '1.2217252674706516', '0.48027722216462937', '0.067748788910962126', '0.0026872914935624654', '1.5280865710465241e-5'] x, w = gauss_gen_laguerre(1, 2, 17) assert [str(r) for r in x] == ['3.0000000000000000'] assert [str(r) for r in w] == ['2.0000000000000000'] x, w = gauss_gen_laguerre(2, 2, 17) assert [str(r) for r in x] == [ '2.0000000000000000', '6.0000000000000000'] assert [str(r) for r in w] == [ '1.5000000000000000', '0.50000000000000000'] x, w = gauss_gen_laguerre(3, 2, 17) assert [str(r) for r in x] == [ '1.5173870806774125', '4.3115831337195203', '9.1710297856030672'] assert [str(r) for r in w] == [ '1.0374949614904253', '0.90575000470306537', '0.056755033806509347'] x, w = gauss_gen_laguerre(4, 2, 17) assert [str(r) for r in x] == [ '1.2267632635003021', '3.4125073586969460', '6.9026926058516134', '12.458036771951139'] assert [str(r) for r in w] == [ '0.72552499769865438', '1.0634242919791946', '0.20669613102835355', '0.0043545792937974889'] x, w = gauss_gen_laguerre(5, 2, 17) assert [str(r) for r in x] == [ '1.0311091440933816', '2.8372128239538217', '5.6202942725987079', '9.6829098376640271', '15.828473921690062'] assert [str(r) for r in w] == [ '0.52091739683509184', '1.0667059331592211', '0.38354972366693113', '0.028564233532974658', '0.00026271280578124935'] def test_gen_laguerre_precise(): x, w = gauss_gen_laguerre(3, Rational(-1, 2), 40) assert [str(r) for r in x] == [ '0.1901635091934881328718554276203028970878', '1.784492748543251591186722461957367638500', '5.525343742263260275941422110422329464413'] assert [str(r) for r in w] == [ '1.449259190448785048183829411195134343108', '0.3141346406457132878326231270167565378246', '0.009060019811017691281714945129254301865020'] x, w = gauss_gen_laguerre(3, 2, 40) assert [str(r) for r in x] == [ '1.517387080677412495020323111016672547482', '4.311583133719520302881184669723530562299', '9.171029785603067202098492219259796890218'] assert [str(r) for r in w] == [ '1.037494961490425285817554606541269153041', '0.9057500047030653669269785048806009945254', '0.05675503380650934725546688857812985243312'] def test_chebyshev_t(): x, w = gauss_chebyshev_t(1, 17) assert [str(r) for r in x] == ['0'] assert [str(r) for r in w] == ['3.1415926535897932'] x, w = gauss_chebyshev_t(2, 17) assert [str(r) for r in x] == [ '0.70710678118654752', '-0.70710678118654752'] assert [str(r) for r in w] == [ '1.5707963267948966', '1.5707963267948966'] x, w = gauss_chebyshev_t(3, 17) assert [str(r) for r in x] == [ '0.86602540378443865', '0', '-0.86602540378443865'] assert [str(r) for r in w] == [ '1.0471975511965977', '1.0471975511965977', '1.0471975511965977'] x, w = gauss_chebyshev_t(4, 17) assert [str(r) for r in x] == [ '0.92387953251128676', '0.38268343236508977', '-0.38268343236508977', '-0.92387953251128676'] assert [str(r) for r in w] == [ '0.78539816339744831', '0.78539816339744831', '0.78539816339744831', '0.78539816339744831'] x, w = gauss_chebyshev_t(5, 17) assert [str(r) for r in x] == [ '0.95105651629515357', '0.58778525229247313', '0', '-0.58778525229247313', '-0.95105651629515357'] assert [str(r) for r in w] == [ '0.62831853071795865', '0.62831853071795865', '0.62831853071795865', '0.62831853071795865', '0.62831853071795865'] def test_chebyshev_t_precise(): x, w = gauss_chebyshev_t(3, 40) assert [str(r) for r in x] == [ '0.8660254037844386467637231707529361834714', '0', '-0.8660254037844386467637231707529361834714'] assert [str(r) for r in w] == [ '1.047197551196597746154214461093167628066', '1.047197551196597746154214461093167628066', '1.047197551196597746154214461093167628066'] def test_chebyshev_u(): x, w = gauss_chebyshev_u(1, 17) assert [str(r) for r in x] == ['0'] assert [str(r) for r in w] == ['1.5707963267948966'] x, w = gauss_chebyshev_u(2, 17) assert [str(r) for r in x] == [ '0.50000000000000000', '-0.50000000000000000'] assert [str(r) for r in w] == [ '0.78539816339744831', '0.78539816339744831'] x, w = gauss_chebyshev_u(3, 17) assert [str(r) for r in x] == [ '0.70710678118654752', '0', '-0.70710678118654752'] assert [str(r) for r in w] == [ '0.39269908169872415', '0.78539816339744831', '0.39269908169872415'] x, w = gauss_chebyshev_u(4, 17) assert [str(r) for r in x] == [ '0.80901699437494742', '0.30901699437494742', '-0.30901699437494742', '-0.80901699437494742'] assert [str(r) for r in w] == [ '0.21707871342270599', '0.56831944997474231', '0.56831944997474231', '0.21707871342270599'] x, w = gauss_chebyshev_u(5, 17) assert [str(r) for r in x] == [ '0.86602540378443865', '0.50000000000000000', '0', '-0.50000000000000000', '-0.86602540378443865'] assert [str(r) for r in w] == [ '0.13089969389957472', '0.39269908169872415', '0.52359877559829887', '0.39269908169872415', '0.13089969389957472'] def test_chebyshev_u_precise(): x, w = gauss_chebyshev_u(3, 40) assert [str(r) for r in x] == [ '0.7071067811865475244008443621048490392848', '0', '-0.7071067811865475244008443621048490392848'] assert [str(r) for r in w] == [ '0.3926990816987241548078304229099378605246', '0.7853981633974483096156608458198757210493', '0.3926990816987241548078304229099378605246'] def test_jacobi(): x, w = gauss_jacobi(1, Rational(-1, 2), S.Half, 17) assert [str(r) for r in x] == ['0.50000000000000000'] assert [str(r) for r in w] == ['3.1415926535897932'] x, w = gauss_jacobi(2, Rational(-1, 2), S.Half, 17) assert [str(r) for r in x] == [ '-0.30901699437494742', '0.80901699437494742'] assert [str(r) for r in w] == [ '0.86831485369082398', '2.2732777998989693'] x, w = gauss_jacobi(3, Rational(-1, 2), S.Half, 17) assert [str(r) for r in x] == [ '-0.62348980185873353', '0.22252093395631440', '0.90096886790241913'] assert [str(r) for r in w] == [ '0.33795476356635433', '1.0973322242791115', '1.7063056657443274'] x, w = gauss_jacobi(4, Rational(-1, 2), S.Half, 17) assert [str(r) for r in x] == [ '-0.76604444311897804', '-0.17364817766693035', '0.50000000000000000', '0.93969262078590838'] assert [str(r) for r in w] == [ '0.16333179083642836', '0.57690240318269103', '1.0471975511965977', '1.3541609083740761'] x, w = gauss_jacobi(5, Rational(-1, 2), S.Half, 17) assert [str(r) for r in x] == [ '-0.84125353283118117', '-0.41541501300188643', '0.14231483827328514', '0.65486073394528506', '0.95949297361449739'] assert [str(r) for r in w] == [ '0.090675770007435372', '0.33391416373675607', '0.65248870981926643', '0.94525424081394926', '1.1192597692123861'] x, w = gauss_jacobi(1, 2, 3, 17) assert [str(r) for r in x] == ['0.14285714285714286'] assert [str(r) for r in w] == ['1.0666666666666667'] x, w = gauss_jacobi(2, 2, 3, 17) assert [str(r) for r in x] == [ '-0.24025307335204215', '0.46247529557426437'] assert [str(r) for r in w] == [ '0.48514624517838660', '0.58152042148828007'] x, w = gauss_jacobi(3, 2, 3, 17) assert [str(r) for r in x] == [ '-0.46115870378089762', '0.10438533038323902', '0.62950064612493132'] assert [str(r) for r in w] == [ '0.17937613502213266', '0.61595640991147154', '0.27133412173306246'] x, w = gauss_jacobi(4, 2, 3, 17) assert [str(r) for r in x] == [ '-0.59903470850824782', '-0.14761105199952565', '0.32554377081188859', '0.72879429738819258'] assert [str(r) for r in w] == [ '0.067809641836772187', '0.38956404952032481', '0.47995970868024150', '0.12933326662932816'] x, w = gauss_jacobi(5, 2, 3, 17) assert [str(r) for r in x] == [ '-0.69045775012676106', '-0.32651993134900065', '0.082337849552034905', '0.47517887061283164', '0.79279429464422850'] assert [str(r) for r in w] == [ '0.027410178066337099', '0.21291786060364828', '0.43908437944395081', '0.32220656547221822', '0.065047683080512268'] def test_jacobi_precise(): x, w = gauss_jacobi(3, Rational(-1, 2), S.Half, 40) assert [str(r) for r in x] == [ '-0.6234898018587335305250048840042398106323', '0.2225209339563144042889025644967947594664', '0.9009688679024191262361023195074450511659'] assert [str(r) for r in w] == [ '0.3379547635663543330553835737094171534907', '1.097332224279111467485302294320899710461', '1.706305665744327437921957515249186020246'] x, w = gauss_jacobi(3, 2, 3, 40) assert [str(r) for r in x] == [ '-0.4611587037808976179121958105554375981274', '0.1043853303832390210914918407615869143233', '0.6295006461249313240934312425211234110769'] assert [str(r) for r in w] == [ '0.1793761350221326596137764371503859752628', '0.6159564099114715430909548532229749439714', '0.2713341217330624639619353762933057474325'] def test_lobatto(): x, w = gauss_lobatto(2, 17) assert [str(r) for r in x] == [ '-1', '1'] assert [str(r) for r in w] == [ '1.0000000000000000', '1.0000000000000000'] x, w = gauss_lobatto(3, 17) assert [str(r) for r in x] == [ '-1', '0', '1'] assert [str(r) for r in w] == [ '0.33333333333333333', '1.3333333333333333', '0.33333333333333333'] x, w = gauss_lobatto(4, 17) assert [str(r) for r in x] == [ '-1', '-0.44721359549995794', '0.44721359549995794', '1'] assert [str(r) for r in w] == [ '0.16666666666666667', '0.83333333333333333', '0.83333333333333333', '0.16666666666666667'] x, w = gauss_lobatto(5, 17) assert [str(r) for r in x] == [ '-1', '-0.65465367070797714', '0', '0.65465367070797714', '1'] assert [str(r) for r in w] == [ '0.10000000000000000', '0.54444444444444444', '0.71111111111111111', '0.54444444444444444', '0.10000000000000000'] def test_lobatto_precise(): x, w = gauss_lobatto(3, 40) assert [str(r) for r in x] == [ '-1', '0', '1'] assert [str(r) for r in w] == [ '0.3333333333333333333333333333333333333333', '1.333333333333333333333333333333333333333', '0.3333333333333333333333333333333333333333'] sympy-sympy-1.9/sympy/integrals/tests/test_rationaltools.py000066400000000000000000000115631412543434000245470ustar00rootroot00000000000000from sympy import (S, symbols, I, atan, log, Poly, sqrt, simplify, integrate, Rational, Dummy) from sympy.integrals.rationaltools import ratint, ratint_logpart, log_to_atan from sympy.abc import a, b, x, t half = S.Half def test_ratint(): assert ratint(S.Zero, x) == 0 assert ratint(S(7), x) == 7*x assert ratint(x, x) == x**2/2 assert ratint(2*x, x) == x**2 assert ratint(-2*x, x) == -x**2 assert ratint(8*x**7 + 2*x + 1, x) == x**8 + x**2 + x f = S.One g = x + 1 assert ratint(f / g, x) == log(x + 1) assert ratint((f, g), x) == log(x + 1) f = x**3 - x g = x - 1 assert ratint(f/g, x) == x**3/3 + x**2/2 f = x g = (x - a)*(x + a) assert ratint(f/g, x) == log(x**2 - a**2)/2 f = S.One g = x**2 + 1 assert ratint(f/g, x, real=None) == atan(x) assert ratint(f/g, x, real=True) == atan(x) assert ratint(f/g, x, real=False) == I*log(x + I)/2 - I*log(x - I)/2 f = S(36) g = x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2 assert ratint(f/g, x) == \ -4*log(x + 1) + 4*log(x - 2) + (12*x + 6)/(x**2 - 1) f = x**4 - 3*x**2 + 6 g = x**6 - 5*x**4 + 5*x**2 + 4 assert ratint(f/g, x) == \ atan(x) + atan(x**3) + atan(x/2 - Rational(3, 2)*x**3 + S.Half*x**5) f = x**7 - 24*x**4 - 4*x**2 + 8*x - 8 g = x**8 + 6*x**6 + 12*x**4 + 8*x**2 assert ratint(f/g, x) == \ (4 + 6*x + 8*x**2 + 3*x**3)/(4*x + 4*x**3 + x**5) + log(x) assert ratint((x**3*f)/(x*g), x) == \ -(12 - 16*x + 6*x**2 - 14*x**3)/(4 + 4*x**2 + x**4) - \ 5*sqrt(2)*atan(x*sqrt(2)/2) + S.Half*x**2 - 3*log(2 + x**2) f = x**5 - x**4 + 4*x**3 + x**2 - x + 5 g = x**4 - 2*x**3 + 5*x**2 - 4*x + 4 assert ratint(f/g, x) == \ x + S.Half*x**2 + S.Half*log(2 - x + x**2) + (9 - 4*x)/(7*x**2 - 7*x + 14) + \ 13*sqrt(7)*atan(Rational(-1, 7)*sqrt(7) + 2*x*sqrt(7)/7)/49 assert ratint(1/(x**2 + x + 1), x) == \ 2*sqrt(3)*atan(sqrt(3)/3 + 2*x*sqrt(3)/3)/3 assert ratint(1/(x**3 + 1), x) == \ -log(1 - x + x**2)/6 + log(1 + x)/3 + sqrt(3)*atan(-sqrt(3) /3 + 2*x*sqrt(3)/3)/3 assert ratint(1/(x**2 + x + 1), x, real=False) == \ -I*3**half*log(half + x - half*I*3**half)/3 + \ I*3**half*log(half + x + half*I*3**half)/3 assert ratint(1/(x**3 + 1), x, real=False) == log(1 + x)/3 + \ (Rational(-1, 6) + I*3**half/6)*log(-half + x + I*3**half/2) + \ (Rational(-1, 6) - I*3**half/6)*log(-half + x - I*3**half/2) # issue 4991 assert ratint(1/(x*(a + b*x)**3), x) == \ (3*a + 2*b*x)/(2*a**4 + 4*a**3*b*x + 2*a**2*b**2*x**2) + ( log(x) - log(a/b + x))/a**3 assert ratint(x/(1 - x**2), x) == -log(x**2 - 1)/2 assert ratint(-x/(1 - x**2), x) == log(x**2 - 1)/2 assert ratint((x/4 - 4/(1 - x)).diff(x), x) == x/4 + 4/(x - 1) ans = atan(x) assert ratint(1/(x**2 + 1), x, symbol=x) == ans assert ratint(1/(x**2 + 1), x, symbol='x') == ans assert ratint(1/(x**2 + 1), x, symbol=a) == ans # this asserts that as_dummy must return a unique symbol # even if the symbol is already a Dummy d = Dummy() assert ratint(1/(d**2 + 1), d, symbol=d) == atan(d) def test_ratint_logpart(): assert ratint_logpart(x, x**2 - 9, x, t) == \ [(Poly(x**2 - 9, x), Poly(-2*t + 1, t))] assert ratint_logpart(x**2, x**3 - 5, x, t) == \ [(Poly(x**3 - 5, x), Poly(-3*t + 1, t))] def test_issue_5414(): assert ratint(1/(x**2 + 16), x) == atan(x/4)/4 def test_issue_5249(): assert ratint( 1/(x**2 + a**2), x) == (-I*log(-I*a + x)/2 + I*log(I*a + x)/2)/a def test_issue_5817(): a, b, c = symbols('a,b,c', positive=True) assert simplify(ratint(a/(b*c*x**2 + a**2 + b*a), x)) == \ sqrt(a)*atan(sqrt( b)*sqrt(c)*x/(sqrt(a)*sqrt(a + b)))/(sqrt(b)*sqrt(c)*sqrt(a + b)) def test_issue_5981(): u = symbols('u') assert integrate(1/(u**2 + 1)) == atan(u) def test_issue_10488(): a,b,c,x = symbols('a b c x', real=True, positive=True) assert integrate(x/(a*x+b),x) == x/a - b*log(a*x + b)/a**2 def test_issues_8246_12050_13501_14080(): a = symbols('a', nonzero=True) assert integrate(a/(x**2 + a**2), x) == atan(x/a) assert integrate(1/(x**2 + a**2), x) == atan(x/a)/a assert integrate(1/(1 + a**2*x**2), x) == atan(a*x)/a def test_issue_6308(): k, a0 = symbols('k a0', real=True) assert integrate((x**2 + 1 - k**2)/(x**2 + 1 + a0**2), x) == \ x - (a0**2 + k**2)*atan(x/sqrt(a0**2 + 1))/sqrt(a0**2 + 1) def test_issue_5907(): a = symbols('a', nonzero=True) assert integrate(1/(x**2 + a**2)**2, x) == \ x/(2*a**4 + 2*a**2*x**2) + atan(x/a)/(2*a**3) def test_log_to_atan(): f, g = (Poly(x + S.Half, x, domain='QQ'), Poly(sqrt(3)/2, x, domain='EX')) fg_ans = 2*atan(2*sqrt(3)*x/3 + sqrt(3)/3) assert log_to_atan(f, g) == fg_ans assert log_to_atan(g, f) == -fg_ans sympy-sympy-1.9/sympy/integrals/tests/test_rde.py000066400000000000000000000224261412543434000224270ustar00rootroot00000000000000"""Most of these tests come from the examples in Bronstein's book.""" from sympy import Poly, symbols, oo, I, Rational from sympy.integrals.risch import (DifferentialExtension, NonElementaryIntegralException) from sympy.integrals.rde import (order_at, order_at_oo, weak_normalizer, normal_denom, special_denom, bound_degree, spde, solve_poly_rde, no_cancel_equal, cancel_primitive, cancel_exp, rischDE) from sympy.testing.pytest import raises from sympy.abc import x, t, z, n t0, t1, t2, k = symbols('t:3 k') def test_order_at(): a = Poly(t**4, t) b = Poly((t**2 + 1)**3*t, t) c = Poly((t**2 + 1)**6*t, t) d = Poly((t**2 + 1)**10*t**10, t) e = Poly((t**2 + 1)**100*t**37, t) p1 = Poly(t, t) p2 = Poly(1 + t**2, t) assert order_at(a, p1, t) == 4 assert order_at(b, p1, t) == 1 assert order_at(c, p1, t) == 1 assert order_at(d, p1, t) == 10 assert order_at(e, p1, t) == 37 assert order_at(a, p2, t) == 0 assert order_at(b, p2, t) == 3 assert order_at(c, p2, t) == 6 assert order_at(d, p1, t) == 10 assert order_at(e, p2, t) == 100 assert order_at(Poly(0, t), Poly(t, t), t) is oo assert order_at_oo(Poly(t**2 - 1, t), Poly(t + 1), t) == \ order_at_oo(Poly(t - 1, t), Poly(1, t), t) == -1 assert order_at_oo(Poly(0, t), Poly(1, t), t) is oo def test_weak_normalizer(): a = Poly((1 + x)*t**5 + 4*t**4 + (-1 - 3*x)*t**3 - 4*t**2 + (-2 + 2*x)*t, t) d = Poly(t**4 - 3*t**2 + 2, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) r = weak_normalizer(a, d, DE, z) assert r == (Poly(t**5 - t**4 - 4*t**3 + 4*t**2 + 4*t - 4, t, domain='ZZ[x]'), (Poly((1 + x)*t**2 + x*t, t, domain='ZZ[x]'), Poly(t + 1, t, domain='ZZ[x]'))) assert weak_normalizer(r[1][0], r[1][1], DE) == (Poly(1, t), r[1]) r = weak_normalizer(Poly(1 + t**2), Poly(t**2 - 1, t), DE, z) assert r == (Poly(t**4 - 2*t**2 + 1, t), (Poly(-3*t**2 + 1, t), Poly(t**2 - 1, t))) assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1]) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2)]}) r = weak_normalizer(Poly(1 + t**2), Poly(t, t), DE, z) assert r == (Poly(t, t), (Poly(0, t), Poly(1, t))) assert weak_normalizer(r[1][0], r[1][1], DE, z) == (Poly(1, t), r[1]) def test_normal_denom(): DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) raises(NonElementaryIntegralException, lambda: normal_denom(Poly(1, x), Poly(1, x), Poly(1, x), Poly(x, x), DE)) fa, fd = Poly(t**2 + 1, t), Poly(1, t) ga, gd = Poly(1, t), Poly(t**2, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert normal_denom(fa, fd, ga, gd, DE) == \ (Poly(t, t), (Poly(t**3 - t**2 + t - 1, t), Poly(1, t)), (Poly(1, t), Poly(1, t)), Poly(t, t)) def test_special_denom(): # TODO: add more tests here DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t), Poly(t, t), DE) == \ (Poly(1, t), Poly(t**2 - 1, t), Poly(t**2 - 1, t), Poly(t, t)) # assert special_denom(Poly(1, t), Poly(2*x, t), Poly((1 + 2*x)*t, t), DE) == 1 # issue 3940 # Note, this isn't a very good test, because the denominator is just 1, # but at least it tests the exp cancellation case DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-2*x*t0, t0), Poly(I*k*t1, t1)]}) DE.decrement_level() assert special_denom(Poly(1, t0), Poly(I*k, t0), Poly(1, t0), Poly(t0, t0), Poly(1, t0), DE) == \ (Poly(1, t0, domain='ZZ'), Poly(I*k, t0, domain='ZZ_I[k,x]'), Poly(t0, t0, domain='ZZ'), Poly(1, t0, domain='ZZ')) assert special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t), Poly(t, t), DE, case='tan') == \ (Poly(1, t, t0, domain='ZZ'), Poly(t**2, t0, t, domain='ZZ[x]'), Poly(t, t, t0, domain='ZZ'), Poly(1, t0, domain='ZZ')) raises(ValueError, lambda: special_denom(Poly(1, t), Poly(t**2, t), Poly(1, t), Poly(t**2 - 1, t), Poly(t, t), DE, case='unrecognized_case')) def test_bound_degree_fail(): # Primitive DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0/x**2, t0), Poly(1/x, t)]}) assert bound_degree(Poly(t**2, t), Poly(-(1/x**2*t**2 + 1/x), t), Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/2*x*t**2 + x*t, t), DE) == 3 def test_bound_degree(): # Base DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) assert bound_degree(Poly(1, x), Poly(-2*x, x), Poly(1, x), DE) == 0 # Primitive (see above test_bound_degree_fail) # TODO: Add test for when the degree bound becomes larger after limited_integrate # TODO: Add test for db == da - 1 case # Exp # TODO: Add tests # TODO: Add test for when the degree becomes larger after parametric_log_deriv() # Nonlinear DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert bound_degree(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), DE) == 0 def test_spde(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) raises(NonElementaryIntegralException, lambda: spde(Poly(t, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE)) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert spde(Poly(t**2 + x*t*2 + x**2, t), Poly(t**2/x**2 + (2/x - 1)*t, t), Poly(t**2/x**2 + (2/x - 1)*t, t), 0, DE) == \ (Poly(0, t), Poly(0, t), 0, Poly(0, t), Poly(1, t, domain='ZZ(x)')) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0/x**2, t0), Poly(1/x, t)]}) assert spde(Poly(t**2, t), Poly(-t**2/x**2 - 1/x, t), Poly((2*x - 1)*t**4 + (t0 + x)/x*t**3 - (t0 + 4*x**2)/(2*x)*t**2 + x*t, t), 3, DE) == \ (Poly(0, t), Poly(0, t), 0, Poly(0, t), Poly(t0*t**2/2 + x**2*t**2 - x**2*t, t, domain='ZZ(x,t0)')) DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 + 3*x**4/4 + x**3 - x**2 + 1, x), 4, DE) == \ (Poly(0, x, domain='QQ'), Poly(x/2 - Rational(1, 4), x), 2, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 4), x)) assert spde(Poly(x**2 + x + 1, x), Poly(-2*x - 1, x), Poly(x**5/2 + 3*x**4/4 + x**3 - x**2 + 1, x), n, DE) == \ (Poly(0, x, domain='QQ'), Poly(x/2 - Rational(1, 4), x), -2 + n, Poly(x**2 + x + 1, x), Poly(x*Rational(5, 4), x)) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]}) raises(NonElementaryIntegralException, lambda: spde(Poly((t - 1)*(t**2 + 1)**2, t), Poly((t - 1)*(t**2 + 1), t), Poly(1, t), 0, DE)) DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) assert spde(Poly(x**2 - x, x), Poly(1, x), Poly(9*x**4 - 10*x**3 + 2*x**2, x), 4, DE) == \ (Poly(0, x, domain='ZZ'), Poly(0, x), 0, Poly(0, x), Poly(3*x**3 - 2*x**2, x, domain='QQ')) assert spde(Poly(x**2 - x, x), Poly(x**2 - 5*x + 3, x), Poly(x**7 - x**6 - 2*x**4 + 3*x**3 - x**2, x), 5, DE) == \ (Poly(1, x, domain='QQ'), Poly(x + 1, x, domain='QQ'), 1, Poly(x**4 - x**3, x), Poly(x**3 - x**2, x, domain='QQ')) def test_solve_poly_rde_no_cancel(): # deg(b) large DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) assert solve_poly_rde(Poly(t**2 + 1, t), Poly(t**3 + (x + 1)*t**2 + t + x + 2, t), oo, DE) == Poly(t + x, t) # deg(b) small DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) assert solve_poly_rde(Poly(0, x), Poly(x/2 - Rational(1, 4), x), oo, DE) == \ Poly(x**2/4 - x/4, x) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert solve_poly_rde(Poly(2, t), Poly(t**2 + 2*t + 3, t), 1, DE) == \ Poly(t + 1, t, x) # deg(b) == deg(D) - 1 DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert no_cancel_equal(Poly(1 - t, t), Poly(t**3 + t**2 - 2*x*t - 2*x, t), oo, DE) == \ (Poly(t**2, t), 1, Poly((-2 - 2*x)*t - 2*x, t)) def test_solve_poly_rde_cancel(): # exp DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert cancel_exp(Poly(2*x, t), Poly(2*x, t), 0, DE) == \ Poly(1, t) assert cancel_exp(Poly(2*x, t), Poly((1 + 2*x)*t, t), 1, DE) == \ Poly(t, t) # TODO: Add more exp tests, including tests that require is_deriv_in_field() # primitive DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) # If the DecrementLevel context manager is working correctly, this shouldn't # cause any problems with the further tests. raises(NonElementaryIntegralException, lambda: cancel_primitive(Poly(1, t), Poly(t, t), oo, DE)) assert cancel_primitive(Poly(1, t), Poly(t + 1/x, t), 2, DE) == \ Poly(t, t) assert cancel_primitive(Poly(4*x, t), Poly(4*x*t**2 + 2*t/x, t), 3, DE) == \ Poly(t**2, t) # TODO: Add more primitive tests, including tests that require is_deriv_in_field() def test_rischDE(): # TODO: Add more tests for rischDE, including ones from the text DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) DE.decrement_level() assert rischDE(Poly(-2*x, x), Poly(1, x), Poly(1 - 2*x - 2*x**2, x), Poly(1, x), DE) == \ (Poly(x + 1, x), Poly(1, x)) sympy-sympy-1.9/sympy/integrals/tests/test_risch.py000066400000000000000000001105751412543434000227700ustar00rootroot00000000000000"""Most of these tests come from the examples in Bronstein's book.""" from sympy import (Poly, I, S, Function, log, symbols, exp, tan, sqrt, Symbol, Lambda, sin, Ne, Piecewise, factor, expand_log, cancel, diff, pi, atan, Rational) from sympy.integrals.risch import (gcdex_diophantine, frac_in, as_poly_1t, derivation, splitfactor, splitfactor_sqf, canonical_representation, hermite_reduce, polynomial_reduce, residue_reduce, residue_reduce_to_basic, integrate_primitive, integrate_hyperexponential_polynomial, integrate_hyperexponential, integrate_hypertangent_polynomial, integrate_nonlinear_no_specials, integer_powers, DifferentialExtension, risch_integrate, DecrementLevel, NonElementaryIntegral, recognize_log_derivative, recognize_derivative, laurent_series) from sympy.testing.pytest import raises from sympy.abc import x, t, nu, z, a, y t0, t1, t2 = symbols('t:3') i = Symbol('i') def test_gcdex_diophantine(): assert gcdex_diophantine(Poly(x**4 - 2*x**3 - 6*x**2 + 12*x + 15), Poly(x**3 + x**2 - 4*x - 4), Poly(x**2 - 1)) == \ (Poly((-x**2 + 4*x - 3)/5), Poly((x**3 - 7*x**2 + 16*x - 10)/5)) assert gcdex_diophantine(Poly(x**3 + 6*x + 7), Poly(x**2 + 3*x + 2), Poly(x + 1)) == \ (Poly(1/13, x, domain='QQ'), Poly(-1/13*x + 3/13, x, domain='QQ')) def test_frac_in(): assert frac_in(Poly((x + 1)/x*t, t), x) == \ (Poly(t*x + t, x), Poly(x, x)) assert frac_in((x + 1)/x*t, x) == \ (Poly(t*x + t, x), Poly(x, x)) assert frac_in((Poly((x + 1)/x*t, t), Poly(t + 1, t)), x) == \ (Poly(t*x + t, x), Poly((1 + t)*x, x)) raises(ValueError, lambda: frac_in((x + 1)/log(x)*t, x)) assert frac_in(Poly((2 + 2*x + x*(1 + x))/(1 + x)**2, t), x, cancel=True) == \ (Poly(x + 2, x), Poly(x + 1, x)) def test_as_poly_1t(): assert as_poly_1t(2/t + t, t, z) in [ Poly(t + 2*z, t, z), Poly(t + 2*z, z, t)] assert as_poly_1t(2/t + 3/t**2, t, z) in [ Poly(2*z + 3*z**2, t, z), Poly(2*z + 3*z**2, z, t)] assert as_poly_1t(2/((exp(2) + 1)*t), t, z) in [ Poly(2/(exp(2) + 1)*z, t, z), Poly(2/(exp(2) + 1)*z, z, t)] assert as_poly_1t(2/((exp(2) + 1)*t) + t, t, z) in [ Poly(t + 2/(exp(2) + 1)*z, t, z), Poly(t + 2/(exp(2) + 1)*z, z, t)] assert as_poly_1t(S.Zero, t, z) == Poly(0, t, z) def test_derivation(): p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 + (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]}) assert derivation(p, DE) == Poly(-20*x**4*t**6 + (2*x**3 + 16*x**4)*t**5 + (21*x**2 + 12*x**3)*t**4 + (x*Rational(7, 2) - 25*x**2 - 12*x**3)*t**3 + (-5 - x*Rational(15, 2) + 7*x**2)*t**2 - (3 - 8*x - 10*x**2 - 4*x**3)/(2*x)*t + (1 - 4*x**2)/(2*x), t) assert derivation(Poly(1, t), DE) == Poly(0, t) assert derivation(Poly(t, t), DE) == DE.d assert derivation(Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t), DE) == \ Poly(-2*t**3 - 4/x*t**2 - (5 - 2*x)/(2*x**2)*t - (1 - 2*x)/(2*x**3), t, domain='ZZ(x)') DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(t, t)]}) assert derivation(Poly(x*t*t1, t), DE) == Poly(t*t1 + x*t*t1 + t, t) assert derivation(Poly(x*t*t1, t), DE, coefficientD=True) == \ Poly((1 + t1)*t, t) DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) assert derivation(Poly(x, x), DE) == Poly(1, x) # Test basic option assert derivation((x + 1)/(x - 1), DE, basic=True) == -2/(1 - 2*x + x**2) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert derivation((t + 1)/(t - 1), DE, basic=True) == -2*t/(1 - 2*t + t**2) assert derivation(t + 1, DE, basic=True) == t def test_splitfactor(): p = Poly(4*x**4*t**5 + (-4*x**3 - 4*x**4)*t**4 + (-3*x**2 + 2*x**3)*t**3 + (2*x + 7*x**2 + 2*x**3)*t**2 + (1 - 4*x - 4*x**2)*t - 1 + 2*x, t, field=True) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - 3/(2*x)*t + 1/(2*x), t)]}) assert splitfactor(p, DE) == (Poly(4*x**4*t**3 + (-8*x**3 - 4*x**4)*t**2 + (4*x**2 + 8*x**3)*t - 4*x**2, t, domain='ZZ(x)'), Poly(t**2 + 1/x*t + (1 - 2*x)/(4*x**2), t, domain='ZZ(x)')) assert splitfactor(Poly(x, t), DE) == (Poly(x, t), Poly(1, t)) r = Poly(-4*x**4*z**2 + 4*x**6*z**2 - z*x**3 - 4*x**5*z**3 + 4*x**3*z**3 + x**4 + z*x**5 - x**6, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) assert splitfactor(r, DE, coefficientD=True) == \ (Poly(x*z - x**2 - z*x**3 + x**4, t), Poly(-x**2 + 4*x**2*z**2, t)) assert splitfactor_sqf(r, DE, coefficientD=True) == \ (((Poly(x*z - x**2 - z*x**3 + x**4, t), 1),), ((Poly(-x**2 + 4*x**2*z**2, t), 1),)) assert splitfactor(Poly(0, t), DE) == (Poly(0, t), Poly(1, t)) assert splitfactor_sqf(Poly(0, t), DE) == (((Poly(0, t), 1),), ()) def test_canonical_representation(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) assert canonical_representation(Poly(x - t, t), Poly(t**2, t), DE) == \ (Poly(0, t, domain='ZZ[x]'), (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='ZZ')), (Poly(-t + x, t, domain='QQ[x]'), Poly(t**2, t))) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert canonical_representation(Poly(t**5 + t**3 + x**2*t + 1, t), Poly((t**2 + 1)**3, t), DE) == \ (Poly(0, t, domain='ZZ[x]'), (Poly(t**5 + t**3 + x**2*t + 1, t, domain='QQ[x]'), Poly(t**6 + 3*t**4 + 3*t**2 + 1, t, domain='QQ')), (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ'))) def test_hermite_reduce(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert hermite_reduce(Poly(x - t, t), Poly(t**2, t), DE) == \ ((Poly(-x, t, domain='QQ[x]'), Poly(t, t, domain='QQ[x]')), (Poly(0, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]')), (Poly(-x, t, domain='QQ[x]'), Poly(1, t, domain='QQ[x]'))) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]}) assert hermite_reduce( Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 - nu**2)*t - x**5/4, t), Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t), DE) == \ ((Poly(-x**2 - 4, t, domain='ZZ(x,nu)'), Poly(4*t**2 + 2*x**2 + 4, t, domain='ZZ(x,nu)')), (Poly((-2*nu**2 - x**4)*t - (2*x**3 + 2*x), t, domain='ZZ(x,nu)'), Poly(2*x**2*t**2 + x**4 + 2*x**2, t, domain='ZZ(x,nu)')), (Poly(x*t + 1, t, domain='ZZ(x,nu)'), Poly(x, t, domain='ZZ(x,nu)'))) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) a = Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t) d = Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t) assert hermite_reduce(a, d, DE) == \ ((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'), Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')), (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)'))) assert hermite_reduce( Poly(-t**2 + 2*t + 2, t, domain='ZZ(x)'), Poly(-x*t**2 + 2*x*t - x, t, domain='ZZ(x)'), DE) == \ ((Poly(3, t, domain='ZZ(x)'), Poly(t - 1, t, domain='ZZ(x)')), (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), (Poly(1, t, domain='ZZ(x)'), Poly(x, t, domain='ZZ(x)'))) assert hermite_reduce( Poly(-x**2*t**6 + (-1 - 2*x**3 + x**4)*t**3 + (-3 - 3*x**4)*t**2 - 2*x*t - x - 3*x**2, t, domain='ZZ(x)'), Poly(x**4*t**6 - 2*x**2*t**3 + 1, t, domain='ZZ(x)'), DE) == \ ((Poly(x**3*t + x**4 + 1, t, domain='ZZ(x)'), Poly(x**3*t**3 - x, t, domain='ZZ(x)')), (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), (Poly(-1, t, domain='ZZ(x)'), Poly(x**2, t, domain='ZZ(x)'))) assert hermite_reduce( Poly((-2 + 3*x)*t**3 + (-1 + x)*t**2 + (-4*x + 2*x**2)*t + x**2, t), Poly(x*t**6 - 4*x**2*t**5 + 6*x**3*t**4 - 4*x**4*t**3 + x**5*t**2, t), DE) == \ ((Poly(3*t**2 + t + 3*x, t, domain='ZZ(x)'), Poly(3*t**4 - 9*x*t**3 + 9*x**2*t**2 - 3*x**3*t, t, domain='ZZ(x)')), (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)')), (Poly(0, t, domain='ZZ(x)'), Poly(1, t, domain='ZZ(x)'))) def test_polynomial_reduce(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) assert polynomial_reduce(Poly(1 + x*t + t**2, t), DE) == \ (Poly(t, t), Poly(x*t, t)) assert polynomial_reduce(Poly(0, t), DE) == \ (Poly(0, t), Poly(0, t)) def test_laurent_series(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1, t)]}) a = Poly(36, t) d = Poly((t - 2)*(t**2 - 1)**2, t) F = Poly(t**2 - 1, t) n = 2 assert laurent_series(a, d, F, n, DE) == \ (Poly(-3*t**3 + 3*t**2 - 6*t - 8, t), Poly(t**5 + t**4 - 2*t**3 - 2*t**2 + t + 1, t), [Poly(-3*t**3 - 6*t**2, t, domain='QQ'), Poly(2*t**6 + 6*t**5 - 8*t**3, t, domain='QQ')]) def test_recognize_derivative(): DE = DifferentialExtension(extension={'D': [Poly(1, t)]}) a = Poly(36, t) d = Poly((t - 2)*(t**2 - 1)**2, t) assert recognize_derivative(a, d, DE) == False DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) a = Poly(2, t) d = Poly(t**2 - 1, t) assert recognize_derivative(a, d, DE) == False assert recognize_derivative(Poly(x*t, t), Poly(1, t), DE) == True DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert recognize_derivative(Poly(t, t), Poly(1, t), DE) == True def test_recognize_log_derivative(): a = Poly(2*x**2 + 4*x*t - 2*t - x**2*t, t) d = Poly((2*x + t)*(t + x**2), t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert recognize_log_derivative(a, d, DE, z) == True DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)]}) assert recognize_log_derivative(Poly(t + 1, t), Poly(t + x, t), DE) == True assert recognize_log_derivative(Poly(2, t), Poly(t**2 - 1, t), DE) == True DE = DifferentialExtension(extension={'D': [Poly(1, x)]}) assert recognize_log_derivative(Poly(1, x), Poly(x**2 - 2, x), DE) == False assert recognize_log_derivative(Poly(1, x), Poly(x**2 + x, x), DE) == True DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert recognize_log_derivative(Poly(1, t), Poly(t**2 - 2, t), DE) == False assert recognize_log_derivative(Poly(1, t), Poly(t**2 + t, t), DE) == False def test_residue_reduce(): a = Poly(2*t**2 - t - x**2, t) d = Poly(t**3 - x**2*t, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)], 'Tfuncs': [log]}) assert residue_reduce(a, d, DE, z, invert=False) == \ ([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'), Poly((1 + 3*x*z - 6*z**2 - 2*x**2 + 4*x**2*z**2)*t - x*z + x**2 + 2*x**2*z**2 - 2*z*x**3, t, domain='ZZ(z, x)'))], False) assert residue_reduce(a, d, DE, z, invert=True) == \ ([(Poly(z**2 - Rational(1, 4), z, domain='ZZ(x)'), Poly(t + 2*x*z, t))], False) assert residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t,), DE, z, invert=False) == \ ([(Poly(z**2 - 1, z, domain='QQ'), Poly(-2*z*t/x - 2/x, t, domain='ZZ(z,x)'))], True) ans = residue_reduce(Poly(-2/x, t), Poly(t**2 - 1, t), DE, z, invert=True) assert ans == ([(Poly(z**2 - 1, z, domain='QQ'), Poly(t + z, t))], True) assert residue_reduce_to_basic(ans[0], DE, z) == -log(-1 + log(x)) + log(1 + log(x)) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)]}) # TODO: Skip or make faster assert residue_reduce(Poly((-2*nu**2 - x**4)/(2*x**2)*t - (1 + x**2)/x, t), Poly(t**2 + 1 + x**2/2, t), DE, z) == \ ([(Poly(z + S.Half, z, domain='QQ'), Poly(t**2 + 1 + x**2/2, t, domain='ZZ(x,nu)'))], True) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t**2, t)]}) assert residue_reduce(Poly(-2*x*t + 1 - x**2, t), Poly(t**2 + 2*x*t + 1 + x**2, t), DE, z) == \ ([(Poly(z**2 + Rational(1, 4), z), Poly(t + x + 2*z, t))], True) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert residue_reduce(Poly(t, t), Poly(t + sqrt(2), t), DE, z) == \ ([(Poly(z - 1, z, domain='QQ'), Poly(t + sqrt(2), t))], True) def test_integrate_hyperexponential(): # TODO: Add tests for integrate_hyperexponential() from the book a = Poly((1 + 2*t1 + t1**2 + 2*t1**3)*t**2 + (1 + t1**2)*t + 1 + t1**2, t) d = Poly(1, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1 + t1**2, t1), Poly(t*(1 + t1**2), t)], 'Tfuncs': [tan, Lambda(i, exp(tan(i)))]}) assert integrate_hyperexponential(a, d, DE) == \ (exp(2*tan(x))*tan(x) + exp(tan(x)), 1 + t1**2, True) a = Poly((t1**3 + (x + 1)*t1**2 + t1 + x + 2)*t, t) assert integrate_hyperexponential(a, d, DE) == \ ((x + tan(x))*exp(tan(x)), 0, True) a = Poly(t, t) d = Poly(1, t) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(2*x*t, t)], 'Tfuncs': [Lambda(i, exp(x**2))]}) assert integrate_hyperexponential(a, d, DE) == \ (0, NonElementaryIntegral(exp(x**2), x), False) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]}) assert integrate_hyperexponential(a, d, DE) == (exp(x), 0, True) a = Poly(25*t**6 - 10*t**5 + 7*t**4 - 8*t**3 + 13*t**2 + 2*t - 1, t) d = Poly(25*t**6 + 35*t**4 + 11*t**2 + 1, t) assert integrate_hyperexponential(a, d, DE) == \ (-(11 - 10*exp(x))/(5 + 25*exp(2*x)) + log(1 + exp(2*x)), -1, True) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(t0*t, t)], 'Tfuncs': [exp, Lambda(i, exp(exp(i)))]}) assert integrate_hyperexponential(Poly(2*t0*t**2, t), Poly(1, t), DE) == (exp(2*exp(x)), 0, True) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t0, t0), Poly(-t0*t, t)], 'Tfuncs': [exp, Lambda(i, exp(-exp(i)))]}) assert integrate_hyperexponential(Poly(-27*exp(9) - 162*t0*exp(9) + 27*x*t0*exp(9), t), Poly((36*exp(18) + x**2*exp(18) - 12*x*exp(18))*t, t), DE) == \ (27*exp(exp(x))/(-6*exp(9) + x*exp(9)), 0, True) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'Tfuncs': [exp]}) assert integrate_hyperexponential(Poly(x**2/2*t, t), Poly(1, t), DE) == \ ((2 - 2*x + x**2)*exp(x)/2, 0, True) assert integrate_hyperexponential(Poly(1 + t, t), Poly(t, t), DE) == \ (-exp(-x), 1, True) # x - exp(-x) assert integrate_hyperexponential(Poly(x, t), Poly(t + 1, t), DE) == \ (0, NonElementaryIntegral(x/(1 + exp(x)), x), False) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)], 'Tfuncs': [log, Lambda(i, exp(i**2))]}) elem, nonelem, b = integrate_hyperexponential(Poly((8*x**7 - 12*x**5 + 6*x**3 - x)*t1**4 + (8*t0*x**7 - 8*t0*x**6 - 4*t0*x**5 + 2*t0*x**3 + 2*t0*x**2 - t0*x + 24*x**8 - 36*x**6 - 4*x**5 + 22*x**4 + 4*x**3 - 7*x**2 - x + 1)*t1**3 + (8*t0*x**8 - 4*t0*x**6 - 16*t0*x**5 - 2*t0*x**4 + 12*t0*x**3 + t0*x**2 - 2*t0*x + 24*x**9 - 36*x**7 - 8*x**6 + 22*x**5 + 12*x**4 - 7*x**3 - 6*x**2 + x + 1)*t1**2 + (8*t0*x**8 - 8*t0*x**6 - 16*t0*x**5 + 6*t0*x**4 + 10*t0*x**3 - 2*t0*x**2 - t0*x + 8*x**10 - 12*x**8 - 4*x**7 + 2*x**6 + 12*x**5 + 3*x**4 - 9*x**3 - x**2 + 2*x)*t1 + 8*t0*x**7 - 12*t0*x**6 - 4*t0*x**5 + 8*t0*x**4 - t0*x**2 - 4*x**7 + 4*x**6 + 4*x**5 - 4*x**4 - x**3 + x**2, t1), Poly((8*x**7 - 12*x**5 + 6*x**3 - x)*t1**4 + (24*x**8 + 8*x**7 - 36*x**6 - 12*x**5 + 18*x**4 + 6*x**3 - 3*x**2 - x)*t1**3 + (24*x**9 + 24*x**8 - 36*x**7 - 36*x**6 + 18*x**5 + 18*x**4 - 3*x**3 - 3*x**2)*t1**2 + (8*x**10 + 24*x**9 - 12*x**8 - 36*x**7 + 6*x**6 + 18*x**5 - x**4 - 3*x**3)*t1 + 8*x**10 - 12*x**8 + 6*x**6 - x**4, t1), DE) assert factor(elem) == -((x - 1)*log(x)/((x + exp(x**2))*(2*x**2 - 1))) assert (nonelem, b) == (NonElementaryIntegral(exp(x**2)/(exp(x**2) + 1), x), False) def test_integrate_hyperexponential_polynomial(): # Without proper cancellation within integrate_hyperexponential_polynomial(), # this will take a long time to complete, and will return a complicated # expression p = Poly((-28*x**11*t0 - 6*x**8*t0 + 6*x**9*t0 - 15*x**8*t0**2 + 15*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 20*x**6*t0**3 + 20*x**7*t0**3 - 15*x**6*t0**4 + 15*x**5*t0**4 + 140*x**8*t0**4 - 84*x**7*t0**5 - 6*x**4*t0**5 + 6*x**5*t0**5 + x**3*t0**6 - x**4*t0**6 + 28*x**6*t0**6 - 4*x**5*t0**7 + x**9 - x**10 + 4*x**12)/(-8*x**11*t0 + 28*x**10*t0**2 - 56*x**9*t0**3 + 70*x**8*t0**4 - 56*x**7*t0**5 + 28*x**6*t0**6 - 8*x**5*t0**7 + x**4*t0**8 + x**12)*t1**2 + (-28*x**11*t0 - 12*x**8*t0 + 12*x**9*t0 - 30*x**8*t0**2 + 30*x**7*t0**2 + 84*x**10*t0**2 - 140*x**9*t0**3 - 40*x**6*t0**3 + 40*x**7*t0**3 - 30*x**6*t0**4 + 30*x**5*t0**4 + 140*x**8*t0**4 - 84*x**7*t0**5 - 12*x**4*t0**5 + 12*x**5*t0**5 - 2*x**4*t0**6 + 2*x**3*t0**6 + 28*x**6*t0**6 - 4*x**5*t0**7 + 2*x**9 - 2*x**10 + 4*x**12)/(-8*x**11*t0 + 28*x**10*t0**2 - 56*x**9*t0**3 + 70*x**8*t0**4 - 56*x**7*t0**5 + 28*x**6*t0**6 - 8*x**5*t0**7 + x**4*t0**8 + x**12)*t1 + (-2*x**2*t0 + 2*x**3*t0 + x*t0**2 - x**2*t0**2 + x**3 - x**4)/(-4*x**5*t0 + 6*x**4*t0**2 - 4*x**3*t0**3 + x**2*t0**4 + x**6), t1, z, expand=False) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0), Poly(2*x*t1, t1)]}) assert integrate_hyperexponential_polynomial(p, DE, z) == ( Poly((x - t0)*t1**2 + (-2*t0 + 2*x)*t1, t1), Poly(-2*x*t0 + x**2 + t0**2, t1), True) DE = DifferentialExtension(extension={'D':[Poly(1, x), Poly(t0, t0)]}) assert integrate_hyperexponential_polynomial(Poly(0, t0), DE, z) == ( Poly(0, t0), Poly(1, t0), True) def test_integrate_hyperexponential_returns_piecewise(): a, b = symbols('a b') DE = DifferentialExtension(a**x, x) assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( (exp(x*log(a))/log(a), Ne(log(a), 0)), (x, True)), 0, True) DE = DifferentialExtension(a**(b*x), x) assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( (exp(b*x*log(a))/(b*log(a)), Ne(b*log(a), 0)), (x, True)), 0, True) DE = DifferentialExtension(exp(a*x), x) assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( (exp(a*x)/a, Ne(a, 0)), (x, True)), 0, True) DE = DifferentialExtension(x*exp(a*x), x) assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( ((a*x - 1)*exp(a*x)/a**2, Ne(a**2, 0)), (x**2/2, True)), 0, True) DE = DifferentialExtension(x**2*exp(a*x), x) assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( ((x**2*a**2 - 2*a*x + 2)*exp(a*x)/a**3, Ne(a**3, 0)), (x**3/3, True)), 0, True) DE = DifferentialExtension(x**y + z, y) assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( (exp(log(x)*y)/log(x), Ne(log(x), 0)), (y, True)), z, True) DE = DifferentialExtension(x**y + z + x**(2*y), y) assert integrate_hyperexponential(DE.fa, DE.fd, DE) == (Piecewise( ((exp(2*log(x)*y)*log(x) + 2*exp(log(x)*y)*log(x))/(2*log(x)**2), Ne(2*log(x)**2, 0)), (2*y, True), ), z, True) # TODO: Add a test where two different parts of the extension use a # Piecewise, like y**x + z**x. def test_issue_13947(): a, t, s = symbols('a t s') assert risch_integrate(2**(-pi)/(2**t + 1), t) == \ 2**(-pi)*t - 2**(-pi)*log(2**t + 1)/log(2) assert risch_integrate(a**(t - s)/(a**t + 1), t) == \ exp(-s*log(a))*log(a**t + 1)/log(a) def test_integrate_primitive(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t)], 'Tfuncs': [log]}) assert integrate_primitive(Poly(t, t), Poly(1, t), DE) == (x*log(x), -1, True) assert integrate_primitive(Poly(x, t), Poly(t, t), DE) == (0, NonElementaryIntegral(x/log(x), x), False) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x + 1), t2)], 'Tfuncs': [log, Lambda(i, log(i + 1))]}) assert integrate_primitive(Poly(t1, t2), Poly(t2, t2), DE) == \ (0, NonElementaryIntegral(log(x)/log(1 + x), x), False) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t1), Poly(1/(x*t1), t2)], 'Tfuncs': [log, Lambda(i, log(log(i)))]}) assert integrate_primitive(Poly(t2, t2), Poly(t1, t2), DE) == \ (0, NonElementaryIntegral(log(log(x))/log(x), x), False) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(1/x, t0)], 'Tfuncs': [log]}) assert integrate_primitive(Poly(x**2*t0**3 + (3*x**2 + x)*t0**2 + (3*x**2 + 2*x)*t0 + x**2 + x, t0), Poly(x**2*t0**4 + 4*x**2*t0**3 + 6*x**2*t0**2 + 4*x**2*t0 + x**2, t0), DE) == \ (-1/(log(x) + 1), NonElementaryIntegral(1/(log(x) + 1), x), False) def test_integrate_hypertangent_polynomial(): DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t**2 + 1, t)]}) assert integrate_hypertangent_polynomial(Poly(t**2 + x*t + 1, t), DE) == \ (Poly(t, t), Poly(x/2, t)) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(a*(t**2 + 1), t)]}) assert integrate_hypertangent_polynomial(Poly(t**5, t), DE) == \ (Poly(1/(4*a)*t**4 - 1/(2*a)*t**2, t), Poly(1/(2*a), t)) def test_integrate_nonlinear_no_specials(): a, d, = Poly(x**2*t**5 + x*t**4 - nu**2*t**3 - x*(x**2 + 1)*t**2 - (x**2 - nu**2)*t - x**5/4, t), Poly(x**2*t**4 + x**2*(x**2 + 2)*t**2 + x**2 + x**4 + x**6/4, t) # f(x) == phi_nu(x), the logarithmic derivative of J_v, the Bessel function, # which has no specials (see Chapter 5, note 4 of Bronstein's book). f = Function('phi_nu') DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(-t**2 - t/x - (1 - nu**2/x**2), t)], 'Tfuncs': [f]}) assert integrate_nonlinear_no_specials(a, d, DE) == \ (-log(1 + f(x)**2 + x**2/2)/2 + (- 4 - x**2)/(4 + 2*x**2 + 4*f(x)**2), True) assert integrate_nonlinear_no_specials(Poly(t, t), Poly(1, t), DE) == \ (0, False) def test_integer_powers(): assert integer_powers([x, x/2, x**2 + 1, x*Rational(2, 3)]) == [ (x/6, [(x, 6), (x/2, 3), (x*Rational(2, 3), 4)]), (1 + x**2, [(1 + x**2, 1)])] def test_DifferentialExtension_exp(): assert DifferentialExtension(exp(x) + exp(x**2), x)._important_attrs == \ (Poly(t1 + t0, t1), Poly(1, t1), [Poly(1, x,), Poly(t0, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2]) assert DifferentialExtension(exp(x) + exp(2*x), x)._important_attrs == \ (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0, t0)], [x, t0], [Lambda(i, exp(i))], [], [None, 'exp'], [None, x]) assert DifferentialExtension(exp(x) + exp(x/2), x)._important_attrs == \ (Poly(t0**2 + t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0], [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2]) assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2), x)._important_attrs == \ (Poly((1 + t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2]) assert DifferentialExtension(exp(x) + exp(x**2) + exp(x + x**2 + 1), x)._important_attrs == \ (Poly((1 + S.Exp1*t0)*t1 + t0, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, exp(i**2))], [], [None, 'exp', 'exp'], [None, x, x**2]) assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2), x)._important_attrs == \ (Poly((t0 + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x), Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i/2)), Lambda(i, exp(i**2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'], [None, x/2, x**2]) assert DifferentialExtension(exp(x) + exp(x**2) + exp(x/2 + x**2 + 3), x)._important_attrs == \ (Poly((t0*exp(3) + 1)*t1 + t0**2, t1), Poly(1, t1), [Poly(1, x), Poly(t0/2, t0), Poly(2*x*t1, t1)], [x, t0, t1], [Lambda(i, exp(i/2)), Lambda(i, exp(i**2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp', 'exp'], [None, x/2, x**2]) assert DifferentialExtension(sqrt(exp(x)), x)._important_attrs == \ (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0], [Lambda(i, exp(i/2))], [(exp(x/2), sqrt(exp(x)))], [None, 'exp'], [None, x/2]) assert DifferentialExtension(exp(x/2), x)._important_attrs == \ (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(t0/2, t0)], [x, t0], [Lambda(i, exp(i/2))], [], [None, 'exp'], [None, x/2]) def test_DifferentialExtension_log(): assert DifferentialExtension(log(x)*log(x + 1)*log(2*x**2 + 2*x), x)._important_attrs == \ (Poly(t0*t1**2 + (t0*log(2) + t0**2)*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly(1/(x + 1), t1, expand=False)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, log(i + 1))], [], [None, 'log', 'log'], [None, x, x + 1]) assert DifferentialExtension(x**x*log(x), x)._important_attrs == \ (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly((1 + t0)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)], [None, 'log', 'exp'], [None, x, t0*x]) def test_DifferentialExtension_symlog(): # See comment on test_risch_integrate below assert DifferentialExtension(log(x**x), x)._important_attrs == \ (Poly(t0*x, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly((t0 + 1)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i*t0))], [(exp(x*log(x)), x**x)], [None, 'log', 'exp'], [None, x, t0*x]) assert DifferentialExtension(log(x**y), x)._important_attrs == \ (Poly(y*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], [Lambda(i, log(i))], [(y*log(x), log(x**y))], [None, 'log'], [None, x]) assert DifferentialExtension(log(sqrt(x)), x)._important_attrs == \ (Poly(t0, t0), Poly(2, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], [Lambda(i, log(i))], [(log(x)/2, log(sqrt(x)))], [None, 'log'], [None, x]) def test_DifferentialExtension_handle_first(): assert DifferentialExtension(exp(x)*log(x), x, handle_first='log')._important_attrs == \ (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(1/x, t0), Poly(t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(i))], [], [None, 'log', 'exp'], [None, x, x]) assert DifferentialExtension(exp(x)*log(x), x, handle_first='exp')._important_attrs == \ (Poly(t0*t1, t1), Poly(1, t1), [Poly(1, x), Poly(t0, t0), Poly(1/x, t1)], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, log(i))], [], [None, 'exp', 'log'], [None, x, x]) # This one must have the log first, regardless of what we set it to # (because the log is inside of the exponential: x**x == exp(x*log(x))) assert DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x, handle_first='exp')._important_attrs == \ DifferentialExtension(-x**x*log(x)**2 + x**x - x**x/x, x, handle_first='log')._important_attrs == \ (Poly((-1 + x - x*t0**2)*t1, t1), Poly(x, t1), [Poly(1, x), Poly(1/x, t0), Poly((1 + t0)*t1, t1)], [x, t0, t1], [Lambda(i, log(i)), Lambda(i, exp(t0*i))], [(exp(x*log(x)), x**x)], [None, 'log', 'exp'], [None, x, t0*x]) def test_DifferentialExtension_all_attrs(): # Test 'unimportant' attributes DE = DifferentialExtension(exp(x)*log(x), x, handle_first='exp') assert DE.f == exp(x)*log(x) assert DE.newf == t0*t1 assert DE.x == x assert DE.cases == ['base', 'exp', 'primitive'] assert DE.case == 'primitive' assert DE.level == -1 assert DE.t == t1 == DE.T[DE.level] assert DE.d == Poly(1/x, t1) == DE.D[DE.level] raises(ValueError, lambda: DE.increment_level()) DE.decrement_level() assert DE.level == -2 assert DE.t == t0 == DE.T[DE.level] assert DE.d == Poly(t0, t0) == DE.D[DE.level] assert DE.case == 'exp' DE.decrement_level() assert DE.level == -3 assert DE.t == x == DE.T[DE.level] == DE.x assert DE.d == Poly(1, x) == DE.D[DE.level] assert DE.case == 'base' raises(ValueError, lambda: DE.decrement_level()) DE.increment_level() DE.increment_level() assert DE.level == -1 assert DE.t == t1 == DE.T[DE.level] assert DE.d == Poly(1/x, t1) == DE.D[DE.level] assert DE.case == 'primitive' # Test methods assert DE.indices('log') == [2] assert DE.indices('exp') == [1] def test_DifferentialExtension_extension_flag(): raises(ValueError, lambda: DifferentialExtension(extension={'T': [x, t]})) DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)]}) assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t], None, None, None, None) assert DE.d == Poly(t, t) assert DE.t == t assert DE.level == -1 assert DE.cases == ['base', 'exp'] assert DE.x == x assert DE.case == 'exp' DE = DifferentialExtension(extension={'D': [Poly(1, x), Poly(t, t)], 'exts': [None, 'exp'], 'extargs': [None, x]}) assert DE._important_attrs == (None, None, [Poly(1, x), Poly(t, t)], [x, t], None, None, [None, 'exp'], [None, x]) raises(ValueError, lambda: DifferentialExtension()) def test_DifferentialExtension_misc(): # Odd ends assert DifferentialExtension(sin(y)*exp(x), x)._important_attrs == \ (Poly(sin(y)*t0, t0, domain='ZZ[sin(y)]'), Poly(1, t0, domain='ZZ'), [Poly(1, x, domain='ZZ'), Poly(t0, t0, domain='ZZ')], [x, t0], [Lambda(i, exp(i))], [], [None, 'exp'], [None, x]) raises(NotImplementedError, lambda: DifferentialExtension(sin(x), x)) assert DifferentialExtension(10**x, x)._important_attrs == \ (Poly(t0, t0), Poly(1, t0), [Poly(1, x), Poly(log(10)*t0, t0)], [x, t0], [Lambda(i, exp(i*log(10)))], [(exp(x*log(10)), 10**x)], [None, 'exp'], [None, x*log(10)]) assert DifferentialExtension(log(x) + log(x**2), x)._important_attrs in [ (Poly(3*t0, t0), Poly(2, t0), [Poly(1, x), Poly(2/x, t0)], [x, t0], [Lambda(i, log(i**2))], [], [None, ], [], [1], [x**2]), (Poly(3*t0, t0), Poly(1, t0), [Poly(1, x), Poly(1/x, t0)], [x, t0], [Lambda(i, log(i))], [], [None, 'log'], [None, x])] assert DifferentialExtension(S.Zero, x)._important_attrs == \ (Poly(0, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None]) assert DifferentialExtension(tan(atan(x).rewrite(log)), x)._important_attrs == \ (Poly(x, x), Poly(1, x), [Poly(1, x)], [x], [], [], [None], [None]) def test_DifferentialExtension_Rothstein(): # Rothstein's integral f = (2581284541*exp(x) + 1757211400)/(39916800*exp(3*x) + 119750400*exp(x)**2 + 119750400*exp(x) + 39916800)*exp(1/(exp(x) + 1) - 10*x) assert DifferentialExtension(f, x)._important_attrs == \ (Poly((1757211400 + 2581284541*t0)*t1, t1), Poly(39916800 + 119750400*t0 + 119750400*t0**2 + 39916800*t0**3, t1), [Poly(1, x), Poly(t0, t0), Poly(-(10 + 21*t0 + 10*t0**2)/(1 + 2*t0 + t0**2)*t1, t1, domain='ZZ(t0)')], [x, t0, t1], [Lambda(i, exp(i)), Lambda(i, exp(1/(t0 + 1) - 10*i))], [], [None, 'exp', 'exp'], [None, x, 1/(t0 + 1) - 10*x]) class _TestingException(Exception): """Dummy Exception class for testing.""" pass def test_DecrementLevel(): DE = DifferentialExtension(x*log(exp(x) + 1), x) assert DE.level == -1 assert DE.t == t1 assert DE.d == Poly(t0/(t0 + 1), t1) assert DE.case == 'primitive' with DecrementLevel(DE): assert DE.level == -2 assert DE.t == t0 assert DE.d == Poly(t0, t0) assert DE.case == 'exp' with DecrementLevel(DE): assert DE.level == -3 assert DE.t == x assert DE.d == Poly(1, x) assert DE.case == 'base' assert DE.level == -2 assert DE.t == t0 assert DE.d == Poly(t0, t0) assert DE.case == 'exp' assert DE.level == -1 assert DE.t == t1 assert DE.d == Poly(t0/(t0 + 1), t1) assert DE.case == 'primitive' # Test that __exit__ is called after an exception correctly try: with DecrementLevel(DE): raise _TestingException except _TestingException: pass else: raise AssertionError("Did not raise.") assert DE.level == -1 assert DE.t == t1 assert DE.d == Poly(t0/(t0 + 1), t1) assert DE.case == 'primitive' def test_risch_integrate(): assert risch_integrate(t0*exp(x), x) == t0*exp(x) assert risch_integrate(sin(x), x, rewrite_complex=True) == -exp(I*x)/2 - exp(-I*x)/2 # From my GSoC writeup assert risch_integrate((1 + 2*x**2 + x**4 + 2*x**3*exp(2*x**2))/ (x**4*exp(x**2) + 2*x**2*exp(x**2) + exp(x**2)), x) == \ NonElementaryIntegral(exp(-x**2), x) + exp(x**2)/(1 + x**2) assert risch_integrate(0, x) == 0 # also tests prde_cancel() e1 = log(x/exp(x) + 1) ans1 = risch_integrate(e1, x) assert ans1 == (x*log(x*exp(-x) + 1) + NonElementaryIntegral((x**2 - x)/(x + exp(x)), x)) assert cancel(diff(ans1, x) - e1) == 0 # also tests issue #10798 e2 = (log(-1/y)/2 - log(1/y)/2)/y - (log(1 - 1/y)/2 - log(1 + 1/y)/2)/y ans2 = risch_integrate(e2, y) assert ans2 == log(1/y)*log(1 - 1/y)/2 - log(1/y)*log(1 + 1/y)/2 + \ NonElementaryIntegral((I*pi*y**2 - 2*y*log(1/y) - I*pi)/(2*y**3 - 2*y), y) assert expand_log(cancel(diff(ans2, y) - e2), force=True) == 0 # These are tested here in addition to in test_DifferentialExtension above # (symlogs) to test that backsubs works correctly. The integrals should be # written in terms of the original logarithms in the integrands. # XXX: Unfortunately, making backsubs work on this one is a little # trickier, because x**x is converted to exp(x*log(x)), and so log(x**x) # is converted to x*log(x). (x**2*log(x)).subs(x*log(x), log(x**x)) is # smart enough, the issue is that these splits happen at different places # in the algorithm. Maybe a heuristic is in order assert risch_integrate(log(x**x), x) == x**2*log(x)/2 - x**2/4 assert risch_integrate(log(x**y), x) == x*log(x**y) - x*y assert risch_integrate(log(sqrt(x)), x) == x*log(sqrt(x)) - x/2 def test_risch_integrate_float(): assert risch_integrate((-60*exp(x) - 19.2*exp(4*x))*exp(4*x), x) == -2.4*exp(8*x) - 12.0*exp(5*x) def test_NonElementaryIntegral(): assert isinstance(risch_integrate(exp(x**2), x), NonElementaryIntegral) assert isinstance(risch_integrate(x**x*log(x), x), NonElementaryIntegral) # Make sure methods of Integral still give back a NonElementaryIntegral assert isinstance(NonElementaryIntegral(x**x*t0, x).subs(t0, log(x)), NonElementaryIntegral) def test_xtothex(): a = risch_integrate(x**x, x) assert a == NonElementaryIntegral(x**x, x) assert isinstance(a, NonElementaryIntegral) def test_DifferentialExtension_equality(): DE1 = DE2 = DifferentialExtension(log(x), x) assert DE1 == DE2 def test_DifferentialExtension_printing(): DE = DifferentialExtension(exp(2*x**2) + log(exp(x**2) + 1), x) assert repr(DE) == ("DifferentialExtension(dict([('f', exp(2*x**2) + log(exp(x**2) + 1)), " "('x', x), ('T', [x, t0, t1]), ('D', [Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), " "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]), ('fa', Poly(t1 + t0**2, t1, domain='ZZ[t0]')), " "('fd', Poly(1, t1, domain='ZZ')), ('Tfuncs', [Lambda(i, exp(i**2)), Lambda(i, log(t0 + 1))]), " "('backsubs', []), ('exts', [None, 'exp', 'log']), ('extargs', [None, x**2, t0 + 1]), " "('cases', ['base', 'exp', 'primitive']), ('case', 'primitive'), ('t', t1), " "('d', Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')), ('newf', t0**2 + t1), ('level', -1), " "('dummy', False)]))") assert str(DE) == ("DifferentialExtension({fa=Poly(t1 + t0**2, t1, domain='ZZ[t0]'), " "fd=Poly(1, t1, domain='ZZ'), D=[Poly(1, x, domain='ZZ'), Poly(2*x*t0, t0, domain='ZZ[x]'), " "Poly(2*t0*x/(t0 + 1), t1, domain='ZZ(x,t0)')]})") sympy-sympy-1.9/sympy/integrals/tests/test_singularityfunctions.py000066400000000000000000000022161412543434000261530ustar00rootroot00000000000000from sympy.integrals.singularityfunctions import singularityintegrate from sympy import SingularityFunction, symbols, Function x, a, n, y = symbols('x a n y') f = Function('f') def test_singularityintegrate(): assert singularityintegrate(x, x) is None assert singularityintegrate(x + SingularityFunction(x, 9, 1), x) is None assert 4*singularityintegrate(SingularityFunction(x, a, 3), x) == 4*SingularityFunction(x, a, 4)/4 assert singularityintegrate(5*SingularityFunction(x, 5, -2), x) == 5*SingularityFunction(x, 5, -1) assert singularityintegrate(6*SingularityFunction(x, 5, -1), x) == 6*SingularityFunction(x, 5, 0) assert singularityintegrate(x*SingularityFunction(x, 0, -1), x) == 0 assert singularityintegrate((x - 5)*SingularityFunction(x, 5, -1), x) == 0 assert singularityintegrate(SingularityFunction(x, 0, -1) * f(x), x) == f(0) * SingularityFunction(x, 0, 0) assert singularityintegrate(SingularityFunction(x, 1, -1) * f(x), x) == f(1) * SingularityFunction(x, 1, 0) assert singularityintegrate(y*SingularityFunction(x, 0, -1)**2, x) == \ y*SingularityFunction(0, 0, -1)*SingularityFunction(x, 0, 0) sympy-sympy-1.9/sympy/integrals/tests/test_transforms.py000066400000000000000000001124551412543434000240550ustar00rootroot00000000000000from sympy.integrals.transforms import (mellin_transform, inverse_mellin_transform, laplace_transform, inverse_laplace_transform, fourier_transform, inverse_fourier_transform, sine_transform, inverse_sine_transform, cosine_transform, inverse_cosine_transform, hankel_transform, inverse_hankel_transform, LaplaceTransform, FourierTransform, SineTransform, CosineTransform, InverseLaplaceTransform, InverseFourierTransform, InverseSineTransform, InverseCosineTransform, IntegralTransformError) from sympy import ( gamma, exp, oo, Heaviside, symbols, Symbol, re, factorial, pi, arg, cos, S, Abs, And, sin, sqrt, I, log, tan, hyperexpand, meijerg, EulerGamma, erf, erfc, besselj, bessely, besseli, besselk, exp_polar, unpolarify, Function, expint, expand_mul, Rational, gammasimp, trigsimp, atan, sinh, cosh, Ne, periodic_argument, atan2) from sympy.testing.pytest import XFAIL, slow, skip, raises, warns_deprecated_sympy from sympy.matrices import Matrix, eye from sympy.abc import x, s, a, b, c, d nu, beta, rho = symbols('nu beta rho') def test_undefined_function(): from sympy import Function, MellinTransform f = Function('f') assert mellin_transform(f(x), x, s) == MellinTransform(f(x), x, s) assert mellin_transform(f(x) + exp(-x), x, s) == \ (MellinTransform(f(x), x, s) + gamma(s), (0, oo), True) assert laplace_transform(2*f(x), x, s) == 2*LaplaceTransform(f(x), x, s) # TODO test derivative and other rules when implemented def test_free_symbols(): from sympy import Function f = Function('f') assert mellin_transform(f(x), x, s).free_symbols == {s} assert mellin_transform(f(x)*a, x, s).free_symbols == {s, a} def test_as_integral(): from sympy import Function, Integral f = Function('f') assert mellin_transform(f(x), x, s).rewrite('Integral') == \ Integral(x**(s - 1)*f(x), (x, 0, oo)) assert fourier_transform(f(x), x, s).rewrite('Integral') == \ Integral(f(x)*exp(-2*I*pi*s*x), (x, -oo, oo)) assert laplace_transform(f(x), x, s).rewrite('Integral') == \ Integral(f(x)*exp(-s*x), (x, 0, oo)) assert str(2*pi*I*inverse_mellin_transform(f(s), s, x, (a, b)).rewrite('Integral')) \ == "Integral(f(s)/x**s, (s, _c - oo*I, _c + oo*I))" assert str(2*pi*I*inverse_laplace_transform(f(s), s, x).rewrite('Integral')) == \ "Integral(f(s)*exp(s*x), (s, _c - oo*I, _c + oo*I))" assert inverse_fourier_transform(f(s), s, x).rewrite('Integral') == \ Integral(f(s)*exp(2*I*pi*s*x), (s, -oo, oo)) # NOTE this is stuck in risch because meijerint cannot handle it @slow @XFAIL def test_mellin_transform_fail(): skip("Risch takes forever.") MT = mellin_transform bpos = symbols('b', positive=True) # bneg = symbols('b', negative=True) expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2) # TODO does not work with bneg, argument wrong. Needs changes to matching. assert MT(expr.subs(b, -bpos), x, s) == \ ((-1)**(a + 1)*2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(a + s) *gamma(1 - a - 2*s)/gamma(1 - s), (-re(a), -re(a)/2 + S.Half), True) expr = (sqrt(x + b**2) + b)**a assert MT(expr.subs(b, -bpos), x, s) == \ ( 2**(a + 2*s)*a*bpos**(a + 2*s)*gamma(-a - 2* s)*gamma(a + s)/gamma(-s + 1), (-re(a), -re(a)/2), True) # Test exponent 1: assert MT(expr.subs({b: -bpos, a: 1}), x, s) == \ (-bpos**(2*s + 1)*gamma(s)*gamma(-s - S.Half)/(2*sqrt(pi)), (-1, Rational(-1, 2)), True) def test_mellin_transform(): from sympy import Max, Min MT = mellin_transform bpos = symbols('b', positive=True) # 8.4.2 assert MT(x**nu*Heaviside(x - 1), x, s) == \ (-1/(nu + s), (-oo, -re(nu)), True) assert MT(x**nu*Heaviside(1 - x), x, s) == \ (1/(nu + s), (-re(nu), oo), True) assert MT((1 - x)**(beta - 1)*Heaviside(1 - x), x, s) == \ (gamma(beta)*gamma(s)/gamma(beta + s), (0, oo), re(beta) > 0) assert MT((x - 1)**(beta - 1)*Heaviside(x - 1), x, s) == \ (gamma(beta)*gamma(1 - beta - s)/gamma(1 - s), (-oo, -re(beta) + 1), re(beta) > 0) assert MT((1 + x)**(-rho), x, s) == \ (gamma(s)*gamma(rho - s)/gamma(rho), (0, re(rho)), True) # TODO also the conditions should be simplified, e.g. # And(re(rho) - 1 < 0, re(rho) < 1) should just be # re(rho) < 1 assert MT(abs(1 - x)**(-rho), x, s) == ( 2*sin(pi*rho/2)*gamma(1 - rho)* cos(pi*(rho/2 - s))*gamma(s)*gamma(rho-s)/pi, (0, re(rho)), And(re(rho) - 1 < 0, re(rho) < 1)) mt = MT((1 - x)**(beta - 1)*Heaviside(1 - x) + a*(x - 1)**(beta - 1)*Heaviside(x - 1), x, s) assert mt[1], mt[2] == ((0, -re(beta) + 1), re(beta) > 0) assert MT((x**a - b**a)/(x - b), x, s)[0] == \ pi*b**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))) assert MT((x**a - bpos**a)/(x - bpos), x, s) == \ (pi*bpos**(a + s - 1)*sin(pi*a)/(sin(pi*s)*sin(pi*(a + s))), (Max(-re(a), 0), Min(1 - re(a), 1)), True) expr = (sqrt(x + b**2) + b)**a assert MT(expr.subs(b, bpos), x, s) == \ (-a*(2*bpos)**(a + 2*s)*gamma(s)*gamma(-a - 2*s)/gamma(-a - s + 1), (0, -re(a)/2), True) expr = (sqrt(x + b**2) + b)**a/sqrt(x + b**2) assert MT(expr.subs(b, bpos), x, s) == \ (2**(a + 2*s)*bpos**(a + 2*s - 1)*gamma(s) *gamma(1 - a - 2*s)/gamma(1 - a - s), (0, -re(a)/2 + S.Half), True) # 8.4.2 assert MT(exp(-x), x, s) == (gamma(s), (0, oo), True) assert MT(exp(-1/x), x, s) == (gamma(-s), (-oo, 0), True) # 8.4.5 assert MT(log(x)**4*Heaviside(1 - x), x, s) == (24/s**5, (0, oo), True) assert MT(log(x)**3*Heaviside(x - 1), x, s) == (6/s**4, (-oo, 0), True) assert MT(log(x + 1), x, s) == (pi/(s*sin(pi*s)), (-1, 0), True) assert MT(log(1/x + 1), x, s) == (pi/(s*sin(pi*s)), (0, 1), True) assert MT(log(abs(1 - x)), x, s) == (pi/(s*tan(pi*s)), (-1, 0), True) assert MT(log(abs(1 - 1/x)), x, s) == (pi/(s*tan(pi*s)), (0, 1), True) # 8.4.14 assert MT(erf(sqrt(x)), x, s) == \ (-gamma(s + S.Half)/(sqrt(pi)*s), (Rational(-1, 2), 0), True) def test_mellin_transform2(): MT = mellin_transform # TODO we cannot currently do these (needs summation of 3F2(-1)) # this also implies that they cannot be written as a single g-function # (although this is possible) mt = MT(log(x)/(x + 1), x, s) assert mt[1:] == ((0, 1), True) assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg) mt = MT(log(x)**2/(x + 1), x, s) assert mt[1:] == ((0, 1), True) assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg) mt = MT(log(x)/(x + 1)**2, x, s) assert mt[1:] == ((0, 2), True) assert not hyperexpand(mt[0], allow_hyper=True).has(meijerg) @slow def test_mellin_transform_bessel(): from sympy import Max MT = mellin_transform # 8.4.19 assert MT(besselj(a, 2*sqrt(x)), x, s) == \ (gamma(a/2 + s)/gamma(a/2 - s + 1), (-re(a)/2, Rational(3, 4)), True) assert MT(sin(sqrt(x))*besselj(a, sqrt(x)), x, s) == \ (2**a*gamma(-2*s + S.Half)*gamma(a/2 + s + S.Half)/( gamma(-a/2 - s + 1)*gamma(a - 2*s + 1)), ( -re(a)/2 - S.Half, Rational(1, 4)), True) assert MT(cos(sqrt(x))*besselj(a, sqrt(x)), x, s) == \ (2**a*gamma(a/2 + s)*gamma(-2*s + S.Half)/( gamma(-a/2 - s + S.Half)*gamma(a - 2*s + 1)), ( -re(a)/2, Rational(1, 4)), True) assert MT(besselj(a, sqrt(x))**2, x, s) == \ (gamma(a + s)*gamma(S.Half - s) / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)), (-re(a), S.Half), True) assert MT(besselj(a, sqrt(x))*besselj(-a, sqrt(x)), x, s) == \ (gamma(s)*gamma(S.Half - s) / (sqrt(pi)*gamma(1 - a - s)*gamma(1 + a - s)), (0, S.Half), True) # NOTE: prudnikov gives the strip below as (1/2 - re(a), 1). As far as # I can see this is wrong (since besselj(z) ~ 1/sqrt(z) for z large) assert MT(besselj(a - 1, sqrt(x))*besselj(a, sqrt(x)), x, s) == \ (gamma(1 - s)*gamma(a + s - S.Half) / (sqrt(pi)*gamma(Rational(3, 2) - s)*gamma(a - s + S.Half)), (S.Half - re(a), S.Half), True) assert MT(besselj(a, sqrt(x))*besselj(b, sqrt(x)), x, s) == \ (4**s*gamma(1 - 2*s)*gamma((a + b)/2 + s) / (gamma(1 - s + (b - a)/2)*gamma(1 - s + (a - b)/2) *gamma( 1 - s + (a + b)/2)), (-(re(a) + re(b))/2, S.Half), True) assert MT(besselj(a, sqrt(x))**2 + besselj(-a, sqrt(x))**2, x, s)[1:] == \ ((Max(re(a), -re(a)), S.Half), True) # Section 8.4.20 assert MT(bessely(a, 2*sqrt(x)), x, s) == \ (-cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)/pi, (Max(-re(a)/2, re(a)/2), Rational(3, 4)), True) assert MT(sin(sqrt(x))*bessely(a, sqrt(x)), x, s) == \ (-4**s*sin(pi*(a/2 - s))*gamma(S.Half - 2*s) * gamma((1 - a)/2 + s)*gamma((1 + a)/2 + s) / (sqrt(pi)*gamma(1 - s - a/2)*gamma(1 - s + a/2)), (Max(-(re(a) + 1)/2, (re(a) - 1)/2), Rational(1, 4)), True) assert MT(cos(sqrt(x))*bessely(a, sqrt(x)), x, s) == \ (-4**s*cos(pi*(a/2 - s))*gamma(s - a/2)*gamma(s + a/2)*gamma(S.Half - 2*s) / (sqrt(pi)*gamma(S.Half - s - a/2)*gamma(S.Half - s + a/2)), (Max(-re(a)/2, re(a)/2), Rational(1, 4)), True) assert MT(besselj(a, sqrt(x))*bessely(a, sqrt(x)), x, s) == \ (-cos(pi*s)*gamma(s)*gamma(a + s)*gamma(S.Half - s) / (pi**S('3/2')*gamma(1 + a - s)), (Max(-re(a), 0), S.Half), True) assert MT(besselj(a, sqrt(x))*bessely(b, sqrt(x)), x, s) == \ (-4**s*cos(pi*(a/2 - b/2 + s))*gamma(1 - 2*s) * gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) / (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)), (Max((-re(a) + re(b))/2, (-re(a) - re(b))/2), S.Half), True) # NOTE bessely(a, sqrt(x))**2 and bessely(a, sqrt(x))*bessely(b, sqrt(x)) # are a mess (no matter what way you look at it ...) assert MT(bessely(a, sqrt(x))**2, x, s)[1:] == \ ((Max(-re(a), 0, re(a)), S.Half), True) # Section 8.4.22 # TODO we can't do any of these (delicate cancellation) # Section 8.4.23 assert MT(besselk(a, 2*sqrt(x)), x, s) == \ (gamma( s - a/2)*gamma(s + a/2)/2, (Max(-re(a)/2, re(a)/2), oo), True) assert MT(besselj(a, 2*sqrt(2*sqrt(x)))*besselk( a, 2*sqrt(2*sqrt(x))), x, s) == (4**(-s)*gamma(2*s)* gamma(a/2 + s)/(2*gamma(a/2 - s + 1)), (Max(0, -re(a)/2), oo), True) # TODO bessely(a, x)*besselk(a, x) is a mess assert MT(besseli(a, sqrt(x))*besselk(a, sqrt(x)), x, s) == \ (gamma(s)*gamma( a + s)*gamma(-s + S.Half)/(2*sqrt(pi)*gamma(a - s + 1)), (Max(-re(a), 0), S.Half), True) assert MT(besseli(b, sqrt(x))*besselk(a, sqrt(x)), x, s) == \ (2**(2*s - 1)*gamma(-2*s + 1)*gamma(-a/2 + b/2 + s)* \ gamma(a/2 + b/2 + s)/(gamma(-a/2 + b/2 - s + 1)* \ gamma(a/2 + b/2 - s + 1)), (Max(-re(a)/2 - re(b)/2, \ re(a)/2 - re(b)/2), S.Half), True) # TODO products of besselk are a mess mt = MT(exp(-x/2)*besselk(a, x/2), x, s) mt0 = gammasimp(trigsimp(gammasimp(mt[0].expand(func=True)))) assert mt0 == 2*pi**Rational(3, 2)*cos(pi*s)*gamma(-s + S.Half)/( (cos(2*pi*a) - cos(2*pi*s))*gamma(-a - s + 1)*gamma(a - s + 1)) assert mt[1:] == ((Max(-re(a), re(a)), oo), True) # TODO exp(x/2)*besselk(a, x/2) [etc] cannot currently be done # TODO various strange products of special orders @slow def test_expint(): from sympy import E1, expint, Max, re, lerchphi, Symbol, simplify, Si, Ci, Ei aneg = Symbol('a', negative=True) u = Symbol('u', polar=True) assert mellin_transform(E1(x), x, s) == (gamma(s)/s, (0, oo), True) assert inverse_mellin_transform(gamma(s)/s, s, x, (0, oo)).rewrite(expint).expand() == E1(x) assert mellin_transform(expint(a, x), x, s) == \ (gamma(s)/(a + s - 1), (Max(1 - re(a), 0), oo), True) # XXX IMT has hickups with complicated strips ... assert simplify(unpolarify( inverse_mellin_transform(gamma(s)/(aneg + s - 1), s, x, (1 - aneg, oo)).rewrite(expint).expand(func=True))) == \ expint(aneg, x) assert mellin_transform(Si(x), x, s) == \ (-2**s*sqrt(pi)*gamma(s/2 + S.Half)/( 2*s*gamma(-s/2 + 1)), (-1, 0), True) assert inverse_mellin_transform(-2**s*sqrt(pi)*gamma((s + 1)/2) /(2*s*gamma(-s/2 + 1)), s, x, (-1, 0)) \ == Si(x) assert mellin_transform(Ci(sqrt(x)), x, s) == \ (-2**(2*s - 1)*sqrt(pi)*gamma(s)/(s*gamma(-s + S.Half)), (0, 1), True) assert inverse_mellin_transform( -4**s*sqrt(pi)*gamma(s)/(2*s*gamma(-s + S.Half)), s, u, (0, 1)).expand() == Ci(sqrt(u)) # TODO LT of Si, Shi, Chi is a mess ... assert laplace_transform(Ci(x), x, s) == (-log(1 + s**2)/2/s, 0, True) assert laplace_transform(expint(a, x), x, s) == \ (lerchphi(s*exp_polar(I*pi), 1, a), 0, re(a) > S.Zero) assert laplace_transform(expint(1, x), x, s) == (log(s + 1)/s, 0, True) assert laplace_transform(expint(2, x), x, s) == \ ((s - log(s + 1))/s**2, 0, True) assert inverse_laplace_transform(-log(1 + s**2)/2/s, s, u).expand() == \ Heaviside(u)*Ci(u) assert inverse_laplace_transform(log(s + 1)/s, s, x).rewrite(expint) == \ Heaviside(x)*E1(x) assert inverse_laplace_transform((s - log(s + 1))/s**2, s, x).rewrite(expint).expand() == \ (expint(2, x)*Heaviside(x)).rewrite(Ei).rewrite(expint).expand() @slow def test_inverse_mellin_transform(): from sympy import (sin, simplify, Max, Min, expand, powsimp, exp_polar, cos, cot) IMT = inverse_mellin_transform assert IMT(gamma(s), s, x, (0, oo)) == exp(-x) assert IMT(gamma(-s), s, x, (-oo, 0)) == exp(-1/x) assert simplify(IMT(s/(2*s**2 - 2), s, x, (2, oo))) == \ (x**2 + 1)*Heaviside(1 - x)/(4*x) # test passing "None" assert IMT(1/(s**2 - 1), s, x, (-1, None)) == \ -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x) assert IMT(1/(s**2 - 1), s, x, (None, 1)) == \ -x*Heaviside(-x + 1)/2 - Heaviside(x - 1)/(2*x) # test expansion of sums assert IMT(gamma(s) + gamma(s - 1), s, x, (1, oo)) == (x + 1)*exp(-x)/x # test factorisation of polys r = symbols('r', real=True) assert IMT(1/(s**2 + 1), s, exp(-x), (None, oo) ).subs(x, r).rewrite(sin).simplify() \ == sin(r)*Heaviside(1 - exp(-r)) # test multiplicative substitution _a, _b = symbols('a b', positive=True) assert IMT(_b**(-s/_a)*factorial(s/_a)/s, s, x, (0, oo)) == exp(-_b*x**_a) assert IMT(factorial(_a/_b + s/_b)/(_a + s), s, x, (-_a, oo)) == x**_a*exp(-x**_b) def simp_pows(expr): return simplify(powsimp(expand_mul(expr, deep=False), force=True)).replace(exp_polar, exp) # Now test the inverses of all direct transforms tested above # Section 8.4.2 nu = symbols('nu', real=True) assert IMT(-1/(nu + s), s, x, (-oo, None)) == x**nu*Heaviside(x - 1) assert IMT(1/(nu + s), s, x, (None, oo)) == x**nu*Heaviside(1 - x) assert simp_pows(IMT(gamma(beta)*gamma(s)/gamma(s + beta), s, x, (0, oo))) \ == (1 - x)**(beta - 1)*Heaviside(1 - x) assert simp_pows(IMT(gamma(beta)*gamma(1 - beta - s)/gamma(1 - s), s, x, (-oo, None))) \ == (x - 1)**(beta - 1)*Heaviside(x - 1) assert simp_pows(IMT(gamma(s)*gamma(rho - s)/gamma(rho), s, x, (0, None))) \ == (1/(x + 1))**rho assert simp_pows(IMT(d**c*d**(s - 1)*sin(pi*c) *gamma(s)*gamma(s + c)*gamma(1 - s)*gamma(1 - s - c)/pi, s, x, (Max(-re(c), 0), Min(1 - re(c), 1)))) \ == (x**c - d**c)/(x - d) assert simplify(IMT(1/sqrt(pi)*(-c/2)*gamma(s)*gamma((1 - c)/2 - s) *gamma(-c/2 - s)/gamma(1 - c - s), s, x, (0, -re(c)/2))) == \ (1 + sqrt(x + 1))**c assert simplify(IMT(2**(a + 2*s)*b**(a + 2*s - 1)*gamma(s)*gamma(1 - a - 2*s) /gamma(1 - a - s), s, x, (0, (-re(a) + 1)/2))) == \ b**(a - 1)*(sqrt(1 + x/b**2) + 1)**(a - 1)*(b**2*sqrt(1 + x/b**2) + b**2 + x)/(b**2 + x) assert simplify(IMT(-2**(c + 2*s)*c*b**(c + 2*s)*gamma(s)*gamma(-c - 2*s) / gamma(-c - s + 1), s, x, (0, -re(c)/2))) == \ b**c*(sqrt(1 + x/b**2) + 1)**c # Section 8.4.5 assert IMT(24/s**5, s, x, (0, oo)) == log(x)**4*Heaviside(1 - x) assert expand(IMT(6/s**4, s, x, (-oo, 0)), force=True) == \ log(x)**3*Heaviside(x - 1) assert IMT(pi/(s*sin(pi*s)), s, x, (-1, 0)) == log(x + 1) assert IMT(pi/(s*sin(pi*s/2)), s, x, (-2, 0)) == log(x**2 + 1) assert IMT(pi/(s*sin(2*pi*s)), s, x, (Rational(-1, 2), 0)) == log(sqrt(x) + 1) assert IMT(pi/(s*sin(pi*s)), s, x, (0, 1)) == log(1 + 1/x) # TODO def mysimp(expr): from sympy import expand, logcombine, powsimp return expand( powsimp(logcombine(expr, force=True), force=True, deep=True), force=True).replace(exp_polar, exp) assert mysimp(mysimp(IMT(pi/(s*tan(pi*s)), s, x, (-1, 0)))) in [ log(1 - x)*Heaviside(1 - x) + log(x - 1)*Heaviside(x - 1), log(x)*Heaviside(x - 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x + 1)*Heaviside(-x + 1)] # test passing cot assert mysimp(IMT(pi*cot(pi*s)/s, s, x, (0, 1))) in [ log(1/x - 1)*Heaviside(1 - x) + log(1 - 1/x)*Heaviside(x - 1), -log(x)*Heaviside(-x + 1) + log(1 - 1/x)*Heaviside(x - 1) + log(-x + 1)*Heaviside(-x + 1), ] # 8.4.14 assert IMT(-gamma(s + S.Half)/(sqrt(pi)*s), s, x, (Rational(-1, 2), 0)) == \ erf(sqrt(x)) # 8.4.19 assert simplify(IMT(gamma(a/2 + s)/gamma(a/2 - s + 1), s, x, (-re(a)/2, Rational(3, 4)))) \ == besselj(a, 2*sqrt(x)) assert simplify(IMT(2**a*gamma(S.Half - 2*s)*gamma(s + (a + 1)/2) / (gamma(1 - s - a/2)*gamma(1 - 2*s + a)), s, x, (-(re(a) + 1)/2, Rational(1, 4)))) == \ sin(sqrt(x))*besselj(a, sqrt(x)) assert simplify(IMT(2**a*gamma(a/2 + s)*gamma(S.Half - 2*s) / (gamma(S.Half - s - a/2)*gamma(1 - 2*s + a)), s, x, (-re(a)/2, Rational(1, 4)))) == \ cos(sqrt(x))*besselj(a, sqrt(x)) # TODO this comes out as an amazing mess, but simplifies nicely assert simplify(IMT(gamma(a + s)*gamma(S.Half - s) / (sqrt(pi)*gamma(1 - s)*gamma(1 + a - s)), s, x, (-re(a), S.Half))) == \ besselj(a, sqrt(x))**2 assert simplify(IMT(gamma(s)*gamma(S.Half - s) / (sqrt(pi)*gamma(1 - s - a)*gamma(1 + a - s)), s, x, (0, S.Half))) == \ besselj(-a, sqrt(x))*besselj(a, sqrt(x)) assert simplify(IMT(4**s*gamma(-2*s + 1)*gamma(a/2 + b/2 + s) / (gamma(-a/2 + b/2 - s + 1)*gamma(a/2 - b/2 - s + 1) *gamma(a/2 + b/2 - s + 1)), s, x, (-(re(a) + re(b))/2, S.Half))) == \ besselj(a, sqrt(x))*besselj(b, sqrt(x)) # Section 8.4.20 # TODO this can be further simplified! assert simplify(IMT(-2**(2*s)*cos(pi*a/2 - pi*b/2 + pi*s)*gamma(-2*s + 1) * gamma(a/2 - b/2 + s)*gamma(a/2 + b/2 + s) / (pi*gamma(a/2 - b/2 - s + 1)*gamma(a/2 + b/2 - s + 1)), s, x, (Max(-re(a)/2 - re(b)/2, -re(a)/2 + re(b)/2), S.Half))) == \ besselj(a, sqrt(x))*-(besselj(-b, sqrt(x)) - besselj(b, sqrt(x))*cos(pi*b))/sin(pi*b) # TODO more # for coverage assert IMT(pi/cos(pi*s), s, x, (0, S.Half)) == sqrt(x)/(x + 1) @slow def test_laplace_transform(): from sympy import fresnels, fresnelc, DiracDelta LT = laplace_transform a, b, c, = symbols('a b c', positive=True) t = symbols('t') w = Symbol("w") f = Function("f") # Test unevaluated form assert laplace_transform(f(t), t, w) == LaplaceTransform(f(t), t, w) assert inverse_laplace_transform( f(w), w, t, plane=0) == InverseLaplaceTransform(f(w), w, t, 0) # test a bug spos = symbols('s', positive=True) assert LT(exp(t), t, spos)[:2] == (1/(spos - 1), 1) # basic tests from wikipedia assert LT((t - a)**b*exp(-c*(t - a))*Heaviside(t - a), t, s) == \ ((s + c)**(-b - 1)*exp(-a*s)*gamma(b + 1), -c, True) assert LT(t**a, t, s) == (s**(-a - 1)*gamma(a + 1), 0, True) assert LT(Heaviside(t), t, s) == (1/s, 0, True) assert LT(Heaviside(t - a), t, s) == (exp(-a*s)/s, 0, True) assert LT(1 - exp(-a*t), t, s) == (a/(s*(a + s)), 0, True) assert LT((exp(2*t) - 1)*exp(-b - t)*Heaviside(t)/2, t, s, noconds=True) \ == exp(-b)/(s**2 - 1) assert LT(exp(t), t, s)[:2] == (1/(s - 1), 1) assert LT(exp(2*t), t, s)[:2] == (1/(s - 2), 2) assert LT(exp(a*t), t, s)[:2] == (1/(s - a), a) assert LT(log(t/a), t, s) == ((log(a*s) + EulerGamma)/s/-1, 0, True) assert LT(erf(t), t, s) == (erfc(s/2)*exp(s**2/4)/s, 0, True) assert LT(sin(a*t), t, s) == (a/(a**2 + s**2), 0, True) assert LT(cos(a*t), t, s) == (s/(a**2 + s**2), 0, True) # TODO would be nice to have these come out better assert LT(exp(-a*t)*sin(b*t), t, s) == (b/(b**2 + (a + s)**2), -a, True) assert LT(exp(-a*t)*cos(b*t), t, s) == \ ((a + s)/(b**2 + (a + s)**2), -a, True) assert LT(besselj(0, t), t, s) == (1/sqrt(1 + s**2), 0, True) assert LT(besselj(1, t), t, s) == (1 - 1/sqrt(1 + 1/s**2), 0, True) # TODO general order works, but is a *mess* # TODO besseli also works, but is an even greater mess # test a bug in conditions processing # TODO the auxiliary condition should be recognised/simplified assert LT(exp(t)*cos(t), t, s)[:-1] in [ ((s - 1)/(s**2 - 2*s + 2), -oo), ((s - 1)/((s - 1)**2 + 1), -oo), ] # DiracDelta function: standard cases assert LT(DiracDelta(t), t, s) == (1, -oo, True) assert LT(DiracDelta(a*t), t, s) == (1/a, -oo, True) assert LT(DiracDelta(t/42), t, s) == (42, -oo, True) assert LT(DiracDelta(t+42), t, s) == (0, -oo, True) assert LT(DiracDelta(t)+DiracDelta(t-42), t, s) == \ (1 + exp(-42*s), -oo, True) assert LT(DiracDelta(t)-a*exp(-a*t), t, s) == (-a/(a + s) + 1, 0, True) assert LT(exp(-t)*(DiracDelta(t)+DiracDelta(t-42)), t, s) == \ (exp(-42*s - 42) + 1, -oo, True) # Collection of cases that cannot be fully evaluated and/or would catch # some common implementation errors assert LT(DiracDelta(t**2), t, s) == LaplaceTransform(DiracDelta(t**2), t, s) assert LT(DiracDelta(t**2 - 1), t, s) == (exp(-s)/2, -oo, True) assert LT(DiracDelta(t*(1 - t)), t, s) == \ LaplaceTransform(DiracDelta(-t**2 + t), t, s) assert LT((DiracDelta(t) + 1)*(DiracDelta(t - 1) + 1), t, s) == \ (LaplaceTransform(DiracDelta(t)*DiracDelta(t - 1), t, s) + \ 1 + exp(-s) + 1/s, 0, True) assert LT(DiracDelta(2*t - 2*exp(a)), t, s) == \ (exp(-s*exp(a))/2, -oo, True) # Fresnel functions assert laplace_transform(fresnels(t), t, s) == \ ((-sin(s**2/(2*pi))*fresnels(s/pi) + sin(s**2/(2*pi))/2 - cos(s**2/(2*pi))*fresnelc(s/pi) + cos(s**2/(2*pi))/2)/s, 0, True) assert laplace_transform(fresnelc(t), t, s) == ( ((2*sin(s**2/(2*pi))*fresnelc(s/pi) - 2*cos(s**2/(2*pi))*fresnels(s/pi) + sqrt(2)*cos(s**2/(2*pi) + pi/4))/(2*s), 0, True)) # What is this testing: Ne(1/s, 1) & (0 < cos(Abs(periodic_argument(s, oo)))*Abs(s) - 1) Mt = Matrix([[exp(t), t*exp(-t)], [t*exp(-t), exp(t)]]) Ms = Matrix([[ 1/(s - 1), (s + 1)**(-2)], [(s + 1)**(-2), 1/(s - 1)]]) # The default behaviour for Laplace tranform of a Matrix returns a Matrix # of Tuples and is deprecated: with warns_deprecated_sympy(): Ms_conds = Matrix([[(1/(s - 1), 1, s > 1), ((s + 1)**(-2), 0, True)], [((s + 1)**(-2), 0, True), (1/(s - 1), 1, s > 1)]]) with warns_deprecated_sympy(): assert LT(Mt, t, s) == Ms_conds # The new behavior is to return a tuple of a Matrix and the convergence # conditions for the matrix as a whole: assert LT(Mt, t, s, legacy_matrix=False) == (Ms, 1, s > 1) # With noconds=True the transformed matrix is returned without conditions # either way: assert LT(Mt, t, s, noconds=True) == Ms assert LT(Mt, t, s, legacy_matrix=False, noconds=True) == Ms @slow def test_issue_8368_7173(): LT = laplace_transform # hyperbolic assert LT(sinh(x), x, s) == (1/(s**2 - 1), 1, s > 1) assert LT(cosh(x), x, s) == (s/(s**2 - 1), 1, s > 1) assert LT(sinh(x + 3), x, s) == ( (-s + (s + 1)*exp(6) + 1)*exp(-3)/(s - 1)/(s + 1)/2, 1, s > 1) assert LT(sinh(x)*cosh(x), x, s) == ( 1/(s**2 - 4), 2, s > 2) # trig (make sure they are not being rewritten in terms of exp) assert LT(cos(x + 3), x, s) == ((s*cos(3) - sin(3))/(s**2 + 1), 0, True) @slow def test_inverse_laplace_transform(): from sympy import sinh, cosh, besselj, besseli, simplify, factor_terms,\ DiracDelta ILT = inverse_laplace_transform a, b, c, = symbols('a b c', positive=True) t = symbols('t') def simp_hyp(expr): return factor_terms(expand_mul(expr)).rewrite(sin) assert ILT(1, s, t) == DiracDelta(t) assert ILT(1/s, s, t) == Heaviside(t) assert ILT(a/(a + s), s, t) == a*exp(-a*t)*Heaviside(t) assert ILT(s/(a + s), s, t) == -a*exp(-a*t)*Heaviside(t) + DiracDelta(t) assert ILT((a + s)**(-2), s, t) == t*exp(-a*t)*Heaviside(t) assert ILT((a + s)**(-5), s, t) == t**4*exp(-a*t)*Heaviside(t)/24 assert ILT(a/(a**2 + s**2), s, t) == sin(a*t)*Heaviside(t) assert ILT(s/(s**2 + a**2), s, t) == cos(a*t)*Heaviside(t) assert ILT(b/(b**2 + (a + s)**2), s, t) == exp(-a*t)*sin(b*t)*Heaviside(t) assert ILT(b*s/(b**2 + (a + s)**2), s, t) +\ (a*sin(b*t) - b*cos(b*t))*exp(-a*t)*Heaviside(t) == 0 assert ILT(exp(-a*s)/s, s, t) == Heaviside(-a + t) assert ILT(exp(-a*s)/(b + s), s, t) == exp(b*(a - t))*Heaviside(-a + t) assert ILT((b + s)/(a**2 + (b + s)**2), s, t) == \ exp(-b*t)*cos(a*t)*Heaviside(t) assert ILT(exp(-a*s)/s**b, s, t) == \ (-a + t)**(b - 1)*Heaviside(-a + t)/gamma(b) assert ILT(exp(-a*s)/sqrt(s**2 + 1), s, t) == \ Heaviside(-a + t)*besselj(0, a - t) assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t)) assert ILT(1/(s**2*(s**2 + 1)), s, t) == (t - sin(t))*Heaviside(t) assert ILT(s**2/(s**2 + 1), s, t) == -sin(t)*Heaviside(t) + DiracDelta(t) assert ILT(1 - 1/(s**2 + 1), s, t) == -sin(t)*Heaviside(t) + DiracDelta(t) assert ILT(1/s**2, s, t) == t*Heaviside(t) assert ILT(1/s**5, s, t) == t**4*Heaviside(t)/24 assert simp_hyp(ILT(a/(s**2 - a**2), s, t)) == sinh(a*t)*Heaviside(t) assert simp_hyp(ILT(s/(s**2 - a**2), s, t)) == cosh(a*t)*Heaviside(t) # TODO sinh/cosh shifted come out a mess. also delayed trig is a mess # TODO should this simplify further? assert ILT(exp(-a*s)/s**b, s, t) == \ (t - a)**(b - 1)*Heaviside(t - a)/gamma(b) assert ILT(exp(-a*s)/sqrt(1 + s**2), s, t) == \ Heaviside(t - a)*besselj(0, a - t) # note: besselj(0, x) is even # XXX ILT turns these branch factor into trig functions ... assert simplify(ILT(a**b*(s + sqrt(s**2 - a**2))**(-b)/sqrt(s**2 - a**2), s, t).rewrite(exp)) == \ Heaviside(t)*besseli(b, a*t) assert ILT(a**b*(s + sqrt(s**2 + a**2))**(-b)/sqrt(s**2 + a**2), s, t).rewrite(exp) == \ Heaviside(t)*besselj(b, a*t) assert ILT(1/(s*sqrt(s + 1)), s, t) == Heaviside(t)*erf(sqrt(t)) # TODO can we make erf(t) work? assert ILT(1/(s**2*(s**2 + 1)),s,t) == (t - sin(t))*Heaviside(t) assert ILT( (s * eye(2) - Matrix([[1, 0], [0, 2]])).inv(), s, t) ==\ Matrix([[exp(t)*Heaviside(t), 0], [0, exp(2*t)*Heaviside(t)]]) def test_inverse_laplace_transform_delta(): from sympy import DiracDelta ILT = inverse_laplace_transform t = symbols('t') assert ILT(2, s, t) == 2*DiracDelta(t) assert ILT(2*exp(3*s) - 5*exp(-7*s), s, t) == \ 2*DiracDelta(t + 3) - 5*DiracDelta(t - 7) a = cos(sin(7)/2) assert ILT(a*exp(-3*s), s, t) == a*DiracDelta(t - 3) assert ILT(exp(2*s), s, t) == DiracDelta(t + 2) r = Symbol('r', real=True) assert ILT(exp(r*s), s, t) == DiracDelta(t + r) def test_inverse_laplace_transform_delta_cond(): from sympy import DiracDelta, Eq, im, Heaviside ILT = inverse_laplace_transform t = symbols('t') r = Symbol('r', real=True) assert ILT(exp(r*s), s, t, noconds=False) == (DiracDelta(t + r), True) z = Symbol('z') assert ILT(exp(z*s), s, t, noconds=False) == \ (DiracDelta(t + z), Eq(im(z), 0)) # inversion does not exist: verify it doesn't evaluate to DiracDelta for z in (Symbol('z', extended_real=False), Symbol('z', imaginary=True, zero=False)): f = ILT(exp(z*s), s, t, noconds=False) f = f[0] if isinstance(f, tuple) else f assert f.func != DiracDelta # issue 15043 assert ILT(1/s + exp(r*s)/s, s, t, noconds=False) == ( Heaviside(t) + Heaviside(r + t), True) def test_fourier_transform(): from sympy import simplify, expand, expand_complex, factor, expand_trig FT = fourier_transform IFT = inverse_fourier_transform def simp(x): return simplify(expand_trig(expand_complex(expand(x)))) def sinc(x): return sin(pi*x)/(pi*x) k = symbols('k', real=True) f = Function("f") # TODO for this to work with real a, need to expand abs(a*x) to abs(a)*abs(x) a = symbols('a', positive=True) b = symbols('b', positive=True) posk = symbols('posk', positive=True) # Test unevaluated form assert fourier_transform(f(x), x, k) == FourierTransform(f(x), x, k) assert inverse_fourier_transform( f(k), k, x) == InverseFourierTransform(f(k), k, x) # basic examples from wikipedia assert simp(FT(Heaviside(1 - abs(2*a*x)), x, k)) == sinc(k/a)/a # TODO IFT is a *mess* assert simp(FT(Heaviside(1 - abs(a*x))*(1 - abs(a*x)), x, k)) == sinc(k/a)**2/a # TODO IFT assert factor(FT(exp(-a*x)*Heaviside(x), x, k), extension=I) == \ 1/(a + 2*pi*I*k) # NOTE: the ift comes out in pieces assert IFT(1/(a + 2*pi*I*x), x, posk, noconds=False) == (exp(-a*posk), True) assert IFT(1/(a + 2*pi*I*x), x, -posk, noconds=False) == (0, True) assert IFT(1/(a + 2*pi*I*x), x, symbols('k', negative=True), noconds=False) == (0, True) # TODO IFT without factoring comes out as meijer g assert factor(FT(x*exp(-a*x)*Heaviside(x), x, k), extension=I) == \ 1/(a + 2*pi*I*k)**2 assert FT(exp(-a*x)*sin(b*x)*Heaviside(x), x, k) == \ b/(b**2 + (a + 2*I*pi*k)**2) assert FT(exp(-a*x**2), x, k) == sqrt(pi)*exp(-pi**2*k**2/a)/sqrt(a) assert IFT(sqrt(pi/a)*exp(-(pi*k)**2/a), k, x) == exp(-a*x**2) assert FT(exp(-a*abs(x)), x, k) == 2*a/(a**2 + 4*pi**2*k**2) # TODO IFT (comes out as meijer G) # TODO besselj(n, x), n an integer > 0 actually can be done... # TODO are there other common transforms (no distributions!)? def test_sine_transform(): from sympy import EulerGamma t = symbols("t") w = symbols("w") a = symbols("a") f = Function("f") # Test unevaluated form assert sine_transform(f(t), t, w) == SineTransform(f(t), t, w) assert inverse_sine_transform( f(w), w, t) == InverseSineTransform(f(w), w, t) assert sine_transform(1/sqrt(t), t, w) == 1/sqrt(w) assert inverse_sine_transform(1/sqrt(w), w, t) == 1/sqrt(t) assert sine_transform((1/sqrt(t))**3, t, w) == 2*sqrt(w) assert sine_transform(t**(-a), t, w) == 2**( -a + S.Half)*w**(a - 1)*gamma(-a/2 + 1)/gamma((a + 1)/2) assert inverse_sine_transform(2**(-a + S( 1)/2)*w**(a - 1)*gamma(-a/2 + 1)/gamma(a/2 + S.Half), w, t) == t**(-a) assert sine_transform( exp(-a*t), t, w) == sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)) assert inverse_sine_transform( sqrt(2)*w/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t) assert sine_transform( log(t)/t, t, w) == -sqrt(2)*sqrt(pi)*(log(w**2) + 2*EulerGamma)/4 assert sine_transform( t*exp(-a*t**2), t, w) == sqrt(2)*w*exp(-w**2/(4*a))/(4*a**Rational(3, 2)) assert inverse_sine_transform( sqrt(2)*w*exp(-w**2/(4*a))/(4*a**Rational(3, 2)), w, t) == t*exp(-a*t**2) def test_cosine_transform(): from sympy import Si, Ci t = symbols("t") w = symbols("w") a = symbols("a") f = Function("f") # Test unevaluated form assert cosine_transform(f(t), t, w) == CosineTransform(f(t), t, w) assert inverse_cosine_transform( f(w), w, t) == InverseCosineTransform(f(w), w, t) assert cosine_transform(1/sqrt(t), t, w) == 1/sqrt(w) assert inverse_cosine_transform(1/sqrt(w), w, t) == 1/sqrt(t) assert cosine_transform(1/( a**2 + t**2), t, w) == sqrt(2)*sqrt(pi)*exp(-a*w)/(2*a) assert cosine_transform(t**( -a), t, w) == 2**(-a + S.Half)*w**(a - 1)*gamma((-a + 1)/2)/gamma(a/2) assert inverse_cosine_transform(2**(-a + S( 1)/2)*w**(a - 1)*gamma(-a/2 + S.Half)/gamma(a/2), w, t) == t**(-a) assert cosine_transform( exp(-a*t), t, w) == sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)) assert inverse_cosine_transform( sqrt(2)*a/(sqrt(pi)*(a**2 + w**2)), w, t) == exp(-a*t) assert cosine_transform(exp(-a*sqrt(t))*cos(a*sqrt( t)), t, w) == a*exp(-a**2/(2*w))/(2*w**Rational(3, 2)) assert cosine_transform(1/(a + t), t, w) == sqrt(2)*( (-2*Si(a*w) + pi)*sin(a*w)/2 - cos(a*w)*Ci(a*w))/sqrt(pi) assert inverse_cosine_transform(sqrt(2)*meijerg(((S.Half, 0), ()), ( (S.Half, 0, 0), (S.Half,)), a**2*w**2/4)/(2*pi), w, t) == 1/(a + t) assert cosine_transform(1/sqrt(a**2 + t**2), t, w) == sqrt(2)*meijerg( ((S.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi)) assert inverse_cosine_transform(sqrt(2)*meijerg(((S.Half,), ()), ((0, 0), (S.Half,)), a**2*w**2/4)/(2*sqrt(pi)), w, t) == 1/(t*sqrt(a**2/t**2 + 1)) def test_hankel_transform(): from sympy import gamma, sqrt, exp r = Symbol("r") k = Symbol("k") nu = Symbol("nu") m = Symbol("m") a = symbols("a") assert hankel_transform(1/r, r, k, 0) == 1/k assert inverse_hankel_transform(1/k, k, r, 0) == 1/r assert hankel_transform( 1/r**m, r, k, 0) == 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2) assert inverse_hankel_transform( 2**(-m + 1)*k**(m - 2)*gamma(-m/2 + 1)/gamma(m/2), k, r, 0) == r**(-m) assert hankel_transform(1/r**m, r, k, nu) == ( 2*2**(-m)*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2)) assert inverse_hankel_transform(2**(-m + 1)*k**( m - 2)*gamma(-m/2 + nu/2 + 1)/gamma(m/2 + nu/2), k, r, nu) == r**(-m) assert hankel_transform(r**nu*exp(-a*r), r, k, nu) == \ 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - S( 3)/2)*gamma(nu + Rational(3, 2))/sqrt(pi) assert inverse_hankel_transform( 2**(nu + 1)*a*k**(-nu - 3)*(a**2/k**2 + 1)**(-nu - Rational(3, 2))*gamma( nu + Rational(3, 2))/sqrt(pi), k, r, nu) == r**nu*exp(-a*r) def test_issue_7181(): assert mellin_transform(1/(1 - x), x, s) != None def test_issue_8882(): # This is the original test. # from sympy import diff, Integral, integrate # r = Symbol('r') # psi = 1/r*sin(r)*exp(-(a0*r)) # h = -1/2*diff(psi, r, r) - 1/r*psi # f = 4*pi*psi*h*r**2 # assert integrate(f, (r, -oo, 3), meijerg=True).has(Integral) == True # To save time, only the critical part is included. F = -a**(-s + 1)*(4 + 1/a**2)**(-s/2)*sqrt(1/a**2)*exp(-s*I*pi)* \ sin(s*atan(sqrt(1/a**2)/2))*gamma(s) raises(IntegralTransformError, lambda: inverse_mellin_transform(F, s, x, (-1, oo), **{'as_meijerg': True, 'needeval': True})) def test_issue_7173(): from sympy import cse x0, x1, x2, x3 = symbols('x:4') ans = laplace_transform(sinh(a*x)*cosh(a*x), x, s) r, e = cse(ans) assert r == [ (x0, arg(a)), (x1, Abs(x0)), (x2, pi/2), (x3, Abs(x0 + pi))] assert e == [ a/(-4*a**2 + s**2), 0, ((x1 <= x2) | (x1 < x2)) & ((x3 <= x2) | (x3 < x2))] def test_issue_8514(): from sympy import simplify a, b, c, = symbols('a b c', positive=True) t = symbols('t', positive=True) ft = simplify(inverse_laplace_transform(1/(a*s**2+b*s+c),s, t)) assert ft == (I*exp(t*cos(atan2(0, -4*a*c + b**2)/2)*sqrt(Abs(4*a*c - b**2))/a)*sin(t*sin(atan2(0, -4*a*c + b**2)/2)*sqrt(Abs( 4*a*c - b**2))/(2*a)) + exp(t*cos(atan2(0, -4*a*c + b**2) /2)*sqrt(Abs(4*a*c - b**2))/a)*cos(t*sin(atan2(0, -4*a*c + b**2)/2)*sqrt(Abs(4*a*c - b**2))/(2*a)) + I*sin(t*sin( atan2(0, -4*a*c + b**2)/2)*sqrt(Abs(4*a*c - b**2))/(2*a)) - cos(t*sin(atan2(0, -4*a*c + b**2)/2)*sqrt(Abs(4*a*c - b**2))/(2*a)))*exp(-t*(b + cos(atan2(0, -4*a*c + b**2)/2) *sqrt(Abs(4*a*c - b**2)))/(2*a))/sqrt(-4*a*c + b**2) def test_issue_12591(): x, y = symbols("x y", real=True) assert fourier_transform(exp(x), x, y) == FourierTransform(exp(x), x, y) def test_issue_14692(): b = Symbol('b', negative=True) assert laplace_transform(1/(I*x - b), x, s) == \ (-I*exp(I*b*s)*expint(1, b*s*exp_polar(I*pi/2)), 0, True) sympy-sympy-1.9/sympy/integrals/tests/test_trigonometry.py000066400000000000000000000074351412543434000244220ustar00rootroot00000000000000from sympy.core import Ne, Rational, Symbol from sympy.functions import sin, cos, tan, csc, sec, cot, log, Piecewise from sympy.integrals.trigonometry import trigintegrate x = Symbol('x') def test_trigintegrate_odd(): assert trigintegrate(Rational(1), x) == x assert trigintegrate(x, x) is None assert trigintegrate(x**2, x) is None assert trigintegrate(sin(x), x) == -cos(x) assert trigintegrate(cos(x), x) == sin(x) assert trigintegrate(sin(3*x), x) == -cos(3*x)/3 assert trigintegrate(cos(3*x), x) == sin(3*x)/3 y = Symbol('y') assert trigintegrate(sin(y*x), x) == Piecewise( (-cos(y*x)/y, Ne(y, 0)), (0, True)) assert trigintegrate(cos(y*x), x) == Piecewise( (sin(y*x)/y, Ne(y, 0)), (x, True)) assert trigintegrate(sin(y*x)**2, x) == Piecewise( ((x*y/2 - sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (0, True)) assert trigintegrate(sin(y*x)*cos(y*x), x) == Piecewise( (sin(x*y)**2/(2*y), Ne(y, 0)), (0, True)) assert trigintegrate(cos(y*x)**2, x) == Piecewise( ((x*y/2 + sin(x*y)*cos(x*y)/2)/y, Ne(y, 0)), (x, True)) y = Symbol('y', positive=True) # TODO: remove conds='none' below. For this to work we would have to rule # out (e.g. by trying solve) the condition y = 0, incompatible with # y.is_positive being True. assert trigintegrate(sin(y*x), x, conds='none') == -cos(y*x)/y assert trigintegrate(cos(y*x), x, conds='none') == sin(y*x)/y assert trigintegrate(sin(x)*cos(x), x) == sin(x)**2/2 assert trigintegrate(sin(x)*cos(x)**2, x) == -cos(x)**3/3 assert trigintegrate(sin(x)**2*cos(x), x) == sin(x)**3/3 # check if it selects right function to substitute, # so the result is kept simple assert trigintegrate(sin(x)**7 * cos(x), x) == sin(x)**8/8 assert trigintegrate(sin(x) * cos(x)**7, x) == -cos(x)**8/8 assert trigintegrate(sin(x)**7 * cos(x)**3, x) == \ -sin(x)**10/10 + sin(x)**8/8 assert trigintegrate(sin(x)**3 * cos(x)**7, x) == \ cos(x)**10/10 - cos(x)**8/8 # both n, m are odd and -ve, and not necessarily equal assert trigintegrate(sin(x)**-1*cos(x)**-1, x) == \ -log(sin(x)**2 - 1)/2 + log(sin(x)) def test_trigintegrate_even(): assert trigintegrate(sin(x)**2, x) == x/2 - cos(x)*sin(x)/2 assert trigintegrate(cos(x)**2, x) == x/2 + cos(x)*sin(x)/2 assert trigintegrate(sin(3*x)**2, x) == x/2 - cos(3*x)*sin(3*x)/6 assert trigintegrate(cos(3*x)**2, x) == x/2 + cos(3*x)*sin(3*x)/6 assert trigintegrate(sin(x)**2 * cos(x)**2, x) == \ x/8 - sin(2*x)*cos(2*x)/16 assert trigintegrate(sin(x)**4 * cos(x)**2, x) == \ x/16 - sin(x) *cos(x)/16 - sin(x)**3*cos(x)/24 + \ sin(x)**5*cos(x)/6 assert trigintegrate(sin(x)**2 * cos(x)**4, x) == \ x/16 + cos(x) *sin(x)/16 + cos(x)**3*sin(x)/24 - \ cos(x)**5*sin(x)/6 assert trigintegrate(sin(x)**(-4), x) == -2*cos(x)/(3*sin(x)) \ - cos(x)/(3*sin(x)**3) assert trigintegrate(cos(x)**(-6), x) == sin(x)/(5*cos(x)**5) \ + 4*sin(x)/(15*cos(x)**3) + 8*sin(x)/(15*cos(x)) def test_trigintegrate_mixed(): assert trigintegrate(sin(x)*sec(x), x) == -log(cos(x)) assert trigintegrate(sin(x)*csc(x), x) == x assert trigintegrate(sin(x)*cot(x), x) == sin(x) assert trigintegrate(cos(x)*sec(x), x) == x assert trigintegrate(cos(x)*csc(x), x) == log(sin(x)) assert trigintegrate(cos(x)*tan(x), x) == -cos(x) assert trigintegrate(cos(x)*cot(x), x) == log(cos(x) - 1)/2 \ - log(cos(x) + 1)/2 + cos(x) assert trigintegrate(cot(x)*cos(x)**2, x) == log(sin(x)) - sin(x)**2/2 def test_trigintegrate_symbolic(): n = Symbol('n', integer=True) assert trigintegrate(cos(x)**n, x) is None assert trigintegrate(sin(x)**n, x) is None assert trigintegrate(cot(x)**n, x) is None sympy-sympy-1.9/sympy/integrals/transforms.py000066400000000000000000002070111412543434000216450ustar00rootroot00000000000000""" Integral Transforms """ from functools import reduce from sympy import (symbols, Wild, RootSum, Lambda, together, exp, gamma) from sympy.core import S from sympy.core.compatibility import iterable, ordered from sympy.core.function import Function from sympy.core.relational import _canonical, Ge, Gt from sympy.core.numbers import oo from sympy.core.symbol import Dummy from sympy.functions import DiracDelta from sympy.functions.elementary.miscellaneous import Max from sympy.integrals import integrate, Integral from sympy.integrals.meijerint import _dummy from sympy.logic.boolalg import to_cnf, conjuncts, disjuncts, Or, And from sympy.simplify import simplify from sympy.utilities import default_sort_key from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.matrices.matrices import MatrixBase from sympy.polys.matrices.linsolve import _lin_eq2dict, PolyNonlinearError ########################################################################## # Helpers / Utilities ########################################################################## class IntegralTransformError(NotImplementedError): """ Exception raised in relation to problems computing transforms. Explanation =========== This class is mostly used internally; if integrals cannot be computed objects representing unevaluated transforms are usually returned. The hint ``needeval=True`` can be used to disable returning transform objects, and instead raise this exception if an integral cannot be computed. """ def __init__(self, transform, function, msg): super().__init__( "%s Transform could not be computed: %s." % (transform, msg)) self.function = function class IntegralTransform(Function): """ Base class for integral transforms. Explanation =========== This class represents unevaluated transforms. To implement a concrete transform, derive from this class and implement the ``_compute_transform(f, x, s, **hints)`` and ``_as_integral(f, x, s)`` functions. If the transform cannot be computed, raise :obj:`IntegralTransformError`. Also set ``cls._name``. For instance, >>> from sympy.integrals.transforms import LaplaceTransform >>> LaplaceTransform._name 'Laplace' Implement ``self._collapse_extra`` if your function returns more than just a number and possibly a convergence condition. """ @property def function(self): """ The function to be transformed. """ return self.args[0] @property def function_variable(self): """ The dependent variable of the function to be transformed. """ return self.args[1] @property def transform_variable(self): """ The independent transform variable. """ return self.args[2] @property def free_symbols(self): """ This method returns the symbols that will exist when the transform is evaluated. """ return self.function.free_symbols.union({self.transform_variable}) \ - {self.function_variable} def _compute_transform(self, f, x, s, **hints): raise NotImplementedError def _as_integral(self, f, x, s): raise NotImplementedError def _collapse_extra(self, extra): cond = And(*extra) if cond == False: raise IntegralTransformError(self.__class__.name, None, '') return cond def doit(self, **hints): """ Try to evaluate the transform in closed form. Explanation =========== This general function handles linearity, but apart from that leaves pretty much everything to _compute_transform. Standard hints are the following: - ``simplify``: whether or not to simplify the result - ``noconds``: if True, don't return convergence conditions - ``needeval``: if True, raise IntegralTransformError instead of returning IntegralTransform objects The default values of these hints depend on the concrete transform, usually the default is ``(simplify, noconds, needeval) = (True, False, False)``. """ from sympy import Add, expand_mul, Mul from sympy.core.function import AppliedUndef needeval = hints.pop('needeval', False) try_directly = not any(func.has(self.function_variable) for func in self.function.atoms(AppliedUndef)) if try_directly: try: return self._compute_transform(self.function, self.function_variable, self.transform_variable, **hints) except IntegralTransformError: pass fn = self.function if not fn.is_Add: fn = expand_mul(fn) if fn.is_Add: hints['needeval'] = needeval res = [self.__class__(*([x] + list(self.args[1:]))).doit(**hints) for x in fn.args] extra = [] ress = [] for x in res: if not isinstance(x, tuple): x = [x] ress.append(x[0]) if len(x) == 2: # only a condition extra.append(x[1]) elif len(x) > 2: # some region parameters and a condition (Mellin, Laplace) extra += [x[1:]] res = Add(*ress) if not extra: return res try: extra = self._collapse_extra(extra) if iterable(extra): return tuple([res]) + tuple(extra) else: return (res, extra) except IntegralTransformError: pass if needeval: raise IntegralTransformError( self.__class__._name, self.function, 'needeval') # TODO handle derivatives etc # pull out constant coefficients coeff, rest = fn.as_coeff_mul(self.function_variable) return coeff*self.__class__(*([Mul(*rest)] + list(self.args[1:]))) @property def as_integral(self): return self._as_integral(self.function, self.function_variable, self.transform_variable) def _eval_rewrite_as_Integral(self, *args, **kwargs): return self.as_integral from sympy.solvers.inequalities import _solve_inequality def _simplify(expr, doit): from sympy import powdenest, piecewise_fold if doit: return simplify(powdenest(piecewise_fold(expr), polar=True)) return expr def _noconds_(default): """ This is a decorator generator for dropping convergence conditions. Explanation =========== Suppose you define a function ``transform(*args)`` which returns a tuple of the form ``(result, cond1, cond2, ...)``. Decorating it ``@_noconds_(default)`` will add a new keyword argument ``noconds`` to it. If ``noconds=True``, the return value will be altered to be only ``result``, whereas if ``noconds=False`` the return value will not be altered. The default value of the ``noconds`` keyword will be ``default`` (i.e. the argument of this function). """ def make_wrapper(func): from sympy.core.decorators import wraps @wraps(func) def wrapper(*args, noconds=default, **kwargs): res = func(*args, **kwargs) if noconds: return res[0] return res return wrapper return make_wrapper _noconds = _noconds_(False) ########################################################################## # Mellin Transform ########################################################################## def _default_integrator(f, x): return integrate(f, (x, 0, oo)) @_noconds def _mellin_transform(f, x, s_, integrator=_default_integrator, simplify=True): """ Backend function to compute Mellin transforms. """ from sympy import re, Max, Min, count_ops # We use a fresh dummy, because assumptions on s might drop conditions on # convergence of the integral. s = _dummy('s', 'mellin-transform', f) F = integrator(x**(s - 1) * f, x) if not F.has(Integral): return _simplify(F.subs(s, s_), simplify), (-oo, oo), S.true if not F.is_Piecewise: # XXX can this work if integration gives continuous result now? raise IntegralTransformError('Mellin', f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError( 'Mellin', f, 'integral in unexpected form') def process_conds(cond): """ Turn ``cond`` into a strip (a, b), and auxiliary conditions. """ a = -oo b = oo aux = S.true conds = conjuncts(to_cnf(cond)) t = Dummy('t', real=True) for c in conds: a_ = oo b_ = -oo aux_ = [] for d in disjuncts(c): d_ = d.replace( re, lambda x: x.as_real_imag()[0]).subs(re(s), t) if not d.is_Relational or \ d.rel_op in ('==', '!=') \ or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ soln.rel_op in ('==', '!='): aux_ += [d] continue if soln.lts == t: b_ = Max(soln.gts, b_) else: a_ = Min(soln.lts, a_) if a_ != oo and a_ != b: a = Max(a_, a) elif b_ != -oo and b_ != a: b = Min(b_, b) else: aux = And(aux, Or(*aux_)) return a, b, aux conds = [process_conds(c) for c in disjuncts(cond)] conds = [x for x in conds if x[2] != False] conds.sort(key=lambda x: (x[0] - x[1], count_ops(x[2]))) if not conds: raise IntegralTransformError('Mellin', f, 'no convergence found') a, b, aux = conds[0] return _simplify(F.subs(s, s_), simplify), (a, b), aux class MellinTransform(IntegralTransform): """ Class representing unevaluated Mellin transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute Mellin transforms, see the :func:`mellin_transform` docstring. """ _name = 'Mellin' def _compute_transform(self, f, x, s, **hints): return _mellin_transform(f, x, s, **hints) def _as_integral(self, f, x, s): return Integral(f*x**(s - 1), (x, 0, oo)) def _collapse_extra(self, extra): from sympy import Max, Min a = [] b = [] cond = [] for (sa, sb), c in extra: a += [sa] b += [sb] cond += [c] res = (Max(*a), Min(*b)), And(*cond) if (res[0][0] >= res[0][1]) == True or res[1] == False: raise IntegralTransformError( 'Mellin', None, 'no combined convergence.') return res def mellin_transform(f, x, s, **hints): r""" Compute the Mellin transform `F(s)` of `f(x)`, .. math :: F(s) = \int_0^\infty x^{s-1} f(x) \mathrm{d}x. For all "sensible" functions, this converges absolutely in a strip `a < \operatorname{Re}(s) < b`. Explanation =========== The Mellin transform is related via change of variables to the Fourier transform, and also to the (bilateral) Laplace transform. This function returns ``(F, (a, b), cond)`` where ``F`` is the Mellin transform of ``f``, ``(a, b)`` is the fundamental strip (as above), and ``cond`` are auxiliary convergence conditions. If the integral cannot be computed in closed form, this function returns an unevaluated :class:`MellinTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. If ``noconds=False``, then only `F` will be returned (i.e. not ``cond``, and also not the strip ``(a, b)``). Examples ======== >>> from sympy.integrals.transforms import mellin_transform >>> from sympy import exp >>> from sympy.abc import x, s >>> mellin_transform(exp(-x), x, s) (gamma(s), (0, oo), True) See Also ======== inverse_mellin_transform, laplace_transform, fourier_transform hankel_transform, inverse_hankel_transform """ return MellinTransform(f, x, s).doit(**hints) def _rewrite_sin(m_n, s, a, b): """ Re-write the sine function ``sin(m*s + n)`` as gamma functions, compatible with the strip (a, b). Return ``(gamma1, gamma2, fac)`` so that ``f == fac/(gamma1 * gamma2)``. Examples ======== >>> from sympy.integrals.transforms import _rewrite_sin >>> from sympy import pi, S >>> from sympy.abc import s >>> _rewrite_sin((pi, 0), s, 0, 1) (gamma(s), gamma(1 - s), pi) >>> _rewrite_sin((pi, 0), s, 1, 0) (gamma(s - 1), gamma(2 - s), -pi) >>> _rewrite_sin((pi, 0), s, -1, 0) (gamma(s + 1), gamma(-s), -pi) >>> _rewrite_sin((pi, pi/2), s, S(1)/2, S(3)/2) (gamma(s - 1/2), gamma(3/2 - s), -pi) >>> _rewrite_sin((pi, pi), s, 0, 1) (gamma(s), gamma(1 - s), -pi) >>> _rewrite_sin((2*pi, 0), s, 0, S(1)/2) (gamma(2*s), gamma(1 - 2*s), pi) >>> _rewrite_sin((2*pi, 0), s, S(1)/2, 1) (gamma(2*s - 1), gamma(2 - 2*s), -pi) """ # (This is a separate function because it is moderately complicated, # and I want to doctest it.) # We want to use pi/sin(pi*x) = gamma(x)*gamma(1-x). # But there is one comlication: the gamma functions determine the # inegration contour in the definition of the G-function. Usually # it would not matter if this is slightly shifted, unless this way # we create an undefined function! # So we try to write this in such a way that the gammas are # eminently on the right side of the strip. from sympy import expand_mul, pi, ceiling, gamma m, n = m_n m = expand_mul(m/pi) n = expand_mul(n/pi) r = ceiling(-m*a - n.as_real_imag()[0]) # Don't use re(n), does not expand return gamma(m*s + n + r), gamma(1 - n - r - m*s), (-1)**r*pi class MellinTransformStripError(ValueError): """ Exception raised by _rewrite_gamma. Mainly for internal use. """ pass def _rewrite_gamma(f, s, a, b): """ Try to rewrite the product f(s) as a product of gamma functions, so that the inverse Mellin transform of f can be expressed as a meijer G function. Explanation =========== Return (an, ap), (bm, bq), arg, exp, fac such that G((an, ap), (bm, bq), arg/z**exp)*fac is the inverse Mellin transform of f(s). Raises IntegralTransformError or MellinTransformStripError on failure. It is asserted that f has no poles in the fundamental strip designated by (a, b). One of a and b is allowed to be None. The fundamental strip is important, because it determines the inversion contour. This function can handle exponentials, linear factors, trigonometric functions. This is a helper function for inverse_mellin_transform that will not attempt any transformations on f. Examples ======== >>> from sympy.integrals.transforms import _rewrite_gamma >>> from sympy.abc import s >>> from sympy import oo >>> _rewrite_gamma(s*(s+3)*(s-1), s, -oo, oo) (([], [-3, 0, 1]), ([-2, 1, 2], []), 1, 1, -1) >>> _rewrite_gamma((s-1)**2, s, -oo, oo) (([], [1, 1]), ([2, 2], []), 1, 1, 1) Importance of the fundamental strip: >>> _rewrite_gamma(1/s, s, 0, oo) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, None, oo) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, 0, None) (([1], []), ([], [0]), 1, 1, 1) >>> _rewrite_gamma(1/s, s, -oo, 0) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(1/s, s, None, 0) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(1/s, s, -oo, None) (([], [1]), ([0], []), 1, 1, -1) >>> _rewrite_gamma(2**(-s+3), s, -oo, oo) (([], []), ([], []), 1/2, 1, 8) """ from itertools import repeat from sympy import (Poly, gamma, Mul, re, CRootOf, exp as exp_, expand, roots, ilcm, pi, sin, cos, tan, cot, igcd, exp_polar) # Our strategy will be as follows: # 1) Guess a constant c such that the inversion integral should be # performed wrt s'=c*s (instead of plain s). Write s for s'. # 2) Process all factors, rewrite them independently as gamma functions in # argument s, or exponentials of s. # 3) Try to transform all gamma functions s.t. they have argument # a+s or a-s. # 4) Check that the resulting G function parameters are valid. # 5) Combine all the exponentials. a_, b_ = S([a, b]) def left(c, is_numer): """ Decide whether pole at c lies to the left of the fundamental strip. """ # heuristically, this is the best chance for us to solve the inequalities c = expand(re(c)) if a_ is None and b_ is oo: return True if a_ is None: return c < b_ if b_ is None: return c <= a_ if (c >= b_) == True: return False if (c <= a_) == True: return True if is_numer: return None if a_.free_symbols or b_.free_symbols or c.free_symbols: return None # XXX #raise IntegralTransformError('Inverse Mellin', f, # 'Could not determine position of singularity %s' # ' relative to fundamental strip' % c) raise MellinTransformStripError('Pole inside critical strip?') # 1) s_multipliers = [] for g in f.atoms(gamma): if not g.has(s): continue arg = g.args[0] if arg.is_Add: arg = arg.as_independent(s)[1] coeff, _ = arg.as_coeff_mul(s) s_multipliers += [coeff] for g in f.atoms(sin, cos, tan, cot): if not g.has(s): continue arg = g.args[0] if arg.is_Add: arg = arg.as_independent(s)[1] coeff, _ = arg.as_coeff_mul(s) s_multipliers += [coeff/pi] s_multipliers = [abs(x) if x.is_extended_real else x for x in s_multipliers] common_coefficient = S.One for x in s_multipliers: if not x.is_Rational: common_coefficient = x break s_multipliers = [x/common_coefficient for x in s_multipliers] if (any(not x.is_Rational for x in s_multipliers) or not common_coefficient.is_extended_real): raise IntegralTransformError("Gamma", None, "Nonrational multiplier") s_multiplier = common_coefficient/reduce(ilcm, [S(x.q) for x in s_multipliers], S.One) if s_multiplier == common_coefficient: if len(s_multipliers) == 0: s_multiplier = common_coefficient else: s_multiplier = common_coefficient \ *reduce(igcd, [S(x.p) for x in s_multipliers]) f = f.subs(s, s/s_multiplier) fac = S.One/s_multiplier exponent = S.One/s_multiplier if a_ is not None: a_ *= s_multiplier if b_ is not None: b_ *= s_multiplier # 2) numer, denom = f.as_numer_denom() numer = Mul.make_args(numer) denom = Mul.make_args(denom) args = list(zip(numer, repeat(True))) + list(zip(denom, repeat(False))) facs = [] dfacs = [] # *_gammas will contain pairs (a, c) representing Gamma(a*s + c) numer_gammas = [] denom_gammas = [] # exponentials will contain bases for exponentials of s exponentials = [] def exception(fact): return IntegralTransformError("Inverse Mellin", f, "Unrecognised form '%s'." % fact) while args: fact, is_numer = args.pop() if is_numer: ugammas, lgammas = numer_gammas, denom_gammas ufacs = facs else: ugammas, lgammas = denom_gammas, numer_gammas ufacs = dfacs def linear_arg(arg): """ Test if arg is of form a*s+b, raise exception if not. """ if not arg.is_polynomial(s): raise exception(fact) p = Poly(arg, s) if p.degree() != 1: raise exception(fact) return p.all_coeffs() # constants if not fact.has(s): ufacs += [fact] # exponentials elif fact.is_Pow or isinstance(fact, exp_): if fact.is_Pow: base = fact.base exp = fact.exp else: base = exp_polar(1) exp = fact.exp if exp.is_Integer: cond = is_numer if exp < 0: cond = not cond args += [(base, cond)]*abs(exp) continue elif not base.has(s): a, b = linear_arg(exp) if not is_numer: base = 1/base exponentials += [base**a] facs += [base**b] else: raise exception(fact) # linear factors elif fact.is_polynomial(s): p = Poly(fact, s) if p.degree() != 1: # We completely factor the poly. For this we need the roots. # Now roots() only works in some cases (low degree), and CRootOf # only works without parameters. So try both... coeff = p.LT()[1] rs = roots(p, s) if len(rs) != p.degree(): rs = CRootOf.all_roots(p) ufacs += [coeff] args += [(s - c, is_numer) for c in rs] continue a, c = p.all_coeffs() ufacs += [a] c /= -a # Now need to convert s - c if left(c, is_numer): ugammas += [(S.One, -c + 1)] lgammas += [(S.One, -c)] else: ufacs += [-1] ugammas += [(S.NegativeOne, c + 1)] lgammas += [(S.NegativeOne, c)] elif isinstance(fact, gamma): a, b = linear_arg(fact.args[0]) if is_numer: if (a > 0 and (left(-b/a, is_numer) == False)) or \ (a < 0 and (left(-b/a, is_numer) == True)): raise NotImplementedError( 'Gammas partially over the strip.') ugammas += [(a, b)] elif isinstance(fact, sin): # We try to re-write all trigs as gammas. This is not in # general the best strategy, since sometimes this is impossible, # but rewriting as exponentials would work. However trig functions # in inverse mellin transforms usually all come from simplifying # gamma terms, so this should work. a = fact.args[0] if is_numer: # No problem with the poles. gamma1, gamma2, fac_ = gamma(a/pi), gamma(1 - a/pi), pi else: gamma1, gamma2, fac_ = _rewrite_sin(linear_arg(a), s, a_, b_) args += [(gamma1, not is_numer), (gamma2, not is_numer)] ufacs += [fac_] elif isinstance(fact, tan): a = fact.args[0] args += [(sin(a, evaluate=False), is_numer), (sin(pi/2 - a, evaluate=False), not is_numer)] elif isinstance(fact, cos): a = fact.args[0] args += [(sin(pi/2 - a, evaluate=False), is_numer)] elif isinstance(fact, cot): a = fact.args[0] args += [(sin(pi/2 - a, evaluate=False), is_numer), (sin(a, evaluate=False), not is_numer)] else: raise exception(fact) fac *= Mul(*facs)/Mul(*dfacs) # 3) an, ap, bm, bq = [], [], [], [] for gammas, plus, minus, is_numer in [(numer_gammas, an, bm, True), (denom_gammas, bq, ap, False)]: while gammas: a, c = gammas.pop() if a != -1 and a != +1: # We use the gamma function multiplication theorem. p = abs(S(a)) newa = a/p newc = c/p if not a.is_Integer: raise TypeError("a is not an integer") for k in range(p): gammas += [(newa, newc + k/p)] if is_numer: fac *= (2*pi)**((1 - p)/2) * p**(c - S.Half) exponentials += [p**a] else: fac /= (2*pi)**((1 - p)/2) * p**(c - S.Half) exponentials += [p**(-a)] continue if a == +1: plus.append(1 - c) else: minus.append(c) # 4) # TODO # 5) arg = Mul(*exponentials) # for testability, sort the arguments an.sort(key=default_sort_key) ap.sort(key=default_sort_key) bm.sort(key=default_sort_key) bq.sort(key=default_sort_key) return (an, ap), (bm, bq), arg, exponent, fac @_noconds_(True) def _inverse_mellin_transform(F, s, x_, strip, as_meijerg=False): """ A helper for the real inverse_mellin_transform function, this one here assumes x to be real and positive. """ from sympy import (expand, expand_mul, hyperexpand, meijerg, arg, pi, re, factor, Heaviside, gamma, Add) x = _dummy('t', 'inverse-mellin-transform', F, positive=True) # Actually, we won't try integration at all. Instead we use the definition # of the Meijer G function as a fairly general inverse mellin transform. F = F.rewrite(gamma) for g in [factor(F), expand_mul(F), expand(F)]: if g.is_Add: # do all terms separately ress = [_inverse_mellin_transform(G, s, x, strip, as_meijerg, noconds=False) for G in g.args] conds = [p[1] for p in ress] ress = [p[0] for p in ress] res = Add(*ress) if not as_meijerg: res = factor(res, gens=res.atoms(Heaviside)) return res.subs(x, x_), And(*conds) try: a, b, C, e, fac = _rewrite_gamma(g, s, strip[0], strip[1]) except IntegralTransformError: continue try: G = meijerg(a, b, C/x**e) except ValueError: continue if as_meijerg: h = G else: try: h = hyperexpand(G) except NotImplementedError: raise IntegralTransformError( 'Inverse Mellin', F, 'Could not calculate integral') if h.is_Piecewise and len(h.args) == 3: # XXX we break modularity here! h = Heaviside(x - abs(C))*h.args[0].args[0] \ + Heaviside(abs(C) - x)*h.args[1].args[0] # We must ensure that the integral along the line we want converges, # and return that value. # See [L], 5.2 cond = [abs(arg(G.argument)) < G.delta*pi] # Note: we allow ">=" here, this corresponds to convergence if we let # limits go to oo symmetrically. ">" corresponds to absolute convergence. cond += [And(Or(len(G.ap) != len(G.bq), 0 >= re(G.nu) + 1), abs(arg(G.argument)) == G.delta*pi)] cond = Or(*cond) if cond == False: raise IntegralTransformError( 'Inverse Mellin', F, 'does not converge') return (h*fac).subs(x, x_), cond raise IntegralTransformError('Inverse Mellin', F, '') _allowed = None class InverseMellinTransform(IntegralTransform): """ Class representing unevaluated inverse Mellin transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute inverse Mellin transforms, see the :func:`inverse_mellin_transform` docstring. """ _name = 'Inverse Mellin' _none_sentinel = Dummy('None') _c = Dummy('c') def __new__(cls, F, s, x, a, b, **opts): if a is None: a = InverseMellinTransform._none_sentinel if b is None: b = InverseMellinTransform._none_sentinel return IntegralTransform.__new__(cls, F, s, x, a, b, **opts) @property def fundamental_strip(self): a, b = self.args[3], self.args[4] if a is InverseMellinTransform._none_sentinel: a = None if b is InverseMellinTransform._none_sentinel: b = None return a, b def _compute_transform(self, F, s, x, **hints): from sympy import postorder_traversal global _allowed if _allowed is None: from sympy import ( exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth, factorial, rf) _allowed = { exp, gamma, sin, cos, tan, cot, cosh, sinh, tanh, coth, factorial, rf} for f in postorder_traversal(F): if f.is_Function and f.has(s) and f.func not in _allowed: raise IntegralTransformError('Inverse Mellin', F, 'Component %s not recognised.' % f) strip = self.fundamental_strip return _inverse_mellin_transform(F, s, x, strip, **hints) def _as_integral(self, F, s, x): from sympy import I c = self.__class__._c return Integral(F*x**(-s), (s, c - I*oo, c + I*oo))/(2*S.Pi*S.ImaginaryUnit) def inverse_mellin_transform(F, s, x, strip, **hints): r""" Compute the inverse Mellin transform of `F(s)` over the fundamental strip given by ``strip=(a, b)``. Explanation =========== This can be defined as .. math:: f(x) = \frac{1}{2\pi i} \int_{c - i\infty}^{c + i\infty} x^{-s} F(s) \mathrm{d}s, for any `c` in the fundamental strip. Under certain regularity conditions on `F` and/or `f`, this recovers `f` from its Mellin transform `F` (and vice versa), for positive real `x`. One of `a` or `b` may be passed as ``None``; a suitable `c` will be inferred. If the integral cannot be computed in closed form, this function returns an unevaluated :class:`InverseMellinTransform` object. Note that this function will assume x to be positive and real, regardless of the sympy assumptions! For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Examples ======== >>> from sympy.integrals.transforms import inverse_mellin_transform >>> from sympy import oo, gamma >>> from sympy.abc import x, s >>> inverse_mellin_transform(gamma(s), s, x, (0, oo)) exp(-x) The fundamental strip matters: >>> f = 1/(s**2 - 1) >>> inverse_mellin_transform(f, s, x, (-oo, -1)) x*(1 - 1/x**2)*Heaviside(x - 1)/2 >>> inverse_mellin_transform(f, s, x, (-1, 1)) -x*Heaviside(1 - x)/2 - Heaviside(x - 1)/(2*x) >>> inverse_mellin_transform(f, s, x, (1, oo)) (1/2 - x**2/2)*Heaviside(1 - x)/x See Also ======== mellin_transform hankel_transform, inverse_hankel_transform """ return InverseMellinTransform(F, s, x, strip[0], strip[1]).doit(**hints) ########################################################################## # Laplace Transform ########################################################################## def _simplifyconds(expr, s, a): r""" Naively simplify some conditions occurring in ``expr``, given that `\operatorname{Re}(s) > a`. Examples ======== >>> from sympy.integrals.transforms import _simplifyconds as simp >>> from sympy.abc import x >>> from sympy import sympify as S >>> simp(abs(x**2) < 1, x, 1) False >>> simp(abs(x**2) < 1, x, 2) False >>> simp(abs(x**2) < 1, x, 0) Abs(x**2) < 1 >>> simp(abs(1/x**2) < 1, x, 1) True >>> simp(S(1) < abs(x), x, 1) True >>> simp(S(1) < abs(1/x), x, 1) False >>> from sympy import Ne >>> simp(Ne(1, x**3), x, 1) True >>> simp(Ne(1, x**3), x, 2) True >>> simp(Ne(1, x**3), x, 0) Ne(1, x**3) """ from sympy.core.relational import ( StrictGreaterThan, StrictLessThan, Unequality ) from sympy import Abs def power(ex): if ex == s: return 1 if ex.is_Pow and ex.base == s: return ex.exp return None def bigger(ex1, ex2): """ Return True only if |ex1| > |ex2|, False only if |ex1| < |ex2|. Else return None. """ if ex1.has(s) and ex2.has(s): return None if isinstance(ex1, Abs): ex1 = ex1.args[0] if isinstance(ex2, Abs): ex2 = ex2.args[0] if ex1.has(s): return bigger(1/ex2, 1/ex1) n = power(ex2) if n is None: return None try: if n > 0 and (abs(ex1) <= abs(a)**n) == True: return False if n < 0 and (abs(ex1) >= abs(a)**n) == True: return True except TypeError: pass def replie(x, y): """ simplify x < y """ if not (x.is_positive or isinstance(x, Abs)) \ or not (y.is_positive or isinstance(y, Abs)): return (x < y) r = bigger(x, y) if r is not None: return not r return (x < y) def replue(x, y): b = bigger(x, y) if b == True or b == False: return True return Unequality(x, y) def repl(ex, *args): if ex == True or ex == False: return bool(ex) return ex.replace(*args) from sympy.simplify.radsimp import collect_abs expr = collect_abs(expr) expr = repl(expr, StrictLessThan, replie) expr = repl(expr, StrictGreaterThan, lambda x, y: replie(y, x)) expr = repl(expr, Unequality, replue) return S(expr) def expand_dirac_delta(expr): """ Expand an expression involving DiractDelta to get it as a linear combination of DiracDelta functions. """ return _lin_eq2dict(expr, expr.atoms(DiracDelta)) @_noconds def _laplace_transform(f, t, s_, simplify=True): """ The backend function for Laplace transforms. """ from sympy import (re, Max, exp, pi, Min, periodic_argument as arg_, arg, cos, Wild, symbols, polar_lift, Add) s = Dummy('s') a = Wild('a', exclude=[t]) deltazero = [] deltanonzero = [] try: integratable, deltadict = expand_dirac_delta(f) except PolyNonlinearError: raise IntegralTransformError( 'Laplace', f, 'could not expand DiracDelta expressions') for dirac_func, dirac_coeff in deltadict.items(): p = dirac_func.match(DiracDelta(a*t)) if p: deltazero.append(dirac_coeff.subs(t,0)/p[a]) else: if dirac_func.args[0].subs(t,0).is_zero: raise IntegralTransformError('Laplace', f,\ 'not implemented yet.') else: deltanonzero.append(dirac_func*dirac_coeff) F = Add(integrate(exp(-s*t) * Add(integratable, *deltanonzero), (t, 0, oo)), Add(*deltazero)) if not F.has(Integral): return _simplify(F.subs(s, s_), simplify), -oo, S.true if not F.is_Piecewise: raise IntegralTransformError( 'Laplace', f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError( 'Laplace', f, 'integral in unexpected form') def process_conds(conds): """ Turn ``conds`` into a strip and auxiliary conditions. """ a = -oo aux = S.true conds = conjuncts(to_cnf(conds)) p, q, w1, w2, w3, w4, w5 = symbols( 'p q w1 w2 w3 w4 w5', cls=Wild, exclude=[s]) patterns = ( p*abs(arg((s + w3)*q)) < w2, p*abs(arg((s + w3)*q)) <= w2, abs(arg_((s + w3)**p*q, w1)) < w2, abs(arg_((s + w3)**p*q, w1)) <= w2, abs(arg_((polar_lift(s + w3))**p*q, w1)) < w2, abs(arg_((polar_lift(s + w3))**p*q, w1)) <= w2) for c in conds: a_ = oo aux_ = [] for d in disjuncts(c): if d.is_Relational and s in d.rhs.free_symbols: d = d.reversed if d.is_Relational and isinstance(d, (Ge, Gt)): d = d.reversedsign for pat in patterns: m = d.match(pat) if m: break if m: if m[q].is_positive and m[w2]/m[p] == pi/2: d = -re(s + m[w3]) < 0 m = d.match(p - cos(w1*abs(arg(s*w5))*w2)*abs(s**w3)**w4 < 0) if not m: m = d.match( cos(p - abs(arg_(s**w1*w5, q))*w2)*abs(s**w3)**w4 < 0) if not m: m = d.match( p - cos(abs(arg_(polar_lift(s)**w1*w5, q))*w2 )*abs(s**w3)**w4 < 0) if m and all(m[wild].is_positive for wild in [w1, w2, w3, w4, w5]): d = re(s) > m[p] d_ = d.replace( re, lambda x: x.expand().as_real_imag()[0]).subs(re(s), t) if not d.is_Relational or \ d.rel_op in ('==', '!=') \ or d_.has(s) or not d_.has(t): aux_ += [d] continue soln = _solve_inequality(d_, t) if not soln.is_Relational or \ soln.rel_op in ('==', '!='): aux_ += [d] continue if soln.lts == t: raise IntegralTransformError('Laplace', f, 'convergence not in half-plane?') else: a_ = Min(soln.lts, a_) if a_ != oo: a = Max(a_, a) else: aux = And(aux, Or(*aux_)) return a, aux.canonical if aux.is_Relational else aux conds = [process_conds(c) for c in disjuncts(cond)] conds2 = [x for x in conds if x[1] != False and x[0] != -oo] if not conds2: conds2 = [x for x in conds if x[1] != False] conds = list(ordered(conds2)) def cnt(expr): if expr == True or expr == False: return 0 return expr.count_ops() conds.sort(key=lambda x: (-x[0], cnt(x[1]))) if not conds: raise IntegralTransformError('Laplace', f, 'no convergence found') a, aux = conds[0] # XXX is [0] always the right one? def sbs(expr): return expr.subs(s, s_) if simplify: F = _simplifyconds(F, s, a) aux = _simplifyconds(aux, s, a) return _simplify(F.subs(s, s_), simplify), sbs(a), _canonical(sbs(aux)) class LaplaceTransform(IntegralTransform): """ Class representing unevaluated Laplace transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute Laplace transforms, see the :func:`laplace_transform` docstring. """ _name = 'Laplace' def _compute_transform(self, f, t, s, **hints): return _laplace_transform(f, t, s, **hints) def _as_integral(self, f, t, s): from sympy import exp return Integral(f*exp(-s*t), (t, 0, oo)) def _collapse_extra(self, extra): from sympy import Max conds = [] planes = [] for plane, cond in extra: conds.append(cond) planes.append(plane) cond = And(*conds) plane = Max(*planes) if cond == False: raise IntegralTransformError( 'Laplace', None, 'No combined convergence.') return plane, cond def laplace_transform(f, t, s, legacy_matrix=True, **hints): r""" Compute the Laplace Transform `F(s)` of `f(t)`, .. math :: F(s) = \int_{0^{-}}^\infty e^{-st} f(t) \mathrm{d}t. Explanation =========== For all sensible functions, this converges absolutely in a half plane `a < \operatorname{Re}(s)`. This function returns ``(F, a, cond)`` where ``F`` is the Laplace transform of ``f``, `\operatorname{Re}(s) > a` is the half-plane of convergence, and ``cond`` are auxiliary convergence conditions. The lower bound is `0^{-}`, meaning that this bound should be approached from the lower side. This is only necessary if distributions are involved. At present, it is only done if `f(t)` contains ``DiracDelta``, in which case the Laplace transform is computed as .. math :: F(s) = \lim_{\tau\to 0^{-}} \int_{\tau}^\infty e^{-st} f(t) \mathrm{d}t. If the integral cannot be computed in closed form, this function returns an unevaluated :class:`LaplaceTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. If ``noconds=True``, only `F` will be returned (i.e. not ``cond``, and also not the plane ``a``). .. deprecated:: 1.9 Legacy behavior for matrices where ``laplace_transform`` with ``noconds=False`` (the default) returns a Matrix whose elements are tuples. The behavior of ``laplace_transform`` for matrices will change in a future release of SymPy to return a tuple of the transformed Matrix and the convergence conditions for the matrix as a whole. Use ``legacy_matrix=False`` to enable the new behavior. Examples ======== >>> from sympy.integrals import laplace_transform >>> from sympy.abc import t, s, a >>> from sympy.functions import DiracDelta, exp >>> laplace_transform(t**a, t, s) (gamma(a + 1)/(s*s**a), 0, re(a) > -1) >>> laplace_transform(DiracDelta(t)-a*exp(-a*t),t,s) (-a/(a + s) + 1, 0, Abs(arg(a)) <= pi/2) See Also ======== inverse_laplace_transform, mellin_transform, fourier_transform hankel_transform, inverse_hankel_transform """ if isinstance(f, MatrixBase) and hasattr(f, 'applyfunc'): conds = not hints.get('noconds', False) if conds and legacy_matrix: SymPyDeprecationWarning( feature="laplace_transform of a Matrix with noconds=False (default)", useinstead="the option legacy_matrix=False to get the new behaviour", issue=21504, deprecated_since_version="1.9" ).warn() return f.applyfunc(lambda fij: laplace_transform(fij, t, s, **hints)) else: elements_trans = [laplace_transform(fij, t, s, **hints) for fij in f] if conds: elements, avals, conditions = zip(*elements_trans) f_laplace = type(f)(*f.shape, elements) return f_laplace, Max(*avals), And(*conditions) else: return type(f)(*f.shape, elements_trans) return LaplaceTransform(f, t, s).doit(**hints) @_noconds_(True) def _inverse_laplace_transform(F, s, t_, plane, simplify=True): """ The backend function for inverse Laplace transforms. """ from sympy import exp, Heaviside, log, expand_complex, Integral,\ Piecewise, Add from sympy.integrals.meijerint import meijerint_inversion, _get_coeff_exp # There are two strategies we can try: # 1) Use inverse mellin transforms - related by a simple change of variables. # 2) Use the inversion integral. t = Dummy('t', real=True) def pw_simp(*args): """ Simplify a piecewise expression from hyperexpand. """ # XXX we break modularity here! if len(args) != 3: return Piecewise(*args) arg = args[2].args[0].argument coeff, exponent = _get_coeff_exp(arg, t) e1 = args[0].args[0] e2 = args[1].args[0] return Heaviside(1/abs(coeff) - t**exponent)*e1 \ + Heaviside(t**exponent - 1/abs(coeff))*e2 if F.is_rational_function(s): F = F.apart(s) if F.is_Add: f = Add(*[_inverse_laplace_transform(X, s, t, plane, simplify)\ for X in F.args]) return _simplify(f.subs(t, t_), simplify), True try: f, cond = inverse_mellin_transform(F, s, exp(-t), (None, oo), needeval=True, noconds=False) except IntegralTransformError: f = None if f is None: f = meijerint_inversion(F, s, t) if f is None: raise IntegralTransformError('Inverse Laplace', f, '') if f.is_Piecewise: f, cond = f.args[0] if f.has(Integral): raise IntegralTransformError('Inverse Laplace', f, 'inversion integral of unrecognised form.') else: cond = S.true f = f.replace(Piecewise, pw_simp) if f.is_Piecewise: # many of the functions called below can't work with piecewise # (b/c it has a bool in args) return f.subs(t, t_), cond u = Dummy('u') def simp_heaviside(arg, H0=S.Half): a = arg.subs(exp(-t), u) if a.has(t): return Heaviside(arg, H0) rel = _solve_inequality(a > 0, u) if rel.lts == u: k = log(rel.gts) return Heaviside(t + k, H0) else: k = log(rel.lts) return Heaviside(-(t + k), H0) f = f.replace(Heaviside, simp_heaviside) def simp_exp(arg): return expand_complex(exp(arg)) f = f.replace(exp, simp_exp) # TODO it would be nice to fix cosh and sinh ... simplify messes these # exponentials up return _simplify(f.subs(t, t_), simplify), cond class InverseLaplaceTransform(IntegralTransform): """ Class representing unevaluated inverse Laplace transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute inverse Laplace transforms, see the :func:`inverse_laplace_transform` docstring. """ _name = 'Inverse Laplace' _none_sentinel = Dummy('None') _c = Dummy('c') def __new__(cls, F, s, x, plane, **opts): if plane is None: plane = InverseLaplaceTransform._none_sentinel return IntegralTransform.__new__(cls, F, s, x, plane, **opts) @property def fundamental_plane(self): plane = self.args[3] if plane is InverseLaplaceTransform._none_sentinel: plane = None return plane def _compute_transform(self, F, s, t, **hints): return _inverse_laplace_transform(F, s, t, self.fundamental_plane, **hints) def _as_integral(self, F, s, t): from sympy import I, exp c = self.__class__._c return Integral(exp(s*t)*F, (s, c - I*oo, c + I*oo))/(2*S.Pi*S.ImaginaryUnit) def inverse_laplace_transform(F, s, t, plane=None, **hints): r""" Compute the inverse Laplace transform of `F(s)`, defined as .. math :: f(t) = \frac{1}{2\pi i} \int_{c-i\infty}^{c+i\infty} e^{st} F(s) \mathrm{d}s, for `c` so large that `F(s)` has no singularites in the half-plane `\operatorname{Re}(s) > c-\epsilon`. Explanation =========== The plane can be specified by argument ``plane``, but will be inferred if passed as None. Under certain regularity conditions, this recovers `f(t)` from its Laplace Transform `F(s)`, for non-negative `t`, and vice versa. If the integral cannot be computed in closed form, this function returns an unevaluated :class:`InverseLaplaceTransform` object. Note that this function will always assume `t` to be real, regardless of the sympy assumption on `t`. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Examples ======== >>> from sympy.integrals.transforms import inverse_laplace_transform >>> from sympy import exp, Symbol >>> from sympy.abc import s, t >>> a = Symbol('a', positive=True) >>> inverse_laplace_transform(exp(-a*s)/s, s, t) Heaviside(-a + t) See Also ======== laplace_transform, _fast_inverse_laplace hankel_transform, inverse_hankel_transform """ if isinstance(F, MatrixBase) and hasattr(F, 'applyfunc'): return F.applyfunc(lambda Fij: inverse_laplace_transform(Fij, s, t, plane, **hints)) return InverseLaplaceTransform(F, s, t, plane).doit(**hints) def _fast_inverse_laplace(e, s, t): """Fast inverse Laplace transform of rational function including RootSum""" a, b, n = symbols('a, b, n', cls=Wild, exclude=[s]) def _ilt(e): if not e.has(s): return e elif e.is_Add: return _ilt_add(e) elif e.is_Mul: return _ilt_mul(e) elif e.is_Pow: return _ilt_pow(e) elif isinstance(e, RootSum): return _ilt_rootsum(e) else: raise NotImplementedError def _ilt_add(e): return e.func(*map(_ilt, e.args)) def _ilt_mul(e): coeff, expr = e.as_independent(s) if expr.is_Mul: raise NotImplementedError return coeff * _ilt(expr) def _ilt_pow(e): match = e.match((a*s + b)**n) if match is not None: nm, am, bm = match[n], match[a], match[b] if nm.is_Integer and nm < 0: return t**(-nm-1)*exp(-(bm/am)*t)/(am**-nm*gamma(-nm)) if nm == 1: return exp(-(bm/am)*t) / am raise NotImplementedError def _ilt_rootsum(e): expr = e.fun.expr [variable] = e.fun.variables return RootSum(e.poly, Lambda(variable, together(_ilt(expr)))) return _ilt(e) ########################################################################## # Fourier Transform ########################################################################## @_noconds_(True) def _fourier_transform(f, x, k, a, b, name, simplify=True): r""" Compute a general Fourier-type transform .. math:: F(k) = a \int_{-\infty}^{\infty} e^{bixk} f(x)\, dx. For suitable choice of *a* and *b*, this reduces to the standard Fourier and inverse Fourier transforms. """ from sympy import exp, I F = integrate(a*f*exp(b*I*x*k), (x, -oo, oo)) if not F.has(Integral): return _simplify(F, simplify), S.true integral_f = integrate(f, (x, -oo, oo)) if integral_f in (-oo, oo, S.NaN) or integral_f.has(Integral): raise IntegralTransformError(name, f, 'function not integrable on real axis') if not F.is_Piecewise: raise IntegralTransformError(name, f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError(name, f, 'integral in unexpected form') return _simplify(F, simplify), cond class FourierTypeTransform(IntegralTransform): """ Base class for Fourier transforms.""" def a(self): raise NotImplementedError( "Class %s must implement a(self) but does not" % self.__class__) def b(self): raise NotImplementedError( "Class %s must implement b(self) but does not" % self.__class__) def _compute_transform(self, f, x, k, **hints): return _fourier_transform(f, x, k, self.a(), self.b(), self.__class__._name, **hints) def _as_integral(self, f, x, k): from sympy import exp, I a = self.a() b = self.b() return Integral(a*f*exp(b*I*x*k), (x, -oo, oo)) class FourierTransform(FourierTypeTransform): """ Class representing unevaluated Fourier transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute Fourier transforms, see the :func:`fourier_transform` docstring. """ _name = 'Fourier' def a(self): return 1 def b(self): return -2*S.Pi def fourier_transform(f, x, k, **hints): r""" Compute the unitary, ordinary-frequency Fourier transform of ``f``, defined as .. math:: F(k) = \int_{-\infty}^\infty f(x) e^{-2\pi i x k} \mathrm{d} x. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`FourierTransform` object. For other Fourier transform conventions, see the function :func:`sympy.integrals.transforms._fourier_transform`. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import fourier_transform, exp >>> from sympy.abc import x, k >>> fourier_transform(exp(-x**2), x, k) sqrt(pi)*exp(-pi**2*k**2) >>> fourier_transform(exp(-x**2), x, k, noconds=False) (sqrt(pi)*exp(-pi**2*k**2), True) See Also ======== inverse_fourier_transform sine_transform, inverse_sine_transform cosine_transform, inverse_cosine_transform hankel_transform, inverse_hankel_transform mellin_transform, laplace_transform """ return FourierTransform(f, x, k).doit(**hints) class InverseFourierTransform(FourierTypeTransform): """ Class representing unevaluated inverse Fourier transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute inverse Fourier transforms, see the :func:`inverse_fourier_transform` docstring. """ _name = 'Inverse Fourier' def a(self): return 1 def b(self): return 2*S.Pi def inverse_fourier_transform(F, k, x, **hints): r""" Compute the unitary, ordinary-frequency inverse Fourier transform of `F`, defined as .. math:: f(x) = \int_{-\infty}^\infty F(k) e^{2\pi i x k} \mathrm{d} k. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`InverseFourierTransform` object. For other Fourier transform conventions, see the function :func:`sympy.integrals.transforms._fourier_transform`. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import inverse_fourier_transform, exp, sqrt, pi >>> from sympy.abc import x, k >>> inverse_fourier_transform(sqrt(pi)*exp(-(pi*k)**2), k, x) exp(-x**2) >>> inverse_fourier_transform(sqrt(pi)*exp(-(pi*k)**2), k, x, noconds=False) (exp(-x**2), True) See Also ======== fourier_transform sine_transform, inverse_sine_transform cosine_transform, inverse_cosine_transform hankel_transform, inverse_hankel_transform mellin_transform, laplace_transform """ return InverseFourierTransform(F, k, x).doit(**hints) ########################################################################## # Fourier Sine and Cosine Transform ########################################################################## from sympy import sin, cos, sqrt, pi @_noconds_(True) def _sine_cosine_transform(f, x, k, a, b, K, name, simplify=True): """ Compute a general sine or cosine-type transform F(k) = a int_0^oo b*sin(x*k) f(x) dx. F(k) = a int_0^oo b*cos(x*k) f(x) dx. For suitable choice of a and b, this reduces to the standard sine/cosine and inverse sine/cosine transforms. """ F = integrate(a*f*K(b*x*k), (x, 0, oo)) if not F.has(Integral): return _simplify(F, simplify), S.true if not F.is_Piecewise: raise IntegralTransformError(name, f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError(name, f, 'integral in unexpected form') return _simplify(F, simplify), cond class SineCosineTypeTransform(IntegralTransform): """ Base class for sine and cosine transforms. Specify cls._kern. """ def a(self): raise NotImplementedError( "Class %s must implement a(self) but does not" % self.__class__) def b(self): raise NotImplementedError( "Class %s must implement b(self) but does not" % self.__class__) def _compute_transform(self, f, x, k, **hints): return _sine_cosine_transform(f, x, k, self.a(), self.b(), self.__class__._kern, self.__class__._name, **hints) def _as_integral(self, f, x, k): a = self.a() b = self.b() K = self.__class__._kern return Integral(a*f*K(b*x*k), (x, 0, oo)) class SineTransform(SineCosineTypeTransform): """ Class representing unevaluated sine transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute sine transforms, see the :func:`sine_transform` docstring. """ _name = 'Sine' _kern = sin def a(self): return sqrt(2)/sqrt(pi) def b(self): return 1 def sine_transform(f, x, k, **hints): r""" Compute the unitary, ordinary-frequency sine transform of `f`, defined as .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \sin(2\pi x k) \mathrm{d} x. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`SineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import sine_transform, exp >>> from sympy.abc import x, k, a >>> sine_transform(x*exp(-a*x**2), x, k) sqrt(2)*k*exp(-k**2/(4*a))/(4*a**(3/2)) >>> sine_transform(x**(-a), x, k) 2**(1/2 - a)*k**(a - 1)*gamma(1 - a/2)/gamma(a/2 + 1/2) See Also ======== fourier_transform, inverse_fourier_transform inverse_sine_transform cosine_transform, inverse_cosine_transform hankel_transform, inverse_hankel_transform mellin_transform, laplace_transform """ return SineTransform(f, x, k).doit(**hints) class InverseSineTransform(SineCosineTypeTransform): """ Class representing unevaluated inverse sine transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute inverse sine transforms, see the :func:`inverse_sine_transform` docstring. """ _name = 'Inverse Sine' _kern = sin def a(self): return sqrt(2)/sqrt(pi) def b(self): return 1 def inverse_sine_transform(F, k, x, **hints): r""" Compute the unitary, ordinary-frequency inverse sine transform of `F`, defined as .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \sin(2\pi x k) \mathrm{d} k. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`InverseSineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import inverse_sine_transform, exp, sqrt, gamma >>> from sympy.abc import x, k, a >>> inverse_sine_transform(2**((1-2*a)/2)*k**(a - 1)* ... gamma(-a/2 + 1)/gamma((a+1)/2), k, x) x**(-a) >>> inverse_sine_transform(sqrt(2)*k*exp(-k**2/(4*a))/(4*sqrt(a)**3), k, x) x*exp(-a*x**2) See Also ======== fourier_transform, inverse_fourier_transform sine_transform cosine_transform, inverse_cosine_transform hankel_transform, inverse_hankel_transform mellin_transform, laplace_transform """ return InverseSineTransform(F, k, x).doit(**hints) class CosineTransform(SineCosineTypeTransform): """ Class representing unevaluated cosine transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute cosine transforms, see the :func:`cosine_transform` docstring. """ _name = 'Cosine' _kern = cos def a(self): return sqrt(2)/sqrt(pi) def b(self): return 1 def cosine_transform(f, x, k, **hints): r""" Compute the unitary, ordinary-frequency cosine transform of `f`, defined as .. math:: F(k) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty f(x) \cos(2\pi x k) \mathrm{d} x. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`CosineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import cosine_transform, exp, sqrt, cos >>> from sympy.abc import x, k, a >>> cosine_transform(exp(-a*x), x, k) sqrt(2)*a/(sqrt(pi)*(a**2 + k**2)) >>> cosine_transform(exp(-a*sqrt(x))*cos(a*sqrt(x)), x, k) a*exp(-a**2/(2*k))/(2*k**(3/2)) See Also ======== fourier_transform, inverse_fourier_transform, sine_transform, inverse_sine_transform inverse_cosine_transform hankel_transform, inverse_hankel_transform mellin_transform, laplace_transform """ return CosineTransform(f, x, k).doit(**hints) class InverseCosineTransform(SineCosineTypeTransform): """ Class representing unevaluated inverse cosine transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute inverse cosine transforms, see the :func:`inverse_cosine_transform` docstring. """ _name = 'Inverse Cosine' _kern = cos def a(self): return sqrt(2)/sqrt(pi) def b(self): return 1 def inverse_cosine_transform(F, k, x, **hints): r""" Compute the unitary, ordinary-frequency inverse cosine transform of `F`, defined as .. math:: f(x) = \sqrt{\frac{2}{\pi}} \int_{0}^\infty F(k) \cos(2\pi x k) \mathrm{d} k. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`InverseCosineTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import inverse_cosine_transform, sqrt, pi >>> from sympy.abc import x, k, a >>> inverse_cosine_transform(sqrt(2)*a/(sqrt(pi)*(a**2 + k**2)), k, x) exp(-a*x) >>> inverse_cosine_transform(1/sqrt(k), k, x) 1/sqrt(x) See Also ======== fourier_transform, inverse_fourier_transform, sine_transform, inverse_sine_transform cosine_transform hankel_transform, inverse_hankel_transform mellin_transform, laplace_transform """ return InverseCosineTransform(F, k, x).doit(**hints) ########################################################################## # Hankel Transform ########################################################################## @_noconds_(True) def _hankel_transform(f, r, k, nu, name, simplify=True): r""" Compute a general Hankel transform .. math:: F_\nu(k) = \int_{0}^\infty f(r) J_\nu(k r) r \mathrm{d} r. """ from sympy import besselj F = integrate(f*besselj(nu, k*r)*r, (r, 0, oo)) if not F.has(Integral): return _simplify(F, simplify), S.true if not F.is_Piecewise: raise IntegralTransformError(name, f, 'could not compute integral') F, cond = F.args[0] if F.has(Integral): raise IntegralTransformError(name, f, 'integral in unexpected form') return _simplify(F, simplify), cond class HankelTypeTransform(IntegralTransform): """ Base class for Hankel transforms. """ def doit(self, **hints): return self._compute_transform(self.function, self.function_variable, self.transform_variable, self.args[3], **hints) def _compute_transform(self, f, r, k, nu, **hints): return _hankel_transform(f, r, k, nu, self._name, **hints) def _as_integral(self, f, r, k, nu): from sympy import besselj return Integral(f*besselj(nu, k*r)*r, (r, 0, oo)) @property def as_integral(self): return self._as_integral(self.function, self.function_variable, self.transform_variable, self.args[3]) class HankelTransform(HankelTypeTransform): """ Class representing unevaluated Hankel transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute Hankel transforms, see the :func:`hankel_transform` docstring. """ _name = 'Hankel' def hankel_transform(f, r, k, nu, **hints): r""" Compute the Hankel transform of `f`, defined as .. math:: F_\nu(k) = \int_{0}^\infty f(r) J_\nu(k r) r \mathrm{d} r. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`HankelTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import hankel_transform, inverse_hankel_transform >>> from sympy import exp >>> from sympy.abc import r, k, m, nu, a >>> ht = hankel_transform(1/r**m, r, k, nu) >>> ht 2*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/(2**m*gamma(m/2 + nu/2)) >>> inverse_hankel_transform(ht, k, r, nu) r**(-m) >>> ht = hankel_transform(exp(-a*r), r, k, 0) >>> ht a/(k**3*(a**2/k**2 + 1)**(3/2)) >>> inverse_hankel_transform(ht, k, r, 0) exp(-a*r) See Also ======== fourier_transform, inverse_fourier_transform sine_transform, inverse_sine_transform cosine_transform, inverse_cosine_transform inverse_hankel_transform mellin_transform, laplace_transform """ return HankelTransform(f, r, k, nu).doit(**hints) class InverseHankelTransform(HankelTypeTransform): """ Class representing unevaluated inverse Hankel transforms. For usage of this class, see the :class:`IntegralTransform` docstring. For how to compute inverse Hankel transforms, see the :func:`inverse_hankel_transform` docstring. """ _name = 'Inverse Hankel' def inverse_hankel_transform(F, k, r, nu, **hints): r""" Compute the inverse Hankel transform of `F` defined as .. math:: f(r) = \int_{0}^\infty F_\nu(k) J_\nu(k r) k \mathrm{d} k. Explanation =========== If the transform cannot be computed in closed form, this function returns an unevaluated :class:`InverseHankelTransform` object. For a description of possible hints, refer to the docstring of :func:`sympy.integrals.transforms.IntegralTransform.doit`. Note that for this transform, by default ``noconds=True``. Examples ======== >>> from sympy import hankel_transform, inverse_hankel_transform >>> from sympy import exp >>> from sympy.abc import r, k, m, nu, a >>> ht = hankel_transform(1/r**m, r, k, nu) >>> ht 2*k**(m - 2)*gamma(-m/2 + nu/2 + 1)/(2**m*gamma(m/2 + nu/2)) >>> inverse_hankel_transform(ht, k, r, nu) r**(-m) >>> ht = hankel_transform(exp(-a*r), r, k, 0) >>> ht a/(k**3*(a**2/k**2 + 1)**(3/2)) >>> inverse_hankel_transform(ht, k, r, 0) exp(-a*r) See Also ======== fourier_transform, inverse_fourier_transform sine_transform, inverse_sine_transform cosine_transform, inverse_cosine_transform hankel_transform mellin_transform, laplace_transform """ return InverseHankelTransform(F, k, r, nu).doit(**hints) sympy-sympy-1.9/sympy/integrals/trigonometry.py000066400000000000000000000255101412543434000222130ustar00rootroot00000000000000from sympy.core import cacheit, Dummy, Ne, Integer, Rational, S, Wild from sympy.functions import binomial, sin, cos, Piecewise # TODO sin(a*x)*cos(b*x) -> sin((a+b)x) + sin((a-b)x) ? # creating, each time, Wild's and sin/cos/Mul is expensive. Also, our match & # subs are very slow when not cached, and if we create Wild each time, we # effectively block caching. # # so we cache the pattern # need to use a function instead of lamda since hash of lambda changes on # each call to _pat_sincos def _integer_instance(n): return isinstance(n , Integer) @cacheit def _pat_sincos(x): a = Wild('a', exclude=[x]) n, m = [Wild(s, exclude=[x], properties=[_integer_instance]) for s in 'nm'] pat = sin(a*x)**n * cos(a*x)**m return pat, a, n, m _u = Dummy('u') def trigintegrate(f, x, conds='piecewise'): """ Integrate f = Mul(trig) over x. Examples ======== >>> from sympy import sin, cos, tan, sec >>> from sympy.integrals.trigonometry import trigintegrate >>> from sympy.abc import x >>> trigintegrate(sin(x)*cos(x), x) sin(x)**2/2 >>> trigintegrate(sin(x)**2, x) x/2 - sin(x)*cos(x)/2 >>> trigintegrate(tan(x)*sec(x), x) 1/cos(x) >>> trigintegrate(sin(x)*tan(x), x) -log(sin(x) - 1)/2 + log(sin(x) + 1)/2 - sin(x) References ========== .. [1] http://en.wikibooks.org/wiki/Calculus/Integration_techniques See Also ======== sympy.integrals.integrals.Integral.doit sympy.integrals.integrals.Integral """ from sympy.integrals.integrals import integrate pat, a, n, m = _pat_sincos(x) f = f.rewrite('sincos') M = f.match(pat) if M is None: return n, m = M[n], M[m] if n.is_zero and m.is_zero: return x zz = x if n.is_zero else S.Zero a = M[a] if n.is_odd or m.is_odd: u = _u n_, m_ = n.is_odd, m.is_odd # take smallest n or m -- to choose simplest substitution if n_ and m_: # Make sure to choose the positive one # otherwise an incorrect integral can occur. if n < 0 and m > 0: m_ = True n_ = False elif m < 0 and n > 0: n_ = True m_ = False # Both are negative so choose the smallest n or m # in absolute value for simplest substitution. elif (n < 0 and m < 0): n_ = n > m m_ = not (n > m) # Both n and m are odd and positive else: n_ = (n < m) # NB: careful here, one of the m_ = not (n < m) # conditions *must* be true # n m u=C (n-1)/2 m # S(x) * C(x) dx --> -(1-u^2) * u du if n_: ff = -(1 - u**2)**((n - 1)/2) * u**m uu = cos(a*x) # n m u=S n (m-1)/2 # S(x) * C(x) dx --> u * (1-u^2) du elif m_: ff = u**n * (1 - u**2)**((m - 1)/2) uu = sin(a*x) fi = integrate(ff, u) # XXX cyclic deps fx = fi.subs(u, uu) if conds == 'piecewise': return Piecewise((fx / a, Ne(a, 0)), (zz, True)) return fx / a # n & m are both even # # 2k 2m 2l 2l # we transform S (x) * C (x) into terms with only S (x) or C (x) # # example: # 100 4 100 2 2 100 4 2 # S (x) * C (x) = S (x) * (1-S (x)) = S (x) * (1 + S (x) - 2*S (x)) # # 104 102 100 # = S (x) - 2*S (x) + S (x) # 2k # then S is integrated with recursive formula # take largest n or m -- to choose simplest substitution n_ = (abs(n) > abs(m)) m_ = (abs(m) > abs(n)) res = S.Zero if n_: # 2k 2 k i 2i # C = (1 - S ) = sum(i, (-) * B(k, i) * S ) if m > 0: for i in range(0, m//2 + 1): res += ((-1)**i * binomial(m//2, i) * _sin_pow_integrate(n + 2*i, x)) elif m == 0: res = _sin_pow_integrate(n, x) else: # m < 0 , |n| > |m| # / # | # | m n # | cos (x) sin (x) dx = # | # | #/ # / # | # -1 m+1 n-1 n - 1 | m+2 n-2 # ________ cos (x) sin (x) + _______ | cos (x) sin (x) dx # | # m + 1 m + 1 | # / res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) + Rational(n - 1, m + 1) * trigintegrate(cos(x)**(m + 2)*sin(x)**(n - 2), x)) elif m_: # 2k 2 k i 2i # S = (1 - C ) = sum(i, (-) * B(k, i) * C ) if n > 0: # / / # | | # | m n | -m n # | cos (x)*sin (x) dx or | cos (x) * sin (x) dx # | | # / / # # |m| > |n| ; m, n >0 ; m, n belong to Z - {0} # n 2 # sin (x) term is expanded here in terms of cos (x), # and then integrated. # for i in range(0, n//2 + 1): res += ((-1)**i * binomial(n//2, i) * _cos_pow_integrate(m + 2*i, x)) elif n == 0: # / # | # | 1 # | _ _ _ # | m # | cos (x) # / # res = _cos_pow_integrate(m, x) else: # n < 0 , |m| > |n| # / # | # | m n # | cos (x) sin (x) dx = # | # | #/ # / # | # 1 m-1 n+1 m - 1 | m-2 n+2 # _______ cos (x) sin (x) + _______ | cos (x) sin (x) dx # | # n + 1 n + 1 | # / res = (Rational(1, n + 1) * cos(x)**(m - 1)*sin(x)**(n + 1) + Rational(m - 1, n + 1) * trigintegrate(cos(x)**(m - 2)*sin(x)**(n + 2), x)) else: if m == n: ##Substitute sin(2x)/2 for sin(x)cos(x) and then Integrate. res = integrate((sin(2*x)*S.Half)**m, x) elif (m == -n): if n < 0: # Same as the scheme described above. # the function argument to integrate in the end will # be 1 , this cannot be integrated by trigintegrate. # Hence use sympy.integrals.integrate. res = (Rational(1, n + 1) * cos(x)**(m - 1) * sin(x)**(n + 1) + Rational(m - 1, n + 1) * integrate(cos(x)**(m - 2) * sin(x)**(n + 2), x)) else: res = (Rational(-1, m + 1) * cos(x)**(m + 1) * sin(x)**(n - 1) + Rational(n - 1, m + 1) * integrate(cos(x)**(m + 2)*sin(x)**(n - 2), x)) if conds == 'piecewise': return Piecewise((res.subs(x, a*x) / a, Ne(a, 0)), (zz, True)) return res.subs(x, a*x) / a def _sin_pow_integrate(n, x): if n > 0: if n == 1: #Recursion break return -cos(x) # n > 0 # / / # | | # | n -1 n-1 n - 1 | n-2 # | sin (x) dx = ______ cos (x) sin (x) + _______ | sin (x) dx # | | # | n n | #/ / # # return (Rational(-1, n) * cos(x) * sin(x)**(n - 1) + Rational(n - 1, n) * _sin_pow_integrate(n - 2, x)) if n < 0: if n == -1: ##Make sure this does not come back here again. ##Recursion breaks here or at n==0. return trigintegrate(1/sin(x), x) # n < 0 # / / # | | # | n 1 n+1 n + 2 | n+2 # | sin (x) dx = _______ cos (x) sin (x) + _______ | sin (x) dx # | | # | n + 1 n + 1 | #/ / # return (Rational(1, n + 1) * cos(x) * sin(x)**(n + 1) + Rational(n + 2, n + 1) * _sin_pow_integrate(n + 2, x)) else: #n == 0 #Recursion break. return x def _cos_pow_integrate(n, x): if n > 0: if n == 1: #Recursion break. return sin(x) # n > 0 # / / # | | # | n 1 n-1 n - 1 | n-2 # | sin (x) dx = ______ sin (x) cos (x) + _______ | cos (x) dx # | | # | n n | #/ / # return (Rational(1, n) * sin(x) * cos(x)**(n - 1) + Rational(n - 1, n) * _cos_pow_integrate(n - 2, x)) if n < 0: if n == -1: ##Recursion break return trigintegrate(1/cos(x), x) # n < 0 # / / # | | # | n -1 n+1 n + 2 | n+2 # | cos (x) dx = _______ sin (x) cos (x) + _______ | cos (x) dx # | | # | n + 1 n + 1 | #/ / # return (Rational(-1, n + 1) * sin(x) * cos(x)**(n + 1) + Rational(n + 2, n + 1) * _cos_pow_integrate(n + 2, x)) else: # n == 0 #Recursion Break. return x sympy-sympy-1.9/sympy/interactive/000077500000000000000000000000001412543434000174215ustar00rootroot00000000000000sympy-sympy-1.9/sympy/interactive/__init__.py000066400000000000000000000002641412543434000215340ustar00rootroot00000000000000"""Helper module for setting up interactive SymPy sessions. """ from .printing import init_printing from .session import init_session __all__ = ['init_printing', 'init_session'] sympy-sympy-1.9/sympy/interactive/ipythonprinting.py000066400000000000000000000033101412543434000232350ustar00rootroot00000000000000""" A print function that pretty prints SymPy objects. :moduleauthor: Brian Granger Usage ===== To use this extension, execute: %load_ext sympy.interactive.ipythonprinting Once the extension is loaded, SymPy Basic objects are automatically pretty-printed in the terminal and rendered in LaTeX in the Qt console and notebook. """ #----------------------------------------------------------------------------- # Copyright (C) 2008 The IPython Development Team # # Distributed under the terms of the BSD License. The full license is in # the file COPYING, distributed as part of this software. #----------------------------------------------------------------------------- #----------------------------------------------------------------------------- # Imports #----------------------------------------------------------------------------- import warnings from sympy.interactive.printing import init_printing from sympy.utilities.exceptions import SymPyDeprecationWarning #----------------------------------------------------------------------------- # Definitions of special display functions for use with IPython #----------------------------------------------------------------------------- def load_ipython_extension(ip): """Load the extension in IPython.""" # Since Python filters deprecation warnings by default, # we add a filter to make sure this message will be shown. warnings.simplefilter("once", SymPyDeprecationWarning) SymPyDeprecationWarning( feature="using %load_ext sympy.interactive.ipythonprinting", useinstead="from sympy import init_printing ; init_printing()", deprecated_since_version="0.7.3", issue=7013 ).warn() init_printing(ip=ip) sympy-sympy-1.9/sympy/interactive/printing.py000066400000000000000000000546251412543434000216410ustar00rootroot00000000000000"""Tools for setting up printing in interactive sessions. """ import sys from sympy.external.importtools import version_tuple from io import BytesIO from sympy import latex as default_latex from sympy import preview from sympy.utilities.misc import debug from sympy.printing.defaults import Printable def _init_python_printing(stringify_func, **settings): """Setup printing in Python interactive session. """ import sys import builtins def _displayhook(arg): """Python's pretty-printer display hook. This function was adapted from: http://www.python.org/dev/peps/pep-0217/ """ if arg is not None: builtins._ = None print(stringify_func(arg, **settings)) builtins._ = arg sys.displayhook = _displayhook def _init_ipython_printing(ip, stringify_func, use_latex, euler, forecolor, backcolor, fontsize, latex_mode, print_builtin, latex_printer, scale, **settings): """Setup printing in IPython interactive session. """ try: from IPython.lib.latextools import latex_to_png except ImportError: pass # Guess best font color if none was given based on the ip.colors string. # From the IPython documentation: # It has four case-insensitive values: 'nocolor', 'neutral', 'linux', # 'lightbg'. The default is neutral, which should be legible on either # dark or light terminal backgrounds. linux is optimised for dark # backgrounds and lightbg for light ones. if forecolor is None: color = ip.colors.lower() if color == 'lightbg': forecolor = 'Black' elif color == 'linux': forecolor = 'White' else: # No idea, go with gray. forecolor = 'Gray' debug("init_printing: Automatic foreground color:", forecolor) preamble = "\\documentclass[varwidth,%s]{standalone}\n" \ "\\usepackage{amsmath,amsfonts}%s\\begin{document}" if euler: addpackages = '\\usepackage{euler}' else: addpackages = '' if use_latex == "svg": addpackages = addpackages + "\n\\special{color %s}" % forecolor preamble = preamble % (fontsize, addpackages) imagesize = 'tight' offset = "0cm,0cm" resolution = round(150*scale) dvi = r"-T %s -D %d -bg %s -fg %s -O %s" % ( imagesize, resolution, backcolor, forecolor, offset) dvioptions = dvi.split() svg_scale = 150/72*scale dvioptions_svg = ["--no-fonts", "--scale={}".format(svg_scale)] debug("init_printing: DVIOPTIONS:", dvioptions) debug("init_printing: DVIOPTIONS_SVG:", dvioptions_svg) debug("init_printing: PREAMBLE:", preamble) latex = latex_printer or default_latex def _print_plain(arg, p, cycle): """caller for pretty, for use in IPython 0.11""" if _can_print(arg): p.text(stringify_func(arg)) else: p.text(IPython.lib.pretty.pretty(arg)) def _preview_wrapper(o): exprbuffer = BytesIO() try: preview(o, output='png', viewer='BytesIO', outputbuffer=exprbuffer, preamble=preamble, dvioptions=dvioptions) except Exception as e: # IPython swallows exceptions debug("png printing:", "_preview_wrapper exception raised:", repr(e)) raise return exprbuffer.getvalue() def _svg_wrapper(o): exprbuffer = BytesIO() try: preview(o, output='svg', viewer='BytesIO', outputbuffer=exprbuffer, preamble=preamble, dvioptions=dvioptions_svg) except Exception as e: # IPython swallows exceptions debug("svg printing:", "_preview_wrapper exception raised:", repr(e)) raise return exprbuffer.getvalue().decode('utf-8') def _matplotlib_wrapper(o): # mathtext does not understand certain latex flags, so we try to # replace them with suitable subs o = o.replace(r'\operatorname', '') o = o.replace(r'\overline', r'\bar') # mathtext can't render some LaTeX commands. For example, it can't # render any LaTeX environments such as array or matrix. So here we # ensure that if mathtext fails to render, we return None. try: try: return latex_to_png(o, color=forecolor, scale=scale) except TypeError: # Old IPython version without color and scale return latex_to_png(o) except ValueError as e: debug('matplotlib exception caught:', repr(e)) return None # Hook methods for builtin sympy printers printing_hooks = ('_latex', '_sympystr', '_pretty', '_sympyrepr') def _can_print(o): """Return True if type o can be printed with one of the sympy printers. If o is a container type, this is True if and only if every element of o can be printed in this way. """ try: # If you're adding another type, make sure you add it to printable_types # later in this file as well builtin_types = (list, tuple, set, frozenset) if isinstance(o, builtin_types): # If the object is a custom subclass with a custom str or # repr, use that instead. if (type(o).__str__ not in (i.__str__ for i in builtin_types) or type(o).__repr__ not in (i.__repr__ for i in builtin_types)): return False return all(_can_print(i) for i in o) elif isinstance(o, dict): return all(_can_print(i) and _can_print(o[i]) for i in o) elif isinstance(o, bool): return False elif isinstance(o, Printable): # types known to sympy return True elif any(hasattr(o, hook) for hook in printing_hooks): # types which add support themselves return True elif isinstance(o, (float, int)) and print_builtin: return True return False except RuntimeError: return False # This is in case maximum recursion depth is reached. # Since RecursionError is for versions of Python 3.5+ # so this is to guard against RecursionError for older versions. def _print_latex_png(o): """ A function that returns a png rendered by an external latex distribution, falling back to matplotlib rendering """ if _can_print(o): s = latex(o, mode=latex_mode, **settings) if latex_mode == 'plain': s = '$\\displaystyle %s$' % s try: return _preview_wrapper(s) except RuntimeError as e: debug('preview failed with:', repr(e), ' Falling back to matplotlib backend') if latex_mode != 'inline': s = latex(o, mode='inline', **settings) return _matplotlib_wrapper(s) def _print_latex_svg(o): """ A function that returns a svg rendered by an external latex distribution, no fallback available. """ if _can_print(o): s = latex(o, mode=latex_mode, **settings) if latex_mode == 'plain': s = '$\\displaystyle %s$' % s try: return _svg_wrapper(s) except RuntimeError as e: debug('preview failed with:', repr(e), ' No fallback available.') def _print_latex_matplotlib(o): """ A function that returns a png rendered by mathtext """ if _can_print(o): s = latex(o, mode='inline', **settings) return _matplotlib_wrapper(s) def _print_latex_text(o): """ A function to generate the latex representation of sympy expressions. """ if _can_print(o): s = latex(o, mode=latex_mode, **settings) if latex_mode == 'plain': return '$\\displaystyle %s$' % s return s def _result_display(self, arg): """IPython's pretty-printer display hook, for use in IPython 0.10 This function was adapted from: ipython/IPython/hooks.py:155 """ if self.rc.pprint: out = stringify_func(arg) if '\n' in out: print() print(out) else: print(repr(arg)) import IPython if version_tuple(IPython.__version__) >= version_tuple('0.11'): # Printable is our own type, so we handle it with methods instead of # the approach required by builtin types. This allows downstream # packages to override the methods in their own subclasses of Printable, # which avoids the effects of gh-16002. printable_types = [float, tuple, list, set, frozenset, dict, int] plaintext_formatter = ip.display_formatter.formatters['text/plain'] # Exception to the rule above: IPython has better dispatching rules # for plaintext printing (xref ipython/ipython#8938), and we can't # use `_repr_pretty_` without hitting a recursion error in _print_plain. for cls in printable_types + [Printable]: plaintext_formatter.for_type(cls, _print_plain) svg_formatter = ip.display_formatter.formatters['image/svg+xml'] if use_latex in ('svg', ): debug("init_printing: using svg formatter") for cls in printable_types: svg_formatter.for_type(cls, _print_latex_svg) Printable._repr_svg_ = _print_latex_svg else: debug("init_printing: not using any svg formatter") for cls in printable_types: # Better way to set this, but currently does not work in IPython #png_formatter.for_type(cls, None) if cls in svg_formatter.type_printers: svg_formatter.type_printers.pop(cls) Printable._repr_svg_ = Printable._repr_disabled png_formatter = ip.display_formatter.formatters['image/png'] if use_latex in (True, 'png'): debug("init_printing: using png formatter") for cls in printable_types: png_formatter.for_type(cls, _print_latex_png) Printable._repr_png_ = _print_latex_png elif use_latex == 'matplotlib': debug("init_printing: using matplotlib formatter") for cls in printable_types: png_formatter.for_type(cls, _print_latex_matplotlib) Printable._repr_png_ = _print_latex_matplotlib else: debug("init_printing: not using any png formatter") for cls in printable_types: # Better way to set this, but currently does not work in IPython #png_formatter.for_type(cls, None) if cls in png_formatter.type_printers: png_formatter.type_printers.pop(cls) Printable._repr_png_ = Printable._repr_disabled latex_formatter = ip.display_formatter.formatters['text/latex'] if use_latex in (True, 'mathjax'): debug("init_printing: using mathjax formatter") for cls in printable_types: latex_formatter.for_type(cls, _print_latex_text) Printable._repr_latex_ = _print_latex_text else: debug("init_printing: not using text/latex formatter") for cls in printable_types: # Better way to set this, but currently does not work in IPython #latex_formatter.for_type(cls, None) if cls in latex_formatter.type_printers: latex_formatter.type_printers.pop(cls) Printable._repr_latex_ = Printable._repr_disabled else: ip.set_hook('result_display', _result_display) def _is_ipython(shell): """Is a shell instance an IPython shell?""" # shortcut, so we don't import IPython if we don't have to if 'IPython' not in sys.modules: return False try: from IPython.core.interactiveshell import InteractiveShell except ImportError: # IPython < 0.11 try: from IPython.iplib import InteractiveShell except ImportError: # Reaching this points means IPython has changed in a backward-incompatible way # that we don't know about. Warn? return False return isinstance(shell, InteractiveShell) # Used by the doctester to override the default for no_global NO_GLOBAL = False def init_printing(pretty_print=True, order=None, use_unicode=None, use_latex=None, wrap_line=None, num_columns=None, no_global=False, ip=None, euler=False, forecolor=None, backcolor='Transparent', fontsize='10pt', latex_mode='plain', print_builtin=True, str_printer=None, pretty_printer=None, latex_printer=None, scale=1.0, **settings): r""" Initializes pretty-printer depending on the environment. Parameters ========== pretty_print : boolean, default=True If True, use pretty_print to stringify or the provided pretty printer; if False, use sstrrepr to stringify or the provided string printer. order : string or None, default='lex' There are a few different settings for this parameter: lex (default), which is lexographic order; grlex, which is graded lexographic order; grevlex, which is reversed graded lexographic order; old, which is used for compatibility reasons and for long expressions; None, which sets it to lex. use_unicode : boolean or None, default=None If True, use unicode characters; if False, do not use unicode characters; if None, make a guess based on the environment. use_latex : string, boolean, or None, default=None If True, use default LaTeX rendering in GUI interfaces (png and mathjax); if False, do not use LaTeX rendering; if None, make a guess based on the environment; if 'png', enable latex rendering with an external latex compiler, falling back to matplotlib if external compilation fails; if 'matplotlib', enable LaTeX rendering with matplotlib; if 'mathjax', enable LaTeX text generation, for example MathJax rendering in IPython notebook or text rendering in LaTeX documents; if 'svg', enable LaTeX rendering with an external latex compiler, no fallback wrap_line : boolean If True, lines will wrap at the end; if False, they will not wrap but continue as one line. This is only relevant if ``pretty_print`` is True. num_columns : int or None, default=None If int, number of columns before wrapping is set to num_columns; if None, number of columns before wrapping is set to terminal width. This is only relevant if ``pretty_print`` is True. no_global : boolean, default=False If True, the settings become system wide; if False, use just for this console/session. ip : An interactive console This can either be an instance of IPython, or a class that derives from code.InteractiveConsole. euler : boolean, optional, default=False Loads the euler package in the LaTeX preamble for handwritten style fonts (http://www.ctan.org/pkg/euler). forecolor : string or None, optional, default=None DVI setting for foreground color. None means that either 'Black', 'White', or 'Gray' will be selected based on a guess of the IPython terminal color setting. See notes. backcolor : string, optional, default='Transparent' DVI setting for background color. See notes. fontsize : string, optional, default='10pt' A font size to pass to the LaTeX documentclass function in the preamble. Note that the options are limited by the documentclass. Consider using scale instead. latex_mode : string, optional, default='plain' The mode used in the LaTeX printer. Can be one of: {'inline'|'plain'|'equation'|'equation*'}. print_builtin : boolean, optional, default=True If ``True`` then floats and integers will be printed. If ``False`` the printer will only print SymPy types. str_printer : function, optional, default=None A custom string printer function. This should mimic sympy.printing.sstrrepr(). pretty_printer : function, optional, default=None A custom pretty printer. This should mimic sympy.printing.pretty(). latex_printer : function, optional, default=None A custom LaTeX printer. This should mimic sympy.printing.latex(). scale : float, optional, default=1.0 Scale the LaTeX output when using the ``png`` or ``svg`` backends. Useful for high dpi screens. settings : Any additional settings for the ``latex`` and ``pretty`` commands can be used to fine-tune the output. Examples ======== >>> from sympy.interactive import init_printing >>> from sympy import Symbol, sqrt >>> from sympy.abc import x, y >>> sqrt(5) sqrt(5) >>> init_printing(pretty_print=True) # doctest: +SKIP >>> sqrt(5) # doctest: +SKIP ___ \/ 5 >>> theta = Symbol('theta') # doctest: +SKIP >>> init_printing(use_unicode=True) # doctest: +SKIP >>> theta # doctest: +SKIP \u03b8 >>> init_printing(use_unicode=False) # doctest: +SKIP >>> theta # doctest: +SKIP theta >>> init_printing(order='lex') # doctest: +SKIP >>> str(y + x + y**2 + x**2) # doctest: +SKIP x**2 + x + y**2 + y >>> init_printing(order='grlex') # doctest: +SKIP >>> str(y + x + y**2 + x**2) # doctest: +SKIP x**2 + x + y**2 + y >>> init_printing(order='grevlex') # doctest: +SKIP >>> str(y * x**2 + x * y**2) # doctest: +SKIP x**2*y + x*y**2 >>> init_printing(order='old') # doctest: +SKIP >>> str(x**2 + y**2 + x + y) # doctest: +SKIP x**2 + x + y**2 + y >>> init_printing(num_columns=10) # doctest: +SKIP >>> x**2 + x + y**2 + y # doctest: +SKIP x + y + x**2 + y**2 Notes ===== The foreground and background colors can be selected when using 'png' or 'svg' LaTeX rendering. Note that before the ``init_printing`` command is executed, the LaTeX rendering is handled by the IPython console and not SymPy. The colors can be selected among the 68 standard colors known to ``dvips``, for a list see [1]_. In addition, the background color can be set to 'Transparent' (which is the default value). When using the 'Auto' foreground color, the guess is based on the ``colors`` variable in the IPython console, see [2]_. Hence, if that variable is set correctly in your IPython console, there is a high chance that the output will be readable, although manual settings may be needed. References ========== .. [1] https://en.wikibooks.org/wiki/LaTeX/Colors#The_68_standard_colors_known_to_dvips .. [2] https://ipython.readthedocs.io/en/stable/config/details.html#terminal-colors See Also ======== sympy.printing.latex sympy.printing.pretty """ import sys from sympy.printing.printer import Printer if pretty_print: if pretty_printer is not None: stringify_func = pretty_printer else: from sympy.printing import pretty as stringify_func else: if str_printer is not None: stringify_func = str_printer else: from sympy.printing import sstrrepr as stringify_func # Even if ip is not passed, double check that not in IPython shell in_ipython = False if ip is None: try: ip = get_ipython() except NameError: pass else: in_ipython = (ip is not None) if ip and not in_ipython: in_ipython = _is_ipython(ip) if in_ipython and pretty_print: try: import IPython # IPython 1.0 deprecates the frontend module, so we import directly # from the terminal module to prevent a deprecation message from being # shown. if version_tuple(IPython.__version__) >= version_tuple('1.0'): from IPython.terminal.interactiveshell import TerminalInteractiveShell else: from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell from code import InteractiveConsole except ImportError: pass else: # This will be True if we are in the qtconsole or notebook if not isinstance(ip, (InteractiveConsole, TerminalInteractiveShell)) \ and 'ipython-console' not in ''.join(sys.argv): if use_unicode is None: debug("init_printing: Setting use_unicode to True") use_unicode = True if use_latex is None: debug("init_printing: Setting use_latex to True") use_latex = True if not NO_GLOBAL and not no_global: Printer.set_global_settings(order=order, use_unicode=use_unicode, wrap_line=wrap_line, num_columns=num_columns) else: _stringify_func = stringify_func if pretty_print: stringify_func = lambda expr, **settings: \ _stringify_func(expr, order=order, use_unicode=use_unicode, wrap_line=wrap_line, num_columns=num_columns, **settings) else: stringify_func = \ lambda expr, **settings: _stringify_func( expr, order=order, **settings) if in_ipython: mode_in_settings = settings.pop("mode", None) if mode_in_settings: debug("init_printing: Mode is not able to be set due to internals" "of IPython printing") _init_ipython_printing(ip, stringify_func, use_latex, euler, forecolor, backcolor, fontsize, latex_mode, print_builtin, latex_printer, scale, **settings) else: _init_python_printing(stringify_func, **settings) sympy-sympy-1.9/sympy/interactive/session.py000066400000000000000000000360511412543434000214630ustar00rootroot00000000000000"""Tools for setting up interactive sessions. """ from sympy.external.importtools import version_tuple from sympy.interactive.printing import init_printing preexec_source = """\ from __future__ import division from sympy import * x, y, z, t = symbols('x y z t') k, m, n = symbols('k m n', integer=True) f, g, h = symbols('f g h', cls=Function) init_printing() """ verbose_message = """\ These commands were executed: %(source)s Documentation can be found at https://docs.sympy.org/%(version)s """ no_ipython = """\ Couldn't locate IPython. Having IPython installed is greatly recommended. See http://ipython.scipy.org for more details. If you use Debian/Ubuntu, just install the 'ipython' package and start isympy again. """ def _make_message(ipython=True, quiet=False, source=None): """Create a banner for an interactive session. """ from sympy import __version__ as sympy_version from sympy.external.gmpy import GROUND_TYPES from sympy.utilities.misc import ARCH from sympy import SYMPY_DEBUG import sys import os if quiet: return "" python_version = "%d.%d.%d" % sys.version_info[:3] if ipython: shell_name = "IPython" else: shell_name = "Python" info = ['ground types: %s' % GROUND_TYPES] cache = os.getenv('SYMPY_USE_CACHE') if cache is not None and cache.lower() == 'no': info.append('cache: off') if SYMPY_DEBUG: info.append('debugging: on') args = shell_name, sympy_version, python_version, ARCH, ', '.join(info) message = "%s console for SymPy %s (Python %s-%s) (%s)\n" % args if source is None: source = preexec_source _source = "" for line in source.split('\n')[:-1]: if not line: _source += '\n' else: _source += '>>> ' + line + '\n' doc_version = sympy_version if 'dev' in doc_version: doc_version = "dev" else: doc_version = "%s/" % doc_version message += '\n' + verbose_message % {'source': _source, 'version': doc_version} return message def int_to_Integer(s): """ Wrap integer literals with Integer. This is based on the decistmt example from http://docs.python.org/library/tokenize.html. Only integer literals are converted. Float literals are left alone. Examples ======== >>> from __future__ import division >>> from sympy import Integer # noqa: F401 >>> from sympy.interactive.session import int_to_Integer >>> s = '1.2 + 1/2 - 0x12 + a1' >>> int_to_Integer(s) '1.2 +Integer (1 )/Integer (2 )-Integer (0x12 )+a1 ' >>> s = 'print (1/2)' >>> int_to_Integer(s) 'print (Integer (1 )/Integer (2 ))' >>> exec(s) 0.5 >>> exec(int_to_Integer(s)) 1/2 """ from tokenize import generate_tokens, untokenize, NUMBER, NAME, OP from io import StringIO def _is_int(num): """ Returns true if string value num (with token NUMBER) represents an integer. """ # XXX: Is there something in the standard library that will do this? if '.' in num or 'j' in num.lower() or 'e' in num.lower(): return False return True result = [] g = generate_tokens(StringIO(s).readline) # tokenize the string for toknum, tokval, _, _, _ in g: if toknum == NUMBER and _is_int(tokval): # replace NUMBER tokens result.extend([ (NAME, 'Integer'), (OP, '('), (NUMBER, tokval), (OP, ')') ]) else: result.append((toknum, tokval)) return untokenize(result) def enable_automatic_int_sympification(shell): """ Allow IPython to automatically convert integer literals to Integer. """ import ast old_run_cell = shell.run_cell def my_run_cell(cell, *args, **kwargs): try: # Check the cell for syntax errors. This way, the syntax error # will show the original input, not the transformed input. The # downside here is that IPython magic like %timeit will not work # with transformed input (but on the other hand, IPython magic # that doesn't expect transformed input will continue to work). ast.parse(cell) except SyntaxError: pass else: cell = int_to_Integer(cell) old_run_cell(cell, *args, **kwargs) shell.run_cell = my_run_cell def enable_automatic_symbols(shell): """Allow IPython to automatically create symbols (``isympy -a``). """ # XXX: This should perhaps use tokenize, like int_to_Integer() above. # This would avoid re-executing the code, which can lead to subtle # issues. For example: # # In [1]: a = 1 # # In [2]: for i in range(10): # ...: a += 1 # ...: # # In [3]: a # Out[3]: 11 # # In [4]: a = 1 # # In [5]: for i in range(10): # ...: a += 1 # ...: print b # ...: # b # b # b # b # b # b # b # b # b # b # # In [6]: a # Out[6]: 12 # # Note how the for loop is executed again because `b` was not defined, but `a` # was already incremented once, so the result is that it is incremented # multiple times. import re re_nameerror = re.compile( "name '(?P[A-Za-z_][A-Za-z0-9_]*)' is not defined") def _handler(self, etype, value, tb, tb_offset=None): """Handle :exc:`NameError` exception and allow injection of missing symbols. """ if etype is NameError and tb.tb_next and not tb.tb_next.tb_next: match = re_nameerror.match(str(value)) if match is not None: # XXX: Make sure Symbol is in scope. Otherwise you'll get infinite recursion. self.run_cell("%(symbol)s = Symbol('%(symbol)s')" % {'symbol': match.group("symbol")}, store_history=False) try: code = self.user_ns['In'][-1] except (KeyError, IndexError): pass else: self.run_cell(code, store_history=False) return None finally: self.run_cell("del %s" % match.group("symbol"), store_history=False) stb = self.InteractiveTB.structured_traceback( etype, value, tb, tb_offset=tb_offset) self._showtraceback(etype, value, stb) shell.set_custom_exc((NameError,), _handler) def init_ipython_session(shell=None, argv=[], auto_symbols=False, auto_int_to_Integer=False): """Construct new IPython session. """ import IPython if version_tuple(IPython.__version__) >= version_tuple('0.11'): if not shell: # use an app to parse the command line, and init config # IPython 1.0 deprecates the frontend module, so we import directly # from the terminal module to prevent a deprecation message from being # shown. if version_tuple(IPython.__version__) >= version_tuple('1.0'): from IPython.terminal import ipapp else: from IPython.frontend.terminal import ipapp app = ipapp.TerminalIPythonApp() # don't draw IPython banner during initialization: app.display_banner = False app.initialize(argv) shell = app.shell if auto_symbols: enable_automatic_symbols(shell) if auto_int_to_Integer: enable_automatic_int_sympification(shell) return shell else: from IPython.Shell import make_IPython return make_IPython(argv) def init_python_session(): """Construct new Python session. """ from code import InteractiveConsole class SymPyConsole(InteractiveConsole): """An interactive console with readline support. """ def __init__(self): ns_locals = dict() InteractiveConsole.__init__(self, locals=ns_locals) try: import rlcompleter import readline except ImportError: pass else: import os import atexit readline.set_completer(rlcompleter.Completer(ns_locals).complete) readline.parse_and_bind('tab: complete') if hasattr(readline, 'read_history_file'): history = os.path.expanduser('~/.sympy-history') try: readline.read_history_file(history) except OSError: pass atexit.register(readline.write_history_file, history) return SymPyConsole() def init_session(ipython=None, pretty_print=True, order=None, use_unicode=None, use_latex=None, quiet=False, auto_symbols=False, auto_int_to_Integer=False, str_printer=None, pretty_printer=None, latex_printer=None, argv=[]): """ Initialize an embedded IPython or Python session. The IPython session is initiated with the --pylab option, without the numpy imports, so that matplotlib plotting can be interactive. Parameters ========== pretty_print: boolean If True, use pretty_print to stringify; if False, use sstrrepr to stringify. order: string or None There are a few different settings for this parameter: lex (default), which is lexographic order; grlex, which is graded lexographic order; grevlex, which is reversed graded lexographic order; old, which is used for compatibility reasons and for long expressions; None, which sets it to lex. use_unicode: boolean or None If True, use unicode characters; if False, do not use unicode characters. use_latex: boolean or None If True, use latex rendering if IPython GUI's; if False, do not use latex rendering. quiet: boolean If True, init_session will not print messages regarding its status; if False, init_session will print messages regarding its status. auto_symbols: boolean If True, IPython will automatically create symbols for you. If False, it will not. The default is False. auto_int_to_Integer: boolean If True, IPython will automatically wrap int literals with Integer, so that things like 1/2 give Rational(1, 2). If False, it will not. The default is False. ipython: boolean or None If True, printing will initialize for an IPython console; if False, printing will initialize for a normal console; The default is None, which automatically determines whether we are in an ipython instance or not. str_printer: function, optional, default=None A custom string printer function. This should mimic sympy.printing.sstrrepr(). pretty_printer: function, optional, default=None A custom pretty printer. This should mimic sympy.printing.pretty(). latex_printer: function, optional, default=None A custom LaTeX printer. This should mimic sympy.printing.latex() This should mimic sympy.printing.latex(). argv: list of arguments for IPython See sympy.bin.isympy for options that can be used to initialize IPython. See Also ======== sympy.interactive.printing.init_printing: for examples and the rest of the parameters. Examples ======== >>> from sympy import init_session, Symbol, sin, sqrt >>> sin(x) #doctest: +SKIP NameError: name 'x' is not defined >>> init_session() #doctest: +SKIP >>> sin(x) #doctest: +SKIP sin(x) >>> sqrt(5) #doctest: +SKIP ___ \\/ 5 >>> init_session(pretty_print=False) #doctest: +SKIP >>> sqrt(5) #doctest: +SKIP sqrt(5) >>> y + x + y**2 + x**2 #doctest: +SKIP x**2 + x + y**2 + y >>> init_session(order='grlex') #doctest: +SKIP >>> y + x + y**2 + x**2 #doctest: +SKIP x**2 + y**2 + x + y >>> init_session(order='grevlex') #doctest: +SKIP >>> y * x**2 + x * y**2 #doctest: +SKIP x**2*y + x*y**2 >>> init_session(order='old') #doctest: +SKIP >>> x**2 + y**2 + x + y #doctest: +SKIP x + y + x**2 + y**2 >>> theta = Symbol('theta') #doctest: +SKIP >>> theta #doctest: +SKIP theta >>> init_session(use_unicode=True) #doctest: +SKIP >>> theta # doctest: +SKIP \u03b8 """ import sys in_ipython = False if ipython is not False: try: import IPython except ImportError: if ipython is True: raise RuntimeError("IPython is not available on this system") ip = None else: try: from IPython import get_ipython ip = get_ipython() except ImportError: ip = None in_ipython = bool(ip) if ipython is None: ipython = in_ipython if ipython is False: ip = init_python_session() mainloop = ip.interact else: ip = init_ipython_session(ip, argv=argv, auto_symbols=auto_symbols, auto_int_to_Integer=auto_int_to_Integer) if version_tuple(IPython.__version__) >= version_tuple('0.11'): # runsource is gone, use run_cell instead, which doesn't # take a symbol arg. The second arg is `store_history`, # and False means don't add the line to IPython's history. ip.runsource = lambda src, symbol='exec': ip.run_cell(src, False) # Enable interactive plotting using pylab. try: ip.enable_pylab(import_all=False) except Exception: # Causes an import error if matplotlib is not installed. # Causes other errors (depending on the backend) if there # is no display, or if there is some problem in the # backend, so we have a bare "except Exception" here pass if not in_ipython: mainloop = ip.mainloop if auto_symbols and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')): raise RuntimeError("automatic construction of symbols is possible only in IPython 0.11 or above") if auto_int_to_Integer and (not ipython or version_tuple(IPython.__version__) < version_tuple('0.11')): raise RuntimeError("automatic int to Integer transformation is possible only in IPython 0.11 or above") _preexec_source = preexec_source ip.runsource(_preexec_source, symbol='exec') init_printing(pretty_print=pretty_print, order=order, use_unicode=use_unicode, use_latex=use_latex, ip=ip, str_printer=str_printer, pretty_printer=pretty_printer, latex_printer=latex_printer) message = _make_message(ipython, quiet, _preexec_source) if not in_ipython: print(message) mainloop() sys.exit('Exiting ...') else: print(message) import atexit atexit.register(lambda: print("Exiting ...\n")) sympy-sympy-1.9/sympy/interactive/tests/000077500000000000000000000000001412543434000205635ustar00rootroot00000000000000sympy-sympy-1.9/sympy/interactive/tests/__init__.py000066400000000000000000000000001412543434000226620ustar00rootroot00000000000000sympy-sympy-1.9/sympy/interactive/tests/test_interactive.py000066400000000000000000000007451412543434000245170ustar00rootroot00000000000000from sympy.interactive.session import int_to_Integer def test_int_to_Integer(): assert int_to_Integer("1 + 2.2 + 0x3 + 40") == \ 'Integer (1 )+2.2 +Integer (0x3 )+Integer (40 )' assert int_to_Integer("0b101") == 'Integer (0b101 )' assert int_to_Integer("ab1 + 1 + '1 + 2'") == "ab1 +Integer (1 )+'1 + 2'" assert int_to_Integer("(2 + \n3)") == '(Integer (2 )+\nInteger (3 ))' assert int_to_Integer("2 + 2.0 + 2j + 2e-10") == 'Integer (2 )+2.0 +2j +2e-10 ' sympy-sympy-1.9/sympy/interactive/tests/test_ipython.py000066400000000000000000000054031412543434000236700ustar00rootroot00000000000000"""Tests of tools for setting up interactive IPython sessions. """ from sympy.interactive.session import (init_ipython_session, enable_automatic_symbols, enable_automatic_int_sympification) from sympy.core import Symbol, Rational, Integer from sympy.external import import_module # TODO: The code below could be made more granular with something like: # # @requires('IPython', version=">=0.11") # def test_automatic_symbols(ipython): ipython = import_module("IPython", min_module_version="0.11") if not ipython: #bin/test will not execute any tests now disabled = True # WARNING: These tests will modify the existing IPython environment. IPython # uses a single instance for its interpreter, so there is no way to isolate # the test from another IPython session. It also means that if this test is # run twice in the same Python session it will fail. This isn't usually a # problem because the test suite is run in a subprocess by default, but if the # tests are run with subprocess=False it can pollute the current IPython # session. See the discussion in issue #15149. def test_automatic_symbols(): # NOTE: Because of the way the hook works, you have to use run_cell(code, # True). This means that the code must have no Out, or it will be printed # during the tests. app = init_ipython_session() app.run_cell("from sympy import *") enable_automatic_symbols(app) symbol = "verylongsymbolname" assert symbol not in app.user_ns app.run_cell("a = %s" % symbol, True) assert symbol not in app.user_ns app.run_cell("a = type(%s)" % symbol, True) assert app.user_ns['a'] == Symbol app.run_cell("%s = Symbol('%s')" % (symbol, symbol), True) assert symbol in app.user_ns # Check that built-in names aren't overridden app.run_cell("a = all == __builtin__.all", True) assert "all" not in app.user_ns assert app.user_ns['a'] is True # Check that sympy names aren't overridden app.run_cell("import sympy") app.run_cell("a = factorial == sympy.factorial", True) assert app.user_ns['a'] is True def test_int_to_Integer(): # XXX: Warning, don't test with == here. 0.5 == Rational(1, 2) is True! app = init_ipython_session() app.run_cell("from sympy import Integer") app.run_cell("a = 1") assert isinstance(app.user_ns['a'], int) enable_automatic_int_sympification(app) app.run_cell("a = 1/2") assert isinstance(app.user_ns['a'], Rational) app.run_cell("a = 1") assert isinstance(app.user_ns['a'], Integer) app.run_cell("a = int(1)") assert isinstance(app.user_ns['a'], int) app.run_cell("a = (1/\n2)") assert app.user_ns['a'] == Rational(1, 2) # TODO: How can we test that the output of a SyntaxError is the original # input, not the transformed input? sympy-sympy-1.9/sympy/interactive/tests/test_ipythonprinting.py000066400000000000000000000224351412543434000254470ustar00rootroot00000000000000"""Tests that the IPython printing module is properly loaded. """ from sympy.interactive.session import init_ipython_session from sympy.external import import_module from sympy.testing.pytest import raises # run_cell was added in IPython 0.11 ipython = import_module("IPython", min_module_version="0.11") # disable tests if ipython is not present if not ipython: disabled = True def test_ipythonprinting(): # Initialize and setup IPython session app = init_ipython_session() app.run_cell("ip = get_ipython()") app.run_cell("inst = ip.instance()") app.run_cell("format = inst.display_formatter.format") app.run_cell("from sympy import Symbol") # Printing without printing extension app.run_cell("a = format(Symbol('pi'))") app.run_cell("a2 = format(Symbol('pi')**2)") # Deal with API change starting at IPython 1.0 if int(ipython.__version__.split(".")[0]) < 1: assert app.user_ns['a']['text/plain'] == "pi" assert app.user_ns['a2']['text/plain'] == "pi**2" else: assert app.user_ns['a'][0]['text/plain'] == "pi" assert app.user_ns['a2'][0]['text/plain'] == "pi**2" # Load printing extension app.run_cell("from sympy import init_printing") app.run_cell("init_printing()") # Printing with printing extension app.run_cell("a = format(Symbol('pi'))") app.run_cell("a2 = format(Symbol('pi')**2)") # Deal with API change starting at IPython 1.0 if int(ipython.__version__.split(".")[0]) < 1: assert app.user_ns['a']['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi') assert app.user_ns['a2']['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', ' 2\npi ') else: assert app.user_ns['a'][0]['text/plain'] in ('\N{GREEK SMALL LETTER PI}', 'pi') assert app.user_ns['a2'][0]['text/plain'] in (' 2\n\N{GREEK SMALL LETTER PI} ', ' 2\npi ') def test_print_builtin_option(): # Initialize and setup IPython session app = init_ipython_session() app.run_cell("ip = get_ipython()") app.run_cell("inst = ip.instance()") app.run_cell("format = inst.display_formatter.format") app.run_cell("from sympy import Symbol") app.run_cell("from sympy import init_printing") app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})") # Deal with API change starting at IPython 1.0 if int(ipython.__version__.split(".")[0]) < 1: text = app.user_ns['a']['text/plain'] raises(KeyError, lambda: app.user_ns['a']['text/latex']) else: text = app.user_ns['a'][0]['text/plain'] raises(KeyError, lambda: app.user_ns['a'][0]['text/latex']) # Note : Unicode of Python2 is equivalent to str in Python3. In Python 3 we have one # text type: str which holds Unicode data and two byte types bytes and bytearray. # XXX: How can we make this ignore the terminal width? This test fails if # the terminal is too narrow. assert text in ("{pi: 3.14, n_i: 3}", '{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}', "{n_i: 3, pi: 3.14}", '{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}') # If we enable the default printing, then the dictionary's should render # as a LaTeX version of the whole dict: ${\pi: 3.14, n_i: 3}$ app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True") app.run_cell("init_printing(use_latex=True)") app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})") # Deal with API change starting at IPython 1.0 if int(ipython.__version__.split(".")[0]) < 1: text = app.user_ns['a']['text/plain'] latex = app.user_ns['a']['text/latex'] else: text = app.user_ns['a'][0]['text/plain'] latex = app.user_ns['a'][0]['text/latex'] assert text in ("{pi: 3.14, n_i: 3}", '{n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3, \N{GREEK SMALL LETTER PI}: 3.14}', "{n_i: 3, pi: 3.14}", '{\N{GREEK SMALL LETTER PI}: 3.14, n\N{LATIN SUBSCRIPT SMALL LETTER I}: 3}') assert latex == r'$\displaystyle \left\{ n_{i} : 3, \ \pi : 3.14\right\}$' # Objects with an _latex overload should also be handled by our tuple # printer. app.run_cell("""\ class WithOverload: def _latex(self, printer): return r"\\LaTeX" """) app.run_cell("a = format((WithOverload(),))") # Deal with API change starting at IPython 1.0 if int(ipython.__version__.split(".")[0]) < 1: latex = app.user_ns['a']['text/latex'] else: latex = app.user_ns['a'][0]['text/latex'] assert latex == r'$\displaystyle \left( \LaTeX,\right)$' app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True") app.run_cell("init_printing(use_latex=True, print_builtin=False)") app.run_cell("a = format({Symbol('pi'): 3.14, Symbol('n_i'): 3})") # Deal with API change starting at IPython 1.0 if int(ipython.__version__.split(".")[0]) < 1: text = app.user_ns['a']['text/plain'] raises(KeyError, lambda: app.user_ns['a']['text/latex']) else: text = app.user_ns['a'][0]['text/plain'] raises(KeyError, lambda: app.user_ns['a'][0]['text/latex']) # Note : In Python 3 we have one text type: str which holds Unicode data # and two byte types bytes and bytearray. # Python 3.3.3 + IPython 0.13.2 gives: '{n_i: 3, pi: 3.14}' # Python 3.3.3 + IPython 1.1.0 gives: '{n_i: 3, pi: 3.14}' assert text in ("{pi: 3.14, n_i: 3}", "{n_i: 3, pi: 3.14}") def test_builtin_containers(): # Initialize and setup IPython session app = init_ipython_session() app.run_cell("ip = get_ipython()") app.run_cell("inst = ip.instance()") app.run_cell("format = inst.display_formatter.format") app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True") app.run_cell("from sympy import init_printing, Matrix") app.run_cell('init_printing(use_latex=True, use_unicode=False)') # Make sure containers that shouldn't pretty print don't. app.run_cell('a = format((True, False))') app.run_cell('import sys') app.run_cell('b = format(sys.flags)') app.run_cell('c = format((Matrix([1, 2]),))') # Deal with API change starting at IPython 1.0 if int(ipython.__version__.split(".")[0]) < 1: assert app.user_ns['a']['text/plain'] == '(True, False)' assert 'text/latex' not in app.user_ns['a'] assert app.user_ns['b']['text/plain'][:10] == 'sys.flags(' assert 'text/latex' not in app.user_ns['b'] assert app.user_ns['c']['text/plain'] == \ """\ [1] \n\ ([ ],) [2] \ """ assert app.user_ns['c']['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$' else: assert app.user_ns['a'][0]['text/plain'] == '(True, False)' assert 'text/latex' not in app.user_ns['a'][0] assert app.user_ns['b'][0]['text/plain'][:10] == 'sys.flags(' assert 'text/latex' not in app.user_ns['b'][0] assert app.user_ns['c'][0]['text/plain'] == \ """\ [1] \n\ ([ ],) [2] \ """ assert app.user_ns['c'][0]['text/latex'] == '$\\displaystyle \\left( \\left[\\begin{matrix}1\\\\2\\end{matrix}\\right],\\right)$' def test_matplotlib_bad_latex(): # Initialize and setup IPython session app = init_ipython_session() app.run_cell("import IPython") app.run_cell("ip = get_ipython()") app.run_cell("inst = ip.instance()") app.run_cell("format = inst.display_formatter.format") app.run_cell("from sympy import init_printing, Matrix") app.run_cell("init_printing(use_latex='matplotlib')") # The png formatter is not enabled by default in this context app.run_cell("inst.display_formatter.formatters['image/png'].enabled = True") # Make sure no warnings are raised by IPython app.run_cell("import warnings") # IPython.core.formatters.FormatterWarning was introduced in IPython 2.0 if int(ipython.__version__.split(".")[0]) < 2: app.run_cell("warnings.simplefilter('error')") else: app.run_cell("warnings.simplefilter('error', IPython.core.formatters.FormatterWarning)") # This should not raise an exception app.run_cell("a = format(Matrix([1, 2, 3]))") # issue 9799 app.run_cell("from sympy import Piecewise, Symbol, Eq") app.run_cell("x = Symbol('x'); pw = format(Piecewise((1, Eq(x, 0)), (0, True)))") def test_override_repr_latex(): # Initialize and setup IPython session app = init_ipython_session() app.run_cell("import IPython") app.run_cell("ip = get_ipython()") app.run_cell("inst = ip.instance()") app.run_cell("format = inst.display_formatter.format") app.run_cell("inst.display_formatter.formatters['text/latex'].enabled = True") app.run_cell("from sympy import init_printing") app.run_cell("from sympy import Symbol") app.run_cell("init_printing(use_latex=True)") app.run_cell("""\ class SymbolWithOverload(Symbol): def _repr_latex_(self): return r"Hello " + super()._repr_latex_() + " world" """) app.run_cell("a = format(SymbolWithOverload('s'))") if int(ipython.__version__.split(".")[0]) < 1: latex = app.user_ns['a']['text/latex'] else: latex = app.user_ns['a'][0]['text/latex'] assert latex == r'Hello $\displaystyle s$ world' sympy-sympy-1.9/sympy/liealgebras/000077500000000000000000000000001412543434000173565ustar00rootroot00000000000000sympy-sympy-1.9/sympy/liealgebras/__init__.py000066400000000000000000000001171412543434000214660ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType __all__ = ['CartanType'] sympy-sympy-1.9/sympy/liealgebras/cartan_matrix.py000066400000000000000000000010141412543434000225600ustar00rootroot00000000000000from .cartan_type import CartanType def CartanMatrix(ct): """Access the Cartan matrix of a specific Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_matrix import CartanMatrix >>> CartanMatrix("A2") Matrix([ [ 2, -1], [-1, 2]]) >>> CartanMatrix(['C', 3]) Matrix([ [ 2, -1, 0], [-1, 2, -1], [ 0, -2, 2]]) This method works by returning the Cartan matrix which corresponds to Cartan type t. """ return CartanType(ct).cartan_matrix() sympy-sympy-1.9/sympy/liealgebras/cartan_type.py000066400000000000000000000034011412543434000222370ustar00rootroot00000000000000from sympy.core import Basic class CartanType_generator(Basic): """ Constructor for actually creating things """ def __call__(self, *args): c = args[0] if type(c) == list: letter, n = c[0], int(c[1]) elif type(c) == str: letter, n = c[0], int(c[1:]) else: raise TypeError("Argument must be a string (e.g. 'A3') or a list (e.g. ['A', 3])") if n < 0: raise ValueError("Lie algebra rank cannot be negative") if letter == "A": from . import type_a return type_a.TypeA(n) if letter == "B": from . import type_b return type_b.TypeB(n) if letter == "C": from . import type_c return type_c.TypeC(n) if letter == "D": from . import type_d return type_d.TypeD(n) if letter == "E": if n >= 6 and n <= 8: from . import type_e return type_e.TypeE(n) if letter == "F": if n == 4: from . import type_f return type_f.TypeF(n) if letter == "G": if n == 2: from . import type_g return type_g.TypeG(n) CartanType = CartanType_generator() class Standard_Cartan(Basic): """ Concrete base class for Cartan types such as A4, etc """ def __new__(cls, series, n): obj = Basic.__new__(cls, series, n) obj.n = n obj.series = series return obj def rank(self): """ Returns the rank of the Lie algebra """ return self.n def series(self): """ Returns the type of the Lie algebra """ return self.series sympy-sympy-1.9/sympy/liealgebras/dynkin_diagram.py000066400000000000000000000010271412543434000227100ustar00rootroot00000000000000from .cartan_type import CartanType def DynkinDiagram(t): """Display the Dynkin diagram of a given Lie algebra Works by generating the CartanType for the input, t, and then returning the Dynkin diagram method from the individual classes. Examples ======== >>> from sympy.liealgebras.dynkin_diagram import DynkinDiagram >>> print(DynkinDiagram("A3")) 0---0---0 1 2 3 >>> print(DynkinDiagram("B4")) 0---0---0=>=0 1 2 3 4 """ return CartanType(t).dynkin_diagram() sympy-sympy-1.9/sympy/liealgebras/root_system.py000066400000000000000000000152721412543434000223260ustar00rootroot00000000000000from .cartan_type import CartanType from sympy.core.backend import Basic class RootSystem(Basic): """Represent the root system of a simple Lie algebra Every simple Lie algebra has a unique root system. To find the root system, we first consider the Cartan subalgebra of g, which is the maximal abelian subalgebra, and consider the adjoint action of g on this subalgebra. There is a root system associated with this action. Now, a root system over a vector space V is a set of finite vectors Phi (called roots), which satisfy: 1. The roots span V 2. The only scalar multiples of x in Phi are x and -x 3. For every x in Phi, the set Phi is closed under reflection through the hyperplane perpendicular to x. 4. If x and y are roots in Phi, then the projection of y onto the line through x is a half-integral multiple of x. Now, there is a subset of Phi, which we will call Delta, such that: 1. Delta is a basis of V 2. Each root x in Phi can be written x = sum k_y y for y in Delta The elements of Delta are called the simple roots. Therefore, we see that the simple roots span the root space of a given simple Lie algebra. References: https://en.wikipedia.org/wiki/Root_system Lie Algebras and Representation Theory - Humphreys """ def __new__(cls, cartantype): """Create a new RootSystem object This method assigns an attribute called cartan_type to each instance of a RootSystem object. When an instance of RootSystem is called, it needs an argument, which should be an instance of a simple Lie algebra. We then take the CartanType of this argument and set it as the cartan_type attribute of the RootSystem instance. """ obj = Basic.__new__(cls, cartantype) obj.cartan_type = CartanType(cartantype) return obj def simple_roots(self): """Generate the simple roots of the Lie algebra The rank of the Lie algebra determines the number of simple roots that it has. This method obtains the rank of the Lie algebra, and then uses the simple_root method from the Lie algebra classes to generate all the simple roots. Examples ======== >>> from sympy.liealgebras.root_system import RootSystem >>> c = RootSystem("A3") >>> roots = c.simple_roots() >>> roots {1: [1, -1, 0, 0], 2: [0, 1, -1, 0], 3: [0, 0, 1, -1]} """ n = self.cartan_type.rank() roots = {} for i in range(1, n+1): root = self.cartan_type.simple_root(i) roots[i] = root return roots def all_roots(self): """Generate all the roots of a given root system The result is a dictionary where the keys are integer numbers. It generates the roots by getting the dictionary of all positive roots from the bases classes, and then taking each root, and multiplying it by -1 and adding it to the dictionary. In this way all the negative roots are generated. """ alpha = self.cartan_type.positive_roots() keys = list(alpha.keys()) k = max(keys) for val in keys: k += 1 root = alpha[val] newroot = [-x for x in root] alpha[k] = newroot return alpha def root_space(self): """Return the span of the simple roots The root space is the vector space spanned by the simple roots, i.e. it is a vector space with a distinguished basis, the simple roots. This method returns a string that represents the root space as the span of the simple roots, alpha[1],...., alpha[n]. Examples ======== >>> from sympy.liealgebras.root_system import RootSystem >>> c = RootSystem("A3") >>> c.root_space() 'alpha[1] + alpha[2] + alpha[3]' """ n = self.cartan_type.rank() rs = " + ".join("alpha["+str(i) +"]" for i in range(1, n+1)) return rs def add_simple_roots(self, root1, root2): """Add two simple roots together The function takes as input two integers, root1 and root2. It then uses these integers as keys in the dictionary of simple roots, and gets the corresponding simple roots, and then adds them together. Examples ======== >>> from sympy.liealgebras.root_system import RootSystem >>> c = RootSystem("A3") >>> newroot = c.add_simple_roots(1, 2) >>> newroot [1, 0, -1, 0] """ alpha = self.simple_roots() if root1 > len(alpha) or root2 > len(alpha): raise ValueError("You've used a root that doesn't exist!") a1 = alpha[root1] a2 = alpha[root2] newroot = [] length = len(a1) for i in range(length): newroot.append(a1[i] + a2[i]) return newroot def add_as_roots(self, root1, root2): """Add two roots together if and only if their sum is also a root It takes as input two vectors which should be roots. It then computes their sum and checks if it is in the list of all possible roots. If it is, it returns the sum. Otherwise it returns a string saying that the sum is not a root. Examples ======== >>> from sympy.liealgebras.root_system import RootSystem >>> c = RootSystem("A3") >>> c.add_as_roots([1, 0, -1, 0], [0, 0, 1, -1]) [1, 0, 0, -1] >>> c.add_as_roots([1, -1, 0, 0], [0, 0, -1, 1]) 'The sum of these two roots is not a root' """ alpha = self.all_roots() newroot = [] for entry in range(len(root1)): newroot.append(root1[entry] + root2[entry]) if newroot in alpha.values(): return newroot else: return "The sum of these two roots is not a root" def cartan_matrix(self): """Cartan matrix of Lie algebra associated with this root system Examples ======== >>> from sympy.liealgebras.root_system import RootSystem >>> c = RootSystem("A3") >>> c.cartan_matrix() Matrix([ [ 2, -1, 0], [-1, 2, -1], [ 0, -1, 2]]) """ return self.cartan_type.cartan_matrix() def dynkin_diagram(self): """Dynkin diagram of the Lie algebra associated with this root system Examples ======== >>> from sympy.liealgebras.root_system import RootSystem >>> c = RootSystem("A3") >>> print(c.dynkin_diagram()) 0---0---0 1 2 3 """ return self.cartan_type.dynkin_diagram() sympy-sympy-1.9/sympy/liealgebras/tests/000077500000000000000000000000001412543434000205205ustar00rootroot00000000000000sympy-sympy-1.9/sympy/liealgebras/tests/__init__.py000066400000000000000000000000001412543434000226170ustar00rootroot00000000000000sympy-sympy-1.9/sympy/liealgebras/tests/test_cartan_matrix.py000066400000000000000000000004571412543434000247730ustar00rootroot00000000000000from sympy.liealgebras.cartan_matrix import CartanMatrix from sympy.matrices import Matrix def test_CartanMatrix(): c = CartanMatrix("A3") m = Matrix(3, 3, [2, -1, 0, -1, 2, -1, 0, -1, 2]) assert c == m a = CartanMatrix(["G",2]) mt = Matrix(2, 2, [2, -1, -3, 2]) assert a == mt sympy-sympy-1.9/sympy/liealgebras/tests/test_cartan_type.py000066400000000000000000000005231412543434000244420ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType, Standard_Cartan def test_Standard_Cartan(): c = CartanType("A4") assert c.rank() == 4 assert c.series == "A" m = Standard_Cartan("A", 2) assert m.rank() == 2 assert m.series == "A" b = CartanType("B12") assert b.rank() == 12 assert b.series == "B" sympy-sympy-1.9/sympy/liealgebras/tests/test_dynkin_diagram.py000066400000000000000000000004041412543434000251070ustar00rootroot00000000000000from sympy.liealgebras.dynkin_diagram import DynkinDiagram def test_DynkinDiagram(): c = DynkinDiagram("A3") diag = "0---0---0\n1 2 3" assert c == diag ct = DynkinDiagram(["B", 3]) diag2 = "0---0=>=0\n1 2 3" assert ct == diag2 sympy-sympy-1.9/sympy/liealgebras/tests/test_root_system.py000066400000000000000000000016371412543434000245270ustar00rootroot00000000000000from sympy.liealgebras.root_system import RootSystem from sympy.liealgebras.type_a import TypeA from sympy.matrices import Matrix def test_root_system(): c = RootSystem("A3") assert c.cartan_type == TypeA(3) assert c.simple_roots() == {1: [1, -1, 0, 0], 2: [0, 1, -1, 0], 3: [0, 0, 1, -1]} assert c.root_space() == "alpha[1] + alpha[2] + alpha[3]" assert c.cartan_matrix() == Matrix([[ 2, -1, 0], [-1, 2, -1], [ 0, -1, 2]]) assert c.dynkin_diagram() == "0---0---0\n1 2 3" assert c.add_simple_roots(1, 2) == [1, 0, -1, 0] assert c.all_roots() == {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1], 7: [-1, 1, 0, 0], 8: [-1, 0, 1, 0], 9: [-1, 0, 0, 1], 10: [0, -1, 1, 0], 11: [0, -1, 0, 1], 12: [0, 0, -1, 1]} assert c.add_as_roots([1, 0, -1, 0], [0, 0, 1, -1]) == [1, 0, 0, -1] sympy-sympy-1.9/sympy/liealgebras/tests/test_type_A.py000066400000000000000000000012211412543434000233460ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType from sympy.matrices import Matrix def test_type_A(): c = CartanType("A3") m = Matrix(3, 3, [2, -1, 0, -1, 2, -1, 0, -1, 2]) assert m == c.cartan_matrix() assert c.basis() == 8 assert c.roots() == 12 assert c.dimension() == 4 assert c.simple_root(1) == [1, -1, 0, 0] assert c.highest_root() == [1, 0, 0, -1] assert c.lie_algebra() == "su(4)" diag = "0---0---0\n1 2 3" assert c.dynkin_diagram() == diag assert c.positive_roots() == {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} sympy-sympy-1.9/sympy/liealgebras/tests/test_type_B.py000066400000000000000000000012021412543434000233460ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType from sympy.matrices import Matrix def test_type_B(): c = CartanType("B3") m = Matrix(3, 3, [2, -1, 0, -1, 2, -2, 0, -1, 2]) assert m == c.cartan_matrix() assert c.dimension() == 3 assert c.roots() == 18 assert c.simple_root(3) == [0, 0, 1] assert c.basis() == 3 assert c.lie_algebra() == "so(6)" diag = "0---0=>=0\n1 2 3" assert c.dynkin_diagram() == diag assert c.positive_roots() == {1: [1, -1, 0], 2: [1, 1, 0], 3: [1, 0, -1], 4: [1, 0, 1], 5: [0, 1, -1], 6: [0, 1, 1], 7: [1, 0, 0], 8: [0, 1, 0], 9: [0, 0, 1]} sympy-sympy-1.9/sympy/liealgebras/tests/test_type_C.py000066400000000000000000000016371412543434000233630ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType from sympy.matrices import Matrix def test_type_C(): c = CartanType("C4") m = Matrix(4, 4, [2, -1, 0, 0, -1, 2, -1, 0, 0, -1, 2, -1, 0, 0, -2, 2]) assert c.cartan_matrix() == m assert c.dimension() == 4 assert c.simple_root(4) == [0, 0, 0, 2] assert c.roots() == 32 assert c.basis() == 36 assert c.lie_algebra() == "sp(8)" t = CartanType(['C', 3]) assert t.dimension() == 3 diag = "0---0---0=<=0\n1 2 3 4" assert c.dynkin_diagram() == diag assert c.positive_roots() == {1: [1, -1, 0, 0], 2: [1, 1, 0, 0], 3: [1, 0, -1, 0], 4: [1, 0, 1, 0], 5: [1, 0, 0, -1], 6: [1, 0, 0, 1], 7: [0, 1, -1, 0], 8: [0, 1, 1, 0], 9: [0, 1, 0, -1], 10: [0, 1, 0, 1], 11: [0, 0, 1, -1], 12: [0, 0, 1, 1], 13: [2, 0, 0, 0], 14: [0, 2, 0, 0], 15: [0, 0, 2, 0], 16: [0, 0, 0, 2]} sympy-sympy-1.9/sympy/liealgebras/tests/test_type_D.py000066400000000000000000000013751412543434000233630ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType from sympy.matrices import Matrix def test_type_D(): c = CartanType("D4") m = Matrix(4, 4, [2, -1, 0, 0, -1, 2, -1, -1, 0, -1, 2, 0, 0, -1, 0 , 2]) assert c.cartan_matrix() == m assert c.basis() == 6 assert c.lie_algebra() == "so(8)" assert c.roots() == 24 assert c.simple_root(3) == [0, 0, 1, -1] diag = " 3\n 0\n |\n |\n0---0---0\n1 2 4" assert diag == c.dynkin_diagram() assert c.positive_roots() == {1: [1, -1, 0, 0], 2: [1, 1, 0, 0], 3: [1, 0, -1, 0], 4: [1, 0, 1, 0], 5: [1, 0, 0, -1], 6: [1, 0, 0, 1], 7: [0, 1, -1, 0], 8: [0, 1, 1, 0], 9: [0, 1, 0, -1], 10: [0, 1, 0, 1], 11: [0, 0, 1, -1], 12: [0, 0, 1, 1]} sympy-sympy-1.9/sympy/liealgebras/tests/test_type_E.py000066400000000000000000000014071412543434000233600ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType from sympy.matrices import Matrix def test_type_E(): c = CartanType("E6") m = Matrix(6, 6, [2, 0, -1, 0, 0, 0, 0, 2, 0, -1, 0, 0, -1, 0, 2, -1, 0, 0, 0, -1, -1, 2, -1, 0, 0, 0, 0, -1, 2, -1, 0, 0, 0, 0, -1, 2]) assert c.cartan_matrix() == m assert c.dimension() == 8 assert c.simple_root(6) == [0, 0, 0, -1, 1, 0, 0, 0] assert c.roots() == 72 assert c.basis() == 78 diag = " "*8 + "2\n" + " "*8 + "0\n" + " "*8 + "|\n" + " "*8 + "|\n" diag += "---".join("0" for i in range(1, 6))+"\n" diag += "1 " + " ".join(str(i) for i in range(3, 7)) assert c.dynkin_diagram() == diag posroots = c.positive_roots() assert posroots[8] == [1, 0, 0, 0, 1, 0, 0, 0] sympy-sympy-1.9/sympy/liealgebras/tests/test_type_F.py000066400000000000000000000025421412543434000233620ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import CartanType from sympy.matrices import Matrix from sympy.core.backend import S def test_type_F(): c = CartanType("F4") m = Matrix(4, 4, [2, -1, 0, 0, -1, 2, -2, 0, 0, -1, 2, -1, 0, 0, -1, 2]) assert c.cartan_matrix() == m assert c.dimension() == 4 assert c.simple_root(1) == [1, -1, 0, 0] assert c.simple_root(2) == [0, 1, -1, 0] assert c.simple_root(3) == [0, 0, 0, 1] assert c.simple_root(4) == [-S.Half, -S.Half, -S.Half, -S.Half] assert c.roots() == 48 assert c.basis() == 52 diag = "0---0=>=0---0\n" + " ".join(str(i) for i in range(1, 5)) assert c.dynkin_diagram() == diag assert c.positive_roots() == {1: [1, -1, 0, 0], 2: [1, 1, 0, 0], 3: [1, 0, -1, 0], 4: [1, 0, 1, 0], 5: [1, 0, 0, -1], 6: [1, 0, 0, 1], 7: [0, 1, -1, 0], 8: [0, 1, 1, 0], 9: [0, 1, 0, -1], 10: [0, 1, 0, 1], 11: [0, 0, 1, -1], 12: [0, 0, 1, 1], 13: [1, 0, 0, 0], 14: [0, 1, 0, 0], 15: [0, 0, 1, 0], 16: [0, 0, 0, 1], 17: [S.Half, S.Half, S.Half, S.Half], 18: [S.Half, -S.Half, S.Half, S.Half], 19: [S.Half, S.Half, -S.Half, S.Half], 20: [S.Half, S.Half, S.Half, -S.Half], 21: [S.Half, S.Half, -S.Half, -S.Half], 22: [S.Half, -S.Half, S.Half, -S.Half], 23: [S.Half, -S.Half, -S.Half, S.Half], 24: [S.Half, -S.Half, -S.Half, -S.Half]} sympy-sympy-1.9/sympy/liealgebras/tests/test_type_G.py000066400000000000000000000010441412543434000233570ustar00rootroot00000000000000# coding=utf-8 from sympy.liealgebras.cartan_type import CartanType from sympy.matrices import Matrix def test_type_G(): c = CartanType("G2") m = Matrix(2, 2, [2, -1, -3, 2]) assert c.cartan_matrix() == m assert c.simple_root(2) == [1, -2, 1] assert c.basis() == 14 assert c.roots() == 12 assert c.dimension() == 3 diag = "0≡<≡0\n1 2" assert diag == c.dynkin_diagram() assert c.positive_roots() == {1: [0, 1, -1], 2: [1, -2, 1], 3: [1, -1, 0], 4: [1, 0, 1], 5: [1, 1, -2], 6: [2, -1, -1]} sympy-sympy-1.9/sympy/liealgebras/tests/test_weyl_group.py000066400000000000000000000027351412543434000243340ustar00rootroot00000000000000from sympy.liealgebras.weyl_group import WeylGroup from sympy.matrices import Matrix def test_weyl_group(): c = WeylGroup("A3") assert c.matrix_form('r1*r2') == Matrix([[0, 0, 1, 0], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) assert c.generators() == ['r1', 'r2', 'r3'] assert c.group_order() == 24.0 assert c.group_name() == "S4: the symmetric group acting on 4 elements." assert c.coxeter_diagram() == "0---0---0\n1 2 3" assert c.element_order('r1*r2*r3') == 4 assert c.element_order('r1*r3*r2*r3') == 3 d = WeylGroup("B5") assert d.group_order() == 3840 assert d.element_order('r1*r2*r4*r5') == 12 assert d.matrix_form('r2*r3') == Matrix([[0, 0, 1, 0, 0], [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]) assert d.element_order('r1*r2*r1*r3*r5') == 6 e = WeylGroup("D5") assert e.element_order('r2*r3*r5') == 4 assert e.matrix_form('r2*r3*r5') == Matrix([[1, 0, 0, 0, 0], [0, 0, 0, 0, -1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, -1, 0]]) f = WeylGroup("G2") assert f.element_order('r1*r2*r1*r2') == 3 assert f.element_order('r2*r1*r1*r2') == 1 assert f.matrix_form('r1*r2*r1*r2') == Matrix([[0, 1, 0], [0, 0, 1], [1, 0, 0]]) g = WeylGroup("F4") assert g.matrix_form('r2*r3') == Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1], [0, 0, 1, 0]]) assert g.element_order('r2*r3') == 4 h = WeylGroup("E6") assert h.group_order() == 51840 sympy-sympy-1.9/sympy/liealgebras/type_a.py000066400000000000000000000103331412543434000212110ustar00rootroot00000000000000from sympy.liealgebras.cartan_type import Standard_Cartan from sympy.core.backend import eye class TypeA(Standard_Cartan): """ This class contains the information about the A series of simple Lie algebras. ==== """ def __new__(cls, n): if n < 1: raise ValueError("n can not be less than 1") return Standard_Cartan.__new__(cls, "A", n) def dimension(self): """Dimension of the vector space V underlying the Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A4") >>> c.dimension() 5 """ return self.n+1 def basic_root(self, i, j): """ This is a method just to generate roots with a 1 iin the ith position and a -1 in the jth position. """ n = self.n root = [0]*(n+1) root[i] = 1 root[j] = -1 return root def simple_root(self, i): """ Every lie algebra has a unique root system. Given a root system Q, there is a subset of the roots such that an element of Q is called a simple root if it cannot be written as the sum of two elements in Q. If we let D denote the set of simple roots, then it is clear that every element of Q can be written as a linear combination of elements of D with all coefficients non-negative. In A_n the ith simple root is the root which has a 1 in the ith position, a -1 in the (i+1)th position, and zeroes elsewhere. This method returns the ith simple root for the A series. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A4") >>> c.simple_root(1) [1, -1, 0, 0, 0] """ return self.basic_root(i-1, i) def positive_roots(self): """ This method generates all the positive roots of A_n. This is half of all of the roots of A_n; by multiplying all the positive roots by -1 we get the negative roots. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A3") >>> c.positive_roots() {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} """ n = self.n posroots = {} k = 0 for i in range(0, n): for j in range(i+1, n+1): k += 1 posroots[k] = self.basic_root(i, j) return posroots def highest_root(self): """ Returns the highest weight root for A_n """ return self.basic_root(0, self.n) def roots(self): """ Returns the total number of roots for A_n """ n = self.n return n*(n+1) def cartan_matrix(self): """ Returns the Cartan matrix for A_n. The Cartan matrix matrix for a Lie algebra is generated by assigning an ordering to the simple roots, (alpha[1], ...., alpha[l]). Then the ijth entry of the Cartan matrix is (). Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType('A4') >>> c.cartan_matrix() Matrix([ [ 2, -1, 0, 0], [-1, 2, -1, 0], [ 0, -1, 2, -1], [ 0, 0, -1, 2]]) """ n = self.n m = 2 * eye(n) i = 1 while i < n-1: m[i, i+1] = -1 m[i, i-1] = -1 i += 1 m[0,1] = -1 m[n-1, n-2] = -1 return m def basis(self): """ Returns the number of independent generators of A_n """ n = self.n return n**2 - 1 def lie_algebra(self): """ Returns the Lie algebra associated with A_n """ n = self.n return "su(" + str(n + 1) + ")" def dynkin_diagram(self): n = self.n diag = "---".join("0" for i in range(1, n+1)) + "\n" diag += " ".join(str(i) for i in range(1, n+1)) return diag sympy-sympy-1.9/sympy/liealgebras/type_b.py000066400000000000000000000107241412543434000212160ustar00rootroot00000000000000from .cartan_type import Standard_Cartan from sympy.core.backend import eye class TypeB(Standard_Cartan): def __new__(cls, n): if n < 2: raise ValueError("n can not be less than 2") return Standard_Cartan.__new__(cls, "B", n) def dimension(self): """Dimension of the vector space V underlying the Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("B3") >>> c.dimension() 3 """ return self.n def basic_root(self, i, j): """ This is a method just to generate roots with a 1 iin the ith position and a -1 in the jth position. """ root = [0]*self.n root[i] = 1 root[j] = -1 return root def simple_root(self, i): """ Every lie algebra has a unique root system. Given a root system Q, there is a subset of the roots such that an element of Q is called a simple root if it cannot be written as the sum of two elements in Q. If we let D denote the set of simple roots, then it is clear that every element of Q can be written as a linear combination of elements of D with all coefficients non-negative. In B_n the first n-1 simple roots are the same as the roots in A_(n-1) (a 1 in the ith position, a -1 in the (i+1)th position, and zeroes elsewhere). The n-th simple root is the root with a 1 in the nth position and zeroes elsewhere. This method returns the ith simple root for the B series. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("B3") >>> c.simple_root(2) [0, 1, -1] """ n = self.n if i < n: return self.basic_root(i-1, i) else: root = [0]*self.n root[n-1] = 1 return root def positive_roots(self): """ This method generates all the positive roots of A_n. This is half of all of the roots of B_n; by multiplying all the positive roots by -1 we get the negative roots. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A3") >>> c.positive_roots() {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} """ n = self.n posroots = {} k = 0 for i in range(0, n-1): for j in range(i+1, n): k += 1 posroots[k] = self.basic_root(i, j) k += 1 root = self.basic_root(i, j) root[j] = 1 posroots[k] = root for i in range(0, n): k += 1 root = [0]*n root[i] = 1 posroots[k] = root return posroots def roots(self): """ Returns the total number of roots for B_n" """ n = self.n return 2*(n**2) def cartan_matrix(self): """ Returns the Cartan matrix for B_n. The Cartan matrix matrix for a Lie algebra is generated by assigning an ordering to the simple roots, (alpha[1], ...., alpha[l]). Then the ijth entry of the Cartan matrix is (). Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType('B4') >>> c.cartan_matrix() Matrix([ [ 2, -1, 0, 0], [-1, 2, -1, 0], [ 0, -1, 2, -2], [ 0, 0, -1, 2]]) """ n = self.n m = 2* eye(n) i = 1 while i < n-1: m[i, i+1] = -1 m[i, i-1] = -1 i += 1 m[0, 1] = -1 m[n-2, n-1] = -2 m[n-1, n-2] = -1 return m def basis(self): """ Returns the number of independent generators of B_n """ n = self.n return (n**2 - n)/2 def lie_algebra(self): """ Returns the Lie algebra associated with B_n """ n = self.n return "so(" + str(2*n) + ")" def dynkin_diagram(self): n = self.n diag = "---".join("0" for i in range(1, n)) + "=>=0\n" diag += " ".join(str(i) for i in range(1, n+1)) return diag sympy-sympy-1.9/sympy/liealgebras/type_c.py000066400000000000000000000105301412543434000212120ustar00rootroot00000000000000from .cartan_type import Standard_Cartan from sympy.core.backend import eye class TypeC(Standard_Cartan): def __new__(cls, n): if n < 3: raise ValueError("n can not be less than 3") return Standard_Cartan.__new__(cls, "C", n) def dimension(self): """Dimension of the vector space V underlying the Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("C3") >>> c.dimension() 3 """ n = self.n return n def basic_root(self, i, j): """Generate roots with 1 in ith position and a -1 in jth position """ n = self.n root = [0]*n root[i] = 1 root[j] = -1 return root def simple_root(self, i): """The ith simple root for the C series Every lie algebra has a unique root system. Given a root system Q, there is a subset of the roots such that an element of Q is called a simple root if it cannot be written as the sum of two elements in Q. If we let D denote the set of simple roots, then it is clear that every element of Q can be written as a linear combination of elements of D with all coefficients non-negative. In C_n, the first n-1 simple roots are the same as the roots in A_(n-1) (a 1 in the ith position, a -1 in the (i+1)th position, and zeroes elsewhere). The nth simple root is the root in which there is a 2 in the nth position and zeroes elsewhere. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("C3") >>> c.simple_root(2) [0, 1, -1] """ n = self.n if i < n: return self.basic_root(i-1,i) else: root = [0]*self.n root[n-1] = 2 return root def positive_roots(self): """Generates all the positive roots of A_n This is half of all of the roots of C_n; by multiplying all the positive roots by -1 we get the negative roots. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A3") >>> c.positive_roots() {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} """ n = self.n posroots = {} k = 0 for i in range(0, n-1): for j in range(i+1, n): k += 1 posroots[k] = self.basic_root(i, j) k += 1 root = self.basic_root(i, j) root[j] = 1 posroots[k] = root for i in range(0, n): k += 1 root = [0]*n root[i] = 2 posroots[k] = root return posroots def roots(self): """ Returns the total number of roots for C_n" """ n = self.n return 2*(n**2) def cartan_matrix(self): """The Cartan matrix for C_n The Cartan matrix matrix for a Lie algebra is generated by assigning an ordering to the simple roots, (alpha[1], ...., alpha[l]). Then the ijth entry of the Cartan matrix is (). Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType('C4') >>> c.cartan_matrix() Matrix([ [ 2, -1, 0, 0], [-1, 2, -1, 0], [ 0, -1, 2, -1], [ 0, 0, -2, 2]]) """ n = self.n m = 2 * eye(n) i = 1 while i < n-1: m[i, i+1] = -1 m[i, i-1] = -1 i += 1 m[0,1] = -1 m[n-1, n-2] = -2 return m def basis(self): """ Returns the number of independent generators of C_n """ n = self.n return n*(2*n + 1) def lie_algebra(self): """ Returns the Lie algebra associated with C_n" """ n = self.n return "sp(" + str(2*n) + ")" def dynkin_diagram(self): n = self.n diag = "---".join("0" for i in range(1, n)) + "=<=0\n" diag += " ".join(str(i) for i in range(1, n+1)) return diag sympy-sympy-1.9/sympy/liealgebras/type_d.py000066400000000000000000000111261412543434000212150ustar00rootroot00000000000000from .cartan_type import Standard_Cartan from sympy.core.backend import eye class TypeD(Standard_Cartan): def __new__(cls, n): if n < 3: raise ValueError("n cannot be less than 3") return Standard_Cartan.__new__(cls, "D", n) def dimension(self): """Dmension of the vector space V underlying the Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("D4") >>> c.dimension() 4 """ return self.n def basic_root(self, i, j): """ This is a method just to generate roots with a 1 iin the ith position and a -1 in the jth position. """ n = self.n root = [0]*n root[i] = 1 root[j] = -1 return root def simple_root(self, i): """ Every lie algebra has a unique root system. Given a root system Q, there is a subset of the roots such that an element of Q is called a simple root if it cannot be written as the sum of two elements in Q. If we let D denote the set of simple roots, then it is clear that every element of Q can be written as a linear combination of elements of D with all coefficients non-negative. In D_n, the first n-1 simple roots are the same as the roots in A_(n-1) (a 1 in the ith position, a -1 in the (i+1)th position, and zeroes elsewhere). The nth simple root is the root in which there 1s in the nth and (n-1)th positions, and zeroes elsewhere. This method returns the ith simple root for the D series. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("D4") >>> c.simple_root(2) [0, 1, -1, 0] """ n = self.n if i < n: return self.basic_root(i-1, i) else: root = [0]*n root[n-2] = 1 root[n-1] = 1 return root def positive_roots(self): """ This method generates all the positive roots of A_n. This is half of all of the roots of D_n by multiplying all the positive roots by -1 we get the negative roots. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A3") >>> c.positive_roots() {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} """ n = self.n posroots = {} k = 0 for i in range(0, n-1): for j in range(i+1, n): k += 1 posroots[k] = self.basic_root(i, j) k += 1 root = self.basic_root(i, j) root[j] = 1 posroots[k] = root return posroots def roots(self): """ Returns the total number of roots for D_n" """ n = self.n return 2*n*(n-1) def cartan_matrix(self): """ Returns the Cartan matrix for D_n. The Cartan matrix matrix for a Lie algebra is generated by assigning an ordering to the simple roots, (alpha[1], ...., alpha[l]). Then the ijth entry of the Cartan matrix is (). Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType('D4') >>> c.cartan_matrix() Matrix([ [ 2, -1, 0, 0], [-1, 2, -1, -1], [ 0, -1, 2, 0], [ 0, -1, 0, 2]]) """ n = self.n m = 2*eye(n) i = 1 while i < n-2: m[i,i+1] = -1 m[i,i-1] = -1 i += 1 m[n-2, n-3] = -1 m[n-3, n-1] = -1 m[n-1, n-3] = -1 m[0, 1] = -1 return m def basis(self): """ Returns the number of independent generators of D_n """ n = self.n return n*(n-1)/2 def lie_algebra(self): """ Returns the Lie algebra associated with D_n" """ n = self.n return "so(" + str(2*n) + ")" def dynkin_diagram(self): n = self.n diag = " "*4*(n-3) + str(n-1) + "\n" diag += " "*4*(n-3) + "0\n" diag += " "*4*(n-3) +"|\n" diag += " "*4*(n-3) + "|\n" diag += "---".join("0" for i in range(1,n)) + "\n" diag += " ".join(str(i) for i in range(1, n-1)) + " "+str(n) return diag sympy-sympy-1.9/sympy/liealgebras/type_e.py000066400000000000000000000230651412543434000212230ustar00rootroot00000000000000from .cartan_type import Standard_Cartan from sympy.core.backend import eye, Rational class TypeE(Standard_Cartan): def __new__(cls, n): if n < 6 or n > 8: raise ValueError("Invalid value of n") return Standard_Cartan.__new__(cls, "E", n) def dimension(self): """Dimension of the vector space V underlying the Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("E6") >>> c.dimension() 8 """ return 8 def basic_root(self, i, j): """ This is a method just to generate roots with a -1 in the ith position and a 1 in the jth position. """ root = [0]*8 root[i] = -1 root[j] = 1 return root def simple_root(self, i): """ Every lie algebra has a unique root system. Given a root system Q, there is a subset of the roots such that an element of Q is called a simple root if it cannot be written as the sum of two elements in Q. If we let D denote the set of simple roots, then it is clear that every element of Q can be written as a linear combination of elements of D with all coefficients non-negative. This method returns the ith simple root for E_n. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("E6") >>> c.simple_root(2) [1, 1, 0, 0, 0, 0, 0, 0] """ n = self.n if i == 1: root = [-0.5]*8 root[0] = 0.5 root[7] = 0.5 return root elif i == 2: root = [0]*8 root[1] = 1 root[0] = 1 return root else: if i == 7 or i == 8 and n == 6: raise ValueError("E6 only has six simple roots!") if i == 8 and n == 7: raise ValueError("E7 has only 7 simple roots!") return self.basic_root(i-3, i-2) def positive_roots(self): """ This method generates all the positive roots of A_n. This is half of all of the roots of E_n; by multiplying all the positive roots by -1 we get the negative roots. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A3") >>> c.positive_roots() {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} """ n = self.n if n == 6: posroots = {} k = 0 for i in range(n-1): for j in range(i+1, n-1): k += 1 root = self.basic_root(i, j) posroots[k] = root k += 1 root = self.basic_root(i, j) root[i] = 1 posroots[k] = root root = [Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(1, 2)] for a in range(0, 2): for b in range(0, 2): for c in range(0, 2): for d in range(0, 2): for e in range(0, 2): if (a + b + c + d + e)%2 == 0: k += 1 if a == 1: root[0] = Rational(-1, 2) if b == 1: root[1] = Rational(-1, 2) if c == 1: root[2] = Rational(-1, 2) if d == 1: root[3] = Rational(-1, 2) if e == 1: root[4] = Rational(-1, 2) posroots[k] = root return posroots if n == 7: posroots = {} k = 0 for i in range(n-1): for j in range(i+1, n-1): k += 1 root = self.basic_root(i, j) posroots[k] = root k += 1 root = self.basic_root(i, j) root[i] = 1 posroots[k] = root k += 1 posroots[k] = [0, 0, 0, 0, 0, 1, 1, 0] root = [Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(1, 2)] for a in range(0, 2): for b in range(0, 2): for c in range(0, 2): for d in range(0, 2): for e in range(0, 2): for f in range(0, 2): if (a + b + c + d + e + f)%2 == 0: k += 1 if a == 1: root[0] = Rational(-1, 2) if b == 1: root[1] = Rational(-1, 2) if c == 1: root[2] = Rational(-1, 2) if d == 1: root[3] = Rational(-1, 2) if e == 1: root[4] = Rational(-1, 2) if f == 1: root[5] = Rational(1, 2) posroots[k] = root return posroots if n == 8: posroots = {} k = 0 for i in range(n): for j in range(i+1, n): k += 1 root = self.basic_root(i, j) posroots[k] = root k += 1 root = self.basic_root(i, j) root[i] = 1 posroots[k] = root root = [Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(1, 2)] for a in range(0, 2): for b in range(0, 2): for c in range(0, 2): for d in range(0, 2): for e in range(0, 2): for f in range(0, 2): for g in range(0, 2): if (a + b + c + d + e + f + g)%2 == 0: k += 1 if a == 1: root[0] = Rational(-1, 2) if b == 1: root[1] = Rational(-1, 2) if c == 1: root[2] = Rational(-1, 2) if d == 1: root[3] = Rational(-1, 2) if e == 1: root[4] = Rational(-1, 2) if f == 1: root[5] = Rational(1, 2) if g == 1: root[6] = Rational(1, 2) posroots[k] = root return posroots def roots(self): """ Returns the total number of roots of E_n """ n = self.n if n == 6: return 72 if n == 7: return 126 if n == 8: return 240 def cartan_matrix(self): """ Returns the Cartan matrix for G_2 The Cartan matrix matrix for a Lie algebra is generated by assigning an ordering to the simple roots, (alpha[1], ...., alpha[l]). Then the ijth entry of the Cartan matrix is (). Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType('A4') >>> c.cartan_matrix() Matrix([ [ 2, -1, 0, 0], [-1, 2, -1, 0], [ 0, -1, 2, -1], [ 0, 0, -1, 2]]) """ n = self.n m = 2*eye(n) i = 3 while i < n-1: m[i, i+1] = -1 m[i, i-1] = -1 i += 1 m[0, 2] = m[2, 0] = -1 m[1, 3] = m[3, 1] = -1 m[2, 3] = -1 m[n-1, n-2] = -1 return m def basis(self): """ Returns the number of independent generators of E_n """ n = self.n if n == 6: return 78 if n == 7: return 133 if n == 8: return 248 def dynkin_diagram(self): n = self.n diag = " "*8 + str(2) + "\n" diag += " "*8 + "0\n" diag += " "*8 + "|\n" diag += " "*8 + "|\n" diag += "---".join("0" for i in range(1, n)) + "\n" diag += "1 " + " ".join(str(i) for i in range(3, n+1)) return diag sympy-sympy-1.9/sympy/liealgebras/type_f.py000066400000000000000000000105011412543434000212130ustar00rootroot00000000000000from .cartan_type import Standard_Cartan from sympy.core.backend import Matrix, Rational class TypeF(Standard_Cartan): def __new__(cls, n): if n != 4: raise ValueError("n should be 4") return Standard_Cartan.__new__(cls, "F", 4) def dimension(self): """Dimension of the vector space V underlying the Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("F4") >>> c.dimension() 4 """ return 4 def basic_root(self, i, j): """Generate roots with 1 in ith position and -1 in jth position """ n = self.n root = [0]*n root[i] = 1 root[j] = -1 return root def simple_root(self, i): """The ith simple root of F_4 Every lie algebra has a unique root system. Given a root system Q, there is a subset of the roots such that an element of Q is called a simple root if it cannot be written as the sum of two elements in Q. If we let D denote the set of simple roots, then it is clear that every element of Q can be written as a linear combination of elements of D with all coefficients non-negative. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("F4") >>> c.simple_root(3) [0, 0, 0, 1] """ if i < 3: return self.basic_root(i-1, i) if i == 3: root = [0]*4 root[3] = 1 return root if i == 4: root = [Rational(-1, 2)]*4 return root def positive_roots(self): """Generate all the positive roots of A_n This is half of all of the roots of F_4; by multiplying all the positive roots by -1 we get the negative roots. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A3") >>> c.positive_roots() {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} """ n = self.n posroots = {} k = 0 for i in range(0, n-1): for j in range(i+1, n): k += 1 posroots[k] = self.basic_root(i, j) k += 1 root = self.basic_root(i, j) root[j] = 1 posroots[k] = root for i in range(0, n): k += 1 root = [0]*n root[i] = 1 posroots[k] = root k += 1 root = [Rational(1, 2)]*n posroots[k] = root for i in range(1, 4): k += 1 root = [Rational(1, 2)]*n root[i] = Rational(-1, 2) posroots[k] = root posroots[k+1] = [Rational(1, 2), Rational(1, 2), Rational(-1, 2), Rational(-1, 2)] posroots[k+2] = [Rational(1, 2), Rational(-1, 2), Rational(1, 2), Rational(-1, 2)] posroots[k+3] = [Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(1, 2)] posroots[k+4] = [Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(-1, 2)] return posroots def roots(self): """ Returns the total number of roots for F_4 """ return 48 def cartan_matrix(self): """The Cartan matrix for F_4 The Cartan matrix matrix for a Lie algebra is generated by assigning an ordering to the simple roots, (alpha[1], ...., alpha[l]). Then the ijth entry of the Cartan matrix is (). Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType('A4') >>> c.cartan_matrix() Matrix([ [ 2, -1, 0, 0], [-1, 2, -1, 0], [ 0, -1, 2, -1], [ 0, 0, -1, 2]]) """ m = Matrix( 4, 4, [2, -1, 0, 0, -1, 2, -2, 0, 0, -1, 2, -1, 0, 0, -1, 2]) return m def basis(self): """ Returns the number of independent generators of F_4 """ return 52 def dynkin_diagram(self): diag = "0---0=>=0---0\n" diag += " ".join(str(i) for i in range(1, 5)) return diag sympy-sympy-1.9/sympy/liealgebras/type_g.py000066400000000000000000000056251412543434000212270ustar00rootroot00000000000000# -*- coding: utf-8 -*- from .cartan_type import Standard_Cartan from sympy.core.backend import Matrix class TypeG(Standard_Cartan): def __new__(cls, n): if n != 2: raise ValueError("n should be 2") return Standard_Cartan.__new__(cls, "G", 2) def dimension(self): """Dimension of the vector space V underlying the Lie algebra Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("G2") >>> c.dimension() 3 """ return 3 def simple_root(self, i): """The ith simple root of G_2 Every lie algebra has a unique root system. Given a root system Q, there is a subset of the roots such that an element of Q is called a simple root if it cannot be written as the sum of two elements in Q. If we let D denote the set of simple roots, then it is clear that every element of Q can be written as a linear combination of elements of D with all coefficients non-negative. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("G2") >>> c.simple_root(1) [0, 1, -1] """ if i == 1: return [0, 1, -1] else: return [1, -2, 1] def positive_roots(self): """Generate all the positive roots of A_n This is half of all of the roots of A_n; by multiplying all the positive roots by -1 we get the negative roots. Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("A3") >>> c.positive_roots() {1: [1, -1, 0, 0], 2: [1, 0, -1, 0], 3: [1, 0, 0, -1], 4: [0, 1, -1, 0], 5: [0, 1, 0, -1], 6: [0, 0, 1, -1]} """ roots = {1: [0, 1, -1], 2: [1, -2, 1], 3: [1, -1, 0], 4: [1, 0, 1], 5: [1, 1, -2], 6: [2, -1, -1]} return roots def roots(self): """ Returns the total number of roots of G_2" """ return 12 def cartan_matrix(self): """The Cartan matrix for G_2 The Cartan matrix matrix for a Lie algebra is generated by assigning an ordering to the simple roots, (alpha[1], ...., alpha[l]). Then the ijth entry of the Cartan matrix is (). Examples ======== >>> from sympy.liealgebras.cartan_type import CartanType >>> c = CartanType("G2") >>> c.cartan_matrix() Matrix([ [ 2, -1], [-3, 2]]) """ m = Matrix( 2, 2, [2, -1, -3, 2]) return m def basis(self): """ Returns the number of independent generators of G_2 """ return 14 def dynkin_diagram(self): diag = "0≡<≡0\n1 2" return diag sympy-sympy-1.9/sympy/liealgebras/weyl_group.py000066400000000000000000000346051412543434000221340ustar00rootroot00000000000000# -*- coding: utf-8 -*- from .cartan_type import CartanType from mpmath import fac from sympy.core.backend import Matrix, eye, Rational, Basic, igcd class WeylGroup(Basic): """ For each semisimple Lie group, we have a Weyl group. It is a subgroup of the isometry group of the root system. Specifically, it's the subgroup that is generated by reflections through the hyperplanes orthogonal to the roots. Therefore, Weyl groups are reflection groups, and so a Weyl group is a finite Coxeter group. """ def __new__(cls, cartantype): obj = Basic.__new__(cls, cartantype) obj.cartan_type = CartanType(cartantype) return obj def generators(self): """ This method creates the generating reflections of the Weyl group for a given Lie algebra. For a Lie algebra of rank n, there are n different generating reflections. This function returns them as a list. Examples ======== >>> from sympy.liealgebras.weyl_group import WeylGroup >>> c = WeylGroup("F4") >>> c.generators() ['r1', 'r2', 'r3', 'r4'] """ n = self.cartan_type.rank() generators = [] for i in range(1, n+1): reflection = "r"+str(i) generators.append(reflection) return generators def group_order(self): """ This method returns the order of the Weyl group. For types A, B, C, D, and E the order depends on the rank of the Lie algebra. For types F and G, the order is fixed. Examples ======== >>> from sympy.liealgebras.weyl_group import WeylGroup >>> c = WeylGroup("D4") >>> c.group_order() 192.0 """ n = self.cartan_type.rank() if self.cartan_type.series == "A": return fac(n+1) if self.cartan_type.series == "B" or self.cartan_type.series == "C": return fac(n)*(2**n) if self.cartan_type.series == "D": return fac(n)*(2**(n-1)) if self.cartan_type.series == "E": if n == 6: return 51840 if n == 7: return 2903040 if n == 8: return 696729600 if self.cartan_type.series == "F": return 1152 if self.cartan_type.series == "G": return 12 def group_name(self): """ This method returns some general information about the Weyl group for a given Lie algebra. It returns the name of the group and the elements it acts on, if relevant. """ n = self.cartan_type.rank() if self.cartan_type.series == "A": return "S"+str(n+1) + ": the symmetric group acting on " + str(n+1) + " elements." if self.cartan_type.series == "B" or self.cartan_type.series == "C": return "The hyperoctahedral group acting on " + str(2*n) + " elements." if self.cartan_type.series == "D": return "The symmetry group of the " + str(n) + "-dimensional demihypercube." if self.cartan_type.series == "E": if n == 6: return "The symmetry group of the 6-polytope." if n == 7: return "The symmetry group of the 7-polytope." if n == 8: return "The symmetry group of the 8-polytope." if self.cartan_type.series == "F": return "The symmetry group of the 24-cell, or icositetrachoron." if self.cartan_type.series == "G": return "D6, the dihedral group of order 12, and symmetry group of the hexagon." def element_order(self, weylelt): """ This method returns the order of a given Weyl group element, which should be specified by the user in the form of products of the generating reflections, i.e. of the form r1*r2 etc. For types A-F, this method current works by taking the matrix form of the specified element, and then finding what power of the matrix is the identity. It then returns this power. Examples ======== >>> from sympy.liealgebras.weyl_group import WeylGroup >>> b = WeylGroup("B4") >>> b.element_order('r1*r4*r2') 4 """ n = self.cartan_type.rank() if self.cartan_type.series == "A": a = self.matrix_form(weylelt) order = 1 while a != eye(n+1): a *= self.matrix_form(weylelt) order += 1 return order if self.cartan_type.series == "D": a = self.matrix_form(weylelt) order = 1 while a != eye(n): a *= self.matrix_form(weylelt) order += 1 return order if self.cartan_type.series == "E": a = self.matrix_form(weylelt) order = 1 while a != eye(8): a *= self.matrix_form(weylelt) order += 1 return order if self.cartan_type.series == "G": elts = list(weylelt) reflections = elts[1::3] m = self.delete_doubles(reflections) while self.delete_doubles(m) != m: m = self.delete_doubles(m) reflections = m if len(reflections) % 2 == 1: return 2 elif len(reflections) == 0: return 1 else: if len(reflections) == 1: return 2 else: m = len(reflections) // 2 lcm = (6 * m)/ igcd(m, 6) order = lcm / m return order if self.cartan_type.series == 'F': a = self.matrix_form(weylelt) order = 1 while a != eye(4): a *= self.matrix_form(weylelt) order += 1 return order if self.cartan_type.series == "B" or self.cartan_type.series == "C": a = self.matrix_form(weylelt) order = 1 while a != eye(n): a *= self.matrix_form(weylelt) order += 1 return order def delete_doubles(self, reflections): """ This is a helper method for determining the order of an element in the Weyl group of G2. It takes a Weyl element and if repeated simple reflections in it, it deletes them. """ counter = 0 copy = list(reflections) for elt in copy: if counter < len(copy)-1: if copy[counter + 1] == elt: del copy[counter] del copy[counter] counter += 1 return copy def matrix_form(self, weylelt): """ This method takes input from the user in the form of products of the generating reflections, and returns the matrix corresponding to the element of the Weyl group. Since each element of the Weyl group is a reflection of some type, there is a corresponding matrix representation. This method uses the standard representation for all the generating reflections. Examples ======== >>> from sympy.liealgebras.weyl_group import WeylGroup >>> f = WeylGroup("F4") >>> f.matrix_form('r2*r3') Matrix([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, -1], [0, 0, 1, 0]]) """ elts = list(weylelt) reflections = elts[1::3] n = self.cartan_type.rank() if self.cartan_type.series == 'A': matrixform = eye(n+1) for elt in reflections: a = int(elt) mat = eye(n+1) mat[a-1, a-1] = 0 mat[a-1, a] = 1 mat[a, a-1] = 1 mat[a, a] = 0 matrixform *= mat return matrixform if self.cartan_type.series == 'D': matrixform = eye(n) for elt in reflections: a = int(elt) mat = eye(n) if a < n: mat[a-1, a-1] = 0 mat[a-1, a] = 1 mat[a, a-1] = 1 mat[a, a] = 0 matrixform *= mat else: mat[n-2, n-1] = -1 mat[n-2, n-2] = 0 mat[n-1, n-2] = -1 mat[n-1, n-1] = 0 matrixform *= mat return matrixform if self.cartan_type.series == 'G': matrixform = eye(3) for elt in reflections: a = int(elt) if a == 1: gen1 = Matrix([[1, 0, 0], [0, 0, 1], [0, 1, 0]]) matrixform *= gen1 else: gen2 = Matrix([[Rational(2, 3), Rational(2, 3), Rational(-1, 3)], [Rational(2, 3), Rational(-1, 3), Rational(2, 3)], [Rational(-1, 3), Rational(2, 3), Rational(2, 3)]]) matrixform *= gen2 return matrixform if self.cartan_type.series == 'F': matrixform = eye(4) for elt in reflections: a = int(elt) if a == 1: mat = Matrix([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]) matrixform *= mat elif a == 2: mat = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) matrixform *= mat elif a == 3: mat = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]]) matrixform *= mat else: mat = Matrix([[Rational(1, 2), Rational(1, 2), Rational(1, 2), Rational(1, 2)], [Rational(1, 2), Rational(1, 2), Rational(-1, 2), Rational(-1, 2)], [Rational(1, 2), Rational(-1, 2), Rational(1, 2), Rational(-1, 2)], [Rational(1, 2), Rational(-1, 2), Rational(-1, 2), Rational(1, 2)]]) matrixform *= mat return matrixform if self.cartan_type.series == 'E': matrixform = eye(8) for elt in reflections: a = int(elt) if a == 1: mat = Matrix([[Rational(3, 4), Rational(1, 4), Rational(1, 4), Rational(1, 4), Rational(1, 4), Rational(1, 4), Rational(1, 4), Rational(-1, 4)], [Rational(1, 4), Rational(3, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(1, 4), Rational(-1, 4)], [Rational(1, 4), Rational(-1, 4), Rational(3, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(1, 4)], [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(3, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(1, 4)], [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(3, 4), Rational(-1, 4), Rational(-1, 4), Rational(1, 4)], [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(3, 4), Rational(-1, 4), Rational(1, 4)], [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-3, 4), Rational(1, 4)], [Rational(1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(-1, 4), Rational(3, 4)]]) matrixform *= mat elif a == 2: mat = eye(8) mat[0, 0] = 0 mat[0, 1] = -1 mat[1, 0] = -1 mat[1, 1] = 0 matrixform *= mat else: mat = eye(8) mat[a-3, a-3] = 0 mat[a-3, a-2] = 1 mat[a-2, a-3] = 1 mat[a-2, a-2] = 0 matrixform *= mat return matrixform if self.cartan_type.series == 'B' or self.cartan_type.series == 'C': matrixform = eye(n) for elt in reflections: a = int(elt) mat = eye(n) if a == 1: mat[0, 0] = -1 matrixform *= mat else: mat[a - 2, a - 2] = 0 mat[a-2, a-1] = 1 mat[a - 1, a - 2] = 1 mat[a -1, a - 1] = 0 matrixform *= mat return matrixform def coxeter_diagram(self): """ This method returns the Coxeter diagram corresponding to a Weyl group. The Coxeter diagram can be obtained from a Lie algebra's Dynkin diagram by deleting all arrows; the Coxeter diagram is the undirected graph. The vertices of the Coxeter diagram represent the generating reflections of the Weyl group, , s_i. An edge is drawn between s_i and s_j if the order m(i, j) of s_i*s_j is greater than two. If there is one edge, the order m(i, j) is 3. If there are two edges, the order m(i, j) is 4, and if there are three edges, the order m(i, j) is 6. Examples ======== >>> from sympy.liealgebras.weyl_group import WeylGroup >>> c = WeylGroup("B3") >>> print(c.coxeter_diagram()) 0---0===0 1 2 3 """ n = self.cartan_type.rank() if self.cartan_type.series == "A" or self.cartan_type.series == "D" or self.cartan_type.series == "E": return self.cartan_type.dynkin_diagram() if self.cartan_type.series == "B" or self.cartan_type.series == "C": diag = "---".join("0" for i in range(1, n)) + "===0\n" diag += " ".join(str(i) for i in range(1, n+1)) return diag if self.cartan_type.series == "F": diag = "0---0===0---0\n" diag += " ".join(str(i) for i in range(1, 5)) return diag if self.cartan_type.series == "G": diag = "0≡≡≡0\n1 2" return diag sympy-sympy-1.9/sympy/logic/000077500000000000000000000000001412543434000162015ustar00rootroot00000000000000sympy-sympy-1.9/sympy/logic/__init__.py000066400000000000000000000006421412543434000203140ustar00rootroot00000000000000from .boolalg import (to_cnf, to_dnf, to_nnf, And, Or, Not, Xor, Nand, Nor, Implies, Equivalent, ITE, POSform, SOPform, simplify_logic, bool_map, true, false) from .inference import satisfiable __all__ = [ 'to_cnf', 'to_dnf', 'to_nnf', 'And', 'Or', 'Not', 'Xor', 'Nand', 'Nor', 'Implies', 'Equivalent', 'ITE', 'POSform', 'SOPform', 'simplify_logic', 'bool_map', 'true', 'false', 'satisfiable', ] sympy-sympy-1.9/sympy/logic/algorithms/000077500000000000000000000000001412543434000203525ustar00rootroot00000000000000sympy-sympy-1.9/sympy/logic/algorithms/__init__.py000066400000000000000000000000001412543434000224510ustar00rootroot00000000000000sympy-sympy-1.9/sympy/logic/algorithms/dpll.py000066400000000000000000000217271412543434000216700ustar00rootroot00000000000000"""Implementation of DPLL algorithm Further improvements: eliminate calls to pl_true, implement branching rules, efficient unit propagation. References: - https://en.wikipedia.org/wiki/DPLL_algorithm - https://www.researchgate.net/publication/242384772_Implementations_of_the_DPLL_Algorithm """ from sympy import default_sort_key from sympy.logic.boolalg import Or, Not, conjuncts, disjuncts, to_cnf, \ to_int_repr, _find_predicates from sympy.assumptions.cnf import CNF from sympy.logic.inference import pl_true, literal_symbol def dpll_satisfiable(expr): """ Check satisfiability of a propositional sentence. It returns a model rather than True when it succeeds >>> from sympy.abc import A, B >>> from sympy.logic.algorithms.dpll import dpll_satisfiable >>> dpll_satisfiable(A & ~B) {A: True, B: False} >>> dpll_satisfiable(A & ~A) False """ if not isinstance(expr, CNF): clauses = conjuncts(to_cnf(expr)) else: clauses = expr.clauses if False in clauses: return False symbols = sorted(_find_predicates(expr), key=default_sort_key) symbols_int_repr = set(range(1, len(symbols) + 1)) clauses_int_repr = to_int_repr(clauses, symbols) result = dpll_int_repr(clauses_int_repr, symbols_int_repr, {}) if not result: return result output = {} for key in result: output.update({symbols[key - 1]: result[key]}) return output def dpll(clauses, symbols, model): """ Compute satisfiability in a partial model. Clauses is an array of conjuncts. >>> from sympy.abc import A, B, D >>> from sympy.logic.algorithms.dpll import dpll >>> dpll([A, B, D], [A, B], {D: False}) False """ # compute DP kernel P, value = find_unit_clause(clauses, model) while P: model.update({P: value}) symbols.remove(P) if not value: P = ~P clauses = unit_propagate(clauses, P) P, value = find_unit_clause(clauses, model) P, value = find_pure_symbol(symbols, clauses) while P: model.update({P: value}) symbols.remove(P) if not value: P = ~P clauses = unit_propagate(clauses, P) P, value = find_pure_symbol(symbols, clauses) # end DP kernel unknown_clauses = [] for c in clauses: val = pl_true(c, model) if val is False: return False if val is not True: unknown_clauses.append(c) if not unknown_clauses: return model if not clauses: return model P = symbols.pop() model_copy = model.copy() model.update({P: True}) model_copy.update({P: False}) symbols_copy = symbols[:] return (dpll(unit_propagate(unknown_clauses, P), symbols, model) or dpll(unit_propagate(unknown_clauses, Not(P)), symbols_copy, model_copy)) def dpll_int_repr(clauses, symbols, model): """ Compute satisfiability in a partial model. Arguments are expected to be in integer representation >>> from sympy.logic.algorithms.dpll import dpll_int_repr >>> dpll_int_repr([{1}, {2}, {3}], {1, 2}, {3: False}) False """ # compute DP kernel P, value = find_unit_clause_int_repr(clauses, model) while P: model.update({P: value}) symbols.remove(P) if not value: P = -P clauses = unit_propagate_int_repr(clauses, P) P, value = find_unit_clause_int_repr(clauses, model) P, value = find_pure_symbol_int_repr(symbols, clauses) while P: model.update({P: value}) symbols.remove(P) if not value: P = -P clauses = unit_propagate_int_repr(clauses, P) P, value = find_pure_symbol_int_repr(symbols, clauses) # end DP kernel unknown_clauses = [] for c in clauses: val = pl_true_int_repr(c, model) if val is False: return False if val is not True: unknown_clauses.append(c) if not unknown_clauses: return model P = symbols.pop() model_copy = model.copy() model.update({P: True}) model_copy.update({P: False}) symbols_copy = symbols.copy() return (dpll_int_repr(unit_propagate_int_repr(unknown_clauses, P), symbols, model) or dpll_int_repr(unit_propagate_int_repr(unknown_clauses, -P), symbols_copy, model_copy)) ### helper methods for DPLL def pl_true_int_repr(clause, model={}): """ Lightweight version of pl_true. Argument clause represents the set of args of an Or clause. This is used inside dpll_int_repr, it is not meant to be used directly. >>> from sympy.logic.algorithms.dpll import pl_true_int_repr >>> pl_true_int_repr({1, 2}, {1: False}) >>> pl_true_int_repr({1, 2}, {1: False, 2: False}) False """ result = False for lit in clause: if lit < 0: p = model.get(-lit) if p is not None: p = not p else: p = model.get(lit) if p is True: return True elif p is None: result = None return result def unit_propagate(clauses, symbol): """ Returns an equivalent set of clauses If a set of clauses contains the unit clause l, the other clauses are simplified by the application of the two following rules: 1. every clause containing l is removed 2. in every clause that contains ~l this literal is deleted Arguments are expected to be in CNF. >>> from sympy.abc import A, B, D >>> from sympy.logic.algorithms.dpll import unit_propagate >>> unit_propagate([A | B, D | ~B, B], B) [D, B] """ output = [] for c in clauses: if c.func != Or: output.append(c) continue for arg in c.args: if arg == ~symbol: output.append(Or(*[x for x in c.args if x != ~symbol])) break if arg == symbol: break else: output.append(c) return output def unit_propagate_int_repr(clauses, s): """ Same as unit_propagate, but arguments are expected to be in integer representation >>> from sympy.logic.algorithms.dpll import unit_propagate_int_repr >>> unit_propagate_int_repr([{1, 2}, {3, -2}, {2}], 2) [{3}] """ negated = {-s} return [clause - negated for clause in clauses if s not in clause] def find_pure_symbol(symbols, unknown_clauses): """ Find a symbol and its value if it appears only as a positive literal (or only as a negative) in clauses. >>> from sympy.abc import A, B, D >>> from sympy.logic.algorithms.dpll import find_pure_symbol >>> find_pure_symbol([A, B, D], [A|~B,~B|~D,D|A]) (A, True) """ for sym in symbols: found_pos, found_neg = False, False for c in unknown_clauses: if not found_pos and sym in disjuncts(c): found_pos = True if not found_neg and Not(sym) in disjuncts(c): found_neg = True if found_pos != found_neg: return sym, found_pos return None, None def find_pure_symbol_int_repr(symbols, unknown_clauses): """ Same as find_pure_symbol, but arguments are expected to be in integer representation >>> from sympy.logic.algorithms.dpll import find_pure_symbol_int_repr >>> find_pure_symbol_int_repr({1,2,3}, ... [{1, -2}, {-2, -3}, {3, 1}]) (1, True) """ all_symbols = set().union(*unknown_clauses) found_pos = all_symbols.intersection(symbols) found_neg = all_symbols.intersection([-s for s in symbols]) for p in found_pos: if -p not in found_neg: return p, True for p in found_neg: if -p not in found_pos: return -p, False return None, None def find_unit_clause(clauses, model): """ A unit clause has only 1 variable that is not bound in the model. >>> from sympy.abc import A, B, D >>> from sympy.logic.algorithms.dpll import find_unit_clause >>> find_unit_clause([A | B | D, B | ~D, A | ~B], {A:True}) (B, False) """ for clause in clauses: num_not_in_model = 0 for literal in disjuncts(clause): sym = literal_symbol(literal) if sym not in model: num_not_in_model += 1 P, value = sym, not isinstance(literal, Not) if num_not_in_model == 1: return P, value return None, None def find_unit_clause_int_repr(clauses, model): """ Same as find_unit_clause, but arguments are expected to be in integer representation. >>> from sympy.logic.algorithms.dpll import find_unit_clause_int_repr >>> find_unit_clause_int_repr([{1, 2, 3}, ... {2, -3}, {1, -2}], {1: True}) (2, False) """ bound = set(model) | {-sym for sym in model} for clause in clauses: unbound = clause - bound if len(unbound) == 1: p = unbound.pop() if p < 0: return -p, False else: return p, True return None, None sympy-sympy-1.9/sympy/logic/algorithms/dpll2.py000066400000000000000000000476331412543434000217560ustar00rootroot00000000000000"""Implementation of DPLL algorithm Features: - Clause learning - Watch literal scheme - VSIDS heuristic References: - https://en.wikipedia.org/wiki/DPLL_algorithm """ from collections import defaultdict from heapq import heappush, heappop from sympy import ordered from sympy.assumptions.cnf import EncodedCNF def dpll_satisfiable(expr, all_models=False): """ Check satisfiability of a propositional sentence. It returns a model rather than True when it succeeds. Returns a generator of all models if all_models is True. Examples ======== >>> from sympy.abc import A, B >>> from sympy.logic.algorithms.dpll2 import dpll_satisfiable >>> dpll_satisfiable(A & ~B) {A: True, B: False} >>> dpll_satisfiable(A & ~A) False """ if not isinstance(expr, EncodedCNF): exprs = EncodedCNF() exprs.add_prop(expr) expr = exprs # Return UNSAT when False (encoded as 0) is present in the CNF if {0} in expr.data: if all_models: return (f for f in [False]) return False solver = SATSolver(expr.data, expr.variables, set(), expr.symbols) models = solver._find_model() if all_models: return _all_models(models) try: return next(models) except StopIteration: return False # Uncomment to confirm the solution is valid (hitting set for the clauses) #else: #for cls in clauses_int_repr: #assert solver.var_settings.intersection(cls) def _all_models(models): satisfiable = False try: while True: yield next(models) satisfiable = True except StopIteration: if not satisfiable: yield False class SATSolver: """ Class for representing a SAT solver capable of finding a model to a boolean theory in conjunctive normal form. """ def __init__(self, clauses, variables, var_settings, symbols=None, heuristic='vsids', clause_learning='none', INTERVAL=500): self.var_settings = var_settings self.heuristic = heuristic self.is_unsatisfied = False self._unit_prop_queue = [] self.update_functions = [] self.INTERVAL = INTERVAL if symbols is None: self.symbols = list(ordered(variables)) else: self.symbols = symbols self._initialize_variables(variables) self._initialize_clauses(clauses) if 'vsids' == heuristic: self._vsids_init() self.heur_calculate = self._vsids_calculate self.heur_lit_assigned = self._vsids_lit_assigned self.heur_lit_unset = self._vsids_lit_unset self.heur_clause_added = self._vsids_clause_added # Note: Uncomment this if/when clause learning is enabled #self.update_functions.append(self._vsids_decay) else: raise NotImplementedError if 'simple' == clause_learning: self.add_learned_clause = self._simple_add_learned_clause self.compute_conflict = self.simple_compute_conflict self.update_functions.append(self.simple_clean_clauses) elif 'none' == clause_learning: self.add_learned_clause = lambda x: None self.compute_conflict = lambda: None else: raise NotImplementedError # Create the base level self.levels = [Level(0)] self._current_level.varsettings = var_settings # Keep stats self.num_decisions = 0 self.num_learned_clauses = 0 self.original_num_clauses = len(self.clauses) def _initialize_variables(self, variables): """Set up the variable data structures needed.""" self.sentinels = defaultdict(set) self.occurrence_count = defaultdict(int) self.variable_set = [False] * (len(variables) + 1) def _initialize_clauses(self, clauses): """Set up the clause data structures needed. For each clause, the following changes are made: - Unit clauses are queued for propagation right away. - Non-unit clauses have their first and last literals set as sentinels. - The number of clauses a literal appears in is computed. """ self.clauses = [] for cls in clauses: self.clauses.append(list(cls)) for i in range(len(self.clauses)): # Handle the unit clauses if 1 == len(self.clauses[i]): self._unit_prop_queue.append(self.clauses[i][0]) continue self.sentinels[self.clauses[i][0]].add(i) self.sentinels[self.clauses[i][-1]].add(i) for lit in self.clauses[i]: self.occurrence_count[lit] += 1 def _find_model(self): """ Main DPLL loop. Returns a generator of models. Variables are chosen successively, and assigned to be either True or False. If a solution is not found with this setting, the opposite is chosen and the search continues. The solver halts when every variable has a setting. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> list(l._find_model()) [{1: True, 2: False, 3: False}, {1: True, 2: True, 3: True}] >>> from sympy.abc import A, B, C >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set(), [A, B, C]) >>> list(l._find_model()) [{A: True, B: False, C: False}, {A: True, B: True, C: True}] """ # We use this variable to keep track of if we should flip a # variable setting in successive rounds flip_var = False # Check if unit prop says the theory is unsat right off the bat self._simplify() if self.is_unsatisfied: return # While the theory still has clauses remaining while True: # Perform cleanup / fixup at regular intervals if self.num_decisions % self.INTERVAL == 0: for func in self.update_functions: func() if flip_var: # We have just backtracked and we are trying to opposite literal flip_var = False lit = self._current_level.decision else: # Pick a literal to set lit = self.heur_calculate() self.num_decisions += 1 # Stopping condition for a satisfying theory if 0 == lit: yield {self.symbols[abs(lit) - 1]: lit > 0 for lit in self.var_settings} while self._current_level.flipped: self._undo() if len(self.levels) == 1: return flip_lit = -self._current_level.decision self._undo() self.levels.append(Level(flip_lit, flipped=True)) flip_var = True continue # Start the new decision level self.levels.append(Level(lit)) # Assign the literal, updating the clauses it satisfies self._assign_literal(lit) # _simplify the theory self._simplify() # Check if we've made the theory unsat if self.is_unsatisfied: self.is_unsatisfied = False # We unroll all of the decisions until we can flip a literal while self._current_level.flipped: self._undo() # If we've unrolled all the way, the theory is unsat if 1 == len(self.levels): return # Detect and add a learned clause self.add_learned_clause(self.compute_conflict()) # Try the opposite setting of the most recent decision flip_lit = -self._current_level.decision self._undo() self.levels.append(Level(flip_lit, flipped=True)) flip_var = True ######################## # Helper Methods # ######################## @property def _current_level(self): """The current decision level data structure Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{1}, {2}], {1, 2}, set()) >>> next(l._find_model()) {1: True, 2: True} >>> l._current_level.decision 0 >>> l._current_level.flipped False >>> l._current_level.var_settings {1, 2} """ return self.levels[-1] def _clause_sat(self, cls): """Check if a clause is satisfied by the current variable setting. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{1}, {-1}], {1}, set()) >>> try: ... next(l._find_model()) ... except StopIteration: ... pass >>> l._clause_sat(0) False >>> l._clause_sat(1) True """ for lit in self.clauses[cls]: if lit in self.var_settings: return True return False def _is_sentinel(self, lit, cls): """Check if a literal is a sentinel of a given clause. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> l._is_sentinel(2, 3) True >>> l._is_sentinel(-3, 1) False """ return cls in self.sentinels[lit] def _assign_literal(self, lit): """Make a literal assignment. The literal assignment must be recorded as part of the current decision level. Additionally, if the literal is marked as a sentinel of any clause, then a new sentinel must be chosen. If this is not possible, then unit propagation is triggered and another literal is added to the queue to be set in the future. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> l.var_settings {-3, -2, 1} >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l._assign_literal(-1) >>> try: ... next(l._find_model()) ... except StopIteration: ... pass >>> l.var_settings {-1} """ self.var_settings.add(lit) self._current_level.var_settings.add(lit) self.variable_set[abs(lit)] = True self.heur_lit_assigned(lit) sentinel_list = list(self.sentinels[-lit]) for cls in sentinel_list: if not self._clause_sat(cls): other_sentinel = None for newlit in self.clauses[cls]: if newlit != -lit: if self._is_sentinel(newlit, cls): other_sentinel = newlit elif not self.variable_set[abs(newlit)]: self.sentinels[-lit].remove(cls) self.sentinels[newlit].add(cls) other_sentinel = None break # Check if no sentinel update exists if other_sentinel: self._unit_prop_queue.append(other_sentinel) def _undo(self): """ _undo the changes of the most recent decision level. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> level = l._current_level >>> level.decision, level.var_settings, level.flipped (-3, {-3, -2}, False) >>> l._undo() >>> level = l._current_level >>> level.decision, level.var_settings, level.flipped (0, {1}, False) """ # Undo the variable settings for lit in self._current_level.var_settings: self.var_settings.remove(lit) self.heur_lit_unset(lit) self.variable_set[abs(lit)] = False # Pop the level off the stack self.levels.pop() ######################### # Propagation # ######################### """ Propagation methods should attempt to soundly simplify the boolean theory, and return True if any simplification occurred and False otherwise. """ def _simplify(self): """Iterate over the various forms of propagation to simplify the theory. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.variable_set [False, False, False, False] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4}} >>> l._simplify() >>> l.variable_set [False, True, False, False] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, -1: set(), 2: {0, 3}, ...3: {2, 4}} """ changed = True while changed: changed = False changed |= self._unit_prop() changed |= self._pure_literal() def _unit_prop(self): """Perform unit propagation on the current theory.""" result = len(self._unit_prop_queue) > 0 while self._unit_prop_queue: next_lit = self._unit_prop_queue.pop() if -next_lit in self.var_settings: self.is_unsatisfied = True self._unit_prop_queue = [] return False else: self._assign_literal(next_lit) return result def _pure_literal(self): """Look for pure literals and assign them when found.""" return False ######################### # Heuristics # ######################### def _vsids_init(self): """Initialize the data structures needed for the VSIDS heuristic.""" self.lit_heap = [] self.lit_scores = {} for var in range(1, len(self.variable_set)): self.lit_scores[var] = float(-self.occurrence_count[var]) self.lit_scores[-var] = float(-self.occurrence_count[-var]) heappush(self.lit_heap, (self.lit_scores[var], var)) heappush(self.lit_heap, (self.lit_scores[-var], -var)) def _vsids_decay(self): """Decay the VSIDS scores for every literal. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.lit_scores {-3: -2.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -2.0, 3: -2.0} >>> l._vsids_decay() >>> l.lit_scores {-3: -1.0, -2: -1.0, -1: 0.0, 1: 0.0, 2: -1.0, 3: -1.0} """ # We divide every literal score by 2 for a decay factor # Note: This doesn't change the heap property for lit in self.lit_scores.keys(): self.lit_scores[lit] /= 2.0 def _vsids_calculate(self): """ VSIDS Heuristic Calculation Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.lit_heap [(-2.0, -3), (-2.0, 2), (-2.0, -2), (0.0, 1), (-2.0, 3), (0.0, -1)] >>> l._vsids_calculate() -3 >>> l.lit_heap [(-2.0, -2), (-2.0, 2), (0.0, -1), (0.0, 1), (-2.0, 3)] """ if len(self.lit_heap) == 0: return 0 # Clean out the front of the heap as long the variables are set while self.variable_set[abs(self.lit_heap[0][1])]: heappop(self.lit_heap) if len(self.lit_heap) == 0: return 0 return heappop(self.lit_heap)[1] def _vsids_lit_assigned(self, lit): """Handle the assignment of a literal for the VSIDS heuristic.""" pass def _vsids_lit_unset(self, lit): """Handle the unsetting of a literal for the VSIDS heuristic. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.lit_heap [(-2.0, -3), (-2.0, 2), (-2.0, -2), (0.0, 1), (-2.0, 3), (0.0, -1)] >>> l._vsids_lit_unset(2) >>> l.lit_heap [(-2.0, -3), (-2.0, -2), (-2.0, -2), (-2.0, 2), (-2.0, 3), (0.0, -1), ...(-2.0, 2), (0.0, 1)] """ var = abs(lit) heappush(self.lit_heap, (self.lit_scores[var], var)) heappush(self.lit_heap, (self.lit_scores[-var], -var)) def _vsids_clause_added(self, cls): """Handle the addition of a new clause for the VSIDS heuristic. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.num_learned_clauses 0 >>> l.lit_scores {-3: -2.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -2.0, 3: -2.0} >>> l._vsids_clause_added({2, -3}) >>> l.num_learned_clauses 1 >>> l.lit_scores {-3: -1.0, -2: -2.0, -1: 0.0, 1: 0.0, 2: -1.0, 3: -2.0} """ self.num_learned_clauses += 1 for lit in cls: self.lit_scores[lit] += 1 ######################## # Clause Learning # ######################## def _simple_add_learned_clause(self, cls): """Add a new clause to the theory. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> l.num_learned_clauses 0 >>> l.clauses [[2, -3], [1], [3, -3], [2, -2], [3, -2]] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4}} >>> l._simple_add_learned_clause([3]) >>> l.clauses [[2, -3], [1], [3, -3], [2, -2], [3, -2], [3]] >>> l.sentinels {-3: {0, 2}, -2: {3, 4}, 2: {0, 3}, 3: {2, 4, 5}} """ cls_num = len(self.clauses) self.clauses.append(cls) for lit in cls: self.occurrence_count[lit] += 1 self.sentinels[cls[0]].add(cls_num) self.sentinels[cls[-1]].add(cls_num) self.heur_clause_added(cls) def _simple_compute_conflict(self): """ Build a clause representing the fact that at least one decision made so far is wrong. Examples ======== >>> from sympy.logic.algorithms.dpll2 import SATSolver >>> l = SATSolver([{2, -3}, {1}, {3, -3}, {2, -2}, ... {3, -2}], {1, 2, 3}, set()) >>> next(l._find_model()) {1: True, 2: False, 3: False} >>> l._simple_compute_conflict() [3] """ return [-(level.decision) for level in self.levels[1:]] def _simple_clean_clauses(self): """Clean up learned clauses.""" pass class Level: """ Represents a single level in the DPLL algorithm, and contains enough information for a sound backtracking procedure. """ def __init__(self, decision, flipped=False): self.decision = decision self.var_settings = set() self.flipped = flipped sympy-sympy-1.9/sympy/logic/algorithms/minisat22_wrapper.py000066400000000000000000000024451412543434000243010ustar00rootroot00000000000000from sympy.assumptions.cnf import EncodedCNF def minisat22_satisfiable(expr, all_models=False, minimal=False): if not isinstance(expr, EncodedCNF): exprs = EncodedCNF() exprs.add_prop(expr) expr = exprs from pysat.solvers import Minisat22 # Return UNSAT when False (encoded as 0) is present in the CNF if {0} in expr.data: if all_models: return (f for f in [False]) return False r = Minisat22(expr.data) if minimal: r.set_phases([-(i+1) for i in range(r.nof_vars())]) if not r.solve(): return False if not all_models: return {expr.symbols[abs(lit) - 1]: lit > 0 for lit in r.get_model()} else: # Make solutions sympy compatible by creating a generator def _gen(results): satisfiable = False while results.solve(): sol = results.get_model() yield {expr.symbols[abs(lit) - 1]: lit > 0 for lit in sol} if minimal: results.add_clause([-i for i in sol if i>0]) else: results.add_clause([-i for i in sol]) satisfiable = True if not satisfiable: yield False raise StopIteration return _gen(r) sympy-sympy-1.9/sympy/logic/algorithms/pycosat_wrapper.py000066400000000000000000000022671412543434000241550ustar00rootroot00000000000000from sympy.assumptions.cnf import EncodedCNF def pycosat_satisfiable(expr, all_models=False): import pycosat if not isinstance(expr, EncodedCNF): exprs = EncodedCNF() exprs.add_prop(expr) expr = exprs # Return UNSAT when False (encoded as 0) is present in the CNF if {0} in expr.data: if all_models: return (f for f in [False]) return False if not all_models: r = pycosat.solve(expr.data) result = (r != "UNSAT") if not result: return result return {expr.symbols[abs(lit) - 1]: lit > 0 for lit in r} else: r = pycosat.itersolve(expr.data) result = (r != "UNSAT") if not result: return result # Make solutions sympy compatible by creating a generator def _gen(results): satisfiable = False try: while True: sol = next(results) yield {expr.symbols[abs(lit) - 1]: lit > 0 for lit in sol} satisfiable = True except StopIteration: if not satisfiable: yield False return _gen(r) sympy-sympy-1.9/sympy/logic/boolalg.py000066400000000000000000002773231412543434000202100ustar00rootroot00000000000000""" Boolean algebra module for SymPy """ from collections import defaultdict from itertools import chain, combinations, product from sympy.core.add import Add from sympy.core.basic import Basic from sympy.core.cache import cacheit from sympy.core.compatibility import ordered, as_int from sympy.core.decorators import sympify_method_args, sympify_return from sympy.core.function import Application, Derivative from sympy.core.numbers import Number from sympy.core.operations import LatticeOp from sympy.core.singleton import Singleton, S from sympy.core.sympify import converter, _sympify, sympify from sympy.core.kind import BooleanKind from sympy.utilities.iterables import sift, ibin from sympy.utilities.misc import filldedent def as_Boolean(e): """Like bool, return the Boolean value of an expression, e, which can be any instance of Boolean or bool. Examples ======== >>> from sympy import true, false, nan >>> from sympy.logic.boolalg import as_Boolean >>> from sympy.abc import x >>> as_Boolean(0) is false True >>> as_Boolean(1) is true True >>> as_Boolean(x) x >>> as_Boolean(2) Traceback (most recent call last): ... TypeError: expecting bool or Boolean, not `2`. >>> as_Boolean(nan) Traceback (most recent call last): ... TypeError: expecting bool or Boolean, not `nan`. """ from sympy.core.symbol import Symbol if e == True: return S.true if e == False: return S.false if isinstance(e, Symbol): z = e.is_zero if z is None: return e return S.false if z else S.true if isinstance(e, Boolean): return e raise TypeError('expecting bool or Boolean, not `%s`.' % e) @sympify_method_args class Boolean(Basic): """A boolean object is an object for which logic operations make sense.""" __slots__ = () kind = BooleanKind @sympify_return([('other', 'Boolean')], NotImplemented) def __and__(self, other): return And(self, other) __rand__ = __and__ @sympify_return([('other', 'Boolean')], NotImplemented) def __or__(self, other): return Or(self, other) __ror__ = __or__ def __invert__(self): """Overloading for ~""" return Not(self) @sympify_return([('other', 'Boolean')], NotImplemented) def __rshift__(self, other): return Implies(self, other) @sympify_return([('other', 'Boolean')], NotImplemented) def __lshift__(self, other): return Implies(other, self) __rrshift__ = __lshift__ __rlshift__ = __rshift__ @sympify_return([('other', 'Boolean')], NotImplemented) def __xor__(self, other): return Xor(self, other) __rxor__ = __xor__ def equals(self, other): """ Returns True if the given formulas have the same truth table. For two formulas to be equal they must have the same literals. Examples ======== >>> from sympy.abc import A, B, C >>> from sympy.logic.boolalg import And, Or, Not >>> (A >> B).equals(~B >> ~A) True >>> Not(And(A, B, C)).equals(And(Not(A), Not(B), Not(C))) False >>> Not(And(A, Not(A))).equals(Or(B, Not(B))) False """ from sympy.logic.inference import satisfiable from sympy.core.relational import Relational if self.has(Relational) or other.has(Relational): raise NotImplementedError('handling of relationals') return self.atoms() == other.atoms() and \ not satisfiable(Not(Equivalent(self, other))) def to_nnf(self, simplify=True): # override where necessary return self def as_set(self): """ Rewrites Boolean expression in terms of real sets. Examples ======== >>> from sympy import Symbol, Eq, Or, And >>> x = Symbol('x', real=True) >>> Eq(x, 0).as_set() {0} >>> (x > 0).as_set() Interval.open(0, oo) >>> And(-2 < x, x < 2).as_set() Interval.open(-2, 2) >>> Or(x < -2, 2 < x).as_set() Union(Interval.open(-oo, -2), Interval.open(2, oo)) """ from sympy.calculus.util import periodicity from sympy.core.relational import Relational free = self.free_symbols if len(free) == 1: x = free.pop() reps = {} for r in self.atoms(Relational): if periodicity(r, x) not in (0, None): s = r._eval_as_set() if s in (S.EmptySet, S.UniversalSet, S.Reals): reps[r] = s.as_relational(x) continue raise NotImplementedError(filldedent(''' as_set is not implemented for relationals with periodic solutions ''')) return self.subs(reps)._eval_as_set() else: raise NotImplementedError("Sorry, as_set has not yet been" " implemented for multivariate" " expressions") @property def binary_symbols(self): from sympy.core.relational import Eq, Ne return set().union(*[i.binary_symbols for i in self.args if i.is_Boolean or i.is_Symbol or isinstance(i, (Eq, Ne))]) def _eval_refine(self, assumptions): from sympy.assumptions import ask ret = ask(self, assumptions) if ret is True: return true elif ret is False: return false return None class BooleanAtom(Boolean): """ Base class of BooleanTrue and BooleanFalse. """ is_Boolean = True is_Atom = True _op_priority = 11 # higher than Expr def simplify(self, *a, **kw): return self def expand(self, *a, **kw): return self @property def canonical(self): return self def _noop(self, other=None): raise TypeError('BooleanAtom not allowed in this context.') __add__ = _noop __radd__ = _noop __sub__ = _noop __rsub__ = _noop __mul__ = _noop __rmul__ = _noop __pow__ = _noop __rpow__ = _noop __truediv__ = _noop __rtruediv__ = _noop __mod__ = _noop __rmod__ = _noop _eval_power = _noop # /// drop when Py2 is no longer supported def __lt__(self, other): raise TypeError(filldedent(''' A Boolean argument can only be used in Eq and Ne; all other relationals expect real expressions. ''')) __le__ = __lt__ __gt__ = __lt__ __ge__ = __lt__ # \\\ class BooleanTrue(BooleanAtom, metaclass=Singleton): """ SymPy version of True, a singleton that can be accessed via S.true. This is the SymPy version of True, for use in the logic module. The primary advantage of using true instead of True is that shorthand boolean operations like ~ and >> will work as expected on this class, whereas with True they act bitwise on 1. Functions in the logic module will return this class when they evaluate to true. Notes ===== There is liable to be some confusion as to when ``True`` should be used and when ``S.true`` should be used in various contexts throughout SymPy. An important thing to remember is that ``sympify(True)`` returns ``S.true``. This means that for the most part, you can just use ``True`` and it will automatically be converted to ``S.true`` when necessary, similar to how you can generally use 1 instead of ``S.One``. The rule of thumb is: "If the boolean in question can be replaced by an arbitrary symbolic ``Boolean``, like ``Or(x, y)`` or ``x > 1``, use ``S.true``. Otherwise, use ``True``" In other words, use ``S.true`` only on those contexts where the boolean is being used as a symbolic representation of truth. For example, if the object ends up in the ``.args`` of any expression, then it must necessarily be ``S.true`` instead of ``True``, as elements of ``.args`` must be ``Basic``. On the other hand, ``==`` is not a symbolic operation in SymPy, since it always returns ``True`` or ``False``, and does so in terms of structural equality rather than mathematical, so it should return ``True``. The assumptions system should use ``True`` and ``False``. Aside from not satisfying the above rule of thumb, the assumptions system uses a three-valued logic (``True``, ``False``, ``None``), whereas ``S.true`` and ``S.false`` represent a two-valued logic. When in doubt, use ``True``. "``S.true == True is True``." While "``S.true is True``" is ``False``, "``S.true == True``" is ``True``, so if there is any doubt over whether a function or expression will return ``S.true`` or ``True``, just use ``==`` instead of ``is`` to do the comparison, and it will work in either case. Finally, for boolean flags, it's better to just use ``if x`` instead of ``if x is True``. To quote PEP 8: Don't compare boolean values to ``True`` or ``False`` using ``==``. * Yes: ``if greeting:`` * No: ``if greeting == True:`` * Worse: ``if greeting is True:`` Examples ======== >>> from sympy import sympify, true, false, Or >>> sympify(True) True >>> _ is True, _ is true (False, True) >>> Or(true, false) True >>> _ is true True Python operators give a boolean result for true but a bitwise result for True >>> ~true, ~True (False, -2) >>> true >> true, True >> True (True, 0) Python operators give a boolean result for true but a bitwise result for True >>> ~true, ~True (False, -2) >>> true >> true, True >> True (True, 0) See Also ======== sympy.logic.boolalg.BooleanFalse """ def __bool__(self): return True def __hash__(self): return hash(True) @property def negated(self): return S.false def as_set(self): """ Rewrite logic operators and relationals in terms of real sets. Examples ======== >>> from sympy import true >>> true.as_set() UniversalSet """ return S.UniversalSet class BooleanFalse(BooleanAtom, metaclass=Singleton): """ SymPy version of False, a singleton that can be accessed via S.false. This is the SymPy version of False, for use in the logic module. The primary advantage of using false instead of False is that shorthand boolean operations like ~ and >> will work as expected on this class, whereas with False they act bitwise on 0. Functions in the logic module will return this class when they evaluate to false. Notes ====== See the notes section in :py:class:`sympy.logic.boolalg.BooleanTrue` Examples ======== >>> from sympy import sympify, true, false, Or >>> sympify(False) False >>> _ is False, _ is false (False, True) >>> Or(true, false) True >>> _ is true True Python operators give a boolean result for false but a bitwise result for False >>> ~false, ~False (True, -1) >>> false >> false, False >> False (True, 0) See Also ======== sympy.logic.boolalg.BooleanTrue """ def __bool__(self): return False def __hash__(self): return hash(False) @property def negated(self): return S.true def as_set(self): """ Rewrite logic operators and relationals in terms of real sets. Examples ======== >>> from sympy import false >>> false.as_set() EmptySet """ return S.EmptySet true = BooleanTrue() false = BooleanFalse() # We want S.true and S.false to work, rather than S.BooleanTrue and # S.BooleanFalse, but making the class and instance names the same causes some # major issues (like the inability to import the class directly from this # file). S.true = true S.false = false converter[bool] = lambda x: S.true if x else S.false class BooleanFunction(Application, Boolean): """Boolean function is a function that lives in a boolean space It is used as base class for And, Or, Not, etc. """ is_Boolean = True def _eval_simplify(self, **kwargs): rv = self.func(*[a.simplify(**kwargs) for a in self.args]) return simplify_logic(rv) def simplify(self, **kwargs): from sympy.simplify.simplify import simplify return simplify(self, **kwargs) def __lt__(self, other): raise TypeError(filldedent(''' A Boolean argument can only be used in Eq and Ne; all other relationals expect real expressions. ''')) __le__ = __lt__ __ge__ = __lt__ __gt__ = __lt__ @classmethod def binary_check_and_simplify(self, *args): from sympy.core.relational import Relational, Eq, Ne args = [as_Boolean(i) for i in args] bin_syms = set().union(*[i.binary_symbols for i in args]) rel = set().union(*[i.atoms(Relational) for i in args]) reps = {} for x in bin_syms: for r in rel: if x in bin_syms and x in r.free_symbols: if isinstance(r, (Eq, Ne)): if not ( S.true in r.args or S.false in r.args): reps[r] = S.false else: raise TypeError(filldedent(''' Incompatible use of binary symbol `%s` as a real variable in `%s` ''' % (x, r))) return [i.subs(reps) for i in args] def to_nnf(self, simplify=True): return self._to_nnf(*self.args, simplify=simplify) def to_anf(self, deep=True): return self._to_anf(*self.args, deep=deep) @classmethod def _to_nnf(cls, *args, **kwargs): simplify = kwargs.get('simplify', True) argset = set() for arg in args: if not is_literal(arg): arg = arg.to_nnf(simplify) if simplify: if isinstance(arg, cls): arg = arg.args else: arg = (arg,) for a in arg: if Not(a) in argset: return cls.zero argset.add(a) else: argset.add(arg) return cls(*argset) @classmethod def _to_anf(cls, *args, **kwargs): deep = kwargs.get('deep', True) argset = set() for arg in args: if deep: if not is_literal(arg) or isinstance(arg, Not): arg = arg.to_anf(deep=deep) argset.add(arg) else: argset.add(arg) return cls(*argset, remove_true=False) # the diff method below is copied from Expr class def diff(self, *symbols, **assumptions): assumptions.setdefault("evaluate", True) return Derivative(self, *symbols, **assumptions) def _eval_derivative(self, x): if x in self.binary_symbols: from sympy.core.relational import Eq from sympy.functions.elementary.piecewise import Piecewise return Piecewise( (0, Eq(self.subs(x, 0), self.subs(x, 1))), (1, True)) elif x in self.free_symbols: # not implemented, see https://www.encyclopediaofmath.org/ # index.php/Boolean_differential_calculus pass else: return S.Zero def _apply_patternbased_simplification(self, rv, patterns, measure, dominatingvalue, replacementvalue=None): """ Replace patterns of Relational Parameters ========== rv : Expr Boolean expression patterns : tuple Tuple of tuples, with (pattern to simplify, simplified pattern) measure : function Simplification measure dominatingvalue : boolean or None The dominating value for the function of consideration. For example, for And S.false is dominating. As soon as one expression is S.false in And, the whole expression is S.false. replacementvalue : boolean or None, optional The resulting value for the whole expression if one argument evaluates to dominatingvalue. For example, for Nand S.false is dominating, but in this case the resulting value is S.true. Default is None. If replacementvalue is None and dominatingvalue is not None, replacementvalue = dominatingvalue """ from sympy.core.relational import Relational, _canonical from sympy.functions.elementary.miscellaneous import Min, Max if replacementvalue is None and dominatingvalue is not None: replacementvalue = dominatingvalue # Use replacement patterns for Relationals changed = True Rel, nonRel = sift(rv.args, lambda i: isinstance(i, Relational), binary=True) if len(Rel) <= 1: return rv Rel, nonRealRel = sift(Rel, lambda i: all(s.is_real is not False for s in i.free_symbols), binary=True) Rel = [i.canonical for i in Rel] while changed and len(Rel) >= 2: changed = False # Sort based on ordered Rel = list(ordered(Rel)) # Create a list of possible replacements results = [] # Try all combinations for ((i, pi), (j, pj)) in combinations(enumerate(Rel), 2): for pattern, simp in patterns: res = [] # use SymPy matching oldexpr = rv.func(pi, pj) tmpres = oldexpr.match(pattern) if tmpres: res.append((tmpres, oldexpr)) # Try reversing first relational # This and the rest should not be required with a better # canonical oldexpr = rv.func(pi.reversed, pj) tmpres = oldexpr.match(pattern) if tmpres: res.append((tmpres, oldexpr)) # Try reversing second relational oldexpr = rv.func(pi, pj.reversed) tmpres = oldexpr.match(pattern) if tmpres: res.append((tmpres, oldexpr)) # Try reversing both relationals oldexpr = rv.func(pi.reversed, pj.reversed) tmpres = oldexpr.match(pattern) if tmpres: res.append((tmpres, oldexpr)) if res: for tmpres, oldexpr in res: # we have a matching, compute replacement np = simp.subs(tmpres) if np == dominatingvalue: # if dominatingvalue, the whole expression # will be replacementvalue return replacementvalue # add replacement if not isinstance(np, ITE) and not np.has(Min, Max): # We only want to use ITE and Min/Max # replacements if they simplify away costsaving = measure(oldexpr) - measure(np) if costsaving > 0: results.append((costsaving, (i, j, np))) if results: # Sort results based on complexity results = list(reversed(sorted(results, key=lambda pair: pair[0]))) # Replace the one providing most simplification replacement = results[0][1] i, j, newrel = replacement # Remove the old relationals del Rel[j] del Rel[i] if dominatingvalue is None or newrel != ~dominatingvalue: # Insert the new one (no need to insert a value that will # not affect the result) Rel.append(newrel) # We did change something so try again changed = True rv = rv.func(*([_canonical(i) for i in ordered(Rel)] + nonRel + nonRealRel)) return rv class And(LatticeOp, BooleanFunction): """ Logical AND function. It evaluates its arguments in order, giving False immediately if any of them are False, and True if they are all True. Examples ======== >>> from sympy.abc import x, y >>> from sympy.logic.boolalg import And >>> x & y x & y Notes ===== The ``&`` operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise and. Hence, ``And(a, b)`` and ``a & b`` will return different things if ``a`` and ``b`` are integers. >>> And(x, y).subs(x, 1) y """ zero = false identity = true nargs = None @classmethod def _new_args_filter(cls, args): args = BooleanFunction.binary_check_and_simplify(*args) args = LatticeOp._new_args_filter(args, And) newargs = [] rel = set() for x in ordered(args): if x.is_Relational: c = x.canonical if c in rel: continue elif c.negated.canonical in rel: return [S.false] else: rel.add(c) newargs.append(x) return newargs def _eval_subs(self, old, new): args = [] bad = None for i in self.args: try: i = i.subs(old, new) except TypeError: # store TypeError if bad is None: bad = i continue if i == False: return S.false elif i != True: args.append(i) if bad is not None: # let it raise bad.subs(old, new) # If old is And, replace the parts of the arguments with new if all # are there if isinstance(old, And): old_set = set(old.args) if old_set.issubset(args): args = set(args) - old_set args.add(new) return self.func(*args) def _eval_simplify(self, **kwargs): from sympy.core.relational import Equality, Relational from sympy.solvers.solveset import linear_coeffs # standard simplify rv = super()._eval_simplify(**kwargs) if not isinstance(rv, And): return rv # simplify args that are equalities involving # symbols so x == 0 & x == y -> x==0 & y == 0 Rel, nonRel = sift(rv.args, lambda i: isinstance(i, Relational), binary=True) if not Rel: return rv eqs, other = sift(Rel, lambda i: isinstance(i, Equality), binary=True) measure = kwargs['measure'] if eqs: ratio = kwargs['ratio'] reps = {} sifted = {} # group by length of free symbols sifted = sift(ordered([ (i.free_symbols, i) for i in eqs]), lambda x: len(x[0])) eqs = [] nonlineqs = [] while 1 in sifted: for free, e in sifted.pop(1): x = free.pop() if (e.lhs != x or x in e.rhs.free_symbols) and x not in reps: try: m, b = linear_coeffs( e.rewrite(Add, evaluate=False), x) enew = e.func(x, -b/m) if measure(enew) <= ratio*measure(e): e = enew else: eqs.append(e) continue except ValueError: pass if x in reps: eqs.append(e.subs(x, reps[x])) elif e.lhs == x and x not in e.rhs.free_symbols: reps[x] = e.rhs eqs.append(e) else: # x is not yet identified, but may be later nonlineqs.append(e) resifted = defaultdict(list) for k in sifted: for f, e in sifted[k]: e = e.xreplace(reps) f = e.free_symbols resifted[len(f)].append((f, e)) sifted = resifted for k in sifted: eqs.extend([e for f, e in sifted[k]]) nonlineqs = [ei.subs(reps) for ei in nonlineqs] other = [ei.subs(reps) for ei in other] rv = rv.func(*([i.canonical for i in (eqs + nonlineqs + other)] + nonRel)) patterns = simplify_patterns_and() return self._apply_patternbased_simplification(rv, patterns, measure, False) def _eval_as_set(self): from sympy.sets.sets import Intersection return Intersection(*[arg.as_set() for arg in self.args]) def _eval_rewrite_as_Nor(self, *args, **kwargs): return Nor(*[Not(arg) for arg in self.args]) def to_anf(self, deep=True): if deep: result = And._to_anf(*self.args, deep=deep) return distribute_xor_over_and(result) return self class Or(LatticeOp, BooleanFunction): """ Logical OR function It evaluates its arguments in order, giving True immediately if any of them are True, and False if they are all False. Examples ======== >>> from sympy.abc import x, y >>> from sympy.logic.boolalg import Or >>> x | y x | y Notes ===== The ``|`` operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise or. Hence, ``Or(a, b)`` and ``a | b`` will return different things if ``a`` and ``b`` are integers. >>> Or(x, y).subs(x, 0) y """ zero = true identity = false @classmethod def _new_args_filter(cls, args): newargs = [] rel = [] args = BooleanFunction.binary_check_and_simplify(*args) for x in args: if x.is_Relational: c = x.canonical if c in rel: continue nc = c.negated.canonical if any(r == nc for r in rel): return [S.true] rel.append(c) newargs.append(x) return LatticeOp._new_args_filter(newargs, Or) def _eval_subs(self, old, new): args = [] bad = None for i in self.args: try: i = i.subs(old, new) except TypeError: # store TypeError if bad is None: bad = i continue if i == True: return S.true elif i != False: args.append(i) if bad is not None: # let it raise bad.subs(old, new) # If old is Or, replace the parts of the arguments with new if all # are there if isinstance(old, Or): old_set = set(old.args) if old_set.issubset(args): args = set(args) - old_set args.add(new) return self.func(*args) def _eval_as_set(self): from sympy.sets.sets import Union return Union(*[arg.as_set() for arg in self.args]) def _eval_rewrite_as_Nand(self, *args, **kwargs): return Nand(*[Not(arg) for arg in self.args]) def _eval_simplify(self, **kwargs): # standard simplify rv = super()._eval_simplify(**kwargs) if not isinstance(rv, Or): return rv patterns = simplify_patterns_or() return self._apply_patternbased_simplification(rv, patterns, kwargs['measure'], S.true) def to_anf(self, deep=True): args = range(1, len(self.args) + 1) args = (combinations(self.args, j) for j in args) args = chain.from_iterable(args) # powerset args = (And(*arg) for arg in args) args = map(lambda x: to_anf(x, deep=deep) if deep else x, args) return Xor(*list(args), remove_true=False) class Not(BooleanFunction): """ Logical Not function (negation) Returns True if the statement is False Returns False if the statement is True Examples ======== >>> from sympy.logic.boolalg import Not, And, Or >>> from sympy.abc import x, A, B >>> Not(True) False >>> Not(False) True >>> Not(And(True, False)) True >>> Not(Or(True, False)) False >>> Not(And(And(True, x), Or(x, False))) ~x >>> ~x ~x >>> Not(And(Or(A, B), Or(~A, ~B))) ~((A | B) & (~A | ~B)) Notes ===== - The ``~`` operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise not. In particular, ``~a`` and ``Not(a)`` will be different if ``a`` is an integer. Furthermore, since bools in Python subclass from ``int``, ``~True`` is the same as ``~1`` which is ``-2``, which has a boolean value of True. To avoid this issue, use the SymPy boolean types ``true`` and ``false``. >>> from sympy import true >>> ~True -2 >>> ~true False """ is_Not = True @classmethod def eval(cls, arg): if isinstance(arg, Number) or arg in (True, False): return false if arg else true if arg.is_Not: return arg.args[0] # Simplify Relational objects. if arg.is_Relational: return arg.negated def _eval_as_set(self): """ Rewrite logic operators and relationals in terms of real sets. Examples ======== >>> from sympy import Not, Symbol >>> x = Symbol('x') >>> Not(x > 0).as_set() Interval(-oo, 0) """ return self.args[0].as_set().complement(S.Reals) def to_nnf(self, simplify=True): if is_literal(self): return self expr = self.args[0] func, args = expr.func, expr.args if func == And: return Or._to_nnf(*[~arg for arg in args], simplify=simplify) if func == Or: return And._to_nnf(*[~arg for arg in args], simplify=simplify) if func == Implies: a, b = args return And._to_nnf(a, ~b, simplify=simplify) if func == Equivalent: return And._to_nnf(Or(*args), Or(*[~arg for arg in args]), simplify=simplify) if func == Xor: result = [] for i in range(1, len(args)+1, 2): for neg in combinations(args, i): clause = [~s if s in neg else s for s in args] result.append(Or(*clause)) return And._to_nnf(*result, simplify=simplify) if func == ITE: a, b, c = args return And._to_nnf(Or(a, ~c), Or(~a, ~b), simplify=simplify) raise ValueError("Illegal operator %s in expression" % func) def to_anf(self, deep=True): return Xor._to_anf(true, self.args[0], deep=deep) class Xor(BooleanFunction): """ Logical XOR (exclusive OR) function. Returns True if an odd number of the arguments are True and the rest are False. Returns False if an even number of the arguments are True and the rest are False. Examples ======== >>> from sympy.logic.boolalg import Xor >>> from sympy import symbols >>> x, y = symbols('x y') >>> Xor(True, False) True >>> Xor(True, True) False >>> Xor(True, False, True, True, False) True >>> Xor(True, False, True, False) False >>> x ^ y x ^ y Notes ===== The ``^`` operator is provided as a convenience, but note that its use here is different from its normal use in Python, which is bitwise xor. In particular, ``a ^ b`` and ``Xor(a, b)`` will be different if ``a`` and ``b`` are integers. >>> Xor(x, y).subs(y, 0) x """ def __new__(cls, *args, remove_true=True, **kwargs): argset = set() obj = super().__new__(cls, *args, **kwargs) for arg in obj._args: if isinstance(arg, Number) or arg in (True, False): if arg: arg = true else: continue if isinstance(arg, Xor): for a in arg.args: argset.remove(a) if a in argset else argset.add(a) elif arg in argset: argset.remove(arg) else: argset.add(arg) rel = [(r, r.canonical, r.negated.canonical) for r in argset if r.is_Relational] odd = False # is number of complimentary pairs odd? start 0 -> False remove = [] for i, (r, c, nc) in enumerate(rel): for j in range(i + 1, len(rel)): rj, cj = rel[j][:2] if cj == nc: odd = ~odd break elif cj == c: break else: continue remove.append((r, rj)) if odd: argset.remove(true) if true in argset else argset.add(true) for a, b in remove: argset.remove(a) argset.remove(b) if len(argset) == 0: return false elif len(argset) == 1: return argset.pop() elif True in argset and remove_true: argset.remove(True) return Not(Xor(*argset)) else: obj._args = tuple(ordered(argset)) obj._argset = frozenset(argset) return obj # XXX: This should be cached on the object rather than using cacheit # Maybe it can be computed in __new__? @property # type: ignore @cacheit def args(self): return tuple(ordered(self._argset)) def to_nnf(self, simplify=True): args = [] for i in range(0, len(self.args)+1, 2): for neg in combinations(self.args, i): clause = [~s if s in neg else s for s in self.args] args.append(Or(*clause)) return And._to_nnf(*args, simplify=simplify) def _eval_rewrite_as_Or(self, *args, **kwargs): a = self.args return Or(*[_convert_to_varsSOP(x, self.args) for x in _get_odd_parity_terms(len(a))]) def _eval_rewrite_as_And(self, *args, **kwargs): a = self.args return And(*[_convert_to_varsPOS(x, self.args) for x in _get_even_parity_terms(len(a))]) def _eval_simplify(self, **kwargs): # as standard simplify uses simplify_logic which writes things as # And and Or, we only simplify the partial expressions before using # patterns rv = self.func(*[a.simplify(**kwargs) for a in self.args]) if not isinstance(rv, Xor): # This shouldn't really happen here return rv patterns = simplify_patterns_xor() return self._apply_patternbased_simplification(rv, patterns, kwargs['measure'], None) def _eval_subs(self, old, new): # If old is Xor, replace the parts of the arguments with new if all # are there if isinstance(old, Xor): old_set = set(old.args) if old_set.issubset(self.args): args = set(self.args) - old_set args.add(new) return self.func(*args) class Nand(BooleanFunction): """ Logical NAND function. It evaluates its arguments in order, giving True immediately if any of them are False, and False if they are all True. Returns True if any of the arguments are False Returns False if all arguments are True Examples ======== >>> from sympy.logic.boolalg import Nand >>> from sympy import symbols >>> x, y = symbols('x y') >>> Nand(False, True) True >>> Nand(True, True) False >>> Nand(x, y) ~(x & y) """ @classmethod def eval(cls, *args): return Not(And(*args)) class Nor(BooleanFunction): """ Logical NOR function. It evaluates its arguments in order, giving False immediately if any of them are True, and True if they are all False. Returns False if any argument is True Returns True if all arguments are False Examples ======== >>> from sympy.logic.boolalg import Nor >>> from sympy import symbols >>> x, y = symbols('x y') >>> Nor(True, False) False >>> Nor(True, True) False >>> Nor(False, True) False >>> Nor(False, False) True >>> Nor(x, y) ~(x | y) """ @classmethod def eval(cls, *args): return Not(Or(*args)) class Xnor(BooleanFunction): """ Logical XNOR function. Returns False if an odd number of the arguments are True and the rest are False. Returns True if an even number of the arguments are True and the rest are False. Examples ======== >>> from sympy.logic.boolalg import Xnor >>> from sympy import symbols >>> x, y = symbols('x y') >>> Xnor(True, False) False >>> Xnor(True, True) True >>> Xnor(True, False, True, True, False) False >>> Xnor(True, False, True, False) True """ @classmethod def eval(cls, *args): return Not(Xor(*args)) class Implies(BooleanFunction): """ Logical implication. A implies B is equivalent to !A v B Accepts two Boolean arguments; A and B. Returns False if A is True and B is False Returns True otherwise. Examples ======== >>> from sympy.logic.boolalg import Implies >>> from sympy import symbols >>> x, y = symbols('x y') >>> Implies(True, False) False >>> Implies(False, False) True >>> Implies(True, True) True >>> Implies(False, True) True >>> x >> y Implies(x, y) >>> y << x Implies(x, y) Notes ===== The ``>>`` and ``<<`` operators are provided as a convenience, but note that their use here is different from their normal use in Python, which is bit shifts. Hence, ``Implies(a, b)`` and ``a >> b`` will return different things if ``a`` and ``b`` are integers. In particular, since Python considers ``True`` and ``False`` to be integers, ``True >> True`` will be the same as ``1 >> 1``, i.e., 0, which has a truth value of False. To avoid this issue, use the SymPy objects ``true`` and ``false``. >>> from sympy import true, false >>> True >> False 1 >>> true >> false False """ @classmethod def eval(cls, *args): try: newargs = [] for x in args: if isinstance(x, Number) or x in (0, 1): newargs.append(bool(x)) else: newargs.append(x) A, B = newargs except ValueError: raise ValueError( "%d operand(s) used for an Implies " "(pairs are required): %s" % (len(args), str(args))) if A == True or A == False or B == True or B == False: return Or(Not(A), B) elif A == B: return S.true elif A.is_Relational and B.is_Relational: if A.canonical == B.canonical: return S.true if A.negated.canonical == B.canonical: return B else: return Basic.__new__(cls, *args) def to_nnf(self, simplify=True): a, b = self.args return Or._to_nnf(~a, b, simplify=simplify) def to_anf(self, deep=True): a, b = self.args return Xor._to_anf(true, a, And(a, b), deep=deep) class Equivalent(BooleanFunction): """ Equivalence relation. Equivalent(A, B) is True iff A and B are both True or both False Returns True if all of the arguments are logically equivalent. Returns False otherwise. Examples ======== >>> from sympy.logic.boolalg import Equivalent, And >>> from sympy.abc import x >>> Equivalent(False, False, False) True >>> Equivalent(True, False, False) False >>> Equivalent(x, And(x, True)) True """ def __new__(cls, *args, **options): from sympy.core.relational import Relational args = [_sympify(arg) for arg in args] argset = set(args) for x in args: if isinstance(x, Number) or x in [True, False]: # Includes 0, 1 argset.discard(x) argset.add(bool(x)) rel = [] for r in argset: if isinstance(r, Relational): rel.append((r, r.canonical, r.negated.canonical)) remove = [] for i, (r, c, nc) in enumerate(rel): for j in range(i + 1, len(rel)): rj, cj = rel[j][:2] if cj == nc: return false elif cj == c: remove.append((r, rj)) break for a, b in remove: argset.remove(a) argset.remove(b) argset.add(True) if len(argset) <= 1: return true if True in argset: argset.discard(True) return And(*argset) if False in argset: argset.discard(False) return And(*[~arg for arg in argset]) _args = frozenset(argset) obj = super().__new__(cls, _args) obj._argset = _args return obj # XXX: This should be cached on the object rather than using cacheit # Maybe it can be computed in __new__? @property # type: ignore @cacheit def args(self): return tuple(ordered(self._argset)) def to_nnf(self, simplify=True): args = [] for a, b in zip(self.args, self.args[1:]): args.append(Or(~a, b)) args.append(Or(~self.args[-1], self.args[0])) return And._to_nnf(*args, simplify=simplify) def to_anf(self, deep=True): a = And(*self.args) b = And(*[to_anf(Not(arg), deep=False) for arg in self.args]) b = distribute_xor_over_and(b) return Xor._to_anf(a, b, deep=deep) class ITE(BooleanFunction): """ If then else clause. ITE(A, B, C) evaluates and returns the result of B if A is true else it returns the result of C. All args must be Booleans. Examples ======== >>> from sympy.logic.boolalg import ITE, And, Xor, Or >>> from sympy.abc import x, y, z >>> ITE(True, False, True) False >>> ITE(Or(True, False), And(True, True), Xor(True, True)) True >>> ITE(x, y, z) ITE(x, y, z) >>> ITE(True, x, y) x >>> ITE(False, x, y) y >>> ITE(x, y, y) y Trying to use non-Boolean args will generate a TypeError: >>> ITE(True, [], ()) Traceback (most recent call last): ... TypeError: expecting bool, Boolean or ITE, not `[]` """ def __new__(cls, *args, **kwargs): from sympy.core.relational import Eq, Ne if len(args) != 3: raise ValueError('expecting exactly 3 args') a, b, c = args # check use of binary symbols if isinstance(a, (Eq, Ne)): # in this context, we can evaluate the Eq/Ne # if one arg is a binary symbol and the other # is true/false b, c = map(as_Boolean, (b, c)) bin_syms = set().union(*[i.binary_symbols for i in (b, c)]) if len(set(a.args) - bin_syms) == 1: # one arg is a binary_symbols _a = a if a.lhs is S.true: a = a.rhs elif a.rhs is S.true: a = a.lhs elif a.lhs is S.false: a = ~a.rhs elif a.rhs is S.false: a = ~a.lhs else: # binary can only equal True or False a = S.false if isinstance(_a, Ne): a = ~a else: a, b, c = BooleanFunction.binary_check_and_simplify( a, b, c) rv = None if kwargs.get('evaluate', True): rv = cls.eval(a, b, c) if rv is None: rv = BooleanFunction.__new__(cls, a, b, c, evaluate=False) return rv @classmethod def eval(cls, *args): from sympy.core.relational import Eq, Ne # do the args give a singular result? a, b, c = args if isinstance(a, (Ne, Eq)): _a = a if S.true in a.args: a = a.lhs if a.rhs is S.true else a.rhs elif S.false in a.args: a = ~a.lhs if a.rhs is S.false else ~a.rhs else: _a = None if _a is not None and isinstance(_a, Ne): a = ~a if a is S.true: return b if a is S.false: return c if b == c: return b else: # or maybe the results allow the answer to be expressed # in terms of the condition if b is S.true and c is S.false: return a if b is S.false and c is S.true: return Not(a) if [a, b, c] != args: return cls(a, b, c, evaluate=False) def to_nnf(self, simplify=True): a, b, c = self.args return And._to_nnf(Or(~a, b), Or(a, c), simplify=simplify) def _eval_as_set(self): return self.to_nnf().as_set() def _eval_rewrite_as_Piecewise(self, *args, **kwargs): from sympy.functions import Piecewise return Piecewise((args[1], args[0]), (args[2], True)) class Exclusive(BooleanFunction): """ True if only one or no argument is true. ``Exclusive(A, B, C)`` is equivalent to ``~(A & B) & ~(A & C) & ~(B & C)``. Examples ======== >>> from sympy.logic.boolalg import Exclusive >>> Exclusive(False, False, False) True >>> Exclusive(False, True, False) True >>> Exclusive(False, True, True) False """ @classmethod def eval(cls, *args): and_args = [] for a, b in combinations(args, 2): and_args.append(Not(And(a, b))) return And(*and_args) # end class definitions. Some useful methods def conjuncts(expr): """Return a list of the conjuncts in the expr s. Examples ======== >>> from sympy.logic.boolalg import conjuncts >>> from sympy.abc import A, B >>> conjuncts(A & B) frozenset({A, B}) >>> conjuncts(A | B) frozenset({A | B}) """ return And.make_args(expr) def disjuncts(expr): """Return a list of the disjuncts in the sentence s. Examples ======== >>> from sympy.logic.boolalg import disjuncts >>> from sympy.abc import A, B >>> disjuncts(A | B) frozenset({A, B}) >>> disjuncts(A & B) frozenset({A & B}) """ return Or.make_args(expr) def distribute_and_over_or(expr): """ Given a sentence s consisting of conjunctions and disjunctions of literals, return an equivalent sentence in CNF. Examples ======== >>> from sympy.logic.boolalg import distribute_and_over_or, And, Or, Not >>> from sympy.abc import A, B, C >>> distribute_and_over_or(Or(A, And(Not(B), Not(C)))) (A | ~B) & (A | ~C) """ return _distribute((expr, And, Or)) def distribute_or_over_and(expr): """ Given a sentence s consisting of conjunctions and disjunctions of literals, return an equivalent sentence in DNF. Note that the output is NOT simplified. Examples ======== >>> from sympy.logic.boolalg import distribute_or_over_and, And, Or, Not >>> from sympy.abc import A, B, C >>> distribute_or_over_and(And(Or(Not(A), B), C)) (B & C) | (C & ~A) """ return _distribute((expr, Or, And)) def distribute_xor_over_and(expr): """ Given a sentence s consisting of conjunction and exclusive disjunctions of literals, return an equivalent exclusive disjunction. Note that the output is NOT simplified. Examples ======== >>> from sympy.logic.boolalg import distribute_xor_over_and, And, Xor, Not >>> from sympy.abc import A, B, C >>> distribute_xor_over_and(And(Xor(Not(A), B), C)) (B & C) ^ (C & ~A) """ return _distribute((expr, Xor, And)) def _distribute(info): """ Distributes info[1] over info[2] with respect to info[0]. """ if isinstance(info[0], info[2]): for arg in info[0].args: if isinstance(arg, info[1]): conj = arg break else: return info[0] rest = info[2](*[a for a in info[0].args if a is not conj]) return info[1](*list(map(_distribute, [(info[2](c, rest), info[1], info[2]) for c in conj.args])), remove_true=False) elif isinstance(info[0], info[1]): return info[1](*list(map(_distribute, [(x, info[1], info[2]) for x in info[0].args])), remove_true=False) else: return info[0] def to_anf(expr, deep=True): r""" Converts expr to Algebraic Normal Form (ANF). ANF is a canonical normal form, which means that two equivalent formulas will convert to the same ANF. A logical expression is in ANF if it has the form .. math:: 1 \oplus a \oplus b \oplus ab \oplus abc i.e. it can be: - purely true, - purely false, - conjunction of variables, - exclusive disjunction. The exclusive disjunction can only contain true, variables or conjunction of variables. No negations are permitted. If ``deep`` is ``False``, arguments of the boolean expression are considered variables, i.e. only the top-level expression is converted to ANF. Examples ======== >>> from sympy.logic.boolalg import And, Or, Not, Implies, Equivalent >>> from sympy.logic.boolalg import to_anf >>> from sympy.abc import A, B, C >>> to_anf(Not(A)) A ^ True >>> to_anf(And(Or(A, B), Not(C))) A ^ B ^ (A & B) ^ (A & C) ^ (B & C) ^ (A & B & C) >>> to_anf(Implies(Not(A), Equivalent(B, C)), deep=False) True ^ ~A ^ (~A & (Equivalent(B, C))) """ expr = sympify(expr) if is_anf(expr): return expr return expr.to_anf(deep=deep) def to_nnf(expr, simplify=True): """ Converts expr to Negation Normal Form. A logical expression is in Negation Normal Form (NNF) if it contains only And, Or and Not, and Not is applied only to literals. If simplify is True, the result contains no redundant clauses. Examples ======== >>> from sympy.abc import A, B, C, D >>> from sympy.logic.boolalg import Not, Equivalent, to_nnf >>> to_nnf(Not((~A & ~B) | (C & D))) (A | B) & (~C | ~D) >>> to_nnf(Equivalent(A >> B, B >> A)) (A | ~B | (A & ~B)) & (B | ~A | (B & ~A)) """ if is_nnf(expr, simplify): return expr return expr.to_nnf(simplify) def to_cnf(expr, simplify=False, force=False): """ Convert a propositional logical sentence s to conjunctive normal form: ((A | ~B | ...) & (B | C | ...) & ...). If simplify is True, the expr is evaluated to its simplest CNF form using the Quine-McCluskey algorithm; this may take a long time if there are more than 8 variables and requires that the ``force`` flag be set to True (default is False). Examples ======== >>> from sympy.logic.boolalg import to_cnf >>> from sympy.abc import A, B, D >>> to_cnf(~(A | B) | D) (D | ~A) & (D | ~B) >>> to_cnf((A | B) & (A | ~A), True) A | B """ expr = sympify(expr) if not isinstance(expr, BooleanFunction): return expr if simplify: if not force and len(_find_predicates(expr)) > 8: raise ValueError(filldedent(''' To simplify a logical expression with more than 8 variables may take a long time and requires the use of `force=True`.''')) return simplify_logic(expr, 'cnf', True, force=force) # Don't convert unless we have to if is_cnf(expr): return expr expr = eliminate_implications(expr) res = distribute_and_over_or(expr) return res def to_dnf(expr, simplify=False, force=False): """ Convert a propositional logical sentence s to disjunctive normal form: ((A & ~B & ...) | (B & C & ...) | ...). If simplify is True, the expr is evaluated to its simplest DNF form using the Quine-McCluskey algorithm; this may take a long time if there are more than 8 variables and requires that the ``force`` flag be set to True (default is False). Examples ======== >>> from sympy.logic.boolalg import to_dnf >>> from sympy.abc import A, B, C >>> to_dnf(B & (A | C)) (A & B) | (B & C) >>> to_dnf((A & B) | (A & ~B) | (B & C) | (~B & C), True) A | C """ expr = sympify(expr) if not isinstance(expr, BooleanFunction): return expr if simplify: if not force and len(_find_predicates(expr)) > 8: raise ValueError(filldedent(''' To simplify a logical expression with more than 8 variables may take a long time and requires the use of `force=True`.''')) return simplify_logic(expr, 'dnf', True, force=force) # Don't convert unless we have to if is_dnf(expr): return expr expr = eliminate_implications(expr) return distribute_or_over_and(expr) def is_anf(expr): r""" Checks if expr is in Algebraic Normal Form (ANF). A logical expression is in ANF if it has the form .. math:: 1 \oplus a \oplus b \oplus ab \oplus abc i.e. it is purely true, purely false, conjunction of variables or exclusive disjunction. The exclusive disjunction can only contain true, variables or conjunction of variables. No negations are permitted. Examples ======== >>> from sympy.logic.boolalg import And, Not, Xor, true, is_anf >>> from sympy.abc import A, B, C >>> is_anf(true) True >>> is_anf(A) True >>> is_anf(And(A, B, C)) True >>> is_anf(Xor(A, Not(B))) False """ expr = sympify(expr) if is_literal(expr) and not isinstance(expr, Not): return True if isinstance(expr, And): for arg in expr.args: if not arg.is_Symbol: return False return True elif isinstance(expr, Xor): for arg in expr.args: if isinstance(arg, And): for a in arg.args: if not a.is_Symbol: return False elif is_literal(arg): if isinstance(arg, Not): return False else: return False return True else: return False def is_nnf(expr, simplified=True): """ Checks if expr is in Negation Normal Form. A logical expression is in Negation Normal Form (NNF) if it contains only And, Or and Not, and Not is applied only to literals. If simplified is True, checks if result contains no redundant clauses. Examples ======== >>> from sympy.abc import A, B, C >>> from sympy.logic.boolalg import Not, is_nnf >>> is_nnf(A & B | ~C) True >>> is_nnf((A | ~A) & (B | C)) False >>> is_nnf((A | ~A) & (B | C), False) True >>> is_nnf(Not(A & B) | C) False >>> is_nnf((A >> B) & (B >> A)) False """ expr = sympify(expr) if is_literal(expr): return True stack = [expr] while stack: expr = stack.pop() if expr.func in (And, Or): if simplified: args = expr.args for arg in args: if Not(arg) in args: return False stack.extend(expr.args) elif not is_literal(expr): return False return True def is_cnf(expr): """ Test whether or not an expression is in conjunctive normal form. Examples ======== >>> from sympy.logic.boolalg import is_cnf >>> from sympy.abc import A, B, C >>> is_cnf(A | B | C) True >>> is_cnf(A & B & C) True >>> is_cnf((A & B) | C) False """ return _is_form(expr, And, Or) def is_dnf(expr): """ Test whether or not an expression is in disjunctive normal form. Examples ======== >>> from sympy.logic.boolalg import is_dnf >>> from sympy.abc import A, B, C >>> is_dnf(A | B | C) True >>> is_dnf(A & B & C) True >>> is_dnf((A & B) | C) True >>> is_dnf(A & (B | C)) False """ return _is_form(expr, Or, And) def _is_form(expr, function1, function2): """ Test whether or not an expression is of the required form. """ expr = sympify(expr) vals = function1.make_args(expr) if isinstance(expr, function1) else [expr] for lit in vals: if isinstance(lit, function2): vals2 = function2.make_args(lit) if isinstance(lit, function2) else [lit] for l in vals2: if is_literal(l) is False: return False elif is_literal(lit) is False: return False return True def eliminate_implications(expr): """ Change >>, <<, and Equivalent into &, |, and ~. That is, return an expression that is equivalent to s, but has only &, |, and ~ as logical operators. Examples ======== >>> from sympy.logic.boolalg import Implies, Equivalent, \ eliminate_implications >>> from sympy.abc import A, B, C >>> eliminate_implications(Implies(A, B)) B | ~A >>> eliminate_implications(Equivalent(A, B)) (A | ~B) & (B | ~A) >>> eliminate_implications(Equivalent(A, B, C)) (A | ~C) & (B | ~A) & (C | ~B) """ return to_nnf(expr, simplify=False) def is_literal(expr): """ Returns True if expr is a literal, else False. Examples ======== >>> from sympy import Or, Q >>> from sympy.abc import A, B >>> from sympy.logic.boolalg import is_literal >>> is_literal(A) True >>> is_literal(~A) True >>> is_literal(Q.zero(A)) True >>> is_literal(A + B) True >>> is_literal(Or(A, B)) False """ from sympy.assumptions import AppliedPredicate if isinstance(expr, Not): return is_literal(expr.args[0]) elif expr in (True, False) or isinstance(expr, AppliedPredicate) or expr.is_Atom: return True elif not isinstance(expr, BooleanFunction) and all( (isinstance(expr, AppliedPredicate) or a.is_Atom) for a in expr.args): return True return False def to_int_repr(clauses, symbols): """ Takes clauses in CNF format and puts them into an integer representation. Examples ======== >>> from sympy.logic.boolalg import to_int_repr >>> from sympy.abc import x, y >>> to_int_repr([x | y, y], [x, y]) == [{1, 2}, {2}] True """ # Convert the symbol list into a dict symbols = dict(list(zip(symbols, list(range(1, len(symbols) + 1))))) def append_symbol(arg, symbols): if isinstance(arg, Not): return -symbols[arg.args[0]] else: return symbols[arg] return [{append_symbol(arg, symbols) for arg in Or.make_args(c)} for c in clauses] def term_to_integer(term): """ Return an integer corresponding to the base-2 digits given by ``term``. Parameters ========== term : a string or list of ones and zeros Examples ======== >>> from sympy.logic.boolalg import term_to_integer >>> term_to_integer([1, 0, 0]) 4 >>> term_to_integer('100') 4 """ return int(''.join(list(map(str, list(term)))), 2) def integer_to_term(k, n_bits=None): """ Return a list of the base-2 digits in the integer, ``k``. Parameters ========== k : int n_bits : int If ``n_bits`` is given and the number of digits in the binary representation of ``k`` is smaller than ``n_bits`` then left-pad the list with 0s. Examples ======== >>> from sympy.logic.boolalg import integer_to_term >>> integer_to_term(4) [1, 0, 0] >>> integer_to_term(4, 6) [0, 0, 0, 1, 0, 0] """ s = '{0:0{1}b}'.format(abs(as_int(k)), as_int(abs(n_bits or 0))) return list(map(int, s)) def truth_table(expr, variables, input=True): """ Return a generator of all possible configurations of the input variables, and the result of the boolean expression for those values. Parameters ========== expr : string or boolean expression variables : list of variables input : boolean (default True) indicates whether to return the input combinations. Examples ======== >>> from sympy.logic.boolalg import truth_table >>> from sympy.abc import x,y >>> table = truth_table(x >> y, [x, y]) >>> for t in table: ... print('{0} -> {1}'.format(*t)) [0, 0] -> True [0, 1] -> True [1, 0] -> False [1, 1] -> True >>> table = truth_table(x | y, [x, y]) >>> list(table) [([0, 0], False), ([0, 1], True), ([1, 0], True), ([1, 1], True)] If input is false, truth_table returns only a list of truth values. In this case, the corresponding input values of variables can be deduced from the index of a given output. >>> from sympy.logic.boolalg import integer_to_term >>> vars = [y, x] >>> values = truth_table(x >> y, vars, input=False) >>> values = list(values) >>> values [True, False, True, True] >>> for i, value in enumerate(values): ... print('{0} -> {1}'.format(list(zip( ... vars, integer_to_term(i, len(vars)))), value)) [(y, 0), (x, 0)] -> True [(y, 0), (x, 1)] -> False [(y, 1), (x, 0)] -> True [(y, 1), (x, 1)] -> True """ variables = [sympify(v) for v in variables] expr = sympify(expr) if not isinstance(expr, BooleanFunction) and not is_literal(expr): return table = product((0, 1), repeat=len(variables)) for term in table: term = list(term) value = expr.xreplace(dict(zip(variables, term))) if input: yield term, value else: yield value def _check_pair(minterm1, minterm2): """ Checks if a pair of minterms differs by only one bit. If yes, returns index, else returns -1. """ # Early termination seems to be faster than list comprehension, # at least for large examples. index = -1 for x, i in enumerate(minterm1): # zip(minterm1, minterm2) is slower if i != minterm2[x]: if index == -1: index = x else: return -1 return index def _convert_to_varsSOP(minterm, variables): """ Converts a term in the expansion of a function from binary to its variable form (for SOP). """ temp = [variables[n] if val == 1 else Not(variables[n]) for n, val in enumerate(minterm) if val != 3] return And(*temp) def _convert_to_varsPOS(maxterm, variables): """ Converts a term in the expansion of a function from binary to its variable form (for POS). """ temp = [variables[n] if val == 0 else Not(variables[n]) for n, val in enumerate(maxterm) if val != 3] return Or(*temp) def _convert_to_varsANF(term, variables): """ Converts a term in the expansion of a function from binary to it's variable form (for ANF). Parameters ========== term : list of 1's and 0's (complementation patter) variables : list of variables """ temp = [variables[n] for n, t in enumerate(term) if t == 1] if not temp: return true return And(*temp) def _get_odd_parity_terms(n): """ Returns a list of lists, with all possible combinations of n zeros and ones with an odd number of ones. """ return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 1] def _get_even_parity_terms(n): """ Returns a list of lists, with all possible combinations of n zeros and ones with an even number of ones. """ return [e for e in [ibin(i, n) for i in range(2**n)] if sum(e) % 2 == 0] def _simplified_pairs(terms): """ Reduces a set of minterms, if possible, to a simplified set of minterms with one less variable in the terms using QM method. """ if not terms: return [] simplified_terms = [] todo = list(range(len(terms))) # Count number of ones as _check_pair can only potentially match if there # is at most a difference of a single one termdict = defaultdict(list) for n, term in enumerate(terms): ones = sum([1 for t in term if t == 1]) termdict[ones].append(n) variables = len(terms[0]) for k in range(variables): for i in termdict[k]: for j in termdict[k+1]: index = _check_pair(terms[i], terms[j]) if index != -1: # Mark terms handled todo[i] = todo[j] = None # Copy old term newterm = terms[i][:] # Set differing position to don't care newterm[index] = 3 # Add if not already there if newterm not in simplified_terms: simplified_terms.append(newterm) if simplified_terms: # Further simplifications only among the new terms simplified_terms = _simplified_pairs(simplified_terms) # Add remaining, non-simplified, terms simplified_terms.extend([terms[i] for i in todo if i is not None]) return simplified_terms def _rem_redundancy(l1, terms): """ After the truth table has been sufficiently simplified, use the prime implicant table method to recognize and eliminate redundant pairs, and return the essential arguments. """ if not terms: return [] nterms = len(terms) nl1 = len(l1) # Create dominating matrix dommatrix = [[0]*nl1 for n in range(nterms)] colcount = [0]*nl1 rowcount = [0]*nterms for primei, prime in enumerate(l1): for termi, term in enumerate(terms): # Check prime implicant covering term if all(t == 3 or t == mt for t, mt in zip(prime, term)): dommatrix[termi][primei] = 1 colcount[primei] += 1 rowcount[termi] += 1 # Keep track if anything changed anythingchanged = True # Then, go again while anythingchanged: anythingchanged = False for rowi in range(nterms): # Still non-dominated? if rowcount[rowi]: row = dommatrix[rowi] for row2i in range(nterms): # Still non-dominated? if rowi != row2i and rowcount[rowi] and (rowcount[rowi] <= rowcount[row2i]): row2 = dommatrix[row2i] if all(row2[n] >= row[n] for n in range(nl1)): # row2 dominating row, remove row2 rowcount[row2i] = 0 anythingchanged = True for primei, prime in enumerate(row2): if prime: # Make corresponding entry 0 dommatrix[row2i][primei] = 0 colcount[primei] -= 1 colcache = dict() for coli in range(nl1): # Still non-dominated? if colcount[coli]: if coli in colcache: col = colcache[coli] else: col = [dommatrix[i][coli] for i in range(nterms)] colcache[coli] = col for col2i in range(nl1): # Still non-dominated? if coli != col2i and colcount[col2i] and (colcount[coli] >= colcount[col2i]): if col2i in colcache: col2 = colcache[col2i] else: col2 = [dommatrix[i][col2i] for i in range(nterms)] colcache[col2i] = col2 if all(col[n] >= col2[n] for n in range(nterms)): # col dominating col2, remove col2 colcount[col2i] = 0 anythingchanged = True for termi, term in enumerate(col2): if term and dommatrix[termi][col2i]: # Make corresponding entry 0 dommatrix[termi][col2i] = 0 rowcount[termi] -= 1 if not anythingchanged: # Heuristically select the prime implicant covering most terms maxterms = 0 bestcolidx = -1 for coli in range(nl1): s = colcount[coli] if s > maxterms: bestcolidx = coli maxterms = s # In case we found a prime implicant covering at least two terms if bestcolidx != -1 and maxterms > 1: for primei, prime in enumerate(l1): if primei != bestcolidx: for termi, term in enumerate(colcache[bestcolidx]): if term and dommatrix[termi][primei]: # Make corresponding entry 0 dommatrix[termi][primei] = 0 anythingchanged = True rowcount[termi] -= 1 colcount[primei] -= 1 return [l1[i] for i in range(nl1) if colcount[i]] def _input_to_binlist(inputlist, variables): binlist = [] bits = len(variables) for val in inputlist: if isinstance(val, int): binlist.append(ibin(val, bits)) elif isinstance(val, dict): nonspecvars = list(variables) for key in val.keys(): nonspecvars.remove(key) for t in product((0, 1), repeat=len(nonspecvars)): d = dict(zip(nonspecvars, t)) d.update(val) binlist.append([d[v] for v in variables]) elif isinstance(val, (list, tuple)): if len(val) != bits: raise ValueError("Each term must contain {bits} bits as there are" "\n{bits} variables (or be an integer)." "".format(bits=bits)) binlist.append(list(val)) else: raise TypeError("A term list can only contain lists," " ints or dicts.") return binlist def SOPform(variables, minterms, dontcares=None): """ The SOPform function uses simplified_pairs and a redundant group- eliminating algorithm to convert the list of all input combos that generate '1' (the minterms) into the smallest Sum of Products form. The variables must be given as the first argument. Return a logical Or function (i.e., the "sum of products" or "SOP" form) that gives the desired outcome. If there are inputs that can be ignored, pass them as a list, too. The result will be one of the (perhaps many) functions that satisfy the conditions. Examples ======== >>> from sympy.logic import SOPform >>> from sympy import symbols >>> w, x, y, z = symbols('w x y z') >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], ... [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]] >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] >>> SOPform([w, x, y, z], minterms, dontcares) (y & z) | (~w & ~x) The terms can also be represented as integers: >>> minterms = [1, 3, 7, 11, 15] >>> dontcares = [0, 2, 5] >>> SOPform([w, x, y, z], minterms, dontcares) (y & z) | (~w & ~x) They can also be specified using dicts, which does not have to be fully specified: >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}] >>> SOPform([w, x, y, z], minterms) (x & ~w) | (y & z & ~x) Or a combination: >>> minterms = [4, 7, 11, [1, 1, 1, 1]] >>> dontcares = [{w : 0, x : 0, y: 0}, 5] >>> SOPform([w, x, y, z], minterms, dontcares) (w & y & z) | (~w & ~y) | (x & z & ~w) References ========== .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm """ if minterms == []: return false variables = tuple(map(sympify, variables)) minterms = _input_to_binlist(minterms, variables) dontcares = _input_to_binlist((dontcares or []), variables) for d in dontcares: if d in minterms: raise ValueError('%s in minterms is also in dontcares' % d) new = _simplified_pairs(minterms + dontcares) essential = _rem_redundancy(new, minterms) return Or(*[_convert_to_varsSOP(x, variables) for x in essential]) def POSform(variables, minterms, dontcares=None): """ The POSform function uses simplified_pairs and a redundant-group eliminating algorithm to convert the list of all input combinations that generate '1' (the minterms) into the smallest Product of Sums form. The variables must be given as the first argument. Return a logical And function (i.e., the "product of sums" or "POS" form) that gives the desired outcome. If there are inputs that can be ignored, pass them as a list, too. The result will be one of the (perhaps many) functions that satisfy the conditions. Examples ======== >>> from sympy.logic import POSform >>> from sympy import symbols >>> w, x, y, z = symbols('w x y z') >>> minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], ... [1, 0, 1, 1], [1, 1, 1, 1]] >>> dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] >>> POSform([w, x, y, z], minterms, dontcares) z & (y | ~w) The terms can also be represented as integers: >>> minterms = [1, 3, 7, 11, 15] >>> dontcares = [0, 2, 5] >>> POSform([w, x, y, z], minterms, dontcares) z & (y | ~w) They can also be specified using dicts, which does not have to be fully specified: >>> minterms = [{w: 0, x: 1}, {y: 1, z: 1, x: 0}] >>> POSform([w, x, y, z], minterms) (x | y) & (x | z) & (~w | ~x) Or a combination: >>> minterms = [4, 7, 11, [1, 1, 1, 1]] >>> dontcares = [{w : 0, x : 0, y: 0}, 5] >>> POSform([w, x, y, z], minterms, dontcares) (w | x) & (y | ~w) & (z | ~y) References ========== .. [1] https://en.wikipedia.org/wiki/Quine-McCluskey_algorithm """ if minterms == []: return false variables = tuple(map(sympify, variables)) minterms = _input_to_binlist(minterms, variables) dontcares = _input_to_binlist((dontcares or []), variables) for d in dontcares: if d in minterms: raise ValueError('%s in minterms is also in dontcares' % d) maxterms = [] for t in product((0, 1), repeat=len(variables)): t = list(t) if (t not in minterms) and (t not in dontcares): maxterms.append(t) new = _simplified_pairs(maxterms + dontcares) essential = _rem_redundancy(new, maxterms) return And(*[_convert_to_varsPOS(x, variables) for x in essential]) def ANFform(variables, truthvalues): """ The ANFform function converts the list of truth values to Algebraic Normal Form (ANF). The variables must be given as the first argument. Return True, False, logical And funciton (i.e., the "Zhegalkin monomial") or logical Xor function (i.e., the "Zhegalkin polynomial"). When True and False are represented by 1 and 0, respectively, then And is multiplication and Xor is addition. Formally a "Zhegalkin monomial" is the product (logical And) of a finite set of distinct variables, including the empty set whose product is denoted 1 (True). A "Zhegalkin polynomial" is the sum (logical Xor) of a set of Zhegalkin monomials, with the empty set denoted by 0 (False). Parameters ========== variables : list of variables truthvalues : list of 1's and 0's (result column of truth table) Examples ======== >>> from sympy.logic.boolalg import ANFform >>> from sympy.abc import x, y >>> ANFform([x], [1, 0]) x ^ True >>> ANFform([x, y], [0, 1, 1, 1]) x ^ y ^ (x & y) References ========== .. [2] https://en.wikipedia.org/wiki/Zhegalkin_polynomial """ n_vars = len(variables) n_values = len(truthvalues) if n_values != 2 ** n_vars: raise ValueError("The number of truth values must be equal to 2^%d, " "got %d" % (n_vars, n_values)) variables = tuple(map(sympify, variables)) coeffs = anf_coeffs(truthvalues) terms = [] for i, t in enumerate(product((0, 1), repeat=n_vars)): if coeffs[i] == 1: terms.append(t) return Xor(*[_convert_to_varsANF(x, variables) for x in terms], remove_true=False) def anf_coeffs(truthvalues): """ Convert a list of truth values of some boolean expression to the list of coefficients of the polynomial mod 2 (exclusive disjunction) representing the boolean expression in ANF (i.e., the "Zhegalkin polynomial"). There are 2^n possible Zhegalkin monomials in n variables, since each monomial is fully specified by the presence or absence of each variable. We can enumerate all the monomials. For example, boolean function with four variables (a, b, c, d) can contain up to 2^4 = 16 monomials. The 13-th monomial is the product a & b & d, because 13 in binary is 1, 1, 0, 1. A given monomial's presence or absence in a polynomial corresponds to that monomial's coefficient being 1 or 0 respectively. Examples ======== >>> from sympy.logic.boolalg import anf_coeffs, bool_monomial, Xor >>> from sympy.abc import a, b, c >>> truthvalues = [0, 1, 1, 0, 0, 1, 0, 1] >>> coeffs = anf_coeffs(truthvalues) >>> coeffs [0, 1, 1, 0, 0, 0, 1, 0] >>> polynomial = Xor(*[ ... bool_monomial(k, [a, b, c]) ... for k, coeff in enumerate(coeffs) if coeff == 1 ... ]) >>> polynomial b ^ c ^ (a & b) """ s = '{:b}'.format(len(truthvalues)) n = len(s) - 1 if len(truthvalues) != 2**n: raise ValueError("The number of truth values must be a power of two, " "got %d" % len(truthvalues)) coeffs = [[v] for v in truthvalues] for i in range(n): tmp = [] for j in range(2 ** (n-i-1)): tmp.append(coeffs[2*j] + list(map(lambda x, y: x^y, coeffs[2*j], coeffs[2*j+1]))) coeffs = tmp return coeffs[0] def bool_minterm(k, variables): """ Return the k-th minterm. Minterms are numbered by a binary encoding of the complementation pattern of the variables. This convention assigns the value 1 to the direct form and 0 to the complemented form. Parameters ========== k : int or list of 1's and 0's (complementation patter) variables : list of variables Examples ======== >>> from sympy.logic.boolalg import bool_minterm >>> from sympy.abc import x, y, z >>> bool_minterm([1, 0, 1], [x, y, z]) x & z & ~y >>> bool_minterm(6, [x, y, z]) x & y & ~z References ========== .. [3] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_minterms """ if isinstance(k, int): k = integer_to_term(k, len(variables)) variables = tuple(map(sympify, variables)) return _convert_to_varsSOP(k, variables) def bool_maxterm(k, variables): """ Return the k-th maxterm. Each maxterm is assigned an index based on the opposite conventional binary encoding used for minterms. The maxterm convention assigns the value 0 to the direct form and 1 to the complemented form. Parameters ========== k : int or list of 1's and 0's (complementation pattern) variables : list of variables Examples ======== >>> from sympy.logic.boolalg import bool_maxterm >>> from sympy.abc import x, y, z >>> bool_maxterm([1, 0, 1], [x, y, z]) y | ~x | ~z >>> bool_maxterm(6, [x, y, z]) z | ~x | ~y References ========== .. [4] https://en.wikipedia.org/wiki/Canonical_normal_form#Indexing_maxterms """ if isinstance(k, int): k = integer_to_term(k, len(variables)) variables = tuple(map(sympify, variables)) return _convert_to_varsPOS(k, variables) def bool_monomial(k, variables): """ Return the k-th monomial. Monomials are numbered by a binary encoding of the presence and absences of the variables. This convention assigns the value 1 to the presence of variable and 0 to the absence of variable. Each boolean function can be uniquely represented by a Zhegalkin Polynomial (Algebraic Normal Form). The Zhegalkin Polynomial of the boolean function with n variables can contain up to 2^n monomials. We can enumarate all the monomials. Each monomial is fully specified by the presence or absence of each variable. For example, boolean function with four variables (a, b, c, d) can contain up to 2^4 = 16 monomials. The 13-th monomial is the product a & b & d, because 13 in binary is 1, 1, 0, 1. Parameters ========== k : int or list of 1's and 0's variables : list of variables Examples ======== >>> from sympy.logic.boolalg import bool_monomial >>> from sympy.abc import x, y, z >>> bool_monomial([1, 0, 1], [x, y, z]) x & z >>> bool_monomial(6, [x, y, z]) x & y """ if isinstance(k, int): k = integer_to_term(k, len(variables)) variables = tuple(map(sympify, variables)) return _convert_to_varsANF(k, variables) def _find_predicates(expr): """Helper to find logical predicates in BooleanFunctions. A logical predicate is defined here as anything within a BooleanFunction that is not a BooleanFunction itself. """ if not isinstance(expr, BooleanFunction): return {expr} return set().union(*(map(_find_predicates, expr.args))) def simplify_logic(expr, form=None, deep=True, force=False): """ This function simplifies a boolean function to its simplified version in SOP or POS form. The return type is an Or or And object in SymPy. Parameters ========== expr : string or boolean expression form : string ('cnf' or 'dnf') or None (default). If 'cnf' or 'dnf', the simplest expression in the corresponding normal form is returned; if None, the answer is returned according to the form with fewest args (in CNF by default). deep : boolean (default True) Indicates whether to recursively simplify any non-boolean functions contained within the input. force : boolean (default False) As the simplifications require exponential time in the number of variables, there is by default a limit on expressions with 8 variables. When the expression has more than 8 variables only symbolical simplification (controlled by ``deep``) is made. By setting force to ``True``, this limit is removed. Be aware that this can lead to very long simplification times. Examples ======== >>> from sympy.logic import simplify_logic >>> from sympy.abc import x, y, z >>> from sympy import S >>> b = (~x & ~y & ~z) | ( ~x & ~y & z) >>> simplify_logic(b) ~x & ~y >>> S(b) (z & ~x & ~y) | (~x & ~y & ~z) >>> simplify_logic(_) ~x & ~y """ if form not in (None, 'cnf', 'dnf'): raise ValueError("form can be cnf or dnf only") expr = sympify(expr) # check for quick exit if form is given: right form and all args are # literal and do not involve Not if form: form_ok = False if form == 'cnf': form_ok = is_cnf(expr) elif form == 'dnf': form_ok = is_dnf(expr) if form_ok and all(is_literal(a) for a in expr.args): return expr if deep: variables = _find_predicates(expr) from sympy.simplify.simplify import simplify s = tuple(map(simplify, variables)) expr = expr.xreplace(dict(zip(variables, s))) if not isinstance(expr, BooleanFunction): return expr # get variables in case not deep or after doing # deep simplification since they may have changed variables = _find_predicates(expr) if not force and len(variables) > 8: return expr # group into constants and variable values c, v = sift(ordered(variables), lambda x: x in (True, False), binary=True) variables = c + v truthtable = [] # standardize constants to be 1 or 0 in keeping with truthtable c = [1 if i == True else 0 for i in c] for t in product((0, 1), repeat=len(v)): if expr.xreplace(dict(zip(v, t))) == True: truthtable.append(c + list(t)) big = len(truthtable) >= (2 ** (len(variables) - 1)) if form == 'dnf' or form is None and big: return SOPform(variables, truthtable) return POSform(variables, truthtable) def _finger(eq): """ Assign a 5-item fingerprint to each symbol in the equation: [ # of times it appeared as a Symbol; # of times it appeared as a Not(symbol); # of times it appeared as a Symbol in an And or Or; # of times it appeared as a Not(Symbol) in an And or Or; a sorted tuple of tuples, (i, j, k), where i is the number of arguments in an And or Or with which it appeared as a Symbol, and j is the number of arguments that were Not(Symbol); k is the number of times that (i, j) was seen. ] Examples ======== >>> from sympy.logic.boolalg import _finger as finger >>> from sympy import And, Or, Not, Xor, to_cnf, symbols >>> from sympy.abc import a, b, x, y >>> eq = Or(And(Not(y), a), And(Not(y), b), And(x, y)) >>> dict(finger(eq)) {(0, 0, 1, 0, ((2, 0, 1),)): [x], (0, 0, 1, 0, ((2, 1, 1),)): [a, b], (0, 0, 1, 2, ((2, 0, 1),)): [y]} >>> dict(finger(x & ~y)) {(0, 1, 0, 0, ()): [y], (1, 0, 0, 0, ()): [x]} In the following, the (5, 2, 6) means that there were 6 Or functions in which a symbol appeared as itself amongst 5 arguments in which there were also 2 negated symbols, e.g. ``(a0 | a1 | a2 | ~a3 | ~a4)`` is counted once for a0, a1 and a2. >>> dict(finger(to_cnf(Xor(*symbols('a:5'))))) {(0, 0, 8, 8, ((5, 0, 1), (5, 2, 6), (5, 4, 1))): [a0, a1, a2, a3, a4]} The equation must not have more than one level of nesting: >>> dict(finger(And(Or(x, y), y))) {(0, 0, 1, 0, ((2, 0, 1),)): [x], (1, 0, 1, 0, ((2, 0, 1),)): [y]} >>> dict(finger(And(Or(x, And(a, x)), y))) Traceback (most recent call last): ... NotImplementedError: unexpected level of nesting So y and x have unique fingerprints, but a and b do not. """ f = eq.free_symbols d = dict(list(zip(f, [[0]*4 + [defaultdict(int)] for fi in f]))) for a in eq.args: if a.is_Symbol: d[a][0] += 1 elif a.is_Not: d[a.args[0]][1] += 1 else: o = len(a.args), sum(isinstance(ai, Not) for ai in a.args) for ai in a.args: if ai.is_Symbol: d[ai][2] += 1 d[ai][-1][o] += 1 elif ai.is_Not: d[ai.args[0]][3] += 1 else: raise NotImplementedError('unexpected level of nesting') inv = defaultdict(list) for k, v in ordered(iter(d.items())): v[-1] = tuple(sorted([i + (j,) for i, j in v[-1].items()])) inv[tuple(v)].append(k) return inv def bool_map(bool1, bool2): """ Return the simplified version of bool1, and the mapping of variables that makes the two expressions bool1 and bool2 represent the same logical behaviour for some correspondence between the variables of each. If more than one mappings of this sort exist, one of them is returned. For example, And(x, y) is logically equivalent to And(a, b) for the mapping {x: a, y:b} or {x: b, y:a}. If no such mapping exists, return False. Examples ======== >>> from sympy import SOPform, bool_map, Or, And, Not, Xor >>> from sympy.abc import w, x, y, z, a, b, c, d >>> function1 = SOPform([x, z, y],[[1, 0, 1], [0, 0, 1]]) >>> function2 = SOPform([a, b, c],[[1, 0, 1], [1, 0, 0]]) >>> bool_map(function1, function2) (y & ~z, {y: a, z: b}) The results are not necessarily unique, but they are canonical. Here, ``(w, z)`` could be ``(a, d)`` or ``(d, a)``: >>> eq = Or(And(Not(y), w), And(Not(y), z), And(x, y)) >>> eq2 = Or(And(Not(c), a), And(Not(c), d), And(b, c)) >>> bool_map(eq, eq2) ((x & y) | (w & ~y) | (z & ~y), {w: a, x: b, y: c, z: d}) >>> eq = And(Xor(a, b), c, And(c,d)) >>> bool_map(eq, eq.subs(c, x)) (c & d & (a | b) & (~a | ~b), {a: a, b: b, c: d, d: x}) """ def match(function1, function2): """Return the mapping that equates variables between two simplified boolean expressions if possible. By "simplified" we mean that a function has been denested and is either an And (or an Or) whose arguments are either symbols (x), negated symbols (Not(x)), or Or (or an And) whose arguments are only symbols or negated symbols. For example, And(x, Not(y), Or(w, Not(z))). Basic.match is not robust enough (see issue 4835) so this is a workaround that is valid for simplified boolean expressions """ # do some quick checks if function1.__class__ != function2.__class__: return None # maybe simplification makes them the same? if len(function1.args) != len(function2.args): return None # maybe simplification makes them the same? if function1.is_Symbol: return {function1: function2} # get the fingerprint dictionaries f1 = _finger(function1) f2 = _finger(function2) # more quick checks if len(f1) != len(f2): return False # assemble the match dictionary if possible matchdict = {} for k in f1.keys(): if k not in f2: return False if len(f1[k]) != len(f2[k]): return False for i, x in enumerate(f1[k]): matchdict[x] = f2[k][i] return matchdict a = simplify_logic(bool1) b = simplify_logic(bool2) m = match(a, b) if m: return a, m return m def simplify_patterns_and(): from sympy.functions.elementary.miscellaneous import Min, Max from sympy.core import Wild from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt a = Wild('a') b = Wild('b') c = Wild('c') # With a better canonical fewer results are required _matchers_and = ((And(Eq(a, b), Ge(a, b)), Eq(a, b)), (And(Eq(a, b), Gt(a, b)), S.false), (And(Eq(a, b), Le(a, b)), Eq(a, b)), (And(Eq(a, b), Lt(a, b)), S.false), (And(Ge(a, b), Gt(a, b)), Gt(a, b)), (And(Ge(a, b), Le(a, b)), Eq(a, b)), (And(Ge(a, b), Lt(a, b)), S.false), (And(Ge(a, b), Ne(a, b)), Gt(a, b)), (And(Gt(a, b), Le(a, b)), S.false), (And(Gt(a, b), Lt(a, b)), S.false), (And(Gt(a, b), Ne(a, b)), Gt(a, b)), (And(Le(a, b), Lt(a, b)), Lt(a, b)), (And(Le(a, b), Ne(a, b)), Lt(a, b)), (And(Lt(a, b), Ne(a, b)), Lt(a, b)), # Min/max (And(Ge(a, b), Ge(a, c)), Ge(a, Max(b, c))), (And(Ge(a, b), Gt(a, c)), ITE(b > c, Ge(a, b), Gt(a, c))), (And(Gt(a, b), Gt(a, c)), Gt(a, Max(b, c))), (And(Le(a, b), Le(a, c)), Le(a, Min(b, c))), (And(Le(a, b), Lt(a, c)), ITE(b < c, Le(a, b), Lt(a, c))), (And(Lt(a, b), Lt(a, c)), Lt(a, Min(b, c))), # Sign (And(Eq(a, b), Eq(a, -b)), And(Eq(a, S.Zero), Eq(b, S.Zero))), ) return _matchers_and def simplify_patterns_or(): from sympy.functions.elementary.miscellaneous import Min, Max from sympy.core import Wild from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt a = Wild('a') b = Wild('b') c = Wild('c') _matchers_or = ((Or(Eq(a, b), Ge(a, b)), Ge(a, b)), (Or(Eq(a, b), Gt(a, b)), Ge(a, b)), (Or(Eq(a, b), Le(a, b)), Le(a, b)), (Or(Eq(a, b), Lt(a, b)), Le(a, b)), (Or(Ge(a, b), Gt(a, b)), Ge(a, b)), (Or(Ge(a, b), Le(a, b)), S.true), (Or(Ge(a, b), Lt(a, b)), S.true), (Or(Ge(a, b), Ne(a, b)), S.true), (Or(Gt(a, b), Le(a, b)), S.true), (Or(Gt(a, b), Lt(a, b)), Ne(a, b)), (Or(Gt(a, b), Ne(a, b)), Ne(a, b)), (Or(Le(a, b), Lt(a, b)), Le(a, b)), (Or(Le(a, b), Ne(a, b)), S.true), (Or(Lt(a, b), Ne(a, b)), Ne(a, b)), # Min/max (Or(Ge(a, b), Ge(a, c)), Ge(a, Min(b, c))), (Or(Ge(a, b), Gt(a, c)), ITE(b > c, Gt(a, c), Ge(a, b))), (Or(Gt(a, b), Gt(a, c)), Gt(a, Min(b, c))), (Or(Le(a, b), Le(a, c)), Le(a, Max(b, c))), (Or(Le(a, b), Lt(a, c)), ITE(b >= c, Le(a, b), Lt(a, c))), (Or(Lt(a, b), Lt(a, c)), Lt(a, Max(b, c))), ) return _matchers_or def simplify_patterns_xor(): from sympy.functions.elementary.miscellaneous import Min, Max from sympy.core import Wild from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt a = Wild('a') b = Wild('b') c = Wild('c') _matchers_xor = ((Xor(Eq(a, b), Ge(a, b)), Gt(a, b)), (Xor(Eq(a, b), Gt(a, b)), Ge(a, b)), (Xor(Eq(a, b), Le(a, b)), Lt(a, b)), (Xor(Eq(a, b), Lt(a, b)), Le(a, b)), (Xor(Ge(a, b), Gt(a, b)), Eq(a, b)), (Xor(Ge(a, b), Le(a, b)), Ne(a, b)), (Xor(Ge(a, b), Lt(a, b)), S.true), (Xor(Ge(a, b), Ne(a, b)), Le(a, b)), (Xor(Gt(a, b), Le(a, b)), S.true), (Xor(Gt(a, b), Lt(a, b)), Ne(a, b)), (Xor(Gt(a, b), Ne(a, b)), Lt(a, b)), (Xor(Le(a, b), Lt(a, b)), Eq(a, b)), (Xor(Le(a, b), Ne(a, b)), Ge(a, b)), (Xor(Lt(a, b), Ne(a, b)), Gt(a, b)), # Min/max (Xor(Ge(a, b), Ge(a, c)), And(Ge(a, Min(b, c)), Lt(a, Max(b, c)))), (Xor(Ge(a, b), Gt(a, c)), ITE(b > c, And(Gt(a, c), Lt(a, b)), And(Ge(a, b), Le(a, c)))), (Xor(Gt(a, b), Gt(a, c)), And(Gt(a, Min(b, c)), Le(a, Max(b, c)))), (Xor(Le(a, b), Le(a, c)), And(Le(a, Max(b, c)), Gt(a, Min(b, c)))), (Xor(Le(a, b), Lt(a, c)), ITE(b < c, And(Lt(a, c), Gt(a, b)), And(Le(a, b), Ge(a, c)))), (Xor(Lt(a, b), Lt(a, c)), And(Lt(a, Max(b, c)), Ge(a, Min(b, c)))), ) return _matchers_xor sympy-sympy-1.9/sympy/logic/inference.py000066400000000000000000000206061412543434000205150ustar00rootroot00000000000000"""Inference in propositional logic""" from sympy.logic.boolalg import And, Not, conjuncts, to_cnf from sympy.core.compatibility import ordered from sympy.core.sympify import sympify from sympy.external.importtools import import_module def literal_symbol(literal): """ The symbol in this literal (without the negation). Examples ======== >>> from sympy.abc import A >>> from sympy.logic.inference import literal_symbol >>> literal_symbol(A) A >>> literal_symbol(~A) A """ if literal is True or literal is False: return literal try: if literal.is_Symbol: return literal if literal.is_Not: return literal_symbol(literal.args[0]) else: raise ValueError except (AttributeError, ValueError): raise ValueError("Argument must be a boolean literal.") def satisfiable(expr, algorithm=None, all_models=False, minimal=False): """ Check satisfiability of a propositional sentence. Returns a model when it succeeds. Returns {true: true} for trivially true expressions. On setting all_models to True, if given expr is satisfiable then returns a generator of models. However, if expr is unsatisfiable then returns a generator containing the single element False. Examples ======== >>> from sympy.abc import A, B >>> from sympy.logic.inference import satisfiable >>> satisfiable(A & ~B) {A: True, B: False} >>> satisfiable(A & ~A) False >>> satisfiable(True) {True: True} >>> next(satisfiable(A & ~A, all_models=True)) False >>> models = satisfiable((A >> B) & B, all_models=True) >>> next(models) {A: False, B: True} >>> next(models) {A: True, B: True} >>> def use_models(models): ... for model in models: ... if model: ... # Do something with the model. ... print(model) ... else: ... # Given expr is unsatisfiable. ... print("UNSAT") >>> use_models(satisfiable(A >> ~A, all_models=True)) {A: False} >>> use_models(satisfiable(A ^ A, all_models=True)) UNSAT """ if algorithm is None or algorithm == "pycosat": pycosat = import_module('pycosat') if pycosat is not None: algorithm = "pycosat" else: if algorithm == "pycosat": raise ImportError("pycosat module is not present") # Silently fall back to dpll2 if pycosat # is not installed algorithm = "dpll2" if algorithm=="minisat22": pysat = import_module('pysat') if pysat is None: algorithm = "dpll2" if algorithm == "dpll": from sympy.logic.algorithms.dpll import dpll_satisfiable return dpll_satisfiable(expr) elif algorithm == "dpll2": from sympy.logic.algorithms.dpll2 import dpll_satisfiable return dpll_satisfiable(expr, all_models) elif algorithm == "pycosat": from sympy.logic.algorithms.pycosat_wrapper import pycosat_satisfiable return pycosat_satisfiable(expr, all_models) elif algorithm == "minisat22": from sympy.logic.algorithms.minisat22_wrapper import minisat22_satisfiable return minisat22_satisfiable(expr, all_models, minimal) raise NotImplementedError def valid(expr): """ Check validity of a propositional sentence. A valid propositional sentence is True under every assignment. Examples ======== >>> from sympy.abc import A, B >>> from sympy.logic.inference import valid >>> valid(A | ~A) True >>> valid(A | B) False References ========== .. [1] https://en.wikipedia.org/wiki/Validity """ return not satisfiable(Not(expr)) def pl_true(expr, model=None, deep=False): """ Returns whether the given assignment is a model or not. If the assignment does not specify the value for every proposition, this may return None to indicate 'not obvious'. Parameters ========== model : dict, optional, default: {} Mapping of symbols to boolean values to indicate assignment. deep: boolean, optional, default: False Gives the value of the expression under partial assignments correctly. May still return None to indicate 'not obvious'. Examples ======== >>> from sympy.abc import A, B >>> from sympy.logic.inference import pl_true >>> pl_true( A & B, {A: True, B: True}) True >>> pl_true(A & B, {A: False}) False >>> pl_true(A & B, {A: True}) >>> pl_true(A & B, {A: True}, deep=True) >>> pl_true(A >> (B >> A)) >>> pl_true(A >> (B >> A), deep=True) True >>> pl_true(A & ~A) >>> pl_true(A & ~A, deep=True) False >>> pl_true(A & B & (~A | ~B), {A: True}) >>> pl_true(A & B & (~A | ~B), {A: True}, deep=True) False """ from sympy.core.symbol import Symbol from sympy.logic.boolalg import BooleanFunction boolean = (True, False) def _validate(expr): if isinstance(expr, Symbol) or expr in boolean: return True if not isinstance(expr, BooleanFunction): return False return all(_validate(arg) for arg in expr.args) if expr in boolean: return expr expr = sympify(expr) if not _validate(expr): raise ValueError("%s is not a valid boolean expression" % expr) if not model: model = {} model = {k: v for k, v in model.items() if v in boolean} result = expr.subs(model) if result in boolean: return bool(result) if deep: model = {k: True for k in result.atoms()} if pl_true(result, model): if valid(result): return True else: if not satisfiable(result): return False return None def entails(expr, formula_set=None): """ Check whether the given expr_set entail an expr. If formula_set is empty then it returns the validity of expr. Examples ======== >>> from sympy.abc import A, B, C >>> from sympy.logic.inference import entails >>> entails(A, [A >> B, B >> C]) False >>> entails(C, [A >> B, B >> C, A]) True >>> entails(A >> B) False >>> entails(A >> (B >> A)) True References ========== .. [1] https://en.wikipedia.org/wiki/Logical_consequence """ if formula_set: formula_set = list(formula_set) else: formula_set = [] formula_set.append(Not(expr)) return not satisfiable(And(*formula_set)) class KB: """Base class for all knowledge bases""" def __init__(self, sentence=None): self.clauses_ = set() if sentence: self.tell(sentence) def tell(self, sentence): raise NotImplementedError def ask(self, query): raise NotImplementedError def retract(self, sentence): raise NotImplementedError @property def clauses(self): return list(ordered(self.clauses_)) class PropKB(KB): """A KB for Propositional Logic. Inefficient, with no indexing.""" def tell(self, sentence): """Add the sentence's clauses to the KB Examples ======== >>> from sympy.logic.inference import PropKB >>> from sympy.abc import x, y >>> l = PropKB() >>> l.clauses [] >>> l.tell(x | y) >>> l.clauses [x | y] >>> l.tell(y) >>> l.clauses [y, x | y] """ for c in conjuncts(to_cnf(sentence)): self.clauses_.add(c) def ask(self, query): """Checks if the query is true given the set of clauses. Examples ======== >>> from sympy.logic.inference import PropKB >>> from sympy.abc import x, y >>> l = PropKB() >>> l.tell(x & ~y) >>> l.ask(x) True >>> l.ask(y) False """ return entails(query, self.clauses_) def retract(self, sentence): """Remove the sentence's clauses from the KB Examples ======== >>> from sympy.logic.inference import PropKB >>> from sympy.abc import x, y >>> l = PropKB() >>> l.clauses [] >>> l.tell(x | y) >>> l.clauses [x | y] >>> l.retract(x | y) >>> l.clauses [] """ for c in conjuncts(to_cnf(sentence)): self.clauses_.discard(c) sympy-sympy-1.9/sympy/logic/tests/000077500000000000000000000000001412543434000173435ustar00rootroot00000000000000sympy-sympy-1.9/sympy/logic/tests/__init__.py000066400000000000000000000000001412543434000214420ustar00rootroot00000000000000sympy-sympy-1.9/sympy/logic/tests/test_boolalg.py000066400000000000000000001314031412543434000223750ustar00rootroot00000000000000from sympy.assumptions.ask import Q from sympy.assumptions.refine import refine from sympy.core.numbers import oo from sympy.core.relational import Equality, Eq, Ne from sympy.core.singleton import S from sympy.core.symbol import (Dummy, symbols) from sympy.functions import Piecewise from sympy.functions.elementary.trigonometric import sin from sympy.sets.sets import (EmptySet, Interval, Union) from sympy.simplify.simplify import simplify from sympy.logic.boolalg import ( And, Boolean, Equivalent, ITE, Implies, Nand, Nor, Not, Or, POSform, SOPform, Xor, Xnor, conjuncts, disjuncts, distribute_or_over_and, distribute_and_over_or, eliminate_implications, is_nnf, is_cnf, is_dnf, simplify_logic, to_nnf, to_cnf, to_dnf, to_int_repr, bool_map, true, false, BooleanAtom, is_literal, term_to_integer, integer_to_term, truth_table, as_Boolean, to_anf, is_anf, distribute_xor_over_and, anf_coeffs, ANFform, bool_minterm, bool_maxterm, bool_monomial, _check_pair, _convert_to_varsSOP, _convert_to_varsPOS, Exclusive,) from sympy.assumptions.cnf import CNF from sympy.testing.pytest import raises, XFAIL, slow from sympy.utilities.iterables import cartes from itertools import combinations, permutations A, B, C, D = symbols('A:D') a, b, c, d, e, w, x, y, z = symbols('a:e w:z') def test_overloading(): """Test that |, & are overloaded as expected""" assert A & B == And(A, B) assert A | B == Or(A, B) assert (A & B) | C == Or(And(A, B), C) assert A >> B == Implies(A, B) assert A << B == Implies(B, A) assert ~A == Not(A) assert A ^ B == Xor(A, B) def test_And(): assert And() is true assert And(A) == A assert And(True) is true assert And(False) is false assert And(True, True) is true assert And(True, False) is false assert And(False, False) is false assert And(True, A) == A assert And(False, A) is false assert And(True, True, True) is true assert And(True, True, A) == A assert And(True, False, A) is false assert And(1, A) == A raises(TypeError, lambda: And(2, A)) raises(TypeError, lambda: And(A < 2, A)) assert And(A < 1, A >= 1) is false e = A > 1 assert And(e, e.canonical) == e.canonical g, l, ge, le = A > B, B < A, A >= B, B <= A assert And(g, l, ge, le) == And(ge, g) assert {And(*i) for i in permutations((l,g,le,ge))} == {And(ge, g)} assert And(And(Eq(a, 0), Eq(b, 0)), And(Ne(a, 0), Eq(c, 0))) is false def test_Or(): assert Or() is false assert Or(A) == A assert Or(True) is true assert Or(False) is false assert Or(True, True) is true assert Or(True, False) is true assert Or(False, False) is false assert Or(True, A) is true assert Or(False, A) == A assert Or(True, False, False) is true assert Or(True, False, A) is true assert Or(False, False, A) == A assert Or(1, A) is true raises(TypeError, lambda: Or(2, A)) raises(TypeError, lambda: Or(A < 2, A)) assert Or(A < 1, A >= 1) is true e = A > 1 assert Or(e, e.canonical) == e g, l, ge, le = A > B, B < A, A >= B, B <= A assert Or(g, l, ge, le) == Or(g, ge) def test_Xor(): assert Xor() is false assert Xor(A) == A assert Xor(A, A) is false assert Xor(True, A, A) is true assert Xor(A, A, A, A, A) == A assert Xor(True, False, False, A, B) == ~Xor(A, B) assert Xor(True) is true assert Xor(False) is false assert Xor(True, True) is false assert Xor(True, False) is true assert Xor(False, False) is false assert Xor(True, A) == ~A assert Xor(False, A) == A assert Xor(True, False, False) is true assert Xor(True, False, A) == ~A assert Xor(False, False, A) == A assert isinstance(Xor(A, B), Xor) assert Xor(A, B, Xor(C, D)) == Xor(A, B, C, D) assert Xor(A, B, Xor(B, C)) == Xor(A, C) assert Xor(A < 1, A >= 1, B) == Xor(0, 1, B) == Xor(1, 0, B) e = A > 1 assert Xor(e, e.canonical) == Xor(0, 0) == Xor(1, 1) def test_rewrite_as_And(): expr = x ^ y assert expr.rewrite(And) == (x | y) & (~x | ~y) def test_rewrite_as_Or(): expr = x ^ y assert expr.rewrite(Or) == (x & ~y) | (y & ~x) def test_rewrite_as_Nand(): expr = (y & z) | (z & ~w) assert expr.rewrite(Nand) == ~(~(y & z) & ~(z & ~w)) def test_rewrite_as_Nor(): expr = z & (y | ~w) assert expr.rewrite(Nor) == ~(~z | ~(y | ~w)) def test_Not(): raises(TypeError, lambda: Not(True, False)) assert Not(True) is false assert Not(False) is true assert Not(0) is true assert Not(1) is false assert Not(2) is false def test_Nand(): assert Nand() is false assert Nand(A) == ~A assert Nand(True) is false assert Nand(False) is true assert Nand(True, True) is false assert Nand(True, False) is true assert Nand(False, False) is true assert Nand(True, A) == ~A assert Nand(False, A) is true assert Nand(True, True, True) is false assert Nand(True, True, A) == ~A assert Nand(True, False, A) is true def test_Nor(): assert Nor() is true assert Nor(A) == ~A assert Nor(True) is false assert Nor(False) is true assert Nor(True, True) is false assert Nor(True, False) is false assert Nor(False, False) is true assert Nor(True, A) is false assert Nor(False, A) == ~A assert Nor(True, True, True) is false assert Nor(True, True, A) is false assert Nor(True, False, A) is false def test_Xnor(): assert Xnor() is true assert Xnor(A) == ~A assert Xnor(A, A) is true assert Xnor(True, A, A) is false assert Xnor(A, A, A, A, A) == ~A assert Xnor(True) is false assert Xnor(False) is true assert Xnor(True, True) is true assert Xnor(True, False) is false assert Xnor(False, False) is true assert Xnor(True, A) == A assert Xnor(False, A) == ~A assert Xnor(True, False, False) is false assert Xnor(True, False, A) == A assert Xnor(False, False, A) == ~A def test_Implies(): raises(ValueError, lambda: Implies(A, B, C)) assert Implies(True, True) is true assert Implies(True, False) is false assert Implies(False, True) is true assert Implies(False, False) is true assert Implies(0, A) is true assert Implies(1, 1) is true assert Implies(1, 0) is false assert A >> B == B << A assert (A < 1) >> (A >= 1) == (A >= 1) assert (A < 1) >> (S.One > A) is true assert A >> A is true def test_Equivalent(): assert Equivalent(A, B) == Equivalent(B, A) == Equivalent(A, B, A) assert Equivalent() is true assert Equivalent(A, A) == Equivalent(A) is true assert Equivalent(True, True) == Equivalent(False, False) is true assert Equivalent(True, False) == Equivalent(False, True) is false assert Equivalent(A, True) == A assert Equivalent(A, False) == Not(A) assert Equivalent(A, B, True) == A & B assert Equivalent(A, B, False) == ~A & ~B assert Equivalent(1, A) == A assert Equivalent(0, A) == Not(A) assert Equivalent(A, Equivalent(B, C)) != Equivalent(Equivalent(A, B), C) assert Equivalent(A < 1, A >= 1) is false assert Equivalent(A < 1, A >= 1, 0) is false assert Equivalent(A < 1, A >= 1, 1) is false assert Equivalent(A < 1, S.One > A) == Equivalent(1, 1) == Equivalent(0, 0) assert Equivalent(Equality(A, B), Equality(B, A)) is true def test_Exclusive(): assert Exclusive(False, False, False) is true assert Exclusive(True, False, False) is true assert Exclusive(True, True, False) is false assert Exclusive(True, True, True) is false def test_equals(): assert Not(Or(A, B)).equals(And(Not(A), Not(B))) is True assert Equivalent(A, B).equals((A >> B) & (B >> A)) is True assert ((A | ~B) & (~A | B)).equals((~A & ~B) | (A & B)) is True assert (A >> B).equals(~A >> ~B) is False assert (A >> (B >> A)).equals(A >> (C >> A)) is False raises(NotImplementedError, lambda: (A & B).equals(A > B)) def test_simplification(): """ Test working of simplification methods. """ set1 = [[0, 0, 1], [0, 1, 1], [1, 0, 0], [1, 1, 0]] set2 = [[0, 0, 0], [0, 1, 0], [1, 0, 1], [1, 1, 1]] assert SOPform([x, y, z], set1) == Or(And(Not(x), z), And(Not(z), x)) assert Not(SOPform([x, y, z], set2)) == \ Not(Or(And(Not(x), Not(z)), And(x, z))) assert POSform([x, y, z], set1 + set2) is true assert SOPform([x, y, z], set1 + set2) is true assert SOPform([Dummy(), Dummy(), Dummy()], set1 + set2) is true minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]] dontcares = [[0, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 1]] assert ( SOPform([w, x, y, z], minterms, dontcares) == Or(And(y, z), And(Not(w), Not(x)))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [1, 3, 7, 11, 15] dontcares = [0, 2, 5] assert ( SOPform([w, x, y, z], minterms, dontcares) == Or(And(y, z), And(Not(w), Not(x)))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [1, [0, 0, 1, 1], 7, [1, 0, 1, 1], [1, 1, 1, 1]] dontcares = [0, [0, 0, 1, 0], 5] assert ( SOPform([w, x, y, z], minterms, dontcares) == Or(And(y, z), And(Not(w), Not(x)))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [1, {y: 1, z: 1}] dontcares = [0, [0, 0, 1, 0], 5] assert ( SOPform([w, x, y, z], minterms, dontcares) == Or(And(y, z), And(Not(w), Not(x)))) assert POSform([w, x, y, z], minterms, dontcares) == And(Or(Not(w), y), z) minterms = [{y: 1, z: 1}, 1] dontcares = [[0, 0, 0, 0]] minterms = [[0, 0, 0]] raises(ValueError, lambda: SOPform([w, x, y, z], minterms)) raises(ValueError, lambda: POSform([w, x, y, z], minterms)) raises(TypeError, lambda: POSform([w, x, y, z], ["abcdefg"])) # test simplification ans = And(A, Or(B, C)) assert simplify_logic(A & (B | C)) == ans assert simplify_logic((A & B) | (A & C)) == ans assert simplify_logic(Implies(A, B)) == Or(Not(A), B) assert simplify_logic(Equivalent(A, B)) == \ Or(And(A, B), And(Not(A), Not(B))) assert simplify_logic(And(Equality(A, 2), C)) == And(Equality(A, 2), C) assert simplify_logic(And(Equality(A, 2), A)) is S.false assert simplify_logic(And(Equality(A, 2), A)) == And(Equality(A, 2), A) assert simplify_logic(And(Equality(A, B), C)) == And(Equality(A, B), C) assert simplify_logic(Or(And(Equality(A, 3), B), And(Equality(A, 3), C))) \ == And(Equality(A, 3), Or(B, C)) b = (~x & ~y & ~z) | (~x & ~y & z) e = And(A, b) assert simplify_logic(e) == A & ~x & ~y raises(ValueError, lambda: simplify_logic(A & (B | C), form='blabla')) # Check that expressions with nine variables or more are not simplified # (without the force-flag) a, b, c, d, e, f, g, h, j = symbols('a b c d e f g h j') expr = a & b & c & d & e & f & g & h & j | \ a & b & c & d & e & f & g & h & ~j # This expression can be simplified to get rid of the j variables assert simplify_logic(expr) == expr # check input ans = SOPform([x, y], [[1, 0]]) assert SOPform([x, y], [[1, 0]]) == ans assert POSform([x, y], [[1, 0]]) == ans raises(ValueError, lambda: SOPform([x], [[1]], [[1]])) assert SOPform([x], [[1]], [[0]]) is true assert SOPform([x], [[0]], [[1]]) is true assert SOPform([x], [], []) is false raises(ValueError, lambda: POSform([x], [[1]], [[1]])) assert POSform([x], [[1]], [[0]]) is true assert POSform([x], [[0]], [[1]]) is true assert POSform([x], [], []) is false # check working of simplify assert simplify((A & B) | (A & C)) == And(A, Or(B, C)) assert simplify(And(x, Not(x))) == False assert simplify(Or(x, Not(x))) == True assert simplify(And(Eq(x, 0), Eq(x, y))) == And(Eq(x, 0), Eq(y, 0)) assert And(Eq(x - 1, 0), Eq(x, y)).simplify() == And(Eq(x, 1), Eq(y, 1)) assert And(Ne(x - 1, 0), Ne(x, y)).simplify() == And(Ne(x, 1), Ne(x, y)) assert And(Eq(x - 1, 0), Ne(x, y)).simplify() == And(Eq(x, 1), Ne(y, 1)) assert And(Eq(x - 1, 0), Eq(x, z + y), Eq(y + x, 0)).simplify( ) == And(Eq(x, 1), Eq(y, -1), Eq(z, 2)) assert And(Eq(x - 1, 0), Eq(x + 2, 3)).simplify() == Eq(x, 1) assert And(Ne(x - 1, 0), Ne(x + 2, 3)).simplify() == Ne(x, 1) assert And(Eq(x - 1, 0), Eq(x + 2, 2)).simplify() == False assert And(Ne(x - 1, 0), Ne(x + 2, 2)).simplify( ) == And(Ne(x, 1), Ne(x, 0)) def test_bool_map(): """ Test working of bool_map function. """ minterms = [[0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 1, 1], [1, 0, 1, 1], [1, 1, 1, 1]] assert bool_map(Not(Not(a)), a) == (a, {a: a}) assert bool_map(SOPform([w, x, y, z], minterms), POSform([w, x, y, z], minterms)) == \ (And(Or(Not(w), y), Or(Not(x), y), z), {x: x, w: w, z: z, y: y}) assert bool_map(SOPform([x, z, y], [[1, 0, 1]]), SOPform([a, b, c], [[1, 0, 1]])) != False function1 = SOPform([x, z, y], [[1, 0, 1], [0, 0, 1]]) function2 = SOPform([a, b, c], [[1, 0, 1], [1, 0, 0]]) assert bool_map(function1, function2) == \ (function1, {y: a, z: b}) assert bool_map(Xor(x, y), ~Xor(x, y)) == False assert bool_map(And(x, y), Or(x, y)) is None assert bool_map(And(x, y), And(x, y, z)) is None # issue 16179 assert bool_map(Xor(x, y, z), ~Xor(x, y, z)) == False assert bool_map(Xor(a, x, y, z), ~Xor(a, x, y, z)) == False def test_bool_symbol(): """Test that mixing symbols with boolean values works as expected""" assert And(A, True) == A assert And(A, True, True) == A assert And(A, False) is false assert And(A, True, False) is false assert Or(A, True) is true assert Or(A, False) == A def test_is_boolean(): assert isinstance(True, Boolean) is False assert isinstance(true, Boolean) is True assert 1 == True assert 1 != true assert (1 == true) is False assert 0 == False assert 0 != false assert (0 == false) is False assert true.is_Boolean is True assert (A & B).is_Boolean assert (A | B).is_Boolean assert (~A).is_Boolean assert (A ^ B).is_Boolean assert A.is_Boolean != isinstance(A, Boolean) assert isinstance(A, Boolean) def test_subs(): assert (A & B).subs(A, True) == B assert (A & B).subs(A, False) is false assert (A & B).subs(B, True) == A assert (A & B).subs(B, False) is false assert (A & B).subs({A: True, B: True}) is true assert (A | B).subs(A, True) is true assert (A | B).subs(A, False) == B assert (A | B).subs(B, True) is true assert (A | B).subs(B, False) == A assert (A | B).subs({A: True, B: True}) is true """ we test for axioms of boolean algebra see https://en.wikipedia.org/wiki/Boolean_algebra_(structure) """ def test_commutative(): """Test for commutativity of And and Or""" A, B = map(Boolean, symbols('A,B')) assert A & B == B & A assert A | B == B | A def test_and_associativity(): """Test for associativity of And""" assert (A & B) & C == A & (B & C) def test_or_assicativity(): assert ((A | B) | C) == (A | (B | C)) def test_double_negation(): a = Boolean() assert ~(~a) == a # test methods def test_eliminate_implications(): assert eliminate_implications(Implies(A, B, evaluate=False)) == (~A) | B assert eliminate_implications( A >> (C >> Not(B))) == Or(Or(Not(B), Not(C)), Not(A)) assert eliminate_implications(Equivalent(A, B, C, D)) == \ (~A | B) & (~B | C) & (~C | D) & (~D | A) def test_conjuncts(): assert conjuncts(A & B & C) == {A, B, C} assert conjuncts((A | B) & C) == {A | B, C} assert conjuncts(A) == {A} assert conjuncts(True) == {True} assert conjuncts(False) == {False} def test_disjuncts(): assert disjuncts(A | B | C) == {A, B, C} assert disjuncts((A | B) & C) == {(A | B) & C} assert disjuncts(A) == {A} assert disjuncts(True) == {True} assert disjuncts(False) == {False} def test_distribute(): assert distribute_and_over_or(Or(And(A, B), C)) == And(Or(A, C), Or(B, C)) assert distribute_or_over_and(And(A, Or(B, C))) == Or(And(A, B), And(A, C)) assert distribute_xor_over_and(And(A, Xor(B, C))) == Xor(And(A, B), And(A, C)) def test_to_anf(): x, y, z = symbols('x,y,z') assert to_anf(And(x, y)) == And(x, y) assert to_anf(Or(x, y)) == Xor(x, y, And(x, y)) assert to_anf(Or(Implies(x, y), And(x, y), y)) == \ Xor(x, True, x & y, remove_true=False) assert to_anf(Or(Nand(x, y), Nor(x, y), Xnor(x, y), Implies(x, y))) == True assert to_anf(Or(x, Not(y), Nor(x,z), And(x, y), Nand(y, z))) == \ Xor(True, And(y, z), And(x, y, z), remove_true=False) assert to_anf(Xor(x, y)) == Xor(x, y) assert to_anf(Not(x)) == Xor(x, True, remove_true=False) assert to_anf(Nand(x, y)) == Xor(True, And(x, y), remove_true=False) assert to_anf(Nor(x, y)) == Xor(x, y, True, And(x, y), remove_true=False) assert to_anf(Implies(x, y)) == Xor(x, True, And(x, y), remove_true=False) assert to_anf(Equivalent(x, y)) == Xor(x, y, True, remove_true=False) assert to_anf(Nand(x | y, x >> y), deep=False) == \ Xor(True, And(Or(x, y), Implies(x, y)), remove_true=False) assert to_anf(Nor(x ^ y, x & y), deep=False) == \ Xor(True, Or(Xor(x, y), And(x, y)), remove_true=False) def test_to_nnf(): assert to_nnf(true) is true assert to_nnf(false) is false assert to_nnf(A) == A assert to_nnf(A | ~A | B) is true assert to_nnf(A & ~A & B) is false assert to_nnf(A >> B) == ~A | B assert to_nnf(Equivalent(A, B, C)) == (~A | B) & (~B | C) & (~C | A) assert to_nnf(A ^ B ^ C) == \ (A | B | C) & (~A | ~B | C) & (A | ~B | ~C) & (~A | B | ~C) assert to_nnf(ITE(A, B, C)) == (~A | B) & (A | C) assert to_nnf(Not(A | B | C)) == ~A & ~B & ~C assert to_nnf(Not(A & B & C)) == ~A | ~B | ~C assert to_nnf(Not(A >> B)) == A & ~B assert to_nnf(Not(Equivalent(A, B, C))) == And(Or(A, B, C), Or(~A, ~B, ~C)) assert to_nnf(Not(A ^ B ^ C)) == \ (~A | B | C) & (A | ~B | C) & (A | B | ~C) & (~A | ~B | ~C) assert to_nnf(Not(ITE(A, B, C))) == (~A | ~B) & (A | ~C) assert to_nnf((A >> B) ^ (B >> A)) == (A & ~B) | (~A & B) assert to_nnf((A >> B) ^ (B >> A), False) == \ (~A | ~B | A | B) & ((A & ~B) | (~A & B)) assert ITE(A, 1, 0).to_nnf() == A assert ITE(A, 0, 1).to_nnf() == ~A # although ITE can hold non-Boolean, it will complain if # an attempt is made to convert the ITE to Boolean nnf raises(TypeError, lambda: ITE(A < 1, [1], B).to_nnf()) def test_to_cnf(): assert to_cnf(~(B | C)) == And(Not(B), Not(C)) assert to_cnf((A & B) | C) == And(Or(A, C), Or(B, C)) assert to_cnf(A >> B) == (~A) | B assert to_cnf(A >> (B & C)) == (~A | B) & (~A | C) assert to_cnf(A & (B | C) | ~A & (B | C), True) == B | C assert to_cnf(A & B) == And(A, B) assert to_cnf(Equivalent(A, B)) == And(Or(A, Not(B)), Or(B, Not(A))) assert to_cnf(Equivalent(A, B & C)) == \ (~A | B) & (~A | C) & (~B | ~C | A) assert to_cnf(Equivalent(A, B | C), True) == \ And(Or(Not(B), A), Or(Not(C), A), Or(B, C, Not(A))) assert to_cnf(A + 1) == A + 1 def test_issue_18904(): x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 = symbols('x1:16') eq = (( x1 & x2 & x3 & x4 & x5 & x6 & x7 & x8 & x9 ) | ( x1 & x2 & x3 & x4 & x5 & x6 & x7 & x10 & x9 ) | ( x1 & x11 & x3 & x12 & x5 & x13 & x14 & x15 & x9 )) assert is_cnf(to_cnf(eq)) raises(ValueError, lambda: to_cnf(eq, simplify=True)) for f, t in zip((And, Or), (to_cnf, to_dnf)): eq = f(x1, x2, x3, x4, x5, x6, x7, x8, x9) raises(ValueError, lambda: to_cnf(eq, simplify=True)) assert t(eq, simplify=True, force=True) == eq def test_issue_9949(): assert is_cnf(to_cnf((b > -5) | (a > 2) & (a < 4))) def test_to_CNF(): assert CNF.CNF_to_cnf(CNF.to_CNF(~(B | C))) == to_cnf(~(B | C)) assert CNF.CNF_to_cnf(CNF.to_CNF((A & B) | C)) == to_cnf((A & B) | C) assert CNF.CNF_to_cnf(CNF.to_CNF(A >> B)) == to_cnf(A >> B) assert CNF.CNF_to_cnf(CNF.to_CNF(A >> (B & C))) == to_cnf(A >> (B & C)) assert CNF.CNF_to_cnf(CNF.to_CNF(A & (B | C) | ~A & (B | C))) == to_cnf(A & (B | C) | ~A & (B | C)) assert CNF.CNF_to_cnf(CNF.to_CNF(A & B)) == to_cnf(A & B) def test_to_dnf(): assert to_dnf(~(B | C)) == And(Not(B), Not(C)) assert to_dnf(A & (B | C)) == Or(And(A, B), And(A, C)) assert to_dnf(A >> B) == (~A) | B assert to_dnf(A >> (B & C)) == (~A) | (B & C) assert to_dnf(A | B) == A | B assert to_dnf(Equivalent(A, B), True) == \ Or(And(A, B), And(Not(A), Not(B))) assert to_dnf(Equivalent(A, B & C), True) == \ Or(And(A, B, C), And(Not(A), Not(B)), And(Not(A), Not(C))) assert to_dnf(A + 1) == A + 1 def test_to_int_repr(): x, y, z = map(Boolean, symbols('x,y,z')) def sorted_recursive(arg): try: return sorted(sorted_recursive(x) for x in arg) except TypeError: # arg is not a sequence return arg assert sorted_recursive(to_int_repr([x | y, z | x], [x, y, z])) == \ sorted_recursive([[1, 2], [1, 3]]) assert sorted_recursive(to_int_repr([x | y, z | ~x], [x, y, z])) == \ sorted_recursive([[1, 2], [3, -1]]) def test_is_anf(): x, y = symbols('x,y') assert is_anf(true) is True assert is_anf(false) is True assert is_anf(x) is True assert is_anf(And(x, y)) is True assert is_anf(Xor(x, y, And(x, y))) is True assert is_anf(Xor(x, y, Or(x, y))) is False assert is_anf(Xor(Not(x), y)) is False def test_is_nnf(): assert is_nnf(true) is True assert is_nnf(A) is True assert is_nnf(~A) is True assert is_nnf(A & B) is True assert is_nnf((A & B) | (~A & A) | (~B & B) | (~A & ~B), False) is True assert is_nnf((A | B) & (~A | ~B)) is True assert is_nnf(Not(Or(A, B))) is False assert is_nnf(A ^ B) is False assert is_nnf((A & B) | (~A & A) | (~B & B) | (~A & ~B), True) is False def test_is_cnf(): assert is_cnf(x) is True assert is_cnf(x | y | z) is True assert is_cnf(x & y & z) is True assert is_cnf((x | y) & z) is True assert is_cnf((x & y) | z) is False assert is_cnf(~(x & y) | z) is False def test_is_dnf(): assert is_dnf(x) is True assert is_dnf(x | y | z) is True assert is_dnf(x & y & z) is True assert is_dnf((x & y) | z) is True assert is_dnf((x | y) & z) is False assert is_dnf(~(x | y) & z) is False def test_ITE(): A, B, C = symbols('A:C') assert ITE(True, False, True) is false assert ITE(True, True, False) is true assert ITE(False, True, False) is false assert ITE(False, False, True) is true assert isinstance(ITE(A, B, C), ITE) A = True assert ITE(A, B, C) == B A = False assert ITE(A, B, C) == C B = True assert ITE(And(A, B), B, C) == C assert ITE(Or(A, False), And(B, True), False) is false assert ITE(x, A, B) == Not(x) assert ITE(x, B, A) == x assert ITE(1, x, y) == x assert ITE(0, x, y) == y raises(TypeError, lambda: ITE(2, x, y)) raises(TypeError, lambda: ITE(1, [], y)) raises(TypeError, lambda: ITE(1, (), y)) raises(TypeError, lambda: ITE(1, y, [])) assert ITE(1, 1, 1) is S.true assert isinstance(ITE(1, 1, 1, evaluate=False), ITE) raises(TypeError, lambda: ITE(x > 1, y, x)) assert ITE(Eq(x, True), y, x) == ITE(x, y, x) assert ITE(Eq(x, False), y, x) == ITE(~x, y, x) assert ITE(Ne(x, True), y, x) == ITE(~x, y, x) assert ITE(Ne(x, False), y, x) == ITE(x, y, x) assert ITE(Eq(S. true, x), y, x) == ITE(x, y, x) assert ITE(Eq(S.false, x), y, x) == ITE(~x, y, x) assert ITE(Ne(S.true, x), y, x) == ITE(~x, y, x) assert ITE(Ne(S.false, x), y, x) == ITE(x, y, x) # 0 and 1 in the context are not treated as True/False # so the equality must always be False since dissimilar # objects cannot be equal assert ITE(Eq(x, 0), y, x) == x assert ITE(Eq(x, 1), y, x) == x assert ITE(Ne(x, 0), y, x) == y assert ITE(Ne(x, 1), y, x) == y assert ITE(Eq(x, 0), y, z).subs(x, 0) == y assert ITE(Eq(x, 0), y, z).subs(x, 1) == z raises(ValueError, lambda: ITE(x > 1, y, x, z)) def test_is_literal(): assert is_literal(True) is True assert is_literal(False) is True assert is_literal(A) is True assert is_literal(~A) is True assert is_literal(Or(A, B)) is False assert is_literal(Q.zero(A)) is True assert is_literal(Not(Q.zero(A))) is True assert is_literal(Or(A, B)) is False assert is_literal(And(Q.zero(A), Q.zero(B))) is False assert is_literal(x < 3) assert not is_literal(x + y < 3) def test_operators(): # Mostly test __and__, __rand__, and so on assert True & A == A & True == A assert False & A == A & False == False assert A & B == And(A, B) assert True | A == A | True == True assert False | A == A | False == A assert A | B == Or(A, B) assert ~A == Not(A) assert True >> A == A << True == A assert False >> A == A << False == True assert A >> True == True << A == True assert A >> False == False << A == ~A assert A >> B == B << A == Implies(A, B) assert True ^ A == A ^ True == ~A assert False ^ A == A ^ False == A assert A ^ B == Xor(A, B) def test_true_false(): assert true is S.true assert false is S.false assert true is not True assert false is not False assert true assert not false assert true == True assert false == False assert not (true == False) assert not (false == True) assert not (true == false) assert hash(true) == hash(True) assert hash(false) == hash(False) assert len({true, True}) == len({false, False}) == 1 assert isinstance(true, BooleanAtom) assert isinstance(false, BooleanAtom) # We don't want to subclass from bool, because bool subclasses from # int. But operators like &, |, ^, <<, >>, and ~ act differently on 0 and # 1 then we want them to on true and false. See the docstrings of the # various And, Or, etc. functions for examples. assert not isinstance(true, bool) assert not isinstance(false, bool) # Note: using 'is' comparison is important here. We want these to return # true and false, not True and False assert Not(true) is false assert Not(True) is false assert Not(false) is true assert Not(False) is true assert ~true is false assert ~false is true for T, F in cartes([True, true], [False, false]): assert And(T, F) is false assert And(F, T) is false assert And(F, F) is false assert And(T, T) is true assert And(T, x) == x assert And(F, x) is false if not (T is True and F is False): assert T & F is false assert F & T is false if F is not False: assert F & F is false if T is not True: assert T & T is true assert Or(T, F) is true assert Or(F, T) is true assert Or(F, F) is false assert Or(T, T) is true assert Or(T, x) is true assert Or(F, x) == x if not (T is True and F is False): assert T | F is true assert F | T is true if F is not False: assert F | F is false if T is not True: assert T | T is true assert Xor(T, F) is true assert Xor(F, T) is true assert Xor(F, F) is false assert Xor(T, T) is false assert Xor(T, x) == ~x assert Xor(F, x) == x if not (T is True and F is False): assert T ^ F is true assert F ^ T is true if F is not False: assert F ^ F is false if T is not True: assert T ^ T is false assert Nand(T, F) is true assert Nand(F, T) is true assert Nand(F, F) is true assert Nand(T, T) is false assert Nand(T, x) == ~x assert Nand(F, x) is true assert Nor(T, F) is false assert Nor(F, T) is false assert Nor(F, F) is true assert Nor(T, T) is false assert Nor(T, x) is false assert Nor(F, x) == ~x assert Implies(T, F) is false assert Implies(F, T) is true assert Implies(F, F) is true assert Implies(T, T) is true assert Implies(T, x) == x assert Implies(F, x) is true assert Implies(x, T) is true assert Implies(x, F) == ~x if not (T is True and F is False): assert T >> F is false assert F << T is false assert F >> T is true assert T << F is true if F is not False: assert F >> F is true assert F << F is true if T is not True: assert T >> T is true assert T << T is true assert Equivalent(T, F) is false assert Equivalent(F, T) is false assert Equivalent(F, F) is true assert Equivalent(T, T) is true assert Equivalent(T, x) == x assert Equivalent(F, x) == ~x assert Equivalent(x, T) == x assert Equivalent(x, F) == ~x assert ITE(T, T, T) is true assert ITE(T, T, F) is true assert ITE(T, F, T) is false assert ITE(T, F, F) is false assert ITE(F, T, T) is true assert ITE(F, T, F) is false assert ITE(F, F, T) is true assert ITE(F, F, F) is false assert all(i.simplify(1, 2) is i for i in (S.true, S.false)) def test_bool_as_set(): assert ITE(y <= 0, False, y >= 1).as_set() == Interval(1, oo) assert And(x <= 2, x >= -2).as_set() == Interval(-2, 2) assert Or(x >= 2, x <= -2).as_set() == Interval(-oo, -2) + Interval(2, oo) assert Not(x > 2).as_set() == Interval(-oo, 2) # issue 10240 assert Not(And(x > 2, x < 3)).as_set() == \ Union(Interval(-oo, 2), Interval(3, oo)) assert true.as_set() == S.UniversalSet assert false.as_set() == EmptySet() assert x.as_set() == S.UniversalSet assert And(Or(x < 1, x > 3), x < 2).as_set() == Interval.open(-oo, 1) assert And(x < 1, sin(x) < 3).as_set() == (x < 1).as_set() raises(NotImplementedError, lambda: (sin(x) < 1).as_set()) @XFAIL def test_multivariate_bool_as_set(): x, y = symbols('x,y') assert And(x >= 0, y >= 0).as_set() == Interval(0, oo)*Interval(0, oo) assert Or(x >= 0, y >= 0).as_set() == S.Reals*S.Reals - \ Interval(-oo, 0, True, True)*Interval(-oo, 0, True, True) def test_all_or_nothing(): x = symbols('x', extended_real=True) args = x >= -oo, x <= oo v = And(*args) if v.func is And: assert len(v.args) == len(args) - args.count(S.true) else: assert v == True v = Or(*args) if v.func is Or: assert len(v.args) == 2 else: assert v == True def test_canonical_atoms(): assert true.canonical == true assert false.canonical == false def test_negated_atoms(): assert true.negated == false assert false.negated == true def test_issue_8777(): assert And(x > 2, x < oo).as_set() == Interval(2, oo, left_open=True) assert And(x >= 1, x < oo).as_set() == Interval(1, oo) assert (x < oo).as_set() == Interval(-oo, oo) assert (x > -oo).as_set() == Interval(-oo, oo) def test_issue_8975(): assert Or(And(-oo < x, x <= -2), And(2 <= x, x < oo)).as_set() == \ Interval(-oo, -2) + Interval(2, oo) def test_term_to_integer(): assert term_to_integer([1, 0, 1, 0, 0, 1, 0]) == 82 assert term_to_integer('0010101000111001') == 10809 def test_integer_to_term(): assert integer_to_term(777) == [1, 1, 0, 0, 0, 0, 1, 0, 0, 1] assert integer_to_term(123, 3) == [1, 1, 1, 1, 0, 1, 1] assert integer_to_term(456, 16) == [0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0] def test_issue_21971(): a, b, c, d = symbols('a b c d') f = a & b & c | a & c assert f.subs(a & c, d) == b & d | d assert f.subs(a & b & c, d) == a & c | d f = (a | b | c) & (a | c) assert f.subs(a | c, d) == (b | d) & d assert f.subs(a | b | c, d) == (a | c) & d f = (a ^ b ^ c) & (a ^ c) assert f.subs(a ^ c, d) == (b ^ d) & d assert f.subs(a ^ b ^ c, d) == (a ^ c) & d def test_truth_table(): assert list(truth_table(And(x, y), [x, y], input=False)) == \ [False, False, False, True] assert list(truth_table(x | y, [x, y], input=False)) == \ [False, True, True, True] assert list(truth_table(x >> y, [x, y], input=False)) == \ [True, True, False, True] assert list(truth_table(And(x, y), [x, y])) == \ [([0, 0], False), ([0, 1], False), ([1, 0], False), ([1, 1], True)] def test_issue_8571(): for t in (S.true, S.false): raises(TypeError, lambda: +t) raises(TypeError, lambda: -t) raises(TypeError, lambda: abs(t)) # use int(bool(t)) to get 0 or 1 raises(TypeError, lambda: int(t)) for o in [S.Zero, S.One, x]: for _ in range(2): raises(TypeError, lambda: o + t) raises(TypeError, lambda: o - t) raises(TypeError, lambda: o % t) raises(TypeError, lambda: o*t) raises(TypeError, lambda: o/t) raises(TypeError, lambda: o**t) o, t = t, o # do again in reversed order def test_expand_relational(): n = symbols('n', negative=True) p, q = symbols('p q', positive=True) r = ((n + q*(-n/q + 1))/(q*(-n/q + 1)) < 0) assert r is not S.false assert r.expand() is S.false assert (q > 0).expand() is S.true def test_issue_12717(): assert S.true.is_Atom == True assert S.false.is_Atom == True def test_as_Boolean(): nz = symbols('nz', nonzero=True) assert all(as_Boolean(i) is S.true for i in (True, S.true, 1, nz)) z = symbols('z', zero=True) assert all(as_Boolean(i) is S.false for i in (False, S.false, 0, z)) assert all(as_Boolean(i) == i for i in (x, x < 0)) for i in (2, S(2), x + 1, []): raises(TypeError, lambda: as_Boolean(i)) def test_binary_symbols(): assert ITE(x < 1, y, z).binary_symbols == {y, z} for f in (Eq, Ne): assert f(x, 1).binary_symbols == set() assert f(x, True).binary_symbols == {x} assert f(x, False).binary_symbols == {x} assert S.true.binary_symbols == set() assert S.false.binary_symbols == set() assert x.binary_symbols == {x} assert And(x, Eq(y, False), Eq(z, 1)).binary_symbols == {x, y} assert Q.prime(x).binary_symbols == set() assert Q.lt(x, 1).binary_symbols == set() assert Q.is_true(x).binary_symbols == {x} assert Q.eq(x, True).binary_symbols == {x} assert Q.prime(x).binary_symbols == set() def test_BooleanFunction_diff(): assert And(x, y).diff(x) == Piecewise((0, Eq(y, False)), (1, True)) def test_issue_14700(): A, B, C, D, E, F, G, H = symbols('A B C D E F G H') q = ((B & D & H & ~F) | (B & H & ~C & ~D) | (B & H & ~C & ~F) | (B & H & ~D & ~G) | (B & H & ~F & ~G) | (C & G & ~B & ~D) | (C & G & ~D & ~H) | (C & G & ~F & ~H) | (D & F & H & ~B) | (D & F & ~G & ~H) | (B & D & F & ~C & ~H) | (D & E & F & ~B & ~C) | (D & F & ~A & ~B & ~C) | (D & F & ~A & ~C & ~H) | (A & B & D & F & ~E & ~H)) soldnf = ((B & D & H & ~F) | (D & F & H & ~B) | (B & H & ~C & ~D) | (B & H & ~D & ~G) | (C & G & ~B & ~D) | (C & G & ~D & ~H) | (C & G & ~F & ~H) | (D & F & ~G & ~H) | (D & E & F & ~C & ~H) | (D & F & ~A & ~C & ~H) | (A & B & D & F & ~E & ~H)) solcnf = ((B | C | D) & (B | D | G) & (C | D | H) & (C | F | H) & (D | G | H) & (F | G | H) & (B | F | ~D | ~H) & (~B | ~D | ~F | ~H) & (D | ~B | ~C | ~G | ~H) & (A | H | ~C | ~D | ~F | ~G) & (H | ~C | ~D | ~E | ~F | ~G) & (B | E | H | ~A | ~D | ~F | ~G)) assert simplify_logic(q, "dnf") == soldnf assert simplify_logic(q, "cnf") == solcnf minterms = [[0, 1, 0, 0], [0, 1, 0, 1], [0, 1, 1, 0], [0, 1, 1, 1], [0, 0, 1, 1], [1, 0, 1, 1]] dontcares = [[1, 0, 0, 0], [1, 0, 0, 1], [1, 1, 0, 0], [1, 1, 0, 1]] assert SOPform([w, x, y, z], minterms) == (x & ~w) | (y & z & ~x) # Should not be more complicated with don't cares assert SOPform([w, x, y, z], minterms, dontcares) == \ (x & ~w) | (y & z & ~x) def test_relational_simplification(): w, x, y, z = symbols('w x y z', real=True) d, e = symbols('d e', real=False) # Test all combinations or sign and order assert Or(x >= y, x < y).simplify() == S.true assert Or(x >= y, y > x).simplify() == S.true assert Or(x >= y, -x > -y).simplify() == S.true assert Or(x >= y, -y < -x).simplify() == S.true assert Or(-x <= -y, x < y).simplify() == S.true assert Or(-x <= -y, -x > -y).simplify() == S.true assert Or(-x <= -y, y > x).simplify() == S.true assert Or(-x <= -y, -y < -x).simplify() == S.true assert Or(y <= x, x < y).simplify() == S.true assert Or(y <= x, y > x).simplify() == S.true assert Or(y <= x, -x > -y).simplify() == S.true assert Or(y <= x, -y < -x).simplify() == S.true assert Or(-y >= -x, x < y).simplify() == S.true assert Or(-y >= -x, y > x).simplify() == S.true assert Or(-y >= -x, -x > -y).simplify() == S.true assert Or(-y >= -x, -y < -x).simplify() == S.true assert Or(x < y, x >= y).simplify() == S.true assert Or(y > x, x >= y).simplify() == S.true assert Or(-x > -y, x >= y).simplify() == S.true assert Or(-y < -x, x >= y).simplify() == S.true assert Or(x < y, -x <= -y).simplify() == S.true assert Or(-x > -y, -x <= -y).simplify() == S.true assert Or(y > x, -x <= -y).simplify() == S.true assert Or(-y < -x, -x <= -y).simplify() == S.true assert Or(x < y, y <= x).simplify() == S.true assert Or(y > x, y <= x).simplify() == S.true assert Or(-x > -y, y <= x).simplify() == S.true assert Or(-y < -x, y <= x).simplify() == S.true assert Or(x < y, -y >= -x).simplify() == S.true assert Or(y > x, -y >= -x).simplify() == S.true assert Or(-x > -y, -y >= -x).simplify() == S.true assert Or(-y < -x, -y >= -x).simplify() == S.true # Some other tests assert Or(x >= y, w < z, x <= y).simplify() == S.true assert And(x >= y, x < y).simplify() == S.false assert Or(x >= y, Eq(y, x)).simplify() == (x >= y) assert And(x >= y, Eq(y, x)).simplify() == Eq(x, y) assert And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y).simplify() == \ (Eq(x, y) & (x >= 1) & (y >= 5) & (y > z)) assert (Eq(x, y) & Eq(d, e) & (x >= y) & (d >= e)).simplify() == \ (Eq(x, y) & Eq(d, e) & (d >= e)) assert And(Eq(x, y), Eq(x, -y)).simplify() == And(Eq(x, 0), Eq(y, 0)) assert Xor(x >= y, x <= y).simplify() == Ne(x, y) @slow def test_relational_simplification_numerically(): def test_simplification_numerically_function(original, simplified): symb = original.free_symbols n = len(symb) valuelist = list(set(list(combinations(list(range(-(n-1), n))*n, n)))) for values in valuelist: sublist = dict(zip(symb, values)) originalvalue = original.subs(sublist) simplifiedvalue = simplified.subs(sublist) assert originalvalue == simplifiedvalue, "Original: {}\nand"\ " simplified: {}\ndo not evaluate to the same value for {}"\ "".format(original, simplified, sublist) w, x, y, z = symbols('w x y z', real=True) d, e = symbols('d e', real=False) expressions = (And(Eq(x, y), x >= y, w < y, y >= z, z < y), And(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y), Or(Eq(x, y), x >= 1, 2 < y, y >= 5, z < y), And(x >= y, Eq(y, x)), Or(And(Eq(x, y), x >= y, w < y, Or(y >= z, z < y)), And(Eq(x, y), x >= 1, 2 < y, y >= -1, z < y)), (Eq(x, y) & Eq(d, e) & (x >= y) & (d >= e)), ) for expression in expressions: test_simplification_numerically_function(expression, expression.simplify()) def test_relational_simplification_patterns_numerically(): from sympy.core import Wild from sympy.logic.boolalg import simplify_patterns_and, \ simplify_patterns_or, simplify_patterns_xor a = Wild('a') b = Wild('b') c = Wild('c') symb = [a, b, c] patternlists = [simplify_patterns_and(), simplify_patterns_or(), simplify_patterns_xor()] for patternlist in patternlists: for pattern in patternlist: original = pattern[0] simplified = pattern[1] valuelist = list(set(list(combinations(list(range(-2, 2))*3, 3)))) for values in valuelist: sublist = dict(zip(symb, values)) originalvalue = original.subs(sublist) simplifiedvalue = simplified.subs(sublist) assert originalvalue == simplifiedvalue, "Original: {}\nand"\ " simplified: {}\ndo not evaluate to the same value for"\ "{}".format(original, simplified, sublist) def test_issue_16803(): n = symbols('n') # No simplification done, but should not raise an exception assert ((n > 3) | (n < 0) | ((n > 0) & (n < 3))).simplify() == \ ((n > 3) | (n < 0) | ((n > 0) & (n < 3))) def test_issue_17530(): r = {x: oo, y: oo} assert Or(x + y > 0, x - y < 0).subs(r) assert not And(x + y < 0, x - y < 0).subs(r) raises(TypeError, lambda: Or(x + y < 0, x - y < 0).subs(r)) raises(TypeError, lambda: And(x + y > 0, x - y < 0).subs(r)) raises(TypeError, lambda: And(x + y > 0, x - y < 0).subs(r)) def test_anf_coeffs(): assert anf_coeffs([1, 0]) == [1, 1] assert anf_coeffs([0, 0, 0, 1]) == [0, 0, 0, 1] assert anf_coeffs([0, 1, 1, 1]) == [0, 1, 1, 1] assert anf_coeffs([1, 1, 1, 0]) == [1, 0, 0, 1] assert anf_coeffs([1, 0, 0, 0]) == [1, 1, 1, 1] assert anf_coeffs([1, 0, 0, 1]) == [1, 1, 1, 0] assert anf_coeffs([1, 1, 0, 1]) == [1, 0, 1, 1] def test_ANFform(): x, y = symbols('x,y') assert ANFform([x], [1, 1]) == True assert ANFform([x], [0, 0]) == False assert ANFform([x], [1, 0]) == Xor(x, True, remove_true=False) assert ANFform([x, y], [1, 1, 1, 0]) == \ Xor(True, And(x, y), remove_true=False) def test_bool_minterm(): x, y = symbols('x,y') assert bool_minterm(3, [x, y]) == And(x, y) assert bool_minterm([1, 0], [x, y]) == And(Not(y), x) def test_bool_maxterm(): x, y = symbols('x,y') assert bool_maxterm(2, [x, y]) == Or(Not(x), y) assert bool_maxterm([0, 1], [x, y]) == Or(Not(y), x) def test_bool_monomial(): x, y = symbols('x,y') assert bool_monomial(1, [x, y]) == y assert bool_monomial([1, 1], [x, y]) == And(x, y) def test_check_pair(): assert _check_pair([0, 1, 0], [0, 1, 1]) == 2 assert _check_pair([0, 1, 0], [1, 1, 1]) == -1 def test_issue_19114(): expr = (B & C) | (A & ~C) | (~A & ~B) result = to_dnf(expr, simplify=True) assert result == expr def test_issue_20870(): result = SOPform([a, b, c, d], [1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 14, 15]) expected = ((d & ~b) | (a & b & c) | (a & ~c & ~d) | (b & ~a & ~c) | (c & ~a & ~d)) assert result == expected def test_convert_to_varsSOP(): assert _convert_to_varsSOP([0, 1, 0], [x, y, z]) == And(Not(x), y, Not(z)) assert _convert_to_varsSOP([3, 1, 0], [x, y, z]) == And(y, Not(z)) def test_convert_to_varsPOS(): assert _convert_to_varsPOS([0, 1, 0], [x, y, z]) == Or(x, Not(y), z) assert _convert_to_varsPOS([3, 1, 0], [x, y, z]) == Or(Not(y), z) def test_refine(): # relational assert not refine(x < 0, ~(x < 0)) assert refine(x < 0, (x < 0)) assert refine(x < 0, (0 > x)) is S.true assert refine(x < 0, (y < 0)) == (x < 0) assert not refine(x <= 0, ~(x <= 0)) assert refine(x <= 0, (x <= 0)) assert refine(x <= 0, (0 >= x)) is S.true assert refine(x <= 0, (y <= 0)) == (x <= 0) assert not refine(x > 0, ~(x > 0)) assert refine(x > 0, (x > 0)) assert refine(x > 0, (0 < x)) is S.true assert refine(x > 0, (y > 0)) == (x > 0) assert not refine(x >= 0, ~(x >= 0)) assert refine(x >= 0, (x >= 0)) assert refine(x >= 0, (0 <= x)) is S.true assert refine(x >= 0, (y >= 0)) == (x >= 0) assert not refine(Eq(x, 0), ~(Eq(x, 0))) assert refine(Eq(x, 0), (Eq(x, 0))) assert refine(Eq(x, 0), (Eq(0, x))) is S.true assert refine(Eq(x, 0), (Eq(y, 0))) == Eq(x, 0) assert not refine(Ne(x, 0), ~(Ne(x, 0))) assert refine(Ne(x, 0), (Ne(0, x))) is S.true assert refine(Ne(x, 0), (Ne(x, 0))) assert refine(Ne(x, 0), (Ne(y, 0))) == (Ne(x, 0)) # boolean functions assert refine(And(x > 0, y > 0), (x > 0)) == (y > 0) assert refine(And(x > 0, y > 0), (x > 0) & (y > 0)) is S.true # predicates assert refine(Q.positive(x), Q.positive(x)) is S.true assert refine(Q.positive(x), Q.negative(x)) is S.false assert refine(Q.positive(x), Q.real(x)) == Q.positive(x) sympy-sympy-1.9/sympy/logic/tests/test_dimacs.py000066400000000000000000000074561412543434000222300ustar00rootroot00000000000000"""Various tests on satisfiability using dimacs cnf file syntax You can find lots of cnf files in ftp://dimacs.rutgers.edu/pub/challenge/satisfiability/benchmarks/cnf/ """ from sympy.logic.utilities.dimacs import load from sympy.logic.algorithms.dpll import dpll_satisfiable def test_f1(): assert bool(dpll_satisfiable(load(f1))) def test_f2(): assert bool(dpll_satisfiable(load(f2))) def test_f3(): assert bool(dpll_satisfiable(load(f3))) def test_f4(): assert not bool(dpll_satisfiable(load(f4))) def test_f5(): assert bool(dpll_satisfiable(load(f5))) f1 = """c simple example c Resolution: SATISFIABLE c p cnf 3 2 1 -3 0 2 3 -1 0 """ f2 = """c an example from Quinn's text, 16 variables and 18 clauses. c Resolution: SATISFIABLE c p cnf 16 18 1 2 0 -2 -4 0 3 4 0 -4 -5 0 5 -6 0 6 -7 0 6 7 0 7 -16 0 8 -9 0 -8 -14 0 9 10 0 9 -10 0 -10 -11 0 10 12 0 11 12 0 13 14 0 14 -15 0 15 16 0 """ f3 = """c p cnf 6 9 -1 0 -3 0 2 -1 0 2 -4 0 5 -4 0 -1 -3 0 -4 -6 0 1 3 -2 0 4 6 -2 -5 0 """ f4 = """c c file: hole6.cnf [http://people.sc.fsu.edu/~jburkardt/data/cnf/hole6.cnf] c c SOURCE: John Hooker (jh38+@andrew.cmu.edu) c c DESCRIPTION: Pigeon hole problem of placing n (for file 'holen.cnf') pigeons c in n+1 holes without placing 2 pigeons in the same hole c c NOTE: Part of the collection at the Forschungsinstitut fuer c anwendungsorientierte Wissensverarbeitung in Ulm Germany. c c NOTE: Not satisfiable c p cnf 42 133 -1 -7 0 -1 -13 0 -1 -19 0 -1 -25 0 -1 -31 0 -1 -37 0 -7 -13 0 -7 -19 0 -7 -25 0 -7 -31 0 -7 -37 0 -13 -19 0 -13 -25 0 -13 -31 0 -13 -37 0 -19 -25 0 -19 -31 0 -19 -37 0 -25 -31 0 -25 -37 0 -31 -37 0 -2 -8 0 -2 -14 0 -2 -20 0 -2 -26 0 -2 -32 0 -2 -38 0 -8 -14 0 -8 -20 0 -8 -26 0 -8 -32 0 -8 -38 0 -14 -20 0 -14 -26 0 -14 -32 0 -14 -38 0 -20 -26 0 -20 -32 0 -20 -38 0 -26 -32 0 -26 -38 0 -32 -38 0 -3 -9 0 -3 -15 0 -3 -21 0 -3 -27 0 -3 -33 0 -3 -39 0 -9 -15 0 -9 -21 0 -9 -27 0 -9 -33 0 -9 -39 0 -15 -21 0 -15 -27 0 -15 -33 0 -15 -39 0 -21 -27 0 -21 -33 0 -21 -39 0 -27 -33 0 -27 -39 0 -33 -39 0 -4 -10 0 -4 -16 0 -4 -22 0 -4 -28 0 -4 -34 0 -4 -40 0 -10 -16 0 -10 -22 0 -10 -28 0 -10 -34 0 -10 -40 0 -16 -22 0 -16 -28 0 -16 -34 0 -16 -40 0 -22 -28 0 -22 -34 0 -22 -40 0 -28 -34 0 -28 -40 0 -34 -40 0 -5 -11 0 -5 -17 0 -5 -23 0 -5 -29 0 -5 -35 0 -5 -41 0 -11 -17 0 -11 -23 0 -11 -29 0 -11 -35 0 -11 -41 0 -17 -23 0 -17 -29 0 -17 -35 0 -17 -41 0 -23 -29 0 -23 -35 0 -23 -41 0 -29 -35 0 -29 -41 0 -35 -41 0 -6 -12 0 -6 -18 0 -6 -24 0 -6 -30 0 -6 -36 0 -6 -42 0 -12 -18 0 -12 -24 0 -12 -30 0 -12 -36 0 -12 -42 0 -18 -24 0 -18 -30 0 -18 -36 0 -18 -42 0 -24 -30 0 -24 -36 0 -24 -42 0 -30 -36 0 -30 -42 0 -36 -42 0 6 5 4 3 2 1 0 12 11 10 9 8 7 0 18 17 16 15 14 13 0 24 23 22 21 20 19 0 30 29 28 27 26 25 0 36 35 34 33 32 31 0 42 41 40 39 38 37 0 """ f5 = """c simple example requiring variable selection c c NOTE: Satisfiable c p cnf 5 5 1 2 3 0 1 -2 3 0 4 5 -3 0 1 -4 -3 0 -1 -5 0 """ sympy-sympy-1.9/sympy/logic/tests/test_inference.py000066400000000000000000000315611412543434000227200ustar00rootroot00000000000000"""For more tests on satisfiability, see test_dimacs""" from sympy import symbols, Q from sympy.logic.boolalg import And, Implies, Equivalent, true, false from sympy.logic.inference import literal_symbol, \ pl_true, satisfiable, valid, entails, PropKB from sympy.logic.algorithms.dpll import dpll, dpll_satisfiable, \ find_pure_symbol, find_unit_clause, unit_propagate, \ find_pure_symbol_int_repr, find_unit_clause_int_repr, \ unit_propagate_int_repr from sympy.logic.algorithms.dpll2 import dpll_satisfiable as dpll2_satisfiable from sympy.testing.pytest import raises def test_literal(): A, B = symbols('A,B') assert literal_symbol(True) is True assert literal_symbol(False) is False assert literal_symbol(A) is A assert literal_symbol(~A) is A def test_find_pure_symbol(): A, B, C = symbols('A,B,C') assert find_pure_symbol([A], [A]) == (A, True) assert find_pure_symbol([A, B], [~A | B, ~B | A]) == (None, None) assert find_pure_symbol([A, B, C], [ A | ~B, ~B | ~C, C | A]) == (A, True) assert find_pure_symbol([A, B, C], [~A | B, B | ~C, C | A]) == (B, True) assert find_pure_symbol([A, B, C], [~A | ~B, ~B | ~C, C | A]) == (B, False) assert find_pure_symbol( [A, B, C], [~A | B, ~B | ~C, C | A]) == (None, None) def test_find_pure_symbol_int_repr(): assert find_pure_symbol_int_repr([1], [{1}]) == (1, True) assert find_pure_symbol_int_repr([1, 2], [{-1, 2}, {-2, 1}]) == (None, None) assert find_pure_symbol_int_repr([1, 2, 3], [{1, -2}, {-2, -3}, {3, 1}]) == (1, True) assert find_pure_symbol_int_repr([1, 2, 3], [{-1, 2}, {2, -3}, {3, 1}]) == (2, True) assert find_pure_symbol_int_repr([1, 2, 3], [{-1, -2}, {-2, -3}, {3, 1}]) == (2, False) assert find_pure_symbol_int_repr([1, 2, 3], [{-1, 2}, {-2, -3}, {3, 1}]) == (None, None) def test_unit_clause(): A, B, C = symbols('A,B,C') assert find_unit_clause([A], {}) == (A, True) assert find_unit_clause([A, ~A], {}) == (A, True) # Wrong ?? assert find_unit_clause([A | B], {A: True}) == (B, True) assert find_unit_clause([A | B], {B: True}) == (A, True) assert find_unit_clause( [A | B | C, B | ~C, A | ~B], {A: True}) == (B, False) assert find_unit_clause([A | B | C, B | ~C, A | B], {A: True}) == (B, True) assert find_unit_clause([A | B | C, B | ~C, A ], {}) == (A, True) def test_unit_clause_int_repr(): assert find_unit_clause_int_repr(map(set, [[1]]), {}) == (1, True) assert find_unit_clause_int_repr(map(set, [[1], [-1]]), {}) == (1, True) assert find_unit_clause_int_repr([{1, 2}], {1: True}) == (2, True) assert find_unit_clause_int_repr([{1, 2}], {2: True}) == (1, True) assert find_unit_clause_int_repr(map(set, [[1, 2, 3], [2, -3], [1, -2]]), {1: True}) == (2, False) assert find_unit_clause_int_repr(map(set, [[1, 2, 3], [3, -3], [1, 2]]), {1: True}) == (2, True) A, B, C = symbols('A,B,C') assert find_unit_clause([A | B | C, B | ~C, A ], {}) == (A, True) def test_unit_propagate(): A, B, C = symbols('A,B,C') assert unit_propagate([A | B], A) == [] assert unit_propagate([A | B, ~A | C, ~C | B, A], A) == [C, ~C | B, A] def test_unit_propagate_int_repr(): assert unit_propagate_int_repr([{1, 2}], 1) == [] assert unit_propagate_int_repr(map(set, [[1, 2], [-1, 3], [-3, 2], [1]]), 1) == [{3}, {-3, 2}] def test_dpll(): """This is also tested in test_dimacs""" A, B, C = symbols('A,B,C') assert dpll([A | B], [A, B], {A: True, B: True}) == {A: True, B: True} def test_dpll_satisfiable(): A, B, C = symbols('A,B,C') assert dpll_satisfiable( A & ~A ) is False assert dpll_satisfiable( A & ~B ) == {A: True, B: False} assert dpll_satisfiable( A | B ) in ({A: True}, {B: True}, {A: True, B: True}) assert dpll_satisfiable( (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False}) assert dpll_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False}, {A: True, C: True}, {B: True, C: True}) assert dpll_satisfiable( A & B & C ) == {A: True, B: True, C: True} assert dpll_satisfiable( (A | B) & (A >> B) ) == {B: True} assert dpll_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True} assert dpll_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False} def test_dpll2_satisfiable(): A, B, C = symbols('A,B,C') assert dpll2_satisfiable( A & ~A ) is False assert dpll2_satisfiable( A & ~B ) == {A: True, B: False} assert dpll2_satisfiable( A | B ) in ({A: True}, {B: True}, {A: True, B: True}) assert dpll2_satisfiable( (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False}) assert dpll2_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False, C: True}, {A: True, B: True, C: True}) assert dpll2_satisfiable( A & B & C ) == {A: True, B: True, C: True} assert dpll2_satisfiable( (A | B) & (A >> B) ) in ({B: True, A: False}, {B: True, A: True}) assert dpll2_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True} assert dpll2_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False} def test_minisat22_satisfiable(): A, B, C = symbols('A,B,C') minisat22_satisfiable = lambda expr: satisfiable(expr, algorithm="minisat22") assert minisat22_satisfiable( A & ~A ) is False assert minisat22_satisfiable( A & ~B ) == {A: True, B: False} assert minisat22_satisfiable( A | B ) in ({A: True}, {B: False}, {A: False, B: True}, {A: True, B: True}, {A: True, B: False}) assert minisat22_satisfiable( (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False}) assert minisat22_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False, C: True}, {A: True, B: True, C: True}, {A: False, B: True, C: True}, {A: True, B: False, C: False}) assert minisat22_satisfiable( A & B & C ) == {A: True, B: True, C: True} assert minisat22_satisfiable( (A | B) & (A >> B) ) in ({B: True, A: False}, {B: True, A: True}) assert minisat22_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True} assert minisat22_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False} def test_minisat22_minimal_satisfiable(): A, B, C = symbols('A,B,C') minisat22_satisfiable = lambda expr, minimal=True: satisfiable(expr, algorithm="minisat22", minimal=True) assert minisat22_satisfiable( A & ~A ) is False assert minisat22_satisfiable( A & ~B ) == {A: True, B: False} assert minisat22_satisfiable( A | B ) in ({A: True}, {B: False}, {A: False, B: True}, {A: True, B: True}, {A: True, B: False}) assert minisat22_satisfiable( (~A | B) & (~B | A) ) in ({A: True, B: True}, {A: False, B: False}) assert minisat22_satisfiable( (A | B) & (~B | C) ) in ({A: True, B: False, C: True}, {A: True, B: True, C: True}, {A: False, B: True, C: True}, {A: True, B: False, C: False}) assert minisat22_satisfiable( A & B & C ) == {A: True, B: True, C: True} assert minisat22_satisfiable( (A | B) & (A >> B) ) in ({B: True, A: False}, {B: True, A: True}) assert minisat22_satisfiable( Equivalent(A, B) & A ) == {A: True, B: True} assert minisat22_satisfiable( Equivalent(A, B) & ~A ) == {A: False, B: False} g = satisfiable((A | B | C),algorithm="minisat22",minimal=True,all_models=True) sol = next(g) first_solution = {key for key, value in sol.items() if value} sol=next(g) second_solution = {key for key, value in sol.items() if value} sol=next(g) third_solution = {key for key, value in sol.items() if value} assert not first_solution <= second_solution assert not second_solution <= third_solution assert not first_solution <= third_solution def test_satisfiable(): A, B, C = symbols('A,B,C') assert satisfiable(A & (A >> B) & ~B) is False def test_valid(): A, B, C = symbols('A,B,C') assert valid(A >> (B >> A)) is True assert valid((A >> (B >> C)) >> ((A >> B) >> (A >> C))) is True assert valid((~B >> ~A) >> (A >> B)) is True assert valid(A | B | C) is False assert valid(A >> B) is False def test_pl_true(): A, B, C = symbols('A,B,C') assert pl_true(True) is True assert pl_true( A & B, {A: True, B: True}) is True assert pl_true( A | B, {A: True}) is True assert pl_true( A | B, {B: True}) is True assert pl_true( A | B, {A: None, B: True}) is True assert pl_true( A >> B, {A: False}) is True assert pl_true( A | B | ~C, {A: False, B: True, C: True}) is True assert pl_true(Equivalent(A, B), {A: False, B: False}) is True # test for false assert pl_true(False) is False assert pl_true( A & B, {A: False, B: False}) is False assert pl_true( A & B, {A: False}) is False assert pl_true( A & B, {B: False}) is False assert pl_true( A | B, {A: False, B: False}) is False #test for None assert pl_true(B, {B: None}) is None assert pl_true( A & B, {A: True, B: None}) is None assert pl_true( A >> B, {A: True, B: None}) is None assert pl_true(Equivalent(A, B), {A: None}) is None assert pl_true(Equivalent(A, B), {A: True, B: None}) is None # Test for deep assert pl_true(A | B, {A: False}, deep=True) is None assert pl_true(~A & ~B, {A: False}, deep=True) is None assert pl_true(A | B, {A: False, B: False}, deep=True) is False assert pl_true(A & B & (~A | ~B), {A: True}, deep=True) is False assert pl_true((C >> A) >> (B >> A), {C: True}, deep=True) is True def test_pl_true_wrong_input(): from sympy import pi raises(ValueError, lambda: pl_true('John Cleese')) raises(ValueError, lambda: pl_true(42 + pi + pi ** 2)) raises(ValueError, lambda: pl_true(42)) def test_entails(): A, B, C = symbols('A, B, C') assert entails(A, [A >> B, ~B]) is False assert entails(B, [Equivalent(A, B), A]) is True assert entails((A >> B) >> (~A >> ~B)) is False assert entails((A >> B) >> (~B >> ~A)) is True def test_PropKB(): A, B, C = symbols('A,B,C') kb = PropKB() assert kb.ask(A >> B) is False assert kb.ask(A >> (B >> A)) is True kb.tell(A >> B) kb.tell(B >> C) assert kb.ask(A) is False assert kb.ask(B) is False assert kb.ask(C) is False assert kb.ask(~A) is False assert kb.ask(~B) is False assert kb.ask(~C) is False assert kb.ask(A >> C) is True kb.tell(A) assert kb.ask(A) is True assert kb.ask(B) is True assert kb.ask(C) is True assert kb.ask(~C) is False kb.retract(A) assert kb.ask(C) is False def test_propKB_tolerant(): """"tolerant to bad input""" kb = PropKB() A, B, C = symbols('A,B,C') assert kb.ask(B) is False def test_satisfiable_non_symbols(): x, y = symbols('x y') assumptions = Q.zero(x*y) facts = Implies(Q.zero(x*y), Q.zero(x) | Q.zero(y)) query = ~Q.zero(x) & ~Q.zero(y) refutations = [ {Q.zero(x): True, Q.zero(x*y): True}, {Q.zero(y): True, Q.zero(x*y): True}, {Q.zero(x): True, Q.zero(y): True, Q.zero(x*y): True}, {Q.zero(x): True, Q.zero(y): False, Q.zero(x*y): True}, {Q.zero(x): False, Q.zero(y): True, Q.zero(x*y): True}] assert not satisfiable(And(assumptions, facts, query), algorithm='dpll') assert satisfiable(And(assumptions, facts, ~query), algorithm='dpll') in refutations assert not satisfiable(And(assumptions, facts, query), algorithm='dpll2') assert satisfiable(And(assumptions, facts, ~query), algorithm='dpll2') in refutations def test_satisfiable_bool(): from sympy.core.singleton import S assert satisfiable(true) == {true: true} assert satisfiable(S.true) == {true: true} assert satisfiable(false) is False assert satisfiable(S.false) is False def test_satisfiable_all_models(): from sympy.abc import A, B assert next(satisfiable(False, all_models=True)) is False assert list(satisfiable((A >> ~A) & A , all_models=True)) == [False] assert list(satisfiable(True, all_models=True)) == [{true: true}] models = [{A: True, B: False}, {A: False, B: True}] result = satisfiable(A ^ B, all_models=True) models.remove(next(result)) models.remove(next(result)) raises(StopIteration, lambda: next(result)) assert not models assert list(satisfiable(Equivalent(A, B), all_models=True)) == \ [{A: False, B: False}, {A: True, B: True}] models = [{A: False, B: False}, {A: False, B: True}, {A: True, B: True}] for model in satisfiable(A >> B, all_models=True): models.remove(model) assert not models # This is a santiy test to check that only the required number # of solutions are generated. The expr below has 2**100 - 1 models # which would time out the test if all are generated at once. from sympy import numbered_symbols from sympy.logic.boolalg import Or sym = numbered_symbols() X = [next(sym) for i in range(100)] result = satisfiable(Or(*X), all_models=True) for i in range(10): assert next(result) sympy-sympy-1.9/sympy/logic/utilities/000077500000000000000000000000001412543434000202145ustar00rootroot00000000000000sympy-sympy-1.9/sympy/logic/utilities/__init__.py000066400000000000000000000000671412543434000223300ustar00rootroot00000000000000from .dimacs import load_file __all__ = ['load_file'] sympy-sympy-1.9/sympy/logic/utilities/dimacs.py000066400000000000000000000031771412543434000220360ustar00rootroot00000000000000"""For reading in DIMACS file format www.cs.ubc.ca/~hoos/SATLIB/Benchmarks/SAT/satformat.ps """ from sympy.core import Symbol from sympy.logic.boolalg import And, Or import re def load(s): """Loads a boolean expression from a string. Examples ======== >>> from sympy.logic.utilities.dimacs import load >>> load('1') cnf_1 >>> load('1 2') cnf_1 | cnf_2 >>> load('1 \\n 2') cnf_1 & cnf_2 >>> load('1 2 \\n 3') cnf_3 & (cnf_1 | cnf_2) """ clauses = [] lines = s.split('\n') pComment = re.compile(r'c.*') pStats = re.compile(r'p\s*cnf\s*(\d*)\s*(\d*)') while len(lines) > 0: line = lines.pop(0) # Only deal with lines that aren't comments if not pComment.match(line): m = pStats.match(line) if not m: nums = line.rstrip('\n').split(' ') list = [] for lit in nums: if lit != '': if int(lit) == 0: continue num = abs(int(lit)) sign = True if int(lit) < 0: sign = False if sign: list.append(Symbol("cnf_%s" % num)) else: list.append(~Symbol("cnf_%s" % num)) if len(list) > 0: clauses.append(Or(*list)) return And(*clauses) def load_file(location): """Loads a boolean expression from a file.""" with open(location) as f: s = f.read() return load(s) sympy-sympy-1.9/sympy/matrices/000077500000000000000000000000001412543434000167135ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/__init__.py000066400000000000000000000046431412543434000210330ustar00rootroot00000000000000"""A module that handles matrices. Includes functions for fast creating matrices like zero, one/eye, random matrix, etc. """ from .common import ShapeError, NonSquareMatrixError, MatrixKind from .dense import ( GramSchmidt, casoratian, diag, eye, hessian, jordan_cell, list2numpy, matrix2numpy, matrix_multiply_elementwise, ones, randMatrix, rot_axis1, rot_axis2, rot_axis3, symarray, wronskian, zeros) from .dense import MutableDenseMatrix from .matrices import DeferredVector, MatrixBase Matrix = MutableMatrix = MutableDenseMatrix from .sparse import MutableSparseMatrix from .sparsetools import banded from .immutable import ImmutableDenseMatrix, ImmutableSparseMatrix ImmutableMatrix = ImmutableDenseMatrix SparseMatrix = MutableSparseMatrix from .expressions import ( MatrixSlice, BlockDiagMatrix, BlockMatrix, FunctionMatrix, Identity, Inverse, MatAdd, MatMul, MatPow, MatrixExpr, MatrixSymbol, Trace, Transpose, ZeroMatrix, OneMatrix, blockcut, block_collapse, matrix_symbols, Adjoint, hadamard_product, HadamardProduct, HadamardPower, Determinant, det, diagonalize_vector, DiagMatrix, DiagonalMatrix, DiagonalOf, trace, DotProduct, kronecker_product, KroneckerProduct, PermutationMatrix, MatrixPermute, MatrixSet, Permanent, per) from .utilities import dotprodsimp __all__ = [ 'ShapeError', 'NonSquareMatrixError', 'MatrixKind', 'GramSchmidt', 'casoratian', 'diag', 'eye', 'hessian', 'jordan_cell', 'list2numpy', 'matrix2numpy', 'matrix_multiply_elementwise', 'ones', 'randMatrix', 'rot_axis1', 'rot_axis2', 'rot_axis3', 'symarray', 'wronskian', 'zeros', 'MutableDenseMatrix', 'DeferredVector', 'MatrixBase', 'Matrix', 'MutableMatrix', 'MutableSparseMatrix', 'banded', 'ImmutableDenseMatrix', 'ImmutableSparseMatrix', 'ImmutableMatrix', 'SparseMatrix', 'MatrixSlice', 'BlockDiagMatrix', 'BlockMatrix', 'FunctionMatrix', 'Identity', 'Inverse', 'MatAdd', 'MatMul', 'MatPow', 'MatrixExpr', 'MatrixSymbol', 'Trace', 'Transpose', 'ZeroMatrix', 'OneMatrix', 'blockcut', 'block_collapse', 'matrix_symbols', 'Adjoint', 'hadamard_product', 'HadamardProduct', 'HadamardPower', 'Determinant', 'det', 'diagonalize_vector', 'DiagMatrix', 'DiagonalMatrix', 'DiagonalOf', 'trace', 'DotProduct', 'kronecker_product', 'KroneckerProduct', 'PermutationMatrix', 'MatrixPermute', 'MatrixSet', 'Permanent', 'per', 'dotprodsimp', ] sympy-sympy-1.9/sympy/matrices/benchmarks/000077500000000000000000000000001412543434000210305ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/benchmarks/__init__.py000066400000000000000000000000001412543434000231270ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/benchmarks/bench_matrix.py000066400000000000000000000004031412543434000240420ustar00rootroot00000000000000from sympy import eye, zeros, Integer i3 = Integer(3) M = eye(100) def timeit_Matrix__getitem_ii(): M[3, 3] def timeit_Matrix__getitem_II(): M[i3, i3] def timeit_Matrix__getslice(): M[:, :] def timeit_Matrix_zeronm(): zeros(100, 100) sympy-sympy-1.9/sympy/matrices/common.py000066400000000000000000002736041412543434000205710ustar00rootroot00000000000000""" Basic methods common to all matrices to be used when creating more advanced matrices (e.g., matrices over rings, etc.). """ from collections import defaultdict from collections.abc import Iterable from inspect import isfunction from functools import reduce from sympy.core.logic import FuzzyBool from sympy.assumptions.refine import refine from sympy.core import SympifyError, Add from sympy.core.basic import Atom from sympy.core.compatibility import as_int, is_sequence from sympy.core.decorators import call_highest_priority from sympy.core.kind import Kind, NumberKind from sympy.core.logic import fuzzy_and from sympy.core.singleton import S from sympy.core.symbol import Symbol from sympy.core.sympify import sympify from sympy.functions import Abs from sympy.polys.polytools import Poly from sympy.simplify import simplify as _simplify from sympy.simplify.simplify import dotprodsimp as _dotprodsimp from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.iterables import flatten from sympy.utilities.misc import filldedent from sympy.tensor.array import NDimArray from .utilities import _get_intermediate_simp_bool class MatrixError(Exception): pass class ShapeError(ValueError, MatrixError): """Wrong matrix shape""" pass class NonSquareMatrixError(ShapeError): pass class NonInvertibleMatrixError(ValueError, MatrixError): """The matrix in not invertible (division by multidimensional zero error).""" pass class NonPositiveDefiniteMatrixError(ValueError, MatrixError): """The matrix is not a positive-definite matrix.""" pass class MatrixRequired: """All subclasses of matrix objects must implement the required matrix properties listed here.""" rows = None # type: int cols = None # type: int _simplify = None @classmethod def _new(cls, *args, **kwargs): """`_new` must, at minimum, be callable as `_new(rows, cols, mat) where mat is a flat list of the elements of the matrix.""" raise NotImplementedError("Subclasses must implement this.") def __eq__(self, other): raise NotImplementedError("Subclasses must implement this.") def __getitem__(self, key): """Implementations of __getitem__ should accept ints, in which case the matrix is indexed as a flat list, tuples (i,j) in which case the (i,j) entry is returned, slices, or mixed tuples (a,b) where a and b are any combintion of slices and integers.""" raise NotImplementedError("Subclasses must implement this.") def __len__(self): """The total number of entries in the matrix.""" raise NotImplementedError("Subclasses must implement this.") @property def shape(self): raise NotImplementedError("Subclasses must implement this.") class MatrixShaping(MatrixRequired): """Provides basic matrix shaping and extracting of submatrices""" def _eval_col_del(self, col): def entry(i, j): return self[i, j] if j < col else self[i, j + 1] return self._new(self.rows, self.cols - 1, entry) def _eval_col_insert(self, pos, other): def entry(i, j): if j < pos: return self[i, j] elif pos <= j < pos + other.cols: return other[i, j - pos] return self[i, j - other.cols] return self._new(self.rows, self.cols + other.cols, lambda i, j: entry(i, j)) def _eval_col_join(self, other): rows = self.rows def entry(i, j): if i < rows: return self[i, j] return other[i - rows, j] return classof(self, other)._new(self.rows + other.rows, self.cols, lambda i, j: entry(i, j)) def _eval_extract(self, rowsList, colsList): mat = list(self) cols = self.cols indices = (i * cols + j for i in rowsList for j in colsList) return self._new(len(rowsList), len(colsList), list(mat[i] for i in indices)) def _eval_get_diag_blocks(self): sub_blocks = [] def recurse_sub_blocks(M): i = 1 while i <= M.shape[0]: if i == 1: to_the_right = M[0, i:] to_the_bottom = M[i:, 0] else: to_the_right = M[:i, i:] to_the_bottom = M[i:, :i] if any(to_the_right) or any(to_the_bottom): i += 1 continue else: sub_blocks.append(M[:i, :i]) if M.shape == M[:i, :i].shape: return else: recurse_sub_blocks(M[i:, i:]) return recurse_sub_blocks(self) return sub_blocks def _eval_row_del(self, row): def entry(i, j): return self[i, j] if i < row else self[i + 1, j] return self._new(self.rows - 1, self.cols, entry) def _eval_row_insert(self, pos, other): entries = list(self) insert_pos = pos * self.cols entries[insert_pos:insert_pos] = list(other) return self._new(self.rows + other.rows, self.cols, entries) def _eval_row_join(self, other): cols = self.cols def entry(i, j): if j < cols: return self[i, j] return other[i, j - cols] return classof(self, other)._new(self.rows, self.cols + other.cols, lambda i, j: entry(i, j)) def _eval_tolist(self): return [list(self[i,:]) for i in range(self.rows)] def _eval_todok(self): dok = {} rows, cols = self.shape for i in range(rows): for j in range(cols): val = self[i, j] if val != self.zero: dok[i, j] = val return dok def _eval_vec(self): rows = self.rows def entry(n, _): # we want to read off the columns first j = n // rows i = n - j * rows return self[i, j] return self._new(len(self), 1, entry) def _eval_vech(self, diagonal): c = self.cols v = [] if diagonal: for j in range(c): for i in range(j, c): v.append(self[i, j]) else: for j in range(c): for i in range(j + 1, c): v.append(self[i, j]) return self._new(len(v), 1, v) def col_del(self, col): """Delete the specified column.""" if col < 0: col += self.cols if not 0 <= col < self.cols: raise IndexError("Column {} is out of range.".format(col)) return self._eval_col_del(col) def col_insert(self, pos, other): """Insert one or more columns at the given column position. Examples ======== >>> from sympy import zeros, ones >>> M = zeros(3) >>> V = ones(3, 1) >>> M.col_insert(1, V) Matrix([ [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]) See Also ======== col row_insert """ # Allows you to build a matrix even if it is null matrix if not self: return type(self)(other) pos = as_int(pos) if pos < 0: pos = self.cols + pos if pos < 0: pos = 0 elif pos > self.cols: pos = self.cols if self.rows != other.rows: raise ShapeError( "`self` and `other` must have the same number of rows.") return self._eval_col_insert(pos, other) def col_join(self, other): """Concatenates two matrices along self's last and other's first row. Examples ======== >>> from sympy import zeros, ones >>> M = zeros(3) >>> V = ones(1, 3) >>> M.col_join(V) Matrix([ [0, 0, 0], [0, 0, 0], [0, 0, 0], [1, 1, 1]]) See Also ======== col row_join """ # A null matrix can always be stacked (see #10770) if self.rows == 0 and self.cols != other.cols: return self._new(0, other.cols, []).col_join(other) if self.cols != other.cols: raise ShapeError( "`self` and `other` must have the same number of columns.") return self._eval_col_join(other) def col(self, j): """Elementary column selector. Examples ======== >>> from sympy import eye >>> eye(2).col(0) Matrix([ [1], [0]]) See Also ======== row col_del col_join col_insert """ return self[:, j] def extract(self, rowsList, colsList): """Return a submatrix by specifying a list of rows and columns. Negative indices can be given. All indices must be in the range -n <= i < n where n is the number of rows or columns. Examples ======== >>> from sympy import Matrix >>> m = Matrix(4, 3, range(12)) >>> m Matrix([ [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]) >>> m.extract([0, 1, 3], [0, 1]) Matrix([ [0, 1], [3, 4], [9, 10]]) Rows or columns can be repeated: >>> m.extract([0, 0, 1], [-1]) Matrix([ [2], [2], [5]]) Every other row can be taken by using range to provide the indices: >>> m.extract(range(0, m.rows, 2), [-1]) Matrix([ [2], [8]]) RowsList or colsList can also be a list of booleans, in which case the rows or columns corresponding to the True values will be selected: >>> m.extract([0, 1, 2, 3], [True, False, True]) Matrix([ [0, 2], [3, 5], [6, 8], [9, 11]]) """ if not is_sequence(rowsList) or not is_sequence(colsList): raise TypeError("rowsList and colsList must be iterable") # ensure rowsList and colsList are lists of integers if rowsList and all(isinstance(i, bool) for i in rowsList): rowsList = [index for index, item in enumerate(rowsList) if item] if colsList and all(isinstance(i, bool) for i in colsList): colsList = [index for index, item in enumerate(colsList) if item] # ensure everything is in range rowsList = [a2idx(k, self.rows) for k in rowsList] colsList = [a2idx(k, self.cols) for k in colsList] return self._eval_extract(rowsList, colsList) def get_diag_blocks(self): """Obtains the square sub-matrices on the main diagonal of a square matrix. Useful for inverting symbolic matrices or solving systems of linear equations which may be decoupled by having a block diagonal structure. Examples ======== >>> from sympy import Matrix >>> from sympy.abc import x, y, z >>> A = Matrix([[1, 3, 0, 0], [y, z*z, 0, 0], [0, 0, x, 0], [0, 0, 0, 0]]) >>> a1, a2, a3 = A.get_diag_blocks() >>> a1 Matrix([ [1, 3], [y, z**2]]) >>> a2 Matrix([[x]]) >>> a3 Matrix([[0]]) """ return self._eval_get_diag_blocks() @classmethod def hstack(cls, *args): """Return a matrix formed by joining args horizontally (i.e. by repeated application of row_join). Examples ======== >>> from sympy.matrices import Matrix, eye >>> Matrix.hstack(eye(2), 2*eye(2)) Matrix([ [1, 0, 2, 0], [0, 1, 0, 2]]) """ if len(args) == 0: return cls._new() kls = type(args[0]) return reduce(kls.row_join, args) def reshape(self, rows, cols): """Reshape the matrix. Total number of elements must remain the same. Examples ======== >>> from sympy import Matrix >>> m = Matrix(2, 3, lambda i, j: 1) >>> m Matrix([ [1, 1, 1], [1, 1, 1]]) >>> m.reshape(1, 6) Matrix([[1, 1, 1, 1, 1, 1]]) >>> m.reshape(3, 2) Matrix([ [1, 1], [1, 1], [1, 1]]) """ if self.rows * self.cols != rows * cols: raise ValueError("Invalid reshape parameters %d %d" % (rows, cols)) return self._new(rows, cols, lambda i, j: self[i * cols + j]) def row_del(self, row): """Delete the specified row.""" if row < 0: row += self.rows if not 0 <= row < self.rows: raise IndexError("Row {} is out of range.".format(row)) return self._eval_row_del(row) def row_insert(self, pos, other): """Insert one or more rows at the given row position. Examples ======== >>> from sympy import zeros, ones >>> M = zeros(3) >>> V = ones(1, 3) >>> M.row_insert(1, V) Matrix([ [0, 0, 0], [1, 1, 1], [0, 0, 0], [0, 0, 0]]) See Also ======== row col_insert """ # Allows you to build a matrix even if it is null matrix if not self: return self._new(other) pos = as_int(pos) if pos < 0: pos = self.rows + pos if pos < 0: pos = 0 elif pos > self.rows: pos = self.rows if self.cols != other.cols: raise ShapeError( "`self` and `other` must have the same number of columns.") return self._eval_row_insert(pos, other) def row_join(self, other): """Concatenates two matrices along self's last and rhs's first column Examples ======== >>> from sympy import zeros, ones >>> M = zeros(3) >>> V = ones(3, 1) >>> M.row_join(V) Matrix([ [0, 0, 0, 1], [0, 0, 0, 1], [0, 0, 0, 1]]) See Also ======== row col_join """ # A null matrix can always be stacked (see #10770) if self.cols == 0 and self.rows != other.rows: return self._new(other.rows, 0, []).row_join(other) if self.rows != other.rows: raise ShapeError( "`self` and `rhs` must have the same number of rows.") return self._eval_row_join(other) def diagonal(self, k=0): """Returns the kth diagonal of self. The main diagonal corresponds to `k=0`; diagonals above and below correspond to `k > 0` and `k < 0`, respectively. The values of `self[i, j]` for which `j - i = k`, are returned in order of increasing `i + j`, starting with `i + j = |k|`. Examples ======== >>> from sympy import Matrix >>> m = Matrix(3, 3, lambda i, j: j - i); m Matrix([ [ 0, 1, 2], [-1, 0, 1], [-2, -1, 0]]) >>> _.diagonal() Matrix([[0, 0, 0]]) >>> m.diagonal(1) Matrix([[1, 1]]) >>> m.diagonal(-2) Matrix([[-2]]) Even though the diagonal is returned as a Matrix, the element retrieval can be done with a single index: >>> Matrix.diag(1, 2, 3).diagonal()[1] # instead of [0, 1] 2 See Also ======== diag - to create a diagonal matrix """ rv = [] k = as_int(k) r = 0 if k > 0 else -k c = 0 if r else k while True: if r == self.rows or c == self.cols: break rv.append(self[r, c]) r += 1 c += 1 if not rv: raise ValueError(filldedent(''' The %s diagonal is out of range [%s, %s]''' % ( k, 1 - self.rows, self.cols - 1))) return self._new(1, len(rv), rv) def row(self, i): """Elementary row selector. Examples ======== >>> from sympy import eye >>> eye(2).row(0) Matrix([[1, 0]]) See Also ======== col row_del row_join row_insert """ return self[i, :] @property def shape(self): """The shape (dimensions) of the matrix as the 2-tuple (rows, cols). Examples ======== >>> from sympy.matrices import zeros >>> M = zeros(2, 3) >>> M.shape (2, 3) >>> M.rows 2 >>> M.cols 3 """ return (self.rows, self.cols) def todok(self): """Return the matrix as dictionary of keys. Examples ======== >>> from sympy import Matrix >>> M = Matrix.eye(3) >>> M.todok() {(0, 0): 1, (1, 1): 1, (2, 2): 1} """ return self._eval_todok() def tolist(self): """Return the Matrix as a nested Python list. Examples ======== >>> from sympy import Matrix, ones >>> m = Matrix(3, 3, range(9)) >>> m Matrix([ [0, 1, 2], [3, 4, 5], [6, 7, 8]]) >>> m.tolist() [[0, 1, 2], [3, 4, 5], [6, 7, 8]] >>> ones(3, 0).tolist() [[], [], []] When there are no rows then it will not be possible to tell how many columns were in the original matrix: >>> ones(0, 3).tolist() [] """ if not self.rows: return [] if not self.cols: return [[] for i in range(self.rows)] return self._eval_tolist() def todod(M): """Returns matrix as dict of dicts containing non-zero elements of the Matrix Examples ======== >>> from sympy import Matrix >>> A = Matrix([[0, 1],[0, 3]]) >>> A Matrix([ [0, 1], [0, 3]]) >>> A.todod() {0: {1: 1}, 1: {1: 3}} """ rowsdict = {} Mlol = M.tolist() for i, Mi in enumerate(Mlol): row = {j: Mij for j, Mij in enumerate(Mi) if Mij} if row: rowsdict[i] = row return rowsdict def vec(self): """Return the Matrix converted into a one column matrix by stacking columns Examples ======== >>> from sympy import Matrix >>> m=Matrix([[1, 3], [2, 4]]) >>> m Matrix([ [1, 3], [2, 4]]) >>> m.vec() Matrix([ [1], [2], [3], [4]]) See Also ======== vech """ return self._eval_vec() def vech(self, diagonal=True, check_symmetry=True): """Reshapes the matrix into a column vector by stacking the elements in the lower triangle. Parameters ========== diagonal : bool, optional If ``True``, it includes the diagonal elements. check_symmetry : bool, optional If ``True``, it checks whether the matrix is symmetric. Examples ======== >>> from sympy import Matrix >>> m=Matrix([[1, 2], [2, 3]]) >>> m Matrix([ [1, 2], [2, 3]]) >>> m.vech() Matrix([ [1], [2], [3]]) >>> m.vech(diagonal=False) Matrix([[2]]) Notes ===== This should work for symmetric matrices and ``vech`` can represent symmetric matrices in vector form with less size than ``vec``. See Also ======== vec """ if not self.is_square: raise NonSquareMatrixError if check_symmetry and not self.is_symmetric(): raise ValueError("The matrix is not symmetric.") return self._eval_vech(diagonal) @classmethod def vstack(cls, *args): """Return a matrix formed by joining args vertically (i.e. by repeated application of col_join). Examples ======== >>> from sympy.matrices import Matrix, eye >>> Matrix.vstack(eye(2), 2*eye(2)) Matrix([ [1, 0], [0, 1], [2, 0], [0, 2]]) """ if len(args) == 0: return cls._new() kls = type(args[0]) return reduce(kls.col_join, args) class MatrixSpecial(MatrixRequired): """Construction of special matrices""" @classmethod def _eval_diag(cls, rows, cols, diag_dict): """diag_dict is a defaultdict containing all the entries of the diagonal matrix.""" def entry(i, j): return diag_dict[(i, j)] return cls._new(rows, cols, entry) @classmethod def _eval_eye(cls, rows, cols): vals = [cls.zero]*(rows*cols) vals[::cols+1] = [cls.one]*min(rows, cols) return cls._new(rows, cols, vals, copy=False) @classmethod def _eval_jordan_block(cls, rows, cols, eigenvalue, band='upper'): if band == 'lower': def entry(i, j): if i == j: return eigenvalue elif j + 1 == i: return cls.one return cls.zero else: def entry(i, j): if i == j: return eigenvalue elif i + 1 == j: return cls.one return cls.zero return cls._new(rows, cols, entry) @classmethod def _eval_ones(cls, rows, cols): def entry(i, j): return cls.one return cls._new(rows, cols, entry) @classmethod def _eval_zeros(cls, rows, cols): return cls._new(rows, cols, [cls.zero]*(rows*cols), copy=False) @classmethod def _eval_wilkinson(cls, n): def entry(i, j): return cls.one if i + 1 == j else cls.zero D = cls._new(2*n + 1, 2*n + 1, entry) wminus = cls.diag([i for i in range(-n, n + 1)], unpack=True) + D + D.T wplus = abs(cls.diag([i for i in range(-n, n + 1)], unpack=True)) + D + D.T return wminus, wplus @classmethod def diag(kls, *args, strict=False, unpack=True, rows=None, cols=None, **kwargs): """Returns a matrix with the specified diagonal. If matrices are passed, a block-diagonal matrix is created (i.e. the "direct sum" of the matrices). kwargs ====== rows : rows of the resulting matrix; computed if not given. cols : columns of the resulting matrix; computed if not given. cls : class for the resulting matrix unpack : bool which, when True (default), unpacks a single sequence rather than interpreting it as a Matrix. strict : bool which, when False (default), allows Matrices to have variable-length rows. Examples ======== >>> from sympy.matrices import Matrix >>> Matrix.diag(1, 2, 3) Matrix([ [1, 0, 0], [0, 2, 0], [0, 0, 3]]) The current default is to unpack a single sequence. If this is not desired, set `unpack=False` and it will be interpreted as a matrix. >>> Matrix.diag([1, 2, 3]) == Matrix.diag(1, 2, 3) True When more than one element is passed, each is interpreted as something to put on the diagonal. Lists are converted to matrices. Filling of the diagonal always continues from the bottom right hand corner of the previous item: this will create a block-diagonal matrix whether the matrices are square or not. >>> col = [1, 2, 3] >>> row = [[4, 5]] >>> Matrix.diag(col, row) Matrix([ [1, 0, 0], [2, 0, 0], [3, 0, 0], [0, 4, 5]]) When `unpack` is False, elements within a list need not all be of the same length. Setting `strict` to True would raise a ValueError for the following: >>> Matrix.diag([[1, 2, 3], [4, 5], [6]], unpack=False) Matrix([ [1, 2, 3], [4, 5, 0], [6, 0, 0]]) The type of the returned matrix can be set with the ``cls`` keyword. >>> from sympy.matrices import ImmutableMatrix >>> from sympy.utilities.misc import func_name >>> func_name(Matrix.diag(1, cls=ImmutableMatrix)) 'ImmutableDenseMatrix' A zero dimension matrix can be used to position the start of the filling at the start of an arbitrary row or column: >>> from sympy import ones >>> r2 = ones(0, 2) >>> Matrix.diag(r2, 1, 2) Matrix([ [0, 0, 1, 0], [0, 0, 0, 2]]) See Also ======== eye diagonal - to extract a diagonal .dense.diag .expressions.blockmatrix.BlockMatrix .sparsetools.banded - to create multi-diagonal matrices """ from sympy.matrices.matrices import MatrixBase from sympy.matrices.dense import Matrix from sympy.matrices.sparse import SparseMatrix klass = kwargs.get('cls', kls) if unpack and len(args) == 1 and is_sequence(args[0]) and \ not isinstance(args[0], MatrixBase): args = args[0] # fill a default dict with the diagonal entries diag_entries = defaultdict(int) rmax = cmax = 0 # keep track of the biggest index seen for m in args: if isinstance(m, list): if strict: # if malformed, Matrix will raise an error _ = Matrix(m) r, c = _.shape m = _.tolist() else: r, c, smat = SparseMatrix._handle_creation_inputs(m) for (i, j), _ in smat.items(): diag_entries[(i + rmax, j + cmax)] = _ m = [] # to skip process below elif hasattr(m, 'shape'): # a Matrix # convert to list of lists r, c = m.shape m = m.tolist() else: # in this case, we're a single value diag_entries[(rmax, cmax)] = m rmax += 1 cmax += 1 continue # process list of lists for i in range(len(m)): for j, _ in enumerate(m[i]): diag_entries[(i + rmax, j + cmax)] = _ rmax += r cmax += c if rows is None: rows, cols = cols, rows if rows is None: rows, cols = rmax, cmax else: cols = rows if cols is None else cols if rows < rmax or cols < cmax: raise ValueError(filldedent(''' The constructed matrix is {} x {} but a size of {} x {} was specified.'''.format(rmax, cmax, rows, cols))) return klass._eval_diag(rows, cols, diag_entries) @classmethod def eye(kls, rows, cols=None, **kwargs): """Returns an identity matrix. Args ==== rows : rows of the matrix cols : cols of the matrix (if None, cols=rows) kwargs ====== cls : class of the returned matrix """ if cols is None: cols = rows if rows < 0 or cols < 0: raise ValueError("Cannot create a {} x {} matrix. " "Both dimensions must be positive".format(rows, cols)) klass = kwargs.get('cls', kls) rows, cols = as_int(rows), as_int(cols) return klass._eval_eye(rows, cols) @classmethod def jordan_block(kls, size=None, eigenvalue=None, *, band='upper', **kwargs): """Returns a Jordan block Parameters ========== size : Integer, optional Specifies the shape of the Jordan block matrix. eigenvalue : Number or Symbol Specifies the value for the main diagonal of the matrix. .. note:: The keyword ``eigenval`` is also specified as an alias of this keyword, but it is not recommended to use. We may deprecate the alias in later release. band : 'upper' or 'lower', optional Specifies the position of the off-diagonal to put `1` s on. cls : Matrix, optional Specifies the matrix class of the output form. If it is not specified, the class type where the method is being executed on will be returned. rows, cols : Integer, optional Specifies the shape of the Jordan block matrix. See Notes section for the details of how these key works. .. note:: This feature will be deprecated in the future. Returns ======= Matrix A Jordan block matrix. Raises ====== ValueError If insufficient arguments are given for matrix size specification, or no eigenvalue is given. Examples ======== Creating a default Jordan block: >>> from sympy import Matrix >>> from sympy.abc import x >>> Matrix.jordan_block(4, x) Matrix([ [x, 1, 0, 0], [0, x, 1, 0], [0, 0, x, 1], [0, 0, 0, x]]) Creating an alternative Jordan block matrix where `1` is on lower off-diagonal: >>> Matrix.jordan_block(4, x, band='lower') Matrix([ [x, 0, 0, 0], [1, x, 0, 0], [0, 1, x, 0], [0, 0, 1, x]]) Creating a Jordan block with keyword arguments >>> Matrix.jordan_block(size=4, eigenvalue=x) Matrix([ [x, 1, 0, 0], [0, x, 1, 0], [0, 0, x, 1], [0, 0, 0, x]]) Notes ===== .. note:: This feature will be deprecated in the future. The keyword arguments ``size``, ``rows``, ``cols`` relates to the Jordan block size specifications. If you want to create a square Jordan block, specify either one of the three arguments. If you want to create a rectangular Jordan block, specify ``rows`` and ``cols`` individually. +--------------------------------+---------------------+ | Arguments Given | Matrix Shape | +----------+----------+----------+----------+----------+ | size | rows | cols | rows | cols | +==========+==========+==========+==========+==========+ | size | Any | size | size | +----------+----------+----------+----------+----------+ | | None | ValueError | | +----------+----------+----------+----------+ | None | rows | None | rows | rows | | +----------+----------+----------+----------+ | | None | cols | cols | cols | + +----------+----------+----------+----------+ | | rows | cols | rows | cols | +----------+----------+----------+----------+----------+ References ========== .. [1] https://en.wikipedia.org/wiki/Jordan_matrix """ if 'rows' in kwargs or 'cols' in kwargs: SymPyDeprecationWarning( feature="Keyword arguments 'rows' or 'cols'", issue=16102, useinstead="a more generic banded matrix constructor", deprecated_since_version="1.4" ).warn() klass = kwargs.pop('cls', kls) rows = kwargs.pop('rows', None) cols = kwargs.pop('cols', None) eigenval = kwargs.get('eigenval', None) if eigenvalue is None and eigenval is None: raise ValueError("Must supply an eigenvalue") elif eigenvalue != eigenval and None not in (eigenval, eigenvalue): raise ValueError( "Inconsistent values are given: 'eigenval'={}, " "'eigenvalue'={}".format(eigenval, eigenvalue)) else: if eigenval is not None: eigenvalue = eigenval if (size, rows, cols) == (None, None, None): raise ValueError("Must supply a matrix size") if size is not None: rows, cols = size, size elif rows is not None and cols is None: cols = rows elif cols is not None and rows is None: rows = cols rows, cols = as_int(rows), as_int(cols) return klass._eval_jordan_block(rows, cols, eigenvalue, band) @classmethod def ones(kls, rows, cols=None, **kwargs): """Returns a matrix of ones. Args ==== rows : rows of the matrix cols : cols of the matrix (if None, cols=rows) kwargs ====== cls : class of the returned matrix """ if cols is None: cols = rows klass = kwargs.get('cls', kls) rows, cols = as_int(rows), as_int(cols) return klass._eval_ones(rows, cols) @classmethod def zeros(kls, rows, cols=None, **kwargs): """Returns a matrix of zeros. Args ==== rows : rows of the matrix cols : cols of the matrix (if None, cols=rows) kwargs ====== cls : class of the returned matrix """ if cols is None: cols = rows if rows < 0 or cols < 0: raise ValueError("Cannot create a {} x {} matrix. " "Both dimensions must be positive".format(rows, cols)) klass = kwargs.get('cls', kls) rows, cols = as_int(rows), as_int(cols) return klass._eval_zeros(rows, cols) @classmethod def companion(kls, poly): """Returns a companion matrix of a polynomial. Examples ======== >>> from sympy import Matrix, Poly, Symbol, symbols >>> x = Symbol('x') >>> c0, c1, c2, c3, c4 = symbols('c0:5') >>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x) >>> Matrix.companion(p) Matrix([ [0, 0, 0, 0, -c0], [1, 0, 0, 0, -c1], [0, 1, 0, 0, -c2], [0, 0, 1, 0, -c3], [0, 0, 0, 1, -c4]]) """ poly = kls._sympify(poly) if not isinstance(poly, Poly): raise ValueError("{} must be a Poly instance.".format(poly)) if not poly.is_monic: raise ValueError("{} must be a monic polynomial.".format(poly)) if not poly.is_univariate: raise ValueError( "{} must be a univariate polynomial.".format(poly)) size = poly.degree() if not size >= 1: raise ValueError( "{} must have degree not less than 1.".format(poly)) coeffs = poly.all_coeffs() def entry(i, j): if j == size - 1: return -coeffs[-1 - i] elif i == j + 1: return kls.one return kls.zero return kls._new(size, size, entry) @classmethod def wilkinson(kls, n, **kwargs): """Returns two square Wilkinson Matrix of size 2*n + 1 $W_{2n + 1}^-, W_{2n + 1}^+ =$ Wilkinson(n) Examples ======== >>> from sympy.matrices import Matrix >>> wminus, wplus = Matrix.wilkinson(3) >>> wminus Matrix([ [-3, 1, 0, 0, 0, 0, 0], [ 1, -2, 1, 0, 0, 0, 0], [ 0, 1, -1, 1, 0, 0, 0], [ 0, 0, 1, 0, 1, 0, 0], [ 0, 0, 0, 1, 1, 1, 0], [ 0, 0, 0, 0, 1, 2, 1], [ 0, 0, 0, 0, 0, 1, 3]]) >>> wplus Matrix([ [3, 1, 0, 0, 0, 0, 0], [1, 2, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0], [0, 0, 0, 0, 1, 2, 1], [0, 0, 0, 0, 0, 1, 3]]) References ========== .. [1] https://blogs.mathworks.com/cleve/2013/04/15/wilkinsons-matrices-2/ .. [2] J. H. Wilkinson, The Algebraic Eigenvalue Problem, Claredon Press, Oxford, 1965, 662 pp. """ klass = kwargs.get('cls', kls) n = as_int(n) return klass._eval_wilkinson(n) class MatrixProperties(MatrixRequired): """Provides basic properties of a matrix.""" def _eval_atoms(self, *types): result = set() for i in self: result.update(i.atoms(*types)) return result def _eval_free_symbols(self): return set().union(*(i.free_symbols for i in self if i)) def _eval_has(self, *patterns): return any(a.has(*patterns) for a in self) def _eval_is_anti_symmetric(self, simpfunc): if not all(simpfunc(self[i, j] + self[j, i]).is_zero for i in range(self.rows) for j in range(self.cols)): return False return True def _eval_is_diagonal(self): for i in range(self.rows): for j in range(self.cols): if i != j and self[i, j]: return False return True # _eval_is_hermitian is called by some general sympy # routines and has a different *args signature. Make # sure the names don't clash by adding `_matrix_` in name. def _eval_is_matrix_hermitian(self, simpfunc): mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i].conjugate())) return mat.is_zero_matrix def _eval_is_Identity(self) -> FuzzyBool: def dirac(i, j): if i == j: return 1 return 0 return all(self[i, j] == dirac(i, j) for i in range(self.rows) for j in range(self.cols)) def _eval_is_lower_hessenberg(self): return all(self[i, j].is_zero for i in range(self.rows) for j in range(i + 2, self.cols)) def _eval_is_lower(self): return all(self[i, j].is_zero for i in range(self.rows) for j in range(i + 1, self.cols)) def _eval_is_symbolic(self): return self.has(Symbol) def _eval_is_symmetric(self, simpfunc): mat = self._new(self.rows, self.cols, lambda i, j: simpfunc(self[i, j] - self[j, i])) return mat.is_zero_matrix def _eval_is_zero_matrix(self): if any(i.is_zero == False for i in self): return False if any(i.is_zero is None for i in self): return None return True def _eval_is_upper_hessenberg(self): return all(self[i, j].is_zero for i in range(2, self.rows) for j in range(min(self.cols, (i - 1)))) def _eval_values(self): return [i for i in self if not i.is_zero] def _has_positive_diagonals(self): diagonal_entries = (self[i, i] for i in range(self.rows)) return fuzzy_and(x.is_positive for x in diagonal_entries) def _has_nonnegative_diagonals(self): diagonal_entries = (self[i, i] for i in range(self.rows)) return fuzzy_and(x.is_nonnegative for x in diagonal_entries) def atoms(self, *types): """Returns the atoms that form the current object. Examples ======== >>> from sympy.abc import x, y >>> from sympy.matrices import Matrix >>> Matrix([[x]]) Matrix([[x]]) >>> _.atoms() {x} >>> Matrix([[x, y], [y, x]]) Matrix([ [x, y], [y, x]]) >>> _.atoms() {x, y} """ types = tuple(t if isinstance(t, type) else type(t) for t in types) if not types: types = (Atom,) return self._eval_atoms(*types) @property def free_symbols(self): """Returns the free symbols within the matrix. Examples ======== >>> from sympy.abc import x >>> from sympy.matrices import Matrix >>> Matrix([[x], [1]]).free_symbols {x} """ return self._eval_free_symbols() def has(self, *patterns): """Test whether any subexpression matches any of the patterns. Examples ======== >>> from sympy import Matrix, SparseMatrix, Float >>> from sympy.abc import x, y >>> A = Matrix(((1, x), (0.2, 3))) >>> B = SparseMatrix(((1, x), (0.2, 3))) >>> A.has(x) True >>> A.has(y) False >>> A.has(Float) True >>> B.has(x) True >>> B.has(y) False >>> B.has(Float) True """ return self._eval_has(*patterns) def is_anti_symmetric(self, simplify=True): """Check if matrix M is an antisymmetric matrix, that is, M is a square matrix with all M[i, j] == -M[j, i]. When ``simplify=True`` (default), the sum M[i, j] + M[j, i] is simplified before testing to see if it is zero. By default, the SymPy simplify function is used. To use a custom function set simplify to a function that accepts a single argument which returns a simplified expression. To skip simplification, set simplify to False but note that although this will be faster, it may induce false negatives. Examples ======== >>> from sympy import Matrix, symbols >>> m = Matrix(2, 2, [0, 1, -1, 0]) >>> m Matrix([ [ 0, 1], [-1, 0]]) >>> m.is_anti_symmetric() True >>> x, y = symbols('x y') >>> m = Matrix(2, 3, [0, 0, x, -y, 0, 0]) >>> m Matrix([ [ 0, 0, x], [-y, 0, 0]]) >>> m.is_anti_symmetric() False >>> from sympy.abc import x, y >>> m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, ... -(x + 1)**2 , 0, x*y, ... -y, -x*y, 0]) Simplification of matrix elements is done by default so even though two elements which should be equal and opposite wouldn't pass an equality test, the matrix is still reported as anti-symmetric: >>> m[0, 1] == -m[1, 0] False >>> m.is_anti_symmetric() True If 'simplify=False' is used for the case when a Matrix is already simplified, this will speed things up. Here, we see that without simplification the matrix does not appear anti-symmetric: >>> m.is_anti_symmetric(simplify=False) False But if the matrix were already expanded, then it would appear anti-symmetric and simplification in the is_anti_symmetric routine is not needed: >>> m = m.expand() >>> m.is_anti_symmetric(simplify=False) True """ # accept custom simplification simpfunc = simplify if not isfunction(simplify): simpfunc = _simplify if simplify else lambda x: x if not self.is_square: return False return self._eval_is_anti_symmetric(simpfunc) def is_diagonal(self): """Check if matrix is diagonal, that is matrix in which the entries outside the main diagonal are all zero. Examples ======== >>> from sympy import Matrix, diag >>> m = Matrix(2, 2, [1, 0, 0, 2]) >>> m Matrix([ [1, 0], [0, 2]]) >>> m.is_diagonal() True >>> m = Matrix(2, 2, [1, 1, 0, 2]) >>> m Matrix([ [1, 1], [0, 2]]) >>> m.is_diagonal() False >>> m = diag(1, 2, 3) >>> m Matrix([ [1, 0, 0], [0, 2, 0], [0, 0, 3]]) >>> m.is_diagonal() True See Also ======== is_lower is_upper sympy.matrices.matrices.MatrixEigen.is_diagonalizable diagonalize """ return self._eval_is_diagonal() @property def is_weakly_diagonally_dominant(self): r"""Tests if the matrix is row weakly diagonally dominant. Explanation =========== A $n, n$ matrix $A$ is row weakly diagonally dominant if .. math:: \left|A_{i, i}\right| \ge \sum_{j = 0, j \neq i}^{n-1} \left|A_{i, j}\right| \quad {\text{for all }} i \in \{ 0, ..., n-1 \} Examples ======== >>> from sympy.matrices import Matrix >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) >>> A.is_weakly_diagonally_dominant True >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) >>> A.is_weakly_diagonally_dominant False >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) >>> A.is_weakly_diagonally_dominant True Notes ===== If you want to test whether a matrix is column diagonally dominant, you can apply the test after transposing the matrix. """ if not self.is_square: return False rows, cols = self.shape def test_row(i): summation = self.zero for j in range(cols): if i != j: summation += Abs(self[i, j]) return (Abs(self[i, i]) - summation).is_nonnegative return fuzzy_and(test_row(i) for i in range(rows)) @property def is_strongly_diagonally_dominant(self): r"""Tests if the matrix is row strongly diagonally dominant. Explanation =========== A $n, n$ matrix $A$ is row strongly diagonally dominant if .. math:: \left|A_{i, i}\right| > \sum_{j = 0, j \neq i}^{n-1} \left|A_{i, j}\right| \quad {\text{for all }} i \in \{ 0, ..., n-1 \} Examples ======== >>> from sympy.matrices import Matrix >>> A = Matrix([[3, -2, 1], [1, -3, 2], [-1, 2, 4]]) >>> A.is_strongly_diagonally_dominant False >>> A = Matrix([[-2, 2, 1], [1, 3, 2], [1, -2, 0]]) >>> A.is_strongly_diagonally_dominant False >>> A = Matrix([[-4, 2, 1], [1, 6, 2], [1, -2, 5]]) >>> A.is_strongly_diagonally_dominant True Notes ===== If you want to test whether a matrix is column diagonally dominant, you can apply the test after transposing the matrix. """ if not self.is_square: return False rows, cols = self.shape def test_row(i): summation = self.zero for j in range(cols): if i != j: summation += Abs(self[i, j]) return (Abs(self[i, i]) - summation).is_positive return fuzzy_and(test_row(i) for i in range(rows)) @property def is_hermitian(self): """Checks if the matrix is Hermitian. In a Hermitian matrix element i,j is the complex conjugate of element j,i. Examples ======== >>> from sympy.matrices import Matrix >>> from sympy import I >>> from sympy.abc import x >>> a = Matrix([[1, I], [-I, 1]]) >>> a Matrix([ [ 1, I], [-I, 1]]) >>> a.is_hermitian True >>> a[0, 0] = 2*I >>> a.is_hermitian False >>> a[0, 0] = x >>> a.is_hermitian >>> a[0, 1] = a[1, 0]*I >>> a.is_hermitian False """ if not self.is_square: return False return self._eval_is_matrix_hermitian(_simplify) @property def is_Identity(self) -> FuzzyBool: if not self.is_square: return False return self._eval_is_Identity() @property def is_lower_hessenberg(self): r"""Checks if the matrix is in the lower-Hessenberg form. The lower hessenberg matrix has zero entries above the first superdiagonal. Examples ======== >>> from sympy.matrices import Matrix >>> a = Matrix([[1, 2, 0, 0], [5, 2, 3, 0], [3, 4, 3, 7], [5, 6, 1, 1]]) >>> a Matrix([ [1, 2, 0, 0], [5, 2, 3, 0], [3, 4, 3, 7], [5, 6, 1, 1]]) >>> a.is_lower_hessenberg True See Also ======== is_upper_hessenberg is_lower """ return self._eval_is_lower_hessenberg() @property def is_lower(self): """Check if matrix is a lower triangular matrix. True can be returned even if the matrix is not square. Examples ======== >>> from sympy import Matrix >>> m = Matrix(2, 2, [1, 0, 0, 1]) >>> m Matrix([ [1, 0], [0, 1]]) >>> m.is_lower True >>> m = Matrix(4, 3, [0, 0, 0, 2, 0, 0, 1, 4 , 0, 6, 6, 5]) >>> m Matrix([ [0, 0, 0], [2, 0, 0], [1, 4, 0], [6, 6, 5]]) >>> m.is_lower True >>> from sympy.abc import x, y >>> m = Matrix(2, 2, [x**2 + y, y**2 + x, 0, x + y]) >>> m Matrix([ [x**2 + y, x + y**2], [ 0, x + y]]) >>> m.is_lower False See Also ======== is_upper is_diagonal is_lower_hessenberg """ return self._eval_is_lower() @property def is_square(self): """Checks if a matrix is square. A matrix is square if the number of rows equals the number of columns. The empty matrix is square by definition, since the number of rows and the number of columns are both zero. Examples ======== >>> from sympy import Matrix >>> a = Matrix([[1, 2, 3], [4, 5, 6]]) >>> b = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> c = Matrix([]) >>> a.is_square False >>> b.is_square True >>> c.is_square True """ return self.rows == self.cols def is_symbolic(self): """Checks if any elements contain Symbols. Examples ======== >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y >>> M = Matrix([[x, y], [1, 0]]) >>> M.is_symbolic() True """ return self._eval_is_symbolic() def is_symmetric(self, simplify=True): """Check if matrix is symmetric matrix, that is square matrix and is equal to its transpose. By default, simplifications occur before testing symmetry. They can be skipped using 'simplify=False'; while speeding things a bit, this may however induce false negatives. Examples ======== >>> from sympy import Matrix >>> m = Matrix(2, 2, [0, 1, 1, 2]) >>> m Matrix([ [0, 1], [1, 2]]) >>> m.is_symmetric() True >>> m = Matrix(2, 2, [0, 1, 2, 0]) >>> m Matrix([ [0, 1], [2, 0]]) >>> m.is_symmetric() False >>> m = Matrix(2, 3, [0, 0, 0, 0, 0, 0]) >>> m Matrix([ [0, 0, 0], [0, 0, 0]]) >>> m.is_symmetric() False >>> from sympy.abc import x, y >>> m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2 , 2, 0, y, 0, 3]) >>> m Matrix([ [ 1, x**2 + 2*x + 1, y], [(x + 1)**2, 2, 0], [ y, 0, 3]]) >>> m.is_symmetric() True If the matrix is already simplified, you may speed-up is_symmetric() test by using 'simplify=False'. >>> bool(m.is_symmetric(simplify=False)) False >>> m1 = m.expand() >>> m1.is_symmetric(simplify=False) True """ simpfunc = simplify if not isfunction(simplify): simpfunc = _simplify if simplify else lambda x: x if not self.is_square: return False return self._eval_is_symmetric(simpfunc) @property def is_upper_hessenberg(self): """Checks if the matrix is the upper-Hessenberg form. The upper hessenberg matrix has zero entries below the first subdiagonal. Examples ======== >>> from sympy.matrices import Matrix >>> a = Matrix([[1, 4, 2, 3], [3, 4, 1, 7], [0, 2, 3, 4], [0, 0, 1, 3]]) >>> a Matrix([ [1, 4, 2, 3], [3, 4, 1, 7], [0, 2, 3, 4], [0, 0, 1, 3]]) >>> a.is_upper_hessenberg True See Also ======== is_lower_hessenberg is_upper """ return self._eval_is_upper_hessenberg() @property def is_upper(self): """Check if matrix is an upper triangular matrix. True can be returned even if the matrix is not square. Examples ======== >>> from sympy import Matrix >>> m = Matrix(2, 2, [1, 0, 0, 1]) >>> m Matrix([ [1, 0], [0, 1]]) >>> m.is_upper True >>> m = Matrix(4, 3, [5, 1, 9, 0, 4 , 6, 0, 0, 5, 0, 0, 0]) >>> m Matrix([ [5, 1, 9], [0, 4, 6], [0, 0, 5], [0, 0, 0]]) >>> m.is_upper True >>> m = Matrix(2, 3, [4, 2, 5, 6, 1, 1]) >>> m Matrix([ [4, 2, 5], [6, 1, 1]]) >>> m.is_upper False See Also ======== is_lower is_diagonal is_upper_hessenberg """ return all(self[i, j].is_zero for i in range(1, self.rows) for j in range(min(i, self.cols))) @property def is_zero_matrix(self): """Checks if a matrix is a zero matrix. A matrix is zero if every element is zero. A matrix need not be square to be considered zero. The empty matrix is zero by the principle of vacuous truth. For a matrix that may or may not be zero (e.g. contains a symbol), this will be None Examples ======== >>> from sympy import Matrix, zeros >>> from sympy.abc import x >>> a = Matrix([[0, 0], [0, 0]]) >>> b = zeros(3, 4) >>> c = Matrix([[0, 1], [0, 0]]) >>> d = Matrix([]) >>> e = Matrix([[x, 0], [0, 0]]) >>> a.is_zero_matrix True >>> b.is_zero_matrix True >>> c.is_zero_matrix False >>> d.is_zero_matrix True >>> e.is_zero_matrix """ return self._eval_is_zero_matrix() def values(self): """Return non-zero values of self.""" return self._eval_values() class MatrixOperations(MatrixRequired): """Provides basic matrix shape and elementwise operations. Should not be instantiated directly.""" def _eval_adjoint(self): return self.transpose().conjugate() def _eval_applyfunc(self, f): out = self._new(self.rows, self.cols, [f(x) for x in self]) return out def _eval_as_real_imag(self): # type: ignore from sympy.functions.elementary.complexes import re, im return (self.applyfunc(re), self.applyfunc(im)) def _eval_conjugate(self): return self.applyfunc(lambda x: x.conjugate()) def _eval_permute_cols(self, perm): # apply the permutation to a list mapping = list(perm) def entry(i, j): return self[i, mapping[j]] return self._new(self.rows, self.cols, entry) def _eval_permute_rows(self, perm): # apply the permutation to a list mapping = list(perm) def entry(i, j): return self[mapping[i], j] return self._new(self.rows, self.cols, entry) def _eval_trace(self): return sum(self[i, i] for i in range(self.rows)) def _eval_transpose(self): return self._new(self.cols, self.rows, lambda i, j: self[j, i]) def adjoint(self): """Conjugate transpose or Hermitian conjugation.""" return self._eval_adjoint() def applyfunc(self, f): """Apply a function to each element of the matrix. Examples ======== >>> from sympy import Matrix >>> m = Matrix(2, 2, lambda i, j: i*2+j) >>> m Matrix([ [0, 1], [2, 3]]) >>> m.applyfunc(lambda i: 2*i) Matrix([ [0, 2], [4, 6]]) """ if not callable(f): raise TypeError("`f` must be callable.") return self._eval_applyfunc(f) def as_real_imag(self, deep=True, **hints): """Returns a tuple containing the (real, imaginary) part of matrix.""" # XXX: Ignoring deep and hints... return self._eval_as_real_imag() def conjugate(self): """Return the by-element conjugation. Examples ======== >>> from sympy.matrices import SparseMatrix >>> from sympy import I >>> a = SparseMatrix(((1, 2 + I), (3, 4), (I, -I))) >>> a Matrix([ [1, 2 + I], [3, 4], [I, -I]]) >>> a.C Matrix([ [ 1, 2 - I], [ 3, 4], [-I, I]]) See Also ======== transpose: Matrix transposition H: Hermite conjugation sympy.matrices.matrices.MatrixBase.D: Dirac conjugation """ return self._eval_conjugate() def doit(self, **kwargs): return self.applyfunc(lambda x: x.doit()) def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): """Apply evalf() to each element of self.""" options = {'subs':subs, 'maxn':maxn, 'chop':chop, 'strict':strict, 'quad':quad, 'verbose':verbose} return self.applyfunc(lambda i: i.evalf(n, **options)) def expand(self, deep=True, modulus=None, power_base=True, power_exp=True, mul=True, log=True, multinomial=True, basic=True, **hints): """Apply core.function.expand to each entry of the matrix. Examples ======== >>> from sympy.abc import x >>> from sympy.matrices import Matrix >>> Matrix(1, 1, [x*(x+1)]) Matrix([[x*(x + 1)]]) >>> _.expand() Matrix([[x**2 + x]]) """ return self.applyfunc(lambda x: x.expand( deep, modulus, power_base, power_exp, mul, log, multinomial, basic, **hints)) @property def H(self): """Return Hermite conjugate. Examples ======== >>> from sympy import Matrix, I >>> m = Matrix((0, 1 + I, 2, 3)) >>> m Matrix([ [ 0], [1 + I], [ 2], [ 3]]) >>> m.H Matrix([[0, 1 - I, 2, 3]]) See Also ======== conjugate: By-element conjugation sympy.matrices.matrices.MatrixBase.D: Dirac conjugation """ return self.T.C def permute(self, perm, orientation='rows', direction='forward'): r"""Permute the rows or columns of a matrix by the given list of swaps. Parameters ========== perm : Permutation, list, or list of lists A representation for the permutation. If it is ``Permutation``, it is used directly with some resizing with respect to the matrix size. If it is specified as list of lists, (e.g., ``[[0, 1], [0, 2]]``), then the permutation is formed from applying the product of cycles. The direction how the cyclic product is applied is described in below. If it is specified as a list, the list should represent an array form of a permutation. (e.g., ``[1, 2, 0]``) which would would form the swapping function `0 \mapsto 1, 1 \mapsto 2, 2\mapsto 0`. orientation : 'rows', 'cols' A flag to control whether to permute the rows or the columns direction : 'forward', 'backward' A flag to control whether to apply the permutations from the start of the list first, or from the back of the list first. For example, if the permutation specification is ``[[0, 1], [0, 2]]``, If the flag is set to ``'forward'``, the cycle would be formed as `0 \mapsto 2, 2 \mapsto 1, 1 \mapsto 0`. If the flag is set to ``'backward'``, the cycle would be formed as `0 \mapsto 1, 1 \mapsto 2, 2 \mapsto 0`. If the argument ``perm`` is not in a form of list of lists, this flag takes no effect. Examples ======== >>> from sympy.matrices import eye >>> M = eye(3) >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='forward') Matrix([ [0, 0, 1], [1, 0, 0], [0, 1, 0]]) >>> from sympy.matrices import eye >>> M = eye(3) >>> M.permute([[0, 1], [0, 2]], orientation='rows', direction='backward') Matrix([ [0, 1, 0], [0, 0, 1], [1, 0, 0]]) Notes ===== If a bijective function `\sigma : \mathbb{N}_0 \rightarrow \mathbb{N}_0` denotes the permutation. If the matrix `A` is the matrix to permute, represented as a horizontal or a vertical stack of vectors: .. math:: A = \begin{bmatrix} a_0 \\ a_1 \\ \vdots \\ a_{n-1} \end{bmatrix} = \begin{bmatrix} \alpha_0 & \alpha_1 & \cdots & \alpha_{n-1} \end{bmatrix} If the matrix `B` is the result, the permutation of matrix rows is defined as: .. math:: B := \begin{bmatrix} a_{\sigma(0)} \\ a_{\sigma(1)} \\ \vdots \\ a_{\sigma(n-1)} \end{bmatrix} And the permutation of matrix columns is defined as: .. math:: B := \begin{bmatrix} \alpha_{\sigma(0)} & \alpha_{\sigma(1)} & \cdots & \alpha_{\sigma(n-1)} \end{bmatrix} """ from sympy.combinatorics import Permutation # allow british variants and `columns` if direction == 'forwards': direction = 'forward' if direction == 'backwards': direction = 'backward' if orientation == 'columns': orientation = 'cols' if direction not in ('forward', 'backward'): raise TypeError("direction='{}' is an invalid kwarg. " "Try 'forward' or 'backward'".format(direction)) if orientation not in ('rows', 'cols'): raise TypeError("orientation='{}' is an invalid kwarg. " "Try 'rows' or 'cols'".format(orientation)) if not isinstance(perm, (Permutation, Iterable)): raise ValueError( "{} must be a list, a list of lists, " "or a SymPy permutation object.".format(perm)) # ensure all swaps are in range max_index = self.rows if orientation == 'rows' else self.cols if not all(0 <= t <= max_index for t in flatten(list(perm))): raise IndexError("`swap` indices out of range.") if perm and not isinstance(perm, Permutation) and \ isinstance(perm[0], Iterable): if direction == 'forward': perm = list(reversed(perm)) perm = Permutation(perm, size=max_index+1) else: perm = Permutation(perm, size=max_index+1) if orientation == 'rows': return self._eval_permute_rows(perm) if orientation == 'cols': return self._eval_permute_cols(perm) def permute_cols(self, swaps, direction='forward'): """Alias for ``self.permute(swaps, orientation='cols', direction=direction)`` See Also ======== permute """ return self.permute(swaps, orientation='cols', direction=direction) def permute_rows(self, swaps, direction='forward'): """Alias for ``self.permute(swaps, orientation='rows', direction=direction)`` See Also ======== permute """ return self.permute(swaps, orientation='rows', direction=direction) def refine(self, assumptions=True): """Apply refine to each element of the matrix. Examples ======== >>> from sympy import Symbol, Matrix, Abs, sqrt, Q >>> x = Symbol('x') >>> Matrix([[Abs(x)**2, sqrt(x**2)],[sqrt(x**2), Abs(x)**2]]) Matrix([ [ Abs(x)**2, sqrt(x**2)], [sqrt(x**2), Abs(x)**2]]) >>> _.refine(Q.real(x)) Matrix([ [ x**2, Abs(x)], [Abs(x), x**2]]) """ return self.applyfunc(lambda x: refine(x, assumptions)) def replace(self, F, G, map=False, simultaneous=True, exact=None): """Replaces Function F in Matrix entries with Function G. Examples ======== >>> from sympy import symbols, Function, Matrix >>> F, G = symbols('F, G', cls=Function) >>> M = Matrix(2, 2, lambda i, j: F(i+j)) ; M Matrix([ [F(0), F(1)], [F(1), F(2)]]) >>> N = M.replace(F,G) >>> N Matrix([ [G(0), G(1)], [G(1), G(2)]]) """ return self.applyfunc( lambda x: x.replace(F, G, map=map, simultaneous=simultaneous, exact=exact)) def rot90(self, k=1): """Rotates Matrix by 90 degrees Parameters ========== k : int Specifies how many times the matrix is rotated by 90 degrees (clockwise when positive, counter-clockwise when negative). Examples ======== >>> from sympy import Matrix, symbols >>> A = Matrix(2, 2, symbols('a:d')) >>> A Matrix([ [a, b], [c, d]]) Rotating the matrix clockwise one time: >>> A.rot90(1) Matrix([ [c, a], [d, b]]) Rotating the matrix anticlockwise two times: >>> A.rot90(-2) Matrix([ [d, c], [b, a]]) """ mod = k%4 if mod == 0: return self if mod == 1: return self[::-1, ::].T if mod == 2: return self[::-1, ::-1] if mod == 3: return self[::, ::-1].T def simplify(self, **kwargs): """Apply simplify to each element of the matrix. Examples ======== >>> from sympy.abc import x, y >>> from sympy import sin, cos >>> from sympy.matrices import SparseMatrix >>> SparseMatrix(1, 1, [x*sin(y)**2 + x*cos(y)**2]) Matrix([[x*sin(y)**2 + x*cos(y)**2]]) >>> _.simplify() Matrix([[x]]) """ return self.applyfunc(lambda x: x.simplify(**kwargs)) def subs(self, *args, **kwargs): # should mirror core.basic.subs """Return a new matrix with subs applied to each entry. Examples ======== >>> from sympy.abc import x, y >>> from sympy.matrices import SparseMatrix, Matrix >>> SparseMatrix(1, 1, [x]) Matrix([[x]]) >>> _.subs(x, y) Matrix([[y]]) >>> Matrix(_).subs(y, x) Matrix([[x]]) """ if len(args) == 1 and not isinstance(args[0], (dict, set)) and iter(args[0]) and not is_sequence(args[0]): args = (list(args[0]),) return self.applyfunc(lambda x: x.subs(*args, **kwargs)) def trace(self): """ Returns the trace of a square matrix i.e. the sum of the diagonal elements. Examples ======== >>> from sympy import Matrix >>> A = Matrix(2, 2, [1, 2, 3, 4]) >>> A.trace() 5 """ if self.rows != self.cols: raise NonSquareMatrixError() return self._eval_trace() def transpose(self): """ Returns the transpose of the matrix. Examples ======== >>> from sympy import Matrix >>> A = Matrix(2, 2, [1, 2, 3, 4]) >>> A.transpose() Matrix([ [1, 3], [2, 4]]) >>> from sympy import Matrix, I >>> m=Matrix(((1, 2+I), (3, 4))) >>> m Matrix([ [1, 2 + I], [3, 4]]) >>> m.transpose() Matrix([ [ 1, 3], [2 + I, 4]]) >>> m.T == m.transpose() True See Also ======== conjugate: By-element conjugation """ return self._eval_transpose() @property def T(self): '''Matrix transposition''' return self.transpose() @property def C(self): '''By-element conjugation''' return self.conjugate() def n(self, *args, **kwargs): """Apply evalf() to each element of self.""" return self.evalf(*args, **kwargs) def xreplace(self, rule): # should mirror core.basic.xreplace """Return a new matrix with xreplace applied to each entry. Examples ======== >>> from sympy.abc import x, y >>> from sympy.matrices import SparseMatrix, Matrix >>> SparseMatrix(1, 1, [x]) Matrix([[x]]) >>> _.xreplace({x: y}) Matrix([[y]]) >>> Matrix(_).xreplace({y: x}) Matrix([[x]]) """ return self.applyfunc(lambda x: x.xreplace(rule)) def _eval_simplify(self, **kwargs): # XXX: We can't use self.simplify here as mutable subclasses will # override simplify and have it return None return MatrixOperations.simplify(self, **kwargs) def _eval_trigsimp(self, **opts): from sympy.simplify import trigsimp return self.applyfunc(lambda x: trigsimp(x, **opts)) def upper_triangular(self, k=0): """returns the elements on and above the kth diagonal of a matrix. If k is not specified then simply returns upper-triangular portion of a matrix Examples ======== >>> from sympy import ones >>> A = ones(4) >>> A.upper_triangular() Matrix([ [1, 1, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 1]]) >>> A.upper_triangular(2) Matrix([ [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0]]) >>> A.upper_triangular(-1) Matrix([ [1, 1, 1, 1], [1, 1, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1]]) """ def entry(i, j): return self[i, j] if i + k <= j else self.zero return self._new(self.rows, self.cols, entry) def lower_triangular(self, k=0): """returns the elements on and below the kth diagonal of a matrix. If k is not specified then simply returns lower-triangular portion of a matrix Examples ======== >>> from sympy import ones >>> A = ones(4) >>> A.lower_triangular() Matrix([ [1, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [1, 1, 1, 1]]) >>> A.lower_triangular(-2) Matrix([ [0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 0, 0]]) >>> A.lower_triangular(1) Matrix([ [1, 1, 0, 0], [1, 1, 1, 0], [1, 1, 1, 1], [1, 1, 1, 1]]) """ def entry(i, j): return self[i, j] if i + k >= j else self.zero return self._new(self.rows, self.cols, entry) class MatrixArithmetic(MatrixRequired): """Provides basic matrix arithmetic operations. Should not be instantiated directly.""" _op_priority = 10.01 def _eval_Abs(self): return self._new(self.rows, self.cols, lambda i, j: Abs(self[i, j])) def _eval_add(self, other): return self._new(self.rows, self.cols, lambda i, j: self[i, j] + other[i, j]) def _eval_matrix_mul(self, other): def entry(i, j): vec = [self[i,k]*other[k,j] for k in range(self.cols)] try: return Add(*vec) except (TypeError, SympifyError): # Some matrices don't work with `sum` or `Add` # They don't work with `sum` because `sum` tries to add `0` # Fall back to a safe way to multiply if the `Add` fails. return reduce(lambda a, b: a + b, vec) return self._new(self.rows, other.cols, entry) def _eval_matrix_mul_elementwise(self, other): return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other[i,j]) def _eval_matrix_rmul(self, other): def entry(i, j): return sum(other[i,k]*self[k,j] for k in range(other.cols)) return self._new(other.rows, self.cols, entry) def _eval_pow_by_recursion(self, num): if num == 1: return self if num % 2 == 1: a, b = self, self._eval_pow_by_recursion(num - 1) else: a = b = self._eval_pow_by_recursion(num // 2) return a.multiply(b) def _eval_pow_by_cayley(self, exp): from sympy.discrete.recurrences import linrec_coeffs row = self.shape[0] p = self.charpoly() coeffs = (-p).all_coeffs()[1:] coeffs = linrec_coeffs(coeffs, exp) new_mat = self.eye(row) ans = self.zeros(row) for i in range(row): ans += coeffs[i]*new_mat new_mat *= self return ans def _eval_pow_by_recursion_dotprodsimp(self, num, prevsimp=None): if prevsimp is None: prevsimp = [True]*len(self) if num == 1: return self if num % 2 == 1: a, b = self, self._eval_pow_by_recursion_dotprodsimp(num - 1, prevsimp=prevsimp) else: a = b = self._eval_pow_by_recursion_dotprodsimp(num // 2, prevsimp=prevsimp) m = a.multiply(b, dotprodsimp=False) lenm = len(m) elems = [None]*lenm for i in range(lenm): if prevsimp[i]: elems[i], prevsimp[i] = _dotprodsimp(m[i], withsimp=True) else: elems[i] = m[i] return m._new(m.rows, m.cols, elems) def _eval_scalar_mul(self, other): return self._new(self.rows, self.cols, lambda i, j: self[i,j]*other) def _eval_scalar_rmul(self, other): return self._new(self.rows, self.cols, lambda i, j: other*self[i,j]) def _eval_Mod(self, other): from sympy import Mod return self._new(self.rows, self.cols, lambda i, j: Mod(self[i, j], other)) # python arithmetic functions def __abs__(self): """Returns a new matrix with entry-wise absolute values.""" return self._eval_Abs() @call_highest_priority('__radd__') def __add__(self, other): """Return self + other, raising ShapeError if shapes don't match.""" if isinstance(other, NDimArray): # Matrix and array addition is currently not implemented return NotImplemented other = _matrixify(other) # matrix-like objects can have shapes. This is # our first sanity check. if hasattr(other, 'shape'): if self.shape != other.shape: raise ShapeError("Matrix size mismatch: %s + %s" % ( self.shape, other.shape)) # honest sympy matrices defer to their class's routine if getattr(other, 'is_Matrix', False): # call the highest-priority class's _eval_add a, b = self, other if a.__class__ != classof(a, b): b, a = a, b return a._eval_add(b) # Matrix-like objects can be passed to CommonMatrix routines directly. if getattr(other, 'is_MatrixLike', False): return MatrixArithmetic._eval_add(self, other) raise TypeError('cannot add %s and %s' % (type(self), type(other))) @call_highest_priority('__rtruediv__') def __truediv__(self, other): return self * (self.one / other) @call_highest_priority('__rmatmul__') def __matmul__(self, other): other = _matrixify(other) if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): return NotImplemented return self.__mul__(other) def __mod__(self, other): return self.applyfunc(lambda x: x % other) @call_highest_priority('__rmul__') def __mul__(self, other): """Return self*other where other is either a scalar or a matrix of compatible dimensions. Examples ======== >>> from sympy.matrices import Matrix >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> 2*A == A*2 == Matrix([[2, 4, 6], [8, 10, 12]]) True >>> B = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> A*B Matrix([ [30, 36, 42], [66, 81, 96]]) >>> B*A Traceback (most recent call last): ... ShapeError: Matrices size mismatch. >>> See Also ======== matrix_multiply_elementwise """ return self.multiply(other) def multiply(self, other, dotprodsimp=None): """Same as __mul__() but with optional simplification. Parameters ========== dotprodsimp : bool, optional Specifies whether intermediate term algebraic simplification is used during matrix multiplications to control expression blowup and thus speed up calculation. Default is off. """ isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) other = _matrixify(other) # matrix-like objects can have shapes. This is # our first sanity check. Double check other is not explicitly not a Matrix. if (hasattr(other, 'shape') and len(other.shape) == 2 and (getattr(other, 'is_Matrix', True) or getattr(other, 'is_MatrixLike', True))): if self.shape[1] != other.shape[0]: raise ShapeError("Matrix size mismatch: %s * %s." % ( self.shape, other.shape)) # honest sympy matrices defer to their class's routine if getattr(other, 'is_Matrix', False): m = self._eval_matrix_mul(other) if isimpbool: return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) return m # Matrix-like objects can be passed to CommonMatrix routines directly. if getattr(other, 'is_MatrixLike', False): return MatrixArithmetic._eval_matrix_mul(self, other) # if 'other' is not iterable then scalar multiplication. if not isinstance(other, Iterable): try: return self._eval_scalar_mul(other) except TypeError: pass return NotImplemented def multiply_elementwise(self, other): """Return the Hadamard product (elementwise product) of A and B Examples ======== >>> from sympy.matrices import Matrix >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) >>> A.multiply_elementwise(B) Matrix([ [ 0, 10, 200], [300, 40, 5]]) See Also ======== sympy.matrices.matrices.MatrixBase.cross sympy.matrices.matrices.MatrixBase.dot multiply """ if self.shape != other.shape: raise ShapeError("Matrix shapes must agree {} != {}".format(self.shape, other.shape)) return self._eval_matrix_mul_elementwise(other) def __neg__(self): return self._eval_scalar_mul(-1) @call_highest_priority('__rpow__') def __pow__(self, exp): """Return self**exp a scalar or symbol.""" return self.pow(exp) def pow(self, exp, method=None): r"""Return self**exp a scalar or symbol. Parameters ========== method : multiply, mulsimp, jordan, cayley If multiply then it returns exponentiation using recursion. If jordan then Jordan form exponentiation will be used. If cayley then the exponentiation is done using Cayley-Hamilton theorem. If mulsimp then the exponentiation is done using recursion with dotprodsimp. This specifies whether intermediate term algebraic simplification is used during naive matrix power to control expression blowup and thus speed up calculation. If None, then it heuristically decides which method to use. """ if method is not None and method not in ['multiply', 'mulsimp', 'jordan', 'cayley']: raise TypeError('No such method') if self.rows != self.cols: raise NonSquareMatrixError() a = self jordan_pow = getattr(a, '_matrix_pow_by_jordan_blocks', None) exp = sympify(exp) if exp.is_zero: return a._new(a.rows, a.cols, lambda i, j: int(i == j)) if exp == 1: return a diagonal = getattr(a, 'is_diagonal', None) if diagonal is not None and diagonal(): return a._new(a.rows, a.cols, lambda i, j: a[i,j]**exp if i == j else 0) if exp.is_Number and exp % 1 == 0: if a.rows == 1: return a._new([[a[0]**exp]]) if exp < 0: exp = -exp a = a.inv() # When certain conditions are met, # Jordan block algorithm is faster than # computation by recursion. if method == 'jordan': try: return jordan_pow(exp) except MatrixError: if method == 'jordan': raise elif method == 'cayley': if not exp.is_Number or exp % 1 != 0: raise ValueError("cayley method is only valid for integer powers") return a._eval_pow_by_cayley(exp) elif method == "mulsimp": if not exp.is_Number or exp % 1 != 0: raise ValueError("mulsimp method is only valid for integer powers") return a._eval_pow_by_recursion_dotprodsimp(exp) elif method == "multiply": if not exp.is_Number or exp % 1 != 0: raise ValueError("multiply method is only valid for integer powers") return a._eval_pow_by_recursion(exp) elif method is None and exp.is_Number and exp % 1 == 0: # Decide heuristically which method to apply if a.rows == 2 and exp > 100000: return jordan_pow(exp) elif _get_intermediate_simp_bool(True, None): return a._eval_pow_by_recursion_dotprodsimp(exp) elif exp > 10000: return a._eval_pow_by_cayley(exp) else: return a._eval_pow_by_recursion(exp) if jordan_pow: try: return jordan_pow(exp) except NonInvertibleMatrixError: # Raised by jordan_pow on zero determinant matrix unless exp is # definitely known to be a non-negative integer. # Here we raise if n is definitely not a non-negative integer # but otherwise we can leave this as an unevaluated MatPow. if exp.is_integer is False or exp.is_nonnegative is False: raise from sympy.matrices.expressions import MatPow return MatPow(a, exp) @call_highest_priority('__add__') def __radd__(self, other): return self + other @call_highest_priority('__matmul__') def __rmatmul__(self, other): other = _matrixify(other) if not getattr(other, 'is_Matrix', False) and not getattr(other, 'is_MatrixLike', False): return NotImplemented return self.__rmul__(other) @call_highest_priority('__mul__') def __rmul__(self, other): return self.rmultiply(other) def rmultiply(self, other, dotprodsimp=None): """Same as __rmul__() but with optional simplification. Parameters ========== dotprodsimp : bool, optional Specifies whether intermediate term algebraic simplification is used during matrix multiplications to control expression blowup and thus speed up calculation. Default is off. """ isimpbool = _get_intermediate_simp_bool(False, dotprodsimp) other = _matrixify(other) # matrix-like objects can have shapes. This is # our first sanity check. Double check other is not explicitly not a Matrix. if (hasattr(other, 'shape') and len(other.shape) == 2 and (getattr(other, 'is_Matrix', True) or getattr(other, 'is_MatrixLike', True))): if self.shape[0] != other.shape[1]: raise ShapeError("Matrix size mismatch.") # honest sympy matrices defer to their class's routine if getattr(other, 'is_Matrix', False): m = self._eval_matrix_rmul(other) if isimpbool: return m._new(m.rows, m.cols, [_dotprodsimp(e) for e in m]) return m # Matrix-like objects can be passed to CommonMatrix routines directly. if getattr(other, 'is_MatrixLike', False): return MatrixArithmetic._eval_matrix_rmul(self, other) # if 'other' is not iterable then scalar multiplication. if not isinstance(other, Iterable): try: return self._eval_scalar_rmul(other) except TypeError: pass return NotImplemented @call_highest_priority('__sub__') def __rsub__(self, a): return (-self) + a @call_highest_priority('__rsub__') def __sub__(self, a): return self + (-a) class MatrixCommon(MatrixArithmetic, MatrixOperations, MatrixProperties, MatrixSpecial, MatrixShaping): """All common matrix operations including basic arithmetic, shaping, and special matrices like `zeros`, and `eye`.""" _diff_wrt = True # type: bool class _MinimalMatrix: """Class providing the minimum functionality for a matrix-like object and implementing every method required for a `MatrixRequired`. This class does not have everything needed to become a full-fledged SymPy object, but it will satisfy the requirements of anything inheriting from `MatrixRequired`. If you wish to make a specialized matrix type, make sure to implement these methods and properties with the exception of `__init__` and `__repr__` which are included for convenience.""" is_MatrixLike = True _sympify = staticmethod(sympify) _class_priority = 3 zero = S.Zero one = S.One is_Matrix = True is_MatrixExpr = False @classmethod def _new(cls, *args, **kwargs): return cls(*args, **kwargs) def __init__(self, rows, cols=None, mat=None, copy=False): if isfunction(mat): # if we passed in a function, use that to populate the indices mat = list(mat(i, j) for i in range(rows) for j in range(cols)) if cols is None and mat is None: mat = rows rows, cols = getattr(mat, 'shape', (rows, cols)) try: # if we passed in a list of lists, flatten it and set the size if cols is None and mat is None: mat = rows cols = len(mat[0]) rows = len(mat) mat = [x for l in mat for x in l] except (IndexError, TypeError): pass self.mat = tuple(self._sympify(x) for x in mat) self.rows, self.cols = rows, cols if self.rows is None or self.cols is None: raise NotImplementedError("Cannot initialize matrix with given parameters") def __getitem__(self, key): def _normalize_slices(row_slice, col_slice): """Ensure that row_slice and col_slice don't have `None` in their arguments. Any integers are converted to slices of length 1""" if not isinstance(row_slice, slice): row_slice = slice(row_slice, row_slice + 1, None) row_slice = slice(*row_slice.indices(self.rows)) if not isinstance(col_slice, slice): col_slice = slice(col_slice, col_slice + 1, None) col_slice = slice(*col_slice.indices(self.cols)) return (row_slice, col_slice) def _coord_to_index(i, j): """Return the index in _mat corresponding to the (i,j) position in the matrix. """ return i * self.cols + j if isinstance(key, tuple): i, j = key if isinstance(i, slice) or isinstance(j, slice): # if the coordinates are not slices, make them so # and expand the slices so they don't contain `None` i, j = _normalize_slices(i, j) rowsList, colsList = list(range(self.rows))[i], \ list(range(self.cols))[j] indices = (i * self.cols + j for i in rowsList for j in colsList) return self._new(len(rowsList), len(colsList), list(self.mat[i] for i in indices)) # if the key is a tuple of ints, change # it to an array index key = _coord_to_index(i, j) return self.mat[key] def __eq__(self, other): try: classof(self, other) except TypeError: return False return ( self.shape == other.shape and list(self) == list(other)) def __len__(self): return self.rows*self.cols def __repr__(self): return "_MinimalMatrix({}, {}, {})".format(self.rows, self.cols, self.mat) @property def shape(self): return (self.rows, self.cols) class _CastableMatrix: # this is needed here ONLY FOR TESTS. def as_mutable(self): return self def as_immutable(self): return self class _MatrixWrapper: """Wrapper class providing the minimum functionality for a matrix-like object: .rows, .cols, .shape, indexability, and iterability. CommonMatrix math operations should work on matrix-like objects. This one is intended for matrix-like objects which use the same indexing format as SymPy with respect to returning matrix elements instead of rows for non-tuple indexes. """ is_Matrix = False # needs to be here because of __getattr__ is_MatrixLike = True def __init__(self, mat, shape): self.mat = mat self.shape = shape self.rows, self.cols = shape def __getitem__(self, key): if isinstance(key, tuple): return sympify(self.mat.__getitem__(key)) return sympify(self.mat.__getitem__((key // self.rows, key % self.cols))) def __iter__(self): # supports numpy.matrix and numpy.array mat = self.mat cols = self.cols return iter(sympify(mat[r, c]) for r in range(self.rows) for c in range(cols)) class MatrixKind(Kind): """ Kind for all matrices in SymPy. Basic class for this kind is ``MatrixBase`` and ``MatrixExpr``, but any expression representing the matrix can have this. Parameters ========== element_kind : Kind Kind of the element. Default is :obj:NumberKind ``, which means that the matrix contains only numbers. Examples ======== Any instance of matrix class has ``MatrixKind``. >>> from sympy import MatrixSymbol >>> A = MatrixSymbol('A', 2,2) >>> A.kind MatrixKind(NumberKind) Although expression representing a matrix may be not instance of matrix class, it will have ``MatrixKind`` as well. >>> from sympy import Integral >>> from sympy.matrices.expressions import MatrixExpr >>> from sympy.abc import x >>> intM = Integral(A, x) >>> isinstance(intM, MatrixExpr) False >>> intM.kind MatrixKind(NumberKind) Use ``isinstance()`` to check for ``MatrixKind` without specifying the element kind. Use ``is`` with specifying the element kind. >>> from sympy import Matrix >>> from sympy.matrices import MatrixKind >>> from sympy.core.kind import NumberKind >>> M = Matrix([1, 2]) >>> isinstance(M.kind, MatrixKind) True >>> M.kind is MatrixKind(NumberKind) True See Also ======== shape : Function to return the shape of objects with ``MatrixKind``. """ def __new__(cls, element_kind=NumberKind): obj = super().__new__(cls, element_kind) obj.element_kind = element_kind return obj def __repr__(self): return "MatrixKind(%s)" % self.element_kind def _matrixify(mat): """If `mat` is a Matrix or is matrix-like, return a Matrix or MatrixWrapper object. Otherwise `mat` is passed through without modification.""" if getattr(mat, 'is_Matrix', False) or getattr(mat, 'is_MatrixLike', False): return mat if not(getattr(mat, 'is_Matrix', True) or getattr(mat, 'is_MatrixLike', True)): return mat shape = None if hasattr(mat, 'shape'): # numpy, scipy.sparse if len(mat.shape) == 2: shape = mat.shape elif hasattr(mat, 'rows') and hasattr(mat, 'cols'): # mpmath shape = (mat.rows, mat.cols) if shape: return _MatrixWrapper(mat, shape) return mat def a2idx(j, n=None): """Return integer after making positive and validating against n.""" if type(j) is not int: jindex = getattr(j, '__index__', None) if jindex is not None: j = jindex() else: raise IndexError("Invalid index a[%r]" % (j,)) if n is not None: if j < 0: j += n if not (j >= 0 and j < n): raise IndexError("Index out of range: a[%s]" % (j,)) return int(j) def classof(A, B): """ Get the type of the result when combining matrices of different types. Currently the strategy is that immutability is contagious. Examples ======== >>> from sympy import Matrix, ImmutableMatrix >>> from sympy.matrices.common import classof >>> M = Matrix([[1, 2], [3, 4]]) # a Mutable Matrix >>> IM = ImmutableMatrix([[1, 2], [3, 4]]) >>> classof(M, IM) """ priority_A = getattr(A, '_class_priority', None) priority_B = getattr(B, '_class_priority', None) if None not in (priority_A, priority_B): if A._class_priority > B._class_priority: return A.__class__ else: return B.__class__ try: import numpy except ImportError: pass else: if isinstance(A, numpy.ndarray): return B.__class__ if isinstance(B, numpy.ndarray): return A.__class__ raise TypeError("Incompatible classes %s, %s" % (A.__class__, B.__class__)) sympy-sympy-1.9/sympy/matrices/decompositions.py000066400000000000000000001357341412543434000223410ustar00rootroot00000000000000import copy from sympy.core.function import expand_mul from sympy.functions.elementary.miscellaneous import Min, sqrt from sympy.functions.elementary.complexes import sign from .common import NonSquareMatrixError, NonPositiveDefiniteMatrixError from .utilities import _get_intermediate_simp, _iszero from .determinant import _find_reasonable_pivot_naive def _rank_decomposition(M, iszerofunc=_iszero, simplify=False): r"""Returns a pair of matrices (`C`, `F`) with matching rank such that `A = C F`. Parameters ========== iszerofunc : Function, optional A function used for detecting whether an element can act as a pivot. ``lambda x: x.is_zero`` is used by default. simplify : Bool or Function, optional A function used to simplify elements when looking for a pivot. By default SymPy's ``simplify`` is used. Returns ======= (C, F) : Matrices `C` and `F` are full-rank matrices with rank as same as `A`, whose product gives `A`. See Notes for additional mathematical details. Examples ======== >>> from sympy.matrices import Matrix >>> A = Matrix([ ... [1, 3, 1, 4], ... [2, 7, 3, 9], ... [1, 5, 3, 1], ... [1, 2, 0, 8] ... ]) >>> C, F = A.rank_decomposition() >>> C Matrix([ [1, 3, 4], [2, 7, 9], [1, 5, 1], [1, 2, 8]]) >>> F Matrix([ [1, 0, -2, 0], [0, 1, 1, 0], [0, 0, 0, 1]]) >>> C * F == A True Notes ===== Obtaining `F`, an RREF of `A`, is equivalent to creating a product .. math:: E_n E_{n-1} ... E_1 A = F where `E_n, E_{n-1}, ... , E_1` are the elimination matrices or permutation matrices equivalent to each row-reduction step. The inverse of the same product of elimination matrices gives `C`: .. math:: C = (E_n E_{n-1} ... E_1)^{-1} It is not necessary, however, to actually compute the inverse: the columns of `C` are those from the original matrix with the same column indices as the indices of the pivot columns of `F`. References ========== .. [1] https://en.wikipedia.org/wiki/Rank_factorization .. [2] Piziak, R.; Odell, P. L. (1 June 1999). "Full Rank Factorization of Matrices". Mathematics Magazine. 72 (3): 193. doi:10.2307/2690882 See Also ======== sympy.matrices.matrices.MatrixReductions.rref """ F, pivot_cols = M.rref(simplify=simplify, iszerofunc=iszerofunc, pivots=True) rank = len(pivot_cols) C = M.extract(range(M.rows), pivot_cols) F = F[:rank, :] return C, F def _liupc(M): """Liu's algorithm, for pre-determination of the Elimination Tree of the given matrix, used in row-based symbolic Cholesky factorization. Examples ======== >>> from sympy.matrices import SparseMatrix >>> S = SparseMatrix([ ... [1, 0, 3, 2], ... [0, 0, 1, 0], ... [4, 0, 0, 5], ... [0, 6, 7, 0]]) >>> S.liupc() ([[0], [], [0], [1, 2]], [4, 3, 4, 4]) References ========== Symbolic Sparse Cholesky Factorization using Elimination Trees, Jeroen Van Grondelle (1999) http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582 """ # Algorithm 2.4, p 17 of reference # get the indices of the elements that are non-zero on or below diag R = [[] for r in range(M.rows)] for r, c, _ in M.row_list(): if c <= r: R[r].append(c) inf = len(R) # nothing will be this large parent = [inf]*M.rows virtual = [inf]*M.rows for r in range(M.rows): for c in R[r][:-1]: while virtual[c] < r: t = virtual[c] virtual[c] = r c = t if virtual[c] == inf: parent[c] = virtual[c] = r return R, parent def _row_structure_symbolic_cholesky(M): """Symbolic cholesky factorization, for pre-determination of the non-zero structure of the Cholesky factororization. Examples ======== >>> from sympy.matrices import SparseMatrix >>> S = SparseMatrix([ ... [1, 0, 3, 2], ... [0, 0, 1, 0], ... [4, 0, 0, 5], ... [0, 6, 7, 0]]) >>> S.row_structure_symbolic_cholesky() [[0], [], [0], [1, 2]] References ========== Symbolic Sparse Cholesky Factorization using Elimination Trees, Jeroen Van Grondelle (1999) http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.39.7582 """ R, parent = M.liupc() inf = len(R) # this acts as infinity Lrow = copy.deepcopy(R) for k in range(M.rows): for j in R[k]: while j != inf and j != k: Lrow[k].append(j) j = parent[j] Lrow[k] = list(sorted(set(Lrow[k]))) return Lrow def _cholesky(M, hermitian=True): """Returns the Cholesky-type decomposition L of a matrix A such that L * L.H == A if hermitian flag is True, or L * L.T == A if hermitian is False. A must be a Hermitian positive-definite matrix if hermitian is True, or a symmetric matrix if it is False. Examples ======== >>> from sympy.matrices import Matrix >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) >>> A.cholesky() Matrix([ [ 5, 0, 0], [ 3, 3, 0], [-1, 1, 3]]) >>> A.cholesky() * A.cholesky().T Matrix([ [25, 15, -5], [15, 18, 0], [-5, 0, 11]]) The matrix can have complex entries: >>> from sympy import I >>> A = Matrix(((9, 3*I), (-3*I, 5))) >>> A.cholesky() Matrix([ [ 3, 0], [-I, 2]]) >>> A.cholesky() * A.cholesky().H Matrix([ [ 9, 3*I], [-3*I, 5]]) Non-hermitian Cholesky-type decomposition may be useful when the matrix is not positive-definite. >>> A = Matrix([[1, 2], [2, 1]]) >>> L = A.cholesky(hermitian=False) >>> L Matrix([ [1, 0], [2, sqrt(3)*I]]) >>> L*L.T == A True See Also ======== sympy.matrices.dense.DenseMatrix.LDLdecomposition sympy.matrices.matrices.MatrixBase.LUdecomposition QRdecomposition """ from .dense import MutableDenseMatrix if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if hermitian and not M.is_hermitian: raise ValueError("Matrix must be Hermitian.") if not hermitian and not M.is_symmetric(): raise ValueError("Matrix must be symmetric.") L = MutableDenseMatrix.zeros(M.rows, M.rows) if hermitian: for i in range(M.rows): for j in range(i): L[i, j] = ((1 / L[j, j])*(M[i, j] - sum(L[i, k]*L[j, k].conjugate() for k in range(j)))) Lii2 = (M[i, i] - sum(L[i, k]*L[i, k].conjugate() for k in range(i))) if Lii2.is_positive is False: raise NonPositiveDefiniteMatrixError( "Matrix must be positive-definite") L[i, i] = sqrt(Lii2) else: for i in range(M.rows): for j in range(i): L[i, j] = ((1 / L[j, j])*(M[i, j] - sum(L[i, k]*L[j, k] for k in range(j)))) L[i, i] = sqrt(M[i, i] - sum(L[i, k]**2 for k in range(i))) return M._new(L) def _cholesky_sparse(M, hermitian=True): """ Returns the Cholesky decomposition L of a matrix A such that L * L.T = A A must be a square, symmetric, positive-definite and non-singular matrix Examples ======== >>> from sympy.matrices import SparseMatrix >>> A = SparseMatrix(((25,15,-5),(15,18,0),(-5,0,11))) >>> A.cholesky() Matrix([ [ 5, 0, 0], [ 3, 3, 0], [-1, 1, 3]]) >>> A.cholesky() * A.cholesky().T == A True The matrix can have complex entries: >>> from sympy import I >>> A = SparseMatrix(((9, 3*I), (-3*I, 5))) >>> A.cholesky() Matrix([ [ 3, 0], [-I, 2]]) >>> A.cholesky() * A.cholesky().H Matrix([ [ 9, 3*I], [-3*I, 5]]) Non-hermitian Cholesky-type decomposition may be useful when the matrix is not positive-definite. >>> A = SparseMatrix([[1, 2], [2, 1]]) >>> L = A.cholesky(hermitian=False) >>> L Matrix([ [1, 0], [2, sqrt(3)*I]]) >>> L*L.T == A True See Also ======== sympy.matrices.sparse.SparseMatrix.LDLdecomposition sympy.matrices.matrices.MatrixBase.LUdecomposition QRdecomposition """ from .dense import MutableDenseMatrix if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if hermitian and not M.is_hermitian: raise ValueError("Matrix must be Hermitian.") if not hermitian and not M.is_symmetric(): raise ValueError("Matrix must be symmetric.") dps = _get_intermediate_simp(expand_mul, expand_mul) Crowstruc = M.row_structure_symbolic_cholesky() C = MutableDenseMatrix.zeros(M.rows) for i in range(len(Crowstruc)): for j in Crowstruc[i]: if i != j: C[i, j] = M[i, j] summ = 0 for p1 in Crowstruc[i]: if p1 < j: for p2 in Crowstruc[j]: if p2 < j: if p1 == p2: if hermitian: summ += C[i, p1]*C[j, p1].conjugate() else: summ += C[i, p1]*C[j, p1] else: break else: break C[i, j] = dps((C[i, j] - summ) / C[j, j]) else: # i == j C[j, j] = M[j, j] summ = 0 for k in Crowstruc[j]: if k < j: if hermitian: summ += C[j, k]*C[j, k].conjugate() else: summ += C[j, k]**2 else: break Cjj2 = dps(C[j, j] - summ) if hermitian and Cjj2.is_positive is False: raise NonPositiveDefiniteMatrixError( "Matrix must be positive-definite") C[j, j] = sqrt(Cjj2) return M._new(C) def _LDLdecomposition(M, hermitian=True): """Returns the LDL Decomposition (L, D) of matrix A, such that L * D * L.H == A if hermitian flag is True, or L * D * L.T == A if hermitian is False. This method eliminates the use of square root. Further this ensures that all the diagonal entries of L are 1. A must be a Hermitian positive-definite matrix if hermitian is True, or a symmetric matrix otherwise. Examples ======== >>> from sympy.matrices import Matrix, eye >>> A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) >>> L, D = A.LDLdecomposition() >>> L Matrix([ [ 1, 0, 0], [ 3/5, 1, 0], [-1/5, 1/3, 1]]) >>> D Matrix([ [25, 0, 0], [ 0, 9, 0], [ 0, 0, 9]]) >>> L * D * L.T * A.inv() == eye(A.rows) True The matrix can have complex entries: >>> from sympy import I >>> A = Matrix(((9, 3*I), (-3*I, 5))) >>> L, D = A.LDLdecomposition() >>> L Matrix([ [ 1, 0], [-I/3, 1]]) >>> D Matrix([ [9, 0], [0, 4]]) >>> L*D*L.H == A True See Also ======== sympy.matrices.dense.DenseMatrix.cholesky sympy.matrices.matrices.MatrixBase.LUdecomposition QRdecomposition """ from .dense import MutableDenseMatrix if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if hermitian and not M.is_hermitian: raise ValueError("Matrix must be Hermitian.") if not hermitian and not M.is_symmetric(): raise ValueError("Matrix must be symmetric.") D = MutableDenseMatrix.zeros(M.rows, M.rows) L = MutableDenseMatrix.eye(M.rows) if hermitian: for i in range(M.rows): for j in range(i): L[i, j] = (1 / D[j, j])*(M[i, j] - sum( L[i, k]*L[j, k].conjugate()*D[k, k] for k in range(j))) D[i, i] = (M[i, i] - sum(L[i, k]*L[i, k].conjugate()*D[k, k] for k in range(i))) if D[i, i].is_positive is False: raise NonPositiveDefiniteMatrixError( "Matrix must be positive-definite") else: for i in range(M.rows): for j in range(i): L[i, j] = (1 / D[j, j])*(M[i, j] - sum( L[i, k]*L[j, k]*D[k, k] for k in range(j))) D[i, i] = M[i, i] - sum(L[i, k]**2*D[k, k] for k in range(i)) return M._new(L), M._new(D) def _LDLdecomposition_sparse(M, hermitian=True): """ Returns the LDL Decomposition (matrices ``L`` and ``D``) of matrix ``A``, such that ``L * D * L.T == A``. ``A`` must be a square, symmetric, positive-definite and non-singular. This method eliminates the use of square root and ensures that all the diagonal entries of L are 1. Examples ======== >>> from sympy.matrices import SparseMatrix >>> A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) >>> L, D = A.LDLdecomposition() >>> L Matrix([ [ 1, 0, 0], [ 3/5, 1, 0], [-1/5, 1/3, 1]]) >>> D Matrix([ [25, 0, 0], [ 0, 9, 0], [ 0, 0, 9]]) >>> L * D * L.T == A True """ from .dense import MutableDenseMatrix if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if hermitian and not M.is_hermitian: raise ValueError("Matrix must be Hermitian.") if not hermitian and not M.is_symmetric(): raise ValueError("Matrix must be symmetric.") dps = _get_intermediate_simp(expand_mul, expand_mul) Lrowstruc = M.row_structure_symbolic_cholesky() L = MutableDenseMatrix.eye(M.rows) D = MutableDenseMatrix.zeros(M.rows, M.cols) for i in range(len(Lrowstruc)): for j in Lrowstruc[i]: if i != j: L[i, j] = M[i, j] summ = 0 for p1 in Lrowstruc[i]: if p1 < j: for p2 in Lrowstruc[j]: if p2 < j: if p1 == p2: if hermitian: summ += L[i, p1]*L[j, p1].conjugate()*D[p1, p1] else: summ += L[i, p1]*L[j, p1]*D[p1, p1] else: break else: break L[i, j] = dps((L[i, j] - summ) / D[j, j]) else: # i == j D[i, i] = M[i, i] summ = 0 for k in Lrowstruc[i]: if k < i: if hermitian: summ += L[i, k]*L[i, k].conjugate()*D[k, k] else: summ += L[i, k]**2*D[k, k] else: break D[i, i] = dps(D[i, i] - summ) if hermitian and D[i, i].is_positive is False: raise NonPositiveDefiniteMatrixError( "Matrix must be positive-definite") return M._new(L), M._new(D) def _LUdecomposition(M, iszerofunc=_iszero, simpfunc=None, rankcheck=False): """Returns (L, U, perm) where L is a lower triangular matrix with unit diagonal, U is an upper triangular matrix, and perm is a list of row swap index pairs. If A is the original matrix, then ``A = (L*U).permuteBkwd(perm)``, and the row permutation matrix P such that $P A = L U$ can be computed by ``P = eye(A.rows).permuteFwd(perm)``. See documentation for LUCombined for details about the keyword argument rankcheck, iszerofunc, and simpfunc. Parameters ========== rankcheck : bool, optional Determines if this function should detect the rank deficiency of the matrixis and should raise a ``ValueError``. iszerofunc : function, optional A function which determines if a given expression is zero. The function should be a callable that takes a single sympy expression and returns a 3-valued boolean value ``True``, ``False``, or ``None``. It is internally used by the pivot searching algorithm. See the notes section for a more information about the pivot searching algorithm. simpfunc : function or None, optional A function that simplifies the input. If this is specified as a function, this function should be a callable that takes a single sympy expression and returns an another sympy expression that is algebraically equivalent. If ``None``, it indicates that the pivot search algorithm should not attempt to simplify any candidate pivots. It is internally used by the pivot searching algorithm. See the notes section for a more information about the pivot searching algorithm. Examples ======== >>> from sympy import Matrix >>> a = Matrix([[4, 3], [6, 3]]) >>> L, U, _ = a.LUdecomposition() >>> L Matrix([ [ 1, 0], [3/2, 1]]) >>> U Matrix([ [4, 3], [0, -3/2]]) See Also ======== sympy.matrices.dense.DenseMatrix.cholesky sympy.matrices.dense.DenseMatrix.LDLdecomposition QRdecomposition LUdecomposition_Simple LUdecompositionFF LUsolve """ combined, p = M.LUdecomposition_Simple(iszerofunc=iszerofunc, simpfunc=simpfunc, rankcheck=rankcheck) # L is lower triangular ``M.rows x M.rows`` # U is upper triangular ``M.rows x M.cols`` # L has unit diagonal. For each column in combined, the subcolumn # below the diagonal of combined is shared by L. # If L has more columns than combined, then the remaining subcolumns # below the diagonal of L are zero. # The upper triangular portion of L and combined are equal. def entry_L(i, j): if i < j: # Super diagonal entry return M.zero elif i == j: return M.one elif j < combined.cols: return combined[i, j] # Subdiagonal entry of L with no corresponding # entry in combined return M.zero def entry_U(i, j): return M.zero if i > j else combined[i, j] L = M._new(combined.rows, combined.rows, entry_L) U = M._new(combined.rows, combined.cols, entry_U) return L, U, p def _LUdecomposition_Simple(M, iszerofunc=_iszero, simpfunc=None, rankcheck=False): r"""Compute the PLU decomposition of the matrix. Parameters ========== rankcheck : bool, optional Determines if this function should detect the rank deficiency of the matrixis and should raise a ``ValueError``. iszerofunc : function, optional A function which determines if a given expression is zero. The function should be a callable that takes a single sympy expression and returns a 3-valued boolean value ``True``, ``False``, or ``None``. It is internally used by the pivot searching algorithm. See the notes section for a more information about the pivot searching algorithm. simpfunc : function or None, optional A function that simplifies the input. If this is specified as a function, this function should be a callable that takes a single sympy expression and returns an another sympy expression that is algebraically equivalent. If ``None``, it indicates that the pivot search algorithm should not attempt to simplify any candidate pivots. It is internally used by the pivot searching algorithm. See the notes section for a more information about the pivot searching algorithm. Returns ======= (lu, row_swaps) : (Matrix, list) If the original matrix is a $m, n$ matrix: *lu* is a $m, n$ matrix, which contains result of the decomposition in a compresed form. See the notes section to see how the matrix is compressed. *row_swaps* is a $m$-element list where each element is a pair of row exchange indices. ``A = (L*U).permute_backward(perm)``, and the row permutation matrix $P$ from the formula $P A = L U$ can be computed by ``P=eye(A.row).permute_forward(perm)``. Raises ====== ValueError Raised if ``rankcheck=True`` and the matrix is found to be rank deficient during the computation. Notes ===== About the PLU decomposition: PLU decomposition is a generalization of a LU decomposition which can be extended for rank-deficient matrices. It can further be generalized for non-square matrices, and this is the notation that SymPy is using. PLU decomposition is a decomposition of a $m, n$ matrix $A$ in the form of $P A = L U$ where * $L$ is a $m, m$ lower triangular matrix with unit diagonal entries. * $U$ is a $m, n$ upper triangular matrix. * $P$ is a $m, m$ permutation matrix. So, for a square matrix, the decomposition would look like: .. math:: L = \begin{bmatrix} 1 & 0 & 0 & \cdots & 0 \\ L_{1, 0} & 1 & 0 & \cdots & 0 \\ L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & 1 \end{bmatrix} .. math:: U = \begin{bmatrix} U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ 0 & 0 & U_{2, 2} & \cdots & U_{2, n-1} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & U_{n-1, n-1} \end{bmatrix} And for a matrix with more rows than the columns, the decomposition would look like: .. math:: L = \begin{bmatrix} 1 & 0 & 0 & \cdots & 0 & 0 & \cdots & 0 \\ L_{1, 0} & 1 & 0 & \cdots & 0 & 0 & \cdots & 0 \\ L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 & 0 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & 1 & 0 & \cdots & 0 \\ L_{n, 0} & L_{n, 1} & L_{n, 2} & \cdots & L_{n, n-1} & 1 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots & \vdots & \ddots & \vdots \\ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & L_{m-1, n-1} & 0 & \cdots & 1 \\ \end{bmatrix} .. math:: U = \begin{bmatrix} U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ 0 & 0 & U_{2, 2} & \cdots & U_{2, n-1} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & U_{n-1, n-1} \\ 0 & 0 & 0 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ 0 & 0 & 0 & \cdots & 0 \end{bmatrix} Finally, for a matrix with more columns than the rows, the decomposition would look like: .. math:: L = \begin{bmatrix} 1 & 0 & 0 & \cdots & 0 \\ L_{1, 0} & 1 & 0 & \cdots & 0 \\ L_{2, 0} & L_{2, 1} & 1 & \cdots & 0 \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & 1 \end{bmatrix} .. math:: U = \begin{bmatrix} U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, m-1} & \cdots & U_{0, n-1} \\ 0 & U_{1, 1} & U_{1, 2} & \cdots & U_{1, m-1} & \cdots & U_{1, n-1} \\ 0 & 0 & U_{2, 2} & \cdots & U_{2, m-1} & \cdots & U_{2, n-1} \\ \vdots & \vdots & \vdots & \ddots & \vdots & \cdots & \vdots \\ 0 & 0 & 0 & \cdots & U_{m-1, m-1} & \cdots & U_{m-1, n-1} \\ \end{bmatrix} About the compressed LU storage: The results of the decomposition are often stored in compressed forms rather than returning $L$ and $U$ matrices individually. It may be less intiuitive, but it is commonly used for a lot of numeric libraries because of the efficiency. The storage matrix is defined as following for this specific method: * The subdiagonal elements of $L$ are stored in the subdiagonal portion of $LU$, that is $LU_{i, j} = L_{i, j}$ whenever $i > j$. * The elements on the diagonal of $L$ are all 1, and are not explicitly stored. * $U$ is stored in the upper triangular portion of $LU$, that is $LU_{i, j} = U_{i, j}$ whenever $i <= j$. * For a case of $m > n$, the right side of the $L$ matrix is trivial to store. * For a case of $m < n$, the below side of the $U$ matrix is trivial to store. So, for a square matrix, the compressed output matrix would be: .. math:: LU = \begin{bmatrix} U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, n-1} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & U_{n-1, n-1} \end{bmatrix} For a matrix with more rows than the columns, the compressed output matrix would be: .. math:: LU = \begin{bmatrix} U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, n-1} \\ L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, n-1} \\ L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, n-1} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ L_{n-1, 0} & L_{n-1, 1} & L_{n-1, 2} & \cdots & U_{n-1, n-1} \\ \vdots & \vdots & \vdots & \ddots & \vdots \\ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & L_{m-1, n-1} \\ \end{bmatrix} For a matrix with more columns than the rows, the compressed output matrix would be: .. math:: LU = \begin{bmatrix} U_{0, 0} & U_{0, 1} & U_{0, 2} & \cdots & U_{0, m-1} & \cdots & U_{0, n-1} \\ L_{1, 0} & U_{1, 1} & U_{1, 2} & \cdots & U_{1, m-1} & \cdots & U_{1, n-1} \\ L_{2, 0} & L_{2, 1} & U_{2, 2} & \cdots & U_{2, m-1} & \cdots & U_{2, n-1} \\ \vdots & \vdots & \vdots & \ddots & \vdots & \cdots & \vdots \\ L_{m-1, 0} & L_{m-1, 1} & L_{m-1, 2} & \cdots & U_{m-1, m-1} & \cdots & U_{m-1, n-1} \\ \end{bmatrix} About the pivot searching algorithm: When a matrix contains symbolic entries, the pivot search algorithm differs from the case where every entry can be categorized as zero or nonzero. The algorithm searches column by column through the submatrix whose top left entry coincides with the pivot position. If it exists, the pivot is the first entry in the current search column that iszerofunc guarantees is nonzero. If no such candidate exists, then each candidate pivot is simplified if simpfunc is not None. The search is repeated, with the difference that a candidate may be the pivot if ``iszerofunc()`` cannot guarantee that it is nonzero. In the second search the pivot is the first candidate that iszerofunc can guarantee is nonzero. If no such candidate exists, then the pivot is the first candidate for which iszerofunc returns None. If no such candidate exists, then the search is repeated in the next column to the right. The pivot search algorithm differs from the one in ``rref()``, which relies on ``_find_reasonable_pivot()``. Future versions of ``LUdecomposition_simple()`` may use ``_find_reasonable_pivot()``. See Also ======== sympy.matrices.matrices.MatrixBase.LUdecomposition LUdecompositionFF LUsolve """ if rankcheck: # https://github.com/sympy/sympy/issues/9796 pass if M.rows == 0 or M.cols == 0: # Define LU decomposition of a matrix with no entries as a matrix # of the same dimensions with all zero entries. return M.zeros(M.rows, M.cols), [] dps = _get_intermediate_simp() lu = M.as_mutable() row_swaps = [] pivot_col = 0 for pivot_row in range(0, lu.rows - 1): # Search for pivot. Prefer entry that iszeropivot determines # is nonzero, over entry that iszeropivot cannot guarantee # is zero. # XXX ``_find_reasonable_pivot`` uses slow zero testing. Blocked by bug #10279 # Future versions of LUdecomposition_simple can pass iszerofunc and simpfunc # to _find_reasonable_pivot(). # In pass 3 of _find_reasonable_pivot(), the predicate in ``if x.equals(S.Zero):`` # calls sympy.simplify(), and not the simplification function passed in via # the keyword argument simpfunc. iszeropivot = True while pivot_col != M.cols and iszeropivot: sub_col = (lu[r, pivot_col] for r in range(pivot_row, M.rows)) pivot_row_offset, pivot_value, is_assumed_non_zero, ind_simplified_pairs =\ _find_reasonable_pivot_naive(sub_col, iszerofunc, simpfunc) iszeropivot = pivot_value is None if iszeropivot: # All candidate pivots in this column are zero. # Proceed to next column. pivot_col += 1 if rankcheck and pivot_col != pivot_row: # All entries including and below the pivot position are # zero, which indicates that the rank of the matrix is # strictly less than min(num rows, num cols) # Mimic behavior of previous implementation, by throwing a # ValueError. raise ValueError("Rank of matrix is strictly less than" " number of rows or columns." " Pass keyword argument" " rankcheck=False to compute" " the LU decomposition of this matrix.") candidate_pivot_row = None if pivot_row_offset is None else pivot_row + pivot_row_offset if candidate_pivot_row is None and iszeropivot: # If candidate_pivot_row is None and iszeropivot is True # after pivot search has completed, then the submatrix # below and to the right of (pivot_row, pivot_col) is # all zeros, indicating that Gaussian elimination is # complete. return lu, row_swaps # Update entries simplified during pivot search. for offset, val in ind_simplified_pairs: lu[pivot_row + offset, pivot_col] = val if pivot_row != candidate_pivot_row: # Row swap book keeping: # Record which rows were swapped. # Update stored portion of L factor by multiplying L on the # left and right with the current permutation. # Swap rows of U. row_swaps.append([pivot_row, candidate_pivot_row]) # Update L. lu[pivot_row, 0:pivot_row], lu[candidate_pivot_row, 0:pivot_row] = \ lu[candidate_pivot_row, 0:pivot_row], lu[pivot_row, 0:pivot_row] # Swap pivot row of U with candidate pivot row. lu[pivot_row, pivot_col:lu.cols], lu[candidate_pivot_row, pivot_col:lu.cols] = \ lu[candidate_pivot_row, pivot_col:lu.cols], lu[pivot_row, pivot_col:lu.cols] # Introduce zeros below the pivot by adding a multiple of the # pivot row to a row under it, and store the result in the # row under it. # Only entries in the target row whose index is greater than # start_col may be nonzero. start_col = pivot_col + 1 for row in range(pivot_row + 1, lu.rows): # Store factors of L in the subcolumn below # (pivot_row, pivot_row). lu[row, pivot_row] = \ dps(lu[row, pivot_col]/lu[pivot_row, pivot_col]) # Form the linear combination of the pivot row and the current # row below the pivot row that zeros the entries below the pivot. # Employing slicing instead of a loop here raises # NotImplementedError: Cannot add Zero to MutableSparseMatrix # in sympy/matrices/tests/test_sparse.py. # c = pivot_row + 1 if pivot_row == pivot_col else pivot_col for c in range(start_col, lu.cols): lu[row, c] = dps(lu[row, c] - lu[row, pivot_row]*lu[pivot_row, c]) if pivot_row != pivot_col: # matrix rank < min(num rows, num cols), # so factors of L are not stored directly below the pivot. # These entries are zero by construction, so don't bother # computing them. for row in range(pivot_row + 1, lu.rows): lu[row, pivot_col] = M.zero pivot_col += 1 if pivot_col == lu.cols: # All candidate pivots are zero implies that Gaussian # elimination is complete. return lu, row_swaps if rankcheck: if iszerofunc( lu[Min(lu.rows, lu.cols) - 1, Min(lu.rows, lu.cols) - 1]): raise ValueError("Rank of matrix is strictly less than" " number of rows or columns." " Pass keyword argument" " rankcheck=False to compute" " the LU decomposition of this matrix.") return lu, row_swaps def _LUdecompositionFF(M): """Compute a fraction-free LU decomposition. Returns 4 matrices P, L, D, U such that PA = L D**-1 U. If the elements of the matrix belong to some integral domain I, then all elements of L, D and U are guaranteed to belong to I. See Also ======== sympy.matrices.matrices.MatrixBase.LUdecomposition LUdecomposition_Simple LUsolve References ========== .. [1] W. Zhou & D.J. Jeffrey, "Fraction-free matrix factors: new forms for LU and QR factors". Frontiers in Computer Science in China, Vol 2, no. 1, pp. 67-80, 2008. """ from sympy.matrices import SparseMatrix zeros = SparseMatrix.zeros eye = SparseMatrix.eye n, m = M.rows, M.cols U, L, P = M.as_mutable(), eye(n), eye(n) DD = zeros(n, n) oldpivot = 1 for k in range(n - 1): if U[k, k] == 0: for kpivot in range(k + 1, n): if U[kpivot, k]: break else: raise ValueError("Matrix is not full rank") U[k, k:], U[kpivot, k:] = U[kpivot, k:], U[k, k:] L[k, :k], L[kpivot, :k] = L[kpivot, :k], L[k, :k] P[k, :], P[kpivot, :] = P[kpivot, :], P[k, :] L [k, k] = Ukk = U[k, k] DD[k, k] = oldpivot * Ukk for i in range(k + 1, n): L[i, k] = Uik = U[i, k] for j in range(k + 1, m): U[i, j] = (Ukk * U[i, j] - U[k, j] * Uik) / oldpivot U[i, k] = 0 oldpivot = Ukk DD[n - 1, n - 1] = oldpivot return P, L, DD, U def _singular_value_decomposition(A): r"""Returns a Condensed Singular Value decomposition. Explanation =========== A Singular Value decomposition is a decomposition in the form $A = U \Sigma V$ where - $U, V$ are column orthogonal matrix. - $\Sigma$ is a diagonal matrix, where the main diagonal contains singular values of matrix A. A column orthogonal matrix satisfies $\mathbb{I} = U^H U$ while a full orthogonal matrix satisfies relation $\mathbb{I} = U U^H = U^H U$ where $\mathbb{I}$ is an identity matrix with matching dimensions. For matrices which are not square or are rank-deficient, it is sufficient to return a column orthogonal matrix because augmenting them may introduce redundant computations. In condensed Singular Value Decomposition we only return column orthognal matrices because of this reason If you want to augment the results to return a full orthogonal decomposition, you should use the following procedures. - Augment the $U , V$ matrices with columns that are orthogonal to every other columns and make it square. - Augument the $\Sigma$ matrix with zero rows to make it have the same shape as the original matrix. The procedure will be illustrated in the examples section. Examples ======== we take a full rank matrix first: >>> from sympy import Matrix >>> A = Matrix([[1, 2],[2,1]]) >>> U, S, V = A.singular_value_decomposition() >>> U Matrix([ [ sqrt(2)/2, sqrt(2)/2], [-sqrt(2)/2, sqrt(2)/2]]) >>> S Matrix([ [1, 0], [0, 3]]) >>> V Matrix([ [-sqrt(2)/2, sqrt(2)/2], [ sqrt(2)/2, sqrt(2)/2]]) If a matrix if square and full rank both U, V are orthogonal in both directions >>> U * U.H Matrix([ [1, 0], [0, 1]]) >>> U.H * U Matrix([ [1, 0], [0, 1]]) >>> V * V.H Matrix([ [1, 0], [0, 1]]) >>> V.H * V Matrix([ [1, 0], [0, 1]]) >>> A == U * S * V.H True >>> C = Matrix([ ... [1, 0, 0, 0, 2], ... [0, 0, 3, 0, 0], ... [0, 0, 0, 0, 0], ... [0, 2, 0, 0, 0], ... ]) >>> U, S, V = C.singular_value_decomposition() >>> V.H * V Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> V * V.H Matrix([ [1/5, 0, 0, 0, 2/5], [ 0, 1, 0, 0, 0], [ 0, 0, 1, 0, 0], [ 0, 0, 0, 0, 0], [2/5, 0, 0, 0, 4/5]]) If you want to augment the results to be a full orthogonal decomposition, you should augment $V$ with an another orthogonal column. You are able to append an arbitrary standard basis that are linearly independent to every other columns and you can run the Gram-Schmidt process to make them augmented as orthogonal basis. >>> V_aug = V.row_join(Matrix([[0,0,0,0,1], ... [0,0,0,1,0]]).H) >>> V_aug = V_aug.QRdecomposition()[0] >>> V_aug Matrix([ [0, sqrt(5)/5, 0, -2*sqrt(5)/5, 0], [1, 0, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 0, 1], [0, 2*sqrt(5)/5, 0, sqrt(5)/5, 0]]) >>> V_aug.H * V_aug Matrix([ [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]) >>> V_aug * V_aug.H Matrix([ [1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0], [0, 0, 0, 0, 1]]) Similarly we augment U >>> U_aug = U.row_join(Matrix([0,0,1,0])) >>> U_aug = U_aug.QRdecomposition()[0] >>> U_aug Matrix([ [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1], [1, 0, 0, 0]]) >>> U_aug.H * U_aug Matrix([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) >>> U_aug * U_aug.H Matrix([ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) We add 2 zero columns and one row to S >>> S_aug = S.col_join(Matrix([[0,0,0]])) >>> S_aug = S_aug.row_join(Matrix([[0,0,0,0], ... [0,0,0,0]]).H) >>> S_aug Matrix([ [2, 0, 0, 0, 0], [0, sqrt(5), 0, 0, 0], [0, 0, 3, 0, 0], [0, 0, 0, 0, 0]]) >>> U_aug * S_aug * V_aug.H == C True """ AH = A.H m, n = A.shape if m >= n: V, S = (AH * A).diagonalize() ranked = [] for i, x in enumerate(S.diagonal()): if not x.is_zero: ranked.append(i) V = V[:, ranked] Singular_vals = [sqrt(S[i, i]) for i in range(S.rows) if i in ranked] S = S.zeros(len(Singular_vals)) for i in range(len(Singular_vals)): S[i, i] = Singular_vals[i] V, _ = V.QRdecomposition() U = A * V * S.inv() else: U, S = (A * AH).diagonalize() ranked = [] for i, x in enumerate(S.diagonal()): if not x.is_zero: ranked.append(i) U = U[:, ranked] Singular_vals = [sqrt(S[i, i]) for i in range(S.rows) if i in ranked] S = S.zeros(len(Singular_vals)) for i in range(len(Singular_vals)): S[i, i] = Singular_vals[i] U, _ = U.QRdecomposition() V = AH * U * S.inv() return U, S, V def _QRdecomposition_optional(M, normalize=True): def dot(u, v): return u.dot(v, hermitian=True) dps = _get_intermediate_simp(expand_mul, expand_mul) A = M.as_mutable() ranked = list() Q = A R = A.zeros(A.cols) for j in range(A.cols): for i in range(j): if Q[:, i].is_zero_matrix: continue R[i, j] = dot(Q[:, i], Q[:, j]) / dot(Q[:, i], Q[:, i]) R[i, j] = dps(R[i, j]) Q[:, j] -= Q[:, i] * R[i, j] Q[:, j] = dps(Q[:, j]) if Q[:, j].is_zero_matrix is False: ranked.append(j) R[j, j] = M.one Q = Q.extract(range(Q.rows), ranked) R = R.extract(ranked, range(R.cols)) if normalize: # Normalization for i in range(Q.cols): norm = Q[:, i].norm() Q[:, i] /= norm R[i, :] *= norm return M.__class__(Q), M.__class__(R) def _QRdecomposition(M): r"""Returns a QR decomposition. Explanation =========== A QR decomposition is a decomposition in the form $A = Q R$ where - $Q$ is a column orthogonal matrix. - $R$ is a upper triangular (trapezoidal) matrix. A column orthogonal matrix satisfies $\mathbb{I} = Q^H Q$ while a full orthogonal matrix satisfies relation $\mathbb{I} = Q Q^H = Q^H Q$ where $I$ is an identity matrix with matching dimensions. For matrices which are not square or are rank-deficient, it is sufficient to return a column orthogonal matrix because augmenting them may introduce redundant computations. And an another advantage of this is that you can easily inspect the matrix rank by counting the number of columns of $Q$. If you want to augment the results to return a full orthogonal decomposition, you should use the following procedures. - Augment the $Q$ matrix with columns that are orthogonal to every other columns and make it square. - Augument the $R$ matrix with zero rows to make it have the same shape as the original matrix. The procedure will be illustrated in the examples section. Examples ======== A full rank matrix example: >>> from sympy import Matrix >>> A = Matrix([[12, -51, 4], [6, 167, -68], [-4, 24, -41]]) >>> Q, R = A.QRdecomposition() >>> Q Matrix([ [ 6/7, -69/175, -58/175], [ 3/7, 158/175, 6/175], [-2/7, 6/35, -33/35]]) >>> R Matrix([ [14, 21, -14], [ 0, 175, -70], [ 0, 0, 35]]) If the matrix is square and full rank, the $Q$ matrix becomes orthogonal in both directions, and needs no augmentation. >>> Q * Q.H Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> Q.H * Q Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> A == Q*R True A rank deficient matrix example: >>> A = Matrix([[12, -51, 0], [6, 167, 0], [-4, 24, 0]]) >>> Q, R = A.QRdecomposition() >>> Q Matrix([ [ 6/7, -69/175], [ 3/7, 158/175], [-2/7, 6/35]]) >>> R Matrix([ [14, 21, 0], [ 0, 175, 0]]) QRdecomposition might return a matrix Q that is rectangular. In this case the orthogonality condition might be satisfied as $\mathbb{I} = Q.H*Q$ but not in the reversed product $\mathbb{I} = Q * Q.H$. >>> Q.H * Q Matrix([ [1, 0], [0, 1]]) >>> Q * Q.H Matrix([ [27261/30625, 348/30625, -1914/6125], [ 348/30625, 30589/30625, 198/6125], [ -1914/6125, 198/6125, 136/1225]]) If you want to augment the results to be a full orthogonal decomposition, you should augment $Q$ with an another orthogonal column. You are able to append an arbitrary standard basis that are linearly independent to every other columns and you can run the Gram-Schmidt process to make them augmented as orthogonal basis. >>> Q_aug = Q.row_join(Matrix([0, 0, 1])) >>> Q_aug = Q_aug.QRdecomposition()[0] >>> Q_aug Matrix([ [ 6/7, -69/175, 58/175], [ 3/7, 158/175, -6/175], [-2/7, 6/35, 33/35]]) >>> Q_aug.H * Q_aug Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> Q_aug * Q_aug.H Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) Augmenting the $R$ matrix with zero row is straightforward. >>> R_aug = R.col_join(Matrix([[0, 0, 0]])) >>> R_aug Matrix([ [14, 21, 0], [ 0, 175, 0], [ 0, 0, 0]]) >>> Q_aug * R_aug == A True A zero matrix example: >>> from sympy import Matrix >>> A = Matrix.zeros(3, 4) >>> Q, R = A.QRdecomposition() They may return matrices with zero rows and columns. >>> Q Matrix(3, 0, []) >>> R Matrix(0, 4, []) >>> Q*R Matrix([ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) As the same augmentation rule described above, $Q$ can be augmented with columns of an identity matrix and $R$ can be augmented with rows of a zero matrix. >>> Q_aug = Q.row_join(Matrix.eye(3)) >>> R_aug = R.col_join(Matrix.zeros(3, 4)) >>> Q_aug * Q_aug.T Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> R_aug Matrix([ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) >>> Q_aug * R_aug == A True See Also ======== sympy.matrices.dense.DenseMatrix.cholesky sympy.matrices.dense.DenseMatrix.LDLdecomposition sympy.matrices.matrices.MatrixBase.LUdecomposition QRsolve """ return _QRdecomposition_optional(M, normalize=True) def _upper_hessenberg_decomposition(A): """Converts a matrix into Hessenberg matrix H Returns 2 matrices H, P s.t. $P H P^{T} = A$, where H is an upper hessenberg matrix and P is an orthogonal matrix Examples ======== >>> from sympy import Matrix >>> A = Matrix([ ... [1,2,3], ... [-3,5,6], ... [4,-8,9], ... ]) >>> H, P = A.upper_hessenberg_decomposition() >>> H Matrix([ [1, 6/5, 17/5], [5, 213/25, -134/25], [0, 216/25, 137/25]]) >>> P Matrix([ [1, 0, 0], [0, -3/5, 4/5], [0, 4/5, 3/5]]) >>> P * H * P.H == A True References ========== .. [#] https://mathworld.wolfram.com/HessenbergDecomposition.html """ M = A.as_mutable() if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") n = M.cols P = M.eye(n) H = M for j in range(n - 2): u = H[j + 1:, j] if u[1:, :].is_zero_matrix: continue if sign(u[0]) != 0: u[0] = u[0] + sign(u[0]) * u.norm() else: u[0] = u[0] + u.norm() v = u / u.norm() H[j + 1:, :] = H[j + 1:, :] - 2 * v * (v.H * H[j + 1:, :]) H[:, j + 1:] = H[:, j + 1:] - (H[:, j + 1:] * (2 * v)) * v.H P[:, j + 1:] = P[:, j + 1:] - (P[:, j + 1:] * (2 * v)) * v.H return H, P sympy-sympy-1.9/sympy/matrices/dense.py000066400000000000000000000474601412543434000203760ustar00rootroot00000000000000import random from sympy.core.basic import Basic from sympy.core.compatibility import is_sequence from sympy.core.symbol import Symbol from sympy.core.sympify import sympify from sympy.functions.elementary.trigonometric import cos, sin from sympy.simplify.simplify import simplify as _simplify from sympy.utilities.decorator import doctest_depends_on from sympy.utilities.exceptions import SymPyDeprecationWarning from .common import ShapeError from .decompositions import _cholesky, _LDLdecomposition from .matrices import MatrixBase from .repmatrix import MutableRepMatrix, RepMatrix from .solvers import _lower_triangular_solve, _upper_triangular_solve def _iszero(x): """Returns True if x is zero.""" return x.is_zero class DenseMatrix(RepMatrix): """Matrix implementation based on DomainMatrix as the internal representation""" # # DenseMatrix is a superclass for both MutableDenseMatrix and # ImmutableDenseMatrix. Methods shared by both classes but not for the # Sparse classes should be implemented here. # is_MatrixExpr = False # type: bool _op_priority = 10.01 _class_priority = 4 @property def _mat(self): SymPyDeprecationWarning( feature="The private _mat attribute of Matrix", useinstead="the .flat() method", issue=21715, deprecated_since_version="1.9").warn() return self.flat() def _eval_inverse(self, **kwargs): return self.inv(method=kwargs.get('method', 'GE'), iszerofunc=kwargs.get('iszerofunc', _iszero), try_block_diag=kwargs.get('try_block_diag', False)) def as_immutable(self): """Returns an Immutable version of this Matrix """ from .immutable import ImmutableDenseMatrix as cls return cls._fromrep(self._rep.copy()) def as_mutable(self): """Returns a mutable version of this matrix Examples ======== >>> from sympy import ImmutableMatrix >>> X = ImmutableMatrix([[1, 2], [3, 4]]) >>> Y = X.as_mutable() >>> Y[1, 1] = 5 # Can set values in Y >>> Y Matrix([ [1, 2], [3, 5]]) """ return Matrix(self) def cholesky(self, hermitian=True): return _cholesky(self, hermitian=hermitian) def LDLdecomposition(self, hermitian=True): return _LDLdecomposition(self, hermitian=hermitian) def lower_triangular_solve(self, rhs): return _lower_triangular_solve(self, rhs) def upper_triangular_solve(self, rhs): return _upper_triangular_solve(self, rhs) cholesky.__doc__ = _cholesky.__doc__ LDLdecomposition.__doc__ = _LDLdecomposition.__doc__ lower_triangular_solve.__doc__ = _lower_triangular_solve.__doc__ upper_triangular_solve.__doc__ = _upper_triangular_solve.__doc__ def _force_mutable(x): """Return a matrix as a Matrix, otherwise return x.""" if getattr(x, 'is_Matrix', False): return x.as_mutable() elif isinstance(x, Basic): return x elif hasattr(x, '__array__'): a = x.__array__() if len(a.shape) == 0: return sympify(a) return Matrix(x) return x class MutableDenseMatrix(DenseMatrix, MutableRepMatrix): def simplify(self, **kwargs): """Applies simplify to the elements of a matrix in place. This is a shortcut for M.applyfunc(lambda x: simplify(x, ratio, measure)) See Also ======== sympy.simplify.simplify.simplify """ for (i, j), element in self.todok().items(): self[i, j] = _simplify(element, **kwargs) MutableMatrix = Matrix = MutableDenseMatrix ########### # Numpy Utility Functions: # list2numpy, matrix2numpy, symmarray, rot_axis[123] ########### def list2numpy(l, dtype=object): # pragma: no cover """Converts python list of SymPy expressions to a NumPy array. See Also ======== matrix2numpy """ from numpy import empty a = empty(len(l), dtype) for i, s in enumerate(l): a[i] = s return a def matrix2numpy(m, dtype=object): # pragma: no cover """Converts SymPy's matrix to a NumPy array. See Also ======== list2numpy """ from numpy import empty a = empty(m.shape, dtype) for i in range(m.rows): for j in range(m.cols): a[i, j] = m[i, j] return a def rot_axis3(theta): """Returns a rotation matrix for a rotation of theta (in radians) about the 3-axis. Examples ======== >>> from sympy import pi >>> from sympy.matrices import rot_axis3 A rotation of pi/3 (60 degrees): >>> theta = pi/3 >>> rot_axis3(theta) Matrix([ [ 1/2, sqrt(3)/2, 0], [-sqrt(3)/2, 1/2, 0], [ 0, 0, 1]]) If we rotate by pi/2 (90 degrees): >>> rot_axis3(pi/2) Matrix([ [ 0, 1, 0], [-1, 0, 0], [ 0, 0, 1]]) See Also ======== rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) about the 1-axis rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) about the 2-axis """ ct = cos(theta) st = sin(theta) lil = ((ct, st, 0), (-st, ct, 0), (0, 0, 1)) return Matrix(lil) def rot_axis2(theta): """Returns a rotation matrix for a rotation of theta (in radians) about the 2-axis. Examples ======== >>> from sympy import pi >>> from sympy.matrices import rot_axis2 A rotation of pi/3 (60 degrees): >>> theta = pi/3 >>> rot_axis2(theta) Matrix([ [ 1/2, 0, -sqrt(3)/2], [ 0, 1, 0], [sqrt(3)/2, 0, 1/2]]) If we rotate by pi/2 (90 degrees): >>> rot_axis2(pi/2) Matrix([ [0, 0, -1], [0, 1, 0], [1, 0, 0]]) See Also ======== rot_axis1: Returns a rotation matrix for a rotation of theta (in radians) about the 1-axis rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) about the 3-axis """ ct = cos(theta) st = sin(theta) lil = ((ct, 0, -st), (0, 1, 0), (st, 0, ct)) return Matrix(lil) def rot_axis1(theta): """Returns a rotation matrix for a rotation of theta (in radians) about the 1-axis. Examples ======== >>> from sympy import pi >>> from sympy.matrices import rot_axis1 A rotation of pi/3 (60 degrees): >>> theta = pi/3 >>> rot_axis1(theta) Matrix([ [1, 0, 0], [0, 1/2, sqrt(3)/2], [0, -sqrt(3)/2, 1/2]]) If we rotate by pi/2 (90 degrees): >>> rot_axis1(pi/2) Matrix([ [1, 0, 0], [0, 0, 1], [0, -1, 0]]) See Also ======== rot_axis2: Returns a rotation matrix for a rotation of theta (in radians) about the 2-axis rot_axis3: Returns a rotation matrix for a rotation of theta (in radians) about the 3-axis """ ct = cos(theta) st = sin(theta) lil = ((1, 0, 0), (0, ct, st), (0, -st, ct)) return Matrix(lil) @doctest_depends_on(modules=('numpy',)) def symarray(prefix, shape, **kwargs): # pragma: no cover r"""Create a numpy ndarray of symbols (as an object array). The created symbols are named ``prefix_i1_i2_``... You should thus provide a non-empty prefix if you want your symbols to be unique for different output arrays, as SymPy symbols with identical names are the same object. Parameters ---------- prefix : string A prefix prepended to the name of every symbol. shape : int or tuple Shape of the created array. If an int, the array is one-dimensional; for more than one dimension the shape must be a tuple. \*\*kwargs : dict keyword arguments passed on to Symbol Examples ======== These doctests require numpy. >>> from sympy import symarray >>> symarray('', 3) [_0 _1 _2] If you want multiple symarrays to contain distinct symbols, you *must* provide unique prefixes: >>> a = symarray('', 3) >>> b = symarray('', 3) >>> a[0] == b[0] True >>> a = symarray('a', 3) >>> b = symarray('b', 3) >>> a[0] == b[0] False Creating symarrays with a prefix: >>> symarray('a', 3) [a_0 a_1 a_2] For more than one dimension, the shape must be given as a tuple: >>> symarray('a', (2, 3)) [[a_0_0 a_0_1 a_0_2] [a_1_0 a_1_1 a_1_2]] >>> symarray('a', (2, 3, 2)) [[[a_0_0_0 a_0_0_1] [a_0_1_0 a_0_1_1] [a_0_2_0 a_0_2_1]] [[a_1_0_0 a_1_0_1] [a_1_1_0 a_1_1_1] [a_1_2_0 a_1_2_1]]] For setting assumptions of the underlying Symbols: >>> [s.is_real for s in symarray('a', 2, real=True)] [True, True] """ from numpy import empty, ndindex arr = empty(shape, dtype=object) for index in ndindex(shape): arr[index] = Symbol('%s_%s' % (prefix, '_'.join(map(str, index))), **kwargs) return arr ############### # Functions ############### def casoratian(seqs, n, zero=True): """Given linear difference operator L of order 'k' and homogeneous equation Ly = 0 we want to compute kernel of L, which is a set of 'k' sequences: a(n), b(n), ... z(n). Solutions of L are linearly independent iff their Casoratian, denoted as C(a, b, ..., z), do not vanish for n = 0. Casoratian is defined by k x k determinant:: + a(n) b(n) . . . z(n) + | a(n+1) b(n+1) . . . z(n+1) | | . . . . | | . . . . | | . . . . | + a(n+k-1) b(n+k-1) . . . z(n+k-1) + It proves very useful in rsolve_hyper() where it is applied to a generating set of a recurrence to factor out linearly dependent solutions and return a basis: >>> from sympy import Symbol, casoratian, factorial >>> n = Symbol('n', integer=True) Exponential and factorial are linearly independent: >>> casoratian([2**n, factorial(n)], n) != 0 True """ seqs = list(map(sympify, seqs)) if not zero: f = lambda i, j: seqs[j].subs(n, n + i) else: f = lambda i, j: seqs[j].subs(n, i) k = len(seqs) return Matrix(k, k, f).det() def eye(*args, **kwargs): """Create square identity matrix n x n See Also ======== diag zeros ones """ return Matrix.eye(*args, **kwargs) def diag(*values, strict=True, unpack=False, **kwargs): """Returns a matrix with the provided values placed on the diagonal. If non-square matrices are included, they will produce a block-diagonal matrix. Examples ======== This version of diag is a thin wrapper to Matrix.diag that differs in that it treats all lists like matrices -- even when a single list is given. If this is not desired, either put a `*` before the list or set `unpack=True`. >>> from sympy import diag >>> diag([1, 2, 3], unpack=True) # = diag(1,2,3) or diag(*[1,2,3]) Matrix([ [1, 0, 0], [0, 2, 0], [0, 0, 3]]) >>> diag([1, 2, 3]) # a column vector Matrix([ [1], [2], [3]]) See Also ======== .common.MatrixCommon.eye .common.MatrixCommon.diagonal - to extract a diagonal .common.MatrixCommon.diag .expressions.blockmatrix.BlockMatrix """ return Matrix.diag(*values, strict=strict, unpack=unpack, **kwargs) def GramSchmidt(vlist, orthonormal=False): """Apply the Gram-Schmidt process to a set of vectors. Parameters ========== vlist : List of Matrix Vectors to be orthogonalized for. orthonormal : Bool, optional If true, return an orthonormal basis. Returns ======= vlist : List of Matrix Orthogonalized vectors Notes ===== This routine is mostly duplicate from ``Matrix.orthogonalize``, except for some difference that this always raises error when linearly dependent vectors are found, and the keyword ``normalize`` has been named as ``orthonormal`` in this function. See Also ======== .matrices.MatrixSubspaces.orthogonalize References ========== .. [1] https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process """ return MutableDenseMatrix.orthogonalize( *vlist, normalize=orthonormal, rankcheck=True ) def hessian(f, varlist, constraints=[]): """Compute Hessian matrix for a function f wrt parameters in varlist which may be given as a sequence or a row/column vector. A list of constraints may optionally be given. Examples ======== >>> from sympy import Function, hessian, pprint >>> from sympy.abc import x, y >>> f = Function('f')(x, y) >>> g1 = Function('g')(x, y) >>> g2 = x**2 + 3*y >>> pprint(hessian(f, (x, y), [g1, g2])) [ d d ] [ 0 0 --(g(x, y)) --(g(x, y)) ] [ dx dy ] [ ] [ 0 0 2*x 3 ] [ ] [ 2 2 ] [d d d ] [--(g(x, y)) 2*x ---(f(x, y)) -----(f(x, y))] [dx 2 dy dx ] [ dx ] [ ] [ 2 2 ] [d d d ] [--(g(x, y)) 3 -----(f(x, y)) ---(f(x, y)) ] [dy dy dx 2 ] [ dy ] References ========== https://en.wikipedia.org/wiki/Hessian_matrix See Also ======== sympy.matrices.matrices.MatrixCalculus.jacobian wronskian """ # f is the expression representing a function f, return regular matrix if isinstance(varlist, MatrixBase): if 1 not in varlist.shape: raise ShapeError("`varlist` must be a column or row vector.") if varlist.cols == 1: varlist = varlist.T varlist = varlist.tolist()[0] if is_sequence(varlist): n = len(varlist) if not n: raise ShapeError("`len(varlist)` must not be zero.") else: raise ValueError("Improper variable list in hessian function") if not getattr(f, 'diff'): # check differentiability raise ValueError("Function `f` (%s) is not differentiable" % f) m = len(constraints) N = m + n out = zeros(N) for k, g in enumerate(constraints): if not getattr(g, 'diff'): # check differentiability raise ValueError("Function `f` (%s) is not differentiable" % f) for i in range(n): out[k, i + m] = g.diff(varlist[i]) for i in range(n): for j in range(i, n): out[i + m, j + m] = f.diff(varlist[i]).diff(varlist[j]) for i in range(N): for j in range(i + 1, N): out[j, i] = out[i, j] return out def jordan_cell(eigenval, n): """ Create a Jordan block: Examples ======== >>> from sympy.matrices import jordan_cell >>> from sympy.abc import x >>> jordan_cell(x, 4) Matrix([ [x, 1, 0, 0], [0, x, 1, 0], [0, 0, x, 1], [0, 0, 0, x]]) """ return Matrix.jordan_block(size=n, eigenvalue=eigenval) def matrix_multiply_elementwise(A, B): """Return the Hadamard product (elementwise product) of A and B >>> from sympy.matrices import matrix_multiply_elementwise >>> from sympy.matrices import Matrix >>> A = Matrix([[0, 1, 2], [3, 4, 5]]) >>> B = Matrix([[1, 10, 100], [100, 10, 1]]) >>> matrix_multiply_elementwise(A, B) Matrix([ [ 0, 10, 200], [300, 40, 5]]) See Also ======== sympy.matrices.common.MatrixCommon.__mul__ """ return A.multiply_elementwise(B) def ones(*args, **kwargs): """Returns a matrix of ones with ``rows`` rows and ``cols`` columns; if ``cols`` is omitted a square matrix will be returned. See Also ======== zeros eye diag """ if 'c' in kwargs: kwargs['cols'] = kwargs.pop('c') return Matrix.ones(*args, **kwargs) def randMatrix(r, c=None, min=0, max=99, seed=None, symmetric=False, percent=100, prng=None): """Create random matrix with dimensions ``r`` x ``c``. If ``c`` is omitted the matrix will be square. If ``symmetric`` is True the matrix must be square. If ``percent`` is less than 100 then only approximately the given percentage of elements will be non-zero. The pseudo-random number generator used to generate matrix is chosen in the following way. * If ``prng`` is supplied, it will be used as random number generator. It should be an instance of ``random.Random``, or at least have ``randint`` and ``shuffle`` methods with same signatures. * if ``prng`` is not supplied but ``seed`` is supplied, then new ``random.Random`` with given ``seed`` will be created; * otherwise, a new ``random.Random`` with default seed will be used. Examples ======== >>> from sympy.matrices import randMatrix >>> randMatrix(3) # doctest:+SKIP [25, 45, 27] [44, 54, 9] [23, 96, 46] >>> randMatrix(3, 2) # doctest:+SKIP [87, 29] [23, 37] [90, 26] >>> randMatrix(3, 3, 0, 2) # doctest:+SKIP [0, 2, 0] [2, 0, 1] [0, 0, 1] >>> randMatrix(3, symmetric=True) # doctest:+SKIP [85, 26, 29] [26, 71, 43] [29, 43, 57] >>> A = randMatrix(3, seed=1) >>> B = randMatrix(3, seed=2) >>> A == B False >>> A == randMatrix(3, seed=1) True >>> randMatrix(3, symmetric=True, percent=50) # doctest:+SKIP [77, 70, 0], [70, 0, 0], [ 0, 0, 88] """ # Note that ``Random()`` is equivalent to ``Random(None)`` prng = prng or random.Random(seed) if c is None: c = r if symmetric and r != c: raise ValueError('For symmetric matrices, r must equal c, but %i != %i' % (r, c)) ij = range(r * c) if percent != 100: ij = prng.sample(ij, int(len(ij)*percent // 100)) m = zeros(r, c) if not symmetric: for ijk in ij: i, j = divmod(ijk, c) m[i, j] = prng.randint(min, max) else: for ijk in ij: i, j = divmod(ijk, c) if i <= j: m[i, j] = m[j, i] = prng.randint(min, max) return m def wronskian(functions, var, method='bareiss'): """ Compute Wronskian for [] of functions :: | f1 f2 ... fn | | f1' f2' ... fn' | | . . . . | W(f1, ..., fn) = | . . . . | | . . . . | | (n) (n) (n) | | D (f1) D (f2) ... D (fn) | see: https://en.wikipedia.org/wiki/Wronskian See Also ======== sympy.matrices.matrices.MatrixCalculus.jacobian hessian """ for index in range(0, len(functions)): functions[index] = sympify(functions[index]) n = len(functions) if n == 0: return 1 W = Matrix(n, n, lambda i, j: functions[i].diff(var, j)) return W.det(method) def zeros(*args, **kwargs): """Returns a matrix of zeros with ``rows`` rows and ``cols`` columns; if ``cols`` is omitted a square matrix will be returned. See Also ======== ones eye diag """ if 'c' in kwargs: kwargs['cols'] = kwargs.pop('c') return Matrix.zeros(*args, **kwargs) sympy-sympy-1.9/sympy/matrices/densearith.py000066400000000000000000000125551412543434000214230ustar00rootroot00000000000000""" Fundamental arithmetic of dense matrices. The dense matrix is stored as a list of lists. """ from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="densearith", issue=12695, deprecated_since_version="1.1").warn() def add(matlist1, matlist2, K): """ Adds matrices row-wise. Examples ======== >>> from sympy.matrices.densearith import add >>> from sympy import ZZ >>> e = [ ... [ZZ(12), ZZ(78)], ... [ZZ(56), ZZ(79)]] >>> f = [ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]] >>> g = [ ... [ZZ.zero, ZZ.zero], ... [ZZ.zero, ZZ.zero]] >>> add(e, f, ZZ) [[13, 80], [59, 83]] >>> add(f, g, ZZ) [[1, 2], [3, 4]] See Also ======== addrow """ return [addrow(row1, row2, K) for row1, row2 in zip(matlist1, matlist2)] def addrow(row1, row2, K): """ Adds two rows of a matrix element-wise. Examples ======== >>> from sympy.matrices.densearith import addrow >>> from sympy import ZZ >>> a = [ZZ(12), ZZ(34), ZZ(56)] >>> b = [ZZ(14), ZZ(56), ZZ(63)] >>> c = [ZZ(0), ZZ(0), ZZ(0)] >>> addrow(a, b, ZZ) [26, 90, 119] >>> addrow(b, c, ZZ) [14, 56, 63] """ return [element1 + element2 for element1, element2 in zip(row1, row2)] def sub(matlist1, matlist2, K): """ Subtracts two matrices by first negating the second matrix and then adding it to first matrix. Examples ======== >>> from sympy.matrices.densearith import sub >>> from sympy import ZZ >>> e = [ ... [ZZ(12), ZZ(78)], ... [ZZ(56), ZZ(79)]] >>> f = [ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]] >>> g = [ ... [ZZ.zero, ZZ.zero], ... [ZZ.zero, ZZ.zero]] >>> sub(e, f, ZZ) [[11, 76], [53, 75]] >>> sub(f, g, ZZ) [[1, 2], [3, 4]] See Also ======== negate negaterow """ return add(matlist1, negate(matlist2, K), K) def negate(matlist, K): """ Negates the elements of a matrix row-wise. Examples ======== >>> from sympy.matrices.densearith import negate >>> from sympy import ZZ >>> a = [ ... [ZZ(2), ZZ(3)], ... [ZZ(4), ZZ(5)]] >>> b = [ ... [ZZ(0), ZZ(0)], ... [ZZ(0), ZZ(0)]] >>> negate(a, ZZ) [[-2, -3], [-4, -5]] >>> negate(b, ZZ) [[0, 0], [0, 0]] See Also ======== negaterow """ return [negaterow(row, K) for row in matlist] def negaterow(row, K): """ Negates a row element-wise. Examples ======== >>> from sympy.matrices.densearith import negaterow >>> from sympy import ZZ >>> a = [ZZ(2), ZZ(3), ZZ(4)] >>> b = [ZZ(0), ZZ(0), ZZ(0)] >>> negaterow(a, ZZ) [-2, -3, -4] >>> negaterow(b, ZZ) [0, 0, 0] """ return [-element for element in row] def mulmatmat(matlist1, matlist2, K): """ Multiplies two matrices by multiplying each row with each column at a time. The multiplication of row and column is done with mulrowcol. Firstly, the second matrix is converted from a list of rows to a list of columns using zip and then multiplication is done. Examples ======== >>> from sympy.matrices.densearith import mulmatmat >>> from sympy import ZZ >>> from sympy.matrices.densetools import eye >>> a = [ ... [ZZ(3), ZZ(4)], ... [ZZ(5), ZZ(6)]] >>> b = [ ... [ZZ(1), ZZ(2)], ... [ZZ(7), ZZ(8)]] >>> c = eye(2, ZZ) >>> mulmatmat(a, b, ZZ) [[31, 38], [47, 58]] >>> mulmatmat(a, c, ZZ) [[3, 4], [5, 6]] See Also ======== mulrowcol """ matcol = [list(i) for i in zip(*matlist2)] result = [] for row in matlist1: result.append([mulrowcol(row, col, K) for col in matcol]) return result def mulmatscaler(matlist, scaler, K): """ Performs scaler matrix multiplication one row at at time. The row-scaler multiplication is done using mulrowscaler. Examples ======== >>> from sympy import ZZ >>> from sympy.matrices.densearith import mulmatscaler >>> a = [ ... [ZZ(3), ZZ(7), ZZ(4)], ... [ZZ(2), ZZ(4), ZZ(5)], ... [ZZ(6), ZZ(2), ZZ(3)]] >>> mulmatscaler(a, ZZ(1), ZZ) [[3, 7, 4], [2, 4, 5], [6, 2, 3]] See Also ======== mulscalerrow """ return [mulrowscaler(row, scaler, K) for row in matlist] def mulrowscaler(row, scaler, K): """ Performs the scaler-row multiplication element-wise. Examples ======== >>> from sympy import ZZ >>> from sympy.matrices.densearith import mulrowscaler >>> a = [ZZ(3), ZZ(4), ZZ(5)] >>> mulrowscaler(a, 2, ZZ) [6, 8, 10] """ return [scaler*element for element in row] def mulrowcol(row, col, K): """ Multiplies two lists representing row and column element-wise. Gotcha: Here the column is represented as a list contrary to the norm where it is represented as a list of one element lists. The reason is that the theoretically correct approach is too expensive. This problem is expected to be removed later as we have a good data structure to facilitate column operations. Examples ======== >>> from sympy.matrices.densearith import mulrowcol >>> from sympy import ZZ >>> a = [ZZ(2), ZZ(4), ZZ(6)] >>> mulrowcol(a, a, ZZ) 56 """ result = K.zero for i in range(len(row)): result += row[i]*col[i] return result sympy-sympy-1.9/sympy/matrices/densesolve.py000066400000000000000000000266701412543434000214470ustar00rootroot00000000000000""" Solution of equations using dense matrices. The dense matrix is stored as a list of lists. """ import copy from sympy.core.power import isqrt from sympy.core.symbol import symbols from sympy.matrices.densetools import ( augment, col, conjugate_transpose, eye, rowadd, rowmul) from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="densesolve", issue=12695, deprecated_since_version="1.1").warn() def row_echelon(matlist, K): """ Returns the row echelon form of a matrix with diagonal elements reduced to 1. Examples ======== >>> from sympy.matrices.densesolve import row_echelon >>> from sympy import QQ >>> a = [ ... [QQ(3), QQ(7), QQ(4)], ... [QQ(2), QQ(4), QQ(5)], ... [QQ(6), QQ(2), QQ(3)]] >>> row_echelon(a, QQ) [[1, 7/3, 4/3], [0, 1, -7/2], [0, 0, 1]] See Also ======== rref """ result_matlist = copy.deepcopy(matlist) nrow = len(result_matlist) for i in range(nrow): if (result_matlist[i][i] != 1 and result_matlist[i][i] != 0): rowmul(result_matlist, i, 1/result_matlist[i][i], K) for j in range(i + 1, nrow): if (result_matlist[j][i] != 0): rowadd(result_matlist, j, i, -result_matlist[j][i], K) return result_matlist def rref(matlist, K): """ Returns the reduced row echelon form of a Matrix. Examples ======== >>> from sympy.matrices.densesolve import rref >>> from sympy import QQ >>> a = [ ... [QQ(1), QQ(2), QQ(1)], ... [QQ(-2), QQ(-3), QQ(1)], ... [QQ(3), QQ(5), QQ(0)]] >>> rref(a, QQ) [[1, 0, -5], [0, 1, 3], [0, 0, 0]] See Also ======== row_echelon """ result_matlist = copy.deepcopy(matlist) result_matlist = row_echelon(result_matlist, K) nrow = len(result_matlist) for i in range(nrow): if result_matlist[i][i] == 1: for j in range(i): rowadd(result_matlist, j, i, -result_matlist[j][i], K) return result_matlist def LU(matlist, K, reverse = 0): """ It computes the LU decomposition of a matrix and returns L and U matrices. Examples ======== >>> from sympy.matrices.densesolve import LU >>> from sympy import QQ >>> a = [ ... [QQ(1), QQ(2), QQ(3)], ... [QQ(2), QQ(-4), QQ(6)], ... [QQ(3), QQ(-9), QQ(-3)]] >>> LU(a, QQ) ([[1, 0, 0], [2, 1, 0], [3, 15/8, 1]], [[1, 2, 3], [0, -8, 0], [0, 0, -12]]) See Also ======== upper_triangle lower_triangle """ nrow = len(matlist) new_matlist1, new_matlist2 = eye(nrow, K), copy.deepcopy(matlist) for i in range(nrow): for j in range(i + 1, nrow): if (new_matlist2[j][i] != 0): new_matlist1[j][i] = new_matlist2[j][i]/new_matlist2[i][i] rowadd(new_matlist2, j, i, -new_matlist2[j][i]/new_matlist2[i][i], K) return new_matlist1, new_matlist2 def cholesky(matlist, K): """ Performs the cholesky decomposition of a Hermitian matrix and returns L and it's conjugate transpose. Examples ======== >>> from sympy.matrices.densesolve import cholesky >>> from sympy import QQ >>> cholesky([[QQ(25), QQ(15), QQ(-5)], [QQ(15), QQ(18), QQ(0)], [QQ(-5), QQ(0), QQ(11)]], QQ) ([[5, 0, 0], [3, 3, 0], [-1, 1, 3]], [[5, 3, -1], [0, 3, 1], [0, 0, 3]]) See Also ======== cholesky_solve """ new_matlist = copy.deepcopy(matlist) nrow = len(new_matlist) L = eye(nrow, K) for i in range(nrow): for j in range(i + 1): a = K.zero for k in range(j): a += L[i][k]*L[j][k] if i == j: L[i][j] = isqrt(new_matlist[i][j] - a) else: L[i][j] = (new_matlist[i][j] - a)/L[j][j] return L, conjugate_transpose(L, K) def LDL(matlist, K): """ Performs the LDL decomposition of a hermitian matrix and returns L, D and transpose of L. Only applicable to rational entries. Examples ======== >>> from sympy.matrices.densesolve import LDL >>> from sympy import QQ >>> a = [ ... [QQ(4), QQ(12), QQ(-16)], ... [QQ(12), QQ(37), QQ(-43)], ... [QQ(-16), QQ(-43), QQ(98)]] >>> LDL(a, QQ) ([[1, 0, 0], [3, 1, 0], [-4, 5, 1]], [[4, 0, 0], [0, 1, 0], [0, 0, 9]], [[1, 3, -4], [0, 1, 5], [0, 0, 1]]) """ new_matlist = copy.deepcopy(matlist) nrow = len(new_matlist) L, D = eye(nrow, K), eye(nrow, K) for i in range(nrow): for j in range(i + 1): a = K.zero for k in range(j): a += L[i][k]*L[j][k]*D[k][k] if i == j: D[j][j] = new_matlist[j][j] - a else: L[i][j] = (new_matlist[i][j] - a)/D[j][j] return L, D, conjugate_transpose(L, K) def upper_triangle(matlist, K): """ Transforms a given matrix to an upper triangle matrix by performing row operations on it. Examples ======== >>> from sympy.matrices.densesolve import upper_triangle >>> from sympy import QQ >>> a = [ ... [QQ(4,1), QQ(12,1), QQ(-16,1)], ... [QQ(12,1), QQ(37,1), QQ(-43,1)], ... [QQ(-16,1), QQ(-43,1), QQ(98,1)]] >>> upper_triangle(a, QQ) [[4, 12, -16], [0, 1, 5], [0, 0, 9]] See Also ======== LU """ copy_matlist = copy.deepcopy(matlist) lower_triangle, upper_triangle = LU(copy_matlist, K) return upper_triangle def lower_triangle(matlist, K): """ Transforms a given matrix to a lower triangle matrix by performing row operations on it. Examples ======== >>> from sympy.matrices.densesolve import lower_triangle >>> from sympy import QQ >>> a = [ ... [QQ(4,1), QQ(12,1), QQ(-16)], ... [QQ(12,1), QQ(37,1), QQ(-43,1)], ... [QQ(-16,1), QQ(-43,1), QQ(98,1)]] >>> lower_triangle(a, QQ) [[1, 0, 0], [3, 1, 0], [-4, 5, 1]] See Also ======== LU """ copy_matlist = copy.deepcopy(matlist) lower_triangle, upper_triangle = LU(copy_matlist, K, reverse = 1) return lower_triangle def rref_solve(matlist, variable, constant, K): """ Solves a system of equations using reduced row echelon form given a matrix of coefficients, a vector of variables and a vector of constants. Examples ======== >>> from sympy.matrices.densesolve import rref_solve >>> from sympy import QQ >>> from sympy import Dummy >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z') >>> coefficients = [ ... [QQ(25), QQ(15), QQ(-5)], ... [QQ(15), QQ(18), QQ(0)], ... [QQ(-5), QQ(0), QQ(11)]] >>> constants = [ ... [QQ(2)], ... [QQ(3)], ... [QQ(1)]] >>> variables = [ ... [x], ... [y], ... [z]] >>> rref_solve(coefficients, variables, constants, QQ) [[-1/225], [23/135], [4/45]] See Also ======== row_echelon augment """ new_matlist = copy.deepcopy(matlist) augmented = augment(new_matlist, constant, K) solution = rref(augmented, K) return col(solution, -1) def LU_solve(matlist, variable, constant, K): """ Solves a system of equations using LU decomposition given a matrix of coefficients, a vector of variables and a vector of constants. Examples ======== >>> from sympy.matrices.densesolve import LU_solve >>> from sympy import QQ >>> from sympy import Dummy >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z') >>> coefficients = [ ... [QQ(2), QQ(-1), QQ(-2)], ... [QQ(-4), QQ(6), QQ(3)], ... [QQ(-4), QQ(-2), QQ(8)]] >>> variables = [ ... [x], ... [y], ... [z]] >>> constants = [ ... [QQ(-1)], ... [QQ(13)], ... [QQ(-6)]] >>> LU_solve(coefficients, variables, constants, QQ) [[2], [3], [1]] See Also ======== LU forward_substitution backward_substitution """ new_matlist = copy.deepcopy(matlist) nrow = len(new_matlist) L, U = LU(new_matlist, K) y = [[i] for i in symbols('y:%i' % nrow)] forward_substitution(L, y, constant, K) backward_substitution(U, variable, y, K) return variable def cholesky_solve(matlist, variable, constant, K): """ Solves a system of equations using Cholesky decomposition given a matrix of coefficients, a vector of variables and a vector of constants. Examples ======== >>> from sympy.matrices.densesolve import cholesky_solve >>> from sympy import QQ >>> from sympy import Dummy >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z') >>> coefficients = [ ... [QQ(25), QQ(15), QQ(-5)], ... [QQ(15), QQ(18), QQ(0)], ... [QQ(-5), QQ(0), QQ(11)]] >>> variables = [ ... [x], ... [y], ... [z]] >>> coefficients = [ ... [QQ(2)], ... [QQ(3)], ... [QQ(1)]] >>> cholesky_solve([[QQ(25), QQ(15), QQ(-5)], [QQ(15), QQ(18), QQ(0)], [QQ(-5), QQ(0), QQ(11)]], [[x], [y], [z]], [[QQ(2)], [QQ(3)], [QQ(1)]], QQ) [[-1/225], [23/135], [4/45]] See Also ======== cholesky forward_substitution backward_substitution """ new_matlist = copy.deepcopy(matlist) nrow = len(new_matlist) L, Lstar = cholesky(new_matlist, K) y = [[i] for i in symbols('y:%i' % nrow)] forward_substitution(L, y, constant, K) backward_substitution(Lstar, variable, y, K) return variable def forward_substitution(lower_triangle, variable, constant, K): """ Performs forward substitution given a lower triangular matrix, a vector of variables and a vector of constants. Examples ======== >>> from sympy.matrices.densesolve import forward_substitution >>> from sympy import QQ >>> from sympy import Dummy >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z') >>> a = [ ... [QQ(1), QQ(0), QQ(0)], ... [QQ(-2), QQ(1), QQ(0)], ... [QQ(-2), QQ(-1), QQ(1)]] >>> variables = [ ... [x], ... [y], ... [z]] >>> constants = [ ... [QQ(-1)], ... [QQ(13)], ... [QQ(-6)]] >>> forward_substitution(a, variables, constants, QQ) [[-1], [11], [3]] See Also ======== LU_solve cholesky_solve """ copy_lower_triangle = copy.deepcopy(lower_triangle) nrow = len(copy_lower_triangle) for i in range(nrow): a = K.zero for j in range(i): a += copy_lower_triangle[i][j]*variable[j][0] variable[i][0] = (constant[i][0] - a)/copy_lower_triangle[i][i] return variable def backward_substitution(upper_triangle, variable, constant, K): """ Performs forward substitution given a lower triangular matrix, a vector of variables and a vector constants. Examples ======== >>> from sympy.matrices.densesolve import backward_substitution >>> from sympy import QQ >>> from sympy import Dummy >>> x, y, z = Dummy('x'), Dummy('y'), Dummy('z') >>> a = [ ... [QQ(2), QQ(-1), QQ(-2)], ... [QQ(0), QQ(4), QQ(-1)], ... [QQ(0), QQ(0), QQ(3)]] >>> variables = [ ... [x], ... [y], ... [z]] >>> constants = [ ... [QQ(-1)], ... [QQ(11)], ... [QQ(3)]] >>> backward_substitution(a, variables, constants, QQ) [[2], [3], [1]] See Also ======== LU_solve cholesky_solve """ copy_upper_triangle = copy.deepcopy(upper_triangle) nrow = len(copy_upper_triangle) for i in reversed(range(nrow)): a = K.zero for j in reversed(range(i + 1, nrow)): a += copy_upper_triangle[i][j]*variable[j][0] variable[i][0] = (constant[i][0] - a)/copy_upper_triangle[i][i] return variable sympy-sympy-1.9/sympy/matrices/densetools.py000066400000000000000000000125411412543434000214470ustar00rootroot00000000000000""" Fundamental operations of dense matrices. The dense matrix is stored as a list of lists """ from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="densetools", issue=12695, deprecated_since_version="1.1").warn() def trace(matlist, K): """ Returns the trace of a matrix. Examples ======== >>> from sympy.matrices.densetools import trace, eye >>> from sympy import ZZ >>> a = [ ... [ZZ(3), ZZ(7), ZZ(4)], ... [ZZ(2), ZZ(4), ZZ(5)], ... [ZZ(6), ZZ(2), ZZ(3)]] >>> b = eye(4, ZZ) >>> trace(a, ZZ) 10 >>> trace(b, ZZ) 4 """ result = K.zero for i in range(len(matlist)): result += matlist[i][i] return result def transpose(matlist, K): """ Returns the transpose of a matrix Examples ======== >>> from sympy.matrices.densetools import transpose >>> from sympy import ZZ >>> a = [ ... [ZZ(3), ZZ(7), ZZ(4)], ... [ZZ(2), ZZ(4), ZZ(5)], ... [ZZ(6), ZZ(2), ZZ(3)]] >>> transpose(a, ZZ) [[3, 2, 6], [7, 4, 2], [4, 5, 3]] """ return [list(a) for a in (zip(*matlist))] def conjugate(matlist, K): """ Returns the conjugate of a matrix row-wise. Examples ======== >>> from sympy.matrices.densetools import conjugate >>> from sympy import ZZ >>> a = [ ... [ZZ(3), ZZ(2), ZZ(6)], ... [ZZ(7), ZZ(4), ZZ(2)], ... [ZZ(4), ZZ(5), ZZ(3)]] >>> conjugate(a, ZZ) [[3, 2, 6], [7, 4, 2], [4, 5, 3]] See Also ======== conjugate_row """ return [conjugate_row(row, K) for row in matlist] def conjugate_row(row, K): """ Returns the conjugate of a row element-wise Examples ======== >>> from sympy.matrices.densetools import conjugate_row >>> from sympy import ZZ >>> a = [ZZ(3), ZZ(2), ZZ(6)] >>> conjugate_row(a, ZZ) [3, 2, 6] """ result = [] for r in row: conj = getattr(r, 'conjugate', None) if conj is not None: conjrow = conj() else: conjrow = r result.append(conjrow) return result def conjugate_transpose(matlist, K): """ Returns the conjugate-transpose of a matrix Examples ======== >>> from sympy import ZZ >>> from sympy.matrices.densetools import conjugate_transpose >>> a = [ ... [ZZ(3), ZZ(7), ZZ(4)], ... [ZZ(2), ZZ(4), ZZ(5)], ... [ZZ(6), ZZ(2), ZZ(3)]] >>> conjugate_transpose(a, ZZ) [[3, 2, 6], [7, 4, 2], [4, 5, 3]] """ return conjugate(transpose(matlist, K), K) def augment(matlist, column, K): """ Augments a matrix and a column. Examples ======== >>> from sympy.matrices.densetools import augment >>> from sympy import ZZ >>> a = [ ... [ZZ(3), ZZ(7), ZZ(4)], ... [ZZ(2), ZZ(4), ZZ(5)], ... [ZZ(6), ZZ(2), ZZ(3)]] >>> b = [ ... [ZZ(4)], ... [ZZ(5)], ... [ZZ(6)]] >>> augment(a, b, ZZ) [[3, 7, 4, 4], [2, 4, 5, 5], [6, 2, 3, 6]] """ return [row + element for row, element in zip(matlist, column)] def eye(n, K): """ Returns an identity matrix of size n. Examples ======== >>> from sympy.matrices.densetools import eye >>> from sympy import ZZ >>> eye(3, ZZ) [[1, 0, 0], [0, 1, 0], [0, 0, 1]] """ result = [] for i in range(n): result.append([]) for j in range(n): if (i == j): result[i].append(K(1)) else: result[i].append(K.zero) return result def row(matlist, i): """ Returns the ith row of a matrix Examples ======== >>> from sympy.matrices.densetools import row >>> from sympy import ZZ >>> a = [ ... [ZZ(3), ZZ(7), ZZ(4)], ... [ZZ(2), ZZ(4), ZZ(5)], ... [ZZ(6), ZZ(2), ZZ(3)]] >>> row(a, 2) [6, 2, 3] """ return matlist[i] def col(matlist, i): """ Returns the ith column of a matrix Note: Currently very expensive Examples ======== >>> from sympy.matrices.densetools import col >>> from sympy import ZZ >>> a = [ ... [ZZ(3), ZZ(7), ZZ(4)], ... [ZZ(2), ZZ(4), ZZ(5)], ... [ZZ(6), ZZ(2), ZZ(3)]] >>> col(a, 1) [[7], [4], [2]] """ matcol = [list(l) for l in zip(*matlist)] return [[l] for l in matcol[i]] def rowswap(matlist, index1, index2, K): """ Returns the matrix with index1 row and index2 row swapped """ matlist[index1], matlist[index2] = matlist[index2], matlist[index1] return matlist def rowmul(matlist, index, k, K): """ Multiplies index row with k """ for i in range(len(matlist[index])): matlist[index][i] = k*matlist[index][i] return matlist def rowadd(matlist, index1, index2 , k, K): """ Adds the index1 row with index2 row which in turn is multiplied by k """ for i in range(len(matlist[index1])): matlist[index1][i] = (matlist[index1][i] + k*matlist[index2][i]) return matlist def isHermitian(matlist, K): """ Checks whether matrix is hermitian Examples ======== >>> from sympy.matrices.densetools import isHermitian >>> from sympy import QQ >>> a = [ ... [QQ(2,1), QQ(-1,1), QQ(-1,1)], ... [QQ(0,1), QQ(4,1), QQ(-1,1)], ... [QQ(0,1), QQ(0,1), QQ(3,1)]] >>> isHermitian(a, QQ) False """ return conjugate_transpose(matlist, K) == matlist sympy-sympy-1.9/sympy/matrices/determinant.py000066400000000000000000000730131412543434000216030ustar00rootroot00000000000000from types import FunctionType from sympy.core.numbers import Float, Integer from sympy.core.singleton import S from sympy.core.symbol import uniquely_named_symbol from sympy.core.mul import Mul from sympy.polys import PurePoly, cancel from sympy.simplify.simplify import (simplify as _simplify, dotprodsimp as _dotprodsimp) from sympy import sympify from sympy.functions.combinatorial.numbers import nC from sympy.polys.matrices.domainmatrix import DomainMatrix from .common import NonSquareMatrixError from .utilities import ( _get_intermediate_simp, _get_intermediate_simp_bool, _iszero, _is_zero_after_expand_mul) def _find_reasonable_pivot(col, iszerofunc=_iszero, simpfunc=_simplify): """ Find the lowest index of an item in ``col`` that is suitable for a pivot. If ``col`` consists only of Floats, the pivot with the largest norm is returned. Otherwise, the first element where ``iszerofunc`` returns False is used. If ``iszerofunc`` doesn't return false, items are simplified and retested until a suitable pivot is found. Returns a 4-tuple (pivot_offset, pivot_val, assumed_nonzero, newly_determined) where pivot_offset is the index of the pivot, pivot_val is the (possibly simplified) value of the pivot, assumed_nonzero is True if an assumption that the pivot was non-zero was made without being proved, and newly_determined are elements that were simplified during the process of pivot finding.""" newly_determined = [] col = list(col) # a column that contains a mix of floats and integers # but at least one float is considered a numerical # column, and so we do partial pivoting if all(isinstance(x, (Float, Integer)) for x in col) and any( isinstance(x, Float) for x in col): col_abs = [abs(x) for x in col] max_value = max(col_abs) if iszerofunc(max_value): # just because iszerofunc returned True, doesn't # mean the value is numerically zero. Make sure # to replace all entries with numerical zeros if max_value != 0: newly_determined = [(i, 0) for i, x in enumerate(col) if x != 0] return (None, None, False, newly_determined) index = col_abs.index(max_value) return (index, col[index], False, newly_determined) # PASS 1 (iszerofunc directly) possible_zeros = [] for i, x in enumerate(col): is_zero = iszerofunc(x) # is someone wrote a custom iszerofunc, it may return # BooleanFalse or BooleanTrue instead of True or False, # so use == for comparison instead of `is` if is_zero == False: # we found something that is definitely not zero return (i, x, False, newly_determined) possible_zeros.append(is_zero) # by this point, we've found no certain non-zeros if all(possible_zeros): # if everything is definitely zero, we have # no pivot return (None, None, False, newly_determined) # PASS 2 (iszerofunc after simplify) # we haven't found any for-sure non-zeros, so # go through the elements iszerofunc couldn't # make a determination about and opportunistically # simplify to see if we find something for i, x in enumerate(col): if possible_zeros[i] is not None: continue simped = simpfunc(x) is_zero = iszerofunc(simped) if is_zero == True or is_zero == False: newly_determined.append((i, simped)) if is_zero == False: return (i, simped, False, newly_determined) possible_zeros[i] = is_zero # after simplifying, some things that were recognized # as zeros might be zeros if all(possible_zeros): # if everything is definitely zero, we have # no pivot return (None, None, False, newly_determined) # PASS 3 (.equals(0)) # some expressions fail to simplify to zero, but # ``.equals(0)`` evaluates to True. As a last-ditch # attempt, apply ``.equals`` to these expressions for i, x in enumerate(col): if possible_zeros[i] is not None: continue if x.equals(S.Zero): # ``.iszero`` may return False with # an implicit assumption (e.g., ``x.equals(0)`` # when ``x`` is a symbol), so only treat it # as proved when ``.equals(0)`` returns True possible_zeros[i] = True newly_determined.append((i, S.Zero)) if all(possible_zeros): return (None, None, False, newly_determined) # at this point there is nothing that could definitely # be a pivot. To maintain compatibility with existing # behavior, we'll assume that an illdetermined thing is # non-zero. We should probably raise a warning in this case i = possible_zeros.index(None) return (i, col[i], True, newly_determined) def _find_reasonable_pivot_naive(col, iszerofunc=_iszero, simpfunc=None): """ Helper that computes the pivot value and location from a sequence of contiguous matrix column elements. As a side effect of the pivot search, this function may simplify some of the elements of the input column. A list of these simplified entries and their indices are also returned. This function mimics the behavior of _find_reasonable_pivot(), but does less work trying to determine if an indeterminate candidate pivot simplifies to zero. This more naive approach can be much faster, with the trade-off that it may erroneously return a pivot that is zero. ``col`` is a sequence of contiguous column entries to be searched for a suitable pivot. ``iszerofunc`` is a callable that returns a Boolean that indicates if its input is zero, or None if no such determination can be made. ``simpfunc`` is a callable that simplifies its input. It must return its input if it does not simplify its input. Passing in ``simpfunc=None`` indicates that the pivot search should not attempt to simplify any candidate pivots. Returns a 4-tuple: (pivot_offset, pivot_val, assumed_nonzero, newly_determined) ``pivot_offset`` is the sequence index of the pivot. ``pivot_val`` is the value of the pivot. pivot_val and col[pivot_index] are equivalent, but will be different when col[pivot_index] was simplified during the pivot search. ``assumed_nonzero`` is a boolean indicating if the pivot cannot be guaranteed to be zero. If assumed_nonzero is true, then the pivot may or may not be non-zero. If assumed_nonzero is false, then the pivot is non-zero. ``newly_determined`` is a list of index-value pairs of pivot candidates that were simplified during the pivot search. """ # indeterminates holds the index-value pairs of each pivot candidate # that is neither zero or non-zero, as determined by iszerofunc(). # If iszerofunc() indicates that a candidate pivot is guaranteed # non-zero, or that every candidate pivot is zero then the contents # of indeterminates are unused. # Otherwise, the only viable candidate pivots are symbolic. # In this case, indeterminates will have at least one entry, # and all but the first entry are ignored when simpfunc is None. indeterminates = [] for i, col_val in enumerate(col): col_val_is_zero = iszerofunc(col_val) if col_val_is_zero == False: # This pivot candidate is non-zero. return i, col_val, False, [] elif col_val_is_zero is None: # The candidate pivot's comparison with zero # is indeterminate. indeterminates.append((i, col_val)) if len(indeterminates) == 0: # All candidate pivots are guaranteed to be zero, i.e. there is # no pivot. return None, None, False, [] if simpfunc is None: # Caller did not pass in a simplification function that might # determine if an indeterminate pivot candidate is guaranteed # to be nonzero, so assume the first indeterminate candidate # is non-zero. return indeterminates[0][0], indeterminates[0][1], True, [] # newly_determined holds index-value pairs of candidate pivots # that were simplified during the search for a non-zero pivot. newly_determined = [] for i, col_val in indeterminates: tmp_col_val = simpfunc(col_val) if id(col_val) != id(tmp_col_val): # simpfunc() simplified this candidate pivot. newly_determined.append((i, tmp_col_val)) if iszerofunc(tmp_col_val) == False: # Candidate pivot simplified to a guaranteed non-zero value. return i, tmp_col_val, False, newly_determined return indeterminates[0][0], indeterminates[0][1], True, newly_determined # This functions is a candidate for caching if it gets implemented for matrices. def _berkowitz_toeplitz_matrix(M): """Return (A,T) where T the Toeplitz matrix used in the Berkowitz algorithm corresponding to ``M`` and A is the first principal submatrix. """ # the 0 x 0 case is trivial if M.rows == 0 and M.cols == 0: return M._new(1,1, [M.one]) # # Partition M = [ a_11 R ] # [ C A ] # a, R = M[0,0], M[0, 1:] C, A = M[1:, 0], M[1:,1:] # # The Toeplitz matrix looks like # # [ 1 ] # [ -a 1 ] # [ -RC -a 1 ] # [ -RAC -RC -a 1 ] # [ -RA**2C -RAC -RC -a 1 ] # etc. # Compute the diagonal entries. # Because multiplying matrix times vector is so much # more efficient than matrix times matrix, recursively # compute -R * A**n * C. diags = [C] for i in range(M.rows - 2): diags.append(A.multiply(diags[i], dotprodsimp=None)) diags = [(-R).multiply(d, dotprodsimp=None)[0, 0] for d in diags] diags = [M.one, -a] + diags def entry(i,j): if j > i: return M.zero return diags[i - j] toeplitz = M._new(M.cols + 1, M.rows, entry) return (A, toeplitz) # This functions is a candidate for caching if it gets implemented for matrices. def _berkowitz_vector(M): """ Run the Berkowitz algorithm and return a vector whose entries are the coefficients of the characteristic polynomial of ``M``. Given N x N matrix, efficiently compute coefficients of characteristic polynomials of ``M`` without division in the ground domain. This method is particularly useful for computing determinant, principal minors and characteristic polynomial when ``M`` has complicated coefficients e.g. polynomials. Semi-direct usage of this algorithm is also important in computing efficiently sub-resultant PRS. Assuming that M is a square matrix of dimension N x N and I is N x N identity matrix, then the Berkowitz vector is an N x 1 vector whose entries are coefficients of the polynomial charpoly(M) = det(t*I - M) As a consequence, all polynomials generated by Berkowitz algorithm are monic. For more information on the implemented algorithm refer to: [1] S.J. Berkowitz, On computing the determinant in small parallel time using a small number of processors, ACM, Information Processing Letters 18, 1984, pp. 147-150 [2] M. Keber, Division-Free computation of sub-resultants using Bezout matrices, Tech. Report MPI-I-2006-1-006, Saarbrucken, 2006 """ # handle the trivial cases if M.rows == 0 and M.cols == 0: return M._new(1, 1, [M.one]) elif M.rows == 1 and M.cols == 1: return M._new(2, 1, [M.one, -M[0,0]]) submat, toeplitz = _berkowitz_toeplitz_matrix(M) return toeplitz.multiply(_berkowitz_vector(submat), dotprodsimp=None) def _adjugate(M, method="berkowitz"): """Returns the adjugate, or classical adjoint, of a matrix. That is, the transpose of the matrix of cofactors. https://en.wikipedia.org/wiki/Adjugate Parameters ========== method : string, optional Method to use to find the cofactors, can be "bareiss", "berkowitz" or "lu". Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2], [3, 4]]) >>> M.adjugate() Matrix([ [ 4, -2], [-3, 1]]) See Also ======== cofactor_matrix sympy.matrices.common.MatrixCommon.transpose """ return M.cofactor_matrix(method=method).transpose() # This functions is a candidate for caching if it gets implemented for matrices. def _charpoly(M, x='lambda', simplify=_simplify): """Computes characteristic polynomial det(x*I - M) where I is the identity matrix. A PurePoly is returned, so using different variables for ``x`` does not affect the comparison or the polynomials: Parameters ========== x : string, optional Name for the "lambda" variable, defaults to "lambda". simplify : function, optional Simplification function to use on the characteristic polynomial calculated. Defaults to ``simplify``. Examples ======== >>> from sympy import Matrix >>> from sympy.abc import x, y >>> M = Matrix([[1, 3], [2, 0]]) >>> M.charpoly() PurePoly(lambda**2 - lambda - 6, lambda, domain='ZZ') >>> M.charpoly(x) == M.charpoly(y) True >>> M.charpoly(x) == M.charpoly(y) True Specifying ``x`` is optional; a symbol named ``lambda`` is used by default (which looks good when pretty-printed in unicode): >>> M.charpoly().as_expr() lambda**2 - lambda - 6 And if ``x`` clashes with an existing symbol, underscores will be prepended to the name to make it unique: >>> M = Matrix([[1, 2], [x, 0]]) >>> M.charpoly(x).as_expr() _x**2 - _x - 2*x Whether you pass a symbol or not, the generator can be obtained with the gen attribute since it may not be the same as the symbol that was passed: >>> M.charpoly(x).gen _x >>> M.charpoly(x).gen == x False Notes ===== The Samuelson-Berkowitz algorithm is used to compute the characteristic polynomial efficiently and without any division operations. Thus the characteristic polynomial over any commutative ring without zero divisors can be computed. If the determinant det(x*I - M) can be found out easily as in the case of an upper or a lower triangular matrix, then instead of Samuelson-Berkowitz algorithm, eigenvalues are computed and the characteristic polynomial with their help. See Also ======== det """ if not M.is_square: raise NonSquareMatrixError() if M.is_lower or M.is_upper: diagonal_elements = M.diagonal() x = uniquely_named_symbol(x, diagonal_elements, modify=lambda s: '_' + s) m = 1 for i in diagonal_elements: m = m * (x - simplify(i)) return PurePoly(m, x) berk_vector = _berkowitz_vector(M) x = uniquely_named_symbol(x, berk_vector, modify=lambda s: '_' + s) return PurePoly([simplify(a) for a in berk_vector], x) def _cofactor(M, i, j, method="berkowitz"): """Calculate the cofactor of an element. Parameters ========== method : string, optional Method to use to find the cofactors, can be "bareiss", "berkowitz" or "lu". Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2], [3, 4]]) >>> M.cofactor(0, 1) -3 See Also ======== cofactor_matrix minor minor_submatrix """ if not M.is_square or M.rows < 1: raise NonSquareMatrixError() return (-1)**((i + j) % 2) * M.minor(i, j, method) def _cofactor_matrix(M, method="berkowitz"): """Return a matrix containing the cofactor of each element. Parameters ========== method : string, optional Method to use to find the cofactors, can be "bareiss", "berkowitz" or "lu". Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2], [3, 4]]) >>> M.cofactor_matrix() Matrix([ [ 4, -3], [-2, 1]]) See Also ======== cofactor minor minor_submatrix """ if not M.is_square or M.rows < 1: raise NonSquareMatrixError() return M._new(M.rows, M.cols, lambda i, j: M.cofactor(i, j, method)) def _per(M): """Returns the permanent of a matrix. Unlike determinant, permanent is defined for both square and non-square matrices. For an m x n matrix, with m less than or equal to n, it is given as the sum over the permutations s of size less than or equal to m on [1, 2, . . . n] of the product from i = 1 to m of M[i, s[i]]. Taking the transpose will not affect the value of the permanent. In the case of a square matrix, this is the same as the permutation definition of the determinant, but it does not take the sign of the permutation into account. Computing the permanent with this definition is quite inefficient, so here the Ryser formula is used. Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> M.per() 450 >>> M = Matrix([1, 5, 7]) >>> M.per() 13 References ========== .. [1] Prof. Frank Ben's notes: https://math.berkeley.edu/~bernd/ban275.pdf .. [2] Wikipedia article on Permanent: https://en.wikipedia.org/wiki/Permanent_(mathematics) .. [3] https://reference.wolfram.com/language/ref/Permanent.html .. [4] Permanent of a rectangular matrix : https://arxiv.org/pdf/0904.3251.pdf """ import itertools m, n = M.shape if m > n: M = M.T m, n = n, m s = list(range(n)) subsets = [] for i in range(1, m + 1): subsets += list(map(list, itertools.combinations(s, i))) perm = 0 for subset in subsets: prod = 1 sub_len = len(subset) for i in range(m): prod *= sum([M[i, j] for j in subset]) perm += prod * (-1)**sub_len * nC(n - sub_len, m - sub_len) perm *= (-1)**m perm = sympify(perm) return perm.simplify() def _det_DOM(M): DOM = DomainMatrix.from_Matrix(M, field=True, extension=True) K = DOM.domain return K.to_sympy(DOM.det()) # This functions is a candidate for caching if it gets implemented for matrices. def _det(M, method="bareiss", iszerofunc=None): """Computes the determinant of a matrix if ``M`` is a concrete matrix object otherwise return an expressions ``Determinant(M)`` if ``M`` is a ``MatrixSymbol`` or other expression. Parameters ========== method : string, optional Specifies the algorithm used for computing the matrix determinant. If the matrix is at most 3x3, a hard-coded formula is used and the specified method is ignored. Otherwise, it defaults to ``'bareiss'``. Also, if the matrix is an upper or a lower triangular matrix, determinant is computed by simple multiplication of diagonal elements, and the specified method is ignored. If it is set to ``'domain-ge'``, then Gaussian elimination method will be used via using DomainMatrix. If it is set to ``'bareiss'``, Bareiss' fraction-free algorithm will be used. If it is set to ``'berkowitz'``, Berkowitz' algorithm will be used. Otherwise, if it is set to ``'lu'``, LU decomposition will be used. .. note:: For backward compatibility, legacy keys like "bareis" and "det_lu" can still be used to indicate the corresponding methods. And the keys are also case-insensitive for now. However, it is suggested to use the precise keys for specifying the method. iszerofunc : FunctionType or None, optional If it is set to ``None``, it will be defaulted to ``_iszero`` if the method is set to ``'bareiss'``, and ``_is_zero_after_expand_mul`` if the method is set to ``'lu'``. It can also accept any user-specified zero testing function, if it is formatted as a function which accepts a single symbolic argument and returns ``True`` if it is tested as zero and ``False`` if it tested as non-zero, and also ``None`` if it is undecidable. Returns ======= det : Basic Result of determinant. Raises ====== ValueError If unrecognized keys are given for ``method`` or ``iszerofunc``. NonSquareMatrixError If attempted to calculate determinant from a non-square matrix. Examples ======== >>> from sympy import Matrix, eye, det >>> I3 = eye(3) >>> det(I3) 1 >>> M = Matrix([[1, 2], [3, 4]]) >>> det(M) -2 >>> det(M) == M.det() True >>> M.det(method="domain-ge") -2 """ # sanitize `method` method = method.lower() if method == "bareis": method = "bareiss" elif method == "det_lu": method = "lu" if method not in ("bareiss", "berkowitz", "lu", "domain-ge"): raise ValueError("Determinant method '%s' unrecognized" % method) if iszerofunc is None: if method == "bareiss": iszerofunc = _is_zero_after_expand_mul elif method == "lu": iszerofunc = _iszero elif not isinstance(iszerofunc, FunctionType): raise ValueError("Zero testing method '%s' unrecognized" % iszerofunc) n = M.rows if n == M.cols: # square check is done in individual method functions if n == 0: return M.one elif n == 1: return M[0, 0] elif n == 2: m = M[0, 0] * M[1, 1] - M[0, 1] * M[1, 0] return _get_intermediate_simp(_dotprodsimp)(m) elif n == 3: m = (M[0, 0] * M[1, 1] * M[2, 2] + M[0, 1] * M[1, 2] * M[2, 0] + M[0, 2] * M[1, 0] * M[2, 1] - M[0, 2] * M[1, 1] * M[2, 0] - M[0, 0] * M[1, 2] * M[2, 1] - M[0, 1] * M[1, 0] * M[2, 2]) return _get_intermediate_simp(_dotprodsimp)(m) dets = [] for b in M.strongly_connected_components(): if method == "domain-ge": # uses DomainMatrix to evalute determinant det = _det_DOM(M[b, b]) elif method == "bareiss": det = M[b, b]._eval_det_bareiss(iszerofunc=iszerofunc) elif method == "berkowitz": det = M[b, b]._eval_det_berkowitz() elif method == "lu": det = M[b, b]._eval_det_lu(iszerofunc=iszerofunc) dets.append(det) return Mul(*dets) # This functions is a candidate for caching if it gets implemented for matrices. def _det_bareiss(M, iszerofunc=_is_zero_after_expand_mul): """Compute matrix determinant using Bareiss' fraction-free algorithm which is an extension of the well known Gaussian elimination method. This approach is best suited for dense symbolic matrices and will result in a determinant with minimal number of fractions. It means that less term rewriting is needed on resulting formulae. Parameters ========== iszerofunc : function, optional The function to use to determine zeros when doing an LU decomposition. Defaults to ``lambda x: x.is_zero``. TODO: Implement algorithm for sparse matrices (SFF), http://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps. """ # Recursively implemented Bareiss' algorithm as per Deanna Richelle Leggett's # thesis http://www.math.usm.edu/perry/Research/Thesis_DRL.pdf def bareiss(mat, cumm=1): if mat.rows == 0: return mat.one elif mat.rows == 1: return mat[0, 0] # find a pivot and extract the remaining matrix # With the default iszerofunc, _find_reasonable_pivot slows down # the computation by the factor of 2.5 in one test. # Relevant issues: #10279 and #13877. pivot_pos, pivot_val, _, _ = _find_reasonable_pivot(mat[:, 0], iszerofunc=iszerofunc) if pivot_pos is None: return mat.zero # if we have a valid pivot, we'll do a "row swap", so keep the # sign of the det sign = (-1) ** (pivot_pos % 2) # we want every row but the pivot row and every column rows = list(i for i in range(mat.rows) if i != pivot_pos) cols = list(range(mat.cols)) tmp_mat = mat.extract(rows, cols) def entry(i, j): ret = (pivot_val*tmp_mat[i, j + 1] - mat[pivot_pos, j + 1]*tmp_mat[i, 0]) / cumm if _get_intermediate_simp_bool(True): return _dotprodsimp(ret) elif not ret.is_Atom: return cancel(ret) return ret return sign*bareiss(M._new(mat.rows - 1, mat.cols - 1, entry), pivot_val) if not M.is_square: raise NonSquareMatrixError() if M.rows == 0: return M.one # sympy/matrices/tests/test_matrices.py contains a test that # suggests that the determinant of a 0 x 0 matrix is one, by # convention. return bareiss(M) def _det_berkowitz(M): """ Use the Berkowitz algorithm to compute the determinant.""" if not M.is_square: raise NonSquareMatrixError() if M.rows == 0: return M.one # sympy/matrices/tests/test_matrices.py contains a test that # suggests that the determinant of a 0 x 0 matrix is one, by # convention. berk_vector = _berkowitz_vector(M) return (-1)**(len(berk_vector) - 1) * berk_vector[-1] # This functions is a candidate for caching if it gets implemented for matrices. def _det_LU(M, iszerofunc=_iszero, simpfunc=None): """ Computes the determinant of a matrix from its LU decomposition. This function uses the LU decomposition computed by LUDecomposition_Simple(). The keyword arguments iszerofunc and simpfunc are passed to LUDecomposition_Simple(). iszerofunc is a callable that returns a boolean indicating if its input is zero, or None if it cannot make the determination. simpfunc is a callable that simplifies its input. The default is simpfunc=None, which indicate that the pivot search algorithm should not attempt to simplify any candidate pivots. If simpfunc fails to simplify its input, then it must return its input instead of a copy. Parameters ========== iszerofunc : function, optional The function to use to determine zeros when doing an LU decomposition. Defaults to ``lambda x: x.is_zero``. simpfunc : function, optional The simplification function to use when looking for zeros for pivots. """ if not M.is_square: raise NonSquareMatrixError() if M.rows == 0: return M.one # sympy/matrices/tests/test_matrices.py contains a test that # suggests that the determinant of a 0 x 0 matrix is one, by # convention. lu, row_swaps = M.LUdecomposition_Simple(iszerofunc=iszerofunc, simpfunc=simpfunc) # P*A = L*U => det(A) = det(L)*det(U)/det(P) = det(P)*det(U). # Lower triangular factor L encoded in lu has unit diagonal => det(L) = 1. # P is a permutation matrix => det(P) in {-1, 1} => 1/det(P) = det(P). # LUdecomposition_Simple() returns a list of row exchange index pairs, rather # than a permutation matrix, but det(P) = (-1)**len(row_swaps). # Avoid forming the potentially time consuming product of U's diagonal entries # if the product is zero. # Bottom right entry of U is 0 => det(A) = 0. # It may be impossible to determine if this entry of U is zero when it is symbolic. if iszerofunc(lu[lu.rows-1, lu.rows-1]): return M.zero # Compute det(P) det = -M.one if len(row_swaps)%2 else M.one # Compute det(U) by calculating the product of U's diagonal entries. # The upper triangular portion of lu is the upper triangular portion of the # U factor in the LU decomposition. for k in range(lu.rows): det *= lu[k, k] # return det(P)*det(U) return det def _minor(M, i, j, method="berkowitz"): """Return the (i,j) minor of ``M``. That is, return the determinant of the matrix obtained by deleting the `i`th row and `j`th column from ``M``. Parameters ========== i, j : int The row and column to exclude to obtain the submatrix. method : string, optional Method to use to find the determinant of the submatrix, can be "bareiss", "berkowitz" or "lu". Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> M.minor(1, 1) -12 See Also ======== minor_submatrix cofactor det """ if not M.is_square: raise NonSquareMatrixError() return M.minor_submatrix(i, j).det(method=method) def _minor_submatrix(M, i, j): """Return the submatrix obtained by removing the `i`th row and `j`th column from ``M`` (works with Pythonic negative indices). Parameters ========== i, j : int The row and column to exclude to obtain the submatrix. Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> M.minor_submatrix(1, 1) Matrix([ [1, 3], [7, 9]]) See Also ======== minor cofactor """ if i < 0: i += M.rows if j < 0: j += M.cols if not 0 <= i < M.rows or not 0 <= j < M.cols: raise ValueError("`i` and `j` must satisfy 0 <= i < ``M.rows`` " "(%d)" % M.rows + "and 0 <= j < ``M.cols`` (%d)." % M.cols) rows = [a for a in range(M.rows) if a != i] cols = [a for a in range(M.cols) if a != j] return M.extract(rows, cols) sympy-sympy-1.9/sympy/matrices/eigen.py000066400000000000000000001163521412543434000203640ustar00rootroot00000000000000from types import FunctionType from collections import Counter from mpmath import mp, workprec from mpmath.libmp.libmpf import prec_to_dps from sympy.core.compatibility import default_sort_key from sympy.core.evalf import DEFAULT_MAXPREC, PrecisionExhausted from sympy.core.logic import fuzzy_and, fuzzy_or from sympy.core.numbers import Float from sympy.core.sympify import _sympify from sympy.functions.elementary.miscellaneous import sqrt from sympy.polys import roots, CRootOf, ZZ, QQ, EX from sympy.polys.matrices import DomainMatrix from sympy.polys.matrices.eigen import dom_eigenvects, dom_eigenvects_to_sympy from sympy.simplify import nsimplify, simplify as _simplify from sympy.utilities.exceptions import SymPyDeprecationWarning from .common import MatrixError, NonSquareMatrixError from .determinant import _find_reasonable_pivot from .utilities import _iszero def _eigenvals_eigenvects_mpmath(M): norm2 = lambda v: mp.sqrt(sum(i**2 for i in v)) v1 = None prec = max([x._prec for x in M.atoms(Float)]) eps = 2**-prec while prec < DEFAULT_MAXPREC: with workprec(prec): A = mp.matrix(M.evalf(n=prec_to_dps(prec))) E, ER = mp.eig(A) v2 = norm2([i for e in E for i in (mp.re(e), mp.im(e))]) if v1 is not None and mp.fabs(v1 - v2) < eps: return E, ER v1 = v2 prec *= 2 # we get here because the next step would have taken us # past MAXPREC or because we never took a step; in case # of the latter, we refuse to send back a solution since # it would not have been verified; we also resist taking # a small step to arrive exactly at MAXPREC since then # the two calculations might be artificially close. raise PrecisionExhausted def _eigenvals_mpmath(M, multiple=False): """Compute eigenvalues using mpmath""" E, _ = _eigenvals_eigenvects_mpmath(M) result = [_sympify(x) for x in E] if multiple: return result return dict(Counter(result)) def _eigenvects_mpmath(M): E, ER = _eigenvals_eigenvects_mpmath(M) result = [] for i in range(M.rows): eigenval = _sympify(E[i]) eigenvect = _sympify(ER[:, i]) result.append((eigenval, 1, [eigenvect])) return result # This function is a candidate for caching if it gets implemented for matrices. def _eigenvals( M, error_when_incomplete=True, *, simplify=False, multiple=False, rational=False, **flags): r"""Compute eigenvalues of the matrix. Parameters ========== error_when_incomplete : bool, optional If it is set to ``True``, it will raise an error if not all eigenvalues are computed. This is caused by ``roots`` not returning a full list of eigenvalues. simplify : bool or function, optional If it is set to ``True``, it attempts to return the most simplified form of expressions returned by applying default simplification method in every routine. If it is set to ``False``, it will skip simplification in this particular routine to save computation resources. If a function is passed to, it will attempt to apply the particular function as simplification method. rational : bool, optional If it is set to ``True``, every floating point numbers would be replaced with rationals before computation. It can solve some issues of ``roots`` routine not working well with floats. multiple : bool, optional If it is set to ``True``, the result will be in the form of a list. If it is set to ``False``, the result will be in the form of a dictionary. Returns ======= eigs : list or dict Eigenvalues of a matrix. The return format would be specified by the key ``multiple``. Raises ====== MatrixError If not enough roots had got computed. NonSquareMatrixError If attempted to compute eigenvalues from a non-square matrix. Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix(3, 3, [0, 1, 1, 1, 0, 0, 1, 1, 1]) >>> M.eigenvals() {-1: 1, 0: 1, 2: 1} See Also ======== MatrixDeterminant.charpoly eigenvects Notes ===== Eigenvalues of a matrix $A$ can be computed by solving a matrix equation $\det(A - \lambda I) = 0$ It's not always possible to return radical solutions for eigenvalues for matrices larger than $4, 4$ shape due to Abel-Ruffini theorem. If there is no radical solution is found for the eigenvalue, it may return eigenvalues in the form of :class:`sympy.polys.rootoftools.ComplexRootOf`. """ if not M: if multiple: return [] return {} if not M.is_square: raise NonSquareMatrixError("{} must be a square matrix.".format(M)) if M._rep.domain not in (ZZ, QQ): # Skip this check for ZZ/QQ because it can be slow if all(x.is_number for x in M) and M.has(Float): return _eigenvals_mpmath(M, multiple=multiple) if rational: M = M.applyfunc( lambda x: nsimplify(x, rational=True) if x.has(Float) else x) if multiple: return _eigenvals_list( M, error_when_incomplete=error_when_incomplete, simplify=simplify, **flags) return _eigenvals_dict( M, error_when_incomplete=error_when_incomplete, simplify=simplify, **flags) eigenvals_error_message = \ "It is not always possible to express the eigenvalues of a matrix " + \ "of size 5x5 or higher in radicals. " + \ "We have CRootOf, but domains other than the rationals are not " + \ "currently supported. " + \ "If there are no symbols in the matrix, " + \ "it should still be possible to compute numeric approximations " + \ "of the eigenvalues using " + \ "M.evalf().eigenvals() or M.charpoly().nroots()." def _eigenvals_list( M, error_when_incomplete=True, simplify=False, **flags): iblocks = M.strongly_connected_components() all_eigs = [] is_dom = M._rep.domain in (ZZ, QQ) for b in iblocks: # Fast path for a 1x1 block: if is_dom and len(b) == 1: index = b[0] val = M[index, index] all_eigs.append(val) continue block = M[b, b] if isinstance(simplify, FunctionType): charpoly = block.charpoly(simplify=simplify) else: charpoly = block.charpoly() eigs = roots(charpoly, multiple=True, **flags) if len(eigs) != block.rows: degree = int(charpoly.degree()) f = charpoly.as_expr() x = charpoly.gen try: eigs = [CRootOf(f, x, idx) for idx in range(degree)] except NotImplementedError: if error_when_incomplete: raise MatrixError(eigenvals_error_message) else: eigs = [] all_eigs += eigs if not simplify: return all_eigs if not isinstance(simplify, FunctionType): simplify = _simplify return [simplify(value) for value in all_eigs] def _eigenvals_dict( M, error_when_incomplete=True, simplify=False, **flags): iblocks = M.strongly_connected_components() all_eigs = {} is_dom = M._rep.domain in (ZZ, QQ) for b in iblocks: # Fast path for a 1x1 block: if is_dom and len(b) == 1: index = b[0] val = M[index, index] all_eigs[val] = all_eigs.get(val, 0) + 1 continue block = M[b, b] if isinstance(simplify, FunctionType): charpoly = block.charpoly(simplify=simplify) else: charpoly = block.charpoly() eigs = roots(charpoly, multiple=False, **flags) if sum(eigs.values()) != block.rows: degree = int(charpoly.degree()) f = charpoly.as_expr() x = charpoly.gen try: eigs = {CRootOf(f, x, idx): 1 for idx in range(degree)} except NotImplementedError: if error_when_incomplete: raise MatrixError(eigenvals_error_message) else: eigs = {} for k, v in eigs.items(): if k in all_eigs: all_eigs[k] += v else: all_eigs[k] = v if not simplify: return all_eigs if not isinstance(simplify, FunctionType): simplify = _simplify return {simplify(key): value for key, value in all_eigs.items()} def _eigenspace(M, eigenval, iszerofunc=_iszero, simplify=False): """Get a basis for the eigenspace for a particular eigenvalue""" m = M - M.eye(M.rows) * eigenval ret = m.nullspace(iszerofunc=iszerofunc) # The nullspace for a real eigenvalue should be non-trivial. # If we didn't find an eigenvector, try once more a little harder if len(ret) == 0 and simplify: ret = m.nullspace(iszerofunc=iszerofunc, simplify=True) if len(ret) == 0: raise NotImplementedError( "Can't evaluate eigenvector for eigenvalue {}".format(eigenval)) return ret def _eigenvects_DOM(M, **kwargs): DOM = DomainMatrix.from_Matrix(M, field=True, extension=True) DOM = DOM.to_dense() if DOM.domain != EX: rational, algebraic = dom_eigenvects(DOM) eigenvects = dom_eigenvects_to_sympy( rational, algebraic, M.__class__, **kwargs) eigenvects = sorted(eigenvects, key=lambda x: default_sort_key(x[0])) return eigenvects return None def _eigenvects_sympy(M, iszerofunc, simplify=True, **flags): eigenvals = M.eigenvals(rational=False, **flags) # Make sure that we have all roots in radical form for x in eigenvals: if x.has(CRootOf): raise MatrixError( "Eigenvector computation is not implemented if the matrix have " "eigenvalues in CRootOf form") eigenvals = sorted(eigenvals.items(), key=default_sort_key) ret = [] for val, mult in eigenvals: vects = _eigenspace(M, val, iszerofunc=iszerofunc, simplify=simplify) ret.append((val, mult, vects)) return ret # This functions is a candidate for caching if it gets implemented for matrices. def _eigenvects(M, error_when_incomplete=True, iszerofunc=_iszero, *, chop=False, **flags): """Compute eigenvectors of the matrix. Parameters ========== error_when_incomplete : bool, optional Raise an error when not all eigenvalues are computed. This is caused by ``roots`` not returning a full list of eigenvalues. iszerofunc : function, optional Specifies a zero testing function to be used in ``rref``. Default value is ``_iszero``, which uses SymPy's naive and fast default assumption handler. It can also accept any user-specified zero testing function, if it is formatted as a function which accepts a single symbolic argument and returns ``True`` if it is tested as zero and ``False`` if it is tested as non-zero, and ``None`` if it is undecidable. simplify : bool or function, optional If ``True``, ``as_content_primitive()`` will be used to tidy up normalization artifacts. It will also be used by the ``nullspace`` routine. chop : bool or positive number, optional If the matrix contains any Floats, they will be changed to Rationals for computation purposes, but the answers will be returned after being evaluated with evalf. The ``chop`` flag is passed to ``evalf``. When ``chop=True`` a default precision will be used; a number will be interpreted as the desired level of precision. Returns ======= ret : [(eigenval, multiplicity, eigenspace), ...] A ragged list containing tuples of data obtained by ``eigenvals`` and ``nullspace``. ``eigenspace`` is a list containing the ``eigenvector`` for each eigenvalue. ``eigenvector`` is a vector in the form of a ``Matrix``. e.g. a vector of length 3 is returned as ``Matrix([a_1, a_2, a_3])``. Raises ====== NotImplementedError If failed to compute nullspace. Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix(3, 3, [0, 1, 1, 1, 0, 0, 1, 1, 1]) >>> M.eigenvects() [(-1, 1, [Matrix([ [-1], [ 1], [ 0]])]), (0, 1, [Matrix([ [ 0], [-1], [ 1]])]), (2, 1, [Matrix([ [2/3], [1/3], [ 1]])])] See Also ======== eigenvals MatrixSubspaces.nullspace """ simplify = flags.get('simplify', True) primitive = flags.get('simplify', False) flags.pop('simplify', None) # remove this if it's there flags.pop('multiple', None) # remove this if it's there if not isinstance(simplify, FunctionType): simpfunc = _simplify if simplify else lambda x: x has_floats = M.has(Float) if has_floats: if all(x.is_number for x in M): return _eigenvects_mpmath(M) M = M.applyfunc(lambda x: nsimplify(x, rational=True)) ret = _eigenvects_DOM(M) if ret is None: ret = _eigenvects_sympy(M, iszerofunc, simplify=simplify, **flags) if primitive: # if the primitive flag is set, get rid of any common # integer denominators def denom_clean(l): from sympy import gcd return [(v / gcd(list(v))).applyfunc(simpfunc) for v in l] ret = [(val, mult, denom_clean(es)) for val, mult, es in ret] if has_floats: # if we had floats to start with, turn the eigenvectors to floats ret = [(val.evalf(chop=chop), mult, [v.evalf(chop=chop) for v in es]) for val, mult, es in ret] return ret def _is_diagonalizable_with_eigen(M, reals_only=False): """See _is_diagonalizable. This function returns the bool along with the eigenvectors to avoid calculating them again in functions like ``diagonalize``.""" if not M.is_square: return False, [] eigenvecs = M.eigenvects(simplify=True) for val, mult, basis in eigenvecs: if reals_only and not val.is_real: # if we have a complex eigenvalue return False, eigenvecs if mult != len(basis): # if the geometric multiplicity doesn't equal the algebraic return False, eigenvecs return True, eigenvecs def _is_diagonalizable(M, reals_only=False, **kwargs): """Returns ``True`` if a matrix is diagonalizable. Parameters ========== reals_only : bool, optional If ``True``, it tests whether the matrix can be diagonalized to contain only real numbers on the diagonal. If ``False``, it tests whether the matrix can be diagonalized at all, even with numbers that may not be real. Examples ======== Example of a diagonalizable matrix: >>> from sympy import Matrix >>> M = Matrix([[1, 2, 0], [0, 3, 0], [2, -4, 2]]) >>> M.is_diagonalizable() True Example of a non-diagonalizable matrix: >>> M = Matrix([[0, 1], [0, 0]]) >>> M.is_diagonalizable() False Example of a matrix that is diagonalized in terms of non-real entries: >>> M = Matrix([[0, 1], [-1, 0]]) >>> M.is_diagonalizable(reals_only=False) True >>> M.is_diagonalizable(reals_only=True) False See Also ======== is_diagonal diagonalize """ if 'clear_cache' in kwargs: SymPyDeprecationWarning( feature='clear_cache', deprecated_since_version=1.4, issue=15887 ).warn() if 'clear_subproducts' in kwargs: SymPyDeprecationWarning( feature='clear_subproducts', deprecated_since_version=1.4, issue=15887 ).warn() if not M.is_square: return False if all(e.is_real for e in M) and M.is_symmetric(): return True if all(e.is_complex for e in M) and M.is_hermitian: return True return _is_diagonalizable_with_eigen(M, reals_only=reals_only)[0] #G&VL, Matrix Computations, Algo 5.4.2 def _householder_vector(x): if not x.cols == 1: raise ValueError("Input must be a column matrix") v = x.copy() v_plus = x.copy() v_minus = x.copy() q = x[0, 0] / abs(x[0, 0]) norm_x = x.norm() v_plus[0, 0] = x[0, 0] + q * norm_x v_minus[0, 0] = x[0, 0] - q * norm_x if x[1:, 0].norm() == 0: bet = 0 v[0, 0] = 1 else: if v_plus.norm() <= v_minus.norm(): v = v_plus else: v = v_minus v = v / v[0] bet = 2 / (v.norm() ** 2) return v, bet def _bidiagonal_decmp_hholder(M): m = M.rows n = M.cols A = M.as_mutable() U, V = A.eye(m), A.eye(n) for i in range(min(m, n)): v, bet = _householder_vector(A[i:, i]) hh_mat = A.eye(m - i) - bet * v * v.H A[i:, i:] = hh_mat * A[i:, i:] temp = A.eye(m) temp[i:, i:] = hh_mat U = U * temp if i + 1 <= n - 2: v, bet = _householder_vector(A[i, i+1:].T) hh_mat = A.eye(n - i - 1) - bet * v * v.H A[i:, i+1:] = A[i:, i+1:] * hh_mat temp = A.eye(n) temp[i+1:, i+1:] = hh_mat V = temp * V return U, A, V def _eval_bidiag_hholder(M): m = M.rows n = M.cols A = M.as_mutable() for i in range(min(m, n)): v, bet = _householder_vector(A[i:, i]) hh_mat = A.eye(m-i) - bet * v * v.H A[i:, i:] = hh_mat * A[i:, i:] if i + 1 <= n - 2: v, bet = _householder_vector(A[i, i+1:].T) hh_mat = A.eye(n - i - 1) - bet * v * v.H A[i:, i+1:] = A[i:, i+1:] * hh_mat return A def _bidiagonal_decomposition(M, upper=True): """ Returns (U,B,V.H) $A = UBV^{H}$ where A is the input matrix, and B is its Bidiagonalized form Note: Bidiagonal Computation can hang for symbolic matrices. Parameters ========== upper : bool. Whether to do upper bidiagnalization or lower. True for upper and False for lower. References ========== 1. Algorith 5.4.2, Matrix computations by Golub and Van Loan, 4th edition 2. Complex Matrix Bidiagonalization : https://github.com/vslobody/Householder-Bidiagonalization """ if type(upper) is not bool: raise ValueError("upper must be a boolean") if not upper: X = _bidiagonal_decmp_hholder(M.H) return X[2].H, X[1].H, X[0].H return _bidiagonal_decmp_hholder(M) def _bidiagonalize(M, upper=True): """ Returns $B$, the Bidiagonalized form of the input matrix. Note: Bidiagonal Computation can hang for symbolic matrices. Parameters ========== upper : bool. Whether to do upper bidiagnalization or lower. True for upper and False for lower. References ========== 1. Algorith 5.4.2, Matrix computations by Golub and Van Loan, 4th edition 2. Complex Matrix Bidiagonalization : https://github.com/vslobody/Householder-Bidiagonalization """ if type(upper) is not bool: raise ValueError("upper must be a boolean") if not upper: return _eval_bidiag_hholder(M.H).H return _eval_bidiag_hholder(M) def _diagonalize(M, reals_only=False, sort=False, normalize=False): """ Return (P, D), where D is diagonal and D = P^-1 * M * P where M is current matrix. Parameters ========== reals_only : bool. Whether to throw an error if complex numbers are need to diagonalize. (Default: False) sort : bool. Sort the eigenvalues along the diagonal. (Default: False) normalize : bool. If True, normalize the columns of P. (Default: False) Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) >>> M Matrix([ [1, 2, 0], [0, 3, 0], [2, -4, 2]]) >>> (P, D) = M.diagonalize() >>> D Matrix([ [1, 0, 0], [0, 2, 0], [0, 0, 3]]) >>> P Matrix([ [-1, 0, -1], [ 0, 0, -1], [ 2, 1, 2]]) >>> P.inv() * M * P Matrix([ [1, 0, 0], [0, 2, 0], [0, 0, 3]]) See Also ======== is_diagonal is_diagonalizable """ if not M.is_square: raise NonSquareMatrixError() is_diagonalizable, eigenvecs = _is_diagonalizable_with_eigen(M, reals_only=reals_only) if not is_diagonalizable: raise MatrixError("Matrix is not diagonalizable") if sort: eigenvecs = sorted(eigenvecs, key=default_sort_key) p_cols, diag = [], [] for val, mult, basis in eigenvecs: diag += [val] * mult p_cols += basis if normalize: p_cols = [v / v.norm() for v in p_cols] return M.hstack(*p_cols), M.diag(*diag) def _fuzzy_positive_definite(M): positive_diagonals = M._has_positive_diagonals() if positive_diagonals is False: return False if positive_diagonals and M.is_strongly_diagonally_dominant: return True return None def _fuzzy_positive_semidefinite(M): nonnegative_diagonals = M._has_nonnegative_diagonals() if nonnegative_diagonals is False: return False if nonnegative_diagonals and M.is_weakly_diagonally_dominant: return True return None def _is_positive_definite(M): if not M.is_hermitian: if not M.is_square: return False M = M + M.H fuzzy = _fuzzy_positive_definite(M) if fuzzy is not None: return fuzzy return _is_positive_definite_GE(M) def _is_positive_semidefinite(M): if not M.is_hermitian: if not M.is_square: return False M = M + M.H fuzzy = _fuzzy_positive_semidefinite(M) if fuzzy is not None: return fuzzy return _is_positive_semidefinite_cholesky(M) def _is_negative_definite(M): return _is_positive_definite(-M) def _is_negative_semidefinite(M): return _is_positive_semidefinite(-M) def _is_indefinite(M): if M.is_hermitian: eigen = M.eigenvals() args1 = [x.is_positive for x in eigen.keys()] any_positive = fuzzy_or(args1) args2 = [x.is_negative for x in eigen.keys()] any_negative = fuzzy_or(args2) return fuzzy_and([any_positive, any_negative]) elif M.is_square: return (M + M.H).is_indefinite return False def _is_positive_definite_GE(M): """A division-free gaussian elimination method for testing positive-definiteness.""" M = M.as_mutable() size = M.rows for i in range(size): is_positive = M[i, i].is_positive if is_positive is not True: return is_positive for j in range(i+1, size): M[j, i+1:] = M[i, i] * M[j, i+1:] - M[j, i] * M[i, i+1:] return True def _is_positive_semidefinite_cholesky(M): """Uses Cholesky factorization with complete pivoting References ========== .. [1] http://eprints.ma.man.ac.uk/1199/1/covered/MIMS_ep2008_116.pdf .. [2] https://www.value-at-risk.net/cholesky-factorization/ """ M = M.as_mutable() for k in range(M.rows): diags = [M[i, i] for i in range(k, M.rows)] pivot, pivot_val, nonzero, _ = _find_reasonable_pivot(diags) if nonzero: return None if pivot is None: for i in range(k+1, M.rows): for j in range(k, M.cols): iszero = M[i, j].is_zero if iszero is None: return None elif iszero is False: return False return True if M[k, k].is_negative or pivot_val.is_negative: return False elif not (M[k, k].is_nonnegative and pivot_val.is_nonnegative): return None if pivot > 0: M.col_swap(k, k+pivot) M.row_swap(k, k+pivot) M[k, k] = sqrt(M[k, k]) M[k, k+1:] /= M[k, k] M[k+1:, k+1:] -= M[k, k+1:].H * M[k, k+1:] return M[-1, -1].is_nonnegative _doc_positive_definite = \ r"""Finds out the definiteness of a matrix. Explanation =========== A square real matrix $A$ is: - A positive definite matrix if $x^T A x > 0$ for all non-zero real vectors $x$. - A positive semidefinite matrix if $x^T A x \geq 0$ for all non-zero real vectors $x$. - A negative definite matrix if $x^T A x < 0$ for all non-zero real vectors $x$. - A negative semidefinite matrix if $x^T A x \leq 0$ for all non-zero real vectors $x$. - An indefinite matrix if there exists non-zero real vectors $x, y$ with $x^T A x > 0 > y^T A y$. A square complex matrix $A$ is: - A positive definite matrix if $\text{re}(x^H A x) > 0$ for all non-zero complex vectors $x$. - A positive semidefinite matrix if $\text{re}(x^H A x) \geq 0$ for all non-zero complex vectors $x$. - A negative definite matrix if $\text{re}(x^H A x) < 0$ for all non-zero complex vectors $x$. - A negative semidefinite matrix if $\text{re}(x^H A x) \leq 0$ for all non-zero complex vectors $x$. - An indefinite matrix if there exists non-zero complex vectors $x, y$ with $\text{re}(x^H A x) > 0 > \text{re}(y^H A y)$. A matrix need not be symmetric or hermitian to be positive definite. - A real non-symmetric matrix is positive definite if and only if $\frac{A + A^T}{2}$ is positive definite. - A complex non-hermitian matrix is positive definite if and only if $\frac{A + A^H}{2}$ is positive definite. And this extension can apply for all the definitions above. However, for complex cases, you can restrict the definition of $\text{re}(x^H A x) > 0$ to $x^H A x > 0$ and require the matrix to be hermitian. But we do not present this restriction for computation because you can check ``M.is_hermitian`` independently with this and use the same procedure. Examples ======== An example of symmetric positive definite matrix: .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import Matrix, symbols >>> from sympy.plotting import plot3d >>> a, b = symbols('a b') >>> x = Matrix([a, b]) >>> A = Matrix([[1, 0], [0, 1]]) >>> A.is_positive_definite True >>> A.is_positive_semidefinite True >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) An example of symmetric positive semidefinite matrix: .. plot:: :context: close-figs :format: doctest :include-source: True >>> A = Matrix([[1, -1], [-1, 1]]) >>> A.is_positive_definite False >>> A.is_positive_semidefinite True >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) An example of symmetric negative definite matrix: .. plot:: :context: close-figs :format: doctest :include-source: True >>> A = Matrix([[-1, 0], [0, -1]]) >>> A.is_negative_definite True >>> A.is_negative_semidefinite True >>> A.is_indefinite False >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) An example of symmetric indefinite matrix: .. plot:: :context: close-figs :format: doctest :include-source: True >>> A = Matrix([[1, 2], [2, -1]]) >>> A.is_indefinite True >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) An example of non-symmetric positive definite matrix. .. plot:: :context: close-figs :format: doctest :include-source: True >>> A = Matrix([[1, 2], [-2, 1]]) >>> A.is_positive_definite True >>> A.is_positive_semidefinite True >>> p = plot3d((x.T*A*x)[0, 0], (a, -1, 1), (b, -1, 1)) Notes ===== Although some people trivialize the definition of positive definite matrices only for symmetric or hermitian matrices, this restriction is not correct because it does not classify all instances of positive definite matrices from the definition $x^T A x > 0$ or $\text{re}(x^H A x) > 0$. For instance, ``Matrix([[1, 2], [-2, 1]])`` presented in the example above is an example of real positive definite matrix that is not symmetric. However, since the following formula holds true; .. math:: \text{re}(x^H A x) > 0 \iff \text{re}(x^H \frac{A + A^H}{2} x) > 0 We can classify all positive definite matrices that may or may not be symmetric or hermitian by transforming the matrix to $\frac{A + A^T}{2}$ or $\frac{A + A^H}{2}$ (which is guaranteed to be always real symmetric or complex hermitian) and we can defer most of the studies to symmetric or hermitian positive definite matrices. But it is a different problem for the existance of Cholesky decomposition. Because even though a non symmetric or a non hermitian matrix can be positive definite, Cholesky or LDL decomposition does not exist because the decompositions require the matrix to be symmetric or hermitian. References ========== .. [1] https://en.wikipedia.org/wiki/Definiteness_of_a_matrix#Eigenvalues .. [2] http://mathworld.wolfram.com/PositiveDefiniteMatrix.html .. [3] Johnson, C. R. "Positive Definite Matrices." Amer. Math. Monthly 77, 259-264 1970. """ _is_positive_definite.__doc__ = _doc_positive_definite _is_positive_semidefinite.__doc__ = _doc_positive_definite _is_negative_definite.__doc__ = _doc_positive_definite _is_negative_semidefinite.__doc__ = _doc_positive_definite _is_indefinite.__doc__ = _doc_positive_definite def _jordan_form(M, calc_transform=True, *, chop=False): """Return $(P, J)$ where $J$ is a Jordan block matrix and $P$ is a matrix such that $M = P J P^{-1}$ Parameters ========== calc_transform : bool If ``False``, then only $J$ is returned. chop : bool All matrices are converted to exact types when computing eigenvalues and eigenvectors. As a result, there may be approximation errors. If ``chop==True``, these errors will be truncated. Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix([[ 6, 5, -2, -3], [-3, -1, 3, 3], [ 2, 1, -2, -3], [-1, 1, 5, 5]]) >>> P, J = M.jordan_form() >>> J Matrix([ [2, 1, 0, 0], [0, 2, 0, 0], [0, 0, 2, 1], [0, 0, 0, 2]]) See Also ======== jordan_block """ if not M.is_square: raise NonSquareMatrixError("Only square matrices have Jordan forms") mat = M has_floats = M.has(Float) if has_floats: try: max_prec = max(term._prec for term in M.values() if isinstance(term, Float)) except ValueError: # if no term in the matrix is explicitly a Float calling max() # will throw a error so setting max_prec to default value of 53 max_prec = 53 # setting minimum max_dps to 15 to prevent loss of precision in # matrix containing non evaluated expressions max_dps = max(prec_to_dps(max_prec), 15) def restore_floats(*args): """If ``has_floats`` is `True`, cast all ``args`` as matrices of floats.""" if has_floats: args = [m.evalf(n=max_dps, chop=chop) for m in args] if len(args) == 1: return args[0] return args # cache calculations for some speedup mat_cache = {} def eig_mat(val, pow): """Cache computations of ``(M - val*I)**pow`` for quick retrieval""" if (val, pow) in mat_cache: return mat_cache[(val, pow)] if (val, pow - 1) in mat_cache: mat_cache[(val, pow)] = mat_cache[(val, pow - 1)].multiply( mat_cache[(val, 1)], dotprodsimp=None) else: mat_cache[(val, pow)] = (mat - val*M.eye(M.rows)).pow(pow) return mat_cache[(val, pow)] # helper functions def nullity_chain(val, algebraic_multiplicity): """Calculate the sequence [0, nullity(E), nullity(E**2), ...] until it is constant where ``E = M - val*I``""" # mat.rank() is faster than computing the null space, # so use the rank-nullity theorem cols = M.cols ret = [0] nullity = cols - eig_mat(val, 1).rank() i = 2 while nullity != ret[-1]: ret.append(nullity) if nullity == algebraic_multiplicity: break nullity = cols - eig_mat(val, i).rank() i += 1 # Due to issues like #7146 and #15872, SymPy sometimes # gives the wrong rank. In this case, raise an error # instead of returning an incorrect matrix if nullity < ret[-1] or nullity > algebraic_multiplicity: raise MatrixError( "SymPy had encountered an inconsistent " "result while computing Jordan block: " "{}".format(M)) return ret def blocks_from_nullity_chain(d): """Return a list of the size of each Jordan block. If d_n is the nullity of E**n, then the number of Jordan blocks of size n is 2*d_n - d_(n-1) - d_(n+1)""" # d[0] is always the number of columns, so skip past it mid = [2*d[n] - d[n - 1] - d[n + 1] for n in range(1, len(d) - 1)] # d is assumed to plateau with "d[ len(d) ] == d[-1]", so # 2*d_n - d_(n-1) - d_(n+1) == d_n - d_(n-1) end = [d[-1] - d[-2]] if len(d) > 1 else [d[0]] return mid + end def pick_vec(small_basis, big_basis): """Picks a vector from big_basis that isn't in the subspace spanned by small_basis""" if len(small_basis) == 0: return big_basis[0] for v in big_basis: _, pivots = M.hstack(*(small_basis + [v])).echelon_form( with_pivots=True) if pivots[-1] == len(small_basis): return v # roots doesn't like Floats, so replace them with Rationals if has_floats: mat = mat.applyfunc(lambda x: nsimplify(x, rational=True)) # first calculate the jordan block structure eigs = mat.eigenvals() # Make sure that we have all roots in radical form for x in eigs: if x.has(CRootOf): raise MatrixError( "Jordan normal form is not implemented if the matrix have " "eigenvalues in CRootOf form") # most matrices have distinct eigenvalues # and so are diagonalizable. In this case, don't # do extra work! if len(eigs.keys()) == mat.cols: blocks = list(sorted(eigs.keys(), key=default_sort_key)) jordan_mat = mat.diag(*blocks) if not calc_transform: return restore_floats(jordan_mat) jordan_basis = [eig_mat(eig, 1).nullspace()[0] for eig in blocks] basis_mat = mat.hstack(*jordan_basis) return restore_floats(basis_mat, jordan_mat) block_structure = [] for eig in sorted(eigs.keys(), key=default_sort_key): algebraic_multiplicity = eigs[eig] chain = nullity_chain(eig, algebraic_multiplicity) block_sizes = blocks_from_nullity_chain(chain) # if block_sizes = = [a, b, c, ...], then the number of # Jordan blocks of size 1 is a, of size 2 is b, etc. # create an array that has (eig, block_size) with one # entry for each block size_nums = [(i+1, num) for i, num in enumerate(block_sizes)] # we expect larger Jordan blocks to come earlier size_nums.reverse() block_structure.extend( (eig, size) for size, num in size_nums for _ in range(num)) jordan_form_size = sum(size for eig, size in block_structure) if jordan_form_size != M.rows: raise MatrixError( "SymPy had encountered an inconsistent result while " "computing Jordan block. : {}".format(M)) blocks = (mat.jordan_block(size=size, eigenvalue=eig) for eig, size in block_structure) jordan_mat = mat.diag(*blocks) if not calc_transform: return restore_floats(jordan_mat) # For each generalized eigenspace, calculate a basis. # We start by looking for a vector in null( (A - eig*I)**n ) # which isn't in null( (A - eig*I)**(n-1) ) where n is # the size of the Jordan block # # Ideally we'd just loop through block_structure and # compute each generalized eigenspace. However, this # causes a lot of unneeded computation. Instead, we # go through the eigenvalues separately, since we know # their generalized eigenspaces must have bases that # are linearly independent. jordan_basis = [] for eig in sorted(eigs.keys(), key=default_sort_key): eig_basis = [] for block_eig, size in block_structure: if block_eig != eig: continue null_big = (eig_mat(eig, size)).nullspace() null_small = (eig_mat(eig, size - 1)).nullspace() # we want to pick something that is in the big basis # and not the small, but also something that is independent # of any other generalized eigenvectors from a different # generalized eigenspace sharing the same eigenvalue. vec = pick_vec(null_small + eig_basis, null_big) new_vecs = [eig_mat(eig, i).multiply(vec, dotprodsimp=None) for i in range(size)] eig_basis.extend(new_vecs) jordan_basis.extend(reversed(new_vecs)) basis_mat = mat.hstack(*jordan_basis) return restore_floats(basis_mat, jordan_mat) def _left_eigenvects(M, **flags): """Returns left eigenvectors and eigenvalues. This function returns the list of triples (eigenval, multiplicity, basis) for the left eigenvectors. Options are the same as for eigenvects(), i.e. the ``**flags`` arguments gets passed directly to eigenvects(). Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix([[0, 1, 1], [1, 0, 0], [1, 1, 1]]) >>> M.eigenvects() [(-1, 1, [Matrix([ [-1], [ 1], [ 0]])]), (0, 1, [Matrix([ [ 0], [-1], [ 1]])]), (2, 1, [Matrix([ [2/3], [1/3], [ 1]])])] >>> M.left_eigenvects() [(-1, 1, [Matrix([[-2, 1, 1]])]), (0, 1, [Matrix([[-1, -1, 1]])]), (2, 1, [Matrix([[1, 1, 1]])])] """ eigs = M.transpose().eigenvects(**flags) return [(val, mult, [l.transpose() for l in basis]) for val, mult, basis in eigs] def _singular_values(M): """Compute the singular values of a Matrix Examples ======== >>> from sympy import Matrix, Symbol >>> x = Symbol('x', real=True) >>> M = Matrix([[0, 1, 0], [0, x, 0], [-1, 0, 0]]) >>> M.singular_values() [sqrt(x**2 + 1), 1, 0] See Also ======== condition_number """ if M.rows >= M.cols: valmultpairs = M.H.multiply(M).eigenvals() else: valmultpairs = M.multiply(M.H).eigenvals() # Expands result from eigenvals into a simple list vals = [] for k, v in valmultpairs.items(): vals += [sqrt(k)] * v # dangerous! same k in several spots! # Pad with zeros if singular values are computed in reverse way, # to give consistent format. if len(vals) < M.cols: vals += [M.zero] * (M.cols - len(vals)) # sort them in descending order vals.sort(reverse=True, key=default_sort_key) return vals sympy-sympy-1.9/sympy/matrices/expressions/000077500000000000000000000000001412543434000212755ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/expressions/__init__.py000066400000000000000000000032341412543434000234100ustar00rootroot00000000000000""" A module which handles Matrix Expressions """ from .slice import MatrixSlice from .blockmatrix import BlockMatrix, BlockDiagMatrix, block_collapse, blockcut from .companion import CompanionMatrix from .funcmatrix import FunctionMatrix from .inverse import Inverse from .matadd import MatAdd from .matexpr import MatrixExpr, MatrixSymbol, matrix_symbols from .matmul import MatMul from .matpow import MatPow from .trace import Trace, trace from .determinant import Determinant, det, Permanent, per from .transpose import Transpose from .adjoint import Adjoint from .hadamard import hadamard_product, HadamardProduct, hadamard_power, HadamardPower from .diagonal import DiagonalMatrix, DiagonalOf, DiagMatrix, diagonalize_vector from .dotproduct import DotProduct from .kronecker import kronecker_product, KroneckerProduct, combine_kronecker from .permutation import PermutationMatrix, MatrixPermute from .sets import MatrixSet from .special import ZeroMatrix, Identity, OneMatrix __all__ = [ 'MatrixSlice', 'BlockMatrix', 'BlockDiagMatrix', 'block_collapse', 'blockcut', 'FunctionMatrix', 'CompanionMatrix', 'Inverse', 'MatAdd', 'Identity', 'MatrixExpr', 'MatrixSymbol', 'ZeroMatrix', 'OneMatrix', 'matrix_symbols', 'MatrixSet', 'MatMul', 'MatPow', 'Trace', 'trace', 'Determinant', 'det', 'Transpose', 'Adjoint', 'hadamard_product', 'HadamardProduct', 'hadamard_power', 'HadamardPower', 'DiagonalMatrix', 'DiagonalOf', 'DiagMatrix', 'diagonalize_vector', 'DotProduct', 'kronecker_product', 'KroneckerProduct', 'combine_kronecker', 'PermutationMatrix', 'MatrixPermute', 'Permanent', 'per' ] sympy-sympy-1.9/sympy/matrices/expressions/adjoint.py000066400000000000000000000031201412543434000232730ustar00rootroot00000000000000from sympy.core import Basic from sympy.functions import adjoint, conjugate from sympy.matrices.expressions.transpose import transpose from sympy.matrices.expressions.matexpr import MatrixExpr class Adjoint(MatrixExpr): """ The Hermitian adjoint of a matrix expression. This is a symbolic object that simply stores its argument without evaluating it. To actually compute the adjoint, use the ``adjoint()`` function. Examples ======== >>> from sympy.matrices import MatrixSymbol, Adjoint >>> from sympy.functions import adjoint >>> A = MatrixSymbol('A', 3, 5) >>> B = MatrixSymbol('B', 5, 3) >>> Adjoint(A*B) Adjoint(A*B) >>> adjoint(A*B) Adjoint(B)*Adjoint(A) >>> adjoint(A*B) == Adjoint(A*B) False >>> adjoint(A*B) == Adjoint(A*B).doit() True """ is_Adjoint = True def doit(self, **hints): arg = self.arg if hints.get('deep', True) and isinstance(arg, Basic): return adjoint(arg.doit(**hints)) else: return adjoint(self.arg) @property def arg(self): return self.args[0] @property def shape(self): return self.arg.shape[::-1] def _entry(self, i, j, **kwargs): return conjugate(self.arg._entry(j, i, **kwargs)) def _eval_adjoint(self): return self.arg def _eval_conjugate(self): return transpose(self.arg) def _eval_trace(self): from sympy.matrices.expressions.trace import Trace return conjugate(Trace(self.arg)) def _eval_transpose(self): return conjugate(self.arg) sympy-sympy-1.9/sympy/matrices/expressions/applyfunc.py000066400000000000000000000147141412543434000236570ustar00rootroot00000000000000from sympy.matrices.expressions import MatrixExpr from sympy import MatrixBase, Dummy, Lambda, Function, FunctionClass from sympy.core.sympify import sympify, _sympify class ElementwiseApplyFunction(MatrixExpr): r""" Apply function to a matrix elementwise without evaluating. Examples ======== It can be created by calling ``.applyfunc()`` on a matrix expression: >>> from sympy.matrices.expressions import MatrixSymbol >>> from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction >>> from sympy import exp >>> X = MatrixSymbol("X", 3, 3) >>> X.applyfunc(exp) Lambda(_d, exp(_d)).(X) Otherwise using the class constructor: >>> from sympy import eye >>> expr = ElementwiseApplyFunction(exp, eye(3)) >>> expr Lambda(_d, exp(_d)).(Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]])) >>> expr.doit() Matrix([ [E, 1, 1], [1, E, 1], [1, 1, E]]) Notice the difference with the real mathematical functions: >>> exp(eye(3)) Matrix([ [E, 0, 0], [0, E, 0], [0, 0, E]]) """ def __new__(cls, function, expr): expr = _sympify(expr) if not expr.is_Matrix: raise ValueError("{} must be a matrix instance.".format(expr)) if expr.shape == (1, 1): # Check if the function returns a matrix, in that case, just apply # the function instead of creating an ElementwiseApplyFunc object: ret = function(expr) if isinstance(ret, MatrixExpr): return ret if not isinstance(function, (FunctionClass, Lambda)): d = Dummy('d') function = Lambda(d, function(d)) function = sympify(function) if not isinstance(function, (FunctionClass, Lambda)): raise ValueError( "{} should be compatible with SymPy function classes." .format(function)) if 1 not in function.nargs: raise ValueError( '{} should be able to accept 1 arguments.'.format(function)) if not isinstance(function, Lambda): d = Dummy('d') function = Lambda(d, function(d)) obj = MatrixExpr.__new__(cls, function, expr) return obj @property def function(self): return self.args[0] @property def expr(self): return self.args[1] @property def shape(self): return self.expr.shape def doit(self, **kwargs): deep = kwargs.get("deep", True) expr = self.expr if deep: expr = expr.doit(**kwargs) function = self.function if isinstance(function, Lambda) and function.is_identity: # This is a Lambda containing the identity function. return expr if isinstance(expr, MatrixBase): return expr.applyfunc(self.function) elif isinstance(expr, ElementwiseApplyFunction): return ElementwiseApplyFunction( lambda x: self.function(expr.function(x)), expr.expr ).doit() else: return self def _entry(self, i, j, **kwargs): return self.function(self.expr._entry(i, j, **kwargs)) def _get_function_fdiff(self): d = Dummy("d") function = self.function(d) fdiff = function.diff(d) if isinstance(fdiff, Function): fdiff = type(fdiff) else: fdiff = Lambda(d, fdiff) return fdiff def _eval_derivative(self, x): from sympy import hadamard_product dexpr = self.expr.diff(x) fdiff = self._get_function_fdiff() return hadamard_product( dexpr, ElementwiseApplyFunction(fdiff, self.expr) ) def _eval_derivative_matrix_lines(self, x): from sympy import Identity from sympy.tensor.array.expressions.array_expressions import ArrayContraction from sympy.tensor.array.expressions.array_expressions import ArrayDiagonal from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct from sympy.core.expr import ExprBuilder fdiff = self._get_function_fdiff() lr = self.expr._eval_derivative_matrix_lines(x) ewdiff = ElementwiseApplyFunction(fdiff, self.expr) if 1 in x.shape: # Vector: iscolumn = self.shape[1] == 1 for i in lr: if iscolumn: ptr1 = i.first_pointer ptr2 = Identity(self.shape[1]) else: ptr1 = Identity(self.shape[0]) ptr2 = i.second_pointer subexpr = ExprBuilder( ArrayDiagonal, [ ExprBuilder( ArrayTensorProduct, [ ewdiff, ptr1, ptr2, ] ), (0, 2) if iscolumn else (1, 4) ], validator=ArrayDiagonal._validate ) i._lines = [subexpr] i._first_pointer_parent = subexpr.args[0].args i._first_pointer_index = 1 i._second_pointer_parent = subexpr.args[0].args i._second_pointer_index = 2 else: # Matrix case: for i in lr: ptr1 = i.first_pointer ptr2 = i.second_pointer newptr1 = Identity(ptr1.shape[1]) newptr2 = Identity(ptr2.shape[1]) subexpr = ExprBuilder( ArrayContraction, [ ExprBuilder( ArrayTensorProduct, [ptr1, newptr1, ewdiff, ptr2, newptr2] ), (1, 2, 4), (5, 7, 8), ], validator=ArrayContraction._validate ) i._first_pointer_parent = subexpr.args[0].args i._first_pointer_index = 1 i._second_pointer_parent = subexpr.args[0].args i._second_pointer_index = 4 i._lines = [subexpr] return lr def _eval_transpose(self): from sympy import Transpose return self.func(self.function, Transpose(self.expr).doit()) sympy-sympy-1.9/sympy/matrices/expressions/blockmatrix.py000066400000000000000000000754151412543434000242020ustar00rootroot00000000000000from sympy import ask, Q from sympy.core import Basic, Add, Mul, S from sympy.core.sympify import _sympify from sympy.matrices.common import NonInvertibleMatrixError from sympy.strategies import typed, exhaust, condition, do_one, unpack from sympy.strategies.traverse import bottom_up from sympy.utilities import sift from sympy.utilities.misc import filldedent from sympy.matrices.expressions.matexpr import MatrixExpr, MatrixElement from sympy.matrices.expressions.matmul import MatMul from sympy.matrices.expressions.matadd import MatAdd from sympy.matrices.expressions.matpow import MatPow from sympy.matrices.expressions.transpose import Transpose, transpose from sympy.matrices.expressions.trace import trace from sympy.matrices.expressions.determinant import det, Determinant from sympy.matrices.expressions.slice import MatrixSlice from sympy.matrices.expressions.inverse import Inverse from sympy.matrices.expressions.special import ZeroMatrix, Identity from sympy.matrices import Matrix, ShapeError from sympy.functions.elementary.complexes import re, im class BlockMatrix(MatrixExpr): """A BlockMatrix is a Matrix comprised of other matrices. The submatrices are stored in a SymPy Matrix object but accessed as part of a Matrix Expression >>> from sympy import (MatrixSymbol, BlockMatrix, symbols, ... Identity, ZeroMatrix, block_collapse) >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) >>> print(B) Matrix([ [X, Z], [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]]) >>> print(block_collapse(C*B)) Matrix([[X, Z + Z*Y]]) Some matrices might be comprised of rows of blocks with the matrices in each row having the same height and the rows all having the same total number of columns but not having the same number of columns for each matrix in each row. In this case, the matrix is not a block matrix and should be instantiated by Matrix. >>> from sympy import ones, Matrix >>> dat = [ ... [ones(3,2), ones(3,3)*2], ... [ones(2,3)*3, ones(2,2)*4]] ... >>> BlockMatrix(dat) Traceback (most recent call last): ... ValueError: Although this matrix is comprised of blocks, the blocks do not fill the matrix in a size-symmetric fashion. To create a full matrix from these arguments, pass them directly to Matrix. >>> Matrix(dat) Matrix([ [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [3, 3, 3, 4, 4], [3, 3, 3, 4, 4]]) See Also ======== sympy.matrices.matrices.MatrixBase.irregular """ def __new__(cls, *args, **kwargs): from sympy.matrices.immutable import ImmutableDenseMatrix from sympy.utilities.iterables import is_sequence isMat = lambda i: getattr(i, 'is_Matrix', False) if len(args) != 1 or \ not is_sequence(args[0]) or \ len({isMat(r) for r in args[0]}) != 1: raise ValueError(filldedent(''' expecting a sequence of 1 or more rows containing Matrices.''')) rows = args[0] if args else [] if not isMat(rows): if rows and isMat(rows[0]): rows = [rows] # rows is not list of lists or [] # regularity check # same number of matrices in each row blocky = ok = len({len(r) for r in rows}) == 1 if ok: # same number of rows for each matrix in a row for r in rows: ok = len({i.rows for i in r}) == 1 if not ok: break blocky = ok if ok: # same number of cols for each matrix in each col for c in range(len(rows[0])): ok = len({rows[i][c].cols for i in range(len(rows))}) == 1 if not ok: break if not ok: # same total cols in each row ok = len({ sum([i.cols for i in r]) for r in rows}) == 1 if blocky and ok: raise ValueError(filldedent(''' Although this matrix is comprised of blocks, the blocks do not fill the matrix in a size-symmetric fashion. To create a full matrix from these arguments, pass them directly to Matrix.''')) raise ValueError(filldedent(''' When there are not the same number of rows in each row's matrices or there are not the same number of total columns in each row, the matrix is not a block matrix. If this matrix is known to consist of blocks fully filling a 2-D space then see Matrix.irregular.''')) mat = ImmutableDenseMatrix(rows, evaluate=False) obj = Basic.__new__(cls, mat) return obj @property def shape(self): numrows = numcols = 0 M = self.blocks for i in range(M.shape[0]): numrows += M[i, 0].shape[0] for i in range(M.shape[1]): numcols += M[0, i].shape[1] return (numrows, numcols) @property def blockshape(self): return self.blocks.shape @property def blocks(self): return self.args[0] @property def rowblocksizes(self): return [self.blocks[i, 0].rows for i in range(self.blockshape[0])] @property def colblocksizes(self): return [self.blocks[0, i].cols for i in range(self.blockshape[1])] def structurally_equal(self, other): return (isinstance(other, BlockMatrix) and self.shape == other.shape and self.blockshape == other.blockshape and self.rowblocksizes == other.rowblocksizes and self.colblocksizes == other.colblocksizes) def _blockmul(self, other): if (isinstance(other, BlockMatrix) and self.colblocksizes == other.rowblocksizes): return BlockMatrix(self.blocks*other.blocks) return self * other def _blockadd(self, other): if (isinstance(other, BlockMatrix) and self.structurally_equal(other)): return BlockMatrix(self.blocks + other.blocks) return self + other def _eval_transpose(self): # Flip all the individual matrices matrices = [transpose(matrix) for matrix in self.blocks] # Make a copy M = Matrix(self.blockshape[0], self.blockshape[1], matrices) # Transpose the block structure M = M.transpose() return BlockMatrix(M) def _eval_trace(self): if self.rowblocksizes == self.colblocksizes: return Add(*[trace(self.blocks[i, i]) for i in range(self.blockshape[0])]) raise NotImplementedError( "Can't perform trace of irregular blockshape") def _eval_determinant(self): if self.blockshape == (1, 1): return det(self.blocks[0, 0]) if self.blockshape == (2, 2): [[A, B], [C, D]] = self.blocks.tolist() if ask(Q.invertible(A)): return det(A)*det(D - C*A.I*B) elif ask(Q.invertible(D)): return det(D)*det(A - B*D.I*C) return Determinant(self) def as_real_imag(self): real_matrices = [re(matrix) for matrix in self.blocks] real_matrices = Matrix(self.blockshape[0], self.blockshape[1], real_matrices) im_matrices = [im(matrix) for matrix in self.blocks] im_matrices = Matrix(self.blockshape[0], self.blockshape[1], im_matrices) return (real_matrices, im_matrices) def transpose(self): """Return transpose of matrix. Examples ======== >>> from sympy import MatrixSymbol, BlockMatrix, ZeroMatrix >>> from sympy.abc import m, n >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m,n), Y]]) >>> B.transpose() Matrix([ [X.T, 0], [Z.T, Y.T]]) >>> _.transpose() Matrix([ [X, Z], [0, Y]]) """ return self._eval_transpose() def schur(self, mat = 'A', generalized = False): """Return the Schur Complement of the 2x2 BlockMatrix Parameters ========== mat : String, optional The matrix with respect to which the Schur Complement is calculated. 'A' is used by default generalized : bool, optional If True, returns the generalized Schur Component which uses Moore-Penrose Inverse Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) The default Schur Complement is evaluated with "A" >>> X.schur() -C*A**(-1)*B + D >>> X.schur('D') A - B*D**(-1)*C Schur complement with non-invertible matrices is not defined. Instead, the generalized Schur complement can be calculated which uses the Moore-Penrose Inverse. To achieve this, `generalized` must be set to `True` >>> X.schur('B', generalized=True) C - D*(B.T*B)**(-1)*B.T*A >>> X.schur('C', generalized=True) -A*(C.T*C)**(-1)*C.T*D + B Returns ======= M : Matrix The Schur Complement Matrix Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If given matrix is non-invertible References ========== .. [1] Wikipedia Article on Schur Component : https://en.wikipedia.org/wiki/Schur_complement See Also ======== sympy.matrices.matrices.MatrixBase.pinv """ if self.blockshape == (2, 2): [[A, B], [C, D]] = self.blocks.tolist() d={'A' : A, 'B' : B, 'C' : C, 'D' : D} try: inv = (d[mat].T*d[mat]).inv()*d[mat].T if generalized else d[mat].inv() if mat == 'A': return D - C * inv * B elif mat == 'B': return C - D * inv * A elif mat == 'C': return B - A * inv * D elif mat == 'D': return A - B * inv * C #For matrices where no sub-matrix is square return self except NonInvertibleMatrixError: raise NonInvertibleMatrixError('The given matrix is not invertible. Please set generalized=True \ to compute the generalized Schur Complement which uses Moore-Penrose Inverse') else: raise ShapeError('Schur Complement can only be calculated for 2x2 block matrices') def LDUdecomposition(self): """Returns the Block LDU decomposition of a 2x2 Block Matrix Returns ======= (L, D, U) : Matrices L : Lower Diagonal Matrix D : Diagonal Matrix U : Upper Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> L, D, U = X.LDUdecomposition() >>> block_collapse(L*D*U) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "A" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition """ if self.blockshape == (2,2): [[A, B], [C, D]] = self.blocks.tolist() try: AI = A.I except NonInvertibleMatrixError: raise NonInvertibleMatrixError('Block LDU decomposition cannot be calculated when\ "A" is singular') Ip = Identity(B.shape[0]) Iq = Identity(B.shape[1]) Z = ZeroMatrix(*B.shape) L = BlockMatrix([[Ip, Z], [C*AI, Iq]]) D = BlockDiagMatrix(A, self.schur()) U = BlockMatrix([[Ip, AI*B],[Z.T, Iq]]) return L, D, U else: raise ShapeError("Block LDU decomposition is supported only for 2x2 block matrices") def UDLdecomposition(self): """Returns the Block UDL decomposition of a 2x2 Block Matrix Returns ======= (U, D, L) : Matrices U : Upper Diagonal Matrix D : Diagonal Matrix L : Lower Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> U, D, L = X.UDLdecomposition() >>> block_collapse(U*D*L) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "D" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LUdecomposition """ if self.blockshape == (2,2): [[A, B], [C, D]] = self.blocks.tolist() try: DI = D.I except NonInvertibleMatrixError: raise NonInvertibleMatrixError('Block UDL decomposition cannot be calculated when\ "D" is singular') Ip = Identity(A.shape[0]) Iq = Identity(B.shape[1]) Z = ZeroMatrix(*B.shape) U = BlockMatrix([[Ip, B*DI], [Z.T, Iq]]) D = BlockDiagMatrix(self.schur('D'), D) L = BlockMatrix([[Ip, Z],[DI*C, Iq]]) return U, D, L else: raise ShapeError("Block UDL decomposition is supported only for 2x2 block matrices") def LUdecomposition(self): """Returns the Block LU decomposition of a 2x2 Block Matrix Returns ======= (L, U) : Matrices L : Lower Diagonal Matrix U : Upper Diagonal Matrix Examples ======== >>> from sympy import symbols, MatrixSymbol, BlockMatrix, block_collapse >>> m, n = symbols('m n') >>> A = MatrixSymbol('A', n, n) >>> B = MatrixSymbol('B', n, m) >>> C = MatrixSymbol('C', m, n) >>> D = MatrixSymbol('D', m, m) >>> X = BlockMatrix([[A, B], [C, D]]) >>> L, U = X.LUdecomposition() >>> block_collapse(L*U) Matrix([ [A, B], [C, D]]) Raises ====== ShapeError If the block matrix is not a 2x2 matrix NonInvertibleMatrixError If the matrix "A" is non-invertible See Also ======== sympy.matrices.expressions.blockmatrix.BlockMatrix.UDLdecomposition sympy.matrices.expressions.blockmatrix.BlockMatrix.LDUdecomposition """ if self.blockshape == (2,2): [[A, B], [C, D]] = self.blocks.tolist() try: A = A**0.5 AI = A.I except NonInvertibleMatrixError: raise NonInvertibleMatrixError('Block LU decomposition cannot be calculated when\ "A" is singular') Z = ZeroMatrix(*B.shape) Q = self.schur()**0.5 L = BlockMatrix([[A, Z], [C*AI, Q]]) U = BlockMatrix([[A, AI*B],[Z.T, Q]]) return L, U else: raise ShapeError("Block LU decomposition is supported only for 2x2 block matrices") def _entry(self, i, j, **kwargs): # Find row entry orig_i, orig_j = i, j for row_block, numrows in enumerate(self.rowblocksizes): cmp = i < numrows if cmp == True: break elif cmp == False: i -= numrows elif row_block < self.blockshape[0] - 1: # Can't tell which block and it's not the last one, return unevaluated return MatrixElement(self, orig_i, orig_j) for col_block, numcols in enumerate(self.colblocksizes): cmp = j < numcols if cmp == True: break elif cmp == False: j -= numcols elif col_block < self.blockshape[1] - 1: return MatrixElement(self, orig_i, orig_j) return self.blocks[row_block, col_block][i, j] @property def is_Identity(self): if self.blockshape[0] != self.blockshape[1]: return False for i in range(self.blockshape[0]): for j in range(self.blockshape[1]): if i==j and not self.blocks[i, j].is_Identity: return False if i!=j and not self.blocks[i, j].is_ZeroMatrix: return False return True @property def is_structurally_symmetric(self): return self.rowblocksizes == self.colblocksizes def equals(self, other): if self == other: return True if (isinstance(other, BlockMatrix) and self.blocks == other.blocks): return True return super().equals(other) class BlockDiagMatrix(BlockMatrix): """A sparse matrix with block matrices along its diagonals Examples ======== >>> from sympy import MatrixSymbol, BlockDiagMatrix, symbols >>> n, m, l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> BlockDiagMatrix(X, Y) Matrix([ [X, 0], [0, Y]]) Notes ===== If you want to get the individual diagonal blocks, use :meth:`get_diag_blocks`. See Also ======== sympy.matrices.dense.diag """ def __new__(cls, *mats): return Basic.__new__(BlockDiagMatrix, *[_sympify(m) for m in mats]) @property def diag(self): return self.args @property def blocks(self): from sympy.matrices.immutable import ImmutableDenseMatrix mats = self.args data = [[mats[i] if i == j else ZeroMatrix(mats[i].rows, mats[j].cols) for j in range(len(mats))] for i in range(len(mats))] return ImmutableDenseMatrix(data, evaluate=False) @property def shape(self): return (sum(block.rows for block in self.args), sum(block.cols for block in self.args)) @property def blockshape(self): n = len(self.args) return (n, n) @property def rowblocksizes(self): return [block.rows for block in self.args] @property def colblocksizes(self): return [block.cols for block in self.args] def _all_square_blocks(self): """Returns true if all blocks are square""" return all(mat.is_square for mat in self.args) def _eval_determinant(self): if self._all_square_blocks(): return Mul(*[det(mat) for mat in self.args]) # At least one block is non-square. Since the entire matrix must be square we know there must # be at least two blocks in this matrix, in which case the entire matrix is necessarily rank-deficient return S.Zero def _eval_inverse(self, expand='ignored'): if self._all_square_blocks(): return BlockDiagMatrix(*[mat.inverse() for mat in self.args]) # See comment in _eval_determinant() raise NonInvertibleMatrixError('Matrix det == 0; not invertible.') def _eval_transpose(self): return BlockDiagMatrix(*[mat.transpose() for mat in self.args]) def _blockmul(self, other): if (isinstance(other, BlockDiagMatrix) and self.colblocksizes == other.rowblocksizes): return BlockDiagMatrix(*[a*b for a, b in zip(self.args, other.args)]) else: return BlockMatrix._blockmul(self, other) def _blockadd(self, other): if (isinstance(other, BlockDiagMatrix) and self.blockshape == other.blockshape and self.rowblocksizes == other.rowblocksizes and self.colblocksizes == other.colblocksizes): return BlockDiagMatrix(*[a + b for a, b in zip(self.args, other.args)]) else: return BlockMatrix._blockadd(self, other) def get_diag_blocks(self): """Return the list of diagonal blocks of the matrix. Examples ======== >>> from sympy.matrices import BlockDiagMatrix, Matrix >>> A = Matrix([[1, 2], [3, 4]]) >>> B = Matrix([[5, 6], [7, 8]]) >>> M = BlockDiagMatrix(A, B) How to get diagonal blocks from the block diagonal matrix: >>> diag_blocks = M.get_diag_blocks() >>> diag_blocks[0] Matrix([ [1, 2], [3, 4]]) >>> diag_blocks[1] Matrix([ [5, 6], [7, 8]]) """ return self.args def block_collapse(expr): """Evaluates a block matrix expression >>> from sympy import MatrixSymbol, BlockMatrix, symbols, \ Identity, ZeroMatrix, block_collapse >>> n,m,l = symbols('n m l') >>> X = MatrixSymbol('X', n, n) >>> Y = MatrixSymbol('Y', m ,m) >>> Z = MatrixSymbol('Z', n, m) >>> B = BlockMatrix([[X, Z], [ZeroMatrix(m, n), Y]]) >>> print(B) Matrix([ [X, Z], [0, Y]]) >>> C = BlockMatrix([[Identity(n), Z]]) >>> print(C) Matrix([[I, Z]]) >>> print(block_collapse(C*B)) Matrix([[X, Z + Z*Y]]) """ from sympy.strategies.util import expr_fns hasbm = lambda expr: isinstance(expr, MatrixExpr) and expr.has(BlockMatrix) conditioned_rl = condition( hasbm, typed( {MatAdd: do_one(bc_matadd, bc_block_plus_ident), MatMul: do_one(bc_matmul, bc_dist), MatPow: bc_matmul, Transpose: bc_transpose, Inverse: bc_inverse, BlockMatrix: do_one(bc_unpack, deblock)} ) ) rule = exhaust( bottom_up( exhaust(conditioned_rl), fns=expr_fns ) ) result = rule(expr) doit = getattr(result, 'doit', None) if doit is not None: return doit() else: return result def bc_unpack(expr): if expr.blockshape == (1, 1): return expr.blocks[0, 0] return expr def bc_matadd(expr): args = sift(expr.args, lambda M: isinstance(M, BlockMatrix)) blocks = args[True] if not blocks: return expr nonblocks = args[False] block = blocks[0] for b in blocks[1:]: block = block._blockadd(b) if nonblocks: return MatAdd(*nonblocks) + block else: return block def bc_block_plus_ident(expr): idents = [arg for arg in expr.args if arg.is_Identity] if not idents: return expr blocks = [arg for arg in expr.args if isinstance(arg, BlockMatrix)] if (blocks and all(b.structurally_equal(blocks[0]) for b in blocks) and blocks[0].is_structurally_symmetric): block_id = BlockDiagMatrix(*[Identity(k) for k in blocks[0].rowblocksizes]) rest = [arg for arg in expr.args if not arg.is_Identity and not isinstance(arg, BlockMatrix)] return MatAdd(block_id * len(idents), *blocks, *rest).doit() return expr def bc_dist(expr): """ Turn a*[X, Y] into [a*X, a*Y] """ factor, mat = expr.as_coeff_mmul() if factor == 1: return expr unpacked = unpack(mat) if isinstance(unpacked, BlockDiagMatrix): B = unpacked.diag new_B = [factor * mat for mat in B] return BlockDiagMatrix(*new_B) elif isinstance(unpacked, BlockMatrix): B = unpacked.blocks new_B = [ [factor * B[i, j] for j in range(B.cols)] for i in range(B.rows)] return BlockMatrix(new_B) return unpacked def bc_matmul(expr): if isinstance(expr, MatPow): if expr.args[1].is_Integer: factor, matrices = (1, [expr.args[0]]*expr.args[1]) else: return expr else: factor, matrices = expr.as_coeff_matrices() i = 0 while (i+1 < len(matrices)): A, B = matrices[i:i+2] if isinstance(A, BlockMatrix) and isinstance(B, BlockMatrix): matrices[i] = A._blockmul(B) matrices.pop(i+1) elif isinstance(A, BlockMatrix): matrices[i] = A._blockmul(BlockMatrix([[B]])) matrices.pop(i+1) elif isinstance(B, BlockMatrix): matrices[i] = BlockMatrix([[A]])._blockmul(B) matrices.pop(i+1) else: i+=1 return MatMul(factor, *matrices).doit() def bc_transpose(expr): collapse = block_collapse(expr.arg) return collapse._eval_transpose() def bc_inverse(expr): if isinstance(expr.arg, BlockDiagMatrix): return expr.inverse() expr2 = blockinverse_1x1(expr) if expr != expr2: return expr2 return blockinverse_2x2(Inverse(reblock_2x2(expr.arg))) def blockinverse_1x1(expr): if isinstance(expr.arg, BlockMatrix) and expr.arg.blockshape == (1, 1): mat = Matrix([[expr.arg.blocks[0].inverse()]]) return BlockMatrix(mat) return expr def blockinverse_2x2(expr): if isinstance(expr.arg, BlockMatrix) and expr.arg.blockshape == (2, 2): # See: Inverses of 2x2 Block Matrices, Tzon-Tzer Lu and Sheng-Hua Shiou [[A, B], [C, D]] = expr.arg.blocks.tolist() formula = _choose_2x2_inversion_formula(A, B, C, D) if formula != None: MI = expr.arg.schur(formula).I if formula == 'A': AI = A.I return BlockMatrix([[AI + AI * B * MI * C * AI, -AI * B * MI], [-MI * C * AI, MI]]) if formula == 'B': BI = B.I return BlockMatrix([[-MI * D * BI, MI], [BI + BI * A * MI * D * BI, -BI * A * MI]]) if formula == 'C': CI = C.I return BlockMatrix([[-CI * D * MI, CI + CI * D * MI * A * CI], [MI, -MI * A * CI]]) if formula == 'D': DI = D.I return BlockMatrix([[MI, -MI * B * DI], [-DI * C * MI, DI + DI * C * MI * B * DI]]) return expr def _choose_2x2_inversion_formula(A, B, C, D): """ Assuming [[A, B], [C, D]] would form a valid square block matrix, find which of the classical 2x2 block matrix inversion formulas would be best suited. Returns 'A', 'B', 'C', 'D' to represent the algorithm involving inversion of the given argument or None if the matrix cannot be inverted using any of those formulas. """ # Try to find a known invertible matrix. Note that the Schur complement # is currently not being considered for this A_inv = ask(Q.invertible(A)) if A_inv == True: return 'A' B_inv = ask(Q.invertible(B)) if B_inv == True: return 'B' C_inv = ask(Q.invertible(C)) if C_inv == True: return 'C' D_inv = ask(Q.invertible(D)) if D_inv == True: return 'D' # Otherwise try to find a matrix that isn't known to be non-invertible if A_inv != False: return 'A' if B_inv != False: return 'B' if C_inv != False: return 'C' if D_inv != False: return 'D' return None def deblock(B): """ Flatten a BlockMatrix of BlockMatrices """ if not isinstance(B, BlockMatrix) or not B.blocks.has(BlockMatrix): return B wrap = lambda x: x if isinstance(x, BlockMatrix) else BlockMatrix([[x]]) bb = B.blocks.applyfunc(wrap) # everything is a block from sympy import Matrix try: MM = Matrix(0, sum(bb[0, i].blocks.shape[1] for i in range(bb.shape[1])), []) for row in range(0, bb.shape[0]): M = Matrix(bb[row, 0].blocks) for col in range(1, bb.shape[1]): M = M.row_join(bb[row, col].blocks) MM = MM.col_join(M) return BlockMatrix(MM) except ShapeError: return B def reblock_2x2(expr): """ Reblock a BlockMatrix so that it has 2x2 blocks of block matrices. If possible in such a way that the matrix continues to be invertible using the classical 2x2 block inversion formulas. """ if not isinstance(expr, BlockMatrix) or not all(d > 2 for d in expr.blockshape): return expr BM = BlockMatrix # for brevity's sake rowblocks, colblocks = expr.blockshape blocks = expr.blocks for i in range(1, rowblocks): for j in range(1, colblocks): # try to split rows at i and cols at j A = bc_unpack(BM(blocks[:i, :j])) B = bc_unpack(BM(blocks[:i, j:])) C = bc_unpack(BM(blocks[i:, :j])) D = bc_unpack(BM(blocks[i:, j:])) formula = _choose_2x2_inversion_formula(A, B, C, D) if formula is not None: return BlockMatrix([[A, B], [C, D]]) # else: nothing worked, just split upper left corner return BM([[blocks[0, 0], BM(blocks[0, 1:])], [BM(blocks[1:, 0]), BM(blocks[1:, 1:])]]) def bounds(sizes): """ Convert sequence of numbers into pairs of low-high pairs >>> from sympy.matrices.expressions.blockmatrix import bounds >>> bounds((1, 10, 50)) [(0, 1), (1, 11), (11, 61)] """ low = 0 rv = [] for size in sizes: rv.append((low, low + size)) low += size return rv def blockcut(expr, rowsizes, colsizes): """ Cut a matrix expression into Blocks >>> from sympy import ImmutableMatrix, blockcut >>> M = ImmutableMatrix(4, 4, range(16)) >>> B = blockcut(M, (1, 3), (1, 3)) >>> type(B).__name__ 'BlockMatrix' >>> ImmutableMatrix(B.blocks[0, 1]) Matrix([[1, 2, 3]]) """ rowbounds = bounds(rowsizes) colbounds = bounds(colsizes) return BlockMatrix([[MatrixSlice(expr, rowbound, colbound) for colbound in colbounds] for rowbound in rowbounds]) sympy-sympy-1.9/sympy/matrices/expressions/companion.py000066400000000000000000000032511412543434000236330ustar00rootroot00000000000000from sympy.core.singleton import S from sympy.core.sympify import _sympify from sympy.polys.polytools import Poly from .matexpr import MatrixExpr class CompanionMatrix(MatrixExpr): """A symbolic companion matrix of a polynomial. Examples ======== >>> from sympy import Poly, Symbol, symbols >>> from sympy.matrices.expressions import CompanionMatrix >>> x = Symbol('x') >>> c0, c1, c2, c3, c4 = symbols('c0:5') >>> p = Poly(c0 + c1*x + c2*x**2 + c3*x**3 + c4*x**4 + x**5, x) >>> CompanionMatrix(p) CompanionMatrix(Poly(x**5 + c4*x**4 + c3*x**3 + c2*x**2 + c1*x + c0, x, domain='ZZ[c0,c1,c2,c3,c4]')) """ def __new__(cls, poly): poly = _sympify(poly) if not isinstance(poly, Poly): raise ValueError("{} must be a Poly instance.".format(poly)) if not poly.is_monic: raise ValueError("{} must be a monic polynomial.".format(poly)) if not poly.is_univariate: raise ValueError( "{} must be a univariate polynomial.".format(poly)) if not poly.degree() >= 1: raise ValueError( "{} must have degree not less than 1.".format(poly)) return super().__new__(cls, poly) @property def shape(self): poly = self.args[0] size = poly.degree() return size, size def _entry(self, i, j): if j == self.cols - 1: return -self.args[0].all_coeffs()[-1 - i] elif i == j + 1: return S.One return S.Zero def as_explicit(self): from sympy.matrices.immutable import ImmutableDenseMatrix return ImmutableDenseMatrix.companion(self.args[0]) sympy-sympy-1.9/sympy/matrices/expressions/determinant.py000066400000000000000000000057521412543434000241720ustar00rootroot00000000000000from sympy import Basic, Expr, S, sympify from sympy.matrices.common import NonSquareMatrixError class Determinant(Expr): """Matrix Determinant Represents the determinant of a matrix expression. Examples ======== >>> from sympy import MatrixSymbol, Determinant, eye >>> A = MatrixSymbol('A', 3, 3) >>> Determinant(A) Determinant(A) >>> Determinant(eye(3)).doit() 1 """ is_commutative = True def __new__(cls, mat): mat = sympify(mat) if not mat.is_Matrix: raise TypeError("Input to Determinant, %s, not a matrix" % str(mat)) if not mat.is_square: raise NonSquareMatrixError("Det of a non-square matrix") return Basic.__new__(cls, mat) @property def arg(self): return self.args[0] @property def kind(self): return self.arg.kind.element_kind def doit(self, expand=False): try: return self.arg._eval_determinant() except (AttributeError, NotImplementedError): return self def det(matexpr): """ Matrix Determinant Examples ======== >>> from sympy import MatrixSymbol, det, eye >>> A = MatrixSymbol('A', 3, 3) >>> det(A) Determinant(A) >>> det(eye(3)) 1 """ return Determinant(matexpr).doit() class Permanent(Expr): """Matrix Permanent Represents the permanent of a matrix expression. Examples ======== >>> from sympy import MatrixSymbol, Permanent, ones >>> A = MatrixSymbol('A', 3, 3) >>> Permanent(A) Permanent(A) >>> Permanent(ones(3, 3)).doit() 6 """ def __new__(cls, mat): mat = sympify(mat) if not mat.is_Matrix: raise TypeError("Input to Permanent, %s, not a matrix" % str(mat)) return Basic.__new__(cls, mat) @property def arg(self): return self.args[0] def doit(self, expand=False): try: return self.arg.per() except (AttributeError, NotImplementedError): return self def per(matexpr): """ Matrix Permanent Examples ======== >>> from sympy import MatrixSymbol, Matrix, per, ones >>> A = MatrixSymbol('A', 3, 3) >>> per(A) Permanent(A) >>> per(ones(5, 5)) 120 >>> M = Matrix([1, 2, 5]) >>> per(M) 8 """ return Permanent(matexpr).doit() from sympy.assumptions.ask import ask, Q from sympy.assumptions.refine import handlers_dict def refine_Determinant(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine, det >>> X = MatrixSymbol('X', 2, 2) >>> det(X) Determinant(X) >>> with assuming(Q.orthogonal(X)): ... print(refine(det(X))) 1 """ if ask(Q.orthogonal(expr.arg), assumptions): return S.One elif ask(Q.singular(expr.arg), assumptions): return S.Zero elif ask(Q.unit_triangular(expr.arg), assumptions): return S.One return expr handlers_dict['Determinant'] = refine_Determinant sympy-sympy-1.9/sympy/matrices/expressions/diagonal.py000066400000000000000000000137771412543434000234440ustar00rootroot00000000000000from sympy.core.sympify import _sympify from sympy.matrices.expressions import MatrixExpr from sympy.core import S, Eq, Ge from sympy.functions.special.tensor_functions import KroneckerDelta class DiagonalMatrix(MatrixExpr): """DiagonalMatrix(M) will create a matrix expression that behaves as though all off-diagonal elements, `M[i, j]` where `i != j`, are zero. Examples ======== >>> from sympy import MatrixSymbol, DiagonalMatrix, Symbol >>> n = Symbol('n', integer=True) >>> m = Symbol('m', integer=True) >>> D = DiagonalMatrix(MatrixSymbol('x', 2, 3)) >>> D[1, 2] 0 >>> D[1, 1] x[1, 1] The length of the diagonal -- the lesser of the two dimensions of `M` -- is accessed through the `diagonal_length` property: >>> D.diagonal_length 2 >>> DiagonalMatrix(MatrixSymbol('x', n + 1, n)).diagonal_length n When one of the dimensions is symbolic the other will be treated as though it is smaller: >>> tall = DiagonalMatrix(MatrixSymbol('x', n, 3)) >>> tall.diagonal_length 3 >>> tall[10, 1] 0 When the size of the diagonal is not known, a value of None will be returned: >>> DiagonalMatrix(MatrixSymbol('x', n, m)).diagonal_length is None True """ arg = property(lambda self: self.args[0]) shape = property(lambda self: self.arg.shape) # type:ignore @property def diagonal_length(self): r, c = self.shape if r.is_Integer and c.is_Integer: m = min(r, c) elif r.is_Integer and not c.is_Integer: m = r elif c.is_Integer and not r.is_Integer: m = c elif r == c: m = r else: try: m = min(r, c) except TypeError: m = None return m def _entry(self, i, j, **kwargs): if self.diagonal_length is not None: if Ge(i, self.diagonal_length) is S.true: return S.Zero elif Ge(j, self.diagonal_length) is S.true: return S.Zero eq = Eq(i, j) if eq is S.true: return self.arg[i, i] elif eq is S.false: return S.Zero return self.arg[i, j]*KroneckerDelta(i, j) class DiagonalOf(MatrixExpr): """DiagonalOf(M) will create a matrix expression that is equivalent to the diagonal of `M`, represented as a single column matrix. Examples ======== >>> from sympy import MatrixSymbol, DiagonalOf, Symbol >>> n = Symbol('n', integer=True) >>> m = Symbol('m', integer=True) >>> x = MatrixSymbol('x', 2, 3) >>> diag = DiagonalOf(x) >>> diag.shape (2, 1) The diagonal can be addressed like a matrix or vector and will return the corresponding element of the original matrix: >>> diag[1, 0] == diag[1] == x[1, 1] True The length of the diagonal -- the lesser of the two dimensions of `M` -- is accessed through the `diagonal_length` property: >>> diag.diagonal_length 2 >>> DiagonalOf(MatrixSymbol('x', n + 1, n)).diagonal_length n When only one of the dimensions is symbolic the other will be treated as though it is smaller: >>> dtall = DiagonalOf(MatrixSymbol('x', n, 3)) >>> dtall.diagonal_length 3 When the size of the diagonal is not known, a value of None will be returned: >>> DiagonalOf(MatrixSymbol('x', n, m)).diagonal_length is None True """ arg = property(lambda self: self.args[0]) @property def shape(self): r, c = self.arg.shape if r.is_Integer and c.is_Integer: m = min(r, c) elif r.is_Integer and not c.is_Integer: m = r elif c.is_Integer and not r.is_Integer: m = c elif r == c: m = r else: try: m = min(r, c) except TypeError: m = None return m, S.One @property def diagonal_length(self): return self.shape[0] def _entry(self, i, j, **kwargs): return self.arg._entry(i, i, **kwargs) class DiagMatrix(MatrixExpr): """ Turn a vector into a diagonal matrix. """ def __new__(cls, vector): vector = _sympify(vector) obj = MatrixExpr.__new__(cls, vector) shape = vector.shape dim = shape[1] if shape[0] == 1 else shape[0] if vector.shape[0] != 1: obj._iscolumn = True else: obj._iscolumn = False obj._shape = (dim, dim) obj._vector = vector return obj @property def shape(self): return self._shape def _entry(self, i, j, **kwargs): if self._iscolumn: result = self._vector._entry(i, 0, **kwargs) else: result = self._vector._entry(0, j, **kwargs) if i != j: result *= KroneckerDelta(i, j) return result def _eval_transpose(self): return self def as_explicit(self): from sympy import diag return diag(*list(self._vector.as_explicit())) def doit(self, **hints): from sympy.assumptions import ask, Q from sympy import Transpose, Mul, MatMul from sympy import MatrixBase, eye vector = self._vector # This accounts for shape (1, 1) and identity matrices, among others: if ask(Q.diagonal(vector)): return vector if isinstance(vector, MatrixBase): ret = eye(max(vector.shape)) for i in range(ret.shape[0]): ret[i, i] = vector[i] return type(vector)(ret) if vector.is_MatMul: matrices = [arg for arg in vector.args if arg.is_Matrix] scalars = [arg for arg in vector.args if arg not in matrices] if scalars: return Mul.fromiter(scalars)*DiagMatrix(MatMul.fromiter(matrices).doit()).doit() if isinstance(vector, Transpose): vector = vector.arg return DiagMatrix(vector) def diagonalize_vector(vector): return DiagMatrix(vector).doit() sympy-sympy-1.9/sympy/matrices/expressions/dotproduct.py000066400000000000000000000035561412543434000240470ustar00rootroot00000000000000from sympy.core import Basic, Expr from sympy.core.sympify import _sympify from sympy.matrices.expressions.transpose import transpose class DotProduct(Expr): """ Dot product of vector matrices The input should be two 1 x n or n x 1 matrices. The output represents the scalar dotproduct. This is similar to using MatrixElement and MatMul, except DotProduct does not require that one vector to be a row vector and the other vector to be a column vector. >>> from sympy import MatrixSymbol, DotProduct >>> A = MatrixSymbol('A', 1, 3) >>> B = MatrixSymbol('B', 1, 3) >>> DotProduct(A, B) DotProduct(A, B) >>> DotProduct(A, B).doit() A[0, 0]*B[0, 0] + A[0, 1]*B[0, 1] + A[0, 2]*B[0, 2] """ def __new__(cls, arg1, arg2): arg1, arg2 = _sympify((arg1, arg2)) if not arg1.is_Matrix: raise TypeError("Argument 1 of DotProduct is not a matrix") if not arg2.is_Matrix: raise TypeError("Argument 2 of DotProduct is not a matrix") if not (1 in arg1.shape): raise TypeError("Argument 1 of DotProduct is not a vector") if not (1 in arg2.shape): raise TypeError("Argument 2 of DotProduct is not a vector") if set(arg1.shape) != set(arg2.shape): raise TypeError("DotProduct arguments are not the same length") return Basic.__new__(cls, arg1, arg2) def doit(self, expand=False): if self.args[0].shape == self.args[1].shape: if self.args[0].shape[0] == 1: mul = self.args[0]*transpose(self.args[1]) else: mul = transpose(self.args[0])*self.args[1] else: if self.args[0].shape[0] == 1: mul = self.args[0]*self.args[1] else: mul = transpose(self.args[0])*transpose(self.args[1]) return mul[0] sympy-sympy-1.9/sympy/matrices/expressions/factorizations.py000066400000000000000000000026401412543434000247100ustar00rootroot00000000000000from sympy.matrices.expressions import MatrixExpr from sympy import Q class Factorization(MatrixExpr): arg = property(lambda self: self.args[0]) shape = property(lambda self: self.arg.shape) # type: ignore class LofLU(Factorization): @property def predicates(self): return (Q.lower_triangular,) class UofLU(Factorization): @property def predicates(self): return (Q.upper_triangular,) class LofCholesky(LofLU): pass class UofCholesky(UofLU): pass class QofQR(Factorization): @property def predicates(self): return (Q.orthogonal,) class RofQR(Factorization): @property def predicates(self): return (Q.upper_triangular,) class EigenVectors(Factorization): @property def predicates(self): return (Q.orthogonal,) class EigenValues(Factorization): @property def predicates(self): return (Q.diagonal,) class UofSVD(Factorization): @property def predicates(self): return (Q.orthogonal,) class SofSVD(Factorization): @property def predicates(self): return (Q.diagonal,) class VofSVD(Factorization): @property def predicates(self): return (Q.orthogonal,) def lu(expr): return LofLU(expr), UofLU(expr) def qr(expr): return QofQR(expr), RofQR(expr) def eig(expr): return EigenValues(expr), EigenVectors(expr) def svd(expr): return UofSVD(expr), SofSVD(expr), VofSVD(expr) sympy-sympy-1.9/sympy/matrices/expressions/fourier.py000066400000000000000000000036331412543434000233270ustar00rootroot00000000000000from sympy.core.sympify import _sympify from sympy.matrices.expressions import MatrixExpr from sympy import S, I, sqrt, exp class DFT(MatrixExpr): r""" Returns a discrete Fourier transform matrix. The matrix is scaled with :math:`\frac{1}{\sqrt{n}}` so that it is unitary. Parameters ========== n : integer or Symbol Size of the transform. Examples ======== >>> from sympy.abc import n >>> from sympy.matrices.expressions.fourier import DFT >>> DFT(3) DFT(3) >>> DFT(3).as_explicit() Matrix([ [sqrt(3)/3, sqrt(3)/3, sqrt(3)/3], [sqrt(3)/3, sqrt(3)*exp(-2*I*pi/3)/3, sqrt(3)*exp(2*I*pi/3)/3], [sqrt(3)/3, sqrt(3)*exp(2*I*pi/3)/3, sqrt(3)*exp(-2*I*pi/3)/3]]) >>> DFT(n).shape (n, n) References ========== .. [1] https://en.wikipedia.org/wiki/DFT_matrix """ def __new__(cls, n): n = _sympify(n) cls._check_dim(n) obj = super().__new__(cls, n) return obj n = property(lambda self: self.args[0]) # type: ignore shape = property(lambda self: (self.n, self.n)) # type: ignore def _entry(self, i, j, **kwargs): w = exp(-2*S.Pi*I/self.n) return w**(i*j) / sqrt(self.n) def _eval_inverse(self): return IDFT(self.n) class IDFT(DFT): r""" Returns an inverse discrete Fourier transform matrix. The matrix is scaled with :math:`\frac{1}{\sqrt{n}}` so that it is unitary. Parameters ========== n : integer or Symbol Size of the transform Examples ======== >>> from sympy.matrices.expressions.fourier import DFT, IDFT >>> IDFT(3) IDFT(3) >>> IDFT(4)*DFT(4) I See Also ======== DFT """ def _entry(self, i, j, **kwargs): w = exp(-2*S.Pi*I/self.n) return w**(-i*j) / sqrt(self.n) def _eval_inverse(self): return DFT(self.n) sympy-sympy-1.9/sympy/matrices/expressions/funcmatrix.py000066400000000000000000000066761412543434000240460ustar00rootroot00000000000000from .matexpr import MatrixExpr from sympy.core.function import FunctionClass, Lambda from sympy.core.symbol import Dummy from sympy.core.sympify import _sympify, sympify from sympy.matrices import Matrix from sympy.functions.elementary.complexes import re, im class FunctionMatrix(MatrixExpr): """Represents a matrix using a function (``Lambda``) which gives outputs according to the coordinates of each matrix entries. Parameters ========== rows : nonnegative integer. Can be symbolic. cols : nonnegative integer. Can be symbolic. lamda : Function, Lambda or str If it is a SymPy ``Function`` or ``Lambda`` instance, it should be able to accept two arguments which represents the matrix coordinates. If it is a pure string containing python ``lambda`` semantics, it is interpreted by the SymPy parser and casted into a SymPy ``Lambda`` instance. Examples ======== Creating a ``FunctionMatrix`` from ``Lambda``: >>> from sympy import FunctionMatrix, symbols, Lambda, MatPow >>> i, j, n, m = symbols('i,j,n,m') >>> FunctionMatrix(n, m, Lambda((i, j), i + j)) FunctionMatrix(n, m, Lambda((i, j), i + j)) Creating a ``FunctionMatrix`` from a sympy function: >>> from sympy.functions import KroneckerDelta >>> X = FunctionMatrix(3, 3, KroneckerDelta) >>> X.as_explicit() Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) Creating a ``FunctionMatrix`` from a sympy undefined function: >>> from sympy.core.function import Function >>> f = Function('f') >>> X = FunctionMatrix(3, 3, f) >>> X.as_explicit() Matrix([ [f(0, 0), f(0, 1), f(0, 2)], [f(1, 0), f(1, 1), f(1, 2)], [f(2, 0), f(2, 1), f(2, 2)]]) Creating a ``FunctionMatrix`` from python ``lambda``: >>> FunctionMatrix(n, m, 'lambda i, j: i + j') FunctionMatrix(n, m, Lambda((i, j), i + j)) Example of lazy evaluation of matrix product: >>> Y = FunctionMatrix(1000, 1000, Lambda((i, j), i + j)) >>> isinstance(Y*Y, MatPow) # this is an expression object True >>> (Y**2)[10,10] # So this is evaluated lazily 342923500 Notes ===== This class provides an alternative way to represent an extremely dense matrix with entries in some form of a sequence, in a most sparse way. """ def __new__(cls, rows, cols, lamda): rows, cols = _sympify(rows), _sympify(cols) cls._check_dim(rows) cls._check_dim(cols) lamda = sympify(lamda) if not isinstance(lamda, (FunctionClass, Lambda)): raise ValueError( "{} should be compatible with SymPy function classes." .format(lamda)) if 2 not in lamda.nargs: raise ValueError( '{} should be able to accept 2 arguments.'.format(lamda)) if not isinstance(lamda, Lambda): i, j = Dummy('i'), Dummy('j') lamda = Lambda((i, j), lamda(i, j)) return super().__new__(cls, rows, cols, lamda) @property def shape(self): return self.args[0:2] @property def lamda(self): return self.args[2] def _entry(self, i, j, **kwargs): return self.lamda(i, j) def _eval_trace(self): from sympy.matrices.expressions.trace import Trace from sympy import Sum return Trace(self).rewrite(Sum).doit() def as_real_imag(self): return (re(Matrix(self)), im(Matrix(self))) sympy-sympy-1.9/sympy/matrices/expressions/hadamard.py000066400000000000000000000327261412543434000234220ustar00rootroot00000000000000from sympy.core import Mul, sympify from sympy.matrices.common import ShapeError from sympy.matrices.expressions.matexpr import MatrixExpr from sympy.matrices.expressions.special import ZeroMatrix, OneMatrix from sympy.strategies import ( unpack, flatten, condition, exhaust, rm_id, sort ) def hadamard_product(*matrices): """ Return the elementwise (aka Hadamard) product of matrices. Examples ======== >>> from sympy.matrices import hadamard_product, MatrixSymbol >>> A = MatrixSymbol('A', 2, 3) >>> B = MatrixSymbol('B', 2, 3) >>> hadamard_product(A) A >>> hadamard_product(A, B) HadamardProduct(A, B) >>> hadamard_product(A, B)[0, 1] A[0, 1]*B[0, 1] """ if not matrices: raise TypeError("Empty Hadamard product is undefined") validate(*matrices) if len(matrices) == 1: return matrices[0] else: matrices = [i for i in matrices if not i.is_Identity] return HadamardProduct(*matrices).doit() class HadamardProduct(MatrixExpr): """ Elementwise product of matrix expressions Examples ======== Hadamard product for matrix symbols: >>> from sympy.matrices import hadamard_product, HadamardProduct, MatrixSymbol >>> A = MatrixSymbol('A', 5, 5) >>> B = MatrixSymbol('B', 5, 5) >>> isinstance(hadamard_product(A, B), HadamardProduct) True Notes ===== This is a symbolic object that simply stores its argument without evaluating it. To actually compute the product, use the function ``hadamard_product()`` or ``HadamardProduct.doit`` """ is_HadamardProduct = True def __new__(cls, *args, evaluate=False, check=True): args = list(map(sympify, args)) if check: validate(*args) obj = super().__new__(cls, *args) if evaluate: obj = obj.doit(deep=False) return obj @property def shape(self): return self.args[0].shape def _entry(self, i, j, **kwargs): return Mul(*[arg._entry(i, j, **kwargs) for arg in self.args]) def _eval_transpose(self): from sympy.matrices.expressions.transpose import transpose return HadamardProduct(*list(map(transpose, self.args))) def doit(self, **ignored): expr = self.func(*[i.doit(**ignored) for i in self.args]) # Check for explicit matrices: from sympy import MatrixBase from sympy.matrices.immutable import ImmutableMatrix explicit = [i for i in expr.args if isinstance(i, MatrixBase)] if explicit: remainder = [i for i in expr.args if i not in explicit] expl_mat = ImmutableMatrix([ Mul.fromiter(i) for i in zip(*explicit) ]).reshape(*self.shape) expr = HadamardProduct(*([expl_mat] + remainder)) return canonicalize(expr) def _eval_derivative(self, x): from sympy import Add terms = [] args = list(self.args) for i in range(len(args)): factors = args[:i] + [args[i].diff(x)] + args[i+1:] terms.append(hadamard_product(*factors)) return Add.fromiter(terms) def _eval_derivative_matrix_lines(self, x): from sympy.core.expr import ExprBuilder from sympy.tensor.array.expressions.array_expressions import ArrayDiagonal from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct from sympy.matrices.expressions.matexpr import _make_matrix with_x_ind = [i for i, arg in enumerate(self.args) if arg.has(x)] lines = [] for ind in with_x_ind: left_args = self.args[:ind] right_args = self.args[ind+1:] d = self.args[ind]._eval_derivative_matrix_lines(x) hadam = hadamard_product(*(right_args + left_args)) diagonal = [(0, 2), (3, 4)] diagonal = [e for j, e in enumerate(diagonal) if self.shape[j] != 1] for i in d: l1 = i._lines[i._first_line_index] l2 = i._lines[i._second_line_index] subexpr = ExprBuilder( ArrayDiagonal, [ ExprBuilder( ArrayTensorProduct, [ ExprBuilder(_make_matrix, [l1]), hadam, ExprBuilder(_make_matrix, [l2]), ] ), *diagonal], ) i._first_pointer_parent = subexpr.args[0].args[0].args i._first_pointer_index = 0 i._second_pointer_parent = subexpr.args[0].args[2].args i._second_pointer_index = 0 i._lines = [subexpr] lines.append(i) return lines def validate(*args): if not all(arg.is_Matrix for arg in args): raise TypeError("Mix of Matrix and Scalar symbols") A = args[0] for B in args[1:]: if A.shape != B.shape: raise ShapeError("Matrices %s and %s are not aligned" % (A, B)) # TODO Implement algorithm for rewriting Hadamard product as diagonal matrix # if matmul identy matrix is multiplied. def canonicalize(x): """Canonicalize the Hadamard product ``x`` with mathematical properties. Examples ======== >>> from sympy.matrices.expressions import MatrixSymbol, HadamardProduct >>> from sympy.matrices.expressions import OneMatrix, ZeroMatrix >>> from sympy.matrices.expressions.hadamard import canonicalize >>> from sympy import init_printing >>> init_printing(use_unicode=False) >>> A = MatrixSymbol('A', 2, 2) >>> B = MatrixSymbol('B', 2, 2) >>> C = MatrixSymbol('C', 2, 2) Hadamard product associativity: >>> X = HadamardProduct(A, HadamardProduct(B, C)) >>> X A.*(B.*C) >>> canonicalize(X) A.*B.*C Hadamard product commutativity: >>> X = HadamardProduct(A, B) >>> Y = HadamardProduct(B, A) >>> X A.*B >>> Y B.*A >>> canonicalize(X) A.*B >>> canonicalize(Y) A.*B Hadamard product identity: >>> X = HadamardProduct(A, OneMatrix(2, 2)) >>> X A.*1 >>> canonicalize(X) A Absorbing element of Hadamard product: >>> X = HadamardProduct(A, ZeroMatrix(2, 2)) >>> X A.*0 >>> canonicalize(X) 0 Rewriting to Hadamard Power >>> X = HadamardProduct(A, A, A) >>> X A.*A.*A >>> canonicalize(X) .3 A Notes ===== As the Hadamard product is associative, nested products can be flattened. The Hadamard product is commutative so that factors can be sorted for canonical form. A matrix of only ones is an identity for Hadamard product, so every matrices of only ones can be removed. Any zero matrix will make the whole product a zero matrix. Duplicate elements can be collected and rewritten as HadamardPower References ========== .. [1] https://en.wikipedia.org/wiki/Hadamard_product_(matrices) """ from sympy.core.compatibility import default_sort_key # Associativity rule = condition( lambda x: isinstance(x, HadamardProduct), flatten ) fun = exhaust(rule) x = fun(x) # Identity fun = condition( lambda x: isinstance(x, HadamardProduct), rm_id(lambda x: isinstance(x, OneMatrix)) ) x = fun(x) # Absorbing by Zero Matrix def absorb(x): if any(isinstance(c, ZeroMatrix) for c in x.args): return ZeroMatrix(*x.shape) else: return x fun = condition( lambda x: isinstance(x, HadamardProduct), absorb ) x = fun(x) # Rewriting with HadamardPower if isinstance(x, HadamardProduct): from collections import Counter tally = Counter(x.args) new_arg = [] for base, exp in tally.items(): if exp == 1: new_arg.append(base) else: new_arg.append(HadamardPower(base, exp)) x = HadamardProduct(*new_arg) # Commutativity fun = condition( lambda x: isinstance(x, HadamardProduct), sort(default_sort_key) ) x = fun(x) # Unpacking x = unpack(x) return x def hadamard_power(base, exp): base = sympify(base) exp = sympify(exp) if exp == 1: return base if not base.is_Matrix: return base**exp if exp.is_Matrix: raise ValueError("cannot raise expression to a matrix") return HadamardPower(base, exp) class HadamardPower(MatrixExpr): r""" Elementwise power of matrix expressions Parameters ========== base : scalar or matrix exp : scalar or matrix Notes ===== There are four definitions for the hadamard power which can be used. Let's consider `A, B` as `(m, n)` matrices, and `a, b` as scalars. Matrix raised to a scalar exponent: .. math:: A^{\circ b} = \begin{bmatrix} A_{0, 0}^b & A_{0, 1}^b & \cdots & A_{0, n-1}^b \\ A_{1, 0}^b & A_{1, 1}^b & \cdots & A_{1, n-1}^b \\ \vdots & \vdots & \ddots & \vdots \\ A_{m-1, 0}^b & A_{m-1, 1}^b & \cdots & A_{m-1, n-1}^b \end{bmatrix} Scalar raised to a matrix exponent: .. math:: a^{\circ B} = \begin{bmatrix} a^{B_{0, 0}} & a^{B_{0, 1}} & \cdots & a^{B_{0, n-1}} \\ a^{B_{1, 0}} & a^{B_{1, 1}} & \cdots & a^{B_{1, n-1}} \\ \vdots & \vdots & \ddots & \vdots \\ a^{B_{m-1, 0}} & a^{B_{m-1, 1}} & \cdots & a^{B_{m-1, n-1}} \end{bmatrix} Matrix raised to a matrix exponent: .. math:: A^{\circ B} = \begin{bmatrix} A_{0, 0}^{B_{0, 0}} & A_{0, 1}^{B_{0, 1}} & \cdots & A_{0, n-1}^{B_{0, n-1}} \\ A_{1, 0}^{B_{1, 0}} & A_{1, 1}^{B_{1, 1}} & \cdots & A_{1, n-1}^{B_{1, n-1}} \\ \vdots & \vdots & \ddots & \vdots \\ A_{m-1, 0}^{B_{m-1, 0}} & A_{m-1, 1}^{B_{m-1, 1}} & \cdots & A_{m-1, n-1}^{B_{m-1, n-1}} \end{bmatrix} Scalar raised to a scalar exponent: .. math:: a^{\circ b} = a^b """ def __new__(cls, base, exp): base = sympify(base) exp = sympify(exp) if base.is_scalar and exp.is_scalar: return base ** exp if base.is_Matrix and exp.is_Matrix and base.shape != exp.shape: raise ValueError( 'The shape of the base {} and ' 'the shape of the exponent {} do not match.' .format(base.shape, exp.shape) ) obj = super().__new__(cls, base, exp) return obj @property def base(self): return self._args[0] @property def exp(self): return self._args[1] @property def shape(self): if self.base.is_Matrix: return self.base.shape return self.exp.shape def _entry(self, i, j, **kwargs): base = self.base exp = self.exp if base.is_Matrix: a = base._entry(i, j, **kwargs) elif base.is_scalar: a = base else: raise ValueError( 'The base {} must be a scalar or a matrix.'.format(base)) if exp.is_Matrix: b = exp._entry(i, j, **kwargs) elif exp.is_scalar: b = exp else: raise ValueError( 'The exponent {} must be a scalar or a matrix.'.format(exp)) return a ** b def _eval_transpose(self): from sympy.matrices.expressions.transpose import transpose return HadamardPower(transpose(self.base), self.exp) def _eval_derivative(self, x): from sympy import log dexp = self.exp.diff(x) logbase = self.base.applyfunc(log) dlbase = logbase.diff(x) return hadamard_product( dexp*logbase + self.exp*dlbase, self ) def _eval_derivative_matrix_lines(self, x): from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct from sympy.tensor.array.expressions.array_expressions import ArrayDiagonal from sympy.core.expr import ExprBuilder from sympy.matrices.expressions.matexpr import _make_matrix lr = self.base._eval_derivative_matrix_lines(x) for i in lr: diagonal = [(1, 2), (3, 4)] diagonal = [e for j, e in enumerate(diagonal) if self.base.shape[j] != 1] l1 = i._lines[i._first_line_index] l2 = i._lines[i._second_line_index] subexpr = ExprBuilder( ArrayDiagonal, [ ExprBuilder( ArrayTensorProduct, [ ExprBuilder(_make_matrix, [l1]), self.exp*hadamard_power(self.base, self.exp-1), ExprBuilder(_make_matrix, [l2]), ] ), *diagonal], validator=ArrayDiagonal._validate ) i._first_pointer_parent = subexpr.args[0].args[0].args i._first_pointer_index = 0 i._first_line_index = 0 i._second_pointer_parent = subexpr.args[0].args[2].args i._second_pointer_index = 0 i._second_line_index = 0 i._lines = [subexpr] return lr sympy-sympy-1.9/sympy/matrices/expressions/inverse.py000066400000000000000000000052131412543434000233230ustar00rootroot00000000000000from sympy.core.sympify import _sympify from sympy.core import S, Basic from sympy.matrices.common import NonSquareMatrixError from sympy.matrices.expressions.matpow import MatPow class Inverse(MatPow): """ The multiplicative inverse of a matrix expression This is a symbolic object that simply stores its argument without evaluating it. To actually compute the inverse, use the ``.inverse()`` method of matrices. Examples ======== >>> from sympy import MatrixSymbol, Inverse >>> A = MatrixSymbol('A', 3, 3) >>> B = MatrixSymbol('B', 3, 3) >>> Inverse(A) A**(-1) >>> A.inverse() == Inverse(A) True >>> (A*B).inverse() B**(-1)*A**(-1) >>> Inverse(A*B) (A*B)**(-1) """ is_Inverse = True exp = S.NegativeOne def __new__(cls, mat, exp=S.NegativeOne): # exp is there to make it consistent with # inverse.func(*inverse.args) == inverse mat = _sympify(mat) if not mat.is_Matrix: raise TypeError("mat should be a matrix") if not mat.is_square: raise NonSquareMatrixError("Inverse of non-square matrix %s" % mat) return Basic.__new__(cls, mat, exp) @property def arg(self): return self.args[0] @property def shape(self): return self.arg.shape def _eval_inverse(self): return self.arg def _eval_determinant(self): from sympy.matrices.expressions.determinant import det return 1/det(self.arg) def doit(self, **hints): if 'inv_expand' in hints and hints['inv_expand'] == False: return self arg = self.arg if hints.get('deep', True): arg = arg.doit(**hints) return arg.inverse() def _eval_derivative_matrix_lines(self, x): arg = self.args[0] lines = arg._eval_derivative_matrix_lines(x) for line in lines: line.first_pointer *= -self.T line.second_pointer *= self return lines from sympy.assumptions.ask import ask, Q from sympy.assumptions.refine import handlers_dict def refine_Inverse(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine >>> X = MatrixSymbol('X', 2, 2) >>> X.I X**(-1) >>> with assuming(Q.orthogonal(X)): ... print(refine(X.I)) X.T """ if ask(Q.orthogonal(expr), assumptions): return expr.arg.T elif ask(Q.unitary(expr), assumptions): return expr.arg.conjugate() elif ask(Q.singular(expr), assumptions): raise ValueError("Inverse of singular matrix %s" % expr.arg) return expr handlers_dict['Inverse'] = refine_Inverse sympy-sympy-1.9/sympy/matrices/expressions/kronecker.py000066400000000000000000000321761412543434000236430ustar00rootroot00000000000000"""Implementation of the Kronecker product""" from sympy.core import Mul, prod, sympify from sympy.functions import adjoint from sympy.matrices.common import ShapeError from sympy.matrices.expressions.matexpr import MatrixExpr from sympy.matrices.expressions.transpose import transpose from sympy.matrices.expressions.special import Identity from sympy.matrices.matrices import MatrixBase from sympy.strategies import ( canon, condition, distribute, do_one, exhaust, flatten, typed, unpack) from sympy.strategies.traverse import bottom_up from sympy.utilities import sift from .matadd import MatAdd from .matmul import MatMul from .matpow import MatPow def kronecker_product(*matrices): """ The Kronecker product of two or more arguments. This computes the explicit Kronecker product for subclasses of ``MatrixBase`` i.e. explicit matrices. Otherwise, a symbolic ``KroneckerProduct`` object is returned. Examples ======== For ``MatrixSymbol`` arguments a ``KroneckerProduct`` object is returned. Elements of this matrix can be obtained by indexing, or for MatrixSymbols with known dimension the explicit matrix can be obtained with ``.as_explicit()`` >>> from sympy.matrices import kronecker_product, MatrixSymbol >>> A = MatrixSymbol('A', 2, 2) >>> B = MatrixSymbol('B', 2, 2) >>> kronecker_product(A) A >>> kronecker_product(A, B) KroneckerProduct(A, B) >>> kronecker_product(A, B)[0, 1] A[0, 0]*B[0, 1] >>> kronecker_product(A, B).as_explicit() Matrix([ [A[0, 0]*B[0, 0], A[0, 0]*B[0, 1], A[0, 1]*B[0, 0], A[0, 1]*B[0, 1]], [A[0, 0]*B[1, 0], A[0, 0]*B[1, 1], A[0, 1]*B[1, 0], A[0, 1]*B[1, 1]], [A[1, 0]*B[0, 0], A[1, 0]*B[0, 1], A[1, 1]*B[0, 0], A[1, 1]*B[0, 1]], [A[1, 0]*B[1, 0], A[1, 0]*B[1, 1], A[1, 1]*B[1, 0], A[1, 1]*B[1, 1]]]) For explicit matrices the Kronecker product is returned as a Matrix >>> from sympy.matrices import Matrix, kronecker_product >>> sigma_x = Matrix([ ... [0, 1], ... [1, 0]]) ... >>> Isigma_y = Matrix([ ... [0, 1], ... [-1, 0]]) ... >>> kronecker_product(sigma_x, Isigma_y) Matrix([ [ 0, 0, 0, 1], [ 0, 0, -1, 0], [ 0, 1, 0, 0], [-1, 0, 0, 0]]) See Also ======== KroneckerProduct """ if not matrices: raise TypeError("Empty Kronecker product is undefined") validate(*matrices) if len(matrices) == 1: return matrices[0] else: return KroneckerProduct(*matrices).doit() class KroneckerProduct(MatrixExpr): """ The Kronecker product of two or more arguments. The Kronecker product is a non-commutative product of matrices. Given two matrices of dimension (m, n) and (s, t) it produces a matrix of dimension (m s, n t). This is a symbolic object that simply stores its argument without evaluating it. To actually compute the product, use the function ``kronecker_product()`` or call the the ``.doit()`` or ``.as_explicit()`` methods. >>> from sympy.matrices import KroneckerProduct, MatrixSymbol >>> A = MatrixSymbol('A', 5, 5) >>> B = MatrixSymbol('B', 5, 5) >>> isinstance(KroneckerProduct(A, B), KroneckerProduct) True """ is_KroneckerProduct = True def __new__(cls, *args, check=True): args = list(map(sympify, args)) if all(a.is_Identity for a in args): ret = Identity(prod(a.rows for a in args)) if all(isinstance(a, MatrixBase) for a in args): return ret.as_explicit() else: return ret if check: validate(*args) return super().__new__(cls, *args) @property def shape(self): rows, cols = self.args[0].shape for mat in self.args[1:]: rows *= mat.rows cols *= mat.cols return (rows, cols) def _entry(self, i, j, **kwargs): result = 1 for mat in reversed(self.args): i, m = divmod(i, mat.rows) j, n = divmod(j, mat.cols) result *= mat[m, n] return result def _eval_adjoint(self): return KroneckerProduct(*list(map(adjoint, self.args))).doit() def _eval_conjugate(self): return KroneckerProduct(*[a.conjugate() for a in self.args]).doit() def _eval_transpose(self): return KroneckerProduct(*list(map(transpose, self.args))).doit() def _eval_trace(self): from .trace import trace return prod(trace(a) for a in self.args) def _eval_determinant(self): from .determinant import det, Determinant if not all(a.is_square for a in self.args): return Determinant(self) m = self.rows return prod(det(a)**(m/a.rows) for a in self.args) def _eval_inverse(self): try: return KroneckerProduct(*[a.inverse() for a in self.args]) except ShapeError: from sympy.matrices.expressions.inverse import Inverse return Inverse(self) def structurally_equal(self, other): '''Determine whether two matrices have the same Kronecker product structure Examples ======== >>> from sympy import KroneckerProduct, MatrixSymbol, symbols >>> m, n = symbols(r'm, n', integer=True) >>> A = MatrixSymbol('A', m, m) >>> B = MatrixSymbol('B', n, n) >>> C = MatrixSymbol('C', m, m) >>> D = MatrixSymbol('D', n, n) >>> KroneckerProduct(A, B).structurally_equal(KroneckerProduct(C, D)) True >>> KroneckerProduct(A, B).structurally_equal(KroneckerProduct(D, C)) False >>> KroneckerProduct(A, B).structurally_equal(C) False ''' # Inspired by BlockMatrix return (isinstance(other, KroneckerProduct) and self.shape == other.shape and len(self.args) == len(other.args) and all(a.shape == b.shape for (a, b) in zip(self.args, other.args))) def has_matching_shape(self, other): '''Determine whether two matrices have the appropriate structure to bring matrix multiplication inside the KroneckerProdut Examples ======== >>> from sympy import KroneckerProduct, MatrixSymbol, symbols >>> m, n = symbols(r'm, n', integer=True) >>> A = MatrixSymbol('A', m, n) >>> B = MatrixSymbol('B', n, m) >>> KroneckerProduct(A, B).has_matching_shape(KroneckerProduct(B, A)) True >>> KroneckerProduct(A, B).has_matching_shape(KroneckerProduct(A, B)) False >>> KroneckerProduct(A, B).has_matching_shape(A) False ''' return (isinstance(other, KroneckerProduct) and self.cols == other.rows and len(self.args) == len(other.args) and all(a.cols == b.rows for (a, b) in zip(self.args, other.args))) def _eval_expand_kroneckerproduct(self, **hints): return flatten(canon(typed({KroneckerProduct: distribute(KroneckerProduct, MatAdd)}))(self)) def _kronecker_add(self, other): if self.structurally_equal(other): return self.__class__(*[a + b for (a, b) in zip(self.args, other.args)]) else: return self + other def _kronecker_mul(self, other): if self.has_matching_shape(other): return self.__class__(*[a*b for (a, b) in zip(self.args, other.args)]) else: return self * other def doit(self, **kwargs): deep = kwargs.get('deep', True) if deep: args = [arg.doit(**kwargs) for arg in self.args] else: args = self.args return canonicalize(KroneckerProduct(*args)) def validate(*args): if not all(arg.is_Matrix for arg in args): raise TypeError("Mix of Matrix and Scalar symbols") # rules def extract_commutative(kron): c_part = [] nc_part = [] for arg in kron.args: c, nc = arg.args_cnc() c_part.extend(c) nc_part.append(Mul._from_args(nc)) c_part = Mul(*c_part) if c_part != 1: return c_part*KroneckerProduct(*nc_part) return kron def matrix_kronecker_product(*matrices): """Compute the Kronecker product of a sequence of SymPy Matrices. This is the standard Kronecker product of matrices [1]. Parameters ========== matrices : tuple of MatrixBase instances The matrices to take the Kronecker product of. Returns ======= matrix : MatrixBase The Kronecker product matrix. Examples ======== >>> from sympy import Matrix >>> from sympy.matrices.expressions.kronecker import ( ... matrix_kronecker_product) >>> m1 = Matrix([[1,2],[3,4]]) >>> m2 = Matrix([[1,0],[0,1]]) >>> matrix_kronecker_product(m1, m2) Matrix([ [1, 0, 2, 0], [0, 1, 0, 2], [3, 0, 4, 0], [0, 3, 0, 4]]) >>> matrix_kronecker_product(m2, m1) Matrix([ [1, 2, 0, 0], [3, 4, 0, 0], [0, 0, 1, 2], [0, 0, 3, 4]]) References ========== [1] https://en.wikipedia.org/wiki/Kronecker_product """ # Make sure we have a sequence of Matrices if not all(isinstance(m, MatrixBase) for m in matrices): raise TypeError( 'Sequence of Matrices expected, got: %s' % repr(matrices) ) # Pull out the first element in the product. matrix_expansion = matrices[-1] # Do the kronecker product working from right to left. for mat in reversed(matrices[:-1]): rows = mat.rows cols = mat.cols # Go through each row appending kronecker product to. # running matrix_expansion. for i in range(rows): start = matrix_expansion*mat[i*cols] # Go through each column joining each item for j in range(cols - 1): start = start.row_join( matrix_expansion*mat[i*cols + j + 1] ) # If this is the first element, make it the start of the # new row. if i == 0: next = start else: next = next.col_join(start) matrix_expansion = next MatrixClass = max(matrices, key=lambda M: M._class_priority).__class__ if isinstance(matrix_expansion, MatrixClass): return matrix_expansion else: return MatrixClass(matrix_expansion) def explicit_kronecker_product(kron): # Make sure we have a sequence of Matrices if not all(isinstance(m, MatrixBase) for m in kron.args): return kron return matrix_kronecker_product(*kron.args) rules = (unpack, explicit_kronecker_product, flatten, extract_commutative) canonicalize = exhaust(condition(lambda x: isinstance(x, KroneckerProduct), do_one(*rules))) def _kronecker_dims_key(expr): if isinstance(expr, KroneckerProduct): return tuple(a.shape for a in expr.args) else: return (0,) def kronecker_mat_add(expr): from functools import reduce args = sift(expr.args, _kronecker_dims_key) nonkrons = args.pop((0,), None) if not args: return expr krons = [reduce(lambda x, y: x._kronecker_add(y), group) for group in args.values()] if not nonkrons: return MatAdd(*krons) else: return MatAdd(*krons) + nonkrons def kronecker_mat_mul(expr): # modified from block matrix code factor, matrices = expr.as_coeff_matrices() i = 0 while i < len(matrices) - 1: A, B = matrices[i:i+2] if isinstance(A, KroneckerProduct) and isinstance(B, KroneckerProduct): matrices[i] = A._kronecker_mul(B) matrices.pop(i+1) else: i += 1 return factor*MatMul(*matrices) def kronecker_mat_pow(expr): if isinstance(expr.base, KroneckerProduct) and all(a.is_square for a in expr.base.args): return KroneckerProduct(*[MatPow(a, expr.exp) for a in expr.base.args]) else: return expr def combine_kronecker(expr): """Combine KronekeckerProduct with expression. If possible write operations on KroneckerProducts of compatible shapes as a single KroneckerProduct. Examples ======== >>> from sympy.matrices.expressions import MatrixSymbol, KroneckerProduct, combine_kronecker >>> from sympy import symbols >>> m, n = symbols(r'm, n', integer=True) >>> A = MatrixSymbol('A', m, n) >>> B = MatrixSymbol('B', n, m) >>> combine_kronecker(KroneckerProduct(A, B)*KroneckerProduct(B, A)) KroneckerProduct(A*B, B*A) >>> combine_kronecker(KroneckerProduct(A, B)+KroneckerProduct(B.T, A.T)) KroneckerProduct(A + B.T, B + A.T) >>> C = MatrixSymbol('C', n, n) >>> D = MatrixSymbol('D', m, m) >>> combine_kronecker(KroneckerProduct(C, D)**m) KroneckerProduct(C**m, D**m) """ def haskron(expr): return isinstance(expr, MatrixExpr) and expr.has(KroneckerProduct) rule = exhaust( bottom_up(exhaust(condition(haskron, typed( {MatAdd: kronecker_mat_add, MatMul: kronecker_mat_mul, MatPow: kronecker_mat_pow}))))) result = rule(expr) doit = getattr(result, 'doit', None) if doit is not None: return doit() else: return result sympy-sympy-1.9/sympy/matrices/expressions/matadd.py000066400000000000000000000103521412543434000231020ustar00rootroot00000000000000from functools import reduce import operator from sympy.core import Add, Basic, sympify from sympy.core.add import add from sympy.functions import adjoint from sympy.matrices.common import ShapeError from sympy.matrices.matrices import MatrixBase from sympy.matrices.expressions.transpose import transpose from sympy.strategies import (rm_id, unpack, flatten, sort, condition, exhaust, do_one, glom) from sympy.matrices.expressions.matexpr import MatrixExpr from sympy.matrices.expressions.special import ZeroMatrix, GenericZeroMatrix from sympy.utilities import default_sort_key, sift # XXX: MatAdd should perhaps not subclass directly from Add class MatAdd(MatrixExpr, Add): """A Sum of Matrix Expressions MatAdd inherits from and operates like SymPy Add Examples ======== >>> from sympy import MatAdd, MatrixSymbol >>> A = MatrixSymbol('A', 5, 5) >>> B = MatrixSymbol('B', 5, 5) >>> C = MatrixSymbol('C', 5, 5) >>> MatAdd(A, B, C) A + B + C """ is_MatAdd = True identity = GenericZeroMatrix() def __new__(cls, *args, evaluate=False, check=False, _sympify=True): if not args: return cls.identity # This must be removed aggressively in the constructor to avoid # TypeErrors from GenericZeroMatrix().shape args = list(filter(lambda i: cls.identity != i, args)) if _sympify: args = list(map(sympify, args)) obj = Basic.__new__(cls, *args) if check: if all(not isinstance(i, MatrixExpr) for i in args): return Add.fromiter(args) validate(*args) if evaluate: if all(not isinstance(i, MatrixExpr) for i in args): return Add(*args, evaluate=True) obj = canonicalize(obj) return obj @property def shape(self): return self.args[0].shape def _entry(self, i, j, **kwargs): return Add(*[arg._entry(i, j, **kwargs) for arg in self.args]) def _eval_transpose(self): return MatAdd(*[transpose(arg) for arg in self.args]).doit() def _eval_adjoint(self): return MatAdd(*[adjoint(arg) for arg in self.args]).doit() def _eval_trace(self): from .trace import trace return Add(*[trace(arg) for arg in self.args]).doit() def doit(self, **kwargs): deep = kwargs.get('deep', True) if deep: args = [arg.doit(**kwargs) for arg in self.args] else: args = self.args return canonicalize(MatAdd(*args)) def _eval_derivative_matrix_lines(self, x): add_lines = [arg._eval_derivative_matrix_lines(x) for arg in self.args] return [j for i in add_lines for j in i] add.register_handlerclass((Add, MatAdd), MatAdd) def validate(*args): if not all(arg.is_Matrix for arg in args): raise TypeError("Mix of Matrix and Scalar symbols") A = args[0] for B in args[1:]: if A.shape != B.shape: raise ShapeError("Matrices %s and %s are not aligned"%(A, B)) factor_of = lambda arg: arg.as_coeff_mmul()[0] matrix_of = lambda arg: unpack(arg.as_coeff_mmul()[1]) def combine(cnt, mat): if cnt == 1: return mat else: return cnt * mat def merge_explicit(matadd): """ Merge explicit MatrixBase arguments Examples ======== >>> from sympy import MatrixSymbol, eye, Matrix, MatAdd, pprint >>> from sympy.matrices.expressions.matadd import merge_explicit >>> A = MatrixSymbol('A', 2, 2) >>> B = eye(2) >>> C = Matrix([[1, 2], [3, 4]]) >>> X = MatAdd(A, B, C) >>> pprint(X) [1 0] [1 2] A + [ ] + [ ] [0 1] [3 4] >>> pprint(merge_explicit(X)) [2 2] A + [ ] [3 5] """ groups = sift(matadd.args, lambda arg: isinstance(arg, MatrixBase)) if len(groups[True]) > 1: return MatAdd(*(groups[False] + [reduce(operator.add, groups[True])])) else: return matadd rules = (rm_id(lambda x: x == 0 or isinstance(x, ZeroMatrix)), unpack, flatten, glom(matrix_of, factor_of, combine), merge_explicit, sort(default_sort_key)) canonicalize = exhaust(condition(lambda x: isinstance(x, MatAdd), do_one(*rules))) sympy-sympy-1.9/sympy/matrices/expressions/matexpr.py000066400000000000000000001004001412543434000233220ustar00rootroot00000000000000from typing import Tuple as tTuple from sympy.core.logic import FuzzyBool from functools import wraps, reduce import collections from sympy.core import S, Symbol, Integer, Basic, Expr, Mul, Add from sympy.core.decorators import call_highest_priority from sympy.core.compatibility import SYMPY_INTS, default_sort_key from sympy.core.symbol import Str from sympy.core.sympify import SympifyError, _sympify from sympy.functions import conjugate, adjoint from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.matrices.common import NonSquareMatrixError from sympy.simplify import simplify from sympy.matrices.matrices import MatrixKind from sympy.utilities.misc import filldedent from sympy.multipledispatch import dispatch def _sympifyit(arg, retval=None): # This version of _sympifyit sympifies MutableMatrix objects def deco(func): @wraps(func) def __sympifyit_wrapper(a, b): try: b = _sympify(b) return func(a, b) except SympifyError: return retval return __sympifyit_wrapper return deco class MatrixExpr(Expr): """Superclass for Matrix Expressions MatrixExprs represent abstract matrices, linear transformations represented within a particular basis. Examples ======== >>> from sympy import MatrixSymbol >>> A = MatrixSymbol('A', 3, 3) >>> y = MatrixSymbol('y', 3, 1) >>> x = (A.T*A).I * A * y See Also ======== MatrixSymbol, MatAdd, MatMul, Transpose, Inverse """ # Should not be considered iterable by the # sympy.core.compatibility.iterable function. Subclass that actually are # iterable (i.e., explicit matrices) should set this to True. _iterable = False _op_priority = 11.0 is_Matrix = True # type: bool is_MatrixExpr = True # type: bool is_Identity = None # type: FuzzyBool is_Inverse = False is_Transpose = False is_ZeroMatrix = False is_MatAdd = False is_MatMul = False is_commutative = False is_number = False is_symbol = False is_scalar = False kind = MatrixKind() def __new__(cls, *args, **kwargs): args = map(_sympify, args) return Basic.__new__(cls, *args, **kwargs) # The following is adapted from the core Expr object @property def shape(self) -> tTuple[Expr, Expr]: raise NotImplementedError @property def _add_handler(self): return MatAdd @property def _mul_handler(self): return MatMul def __neg__(self): return MatMul(S.NegativeOne, self).doit() def __abs__(self): raise NotImplementedError @_sympifyit('other', NotImplemented) @call_highest_priority('__radd__') def __add__(self, other): return MatAdd(self, other, check=True).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__add__') def __radd__(self, other): return MatAdd(other, self, check=True).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__rsub__') def __sub__(self, other): return MatAdd(self, -other, check=True).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__sub__') def __rsub__(self, other): return MatAdd(other, -self, check=True).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__rmul__') def __mul__(self, other): return MatMul(self, other).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__rmul__') def __matmul__(self, other): return MatMul(self, other).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__mul__') def __rmul__(self, other): return MatMul(other, self).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__mul__') def __rmatmul__(self, other): return MatMul(other, self).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__rpow__') def __pow__(self, other): return MatPow(self, other).doit() @_sympifyit('other', NotImplemented) @call_highest_priority('__pow__') def __rpow__(self, other): raise NotImplementedError("Matrix Power not defined") @_sympifyit('other', NotImplemented) @call_highest_priority('__rtruediv__') def __truediv__(self, other): return self * other**S.NegativeOne @_sympifyit('other', NotImplemented) @call_highest_priority('__truediv__') def __rtruediv__(self, other): raise NotImplementedError() #return MatMul(other, Pow(self, S.NegativeOne)) @property def rows(self): return self.shape[0] @property def cols(self): return self.shape[1] @property def is_square(self): return self.rows == self.cols def _eval_conjugate(self): from sympy.matrices.expressions.adjoint import Adjoint from sympy.matrices.expressions.transpose import Transpose return Adjoint(Transpose(self)) def as_real_imag(self, deep=True, **hints): from sympy import I real = S.Half * (self + self._eval_conjugate()) im = (self - self._eval_conjugate())/(2*I) return (real, im) def _eval_inverse(self): from sympy.matrices.expressions.inverse import Inverse return Inverse(self) def _eval_transpose(self): return Transpose(self) def _eval_power(self, exp): """ Override this in sub-classes to implement simplification of powers. The cases where the exponent is -1, 0, 1 are already covered in MatPow.doit(), so implementations can exclude these cases. """ return MatPow(self, exp) def _eval_simplify(self, **kwargs): if self.is_Atom: return self else: return self.func(*[simplify(x, **kwargs) for x in self.args]) def _eval_adjoint(self): from sympy.matrices.expressions.adjoint import Adjoint return Adjoint(self) def _eval_derivative_n_times(self, x, n): return Basic._eval_derivative_n_times(self, x, n) def _eval_derivative(self, x): # `x` is a scalar: if self.has(x): # See if there are other methods using it: return super()._eval_derivative(x) else: return ZeroMatrix(*self.shape) @classmethod def _check_dim(cls, dim): """Helper function to check invalid matrix dimensions""" from sympy.core.assumptions import check_assumptions ok = check_assumptions(dim, integer=True, nonnegative=True) if ok is False: raise ValueError( "The dimension specification {} should be " "a nonnegative integer.".format(dim)) def _entry(self, i, j, **kwargs): raise NotImplementedError( "Indexing not implemented for %s" % self.__class__.__name__) def adjoint(self): return adjoint(self) def as_coeff_Mul(self, rational=False): """Efficiently extract the coefficient of a product. """ return S.One, self def conjugate(self): return conjugate(self) def transpose(self): from sympy.matrices.expressions.transpose import transpose return transpose(self) @property def T(self): '''Matrix transposition''' return self.transpose() def inverse(self): if not self.is_square: raise NonSquareMatrixError('Inverse of non-square matrix') return self._eval_inverse() def inv(self): return self.inverse() @property def I(self): return self.inverse() def valid_index(self, i, j): def is_valid(idx): return isinstance(idx, (int, Integer, Symbol, Expr)) return (is_valid(i) and is_valid(j) and (self.rows is None or (0 <= i) != False and (i < self.rows) != False) and (0 <= j) != False and (j < self.cols) != False) def __getitem__(self, key): if not isinstance(key, tuple) and isinstance(key, slice): from sympy.matrices.expressions.slice import MatrixSlice return MatrixSlice(self, key, (0, None, 1)) if isinstance(key, tuple) and len(key) == 2: i, j = key if isinstance(i, slice) or isinstance(j, slice): from sympy.matrices.expressions.slice import MatrixSlice return MatrixSlice(self, i, j) i, j = _sympify(i), _sympify(j) if self.valid_index(i, j) != False: return self._entry(i, j) else: raise IndexError("Invalid indices (%s, %s)" % (i, j)) elif isinstance(key, (SYMPY_INTS, Integer)): # row-wise decomposition of matrix rows, cols = self.shape # allow single indexing if number of columns is known if not isinstance(cols, Integer): raise IndexError(filldedent(''' Single indexing is only supported when the number of columns is known.''')) key = _sympify(key) i = key // cols j = key % cols if self.valid_index(i, j) != False: return self._entry(i, j) else: raise IndexError("Invalid index %s" % key) elif isinstance(key, (Symbol, Expr)): raise IndexError(filldedent(''' Only integers may be used when addressing the matrix with a single index.''')) raise IndexError("Invalid index, wanted %s[i,j]" % self) def as_explicit(self): """ Returns a dense Matrix with elements represented explicitly Returns an object of type ImmutableDenseMatrix. Examples ======== >>> from sympy import Identity >>> I = Identity(3) >>> I I >>> I.as_explicit() Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) See Also ======== as_mutable: returns mutable Matrix type """ if (not isinstance(self.rows, (SYMPY_INTS, Integer)) or not isinstance(self.cols, (SYMPY_INTS, Integer))): raise ValueError( 'Matrix with symbolic shape ' 'cannot be represented explicitly.') from sympy.matrices.immutable import ImmutableDenseMatrix return ImmutableDenseMatrix([[self[i, j] for j in range(self.cols)] for i in range(self.rows)]) def as_mutable(self): """ Returns a dense, mutable matrix with elements represented explicitly Examples ======== >>> from sympy import Identity >>> I = Identity(3) >>> I I >>> I.shape (3, 3) >>> I.as_mutable() Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) See Also ======== as_explicit: returns ImmutableDenseMatrix """ return self.as_explicit().as_mutable() def __array__(self): from numpy import empty a = empty(self.shape, dtype=object) for i in range(self.rows): for j in range(self.cols): a[i, j] = self[i, j] return a def equals(self, other): """ Test elementwise equality between matrices, potentially of different types >>> from sympy import Identity, eye >>> Identity(3).equals(eye(3)) True """ return self.as_explicit().equals(other) def canonicalize(self): return self def as_coeff_mmul(self): return 1, MatMul(self) @staticmethod def from_index_summation(expr, first_index=None, last_index=None, dimensions=None): r""" Parse expression of matrices with explicitly summed indices into a matrix expression without indices, if possible. This transformation expressed in mathematical notation: `\sum_{j=0}^{N-1} A_{i,j} B_{j,k} \Longrightarrow \mathbf{A}\cdot \mathbf{B}` Optional parameter ``first_index``: specify which free index to use as the index starting the expression. Examples ======== >>> from sympy import MatrixSymbol, MatrixExpr, Sum >>> from sympy.abc import i, j, k, l, N >>> A = MatrixSymbol("A", N, N) >>> B = MatrixSymbol("B", N, N) >>> expr = Sum(A[i, j]*B[j, k], (j, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) A*B Transposition is detected: >>> expr = Sum(A[j, i]*B[j, k], (j, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) A.T*B Detect the trace: >>> expr = Sum(A[i, i], (i, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) Trace(A) More complicated expressions: >>> expr = Sum(A[i, j]*B[k, j]*A[l, k], (j, 0, N-1), (k, 0, N-1)) >>> MatrixExpr.from_index_summation(expr) A*B.T*A.T """ from sympy import Sum, Mul, Add, MatMul, transpose, trace from sympy.strategies.traverse import bottom_up def remove_matelement(expr, i1, i2): def repl_match(pos): def func(x): if not isinstance(x, MatrixElement): return False if x.args[pos] != i1: return False if x.args[3-pos] == 0: if x.args[0].shape[2-pos] == 1: return True else: return False return True return func expr = expr.replace(repl_match(1), lambda x: x.args[0]) expr = expr.replace(repl_match(2), lambda x: transpose(x.args[0])) # Make sure that all Mul are transformed to MatMul and that they # are flattened: rule = bottom_up(lambda x: reduce(lambda a, b: a*b, x.args) if isinstance(x, (Mul, MatMul)) else x) return rule(expr) def recurse_expr(expr, index_ranges={}): if expr.is_Mul: nonmatargs = [] pos_arg = [] pos_ind = [] dlinks = {} link_ind = [] counter = 0 args_ind = [] for arg in expr.args: retvals = recurse_expr(arg, index_ranges) assert isinstance(retvals, list) if isinstance(retvals, list): for i in retvals: args_ind.append(i) else: args_ind.append(retvals) for arg_symbol, arg_indices in args_ind: if arg_indices is None: nonmatargs.append(arg_symbol) continue if isinstance(arg_symbol, MatrixElement): arg_symbol = arg_symbol.args[0] pos_arg.append(arg_symbol) pos_ind.append(arg_indices) link_ind.append([None]*len(arg_indices)) for i, ind in enumerate(arg_indices): if ind in dlinks: other_i = dlinks[ind] link_ind[counter][i] = other_i link_ind[other_i[0]][other_i[1]] = (counter, i) dlinks[ind] = (counter, i) counter += 1 counter2 = 0 lines = {} while counter2 < len(link_ind): for i, e in enumerate(link_ind): if None in e: line_start_index = (i, e.index(None)) break cur_ind_pos = line_start_index cur_line = [] index1 = pos_ind[cur_ind_pos[0]][cur_ind_pos[1]] while True: d, r = cur_ind_pos if pos_arg[d] != 1: if r % 2 == 1: cur_line.append(transpose(pos_arg[d])) else: cur_line.append(pos_arg[d]) next_ind_pos = link_ind[d][1-r] counter2 += 1 # Mark as visited, there will be no `None` anymore: link_ind[d] = (-1, -1) if next_ind_pos is None: index2 = pos_ind[d][1-r] lines[(index1, index2)] = cur_line break cur_ind_pos = next_ind_pos lines = {k: MatMul.fromiter(v) if len(v) != 1 else v[0] for k, v in lines.items()} return [(Mul.fromiter(nonmatargs), None)] + [ (MatrixElement(a, i, j), (i, j)) for (i, j), a in lines.items() ] elif expr.is_Add: res = [recurse_expr(i) for i in expr.args] d = collections.defaultdict(list) for res_addend in res: scalar = 1 for elem, indices in res_addend: if indices is None: scalar = elem continue indices = tuple(sorted(indices, key=default_sort_key)) d[indices].append(scalar*remove_matelement(elem, *indices)) scalar = 1 return [(MatrixElement(Add.fromiter(v), *k), k) for k, v in d.items()] elif isinstance(expr, KroneckerDelta): i1, i2 = expr.args shape = dimensions if shape is None: shape = [] for kr_ind in expr.args: if kr_ind not in index_ranges: continue r1, r2 = index_ranges[kr_ind] if r1 != 0: raise ValueError(f"index ranges should start from zero: {index_ranges}") shape.append(r2) if len(shape) == 0: shape = None elif len(shape) == 1: shape = (shape[0] + 1, shape[0] + 1) else: shape = (shape[0] + 1, shape[1] + 1) if shape[0] != shape[1]: raise ValueError(f"upper index ranges should be equal: {index_ranges}") identity = Identity(shape[0]) return [(MatrixElement(identity, i1, i2), (i1, i2))] elif isinstance(expr, MatrixElement): matrix_symbol, i1, i2 = expr.args if i1 in index_ranges: r1, r2 = index_ranges[i1] if r1 != 0 or matrix_symbol.shape[0] != r2+1: raise ValueError("index range mismatch: {} vs. (0, {})".format( (r1, r2), matrix_symbol.shape[0])) if i2 in index_ranges: r1, r2 = index_ranges[i2] if r1 != 0 or matrix_symbol.shape[1] != r2+1: raise ValueError("index range mismatch: {} vs. (0, {})".format( (r1, r2), matrix_symbol.shape[1])) if (i1 == i2) and (i1 in index_ranges): return [(trace(matrix_symbol), None)] return [(MatrixElement(matrix_symbol, i1, i2), (i1, i2))] elif isinstance(expr, Sum): return recurse_expr( expr.args[0], index_ranges={i[0]: i[1:] for i in expr.args[1:]} ) else: return [(expr, None)] retvals = recurse_expr(expr) factors, indices = zip(*retvals) retexpr = Mul.fromiter(factors) if len(indices) == 0 or list(set(indices)) == [None]: return retexpr if first_index is None: for i in indices: if i is not None: ind0 = i break return remove_matelement(retexpr, *ind0) else: return remove_matelement(retexpr, first_index, last_index) def applyfunc(self, func): from .applyfunc import ElementwiseApplyFunction return ElementwiseApplyFunction(func, self) @dispatch(MatrixExpr, Expr) def _eval_is_eq(lhs, rhs): # noqa:F811 return False @dispatch(MatrixExpr, MatrixExpr) # type: ignore def _eval_is_eq(lhs, rhs): # noqa:F811 if lhs.shape != rhs.shape: return False if (lhs - rhs).is_ZeroMatrix: return True def get_postprocessor(cls): def _postprocessor(expr): # To avoid circular imports, we can't have MatMul/MatAdd on the top level mat_class = {Mul: MatMul, Add: MatAdd}[cls] nonmatrices = [] matrices = [] for term in expr.args: if isinstance(term, MatrixExpr): matrices.append(term) else: nonmatrices.append(term) if not matrices: return cls._from_args(nonmatrices) if nonmatrices: if cls == Mul: for i in range(len(matrices)): if not matrices[i].is_MatrixExpr: # If one of the matrices explicit, absorb the scalar into it # (doit will combine all explicit matrices into one, so it # doesn't matter which) matrices[i] = matrices[i].__mul__(cls._from_args(nonmatrices)) nonmatrices = [] break else: # Maintain the ability to create Add(scalar, matrix) without # raising an exception. That way different algorithms can # replace matrix expressions with non-commutative symbols to # manipulate them like non-commutative scalars. return cls._from_args(nonmatrices + [mat_class(*matrices).doit(deep=False)]) if mat_class == MatAdd: return mat_class(*matrices).doit(deep=False) return mat_class(cls._from_args(nonmatrices), *matrices).doit(deep=False) return _postprocessor Basic._constructor_postprocessor_mapping[MatrixExpr] = { "Mul": [get_postprocessor(Mul)], "Add": [get_postprocessor(Add)], } def _matrix_derivative(expr, x): from sympy.tensor.array.array_derivatives import ArrayDerivative lines = expr._eval_derivative_matrix_lines(x) parts = [i.build() for i in lines] from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix parts = [[convert_array_to_matrix(j) for j in i] for i in parts] def _get_shape(elem): if isinstance(elem, MatrixExpr): return elem.shape return 1, 1 def get_rank(parts): return sum([j not in (1, None) for i in parts for j in _get_shape(i)]) ranks = [get_rank(i) for i in parts] rank = ranks[0] def contract_one_dims(parts): if len(parts) == 1: return parts[0] else: p1, p2 = parts[:2] if p2.is_Matrix: p2 = p2.T if p1 == Identity(1): pbase = p2 elif p2 == Identity(1): pbase = p1 else: pbase = p1*p2 if len(parts) == 2: return pbase else: # len(parts) > 2 if pbase.is_Matrix: raise ValueError("") return pbase*Mul.fromiter(parts[2:]) if rank <= 2: return Add.fromiter([contract_one_dims(i) for i in parts]) return ArrayDerivative(expr, x) class MatrixElement(Expr): parent = property(lambda self: self.args[0]) i = property(lambda self: self.args[1]) j = property(lambda self: self.args[2]) _diff_wrt = True is_symbol = True is_commutative = True def __new__(cls, name, n, m): n, m = map(_sympify, (n, m)) from sympy import MatrixBase if isinstance(name, (MatrixBase,)): if n.is_Integer and m.is_Integer: return name[n, m] if isinstance(name, str): name = Symbol(name) else: name = _sympify(name) if not isinstance(name.kind, MatrixKind): raise TypeError("First argument of MatrixElement should be a matrix") obj = Expr.__new__(cls, name, n, m) return obj def doit(self, **kwargs): deep = kwargs.get('deep', True) if deep: args = [arg.doit(**kwargs) for arg in self.args] else: args = self.args return args[0][args[1], args[2]] @property def indices(self): return self.args[1:] def _eval_derivative(self, v): from sympy import Sum, symbols, Dummy if not isinstance(v, MatrixElement): from sympy import MatrixBase if isinstance(self.parent, MatrixBase): return self.parent.diff(v)[self.i, self.j] return S.Zero M = self.args[0] m, n = self.parent.shape if M == v.args[0]: return KroneckerDelta(self.args[1], v.args[1], (0, m-1)) * \ KroneckerDelta(self.args[2], v.args[2], (0, n-1)) if isinstance(M, Inverse): i, j = self.args[1:] i1, i2 = symbols("z1, z2", cls=Dummy) Y = M.args[0] r1, r2 = Y.shape return -Sum(M[i, i1]*Y[i1, i2].diff(v)*M[i2, j], (i1, 0, r1-1), (i2, 0, r2-1)) if self.has(v.args[0]): return None return S.Zero class MatrixSymbol(MatrixExpr): """Symbolic representation of a Matrix object Creates a SymPy Symbol to represent a Matrix. This matrix has a shape and can be included in Matrix Expressions Examples ======== >>> from sympy import MatrixSymbol, Identity >>> A = MatrixSymbol('A', 3, 4) # A 3 by 4 Matrix >>> B = MatrixSymbol('B', 4, 3) # A 4 by 3 Matrix >>> A.shape (3, 4) >>> 2*A*B + Identity(3) I + 2*A*B """ is_commutative = False is_symbol = True _diff_wrt = True def __new__(cls, name, n, m): n, m = _sympify(n), _sympify(m) cls._check_dim(m) cls._check_dim(n) if isinstance(name, str): name = Str(name) obj = Basic.__new__(cls, name, n, m) return obj @property def shape(self): return self.args[1], self.args[2] @property def name(self): return self.args[0].name def _entry(self, i, j, **kwargs): return MatrixElement(self, i, j) @property def free_symbols(self): return {self} def _eval_simplify(self, **kwargs): return self def _eval_derivative(self, x): # x is a scalar: return ZeroMatrix(self.shape[0], self.shape[1]) def _eval_derivative_matrix_lines(self, x): if self != x: first = ZeroMatrix(x.shape[0], self.shape[0]) if self.shape[0] != 1 else S.Zero second = ZeroMatrix(x.shape[1], self.shape[1]) if self.shape[1] != 1 else S.Zero return [_LeftRightArgs( [first, second], )] else: first = Identity(self.shape[0]) if self.shape[0] != 1 else S.One second = Identity(self.shape[1]) if self.shape[1] != 1 else S.One return [_LeftRightArgs( [first, second], )] def matrix_symbols(expr): return [sym for sym in expr.free_symbols if sym.is_Matrix] class _LeftRightArgs: r""" Helper class to compute matrix derivatives. The logic: when an expression is derived by a matrix `X_{mn}`, two lines of matrix multiplications are created: the one contracted to `m` (first line), and the one contracted to `n` (second line). Transposition flips the side by which new matrices are connected to the lines. The trace connects the end of the two lines. """ def __init__(self, lines, higher=S.One): self._lines = [i for i in lines] self._first_pointer_parent = self._lines self._first_pointer_index = 0 self._first_line_index = 0 self._second_pointer_parent = self._lines self._second_pointer_index = 1 self._second_line_index = 1 self.higher = higher @property def first_pointer(self): return self._first_pointer_parent[self._first_pointer_index] @first_pointer.setter def first_pointer(self, value): self._first_pointer_parent[self._first_pointer_index] = value @property def second_pointer(self): return self._second_pointer_parent[self._second_pointer_index] @second_pointer.setter def second_pointer(self, value): self._second_pointer_parent[self._second_pointer_index] = value def __repr__(self): built = [self._build(i) for i in self._lines] return "_LeftRightArgs(lines=%s, higher=%s)" % ( built, self.higher, ) def transpose(self): self._first_pointer_parent, self._second_pointer_parent = self._second_pointer_parent, self._first_pointer_parent self._first_pointer_index, self._second_pointer_index = self._second_pointer_index, self._first_pointer_index self._first_line_index, self._second_line_index = self._second_line_index, self._first_line_index return self @staticmethod def _build(expr): from sympy.core.expr import ExprBuilder if isinstance(expr, ExprBuilder): return expr.build() if isinstance(expr, list): if len(expr) == 1: return expr[0] else: return expr[0](*[_LeftRightArgs._build(i) for i in expr[1]]) else: return expr def build(self): data = [self._build(i) for i in self._lines] if self.higher != 1: data += [self._build(self.higher)] data = [i for i in data] return data def matrix_form(self): if self.first != 1 and self.higher != 1: raise ValueError("higher dimensional array cannot be represented") def _get_shape(elem): if isinstance(elem, MatrixExpr): return elem.shape return (None, None) if _get_shape(self.first)[1] != _get_shape(self.second)[1]: # Remove one-dimensional identity matrices: # (this is needed by `a.diff(a)` where `a` is a vector) if _get_shape(self.second) == (1, 1): return self.first*self.second[0, 0] if _get_shape(self.first) == (1, 1): return self.first[1, 1]*self.second.T raise ValueError("incompatible shapes") if self.first != 1: return self.first*self.second.T else: return self.higher def rank(self): """ Number of dimensions different from trivial (warning: not related to matrix rank). """ rank = 0 if self.first != 1: rank += sum([i != 1 for i in self.first.shape]) if self.second != 1: rank += sum([i != 1 for i in self.second.shape]) if self.higher != 1: rank += 2 return rank def _multiply_pointer(self, pointer, other): from sympy.core.expr import ExprBuilder from ...tensor.array.expressions.array_expressions import ArrayTensorProduct from ...tensor.array.expressions.array_expressions import ArrayContraction subexpr = ExprBuilder( ArrayContraction, [ ExprBuilder( ArrayTensorProduct, [ pointer, other ] ), (1, 2) ], validator=ArrayContraction._validate ) return subexpr def append_first(self, other): self.first_pointer *= other def append_second(self, other): self.second_pointer *= other def _make_matrix(x): from sympy import ImmutableDenseMatrix if isinstance(x, MatrixExpr): return x return ImmutableDenseMatrix([[x]]) from .matmul import MatMul from .matadd import MatAdd from .matpow import MatPow from .transpose import Transpose from .inverse import Inverse from .special import ZeroMatrix, Identity sympy-sympy-1.9/sympy/matrices/expressions/matmul.py000066400000000000000000000331441412543434000231530ustar00rootroot00000000000000from sympy import Number from sympy.core import Mul, Basic, sympify, S from sympy.core.mul import mul from sympy.functions import adjoint from sympy.strategies import (rm_id, unpack, typed, flatten, exhaust, do_one, new) from sympy.matrices.common import ShapeError, NonInvertibleMatrixError from sympy.matrices.matrices import MatrixBase from .inverse import Inverse from .matexpr import MatrixExpr from .matpow import MatPow from .transpose import transpose from .permutation import PermutationMatrix from .special import ZeroMatrix, Identity, GenericIdentity, OneMatrix # XXX: MatMul should perhaps not subclass directly from Mul class MatMul(MatrixExpr, Mul): """ A product of matrix expressions Examples ======== >>> from sympy import MatMul, MatrixSymbol >>> A = MatrixSymbol('A', 5, 4) >>> B = MatrixSymbol('B', 4, 3) >>> C = MatrixSymbol('C', 3, 6) >>> MatMul(A, B, C) A*B*C """ is_MatMul = True identity = GenericIdentity() def __new__(cls, *args, evaluate=False, check=True, _sympify=True): if not args: return cls.identity # This must be removed aggressively in the constructor to avoid # TypeErrors from GenericIdentity().shape args = list(filter(lambda i: cls.identity != i, args)) if _sympify: args = list(map(sympify, args)) obj = Basic.__new__(cls, *args) factor, matrices = obj.as_coeff_matrices() if check: validate(*matrices) if not matrices: # Should it be # # return Basic.__neq__(cls, factor, GenericIdentity()) ? return factor if evaluate: return canonicalize(obj) return obj @property def shape(self): matrices = [arg for arg in self.args if arg.is_Matrix] return (matrices[0].rows, matrices[-1].cols) def _entry(self, i, j, expand=True, **kwargs): from sympy import Dummy, Sum, Mul, ImmutableMatrix, Integer coeff, matrices = self.as_coeff_matrices() if len(matrices) == 1: # situation like 2*X, matmul is just X return coeff * matrices[0][i, j] indices = [None]*(len(matrices) + 1) ind_ranges = [None]*(len(matrices) - 1) indices[0] = i indices[-1] = j def f(): counter = 1 while True: yield Dummy("i_%i" % counter) counter += 1 dummy_generator = kwargs.get("dummy_generator", f()) for i in range(1, len(matrices)): indices[i] = next(dummy_generator) for i, arg in enumerate(matrices[:-1]): ind_ranges[i] = arg.shape[1] - 1 matrices = [arg._entry(indices[i], indices[i+1], dummy_generator=dummy_generator) for i, arg in enumerate(matrices)] expr_in_sum = Mul.fromiter(matrices) if any(v.has(ImmutableMatrix) for v in matrices): expand = True result = coeff*Sum( expr_in_sum, *zip(indices[1:-1], [0]*len(ind_ranges), ind_ranges) ) # Don't waste time in result.doit() if the sum bounds are symbolic if not any(isinstance(v, (Integer, int)) for v in ind_ranges): expand = False return result.doit() if expand else result def as_coeff_matrices(self): scalars = [x for x in self.args if not x.is_Matrix] matrices = [x for x in self.args if x.is_Matrix] coeff = Mul(*scalars) if coeff.is_commutative is False: raise NotImplementedError("noncommutative scalars in MatMul are not supported.") return coeff, matrices def as_coeff_mmul(self): coeff, matrices = self.as_coeff_matrices() return coeff, MatMul(*matrices) def _eval_transpose(self): """Transposition of matrix multiplication. Notes ===== The following rules are applied. Transposition for matrix multiplied with another matrix: `\\left(A B\\right)^{T} = B^{T} A^{T}` Transposition for matrix multiplied with scalar: `\\left(c A\\right)^{T} = c A^{T}` References ========== .. [1] https://en.wikipedia.org/wiki/Transpose """ coeff, matrices = self.as_coeff_matrices() return MatMul( coeff, *[transpose(arg) for arg in matrices[::-1]]).doit() def _eval_adjoint(self): return MatMul(*[adjoint(arg) for arg in self.args[::-1]]).doit() def _eval_trace(self): factor, mmul = self.as_coeff_mmul() if factor != 1: from .trace import trace return factor * trace(mmul.doit()) else: raise NotImplementedError("Can't simplify any further") def _eval_determinant(self): from sympy.matrices.expressions.determinant import Determinant factor, matrices = self.as_coeff_matrices() square_matrices = only_squares(*matrices) return factor**self.rows * Mul(*list(map(Determinant, square_matrices))) def _eval_inverse(self): try: return MatMul(*[ arg.inverse() if isinstance(arg, MatrixExpr) else arg**-1 for arg in self.args[::-1]]).doit() except ShapeError: return Inverse(self) def doit(self, **kwargs): deep = kwargs.get('deep', True) if deep: args = [arg.doit(**kwargs) for arg in self.args] else: args = self.args # treat scalar*MatrixSymbol or scalar*MatPow separately expr = canonicalize(MatMul(*args)) return expr # Needed for partial compatibility with Mul def args_cnc(self, **kwargs): coeff_c = [x for x in self.args if x.is_commutative] coeff_nc = [x for x in self.args if not x.is_commutative] return [coeff_c, coeff_nc] def _eval_derivative_matrix_lines(self, x): from .transpose import Transpose with_x_ind = [i for i, arg in enumerate(self.args) if arg.has(x)] lines = [] for ind in with_x_ind: left_args = self.args[:ind] right_args = self.args[ind+1:] if right_args: right_mat = MatMul.fromiter(right_args) else: right_mat = Identity(self.shape[1]) if left_args: left_rev = MatMul.fromiter([Transpose(i).doit() if i.is_Matrix else i for i in reversed(left_args)]) else: left_rev = Identity(self.shape[0]) d = self.args[ind]._eval_derivative_matrix_lines(x) for i in d: i.append_first(left_rev) i.append_second(right_mat) lines.append(i) return lines mul.register_handlerclass((Mul, MatMul), MatMul) def validate(*matrices): """ Checks for valid shapes for args of MatMul """ for i in range(len(matrices)-1): A, B = matrices[i:i+2] if A.cols != B.rows: raise ShapeError("Matrices %s and %s are not aligned"%(A, B)) # Rules def newmul(*args): if args[0] == 1: args = args[1:] return new(MatMul, *args) def any_zeros(mul): if any([arg.is_zero or (arg.is_Matrix and arg.is_ZeroMatrix) for arg in mul.args]): matrices = [arg for arg in mul.args if arg.is_Matrix] return ZeroMatrix(matrices[0].rows, matrices[-1].cols) return mul def merge_explicit(matmul): """ Merge explicit MatrixBase arguments >>> from sympy import MatrixSymbol, Matrix, MatMul, pprint >>> from sympy.matrices.expressions.matmul import merge_explicit >>> A = MatrixSymbol('A', 2, 2) >>> B = Matrix([[1, 1], [1, 1]]) >>> C = Matrix([[1, 2], [3, 4]]) >>> X = MatMul(A, B, C) >>> pprint(X) [1 1] [1 2] A*[ ]*[ ] [1 1] [3 4] >>> pprint(merge_explicit(X)) [4 6] A*[ ] [4 6] >>> X = MatMul(B, A, C) >>> pprint(X) [1 1] [1 2] [ ]*A*[ ] [1 1] [3 4] >>> pprint(merge_explicit(X)) [1 1] [1 2] [ ]*A*[ ] [1 1] [3 4] """ if not any(isinstance(arg, MatrixBase) for arg in matmul.args): return matmul newargs = [] last = matmul.args[0] for arg in matmul.args[1:]: if isinstance(arg, (MatrixBase, Number)) and isinstance(last, (MatrixBase, Number)): last = last * arg else: newargs.append(last) last = arg newargs.append(last) return MatMul(*newargs) def remove_ids(mul): """ Remove Identities from a MatMul This is a modified version of sympy.strategies.rm_id. This is necesssary because MatMul may contain both MatrixExprs and Exprs as args. See Also ======== sympy.strategies.rm_id """ # Separate Exprs from MatrixExprs in args factor, mmul = mul.as_coeff_mmul() # Apply standard rm_id for MatMuls result = rm_id(lambda x: x.is_Identity is True)(mmul) if result != mmul: return newmul(factor, *result.args) # Recombine and return else: return mul def factor_in_front(mul): factor, matrices = mul.as_coeff_matrices() if factor != 1: return newmul(factor, *matrices) return mul def combine_powers(mul): """Combine consecutive powers with the same base into one e.g. A*A**2 -> A**3 This also cancels out the possible matrix inverses using the knowledgebase of ``Inverse``. e.g. Y * X * X.I -> Y """ factor, args = mul.as_coeff_matrices() new_args = [args[0]] for B in args[1:]: A = new_args[-1] if A.is_square == False or B.is_square == False: new_args.append(B) continue if isinstance(A, MatPow): A_base, A_exp = A.args else: A_base, A_exp = A, S.One if isinstance(B, MatPow): B_base, B_exp = B.args else: B_base, B_exp = B, S.One if A_base == B_base: new_exp = A_exp + B_exp new_args[-1] = MatPow(A_base, new_exp).doit(deep=False) continue elif not isinstance(B_base, MatrixBase): try: B_base_inv = B_base.inverse() except NonInvertibleMatrixError: B_base_inv = None if B_base_inv is not None and A_base == B_base_inv: new_exp = A_exp - B_exp new_args[-1] = MatPow(A_base, new_exp).doit(deep=False) continue new_args.append(B) return newmul(factor, *new_args) def combine_permutations(mul): """Refine products of permutation matrices as the products of cycles. """ args = mul.args l = len(args) if l < 2: return mul result = [args[0]] for i in range(1, l): A = result[-1] B = args[i] if isinstance(A, PermutationMatrix) and \ isinstance(B, PermutationMatrix): cycle_1 = A.args[0] cycle_2 = B.args[0] result[-1] = PermutationMatrix(cycle_1 * cycle_2) else: result.append(B) return MatMul(*result) def combine_one_matrices(mul): """ Combine products of OneMatrix e.g. OneMatrix(2, 3) * OneMatrix(3, 4) -> 3 * OneMatrix(2, 4) """ factor, args = mul.as_coeff_matrices() new_args = [args[0]] for B in args[1:]: A = new_args[-1] if not isinstance(A, OneMatrix) or not isinstance(B, OneMatrix): new_args.append(B) continue new_args.pop() new_args.append(OneMatrix(A.shape[0], B.shape[1])) factor *= A.shape[1] return newmul(factor, *new_args) def distribute_monom(mul): """ Simplify MatMul expressions but distributing rational term to MatMul. e.g. 2*(A+B) -> 2*A + 2*B """ args = mul.args if len(args) == 2: from .matadd import MatAdd if args[0].is_MatAdd and args[1].is_Rational: return MatAdd(*[MatMul(mat, args[1]).doit() for mat in args[0].args]) if args[1].is_MatAdd and args[0].is_Rational: return MatAdd(*[MatMul(args[0], mat).doit() for mat in args[1].args]) return mul rules = ( distribute_monom, any_zeros, remove_ids, combine_one_matrices, combine_powers, unpack, rm_id(lambda x: x == 1), merge_explicit, factor_in_front, flatten, combine_permutations) canonicalize = exhaust(typed({MatMul: do_one(*rules)})) def only_squares(*matrices): """factor matrices only if they are square""" if matrices[0].rows != matrices[-1].cols: raise RuntimeError("Invalid matrices being multiplied") out = [] start = 0 for i, M in enumerate(matrices): if M.cols == matrices[start].rows: out.append(MatMul(*matrices[start:i+1]).doit()) start = i+1 return out from sympy.assumptions.ask import ask, Q from sympy.assumptions.refine import handlers_dict def refine_MatMul(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine >>> X = MatrixSymbol('X', 2, 2) >>> expr = X * X.T >>> print(expr) X*X.T >>> with assuming(Q.orthogonal(X)): ... print(refine(expr)) I """ newargs = [] exprargs = [] for args in expr.args: if args.is_Matrix: exprargs.append(args) else: newargs.append(args) last = exprargs[0] for arg in exprargs[1:]: if arg == last.T and ask(Q.orthogonal(arg), assumptions): last = Identity(arg.shape[0]) elif arg == last.conjugate() and ask(Q.unitary(arg), assumptions): last = Identity(arg.shape[0]) else: newargs.append(last) last = arg newargs.append(last) return MatMul(*newargs) handlers_dict['MatMul'] = refine_MatMul sympy-sympy-1.9/sympy/matrices/expressions/matpow.py000066400000000000000000000117221412543434000231610ustar00rootroot00000000000000from sympy.matrices.common import NonSquareMatrixError from .matexpr import MatrixExpr from .special import Identity from sympy.core import S from sympy.core.sympify import _sympify from sympy.matrices import MatrixBase class MatPow(MatrixExpr): def __new__(cls, base, exp, evaluate=False, **options): base = _sympify(base) if not base.is_Matrix: raise TypeError("MatPow base should be a matrix") if not base.is_square: raise NonSquareMatrixError("Power of non-square matrix %s" % base) exp = _sympify(exp) obj = super().__new__(cls, base, exp) if evaluate: obj = obj.doit(deep=False) return obj @property def base(self): return self.args[0] @property def exp(self): return self.args[1] @property def shape(self): return self.base.shape def _entry(self, i, j, **kwargs): from sympy.matrices.expressions import MatMul A = self.doit() if isinstance(A, MatPow): # We still have a MatPow, make an explicit MatMul out of it. if A.exp.is_Integer and A.exp.is_positive: A = MatMul(*[A.base for k in range(A.exp)]) #elif A.exp.is_Integer and self.exp.is_negative: # Note: possible future improvement: in principle we can take # positive powers of the inverse, but carefully avoid recursion, # perhaps by adding `_entry` to Inverse (as it is our subclass). # T = A.base.as_explicit().inverse() # A = MatMul(*[T for k in range(-A.exp)]) else: # Leave the expression unevaluated: from sympy.matrices.expressions.matexpr import MatrixElement return MatrixElement(self, i, j) return A[i, j] def doit(self, **kwargs): if kwargs.get('deep', True): base, exp = [arg.doit(**kwargs) for arg in self.args] else: base, exp = self.args # combine all powers, e.g. (A ** 2) ** 3 -> A ** 6 while isinstance(base, MatPow): exp *= base.args[1] base = base.args[0] if isinstance(base, MatrixBase): # Delegate return base ** exp # Handle simple cases so that _eval_power() in MatrixExpr sub-classes can ignore them if exp == S.One: return base if exp == S.Zero: return Identity(base.rows) if exp == S.NegativeOne: from sympy.matrices.expressions import Inverse return Inverse(base).doit(**kwargs) eval_power = getattr(base, '_eval_power', None) if eval_power is not None: return eval_power(exp) return MatPow(base, exp) def _eval_transpose(self): base, exp = self.args return MatPow(base.T, exp) def _eval_derivative(self, x): from sympy import Pow return Pow._eval_derivative(self, x) def _eval_derivative_matrix_lines(self, x): from sympy.core.expr import ExprBuilder from sympy.tensor.array.expressions.array_expressions import ArrayContraction from ...tensor.array.expressions.array_expressions import ArrayTensorProduct from .matmul import MatMul from .inverse import Inverse exp = self.exp if self.base.shape == (1, 1) and not exp.has(x): lr = self.base._eval_derivative_matrix_lines(x) for i in lr: subexpr = ExprBuilder( ArrayContraction, [ ExprBuilder( ArrayTensorProduct, [ Identity(1), i._lines[0], exp*self.base**(exp-1), i._lines[1], Identity(1), ] ), (0, 3, 4), (5, 7, 8) ], validator=ArrayContraction._validate ) i._first_pointer_parent = subexpr.args[0].args i._first_pointer_index = 0 i._second_pointer_parent = subexpr.args[0].args i._second_pointer_index = 4 i._lines = [subexpr] return lr if (exp > 0) == True: newexpr = MatMul.fromiter([self.base for i in range(exp)]) elif (exp == -1) == True: return Inverse(self.base)._eval_derivative_matrix_lines(x) elif (exp < 0) == True: newexpr = MatMul.fromiter([Inverse(self.base) for i in range(-exp)]) elif (exp == 0) == True: return self.doit()._eval_derivative_matrix_lines(x) else: raise NotImplementedError("cannot evaluate %s derived by %s" % (self, x)) return newexpr._eval_derivative_matrix_lines(x) def _eval_inverse(self): return MatPow(self.base, -self.exp) sympy-sympy-1.9/sympy/matrices/expressions/permutation.py000066400000000000000000000175341412543434000242300ustar00rootroot00000000000000from sympy.core import S from sympy.core.sympify import _sympify from sympy.functions import KroneckerDelta from .matexpr import MatrixExpr from .special import ZeroMatrix, Identity, OneMatrix class PermutationMatrix(MatrixExpr): """A Permutation Matrix Parameters ========== perm : Permutation The permutation the matrix uses. The size of the permutation determines the matrix size. See the documentation of :class:`sympy.combinatorics.permutations.Permutation` for the further information of how to create a permutation object. Examples ======== >>> from sympy.matrices import Matrix, PermutationMatrix >>> from sympy.combinatorics import Permutation Creating a permutation matrix: >>> p = Permutation(1, 2, 0) >>> P = PermutationMatrix(p) >>> P = P.as_explicit() >>> P Matrix([ [0, 1, 0], [0, 0, 1], [1, 0, 0]]) Permuting a matrix row and column: >>> M = Matrix([0, 1, 2]) >>> Matrix(P*M) Matrix([ [1], [2], [0]]) >>> Matrix(M.T*P) Matrix([[2, 0, 1]]) See Also ======== sympy.combinatorics.permutations.Permutation """ def __new__(cls, perm): from sympy.combinatorics.permutations import Permutation perm = _sympify(perm) if not isinstance(perm, Permutation): raise ValueError( "{} must be a SymPy Permutation instance.".format(perm)) return super().__new__(cls, perm) @property def shape(self): size = self.args[0].size return (size, size) @property def is_Identity(self): return self.args[0].is_Identity def doit(self): if self.is_Identity: return Identity(self.rows) return self def _entry(self, i, j, **kwargs): perm = self.args[0] return KroneckerDelta(perm.apply(i), j) def _eval_power(self, exp): return PermutationMatrix(self.args[0] ** exp).doit() def _eval_inverse(self): return PermutationMatrix(self.args[0] ** -1) _eval_transpose = _eval_adjoint = _eval_inverse def _eval_determinant(self): sign = self.args[0].signature() if sign == 1: return S.One elif sign == -1: return S.NegativeOne raise NotImplementedError def _eval_rewrite_as_BlockDiagMatrix(self, *args, **kwargs): from sympy.combinatorics.permutations import Permutation from .blockmatrix import BlockDiagMatrix perm = self.args[0] full_cyclic_form = perm.full_cyclic_form cycles_picks = [] # Stage 1. Decompose the cycles into the blockable form. a, b, c = 0, 0, 0 flag = False for cycle in full_cyclic_form: l = len(cycle) m = max(cycle) if not flag: if m + 1 > a + l: flag = True temp = [cycle] b = m c = l else: cycles_picks.append([cycle]) a += l else: if m > b: if m + 1 == a + c + l: temp.append(cycle) cycles_picks.append(temp) flag = False a = m+1 else: b = m temp.append(cycle) c += l else: if b + 1 == a + c + l: temp.append(cycle) cycles_picks.append(temp) flag = False a = b+1 else: temp.append(cycle) c += l # Stage 2. Normalize each decomposed cycles and build matrix. p = 0 args = [] for pick in cycles_picks: new_cycles = [] l = 0 for cycle in pick: new_cycle = [i - p for i in cycle] new_cycles.append(new_cycle) l += len(cycle) p += l perm = Permutation(new_cycles) mat = PermutationMatrix(perm) args.append(mat) return BlockDiagMatrix(*args) class MatrixPermute(MatrixExpr): r"""Symbolic representation for permuting matrix rows or columns. Parameters ========== perm : Permutation, PermutationMatrix The permutation to use for permuting the matrix. The permutation can be resized to the suitable one, axis : 0 or 1 The axis to permute alongside. If `0`, it will permute the matrix rows. If `1`, it will permute the matrix columns. Notes ===== This follows the same notation used in :meth:`sympy.matrices.common.MatrixCommon.permute`. Examples ======== >>> from sympy.matrices import Matrix, MatrixPermute >>> from sympy.combinatorics import Permutation Permuting the matrix rows: >>> p = Permutation(1, 2, 0) >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> B = MatrixPermute(A, p, axis=0) >>> B.as_explicit() Matrix([ [4, 5, 6], [7, 8, 9], [1, 2, 3]]) Permuting the matrix columns: >>> B = MatrixPermute(A, p, axis=1) >>> B.as_explicit() Matrix([ [2, 3, 1], [5, 6, 4], [8, 9, 7]]) See Also ======== sympy.matrices.common.MatrixCommon.permute """ def __new__(cls, mat, perm, axis=S.Zero): from sympy.combinatorics.permutations import Permutation mat = _sympify(mat) if not mat.is_Matrix: raise ValueError( "{} must be a SymPy matrix instance.".format(perm)) perm = _sympify(perm) if isinstance(perm, PermutationMatrix): perm = perm.args[0] if not isinstance(perm, Permutation): raise ValueError( "{} must be a SymPy Permutation or a PermutationMatrix " \ "instance".format(perm)) axis = _sympify(axis) if axis not in (0, 1): raise ValueError("The axis must be 0 or 1.") mat_size = mat.shape[axis] if mat_size != perm.size: try: perm = perm.resize(mat_size) except ValueError: raise ValueError( "Size does not match between the permutation {} " "and the matrix {} threaded over the axis {} " "and cannot be converted." .format(perm, mat, axis)) return super().__new__(cls, mat, perm, axis) def doit(self, deep=True): mat, perm, axis = self.args if deep: mat = mat.doit(deep=deep) perm = perm.doit(deep=deep) if perm.is_Identity: return mat if mat.is_Identity: if axis is S.Zero: return PermutationMatrix(perm) elif axis is S.One: return PermutationMatrix(perm**-1) if isinstance(mat, (ZeroMatrix, OneMatrix)): return mat if isinstance(mat, MatrixPermute) and mat.args[2] == axis: return MatrixPermute(mat.args[0], perm * mat.args[1], axis) return self @property def shape(self): return self.args[0].shape def _entry(self, i, j, **kwargs): mat, perm, axis = self.args if axis == 0: return mat[perm.apply(i), j] elif axis == 1: return mat[i, perm.apply(j)] def _eval_rewrite_as_MatMul(self, *args, **kwargs): from .matmul import MatMul mat, perm, axis = self.args deep = kwargs.get("deep", True) if deep: mat = mat.rewrite(MatMul) if axis == 0: return MatMul(PermutationMatrix(perm), mat) elif axis == 1: return MatMul(mat, PermutationMatrix(perm**-1)) sympy-sympy-1.9/sympy/matrices/expressions/sets.py000066400000000000000000000034671412543434000226370ustar00rootroot00000000000000from sympy.core.logic import fuzzy_and from sympy.core.sympify import _sympify from sympy.sets.sets import Set from .matexpr import MatrixExpr class MatrixSet(Set): """ MatrixSet represents the set of matrices with ``shape = (n, m)`` over the given set. Examples ======== >>> from sympy.matrices import MatrixSet, Matrix >>> from sympy import S, I >>> M = MatrixSet(2, 2, set=S.Reals) >>> X = Matrix([[1, 2], [3, 4]]) >>> X in M True >>> X = Matrix([[1, 2], [I, 4]]) >>> X in M False """ is_empty = False def __new__(cls, n, m, set): n, m, set = _sympify(n), _sympify(m), _sympify(set) cls._check_dim(n) cls._check_dim(m) if not isinstance(set, Set): raise TypeError("{} should be an instance of Set.".format(set)) return Set.__new__(cls, n, m, set) @property def shape(self): return self.args[:2] @property def set(self): return self.args[2] def _contains(self, other): if not isinstance(other, MatrixExpr): raise TypeError("{} should be an instance of MatrixExpr.".format(other)) if other.shape != self.shape: are_symbolic = any(_sympify(x).is_Symbol for x in other.shape + self.shape) if are_symbolic: return None return False return fuzzy_and(self.set.contains(x) for x in other) @classmethod def _check_dim(cls, dim): """Helper function to check invalid matrix dimensions""" from sympy.core.assumptions import check_assumptions ok = check_assumptions(dim, integer=True, nonnegative=True) if ok is False: raise ValueError( "The dimension specification {} should be " "a nonnegative integer.".format(dim)) sympy-sympy-1.9/sympy/matrices/expressions/slice.py000066400000000000000000000063601412543434000227530ustar00rootroot00000000000000from sympy.matrices.expressions.matexpr import MatrixExpr from sympy import Tuple, Basic from sympy.functions.elementary.integers import floor def normalize(i, parentsize): if isinstance(i, slice): i = (i.start, i.stop, i.step) if not isinstance(i, (tuple, list, Tuple)): if (i < 0) == True: i += parentsize i = (i, i+1, 1) i = list(i) if len(i) == 2: i.append(1) start, stop, step = i start = start or 0 if stop is None: stop = parentsize if (start < 0) == True: start += parentsize if (stop < 0) == True: stop += parentsize step = step or 1 if ((stop - start) * step < 1) == True: raise IndexError() return (start, stop, step) class MatrixSlice(MatrixExpr): """ A MatrixSlice of a Matrix Expression Examples ======== >>> from sympy import MatrixSlice, ImmutableMatrix >>> M = ImmutableMatrix(4, 4, range(16)) >>> M Matrix([ [ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) >>> B = MatrixSlice(M, (0, 2), (2, 4)) >>> ImmutableMatrix(B) Matrix([ [2, 3], [6, 7]]) """ parent = property(lambda self: self.args[0]) rowslice = property(lambda self: self.args[1]) colslice = property(lambda self: self.args[2]) def __new__(cls, parent, rowslice, colslice): rowslice = normalize(rowslice, parent.shape[0]) colslice = normalize(colslice, parent.shape[1]) if not (len(rowslice) == len(colslice) == 3): raise IndexError() if ((0 > rowslice[0]) == True or (parent.shape[0] < rowslice[1]) == True or (0 > colslice[0]) == True or (parent.shape[1] < colslice[1]) == True): raise IndexError() if isinstance(parent, MatrixSlice): return mat_slice_of_slice(parent, rowslice, colslice) return Basic.__new__(cls, parent, Tuple(*rowslice), Tuple(*colslice)) @property def shape(self): rows = self.rowslice[1] - self.rowslice[0] rows = rows if self.rowslice[2] == 1 else floor(rows/self.rowslice[2]) cols = self.colslice[1] - self.colslice[0] cols = cols if self.colslice[2] == 1 else floor(cols/self.colslice[2]) return rows, cols def _entry(self, i, j, **kwargs): return self.parent._entry(i*self.rowslice[2] + self.rowslice[0], j*self.colslice[2] + self.colslice[0], **kwargs) @property def on_diag(self): return self.rowslice == self.colslice def slice_of_slice(s, t): start1, stop1, step1 = s start2, stop2, step2 = t start = start1 + start2*step1 step = step1 * step2 stop = start1 + step1*stop2 if stop > stop1: raise IndexError() return start, stop, step def mat_slice_of_slice(parent, rowslice, colslice): """ Collapse nested matrix slices >>> from sympy import MatrixSymbol >>> X = MatrixSymbol('X', 10, 10) >>> X[:, 1:5][5:8, :] X[5:8, 1:5] >>> X[1:9:2, 2:6][1:3, 2] X[3:7:2, 4:5] """ row = slice_of_slice(parent.rowslice, rowslice) col = slice_of_slice(parent.colslice, colslice) return MatrixSlice(parent.parent, row, col) sympy-sympy-1.9/sympy/matrices/expressions/special.py000066400000000000000000000154361412543434000233000ustar00rootroot00000000000000from sympy.assumptions.ask import ask, Q from sympy.core.relational import Eq from sympy.core.singleton import S from sympy.core.sympify import _sympify from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.matrices.common import NonInvertibleMatrixError from .matexpr import MatrixExpr class ZeroMatrix(MatrixExpr): """The Matrix Zero 0 - additive identity Examples ======== >>> from sympy import MatrixSymbol, ZeroMatrix >>> A = MatrixSymbol('A', 3, 5) >>> Z = ZeroMatrix(3, 5) >>> A + Z A >>> Z*A.T 0 """ is_ZeroMatrix = True def __new__(cls, m, n): m, n = _sympify(m), _sympify(n) cls._check_dim(m) cls._check_dim(n) return super().__new__(cls, m, n) @property def shape(self): return (self.args[0], self.args[1]) def _eval_power(self, exp): # exp = -1, 0, 1 are already handled at this stage if (exp < 0) == True: raise NonInvertibleMatrixError("Matrix det == 0; not invertible") return self def _eval_transpose(self): return ZeroMatrix(self.cols, self.rows) def _eval_trace(self): return S.Zero def _eval_determinant(self): return S.Zero def _eval_inverse(self): raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") def conjugate(self): return self def _entry(self, i, j, **kwargs): return S.Zero class GenericZeroMatrix(ZeroMatrix): """ A zero matrix without a specified shape This exists primarily so MatAdd() with no arguments can return something meaningful. """ def __new__(cls): # super(ZeroMatrix, cls) instead of super(GenericZeroMatrix, cls) # because ZeroMatrix.__new__ doesn't have the same signature return super(ZeroMatrix, cls).__new__(cls) @property def rows(self): raise TypeError("GenericZeroMatrix does not have a specified shape") @property def cols(self): raise TypeError("GenericZeroMatrix does not have a specified shape") @property def shape(self): raise TypeError("GenericZeroMatrix does not have a specified shape") # Avoid Matrix.__eq__ which might call .shape def __eq__(self, other): return isinstance(other, GenericZeroMatrix) def __ne__(self, other): return not (self == other) def __hash__(self): return super().__hash__() class Identity(MatrixExpr): """The Matrix Identity I - multiplicative identity Examples ======== >>> from sympy.matrices import Identity, MatrixSymbol >>> A = MatrixSymbol('A', 3, 5) >>> I = Identity(3) >>> I*A A """ is_Identity = True def __new__(cls, n): n = _sympify(n) cls._check_dim(n) return super().__new__(cls, n) @property def rows(self): return self.args[0] @property def cols(self): return self.args[0] @property def shape(self): return (self.args[0], self.args[0]) @property def is_square(self): return True def _eval_transpose(self): return self def _eval_trace(self): return self.rows def _eval_inverse(self): return self def conjugate(self): return self def _entry(self, i, j, **kwargs): eq = Eq(i, j) if eq is S.true: return S.One elif eq is S.false: return S.Zero return KroneckerDelta(i, j, (0, self.cols-1)) def _eval_determinant(self): return S.One def _eval_power(self, exp): return self class GenericIdentity(Identity): """ An identity matrix without a specified shape This exists primarily so MatMul() with no arguments can return something meaningful. """ def __new__(cls): # super(Identity, cls) instead of super(GenericIdentity, cls) because # Identity.__new__ doesn't have the same signature return super(Identity, cls).__new__(cls) @property def rows(self): raise TypeError("GenericIdentity does not have a specified shape") @property def cols(self): raise TypeError("GenericIdentity does not have a specified shape") @property def shape(self): raise TypeError("GenericIdentity does not have a specified shape") # Avoid Matrix.__eq__ which might call .shape def __eq__(self, other): return isinstance(other, GenericIdentity) def __ne__(self, other): return not (self == other) def __hash__(self): return super().__hash__() class OneMatrix(MatrixExpr): """ Matrix whose all entries are ones. """ def __new__(cls, m, n, evaluate=False): m, n = _sympify(m), _sympify(n) cls._check_dim(m) cls._check_dim(n) if evaluate: condition = Eq(m, 1) & Eq(n, 1) if condition == True: return Identity(1) obj = super().__new__(cls, m, n) return obj @property def shape(self): return self._args @property def is_Identity(self): return self._is_1x1() == True def as_explicit(self): from sympy import ImmutableDenseMatrix return ImmutableDenseMatrix.ones(*self.shape) def doit(self, **hints): args = self.args if hints.get('deep', True): args = [a.doit(**hints) for a in args] return self.func(*args, evaluate=True) def _eval_power(self, exp): # exp = -1, 0, 1 are already handled at this stage if self._is_1x1() == True: return Identity(1) if (exp < 0) == True: raise NonInvertibleMatrixError("Matrix det == 0; not invertible") if ask(Q.integer(exp)): return self.shape[0] ** (exp - 1) * OneMatrix(*self.shape) return super()._eval_power(exp) def _eval_transpose(self): return OneMatrix(self.cols, self.rows) def _eval_trace(self): return S.One*self.rows def _is_1x1(self): """Returns true if the matrix is known to be 1x1""" shape = self.shape return Eq(shape[0], 1) & Eq(shape[1], 1) def _eval_determinant(self): condition = self._is_1x1() if condition == True: return S.One elif condition == False: return S.Zero else: from sympy import Determinant return Determinant(self) def _eval_inverse(self): condition = self._is_1x1() if condition == True: return Identity(1) elif condition == False: raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") else: from .inverse import Inverse return Inverse(self) def conjugate(self): return self def _entry(self, i, j, **kwargs): return S.One sympy-sympy-1.9/sympy/matrices/expressions/tests/000077500000000000000000000000001412543434000224375ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/expressions/tests/__init__.py000066400000000000000000000000001412543434000245360ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/expressions/tests/test_adjoint.py000066400000000000000000000020511412543434000254760ustar00rootroot00000000000000from sympy.core import symbols, S from sympy.functions import adjoint, conjugate, transpose from sympy.matrices.expressions import MatrixSymbol, Adjoint, trace, Transpose from sympy.matrices import eye, Matrix n, m, l, k, p = symbols('n m l k p', integer=True) A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) def test_adjoint(): Sq = MatrixSymbol('Sq', n, n) assert Adjoint(A).shape == (m, n) assert Adjoint(A*B).shape == (l, n) assert adjoint(Adjoint(A)) == A assert isinstance(Adjoint(Adjoint(A)), Adjoint) assert conjugate(Adjoint(A)) == Transpose(A) assert transpose(Adjoint(A)) == Adjoint(Transpose(A)) assert Adjoint(eye(3)).doit() == eye(3) assert Adjoint(S(5)).doit() == S(5) assert Adjoint(Matrix([[1, 2], [3, 4]])).doit() == Matrix([[1, 3], [2, 4]]) assert adjoint(trace(Sq)) == conjugate(trace(Sq)) assert trace(adjoint(Sq)) == conjugate(trace(Sq)) assert Adjoint(Sq)[0, 1] == conjugate(Sq[1, 0]) assert Adjoint(A*B).doit() == Adjoint(B) * Adjoint(A) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_applyfunc.py000066400000000000000000000066201412543434000260550ustar00rootroot00000000000000from sympy.core.symbol import symbols, Dummy from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction from sympy import Matrix, Lambda, MatrixSymbol, exp, MatMul, sin, simplify from sympy.testing.pytest import raises from sympy.matrices.common import ShapeError X = MatrixSymbol("X", 3, 3) Y = MatrixSymbol("Y", 3, 3) k = symbols("k") Xk = MatrixSymbol("X", k, k) Xd = X.as_explicit() x, y, z, t = symbols("x y z t") def test_applyfunc_matrix(): x = Dummy('x') double = Lambda(x, x**2) expr = ElementwiseApplyFunction(double, Xd) assert isinstance(expr, ElementwiseApplyFunction) assert expr.doit() == Xd.applyfunc(lambda x: x**2) assert expr.shape == (3, 3) assert expr.func(*expr.args) == expr assert simplify(expr) == expr assert expr[0, 0] == double(Xd[0, 0]) expr = ElementwiseApplyFunction(double, X) assert isinstance(expr, ElementwiseApplyFunction) assert isinstance(expr.doit(), ElementwiseApplyFunction) assert expr == X.applyfunc(double) assert expr.func(*expr.args) == expr expr = ElementwiseApplyFunction(exp, X*Y) assert expr.expr == X*Y assert expr.function.dummy_eq(Lambda(x, exp(x))) assert expr.dummy_eq((X*Y).applyfunc(exp)) assert expr.func(*expr.args) == expr assert isinstance(X*expr, MatMul) assert (X*expr).shape == (3, 3) Z = MatrixSymbol("Z", 2, 3) assert (Z*expr).shape == (2, 3) expr = ElementwiseApplyFunction(exp, Z.T)*ElementwiseApplyFunction(exp, Z) assert expr.shape == (3, 3) expr = ElementwiseApplyFunction(exp, Z)*ElementwiseApplyFunction(exp, Z.T) assert expr.shape == (2, 2) raises(ShapeError, lambda: ElementwiseApplyFunction(exp, Z)*ElementwiseApplyFunction(exp, Z)) M = Matrix([[x, y], [z, t]]) expr = ElementwiseApplyFunction(sin, M) assert isinstance(expr, ElementwiseApplyFunction) assert expr.function.dummy_eq(Lambda(x, sin(x))) assert expr.expr == M assert expr.doit() == M.applyfunc(sin) assert expr.doit() == Matrix([[sin(x), sin(y)], [sin(z), sin(t)]]) assert expr.func(*expr.args) == expr expr = ElementwiseApplyFunction(double, Xk) assert expr.doit() == expr assert expr.subs(k, 2).shape == (2, 2) assert (expr*expr).shape == (k, k) M = MatrixSymbol("M", k, t) expr2 = M.T*expr*M assert isinstance(expr2, MatMul) assert expr2.args[1] == expr assert expr2.shape == (t, t) expr3 = expr*M assert expr3.shape == (k, t) raises(ShapeError, lambda: M*expr) expr1 = ElementwiseApplyFunction(lambda x: x+1, Xk) expr2 = ElementwiseApplyFunction(lambda x: x, Xk) assert expr1 != expr2 def test_applyfunc_entry(): af = X.applyfunc(sin) assert af[0, 0] == sin(X[0, 0]) af = Xd.applyfunc(sin) assert af[0, 0] == sin(X[0, 0]) def test_applyfunc_as_explicit(): af = X.applyfunc(sin) assert af.as_explicit() == Matrix([ [sin(X[0, 0]), sin(X[0, 1]), sin(X[0, 2])], [sin(X[1, 0]), sin(X[1, 1]), sin(X[1, 2])], [sin(X[2, 0]), sin(X[2, 1]), sin(X[2, 2])], ]) def test_applyfunc_transpose(): af = Xk.applyfunc(sin) assert af.T.dummy_eq(Xk.T.applyfunc(sin)) def test_applyfunc_shape_11_matrices(): M = MatrixSymbol("M", 1, 1) double = Lambda(x, x*2) expr = M.applyfunc(sin) assert isinstance(expr, ElementwiseApplyFunction) expr = M.applyfunc(double) assert isinstance(expr, MatMul) assert expr == 2*M sympy-sympy-1.9/sympy/matrices/expressions/tests/test_blockmatrix.py000066400000000000000000000343371412543434000264010ustar00rootroot00000000000000from sympy import Trace from sympy.testing.pytest import raises, slow from sympy.matrices.expressions.blockmatrix import ( block_collapse, bc_matmul, bc_block_plus_ident, BlockDiagMatrix, BlockMatrix, bc_dist, bc_matadd, bc_transpose, bc_inverse, blockcut, reblock_2x2, deblock) from sympy.matrices.expressions import (MatrixSymbol, Identity, Inverse, trace, Transpose, det, ZeroMatrix) from sympy.matrices.common import NonInvertibleMatrixError from sympy.matrices import ( Matrix, ImmutableMatrix, ImmutableSparseMatrix) from sympy.core import Tuple, symbols, Expr from sympy.functions import transpose i, j, k, l, m, n, p = symbols('i:n, p', integer=True) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) C = MatrixSymbol('C', n, n) D = MatrixSymbol('D', n, n) G = MatrixSymbol('G', n, n) H = MatrixSymbol('H', n, n) b1 = BlockMatrix([[G, H]]) b2 = BlockMatrix([[G], [H]]) def test_bc_matmul(): assert bc_matmul(H*b1*b2*G) == BlockMatrix([[(H*G*G + H*H*H)*G]]) def test_bc_matadd(): assert bc_matadd(BlockMatrix([[G, H]]) + BlockMatrix([[H, H]])) == \ BlockMatrix([[G+H, H+H]]) def test_bc_transpose(): assert bc_transpose(Transpose(BlockMatrix([[A, B], [C, D]]))) == \ BlockMatrix([[A.T, C.T], [B.T, D.T]]) def test_bc_dist_diag(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', m, m) C = MatrixSymbol('C', l, l) X = BlockDiagMatrix(A, B, C) assert bc_dist(X+X).equals(BlockDiagMatrix(2*A, 2*B, 2*C)) def test_block_plus_ident(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', m, m) X = BlockMatrix([[A, B], [C, D]]) Z = MatrixSymbol('Z', n + m, n + m) assert bc_block_plus_ident(X + Identity(m + n) + Z) == \ BlockDiagMatrix(Identity(n), Identity(m)) + X + Z def test_BlockMatrix(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, k) C = MatrixSymbol('C', l, m) D = MatrixSymbol('D', l, k) M = MatrixSymbol('M', m + k, p) N = MatrixSymbol('N', l + n, k + m) X = BlockMatrix(Matrix([[A, B], [C, D]])) assert X.__class__(*X.args) == X # block_collapse does nothing on normal inputs E = MatrixSymbol('E', n, m) assert block_collapse(A + 2*E) == A + 2*E F = MatrixSymbol('F', m, m) assert block_collapse(E.T*A*F) == E.T*A*F assert X.shape == (l + n, k + m) assert X.blockshape == (2, 2) assert transpose(X) == BlockMatrix(Matrix([[A.T, C.T], [B.T, D.T]])) assert transpose(X).shape == X.shape[::-1] # Test that BlockMatrices and MatrixSymbols can still mix assert (X*M).is_MatMul assert X._blockmul(M).is_MatMul assert (X*M).shape == (n + l, p) assert (X + N).is_MatAdd assert X._blockadd(N).is_MatAdd assert (X + N).shape == X.shape E = MatrixSymbol('E', m, 1) F = MatrixSymbol('F', k, 1) Y = BlockMatrix(Matrix([[E], [F]])) assert (X*Y).shape == (l + n, 1) assert block_collapse(X*Y).blocks[0, 0] == A*E + B*F assert block_collapse(X*Y).blocks[1, 0] == C*E + D*F # block_collapse passes down into container objects, transposes, and inverse assert block_collapse(transpose(X*Y)) == transpose(block_collapse(X*Y)) assert block_collapse(Tuple(X*Y, 2*X)) == ( block_collapse(X*Y), block_collapse(2*X)) # Make sure that MatrixSymbols will enter 1x1 BlockMatrix if it simplifies Ab = BlockMatrix([[A]]) Z = MatrixSymbol('Z', *A.shape) assert block_collapse(Ab + Z) == A + Z def test_block_collapse_explicit_matrices(): A = Matrix([[1, 2], [3, 4]]) assert block_collapse(BlockMatrix([[A]])) == A A = ImmutableSparseMatrix([[1, 2], [3, 4]]) assert block_collapse(BlockMatrix([[A]])) == A def test_issue_17624(): a = MatrixSymbol("a", 2, 2) z = ZeroMatrix(2, 2) b = BlockMatrix([[a, z], [z, z]]) assert block_collapse(b * b) == BlockMatrix([[a**2, z], [z, z]]) assert block_collapse(b * b * b) == BlockMatrix([[a**3, z], [z, z]]) def test_issue_18618(): A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) assert A == Matrix(BlockDiagMatrix(A)) def test_BlockMatrix_trace(): A, B, C, D = [MatrixSymbol(s, 3, 3) for s in 'ABCD'] X = BlockMatrix([[A, B], [C, D]]) assert trace(X) == trace(A) + trace(D) assert trace(BlockMatrix([ZeroMatrix(n, n)])) == 0 def test_BlockMatrix_Determinant(): A, B, C, D = [MatrixSymbol(s, 3, 3) for s in 'ABCD'] X = BlockMatrix([[A, B], [C, D]]) from sympy import assuming, Q with assuming(Q.invertible(A)): assert det(X) == det(A) * det(X.schur('A')) assert isinstance(det(X), Expr) assert det(BlockMatrix([A])) == det(A) assert det(BlockMatrix([ZeroMatrix(n, n)])) == 0 def test_squareBlockMatrix(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', m, m) X = BlockMatrix([[A, B], [C, D]]) Y = BlockMatrix([[A]]) assert X.is_square Q = X + Identity(m + n) assert (block_collapse(Q) == BlockMatrix([[A + Identity(n), B], [C, D + Identity(m)]])) assert (X + MatrixSymbol('Q', n + m, n + m)).is_MatAdd assert (X * MatrixSymbol('Q', n + m, n + m)).is_MatMul assert block_collapse(Y.I) == A.I assert isinstance(X.inverse(), Inverse) assert not X.is_Identity Z = BlockMatrix([[Identity(n), B], [C, D]]) assert not Z.is_Identity def test_BlockMatrix_2x2_inverse_symbolic(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, k - m) C = MatrixSymbol('C', k - n, m) D = MatrixSymbol('D', k - n, k - m) X = BlockMatrix([[A, B], [C, D]]) assert X.is_square and X.shape == (k, k) assert isinstance(block_collapse(X.I), Inverse) # Can't invert when none of the blocks is square # test code path where only A is invertible A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = ZeroMatrix(m, m) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [A.I + A.I * B * X.schur('A').I * C * A.I, -A.I * B * X.schur('A').I], [-X.schur('A').I * C * A.I, X.schur('A').I], ]) # test code path where only B is invertible A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, n) C = ZeroMatrix(m, m) D = MatrixSymbol('D', m, n) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [-X.schur('B').I * D * B.I, X.schur('B').I], [B.I + B.I * A * X.schur('B').I * D * B.I, -B.I * A * X.schur('B').I], ]) # test code path where only C is invertible A = MatrixSymbol('A', n, m) B = ZeroMatrix(n, n) C = MatrixSymbol('C', m, m) D = MatrixSymbol('D', m, n) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [-C.I * D * X.schur('C').I, C.I + C.I * D * X.schur('C').I * A * C.I], [X.schur('C').I, -X.schur('C').I * A * C.I], ]) # test code path where only D is invertible A = ZeroMatrix(n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', m, m) X = BlockMatrix([[A, B], [C, D]]) assert block_collapse(X.inverse()) == BlockMatrix([ [X.schur('D').I, -X.schur('D').I * B * D.I], [-D.I * C * X.schur('D').I, D.I + D.I * C * X.schur('D').I * B * D.I], ]) def test_BlockMatrix_2x2_inverse_numeric(): """Test 2x2 block matrix inversion numerically for all 4 formulas""" M = Matrix([[1, 2], [3, 4]]) # rank deficient matrices that have full rank when two of them combined D1 = Matrix([[1, 2], [2, 4]]) D2 = Matrix([[1, 3], [3, 9]]) D3 = Matrix([[1, 4], [4, 16]]) assert D1.rank() == D2.rank() == D3.rank() == 1 assert (D1 + D2).rank() == (D2 + D3).rank() == (D3 + D1).rank() == 2 # Only A is invertible K = BlockMatrix([[M, D1], [D2, D3]]) assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv() # Only B is invertible K = BlockMatrix([[D1, M], [D2, D3]]) assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv() # Only C is invertible K = BlockMatrix([[D1, D2], [M, D3]]) assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv() # Only D is invertible K = BlockMatrix([[D1, D2], [D3, M]]) assert block_collapse(K.inv()).as_explicit() == K.as_explicit().inv() @slow def test_BlockMatrix_3x3_symbolic(): # Only test one of these, instead of all permutations, because it's slow rowblocksizes = (n, m, k) colblocksizes = (m, k, n) K = BlockMatrix([ [MatrixSymbol('M%s%s' % (rows, cols), rows, cols) for cols in colblocksizes] for rows in rowblocksizes ]) collapse = block_collapse(K.I) assert isinstance(collapse, BlockMatrix) def test_BlockDiagMatrix(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', m, m) C = MatrixSymbol('C', l, l) M = MatrixSymbol('M', n + m + l, n + m + l) X = BlockDiagMatrix(A, B, C) Y = BlockDiagMatrix(A, 2*B, 3*C) assert X.blocks[1, 1] == B assert X.shape == (n + m + l, n + m + l) assert all(X.blocks[i, j].is_ZeroMatrix if i != j else X.blocks[i, j] in [A, B, C] for i in range(3) for j in range(3)) assert X.__class__(*X.args) == X assert X.get_diag_blocks() == (A, B, C) assert isinstance(block_collapse(X.I * X), Identity) assert bc_matmul(X*X) == BlockDiagMatrix(A*A, B*B, C*C) assert block_collapse(X*X) == BlockDiagMatrix(A*A, B*B, C*C) #XXX: should be == ?? assert block_collapse(X + X).equals(BlockDiagMatrix(2*A, 2*B, 2*C)) assert block_collapse(X*Y) == BlockDiagMatrix(A*A, 2*B*B, 3*C*C) assert block_collapse(X + Y) == BlockDiagMatrix(2*A, 3*B, 4*C) # Ensure that BlockDiagMatrices can still interact with normal MatrixExprs assert (X*(2*M)).is_MatMul assert (X + (2*M)).is_MatAdd assert (X._blockmul(M)).is_MatMul assert (X._blockadd(M)).is_MatAdd def test_BlockDiagMatrix_nonsquare(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', k, l) X = BlockDiagMatrix(A, B) assert X.shape == (n + k, m + l) assert X.shape == (n + k, m + l) assert X.rowblocksizes == [n, k] assert X.colblocksizes == [m, l] C = MatrixSymbol('C', n, m) D = MatrixSymbol('D', k, l) Y = BlockDiagMatrix(C, D) assert block_collapse(X + Y) == BlockDiagMatrix(A + C, B + D) assert block_collapse(X * Y.T) == BlockDiagMatrix(A * C.T, B * D.T) raises(NonInvertibleMatrixError, lambda: BlockDiagMatrix(A, C.T).inverse()) def test_BlockDiagMatrix_determinant(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', m, m) assert det(BlockDiagMatrix()) == 1 assert det(BlockDiagMatrix(A)) == det(A) assert det(BlockDiagMatrix(A, B)) == det(A) * det(B) # non-square blocks C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', n, m) assert det(BlockDiagMatrix(C, D)) == 0 def test_BlockDiagMatrix_trace(): assert trace(BlockDiagMatrix()) == 0 assert trace(BlockDiagMatrix(ZeroMatrix(n, n))) == 0 A = MatrixSymbol('A', n, n) assert trace(BlockDiagMatrix(A)) == trace(A) B = MatrixSymbol('B', m, m) assert trace(BlockDiagMatrix(A, B)) == trace(A) + trace(B) # non-square blocks C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', n, m) assert isinstance(trace(BlockDiagMatrix(C, D)), Trace) def test_BlockDiagMatrix_transpose(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', k, l) assert transpose(BlockDiagMatrix()) == BlockDiagMatrix() assert transpose(BlockDiagMatrix(A)) == BlockDiagMatrix(A.T) assert transpose(BlockDiagMatrix(A, B)) == BlockDiagMatrix(A.T, B.T) def test_issue_2460(): bdm1 = BlockDiagMatrix(Matrix([i]), Matrix([j])) bdm2 = BlockDiagMatrix(Matrix([k]), Matrix([l])) assert block_collapse(bdm1 + bdm2) == BlockDiagMatrix(Matrix([i + k]), Matrix([j + l])) def test_blockcut(): A = MatrixSymbol('A', n, m) B = blockcut(A, (n/2, n/2), (m/2, m/2)) assert B == BlockMatrix([[A[:n/2, :m/2], A[:n/2, m/2:]], [A[n/2:, :m/2], A[n/2:, m/2:]]]) M = ImmutableMatrix(4, 4, range(16)) B = blockcut(M, (2, 2), (2, 2)) assert M == ImmutableMatrix(B) B = blockcut(M, (1, 3), (2, 2)) assert ImmutableMatrix(B.blocks[0, 1]) == ImmutableMatrix([[2, 3]]) def test_reblock_2x2(): B = BlockMatrix([[MatrixSymbol('A_%d%d'%(i,j), 2, 2) for j in range(3)] for i in range(3)]) assert B.blocks.shape == (3, 3) BB = reblock_2x2(B) assert BB.blocks.shape == (2, 2) assert B.shape == BB.shape assert B.as_explicit() == BB.as_explicit() def test_deblock(): B = BlockMatrix([[MatrixSymbol('A_%d%d'%(i,j), n, n) for j in range(4)] for i in range(4)]) assert deblock(reblock_2x2(B)) == B def test_block_collapse_type(): bm1 = BlockDiagMatrix(ImmutableMatrix([1]), ImmutableMatrix([2])) bm2 = BlockDiagMatrix(ImmutableMatrix([3]), ImmutableMatrix([4])) assert bm1.T.__class__ == BlockDiagMatrix assert block_collapse(bm1 - bm2).__class__ == BlockDiagMatrix assert block_collapse(Inverse(bm1)).__class__ == BlockDiagMatrix assert block_collapse(Transpose(bm1)).__class__ == BlockDiagMatrix assert bc_transpose(Transpose(bm1)).__class__ == BlockDiagMatrix assert bc_inverse(Inverse(bm1)).__class__ == BlockDiagMatrix def test_invalid_block_matrix(): raises(ValueError, lambda: BlockMatrix([ [Identity(2), Identity(5)], ])) raises(ValueError, lambda: BlockMatrix([ [Identity(n), Identity(m)], ])) raises(ValueError, lambda: BlockMatrix([ [ZeroMatrix(n, n), ZeroMatrix(n, n)], [ZeroMatrix(n, n - 1), ZeroMatrix(n, n + 1)], ])) raises(ValueError, lambda: BlockMatrix([ [ZeroMatrix(n - 1, n), ZeroMatrix(n, n)], [ZeroMatrix(n + 1, n), ZeroMatrix(n, n)], ])) def test_block_lu_decomposition(): A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, n) D = MatrixSymbol('D', m, m) X = BlockMatrix([[A, B], [C, D]]) #LDU decomposition L, D, U = X.LDUdecomposition() assert block_collapse(L*D*U) == X #UDL decomposition U, D, L = X.UDLdecomposition() assert block_collapse(U*D*L) == X #LU decomposition L, U = X.LUdecomposition() assert block_collapse(L*U) == X sympy-sympy-1.9/sympy/matrices/expressions/tests/test_companion.py000066400000000000000000000031621412543434000260350ustar00rootroot00000000000000from sympy.core.expr import unchanged from sympy.core.symbol import Symbol, symbols from sympy.matrices.immutable import ImmutableDenseMatrix from sympy.matrices.expressions.companion import CompanionMatrix from sympy.polys.polytools import Poly from sympy.testing.pytest import raises def test_creation(): x = Symbol('x') y = Symbol('y') raises(ValueError, lambda: CompanionMatrix(1)) raises(ValueError, lambda: CompanionMatrix(Poly([1], x))) raises(ValueError, lambda: CompanionMatrix(Poly([2, 1], x))) raises(ValueError, lambda: CompanionMatrix(Poly(x*y, [x, y]))) unchanged(CompanionMatrix, Poly([1, 2, 3], x)) def test_shape(): c0, c1, c2 = symbols('c0:3') x = Symbol('x') assert CompanionMatrix(Poly([1, c0], x)).shape == (1, 1) assert CompanionMatrix(Poly([1, c1, c0], x)).shape == (2, 2) assert CompanionMatrix(Poly([1, c2, c1, c0], x)).shape == (3, 3) def test_entry(): c0, c1, c2 = symbols('c0:3') x = Symbol('x') A = CompanionMatrix(Poly([1, c2, c1, c0], x)) assert A[0, 0] == 0 assert A[1, 0] == 1 assert A[1, 1] == 0 assert A[2, 1] == 1 assert A[0, 2] == -c0 assert A[1, 2] == -c1 assert A[2, 2] == -c2 def test_as_explicit(): c0, c1, c2 = symbols('c0:3') x = Symbol('x') assert CompanionMatrix(Poly([1, c0], x)).as_explicit() == \ ImmutableDenseMatrix([-c0]) assert CompanionMatrix(Poly([1, c1, c0], x)).as_explicit() == \ ImmutableDenseMatrix([[0, -c0], [1, -c1]]) assert CompanionMatrix(Poly([1, c2, c1, c0], x)).as_explicit() == \ ImmutableDenseMatrix([[0, 0, -c0], [1, 0, -c1], [0, 1, -c2]]) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_derivatives.py000066400000000000000000000345751412543434000264130ustar00rootroot00000000000000""" Some examples have been taken from: http://www.math.uwaterloo.ca/~hwolkowi//matrixcookbook.pdf """ from sympy import (MatrixSymbol, Inverse, symbols, Determinant, Trace, sin, exp, cos, tan, log, S, sqrt, hadamard_product, DiagMatrix, OneMatrix, HadamardProduct, HadamardPower, KroneckerDelta, Sum, Rational) from sympy import MatAdd, Identity, MatMul, ZeroMatrix from sympy.tensor.array.array_derivatives import ArrayDerivative from sympy.matrices.expressions import hadamard_power k = symbols("k") i, j = symbols("i j") m, n = symbols("m n") X = MatrixSymbol("X", k, k) x = MatrixSymbol("x", k, 1) y = MatrixSymbol("y", k, 1) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) D = MatrixSymbol("D", k, k) a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) c = MatrixSymbol("c", k, 1) d = MatrixSymbol("d", k, 1) KDelta = lambda i, j: KroneckerDelta(i, j, (0, k-1)) def _check_derivative_with_explicit_matrix(expr, x, diffexpr, dim=2): # TODO: this is commented because it slows down the tests. return expr = expr.xreplace({k: dim}) x = x.xreplace({k: dim}) diffexpr = diffexpr.xreplace({k: dim}) expr = expr.as_explicit() x = x.as_explicit() diffexpr = diffexpr.as_explicit() assert expr.diff(x).reshape(*diffexpr.shape).tomatrix() == diffexpr def test_matrix_derivative_by_scalar(): assert A.diff(i) == ZeroMatrix(k, k) assert (A*(X + B)*c).diff(i) == ZeroMatrix(k, 1) assert x.diff(i) == ZeroMatrix(k, 1) assert (x.T*y).diff(i) == ZeroMatrix(1, 1) assert (x*x.T).diff(i) == ZeroMatrix(k, k) assert (x + y).diff(i) == ZeroMatrix(k, 1) assert hadamard_power(x, 2).diff(i) == ZeroMatrix(k, 1) assert hadamard_power(x, i).diff(i).dummy_eq( HadamardProduct(x.applyfunc(log), HadamardPower(x, i))) assert hadamard_product(x, y).diff(i) == ZeroMatrix(k, 1) assert hadamard_product(i*OneMatrix(k, 1), x, y).diff(i) == hadamard_product(x, y) assert (i*x).diff(i) == x assert (sin(i)*A*B*x).diff(i) == cos(i)*A*B*x assert x.applyfunc(sin).diff(i) == ZeroMatrix(k, 1) assert Trace(i**2*X).diff(i) == 2*i*Trace(X) mu = symbols("mu") expr = (2*mu*x) assert expr.diff(x) == 2*mu*Identity(k) def test_matrix_derivative_non_matrix_result(): # This is a 4-dimensional array: assert A.diff(A) == ArrayDerivative(A, A) assert A.T.diff(A) == ArrayDerivative(A.T, A) assert (2*A).diff(A) == ArrayDerivative(2*A, A) assert MatAdd(A, A).diff(A) == ArrayDerivative(MatAdd(A, A), A) assert (A + B).diff(A) == ArrayDerivative(A + B, A) # TODO: `B` can be removed. def test_matrix_derivative_trivial_cases(): # Cookbook example 33: # TODO: find a way to represent a four-dimensional zero-array: assert X.diff(A) == ArrayDerivative(X, A) def test_matrix_derivative_with_inverse(): # Cookbook example 61: expr = a.T*Inverse(X)*b assert expr.diff(X) == -Inverse(X).T*a*b.T*Inverse(X).T # Cookbook example 62: expr = Determinant(Inverse(X)) # Not implemented yet: # assert expr.diff(X) == -Determinant(X.inv())*(X.inv()).T # Cookbook example 63: expr = Trace(A*Inverse(X)*B) assert expr.diff(X) == -(X**(-1)*B*A*X**(-1)).T # Cookbook example 64: expr = Trace(Inverse(X + A)) assert expr.diff(X) == -(Inverse(X + A)).T**2 def test_matrix_derivative_vectors_and_scalars(): assert x.diff(x) == Identity(k) assert x[i, 0].diff(x[m, 0]).doit() == KDelta(m, i) assert x.T.diff(x) == Identity(k) # Cookbook example 69: expr = x.T*a assert expr.diff(x) == a assert expr[0, 0].diff(x[m, 0]).doit() == a[m, 0] expr = a.T*x assert expr.diff(x) == a # Cookbook example 70: expr = a.T*X*b assert expr.diff(X) == a*b.T # Cookbook example 71: expr = a.T*X.T*b assert expr.diff(X) == b*a.T # Cookbook example 72: expr = a.T*X*a assert expr.diff(X) == a*a.T expr = a.T*X.T*a assert expr.diff(X) == a*a.T # Cookbook example 77: expr = b.T*X.T*X*c assert expr.diff(X) == X*b*c.T + X*c*b.T # Cookbook example 78: expr = (B*x + b).T*C*(D*x + d) assert expr.diff(x) == B.T*C*(D*x + d) + D.T*C.T*(B*x + b) # Cookbook example 81: expr = x.T*B*x assert expr.diff(x) == B*x + B.T*x # Cookbook example 82: expr = b.T*X.T*D*X*c assert expr.diff(X) == D.T*X*b*c.T + D*X*c*b.T # Cookbook example 83: expr = (X*b + c).T*D*(X*b + c) assert expr.diff(X) == D*(X*b + c)*b.T + D.T*(X*b + c)*b.T assert str(expr[0, 0].diff(X[m, n]).doit()) == \ 'b[n, 0]*Sum((c[_i_1, 0] + Sum(X[_i_1, _i_3]*b[_i_3, 0], (_i_3, 0, k - 1)))*D[_i_1, m], (_i_1, 0, k - 1)) + Sum((c[_i_2, 0] + Sum(X[_i_2, _i_4]*b[_i_4, 0], (_i_4, 0, k - 1)))*D[m, _i_2]*b[n, 0], (_i_2, 0, k - 1))' def test_matrix_derivatives_of_traces(): expr = Trace(A)*A assert expr.diff(A) == ArrayDerivative(Trace(A)*A, A) assert expr[i, j].diff(A[m, n]).doit() == ( KDelta(i, m)*KDelta(j, n)*Trace(A) + KDelta(m, n)*A[i, j] ) ## First order: # Cookbook example 99: expr = Trace(X) assert expr.diff(X) == Identity(k) assert expr.rewrite(Sum).diff(X[m, n]).doit() == KDelta(m, n) # Cookbook example 100: expr = Trace(X*A) assert expr.diff(X) == A.T assert expr.rewrite(Sum).diff(X[m, n]).doit() == A[n, m] # Cookbook example 101: expr = Trace(A*X*B) assert expr.diff(X) == A.T*B.T assert expr.rewrite(Sum).diff(X[m, n]).doit().dummy_eq((A.T*B.T)[m, n]) # Cookbook example 102: expr = Trace(A*X.T*B) assert expr.diff(X) == B*A # Cookbook example 103: expr = Trace(X.T*A) assert expr.diff(X) == A # Cookbook example 104: expr = Trace(A*X.T) assert expr.diff(X) == A # Cookbook example 105: # TODO: TensorProduct is not supported #expr = Trace(TensorProduct(A, X)) #assert expr.diff(X) == Trace(A)*Identity(k) ## Second order: # Cookbook example 106: expr = Trace(X**2) assert expr.diff(X) == 2*X.T # Cookbook example 107: expr = Trace(X**2*B) assert expr.diff(X) == (X*B + B*X).T expr = Trace(MatMul(X, X, B)) assert expr.diff(X) == (X*B + B*X).T # Cookbook example 108: expr = Trace(X.T*B*X) assert expr.diff(X) == B*X + B.T*X # Cookbook example 109: expr = Trace(B*X*X.T) assert expr.diff(X) == B*X + B.T*X # Cookbook example 110: expr = Trace(X*X.T*B) assert expr.diff(X) == B*X + B.T*X # Cookbook example 111: expr = Trace(X*B*X.T) assert expr.diff(X) == X*B.T + X*B # Cookbook example 112: expr = Trace(B*X.T*X) assert expr.diff(X) == X*B.T + X*B # Cookbook example 113: expr = Trace(X.T*X*B) assert expr.diff(X) == X*B.T + X*B # Cookbook example 114: expr = Trace(A*X*B*X) assert expr.diff(X) == A.T*X.T*B.T + B.T*X.T*A.T # Cookbook example 115: expr = Trace(X.T*X) assert expr.diff(X) == 2*X expr = Trace(X*X.T) assert expr.diff(X) == 2*X # Cookbook example 116: expr = Trace(B.T*X.T*C*X*B) assert expr.diff(X) == C.T*X*B*B.T + C*X*B*B.T # Cookbook example 117: expr = Trace(X.T*B*X*C) assert expr.diff(X) == B*X*C + B.T*X*C.T # Cookbook example 118: expr = Trace(A*X*B*X.T*C) assert expr.diff(X) == A.T*C.T*X*B.T + C*A*X*B # Cookbook example 119: expr = Trace((A*X*B + C)*(A*X*B + C).T) assert expr.diff(X) == 2*A.T*(A*X*B + C)*B.T # Cookbook example 120: # TODO: no support for TensorProduct. # expr = Trace(TensorProduct(X, X)) # expr = Trace(X)*Trace(X) # expr.diff(X) == 2*Trace(X)*Identity(k) # Higher Order # Cookbook example 121: expr = Trace(X**k) #assert expr.diff(X) == k*(X**(k-1)).T # Cookbook example 122: expr = Trace(A*X**k) #assert expr.diff(X) == # Needs indices # Cookbook example 123: expr = Trace(B.T*X.T*C*X*X.T*C*X*B) assert expr.diff(X) == C*X*X.T*C*X*B*B.T + C.T*X*B*B.T*X.T*C.T*X + C*X*B*B.T*X.T*C*X + C.T*X*X.T*C.T*X*B*B.T # Other # Cookbook example 124: expr = Trace(A*X**(-1)*B) assert expr.diff(X) == -Inverse(X).T*A.T*B.T*Inverse(X).T # Cookbook example 125: expr = Trace(Inverse(X.T*C*X)*A) # Warning: result in the cookbook is equivalent if B and C are symmetric: assert expr.diff(X) == - X.inv().T*A.T*X.inv()*C.inv().T*X.inv().T - X.inv().T*A*X.inv()*C.inv()*X.inv().T # Cookbook example 126: expr = Trace((X.T*C*X).inv()*(X.T*B*X)) assert expr.diff(X) == -2*C*X*(X.T*C*X).inv()*X.T*B*X*(X.T*C*X).inv() + 2*B*X*(X.T*C*X).inv() # Cookbook example 127: expr = Trace((A + X.T*C*X).inv()*(X.T*B*X)) # Warning: result in the cookbook is equivalent if B and C are symmetric: assert expr.diff(X) == B*X*Inverse(A + X.T*C*X) - C*X*Inverse(A + X.T*C*X)*X.T*B*X*Inverse(A + X.T*C*X) - C.T*X*Inverse(A.T + (C*X).T*X)*X.T*B.T*X*Inverse(A.T + (C*X).T*X) + B.T*X*Inverse(A.T + (C*X).T*X) def test_derivatives_of_complicated_matrix_expr(): expr = a.T*(A*X*(X.T*B + X*A) + B.T*X.T*(a*b.T*(X*D*X.T + X*(X.T*B + A*X)*D*B - X.T*C.T*A)*B + B*(X*D.T + B*A*X*A.T - 3*X*D))*B + 42*X*B*X.T*A.T*(X + X.T))*b result = (B*(B*A*X*A.T - 3*X*D + X*D.T) + a*b.T*(X*(A*X + X.T*B)*D*B + X*D*X.T - X.T*C.T*A)*B)*B*b*a.T*B.T + B**2*b*a.T*B.T*X.T*a*b.T*X*D + 42*A*X*B.T*X.T*a*b.T + B*D*B**3*b*a.T*B.T*X.T*a*b.T*X + B*b*a.T*A*X + 42*a*b.T*(X + X.T)*A*X*B.T + b*a.T*X*B*a*b.T*B.T**2*X*D.T + b*a.T*X*B*a*b.T*B.T**3*D.T*(B.T*X + X.T*A.T) + 42*b*a.T*X*B*X.T*A.T + 42*A.T*(X + X.T)*b*a.T*X*B + A.T*B.T**2*X*B*a*b.T*B.T*A + A.T*a*b.T*(A.T*X.T + B.T*X) + A.T*X.T*b*a.T*X*B*a*b.T*B.T**3*D.T + B.T*X*B*a*b.T*B.T*D - 3*B.T*X*B*a*b.T*B.T*D.T - C.T*A*B**2*b*a.T*B.T*X.T*a*b.T + X.T*A.T*a*b.T*A.T assert expr.diff(X) == result def test_mixed_deriv_mixed_expressions(): expr = 3*Trace(A) assert expr.diff(A) == 3*Identity(k) expr = k deriv = expr.diff(A) assert isinstance(deriv, ZeroMatrix) assert deriv == ZeroMatrix(k, k) expr = Trace(A)**2 assert expr.diff(A) == (2*Trace(A))*Identity(k) expr = Trace(A)*A # TODO: this is not yet supported: assert expr.diff(A) == ArrayDerivative(expr, A) expr = Trace(Trace(A)*A) assert expr.diff(A) == (2*Trace(A))*Identity(k) expr = Trace(Trace(Trace(A)*A)*A) assert expr.diff(A) == (3*Trace(A)**2)*Identity(k) def test_derivatives_matrix_norms(): expr = x.T*y assert expr.diff(x) == y assert expr[0, 0].diff(x[m, 0]).doit() == y[m, 0] expr = (x.T*y)**S.Half assert expr.diff(x) == y/(2*sqrt(x.T*y)) expr = (x.T*x)**S.Half assert expr.diff(x) == x*(x.T*x)**Rational(-1, 2) expr = (c.T*a*x.T*b)**S.Half assert expr.diff(x) == b/(2*sqrt(c.T*a*x.T*b))*c.T*a expr = (c.T*a*x.T*b)**Rational(1, 3) assert expr.diff(x) == b*(c.T*a*x.T*b)**Rational(-2, 3)*c.T*a/3 expr = (a.T*X*b)**S.Half assert expr.diff(X) == a/(2*sqrt(a.T*X*b))*b.T expr = d.T*x*(a.T*X*b)**S.Half*y.T*c assert expr.diff(X) == a*d.T*x/(2*sqrt(a.T*X*b))*y.T*c*b.T def test_derivatives_elementwise_applyfunc(): from sympy.matrices.expressions.diagonal import DiagMatrix expr = x.applyfunc(tan) assert expr.diff(x).dummy_eq( DiagMatrix(x.applyfunc(lambda x: tan(x)**2 + 1))) assert expr[i, 0].diff(x[m, 0]).doit() == (tan(x[i, 0])**2 + 1)*KDelta(i, m) _check_derivative_with_explicit_matrix(expr, x, expr.diff(x)) expr = (i**2*x).applyfunc(sin) assert expr.diff(i).dummy_eq( HadamardProduct((2*i)*x, (i**2*x).applyfunc(cos))) assert expr[i, 0].diff(i).doit() == 2*i*x[i, 0]*cos(i**2*x[i, 0]) _check_derivative_with_explicit_matrix(expr, i, expr.diff(i)) expr = (log(i)*A*B).applyfunc(sin) assert expr.diff(i).dummy_eq( HadamardProduct(A*B/i, (log(i)*A*B).applyfunc(cos))) _check_derivative_with_explicit_matrix(expr, i, expr.diff(i)) expr = A*x.applyfunc(exp) # TODO: restore this result (currently returning the transpose): # assert expr.diff(x).dummy_eq(DiagMatrix(x.applyfunc(exp))*A.T) _check_derivative_with_explicit_matrix(expr, x, expr.diff(x)) expr = x.T*A*x + k*y.applyfunc(sin).T*x assert expr.diff(x).dummy_eq(A.T*x + A*x + k*y.applyfunc(sin)) _check_derivative_with_explicit_matrix(expr, x, expr.diff(x)) expr = x.applyfunc(sin).T*y # TODO: restore (currently returning the traspose): # assert expr.diff(x).dummy_eq(DiagMatrix(x.applyfunc(cos))*y) _check_derivative_with_explicit_matrix(expr, x, expr.diff(x)) expr = (a.T * X * b).applyfunc(sin) assert expr.diff(X).dummy_eq(a*(a.T*X*b).applyfunc(cos)*b.T) _check_derivative_with_explicit_matrix(expr, X, expr.diff(X)) expr = a.T * X.applyfunc(sin) * b assert expr.diff(X).dummy_eq( DiagMatrix(a)*X.applyfunc(cos)*DiagMatrix(b)) _check_derivative_with_explicit_matrix(expr, X, expr.diff(X)) expr = a.T * (A*X*B).applyfunc(sin) * b assert expr.diff(X).dummy_eq( A.T*DiagMatrix(a)*(A*X*B).applyfunc(cos)*DiagMatrix(b)*B.T) _check_derivative_with_explicit_matrix(expr, X, expr.diff(X)) expr = a.T * (A*X*b).applyfunc(sin) * b.T # TODO: not implemented #assert expr.diff(X) == ... #_check_derivative_with_explicit_matrix(expr, X, expr.diff(X)) expr = a.T*A*X.applyfunc(sin)*B*b assert expr.diff(X).dummy_eq( DiagMatrix(A.T*a)*X.applyfunc(cos)*DiagMatrix(B*b)) expr = a.T * (A*X.applyfunc(sin)*B).applyfunc(log) * b # TODO: wrong # assert expr.diff(X) == A.T*DiagMatrix(a)*(A*X.applyfunc(sin)*B).applyfunc(Lambda(k, 1/k))*DiagMatrix(b)*B.T expr = a.T * (X.applyfunc(sin)).applyfunc(log) * b # TODO: wrong # assert expr.diff(X) == DiagMatrix(a)*X.applyfunc(sin).applyfunc(Lambda(k, 1/k))*DiagMatrix(b) def test_derivatives_of_hadamard_expressions(): # Hadamard Product expr = hadamard_product(a, x, b) assert expr.diff(x) == DiagMatrix(hadamard_product(b, a)) expr = a.T*hadamard_product(A, X, B)*b assert expr.diff(X) == DiagMatrix(a)*hadamard_product(B, A)*DiagMatrix(b) # Hadamard Power expr = hadamard_power(x, 2) assert expr.diff(x).doit() == 2*DiagMatrix(x) expr = hadamard_power(x.T, 2) assert expr.diff(x).doit() == 2*DiagMatrix(x) expr = hadamard_power(x, S.Half) assert expr.diff(x) == S.Half*DiagMatrix(hadamard_power(x, Rational(-1, 2))) expr = hadamard_power(a.T*X*b, 2) assert expr.diff(X) == 2*a*a.T*X*b*b.T expr = hadamard_power(a.T*X*b, S.Half) assert expr.diff(X) == a/2*hadamard_power(a.T*X*b, Rational(-1, 2))*b.T sympy-sympy-1.9/sympy/matrices/expressions/tests/test_determinant.py000066400000000000000000000026221412543434000263640ustar00rootroot00000000000000from sympy.core import S, symbols from sympy.matrices import eye, Matrix, ShapeError from sympy.matrices.expressions import ( Identity, MatrixExpr, MatrixSymbol, Determinant, det, ZeroMatrix, Transpose ) from sympy.matrices.expressions.special import OneMatrix from sympy.testing.pytest import raises from sympy import refine, Q n = symbols('n', integer=True) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) C = MatrixSymbol('C', 3, 4) def test_det(): assert isinstance(Determinant(A), Determinant) assert not isinstance(Determinant(A), MatrixExpr) raises(ShapeError, lambda: Determinant(C)) assert det(eye(3)) == 1 assert det(Matrix(3, 3, [1, 3, 2, 4, 1, 3, 2, 5, 2])) == 17 A / det(A) # Make sure this is possible raises(TypeError, lambda: Determinant(S.One)) assert Determinant(A).arg is A def test_eval_determinant(): assert det(Identity(n)) == 1 assert det(ZeroMatrix(n, n)) == 0 assert det(OneMatrix(n, n)) == Determinant(OneMatrix(n, n)) assert det(OneMatrix(1, 1)) == 1 assert det(OneMatrix(2, 2)) == 0 assert det(Transpose(A)) == det(A) def test_refine(): assert refine(det(A), Q.orthogonal(A)) == 1 assert refine(det(A), Q.singular(A)) == 0 def test_commutative(): det_a = Determinant(A) det_b = Determinant(B) assert det_a.is_commutative assert det_b.is_commutative assert det_a * det_b == det_b * det_a sympy-sympy-1.9/sympy/matrices/expressions/tests/test_diagonal.py000066400000000000000000000103061412543434000256260ustar00rootroot00000000000000from sympy.matrices.expressions import MatrixSymbol from sympy.matrices.expressions.diagonal import DiagonalMatrix, DiagonalOf, DiagMatrix, diagonalize_vector from sympy import Symbol, ask, Q, KroneckerDelta, Identity, Matrix, MatMul from sympy.testing.pytest import raises n = Symbol('n') m = Symbol('m') def test_DiagonalMatrix(): x = MatrixSymbol('x', n, m) D = DiagonalMatrix(x) assert D.diagonal_length is None assert D.shape == (n, m) x = MatrixSymbol('x', n, n) D = DiagonalMatrix(x) assert D.diagonal_length == n assert D.shape == (n, n) assert D[1, 2] == 0 assert D[1, 1] == x[1, 1] i = Symbol('i') j = Symbol('j') x = MatrixSymbol('x', 3, 3) ij = DiagonalMatrix(x)[i, j] assert ij != 0 assert ij.subs({i:0, j:0}) == x[0, 0] assert ij.subs({i:0, j:1}) == 0 assert ij.subs({i:1, j:1}) == x[1, 1] assert ask(Q.diagonal(D)) # affirm that D is diagonal x = MatrixSymbol('x', n, 3) D = DiagonalMatrix(x) assert D.diagonal_length == 3 assert D.shape == (n, 3) assert D[2, m] == KroneckerDelta(2, m)*x[2, m] assert D[3, m] == 0 raises(IndexError, lambda: D[m, 3]) x = MatrixSymbol('x', 3, n) D = DiagonalMatrix(x) assert D.diagonal_length == 3 assert D.shape == (3, n) assert D[m, 2] == KroneckerDelta(m, 2)*x[m, 2] assert D[m, 3] == 0 raises(IndexError, lambda: D[3, m]) x = MatrixSymbol('x', n, m) D = DiagonalMatrix(x) assert D.diagonal_length is None assert D.shape == (n, m) assert D[m, 4] != 0 x = MatrixSymbol('x', 3, 4) assert [DiagonalMatrix(x)[i] for i in range(12)] == [ x[0, 0], 0, 0, 0, 0, x[1, 1], 0, 0, 0, 0, x[2, 2], 0] # shape is retained, issue 12427 assert ( DiagonalMatrix(MatrixSymbol('x', 3, 4))* DiagonalMatrix(MatrixSymbol('x', 4, 2))).shape == (3, 2) def test_DiagonalOf(): x = MatrixSymbol('x', n, n) d = DiagonalOf(x) assert d.shape == (n, 1) assert d.diagonal_length == n assert d[2, 0] == d[2] == x[2, 2] x = MatrixSymbol('x', n, m) d = DiagonalOf(x) assert d.shape == (None, 1) assert d.diagonal_length is None assert d[2, 0] == d[2] == x[2, 2] d = DiagonalOf(MatrixSymbol('x', 4, 3)) assert d.shape == (3, 1) d = DiagonalOf(MatrixSymbol('x', n, 3)) assert d.shape == (3, 1) d = DiagonalOf(MatrixSymbol('x', 3, n)) assert d.shape == (3, 1) x = MatrixSymbol('x', n, m) assert [DiagonalOf(x)[i] for i in range(4)] ==[ x[0, 0], x[1, 1], x[2, 2], x[3, 3]] def test_DiagMatrix(): x = MatrixSymbol('x', n, 1) d = DiagMatrix(x) assert d.shape == (n, n) assert d[0, 1] == 0 assert d[0, 0] == x[0, 0] a = MatrixSymbol('a', 1, 1) d = diagonalize_vector(a) assert isinstance(d, MatrixSymbol) assert a == d assert diagonalize_vector(Identity(3)) == Identity(3) assert DiagMatrix(Identity(3)).doit() == Identity(3) assert isinstance(DiagMatrix(Identity(3)), DiagMatrix) # A diagonal matrix is equal to its transpose: assert DiagMatrix(x).T == DiagMatrix(x) assert diagonalize_vector(x.T) == DiagMatrix(x) dx = DiagMatrix(x) assert dx[0, 0] == x[0, 0] assert dx[1, 1] == x[1, 0] assert dx[0, 1] == 0 assert dx[0, m] == x[0, 0]*KroneckerDelta(0, m) z = MatrixSymbol('z', 1, n) dz = DiagMatrix(z) assert dz[0, 0] == z[0, 0] assert dz[1, 1] == z[0, 1] assert dz[0, 1] == 0 assert dz[0, m] == z[0, m]*KroneckerDelta(0, m) v = MatrixSymbol('v', 3, 1) dv = DiagMatrix(v) assert dv.as_explicit() == Matrix([ [v[0, 0], 0, 0], [0, v[1, 0], 0], [0, 0, v[2, 0]], ]) v = MatrixSymbol('v', 1, 3) dv = DiagMatrix(v) assert dv.as_explicit() == Matrix([ [v[0, 0], 0, 0], [0, v[0, 1], 0], [0, 0, v[0, 2]], ]) dv = DiagMatrix(3*v) assert dv.args == (3*v,) assert dv.doit() == 3*DiagMatrix(v) assert isinstance(dv.doit(), MatMul) a = MatrixSymbol("a", 3, 1).as_explicit() expr = DiagMatrix(a) result = Matrix([ [a[0, 0], 0, 0], [0, a[1, 0], 0], [0, 0, a[2, 0]], ]) assert expr.doit() == result expr = DiagMatrix(a.T) assert expr.doit() == result sympy-sympy-1.9/sympy/matrices/expressions/tests/test_dotproduct.py000066400000000000000000000022231412543434000262360ustar00rootroot00000000000000from sympy.core.expr import unchanged from sympy.core.mul import Mul from sympy.matrices import Matrix from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.matrices.expressions.dotproduct import DotProduct from sympy.testing.pytest import raises A = Matrix(3, 1, [1, 2, 3]) B = Matrix(3, 1, [1, 3, 5]) C = Matrix(4, 1, [1, 2, 4, 5]) D = Matrix(2, 2, [1, 2, 3, 4]) def test_docproduct(): assert DotProduct(A, B).doit() == 22 assert DotProduct(A.T, B).doit() == 22 assert DotProduct(A, B.T).doit() == 22 assert DotProduct(A.T, B.T).doit() == 22 raises(TypeError, lambda: DotProduct(1, A)) raises(TypeError, lambda: DotProduct(A, 1)) raises(TypeError, lambda: DotProduct(A, D)) raises(TypeError, lambda: DotProduct(D, A)) raises(TypeError, lambda: DotProduct(B, C).doit()) def test_dotproduct_symbolic(): A = MatrixSymbol('A', 3, 1) B = MatrixSymbol('B', 3, 1) dot = DotProduct(A, B) assert dot.is_scalar == True assert unchanged(Mul, 2, dot) # XXX Fix forced evaluation for arithmetics with matrix expressions assert dot * A == (A[0, 0]*B[0, 0] + A[1, 0]*B[1, 0] + A[2, 0]*B[2, 0])*A sympy-sympy-1.9/sympy/matrices/expressions/tests/test_factorizations.py000066400000000000000000000012651412543434000271130ustar00rootroot00000000000000from sympy.matrices.expressions.factorizations import lu, LofCholesky, qr, svd from sympy import Symbol, MatrixSymbol, ask, Q n = Symbol('n') X = MatrixSymbol('X', n, n) def test_LU(): L, U = lu(X) assert L.shape == U.shape == X.shape assert ask(Q.lower_triangular(L)) assert ask(Q.upper_triangular(U)) def test_Cholesky(): LofCholesky(X) def test_QR(): Q_, R = qr(X) assert Q_.shape == R.shape == X.shape assert ask(Q.orthogonal(Q_)) assert ask(Q.upper_triangular(R)) def test_svd(): U, S, V = svd(X) assert U.shape == S.shape == V.shape == X.shape assert ask(Q.orthogonal(U)) assert ask(Q.orthogonal(V)) assert ask(Q.diagonal(S)) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_fourier.py000066400000000000000000000025331412543434000255260ustar00rootroot00000000000000from sympy import S, I, ask, Q, Abs, simplify, exp, sqrt, Rational from sympy.core.symbol import symbols from sympy.matrices.expressions.fourier import DFT, IDFT from sympy.matrices import det, Matrix, Identity from sympy.testing.pytest import raises def test_dft_creation(): assert DFT(2) assert DFT(0) raises(ValueError, lambda: DFT(-1)) raises(ValueError, lambda: DFT(2.0)) raises(ValueError, lambda: DFT(2 + 1j)) n = symbols('n') assert DFT(n) n = symbols('n', integer=False) raises(ValueError, lambda: DFT(n)) n = symbols('n', negative=True) raises(ValueError, lambda: DFT(n)) def test_dft(): n, i, j = symbols('n i j') assert DFT(4).shape == (4, 4) assert ask(Q.unitary(DFT(4))) assert Abs(simplify(det(Matrix(DFT(4))))) == 1 assert DFT(n)*IDFT(n) == Identity(n) assert DFT(n)[i, j] == exp(-2*S.Pi*I/n)**(i*j) / sqrt(n) def test_dft2(): assert DFT(1).as_explicit() == Matrix([[1]]) assert DFT(2).as_explicit() == 1/sqrt(2)*Matrix([[1,1],[1,-1]]) assert DFT(4).as_explicit() == Matrix([[S.Half, S.Half, S.Half, S.Half], [S.Half, -I/2, Rational(-1,2), I/2], [S.Half, Rational(-1,2), S.Half, Rational(-1,2)], [S.Half, I/2, Rational(-1,2), -I/2]]) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_funcmatrix.py000066400000000000000000000043071412543434000262340ustar00rootroot00000000000000from sympy.core import symbols, Lambda from sympy.functions import KroneckerDelta from sympy.matrices import Matrix from sympy.matrices.expressions import FunctionMatrix, MatrixExpr, Identity from sympy.testing.pytest import raises, warns_deprecated_sympy def test_funcmatrix_creation(): i, j, k = symbols('i j k') assert FunctionMatrix(2, 2, Lambda((i, j), 0)) assert FunctionMatrix(0, 0, Lambda((i, j), 0)) raises(ValueError, lambda: FunctionMatrix(-1, 0, Lambda((i, j), 0))) raises(ValueError, lambda: FunctionMatrix(2.0, 0, Lambda((i, j), 0))) raises(ValueError, lambda: FunctionMatrix(2j, 0, Lambda((i, j), 0))) raises(ValueError, lambda: FunctionMatrix(0, -1, Lambda((i, j), 0))) raises(ValueError, lambda: FunctionMatrix(0, 2.0, Lambda((i, j), 0))) raises(ValueError, lambda: FunctionMatrix(0, 2j, Lambda((i, j), 0))) raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda(i, 0))) with warns_deprecated_sympy(): raises(ValueError, lambda: FunctionMatrix(2, 2, lambda i, j: 0)) raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i,), 0))) raises(ValueError, lambda: FunctionMatrix(2, 2, Lambda((i, j, k), 0))) raises(ValueError, lambda: FunctionMatrix(2, 2, i+j)) assert FunctionMatrix(2, 2, "lambda i, j: 0") == \ FunctionMatrix(2, 2, Lambda((i, j), 0)) m = FunctionMatrix(2, 2, KroneckerDelta) assert m.as_explicit() == Identity(2).as_explicit() assert m.args[2].dummy_eq(Lambda((i, j), KroneckerDelta(i, j))) n = symbols('n') assert FunctionMatrix(n, n, Lambda((i, j), 0)) n = symbols('n', integer=False) raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0))) n = symbols('n', negative=True) raises(ValueError, lambda: FunctionMatrix(n, n, Lambda((i, j), 0))) def test_funcmatrix(): i, j = symbols('i,j') X = FunctionMatrix(3, 3, Lambda((i, j), i - j)) assert X[1, 1] == 0 assert X[1, 2] == -1 assert X.shape == (3, 3) assert X.rows == X.cols == 3 assert Matrix(X) == Matrix(3, 3, lambda i, j: i - j) assert isinstance(X*X + X, MatrixExpr) def test_replace_issue(): X = FunctionMatrix(3, 3, KroneckerDelta) assert X.replace(lambda x: True, lambda x: x) == X sympy-sympy-1.9/sympy/matrices/expressions/tests/test_hadamard.py000066400000000000000000000076751412543434000256300ustar00rootroot00000000000000from sympy import Identity, OneMatrix, ZeroMatrix, Matrix, MatAdd from sympy.core import symbols from sympy.testing.pytest import raises from sympy.matrices import ShapeError, MatrixSymbol from sympy.matrices.expressions import (HadamardProduct, hadamard_product, HadamardPower, hadamard_power) n, m, k = symbols('n,m,k') Z = MatrixSymbol('Z', n, n) A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, k) def test_HadamardProduct(): assert HadamardProduct(A, B, A).shape == A.shape raises(ShapeError, lambda: HadamardProduct(A, B.T)) raises(TypeError, lambda: HadamardProduct(A, n)) raises(TypeError, lambda: HadamardProduct(A, 1)) assert HadamardProduct(A, 2*B, -A)[1, 1] == \ -2 * A[1, 1] * B[1, 1] * A[1, 1] mix = HadamardProduct(Z*A, B)*C assert mix.shape == (n, k) assert set(HadamardProduct(A, B, A).T.args) == {A.T, A.T, B.T} def test_HadamardProduct_isnt_commutative(): assert HadamardProduct(A, B) != HadamardProduct(B, A) def test_mixed_indexing(): X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) Z = MatrixSymbol('Z', 2, 2) assert (X*HadamardProduct(Y, Z))[0, 0] == \ X[0, 0]*Y[0, 0]*Z[0, 0] + X[0, 1]*Y[1, 0]*Z[1, 0] def test_canonicalize(): X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) expr = HadamardProduct(X, check=False) assert isinstance(expr, HadamardProduct) expr2 = expr.doit() # unpack is called assert isinstance(expr2, MatrixSymbol) Z = ZeroMatrix(2, 2) U = OneMatrix(2, 2) assert HadamardProduct(Z, X).doit() == Z assert HadamardProduct(U, X, X, U).doit() == HadamardPower(X, 2) assert HadamardProduct(X, U, Y).doit() == HadamardProduct(X, Y) assert HadamardProduct(X, Z, U, Y).doit() == Z def test_hadamard(): m, n, p = symbols('m, n, p', integer=True) A = MatrixSymbol('A', m, n) B = MatrixSymbol('B', m, n) C = MatrixSymbol('C', m, p) X = MatrixSymbol('X', m, m) I = Identity(m) with raises(TypeError): hadamard_product() assert hadamard_product(A) == A assert isinstance(hadamard_product(A, B), HadamardProduct) assert hadamard_product(A, B).doit() == hadamard_product(A, B) with raises(ShapeError): hadamard_product(A, C) hadamard_product(A, I) assert hadamard_product(X, I) == X assert isinstance(hadamard_product(X, I), MatrixSymbol) a = MatrixSymbol("a", k, 1) expr = MatAdd(ZeroMatrix(k, 1), OneMatrix(k, 1)) expr = HadamardProduct(expr, a) assert expr.doit() == a def test_hadamard_product_with_explicit_mat(): A = MatrixSymbol("A", 3, 3).as_explicit() B = MatrixSymbol("B", 3, 3).as_explicit() X = MatrixSymbol("X", 3, 3) expr = hadamard_product(A, B) ret = Matrix([i*j for i, j in zip(A, B)]).reshape(3, 3) assert expr == ret expr = hadamard_product(A, X, B) assert expr == HadamardProduct(ret, X) def test_hadamard_power(): m, n, p = symbols('m, n, p', integer=True) A = MatrixSymbol('A', m, n) assert hadamard_power(A, 1) == A assert isinstance(hadamard_power(A, 2), HadamardPower) assert hadamard_power(A, n).T == hadamard_power(A.T, n) assert hadamard_power(A, n)[0, 0] == A[0, 0]**n assert hadamard_power(m, n) == m**n raises(ValueError, lambda: hadamard_power(A, A)) def test_hadamard_power_explicit(): from sympy.matrices import Matrix A = MatrixSymbol('A', 2, 2) B = MatrixSymbol('B', 2, 2) a, b = symbols('a b') assert HadamardPower(a, b) == a**b assert HadamardPower(a, B).as_explicit() == \ Matrix([ [a**B[0, 0], a**B[0, 1]], [a**B[1, 0], a**B[1, 1]]]) assert HadamardPower(A, b).as_explicit() == \ Matrix([ [A[0, 0]**b, A[0, 1]**b], [A[1, 0]**b, A[1, 1]**b]]) assert HadamardPower(A, B).as_explicit() == \ Matrix([ [A[0, 0]**B[0, 0], A[0, 1]**B[0, 1]], [A[1, 0]**B[1, 0], A[1, 1]**B[1, 1]]]) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_indexing.py000066400000000000000000000242051412543434000256600ustar00rootroot00000000000000from sympy import (symbols, MatrixSymbol, MatPow, BlockMatrix, KroneckerDelta, Identity, ZeroMatrix, ImmutableMatrix, eye, Sum, Dummy, trace, Symbol) from sympy.testing.pytest import raises, XFAIL from sympy.matrices.expressions.matexpr import MatrixElement, MatrixExpr k, l, m, n = symbols('k l m n', integer=True) i, j = symbols('i j', integer=True) W = MatrixSymbol('W', k, l) X = MatrixSymbol('X', l, m) Y = MatrixSymbol('Y', l, m) Z = MatrixSymbol('Z', m, n) X1 = MatrixSymbol('X1', m, m) X2 = MatrixSymbol('X2', m, m) X3 = MatrixSymbol('X3', m, m) X4 = MatrixSymbol('X4', m, m) A = MatrixSymbol('A', 2, 2) B = MatrixSymbol('B', 2, 2) x = MatrixSymbol('x', 1, 2) y = MatrixSymbol('x', 2, 1) def test_symbolic_indexing(): x12 = X[1, 2] assert all(s in str(x12) for s in ['1', '2', X.name]) # We don't care about the exact form of this. We do want to make sure # that all of these features are present def test_add_index(): assert (X + Y)[i, j] == X[i, j] + Y[i, j] def test_mul_index(): assert (A*y)[0, 0] == A[0, 0]*y[0, 0] + A[0, 1]*y[1, 0] assert (A*B).as_mutable() == (A.as_mutable() * B.as_mutable()) X = MatrixSymbol('X', n, m) Y = MatrixSymbol('Y', m, k) result = (X*Y)[4,2] expected = Sum(X[4, i]*Y[i, 2], (i, 0, m - 1)) assert result.args[0].dummy_eq(expected.args[0], i) assert result.args[1][1:] == expected.args[1][1:] def test_pow_index(): Q = MatPow(A, 2) assert Q[0, 0] == A[0, 0]**2 + A[0, 1]*A[1, 0] n = symbols("n") Q2 = A**n assert Q2[0, 0] == MatrixElement(Q2, 0, 0) def test_transpose_index(): assert X.T[i, j] == X[j, i] def test_Identity_index(): I = Identity(3) assert I[0, 0] == I[1, 1] == I[2, 2] == 1 assert I[1, 0] == I[0, 1] == I[2, 1] == 0 assert I[i, 0].delta_range == (0, 2) raises(IndexError, lambda: I[3, 3]) def test_block_index(): I = Identity(3) Z = ZeroMatrix(3, 3) B = BlockMatrix([[I, I], [I, I]]) e3 = ImmutableMatrix(eye(3)) BB = BlockMatrix([[e3, e3], [e3, e3]]) assert B[0, 0] == B[3, 0] == B[0, 3] == B[3, 3] == 1 assert B[4, 3] == B[5, 1] == 0 BB = BlockMatrix([[e3, e3], [e3, e3]]) assert B.as_explicit() == BB.as_explicit() BI = BlockMatrix([[I, Z], [Z, I]]) assert BI.as_explicit().equals(eye(6)) def test_block_index_symbolic(): # Note that these matrices may be zero-sized and indices may be negative, which causes # all naive simplifications given in the comments to be invalid A1 = MatrixSymbol('A1', n, k) A2 = MatrixSymbol('A2', n, l) A3 = MatrixSymbol('A3', m, k) A4 = MatrixSymbol('A4', m, l) A = BlockMatrix([[A1, A2], [A3, A4]]) assert A[0, 0] == MatrixElement(A, 0, 0) # Cannot be A1[0, 0] assert A[n - 1, k - 1] == A1[n - 1, k - 1] assert A[n, k] == A4[0, 0] assert A[n + m - 1, 0] == MatrixElement(A, n + m - 1, 0) # Cannot be A3[m - 1, 0] assert A[0, k + l - 1] == MatrixElement(A, 0, k + l - 1) # Cannot be A2[0, l - 1] assert A[n + m - 1, k + l - 1] == MatrixElement(A, n + m - 1, k + l - 1) # Cannot be A4[m - 1, l - 1] assert A[i, j] == MatrixElement(A, i, j) assert A[n + i, k + j] == MatrixElement(A, n + i, k + j) # Cannot be A4[i, j] assert A[n - i - 1, k - j - 1] == MatrixElement(A, n - i - 1, k - j - 1) # Cannot be A1[n - i - 1, k - j - 1] def test_block_index_symbolic_nonzero(): # All invalid simplifications from test_block_index_symbolic() that become valid if all # matrices have nonzero size and all indices are nonnegative k, l, m, n = symbols('k l m n', integer=True, positive=True) i, j = symbols('i j', integer=True, nonnegative=True) A1 = MatrixSymbol('A1', n, k) A2 = MatrixSymbol('A2', n, l) A3 = MatrixSymbol('A3', m, k) A4 = MatrixSymbol('A4', m, l) A = BlockMatrix([[A1, A2], [A3, A4]]) assert A[0, 0] == A1[0, 0] assert A[n + m - 1, 0] == A3[m - 1, 0] assert A[0, k + l - 1] == A2[0, l - 1] assert A[n + m - 1, k + l - 1] == A4[m - 1, l - 1] assert A[i, j] == MatrixElement(A, i, j) assert A[n + i, k + j] == A4[i, j] assert A[n - i - 1, k - j - 1] == A1[n - i - 1, k - j - 1] assert A[2 * n, 2 * k] == A4[n, k] def test_block_index_large(): n, m, k = symbols('n m k', integer=True, positive=True) i = symbols('i', integer=True, nonnegative=True) A1 = MatrixSymbol('A1', n, n) A2 = MatrixSymbol('A2', n, m) A3 = MatrixSymbol('A3', n, k) A4 = MatrixSymbol('A4', m, n) A5 = MatrixSymbol('A5', m, m) A6 = MatrixSymbol('A6', m, k) A7 = MatrixSymbol('A7', k, n) A8 = MatrixSymbol('A8', k, m) A9 = MatrixSymbol('A9', k, k) A = BlockMatrix([[A1, A2, A3], [A4, A5, A6], [A7, A8, A9]]) assert A[n + i, n + i] == MatrixElement(A, n + i, n + i) @XFAIL def test_block_index_symbolic_fail(): # To make this work, symbolic matrix dimensions would need to be somehow assumed nonnegative # even if the symbols aren't specified as such. Then 2 * n < n would correctly evaluate to # False in BlockMatrix._entry() A1 = MatrixSymbol('A1', n, 1) A2 = MatrixSymbol('A2', m, 1) A = BlockMatrix([[A1], [A2]]) assert A[2 * n, 0] == A2[n, 0] def test_slicing(): A.as_explicit()[0, :] # does not raise an error def test_errors(): raises(IndexError, lambda: Identity(2)[1, 2, 3, 4, 5]) raises(IndexError, lambda: Identity(2)[[1, 2, 3, 4, 5]]) def test_matrix_expression_to_indices(): i, j = symbols("i, j") i1, i2, i3 = symbols("i_1:4") def replace_dummies(expr): repl = {i: Symbol(i.name) for i in expr.atoms(Dummy)} return expr.xreplace(repl) expr = W*X*Z assert replace_dummies(expr._entry(i, j)) == \ Sum(W[i, i1]*X[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr expr = Z.T*X.T*W.T assert replace_dummies(expr._entry(i, j)) == \ Sum(W[j, i2]*X[i2, i1]*Z[i1, i], (i1, 0, m-1), (i2, 0, l-1)) assert MatrixExpr.from_index_summation(expr._entry(i, j), i) == expr expr = W*X*Z + W*Y*Z assert replace_dummies(expr._entry(i, j)) == \ Sum(W[i, i1]*X[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) +\ Sum(W[i, i1]*Y[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr expr = 2*W*X*Z + 3*W*Y*Z assert replace_dummies(expr._entry(i, j)) == \ 2*Sum(W[i, i1]*X[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) +\ 3*Sum(W[i, i1]*Y[i1, i2]*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr expr = W*(X + Y)*Z assert replace_dummies(expr._entry(i, j)) == \ Sum(W[i, i1]*(X[i1, i2] + Y[i1, i2])*Z[i2, j], (i1, 0, l-1), (i2, 0, m-1)) assert MatrixExpr.from_index_summation(expr._entry(i, j)) == expr expr = A*B**2*A #assert replace_dummies(expr._entry(i, j)) == \ # Sum(A[i, i1]*B[i1, i2]*B[i2, i3]*A[i3, j], (i1, 0, 1), (i2, 0, 1), (i3, 0, 1)) # Check that different dummies are used in sub-multiplications: expr = (X1*X2 + X2*X1)*X3 assert replace_dummies(expr._entry(i, j)) == \ Sum((Sum(X1[i, i2] * X2[i2, i1], (i2, 0, m - 1)) + Sum(X1[i3, i1] * X2[i, i3], (i3, 0, m - 1))) * X3[ i1, j], (i1, 0, m - 1)) def test_matrix_expression_from_index_summation(): from sympy.abc import a,b,c,d A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) w1 = MatrixSymbol("w1", k, 1) i0, i1, i2, i3, i4 = symbols("i0:5", cls=Dummy) expr = Sum(W[a,b]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 0, m-1)) assert MatrixExpr.from_index_summation(expr, a) == W*X*Z expr = Sum(W.T[b,a]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 0, m-1)) assert MatrixExpr.from_index_summation(expr, a) == W*X*Z expr = Sum(A[b, a]*B[b, c]*C[c, d], (b, 0, k-1), (c, 0, k-1)) assert MatrixSymbol.from_index_summation(expr, a) == A.T*B*C expr = Sum(A[b, a]*B[c, b]*C[c, d], (b, 0, k-1), (c, 0, k-1)) assert MatrixSymbol.from_index_summation(expr, a) == A.T*B.T*C expr = Sum(C[c, d]*A[b, a]*B[c, b], (b, 0, k-1), (c, 0, k-1)) assert MatrixSymbol.from_index_summation(expr, a) == A.T*B.T*C expr = Sum(A[a, b] + B[a, b], (a, 0, k-1), (b, 0, k-1)) assert MatrixExpr.from_index_summation(expr, a) == A + B expr = Sum((A[a, b] + B[a, b])*C[b, c], (b, 0, k-1)) assert MatrixExpr.from_index_summation(expr, a) == (A+B)*C expr = Sum((A[a, b] + B[b, a])*C[b, c], (b, 0, k-1)) assert MatrixExpr.from_index_summation(expr, a) == (A+B.T)*C expr = Sum(A[a, b]*A[b, c]*A[c, d], (b, 0, k-1), (c, 0, k-1)) assert MatrixExpr.from_index_summation(expr, a) == A**3 expr = Sum(A[a, b]*A[b, c]*B[c, d], (b, 0, k-1), (c, 0, k-1)) assert MatrixExpr.from_index_summation(expr, a) == A**2*B # Parse the trace of a matrix: expr = Sum(A[a, a], (a, 0, k-1)) assert MatrixExpr.from_index_summation(expr, None) == trace(A) expr = Sum(A[a, a]*B[b, c]*C[c, d], (a, 0, k-1), (c, 0, k-1)) assert MatrixExpr.from_index_summation(expr, b) == trace(A)*B*C # Check wrong sum ranges (should raise an exception): ## Case 1: 0 to m instead of 0 to m-1 expr = Sum(W[a,b]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 0, m)) raises(ValueError, lambda: MatrixExpr.from_index_summation(expr, a)) ## Case 2: 1 to m-1 instead of 0 to m-1 expr = Sum(W[a,b]*X[b,c]*Z[c,d], (b, 0, l-1), (c, 1, m-1)) raises(ValueError, lambda: MatrixExpr.from_index_summation(expr, a)) # Parse nested sums: expr = Sum(A[a, b]*Sum(B[b, c]*C[c, d], (c, 0, k-1)), (b, 0, k-1)) assert MatrixExpr.from_index_summation(expr, a) == A*B*C # Test Kronecker delta: expr = Sum(A[a, b]*KroneckerDelta(b, c)*B[c, d], (b, 0, k-1), (c, 0, k-1)) assert MatrixExpr.from_index_summation(expr, a) == A*B expr = Sum(KroneckerDelta(i1, m)*KroneckerDelta(i2, n)*A[i, i1]*A[j, i2], (i1, 0, k-1), (i2, 0, k-1)) assert MatrixExpr.from_index_summation(expr, m) == A.T*A[j, n] # Test numbered indices: expr = Sum(A[i1, i2]*w1[i2, 0], (i2, 0, k-1)) assert MatrixExpr.from_index_summation(expr, i1) == A*w1 expr = Sum(A[i1, i2]*B[i2, 0], (i2, 0, k-1)) assert MatrixExpr.from_index_summation(expr, i1) == MatrixElement(A*B, i1, 0) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_inverse.py000066400000000000000000000041121412543434000255210ustar00rootroot00000000000000from sympy.core import symbols, S from sympy.matrices.expressions import MatrixSymbol, Inverse, MatPow, ZeroMatrix, OneMatrix from sympy.matrices.common import NonSquareMatrixError, NonInvertibleMatrixError from sympy.matrices import eye, Identity from sympy.testing.pytest import raises from sympy import refine, Q n, m, l = symbols('n m l', integer=True) A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) D = MatrixSymbol('D', n, n) E = MatrixSymbol('E', m, n) def test_inverse(): assert Inverse(C).args == (C, S.NegativeOne) assert Inverse(C).shape == (n, n) assert Inverse(A*E).shape == (n, n) assert Inverse(E*A).shape == (m, m) assert Inverse(C).inverse() == C assert Inverse(Inverse(C)).doit() == C assert isinstance(Inverse(Inverse(C)), Inverse) assert Inverse(*Inverse(E*A).args) == Inverse(E*A) assert C.inverse().inverse() == C assert C.inverse()*C == Identity(C.rows) assert Identity(n).inverse() == Identity(n) assert (3*Identity(n)).inverse() == Identity(n)/3 # Simplifies Muls if possible (i.e. submatrices are square) assert (C*D).inverse() == D.I*C.I # But still works when not possible assert isinstance((A*E).inverse(), Inverse) assert Inverse(C*D).doit(inv_expand=False) == Inverse(C*D) assert Inverse(eye(3)).doit() == eye(3) assert Inverse(eye(3)).doit(deep=False) == eye(3) assert OneMatrix(1, 1).I == Identity(1) assert isinstance(OneMatrix(n, n).I, Inverse) def test_inverse_non_invertible(): raises(NonSquareMatrixError, lambda: Inverse(A)) raises(NonSquareMatrixError, lambda: Inverse(A*B)) raises(NonSquareMatrixError, lambda: ZeroMatrix(n, m).I) raises(NonInvertibleMatrixError, lambda: ZeroMatrix(n, n).I) raises(NonSquareMatrixError, lambda: OneMatrix(n, m).I) raises(NonInvertibleMatrixError, lambda: OneMatrix(2, 2).I) def test_refine(): assert refine(C.I, Q.orthogonal(C)) == C.T def test_inverse_matpow_canonicalization(): A = MatrixSymbol('A', 3, 3) assert Inverse(MatPow(A, 3)).doit() == MatPow(Inverse(A), 3).doit() sympy-sympy-1.9/sympy/matrices/expressions/tests/test_kronecker.py000066400000000000000000000121411412543434000260320ustar00rootroot00000000000000from sympy import I, symbols, Matrix, eye, Mod, floor from sympy.matrices import MatrixSymbol, Identity from sympy.matrices.expressions import det, trace from sympy.matrices.expressions.kronecker import (KroneckerProduct, kronecker_product, combine_kronecker) mat1 = Matrix([[1, 2 * I], [1 + I, 3]]) mat2 = Matrix([[2 * I, 3], [4 * I, 2]]) i, j, k, n, m, o, p, x = symbols('i,j,k,n,m,o,p,x') Z = MatrixSymbol('Z', n, n) W = MatrixSymbol('W', m, m) A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, m) C = MatrixSymbol('C', m, k) def test_KroneckerProduct(): assert isinstance(KroneckerProduct(A, B), KroneckerProduct) assert KroneckerProduct(A, B).subs(A, C) == KroneckerProduct(C, B) assert KroneckerProduct(A, C).shape == (n*m, m*k) assert (KroneckerProduct(A, C) + KroneckerProduct(-A, C)).is_ZeroMatrix assert (KroneckerProduct(W, Z) * KroneckerProduct(W.I, Z.I)).is_Identity def test_KroneckerProduct_identity(): assert KroneckerProduct(Identity(m), Identity(n)) == Identity(m*n) assert KroneckerProduct(eye(2), eye(3)) == eye(6) def test_KroneckerProduct_explicit(): X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) kp = KroneckerProduct(X, Y) assert kp.shape == (4, 4) assert kp.as_explicit() == Matrix( [ [X[0, 0]*Y[0, 0], X[0, 0]*Y[0, 1], X[0, 1]*Y[0, 0], X[0, 1]*Y[0, 1]], [X[0, 0]*Y[1, 0], X[0, 0]*Y[1, 1], X[0, 1]*Y[1, 0], X[0, 1]*Y[1, 1]], [X[1, 0]*Y[0, 0], X[1, 0]*Y[0, 1], X[1, 1]*Y[0, 0], X[1, 1]*Y[0, 1]], [X[1, 0]*Y[1, 0], X[1, 0]*Y[1, 1], X[1, 1]*Y[1, 0], X[1, 1]*Y[1, 1]] ] ) def test_tensor_product_adjoint(): assert KroneckerProduct(I*A, B).adjoint() == \ -I*KroneckerProduct(A.adjoint(), B.adjoint()) assert KroneckerProduct(mat1, mat2).adjoint() == \ kronecker_product(mat1.adjoint(), mat2.adjoint()) def test_tensor_product_conjugate(): assert KroneckerProduct(I*A, B).conjugate() == \ -I*KroneckerProduct(A.conjugate(), B.conjugate()) assert KroneckerProduct(mat1, mat2).conjugate() == \ kronecker_product(mat1.conjugate(), mat2.conjugate()) def test_tensor_product_transpose(): assert KroneckerProduct(I*A, B).transpose() == \ I*KroneckerProduct(A.transpose(), B.transpose()) assert KroneckerProduct(mat1, mat2).transpose() == \ kronecker_product(mat1.transpose(), mat2.transpose()) def test_KroneckerProduct_is_associative(): assert kronecker_product(A, kronecker_product( B, C)) == kronecker_product(kronecker_product(A, B), C) assert kronecker_product(A, kronecker_product( B, C)) == KroneckerProduct(A, B, C) def test_KroneckerProduct_is_bilinear(): assert kronecker_product(x*A, B) == x*kronecker_product(A, B) assert kronecker_product(A, x*B) == x*kronecker_product(A, B) def test_KroneckerProduct_determinant(): kp = kronecker_product(W, Z) assert det(kp) == det(W)**n * det(Z)**m def test_KroneckerProduct_trace(): kp = kronecker_product(W, Z) assert trace(kp) == trace(W)*trace(Z) def test_KroneckerProduct_isnt_commutative(): assert KroneckerProduct(A, B) != KroneckerProduct(B, A) assert KroneckerProduct(A, B).is_commutative is False def test_KroneckerProduct_extracts_commutative_part(): assert kronecker_product(x * A, 2 * B) == x * \ 2 * KroneckerProduct(A, B) def test_KroneckerProduct_inverse(): kp = kronecker_product(W, Z) assert kp.inverse() == kronecker_product(W.inverse(), Z.inverse()) def test_KroneckerProduct_combine_add(): kp1 = kronecker_product(A, B) kp2 = kronecker_product(C, W) assert combine_kronecker(kp1*kp2) == kronecker_product(A*C, B*W) def test_KroneckerProduct_combine_mul(): X = MatrixSymbol('X', m, n) Y = MatrixSymbol('Y', m, n) kp1 = kronecker_product(A, X) kp2 = kronecker_product(B, Y) assert combine_kronecker(kp1+kp2) == kronecker_product(A+B, X+Y) def test_KroneckerProduct_combine_pow(): X = MatrixSymbol('X', n, n) Y = MatrixSymbol('Y', n, n) assert combine_kronecker(KroneckerProduct( X, Y)**x) == KroneckerProduct(X**x, Y**x) assert combine_kronecker(x * KroneckerProduct(X, Y) ** 2) == x * KroneckerProduct(X**2, Y**2) assert combine_kronecker( x * (KroneckerProduct(X, Y)**2) * KroneckerProduct(A, B)) == x * KroneckerProduct(X**2 * A, Y**2 * B) # cannot simplify because of non-square arguments to kronecker product: assert combine_kronecker(KroneckerProduct(A, B.T) ** m) == KroneckerProduct(A, B.T) ** m def test_KroneckerProduct_expand(): X = MatrixSymbol('X', n, n) Y = MatrixSymbol('Y', n, n) assert KroneckerProduct(X + Y, Y + Z).expand(kroneckerproduct=True) == \ KroneckerProduct(X, Y) + KroneckerProduct(X, Z) + \ KroneckerProduct(Y, Y) + KroneckerProduct(Y, Z) def test_KroneckerProduct_entry(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', o, p) assert KroneckerProduct(A, B)._entry(i, j) == A[Mod(floor(i/o), n), Mod(floor(j/p), m)]*B[Mod(i, o), Mod(j, p)] sympy-sympy-1.9/sympy/matrices/expressions/tests/test_matadd.py000066400000000000000000000031041412543434000253000ustar00rootroot00000000000000from sympy.matrices.expressions import MatrixSymbol, MatAdd, MatPow, MatMul from sympy.matrices.expressions.special import GenericZeroMatrix, ZeroMatrix from sympy.matrices import eye, ImmutableMatrix from sympy.core import Add, Basic, S from sympy.core.add import add from sympy.testing.pytest import XFAIL, raises X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) def test_evaluate(): assert MatAdd(X, X, evaluate=True) == add(X, X, evaluate=True) == MatAdd(X, X).doit() def test_sort_key(): assert MatAdd(Y, X).doit().args == add(Y, X).doit().args == (X, Y) def test_matadd_sympify(): assert isinstance(MatAdd(eye(1), eye(1)).args[0], Basic) assert isinstance(add(eye(1), eye(1)).args[0], Basic) def test_matadd_of_matrices(): assert MatAdd(eye(2), 4*eye(2), eye(2)).doit() == ImmutableMatrix(6*eye(2)) assert add(eye(2), 4*eye(2), eye(2)).doit() == ImmutableMatrix(6*eye(2)) def test_doit_args(): A = ImmutableMatrix([[1, 2], [3, 4]]) B = ImmutableMatrix([[2, 3], [4, 5]]) assert MatAdd(A, MatPow(B, 2)).doit() == A + B**2 assert MatAdd(A, MatMul(A, B)).doit() == A + A*B assert (MatAdd(A, X, MatMul(A, B), Y, MatAdd(2*A, B)).doit() == add(A, X, MatMul(A, B), Y, add(2*A, B)).doit() == MatAdd(3*A + A*B + B, X, Y)) def test_generic_identity(): assert MatAdd.identity == GenericZeroMatrix() assert MatAdd.identity != S.Zero def test_zero_matrix_add(): assert Add(ZeroMatrix(2, 2), ZeroMatrix(2, 2)) == ZeroMatrix(2, 2) @XFAIL def test_matrix_Add_with_scalar(): raises(TypeError, lambda: Add(0, ZeroMatrix(2, 2))) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_matexpr.py000066400000000000000000000365461412543434000255460ustar00rootroot00000000000000from sympy import (KroneckerDelta, diff, Sum, Dummy, factor, expand, zeros, gcd_terms, Eq, Symbol) from sympy.core import (S, symbols, Add, Mul, SympifyError, Rational, Function) from sympy.functions import sin, cos, tan, sqrt, cbrt, exp from sympy.simplify import simplify from sympy.matrices import (ImmutableMatrix, Inverse, MatAdd, MatMul, MatPow, Matrix, MatrixExpr, MatrixSymbol, ShapeError, SparseMatrix, Transpose, Adjoint, NonSquareMatrixError, MatrixSet) from sympy.matrices.expressions.matexpr import MatrixElement from sympy.matrices.expressions.special import ZeroMatrix, Identity from sympy.testing.pytest import raises, XFAIL n, m, l, k, p = symbols('n m l k p', integer=True) x = symbols('x') A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) D = MatrixSymbol('D', n, n) E = MatrixSymbol('E', m, n) w = MatrixSymbol('w', n, 1) def test_matrix_symbol_creation(): assert MatrixSymbol('A', 2, 2) assert MatrixSymbol('A', 0, 0) raises(ValueError, lambda: MatrixSymbol('A', -1, 2)) raises(ValueError, lambda: MatrixSymbol('A', 2.0, 2)) raises(ValueError, lambda: MatrixSymbol('A', 2j, 2)) raises(ValueError, lambda: MatrixSymbol('A', 2, -1)) raises(ValueError, lambda: MatrixSymbol('A', 2, 2.0)) raises(ValueError, lambda: MatrixSymbol('A', 2, 2j)) n = symbols('n') assert MatrixSymbol('A', n, n) n = symbols('n', integer=False) raises(ValueError, lambda: MatrixSymbol('A', n, n)) n = symbols('n', negative=True) raises(ValueError, lambda: MatrixSymbol('A', n, n)) def test_shape(): assert A.shape == (n, m) assert (A*B).shape == (n, l) raises(ShapeError, lambda: B*A) def test_matexpr(): assert (x*A).shape == A.shape assert (x*A).__class__ == MatMul assert 2*A - A - A == ZeroMatrix(*A.shape) assert (A*B).shape == (n, l) def test_subs(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', m, l) assert A.subs(n, m).shape == (m, m) assert (A*B).subs(B, C) == A*C assert (A*B).subs(l, n).is_square A = SparseMatrix([[1, 2], [3, 4]]) B = Matrix([[1, 2], [3, 4]]) C, D = MatrixSymbol('C', 2, 2), MatrixSymbol('D', 2, 2) assert (C*D).subs({C: A, D: B}) == MatMul(A, B) def test_addition(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', n, m) assert isinstance(A + B, MatAdd) assert (A + B).shape == A.shape assert isinstance(A - A + 2*B, MatMul) raises(ShapeError, lambda: A + B.T) raises(TypeError, lambda: A + 1) raises(TypeError, lambda: 5 + A) raises(TypeError, lambda: 5 - A) assert A + ZeroMatrix(n, m) - A == ZeroMatrix(n, m) with raises(TypeError): ZeroMatrix(n,m) + S.Zero def test_multiplication(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) assert (2*A*B).shape == (n, l) assert (A*0*B) == ZeroMatrix(n, l) raises(ShapeError, lambda: B*A) assert (2*A).shape == A.shape assert A * ZeroMatrix(m, m) * B == ZeroMatrix(n, l) assert C * Identity(n) * C.I == Identity(n) assert B/2 == S.Half*B raises(NotImplementedError, lambda: 2/B) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) assert Identity(n) * (A + B) == A + B assert A**2*A == A**3 assert A**2*(A.I)**3 == A.I assert A**3*(A.I)**2 == A def test_MatPow(): A = MatrixSymbol('A', n, n) AA = MatPow(A, 2) assert AA.exp == 2 assert AA.base == A assert (A**n).exp == n assert A**0 == Identity(n) assert A**1 == A assert A**2 == AA assert A**-1 == Inverse(A) assert (A**-1)**-1 == A assert (A**2)**3 == A**6 assert A**S.Half == sqrt(A) assert A**Rational(1, 3) == cbrt(A) raises(NonSquareMatrixError, lambda: MatrixSymbol('B', 3, 2)**2) def test_MatrixSymbol(): n, m, t = symbols('n,m,t') X = MatrixSymbol('X', n, m) assert X.shape == (n, m) raises(TypeError, lambda: MatrixSymbol('X', n, m)(t)) # issue 5855 assert X.doit() == X def test_dense_conversion(): X = MatrixSymbol('X', 2, 2) assert ImmutableMatrix(X) == ImmutableMatrix(2, 2, lambda i, j: X[i, j]) assert Matrix(X) == Matrix(2, 2, lambda i, j: X[i, j]) def test_free_symbols(): assert (C*D).free_symbols == {C, D} def test_zero_matmul(): assert isinstance(S.Zero * MatrixSymbol('X', 2, 2), MatrixExpr) def test_matadd_simplify(): A = MatrixSymbol('A', 1, 1) assert simplify(MatAdd(A, ImmutableMatrix([[sin(x)**2 + cos(x)**2]]))) == \ MatAdd(A, Matrix([[1]])) def test_matmul_simplify(): A = MatrixSymbol('A', 1, 1) assert simplify(MatMul(A, ImmutableMatrix([[sin(x)**2 + cos(x)**2]]))) == \ MatMul(A, Matrix([[1]])) def test_invariants(): A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) X = MatrixSymbol('X', n, n) objs = [Identity(n), ZeroMatrix(m, n), A, MatMul(A, B), MatAdd(A, A), Transpose(A), Adjoint(A), Inverse(X), MatPow(X, 2), MatPow(X, -1), MatPow(X, 0)] for obj in objs: assert obj == obj.__class__(*obj.args) def test_indexing(): A = MatrixSymbol('A', n, m) A[1, 2] A[l, k] A[l+1, k+1] def test_single_indexing(): A = MatrixSymbol('A', 2, 3) assert A[1] == A[0, 1] assert A[int(1)] == A[0, 1] assert A[3] == A[1, 0] assert list(A[:2, :2]) == [A[0, 0], A[0, 1], A[1, 0], A[1, 1]] raises(IndexError, lambda: A[6]) raises(IndexError, lambda: A[n]) B = MatrixSymbol('B', n, m) raises(IndexError, lambda: B[1]) B = MatrixSymbol('B', n, 3) assert B[3] == B[1, 0] def test_MatrixElement_commutative(): assert A[0, 1]*A[1, 0] == A[1, 0]*A[0, 1] def test_MatrixSymbol_determinant(): A = MatrixSymbol('A', 4, 4) assert A.as_explicit().det() == A[0, 0]*A[1, 1]*A[2, 2]*A[3, 3] - \ A[0, 0]*A[1, 1]*A[2, 3]*A[3, 2] - A[0, 0]*A[1, 2]*A[2, 1]*A[3, 3] + \ A[0, 0]*A[1, 2]*A[2, 3]*A[3, 1] + A[0, 0]*A[1, 3]*A[2, 1]*A[3, 2] - \ A[0, 0]*A[1, 3]*A[2, 2]*A[3, 1] - A[0, 1]*A[1, 0]*A[2, 2]*A[3, 3] + \ A[0, 1]*A[1, 0]*A[2, 3]*A[3, 2] + A[0, 1]*A[1, 2]*A[2, 0]*A[3, 3] - \ A[0, 1]*A[1, 2]*A[2, 3]*A[3, 0] - A[0, 1]*A[1, 3]*A[2, 0]*A[3, 2] + \ A[0, 1]*A[1, 3]*A[2, 2]*A[3, 0] + A[0, 2]*A[1, 0]*A[2, 1]*A[3, 3] - \ A[0, 2]*A[1, 0]*A[2, 3]*A[3, 1] - A[0, 2]*A[1, 1]*A[2, 0]*A[3, 3] + \ A[0, 2]*A[1, 1]*A[2, 3]*A[3, 0] + A[0, 2]*A[1, 3]*A[2, 0]*A[3, 1] - \ A[0, 2]*A[1, 3]*A[2, 1]*A[3, 0] - A[0, 3]*A[1, 0]*A[2, 1]*A[3, 2] + \ A[0, 3]*A[1, 0]*A[2, 2]*A[3, 1] + A[0, 3]*A[1, 1]*A[2, 0]*A[3, 2] - \ A[0, 3]*A[1, 1]*A[2, 2]*A[3, 0] - A[0, 3]*A[1, 2]*A[2, 0]*A[3, 1] + \ A[0, 3]*A[1, 2]*A[2, 1]*A[3, 0] def test_MatrixElement_diff(): assert (A[3, 0]*A[0, 0]).diff(A[0, 0]) == A[3, 0] def test_MatrixElement_doit(): u = MatrixSymbol('u', 2, 1) v = ImmutableMatrix([3, 5]) assert u[0, 0].subs(u, v).doit() == v[0, 0] def test_identity_powers(): M = Identity(n) assert MatPow(M, 3).doit() == M**3 assert M**n == M assert MatPow(M, 0).doit() == M**2 assert M**-2 == M assert MatPow(M, -2).doit() == M**0 N = Identity(3) assert MatPow(N, 2).doit() == N**n assert MatPow(N, 3).doit() == N assert MatPow(N, -2).doit() == N**4 assert MatPow(N, 2).doit() == N**0 def test_Zero_power(): z1 = ZeroMatrix(n, n) assert z1**4 == z1 raises(ValueError, lambda:z1**-2) assert z1**0 == Identity(n) assert MatPow(z1, 2).doit() == z1**2 raises(ValueError, lambda:MatPow(z1, -2).doit()) z2 = ZeroMatrix(3, 3) assert MatPow(z2, 4).doit() == z2**4 raises(ValueError, lambda:z2**-3) assert z2**3 == MatPow(z2, 3).doit() assert z2**0 == Identity(3) raises(ValueError, lambda:MatPow(z2, -1).doit()) def test_matrixelement_diff(): dexpr = diff((D*w)[k,0], w[p,0]) assert w[k, p].diff(w[k, p]) == 1 assert w[k, p].diff(w[0, 0]) == KroneckerDelta(0, k, (0, n-1))*KroneckerDelta(0, p, (0, 0)) _i_1 = Dummy("_i_1") assert dexpr.dummy_eq(Sum(KroneckerDelta(_i_1, p, (0, n-1))*D[k, _i_1], (_i_1, 0, n - 1))) assert dexpr.doit() == D[k, p] def test_MatrixElement_with_values(): x, y, z, w = symbols("x y z w") M = Matrix([[x, y], [z, w]]) i, j = symbols("i, j") Mij = M[i, j] assert isinstance(Mij, MatrixElement) Ms = SparseMatrix([[2, 3], [4, 5]]) msij = Ms[i, j] assert isinstance(msij, MatrixElement) for oi, oj in [(0, 0), (0, 1), (1, 0), (1, 1)]: assert Mij.subs({i: oi, j: oj}) == M[oi, oj] assert msij.subs({i: oi, j: oj}) == Ms[oi, oj] A = MatrixSymbol("A", 2, 2) assert A[0, 0].subs(A, M) == x assert A[i, j].subs(A, M) == M[i, j] assert M[i, j].subs(M, A) == A[i, j] assert isinstance(M[3*i - 2, j], MatrixElement) assert M[3*i - 2, j].subs({i: 1, j: 0}) == M[1, 0] assert isinstance(M[i, 0], MatrixElement) assert M[i, 0].subs(i, 0) == M[0, 0] assert M[0, i].subs(i, 1) == M[0, 1] assert M[i, j].diff(x) == Matrix([[1, 0], [0, 0]])[i, j] raises(ValueError, lambda: M[i, 2]) raises(ValueError, lambda: M[i, -1]) raises(ValueError, lambda: M[2, i]) raises(ValueError, lambda: M[-1, i]) def test_inv(): B = MatrixSymbol('B', 3, 3) assert B.inv() == B**-1 # https://github.com/sympy/sympy/issues/19162 X = MatrixSymbol('X', 1, 1).as_explicit() assert X.inv() == Matrix([[1/X[0, 0]]]) X = MatrixSymbol('X', 2, 2).as_explicit() detX = X[0, 0]*X[1, 1] - X[0, 1]*X[1, 0] invX = Matrix([[ X[1, 1], -X[0, 1]], [-X[1, 0], X[0, 0]]]) / detX assert X.inv() == invX @XFAIL def test_factor_expand(): A = MatrixSymbol("A", n, n) B = MatrixSymbol("B", n, n) expr1 = (A + B)*(C + D) expr2 = A*C + B*C + A*D + B*D assert expr1 != expr2 assert expand(expr1) == expr2 assert factor(expr2) == expr1 expr = B**(-1)*(A**(-1)*B**(-1) - A**(-1)*C*B**(-1))**(-1)*A**(-1) I = Identity(n) # Ideally we get the first, but we at least don't want a wrong answer assert factor(expr) in [I - C, B**-1*(A**-1*(I - C)*B**-1)**-1*A**-1] def test_issue_2749(): A = MatrixSymbol("A", 5, 2) assert (A.T * A).I.as_explicit() == Matrix([[(A.T * A).I[0, 0], (A.T * A).I[0, 1]], \ [(A.T * A).I[1, 0], (A.T * A).I[1, 1]]]) def test_issue_2750(): x = MatrixSymbol('x', 1, 1) assert (x.T*x).as_explicit()**-1 == Matrix([[x[0, 0]**(-2)]]) def test_issue_7842(): A = MatrixSymbol('A', 3, 1) B = MatrixSymbol('B', 2, 1) assert Eq(A, B) == False assert Eq(A[1,0], B[1, 0]).func is Eq A = ZeroMatrix(2, 3) B = ZeroMatrix(2, 3) assert Eq(A, B) == True def test_issue_21195(): t = symbols('t') x = Function('x')(t) dx = x.diff(t) exp1 = cos(x) + cos(x)*dx exp2 = sin(x) + tan(x)*(dx.diff(t)) exp3 = sin(x)*sin(t)*(dx.diff(t)).diff(t) A = Matrix([[exp1], [exp2], [exp3]]) B = Matrix([[exp1.diff(x)], [exp2.diff(x)], [exp3.diff(x)]]) assert A.diff(x) == B def test_MatMul_postprocessor(): z = zeros(2) z1 = ZeroMatrix(2, 2) assert Mul(0, z) == Mul(z, 0) in [z, z1] M = Matrix([[1, 2], [3, 4]]) Mx = Matrix([[x, 2*x], [3*x, 4*x]]) assert Mul(x, M) == Mul(M, x) == Mx A = MatrixSymbol("A", 2, 2) assert Mul(A, M) == MatMul(A, M) assert Mul(M, A) == MatMul(M, A) # Scalars should be absorbed into constant matrices a = Mul(x, M, A) b = Mul(M, x, A) c = Mul(M, A, x) assert a == b == c == MatMul(Mx, A) a = Mul(x, A, M) b = Mul(A, x, M) c = Mul(A, M, x) assert a == b == c == MatMul(A, Mx) assert Mul(M, M) == M**2 assert Mul(A, M, M) == MatMul(A, M**2) assert Mul(M, M, A) == MatMul(M**2, A) assert Mul(M, A, M) == MatMul(M, A, M) assert Mul(A, x, M, M, x) == MatMul(A, Mx**2) @XFAIL def test_MatAdd_postprocessor_xfail(): # This is difficult to get working because of the way that Add processes # its args. z = zeros(2) assert Add(z, S.NaN) == Add(S.NaN, z) def test_MatAdd_postprocessor(): # Some of these are nonsensical, but we do not raise errors for Add # because that breaks algorithms that want to replace matrices with dummy # symbols. z = zeros(2) assert Add(0, z) == Add(z, 0) == z a = Add(S.Infinity, z) assert a == Add(z, S.Infinity) assert isinstance(a, Add) assert a.args == (S.Infinity, z) a = Add(S.ComplexInfinity, z) assert a == Add(z, S.ComplexInfinity) assert isinstance(a, Add) assert a.args == (S.ComplexInfinity, z) a = Add(z, S.NaN) # assert a == Add(S.NaN, z) # See the XFAIL above assert isinstance(a, Add) assert a.args == (S.NaN, z) M = Matrix([[1, 2], [3, 4]]) a = Add(x, M) assert a == Add(M, x) assert isinstance(a, Add) assert a.args == (x, M) A = MatrixSymbol("A", 2, 2) assert Add(A, M) == Add(M, A) == A + M # Scalars should be absorbed into constant matrices (producing an error) a = Add(x, M, A) assert a == Add(M, x, A) == Add(M, A, x) == Add(x, A, M) == Add(A, x, M) == Add(A, M, x) assert isinstance(a, Add) assert a.args == (x, A + M) assert Add(M, M) == 2*M assert Add(M, A, M) == Add(M, M, A) == Add(A, M, M) == A + 2*M a = Add(A, x, M, M, x) assert isinstance(a, Add) assert a.args == (2*x, A + 2*M) def test_simplify_matrix_expressions(): # Various simplification functions assert type(gcd_terms(C*D + D*C)) == MatAdd a = gcd_terms(2*C*D + 4*D*C) assert type(a) == MatAdd assert a.args == (2*C*D, 4*D*C) def test_exp(): A = MatrixSymbol('A', 2, 2) B = MatrixSymbol('B', 2, 2) expr1 = exp(A)*exp(B) expr2 = exp(B)*exp(A) assert expr1 != expr2 assert expr1 - expr2 != 0 assert not isinstance(expr1, exp) assert not isinstance(expr2, exp) def test_invalid_args(): raises(SympifyError, lambda: MatrixSymbol(1, 2, 'A')) def test_matrixsymbol_from_symbol(): # The label should be preserved during doit and subs A_label = Symbol('A', complex=True) A = MatrixSymbol(A_label, 2, 2) A_1 = A.doit() A_2 = A.subs(2, 3) assert A_1.args == A.args assert A_2.args[0] == A.args[0] def test_as_explicit(): Z = MatrixSymbol('Z', 2, 3) assert Z.as_explicit() == ImmutableMatrix([ [Z[0, 0], Z[0, 1], Z[0, 2]], [Z[1, 0], Z[1, 1], Z[1, 2]], ]) raises(ValueError, lambda: A.as_explicit()) def test_MatrixSet(): M = MatrixSet(2, 2, set=S.Reals) assert M.shape == (2, 2) assert M.set == S.Reals X = Matrix([[1, 2], [3, 4]]) assert X in M X = ZeroMatrix(2, 2) assert X in M raises(TypeError, lambda: A in M) raises(TypeError, lambda: 1 in M) M = MatrixSet(n, m, set=S.Reals) assert A in M raises(TypeError, lambda: C in M) raises(TypeError, lambda: X in M) M = MatrixSet(2, 2, set={1, 2, 3}) X = Matrix([[1, 2], [3, 4]]) Y = Matrix([[1, 2]]) assert (X in M) == S.false assert (Y in M) == S.false raises(ValueError, lambda: MatrixSet(2, -2, S.Reals)) raises(ValueError, lambda: MatrixSet(2.4, -1, S.Reals)) raises(TypeError, lambda: MatrixSet(2, 2, (1, 2, 3))) def test_matrixsymbol_solving(): A = MatrixSymbol('A', 2, 2) B = MatrixSymbol('B', 2, 2) Z = ZeroMatrix(2, 2) assert -(-A + B) - A + B == Z assert (-(-A + B) - A + B).simplify() == Z assert (-(-A + B) - A + B).expand() == Z assert (-(-A + B) - A + B - Z).simplify() == Z assert (-(-A + B) - A + B - Z).expand() == Z sympy-sympy-1.9/sympy/matrices/expressions/tests/test_matmul.py000066400000000000000000000121341412543434000253500ustar00rootroot00000000000000from sympy.core import I, symbols, Basic, Mul, S from sympy.core.mul import mul from sympy.functions import adjoint, transpose from sympy.matrices import (Identity, Inverse, Matrix, MatrixSymbol, ZeroMatrix, eye, ImmutableMatrix) from sympy.matrices.expressions import Adjoint, Transpose, det, MatPow from sympy.matrices.expressions.special import GenericIdentity from sympy.matrices.expressions.matmul import (factor_in_front, remove_ids, MatMul, combine_powers, any_zeros, unpack, only_squares) from sympy.strategies import null_safe from sympy import refine, Q, Symbol from sympy.testing.pytest import XFAIL n, m, l, k = symbols('n m l k', integer=True) x = symbols('x') A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) D = MatrixSymbol('D', n, n) E = MatrixSymbol('E', m, n) def test_evaluate(): assert MatMul(C, C, evaluate=True) == MatMul(C, C).doit() def test_adjoint(): assert adjoint(A*B) == Adjoint(B)*Adjoint(A) assert adjoint(2*A*B) == 2*Adjoint(B)*Adjoint(A) assert adjoint(2*I*C) == -2*I*Adjoint(C) M = Matrix(2, 2, [1, 2 + I, 3, 4]) MA = Matrix(2, 2, [1, 3, 2 - I, 4]) assert adjoint(M) == MA assert adjoint(2*M) == 2*MA assert adjoint(MatMul(2, M)) == MatMul(2, MA).doit() def test_transpose(): assert transpose(A*B) == Transpose(B)*Transpose(A) assert transpose(2*A*B) == 2*Transpose(B)*Transpose(A) assert transpose(2*I*C) == 2*I*Transpose(C) M = Matrix(2, 2, [1, 2 + I, 3, 4]) MT = Matrix(2, 2, [1, 3, 2 + I, 4]) assert transpose(M) == MT assert transpose(2*M) == 2*MT assert transpose(x*M) == x*MT assert transpose(MatMul(2, M)) == MatMul(2, MT).doit() def test_factor_in_front(): assert factor_in_front(MatMul(A, 2, B, evaluate=False)) ==\ MatMul(2, A, B, evaluate=False) def test_remove_ids(): assert remove_ids(MatMul(A, Identity(m), B, evaluate=False)) == \ MatMul(A, B, evaluate=False) assert null_safe(remove_ids)(MatMul(Identity(n), evaluate=False)) == \ MatMul(Identity(n), evaluate=False) def test_combine_powers(): assert combine_powers(MatMul(D, Inverse(D), D, evaluate=False)) == \ MatMul(Identity(n), D, evaluate=False) def test_any_zeros(): assert any_zeros(MatMul(A, ZeroMatrix(m, k), evaluate=False)) == \ ZeroMatrix(n, k) def test_unpack(): assert unpack(MatMul(A, evaluate=False)) == A x = MatMul(A, B) assert unpack(x) == x def test_only_squares(): assert only_squares(C) == [C] assert only_squares(C, D) == [C, D] assert only_squares(C, A, A.T, D) == [C, A*A.T, D] def test_determinant(): assert det(2*C) == 2**n*det(C) assert det(2*C*D) == 2**n*det(C)*det(D) assert det(3*C*A*A.T*D) == 3**n*det(C)*det(A*A.T)*det(D) def test_doit(): assert MatMul(C, 2, D).args == (C, 2, D) assert MatMul(C, 2, D).doit().args == (2, C, D) assert MatMul(C, Transpose(D*C)).args == (C, Transpose(D*C)) assert MatMul(C, Transpose(D*C)).doit(deep=True).args == (C, C.T, D.T) def test_doit_drills_down(): X = ImmutableMatrix([[1, 2], [3, 4]]) Y = ImmutableMatrix([[2, 3], [4, 5]]) assert MatMul(X, MatPow(Y, 2)).doit() == X*Y**2 assert MatMul(C, Transpose(D*C)).doit().args == (C, C.T, D.T) def test_doit_deep_false_still_canonical(): assert (MatMul(C, Transpose(D*C), 2).doit(deep=False).args == (2, C, Transpose(D*C))) def test_matmul_scalar_Matrix_doit(): # Issue 9053 X = Matrix([[1, 2], [3, 4]]) assert MatMul(2, X).doit() == 2*X def test_matmul_sympify(): assert isinstance(MatMul(eye(1), eye(1)).args[0], Basic) def test_collapse_MatrixBase(): A = Matrix([[1, 1], [1, 1]]) B = Matrix([[1, 2], [3, 4]]) assert MatMul(A, B).doit() == ImmutableMatrix([[4, 6], [4, 6]]) def test_refine(): assert refine(C*C.T*D, Q.orthogonal(C)).doit() == D kC = k*C assert refine(kC*C.T, Q.orthogonal(C)).doit() == k*Identity(n) assert refine(kC* kC.T, Q.orthogonal(C)).doit() == (k**2)*Identity(n) def test_matmul_no_matrices(): assert MatMul(1) == 1 assert MatMul(n, m) == n*m assert not isinstance(MatMul(n, m), MatMul) def test_matmul_args_cnc(): assert MatMul(n, A, A.T).args_cnc() == [[n], [A, A.T]] assert MatMul(A, A.T).args_cnc() == [[], [A, A.T]] @XFAIL def test_matmul_args_cnc_symbols(): # Not currently supported a, b = symbols('a b', commutative=False) assert MatMul(n, a, b, A, A.T).args_cnc() == [[n], [a, b, A, A.T]] assert MatMul(n, a, A, b, A.T).args_cnc() == [[n], [a, A, b, A.T]] def test_issue_12950(): M = Matrix([[Symbol("x")]]) * MatrixSymbol("A", 1, 1) assert MatrixSymbol("A", 1, 1).as_explicit()[0]*Symbol('x') == M.as_explicit()[0] def test_construction_with_Mul(): assert Mul(C, D) == MatMul(C, D) assert Mul(D, C) == MatMul(D, C) def test_construction_with_mul(): assert mul(C, D) == MatMul(C, D) assert mul(D, C) == MatMul(D, C) assert mul(C, D) != MatMul(D, C) def test_generic_identity(): assert MatMul.identity == GenericIdentity() assert MatMul.identity != S.One sympy-sympy-1.9/sympy/matrices/expressions/tests/test_matpow.py000066400000000000000000000141411412543434000253600ustar00rootroot00000000000000from sympy.simplify.powsimp import powsimp from sympy.testing.pytest import raises from sympy.core.expr import unchanged from sympy.core import symbols, S from sympy.matrices import Identity, MatrixSymbol, ImmutableMatrix, ZeroMatrix, OneMatrix from sympy.matrices.common import NonSquareMatrixError from sympy.matrices.expressions import MatPow, MatAdd, MatMul from sympy.matrices.expressions.inverse import Inverse from sympy.matrices.expressions.matexpr import MatrixElement n, m, l, k = symbols('n m l k', integer=True) A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) D = MatrixSymbol('D', n, n) E = MatrixSymbol('E', m, n) def test_entry_matrix(): X = ImmutableMatrix([[1, 2], [3, 4]]) assert MatPow(X, 0)[0, 0] == 1 assert MatPow(X, 0)[0, 1] == 0 assert MatPow(X, 1)[0, 0] == 1 assert MatPow(X, 1)[0, 1] == 2 assert MatPow(X, 2)[0, 0] == 7 def test_entry_symbol(): from sympy.concrete import Sum assert MatPow(C, 0)[0, 0] == 1 assert MatPow(C, 0)[0, 1] == 0 assert MatPow(C, 1)[0, 0] == C[0, 0] assert isinstance(MatPow(C, 2)[0, 0], Sum) assert isinstance(MatPow(C, n)[0, 0], MatrixElement) def test_as_explicit_symbol(): X = MatrixSymbol('X', 2, 2) assert MatPow(X, 0).as_explicit() == ImmutableMatrix(Identity(2)) assert MatPow(X, 1).as_explicit() == X.as_explicit() assert MatPow(X, 2).as_explicit() == (X.as_explicit())**2 assert MatPow(X, n).as_explicit() == ImmutableMatrix([ [(X ** n)[0, 0], (X ** n)[0, 1]], [(X ** n)[1, 0], (X ** n)[1, 1]], ]) def test_as_explicit_matrix(): A = ImmutableMatrix([[1, 2], [3, 4]]) assert MatPow(A, 0).as_explicit() == ImmutableMatrix(Identity(2)) assert MatPow(A, 1).as_explicit() == A assert MatPow(A, 2).as_explicit() == A**2 assert MatPow(A, -1).as_explicit() == A.inv() assert MatPow(A, -2).as_explicit() == (A.inv())**2 # less expensive than testing on a 2x2 A = ImmutableMatrix([4]) assert MatPow(A, S.Half).as_explicit() == A**S.Half def test_doit_symbol(): assert MatPow(C, 0).doit() == Identity(n) assert MatPow(C, 1).doit() == C assert MatPow(C, -1).doit() == C.I for r in [2, S.Half, S.Pi, n]: assert MatPow(C, r).doit() == MatPow(C, r) def test_doit_matrix(): X = ImmutableMatrix([[1, 2], [3, 4]]) assert MatPow(X, 0).doit() == ImmutableMatrix(Identity(2)) assert MatPow(X, 1).doit() == X assert MatPow(X, 2).doit() == X**2 assert MatPow(X, -1).doit() == X.inv() assert MatPow(X, -2).doit() == (X.inv())**2 # less expensive than testing on a 2x2 assert MatPow(ImmutableMatrix([4]), S.Half).doit() == ImmutableMatrix([2]) X = ImmutableMatrix([[0, 2], [0, 4]]) # det() == 0 raises(ValueError, lambda: MatPow(X,-1).doit()) raises(ValueError, lambda: MatPow(X,-2).doit()) def test_nonsquare(): A = MatrixSymbol('A', 2, 3) B = ImmutableMatrix([[1, 2, 3], [4, 5, 6]]) for r in [-1, 0, 1, 2, S.Half, S.Pi, n]: raises(NonSquareMatrixError, lambda: MatPow(A, r)) raises(NonSquareMatrixError, lambda: MatPow(B, r)) def test_doit_equals_pow(): #17179 X = ImmutableMatrix ([[1,0],[0,1]]) assert MatPow(X, n).doit() == X**n == X def test_doit_nested_MatrixExpr(): X = ImmutableMatrix([[1, 2], [3, 4]]) Y = ImmutableMatrix([[2, 3], [4, 5]]) assert MatPow(MatMul(X, Y), 2).doit() == (X*Y)**2 assert MatPow(MatAdd(X, Y), 2).doit() == (X + Y)**2 def test_identity_power(): k = Identity(n) assert MatPow(k, 4).doit() == k assert MatPow(k, n).doit() == k assert MatPow(k, -3).doit() == k assert MatPow(k, 0).doit() == k l = Identity(3) assert MatPow(l, n).doit() == l assert MatPow(l, -1).doit() == l assert MatPow(l, 0).doit() == l def test_zero_power(): z1 = ZeroMatrix(n, n) assert MatPow(z1, 3).doit() == z1 raises(ValueError, lambda:MatPow(z1, -1).doit()) assert MatPow(z1, 0).doit() == Identity(n) assert MatPow(z1, n).doit() == z1 raises(ValueError, lambda:MatPow(z1, -2).doit()) z2 = ZeroMatrix(4, 4) assert MatPow(z2, n).doit() == z2 raises(ValueError, lambda:MatPow(z2, -3).doit()) assert MatPow(z2, 2).doit() == z2 assert MatPow(z2, 0).doit() == Identity(4) raises(ValueError, lambda:MatPow(z2, -1).doit()) def test_OneMatrix_power(): o = OneMatrix(3, 3) assert o ** 0 == Identity(3) assert o ** 1 == o assert o * o == o ** 2 == 3 * o assert o * o * o == o ** 3 == 9 * o o = OneMatrix(n, n) assert o * o == o ** 2 == n * o # powsimp necessary as n ** (n - 2) * n does not produce n ** (n - 1) assert powsimp(o ** (n - 1) * o) == o ** n == n ** (n - 1) * o def test_transpose_power(): from sympy.matrices.expressions.transpose import Transpose as TP assert (C*D).T**5 == ((C*D)**5).T == (D.T * C.T)**5 assert ((C*D).T**5).T == (C*D)**5 assert (C.T.I.T)**7 == C**-7 assert (C.T**l).T**k == C**(l*k) assert ((E.T * A.T)**5).T == (A*E)**5 assert ((A*E).T**5).T**7 == (A*E)**35 assert TP(TP(C**2 * D**3)**5).doit() == (C**2 * D**3)**5 assert ((D*C)**-5).T**-5 == ((D*C)**25).T assert (((D*C)**l).T**k).T == (D*C)**(l*k) def test_Inverse(): assert Inverse(MatPow(C, 0)).doit() == Identity(n) assert Inverse(MatPow(C, 1)).doit() == Inverse(C) assert Inverse(MatPow(C, 2)).doit() == MatPow(C, -2) assert Inverse(MatPow(C, -1)).doit() == C assert MatPow(Inverse(C), 0).doit() == Identity(n) assert MatPow(Inverse(C), 1).doit() == Inverse(C) assert MatPow(Inverse(C), 2).doit() == MatPow(C, -2) assert MatPow(Inverse(C), -1).doit() == C def test_combine_powers(): assert (C ** 1) ** 1 == C assert (C ** 2) ** 3 == MatPow(C, 6) assert (C ** -2) ** -3 == MatPow(C, 6) assert (C ** -1) ** -1 == C assert (((C ** 2) ** 3) ** 4) ** 5 == MatPow(C, 120) assert (C ** n) ** n == C ** (n ** 2) def test_unchanged(): assert unchanged(MatPow, C, 0) assert unchanged(MatPow, C, 1) assert unchanged(MatPow, Inverse(C), -1) assert unchanged(Inverse, MatPow(C, -1), -1) assert unchanged(MatPow, MatPow(C, -1), -1) assert unchanged(MatPow, MatPow(C, 1), 1) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_permutation.py000066400000000000000000000127331412543434000264250ustar00rootroot00000000000000from sympy.combinatorics import Permutation from sympy.core.expr import unchanged from sympy.matrices import Matrix from sympy.matrices.expressions import \ MatMul, BlockDiagMatrix, Determinant, Inverse from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.matrices.expressions.special import ZeroMatrix, OneMatrix, Identity from sympy.matrices.expressions.permutation import \ MatrixPermute, PermutationMatrix from sympy.testing.pytest import raises from sympy import Symbol def test_PermutationMatrix_basic(): p = Permutation([1, 0]) assert unchanged(PermutationMatrix, p) raises(ValueError, lambda: PermutationMatrix((0, 1, 2))) assert PermutationMatrix(p).as_explicit() == Matrix([[0, 1], [1, 0]]) assert isinstance(PermutationMatrix(p)*MatrixSymbol('A', 2, 2), MatMul) def test_PermutationMatrix_matmul(): p = Permutation([1, 2, 0]) P = PermutationMatrix(p) M = Matrix([[0, 1, 2], [3, 4, 5], [6, 7, 8]]) assert (P*M).as_explicit() == P.as_explicit()*M assert (M*P).as_explicit() == M*P.as_explicit() P1 = PermutationMatrix(Permutation([1, 2, 0])) P2 = PermutationMatrix(Permutation([2, 1, 0])) P3 = PermutationMatrix(Permutation([1, 0, 2])) assert P1*P2 == P3 def test_PermutationMatrix_matpow(): p1 = Permutation([1, 2, 0]) P1 = PermutationMatrix(p1) p2 = Permutation([2, 0, 1]) P2 = PermutationMatrix(p2) assert P1**2 == P2 assert P1**3 == Identity(3) def test_PermutationMatrix_identity(): p = Permutation([0, 1]) assert PermutationMatrix(p).is_Identity p = Permutation([1, 0]) assert not PermutationMatrix(p).is_Identity def test_PermutationMatrix_determinant(): P = PermutationMatrix(Permutation([0, 1, 2])) assert Determinant(P).doit() == 1 P = PermutationMatrix(Permutation([0, 2, 1])) assert Determinant(P).doit() == -1 P = PermutationMatrix(Permutation([2, 0, 1])) assert Determinant(P).doit() == 1 def test_PermutationMatrix_inverse(): P = PermutationMatrix(Permutation(0, 1, 2)) assert Inverse(P).doit() == PermutationMatrix(Permutation(0, 2, 1)) def test_PermutationMatrix_rewrite_BlockDiagMatrix(): P = PermutationMatrix(Permutation([0, 1, 2, 3, 4, 5])) P0 = PermutationMatrix(Permutation([0])) assert P.rewrite(BlockDiagMatrix) == \ BlockDiagMatrix(P0, P0, P0, P0, P0, P0) P = PermutationMatrix(Permutation([0, 1, 3, 2, 4, 5])) P10 = PermutationMatrix(Permutation(0, 1)) assert P.rewrite(BlockDiagMatrix) == \ BlockDiagMatrix(P0, P0, P10, P0, P0) P = PermutationMatrix(Permutation([1, 0, 3, 2, 5, 4])) assert P.rewrite(BlockDiagMatrix) == \ BlockDiagMatrix(P10, P10, P10) P = PermutationMatrix(Permutation([0, 4, 3, 2, 1, 5])) P3210 = PermutationMatrix(Permutation([3, 2, 1, 0])) assert P.rewrite(BlockDiagMatrix) == \ BlockDiagMatrix(P0, P3210, P0) P = PermutationMatrix(Permutation([0, 4, 2, 3, 1, 5])) P3120 = PermutationMatrix(Permutation([3, 1, 2, 0])) assert P.rewrite(BlockDiagMatrix) == \ BlockDiagMatrix(P0, P3120, P0) P = PermutationMatrix(Permutation(0, 3)(1, 4)(2, 5)) assert P.rewrite(BlockDiagMatrix) == BlockDiagMatrix(P) def test_MartrixPermute_basic(): p = Permutation(0, 1) P = PermutationMatrix(p) A = MatrixSymbol('A', 2, 2) raises(ValueError, lambda: MatrixPermute(Symbol('x'), p)) raises(ValueError, lambda: MatrixPermute(A, Symbol('x'))) assert MatrixPermute(A, P) == MatrixPermute(A, p) raises(ValueError, lambda: MatrixPermute(A, p, 2)) pp = Permutation(0, 1, size=3) assert MatrixPermute(A, pp) == MatrixPermute(A, p) pp = Permutation(0, 1, 2) raises(ValueError, lambda: MatrixPermute(A, pp)) def test_MatrixPermute_shape(): p = Permutation(0, 1) A = MatrixSymbol('A', 2, 3) assert MatrixPermute(A, p).shape == (2, 3) def test_MatrixPermute_explicit(): p = Permutation(0, 1, 2) A = MatrixSymbol('A', 3, 3) AA = A.as_explicit() assert MatrixPermute(A, p, 0).as_explicit() == \ AA.permute(p, orientation='rows') assert MatrixPermute(A, p, 1).as_explicit() == \ AA.permute(p, orientation='cols') def test_MatrixPermute_rewrite_MatMul(): p = Permutation(0, 1, 2) A = MatrixSymbol('A', 3, 3) assert MatrixPermute(A, p, 0).rewrite(MatMul).as_explicit() == \ MatrixPermute(A, p, 0).as_explicit() assert MatrixPermute(A, p, 1).rewrite(MatMul).as_explicit() == \ MatrixPermute(A, p, 1).as_explicit() def test_MatrixPermute_doit(): p = Permutation(0, 1, 2) A = MatrixSymbol('A', 3, 3) assert MatrixPermute(A, p).doit() == MatrixPermute(A, p) p = Permutation(0, size=3) A = MatrixSymbol('A', 3, 3) assert MatrixPermute(A, p).doit().as_explicit() == \ MatrixPermute(A, p).as_explicit() p = Permutation(0, 1, 2) A = Identity(3) assert MatrixPermute(A, p, 0).doit().as_explicit() == \ MatrixPermute(A, p, 0).as_explicit() assert MatrixPermute(A, p, 1).doit().as_explicit() == \ MatrixPermute(A, p, 1).as_explicit() A = ZeroMatrix(3, 3) assert MatrixPermute(A, p).doit() == A A = OneMatrix(3, 3) assert MatrixPermute(A, p).doit() == A A = MatrixSymbol('A', 4, 4) p1 = Permutation(0, 1, 2, 3) p2 = Permutation(0, 2, 3, 1) expr = MatrixPermute(MatrixPermute(A, p1, 0), p2, 0) assert expr.as_explicit() == expr.doit().as_explicit() expr = MatrixPermute(MatrixPermute(A, p1, 1), p2, 1) assert expr.as_explicit() == expr.doit().as_explicit() sympy-sympy-1.9/sympy/matrices/expressions/tests/test_sets.py000066400000000000000000000022321412543434000250250ustar00rootroot00000000000000from sympy.core.singleton import S from sympy.core.symbol import symbols from sympy.matrices import Matrix from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.matrices.expressions.sets import MatrixSet from sympy.matrices.expressions.special import ZeroMatrix from sympy.testing.pytest import raises def test_MatrixSet(): n, m = symbols('n m', integer=True) A = MatrixSymbol('A', n, m) C = MatrixSymbol('C', n, n) M = MatrixSet(2, 2, set=S.Reals) assert M.shape == (2, 2) assert M.set == S.Reals X = Matrix([[1, 2], [3, 4]]) assert X in M X = ZeroMatrix(2, 2) assert X in M raises(TypeError, lambda: A in M) raises(TypeError, lambda: 1 in M) M = MatrixSet(n, m, set=S.Reals) assert A in M raises(TypeError, lambda: C in M) raises(TypeError, lambda: X in M) M = MatrixSet(2, 2, set={1, 2, 3}) X = Matrix([[1, 2], [3, 4]]) Y = Matrix([[1, 2]]) assert (X in M) == S.false assert (Y in M) == S.false raises(ValueError, lambda: MatrixSet(2, -2, S.Reals)) raises(ValueError, lambda: MatrixSet(2.4, -1, S.Reals)) raises(TypeError, lambda: MatrixSet(2, 2, (1, 2, 3))) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_slice.py000066400000000000000000000037531412543434000251570ustar00rootroot00000000000000from sympy.matrices.expressions.slice import MatrixSlice from sympy.matrices.expressions import MatrixSymbol from sympy.abc import a, b, c, d, k, l, m, n from sympy.testing.pytest import raises, XFAIL from sympy.functions.elementary.integers import floor from sympy.assumptions import assuming, Q X = MatrixSymbol('X', n, m) Y = MatrixSymbol('Y', m, k) def test_shape(): B = MatrixSlice(X, (a, b), (c, d)) assert B.shape == (b - a, d - c) def test_entry(): B = MatrixSlice(X, (a, b), (c, d)) assert B[0,0] == X[a, c] assert B[k,l] == X[a+k, c+l] raises(IndexError, lambda : MatrixSlice(X, 1, (2, 5))[1, 0]) assert X[1::2, :][1, 3] == X[1+2, 3] assert X[:, 1::2][3, 1] == X[3, 1+2] def test_on_diag(): assert not MatrixSlice(X, (a, b), (c, d)).on_diag assert MatrixSlice(X, (a, b), (a, b)).on_diag def test_inputs(): assert MatrixSlice(X, 1, (2, 5)) == MatrixSlice(X, (1, 2), (2, 5)) assert MatrixSlice(X, 1, (2, 5)).shape == (1, 3) def test_slicing(): assert X[1:5, 2:4] == MatrixSlice(X, (1, 5), (2, 4)) assert X[1, 2:4] == MatrixSlice(X, 1, (2, 4)) assert X[1:5, :].shape == (4, X.shape[1]) assert X[:, 1:5].shape == (X.shape[0], 4) assert X[::2, ::2].shape == (floor(n/2), floor(m/2)) assert X[2, :] == MatrixSlice(X, 2, (0, m)) assert X[k, :] == MatrixSlice(X, k, (0, m)) def test_exceptions(): X = MatrixSymbol('x', 10, 20) raises(IndexError, lambda: X[0:12, 2]) raises(IndexError, lambda: X[0:9, 22]) raises(IndexError, lambda: X[-1:5, 2]) @XFAIL def test_symmetry(): X = MatrixSymbol('x', 10, 10) Y = X[:5, 5:] with assuming(Q.symmetric(X)): assert Y.T == X[5:, :5] def test_slice_of_slice(): X = MatrixSymbol('x', 10, 10) assert X[2, :][:, 3][0, 0] == X[2, 3] assert X[:5, :5][:4, :4] == X[:4, :4] assert X[1:5, 2:6][1:3, 2] == X[2:4, 4] assert X[1:9:2, 2:6][1:3, 2] == X[3:7:2, 4] def test_negative_index(): X = MatrixSymbol('x', 10, 10) assert X[-1, :] == X[9, :] sympy-sympy-1.9/sympy/matrices/expressions/tests/test_special.py000066400000000000000000000147361412543434000255030ustar00rootroot00000000000000from sympy.core.add import Add from sympy.core.expr import unchanged from sympy.core.mul import Mul from sympy.core.symbol import symbols from sympy.core.relational import Eq from sympy.concrete.summations import Sum from sympy.functions.elementary.piecewise import Piecewise from sympy.matrices.common import NonSquareMatrixError, ShapeError from sympy.matrices.immutable import ImmutableDenseMatrix from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.matrices.expressions.matadd import MatAdd from sympy.matrices.expressions.special import ( ZeroMatrix, GenericZeroMatrix, Identity, GenericIdentity, OneMatrix) from sympy.matrices.expressions.matmul import MatMul from sympy.testing.pytest import raises def test_zero_matrix_creation(): assert unchanged(ZeroMatrix, 2, 2) assert unchanged(ZeroMatrix, 0, 0) raises(ValueError, lambda: ZeroMatrix(-1, 2)) raises(ValueError, lambda: ZeroMatrix(2.0, 2)) raises(ValueError, lambda: ZeroMatrix(2j, 2)) raises(ValueError, lambda: ZeroMatrix(2, -1)) raises(ValueError, lambda: ZeroMatrix(2, 2.0)) raises(ValueError, lambda: ZeroMatrix(2, 2j)) n = symbols('n') assert unchanged(ZeroMatrix, n, n) n = symbols('n', integer=False) raises(ValueError, lambda: ZeroMatrix(n, n)) n = symbols('n', negative=True) raises(ValueError, lambda: ZeroMatrix(n, n)) def test_generic_zero_matrix(): z = GenericZeroMatrix() n = symbols('n', integer=True) A = MatrixSymbol("A", n, n) assert z == z assert z != A assert A != z assert z.is_ZeroMatrix raises(TypeError, lambda: z.shape) raises(TypeError, lambda: z.rows) raises(TypeError, lambda: z.cols) assert MatAdd() == z assert MatAdd(z, A) == MatAdd(A) # Make sure it is hashable hash(z) def test_identity_matrix_creation(): assert Identity(2) assert Identity(0) raises(ValueError, lambda: Identity(-1)) raises(ValueError, lambda: Identity(2.0)) raises(ValueError, lambda: Identity(2j)) n = symbols('n') assert Identity(n) n = symbols('n', integer=False) raises(ValueError, lambda: Identity(n)) n = symbols('n', negative=True) raises(ValueError, lambda: Identity(n)) def test_generic_identity(): I = GenericIdentity() n = symbols('n', integer=True) A = MatrixSymbol("A", n, n) assert I == I assert I != A assert A != I assert I.is_Identity assert I**-1 == I raises(TypeError, lambda: I.shape) raises(TypeError, lambda: I.rows) raises(TypeError, lambda: I.cols) assert MatMul() == I assert MatMul(I, A) == MatMul(A) # Make sure it is hashable hash(I) def test_one_matrix_creation(): assert OneMatrix(2, 2) assert OneMatrix(0, 0) assert Eq(OneMatrix(1, 1), Identity(1)) raises(ValueError, lambda: OneMatrix(-1, 2)) raises(ValueError, lambda: OneMatrix(2.0, 2)) raises(ValueError, lambda: OneMatrix(2j, 2)) raises(ValueError, lambda: OneMatrix(2, -1)) raises(ValueError, lambda: OneMatrix(2, 2.0)) raises(ValueError, lambda: OneMatrix(2, 2j)) n = symbols('n') assert OneMatrix(n, n) n = symbols('n', integer=False) raises(ValueError, lambda: OneMatrix(n, n)) n = symbols('n', negative=True) raises(ValueError, lambda: OneMatrix(n, n)) def test_ZeroMatrix(): n, m = symbols('n m', integer=True) A = MatrixSymbol('A', n, m) Z = ZeroMatrix(n, m) assert A + Z == A assert A*Z.T == ZeroMatrix(n, n) assert Z*A.T == ZeroMatrix(n, n) assert A - A == ZeroMatrix(*A.shape) assert Z assert Z.transpose() == ZeroMatrix(m, n) assert Z.conjugate() == Z assert ZeroMatrix(n, n)**0 == Identity(n) with raises(NonSquareMatrixError): Z**0 with raises(NonSquareMatrixError): Z**1 with raises(NonSquareMatrixError): Z**2 assert ZeroMatrix(3, 3).as_explicit() == ImmutableDenseMatrix.zeros(3, 3) def test_ZeroMatrix_doit(): n = symbols('n', integer=True) Znn = ZeroMatrix(Add(n, n, evaluate=False), n) assert isinstance(Znn.rows, Add) assert Znn.doit() == ZeroMatrix(2*n, n) assert isinstance(Znn.doit().rows, Mul) def test_OneMatrix(): n, m = symbols('n m', integer=True) A = MatrixSymbol('A', n, m) a = MatrixSymbol('a', n, 1) U = OneMatrix(n, m) assert U.shape == (n, m) assert isinstance(A + U, Add) assert U.transpose() == OneMatrix(m, n) assert U.conjugate() == U assert OneMatrix(n, n) ** 0 == Identity(n) with raises(NonSquareMatrixError): U ** 0 with raises(NonSquareMatrixError): U ** 1 with raises(NonSquareMatrixError): U ** 2 with raises(ShapeError): a + U U = OneMatrix(n, n) assert U[1, 2] == 1 U = OneMatrix(2, 3) assert U.as_explicit() == ImmutableDenseMatrix.ones(2, 3) def test_OneMatrix_doit(): n = symbols('n', integer=True) Unn = OneMatrix(Add(n, n, evaluate=False), n) assert isinstance(Unn.rows, Add) assert Unn.doit() == OneMatrix(2 * n, n) assert isinstance(Unn.doit().rows, Mul) def test_OneMatrix_mul(): n, m, k = symbols('n m k', integer=True) w = MatrixSymbol('w', n, 1) assert OneMatrix(n, m) * OneMatrix(m, k) == OneMatrix(n, k) * m assert w * OneMatrix(1, 1) == w assert OneMatrix(1, 1) * w.T == w.T def test_Identity(): n, m = symbols('n m', integer=True) A = MatrixSymbol('A', n, m) i, j = symbols('i j') In = Identity(n) Im = Identity(m) assert A*Im == A assert In*A == A assert In.transpose() == In assert In.inverse() == In assert In.conjugate() == In assert In[i, j] != 0 assert Sum(In[i, j], (i, 0, n-1), (j, 0, n-1)).subs(n,3).doit() == 3 assert Sum(Sum(In[i, j], (i, 0, n-1)), (j, 0, n-1)).subs(n,3).doit() == 3 # If range exceeds the limit `(0, n-1)`, do not remove `Piecewise`: expr = Sum(In[i, j], (i, 0, n-1)) assert expr.doit() == 1 expr = Sum(In[i, j], (i, 0, n-2)) assert expr.doit().dummy_eq( Piecewise( (1, (j >= 0) & (j <= n-2)), (0, True) ) ) expr = Sum(In[i, j], (i, 1, n-1)) assert expr.doit().dummy_eq( Piecewise( (1, (j >= 1) & (j <= n-1)), (0, True) ) ) assert Identity(3).as_explicit() == ImmutableDenseMatrix.eye(3) def test_Identity_doit(): n = symbols('n', integer=True) Inn = Identity(Add(n, n, evaluate=False)) assert isinstance(Inn.rows, Add) assert Inn.doit() == Identity(2*n) assert isinstance(Inn.doit().rows, Mul) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_trace.py000066400000000000000000000057661412543434000251640ustar00rootroot00000000000000from sympy.core import Lambda, S, symbols from sympy.concrete import Sum from sympy.functions import adjoint, conjugate, transpose from sympy.matrices import eye, Matrix, ShapeError, ImmutableMatrix from sympy.matrices.expressions import ( Adjoint, Identity, FunctionMatrix, MatrixExpr, MatrixSymbol, Trace, ZeroMatrix, trace, MatPow, MatAdd, MatMul ) from sympy.matrices.expressions.special import OneMatrix from sympy.testing.pytest import raises n = symbols('n', integer=True) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) C = MatrixSymbol('C', 3, 4) def test_Trace(): assert isinstance(Trace(A), Trace) assert not isinstance(Trace(A), MatrixExpr) raises(ShapeError, lambda: Trace(C)) assert trace(eye(3)) == 3 assert trace(Matrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9])) == 15 assert adjoint(Trace(A)) == trace(Adjoint(A)) assert conjugate(Trace(A)) == trace(Adjoint(A)) assert transpose(Trace(A)) == Trace(A) A / Trace(A) # Make sure this is possible # Some easy simplifications assert trace(Identity(5)) == 5 assert trace(ZeroMatrix(5, 5)) == 0 assert trace(OneMatrix(1, 1)) == 1 assert trace(OneMatrix(2, 2)) == 2 assert trace(OneMatrix(n, n)) == n assert trace(2*A*B) == 2*Trace(A*B) assert trace(A.T) == trace(A) i, j = symbols('i j') F = FunctionMatrix(3, 3, Lambda((i, j), i + j)) assert trace(F) == (0 + 0) + (1 + 1) + (2 + 2) raises(TypeError, lambda: Trace(S.One)) assert Trace(A).arg is A assert str(trace(A)) == str(Trace(A).doit()) assert Trace(A).is_commutative is True def test_Trace_A_plus_B(): assert trace(A + B) == Trace(A) + Trace(B) assert Trace(A + B).arg == MatAdd(A, B) assert Trace(A + B).doit() == Trace(A) + Trace(B) def test_Trace_MatAdd_doit(): # See issue #9028 X = ImmutableMatrix([[1, 2, 3]]*3) Y = MatrixSymbol('Y', 3, 3) q = MatAdd(X, 2*X, Y, -3*Y) assert Trace(q).arg == q assert Trace(q).doit() == 18 - 2*Trace(Y) def test_Trace_MatPow_doit(): X = Matrix([[1, 2], [3, 4]]) assert Trace(X).doit() == 5 q = MatPow(X, 2) assert Trace(q).arg == q assert Trace(q).doit() == 29 def test_Trace_MutableMatrix_plus(): # See issue #9043 X = Matrix([[1, 2], [3, 4]]) assert Trace(X) + Trace(X) == 2*Trace(X) def test_Trace_doit_deep_False(): X = Matrix([[1, 2], [3, 4]]) q = MatPow(X, 2) assert Trace(q).doit(deep=False).arg == q q = MatAdd(X, 2*X) assert Trace(q).doit(deep=False).arg == q q = MatMul(X, 2*X) assert Trace(q).doit(deep=False).arg == q def test_trace_constant_factor(): # Issue 9052: gave 2*Trace(MatMul(A)) instead of 2*Trace(A) assert trace(2*A) == 2*Trace(A) X = ImmutableMatrix([[1, 2], [3, 4]]) assert trace(MatMul(2, X)) == 10 def test_rewrite(): assert isinstance(trace(A).rewrite(Sum), Sum) def test_trace_normalize(): assert Trace(B*A) != Trace(A*B) assert Trace(B*A)._normalize() == Trace(A*B) assert Trace(B*A.T)._normalize() == Trace(A*B.T) sympy-sympy-1.9/sympy/matrices/expressions/tests/test_transpose.py000066400000000000000000000035431412543434000260730ustar00rootroot00000000000000from sympy.functions import adjoint, conjugate, transpose from sympy.matrices.expressions import MatrixSymbol, Adjoint, trace, Transpose from sympy.matrices import eye, Matrix from sympy import symbols, S from sympy import refine, Q n, m, l, k, p = symbols('n m l k p', integer=True) A = MatrixSymbol('A', n, m) B = MatrixSymbol('B', m, l) C = MatrixSymbol('C', n, n) def test_transpose(): Sq = MatrixSymbol('Sq', n, n) assert transpose(A) == Transpose(A) assert Transpose(A).shape == (m, n) assert Transpose(A*B).shape == (l, n) assert transpose(Transpose(A)) == A assert isinstance(Transpose(Transpose(A)), Transpose) assert adjoint(Transpose(A)) == Adjoint(Transpose(A)) assert conjugate(Transpose(A)) == Adjoint(A) assert Transpose(eye(3)).doit() == eye(3) assert Transpose(S(5)).doit() == S(5) assert Transpose(Matrix([[1, 2], [3, 4]])).doit() == Matrix([[1, 3], [2, 4]]) assert transpose(trace(Sq)) == trace(Sq) assert trace(Transpose(Sq)) == trace(Sq) assert Transpose(Sq)[0, 1] == Sq[1, 0] assert Transpose(A*B).doit() == Transpose(B) * Transpose(A) def test_transpose_MatAdd_MatMul(): # Issue 16807 from sympy.functions.elementary.trigonometric import cos x = symbols('x') M = MatrixSymbol('M', 3, 3) N = MatrixSymbol('N', 3, 3) assert (N + (cos(x) * M)).T == cos(x)*M.T + N.T def test_refine(): assert refine(C.T, Q.symmetric(C)) == C def test_transpose1x1(): m = MatrixSymbol('m', 1, 1) assert m == refine(m.T) assert m == refine(m.T.T) def test_issue_9817(): from sympy.matrices.expressions import Identity v = MatrixSymbol('v', 3, 1) A = MatrixSymbol('A', 3, 3) x = Matrix([i + 1 for i in range(3)]) X = Identity(3) quadratic = v.T * A * v subbed = quadratic.xreplace({v:x, A:X}) assert subbed.as_explicit() == Matrix([[14]]) sympy-sympy-1.9/sympy/matrices/expressions/trace.py000066400000000000000000000115431412543434000227510ustar00rootroot00000000000000from sympy import Basic, Expr, sympify, S from sympy.matrices.matrices import MatrixBase from sympy.matrices.common import NonSquareMatrixError class Trace(Expr): """Matrix Trace Represents the trace of a matrix expression. Examples ======== >>> from sympy import MatrixSymbol, Trace, eye >>> A = MatrixSymbol('A', 3, 3) >>> Trace(A) Trace(A) >>> Trace(eye(3)) Trace(Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]])) >>> Trace(eye(3)).simplify() 3 """ is_Trace = True is_commutative = True def __new__(cls, mat): mat = sympify(mat) if not mat.is_Matrix: raise TypeError("input to Trace, %s, is not a matrix" % str(mat)) if not mat.is_square: raise NonSquareMatrixError("Trace of a non-square matrix") return Basic.__new__(cls, mat) def _eval_transpose(self): return self def _eval_derivative(self, v): from sympy import Sum from .matexpr import MatrixElement if isinstance(v, MatrixElement): return self.rewrite(Sum).diff(v) expr = self.doit() if isinstance(expr, Trace): # Avoid looping infinitely: raise NotImplementedError return expr._eval_derivative(v) def _eval_derivative_matrix_lines(self, x): from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayContraction from sympy.core.expr import ExprBuilder r = self.args[0]._eval_derivative_matrix_lines(x) for lr in r: if lr.higher == 1: lr.higher = ExprBuilder( ArrayContraction, [ ExprBuilder( ArrayTensorProduct, [ lr._lines[0], lr._lines[1], ] ), (1, 3), ], validator=ArrayContraction._validate ) else: # This is not a matrix line: lr.higher = ExprBuilder( ArrayContraction, [ ExprBuilder( ArrayTensorProduct, [ lr._lines[0], lr._lines[1], lr.higher, ] ), (1, 3), (0, 2) ] ) lr._lines = [S.One, S.One] lr._first_pointer_parent = lr._lines lr._second_pointer_parent = lr._lines lr._first_pointer_index = 0 lr._second_pointer_index = 1 return r @property def arg(self): return self.args[0] def doit(self, **kwargs): if kwargs.get('deep', True): arg = self.arg.doit(**kwargs) try: return arg._eval_trace() except (AttributeError, NotImplementedError): return Trace(arg) else: # _eval_trace would go too deep here if isinstance(self.arg, MatrixBase): return trace(self.arg) else: return Trace(self.arg) def _normalize(self): # Normalization of trace of matrix products. Use transposition and # cyclic properties of traces to make sure the arguments of the matrix # product are sorted and the first argument is not a trasposition. from sympy import MatMul, Transpose, default_sort_key trace_arg = self.arg if isinstance(trace_arg, MatMul): def get_arg_key(x): a = trace_arg.args[x] if isinstance(a, Transpose): a = a.arg return default_sort_key(a) indmin = min(range(len(trace_arg.args)), key=get_arg_key) if isinstance(trace_arg.args[indmin], Transpose): trace_arg = Transpose(trace_arg).doit() indmin = min(range(len(trace_arg.args)), key=lambda x: default_sort_key(trace_arg.args[x])) trace_arg = MatMul.fromiter(trace_arg.args[indmin:] + trace_arg.args[:indmin]) return Trace(trace_arg) return self def _eval_rewrite_as_Sum(self, expr, **kwargs): from sympy import Sum, Dummy i = Dummy('i') return Sum(self.arg[i, i], (i, 0, self.arg.rows-1)).doit() def trace(expr): """Trace of a Matrix. Sum of the diagonal elements. Examples ======== >>> from sympy import trace, Symbol, MatrixSymbol, eye >>> n = Symbol('n') >>> X = MatrixSymbol('X', n, n) # A square matrix >>> trace(2*X) 2*Trace(X) >>> trace(eye(3)) 3 """ return Trace(expr).doit() sympy-sympy-1.9/sympy/matrices/expressions/transpose.py000066400000000000000000000052441412543434000236720ustar00rootroot00000000000000from sympy import Basic from sympy.functions import adjoint, conjugate from sympy.matrices.expressions.matexpr import MatrixExpr class Transpose(MatrixExpr): """ The transpose of a matrix expression. This is a symbolic object that simply stores its argument without evaluating it. To actually compute the transpose, use the ``transpose()`` function, or the ``.T`` attribute of matrices. Examples ======== >>> from sympy.matrices import MatrixSymbol, Transpose >>> from sympy.functions import transpose >>> A = MatrixSymbol('A', 3, 5) >>> B = MatrixSymbol('B', 5, 3) >>> Transpose(A) A.T >>> A.T == transpose(A) == Transpose(A) True >>> Transpose(A*B) (A*B).T >>> transpose(A*B) B.T*A.T """ is_Transpose = True def doit(self, **hints): arg = self.arg if hints.get('deep', True) and isinstance(arg, Basic): arg = arg.doit(**hints) _eval_transpose = getattr(arg, '_eval_transpose', None) if _eval_transpose is not None: result = _eval_transpose() return result if result is not None else Transpose(arg) else: return Transpose(arg) @property def arg(self): return self.args[0] @property def shape(self): return self.arg.shape[::-1] def _entry(self, i, j, expand=False, **kwargs): return self.arg._entry(j, i, expand=expand, **kwargs) def _eval_adjoint(self): return conjugate(self.arg) def _eval_conjugate(self): return adjoint(self.arg) def _eval_transpose(self): return self.arg def _eval_trace(self): from .trace import Trace return Trace(self.arg) # Trace(X.T) => Trace(X) def _eval_determinant(self): from sympy.matrices.expressions.determinant import det return det(self.arg) def _eval_derivative(self, x): # x is a scalar: return self.arg._eval_derivative(x) def _eval_derivative_matrix_lines(self, x): lines = self.args[0]._eval_derivative_matrix_lines(x) return [i.transpose() for i in lines] def transpose(expr): """Matrix transpose""" return Transpose(expr).doit(deep=False) from sympy.assumptions.ask import ask, Q from sympy.assumptions.refine import handlers_dict def refine_Transpose(expr, assumptions): """ >>> from sympy import MatrixSymbol, Q, assuming, refine >>> X = MatrixSymbol('X', 2, 2) >>> X.T X.T >>> with assuming(Q.symmetric(X)): ... print(refine(X.T)) X """ if ask(Q.symmetric(expr), assumptions): return expr.arg return expr handlers_dict['Transpose'] = refine_Transpose sympy-sympy-1.9/sympy/matrices/graph.py000066400000000000000000000215641412543434000203760ustar00rootroot00000000000000from sympy.utilities.iterables import \ flatten, connected_components, strongly_connected_components from .common import NonSquareMatrixError def _connected_components(M): """Returns the list of connected vertices of the graph when a square matrix is viewed as a weighted graph. Examples ======== >>> from sympy import Matrix >>> A = Matrix([ ... [66, 0, 0, 68, 0, 0, 0, 0, 67], ... [0, 55, 0, 0, 0, 0, 54, 53, 0], ... [0, 0, 0, 0, 1, 2, 0, 0, 0], ... [86, 0, 0, 88, 0, 0, 0, 0, 87], ... [0, 0, 10, 0, 11, 12, 0, 0, 0], ... [0, 0, 20, 0, 21, 22, 0, 0, 0], ... [0, 45, 0, 0, 0, 0, 44, 43, 0], ... [0, 35, 0, 0, 0, 0, 34, 33, 0], ... [76, 0, 0, 78, 0, 0, 0, 0, 77]]) >>> A.connected_components() [[0, 3, 8], [1, 6, 7], [2, 4, 5]] Notes ===== Even if any symbolic elements of the matrix can be indeterminate to be zero mathematically, this only takes the account of the structural aspect of the matrix, so they will considered to be nonzero. """ if not M.is_square: raise NonSquareMatrixError V = range(M.rows) E = sorted(M.todok().keys()) return connected_components((V, E)) def _strongly_connected_components(M): """Returns the list of strongly connected vertices of the graph when a square matrix is viewed as a weighted graph. Examples ======== >>> from sympy import Matrix >>> A = Matrix([ ... [44, 0, 0, 0, 43, 0, 45, 0, 0], ... [0, 66, 62, 61, 0, 68, 0, 60, 67], ... [0, 0, 22, 21, 0, 0, 0, 20, 0], ... [0, 0, 12, 11, 0, 0, 0, 10, 0], ... [34, 0, 0, 0, 33, 0, 35, 0, 0], ... [0, 86, 82, 81, 0, 88, 0, 80, 87], ... [54, 0, 0, 0, 53, 0, 55, 0, 0], ... [0, 0, 2, 1, 0, 0, 0, 0, 0], ... [0, 76, 72, 71, 0, 78, 0, 70, 77]]) >>> A.strongly_connected_components() [[0, 4, 6], [2, 3, 7], [1, 5, 8]] """ if not M.is_square: raise NonSquareMatrixError # RepMatrix uses the more efficient DomainMatrix.scc() method rep = getattr(M, '_rep', None) if rep is not None: return rep.scc() V = range(M.rows) E = sorted(M.todok().keys()) return strongly_connected_components((V, E)) def _connected_components_decomposition(M): """Decomposes a square matrix into block diagonal form only using the permutations. Explanation =========== The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a permutation matrix and $B$ is a block diagonal matrix. Returns ======= P, B : PermutationMatrix, BlockDiagMatrix *P* is a permutation matrix for the similarity transform as in the explanation. And *B* is the block diagonal matrix of the result of the permutation. If you would like to get the diagonal blocks from the BlockDiagMatrix, see :meth:`~sympy.matrices.expressions.blockmatrix.BlockDiagMatrix.get_diag_blocks`. Examples ======== >>> from sympy import Matrix, pprint >>> A = Matrix([ ... [66, 0, 0, 68, 0, 0, 0, 0, 67], ... [0, 55, 0, 0, 0, 0, 54, 53, 0], ... [0, 0, 0, 0, 1, 2, 0, 0, 0], ... [86, 0, 0, 88, 0, 0, 0, 0, 87], ... [0, 0, 10, 0, 11, 12, 0, 0, 0], ... [0, 0, 20, 0, 21, 22, 0, 0, 0], ... [0, 45, 0, 0, 0, 0, 44, 43, 0], ... [0, 35, 0, 0, 0, 0, 34, 33, 0], ... [76, 0, 0, 78, 0, 0, 0, 0, 77]]) >>> P, B = A.connected_components_decomposition() >>> pprint(P) PermutationMatrix((1 3)(2 8 5 7 4 6)) >>> pprint(B) [[66 68 67] ] [[ ] ] [[86 88 87] 0 0 ] [[ ] ] [[76 78 77] ] [ ] [ [55 54 53] ] [ [ ] ] [ 0 [45 44 43] 0 ] [ [ ] ] [ [35 34 33] ] [ ] [ [0 1 2 ]] [ [ ]] [ 0 0 [10 11 12]] [ [ ]] [ [20 21 22]] >>> P = P.as_explicit() >>> B = B.as_explicit() >>> P.T*B*P == A True Notes ===== This problem corresponds to the finding of the connected components of a graph, when a matrix is viewed as a weighted graph. """ from sympy.combinatorics.permutations import Permutation from sympy.matrices.expressions.blockmatrix import BlockDiagMatrix from sympy.matrices.expressions.permutation import PermutationMatrix iblocks = M.connected_components() p = Permutation(flatten(iblocks)) P = PermutationMatrix(p) blocks = [] for b in iblocks: blocks.append(M[b, b]) B = BlockDiagMatrix(*blocks) return P, B def _strongly_connected_components_decomposition(M, lower=True): """Decomposes a square matrix into block triangular form only using the permutations. Explanation =========== The decomposition is in a form of $A = P^{-1} B P$ where $P$ is a permutation matrix and $B$ is a block diagonal matrix. Parameters ========== lower : bool Makes $B$ lower block triangular when ``True``. Otherwise, makes $B$ upper block triangular. Returns ======= P, B : PermutationMatrix, BlockMatrix *P* is a permutation matrix for the similarity transform as in the explanation. And *B* is the block triangular matrix of the result of the permutation. Examples ======== >>> from sympy import Matrix, pprint >>> A = Matrix([ ... [44, 0, 0, 0, 43, 0, 45, 0, 0], ... [0, 66, 62, 61, 0, 68, 0, 60, 67], ... [0, 0, 22, 21, 0, 0, 0, 20, 0], ... [0, 0, 12, 11, 0, 0, 0, 10, 0], ... [34, 0, 0, 0, 33, 0, 35, 0, 0], ... [0, 86, 82, 81, 0, 88, 0, 80, 87], ... [54, 0, 0, 0, 53, 0, 55, 0, 0], ... [0, 0, 2, 1, 0, 0, 0, 0, 0], ... [0, 76, 72, 71, 0, 78, 0, 70, 77]]) A lower block triangular decomposition: >>> P, B = A.strongly_connected_components_decomposition() >>> pprint(P) PermutationMatrix((8)(1 4 3 2 6)(5 7)) >>> pprint(B) [[44 43 45] [0 0 0] [0 0 0] ] [[ ] [ ] [ ] ] [[34 33 35] [0 0 0] [0 0 0] ] [[ ] [ ] [ ] ] [[54 53 55] [0 0 0] [0 0 0] ] [ ] [ [0 0 0] [22 21 20] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [12 11 10] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [2 1 0 ] [0 0 0] ] [ ] [ [0 0 0] [62 61 60] [66 68 67]] [ [ ] [ ] [ ]] [ [0 0 0] [82 81 80] [86 88 87]] [ [ ] [ ] [ ]] [ [0 0 0] [72 71 70] [76 78 77]] >>> P = P.as_explicit() >>> B = B.as_explicit() >>> P.T * B * P == A True An upper block triangular decomposition: >>> P, B = A.strongly_connected_components_decomposition(lower=False) >>> pprint(P) PermutationMatrix((0 1 5 7 4 3 2 8 6)) >>> pprint(B) [[66 68 67] [62 61 60] [0 0 0] ] [[ ] [ ] [ ] ] [[86 88 87] [82 81 80] [0 0 0] ] [[ ] [ ] [ ] ] [[76 78 77] [72 71 70] [0 0 0] ] [ ] [ [0 0 0] [22 21 20] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [12 11 10] [0 0 0] ] [ [ ] [ ] [ ] ] [ [0 0 0] [2 1 0 ] [0 0 0] ] [ ] [ [0 0 0] [0 0 0] [44 43 45]] [ [ ] [ ] [ ]] [ [0 0 0] [0 0 0] [34 33 35]] [ [ ] [ ] [ ]] [ [0 0 0] [0 0 0] [54 53 55]] >>> P = P.as_explicit() >>> B = B.as_explicit() >>> P.T * B * P == A True """ from sympy.combinatorics.permutations import Permutation from sympy.matrices.expressions.blockmatrix import BlockMatrix from sympy.matrices.expressions.permutation import PermutationMatrix iblocks = M.strongly_connected_components() if not lower: iblocks = list(reversed(iblocks)) p = Permutation(flatten(iblocks)) P = PermutationMatrix(p) rows = [] for a in iblocks: cols = [] for b in iblocks: cols.append(M[a, b]) rows.append(cols) B = BlockMatrix(rows) return P, B sympy-sympy-1.9/sympy/matrices/immutable.py000066400000000000000000000125401412543434000212460ustar00rootroot00000000000000from mpmath.matrices.matrices import _matrix from sympy.core import Basic, Dict, Tuple from sympy.core.numbers import Integer from sympy.core.cache import cacheit from sympy.core.sympify import converter as sympify_converter, _sympify from sympy.matrices.dense import DenseMatrix from sympy.matrices.expressions import MatrixExpr from sympy.matrices.matrices import MatrixBase from sympy.matrices.repmatrix import RepMatrix from sympy.matrices.sparse import SparseMatrix from sympy.multipledispatch import dispatch def sympify_matrix(arg): return arg.as_immutable() sympify_converter[MatrixBase] = sympify_matrix def sympify_mpmath_matrix(arg): mat = [_sympify(x) for x in arg] return ImmutableDenseMatrix(arg.rows, arg.cols, mat) sympify_converter[_matrix] = sympify_mpmath_matrix class ImmutableRepMatrix(RepMatrix, MatrixExpr): """Immutable matrix based on RepMatrix Uses DomainMAtrix as the internal representation. """ # # This is a subclass of RepMatrix that adds/overrides some methods to make # the instances Basic and immutable. ImmutableRepMatrix is a superclass for # both ImmutableDenseMatrix and ImmutableSparseMatrix. # def __new__(cls, *args, **kwargs): return cls._new(*args, **kwargs) __hash__ = MatrixExpr.__hash__ def copy(self): return self @property def cols(self): return self._cols @property def rows(self): return self._rows @property def shape(self): return self._rows, self._cols def as_immutable(self): return self def _entry(self, i, j, **kwargs): return self[i, j] def __setitem__(self, *args): raise TypeError("Cannot set values of {}".format(self.__class__)) def is_diagonalizable(self, reals_only=False, **kwargs): return super().is_diagonalizable( reals_only=reals_only, **kwargs) is_diagonalizable.__doc__ = SparseMatrix.is_diagonalizable.__doc__ is_diagonalizable = cacheit(is_diagonalizable) class ImmutableDenseMatrix(DenseMatrix, ImmutableRepMatrix): # type: ignore """Create an immutable version of a matrix. Examples ======== >>> from sympy import eye >>> from sympy.matrices import ImmutableMatrix >>> ImmutableMatrix(eye(3)) Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> _[0, 0] = 42 Traceback (most recent call last): ... TypeError: Cannot set values of ImmutableDenseMatrix """ # MatrixExpr is set as NotIterable, but we want explicit matrices to be # iterable _iterable = True _class_priority = 8 _op_priority = 10.001 @classmethod def _new(cls, *args, **kwargs): if len(args) == 1 and isinstance(args[0], ImmutableDenseMatrix): return args[0] if kwargs.get('copy', True) is False: if len(args) != 3: raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]") rows, cols, flat_list = args else: rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs) flat_list = list(flat_list) # create a shallow copy rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list) return cls._fromrep(rep) @classmethod def _fromrep(cls, rep): rows, cols = rep.shape flat_list = rep.to_sympy().to_list_flat() obj = Basic.__new__(cls, Integer(rows), Integer(cols), Tuple(*flat_list, sympify=False)) obj._rows = rows obj._cols = cols obj._rep = rep return obj # make sure ImmutableDenseMatrix is aliased as ImmutableMatrix ImmutableMatrix = ImmutableDenseMatrix class ImmutableSparseMatrix(SparseMatrix, ImmutableRepMatrix): # type:ignore """Create an immutable version of a sparse matrix. Examples ======== >>> from sympy import eye >>> from sympy.matrices.immutable import ImmutableSparseMatrix >>> ImmutableSparseMatrix(1, 1, {}) Matrix([[0]]) >>> ImmutableSparseMatrix(eye(3)) Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> _[0, 0] = 42 Traceback (most recent call last): ... TypeError: Cannot set values of ImmutableSparseMatrix >>> _.shape (3, 3) """ is_Matrix = True _class_priority = 9 @classmethod def _new(cls, *args, **kwargs): rows, cols, smat = cls._handle_creation_inputs(*args, **kwargs) rep = cls._smat_to_DomainMatrix(rows, cols, smat) return cls._fromrep(rep) @classmethod def _fromrep(cls, rep): rows, cols = rep.shape smat = rep.to_sympy().to_dok() obj = Basic.__new__(cls, Integer(rows), Integer(cols), Dict(smat)) obj._rows = rows obj._cols = cols obj._rep = rep return obj @dispatch(ImmutableDenseMatrix, ImmutableDenseMatrix) def _eval_is_eq(lhs, rhs): # noqa:F811 """Helper method for Equality with matrices.sympy. Relational automatically converts matrices to ImmutableDenseMatrix instances, so this method only applies here. Returns True if the matrices are definitively the same, False if they are definitively different, and None if undetermined (e.g. if they contain Symbols). Returning None triggers default handling of Equalities. """ if lhs.shape != rhs.shape: return False return (lhs - rhs).is_zero_matrix sympy-sympy-1.9/sympy/matrices/inverse.py000066400000000000000000000261601412543434000207450ustar00rootroot00000000000000from sympy.core.numbers import mod_inverse from .common import MatrixError, NonSquareMatrixError, NonInvertibleMatrixError from .utilities import _iszero def _pinv_full_rank(M): """Subroutine for full row or column rank matrices. For full row rank matrices, inverse of ``A * A.H`` Exists. For full column rank matrices, inverse of ``A.H * A`` Exists. This routine can apply for both cases by checking the shape and have small decision. """ if M.is_zero_matrix: return M.H if M.rows >= M.cols: return M.H.multiply(M).inv().multiply(M.H) else: return M.H.multiply(M.multiply(M.H).inv()) def _pinv_rank_decomposition(M): """Subroutine for rank decomposition With rank decompositions, `A` can be decomposed into two full- rank matrices, and each matrix can take pseudoinverse individually. """ if M.is_zero_matrix: return M.H B, C = M.rank_decomposition() Bp = _pinv_full_rank(B) Cp = _pinv_full_rank(C) return Cp.multiply(Bp) def _pinv_diagonalization(M): """Subroutine using diagonalization This routine can sometimes fail if SymPy's eigenvalue computation is not reliable. """ if M.is_zero_matrix: return M.H A = M AH = M.H try: if M.rows >= M.cols: P, D = AH.multiply(A).diagonalize(normalize=True) D_pinv = D.applyfunc(lambda x: 0 if _iszero(x) else 1 / x) return P.multiply(D_pinv).multiply(P.H).multiply(AH) else: P, D = A.multiply(AH).diagonalize( normalize=True) D_pinv = D.applyfunc(lambda x: 0 if _iszero(x) else 1 / x) return AH.multiply(P).multiply(D_pinv).multiply(P.H) except MatrixError: raise NotImplementedError( 'pinv for rank-deficient matrices where ' 'diagonalization of A.H*A fails is not supported yet.') def _pinv(M, method='RD'): """Calculate the Moore-Penrose pseudoinverse of the matrix. The Moore-Penrose pseudoinverse exists and is unique for any matrix. If the matrix is invertible, the pseudoinverse is the same as the inverse. Parameters ========== method : String, optional Specifies the method for computing the pseudoinverse. If ``'RD'``, Rank-Decomposition will be used. If ``'ED'``, Diagonalization will be used. Examples ======== Computing pseudoinverse by rank decomposition : >>> from sympy import Matrix >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> A.pinv() Matrix([ [-17/18, 4/9], [ -1/9, 1/9], [ 13/18, -2/9]]) Computing pseudoinverse by diagonalization : >>> B = A.pinv(method='ED') >>> B.simplify() >>> B Matrix([ [-17/18, 4/9], [ -1/9, 1/9], [ 13/18, -2/9]]) See Also ======== inv pinv_solve References ========== .. [1] https://en.wikipedia.org/wiki/Moore-Penrose_pseudoinverse """ # Trivial case: pseudoinverse of all-zero matrix is its transpose. if M.is_zero_matrix: return M.H if method == 'RD': return _pinv_rank_decomposition(M) elif method == 'ED': return _pinv_diagonalization(M) else: raise ValueError('invalid pinv method %s' % repr(method)) def _inv_mod(M, m): r""" Returns the inverse of the matrix `K` (mod `m`), if it exists. Method to find the matrix inverse of `K` (mod `m`) implemented in this function: * Compute `\mathrm{adj}(K) = \mathrm{cof}(K)^t`, the adjoint matrix of `K`. * Compute `r = 1/\mathrm{det}(K) \pmod m`. * `K^{-1} = r\cdot \mathrm{adj}(K) \pmod m`. Examples ======== >>> from sympy import Matrix >>> A = Matrix(2, 2, [1, 2, 3, 4]) >>> A.inv_mod(5) Matrix([ [3, 1], [4, 2]]) >>> A.inv_mod(3) Matrix([ [1, 1], [0, 1]]) """ if not M.is_square: raise NonSquareMatrixError() N = M.cols det_K = M.det() det_inv = None try: det_inv = mod_inverse(det_K, m) except ValueError: raise NonInvertibleMatrixError('Matrix is not invertible (mod %d)' % m) K_adj = M.adjugate() K_inv = M.__class__(N, N, [det_inv * K_adj[i, j] % m for i in range(N) for j in range(N)]) return K_inv def _verify_invertible(M, iszerofunc=_iszero): """Initial check to see if a matrix is invertible. Raises or returns determinant for use in _inv_ADJ.""" if not M.is_square: raise NonSquareMatrixError("A Matrix must be square to invert.") d = M.det(method='berkowitz') zero = d.equals(0) if zero is None: # if equals() can't decide, will rref be able to? ok = M.rref(simplify=True)[0] zero = any(iszerofunc(ok[j, j]) for j in range(ok.rows)) if zero: raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") return d def _inv_ADJ(M, iszerofunc=_iszero): """Calculates the inverse using the adjugate matrix and a determinant. See Also ======== inv inverse_GE inverse_LU inverse_CH inverse_LDL """ d = _verify_invertible(M, iszerofunc=iszerofunc) return M.adjugate() / d def _inv_GE(M, iszerofunc=_iszero): """Calculates the inverse using Gaussian elimination. See Also ======== inv inverse_ADJ inverse_LU inverse_CH inverse_LDL """ from .dense import Matrix if not M.is_square: raise NonSquareMatrixError("A Matrix must be square to invert.") big = Matrix.hstack(M.as_mutable(), Matrix.eye(M.rows)) red = big.rref(iszerofunc=iszerofunc, simplify=True)[0] if any(iszerofunc(red[j, j]) for j in range(red.rows)): raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") return M._new(red[:, big.rows:]) def _inv_LU(M, iszerofunc=_iszero): """Calculates the inverse using LU decomposition. See Also ======== inv inverse_ADJ inverse_GE inverse_CH inverse_LDL """ if not M.is_square: raise NonSquareMatrixError("A Matrix must be square to invert.") if M.free_symbols: _verify_invertible(M, iszerofunc=iszerofunc) return M.LUsolve(M.eye(M.rows), iszerofunc=_iszero) def _inv_CH(M, iszerofunc=_iszero): """Calculates the inverse using cholesky decomposition. See Also ======== inv inverse_ADJ inverse_GE inverse_LU inverse_LDL """ _verify_invertible(M, iszerofunc=iszerofunc) return M.cholesky_solve(M.eye(M.rows)) def _inv_LDL(M, iszerofunc=_iszero): """Calculates the inverse using LDL decomposition. See Also ======== inv inverse_ADJ inverse_GE inverse_LU inverse_CH """ _verify_invertible(M, iszerofunc=iszerofunc) return M.LDLsolve(M.eye(M.rows)) def _inv_QR(M, iszerofunc=_iszero): """Calculates the inverse using QR decomposition. See Also ======== inv inverse_ADJ inverse_GE inverse_CH inverse_LDL """ _verify_invertible(M, iszerofunc=iszerofunc) return M.QRsolve(M.eye(M.rows)) def _inv_block(M, iszerofunc=_iszero): """Calculates the inverse using BLOCKWISE inversion. See Also ======== inv inverse_ADJ inverse_GE inverse_CH inverse_LDL """ from sympy import BlockMatrix i = M.shape[0] if i <= 20 : return M.inv(method="LU", iszerofunc=_iszero) A = M[:i // 2, :i //2] B = M[:i // 2, i // 2:] C = M[i // 2:, :i // 2] D = M[i // 2:, i // 2:] try: D_inv = _inv_block(D) except NonInvertibleMatrixError: return M.inv(method="LU", iszerofunc=_iszero) B_D_i = B*D_inv BDC = B_D_i*C A_n = A - BDC try: A_n = _inv_block(A_n) except NonInvertibleMatrixError: return M.inv(method="LU", iszerofunc=_iszero) B_n = -A_n*B_D_i dc = D_inv*C C_n = -dc*A_n D_n = D_inv + dc*-B_n nn = BlockMatrix([[A_n, B_n], [C_n, D_n]]).as_explicit() return nn def _inv(M, method=None, iszerofunc=_iszero, try_block_diag=False): """ Return the inverse of a matrix using the method indicated. Default for dense matrices is is Gauss elimination, default for sparse matrices is LDL. Parameters ========== method : ('GE', 'LU', 'ADJ', 'CH', 'LDL') iszerofunc : function, optional Zero-testing function to use. try_block_diag : bool, optional If True then will try to form block diagonal matrices using the method get_diag_blocks(), invert these individually, and then reconstruct the full inverse matrix. Examples ======== >>> from sympy import SparseMatrix, Matrix >>> A = SparseMatrix([ ... [ 2, -1, 0], ... [-1, 2, -1], ... [ 0, 0, 2]]) >>> A.inv('CH') Matrix([ [2/3, 1/3, 1/6], [1/3, 2/3, 1/3], [ 0, 0, 1/2]]) >>> A.inv(method='LDL') # use of 'method=' is optional Matrix([ [2/3, 1/3, 1/6], [1/3, 2/3, 1/3], [ 0, 0, 1/2]]) >>> A * _ Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> A = Matrix(A) >>> A.inv('CH') Matrix([ [2/3, 1/3, 1/6], [1/3, 2/3, 1/3], [ 0, 0, 1/2]]) >>> A.inv('ADJ') == A.inv('GE') == A.inv('LU') == A.inv('CH') == A.inv('LDL') == A.inv('QR') True Notes ===== According to the ``method`` keyword, it calls the appropriate method: GE .... inverse_GE(); default for dense matrices LU .... inverse_LU() ADJ ... inverse_ADJ() CH ... inverse_CH() LDL ... inverse_LDL(); default for sparse matrices QR ... inverse_QR() Note, the GE and LU methods may require the matrix to be simplified before it is inverted in order to properly detect zeros during pivoting. In difficult cases a custom zero detection function can be provided by setting the ``iszerofunc`` argument to a function that should return True if its argument is zero. The ADJ routine computes the determinant and uses that to detect singular matrices in addition to testing for zeros on the diagonal. See Also ======== inverse_ADJ inverse_GE inverse_LU inverse_CH inverse_LDL Raises ====== ValueError If the determinant of the matrix is zero. """ from sympy.matrices import diag, SparseMatrix if method is None: method = 'LDL' if isinstance(M, SparseMatrix) else 'GE' if try_block_diag: blocks = M.get_diag_blocks() r = [] for block in blocks: r.append(block.inv(method=method, iszerofunc=iszerofunc)) return diag(*r) if method == "GE": rv = M.inverse_GE(iszerofunc=iszerofunc) elif method == "LU": rv = M.inverse_LU(iszerofunc=iszerofunc) elif method == "ADJ": rv = M.inverse_ADJ(iszerofunc=iszerofunc) elif method == "CH": rv = M.inverse_CH(iszerofunc=iszerofunc) elif method == "LDL": rv = M.inverse_LDL(iszerofunc=iszerofunc) elif method == "QR": rv = M.inverse_QR(iszerofunc=iszerofunc) elif method == "BLOCK": rv = M.inverse_BLOCK(iszerofunc=iszerofunc) else: raise ValueError("Inversion method unrecognized") return M._new(rv) sympy-sympy-1.9/sympy/matrices/matrices.py000066400000000000000000002301231412543434000210750ustar00rootroot00000000000000import mpmath as mp from sympy.core.add import Add from sympy.core.basic import Basic from sympy.core.compatibility import ( Callable, NotIterable, as_int, is_sequence) from sympy.core.decorators import deprecated from sympy.core.expr import Expr from sympy.core.kind import _NumberKind, UndefinedKind from sympy.core.mul import Mul from sympy.core.power import Pow from sympy.core.singleton import S from sympy.core.symbol import Dummy, Symbol, uniquely_named_symbol from sympy.core.sympify import sympify from sympy.core.sympify import _sympify from sympy.functions import exp, factorial, log from sympy.functions.elementary.miscellaneous import Max, Min, sqrt from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.polys import cancel from sympy.printing import sstr from sympy.printing.defaults import Printable from sympy.simplify import simplify as _simplify from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.iterables import flatten from sympy.utilities.misc import filldedent from .common import ( MatrixCommon, MatrixError, NonSquareMatrixError, NonInvertibleMatrixError, ShapeError, MatrixKind) from .utilities import _iszero, _is_zero_after_expand_mul from .determinant import ( _find_reasonable_pivot, _find_reasonable_pivot_naive, _adjugate, _charpoly, _cofactor, _cofactor_matrix, _per, _det, _det_bareiss, _det_berkowitz, _det_LU, _minor, _minor_submatrix) from .reductions import _is_echelon, _echelon_form, _rank, _rref from .subspaces import _columnspace, _nullspace, _rowspace, _orthogonalize from .eigen import ( _eigenvals, _eigenvects, _bidiagonalize, _bidiagonal_decomposition, _is_diagonalizable, _diagonalize, _is_positive_definite, _is_positive_semidefinite, _is_negative_definite, _is_negative_semidefinite, _is_indefinite, _jordan_form, _left_eigenvects, _singular_values) from .decompositions import ( _rank_decomposition, _cholesky, _LDLdecomposition, _LUdecomposition, _LUdecomposition_Simple, _LUdecompositionFF, _singular_value_decomposition, _QRdecomposition, _upper_hessenberg_decomposition) from .graph import ( _connected_components, _connected_components_decomposition, _strongly_connected_components, _strongly_connected_components_decomposition) from .solvers import ( _diagonal_solve, _lower_triangular_solve, _upper_triangular_solve, _cholesky_solve, _LDLsolve, _LUsolve, _QRsolve, _gauss_jordan_solve, _pinv_solve, _solve, _solve_least_squares) from .inverse import ( _pinv, _inv_mod, _inv_ADJ, _inv_GE, _inv_LU, _inv_CH, _inv_LDL, _inv_QR, _inv, _inv_block) class DeferredVector(Symbol, NotIterable): """A vector whose components are deferred (e.g. for use with lambdify) Examples ======== >>> from sympy import DeferredVector, lambdify >>> X = DeferredVector( 'X' ) >>> X X >>> expr = (X[0] + 2, X[2] + 3) >>> func = lambdify( X, expr) >>> func( [1, 2, 3] ) (3, 6) """ def __getitem__(self, i): if i == -0: i = 0 if i < 0: raise IndexError('DeferredVector index out of range') component_name = '%s[%d]' % (self.name, i) return Symbol(component_name) def __str__(self): return sstr(self) def __repr__(self): return "DeferredVector('%s')" % self.name class MatrixDeterminant(MatrixCommon): """Provides basic matrix determinant operations. Should not be instantiated directly. See ``determinant.py`` for their implementations.""" def _eval_det_bareiss(self, iszerofunc=_is_zero_after_expand_mul): return _det_bareiss(self, iszerofunc=iszerofunc) def _eval_det_berkowitz(self): return _det_berkowitz(self) def _eval_det_lu(self, iszerofunc=_iszero, simpfunc=None): return _det_LU(self, iszerofunc=iszerofunc, simpfunc=simpfunc) def _eval_determinant(self): # for expressions.determinant.Determinant return _det(self) def adjugate(self, method="berkowitz"): return _adjugate(self, method=method) def charpoly(self, x='lambda', simplify=_simplify): return _charpoly(self, x=x, simplify=simplify) def cofactor(self, i, j, method="berkowitz"): return _cofactor(self, i, j, method=method) def cofactor_matrix(self, method="berkowitz"): return _cofactor_matrix(self, method=method) def det(self, method="bareiss", iszerofunc=None): return _det(self, method=method, iszerofunc=iszerofunc) def per(self): return _per(self) def minor(self, i, j, method="berkowitz"): return _minor(self, i, j, method=method) def minor_submatrix(self, i, j): return _minor_submatrix(self, i, j) _find_reasonable_pivot.__doc__ = _find_reasonable_pivot.__doc__ _find_reasonable_pivot_naive.__doc__ = _find_reasonable_pivot_naive.__doc__ _eval_det_bareiss.__doc__ = _det_bareiss.__doc__ _eval_det_berkowitz.__doc__ = _det_berkowitz.__doc__ _eval_det_lu.__doc__ = _det_LU.__doc__ _eval_determinant.__doc__ = _det.__doc__ adjugate.__doc__ = _adjugate.__doc__ charpoly.__doc__ = _charpoly.__doc__ cofactor.__doc__ = _cofactor.__doc__ cofactor_matrix.__doc__ = _cofactor_matrix.__doc__ det.__doc__ = _det.__doc__ per.__doc__ = _per.__doc__ minor.__doc__ = _minor.__doc__ minor_submatrix.__doc__ = _minor_submatrix.__doc__ class MatrixReductions(MatrixDeterminant): """Provides basic matrix row/column operations. Should not be instantiated directly. See ``reductions.py`` for some of their implementations.""" def echelon_form(self, iszerofunc=_iszero, simplify=False, with_pivots=False): return _echelon_form(self, iszerofunc=iszerofunc, simplify=simplify, with_pivots=with_pivots) @property def is_echelon(self): return _is_echelon(self) def rank(self, iszerofunc=_iszero, simplify=False): return _rank(self, iszerofunc=iszerofunc, simplify=simplify) def rref(self, iszerofunc=_iszero, simplify=False, pivots=True, normalize_last=True): return _rref(self, iszerofunc=iszerofunc, simplify=simplify, pivots=pivots, normalize_last=normalize_last) echelon_form.__doc__ = _echelon_form.__doc__ is_echelon.__doc__ = _is_echelon.__doc__ rank.__doc__ = _rank.__doc__ rref.__doc__ = _rref.__doc__ def _normalize_op_args(self, op, col, k, col1, col2, error_str="col"): """Validate the arguments for a row/column operation. ``error_str`` can be one of "row" or "col" depending on the arguments being parsed.""" if op not in ["n->kn", "n<->m", "n->n+km"]: raise ValueError("Unknown {} operation '{}'. Valid col operations " "are 'n->kn', 'n<->m', 'n->n+km'".format(error_str, op)) # define self_col according to error_str self_cols = self.cols if error_str == 'col' else self.rows # normalize and validate the arguments if op == "n->kn": col = col if col is not None else col1 if col is None or k is None: raise ValueError("For a {0} operation 'n->kn' you must provide the " "kwargs `{0}` and `k`".format(error_str)) if not 0 <= col < self_cols: raise ValueError("This matrix doesn't have a {} '{}'".format(error_str, col)) elif op == "n<->m": # we need two cols to swap. It doesn't matter # how they were specified, so gather them together and # remove `None` cols = {col, k, col1, col2}.difference([None]) if len(cols) > 2: # maybe the user left `k` by mistake? cols = {col, col1, col2}.difference([None]) if len(cols) != 2: raise ValueError("For a {0} operation 'n<->m' you must provide the " "kwargs `{0}1` and `{0}2`".format(error_str)) col1, col2 = cols if not 0 <= col1 < self_cols: raise ValueError("This matrix doesn't have a {} '{}'".format(error_str, col1)) if not 0 <= col2 < self_cols: raise ValueError("This matrix doesn't have a {} '{}'".format(error_str, col2)) elif op == "n->n+km": col = col1 if col is None else col col2 = col1 if col2 is None else col2 if col is None or col2 is None or k is None: raise ValueError("For a {0} operation 'n->n+km' you must provide the " "kwargs `{0}`, `k`, and `{0}2`".format(error_str)) if col == col2: raise ValueError("For a {0} operation 'n->n+km' `{0}` and `{0}2` must " "be different.".format(error_str)) if not 0 <= col < self_cols: raise ValueError("This matrix doesn't have a {} '{}'".format(error_str, col)) if not 0 <= col2 < self_cols: raise ValueError("This matrix doesn't have a {} '{}'".format(error_str, col2)) else: raise ValueError('invalid operation %s' % repr(op)) return op, col, k, col1, col2 def _eval_col_op_multiply_col_by_const(self, col, k): def entry(i, j): if j == col: return k * self[i, j] return self[i, j] return self._new(self.rows, self.cols, entry) def _eval_col_op_swap(self, col1, col2): def entry(i, j): if j == col1: return self[i, col2] elif j == col2: return self[i, col1] return self[i, j] return self._new(self.rows, self.cols, entry) def _eval_col_op_add_multiple_to_other_col(self, col, k, col2): def entry(i, j): if j == col: return self[i, j] + k * self[i, col2] return self[i, j] return self._new(self.rows, self.cols, entry) def _eval_row_op_swap(self, row1, row2): def entry(i, j): if i == row1: return self[row2, j] elif i == row2: return self[row1, j] return self[i, j] return self._new(self.rows, self.cols, entry) def _eval_row_op_multiply_row_by_const(self, row, k): def entry(i, j): if i == row: return k * self[i, j] return self[i, j] return self._new(self.rows, self.cols, entry) def _eval_row_op_add_multiple_to_other_row(self, row, k, row2): def entry(i, j): if i == row: return self[i, j] + k * self[row2, j] return self[i, j] return self._new(self.rows, self.cols, entry) def elementary_col_op(self, op="n->kn", col=None, k=None, col1=None, col2=None): """Performs the elementary column operation `op`. `op` may be one of * "n->kn" (column n goes to k*n) * "n<->m" (swap column n and column m) * "n->n+km" (column n goes to column n + k*column m) Parameters ========== op : string; the elementary row operation col : the column to apply the column operation k : the multiple to apply in the column operation col1 : one column of a column swap col2 : second column of a column swap or column "m" in the column operation "n->n+km" """ op, col, k, col1, col2 = self._normalize_op_args(op, col, k, col1, col2, "col") # now that we've validated, we're all good to dispatch if op == "n->kn": return self._eval_col_op_multiply_col_by_const(col, k) if op == "n<->m": return self._eval_col_op_swap(col1, col2) if op == "n->n+km": return self._eval_col_op_add_multiple_to_other_col(col, k, col2) def elementary_row_op(self, op="n->kn", row=None, k=None, row1=None, row2=None): """Performs the elementary row operation `op`. `op` may be one of * "n->kn" (row n goes to k*n) * "n<->m" (swap row n and row m) * "n->n+km" (row n goes to row n + k*row m) Parameters ========== op : string; the elementary row operation row : the row to apply the row operation k : the multiple to apply in the row operation row1 : one row of a row swap row2 : second row of a row swap or row "m" in the row operation "n->n+km" """ op, row, k, row1, row2 = self._normalize_op_args(op, row, k, row1, row2, "row") # now that we've validated, we're all good to dispatch if op == "n->kn": return self._eval_row_op_multiply_row_by_const(row, k) if op == "n<->m": return self._eval_row_op_swap(row1, row2) if op == "n->n+km": return self._eval_row_op_add_multiple_to_other_row(row, k, row2) class MatrixSubspaces(MatrixReductions): """Provides methods relating to the fundamental subspaces of a matrix. Should not be instantiated directly. See ``subspaces.py`` for their implementations.""" def columnspace(self, simplify=False): return _columnspace(self, simplify=simplify) def nullspace(self, simplify=False, iszerofunc=_iszero): return _nullspace(self, simplify=simplify, iszerofunc=iszerofunc) def rowspace(self, simplify=False): return _rowspace(self, simplify=simplify) # This is a classmethod but is converted to such later in order to allow # assignment of __doc__ since that does not work for already wrapped # classmethods in Python 3.6. def orthogonalize(cls, *vecs, **kwargs): return _orthogonalize(cls, *vecs, **kwargs) columnspace.__doc__ = _columnspace.__doc__ nullspace.__doc__ = _nullspace.__doc__ rowspace.__doc__ = _rowspace.__doc__ orthogonalize.__doc__ = _orthogonalize.__doc__ orthogonalize = classmethod(orthogonalize) # type:ignore class MatrixEigen(MatrixSubspaces): """Provides basic matrix eigenvalue/vector operations. Should not be instantiated directly. See ``eigen.py`` for their implementations.""" def eigenvals(self, error_when_incomplete=True, **flags): return _eigenvals(self, error_when_incomplete=error_when_incomplete, **flags) def eigenvects(self, error_when_incomplete=True, iszerofunc=_iszero, **flags): return _eigenvects(self, error_when_incomplete=error_when_incomplete, iszerofunc=iszerofunc, **flags) def is_diagonalizable(self, reals_only=False, **kwargs): return _is_diagonalizable(self, reals_only=reals_only, **kwargs) def diagonalize(self, reals_only=False, sort=False, normalize=False): return _diagonalize(self, reals_only=reals_only, sort=sort, normalize=normalize) def bidiagonalize(self, upper=True): return _bidiagonalize(self, upper=upper) def bidiagonal_decomposition(self, upper=True): return _bidiagonal_decomposition(self, upper=upper) @property def is_positive_definite(self): return _is_positive_definite(self) @property def is_positive_semidefinite(self): return _is_positive_semidefinite(self) @property def is_negative_definite(self): return _is_negative_definite(self) @property def is_negative_semidefinite(self): return _is_negative_semidefinite(self) @property def is_indefinite(self): return _is_indefinite(self) def jordan_form(self, calc_transform=True, **kwargs): return _jordan_form(self, calc_transform=calc_transform, **kwargs) def left_eigenvects(self, **flags): return _left_eigenvects(self, **flags) def singular_values(self): return _singular_values(self) eigenvals.__doc__ = _eigenvals.__doc__ eigenvects.__doc__ = _eigenvects.__doc__ is_diagonalizable.__doc__ = _is_diagonalizable.__doc__ diagonalize.__doc__ = _diagonalize.__doc__ is_positive_definite.__doc__ = _is_positive_definite.__doc__ is_positive_semidefinite.__doc__ = _is_positive_semidefinite.__doc__ is_negative_definite.__doc__ = _is_negative_definite.__doc__ is_negative_semidefinite.__doc__ = _is_negative_semidefinite.__doc__ is_indefinite.__doc__ = _is_indefinite.__doc__ jordan_form.__doc__ = _jordan_form.__doc__ left_eigenvects.__doc__ = _left_eigenvects.__doc__ singular_values.__doc__ = _singular_values.__doc__ bidiagonalize.__doc__ = _bidiagonalize.__doc__ bidiagonal_decomposition.__doc__ = _bidiagonal_decomposition.__doc__ class MatrixCalculus(MatrixCommon): """Provides calculus-related matrix operations.""" def diff(self, *args, **kwargs): """Calculate the derivative of each element in the matrix. ``args`` will be passed to the ``integrate`` function. Examples ======== >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y >>> M = Matrix([[x, y], [1, 0]]) >>> M.diff(x) Matrix([ [1, 0], [0, 0]]) See Also ======== integrate limit """ # XXX this should be handled here rather than in Derivative from sympy.tensor.array.array_derivatives import ArrayDerivative kwargs.setdefault('evaluate', True) deriv = ArrayDerivative(self, *args, evaluate=True) if not isinstance(self, Basic): return deriv.as_mutable() else: return deriv def _eval_derivative(self, arg): return self.applyfunc(lambda x: x.diff(arg)) def integrate(self, *args, **kwargs): """Integrate each element of the matrix. ``args`` will be passed to the ``integrate`` function. Examples ======== >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y >>> M = Matrix([[x, y], [1, 0]]) >>> M.integrate((x, )) Matrix([ [x**2/2, x*y], [ x, 0]]) >>> M.integrate((x, 0, 2)) Matrix([ [2, 2*y], [2, 0]]) See Also ======== limit diff """ return self.applyfunc(lambda x: x.integrate(*args, **kwargs)) def jacobian(self, X): """Calculates the Jacobian matrix (derivative of a vector-valued function). Parameters ========== ``self`` : vector of expressions representing functions f_i(x_1, ..., x_n). X : set of x_i's in order, it can be a list or a Matrix Both ``self`` and X can be a row or a column matrix in any order (i.e., jacobian() should always work). Examples ======== >>> from sympy import sin, cos, Matrix >>> from sympy.abc import rho, phi >>> X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) >>> Y = Matrix([rho, phi]) >>> X.jacobian(Y) Matrix([ [cos(phi), -rho*sin(phi)], [sin(phi), rho*cos(phi)], [ 2*rho, 0]]) >>> X = Matrix([rho*cos(phi), rho*sin(phi)]) >>> X.jacobian(Y) Matrix([ [cos(phi), -rho*sin(phi)], [sin(phi), rho*cos(phi)]]) See Also ======== hessian wronskian """ if not isinstance(X, MatrixBase): X = self._new(X) # Both X and ``self`` can be a row or a column matrix, so we need to make # sure all valid combinations work, but everything else fails: if self.shape[0] == 1: m = self.shape[1] elif self.shape[1] == 1: m = self.shape[0] else: raise TypeError("``self`` must be a row or a column matrix") if X.shape[0] == 1: n = X.shape[1] elif X.shape[1] == 1: n = X.shape[0] else: raise TypeError("X must be a row or a column matrix") # m is the number of functions and n is the number of variables # computing the Jacobian is now easy: return self._new(m, n, lambda j, i: self[j].diff(X[i])) def limit(self, *args): """Calculate the limit of each element in the matrix. ``args`` will be passed to the ``limit`` function. Examples ======== >>> from sympy.matrices import Matrix >>> from sympy.abc import x, y >>> M = Matrix([[x, y], [1, 0]]) >>> M.limit(x, 2) Matrix([ [2, y], [1, 0]]) See Also ======== integrate diff """ return self.applyfunc(lambda x: x.limit(*args)) # https://github.com/sympy/sympy/pull/12854 class MatrixDeprecated(MatrixCommon): """A class to house deprecated matrix methods.""" def _legacy_array_dot(self, b): """Compatibility function for deprecated behavior of ``matrix.dot(vector)`` """ from .dense import Matrix if not isinstance(b, MatrixBase): if is_sequence(b): if len(b) != self.cols and len(b) != self.rows: raise ShapeError( "Dimensions incorrect for dot product: %s, %s" % ( self.shape, len(b))) return self.dot(Matrix(b)) else: raise TypeError( "`b` must be an ordered iterable or Matrix, not %s." % type(b)) mat = self if mat.cols == b.rows: if b.cols != 1: mat = mat.T b = b.T prod = flatten((mat * b).tolist()) return prod if mat.cols == b.cols: return mat.dot(b.T) elif mat.rows == b.rows: return mat.T.dot(b) else: raise ShapeError("Dimensions incorrect for dot product: %s, %s" % ( self.shape, b.shape)) def berkowitz_charpoly(self, x=Dummy('lambda'), simplify=_simplify): return self.charpoly(x=x) def berkowitz_det(self): """Computes determinant using Berkowitz method. See Also ======== det berkowitz """ return self.det(method='berkowitz') def berkowitz_eigenvals(self, **flags): """Computes eigenvalues of a Matrix using Berkowitz method. See Also ======== berkowitz """ return self.eigenvals(**flags) def berkowitz_minors(self): """Computes principal minors using Berkowitz method. See Also ======== berkowitz """ sign, minors = self.one, [] for poly in self.berkowitz(): minors.append(sign * poly[-1]) sign = -sign return tuple(minors) def berkowitz(self): from sympy.matrices import zeros berk = ((1,),) if not self: return berk if not self.is_square: raise NonSquareMatrixError() A, N = self, self.rows transforms = [0] * (N - 1) for n in range(N, 1, -1): T, k = zeros(n + 1, n), n - 1 R, C = -A[k, :k], A[:k, k] A, a = A[:k, :k], -A[k, k] items = [C] for i in range(0, n - 2): items.append(A * items[i]) for i, B in enumerate(items): items[i] = (R * B)[0, 0] items = [self.one, a] + items for i in range(n): T[i:, i] = items[:n - i + 1] transforms[k - 1] = T polys = [self._new([self.one, -A[0, 0]])] for i, T in enumerate(transforms): polys.append(T * polys[i]) return berk + tuple(map(tuple, polys)) def cofactorMatrix(self, method="berkowitz"): return self.cofactor_matrix(method=method) def det_bareis(self): return _det_bareiss(self) def det_LU_decomposition(self): """Compute matrix determinant using LU decomposition Note that this method fails if the LU decomposition itself fails. In particular, if the matrix has no inverse this method will fail. TODO: Implement algorithm for sparse matrices (SFF), http://www.eecis.udel.edu/~saunders/papers/sffge/it5.ps. See Also ======== det det_bareiss berkowitz_det """ return self.det(method='lu') def jordan_cell(self, eigenval, n): return self.jordan_block(size=n, eigenvalue=eigenval) def jordan_cells(self, calc_transformation=True): P, J = self.jordan_form() return P, J.get_diag_blocks() def minorEntry(self, i, j, method="berkowitz"): return self.minor(i, j, method=method) def minorMatrix(self, i, j): return self.minor_submatrix(i, j) def permuteBkwd(self, perm): """Permute the rows of the matrix with the given permutation in reverse.""" return self.permute_rows(perm, direction='backward') def permuteFwd(self, perm): """Permute the rows of the matrix with the given permutation.""" return self.permute_rows(perm, direction='forward') @Mul._kind_dispatcher.register(_NumberKind, MatrixKind) def num_mat_mul(k1, k2): """ Return MatrixKind. The element kind is selected by recursive dispatching. Do not need to dispatch in reversed order because KindDispatcher searches for this automatically. """ # Deal with Mul._kind_dispatcher's commutativity # XXX: this function is called with either k1 or k2 as MatrixKind because # the Mul kind dispatcher is commutative. Maybe it shouldn't be. Need to # swap the args here because NumberKind doesn't have an element_kind # attribute. if not isinstance(k2, MatrixKind): k1, k2 = k2, k1 elemk = Mul._kind_dispatcher(k1, k2.element_kind) return MatrixKind(elemk) @Mul._kind_dispatcher.register(MatrixKind, MatrixKind) def mat_mat_mul(k1, k2): """ Return MatrixKind. The element kind is selected by recursive dispatching. """ elemk = Mul._kind_dispatcher(k1.element_kind, k2.element_kind) return MatrixKind(elemk) class MatrixBase(MatrixDeprecated, MatrixCalculus, MatrixEigen, MatrixCommon, Printable): """Base class for matrix objects.""" # Added just for numpy compatibility __array_priority__ = 11 is_Matrix = True _class_priority = 3 _sympify = staticmethod(sympify) zero = S.Zero one = S.One @property def kind(self): elem_kinds = set(e.kind for e in self.flat()) if len(elem_kinds) == 1: elemkind, = elem_kinds else: elemkind = UndefinedKind return MatrixKind(elemkind) def flat(self): return [self[i, j] for i in range(self.rows) for j in range(self.cols)] def __array__(self, dtype=object): from .dense import matrix2numpy return matrix2numpy(self, dtype=dtype) def __len__(self): """Return the number of elements of ``self``. Implemented mainly so bool(Matrix()) == False. """ return self.rows * self.cols def _matrix_pow_by_jordan_blocks(self, num): from sympy.matrices import diag, MutableMatrix from sympy import binomial def jordan_cell_power(jc, n): N = jc.shape[0] l = jc[0,0] if l.is_zero: if N == 1 and n.is_nonnegative: jc[0,0] = l**n elif not (n.is_integer and n.is_nonnegative): raise NonInvertibleMatrixError("Non-invertible matrix can only be raised to a nonnegative integer") else: for i in range(N): jc[0,i] = KroneckerDelta(i, n) else: for i in range(N): bn = binomial(n, i) if isinstance(bn, binomial): bn = bn._eval_expand_func() jc[0,i] = l**(n-i)*bn for i in range(N): for j in range(1, N-i): jc[j,i+j] = jc [j-1,i+j-1] P, J = self.jordan_form() jordan_cells = J.get_diag_blocks() # Make sure jordan_cells matrices are mutable: jordan_cells = [MutableMatrix(j) for j in jordan_cells] for j in jordan_cells: jordan_cell_power(j, num) return self._new(P.multiply(diag(*jordan_cells)) .multiply(P.inv())) def __str__(self): if self.rows == 0 or self.cols == 0: return 'Matrix(%s, %s, [])' % (self.rows, self.cols) return "Matrix(%s)" % str(self.tolist()) def _format_str(self, printer=None): if not printer: from sympy.printing.str import StrPrinter printer = StrPrinter() # Handle zero dimensions: if self.rows == 0 or self.cols == 0: return 'Matrix(%s, %s, [])' % (self.rows, self.cols) if self.rows == 1: return "Matrix([%s])" % self.table(printer, rowsep=',\n') return "Matrix([\n%s])" % self.table(printer, rowsep=',\n') @classmethod def irregular(cls, ntop, *matrices, **kwargs): """Return a matrix filled by the given matrices which are listed in order of appearance from left to right, top to bottom as they first appear in the matrix. They must fill the matrix completely. Examples ======== >>> from sympy import ones, Matrix >>> Matrix.irregular(3, ones(2,1), ones(3,3)*2, ones(2,2)*3, ... ones(1,1)*4, ones(2,2)*5, ones(1,2)*6, ones(1,2)*7) Matrix([ [1, 2, 2, 2, 3, 3], [1, 2, 2, 2, 3, 3], [4, 2, 2, 2, 5, 5], [6, 6, 7, 7, 5, 5]]) """ from sympy.core.compatibility import as_int ntop = as_int(ntop) # make sure we are working with explicit matrices b = [i.as_explicit() if hasattr(i, 'as_explicit') else i for i in matrices] q = list(range(len(b))) dat = [i.rows for i in b] active = [q.pop(0) for _ in range(ntop)] cols = sum([b[i].cols for i in active]) rows = [] while any(dat): r = [] for a, j in enumerate(active): r.extend(b[j][-dat[j], :]) dat[j] -= 1 if dat[j] == 0 and q: active[a] = q.pop(0) if len(r) != cols: raise ValueError(filldedent(''' Matrices provided do not appear to fill the space completely.''')) rows.append(r) return cls._new(rows) @classmethod def _handle_ndarray(cls, arg): # NumPy array or matrix or some other object that implements # __array__. So let's first use this method to get a # numpy.array() and then make a python list out of it. arr = arg.__array__() if len(arr.shape) == 2: rows, cols = arr.shape[0], arr.shape[1] flat_list = [cls._sympify(i) for i in arr.ravel()] return rows, cols, flat_list elif len(arr.shape) == 1: flat_list = [cls._sympify(i) for i in arr] return arr.shape[0], 1, flat_list else: raise NotImplementedError( "SymPy supports just 1D and 2D matrices") @classmethod def _handle_creation_inputs(cls, *args, **kwargs): """Return the number of rows, cols and flat matrix elements. Examples ======== >>> from sympy import Matrix, I Matrix can be constructed as follows: * from a nested list of iterables >>> Matrix( ((1, 2+I), (3, 4)) ) Matrix([ [1, 2 + I], [3, 4]]) * from un-nested iterable (interpreted as a column) >>> Matrix( [1, 2] ) Matrix([ [1], [2]]) * from un-nested iterable with dimensions >>> Matrix(1, 2, [1, 2] ) Matrix([[1, 2]]) * from no arguments (a 0 x 0 matrix) >>> Matrix() Matrix(0, 0, []) * from a rule >>> Matrix(2, 2, lambda i, j: i/(j + 1) ) Matrix([ [0, 0], [1, 1/2]]) See Also ======== irregular - filling a matrix with irregular blocks """ from sympy.matrices.sparse import SparseMatrix from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.matrices.expressions.blockmatrix import BlockMatrix from sympy.utilities.iterables import reshape flat_list = None if len(args) == 1: # Matrix(SparseMatrix(...)) if isinstance(args[0], SparseMatrix): return args[0].rows, args[0].cols, flatten(args[0].tolist()) # Matrix(Matrix(...)) elif isinstance(args[0], MatrixBase): return args[0].rows, args[0].cols, args[0].flat() # Matrix(MatrixSymbol('X', 2, 2)) elif isinstance(args[0], Basic) and args[0].is_Matrix: return args[0].rows, args[0].cols, args[0].as_explicit().flat() elif isinstance(args[0], mp.matrix): M = args[0] flat_list = [cls._sympify(x) for x in M] return M.rows, M.cols, flat_list # Matrix(numpy.ones((2, 2))) elif hasattr(args[0], "__array__"): return cls._handle_ndarray(args[0]) # Matrix([1, 2, 3]) or Matrix([[1, 2], [3, 4]]) elif is_sequence(args[0]) \ and not isinstance(args[0], DeferredVector): dat = list(args[0]) ismat = lambda i: isinstance(i, MatrixBase) and ( evaluate or isinstance(i, BlockMatrix) or isinstance(i, MatrixSymbol)) raw = lambda i: is_sequence(i) and not ismat(i) evaluate = kwargs.get('evaluate', True) if evaluate: def make_explicit(x): """make Block and Symbol explicit""" if isinstance(x, BlockMatrix): return x.as_explicit() elif isinstance(x, MatrixSymbol) and all(_.is_Integer for _ in x.shape): return x.as_explicit() else: return x def make_explicit_row(row): # Could be list or could be list of lists if isinstance(row, (list, tuple)): return [make_explicit(x) for x in row] else: return make_explicit(row) if isinstance(dat, (list, tuple)): dat = [make_explicit_row(row) for row in dat] if dat == [] or dat == [[]]: rows = cols = 0 flat_list = [] elif not any(raw(i) or ismat(i) for i in dat): # a column as a list of values flat_list = [cls._sympify(i) for i in dat] rows = len(flat_list) cols = 1 if rows else 0 elif evaluate and all(ismat(i) for i in dat): # a column as a list of matrices ncol = {i.cols for i in dat if any(i.shape)} if ncol: if len(ncol) != 1: raise ValueError('mismatched dimensions') flat_list = [_ for i in dat for r in i.tolist() for _ in r] cols = ncol.pop() rows = len(flat_list)//cols else: rows = cols = 0 flat_list = [] elif evaluate and any(ismat(i) for i in dat): ncol = set() flat_list = [] for i in dat: if ismat(i): flat_list.extend( [k for j in i.tolist() for k in j]) if any(i.shape): ncol.add(i.cols) elif raw(i): if i: ncol.add(len(i)) flat_list.extend([cls._sympify(ij) for ij in i]) else: ncol.add(1) flat_list.append(i) if len(ncol) > 1: raise ValueError('mismatched dimensions') cols = ncol.pop() rows = len(flat_list)//cols else: # list of lists; each sublist is a logical row # which might consist of many rows if the values in # the row are matrices flat_list = [] ncol = set() rows = cols = 0 for row in dat: if not is_sequence(row) and \ not getattr(row, 'is_Matrix', False): raise ValueError('expecting list of lists') if hasattr(row, '__array__'): if 0 in row.shape: continue elif not row: continue if evaluate and all(ismat(i) for i in row): r, c, flatT = cls._handle_creation_inputs( [i.T for i in row]) T = reshape(flatT, [c]) flat = \ [T[i][j] for j in range(c) for i in range(r)] r, c = c, r else: r = 1 if getattr(row, 'is_Matrix', False): c = 1 flat = [row] else: c = len(row) flat = [cls._sympify(i) for i in row] ncol.add(c) if len(ncol) > 1: raise ValueError('mismatched dimensions') flat_list.extend(flat) rows += r cols = ncol.pop() if ncol else 0 elif len(args) == 3: rows = as_int(args[0]) cols = as_int(args[1]) if rows < 0 or cols < 0: raise ValueError("Cannot create a {} x {} matrix. " "Both dimensions must be positive".format(rows, cols)) # Matrix(2, 2, lambda i, j: i+j) if len(args) == 3 and isinstance(args[2], Callable): op = args[2] flat_list = [] for i in range(rows): flat_list.extend( [cls._sympify(op(cls._sympify(i), cls._sympify(j))) for j in range(cols)]) # Matrix(2, 2, [1, 2, 3, 4]) elif len(args) == 3 and is_sequence(args[2]): flat_list = args[2] if len(flat_list) != rows * cols: raise ValueError( 'List length should be equal to rows*columns') flat_list = [cls._sympify(i) for i in flat_list] # Matrix() elif len(args) == 0: # Empty Matrix rows = cols = 0 flat_list = [] if flat_list is None: raise TypeError(filldedent(''' Data type not understood; expecting list of lists or lists of values.''')) return rows, cols, flat_list def _setitem(self, key, value): """Helper to set value at location given by key. Examples ======== >>> from sympy import Matrix, I, zeros, ones >>> m = Matrix(((1, 2+I), (3, 4))) >>> m Matrix([ [1, 2 + I], [3, 4]]) >>> m[1, 0] = 9 >>> m Matrix([ [1, 2 + I], [9, 4]]) >>> m[1, 0] = [[0, 1]] To replace row r you assign to position r*m where m is the number of columns: >>> M = zeros(4) >>> m = M.cols >>> M[3*m] = ones(1, m)*2; M Matrix([ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 2, 2, 2]]) And to replace column c you can assign to position c: >>> M[2] = ones(m, 1)*4; M Matrix([ [0, 0, 4, 0], [0, 0, 4, 0], [0, 0, 4, 0], [2, 2, 4, 2]]) """ from .dense import Matrix is_slice = isinstance(key, slice) i, j = key = self.key2ij(key) is_mat = isinstance(value, MatrixBase) if type(i) is slice or type(j) is slice: if is_mat: self.copyin_matrix(key, value) return if not isinstance(value, Expr) and is_sequence(value): self.copyin_list(key, value) return raise ValueError('unexpected value: %s' % value) else: if (not is_mat and not isinstance(value, Basic) and is_sequence(value)): value = Matrix(value) is_mat = True if is_mat: if is_slice: key = (slice(*divmod(i, self.cols)), slice(*divmod(j, self.cols))) else: key = (slice(i, i + value.rows), slice(j, j + value.cols)) self.copyin_matrix(key, value) else: return i, j, self._sympify(value) return def add(self, b): """Return self + b """ return self + b def condition_number(self): """Returns the condition number of a matrix. This is the maximum singular value divided by the minimum singular value Examples ======== >>> from sympy import Matrix, S >>> A = Matrix([[1, 0, 0], [0, 10, 0], [0, 0, S.One/10]]) >>> A.condition_number() 100 See Also ======== singular_values """ if not self: return self.zero singularvalues = self.singular_values() return Max(*singularvalues) / Min(*singularvalues) def copy(self): """ Returns the copy of a matrix. Examples ======== >>> from sympy import Matrix >>> A = Matrix(2, 2, [1, 2, 3, 4]) >>> A.copy() Matrix([ [1, 2], [3, 4]]) """ return self._new(self.rows, self.cols, self.flat()) def cross(self, b): r""" Return the cross product of ``self`` and ``b`` relaxing the condition of compatible dimensions: if each has 3 elements, a matrix of the same type and shape as ``self`` will be returned. If ``b`` has the same shape as ``self`` then common identities for the cross product (like `a \times b = - b \times a`) will hold. Parameters ========== b : 3x1 or 1x3 Matrix See Also ======== dot multiply multiply_elementwise """ from sympy.matrices.expressions.matexpr import MatrixExpr if not isinstance(b, MatrixBase) and not isinstance(b, MatrixExpr): raise TypeError( "{} must be a Matrix, not {}.".format(b, type(b))) if not (self.rows * self.cols == b.rows * b.cols == 3): raise ShapeError("Dimensions incorrect for cross product: %s x %s" % ((self.rows, self.cols), (b.rows, b.cols))) else: return self._new(self.rows, self.cols, ( (self[1] * b[2] - self[2] * b[1]), (self[2] * b[0] - self[0] * b[2]), (self[0] * b[1] - self[1] * b[0]))) @property def D(self): """Return Dirac conjugate (if ``self.rows == 4``). Examples ======== >>> from sympy import Matrix, I, eye >>> m = Matrix((0, 1 + I, 2, 3)) >>> m.D Matrix([[0, 1 - I, -2, -3]]) >>> m = (eye(4) + I*eye(4)) >>> m[0, 3] = 2 >>> m.D Matrix([ [1 - I, 0, 0, 0], [ 0, 1 - I, 0, 0], [ 0, 0, -1 + I, 0], [ 2, 0, 0, -1 + I]]) If the matrix does not have 4 rows an AttributeError will be raised because this property is only defined for matrices with 4 rows. >>> Matrix(eye(2)).D Traceback (most recent call last): ... AttributeError: Matrix has no attribute D. See Also ======== sympy.matrices.common.MatrixCommon.conjugate: By-element conjugation sympy.matrices.common.MatrixCommon.H: Hermite conjugation """ from sympy.physics.matrices import mgamma if self.rows != 4: # In Python 3.2, properties can only return an AttributeError # so we can't raise a ShapeError -- see commit which added the # first line of this inline comment. Also, there is no need # for a message since MatrixBase will raise the AttributeError raise AttributeError return self.H * mgamma(0) def dot(self, b, hermitian=None, conjugate_convention=None): """Return the dot or inner product of two vectors of equal length. Here ``self`` must be a ``Matrix`` of size 1 x n or n x 1, and ``b`` must be either a matrix of size 1 x n, n x 1, or a list/tuple of length n. A scalar is returned. By default, ``dot`` does not conjugate ``self`` or ``b``, even if there are complex entries. Set ``hermitian=True`` (and optionally a ``conjugate_convention``) to compute the hermitian inner product. Possible kwargs are ``hermitian`` and ``conjugate_convention``. If ``conjugate_convention`` is ``"left"``, ``"math"`` or ``"maths"``, the conjugate of the first vector (``self``) is used. If ``"right"`` or ``"physics"`` is specified, the conjugate of the second vector ``b`` is used. Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> v = Matrix([1, 1, 1]) >>> M.row(0).dot(v) 6 >>> M.col(0).dot(v) 12 >>> v = [3, 2, 1] >>> M.row(0).dot(v) 10 >>> from sympy import I >>> q = Matrix([1*I, 1*I, 1*I]) >>> q.dot(q, hermitian=False) -3 >>> q.dot(q, hermitian=True) 3 >>> q1 = Matrix([1, 1, 1*I]) >>> q.dot(q1, hermitian=True, conjugate_convention="maths") 1 - 2*I >>> q.dot(q1, hermitian=True, conjugate_convention="physics") 1 + 2*I See Also ======== cross multiply multiply_elementwise """ from .dense import Matrix if not isinstance(b, MatrixBase): if is_sequence(b): if len(b) != self.cols and len(b) != self.rows: raise ShapeError( "Dimensions incorrect for dot product: %s, %s" % ( self.shape, len(b))) return self.dot(Matrix(b)) else: raise TypeError( "`b` must be an ordered iterable or Matrix, not %s." % type(b)) mat = self if (1 not in mat.shape) or (1 not in b.shape) : SymPyDeprecationWarning( feature="Dot product of non row/column vectors", issue=13815, deprecated_since_version="1.2", useinstead="* to take matrix products").warn() return mat._legacy_array_dot(b) if len(mat) != len(b): raise ShapeError("Dimensions incorrect for dot product: %s, %s" % (self.shape, b.shape)) n = len(mat) if mat.shape != (1, n): mat = mat.reshape(1, n) if b.shape != (n, 1): b = b.reshape(n, 1) # Now ``mat`` is a row vector and ``b`` is a column vector. # If it so happens that only conjugate_convention is passed # then automatically set hermitian to True. If only hermitian # is true but no conjugate_convention is not passed then # automatically set it to ``"maths"`` if conjugate_convention is not None and hermitian is None: hermitian = True if hermitian and conjugate_convention is None: conjugate_convention = "maths" if hermitian == True: if conjugate_convention in ("maths", "left", "math"): mat = mat.conjugate() elif conjugate_convention in ("physics", "right"): b = b.conjugate() else: raise ValueError("Unknown conjugate_convention was entered." " conjugate_convention must be one of the" " following: math, maths, left, physics or right.") return (mat * b)[0] def dual(self): """Returns the dual of a matrix, which is: ``(1/2)*levicivita(i, j, k, l)*M(k, l)`` summed over indices `k` and `l` Since the levicivita method is anti_symmetric for any pairwise exchange of indices, the dual of a symmetric matrix is the zero matrix. Strictly speaking the dual defined here assumes that the 'matrix' `M` is a contravariant anti_symmetric second rank tensor, so that the dual is a covariant second rank tensor. """ from sympy import LeviCivita from sympy.matrices import zeros M, n = self[:, :], self.rows work = zeros(n) if self.is_symmetric(): return work for i in range(1, n): for j in range(1, n): acum = 0 for k in range(1, n): acum += LeviCivita(i, j, 0, k) * M[0, k] work[i, j] = acum work[j, i] = -acum for l in range(1, n): acum = 0 for a in range(1, n): for b in range(1, n): acum += LeviCivita(0, l, a, b) * M[a, b] acum /= 2 work[0, l] = -acum work[l, 0] = acum return work def _eval_matrix_exp_jblock(self): """A helper function to compute an exponential of a Jordan block matrix Examples ======== >>> from sympy import Symbol, Matrix >>> l = Symbol('lamda') A trivial example of 1*1 Jordan block: >>> m = Matrix.jordan_block(1, l) >>> m._eval_matrix_exp_jblock() Matrix([[exp(lamda)]]) An example of 3*3 Jordan block: >>> m = Matrix.jordan_block(3, l) >>> m._eval_matrix_exp_jblock() Matrix([ [exp(lamda), exp(lamda), exp(lamda)/2], [ 0, exp(lamda), exp(lamda)], [ 0, 0, exp(lamda)]]) References ========== .. [1] https://en.wikipedia.org/wiki/Matrix_function#Jordan_decomposition """ size = self.rows l = self[0, 0] exp_l = exp(l) bands = {i: exp_l / factorial(i) for i in range(size)} from .sparsetools import banded return self.__class__(banded(size, bands)) def analytic_func(self, f, x): """ Computes f(A) where A is a Square Matrix and f is an analytic function. Examples ======== >>> from sympy import Symbol, Matrix, S, log >>> x = Symbol('x') >>> m = Matrix([[S(5)/4, S(3)/4], [S(3)/4, S(5)/4]]) >>> f = log(x) >>> m.analytic_func(f, x) Matrix([ [ 0, log(2)], [log(2), 0]]) Parameters ========== f : Expr Analytic Function x : Symbol parameter of f """ from sympy import diff f, x = _sympify(f), _sympify(x) if not self.is_square: raise NonSquareMatrixError if not x.is_symbol: raise ValueError("{} must be a symbol.".format(x)) if x not in f.free_symbols: raise ValueError( "{} must be a parameter of {}.".format(x, f)) if x in self.free_symbols: raise ValueError( "{} must not be a parameter of {}.".format(x, self)) eigen = self.eigenvals() max_mul = max(eigen.values()) derivative = {} dd = f for i in range(max_mul - 1): dd = diff(dd, x) derivative[i + 1] = dd n = self.shape[0] r = self.zeros(n) f_val = self.zeros(n, 1) row = 0 for i in eigen: mul = eigen[i] f_val[row] = f.subs(x, i) if f_val[row].is_number and not f_val[row].is_complex: raise ValueError( "Cannot evaluate the function because the " "function {} is not analytic at the given " "eigenvalue {}".format(f, f_val[row])) val = 1 for a in range(n): r[row, a] = val val *= i if mul > 1: coe = [1 for ii in range(n)] deri = 1 while mul > 1: row = row + 1 mul -= 1 d_i = derivative[deri].subs(x, i) if d_i.is_number and not d_i.is_complex: raise ValueError( "Cannot evaluate the function because the " "derivative {} is not analytic at the given " "eigenvalue {}".format(derivative[deri], d_i)) f_val[row] = d_i for a in range(n): if a - deri + 1 <= 0: r[row, a] = 0 coe[a] = 0 continue coe[a] = coe[a]*(a - deri + 1) r[row, a] = coe[a]*pow(i, a - deri) deri += 1 row += 1 c = r.solve(f_val) ans = self.zeros(n) pre = self.eye(n) for i in range(n): ans = ans + c[i]*pre pre *= self return ans def exp(self): """Return the exponential of a square matrix Examples ======== >>> from sympy import Symbol, Matrix >>> t = Symbol('t') >>> m = Matrix([[0, 1], [-1, 0]]) * t >>> m.exp() Matrix([ [ exp(I*t)/2 + exp(-I*t)/2, -I*exp(I*t)/2 + I*exp(-I*t)/2], [I*exp(I*t)/2 - I*exp(-I*t)/2, exp(I*t)/2 + exp(-I*t)/2]]) """ if not self.is_square: raise NonSquareMatrixError( "Exponentiation is valid only for square matrices") try: P, J = self.jordan_form() cells = J.get_diag_blocks() except MatrixError: raise NotImplementedError( "Exponentiation is implemented only for matrices for which the Jordan normal form can be computed") blocks = [cell._eval_matrix_exp_jblock() for cell in cells] from sympy.matrices import diag from sympy import re eJ = diag(*blocks) # n = self.rows ret = P.multiply(eJ, dotprodsimp=None).multiply(P.inv(), dotprodsimp=None) if all(value.is_real for value in self.values()): return type(self)(re(ret)) else: return type(self)(ret) def _eval_matrix_log_jblock(self): """Helper function to compute logarithm of a jordan block. Examples ======== >>> from sympy import Symbol, Matrix >>> l = Symbol('lamda') A trivial example of 1*1 Jordan block: >>> m = Matrix.jordan_block(1, l) >>> m._eval_matrix_log_jblock() Matrix([[log(lamda)]]) An example of 3*3 Jordan block: >>> m = Matrix.jordan_block(3, l) >>> m._eval_matrix_log_jblock() Matrix([ [log(lamda), 1/lamda, -1/(2*lamda**2)], [ 0, log(lamda), 1/lamda], [ 0, 0, log(lamda)]]) """ size = self.rows l = self[0, 0] if l.is_zero: raise MatrixError( 'Could not take logarithm or reciprocal for the given ' 'eigenvalue {}'.format(l)) bands = {0: log(l)} for i in range(1, size): bands[i] = -((-l) ** -i) / i from .sparsetools import banded return self.__class__(banded(size, bands)) def log(self, simplify=cancel): """Return the logarithm of a square matrix Parameters ========== simplify : function, bool The function to simplify the result with. Default is ``cancel``, which is effective to reduce the expression growing for taking reciprocals and inverses for symbolic matrices. Examples ======== >>> from sympy import S, Matrix Examples for positive-definite matrices: >>> m = Matrix([[1, 1], [0, 1]]) >>> m.log() Matrix([ [0, 1], [0, 0]]) >>> m = Matrix([[S(5)/4, S(3)/4], [S(3)/4, S(5)/4]]) >>> m.log() Matrix([ [ 0, log(2)], [log(2), 0]]) Examples for non positive-definite matrices: >>> m = Matrix([[S(3)/4, S(5)/4], [S(5)/4, S(3)/4]]) >>> m.log() Matrix([ [ I*pi/2, log(2) - I*pi/2], [log(2) - I*pi/2, I*pi/2]]) >>> m = Matrix( ... [[0, 0, 0, 1], ... [0, 0, 1, 0], ... [0, 1, 0, 0], ... [1, 0, 0, 0]]) >>> m.log() Matrix([ [ I*pi/2, 0, 0, -I*pi/2], [ 0, I*pi/2, -I*pi/2, 0], [ 0, -I*pi/2, I*pi/2, 0], [-I*pi/2, 0, 0, I*pi/2]]) """ if not self.is_square: raise NonSquareMatrixError( "Logarithm is valid only for square matrices") try: if simplify: P, J = simplify(self).jordan_form() else: P, J = self.jordan_form() cells = J.get_diag_blocks() except MatrixError: raise NotImplementedError( "Logarithm is implemented only for matrices for which " "the Jordan normal form can be computed") blocks = [ cell._eval_matrix_log_jblock() for cell in cells] from sympy.matrices import diag eJ = diag(*blocks) if simplify: ret = simplify(P * eJ * simplify(P.inv())) ret = self.__class__(ret) else: ret = P * eJ * P.inv() return ret def is_nilpotent(self): """Checks if a matrix is nilpotent. A matrix B is nilpotent if for some integer k, B**k is a zero matrix. Examples ======== >>> from sympy import Matrix >>> a = Matrix([[0, 0, 0], [1, 0, 0], [1, 1, 0]]) >>> a.is_nilpotent() True >>> a = Matrix([[1, 0, 1], [1, 0, 0], [1, 1, 0]]) >>> a.is_nilpotent() False """ if not self: return True if not self.is_square: raise NonSquareMatrixError( "Nilpotency is valid only for square matrices") x = uniquely_named_symbol('x', self, modify=lambda s: '_' + s) p = self.charpoly(x) if p.args[0] == x ** self.rows: return True return False def key2bounds(self, keys): """Converts a key with potentially mixed types of keys (integer and slice) into a tuple of ranges and raises an error if any index is out of ``self``'s range. See Also ======== key2ij """ from sympy.matrices.common import a2idx as a2idx_ # Remove this line after deprecation of a2idx from matrices.py islice, jslice = [isinstance(k, slice) for k in keys] if islice: if not self.rows: rlo = rhi = 0 else: rlo, rhi = keys[0].indices(self.rows)[:2] else: rlo = a2idx_(keys[0], self.rows) rhi = rlo + 1 if jslice: if not self.cols: clo = chi = 0 else: clo, chi = keys[1].indices(self.cols)[:2] else: clo = a2idx_(keys[1], self.cols) chi = clo + 1 return rlo, rhi, clo, chi def key2ij(self, key): """Converts key into canonical form, converting integers or indexable items into valid integers for ``self``'s range or returning slices unchanged. See Also ======== key2bounds """ from sympy.matrices.common import a2idx as a2idx_ # Remove this line after deprecation of a2idx from matrices.py if is_sequence(key): if not len(key) == 2: raise TypeError('key must be a sequence of length 2') return [a2idx_(i, n) if not isinstance(i, slice) else i for i, n in zip(key, self.shape)] elif isinstance(key, slice): return key.indices(len(self))[:2] else: return divmod(a2idx_(key, len(self)), self.cols) def normalized(self, iszerofunc=_iszero): """Return the normalized version of ``self``. Parameters ========== iszerofunc : Function, optional A function to determine whether ``self`` is a zero vector. The default ``_iszero`` tests to see if each element is exactly zero. Returns ======= Matrix Normalized vector form of ``self``. It has the same length as a unit vector. However, a zero vector will be returned for a vector with norm 0. Raises ====== ShapeError If the matrix is not in a vector form. See Also ======== norm """ if self.rows != 1 and self.cols != 1: raise ShapeError("A Matrix must be a vector to normalize.") norm = self.norm() if iszerofunc(norm): out = self.zeros(self.rows, self.cols) else: out = self.applyfunc(lambda i: i / norm) return out def norm(self, ord=None): """Return the Norm of a Matrix or Vector. In the simplest case this is the geometric size of the vector Other norms can be specified by the ord parameter ===== ============================ ========================== ord norm for matrices norm for vectors ===== ============================ ========================== None Frobenius norm 2-norm 'fro' Frobenius norm - does not exist inf maximum row sum max(abs(x)) -inf -- min(abs(x)) 1 maximum column sum as below -1 -- as below 2 2-norm (largest sing. value) as below -2 smallest singular value as below other - does not exist sum(abs(x)**ord)**(1./ord) ===== ============================ ========================== Examples ======== >>> from sympy import Matrix, Symbol, trigsimp, cos, sin, oo >>> x = Symbol('x', real=True) >>> v = Matrix([cos(x), sin(x)]) >>> trigsimp( v.norm() ) 1 >>> v.norm(10) (sin(x)**10 + cos(x)**10)**(1/10) >>> A = Matrix([[1, 1], [1, 1]]) >>> A.norm(1) # maximum sum of absolute values of A is 2 2 >>> A.norm(2) # Spectral norm (max of |Ax|/|x| under 2-vector-norm) 2 >>> A.norm(-2) # Inverse spectral norm (smallest singular value) 0 >>> A.norm() # Frobenius Norm 2 >>> A.norm(oo) # Infinity Norm 2 >>> Matrix([1, -2]).norm(oo) 2 >>> Matrix([-1, 2]).norm(-oo) 1 See Also ======== normalized """ # Row or Column Vector Norms vals = list(self.values()) or [0] if self.rows == 1 or self.cols == 1: if ord == 2 or ord is None: # Common case sqrt() return sqrt(Add(*(abs(i) ** 2 for i in vals))) elif ord == 1: # sum(abs(x)) return Add(*(abs(i) for i in vals)) elif ord is S.Infinity: # max(abs(x)) return Max(*[abs(i) for i in vals]) elif ord is S.NegativeInfinity: # min(abs(x)) return Min(*[abs(i) for i in vals]) # Otherwise generalize the 2-norm, Sum(x_i**ord)**(1/ord) # Note that while useful this is not mathematically a norm try: return Pow(Add(*(abs(i) ** ord for i in vals)), S.One / ord) except (NotImplementedError, TypeError): raise ValueError("Expected order to be Number, Symbol, oo") # Matrix Norms else: if ord == 1: # Maximum column sum m = self.applyfunc(abs) return Max(*[sum(m.col(i)) for i in range(m.cols)]) elif ord == 2: # Spectral Norm # Maximum singular value return Max(*self.singular_values()) elif ord == -2: # Minimum singular value return Min(*self.singular_values()) elif ord is S.Infinity: # Infinity Norm - Maximum row sum m = self.applyfunc(abs) return Max(*[sum(m.row(i)) for i in range(m.rows)]) elif (ord is None or isinstance(ord, str) and ord.lower() in ['f', 'fro', 'frobenius', 'vector']): # Reshape as vector and send back to norm function return self.vec().norm(ord=2) else: raise NotImplementedError("Matrix Norms under development") def print_nonzero(self, symb="X"): """Shows location of non-zero entries for fast shape lookup. Examples ======== >>> from sympy.matrices import Matrix, eye >>> m = Matrix(2, 3, lambda i, j: i*3+j) >>> m Matrix([ [0, 1, 2], [3, 4, 5]]) >>> m.print_nonzero() [ XX] [XXX] >>> m = eye(4) >>> m.print_nonzero("x") [x ] [ x ] [ x ] [ x] """ s = [] for i in range(self.rows): line = [] for j in range(self.cols): if self[i, j] == 0: line.append(" ") else: line.append(str(symb)) s.append("[%s]" % ''.join(line)) print('\n'.join(s)) def project(self, v): """Return the projection of ``self`` onto the line containing ``v``. Examples ======== >>> from sympy import Matrix, S, sqrt >>> V = Matrix([sqrt(3)/2, S.Half]) >>> x = Matrix([[1, 0]]) >>> V.project(x) Matrix([[sqrt(3)/2, 0]]) >>> V.project(-x) Matrix([[sqrt(3)/2, 0]]) """ return v * (self.dot(v) / v.dot(v)) def table(self, printer, rowstart='[', rowend=']', rowsep='\n', colsep=', ', align='right'): r""" String form of Matrix as a table. ``printer`` is the printer to use for on the elements (generally something like StrPrinter()) ``rowstart`` is the string used to start each row (by default '['). ``rowend`` is the string used to end each row (by default ']'). ``rowsep`` is the string used to separate rows (by default a newline). ``colsep`` is the string used to separate columns (by default ', '). ``align`` defines how the elements are aligned. Must be one of 'left', 'right', or 'center'. You can also use '<', '>', and '^' to mean the same thing, respectively. This is used by the string printer for Matrix. Examples ======== >>> from sympy import Matrix >>> from sympy.printing.str import StrPrinter >>> M = Matrix([[1, 2], [-33, 4]]) >>> printer = StrPrinter() >>> M.table(printer) '[ 1, 2]\n[-33, 4]' >>> print(M.table(printer)) [ 1, 2] [-33, 4] >>> print(M.table(printer, rowsep=',\n')) [ 1, 2], [-33, 4] >>> print('[%s]' % M.table(printer, rowsep=',\n')) [[ 1, 2], [-33, 4]] >>> print(M.table(printer, colsep=' ')) [ 1 2] [-33 4] >>> print(M.table(printer, align='center')) [ 1 , 2] [-33, 4] >>> print(M.table(printer, rowstart='{', rowend='}')) { 1, 2} {-33, 4} """ # Handle zero dimensions: if self.rows == 0 or self.cols == 0: return '[]' # Build table of string representations of the elements res = [] # Track per-column max lengths for pretty alignment maxlen = [0] * self.cols for i in range(self.rows): res.append([]) for j in range(self.cols): s = printer._print(self[i, j]) res[-1].append(s) maxlen[j] = max(len(s), maxlen[j]) # Patch strings together align = { 'left': 'ljust', 'right': 'rjust', 'center': 'center', '<': 'ljust', '>': 'rjust', '^': 'center', }[align] for i, row in enumerate(res): for j, elem in enumerate(row): row[j] = getattr(elem, align)(maxlen[j]) res[i] = rowstart + colsep.join(row) + rowend return rowsep.join(res) def rank_decomposition(self, iszerofunc=_iszero, simplify=False): return _rank_decomposition(self, iszerofunc=iszerofunc, simplify=simplify) def cholesky(self, hermitian=True): raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') def LDLdecomposition(self, hermitian=True): raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') def LUdecomposition(self, iszerofunc=_iszero, simpfunc=None, rankcheck=False): return _LUdecomposition(self, iszerofunc=iszerofunc, simpfunc=simpfunc, rankcheck=rankcheck) def LUdecomposition_Simple(self, iszerofunc=_iszero, simpfunc=None, rankcheck=False): return _LUdecomposition_Simple(self, iszerofunc=iszerofunc, simpfunc=simpfunc, rankcheck=rankcheck) def LUdecompositionFF(self): return _LUdecompositionFF(self) def singular_value_decomposition(self): return _singular_value_decomposition(self) def QRdecomposition(self): return _QRdecomposition(self) def upper_hessenberg_decomposition(self): return _upper_hessenberg_decomposition(self) def diagonal_solve(self, rhs): return _diagonal_solve(self, rhs) def lower_triangular_solve(self, rhs): raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') def upper_triangular_solve(self, rhs): raise NotImplementedError('This function is implemented in DenseMatrix or SparseMatrix') def cholesky_solve(self, rhs): return _cholesky_solve(self, rhs) def LDLsolve(self, rhs): return _LDLsolve(self, rhs) def LUsolve(self, rhs, iszerofunc=_iszero): return _LUsolve(self, rhs, iszerofunc=iszerofunc) def QRsolve(self, b): return _QRsolve(self, b) def gauss_jordan_solve(self, B, freevar=False): return _gauss_jordan_solve(self, B, freevar=freevar) def pinv_solve(self, B, arbitrary_matrix=None): return _pinv_solve(self, B, arbitrary_matrix=arbitrary_matrix) def solve(self, rhs, method='GJ'): return _solve(self, rhs, method=method) def solve_least_squares(self, rhs, method='CH'): return _solve_least_squares(self, rhs, method=method) def pinv(self, method='RD'): return _pinv(self, method=method) def inv_mod(self, m): return _inv_mod(self, m) def inverse_ADJ(self, iszerofunc=_iszero): return _inv_ADJ(self, iszerofunc=iszerofunc) def inverse_BLOCK(self, iszerofunc=_iszero): return _inv_block(self, iszerofunc=iszerofunc) def inverse_GE(self, iszerofunc=_iszero): return _inv_GE(self, iszerofunc=iszerofunc) def inverse_LU(self, iszerofunc=_iszero): return _inv_LU(self, iszerofunc=iszerofunc) def inverse_CH(self, iszerofunc=_iszero): return _inv_CH(self, iszerofunc=iszerofunc) def inverse_LDL(self, iszerofunc=_iszero): return _inv_LDL(self, iszerofunc=iszerofunc) def inverse_QR(self, iszerofunc=_iszero): return _inv_QR(self, iszerofunc=iszerofunc) def inv(self, method=None, iszerofunc=_iszero, try_block_diag=False): return _inv(self, method=method, iszerofunc=iszerofunc, try_block_diag=try_block_diag) def connected_components(self): return _connected_components(self) def connected_components_decomposition(self): return _connected_components_decomposition(self) def strongly_connected_components(self): return _strongly_connected_components(self) def strongly_connected_components_decomposition(self, lower=True): return _strongly_connected_components_decomposition(self, lower=lower) _sage_ = Basic._sage_ rank_decomposition.__doc__ = _rank_decomposition.__doc__ cholesky.__doc__ = _cholesky.__doc__ LDLdecomposition.__doc__ = _LDLdecomposition.__doc__ LUdecomposition.__doc__ = _LUdecomposition.__doc__ LUdecomposition_Simple.__doc__ = _LUdecomposition_Simple.__doc__ LUdecompositionFF.__doc__ = _LUdecompositionFF.__doc__ singular_value_decomposition.__doc__ = _singular_value_decomposition.__doc__ QRdecomposition.__doc__ = _QRdecomposition.__doc__ upper_hessenberg_decomposition.__doc__ = _upper_hessenberg_decomposition.__doc__ diagonal_solve.__doc__ = _diagonal_solve.__doc__ lower_triangular_solve.__doc__ = _lower_triangular_solve.__doc__ upper_triangular_solve.__doc__ = _upper_triangular_solve.__doc__ cholesky_solve.__doc__ = _cholesky_solve.__doc__ LDLsolve.__doc__ = _LDLsolve.__doc__ LUsolve.__doc__ = _LUsolve.__doc__ QRsolve.__doc__ = _QRsolve.__doc__ gauss_jordan_solve.__doc__ = _gauss_jordan_solve.__doc__ pinv_solve.__doc__ = _pinv_solve.__doc__ solve.__doc__ = _solve.__doc__ solve_least_squares.__doc__ = _solve_least_squares.__doc__ pinv.__doc__ = _pinv.__doc__ inv_mod.__doc__ = _inv_mod.__doc__ inverse_ADJ.__doc__ = _inv_ADJ.__doc__ inverse_GE.__doc__ = _inv_GE.__doc__ inverse_LU.__doc__ = _inv_LU.__doc__ inverse_CH.__doc__ = _inv_CH.__doc__ inverse_LDL.__doc__ = _inv_LDL.__doc__ inverse_QR.__doc__ = _inv_QR.__doc__ inverse_BLOCK.__doc__ = _inv_block.__doc__ inv.__doc__ = _inv.__doc__ connected_components.__doc__ = _connected_components.__doc__ connected_components_decomposition.__doc__ = \ _connected_components_decomposition.__doc__ strongly_connected_components.__doc__ = \ _strongly_connected_components.__doc__ strongly_connected_components_decomposition.__doc__ = \ _strongly_connected_components_decomposition.__doc__ @deprecated( issue=15109, useinstead="from sympy.matrices.common import classof", deprecated_since_version="1.3") def classof(A, B): from sympy.matrices.common import classof as classof_ return classof_(A, B) @deprecated( issue=15109, deprecated_since_version="1.3", useinstead="from sympy.matrices.common import a2idx") def a2idx(j, n=None): from sympy.matrices.common import a2idx as a2idx_ return a2idx_(j, n) sympy-sympy-1.9/sympy/matrices/normalforms.py000066400000000000000000000035031412543434000216250ustar00rootroot00000000000000'''Functions returning normal forms of matrices''' from sympy.polys.polytools import Poly from sympy.polys.matrices import DomainMatrix from sympy.polys.matrices.normalforms import ( smith_normal_form as _snf, invariant_factors as _invf, ) def _to_domain(m, domain=None): """Convert Matrix to DomainMatrix""" # XXX: deprecated support for RawMatrix: ring = getattr(m, "ring", None) m = m.applyfunc(lambda e: e.as_expr() if isinstance(e, Poly) else e) dM = DomainMatrix.from_Matrix(m) domain = domain or ring if domain is not None: dM = dM.convert_to(domain) return dM def smith_normal_form(m, domain=None): ''' Return the Smith Normal Form of a matrix `m` over the ring `domain`. This will only work if the ring is a principal ideal domain. Examples ======== >>> from sympy import Matrix, ZZ >>> from sympy.matrices.normalforms import smith_normal_form >>> m = Matrix([[12, 6, 4], [3, 9, 6], [2, 16, 14]]) >>> print(smith_normal_form(m, domain=ZZ)) Matrix([[1, 0, 0], [0, 10, 0], [0, 0, -30]]) ''' dM = _to_domain(m, domain) return _snf(dM).to_Matrix() def invariant_factors(m, domain=None): ''' Return the tuple of abelian invariants for a matrix `m` (as in the Smith-Normal form) References ========== [1] https://en.wikipedia.org/wiki/Smith_normal_form#Algorithm [2] http://sierra.nmsu.edu/morandi/notes/SmithNormalForm.pdf ''' dM = _to_domain(m, domain) factors = _invf(dM) factors = tuple(dM.domain.to_sympy(f) for f in factors) # XXX: deprecated. if hasattr(m, "ring"): if m.ring.is_PolynomialRing: K = m.ring to_poly = lambda f: Poly(f, K.symbols, domain=K.domain) factors = tuple(to_poly(f) for f in factors) return factors sympy-sympy-1.9/sympy/matrices/reductions.py000066400000000000000000000237031412543434000214510ustar00rootroot00000000000000from types import FunctionType from sympy.simplify.simplify import ( simplify as _simplify, dotprodsimp as _dotprodsimp) from .utilities import _get_intermediate_simp, _iszero from .determinant import _find_reasonable_pivot def _row_reduce_list(mat, rows, cols, one, iszerofunc, simpfunc, normalize_last=True, normalize=True, zero_above=True): """Row reduce a flat list representation of a matrix and return a tuple (rref_matrix, pivot_cols, swaps) where ``rref_matrix`` is a flat list, ``pivot_cols`` are the pivot columns and ``swaps`` are any row swaps that were used in the process of row reduction. Parameters ========== mat : list list of matrix elements, must be ``rows`` * ``cols`` in length rows, cols : integer number of rows and columns in flat list representation one : SymPy object represents the value one, from ``Matrix.one`` iszerofunc : determines if an entry can be used as a pivot simpfunc : used to simplify elements and test if they are zero if ``iszerofunc`` returns `None` normalize_last : indicates where all row reduction should happen in a fraction-free manner and then the rows are normalized (so that the pivots are 1), or whether rows should be normalized along the way (like the naive row reduction algorithm) normalize : whether pivot rows should be normalized so that the pivot value is 1 zero_above : whether entries above the pivot should be zeroed. If ``zero_above=False``, an echelon matrix will be returned. """ def get_col(i): return mat[i::cols] def row_swap(i, j): mat[i*cols:(i + 1)*cols], mat[j*cols:(j + 1)*cols] = \ mat[j*cols:(j + 1)*cols], mat[i*cols:(i + 1)*cols] def cross_cancel(a, i, b, j): """Does the row op row[i] = a*row[i] - b*row[j]""" q = (j - i)*cols for p in range(i*cols, (i + 1)*cols): mat[p] = isimp(a*mat[p] - b*mat[p + q]) isimp = _get_intermediate_simp(_dotprodsimp) piv_row, piv_col = 0, 0 pivot_cols = [] swaps = [] # use a fraction free method to zero above and below each pivot while piv_col < cols and piv_row < rows: pivot_offset, pivot_val, \ assumed_nonzero, newly_determined = _find_reasonable_pivot( get_col(piv_col)[piv_row:], iszerofunc, simpfunc) # _find_reasonable_pivot may have simplified some things # in the process. Let's not let them go to waste for (offset, val) in newly_determined: offset += piv_row mat[offset*cols + piv_col] = val if pivot_offset is None: piv_col += 1 continue pivot_cols.append(piv_col) if pivot_offset != 0: row_swap(piv_row, pivot_offset + piv_row) swaps.append((piv_row, pivot_offset + piv_row)) # if we aren't normalizing last, we normalize # before we zero the other rows if normalize_last is False: i, j = piv_row, piv_col mat[i*cols + j] = one for p in range(i*cols + j + 1, (i + 1)*cols): mat[p] = isimp(mat[p] / pivot_val) # after normalizing, the pivot value is 1 pivot_val = one # zero above and below the pivot for row in range(rows): # don't zero our current row if row == piv_row: continue # don't zero above the pivot unless we're told. if zero_above is False and row < piv_row: continue # if we're already a zero, don't do anything val = mat[row*cols + piv_col] if iszerofunc(val): continue cross_cancel(pivot_val, row, val, piv_row) piv_row += 1 # normalize each row if normalize_last is True and normalize is True: for piv_i, piv_j in enumerate(pivot_cols): pivot_val = mat[piv_i*cols + piv_j] mat[piv_i*cols + piv_j] = one for p in range(piv_i*cols + piv_j + 1, (piv_i + 1)*cols): mat[p] = isimp(mat[p] / pivot_val) return mat, tuple(pivot_cols), tuple(swaps) # This functions is a candidate for caching if it gets implemented for matrices. def _row_reduce(M, iszerofunc, simpfunc, normalize_last=True, normalize=True, zero_above=True): mat, pivot_cols, swaps = _row_reduce_list(list(M), M.rows, M.cols, M.one, iszerofunc, simpfunc, normalize_last=normalize_last, normalize=normalize, zero_above=zero_above) return M._new(M.rows, M.cols, mat), pivot_cols, swaps def _is_echelon(M, iszerofunc=_iszero): """Returns `True` if the matrix is in echelon form. That is, all rows of zeros are at the bottom, and below each leading non-zero in a row are exclusively zeros.""" if M.rows <= 0 or M.cols <= 0: return True zeros_below = all(iszerofunc(t) for t in M[1:, 0]) if iszerofunc(M[0, 0]): return zeros_below and _is_echelon(M[:, 1:], iszerofunc) return zeros_below and _is_echelon(M[1:, 1:], iszerofunc) def _echelon_form(M, iszerofunc=_iszero, simplify=False, with_pivots=False): """Returns a matrix row-equivalent to ``M`` that is in echelon form. Note that echelon form of a matrix is *not* unique, however, properties like the row space and the null space are preserved. Examples ======== >>> from sympy import Matrix >>> M = Matrix([[1, 2], [3, 4]]) >>> M.echelon_form() Matrix([ [1, 2], [0, -2]]) """ simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify mat, pivots, _ = _row_reduce(M, iszerofunc, simpfunc, normalize_last=True, normalize=False, zero_above=False) if with_pivots: return mat, pivots return mat # This functions is a candidate for caching if it gets implemented for matrices. def _rank(M, iszerofunc=_iszero, simplify=False): """Returns the rank of a matrix. Examples ======== >>> from sympy import Matrix >>> from sympy.abc import x >>> m = Matrix([[1, 2], [x, 1 - 1/x]]) >>> m.rank() 2 >>> n = Matrix(3, 3, range(1, 10)) >>> n.rank() 2 """ def _permute_complexity_right(M, iszerofunc): """Permute columns with complicated elements as far right as they can go. Since the ``sympy`` row reduction algorithms start on the left, having complexity right-shifted speeds things up. Returns a tuple (mat, perm) where perm is a permutation of the columns to perform to shift the complex columns right, and mat is the permuted matrix.""" def complexity(i): # the complexity of a column will be judged by how many # element's zero-ness cannot be determined return sum(1 if iszerofunc(e) is None else 0 for e in M[:, i]) complex = [(complexity(i), i) for i in range(M.cols)] perm = [j for (i, j) in sorted(complex)] return (M.permute(perm, orientation='cols'), perm) simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify # for small matrices, we compute the rank explicitly # if is_zero on elements doesn't answer the question # for small matrices, we fall back to the full routine. if M.rows <= 0 or M.cols <= 0: return 0 if M.rows <= 1 or M.cols <= 1: zeros = [iszerofunc(x) for x in M] if False in zeros: return 1 if M.rows == 2 and M.cols == 2: zeros = [iszerofunc(x) for x in M] if not False in zeros and not None in zeros: return 0 d = M.det() if iszerofunc(d) and False in zeros: return 1 if iszerofunc(d) is False: return 2 mat, _ = _permute_complexity_right(M, iszerofunc=iszerofunc) _, pivots, _ = _row_reduce(mat, iszerofunc, simpfunc, normalize_last=True, normalize=False, zero_above=False) return len(pivots) def _rref(M, iszerofunc=_iszero, simplify=False, pivots=True, normalize_last=True): """Return reduced row-echelon form of matrix and indices of pivot vars. Parameters ========== iszerofunc : Function A function used for detecting whether an element can act as a pivot. ``lambda x: x.is_zero`` is used by default. simplify : Function A function used to simplify elements when looking for a pivot. By default SymPy's ``simplify`` is used. pivots : True or False If ``True``, a tuple containing the row-reduced matrix and a tuple of pivot columns is returned. If ``False`` just the row-reduced matrix is returned. normalize_last : True or False If ``True``, no pivots are normalized to `1` until after all entries above and below each pivot are zeroed. This means the row reduction algorithm is fraction free until the very last step. If ``False``, the naive row reduction procedure is used where each pivot is normalized to be `1` before row operations are used to zero above and below the pivot. Examples ======== >>> from sympy import Matrix >>> from sympy.abc import x >>> m = Matrix([[1, 2], [x, 1 - 1/x]]) >>> m.rref() (Matrix([ [1, 0], [0, 1]]), (0, 1)) >>> rref_matrix, rref_pivots = m.rref() >>> rref_matrix Matrix([ [1, 0], [0, 1]]) >>> rref_pivots (0, 1) Notes ===== The default value of ``normalize_last=True`` can provide significant speedup to row reduction, especially on matrices with symbols. However, if you depend on the form row reduction algorithm leaves entries of the matrix, set ``noramlize_last=False`` """ simpfunc = simplify if isinstance(simplify, FunctionType) else _simplify mat, pivot_cols, _ = _row_reduce(M, iszerofunc, simpfunc, normalize_last, normalize=True, zero_above=True) if pivots: mat = (mat, pivot_cols) return mat sympy-sympy-1.9/sympy/matrices/repmatrix.py000066400000000000000000000516671412543434000213170ustar00rootroot00000000000000from collections import defaultdict from operator import index as index_ from sympy.core.compatibility import is_sequence from sympy.core.expr import Expr from sympy.core.kind import NumberKind, UndefinedKind from sympy.core.numbers import Integer, Rational from sympy.core.sympify import _sympify, SympifyError from sympy.core.singleton import S from sympy.polys.domains import ZZ, QQ, EXRAW from sympy.polys.matrices import DomainMatrix from sympy.utilities.misc import filldedent from sympy.utilities.exceptions import SymPyDeprecationWarning from .common import classof from .matrices import MatrixBase, MatrixKind, ShapeError class RepMatrix(MatrixBase): """Matrix implementation based on DomainMatrix as an internal representation. The RepMatrix class is a superclass for Matrix, ImmutableMatrix, SparseMatrix and ImmutableSparseMatrix which are the main usable matrix classes in SymPy. Most methods on this class are simply forwarded to DomainMatrix. """ # # MatrixBase is the common superclass for all of the usable explicit matrix # classes in SymPy. The idea is that MatrixBase is an abstract class though # and that subclasses will implement the lower-level methods. # # RepMatrix is a subclass of MatrixBase that uses DomainMatrix as an # internal representation and delegates lower-level methods to # DomainMatrix. All of SymPy's standard explicit matrix classes subclass # RepMatrix and so use DomainMatrix internally. # # A RepMatrix uses an internal DomainMatrix with the domain set to ZZ, QQ # or EXRAW. The EXRAW domain is equivalent to the previous implementation # of Matrix that used Expr for the elements. The ZZ and QQ domains are used # when applicable just because they are compatible with the previous # implementation but are much more efficient. Other domains such as QQ[x] # are not used because they differ from Expr in some way (e.g. automatic # expansion of powers and products). # def __eq__(self, other): # Skip sympify for mutable matrices... if not isinstance(other, RepMatrix): try: other = _sympify(other) except SympifyError: return NotImplemented if not isinstance(other, RepMatrix): return NotImplemented return self._rep.unify_eq(other._rep) @classmethod def _unify_element_sympy(cls, rep, element): domain = rep.domain element = _sympify(element) if domain != EXRAW: # The domain can only be ZZ, QQ or EXRAW if element.is_Integer: new_domain = domain elif element.is_Rational: new_domain = QQ else: new_domain = EXRAW # XXX: This converts the domain for all elements in the matrix # which can be slow. This happens e.g. if __setitem__ changes one # element to something that does not fit in the domain if new_domain != domain: rep = rep.convert_to(new_domain) domain = new_domain if domain != EXRAW: element = new_domain.from_sympy(element) if domain == EXRAW and not isinstance(element, Expr): SymPyDeprecationWarning( feature="non-Expr objects in a Matrix", useinstead="list of lists, TableForm or some other data structure", issue=21497, deprecated_since_version="1.9" ).warn() return rep, element @classmethod def _dod_to_DomainMatrix(cls, rows, cols, dod, types): if not all(issubclass(typ, Expr) for typ in types): SymPyDeprecationWarning( feature="non-Expr objects in a Matrix", useinstead="list of lists, TableForm or some other data structure", issue=21497, deprecated_since_version="1.9" ).warn() rep = DomainMatrix(dod, (rows, cols), EXRAW) if all(issubclass(typ, Rational) for typ in types): if all(issubclass(typ, Integer) for typ in types): rep = rep.convert_to(ZZ) else: rep = rep.convert_to(QQ) return rep @classmethod def _flat_list_to_DomainMatrix(cls, rows, cols, flat_list): elements_dod = defaultdict(dict) for n, element in enumerate(flat_list): if element != 0: i, j = divmod(n, cols) elements_dod[i][j] = element types = set(map(type, flat_list)) rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types) return rep @classmethod def _smat_to_DomainMatrix(cls, rows, cols, smat): elements_dod = defaultdict(dict) for (i, j), element in smat.items(): if element != 0: elements_dod[i][j] = element types = set(map(type, smat.values())) rep = cls._dod_to_DomainMatrix(rows, cols, elements_dod, types) return rep def flat(self): return self._rep.to_sympy().to_list_flat() def _eval_tolist(self): return self._rep.to_sympy().to_list() def _eval_todok(self): return self._rep.to_sympy().to_dok() def _eval_values(self): return list(self.todok().values()) def copy(self): return self._fromrep(self._rep.copy()) @property def kind(self): domain = self._rep.domain if domain in (ZZ, QQ): element_kind = NumberKind elif domain == EXRAW: kinds = set(e.kind for e in self.values()) if len(kinds) == 1: [element_kind] = kinds else: element_kind = UndefinedKind else: # pragma: no cover raise RuntimeError("Domain should only be ZZ, QQ or EXRAW") return MatrixKind(element_kind) def _eval_has(self, *patterns): # if the matrix has any zeros, see if S.Zero # has the pattern. If _smat is full length, # the matrix has no zeros. zhas = False dok = self.todok() if len(dok) != self.rows*self.cols: zhas = S.Zero.has(*patterns) return zhas or any(value.has(*patterns) for value in dok.values()) def _eval_is_Identity(self): if not all(self[i, i] == 1 for i in range(self.rows)): return False return len(self.todok()) == self.rows def _eval_is_symmetric(self, simpfunc): diff = (self - self.T).applyfunc(simpfunc) return len(diff.values()) == 0 def _eval_transpose(self): """Returns the transposed SparseMatrix of this SparseMatrix. Examples ======== >>> from sympy.matrices import SparseMatrix >>> a = SparseMatrix(((1, 2), (3, 4))) >>> a Matrix([ [1, 2], [3, 4]]) >>> a.T Matrix([ [1, 3], [2, 4]]) """ return self._fromrep(self._rep.transpose()) def _eval_col_join(self, other): return self._fromrep(self._rep.vstack(other._rep)) def _eval_row_join(self, other): return self._fromrep(self._rep.hstack(other._rep)) def _eval_extract(self, rowsList, colsList): return self._fromrep(self._rep.extract(rowsList, colsList)) def __getitem__(self, key): return _getitem_RepMatrix(self, key) @classmethod def _eval_zeros(cls, rows, cols): rep = DomainMatrix.zeros((rows, cols), ZZ) return cls._fromrep(rep) @classmethod def _eval_eye(cls, rows, cols): rep = DomainMatrix.eye((rows, cols), ZZ) return cls._fromrep(rep) def _eval_add(self, other): return classof(self, other)._fromrep(self._rep + other._rep) def _eval_matrix_mul(self, other): return classof(self, other)._fromrep(self._rep * other._rep) def _eval_matrix_mul_elementwise(self, other): rep = self._rep.mul_elementwise(other._rep) return classof(self, other)._fromrep(rep) def _eval_scalar_mul(self, other): rep, other = self._unify_element_sympy(self._rep, other) return self._fromrep(rep.scalarmul(other)) def _eval_scalar_rmul(self, other): rep, other = self._unify_element_sympy(self._rep, other) return self._fromrep(rep.rscalarmul(other)) def _eval_Abs(self): return self._fromrep(self._rep.applyfunc(abs)) def _eval_conjugate(self): rep = self._rep domain = rep.domain if domain in (ZZ, QQ): return self.copy() else: return self._fromrep(rep.applyfunc(lambda e: e.conjugate())) def equals(self, other, failing_expression=False): """Applies ``equals`` to corresponding elements of the matrices, trying to prove that the elements are equivalent, returning True if they are, False if any pair is not, and None (or the first failing expression if failing_expression is True) if it cannot be decided if the expressions are equivalent or not. This is, in general, an expensive operation. Examples ======== >>> from sympy.matrices import Matrix >>> from sympy.abc import x >>> A = Matrix([x*(x - 1), 0]) >>> B = Matrix([x**2 - x, 0]) >>> A == B False >>> A.simplify() == B.simplify() True >>> A.equals(B) True >>> A.equals(2) False See Also ======== sympy.core.expr.Expr.equals """ if self.shape != getattr(other, 'shape', None): return False rv = True for i in range(self.rows): for j in range(self.cols): ans = self[i, j].equals(other[i, j], failing_expression) if ans is False: return False elif ans is not True and rv is True: rv = ans return rv class MutableRepMatrix(RepMatrix): """Mutable matrix based on DomainMatrix as the internal representation""" # # MutableRepMatrix is a subclass of RepMatrix that adds/overrides methods # to make the instances mutable. MutableRepMatrix is a superclass for both # MutableDenseMatrix and MutableSparseMatrix. # __hash__ = None is_zero = False def __new__(cls, *args, **kwargs): return cls._new(*args, **kwargs) @classmethod def _new(cls, *args, copy=True, **kwargs): if copy is False: # The input was rows, cols, [list]. # It should be used directly without creating a copy. if len(args) != 3: raise TypeError("'copy=False' requires a matrix be initialized as rows,cols,[list]") rows, cols, flat_list = args else: rows, cols, flat_list = cls._handle_creation_inputs(*args, **kwargs) flat_list = list(flat_list) # create a shallow copy rep = cls._flat_list_to_DomainMatrix(rows, cols, flat_list) return cls._fromrep(rep) @classmethod def _fromrep(cls, rep): obj = super().__new__(cls) obj.rows, obj.cols = rep.shape obj._rep = rep return obj def copy(self): return self._fromrep(self._rep.copy()) def as_mutable(self): return self.copy() def __setitem__(self, key, value): """ Examples ======== >>> from sympy import Matrix, I, zeros, ones >>> m = Matrix(((1, 2+I), (3, 4))) >>> m Matrix([ [1, 2 + I], [3, 4]]) >>> m[1, 0] = 9 >>> m Matrix([ [1, 2 + I], [9, 4]]) >>> m[1, 0] = [[0, 1]] To replace row r you assign to position r*m where m is the number of columns: >>> M = zeros(4) >>> m = M.cols >>> M[3*m] = ones(1, m)*2; M Matrix([ [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [2, 2, 2, 2]]) And to replace column c you can assign to position c: >>> M[2] = ones(m, 1)*4; M Matrix([ [0, 0, 4, 0], [0, 0, 4, 0], [0, 0, 4, 0], [2, 2, 4, 2]]) """ rv = self._setitem(key, value) if rv is not None: i, j, value = rv self._rep, value = self._unify_element_sympy(self._rep, value) self._rep.rep.setitem(i, j, value) def _eval_col_del(self, col): self._rep = DomainMatrix.hstack(self._rep[:,:col], self._rep[:,col+1:]) self.cols -= 1 def _eval_row_del(self, row): self._rep = DomainMatrix.vstack(self._rep[:row,:], self._rep[row+1:, :]) self.rows -= 1 def _eval_col_insert(self, col, other): other = self._new(other) return self.hstack(self[:,:col], other, self[:,col:]) def _eval_row_insert(self, row, other): other = self._new(other) return self.vstack(self[:row,:], other, self[row:,:]) def col_op(self, j, f): """In-place operation on col j using two-arg functor whose args are interpreted as (self[i, j], i). Examples ======== >>> from sympy.matrices import eye >>> M = eye(3) >>> M.col_op(1, lambda v, i: v + 2*M[i, 0]); M Matrix([ [1, 2, 0], [0, 1, 0], [0, 0, 1]]) See Also ======== col row_op """ for i in range(self.rows): self[i, j] = f(self[i, j], i) def col_swap(self, i, j): """Swap the two given columns of the matrix in-place. Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix([[1, 0], [1, 0]]) >>> M Matrix([ [1, 0], [1, 0]]) >>> M.col_swap(0, 1) >>> M Matrix([ [0, 1], [0, 1]]) See Also ======== col row_swap """ for k in range(0, self.rows): self[k, i], self[k, j] = self[k, j], self[k, i] def row_op(self, i, f): """In-place operation on row ``i`` using two-arg functor whose args are interpreted as ``(self[i, j], j)``. Examples ======== >>> from sympy.matrices import eye >>> M = eye(3) >>> M.row_op(1, lambda v, j: v + 2*M[0, j]); M Matrix([ [1, 0, 0], [2, 1, 0], [0, 0, 1]]) See Also ======== row zip_row_op col_op """ for j in range(self.cols): self[i, j] = f(self[i, j], j) def row_swap(self, i, j): """Swap the two given rows of the matrix in-place. Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix([[0, 1], [1, 0]]) >>> M Matrix([ [0, 1], [1, 0]]) >>> M.row_swap(0, 1) >>> M Matrix([ [1, 0], [0, 1]]) See Also ======== row col_swap """ for k in range(0, self.cols): self[i, k], self[j, k] = self[j, k], self[i, k] def zip_row_op(self, i, k, f): """In-place operation on row ``i`` using two-arg functor whose args are interpreted as ``(self[i, j], self[k, j])``. Examples ======== >>> from sympy.matrices import eye >>> M = eye(3) >>> M.zip_row_op(1, 0, lambda v, u: v + 2*u); M Matrix([ [1, 0, 0], [2, 1, 0], [0, 0, 1]]) See Also ======== row row_op col_op """ for j in range(self.cols): self[i, j] = f(self[i, j], self[k, j]) def copyin_list(self, key, value): """Copy in elements from a list. Parameters ========== key : slice The section of this matrix to replace. value : iterable The iterable to copy values from. Examples ======== >>> from sympy.matrices import eye >>> I = eye(3) >>> I[:2, 0] = [1, 2] # col >>> I Matrix([ [1, 0, 0], [2, 1, 0], [0, 0, 1]]) >>> I[1, :2] = [[3, 4]] >>> I Matrix([ [1, 0, 0], [3, 4, 0], [0, 0, 1]]) See Also ======== copyin_matrix """ if not is_sequence(value): raise TypeError("`value` must be an ordered iterable, not %s." % type(value)) return self.copyin_matrix(key, type(self)(value)) def copyin_matrix(self, key, value): """Copy in values from a matrix into the given bounds. Parameters ========== key : slice The section of this matrix to replace. value : Matrix The matrix to copy values from. Examples ======== >>> from sympy.matrices import Matrix, eye >>> M = Matrix([[0, 1], [2, 3], [4, 5]]) >>> I = eye(3) >>> I[:3, :2] = M >>> I Matrix([ [0, 1, 0], [2, 3, 0], [4, 5, 1]]) >>> I[0, 1] = M >>> I Matrix([ [0, 0, 1], [2, 2, 3], [4, 4, 5]]) See Also ======== copyin_list """ rlo, rhi, clo, chi = self.key2bounds(key) shape = value.shape dr, dc = rhi - rlo, chi - clo if shape != (dr, dc): raise ShapeError(filldedent("The Matrix `value` doesn't have the " "same dimensions " "as the in sub-Matrix given by `key`.")) for i in range(value.rows): for j in range(value.cols): self[i + rlo, j + clo] = value[i, j] def fill(self, value): """Fill self with the given value. Notes ===== Unless many values are going to be deleted (i.e. set to zero) this will create a matrix that is slower than a dense matrix in operations. Examples ======== >>> from sympy.matrices import SparseMatrix >>> M = SparseMatrix.zeros(3); M Matrix([ [0, 0, 0], [0, 0, 0], [0, 0, 0]]) >>> M.fill(1); M Matrix([ [1, 1, 1], [1, 1, 1], [1, 1, 1]]) See Also ======== zeros ones """ value = _sympify(value) if not value: self._rep = DomainMatrix.zeros(self.shape, EXRAW) else: elements_dod = {i: {j: value for j in range(self.cols)} for i in range(self.rows)} self._rep = DomainMatrix(elements_dod, self.shape, EXRAW) def _getitem_RepMatrix(self, key): """Return portion of self defined by key. If the key involves a slice then a list will be returned (if key is a single slice) or a matrix (if key was a tuple involving a slice). Examples ======== >>> from sympy import Matrix, I >>> m = Matrix([ ... [1, 2 + I], ... [3, 4 ]]) If the key is a tuple that doesn't involve a slice then that element is returned: >>> m[1, 0] 3 When a tuple key involves a slice, a matrix is returned. Here, the first column is selected (all rows, column 0): >>> m[:, 0] Matrix([ [1], [3]]) If the slice is not a tuple then it selects from the underlying list of elements that are arranged in row order and a list is returned if a slice is involved: >>> m[0] 1 >>> m[::2] [1, 3] """ if isinstance(key, tuple): i, j = key try: return self._rep.getitem_sympy(index_(i), index_(j)) except (TypeError, IndexError): if (isinstance(i, Expr) and not i.is_number) or (isinstance(j, Expr) and not j.is_number): if ((j < 0) is True) or ((j >= self.shape[1]) is True) or\ ((i < 0) is True) or ((i >= self.shape[0]) is True): raise ValueError("index out of boundary") from sympy.matrices.expressions.matexpr import MatrixElement return MatrixElement(self, i, j) if isinstance(i, slice): i = range(self.rows)[i] elif is_sequence(i): pass else: i = [i] if isinstance(j, slice): j = range(self.cols)[j] elif is_sequence(j): pass else: j = [j] return self.extract(i, j) else: # Index/slice like a flattened list rows, cols = self.shape # Raise the appropriate exception: if not rows * cols: return [][key] rep = self._rep.rep domain = rep.domain is_slice = isinstance(key, slice) if is_slice: values = [rep.getitem(*divmod(n, cols)) for n in range(rows * cols)[key]] else: values = [rep.getitem(*divmod(index_(key), cols))] if domain != EXRAW: to_sympy = domain.to_sympy values = [to_sympy(val) for val in values] if is_slice: return values else: return values[0] sympy-sympy-1.9/sympy/matrices/solvers.py000066400000000000000000000544211412543434000207700ustar00rootroot00000000000000from sympy.core.function import expand_mul from sympy.core.symbol import Dummy, uniquely_named_symbol, symbols from sympy.utilities.iterables import numbered_symbols from .common import ShapeError, NonSquareMatrixError, NonInvertibleMatrixError from .eigen import _fuzzy_positive_definite from .utilities import _get_intermediate_simp, _iszero def _diagonal_solve(M, rhs): """Solves ``Ax = B`` efficiently, where A is a diagonal Matrix, with non-zero diagonal entries. Examples ======== >>> from sympy.matrices import Matrix, eye >>> A = eye(2)*2 >>> B = Matrix([[1, 2], [3, 4]]) >>> A.diagonal_solve(B) == B/2 True See Also ======== sympy.matrices.dense.DenseMatrix.lower_triangular_solve sympy.matrices.dense.DenseMatrix.upper_triangular_solve gauss_jordan_solve cholesky_solve LDLsolve LUsolve QRsolve pinv_solve """ if not M.is_diagonal(): raise TypeError("Matrix should be diagonal") if rhs.rows != M.rows: raise TypeError("Size mis-match") return M._new( rhs.rows, rhs.cols, lambda i, j: rhs[i, j] / M[i, i]) def _lower_triangular_solve(M, rhs): """Solves ``Ax = B``, where A is a lower triangular matrix. See Also ======== upper_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LDLsolve LUsolve QRsolve pinv_solve """ from .dense import MutableDenseMatrix if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if rhs.rows != M.rows: raise ShapeError("Matrices size mismatch.") if not M.is_lower: raise ValueError("Matrix must be lower triangular.") dps = _get_intermediate_simp() X = MutableDenseMatrix.zeros(M.rows, rhs.cols) for j in range(rhs.cols): for i in range(M.rows): if M[i, i] == 0: raise TypeError("Matrix must be non-singular.") X[i, j] = dps((rhs[i, j] - sum(M[i, k]*X[k, j] for k in range(i))) / M[i, i]) return M._new(X) def _lower_triangular_solve_sparse(M, rhs): """Solves ``Ax = B``, where A is a lower triangular matrix. See Also ======== upper_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LDLsolve LUsolve QRsolve pinv_solve """ if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if rhs.rows != M.rows: raise ShapeError("Matrices size mismatch.") if not M.is_lower: raise ValueError("Matrix must be lower triangular.") dps = _get_intermediate_simp() rows = [[] for i in range(M.rows)] for i, j, v in M.row_list(): if i > j: rows[i].append((j, v)) X = rhs.as_mutable() for j in range(rhs.cols): for i in range(rhs.rows): for u, v in rows[i]: X[i, j] -= v*X[u, j] X[i, j] = dps(X[i, j] / M[i, i]) return M._new(X) def _upper_triangular_solve(M, rhs): """Solves ``Ax = B``, where A is an upper triangular matrix. See Also ======== lower_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LDLsolve LUsolve QRsolve pinv_solve """ from .dense import MutableDenseMatrix if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if rhs.rows != M.rows: raise ShapeError("Matrix size mismatch.") if not M.is_upper: raise TypeError("Matrix is not upper triangular.") dps = _get_intermediate_simp() X = MutableDenseMatrix.zeros(M.rows, rhs.cols) for j in range(rhs.cols): for i in reversed(range(M.rows)): if M[i, i] == 0: raise ValueError("Matrix must be non-singular.") X[i, j] = dps((rhs[i, j] - sum(M[i, k]*X[k, j] for k in range(i + 1, M.rows))) / M[i, i]) return M._new(X) def _upper_triangular_solve_sparse(M, rhs): """Solves ``Ax = B``, where A is an upper triangular matrix. See Also ======== lower_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LDLsolve LUsolve QRsolve pinv_solve """ if not M.is_square: raise NonSquareMatrixError("Matrix must be square.") if rhs.rows != M.rows: raise ShapeError("Matrix size mismatch.") if not M.is_upper: raise TypeError("Matrix is not upper triangular.") dps = _get_intermediate_simp() rows = [[] for i in range(M.rows)] for i, j, v in M.row_list(): if i < j: rows[i].append((j, v)) X = rhs.as_mutable() for j in range(rhs.cols): for i in reversed(range(rhs.rows)): for u, v in reversed(rows[i]): X[i, j] -= v*X[u, j] X[i, j] = dps(X[i, j] / M[i, i]) return M._new(X) def _cholesky_solve(M, rhs): """Solves ``Ax = B`` using Cholesky decomposition, for a general square non-singular matrix. For a non-square matrix with rows > cols, the least squares solution is returned. See Also ======== sympy.matrices.dense.DenseMatrix.lower_triangular_solve sympy.matrices.dense.DenseMatrix.upper_triangular_solve gauss_jordan_solve diagonal_solve LDLsolve LUsolve QRsolve pinv_solve """ if M.rows < M.cols: raise NotImplementedError( 'Under-determined System. Try M.gauss_jordan_solve(rhs)') hermitian = True reform = False if M.is_symmetric(): hermitian = False elif not M.is_hermitian: reform = True if reform or _fuzzy_positive_definite(M) is False: H = M.H M = H.multiply(M) rhs = H.multiply(rhs) hermitian = not M.is_symmetric() L = M.cholesky(hermitian=hermitian) Y = L.lower_triangular_solve(rhs) if hermitian: return (L.H).upper_triangular_solve(Y) else: return (L.T).upper_triangular_solve(Y) def _LDLsolve(M, rhs): """Solves ``Ax = B`` using LDL decomposition, for a general square and non-singular matrix. For a non-square matrix with rows > cols, the least squares solution is returned. Examples ======== >>> from sympy.matrices import Matrix, eye >>> A = eye(2)*2 >>> B = Matrix([[1, 2], [3, 4]]) >>> A.LDLsolve(B) == B/2 True See Also ======== sympy.matrices.dense.DenseMatrix.LDLdecomposition sympy.matrices.dense.DenseMatrix.lower_triangular_solve sympy.matrices.dense.DenseMatrix.upper_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LUsolve QRsolve pinv_solve """ if M.rows < M.cols: raise NotImplementedError( 'Under-determined System. Try M.gauss_jordan_solve(rhs)') hermitian = True reform = False if M.is_symmetric(): hermitian = False elif not M.is_hermitian: reform = True if reform or _fuzzy_positive_definite(M) is False: H = M.H M = H.multiply(M) rhs = H.multiply(rhs) hermitian = not M.is_symmetric() L, D = M.LDLdecomposition(hermitian=hermitian) Y = L.lower_triangular_solve(rhs) Z = D.diagonal_solve(Y) if hermitian: return (L.H).upper_triangular_solve(Z) else: return (L.T).upper_triangular_solve(Z) def _LUsolve(M, rhs, iszerofunc=_iszero): """Solve the linear system ``Ax = rhs`` for ``x`` where ``A = M``. This is for symbolic matrices, for real or complex ones use mpmath.lu_solve or mpmath.qr_solve. See Also ======== sympy.matrices.dense.DenseMatrix.lower_triangular_solve sympy.matrices.dense.DenseMatrix.upper_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LDLsolve QRsolve pinv_solve LUdecomposition """ if rhs.rows != M.rows: raise ShapeError( "``M`` and ``rhs`` must have the same number of rows.") m = M.rows n = M.cols if m < n: raise NotImplementedError("Underdetermined systems not supported.") try: A, perm = M.LUdecomposition_Simple( iszerofunc=_iszero, rankcheck=True) except ValueError: raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") dps = _get_intermediate_simp() b = rhs.permute_rows(perm).as_mutable() # forward substitution, all diag entries are scaled to 1 for i in range(m): for j in range(min(i, n)): scale = A[i, j] b.zip_row_op(i, j, lambda x, y: dps(x - y * scale)) # consistency check for overdetermined systems if m > n: for i in range(n, m): for j in range(b.cols): if not iszerofunc(b[i, j]): raise ValueError("The system is inconsistent.") b = b[0:n, :] # truncate zero rows if consistent # backward substitution for i in range(n - 1, -1, -1): for j in range(i + 1, n): scale = A[i, j] b.zip_row_op(i, j, lambda x, y: dps(x - y * scale)) scale = A[i, i] b.row_op(i, lambda x, _: dps(x / scale)) return rhs.__class__(b) def _QRsolve(M, b): """Solve the linear system ``Ax = b``. ``M`` is the matrix ``A``, the method argument is the vector ``b``. The method returns the solution vector ``x``. If ``b`` is a matrix, the system is solved for each column of ``b`` and the return value is a matrix of the same shape as ``b``. This method is slower (approximately by a factor of 2) but more stable for floating-point arithmetic than the LUsolve method. However, LUsolve usually uses an exact arithmetic, so you don't need to use QRsolve. This is mainly for educational purposes and symbolic matrices, for real (or complex) matrices use mpmath.qr_solve. See Also ======== sympy.matrices.dense.DenseMatrix.lower_triangular_solve sympy.matrices.dense.DenseMatrix.upper_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LDLsolve LUsolve pinv_solve QRdecomposition """ dps = _get_intermediate_simp(expand_mul, expand_mul) Q, R = M.QRdecomposition() y = Q.T * b # back substitution to solve R*x = y: # We build up the result "backwards" in the vector 'x' and reverse it # only in the end. x = [] n = R.rows for j in range(n - 1, -1, -1): tmp = y[j, :] for k in range(j + 1, n): tmp -= R[j, k] * x[n - 1 - k] tmp = dps(tmp) x.append(tmp / R[j, j]) return M.vstack(*x[::-1]) def _gauss_jordan_solve(M, B, freevar=False): """ Solves ``Ax = B`` using Gauss Jordan elimination. There may be zero, one, or infinite solutions. If one solution exists, it will be returned. If infinite solutions exist, it will be returned parametrically. If no solutions exist, It will throw ValueError. Parameters ========== B : Matrix The right hand side of the equation to be solved for. Must have the same number of rows as matrix A. freevar : boolean, optional Flag, when set to `True` will return the indices of the free variables in the solutions (column Matrix), for a system that is undetermined (e.g. A has more columns than rows), for which infinite solutions are possible, in terms of arbitrary values of free variables. Default `False`. Returns ======= x : Matrix The matrix that will satisfy ``Ax = B``. Will have as many rows as matrix A has columns, and as many columns as matrix B. params : Matrix If the system is underdetermined (e.g. A has more columns than rows), infinite solutions are possible, in terms of arbitrary parameters. These arbitrary parameters are returned as params Matrix. free_var_index : List, optional If the system is underdetermined (e.g. A has more columns than rows), infinite solutions are possible, in terms of arbitrary values of free variables. Then the indices of the free variables in the solutions (column Matrix) are returned by free_var_index, if the flag `freevar` is set to `True`. Examples ======== >>> from sympy import Matrix >>> A = Matrix([[1, 2, 1, 1], [1, 2, 2, -1], [2, 4, 0, 6]]) >>> B = Matrix([7, 12, 4]) >>> sol, params = A.gauss_jordan_solve(B) >>> sol Matrix([ [-2*tau0 - 3*tau1 + 2], [ tau0], [ 2*tau1 + 5], [ tau1]]) >>> params Matrix([ [tau0], [tau1]]) >>> taus_zeroes = { tau:0 for tau in params } >>> sol_unique = sol.xreplace(taus_zeroes) >>> sol_unique Matrix([ [2], [0], [5], [0]]) >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) >>> B = Matrix([3, 6, 9]) >>> sol, params = A.gauss_jordan_solve(B) >>> sol Matrix([ [-1], [ 2], [ 0]]) >>> params Matrix(0, 1, []) >>> A = Matrix([[2, -7], [-1, 4]]) >>> B = Matrix([[-21, 3], [12, -2]]) >>> sol, params = A.gauss_jordan_solve(B) >>> sol Matrix([ [0, -2], [3, -1]]) >>> params Matrix(0, 2, []) >>> from sympy import Matrix >>> A = Matrix([[1, 2, 1, 1], [1, 2, 2, -1], [2, 4, 0, 6]]) >>> B = Matrix([7, 12, 4]) >>> sol, params, freevars = A.gauss_jordan_solve(B, freevar=True) >>> sol Matrix([ [-2*tau0 - 3*tau1 + 2], [ tau0], [ 2*tau1 + 5], [ tau1]]) >>> params Matrix([ [tau0], [tau1]]) >>> freevars [1, 3] See Also ======== sympy.matrices.dense.DenseMatrix.lower_triangular_solve sympy.matrices.dense.DenseMatrix.upper_triangular_solve cholesky_solve diagonal_solve LDLsolve LUsolve QRsolve pinv References ========== .. [1] https://en.wikipedia.org/wiki/Gaussian_elimination """ from sympy.matrices import Matrix, zeros cls = M.__class__ aug = M.hstack(M.copy(), B.copy()) B_cols = B.cols row, col = aug[:, :-B_cols].shape # solve by reduced row echelon form A, pivots = aug.rref(simplify=True) A, v = A[:, :-B_cols], A[:, -B_cols:] pivots = list(filter(lambda p: p < col, pivots)) rank = len(pivots) # Get index of free symbols (free parameters) # non-pivots columns are free variables free_var_index = [c for c in range(A.cols) if c not in pivots] # Bring to block form permutation = Matrix(pivots + free_var_index).T # check for existence of solutions # rank of aug Matrix should be equal to rank of coefficient matrix if not v[rank:, :].is_zero_matrix: raise ValueError("Linear system has no solution") # Free parameters # what are current unnumbered free symbol names? name = uniquely_named_symbol('tau', aug, compare=lambda i: str(i).rstrip('1234567890'), modify=lambda s: '_' + s).name gen = numbered_symbols(name) tau = Matrix([next(gen) for k in range((col - rank)*B_cols)]).reshape( col - rank, B_cols) # Full parametric solution V = A[:rank, free_var_index] vt = v[:rank, :] free_sol = tau.vstack(vt - V * tau, tau) # Undo permutation sol = zeros(col, B_cols) for k in range(col): sol[permutation[k], :] = free_sol[k,:] sol, tau = cls(sol), cls(tau) if freevar: return sol, tau, free_var_index else: return sol, tau def _pinv_solve(M, B, arbitrary_matrix=None): """Solve ``Ax = B`` using the Moore-Penrose pseudoinverse. There may be zero, one, or infinite solutions. If one solution exists, it will be returned. If infinite solutions exist, one will be returned based on the value of arbitrary_matrix. If no solutions exist, the least-squares solution is returned. Parameters ========== B : Matrix The right hand side of the equation to be solved for. Must have the same number of rows as matrix A. arbitrary_matrix : Matrix If the system is underdetermined (e.g. A has more columns than rows), infinite solutions are possible, in terms of an arbitrary matrix. This parameter may be set to a specific matrix to use for that purpose; if so, it must be the same shape as x, with as many rows as matrix A has columns, and as many columns as matrix B. If left as None, an appropriate matrix containing dummy symbols in the form of ``wn_m`` will be used, with n and m being row and column position of each symbol. Returns ======= x : Matrix The matrix that will satisfy ``Ax = B``. Will have as many rows as matrix A has columns, and as many columns as matrix B. Examples ======== >>> from sympy import Matrix >>> A = Matrix([[1, 2, 3], [4, 5, 6]]) >>> B = Matrix([7, 8]) >>> A.pinv_solve(B) Matrix([ [ _w0_0/6 - _w1_0/3 + _w2_0/6 - 55/18], [-_w0_0/3 + 2*_w1_0/3 - _w2_0/3 + 1/9], [ _w0_0/6 - _w1_0/3 + _w2_0/6 + 59/18]]) >>> A.pinv_solve(B, arbitrary_matrix=Matrix([0, 0, 0])) Matrix([ [-55/18], [ 1/9], [ 59/18]]) See Also ======== sympy.matrices.dense.DenseMatrix.lower_triangular_solve sympy.matrices.dense.DenseMatrix.upper_triangular_solve gauss_jordan_solve cholesky_solve diagonal_solve LDLsolve LUsolve QRsolve pinv Notes ===== This may return either exact solutions or least squares solutions. To determine which, check ``A * A.pinv() * B == B``. It will be True if exact solutions exist, and False if only a least-squares solution exists. Be aware that the left hand side of that equation may need to be simplified to correctly compare to the right hand side. References ========== .. [1] https://en.wikipedia.org/wiki/Moore-Penrose_pseudoinverse#Obtaining_all_solutions_of_a_linear_system """ from sympy.matrices import eye A = M A_pinv = M.pinv() if arbitrary_matrix is None: rows, cols = A.cols, B.cols w = symbols('w:{}_:{}'.format(rows, cols), cls=Dummy) arbitrary_matrix = M.__class__(cols, rows, w).T return A_pinv.multiply(B) + (eye(A.cols) - A_pinv.multiply(A)).multiply(arbitrary_matrix) def _solve(M, rhs, method='GJ'): """Solves linear equation where the unique solution exists. Parameters ========== rhs : Matrix Vector representing the right hand side of the linear equation. method : string, optional If set to ``'GJ'`` or ``'GE'``, the Gauss-Jordan elimination will be used, which is implemented in the routine ``gauss_jordan_solve``. If set to ``'LU'``, ``LUsolve`` routine will be used. If set to ``'QR'``, ``QRsolve`` routine will be used. If set to ``'PINV'``, ``pinv_solve`` routine will be used. It also supports the methods available for special linear systems For positive definite systems: If set to ``'CH'``, ``cholesky_solve`` routine will be used. If set to ``'LDL'``, ``LDLsolve`` routine will be used. To use a different method and to compute the solution via the inverse, use a method defined in the .inv() docstring. Returns ======= solutions : Matrix Vector representing the solution. Raises ====== ValueError If there is not a unique solution then a ``ValueError`` will be raised. If ``M`` is not square, a ``ValueError`` and a different routine for solving the system will be suggested. """ if method == 'GJ' or method == 'GE': try: soln, param = M.gauss_jordan_solve(rhs) if param: raise NonInvertibleMatrixError("Matrix det == 0; not invertible. " "Try ``M.gauss_jordan_solve(rhs)`` to obtain a parametric solution.") except ValueError: raise NonInvertibleMatrixError("Matrix det == 0; not invertible.") return soln elif method == 'LU': return M.LUsolve(rhs) elif method == 'CH': return M.cholesky_solve(rhs) elif method == 'QR': return M.QRsolve(rhs) elif method == 'LDL': return M.LDLsolve(rhs) elif method == 'PINV': return M.pinv_solve(rhs) else: return M.inv(method=method).multiply(rhs) def _solve_least_squares(M, rhs, method='CH'): """Return the least-square fit to the data. Parameters ========== rhs : Matrix Vector representing the right hand side of the linear equation. method : string or boolean, optional If set to ``'CH'``, ``cholesky_solve`` routine will be used. If set to ``'LDL'``, ``LDLsolve`` routine will be used. If set to ``'QR'``, ``QRsolve`` routine will be used. If set to ``'PINV'``, ``pinv_solve`` routine will be used. Otherwise, the conjugate of ``M`` will be used to create a system of equations that is passed to ``solve`` along with the hint defined by ``method``. Returns ======= solutions : Matrix Vector representing the solution. Examples ======== >>> from sympy.matrices import Matrix, ones >>> A = Matrix([1, 2, 3]) >>> B = Matrix([2, 3, 4]) >>> S = Matrix(A.row_join(B)) >>> S Matrix([ [1, 2], [2, 3], [3, 4]]) If each line of S represent coefficients of Ax + By and x and y are [2, 3] then S*xy is: >>> r = S*Matrix([2, 3]); r Matrix([ [ 8], [13], [18]]) But let's add 1 to the middle value and then solve for the least-squares value of xy: >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy Matrix([ [ 5/3], [10/3]]) The error is given by S*xy - r: >>> S*xy - r Matrix([ [1/3], [1/3], [1/3]]) >>> _.norm().n(2) 0.58 If a different xy is used, the norm will be higher: >>> xy += ones(2, 1)/10 >>> (S*xy - r).norm().n(2) 1.5 """ if method == 'CH': return M.cholesky_solve(rhs) elif method == 'QR': return M.QRsolve(rhs) elif method == 'LDL': return M.LDLsolve(rhs) elif method == 'PINV': return M.pinv_solve(rhs) else: t = M.H return (t * M).solve(t * rhs, method=method) sympy-sympy-1.9/sympy/matrices/sparse.py000066400000000000000000000343471412543434000205750ustar00rootroot00000000000000from collections.abc import Callable from sympy.core.compatibility import as_int, is_sequence from sympy.core.containers import Dict from sympy.utilities.exceptions import SymPyDeprecationWarning from .matrices import MatrixBase from .repmatrix import MutableRepMatrix, RepMatrix from .utilities import _iszero from .decompositions import ( _liupc, _row_structure_symbolic_cholesky, _cholesky_sparse, _LDLdecomposition_sparse) from .solvers import ( _lower_triangular_solve_sparse, _upper_triangular_solve_sparse) class SparseMatrix(RepMatrix): """ A sparse matrix (a matrix with a large number of zero elements). Examples ======== >>> from sympy.matrices import SparseMatrix, ones >>> SparseMatrix(2, 2, range(4)) Matrix([ [0, 1], [2, 3]]) >>> SparseMatrix(2, 2, {(1, 1): 2}) Matrix([ [0, 0], [0, 2]]) A SparseMatrix can be instantiated from a ragged list of lists: >>> SparseMatrix([[1, 2, 3], [1, 2], [1]]) Matrix([ [1, 2, 3], [1, 2, 0], [1, 0, 0]]) For safety, one may include the expected size and then an error will be raised if the indices of any element are out of range or (for a flat list) if the total number of elements does not match the expected shape: >>> SparseMatrix(2, 2, [1, 2]) Traceback (most recent call last): ... ValueError: List length (2) != rows*columns (4) Here, an error is not raised because the list is not flat and no element is out of range: >>> SparseMatrix(2, 2, [[1, 2]]) Matrix([ [1, 2], [0, 0]]) But adding another element to the first (and only) row will cause an error to be raised: >>> SparseMatrix(2, 2, [[1, 2, 3]]) Traceback (most recent call last): ... ValueError: The location (0, 2) is out of designated range: (1, 1) To autosize the matrix, pass None for rows: >>> SparseMatrix(None, [[1, 2, 3]]) Matrix([[1, 2, 3]]) >>> SparseMatrix(None, {(1, 1): 1, (3, 3): 3}) Matrix([ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 3]]) Values that are themselves a Matrix are automatically expanded: >>> SparseMatrix(4, 4, {(1, 1): ones(2)}) Matrix([ [0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]]) A ValueError is raised if the expanding matrix tries to overwrite a different element already present: >>> SparseMatrix(3, 3, {(0, 0): ones(2), (1, 1): 2}) Traceback (most recent call last): ... ValueError: collision at (1, 1) See Also ======== DenseMatrix MutableSparseMatrix ImmutableSparseMatrix """ @classmethod def _handle_creation_inputs(cls, *args, **kwargs): if len(args) == 1 and isinstance(args[0], MatrixBase): rows = args[0].rows cols = args[0].cols smat = args[0].todok() return rows, cols, smat smat = {} # autosizing if len(args) == 2 and args[0] is None: args = [None, None, args[1]] if len(args) == 3: r, c = args[:2] if r is c is None: rows = cols = None elif None in (r, c): raise ValueError( 'Pass rows=None and no cols for autosizing.') else: rows, cols = as_int(args[0]), as_int(args[1]) if isinstance(args[2], Callable): op = args[2] if None in (rows, cols): raise ValueError( "{} and {} must be integers for this " "specification.".format(rows, cols)) row_indices = [cls._sympify(i) for i in range(rows)] col_indices = [cls._sympify(j) for j in range(cols)] for i in row_indices: for j in col_indices: value = cls._sympify(op(i, j)) if value != cls.zero: smat[i, j] = value return rows, cols, smat elif isinstance(args[2], (dict, Dict)): def update(i, j, v): # update smat and make sure there are no collisions if v: if (i, j) in smat and v != smat[i, j]: raise ValueError( "There is a collision at {} for {} and {}." .format((i, j), v, smat[i, j]) ) smat[i, j] = v # manual copy, copy.deepcopy() doesn't work for (r, c), v in args[2].items(): if isinstance(v, MatrixBase): for (i, j), vv in v.todok().items(): update(r + i, c + j, vv) elif isinstance(v, (list, tuple)): _, _, smat = cls._handle_creation_inputs(v, **kwargs) for i, j in smat: update(r + i, c + j, smat[i, j]) else: v = cls._sympify(v) update(r, c, cls._sympify(v)) elif is_sequence(args[2]): flat = not any(is_sequence(i) for i in args[2]) if not flat: _, _, smat = \ cls._handle_creation_inputs(args[2], **kwargs) else: flat_list = args[2] if len(flat_list) != rows * cols: raise ValueError( "The length of the flat list ({}) does not " "match the specified size ({} * {})." .format(len(flat_list), rows, cols) ) for i in range(rows): for j in range(cols): value = flat_list[i*cols + j] value = cls._sympify(value) if value != cls.zero: smat[i, j] = value if rows is None: # autosizing keys = smat.keys() rows = max([r for r, _ in keys]) + 1 if keys else 0 cols = max([c for _, c in keys]) + 1 if keys else 0 else: for i, j in smat.keys(): if i and i >= rows or j and j >= cols: raise ValueError( "The location {} is out of the designated range" "[{}, {}]x[{}, {}]" .format((i, j), 0, rows - 1, 0, cols - 1) ) return rows, cols, smat elif len(args) == 1 and isinstance(args[0], (list, tuple)): # list of values or lists v = args[0] c = 0 for i, row in enumerate(v): if not isinstance(row, (list, tuple)): row = [row] for j, vv in enumerate(row): if vv != cls.zero: smat[i, j] = cls._sympify(vv) c = max(c, len(row)) rows = len(v) if c else 0 cols = c return rows, cols, smat else: # handle full matrix forms with _handle_creation_inputs rows, cols, mat = super()._handle_creation_inputs(*args) for i in range(rows): for j in range(cols): value = mat[cols*i + j] if value != cls.zero: smat[i, j] = value return rows, cols, smat @property def _smat(self): SymPyDeprecationWarning( feature="The private _smat attribute of SparseMatrix", useinstead="the .todok() method", issue=21715, deprecated_since_version="1.9").warn() return self.todok() def _eval_inverse(self, **kwargs): return self.inv(method=kwargs.get('method', 'LDL'), iszerofunc=kwargs.get('iszerofunc', _iszero), try_block_diag=kwargs.get('try_block_diag', False)) def applyfunc(self, f): """Apply a function to each element of the matrix. Examples ======== >>> from sympy.matrices import SparseMatrix >>> m = SparseMatrix(2, 2, lambda i, j: i*2+j) >>> m Matrix([ [0, 1], [2, 3]]) >>> m.applyfunc(lambda i: 2*i) Matrix([ [0, 2], [4, 6]]) """ if not callable(f): raise TypeError("`f` must be callable.") # XXX: This only applies the function to the nonzero elements of the # matrix so is inconsistent with DenseMatrix.applyfunc e.g. # zeros(2, 2).applyfunc(lambda x: x + 1) dok = {} for k, v in self.todok().items(): fv = f(v) if fv != 0: dok[k] = fv return self._new(self.rows, self.cols, dok) def as_immutable(self): """Returns an Immutable version of this Matrix.""" from .immutable import ImmutableSparseMatrix return ImmutableSparseMatrix(self) def as_mutable(self): """Returns a mutable version of this matrix. Examples ======== >>> from sympy import ImmutableMatrix >>> X = ImmutableMatrix([[1, 2], [3, 4]]) >>> Y = X.as_mutable() >>> Y[1, 1] = 5 # Can set values in Y >>> Y Matrix([ [1, 2], [3, 5]]) """ return MutableSparseMatrix(self) def col_list(self): """Returns a column-sorted list of non-zero elements of the matrix. Examples ======== >>> from sympy.matrices import SparseMatrix >>> a=SparseMatrix(((1, 2), (3, 4))) >>> a Matrix([ [1, 2], [3, 4]]) >>> a.CL [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)] See Also ======== sympy.matrices.sparse.SparseMatrix.row_list """ return [tuple(k + (self[k],)) for k in sorted(list(self.todok().keys()), key=lambda k: list(reversed(k)))] def nnz(self): """Returns the number of non-zero elements in Matrix.""" return len(self.todok()) def row_list(self): """Returns a row-sorted list of non-zero elements of the matrix. Examples ======== >>> from sympy.matrices import SparseMatrix >>> a = SparseMatrix(((1, 2), (3, 4))) >>> a Matrix([ [1, 2], [3, 4]]) >>> a.RL [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] See Also ======== sympy.matrices.sparse.SparseMatrix.col_list """ return [tuple(k + (self[k],)) for k in sorted(self.todok().keys(), key=lambda k: list(k))] def scalar_multiply(self, scalar): "Scalar element-wise multiplication" return scalar * self def solve_least_squares(self, rhs, method='LDL'): """Return the least-square fit to the data. By default the cholesky_solve routine is used (method='CH'); other methods of matrix inversion can be used. To find out which are available, see the docstring of the .inv() method. Examples ======== >>> from sympy.matrices import SparseMatrix, Matrix, ones >>> A = Matrix([1, 2, 3]) >>> B = Matrix([2, 3, 4]) >>> S = SparseMatrix(A.row_join(B)) >>> S Matrix([ [1, 2], [2, 3], [3, 4]]) If each line of S represent coefficients of Ax + By and x and y are [2, 3] then S*xy is: >>> r = S*Matrix([2, 3]); r Matrix([ [ 8], [13], [18]]) But let's add 1 to the middle value and then solve for the least-squares value of xy: >>> xy = S.solve_least_squares(Matrix([8, 14, 18])); xy Matrix([ [ 5/3], [10/3]]) The error is given by S*xy - r: >>> S*xy - r Matrix([ [1/3], [1/3], [1/3]]) >>> _.norm().n(2) 0.58 If a different xy is used, the norm will be higher: >>> xy += ones(2, 1)/10 >>> (S*xy - r).norm().n(2) 1.5 """ t = self.T return (t*self).inv(method=method)*t*rhs def solve(self, rhs, method='LDL'): """Return solution to self*soln = rhs using given inversion method. For a list of possible inversion methods, see the .inv() docstring. """ if not self.is_square: if self.rows < self.cols: raise ValueError('Under-determined system.') elif self.rows > self.cols: raise ValueError('For over-determined system, M, having ' 'more rows than columns, try M.solve_least_squares(rhs).') else: return self.inv(method=method).multiply(rhs) RL = property(row_list, None, None, "Alternate faster representation") CL = property(col_list, None, None, "Alternate faster representation") def liupc(self): return _liupc(self) def row_structure_symbolic_cholesky(self): return _row_structure_symbolic_cholesky(self) def cholesky(self, hermitian=True): return _cholesky_sparse(self, hermitian=hermitian) def LDLdecomposition(self, hermitian=True): return _LDLdecomposition_sparse(self, hermitian=hermitian) def lower_triangular_solve(self, rhs): return _lower_triangular_solve_sparse(self, rhs) def upper_triangular_solve(self, rhs): return _upper_triangular_solve_sparse(self, rhs) liupc.__doc__ = _liupc.__doc__ row_structure_symbolic_cholesky.__doc__ = _row_structure_symbolic_cholesky.__doc__ cholesky.__doc__ = _cholesky_sparse.__doc__ LDLdecomposition.__doc__ = _LDLdecomposition_sparse.__doc__ lower_triangular_solve.__doc__ = lower_triangular_solve.__doc__ upper_triangular_solve.__doc__ = upper_triangular_solve.__doc__ class MutableSparseMatrix(SparseMatrix, MutableRepMatrix): @classmethod def _new(cls, *args, **kwargs): rows, cols, smat = cls._handle_creation_inputs(*args, **kwargs) rep = cls._smat_to_DomainMatrix(rows, cols, smat) return cls._fromrep(rep) sympy-sympy-1.9/sympy/matrices/sparsetools.py000066400000000000000000000217361412543434000216540ustar00rootroot00000000000000from sympy.core.compatibility import as_int from sympy.utilities.iterables import is_sequence from sympy.utilities.misc import filldedent from .sparse import MutableSparseMatrix def _doktocsr(dok): """Converts a sparse matrix to Compressed Sparse Row (CSR) format. Parameters ========== A : contains non-zero elements sorted by key (row, column) JA : JA[i] is the column corresponding to A[i] IA : IA[i] contains the index in A for the first non-zero element of row[i]. Thus IA[i+1] - IA[i] gives number of non-zero elements row[i]. The length of IA is always 1 more than the number of rows in the matrix. Examples ======== >>> from sympy.matrices.sparsetools import _doktocsr >>> from sympy import SparseMatrix, diag >>> m = SparseMatrix(diag(1, 2, 3)) >>> m[2, 0] = -1 >>> _doktocsr(m) [[1, 2, -1, 3], [0, 1, 0, 2], [0, 1, 2, 4], [3, 3]] """ row, JA, A = [list(i) for i in zip(*dok.row_list())] IA = [0]*((row[0] if row else 0) + 1) for i, r in enumerate(row): IA.extend([i]*(r - row[i - 1])) # if i = 0 nothing is extended IA.extend([len(A)]*(dok.rows - len(IA) + 1)) shape = [dok.rows, dok.cols] return [A, JA, IA, shape] def _csrtodok(csr): """Converts a CSR representation to DOK representation. Examples ======== >>> from sympy.matrices.sparsetools import _csrtodok >>> _csrtodok([[5, 8, 3, 6], [0, 1, 2, 1], [0, 0, 2, 3, 4], [4, 3]]) Matrix([ [0, 0, 0], [5, 8, 0], [0, 0, 3], [0, 6, 0]]) """ smat = {} A, JA, IA, shape = csr for i in range(len(IA) - 1): indices = slice(IA[i], IA[i + 1]) for l, m in zip(A[indices], JA[indices]): smat[i, m] = l return MutableSparseMatrix(*shape, smat) def banded(*args, **kwargs): """Returns a SparseMatrix from the given dictionary describing the diagonals of the matrix. The keys are positive for upper diagonals and negative for those below the main diagonal. The values may be: * expressions or single-argument functions, * lists or tuples of values, * matrices Unless dimensions are given, the size of the returned matrix will be large enough to contain the largest non-zero value provided. kwargs ====== rows : rows of the resulting matrix; computed if not given. cols : columns of the resulting matrix; computed if not given. Examples ======== >>> from sympy import banded, ones, Matrix >>> from sympy.abc import x If explicit values are given in tuples, the matrix will autosize to contain all values, otherwise a single value is filled onto the entire diagonal: >>> banded({1: (1, 2, 3), -1: (4, 5, 6), 0: x}) Matrix([ [x, 1, 0, 0], [4, x, 2, 0], [0, 5, x, 3], [0, 0, 6, x]]) A function accepting a single argument can be used to fill the diagonal as a function of diagonal index (which starts at 0). The size (or shape) of the matrix must be given to obtain more than a 1x1 matrix: >>> s = lambda d: (1 + d)**2 >>> banded(5, {0: s, 2: s, -2: 2}) Matrix([ [1, 0, 1, 0, 0], [0, 4, 0, 4, 0], [2, 0, 9, 0, 9], [0, 2, 0, 16, 0], [0, 0, 2, 0, 25]]) The diagonal of matrices placed on a diagonal will coincide with the indicated diagonal: >>> vert = Matrix([1, 2, 3]) >>> banded({0: vert}, cols=3) Matrix([ [1, 0, 0], [2, 1, 0], [3, 2, 1], [0, 3, 2], [0, 0, 3]]) >>> banded(4, {0: ones(2)}) Matrix([ [1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1], [0, 0, 1, 1]]) Errors are raised if the designated size will not hold all values an integral number of times. Here, the rows are designated as odd (but an even number is required to hold the off-diagonal 2x2 ones): >>> banded({0: 2, 1: ones(2)}, rows=5) Traceback (most recent call last): ... ValueError: sequence does not fit an integral number of times in the matrix And here, an even number of rows is given...but the square matrix has an even number of columns, too. As we saw in the previous example, an odd number is required: >>> banded(4, {0: 2, 1: ones(2)}) # trying to make 4x4 and cols must be odd Traceback (most recent call last): ... ValueError: sequence does not fit an integral number of times in the matrix A way around having to count rows is to enclosing matrix elements in a tuple and indicate the desired number of them to the right: >>> banded({0: 2, 2: (ones(2),)*3}) Matrix([ [2, 0, 1, 1, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 0, 0], [0, 0, 2, 0, 1, 1, 0, 0], [0, 0, 0, 2, 1, 1, 0, 0], [0, 0, 0, 0, 2, 0, 1, 1], [0, 0, 0, 0, 0, 2, 1, 1]]) An error will be raised if more than one value is written to a given entry. Here, the ones overlap with the main diagonal if they are placed on the first diagonal: >>> banded({0: (2,)*5, 1: (ones(2),)*3}) Traceback (most recent call last): ... ValueError: collision at (1, 1) By placing a 0 at the bottom left of the 2x2 matrix of ones, the collision is avoided: >>> u2 = Matrix([ ... [1, 1], ... [0, 1]]) >>> banded({0: [2]*5, 1: [u2]*3}) Matrix([ [2, 1, 1, 0, 0, 0, 0], [0, 2, 1, 0, 0, 0, 0], [0, 0, 2, 1, 1, 0, 0], [0, 0, 0, 2, 1, 0, 0], [0, 0, 0, 0, 2, 1, 1], [0, 0, 0, 0, 0, 0, 1]]) """ from sympy import Dict, Dummy, SparseMatrix try: if len(args) not in (1, 2, 3): raise TypeError if not isinstance(args[-1], (dict, Dict)): raise TypeError if len(args) == 1: rows = kwargs.get('rows', None) cols = kwargs.get('cols', None) if rows is not None: rows = as_int(rows) if cols is not None: cols = as_int(cols) elif len(args) == 2: rows = cols = as_int(args[0]) else: rows, cols = map(as_int, args[:2]) # fails with ValueError if any keys are not ints _ = all(as_int(k) for k in args[-1]) except (ValueError, TypeError): raise TypeError(filldedent( '''unrecognized input to banded: expecting [[row,] col,] {int: value}''')) def rc(d): # return row,col coord of diagonal start r = -d if d < 0 else 0 c = 0 if r else d return r, c smat = {} undone = [] tba = Dummy() # first handle objects with size for d, v in args[-1].items(): r, c = rc(d) # note: only list and tuple are recognized since this # will allow other Basic objects like Tuple # into the matrix if so desired if isinstance(v, (list, tuple)): extra = 0 for i, vi in enumerate(v): i += extra if is_sequence(vi): vi = SparseMatrix(vi) smat[r + i, c + i] = vi extra += min(vi.shape) - 1 else: smat[r + i, c + i] = vi elif is_sequence(v): v = SparseMatrix(v) rv, cv = v.shape if rows and cols: nr, xr = divmod(rows - r, rv) nc, xc = divmod(cols - c, cv) x = xr or xc do = min(nr, nc) elif rows: do, x = divmod(rows - r, rv) elif cols: do, x = divmod(cols - c, cv) else: do = 1 x = 0 if x: raise ValueError(filldedent(''' sequence does not fit an integral number of times in the matrix''')) j = min(v.shape) for i in range(do): smat[r, c] = v r += j c += j elif v: smat[r, c] = tba undone.append((d, v)) s = SparseMatrix(None, smat) # to expand matrices smat = s.todok() # check for dim errors here if rows is not None and rows < s.rows: raise ValueError('Designated rows %s < needed %s' % (rows, s.rows)) if cols is not None and cols < s.cols: raise ValueError('Designated cols %s < needed %s' % (cols, s.cols)) if rows is cols is None: rows = s.rows cols = s.cols elif rows is not None and cols is None: cols = max(rows, s.cols) elif cols is not None and rows is None: rows = max(cols, s.rows) def update(i, j, v): # update smat and make sure there are # no collisions if v: if (i, j) in smat and smat[i, j] not in (tba, v): raise ValueError('collision at %s' % ((i, j),)) smat[i, j] = v if undone: for d, vi in undone: r, c = rc(d) v = vi if callable(vi) else lambda _: vi i = 0 while r + i < rows and c + i < cols: update(r + i, c + i, v(i)) i += 1 return SparseMatrix(rows, cols, smat) sympy-sympy-1.9/sympy/matrices/subspaces.py000066400000000000000000000073031412543434000212600ustar00rootroot00000000000000from .utilities import _iszero def _columnspace(M, simplify=False): """Returns a list of vectors (Matrix objects) that span columnspace of ``M`` Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6]) >>> M Matrix([ [ 1, 3, 0], [-2, -6, 0], [ 3, 9, 6]]) >>> M.columnspace() [Matrix([ [ 1], [-2], [ 3]]), Matrix([ [0], [0], [6]])] See Also ======== nullspace rowspace """ reduced, pivots = M.echelon_form(simplify=simplify, with_pivots=True) return [M.col(i) for i in pivots] def _nullspace(M, simplify=False, iszerofunc=_iszero): """Returns list of vectors (Matrix objects) that span nullspace of ``M`` Examples ======== >>> from sympy.matrices import Matrix >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6]) >>> M Matrix([ [ 1, 3, 0], [-2, -6, 0], [ 3, 9, 6]]) >>> M.nullspace() [Matrix([ [-3], [ 1], [ 0]])] See Also ======== columnspace rowspace """ reduced, pivots = M.rref(iszerofunc=iszerofunc, simplify=simplify) free_vars = [i for i in range(M.cols) if i not in pivots] basis = [] for free_var in free_vars: # for each free variable, we will set it to 1 and all others # to 0. Then, we will use back substitution to solve the system vec = [M.zero] * M.cols vec[free_var] = M.one for piv_row, piv_col in enumerate(pivots): vec[piv_col] -= reduced[piv_row, free_var] basis.append(vec) return [M._new(M.cols, 1, b) for b in basis] def _rowspace(M, simplify=False): """Returns a list of vectors that span the row space of ``M``. Examples ======== >>> from sympy import Matrix >>> M = Matrix(3, 3, [1, 3, 0, -2, -6, 0, 3, 9, 6]) >>> M Matrix([ [ 1, 3, 0], [-2, -6, 0], [ 3, 9, 6]]) >>> M.rowspace() [Matrix([[1, 3, 0]]), Matrix([[0, 0, 6]])] """ reduced, pivots = M.echelon_form(simplify=simplify, with_pivots=True) return [reduced.row(i) for i in range(len(pivots))] def _orthogonalize(cls, *vecs, normalize=False, rankcheck=False): """Apply the Gram-Schmidt orthogonalization procedure to vectors supplied in ``vecs``. Parameters ========== vecs vectors to be made orthogonal normalize : bool If ``True``, return an orthonormal basis. rankcheck : bool If ``True``, the computation does not stop when encountering linearly dependent vectors. If ``False``, it will raise ``ValueError`` when any zero or linearly dependent vectors are found. Returns ======= list List of orthogonal (or orthonormal) basis vectors. Examples ======== >>> from sympy import I, Matrix >>> v = [Matrix([1, I]), Matrix([1, -I])] >>> Matrix.orthogonalize(*v) [Matrix([ [1], [I]]), Matrix([ [ 1], [-I]])] See Also ======== MatrixBase.QRdecomposition References ========== .. [1] https://en.wikipedia.org/wiki/Gram%E2%80%93Schmidt_process """ from .decompositions import _QRdecomposition_optional if not vecs: return [] all_row_vecs = (vecs[0].rows == 1) vecs = [x.vec() for x in vecs] M = cls.hstack(*vecs) Q, R = _QRdecomposition_optional(M, normalize=normalize) if rankcheck and Q.cols < len(vecs): raise ValueError("GramSchmidt: vector set not linearly independent") ret = [] for i in range(Q.cols): if all_row_vecs: col = cls(Q[:, i].T) else: col = cls(Q[:, i]) ret.append(col) return ret sympy-sympy-1.9/sympy/matrices/tests/000077500000000000000000000000001412543434000200555ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/tests/__init__.py000066400000000000000000000000001412543434000221540ustar00rootroot00000000000000sympy-sympy-1.9/sympy/matrices/tests/test_commonmatrix.py000066400000000000000000001136341412543434000242130ustar00rootroot00000000000000from sympy.assumptions import Q from sympy.core.expr import Expr from sympy.core.add import Add from sympy.core.function import Function from sympy.core.kind import NumberKind, UndefinedKind from sympy.core.numbers import I, Integer, oo, pi, Rational from sympy.core.singleton import S from sympy.core.symbol import Symbol, symbols from sympy.functions.elementary.complexes import Abs from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import cos, sin from sympy.matrices.common import (ShapeError, NonSquareMatrixError, _MinimalMatrix, _CastableMatrix, MatrixShaping, MatrixProperties, MatrixOperations, MatrixArithmetic, MatrixSpecial, MatrixKind) from sympy.matrices.matrices import MatrixCalculus from sympy.matrices import (Matrix, diag, eye, matrix_multiply_elementwise, ones, zeros, SparseMatrix, banded, MutableDenseMatrix, MutableSparseMatrix, ImmutableDenseMatrix, ImmutableSparseMatrix) from sympy.polys.polytools import Poly from sympy.utilities.iterables import flatten from sympy.testing.pytest import raises, XFAIL, warns_deprecated_sympy from sympy import Array from sympy.abc import x, y, z # classes to test the basic matrix classes class ShapingOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixShaping): pass def eye_Shaping(n): return ShapingOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Shaping(n): return ShapingOnlyMatrix(n, n, lambda i, j: 0) class PropertiesOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixProperties): pass def eye_Properties(n): return PropertiesOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Properties(n): return PropertiesOnlyMatrix(n, n, lambda i, j: 0) class OperationsOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixOperations): pass def eye_Operations(n): return OperationsOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Operations(n): return OperationsOnlyMatrix(n, n, lambda i, j: 0) class ArithmeticOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixArithmetic): pass def eye_Arithmetic(n): return ArithmeticOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Arithmetic(n): return ArithmeticOnlyMatrix(n, n, lambda i, j: 0) class SpecialOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixSpecial): pass class CalculusOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixCalculus): pass def test__MinimalMatrix(): x = _MinimalMatrix(2, 3, [1, 2, 3, 4, 5, 6]) assert x.rows == 2 assert x.cols == 3 assert x[2] == 3 assert x[1, 1] == 5 assert list(x) == [1, 2, 3, 4, 5, 6] assert list(x[1, :]) == [4, 5, 6] assert list(x[:, 1]) == [2, 5] assert list(x[:, :]) == list(x) assert x[:, :] == x assert _MinimalMatrix(x) == x assert _MinimalMatrix([[1, 2, 3], [4, 5, 6]]) == x assert _MinimalMatrix(([1, 2, 3], [4, 5, 6])) == x assert _MinimalMatrix([(1, 2, 3), (4, 5, 6)]) == x assert _MinimalMatrix(((1, 2, 3), (4, 5, 6))) == x assert not (_MinimalMatrix([[1, 2], [3, 4], [5, 6]]) == x) def test_kind(): assert Matrix([[1, 2], [3, 4]]).kind == MatrixKind(NumberKind) assert Matrix([[0, 0], [0, 0]]).kind == MatrixKind(NumberKind) assert Matrix(0, 0, []).kind == MatrixKind(NumberKind) assert Matrix([[x]]).kind == MatrixKind(NumberKind) assert Matrix([[1, Matrix([[1]])]]).kind == MatrixKind(UndefinedKind) assert SparseMatrix([[1]]).kind == MatrixKind(NumberKind) assert SparseMatrix([[1, Matrix([[1]])]]).kind == MatrixKind(UndefinedKind) # ShapingOnlyMatrix tests def test_vec(): m = ShapingOnlyMatrix(2, 2, [1, 3, 2, 4]) m_vec = m.vec() assert m_vec.cols == 1 for i in range(4): assert m_vec[i] == i + 1 def test_todok(): a, b, c, d = symbols('a:d') m1 = MutableDenseMatrix([[a, b], [c, d]]) m2 = ImmutableDenseMatrix([[a, b], [c, d]]) m3 = MutableSparseMatrix([[a, b], [c, d]]) m4 = ImmutableSparseMatrix([[a, b], [c, d]]) assert m1.todok() == m2.todok() == m3.todok() == m4.todok() == \ {(0, 0): a, (0, 1): b, (1, 0): c, (1, 1): d} def test_tolist(): lst = [[S.One, S.Half, x*y, S.Zero], [x, y, z, x**2], [y, -S.One, z*x, 3]] flat_lst = [S.One, S.Half, x*y, S.Zero, x, y, z, x**2, y, -S.One, z*x, 3] m = ShapingOnlyMatrix(3, 4, flat_lst) assert m.tolist() == lst def test_todod(): m = ShapingOnlyMatrix(3, 2, [[S.One, 0], [0, S.Half], [x, 0]]) dict = {0: {0: S.One}, 1: {1: S.Half}, 2: {0: x}} assert m.todod() == dict def test_row_col_del(): e = ShapingOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) raises(IndexError, lambda: e.row_del(5)) raises(IndexError, lambda: e.row_del(-5)) raises(IndexError, lambda: e.col_del(5)) raises(IndexError, lambda: e.col_del(-5)) assert e.row_del(2) == e.row_del(-1) == Matrix([[1, 2, 3], [4, 5, 6]]) assert e.col_del(2) == e.col_del(-1) == Matrix([[1, 2], [4, 5], [7, 8]]) assert e.row_del(1) == e.row_del(-2) == Matrix([[1, 2, 3], [7, 8, 9]]) assert e.col_del(1) == e.col_del(-2) == Matrix([[1, 3], [4, 6], [7, 9]]) def test_get_diag_blocks1(): a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) assert a.get_diag_blocks() == [a] assert b.get_diag_blocks() == [b] assert c.get_diag_blocks() == [c] def test_get_diag_blocks2(): a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) A, B, C, D = diag(a, b, b), diag(a, b, c), diag(a, c, b), diag(c, c, b) A = ShapingOnlyMatrix(A.rows, A.cols, A) B = ShapingOnlyMatrix(B.rows, B.cols, B) C = ShapingOnlyMatrix(C.rows, C.cols, C) D = ShapingOnlyMatrix(D.rows, D.cols, D) assert A.get_diag_blocks() == [a, b, b] assert B.get_diag_blocks() == [a, b, c] assert C.get_diag_blocks() == [a, c, b] assert D.get_diag_blocks() == [c, c, b] def test_shape(): m = ShapingOnlyMatrix(1, 2, [0, 0]) m.shape == (1, 2) def test_reshape(): m0 = eye_Shaping(3) assert m0.reshape(1, 9) == Matrix(1, 9, (1, 0, 0, 0, 1, 0, 0, 0, 1)) m1 = ShapingOnlyMatrix(3, 4, lambda i, j: i + j) assert m1.reshape( 4, 3) == Matrix(((0, 1, 2), (3, 1, 2), (3, 4, 2), (3, 4, 5))) assert m1.reshape(2, 6) == Matrix(((0, 1, 2, 3, 1, 2), (3, 4, 2, 3, 4, 5))) def test_row_col(): m = ShapingOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) assert m.row(0) == Matrix(1, 3, [1, 2, 3]) assert m.col(0) == Matrix(3, 1, [1, 4, 7]) def test_row_join(): assert eye_Shaping(3).row_join(Matrix([7, 7, 7])) == \ Matrix([[1, 0, 0, 7], [0, 1, 0, 7], [0, 0, 1, 7]]) def test_col_join(): assert eye_Shaping(3).col_join(Matrix([[7, 7, 7]])) == \ Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1], [7, 7, 7]]) def test_row_insert(): r4 = Matrix([[4, 4, 4]]) for i in range(-4, 5): l = [1, 0, 0] l.insert(i, 4) assert flatten(eye_Shaping(3).row_insert(i, r4).col(0).tolist()) == l def test_col_insert(): c4 = Matrix([4, 4, 4]) for i in range(-4, 5): l = [0, 0, 0] l.insert(i, 4) assert flatten(zeros_Shaping(3).col_insert(i, c4).row(0).tolist()) == l # issue 13643 assert eye_Shaping(6).col_insert(3, Matrix([[2, 2], [2, 2], [2, 2], [2, 2], [2, 2], [2, 2]])) == \ Matrix([[1, 0, 0, 2, 2, 0, 0, 0], [0, 1, 0, 2, 2, 0, 0, 0], [0, 0, 1, 2, 2, 0, 0, 0], [0, 0, 0, 2, 2, 1, 0, 0], [0, 0, 0, 2, 2, 0, 1, 0], [0, 0, 0, 2, 2, 0, 0, 1]]) def test_extract(): m = ShapingOnlyMatrix(4, 3, lambda i, j: i*3 + j) assert m.extract([0, 1, 3], [0, 1]) == Matrix(3, 2, [0, 1, 3, 4, 9, 10]) assert m.extract([0, 3], [0, 0, 2]) == Matrix(2, 3, [0, 0, 2, 9, 9, 11]) assert m.extract(range(4), range(3)) == m raises(IndexError, lambda: m.extract([4], [0])) raises(IndexError, lambda: m.extract([0], [3])) def test_hstack(): m = ShapingOnlyMatrix(4, 3, lambda i, j: i*3 + j) m2 = ShapingOnlyMatrix(3, 4, lambda i, j: i*3 + j) assert m == m.hstack(m) assert m.hstack(m, m, m) == ShapingOnlyMatrix.hstack(m, m, m) == Matrix([ [0, 1, 2, 0, 1, 2, 0, 1, 2], [3, 4, 5, 3, 4, 5, 3, 4, 5], [6, 7, 8, 6, 7, 8, 6, 7, 8], [9, 10, 11, 9, 10, 11, 9, 10, 11]]) raises(ShapeError, lambda: m.hstack(m, m2)) assert Matrix.hstack() == Matrix() # test regression #12938 M1 = Matrix.zeros(0, 0) M2 = Matrix.zeros(0, 1) M3 = Matrix.zeros(0, 2) M4 = Matrix.zeros(0, 3) m = ShapingOnlyMatrix.hstack(M1, M2, M3, M4) assert m.rows == 0 and m.cols == 6 def test_vstack(): m = ShapingOnlyMatrix(4, 3, lambda i, j: i*3 + j) m2 = ShapingOnlyMatrix(3, 4, lambda i, j: i*3 + j) assert m == m.vstack(m) assert m.vstack(m, m, m) == ShapingOnlyMatrix.vstack(m, m, m) == Matrix([ [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]) raises(ShapeError, lambda: m.vstack(m, m2)) assert Matrix.vstack() == Matrix() # PropertiesOnlyMatrix tests def test_atoms(): m = PropertiesOnlyMatrix(2, 2, [1, 2, x, 1 - 1/x]) assert m.atoms() == {S.One, S(2), S.NegativeOne, x} assert m.atoms(Symbol) == {x} def test_free_symbols(): assert PropertiesOnlyMatrix([[x], [0]]).free_symbols == {x} def test_has(): A = PropertiesOnlyMatrix(((x, y), (2, 3))) assert A.has(x) assert not A.has(z) assert A.has(Symbol) A = PropertiesOnlyMatrix(((2, y), (2, 3))) assert not A.has(x) def test_is_anti_symmetric(): x = symbols('x') assert PropertiesOnlyMatrix(2, 1, [1, 2]).is_anti_symmetric() is False m = PropertiesOnlyMatrix(3, 3, [0, x**2 + 2*x + 1, y, -(x + 1)**2, 0, x*y, -y, -x*y, 0]) assert m.is_anti_symmetric() is True assert m.is_anti_symmetric(simplify=False) is False assert m.is_anti_symmetric(simplify=lambda x: x) is False m = PropertiesOnlyMatrix(3, 3, [x.expand() for x in m]) assert m.is_anti_symmetric(simplify=False) is True m = PropertiesOnlyMatrix(3, 3, [x.expand() for x in [S.One] + list(m)[1:]]) assert m.is_anti_symmetric() is False def test_diagonal_symmetrical(): m = PropertiesOnlyMatrix(2, 2, [0, 1, 1, 0]) assert not m.is_diagonal() assert m.is_symmetric() assert m.is_symmetric(simplify=False) m = PropertiesOnlyMatrix(2, 2, [1, 0, 0, 1]) assert m.is_diagonal() m = PropertiesOnlyMatrix(3, 3, diag(1, 2, 3)) assert m.is_diagonal() assert m.is_symmetric() m = PropertiesOnlyMatrix(3, 3, [1, 0, 0, 0, 2, 0, 0, 0, 3]) assert m == diag(1, 2, 3) m = PropertiesOnlyMatrix(2, 3, zeros(2, 3)) assert not m.is_symmetric() assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0), (0, 6), (0, 0))) assert m.is_diagonal() m = PropertiesOnlyMatrix(((5, 0, 0), (0, 6, 0))) assert m.is_diagonal() m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) assert m.is_symmetric() assert not m.is_symmetric(simplify=False) assert m.expand().is_symmetric(simplify=False) def test_is_hermitian(): a = PropertiesOnlyMatrix([[1, I], [-I, 1]]) assert a.is_hermitian a = PropertiesOnlyMatrix([[2*I, I], [-I, 1]]) assert a.is_hermitian is False a = PropertiesOnlyMatrix([[x, I], [-I, 1]]) assert a.is_hermitian is None a = PropertiesOnlyMatrix([[x, 1], [-I, 1]]) assert a.is_hermitian is False def test_is_Identity(): assert eye_Properties(3).is_Identity assert not PropertiesOnlyMatrix(zeros(3)).is_Identity assert not PropertiesOnlyMatrix(ones(3)).is_Identity # issue 6242 assert not PropertiesOnlyMatrix([[1, 0, 0]]).is_Identity def test_is_symbolic(): a = PropertiesOnlyMatrix([[x, x], [x, x]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1, 2, 3, 4], [5, 6, 7, 8]]) assert a.is_symbolic() is False a = PropertiesOnlyMatrix([[1, 2, 3, 4], [5, 6, x, 8]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1, x, 3]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1, 2, 3]]) assert a.is_symbolic() is False a = PropertiesOnlyMatrix([[1], [x], [3]]) assert a.is_symbolic() is True a = PropertiesOnlyMatrix([[1], [2], [3]]) assert a.is_symbolic() is False def test_is_upper(): a = PropertiesOnlyMatrix([[1, 2, 3]]) assert a.is_upper is True a = PropertiesOnlyMatrix([[1], [2], [3]]) assert a.is_upper is False def test_is_lower(): a = PropertiesOnlyMatrix([[1, 2, 3]]) assert a.is_lower is False a = PropertiesOnlyMatrix([[1], [2], [3]]) assert a.is_lower is True def test_is_square(): m = PropertiesOnlyMatrix([[1], [1]]) m2 = PropertiesOnlyMatrix([[2, 2], [2, 2]]) assert not m.is_square assert m2.is_square def test_is_symmetric(): m = PropertiesOnlyMatrix(2, 2, [0, 1, 1, 0]) assert m.is_symmetric() m = PropertiesOnlyMatrix(2, 2, [0, 1, 0, 1]) assert not m.is_symmetric() def test_is_hessenberg(): A = PropertiesOnlyMatrix([[3, 4, 1], [2, 4, 5], [0, 1, 2]]) assert A.is_upper_hessenberg A = PropertiesOnlyMatrix(3, 3, [3, 2, 0, 4, 4, 1, 1, 5, 2]) assert A.is_lower_hessenberg A = PropertiesOnlyMatrix(3, 3, [3, 2, -1, 4, 4, 1, 1, 5, 2]) assert A.is_lower_hessenberg is False assert A.is_upper_hessenberg is False A = PropertiesOnlyMatrix([[3, 4, 1], [2, 4, 5], [3, 1, 2]]) assert not A.is_upper_hessenberg def test_is_zero(): assert PropertiesOnlyMatrix(0, 0, []).is_zero_matrix assert PropertiesOnlyMatrix([[0, 0], [0, 0]]).is_zero_matrix assert PropertiesOnlyMatrix(zeros(3, 4)).is_zero_matrix assert not PropertiesOnlyMatrix(eye(3)).is_zero_matrix assert PropertiesOnlyMatrix([[x, 0], [0, 0]]).is_zero_matrix == None assert PropertiesOnlyMatrix([[x, 1], [0, 0]]).is_zero_matrix == False a = Symbol('a', nonzero=True) assert PropertiesOnlyMatrix([[a, 0], [0, 0]]).is_zero_matrix == False def test_values(): assert set(PropertiesOnlyMatrix(2, 2, [0, 1, 2, 3] ).values()) == {1, 2, 3} x = Symbol('x', real=True) assert set(PropertiesOnlyMatrix(2, 2, [x, 0, 0, 1] ).values()) == {x, 1} # OperationsOnlyMatrix tests def test_applyfunc(): m0 = OperationsOnlyMatrix(eye(3)) assert m0.applyfunc(lambda x: 2*x) == eye(3)*2 assert m0.applyfunc(lambda x: 0) == zeros(3) assert m0.applyfunc(lambda x: 1) == ones(3) def test_adjoint(): dat = [[0, I], [1, 0]] ans = OperationsOnlyMatrix([[0, 1], [-I, 0]]) assert ans.adjoint() == Matrix(dat) def test_as_real_imag(): m1 = OperationsOnlyMatrix(2, 2, [1, 2, 3, 4]) m3 = OperationsOnlyMatrix(2, 2, [1 + S.ImaginaryUnit, 2 + 2*S.ImaginaryUnit, 3 + 3*S.ImaginaryUnit, 4 + 4*S.ImaginaryUnit]) a, b = m3.as_real_imag() assert a == m1 assert b == m1 def test_conjugate(): M = OperationsOnlyMatrix([[0, I, 5], [1, 2, 0]]) assert M.T == Matrix([[0, 1], [I, 2], [5, 0]]) assert M.C == Matrix([[0, -I, 5], [1, 2, 0]]) assert M.C == M.conjugate() assert M.H == M.T.C assert M.H == Matrix([[ 0, 1], [-I, 2], [ 5, 0]]) def test_doit(): a = OperationsOnlyMatrix([[Add(x, x, evaluate=False)]]) assert a[0] != 2*x assert a.doit() == Matrix([[2*x]]) def test_evalf(): a = OperationsOnlyMatrix(2, 1, [sqrt(5), 6]) assert all(a.evalf()[i] == a[i].evalf() for i in range(2)) assert all(a.evalf(2)[i] == a[i].evalf(2) for i in range(2)) assert all(a.n(2)[i] == a[i].n(2) for i in range(2)) def test_expand(): m0 = OperationsOnlyMatrix([[x*(x + y), 2], [((x + y)*y)*x, x*(y + x*(x + y))]]) # Test if expand() returns a matrix m1 = m0.expand() assert m1 == Matrix( [[x*y + x**2, 2], [x*y**2 + y*x**2, x*y + y*x**2 + x**3]]) a = Symbol('a', real=True) assert OperationsOnlyMatrix(1, 1, [exp(I*a)]).expand(complex=True) == \ Matrix([cos(a) + I*sin(a)]) def test_refine(): m0 = OperationsOnlyMatrix([[Abs(x)**2, sqrt(x**2)], [sqrt(x**2)*Abs(y)**2, sqrt(y**2)*Abs(x)**2]]) m1 = m0.refine(Q.real(x) & Q.real(y)) assert m1 == Matrix([[x**2, Abs(x)], [y**2*Abs(x), x**2*Abs(y)]]) m1 = m0.refine(Q.positive(x) & Q.positive(y)) assert m1 == Matrix([[x**2, x], [x*y**2, x**2*y]]) m1 = m0.refine(Q.negative(x) & Q.negative(y)) assert m1 == Matrix([[x**2, -x], [-x*y**2, -x**2*y]]) def test_replace(): F, G = symbols('F, G', cls=Function) K = OperationsOnlyMatrix(2, 2, lambda i, j: G(i+j)) M = OperationsOnlyMatrix(2, 2, lambda i, j: F(i+j)) N = M.replace(F, G) assert N == K def test_replace_map(): F, G = symbols('F, G', cls=Function) K = OperationsOnlyMatrix(2, 2, [(G(0), {F(0): G(0)}), (G(1), {F(1): G(1)}), (G(1), {F(1) \ : G(1)}), (G(2), {F(2): G(2)})]) M = OperationsOnlyMatrix(2, 2, lambda i, j: F(i+j)) N = M.replace(F, G, True) assert N == K def test_rot90(): A = Matrix([[1, 2], [3, 4]]) assert A == A.rot90(0) == A.rot90(4) assert A.rot90(2) == A.rot90(-2) == A.rot90(6) == Matrix(((4, 3), (2, 1))) assert A.rot90(3) == A.rot90(-1) == A.rot90(7) == Matrix(((2, 4), (1, 3))) assert A.rot90() == A.rot90(-7) == A.rot90(-3) == Matrix(((3, 1), (4, 2))) def test_simplify(): n = Symbol('n') f = Function('f') M = OperationsOnlyMatrix([[ 1/x + 1/y, (x + x*y) / x ], [ (f(x) + y*f(x))/f(x), 2 * (1/n - cos(n * pi)/n) / pi ]]) assert M.simplify() == Matrix([[ (x + y)/(x * y), 1 + y ], [ 1 + y, 2*((1 - 1*cos(pi*n))/(pi*n)) ]]) eq = (1 + x)**2 M = OperationsOnlyMatrix([[eq]]) assert M.simplify() == Matrix([[eq]]) assert M.simplify(ratio=oo) == Matrix([[eq.simplify(ratio=oo)]]) # https://github.com/sympy/sympy/issues/19353 m = Matrix([[30, 2], [3, 4]]) assert (1/(m.trace())).simplify() == Rational(1, 34) def test_subs(): assert OperationsOnlyMatrix([[1, x], [x, 4]]).subs(x, 5) == Matrix([[1, 5], [5, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).subs([[x, -1], [y, -2]]) == \ Matrix([[-1, 2], [-3, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).subs([(x, -1), (y, -2)]) == \ Matrix([[-1, 2], [-3, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).subs({x: -1, y: -2}) == \ Matrix([[-1, 2], [-3, 4]]) assert OperationsOnlyMatrix([[x*y]]).subs({x: y - 1, y: x - 1}, simultaneous=True) == \ Matrix([[(x - 1)*(y - 1)]]) def test_trace(): M = OperationsOnlyMatrix([[1, 0, 0], [0, 5, 0], [0, 0, 8]]) assert M.trace() == 14 def test_xreplace(): assert OperationsOnlyMatrix([[1, x], [x, 4]]).xreplace({x: 5}) == \ Matrix([[1, 5], [5, 4]]) assert OperationsOnlyMatrix([[x, 2], [x + y, 4]]).xreplace({x: -1, y: -2}) == \ Matrix([[-1, 2], [-3, 4]]) def test_permute(): a = OperationsOnlyMatrix(3, 4, [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) raises(IndexError, lambda: a.permute([[0, 5]])) raises(ValueError, lambda: a.permute(Symbol('x'))) b = a.permute_rows([[0, 2], [0, 1]]) assert a.permute([[0, 2], [0, 1]]) == b == Matrix([ [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) b = a.permute_cols([[0, 2], [0, 1]]) assert a.permute([[0, 2], [0, 1]], orientation='cols') == b ==\ Matrix([ [ 2, 3, 1, 4], [ 6, 7, 5, 8], [10, 11, 9, 12]]) b = a.permute_cols([[0, 2], [0, 1]], direction='backward') assert a.permute([[0, 2], [0, 1]], orientation='cols', direction='backward') == b ==\ Matrix([ [ 3, 1, 2, 4], [ 7, 5, 6, 8], [11, 9, 10, 12]]) assert a.permute([1, 2, 0, 3]) == Matrix([ [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) from sympy.combinatorics import Permutation assert a.permute(Permutation([1, 2, 0, 3])) == Matrix([ [5, 6, 7, 8], [9, 10, 11, 12], [1, 2, 3, 4]]) def test_upper_triangular(): A = OperationsOnlyMatrix([ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]) R = A.upper_triangular(2) assert R == OperationsOnlyMatrix([ [0, 0, 1, 1], [0, 0, 0, 1], [0, 0, 0, 0], [0, 0, 0, 0] ]) R = A.upper_triangular(-2) assert R == OperationsOnlyMatrix([ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [0, 1, 1, 1] ]) R = A.upper_triangular() assert R == OperationsOnlyMatrix([ [1, 1, 1, 1], [0, 1, 1, 1], [0, 0, 1, 1], [0, 0, 0, 1] ]) def test_lower_triangular(): A = OperationsOnlyMatrix([ [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]) L = A.lower_triangular() assert L == ArithmeticOnlyMatrix([ [1, 0, 0, 0], [1, 1, 0, 0], [1, 1, 1, 0], [1, 1, 1, 1]]) L = A.lower_triangular(2) assert L == ArithmeticOnlyMatrix([ [1, 1, 1, 0], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1] ]) L = A.lower_triangular(-2) assert L == ArithmeticOnlyMatrix([ [0, 0, 0, 0], [0, 0, 0, 0], [1, 0, 0, 0], [1, 1, 0, 0] ]) # ArithmeticOnlyMatrix tests def test_abs(): m = ArithmeticOnlyMatrix([[1, -2], [x, y]]) assert abs(m) == ArithmeticOnlyMatrix([[1, 2], [Abs(x), Abs(y)]]) def test_add(): m = ArithmeticOnlyMatrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]]) assert m + m == ArithmeticOnlyMatrix([[2, 4, 6], [2*x, 2*y, 2*x], [4*y, -100, 2*z*x]]) n = ArithmeticOnlyMatrix(1, 2, [1, 2]) raises(ShapeError, lambda: m + n) def test_multiplication(): a = ArithmeticOnlyMatrix(( (1, 2), (3, 1), (0, 6), )) b = ArithmeticOnlyMatrix(( (1, 2), (3, 0), )) raises(ShapeError, lambda: b*a) raises(TypeError, lambda: a*{}) c = a*b assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 try: eval('c = a @ b') except SyntaxError: pass else: assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 h = a.multiply_elementwise(c) assert h == matrix_multiply_elementwise(a, c) assert h[0, 0] == 7 assert h[0, 1] == 4 assert h[1, 0] == 18 assert h[1, 1] == 6 assert h[2, 0] == 0 assert h[2, 1] == 0 raises(ShapeError, lambda: a.multiply_elementwise(b)) c = b * Symbol("x") assert isinstance(c, ArithmeticOnlyMatrix) assert c[0, 0] == x assert c[0, 1] == 2*x assert c[1, 0] == 3*x assert c[1, 1] == 0 c2 = x * b assert c == c2 c = 5 * b assert isinstance(c, ArithmeticOnlyMatrix) assert c[0, 0] == 5 assert c[0, 1] == 2*5 assert c[1, 0] == 3*5 assert c[1, 1] == 0 try: eval('c = 5 @ b') except SyntaxError: pass else: assert isinstance(c, ArithmeticOnlyMatrix) assert c[0, 0] == 5 assert c[0, 1] == 2*5 assert c[1, 0] == 3*5 assert c[1, 1] == 0 def test_matmul(): a = Matrix([[1, 2], [3, 4]]) assert a.__matmul__(2) == NotImplemented assert a.__rmatmul__(2) == NotImplemented #This is done this way because @ is only supported in Python 3.5+ #To check 2@a case try: eval('2 @ a') except SyntaxError: pass except TypeError: #TypeError is raised in case of NotImplemented is returned pass #Check a@2 case try: eval('a @ 2') except SyntaxError: pass except TypeError: #TypeError is raised in case of NotImplemented is returned pass def test_non_matmul(): """ Test that if explicitly specified as non-matrix, mul reverts to scalar multiplication. """ class foo(Expr): is_Matrix=False is_MatrixLike=False shape = (1, 1) A = Matrix([[1, 2], [3, 4]]) b = foo() assert b*A == Matrix([[b, 2*b], [3*b, 4*b]]) assert A*b == Matrix([[b, 2*b], [3*b, 4*b]]) def test_power(): raises(NonSquareMatrixError, lambda: Matrix((1, 2))**2) A = ArithmeticOnlyMatrix([[2, 3], [4, 5]]) assert (A**5)[:] == (6140, 8097, 10796, 14237) A = ArithmeticOnlyMatrix([[2, 1, 3], [4, 2, 4], [6, 12, 1]]) assert (A**3)[:] == (290, 262, 251, 448, 440, 368, 702, 954, 433) assert A**0 == eye(3) assert A**1 == A assert (ArithmeticOnlyMatrix([[2]]) ** 100)[0, 0] == 2**100 assert ArithmeticOnlyMatrix([[1, 2], [3, 4]])**Integer(2) == ArithmeticOnlyMatrix([[7, 10], [15, 22]]) A = Matrix([[1,2],[4,5]]) assert A.pow(20, method='cayley') == A.pow(20, method='multiply') def test_neg(): n = ArithmeticOnlyMatrix(1, 2, [1, 2]) assert -n == ArithmeticOnlyMatrix(1, 2, [-1, -2]) def test_sub(): n = ArithmeticOnlyMatrix(1, 2, [1, 2]) assert n - n == ArithmeticOnlyMatrix(1, 2, [0, 0]) def test_div(): n = ArithmeticOnlyMatrix(1, 2, [1, 2]) assert n/2 == ArithmeticOnlyMatrix(1, 2, [S.Half, S(2)/2]) # SpecialOnlyMatrix tests def test_eye(): assert list(SpecialOnlyMatrix.eye(2, 2)) == [1, 0, 0, 1] assert list(SpecialOnlyMatrix.eye(2)) == [1, 0, 0, 1] assert type(SpecialOnlyMatrix.eye(2)) == SpecialOnlyMatrix assert type(SpecialOnlyMatrix.eye(2, cls=Matrix)) == Matrix def test_ones(): assert list(SpecialOnlyMatrix.ones(2, 2)) == [1, 1, 1, 1] assert list(SpecialOnlyMatrix.ones(2)) == [1, 1, 1, 1] assert SpecialOnlyMatrix.ones(2, 3) == Matrix([[1, 1, 1], [1, 1, 1]]) assert type(SpecialOnlyMatrix.ones(2)) == SpecialOnlyMatrix assert type(SpecialOnlyMatrix.ones(2, cls=Matrix)) == Matrix def test_zeros(): assert list(SpecialOnlyMatrix.zeros(2, 2)) == [0, 0, 0, 0] assert list(SpecialOnlyMatrix.zeros(2)) == [0, 0, 0, 0] assert SpecialOnlyMatrix.zeros(2, 3) == Matrix([[0, 0, 0], [0, 0, 0]]) assert type(SpecialOnlyMatrix.zeros(2)) == SpecialOnlyMatrix assert type(SpecialOnlyMatrix.zeros(2, cls=Matrix)) == Matrix def test_diag_make(): diag = SpecialOnlyMatrix.diag a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) assert diag(a, b, b) == Matrix([ [1, 2, 0, 0, 0, 0], [2, 3, 0, 0, 0, 0], [0, 0, 3, x, 0, 0], [0, 0, y, 3, 0, 0], [0, 0, 0, 0, 3, x], [0, 0, 0, 0, y, 3], ]) assert diag(a, b, c) == Matrix([ [1, 2, 0, 0, 0, 0, 0], [2, 3, 0, 0, 0, 0, 0], [0, 0, 3, x, 0, 0, 0], [0, 0, y, 3, 0, 0, 0], [0, 0, 0, 0, 3, x, 3], [0, 0, 0, 0, y, 3, z], [0, 0, 0, 0, x, y, z], ]) assert diag(a, c, b) == Matrix([ [1, 2, 0, 0, 0, 0, 0], [2, 3, 0, 0, 0, 0, 0], [0, 0, 3, x, 3, 0, 0], [0, 0, y, 3, z, 0, 0], [0, 0, x, y, z, 0, 0], [0, 0, 0, 0, 0, 3, x], [0, 0, 0, 0, 0, y, 3], ]) a = Matrix([x, y, z]) b = Matrix([[1, 2], [3, 4]]) c = Matrix([[5, 6]]) # this "wandering diagonal" is what makes this # a block diagonal where each block is independent # of the others assert diag(a, 7, b, c) == Matrix([ [x, 0, 0, 0, 0, 0], [y, 0, 0, 0, 0, 0], [z, 0, 0, 0, 0, 0], [0, 7, 0, 0, 0, 0], [0, 0, 1, 2, 0, 0], [0, 0, 3, 4, 0, 0], [0, 0, 0, 0, 5, 6]]) raises(ValueError, lambda: diag(a, 7, b, c, rows=5)) assert diag(1) == Matrix([[1]]) assert diag(1, rows=2) == Matrix([[1, 0], [0, 0]]) assert diag(1, cols=2) == Matrix([[1, 0], [0, 0]]) assert diag(1, rows=3, cols=2) == Matrix([[1, 0], [0, 0], [0, 0]]) assert diag(*[2, 3]) == Matrix([ [2, 0], [0, 3]]) assert diag(Matrix([2, 3])) == Matrix([ [2], [3]]) assert diag([1, [2, 3], 4], unpack=False) == \ diag([[1], [2, 3], [4]], unpack=False) == Matrix([ [1, 0], [2, 3], [4, 0]]) assert type(diag(1)) == SpecialOnlyMatrix assert type(diag(1, cls=Matrix)) == Matrix assert Matrix.diag([1, 2, 3]) == Matrix.diag(1, 2, 3) assert Matrix.diag([1, 2, 3], unpack=False).shape == (3, 1) assert Matrix.diag([[1, 2, 3]]).shape == (3, 1) assert Matrix.diag([[1, 2, 3]], unpack=False).shape == (1, 3) assert Matrix.diag([[[1, 2, 3]]]).shape == (1, 3) # kerning can be used to move the starting point assert Matrix.diag(ones(0, 2), 1, 2) == Matrix([ [0, 0, 1, 0], [0, 0, 0, 2]]) assert Matrix.diag(ones(2, 0), 1, 2) == Matrix([ [0, 0], [0, 0], [1, 0], [0, 2]]) def test_diagonal(): m = Matrix(3, 3, range(9)) d = m.diagonal() assert d == m.diagonal(0) assert tuple(d) == (0, 4, 8) assert tuple(m.diagonal(1)) == (1, 5) assert tuple(m.diagonal(-1)) == (3, 7) assert tuple(m.diagonal(2)) == (2,) assert type(m.diagonal()) == type(m) s = SparseMatrix(3, 3, {(1, 1): 1}) assert type(s.diagonal()) == type(s) assert type(m) != type(s) raises(ValueError, lambda: m.diagonal(3)) raises(ValueError, lambda: m.diagonal(-3)) raises(ValueError, lambda: m.diagonal(pi)) M = ones(2, 3) assert banded({i: list(M.diagonal(i)) for i in range(1-M.rows, M.cols)}) == M def test_jordan_block(): assert SpecialOnlyMatrix.jordan_block(3, 2) == SpecialOnlyMatrix.jordan_block(3, eigenvalue=2) \ == SpecialOnlyMatrix.jordan_block(size=3, eigenvalue=2) \ == SpecialOnlyMatrix.jordan_block(3, 2, band='upper') \ == SpecialOnlyMatrix.jordan_block( size=3, eigenval=2, eigenvalue=2) \ == Matrix([ [2, 1, 0], [0, 2, 1], [0, 0, 2]]) assert SpecialOnlyMatrix.jordan_block(3, 2, band='lower') == Matrix([ [2, 0, 0], [1, 2, 0], [0, 1, 2]]) # missing eigenvalue raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block(2)) # non-integral size raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block(3.5, 2)) # size not specified raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block(eigenvalue=2)) # inconsistent eigenvalue raises(ValueError, lambda: SpecialOnlyMatrix.jordan_block( eigenvalue=2, eigenval=4)) # Deprecated feature with warns_deprecated_sympy(): assert (SpecialOnlyMatrix.jordan_block(cols=3, eigenvalue=2) == SpecialOnlyMatrix(3, 3, (2, 1, 0, 0, 2, 1, 0, 0, 2))) with warns_deprecated_sympy(): assert (SpecialOnlyMatrix.jordan_block(rows=3, eigenvalue=2) == SpecialOnlyMatrix(3, 3, (2, 1, 0, 0, 2, 1, 0, 0, 2))) with warns_deprecated_sympy(): assert SpecialOnlyMatrix.jordan_block(3, 2) == \ SpecialOnlyMatrix.jordan_block(cols=3, eigenvalue=2) == \ SpecialOnlyMatrix.jordan_block(rows=3, eigenvalue=2) with warns_deprecated_sympy(): assert SpecialOnlyMatrix.jordan_block( rows=4, cols=3, eigenvalue=2) == \ Matrix([ [2, 1, 0], [0, 2, 1], [0, 0, 2], [0, 0, 0]]) # Using alias keyword assert SpecialOnlyMatrix.jordan_block(size=3, eigenvalue=2) == \ SpecialOnlyMatrix.jordan_block(size=3, eigenval=2) def test_orthogonalize(): m = Matrix([[1, 2], [3, 4]]) assert m.orthogonalize(Matrix([[2], [1]])) == [Matrix([[2], [1]])] assert m.orthogonalize(Matrix([[2], [1]]), normalize=True) == \ [Matrix([[2*sqrt(5)/5], [sqrt(5)/5]])] assert m.orthogonalize(Matrix([[1], [2]]), Matrix([[-1], [4]])) == \ [Matrix([[1], [2]]), Matrix([[Rational(-12, 5)], [Rational(6, 5)]])] assert m.orthogonalize(Matrix([[0], [0]]), Matrix([[-1], [4]])) == \ [Matrix([[-1], [4]])] assert m.orthogonalize(Matrix([[0], [0]])) == [] n = Matrix([[9, 1, 9], [3, 6, 10], [8, 5, 2]]) vecs = [Matrix([[-5], [1]]), Matrix([[-5], [2]]), Matrix([[-5], [-2]])] assert n.orthogonalize(*vecs) == \ [Matrix([[-5], [1]]), Matrix([[Rational(5, 26)], [Rational(25, 26)]])] vecs = [Matrix([0, 0, 0]), Matrix([1, 2, 3]), Matrix([1, 4, 5])] raises(ValueError, lambda: Matrix.orthogonalize(*vecs, rankcheck=True)) vecs = [Matrix([1, 2, 3]), Matrix([4, 5, 6]), Matrix([7, 8, 9])] raises(ValueError, lambda: Matrix.orthogonalize(*vecs, rankcheck=True)) def test_wilkinson(): wminus, wplus = Matrix.wilkinson(1) assert wminus == Matrix([ [-1, 1, 0], [1, 0, 1], [0, 1, 1]]) assert wplus == Matrix([ [1, 1, 0], [1, 0, 1], [0, 1, 1]]) wminus, wplus = Matrix.wilkinson(3) assert wminus == Matrix([ [-3, 1, 0, 0, 0, 0, 0], [1, -2, 1, 0, 0, 0, 0], [0, 1, -1, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0], [0, 0, 0, 0, 1, 2, 1], [0, 0, 0, 0, 0, 1, 3]]) assert wplus == Matrix([ [3, 1, 0, 0, 0, 0, 0], [1, 2, 1, 0, 0, 0, 0], [0, 1, 1, 1, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0], [0, 0, 0, 1, 1, 1, 0], [0, 0, 0, 0, 1, 2, 1], [0, 0, 0, 0, 0, 1, 3]]) # CalculusOnlyMatrix tests @XFAIL def test_diff(): x, y = symbols('x y') m = CalculusOnlyMatrix(2, 1, [x, y]) # TODO: currently not working as ``_MinimalMatrix`` cannot be sympified: assert m.diff(x) == Matrix(2, 1, [1, 0]) def test_integrate(): x, y = symbols('x y') m = CalculusOnlyMatrix(2, 1, [x, y]) assert m.integrate(x) == Matrix(2, 1, [x**2/2, y*x]) def test_jacobian2(): rho, phi = symbols("rho,phi") X = CalculusOnlyMatrix(3, 1, [rho*cos(phi), rho*sin(phi), rho**2]) Y = CalculusOnlyMatrix(2, 1, [rho, phi]) J = Matrix([ [cos(phi), -rho*sin(phi)], [sin(phi), rho*cos(phi)], [ 2*rho, 0], ]) assert X.jacobian(Y) == J m = CalculusOnlyMatrix(2, 2, [1, 2, 3, 4]) m2 = CalculusOnlyMatrix(4, 1, [1, 2, 3, 4]) raises(TypeError, lambda: m.jacobian(Matrix([1, 2]))) raises(TypeError, lambda: m2.jacobian(m)) def test_limit(): x, y = symbols('x y') m = CalculusOnlyMatrix(2, 1, [1/x, y]) assert m.limit(x, 5) == Matrix(2, 1, [Rational(1, 5), y]) def test_issue_13774(): M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) v = [1, 1, 1] raises(TypeError, lambda: M*v) raises(TypeError, lambda: v*M) def test_companion(): x = Symbol('x') y = Symbol('y') raises(ValueError, lambda: Matrix.companion(1)) raises(ValueError, lambda: Matrix.companion(Poly([1], x))) raises(ValueError, lambda: Matrix.companion(Poly([2, 1], x))) raises(ValueError, lambda: Matrix.companion(Poly(x*y, [x, y]))) c0, c1, c2 = symbols('c0:3') assert Matrix.companion(Poly([1, c0], x)) == Matrix([-c0]) assert Matrix.companion(Poly([1, c1, c0], x)) == \ Matrix([[0, -c0], [1, -c1]]) assert Matrix.companion(Poly([1, c2, c1, c0], x)) == \ Matrix([[0, 0, -c0], [1, 0, -c1], [0, 1, -c2]]) def test_issue_10589(): x, y, z = symbols("x, y z") M1 = Matrix([x, y, z]) M1 = M1.subs(zip([x, y, z], [1, 2, 3])) assert M1 == Matrix([[1], [2], [3]]) M2 = Matrix([[x, x, x, x, x], [x, x, x, x, x], [x, x, x, x, x]]) M2 = M2.subs(zip([x], [1])) assert M2 == Matrix([[1, 1, 1, 1, 1], [1, 1, 1, 1, 1], [1, 1, 1, 1, 1]]) def test_rmul_pr19860(): class Foo(ImmutableDenseMatrix): _op_priority = MutableDenseMatrix._op_priority + 0.01 a = Matrix(2, 2, [1, 2, 3, 4]) b = Foo(2, 2, [1, 2, 3, 4]) # This would throw a RecursionError: maximum recursion depth # since b always has higher priority even after a.as_mutable() c = a*b assert isinstance(c, Foo) assert c == Matrix([[7, 10], [15, 22]]) def test_issue_18956(): A = Array([[1, 2], [3, 4]]) B = Matrix([[1,2],[3,4]]) raises(TypeError, lambda: B + A) raises(TypeError, lambda: A + B) sympy-sympy-1.9/sympy/matrices/tests/test_decompositions.py000066400000000000000000000330351412543434000245310ustar00rootroot00000000000000from sympy import Rational, I, expand_mul, S, simplify, sqrt from sympy.matrices.matrices import NonSquareMatrixError from sympy.matrices import Matrix, zeros, eye, SparseMatrix from sympy.abc import x, y, z from sympy.testing.pytest import raises, slow from sympy.testing.matrices import allclose def test_LUdecomp(): testmat = Matrix([[0, 2, 5, 3], [3, 3, 7, 4], [8, 4, 0, 2], [-2, 6, 3, 4]]) L, U, p = testmat.LUdecomposition() assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - testmat == zeros(4) testmat = Matrix([[6, -2, 7, 4], [0, 3, 6, 7], [1, -2, 7, 4], [-9, 2, 6, 3]]) L, U, p = testmat.LUdecomposition() assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - testmat == zeros(4) # non-square testmat = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9], [10, 11, 12]]) L, U, p = testmat.LUdecomposition(rankcheck=False) assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - testmat == zeros(4, 3) # square and singular testmat = Matrix([[1, 2, 3], [2, 4, 6], [4, 5, 6]]) L, U, p = testmat.LUdecomposition(rankcheck=False) assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - testmat == zeros(3) M = Matrix(((1, x, 1), (2, y, 0), (y, 0, z))) L, U, p = M.LUdecomposition() assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - M == zeros(3) mL = Matrix(( (1, 0, 0), (2, 3, 0), )) assert mL.is_lower is True assert mL.is_upper is False mU = Matrix(( (1, 2, 3), (0, 4, 5), )) assert mU.is_lower is False assert mU.is_upper is True # test FF LUdecomp M = Matrix([[1, 3, 3], [3, 2, 6], [3, 2, 2]]) P, L, Dee, U = M.LUdecompositionFF() assert P*M == L*Dee.inv()*U M = Matrix([[1, 2, 3, 4], [3, -1, 2, 3], [3, 1, 3, -2], [6, -1, 0, 2]]) P, L, Dee, U = M.LUdecompositionFF() assert P*M == L*Dee.inv()*U M = Matrix([[0, 0, 1], [2, 3, 0], [3, 1, 4]]) P, L, Dee, U = M.LUdecompositionFF() assert P*M == L*Dee.inv()*U # issue 15794 M = Matrix( [[1, 2, 3], [4, 5, 6], [7, 8, 9]] ) raises(ValueError, lambda : M.LUdecomposition_Simple(rankcheck=True)) def test_singular_value_decompositionD(): A = Matrix([[1, 2], [2, 1]]) U, S, V = A.singular_value_decomposition() assert U * S * V.T == A assert U.T * U == eye(U.cols) assert V.T * V == eye(V.cols) B = Matrix([[1, 2]]) U, S, V = B.singular_value_decomposition() assert U * S * V.T == B assert U.T * U == eye(U.cols) assert V.T * V == eye(V.cols) C = Matrix([ [1, 0, 0, 0, 2], [0, 0, 3, 0, 0], [0, 0, 0, 0, 0], [0, 2, 0, 0, 0], ]) U, S, V = C.singular_value_decomposition() assert U * S * V.T == C assert U.T * U == eye(U.cols) assert V.T * V == eye(V.cols) D = Matrix([[Rational(1, 3), sqrt(2)], [0, Rational(1, 4)]]) U, S, V = D.singular_value_decomposition() assert simplify(U.T * U) == eye(U.cols) assert simplify(V.T * V) == eye(V.cols) assert simplify(U * S * V.T) == D def test_QR(): A = Matrix([[1, 2], [2, 3]]) Q, S = A.QRdecomposition() R = Rational assert Q == Matrix([ [ 5**R(-1, 2), (R(2)/5)*(R(1)/5)**R(-1, 2)], [2*5**R(-1, 2), (-R(1)/5)*(R(1)/5)**R(-1, 2)]]) assert S == Matrix([[5**R(1, 2), 8*5**R(-1, 2)], [0, (R(1)/5)**R(1, 2)]]) assert Q*S == A assert Q.T * Q == eye(2) A = Matrix([[1, 1, 1], [1, 1, 3], [2, 3, 4]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[12, 0, -51], [6, 0, 167], [-4, 0, 24]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R def test_QR_non_square(): # Narrow (cols < rows) matrices A = Matrix([[9, 0, 26], [12, 0, -7], [0, 4, 4], [0, -3, -3]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[1, -1, 4], [1, 4, -2], [1, 4, 2], [1, -1, 0]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix(2, 1, [1, 2]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R # Wide (cols > rows) matrices A = Matrix([[1, 2, 3], [4, 5, 6]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[1, 2, 3, 4], [1, 4, 9, 16], [1, 8, 27, 64]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix(1, 2, [1, 2]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R def test_QR_trivial(): # Rank deficient matrices A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[1, 1, 1], [2, 2, 2], [3, 3, 3], [4, 4, 4]]).T Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R # Zero rank matrices A = Matrix([[0, 0, 0]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[0, 0, 0]]).T Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[0, 0, 0], [0, 0, 0]]) Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[0, 0, 0], [0, 0, 0]]).T Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R # Rank deficient matrices with zero norm from beginning columns A = Matrix([[0, 0, 0], [1, 2, 3]]).T Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[0, 0, 0, 0], [1, 2, 3, 4], [0, 0, 0, 0]]).T Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[0, 0, 0, 0], [1, 2, 3, 4], [0, 0, 0, 0], [2, 4, 6, 8]]).T Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R A = Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0], [1, 2, 3]]).T Q, R = A.QRdecomposition() assert Q.T * Q == eye(Q.cols) assert R.is_upper assert A == Q*R def test_QR_float(): A = Matrix([[1, 1], [1, 1.01]]) Q, R = A.QRdecomposition() assert allclose(Q * R, A) assert allclose(Q * Q.T, Matrix.eye(2)) assert allclose(Q.T * Q, Matrix.eye(2)) A = Matrix([[1, 1], [1, 1.001]]) Q, R = A.QRdecomposition() assert allclose(Q * R, A) assert allclose(Q * Q.T, Matrix.eye(2)) assert allclose(Q.T * Q, Matrix.eye(2)) def test_LUdecomposition_Simple_iszerofunc(): # Test if callable passed to matrices.LUdecomposition_Simple() as iszerofunc keyword argument is used inside # matrices.LUdecomposition_Simple() magic_string = "I got passed in!" def goofyiszero(value): raise ValueError(magic_string) try: lu, p = Matrix([[1, 0], [0, 1]]).LUdecomposition_Simple(iszerofunc=goofyiszero) except ValueError as err: assert magic_string == err.args[0] return assert False def test_LUdecomposition_iszerofunc(): # Test if callable passed to matrices.LUdecomposition() as iszerofunc keyword argument is used inside # matrices.LUdecomposition_Simple() magic_string = "I got passed in!" def goofyiszero(value): raise ValueError(magic_string) try: l, u, p = Matrix([[1, 0], [0, 1]]).LUdecomposition(iszerofunc=goofyiszero) except ValueError as err: assert magic_string == err.args[0] return assert False def test_LDLdecomposition(): raises(NonSquareMatrixError, lambda: Matrix((1, 2)).LDLdecomposition()) raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).LDLdecomposition()) raises(ValueError, lambda: Matrix(((5 + I, 0), (0, 1))).LDLdecomposition()) raises(ValueError, lambda: Matrix(((1, 5), (5, 1))).LDLdecomposition()) raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).LDLdecomposition(hermitian=False)) A = Matrix(((1, 5), (5, 1))) L, D = A.LDLdecomposition(hermitian=False) assert L * D * L.T == A A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) L, D = A.LDLdecomposition() assert L * D * L.T == A assert L.is_lower assert L == Matrix([[1, 0, 0], [ Rational(3, 5), 1, 0], [Rational(-1, 5), Rational(1, 3), 1]]) assert D.is_diagonal() assert D == Matrix([[25, 0, 0], [0, 9, 0], [0, 0, 9]]) A = Matrix(((4, -2*I, 2 + 2*I), (2*I, 2, -1 + I), (2 - 2*I, -1 - I, 11))) L, D = A.LDLdecomposition() assert expand_mul(L * D * L.H) == A assert L.expand() == Matrix([[1, 0, 0], [I/2, 1, 0], [S.Half - I/2, 0, 1]]) assert D.expand() == Matrix(((4, 0, 0), (0, 1, 0), (0, 0, 9))) raises(NonSquareMatrixError, lambda: SparseMatrix((1, 2)).LDLdecomposition()) raises(ValueError, lambda: SparseMatrix(((1, 2), (3, 4))).LDLdecomposition()) raises(ValueError, lambda: SparseMatrix(((5 + I, 0), (0, 1))).LDLdecomposition()) raises(ValueError, lambda: SparseMatrix(((1, 5), (5, 1))).LDLdecomposition()) raises(ValueError, lambda: SparseMatrix(((1, 2), (3, 4))).LDLdecomposition(hermitian=False)) A = SparseMatrix(((1, 5), (5, 1))) L, D = A.LDLdecomposition(hermitian=False) assert L * D * L.T == A A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) L, D = A.LDLdecomposition() assert L * D * L.T == A assert L.is_lower assert L == Matrix([[1, 0, 0], [ Rational(3, 5), 1, 0], [Rational(-1, 5), Rational(1, 3), 1]]) assert D.is_diagonal() assert D == Matrix([[25, 0, 0], [0, 9, 0], [0, 0, 9]]) A = SparseMatrix(((4, -2*I, 2 + 2*I), (2*I, 2, -1 + I), (2 - 2*I, -1 - I, 11))) L, D = A.LDLdecomposition() assert expand_mul(L * D * L.H) == A assert L == Matrix(((1, 0, 0), (I/2, 1, 0), (S.Half - I/2, 0, 1))) assert D == Matrix(((4, 0, 0), (0, 1, 0), (0, 0, 9))) def test_pinv_succeeds_with_rank_decomposition_method(): # Test rank decomposition method of pseudoinverse succeeding As = [Matrix([ [61, 89, 55, 20, 71, 0], [62, 96, 85, 85, 16, 0], [69, 56, 17, 4, 54, 0], [10, 54, 91, 41, 71, 0], [ 7, 30, 10, 48, 90, 0], [0,0,0,0,0,0]])] for A in As: A_pinv = A.pinv(method="RD") AAp = A * A_pinv ApA = A_pinv * A assert simplify(AAp * A) == A assert simplify(ApA * A_pinv) == A_pinv assert AAp.H == AAp assert ApA.H == ApA def test_rank_decomposition(): a = Matrix(0, 0, []) c, f = a.rank_decomposition() assert f.is_echelon assert c.cols == f.rows == a.rank() assert c * f == a a = Matrix(1, 1, [5]) c, f = a.rank_decomposition() assert f.is_echelon assert c.cols == f.rows == a.rank() assert c * f == a a = Matrix(3, 3, [1, 2, 3, 1, 2, 3, 1, 2, 3]) c, f = a.rank_decomposition() assert f.is_echelon assert c.cols == f.rows == a.rank() assert c * f == a a = Matrix([ [0, 0, 1, 2, 2, -5, 3], [-1, 5, 2, 2, 1, -7, 5], [0, 0, -2, -3, -3, 8, -5], [-1, 5, 0, -1, -2, 1, 0]]) c, f = a.rank_decomposition() assert f.is_echelon assert c.cols == f.rows == a.rank() assert c * f == a @slow def test_upper_hessenberg_decomposition(): A = Matrix([ [1, 0, sqrt(3)], [sqrt(2), Rational(1, 2), 2], [1, Rational(1, 4), 3], ]) H, P = A.upper_hessenberg_decomposition() assert simplify(P * P.H) == eye(P.cols) assert simplify(P.H * P) == eye(P.cols) assert H.is_upper_hessenberg assert (simplify(P * H * P.H)) == A B = Matrix([ [1, 2, 10], [8, 2, 5], [3, 12, 34], ]) H, P = B.upper_hessenberg_decomposition() assert simplify(P * P.H) == eye(P.cols) assert simplify(P.H * P) == eye(P.cols) assert H.is_upper_hessenberg assert simplify(P * H * P.H) == B C = Matrix([ [1, sqrt(2), 2, 3], [0, 5, 3, 4], [1, 1, 4, sqrt(5)], [0, 2, 2, 3] ]) H, P = C.upper_hessenberg_decomposition() assert simplify(P * P.H) == eye(P.cols) assert simplify(P.H * P) == eye(P.cols) assert H.is_upper_hessenberg assert simplify(P * H * P.H) == C D = Matrix([ [1, 2, 3], [-3, 5, 6], [4, -8, 9], ]) H, P = D.upper_hessenberg_decomposition() assert simplify(P * P.H) == eye(P.cols) assert simplify(P.H * P) == eye(P.cols) assert H.is_upper_hessenberg assert simplify(P * H * P.H) == D E = Matrix([ [1, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 1], [1, 1, 1, 0] ]) H, P = E.upper_hessenberg_decomposition() assert simplify(P * P.H) == eye(P.cols) assert simplify(P.H * P) == eye(P.cols) assert H.is_upper_hessenberg assert simplify(P * H * P.H) == E sympy-sympy-1.9/sympy/matrices/tests/test_densearith.py000066400000000000000000000044401412543434000236160ustar00rootroot00000000000000from sympy.testing.pytest import ignore_warnings from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.matrices import Matrix, SparseMatrix, ImmutableMatrix with ignore_warnings(SymPyDeprecationWarning): from sympy.matrices.densetools import eye from sympy.matrices.densearith import add, sub, mulmatmat, mulmatscaler from sympy import ZZ def test_add(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = [[ZZ(5), ZZ(4), ZZ(9)], [ZZ(3), ZZ(7), ZZ(1)], [ZZ(12), ZZ(13), ZZ(14)]] c = [[ZZ(12)], [ZZ(17)], [ZZ(21)]] d = [[ZZ(3)], [ZZ(4)], [ZZ(5)]] e = [[ZZ(12), ZZ(78)], [ZZ(56), ZZ(79)]] f = [[ZZ.zero, ZZ.zero], [ZZ.zero, ZZ.zero]] assert add(a, b, ZZ) == [[ZZ(8), ZZ(11), ZZ(13)], [ZZ(5), ZZ(11), ZZ(6)], [ZZ(18), ZZ(15), ZZ(17)]] assert add(c, d, ZZ) == [[ZZ(15)], [ZZ(21)], [ZZ(26)]] assert add(e, f, ZZ) == e def test_sub(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = [[ZZ(5), ZZ(4), ZZ(9)], [ZZ(3), ZZ(7), ZZ(1)], [ZZ(12), ZZ(13), ZZ(14)]] c = [[ZZ(12)], [ZZ(17)], [ZZ(21)]] d = [[ZZ(3)], [ZZ(4)], [ZZ(5)]] e = [[ZZ(12), ZZ(78)], [ZZ(56), ZZ(79)]] f = [[ZZ.zero, ZZ.zero], [ZZ.zero, ZZ.zero]] assert sub(a, b, ZZ) == [[ZZ(-2), ZZ(3), ZZ(-5)], [ZZ(-1), ZZ(-3), ZZ(4)], [ZZ(-6), ZZ(-11), ZZ(-11)]] assert sub(c, d, ZZ) == [[ZZ(9)], [ZZ(13)], [ZZ(16)]] assert sub(e, f, ZZ) == e def test_mulmatmat(): a = [[ZZ(3), ZZ(4)], [ZZ(5), ZZ(6)]] b = [[ZZ(1), ZZ(2)], [ZZ(7), ZZ(8)]] c = eye(2, ZZ) d = [[ZZ(6)], [ZZ(7)]] assert mulmatmat(a, b, ZZ) == [[ZZ(31), ZZ(38)], [ZZ(47), ZZ(58)]] assert mulmatmat(a, c, ZZ) == [[ZZ(3), ZZ(4)], [ZZ(5), ZZ(6)]] assert mulmatmat(b, d, ZZ) == [[ZZ(20)], [ZZ(98)]] def test_mulmatscaler(): a = eye(3, ZZ) b = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] assert mulmatscaler(a, ZZ(4), ZZ) == [[ZZ(4), ZZ(0), ZZ(0)], [ZZ(0), ZZ(4), ZZ(0)], [ZZ(0), ZZ(0), ZZ(4)]] assert mulmatscaler(b, ZZ(1), ZZ) == [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] def test_eq(): A = Matrix([[1]]) B = ImmutableMatrix([[1]]) C = SparseMatrix([[1]]) assert A != object() assert A != "Matrix([[1]])" assert A == B assert A == C sympy-sympy-1.9/sympy/matrices/tests/test_densesolve.py000066400000000000000000000021101412543434000236270ustar00rootroot00000000000000from sympy.testing.pytest import ignore_warnings from sympy.utilities.exceptions import SymPyDeprecationWarning with ignore_warnings(SymPyDeprecationWarning): from sympy.matrices.densesolve import LU_solve, rref_solve, cholesky_solve from sympy import Dummy from sympy import QQ def test_LU_solve(): x, y, z = Dummy('x'), Dummy('y'), Dummy('z') assert LU_solve([[QQ(2), QQ(-1), QQ(-2)], [QQ(-4), QQ(6), QQ(3)], [QQ(-4), QQ(-2), QQ(8)]], [[x], [y], [z]], [[QQ(-1)], [QQ(13)], [QQ(-6)]], QQ) == [[QQ(2,1)], [QQ(3, 1)], [QQ(1, 1)]] def test_cholesky_solve(): x, y, z = Dummy('x'), Dummy('y'), Dummy('z') assert cholesky_solve([[QQ(25), QQ(15), QQ(-5)], [QQ(15), QQ(18), QQ(0)], [QQ(-5), QQ(0), QQ(11)]], [[x], [y], [z]], [[QQ(2)], [QQ(3)], [QQ(1)]], QQ) == [[QQ(-1, 225)], [QQ(23, 135)], [QQ(4, 45)]] def test_rref_solve(): x, y, z = Dummy('x'), Dummy('y'), Dummy('z') assert rref_solve([[QQ(25), QQ(15), QQ(-5)], [QQ(15), QQ(18), QQ(0)], [QQ(-5), QQ(0), QQ(11)]], [[x], [y], [z]], [[QQ(2)], [QQ(3)], [QQ(1)]], QQ) == [[QQ(-1, 225)], [QQ(23, 135)], [QQ(4, 45)]] sympy-sympy-1.9/sympy/matrices/tests/test_densetools.py000066400000000000000000000012601412543434000236440ustar00rootroot00000000000000from sympy.testing.pytest import ignore_warnings from sympy.utilities.exceptions import SymPyDeprecationWarning with ignore_warnings(SymPyDeprecationWarning): from sympy.matrices.densetools import trace, transpose, eye from sympy import ZZ def test_trace(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = eye(2, ZZ) assert trace(a, ZZ) == ZZ(10) assert trace(b, ZZ) == ZZ(2) def test_transpose(): a = [[ZZ(3), ZZ(7), ZZ(4)], [ZZ(2), ZZ(4), ZZ(5)], [ZZ(6), ZZ(2), ZZ(3)]] b = eye(4, ZZ) assert transpose(a, ZZ) == ([[ZZ(3), ZZ(2), ZZ(6)], [ZZ(7), ZZ(4), ZZ(2)], [ZZ(4), ZZ(5), ZZ(3)]]) assert transpose(b, ZZ) == b sympy-sympy-1.9/sympy/matrices/tests/test_determinant.py000066400000000000000000000311141412543434000240000ustar00rootroot00000000000000import random from sympy.core.numbers import I from sympy import symbols, Symbol, Rational, sqrt, Poly from sympy.matrices import Matrix, eye, ones from sympy.abc import x, y, z from sympy.testing.pytest import raises from sympy.matrices.common import NonSquareMatrixError from sympy.functions.combinatorial.factorials import factorial, subfactorial def test_determinant(): for M in [Matrix(), Matrix([[1]])]: assert ( M.det() == M._eval_det_bareiss() == M._eval_det_berkowitz() == M._eval_det_lu() == 1) M = Matrix(( (-3, 2), ( 8, -5) )) assert M.det(method="domain-ge") == -1 assert M.det(method="bareiss") == -1 assert M.det(method="berkowitz") == -1 assert M.det(method="lu") == -1 M = Matrix(( (x, 1), (y, 2*y) )) assert M.det(method="domain-ge") == 2*x*y - y assert M.det(method="bareiss") == 2*x*y - y assert M.det(method="berkowitz") == 2*x*y - y assert M.det(method="lu") == 2*x*y - y M = Matrix(( (1, 1, 1), (1, 2, 3), (1, 3, 6) )) assert M.det(method="domain-ge") == 1 assert M.det(method="bareiss") == 1 assert M.det(method="berkowitz") == 1 assert M.det(method="lu") == 1 M = Matrix(( ( 3, -2, 0, 5), (-2, 1, -2, 2), ( 0, -2, 5, 0), ( 5, 0, 3, 4) )) assert M.det(method="domain-ge") == -289 assert M.det(method="bareiss") == -289 assert M.det(method="berkowitz") == -289 assert M.det(method="lu") == -289 M = Matrix(( ( 1, 2, 3, 4), ( 5, 6, 7, 8), ( 9, 10, 11, 12), (13, 14, 15, 16) )) assert M.det(method="domain-ge") == 0 assert M.det(method="bareiss") == 0 assert M.det(method="berkowitz") == 0 assert M.det(method="lu") == 0 M = Matrix(( (3, 2, 0, 0, 0), (0, 3, 2, 0, 0), (0, 0, 3, 2, 0), (0, 0, 0, 3, 2), (2, 0, 0, 0, 3) )) assert M.det(method="domain-ge") == 275 assert M.det(method="bareiss") == 275 assert M.det(method="berkowitz") == 275 assert M.det(method="lu") == 275 M = Matrix(( ( 3, 0, 0, 0), (-2, 1, 0, 0), ( 0, -2, 5, 0), ( 5, 0, 3, 4) )) assert M.det(method="domain-ge") == 60 assert M.det(method="bareiss") == 60 assert M.det(method="berkowitz") == 60 assert M.det(method="lu") == 60 M = Matrix(( ( 1, 0, 0, 0), ( 5, 0, 0, 0), ( 9, 10, 11, 0), (13, 14, 15, 16) )) assert M.det(method="domain-ge") == 0 assert M.det(method="bareiss") == 0 assert M.det(method="berkowitz") == 0 assert M.det(method="lu") == 0 M = Matrix(( (3, 2, 0, 0, 0), (0, 3, 2, 0, 0), (0, 0, 3, 2, 0), (0, 0, 0, 3, 2), (0, 0, 0, 0, 3) )) assert M.det(method="domain-ge") == 243 assert M.det(method="bareiss") == 243 assert M.det(method="berkowitz") == 243 assert M.det(method="lu") == 243 M = Matrix(( (1, 0, 1, 2, 12), (2, 0, 1, 1, 4), (2, 1, 1, -1, 3), (3, 2, -1, 1, 8), (1, 1, 1, 0, 6) )) assert M.det(method="domain-ge") == -55 assert M.det(method="bareiss") == -55 assert M.det(method="berkowitz") == -55 assert M.det(method="lu") == -55 M = Matrix(( (-5, 2, 3, 4, 5), ( 1, -4, 3, 4, 5), ( 1, 2, -3, 4, 5), ( 1, 2, 3, -2, 5), ( 1, 2, 3, 4, -1) )) assert M.det(method="domain-ge") == 11664 assert M.det(method="bareiss") == 11664 assert M.det(method="berkowitz") == 11664 assert M.det(method="lu") == 11664 M = Matrix(( ( 2, 7, -1, 3, 2), ( 0, 0, 1, 0, 1), (-2, 0, 7, 0, 2), (-3, -2, 4, 5, 3), ( 1, 0, 0, 0, 1) )) assert M.det(method="domain-ge") == 123 assert M.det(method="bareiss") == 123 assert M.det(method="berkowitz") == 123 assert M.det(method="lu") == 123 M = Matrix(( (x, y, z), (1, 0, 0), (y, z, x) )) assert M.det(method="domain-ge") == z**2 - x*y assert M.det(method="bareiss") == z**2 - x*y assert M.det(method="berkowitz") == z**2 - x*y assert M.det(method="lu") == z**2 - x*y # issue 13835 a = symbols('a') M = lambda n: Matrix([[i + a*j for i in range(n)] for j in range(n)]) assert M(5).det() == 0 assert M(6).det() == 0 assert M(7).det() == 0 def test_issue_14517(): M = Matrix([ [ 0, 10*I, 10*I, 0], [10*I, 0, 0, 10*I], [10*I, 0, 5 + 2*I, 10*I], [ 0, 10*I, 10*I, 5 + 2*I]]) ev = M.eigenvals() # test one random eigenvalue, the computation is a little slow test_ev = random.choice(list(ev.keys())) assert (M - test_ev*eye(4)).det() == 0 def test_legacy_det(): # Minimal support for legacy keys for 'method' in det() # Partially copied from test_determinant() M = Matrix(( ( 3, -2, 0, 5), (-2, 1, -2, 2), ( 0, -2, 5, 0), ( 5, 0, 3, 4) )) assert M.det(method="bareis") == -289 assert M.det(method="det_lu") == -289 assert M.det(method="det_LU") == -289 M = Matrix(( (3, 2, 0, 0, 0), (0, 3, 2, 0, 0), (0, 0, 3, 2, 0), (0, 0, 0, 3, 2), (2, 0, 0, 0, 3) )) assert M.det(method="bareis") == 275 assert M.det(method="det_lu") == 275 assert M.det(method="Bareis") == 275 M = Matrix(( (1, 0, 1, 2, 12), (2, 0, 1, 1, 4), (2, 1, 1, -1, 3), (3, 2, -1, 1, 8), (1, 1, 1, 0, 6) )) assert M.det(method="bareis") == -55 assert M.det(method="det_lu") == -55 assert M.det(method="BAREISS") == -55 M = Matrix(( ( 3, 0, 0, 0), (-2, 1, 0, 0), ( 0, -2, 5, 0), ( 5, 0, 3, 4) )) assert M.det(method="bareiss") == 60 assert M.det(method="berkowitz") == 60 assert M.det(method="lu") == 60 M = Matrix(( ( 1, 0, 0, 0), ( 5, 0, 0, 0), ( 9, 10, 11, 0), (13, 14, 15, 16) )) assert M.det(method="bareiss") == 0 assert M.det(method="berkowitz") == 0 assert M.det(method="lu") == 0 M = Matrix(( (3, 2, 0, 0, 0), (0, 3, 2, 0, 0), (0, 0, 3, 2, 0), (0, 0, 0, 3, 2), (0, 0, 0, 0, 3) )) assert M.det(method="bareiss") == 243 assert M.det(method="berkowitz") == 243 assert M.det(method="lu") == 243 M = Matrix(( (-5, 2, 3, 4, 5), ( 1, -4, 3, 4, 5), ( 1, 2, -3, 4, 5), ( 1, 2, 3, -2, 5), ( 1, 2, 3, 4, -1) )) assert M.det(method="bareis") == 11664 assert M.det(method="det_lu") == 11664 assert M.det(method="BERKOWITZ") == 11664 M = Matrix(( ( 2, 7, -1, 3, 2), ( 0, 0, 1, 0, 1), (-2, 0, 7, 0, 2), (-3, -2, 4, 5, 3), ( 1, 0, 0, 0, 1) )) assert M.det(method="bareis") == 123 assert M.det(method="det_lu") == 123 assert M.det(method="LU") == 123 def eye_Determinant(n): return Matrix(n, n, lambda i, j: int(i == j)) def zeros_Determinant(n): return Matrix(n, n, lambda i, j: 0) def test_det(): a = Matrix(2, 3, [1, 2, 3, 4, 5, 6]) raises(NonSquareMatrixError, lambda: a.det()) z = zeros_Determinant(2) ey = eye_Determinant(2) assert z.det() == 0 assert ey.det() == 1 x = Symbol('x') a = Matrix(0, 0, []) b = Matrix(1, 1, [5]) c = Matrix(2, 2, [1, 2, 3, 4]) d = Matrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 8]) e = Matrix(4, 4, [x, 1, 2, 3, 4, 5, 6, 7, 2, 9, 10, 11, 12, 13, 14, 14]) from sympy.abc import i, j, k, l, m, n f = Matrix(3, 3, [i, l, m, 0, j, n, 0, 0, k]) g = Matrix(3, 3, [i, 0, 0, l, j, 0, m, n, k]) h = Matrix(3, 3, [x**3, 0, 0, i, x**-1, 0, j, k, x**-2]) # the method keyword for `det` doesn't kick in until 4x4 matrices, # so there is no need to test all methods on smaller ones assert a.det() == 1 assert b.det() == 5 assert c.det() == -2 assert d.det() == 3 assert e.det() == 4*x - 24 assert e.det(method="domain-ge") == 4*x - 24 assert e.det(method='bareiss') == 4*x - 24 assert e.det(method='berkowitz') == 4*x - 24 assert f.det() == i*j*k assert g.det() == i*j*k assert h.det() == 1 raises(ValueError, lambda: e.det(iszerofunc="test")) def test_permanent(): M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) assert M.per() == 450 for i in range(1, 12): assert ones(i, i).per() == ones(i, i).T.per() == factorial(i) assert (ones(i, i)-eye(i)).per() == (ones(i, i)-eye(i)).T.per() == subfactorial(i) a1, a2, a3, a4, a5 = symbols('a_1 a_2 a_3 a_4 a_5') M = Matrix([a1, a2, a3, a4, a5]) assert M.per() == M.T.per() == a1 + a2 + a3 + a4 + a5 def test_adjugate(): x = Symbol('x') e = Matrix(4, 4, [x, 1, 2, 3, 4, 5, 6, 7, 2, 9, 10, 11, 12, 13, 14, 14]) adj = Matrix([ [ 4, -8, 4, 0], [ 76, -14*x - 68, 14*x - 8, -4*x + 24], [-122, 17*x + 142, -21*x + 4, 8*x - 48], [ 48, -4*x - 72, 8*x, -4*x + 24]]) assert e.adjugate() == adj assert e.adjugate(method='bareiss') == adj assert e.adjugate(method='berkowitz') == adj a = Matrix(2, 3, [1, 2, 3, 4, 5, 6]) raises(NonSquareMatrixError, lambda: a.adjugate()) def test_util(): R = Rational v1 = Matrix(1, 3, [1, 2, 3]) v2 = Matrix(1, 3, [3, 4, 5]) assert v1.norm() == sqrt(14) assert v1.project(v2) == Matrix(1, 3, [R(39)/25, R(52)/25, R(13)/5]) assert Matrix.zeros(1, 2) == Matrix(1, 2, [0, 0]) assert ones(1, 2) == Matrix(1, 2, [1, 1]) assert v1.copy() == v1 # cofactor assert eye(3) == eye(3).cofactor_matrix() test = Matrix([[1, 3, 2], [2, 6, 3], [2, 3, 6]]) assert test.cofactor_matrix() == \ Matrix([[27, -6, -6], [-12, 2, 3], [-3, 1, 0]]) test = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) assert test.cofactor_matrix() == \ Matrix([[-3, 6, -3], [6, -12, 6], [-3, 6, -3]]) def test_cofactor_and_minors(): x = Symbol('x') e = Matrix(4, 4, [x, 1, 2, 3, 4, 5, 6, 7, 2, 9, 10, 11, 12, 13, 14, 14]) m = Matrix([ [ x, 1, 3], [ 2, 9, 11], [12, 13, 14]]) cm = Matrix([ [ 4, 76, -122, 48], [-8, -14*x - 68, 17*x + 142, -4*x - 72], [ 4, 14*x - 8, -21*x + 4, 8*x], [ 0, -4*x + 24, 8*x - 48, -4*x + 24]]) sub = Matrix([ [x, 1, 2], [4, 5, 6], [2, 9, 10]]) assert e.minor_submatrix(1, 2) == m assert e.minor_submatrix(-1, -1) == sub assert e.minor(1, 2) == -17*x - 142 assert e.cofactor(1, 2) == 17*x + 142 assert e.cofactor_matrix() == cm assert e.cofactor_matrix(method="bareiss") == cm assert e.cofactor_matrix(method="berkowitz") == cm raises(ValueError, lambda: e.cofactor(4, 5)) raises(ValueError, lambda: e.minor(4, 5)) raises(ValueError, lambda: e.minor_submatrix(4, 5)) a = Matrix(2, 3, [1, 2, 3, 4, 5, 6]) assert a.minor_submatrix(0, 0) == Matrix([[5, 6]]) raises(ValueError, lambda: Matrix(0, 0, []).minor_submatrix(0, 0)) raises(NonSquareMatrixError, lambda: a.cofactor(0, 0)) raises(NonSquareMatrixError, lambda: a.minor(0, 0)) raises(NonSquareMatrixError, lambda: a.cofactor_matrix()) def test_charpoly(): x, y = Symbol('x'), Symbol('y') z, t = Symbol('z'), Symbol('t') from sympy.abc import a,b,c m = Matrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) assert eye_Determinant(3).charpoly(x) == Poly((x - 1)**3, x) assert eye_Determinant(3).charpoly(y) == Poly((y - 1)**3, y) assert m.charpoly() == Poly(x**3 - 15*x**2 - 18*x, x) raises(NonSquareMatrixError, lambda: Matrix([[1], [2]]).charpoly()) n = Matrix(4, 4, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) assert n.charpoly() == Poly(x**4, x) n = Matrix(4, 4, [45, 0, 0, 0, 0, 23, 0, 0, 0, 0, 87, 0, 0, 0, 0, 12]) assert n.charpoly() == Poly(x**4 - 167*x**3 + 8811*x**2 - 173457*x + 1080540, x) n = Matrix(3, 3, [x, 0, 0, a, y, 0, b, c, z]) assert n.charpoly() == Poly(t**3 - (x+y+z)*t**2 + t*(x*y+y*z+x*z) - x*y*z , t) sympy-sympy-1.9/sympy/matrices/tests/test_eigen.py000066400000000000000000000522611412543434000225630ustar00rootroot00000000000000from sympy import ( Rational, Symbol, N, I, Abs, sqrt, exp, Float, sin, cos, symbols) from sympy.matrices import eye, Matrix from sympy.core.singleton import S from sympy.testing.pytest import raises, XFAIL from sympy.matrices.matrices import NonSquareMatrixError, MatrixError from sympy.matrices.expressions.fourier import DFT from sympy.simplify.simplify import simplify from sympy.matrices.immutable import ImmutableMatrix from sympy.testing.pytest import slow from sympy.testing.matrices import allclose def test_eigen(): R = Rational M = Matrix.eye(3) assert M.eigenvals(multiple=False) == {S.One: 3} assert M.eigenvals(multiple=True) == [1, 1, 1] assert M.eigenvects() == ( [(1, 3, [Matrix([1, 0, 0]), Matrix([0, 1, 0]), Matrix([0, 0, 1])])]) assert M.left_eigenvects() == ( [(1, 3, [Matrix([[1, 0, 0]]), Matrix([[0, 1, 0]]), Matrix([[0, 0, 1]])])]) M = Matrix([[0, 1, 1], [1, 0, 0], [1, 1, 1]]) assert M.eigenvals() == {2*S.One: 1, -S.One: 1, S.Zero: 1} assert M.eigenvects() == ( [ (-1, 1, [Matrix([-1, 1, 0])]), ( 0, 1, [Matrix([0, -1, 1])]), ( 2, 1, [Matrix([R(2, 3), R(1, 3), 1])]) ]) assert M.left_eigenvects() == ( [ (-1, 1, [Matrix([[-2, 1, 1]])]), (0, 1, [Matrix([[-1, -1, 1]])]), (2, 1, [Matrix([[1, 1, 1]])]) ]) a = Symbol('a') M = Matrix([[a, 0], [0, 1]]) assert M.eigenvals() == {a: 1, S.One: 1} M = Matrix([[1, -1], [1, 3]]) assert M.eigenvects() == ([(2, 2, [Matrix(2, 1, [-1, 1])])]) assert M.left_eigenvects() == ([(2, 2, [Matrix([[1, 1]])])]) M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) a = R(15, 2) b = 3*33**R(1, 2) c = R(13, 2) d = (R(33, 8) + 3*b/8) e = (R(33, 8) - 3*b/8) def NS(e, n): return str(N(e, n)) r = [ (a - b/2, 1, [Matrix([(12 + 24/(c - b/2))/((c - b/2)*e) + 3/(c - b/2), (6 + 12/(c - b/2))/e, 1])]), ( 0, 1, [Matrix([1, -2, 1])]), (a + b/2, 1, [Matrix([(12 + 24/(c + b/2))/((c + b/2)*d) + 3/(c + b/2), (6 + 12/(c + b/2))/d, 1])]), ] r1 = [(NS(r[i][0], 2), NS(r[i][1], 2), [NS(j, 2) for j in r[i][2][0]]) for i in range(len(r))] r = M.eigenvects() r2 = [(NS(r[i][0], 2), NS(r[i][1], 2), [NS(j, 2) for j in r[i][2][0]]) for i in range(len(r))] assert sorted(r1) == sorted(r2) eps = Symbol('eps', real=True) M = Matrix([[abs(eps), I*eps ], [-I*eps, abs(eps) ]]) assert M.eigenvects() == ( [ ( 0, 1, [Matrix([[-I*eps/abs(eps)], [1]])]), ( 2*abs(eps), 1, [ Matrix([[I*eps/abs(eps)], [1]]) ] ), ]) assert M.left_eigenvects() == ( [ (0, 1, [Matrix([[I*eps/Abs(eps), 1]])]), (2*Abs(eps), 1, [Matrix([[-I*eps/Abs(eps), 1]])]) ]) M = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) M._eigenvects = M.eigenvects(simplify=False) assert max(i.q for i in M._eigenvects[0][2][0]) > 1 M._eigenvects = M.eigenvects(simplify=True) assert max(i.q for i in M._eigenvects[0][2][0]) == 1 M = Matrix([[Rational(1, 4), 1], [1, 1]]) assert M.eigenvects() == [ (Rational(5, 8) - sqrt(73)/8, 1, [Matrix([[-sqrt(73)/8 - Rational(3, 8)], [1]])]), (Rational(5, 8) + sqrt(73)/8, 1, [Matrix([[Rational(-3, 8) + sqrt(73)/8], [1]])])] # issue 10719 assert Matrix([]).eigenvals() == {} assert Matrix([]).eigenvals(multiple=True) == [] assert Matrix([]).eigenvects() == [] # issue 15119 raises(NonSquareMatrixError, lambda: Matrix([[1, 2], [0, 4], [0, 0]]).eigenvals()) raises(NonSquareMatrixError, lambda: Matrix([[1, 0], [3, 4], [5, 6]]).eigenvals()) raises(NonSquareMatrixError, lambda: Matrix([[1, 2, 3], [0, 5, 6]]).eigenvals()) raises(NonSquareMatrixError, lambda: Matrix([[1, 0, 0], [4, 5, 0]]).eigenvals()) raises(NonSquareMatrixError, lambda: Matrix([[1, 2, 3], [0, 5, 6]]).eigenvals( error_when_incomplete = False)) raises(NonSquareMatrixError, lambda: Matrix([[1, 0, 0], [4, 5, 0]]).eigenvals( error_when_incomplete = False)) m = Matrix([[1, 2], [3, 4]]) assert isinstance(m.eigenvals(simplify=True, multiple=False), dict) assert isinstance(m.eigenvals(simplify=True, multiple=True), list) assert isinstance(m.eigenvals(simplify=lambda x: x, multiple=False), dict) assert isinstance(m.eigenvals(simplify=lambda x: x, multiple=True), list) @slow def test_eigen_slow(): # issue 15125 from sympy.core.function import count_ops q = Symbol("q", positive = True) m = Matrix([[-2, exp(-q), 1], [exp(q), -2, 1], [1, 1, -2]]) assert count_ops(m.eigenvals(simplify=False)) > \ count_ops(m.eigenvals(simplify=True)) assert count_ops(m.eigenvals(simplify=lambda x: x)) > \ count_ops(m.eigenvals(simplify=True)) def test_float_eigenvals(): m = Matrix([[1, .6, .6], [.6, .9, .9], [.9, .6, .6]]) evals = [ Rational(5, 4) - sqrt(385)/20, sqrt(385)/20 + Rational(5, 4), S.Zero] n_evals = m.eigenvals(rational=True, multiple=True) n_evals = sorted(n_evals) s_evals = [x.evalf() for x in evals] s_evals = sorted(s_evals) for x, y in zip(n_evals, s_evals): assert abs(x-y) < 10**-9 @XFAIL def test_eigen_vects(): m = Matrix(2, 2, [1, 0, 0, I]) raises(NotImplementedError, lambda: m.is_diagonalizable(True)) # !!! bug because of eigenvects() or roots(x**2 + (-1 - I)*x + I, x) # see issue 5292 assert not m.is_diagonalizable(True) raises(MatrixError, lambda: m.diagonalize(True)) (P, D) = m.diagonalize(True) def test_issue_8240(): # Eigenvalues of large triangular matrices x, y = symbols('x y') n = 200 diagonal_variables = [Symbol('x%s' % i) for i in range(n)] M = [[0 for i in range(n)] for j in range(n)] for i in range(n): M[i][i] = diagonal_variables[i] M = Matrix(M) eigenvals = M.eigenvals() assert len(eigenvals) == n for i in range(n): assert eigenvals[diagonal_variables[i]] == 1 eigenvals = M.eigenvals(multiple=True) assert set(eigenvals) == set(diagonal_variables) # with multiplicity M = Matrix([[x, 0, 0], [1, y, 0], [2, 3, x]]) eigenvals = M.eigenvals() assert eigenvals == {x: 2, y: 1} eigenvals = M.eigenvals(multiple=True) assert len(eigenvals) == 3 assert eigenvals.count(x) == 2 assert eigenvals.count(y) == 1 def test_eigenvals(): M = Matrix([[0, 1, 1], [1, 0, 0], [1, 1, 1]]) assert M.eigenvals() == {2*S.One: 1, -S.One: 1, S.Zero: 1} m = Matrix([ [3, 0, 0, 0, -3], [0, -3, -3, 0, 3], [0, 3, 0, 3, 0], [0, 0, 3, 0, 3], [3, 0, 0, 3, 0]]) # XXX Used dry-run test because arbitrary symbol that appears in # CRootOf may not be unique. assert m.eigenvals() def test_eigenvects(): M = Matrix([[0, 1, 1], [1, 0, 0], [1, 1, 1]]) vecs = M.eigenvects() for val, mult, vec_list in vecs: assert len(vec_list) == 1 assert M*vec_list[0] == val*vec_list[0] def test_left_eigenvects(): M = Matrix([[0, 1, 1], [1, 0, 0], [1, 1, 1]]) vecs = M.left_eigenvects() for val, mult, vec_list in vecs: assert len(vec_list) == 1 assert vec_list[0]*M == val*vec_list[0] @slow def test_bidiagonalize(): M = Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) assert M.bidiagonalize() == M assert M.bidiagonalize(upper=False) == M assert M.bidiagonalize() == M assert M.bidiagonal_decomposition() == (M, M, M) assert M.bidiagonal_decomposition(upper=False) == (M, M, M) assert M.bidiagonalize() == M import random #Real Tests for real_test in range(2): test_values = [] row = 2 col = 2 for _ in range(row * col): value = random.randint(-1000000000, 1000000000) test_values = test_values + [value] # L -> Lower Bidiagonalization # M -> Mutable Matrix # N -> Immutable Matrix # 0 -> Bidiagonalized form # 1,2,3 -> Bidiagonal_decomposition matrices # 4 -> Product of 1 2 3 M = Matrix(row, col, test_values) N = ImmutableMatrix(M) N1, N2, N3 = N.bidiagonal_decomposition() M1, M2, M3 = M.bidiagonal_decomposition() M0 = M.bidiagonalize() N0 = N.bidiagonalize() N4 = N1 * N2 * N3 M4 = M1 * M2 * M3 N2.simplify() N4.simplify() N0.simplify() M0.simplify() M2.simplify() M4.simplify() LM0 = M.bidiagonalize(upper=False) LM1, LM2, LM3 = M.bidiagonal_decomposition(upper=False) LN0 = N.bidiagonalize(upper=False) LN1, LN2, LN3 = N.bidiagonal_decomposition(upper=False) LN4 = LN1 * LN2 * LN3 LM4 = LM1 * LM2 * LM3 LN2.simplify() LN4.simplify() LN0.simplify() LM0.simplify() LM2.simplify() LM4.simplify() assert M == M4 assert M2 == M0 assert N == N4 assert N2 == N0 assert M == LM4 assert LM2 == LM0 assert N == LN4 assert LN2 == LN0 #Complex Tests for complex_test in range(2): test_values = [] size = 2 for _ in range(size * size): real = random.randint(-1000000000, 1000000000) comp = random.randint(-1000000000, 1000000000) value = real + comp * I test_values = test_values + [value] M = Matrix(size, size, test_values) N = ImmutableMatrix(M) # L -> Lower Bidiagonalization # M -> Mutable Matrix # N -> Immutable Matrix # 0 -> Bidiagonalized form # 1,2,3 -> Bidiagonal_decomposition matrices # 4 -> Product of 1 2 3 N1, N2, N3 = N.bidiagonal_decomposition() M1, M2, M3 = M.bidiagonal_decomposition() M0 = M.bidiagonalize() N0 = N.bidiagonalize() N4 = N1 * N2 * N3 M4 = M1 * M2 * M3 N2.simplify() N4.simplify() N0.simplify() M0.simplify() M2.simplify() M4.simplify() LM0 = M.bidiagonalize(upper=False) LM1, LM2, LM3 = M.bidiagonal_decomposition(upper=False) LN0 = N.bidiagonalize(upper=False) LN1, LN2, LN3 = N.bidiagonal_decomposition(upper=False) LN4 = LN1 * LN2 * LN3 LM4 = LM1 * LM2 * LM3 LN2.simplify() LN4.simplify() LN0.simplify() LM0.simplify() LM2.simplify() LM4.simplify() assert M == M4 assert M2 == M0 assert N == N4 assert N2 == N0 assert M == LM4 assert LM2 == LM0 assert N == LN4 assert LN2 == LN0 M = Matrix(18, 8, range(1, 145)) M = M.applyfunc(lambda i: Float(i)) assert M.bidiagonal_decomposition()[1] == M.bidiagonalize() assert M.bidiagonal_decomposition(upper=False)[1] == M.bidiagonalize(upper=False) a, b, c = M.bidiagonal_decomposition() diff = a * b * c - M assert abs(max(diff)) < 10**-12 def test_diagonalize(): m = Matrix(2, 2, [0, -1, 1, 0]) raises(MatrixError, lambda: m.diagonalize(reals_only=True)) P, D = m.diagonalize() assert D.is_diagonal() assert D == Matrix([ [-I, 0], [ 0, I]]) # make sure we use floats out if floats are passed in m = Matrix(2, 2, [0, .5, .5, 0]) P, D = m.diagonalize() assert all(isinstance(e, Float) for e in D.values()) assert all(isinstance(e, Float) for e in P.values()) _, D2 = m.diagonalize(reals_only=True) assert D == D2 m = Matrix( [[0, 1, 0, 0], [1, 0, 0, 0.002], [0.002, 0, 0, 1], [0, 0, 1, 0]]) P, D = m.diagonalize() assert allclose(P*D, m*P) def test_is_diagonalizable(): a, b, c = symbols('a b c') m = Matrix(2, 2, [a, c, c, b]) assert m.is_symmetric() assert m.is_diagonalizable() assert not Matrix(2, 2, [1, 1, 0, 1]).is_diagonalizable() m = Matrix(2, 2, [0, -1, 1, 0]) assert m.is_diagonalizable() assert not m.is_diagonalizable(reals_only=True) def test_jordan_form(): m = Matrix(3, 2, [-3, 1, -3, 20, 3, 10]) raises(NonSquareMatrixError, lambda: m.jordan_form()) # the next two tests test the cases where the old # algorithm failed due to the fact that the block structure can # *NOT* be determined from algebraic and geometric multiplicity alone # This can be seen most easily when one lets compute the J.c.f. of a matrix that # is in J.c.f already. m = Matrix(4, 4, [2, 1, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 2 ]) P, J = m.jordan_form() assert m == J m = Matrix(4, 4, [2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2 ]) P, J = m.jordan_form() assert m == J A = Matrix([[ 2, 4, 1, 0], [-4, 2, 0, 1], [ 0, 0, 2, 4], [ 0, 0, -4, 2]]) P, J = A.jordan_form() assert simplify(P*J*P.inv()) == A assert Matrix(1, 1, [1]).jordan_form() == (Matrix([1]), Matrix([1])) assert Matrix(1, 1, [1]).jordan_form(calc_transform=False) == Matrix([1]) # If we have eigenvalues in CRootOf form, raise errors m = Matrix([[3, 0, 0, 0, -3], [0, -3, -3, 0, 3], [0, 3, 0, 3, 0], [0, 0, 3, 0, 3], [3, 0, 0, 3, 0]]) raises(MatrixError, lambda: m.jordan_form()) # make sure that if the input has floats, the output does too m = Matrix([ [ 0.6875, 0.125 + 0.1875*sqrt(3)], [0.125 + 0.1875*sqrt(3), 0.3125]]) P, J = m.jordan_form() assert all(isinstance(x, Float) or x == 0 for x in P) assert all(isinstance(x, Float) or x == 0 for x in J) def test_singular_values(): x = Symbol('x', real=True) A = Matrix([[0, 1*I], [2, 0]]) # if singular values can be sorted, they should be in decreasing order assert A.singular_values() == [2, 1] A = eye(3) A[1, 1] = x A[2, 2] = 5 vals = A.singular_values() # since Abs(x) cannot be sorted, test set equality assert set(vals) == {5, 1, Abs(x)} A = Matrix([[sin(x), cos(x)], [-cos(x), sin(x)]]) vals = [sv.trigsimp() for sv in A.singular_values()] assert vals == [S.One, S.One] A = Matrix([ [2, 4], [1, 3], [0, 0], [0, 0] ]) assert A.singular_values() == \ [sqrt(sqrt(221) + 15), sqrt(15 - sqrt(221))] assert A.T.singular_values() == \ [sqrt(sqrt(221) + 15), sqrt(15 - sqrt(221)), 0, 0] def test___eq__(): assert (Matrix( [[0, 1, 1], [1, 0, 0], [1, 1, 1]]) == {}) is False def test_definite(): # Examples from Gilbert Strang, "Introduction to Linear Algebra" # Positive definite matrices m = Matrix([[2, -1, 0], [-1, 2, -1], [0, -1, 2]]) assert m.is_positive_definite == True assert m.is_positive_semidefinite == True assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == False m = Matrix([[5, 4], [4, 5]]) assert m.is_positive_definite == True assert m.is_positive_semidefinite == True assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == False # Positive semidefinite matrices m = Matrix([[2, -1, -1], [-1, 2, -1], [-1, -1, 2]]) assert m.is_positive_definite == False assert m.is_positive_semidefinite == True assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == False m = Matrix([[1, 2], [2, 4]]) assert m.is_positive_definite == False assert m.is_positive_semidefinite == True assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == False # Examples from Mathematica documentation # Non-hermitian positive definite matrices m = Matrix([[2, 3], [4, 8]]) assert m.is_positive_definite == True assert m.is_positive_semidefinite == True assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == False # Hermetian matrices m = Matrix([[1, 2*I], [-I, 4]]) assert m.is_positive_definite == True assert m.is_positive_semidefinite == True assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == False # Symbolic matrices examples a = Symbol('a', positive=True) b = Symbol('b', negative=True) m = Matrix([[a, 0, 0], [0, a, 0], [0, 0, a]]) assert m.is_positive_definite == True assert m.is_positive_semidefinite == True assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == False m = Matrix([[b, 0, 0], [0, b, 0], [0, 0, b]]) assert m.is_positive_definite == False assert m.is_positive_semidefinite == False assert m.is_negative_definite == True assert m.is_negative_semidefinite == True assert m.is_indefinite == False m = Matrix([[a, 0], [0, b]]) assert m.is_positive_definite == False assert m.is_positive_semidefinite == False assert m.is_negative_definite == False assert m.is_negative_semidefinite == False assert m.is_indefinite == True m = Matrix([ [0.0228202735623867, 0.00518748979085398, -0.0743036351048907, -0.00709135324903921], [0.00518748979085398, 0.0349045359786350, 0.0830317991056637, 0.00233147902806909], [-0.0743036351048907, 0.0830317991056637, 1.15859676366277, 0.340359081555988], [-0.00709135324903921, 0.00233147902806909, 0.340359081555988, 0.928147644848199] ]) assert m.is_positive_definite == True assert m.is_positive_semidefinite == True assert m.is_indefinite == False # test for issue 19547: https://github.com/sympy/sympy/issues/19547 m = Matrix([ [0, 0, 0], [0, 1, 2], [0, 2, 1] ]) assert not m.is_positive_definite assert not m.is_positive_semidefinite def test_positive_semidefinite_cholesky(): from sympy.matrices.eigen import _is_positive_semidefinite_cholesky m = Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) assert _is_positive_semidefinite_cholesky(m) == True m = Matrix([[0, 0, 0], [0, 5, -10*I], [0, 10*I, 5]]) assert _is_positive_semidefinite_cholesky(m) == False m = Matrix([[1, 0, 0], [0, 0, 0], [0, 0, -1]]) assert _is_positive_semidefinite_cholesky(m) == False m = Matrix([[0, 1], [1, 0]]) assert _is_positive_semidefinite_cholesky(m) == False # https://www.value-at-risk.net/cholesky-factorization/ m = Matrix([[4, -2, -6], [-2, 10, 9], [-6, 9, 14]]) assert _is_positive_semidefinite_cholesky(m) == True m = Matrix([[9, -3, 3], [-3, 2, 1], [3, 1, 6]]) assert _is_positive_semidefinite_cholesky(m) == True m = Matrix([[4, -2, 2], [-2, 1, -1], [2, -1, 5]]) assert _is_positive_semidefinite_cholesky(m) == True m = Matrix([[1, 2, -1], [2, 5, 1], [-1, 1, 9]]) assert _is_positive_semidefinite_cholesky(m) == False def test_issue_20582(): A = Matrix([ [5, -5, -3, 2, -7], [-2, -5, 0, 2, 1], [-2, -7, -5, -2, -6], [7, 10, 3, 9, -2], [4, -10, 3, -8, -4] ]) # XXX Used dry-run test because arbitrary symbol that appears in # CRootOf may not be unique. assert A.eigenvects() def test_issue_20275(): # XXX We use complex expansions because complex exponentials are not # recognized by polys.domains A = DFT(3).as_explicit().expand(complex=True) eigenvects = A.eigenvects() assert eigenvects[0] == ( -1, 1, [Matrix([[1 - sqrt(3)], [1], [1]])] ) assert eigenvects[1] == ( 1, 1, [Matrix([[1 + sqrt(3)], [1], [1]])] ) assert eigenvects[2] == ( -I, 1, [Matrix([[0], [-1], [1]])] ) A = DFT(4).as_explicit().expand(complex=True) eigenvects = A.eigenvects() assert eigenvects[0] == ( -1, 1, [Matrix([[-1], [1], [1], [1]])] ) assert eigenvects[1] == ( 1, 2, [Matrix([[1], [0], [1], [0]]), Matrix([[2], [1], [0], [1]])] ) assert eigenvects[2] == ( -I, 1, [Matrix([[0], [-1], [0], [1]])] ) # XXX We skip test for some parts of eigenvectors which are very # complicated and fragile under expression tree changes A = DFT(5).as_explicit().expand(complex=True) eigenvects = A.eigenvects() assert eigenvects[0] == ( -1, 1, [Matrix([[1 - sqrt(5)], [1], [1], [1], [1]])] ) assert eigenvects[1] == ( 1, 2, [Matrix([[S(1)/2 + sqrt(5)/2], [0], [1], [1], [0]]), Matrix([[S(1)/2 + sqrt(5)/2], [1], [0], [0], [1]])] ) def test_issue_20752(): b = symbols('b', nonzero=True) m = Matrix([[0, 0, 0], [0, b, 0], [0, 0, b]]) assert m.is_positive_semidefinite is None sympy-sympy-1.9/sympy/matrices/tests/test_graph.py000066400000000000000000000062151412543434000225730ustar00rootroot00000000000000from sympy.combinatorics import Permutation from sympy.core.symbol import symbols from sympy.matrices import Matrix from sympy.matrices.expressions import ( PermutationMatrix, BlockDiagMatrix, BlockMatrix) def test_connected_components(): a, b, c, d, e, f, g, h, i, j, k, l, m = symbols('a:m') M = Matrix([ [a, 0, 0, 0, b, 0, 0, 0, 0, 0, c, 0, 0], [0, d, 0, 0, 0, e, 0, 0, 0, 0, 0, f, 0], [0, 0, g, 0, 0, 0, h, 0, 0, 0, 0, 0, i], [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [m, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, m, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0], [0, 0, m, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], [j, 0, 0, 0, k, 0, 0, 1, 0, 0, l, 0, 0], [0, j, 0, 0, 0, k, 0, 0, 1, 0, 0, l, 0], [0, 0, j, 0, 0, 0, k, 0, 0, 1, 0, 0, l], [0, 0, 0, 0, d, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, d, 0, 0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, d, 0, 0, 0, 0, 0, 1]]) cc = M.connected_components() assert cc == [[0, 4, 7, 10], [1, 5, 8, 11], [2, 6, 9, 12], [3]] P, B = M.connected_components_decomposition() p = Permutation([0, 4, 7, 10, 1, 5, 8, 11, 2, 6, 9, 12, 3]) assert P == PermutationMatrix(p) B0 = Matrix([ [a, b, 0, c], [m, 1, 0, 0], [j, k, 1, l], [0, d, 0, 1]]) B1 = Matrix([ [d, e, 0, f], [m, 1, 0, 0], [j, k, 1, l], [0, d, 0, 1]]) B2 = Matrix([ [g, h, 0, i], [m, 1, 0, 0], [j, k, 1, l], [0, d, 0, 1]]) B3 = Matrix([[1]]) assert B == BlockDiagMatrix(B0, B1, B2, B3) def test_strongly_connected_components(): M = Matrix([ [11, 14, 10, 0, 15, 0], [0, 44, 0, 0, 45, 0], [1, 4, 0, 0, 5, 0], [0, 0, 0, 22, 0, 23], [0, 54, 0, 0, 55, 0], [0, 0, 0, 32, 0, 33]]) scc = M.strongly_connected_components() assert scc == [[1, 4], [0, 2], [3, 5]] P, B = M.strongly_connected_components_decomposition() p = Permutation([1, 4, 0, 2, 3, 5]) assert P == PermutationMatrix(p) assert B == BlockMatrix([ [ Matrix([[44, 45], [54, 55]]), Matrix.zeros(2, 2), Matrix.zeros(2, 2) ], [ Matrix([[14, 15], [4, 5]]), Matrix([[11, 10], [1, 0]]), Matrix.zeros(2, 2) ], [ Matrix.zeros(2, 2), Matrix.zeros(2, 2), Matrix([[22, 23], [32, 33]]) ] ]) P = P.as_explicit() B = B.as_explicit() assert P.T * B * P == M P, B = M.strongly_connected_components_decomposition(lower=False) p = Permutation([3, 5, 0, 2, 1, 4]) assert P == PermutationMatrix(p) assert B == BlockMatrix([ [ Matrix([[22, 23], [32, 33]]), Matrix.zeros(2, 2), Matrix.zeros(2, 2) ], [ Matrix.zeros(2, 2), Matrix([[11, 10], [1, 0]]), Matrix([[14, 15], [4, 5]]) ], [ Matrix.zeros(2, 2), Matrix.zeros(2, 2), Matrix([[44, 45], [54, 55]]) ] ]) P = P.as_explicit() B = B.as_explicit() assert P.T * B * P == M sympy-sympy-1.9/sympy/matrices/tests/test_immutable.py000066400000000000000000000104771412543434000234560ustar00rootroot00000000000000from itertools import product from sympy import (ImmutableMatrix, Matrix, eye, zeros, S, Equality, Unequality, SparseMatrix, sympify, integrate) from sympy.matrices.immutable import \ ImmutableDenseMatrix, ImmutableSparseMatrix from sympy.abc import x, y from sympy.testing.pytest import raises IM = ImmutableDenseMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) ISM = ImmutableSparseMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) ieye = ImmutableDenseMatrix(eye(3)) def test_creation(): assert IM.shape == ISM.shape == (3, 3) assert IM[1, 2] == ISM[1, 2] == 6 assert IM[2, 2] == ISM[2, 2] == 9 def test_immutability(): with raises(TypeError): IM[2, 2] = 5 with raises(TypeError): ISM[2, 2] = 5 def test_slicing(): assert IM[1, :] == ImmutableDenseMatrix([[4, 5, 6]]) assert IM[:2, :2] == ImmutableDenseMatrix([[1, 2], [4, 5]]) assert ISM[1, :] == ImmutableSparseMatrix([[4, 5, 6]]) assert ISM[:2, :2] == ImmutableSparseMatrix([[1, 2], [4, 5]]) def test_subs(): A = ImmutableMatrix([[1, 2], [3, 4]]) B = ImmutableMatrix([[1, 2], [x, 4]]) C = ImmutableMatrix([[-x, x*y], [-(x + y), y**2]]) assert B.subs(x, 3) == A assert (x*B).subs(x, 3) == 3*A assert (x*eye(2) + B).subs(x, 3) == 3*eye(2) + A assert C.subs([[x, -1], [y, -2]]) == A assert C.subs([(x, -1), (y, -2)]) == A assert C.subs({x: -1, y: -2}) == A assert C.subs({x: y - 1, y: x - 1}, simultaneous=True) == \ ImmutableMatrix([[1 - y, (x - 1)*(y - 1)], [2 - x - y, (x - 1)**2]]) def test_as_immutable(): data = [[1, 2], [3, 4]] X = Matrix(data) assert sympify(X) == X.as_immutable() == ImmutableMatrix(data) data = {(0, 0): 1, (0, 1): 2, (1, 0): 3, (1, 1): 4} X = SparseMatrix(2, 2, data) assert sympify(X) == X.as_immutable() == ImmutableSparseMatrix(2, 2, data) def test_function_return_types(): # Lets ensure that decompositions of immutable matrices remain immutable # I.e. do MatrixBase methods return the correct class? X = ImmutableMatrix([[1, 2], [3, 4]]) Y = ImmutableMatrix([[1], [0]]) q, r = X.QRdecomposition() assert (type(q), type(r)) == (ImmutableMatrix, ImmutableMatrix) assert type(X.LUsolve(Y)) == ImmutableMatrix assert type(X.QRsolve(Y)) == ImmutableMatrix X = ImmutableMatrix([[5, 2], [2, 7]]) assert X.T == X assert X.is_symmetric assert type(X.cholesky()) == ImmutableMatrix L, D = X.LDLdecomposition() assert (type(L), type(D)) == (ImmutableMatrix, ImmutableMatrix) X = ImmutableMatrix([[1, 2], [2, 1]]) assert X.is_diagonalizable() assert X.det() == -3 assert X.norm(2) == 3 assert type(X.eigenvects()[0][2][0]) == ImmutableMatrix assert type(zeros(3, 3).as_immutable().nullspace()[0]) == ImmutableMatrix X = ImmutableMatrix([[1, 0], [2, 1]]) assert type(X.lower_triangular_solve(Y)) == ImmutableMatrix assert type(X.T.upper_triangular_solve(Y)) == ImmutableMatrix assert type(X.minor_submatrix(0, 0)) == ImmutableMatrix # issue 6279 # https://github.com/sympy/sympy/issues/6279 # Test that Immutable _op_ Immutable => Immutable and not MatExpr def test_immutable_evaluation(): X = ImmutableMatrix(eye(3)) A = ImmutableMatrix(3, 3, range(9)) assert isinstance(X + A, ImmutableMatrix) assert isinstance(X * A, ImmutableMatrix) assert isinstance(X * 2, ImmutableMatrix) assert isinstance(2 * X, ImmutableMatrix) assert isinstance(A**2, ImmutableMatrix) def test_deterimant(): assert ImmutableMatrix(4, 4, lambda i, j: i + j).det() == 0 def test_Equality(): assert Equality(IM, IM) is S.true assert Unequality(IM, IM) is S.false assert Equality(IM, IM.subs(1, 2)) is S.false assert Unequality(IM, IM.subs(1, 2)) is S.true assert Equality(IM, 2) is S.false assert Unequality(IM, 2) is S.true M = ImmutableMatrix([x, y]) assert Equality(M, IM) is S.false assert Unequality(M, IM) is S.true assert Equality(M, M.subs(x, 2)).subs(x, 2) is S.true assert Unequality(M, M.subs(x, 2)).subs(x, 2) is S.false assert Equality(M, M.subs(x, 2)).subs(x, 3) is S.false assert Unequality(M, M.subs(x, 2)).subs(x, 3) is S.true def test_integrate(): intIM = integrate(IM, x) assert intIM.shape == IM.shape assert all([intIM[i, j] == (1 + j + 3*i)*x for i, j in product(range(3), range(3))]) sympy-sympy-1.9/sympy/matrices/tests/test_interactions.py000066400000000000000000000040061412543434000241700ustar00rootroot00000000000000""" We have a few different kind of Matrices Matrix, ImmutableMatrix, MatrixExpr Here we test the extent to which they cooperate """ from sympy import symbols from sympy.matrices import (Matrix, MatrixSymbol, eye, Identity, ImmutableMatrix) from sympy.matrices.expressions import MatrixExpr, MatAdd from sympy.matrices.common import classof from sympy.testing.pytest import raises SM = MatrixSymbol('X', 3, 3) SV = MatrixSymbol('v', 3, 1) MM = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) IM = ImmutableMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) meye = eye(3) imeye = ImmutableMatrix(eye(3)) ideye = Identity(3) a, b, c = symbols('a,b,c') def test_IM_MM(): assert isinstance(MM + IM, ImmutableMatrix) assert isinstance(IM + MM, ImmutableMatrix) assert isinstance(2*IM + MM, ImmutableMatrix) assert MM.equals(IM) def test_ME_MM(): assert isinstance(Identity(3) + MM, MatrixExpr) assert isinstance(SM + MM, MatAdd) assert isinstance(MM + SM, MatAdd) assert (Identity(3) + MM)[1, 1] == 6 def test_equality(): a, b, c = Identity(3), eye(3), ImmutableMatrix(eye(3)) for x in [a, b, c]: for y in [a, b, c]: assert x.equals(y) def test_matrix_symbol_MM(): X = MatrixSymbol('X', 3, 3) Y = eye(3) + X assert Y[1, 1] == 1 + X[1, 1] def test_matrix_symbol_vector_matrix_multiplication(): A = MM * SV B = IM * SV assert A == B C = (SV.T * MM.T).T assert B == C D = (SV.T * IM.T).T assert C == D def test_indexing_interactions(): assert (a * IM)[1, 1] == 5*a assert (SM + IM)[1, 1] == SM[1, 1] + IM[1, 1] assert (SM * IM)[1, 1] == SM[1, 0]*IM[0, 1] + SM[1, 1]*IM[1, 1] + \ SM[1, 2]*IM[2, 1] def test_classof(): A = Matrix(3, 3, range(9)) B = ImmutableMatrix(3, 3, range(9)) C = MatrixSymbol('C', 3, 3) assert classof(A, A) == Matrix assert classof(B, B) == ImmutableMatrix assert classof(A, B) == ImmutableMatrix assert classof(B, A) == ImmutableMatrix raises(TypeError, lambda: classof(A, C)) sympy-sympy-1.9/sympy/matrices/tests/test_matrices.py000066400000000000000000004267671412543434000233230ustar00rootroot00000000000000import random import concurrent.futures from collections.abc import Hashable from sympy import ( Abs, Add, E, Float, I, Integer, Max, Min, Poly, Pow, PurePoly, Rational, S, Symbol, cos, exp, log, nan, oo, pi, signsimp, simplify, sin, sqrt, symbols, sympify, trigsimp, tan, sstr, diff, Function, expand, FiniteSet) from sympy.matrices.matrices import (ShapeError, MatrixError, NonSquareMatrixError, DeferredVector, _find_reasonable_pivot_naive, _simplify) from sympy.matrices import ( GramSchmidt, ImmutableMatrix, ImmutableSparseMatrix, Matrix, SparseMatrix, casoratian, diag, eye, hessian, matrix_multiply_elementwise, ones, randMatrix, rot_axis1, rot_axis2, rot_axis3, wronskian, zeros, MutableDenseMatrix, ImmutableDenseMatrix, MatrixSymbol, dotprodsimp) from sympy.matrices.utilities import _dotprodsimp_state from sympy.core.compatibility import iterable from sympy.core import Tuple, Wild from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.utilities.iterables import flatten, capture from sympy.testing.pytest import raises, XFAIL, slow, skip, warns_deprecated_sympy from sympy.assumptions import Q from sympy.tensor.array import Array from sympy.matrices.expressions import MatPow from sympy.abc import a, b, c, d, x, y, z, t # don't re-order this list classes = (Matrix, SparseMatrix, ImmutableMatrix, ImmutableSparseMatrix) def test_args(): for n, cls in enumerate(classes): m = cls.zeros(3, 2) # all should give back the same type of arguments, e.g. ints for shape assert m.shape == (3, 2) and all(type(i) is int for i in m.shape) assert m.rows == 3 and type(m.rows) is int assert m.cols == 2 and type(m.cols) is int if not n % 2: assert type(m.flat()) in (list, tuple, Tuple) else: assert type(m.todok()) is dict def test_deprecated_mat_smat(): for cls in Matrix, ImmutableMatrix: m = cls.zeros(3, 2) with warns_deprecated_sympy(): mat = m._mat assert mat == m.flat() for cls in SparseMatrix, ImmutableSparseMatrix: m = cls.zeros(3, 2) with warns_deprecated_sympy(): smat = m._smat assert smat == m.todok() def test_division(): v = Matrix(1, 2, [x, y]) assert v/z == Matrix(1, 2, [x/z, y/z]) def test_sum(): m = Matrix([[1, 2, 3], [x, y, x], [2*y, -50, z*x]]) assert m + m == Matrix([[2, 4, 6], [2*x, 2*y, 2*x], [4*y, -100, 2*z*x]]) n = Matrix(1, 2, [1, 2]) raises(ShapeError, lambda: m + n) def test_abs(): m = Matrix(1, 2, [-3, x]) n = Matrix(1, 2, [3, Abs(x)]) assert abs(m) == n def test_addition(): a = Matrix(( (1, 2), (3, 1), )) b = Matrix(( (1, 2), (3, 0), )) assert a + b == a.add(b) == Matrix([[2, 4], [6, 1]]) def test_fancy_index_matrix(): for M in (Matrix, SparseMatrix): a = M(3, 3, range(9)) assert a == a[:, :] assert a[1, :] == Matrix(1, 3, [3, 4, 5]) assert a[:, 1] == Matrix([1, 4, 7]) assert a[[0, 1], :] == Matrix([[0, 1, 2], [3, 4, 5]]) assert a[[0, 1], 2] == a[[0, 1], [2]] assert a[2, [0, 1]] == a[[2], [0, 1]] assert a[:, [0, 1]] == Matrix([[0, 1], [3, 4], [6, 7]]) assert a[0, 0] == 0 assert a[0:2, :] == Matrix([[0, 1, 2], [3, 4, 5]]) assert a[:, 0:2] == Matrix([[0, 1], [3, 4], [6, 7]]) assert a[::2, 1] == a[[0, 2], 1] assert a[1, ::2] == a[1, [0, 2]] a = M(3, 3, range(9)) assert a[[0, 2, 1, 2, 1], :] == Matrix([ [0, 1, 2], [6, 7, 8], [3, 4, 5], [6, 7, 8], [3, 4, 5]]) assert a[:, [0,2,1,2,1]] == Matrix([ [0, 2, 1, 2, 1], [3, 5, 4, 5, 4], [6, 8, 7, 8, 7]]) a = SparseMatrix.zeros(3) a[1, 2] = 2 a[0, 1] = 3 a[2, 0] = 4 assert a.extract([1, 1], [2]) == Matrix([ [2], [2]]) assert a.extract([1, 0], [2, 2, 2]) == Matrix([ [2, 2, 2], [0, 0, 0]]) assert a.extract([1, 0, 1, 2], [2, 0, 1, 0]) == Matrix([ [2, 0, 0, 0], [0, 0, 3, 0], [2, 0, 0, 0], [0, 4, 0, 4]]) def test_multiplication(): a = Matrix(( (1, 2), (3, 1), (0, 6), )) b = Matrix(( (1, 2), (3, 0), )) c = a*b assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 try: eval('c = a @ b') except SyntaxError: pass else: assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 h = matrix_multiply_elementwise(a, c) assert h == a.multiply_elementwise(c) assert h[0, 0] == 7 assert h[0, 1] == 4 assert h[1, 0] == 18 assert h[1, 1] == 6 assert h[2, 0] == 0 assert h[2, 1] == 0 raises(ShapeError, lambda: matrix_multiply_elementwise(a, b)) c = b * Symbol("x") assert isinstance(c, Matrix) assert c[0, 0] == x assert c[0, 1] == 2*x assert c[1, 0] == 3*x assert c[1, 1] == 0 c2 = x * b assert c == c2 c = 5 * b assert isinstance(c, Matrix) assert c[0, 0] == 5 assert c[0, 1] == 2*5 assert c[1, 0] == 3*5 assert c[1, 1] == 0 try: eval('c = 5 @ b') except SyntaxError: pass else: assert isinstance(c, Matrix) assert c[0, 0] == 5 assert c[0, 1] == 2*5 assert c[1, 0] == 3*5 assert c[1, 1] == 0 M = Matrix([[oo, 0], [0, oo]]) assert M ** 2 == M M = Matrix([[oo, oo], [0, 0]]) assert M ** 2 == Matrix([[nan, nan], [nan, nan]]) def test_power(): raises(NonSquareMatrixError, lambda: Matrix((1, 2))**2) R = Rational A = Matrix([[2, 3], [4, 5]]) assert (A**-3)[:] == [R(-269)/8, R(153)/8, R(51)/2, R(-29)/2] assert (A**5)[:] == [6140, 8097, 10796, 14237] A = Matrix([[2, 1, 3], [4, 2, 4], [6, 12, 1]]) assert (A**3)[:] == [290, 262, 251, 448, 440, 368, 702, 954, 433] assert A**0 == eye(3) assert A**1 == A assert (Matrix([[2]]) ** 100)[0, 0] == 2**100 assert eye(2)**10000000 == eye(2) assert Matrix([[1, 2], [3, 4]])**Integer(2) == Matrix([[7, 10], [15, 22]]) A = Matrix([[33, 24], [48, 57]]) assert (A**S.Half)[:] == [5, 2, 4, 7] A = Matrix([[0, 4], [-1, 5]]) assert (A**S.Half)**2 == A assert Matrix([[1, 0], [1, 1]])**S.Half == Matrix([[1, 0], [S.Half, 1]]) assert Matrix([[1, 0], [1, 1]])**0.5 == Matrix([[1.0, 0], [0.5, 1.0]]) from sympy.abc import a, b, n assert Matrix([[1, a], [0, 1]])**n == Matrix([[1, a*n], [0, 1]]) assert Matrix([[b, a], [0, b]])**n == Matrix([[b**n, a*b**(n-1)*n], [0, b**n]]) assert Matrix([ [a**n, a**(n - 1)*n, (a**n*n**2 - a**n*n)/(2*a**2)], [ 0, a**n, a**(n - 1)*n], [ 0, 0, a**n]]) assert Matrix([[a, 1, 0], [0, a, 0], [0, 0, b]])**n == Matrix([ [a**n, a**(n-1)*n, 0], [0, a**n, 0], [0, 0, b**n]]) A = Matrix([[1, 0], [1, 7]]) assert A._matrix_pow_by_jordan_blocks(S(3)) == A._eval_pow_by_recursion(3) A = Matrix([[2]]) assert A**10 == Matrix([[2**10]]) == A._matrix_pow_by_jordan_blocks(S(10)) == \ A._eval_pow_by_recursion(10) # testing a matrix that cannot be jordan blocked issue 11766 m = Matrix([[3, 0, 0, 0, -3], [0, -3, -3, 0, 3], [0, 3, 0, 3, 0], [0, 0, 3, 0, 3], [3, 0, 0, 3, 0]]) raises(MatrixError, lambda: m._matrix_pow_by_jordan_blocks(S(10))) # test issue 11964 raises(MatrixError, lambda: Matrix([[1, 1], [3, 3]])._matrix_pow_by_jordan_blocks(S(-10))) A = Matrix([[0, 1, 0], [0, 0, 1], [0, 0, 0]]) # Nilpotent jordan block size 3 assert A**10.0 == Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) raises(ValueError, lambda: A**2.1) raises(ValueError, lambda: A**Rational(3, 2)) A = Matrix([[8, 1], [3, 2]]) assert A**10.0 == Matrix([[1760744107, 272388050], [817164150, 126415807]]) A = Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]]) # Nilpotent jordan block size 1 assert A**10.0 == Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]]) A = Matrix([[0, 1, 0], [0, 0, 1], [0, 0, 1]]) # Nilpotent jordan block size 2 assert A**10.0 == Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]]) n = Symbol('n', integer=True) assert isinstance(A**n, MatPow) n = Symbol('n', integer=True, negative=True) raises(ValueError, lambda: A**n) n = Symbol('n', integer=True, nonnegative=True) assert A**n == Matrix([ [KroneckerDelta(0, n), KroneckerDelta(1, n), -KroneckerDelta(0, n) - KroneckerDelta(1, n) + 1], [ 0, KroneckerDelta(0, n), 1 - KroneckerDelta(0, n)], [ 0, 0, 1]]) assert A**(n + 2) == Matrix([[0, 0, 1], [0, 0, 1], [0, 0, 1]]) raises(ValueError, lambda: A**Rational(3, 2)) A = Matrix([[0, 0, 1], [3, 0, 1], [4, 3, 1]]) assert A**5.0 == Matrix([[168, 72, 89], [291, 144, 161], [572, 267, 329]]) assert A**5.0 == A**5 A = Matrix([[0, 1, 0],[-1, 0, 0],[0, 0, 0]]) n = Symbol("n") An = A**n assert An.subs(n, 2).doit() == A**2 raises(ValueError, lambda: An.subs(n, -2).doit()) assert An * An == A**(2*n) # concretizing behavior for non-integer and complex powers A = Matrix([[0,0,0],[0,0,0],[0,0,0]]) n = Symbol('n', integer=True, positive=True) assert A**n == A n = Symbol('n', integer=True, nonnegative=True) assert A**n == diag(0**n, 0**n, 0**n) assert (A**n).subs(n, 0) == eye(3) assert (A**n).subs(n, 1) == zeros(3) A = Matrix ([[2,0,0],[0,2,0],[0,0,2]]) assert A**2.1 == diag (2**2.1, 2**2.1, 2**2.1) assert A**I == diag (2**I, 2**I, 2**I) A = Matrix([[0, 1, 0], [0, 0, 1], [0, 0, 1]]) raises(ValueError, lambda: A**2.1) raises(ValueError, lambda: A**I) A = Matrix([[S.Half, S.Half], [S.Half, S.Half]]) assert A**S.Half == A A = Matrix([[1, 1],[3, 3]]) assert A**S.Half == Matrix ([[S.Half, S.Half], [3*S.Half, 3*S.Half]]) def test_issue_17247_expression_blowup_1(): M = Matrix([[1+x, 1-x], [1-x, 1+x]]) with dotprodsimp(True): assert M.exp().expand() == Matrix([ [ (exp(2*x) + exp(2))/2, (-exp(2*x) + exp(2))/2], [(-exp(2*x) + exp(2))/2, (exp(2*x) + exp(2))/2]]) def test_issue_17247_expression_blowup_2(): M = Matrix([[1+x, 1-x], [1-x, 1+x]]) with dotprodsimp(True): P, J = M.jordan_form () assert P*J*P.inv() def test_issue_17247_expression_blowup_3(): M = Matrix([[1+x, 1-x], [1-x, 1+x]]) with dotprodsimp(True): assert M**100 == Matrix([ [633825300114114700748351602688*x**100 + 633825300114114700748351602688, 633825300114114700748351602688 - 633825300114114700748351602688*x**100], [633825300114114700748351602688 - 633825300114114700748351602688*x**100, 633825300114114700748351602688*x**100 + 633825300114114700748351602688]]) def test_issue_17247_expression_blowup_4(): # This matrix takes extremely long on current master even with intermediate simplification so an abbreviated version is used. It is left here for test in case of future optimizations. # M = Matrix(S('''[ # [ -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64, 1/4 - 5*I/16, 65/128 + 87*I/64, -9/32 - I/16, 183/256 - 97*I/128, 3/64 + 13*I/64, -23/32 - 59*I/256, 15/128 - 3*I/32, 19/256 + 551*I/1024], # [-149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128, 85/256 - 33*I/16, 805/128 + 2415*I/512, -219/128 + 115*I/256, 6301/4096 - 6609*I/1024, 119/128 + 143*I/128, -10879/2048 + 4343*I/4096, 129/256 - 549*I/512, 42533/16384 + 29103*I/8192], # [ 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64, 1/4 - 5*I/16, 65/128 + 87*I/64, -9/32 - I/16, 183/256 - 97*I/128, 3/64 + 13*I/64, -23/32 - 59*I/256], # [ -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128, 85/256 - 33*I/16, 805/128 + 2415*I/512, -219/128 + 115*I/256, 6301/4096 - 6609*I/1024, 119/128 + 143*I/128, -10879/2048 + 4343*I/4096], # [ 1 + I, -19/4 + 5*I/4, 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64, 1/4 - 5*I/16, 65/128 + 87*I/64, -9/32 - I/16, 183/256 - 97*I/128], # [ 21/8 + I, -537/64 + 143*I/16, -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128, 85/256 - 33*I/16, 805/128 + 2415*I/512, -219/128 + 115*I/256, 6301/4096 - 6609*I/1024], # [ -2, 17/4 - 13*I/2, 1 + I, -19/4 + 5*I/4, 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64, 1/4 - 5*I/16, 65/128 + 87*I/64], # [ 1/4 + 13*I/4, -825/64 - 147*I/32, 21/8 + I, -537/64 + 143*I/16, -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128, 85/256 - 33*I/16, 805/128 + 2415*I/512], # [ -4*I, 27/2 + 6*I, -2, 17/4 - 13*I/2, 1 + I, -19/4 + 5*I/4, 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64], # [ 1/4 + 5*I/2, -23/8 - 57*I/16, 1/4 + 13*I/4, -825/64 - 147*I/32, 21/8 + I, -537/64 + 143*I/16, -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128], # [ -4, 9 - 5*I, -4*I, 27/2 + 6*I, -2, 17/4 - 13*I/2, 1 + I, -19/4 + 5*I/4, 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16], # [ -2*I, 119/8 + 29*I/4, 1/4 + 5*I/2, -23/8 - 57*I/16, 1/4 + 13*I/4, -825/64 - 147*I/32, 21/8 + I, -537/64 + 143*I/16, -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128]]''')) # assert M**10 == Matrix([ # [ 7*(-221393644768594642173548179825793834595 - 1861633166167425978847110897013541127952*I)/9671406556917033397649408, 15*(31670992489131684885307005100073928751695 + 10329090958303458811115024718207404523808*I)/77371252455336267181195264, 7*(-3710978679372178839237291049477017392703 + 1377706064483132637295566581525806894169*I)/19342813113834066795298816, (9727707023582419994616144751727760051598 - 59261571067013123836477348473611225724433*I)/9671406556917033397649408, (31896723509506857062605551443641668183707 + 54643444538699269118869436271152084599580*I)/38685626227668133590597632, (-2024044860947539028275487595741003997397402 + 130959428791783397562960461903698670485863*I)/309485009821345068724781056, 3*(26190251453797590396533756519358368860907 - 27221191754180839338002754608545400941638*I)/77371252455336267181195264, (1154643595139959842768960128434994698330461 + 3385496216250226964322872072260446072295634*I)/618970019642690137449562112, 3*(-31849347263064464698310044805285774295286 - 11877437776464148281991240541742691164309*I)/77371252455336267181195264, (4661330392283532534549306589669150228040221 - 4171259766019818631067810706563064103956871*I)/1237940039285380274899124224, (9598353794289061833850770474812760144506 + 358027153990999990968244906482319780943983*I)/309485009821345068724781056, (-9755135335127734571547571921702373498554177 - 4837981372692695195747379349593041939686540*I)/2475880078570760549798248448], # [(-379516731607474268954110071392894274962069 - 422272153179747548473724096872271700878296*I)/77371252455336267181195264, (41324748029613152354787280677832014263339501 - 12715121258662668420833935373453570749288074*I)/1237940039285380274899124224, (-339216903907423793947110742819264306542397 + 494174755147303922029979279454787373566517*I)/77371252455336267181195264, (-18121350839962855576667529908850640619878381 - 37413012454129786092962531597292531089199003*I)/1237940039285380274899124224, (2489661087330511608618880408199633556675926 + 1137821536550153872137379935240732287260863*I)/309485009821345068724781056, (-136644109701594123227587016790354220062972119 + 110130123468183660555391413889600443583585272*I)/4951760157141521099596496896, (1488043981274920070468141664150073426459593 - 9691968079933445130866371609614474474327650*I)/1237940039285380274899124224, 27*(4636797403026872518131756991410164760195942 + 3369103221138229204457272860484005850416533*I)/4951760157141521099596496896, (-8534279107365915284081669381642269800472363 + 2241118846262661434336333368511372725482742*I)/1237940039285380274899124224, (60923350128174260992536531692058086830950875 - 263673488093551053385865699805250505661590126*I)/9903520314283042199192993792, (18520943561240714459282253753348921824172569 + 24846649186468656345966986622110971925703604*I)/4951760157141521099596496896, (-232781130692604829085973604213529649638644431 + 35981505277760667933017117949103953338570617*I)/9903520314283042199192993792], # [ (8742968295129404279528270438201520488950 + 3061473358639249112126847237482570858327*I)/4835703278458516698824704, (-245657313712011778432792959787098074935273 + 253113767861878869678042729088355086740856*I)/38685626227668133590597632, (1947031161734702327107371192008011621193 - 19462330079296259148177542369999791122762*I)/9671406556917033397649408, (552856485625209001527688949522750288619217 + 392928441196156725372494335248099016686580*I)/77371252455336267181195264, (-44542866621905323121630214897126343414629 + 3265340021421335059323962377647649632959*I)/19342813113834066795298816, (136272594005759723105646069956434264218730 - 330975364731707309489523680957584684763587*I)/38685626227668133590597632, (27392593965554149283318732469825168894401 + 75157071243800133880129376047131061115278*I)/38685626227668133590597632, 7*(-357821652913266734749960136017214096276154 - 45509144466378076475315751988405961498243*I)/309485009821345068724781056, (104485001373574280824835174390219397141149 - 99041000529599568255829489765415726168162*I)/77371252455336267181195264, (1198066993119982409323525798509037696321291 + 4249784165667887866939369628840569844519936*I)/618970019642690137449562112, (-114985392587849953209115599084503853611014 - 52510376847189529234864487459476242883449*I)/77371252455336267181195264, (6094620517051332877965959223269600650951573 - 4683469779240530439185019982269137976201163*I)/1237940039285380274899124224], # [ (611292255597977285752123848828590587708323 - 216821743518546668382662964473055912169502*I)/77371252455336267181195264, (-1144023204575811464652692396337616594307487 + 12295317806312398617498029126807758490062855*I)/309485009821345068724781056, (-374093027769390002505693378578475235158281 - 573533923565898290299607461660384634333639*I)/77371252455336267181195264, (47405570632186659000138546955372796986832987 - 2837476058950808941605000274055970055096534*I)/1237940039285380274899124224, (-571573207393621076306216726219753090535121 + 533381457185823100878764749236639320783831*I)/77371252455336267181195264, (-7096548151856165056213543560958582513797519 - 24035731898756040059329175131592138642195366*I)/618970019642690137449562112, (2396762128833271142000266170154694033849225 + 1448501087375679588770230529017516492953051*I)/309485009821345068724781056, (-150609293845161968447166237242456473262037053 + 92581148080922977153207018003184520294188436*I)/4951760157141521099596496896, 5*(270278244730804315149356082977618054486347 - 1997830155222496880429743815321662710091562*I)/1237940039285380274899124224, (62978424789588828258068912690172109324360330 + 44803641177219298311493356929537007630129097*I)/2475880078570760549798248448, 19*(-451431106327656743945775812536216598712236 + 114924966793632084379437683991151177407937*I)/1237940039285380274899124224, (63417747628891221594106738815256002143915995 - 261508229397507037136324178612212080871150958*I)/9903520314283042199192993792], # [ (-2144231934021288786200752920446633703357 + 2305614436009705803670842248131563850246*I)/1208925819614629174706176, (-90720949337459896266067589013987007078153 - 221951119475096403601562347412753844534569*I)/19342813113834066795298816, (11590973613116630788176337262688659880376 + 6514520676308992726483494976339330626159*I)/4835703278458516698824704, 3*(-131776217149000326618649542018343107657237 + 79095042939612668486212006406818285287004*I)/38685626227668133590597632, (10100577916793945997239221374025741184951 - 28631383488085522003281589065994018550748*I)/9671406556917033397649408, 67*(10090295594251078955008130473573667572549 + 10449901522697161049513326446427839676762*I)/77371252455336267181195264, (-54270981296988368730689531355811033930513 - 3413683117592637309471893510944045467443*I)/19342813113834066795298816, (440372322928679910536575560069973699181278 - 736603803202303189048085196176918214409081*I)/77371252455336267181195264, (33220374714789391132887731139763250155295 + 92055083048787219934030779066298919603554*I)/38685626227668133590597632, 5*(-594638554579967244348856981610805281527116 - 82309245323128933521987392165716076704057*I)/309485009821345068724781056, (128056368815300084550013708313312073721955 - 114619107488668120303579745393765245911404*I)/77371252455336267181195264, 21*(59839959255173222962789517794121843393573 + 241507883613676387255359616163487405826334*I)/618970019642690137449562112], # [ (-13454485022325376674626653802541391955147 + 184471402121905621396582628515905949793486*I)/19342813113834066795298816, (-6158730123400322562149780662133074862437105 - 3416173052604643794120262081623703514107476*I)/154742504910672534362390528, (770558003844914708453618983120686116100419 - 127758381209767638635199674005029818518766*I)/77371252455336267181195264, (-4693005771813492267479835161596671660631703 + 12703585094750991389845384539501921531449948*I)/309485009821345068724781056, (-295028157441149027913545676461260860036601 - 841544569970643160358138082317324743450770*I)/77371252455336267181195264, (56716442796929448856312202561538574275502893 + 7216818824772560379753073185990186711454778*I)/1237940039285380274899124224, 15*(-87061038932753366532685677510172566368387 + 61306141156647596310941396434445461895538*I)/154742504910672534362390528, (-3455315109680781412178133042301025723909347 - 24969329563196972466388460746447646686670670*I)/618970019642690137449562112, (2453418854160886481106557323699250865361849 + 1497886802326243014471854112161398141242514*I)/309485009821345068724781056, (-151343224544252091980004429001205664193082173 + 90471883264187337053549090899816228846836628*I)/4951760157141521099596496896, (1652018205533026103358164026239417416432989 - 9959733619236515024261775397109724431400162*I)/1237940039285380274899124224, 3*(40676374242956907656984876692623172736522006 + 31023357083037817469535762230872667581366205*I)/4951760157141521099596496896], # [ (-1226990509403328460274658603410696548387 - 4131739423109992672186585941938392788458*I)/1208925819614629174706176, (162392818524418973411975140074368079662703 + 23706194236915374831230612374344230400704*I)/9671406556917033397649408, (-3935678233089814180000602553655565621193 + 2283744757287145199688061892165659502483*I)/1208925819614629174706176, (-2400210250844254483454290806930306285131 - 315571356806370996069052930302295432758205*I)/19342813113834066795298816, (13365917938215281056563183751673390817910 + 15911483133819801118348625831132324863881*I)/4835703278458516698824704, 3*(-215950551370668982657516660700301003897855 + 51684341999223632631602864028309400489378*I)/38685626227668133590597632, (20886089946811765149439844691320027184765 - 30806277083146786592790625980769214361844*I)/9671406556917033397649408, (562180634592713285745940856221105667874855 + 1031543963988260765153550559766662245114916*I)/77371252455336267181195264, (-65820625814810177122941758625652476012867 - 12429918324787060890804395323920477537595*I)/19342813113834066795298816, (319147848192012911298771180196635859221089 - 402403304933906769233365689834404519960394*I)/38685626227668133590597632, (23035615120921026080284733394359587955057 + 115351677687031786114651452775242461310624*I)/38685626227668133590597632, (-3426830634881892756966440108592579264936130 - 1022954961164128745603407283836365128598559*I)/309485009821345068724781056], # [ (-192574788060137531023716449082856117537757 - 69222967328876859586831013062387845780692*I)/19342813113834066795298816, (2736383768828013152914815341491629299773262 - 2773252698016291897599353862072533475408743*I)/77371252455336267181195264, (-23280005281223837717773057436155921656805 + 214784953368021840006305033048142888879224*I)/19342813113834066795298816, (-3035247484028969580570400133318947903462326 - 2195168903335435855621328554626336958674325*I)/77371252455336267181195264, (984552428291526892214541708637840971548653 - 64006622534521425620714598573494988589378*I)/77371252455336267181195264, (-3070650452470333005276715136041262898509903 + 7286424705750810474140953092161794621989080*I)/154742504910672534362390528, (-147848877109756404594659513386972921139270 - 416306113044186424749331418059456047650861*I)/38685626227668133590597632, (55272118474097814260289392337160619494260781 + 7494019668394781211907115583302403519488058*I)/1237940039285380274899124224, (-581537886583682322424771088996959213068864 + 542191617758465339135308203815256798407429*I)/77371252455336267181195264, (-6422548983676355789975736799494791970390991 - 23524183982209004826464749309156698827737702*I)/618970019642690137449562112, 7*(180747195387024536886923192475064903482083 + 84352527693562434817771649853047924991804*I)/154742504910672534362390528, (-135485179036717001055310712747643466592387031 + 102346575226653028836678855697782273460527608*I)/4951760157141521099596496896], # [ (3384238362616083147067025892852431152105 + 156724444932584900214919898954874618256*I)/604462909807314587353088, (-59558300950677430189587207338385764871866 + 114427143574375271097298201388331237478857*I)/4835703278458516698824704, (-1356835789870635633517710130971800616227 - 7023484098542340388800213478357340875410*I)/1208925819614629174706176, (234884918567993750975181728413524549575881 + 79757294640629983786895695752733890213506*I)/9671406556917033397649408, (-7632732774935120473359202657160313866419 + 2905452608512927560554702228553291839465*I)/1208925819614629174706176, (52291747908702842344842889809762246649489 - 520996778817151392090736149644507525892649*I)/19342813113834066795298816, (17472406829219127839967951180375981717322 + 23464704213841582137898905375041819568669*I)/4835703278458516698824704, (-911026971811893092350229536132730760943307 + 150799318130900944080399439626714846752360*I)/38685626227668133590597632, (26234457233977042811089020440646443590687 - 45650293039576452023692126463683727692890*I)/9671406556917033397649408, 3*(288348388717468992528382586652654351121357 + 454526517721403048270274049572136109264668*I)/77371252455336267181195264, (-91583492367747094223295011999405657956347 - 12704691128268298435362255538069612411331*I)/19342813113834066795298816, (411208730251327843849027957710164064354221 - 569898526380691606955496789378230959965898*I)/38685626227668133590597632], # [ (27127513117071487872628354831658811211795 - 37765296987901990355760582016892124833857*I)/4835703278458516698824704, (1741779916057680444272938534338833170625435 + 3083041729779495966997526404685535449810378*I)/77371252455336267181195264, 3*(-60642236251815783728374561836962709533401 - 24630301165439580049891518846174101510744*I)/19342813113834066795298816, 3*(445885207364591681637745678755008757483408 - 350948497734812895032502179455610024541643*I)/38685626227668133590597632, (-47373295621391195484367368282471381775684 + 219122969294089357477027867028071400054973*I)/19342813113834066795298816, (-2801565819673198722993348253876353741520438 - 2250142129822658548391697042460298703335701*I)/77371252455336267181195264, (801448252275607253266997552356128790317119 - 50890367688077858227059515894356594900558*I)/77371252455336267181195264, (-5082187758525931944557763799137987573501207 + 11610432359082071866576699236013484487676124*I)/309485009821345068724781056, (-328925127096560623794883760398247685166830 - 643447969697471610060622160899409680422019*I)/77371252455336267181195264, 15*(2954944669454003684028194956846659916299765 + 33434406416888505837444969347824812608566*I)/1237940039285380274899124224, (-415749104352001509942256567958449835766827 + 479330966144175743357171151440020955412219*I)/77371252455336267181195264, 3*(-4639987285852134369449873547637372282914255 - 11994411888966030153196659207284951579243273*I)/1237940039285380274899124224], # [ (-478846096206269117345024348666145495601 + 1249092488629201351470551186322814883283*I)/302231454903657293676544, (-17749319421930878799354766626365926894989 - 18264580106418628161818752318217357231971*I)/1208925819614629174706176, (2801110795431528876849623279389579072819 + 363258850073786330770713557775566973248*I)/604462909807314587353088, (-59053496693129013745775512127095650616252 + 78143588734197260279248498898321500167517*I)/4835703278458516698824704, (-283186724922498212468162690097101115349 - 6443437753863179883794497936345437398276*I)/1208925819614629174706176, (188799118826748909206887165661384998787543 + 84274736720556630026311383931055307398820*I)/9671406556917033397649408, (-5482217151670072904078758141270295025989 + 1818284338672191024475557065444481298568*I)/1208925819614629174706176, (56564463395350195513805521309731217952281 - 360208541416798112109946262159695452898431*I)/19342813113834066795298816, 11*(1259539805728870739006416869463689438068 + 1409136581547898074455004171305324917387*I)/4835703278458516698824704, 5*(-123701190701414554945251071190688818343325 + 30997157322590424677294553832111902279712*I)/38685626227668133590597632, (16130917381301373033736295883982414239781 - 32752041297570919727145380131926943374516*I)/9671406556917033397649408, (650301385108223834347093740500375498354925 + 899526407681131828596801223402866051809258*I)/77371252455336267181195264], # [ (9011388245256140876590294262420614839483 + 8167917972423946282513000869327525382672*I)/1208925819614629174706176, (-426393174084720190126376382194036323028924 + 180692224825757525982858693158209545430621*I)/9671406556917033397649408, (24588556702197802674765733448108154175535 - 45091766022876486566421953254051868331066*I)/4835703278458516698824704, (1872113939365285277373877183750416985089691 + 3030392393733212574744122057679633775773130*I)/77371252455336267181195264, (-222173405538046189185754954524429864167549 - 75193157893478637039381059488387511299116*I)/19342813113834066795298816, (2670821320766222522963689317316937579844558 - 2645837121493554383087981511645435472169191*I)/77371252455336267181195264, 5*(-2100110309556476773796963197283876204940 + 41957457246479840487980315496957337371937*I)/19342813113834066795298816, (-5733743755499084165382383818991531258980593 - 3328949988392698205198574824396695027195732*I)/154742504910672534362390528, (707827994365259025461378911159398206329247 - 265730616623227695108042528694302299777294*I)/77371252455336267181195264, (-1442501604682933002895864804409322823788319 + 11504137805563265043376405214378288793343879*I)/309485009821345068724781056, (-56130472299445561499538726459719629522285 - 61117552419727805035810982426639329818864*I)/9671406556917033397649408, (39053692321126079849054272431599539429908717 - 10209127700342570953247177602860848130710666*I)/1237940039285380274899124224]]) M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64, 1/4 - 5*I/16, 65/128 + 87*I/64], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128, 85/256 - 33*I/16, 805/128 + 2415*I/512], [ 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64], [ -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128], [ 1 + I, -19/4 + 5*I/4, 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16], [ 21/8 + I, -537/64 + 143*I/16, -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M**10 == Matrix(S('''[ [ 7369525394972778926719607798014571861/604462909807314587353088 - 229284202061790301477392339912557559*I/151115727451828646838272, -19704281515163975949388435612632058035/1208925819614629174706176 + 14319858347987648723768698170712102887*I/302231454903657293676544, -3623281909451783042932142262164941211/604462909807314587353088 - 6039240602494288615094338643452320495*I/604462909807314587353088, 109260497799140408739847239685705357695/2417851639229258349412352 - 7427566006564572463236368211555511431*I/2417851639229258349412352, -16095803767674394244695716092817006641/2417851639229258349412352 + 10336681897356760057393429626719177583*I/1208925819614629174706176, -42207883340488041844332828574359769743/2417851639229258349412352 - 182332262671671273188016400290188468499*I/4835703278458516698824704], [50566491050825573392726324995779608259/1208925819614629174706176 - 90047007594468146222002432884052362145*I/2417851639229258349412352, 74273703462900000967697427843983822011/1208925819614629174706176 + 265947522682943571171988741842776095421*I/1208925819614629174706176, -116900341394390200556829767923360888429/2417851639229258349412352 - 53153263356679268823910621474478756845*I/2417851639229258349412352, 195407378023867871243426523048612490249/1208925819614629174706176 - 1242417915995360200584837585002906728929*I/9671406556917033397649408, -863597594389821970177319682495878193/302231454903657293676544 + 476936100741548328800725360758734300481*I/9671406556917033397649408, -3154451590535653853562472176601754835575/19342813113834066795298816 - 232909875490506237386836489998407329215*I/2417851639229258349412352], [ -1715444997702484578716037230949868543/302231454903657293676544 + 5009695651321306866158517287924120777*I/302231454903657293676544, -30551582497996879620371947949342101301/604462909807314587353088 - 7632518367986526187139161303331519629*I/151115727451828646838272, 312680739924495153190604170938220575/18889465931478580854784 - 108664334509328818765959789219208459*I/75557863725914323419136, -14693696966703036206178521686918865509/604462909807314587353088 + 72345386220900843930147151999899692401*I/1208925819614629174706176, -8218872496728882299722894680635296519/1208925819614629174706176 - 16776782833358893712645864791807664983*I/1208925819614629174706176, 143237839169380078671242929143670635137/2417851639229258349412352 + 2883817094806115974748882735218469447*I/2417851639229258349412352], [ 3087979417831061365023111800749855987/151115727451828646838272 + 34441942370802869368851419102423997089*I/604462909807314587353088, -148309181940158040917731426845476175667/604462909807314587353088 - 263987151804109387844966835369350904919*I/9671406556917033397649408, 50259518594816377378747711930008883165/1208925819614629174706176 - 95713974916869240305450001443767979653*I/2417851639229258349412352, 153466447023875527996457943521467271119/2417851639229258349412352 + 517285524891117105834922278517084871349*I/2417851639229258349412352, -29184653615412989036678939366291205575/604462909807314587353088 - 27551322282526322041080173287022121083*I/1208925819614629174706176, 196404220110085511863671393922447671649/1208925819614629174706176 - 1204712019400186021982272049902206202145*I/9671406556917033397649408], [ -2632581805949645784625606590600098779/151115727451828646838272 - 589957435912868015140272627522612771*I/37778931862957161709568, 26727850893953715274702844733506310247/302231454903657293676544 - 10825791956782128799168209600694020481*I/302231454903657293676544, -1036348763702366164044671908440791295/151115727451828646838272 + 3188624571414467767868303105288107375*I/151115727451828646838272, -36814959939970644875593411585393242449/604462909807314587353088 - 18457555789119782404850043842902832647*I/302231454903657293676544, 12454491297984637815063964572803058647/604462909807314587353088 - 340489532842249733975074349495329171*I/302231454903657293676544, -19547211751145597258386735573258916681/604462909807314587353088 + 87299583775782199663414539883938008933*I/1208925819614629174706176], [ -40281994229560039213253423262678393183/604462909807314587353088 - 2939986850065527327299273003299736641*I/604462909807314587353088, 331940684638052085845743020267462794181/2417851639229258349412352 - 284574901963624403933361315517248458969*I/1208925819614629174706176, 6453843623051745485064693628073010961/302231454903657293676544 + 36062454107479732681350914931391590957*I/604462909807314587353088, -147665869053634695632880753646441962067/604462909807314587353088 - 305987938660447291246597544085345123927*I/9671406556917033397649408, 107821369195275772166593879711259469423/2417851639229258349412352 - 11645185518211204108659001435013326687*I/302231454903657293676544, 64121228424717666402009446088588091619/1208925819614629174706176 + 265557133337095047883844369272389762133*I/1208925819614629174706176]]''')) def test_issue_17247_expression_blowup_5(): M = Matrix(6, 6, lambda i, j: 1 + (-1)**(i+j)*I) with dotprodsimp(True): assert M.charpoly('x') == PurePoly(x**6 + (-6 - 6*I)*x**5 + 36*I*x**4, x, domain='EX') def test_issue_17247_expression_blowup_6(): M = Matrix(8, 8, [x+i for i in range (64)]) with dotprodsimp(True): assert M.det('bareiss') == 0 def test_issue_17247_expression_blowup_7(): M = Matrix(6, 6, lambda i, j: 1 + (-1)**(i+j)*I) with dotprodsimp(True): assert M.det('berkowitz') == 0 def test_issue_17247_expression_blowup_8(): M = Matrix(8, 8, [x+i for i in range (64)]) with dotprodsimp(True): assert M.det('lu') == 0 def test_issue_17247_expression_blowup_9(): M = Matrix(8, 8, [x+i for i in range (64)]) with dotprodsimp(True): assert M.rref() == (Matrix([ [1, 0, -1, -2, -3, -4, -5, -6], [0, 1, 2, 3, 4, 5, 6, 7], [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)) def test_issue_17247_expression_blowup_10(): M = Matrix(6, 6, lambda i, j: 1 + (-1)**(i+j)*I) with dotprodsimp(True): assert M.cofactor(0, 0) == 0 def test_issue_17247_expression_blowup_11(): M = Matrix(6, 6, lambda i, j: 1 + (-1)**(i+j)*I) with dotprodsimp(True): assert M.cofactor_matrix() == Matrix(6, 6, [0]*36) def test_issue_17247_expression_blowup_12(): M = Matrix(6, 6, lambda i, j: 1 + (-1)**(i+j)*I) with dotprodsimp(True): assert M.eigenvals() == {6: 1, 6*I: 1, 0: 4} def test_issue_17247_expression_blowup_13(): M = Matrix([ [ 0, 1 - x, x + 1, 1 - x], [1 - x, x + 1, 0, x + 1], [ 0, 1 - x, x + 1, 1 - x], [ 0, 0, 1 - x, 0]]) ev = M.eigenvects() assert ev[0] == (0, 2, [Matrix([0, -1, 0, 1])]) assert ev[1][0] == x - sqrt(2)*(x - 1) + 1 assert ev[1][1] == 1 assert ev[1][2][0].expand(deep=False, numer=True) == Matrix([ [(-x + sqrt(2)*(x - 1) - 1)/(x - 1)], [-4*x/(x**2 - 2*x + 1) + (x + 1)*(x - sqrt(2)*(x - 1) + 1)/(x**2 - 2*x + 1)], [(-x + sqrt(2)*(x - 1) - 1)/(x - 1)], [1] ]) assert ev[2][0] == x + sqrt(2)*(x - 1) + 1 assert ev[2][1] == 1 assert ev[2][2][0].expand(deep=False, numer=True) == Matrix([ [(-x - sqrt(2)*(x - 1) - 1)/(x - 1)], [-4*x/(x**2 - 2*x + 1) + (x + 1)*(x + sqrt(2)*(x - 1) + 1)/(x**2 - 2*x + 1)], [(-x - sqrt(2)*(x - 1) - 1)/(x - 1)], [1] ]) def test_issue_17247_expression_blowup_14(): M = Matrix(8, 8, ([1+x, 1-x]*4 + [1-x, 1+x]*4)*4) with dotprodsimp(True): assert M.echelon_form() == Matrix([ [x + 1, 1 - x, x + 1, 1 - x, x + 1, 1 - x, x + 1, 1 - x], [ 0, 4*x, 0, 4*x, 0, 4*x, 0, 4*x], [ 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]]) def test_issue_17247_expression_blowup_15(): M = Matrix(8, 8, ([1+x, 1-x]*4 + [1-x, 1+x]*4)*4) with dotprodsimp(True): assert M.rowspace() == [Matrix([[x + 1, 1 - x, x + 1, 1 - x, x + 1, 1 - x, x + 1, 1 - x]]), Matrix([[0, 4*x, 0, 4*x, 0, 4*x, 0, 4*x]])] def test_issue_17247_expression_blowup_16(): M = Matrix(8, 8, ([1+x, 1-x]*4 + [1-x, 1+x]*4)*4) with dotprodsimp(True): assert M.columnspace() == [Matrix([[x + 1],[1 - x],[x + 1],[1 - x],[x + 1],[1 - x],[x + 1],[1 - x]]), Matrix([[1 - x],[x + 1],[1 - x],[x + 1],[1 - x],[x + 1],[1 - x],[x + 1]])] def test_issue_17247_expression_blowup_17(): M = Matrix(8, 8, [x+i for i in range (64)]) with dotprodsimp(True): assert M.nullspace() == [ Matrix([[1],[-2],[1],[0],[0],[0],[0],[0]]), Matrix([[2],[-3],[0],[1],[0],[0],[0],[0]]), Matrix([[3],[-4],[0],[0],[1],[0],[0],[0]]), Matrix([[4],[-5],[0],[0],[0],[1],[0],[0]]), Matrix([[5],[-6],[0],[0],[0],[0],[1],[0]]), Matrix([[6],[-7],[0],[0],[0],[0],[0],[1]])] def test_issue_17247_expression_blowup_18(): M = Matrix(6, 6, ([1+x, 1-x]*3 + [1-x, 1+x]*3)*3) with dotprodsimp(True): assert not M.is_nilpotent() def test_issue_17247_expression_blowup_19(): M = Matrix(S('''[ [ -3/4, 0, 1/4 + I/2, 0], [ 0, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 1/2 - I, 0, 0, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert not M.is_diagonalizable() def test_issue_17247_expression_blowup_20(): M = Matrix([ [x + 1, 1 - x, 0, 0], [1 - x, x + 1, 0, x + 1], [ 0, 1 - x, x + 1, 0], [ 0, 0, 0, x + 1]]) with dotprodsimp(True): assert M.diagonalize() == (Matrix([ [1, 1, 0, (x + 1)/(x - 1)], [1, -1, 0, 0], [1, 1, 1, 0], [0, 0, 0, 1]]), Matrix([ [2, 0, 0, 0], [0, 2*x, 0, 0], [0, 0, x + 1, 0], [0, 0, 0, x + 1]])) def test_issue_17247_expression_blowup_21(): M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.inv(method='GE') == Matrix(S('''[ [-26194832/3470993 - 31733264*I/3470993, 156352/3470993 + 10325632*I/3470993, 0, -7741283181072/3306971225785 + 2999007604624*I/3306971225785], [4408224/3470993 - 9675328*I/3470993, -2422272/3470993 + 1523712*I/3470993, 0, -1824666489984/3306971225785 - 1401091949952*I/3306971225785], [-26406945676288/22270005630769 + 10245925485056*I/22270005630769, 7453523312640/22270005630769 + 1601616519168*I/22270005630769, 633088/6416033 - 140288*I/6416033, 872209227109521408/21217636514687010905 + 6066405081802389504*I/21217636514687010905], [0, 0, 0, -11328/952745 + 87616*I/952745]]''')) def test_issue_17247_expression_blowup_22(): M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.inv(method='LU') == Matrix(S('''[ [-26194832/3470993 - 31733264*I/3470993, 156352/3470993 + 10325632*I/3470993, 0, -7741283181072/3306971225785 + 2999007604624*I/3306971225785], [4408224/3470993 - 9675328*I/3470993, -2422272/3470993 + 1523712*I/3470993, 0, -1824666489984/3306971225785 - 1401091949952*I/3306971225785], [-26406945676288/22270005630769 + 10245925485056*I/22270005630769, 7453523312640/22270005630769 + 1601616519168*I/22270005630769, 633088/6416033 - 140288*I/6416033, 872209227109521408/21217636514687010905 + 6066405081802389504*I/21217636514687010905], [0, 0, 0, -11328/952745 + 87616*I/952745]]''')) def test_issue_17247_expression_blowup_23(): M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.inv(method='ADJ').expand() == Matrix(S('''[ [-26194832/3470993 - 31733264*I/3470993, 156352/3470993 + 10325632*I/3470993, 0, -7741283181072/3306971225785 + 2999007604624*I/3306971225785], [4408224/3470993 - 9675328*I/3470993, -2422272/3470993 + 1523712*I/3470993, 0, -1824666489984/3306971225785 - 1401091949952*I/3306971225785], [-26406945676288/22270005630769 + 10245925485056*I/22270005630769, 7453523312640/22270005630769 + 1601616519168*I/22270005630769, 633088/6416033 - 140288*I/6416033, 872209227109521408/21217636514687010905 + 6066405081802389504*I/21217636514687010905], [0, 0, 0, -11328/952745 + 87616*I/952745]]''')) def test_issue_17247_expression_blowup_24(): M = SparseMatrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.inv(method='CH') == Matrix(S('''[ [-26194832/3470993 - 31733264*I/3470993, 156352/3470993 + 10325632*I/3470993, 0, -7741283181072/3306971225785 + 2999007604624*I/3306971225785], [4408224/3470993 - 9675328*I/3470993, -2422272/3470993 + 1523712*I/3470993, 0, -1824666489984/3306971225785 - 1401091949952*I/3306971225785], [-26406945676288/22270005630769 + 10245925485056*I/22270005630769, 7453523312640/22270005630769 + 1601616519168*I/22270005630769, 633088/6416033 - 140288*I/6416033, 872209227109521408/21217636514687010905 + 6066405081802389504*I/21217636514687010905], [0, 0, 0, -11328/952745 + 87616*I/952745]]''')) def test_issue_17247_expression_blowup_25(): M = SparseMatrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.inv(method='LDL') == Matrix(S('''[ [-26194832/3470993 - 31733264*I/3470993, 156352/3470993 + 10325632*I/3470993, 0, -7741283181072/3306971225785 + 2999007604624*I/3306971225785], [4408224/3470993 - 9675328*I/3470993, -2422272/3470993 + 1523712*I/3470993, 0, -1824666489984/3306971225785 - 1401091949952*I/3306971225785], [-26406945676288/22270005630769 + 10245925485056*I/22270005630769, 7453523312640/22270005630769 + 1601616519168*I/22270005630769, 633088/6416033 - 140288*I/6416033, 872209227109521408/21217636514687010905 + 6066405081802389504*I/21217636514687010905], [0, 0, 0, -11328/952745 + 87616*I/952745]]''')) def test_issue_17247_expression_blowup_26(): M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64, 1/4 - 5*I/16, 65/128 + 87*I/64, -9/32 - I/16, 183/256 - 97*I/128], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128, 85/256 - 33*I/16, 805/128 + 2415*I/512, -219/128 + 115*I/256, 6301/4096 - 6609*I/1024], [ 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64, 1/4 - 5*I/16, 65/128 + 87*I/64], [ -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128, 85/256 - 33*I/16, 805/128 + 2415*I/512], [ 1 + I, -19/4 + 5*I/4, 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16, 1/4 + I/2, -129/64 - 9*I/64], [ 21/8 + I, -537/64 + 143*I/16, -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128, 125/64 + 87*I/64, -2063/256 + 541*I/128], [ -2, 17/4 - 13*I/2, 1 + I, -19/4 + 5*I/4, 1/2 - I, 9/4 + 55*I/16, -3/4, 45/32 - 37*I/16], [ 1/4 + 13*I/4, -825/64 - 147*I/32, 21/8 + I, -537/64 + 143*I/16, -5/8 - 39*I/16, 2473/256 + 137*I/64, -149/64 + 49*I/32, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.rank() == 4 def test_issue_17247_expression_blowup_27(): M = Matrix([ [ 0, 1 - x, x + 1, 1 - x], [1 - x, x + 1, 0, x + 1], [ 0, 1 - x, x + 1, 1 - x], [ 0, 0, 1 - x, 0]]) with dotprodsimp(True): P, J = M.jordan_form() assert P.expand() == Matrix(S('''[ [ 0, 4*x/(x**2 - 2*x + 1), -(-17*x**4 + 12*sqrt(2)*x**4 - 4*sqrt(2)*x**3 + 6*x**3 - 6*x - 4*sqrt(2)*x + 12*sqrt(2) + 17)/(-7*x**4 + 5*sqrt(2)*x**4 - 6*sqrt(2)*x**3 + 8*x**3 - 2*x**2 + 8*x + 6*sqrt(2)*x - 5*sqrt(2) - 7), -(12*sqrt(2)*x**4 + 17*x**4 - 6*x**3 - 4*sqrt(2)*x**3 - 4*sqrt(2)*x + 6*x - 17 + 12*sqrt(2))/(7*x**4 + 5*sqrt(2)*x**4 - 6*sqrt(2)*x**3 - 8*x**3 + 2*x**2 - 8*x + 6*sqrt(2)*x - 5*sqrt(2) + 7)], [x - 1, x/(x - 1) + 1/(x - 1), (-7*x**3 + 5*sqrt(2)*x**3 - x**2 + sqrt(2)*x**2 - sqrt(2)*x - x - 5*sqrt(2) - 7)/(-3*x**3 + 2*sqrt(2)*x**3 - 2*sqrt(2)*x**2 + 3*x**2 + 2*sqrt(2)*x + 3*x - 3 - 2*sqrt(2)), (7*x**3 + 5*sqrt(2)*x**3 + x**2 + sqrt(2)*x**2 - sqrt(2)*x + x - 5*sqrt(2) + 7)/(2*sqrt(2)*x**3 + 3*x**3 - 3*x**2 - 2*sqrt(2)*x**2 - 3*x + 2*sqrt(2)*x - 2*sqrt(2) + 3)], [ 0, 1, -(-3*x**2 + 2*sqrt(2)*x**2 + 2*x - 3 - 2*sqrt(2))/(-x**2 + sqrt(2)*x**2 - 2*sqrt(2)*x + 1 + sqrt(2)), -(2*sqrt(2)*x**2 + 3*x**2 - 2*x - 2*sqrt(2) + 3)/(x**2 + sqrt(2)*x**2 - 2*sqrt(2)*x - 1 + sqrt(2))], [1 - x, 0, 1, 1]]''')).expand() assert J == Matrix(S('''[ [0, 1, 0, 0], [0, 0, 0, 0], [0, 0, x - sqrt(2)*(x - 1) + 1, 0], [0, 0, 0, x + sqrt(2)*(x - 1) + 1]]''')) def test_issue_17247_expression_blowup_28(): M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.singular_values() == S('''[ sqrt(14609315/131072 + sqrt(64789115132571/2147483648 - 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3) + 76627253330829751075/(35184372088832*sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))) - 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)))/2 + sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))/2), sqrt(14609315/131072 - sqrt(64789115132571/2147483648 - 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3) + 76627253330829751075/(35184372088832*sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))) - 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)))/2 + sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))/2), sqrt(14609315/131072 - sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))/2 + sqrt(64789115132571/2147483648 - 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3) - 76627253330829751075/(35184372088832*sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))) - 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)))/2), sqrt(14609315/131072 - sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))/2 - sqrt(64789115132571/2147483648 - 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3) - 76627253330829751075/(35184372088832*sqrt(64789115132571/4294967296 + 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)) + 2*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3))) - 3546944054712886603889144627/(110680464442257309696*(25895222463957462655758224991455280215303/633825300114114700748351602688 + sqrt(1213909058710955930446995195883114969038524625997915131236390724543989220134670)*I/22282920707136844948184236032)**(1/3)))/2)]''') def test_issue_16823(): # This still needs to be fixed if not using dotprodsimp. M = Matrix(S('''[ [1+I,-19/4+5/4*I,1/2-I,9/4+55/16*I,-3/4,45/32-37/16*I,1/4+1/2*I,-129/64-9/64*I,1/4-5/16*I,65/128+87/64*I,-9/32-1/16*I,183/256-97/128*I,3/64+13/64*I,-23/32-59/256*I,15/128-3/32*I,19/256+551/1024*I], [21/8+I,-537/64+143/16*I,-5/8-39/16*I,2473/256+137/64*I,-149/64+49/32*I,-177/128-1369/128*I,125/64+87/64*I,-2063/256+541/128*I,85/256-33/16*I,805/128+2415/512*I,-219/128+115/256*I,6301/4096-6609/1024*I,119/128+143/128*I,-10879/2048+4343/4096*I,129/256-549/512*I,42533/16384+29103/8192*I], [-2,17/4-13/2*I,1+I,-19/4+5/4*I,1/2-I,9/4+55/16*I,-3/4,45/32-37/16*I,1/4+1/2*I,-129/64-9/64*I,1/4-5/16*I,65/128+87/64*I,-9/32-1/16*I,183/256-97/128*I,3/64+13/64*I,-23/32-59/256*I], [1/4+13/4*I,-825/64-147/32*I,21/8+I,-537/64+143/16*I,-5/8-39/16*I,2473/256+137/64*I,-149/64+49/32*I,-177/128-1369/128*I,125/64+87/64*I,-2063/256+541/128*I,85/256-33/16*I,805/128+2415/512*I,-219/128+115/256*I,6301/4096-6609/1024*I,119/128+143/128*I,-10879/2048+4343/4096*I], [-4*I,27/2+6*I,-2,17/4-13/2*I,1+I,-19/4+5/4*I,1/2-I,9/4+55/16*I,-3/4,45/32-37/16*I,1/4+1/2*I,-129/64-9/64*I,1/4-5/16*I,65/128+87/64*I,-9/32-1/16*I,183/256-97/128*I], [1/4+5/2*I,-23/8-57/16*I,1/4+13/4*I,-825/64-147/32*I,21/8+I,-537/64+143/16*I,-5/8-39/16*I,2473/256+137/64*I,-149/64+49/32*I,-177/128-1369/128*I,125/64+87/64*I,-2063/256+541/128*I,85/256-33/16*I,805/128+2415/512*I,-219/128+115/256*I,6301/4096-6609/1024*I], [-4,9-5*I,-4*I,27/2+6*I,-2,17/4-13/2*I,1+I,-19/4+5/4*I,1/2-I,9/4+55/16*I,-3/4,45/32-37/16*I,1/4+1/2*I,-129/64-9/64*I,1/4-5/16*I,65/128+87/64*I], [-2*I,119/8+29/4*I,1/4+5/2*I,-23/8-57/16*I,1/4+13/4*I,-825/64-147/32*I,21/8+I,-537/64+143/16*I,-5/8-39/16*I,2473/256+137/64*I,-149/64+49/32*I,-177/128-1369/128*I,125/64+87/64*I,-2063/256+541/128*I,85/256-33/16*I,805/128+2415/512*I], [0,-6,-4,9-5*I,-4*I,27/2+6*I,-2,17/4-13/2*I,1+I,-19/4+5/4*I,1/2-I,9/4+55/16*I,-3/4,45/32-37/16*I,1/4+1/2*I,-129/64-9/64*I], [1,-9/4+3*I,-2*I,119/8+29/4*I,1/4+5/2*I,-23/8-57/16*I,1/4+13/4*I,-825/64-147/32*I,21/8+I,-537/64+143/16*I,-5/8-39/16*I,2473/256+137/64*I,-149/64+49/32*I,-177/128-1369/128*I,125/64+87/64*I,-2063/256+541/128*I], [0,-4*I,0,-6,-4,9-5*I,-4*I,27/2+6*I,-2,17/4-13/2*I,1+I,-19/4+5/4*I,1/2-I,9/4+55/16*I,-3/4,45/32-37/16*I], [0,1/4+1/2*I,1,-9/4+3*I,-2*I,119/8+29/4*I,1/4+5/2*I,-23/8-57/16*I,1/4+13/4*I,-825/64-147/32*I,21/8+I,-537/64+143/16*I,-5/8-39/16*I,2473/256+137/64*I,-149/64+49/32*I,-177/128-1369/128*I]]''')) with dotprodsimp(True): assert M.rank() == 8 def test_issue_18531(): # solve_linear_system still needs fixing but the rref works. M = Matrix([ [1, 1, 1, 1, 1, 0, 1, 0, 0], [1 + sqrt(2), -1 + sqrt(2), 1 - sqrt(2), -sqrt(2) - 1, 1, 1, -1, 1, 1], [-5 + 2*sqrt(2), -5 - 2*sqrt(2), -5 - 2*sqrt(2), -5 + 2*sqrt(2), -7, 2, -7, -2, 0], [-3*sqrt(2) - 1, 1 - 3*sqrt(2), -1 + 3*sqrt(2), 1 + 3*sqrt(2), -7, -5, 7, -5, 3], [7 - 4*sqrt(2), 4*sqrt(2) + 7, 4*sqrt(2) + 7, 7 - 4*sqrt(2), 7, -12, 7, 12, 0], [-1 + 3*sqrt(2), 1 + 3*sqrt(2), -3*sqrt(2) - 1, 1 - 3*sqrt(2), 7, -5, -7, -5, 3], [-3 + 2*sqrt(2), -3 - 2*sqrt(2), -3 - 2*sqrt(2), -3 + 2*sqrt(2), -1, 2, -1, -2, 0], [1 - sqrt(2), -sqrt(2) - 1, 1 + sqrt(2), -1 + sqrt(2), -1, 1, 1, 1, 1] ]) with dotprodsimp(True): assert M.rref() == (Matrix([ [1, 0, 0, 0, 0, 0, 0, 0, 1/2], [0, 1, 0, 0, 0, 0, 0, 0, -1/2], [0, 0, 1, 0, 0, 0, 0, 0, 1/2], [0, 0, 0, 1, 0, 0, 0, 0, -1/2], [0, 0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0, -1/2], [0, 0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1, -1/2]]), (0, 1, 2, 3, 4, 5, 6, 7)) def test_creation(): raises(ValueError, lambda: Matrix(5, 5, range(20))) raises(ValueError, lambda: Matrix(5, -1, [])) raises(IndexError, lambda: Matrix((1, 2))[2]) with raises(IndexError): Matrix((1, 2))[3] = 5 assert Matrix() == Matrix([]) == Matrix([[]]) == Matrix(0, 0, []) # anything used to be allowed in a matrix with warns_deprecated_sympy(): assert Matrix([[[1], (2,)]]).tolist() == [[[1], (2,)]] with warns_deprecated_sympy(): assert Matrix([[[1], (2,)]]).T.tolist() == [[[1]], [(2,)]] M = Matrix([[0]]) with warns_deprecated_sympy(): M[0, 0] = S.EmptySet a = Matrix([[x, 0], [0, 0]]) m = a assert m.cols == m.rows assert m.cols == 2 assert m[:] == [x, 0, 0, 0] b = Matrix(2, 2, [x, 0, 0, 0]) m = b assert m.cols == m.rows assert m.cols == 2 assert m[:] == [x, 0, 0, 0] assert a == b assert Matrix(b) == b c23 = Matrix(2, 3, range(1, 7)) c13 = Matrix(1, 3, range(7, 10)) c = Matrix([c23, c13]) assert c.cols == 3 assert c.rows == 3 assert c[:] == [1, 2, 3, 4, 5, 6, 7, 8, 9] assert Matrix(eye(2)) == eye(2) assert ImmutableMatrix(ImmutableMatrix(eye(2))) == ImmutableMatrix(eye(2)) assert ImmutableMatrix(c) == c.as_immutable() assert Matrix(ImmutableMatrix(c)) == ImmutableMatrix(c).as_mutable() assert c is not Matrix(c) dat = [[ones(3,2), ones(3,3)*2], [ones(2,3)*3, ones(2,2)*4]] M = Matrix(dat) assert M == Matrix([ [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [1, 1, 2, 2, 2], [3, 3, 3, 4, 4], [3, 3, 3, 4, 4]]) assert M.tolist() != dat # keep block form if evaluate=False assert Matrix(dat, evaluate=False).tolist() == dat A = MatrixSymbol("A", 2, 2) dat = [ones(2), A] assert Matrix(dat) == Matrix([ [ 1, 1], [ 1, 1], [A[0, 0], A[0, 1]], [A[1, 0], A[1, 1]]]) with warns_deprecated_sympy(): assert Matrix(dat, evaluate=False).tolist() == [[i] for i in dat] # 0-dim tolerance assert Matrix([ones(2), ones(0)]) == Matrix([ones(2)]) raises(ValueError, lambda: Matrix([ones(2), ones(0, 3)])) raises(ValueError, lambda: Matrix([ones(2), ones(3, 0)])) # mix of Matrix and iterable M = Matrix([[1, 2], [3, 4]]) M2 = Matrix([M, (5, 6)]) assert M2 == Matrix([[1, 2], [3, 4], [5, 6]]) def test_irregular_block(): assert Matrix.irregular(3, ones(2,1), ones(3,3)*2, ones(2,2)*3, ones(1,1)*4, ones(2,2)*5, ones(1,2)*6, ones(1,2)*7) == Matrix([ [1, 2, 2, 2, 3, 3], [1, 2, 2, 2, 3, 3], [4, 2, 2, 2, 5, 5], [6, 6, 7, 7, 5, 5]]) def test_tolist(): lst = [[S.One, S.Half, x*y, S.Zero], [x, y, z, x**2], [y, -S.One, z*x, 3]] m = Matrix(lst) assert m.tolist() == lst def test_as_mutable(): assert zeros(0, 3).as_mutable() == zeros(0, 3) assert zeros(0, 3).as_immutable() == ImmutableMatrix(zeros(0, 3)) assert zeros(3, 0).as_immutable() == ImmutableMatrix(zeros(3, 0)) def test_slicing(): m0 = eye(4) assert m0[:3, :3] == eye(3) assert m0[2:4, 0:2] == zeros(2) m1 = Matrix(3, 3, lambda i, j: i + j) assert m1[0, :] == Matrix(1, 3, (0, 1, 2)) assert m1[1:3, 1] == Matrix(2, 1, (2, 3)) m2 = Matrix([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) assert m2[:, -1] == Matrix(4, 1, [3, 7, 11, 15]) assert m2[-2:, :] == Matrix([[8, 9, 10, 11], [12, 13, 14, 15]]) def test_submatrix_assignment(): m = zeros(4) m[2:4, 2:4] = eye(2) assert m == Matrix(((0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))) m[:2, :2] = eye(2) assert m == eye(4) m[:, 0] = Matrix(4, 1, (1, 2, 3, 4)) assert m == Matrix(((1, 0, 0, 0), (2, 1, 0, 0), (3, 0, 1, 0), (4, 0, 0, 1))) m[:, :] = zeros(4) assert m == zeros(4) m[:, :] = [(1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16)] assert m == Matrix(((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16))) m[:2, 0] = [0, 0] assert m == Matrix(((0, 2, 3, 4), (0, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16))) def test_extract(): m = Matrix(4, 3, lambda i, j: i*3 + j) assert m.extract([0, 1, 3], [0, 1]) == Matrix(3, 2, [0, 1, 3, 4, 9, 10]) assert m.extract([0, 3], [0, 0, 2]) == Matrix(2, 3, [0, 0, 2, 9, 9, 11]) assert m.extract(range(4), range(3)) == m raises(IndexError, lambda: m.extract([4], [0])) raises(IndexError, lambda: m.extract([0], [3])) def test_reshape(): m0 = eye(3) assert m0.reshape(1, 9) == Matrix(1, 9, (1, 0, 0, 0, 1, 0, 0, 0, 1)) m1 = Matrix(3, 4, lambda i, j: i + j) assert m1.reshape( 4, 3) == Matrix(((0, 1, 2), (3, 1, 2), (3, 4, 2), (3, 4, 5))) assert m1.reshape(2, 6) == Matrix(((0, 1, 2, 3, 1, 2), (3, 4, 2, 3, 4, 5))) def test_applyfunc(): m0 = eye(3) assert m0.applyfunc(lambda x: 2*x) == eye(3)*2 assert m0.applyfunc(lambda x: 0) == zeros(3) def test_expand(): m0 = Matrix([[x*(x + y), 2], [((x + y)*y)*x, x*(y + x*(x + y))]]) # Test if expand() returns a matrix m1 = m0.expand() assert m1 == Matrix( [[x*y + x**2, 2], [x*y**2 + y*x**2, x*y + y*x**2 + x**3]]) a = Symbol('a', real=True) assert Matrix([exp(I*a)]).expand(complex=True) == \ Matrix([cos(a) + I*sin(a)]) assert Matrix([[0, 1, 2], [0, 0, -1], [0, 0, 0]]).exp() == Matrix([ [1, 1, Rational(3, 2)], [0, 1, -1], [0, 0, 1]] ) def test_refine(): m0 = Matrix([[Abs(x)**2, sqrt(x**2)], [sqrt(x**2)*Abs(y)**2, sqrt(y**2)*Abs(x)**2]]) m1 = m0.refine(Q.real(x) & Q.real(y)) assert m1 == Matrix([[x**2, Abs(x)], [y**2*Abs(x), x**2*Abs(y)]]) m1 = m0.refine(Q.positive(x) & Q.positive(y)) assert m1 == Matrix([[x**2, x], [x*y**2, x**2*y]]) m1 = m0.refine(Q.negative(x) & Q.negative(y)) assert m1 == Matrix([[x**2, -x], [-x*y**2, -x**2*y]]) def test_random(): M = randMatrix(3, 3) M = randMatrix(3, 3, seed=3) assert M == randMatrix(3, 3, seed=3) M = randMatrix(3, 4, 0, 150) M = randMatrix(3, seed=4, symmetric=True) assert M == randMatrix(3, seed=4, symmetric=True) S = M.copy() S.simplify() assert S == M # doesn't fail when elements are Numbers, not int rng = random.Random(4) assert M == randMatrix(3, symmetric=True, prng=rng) # Ensure symmetry for size in (10, 11): # Test odd and even for percent in (100, 70, 30): M = randMatrix(size, symmetric=True, percent=percent, prng=rng) assert M == M.T M = randMatrix(10, min=1, percent=70) zero_count = 0 for i in range(M.shape[0]): for j in range(M.shape[1]): if M[i, j] == 0: zero_count += 1 assert zero_count == 30 def test_inverse(): A = eye(4) assert A.inv() == eye(4) assert A.inv(method="LU") == eye(4) assert A.inv(method="ADJ") == eye(4) assert A.inv(method="CH") == eye(4) assert A.inv(method="LDL") == eye(4) assert A.inv(method="QR") == eye(4) A = Matrix([[2, 3, 5], [3, 6, 2], [8, 3, 6]]) Ainv = A.inv() assert A*Ainv == eye(3) assert A.inv(method="LU") == Ainv assert A.inv(method="ADJ") == Ainv assert A.inv(method="CH") == Ainv assert A.inv(method="LDL") == Ainv assert A.inv(method="QR") == Ainv AA = Matrix([[0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0], [1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0], [1, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1], [1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0], [1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0], [1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1], [0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0], [1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1], [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1], [1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0], [0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0], [1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0], [0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1], [1, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0], [0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0], [1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 0, 0], [0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1], [0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1], [1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1], [0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1], [0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1], [0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0], [0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0]]) assert AA.inv(method="BLOCK") * AA == eye(AA.shape[0]) # test that immutability is not a problem cls = ImmutableMatrix m = cls([[48, 49, 31], [ 9, 71, 94], [59, 28, 65]]) assert all(type(m.inv(s)) is cls for s in 'GE ADJ LU CH LDL QR'.split()) cls = ImmutableSparseMatrix m = cls([[48, 49, 31], [ 9, 71, 94], [59, 28, 65]]) assert all(type(m.inv(s)) is cls for s in 'GE ADJ LU CH LDL QR'.split()) def test_matrix_inverse_mod(): A = Matrix(2, 1, [1, 0]) raises(NonSquareMatrixError, lambda: A.inv_mod(2)) A = Matrix(2, 2, [1, 0, 0, 0]) raises(ValueError, lambda: A.inv_mod(2)) A = Matrix(2, 2, [1, 2, 3, 4]) Ai = Matrix(2, 2, [1, 1, 0, 1]) assert A.inv_mod(3) == Ai A = Matrix(2, 2, [1, 0, 0, 1]) assert A.inv_mod(2) == A A = Matrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) raises(ValueError, lambda: A.inv_mod(5)) A = Matrix(3, 3, [5, 1, 3, 2, 6, 0, 2, 1, 1]) Ai = Matrix(3, 3, [6, 8, 0, 1, 5, 6, 5, 6, 4]) assert A.inv_mod(9) == Ai A = Matrix(3, 3, [1, 6, -3, 4, 1, -5, 3, -5, 5]) Ai = Matrix(3, 3, [4, 3, 3, 1, 2, 5, 1, 5, 1]) assert A.inv_mod(6) == Ai A = Matrix(3, 3, [1, 6, 1, 4, 1, 5, 3, 2, 5]) Ai = Matrix(3, 3, [6, 0, 3, 6, 6, 4, 1, 6, 1]) assert A.inv_mod(7) == Ai def test_jacobian_hessian(): L = Matrix(1, 2, [x**2*y, 2*y**2 + x*y]) syms = [x, y] assert L.jacobian(syms) == Matrix([[2*x*y, x**2], [y, 4*y + x]]) L = Matrix(1, 2, [x, x**2*y**3]) assert L.jacobian(syms) == Matrix([[1, 0], [2*x*y**3, x**2*3*y**2]]) f = x**2*y syms = [x, y] assert hessian(f, syms) == Matrix([[2*y, 2*x], [2*x, 0]]) f = x**2*y**3 assert hessian(f, syms) == \ Matrix([[2*y**3, 6*x*y**2], [6*x*y**2, 6*x**2*y]]) f = z + x*y**2 g = x**2 + 2*y**3 ans = Matrix([[0, 2*y], [2*y, 2*x]]) assert ans == hessian(f, Matrix([x, y])) assert ans == hessian(f, Matrix([x, y]).T) assert hessian(f, (y, x), [g]) == Matrix([ [ 0, 6*y**2, 2*x], [6*y**2, 2*x, 2*y], [ 2*x, 2*y, 0]]) def test_wronskian(): assert wronskian([cos(x), sin(x)], x) == cos(x)**2 + sin(x)**2 assert wronskian([exp(x), exp(2*x)], x) == exp(3*x) assert wronskian([exp(x), x], x) == exp(x) - x*exp(x) assert wronskian([1, x, x**2], x) == 2 w1 = -6*exp(x)*sin(x)*x + 6*cos(x)*exp(x)*x**2 - 6*exp(x)*cos(x)*x - \ exp(x)*cos(x)*x**3 + exp(x)*sin(x)*x**3 assert wronskian([exp(x), cos(x), x**3], x).expand() == w1 assert wronskian([exp(x), cos(x), x**3], x, method='berkowitz').expand() \ == w1 w2 = -x**3*cos(x)**2 - x**3*sin(x)**2 - 6*x*cos(x)**2 - 6*x*sin(x)**2 assert wronskian([sin(x), cos(x), x**3], x).expand() == w2 assert wronskian([sin(x), cos(x), x**3], x, method='berkowitz').expand() \ == w2 assert wronskian([], x) == 1 def test_subs(): assert Matrix([[1, x], [x, 4]]).subs(x, 5) == Matrix([[1, 5], [5, 4]]) assert Matrix([[x, 2], [x + y, 4]]).subs([[x, -1], [y, -2]]) == \ Matrix([[-1, 2], [-3, 4]]) assert Matrix([[x, 2], [x + y, 4]]).subs([(x, -1), (y, -2)]) == \ Matrix([[-1, 2], [-3, 4]]) assert Matrix([[x, 2], [x + y, 4]]).subs({x: -1, y: -2}) == \ Matrix([[-1, 2], [-3, 4]]) assert Matrix([x*y]).subs({x: y - 1, y: x - 1}, simultaneous=True) == \ Matrix([(x - 1)*(y - 1)]) for cls in classes: assert Matrix([[2, 0], [0, 2]]) == cls.eye(2).subs(1, 2) def test_xreplace(): assert Matrix([[1, x], [x, 4]]).xreplace({x: 5}) == \ Matrix([[1, 5], [5, 4]]) assert Matrix([[x, 2], [x + y, 4]]).xreplace({x: -1, y: -2}) == \ Matrix([[-1, 2], [-3, 4]]) for cls in classes: assert Matrix([[2, 0], [0, 2]]) == cls.eye(2).xreplace({1: 2}) def test_simplify(): n = Symbol('n') f = Function('f') M = Matrix([[ 1/x + 1/y, (x + x*y) / x ], [ (f(x) + y*f(x))/f(x), 2 * (1/n - cos(n * pi)/n) / pi ]]) M.simplify() assert M == Matrix([[ (x + y)/(x * y), 1 + y ], [ 1 + y, 2*((1 - 1*cos(pi*n))/(pi*n)) ]]) eq = (1 + x)**2 M = Matrix([[eq]]) M.simplify() assert M == Matrix([[eq]]) M.simplify(ratio=oo) == M assert M == Matrix([[eq.simplify(ratio=oo)]]) def test_transpose(): M = Matrix([[1, 2, 3, 4, 5, 6, 7, 8, 9, 0], [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]]) assert M.T == Matrix( [ [1, 1], [2, 2], [3, 3], [4, 4], [5, 5], [6, 6], [7, 7], [8, 8], [9, 9], [0, 0] ]) assert M.T.T == M assert M.T == M.transpose() def test_conjugate(): M = Matrix([[0, I, 5], [1, 2, 0]]) assert M.T == Matrix([[0, 1], [I, 2], [5, 0]]) assert M.C == Matrix([[0, -I, 5], [1, 2, 0]]) assert M.C == M.conjugate() assert M.H == M.T.C assert M.H == Matrix([[ 0, 1], [-I, 2], [ 5, 0]]) def test_conj_dirac(): raises(AttributeError, lambda: eye(3).D) M = Matrix([[1, I, I, I], [0, 1, I, I], [0, 0, 1, I], [0, 0, 0, 1]]) assert M.D == Matrix([[ 1, 0, 0, 0], [-I, 1, 0, 0], [-I, -I, -1, 0], [-I, -I, I, -1]]) def test_trace(): M = Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 8]]) assert M.trace() == 14 def test_shape(): M = Matrix([[x, 0, 0], [0, y, 0]]) assert M.shape == (2, 3) def test_col_row_op(): M = Matrix([[x, 0, 0], [0, y, 0]]) M.row_op(1, lambda r, j: r + j + 1) assert M == Matrix([[x, 0, 0], [1, y + 2, 3]]) M.col_op(0, lambda c, j: c + y**j) assert M == Matrix([[x + 1, 0, 0], [1 + y, y + 2, 3]]) # neither row nor slice give copies that allow the original matrix to # be changed assert M.row(0) == Matrix([[x + 1, 0, 0]]) r1 = M.row(0) r1[0] = 42 assert M[0, 0] == x + 1 r1 = M[0, :-1] # also testing negative slice r1[0] = 42 assert M[0, 0] == x + 1 c1 = M.col(0) assert c1 == Matrix([x + 1, 1 + y]) c1[0] = 0 assert M[0, 0] == x + 1 c1 = M[:, 0] c1[0] = 42 assert M[0, 0] == x + 1 def test_zip_row_op(): for cls in classes[:2]: # XXX: immutable matrices don't support row ops M = cls.eye(3) M.zip_row_op(1, 0, lambda v, u: v + 2*u) assert M == cls([[1, 0, 0], [2, 1, 0], [0, 0, 1]]) M = cls.eye(3)*2 M[0, 1] = -1 M.zip_row_op(1, 0, lambda v, u: v + 2*u); M assert M == cls([[2, -1, 0], [4, 0, 0], [0, 0, 2]]) def test_issue_3950(): m = Matrix([1, 2, 3]) a = Matrix([1, 2, 3]) b = Matrix([2, 2, 3]) assert not (m in []) assert not (m in [1]) assert m != 1 assert m == a assert m != b def test_issue_3981(): class Index1: def __index__(self): return 1 class Index2: def __index__(self): return 2 index1 = Index1() index2 = Index2() m = Matrix([1, 2, 3]) assert m[index2] == 3 m[index2] = 5 assert m[2] == 5 m = Matrix([[1, 2, 3], [4, 5, 6]]) assert m[index1, index2] == 6 assert m[1, index2] == 6 assert m[index1, 2] == 6 m[index1, index2] = 4 assert m[1, 2] == 4 m[1, index2] = 6 assert m[1, 2] == 6 m[index1, 2] = 8 assert m[1, 2] == 8 def test_evalf(): a = Matrix([sqrt(5), 6]) assert all(a.evalf()[i] == a[i].evalf() for i in range(2)) assert all(a.evalf(2)[i] == a[i].evalf(2) for i in range(2)) assert all(a.n(2)[i] == a[i].n(2) for i in range(2)) def test_is_symbolic(): a = Matrix([[x, x], [x, x]]) assert a.is_symbolic() is True a = Matrix([[1, 2, 3, 4], [5, 6, 7, 8]]) assert a.is_symbolic() is False a = Matrix([[1, 2, 3, 4], [5, 6, x, 8]]) assert a.is_symbolic() is True a = Matrix([[1, x, 3]]) assert a.is_symbolic() is True a = Matrix([[1, 2, 3]]) assert a.is_symbolic() is False a = Matrix([[1], [x], [3]]) assert a.is_symbolic() is True a = Matrix([[1], [2], [3]]) assert a.is_symbolic() is False def test_is_upper(): a = Matrix([[1, 2, 3]]) assert a.is_upper is True a = Matrix([[1], [2], [3]]) assert a.is_upper is False a = zeros(4, 2) assert a.is_upper is True def test_is_lower(): a = Matrix([[1, 2, 3]]) assert a.is_lower is False a = Matrix([[1], [2], [3]]) assert a.is_lower is True def test_is_nilpotent(): a = Matrix(4, 4, [0, 2, 1, 6, 0, 0, 1, 2, 0, 0, 0, 3, 0, 0, 0, 0]) assert a.is_nilpotent() a = Matrix([[1, 0], [0, 1]]) assert not a.is_nilpotent() a = Matrix([]) assert a.is_nilpotent() def test_zeros_ones_fill(): n, m = 3, 5 a = zeros(n, m) a.fill( 5 ) b = 5 * ones(n, m) assert a == b assert a.rows == b.rows == 3 assert a.cols == b.cols == 5 assert a.shape == b.shape == (3, 5) assert zeros(2) == zeros(2, 2) assert ones(2) == ones(2, 2) assert zeros(2, 3) == Matrix(2, 3, [0]*6) assert ones(2, 3) == Matrix(2, 3, [1]*6) a.fill(0) assert a == zeros(n, m) def test_empty_zeros(): a = zeros(0) assert a == Matrix() a = zeros(0, 2) assert a.rows == 0 assert a.cols == 2 a = zeros(2, 0) assert a.rows == 2 assert a.cols == 0 def test_issue_3749(): a = Matrix([[x**2, x*y], [x*sin(y), x*cos(y)]]) assert a.diff(x) == Matrix([[2*x, y], [sin(y), cos(y)]]) assert Matrix([ [x, -x, x**2], [exp(x), 1/x - exp(-x), x + 1/x]]).limit(x, oo) == \ Matrix([[oo, -oo, oo], [oo, 0, oo]]) assert Matrix([ [(exp(x) - 1)/x, 2*x + y*x, x**x ], [1/x, abs(x), abs(sin(x + 1))]]).limit(x, 0) == \ Matrix([[1, 0, 1], [oo, 0, sin(1)]]) assert a.integrate(x) == Matrix([ [Rational(1, 3)*x**3, y*x**2/2], [x**2*sin(y)/2, x**2*cos(y)/2]]) def test_inv_iszerofunc(): A = eye(4) A.col_swap(0, 1) for method in "GE", "LU": assert A.inv(method=method, iszerofunc=lambda x: x == 0) == \ A.inv(method="ADJ") def test_jacobian_metrics(): rho, phi = symbols("rho,phi") X = Matrix([rho*cos(phi), rho*sin(phi)]) Y = Matrix([rho, phi]) J = X.jacobian(Y) assert J == X.jacobian(Y.T) assert J == (X.T).jacobian(Y) assert J == (X.T).jacobian(Y.T) g = J.T*eye(J.shape[0])*J g = g.applyfunc(trigsimp) assert g == Matrix([[1, 0], [0, rho**2]]) def test_jacobian2(): rho, phi = symbols("rho,phi") X = Matrix([rho*cos(phi), rho*sin(phi), rho**2]) Y = Matrix([rho, phi]) J = Matrix([ [cos(phi), -rho*sin(phi)], [sin(phi), rho*cos(phi)], [ 2*rho, 0], ]) assert X.jacobian(Y) == J def test_issue_4564(): X = Matrix([exp(x + y + z), exp(x + y + z), exp(x + y + z)]) Y = Matrix([x, y, z]) for i in range(1, 3): for j in range(1, 3): X_slice = X[:i, :] Y_slice = Y[:j, :] J = X_slice.jacobian(Y_slice) assert J.rows == i assert J.cols == j for k in range(j): assert J[:, k] == X_slice def test_nonvectorJacobian(): X = Matrix([[exp(x + y + z), exp(x + y + z)], [exp(x + y + z), exp(x + y + z)]]) raises(TypeError, lambda: X.jacobian(Matrix([x, y, z]))) X = X[0, :] Y = Matrix([[x, y], [x, z]]) raises(TypeError, lambda: X.jacobian(Y)) raises(TypeError, lambda: X.jacobian(Matrix([ [x, y], [x, z] ]))) def test_vec(): m = Matrix([[1, 3], [2, 4]]) m_vec = m.vec() assert m_vec.cols == 1 for i in range(4): assert m_vec[i] == i + 1 def test_vech(): m = Matrix([[1, 2], [2, 3]]) m_vech = m.vech() assert m_vech.cols == 1 for i in range(3): assert m_vech[i] == i + 1 m_vech = m.vech(diagonal=False) assert m_vech[0] == 2 m = Matrix([[1, x*(x + y)], [y*x + x**2, 1]]) m_vech = m.vech(diagonal=False) assert m_vech[0] == y*x + x**2 m = Matrix([[1, x*(x + y)], [y*x, 1]]) m_vech = m.vech(diagonal=False, check_symmetry=False) assert m_vech[0] == y*x raises(ShapeError, lambda: Matrix([[1, 3]]).vech()) raises(ValueError, lambda: Matrix([[1, 3], [2, 4]]).vech()) raises(ShapeError, lambda: Matrix([[1, 3]]).vech()) raises(ValueError, lambda: Matrix([[1, 3], [2, 4]]).vech()) def test_diag(): # mostly tested in testcommonmatrix.py assert diag([1, 2, 3]) == Matrix([1, 2, 3]) m = [1, 2, [3]] raises(ValueError, lambda: diag(m)) assert diag(m, strict=False) == Matrix([1, 2, 3]) def test_get_diag_blocks1(): a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) assert a.get_diag_blocks() == [a] assert b.get_diag_blocks() == [b] assert c.get_diag_blocks() == [c] def test_get_diag_blocks2(): a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) assert diag(a, b, b).get_diag_blocks() == [a, b, b] assert diag(a, b, c).get_diag_blocks() == [a, b, c] assert diag(a, c, b).get_diag_blocks() == [a, c, b] assert diag(c, c, b).get_diag_blocks() == [c, c, b] def test_inv_block(): a = Matrix([[1, 2], [2, 3]]) b = Matrix([[3, x], [y, 3]]) c = Matrix([[3, x, 3], [y, 3, z], [x, y, z]]) A = diag(a, b, b) assert A.inv(try_block_diag=True) == diag(a.inv(), b.inv(), b.inv()) A = diag(a, b, c) assert A.inv(try_block_diag=True) == diag(a.inv(), b.inv(), c.inv()) A = diag(a, c, b) assert A.inv(try_block_diag=True) == diag(a.inv(), c.inv(), b.inv()) A = diag(a, a, b, a, c, a) assert A.inv(try_block_diag=True) == diag( a.inv(), a.inv(), b.inv(), a.inv(), c.inv(), a.inv()) assert A.inv(try_block_diag=True, method="ADJ") == diag( a.inv(method="ADJ"), a.inv(method="ADJ"), b.inv(method="ADJ"), a.inv(method="ADJ"), c.inv(method="ADJ"), a.inv(method="ADJ")) def test_creation_args(): """ Check that matrix dimensions can be specified using any reasonable type (see issue 4614). """ raises(ValueError, lambda: zeros(3, -1)) raises(TypeError, lambda: zeros(1, 2, 3, 4)) assert zeros(int(3)) == zeros(3) assert zeros(Integer(3)) == zeros(3) raises(ValueError, lambda: zeros(3.)) assert eye(int(3)) == eye(3) assert eye(Integer(3)) == eye(3) raises(ValueError, lambda: eye(3.)) assert ones(int(3), Integer(4)) == ones(3, 4) raises(TypeError, lambda: Matrix(5)) raises(TypeError, lambda: Matrix(1, 2)) raises(ValueError, lambda: Matrix([1, [2]])) def test_diagonal_symmetrical(): m = Matrix(2, 2, [0, 1, 1, 0]) assert not m.is_diagonal() assert m.is_symmetric() assert m.is_symmetric(simplify=False) m = Matrix(2, 2, [1, 0, 0, 1]) assert m.is_diagonal() m = diag(1, 2, 3) assert m.is_diagonal() assert m.is_symmetric() m = Matrix(3, 3, [1, 0, 0, 0, 2, 0, 0, 0, 3]) assert m == diag(1, 2, 3) m = Matrix(2, 3, zeros(2, 3)) assert not m.is_symmetric() assert m.is_diagonal() m = Matrix(((5, 0), (0, 6), (0, 0))) assert m.is_diagonal() m = Matrix(((5, 0, 0), (0, 6, 0))) assert m.is_diagonal() m = Matrix(3, 3, [1, x**2 + 2*x + 1, y, (x + 1)**2, 2, 0, y, 0, 3]) assert m.is_symmetric() assert not m.is_symmetric(simplify=False) assert m.expand().is_symmetric(simplify=False) def test_diagonalization(): m = Matrix([[1, 2+I], [2-I, 3]]) assert m.is_diagonalizable() m = Matrix(3, 2, [-3, 1, -3, 20, 3, 10]) assert not m.is_diagonalizable() assert not m.is_symmetric() raises(NonSquareMatrixError, lambda: m.diagonalize()) # diagonalizable m = diag(1, 2, 3) (P, D) = m.diagonalize() assert P == eye(3) assert D == m m = Matrix(2, 2, [0, 1, 1, 0]) assert m.is_symmetric() assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D m = Matrix(2, 2, [1, 0, 0, 3]) assert m.is_symmetric() assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D assert P == eye(2) assert D == m m = Matrix(2, 2, [1, 1, 0, 0]) assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D m = Matrix(3, 3, [1, 2, 0, 0, 3, 0, 2, -4, 2]) assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D for i in P: assert i.as_numer_denom()[1] == 1 m = Matrix(2, 2, [1, 0, 0, 0]) assert m.is_diagonal() assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D assert P == Matrix([[0, 1], [1, 0]]) # diagonalizable, complex only m = Matrix(2, 2, [0, 1, -1, 0]) assert not m.is_diagonalizable(True) raises(MatrixError, lambda: m.diagonalize(True)) assert m.is_diagonalizable() (P, D) = m.diagonalize() assert P.inv() * m * P == D # not diagonalizable m = Matrix(2, 2, [0, 1, 0, 0]) assert not m.is_diagonalizable() raises(MatrixError, lambda: m.diagonalize()) m = Matrix(3, 3, [-3, 1, -3, 20, 3, 10, 2, -2, 4]) assert not m.is_diagonalizable() raises(MatrixError, lambda: m.diagonalize()) # symbolic a, b, c, d = symbols('a b c d') m = Matrix(2, 2, [a, c, c, b]) assert m.is_symmetric() assert m.is_diagonalizable() def test_issue_15887(): # Mutable matrix should not use cache a = MutableDenseMatrix([[0, 1], [1, 0]]) assert a.is_diagonalizable() is True a[1, 0] = 0 assert a.is_diagonalizable() is False a = MutableDenseMatrix([[0, 1], [1, 0]]) a.diagonalize() a[1, 0] = 0 raises(MatrixError, lambda: a.diagonalize()) # Test deprecated cache and kwargs with warns_deprecated_sympy(): a.is_diagonalizable(clear_cache=True) with warns_deprecated_sympy(): a.is_diagonalizable(clear_subproducts=True) def test_jordan_form(): m = Matrix(3, 2, [-3, 1, -3, 20, 3, 10]) raises(NonSquareMatrixError, lambda: m.jordan_form()) # diagonalizable m = Matrix(3, 3, [7, -12, 6, 10, -19, 10, 12, -24, 13]) Jmust = Matrix(3, 3, [-1, 0, 0, 0, 1, 0, 0, 0, 1]) P, J = m.jordan_form() assert Jmust == J assert Jmust == m.diagonalize()[1] # m = Matrix(3, 3, [0, 6, 3, 1, 3, 1, -2, 2, 1]) # m.jordan_form() # very long # m.jordan_form() # # diagonalizable, complex only # Jordan cells # complexity: one of eigenvalues is zero m = Matrix(3, 3, [0, 1, 0, -4, 4, 0, -2, 1, 2]) # The blocks are ordered according to the value of their eigenvalues, # in order to make the matrix compatible with .diagonalize() Jmust = Matrix(3, 3, [2, 1, 0, 0, 2, 0, 0, 0, 2]) P, J = m.jordan_form() assert Jmust == J # complexity: all of eigenvalues are equal m = Matrix(3, 3, [2, 6, -15, 1, 1, -5, 1, 2, -6]) # Jmust = Matrix(3, 3, [-1, 0, 0, 0, -1, 1, 0, 0, -1]) # same here see 1456ff Jmust = Matrix(3, 3, [-1, 1, 0, 0, -1, 0, 0, 0, -1]) P, J = m.jordan_form() assert Jmust == J # complexity: two of eigenvalues are zero m = Matrix(3, 3, [4, -5, 2, 5, -7, 3, 6, -9, 4]) Jmust = Matrix(3, 3, [0, 1, 0, 0, 0, 0, 0, 0, 1]) P, J = m.jordan_form() assert Jmust == J m = Matrix(4, 4, [6, 5, -2, -3, -3, -1, 3, 3, 2, 1, -2, -3, -1, 1, 5, 5]) Jmust = Matrix(4, 4, [2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2] ) P, J = m.jordan_form() assert Jmust == J m = Matrix(4, 4, [6, 2, -8, -6, -3, 2, 9, 6, 2, -2, -8, -6, -1, 0, 3, 4]) # Jmust = Matrix(4, 4, [2, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 0, -2]) # same here see 1456ff Jmust = Matrix(4, 4, [-2, 0, 0, 0, 0, 2, 1, 0, 0, 0, 2, 0, 0, 0, 0, 2]) P, J = m.jordan_form() assert Jmust == J m = Matrix(4, 4, [5, 4, 2, 1, 0, 1, -1, -1, -1, -1, 3, 0, 1, 1, -1, 2]) assert not m.is_diagonalizable() Jmust = Matrix(4, 4, [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 4, 1, 0, 0, 0, 4]) P, J = m.jordan_form() assert Jmust == J # checking for maximum precision to remain unchanged m = Matrix([[Float('1.0', precision=110), Float('2.0', precision=110)], [Float('3.14159265358979323846264338327', precision=110), Float('4.0', precision=110)]]) P, J = m.jordan_form() for term in J.values(): if isinstance(term, Float): assert term._prec == 110 def test_jordan_form_complex_issue_9274(): A = Matrix([[ 2, 4, 1, 0], [-4, 2, 0, 1], [ 0, 0, 2, 4], [ 0, 0, -4, 2]]) p = 2 - 4*I; q = 2 + 4*I; Jmust1 = Matrix([[p, 1, 0, 0], [0, p, 0, 0], [0, 0, q, 1], [0, 0, 0, q]]) Jmust2 = Matrix([[q, 1, 0, 0], [0, q, 0, 0], [0, 0, p, 1], [0, 0, 0, p]]) P, J = A.jordan_form() assert J == Jmust1 or J == Jmust2 assert simplify(P*J*P.inv()) == A def test_issue_10220(): # two non-orthogonal Jordan blocks with eigenvalue 1 M = Matrix([[1, 0, 0, 1], [0, 1, 1, 0], [0, 0, 1, 1], [0, 0, 0, 1]]) P, J = M.jordan_form() assert P == Matrix([[0, 1, 0, 1], [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]]) assert J == Matrix([ [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, 0], [0, 0, 0, 1]]) def test_jordan_form_issue_15858(): A = Matrix([ [1, 1, 1, 0], [-2, -1, 0, -1], [0, 0, -1, -1], [0, 0, 2, 1]]) (P, J) = A.jordan_form() assert P.expand() == Matrix([ [ -I, -I/2, I, I/2], [-1 + I, 0, -1 - I, 0], [ 0, -S(1)/2 - I/2, 0, -S(1)/2 + I/2], [ 0, 1, 0, 1]]) assert J == Matrix([ [-I, 1, 0, 0], [0, -I, 0, 0], [0, 0, I, 1], [0, 0, 0, I]]) def test_Matrix_berkowitz_charpoly(): UA, K_i, K_w = symbols('UA K_i K_w') A = Matrix([[-K_i - UA + K_i**2/(K_i + K_w), K_i*K_w/(K_i + K_w)], [ K_i*K_w/(K_i + K_w), -K_w + K_w**2/(K_i + K_w)]]) charpoly = A.charpoly(x) assert charpoly == \ Poly(x**2 + (K_i*UA + K_w*UA + 2*K_i*K_w)/(K_i + K_w)*x + K_i*K_w*UA/(K_i + K_w), x, domain='ZZ(K_i,K_w,UA)') assert type(charpoly) is PurePoly A = Matrix([[1, 3], [2, 0]]) assert A.charpoly() == A.charpoly(x) == PurePoly(x**2 - x - 6) A = Matrix([[1, 2], [x, 0]]) p = A.charpoly(x) assert p.gen != x assert p.as_expr().subs(p.gen, x) == x**2 - 3*x def test_exp_jordan_block(): l = Symbol('lamda') m = Matrix.jordan_block(1, l) assert m._eval_matrix_exp_jblock() == Matrix([[exp(l)]]) m = Matrix.jordan_block(3, l) assert m._eval_matrix_exp_jblock() == \ Matrix([ [exp(l), exp(l), exp(l)/2], [0, exp(l), exp(l)], [0, 0, exp(l)]]) def test_exp(): m = Matrix([[3, 4], [0, -2]]) m_exp = Matrix([[exp(3), -4*exp(-2)/5 + 4*exp(3)/5], [0, exp(-2)]]) assert m.exp() == m_exp assert exp(m) == m_exp m = Matrix([[1, 0], [0, 1]]) assert m.exp() == Matrix([[E, 0], [0, E]]) assert exp(m) == Matrix([[E, 0], [0, E]]) m = Matrix([[1, -1], [1, 1]]) assert m.exp() == Matrix([[E*cos(1), -E*sin(1)], [E*sin(1), E*cos(1)]]) def test_log(): l = Symbol('lamda') m = Matrix.jordan_block(1, l) assert m._eval_matrix_log_jblock() == Matrix([[log(l)]]) m = Matrix.jordan_block(4, l) assert m._eval_matrix_log_jblock() == \ Matrix( [ [log(l), 1/l, -1/(2*l**2), 1/(3*l**3)], [0, log(l), 1/l, -1/(2*l**2)], [0, 0, log(l), 1/l], [0, 0, 0, log(l)] ] ) m = Matrix( [[0, 0, 1], [0, 0, 0], [-1, 0, 0]] ) raises(MatrixError, lambda: m.log()) def test_has(): A = Matrix(((x, y), (2, 3))) assert A.has(x) assert not A.has(z) assert A.has(Symbol) A = A.subs(x, 2) assert not A.has(x) def test_find_reasonable_pivot_naive_finds_guaranteed_nonzero1(): # Test if matrices._find_reasonable_pivot_naive() # finds a guaranteed non-zero pivot when the # some of the candidate pivots are symbolic expressions. # Keyword argument: simpfunc=None indicates that no simplifications # should be performed during the search. x = Symbol('x') column = Matrix(3, 1, [x, cos(x)**2 + sin(x)**2, S.Half]) pivot_offset, pivot_val, pivot_assumed_nonzero, simplified =\ _find_reasonable_pivot_naive(column) assert pivot_val == S.Half def test_find_reasonable_pivot_naive_finds_guaranteed_nonzero2(): # Test if matrices._find_reasonable_pivot_naive() # finds a guaranteed non-zero pivot when the # some of the candidate pivots are symbolic expressions. # Keyword argument: simpfunc=_simplify indicates that the search # should attempt to simplify candidate pivots. x = Symbol('x') column = Matrix(3, 1, [x, cos(x)**2+sin(x)**2+x**2, cos(x)**2+sin(x)**2]) pivot_offset, pivot_val, pivot_assumed_nonzero, simplified =\ _find_reasonable_pivot_naive(column, simpfunc=_simplify) assert pivot_val == 1 def test_find_reasonable_pivot_naive_simplifies(): # Test if matrices._find_reasonable_pivot_naive() # simplifies candidate pivots, and reports # their offsets correctly. x = Symbol('x') column = Matrix(3, 1, [x, cos(x)**2+sin(x)**2+x, cos(x)**2+sin(x)**2]) pivot_offset, pivot_val, pivot_assumed_nonzero, simplified =\ _find_reasonable_pivot_naive(column, simpfunc=_simplify) assert len(simplified) == 2 assert simplified[0][0] == 1 assert simplified[0][1] == 1+x assert simplified[1][0] == 2 assert simplified[1][1] == 1 def test_errors(): raises(ValueError, lambda: Matrix([[1, 2], [1]])) raises(IndexError, lambda: Matrix([[1, 2]])[1.2, 5]) raises(IndexError, lambda: Matrix([[1, 2]])[1, 5.2]) raises(ValueError, lambda: randMatrix(3, c=4, symmetric=True)) raises(ValueError, lambda: Matrix([1, 2]).reshape(4, 6)) raises(ShapeError, lambda: Matrix([[1, 2], [3, 4]]).copyin_matrix([1, 0], Matrix([1, 2]))) raises(TypeError, lambda: Matrix([[1, 2], [3, 4]]).copyin_list([0, 1], set())) raises(NonSquareMatrixError, lambda: Matrix([[1, 2, 3], [2, 3, 0]]).inv()) raises(ShapeError, lambda: Matrix(1, 2, [1, 2]).row_join(Matrix([[1, 2], [3, 4]]))) raises( ShapeError, lambda: Matrix([1, 2]).col_join(Matrix([[1, 2], [3, 4]]))) raises(ShapeError, lambda: Matrix([1]).row_insert(1, Matrix([[1, 2], [3, 4]]))) raises(ShapeError, lambda: Matrix([1]).col_insert(1, Matrix([[1, 2], [3, 4]]))) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).trace()) raises(TypeError, lambda: Matrix([1]).applyfunc(1)) raises(ValueError, lambda: Matrix([[1, 2], [3, 4]]).minor(4, 5)) raises(ValueError, lambda: Matrix([[1, 2], [3, 4]]).minor_submatrix(4, 5)) raises(TypeError, lambda: Matrix([1, 2, 3]).cross(1)) raises(TypeError, lambda: Matrix([1, 2, 3]).dot(1)) raises(ShapeError, lambda: Matrix([1, 2, 3]).dot(Matrix([1, 2]))) raises(ShapeError, lambda: Matrix([1, 2]).dot([])) raises(TypeError, lambda: Matrix([1, 2]).dot('a')) with warns_deprecated_sympy(): Matrix([[1, 2], [3, 4]]).dot(Matrix([[4, 3], [1, 2]])) raises(ShapeError, lambda: Matrix([1, 2]).dot([1, 2, 3])) raises(NonSquareMatrixError, lambda: Matrix([1, 2, 3]).exp()) raises(ShapeError, lambda: Matrix([[1, 2], [3, 4]]).normalized()) raises(ValueError, lambda: Matrix([1, 2]).inv(method='not a method')) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).inverse_GE()) raises(ValueError, lambda: Matrix([[1, 2], [1, 2]]).inverse_GE()) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).inverse_ADJ()) raises(ValueError, lambda: Matrix([[1, 2], [1, 2]]).inverse_ADJ()) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).inverse_LU()) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).is_nilpotent()) raises(NonSquareMatrixError, lambda: Matrix([1, 2]).det()) raises(ValueError, lambda: Matrix([[1, 2], [3, 4]]).det(method='Not a real method')) raises(ValueError, lambda: Matrix([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]).det(iszerofunc="Not function")) raises(ValueError, lambda: Matrix([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]).det(iszerofunc=False)) raises(ValueError, lambda: hessian(Matrix([[1, 2], [3, 4]]), Matrix([[1, 2], [2, 1]]))) raises(ValueError, lambda: hessian(Matrix([[1, 2], [3, 4]]), [])) raises(ValueError, lambda: hessian(Symbol('x')**2, 'a')) raises(IndexError, lambda: eye(3)[5, 2]) raises(IndexError, lambda: eye(3)[2, 5]) M = Matrix(((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16))) raises(ValueError, lambda: M.det('method=LU_decomposition()')) V = Matrix([[10, 10, 10]]) M = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) raises(ValueError, lambda: M.row_insert(4.7, V)) M = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) raises(ValueError, lambda: M.col_insert(-4.2, V)) def test_len(): assert len(Matrix()) == 0 assert len(Matrix([[1, 2]])) == len(Matrix([[1], [2]])) == 2 assert len(Matrix(0, 2, lambda i, j: 0)) == \ len(Matrix(2, 0, lambda i, j: 0)) == 0 assert len(Matrix([[0, 1, 2], [3, 4, 5]])) == 6 assert Matrix([1]) == Matrix([[1]]) assert not Matrix() assert Matrix() == Matrix([]) def test_integrate(): A = Matrix(((1, 4, x), (y, 2, 4), (10, 5, x**2))) assert A.integrate(x) == \ Matrix(((x, 4*x, x**2/2), (x*y, 2*x, 4*x), (10*x, 5*x, x**3/3))) assert A.integrate(y) == \ Matrix(((y, 4*y, x*y), (y**2/2, 2*y, 4*y), (10*y, 5*y, y*x**2))) def test_limit(): A = Matrix(((1, 4, sin(x)/x), (y, 2, 4), (10, 5, x**2 + 1))) assert A.limit(x, 0) == Matrix(((1, 4, 1), (y, 2, 4), (10, 5, 1))) def test_diff(): A = MutableDenseMatrix(((1, 4, x), (y, 2, 4), (10, 5, x**2 + 1))) assert isinstance(A.diff(x), type(A)) assert A.diff(x) == MutableDenseMatrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x))) assert A.diff(y) == MutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0))) assert diff(A, x) == MutableDenseMatrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x))) assert diff(A, y) == MutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0))) A_imm = A.as_immutable() assert isinstance(A_imm.diff(x), type(A_imm)) assert A_imm.diff(x) == ImmutableDenseMatrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x))) assert A_imm.diff(y) == ImmutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0))) assert diff(A_imm, x) == ImmutableDenseMatrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x))) assert diff(A_imm, y) == ImmutableDenseMatrix(((0, 0, 0), (1, 0, 0), (0, 0, 0))) def test_diff_by_matrix(): # Derive matrix by matrix: A = MutableDenseMatrix([[x, y], [z, t]]) assert A.diff(A) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]]) assert diff(A, A) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]]) A_imm = A.as_immutable() assert A_imm.diff(A_imm) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]]) assert diff(A_imm, A_imm) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]]) # Derive a constant matrix: assert A.diff(a) == MutableDenseMatrix([[0, 0], [0, 0]]) B = ImmutableDenseMatrix([a, b]) assert A.diff(B) == Array.zeros(2, 1, 2, 2) assert A.diff(A) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]]) # Test diff with tuples: dB = B.diff([[a, b]]) assert dB.shape == (2, 2, 1) assert dB == Array([[[1], [0]], [[0], [1]]]) f = Function("f") fxyz = f(x, y, z) assert fxyz.diff([[x, y, z]]) == Array([fxyz.diff(x), fxyz.diff(y), fxyz.diff(z)]) assert fxyz.diff(([x, y, z], 2)) == Array([ [fxyz.diff(x, 2), fxyz.diff(x, y), fxyz.diff(x, z)], [fxyz.diff(x, y), fxyz.diff(y, 2), fxyz.diff(y, z)], [fxyz.diff(x, z), fxyz.diff(z, y), fxyz.diff(z, 2)], ]) expr = sin(x)*exp(y) assert expr.diff([[x, y]]) == Array([cos(x)*exp(y), sin(x)*exp(y)]) assert expr.diff(y, ((x, y),)) == Array([cos(x)*exp(y), sin(x)*exp(y)]) assert expr.diff(x, ((x, y),)) == Array([-sin(x)*exp(y), cos(x)*exp(y)]) assert expr.diff(((y, x),), [[x, y]]) == Array([[cos(x)*exp(y), -sin(x)*exp(y)], [sin(x)*exp(y), cos(x)*exp(y)]]) # Test different notations: fxyz.diff(x).diff(y).diff(x) == fxyz.diff(((x, y, z),), 3)[0, 1, 0] fxyz.diff(z).diff(y).diff(x) == fxyz.diff(((x, y, z),), 3)[2, 1, 0] fxyz.diff([[x, y, z]], ((z, y, x),)) == Array([[fxyz.diff(i).diff(j) for i in (x, y, z)] for j in (z, y, x)]) # Test scalar derived by matrix remains matrix: res = x.diff(Matrix([[x, y]])) assert isinstance(res, ImmutableDenseMatrix) assert res == Matrix([[1, 0]]) res = (x**3).diff(Matrix([[x, y]])) assert isinstance(res, ImmutableDenseMatrix) assert res == Matrix([[3*x**2, 0]]) def test_getattr(): A = Matrix(((1, 4, x), (y, 2, 4), (10, 5, x**2 + 1))) raises(AttributeError, lambda: A.nonexistantattribute) assert getattr(A, 'diff')(x) == Matrix(((0, 0, 1), (0, 0, 0), (0, 0, 2*x))) def test_hessenberg(): A = Matrix([[3, 4, 1], [2, 4, 5], [0, 1, 2]]) assert A.is_upper_hessenberg A = A.T assert A.is_lower_hessenberg A[0, -1] = 1 assert A.is_lower_hessenberg is False A = Matrix([[3, 4, 1], [2, 4, 5], [3, 1, 2]]) assert not A.is_upper_hessenberg A = zeros(5, 2) assert A.is_upper_hessenberg def test_cholesky(): raises(NonSquareMatrixError, lambda: Matrix((1, 2)).cholesky()) raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).cholesky()) raises(ValueError, lambda: Matrix(((5 + I, 0), (0, 1))).cholesky()) raises(ValueError, lambda: Matrix(((1, 5), (5, 1))).cholesky()) raises(ValueError, lambda: Matrix(((1, 2), (3, 4))).cholesky(hermitian=False)) assert Matrix(((5 + I, 0), (0, 1))).cholesky(hermitian=False) == Matrix([ [sqrt(5 + I), 0], [0, 1]]) A = Matrix(((1, 5), (5, 1))) L = A.cholesky(hermitian=False) assert L == Matrix([[1, 0], [5, 2*sqrt(6)*I]]) assert L*L.T == A A = Matrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) L = A.cholesky() assert L * L.T == A assert L.is_lower assert L == Matrix([[5, 0, 0], [3, 3, 0], [-1, 1, 3]]) A = Matrix(((4, -2*I, 2 + 2*I), (2*I, 2, -1 + I), (2 - 2*I, -1 - I, 11))) assert A.cholesky().expand() == Matrix(((2, 0, 0), (I, 1, 0), (1 - I, 0, 3))) raises(NonSquareMatrixError, lambda: SparseMatrix((1, 2)).cholesky()) raises(ValueError, lambda: SparseMatrix(((1, 2), (3, 4))).cholesky()) raises(ValueError, lambda: SparseMatrix(((5 + I, 0), (0, 1))).cholesky()) raises(ValueError, lambda: SparseMatrix(((1, 5), (5, 1))).cholesky()) raises(ValueError, lambda: SparseMatrix(((1, 2), (3, 4))).cholesky(hermitian=False)) assert SparseMatrix(((5 + I, 0), (0, 1))).cholesky(hermitian=False) == Matrix([ [sqrt(5 + I), 0], [0, 1]]) A = SparseMatrix(((1, 5), (5, 1))) L = A.cholesky(hermitian=False) assert L == Matrix([[1, 0], [5, 2*sqrt(6)*I]]) assert L*L.T == A A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) L = A.cholesky() assert L * L.T == A assert L.is_lower assert L == Matrix([[5, 0, 0], [3, 3, 0], [-1, 1, 3]]) A = SparseMatrix(((4, -2*I, 2 + 2*I), (2*I, 2, -1 + I), (2 - 2*I, -1 - I, 11))) assert A.cholesky() == Matrix(((2, 0, 0), (I, 1, 0), (1 - I, 0, 3))) def test_matrix_norm(): # Vector Tests # Test columns and symbols x = Symbol('x', real=True) v = Matrix([cos(x), sin(x)]) assert trigsimp(v.norm(2)) == 1 assert v.norm(10) == Pow(cos(x)**10 + sin(x)**10, Rational(1, 10)) # Test Rows A = Matrix([[5, Rational(3, 2)]]) assert A.norm() == Pow(25 + Rational(9, 4), S.Half) assert A.norm(oo) == max(A) assert A.norm(-oo) == min(A) # Matrix Tests # Intuitive test A = Matrix([[1, 1], [1, 1]]) assert A.norm(2) == 2 assert A.norm(-2) == 0 assert A.norm('frobenius') == 2 assert eye(10).norm(2) == eye(10).norm(-2) == 1 assert A.norm(oo) == 2 # Test with Symbols and more complex entries A = Matrix([[3, y, y], [x, S.Half, -pi]]) assert (A.norm('fro') == sqrt(Rational(37, 4) + 2*abs(y)**2 + pi**2 + x**2)) # Check non-square A = Matrix([[1, 2, -3], [4, 5, Rational(13, 2)]]) assert A.norm(2) == sqrt(Rational(389, 8) + sqrt(78665)/8) assert A.norm(-2) is S.Zero assert A.norm('frobenius') == sqrt(389)/2 # Test properties of matrix norms # https://en.wikipedia.org/wiki/Matrix_norm#Definition # Two matrices A = Matrix([[1, 2], [3, 4]]) B = Matrix([[5, 5], [-2, 2]]) C = Matrix([[0, -I], [I, 0]]) D = Matrix([[1, 0], [0, -1]]) L = [A, B, C, D] alpha = Symbol('alpha', real=True) for order in ['fro', 2, -2]: # Zero Check assert zeros(3).norm(order) is S.Zero # Check Triangle Inequality for all Pairs of Matrices for X in L: for Y in L: dif = (X.norm(order) + Y.norm(order) - (X + Y).norm(order)) assert (dif >= 0) # Scalar multiplication linearity for M in [A, B, C, D]: dif = simplify((alpha*M).norm(order) - abs(alpha) * M.norm(order)) assert dif == 0 # Test Properties of Vector Norms # https://en.wikipedia.org/wiki/Vector_norm # Two column vectors a = Matrix([1, 1 - 1*I, -3]) b = Matrix([S.Half, 1*I, 1]) c = Matrix([-1, -1, -1]) d = Matrix([3, 2, I]) e = Matrix([Integer(1e2), Rational(1, 1e2), 1]) L = [a, b, c, d, e] alpha = Symbol('alpha', real=True) for order in [1, 2, -1, -2, S.Infinity, S.NegativeInfinity, pi]: # Zero Check if order > 0: assert Matrix([0, 0, 0]).norm(order) is S.Zero # Triangle inequality on all pairs if order >= 1: # Triangle InEq holds only for these norms for X in L: for Y in L: dif = (X.norm(order) + Y.norm(order) - (X + Y).norm(order)) assert simplify(dif >= 0) is S.true # Linear to scalar multiplication if order in [1, 2, -1, -2, S.Infinity, S.NegativeInfinity]: for X in L: dif = simplify((alpha*X).norm(order) - (abs(alpha) * X.norm(order))) assert dif == 0 # ord=1 M = Matrix(3, 3, [1, 3, 0, -2, -1, 0, 3, 9, 6]) assert M.norm(1) == 13 def test_condition_number(): x = Symbol('x', real=True) A = eye(3) A[0, 0] = 10 A[2, 2] = Rational(1, 10) assert A.condition_number() == 100 A[1, 1] = x assert A.condition_number() == Max(10, Abs(x)) / Min(Rational(1, 10), Abs(x)) M = Matrix([[cos(x), sin(x)], [-sin(x), cos(x)]]) Mc = M.condition_number() assert all(Float(1.).epsilon_eq(Mc.subs(x, val).evalf()) for val in [Rational(1, 5), S.Half, Rational(1, 10), pi/2, pi, pi*Rational(7, 4) ]) #issue 10782 assert Matrix([]).condition_number() == 0 def test_equality(): A = Matrix(((1, 2, 3), (4, 5, 6), (7, 8, 9))) B = Matrix(((9, 8, 7), (6, 5, 4), (3, 2, 1))) assert A == A[:, :] assert not A != A[:, :] assert not A == B assert A != B assert A != 10 assert not A == 10 # A SparseMatrix can be equal to a Matrix C = SparseMatrix(((1, 0, 0), (0, 1, 0), (0, 0, 1))) D = Matrix(((1, 0, 0), (0, 1, 0), (0, 0, 1))) assert C == D assert not C != D def test_col_join(): assert eye(3).col_join(Matrix([[7, 7, 7]])) == \ Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1], [7, 7, 7]]) def test_row_insert(): r4 = Matrix([[4, 4, 4]]) for i in range(-4, 5): l = [1, 0, 0] l.insert(i, 4) assert flatten(eye(3).row_insert(i, r4).col(0).tolist()) == l def test_col_insert(): c4 = Matrix([4, 4, 4]) for i in range(-4, 5): l = [0, 0, 0] l.insert(i, 4) assert flatten(zeros(3).col_insert(i, c4).row(0).tolist()) == l def test_normalized(): assert Matrix([3, 4]).normalized() == \ Matrix([Rational(3, 5), Rational(4, 5)]) # Zero vector trivial cases assert Matrix([0, 0, 0]).normalized() == Matrix([0, 0, 0]) # Machine precision error truncation trivial cases m = Matrix([0,0,1.e-100]) assert m.normalized( iszerofunc=lambda x: x.evalf(n=10, chop=True).is_zero ) == Matrix([0, 0, 0]) def test_print_nonzero(): assert capture(lambda: eye(3).print_nonzero()) == \ '[X ]\n[ X ]\n[ X]\n' assert capture(lambda: eye(3).print_nonzero('.')) == \ '[. ]\n[ . ]\n[ .]\n' def test_zeros_eye(): assert Matrix.eye(3) == eye(3) assert Matrix.zeros(3) == zeros(3) assert ones(3, 4) == Matrix(3, 4, [1]*12) i = Matrix([[1, 0], [0, 1]]) z = Matrix([[0, 0], [0, 0]]) for cls in classes: m = cls.eye(2) assert i == m # but m == i will fail if m is immutable assert i == eye(2, cls=cls) assert type(m) == cls m = cls.zeros(2) assert z == m assert z == zeros(2, cls=cls) assert type(m) == cls def test_is_zero(): assert Matrix().is_zero_matrix assert Matrix([[0, 0], [0, 0]]).is_zero_matrix assert zeros(3, 4).is_zero_matrix assert not eye(3).is_zero_matrix assert Matrix([[x, 0], [0, 0]]).is_zero_matrix == None assert SparseMatrix([[x, 0], [0, 0]]).is_zero_matrix == None assert ImmutableMatrix([[x, 0], [0, 0]]).is_zero_matrix == None assert ImmutableSparseMatrix([[x, 0], [0, 0]]).is_zero_matrix == None assert Matrix([[x, 1], [0, 0]]).is_zero_matrix == False a = Symbol('a', nonzero=True) assert Matrix([[a, 0], [0, 0]]).is_zero_matrix == False def test_rotation_matrices(): # This tests the rotation matrices by rotating about an axis and back. theta = pi/3 r3_plus = rot_axis3(theta) r3_minus = rot_axis3(-theta) r2_plus = rot_axis2(theta) r2_minus = rot_axis2(-theta) r1_plus = rot_axis1(theta) r1_minus = rot_axis1(-theta) assert r3_minus*r3_plus*eye(3) == eye(3) assert r2_minus*r2_plus*eye(3) == eye(3) assert r1_minus*r1_plus*eye(3) == eye(3) # Check the correctness of the trace of the rotation matrix assert r1_plus.trace() == 1 + 2*cos(theta) assert r2_plus.trace() == 1 + 2*cos(theta) assert r3_plus.trace() == 1 + 2*cos(theta) # Check that a rotation with zero angle doesn't change anything. assert rot_axis1(0) == eye(3) assert rot_axis2(0) == eye(3) assert rot_axis3(0) == eye(3) def test_DeferredVector(): assert str(DeferredVector("vector")[4]) == "vector[4]" assert sympify(DeferredVector("d")) == DeferredVector("d") raises(IndexError, lambda: DeferredVector("d")[-1]) assert str(DeferredVector("d")) == "d" assert repr(DeferredVector("test")) == "DeferredVector('test')" def test_DeferredVector_not_iterable(): assert not iterable(DeferredVector('X')) def test_DeferredVector_Matrix(): raises(TypeError, lambda: Matrix(DeferredVector("V"))) def test_GramSchmidt(): R = Rational m1 = Matrix(1, 2, [1, 2]) m2 = Matrix(1, 2, [2, 3]) assert GramSchmidt([m1, m2]) == \ [Matrix(1, 2, [1, 2]), Matrix(1, 2, [R(2)/5, R(-1)/5])] assert GramSchmidt([m1.T, m2.T]) == \ [Matrix(2, 1, [1, 2]), Matrix(2, 1, [R(2)/5, R(-1)/5])] # from wikipedia assert GramSchmidt([Matrix([3, 1]), Matrix([2, 2])], True) == [ Matrix([3*sqrt(10)/10, sqrt(10)/10]), Matrix([-sqrt(10)/10, 3*sqrt(10)/10])] # https://github.com/sympy/sympy/issues/9488 L = FiniteSet(Matrix([1])) assert GramSchmidt(L) == [Matrix([[1]])] def test_casoratian(): assert casoratian([1, 2, 3, 4], 1) == 0 assert casoratian([1, 2, 3, 4], 1, zero=False) == 0 def test_zero_dimension_multiply(): assert (Matrix()*zeros(0, 3)).shape == (0, 3) assert zeros(3, 0)*zeros(0, 3) == zeros(3, 3) assert zeros(0, 3)*zeros(3, 0) == Matrix() def test_slice_issue_2884(): m = Matrix(2, 2, range(4)) assert m[1, :] == Matrix([[2, 3]]) assert m[-1, :] == Matrix([[2, 3]]) assert m[:, 1] == Matrix([[1, 3]]).T assert m[:, -1] == Matrix([[1, 3]]).T raises(IndexError, lambda: m[2, :]) raises(IndexError, lambda: m[2, 2]) def test_slice_issue_3401(): assert zeros(0, 3)[:, -1].shape == (0, 1) assert zeros(3, 0)[0, :] == Matrix(1, 0, []) def test_copyin(): s = zeros(3, 3) s[3] = 1 assert s[:, 0] == Matrix([0, 1, 0]) assert s[3] == 1 assert s[3: 4] == [1] s[1, 1] = 42 assert s[1, 1] == 42 assert s[1, 1:] == Matrix([[42, 0]]) s[1, 1:] = Matrix([[5, 6]]) assert s[1, :] == Matrix([[1, 5, 6]]) s[1, 1:] = [[42, 43]] assert s[1, :] == Matrix([[1, 42, 43]]) s[0, 0] = 17 assert s[:, :1] == Matrix([17, 1, 0]) s[0, 0] = [1, 1, 1] assert s[:, 0] == Matrix([1, 1, 1]) s[0, 0] = Matrix([1, 1, 1]) assert s[:, 0] == Matrix([1, 1, 1]) s[0, 0] = SparseMatrix([1, 1, 1]) assert s[:, 0] == Matrix([1, 1, 1]) def test_invertible_check(): # sometimes a singular matrix will have a pivot vector shorter than # the number of rows in a matrix... assert Matrix([[1, 2], [1, 2]]).rref() == (Matrix([[1, 2], [0, 0]]), (0,)) raises(ValueError, lambda: Matrix([[1, 2], [1, 2]]).inv()) m = Matrix([ [-1, -1, 0], [ x, 1, 1], [ 1, x, -1], ]) assert len(m.rref()[1]) != m.rows # in addition, unless simplify=True in the call to rref, the identity # matrix will be returned even though m is not invertible assert m.rref()[0] != eye(3) assert m.rref(simplify=signsimp)[0] != eye(3) raises(ValueError, lambda: m.inv(method="ADJ")) raises(ValueError, lambda: m.inv(method="GE")) raises(ValueError, lambda: m.inv(method="LU")) def test_issue_3959(): x, y = symbols('x, y') e = x*y assert e.subs(x, Matrix([3, 5, 3])) == Matrix([3, 5, 3])*y def test_issue_5964(): assert str(Matrix([[1, 2], [3, 4]])) == 'Matrix([[1, 2], [3, 4]])' def test_issue_7604(): x, y = symbols("x y") assert sstr(Matrix([[x, 2*y], [y**2, x + 3]])) == \ 'Matrix([\n[ x, 2*y],\n[y**2, x + 3]])' def test_is_Identity(): assert eye(3).is_Identity assert eye(3).as_immutable().is_Identity assert not zeros(3).is_Identity assert not ones(3).is_Identity # issue 6242 assert not Matrix([[1, 0, 0]]).is_Identity # issue 8854 assert SparseMatrix(3,3, {(0,0):1, (1,1):1, (2,2):1}).is_Identity assert not SparseMatrix(2,3, range(6)).is_Identity assert not SparseMatrix(3,3, {(0,0):1, (1,1):1}).is_Identity assert not SparseMatrix(3,3, {(0,0):1, (1,1):1, (2,2):1, (0,1):2, (0,2):3}).is_Identity def test_dot(): assert ones(1, 3).dot(ones(3, 1)) == 3 assert ones(1, 3).dot([1, 1, 1]) == 3 assert Matrix([1, 2, 3]).dot(Matrix([1, 2, 3])) == 14 assert Matrix([1, 2, 3*I]).dot(Matrix([I, 2, 3*I])) == -5 + I assert Matrix([1, 2, 3*I]).dot(Matrix([I, 2, 3*I]), hermitian=False) == -5 + I assert Matrix([1, 2, 3*I]).dot(Matrix([I, 2, 3*I]), hermitian=True) == 13 + I assert Matrix([1, 2, 3*I]).dot(Matrix([I, 2, 3*I]), hermitian=True, conjugate_convention="physics") == 13 - I assert Matrix([1, 2, 3*I]).dot(Matrix([4, 5*I, 6]), hermitian=True, conjugate_convention="right") == 4 + 8*I assert Matrix([1, 2, 3*I]).dot(Matrix([4, 5*I, 6]), hermitian=True, conjugate_convention="left") == 4 - 8*I assert Matrix([I, 2*I]).dot(Matrix([I, 2*I]), hermitian=False, conjugate_convention="left") == -5 assert Matrix([I, 2*I]).dot(Matrix([I, 2*I]), conjugate_convention="left") == 5 raises(ValueError, lambda: Matrix([1, 2]).dot(Matrix([3, 4]), hermitian=True, conjugate_convention="test")) def test_dual(): B_x, B_y, B_z, E_x, E_y, E_z = symbols( 'B_x B_y B_z E_x E_y E_z', real=True) F = Matrix(( ( 0, E_x, E_y, E_z), (-E_x, 0, B_z, -B_y), (-E_y, -B_z, 0, B_x), (-E_z, B_y, -B_x, 0) )) Fd = Matrix(( ( 0, -B_x, -B_y, -B_z), (B_x, 0, E_z, -E_y), (B_y, -E_z, 0, E_x), (B_z, E_y, -E_x, 0) )) assert F.dual().equals(Fd) assert eye(3).dual().equals(zeros(3)) assert F.dual().dual().equals(-F) def test_anti_symmetric(): assert Matrix([1, 2]).is_anti_symmetric() is False m = Matrix(3, 3, [0, x**2 + 2*x + 1, y, -(x + 1)**2, 0, x*y, -y, -x*y, 0]) assert m.is_anti_symmetric() is True assert m.is_anti_symmetric(simplify=False) is False assert m.is_anti_symmetric(simplify=lambda x: x) is False # tweak to fail m[2, 1] = -m[2, 1] assert m.is_anti_symmetric() is False # untweak m[2, 1] = -m[2, 1] m = m.expand() assert m.is_anti_symmetric(simplify=False) is True m[0, 0] = 1 assert m.is_anti_symmetric() is False def test_normalize_sort_diogonalization(): A = Matrix(((1, 2), (2, 1))) P, Q = A.diagonalize(normalize=True) assert P*P.T == P.T*P == eye(P.cols) P, Q = A.diagonalize(normalize=True, sort=True) assert P*P.T == P.T*P == eye(P.cols) assert P*Q*P.inv() == A def test_issue_5321(): raises(ValueError, lambda: Matrix([[1, 2, 3], Matrix(0, 1, [])])) def test_issue_5320(): assert Matrix.hstack(eye(2), 2*eye(2)) == Matrix([ [1, 0, 2, 0], [0, 1, 0, 2] ]) assert Matrix.vstack(eye(2), 2*eye(2)) == Matrix([ [1, 0], [0, 1], [2, 0], [0, 2] ]) cls = SparseMatrix assert cls.hstack(cls(eye(2)), cls(2*eye(2))) == Matrix([ [1, 0, 2, 0], [0, 1, 0, 2] ]) def test_issue_11944(): A = Matrix([[1]]) AIm = sympify(A) assert Matrix.hstack(AIm, A) == Matrix([[1, 1]]) assert Matrix.vstack(AIm, A) == Matrix([[1], [1]]) def test_cross(): a = [1, 2, 3] b = [3, 4, 5] col = Matrix([-2, 4, -2]) row = col.T def test(M, ans): assert ans == M assert type(M) == cls for cls in classes: A = cls(a) B = cls(b) test(A.cross(B), col) test(A.cross(B.T), col) test(A.T.cross(B.T), row) test(A.T.cross(B), row) raises(ShapeError, lambda: Matrix(1, 2, [1, 1]).cross(Matrix(1, 2, [1, 1]))) def test_hash(): for cls in classes[-2:]: s = {cls.eye(1), cls.eye(1)} assert len(s) == 1 and s.pop() == cls.eye(1) # issue 3979 for cls in classes[:2]: assert not isinstance(cls.eye(1), Hashable) @XFAIL def test_issue_3979(): # when this passes, delete this and change the [1:2] # to [:2] in the test_hash above for issue 3979 cls = classes[0] raises(AttributeError, lambda: hash(cls.eye(1))) def test_adjoint(): dat = [[0, I], [1, 0]] ans = Matrix([[0, 1], [-I, 0]]) for cls in classes: assert ans == cls(dat).adjoint() def test_simplify_immutable(): from sympy import simplify, sin, cos assert simplify(ImmutableMatrix([[sin(x)**2 + cos(x)**2]])) == \ ImmutableMatrix([[1]]) def test_replace(): from sympy import symbols, Function, Matrix F, G = symbols('F, G', cls=Function) K = Matrix(2, 2, lambda i, j: G(i+j)) M = Matrix(2, 2, lambda i, j: F(i+j)) N = M.replace(F, G) assert N == K def test_replace_map(): from sympy import symbols, Function, Matrix F, G = symbols('F, G', cls=Function) with warns_deprecated_sympy(): K = Matrix(2, 2, [(G(0), {F(0): G(0)}), (G(1), {F(1): G(1)}), (G(1), {F(1): G(1)}), (G(2), {F(2): G(2)})]) M = Matrix(2, 2, lambda i, j: F(i+j)) with warns_deprecated_sympy(): N = M.replace(F, G, True) assert N == K def test_atoms(): m = Matrix([[1, 2], [x, 1 - 1/x]]) assert m.atoms() == {S.One,S(2),S.NegativeOne, x} assert m.atoms(Symbol) == {x} def test_pinv(): # Pseudoinverse of an invertible matrix is the inverse. A1 = Matrix([[a, b], [c, d]]) assert simplify(A1.pinv(method="RD")) == simplify(A1.inv()) # Test the four properties of the pseudoinverse for various matrices. As = [Matrix([[13, 104], [2212, 3], [-3, 5]]), Matrix([[1, 7, 9], [11, 17, 19]]), Matrix([a, b])] for A in As: A_pinv = A.pinv(method="RD") AAp = A * A_pinv ApA = A_pinv * A assert simplify(AAp * A) == A assert simplify(ApA * A_pinv) == A_pinv assert AAp.H == AAp assert ApA.H == ApA # XXX Pinv with diagonalization makes expression too complicated. for A in As: A_pinv = simplify(A.pinv(method="ED")) AAp = A * A_pinv ApA = A_pinv * A assert simplify(AAp * A) == A assert simplify(ApA * A_pinv) == A_pinv assert AAp.H == AAp assert ApA.H == ApA # XXX Computing pinv using diagonalization makes an expression that # is too complicated to simplify. # A1 = Matrix([[a, b], [c, d]]) # assert simplify(A1.pinv(method="ED")) == simplify(A1.inv()) # so this is tested numerically at a fixed random point from sympy.core.numbers import comp q = A1.pinv(method="ED") w = A1.inv() reps = {a: -73633, b: 11362, c: 55486, d: 62570} assert all( comp(i.n(), j.n()) for i, j in zip(q.subs(reps), w.subs(reps)) ) @slow @XFAIL def test_pinv_rank_deficient_when_diagonalization_fails(): # Test the four properties of the pseudoinverse for matrices when # diagonalization of A.H*A fails. As = [ Matrix([ [61, 89, 55, 20, 71, 0], [62, 96, 85, 85, 16, 0], [69, 56, 17, 4, 54, 0], [10, 54, 91, 41, 71, 0], [ 7, 30, 10, 48, 90, 0], [0, 0, 0, 0, 0, 0]]) ] for A in As: A_pinv = A.pinv(method="ED") AAp = A * A_pinv ApA = A_pinv * A assert AAp.H == AAp assert ApA.H == ApA def test_issue_7201(): assert ones(0, 1) + ones(0, 1) == Matrix(0, 1, []) assert ones(1, 0) + ones(1, 0) == Matrix(1, 0, []) def test_free_symbols(): for M in ImmutableMatrix, ImmutableSparseMatrix, Matrix, SparseMatrix: assert M([[x], [0]]).free_symbols == {x} def test_from_ndarray(): """See issue 7465.""" try: from numpy import array except ImportError: skip('NumPy must be available to test creating matrices from ndarrays') assert Matrix(array([1, 2, 3])) == Matrix([1, 2, 3]) assert Matrix(array([[1, 2, 3]])) == Matrix([[1, 2, 3]]) assert Matrix(array([[1, 2, 3], [4, 5, 6]])) == \ Matrix([[1, 2, 3], [4, 5, 6]]) assert Matrix(array([x, y, z])) == Matrix([x, y, z]) raises(NotImplementedError, lambda: Matrix(array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]))) assert Matrix([array([1, 2]), array([3, 4])]) == Matrix([[1, 2], [3, 4]]) assert Matrix([array([1, 2]), [3, 4]]) == Matrix([[1, 2], [3, 4]]) assert Matrix([array([]), array([])]) == Matrix([]) def test_17522_numpy(): from sympy.matrices.common import _matrixify try: from numpy import array, matrix except ImportError: skip('NumPy must be available to test indexing matrixified NumPy ndarrays and matrices') m = _matrixify(array([[1, 2], [3, 4]])) assert m[3] == 4 assert list(m) == [1, 2, 3, 4] m = _matrixify(matrix([[1, 2], [3, 4]])) assert m[3] == 4 assert list(m) == [1, 2, 3, 4] def test_17522_mpmath(): from sympy.matrices.common import _matrixify try: from mpmath import matrix except ImportError: skip('mpmath must be available to test indexing matrixified mpmath matrices') m = _matrixify(matrix([[1, 2], [3, 4]])) assert m[3] == 4 assert list(m) == [1, 2, 3, 4] def test_17522_scipy(): from sympy.matrices.common import _matrixify try: from scipy.sparse import csr_matrix except ImportError: skip('SciPy must be available to test indexing matrixified SciPy sparse matrices') m = _matrixify(csr_matrix([[1, 2], [3, 4]])) assert m[3] == 4 assert list(m) == [1, 2, 3, 4] def test_hermitian(): a = Matrix([[1, I], [-I, 1]]) assert a.is_hermitian a[0, 0] = 2*I assert a.is_hermitian is False a[0, 0] = x assert a.is_hermitian is None a[0, 1] = a[1, 0]*I assert a.is_hermitian is False def test_doit(): a = Matrix([[Add(x,x, evaluate=False)]]) assert a[0] != 2*x assert a.doit() == Matrix([[2*x]]) def test_issue_9457_9467_9876(): # for row_del(index) M = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) M.row_del(1) assert M == Matrix([[1, 2, 3], [3, 4, 5]]) N = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) N.row_del(-2) assert N == Matrix([[1, 2, 3], [3, 4, 5]]) O = Matrix([[1, 2, 3], [5, 6, 7], [9, 10, 11]]) O.row_del(-1) assert O == Matrix([[1, 2, 3], [5, 6, 7]]) P = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) raises(IndexError, lambda: P.row_del(10)) Q = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) raises(IndexError, lambda: Q.row_del(-10)) # for col_del(index) M = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) M.col_del(1) assert M == Matrix([[1, 3], [2, 4], [3, 5]]) N = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) N.col_del(-2) assert N == Matrix([[1, 3], [2, 4], [3, 5]]) P = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) raises(IndexError, lambda: P.col_del(10)) Q = Matrix([[1, 2, 3], [2, 3, 4], [3, 4, 5]]) raises(IndexError, lambda: Q.col_del(-10)) def test_issue_9422(): x, y = symbols('x y', commutative=False) a, b = symbols('a b') M = eye(2) M1 = Matrix(2, 2, [x, y, y, z]) assert y*x*M != x*y*M assert b*a*M == a*b*M assert x*M1 != M1*x assert a*M1 == M1*a assert y*x*M == Matrix([[y*x, 0], [0, y*x]]) def test_issue_10770(): M = Matrix([]) a = ['col_insert', 'row_join'], Matrix([9, 6, 3]) b = ['row_insert', 'col_join'], a[1].T c = ['row_insert', 'col_insert'], Matrix([[1, 2], [3, 4]]) for ops, m in (a, b, c): for op in ops: f = getattr(M, op) new = f(m) if 'join' in op else f(42, m) assert new == m and id(new) != id(m) def test_issue_10658(): A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) assert A.extract([0, 1, 2], [True, True, False]) == \ Matrix([[1, 2], [4, 5], [7, 8]]) assert A.extract([0, 1, 2], [True, False, False]) == Matrix([[1], [4], [7]]) assert A.extract([True, False, False], [0, 1, 2]) == Matrix([[1, 2, 3]]) assert A.extract([True, False, True], [0, 1, 2]) == \ Matrix([[1, 2, 3], [7, 8, 9]]) assert A.extract([0, 1, 2], [False, False, False]) == Matrix(3, 0, []) assert A.extract([False, False, False], [0, 1, 2]) == Matrix(0, 3, []) assert A.extract([True, False, True], [False, True, False]) == \ Matrix([[2], [8]]) def test_opportunistic_simplification(): # this test relates to issue #10718, #9480, #11434 # issue #9480 m = Matrix([[-5 + 5*sqrt(2), -5], [-5*sqrt(2)/2 + 5, -5*sqrt(2)/2]]) assert m.rank() == 1 # issue #10781 m = Matrix([[3+3*sqrt(3)*I, -9],[4,-3+3*sqrt(3)*I]]) assert simplify(m.rref()[0] - Matrix([[1, -9/(3 + 3*sqrt(3)*I)], [0, 0]])) == zeros(2, 2) # issue #11434 ax,ay,bx,by,cx,cy,dx,dy,ex,ey,t0,t1 = symbols('a_x a_y b_x b_y c_x c_y d_x d_y e_x e_y t_0 t_1') m = Matrix([[ax,ay,ax*t0,ay*t0,0],[bx,by,bx*t0,by*t0,0],[cx,cy,cx*t0,cy*t0,1],[dx,dy,dx*t0,dy*t0,1],[ex,ey,2*ex*t1-ex*t0,2*ey*t1-ey*t0,0]]) assert m.rank() == 4 def test_partial_pivoting(): # example from https://en.wikipedia.org/wiki/Pivot_element # partial pivoting with back substitution gives a perfect result # naive pivoting give an error ~1e-13, so anything better than # 1e-15 is good mm=Matrix([[0.003 ,59.14, 59.17],[ 5.291, -6.13,46.78]]) assert (mm.rref()[0] - Matrix([[1.0, 0, 10.0], [ 0, 1.0, 1.0]])).norm() < 1e-15 # issue #11549 m_mixed = Matrix([[6e-17, 1.0, 4],[ -1.0, 0, 8],[ 0, 0, 1]]) m_float = Matrix([[6e-17, 1.0, 4.],[ -1.0, 0., 8.],[ 0., 0., 1.]]) m_inv = Matrix([[ 0, -1.0, 8.0],[1.0, 6.0e-17, -4.0],[ 0, 0, 1]]) # this example is numerically unstable and involves a matrix with a norm >= 8, # this comparing the difference of the results with 1e-15 is numerically sound. assert (m_mixed.inv() - m_inv).norm() < 1e-15 assert (m_float.inv() - m_inv).norm() < 1e-15 def test_iszero_substitution(): """ When doing numerical computations, all elements that pass the iszerofunc test should be set to numerically zero if they aren't already. """ # Matrix from issue #9060 m = Matrix([[0.9, -0.1, -0.2, 0],[-0.8, 0.9, -0.4, 0],[-0.1, -0.8, 0.6, 0]]) m_rref = m.rref(iszerofunc=lambda x: abs(x)<6e-15)[0] m_correct = Matrix([[1.0, 0, -0.301369863013699, 0],[ 0, 1.0, -0.712328767123288, 0],[ 0, 0, 0, 0]]) m_diff = m_rref - m_correct assert m_diff.norm() < 1e-15 # if a zero-substitution wasn't made, this entry will be -1.11022302462516e-16 assert m_rref[2,2] == 0 def test_issue_11238(): from sympy import Point xx = 8*tan(pi*Rational(13, 45))/(tan(pi*Rational(13, 45)) + sqrt(3)) yy = (-8*sqrt(3)*tan(pi*Rational(13, 45))**2 + 24*tan(pi*Rational(13, 45)))/(-3 + tan(pi*Rational(13, 45))**2) p1 = Point(0, 0) p2 = Point(1, -sqrt(3)) p0 = Point(xx,yy) m1 = Matrix([p1 - simplify(p0), p2 - simplify(p0)]) m2 = Matrix([p1 - p0, p2 - p0]) m3 = Matrix([simplify(p1 - p0), simplify(p2 - p0)]) # This system has expressions which are zero and # cannot be easily proved to be such, so without # numerical testing, these assertions will fail. Z = lambda x: abs(x.n()) < 1e-20 assert m1.rank(simplify=True, iszerofunc=Z) == 1 assert m2.rank(simplify=True, iszerofunc=Z) == 1 assert m3.rank(simplify=True, iszerofunc=Z) == 1 def test_as_real_imag(): m1 = Matrix(2,2,[1,2,3,4]) m2 = m1*S.ImaginaryUnit m3 = m1 + m2 for kls in classes: a,b = kls(m3).as_real_imag() assert list(a) == list(m1) assert list(b) == list(m1) def test_deprecated(): # Maintain tests for deprecated functions. We must capture # the deprecation warnings. When the deprecated functionality is # removed, the corresponding tests should be removed. m = Matrix(3, 3, [0, 1, 0, -4, 4, 0, -2, 1, 2]) P, Jcells = m.jordan_cells() assert Jcells[1] == Matrix(1, 1, [2]) assert Jcells[0] == Matrix(2, 2, [2, 1, 0, 2]) with warns_deprecated_sympy(): assert Matrix([[1,2],[3,4]]).dot(Matrix([[1,3],[4,5]])) == [10, 19, 14, 28] def test_issue_14489(): from sympy import Mod A = Matrix([-1, 1, 2]) B = Matrix([10, 20, -15]) assert Mod(A, 3) == Matrix([2, 1, 2]) assert Mod(B, 4) == Matrix([2, 0, 1]) def test_issue_14943(): # Test that __array__ accepts the optional dtype argument try: from numpy import array except ImportError: skip('NumPy must be available to test creating matrices from ndarrays') M = Matrix([[1,2], [3,4]]) assert array(M, dtype=float).dtype.name == 'float64' def test_case_6913(): m = MatrixSymbol('m', 1, 1) a = Symbol("a") a = m[0, 0]>0 assert str(a) == 'm[0, 0] > 0' def test_issue_11948(): A = MatrixSymbol('A', 3, 3) a = Wild('a') assert A.match(a) == {a: A} def test_gramschmidt_conjugate_dot(): vecs = [Matrix([1, I]), Matrix([1, -I])] assert Matrix.orthogonalize(*vecs) == \ [Matrix([[1], [I]]), Matrix([[1], [-I]])] vecs = [Matrix([1, I, 0]), Matrix([I, 0, -I])] assert Matrix.orthogonalize(*vecs) == \ [Matrix([[1], [I], [0]]), Matrix([[I/2], [S(1)/2], [-I]])] mat = Matrix([[1, I], [1, -I]]) Q, R = mat.QRdecomposition() assert Q * Q.H == Matrix.eye(2) def test_issue_8207(): a = Matrix(MatrixSymbol('a', 3, 1)) b = Matrix(MatrixSymbol('b', 3, 1)) c = a.dot(b) d = diff(c, a[0, 0]) e = diff(d, a[0, 0]) assert d == b[0, 0] assert e == 0 def test_func(): from sympy.simplify.simplify import nthroot A = Matrix([[1, 2],[0, 3]]) assert A.analytic_func(sin(x*t), x) == Matrix([[sin(t), sin(3*t) - sin(t)], [0, sin(3*t)]]) A = Matrix([[2, 1],[1, 2]]) assert (pi * A / 6).analytic_func(cos(x), x) == Matrix([[sqrt(3)/4, -sqrt(3)/4], [-sqrt(3)/4, sqrt(3)/4]]) raises(ValueError, lambda : zeros(5).analytic_func(log(x), x)) raises(ValueError, lambda : (A*x).analytic_func(log(x), x)) A = Matrix([[0, -1, -2, 3], [0, -1, -2, 3], [0, 1, 0, -1], [0, 0, -1, 1]]) assert A.analytic_func(exp(x), x) == A.exp() raises(ValueError, lambda : A.analytic_func(sqrt(x), x)) A = Matrix([[41, 12],[12, 34]]) assert simplify(A.analytic_func(sqrt(x), x)**2) == A A = Matrix([[3, -12, 4], [-1, 0, -2], [-1, 5, -1]]) assert simplify(A.analytic_func(nthroot(x, 3), x)**3) == A A = Matrix([[2, 0, 0, 0], [1, 2, 0, 0], [0, 1, 3, 0], [0, 0, 1, 3]]) assert A.analytic_func(exp(x), x) == A.exp() A = Matrix([[0, 2, 1, 6], [0, 0, 1, 2], [0, 0, 0, 3], [0, 0, 0, 0]]) assert A.analytic_func(exp(x*t), x) == expand(simplify((A*t).exp())) def test_issue_19809(): def f(): assert _dotprodsimp_state.state == None m = Matrix([[1]]) m = m * m return True with dotprodsimp(True): with concurrent.futures.ThreadPoolExecutor() as executor: future = executor.submit(f) assert future.result() sympy-sympy-1.9/sympy/matrices/tests/test_normalforms.py000066400000000000000000000033771412543434000240370ustar00rootroot00000000000000from sympy.testing.pytest import warns_deprecated_sympy from sympy import Symbol, Poly from sympy.matrices import Matrix from sympy.matrices.normalforms import invariant_factors, smith_normal_form from sympy.polys.domains import ZZ, QQ def test_smith_normal(): m = Matrix([[12,6,4,8],[3,9,6,12],[2,16,14,28],[20,10,10,20]]) smf = Matrix([[1, 0, 0, 0], [0, 10, 0, 0], [0, 0, -30, 0], [0, 0, 0, 0]]) assert smith_normal_form(m) == smf x = Symbol('x') with warns_deprecated_sympy(): m = Matrix([[Poly(x-1), Poly(1, x),Poly(-1,x)], [0, Poly(x), Poly(-1,x)], [Poly(0,x),Poly(-1,x),Poly(x)]]) invs = 1, x - 1, x**2 - 1 assert invariant_factors(m, domain=QQ[x]) == invs m = Matrix([[2, 4]]) smf = Matrix([[2, 0]]) assert smith_normal_form(m) == smf def test_smith_normal_deprecated(): from sympy.polys.solvers import RawMatrix as Matrix with warns_deprecated_sympy(): m = Matrix([[12, 6, 4,8],[3,9,6,12],[2,16,14,28],[20,10,10,20]]) setattr(m, 'ring', ZZ) with warns_deprecated_sympy(): smf = Matrix([[1, 0, 0, 0], [0, 10, 0, 0], [0, 0, -30, 0], [0, 0, 0, 0]]) assert smith_normal_form(m) == smf x = Symbol('x') with warns_deprecated_sympy(): m = Matrix([[Poly(x-1), Poly(1, x),Poly(-1,x)], [0, Poly(x), Poly(-1,x)], [Poly(0,x),Poly(-1,x),Poly(x)]]) setattr(m, 'ring', QQ[x]) invs = (Poly(1, x, domain='QQ'), Poly(x - 1, domain='QQ'), Poly(x**2 - 1, domain='QQ')) assert invariant_factors(m) == invs with warns_deprecated_sympy(): m = Matrix([[2, 4]]) setattr(m, 'ring', ZZ) with warns_deprecated_sympy(): smf = Matrix([[2, 0]]) assert smith_normal_form(m) == smf sympy-sympy-1.9/sympy/matrices/tests/test_reductions.py000066400000000000000000000331251412543434000236510ustar00rootroot00000000000000from sympy import symbols, I from sympy.matrices.common import _MinimalMatrix, _CastableMatrix from sympy.matrices.matrices import MatrixReductions from sympy.testing.pytest import raises from sympy.matrices import Matrix, zeros from sympy.core.symbol import Symbol from sympy.core.numbers import Rational from sympy.functions.elementary.miscellaneous import sqrt from sympy.simplify.simplify import simplify from sympy.abc import x class ReductionsOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixReductions): pass def eye_Reductions(n): return ReductionsOnlyMatrix(n, n, lambda i, j: int(i == j)) def zeros_Reductions(n): return ReductionsOnlyMatrix(n, n, lambda i, j: 0) # ReductionsOnlyMatrix tests def test_row_op(): e = eye_Reductions(3) raises(ValueError, lambda: e.elementary_row_op("abc")) raises(ValueError, lambda: e.elementary_row_op()) raises(ValueError, lambda: e.elementary_row_op('n->kn', row=5, k=5)) raises(ValueError, lambda: e.elementary_row_op('n->kn', row=-5, k=5)) raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=1, row2=5)) raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=5, row2=1)) raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=-5, row2=1)) raises(ValueError, lambda: e.elementary_row_op('n<->m', row1=1, row2=-5)) raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=1, row2=5, k=5)) raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=5, row2=1, k=5)) raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=-5, row2=1, k=5)) raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=1, row2=-5, k=5)) raises(ValueError, lambda: e.elementary_row_op('n->n+km', row1=1, row2=1, k=5)) # test various ways to set arguments assert e.elementary_row_op("n->kn", 0, 5) == Matrix([[5, 0, 0], [0, 1, 0], [0, 0, 1]]) assert e.elementary_row_op("n->kn", 1, 5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]]) assert e.elementary_row_op("n->kn", row=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]]) assert e.elementary_row_op("n->kn", row1=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]]) assert e.elementary_row_op("n<->m", 0, 1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) assert e.elementary_row_op("n<->m", row1=0, row2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) assert e.elementary_row_op("n<->m", row=0, row2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) assert e.elementary_row_op("n->n+km", 0, 5, 1) == Matrix([[1, 5, 0], [0, 1, 0], [0, 0, 1]]) assert e.elementary_row_op("n->n+km", row=0, k=5, row2=1) == Matrix([[1, 5, 0], [0, 1, 0], [0, 0, 1]]) assert e.elementary_row_op("n->n+km", row1=0, k=5, row2=1) == Matrix([[1, 5, 0], [0, 1, 0], [0, 0, 1]]) # make sure the matrix doesn't change size a = ReductionsOnlyMatrix(2, 3, [0]*6) assert a.elementary_row_op("n->kn", 1, 5) == Matrix(2, 3, [0]*6) assert a.elementary_row_op("n<->m", 0, 1) == Matrix(2, 3, [0]*6) assert a.elementary_row_op("n->n+km", 0, 5, 1) == Matrix(2, 3, [0]*6) def test_col_op(): e = eye_Reductions(3) raises(ValueError, lambda: e.elementary_col_op("abc")) raises(ValueError, lambda: e.elementary_col_op()) raises(ValueError, lambda: e.elementary_col_op('n->kn', col=5, k=5)) raises(ValueError, lambda: e.elementary_col_op('n->kn', col=-5, k=5)) raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=1, col2=5)) raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=5, col2=1)) raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=-5, col2=1)) raises(ValueError, lambda: e.elementary_col_op('n<->m', col1=1, col2=-5)) raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=1, col2=5, k=5)) raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=5, col2=1, k=5)) raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=-5, col2=1, k=5)) raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=1, col2=-5, k=5)) raises(ValueError, lambda: e.elementary_col_op('n->n+km', col1=1, col2=1, k=5)) # test various ways to set arguments assert e.elementary_col_op("n->kn", 0, 5) == Matrix([[5, 0, 0], [0, 1, 0], [0, 0, 1]]) assert e.elementary_col_op("n->kn", 1, 5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]]) assert e.elementary_col_op("n->kn", col=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]]) assert e.elementary_col_op("n->kn", col1=1, k=5) == Matrix([[1, 0, 0], [0, 5, 0], [0, 0, 1]]) assert e.elementary_col_op("n<->m", 0, 1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) assert e.elementary_col_op("n<->m", col1=0, col2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) assert e.elementary_col_op("n<->m", col=0, col2=1) == Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) assert e.elementary_col_op("n->n+km", 0, 5, 1) == Matrix([[1, 0, 0], [5, 1, 0], [0, 0, 1]]) assert e.elementary_col_op("n->n+km", col=0, k=5, col2=1) == Matrix([[1, 0, 0], [5, 1, 0], [0, 0, 1]]) assert e.elementary_col_op("n->n+km", col1=0, k=5, col2=1) == Matrix([[1, 0, 0], [5, 1, 0], [0, 0, 1]]) # make sure the matrix doesn't change size a = ReductionsOnlyMatrix(2, 3, [0]*6) assert a.elementary_col_op("n->kn", 1, 5) == Matrix(2, 3, [0]*6) assert a.elementary_col_op("n<->m", 0, 1) == Matrix(2, 3, [0]*6) assert a.elementary_col_op("n->n+km", 0, 5, 1) == Matrix(2, 3, [0]*6) def test_is_echelon(): zro = zeros_Reductions(3) ident = eye_Reductions(3) assert zro.is_echelon assert ident.is_echelon a = ReductionsOnlyMatrix(0, 0, []) assert a.is_echelon a = ReductionsOnlyMatrix(2, 3, [3, 2, 1, 0, 0, 6]) assert a.is_echelon a = ReductionsOnlyMatrix(2, 3, [0, 0, 6, 3, 2, 1]) assert not a.is_echelon x = Symbol('x') a = ReductionsOnlyMatrix(3, 1, [x, 0, 0]) assert a.is_echelon a = ReductionsOnlyMatrix(3, 1, [x, x, 0]) assert not a.is_echelon a = ReductionsOnlyMatrix(3, 3, [0, 0, 0, 1, 2, 3, 0, 0, 0]) assert not a.is_echelon def test_echelon_form(): # echelon form is not unique, but the result # must be row-equivalent to the original matrix # and it must be in echelon form. a = zeros_Reductions(3) e = eye_Reductions(3) # we can assume the zero matrix and the identity matrix shouldn't change assert a.echelon_form() == a assert e.echelon_form() == e a = ReductionsOnlyMatrix(0, 0, []) assert a.echelon_form() == a a = ReductionsOnlyMatrix(1, 1, [5]) assert a.echelon_form() == a # now we get to the real tests def verify_row_null_space(mat, rows, nulls): for v in nulls: assert all(t.is_zero for t in a_echelon*v) for v in rows: if not all(t.is_zero for t in v): assert not all(t.is_zero for t in a_echelon*v.transpose()) a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) nulls = [Matrix([ [ 1], [-2], [ 1]])] rows = [a[i, :] for i in range(a.rows)] a_echelon = a.echelon_form() assert a_echelon.is_echelon verify_row_null_space(a, rows, nulls) a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 8]) nulls = [] rows = [a[i, :] for i in range(a.rows)] a_echelon = a.echelon_form() assert a_echelon.is_echelon verify_row_null_space(a, rows, nulls) a = ReductionsOnlyMatrix(3, 3, [2, 1, 3, 0, 0, 0, 2, 1, 3]) nulls = [Matrix([ [Rational(-1, 2)], [ 1], [ 0]]), Matrix([ [Rational(-3, 2)], [ 0], [ 1]])] rows = [a[i, :] for i in range(a.rows)] a_echelon = a.echelon_form() assert a_echelon.is_echelon verify_row_null_space(a, rows, nulls) # this one requires a row swap a = ReductionsOnlyMatrix(3, 3, [2, 1, 3, 0, 0, 0, 1, 1, 3]) nulls = [Matrix([ [ 0], [ -3], [ 1]])] rows = [a[i, :] for i in range(a.rows)] a_echelon = a.echelon_form() assert a_echelon.is_echelon verify_row_null_space(a, rows, nulls) a = ReductionsOnlyMatrix(3, 3, [0, 3, 3, 0, 2, 2, 0, 1, 1]) nulls = [Matrix([ [1], [0], [0]]), Matrix([ [ 0], [-1], [ 1]])] rows = [a[i, :] for i in range(a.rows)] a_echelon = a.echelon_form() assert a_echelon.is_echelon verify_row_null_space(a, rows, nulls) a = ReductionsOnlyMatrix(2, 3, [2, 2, 3, 3, 3, 0]) nulls = [Matrix([ [-1], [1], [0]])] rows = [a[i, :] for i in range(a.rows)] a_echelon = a.echelon_form() assert a_echelon.is_echelon verify_row_null_space(a, rows, nulls) def test_rref(): e = ReductionsOnlyMatrix(0, 0, []) assert e.rref(pivots=False) == e e = ReductionsOnlyMatrix(1, 1, [1]) a = ReductionsOnlyMatrix(1, 1, [5]) assert e.rref(pivots=False) == a.rref(pivots=False) == e a = ReductionsOnlyMatrix(3, 1, [1, 2, 3]) assert a.rref(pivots=False) == Matrix([[1], [0], [0]]) a = ReductionsOnlyMatrix(1, 3, [1, 2, 3]) assert a.rref(pivots=False) == Matrix([[1, 2, 3]]) a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]) assert a.rref(pivots=False) == Matrix([ [1, 0, -1], [0, 1, 2], [0, 0, 0]]) a = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 1, 2, 3, 1, 2, 3]) b = ReductionsOnlyMatrix(3, 3, [1, 2, 3, 0, 0, 0, 0, 0, 0]) c = ReductionsOnlyMatrix(3, 3, [0, 0, 0, 1, 2, 3, 0, 0, 0]) d = ReductionsOnlyMatrix(3, 3, [0, 0, 0, 0, 0, 0, 1, 2, 3]) assert a.rref(pivots=False) == \ b.rref(pivots=False) == \ c.rref(pivots=False) == \ d.rref(pivots=False) == b e = eye_Reductions(3) z = zeros_Reductions(3) assert e.rref(pivots=False) == e assert z.rref(pivots=False) == z a = ReductionsOnlyMatrix([ [ 0, 0, 1, 2, 2, -5, 3], [-1, 5, 2, 2, 1, -7, 5], [ 0, 0, -2, -3, -3, 8, -5], [-1, 5, 0, -1, -2, 1, 0]]) mat, pivot_offsets = a.rref() assert mat == Matrix([ [1, -5, 0, 0, 1, 1, -1], [0, 0, 1, 0, 0, -1, 1], [0, 0, 0, 1, 1, -2, 1], [0, 0, 0, 0, 0, 0, 0]]) assert pivot_offsets == (0, 2, 3) a = ReductionsOnlyMatrix([[Rational(1, 19), Rational(1, 5), 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [ 12, 13, 14, 15]]) assert a.rref(pivots=False) == Matrix([ [1, 0, 0, Rational(-76, 157)], [0, 1, 0, Rational(-5, 157)], [0, 0, 1, Rational(238, 157)], [0, 0, 0, 0]]) x = Symbol('x') a = ReductionsOnlyMatrix(2, 3, [x, 1, 1, sqrt(x), x, 1]) for i, j in zip(a.rref(pivots=False), [1, 0, sqrt(x)*(-x + 1)/(-x**Rational(5, 2) + x), 0, 1, 1/(sqrt(x) + x + 1)]): assert simplify(i - j).is_zero def test_issue_17827(): C = Matrix([ [3, 4, -1, 1], [9, 12, -3, 3], [0, 2, 1, 3], [2, 3, 0, -2], [0, 3, 3, -5], [8, 15, 0, 6] ]) # Tests for row/col within valid range D = C.elementary_row_op('n<->m', row1=2, row2=5) E = C.elementary_row_op('n->n+km', row1=5, row2=3, k=-4) F = C.elementary_row_op('n->kn', row=5, k=2) assert(D[5, :] == Matrix([[0, 2, 1, 3]])) assert(E[5, :] == Matrix([[0, 3, 0, 14]])) assert(F[5, :] == Matrix([[16, 30, 0, 12]])) # Tests for row/col out of range raises(ValueError, lambda: C.elementary_row_op('n<->m', row1=2, row2=6)) raises(ValueError, lambda: C.elementary_row_op('n->kn', row=7, k=2)) raises(ValueError, lambda: C.elementary_row_op('n->n+km', row1=-1, row2=5, k=2)) def test_rank(): m = Matrix([[1, 2], [x, 1 - 1/x]]) assert m.rank() == 2 n = Matrix(3, 3, range(1, 10)) assert n.rank() == 2 p = zeros(3) assert p.rank() == 0 def test_issue_11434(): ax, ay, bx, by, cx, cy, dx, dy, ex, ey, t0, t1 = \ symbols('a_x a_y b_x b_y c_x c_y d_x d_y e_x e_y t_0 t_1') M = Matrix([[ax, ay, ax*t0, ay*t0, 0], [bx, by, bx*t0, by*t0, 0], [cx, cy, cx*t0, cy*t0, 1], [dx, dy, dx*t0, dy*t0, 1], [ex, ey, 2*ex*t1 - ex*t0, 2*ey*t1 - ey*t0, 0]]) assert M.rank() == 4 def test_rank_regression_from_so(): # see: # https://stackoverflow.com/questions/19072700/why-does-sympy-give-me-the-wrong-answer-when-i-row-reduce-a-symbolic-matrix nu, lamb = symbols('nu, lambda') A = Matrix([[-3*nu, 1, 0, 0], [ 3*nu, -2*nu - 1, 2, 0], [ 0, 2*nu, (-1*nu) - lamb - 2, 3], [ 0, 0, nu + lamb, -3]]) expected_reduced = Matrix([[1, 0, 0, 1/(nu**2*(-lamb - nu))], [0, 1, 0, 3/(nu*(-lamb - nu))], [0, 0, 1, 3/(-lamb - nu)], [0, 0, 0, 0]]) expected_pivots = (0, 1, 2) reduced, pivots = A.rref() assert simplify(expected_reduced - reduced) == zeros(*A.shape) assert pivots == expected_pivots def test_issue_15872(): A = Matrix([[1, 1, 1, 0], [-2, -1, 0, -1], [0, 0, -1, -1], [0, 0, 2, 1]]) B = A - Matrix.eye(4) * I assert B.rank() == 3 assert (B**2).rank() == 2 assert (B**3).rank() == 2 sympy-sympy-1.9/sympy/matrices/tests/test_solvers.py000066400000000000000000000474011412543434000231710ustar00rootroot00000000000000from sympy import ( I, Rational, S, Symbol, simplify, symbols, sympify, expand_mul) from sympy.matrices.matrices import (ShapeError, NonSquareMatrixError) from sympy.matrices import ( ImmutableMatrix, Matrix, eye, ones, ImmutableDenseMatrix, dotprodsimp) from sympy.testing.pytest import raises from sympy.matrices.common import NonInvertibleMatrixError from sympy.solvers.solveset import linsolve from sympy.abc import x, y def test_issue_17247_expression_blowup_29(): M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.gauss_jordan_solve(ones(4, 1)) == (Matrix(S('''[ [ -32549314808672/3306971225785 - 17397006745216*I/3306971225785], [ 67439348256/3306971225785 - 9167503335872*I/3306971225785], [-15091965363354518272/21217636514687010905 + 16890163109293858304*I/21217636514687010905], [ -11328/952745 + 87616*I/952745]]''')), Matrix(0, 1, [])) def test_issue_17247_expression_blowup_30(): M = Matrix(S('''[ [ -3/4, 45/32 - 37*I/16, 0, 0], [-149/64 + 49*I/32, -177/128 - 1369*I/128, 0, -2063/256 + 541*I/128], [ 0, 9/4 + 55*I/16, 2473/256 + 137*I/64, 0], [ 0, 0, 0, -177/128 - 1369*I/128]]''')) with dotprodsimp(True): assert M.cholesky_solve(ones(4, 1)) == Matrix(S('''[ [ -32549314808672/3306971225785 - 17397006745216*I/3306971225785], [ 67439348256/3306971225785 - 9167503335872*I/3306971225785], [-15091965363354518272/21217636514687010905 + 16890163109293858304*I/21217636514687010905], [ -11328/952745 + 87616*I/952745]]''')) # @XFAIL # This calculation hangs with dotprodsimp. # def test_issue_17247_expression_blowup_31(): # M = Matrix([ # [x + 1, 1 - x, 0, 0], # [1 - x, x + 1, 0, x + 1], # [ 0, 1 - x, x + 1, 0], # [ 0, 0, 0, x + 1]]) # with dotprodsimp(True): # assert M.LDLsolve(ones(4, 1)) == Matrix([ # [(x + 1)/(4*x)], # [(x - 1)/(4*x)], # [(x + 1)/(4*x)], # [ 1/(x + 1)]]) def test_issue_17247_expression_blowup_32(): M = Matrix([ [x + 1, 1 - x, 0, 0], [1 - x, x + 1, 0, x + 1], [ 0, 1 - x, x + 1, 0], [ 0, 0, 0, x + 1]]) with dotprodsimp(True): assert M.LUsolve(ones(4, 1)) == Matrix([ [(x + 1)/(4*x)], [(x - 1)/(4*x)], [(x + 1)/(4*x)], [ 1/(x + 1)]]) def test_LUsolve(): A = Matrix([[2, 3, 5], [3, 6, 2], [8, 3, 6]]) x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.LUsolve(b) assert soln == x A = Matrix([[0, -1, 2], [5, 10, 7], [8, 3, 4]]) x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.LUsolve(b) assert soln == x A = Matrix([[2, 1], [1, 0], [1, 0]]) # issue 14548 b = Matrix([3, 1, 1]) assert A.LUsolve(b) == Matrix([1, 1]) b = Matrix([3, 1, 2]) # inconsistent raises(ValueError, lambda: A.LUsolve(b)) A = Matrix([[0, -1, 2], [5, 10, 7], [8, 3, 4], [2, 3, 5], [3, 6, 2], [8, 3, 6]]) x = Matrix([2, 1, -4]) b = A*x soln = A.LUsolve(b) assert soln == x A = Matrix([[0, -1, 2], [5, 10, 7]]) # underdetermined x = Matrix([-1, 2, 0]) b = A*x raises(NotImplementedError, lambda: A.LUsolve(b)) A = Matrix(4, 4, lambda i, j: 1/(i+j+1) if i != 3 else 0) b = Matrix.zeros(4, 1) raises(NonInvertibleMatrixError, lambda: A.LUsolve(b)) def test_QRsolve(): A = Matrix([[2, 3, 5], [3, 6, 2], [8, 3, 6]]) x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.QRsolve(b) assert soln == x x = Matrix([[1, 2], [3, 4], [5, 6]]) b = A*x soln = A.QRsolve(b) assert soln == x A = Matrix([[0, -1, 2], [5, 10, 7], [8, 3, 4]]) x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.QRsolve(b) assert soln == x x = Matrix([[7, 8], [9, 10], [11, 12]]) b = A*x soln = A.QRsolve(b) assert soln == x def test_errors(): raises(ShapeError, lambda: Matrix([1]).LUsolve(Matrix([[1, 2], [3, 4]]))) def test_cholesky_solve(): A = Matrix([[2, 3, 5], [3, 6, 2], [8, 3, 6]]) x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.cholesky_solve(b) assert soln == x A = Matrix([[0, -1, 2], [5, 10, 7], [8, 3, 4]]) x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.cholesky_solve(b) assert soln == x A = Matrix(((1, 5), (5, 1))) x = Matrix((4, -3)) b = A*x soln = A.cholesky_solve(b) assert soln == x A = Matrix(((9, 3*I), (-3*I, 5))) x = Matrix((-2, 1)) b = A*x soln = A.cholesky_solve(b) assert expand_mul(soln) == x A = Matrix(((9*I, 3), (-3 + I, 5))) x = Matrix((2 + 3*I, -1)) b = A*x soln = A.cholesky_solve(b) assert expand_mul(soln) == x a00, a01, a11, b0, b1 = symbols('a00, a01, a11, b0, b1') A = Matrix(((a00, a01), (a01, a11))) b = Matrix((b0, b1)) x = A.cholesky_solve(b) assert simplify(A*x) == b def test_LDLsolve(): A = Matrix([[2, 3, 5], [3, 6, 2], [8, 3, 6]]) x = Matrix(3, 1, [3, 7, 5]) b = A*x soln = A.LDLsolve(b) assert soln == x A = Matrix([[0, -1, 2], [5, 10, 7], [8, 3, 4]]) x = Matrix(3, 1, [-1, 2, 5]) b = A*x soln = A.LDLsolve(b) assert soln == x A = Matrix(((9, 3*I), (-3*I, 5))) x = Matrix((-2, 1)) b = A*x soln = A.LDLsolve(b) assert expand_mul(soln) == x A = Matrix(((9*I, 3), (-3 + I, 5))) x = Matrix((2 + 3*I, -1)) b = A*x soln = A.LDLsolve(b) assert expand_mul(soln) == x A = Matrix(((9, 3), (3, 9))) x = Matrix((1, 1)) b = A * x soln = A.LDLsolve(b) assert expand_mul(soln) == x A = Matrix([[-5, -3, -4], [-3, -7, 7]]) x = Matrix([[8], [7], [-2]]) b = A * x raises(NotImplementedError, lambda: A.LDLsolve(b)) def test_lower_triangular_solve(): raises(NonSquareMatrixError, lambda: Matrix([1, 0]).lower_triangular_solve(Matrix([0, 1]))) raises(ShapeError, lambda: Matrix([[1, 0], [0, 1]]).lower_triangular_solve(Matrix([1]))) raises(ValueError, lambda: Matrix([[2, 1], [1, 2]]).lower_triangular_solve( Matrix([[1, 0], [0, 1]]))) A = Matrix([[1, 0], [0, 1]]) B = Matrix([[x, y], [y, x]]) C = Matrix([[4, 8], [2, 9]]) assert A.lower_triangular_solve(B) == B assert A.lower_triangular_solve(C) == C def test_upper_triangular_solve(): raises(NonSquareMatrixError, lambda: Matrix([1, 0]).upper_triangular_solve(Matrix([0, 1]))) raises(ShapeError, lambda: Matrix([[1, 0], [0, 1]]).upper_triangular_solve(Matrix([1]))) raises(TypeError, lambda: Matrix([[2, 1], [1, 2]]).upper_triangular_solve( Matrix([[1, 0], [0, 1]]))) A = Matrix([[1, 0], [0, 1]]) B = Matrix([[x, y], [y, x]]) C = Matrix([[2, 4], [3, 8]]) assert A.upper_triangular_solve(B) == B assert A.upper_triangular_solve(C) == C def test_diagonal_solve(): raises(TypeError, lambda: Matrix([1, 1]).diagonal_solve(Matrix([1]))) A = Matrix([[1, 0], [0, 1]])*2 B = Matrix([[x, y], [y, x]]) assert A.diagonal_solve(B) == B/2 A = Matrix([[1, 0], [1, 2]]) raises(TypeError, lambda: A.diagonal_solve(B)) def test_pinv_solve(): # Fully determined system (unique result, identical to other solvers). A = Matrix([[1, 5], [7, 9]]) B = Matrix([12, 13]) assert A.pinv_solve(B) == A.cholesky_solve(B) assert A.pinv_solve(B) == A.LDLsolve(B) assert A.pinv_solve(B) == Matrix([sympify('-43/26'), sympify('71/26')]) assert A * A.pinv() * B == B # Fully determined, with two-dimensional B matrix. B = Matrix([[12, 13, 14], [15, 16, 17]]) assert A.pinv_solve(B) == A.cholesky_solve(B) assert A.pinv_solve(B) == A.LDLsolve(B) assert A.pinv_solve(B) == Matrix([[-33, -37, -41], [69, 75, 81]]) / 26 assert A * A.pinv() * B == B # Underdetermined system (infinite results). A = Matrix([[1, 0, 1], [0, 1, 1]]) B = Matrix([5, 7]) solution = A.pinv_solve(B) w = {} for s in solution.atoms(Symbol): # Extract dummy symbols used in the solution. w[s.name] = s assert solution == Matrix([[w['w0_0']/3 + w['w1_0']/3 - w['w2_0']/3 + 1], [w['w0_0']/3 + w['w1_0']/3 - w['w2_0']/3 + 3], [-w['w0_0']/3 - w['w1_0']/3 + w['w2_0']/3 + 4]]) assert A * A.pinv() * B == B # Overdetermined system (least squares results). A = Matrix([[1, 0], [0, 0], [0, 1]]) B = Matrix([3, 2, 1]) assert A.pinv_solve(B) == Matrix([3, 1]) # Proof the solution is not exact. assert A * A.pinv() * B != B def test_pinv_rank_deficient(): # Test the four properties of the pseudoinverse for various matrices. As = [Matrix([[1, 1, 1], [2, 2, 2]]), Matrix([[1, 0], [0, 0]]), Matrix([[1, 2], [2, 4], [3, 6]])] for A in As: A_pinv = A.pinv(method="RD") AAp = A * A_pinv ApA = A_pinv * A assert simplify(AAp * A) == A assert simplify(ApA * A_pinv) == A_pinv assert AAp.H == AAp assert ApA.H == ApA for A in As: A_pinv = A.pinv(method="ED") AAp = A * A_pinv ApA = A_pinv * A assert simplify(AAp * A) == A assert simplify(ApA * A_pinv) == A_pinv assert AAp.H == AAp assert ApA.H == ApA # Test solving with rank-deficient matrices. A = Matrix([[1, 0], [0, 0]]) # Exact, non-unique solution. B = Matrix([3, 0]) solution = A.pinv_solve(B) w1 = solution.atoms(Symbol).pop() assert w1.name == 'w1_0' assert solution == Matrix([3, w1]) assert A * A.pinv() * B == B # Least squares, non-unique solution. B = Matrix([3, 1]) solution = A.pinv_solve(B) w1 = solution.atoms(Symbol).pop() assert w1.name == 'w1_0' assert solution == Matrix([3, w1]) assert A * A.pinv() * B != B def test_gauss_jordan_solve(): # Square, full rank, unique solution A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) b = Matrix([3, 6, 9]) sol, params = A.gauss_jordan_solve(b) assert sol == Matrix([[-1], [2], [0]]) assert params == Matrix(0, 1, []) # Square, full rank, unique solution, B has more columns than rows A = eye(3) B = Matrix([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) sol, params = A.gauss_jordan_solve(B) assert sol == B assert params == Matrix(0, 4, []) # Square, reduced rank, parametrized solution A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) b = Matrix([3, 6, 9]) sol, params, freevar = A.gauss_jordan_solve(b, freevar=True) w = {} for s in sol.atoms(Symbol): # Extract dummy symbols used in the solution. w[s.name] = s assert sol == Matrix([[w['tau0'] - 1], [-2*w['tau0'] + 2], [w['tau0']]]) assert params == Matrix([[w['tau0']]]) assert freevar == [2] # Square, reduced rank, parametrized solution, B has two columns A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) B = Matrix([[3, 4], [6, 8], [9, 12]]) sol, params, freevar = A.gauss_jordan_solve(B, freevar=True) w = {} for s in sol.atoms(Symbol): # Extract dummy symbols used in the solution. w[s.name] = s assert sol == Matrix([[w['tau0'] - 1, w['tau1'] - Rational(4, 3)], [-2*w['tau0'] + 2, -2*w['tau1'] + Rational(8, 3)], [w['tau0'], w['tau1']],]) assert params == Matrix([[w['tau0'], w['tau1']]]) assert freevar == [2] # Square, reduced rank, parametrized solution A = Matrix([[1, 2, 3], [2, 4, 6], [3, 6, 9]]) b = Matrix([0, 0, 0]) sol, params = A.gauss_jordan_solve(b) w = {} for s in sol.atoms(Symbol): w[s.name] = s assert sol == Matrix([[-2*w['tau0'] - 3*w['tau1']], [w['tau0']], [w['tau1']]]) assert params == Matrix([[w['tau0']], [w['tau1']]]) # Square, reduced rank, parametrized solution A = Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) b = Matrix([0, 0, 0]) sol, params = A.gauss_jordan_solve(b) w = {} for s in sol.atoms(Symbol): w[s.name] = s assert sol == Matrix([[w['tau0']], [w['tau1']], [w['tau2']]]) assert params == Matrix([[w['tau0']], [w['tau1']], [w['tau2']]]) # Square, reduced rank, no solution A = Matrix([[1, 2, 3], [2, 4, 6], [3, 6, 9]]) b = Matrix([0, 0, 1]) raises(ValueError, lambda: A.gauss_jordan_solve(b)) # Rectangular, tall, full rank, unique solution A = Matrix([[1, 5, 3], [2, 1, 6], [1, 7, 9], [1, 4, 3]]) b = Matrix([0, 0, 1, 0]) sol, params = A.gauss_jordan_solve(b) assert sol == Matrix([[Rational(-1, 2)], [0], [Rational(1, 6)]]) assert params == Matrix(0, 1, []) # Rectangular, tall, full rank, unique solution, B has less columns than rows A = Matrix([[1, 5, 3], [2, 1, 6], [1, 7, 9], [1, 4, 3]]) B = Matrix([[0,0], [0, 0], [1, 2], [0, 0]]) sol, params = A.gauss_jordan_solve(B) assert sol == Matrix([[Rational(-1, 2), Rational(-2, 2)], [0, 0], [Rational(1, 6), Rational(2, 6)]]) assert params == Matrix(0, 2, []) # Rectangular, tall, full rank, no solution A = Matrix([[1, 5, 3], [2, 1, 6], [1, 7, 9], [1, 4, 3]]) b = Matrix([0, 0, 0, 1]) raises(ValueError, lambda: A.gauss_jordan_solve(b)) # Rectangular, tall, full rank, no solution, B has two columns (2nd has no solution) A = Matrix([[1, 5, 3], [2, 1, 6], [1, 7, 9], [1, 4, 3]]) B = Matrix([[0,0], [0, 0], [1, 0], [0, 1]]) raises(ValueError, lambda: A.gauss_jordan_solve(B)) # Rectangular, tall, full rank, no solution, B has two columns (1st has no solution) A = Matrix([[1, 5, 3], [2, 1, 6], [1, 7, 9], [1, 4, 3]]) B = Matrix([[0,0], [0, 0], [0, 1], [1, 0]]) raises(ValueError, lambda: A.gauss_jordan_solve(B)) # Rectangular, tall, reduced rank, parametrized solution A = Matrix([[1, 5, 3], [2, 10, 6], [3, 15, 9], [1, 4, 3]]) b = Matrix([0, 0, 0, 1]) sol, params = A.gauss_jordan_solve(b) w = {} for s in sol.atoms(Symbol): w[s.name] = s assert sol == Matrix([[-3*w['tau0'] + 5], [-1], [w['tau0']]]) assert params == Matrix([[w['tau0']]]) # Rectangular, tall, reduced rank, no solution A = Matrix([[1, 5, 3], [2, 10, 6], [3, 15, 9], [1, 4, 3]]) b = Matrix([0, 0, 1, 1]) raises(ValueError, lambda: A.gauss_jordan_solve(b)) # Rectangular, wide, full rank, parametrized solution A = Matrix([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 1, 12]]) b = Matrix([1, 1, 1]) sol, params = A.gauss_jordan_solve(b) w = {} for s in sol.atoms(Symbol): w[s.name] = s assert sol == Matrix([[2*w['tau0'] - 1], [-3*w['tau0'] + 1], [0], [w['tau0']]]) assert params == Matrix([[w['tau0']]]) # Rectangular, wide, reduced rank, parametrized solution A = Matrix([[1, 2, 3, 4], [5, 6, 7, 8], [2, 4, 6, 8]]) b = Matrix([0, 1, 0]) sol, params = A.gauss_jordan_solve(b) w = {} for s in sol.atoms(Symbol): w[s.name] = s assert sol == Matrix([[w['tau0'] + 2*w['tau1'] + S.Half], [-2*w['tau0'] - 3*w['tau1'] - Rational(1, 4)], [w['tau0']], [w['tau1']]]) assert params == Matrix([[w['tau0']], [w['tau1']]]) # watch out for clashing symbols x0, x1, x2, _x0 = symbols('_tau0 _tau1 _tau2 tau1') M = Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, _x0]]) A = M[:, :-1] b = M[:, -1:] sol, params = A.gauss_jordan_solve(b) assert params == Matrix(3, 1, [x0, x1, x2]) assert sol == Matrix(5, 1, [x0, 0, x1, _x0, x2]) # Rectangular, wide, reduced rank, no solution A = Matrix([[1, 2, 3, 4], [5, 6, 7, 8], [2, 4, 6, 8]]) b = Matrix([1, 1, 1]) raises(ValueError, lambda: A.gauss_jordan_solve(b)) # Test for immutable matrix A = ImmutableMatrix([[1, 0], [0, 1]]) B = ImmutableMatrix([1, 2]) sol, params = A.gauss_jordan_solve(B) assert sol == ImmutableMatrix([1, 2]) assert params == ImmutableMatrix(0, 1, []) assert sol.__class__ == ImmutableDenseMatrix assert params.__class__ == ImmutableDenseMatrix # Test placement of free variables A = Matrix([[1, 0, 0, 0], [0, 0, 0, 1]]) b = Matrix([1, 1]) sol, params = A.gauss_jordan_solve(b) w = {} for s in sol.atoms(Symbol): w[s.name] = s assert sol == Matrix([[1], [w['tau0']], [w['tau1']], [1]]) assert params == Matrix([[w['tau0']], [w['tau1']]]) def test_linsolve_underdetermined_AND_gauss_jordan_solve(): #Test placement of free variables as per issue 19815 A = Matrix([[1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 1, 0, 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, 0, 1, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0], [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1]]) B = Matrix([1, 2, 1, 1, 1, 1, 1, 2]) sol, params = A.gauss_jordan_solve(B) w = {} for s in sol.atoms(Symbol): w[s.name] = s assert params == Matrix([[w['tau0']], [w['tau1']], [w['tau2']], [w['tau3']], [w['tau4']], [w['tau5']]]) assert sol == Matrix([[1 - 1*w['tau2']], [w['tau2']], [1 - 1*w['tau0'] + w['tau1']], [w['tau0']], [w['tau3'] + w['tau4']], [-1*w['tau3'] - 1*w['tau4'] - 1*w['tau1']], [1 - 1*w['tau2']], [w['tau1']], [w['tau2']], [w['tau3']], [w['tau4']], [1 - 1*w['tau5']], [w['tau5']], [1]]) from sympy.abc import j,f # https://github.com/sympy/sympy/issues/20046 A = Matrix([ [1, 1, 1, 1, 1, 1, 1, 1, 1], [0, -1, 0, -1, 0, -1, 0, -1, -j], [0, 0, 0, 0, 1, 1, 1, 1, f] ]) sol_1=Matrix(list(linsolve(A))[0]) tau0, tau1, tau2, tau3, tau4 = symbols('tau:5') assert sol_1 == Matrix([[-f - j - tau0 + tau2 + tau4 + 1], [j - tau1 - tau2 - tau4], [tau0], [tau1], [f - tau2 - tau3 - tau4], [tau2], [tau3], [tau4]]) # https://github.com/sympy/sympy/issues/19815 sol_2 = A[ : , : -1 ] * sol_1 - A[ : , -1 ] assert sol_2 == Matrix([[0] , [0] , [0]]) def test_solve(): A = Matrix([[1,2], [2,4]]) b = Matrix([[3], [4]]) raises(ValueError, lambda: A.solve(b)) #no solution b = Matrix([[ 4], [8]]) raises(ValueError, lambda: A.solve(b)) #infinite solution sympy-sympy-1.9/sympy/matrices/tests/test_sparse.py000066400000000000000000000537221412543434000227740ustar00rootroot00000000000000from sympy import Abs, S, Symbol, symbols, I, Rational, PurePoly, Float from sympy.matrices import \ Matrix, MutableSparseMatrix, ImmutableSparseMatrix, SparseMatrix, eye, \ ones, zeros, ShapeError from sympy.testing.pytest import raises def test_sparse_creation(): a = SparseMatrix(2, 2, {(0, 0): [[1, 2], [3, 4]]}) assert a == SparseMatrix([[1, 2], [3, 4]]) a = SparseMatrix(2, 2, {(0, 0): [[1, 2]]}) assert a == SparseMatrix([[1, 2], [0, 0]]) a = SparseMatrix(2, 2, {(0, 0): [1, 2]}) assert a == SparseMatrix([[1, 0], [2, 0]]) def test_sparse_matrix(): def sparse_eye(n): return SparseMatrix.eye(n) def sparse_zeros(n): return SparseMatrix.zeros(n) # creation args raises(TypeError, lambda: SparseMatrix(1, 2)) a = SparseMatrix(( (1, 0), (0, 1) )) assert SparseMatrix(a) == a from sympy.matrices import MutableSparseMatrix, MutableDenseMatrix a = MutableSparseMatrix([]) b = MutableDenseMatrix([1, 2]) assert a.row_join(b) == b assert a.col_join(b) == b assert type(a.row_join(b)) == type(a) assert type(a.col_join(b)) == type(a) # make sure 0 x n matrices get stacked correctly sparse_matrices = [SparseMatrix.zeros(0, n) for n in range(4)] assert SparseMatrix.hstack(*sparse_matrices) == Matrix(0, 6, []) sparse_matrices = [SparseMatrix.zeros(n, 0) for n in range(4)] assert SparseMatrix.vstack(*sparse_matrices) == Matrix(6, 0, []) # test element assignment a = SparseMatrix(( (1, 0), (0, 1) )) a[3] = 4 assert a[1, 1] == 4 a[3] = 1 a[0, 0] = 2 assert a == SparseMatrix(( (2, 0), (0, 1) )) a[1, 0] = 5 assert a == SparseMatrix(( (2, 0), (5, 1) )) a[1, 1] = 0 assert a == SparseMatrix(( (2, 0), (5, 0) )) assert a.todok() == {(0, 0): 2, (1, 0): 5} # test_multiplication a = SparseMatrix(( (1, 2), (3, 1), (0, 6), )) b = SparseMatrix(( (1, 2), (3, 0), )) c = a*b assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 try: eval('c = a @ b') except SyntaxError: pass else: assert c[0, 0] == 7 assert c[0, 1] == 2 assert c[1, 0] == 6 assert c[1, 1] == 6 assert c[2, 0] == 18 assert c[2, 1] == 0 x = Symbol("x") c = b * Symbol("x") assert isinstance(c, SparseMatrix) assert c[0, 0] == x assert c[0, 1] == 2*x assert c[1, 0] == 3*x assert c[1, 1] == 0 c = 5 * b assert isinstance(c, SparseMatrix) assert c[0, 0] == 5 assert c[0, 1] == 2*5 assert c[1, 0] == 3*5 assert c[1, 1] == 0 #test_power A = SparseMatrix([[2, 3], [4, 5]]) assert (A**5)[:] == [6140, 8097, 10796, 14237] A = SparseMatrix([[2, 1, 3], [4, 2, 4], [6, 12, 1]]) assert (A**3)[:] == [290, 262, 251, 448, 440, 368, 702, 954, 433] # test_creation x = Symbol("x") a = SparseMatrix([[x, 0], [0, 0]]) m = a assert m.cols == m.rows assert m.cols == 2 assert m[:] == [x, 0, 0, 0] b = SparseMatrix(2, 2, [x, 0, 0, 0]) m = b assert m.cols == m.rows assert m.cols == 2 assert m[:] == [x, 0, 0, 0] assert a == b S = sparse_eye(3) S.row_del(1) assert S == SparseMatrix([ [1, 0, 0], [0, 0, 1]]) S = sparse_eye(3) S.col_del(1) assert S == SparseMatrix([ [1, 0], [0, 0], [0, 1]]) S = SparseMatrix.eye(3) S[2, 1] = 2 S.col_swap(1, 0) assert S == SparseMatrix([ [0, 1, 0], [1, 0, 0], [2, 0, 1]]) S.row_swap(0, 1) assert S == SparseMatrix([ [1, 0, 0], [0, 1, 0], [2, 0, 1]]) a = SparseMatrix(1, 2, [1, 2]) b = a.copy() c = a.copy() assert a[0] == 1 a.row_del(0) assert a == SparseMatrix(0, 2, []) b.col_del(1) assert b == SparseMatrix(1, 1, [1]) assert SparseMatrix([[1, 2, 3], [1, 2], [1]]) == Matrix([ [1, 2, 3], [1, 2, 0], [1, 0, 0]]) assert SparseMatrix(4, 4, {(1, 1): sparse_eye(2)}) == Matrix([ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]]) raises(ValueError, lambda: SparseMatrix(1, 1, {(1, 1): 1})) assert SparseMatrix(1, 2, [1, 2]).tolist() == [[1, 2]] assert SparseMatrix(2, 2, [1, [2, 3]]).tolist() == [[1, 0], [2, 3]] raises(ValueError, lambda: SparseMatrix(2, 2, [1])) raises(ValueError, lambda: SparseMatrix(1, 1, [[1, 2]])) assert SparseMatrix([.1]).has(Float) # autosizing assert SparseMatrix(None, {(0, 1): 0}).shape == (0, 0) assert SparseMatrix(None, {(0, 1): 1}).shape == (1, 2) assert SparseMatrix(None, None, {(0, 1): 1}).shape == (1, 2) raises(ValueError, lambda: SparseMatrix(None, 1, [[1, 2]])) raises(ValueError, lambda: SparseMatrix(1, None, [[1, 2]])) raises(ValueError, lambda: SparseMatrix(3, 3, {(0, 0): ones(2), (1, 1): 2})) # test_determinant x, y = Symbol('x'), Symbol('y') assert SparseMatrix(1, 1, [0]).det() == 0 assert SparseMatrix([[1]]).det() == 1 assert SparseMatrix(((-3, 2), (8, -5))).det() == -1 assert SparseMatrix(((x, 1), (y, 2*y))).det() == 2*x*y - y assert SparseMatrix(( (1, 1, 1), (1, 2, 3), (1, 3, 6) )).det() == 1 assert SparseMatrix(( ( 3, -2, 0, 5), (-2, 1, -2, 2), ( 0, -2, 5, 0), ( 5, 0, 3, 4) )).det() == -289 assert SparseMatrix(( ( 1, 2, 3, 4), ( 5, 6, 7, 8), ( 9, 10, 11, 12), (13, 14, 15, 16) )).det() == 0 assert SparseMatrix(( (3, 2, 0, 0, 0), (0, 3, 2, 0, 0), (0, 0, 3, 2, 0), (0, 0, 0, 3, 2), (2, 0, 0, 0, 3) )).det() == 275 assert SparseMatrix(( (1, 0, 1, 2, 12), (2, 0, 1, 1, 4), (2, 1, 1, -1, 3), (3, 2, -1, 1, 8), (1, 1, 1, 0, 6) )).det() == -55 assert SparseMatrix(( (-5, 2, 3, 4, 5), ( 1, -4, 3, 4, 5), ( 1, 2, -3, 4, 5), ( 1, 2, 3, -2, 5), ( 1, 2, 3, 4, -1) )).det() == 11664 assert SparseMatrix(( ( 3, 0, 0, 0), (-2, 1, 0, 0), ( 0, -2, 5, 0), ( 5, 0, 3, 4) )).det() == 60 assert SparseMatrix(( ( 1, 0, 0, 0), ( 5, 0, 0, 0), ( 9, 10, 11, 0), (13, 14, 15, 16) )).det() == 0 assert SparseMatrix(( (3, 2, 0, 0, 0), (0, 3, 2, 0, 0), (0, 0, 3, 2, 0), (0, 0, 0, 3, 2), (0, 0, 0, 0, 3) )).det() == 243 assert SparseMatrix(( ( 2, 7, -1, 3, 2), ( 0, 0, 1, 0, 1), (-2, 0, 7, 0, 2), (-3, -2, 4, 5, 3), ( 1, 0, 0, 0, 1) )).det() == 123 # test_slicing m0 = sparse_eye(4) assert m0[:3, :3] == sparse_eye(3) assert m0[2:4, 0:2] == sparse_zeros(2) m1 = SparseMatrix(3, 3, lambda i, j: i + j) assert m1[0, :] == SparseMatrix(1, 3, (0, 1, 2)) assert m1[1:3, 1] == SparseMatrix(2, 1, (2, 3)) m2 = SparseMatrix( [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11], [12, 13, 14, 15]]) assert m2[:, -1] == SparseMatrix(4, 1, [3, 7, 11, 15]) assert m2[-2:, :] == SparseMatrix([[8, 9, 10, 11], [12, 13, 14, 15]]) assert SparseMatrix([[1, 2], [3, 4]])[[1], [1]] == Matrix([[4]]) # test_submatrix_assignment m = sparse_zeros(4) m[2:4, 2:4] = sparse_eye(2) assert m == SparseMatrix([(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1)]) assert len(m.todok()) == 2 m[:2, :2] = sparse_eye(2) assert m == sparse_eye(4) m[:, 0] = SparseMatrix(4, 1, (1, 2, 3, 4)) assert m == SparseMatrix([(1, 0, 0, 0), (2, 1, 0, 0), (3, 0, 1, 0), (4, 0, 0, 1)]) m[:, :] = sparse_zeros(4) assert m == sparse_zeros(4) m[:, :] = ((1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12), (13, 14, 15, 16)) assert m == SparseMatrix((( 1, 2, 3, 4), ( 5, 6, 7, 8), ( 9, 10, 11, 12), (13, 14, 15, 16))) m[:2, 0] = [0, 0] assert m == SparseMatrix((( 0, 2, 3, 4), ( 0, 6, 7, 8), ( 9, 10, 11, 12), (13, 14, 15, 16))) # test_reshape m0 = sparse_eye(3) assert m0.reshape(1, 9) == SparseMatrix(1, 9, (1, 0, 0, 0, 1, 0, 0, 0, 1)) m1 = SparseMatrix(3, 4, lambda i, j: i + j) assert m1.reshape(4, 3) == \ SparseMatrix([(0, 1, 2), (3, 1, 2), (3, 4, 2), (3, 4, 5)]) assert m1.reshape(2, 6) == \ SparseMatrix([(0, 1, 2, 3, 1, 2), (3, 4, 2, 3, 4, 5)]) # test_applyfunc m0 = sparse_eye(3) assert m0.applyfunc(lambda x: 2*x) == sparse_eye(3)*2 assert m0.applyfunc(lambda x: 0 ) == sparse_zeros(3) # test__eval_Abs assert abs(SparseMatrix(((x, 1), (y, 2*y)))) == SparseMatrix(((Abs(x), 1), (Abs(y), 2*Abs(y)))) # test_LUdecomp testmat = SparseMatrix([[ 0, 2, 5, 3], [ 3, 3, 7, 4], [ 8, 4, 0, 2], [-2, 6, 3, 4]]) L, U, p = testmat.LUdecomposition() assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - testmat == sparse_zeros(4) testmat = SparseMatrix([[ 6, -2, 7, 4], [ 0, 3, 6, 7], [ 1, -2, 7, 4], [-9, 2, 6, 3]]) L, U, p = testmat.LUdecomposition() assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - testmat == sparse_zeros(4) x, y, z = Symbol('x'), Symbol('y'), Symbol('z') M = Matrix(((1, x, 1), (2, y, 0), (y, 0, z))) L, U, p = M.LUdecomposition() assert L.is_lower assert U.is_upper assert (L*U).permute_rows(p, 'backward') - M == sparse_zeros(3) # test_LUsolve A = SparseMatrix([[2, 3, 5], [3, 6, 2], [8, 3, 6]]) x = SparseMatrix(3, 1, [3, 7, 5]) b = A*x soln = A.LUsolve(b) assert soln == x A = SparseMatrix([[0, -1, 2], [5, 10, 7], [8, 3, 4]]) x = SparseMatrix(3, 1, [-1, 2, 5]) b = A*x soln = A.LUsolve(b) assert soln == x # test_inverse A = sparse_eye(4) assert A.inv() == sparse_eye(4) assert A.inv(method="CH") == sparse_eye(4) assert A.inv(method="LDL") == sparse_eye(4) A = SparseMatrix([[2, 3, 5], [3, 6, 2], [7, 2, 6]]) Ainv = SparseMatrix(Matrix(A).inv()) assert A*Ainv == sparse_eye(3) assert A.inv(method="CH") == Ainv assert A.inv(method="LDL") == Ainv A = SparseMatrix([[2, 3, 5], [3, 6, 2], [5, 2, 6]]) Ainv = SparseMatrix(Matrix(A).inv()) assert A*Ainv == sparse_eye(3) assert A.inv(method="CH") == Ainv assert A.inv(method="LDL") == Ainv # test_cross v1 = Matrix(1, 3, [1, 2, 3]) v2 = Matrix(1, 3, [3, 4, 5]) assert v1.cross(v2) == Matrix(1, 3, [-2, 4, -2]) assert v1.norm(2)**2 == 14 # conjugate a = SparseMatrix(((1, 2 + I), (3, 4))) assert a.C == SparseMatrix([ [1, 2 - I], [3, 4] ]) # mul assert a*Matrix(2, 2, [1, 0, 0, 1]) == a assert a + Matrix(2, 2, [1, 1, 1, 1]) == SparseMatrix([ [2, 3 + I], [4, 5] ]) # col join assert a.col_join(sparse_eye(2)) == SparseMatrix([ [1, 2 + I], [3, 4], [1, 0], [0, 1] ]) # row insert assert a.row_insert(2, sparse_eye(2)) == SparseMatrix([ [1, 2 + I], [3, 4], [1, 0], [0, 1] ]) # col insert assert a.col_insert(2, SparseMatrix.zeros(2, 1)) == SparseMatrix([ [1, 2 + I, 0], [3, 4, 0], ]) # symmetric assert not a.is_symmetric(simplify=False) # col op M = SparseMatrix.eye(3)*2 M[1, 0] = -1 M.col_op(1, lambda v, i: v + 2*M[i, 0]) assert M == SparseMatrix([ [ 2, 4, 0], [-1, 0, 0], [ 0, 0, 2] ]) # fill M = SparseMatrix.eye(3) M.fill(2) assert M == SparseMatrix([ [2, 2, 2], [2, 2, 2], [2, 2, 2], ]) # test_cofactor assert sparse_eye(3) == sparse_eye(3).cofactor_matrix() test = SparseMatrix([[1, 3, 2], [2, 6, 3], [2, 3, 6]]) assert test.cofactor_matrix() == \ SparseMatrix([[27, -6, -6], [-12, 2, 3], [-3, 1, 0]]) test = SparseMatrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) assert test.cofactor_matrix() == \ SparseMatrix([[-3, 6, -3], [6, -12, 6], [-3, 6, -3]]) # test_jacobian x = Symbol('x') y = Symbol('y') L = SparseMatrix(1, 2, [x**2*y, 2*y**2 + x*y]) syms = [x, y] assert L.jacobian(syms) == Matrix([[2*x*y, x**2], [y, 4*y + x]]) L = SparseMatrix(1, 2, [x, x**2*y**3]) assert L.jacobian(syms) == SparseMatrix([[1, 0], [2*x*y**3, x**2*3*y**2]]) # test_QR A = Matrix([[1, 2], [2, 3]]) Q, S = A.QRdecomposition() R = Rational assert Q == Matrix([ [ 5**R(-1, 2), (R(2)/5)*(R(1)/5)**R(-1, 2)], [2*5**R(-1, 2), (-R(1)/5)*(R(1)/5)**R(-1, 2)]]) assert S == Matrix([ [5**R(1, 2), 8*5**R(-1, 2)], [ 0, (R(1)/5)**R(1, 2)]]) assert Q*S == A assert Q.T * Q == sparse_eye(2) R = Rational # test nullspace # first test reduced row-ech form M = SparseMatrix([[5, 7, 2, 1], [1, 6, 2, -1]]) out, tmp = M.rref() assert out == Matrix([[1, 0, -R(2)/23, R(13)/23], [0, 1, R(8)/23, R(-6)/23]]) M = SparseMatrix([[ 1, 3, 0, 2, 6, 3, 1], [-2, -6, 0, -2, -8, 3, 1], [ 3, 9, 0, 0, 6, 6, 2], [-1, -3, 0, 1, 0, 9, 3]]) out, tmp = M.rref() assert out == Matrix([[1, 3, 0, 0, 2, 0, 0], [0, 0, 0, 1, 2, 0, 0], [0, 0, 0, 0, 0, 1, R(1)/3], [0, 0, 0, 0, 0, 0, 0]]) # now check the vectors basis = M.nullspace() assert basis[0] == Matrix([-3, 1, 0, 0, 0, 0, 0]) assert basis[1] == Matrix([0, 0, 1, 0, 0, 0, 0]) assert basis[2] == Matrix([-2, 0, 0, -2, 1, 0, 0]) assert basis[3] == Matrix([0, 0, 0, 0, 0, R(-1)/3, 1]) # test eigen x = Symbol('x') y = Symbol('y') sparse_eye3 = sparse_eye(3) assert sparse_eye3.charpoly(x) == PurePoly((x - 1)**3) assert sparse_eye3.charpoly(y) == PurePoly((y - 1)**3) # test values M = Matrix([( 0, 1, -1), ( 1, 1, 0), (-1, 0, 1)]) vals = M.eigenvals() assert sorted(vals.keys()) == [-1, 1, 2] R = Rational M = Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) assert M.eigenvects() == [(1, 3, [ Matrix([1, 0, 0]), Matrix([0, 1, 0]), Matrix([0, 0, 1])])] M = Matrix([[5, 0, 2], [3, 2, 0], [0, 0, 1]]) assert M.eigenvects() == [(1, 1, [Matrix([R(-1)/2, R(3)/2, 1])]), (2, 1, [Matrix([0, 1, 0])]), (5, 1, [Matrix([1, 1, 0])])] assert M.zeros(3, 5) == SparseMatrix(3, 5, {}) A = SparseMatrix(10, 10, {(0, 0): 18, (0, 9): 12, (1, 4): 18, (2, 7): 16, (3, 9): 12, (4, 2): 19, (5, 7): 16, (6, 2): 12, (9, 7): 18}) assert A.row_list() == [(0, 0, 18), (0, 9, 12), (1, 4, 18), (2, 7, 16), (3, 9, 12), (4, 2, 19), (5, 7, 16), (6, 2, 12), (9, 7, 18)] assert A.col_list() == [(0, 0, 18), (4, 2, 19), (6, 2, 12), (1, 4, 18), (2, 7, 16), (5, 7, 16), (9, 7, 18), (0, 9, 12), (3, 9, 12)] assert SparseMatrix.eye(2).nnz() == 2 def test_scalar_multiply(): assert SparseMatrix([[1, 2]]).scalar_multiply(3) == SparseMatrix([[3, 6]]) def test_transpose(): assert SparseMatrix(((1, 2), (3, 4))).transpose() == \ SparseMatrix(((1, 3), (2, 4))) def test_trace(): assert SparseMatrix(((1, 2), (3, 4))).trace() == 5 assert SparseMatrix(((0, 0), (0, 4))).trace() == 4 def test_CL_RL(): assert SparseMatrix(((1, 2), (3, 4))).row_list() == \ [(0, 0, 1), (0, 1, 2), (1, 0, 3), (1, 1, 4)] assert SparseMatrix(((1, 2), (3, 4))).col_list() == \ [(0, 0, 1), (1, 0, 3), (0, 1, 2), (1, 1, 4)] def test_add(): assert SparseMatrix(((1, 0), (0, 1))) + SparseMatrix(((0, 1), (1, 0))) == \ SparseMatrix(((1, 1), (1, 1))) a = SparseMatrix(100, 100, lambda i, j: int(j != 0 and i % j == 0)) b = SparseMatrix(100, 100, lambda i, j: int(i != 0 and j % i == 0)) assert (len(a.todok()) + len(b.todok()) - len((a + b).todok()) > 0) def test_errors(): raises(ValueError, lambda: SparseMatrix(1.4, 2, lambda i, j: 0)) raises(TypeError, lambda: SparseMatrix([1, 2, 3], [1, 2])) raises(ValueError, lambda: SparseMatrix([[1, 2], [3, 4]])[(1, 2, 3)]) raises(IndexError, lambda: SparseMatrix([[1, 2], [3, 4]])[5]) raises(ValueError, lambda: SparseMatrix([[1, 2], [3, 4]])[1, 2, 3]) raises(TypeError, lambda: SparseMatrix([[1, 2], [3, 4]]).copyin_list([0, 1], set())) raises( IndexError, lambda: SparseMatrix([[1, 2], [3, 4]])[1, 2]) raises(TypeError, lambda: SparseMatrix([1, 2, 3]).cross(1)) raises(IndexError, lambda: SparseMatrix(1, 2, [1, 2])[3]) raises(ShapeError, lambda: SparseMatrix(1, 2, [1, 2]) + SparseMatrix(2, 1, [2, 1])) def test_len(): assert not SparseMatrix() assert SparseMatrix() == SparseMatrix([]) assert SparseMatrix() == SparseMatrix([[]]) def test_sparse_zeros_sparse_eye(): assert SparseMatrix.eye(3) == eye(3, cls=SparseMatrix) assert len(SparseMatrix.eye(3).todok()) == 3 assert SparseMatrix.zeros(3) == zeros(3, cls=SparseMatrix) assert len(SparseMatrix.zeros(3).todok()) == 0 def test_copyin(): s = SparseMatrix(3, 3, {}) s[1, 0] = 1 assert s[:, 0] == SparseMatrix(Matrix([0, 1, 0])) assert s[3] == 1 assert s[3: 4] == [1] s[1, 1] = 42 assert s[1, 1] == 42 assert s[1, 1:] == SparseMatrix([[42, 0]]) s[1, 1:] = Matrix([[5, 6]]) assert s[1, :] == SparseMatrix([[1, 5, 6]]) s[1, 1:] = [[42, 43]] assert s[1, :] == SparseMatrix([[1, 42, 43]]) s[0, 0] = 17 assert s[:, :1] == SparseMatrix([17, 1, 0]) s[0, 0] = [1, 1, 1] assert s[:, 0] == SparseMatrix([1, 1, 1]) s[0, 0] = Matrix([1, 1, 1]) assert s[:, 0] == SparseMatrix([1, 1, 1]) s[0, 0] = SparseMatrix([1, 1, 1]) assert s[:, 0] == SparseMatrix([1, 1, 1]) def test_sparse_solve(): from sympy.matrices import SparseMatrix A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) assert A.cholesky() == Matrix([ [ 5, 0, 0], [ 3, 3, 0], [-1, 1, 3]]) assert A.cholesky() * A.cholesky().T == Matrix([ [25, 15, -5], [15, 18, 0], [-5, 0, 11]]) A = SparseMatrix(((25, 15, -5), (15, 18, 0), (-5, 0, 11))) L, D = A.LDLdecomposition() assert 15*L == Matrix([ [15, 0, 0], [ 9, 15, 0], [-3, 5, 15]]) assert D == Matrix([ [25, 0, 0], [ 0, 9, 0], [ 0, 0, 9]]) assert L * D * L.T == A A = SparseMatrix(((3, 0, 2), (0, 0, 1), (1, 2, 0))) assert A.inv() * A == SparseMatrix(eye(3)) A = SparseMatrix([ [ 2, -1, 0], [-1, 2, -1], [ 0, 0, 2]]) ans = SparseMatrix([ [Rational(2, 3), Rational(1, 3), Rational(1, 6)], [Rational(1, 3), Rational(2, 3), Rational(1, 3)], [ 0, 0, S.Half]]) assert A.inv(method='CH') == ans assert A.inv(method='LDL') == ans assert A * ans == SparseMatrix(eye(3)) s = A.solve(A[:, 0], 'LDL') assert A*s == A[:, 0] s = A.solve(A[:, 0], 'CH') assert A*s == A[:, 0] A = A.col_join(A) s = A.solve_least_squares(A[:, 0], 'CH') assert A*s == A[:, 0] s = A.solve_least_squares(A[:, 0], 'LDL') assert A*s == A[:, 0] def test_lower_triangular_solve(): a, b, c, d = symbols('a:d') u, v, w, x = symbols('u:x') A = SparseMatrix([[a, 0], [c, d]]) B = MutableSparseMatrix([[u, v], [w, x]]) C = ImmutableSparseMatrix([[u, v], [w, x]]) sol = Matrix([[u/a, v/a], [(w - c*u/a)/d, (x - c*v/a)/d]]) assert A.lower_triangular_solve(B) == sol assert A.lower_triangular_solve(C) == sol def test_upper_triangular_solve(): a, b, c, d = symbols('a:d') u, v, w, x = symbols('u:x') A = SparseMatrix([[a, b], [0, d]]) B = MutableSparseMatrix([[u, v], [w, x]]) C = ImmutableSparseMatrix([[u, v], [w, x]]) sol = Matrix([[(u - b*w/d)/a, (v - b*x/d)/a], [w/d, x/d]]) assert A.upper_triangular_solve(B) == sol assert A.upper_triangular_solve(C) == sol def test_diagonal_solve(): a, d = symbols('a d') u, v, w, x = symbols('u:x') A = SparseMatrix([[a, 0], [0, d]]) B = MutableSparseMatrix([[u, v], [w, x]]) C = ImmutableSparseMatrix([[u, v], [w, x]]) sol = Matrix([[u/a, v/a], [w/d, x/d]]) assert A.diagonal_solve(B) == sol assert A.diagonal_solve(C) == sol def test_hermitian(): x = Symbol('x') a = SparseMatrix([[0, I], [-I, 0]]) assert a.is_hermitian a = SparseMatrix([[1, I], [-I, 1]]) assert a.is_hermitian a[0, 0] = 2*I assert a.is_hermitian is False a[0, 0] = x assert a.is_hermitian is None a[0, 1] = a[1, 0]*I assert a.is_hermitian is False sympy-sympy-1.9/sympy/matrices/tests/test_sparsetools.py000066400000000000000000000113421412543434000240450ustar00rootroot00000000000000from sympy.matrices.sparsetools import _doktocsr, _csrtodok, banded from sympy import eye, ones, zeros, Matrix, SparseMatrix from sympy.testing.pytest import raises def test_doktocsr(): a = SparseMatrix([[1, 2, 0, 0], [0, 3, 9, 0], [0, 1, 4, 0]]) b = SparseMatrix(4, 6, [10, 20, 0, 0, 0, 0, 0, 30, 0, 40, 0, 0, 0, 0, 50, 60, 70, 0, 0, 0, 0, 0, 0, 80]) c = SparseMatrix(4, 4, [0, 0, 0, 0, 0, 12, 0, 2, 15, 0, 12, 0, 0, 0, 0, 4]) d = SparseMatrix(10, 10, {(1, 1): 12, (3, 5): 7, (7, 8): 12}) e = SparseMatrix([[0, 0, 0], [1, 0, 2], [3, 0, 0]]) f = SparseMatrix(7, 8, {(2, 3): 5, (4, 5):12}) assert _doktocsr(a) == [[1, 2, 3, 9, 1, 4], [0, 1, 1, 2, 1, 2], [0, 2, 4, 6], [3, 4]] assert _doktocsr(b) == [[10, 20, 30, 40, 50, 60, 70, 80], [0, 1, 1, 3, 2, 3, 4, 5], [0, 2, 4, 7, 8], [4, 6]] assert _doktocsr(c) == [[12, 2, 15, 12, 4], [1, 3, 0, 2, 3], [0, 0, 2, 4, 5], [4, 4]] assert _doktocsr(d) == [[12, 7, 12], [1, 5, 8], [0, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3], [10, 10]] assert _doktocsr(e) == [[1, 2, 3], [0, 2, 0], [0, 0, 2, 3], [3, 3]] assert _doktocsr(f) == [[5, 12], [3, 5], [0, 0, 0, 1, 1, 2, 2, 2], [7, 8]] def test_csrtodok(): h = [[5, 7, 5], [2, 1, 3], [0, 1, 1, 3], [3, 4]] g = [[12, 5, 4], [2, 4, 2], [0, 1, 2, 3], [3, 7]] i = [[1, 3, 12], [0, 2, 4], [0, 2, 3], [2, 5]] j = [[11, 15, 12, 15], [2, 4, 1, 2], [0, 1, 1, 2, 3, 4], [5, 8]] k = [[1, 3], [2, 1], [0, 1, 1, 2], [3, 3]] m = _csrtodok(h) assert isinstance(m, SparseMatrix) assert m == SparseMatrix(3, 4, {(0, 2): 5, (2, 1): 7, (2, 3): 5}) assert _csrtodok(g) == SparseMatrix(3, 7, {(0, 2): 12, (1, 4): 5, (2, 2): 4}) assert _csrtodok(i) == SparseMatrix([[1, 0, 3, 0, 0], [0, 0, 0, 0, 12]]) assert _csrtodok(j) == SparseMatrix(5, 8, {(0, 2): 11, (2, 4): 15, (3, 1): 12, (4, 2): 15}) assert _csrtodok(k) == SparseMatrix(3, 3, {(0, 2): 1, (2, 1): 3}) def test_banded(): raises(TypeError, lambda: banded()) raises(TypeError, lambda: banded(1)) raises(TypeError, lambda: banded(1, 2)) raises(TypeError, lambda: banded(1, 2, 3)) raises(TypeError, lambda: banded(1, 2, 3, 4)) raises(ValueError, lambda: banded({0: (1, 2)}, rows=1)) raises(ValueError, lambda: banded({0: (1, 2)}, cols=1)) raises(ValueError, lambda: banded(1, {0: (1, 2)})) raises(ValueError, lambda: banded(2, 1, {0: (1, 2)})) raises(ValueError, lambda: banded(1, 2, {0: (1, 2)})) assert isinstance(banded(2, 4, {}), SparseMatrix) assert banded(2, 4, {}) == zeros(2, 4) assert banded({0: 0, 1: 0}) == zeros(0) assert banded({0: Matrix([1, 2])}) == Matrix([1, 2]) assert banded({1: [1, 2, 3, 0], -1: [4, 5, 6]}) == \ banded({1: (1, 2, 3), -1: (4, 5, 6)}) == \ Matrix([ [0, 1, 0, 0], [4, 0, 2, 0], [0, 5, 0, 3], [0, 0, 6, 0]]) assert banded(3, 4, {-1: 1, 0: 2, 1: 3}) == \ Matrix([ [2, 3, 0, 0], [1, 2, 3, 0], [0, 1, 2, 3]]) s = lambda d: (1 + d)**2 assert banded(5, {0: s, 2: s}) == \ Matrix([ [1, 0, 1, 0, 0], [0, 4, 0, 4, 0], [0, 0, 9, 0, 9], [0, 0, 0, 16, 0], [0, 0, 0, 0, 25]]) assert banded(2, {0: 1}) == \ Matrix([ [1, 0], [0, 1]]) assert banded(2, 3, {0: 1}) == \ Matrix([ [1, 0, 0], [0, 1, 0]]) vert = Matrix([1, 2, 3]) assert banded({0: vert}, cols=3) == \ Matrix([ [1, 0, 0], [2, 1, 0], [3, 2, 1], [0, 3, 2], [0, 0, 3]]) assert banded(4, {0: ones(2)}) == \ Matrix([ [1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 1], [0, 0, 1, 1]]) raises(ValueError, lambda: banded({0: 2, 1: ones(2)}, rows=5)) assert banded({0: 2, 2: (ones(2),)*3}) == \ Matrix([ [2, 0, 1, 1, 0, 0, 0, 0], [0, 2, 1, 1, 0, 0, 0, 0], [0, 0, 2, 0, 1, 1, 0, 0], [0, 0, 0, 2, 1, 1, 0, 0], [0, 0, 0, 0, 2, 0, 1, 1], [0, 0, 0, 0, 0, 2, 1, 1]]) raises(ValueError, lambda: banded({0: (2,)*5, 1: (ones(2),)*3})) u2 = Matrix([[1, 1], [0, 1]]) assert banded({0: (2,)*5, 1: (u2,)*3}) == \ Matrix([ [2, 1, 1, 0, 0, 0, 0], [0, 2, 1, 0, 0, 0, 0], [0, 0, 2, 1, 1, 0, 0], [0, 0, 0, 2, 1, 0, 0], [0, 0, 0, 0, 2, 1, 1], [0, 0, 0, 0, 0, 0, 1]]) assert banded({0:(0, ones(2)), 2: 2}) == \ Matrix([ [0, 0, 2], [0, 1, 1], [0, 1, 1]]) raises(ValueError, lambda: banded({0: (0, ones(2)), 1: 2})) assert banded({0: 1}, cols=3) == banded({0: 1}, rows=3) == eye(3) assert banded({1: 1}, rows=3) == Matrix([ [0, 1, 0], [0, 0, 1], [0, 0, 0]]) sympy-sympy-1.9/sympy/matrices/tests/test_subspaces.py000066400000000000000000000073771412543434000234740ustar00rootroot00000000000000from sympy.matrices.common import _MinimalMatrix, _CastableMatrix from sympy.matrices.matrices import MatrixSubspaces from sympy.matrices import Matrix from sympy.core.numbers import Rational from sympy.core.symbol import symbols from sympy.solvers import solve class SubspaceOnlyMatrix(_MinimalMatrix, _CastableMatrix, MatrixSubspaces): pass # SubspaceOnlyMatrix tests def test_columnspace_one(): m = SubspaceOnlyMatrix([[ 1, 2, 0, 2, 5], [-2, -5, 1, -1, -8], [ 0, -3, 3, 4, 1], [ 3, 6, 0, -7, 2]]) basis = m.columnspace() assert basis[0] == Matrix([1, -2, 0, 3]) assert basis[1] == Matrix([2, -5, -3, 6]) assert basis[2] == Matrix([2, -1, 4, -7]) assert len(basis) == 3 assert Matrix.hstack(m, *basis).columnspace() == basis def test_rowspace(): m = SubspaceOnlyMatrix([[ 1, 2, 0, 2, 5], [-2, -5, 1, -1, -8], [ 0, -3, 3, 4, 1], [ 3, 6, 0, -7, 2]]) basis = m.rowspace() assert basis[0] == Matrix([[1, 2, 0, 2, 5]]) assert basis[1] == Matrix([[0, -1, 1, 3, 2]]) assert basis[2] == Matrix([[0, 0, 0, 5, 5]]) assert len(basis) == 3 def test_nullspace_one(): m = SubspaceOnlyMatrix([[ 1, 2, 0, 2, 5], [-2, -5, 1, -1, -8], [ 0, -3, 3, 4, 1], [ 3, 6, 0, -7, 2]]) basis = m.nullspace() assert basis[0] == Matrix([-2, 1, 1, 0, 0]) assert basis[1] == Matrix([-1, -1, 0, -1, 1]) # make sure the null space is really gets zeroed assert all(e.is_zero for e in m*basis[0]) assert all(e.is_zero for e in m*basis[1]) def test_nullspace_second(): # first test reduced row-ech form R = Rational M = Matrix([[5, 7, 2, 1], [1, 6, 2, -1]]) out, tmp = M.rref() assert out == Matrix([[1, 0, -R(2)/23, R(13)/23], [0, 1, R(8)/23, R(-6)/23]]) M = Matrix([[-5, -1, 4, -3, -1], [ 1, -1, -1, 1, 0], [-1, 0, 0, 0, 0], [ 4, 1, -4, 3, 1], [-2, 0, 2, -2, -1]]) assert M*M.nullspace()[0] == Matrix(5, 1, [0]*5) M = Matrix([[ 1, 3, 0, 2, 6, 3, 1], [-2, -6, 0, -2, -8, 3, 1], [ 3, 9, 0, 0, 6, 6, 2], [-1, -3, 0, 1, 0, 9, 3]]) out, tmp = M.rref() assert out == Matrix([[1, 3, 0, 0, 2, 0, 0], [0, 0, 0, 1, 2, 0, 0], [0, 0, 0, 0, 0, 1, R(1)/3], [0, 0, 0, 0, 0, 0, 0]]) # now check the vectors basis = M.nullspace() assert basis[0] == Matrix([-3, 1, 0, 0, 0, 0, 0]) assert basis[1] == Matrix([0, 0, 1, 0, 0, 0, 0]) assert basis[2] == Matrix([-2, 0, 0, -2, 1, 0, 0]) assert basis[3] == Matrix([0, 0, 0, 0, 0, R(-1)/3, 1]) # issue 4797; just see that we can do it when rows > cols M = Matrix([[1, 2], [2, 4], [3, 6]]) assert M.nullspace() def test_columnspace_second(): M = Matrix([[ 1, 2, 0, 2, 5], [-2, -5, 1, -1, -8], [ 0, -3, 3, 4, 1], [ 3, 6, 0, -7, 2]]) # now check the vectors basis = M.columnspace() assert basis[0] == Matrix([1, -2, 0, 3]) assert basis[1] == Matrix([2, -5, -3, 6]) assert basis[2] == Matrix([2, -1, 4, -7]) #check by columnspace definition a, b, c, d, e = symbols('a b c d e') X = Matrix([a, b, c, d, e]) for i in range(len(basis)): eq=M*X-basis[i] assert len(solve(eq, X)) != 0 #check if rank-nullity theorem holds assert M.rank() == len(basis) assert len(M.nullspace()) + len(M.columnspace()) == M.cols sympy-sympy-1.9/sympy/matrices/utilities.py000066400000000000000000000034371412543434000213070ustar00rootroot00000000000000from contextlib import contextmanager from threading import local from sympy.core.function import expand_mul from sympy.simplify.simplify import dotprodsimp as _dotprodsimp class DotProdSimpState(local): def __init__(self): self.state = None _dotprodsimp_state = DotProdSimpState() @contextmanager def dotprodsimp(x): old = _dotprodsimp_state.state try: _dotprodsimp_state.state = x yield finally: _dotprodsimp_state.state = old def _get_intermediate_simp(deffunc=lambda x: x, offfunc=lambda x: x, onfunc=_dotprodsimp, dotprodsimp=None): """Support function for controlling intermediate simplification. Returns a simplification function according to the global setting of dotprodsimp operation. ``deffunc`` - Function to be used by default. ``offfunc`` - Function to be used if dotprodsimp has been turned off. ``onfunc`` - Function to be used if dotprodsimp has been turned on. ``dotprodsimp`` - True, False or None. Will be overridden by global _dotprodsimp_state.state if that is not None. """ if dotprodsimp is False or _dotprodsimp_state.state is False: return offfunc if dotprodsimp is True or _dotprodsimp_state.state is True: return onfunc return deffunc # None, None def _get_intermediate_simp_bool(default=False, dotprodsimp=None): """Same as ``_get_intermediate_simp`` but returns bools instead of functions by default.""" return _get_intermediate_simp(default, False, True, dotprodsimp) def _iszero(x): """Returns True if x is zero.""" return getattr(x, 'is_zero', None) def _is_zero_after_expand_mul(x): """Tests by expand_mul only, suitable for polynomials and rational functions.""" return expand_mul(x) == 0 sympy-sympy-1.9/sympy/multipledispatch/000077500000000000000000000000001412543434000204575ustar00rootroot00000000000000sympy-sympy-1.9/sympy/multipledispatch/__init__.py000066400000000000000000000004031412543434000225650ustar00rootroot00000000000000from .core import dispatch from .dispatcher import (Dispatcher, halt_ordering, restart_ordering, MDNotImplementedError) __version__ = '0.4.9' __all__ = [ 'dispatch', 'Dispatcher', 'halt_ordering', 'restart_ordering', 'MDNotImplementedError', ] sympy-sympy-1.9/sympy/multipledispatch/conflict.py000066400000000000000000000041051412543434000226320ustar00rootroot00000000000000from .utils import _toposort, groupby class AmbiguityWarning(Warning): pass def supercedes(a, b): """ A is consistent and strictly more specific than B """ return len(a) == len(b) and all(map(issubclass, a, b)) def consistent(a, b): """ It is possible for an argument list to satisfy both A and B """ return (len(a) == len(b) and all(issubclass(aa, bb) or issubclass(bb, aa) for aa, bb in zip(a, b))) def ambiguous(a, b): """ A is consistent with B but neither is strictly more specific """ return consistent(a, b) and not (supercedes(a, b) or supercedes(b, a)) def ambiguities(signatures): """ All signature pairs such that A is ambiguous with B """ signatures = list(map(tuple, signatures)) return {(a, b) for a in signatures for b in signatures if hash(a) < hash(b) and ambiguous(a, b) and not any(supercedes(c, a) and supercedes(c, b) for c in signatures)} def super_signature(signatures): """ A signature that would break ambiguities """ n = len(signatures[0]) assert all(len(s) == n for s in signatures) return [max([type.mro(sig[i]) for sig in signatures], key=len)[0] for i in range(n)] def edge(a, b, tie_breaker=hash): """ A should be checked before B Tie broken by tie_breaker, defaults to ``hash`` """ if supercedes(a, b): if supercedes(b, a): return tie_breaker(a) > tie_breaker(b) else: return True return False def ordering(signatures): """ A sane ordering of signatures to check, first to last Topoological sort of edges as given by ``edge`` and ``supercedes`` """ signatures = list(map(tuple, signatures)) edges = [(a, b) for a in signatures for b in signatures if edge(a, b)] edges = groupby(lambda x: x[0], edges) for s in signatures: if s not in edges: edges[s] = [] edges = {k: [b for a, b in v] for k, v in edges.items()} return _toposort(edges) sympy-sympy-1.9/sympy/multipledispatch/core.py000066400000000000000000000043041412543434000217620ustar00rootroot00000000000000from typing import Dict, Any import inspect from .dispatcher import Dispatcher, MethodDispatcher, ambiguity_warn # XXX: This parameter to dispatch isn't documented and isn't used anywhere in # sympy. Maybe it should just be removed. global_namespace = dict() # type: Dict[str, Any] def dispatch(*types, namespace=global_namespace, on_ambiguity=ambiguity_warn): """ Dispatch function on the types of the inputs Supports dispatch on all non-keyword arguments. Collects implementations based on the function name. Ignores namespaces. If ambiguous type signatures occur a warning is raised when the function is defined suggesting the additional method to break the ambiguity. Examples -------- >>> from sympy.multipledispatch import dispatch >>> @dispatch(int) ... def f(x): ... return x + 1 >>> @dispatch(float) ... def f(x): # noqa: F811 ... return x - 1 >>> f(3) 4 >>> f(3.0) 2.0 Specify an isolated namespace with the namespace keyword argument >>> my_namespace = dict() >>> @dispatch(int, namespace=my_namespace) ... def foo(x): ... return x + 1 Dispatch on instance methods within classes >>> class MyClass(object): ... @dispatch(list) ... def __init__(self, data): ... self.data = data ... @dispatch(int) ... def __init__(self, datum): # noqa: F811 ... self.data = [datum] """ types = tuple(types) def _(func): name = func.__name__ if ismethod(func): dispatcher = inspect.currentframe().f_back.f_locals.get( name, MethodDispatcher(name)) else: if name not in namespace: namespace[name] = Dispatcher(name) dispatcher = namespace[name] dispatcher.add(types, func, on_ambiguity=on_ambiguity) return dispatcher return _ def ismethod(func): """ Is func a method? Note that this has to work as the method is defined but before the class is defined. At this stage methods look like functions. """ signature = inspect.signature(func) return signature.parameters.get('self', None) is not None sympy-sympy-1.9/sympy/multipledispatch/dispatcher.py000066400000000000000000000277111412543434000231670ustar00rootroot00000000000000from typing import Set from warnings import warn import inspect from .conflict import ordering, ambiguities, super_signature, AmbiguityWarning from .utils import expand_tuples import itertools as itl class MDNotImplementedError(NotImplementedError): """ A NotImplementedError for multiple dispatch """ ### Functions for on_ambiguity def ambiguity_warn(dispatcher, ambiguities): """ Raise warning when ambiguity is detected Parameters ---------- dispatcher : Dispatcher The dispatcher on which the ambiguity was detected ambiguities : set Set of type signature pairs that are ambiguous within this dispatcher See Also: Dispatcher.add warning_text """ warn(warning_text(dispatcher.name, ambiguities), AmbiguityWarning) class RaiseNotImplementedError: """Raise ``NotImplementedError`` when called.""" def __init__(self, dispatcher): self.dispatcher = dispatcher def __call__(self, *args, **kwargs): types = tuple(type(a) for a in args) raise NotImplementedError( "Ambiguous signature for %s: <%s>" % ( self.dispatcher.name, str_signature(types) )) def ambiguity_register_error_ignore_dup(dispatcher, ambiguities): """ If super signature for ambiguous types is duplicate types, ignore it. Else, register instance of ``RaiseNotImplementedError`` for ambiguous types. Parameters ---------- dispatcher : Dispatcher The dispatcher on which the ambiguity was detected ambiguities : set Set of type signature pairs that are ambiguous within this dispatcher See Also: Dispatcher.add ambiguity_warn """ for amb in ambiguities: signature = tuple(super_signature(amb)) if len(set(signature)) == 1: continue dispatcher.add( signature, RaiseNotImplementedError(dispatcher), on_ambiguity=ambiguity_register_error_ignore_dup ) ### _unresolved_dispatchers = set() # type: Set[Dispatcher] _resolve = [True] def halt_ordering(): _resolve[0] = False def restart_ordering(on_ambiguity=ambiguity_warn): _resolve[0] = True while _unresolved_dispatchers: dispatcher = _unresolved_dispatchers.pop() dispatcher.reorder(on_ambiguity=on_ambiguity) class Dispatcher: """ Dispatch methods based on type signature Use ``dispatch`` to add implementations Examples -------- >>> from sympy.multipledispatch import dispatch >>> @dispatch(int) ... def f(x): ... return x + 1 >>> @dispatch(float) ... def f(x): # noqa: F811 ... return x - 1 >>> f(3) 4 >>> f(3.0) 2.0 """ __slots__ = '__name__', 'name', 'funcs', 'ordering', '_cache', 'doc' def __init__(self, name, doc=None): self.name = self.__name__ = name self.funcs = dict() self._cache = dict() self.ordering = [] self.doc = doc def register(self, *types, **kwargs): """ Register dispatcher with new implementation >>> from sympy.multipledispatch.dispatcher import Dispatcher >>> f = Dispatcher('f') >>> @f.register(int) ... def inc(x): ... return x + 1 >>> @f.register(float) ... def dec(x): ... return x - 1 >>> @f.register(list) ... @f.register(tuple) ... def reverse(x): ... return x[::-1] >>> f(1) 2 >>> f(1.0) 0.0 >>> f([1, 2, 3]) [3, 2, 1] """ def _(func): self.add(types, func, **kwargs) return func return _ @classmethod def get_func_params(cls, func): if hasattr(inspect, "signature"): sig = inspect.signature(func) return sig.parameters.values() @classmethod def get_func_annotations(cls, func): """ Get annotations of function positional parameters """ params = cls.get_func_params(func) if params: Parameter = inspect.Parameter params = (param for param in params if param.kind in (Parameter.POSITIONAL_ONLY, Parameter.POSITIONAL_OR_KEYWORD)) annotations = tuple( param.annotation for param in params) if all(ann is not Parameter.empty for ann in annotations): return annotations def add(self, signature, func, on_ambiguity=ambiguity_warn): """ Add new types/method pair to dispatcher >>> from sympy.multipledispatch import Dispatcher >>> D = Dispatcher('add') >>> D.add((int, int), lambda x, y: x + y) >>> D.add((float, float), lambda x, y: x + y) >>> D(1, 2) 3 >>> D(1, 2.0) Traceback (most recent call last): ... NotImplementedError: Could not find signature for add: When ``add`` detects a warning it calls the ``on_ambiguity`` callback with a dispatcher/itself, and a set of ambiguous type signature pairs as inputs. See ``ambiguity_warn`` for an example. """ # Handle annotations if not signature: annotations = self.get_func_annotations(func) if annotations: signature = annotations # Handle union types if any(isinstance(typ, tuple) for typ in signature): for typs in expand_tuples(signature): self.add(typs, func, on_ambiguity) return for typ in signature: if not isinstance(typ, type): str_sig = ', '.join(c.__name__ if isinstance(c, type) else str(c) for c in signature) raise TypeError("Tried to dispatch on non-type: %s\n" "In signature: <%s>\n" "In function: %s" % (typ, str_sig, self.name)) self.funcs[signature] = func self.reorder(on_ambiguity=on_ambiguity) self._cache.clear() def reorder(self, on_ambiguity=ambiguity_warn): if _resolve[0]: self.ordering = ordering(self.funcs) amb = ambiguities(self.funcs) if amb: on_ambiguity(self, amb) else: _unresolved_dispatchers.add(self) def __call__(self, *args, **kwargs): types = tuple([type(arg) for arg in args]) try: func = self._cache[types] except KeyError: func = self.dispatch(*types) if not func: raise NotImplementedError( 'Could not find signature for %s: <%s>' % (self.name, str_signature(types))) self._cache[types] = func try: return func(*args, **kwargs) except MDNotImplementedError: funcs = self.dispatch_iter(*types) next(funcs) # burn first for func in funcs: try: return func(*args, **kwargs) except MDNotImplementedError: pass raise NotImplementedError("Matching functions for " "%s: <%s> found, but none completed successfully" % (self.name, str_signature(types))) def __str__(self): return "" % self.name __repr__ = __str__ def dispatch(self, *types): """ Deterimine appropriate implementation for this type signature This method is internal. Users should call this object as a function. Implementation resolution occurs within the ``__call__`` method. >>> from sympy.multipledispatch import dispatch >>> @dispatch(int) ... def inc(x): ... return x + 1 >>> implementation = inc.dispatch(int) >>> implementation(3) 4 >>> print(inc.dispatch(float)) None See Also: ``sympy.multipledispatch.conflict`` - module to determine resolution order """ if types in self.funcs: return self.funcs[types] try: return next(self.dispatch_iter(*types)) except StopIteration: return None def dispatch_iter(self, *types): n = len(types) for signature in self.ordering: if len(signature) == n and all(map(issubclass, types, signature)): result = self.funcs[signature] yield result def resolve(self, types): """ Deterimine appropriate implementation for this type signature .. deprecated:: 0.4.4 Use ``dispatch(*types)`` instead """ warn("resolve() is deprecated, use dispatch(*types)", DeprecationWarning) return self.dispatch(*types) def __getstate__(self): return {'name': self.name, 'funcs': self.funcs} def __setstate__(self, d): self.name = d['name'] self.funcs = d['funcs'] self.ordering = ordering(self.funcs) self._cache = dict() @property def __doc__(self): docs = ["Multiply dispatched method: %s" % self.name] if self.doc: docs.append(self.doc) other = [] for sig in self.ordering[::-1]: func = self.funcs[sig] if func.__doc__: s = 'Inputs: <%s>\n' % str_signature(sig) s += '-' * len(s) + '\n' s += func.__doc__.strip() docs.append(s) else: other.append(str_signature(sig)) if other: docs.append('Other signatures:\n ' + '\n '.join(other)) return '\n\n'.join(docs) def _help(self, *args): return self.dispatch(*map(type, args)).__doc__ def help(self, *args, **kwargs): """ Print docstring for the function corresponding to inputs """ print(self._help(*args)) def _source(self, *args): func = self.dispatch(*map(type, args)) if not func: raise TypeError("No function found") return source(func) def source(self, *args, **kwargs): """ Print source code for the function corresponding to inputs """ print(self._source(*args)) def source(func): s = 'File: %s\n\n' % inspect.getsourcefile(func) s = s + inspect.getsource(func) return s class MethodDispatcher(Dispatcher): """ Dispatch methods based on type signature See Also: Dispatcher """ @classmethod def get_func_params(cls, func): if hasattr(inspect, "signature"): sig = inspect.signature(func) return itl.islice(sig.parameters.values(), 1, None) def __get__(self, instance, owner): self.obj = instance self.cls = owner return self def __call__(self, *args, **kwargs): types = tuple([type(arg) for arg in args]) func = self.dispatch(*types) if not func: raise NotImplementedError('Could not find signature for %s: <%s>' % (self.name, str_signature(types))) return func(self.obj, *args, **kwargs) def str_signature(sig): """ String representation of type signature >>> from sympy.multipledispatch.dispatcher import str_signature >>> str_signature((int, float)) 'int, float' """ return ', '.join(cls.__name__ for cls in sig) def warning_text(name, amb): """ The text for ambiguity warnings """ text = "\nAmbiguities exist in dispatched function %s\n\n" % (name) text += "The following signatures may result in ambiguous behavior:\n" for pair in amb: text += "\t" + \ ', '.join('[' + str_signature(s) + ']' for s in pair) + "\n" text += "\n\nConsider making the following additions:\n\n" text += '\n\n'.join(['@dispatch(' + str_signature(super_signature(s)) + ')\ndef %s(...)' % name for s in amb]) return text sympy-sympy-1.9/sympy/multipledispatch/tests/000077500000000000000000000000001412543434000216215ustar00rootroot00000000000000sympy-sympy-1.9/sympy/multipledispatch/tests/__init__.py000066400000000000000000000000001412543434000237200ustar00rootroot00000000000000sympy-sympy-1.9/sympy/multipledispatch/tests/test_conflict.py000066400000000000000000000033721412543434000250400ustar00rootroot00000000000000from sympy.multipledispatch.conflict import (supercedes, ordering, ambiguities, ambiguous, super_signature, consistent) class A: pass class B(A): pass class C: pass def test_supercedes(): assert supercedes([B], [A]) assert supercedes([B, A], [A, A]) assert not supercedes([B, A], [A, B]) assert not supercedes([A], [B]) def test_consistent(): assert consistent([A], [A]) assert consistent([B], [B]) assert not consistent([A], [C]) assert consistent([A, B], [A, B]) assert consistent([B, A], [A, B]) assert not consistent([B, A], [B]) assert not consistent([B, A], [B, C]) def test_super_signature(): assert super_signature([[A]]) == [A] assert super_signature([[A], [B]]) == [B] assert super_signature([[A, B], [B, A]]) == [B, B] assert super_signature([[A, A, B], [A, B, A], [B, A, A]]) == [B, B, B] def test_ambiguous(): assert not ambiguous([A], [A]) assert not ambiguous([A], [B]) assert not ambiguous([B], [B]) assert not ambiguous([A, B], [B, B]) assert ambiguous([A, B], [B, A]) def test_ambiguities(): signatures = [[A], [B], [A, B], [B, A], [A, C]] expected = {((A, B), (B, A))} result = ambiguities(signatures) assert set(map(frozenset, expected)) == set(map(frozenset, result)) signatures = [[A], [B], [A, B], [B, A], [A, C], [B, B]] expected = set() result = ambiguities(signatures) assert set(map(frozenset, expected)) == set(map(frozenset, result)) def test_ordering(): signatures = [[A, A], [A, B], [B, A], [B, B], [A, C]] ord = ordering(signatures) assert ord[0] == (B, B) or ord[0] == (A, C) assert ord[-1] == (A, A) or ord[-1] == (A, C) def test_type_mro(): assert super_signature([[object], [type]]) == [type] sympy-sympy-1.9/sympy/multipledispatch/tests/test_core.py000066400000000000000000000076641412543434000241770ustar00rootroot00000000000000from typing import Dict, Any from sympy.multipledispatch import dispatch from sympy.multipledispatch.conflict import AmbiguityWarning from sympy.testing.pytest import raises, warns from functools import partial test_namespace = dict() # type: Dict[str, Any] orig_dispatch = dispatch dispatch = partial(dispatch, namespace=test_namespace) def test_singledispatch(): @dispatch(int) def f(x): # noqa:F811 return x + 1 @dispatch(int) def g(x): # noqa:F811 return x + 2 @dispatch(float) # noqa:F811 def f(x): # noqa:F811 return x - 1 assert f(1) == 2 assert g(1) == 3 assert f(1.0) == 0 assert raises(NotImplementedError, lambda: f('hello')) def test_multipledispatch(): @dispatch(int, int) def f(x, y): # noqa:F811 return x + y @dispatch(float, float) # noqa:F811 def f(x, y): # noqa:F811 return x - y assert f(1, 2) == 3 assert f(1.0, 2.0) == -1.0 class A: pass class B: pass class C(A): pass class D(C): pass class E(C): pass def test_inheritance(): @dispatch(A) def f(x): # noqa:F811 return 'a' @dispatch(B) # noqa:F811 def f(x): # noqa:F811 return 'b' assert f(A()) == 'a' assert f(B()) == 'b' assert f(C()) == 'a' def test_inheritance_and_multiple_dispatch(): @dispatch(A, A) def f(x, y): # noqa:F811 return type(x), type(y) @dispatch(A, B) # noqa:F811 def f(x, y): # noqa:F811 return 0 assert f(A(), A()) == (A, A) assert f(A(), C()) == (A, C) assert f(A(), B()) == 0 assert f(C(), B()) == 0 assert raises(NotImplementedError, lambda: f(B(), B())) def test_competing_solutions(): @dispatch(A) def h(x): # noqa:F811 return 1 @dispatch(C) # noqa:F811 def h(x): # noqa:F811 return 2 assert h(D()) == 2 def test_competing_multiple(): @dispatch(A, B) def h(x, y): # noqa:F811 return 1 @dispatch(C, B) # noqa:F811 def h(x, y): # noqa:F811 return 2 assert h(D(), B()) == 2 def test_competing_ambiguous(): test_namespace = dict() dispatch = partial(orig_dispatch, namespace=test_namespace) @dispatch(A, C) def f(x, y): # noqa:F811 return 2 with warns(AmbiguityWarning): @dispatch(C, A) # noqa:F811 def f(x, y): # noqa:F811 return 2 assert f(A(), C()) == f(C(), A()) == 2 # assert raises(Warning, lambda : f(C(), C())) def test_caching_correct_behavior(): @dispatch(A) def f(x): # noqa:F811 return 1 assert f(C()) == 1 @dispatch(C) def f(x): # noqa:F811 return 2 assert f(C()) == 2 def test_union_types(): @dispatch((A, C)) def f(x): # noqa:F811 return 1 assert f(A()) == 1 assert f(C()) == 1 def test_namespaces(): ns1 = dict() ns2 = dict() def foo(x): return 1 foo1 = orig_dispatch(int, namespace=ns1)(foo) def foo(x): return 2 foo2 = orig_dispatch(int, namespace=ns2)(foo) assert foo1(0) == 1 assert foo2(0) == 2 """ Fails def test_dispatch_on_dispatch(): @dispatch(A) @dispatch(C) def q(x): # noqa:F811 return 1 assert q(A()) == 1 assert q(C()) == 1 """ def test_methods(): class Foo: @dispatch(float) def f(self, x): # noqa:F811 return x - 1 @dispatch(int) # noqa:F811 def f(self, x): # noqa:F811 return x + 1 @dispatch(int) def g(self, x): # noqa:F811 return x + 3 foo = Foo() assert foo.f(1) == 2 assert foo.f(1.0) == 0.0 assert foo.g(1) == 4 def test_methods_multiple_dispatch(): class Foo: @dispatch(A, A) def f(x, y): # noqa:F811 return 1 @dispatch(A, C) # noqa:F811 def f(x, y): # noqa:F811 return 2 foo = Foo() assert foo.f(A(), A()) == 1 assert foo.f(A(), C()) == 2 assert foo.f(C(), C()) == 2 sympy-sympy-1.9/sympy/multipledispatch/tests/test_dispatcher.py000066400000000000000000000140751412543434000253670ustar00rootroot00000000000000from sympy.multipledispatch.dispatcher import (Dispatcher, MDNotImplementedError, MethodDispatcher, halt_ordering, restart_ordering, ambiguity_register_error_ignore_dup) from sympy.testing.pytest import raises, warns def identity(x): return x def inc(x): return x + 1 def dec(x): return x - 1 def test_dispatcher(): f = Dispatcher('f') f.add((int,), inc) f.add((float,), dec) with warns(DeprecationWarning): assert f.resolve((int,)) == inc assert f.dispatch(int) is inc assert f(1) == 2 assert f(1.0) == 0.0 def test_union_types(): f = Dispatcher('f') f.register((int, float))(inc) assert f(1) == 2 assert f(1.0) == 2.0 def test_dispatcher_as_decorator(): f = Dispatcher('f') @f.register(int) def inc(x): # noqa:F811 return x + 1 @f.register(float) # noqa:F811 def inc(x): # noqa:F811 return x - 1 assert f(1) == 2 assert f(1.0) == 0.0 def test_register_instance_method(): class Test: __init__ = MethodDispatcher('f') @__init__.register(list) def _init_list(self, data): self.data = data @__init__.register(object) def _init_obj(self, datum): self.data = [datum] a = Test(3) b = Test([3]) assert a.data == b.data def test_on_ambiguity(): f = Dispatcher('f') def identity(x): return x ambiguities = [False] def on_ambiguity(dispatcher, amb): ambiguities[0] = True f.add((object, object), identity, on_ambiguity=on_ambiguity) assert not ambiguities[0] f.add((object, float), identity, on_ambiguity=on_ambiguity) assert not ambiguities[0] f.add((float, object), identity, on_ambiguity=on_ambiguity) assert ambiguities[0] def test_raise_error_on_non_class(): f = Dispatcher('f') assert raises(TypeError, lambda: f.add((1,), inc)) def test_docstring(): def one(x, y): """ Docstring number one """ return x + y def two(x, y): """ Docstring number two """ return x + y def three(x, y): return x + y master_doc = 'Doc of the multimethod itself' f = Dispatcher('f', doc=master_doc) f.add((object, object), one) f.add((int, int), two) f.add((float, float), three) assert one.__doc__.strip() in f.__doc__ assert two.__doc__.strip() in f.__doc__ assert f.__doc__.find(one.__doc__.strip()) < \ f.__doc__.find(two.__doc__.strip()) assert 'object, object' in f.__doc__ assert master_doc in f.__doc__ def test_help(): def one(x, y): """ Docstring number one """ return x + y def two(x, y): """ Docstring number two """ return x + y def three(x, y): """ Docstring number three """ return x + y master_doc = 'Doc of the multimethod itself' f = Dispatcher('f', doc=master_doc) f.add((object, object), one) f.add((int, int), two) f.add((float, float), three) assert f._help(1, 1) == two.__doc__ assert f._help(1.0, 2.0) == three.__doc__ def test_source(): def one(x, y): """ Docstring number one """ return x + y def two(x, y): """ Docstring number two """ return x - y master_doc = 'Doc of the multimethod itself' f = Dispatcher('f', doc=master_doc) f.add((int, int), one) f.add((float, float), two) assert 'x + y' in f._source(1, 1) assert 'x - y' in f._source(1.0, 1.0) def test_source_raises_on_missing_function(): f = Dispatcher('f') assert raises(TypeError, lambda: f.source(1)) def test_halt_method_resolution(): g = [0] def on_ambiguity(a, b): g[0] += 1 f = Dispatcher('f') halt_ordering() def func(*args): pass f.add((int, object), func) f.add((object, int), func) assert g == [0] restart_ordering(on_ambiguity=on_ambiguity) assert g == [1] assert set(f.ordering) == {(int, object), (object, int)} def test_no_implementations(): f = Dispatcher('f') assert raises(NotImplementedError, lambda: f('hello')) def test_register_stacking(): f = Dispatcher('f') @f.register(list) @f.register(tuple) def rev(x): return x[::-1] assert f((1, 2, 3)) == (3, 2, 1) assert f([1, 2, 3]) == [3, 2, 1] assert raises(NotImplementedError, lambda: f('hello')) assert rev('hello') == 'olleh' def test_dispatch_method(): f = Dispatcher('f') @f.register(list) def rev(x): return x[::-1] @f.register(int, int) def add(x, y): return x + y class MyList(list): pass assert f.dispatch(list) is rev assert f.dispatch(MyList) is rev assert f.dispatch(int, int) is add def test_not_implemented(): f = Dispatcher('f') @f.register(object) def _(x): return 'default' @f.register(int) def _(x): if x % 2 == 0: return 'even' else: raise MDNotImplementedError() assert f('hello') == 'default' # default behavior assert f(2) == 'even' # specialized behavior assert f(3) == 'default' # fall bac to default behavior assert raises(NotImplementedError, lambda: f(1, 2)) def test_not_implemented_error(): f = Dispatcher('f') @f.register(float) def _(a): raise MDNotImplementedError() assert raises(NotImplementedError, lambda: f(1.0)) def test_ambiguity_register_error_ignore_dup(): f = Dispatcher('f') class A: pass class B(A): pass class C(A): pass # suppress warning for registering ambiguous signal f.add((A, B), lambda x,y: None, ambiguity_register_error_ignore_dup) f.add((B, A), lambda x,y: None, ambiguity_register_error_ignore_dup) f.add((A, C), lambda x,y: None, ambiguity_register_error_ignore_dup) f.add((C, A), lambda x,y: None, ambiguity_register_error_ignore_dup) # raises error if ambiguous signal is passed assert raises(NotImplementedError, lambda: f(B(), C())) sympy-sympy-1.9/sympy/multipledispatch/utils.py000066400000000000000000000060461412543434000221770ustar00rootroot00000000000000from collections import OrderedDict def expand_tuples(L): """ >>> from sympy.multipledispatch.utils import expand_tuples >>> expand_tuples([1, (2, 3)]) [(1, 2), (1, 3)] >>> expand_tuples([1, 2]) [(1, 2)] """ if not L: return [()] elif not isinstance(L[0], tuple): rest = expand_tuples(L[1:]) return [(L[0],) + t for t in rest] else: rest = expand_tuples(L[1:]) return [(item,) + t for t in rest for item in L[0]] # Taken from theano/theano/gof/sched.py # Avoids licensing issues because this was written by Matthew Rocklin def _toposort(edges): """ Topological sort algorithm by Kahn [1] - O(nodes + vertices) inputs: edges - a dict of the form {a: {b, c}} where b and c depend on a outputs: L - an ordered list of nodes that satisfy the dependencies of edges >>> from sympy.multipledispatch.utils import _toposort >>> _toposort({1: (2, 3), 2: (3, )}) [1, 2, 3] Closely follows the wikipedia page [2] [1] Kahn, Arthur B. (1962), "Topological sorting of large networks", Communications of the ACM [2] https://en.wikipedia.org/wiki/Toposort#Algorithms """ incoming_edges = reverse_dict(edges) incoming_edges = {k: set(val) for k, val in incoming_edges.items()} S = OrderedDict.fromkeys(v for v in edges if v not in incoming_edges) L = [] while S: n, _ = S.popitem() L.append(n) for m in edges.get(n, ()): assert n in incoming_edges[m] incoming_edges[m].remove(n) if not incoming_edges[m]: S[m] = None if any(incoming_edges.get(v, None) for v in edges): raise ValueError("Input has cycles") return L def reverse_dict(d): """Reverses direction of dependence dict >>> d = {'a': (1, 2), 'b': (2, 3), 'c':()} >>> reverse_dict(d) # doctest: +SKIP {1: ('a',), 2: ('a', 'b'), 3: ('b',)} :note: dict order are not deterministic. As we iterate on the input dict, it make the output of this function depend on the dict order. So this function output order should be considered as undeterministic. """ result = {} for key in d: for val in d[key]: result[val] = result.get(val, tuple()) + (key, ) return result # Taken from toolz # Avoids licensing issues because this version was authored by Matthew Rocklin def groupby(func, seq): """ Group a collection by a key function >>> from sympy.multipledispatch.utils import groupby >>> names = ['Alice', 'Bob', 'Charlie', 'Dan', 'Edith', 'Frank'] >>> groupby(len, names) # doctest: +SKIP {3: ['Bob', 'Dan'], 5: ['Alice', 'Edith', 'Frank'], 7: ['Charlie']} >>> iseven = lambda x: x % 2 == 0 >>> groupby(iseven, [1, 2, 3, 4, 5, 6, 7, 8]) # doctest: +SKIP {False: [1, 3, 5, 7], True: [2, 4, 6, 8]} See Also: ``countby`` """ d = dict() for item in seq: key = func(item) if key not in d: d[key] = list() d[key].append(item) return d sympy-sympy-1.9/sympy/ntheory/000077500000000000000000000000001412543434000165745ustar00rootroot00000000000000sympy-sympy-1.9/sympy/ntheory/__init__.py000066400000000000000000000052721412543434000207130ustar00rootroot00000000000000""" Number theory module (primes, etc) """ from .generate import nextprime, prevprime, prime, primepi, primerange, \ randprime, Sieve, sieve, primorial, cycle_length, composite, compositepi from .primetest import isprime, is_gaussian_prime from .factor_ import divisors, proper_divisors, factorint, multiplicity, \ multiplicity_in_factorial, perfect_power, pollard_pm1, pollard_rho, \ primefactors, totient, trailing, \ divisor_count, proper_divisor_count, divisor_sigma, factorrat, \ reduced_totient, primenu, primeomega, mersenne_prime_exponent, \ is_perfect, is_mersenne_prime, is_abundant, is_deficient, is_amicable, \ abundance, dra, drm from .partitions_ import npartitions from .residue_ntheory import is_primitive_root, is_quad_residue, \ legendre_symbol, jacobi_symbol, n_order, sqrt_mod, quadratic_residues, \ primitive_root, nthroot_mod, is_nthpow_residue, sqrt_mod_iter, mobius, \ discrete_log, quadratic_congruence, polynomial_congruence from .multinomial import binomial_coefficients, binomial_coefficients_list, \ multinomial_coefficients from .continued_fraction import continued_fraction_periodic, \ continued_fraction_iterator, continued_fraction_reduce, \ continued_fraction_convergents, continued_fraction from .digits import count_digits, digits, is_palindromic from .egyptian_fraction import egyptian_fraction from .ecm import ecm from .qs import qs __all__ = [ 'nextprime', 'prevprime', 'prime', 'primepi', 'primerange', 'randprime', 'Sieve', 'sieve', 'primorial', 'cycle_length', 'composite', 'compositepi', 'isprime', 'is_gaussian_prime', 'divisors', 'proper_divisors', 'factorint', 'multiplicity', 'perfect_power', 'pollard_pm1', 'pollard_rho', 'primefactors', 'totient', 'trailing', 'divisor_count', 'proper_divisor_count', 'divisor_sigma', 'factorrat', 'reduced_totient', 'primenu', 'primeomega', 'mersenne_prime_exponent', 'is_perfect', 'is_mersenne_prime', 'is_abundant', 'is_deficient', 'is_amicable', 'abundance', 'dra', 'drm', 'multiplicity_in_factorial', 'npartitions', 'is_primitive_root', 'is_quad_residue', 'legendre_symbol', 'jacobi_symbol', 'n_order', 'sqrt_mod', 'quadratic_residues', 'primitive_root', 'nthroot_mod', 'is_nthpow_residue', 'sqrt_mod_iter', 'mobius', 'discrete_log', 'quadratic_congruence', 'polynomial_congruence', 'binomial_coefficients', 'binomial_coefficients_list', 'multinomial_coefficients', 'continued_fraction_periodic', 'continued_fraction_iterator', 'continued_fraction_reduce', 'continued_fraction_convergents', 'continued_fraction', 'digits', 'count_digits', 'is_palindromic', 'egyptian_fraction', 'ecm', 'qs', ] sympy-sympy-1.9/sympy/ntheory/bbp_pi.py000066400000000000000000000121351412543434000204030ustar00rootroot00000000000000''' This implementation is a heavily modified fixed point implementation of BBP_formula for calculating the nth position of pi. The original hosted at: http://en.literateprograms.org/Pi_with_the_BBP_formula_(Python) # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sub-license, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Modifications: 1.Once the nth digit and desired number of digits is selected, the number of digits of working precision is calculated to ensure that the hexadecimal digits returned are accurate. This is calculated as int(math.log(start + prec)/math.log(16) + prec + 3) --------------------------------------- -------- / / number of hex digits additional digits This was checked by the following code which completed without errors (and dig are the digits included in the test_bbp.py file): for i in range(0,1000): for j in range(1,1000): a, b = pi_hex_digits(i, j), dig[i:i+j] if a != b: print('%s\n%s'%(a,b)) Deceasing the additional digits by 1 generated errors, so '3' is the smallest additional precision needed to calculate the above loop without errors. The following trailing 10 digits were also checked to be accurate (and the times were slightly faster with some of the constant modifications that were made): >> from time import time >> t=time();pi_hex_digits(10**2-10 + 1, 10), time()-t ('e90c6cc0ac', 0.0) >> t=time();pi_hex_digits(10**4-10 + 1, 10), time()-t ('26aab49ec6', 0.17100000381469727) >> t=time();pi_hex_digits(10**5-10 + 1, 10), time()-t ('a22673c1a5', 4.7109999656677246) >> t=time();pi_hex_digits(10**6-10 + 1, 10), time()-t ('9ffd342362', 59.985999822616577) >> t=time();pi_hex_digits(10**7-10 + 1, 10), time()-t ('c1a42e06a1', 689.51800012588501) 2. The while loop to evaluate whether the series has converged quits when the addition amount `dt` has dropped to zero. 3. the formatting string to convert the decimal to hexadecimal is calculated for the given precision. 4. pi_hex_digits(n) changed to have coefficient to the formula in an array (perhaps just a matter of preference). ''' import math from sympy.core.compatibility import as_int def _series(j, n, prec=14): # Left sum from the bbp algorithm s = 0 D = _dn(n, prec) D4 = 4 * D k = 0 d = 8 * k + j for k in range(n + 1): s += (pow(16, n - k, d) << D4) // d d += 8 # Right sum iterates to infinity for full precision, but we # stop at the point where one iteration is beyond the precision # specified. t = 0 k = n + 1 e = 4*(D + n - k) d = 8 * k + j while True: dt = (1 << e) // d if not dt: break t += dt # k += 1 e -= 4 d += 8 total = s + t return total def pi_hex_digits(n, prec=14): """Returns a string containing ``prec`` (default 14) digits starting at the nth digit of pi in hex. Counting of digits starts at 0 and the decimal is not counted, so for n = 0 the returned value starts with 3; n = 1 corresponds to the first digit past the decimal point (which in hex is 2). Examples ======== >>> from sympy.ntheory.bbp_pi import pi_hex_digits >>> pi_hex_digits(0) '3243f6a8885a30' >>> pi_hex_digits(0, 3) '324' References ========== .. [1] http://www.numberworld.org/digits/Pi/ """ n, prec = as_int(n), as_int(prec) if n < 0: raise ValueError('n cannot be negative') if prec == 0: return '' # main of implementation arrays holding formulae coefficients n -= 1 a = [4, 2, 1, 1] j = [1, 4, 5, 6] #formulae D = _dn(n, prec) x = + (a[0]*_series(j[0], n, prec) - a[1]*_series(j[1], n, prec) - a[2]*_series(j[2], n, prec) - a[3]*_series(j[3], n, prec)) & (16**D - 1) s = ("%0" + "%ix" % prec) % (x // 16**(D - prec)) return s def _dn(n, prec): # controller for n dependence on precision # n = starting digit index # prec = the number of total digits to compute n += 1 # because we subtract 1 for _series return int(math.log(n + prec)/math.log(16) + prec + 3) sympy-sympy-1.9/sympy/ntheory/continued_fraction.py000066400000000000000000000235331412543434000230310ustar00rootroot00000000000000from sympy.core.numbers import Integer, Rational from sympy.core.singleton import S from sympy.core.sympify import _sympify def continued_fraction(a): """Return the continued fraction representation of a Rational or quadratic irrational. Examples ======== >>> from sympy.ntheory.continued_fraction import continued_fraction >>> from sympy import sqrt >>> continued_fraction((1 + 2*sqrt(3))/5) [0, 1, [8, 3, 34, 3]] See Also ======== continued_fraction_periodic, continued_fraction_reduce, continued_fraction_convergents """ e = _sympify(a) if all(i.is_Rational for i in e.atoms()): if e.is_Integer: return continued_fraction_periodic(e, 1, 0) elif e.is_Rational: return continued_fraction_periodic(e.p, e.q, 0) elif e.is_Pow and e.exp is S.Half and e.base.is_Integer: return continued_fraction_periodic(0, 1, e.base) elif e.is_Mul and len(e.args) == 2 and ( e.args[0].is_Rational and e.args[1].is_Pow and e.args[1].base.is_Integer and e.args[1].exp is S.Half): a, b = e.args return continued_fraction_periodic(0, a.q, b.base, a.p) else: # this should not have to work very hard- no # simplification, cancel, etc... which should be # done by the user. e.g. This is a fancy 1 but # the user should simplify it first: # sqrt(2)*(1 + sqrt(2))/(sqrt(2) + 2) p, d = e.expand().as_numer_denom() if d.is_Integer: if p.is_Rational: return continued_fraction_periodic(p, d) # look for a + b*c # with c = sqrt(s) if p.is_Add and len(p.args) == 2: a, bc = p.args else: a = S.Zero bc = p if a.is_Integer: b = S.NaN if bc.is_Mul and len(bc.args) == 2: b, c = bc.args elif bc.is_Pow: b = Integer(1) c = bc if b.is_Integer and ( c.is_Pow and c.exp is S.Half and c.base.is_Integer): # (a + b*sqrt(c))/d c = c.base return continued_fraction_periodic(a, d, c, b) raise ValueError( 'expecting a rational or quadratic irrational, not %s' % e) def continued_fraction_periodic(p, q, d=0, s=1): r""" Find the periodic continued fraction expansion of a quadratic irrational. Compute the continued fraction expansion of a rational or a quadratic irrational number, i.e. `\frac{p + s\sqrt{d}}{q}`, where `p`, `q \ne 0` and `d \ge 0` are integers. Returns the continued fraction representation (canonical form) as a list of integers, optionally ending (for quadratic irrationals) with list of integers representing the repeating digits. Parameters ========== p : int the rational part of the number's numerator q : int the denominator of the number d : int, optional the irrational part (discriminator) of the number's numerator s : int, optional the coefficient of the irrational part Examples ======== >>> from sympy.ntheory.continued_fraction import continued_fraction_periodic >>> continued_fraction_periodic(3, 2, 7) [2, [1, 4, 1, 1]] Golden ratio has the simplest continued fraction expansion: >>> continued_fraction_periodic(1, 2, 5) [[1]] If the discriminator is zero or a perfect square then the number will be a rational number: >>> continued_fraction_periodic(4, 3, 0) [1, 3] >>> continued_fraction_periodic(4, 3, 49) [3, 1, 2] See Also ======== continued_fraction_iterator, continued_fraction_reduce References ========== .. [1] https://en.wikipedia.org/wiki/Periodic_continued_fraction .. [2] K. Rosen. Elementary Number theory and its applications. Addison-Wesley, 3 Sub edition, pages 379-381, January 1992. """ from sympy.core.compatibility import as_int from sympy.functions import sqrt, floor p, q, d, s = list(map(as_int, [p, q, d, s])) if d < 0: raise ValueError("expected non-negative for `d` but got %s" % d) if q == 0: raise ValueError("The denominator cannot be 0.") if not s: d = 0 # check for rational case sd = sqrt(d) if sd.is_Integer: return list(continued_fraction_iterator(Rational(p + s*sd, q))) # irrational case with sd != Integer if q < 0: p, q, s = -p, -q, -s n = (p + s*sd)/q if n < 0: w = floor(-n) f = -n - w one_f = continued_fraction(1 - f) # 1-f < 1 so cf is [0 ... [...]] one_f[0] -= w + 1 return one_f d *= s**2 sd *= s if (d - p**2)%q: d *= q**2 sd *= q p *= q q *= q terms = [] pq = {} while (p, q) not in pq: pq[(p, q)] = len(terms) terms.append((p + sd)//q) p = terms[-1]*q - p q = (d - p**2)//q i = pq[(p, q)] return terms[:i] + [terms[i:]] def continued_fraction_reduce(cf): """ Reduce a continued fraction to a rational or quadratic irrational. Compute the rational or quadratic irrational number from its terminating or periodic continued fraction expansion. The continued fraction expansion (cf) should be supplied as a terminating iterator supplying the terms of the expansion. For terminating continued fractions, this is equivalent to ``list(continued_fraction_convergents(cf))[-1]``, only a little more efficient. If the expansion has a repeating part, a list of the repeating terms should be returned as the last element from the iterator. This is the format returned by continued_fraction_periodic. For quadratic irrationals, returns the largest solution found, which is generally the one sought, if the fraction is in canonical form (all terms positive except possibly the first). Examples ======== >>> from sympy.ntheory.continued_fraction import continued_fraction_reduce >>> continued_fraction_reduce([1, 2, 3, 4, 5]) 225/157 >>> continued_fraction_reduce([-2, 1, 9, 7, 1, 2]) -256/233 >>> continued_fraction_reduce([2, 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8]).n(10) 2.718281835 >>> continued_fraction_reduce([1, 4, 2, [3, 1]]) (sqrt(21) + 287)/238 >>> continued_fraction_reduce([[1]]) (1 + sqrt(5))/2 >>> from sympy.ntheory.continued_fraction import continued_fraction_periodic >>> continued_fraction_reduce(continued_fraction_periodic(8, 5, 13)) (sqrt(13) + 8)/5 See Also ======== continued_fraction_periodic """ from sympy.core.exprtools import factor_terms from sympy.core.symbol import Dummy from sympy.solvers import solve period = [] x = Dummy('x') def untillist(cf): for nxt in cf: if isinstance(nxt, list): period.extend(nxt) yield x break yield nxt a = Integer(0) for a in continued_fraction_convergents(untillist(cf)): pass if period: y = Dummy('y') solns = solve(continued_fraction_reduce(period + [y]) - y, y) solns.sort() pure = solns[-1] rv = a.subs(x, pure).radsimp() else: rv = a if rv.is_Add: rv = factor_terms(rv) if rv.is_Mul and rv.args[0] == -1: rv = rv.func(*rv.args) return rv def continued_fraction_iterator(x): """ Return continued fraction expansion of x as iterator. Examples ======== >>> from sympy.core import Rational, pi >>> from sympy.ntheory.continued_fraction import continued_fraction_iterator >>> list(continued_fraction_iterator(Rational(3, 8))) [0, 2, 1, 2] >>> list(continued_fraction_iterator(Rational(-3, 8))) [-1, 1, 1, 1, 2] >>> for i, v in enumerate(continued_fraction_iterator(pi)): ... if i > 7: ... break ... print(v) 3 7 15 1 292 1 1 1 References ========== .. [1] https://en.wikipedia.org/wiki/Continued_fraction """ from sympy.functions import floor while True: i = floor(x) yield i x -= i if not x: break x = 1/x def continued_fraction_convergents(cf): """ Return an iterator over the convergents of a continued fraction (cf). The parameter should be an iterable returning successive partial quotients of the continued fraction, such as might be returned by continued_fraction_iterator. In computing the convergents, the continued fraction need not be strictly in canonical form (all integers, all but the first positive). Rational and negative elements may be present in the expansion. Examples ======== >>> from sympy.core import pi >>> from sympy import S >>> from sympy.ntheory.continued_fraction import \ continued_fraction_convergents, continued_fraction_iterator >>> list(continued_fraction_convergents([0, 2, 1, 2])) [0, 1/2, 1/3, 3/8] >>> list(continued_fraction_convergents([1, S('1/2'), -7, S('1/4')])) [1, 3, 19/5, 7] >>> it = continued_fraction_convergents(continued_fraction_iterator(pi)) >>> for n in range(7): ... print(next(it)) 3 22/7 333/106 355/113 103993/33102 104348/33215 208341/66317 See Also ======== continued_fraction_iterator """ p_2, q_2 = Integer(0), Integer(1) p_1, q_1 = Integer(1), Integer(0) for a in cf: p, q = a*p_1 + p_2, a*q_1 + q_2 p_2, q_2 = p_1, q_1 p_1, q_1 = p, q yield p/q sympy-sympy-1.9/sympy/ntheory/digits.py000066400000000000000000000071541412543434000204400ustar00rootroot00000000000000from collections import defaultdict from sympy.core.compatibility import as_int from sympy.utilities.iterables import multiset, is_palindromic as _palindromic def digits(n, b=10, digits=None): """ Return a list of the digits of ``n`` in base ``b``. The first element in the list is ``b`` (or ``-b`` if ``n`` is negative). Examples ======== >>> from sympy.ntheory.digits import digits >>> digits(35) [10, 3, 5] If the number is negative, the negative sign will be placed on the base (which is the first element in the returned list): >>> digits(-35) [-10, 3, 5] Bases other than 10 (and greater than 1) can be selected with ``b``: >>> digits(27, b=2) [2, 1, 1, 0, 1, 1] Use the ``digits`` keyword if a certain number of digits is desired: >>> digits(35, digits=4) [10, 0, 0, 3, 5] Parameters ========== n: integer The number whose digits are returned. b: integer The base in which digits are computed. digits: integer (or None for all digits) The number of digits to be returned (padded with zeros, if necessary). """ b = as_int(b) n = as_int(n) if b < 2: raise ValueError("b must be greater than 1") else: x, y = abs(n), [] while x >= b: x, r = divmod(x, b) y.append(r) y.append(x) y.append(-b if n < 0 else b) y.reverse() ndig = len(y) - 1 if digits is not None: if ndig > digits: raise ValueError( "For %s, at least %s digits are needed." % (n, ndig)) elif ndig < digits: y[1:1] = [0]*(digits - ndig) return y def count_digits(n, b=10): """ Return a dictionary whose keys are the digits of ``n`` in the given base, ``b``, with keys indicating the digits appearing in the number and values indicating how many times that digit appeared. Examples ======== >>> from sympy.ntheory import count_digits >>> count_digits(1111339) {1: 4, 3: 2, 9: 1} The digits returned are always represented in base-10 but the number itself can be entered in any format that is understood by Python; the base of the number can also be given if it is different than 10: >>> n = 0xFA; n 250 >>> count_digits(_) {0: 1, 2: 1, 5: 1} >>> count_digits(n, 16) {10: 1, 15: 1} The default dictionary will return a 0 for any digit that did not appear in the number. For example, which digits appear 7 times in ``77!``: >>> from sympy import factorial >>> c77 = count_digits(factorial(77)) >>> [i for i in range(10) if c77[i] == 7] [1, 3, 7, 9] """ rv = defaultdict(int, multiset(digits(n, b)).items()) rv.pop(b) if b in rv else rv.pop(-b) # b or -b is there return rv def is_palindromic(n, b=10): """return True if ``n`` is the same when read from left to right or right to left in the given base, ``b``. Examples ======== >>> from sympy.ntheory import is_palindromic >>> all(is_palindromic(i) for i in (-11, 1, 22, 121)) True The second argument allows you to test numbers in other bases. For example, 88 is palindromic in base-10 but not in base-8: >>> is_palindromic(88, 8) False On the other hand, a number can be palindromic in base-8 but not in base-10: >>> 0o121, is_palindromic(0o121) (81, False) Or it might be palindromic in both bases: >>> oct(121), is_palindromic(121, 8) and is_palindromic(121) ('0o171', True) """ return _palindromic(digits(n, b), 1) sympy-sympy-1.9/sympy/ntheory/ecm.py000066400000000000000000000236351412543434000177230ustar00rootroot00000000000000from sympy.ntheory import sieve, isprime from sympy.core.power import integer_log from sympy.core.compatibility import as_int import random rgen = random.Random() #----------------------------------------------------------------------------# # # # Lenstra's Elliptic Curve Factorization # # # #----------------------------------------------------------------------------# class Point: """Montgomery form of Points in an elliptic curve. In this form, the addition and doubling of points does not need any y-coordinate information thus decreasing the number of operations. Using Montgomery form we try to perform point addition and doubling in least amount of multiplications. The elliptic curve used here is of the form (E : b*y**2*z = x**3 + a*x**2*z + x*z**2). The a_24 parameter is equal to (a + 2)/4. References ========== .. [1] http://www.hyperelliptic.org/tanja/SHARCS/talks06/Gaj.pdf """ def __init__(self, x_cord, z_cord, a_24, mod): """ Initial parameters for the Point class. Parameters ========== x_cord : X coordinate of the Point z_cord : Z coordinate of the Point a_24 : Parameter of the elliptic curve in Montgomery form mod : modulus """ self.x_cord = x_cord self.z_cord = z_cord self.a_24 = a_24 self.mod = mod def __eq__(self, other): """Two points are equal if X/Z of both points are equal """ from sympy import mod_inverse if self.a_24 != other.a_24 or self.mod != other.mod: return False return self.x_cord * mod_inverse(self.z_cord, self.mod) % self.mod ==\ other.x_cord * mod_inverse(other.z_cord, self.mod) % self.mod def add(self, Q, diff): """ Add two points self and Q where diff = self - Q. Moreover the assumption is self.x_cord*Q.x_cord*(self.x_cord - Q.x_cord) != 0. This algorithm requires 6 multiplications. Here the difference between the points is already known and using this algorihtm speeds up the addition by reducing the number of multiplication required. Also in the mont_ladder algorithm is constructed in a way so that the difference between intermediate points is always equal to the initial point. So, we always know what the difference between the point is. Parameters ========== Q : point on the curve in Montgomery form diff : self - Q Examples ======== >>> from sympy.ntheory.ecm import Point >>> p1 = Point(11, 16, 7, 29) >>> p2 = Point(13, 10, 7, 29) >>> p3 = p2.add(p1, p1) >>> p3.x_cord 23 >>> p3.z_cord 17 """ u = (self.x_cord - self.z_cord)*(Q.x_cord + Q.z_cord) v = (self.x_cord + self.z_cord)*(Q.x_cord - Q.z_cord) add, subt = u + v, u - v x_cord = diff.z_cord * add * add % self.mod z_cord = diff.x_cord * subt * subt % self.mod return Point(x_cord, z_cord, self.a_24, self.mod) def double(self): """ Doubles a point in an elliptic curve in Montgomery form. This algorithm requires 5 multiplications. Examples ======== >>> from sympy.ntheory.ecm import Point >>> p1 = Point(11, 16, 7, 29) >>> p2 = p1.double() >>> p2.x_cord 13 >>> p2.z_cord 10 """ u, v = self.x_cord + self.z_cord, self.x_cord - self.z_cord u, v = u*u, v*v diff = u - v x_cord = u*v % self.mod z_cord = diff*(v + self.a_24*diff) % self.mod return Point(x_cord, z_cord, self.a_24, self.mod) def mont_ladder(self, k): """ Scalar multiplication of a point in Montgomery form using Montgomery Ladder Algorithm. A total of 11 multiplications are required in each step of this algorithm. Parameters ========== k : The positive integer multiplier Examples ======== >>> from sympy.ntheory.ecm import Point >>> p1 = Point(11, 16, 7, 29) >>> p3 = p1.mont_ladder(3) >>> p3.x_cord 23 >>> p3.z_cord 17 """ Q = self R = self.double() for i in bin(k)[3:]: if i == '1': Q = R.add(Q, self) R = R.double() else: R = Q.add(R, self) Q = Q.double() return Q def _ecm_one_factor(n, B1=10000, B2=100000, max_curve=200): """Returns one factor of n using Lenstra's 2 Stage Elliptic curve Factorization with Suyama's Parameterization. Here Montgomery arithmetic is used for fast computation of addition and doubling of points in elliptic curve. This ECM method considers elliptic curves in Montgomery form (E : b*y**2*z = x**3 + a*x**2*z + x*z**2) and involves elliptic curve operations (mod N), where the elements in Z are reduced (mod N). Since N is not a prime, E over FF(N) is not really an elliptic curve but we can still do point additions and doubling as if FF(N) was a field. Stage 1 : The basic algorithm involves taking a random point (P) on an elliptic curve in FF(N). The compute k*P using Montgomery ladder algorithm. Let q be an unknown factor of N. Then the order of the curve E, |E(FF(q))|, might be a smooth number that divides k. Then we have k = l * |E(FF(q))| for some l. For any point belonging to the curve E, |E(FF(q))|*P = O, hence k*P = l*|E(FF(q))|*P. Thus kP.z_cord = 0 (mod q), and the unknownn factor of N (q) can be recovered by taking gcd(kP.z_cord, N). Stage 2 : This is a continuation of Stage 1 if k*P != O. The idea utilize the fact that even if kP != 0, the value of k might miss just one large prime divisor of |E(FF(q))|. In this case we only need to compute the scalar multiplication by p to get p*k*P = O. Here a second bound B2 restrict the size of possible values of p. Parameters ========== n : Number to be Factored B1 : Stage 1 Bound B2 : Stage 2 Bound max_curve : Maximum number of curves generated References ========== .. [1] Carl Pomerance and Richard Crandall "Prime Numbers: A Computational Perspective" (2nd Ed.), page 344 """ from sympy import gcd, mod_inverse, sqrt n = as_int(n) if B1 % 2 != 0 or B2 % 2 != 0: raise ValueError("The Bounds should be an even integer") sieve.extend(B2) if isprime(n): return n curve = 0 D = int(sqrt(B2)) beta = [0]*(D + 1) S = [0]*(D + 1) k = 1 for p in sieve.primerange(1, B1 + 1): k *= pow(p, integer_log(B1, p)[0]) while(curve <= max_curve): curve += 1 #Suyama's Paramatrization sigma = rgen.randint(6, n - 1) u = (sigma*sigma - 5) % n v = (4*sigma) % n diff = v - u u_3 = pow(u, 3, n) try: C = (pow(diff, 3, n)*(3*u + v)*mod_inverse(4*u_3*v, n) - 2) % n except ValueError: #If the mod_inverse(4*u_3*v, n) doesn't exist return gcd(4*u_3*v, n) a24 = (C + 2)*mod_inverse(4, n) % n Q = Point(u_3 , pow(v, 3, n), a24, n) Q = Q.mont_ladder(k) g = gcd(Q.z_cord, n) #Stage 1 factor if g != 1 and g != n: return g #Stage 1 failure. Q.z = 0, Try another curve elif g == n: continue #Stage 2 - Improved Standard Continuation S[1] = Q.double() S[2] = S[1].double() beta[1] = (S[1].x_cord*S[1].z_cord) % n beta[2] = (S[2].x_cord*S[2].z_cord) % n for d in range(3, D + 1): S[d] = S[d - 1].add(S[1], S[d - 2]) beta[d] = (S[d].x_cord*S[d].z_cord) % n g = 1 B = B1 - 1 T = Q.mont_ladder(B - 2*D) R = Q.mont_ladder(B) for r in range(B, B2, 2*D): alpha = (R.x_cord*R.z_cord) % n for q in sieve.primerange(r + 2, r + 2*D + 1): delta = (q - r) // 2 f = (R.x_cord - S[d].x_cord)*(R.z_cord + S[d].z_cord) -\ alpha + beta[delta] g = (g*f) % n #Swap T, R = R, R.add(S[D], T) g = gcd(n, g) #Stage 2 Factor found if g != 1 and g != n: return g #ECM failed, Increase the bounds raise ValueError("Increase the bounds") def ecm(n, B1=10000, B2=100000, max_curve=200, seed=1234): """Performs factorization using Lenstra's Elliptic curve method. This function repeatedly calls `ecm_one_factor` to compute the factors of n. First all the small factors are taken out using trial division. Then `ecm_one_factor` is used to compute one factor at a time. Parameters ========== n : Number to be Factored B1 : Stage 1 Bound B2 : Stage 2 Bound max_curve : Maximum number of curves generated seed : Initialize pseudorandom generator Examples ======== >>> from sympy.ntheory import ecm >>> ecm(25645121643901801) {5394769, 4753701529} >>> ecm(9804659461513846513) {4641991, 2112166839943} """ _factors = set() for prime in sieve.primerange(1, 100000): if n % prime == 0: _factors.add(prime) while(n % prime == 0): n //= prime rgen.seed(seed) while(n > 1): try: factor = _ecm_one_factor(n, B1, B2, max_curve) except ValueError: raise ValueError("Increase the bounds") _factors.add(factor) n //= factor factors = set() for factor in _factors: if isprime(factor): factors.add(factor) continue factors |= ecm(factor) return factors sympy-sympy-1.9/sympy/ntheory/egyptian_fraction.py000066400000000000000000000152321412543434000226560ustar00rootroot00000000000000from sympy import Integer, Rational, Tuple import sympy.polys from math import gcd def egyptian_fraction(r, algorithm="Greedy"): """ Return the list of denominators of an Egyptian fraction expansion [1]_ of the said rational `r`. Parameters ========== r : Rational or (p, q) a positive rational number, ``p/q``. algorithm : { "Greedy", "Graham Jewett", "Takenouchi", "Golomb" }, optional Denotes the algorithm to be used (the default is "Greedy"). Examples ======== >>> from sympy import Rational >>> from sympy.ntheory.egyptian_fraction import egyptian_fraction >>> egyptian_fraction(Rational(3, 7)) [3, 11, 231] >>> egyptian_fraction((3, 7), "Graham Jewett") [7, 8, 9, 56, 57, 72, 3192] >>> egyptian_fraction((3, 7), "Takenouchi") [4, 7, 28] >>> egyptian_fraction((3, 7), "Golomb") [3, 15, 35] >>> egyptian_fraction((11, 5), "Golomb") [1, 2, 3, 4, 9, 234, 1118, 2580] See Also ======== sympy.core.numbers.Rational Notes ===== Currently the following algorithms are supported: 1) Greedy Algorithm Also called the Fibonacci-Sylvester algorithm [2]_. At each step, extract the largest unit fraction less than the target and replace the target with the remainder. It has some distinct properties: a) Given `p/q` in lowest terms, generates an expansion of maximum length `p`. Even as the numerators get large, the number of terms is seldom more than a handful. b) Uses minimal memory. c) The terms can blow up (standard examples of this are 5/121 and 31/311). The denominator is at most squared at each step (doubly-exponential growth) and typically exhibits singly-exponential growth. 2) Graham Jewett Algorithm The algorithm suggested by the result of Graham and Jewett. Note that this has a tendency to blow up: the length of the resulting expansion is always ``2**(x/gcd(x, y)) - 1``. See [3]_. 3) Takenouchi Algorithm The algorithm suggested by Takenouchi (1921). Differs from the Graham-Jewett algorithm only in the handling of duplicates. See [3]_. 4) Golomb's Algorithm A method given by Golumb (1962), using modular arithmetic and inverses. It yields the same results as a method using continued fractions proposed by Bleicher (1972). See [4]_. If the given rational is greater than or equal to 1, a greedy algorithm of summing the harmonic sequence 1/1 + 1/2 + 1/3 + ... is used, taking all the unit fractions of this sequence until adding one more would be greater than the given number. This list of denominators is prefixed to the result from the requested algorithm used on the remainder. For example, if r is 8/3, using the Greedy algorithm, we get [1, 2, 3, 4, 5, 6, 7, 14, 420], where the beginning of the sequence, [1, 2, 3, 4, 5, 6, 7] is part of the harmonic sequence summing to 363/140, leaving a remainder of 31/420, which yields [14, 420] by the Greedy algorithm. The result of egyptian_fraction(Rational(8, 3), "Golomb") is [1, 2, 3, 4, 5, 6, 7, 14, 574, 2788, 6460, 11590, 33062, 113820], and so on. References ========== .. [1] https://en.wikipedia.org/wiki/Egyptian_fraction .. [2] https://en.wikipedia.org/wiki/Greedy_algorithm_for_Egyptian_fractions .. [3] https://www.ics.uci.edu/~eppstein/numth/egypt/conflict.html .. [4] http://ami.ektf.hu/uploads/papers/finalpdf/AMI_42_from129to134.pdf """ if not isinstance(r, Rational): if isinstance(r, (Tuple, tuple)) and len(r) == 2: r = Rational(*r) else: raise ValueError("Value must be a Rational or tuple of ints") if r <= 0: raise ValueError("Value must be positive") # common cases that all methods agree on x, y = r.as_numer_denom() if y == 1 and x == 2: return [Integer(i) for i in [1, 2, 3, 6]] if x == y + 1: return [Integer(1), y] prefix, rem = egypt_harmonic(r) if rem == 0: return prefix # work in python ints x, y = rem.p, rem.q # assert x < y and gcd(x, y) = 1 if algorithm == "Greedy": postfix = egypt_greedy(x, y) elif algorithm == "Graham Jewett": postfix = egypt_graham_jewett(x, y) elif algorithm == "Takenouchi": postfix = egypt_takenouchi(x, y) elif algorithm == "Golomb": postfix = egypt_golomb(x, y) else: raise ValueError("Entered invalid algorithm") return prefix + [Integer(i) for i in postfix] def egypt_greedy(x, y): # assumes gcd(x, y) == 1 if x == 1: return [y] else: a = (-y) % x b = y*(y//x + 1) c = gcd(a, b) if c > 1: num, denom = a//c, b//c else: num, denom = a, b return [y//x + 1] + egypt_greedy(num, denom) def egypt_graham_jewett(x, y): # assumes gcd(x, y) == 1 l = [y] * x # l is now a list of integers whose reciprocals sum to x/y. # we shall now proceed to manipulate the elements of l without # changing the reciprocated sum until all elements are unique. while len(l) != len(set(l)): l.sort() # so the list has duplicates. find a smallest pair for i in range(len(l) - 1): if l[i] == l[i + 1]: break # we have now identified a pair of identical # elements: l[i] and l[i + 1]. # now comes the application of the result of graham and jewett: l[i + 1] = l[i] + 1 # and we just iterate that until the list has no duplicates. l.append(l[i]*(l[i] + 1)) return sorted(l) def egypt_takenouchi(x, y): # assumes gcd(x, y) == 1 # special cases for 3/y if x == 3: if y % 2 == 0: return [y//2, y] i = (y - 1)//2 j = i + 1 k = j + i return [j, k, j*k] l = [y] * x while len(l) != len(set(l)): l.sort() for i in range(len(l) - 1): if l[i] == l[i + 1]: break k = l[i] if k % 2 == 0: l[i] = l[i] // 2 del l[i + 1] else: l[i], l[i + 1] = (k + 1)//2, k*(k + 1)//2 return sorted(l) def egypt_golomb(x, y): # assumes x < y and gcd(x, y) == 1 if x == 1: return [y] xp = sympy.polys.ZZ.invert(int(x), int(y)) rv = [xp*y] rv.extend(egypt_golomb((x*xp - 1)//y, xp)) return sorted(rv) def egypt_harmonic(r): # assumes r is Rational rv = [] d = Integer(1) acc = Integer(0) while acc + 1/d <= r: acc += 1/d rv.append(d) d += 1 return (rv, r - acc) sympy-sympy-1.9/sympy/ntheory/elliptic_curve.py000066400000000000000000000263211412543434000221630ustar00rootroot00000000000000from sympy.core.compatibility import as_int, is_sequence from sympy.core.numbers import oo from sympy.core.relational import Eq from sympy.core.symbol import symbols from sympy.polys.domains import FiniteField, QQ, RationalField, FF from sympy.solvers.solvers import solve from .factor_ import divisors from .residue_ntheory import polynomial_congruence class EllipticCurve: """ Create the following Elliptic Curve over domain. `y^{2} + a_{1} x y + a_{3} y = x^{3} + a_{2} x^{2} + a_{4} x + a_{6}` The default domain is ``QQ``. If no coefficient ``a1``, ``a2``, ``a3``, it create curve as following form. `y^{2} = x^{3} + a_{4} x + a_{6}` Examples ======== References ========== [1] J. Silverman "A Friendly Introduction to Number Theory" Third Edition [2] http://mathworld.wolfram.com/EllipticDiscriminant.html [3] G. Hardy, E. Wright "An Introduction to the Theory of Numbers" Sixth Edition """ def __init__(self, a4, a6, a1=0, a2=0, a3=0, modulus = 0): if modulus == 0: domain = QQ else: domain = FF(modulus) a1, a2, a3, a4, a6 = map(domain.convert, (a1, a2, a3, a4, a6)) self._domain = domain self.modulus = modulus # Calculate discriminant b2 = a1**2 + 4 * a2 b4 = 2 * a4 + a1 * a3 b6 = a3**2 + 4 * a6 b8 = a1**2 * a6 + 4 * a2 * a6 - a1 * a3 * a4 + a2 * a3**2 - a4**2 self._b2, self._b4, self._b6, self._b8 = b2, b4, b6, b8 self._discrim = -b2**2 * b8 - 8 * b4**3 - 27 * b6**2 + 9 * b2 * b4 * b6 self._a1 = a1 self._a2 = a2 self._a3 = a3 self._a4 = a4 self._a6 = a6 x, y, z = symbols('x y z') self.x, self.y, self.z = x, y, z self._eq = Eq(y**2*z + a1*x*y*z + a3*y*z**2, x**3 + a2*x**2*z + a4*x*z**2 + a6*z**3) if isinstance(self._domain, FiniteField): self._rank = 0 elif isinstance(self._domain, RationalField): self._rank = None def __call__(self, x, y, z=1): return EllipticCurvePoint(x, y, z, self) def __contains__(self, point): if is_sequence(point): if len(point) == 2: z1 = 1 else: z1 = point[2] x1, y1 = point[:2] elif isinstance(point, EllipticCurvePoint): x1, y1, z1 = point.x, point.y, point.z else: raise ValueError('Invalid point.') if self.characteristic == 0 and z1 == 0: return True return self._eq.subs({self.x: x1, self.y: y1, self.z: z1}) def __repr__(self): return 'E({}): {}'.format(self._domain, self._eq) def minimal(self): """ Return minimal Weierstrass equation. Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e1 = EllipticCurve(-10, -20, 0, -1, 1) >>> e1.minimal() E(QQ): Eq(y**2*z, x**3 - 13392*x*z**2 - 1080432*z**3) """ char = self.characteristic if char == 2: return self if char == 3: return EllipticCurve(self._b4/2, self._b6/4, a2=self._b2/4, modulus=self.modulus) c4 = self._b2**2 - 24*self._b4 c6 = -self._b2**3 + 36*self._b2*self._b4 - 216*self._b6 return EllipticCurve(-27*c4, -54*c6, modulus=self.modulus) def points(self): """ Return points of curve over Finite Field. Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e2 = EllipticCurve(1, 1, 1, 1, 1, modulus=5) >>> e2.points() {(0, 2), (1, 4), (2, 0), (2, 2), (3, 0), (3, 1), (4, 0)} """ char = self.characteristic all_pt = set() if char >= 1: for i in range(char): congruence_eq = ((self._eq.lhs - self._eq.rhs).subs({self.x: i, self.z: 1})) sol = polynomial_congruence(congruence_eq, char) for num in sol: all_pt.add((i, num)) return all_pt else: raise ValueError("Infinitely many points") def points_x(self, x): "Returns points on with curve where xcoordinate = x" pt = [] if self._domain == QQ: for y in solve(self._eq.subs(self.x, x)): pt.append((x, y)) congruence_eq = ((self._eq.lhs - self._eq.rhs).subs({self.x: x, self.z: 1})) for y in polynomial_congruence(congruence_eq, self.characteristic): pt.append((x, y)) return pt def torsion_points(self): """ Return torsion points of curve over Rational number. Return point objects those are finite order. According to Nagell-Lutz theorem, torsion point p(x, y) x and y are integers, either y = 0 or y**2 is divisor of discriminent. According to Mazur's theorem, there are at most 15 points in torsion collection. Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e2 = EllipticCurve(-43, 166) >>> sorted(e2.torsion_points()) [(-5, -16), (-5, 16), O, (3, -8), (3, 8), (11, -32), (11, 32)] """ if self.characteristic > 0: raise ValueError("No torsion point for Finite Field.") l = [EllipticCurvePoint.point_at_infinity(self)] for xx in solve(self._eq.subs({self.y: 0, self.z: 1})): if xx.is_rational: l.append(self(xx, 0)) for i in divisors(self.discriminant, generator=True): j = int(i**.5) if j**2 == i: for xx in solve(self._eq.subs({self.y: j, self.z: 1})): if not xx.is_rational: continue p = self(xx, j) if p.order() != oo: l.extend([p, -p]) return l @property def characteristic(self): """ Return domain characteristic. Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e2 = EllipticCurve(-43, 166) >>> e2.characteristic 0 """ return self._domain.characteristic() @property def discriminant(self): """ Return curve discriminant. Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e2 = EllipticCurve(0, 17) >>> e2.discriminant -124848 """ return int(self._discrim) @property def is_singular(self): """ Return True if curve discriminant is equal to zero. """ return self.discriminant == 0 @property def j_invariant(self): """ Return curve j-invariant. Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e1 = EllipticCurve(-2, 0, 0, 1, 1) >>> e1.j_invariant 1404928/389 """ c4 = self._b2**2 - 24*self._b4 return self._domain.to_sympy(c4**3 / self._discrim) @property def order(self): """ Number of points in Finite field. Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e2 = EllipticCurve(1, 0, modulus=19) >>> e2.order 19 """ if self.characteristic == 0: raise NotImplementedError("Still not implemented") return len(list(self.points())) @property def rank(self): """ Number of independent points of infinite order. For Finite field, it must be 0. """ if self._rank is not None: return self._rank raise NotImplementedError("Still not implemented") class EllipticCurvePoint: """ Point of Elliptic Curve Examples ======== >>> from sympy.ntheory.elliptic_curve import EllipticCurve >>> e1 = EllipticCurve(-17, 16) >>> p1 = e1(0, -4, 1) >>> p2 = e1(1, 0) >>> p1 + p2 (15, -56) >>> e3 = EllipticCurve(-1, 9) >>> e3(1, -3) * 3 (664/169, 17811/2197) >>> (e3(1, -3) * 3).order() oo >>> e2 = EllipticCurve(-2, 0, 0, 1, 1) >>> p = e2(-1,1) >>> q = e2(0, -1) >>> p+q (4, 8) >>> p-q (1, 0) >>> 3*p-5*q (328/361, -2800/6859) """ @staticmethod def point_at_infinity(curve): return EllipticCurvePoint(0, 1, 0, curve) def __init__(self, x, y, z, curve): dom = curve._domain.convert self.x = dom(x) self.y = dom(y) self.z = dom(z) self._curve = curve self._domain = self._curve._domain if not self._curve.__contains__(self): raise ValueError("The curve does not contain this point") def __add__(self, p): if self.z == 0: return p if p.z == 0: return self x1, y1 = self.x/self.z, self.y/self.z x2, y2 = p.x/p.z, p.y/p.z a1 = self._curve._a1 a2 = self._curve._a2 a3 = self._curve._a3 a4 = self._curve._a4 a6 = self._curve._a6 if x1 != x2: slope = (y1 - y2) / (x1 - x2) yint = (y1 * x2 - y2 * x1) / (x2 - x1) else: if (y1 + y2) == 0: return self.point_at_infinity(self._curve) slope = (3 * x1**2 + 2*a2*x1 + a4 - a1*y1) / (a1 * x1 + a3 + 2 * y1) yint = (-x1**3 + a4*x1 + 2*a6 - a3*y1) / (a1*x1 + a3 + 2*y1) x3 = slope**2 + a1*slope - a2 - x1 - x2 y3 = -(slope + a1) * x3 - yint - a3 return self._curve(x3, y3, 1) def __lt__(self, other): return (self.x, self.y, self.z) < (other.x, other.y, other.z) def __mul__(self, n): n = as_int(n) r = self.point_at_infinity(self._curve) if n == 0: return r if n < 0: return -self * -n p = self while n: if n & 1: r = r + p n >>= 1 p = p + p return r def __rmul__(self, n): return self * n def __neg__(self): return EllipticCurvePoint(self.x, -self.y - self._curve._a1*self.x - self._curve._a3, self.z, self._curve) def __repr__(self): if self.z == 0: return 'O' dom = self._curve._domain try: return '({}, {})'.format(dom.to_sympy(self.x), dom.to_sympy(self.y)) except TypeError: pass return '({}, {})'.format(self.x, self.y) def __sub__(self, other): return self.__add__(-other) def order(self): """ Return point order n where nP = 0. """ if self.z == 0: return 1 if self.y == 0: # P = -P return 2 p = self * 2 if p.y == -self.y: # 2P = -P return 3 i = 2 if self._domain != QQ: while int(p.x) == p.x and int(p.y) == p.y: p = self + p i += 1 if p.z == 0: return i return oo while p.x.numerator == p.x and p.y.numerator == p.y: p = self + p i += 1 if i > 12: return oo if p.z == 0: return i return oo sympy-sympy-1.9/sympy/ntheory/factor_.py000066400000000000000000002230601412543434000205660ustar00rootroot00000000000000""" Integer factorization """ from collections import defaultdict import random import math from sympy.core import sympify from sympy.core.compatibility import as_int, SYMPY_INTS from sympy.core.containers import Dict from sympy.core.evalf import bitcount from sympy.core.expr import Expr from sympy.core.function import Function from sympy.core.logic import fuzzy_and from sympy.core.mul import Mul, prod from sympy.core.numbers import igcd, ilcm, Rational, Integer from sympy.core.power import integer_nthroot, Pow from sympy.core.singleton import S from .primetest import isprime from .generate import sieve, primerange, nextprime from .digits import digits from sympy.utilities.misc import filldedent from .ecm import _ecm_one_factor # Note: This list should be updated whenever new Mersenne primes are found. # Refer: https://www.mersenne.org/ MERSENNE_PRIME_EXPONENTS = (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, 20996011, 24036583, 25964951, 30402457, 32582657, 37156667, 42643801, 43112609, 57885161, 74207281, 77232917, 82589933) # compute more when needed for i in Mersenne prime exponents PERFECT = [6] # 2**(i-1)*(2**i-1) MERSENNES = [3] # 2**i - 1 def _ismersenneprime(n): global MERSENNES j = len(MERSENNES) while n > MERSENNES[-1] and j < len(MERSENNE_PRIME_EXPONENTS): # conservatively grow the list MERSENNES.append(2**MERSENNE_PRIME_EXPONENTS[j] - 1) j += 1 return n in MERSENNES def _isperfect(n): global PERFECT if n % 2 == 0: j = len(PERFECT) while n > PERFECT[-1] and j < len(MERSENNE_PRIME_EXPONENTS): # conservatively grow the list t = 2**(MERSENNE_PRIME_EXPONENTS[j] - 1) PERFECT.append(t*(2*t - 1)) j += 1 return n in PERFECT small_trailing = [0] * 256 for j in range(1,8): small_trailing[1<>> from sympy.ntheory.factor_ import smoothness >>> smoothness(2**7*3**2) (3, 128) >>> smoothness(2**4*13) (13, 16) >>> smoothness(2) (2, 2) See Also ======== factorint, smoothness_p """ if n == 1: return (1, 1) # not prime, but otherwise this causes headaches facs = factorint(n) return max(facs), max(m**facs[m] for m in facs) def smoothness_p(n, m=-1, power=0, visual=None): """ Return a list of [m, (p, (M, sm(p + m), psm(p + m)))...] where: 1. p**M is the base-p divisor of n 2. sm(p + m) is the smoothness of p + m (m = -1 by default) 3. psm(p + m) is the power smoothness of p + m The list is sorted according to smoothness (default) or by power smoothness if power=1. The smoothness of the numbers to the left (m = -1) or right (m = 1) of a factor govern the results that are obtained from the p +/- 1 type factoring methods. >>> from sympy.ntheory.factor_ import smoothness_p, factorint >>> smoothness_p(10431, m=1) (1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))]) >>> smoothness_p(10431) (-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))]) >>> smoothness_p(10431, power=1) (-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))]) If visual=True then an annotated string will be returned: >>> print(smoothness_p(21477639576571, visual=1)) p**i=4410317**1 has p-1 B=1787, B-pow=1787 p**i=4869863**1 has p-1 B=2434931, B-pow=2434931 This string can also be generated directly from a factorization dictionary and vice versa: >>> factorint(17*9) {3: 2, 17: 1} >>> smoothness_p(_) 'p**i=3**2 has p-1 B=2, B-pow=2\\np**i=17**1 has p-1 B=2, B-pow=16' >>> smoothness_p(_) {3: 2, 17: 1} The table of the output logic is: ====== ====== ======= ======= | Visual ------ ---------------------- Input True False other ====== ====== ======= ======= dict str tuple str str str tuple dict tuple str tuple str n str tuple tuple mul str tuple tuple ====== ====== ======= ======= See Also ======== factorint, smoothness """ from sympy.utilities import flatten # visual must be True, False or other (stored as None) if visual in (1, 0): visual = bool(visual) elif visual not in (True, False): visual = None if isinstance(n, str): if visual: return n d = {} for li in n.splitlines(): k, v = [int(i) for i in li.split('has')[0].split('=')[1].split('**')] d[k] = v if visual is not True and visual is not False: return d return smoothness_p(d, visual=False) elif type(n) is not tuple: facs = factorint(n, visual=False) if power: k = -1 else: k = 1 if type(n) is not tuple: rv = (m, sorted([(f, tuple([M] + list(smoothness(f + m)))) for f, M in [i for i in facs.items()]], key=lambda x: (x[1][k], x[0]))) else: rv = n if visual is False or (visual is not True) and (type(n) in [int, Mul]): return rv lines = [] for dat in rv[1]: dat = flatten(dat) dat.insert(2, m) lines.append('p**i=%i**%i has p%+i B=%i, B-pow=%i' % tuple(dat)) return '\n'.join(lines) def trailing(n): """Count the number of trailing zero digits in the binary representation of n, i.e. determine the largest power of 2 that divides n. Examples ======== >>> from sympy import trailing >>> trailing(128) 7 >>> trailing(63) 0 """ n = abs(int(n)) if not n: return 0 low_byte = n & 0xff if low_byte: return small_trailing[low_byte] # 2**m is quick for z up through 2**30 z = bitcount(n) - 1 if isinstance(z, SYMPY_INTS): if n == 1 << z: return z if z < 300: # fixed 8-byte reduction t = 8 n >>= 8 while not n & 0xff: n >>= 8 t += 8 return t + small_trailing[n & 0xff] # binary reduction important when there might be a large # number of trailing 0s t = 0 p = 8 while not n & 1: while not n & ((1 << p) - 1): n >>= p t += p p *= 2 p //= 2 return t def multiplicity(p, n): """ Find the greatest integer m such that p**m divides n. Examples ======== >>> from sympy.ntheory import multiplicity >>> from sympy.core.numbers import Rational as R >>> [multiplicity(5, n) for n in [8, 5, 25, 125, 250]] [0, 1, 2, 3, 3] >>> multiplicity(3, R(1, 9)) -2 Note: when checking for the multiplicity of a number in a large factorial it is most efficient to send it as an unevaluated factorial or to call ``multiplicity_in_factorial`` directly: >>> from sympy.ntheory import multiplicity_in_factorial >>> from sympy import factorial >>> p = factorial(25) >>> n = 2**100 >>> nfac = factorial(n, evaluate=False) >>> multiplicity(p, nfac) 52818775009509558395695966887 >>> _ == multiplicity_in_factorial(p, n) True """ from sympy.functions.combinatorial.factorials import factorial try: p, n = as_int(p), as_int(n) except ValueError: if all(isinstance(i, (SYMPY_INTS, Rational)) for i in (p, n)): p = Rational(p) n = Rational(n) if p.q == 1: if n.p == 1: return -multiplicity(p.p, n.q) return multiplicity(p.p, n.p) - multiplicity(p.p, n.q) elif p.p == 1: return multiplicity(p.q, n.q) else: like = min( multiplicity(p.p, n.p), multiplicity(p.q, n.q)) cross = min( multiplicity(p.q, n.p), multiplicity(p.p, n.q)) return like - cross elif (isinstance(p, (SYMPY_INTS, Integer)) and isinstance(n, factorial) and isinstance(n.args[0], Integer) and n.args[0] >= 0): return multiplicity_in_factorial(p, n.args[0]) raise ValueError('expecting ints or fractions, got %s and %s' % (p, n)) if n == 0: raise ValueError('no such integer exists: multiplicity of %s is not-defined' %(n)) if p == 2: return trailing(n) if p < 2: raise ValueError('p must be an integer, 2 or larger, but got %s' % p) if p == n: return 1 m = 0 n, rem = divmod(n, p) while not rem: m += 1 if m > 5: # The multiplicity could be very large. Better # to increment in powers of two e = 2 while 1: ppow = p**e if ppow < n: nnew, rem = divmod(n, ppow) if not rem: m += e e *= 2 n = nnew continue return m + multiplicity(p, n) n, rem = divmod(n, p) return m def multiplicity_in_factorial(p, n): """return the largest integer ``m`` such that ``p**m`` divides ``n!`` without calculating the factorial of ``n``. Examples ======== >>> from sympy.ntheory import multiplicity_in_factorial >>> from sympy import factorial >>> multiplicity_in_factorial(2, 3) 1 An instructive use of this is to tell how many trailing zeros a given factorial has. For example, there are 6 in 25!: >>> factorial(25) 15511210043330985984000000 >>> multiplicity_in_factorial(10, 25) 6 For large factorials, it is much faster/feasible to use this function rather than computing the actual factorial: >>> multiplicity_in_factorial(factorial(25), 2**100) 52818775009509558395695966887 """ p, n = as_int(p), as_int(n) if p <= 0: raise ValueError('expecting positive integer got %s' % p ) if n < 0: raise ValueError('expecting non-negative integer got %s' % n ) factors = factorint(p) # keep only the largest of a given multiplicity since those # of a given multiplicity will be goverened by the behavior # of the largest factor test = defaultdict(int) for k, v in factors.items(): test[v] = max(k, test[v]) keep = set(test.values()) # remove others from factors for k in list(factors.keys()): if k not in keep: factors.pop(k) mp = S.Infinity for i in factors: # multiplicity of i in n! is mi = (n - (sum(digits(n, i)) - i))//(i - 1) # multiplicity of p in n! depends on multiplicity # of prime `i` in p, so we floor divide by factors[i] # and keep it if smaller than the multiplicity of p # seen so far mp = min(mp, mi//factors[i]) return mp def perfect_power(n, candidates=None, big=True, factor=True): """ Return ``(b, e)`` such that ``n`` == ``b**e`` if ``n`` is a perfect power with ``e > 1``, else ``False``. A ValueError is raised if ``n`` is not an integer or is not positive. By default, the base is recursively decomposed and the exponents collected so the largest possible ``e`` is sought. If ``big=False`` then the smallest possible ``e`` (thus prime) will be chosen. If ``factor=True`` then simultaneous factorization of ``n`` is attempted since finding a factor indicates the only possible root for ``n``. This is True by default since only a few small factors will be tested in the course of searching for the perfect power. The use of ``candidates`` is primarily for internal use; if provided, False will be returned if ``n`` cannot be written as a power with one of the candidates as an exponent and factoring (beyond testing for a factor of 2) will not be attempted. Examples ======== >>> from sympy import perfect_power >>> perfect_power(16) (2, 4) >>> perfect_power(16, big=False) (4, 2) Notes ===== To know whether an integer is a perfect power of 2 use >>> is2pow = lambda n: bool(n and not n & (n - 1)) >>> [(i, is2pow(i)) for i in range(5)] [(0, False), (1, True), (2, True), (3, False), (4, True)] It is not necessary to provide ``candidates``. When provided it will be assumed that they are ints. The first one that is larger than the computed maximum possible exponent will signal failure for the routine. >>> perfect_power(3**8, [9]) False >>> perfect_power(3**8, [2, 4, 8]) (3, 8) >>> perfect_power(3**8, [4, 8], big=False) (9, 4) See Also ======== sympy.core.power.integer_nthroot sympy.ntheory.primetest.is_square """ from sympy.core.power import integer_nthroot n = as_int(n) if n < 3: if n < 1: raise ValueError('expecting positive n') return False logn = math.log(n, 2) max_possible = int(logn) + 2 # only check values less than this not_square = n % 10 in [2, 3, 7, 8] # squares cannot end in 2, 3, 7, 8 min_possible = 2 + not_square if not candidates: candidates = primerange(min_possible, max_possible) else: candidates = sorted([i for i in candidates if min_possible <= i < max_possible]) if n%2 == 0: e = trailing(n) candidates = [i for i in candidates if e%i == 0] if big: candidates = reversed(candidates) for e in candidates: r, ok = integer_nthroot(n, e) if ok: return (r, e) return False def _factors(): rv = 2 + n % 2 while True: yield rv rv = nextprime(rv) for fac, e in zip(_factors(), candidates): # see if there is a factor present if factor and n % fac == 0: # find what the potential power is if fac == 2: e = trailing(n) else: e = multiplicity(fac, n) # if it's a trivial power we are done if e == 1: return False # maybe the e-th root of n is exact r, exact = integer_nthroot(n, e) if not exact: # Having a factor, we know that e is the maximal # possible value for a root of n. # If n = fac**e*m can be written as a perfect # power then see if m can be written as r**E where # gcd(e, E) != 1 so n = (fac**(e//E)*r)**E m = n//fac**e rE = perfect_power(m, candidates=divisors(e, generator=True)) if not rE: return False else: r, E = rE r, e = fac**(e//E)*r, E if not big: e0 = primefactors(e) if e0[0] != e: r, e = r**(e//e0[0]), e0[0] return r, e # Weed out downright impossible candidates if logn/e < 40: b = 2.0**(logn/e) if abs(int(b + 0.5) - b) > 0.01: continue # now see if the plausible e makes a perfect power r, exact = integer_nthroot(n, e) if exact: if big: m = perfect_power(r, big=big, factor=factor) if m: r, e = m[0], e*m[1] return int(r), e return False def pollard_rho(n, s=2, a=1, retries=5, seed=1234, max_steps=None, F=None): r""" Use Pollard's rho method to try to extract a nontrivial factor of ``n``. The returned factor may be a composite number. If no factor is found, ``None`` is returned. The algorithm generates pseudo-random values of x with a generator function, replacing x with F(x). If F is not supplied then the function x**2 + ``a`` is used. The first value supplied to F(x) is ``s``. Upon failure (if ``retries`` is > 0) a new ``a`` and ``s`` will be supplied; the ``a`` will be ignored if F was supplied. The sequence of numbers generated by such functions generally have a a lead-up to some number and then loop around back to that number and begin to repeat the sequence, e.g. 1, 2, 3, 4, 5, 3, 4, 5 -- this leader and loop look a bit like the Greek letter rho, and thus the name, 'rho'. For a given function, very different leader-loop values can be obtained so it is a good idea to allow for retries: >>> from sympy.ntheory.generate import cycle_length >>> n = 16843009 >>> F = lambda x:(2048*pow(x, 2, n) + 32767) % n >>> for s in range(5): ... print('loop length = %4i; leader length = %3i' % next(cycle_length(F, s))) ... loop length = 2489; leader length = 42 loop length = 78; leader length = 120 loop length = 1482; leader length = 99 loop length = 1482; leader length = 285 loop length = 1482; leader length = 100 Here is an explicit example where there is a two element leadup to a sequence of 3 numbers (11, 14, 4) that then repeat: >>> x=2 >>> for i in range(9): ... x=(x**2+12)%17 ... print(x) ... 16 13 11 14 4 11 14 4 11 >>> next(cycle_length(lambda x: (x**2+12)%17, 2)) (3, 2) >>> list(cycle_length(lambda x: (x**2+12)%17, 2, values=True)) [16, 13, 11, 14, 4] Instead of checking the differences of all generated values for a gcd with n, only the kth and 2*kth numbers are checked, e.g. 1st and 2nd, 2nd and 4th, 3rd and 6th until it has been detected that the loop has been traversed. Loops may be many thousands of steps long before rho finds a factor or reports failure. If ``max_steps`` is specified, the iteration is cancelled with a failure after the specified number of steps. Examples ======== >>> from sympy import pollard_rho >>> n=16843009 >>> F=lambda x:(2048*pow(x,2,n) + 32767) % n >>> pollard_rho(n, F=F) 257 Use the default setting with a bad value of ``a`` and no retries: >>> pollard_rho(n, a=n-2, retries=0) If retries is > 0 then perhaps the problem will correct itself when new values are generated for a: >>> pollard_rho(n, a=n-2, retries=1) 257 References ========== .. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers: A Computational Perspective", Springer, 2nd edition, 229-231 """ n = int(n) if n < 5: raise ValueError('pollard_rho should receive n > 4') prng = random.Random(seed + retries) V = s for i in range(retries + 1): U = V if not F: F = lambda x: (pow(x, 2, n) + a) % n j = 0 while 1: if max_steps and (j > max_steps): break j += 1 U = F(U) V = F(F(V)) # V is 2x further along than U g = igcd(U - V, n) if g == 1: continue if g == n: break return int(g) V = prng.randint(0, n - 1) a = prng.randint(1, n - 3) # for x**2 + a, a%n should not be 0 or -2 F = None return None def pollard_pm1(n, B=10, a=2, retries=0, seed=1234): """ Use Pollard's p-1 method to try to extract a nontrivial factor of ``n``. Either a divisor (perhaps composite) or ``None`` is returned. The value of ``a`` is the base that is used in the test gcd(a**M - 1, n). The default is 2. If ``retries`` > 0 then if no factor is found after the first attempt, a new ``a`` will be generated randomly (using the ``seed``) and the process repeated. Note: the value of M is lcm(1..B) = reduce(ilcm, range(2, B + 1)). A search is made for factors next to even numbers having a power smoothness less than ``B``. Choosing a larger B increases the likelihood of finding a larger factor but takes longer. Whether a factor of n is found or not depends on ``a`` and the power smoothness of the even number just less than the factor p (hence the name p - 1). Although some discussion of what constitutes a good ``a`` some descriptions are hard to interpret. At the modular.math site referenced below it is stated that if gcd(a**M - 1, n) = N then a**M % q**r is 1 for every prime power divisor of N. But consider the following: >>> from sympy.ntheory.factor_ import smoothness_p, pollard_pm1 >>> n=257*1009 >>> smoothness_p(n) (-1, [(257, (1, 2, 256)), (1009, (1, 7, 16))]) So we should (and can) find a root with B=16: >>> pollard_pm1(n, B=16, a=3) 1009 If we attempt to increase B to 256 we find that it doesn't work: >>> pollard_pm1(n, B=256) >>> But if the value of ``a`` is changed we find that only multiples of 257 work, e.g.: >>> pollard_pm1(n, B=256, a=257) 1009 Checking different ``a`` values shows that all the ones that didn't work had a gcd value not equal to ``n`` but equal to one of the factors: >>> from sympy.core.numbers import ilcm, igcd >>> from sympy import factorint, Pow >>> M = 1 >>> for i in range(2, 256): ... M = ilcm(M, i) ... >>> set([igcd(pow(a, M, n) - 1, n) for a in range(2, 256) if ... igcd(pow(a, M, n) - 1, n) != n]) {1009} But does aM % d for every divisor of n give 1? >>> aM = pow(255, M, n) >>> [(d, aM%Pow(*d.args)) for d in factorint(n, visual=True).args] [(257**1, 1), (1009**1, 1)] No, only one of them. So perhaps the principle is that a root will be found for a given value of B provided that: 1) the power smoothness of the p - 1 value next to the root does not exceed B 2) a**M % p != 1 for any of the divisors of n. By trying more than one ``a`` it is possible that one of them will yield a factor. Examples ======== With the default smoothness bound, this number can't be cracked: >>> from sympy.ntheory import pollard_pm1 >>> pollard_pm1(21477639576571) Increasing the smoothness bound helps: >>> pollard_pm1(21477639576571, B=2000) 4410317 Looking at the smoothness of the factors of this number we find: >>> from sympy.ntheory.factor_ import smoothness_p, factorint >>> print(smoothness_p(21477639576571, visual=1)) p**i=4410317**1 has p-1 B=1787, B-pow=1787 p**i=4869863**1 has p-1 B=2434931, B-pow=2434931 The B and B-pow are the same for the p - 1 factorizations of the divisors because those factorizations had a very large prime factor: >>> factorint(4410317 - 1) {2: 2, 617: 1, 1787: 1} >>> factorint(4869863-1) {2: 1, 2434931: 1} Note that until B reaches the B-pow value of 1787, the number is not cracked; >>> pollard_pm1(21477639576571, B=1786) >>> pollard_pm1(21477639576571, B=1787) 4410317 The B value has to do with the factors of the number next to the divisor, not the divisors themselves. A worst case scenario is that the number next to the factor p has a large prime divisisor or is a perfect power. If these conditions apply then the power-smoothness will be about p/2 or p. The more realistic is that there will be a large prime factor next to p requiring a B value on the order of p/2. Although primes may have been searched for up to this level, the p/2 is a factor of p - 1, something that we don't know. The modular.math reference below states that 15% of numbers in the range of 10**15 to 15**15 + 10**4 are 10**6 power smooth so a B of 10**6 will fail 85% of the time in that range. From 10**8 to 10**8 + 10**3 the percentages are nearly reversed...but in that range the simple trial division is quite fast. References ========== .. [1] Richard Crandall & Carl Pomerance (2005), "Prime Numbers: A Computational Perspective", Springer, 2nd edition, 236-238 .. [2] http://modular.math.washington.edu/edu/2007/spring/ent/ent-html/node81.html .. [3] https://www.cs.toronto.edu/~yuvalf/Factorization.pdf """ n = int(n) if n < 4 or B < 3: raise ValueError('pollard_pm1 should receive n > 3 and B > 2') prng = random.Random(seed + B) # computing a**lcm(1,2,3,..B) % n for B > 2 # it looks weird, but it's right: primes run [2, B] # and the answer's not right until the loop is done. for i in range(retries + 1): aM = a for p in sieve.primerange(2, B + 1): e = int(math.log(B, p)) aM = pow(aM, pow(p, e), n) g = igcd(aM - 1, n) if 1 < g < n: return int(g) # get a new a: # since the exponent, lcm(1..B), is even, if we allow 'a' to be 'n-1' # then (n - 1)**even % n will be 1 which will give a g of 0 and 1 will # give a zero, too, so we set the range as [2, n-2]. Some references # say 'a' should be coprime to n, but either will detect factors. a = prng.randint(2, n - 2) def _trial(factors, n, candidates, verbose=False): """ Helper function for integer factorization. Trial factors ``n` against all integers given in the sequence ``candidates`` and updates the dict ``factors`` in-place. Returns the reduced value of ``n`` and a flag indicating whether any factors were found. """ if verbose: factors0 = list(factors.keys()) nfactors = len(factors) for d in candidates: if n % d == 0: m = multiplicity(d, n) n //= d**m factors[d] = m if verbose: for k in sorted(set(factors).difference(set(factors0))): print(factor_msg % (k, factors[k])) return int(n), len(factors) != nfactors def _check_termination(factors, n, limitp1, use_trial, use_rho, use_pm1, verbose): """ Helper function for integer factorization. Checks if ``n`` is a prime or a perfect power, and in those cases updates the factorization and raises ``StopIteration``. """ if verbose: print('Check for termination') # since we've already been factoring there is no need to do # simultaneous factoring with the power check p = perfect_power(n, factor=False) if p is not False: base, exp = p if limitp1: limit = limitp1 - 1 else: limit = limitp1 facs = factorint(base, limit, use_trial, use_rho, use_pm1, verbose=False) for b, e in facs.items(): if verbose: print(factor_msg % (b, e)) factors[b] = exp*e raise StopIteration if isprime(n): factors[int(n)] = 1 raise StopIteration if n == 1: raise StopIteration trial_int_msg = "Trial division with ints [%i ... %i] and fail_max=%i" trial_msg = "Trial division with primes [%i ... %i]" rho_msg = "Pollard's rho with retries %i, max_steps %i and seed %i" pm1_msg = "Pollard's p-1 with smoothness bound %i and seed %i" ecm_msg = "Elliptic Curve with B1 bound %i, B2 bound %i, num_curves %i" factor_msg = '\t%i ** %i' fermat_msg = 'Close factors satisying Fermat condition found.' complete_msg = 'Factorization is complete.' def _factorint_small(factors, n, limit, fail_max): """ Return the value of n and either a 0 (indicating that factorization up to the limit was complete) or else the next near-prime that would have been tested. Factoring stops if there are fail_max unsuccessful tests in a row. If factors of n were found they will be in the factors dictionary as {factor: multiplicity} and the returned value of n will have had those factors removed. The factors dictionary is modified in-place. """ def done(n, d): """return n, d if the sqrt(n) wasn't reached yet, else n, 0 indicating that factoring is done. """ if d*d <= n: return n, d return n, 0 d = 2 m = trailing(n) if m: factors[d] = m n >>= m d = 3 if limit < d: if n > 1: factors[n] = 1 return done(n, d) # reduce m = 0 while n % d == 0: n //= d m += 1 if m == 20: mm = multiplicity(d, n) m += mm n //= d**mm break if m: factors[d] = m # when d*d exceeds maxx or n we are done; if limit**2 is greater # than n then maxx is set to zero so the value of n will flag the finish if limit*limit > n: maxx = 0 else: maxx = limit*limit dd = maxx or n d = 5 fails = 0 while fails < fail_max: if d*d > dd: break # d = 6*i - 1 # reduce m = 0 while n % d == 0: n //= d m += 1 if m == 20: mm = multiplicity(d, n) m += mm n //= d**mm break if m: factors[d] = m dd = maxx or n fails = 0 else: fails += 1 d += 2 if d*d > dd: break # d = 6*i - 1 # reduce m = 0 while n % d == 0: n //= d m += 1 if m == 20: mm = multiplicity(d, n) m += mm n //= d**mm break if m: factors[d] = m dd = maxx or n fails = 0 else: fails += 1 # d = 6*(i + 1) - 1 d += 4 return done(n, d) def factorint(n, limit=None, use_trial=True, use_rho=True, use_pm1=True, use_ecm=True, verbose=False, visual=None, multiple=False): r""" Given a positive integer ``n``, ``factorint(n)`` returns a dict containing the prime factors of ``n`` as keys and their respective multiplicities as values. For example: >>> from sympy.ntheory import factorint >>> factorint(2000) # 2000 = (2**4) * (5**3) {2: 4, 5: 3} >>> factorint(65537) # This number is prime {65537: 1} For input less than 2, factorint behaves as follows: - ``factorint(1)`` returns the empty factorization, ``{}`` - ``factorint(0)`` returns ``{0:1}`` - ``factorint(-n)`` adds ``-1:1`` to the factors and then factors ``n`` Partial Factorization: If ``limit`` (> 3) is specified, the search is stopped after performing trial division up to (and including) the limit (or taking a corresponding number of rho/p-1 steps). This is useful if one has a large number and only is interested in finding small factors (if any). Note that setting a limit does not prevent larger factors from being found early; it simply means that the largest factor may be composite. Since checking for perfect power is relatively cheap, it is done regardless of the limit setting. This number, for example, has two small factors and a huge semi-prime factor that cannot be reduced easily: >>> from sympy.ntheory import isprime >>> a = 1407633717262338957430697921446883 >>> f = factorint(a, limit=10000) >>> f == {991: 1, int(202916782076162456022877024859): 1, 7: 1} True >>> isprime(max(f)) False This number has a small factor and a residual perfect power whose base is greater than the limit: >>> factorint(3*101**7, limit=5) {3: 1, 101: 7} List of Factors: If ``multiple`` is set to ``True`` then a list containing the prime factors including multiplicities is returned. >>> factorint(24, multiple=True) [2, 2, 2, 3] Visual Factorization: If ``visual`` is set to ``True``, then it will return a visual factorization of the integer. For example: >>> from sympy import pprint >>> pprint(factorint(4200, visual=True)) 3 1 2 1 2 *3 *5 *7 Note that this is achieved by using the evaluate=False flag in Mul and Pow. If you do other manipulations with an expression where evaluate=False, it may evaluate. Therefore, you should use the visual option only for visualization, and use the normal dictionary returned by visual=False if you want to perform operations on the factors. You can easily switch between the two forms by sending them back to factorint: >>> from sympy import Mul >>> regular = factorint(1764); regular {2: 2, 3: 2, 7: 2} >>> pprint(factorint(regular)) 2 2 2 2 *3 *7 >>> visual = factorint(1764, visual=True); pprint(visual) 2 2 2 2 *3 *7 >>> print(factorint(visual)) {2: 2, 3: 2, 7: 2} If you want to send a number to be factored in a partially factored form you can do so with a dictionary or unevaluated expression: >>> factorint(factorint({4: 2, 12: 3})) # twice to toggle to dict form {2: 10, 3: 3} >>> factorint(Mul(4, 12, evaluate=False)) {2: 4, 3: 1} The table of the output logic is: ====== ====== ======= ======= Visual ------ ---------------------- Input True False other ====== ====== ======= ======= dict mul dict mul n mul dict dict mul mul dict dict ====== ====== ======= ======= Notes ===== Algorithm: The function switches between multiple algorithms. Trial division quickly finds small factors (of the order 1-5 digits), and finds all large factors if given enough time. The Pollard rho and p-1 algorithms are used to find large factors ahead of time; they will often find factors of the order of 10 digits within a few seconds: >>> factors = factorint(12345678910111213141516) >>> for base, exp in sorted(factors.items()): ... print('%s %s' % (base, exp)) ... 2 2 2507191691 1 1231026625769 1 Any of these methods can optionally be disabled with the following boolean parameters: - ``use_trial``: Toggle use of trial division - ``use_rho``: Toggle use of Pollard's rho method - ``use_pm1``: Toggle use of Pollard's p-1 method ``factorint`` also periodically checks if the remaining part is a prime number or a perfect power, and in those cases stops. For unevaluated factorial, it uses Legendre's formula(theorem). If ``verbose`` is set to ``True``, detailed progress is printed. See Also ======== smoothness, smoothness_p, divisors """ if isinstance(n, Dict): n = dict(n) if multiple: fac = factorint(n, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose, visual=False, multiple=False) factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p]) for p in sorted(fac)), []) return factorlist factordict = {} if visual and not isinstance(n, Mul) and not isinstance(n, dict): factordict = factorint(n, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose, visual=False) elif isinstance(n, Mul): factordict = {int(k): int(v) for k, v in n.as_powers_dict().items()} elif isinstance(n, dict): factordict = n if factordict and (isinstance(n, Mul) or isinstance(n, dict)): # check it for key in list(factordict.keys()): if isprime(key): continue e = factordict.pop(key) d = factorint(key, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose, visual=False) for k, v in d.items(): if k in factordict: factordict[k] += v*e else: factordict[k] = v*e if visual or (type(n) is dict and visual is not True and visual is not False): if factordict == {}: return S.One if -1 in factordict: factordict.pop(-1) args = [S.NegativeOne] else: args = [] args.extend([Pow(*i, evaluate=False) for i in sorted(factordict.items())]) return Mul(*args, evaluate=False) elif isinstance(n, dict) or isinstance(n, Mul): return factordict assert use_trial or use_rho or use_pm1 or use_ecm from sympy.functions.combinatorial.factorials import factorial if isinstance(n, factorial): x = as_int(n.args[0]) if x >= 20: factors = {} m = 2 # to initialize the if condition below for p in sieve.primerange(2, x + 1): if m > 1: m, q = 0, x // p while q != 0: m += q q //= p factors[p] = m if factors and verbose: for k in sorted(factors): print(factor_msg % (k, factors[k])) if verbose: print(complete_msg) return factors else: # if n < 20!, direct computation is faster # since it uses a lookup table n = n.func(x) n = as_int(n) if limit: limit = int(limit) use_ecm = False # special cases if n < 0: factors = factorint( -n, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose, visual=False) factors[-1] = 1 return factors if limit and limit < 2: if n == 1: return {} return {n: 1} elif n < 10: # doing this we are assured of getting a limit > 2 # when we have to compute it later return [{0: 1}, {}, {2: 1}, {3: 1}, {2: 2}, {5: 1}, {2: 1, 3: 1}, {7: 1}, {2: 3}, {3: 2}][n] factors = {} # do simplistic factorization if verbose: sn = str(n) if len(sn) > 50: print('Factoring %s' % sn[:5] + \ '..(%i other digits)..' % (len(sn) - 10) + sn[-5:]) else: print('Factoring', n) if use_trial: # this is the preliminary factorization for small factors small = 2**15 fail_max = 600 small = min(small, limit or small) if verbose: print(trial_int_msg % (2, small, fail_max)) n, next_p = _factorint_small(factors, n, small, fail_max) else: next_p = 2 if factors and verbose: for k in sorted(factors): print(factor_msg % (k, factors[k])) if next_p == 0: if n > 1: factors[int(n)] = 1 if verbose: print(complete_msg) return factors # continue with more advanced factorization methods # first check if the simplistic run didn't finish # because of the limit and check for a perfect # power before exiting try: if limit and next_p > limit: if verbose: print('Exceeded limit:', limit) _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, verbose) if n > 1: factors[int(n)] = 1 return factors else: # Before quitting (or continuing on)... # ...do a Fermat test since it's so easy and we need the # square root anyway. Finding 2 factors is easy if they are # "close enough." This is the big root equivalent of dividing by # 2, 3, 5. sqrt_n = integer_nthroot(n, 2)[0] a = sqrt_n + 1 a2 = a**2 b2 = a2 - n for i in range(3): b, fermat = integer_nthroot(b2, 2) if fermat: break b2 += 2*a + 1 # equiv to (a + 1)**2 - n a += 1 if fermat: if verbose: print(fermat_msg) if limit: limit -= 1 for r in [a - b, a + b]: facs = factorint(r, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose) for k, v in facs.items(): factors[k] = factors.get(k, 0) + v raise StopIteration # ...see if factorization can be terminated _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, verbose) except StopIteration: if verbose: print(complete_msg) return factors # these are the limits for trial division which will # be attempted in parallel with pollard methods low, high = next_p, 2*next_p limit = limit or sqrt_n # add 1 to make sure limit is reached in primerange calls limit += 1 iteration = 0 while 1: try: high_ = high if limit < high_: high_ = limit # Trial division if use_trial: if verbose: print(trial_msg % (low, high_)) ps = sieve.primerange(low, high_) n, found_trial = _trial(factors, n, ps, verbose) if found_trial: _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, verbose) else: found_trial = False if high > limit: if verbose: print('Exceeded limit:', limit) if n > 1: factors[int(n)] = 1 raise StopIteration # Only used advanced methods when no small factors were found if not found_trial: if (use_pm1 or use_rho): high_root = max(int(math.log(high_**0.7)), low, 3) # Pollard p-1 if use_pm1: if verbose: print(pm1_msg % (high_root, high_)) c = pollard_pm1(n, B=high_root, seed=high_) if c: # factor it and let _trial do the update ps = factorint(c, limit=limit - 1, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, use_ecm=use_ecm, verbose=verbose) n, _ = _trial(factors, n, ps, verbose=False) _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, verbose) # Pollard rho if use_rho: max_steps = high_root if verbose: print(rho_msg % (1, max_steps, high_)) c = pollard_rho(n, retries=1, max_steps=max_steps, seed=high_) if c: # factor it and let _trial do the update ps = factorint(c, limit=limit - 1, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, use_ecm=use_ecm, verbose=verbose) n, _ = _trial(factors, n, ps, verbose=False) _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, verbose) except StopIteration: if verbose: print(complete_msg) return factors #Use subexponential algorithms if use_ecm #Use pollard algorithms for finding small factors for 3 iterations #if after small factors the number of digits of n is >= 20 then use ecm iteration += 1 if use_ecm and iteration >= 3 and len(str(n)) >= 25: break low, high = high, high*2 B1 = 10000 B2 = 100*B1 num_curves = 50 while(1): if verbose: print(ecm_msg % (B1, B2, num_curves)) while(1): try: factor = _ecm_one_factor(n, B1, B2, num_curves) ps = factorint(factor, limit=limit - 1, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, use_ecm=use_ecm, verbose=verbose) n, _ = _trial(factors, n, ps, verbose=False) _check_termination(factors, n, limit, use_trial, use_rho, use_pm1, verbose) except ValueError: break except StopIteration: if verbose: print(complete_msg) return factors B1 *= 5 B2 = 100*B1 num_curves *= 4 def factorrat(rat, limit=None, use_trial=True, use_rho=True, use_pm1=True, verbose=False, visual=None, multiple=False): r""" Given a Rational ``r``, ``factorrat(r)`` returns a dict containing the prime factors of ``r`` as keys and their respective multiplicities as values. For example: >>> from sympy.ntheory import factorrat >>> from sympy.core.symbol import S >>> factorrat(S(8)/9) # 8/9 = (2**3) * (3**-2) {2: 3, 3: -2} >>> factorrat(S(-1)/987) # -1/789 = -1 * (3**-1) * (7**-1) * (47**-1) {-1: 1, 3: -1, 7: -1, 47: -1} Please see the docstring for ``factorint`` for detailed explanations and examples of the following keywords: - ``limit``: Integer limit up to which trial division is done - ``use_trial``: Toggle use of trial division - ``use_rho``: Toggle use of Pollard's rho method - ``use_pm1``: Toggle use of Pollard's p-1 method - ``verbose``: Toggle detailed printing of progress - ``multiple``: Toggle returning a list of factors or dict - ``visual``: Toggle product form of output """ from collections import defaultdict if multiple: fac = factorrat(rat, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose, visual=False, multiple=False) factorlist = sum(([p] * fac[p] if fac[p] > 0 else [S.One/p]*(-fac[p]) for p, _ in sorted(fac.items(), key=lambda elem: elem[0] if elem[1] > 0 else 1/elem[0])), []) return factorlist f = factorint(rat.p, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose).copy() f = defaultdict(int, f) for p, e in factorint(rat.q, limit=limit, use_trial=use_trial, use_rho=use_rho, use_pm1=use_pm1, verbose=verbose).items(): f[p] += -e if len(f) > 1 and 1 in f: del f[1] if not visual: return dict(f) else: if -1 in f: f.pop(-1) args = [S.NegativeOne] else: args = [] args.extend([Pow(*i, evaluate=False) for i in sorted(f.items())]) return Mul(*args, evaluate=False) def primefactors(n, limit=None, verbose=False): """Return a sorted list of n's prime factors, ignoring multiplicity and any composite factor that remains if the limit was set too low for complete factorization. Unlike factorint(), primefactors() does not return -1 or 0. Examples ======== >>> from sympy.ntheory import primefactors, factorint, isprime >>> primefactors(6) [2, 3] >>> primefactors(-5) [5] >>> sorted(factorint(123456).items()) [(2, 6), (3, 1), (643, 1)] >>> primefactors(123456) [2, 3, 643] >>> sorted(factorint(10000000001, limit=200).items()) [(101, 1), (99009901, 1)] >>> isprime(99009901) False >>> primefactors(10000000001, limit=300) [101] See Also ======== divisors """ n = int(n) factors = sorted(factorint(n, limit=limit, verbose=verbose).keys()) s = [f for f in factors[:-1:] if f not in [-1, 0, 1]] if factors and isprime(factors[-1]): s += [factors[-1]] return s def _divisors(n, proper=False): """Helper function for divisors which generates the divisors.""" factordict = factorint(n) ps = sorted(factordict.keys()) def rec_gen(n=0): if n == len(ps): yield 1 else: pows = [1] for j in range(factordict[ps[n]]): pows.append(pows[-1] * ps[n]) for q in rec_gen(n + 1): for p in pows: yield p * q if proper: for p in rec_gen(): if p != n: yield p else: yield from rec_gen() def divisors(n, generator=False, proper=False): r""" Return all divisors of n sorted from 1..n by default. If generator is ``True`` an unordered generator is returned. The number of divisors of n can be quite large if there are many prime factors (counting repeated factors). If only the number of factors is desired use divisor_count(n). Examples ======== >>> from sympy import divisors, divisor_count >>> divisors(24) [1, 2, 3, 4, 6, 8, 12, 24] >>> divisor_count(24) 8 >>> list(divisors(120, generator=True)) [1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60, 120] Notes ===== This is a slightly modified version of Tim Peters referenced at: https://stackoverflow.com/questions/1010381/python-factorization See Also ======== primefactors, factorint, divisor_count """ n = as_int(abs(n)) if isprime(n): if proper: return [1] return [1, n] if n == 1: if proper: return [] return [1] if n == 0: return [] rv = _divisors(n, proper) if not generator: return sorted(rv) return rv def divisor_count(n, modulus=1, proper=False): """ Return the number of divisors of ``n``. If ``modulus`` is not 1 then only those that are divisible by ``modulus`` are counted. If ``proper`` is True then the divisor of ``n`` will not be counted. Examples ======== >>> from sympy import divisor_count >>> divisor_count(6) 4 >>> divisor_count(6, 2) 2 >>> divisor_count(6, proper=True) 3 See Also ======== factorint, divisors, totient, proper_divisor_count """ if not modulus: return 0 elif modulus != 1: n, r = divmod(n, modulus) if r: return 0 if n == 0: return 0 n = Mul(*[v + 1 for k, v in factorint(n).items() if k > 1]) if n and proper: n -= 1 return n def proper_divisors(n, generator=False): """ Return all divisors of n except n, sorted by default. If generator is ``True`` an unordered generator is returned. Examples ======== >>> from sympy import proper_divisors, proper_divisor_count >>> proper_divisors(24) [1, 2, 3, 4, 6, 8, 12] >>> proper_divisor_count(24) 7 >>> list(proper_divisors(120, generator=True)) [1, 2, 4, 8, 3, 6, 12, 24, 5, 10, 20, 40, 15, 30, 60] See Also ======== factorint, divisors, proper_divisor_count """ return divisors(n, generator=generator, proper=True) def proper_divisor_count(n, modulus=1): """ Return the number of proper divisors of ``n``. Examples ======== >>> from sympy import proper_divisor_count >>> proper_divisor_count(6) 3 >>> proper_divisor_count(6, modulus=2) 1 See Also ======== divisors, proper_divisors, divisor_count """ return divisor_count(n, modulus=modulus, proper=True) def _udivisors(n): """Helper function for udivisors which generates the unitary divisors.""" factorpows = [p**e for p, e in factorint(n).items()] for i in range(2**len(factorpows)): d, j, k = 1, i, 0 while j: if (j & 1): d *= factorpows[k] j >>= 1 k += 1 yield d def udivisors(n, generator=False): r""" Return all unitary divisors of n sorted from 1..n by default. If generator is ``True`` an unordered generator is returned. The number of unitary divisors of n can be quite large if there are many prime factors. If only the number of unitary divisors is desired use udivisor_count(n). Examples ======== >>> from sympy.ntheory.factor_ import udivisors, udivisor_count >>> udivisors(15) [1, 3, 5, 15] >>> udivisor_count(15) 4 >>> sorted(udivisors(120, generator=True)) [1, 3, 5, 8, 15, 24, 40, 120] See Also ======== primefactors, factorint, divisors, divisor_count, udivisor_count References ========== .. [1] https://en.wikipedia.org/wiki/Unitary_divisor .. [2] http://mathworld.wolfram.com/UnitaryDivisor.html """ n = as_int(abs(n)) if isprime(n): return [1, n] if n == 1: return [1] if n == 0: return [] rv = _udivisors(n) if not generator: return sorted(rv) return rv def udivisor_count(n): """ Return the number of unitary divisors of ``n``. Parameters ========== n : integer Examples ======== >>> from sympy.ntheory.factor_ import udivisor_count >>> udivisor_count(120) 8 See Also ======== factorint, divisors, udivisors, divisor_count, totient References ========== .. [1] http://mathworld.wolfram.com/UnitaryDivisorFunction.html """ if n == 0: return 0 return 2**len([p for p in factorint(n) if p > 1]) def _antidivisors(n): """Helper function for antidivisors which generates the antidivisors.""" for d in _divisors(n): y = 2*d if n > y and n % y: yield y for d in _divisors(2*n-1): if n > d >= 2 and n % d: yield d for d in _divisors(2*n+1): if n > d >= 2 and n % d: yield d def antidivisors(n, generator=False): r""" Return all antidivisors of n sorted from 1..n by default. Antidivisors [1]_ of n are numbers that do not divide n by the largest possible margin. If generator is True an unordered generator is returned. Examples ======== >>> from sympy.ntheory.factor_ import antidivisors >>> antidivisors(24) [7, 16] >>> sorted(antidivisors(128, generator=True)) [3, 5, 15, 17, 51, 85] See Also ======== primefactors, factorint, divisors, divisor_count, antidivisor_count References ========== .. [1] definition is described in https://oeis.org/A066272/a066272a.html """ n = as_int(abs(n)) if n <= 2: return [] rv = _antidivisors(n) if not generator: return sorted(rv) return rv def antidivisor_count(n): """ Return the number of antidivisors [1]_ of ``n``. Parameters ========== n : integer Examples ======== >>> from sympy.ntheory.factor_ import antidivisor_count >>> antidivisor_count(13) 4 >>> antidivisor_count(27) 5 See Also ======== factorint, divisors, antidivisors, divisor_count, totient References ========== .. [1] formula from https://oeis.org/A066272 """ n = as_int(abs(n)) if n <= 2: return 0 return divisor_count(2*n - 1) + divisor_count(2*n + 1) + \ divisor_count(n) - divisor_count(n, 2) - 5 class totient(Function): r""" Calculate the Euler totient function phi(n) ``totient(n)`` or `\phi(n)` is the number of positive integers `\leq` n that are relatively prime to n. Parameters ========== n : integer Examples ======== >>> from sympy.ntheory import totient >>> totient(1) 1 >>> totient(25) 20 >>> totient(45) == totient(5)*totient(9) True See Also ======== divisor_count References ========== .. [1] https://en.wikipedia.org/wiki/Euler%27s_totient_function .. [2] http://mathworld.wolfram.com/TotientFunction.html """ @classmethod def eval(cls, n): n = sympify(n) if n.is_Integer: if n < 1: raise ValueError("n must be a positive integer") factors = factorint(n) return cls._from_factors(factors) elif not isinstance(n, Expr) or (n.is_integer is False) or (n.is_positive is False): raise ValueError("n must be a positive integer") def _eval_is_integer(self): return fuzzy_and([self.args[0].is_integer, self.args[0].is_positive]) @classmethod def _from_distinct_primes(self, *args): """Subroutine to compute totient from the list of assumed distinct primes Examples ======== >>> from sympy.ntheory.factor_ import totient >>> totient._from_distinct_primes(5, 7) 24 """ from functools import reduce return reduce(lambda i, j: i * (j-1), args, 1) @classmethod def _from_factors(self, factors): """Subroutine to compute totient from already-computed factors Examples ======== >>> from sympy.ntheory.factor_ import totient >>> totient._from_factors({5: 2}) 20 """ t = 1 for p, k in factors.items(): t *= (p - 1) * p**(k - 1) return t class reduced_totient(Function): r""" Calculate the Carmichael reduced totient function lambda(n) ``reduced_totient(n)`` or `\lambda(n)` is the smallest m > 0 such that `k^m \equiv 1 \mod n` for all k relatively prime to n. Examples ======== >>> from sympy.ntheory import reduced_totient >>> reduced_totient(1) 1 >>> reduced_totient(8) 2 >>> reduced_totient(30) 4 See Also ======== totient References ========== .. [1] https://en.wikipedia.org/wiki/Carmichael_function .. [2] http://mathworld.wolfram.com/CarmichaelFunction.html """ @classmethod def eval(cls, n): n = sympify(n) if n.is_Integer: if n < 1: raise ValueError("n must be a positive integer") factors = factorint(n) return cls._from_factors(factors) @classmethod def _from_factors(self, factors): """Subroutine to compute totient from already-computed factors """ t = 1 for p, k in factors.items(): if p == 2 and k > 2: t = ilcm(t, 2**(k - 2)) else: t = ilcm(t, (p - 1) * p**(k - 1)) return t @classmethod def _from_distinct_primes(self, *args): """Subroutine to compute totient from the list of assumed distinct primes """ args = [p - 1 for p in args] return ilcm(*args) def _eval_is_integer(self): return fuzzy_and([self.args[0].is_integer, self.args[0].is_positive]) class divisor_sigma(Function): r""" Calculate the divisor function `\sigma_k(n)` for positive integer n ``divisor_sigma(n, k)`` is equal to ``sum([x**k for x in divisors(n)])`` If n's prime factorization is: .. math :: n = \prod_{i=1}^\omega p_i^{m_i}, then .. math :: \sigma_k(n) = \prod_{i=1}^\omega (1+p_i^k+p_i^{2k}+\cdots + p_i^{m_ik}). Parameters ========== n : integer k : integer, optional power of divisors in the sum for k = 0, 1: ``divisor_sigma(n, 0)`` is equal to ``divisor_count(n)`` ``divisor_sigma(n, 1)`` is equal to ``sum(divisors(n))`` Default for k is 1. Examples ======== >>> from sympy.ntheory import divisor_sigma >>> divisor_sigma(18, 0) 6 >>> divisor_sigma(39, 1) 56 >>> divisor_sigma(12, 2) 210 >>> divisor_sigma(37) 38 See Also ======== divisor_count, totient, divisors, factorint References ========== .. [1] https://en.wikipedia.org/wiki/Divisor_function """ @classmethod def eval(cls, n, k=1): n = sympify(n) k = sympify(k) if n.is_prime: return 1 + n**k if n.is_Integer: if n <= 0: raise ValueError("n must be a positive integer") elif k.is_Integer: k = int(k) return Integer(prod( (p**(k*(e + 1)) - 1)//(p**k - 1) if k != 0 else e + 1 for p, e in factorint(n).items())) else: return Mul(*[(p**(k*(e + 1)) - 1)/(p**k - 1) if k != 0 else e + 1 for p, e in factorint(n).items()]) if n.is_integer: # symbolic case args = [] for p, e in (_.as_base_exp() for _ in Mul.make_args(n)): if p.is_prime and e.is_positive: args.append((p**(k*(e + 1)) - 1)/(p**k - 1) if k != 0 else e + 1) else: return return Mul(*args) def core(n, t=2): r""" Calculate core(n, t) = `core_t(n)` of a positive integer n ``core_2(n)`` is equal to the squarefree part of n If n's prime factorization is: .. math :: n = \prod_{i=1}^\omega p_i^{m_i}, then .. math :: core_t(n) = \prod_{i=1}^\omega p_i^{m_i \mod t}. Parameters ========== n : integer t : integer core(n, t) calculates the t-th power free part of n ``core(n, 2)`` is the squarefree part of ``n`` ``core(n, 3)`` is the cubefree part of ``n`` Default for t is 2. Examples ======== >>> from sympy.ntheory.factor_ import core >>> core(24, 2) 6 >>> core(9424, 3) 1178 >>> core(379238) 379238 >>> core(15**11, 10) 15 See Also ======== factorint, sympy.solvers.diophantine.diophantine.square_factor References ========== .. [1] https://en.wikipedia.org/wiki/Square-free_integer#Squarefree_core """ n = as_int(n) t = as_int(t) if n <= 0: raise ValueError("n must be a positive integer") elif t <= 1: raise ValueError("t must be >= 2") else: y = 1 for p, e in factorint(n).items(): y *= p**(e % t) return y class udivisor_sigma(Function): r""" Calculate the unitary divisor function `\sigma_k^*(n)` for positive integer n ``udivisor_sigma(n, k)`` is equal to ``sum([x**k for x in udivisors(n)])`` If n's prime factorization is: .. math :: n = \prod_{i=1}^\omega p_i^{m_i}, then .. math :: \sigma_k^*(n) = \prod_{i=1}^\omega (1+ p_i^{m_ik}). Parameters ========== k : power of divisors in the sum for k = 0, 1: ``udivisor_sigma(n, 0)`` is equal to ``udivisor_count(n)`` ``udivisor_sigma(n, 1)`` is equal to ``sum(udivisors(n))`` Default for k is 1. Examples ======== >>> from sympy.ntheory.factor_ import udivisor_sigma >>> udivisor_sigma(18, 0) 4 >>> udivisor_sigma(74, 1) 114 >>> udivisor_sigma(36, 3) 47450 >>> udivisor_sigma(111) 152 See Also ======== divisor_count, totient, divisors, udivisors, udivisor_count, divisor_sigma, factorint References ========== .. [1] http://mathworld.wolfram.com/UnitaryDivisorFunction.html """ @classmethod def eval(cls, n, k=1): n = sympify(n) k = sympify(k) if n.is_prime: return 1 + n**k if n.is_Integer: if n <= 0: raise ValueError("n must be a positive integer") else: return Mul(*[1+p**(k*e) for p, e in factorint(n).items()]) class primenu(Function): r""" Calculate the number of distinct prime factors for a positive integer n. If n's prime factorization is: .. math :: n = \prod_{i=1}^k p_i^{m_i}, then ``primenu(n)`` or `\nu(n)` is: .. math :: \nu(n) = k. Examples ======== >>> from sympy.ntheory.factor_ import primenu >>> primenu(1) 0 >>> primenu(30) 3 See Also ======== factorint References ========== .. [1] http://mathworld.wolfram.com/PrimeFactor.html """ @classmethod def eval(cls, n): n = sympify(n) if n.is_Integer: if n <= 0: raise ValueError("n must be a positive integer") else: return len(factorint(n).keys()) class primeomega(Function): r""" Calculate the number of prime factors counting multiplicities for a positive integer n. If n's prime factorization is: .. math :: n = \prod_{i=1}^k p_i^{m_i}, then ``primeomega(n)`` or `\Omega(n)` is: .. math :: \Omega(n) = \sum_{i=1}^k m_i. Examples ======== >>> from sympy.ntheory.factor_ import primeomega >>> primeomega(1) 0 >>> primeomega(20) 3 See Also ======== factorint References ========== .. [1] http://mathworld.wolfram.com/PrimeFactor.html """ @classmethod def eval(cls, n): n = sympify(n) if n.is_Integer: if n <= 0: raise ValueError("n must be a positive integer") else: return sum(factorint(n).values()) def mersenne_prime_exponent(nth): """Returns the exponent ``i`` for the nth Mersenne prime (which has the form `2^i - 1`). Examples ======== >>> from sympy.ntheory.factor_ import mersenne_prime_exponent >>> mersenne_prime_exponent(1) 2 >>> mersenne_prime_exponent(20) 4423 """ n = as_int(nth) if n < 1: raise ValueError("nth must be a positive integer; mersenne_prime_exponent(1) == 2") if n > 51: raise ValueError("There are only 51 perfect numbers; nth must be less than or equal to 51") return MERSENNE_PRIME_EXPONENTS[n - 1] def is_perfect(n): """Returns True if ``n`` is a perfect number, else False. A perfect number is equal to the sum of its positive, proper divisors. Examples ======== >>> from sympy.ntheory.factor_ import is_perfect, divisors, divisor_sigma >>> is_perfect(20) False >>> is_perfect(6) True >>> 6 == divisor_sigma(6) - 6 == sum(divisors(6)[:-1]) True References ========== .. [1] http://mathworld.wolfram.com/PerfectNumber.html .. [2] https://en.wikipedia.org/wiki/Perfect_number """ from sympy.core.power import integer_log n = as_int(n) if _isperfect(n): return True # all perfect numbers for Mersenne primes with exponents # less than or equal to 43112609 are known iknow = MERSENNE_PRIME_EXPONENTS.index(43112609) if iknow <= len(PERFECT) - 1 and n <= PERFECT[iknow]: # there may be gaps between this and larger known values # so only conclude in the range for which all values # are known return False if n%2 == 0: last2 = n % 100 if last2 != 28 and last2 % 10 != 6: return False r, b = integer_nthroot(1 + 8*n, 2) if not b: return False m, x = divmod(1 + r, 4) if x: return False e, b = integer_log(m, 2) if not b: return False else: if n < 10**2000: # http://www.lirmm.fr/~ochem/opn/ return False if n % 105 == 0: # not divis by 105 return False if not any(n%m == r for m, r in [(12, 1), (468, 117), (324, 81)]): return False # there are many criteria that the factor structure of n # must meet; since we will have to factor it to test the # structure we will have the factors and can then check # to see whether it is a perfect number or not. So we # skip the structure checks and go straight to the final # test below. rv = divisor_sigma(n) - n if rv == n: if n%2 == 0: raise ValueError(filldedent(''' This even number is perfect and is associated with a Mersenne Prime, 2^%s - 1. It should be added to SymPy.''' % (e + 1))) else: raise ValueError(filldedent('''In 1888, Sylvester stated: " ...a prolonged meditation on the subject has satisfied me that the existence of any one such [odd perfect number] -- its escape, so to say, from the complex web of conditions which hem it in on all sides -- would be little short of a miracle." I guess SymPy just found that miracle and it factors like this: %s''' % factorint(n))) def is_mersenne_prime(n): """Returns True if ``n`` is a Mersenne prime, else False. A Mersenne prime is a prime number having the form `2^i - 1`. Examples ======== >>> from sympy.ntheory.factor_ import is_mersenne_prime >>> is_mersenne_prime(6) False >>> is_mersenne_prime(127) True References ========== .. [1] http://mathworld.wolfram.com/MersennePrime.html """ from sympy.core.power import integer_log n = as_int(n) if _ismersenneprime(n): return True if not isprime(n): return False r, b = integer_log(n + 1, 2) if not b: return False raise ValueError(filldedent(''' This Mersenne Prime, 2^%s - 1, should be added to SymPy's known values.''' % r)) def abundance(n): """Returns the difference between the sum of the positive proper divisors of a number and the number. Examples ======== >>> from sympy.ntheory import abundance, is_perfect, is_abundant >>> abundance(6) 0 >>> is_perfect(6) True >>> abundance(10) -2 >>> is_abundant(10) False """ return divisor_sigma(n, 1) - 2 * n def is_abundant(n): """Returns True if ``n`` is an abundant number, else False. A abundant number is smaller than the sum of its positive proper divisors. Examples ======== >>> from sympy.ntheory.factor_ import is_abundant >>> is_abundant(20) True >>> is_abundant(15) False References ========== .. [1] http://mathworld.wolfram.com/AbundantNumber.html """ n = as_int(n) if is_perfect(n): return False return n % 6 == 0 or bool(abundance(n) > 0) def is_deficient(n): """Returns True if ``n`` is a deficient number, else False. A deficient number is greater than the sum of its positive proper divisors. Examples ======== >>> from sympy.ntheory.factor_ import is_deficient >>> is_deficient(20) False >>> is_deficient(15) True References ========== .. [1] http://mathworld.wolfram.com/DeficientNumber.html """ n = as_int(n) if is_perfect(n): return False return bool(abundance(n) < 0) def is_amicable(m, n): """Returns True if the numbers `m` and `n` are "amicable", else False. Amicable numbers are two different numbers so related that the sum of the proper divisors of each is equal to that of the other. Examples ======== >>> from sympy.ntheory.factor_ import is_amicable, divisor_sigma >>> is_amicable(220, 284) True >>> divisor_sigma(220) == divisor_sigma(284) True References ========== .. [1] https://en.wikipedia.org/wiki/Amicable_numbers """ if m == n: return False a, b = map(lambda i: divisor_sigma(i), (m, n)) return a == b == (m + n) def dra(n, b): """ Returns the additive digital root of a natural number ``n`` in base ``b`` which is a single digit value obtained by an iterative process of summing digits, on each iteration using the result from the previous iteration to compute a digit sum. Examples ======== >>> from sympy.ntheory.factor_ import dra >>> dra(3110, 12) 8 References ========== .. [1] https://en.wikipedia.org/wiki/Digital_root """ num = abs(as_int(n)) b = as_int(b) if b <= 1: raise ValueError("Base should be an integer greater than 1") if num == 0: return 0 return (1 + (num - 1) % (b - 1)) def drm(n, b): """ Returns the multiplicative digital root of a natural number ``n`` in a given base ``b`` which is a single digit value obtained by an iterative process of multiplying digits, on each iteration using the result from the previous iteration to compute the digit multiplication. Examples ======== >>> from sympy.ntheory.factor_ import drm >>> drm(9876, 10) 0 >>> drm(49, 10) 8 References ========== .. [1] http://mathworld.wolfram.com/MultiplicativeDigitalRoot.html """ n = abs(as_int(n)) b = as_int(b) if b <= 1: raise ValueError("Base should be an integer greater than 1") while n > b: mul = 1 while n > 1: n, r = divmod(n, b) if r == 0: return 0 mul *= r n = mul return n sympy-sympy-1.9/sympy/ntheory/generate.py000066400000000000000000000732021412543434000207440ustar00rootroot00000000000000""" Generating and counting primes. """ import random from bisect import bisect from itertools import count # Using arrays for sieving instead of lists greatly reduces # memory consumption from array import array as _array from sympy import Function, S from sympy.core.compatibility import as_int from .primetest import isprime def _azeros(n): return _array('l', [0]*n) def _aset(*v): return _array('l', v) def _arange(a, b): return _array('l', range(a, b)) class Sieve: """An infinite list of prime numbers, implemented as a dynamically growing sieve of Eratosthenes. When a lookup is requested involving an odd number that has not been sieved, the sieve is automatically extended up to that number. Examples ======== >>> from sympy import sieve >>> sieve._reset() # this line for doctest only >>> 25 in sieve False >>> sieve._list array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23]) """ # data shared (and updated) by all Sieve instances def __init__(self): self._n = 6 self._list = _aset(2, 3, 5, 7, 11, 13) # primes self._tlist = _aset(0, 1, 1, 2, 2, 4) # totient self._mlist = _aset(0, 1, -1, -1, 0, -1) # mobius assert all(len(i) == self._n for i in (self._list, self._tlist, self._mlist)) def __repr__(self): return ("<%s sieve (%i): %i, %i, %i, ... %i, %i\n" "%s sieve (%i): %i, %i, %i, ... %i, %i\n" "%s sieve (%i): %i, %i, %i, ... %i, %i>") % ( 'prime', len(self._list), self._list[0], self._list[1], self._list[2], self._list[-2], self._list[-1], 'totient', len(self._tlist), self._tlist[0], self._tlist[1], self._tlist[2], self._tlist[-2], self._tlist[-1], 'mobius', len(self._mlist), self._mlist[0], self._mlist[1], self._mlist[2], self._mlist[-2], self._mlist[-1]) def _reset(self, prime=None, totient=None, mobius=None): """Reset all caches (default). To reset one or more set the desired keyword to True.""" if all(i is None for i in (prime, totient, mobius)): prime = totient = mobius = True if prime: self._list = self._list[:self._n] if totient: self._tlist = self._tlist[:self._n] if mobius: self._mlist = self._mlist[:self._n] def extend(self, n): """Grow the sieve to cover all primes <= n (a real number). Examples ======== >>> from sympy import sieve >>> sieve._reset() # this line for doctest only >>> sieve.extend(30) >>> sieve[10] == 29 True """ n = int(n) if n <= self._list[-1]: return # We need to sieve against all bases up to sqrt(n). # This is a recursive call that will do nothing if there are enough # known bases already. maxbase = int(n**0.5) + 1 self.extend(maxbase) # Create a new sieve starting from sqrt(n) begin = self._list[-1] + 1 newsieve = _arange(begin, n + 1) # Now eliminate all multiples of primes in [2, sqrt(n)] for p in self.primerange(maxbase): # Start counting at a multiple of p, offsetting # the index to account for the new sieve's base index startindex = (-begin) % p for i in range(startindex, len(newsieve), p): newsieve[i] = 0 # Merge the sieves self._list += _array('l', [x for x in newsieve if x]) def extend_to_no(self, i): """Extend to include the ith prime number. Parameters ========== i : integer Examples ======== >>> from sympy import sieve >>> sieve._reset() # this line for doctest only >>> sieve.extend_to_no(9) >>> sieve._list array('l', [2, 3, 5, 7, 11, 13, 17, 19, 23]) Notes ===== The list is extended by 50% if it is too short, so it is likely that it will be longer than requested. """ i = as_int(i) while len(self._list) < i: self.extend(int(self._list[-1] * 1.5)) def primerange(self, a, b=None): """Generate all prime numbers in the range [2, a) or [a, b). Examples ======== >>> from sympy import sieve, prime All primes less than 19: >>> print([i for i in sieve.primerange(19)]) [2, 3, 5, 7, 11, 13, 17] All primes greater than or equal to 7 and less than 19: >>> print([i for i in sieve.primerange(7, 19)]) [7, 11, 13, 17] All primes through the 10th prime >>> list(sieve.primerange(prime(10) + 1)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not if b is None: b = as_int(ceiling(a)) a = 2 else: a = max(2, as_int(ceiling(a))) b = as_int(ceiling(b)) if a >= b: return self.extend(b) i = self.search(a)[1] maxi = len(self._list) + 1 while i < maxi: p = self._list[i - 1] if p < b: yield p i += 1 else: return def totientrange(self, a, b): """Generate all totient numbers for the range [a, b). Examples ======== >>> from sympy import sieve >>> print([i for i in sieve.totientrange(7, 18)]) [6, 4, 6, 4, 10, 4, 12, 6, 8, 8, 16] """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not a = max(1, as_int(ceiling(a))) b = as_int(ceiling(b)) n = len(self._tlist) if a >= b: return elif b <= n: for i in range(a, b): yield self._tlist[i] else: self._tlist += _arange(n, b) for i in range(1, n): ti = self._tlist[i] startindex = (n + i - 1) // i * i for j in range(startindex, b, i): self._tlist[j] -= ti if i >= a: yield ti for i in range(n, b): ti = self._tlist[i] for j in range(2 * i, b, i): self._tlist[j] -= ti if i >= a: yield ti def mobiusrange(self, a, b): """Generate all mobius numbers for the range [a, b). Parameters ========== a : integer First number in range b : integer First number outside of range Examples ======== >>> from sympy import sieve >>> print([i for i in sieve.mobiusrange(7, 18)]) [-1, 0, 0, 1, -1, 0, -1, 1, 1, 0, -1] """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not a = max(1, as_int(ceiling(a))) b = as_int(ceiling(b)) n = len(self._mlist) if a >= b: return elif b <= n: for i in range(a, b): yield self._mlist[i] else: self._mlist += _azeros(b - n) for i in range(1, n): mi = self._mlist[i] startindex = (n + i - 1) // i * i for j in range(startindex, b, i): self._mlist[j] -= mi if i >= a: yield mi for i in range(n, b): mi = self._mlist[i] for j in range(2 * i, b, i): self._mlist[j] -= mi if i >= a: yield mi def search(self, n): """Return the indices i, j of the primes that bound n. If n is prime then i == j. Although n can be an expression, if ceiling cannot convert it to an integer then an n error will be raised. Examples ======== >>> from sympy import sieve >>> sieve.search(25) (9, 10) >>> sieve.search(23) (9, 9) """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not test = as_int(ceiling(n)) n = as_int(n) if n < 2: raise ValueError("n should be >= 2 but got: %s" % n) if n > self._list[-1]: self.extend(n) b = bisect(self._list, n) if self._list[b - 1] == test: return b, b else: return b, b + 1 def __contains__(self, n): try: n = as_int(n) assert n >= 2 except (ValueError, AssertionError): return False if n % 2 == 0: return n == 2 a, b = self.search(n) return a == b def __iter__(self): for n in count(1): yield self[n] def __getitem__(self, n): """Return the nth prime number""" if isinstance(n, slice): self.extend_to_no(n.stop) # Python 2.7 slices have 0 instead of None for start, so # we can't default to 1. start = n.start if n.start is not None else 0 if start < 1: # sieve[:5] would be empty (starting at -1), let's # just be explicit and raise. raise IndexError("Sieve indices start at 1.") return self._list[start - 1:n.stop - 1:n.step] else: if n < 1: # offset is one, so forbid explicit access to sieve[0] # (would surprisingly return the last one). raise IndexError("Sieve indices start at 1.") n = as_int(n) self.extend_to_no(n) return self._list[n - 1] # Generate a global object for repeated use in trial division etc sieve = Sieve() def prime(nth): """ Return the nth prime, with the primes indexed as prime(1) = 2, prime(2) = 3, etc.... The nth prime is approximately n*log(n). Logarithmic integral of x is a pretty nice approximation for number of primes <= x, i.e. li(x) ~ pi(x) In fact, for the numbers we are concerned about( x<1e11 ), li(x) - pi(x) < 50000 Also, li(x) > pi(x) can be safely assumed for the numbers which can be evaluated by this function. Here, we find the least integer m such that li(m) > n using binary search. Now pi(m-1) < li(m-1) <= n, We find pi(m - 1) using primepi function. Starting from m, we have to find n - pi(m-1) more primes. For the inputs this implementation can handle, we will have to test primality for at max about 10**5 numbers, to get our answer. Examples ======== >>> from sympy import prime >>> prime(10) 29 >>> prime(1) 2 >>> prime(100000) 1299709 See Also ======== sympy.ntheory.primetest.isprime : Test if n is prime primerange : Generate all primes in a given range primepi : Return the number of primes less than or equal to n References ========== .. [1] https://en.wikipedia.org/wiki/Prime_number_theorem#Table_of_.CF.80.28x.29.2C_x_.2F_log_x.2C_and_li.28x.29 .. [2] https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number .. [3] https://en.wikipedia.org/wiki/Skewes%27_number """ n = as_int(nth) if n < 1: raise ValueError("nth must be a positive integer; prime(1) == 2") if n <= len(sieve._list): return sieve[n] from sympy.functions.special.error_functions import li from sympy.functions.elementary.exponential import log a = 2 # Lower bound for binary search b = int(n*(log(n) + log(log(n)))) # Upper bound for the search. while a < b: mid = (a + b) >> 1 if li(mid) > n: b = mid else: a = mid + 1 n_primes = primepi(a - 1) while n_primes < n: if isprime(a): n_primes += 1 a += 1 return a - 1 class primepi(Function): """ Represents the prime counting function pi(n) = the number of prime numbers less than or equal to n. Algorithm Description: In sieve method, we remove all multiples of prime p except p itself. Let phi(i,j) be the number of integers 2 <= k <= i which remain after sieving from primes less than or equal to j. Clearly, pi(n) = phi(n, sqrt(n)) If j is not a prime, phi(i,j) = phi(i, j - 1) if j is a prime, We remove all numbers(except j) whose smallest prime factor is j. Let x= j*a be such a number, where 2 <= a<= i / j Now, after sieving from primes <= j - 1, a must remain (because x, and hence a has no prime factor <= j - 1) Clearly, there are phi(i / j, j - 1) such a which remain on sieving from primes <= j - 1 Now, if a is a prime less than equal to j - 1, x= j*a has smallest prime factor = a, and has already been removed(by sieving from a). So, we don't need to remove it again. (Note: there will be pi(j - 1) such x) Thus, number of x, that will be removed are: phi(i / j, j - 1) - phi(j - 1, j - 1) (Note that pi(j - 1) = phi(j - 1, j - 1)) => phi(i,j) = phi(i, j - 1) - phi(i / j, j - 1) + phi(j - 1, j - 1) So,following recursion is used and implemented as dp: phi(a, b) = phi(a, b - 1), if b is not a prime phi(a, b) = phi(a, b-1)-phi(a / b, b-1) + phi(b-1, b-1), if b is prime Clearly a is always of the form floor(n / k), which can take at most 2*sqrt(n) values. Two arrays arr1,arr2 are maintained arr1[i] = phi(i, j), arr2[i] = phi(n // i, j) Finally the answer is arr2[1] Examples ======== >>> from sympy import primepi, prime, prevprime, isprime >>> primepi(25) 9 So there are 9 primes less than or equal to 25. Is 25 prime? >>> isprime(25) False It isn't. So the first prime less than 25 must be the 9th prime: >>> prevprime(25) == prime(9) True See Also ======== sympy.ntheory.primetest.isprime : Test if n is prime primerange : Generate all primes in a given range prime : Return the nth prime """ @classmethod def eval(cls, n): if n is S.Infinity: return S.Infinity if n is S.NegativeInfinity: return S.Zero try: n = int(n) except TypeError: if n.is_real == False or n is S.NaN: raise ValueError("n must be real") return if n < 2: return S.Zero if n <= sieve._list[-1]: return S(sieve.search(n)[0]) lim = int(n ** 0.5) lim -= 1 lim = max(lim, 0) while lim * lim <= n: lim += 1 lim -= 1 arr1 = [0] * (lim + 1) arr2 = [0] * (lim + 1) for i in range(1, lim + 1): arr1[i] = i - 1 arr2[i] = n // i - 1 for i in range(2, lim + 1): # Presently, arr1[k]=phi(k,i - 1), # arr2[k] = phi(n // k,i - 1) if arr1[i] == arr1[i - 1]: continue p = arr1[i - 1] for j in range(1, min(n // (i * i), lim) + 1): st = i * j if st <= lim: arr2[j] -= arr2[st] - p else: arr2[j] -= arr1[n // st] - p lim2 = min(lim, i * i - 1) for j in range(lim, lim2, -1): arr1[j] -= arr1[j // i] - p return S(arr2[1]) def nextprime(n, ith=1): """ Return the ith prime greater than n. i must be an integer. Notes ===== Potential primes are located at 6*j +/- 1. This property is used during searching. >>> from sympy import nextprime >>> [(i, nextprime(i)) for i in range(10, 15)] [(10, 11), (11, 13), (12, 13), (13, 17), (14, 17)] >>> nextprime(2, ith=2) # the 2nd prime after 2 5 See Also ======== prevprime : Return the largest prime smaller than n primerange : Generate all primes in a given range """ n = int(n) i = as_int(ith) if i > 1: pr = n j = 1 while 1: pr = nextprime(pr) j += 1 if j > i: break return pr if n < 2: return 2 if n < 7: return {2: 3, 3: 5, 4: 5, 5: 7, 6: 7}[n] if n <= sieve._list[-2]: l, u = sieve.search(n) if l == u: return sieve[u + 1] else: return sieve[u] nn = 6*(n//6) if nn == n: n += 1 if isprime(n): return n n += 4 elif n - nn == 5: n += 2 if isprime(n): return n n += 4 else: n = nn + 5 while 1: if isprime(n): return n n += 2 if isprime(n): return n n += 4 def prevprime(n): """ Return the largest prime smaller than n. Notes ===== Potential primes are located at 6*j +/- 1. This property is used during searching. >>> from sympy import prevprime >>> [(i, prevprime(i)) for i in range(10, 15)] [(10, 7), (11, 7), (12, 11), (13, 11), (14, 13)] See Also ======== nextprime : Return the ith prime greater than n primerange : Generates all primes in a given range """ from sympy.functions.elementary.integers import ceiling # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not n = as_int(ceiling(n)) if n < 3: raise ValueError("no preceding primes") if n < 8: return {3: 2, 4: 3, 5: 3, 6: 5, 7: 5}[n] if n <= sieve._list[-1]: l, u = sieve.search(n) if l == u: return sieve[l-1] else: return sieve[l] nn = 6*(n//6) if n - nn <= 1: n = nn - 1 if isprime(n): return n n -= 4 else: n = nn + 1 while 1: if isprime(n): return n n -= 2 if isprime(n): return n n -= 4 def primerange(a, b=None): """ Generate a list of all prime numbers in the range [2, a), or [a, b). If the range exists in the default sieve, the values will be returned from there; otherwise values will be returned but will not modify the sieve. Examples ======== >>> from sympy import primerange, prime All primes less than 19: >>> list(primerange(19)) [2, 3, 5, 7, 11, 13, 17] All primes greater than or equal to 7 and less than 19: >>> list(primerange(7, 19)) [7, 11, 13, 17] All primes through the 10th prime >>> list(primerange(prime(10) + 1)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] The Sieve method, primerange, is generally faster but it will occupy more memory as the sieve stores values. The default instance of Sieve, named sieve, can be used: >>> from sympy import sieve >>> list(sieve.primerange(1, 30)) [2, 3, 5, 7, 11, 13, 17, 19, 23, 29] Notes ===== Some famous conjectures about the occurrence of primes in a given range are [1]: - Twin primes: though often not, the following will give 2 primes an infinite number of times: primerange(6*n - 1, 6*n + 2) - Legendre's: the following always yields at least one prime primerange(n**2, (n+1)**2+1) - Bertrand's (proven): there is always a prime in the range primerange(n, 2*n) - Brocard's: there are at least four primes in the range primerange(prime(n)**2, prime(n+1)**2) The average gap between primes is log(n) [2]; the gap between primes can be arbitrarily large since sequences of composite numbers are arbitrarily large, e.g. the numbers in the sequence n! + 2, n! + 3 ... n! + n are all composite. See Also ======== prime : Return the nth prime nextprime : Return the ith prime greater than n prevprime : Return the largest prime smaller than n randprime : Returns a random prime in a given range primorial : Returns the product of primes based on condition Sieve.primerange : return range from already computed primes or extend the sieve to contain the requested range. References ========== .. [1] https://en.wikipedia.org/wiki/Prime_number .. [2] http://primes.utm.edu/notes/gaps.html """ from sympy.functions.elementary.integers import ceiling if b is None: a, b = 2, a if a >= b: return # if we already have the range, return it if b <= sieve._list[-1]: yield from sieve.primerange(a, b) return # otherwise compute, without storing, the desired range. # wrapping ceiling in as_int will raise an error if there was a problem # determining whether the expression was exactly an integer or not a = as_int(ceiling(a)) - 1 b = as_int(ceiling(b)) while 1: a = nextprime(a) if a < b: yield a else: return def randprime(a, b): """ Return a random prime number in the range [a, b). Bertrand's postulate assures that randprime(a, 2*a) will always succeed for a > 1. Examples ======== >>> from sympy import randprime, isprime >>> randprime(1, 30) #doctest: +SKIP 13 >>> isprime(randprime(1, 30)) True See Also ======== primerange : Generate all primes in a given range References ========== .. [1] https://en.wikipedia.org/wiki/Bertrand's_postulate """ if a >= b: return a, b = map(int, (a, b)) n = random.randint(a - 1, b) p = nextprime(n) if p >= b: p = prevprime(b) if p < a: raise ValueError("no primes exist in the specified range") return p def primorial(n, nth=True): """ Returns the product of the first n primes (default) or the primes less than or equal to n (when ``nth=False``). Examples ======== >>> from sympy.ntheory.generate import primorial, primerange >>> from sympy import factorint, Mul, primefactors, sqrt >>> primorial(4) # the first 4 primes are 2, 3, 5, 7 210 >>> primorial(4, nth=False) # primes <= 4 are 2 and 3 6 >>> primorial(1) 2 >>> primorial(1, nth=False) 1 >>> primorial(sqrt(101), nth=False) 210 One can argue that the primes are infinite since if you take a set of primes and multiply them together (e.g. the primorial) and then add or subtract 1, the result cannot be divided by any of the original factors, hence either 1 or more new primes must divide this product of primes. In this case, the number itself is a new prime: >>> factorint(primorial(4) + 1) {211: 1} In this case two new primes are the factors: >>> factorint(primorial(4) - 1) {11: 1, 19: 1} Here, some primes smaller and larger than the primes multiplied together are obtained: >>> p = list(primerange(10, 20)) >>> sorted(set(primefactors(Mul(*p) + 1)).difference(set(p))) [2, 5, 31, 149] See Also ======== primerange : Generate all primes in a given range """ if nth: n = as_int(n) else: n = int(n) if n < 1: raise ValueError("primorial argument must be >= 1") p = 1 if nth: for i in range(1, n + 1): p *= prime(i) else: for i in primerange(2, n + 1): p *= i return p def cycle_length(f, x0, nmax=None, values=False): """For a given iterated sequence, return a generator that gives the length of the iterated cycle (lambda) and the length of terms before the cycle begins (mu); if ``values`` is True then the terms of the sequence will be returned instead. The sequence is started with value ``x0``. Note: more than the first lambda + mu terms may be returned and this is the cost of cycle detection with Brent's method; there are, however, generally less terms calculated than would have been calculated if the proper ending point were determined, e.g. by using Floyd's method. >>> from sympy.ntheory.generate import cycle_length This will yield successive values of i <-- func(i): >>> def iter(func, i): ... while 1: ... ii = func(i) ... yield ii ... i = ii ... A function is defined: >>> func = lambda i: (i**2 + 1) % 51 and given a seed of 4 and the mu and lambda terms calculated: >>> next(cycle_length(func, 4)) (6, 2) We can see what is meant by looking at the output: >>> n = cycle_length(func, 4, values=True) >>> list(ni for ni in n) [17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14] There are 6 repeating values after the first 2. If a sequence is suspected of being longer than you might wish, ``nmax`` can be used to exit early (and mu will be returned as None): >>> next(cycle_length(func, 4, nmax = 4)) (4, None) >>> [ni for ni in cycle_length(func, 4, nmax = 4, values=True)] [17, 35, 2, 5] Code modified from: https://en.wikipedia.org/wiki/Cycle_detection. """ nmax = int(nmax or 0) # main phase: search successive powers of two power = lam = 1 tortoise, hare = x0, f(x0) # f(x0) is the element/node next to x0. i = 0 while tortoise != hare and (not nmax or i < nmax): i += 1 if power == lam: # time to start a new power of two? tortoise = hare power *= 2 lam = 0 if values: yield hare hare = f(hare) lam += 1 if nmax and i == nmax: if values: return else: yield nmax, None return if not values: # Find the position of the first repetition of length lambda mu = 0 tortoise = hare = x0 for i in range(lam): hare = f(hare) while tortoise != hare: tortoise = f(tortoise) hare = f(hare) mu += 1 if mu: mu -= 1 yield lam, mu def composite(nth): """ Return the nth composite number, with the composite numbers indexed as composite(1) = 4, composite(2) = 6, etc.... Examples ======== >>> from sympy import composite >>> composite(36) 52 >>> composite(1) 4 >>> composite(17737) 20000 See Also ======== sympy.ntheory.primetest.isprime : Test if n is prime primerange : Generate all primes in a given range primepi : Return the number of primes less than or equal to n prime : Return the nth prime compositepi : Return the number of positive composite numbers less than or equal to n """ n = as_int(nth) if n < 1: raise ValueError("nth must be a positive integer; composite(1) == 4") composite_arr = [4, 6, 8, 9, 10, 12, 14, 15, 16, 18] if n <= 10: return composite_arr[n - 1] a, b = 4, sieve._list[-1] if n <= b - primepi(b) - 1: while a < b - 1: mid = (a + b) >> 1 if mid - primepi(mid) - 1 > n: b = mid else: a = mid if isprime(a): a -= 1 return a from sympy.functions.special.error_functions import li from sympy.functions.elementary.exponential import log a = 4 # Lower bound for binary search b = int(n*(log(n) + log(log(n)))) # Upper bound for the search. while a < b: mid = (a + b) >> 1 if mid - li(mid) - 1 > n: b = mid else: a = mid + 1 n_composites = a - primepi(a) - 1 while n_composites > n: if not isprime(a): n_composites -= 1 a -= 1 if isprime(a): a -= 1 return a def compositepi(n): """ Return the number of positive composite numbers less than or equal to n. The first positive composite is 4, i.e. compositepi(4) = 1. Examples ======== >>> from sympy import compositepi >>> compositepi(25) 15 >>> compositepi(1000) 831 See Also ======== sympy.ntheory.primetest.isprime : Test if n is prime primerange : Generate all primes in a given range prime : Return the nth prime primepi : Return the number of primes less than or equal to n composite : Return the nth composite number """ n = int(n) if n < 4: return 0 return n - primepi(n) - 1 sympy-sympy-1.9/sympy/ntheory/modular.py000066400000000000000000000167531412543434000206250ustar00rootroot00000000000000from functools import reduce from sympy.core.compatibility import as_int from sympy.core.mul import prod from sympy.core.numbers import igcdex, igcd from sympy.ntheory.primetest import isprime from sympy.polys.domains import ZZ from sympy.polys.galoistools import gf_crt, gf_crt1, gf_crt2 def symmetric_residue(a, m): """Return the residual mod m such that it is within half of the modulus. >>> from sympy.ntheory.modular import symmetric_residue >>> symmetric_residue(1, 6) 1 >>> symmetric_residue(4, 6) -2 """ if a <= m // 2: return a return a - m def crt(m, v, symmetric=False, check=True): r"""Chinese Remainder Theorem. The moduli in m are assumed to be pairwise coprime. The output is then an integer f, such that f = v_i mod m_i for each pair out of v and m. If ``symmetric`` is False a positive integer will be returned, else \|f\| will be less than or equal to the LCM of the moduli, and thus f may be negative. If the moduli are not co-prime the correct result will be returned if/when the test of the result is found to be incorrect. This result will be None if there is no solution. The keyword ``check`` can be set to False if it is known that the moduli are coprime. Examples ======== As an example consider a set of residues ``U = [49, 76, 65]`` and a set of moduli ``M = [99, 97, 95]``. Then we have:: >>> from sympy.ntheory.modular import crt >>> crt([99, 97, 95], [49, 76, 65]) (639985, 912285) This is the correct result because:: >>> [639985 % m for m in [99, 97, 95]] [49, 76, 65] If the moduli are not co-prime, you may receive an incorrect result if you use ``check=False``: >>> crt([12, 6, 17], [3, 4, 2], check=False) (954, 1224) >>> [954 % m for m in [12, 6, 17]] [6, 0, 2] >>> crt([12, 6, 17], [3, 4, 2]) is None True >>> crt([3, 6], [2, 5]) (5, 6) Note: the order of gf_crt's arguments is reversed relative to crt, and that solve_congruence takes residue, modulus pairs. Programmer's note: rather than checking that all pairs of moduli share no GCD (an O(n**2) test) and rather than factoring all moduli and seeing that there is no factor in common, a check that the result gives the indicated residuals is performed -- an O(n) operation. See Also ======== solve_congruence sympy.polys.galoistools.gf_crt : low level crt routine used by this routine """ if check: m = list(map(as_int, m)) v = list(map(as_int, v)) result = gf_crt(v, m, ZZ) mm = prod(m) if check: if not all(v % m == result % m for v, m in zip(v, m)): result = solve_congruence(*list(zip(v, m)), check=False, symmetric=symmetric) if result is None: return result result, mm = result if symmetric: return symmetric_residue(result, mm), mm return result, mm def crt1(m): """First part of Chinese Remainder Theorem, for multiple application. Examples ======== >>> from sympy.ntheory.modular import crt1 >>> crt1([18, 42, 6]) (4536, [252, 108, 756], [0, 2, 0]) """ return gf_crt1(m, ZZ) def crt2(m, v, mm, e, s, symmetric=False): """Second part of Chinese Remainder Theorem, for multiple application. Examples ======== >>> from sympy.ntheory.modular import crt1, crt2 >>> mm, e, s = crt1([18, 42, 6]) >>> crt2([18, 42, 6], [0, 0, 0], mm, e, s) (0, 4536) """ result = gf_crt2(v, m, mm, e, s, ZZ) if symmetric: return symmetric_residue(result, mm), mm return result, mm def solve_congruence(*remainder_modulus_pairs, **hint): """Compute the integer ``n`` that has the residual ``ai`` when it is divided by ``mi`` where the ``ai`` and ``mi`` are given as pairs to this function: ((a1, m1), (a2, m2), ...). If there is no solution, return None. Otherwise return ``n`` and its modulus. The ``mi`` values need not be co-prime. If it is known that the moduli are not co-prime then the hint ``check`` can be set to False (default=True) and the check for a quicker solution via crt() (valid when the moduli are co-prime) will be skipped. If the hint ``symmetric`` is True (default is False), the value of ``n`` will be within 1/2 of the modulus, possibly negative. Examples ======== >>> from sympy.ntheory.modular import solve_congruence What number is 2 mod 3, 3 mod 5 and 2 mod 7? >>> solve_congruence((2, 3), (3, 5), (2, 7)) (23, 105) >>> [23 % m for m in [3, 5, 7]] [2, 3, 2] If you prefer to work with all remainder in one list and all moduli in another, send the arguments like this: >>> solve_congruence(*zip((2, 3, 2), (3, 5, 7))) (23, 105) The moduli need not be co-prime; in this case there may or may not be a solution: >>> solve_congruence((2, 3), (4, 6)) is None True >>> solve_congruence((2, 3), (5, 6)) (5, 6) The symmetric flag will make the result be within 1/2 of the modulus: >>> solve_congruence((2, 3), (5, 6), symmetric=True) (-1, 6) See Also ======== crt : high level routine implementing the Chinese Remainder Theorem """ def combine(c1, c2): """Return the tuple (a, m) which satisfies the requirement that n = a + i*m satisfy n = a1 + j*m1 and n = a2 = k*m2. References ========== - https://en.wikipedia.org/wiki/Method_of_successive_substitution """ a1, m1 = c1 a2, m2 = c2 a, b, c = m1, a2 - a1, m2 g = reduce(igcd, [a, b, c]) a, b, c = [i//g for i in [a, b, c]] if a != 1: inv_a, _, g = igcdex(a, c) if g != 1: return None b *= inv_a a, m = a1 + m1*b, m1*c return a, m rm = remainder_modulus_pairs symmetric = hint.get('symmetric', False) if hint.get('check', True): rm = [(as_int(r), as_int(m)) for r, m in rm] # ignore redundant pairs but raise an error otherwise; also # make sure that a unique set of bases is sent to gf_crt if # they are all prime. # # The routine will work out less-trivial violations and # return None, e.g. for the pairs (1,3) and (14,42) there # is no answer because 14 mod 42 (having a gcd of 14) implies # (14/2) mod (42/2), (14/7) mod (42/7) and (14/14) mod (42/14) # which, being 0 mod 3, is inconsistent with 1 mod 3. But to # preprocess the input beyond checking of another pair with 42 # or 3 as the modulus (for this example) is not necessary. uniq = {} for r, m in rm: r %= m if m in uniq: if r != uniq[m]: return None continue uniq[m] = r rm = [(r, m) for m, r in uniq.items()] del uniq # if the moduli are co-prime, the crt will be significantly faster; # checking all pairs for being co-prime gets to be slow but a prime # test is a good trade-off if all(isprime(m) for r, m in rm): r, m = list(zip(*rm)) return crt(m, r, symmetric=symmetric, check=False) rv = (0, 1) for rmi in rm: rv = combine(rv, rmi) if rv is None: break n, m = rv n = n % m else: if symmetric: return symmetric_residue(n, m), m return n, m sympy-sympy-1.9/sympy/ntheory/multinomial.py000066400000000000000000000117251412543434000215060ustar00rootroot00000000000000from sympy.core.compatibility import as_int def binomial_coefficients(n): """Return a dictionary containing pairs :math:`{(k1,k2) : C_kn}` where :math:`C_kn` are binomial coefficients and :math:`n=k1+k2`. Examples ======== >>> from sympy.ntheory import binomial_coefficients >>> binomial_coefficients(9) {(0, 9): 1, (1, 8): 9, (2, 7): 36, (3, 6): 84, (4, 5): 126, (5, 4): 126, (6, 3): 84, (7, 2): 36, (8, 1): 9, (9, 0): 1} See Also ======== binomial_coefficients_list, multinomial_coefficients """ n = as_int(n) d = {(0, n): 1, (n, 0): 1} a = 1 for k in range(1, n//2 + 1): a = (a * (n - k + 1))//k d[k, n - k] = d[n - k, k] = a return d def binomial_coefficients_list(n): """ Return a list of binomial coefficients as rows of the Pascal's triangle. Examples ======== >>> from sympy.ntheory import binomial_coefficients_list >>> binomial_coefficients_list(9) [1, 9, 36, 84, 126, 126, 84, 36, 9, 1] See Also ======== binomial_coefficients, multinomial_coefficients """ n = as_int(n) d = [1] * (n + 1) a = 1 for k in range(1, n//2 + 1): a = (a * (n - k + 1))//k d[k] = d[n - k] = a return d def multinomial_coefficients(m, n): r"""Return a dictionary containing pairs ``{(k1,k2,..,km) : C_kn}`` where ``C_kn`` are multinomial coefficients such that ``n=k1+k2+..+km``. Examples ======== >>> from sympy.ntheory import multinomial_coefficients >>> multinomial_coefficients(2, 5) # indirect doctest {(0, 5): 1, (1, 4): 5, (2, 3): 10, (3, 2): 10, (4, 1): 5, (5, 0): 1} Notes ===== The algorithm is based on the following result: .. math:: \binom{n}{k_1, \ldots, k_m} = \frac{k_1 + 1}{n - k_1} \sum_{i=2}^m \binom{n}{k_1 + 1, \ldots, k_i - 1, \ldots} Code contributed to Sage by Yann Laigle-Chapuy, copied with permission of the author. See Also ======== binomial_coefficients_list, binomial_coefficients """ m = as_int(m) n = as_int(n) if not m: if n: return {} return {(): 1} if m == 2: return binomial_coefficients(n) if m >= 2*n and n > 1: return dict(multinomial_coefficients_iterator(m, n)) t = [n] + [0] * (m - 1) r = {tuple(t): 1} if n: j = 0 # j will be the leftmost nonzero position else: j = m # enumerate tuples in co-lex order while j < m - 1: # compute next tuple tj = t[j] if j: t[j] = 0 t[0] = tj if tj > 1: t[j + 1] += 1 j = 0 start = 1 v = 0 else: j += 1 start = j + 1 v = r[tuple(t)] t[j] += 1 # compute the value # NB: the initialization of v was done above for k in range(start, m): if t[k]: t[k] -= 1 v += r[tuple(t)] t[k] += 1 t[0] -= 1 r[tuple(t)] = (v * tj) // (n - t[0]) return r def multinomial_coefficients_iterator(m, n, _tuple=tuple): """multinomial coefficient iterator This routine has been optimized for `m` large with respect to `n` by taking advantage of the fact that when the monomial tuples `t` are stripped of zeros, their coefficient is the same as that of the monomial tuples from ``multinomial_coefficients(n, n)``. Therefore, the latter coefficients are precomputed to save memory and time. >>> from sympy.ntheory.multinomial import multinomial_coefficients >>> m53, m33 = multinomial_coefficients(5,3), multinomial_coefficients(3,3) >>> m53[(0,0,0,1,2)] == m53[(0,0,1,0,2)] == m53[(1,0,2,0,0)] == m33[(0,1,2)] True Examples ======== >>> from sympy.ntheory.multinomial import multinomial_coefficients_iterator >>> it = multinomial_coefficients_iterator(20,3) >>> next(it) ((3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 1) """ m = as_int(m) n = as_int(n) if m < 2*n or n == 1: mc = multinomial_coefficients(m, n) yield from mc.items() else: mc = multinomial_coefficients(n, n) mc1 = {} for k, v in mc.items(): mc1[_tuple(filter(None, k))] = v mc = mc1 t = [n] + [0] * (m - 1) t1 = _tuple(t) b = _tuple(filter(None, t1)) yield (t1, mc[b]) if n: j = 0 # j will be the leftmost nonzero position else: j = m # enumerate tuples in co-lex order while j < m - 1: # compute next tuple tj = t[j] if j: t[j] = 0 t[0] = tj if tj > 1: t[j + 1] += 1 j = 0 else: j += 1 t[j] += 1 t[0] -= 1 t1 = _tuple(t) b = _tuple(filter(None, t1)) yield (t1, mc[b]) sympy-sympy-1.9/sympy/ntheory/partitions_.py000066400000000000000000000135221412543434000215040ustar00rootroot00000000000000from mpmath.libmp import (fzero, from_int, from_rational, fone, fhalf, bitcount, to_int, to_str, mpf_mul, mpf_div, mpf_sub, mpf_add, mpf_sqrt, mpf_pi, mpf_cosh_sinh, mpf_cos, mpf_sin) from sympy.core.numbers import igcd from .residue_ntheory import (_sqrt_mod_prime_power, legendre_symbol, jacobi_symbol, is_quad_residue) import math def _pre(): maxn = 10**5 global _factor global _totient _factor = [0]*maxn _totient = [1]*maxn lim = int(maxn**0.5) + 5 for i in range(2, lim): if _factor[i] == 0: for j in range(i*i, maxn, i): if _factor[j] == 0: _factor[j] = i for i in range(2, maxn): if _factor[i] == 0: _factor[i] = i _totient[i] = i-1 continue x = _factor[i] y = i//x if y % x == 0: _totient[i] = _totient[y]*x else: _totient[i] = _totient[y]*(x - 1) def _a(n, k, prec): """ Compute the inner sum in HRR formula [1]_ References ========== .. [1] http://msp.org/pjm/1956/6-1/pjm-v6-n1-p18-p.pdf """ if k == 1: return fone k1 = k e = 0 p = _factor[k] while k1 % p == 0: k1 //= p e += 1 k2 = k//k1 # k2 = p^e v = 1 - 24*n pi = mpf_pi(prec) if k1 == 1: # k = p^e if p == 2: mod = 8*k v = mod + v % mod v = (v*pow(9, k - 1, mod)) % mod m = _sqrt_mod_prime_power(v, 2, e + 3)[0] arg = mpf_div(mpf_mul( from_int(4*m), pi, prec), from_int(mod), prec) return mpf_mul(mpf_mul( from_int((-1)**e*jacobi_symbol(m - 1, m)), mpf_sqrt(from_int(k), prec), prec), mpf_sin(arg, prec), prec) if p == 3: mod = 3*k v = mod + v % mod if e > 1: v = (v*pow(64, k//3 - 1, mod)) % mod m = _sqrt_mod_prime_power(v, 3, e + 1)[0] arg = mpf_div(mpf_mul(from_int(4*m), pi, prec), from_int(mod), prec) return mpf_mul(mpf_mul( from_int(2*(-1)**(e + 1)*legendre_symbol(m, 3)), mpf_sqrt(from_int(k//3), prec), prec), mpf_sin(arg, prec), prec) v = k + v % k if v % p == 0: if e == 1: return mpf_mul( from_int(jacobi_symbol(3, k)), mpf_sqrt(from_int(k), prec), prec) return fzero if not is_quad_residue(v, p): return fzero _phi = p**(e - 1)*(p - 1) v = (v*pow(576, _phi - 1, k)) m = _sqrt_mod_prime_power(v, p, e)[0] arg = mpf_div( mpf_mul(from_int(4*m), pi, prec), from_int(k), prec) return mpf_mul(mpf_mul( from_int(2*jacobi_symbol(3, k)), mpf_sqrt(from_int(k), prec), prec), mpf_cos(arg, prec), prec) if p != 2 or e >= 3: d1, d2 = igcd(k1, 24), igcd(k2, 24) e = 24//(d1*d2) n1 = ((d2*e*n + (k2**2 - 1)//d1)* pow(e*k2*k2*d2, _totient[k1] - 1, k1)) % k1 n2 = ((d1*e*n + (k1**2 - 1)//d2)* pow(e*k1*k1*d1, _totient[k2] - 1, k2)) % k2 return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec) if e == 2: n1 = ((8*n + 5)*pow(128, _totient[k1] - 1, k1)) % k1 n2 = (4 + ((n - 2 - (k1**2 - 1)//8)*(k1**2)) % 4) % 4 return mpf_mul(mpf_mul( from_int(-1), _a(n1, k1, prec), prec), _a(n2, k2, prec)) n1 = ((8*n + 1)*pow(32, _totient[k1] - 1, k1)) % k1 n2 = (2 + (n - (k1**2 - 1)//8) % 2) % 2 return mpf_mul(_a(n1, k1, prec), _a(n2, k2, prec), prec) def _d(n, j, prec, sq23pi, sqrt8): """ Compute the sinh term in the outer sum of the HRR formula. The constants sqrt(2/3*pi) and sqrt(8) must be precomputed. """ j = from_int(j) pi = mpf_pi(prec) a = mpf_div(sq23pi, j, prec) b = mpf_sub(from_int(n), from_rational(1, 24, prec), prec) c = mpf_sqrt(b, prec) ch, sh = mpf_cosh_sinh(mpf_mul(a, c), prec) D = mpf_div( mpf_sqrt(j, prec), mpf_mul(mpf_mul(sqrt8, b), pi), prec) E = mpf_sub(mpf_mul(a, ch), mpf_div(sh, c, prec), prec) return mpf_mul(D, E) def npartitions(n, verbose=False): """ Calculate the partition function P(n), i.e. the number of ways that n can be written as a sum of positive integers. P(n) is computed using the Hardy-Ramanujan-Rademacher formula [1]_. The correctness of this implementation has been tested through 10**10. Examples ======== >>> from sympy.ntheory import npartitions >>> npartitions(25) 1958 References ========== .. [1] http://mathworld.wolfram.com/PartitionFunctionP.html """ n = int(n) if n < 0: return 0 if n <= 5: return [1, 1, 2, 3, 5, 7][n] if '_factor' not in globals(): _pre() # Estimate number of bits in p(n). This formula could be tidied pbits = int(( math.pi*(2*n/3.)**0.5 - math.log(4*n))/math.log(10) + 1) * \ math.log(10, 2) prec = p = int(pbits*1.1 + 100) s = fzero M = max(6, int(0.24*n**0.5 + 4)) if M > 10**5: raise ValueError("Input too big") # Corresponds to n > 1.7e11 sq23pi = mpf_mul(mpf_sqrt(from_rational(2, 3, p), p), mpf_pi(p), p) sqrt8 = mpf_sqrt(from_int(8), p) for q in range(1, M): a = _a(n, q, p) d = _d(n, q, p, sq23pi, sqrt8) s = mpf_add(s, mpf_mul(a, d), prec) if verbose: print("step", q, "of", M, to_str(a, 10), to_str(d, 10)) # On average, the terms decrease rapidly in magnitude. # Dynamically reducing the precision greatly improves # performance. p = bitcount(abs(to_int(d))) + 50 return int(to_int(mpf_add(s, fhalf, prec))) __all__ = ['npartitions'] sympy-sympy-1.9/sympy/ntheory/primetest.py000066400000000000000000000456621412543434000211770ustar00rootroot00000000000000""" Primality testing """ from sympy.core.compatibility import as_int from mpmath.libmp import bitcount as _bitlength def _int_tuple(*i): return tuple(int(_) for _ in i) def is_euler_pseudoprime(n, b): """Returns True if n is prime or an Euler pseudoprime to base b, else False. Euler Pseudoprime : In arithmetic, an odd composite integer n is called an euler pseudoprime to base a, if a and n are coprime and satisfy the modular arithmetic congruence relation : a ^ (n-1)/2 = + 1(mod n) or a ^ (n-1)/2 = - 1(mod n) (where mod refers to the modulo operation). Examples ======== >>> from sympy.ntheory.primetest import is_euler_pseudoprime >>> is_euler_pseudoprime(2, 5) True References ========== .. [1] https://en.wikipedia.org/wiki/Euler_pseudoprime """ from sympy.ntheory.factor_ import trailing if not mr(n, [b]): return False n = as_int(n) r = n - 1 c = pow(b, r >> trailing(r), n) if c == 1: return True while True: if c == n - 1: return True c = pow(c, 2, n) if c == 1: return False def is_square(n, prep=True): """Return True if n == a * a for some integer a, else False. If n is suspected of *not* being a square then this is a quick method of confirming that it is not. Examples ======== >>> from sympy.ntheory.primetest import is_square >>> is_square(25) True >>> is_square(2) False References ========== [1] http://mersenneforum.org/showpost.php?p=110896 See Also ======== sympy.core.power.integer_nthroot """ if prep: n = as_int(n) if n < 0: return False if n in [0, 1]: return True m = n & 127 if not ((m*0x8bc40d7d) & (m*0xa1e2f5d1) & 0x14020a): m = n % 63 if not ((m*0x3d491df7) & (m*0xc824a9f9) & 0x10f14008): from sympy.core.power import integer_nthroot return integer_nthroot(n, 2)[1] return False def _test(n, base, s, t): """Miller-Rabin strong pseudoprime test for one base. Return False if n is definitely composite, True if n is probably prime, with a probability greater than 3/4. """ # do the Fermat test b = pow(base, t, n) if b == 1 or b == n - 1: return True else: for j in range(1, s): b = pow(b, 2, n) if b == n - 1: return True # see I. Niven et al. "An Introduction to Theory of Numbers", page 78 if b == 1: return False return False def mr(n, bases): """Perform a Miller-Rabin strong pseudoprime test on n using a given list of bases/witnesses. References ========== - Richard Crandall & Carl Pomerance (2005), "Prime Numbers: A Computational Perspective", Springer, 2nd edition, 135-138 A list of thresholds and the bases they require are here: https://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test#Deterministic_variants Examples ======== >>> from sympy.ntheory.primetest import mr >>> mr(1373651, [2, 3]) False >>> mr(479001599, [31, 73]) True """ from sympy.ntheory.factor_ import trailing from sympy.polys.domains import ZZ n = as_int(n) if n < 2: return False # remove powers of 2 from n-1 (= t * 2**s) s = trailing(n - 1) t = n >> s for base in bases: # Bases >= n are wrapped, bases < 2 are invalid if base >= n: base %= n if base >= 2: base = ZZ(base) if not _test(n, base, s, t): return False return True def _lucas_sequence(n, P, Q, k): """Return the modular Lucas sequence (U_k, V_k, Q_k). Given a Lucas sequence defined by P, Q, returns the kth values for U and V, along with Q^k, all modulo n. This is intended for use with possibly very large values of n and k, where the combinatorial functions would be completely unusable. The modular Lucas sequences are used in numerous places in number theory, especially in the Lucas compositeness tests and the various n + 1 proofs. Examples ======== >>> from sympy.ntheory.primetest import _lucas_sequence >>> N = 10**2000 + 4561 >>> sol = U, V, Qk = _lucas_sequence(N, 3, 1, N//2); sol (0, 2, 1) """ D = P*P - 4*Q if n < 2: raise ValueError("n must be >= 2") if k < 0: raise ValueError("k must be >= 0") if D == 0: raise ValueError("D must not be zero") if k == 0: return _int_tuple(0, 2, Q) U = 1 V = P Qk = Q b = _bitlength(k) if Q == 1: # Optimization for extra strong tests. while b > 1: U = (U*V) % n V = (V*V - 2) % n b -= 1 if (k >> (b - 1)) & 1: U, V = U*P + V, V*P + U*D if U & 1: U += n if V & 1: V += n U, V = U >> 1, V >> 1 elif P == 1 and Q == -1: # Small optimization for 50% of Selfridge parameters. while b > 1: U = (U*V) % n if Qk == 1: V = (V*V - 2) % n else: V = (V*V + 2) % n Qk = 1 b -= 1 if (k >> (b-1)) & 1: U, V = U + V, V + U*D if U & 1: U += n if V & 1: V += n U, V = U >> 1, V >> 1 Qk = -1 else: # The general case with any P and Q. while b > 1: U = (U*V) % n V = (V*V - 2*Qk) % n Qk *= Qk b -= 1 if (k >> (b - 1)) & 1: U, V = U*P + V, V*P + U*D if U & 1: U += n if V & 1: V += n U, V = U >> 1, V >> 1 Qk *= Q Qk %= n return _int_tuple(U % n, V % n, Qk) def _lucas_selfridge_params(n): """Calculates the Selfridge parameters (D, P, Q) for n. This is method A from page 1401 of Baillie and Wagstaff. References ========== - "Lucas Pseudoprimes", Baillie and Wagstaff, 1980. http://mpqs.free.fr/LucasPseudoprimes.pdf """ from sympy.core import igcd from sympy.ntheory.residue_ntheory import jacobi_symbol D = 5 while True: g = igcd(abs(D), n) if g > 1 and g != n: return (0, 0, 0) if jacobi_symbol(D, n) == -1: break if D > 0: D = -D - 2 else: D = -D + 2 return _int_tuple(D, 1, (1 - D)/4) def _lucas_extrastrong_params(n): """Calculates the "extra strong" parameters (D, P, Q) for n. References ========== - OEIS A217719: Extra Strong Lucas Pseudoprimes https://oeis.org/A217719 - https://en.wikipedia.org/wiki/Lucas_pseudoprime """ from sympy.core import igcd from sympy.ntheory.residue_ntheory import jacobi_symbol P, Q, D = 3, 1, 5 while True: g = igcd(D, n) if g > 1 and g != n: return (0, 0, 0) if jacobi_symbol(D, n) == -1: break P += 1 D = P*P - 4 return _int_tuple(D, P, Q) def is_lucas_prp(n): """Standard Lucas compositeness test with Selfridge parameters. Returns False if n is definitely composite, and True if n is a Lucas probable prime. This is typically used in combination with the Miller-Rabin test. References ========== - "Lucas Pseudoprimes", Baillie and Wagstaff, 1980. http://mpqs.free.fr/LucasPseudoprimes.pdf - OEIS A217120: Lucas Pseudoprimes https://oeis.org/A217120 - https://en.wikipedia.org/wiki/Lucas_pseudoprime Examples ======== >>> from sympy.ntheory.primetest import isprime, is_lucas_prp >>> for i in range(10000): ... if is_lucas_prp(i) and not isprime(i): ... print(i) 323 377 1159 1829 3827 5459 5777 9071 9179 """ n = as_int(n) if n == 2: return True if n < 2 or (n % 2) == 0: return False if is_square(n, False): return False D, P, Q = _lucas_selfridge_params(n) if D == 0: return False U, V, Qk = _lucas_sequence(n, P, Q, n+1) return U == 0 def is_strong_lucas_prp(n): """Strong Lucas compositeness test with Selfridge parameters. Returns False if n is definitely composite, and True if n is a strong Lucas probable prime. This is often used in combination with the Miller-Rabin test, and in particular, when combined with M-R base 2 creates the strong BPSW test. References ========== - "Lucas Pseudoprimes", Baillie and Wagstaff, 1980. http://mpqs.free.fr/LucasPseudoprimes.pdf - OEIS A217255: Strong Lucas Pseudoprimes https://oeis.org/A217255 - https://en.wikipedia.org/wiki/Lucas_pseudoprime - https://en.wikipedia.org/wiki/Baillie-PSW_primality_test Examples ======== >>> from sympy.ntheory.primetest import isprime, is_strong_lucas_prp >>> for i in range(20000): ... if is_strong_lucas_prp(i) and not isprime(i): ... print(i) 5459 5777 10877 16109 18971 """ from sympy.ntheory.factor_ import trailing n = as_int(n) if n == 2: return True if n < 2 or (n % 2) == 0: return False if is_square(n, False): return False D, P, Q = _lucas_selfridge_params(n) if D == 0: return False # remove powers of 2 from n+1 (= k * 2**s) s = trailing(n + 1) k = (n+1) >> s U, V, Qk = _lucas_sequence(n, P, Q, k) if U == 0 or V == 0: return True for r in range(1, s): V = (V*V - 2*Qk) % n if V == 0: return True Qk = pow(Qk, 2, n) return False def is_extra_strong_lucas_prp(n): """Extra Strong Lucas compositeness test. Returns False if n is definitely composite, and True if n is a "extra strong" Lucas probable prime. The parameters are selected using P = 3, Q = 1, then incrementing P until (D|n) == -1. The test itself is as defined in Grantham 2000, from the Mo and Jones preprint. The parameter selection and test are the same as used in OEIS A217719, Perl's Math::Prime::Util, and the Lucas pseudoprime page on Wikipedia. With these parameters, there are no counterexamples below 2^64 nor any known above that range. It is 20-50% faster than the strong test. Because of the different parameters selected, there is no relationship between the strong Lucas pseudoprimes and extra strong Lucas pseudoprimes. In particular, one is not a subset of the other. References ========== - "Frobenius Pseudoprimes", Jon Grantham, 2000. http://www.ams.org/journals/mcom/2001-70-234/S0025-5718-00-01197-2/ - OEIS A217719: Extra Strong Lucas Pseudoprimes https://oeis.org/A217719 - https://en.wikipedia.org/wiki/Lucas_pseudoprime Examples ======== >>> from sympy.ntheory.primetest import isprime, is_extra_strong_lucas_prp >>> for i in range(20000): ... if is_extra_strong_lucas_prp(i) and not isprime(i): ... print(i) 989 3239 5777 10877 """ # Implementation notes: # 1) the parameters differ from Thomas R. Nicely's. His parameter # selection leads to pseudoprimes that overlap M-R tests, and # contradict Baillie and Wagstaff's suggestion of (D|n) = -1. # 2) The MathWorld page as of June 2013 specifies Q=-1. The Lucas # sequence must have Q=1. See Grantham theorem 2.3, any of the # references on the MathWorld page, or run it and see Q=-1 is wrong. from sympy.ntheory.factor_ import trailing n = as_int(n) if n == 2: return True if n < 2 or (n % 2) == 0: return False if is_square(n, False): return False D, P, Q = _lucas_extrastrong_params(n) if D == 0: return False # remove powers of 2 from n+1 (= k * 2**s) s = trailing(n + 1) k = (n+1) >> s U, V, Qk = _lucas_sequence(n, P, Q, k) if U == 0 and (V == 2 or V == n - 2): return True for r in range(1, s): if V == 0: return True V = (V*V - 2) % n return False def isprime(n): """ Test if n is a prime number (True) or not (False). For n < 2^64 the answer is definitive; larger n values have a small probability of actually being pseudoprimes. Negative numbers (e.g. -2) are not considered prime. The first step is looking for trivial factors, which if found enables a quick return. Next, if the sieve is large enough, use bisection search on the sieve. For small numbers, a set of deterministic Miller-Rabin tests are performed with bases that are known to have no counterexamples in their range. Finally if the number is larger than 2^64, a strong BPSW test is performed. While this is a probable prime test and we believe counterexamples exist, there are no known counterexamples. Examples ======== >>> from sympy.ntheory import isprime >>> isprime(13) True >>> isprime(13.0) # limited precision False >>> isprime(15) False Notes ===== This routine is intended only for integer input, not numerical expressions which may represent numbers. Floats are also rejected as input because they represent numbers of limited precision. While it is tempting to permit 7.0 to represent an integer there are errors that may "pass silently" if this is allowed: >>> from sympy import Float, S >>> int(1e3) == 1e3 == 10**3 True >>> int(1e23) == 1e23 True >>> int(1e23) == 10**23 False >>> near_int = 1 + S(1)/10**19 >>> near_int == int(near_int) False >>> n = Float(near_int, 10) # truncated by precision >>> n == int(n) True >>> n = Float(near_int, 20) >>> n == int(n) False See Also ======== sympy.ntheory.generate.primerange : Generates all primes in a given range sympy.ntheory.generate.primepi : Return the number of primes less than or equal to n sympy.ntheory.generate.prime : Return the nth prime References ========== - https://en.wikipedia.org/wiki/Strong_pseudoprime - "Lucas Pseudoprimes", Baillie and Wagstaff, 1980. http://mpqs.free.fr/LucasPseudoprimes.pdf - https://en.wikipedia.org/wiki/Baillie-PSW_primality_test """ try: n = as_int(n) except ValueError: return False # Step 1, do quick composite testing via trial division. The individual # modulo tests benchmark faster than one or two primorial igcds for me. # The point here is just to speedily handle small numbers and many # composites. Step 2 only requires that n <= 2 get handled here. if n in [2, 3, 5]: return True if n < 2 or (n % 2) == 0 or (n % 3) == 0 or (n % 5) == 0: return False if n < 49: return True if (n % 7) == 0 or (n % 11) == 0 or (n % 13) == 0 or (n % 17) == 0 or \ (n % 19) == 0 or (n % 23) == 0 or (n % 29) == 0 or (n % 31) == 0 or \ (n % 37) == 0 or (n % 41) == 0 or (n % 43) == 0 or (n % 47) == 0: return False if n < 2809: return True if n <= 23001: return pow(2, n, n) == 2 and n not in [7957, 8321, 13747, 18721, 19951] # bisection search on the sieve if the sieve is large enough from sympy.ntheory.generate import sieve as s if n <= s._list[-1]: l, u = s.search(n) return l == u # If we have GMPY2, skip straight to step 3 and do a strong BPSW test. # This should be a bit faster than our step 2, and for large values will # be a lot faster than our step 3 (C+GMP vs. Python). from sympy.core.compatibility import HAS_GMPY if HAS_GMPY == 2: from gmpy2 import is_strong_prp, is_strong_selfridge_prp return is_strong_prp(n, 2) and is_strong_selfridge_prp(n) # Step 2: deterministic Miller-Rabin testing for numbers < 2^64. See: # https://miller-rabin.appspot.com/ # for lists. We have made sure the M-R routine will successfully handle # bases larger than n, so we can use the minimal set. if n < 341531: return mr(n, [9345883071009581737]) if n < 885594169: return mr(n, [725270293939359937, 3569819667048198375]) if n < 350269456337: return mr(n, [4230279247111683200, 14694767155120705706, 16641139526367750375]) if n < 55245642489451: return mr(n, [2, 141889084524735, 1199124725622454117, 11096072698276303650]) if n < 7999252175582851: return mr(n, [2, 4130806001517, 149795463772692060, 186635894390467037, 3967304179347715805]) if n < 585226005592931977: return mr(n, [2, 123635709730000, 9233062284813009, 43835965440333360, 761179012939631437, 1263739024124850375]) if n < 18446744073709551616: return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022]) # We could do this instead at any point: #if n < 18446744073709551616: # return mr(n, [2]) and is_extra_strong_lucas_prp(n) # Here are tests that are safe for MR routines that don't understand # large bases. #if n < 9080191: # return mr(n, [31, 73]) #if n < 19471033: # return mr(n, [2, 299417]) #if n < 38010307: # return mr(n, [2, 9332593]) #if n < 316349281: # return mr(n, [11000544, 31481107]) #if n < 4759123141: # return mr(n, [2, 7, 61]) #if n < 105936894253: # return mr(n, [2, 1005905886, 1340600841]) #if n < 31858317218647: # return mr(n, [2, 642735, 553174392, 3046413974]) #if n < 3071837692357849: # return mr(n, [2, 75088, 642735, 203659041, 3613982119]) #if n < 18446744073709551616: # return mr(n, [2, 325, 9375, 28178, 450775, 9780504, 1795265022]) # Step 3: BPSW. # # Time for isprime(10**2000 + 4561), no gmpy or gmpy2 installed # 44.0s old isprime using 46 bases # 5.3s strong BPSW + one random base # 4.3s extra strong BPSW + one random base # 4.1s strong BPSW # 3.2s extra strong BPSW # Classic BPSW from page 1401 of the paper. See alternate ideas below. return mr(n, [2]) and is_strong_lucas_prp(n) # Using extra strong test, which is somewhat faster #return mr(n, [2]) and is_extra_strong_lucas_prp(n) # Add a random M-R base #import random #return mr(n, [2, random.randint(3, n-1)]) and is_strong_lucas_prp(n) def is_gaussian_prime(num): r"""Test if num is a Gaussian prime number. References ========== .. [1] https://oeis.org/wiki/Gaussian_primes """ from sympy import sympify num = sympify(num) a, b = num.as_real_imag() a = as_int(a, strict=False) b = as_int(b, strict=False) if a == 0: b = abs(b) return isprime(b) and b % 4 == 3 elif b == 0: a = abs(a) return isprime(a) and a % 4 == 3 return isprime(a**2 + b**2) sympy-sympy-1.9/sympy/ntheory/qs.py000066400000000000000000000437621412543434000176050ustar00rootroot00000000000000from sympy.core.numbers import igcd, mod_inverse from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power from sympy.ntheory import isprime from math import log, sqrt import random rgen = random.Random() class SievePolynomial: def __init__(self, modified_coeff=[], a=None, b=None): """This class denotes the seive polynomial. If ``g(x) = (a*x + b)**2 - N``. `g(x)` can be expanded to ``a*x**2 + 2*a*b*x + b**2 - N``, so the coefficient is stored in the form `[a**2, 2*a*b, b**2 - N]`. This ensures faster `eval` method because we dont have to perform `a**2, 2*a*b, b**2` every time we call the `eval` method. As multiplication is more expensive than addition, by using modified_coefficient we get a faster seiving process. Parameters ========== modified_coeff : modified_coefficient of sieve polynomial a : parameter of the sieve polynomial b : parameter of the sieve polynomial """ self.modified_coeff = modified_coeff self.a = a self.b = b def eval(self, x): """ Compute the value of the sieve polynomial at point x. Parameters ========== x : Integer parameter for sieve polynomial """ ans = 0 for coeff in self.modified_coeff: ans *= x ans += coeff return ans class FactorBaseElem: """This class stores an element of the `factor_base`. """ def __init__(self, prime, tmem_p, log_p): """ Initialization of factor_base_elem. Parameters ========== prime : prime number of the factor_base tmem_p : Integer square root of x**2 = n mod prime log_p : Compute Natural Logarithm of the prime """ self.prime = prime self.tmem_p = tmem_p self.log_p = log_p self.soln1 = None self.soln2 = None self.a_inv = None self.b_ainv = None def _generate_factor_base(prime_bound, n): """Generate `factor_base` for Quadratic Sieve. The `factor_base` consists of all the the points whose ``legendre_symbol(n, p) == 1`` and ``p < num_primes``. Along with the prime `factor_base` also stores natural logarithm of prime and the residue n modulo p. It also returns the of primes numbers in the `factor_base` which are close to 1000 and 5000. Parameters ========== prime_bound : upper prime bound of the factor_base n : integer to be factored """ from sympy import sieve factor_base = [] idx_1000, idx_5000 = None, None for prime in sieve.primerange(1, prime_bound): if pow(n, (prime - 1) // 2, prime) == 1: if prime > 1000 and idx_1000 is None: idx_1000 = len(factor_base) - 1 if prime > 5000 and idx_5000 is None: idx_5000 = len(factor_base) - 1 residue = _sqrt_mod_prime_power(n, prime, 1)[0] log_p = round(log(prime)*2**10) factor_base.append(FactorBaseElem(prime, residue, log_p)) return idx_1000, idx_5000, factor_base def _initialize_first_polynomial(N, M, factor_base, idx_1000, idx_5000, seed=None): """This step is the initialization of the 1st sieve polynomial. Here `a` is selected as a product of several primes of the factor_base such that `a` is about to ``sqrt(2*N) / M``. Other initial values of factor_base elem are also intialized which includes a_inv, b_ainv, soln1, soln2 which are used when the sieve polynomial is changed. The b_ainv is required for fast polynomial change as we don't have to calculate `2*b*mod_inverse(a, prime)` every time. We also ensure that the `factor_base` primes which make `a` are between 1000 and 5000. Parameters ========== N : Number to be factored M : sieve interval factor_base : factor_base primes idx_1000 : index of prime numbe in the factor_base near 1000 idx_5000 : index of primenumber in the factor_base near to 5000 seed : Generate pseudoprime numbers """ if seed is not None: rgen.seed(seed) approx_val = sqrt(2*N) / M # `a` is a parameter of the sieve polynomial and `q` is the prime factors of `a` # randomly search for a combination of primes whose multiplication is close to approx_val # This multiplication of primes will be `a` and the primes will be `q` # `best_a` denotes that `a` is close to approx_val in the random search of combination best_a, best_q, best_ratio = None, None, None start = 0 if idx_1000 is None else idx_1000 end = len(factor_base) - 1 if idx_5000 is None else idx_5000 for _ in range(50): a = 1 q = [] while(a < approx_val): rand_p = 0 while(rand_p == 0 or rand_p in q): rand_p = rgen.randint(start, end) p = factor_base[rand_p].prime a *= p q.append(rand_p) ratio = a / approx_val if best_ratio is None or abs(ratio - 1) < abs(best_ratio - 1): best_q = q best_a = a best_ratio = ratio a = best_a q = best_q B = [] for idx, val in enumerate(q): q_l = factor_base[val].prime gamma = factor_base[val].tmem_p * mod_inverse(a // q_l, q_l) % q_l if gamma > q_l / 2: gamma = q_l - gamma B.append(a//q_l*gamma) b = sum(B) g = SievePolynomial([a*a, 2*a*b, b*b - N], a, b) for fb in factor_base: if a % fb.prime == 0: continue fb.a_inv = mod_inverse(a, fb.prime) fb.b_ainv = [2*b_elem*fb.a_inv % fb.prime for b_elem in B] fb.soln1 = (fb.a_inv*(fb.tmem_p - b)) % fb.prime fb.soln2 = (fb.a_inv*(-fb.tmem_p - b)) % fb.prime return g, B def _initialize_ith_poly(N, factor_base, i, g, B): """Initialization stage of ith poly. After we finish sieving 1`st polynomial here we quickly change to the next polynomial from which we will again start sieving. Suppose we generated ith sieve polynomial and now we want to generate (i + 1)th polynomial, where ``1 <= i <= 2**(j - 1) - 1`` where `j` is the number of prime factors of the coefficient `a` then this function can be used to go to the next polynomial. If ``i = 2**(j - 1) - 1`` then go to _initialize_first_polynomial stage. Parameters ========== N : number to be factored factor_base : factor_base primes i : integer denoting ith polynomial g : (i - 1)th polynomial B : array that stores a//q_l*gamma """ from sympy import ceiling v = 1 j = i while(j % 2 == 0): v += 1 j //= 2 if ceiling(i / (2**v)) % 2 == 1: neg_pow = -1 else: neg_pow = 1 b = g.b + 2*neg_pow*B[v - 1] a = g.a g = SievePolynomial([a*a, 2*a*b, b*b - N], a, b) for fb in factor_base: if a % fb.prime == 0: continue fb.soln1 = (fb.soln1 - neg_pow*fb.b_ainv[v - 1]) % fb.prime fb.soln2 = (fb.soln2 - neg_pow*fb.b_ainv[v - 1]) % fb.prime return g def _gen_sieve_array(M, factor_base): """Sieve Stage of the Quadratic Sieve. For every prime in the factor_base that doesn't divide the coefficient `a` we add log_p over the sieve_array such that ``-M <= soln1 + i*p <= M`` and ``-M <= soln2 + i*p <= M`` where `i` is an integer. When p = 2 then log_p is only added using ``-M <= soln1 + i*p <= M``. Parameters ========== M : sieve interval factor_base : factor_base primes """ sieve_array = [0]*(2*M + 1) for factor in factor_base: if factor.soln1 is None: #The prime does not divides a continue for idx in range((M + factor.soln1) % factor.prime, 2*M, factor.prime): sieve_array[idx] += factor.log_p if factor.prime == 2: continue #if prime is 2 then sieve only with soln_1_p for idx in range((M + factor.soln2) % factor.prime, 2*M, factor.prime): sieve_array[idx] += factor.log_p return sieve_array def _check_smoothness(num, factor_base): """Here we check that if `num` is a smooth number or not. If `a` is a smooth number then it returns a vector of prime exponents modulo 2. For example if a = 2 * 5**2 * 7**3 and the factor base contains {2, 3, 5, 7} then `a` is a smooth number and this function returns ([1, 0, 0, 1], True). If `a` is a partial relation which means that `a` a has one prime factor greater than the `factor_base` then it returns `(a, False)` which denotes `a` is a partial relation. Parameters ========== a : integer whose smootheness is to be checked factor_base : factor_base primes """ vec = [] if num < 0: vec.append(1) num *= -1 else: vec.append(0) #-1 is not included in factor_base add -1 in vector for factor in factor_base: if num % factor.prime != 0: vec.append(0) continue factor_exp = 0 while num % factor.prime == 0: factor_exp += 1 num //= factor.prime vec.append(factor_exp % 2) if num == 1: return vec, True if isprime(num): return num, False return None, None def _trial_division_stage(N, M, factor_base, sieve_array, sieve_poly, partial_relations, ERROR_TERM): """Trial division stage. Here we trial divide the values generetated by sieve_poly in the sieve interval and if it is a smooth number then it is stored in `smooth_relations`. Moreover, if we find two partial relations with same large prime then they are combined to form a smooth relation. First we iterate over sieve array and look for values which are greater than accumulated_val, as these values have a high chance of being smooth number. Then using these values we find smooth relations. In general, let ``t**2 = u*p modN`` and ``r**2 = v*p modN`` be two partial relations with the same large prime p. Then they can be combined ``(t*r/p)**2 = u*v modN`` to form a smooth relation. Parameters ========== N : Number to be factored M : sieve interval factor_base : factor_base primes sieve_array : stores log_p values sieve_poly : polynomial from which we find smooth relations partial_relations : stores partial relations with one large prime ERROR_TERM : error term for accumulated_val """ sqrt_n = sqrt(float(N)) accumulated_val = log(M * sqrt_n)*2**10 - ERROR_TERM smooth_relations = [] proper_factor = set() partial_relation_upper_bound = 128*factor_base[-1].prime for idx, val in enumerate(sieve_array): if val < accumulated_val: continue x = idx - M v = sieve_poly.eval(x) vec, is_smooth = _check_smoothness(v, factor_base) if is_smooth is None:#Neither smooth nor partial continue u = sieve_poly.a*x + sieve_poly.b # Update the partial relation # If 2 partial relation with same large prime is found then generate smooth relation if is_smooth is False:#partial relation found large_prime = vec #Consider the large_primes under 128*F if large_prime > partial_relation_upper_bound: continue if large_prime not in partial_relations: partial_relations[large_prime] = (u, v) continue else: u_prev, v_prev = partial_relations[large_prime] partial_relations.pop(large_prime) try: large_prime_inv = mod_inverse(large_prime, N) except ValueError:#if large_prine divides N proper_factor.add(large_prime) continue u = u*u_prev*large_prime_inv v = v*v_prev // (large_prime*large_prime) vec, is_smooth = _check_smoothness(v, factor_base) #assert u*u % N == v % N smooth_relations.append((u, v, vec)) return smooth_relations, proper_factor #LINEAR ALGEBRA STAGE def _build_matrix(smooth_relations): """Build a 2D matrix from smooth relations. Parameters ========== smooth_relations : Stores smooth relations """ matrix = [] for s_relation in smooth_relations: matrix.append(s_relation[2]) return matrix def _gauss_mod_2(A): """Fast gaussian reduction for modulo 2 matrix. Parameters ========== A : Matrix Examples ======== >>> from sympy.ntheory.qs import _gauss_mod_2 >>> _gauss_mod_2([[0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 1, 1]]) ([[[1, 0, 1], 3]], [True, True, True, False], [[0, 1, 0], [1, 0, 0], [0, 0, 1], [1, 0, 1]]) Reference ========== .. [1] A fast algorithm for gaussian elimination over GF(2) and its implementation on the GAPP. Cetin K.Koc, Sarath N.Arachchige""" import copy matrix = copy.deepcopy(A) row = len(matrix) col = len(matrix[0]) mark = [False]*row for c in range(col): for r in range(row): if matrix[r][c] == 1: break mark[r] = True for c1 in range(col): if c1 == c: continue if matrix[r][c1] == 1: for r2 in range(row): matrix[r2][c1] = (matrix[r2][c1] + matrix[r2][c]) % 2 dependent_row = [] for idx, val in enumerate(mark): if val == False: dependent_row.append([matrix[idx], idx]) return dependent_row, mark, matrix def _find_factor(dependent_rows, mark, gauss_matrix, index, smooth_relations, N): """Finds proper factor of N. Here, transform the dependent rows as a combination of independent rows of the gauss_matrix to form the desired relation of the form ``X**2 = Y**2 modN``. After obtaining the desired relation we obtain a proper factor of N by `gcd(X - Y, N)`. Parameters ========== dependent_rows : denoted dependent rows in the reduced matrix form mark : boolean array to denoted dependent and independent rows gauss_matrix : Reduced form of the smooth relations matrix index : denoted the index of the dependent_rows smooth_relations : Smooth relations vectors matrix N : Number to be factored """ from sympy import integer_nthroot idx_in_smooth = dependent_rows[index][1] independent_u = [smooth_relations[idx_in_smooth][0]] independent_v = [smooth_relations[idx_in_smooth][1]] dept_row = dependent_rows[index][0] for idx, val in enumerate(dept_row): if val == 1: for row in range(len(gauss_matrix)): if gauss_matrix[row][idx] == 1 and mark[row] == True: independent_u.append(smooth_relations[row][0]) independent_v.append(smooth_relations[row][1]) break u = 1 v = 1 for i in independent_u: u *= i for i in independent_v: v *= i #assert u**2 % N == v % N v = integer_nthroot(v, 2)[0] return igcd(u - v, N) def qs(N, prime_bound, M, ERROR_TERM=25, seed=1234): """Performs factorization using Self-Initializing Quadratic Sieve. In SIQS, let N be a number to be factored, and this N should not be a perfect power. If we find two integers such that ``X**2 = Y**2 modN`` and ``X != +-Y modN``, then `gcd(X + Y, N)` will reveal a proper factor of N. In order to find these integers X and Y we try to find relations of form t**2 = u modN where u is a product of small primes. If we have enough of these relations then we can form ``(t1*t2...ti)**2 = u1*u2...ui modN`` such that the right hand side is a square, thus we found a relation of ``X**2 = Y**2 modN``. Here, several optimizations are done like using muliple polynomials for sieving, fast changing between polynomials and using partial relations. The use of partial relations can speeds up the factoring by 2 times. Parameters ========== N : Number to be Factored prime_bound : upper bound for primes in the factor base M : Sieve Interval ERROR_TERM : Error term for checking smoothness threshold : Extra smooth relations for factorization seed : generate pseudo prime numbers Examples ======== >>> from sympy.ntheory import qs >>> qs(25645121643901801, 2000, 10000) {5394769, 4753701529} >>> qs(9804659461513846513, 2000, 10000) {4641991, 2112166839943} References ========== .. [1] https://pdfs.semanticscholar.org/5c52/8a975c1405bd35c65993abf5a4edb667c1db.pdf .. [2] https://www.rieselprime.de/ziki/Self-initializing_quadratic_sieve """ ERROR_TERM*=2**10 rgen.seed(seed) idx_1000, idx_5000, factor_base = _generate_factor_base(prime_bound, N) smooth_relations = [] ith_poly = 0 partial_relations = {} proper_factor = set() threshold = 5*len(factor_base) // 100 while True: if ith_poly == 0: ith_sieve_poly, B_array = _initialize_first_polynomial(N, M, factor_base, idx_1000, idx_5000) else: ith_sieve_poly = _initialize_ith_poly(N, factor_base, ith_poly, ith_sieve_poly, B_array) ith_poly += 1 if ith_poly >= 2**(len(B_array) - 1): # time to start with a new sieve polynomial ith_poly = 0 sieve_array = _gen_sieve_array(M, factor_base) s_rel, p_f = _trial_division_stage(N, M, factor_base, sieve_array, ith_sieve_poly, partial_relations, ERROR_TERM) smooth_relations += s_rel proper_factor |= p_f if len(smooth_relations) >= len(factor_base) + threshold: break matrix = _build_matrix(smooth_relations) dependent_row, mark, gauss_matrix = _gauss_mod_2(matrix) N_copy = N for index in range(len(dependent_row)): factor = _find_factor(dependent_row, mark, gauss_matrix, index, smooth_relations, N) if factor > 1 and factor < N: proper_factor.add(factor) while(N_copy % factor == 0): N_copy //= factor if isprime(N_copy): proper_factor.add(N_copy) break if(N_copy == 1): break return proper_factor sympy-sympy-1.9/sympy/ntheory/residue_ntheory.py000066400000000000000000001156601412543434000223670ustar00rootroot00000000000000from sympy.core.compatibility import as_int from sympy.core.function import Function from sympy.utilities.iterables import cartes from sympy.core.numbers import igcd, igcdex, mod_inverse from sympy.core.power import isqrt from sympy.core.singleton import S from .primetest import isprime from .factor_ import factorint, trailing, totient, multiplicity from random import randint, Random def n_order(a, n): """Returns the order of ``a`` modulo ``n``. The order of ``a`` modulo ``n`` is the smallest integer ``k`` such that ``a**k`` leaves a remainder of 1 with ``n``. Examples ======== >>> from sympy.ntheory import n_order >>> n_order(3, 7) 6 >>> n_order(4, 7) 3 """ from collections import defaultdict a, n = as_int(a), as_int(n) if igcd(a, n) != 1: raise ValueError("The two numbers should be relatively prime") factors = defaultdict(int) f = factorint(n) for px, kx in f.items(): if kx > 1: factors[px] += kx - 1 fpx = factorint(px - 1) for py, ky in fpx.items(): factors[py] += ky group_order = 1 for px, kx in factors.items(): group_order *= px**kx order = 1 if a > n: a = a % n for p, e in factors.items(): exponent = group_order for f in range(e + 1): if pow(a, exponent, n) != 1: order *= p ** (e - f + 1) break exponent = exponent // p return order def _primitive_root_prime_iter(p): """ Generates the primitive roots for a prime ``p`` Examples ======== >>> from sympy.ntheory.residue_ntheory import _primitive_root_prime_iter >>> list(_primitive_root_prime_iter(19)) [2, 3, 10, 13, 14, 15] References ========== .. [1] W. Stein "Elementary Number Theory" (2011), page 44 """ # it is assumed that p is an int v = [(p - 1) // i for i in factorint(p - 1).keys()] a = 2 while a < p: for pw in v: # a TypeError below may indicate that p was not an int if pow(a, pw, p) == 1: break else: yield a a += 1 def primitive_root(p): """ Returns the smallest primitive root or None Parameters ========== p : positive integer Examples ======== >>> from sympy.ntheory.residue_ntheory import primitive_root >>> primitive_root(19) 2 References ========== .. [1] W. Stein "Elementary Number Theory" (2011), page 44 .. [2] P. Hackman "Elementary Number Theory" (2009), Chapter C """ p = as_int(p) if p < 1: raise ValueError('p is required to be positive') if p <= 2: return 1 f = factorint(p) if len(f) > 2: return None if len(f) == 2: if 2 not in f or f[2] > 1: return None # case p = 2*p1**k, p1 prime for p1, e1 in f.items(): if p1 != 2: break i = 1 while i < p: i += 2 if i % p1 == 0: continue if is_primitive_root(i, p): return i else: if 2 in f: if p == 4: return 3 return None p1, n = list(f.items())[0] if n > 1: # see Ref [2], page 81 g = primitive_root(p1) if is_primitive_root(g, p1**2): return g else: for i in range(2, g + p1 + 1): if igcd(i, p) == 1 and is_primitive_root(i, p): return i return next(_primitive_root_prime_iter(p)) def is_primitive_root(a, p): """ Returns True if ``a`` is a primitive root of ``p`` ``a`` is said to be the primitive root of ``p`` if gcd(a, p) == 1 and totient(p) is the smallest positive number s.t. a**totient(p) cong 1 mod(p) Examples ======== >>> from sympy.ntheory import is_primitive_root, n_order, totient >>> is_primitive_root(3, 10) True >>> is_primitive_root(9, 10) False >>> n_order(3, 10) == totient(10) True >>> n_order(9, 10) == totient(10) False """ a, p = as_int(a), as_int(p) if igcd(a, p) != 1: raise ValueError("The two numbers should be relatively prime") if a > p: a = a % p return n_order(a, p) == totient(p) def _sqrt_mod_tonelli_shanks(a, p): """ Returns the square root in the case of ``p`` prime with ``p == 1 (mod 8)`` References ========== .. [1] R. Crandall and C. Pomerance "Prime Numbers", 2nt Ed., page 101 """ s = trailing(p - 1) t = p >> s # find a non-quadratic residue while 1: d = randint(2, p - 1) r = legendre_symbol(d, p) if r == -1: break #assert legendre_symbol(d, p) == -1 A = pow(a, t, p) D = pow(d, t, p) m = 0 for i in range(s): adm = A*pow(D, m, p) % p adm = pow(adm, 2**(s - 1 - i), p) if adm % p == p - 1: m += 2**i #assert A*pow(D, m, p) % p == 1 x = pow(a, (t + 1)//2, p)*pow(D, m//2, p) % p return x def sqrt_mod(a, p, all_roots=False): """ Find a root of ``x**2 = a mod p`` Parameters ========== a : integer p : positive integer all_roots : if True the list of roots is returned or None Notes ===== If there is no root it is returned None; else the returned root is less or equal to ``p // 2``; in general is not the smallest one. It is returned ``p // 2`` only if it is the only root. Use ``all_roots`` only when it is expected that all the roots fit in memory; otherwise use ``sqrt_mod_iter``. Examples ======== >>> from sympy.ntheory import sqrt_mod >>> sqrt_mod(11, 43) 21 >>> sqrt_mod(17, 32, True) [7, 9, 23, 25] """ if all_roots: return sorted(list(sqrt_mod_iter(a, p))) try: p = abs(as_int(p)) it = sqrt_mod_iter(a, p) r = next(it) if r > p // 2: return p - r elif r < p // 2: return r else: try: r = next(it) if r > p // 2: return p - r except StopIteration: pass return r except StopIteration: return None def _product(*iters): """ Cartesian product generator Notes ===== Unlike itertools.product, it works also with iterables which do not fit in memory. See http://bugs.python.org/issue10109 Author: Fernando Sumudu with small changes """ import itertools inf_iters = tuple(itertools.cycle(enumerate(it)) for it in iters) num_iters = len(inf_iters) cur_val = [None]*num_iters first_v = True while True: i, p = 0, num_iters while p and not i: p -= 1 i, cur_val[p] = next(inf_iters[p]) if not p and not i: if first_v: first_v = False else: break yield cur_val def sqrt_mod_iter(a, p, domain=int): """ Iterate over solutions to ``x**2 = a mod p`` Parameters ========== a : integer p : positive integer domain : integer domain, ``int``, ``ZZ`` or ``Integer`` Examples ======== >>> from sympy.ntheory.residue_ntheory import sqrt_mod_iter >>> list(sqrt_mod_iter(11, 43)) [21, 22] """ from sympy.polys.galoistools import gf_crt1, gf_crt2 from sympy.polys.domains import ZZ a, p = as_int(a), abs(as_int(p)) if isprime(p): a = a % p if a == 0: res = _sqrt_mod1(a, p, 1) else: res = _sqrt_mod_prime_power(a, p, 1) if res: if domain is ZZ: yield from res else: for x in res: yield domain(x) else: f = factorint(p) v = [] pv = [] for px, ex in f.items(): if a % px == 0: rx = _sqrt_mod1(a, px, ex) if not rx: return else: rx = _sqrt_mod_prime_power(a, px, ex) if not rx: return v.append(rx) pv.append(px**ex) mm, e, s = gf_crt1(pv, ZZ) if domain is ZZ: for vx in _product(*v): r = gf_crt2(vx, pv, mm, e, s, ZZ) yield r else: for vx in _product(*v): r = gf_crt2(vx, pv, mm, e, s, ZZ) yield domain(r) def _sqrt_mod_prime_power(a, p, k): """ Find the solutions to ``x**2 = a mod p**k`` when ``a % p != 0`` Parameters ========== a : integer p : prime number k : positive integer Examples ======== >>> from sympy.ntheory.residue_ntheory import _sqrt_mod_prime_power >>> _sqrt_mod_prime_power(11, 43, 1) [21, 22] References ========== .. [1] P. Hackman "Elementary Number Theory" (2009), page 160 .. [2] http://www.numbertheory.org/php/squareroot.html .. [3] [Gathen99]_ """ from sympy.core.numbers import igcdex from sympy.polys.domains import ZZ pk = p**k a = a % pk if k == 1: if p == 2: return [ZZ(a)] if not (a % p < 2 or pow(a, (p - 1) // 2, p) == 1): return None if p % 4 == 3: res = pow(a, (p + 1) // 4, p) elif p % 8 == 5: sign = pow(a, (p - 1) // 4, p) if sign == 1: res = pow(a, (p + 3) // 8, p) else: b = pow(4*a, (p - 5) // 8, p) x = (2*a*b) % p if pow(x, 2, p) == a: res = x else: res = _sqrt_mod_tonelli_shanks(a, p) # ``_sqrt_mod_tonelli_shanks(a, p)`` is not deterministic; # sort to get always the same result return sorted([ZZ(res), ZZ(p - res)]) if k > 1: # see Ref.[2] if p == 2: if a % 8 != 1: return None if k <= 3: s = set() for i in range(0, pk, 4): s.add(1 + i) s.add(-1 + i) return list(s) # according to Ref.[2] for k > 2 there are two solutions # (mod 2**k-1), that is four solutions (mod 2**k), which can be # obtained from the roots of x**2 = 0 (mod 8) rv = [ZZ(1), ZZ(3), ZZ(5), ZZ(7)] # hensel lift them to solutions of x**2 = 0 (mod 2**k) # if r**2 - a = 0 mod 2**nx but not mod 2**(nx+1) # then r + 2**(nx - 1) is a root mod 2**(nx+1) n = 3 res = [] for r in rv: nx = n while nx < k: r1 = (r**2 - a) >> nx if r1 % 2: r = r + (1 << (nx - 1)) #assert (r**2 - a)% (1 << (nx + 1)) == 0 nx += 1 if r not in res: res.append(r) x = r + (1 << (k - 1)) #assert (x**2 - a) % pk == 0 if x < (1 << nx) and x not in res: if (x**2 - a) % pk == 0: res.append(x) return res rv = _sqrt_mod_prime_power(a, p, 1) if not rv: return None r = rv[0] fr = r**2 - a # hensel lifting with Newton iteration, see Ref.[3] chapter 9 # with f(x) = x**2 - a; one has f'(a) != 0 (mod p) for p != 2 n = 1 px = p while 1: n1 = n n1 *= 2 if n1 > k: break n = n1 px = px**2 frinv = igcdex(2*r, px)[0] r = (r - fr*frinv) % px fr = r**2 - a if n < k: px = p**k frinv = igcdex(2*r, px)[0] r = (r - fr*frinv) % px return [r, px - r] def _sqrt_mod1(a, p, n): """ Find solution to ``x**2 == a mod p**n`` when ``a % p == 0`` see http://www.numbertheory.org/php/squareroot.html """ pn = p**n a = a % pn if a == 0: # case gcd(a, p**k) = p**n m = n // 2 if n % 2 == 1: pm1 = p**(m + 1) def _iter0a(): i = 0 while i < pn: yield i i += pm1 return _iter0a() else: pm = p**m def _iter0b(): i = 0 while i < pn: yield i i += pm return _iter0b() # case gcd(a, p**k) = p**r, r < n f = factorint(a) r = f[p] if r % 2 == 1: return None m = r // 2 a1 = a >> r if p == 2: if n - r == 1: pnm1 = 1 << (n - m + 1) pm1 = 1 << (m + 1) def _iter1(): k = 1 << (m + 2) i = 1 << m while i < pnm1: j = i while j < pn: yield j j += k i += pm1 return _iter1() if n - r == 2: res = _sqrt_mod_prime_power(a1, p, n - r) if res is None: return None pnm = 1 << (n - m) def _iter2(): s = set() for r in res: i = 0 while i < pn: x = (r << m) + i if x not in s: s.add(x) yield x i += pnm return _iter2() if n - r > 2: res = _sqrt_mod_prime_power(a1, p, n - r) if res is None: return None pnm1 = 1 << (n - m - 1) def _iter3(): s = set() for r in res: i = 0 while i < pn: x = ((r << m) + i) % pn if x not in s: s.add(x) yield x i += pnm1 return _iter3() else: m = r // 2 a1 = a // p**r res1 = _sqrt_mod_prime_power(a1, p, n - r) if res1 is None: return None pm = p**m pnr = p**(n-r) pnm = p**(n-m) def _iter4(): s = set() pm = p**m for rx in res1: i = 0 while i < pnm: x = ((rx + i) % pn) if x not in s: s.add(x) yield x*pm i += pnr return _iter4() def is_quad_residue(a, p): """ Returns True if ``a`` (mod ``p``) is in the set of squares mod ``p``, i.e a % p in set([i**2 % p for i in range(p)]). If ``p`` is an odd prime, an iterative method is used to make the determination: >>> from sympy.ntheory import is_quad_residue >>> sorted(set([i**2 % 7 for i in range(7)])) [0, 1, 2, 4] >>> [j for j in range(7) if is_quad_residue(j, 7)] [0, 1, 2, 4] See Also ======== legendre_symbol, jacobi_symbol """ a, p = as_int(a), as_int(p) if p < 1: raise ValueError('p must be > 0') if a >= p or a < 0: a = a % p if a < 2 or p < 3: return True if not isprime(p): if p % 2 and jacobi_symbol(a, p) == -1: return False r = sqrt_mod(a, p) if r is None: return False else: return True return pow(a, (p - 1) // 2, p) == 1 def is_nthpow_residue(a, n, m): """ Returns True if ``x**n == a (mod m)`` has solutions. References ========== .. [1] P. Hackman "Elementary Number Theory" (2009), page 76 """ a = a % m a, n, m = as_int(a), as_int(n), as_int(m) if m <= 0: raise ValueError('m must be > 0') if n < 0: raise ValueError('n must be >= 0') if n == 0: if m == 1: return False return a == 1 if a == 0: return True if n == 1: return True if n == 2: return is_quad_residue(a, m) return _is_nthpow_residue_bign(a, n, m) def _is_nthpow_residue_bign(a, n, m): """Returns True if ``x**n == a (mod m)`` has solutions for n > 2.""" # assert n > 2 # assert a > 0 and m > 0 if primitive_root(m) is None or igcd(a, m) != 1: # assert m >= 8 for prime, power in factorint(m).items(): if not _is_nthpow_residue_bign_prime_power(a, n, prime, power): return False return True f = totient(m) k = f // igcd(f, n) return pow(a, k, m) == 1 def _is_nthpow_residue_bign_prime_power(a, n, p, k): """Returns True/False if a solution for ``x**n == a (mod(p**k))`` does/doesn't exist.""" # assert a > 0 # assert n > 2 # assert p is prime # assert k > 0 if a % p: if p != 2: return _is_nthpow_residue_bign(a, n, pow(p, k)) if n & 1: return True c = trailing(n) return a % pow(2, min(c + 2, k)) == 1 else: a %= pow(p, k) if not a: return True mu = multiplicity(p, a) if mu % n: return False pm = pow(p, mu) return _is_nthpow_residue_bign_prime_power(a//pm, n, p, k - mu) def _nthroot_mod2(s, q, p): f = factorint(q) v = [] for b, e in f.items(): v.extend([b]*e) for qx in v: s = _nthroot_mod1(s, qx, p, False) return s def _nthroot_mod1(s, q, p, all_roots): """ Root of ``x**q = s mod p``, ``p`` prime and ``q`` divides ``p - 1`` References ========== .. [1] A. M. Johnston "A Generalized qth Root Algorithm" """ g = primitive_root(p) if not isprime(q): r = _nthroot_mod2(s, q, p) else: f = p - 1 assert (p - 1) % q == 0 # determine k k = 0 while f % q == 0: k += 1 f = f // q # find z, x, r1 f1 = igcdex(-f, q)[0] % q z = f*f1 x = (1 + z) // q r1 = pow(s, x, p) s1 = pow(s, f, p) h = pow(g, f*q, p) t = discrete_log(p, s1, h) g2 = pow(g, z*t, p) g3 = igcdex(g2, p)[0] r = r1*g3 % p #assert pow(r, q, p) == s res = [r] h = pow(g, (p - 1) // q, p) #assert pow(h, q, p) == 1 hx = r for i in range(q - 1): hx = (hx*h) % p res.append(hx) if all_roots: res.sort() return res return min(res) def _help(m, prime_modulo_method, diff_method, expr_val): """ Helper function for _nthroot_mod_composite and polynomial_congruence. Parameters ========== m : positive integer prime_modulo_method : function to calculate the root of the congruence equation for the prime divisors of m diff_method : function to calculate derivative of expression at any given point expr_val : function to calculate value of the expression at any given point """ from sympy.ntheory.modular import crt f = factorint(m) dd = {} for p, e in f.items(): tot_roots = set() if e == 1: tot_roots.update(prime_modulo_method(p)) else: for root in prime_modulo_method(p): diff = diff_method(root, p) if diff != 0: ppow = p m_inv = mod_inverse(diff, p) for j in range(1, e): ppow *= p root = (root - expr_val(root, ppow) * m_inv) % ppow tot_roots.add(root) else: new_base = p roots_in_base = {root} while new_base < pow(p, e): new_base *= p new_roots = set() for k in roots_in_base: if expr_val(k, new_base)!= 0: continue while k not in new_roots: new_roots.add(k) k = (k + (new_base // p)) % new_base roots_in_base = new_roots tot_roots = tot_roots | roots_in_base if tot_roots == set(): return [] dd[pow(p, e)] = tot_roots a = [] m = [] for x, y in dd.items(): m.append(x) a.append(list(y)) return sorted({crt(m, list(i))[0] for i in cartes(*a)}) def _nthroot_mod_composite(a, n, m): """ Find the solutions to ``x**n = a mod m`` when m is not prime. """ return _help(m, lambda p: nthroot_mod(a, n, p, True), lambda root, p: (pow(root, n - 1, p) * (n % p)) % p, lambda root, p: (pow(root, n, p) - a) % p) def nthroot_mod(a, n, p, all_roots=False): """ Find the solutions to ``x**n = a mod p`` Parameters ========== a : integer n : positive integer p : positive integer all_roots : if False returns the smallest root, else the list of roots Examples ======== >>> from sympy.ntheory.residue_ntheory import nthroot_mod >>> nthroot_mod(11, 4, 19) 8 >>> nthroot_mod(11, 4, 19, True) [8, 11] >>> nthroot_mod(68, 3, 109) 23 """ from sympy.core.numbers import igcdex a = a % p a, n, p = as_int(a), as_int(n), as_int(p) if n == 2: return sqrt_mod(a, p, all_roots) # see Hackman "Elementary Number Theory" (2009), page 76 if not isprime(p): return _nthroot_mod_composite(a, n, p) if a % p == 0: return [0] if not is_nthpow_residue(a, n, p): return [] if all_roots else None if (p - 1) % n == 0: return _nthroot_mod1(a, n, p, all_roots) # The roots of ``x**n - a = 0 (mod p)`` are roots of # ``gcd(x**n - a, x**(p - 1) - 1) = 0 (mod p)`` pa = n pb = p - 1 b = 1 if pa < pb: a, pa, b, pb = b, pb, a, pa while pb: # x**pa - a = 0; x**pb - b = 0 # x**pa - a = x**(q*pb + r) - a = (x**pb)**q * x**r - a = # b**q * x**r - a; x**r - c = 0; c = b**-q * a mod p q, r = divmod(pa, pb) c = pow(b, q, p) c = igcdex(c, p)[0] c = (c * a) % p pa, pb = pb, r a, b = b, c if pa == 1: if all_roots: res = [a] else: res = a elif pa == 2: return sqrt_mod(a, p , all_roots) else: res = _nthroot_mod1(a, pa, p, all_roots) return res def quadratic_residues(p): """ Returns the list of quadratic residues. Examples ======== >>> from sympy.ntheory.residue_ntheory import quadratic_residues >>> quadratic_residues(7) [0, 1, 2, 4] """ p = as_int(p) r = set() for i in range(p // 2 + 1): r.add(pow(i, 2, p)) return sorted(list(r)) def legendre_symbol(a, p): r""" Returns the Legendre symbol `(a / p)`. For an integer ``a`` and an odd prime ``p``, the Legendre symbol is defined as .. math :: \genfrac(){}{}{a}{p} = \begin{cases} 0 & \text{if } p \text{ divides } a\\ 1 & \text{if } a \text{ is a quadratic residue modulo } p\\ -1 & \text{if } a \text{ is a quadratic nonresidue modulo } p \end{cases} Parameters ========== a : integer p : odd prime Examples ======== >>> from sympy.ntheory import legendre_symbol >>> [legendre_symbol(i, 7) for i in range(7)] [0, 1, 1, -1, 1, -1, -1] >>> sorted(set([i**2 % 7 for i in range(7)])) [0, 1, 2, 4] See Also ======== is_quad_residue, jacobi_symbol """ a, p = as_int(a), as_int(p) if not isprime(p) or p == 2: raise ValueError("p should be an odd prime") a = a % p if not a: return 0 if pow(a, (p - 1) // 2, p) == 1: return 1 return -1 def jacobi_symbol(m, n): r""" Returns the Jacobi symbol `(m / n)`. For any integer ``m`` and any positive odd integer ``n`` the Jacobi symbol is defined as the product of the Legendre symbols corresponding to the prime factors of ``n``: .. math :: \genfrac(){}{}{m}{n} = \genfrac(){}{}{m}{p^{1}}^{\alpha_1} \genfrac(){}{}{m}{p^{2}}^{\alpha_2} ... \genfrac(){}{}{m}{p^{k}}^{\alpha_k} \text{ where } n = p_1^{\alpha_1} p_2^{\alpha_2} ... p_k^{\alpha_k} Like the Legendre symbol, if the Jacobi symbol `\genfrac(){}{}{m}{n} = -1` then ``m`` is a quadratic nonresidue modulo ``n``. But, unlike the Legendre symbol, if the Jacobi symbol `\genfrac(){}{}{m}{n} = 1` then ``m`` may or may not be a quadratic residue modulo ``n``. Parameters ========== m : integer n : odd positive integer Examples ======== >>> from sympy.ntheory import jacobi_symbol, legendre_symbol >>> from sympy import S >>> jacobi_symbol(45, 77) -1 >>> jacobi_symbol(60, 121) 1 The relationship between the ``jacobi_symbol`` and ``legendre_symbol`` can be demonstrated as follows: >>> L = legendre_symbol >>> S(45).factors() {3: 2, 5: 1} >>> jacobi_symbol(7, 45) == L(7, 3)**2 * L(7, 5)**1 True See Also ======== is_quad_residue, legendre_symbol """ m, n = as_int(m), as_int(n) if n < 0 or not n % 2: raise ValueError("n should be an odd positive integer") if m < 0 or m > n: m %= n if not m: return int(n == 1) if n == 1 or m == 1: return 1 if igcd(m, n) != 1: return 0 j = 1 if m < 0: m = -m if n % 4 == 3: j = -j while m != 0: while m % 2 == 0 and m > 0: m >>= 1 if n % 8 in [3, 5]: j = -j m, n = n, m if m % 4 == n % 4 == 3: j = -j m %= n if n != 1: j = 0 return j class mobius(Function): """ Mobius function maps natural number to {-1, 0, 1} It is defined as follows: 1) `1` if `n = 1`. 2) `0` if `n` has a squared prime factor. 3) `(-1)^k` if `n` is a square-free positive integer with `k` number of prime factors. It is an important multiplicative function in number theory and combinatorics. It has applications in mathematical series, algebraic number theory and also physics (Fermion operator has very concrete realization with Mobius Function model). Parameters ========== n : positive integer Examples ======== >>> from sympy.ntheory import mobius >>> mobius(13*7) 1 >>> mobius(1) 1 >>> mobius(13*7*5) -1 >>> mobius(13**2) 0 References ========== .. [1] https://en.wikipedia.org/wiki/M%C3%B6bius_function .. [2] Thomas Koshy "Elementary Number Theory with Applications" """ @classmethod def eval(cls, n): if n.is_integer: if n.is_positive is not True: raise ValueError("n should be a positive integer") else: raise TypeError("n should be an integer") if n.is_prime: return S.NegativeOne elif n is S.One: return S.One elif n.is_Integer: a = factorint(n) if any(i > 1 for i in a.values()): return S.Zero return S.NegativeOne**len(a) def _discrete_log_trial_mul(n, a, b, order=None): """ Trial multiplication algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. The algorithm finds the discrete logarithm using exhaustive search. This naive method is used as fallback algorithm of ``discrete_log`` when the group order is very small. Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_trial_mul >>> _discrete_log_trial_mul(41, 15, 7) 3 See Also ======== discrete_log References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ a %= n b %= n if order is None: order = n x = 1 for i in range(order): if x == a: return i x = x * b % n raise ValueError("Log does not exist") def _discrete_log_shanks_steps(n, a, b, order=None): """ Baby-step giant-step algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. The algorithm is a time-memory trade-off of the method of exhaustive search. It uses `O(sqrt(m))` memory, where `m` is the group order. Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_shanks_steps >>> _discrete_log_shanks_steps(41, 15, 7) 3 See Also ======== discrete_log References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ a %= n b %= n if order is None: order = n_order(b, n) m = isqrt(order) + 1 T = dict() x = 1 for i in range(m): T[x] = i x = x * b % n z = mod_inverse(b, n) z = pow(z, m, n) x = a for i in range(m): if x in T: return i * m + T[x] x = x * z % n raise ValueError("Log does not exist") def _discrete_log_pollard_rho(n, a, b, order=None, retries=10, rseed=None): """ Pollard's Rho algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. It is a randomized algorithm with the same expected running time as ``_discrete_log_shanks_steps``, but requires a negligible amount of memory. Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_pollard_rho >>> _discrete_log_pollard_rho(227, 3**7, 3) 7 See Also ======== discrete_log References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ a %= n b %= n if order is None: order = n_order(b, n) prng = Random() if rseed is not None: prng.seed(rseed) for i in range(retries): aa = prng.randint(1, order - 1) ba = prng.randint(1, order - 1) xa = pow(b, aa, n) * pow(a, ba, n) % n c = xa % 3 if c == 0: xb = a * xa % n ab = aa bb = (ba + 1) % order elif c == 1: xb = xa * xa % n ab = (aa + aa) % order bb = (ba + ba) % order else: xb = b * xa % n ab = (aa + 1) % order bb = ba for j in range(order): c = xa % 3 if c == 0: xa = a * xa % n ba = (ba + 1) % order elif c == 1: xa = xa * xa % n aa = (aa + aa) % order ba = (ba + ba) % order else: xa = b * xa % n aa = (aa + 1) % order c = xb % 3 if c == 0: xb = a * xb % n bb = (bb + 1) % order elif c == 1: xb = xb * xb % n ab = (ab + ab) % order bb = (bb + bb) % order else: xb = b * xb % n ab = (ab + 1) % order c = xb % 3 if c == 0: xb = a * xb % n bb = (bb + 1) % order elif c == 1: xb = xb * xb % n ab = (ab + ab) % order bb = (bb + bb) % order else: xb = b * xb % n ab = (ab + 1) % order if xa == xb: r = (ba - bb) % order try: e = mod_inverse(r, order) * (ab - aa) % order if (pow(b, e, n) - a) % n == 0: return e except ValueError: pass break raise ValueError("Pollard's Rho failed to find logarithm") def _discrete_log_pohlig_hellman(n, a, b, order=None): """ Pohlig-Hellman algorithm for computing the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. In order to compute the discrete logarithm, the algorithm takes advantage of the factorization of the group order. It is more efficient when the group order factors into many small primes. Examples ======== >>> from sympy.ntheory.residue_ntheory import _discrete_log_pohlig_hellman >>> _discrete_log_pohlig_hellman(251, 210, 71) 197 See Also ======== discrete_log References ========== .. [1] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ from .modular import crt a %= n b %= n if order is None: order = n_order(b, n) f = factorint(order) l = [0] * len(f) for i, (pi, ri) in enumerate(f.items()): for j in range(ri): gj = pow(b, l[i], n) aj = pow(a * mod_inverse(gj, n), order // pi**(j + 1), n) bj = pow(b, order // pi, n) cj = discrete_log(n, aj, bj, pi, True) l[i] += cj * pi**j d, _ = crt([pi**ri for pi, ri in f.items()], l) return d def discrete_log(n, a, b, order=None, prime_order=None): """ Compute the discrete logarithm of ``a`` to the base ``b`` modulo ``n``. This is a recursive function to reduce the discrete logarithm problem in cyclic groups of composite order to the problem in cyclic groups of prime order. It employs different algorithms depending on the problem (subgroup order size, prime order or not): * Trial multiplication * Baby-step giant-step * Pollard's Rho * Pohlig-Hellman Examples ======== >>> from sympy.ntheory import discrete_log >>> discrete_log(41, 15, 7) 3 References ========== .. [1] http://mathworld.wolfram.com/DiscreteLogarithm.html .. [2] "Handbook of applied cryptography", Menezes, A. J., Van, O. P. C., & Vanstone, S. A. (1997). """ n, a, b = as_int(n), as_int(a), as_int(b) if order is None: order = n_order(b, n) if prime_order is None: prime_order = isprime(order) if order < 1000: return _discrete_log_trial_mul(n, a, b, order) elif prime_order: if order < 1000000000000: return _discrete_log_shanks_steps(n, a, b, order) return _discrete_log_pollard_rho(n, a, b, order) return _discrete_log_pohlig_hellman(n, a, b, order) def quadratic_congruence(a, b, c, p): """ Find the solutions to ``a x**2 + b x + c = 0 mod p a : integer b : integer c : integer p : positive integer """ from sympy.polys.galoistools import linear_congruence a = as_int(a) b = as_int(b) c = as_int(c) p = as_int(p) a = a % p b = b % p c = c % p if a == 0: return linear_congruence(b, -c, p) if p == 2: roots = [] if c % 2 == 0: roots.append(0) if (a + b + c) % 2 == 0: roots.append(1) return roots if isprime(p): inv_a = mod_inverse(a, p) b *= inv_a c *= inv_a if b % 2 == 1: b = b + p d = ((b * b) // 4 - c) % p y = sqrt_mod(d, p, all_roots=True) res = set() for i in y: res.add((i - b // 2) % p) return sorted(res) y = sqrt_mod(b * b - 4 * a * c , 4 * a * p, all_roots=True) res = set() for i in y: root = linear_congruence(2 * a, i - b, 4 * a * p) for j in root: res.add(j % p) return sorted(res) def _polynomial_congruence_prime(coefficients, p): """A helper function used by polynomial_congruence. It returns the root of a polynomial modulo prime number by naive search from [0, p). Parameters ========== coefficients : list of integers p : prime number """ roots = [] rank = len(coefficients) for i in range(0, p): f_val = 0 for coeff in range(0,rank - 1): f_val = (f_val + pow(i, int(rank - coeff - 1), p) * coefficients[coeff]) % p f_val = f_val + coefficients[-1] if f_val % p == 0: roots.append(i) return roots def _diff_poly(root, coefficients, p): """A helper function used by polynomial_congruence. It returns the derivative of the polynomial evaluated at the root (mod p). Parameters ========== coefficients : list of integers p : prime number root : integer """ diff = 0 rank = len(coefficients) for coeff in range(0, rank - 1): if not coefficients[coeff]: continue diff = (diff + pow(root, rank - coeff - 2, p)*(rank - coeff - 1)* coefficients[coeff]) % p return diff % p def _val_poly(root, coefficients, p): """A helper function used by polynomial_congruence. It returns value of the polynomial at root (mod p). Parameters ========== coefficients : list of integers p : prime number root : integer """ rank = len(coefficients) f_val = 0 for coeff in range(0, rank - 1): f_val = (f_val + pow(root, rank - coeff - 1, p)* coefficients[coeff]) % p f_val = f_val + coefficients[-1] return f_val % p def _valid_expr(expr): """ return coefficients of expr if it is a univariate polynomial with integer coefficients else raise a ValueError. """ from sympy import Poly from sympy.polys.domains import ZZ if not expr.is_polynomial(): raise ValueError("The expression should be a polynomial") polynomial = Poly(expr) if not polynomial.is_univariate: raise ValueError("The expression should be univariate") if not polynomial.domain == ZZ: raise ValueError("The expression should should have integer coefficients") return polynomial.all_coeffs() def polynomial_congruence(expr, m): """ Find the solutions to a polynomial congruence equation modulo m. Parameters ========== coefficients : Coefficients of the Polynomial m : positive integer Examples ======== >>> from sympy.ntheory import polynomial_congruence >>> from sympy.abc import x >>> expr = x**6 - 2*x**5 -35 >>> polynomial_congruence(expr, 6125) [3257] """ coefficients = _valid_expr(expr) coefficients = [num % m for num in coefficients] rank = len(coefficients) if rank == 3: return quadratic_congruence(*coefficients, m) if rank == 2: return quadratic_congruence(0, *coefficients, m) if coefficients[0] == 1 and 1 + coefficients[-1] == sum(coefficients): return nthroot_mod(-coefficients[-1], rank - 1, m, True) if isprime(m): return _polynomial_congruence_prime(coefficients, m) return _help(m, lambda p: _polynomial_congruence_prime(coefficients, p), lambda root, p: _diff_poly(root, coefficients, p), lambda root, p: _val_poly(root, coefficients, p)) sympy-sympy-1.9/sympy/ntheory/tests/000077500000000000000000000000001412543434000177365ustar00rootroot00000000000000sympy-sympy-1.9/sympy/ntheory/tests/__init__.py000066400000000000000000000000001412543434000220350ustar00rootroot00000000000000sympy-sympy-1.9/sympy/ntheory/tests/test_bbp_pi.py000066400000000000000000000223161412543434000226060ustar00rootroot00000000000000from random import randint from sympy.ntheory.bbp_pi import pi_hex_digits from sympy.testing.pytest import raises # http://www.herongyang.com/Cryptography/Blowfish-First-8366-Hex-Digits-of-PI.html # There are actually 8336 listed there; with the prepended 3 there are 8337 # below dig=''.join(''' 3243f6a8885a308d313198a2e03707344a4093822299f31d0082efa98ec4e6c89452821e638d013 77be5466cf34e90c6cc0ac29b7c97c50dd3f84d5b5b54709179216d5d98979fb1bd1310ba698dfb5 ac2ffd72dbd01adfb7b8e1afed6a267e96ba7c9045f12c7f9924a19947b3916cf70801f2e2858efc 16636920d871574e69a458fea3f4933d7e0d95748f728eb658718bcd5882154aee7b54a41dc25a59 b59c30d5392af26013c5d1b023286085f0ca417918b8db38ef8e79dcb0603a180e6c9e0e8bb01e8a 3ed71577c1bd314b2778af2fda55605c60e65525f3aa55ab945748986263e8144055ca396a2aab10 b6b4cc5c341141e8cea15486af7c72e993b3ee1411636fbc2a2ba9c55d741831f6ce5c3e169b8793 1eafd6ba336c24cf5c7a325381289586773b8f48986b4bb9afc4bfe81b6628219361d809ccfb21a9 91487cac605dec8032ef845d5de98575b1dc262302eb651b8823893e81d396acc50f6d6ff383f442 392e0b4482a484200469c8f04a9e1f9b5e21c66842f6e96c9a670c9c61abd388f06a51a0d2d8542f 68960fa728ab5133a36eef0b6c137a3be4ba3bf0507efb2a98a1f1651d39af017666ca593e82430e 888cee8619456f9fb47d84a5c33b8b5ebee06f75d885c12073401a449f56c16aa64ed3aa62363f77 061bfedf72429b023d37d0d724d00a1248db0fead349f1c09b075372c980991b7b25d479d8f6e8de f7e3fe501ab6794c3b976ce0bd04c006bac1a94fb6409f60c45e5c9ec2196a246368fb6faf3e6c53 b51339b2eb3b52ec6f6dfc511f9b30952ccc814544af5ebd09bee3d004de334afd660f2807192e4b b3c0cba85745c8740fd20b5f39b9d3fbdb5579c0bd1a60320ad6a100c6402c7279679f25fefb1fa3 cc8ea5e9f8db3222f83c7516dffd616b152f501ec8ad0552ab323db5fafd23876053317b483e00df 829e5c57bbca6f8ca01a87562edf1769dbd542a8f6287effc3ac6732c68c4f5573695b27b0bbca58 c8e1ffa35db8f011a010fa3d98fd2183b84afcb56c2dd1d35b9a53e479b6f84565d28e49bc4bfb97 90e1ddf2daa4cb7e3362fb1341cee4c6e8ef20cada36774c01d07e9efe2bf11fb495dbda4dae9091 98eaad8e716b93d5a0d08ed1d0afc725e08e3c5b2f8e7594b78ff6e2fbf2122b648888b812900df0 1c4fad5ea0688fc31cd1cff191b3a8c1ad2f2f2218be0e1777ea752dfe8b021fa1e5a0cc0fb56f74 e818acf3d6ce89e299b4a84fe0fd13e0b77cc43b81d2ada8d9165fa2668095770593cc7314211a14 77e6ad206577b5fa86c75442f5fb9d35cfebcdaf0c7b3e89a0d6411bd3ae1e7e4900250e2d2071b3 5e226800bb57b8e0af2464369bf009b91e5563911d59dfa6aa78c14389d95a537f207d5ba202e5b9 c5832603766295cfa911c819684e734a41b3472dca7b14a94a1b5100529a532915d60f573fbc9bc6 e42b60a47681e6740008ba6fb5571be91ff296ec6b2a0dd915b6636521e7b9f9b6ff34052ec58556 6453b02d5da99f8fa108ba47996e85076a4b7a70e9b5b32944db75092ec4192623ad6ea6b049a7df 7d9cee60b88fedb266ecaa8c71699a17ff5664526cc2b19ee1193602a575094c29a0591340e4183a 3e3f54989a5b429d656b8fe4d699f73fd6a1d29c07efe830f54d2d38e6f0255dc14cdd20868470eb 266382e9c6021ecc5e09686b3f3ebaefc93c9718146b6a70a1687f358452a0e286b79c5305aa5007 373e07841c7fdeae5c8e7d44ec5716f2b8b03ada37f0500c0df01c1f040200b3ffae0cf51a3cb574 b225837a58dc0921bdd19113f97ca92ff69432477322f547013ae5e58137c2dadcc8b576349af3dd a7a94461460fd0030eecc8c73ea4751e41e238cd993bea0e2f3280bba1183eb3314e548b384f6db9 086f420d03f60a04bf2cb8129024977c795679b072bcaf89afde9a771fd9930810b38bae12dccf3f 2e5512721f2e6b7124501adde69f84cd877a5847187408da17bc9f9abce94b7d8cec7aec3adb851d fa63094366c464c3d2ef1c18473215d908dd433b3724c2ba1612a14d432a65c45150940002133ae4 dd71dff89e10314e5581ac77d65f11199b043556f1d7a3c76b3c11183b5924a509f28fe6ed97f1fb fa9ebabf2c1e153c6e86e34570eae96fb1860e5e0a5a3e2ab3771fe71c4e3d06fa2965dcb999e71d 0f803e89d65266c8252e4cc9789c10b36ac6150eba94e2ea78a5fc3c531e0a2df4f2f74ea7361d2b 3d1939260f19c279605223a708f71312b6ebadfe6eeac31f66e3bc4595a67bc883b17f37d1018cff 28c332ddefbe6c5aa56558218568ab9802eecea50fdb2f953b2aef7dad5b6e2f841521b628290761 70ecdd4775619f151013cca830eb61bd960334fe1eaa0363cfb5735c904c70a239d59e9e0bcbaade 14eecc86bc60622ca79cab5cabb2f3846e648b1eaf19bdf0caa02369b9655abb5040685a323c2ab4 b3319ee9d5c021b8f79b540b19875fa09995f7997e623d7da8f837889a97e32d7711ed935f166812 810e358829c7e61fd696dedfa17858ba9957f584a51b2272639b83c3ff1ac24696cdb30aeb532e30 548fd948e46dbc312858ebf2ef34c6ffeafe28ed61ee7c3c735d4a14d9e864b7e342105d14203e13 e045eee2b6a3aaabeadb6c4f15facb4fd0c742f442ef6abbb5654f3b1d41cd2105d81e799e86854d c7e44b476a3d816250cf62a1f25b8d2646fc8883a0c1c7b6a37f1524c369cb749247848a0b5692b2 85095bbf00ad19489d1462b17423820e0058428d2a0c55f5ea1dadf43e233f70613372f0928d937e 41d65fecf16c223bdb7cde3759cbee74604085f2a7ce77326ea607808419f8509ee8efd85561d997 35a969a7aac50c06c25a04abfc800bcadc9e447a2ec3453484fdd567050e1e9ec9db73dbd3105588 cd675fda79e3674340c5c43465713e38d83d28f89ef16dff20153e21e78fb03d4ae6e39f2bdb83ad f7e93d5a68948140f7f64c261c94692934411520f77602d4f7bcf46b2ed4a20068d40824713320f4 6a43b7d4b7500061af1e39f62e9724454614214f74bf8b88404d95fc1d96b591af70f4ddd366a02f 45bfbc09ec03bd97857fac6dd031cb850496eb27b355fd3941da2547e6abca0a9a28507825530429 f40a2c86dae9b66dfb68dc1462d7486900680ec0a427a18dee4f3ffea2e887ad8cb58ce0067af4d6 b6aace1e7cd3375fecce78a399406b2a4220fe9e35d9f385b9ee39d7ab3b124e8b1dc9faf74b6d18 5626a36631eae397b23a6efa74dd5b43326841e7f7ca7820fbfb0af54ed8feb397454056acba4895 2755533a3a20838d87fe6ba9b7d096954b55a867bca1159a58cca9296399e1db33a62a4a563f3125 f95ef47e1c9029317cfdf8e80204272f7080bb155c05282ce395c11548e4c66d2248c1133fc70f86 dc07f9c9ee41041f0f404779a45d886e17325f51ebd59bc0d1f2bcc18f41113564257b7834602a9c 60dff8e8a31f636c1b0e12b4c202e1329eaf664fd1cad181156b2395e0333e92e13b240b62eebeb9 2285b2a20ee6ba0d99de720c8c2da2f728d012784595b794fd647d0862e7ccf5f05449a36f877d48 fac39dfd27f33e8d1e0a476341992eff743a6f6eabf4f8fd37a812dc60a1ebddf8991be14cdb6e6b 0dc67b55106d672c372765d43bdcd0e804f1290dc7cc00ffa3b5390f92690fed0b667b9ffbcedb7d 9ca091cf0bd9155ea3bb132f88515bad247b9479bf763bd6eb37392eb3cc1159798026e297f42e31 2d6842ada7c66a2b3b12754ccc782ef11c6a124237b79251e706a1bbe64bfb63501a6b101811caed fa3d25bdd8e2e1c3c9444216590a121386d90cec6ed5abea2a64af674eda86a85fbebfe98864e4c3 fe9dbc8057f0f7c08660787bf86003604dd1fd8346f6381fb07745ae04d736fccc83426b33f01eab 71b08041873c005e5f77a057bebde8ae2455464299bf582e614e58f48ff2ddfda2f474ef388789bd c25366f9c3c8b38e74b475f25546fcd9b97aeb26618b1ddf84846a0e79915f95e2466e598e20b457 708cd55591c902de4cb90bace1bb8205d011a862487574a99eb77f19b6e0a9dc09662d09a1c43246 33e85a1f0209f0be8c4a99a0251d6efe101ab93d1d0ba5a4dfa186f20f2868f169dcb7da83573906 fea1e2ce9b4fcd7f5250115e01a70683faa002b5c40de6d0279af88c27773f8641c3604c0661a806 b5f0177a28c0f586e0006058aa30dc7d6211e69ed72338ea6353c2dd94c2c21634bbcbee5690bcb6 deebfc7da1ce591d766f05e4094b7c018839720a3d7c927c2486e3725f724d9db91ac15bb4d39eb8 fced54557808fca5b5d83d7cd34dad0fc41e50ef5eb161e6f8a28514d96c51133c6fd5c7e756e14e c4362abfceddc6c837d79a323492638212670efa8e406000e03a39ce37d3faf5cfabc277375ac52d 1b5cb0679e4fa33742d382274099bc9bbed5118e9dbf0f7315d62d1c7ec700c47bb78c1b6b21a190 45b26eb1be6a366eb45748ab2fbc946e79c6a376d26549c2c8530ff8ee468dde7dd5730a1d4cd04d c62939bbdba9ba4650ac9526e8be5ee304a1fad5f06a2d519a63ef8ce29a86ee22c089c2b843242e f6a51e03aa9cf2d0a483c061ba9be96a4d8fe51550ba645bd62826a2f9a73a3ae14ba99586ef5562 e9c72fefd3f752f7da3f046f6977fa0a5980e4a91587b086019b09e6ad3b3ee593e990fd5a9e34d7 972cf0b7d9022b8b5196d5ac3a017da67dd1cf3ed67c7d2d281f9f25cfadf2b89b5ad6b4725a88f5 4ce029ac71e019a5e647b0acfded93fa9be8d3c48d283b57ccf8d5662979132e28785f0191ed7560 55f7960e44e3d35e8c15056dd488f46dba03a161250564f0bdc3eb9e153c9057a297271aeca93a07 2a1b3f6d9b1e6321f5f59c66fb26dcf3197533d928b155fdf5035634828aba3cbb28517711c20ad9 f8abcc5167ccad925f4de817513830dc8e379d58629320f991ea7a90c2fb3e7bce5121ce64774fbe 32a8b6e37ec3293d4648de53696413e680a2ae0810dd6db22469852dfd09072166b39a460a6445c0 dd586cdecf1c20c8ae5bbef7dd1b588d40ccd2017f6bb4e3bbdda26a7e3a59ff453e350a44bcb4cd d572eacea8fa6484bb8d6612aebf3c6f47d29be463542f5d9eaec2771bf64e6370740e0d8de75b13 57f8721671af537d5d4040cb084eb4e2cc34d2466a0115af84e1b0042895983a1d06b89fb4ce6ea0 486f3f3b823520ab82011a1d4b277227f8611560b1e7933fdcbb3a792b344525bda08839e151ce79 4b2f32c9b7a01fbac9e01cc87ebcc7d1f6cf0111c3a1e8aac71a908749d44fbd9ad0dadecbd50ada 380339c32ac69136678df9317ce0b12b4ff79e59b743f5bb3af2d519ff27d9459cbf97222c15e6fc 2a0f91fc719b941525fae59361ceb69cebc2a8645912baa8d1b6c1075ee3056a0c10d25065cb03a4 42e0ec6e0e1698db3b4c98a0be3278e9649f1f9532e0d392dfd3a0342b8971f21e1b0a74414ba334 8cc5be7120c37632d8df359f8d9b992f2ee60b6f470fe3f11de54cda541edad891ce6279cfcd3e7e 6f1618b166fd2c1d05848fd2c5f6fb2299f523f357a632762393a8353156cccd02acf081625a75eb b56e16369788d273ccde96629281b949d04c50901b71c65614e6c6c7bd327a140a45e1d006c3f27b 9ac9aa53fd62a80f00bb25bfe235bdd2f671126905b2040222b6cbcf7ccd769c2b53113ec01640e3 d338abbd602547adf0ba38209cf746ce7677afa1c52075606085cbfe4e8ae88dd87aaaf9b04cf9aa 7e1948c25c02fb8a8c01c36ae4d6ebe1f990d4f869a65cdea03f09252dc208e69fb74e6132ce77e2 5b578fdfe33ac372e6'''.split()) def test_hex_pi_nth_digits(): assert pi_hex_digits(0) == '3243f6a8885a30' assert pi_hex_digits(1) == '243f6a8885a308' assert pi_hex_digits(10000) == '68ac8fcfb8016c' assert pi_hex_digits(13) == '08d313198a2e03' assert pi_hex_digits(0, 3) == '324' assert pi_hex_digits(0, 0) == '' raises(ValueError, lambda: pi_hex_digits(-1)) raises(ValueError, lambda: pi_hex_digits(3.14)) # this will pick a random segment to compute every time # it is run. If it ever fails, there is an error in the # computation. n = randint(0, len(dig)) prec = randint(0, len(dig) - n) assert pi_hex_digits(n, prec) == dig[n: n + prec] sympy-sympy-1.9/sympy/ntheory/tests/test_continued_fraction.py000066400000000000000000000055631412543434000252350ustar00rootroot00000000000000from sympy import S, pi, GoldenRatio as phi, sqrt, Rational from sympy.ntheory.continued_fraction import \ (continued_fraction_periodic as cf_p, continued_fraction_iterator as cf_i, continued_fraction_convergents as cf_c, continued_fraction_reduce as cf_r, continued_fraction as cf) from sympy.testing.pytest import raises def test_continued_fraction(): assert cf_p(1, 1, 10, 0) == cf_p(1, 1, 0, 1) assert cf_p(1, -1, 10, 1) == cf_p(-1, 1, 10, -1) t = sqrt(2) assert cf((1 + t)*(1 - t)) == cf(-1) for n in [0, 2, Rational(2, 3), sqrt(2), 3*sqrt(2), 1 + 2*sqrt(3)/5, (2 - 3*sqrt(5))/7, 1 + sqrt(2), (-5 + sqrt(17))/4]: assert (cf_r(cf(n)) - n).expand() == 0 assert (cf_r(cf(-n)) + n).expand() == 0 raises(ValueError, lambda: cf(sqrt(2 + sqrt(3)))) raises(ValueError, lambda: cf(sqrt(2) + sqrt(3))) raises(ValueError, lambda: cf(pi)) raises(ValueError, lambda: cf(.1)) raises(ValueError, lambda: cf_p(1, 0, 0)) raises(ValueError, lambda: cf_p(1, 1, -1)) assert cf_p(4, 3, 0) == [1, 3] assert cf_p(0, 3, 5) == [0, 1, [2, 1, 12, 1, 2, 2]] assert cf_p(1, 1, 0) == [1] assert cf_p(3, 4, 0) == [0, 1, 3] assert cf_p(4, 5, 0) == [0, 1, 4] assert cf_p(5, 6, 0) == [0, 1, 5] assert cf_p(11, 13, 0) == [0, 1, 5, 2] assert cf_p(16, 19, 0) == [0, 1, 5, 3] assert cf_p(27, 32, 0) == [0, 1, 5, 2, 2] assert cf_p(1, 2, 5) == [[1]] assert cf_p(0, 1, 2) == [1, [2]] assert cf_p(6, 7, 49) == [1, 1, 6] assert cf_p(3796, 1387, 0) == [2, 1, 2, 1, 4] assert cf_p(3245, 10000) == [0, 3, 12, 4, 13] assert cf_p(1932, 2568) == [0, 1, 3, 26, 2] assert cf_p(6589, 2569) == [2, 1, 1, 3, 2, 1, 3, 1, 23] def take(iterator, n=7): res = [] for i, t in enumerate(cf_i(iterator)): if i >= n: break res.append(t) return res assert take(phi) == [1, 1, 1, 1, 1, 1, 1] assert take(pi) == [3, 7, 15, 1, 292, 1, 1] assert list(cf_i(Rational(17, 12))) == [1, 2, 2, 2] assert list(cf_i(Rational(-17, 12))) == [-2, 1, 1, 2, 2] assert list(cf_c([1, 6, 1, 8])) == [S.One, Rational(7, 6), Rational(8, 7), Rational(71, 62)] assert list(cf_c([2])) == [S(2)] assert list(cf_c([1, 1, 1, 1, 1, 1, 1])) == [S.One, S(2), Rational(3, 2), Rational(5, 3), Rational(8, 5), Rational(13, 8), Rational(21, 13)] assert list(cf_c([1, 6, Rational(-1, 2), 4])) == [S.One, Rational(7, 6), Rational(5, 4), Rational(3, 2)] assert cf_r([1, 6, 1, 8]) == Rational(71, 62) assert cf_r([3]) == S(3) assert cf_r([-1, 5, 1, 4]) == Rational(-24, 29) assert (cf_r([0, 1, 1, 7, [24, 8]]) - (sqrt(3) + 2)/7).expand() == 0 assert cf_r([1, 5, 9]) == Rational(55, 46) assert (cf_r([[1]]) - (sqrt(5) + 1)/2).expand() == 0 assert cf_r([-3, 1, 1, [2]]) == -1 - sqrt(2) sympy-sympy-1.9/sympy/ntheory/tests/test_digits.py000066400000000000000000000022361412543434000226350ustar00rootroot00000000000000from sympy.ntheory import count_digits, digits, is_palindromic from sympy.testing.pytest import raises def test_digits(): assert all([digits(n, 2)[1:] == [int(d) for d in format(n, 'b')] for n in range(20)]) assert all([digits(n, 8)[1:] == [int(d) for d in format(n, 'o')] for n in range(20)]) assert all([digits(n, 16)[1:] == [int(d, 16) for d in format(n, 'x')] for n in range(20)]) assert digits(2345, 34) == [34, 2, 0, 33] assert digits(384753, 71) == [71, 1, 5, 23, 4] assert digits(93409, 10) == [10, 9, 3, 4, 0, 9] assert digits(-92838, 11) == [-11, 6, 3, 8, 2, 9] assert digits(35, 10) == [10, 3, 5] assert digits(35, 10, 3) == [10, 0, 3, 5] assert digits(-35, 10, 4) == [-10, 0, 0, 3, 5] raises(ValueError, lambda: digits(2, 2, 1)) def test_count_digits(): assert count_digits(55, 2) == {1: 5, 0: 1} assert count_digits(55, 10) == {5: 2} n = count_digits(123) assert n[4] == 0 and type(n[4]) is int def test_is_palindromic(): assert is_palindromic(-11) assert is_palindromic(11) assert is_palindromic(0o121, 8) assert not is_palindromic(123) sympy-sympy-1.9/sympy/ntheory/tests/test_ecm.py000066400000000000000000000043621412543434000221200ustar00rootroot00000000000000from sympy.ntheory.ecm import ecm, Point from sympy.testing.pytest import slow @slow def test_ecm(): assert ecm(3146531246531241245132451321) == {3, 100327907731, 10454157497791297} assert ecm(46167045131415113) == {43, 2634823, 407485517} assert ecm(631211032315670776841) == {9312934919, 67777885039} assert ecm(398883434337287) == {99476569, 4009823} assert ecm(64211816600515193) == {281719, 359641, 633767} assert ecm(4269021180054189416198169786894227) == {184039, 241603, 333331, 477973, 618619, 974123} assert ecm(4516511326451341281684513) == {3, 39869, 131743543, 95542348571} assert ecm(4132846513818654136451) == {47, 160343, 2802377, 195692803} assert ecm(168541512131094651323) == {79, 113, 11011069, 1714635721} #This takes ~10secs while factorint is not able to factorize this even in ~10mins assert ecm(7060005655815754299976961394452809, B1=100000, B2=1000000) == {6988699669998001, 1010203040506070809} def test_Point(): from sympy import mod_inverse #The curve is of the form y**2 = x**3 + a*x**2 + x mod = 101 a = 10 a_24 = (a + 2)*mod_inverse(4, mod) p1 = Point(10, 17, a_24, mod) p2 = p1.double() assert p2 == Point(68, 56, a_24, mod) p4 = p2.double() assert p4 == Point(22, 64, a_24, mod) p8 = p4.double() assert p8 == Point(71, 95, a_24, mod) p16 = p8.double() assert p16 == Point(5, 16, a_24, mod) p32 = p16.double() assert p32 == Point(33, 96, a_24, mod) # p3 = p2 + p1 p3 = p2.add(p1, p1) assert p3 == Point(1, 61, a_24, mod) # p5 = p3 + p2 or p4 + p1 p5 = p3.add(p2, p1) assert p5 == Point(49, 90, a_24, mod) assert p5 == p4.add(p1, p3) # p6 = 2*p3 p6 = p3.double() assert p6 == Point(87, 43, a_24, mod) assert p6 == p4.add(p2, p2) # p7 = p5 + p2 p7 = p5.add(p2, p3) assert p7 == Point(69, 23, a_24, mod) assert p7 == p4.add(p3, p1) assert p7 == p6.add(p1, p5) # p9 = p5 + p4 p9 = p5.add(p4, p1) assert p9 == Point(56, 99, a_24, mod) assert p9 == p6.add(p3, p3) assert p9 == p7.add(p2, p5) assert p9 == p8.add(p1, p7) assert p5 == p1.mont_ladder(5) assert p9 == p1.mont_ladder(9) assert p16 == p1.mont_ladder(16) assert p9 == p3.mont_ladder(3) sympy-sympy-1.9/sympy/ntheory/tests/test_egyptian_fraction.py000066400000000000000000000045171412543434000250630ustar00rootroot00000000000000from sympy.core.numbers import Rational from sympy.ntheory.egyptian_fraction import egyptian_fraction from sympy.core.add import Add from sympy.testing.pytest import raises from sympy.testing.randtest import random_complex_number def test_egyptian_fraction(): def test_equality(r, alg="Greedy"): return r == Add(*[Rational(1, i) for i in egyptian_fraction(r, alg)]) r = random_complex_number(a=0, c=1, b=0, d=0, rational=True) assert test_equality(r) assert egyptian_fraction(Rational(4, 17)) == [5, 29, 1233, 3039345] assert egyptian_fraction(Rational(7, 13), "Greedy") == [2, 26] assert egyptian_fraction(Rational(23, 101), "Greedy") == \ [5, 37, 1438, 2985448, 40108045937720] assert egyptian_fraction(Rational(18, 23), "Takenouchi") == \ [2, 6, 12, 35, 276, 2415] assert egyptian_fraction(Rational(5, 6), "Graham Jewett") == \ [6, 7, 8, 9, 10, 42, 43, 44, 45, 56, 57, 58, 72, 73, 90, 1806, 1807, 1808, 1892, 1893, 1980, 3192, 3193, 3306, 5256, 3263442, 3263443, 3267056, 3581556, 10192056, 10650056950806] assert egyptian_fraction(Rational(5, 6), "Golomb") == [2, 6, 12, 20, 30] assert egyptian_fraction(Rational(5, 121), "Golomb") == [25, 1225, 3577, 7081, 11737] raises(ValueError, lambda: egyptian_fraction(Rational(-4, 9))) assert egyptian_fraction(Rational(8, 3), "Golomb") == [1, 2, 3, 4, 5, 6, 7, 14, 574, 2788, 6460, 11590, 33062, 113820] assert egyptian_fraction(Rational(355, 113)) == [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 27, 744, 893588, 1251493536607, 20361068938197002344405230] def test_input(): r = (2,3), Rational(2, 3), (Rational(2), Rational(3)) for m in ["Greedy", "Graham Jewett", "Takenouchi", "Golomb"]: for i in r: d = egyptian_fraction(i, m) assert all(i.is_Integer for i in d) if m == "Graham Jewett": assert d == [3, 4, 12] else: assert d == [2, 6] # check prefix d = egyptian_fraction(Rational(5, 3)) assert d == [1, 2, 6] and all(i.is_Integer for i in d) sympy-sympy-1.9/sympy/ntheory/tests/test_elliptic_curve.py000066400000000000000000000011601412543434000243560ustar00rootroot00000000000000from sympy.ntheory.elliptic_curve import EllipticCurve def test_elliptic_curve(): # Point addition and multiplication e3 = EllipticCurve(-1, 9) p = e3(0, 3) q = e3(-1, 3) r = p + q assert r.x == 1 and r.y == -3 r = 2*p + q assert r.x == 35 and r.y == 207 r = -p + q assert r.x == 37 and r.y == 225 # Verify result in http://www.lmfdb.org/EllipticCurve/Q # Discriminant assert EllipticCurve(-1, 9).discriminant == -34928 assert EllipticCurve(-2731, -55146, 1, 0, 1).discriminant == 25088 # Torsion points assert len(EllipticCurve(0, 1).torsion_points()) == 6 sympy-sympy-1.9/sympy/ntheory/tests/test_factor_.py000066400000000000000000000600311412543434000227640ustar00rootroot00000000000000from sympy import Mul, S, Pow, Symbol, summation, Dict, factorial as fac from sympy.core.evalf import bitcount from sympy.core.numbers import Integer, Rational from sympy.ntheory import (totient, factorint, primefactors, divisors, nextprime, primerange, pollard_rho, perfect_power, multiplicity, multiplicity_in_factorial, trailing, divisor_count, primorial, pollard_pm1, divisor_sigma, factorrat, reduced_totient) from sympy.ntheory.factor_ import (smoothness, smoothness_p, proper_divisors, antidivisors, antidivisor_count, core, udivisors, udivisor_sigma, udivisor_count, proper_divisor_count, primenu, primeomega, small_trailing, mersenne_prime_exponent, is_perfect, is_mersenne_prime, is_abundant, is_deficient, is_amicable, dra, drm) from sympy.testing.pytest import raises, slow from sympy.utilities.iterables import capture def fac_multiplicity(n, p): """Return the power of the prime number p in the factorization of n!""" if p > n: return 0 if p > n//2: return 1 q, m = n, 0 while q >= p: q //= p m += q return m def multiproduct(seq=(), start=1): """ Return the product of a sequence of factors with multiplicities, times the value of the parameter ``start``. The input may be a sequence of (factor, exponent) pairs or a dict of such pairs. >>> multiproduct({3:7, 2:5}, 4) # = 3**7 * 2**5 * 4 279936 """ if not seq: return start if isinstance(seq, dict): seq = iter(seq.items()) units = start multi = [] for base, exp in seq: if not exp: continue elif exp == 1: units *= base else: if exp % 2: units *= base multi.append((base, exp//2)) return units * multiproduct(multi)**2 def test_trailing_bitcount(): assert trailing(0) == 0 assert trailing(1) == 0 assert trailing(-1) == 0 assert trailing(2) == 1 assert trailing(7) == 0 assert trailing(-7) == 0 for i in range(100): assert trailing(1 << i) == i assert trailing((1 << i) * 31337) == i assert trailing(1 << 1000001) == 1000001 assert trailing((1 << 273956)*7**37) == 273956 # issue 12709 big = small_trailing[-1]*2 assert trailing(-big) == trailing(big) assert bitcount(-big) == bitcount(big) def test_multiplicity(): for b in range(2, 20): for i in range(100): assert multiplicity(b, b**i) == i assert multiplicity(b, (b**i) * 23) == i assert multiplicity(b, (b**i) * 1000249) == i # Should be fast assert multiplicity(10, 10**10023) == 10023 # Should exit quickly assert multiplicity(10**10, 10**10) == 1 # Should raise errors for bad input raises(ValueError, lambda: multiplicity(1, 1)) raises(ValueError, lambda: multiplicity(1, 2)) raises(ValueError, lambda: multiplicity(1.3, 2)) raises(ValueError, lambda: multiplicity(2, 0)) raises(ValueError, lambda: multiplicity(1.3, 0)) # handles Rationals assert multiplicity(10, Rational(30, 7)) == 1 assert multiplicity(Rational(2, 7), Rational(4, 7)) == 1 assert multiplicity(Rational(1, 7), Rational(3, 49)) == 2 assert multiplicity(Rational(2, 7), Rational(7, 2)) == -1 assert multiplicity(3, Rational(1, 9)) == -2 def test_multiplicity_in_factorial(): n = fac(1000) for i in (2, 4, 6, 12, 30, 36, 48, 60, 72, 96): assert multiplicity(i, n) == multiplicity_in_factorial(i, 1000) def test_perfect_power(): raises(ValueError, lambda: perfect_power(0)) raises(ValueError, lambda: perfect_power(Rational(25, 4))) assert perfect_power(1) is False assert perfect_power(2) is False assert perfect_power(3) is False assert perfect_power(4) == (2, 2) assert perfect_power(14) is False assert perfect_power(25) == (5, 2) assert perfect_power(22) is False assert perfect_power(22, [2]) is False assert perfect_power(137**(3*5*13)) == (137, 3*5*13) assert perfect_power(137**(3*5*13) + 1) is False assert perfect_power(137**(3*5*13) - 1) is False assert perfect_power(103005006004**7) == (103005006004, 7) assert perfect_power(103005006004**7 + 1) is False assert perfect_power(103005006004**7 - 1) is False assert perfect_power(103005006004**12) == (103005006004, 12) assert perfect_power(103005006004**12 + 1) is False assert perfect_power(103005006004**12 - 1) is False assert perfect_power(2**10007) == (2, 10007) assert perfect_power(2**10007 + 1) is False assert perfect_power(2**10007 - 1) is False assert perfect_power((9**99 + 1)**60) == (9**99 + 1, 60) assert perfect_power((9**99 + 1)**60 + 1) is False assert perfect_power((9**99 + 1)**60 - 1) is False assert perfect_power((10**40000)**2, big=False) == (10**40000, 2) assert perfect_power(10**100000) == (10, 100000) assert perfect_power(10**100001) == (10, 100001) assert perfect_power(13**4, [3, 5]) is False assert perfect_power(3**4, [3, 10], factor=0) is False assert perfect_power(3**3*5**3) == (15, 3) assert perfect_power(2**3*5**5) is False assert perfect_power(2*13**4) is False assert perfect_power(2**5*3**3) is False t = 2**24 for d in divisors(24): m = perfect_power(t*3**d) assert m and m[1] == d or d == 1 m = perfect_power(t*3**d, big=False) assert m and m[1] == 2 or d == 1 or d == 3, (d, m) @slow def test_factorint(): assert primefactors(123456) == [2, 3, 643] assert factorint(0) == {0: 1} assert factorint(1) == {} assert factorint(-1) == {-1: 1} assert factorint(-2) == {-1: 1, 2: 1} assert factorint(-16) == {-1: 1, 2: 4} assert factorint(2) == {2: 1} assert factorint(126) == {2: 1, 3: 2, 7: 1} assert factorint(123456) == {2: 6, 3: 1, 643: 1} assert factorint(5951757) == {3: 1, 7: 1, 29: 2, 337: 1} assert factorint(64015937) == {7993: 1, 8009: 1} assert factorint(2**(2**6) + 1) == {274177: 1, 67280421310721: 1} #issue 19683 assert factorint(10**38 - 1) == {3: 2, 11: 1, 909090909090909091: 1, 1111111111111111111: 1} #issue 17676 assert factorint(28300421052393658575) == {3: 1, 5: 2, 11: 2, 43: 1, 2063: 2, 4127: 1, 4129: 1} assert factorint(2063**2 * 4127**1 * 4129**1) == {2063: 2, 4127: 1, 4129: 1} assert factorint(2347**2 * 7039**1 * 7043**1) == {2347: 2, 7039: 1, 7043: 1} assert factorint(0, multiple=True) == [0] assert factorint(1, multiple=True) == [] assert factorint(-1, multiple=True) == [-1] assert factorint(-2, multiple=True) == [-1, 2] assert factorint(-16, multiple=True) == [-1, 2, 2, 2, 2] assert factorint(2, multiple=True) == [2] assert factorint(24, multiple=True) == [2, 2, 2, 3] assert factorint(126, multiple=True) == [2, 3, 3, 7] assert factorint(123456, multiple=True) == [2, 2, 2, 2, 2, 2, 3, 643] assert factorint(5951757, multiple=True) == [3, 7, 29, 29, 337] assert factorint(64015937, multiple=True) == [7993, 8009] assert factorint(2**(2**6) + 1, multiple=True) == [274177, 67280421310721] assert factorint(fac(1, evaluate=False)) == {} assert factorint(fac(7, evaluate=False)) == {2: 4, 3: 2, 5: 1, 7: 1} assert factorint(fac(15, evaluate=False)) == \ {2: 11, 3: 6, 5: 3, 7: 2, 11: 1, 13: 1} assert factorint(fac(20, evaluate=False)) == \ {2: 18, 3: 8, 5: 4, 7: 2, 11: 1, 13: 1, 17: 1, 19: 1} assert factorint(fac(23, evaluate=False)) == \ {2: 19, 3: 9, 5: 4, 7: 3, 11: 2, 13: 1, 17: 1, 19: 1, 23: 1} assert multiproduct(factorint(fac(200))) == fac(200) assert multiproduct(factorint(fac(200, evaluate=False))) == fac(200) for b, e in factorint(fac(150)).items(): assert e == fac_multiplicity(150, b) for b, e in factorint(fac(150, evaluate=False)).items(): assert e == fac_multiplicity(150, b) assert factorint(103005006059**7) == {103005006059: 7} assert factorint(31337**191) == {31337: 191} assert factorint(2**1000 * 3**500 * 257**127 * 383**60) == \ {2: 1000, 3: 500, 257: 127, 383: 60} assert len(factorint(fac(10000))) == 1229 assert len(factorint(fac(10000, evaluate=False))) == 1229 assert factorint(12932983746293756928584532764589230) == \ {2: 1, 5: 1, 73: 1, 727719592270351: 1, 63564265087747: 1, 383: 1} assert factorint(727719592270351) == {727719592270351: 1} assert factorint(2**64 + 1, use_trial=False) == factorint(2**64 + 1) for n in range(60000): assert multiproduct(factorint(n)) == n assert pollard_rho(2**64 + 1, seed=1) == 274177 assert pollard_rho(19, seed=1) is None assert factorint(3, limit=2) == {3: 1} assert factorint(12345) == {3: 1, 5: 1, 823: 1} assert factorint( 12345, limit=3) == {4115: 1, 3: 1} # the 5 is greater than the limit assert factorint(1, limit=1) == {} assert factorint(0, 3) == {0: 1} assert factorint(12, limit=1) == {12: 1} assert factorint(30, limit=2) == {2: 1, 15: 1} assert factorint(16, limit=2) == {2: 4} assert factorint(124, limit=3) == {2: 2, 31: 1} assert factorint(4*31**2, limit=3) == {2: 2, 31: 2} p1 = nextprime(2**32) p2 = nextprime(2**16) p3 = nextprime(p2) assert factorint(p1*p2*p3) == {p1: 1, p2: 1, p3: 1} assert factorint(13*17*19, limit=15) == {13: 1, 17*19: 1} assert factorint(1951*15013*15053, limit=2000) == {225990689: 1, 1951: 1} assert factorint(primorial(17) + 1, use_pm1=0) == \ {int(19026377261): 1, 3467: 1, 277: 1, 105229: 1} # when prime b is closer than approx sqrt(8*p) to prime p then they are # "close" and have a trivial factorization a = nextprime(2**2**8) # 78 digits b = nextprime(a + 2**2**4) assert 'Fermat' in capture(lambda: factorint(a*b, verbose=1)) raises(ValueError, lambda: pollard_rho(4)) raises(ValueError, lambda: pollard_pm1(3)) raises(ValueError, lambda: pollard_pm1(10, B=2)) # verbose coverage n = nextprime(2**16)*nextprime(2**17)*nextprime(1901) assert 'with primes' in capture(lambda: factorint(n, verbose=1)) capture(lambda: factorint(nextprime(2**16)*1012, verbose=1)) n = nextprime(2**17) capture(lambda: factorint(n**3, verbose=1)) # perfect power termination capture(lambda: factorint(2*n, verbose=1)) # factoring complete msg # exceed 1st n = nextprime(2**17) n *= nextprime(n) assert '1000' in capture(lambda: factorint(n, limit=1000, verbose=1)) n *= nextprime(n) assert len(factorint(n)) == 3 assert len(factorint(n, limit=p1)) == 3 n *= nextprime(2*n) # exceed 2nd assert '2001' in capture(lambda: factorint(n, limit=2000, verbose=1)) assert capture( lambda: factorint(n, limit=4000, verbose=1)).count('Pollard') == 2 # non-prime pm1 result n = nextprime(8069) n *= nextprime(2*n)*nextprime(2*n, 2) capture(lambda: factorint(n, verbose=1)) # non-prime pm1 result # factor fermat composite p1 = nextprime(2**17) p2 = nextprime(2*p1) assert factorint((p1*p2**2)**3) == {p1: 3, p2: 6} # Test for non integer input raises(ValueError, lambda: factorint(4.5)) # test dict/Dict input sans = '2**10*3**3' n = {4: 2, 12: 3} assert str(factorint(n)) == sans assert str(factorint(Dict(n))) == sans def test_divisors_and_divisor_count(): assert divisors(-1) == [1] assert divisors(0) == [] assert divisors(1) == [1] assert divisors(2) == [1, 2] assert divisors(3) == [1, 3] assert divisors(17) == [1, 17] assert divisors(10) == [1, 2, 5, 10] assert divisors(100) == [1, 2, 4, 5, 10, 20, 25, 50, 100] assert divisors(101) == [1, 101] assert divisor_count(0) == 0 assert divisor_count(-1) == 1 assert divisor_count(1) == 1 assert divisor_count(6) == 4 assert divisor_count(12) == 6 assert divisor_count(180, 3) == divisor_count(180//3) assert divisor_count(2*3*5, 7) == 0 def test_proper_divisors_and_proper_divisor_count(): assert proper_divisors(-1) == [] assert proper_divisors(0) == [] assert proper_divisors(1) == [] assert proper_divisors(2) == [1] assert proper_divisors(3) == [1] assert proper_divisors(17) == [1] assert proper_divisors(10) == [1, 2, 5] assert proper_divisors(100) == [1, 2, 4, 5, 10, 20, 25, 50] assert proper_divisors(1000000007) == [1] assert proper_divisor_count(0) == 0 assert proper_divisor_count(-1) == 0 assert proper_divisor_count(1) == 0 assert proper_divisor_count(36) == 8 assert proper_divisor_count(2*3*5) == 7 def test_udivisors_and_udivisor_count(): assert udivisors(-1) == [1] assert udivisors(0) == [] assert udivisors(1) == [1] assert udivisors(2) == [1, 2] assert udivisors(3) == [1, 3] assert udivisors(17) == [1, 17] assert udivisors(10) == [1, 2, 5, 10] assert udivisors(100) == [1, 4, 25, 100] assert udivisors(101) == [1, 101] assert udivisors(1000) == [1, 8, 125, 1000] assert udivisor_count(0) == 0 assert udivisor_count(-1) == 1 assert udivisor_count(1) == 1 assert udivisor_count(6) == 4 assert udivisor_count(12) == 4 assert udivisor_count(180) == 8 assert udivisor_count(2*3*5*7) == 16 def test_issue_6981(): S = set(divisors(4)).union(set(divisors(Integer(2)))) assert S == {1,2,4} def test_totient(): assert [totient(k) for k in range(1, 12)] == \ [1, 1, 2, 2, 4, 2, 6, 4, 6, 4, 10] assert totient(5005) == 2880 assert totient(5006) == 2502 assert totient(5009) == 5008 assert totient(2**100) == 2**99 raises(ValueError, lambda: totient(30.1)) raises(ValueError, lambda: totient(20.001)) m = Symbol("m", integer=True) assert totient(m) assert totient(m).subs(m, 3**10) == 3**10 - 3**9 assert summation(totient(m), (m, 1, 11)) == 42 n = Symbol("n", integer=True, positive=True) assert totient(n).is_integer x=Symbol("x", integer=False) raises(ValueError, lambda: totient(x)) y=Symbol("y", positive=False) raises(ValueError, lambda: totient(y)) z=Symbol("z", positive=True, integer=True) raises(ValueError, lambda: totient(2**(-z))) def test_reduced_totient(): assert [reduced_totient(k) for k in range(1, 16)] == \ [1, 1, 2, 2, 4, 2, 6, 2, 6, 4, 10, 2, 12, 6, 4] assert reduced_totient(5005) == 60 assert reduced_totient(5006) == 2502 assert reduced_totient(5009) == 5008 assert reduced_totient(2**100) == 2**98 m = Symbol("m", integer=True) assert reduced_totient(m) assert reduced_totient(m).subs(m, 2**3*3**10) == 3**10 - 3**9 assert summation(reduced_totient(m), (m, 1, 16)) == 68 n = Symbol("n", integer=True, positive=True) assert reduced_totient(n).is_integer def test_divisor_sigma(): assert [divisor_sigma(k) for k in range(1, 12)] == \ [1, 3, 4, 7, 6, 12, 8, 15, 13, 18, 12] assert [divisor_sigma(k, 2) for k in range(1, 12)] == \ [1, 5, 10, 21, 26, 50, 50, 85, 91, 130, 122] assert divisor_sigma(23450) == 50592 assert divisor_sigma(23450, 0) == 24 assert divisor_sigma(23450, 1) == 50592 assert divisor_sigma(23450, 2) == 730747500 assert divisor_sigma(23450, 3) == 14666785333344 a = Symbol("a", prime=True) b = Symbol("b", prime=True) j = Symbol("j", integer=True, positive=True) k = Symbol("k", integer=True, positive=True) assert divisor_sigma(a**j*b**k) == (a**(j + 1) - 1)*(b**(k + 1) - 1)/((a - 1)*(b - 1)) assert divisor_sigma(a**j*b**k, 2) == (a**(2*j + 2) - 1)*(b**(2*k + 2) - 1)/((a**2 - 1)*(b**2 - 1)) assert divisor_sigma(a**j*b**k, 0) == (j + 1)*(k + 1) m = Symbol("m", integer=True) k = Symbol("k", integer=True) assert divisor_sigma(m) assert divisor_sigma(m, k) assert divisor_sigma(m).subs(m, 3**10) == 88573 assert divisor_sigma(m, k).subs([(m, 3**10), (k, 3)]) == 213810021790597 assert summation(divisor_sigma(m), (m, 1, 11)) == 99 def test_udivisor_sigma(): assert [udivisor_sigma(k) for k in range(1, 12)] == \ [1, 3, 4, 5, 6, 12, 8, 9, 10, 18, 12] assert [udivisor_sigma(k, 3) for k in range(1, 12)] == \ [1, 9, 28, 65, 126, 252, 344, 513, 730, 1134, 1332] assert udivisor_sigma(23450) == 42432 assert udivisor_sigma(23450, 0) == 16 assert udivisor_sigma(23450, 1) == 42432 assert udivisor_sigma(23450, 2) == 702685000 assert udivisor_sigma(23450, 4) == 321426961814978248 m = Symbol("m", integer=True) k = Symbol("k", integer=True) assert udivisor_sigma(m) assert udivisor_sigma(m, k) assert udivisor_sigma(m).subs(m, 4**9) == 262145 assert udivisor_sigma(m, k).subs([(m, 4**9), (k, 2)]) == 68719476737 assert summation(udivisor_sigma(m), (m, 2, 15)) == 169 def test_issue_4356(): assert factorint(1030903) == {53: 2, 367: 1} def test_divisors(): assert divisors(28) == [1, 2, 4, 7, 14, 28] assert [x for x in divisors(3*5*7, 1)] == [1, 3, 5, 15, 7, 21, 35, 105] assert divisors(0) == [] def test_divisor_count(): assert divisor_count(0) == 0 assert divisor_count(6) == 4 def test_proper_divisors(): assert proper_divisors(-1) == [] assert proper_divisors(28) == [1, 2, 4, 7, 14] assert [x for x in proper_divisors(3*5*7, True)] == [1, 3, 5, 15, 7, 21, 35] def test_proper_divisor_count(): assert proper_divisor_count(6) == 3 assert proper_divisor_count(108) == 11 def test_antidivisors(): assert antidivisors(-1) == [] assert antidivisors(-3) == [2] assert antidivisors(14) == [3, 4, 9] assert antidivisors(237) == [2, 5, 6, 11, 19, 25, 43, 95, 158] assert antidivisors(12345) == [2, 6, 7, 10, 30, 1646, 3527, 4938, 8230] assert antidivisors(393216) == [262144] assert sorted(x for x in antidivisors(3*5*7, 1)) == \ [2, 6, 10, 11, 14, 19, 30, 42, 70] assert antidivisors(1) == [] def test_antidivisor_count(): assert antidivisor_count(0) == 0 assert antidivisor_count(-1) == 0 assert antidivisor_count(-4) == 1 assert antidivisor_count(20) == 3 assert antidivisor_count(25) == 5 assert antidivisor_count(38) == 7 assert antidivisor_count(180) == 6 assert antidivisor_count(2*3*5) == 3 def test_smoothness_and_smoothness_p(): assert smoothness(1) == (1, 1) assert smoothness(2**4*3**2) == (3, 16) assert smoothness_p(10431, m=1) == \ (1, [(3, (2, 2, 4)), (19, (1, 5, 5)), (61, (1, 31, 31))]) assert smoothness_p(10431) == \ (-1, [(3, (2, 2, 2)), (19, (1, 3, 9)), (61, (1, 5, 5))]) assert smoothness_p(10431, power=1) == \ (-1, [(3, (2, 2, 2)), (61, (1, 5, 5)), (19, (1, 3, 9))]) assert smoothness_p(21477639576571, visual=1) == \ 'p**i=4410317**1 has p-1 B=1787, B-pow=1787\n' + \ 'p**i=4869863**1 has p-1 B=2434931, B-pow=2434931' def test_visual_factorint(): assert factorint(1, visual=1) == 1 forty2 = factorint(42, visual=True) assert type(forty2) == Mul assert str(forty2) == '2**1*3**1*7**1' assert factorint(1, visual=True) is S.One no = dict(evaluate=False) assert factorint(42**2, visual=True) == Mul(Pow(2, 2, **no), Pow(3, 2, **no), Pow(7, 2, **no), **no) assert -1 in factorint(-42, visual=True).args def test_factorrat(): assert str(factorrat(S(12)/1, visual=True)) == '2**2*3**1' assert str(factorrat(Rational(1, 1), visual=True)) == '1' assert str(factorrat(S(25)/14, visual=True)) == '5**2/(2*7)' assert str(factorrat(Rational(25, 14), visual=True)) == '5**2/(2*7)' assert str(factorrat(S(-25)/14/9, visual=True)) == '-1*5**2/(2*3**2*7)' assert factorrat(S(12)/1, multiple=True) == [2, 2, 3] assert factorrat(Rational(1, 1), multiple=True) == [] assert factorrat(S(25)/14, multiple=True) == [Rational(1, 7), S.Half, 5, 5] assert factorrat(Rational(25, 14), multiple=True) == [Rational(1, 7), S.Half, 5, 5] assert factorrat(Rational(12, 1), multiple=True) == [2, 2, 3] assert factorrat(S(-25)/14/9, multiple=True) == \ [-1, Rational(1, 7), Rational(1, 3), Rational(1, 3), S.Half, 5, 5] def test_visual_io(): sm = smoothness_p fi = factorint # with smoothness_p n = 124 d = fi(n) m = fi(d, visual=True) t = sm(n) s = sm(t) for th in [d, s, t, n, m]: assert sm(th, visual=True) == s assert sm(th, visual=1) == s for th in [d, s, t, n, m]: assert sm(th, visual=False) == t assert [sm(th, visual=None) for th in [d, s, t, n, m]] == [s, d, s, t, t] assert [sm(th, visual=2) for th in [d, s, t, n, m]] == [s, d, s, t, t] # with factorint for th in [d, m, n]: assert fi(th, visual=True) == m assert fi(th, visual=1) == m for th in [d, m, n]: assert fi(th, visual=False) == d assert [fi(th, visual=None) for th in [d, m, n]] == [m, d, d] assert [fi(th, visual=0) for th in [d, m, n]] == [m, d, d] # test reevaluation no = dict(evaluate=False) assert sm({4: 2}, visual=False) == sm(16) assert sm(Mul(*[Pow(k, v, **no) for k, v in {4: 2, 2: 6}.items()], **no), visual=False) == sm(2**10) assert fi({4: 2}, visual=False) == fi(16) assert fi(Mul(*[Pow(k, v, **no) for k, v in {4: 2, 2: 6}.items()], **no), visual=False) == fi(2**10) def test_core(): assert core(35**13, 10) == 42875 assert core(210**2) == 1 assert core(7776, 3) == 36 assert core(10**27, 22) == 10**5 assert core(537824) == 14 assert core(1, 6) == 1 def test_primenu(): assert primenu(2) == 1 assert primenu(2 * 3) == 2 assert primenu(2 * 3 * 5) == 3 assert primenu(3 * 25) == primenu(3) + primenu(25) assert [primenu(p) for p in primerange(1, 10)] == [1, 1, 1, 1] assert primenu(fac(50)) == 15 assert primenu(2 ** 9941 - 1) == 1 n = Symbol('n', integer=True) assert primenu(n) assert primenu(n).subs(n, 2 ** 31 - 1) == 1 assert summation(primenu(n), (n, 2, 30)) == 43 def test_primeomega(): assert primeomega(2) == 1 assert primeomega(2 * 2) == 2 assert primeomega(2 * 2 * 3) == 3 assert primeomega(3 * 25) == primeomega(3) + primeomega(25) assert [primeomega(p) for p in primerange(1, 10)] == [1, 1, 1, 1] assert primeomega(fac(50)) == 108 assert primeomega(2 ** 9941 - 1) == 1 n = Symbol('n', integer=True) assert primeomega(n) assert primeomega(n).subs(n, 2 ** 31 - 1) == 1 assert summation(primeomega(n), (n, 2, 30)) == 59 def test_mersenne_prime_exponent(): assert mersenne_prime_exponent(1) == 2 assert mersenne_prime_exponent(4) == 7 assert mersenne_prime_exponent(10) == 89 assert mersenne_prime_exponent(25) == 21701 raises(ValueError, lambda: mersenne_prime_exponent(52)) raises(ValueError, lambda: mersenne_prime_exponent(0)) def test_is_perfect(): assert is_perfect(6) is True assert is_perfect(15) is False assert is_perfect(28) is True assert is_perfect(400) is False assert is_perfect(496) is True assert is_perfect(8128) is True assert is_perfect(10000) is False def test_is_mersenne_prime(): assert is_mersenne_prime(10) is False assert is_mersenne_prime(127) is True assert is_mersenne_prime(511) is False assert is_mersenne_prime(131071) is True assert is_mersenne_prime(2147483647) is True def test_is_abundant(): assert is_abundant(10) is False assert is_abundant(12) is True assert is_abundant(18) is True assert is_abundant(21) is False assert is_abundant(945) is True def test_is_deficient(): assert is_deficient(10) is True assert is_deficient(22) is True assert is_deficient(56) is False assert is_deficient(20) is False assert is_deficient(36) is False def test_is_amicable(): assert is_amicable(173, 129) is False assert is_amicable(220, 284) is True assert is_amicable(8756, 8756) is False def test_dra(): assert dra(19, 12) == 8 assert dra(2718, 10) == 9 assert dra(0, 22) == 0 assert dra(23456789, 10) == 8 raises(ValueError, lambda: dra(24, -2)) raises(ValueError, lambda: dra(24.2, 5)) def test_drm(): assert drm(19, 12) == 7 assert drm(2718, 10) == 2 assert drm(0, 15) == 0 assert drm(234161, 10) == 6 raises(ValueError, lambda: drm(24, -2)) raises(ValueError, lambda: drm(11.6, 9)) sympy-sympy-1.9/sympy/ntheory/tests/test_generate.py000066400000000000000000000173671412543434000231570ustar00rootroot00000000000000from sympy import Sieve, sieve, Symbol, S, limit, I, zoo, nan, Rational from sympy.ntheory import isprime, totient, mobius, randprime, nextprime, prevprime, \ primerange, primepi, prime, primorial, composite, compositepi, reduced_totient from sympy.ntheory.generate import cycle_length from sympy.ntheory.primetest import mr from sympy.testing.pytest import raises def test_prime(): assert prime(1) == 2 assert prime(2) == 3 assert prime(5) == 11 assert prime(11) == 31 assert prime(57) == 269 assert prime(296) == 1949 assert prime(559) == 4051 assert prime(3000) == 27449 assert prime(4096) == 38873 assert prime(9096) == 94321 assert prime(25023) == 287341 assert prime(10000000) == 179424673 # issue #20951 assert prime(99999999) == 2038074739 raises(ValueError, lambda: prime(0)) sieve.extend(3000) assert prime(401) == 2749 raises(ValueError , lambda: prime(-1)) def test_primepi(): assert primepi(-1) == 0 assert primepi(1) == 0 assert primepi(2) == 1 assert primepi(Rational(7, 2)) == 2 assert primepi(3.5) == 2 assert primepi(5) == 3 assert primepi(11) == 5 assert primepi(57) == 16 assert primepi(296) == 62 assert primepi(559) == 102 assert primepi(3000) == 430 assert primepi(4096) == 564 assert primepi(9096) == 1128 assert primepi(25023) == 2763 assert primepi(10**8) == 5761455 assert primepi(253425253) == 13856396 assert primepi(8769575643) == 401464322 sieve.extend(3000) assert primepi(2000) == 303 n = Symbol('n') assert primepi(n).subs(n, 2) == 1 r = Symbol('r', real=True) assert primepi(r).subs(r, 2) == 1 assert primepi(S.Infinity) is S.Infinity assert primepi(S.NegativeInfinity) == 0 assert limit(primepi(n), n, 100) == 25 raises(ValueError, lambda: primepi(I)) raises(ValueError, lambda: primepi(1 + I)) raises(ValueError, lambda: primepi(zoo)) raises(ValueError, lambda: primepi(nan)) def test_composite(): from sympy.ntheory.generate import sieve sieve._reset() assert composite(1) == 4 assert composite(2) == 6 assert composite(5) == 10 assert composite(11) == 20 assert composite(41) == 58 assert composite(57) == 80 assert composite(296) == 370 assert composite(559) == 684 assert composite(3000) == 3488 assert composite(4096) == 4736 assert composite(9096) == 10368 assert composite(25023) == 28088 sieve.extend(3000) assert composite(1957) == 2300 assert composite(2568) == 2998 raises(ValueError, lambda: composite(0)) def test_compositepi(): assert compositepi(1) == 0 assert compositepi(2) == 0 assert compositepi(5) == 1 assert compositepi(11) == 5 assert compositepi(57) == 40 assert compositepi(296) == 233 assert compositepi(559) == 456 assert compositepi(3000) == 2569 assert compositepi(4096) == 3531 assert compositepi(9096) == 7967 assert compositepi(25023) == 22259 assert compositepi(10**8) == 94238544 assert compositepi(253425253) == 239568856 assert compositepi(8769575643) == 8368111320 sieve.extend(3000) assert compositepi(2321) == 1976 def test_generate(): from sympy.ntheory.generate import sieve sieve._reset() assert nextprime(-4) == 2 assert nextprime(2) == 3 assert nextprime(5) == 7 assert nextprime(12) == 13 assert prevprime(3) == 2 assert prevprime(7) == 5 assert prevprime(13) == 11 assert prevprime(19) == 17 assert prevprime(20) == 19 sieve.extend_to_no(9) assert sieve._list[-1] == 23 assert sieve._list[-1] < 31 assert 31 in sieve assert nextprime(90) == 97 assert nextprime(10**40) == (10**40 + 121) assert prevprime(97) == 89 assert prevprime(10**40) == (10**40 - 17) assert list(sieve.primerange(10, 1)) == [] assert list(sieve.primerange(5, 9)) == [5, 7] sieve._reset(prime=True) assert list(sieve.primerange(2, 13)) == [2, 3, 5, 7, 11] assert list(sieve.primerange(13)) == [2, 3, 5, 7, 11] assert list(sieve.primerange(8)) == [2, 3, 5, 7] assert list(sieve.primerange(-2)) == [] assert list(sieve.primerange(29)) == [2, 3, 5, 7, 11, 13, 17, 19, 23] assert list(sieve.primerange(34)) == [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31] assert list(sieve.totientrange(5, 15)) == [4, 2, 6, 4, 6, 4, 10, 4, 12, 6] sieve._reset(totient=True) assert list(sieve.totientrange(3, 13)) == [2, 2, 4, 2, 6, 4, 6, 4, 10, 4] assert list(sieve.totientrange(900, 1000)) == [totient(x) for x in range(900, 1000)] assert list(sieve.totientrange(0, 1)) == [] assert list(sieve.totientrange(1, 2)) == [1] assert list(sieve.mobiusrange(5, 15)) == [-1, 1, -1, 0, 0, 1, -1, 0, -1, 1] sieve._reset(mobius=True) assert list(sieve.mobiusrange(3, 13)) == [-1, 0, -1, 1, -1, 0, 0, 1, -1, 0] assert list(sieve.mobiusrange(1050, 1100)) == [mobius(x) for x in range(1050, 1100)] assert list(sieve.mobiusrange(0, 1)) == [] assert list(sieve.mobiusrange(1, 2)) == [1] assert list(primerange(10, 1)) == [] assert list(primerange(2, 7)) == [2, 3, 5] assert list(primerange(2, 10)) == [2, 3, 5, 7] assert list(primerange(1050, 1100)) == [1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097] s = Sieve() for i in range(30, 2350, 376): for j in range(2, 5096, 1139): A = list(s.primerange(i, i + j)) B = list(primerange(i, i + j)) assert A == B s = Sieve() assert s[10] == 29 assert nextprime(2, 2) == 5 raises(ValueError, lambda: totient(0)) raises(ValueError, lambda: reduced_totient(0)) raises(ValueError, lambda: primorial(0)) assert mr(1, [2]) is False func = lambda i: (i**2 + 1) % 51 assert next(cycle_length(func, 4)) == (6, 2) assert list(cycle_length(func, 4, values=True)) == \ [17, 35, 2, 5, 26, 14, 44, 50, 2, 5, 26, 14] assert next(cycle_length(func, 4, nmax=5)) == (5, None) assert list(cycle_length(func, 4, nmax=5, values=True)) == \ [17, 35, 2, 5, 26] sieve.extend(3000) assert nextprime(2968) == 2969 assert prevprime(2930) == 2927 raises(ValueError, lambda: prevprime(1)) raises(ValueError, lambda: prevprime(-4)) def test_randprime(): assert randprime(10, 1) is None assert randprime(3, -3) is None assert randprime(2, 3) == 2 assert randprime(1, 3) == 2 assert randprime(3, 5) == 3 raises(ValueError, lambda: randprime(-12, -2)) raises(ValueError, lambda: randprime(-10, 0)) raises(ValueError, lambda: randprime(20, 22)) raises(ValueError, lambda: randprime(0, 2)) raises(ValueError, lambda: randprime(1, 2)) for a in [100, 300, 500, 250000]: for b in [100, 300, 500, 250000]: p = randprime(a, a + b) assert a <= p < (a + b) and isprime(p) def test_primorial(): assert primorial(1) == 2 assert primorial(1, nth=0) == 1 assert primorial(2) == 6 assert primorial(2, nth=0) == 2 assert primorial(4, nth=0) == 6 def test_search(): assert 2 in sieve assert 2.1 not in sieve assert 1 not in sieve assert 2**1000 not in sieve raises(ValueError, lambda: sieve.search(1)) def test_sieve_slice(): assert sieve[5] == 11 assert list(sieve[5:10]) == [sieve[x] for x in range(5, 10)] assert list(sieve[5:10:2]) == [sieve[x] for x in range(5, 10, 2)] assert list(sieve[1:5]) == [2, 3, 5, 7] raises(IndexError, lambda: sieve[:5]) raises(IndexError, lambda: sieve[0]) raises(IndexError, lambda: sieve[0:5]) def test_sieve_iter(): values = [] for value in sieve: if value > 7: break values.append(value) assert values == list(sieve[1:5]) def test_sieve_repr(): assert "sieve" in repr(sieve) assert "prime" in repr(sieve) sympy-sympy-1.9/sympy/ntheory/tests/test_modular.py000066400000000000000000000026211412543434000230130ustar00rootroot00000000000000from sympy.ntheory.modular import crt, crt1, crt2, solve_congruence from sympy.testing.pytest import raises def test_crt(): def mcrt(m, v, r, symmetric=False): assert crt(m, v, symmetric)[0] == r mm, e, s = crt1(m) assert crt2(m, v, mm, e, s, symmetric) == (r, mm) mcrt([2, 3, 5], [0, 0, 0], 0) mcrt([2, 3, 5], [1, 1, 1], 1) mcrt([2, 3, 5], [-1, -1, -1], -1, True) mcrt([2, 3, 5], [-1, -1, -1], 2*3*5 - 1, False) assert crt([656, 350], [811, 133], symmetric=True) == (-56917, 114800) def test_modular(): assert solve_congruence(*list(zip([3, 4, 2], [12, 35, 17]))) == (1719, 7140) assert solve_congruence(*list(zip([3, 4, 2], [12, 6, 17]))) is None assert solve_congruence(*list(zip([3, 4, 2], [13, 7, 17]))) == (172, 1547) assert solve_congruence(*list(zip([-10, -3, -15], [13, 7, 17]))) == (172, 1547) assert solve_congruence(*list(zip([-10, -3, 1, -15], [13, 7, 7, 17]))) is None assert solve_congruence( *list(zip([-10, -5, 2, -15], [13, 7, 7, 17]))) == (835, 1547) assert solve_congruence( *list(zip([-10, -5, 2, -15], [13, 7, 14, 17]))) == (2382, 3094) assert solve_congruence( *list(zip([-10, 2, 2, -15], [13, 7, 14, 17]))) == (2382, 3094) assert solve_congruence(*list(zip((1, 1, 2), (3, 2, 4)))) is None raises( ValueError, lambda: solve_congruence(*list(zip([3, 4, 2], [12.1, 35, 17])))) sympy-sympy-1.9/sympy/ntheory/tests/test_multinomial.py000066400000000000000000000044221412543434000237030ustar00rootroot00000000000000from sympy import binomial_coefficients, binomial_coefficients_list, multinomial_coefficients from sympy.ntheory.multinomial import multinomial_coefficients_iterator def test_binomial_coefficients_list(): assert binomial_coefficients_list(0) == [1] assert binomial_coefficients_list(1) == [1, 1] assert binomial_coefficients_list(2) == [1, 2, 1] assert binomial_coefficients_list(3) == [1, 3, 3, 1] assert binomial_coefficients_list(4) == [1, 4, 6, 4, 1] assert binomial_coefficients_list(5) == [1, 5, 10, 10, 5, 1] assert binomial_coefficients_list(6) == [1, 6, 15, 20, 15, 6, 1] def test_binomial_coefficients(): for n in range(15): c = binomial_coefficients(n) l = [c[k] for k in sorted(c)] assert l == binomial_coefficients_list(n) def test_multinomial_coefficients(): assert multinomial_coefficients(1, 1) == {(1,): 1} assert multinomial_coefficients(1, 2) == {(2,): 1} assert multinomial_coefficients(1, 3) == {(3,): 1} assert multinomial_coefficients(2, 0) == {(0, 0): 1} assert multinomial_coefficients(2, 1) == {(0, 1): 1, (1, 0): 1} assert multinomial_coefficients(2, 2) == {(2, 0): 1, (0, 2): 1, (1, 1): 2} assert multinomial_coefficients(2, 3) == {(3, 0): 1, (1, 2): 3, (0, 3): 1, (2, 1): 3} assert multinomial_coefficients(3, 1) == {(1, 0, 0): 1, (0, 1, 0): 1, (0, 0, 1): 1} assert multinomial_coefficients(3, 2) == {(0, 1, 1): 2, (0, 0, 2): 1, (1, 1, 0): 2, (0, 2, 0): 1, (1, 0, 1): 2, (2, 0, 0): 1} mc = multinomial_coefficients(3, 3) assert mc == {(2, 1, 0): 3, (0, 3, 0): 1, (1, 0, 2): 3, (0, 2, 1): 3, (0, 1, 2): 3, (3, 0, 0): 1, (2, 0, 1): 3, (1, 2, 0): 3, (1, 1, 1): 6, (0, 0, 3): 1} assert dict(multinomial_coefficients_iterator(2, 0)) == {(0, 0): 1} assert dict( multinomial_coefficients_iterator(2, 1)) == {(0, 1): 1, (1, 0): 1} assert dict(multinomial_coefficients_iterator(2, 2)) == \ {(2, 0): 1, (0, 2): 1, (1, 1): 2} assert dict(multinomial_coefficients_iterator(3, 3)) == mc it = multinomial_coefficients_iterator(7, 2) assert [next(it) for i in range(4)] == \ [((2, 0, 0, 0, 0, 0, 0), 1), ((1, 1, 0, 0, 0, 0, 0), 2), ((0, 2, 0, 0, 0, 0, 0), 1), ((1, 0, 1, 0, 0, 0, 0), 2)] sympy-sympy-1.9/sympy/ntheory/tests/test_partitions.py000066400000000000000000000007731412543434000235520ustar00rootroot00000000000000from sympy.ntheory import npartitions def test_partitions(): assert [npartitions(k) for k in range(13)] == \ [1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42, 56, 77] assert npartitions(100) == 190569292 assert npartitions(200) == 3972999029388 assert npartitions(1000) == 24061467864032622473692149727991 assert npartitions(2000) == 4720819175619413888601432406799959512200344166 assert npartitions(10000) % 10**10 == 6916435144 assert npartitions(100000) % 10**10 == 9421098519 sympy-sympy-1.9/sympy/ntheory/tests/test_primetest.py000066400000000000000000000156111412543434000233670ustar00rootroot00000000000000from sympy.ntheory.generate import Sieve, sieve from sympy.ntheory.primetest import (mr, is_lucas_prp, is_square, is_strong_lucas_prp, is_extra_strong_lucas_prp, isprime, is_euler_pseudoprime, is_gaussian_prime) from sympy.testing.pytest import slow from sympy import I def test_euler_pseudoprimes(): assert is_euler_pseudoprime(9, 1) == True assert is_euler_pseudoprime(341, 2) == False assert is_euler_pseudoprime(121, 3) == True assert is_euler_pseudoprime(341, 4) == True assert is_euler_pseudoprime(217, 5) == False assert is_euler_pseudoprime(185, 6) == False assert is_euler_pseudoprime(55, 111) == True assert is_euler_pseudoprime(115, 114) == True assert is_euler_pseudoprime(49, 117) == True assert is_euler_pseudoprime(85, 84) == True assert is_euler_pseudoprime(87, 88) == True assert is_euler_pseudoprime(49, 128) == True assert is_euler_pseudoprime(39, 77) == True assert is_euler_pseudoprime(9881, 30) == True assert is_euler_pseudoprime(8841, 29) == False assert is_euler_pseudoprime(8421, 29) == False assert is_euler_pseudoprime(9997, 19) == True def test_is_extra_strong_lucas_prp(): assert is_extra_strong_lucas_prp(4) == False assert is_extra_strong_lucas_prp(989) == True assert is_extra_strong_lucas_prp(10877) == True assert is_extra_strong_lucas_prp(9) == False assert is_extra_strong_lucas_prp(16) == False assert is_extra_strong_lucas_prp(169) == False @slow def test_prps(): oddcomposites = [n for n in range(1, 10**5) if n % 2 and not isprime(n)] # A checksum would be better. assert sum(oddcomposites) == 2045603465 assert [n for n in oddcomposites if mr(n, [2])] == [ 2047, 3277, 4033, 4681, 8321, 15841, 29341, 42799, 49141, 52633, 65281, 74665, 80581, 85489, 88357, 90751] assert [n for n in oddcomposites if mr(n, [3])] == [ 121, 703, 1891, 3281, 8401, 8911, 10585, 12403, 16531, 18721, 19345, 23521, 31621, 44287, 47197, 55969, 63139, 74593, 79003, 82513, 87913, 88573, 97567] assert [n for n in oddcomposites if mr(n, [325])] == [ 9, 25, 27, 49, 65, 81, 325, 341, 343, 697, 1141, 2059, 2149, 3097, 3537, 4033, 4681, 4941, 5833, 6517, 7987, 8911, 12403, 12913, 15043, 16021, 20017, 22261, 23221, 24649, 24929, 31841, 35371, 38503, 43213, 44173, 47197, 50041, 55909, 56033, 58969, 59089, 61337, 65441, 68823, 72641, 76793, 78409, 85879] assert not any(mr(n, [9345883071009581737]) for n in oddcomposites) assert [n for n in oddcomposites if is_lucas_prp(n)] == [ 323, 377, 1159, 1829, 3827, 5459, 5777, 9071, 9179, 10877, 11419, 11663, 13919, 14839, 16109, 16211, 18407, 18971, 19043, 22499, 23407, 24569, 25199, 25877, 26069, 27323, 32759, 34943, 35207, 39059, 39203, 39689, 40309, 44099, 46979, 47879, 50183, 51983, 53663, 56279, 58519, 60377, 63881, 69509, 72389, 73919, 75077, 77219, 79547, 79799, 82983, 84419, 86063, 90287, 94667, 97019, 97439] assert [n for n in oddcomposites if is_strong_lucas_prp(n)] == [ 5459, 5777, 10877, 16109, 18971, 22499, 24569, 25199, 40309, 58519, 75077, 97439] assert [n for n in oddcomposites if is_extra_strong_lucas_prp(n) ] == [ 989, 3239, 5777, 10877, 27971, 29681, 30739, 31631, 39059, 72389, 73919, 75077] def test_isprime(): s = Sieve() s.extend(100000) ps = set(s.primerange(2, 100001)) for n in range(100001): # if (n in ps) != isprime(n): print n assert (n in ps) == isprime(n) assert isprime(179424673) assert isprime(20678048681) assert isprime(1968188556461) assert isprime(2614941710599) assert isprime(65635624165761929287) assert isprime(1162566711635022452267983) assert isprime(77123077103005189615466924501) assert isprime(3991617775553178702574451996736229) assert isprime(273952953553395851092382714516720001799) assert isprime(int(''' 531137992816767098689588206552468627329593117727031923199444138200403\ 559860852242739162502265229285668889329486246501015346579337652707239\ 409519978766587351943831270835393219031728127''')) # Some Mersenne primes assert isprime(2**61 - 1) assert isprime(2**89 - 1) assert isprime(2**607 - 1) # (but not all Mersenne's are primes assert not isprime(2**601 - 1) # pseudoprimes #------------- # to some small bases assert not isprime(2152302898747) assert not isprime(3474749660383) assert not isprime(341550071728321) assert not isprime(3825123056546413051) # passes the base set [2, 3, 7, 61, 24251] assert not isprime(9188353522314541) # large examples assert not isprime(877777777777777777777777) # conjectured psi_12 given at http://mathworld.wolfram.com/StrongPseudoprime.html assert not isprime(318665857834031151167461) # conjectured psi_17 given at http://mathworld.wolfram.com/StrongPseudoprime.html assert not isprime(564132928021909221014087501701) # Arnault's 1993 number; a factor of it is # 400958216639499605418306452084546853005188166041132508774506\ # 204738003217070119624271622319159721973358216316508535816696\ # 9145233813917169287527980445796800452592031836601 assert not isprime(int(''' 803837457453639491257079614341942108138837688287558145837488917522297\ 427376533365218650233616396004545791504202360320876656996676098728404\ 396540823292873879185086916685732826776177102938969773947016708230428\ 687109997439976544144845341155872450633409279022275296229414984230688\ 1685404326457534018329786111298960644845216191652872597534901''')) # Arnault's 1995 number; can be factored as # p1*(313*(p1 - 1) + 1)*(353*(p1 - 1) + 1) where p1 is # 296744956686855105501541746429053327307719917998530433509950\ # 755312768387531717701995942385964281211880336647542183455624\ # 93168782883 assert not isprime(int(''' 288714823805077121267142959713039399197760945927972270092651602419743\ 230379915273311632898314463922594197780311092934965557841894944174093\ 380561511397999942154241693397290542371100275104208013496673175515285\ 922696291677532547504444585610194940420003990443211677661994962953925\ 045269871932907037356403227370127845389912612030924484149472897688540\ 6024976768122077071687938121709811322297802059565867''')) sieve.extend(3000) assert isprime(2819) assert not isprime(2931) assert not isprime(2.0) def test_is_square(): assert [i for i in range(25) if is_square(i)] == [0, 1, 4, 9, 16] # issue #17044 assert not is_square(60 ** 3) assert not is_square(60 ** 5) assert not is_square(84 ** 7) assert not is_square(105 ** 9) assert not is_square(120 ** 3) def test_is_gaussianprime(): assert is_gaussian_prime(7*I) assert is_gaussian_prime(7) assert is_gaussian_prime(2 + 3*I) assert not is_gaussian_prime(2 + 2*I) sympy-sympy-1.9/sympy/ntheory/tests/test_qs.py000066400000000000000000000100241412543434000217670ustar00rootroot00000000000000from typing import Dict, Tuple from sympy.ntheory import qs from sympy.ntheory.qs import SievePolynomial, \ _generate_factor_base, _initialize_first_polynomial, _initialize_ith_poly, \ _gen_sieve_array, _check_smoothness, _trial_division_stage, _gauss_mod_2, \ _build_matrix, _find_factor assert qs(10009202107, 100, 10000) == {100043, 100049} assert qs(211107295182713951054568361 , 1000, 10000) == {13791315212531, 15307263442931} assert qs(980835832582657*990377764891511, 3000, 50000) == {980835832582657, 990377764891511} assert qs(18640889198609*20991129234731, 1000, 50000) == {18640889198609, 20991129234731} n = 10009202107 M = 50 #a = 10, b = 15, modified_coeff = [a**2, 2*a*b, b**2 - N] sieve_poly = SievePolynomial([100, 1600, -10009195707], 10, 80) assert sieve_poly.eval(10) == -10009169707 assert sieve_poly.eval(5) == -10009185207 idx_1000, idx_5000, factor_base = _generate_factor_base(2000, n) assert idx_1000 == 82 assert [factor_base[i].prime for i in range(15)] == [2, 3, 7, 11, 17, 19, 29, 31,\ 43, 59, 61, 67, 71, 73, 79] assert [factor_base[i].tmem_p for i in range(15)] == [1, 1, 3, 5, 3, 6, 6, 14, 1,\ 16, 24, 22, 18, 22, 15] assert [factor_base[i].log_p for i in range(5)] == [710, 1125, 1993, 2455, 2901] g, B = _initialize_first_polynomial(n, M, factor_base, idx_1000, idx_5000, seed=0) assert g.a == 1133107 assert g.b == 682543 assert B == [272889, 409654] assert [factor_base[i].soln1 for i in range(15)] == [0, 0, 3, 7, 13, 0, 8, 19,\ 9, 43, 27, 25, 63, 29, 19] assert [factor_base[i].soln2 for i in range(15)] == [0, 1, 1, 3, 12, 16, 15, 6,\ 15, 1, 56, 55, 61, 58, 16] assert [factor_base[i].a_inv for i in range(15)] == [1, 1, 5, 7, 3, 5, 26, 6,\ 40, 5, 21, 45, 4, 1, 8] assert [factor_base[i].b_ainv for i in range(5)] == [[0, 0], [0, 2], [3, 0],\ [3, 9], [13, 13]] g_1 = _initialize_ith_poly(n, factor_base, 1, g, B) assert g_1.a == 1133107 assert g_1.b == 136765 sieve_array = _gen_sieve_array(M, factor_base) assert sieve_array[0:5] == [8424, 13603, 1835, 5335, 710] assert _check_smoothness(9645, factor_base) == (5, False) assert _check_smoothness(210313, factor_base)[0][0:15] == [0, 0, 0, 0, 0, 0, 0,\ 0, 0, 1, 0, 0, 1, 0, 1] assert _check_smoothness(210313, factor_base)[1] == True partial_relations = {} # type: Dict[int, Tuple[int, int]] smooth_relation, partial_relation = _trial_division_stage(n, M, factor_base,\ sieve_array, sieve_poly,\ partial_relations, ERROR_TERM=25*2**10) assert partial_relations == {8699: (440, -10009008507), 166741: (490, -10008962007), 131449: (530, -10008921207), 6653: (550, -10008899607)} assert [smooth_relation[i][0] for i in range(5)] == [-250, -670615476700,\ -45211565844500, -231723037747200, -1811665537200] assert [smooth_relation[i][1] for i in range(5)] == [-10009139607, 1133094251961,\ 5302606761, 53804049849, 1950723889] assert smooth_relation[0][2][0:15] == [1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] assert _gauss_mod_2([[0, 0, 1], [1, 0, 1], [0, 1, 0], [0, 1, 1], [0, 1, 1]]) ==\ ([[[0, 1, 1], 3], [[0, 1, 1], 4]], [True, True, True, False, False], [[0, 0, 1],\ [1, 0, 0], [0, 1, 0], [0, 1, 1], [0, 1, 1]]) N=1817 smooth_relations = [(2455024, 637, [0, 0, 0, 1]), (-27993000, 81536, [0, 1, 0, 1]), (11461840, 12544, [0, 0, 0, 0]), (149, 20384, [0, 1, 0, 1]), (-31138074, 19208, [0, 1, 0, 0])] matrix = _build_matrix(smooth_relations) assert matrix == [[0, 0, 0, 1], [0, 1, 0, 1], [0, 0, 0, 0], [0, 1, 0, 1], [0, 1, 0, 0]] dependent_row, mark, gauss_matrix = _gauss_mod_2(matrix) assert dependent_row == [[[0, 0, 0, 0], 2], [[0, 1, 0, 0], 3]] assert mark == [True, True, False, False, True] assert gauss_matrix == [[0, 0, 0, 1], [0, 1, 0, 0], [0, 0, 0, 0], [0, 1, 0, 0], [0, 1, 0, 1]] factor = _find_factor(dependent_row, mark, gauss_matrix, 0, smooth_relations, N) assert factor == 23 sympy-sympy-1.9/sympy/ntheory/tests/test_residue.py000066400000000000000000000310701412543434000230100ustar00rootroot00000000000000from collections import defaultdict from sympy import S, Symbol, Tuple, Dummy from sympy.ntheory import n_order, is_primitive_root, is_quad_residue, \ legendre_symbol, jacobi_symbol, totient, primerange, sqrt_mod, \ primitive_root, quadratic_residues, is_nthpow_residue, nthroot_mod, \ sqrt_mod_iter, mobius, discrete_log, quadratic_congruence, \ polynomial_congruence from sympy.ntheory.residue_ntheory import _primitive_root_prime_iter, \ _discrete_log_trial_mul, _discrete_log_shanks_steps, \ _discrete_log_pollard_rho, _discrete_log_pohlig_hellman from sympy.polys.domains import ZZ from sympy.testing.pytest import raises def test_residue(): assert n_order(2, 13) == 12 assert [n_order(a, 7) for a in range(1, 7)] == \ [1, 3, 6, 3, 6, 2] assert n_order(5, 17) == 16 assert n_order(17, 11) == n_order(6, 11) assert n_order(101, 119) == 6 assert n_order(11, (10**50 + 151)**2) == 10000000000000000000000000000000000000000000000030100000000000000000000000000000000000000000000022650 raises(ValueError, lambda: n_order(6, 9)) assert is_primitive_root(2, 7) is False assert is_primitive_root(3, 8) is False assert is_primitive_root(11, 14) is False assert is_primitive_root(12, 17) == is_primitive_root(29, 17) raises(ValueError, lambda: is_primitive_root(3, 6)) for p in primerange(3, 100): it = _primitive_root_prime_iter(p) assert len(list(it)) == totient(totient(p)) assert primitive_root(97) == 5 assert primitive_root(97**2) == 5 assert primitive_root(40487) == 5 # note that primitive_root(40487) + 40487 = 40492 is a primitive root # of 40487**2, but it is not the smallest assert primitive_root(40487**2) == 10 assert primitive_root(82) == 7 p = 10**50 + 151 assert primitive_root(p) == 11 assert primitive_root(2*p) == 11 assert primitive_root(p**2) == 11 raises(ValueError, lambda: primitive_root(-3)) assert is_quad_residue(3, 7) is False assert is_quad_residue(10, 13) is True assert is_quad_residue(12364, 139) == is_quad_residue(12364 % 139, 139) assert is_quad_residue(207, 251) is True assert is_quad_residue(0, 1) is True assert is_quad_residue(1, 1) is True assert is_quad_residue(0, 2) == is_quad_residue(1, 2) is True assert is_quad_residue(1, 4) is True assert is_quad_residue(2, 27) is False assert is_quad_residue(13122380800, 13604889600) is True assert [j for j in range(14) if is_quad_residue(j, 14)] == \ [0, 1, 2, 4, 7, 8, 9, 11] raises(ValueError, lambda: is_quad_residue(1.1, 2)) raises(ValueError, lambda: is_quad_residue(2, 0)) assert quadratic_residues(S.One) == [0] assert quadratic_residues(1) == [0] assert quadratic_residues(12) == [0, 1, 4, 9] assert quadratic_residues(12) == [0, 1, 4, 9] assert quadratic_residues(13) == [0, 1, 3, 4, 9, 10, 12] assert [len(quadratic_residues(i)) for i in range(1, 20)] == \ [1, 2, 2, 2, 3, 4, 4, 3, 4, 6, 6, 4, 7, 8, 6, 4, 9, 8, 10] assert list(sqrt_mod_iter(6, 2)) == [0] assert sqrt_mod(3, 13) == 4 assert sqrt_mod(3, -13) == 4 assert sqrt_mod(6, 23) == 11 assert sqrt_mod(345, 690) == 345 assert sqrt_mod(67, 101) == None assert sqrt_mod(1020, 104729) == None for p in range(3, 100): d = defaultdict(list) for i in range(p): d[pow(i, 2, p)].append(i) for i in range(1, p): it = sqrt_mod_iter(i, p) v = sqrt_mod(i, p, True) if v: v = sorted(v) assert d[i] == v else: assert not d[i] assert sqrt_mod(9, 27, True) == [3, 6, 12, 15, 21, 24] assert sqrt_mod(9, 81, True) == [3, 24, 30, 51, 57, 78] assert sqrt_mod(9, 3**5, True) == [3, 78, 84, 159, 165, 240] assert sqrt_mod(81, 3**4, True) == [0, 9, 18, 27, 36, 45, 54, 63, 72] assert sqrt_mod(81, 3**5, True) == [9, 18, 36, 45, 63, 72, 90, 99, 117,\ 126, 144, 153, 171, 180, 198, 207, 225, 234] assert sqrt_mod(81, 3**6, True) == [9, 72, 90, 153, 171, 234, 252, 315,\ 333, 396, 414, 477, 495, 558, 576, 639, 657, 720] assert sqrt_mod(81, 3**7, True) == [9, 234, 252, 477, 495, 720, 738, 963,\ 981, 1206, 1224, 1449, 1467, 1692, 1710, 1935, 1953, 2178] for a, p in [(26214400, 32768000000), (26214400, 16384000000), (262144, 1048576), (87169610025, 163443018796875), (22315420166400, 167365651248000000)]: assert pow(sqrt_mod(a, p), 2, p) == a n = 70 a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+2) it = sqrt_mod_iter(a, p) for i in range(10): assert pow(next(it), 2, p) == a a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+3) it = sqrt_mod_iter(a, p) for i in range(2): assert pow(next(it), 2, p) == a n = 100 a, p = 5**2*3**n*2**n, 5**6*3**(n+1)*2**(n+1) it = sqrt_mod_iter(a, p) for i in range(2): assert pow(next(it), 2, p) == a assert type(next(sqrt_mod_iter(9, 27))) is int assert type(next(sqrt_mod_iter(9, 27, ZZ))) is type(ZZ(1)) assert type(next(sqrt_mod_iter(1, 7, ZZ))) is type(ZZ(1)) assert is_nthpow_residue(2, 1, 5) #issue 10816 assert is_nthpow_residue(1, 0, 1) is False assert is_nthpow_residue(1, 0, 2) is True assert is_nthpow_residue(3, 0, 2) is True assert is_nthpow_residue(0, 1, 8) is True assert is_nthpow_residue(2, 3, 2) is True assert is_nthpow_residue(2, 3, 9) is False assert is_nthpow_residue(3, 5, 30) is True assert is_nthpow_residue(21, 11, 20) is True assert is_nthpow_residue(7, 10, 20) is False assert is_nthpow_residue(5, 10, 20) is True assert is_nthpow_residue(3, 10, 48) is False assert is_nthpow_residue(1, 10, 40) is True assert is_nthpow_residue(3, 10, 24) is False assert is_nthpow_residue(1, 10, 24) is True assert is_nthpow_residue(3, 10, 24) is False assert is_nthpow_residue(2, 10, 48) is False assert is_nthpow_residue(81, 3, 972) is False assert is_nthpow_residue(243, 5, 5103) is True assert is_nthpow_residue(243, 3, 1240029) is False assert is_nthpow_residue(36010, 8, 87382) is True assert is_nthpow_residue(28552, 6, 2218) is True assert is_nthpow_residue(92712, 9, 50026) is True x = {pow(i, 56, 1024) for i in range(1024)} assert {a for a in range(1024) if is_nthpow_residue(a, 56, 1024)} == x x = { pow(i, 256, 2048) for i in range(2048)} assert {a for a in range(2048) if is_nthpow_residue(a, 256, 2048)} == x x = { pow(i, 11, 324000) for i in range(1000)} assert [ is_nthpow_residue(a, 11, 324000) for a in x] x = { pow(i, 17, 22217575536) for i in range(1000)} assert [ is_nthpow_residue(a, 17, 22217575536) for a in x] assert is_nthpow_residue(676, 3, 5364) assert is_nthpow_residue(9, 12, 36) assert is_nthpow_residue(32, 10, 41) assert is_nthpow_residue(4, 2, 64) assert is_nthpow_residue(31, 4, 41) assert not is_nthpow_residue(2, 2, 5) assert is_nthpow_residue(8547, 12, 10007) assert is_nthpow_residue(Dummy(even=True) + 3, 3, 2) == True assert nthroot_mod(Dummy(odd=True), 3, 2) == 1 assert nthroot_mod(29, 31, 74) == [45] assert nthroot_mod(1801, 11, 2663) == 44 for a, q, p in [(51922, 2, 203017), (43, 3, 109), (1801, 11, 2663), (26118163, 1303, 33333347), (1499, 7, 2663), (595, 6, 2663), (1714, 12, 2663), (28477, 9, 33343)]: r = nthroot_mod(a, q, p) assert pow(r, q, p) == a assert nthroot_mod(11, 3, 109) is None assert nthroot_mod(16, 5, 36, True) == [4, 22] assert nthroot_mod(9, 16, 36, True) == [3, 9, 15, 21, 27, 33] assert nthroot_mod(4, 3, 3249000) == [] assert nthroot_mod(36010, 8, 87382, True) == [40208, 47174] assert nthroot_mod(0, 12, 37, True) == [0] assert nthroot_mod(0, 7, 100, True) == [0, 10, 20, 30, 40, 50, 60, 70, 80, 90] assert nthroot_mod(4, 4, 27, True) == [5, 22] assert nthroot_mod(4, 4, 121, True) == [19, 102] assert nthroot_mod(2, 3, 7, True) == [] for p in range(5, 100): qv = range(3, p, 4) for q in qv: d = defaultdict(list) for i in range(p): d[pow(i, q, p)].append(i) for a in range(1, p - 1): res = nthroot_mod(a, q, p, True) if d[a]: assert d[a] == res else: assert res == [] assert legendre_symbol(5, 11) == 1 assert legendre_symbol(25, 41) == 1 assert legendre_symbol(67, 101) == -1 assert legendre_symbol(0, 13) == 0 assert legendre_symbol(9, 3) == 0 raises(ValueError, lambda: legendre_symbol(2, 4)) assert jacobi_symbol(25, 41) == 1 assert jacobi_symbol(-23, 83) == -1 assert jacobi_symbol(3, 9) == 0 assert jacobi_symbol(42, 97) == -1 assert jacobi_symbol(3, 5) == -1 assert jacobi_symbol(7, 9) == 1 assert jacobi_symbol(0, 3) == 0 assert jacobi_symbol(0, 1) == 1 assert jacobi_symbol(2, 1) == 1 assert jacobi_symbol(1, 3) == 1 raises(ValueError, lambda: jacobi_symbol(3, 8)) assert mobius(13*7) == 1 assert mobius(1) == 1 assert mobius(13*7*5) == -1 assert mobius(13**2) == 0 raises(ValueError, lambda: mobius(-3)) p = Symbol('p', integer=True, positive=True, prime=True) x = Symbol('x', positive=True) i = Symbol('i', integer=True) assert mobius(p) == -1 raises(TypeError, lambda: mobius(x)) raises(ValueError, lambda: mobius(i)) assert _discrete_log_trial_mul(587, 2**7, 2) == 7 assert _discrete_log_trial_mul(941, 7**18, 7) == 18 assert _discrete_log_trial_mul(389, 3**81, 3) == 81 assert _discrete_log_trial_mul(191, 19**123, 19) == 123 assert _discrete_log_shanks_steps(442879, 7**2, 7) == 2 assert _discrete_log_shanks_steps(874323, 5**19, 5) == 19 assert _discrete_log_shanks_steps(6876342, 7**71, 7) == 71 assert _discrete_log_shanks_steps(2456747, 3**321, 3) == 321 assert _discrete_log_pollard_rho(6013199, 2**6, 2, rseed=0) == 6 assert _discrete_log_pollard_rho(6138719, 2**19, 2, rseed=0) == 19 assert _discrete_log_pollard_rho(36721943, 2**40, 2, rseed=0) == 40 assert _discrete_log_pollard_rho(24567899, 3**333, 3, rseed=0) == 333 raises(ValueError, lambda: _discrete_log_pollard_rho(11, 7, 31, rseed=0)) raises(ValueError, lambda: _discrete_log_pollard_rho(227, 3**7, 5, rseed=0)) assert _discrete_log_pohlig_hellman(98376431, 11**9, 11) == 9 assert _discrete_log_pohlig_hellman(78723213, 11**31, 11) == 31 assert _discrete_log_pohlig_hellman(32942478, 11**98, 11) == 98 assert _discrete_log_pohlig_hellman(14789363, 11**444, 11) == 444 assert discrete_log(587, 2**9, 2) == 9 assert discrete_log(2456747, 3**51, 3) == 51 assert discrete_log(32942478, 11**127, 11) == 127 assert discrete_log(432751500361, 7**324, 7) == 324 args = 5779, 3528, 6215 assert discrete_log(*args) == 687 assert discrete_log(*Tuple(*args)) == 687 assert quadratic_congruence(400, 85, 125, 1600) == [295, 615, 935, 1255, 1575] assert quadratic_congruence(3, 6, 5, 25) == [3, 20] assert quadratic_congruence(120, 80, 175, 500) == [] assert quadratic_congruence(15, 14, 7, 2) == [1] assert quadratic_congruence(8, 15, 7, 29) == [10, 28] assert quadratic_congruence(160, 200, 300, 461) == [144, 431] assert quadratic_congruence(100000, 123456, 7415263, 48112959837082048697) == [30417843635344493501, 36001135160550533083] assert quadratic_congruence(65, 121, 72, 277) == [249, 252] assert quadratic_congruence(5, 10, 14, 2) == [0] assert quadratic_congruence(10, 17, 19, 2) == [1] assert quadratic_congruence(10, 14, 20, 2) == [0, 1] assert polynomial_congruence(6*x**5 + 10*x**4 + 5*x**3 + x**2 + x + 1, 972000) == [220999, 242999, 463999, 485999, 706999, 728999, 949999, 971999] assert polynomial_congruence(x**3 - 10*x**2 + 12*x - 82, 33075) == [30287] assert polynomial_congruence(x**2 + x + 47, 2401) == [785, 1615] assert polynomial_congruence(10*x**2 + 14*x + 20, 2) == [0, 1] assert polynomial_congruence(x**3 + 3, 16) == [5] assert polynomial_congruence(65*x**2 + 121*x + 72, 277) == [249, 252] assert polynomial_congruence(x**4 - 4, 27) == [5, 22] assert polynomial_congruence(35*x**3 - 6*x**2 - 567*x + 2308, 148225) == [86957, 111157, 122531, 146731] assert polynomial_congruence(x**16 - 9, 36) == [3, 9, 15, 21, 27, 33] assert polynomial_congruence(x**6 - 2*x**5 - 35, 6125) == [3257] raises(ValueError, lambda: polynomial_congruence(x**x, 6125)) raises(ValueError, lambda: polynomial_congruence(x**i, 6125)) raises(ValueError, lambda: polynomial_congruence(0.1*x**2 + 6, 100)) sympy-sympy-1.9/sympy/parsing/000077500000000000000000000000001412543434000165475ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/__init__.py000066400000000000000000000001751412543434000206630ustar00rootroot00000000000000"""Used for translating a string into a SymPy expression. """ __all__ = ['parse_expr'] from .sympy_parser import parse_expr sympy-sympy-1.9/sympy/parsing/ast_parser.py000066400000000000000000000052261412543434000212710ustar00rootroot00000000000000""" This module implements the functionality to take any Python expression as a string and fix all numbers and other things before evaluating it, thus 1/2 returns Integer(1)/Integer(2) We use the ast module for this. It is well documented at docs.python.org. Some tips to understand how this works: use dump() to get a nice representation of any node. Then write a string of what you want to get, e.g. "Integer(1)", parse it, dump it and you'll see that you need to do "Call(Name('Integer', Load()), [node], [], None, None)". You don't need to bother with lineno and col_offset, just call fix_missing_locations() before returning the node. """ from sympy.core.basic import Basic from sympy.core.sympify import SympifyError from ast import parse, NodeTransformer, Call, Name, Load, \ fix_missing_locations, Str, Tuple class Transform(NodeTransformer): def __init__(self, local_dict, global_dict): NodeTransformer.__init__(self) self.local_dict = local_dict self.global_dict = global_dict def visit_Num(self, node): if isinstance(node.n, int): return fix_missing_locations(Call(func=Name('Integer', Load()), args=[node], keywords=[])) elif isinstance(node.n, float): return fix_missing_locations(Call(func=Name('Float', Load()), args=[node], keywords=[])) return node def visit_Name(self, node): if node.id in self.local_dict: return node elif node.id in self.global_dict: name_obj = self.global_dict[node.id] if isinstance(name_obj, (Basic, type)) or callable(name_obj): return node elif node.id in ['True', 'False']: return node return fix_missing_locations(Call(func=Name('Symbol', Load()), args=[Str(node.id)], keywords=[])) def visit_Lambda(self, node): args = [self.visit(arg) for arg in node.args.args] body = self.visit(node.body) n = Call(func=Name('Lambda', Load()), args=[Tuple(args, Load()), body], keywords=[]) return fix_missing_locations(n) def parse_expr(s, local_dict): """ Converts the string "s" to a SymPy expression, in local_dict. It converts all numbers to Integers before feeding it to Python and automatically creates Symbols. """ global_dict = {} exec('from sympy import *', global_dict) try: a = parse(s.strip(), mode="eval") except SyntaxError: raise SympifyError("Cannot parse %s." % repr(s)) a = Transform(local_dict, global_dict).visit(a) e = compile(a, "", "eval") return eval(e, global_dict, local_dict) sympy-sympy-1.9/sympy/parsing/autolev/000077500000000000000000000000001412543434000202265ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/autolev/Autolev.g4000066400000000000000000000100721412543434000221010ustar00rootroot00000000000000grammar Autolev; prog: stat+; stat: varDecl | functionCall | codeCommands | massDecl | inertiaDecl | assignment | settings ; assignment: vec equals expr #vecAssign | ID '[' index ']' equals expr #indexAssign | ID diff? equals expr #regularAssign; equals: ('='|'+='|'-='|':='|'*='|'/='|'^='); index: expr (',' expr)* ; diff: ('\'')+; functionCall: ID '(' (expr (',' expr)*)? ')' | (Mass|Inertia) '(' (ID (',' ID)*)? ')'; varDecl: varType varDecl2 (',' varDecl2)*; varType: Newtonian|Frames|Bodies|Particles|Points|Constants | Specifieds|Imaginary|Variables ('\'')*|MotionVariables ('\'')*; varDecl2: ID ('{' INT ',' INT '}')? (('{' INT ':' INT (',' INT ':' INT)* '}'))? ('{' INT '}')? ('+'|'-')? ('\'')* ('=' expr)?; ranges: ('{' INT ':' INT (',' INT ':' INT)* '}'); massDecl: Mass massDecl2 (',' massDecl2)*; massDecl2: ID '=' expr; inertiaDecl: Inertia ID ('(' ID ')')? (',' expr)+; matrix: '[' expr ((','|';') expr)* ']'; matrixInOutput: (ID (ID '=' (FLOAT|INT)?))|FLOAT|INT; codeCommands: units | inputs | outputs | codegen | commands; settings: ID (EXP|ID|FLOAT|INT)?; units: UnitSystem ID (',' ID)*; inputs: Input inputs2 (',' inputs2)*; id_diff: ID diff?; inputs2: id_diff '=' expr expr?; outputs: Output outputs2 (',' outputs2)*; outputs2: expr expr?; codegen: ID functionCall ('['matrixInOutput (',' matrixInOutput)*']')? ID'.'ID; commands: Save ID'.'ID | Encode ID (',' ID)*; vec: ID ('>')+ | '0>' | '1>>'; expr: expr '^' expr # Exponent | expr ('*'|'/') expr # MulDiv | expr ('+'|'-') expr # AddSub | EXP # exp | '-' expr # negativeOne | FLOAT # float | INT # int | ID('\'')* # id | vec # VectorOrDyadic | ID '['expr (',' expr)* ']' # Indexing | functionCall # function | matrix # matrices | '(' expr ')' # parens | expr '=' expr # idEqualsExpr | expr ':' expr # colon | ID? ranges ('\'')* # rangess ; // These are to take care of the case insensitivity of Autolev. Mass: ('M'|'m')('A'|'a')('S'|'s')('S'|'s'); Inertia: ('I'|'i')('N'|'n')('E'|'e')('R'|'r')('T'|'t')('I'|'i')('A'|'a'); Input: ('I'|'i')('N'|'n')('P'|'p')('U'|'u')('T'|'t')('S'|'s')?; Output: ('O'|'o')('U'|'u')('T'|'t')('P'|'p')('U'|'u')('T'|'t'); Save: ('S'|'s')('A'|'a')('V'|'v')('E'|'e'); UnitSystem: ('U'|'u')('N'|'n')('I'|'i')('T'|'t')('S'|'s')('Y'|'y')('S'|'s')('T'|'t')('E'|'e')('M'|'m'); Encode: ('E'|'e')('N'|'n')('C'|'c')('O'|'o')('D'|'d')('E'|'e'); Newtonian: ('N'|'n')('E'|'e')('W'|'w')('T'|'t')('O'|'o')('N'|'n')('I'|'i')('A'|'a')('N'|'n'); Frames: ('F'|'f')('R'|'r')('A'|'a')('M'|'m')('E'|'e')('S'|'s')?; Bodies: ('B'|'b')('O'|'o')('D'|'d')('I'|'i')('E'|'e')('S'|'s')?; Particles: ('P'|'p')('A'|'a')('R'|'r')('T'|'t')('I'|'i')('C'|'c')('L'|'l')('E'|'e')('S'|'s')?; Points: ('P'|'p')('O'|'o')('I'|'i')('N'|'n')('T'|'t')('S'|'s')?; Constants: ('C'|'c')('O'|'o')('N'|'n')('S'|'s')('T'|'t')('A'|'a')('N'|'n')('T'|'t')('S'|'s')?; Specifieds: ('S'|'s')('P'|'p')('E'|'e')('C'|'c')('I'|'i')('F'|'f')('I'|'i')('E'|'e')('D'|'d')('S'|'s')?; Imaginary: ('I'|'i')('M'|'m')('A'|'a')('G'|'g')('I'|'i')('N'|'n')('A'|'a')('R'|'r')('Y'|'y'); Variables: ('V'|'v')('A'|'a')('R'|'r')('I'|'i')('A'|'a')('B'|'b')('L'|'l')('E'|'e')('S'|'s')?; MotionVariables: ('M'|'m')('O'|'o')('T'|'t')('I'|'i')('O'|'o')('N'|'n')('V'|'v')('A'|'a')('R'|'r')('I'|'i')('A'|'a')('B'|'b')('L'|'l')('E'|'e')('S'|'s')?; fragment DIFF: ('\'')*; fragment DIGIT: [0-9]; INT: [0-9]+ ; // match integers FLOAT: DIGIT+ '.' DIGIT* | '.' DIGIT+; EXP: FLOAT 'E' INT | FLOAT 'E' '-' INT; LINE_COMMENT : '%' .*? '\r'? '\n' -> skip ; ID: [a-zA-Z][a-zA-Z0-9_]*; WS: [ \t\r\n&]+ -> skip ; // toss out whitespace sympy-sympy-1.9/sympy/parsing/autolev/__init__.py000066400000000000000000000070331412543434000223420ustar00rootroot00000000000000from sympy.external import import_module from sympy.utilities.decorator import doctest_depends_on @doctest_depends_on(modules=('antlr4',)) def parse_autolev(autolev_code, include_numeric=False): """Parses Autolev code (version 4.1) to SymPy code. Parameters ========= autolev_code : Can be an str or any object with a readlines() method (such as a file handle or StringIO). include_numeric : boolean, optional If True NumPy, PyDy, or other numeric code is included for numeric evaluation lines in the Autolev code. Returns ======= sympy_code : str Equivalent sympy and/or numpy/pydy code as the input code. Example (Double Pendulum) ========================= >>> my_al_text = ("MOTIONVARIABLES' Q{2}', U{2}'", ... "CONSTANTS L,M,G", ... "NEWTONIAN N", ... "FRAMES A,B", ... "SIMPROT(N, A, 3, Q1)", ... "SIMPROT(N, B, 3, Q2)", ... "W_A_N>=U1*N3>", ... "W_B_N>=U2*N3>", ... "POINT O", ... "PARTICLES P,R", ... "P_O_P> = L*A1>", ... "P_P_R> = L*B1>", ... "V_O_N> = 0>", ... "V2PTS(N, A, O, P)", ... "V2PTS(N, B, P, R)", ... "MASS P=M, R=M", ... "Q1' = U1", ... "Q2' = U2", ... "GRAVITY(G*N1>)", ... "ZERO = FR() + FRSTAR()", ... "KANE()", ... "INPUT M=1,G=9.81,L=1", ... "INPUT Q1=.1,Q2=.2,U1=0,U2=0", ... "INPUT TFINAL=10, INTEGSTP=.01", ... "CODE DYNAMICS() some_filename.c") >>> my_al_text = '\\n'.join(my_al_text) >>> from sympy.parsing.autolev import parse_autolev >>> print(parse_autolev(my_al_text, include_numeric=True)) import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np q1, q2, u1, u2 = _me.dynamicsymbols('q1 q2 u1 u2') q1_d, q2_d, u1_d, u2_d = _me.dynamicsymbols('q1_ q2_ u1_ u2_', 1) l, m, g = _sm.symbols('l m g', real=True) frame_n = _me.ReferenceFrame('n') frame_a = _me.ReferenceFrame('a') frame_b = _me.ReferenceFrame('b') frame_a.orient(frame_n, 'Axis', [q1, frame_n.z]) frame_b.orient(frame_n, 'Axis', [q2, frame_n.z]) frame_a.set_ang_vel(frame_n, u1*frame_n.z) frame_b.set_ang_vel(frame_n, u2*frame_n.z) point_o = _me.Point('o') particle_p = _me.Particle('p', _me.Point('p_pt'), _sm.Symbol('m')) particle_r = _me.Particle('r', _me.Point('r_pt'), _sm.Symbol('m')) particle_p.point.set_pos(point_o, l*frame_a.x) particle_r.point.set_pos(particle_p.point, l*frame_b.x) point_o.set_vel(frame_n, 0) particle_p.point.v2pt_theory(point_o,frame_n,frame_a) particle_r.point.v2pt_theory(particle_p.point,frame_n,frame_b) particle_p.mass = m particle_r.mass = m force_p = particle_p.mass*(g*frame_n.x) force_r = particle_r.mass*(g*frame_n.x) kd_eqs = [q1_d - u1, q2_d - u2] forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x)), (particle_r.point,particle_r.mass*(g*frame_n.x))] kane = _me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs) fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList) zero = fr+frstar from pydy.system import System sys = System(kane, constants = {l:1, m:1, g:9.81}, specifieds={}, initial_conditions={q1:.1, q2:.2, u1:0, u2:0}, times = _np.linspace(0.0, 10, 10/.01)) y=sys.integrate() """ _autolev = import_module( 'sympy.parsing.autolev._parse_autolev_antlr', import_kwargs={'fromlist': ['X']}) if _autolev is not None: return _autolev.parse_autolev(autolev_code, include_numeric) sympy-sympy-1.9/sympy/parsing/autolev/_antlr/000077500000000000000000000000001412543434000215055ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/autolev/_antlr/__init__.py000066400000000000000000000003561412543434000236220ustar00rootroot00000000000000# *** GENERATED BY antlr4, DO NOT EDIT BY HAND *** # # Generated from Autolev.g4 by ANTLR 4.7.1 # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt sympy-sympy-1.9/sympy/parsing/autolev/_antlr/autolevlexer.py000066400000000000000000000407151412543434000246050ustar00rootroot00000000000000# *** GENERATED BY antlr4, DO NOT EDIT BY HAND *** # # Generated from Autolev.g4 by ANTLR 4.7.1 # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt from __future__ import print_function from antlr4 import * from io import StringIO import sys def serializedATN(): with StringIO() as buf: buf.write(u"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2") buf.write(u"\63\u018b\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6") buf.write(u"\4\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4") buf.write(u"\r\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t") buf.write(u"\22\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27") buf.write(u"\4\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4") buf.write(u"\35\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t") buf.write(u"#\4$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4") buf.write(u",\t,\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62") buf.write(u"\4\63\t\63\4\64\t\64\3\2\3\2\3\3\3\3\3\4\3\4\3\5\3\5") buf.write(u"\3\5\3\6\3\6\3\6\3\7\3\7\3\7\3\b\3\b\3\b\3\t\3\t\3\t") buf.write(u"\3\n\3\n\3\n\3\13\3\13\3\f\3\f\3\r\3\r\3\16\3\16\3\17") buf.write(u"\3\17\3\20\3\20\3\21\3\21\3\22\3\22\3\23\3\23\3\24\3") buf.write(u"\24\3\25\3\25\3\26\3\26\3\27\3\27\3\27\3\30\3\30\3\30") buf.write(u"\3\30\3\31\3\31\3\32\3\32\3\33\3\33\3\34\3\34\3\34\3") buf.write(u"\34\3\34\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\36") buf.write(u"\3\36\3\36\3\36\3\36\3\36\5\36\u00ba\n\36\3\37\3\37\3") buf.write(u"\37\3\37\3\37\3\37\3\37\3 \3 \3 \3 \3 \3!\3!\3!\3!\3") buf.write(u"!\3!\3!\3!\3!\3!\3!\3\"\3\"\3\"\3\"\3\"\3\"\3\"\3#\3") buf.write(u"#\3#\3#\3#\3#\3#\3#\3#\3#\3$\3$\3$\3$\3$\3$\5$\u00ea") buf.write(u"\n$\3%\3%\3%\3%\3%\3%\5%\u00f2\n%\3&\3&\3&\3&\3&\3&\3") buf.write(u"&\3&\3&\5&\u00fd\n&\3\'\3\'\3\'\3\'\3\'\3\'\5\'\u0105") buf.write(u"\n\'\3(\3(\3(\3(\3(\3(\3(\3(\3(\5(\u0110\n(\3)\3)\3)") buf.write(u"\3)\3)\3)\3)\3)\3)\3)\5)\u011c\n)\3*\3*\3*\3*\3*\3*\3") buf.write(u"*\3*\3*\3*\3+\3+\3+\3+\3+\3+\3+\3+\3+\5+\u0131\n+\3,") buf.write(u"\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\3,\5,\u0142\n") buf.write(u",\3-\7-\u0145\n-\f-\16-\u0148\13-\3.\3.\3/\6/\u014d\n") buf.write(u"/\r/\16/\u014e\3\60\6\60\u0152\n\60\r\60\16\60\u0153") buf.write(u"\3\60\3\60\7\60\u0158\n\60\f\60\16\60\u015b\13\60\3\60") buf.write(u"\3\60\6\60\u015f\n\60\r\60\16\60\u0160\5\60\u0163\n\60") buf.write(u"\3\61\3\61\3\61\3\61\3\61\3\61\3\61\3\61\3\61\5\61\u016e") buf.write(u"\n\61\3\62\3\62\7\62\u0172\n\62\f\62\16\62\u0175\13\62") buf.write(u"\3\62\5\62\u0178\n\62\3\62\3\62\3\62\3\62\3\63\3\63\7") buf.write(u"\63\u0180\n\63\f\63\16\63\u0183\13\63\3\64\6\64\u0186") buf.write(u"\n\64\r\64\16\64\u0187\3\64\3\64\3\u0173\2\65\3\3\5\4") buf.write(u"\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r\31\16\33") buf.write(u"\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30/\31\61\32") buf.write(u"\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K\'M(O)Q*S+") buf.write(u"U,W-Y\2[\2]._/a\60c\61e\62g\63\3\2\32\4\2OOoo\4\2CCc") buf.write(u"c\4\2UUuu\4\2KKkk\4\2PPpp\4\2GGgg\4\2TTtt\4\2VVvv\4\2") buf.write(u"RRrr\4\2WWww\4\2QQqq\4\2XXxx\4\2[[{{\4\2EEee\4\2FFff") buf.write(u"\4\2YYyy\4\2HHhh\4\2DDdd\4\2NNnn\4\2IIii\3\2\62;\4\2") buf.write(u"C\\c|\6\2\62;C\\aac|\6\2\13\f\17\17\"\"((\2\u019c\2\3") buf.write(u"\3\2\2\2\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2") buf.write(u"\2\2\2\r\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2") buf.write(u"\2\2\25\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2") buf.write(u"\2\2\35\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2") buf.write(u"%\3\2\2\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2") buf.write(u"\2\2/\3\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2") buf.write(u"\2\67\3\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2") buf.write(u"\2\2\2A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3") buf.write(u"\2\2\2\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2") buf.write(u"S\3\2\2\2\2U\3\2\2\2\2W\3\2\2\2\2]\3\2\2\2\2_\3\2\2\2") buf.write(u"\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3\2\2\2\3i\3\2\2") buf.write(u"\2\5k\3\2\2\2\7m\3\2\2\2\to\3\2\2\2\13r\3\2\2\2\ru\3") buf.write(u"\2\2\2\17x\3\2\2\2\21{\3\2\2\2\23~\3\2\2\2\25\u0081\3") buf.write(u"\2\2\2\27\u0083\3\2\2\2\31\u0085\3\2\2\2\33\u0087\3\2") buf.write(u"\2\2\35\u0089\3\2\2\2\37\u008b\3\2\2\2!\u008d\3\2\2\2") buf.write(u"#\u008f\3\2\2\2%\u0091\3\2\2\2\'\u0093\3\2\2\2)\u0095") buf.write(u"\3\2\2\2+\u0097\3\2\2\2-\u0099\3\2\2\2/\u009c\3\2\2\2") buf.write(u"\61\u00a0\3\2\2\2\63\u00a2\3\2\2\2\65\u00a4\3\2\2\2\67") buf.write(u"\u00a6\3\2\2\29\u00ab\3\2\2\2;\u00b3\3\2\2\2=\u00bb\3") buf.write(u"\2\2\2?\u00c2\3\2\2\2A\u00c7\3\2\2\2C\u00d2\3\2\2\2E") buf.write(u"\u00d9\3\2\2\2G\u00e3\3\2\2\2I\u00eb\3\2\2\2K\u00f3\3") buf.write(u"\2\2\2M\u00fe\3\2\2\2O\u0106\3\2\2\2Q\u0111\3\2\2\2S") buf.write(u"\u011d\3\2\2\2U\u0127\3\2\2\2W\u0132\3\2\2\2Y\u0146\3") buf.write(u"\2\2\2[\u0149\3\2\2\2]\u014c\3\2\2\2_\u0162\3\2\2\2a") buf.write(u"\u016d\3\2\2\2c\u016f\3\2\2\2e\u017d\3\2\2\2g\u0185\3") buf.write(u"\2\2\2ij\7]\2\2j\4\3\2\2\2kl\7_\2\2l\6\3\2\2\2mn\7?\2") buf.write(u"\2n\b\3\2\2\2op\7-\2\2pq\7?\2\2q\n\3\2\2\2rs\7/\2\2s") buf.write(u"t\7?\2\2t\f\3\2\2\2uv\7<\2\2vw\7?\2\2w\16\3\2\2\2xy\7") buf.write(u",\2\2yz\7?\2\2z\20\3\2\2\2{|\7\61\2\2|}\7?\2\2}\22\3") buf.write(u"\2\2\2~\177\7`\2\2\177\u0080\7?\2\2\u0080\24\3\2\2\2") buf.write(u"\u0081\u0082\7.\2\2\u0082\26\3\2\2\2\u0083\u0084\7)\2") buf.write(u"\2\u0084\30\3\2\2\2\u0085\u0086\7*\2\2\u0086\32\3\2\2") buf.write(u"\2\u0087\u0088\7+\2\2\u0088\34\3\2\2\2\u0089\u008a\7") buf.write(u"}\2\2\u008a\36\3\2\2\2\u008b\u008c\7\177\2\2\u008c \3") buf.write(u"\2\2\2\u008d\u008e\7<\2\2\u008e\"\3\2\2\2\u008f\u0090") buf.write(u"\7-\2\2\u0090$\3\2\2\2\u0091\u0092\7/\2\2\u0092&\3\2") buf.write(u"\2\2\u0093\u0094\7=\2\2\u0094(\3\2\2\2\u0095\u0096\7") buf.write(u"\60\2\2\u0096*\3\2\2\2\u0097\u0098\7@\2\2\u0098,\3\2") buf.write(u"\2\2\u0099\u009a\7\62\2\2\u009a\u009b\7@\2\2\u009b.\3") buf.write(u"\2\2\2\u009c\u009d\7\63\2\2\u009d\u009e\7@\2\2\u009e") buf.write(u"\u009f\7@\2\2\u009f\60\3\2\2\2\u00a0\u00a1\7`\2\2\u00a1") buf.write(u"\62\3\2\2\2\u00a2\u00a3\7,\2\2\u00a3\64\3\2\2\2\u00a4") buf.write(u"\u00a5\7\61\2\2\u00a5\66\3\2\2\2\u00a6\u00a7\t\2\2\2") buf.write(u"\u00a7\u00a8\t\3\2\2\u00a8\u00a9\t\4\2\2\u00a9\u00aa") buf.write(u"\t\4\2\2\u00aa8\3\2\2\2\u00ab\u00ac\t\5\2\2\u00ac\u00ad") buf.write(u"\t\6\2\2\u00ad\u00ae\t\7\2\2\u00ae\u00af\t\b\2\2\u00af") buf.write(u"\u00b0\t\t\2\2\u00b0\u00b1\t\5\2\2\u00b1\u00b2\t\3\2") buf.write(u"\2\u00b2:\3\2\2\2\u00b3\u00b4\t\5\2\2\u00b4\u00b5\t\6") buf.write(u"\2\2\u00b5\u00b6\t\n\2\2\u00b6\u00b7\t\13\2\2\u00b7\u00b9") buf.write(u"\t\t\2\2\u00b8\u00ba\t\4\2\2\u00b9\u00b8\3\2\2\2\u00b9") buf.write(u"\u00ba\3\2\2\2\u00ba<\3\2\2\2\u00bb\u00bc\t\f\2\2\u00bc") buf.write(u"\u00bd\t\13\2\2\u00bd\u00be\t\t\2\2\u00be\u00bf\t\n\2") buf.write(u"\2\u00bf\u00c0\t\13\2\2\u00c0\u00c1\t\t\2\2\u00c1>\3") buf.write(u"\2\2\2\u00c2\u00c3\t\4\2\2\u00c3\u00c4\t\3\2\2\u00c4") buf.write(u"\u00c5\t\r\2\2\u00c5\u00c6\t\7\2\2\u00c6@\3\2\2\2\u00c7") buf.write(u"\u00c8\t\13\2\2\u00c8\u00c9\t\6\2\2\u00c9\u00ca\t\5\2") buf.write(u"\2\u00ca\u00cb\t\t\2\2\u00cb\u00cc\t\4\2\2\u00cc\u00cd") buf.write(u"\t\16\2\2\u00cd\u00ce\t\4\2\2\u00ce\u00cf\t\t\2\2\u00cf") buf.write(u"\u00d0\t\7\2\2\u00d0\u00d1\t\2\2\2\u00d1B\3\2\2\2\u00d2") buf.write(u"\u00d3\t\7\2\2\u00d3\u00d4\t\6\2\2\u00d4\u00d5\t\17\2") buf.write(u"\2\u00d5\u00d6\t\f\2\2\u00d6\u00d7\t\20\2\2\u00d7\u00d8") buf.write(u"\t\7\2\2\u00d8D\3\2\2\2\u00d9\u00da\t\6\2\2\u00da\u00db") buf.write(u"\t\7\2\2\u00db\u00dc\t\21\2\2\u00dc\u00dd\t\t\2\2\u00dd") buf.write(u"\u00de\t\f\2\2\u00de\u00df\t\6\2\2\u00df\u00e0\t\5\2") buf.write(u"\2\u00e0\u00e1\t\3\2\2\u00e1\u00e2\t\6\2\2\u00e2F\3\2") buf.write(u"\2\2\u00e3\u00e4\t\22\2\2\u00e4\u00e5\t\b\2\2\u00e5\u00e6") buf.write(u"\t\3\2\2\u00e6\u00e7\t\2\2\2\u00e7\u00e9\t\7\2\2\u00e8") buf.write(u"\u00ea\t\4\2\2\u00e9\u00e8\3\2\2\2\u00e9\u00ea\3\2\2") buf.write(u"\2\u00eaH\3\2\2\2\u00eb\u00ec\t\23\2\2\u00ec\u00ed\t") buf.write(u"\f\2\2\u00ed\u00ee\t\20\2\2\u00ee\u00ef\t\5\2\2\u00ef") buf.write(u"\u00f1\t\7\2\2\u00f0\u00f2\t\4\2\2\u00f1\u00f0\3\2\2") buf.write(u"\2\u00f1\u00f2\3\2\2\2\u00f2J\3\2\2\2\u00f3\u00f4\t\n") buf.write(u"\2\2\u00f4\u00f5\t\3\2\2\u00f5\u00f6\t\b\2\2\u00f6\u00f7") buf.write(u"\t\t\2\2\u00f7\u00f8\t\5\2\2\u00f8\u00f9\t\17\2\2\u00f9") buf.write(u"\u00fa\t\24\2\2\u00fa\u00fc\t\7\2\2\u00fb\u00fd\t\4\2") buf.write(u"\2\u00fc\u00fb\3\2\2\2\u00fc\u00fd\3\2\2\2\u00fdL\3\2") buf.write(u"\2\2\u00fe\u00ff\t\n\2\2\u00ff\u0100\t\f\2\2\u0100\u0101") buf.write(u"\t\5\2\2\u0101\u0102\t\6\2\2\u0102\u0104\t\t\2\2\u0103") buf.write(u"\u0105\t\4\2\2\u0104\u0103\3\2\2\2\u0104\u0105\3\2\2") buf.write(u"\2\u0105N\3\2\2\2\u0106\u0107\t\17\2\2\u0107\u0108\t") buf.write(u"\f\2\2\u0108\u0109\t\6\2\2\u0109\u010a\t\4\2\2\u010a") buf.write(u"\u010b\t\t\2\2\u010b\u010c\t\3\2\2\u010c\u010d\t\6\2") buf.write(u"\2\u010d\u010f\t\t\2\2\u010e\u0110\t\4\2\2\u010f\u010e") buf.write(u"\3\2\2\2\u010f\u0110\3\2\2\2\u0110P\3\2\2\2\u0111\u0112") buf.write(u"\t\4\2\2\u0112\u0113\t\n\2\2\u0113\u0114\t\7\2\2\u0114") buf.write(u"\u0115\t\17\2\2\u0115\u0116\t\5\2\2\u0116\u0117\t\22") buf.write(u"\2\2\u0117\u0118\t\5\2\2\u0118\u0119\t\7\2\2\u0119\u011b") buf.write(u"\t\20\2\2\u011a\u011c\t\4\2\2\u011b\u011a\3\2\2\2\u011b") buf.write(u"\u011c\3\2\2\2\u011cR\3\2\2\2\u011d\u011e\t\5\2\2\u011e") buf.write(u"\u011f\t\2\2\2\u011f\u0120\t\3\2\2\u0120\u0121\t\25\2") buf.write(u"\2\u0121\u0122\t\5\2\2\u0122\u0123\t\6\2\2\u0123\u0124") buf.write(u"\t\3\2\2\u0124\u0125\t\b\2\2\u0125\u0126\t\16\2\2\u0126") buf.write(u"T\3\2\2\2\u0127\u0128\t\r\2\2\u0128\u0129\t\3\2\2\u0129") buf.write(u"\u012a\t\b\2\2\u012a\u012b\t\5\2\2\u012b\u012c\t\3\2") buf.write(u"\2\u012c\u012d\t\23\2\2\u012d\u012e\t\24\2\2\u012e\u0130") buf.write(u"\t\7\2\2\u012f\u0131\t\4\2\2\u0130\u012f\3\2\2\2\u0130") buf.write(u"\u0131\3\2\2\2\u0131V\3\2\2\2\u0132\u0133\t\2\2\2\u0133") buf.write(u"\u0134\t\f\2\2\u0134\u0135\t\t\2\2\u0135\u0136\t\5\2") buf.write(u"\2\u0136\u0137\t\f\2\2\u0137\u0138\t\6\2\2\u0138\u0139") buf.write(u"\t\r\2\2\u0139\u013a\t\3\2\2\u013a\u013b\t\b\2\2\u013b") buf.write(u"\u013c\t\5\2\2\u013c\u013d\t\3\2\2\u013d\u013e\t\23\2") buf.write(u"\2\u013e\u013f\t\24\2\2\u013f\u0141\t\7\2\2\u0140\u0142") buf.write(u"\t\4\2\2\u0141\u0140\3\2\2\2\u0141\u0142\3\2\2\2\u0142") buf.write(u"X\3\2\2\2\u0143\u0145\7)\2\2\u0144\u0143\3\2\2\2\u0145") buf.write(u"\u0148\3\2\2\2\u0146\u0144\3\2\2\2\u0146\u0147\3\2\2") buf.write(u"\2\u0147Z\3\2\2\2\u0148\u0146\3\2\2\2\u0149\u014a\t\26") buf.write(u"\2\2\u014a\\\3\2\2\2\u014b\u014d\t\26\2\2\u014c\u014b") buf.write(u"\3\2\2\2\u014d\u014e\3\2\2\2\u014e\u014c\3\2\2\2\u014e") buf.write(u"\u014f\3\2\2\2\u014f^\3\2\2\2\u0150\u0152\5[.\2\u0151") buf.write(u"\u0150\3\2\2\2\u0152\u0153\3\2\2\2\u0153\u0151\3\2\2") buf.write(u"\2\u0153\u0154\3\2\2\2\u0154\u0155\3\2\2\2\u0155\u0159") buf.write(u"\7\60\2\2\u0156\u0158\5[.\2\u0157\u0156\3\2\2\2\u0158") buf.write(u"\u015b\3\2\2\2\u0159\u0157\3\2\2\2\u0159\u015a\3\2\2") buf.write(u"\2\u015a\u0163\3\2\2\2\u015b\u0159\3\2\2\2\u015c\u015e") buf.write(u"\7\60\2\2\u015d\u015f\5[.\2\u015e\u015d\3\2\2\2\u015f") buf.write(u"\u0160\3\2\2\2\u0160\u015e\3\2\2\2\u0160\u0161\3\2\2") buf.write(u"\2\u0161\u0163\3\2\2\2\u0162\u0151\3\2\2\2\u0162\u015c") buf.write(u"\3\2\2\2\u0163`\3\2\2\2\u0164\u0165\5_\60\2\u0165\u0166") buf.write(u"\7G\2\2\u0166\u0167\5]/\2\u0167\u016e\3\2\2\2\u0168\u0169") buf.write(u"\5_\60\2\u0169\u016a\7G\2\2\u016a\u016b\7/\2\2\u016b") buf.write(u"\u016c\5]/\2\u016c\u016e\3\2\2\2\u016d\u0164\3\2\2\2") buf.write(u"\u016d\u0168\3\2\2\2\u016eb\3\2\2\2\u016f\u0173\7\'\2") buf.write(u"\2\u0170\u0172\13\2\2\2\u0171\u0170\3\2\2\2\u0172\u0175") buf.write(u"\3\2\2\2\u0173\u0174\3\2\2\2\u0173\u0171\3\2\2\2\u0174") buf.write(u"\u0177\3\2\2\2\u0175\u0173\3\2\2\2\u0176\u0178\7\17\2") buf.write(u"\2\u0177\u0176\3\2\2\2\u0177\u0178\3\2\2\2\u0178\u0179") buf.write(u"\3\2\2\2\u0179\u017a\7\f\2\2\u017a\u017b\3\2\2\2\u017b") buf.write(u"\u017c\b\62\2\2\u017cd\3\2\2\2\u017d\u0181\t\27\2\2\u017e") buf.write(u"\u0180\t\30\2\2\u017f\u017e\3\2\2\2\u0180\u0183\3\2\2") buf.write(u"\2\u0181\u017f\3\2\2\2\u0181\u0182\3\2\2\2\u0182f\3\2") buf.write(u"\2\2\u0183\u0181\3\2\2\2\u0184\u0186\t\31\2\2\u0185\u0184") buf.write(u"\3\2\2\2\u0186\u0187\3\2\2\2\u0187\u0185\3\2\2\2\u0187") buf.write(u"\u0188\3\2\2\2\u0188\u0189\3\2\2\2\u0189\u018a\b\64\2") buf.write(u"\2\u018ah\3\2\2\2\27\2\u00b9\u00e9\u00f1\u00fc\u0104") buf.write(u"\u010f\u011b\u0130\u0141\u0146\u014e\u0153\u0159\u0160") buf.write(u"\u0162\u016d\u0173\u0177\u0181\u0187\3\b\2\2") return buf.getvalue() class AutolevLexer(Lexer): atn = ATNDeserializer().deserialize(serializedATN()) decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] T__0 = 1 T__1 = 2 T__2 = 3 T__3 = 4 T__4 = 5 T__5 = 6 T__6 = 7 T__7 = 8 T__8 = 9 T__9 = 10 T__10 = 11 T__11 = 12 T__12 = 13 T__13 = 14 T__14 = 15 T__15 = 16 T__16 = 17 T__17 = 18 T__18 = 19 T__19 = 20 T__20 = 21 T__21 = 22 T__22 = 23 T__23 = 24 T__24 = 25 T__25 = 26 Mass = 27 Inertia = 28 Input = 29 Output = 30 Save = 31 UnitSystem = 32 Encode = 33 Newtonian = 34 Frames = 35 Bodies = 36 Particles = 37 Points = 38 Constants = 39 Specifieds = 40 Imaginary = 41 Variables = 42 MotionVariables = 43 INT = 44 FLOAT = 45 EXP = 46 LINE_COMMENT = 47 ID = 48 WS = 49 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] modeNames = [ u"DEFAULT_MODE" ] literalNames = [ u"", u"'['", u"']'", u"'='", u"'+='", u"'-='", u"':='", u"'*='", u"'/='", u"'^='", u"','", u"'''", u"'('", u"')'", u"'{'", u"'}'", u"':'", u"'+'", u"'-'", u"';'", u"'.'", u"'>'", u"'0>'", u"'1>>'", u"'^'", u"'*'", u"'/'" ] symbolicNames = [ u"", u"Mass", u"Inertia", u"Input", u"Output", u"Save", u"UnitSystem", u"Encode", u"Newtonian", u"Frames", u"Bodies", u"Particles", u"Points", u"Constants", u"Specifieds", u"Imaginary", u"Variables", u"MotionVariables", u"INT", u"FLOAT", u"EXP", u"LINE_COMMENT", u"ID", u"WS" ] ruleNames = [ u"T__0", u"T__1", u"T__2", u"T__3", u"T__4", u"T__5", u"T__6", u"T__7", u"T__8", u"T__9", u"T__10", u"T__11", u"T__12", u"T__13", u"T__14", u"T__15", u"T__16", u"T__17", u"T__18", u"T__19", u"T__20", u"T__21", u"T__22", u"T__23", u"T__24", u"T__25", u"Mass", u"Inertia", u"Input", u"Output", u"Save", u"UnitSystem", u"Encode", u"Newtonian", u"Frames", u"Bodies", u"Particles", u"Points", u"Constants", u"Specifieds", u"Imaginary", u"Variables", u"MotionVariables", u"DIFF", u"DIGIT", u"INT", u"FLOAT", u"EXP", u"LINE_COMMENT", u"ID", u"WS" ] grammarFileName = u"Autolev.g4" def __init__(self, input=None, output=sys.stdout): super(AutolevLexer, self).__init__(input, output=output) self.checkVersion("4.7.1") self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) self._actions = None self._predicates = None sympy-sympy-1.9/sympy/parsing/autolev/_antlr/autolevlistener.py000066400000000000000000000235011412543434000253050ustar00rootroot00000000000000# *** GENERATED BY antlr4, DO NOT EDIT BY HAND *** # # Generated from Autolev.g4 by ANTLR 4.7.1 # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt from antlr4 import * # This class defines a complete listener for a parse tree produced by AutolevParser. class AutolevListener(ParseTreeListener): # Enter a parse tree produced by AutolevParser#prog. def enterProg(self, ctx): pass # Exit a parse tree produced by AutolevParser#prog. def exitProg(self, ctx): pass # Enter a parse tree produced by AutolevParser#stat. def enterStat(self, ctx): pass # Exit a parse tree produced by AutolevParser#stat. def exitStat(self, ctx): pass # Enter a parse tree produced by AutolevParser#vecAssign. def enterVecAssign(self, ctx): pass # Exit a parse tree produced by AutolevParser#vecAssign. def exitVecAssign(self, ctx): pass # Enter a parse tree produced by AutolevParser#indexAssign. def enterIndexAssign(self, ctx): pass # Exit a parse tree produced by AutolevParser#indexAssign. def exitIndexAssign(self, ctx): pass # Enter a parse tree produced by AutolevParser#regularAssign. def enterRegularAssign(self, ctx): pass # Exit a parse tree produced by AutolevParser#regularAssign. def exitRegularAssign(self, ctx): pass # Enter a parse tree produced by AutolevParser#equals. def enterEquals(self, ctx): pass # Exit a parse tree produced by AutolevParser#equals. def exitEquals(self, ctx): pass # Enter a parse tree produced by AutolevParser#index. def enterIndex(self, ctx): pass # Exit a parse tree produced by AutolevParser#index. def exitIndex(self, ctx): pass # Enter a parse tree produced by AutolevParser#diff. def enterDiff(self, ctx): pass # Exit a parse tree produced by AutolevParser#diff. def exitDiff(self, ctx): pass # Enter a parse tree produced by AutolevParser#functionCall. def enterFunctionCall(self, ctx): pass # Exit a parse tree produced by AutolevParser#functionCall. def exitFunctionCall(self, ctx): pass # Enter a parse tree produced by AutolevParser#varDecl. def enterVarDecl(self, ctx): pass # Exit a parse tree produced by AutolevParser#varDecl. def exitVarDecl(self, ctx): pass # Enter a parse tree produced by AutolevParser#varType. def enterVarType(self, ctx): pass # Exit a parse tree produced by AutolevParser#varType. def exitVarType(self, ctx): pass # Enter a parse tree produced by AutolevParser#varDecl2. def enterVarDecl2(self, ctx): pass # Exit a parse tree produced by AutolevParser#varDecl2. def exitVarDecl2(self, ctx): pass # Enter a parse tree produced by AutolevParser#ranges. def enterRanges(self, ctx): pass # Exit a parse tree produced by AutolevParser#ranges. def exitRanges(self, ctx): pass # Enter a parse tree produced by AutolevParser#massDecl. def enterMassDecl(self, ctx): pass # Exit a parse tree produced by AutolevParser#massDecl. def exitMassDecl(self, ctx): pass # Enter a parse tree produced by AutolevParser#massDecl2. def enterMassDecl2(self, ctx): pass # Exit a parse tree produced by AutolevParser#massDecl2. def exitMassDecl2(self, ctx): pass # Enter a parse tree produced by AutolevParser#inertiaDecl. def enterInertiaDecl(self, ctx): pass # Exit a parse tree produced by AutolevParser#inertiaDecl. def exitInertiaDecl(self, ctx): pass # Enter a parse tree produced by AutolevParser#matrix. def enterMatrix(self, ctx): pass # Exit a parse tree produced by AutolevParser#matrix. def exitMatrix(self, ctx): pass # Enter a parse tree produced by AutolevParser#matrixInOutput. def enterMatrixInOutput(self, ctx): pass # Exit a parse tree produced by AutolevParser#matrixInOutput. def exitMatrixInOutput(self, ctx): pass # Enter a parse tree produced by AutolevParser#codeCommands. def enterCodeCommands(self, ctx): pass # Exit a parse tree produced by AutolevParser#codeCommands. def exitCodeCommands(self, ctx): pass # Enter a parse tree produced by AutolevParser#settings. def enterSettings(self, ctx): pass # Exit a parse tree produced by AutolevParser#settings. def exitSettings(self, ctx): pass # Enter a parse tree produced by AutolevParser#units. def enterUnits(self, ctx): pass # Exit a parse tree produced by AutolevParser#units. def exitUnits(self, ctx): pass # Enter a parse tree produced by AutolevParser#inputs. def enterInputs(self, ctx): pass # Exit a parse tree produced by AutolevParser#inputs. def exitInputs(self, ctx): pass # Enter a parse tree produced by AutolevParser#id_diff. def enterId_diff(self, ctx): pass # Exit a parse tree produced by AutolevParser#id_diff. def exitId_diff(self, ctx): pass # Enter a parse tree produced by AutolevParser#inputs2. def enterInputs2(self, ctx): pass # Exit a parse tree produced by AutolevParser#inputs2. def exitInputs2(self, ctx): pass # Enter a parse tree produced by AutolevParser#outputs. def enterOutputs(self, ctx): pass # Exit a parse tree produced by AutolevParser#outputs. def exitOutputs(self, ctx): pass # Enter a parse tree produced by AutolevParser#outputs2. def enterOutputs2(self, ctx): pass # Exit a parse tree produced by AutolevParser#outputs2. def exitOutputs2(self, ctx): pass # Enter a parse tree produced by AutolevParser#codegen. def enterCodegen(self, ctx): pass # Exit a parse tree produced by AutolevParser#codegen. def exitCodegen(self, ctx): pass # Enter a parse tree produced by AutolevParser#commands. def enterCommands(self, ctx): pass # Exit a parse tree produced by AutolevParser#commands. def exitCommands(self, ctx): pass # Enter a parse tree produced by AutolevParser#vec. def enterVec(self, ctx): pass # Exit a parse tree produced by AutolevParser#vec. def exitVec(self, ctx): pass # Enter a parse tree produced by AutolevParser#parens. def enterParens(self, ctx): pass # Exit a parse tree produced by AutolevParser#parens. def exitParens(self, ctx): pass # Enter a parse tree produced by AutolevParser#VectorOrDyadic. def enterVectorOrDyadic(self, ctx): pass # Exit a parse tree produced by AutolevParser#VectorOrDyadic. def exitVectorOrDyadic(self, ctx): pass # Enter a parse tree produced by AutolevParser#Exponent. def enterExponent(self, ctx): pass # Exit a parse tree produced by AutolevParser#Exponent. def exitExponent(self, ctx): pass # Enter a parse tree produced by AutolevParser#MulDiv. def enterMulDiv(self, ctx): pass # Exit a parse tree produced by AutolevParser#MulDiv. def exitMulDiv(self, ctx): pass # Enter a parse tree produced by AutolevParser#AddSub. def enterAddSub(self, ctx): pass # Exit a parse tree produced by AutolevParser#AddSub. def exitAddSub(self, ctx): pass # Enter a parse tree produced by AutolevParser#float. def enterFloat(self, ctx): pass # Exit a parse tree produced by AutolevParser#float. def exitFloat(self, ctx): pass # Enter a parse tree produced by AutolevParser#int. def enterInt(self, ctx): pass # Exit a parse tree produced by AutolevParser#int. def exitInt(self, ctx): pass # Enter a parse tree produced by AutolevParser#idEqualsExpr. def enterIdEqualsExpr(self, ctx): pass # Exit a parse tree produced by AutolevParser#idEqualsExpr. def exitIdEqualsExpr(self, ctx): pass # Enter a parse tree produced by AutolevParser#negativeOne. def enterNegativeOne(self, ctx): pass # Exit a parse tree produced by AutolevParser#negativeOne. def exitNegativeOne(self, ctx): pass # Enter a parse tree produced by AutolevParser#function. def enterFunction(self, ctx): pass # Exit a parse tree produced by AutolevParser#function. def exitFunction(self, ctx): pass # Enter a parse tree produced by AutolevParser#rangess. def enterRangess(self, ctx): pass # Exit a parse tree produced by AutolevParser#rangess. def exitRangess(self, ctx): pass # Enter a parse tree produced by AutolevParser#colon. def enterColon(self, ctx): pass # Exit a parse tree produced by AutolevParser#colon. def exitColon(self, ctx): pass # Enter a parse tree produced by AutolevParser#id. def enterId(self, ctx): pass # Exit a parse tree produced by AutolevParser#id. def exitId(self, ctx): pass # Enter a parse tree produced by AutolevParser#exp. def enterExp(self, ctx): pass # Exit a parse tree produced by AutolevParser#exp. def exitExp(self, ctx): pass # Enter a parse tree produced by AutolevParser#matrices. def enterMatrices(self, ctx): pass # Exit a parse tree produced by AutolevParser#matrices. def exitMatrices(self, ctx): pass # Enter a parse tree produced by AutolevParser#Indexing. def enterIndexing(self, ctx): pass # Exit a parse tree produced by AutolevParser#Indexing. def exitIndexing(self, ctx): pass sympy-sympy-1.9/sympy/parsing/autolev/_antlr/autolevparser.py000066400000000000000000003316501412543434000247630ustar00rootroot00000000000000# *** GENERATED BY antlr4, DO NOT EDIT BY HAND *** # # Generated from Autolev.g4 by ANTLR 4.7.1 # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt from __future__ import print_function from antlr4 import * from io import StringIO import sys def serializedATN(): with StringIO() as buf: buf.write(u"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3") buf.write(u"\63\u01b1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7") buf.write(u"\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t") buf.write(u"\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22") buf.write(u"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4") buf.write(u"\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35") buf.write(u"\t\35\3\2\6\2<\n\2\r\2\16\2=\3\3\3\3\3\3\3\3\3\3\3\3") buf.write(u"\3\3\5\3G\n\3\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4") buf.write(u"\3\4\3\4\3\4\5\4V\n\4\3\4\3\4\3\4\5\4[\n\4\3\5\3\5\3") buf.write(u"\6\3\6\3\6\7\6b\n\6\f\6\16\6e\13\6\3\7\6\7h\n\7\r\7\16") buf.write(u"\7i\3\b\3\b\3\b\3\b\3\b\7\bq\n\b\f\b\16\bt\13\b\5\bv") buf.write(u"\n\b\3\b\3\b\3\b\3\b\3\b\3\b\7\b~\n\b\f\b\16\b\u0081") buf.write(u"\13\b\5\b\u0083\n\b\3\b\5\b\u0086\n\b\3\t\3\t\3\t\3\t") buf.write(u"\7\t\u008c\n\t\f\t\16\t\u008f\13\t\3\n\3\n\3\n\3\n\3") buf.write(u"\n\3\n\3\n\3\n\3\n\3\n\7\n\u009b\n\n\f\n\16\n\u009e\13") buf.write(u"\n\3\n\3\n\7\n\u00a2\n\n\f\n\16\n\u00a5\13\n\5\n\u00a7") buf.write(u"\n\n\3\13\3\13\3\13\3\13\3\13\3\13\5\13\u00af\n\13\3") buf.write(u"\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\7\13\u00b9\n\13") buf.write(u"\f\13\16\13\u00bc\13\13\3\13\5\13\u00bf\n\13\3\13\3\13") buf.write(u"\3\13\5\13\u00c4\n\13\3\13\5\13\u00c7\n\13\3\13\7\13") buf.write(u"\u00ca\n\13\f\13\16\13\u00cd\13\13\3\13\3\13\5\13\u00d1") buf.write(u"\n\13\3\f\3\f\3\f\3\f\3\f\3\f\3\f\3\f\7\f\u00db\n\f\f") buf.write(u"\f\16\f\u00de\13\f\3\f\3\f\3\r\3\r\3\r\3\r\7\r\u00e6") buf.write(u"\n\r\f\r\16\r\u00e9\13\r\3\16\3\16\3\16\3\16\3\17\3\17") buf.write(u"\3\17\3\17\3\17\5\17\u00f4\n\17\3\17\3\17\6\17\u00f8") buf.write(u"\n\17\r\17\16\17\u00f9\3\20\3\20\3\20\3\20\7\20\u0100") buf.write(u"\n\20\f\20\16\20\u0103\13\20\3\20\3\20\3\21\3\21\3\21") buf.write(u"\3\21\5\21\u010b\n\21\3\21\3\21\5\21\u010f\n\21\3\22") buf.write(u"\3\22\3\22\3\22\3\22\5\22\u0116\n\22\3\23\3\23\5\23\u011a") buf.write(u"\n\23\3\24\3\24\3\24\3\24\7\24\u0120\n\24\f\24\16\24") buf.write(u"\u0123\13\24\3\25\3\25\3\25\3\25\7\25\u0129\n\25\f\25") buf.write(u"\16\25\u012c\13\25\3\26\3\26\5\26\u0130\n\26\3\27\3\27") buf.write(u"\3\27\3\27\5\27\u0136\n\27\3\30\3\30\3\30\3\30\7\30\u013c") buf.write(u"\n\30\f\30\16\30\u013f\13\30\3\31\3\31\5\31\u0143\n\31") buf.write(u"\3\32\3\32\3\32\3\32\3\32\3\32\7\32\u014b\n\32\f\32\16") buf.write(u"\32\u014e\13\32\3\32\3\32\5\32\u0152\n\32\3\32\3\32\3") buf.write(u"\32\3\32\3\33\3\33\3\33\3\33\3\33\3\33\3\33\3\33\7\33") buf.write(u"\u0160\n\33\f\33\16\33\u0163\13\33\5\33\u0165\n\33\3") buf.write(u"\34\3\34\6\34\u0169\n\34\r\34\16\34\u016a\3\34\3\34\5") buf.write(u"\34\u016f\n\34\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35") buf.write(u"\7\35\u0179\n\35\f\35\16\35\u017c\13\35\3\35\3\35\3\35") buf.write(u"\3\35\3\35\3\35\7\35\u0184\n\35\f\35\16\35\u0187\13\35") buf.write(u"\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\5\35\u0192") buf.write(u"\n\35\3\35\3\35\7\35\u0196\n\35\f\35\16\35\u0199\13\35") buf.write(u"\5\35\u019b\n\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3") buf.write(u"\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\7\35\u01ac\n\35") buf.write(u"\f\35\16\35\u01af\13\35\3\35\2\38\36\2\4\6\b\n\f\16\20") buf.write(u"\22\24\26\30\32\34\36 \"$&(*,.\60\62\64\668\2\t\3\2\5") buf.write(u"\13\3\2\35\36\3\2\23\24\4\2\f\f\25\25\3\2./\4\2.\60\62") buf.write(u"\62\3\2\33\34\2\u01e5\2;\3\2\2\2\4F\3\2\2\2\6Z\3\2\2") buf.write(u"\2\b\\\3\2\2\2\n^\3\2\2\2\fg\3\2\2\2\16\u0085\3\2\2\2") buf.write(u"\20\u0087\3\2\2\2\22\u00a6\3\2\2\2\24\u00a8\3\2\2\2\26") buf.write(u"\u00d2\3\2\2\2\30\u00e1\3\2\2\2\32\u00ea\3\2\2\2\34\u00ee") buf.write(u"\3\2\2\2\36\u00fb\3\2\2\2 \u010e\3\2\2\2\"\u0115\3\2") buf.write(u"\2\2$\u0117\3\2\2\2&\u011b\3\2\2\2(\u0124\3\2\2\2*\u012d") buf.write(u"\3\2\2\2,\u0131\3\2\2\2.\u0137\3\2\2\2\60\u0140\3\2\2") buf.write(u"\2\62\u0144\3\2\2\2\64\u0164\3\2\2\2\66\u016e\3\2\2\2") buf.write(u"8\u019a\3\2\2\2:<\5\4\3\2;:\3\2\2\2<=\3\2\2\2=;\3\2\2") buf.write(u"\2=>\3\2\2\2>\3\3\2\2\2?G\5\20\t\2@G\5\16\b\2AG\5\"\22") buf.write(u"\2BG\5\30\r\2CG\5\34\17\2DG\5\6\4\2EG\5$\23\2F?\3\2\2") buf.write(u"\2F@\3\2\2\2FA\3\2\2\2FB\3\2\2\2FC\3\2\2\2FD\3\2\2\2") buf.write(u"FE\3\2\2\2G\5\3\2\2\2HI\5\66\34\2IJ\5\b\5\2JK\58\35\2") buf.write(u"K[\3\2\2\2LM\7\62\2\2MN\7\3\2\2NO\5\n\6\2OP\7\4\2\2P") buf.write(u"Q\5\b\5\2QR\58\35\2R[\3\2\2\2SU\7\62\2\2TV\5\f\7\2UT") buf.write(u"\3\2\2\2UV\3\2\2\2VW\3\2\2\2WX\5\b\5\2XY\58\35\2Y[\3") buf.write(u"\2\2\2ZH\3\2\2\2ZL\3\2\2\2ZS\3\2\2\2[\7\3\2\2\2\\]\t") buf.write(u"\2\2\2]\t\3\2\2\2^c\58\35\2_`\7\f\2\2`b\58\35\2a_\3\2") buf.write(u"\2\2be\3\2\2\2ca\3\2\2\2cd\3\2\2\2d\13\3\2\2\2ec\3\2") buf.write(u"\2\2fh\7\r\2\2gf\3\2\2\2hi\3\2\2\2ig\3\2\2\2ij\3\2\2") buf.write(u"\2j\r\3\2\2\2kl\7\62\2\2lu\7\16\2\2mr\58\35\2no\7\f\2") buf.write(u"\2oq\58\35\2pn\3\2\2\2qt\3\2\2\2rp\3\2\2\2rs\3\2\2\2") buf.write(u"sv\3\2\2\2tr\3\2\2\2um\3\2\2\2uv\3\2\2\2vw\3\2\2\2w\u0086") buf.write(u"\7\17\2\2xy\t\3\2\2y\u0082\7\16\2\2z\177\7\62\2\2{|\7") buf.write(u"\f\2\2|~\7\62\2\2}{\3\2\2\2~\u0081\3\2\2\2\177}\3\2\2") buf.write(u"\2\177\u0080\3\2\2\2\u0080\u0083\3\2\2\2\u0081\177\3") buf.write(u"\2\2\2\u0082z\3\2\2\2\u0082\u0083\3\2\2\2\u0083\u0084") buf.write(u"\3\2\2\2\u0084\u0086\7\17\2\2\u0085k\3\2\2\2\u0085x\3") buf.write(u"\2\2\2\u0086\17\3\2\2\2\u0087\u0088\5\22\n\2\u0088\u008d") buf.write(u"\5\24\13\2\u0089\u008a\7\f\2\2\u008a\u008c\5\24\13\2") buf.write(u"\u008b\u0089\3\2\2\2\u008c\u008f\3\2\2\2\u008d\u008b") buf.write(u"\3\2\2\2\u008d\u008e\3\2\2\2\u008e\21\3\2\2\2\u008f\u008d") buf.write(u"\3\2\2\2\u0090\u00a7\7$\2\2\u0091\u00a7\7%\2\2\u0092") buf.write(u"\u00a7\7&\2\2\u0093\u00a7\7\'\2\2\u0094\u00a7\7(\2\2") buf.write(u"\u0095\u00a7\7)\2\2\u0096\u00a7\7*\2\2\u0097\u00a7\7") buf.write(u"+\2\2\u0098\u009c\7,\2\2\u0099\u009b\7\r\2\2\u009a\u0099") buf.write(u"\3\2\2\2\u009b\u009e\3\2\2\2\u009c\u009a\3\2\2\2\u009c") buf.write(u"\u009d\3\2\2\2\u009d\u00a7\3\2\2\2\u009e\u009c\3\2\2") buf.write(u"\2\u009f\u00a3\7-\2\2\u00a0\u00a2\7\r\2\2\u00a1\u00a0") buf.write(u"\3\2\2\2\u00a2\u00a5\3\2\2\2\u00a3\u00a1\3\2\2\2\u00a3") buf.write(u"\u00a4\3\2\2\2\u00a4\u00a7\3\2\2\2\u00a5\u00a3\3\2\2") buf.write(u"\2\u00a6\u0090\3\2\2\2\u00a6\u0091\3\2\2\2\u00a6\u0092") buf.write(u"\3\2\2\2\u00a6\u0093\3\2\2\2\u00a6\u0094\3\2\2\2\u00a6") buf.write(u"\u0095\3\2\2\2\u00a6\u0096\3\2\2\2\u00a6\u0097\3\2\2") buf.write(u"\2\u00a6\u0098\3\2\2\2\u00a6\u009f\3\2\2\2\u00a7\23\3") buf.write(u"\2\2\2\u00a8\u00ae\7\62\2\2\u00a9\u00aa\7\20\2\2\u00aa") buf.write(u"\u00ab\7.\2\2\u00ab\u00ac\7\f\2\2\u00ac\u00ad\7.\2\2") buf.write(u"\u00ad\u00af\7\21\2\2\u00ae\u00a9\3\2\2\2\u00ae\u00af") buf.write(u"\3\2\2\2\u00af\u00be\3\2\2\2\u00b0\u00b1\7\20\2\2\u00b1") buf.write(u"\u00b2\7.\2\2\u00b2\u00b3\7\22\2\2\u00b3\u00ba\7.\2\2") buf.write(u"\u00b4\u00b5\7\f\2\2\u00b5\u00b6\7.\2\2\u00b6\u00b7\7") buf.write(u"\22\2\2\u00b7\u00b9\7.\2\2\u00b8\u00b4\3\2\2\2\u00b9") buf.write(u"\u00bc\3\2\2\2\u00ba\u00b8\3\2\2\2\u00ba\u00bb\3\2\2") buf.write(u"\2\u00bb\u00bd\3\2\2\2\u00bc\u00ba\3\2\2\2\u00bd\u00bf") buf.write(u"\7\21\2\2\u00be\u00b0\3\2\2\2\u00be\u00bf\3\2\2\2\u00bf") buf.write(u"\u00c3\3\2\2\2\u00c0\u00c1\7\20\2\2\u00c1\u00c2\7.\2") buf.write(u"\2\u00c2\u00c4\7\21\2\2\u00c3\u00c0\3\2\2\2\u00c3\u00c4") buf.write(u"\3\2\2\2\u00c4\u00c6\3\2\2\2\u00c5\u00c7\t\4\2\2\u00c6") buf.write(u"\u00c5\3\2\2\2\u00c6\u00c7\3\2\2\2\u00c7\u00cb\3\2\2") buf.write(u"\2\u00c8\u00ca\7\r\2\2\u00c9\u00c8\3\2\2\2\u00ca\u00cd") buf.write(u"\3\2\2\2\u00cb\u00c9\3\2\2\2\u00cb\u00cc\3\2\2\2\u00cc") buf.write(u"\u00d0\3\2\2\2\u00cd\u00cb\3\2\2\2\u00ce\u00cf\7\5\2") buf.write(u"\2\u00cf\u00d1\58\35\2\u00d0\u00ce\3\2\2\2\u00d0\u00d1") buf.write(u"\3\2\2\2\u00d1\25\3\2\2\2\u00d2\u00d3\7\20\2\2\u00d3") buf.write(u"\u00d4\7.\2\2\u00d4\u00d5\7\22\2\2\u00d5\u00dc\7.\2\2") buf.write(u"\u00d6\u00d7\7\f\2\2\u00d7\u00d8\7.\2\2\u00d8\u00d9\7") buf.write(u"\22\2\2\u00d9\u00db\7.\2\2\u00da\u00d6\3\2\2\2\u00db") buf.write(u"\u00de\3\2\2\2\u00dc\u00da\3\2\2\2\u00dc\u00dd\3\2\2") buf.write(u"\2\u00dd\u00df\3\2\2\2\u00de\u00dc\3\2\2\2\u00df\u00e0") buf.write(u"\7\21\2\2\u00e0\27\3\2\2\2\u00e1\u00e2\7\35\2\2\u00e2") buf.write(u"\u00e7\5\32\16\2\u00e3\u00e4\7\f\2\2\u00e4\u00e6\5\32") buf.write(u"\16\2\u00e5\u00e3\3\2\2\2\u00e6\u00e9\3\2\2\2\u00e7\u00e5") buf.write(u"\3\2\2\2\u00e7\u00e8\3\2\2\2\u00e8\31\3\2\2\2\u00e9\u00e7") buf.write(u"\3\2\2\2\u00ea\u00eb\7\62\2\2\u00eb\u00ec\7\5\2\2\u00ec") buf.write(u"\u00ed\58\35\2\u00ed\33\3\2\2\2\u00ee\u00ef\7\36\2\2") buf.write(u"\u00ef\u00f3\7\62\2\2\u00f0\u00f1\7\16\2\2\u00f1\u00f2") buf.write(u"\7\62\2\2\u00f2\u00f4\7\17\2\2\u00f3\u00f0\3\2\2\2\u00f3") buf.write(u"\u00f4\3\2\2\2\u00f4\u00f7\3\2\2\2\u00f5\u00f6\7\f\2") buf.write(u"\2\u00f6\u00f8\58\35\2\u00f7\u00f5\3\2\2\2\u00f8\u00f9") buf.write(u"\3\2\2\2\u00f9\u00f7\3\2\2\2\u00f9\u00fa\3\2\2\2\u00fa") buf.write(u"\35\3\2\2\2\u00fb\u00fc\7\3\2\2\u00fc\u0101\58\35\2\u00fd") buf.write(u"\u00fe\t\5\2\2\u00fe\u0100\58\35\2\u00ff\u00fd\3\2\2") buf.write(u"\2\u0100\u0103\3\2\2\2\u0101\u00ff\3\2\2\2\u0101\u0102") buf.write(u"\3\2\2\2\u0102\u0104\3\2\2\2\u0103\u0101\3\2\2\2\u0104") buf.write(u"\u0105\7\4\2\2\u0105\37\3\2\2\2\u0106\u0107\7\62\2\2") buf.write(u"\u0107\u0108\7\62\2\2\u0108\u010a\7\5\2\2\u0109\u010b") buf.write(u"\t\6\2\2\u010a\u0109\3\2\2\2\u010a\u010b\3\2\2\2\u010b") buf.write(u"\u010f\3\2\2\2\u010c\u010f\7/\2\2\u010d\u010f\7.\2\2") buf.write(u"\u010e\u0106\3\2\2\2\u010e\u010c\3\2\2\2\u010e\u010d") buf.write(u"\3\2\2\2\u010f!\3\2\2\2\u0110\u0116\5&\24\2\u0111\u0116") buf.write(u"\5(\25\2\u0112\u0116\5.\30\2\u0113\u0116\5\62\32\2\u0114") buf.write(u"\u0116\5\64\33\2\u0115\u0110\3\2\2\2\u0115\u0111\3\2") buf.write(u"\2\2\u0115\u0112\3\2\2\2\u0115\u0113\3\2\2\2\u0115\u0114") buf.write(u"\3\2\2\2\u0116#\3\2\2\2\u0117\u0119\7\62\2\2\u0118\u011a") buf.write(u"\t\7\2\2\u0119\u0118\3\2\2\2\u0119\u011a\3\2\2\2\u011a") buf.write(u"%\3\2\2\2\u011b\u011c\7\"\2\2\u011c\u0121\7\62\2\2\u011d") buf.write(u"\u011e\7\f\2\2\u011e\u0120\7\62\2\2\u011f\u011d\3\2\2") buf.write(u"\2\u0120\u0123\3\2\2\2\u0121\u011f\3\2\2\2\u0121\u0122") buf.write(u"\3\2\2\2\u0122\'\3\2\2\2\u0123\u0121\3\2\2\2\u0124\u0125") buf.write(u"\7\37\2\2\u0125\u012a\5,\27\2\u0126\u0127\7\f\2\2\u0127") buf.write(u"\u0129\5,\27\2\u0128\u0126\3\2\2\2\u0129\u012c\3\2\2") buf.write(u"\2\u012a\u0128\3\2\2\2\u012a\u012b\3\2\2\2\u012b)\3\2") buf.write(u"\2\2\u012c\u012a\3\2\2\2\u012d\u012f\7\62\2\2\u012e\u0130") buf.write(u"\5\f\7\2\u012f\u012e\3\2\2\2\u012f\u0130\3\2\2\2\u0130") buf.write(u"+\3\2\2\2\u0131\u0132\5*\26\2\u0132\u0133\7\5\2\2\u0133") buf.write(u"\u0135\58\35\2\u0134\u0136\58\35\2\u0135\u0134\3\2\2") buf.write(u"\2\u0135\u0136\3\2\2\2\u0136-\3\2\2\2\u0137\u0138\7 ") buf.write(u"\2\2\u0138\u013d\5\60\31\2\u0139\u013a\7\f\2\2\u013a") buf.write(u"\u013c\5\60\31\2\u013b\u0139\3\2\2\2\u013c\u013f\3\2") buf.write(u"\2\2\u013d\u013b\3\2\2\2\u013d\u013e\3\2\2\2\u013e/\3") buf.write(u"\2\2\2\u013f\u013d\3\2\2\2\u0140\u0142\58\35\2\u0141") buf.write(u"\u0143\58\35\2\u0142\u0141\3\2\2\2\u0142\u0143\3\2\2") buf.write(u"\2\u0143\61\3\2\2\2\u0144\u0145\7\62\2\2\u0145\u0151") buf.write(u"\5\16\b\2\u0146\u0147\7\3\2\2\u0147\u014c\5 \21\2\u0148") buf.write(u"\u0149\7\f\2\2\u0149\u014b\5 \21\2\u014a\u0148\3\2\2") buf.write(u"\2\u014b\u014e\3\2\2\2\u014c\u014a\3\2\2\2\u014c\u014d") buf.write(u"\3\2\2\2\u014d\u014f\3\2\2\2\u014e\u014c\3\2\2\2\u014f") buf.write(u"\u0150\7\4\2\2\u0150\u0152\3\2\2\2\u0151\u0146\3\2\2") buf.write(u"\2\u0151\u0152\3\2\2\2\u0152\u0153\3\2\2\2\u0153\u0154") buf.write(u"\7\62\2\2\u0154\u0155\7\26\2\2\u0155\u0156\7\62\2\2\u0156") buf.write(u"\63\3\2\2\2\u0157\u0158\7!\2\2\u0158\u0159\7\62\2\2\u0159") buf.write(u"\u015a\7\26\2\2\u015a\u0165\7\62\2\2\u015b\u015c\7#\2") buf.write(u"\2\u015c\u0161\7\62\2\2\u015d\u015e\7\f\2\2\u015e\u0160") buf.write(u"\7\62\2\2\u015f\u015d\3\2\2\2\u0160\u0163\3\2\2\2\u0161") buf.write(u"\u015f\3\2\2\2\u0161\u0162\3\2\2\2\u0162\u0165\3\2\2") buf.write(u"\2\u0163\u0161\3\2\2\2\u0164\u0157\3\2\2\2\u0164\u015b") buf.write(u"\3\2\2\2\u0165\65\3\2\2\2\u0166\u0168\7\62\2\2\u0167") buf.write(u"\u0169\7\27\2\2\u0168\u0167\3\2\2\2\u0169\u016a\3\2\2") buf.write(u"\2\u016a\u0168\3\2\2\2\u016a\u016b\3\2\2\2\u016b\u016f") buf.write(u"\3\2\2\2\u016c\u016f\7\30\2\2\u016d\u016f\7\31\2\2\u016e") buf.write(u"\u0166\3\2\2\2\u016e\u016c\3\2\2\2\u016e\u016d\3\2\2") buf.write(u"\2\u016f\67\3\2\2\2\u0170\u0171\b\35\1\2\u0171\u019b") buf.write(u"\7\60\2\2\u0172\u0173\7\24\2\2\u0173\u019b\58\35\16\u0174") buf.write(u"\u019b\7/\2\2\u0175\u019b\7.\2\2\u0176\u017a\7\62\2\2") buf.write(u"\u0177\u0179\7\r\2\2\u0178\u0177\3\2\2\2\u0179\u017c") buf.write(u"\3\2\2\2\u017a\u0178\3\2\2\2\u017a\u017b\3\2\2\2\u017b") buf.write(u"\u019b\3\2\2\2\u017c\u017a\3\2\2\2\u017d\u019b\5\66\34") buf.write(u"\2\u017e\u017f\7\62\2\2\u017f\u0180\7\3\2\2\u0180\u0185") buf.write(u"\58\35\2\u0181\u0182\7\f\2\2\u0182\u0184\58\35\2\u0183") buf.write(u"\u0181\3\2\2\2\u0184\u0187\3\2\2\2\u0185\u0183\3\2\2") buf.write(u"\2\u0185\u0186\3\2\2\2\u0186\u0188\3\2\2\2\u0187\u0185") buf.write(u"\3\2\2\2\u0188\u0189\7\4\2\2\u0189\u019b\3\2\2\2\u018a") buf.write(u"\u019b\5\16\b\2\u018b\u019b\5\36\20\2\u018c\u018d\7\16") buf.write(u"\2\2\u018d\u018e\58\35\2\u018e\u018f\7\17\2\2\u018f\u019b") buf.write(u"\3\2\2\2\u0190\u0192\7\62\2\2\u0191\u0190\3\2\2\2\u0191") buf.write(u"\u0192\3\2\2\2\u0192\u0193\3\2\2\2\u0193\u0197\5\26\f") buf.write(u"\2\u0194\u0196\7\r\2\2\u0195\u0194\3\2\2\2\u0196\u0199") buf.write(u"\3\2\2\2\u0197\u0195\3\2\2\2\u0197\u0198\3\2\2\2\u0198") buf.write(u"\u019b\3\2\2\2\u0199\u0197\3\2\2\2\u019a\u0170\3\2\2") buf.write(u"\2\u019a\u0172\3\2\2\2\u019a\u0174\3\2\2\2\u019a\u0175") buf.write(u"\3\2\2\2\u019a\u0176\3\2\2\2\u019a\u017d\3\2\2\2\u019a") buf.write(u"\u017e\3\2\2\2\u019a\u018a\3\2\2\2\u019a\u018b\3\2\2") buf.write(u"\2\u019a\u018c\3\2\2\2\u019a\u0191\3\2\2\2\u019b\u01ad") buf.write(u"\3\2\2\2\u019c\u019d\f\22\2\2\u019d\u019e\7\32\2\2\u019e") buf.write(u"\u01ac\58\35\23\u019f\u01a0\f\21\2\2\u01a0\u01a1\t\b") buf.write(u"\2\2\u01a1\u01ac\58\35\22\u01a2\u01a3\f\20\2\2\u01a3") buf.write(u"\u01a4\t\4\2\2\u01a4\u01ac\58\35\21\u01a5\u01a6\f\5\2") buf.write(u"\2\u01a6\u01a7\7\5\2\2\u01a7\u01ac\58\35\6\u01a8\u01a9") buf.write(u"\f\4\2\2\u01a9\u01aa\7\22\2\2\u01aa\u01ac\58\35\5\u01ab") buf.write(u"\u019c\3\2\2\2\u01ab\u019f\3\2\2\2\u01ab\u01a2\3\2\2") buf.write(u"\2\u01ab\u01a5\3\2\2\2\u01ab\u01a8\3\2\2\2\u01ac\u01af") buf.write(u"\3\2\2\2\u01ad\u01ab\3\2\2\2\u01ad\u01ae\3\2\2\2\u01ae") buf.write(u"9\3\2\2\2\u01af\u01ad\3\2\2\2\64=FUZciru\177\u0082\u0085") buf.write(u"\u008d\u009c\u00a3\u00a6\u00ae\u00ba\u00be\u00c3\u00c6") buf.write(u"\u00cb\u00d0\u00dc\u00e7\u00f3\u00f9\u0101\u010a\u010e") buf.write(u"\u0115\u0119\u0121\u012a\u012f\u0135\u013d\u0142\u014c") buf.write(u"\u0151\u0161\u0164\u016a\u016e\u017a\u0185\u0191\u0197") buf.write(u"\u019a\u01ab\u01ad") return buf.getvalue() class AutolevParser ( Parser ): grammarFileName = "Autolev.g4" atn = ATNDeserializer().deserialize(serializedATN()) decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] sharedContextCache = PredictionContextCache() literalNames = [ u"", u"'['", u"']'", u"'='", u"'+='", u"'-='", u"':='", u"'*='", u"'/='", u"'^='", u"','", u"'''", u"'('", u"')'", u"'{'", u"'}'", u"':'", u"'+'", u"'-'", u"';'", u"'.'", u"'>'", u"'0>'", u"'1>>'", u"'^'", u"'*'", u"'/'" ] symbolicNames = [ u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"", u"Mass", u"Inertia", u"Input", u"Output", u"Save", u"UnitSystem", u"Encode", u"Newtonian", u"Frames", u"Bodies", u"Particles", u"Points", u"Constants", u"Specifieds", u"Imaginary", u"Variables", u"MotionVariables", u"INT", u"FLOAT", u"EXP", u"LINE_COMMENT", u"ID", u"WS" ] RULE_prog = 0 RULE_stat = 1 RULE_assignment = 2 RULE_equals = 3 RULE_index = 4 RULE_diff = 5 RULE_functionCall = 6 RULE_varDecl = 7 RULE_varType = 8 RULE_varDecl2 = 9 RULE_ranges = 10 RULE_massDecl = 11 RULE_massDecl2 = 12 RULE_inertiaDecl = 13 RULE_matrix = 14 RULE_matrixInOutput = 15 RULE_codeCommands = 16 RULE_settings = 17 RULE_units = 18 RULE_inputs = 19 RULE_id_diff = 20 RULE_inputs2 = 21 RULE_outputs = 22 RULE_outputs2 = 23 RULE_codegen = 24 RULE_commands = 25 RULE_vec = 26 RULE_expr = 27 ruleNames = [ u"prog", u"stat", u"assignment", u"equals", u"index", u"diff", u"functionCall", u"varDecl", u"varType", u"varDecl2", u"ranges", u"massDecl", u"massDecl2", u"inertiaDecl", u"matrix", u"matrixInOutput", u"codeCommands", u"settings", u"units", u"inputs", u"id_diff", u"inputs2", u"outputs", u"outputs2", u"codegen", u"commands", u"vec", u"expr" ] EOF = Token.EOF T__0=1 T__1=2 T__2=3 T__3=4 T__4=5 T__5=6 T__6=7 T__7=8 T__8=9 T__9=10 T__10=11 T__11=12 T__12=13 T__13=14 T__14=15 T__15=16 T__16=17 T__17=18 T__18=19 T__19=20 T__20=21 T__21=22 T__22=23 T__23=24 T__24=25 T__25=26 Mass=27 Inertia=28 Input=29 Output=30 Save=31 UnitSystem=32 Encode=33 Newtonian=34 Frames=35 Bodies=36 Particles=37 Points=38 Constants=39 Specifieds=40 Imaginary=41 Variables=42 MotionVariables=43 INT=44 FLOAT=45 EXP=46 LINE_COMMENT=47 ID=48 WS=49 def __init__(self, input, output=sys.stdout): super(AutolevParser, self).__init__(input, output=output) self.checkVersion("4.7.1") self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) self._predicates = None class ProgContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.ProgContext, self).__init__(parent, invokingState) self.parser = parser def stat(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.StatContext) else: return self.getTypedRuleContext(AutolevParser.StatContext,i) def getRuleIndex(self): return AutolevParser.RULE_prog def enterRule(self, listener): if hasattr(listener, "enterProg"): listener.enterProg(self) def exitRule(self, listener): if hasattr(listener, "exitProg"): listener.exitProg(self) def prog(self): localctx = AutolevParser.ProgContext(self, self._ctx, self.state) self.enterRule(localctx, 0, self.RULE_prog) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 57 self._errHandler.sync(self) _la = self._input.LA(1) while True: self.state = 56 self.stat() self.state = 59 self._errHandler.sync(self) _la = self._input.LA(1) if not ((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << AutolevParser.T__21) | (1 << AutolevParser.T__22) | (1 << AutolevParser.Mass) | (1 << AutolevParser.Inertia) | (1 << AutolevParser.Input) | (1 << AutolevParser.Output) | (1 << AutolevParser.Save) | (1 << AutolevParser.UnitSystem) | (1 << AutolevParser.Encode) | (1 << AutolevParser.Newtonian) | (1 << AutolevParser.Frames) | (1 << AutolevParser.Bodies) | (1 << AutolevParser.Particles) | (1 << AutolevParser.Points) | (1 << AutolevParser.Constants) | (1 << AutolevParser.Specifieds) | (1 << AutolevParser.Imaginary) | (1 << AutolevParser.Variables) | (1 << AutolevParser.MotionVariables) | (1 << AutolevParser.ID))) != 0)): break except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class StatContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.StatContext, self).__init__(parent, invokingState) self.parser = parser def varDecl(self): return self.getTypedRuleContext(AutolevParser.VarDeclContext,0) def functionCall(self): return self.getTypedRuleContext(AutolevParser.FunctionCallContext,0) def codeCommands(self): return self.getTypedRuleContext(AutolevParser.CodeCommandsContext,0) def massDecl(self): return self.getTypedRuleContext(AutolevParser.MassDeclContext,0) def inertiaDecl(self): return self.getTypedRuleContext(AutolevParser.InertiaDeclContext,0) def assignment(self): return self.getTypedRuleContext(AutolevParser.AssignmentContext,0) def settings(self): return self.getTypedRuleContext(AutolevParser.SettingsContext,0) def getRuleIndex(self): return AutolevParser.RULE_stat def enterRule(self, listener): if hasattr(listener, "enterStat"): listener.enterStat(self) def exitRule(self, listener): if hasattr(listener, "exitStat"): listener.exitStat(self) def stat(self): localctx = AutolevParser.StatContext(self, self._ctx, self.state) self.enterRule(localctx, 2, self.RULE_stat) try: self.state = 68 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,1,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) self.state = 61 self.varDecl() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) self.state = 62 self.functionCall() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) self.state = 63 self.codeCommands() pass elif la_ == 4: self.enterOuterAlt(localctx, 4) self.state = 64 self.massDecl() pass elif la_ == 5: self.enterOuterAlt(localctx, 5) self.state = 65 self.inertiaDecl() pass elif la_ == 6: self.enterOuterAlt(localctx, 6) self.state = 66 self.assignment() pass elif la_ == 7: self.enterOuterAlt(localctx, 7) self.state = 67 self.settings() pass except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class AssignmentContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.AssignmentContext, self).__init__(parent, invokingState) self.parser = parser def getRuleIndex(self): return AutolevParser.RULE_assignment def copyFrom(self, ctx): super(AutolevParser.AssignmentContext, self).copyFrom(ctx) class VecAssignContext(AssignmentContext): def __init__(self, parser, ctx): # actually a AutolevParser.AssignmentContext) super(AutolevParser.VecAssignContext, self).__init__(parser) self.copyFrom(ctx) def vec(self): return self.getTypedRuleContext(AutolevParser.VecContext,0) def equals(self): return self.getTypedRuleContext(AutolevParser.EqualsContext,0) def expr(self): return self.getTypedRuleContext(AutolevParser.ExprContext,0) def enterRule(self, listener): if hasattr(listener, "enterVecAssign"): listener.enterVecAssign(self) def exitRule(self, listener): if hasattr(listener, "exitVecAssign"): listener.exitVecAssign(self) class RegularAssignContext(AssignmentContext): def __init__(self, parser, ctx): # actually a AutolevParser.AssignmentContext) super(AutolevParser.RegularAssignContext, self).__init__(parser) self.copyFrom(ctx) def ID(self): return self.getToken(AutolevParser.ID, 0) def equals(self): return self.getTypedRuleContext(AutolevParser.EqualsContext,0) def expr(self): return self.getTypedRuleContext(AutolevParser.ExprContext,0) def diff(self): return self.getTypedRuleContext(AutolevParser.DiffContext,0) def enterRule(self, listener): if hasattr(listener, "enterRegularAssign"): listener.enterRegularAssign(self) def exitRule(self, listener): if hasattr(listener, "exitRegularAssign"): listener.exitRegularAssign(self) class IndexAssignContext(AssignmentContext): def __init__(self, parser, ctx): # actually a AutolevParser.AssignmentContext) super(AutolevParser.IndexAssignContext, self).__init__(parser) self.copyFrom(ctx) def ID(self): return self.getToken(AutolevParser.ID, 0) def index(self): return self.getTypedRuleContext(AutolevParser.IndexContext,0) def equals(self): return self.getTypedRuleContext(AutolevParser.EqualsContext,0) def expr(self): return self.getTypedRuleContext(AutolevParser.ExprContext,0) def enterRule(self, listener): if hasattr(listener, "enterIndexAssign"): listener.enterIndexAssign(self) def exitRule(self, listener): if hasattr(listener, "exitIndexAssign"): listener.exitIndexAssign(self) def assignment(self): localctx = AutolevParser.AssignmentContext(self, self._ctx, self.state) self.enterRule(localctx, 4, self.RULE_assignment) self._la = 0 # Token type try: self.state = 88 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,3,self._ctx) if la_ == 1: localctx = AutolevParser.VecAssignContext(self, localctx) self.enterOuterAlt(localctx, 1) self.state = 70 self.vec() self.state = 71 self.equals() self.state = 72 self.expr(0) pass elif la_ == 2: localctx = AutolevParser.IndexAssignContext(self, localctx) self.enterOuterAlt(localctx, 2) self.state = 74 self.match(AutolevParser.ID) self.state = 75 self.match(AutolevParser.T__0) self.state = 76 self.index() self.state = 77 self.match(AutolevParser.T__1) self.state = 78 self.equals() self.state = 79 self.expr(0) pass elif la_ == 3: localctx = AutolevParser.RegularAssignContext(self, localctx) self.enterOuterAlt(localctx, 3) self.state = 81 self.match(AutolevParser.ID) self.state = 83 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.T__10: self.state = 82 self.diff() self.state = 85 self.equals() self.state = 86 self.expr(0) pass except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class EqualsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.EqualsContext, self).__init__(parent, invokingState) self.parser = parser def getRuleIndex(self): return AutolevParser.RULE_equals def enterRule(self, listener): if hasattr(listener, "enterEquals"): listener.enterEquals(self) def exitRule(self, listener): if hasattr(listener, "exitEquals"): listener.exitEquals(self) def equals(self): localctx = AutolevParser.EqualsContext(self, self._ctx, self.state) self.enterRule(localctx, 6, self.RULE_equals) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 90 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << AutolevParser.T__2) | (1 << AutolevParser.T__3) | (1 << AutolevParser.T__4) | (1 << AutolevParser.T__5) | (1 << AutolevParser.T__6) | (1 << AutolevParser.T__7) | (1 << AutolevParser.T__8))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class IndexContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.IndexContext, self).__init__(parent, invokingState) self.parser = parser def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def getRuleIndex(self): return AutolevParser.RULE_index def enterRule(self, listener): if hasattr(listener, "enterIndex"): listener.enterIndex(self) def exitRule(self, listener): if hasattr(listener, "exitIndex"): listener.exitIndex(self) def index(self): localctx = AutolevParser.IndexContext(self, self._ctx, self.state) self.enterRule(localctx, 8, self.RULE_index) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 92 self.expr(0) self.state = 97 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 93 self.match(AutolevParser.T__9) self.state = 94 self.expr(0) self.state = 99 self._errHandler.sync(self) _la = self._input.LA(1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class DiffContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.DiffContext, self).__init__(parent, invokingState) self.parser = parser def getRuleIndex(self): return AutolevParser.RULE_diff def enterRule(self, listener): if hasattr(listener, "enterDiff"): listener.enterDiff(self) def exitRule(self, listener): if hasattr(listener, "exitDiff"): listener.exitDiff(self) def diff(self): localctx = AutolevParser.DiffContext(self, self._ctx, self.state) self.enterRule(localctx, 10, self.RULE_diff) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 101 self._errHandler.sync(self) _la = self._input.LA(1) while True: self.state = 100 self.match(AutolevParser.T__10) self.state = 103 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==AutolevParser.T__10): break except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class FunctionCallContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.FunctionCallContext, self).__init__(parent, invokingState) self.parser = parser def ID(self, i=None): if i is None: return self.getTokens(AutolevParser.ID) else: return self.getToken(AutolevParser.ID, i) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def Mass(self): return self.getToken(AutolevParser.Mass, 0) def Inertia(self): return self.getToken(AutolevParser.Inertia, 0) def getRuleIndex(self): return AutolevParser.RULE_functionCall def enterRule(self, listener): if hasattr(listener, "enterFunctionCall"): listener.enterFunctionCall(self) def exitRule(self, listener): if hasattr(listener, "exitFunctionCall"): listener.exitFunctionCall(self) def functionCall(self): localctx = AutolevParser.FunctionCallContext(self, self._ctx, self.state) self.enterRule(localctx, 12, self.RULE_functionCall) self._la = 0 # Token type try: self.state = 131 self._errHandler.sync(self) token = self._input.LA(1) if token in [AutolevParser.ID]: self.enterOuterAlt(localctx, 1) self.state = 105 self.match(AutolevParser.ID) self.state = 106 self.match(AutolevParser.T__11) self.state = 115 self._errHandler.sync(self) _la = self._input.LA(1) if (((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << AutolevParser.T__0) | (1 << AutolevParser.T__11) | (1 << AutolevParser.T__13) | (1 << AutolevParser.T__17) | (1 << AutolevParser.T__21) | (1 << AutolevParser.T__22) | (1 << AutolevParser.Mass) | (1 << AutolevParser.Inertia) | (1 << AutolevParser.INT) | (1 << AutolevParser.FLOAT) | (1 << AutolevParser.EXP) | (1 << AutolevParser.ID))) != 0): self.state = 107 self.expr(0) self.state = 112 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 108 self.match(AutolevParser.T__9) self.state = 109 self.expr(0) self.state = 114 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 117 self.match(AutolevParser.T__12) pass elif token in [AutolevParser.Mass, AutolevParser.Inertia]: self.enterOuterAlt(localctx, 2) self.state = 118 _la = self._input.LA(1) if not(_la==AutolevParser.Mass or _la==AutolevParser.Inertia): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 119 self.match(AutolevParser.T__11) self.state = 128 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.ID: self.state = 120 self.match(AutolevParser.ID) self.state = 125 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 121 self.match(AutolevParser.T__9) self.state = 122 self.match(AutolevParser.ID) self.state = 127 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 130 self.match(AutolevParser.T__12) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class VarDeclContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.VarDeclContext, self).__init__(parent, invokingState) self.parser = parser def varType(self): return self.getTypedRuleContext(AutolevParser.VarTypeContext,0) def varDecl2(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.VarDecl2Context) else: return self.getTypedRuleContext(AutolevParser.VarDecl2Context,i) def getRuleIndex(self): return AutolevParser.RULE_varDecl def enterRule(self, listener): if hasattr(listener, "enterVarDecl"): listener.enterVarDecl(self) def exitRule(self, listener): if hasattr(listener, "exitVarDecl"): listener.exitVarDecl(self) def varDecl(self): localctx = AutolevParser.VarDeclContext(self, self._ctx, self.state) self.enterRule(localctx, 14, self.RULE_varDecl) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 133 self.varType() self.state = 134 self.varDecl2() self.state = 139 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 135 self.match(AutolevParser.T__9) self.state = 136 self.varDecl2() self.state = 141 self._errHandler.sync(self) _la = self._input.LA(1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class VarTypeContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.VarTypeContext, self).__init__(parent, invokingState) self.parser = parser def Newtonian(self): return self.getToken(AutolevParser.Newtonian, 0) def Frames(self): return self.getToken(AutolevParser.Frames, 0) def Bodies(self): return self.getToken(AutolevParser.Bodies, 0) def Particles(self): return self.getToken(AutolevParser.Particles, 0) def Points(self): return self.getToken(AutolevParser.Points, 0) def Constants(self): return self.getToken(AutolevParser.Constants, 0) def Specifieds(self): return self.getToken(AutolevParser.Specifieds, 0) def Imaginary(self): return self.getToken(AutolevParser.Imaginary, 0) def Variables(self): return self.getToken(AutolevParser.Variables, 0) def MotionVariables(self): return self.getToken(AutolevParser.MotionVariables, 0) def getRuleIndex(self): return AutolevParser.RULE_varType def enterRule(self, listener): if hasattr(listener, "enterVarType"): listener.enterVarType(self) def exitRule(self, listener): if hasattr(listener, "exitVarType"): listener.exitVarType(self) def varType(self): localctx = AutolevParser.VarTypeContext(self, self._ctx, self.state) self.enterRule(localctx, 16, self.RULE_varType) self._la = 0 # Token type try: self.state = 164 self._errHandler.sync(self) token = self._input.LA(1) if token in [AutolevParser.Newtonian]: self.enterOuterAlt(localctx, 1) self.state = 142 self.match(AutolevParser.Newtonian) pass elif token in [AutolevParser.Frames]: self.enterOuterAlt(localctx, 2) self.state = 143 self.match(AutolevParser.Frames) pass elif token in [AutolevParser.Bodies]: self.enterOuterAlt(localctx, 3) self.state = 144 self.match(AutolevParser.Bodies) pass elif token in [AutolevParser.Particles]: self.enterOuterAlt(localctx, 4) self.state = 145 self.match(AutolevParser.Particles) pass elif token in [AutolevParser.Points]: self.enterOuterAlt(localctx, 5) self.state = 146 self.match(AutolevParser.Points) pass elif token in [AutolevParser.Constants]: self.enterOuterAlt(localctx, 6) self.state = 147 self.match(AutolevParser.Constants) pass elif token in [AutolevParser.Specifieds]: self.enterOuterAlt(localctx, 7) self.state = 148 self.match(AutolevParser.Specifieds) pass elif token in [AutolevParser.Imaginary]: self.enterOuterAlt(localctx, 8) self.state = 149 self.match(AutolevParser.Imaginary) pass elif token in [AutolevParser.Variables]: self.enterOuterAlt(localctx, 9) self.state = 150 self.match(AutolevParser.Variables) self.state = 154 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__10: self.state = 151 self.match(AutolevParser.T__10) self.state = 156 self._errHandler.sync(self) _la = self._input.LA(1) pass elif token in [AutolevParser.MotionVariables]: self.enterOuterAlt(localctx, 10) self.state = 157 self.match(AutolevParser.MotionVariables) self.state = 161 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__10: self.state = 158 self.match(AutolevParser.T__10) self.state = 163 self._errHandler.sync(self) _la = self._input.LA(1) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class VarDecl2Context(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.VarDecl2Context, self).__init__(parent, invokingState) self.parser = parser def ID(self): return self.getToken(AutolevParser.ID, 0) def INT(self, i=None): if i is None: return self.getTokens(AutolevParser.INT) else: return self.getToken(AutolevParser.INT, i) def expr(self): return self.getTypedRuleContext(AutolevParser.ExprContext,0) def getRuleIndex(self): return AutolevParser.RULE_varDecl2 def enterRule(self, listener): if hasattr(listener, "enterVarDecl2"): listener.enterVarDecl2(self) def exitRule(self, listener): if hasattr(listener, "exitVarDecl2"): listener.exitVarDecl2(self) def varDecl2(self): localctx = AutolevParser.VarDecl2Context(self, self._ctx, self.state) self.enterRule(localctx, 18, self.RULE_varDecl2) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 166 self.match(AutolevParser.ID) self.state = 172 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,15,self._ctx) if la_ == 1: self.state = 167 self.match(AutolevParser.T__13) self.state = 168 self.match(AutolevParser.INT) self.state = 169 self.match(AutolevParser.T__9) self.state = 170 self.match(AutolevParser.INT) self.state = 171 self.match(AutolevParser.T__14) self.state = 188 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,17,self._ctx) if la_ == 1: self.state = 174 self.match(AutolevParser.T__13) self.state = 175 self.match(AutolevParser.INT) self.state = 176 self.match(AutolevParser.T__15) self.state = 177 self.match(AutolevParser.INT) self.state = 184 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 178 self.match(AutolevParser.T__9) self.state = 179 self.match(AutolevParser.INT) self.state = 180 self.match(AutolevParser.T__15) self.state = 181 self.match(AutolevParser.INT) self.state = 186 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 187 self.match(AutolevParser.T__14) self.state = 193 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.T__13: self.state = 190 self.match(AutolevParser.T__13) self.state = 191 self.match(AutolevParser.INT) self.state = 192 self.match(AutolevParser.T__14) self.state = 196 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.T__16 or _la==AutolevParser.T__17: self.state = 195 _la = self._input.LA(1) if not(_la==AutolevParser.T__16 or _la==AutolevParser.T__17): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 201 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__10: self.state = 198 self.match(AutolevParser.T__10) self.state = 203 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 206 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.T__2: self.state = 204 self.match(AutolevParser.T__2) self.state = 205 self.expr(0) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class RangesContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.RangesContext, self).__init__(parent, invokingState) self.parser = parser def INT(self, i=None): if i is None: return self.getTokens(AutolevParser.INT) else: return self.getToken(AutolevParser.INT, i) def getRuleIndex(self): return AutolevParser.RULE_ranges def enterRule(self, listener): if hasattr(listener, "enterRanges"): listener.enterRanges(self) def exitRule(self, listener): if hasattr(listener, "exitRanges"): listener.exitRanges(self) def ranges(self): localctx = AutolevParser.RangesContext(self, self._ctx, self.state) self.enterRule(localctx, 20, self.RULE_ranges) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 208 self.match(AutolevParser.T__13) self.state = 209 self.match(AutolevParser.INT) self.state = 210 self.match(AutolevParser.T__15) self.state = 211 self.match(AutolevParser.INT) self.state = 218 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 212 self.match(AutolevParser.T__9) self.state = 213 self.match(AutolevParser.INT) self.state = 214 self.match(AutolevParser.T__15) self.state = 215 self.match(AutolevParser.INT) self.state = 220 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 221 self.match(AutolevParser.T__14) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class MassDeclContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.MassDeclContext, self).__init__(parent, invokingState) self.parser = parser def Mass(self): return self.getToken(AutolevParser.Mass, 0) def massDecl2(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.MassDecl2Context) else: return self.getTypedRuleContext(AutolevParser.MassDecl2Context,i) def getRuleIndex(self): return AutolevParser.RULE_massDecl def enterRule(self, listener): if hasattr(listener, "enterMassDecl"): listener.enterMassDecl(self) def exitRule(self, listener): if hasattr(listener, "exitMassDecl"): listener.exitMassDecl(self) def massDecl(self): localctx = AutolevParser.MassDeclContext(self, self._ctx, self.state) self.enterRule(localctx, 22, self.RULE_massDecl) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 223 self.match(AutolevParser.Mass) self.state = 224 self.massDecl2() self.state = 229 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 225 self.match(AutolevParser.T__9) self.state = 226 self.massDecl2() self.state = 231 self._errHandler.sync(self) _la = self._input.LA(1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class MassDecl2Context(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.MassDecl2Context, self).__init__(parent, invokingState) self.parser = parser def ID(self): return self.getToken(AutolevParser.ID, 0) def expr(self): return self.getTypedRuleContext(AutolevParser.ExprContext,0) def getRuleIndex(self): return AutolevParser.RULE_massDecl2 def enterRule(self, listener): if hasattr(listener, "enterMassDecl2"): listener.enterMassDecl2(self) def exitRule(self, listener): if hasattr(listener, "exitMassDecl2"): listener.exitMassDecl2(self) def massDecl2(self): localctx = AutolevParser.MassDecl2Context(self, self._ctx, self.state) self.enterRule(localctx, 24, self.RULE_massDecl2) try: self.enterOuterAlt(localctx, 1) self.state = 232 self.match(AutolevParser.ID) self.state = 233 self.match(AutolevParser.T__2) self.state = 234 self.expr(0) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class InertiaDeclContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.InertiaDeclContext, self).__init__(parent, invokingState) self.parser = parser def Inertia(self): return self.getToken(AutolevParser.Inertia, 0) def ID(self, i=None): if i is None: return self.getTokens(AutolevParser.ID) else: return self.getToken(AutolevParser.ID, i) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def getRuleIndex(self): return AutolevParser.RULE_inertiaDecl def enterRule(self, listener): if hasattr(listener, "enterInertiaDecl"): listener.enterInertiaDecl(self) def exitRule(self, listener): if hasattr(listener, "exitInertiaDecl"): listener.exitInertiaDecl(self) def inertiaDecl(self): localctx = AutolevParser.InertiaDeclContext(self, self._ctx, self.state) self.enterRule(localctx, 26, self.RULE_inertiaDecl) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 236 self.match(AutolevParser.Inertia) self.state = 237 self.match(AutolevParser.ID) self.state = 241 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.T__11: self.state = 238 self.match(AutolevParser.T__11) self.state = 239 self.match(AutolevParser.ID) self.state = 240 self.match(AutolevParser.T__12) self.state = 245 self._errHandler.sync(self) _la = self._input.LA(1) while True: self.state = 243 self.match(AutolevParser.T__9) self.state = 244 self.expr(0) self.state = 247 self._errHandler.sync(self) _la = self._input.LA(1) if not (_la==AutolevParser.T__9): break except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class MatrixContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.MatrixContext, self).__init__(parent, invokingState) self.parser = parser def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def getRuleIndex(self): return AutolevParser.RULE_matrix def enterRule(self, listener): if hasattr(listener, "enterMatrix"): listener.enterMatrix(self) def exitRule(self, listener): if hasattr(listener, "exitMatrix"): listener.exitMatrix(self) def matrix(self): localctx = AutolevParser.MatrixContext(self, self._ctx, self.state) self.enterRule(localctx, 28, self.RULE_matrix) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 249 self.match(AutolevParser.T__0) self.state = 250 self.expr(0) self.state = 255 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9 or _la==AutolevParser.T__18: self.state = 251 _la = self._input.LA(1) if not(_la==AutolevParser.T__9 or _la==AutolevParser.T__18): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 252 self.expr(0) self.state = 257 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 258 self.match(AutolevParser.T__1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class MatrixInOutputContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.MatrixInOutputContext, self).__init__(parent, invokingState) self.parser = parser def ID(self, i=None): if i is None: return self.getTokens(AutolevParser.ID) else: return self.getToken(AutolevParser.ID, i) def FLOAT(self): return self.getToken(AutolevParser.FLOAT, 0) def INT(self): return self.getToken(AutolevParser.INT, 0) def getRuleIndex(self): return AutolevParser.RULE_matrixInOutput def enterRule(self, listener): if hasattr(listener, "enterMatrixInOutput"): listener.enterMatrixInOutput(self) def exitRule(self, listener): if hasattr(listener, "exitMatrixInOutput"): listener.exitMatrixInOutput(self) def matrixInOutput(self): localctx = AutolevParser.MatrixInOutputContext(self, self._ctx, self.state) self.enterRule(localctx, 30, self.RULE_matrixInOutput) self._la = 0 # Token type try: self.state = 268 self._errHandler.sync(self) token = self._input.LA(1) if token in [AutolevParser.ID]: self.enterOuterAlt(localctx, 1) self.state = 260 self.match(AutolevParser.ID) self.state = 261 self.match(AutolevParser.ID) self.state = 262 self.match(AutolevParser.T__2) self.state = 264 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.INT or _la==AutolevParser.FLOAT: self.state = 263 _la = self._input.LA(1) if not(_la==AutolevParser.INT or _la==AutolevParser.FLOAT): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() pass elif token in [AutolevParser.FLOAT]: self.enterOuterAlt(localctx, 2) self.state = 266 self.match(AutolevParser.FLOAT) pass elif token in [AutolevParser.INT]: self.enterOuterAlt(localctx, 3) self.state = 267 self.match(AutolevParser.INT) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class CodeCommandsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.CodeCommandsContext, self).__init__(parent, invokingState) self.parser = parser def units(self): return self.getTypedRuleContext(AutolevParser.UnitsContext,0) def inputs(self): return self.getTypedRuleContext(AutolevParser.InputsContext,0) def outputs(self): return self.getTypedRuleContext(AutolevParser.OutputsContext,0) def codegen(self): return self.getTypedRuleContext(AutolevParser.CodegenContext,0) def commands(self): return self.getTypedRuleContext(AutolevParser.CommandsContext,0) def getRuleIndex(self): return AutolevParser.RULE_codeCommands def enterRule(self, listener): if hasattr(listener, "enterCodeCommands"): listener.enterCodeCommands(self) def exitRule(self, listener): if hasattr(listener, "exitCodeCommands"): listener.exitCodeCommands(self) def codeCommands(self): localctx = AutolevParser.CodeCommandsContext(self, self._ctx, self.state) self.enterRule(localctx, 32, self.RULE_codeCommands) try: self.state = 275 self._errHandler.sync(self) token = self._input.LA(1) if token in [AutolevParser.UnitSystem]: self.enterOuterAlt(localctx, 1) self.state = 270 self.units() pass elif token in [AutolevParser.Input]: self.enterOuterAlt(localctx, 2) self.state = 271 self.inputs() pass elif token in [AutolevParser.Output]: self.enterOuterAlt(localctx, 3) self.state = 272 self.outputs() pass elif token in [AutolevParser.ID]: self.enterOuterAlt(localctx, 4) self.state = 273 self.codegen() pass elif token in [AutolevParser.Save, AutolevParser.Encode]: self.enterOuterAlt(localctx, 5) self.state = 274 self.commands() pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class SettingsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.SettingsContext, self).__init__(parent, invokingState) self.parser = parser def ID(self, i=None): if i is None: return self.getTokens(AutolevParser.ID) else: return self.getToken(AutolevParser.ID, i) def EXP(self): return self.getToken(AutolevParser.EXP, 0) def FLOAT(self): return self.getToken(AutolevParser.FLOAT, 0) def INT(self): return self.getToken(AutolevParser.INT, 0) def getRuleIndex(self): return AutolevParser.RULE_settings def enterRule(self, listener): if hasattr(listener, "enterSettings"): listener.enterSettings(self) def exitRule(self, listener): if hasattr(listener, "exitSettings"): listener.exitSettings(self) def settings(self): localctx = AutolevParser.SettingsContext(self, self._ctx, self.state) self.enterRule(localctx, 34, self.RULE_settings) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 277 self.match(AutolevParser.ID) self.state = 279 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,30,self._ctx) if la_ == 1: self.state = 278 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << AutolevParser.INT) | (1 << AutolevParser.FLOAT) | (1 << AutolevParser.EXP) | (1 << AutolevParser.ID))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class UnitsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.UnitsContext, self).__init__(parent, invokingState) self.parser = parser def UnitSystem(self): return self.getToken(AutolevParser.UnitSystem, 0) def ID(self, i=None): if i is None: return self.getTokens(AutolevParser.ID) else: return self.getToken(AutolevParser.ID, i) def getRuleIndex(self): return AutolevParser.RULE_units def enterRule(self, listener): if hasattr(listener, "enterUnits"): listener.enterUnits(self) def exitRule(self, listener): if hasattr(listener, "exitUnits"): listener.exitUnits(self) def units(self): localctx = AutolevParser.UnitsContext(self, self._ctx, self.state) self.enterRule(localctx, 36, self.RULE_units) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 281 self.match(AutolevParser.UnitSystem) self.state = 282 self.match(AutolevParser.ID) self.state = 287 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 283 self.match(AutolevParser.T__9) self.state = 284 self.match(AutolevParser.ID) self.state = 289 self._errHandler.sync(self) _la = self._input.LA(1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class InputsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.InputsContext, self).__init__(parent, invokingState) self.parser = parser def Input(self): return self.getToken(AutolevParser.Input, 0) def inputs2(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.Inputs2Context) else: return self.getTypedRuleContext(AutolevParser.Inputs2Context,i) def getRuleIndex(self): return AutolevParser.RULE_inputs def enterRule(self, listener): if hasattr(listener, "enterInputs"): listener.enterInputs(self) def exitRule(self, listener): if hasattr(listener, "exitInputs"): listener.exitInputs(self) def inputs(self): localctx = AutolevParser.InputsContext(self, self._ctx, self.state) self.enterRule(localctx, 38, self.RULE_inputs) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 290 self.match(AutolevParser.Input) self.state = 291 self.inputs2() self.state = 296 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 292 self.match(AutolevParser.T__9) self.state = 293 self.inputs2() self.state = 298 self._errHandler.sync(self) _la = self._input.LA(1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Id_diffContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.Id_diffContext, self).__init__(parent, invokingState) self.parser = parser def ID(self): return self.getToken(AutolevParser.ID, 0) def diff(self): return self.getTypedRuleContext(AutolevParser.DiffContext,0) def getRuleIndex(self): return AutolevParser.RULE_id_diff def enterRule(self, listener): if hasattr(listener, "enterId_diff"): listener.enterId_diff(self) def exitRule(self, listener): if hasattr(listener, "exitId_diff"): listener.exitId_diff(self) def id_diff(self): localctx = AutolevParser.Id_diffContext(self, self._ctx, self.state) self.enterRule(localctx, 40, self.RULE_id_diff) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 299 self.match(AutolevParser.ID) self.state = 301 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.T__10: self.state = 300 self.diff() except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Inputs2Context(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.Inputs2Context, self).__init__(parent, invokingState) self.parser = parser def id_diff(self): return self.getTypedRuleContext(AutolevParser.Id_diffContext,0) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def getRuleIndex(self): return AutolevParser.RULE_inputs2 def enterRule(self, listener): if hasattr(listener, "enterInputs2"): listener.enterInputs2(self) def exitRule(self, listener): if hasattr(listener, "exitInputs2"): listener.exitInputs2(self) def inputs2(self): localctx = AutolevParser.Inputs2Context(self, self._ctx, self.state) self.enterRule(localctx, 42, self.RULE_inputs2) try: self.enterOuterAlt(localctx, 1) self.state = 303 self.id_diff() self.state = 304 self.match(AutolevParser.T__2) self.state = 305 self.expr(0) self.state = 307 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,34,self._ctx) if la_ == 1: self.state = 306 self.expr(0) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class OutputsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.OutputsContext, self).__init__(parent, invokingState) self.parser = parser def Output(self): return self.getToken(AutolevParser.Output, 0) def outputs2(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.Outputs2Context) else: return self.getTypedRuleContext(AutolevParser.Outputs2Context,i) def getRuleIndex(self): return AutolevParser.RULE_outputs def enterRule(self, listener): if hasattr(listener, "enterOutputs"): listener.enterOutputs(self) def exitRule(self, listener): if hasattr(listener, "exitOutputs"): listener.exitOutputs(self) def outputs(self): localctx = AutolevParser.OutputsContext(self, self._ctx, self.state) self.enterRule(localctx, 44, self.RULE_outputs) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 309 self.match(AutolevParser.Output) self.state = 310 self.outputs2() self.state = 315 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 311 self.match(AutolevParser.T__9) self.state = 312 self.outputs2() self.state = 317 self._errHandler.sync(self) _la = self._input.LA(1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Outputs2Context(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.Outputs2Context, self).__init__(parent, invokingState) self.parser = parser def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def getRuleIndex(self): return AutolevParser.RULE_outputs2 def enterRule(self, listener): if hasattr(listener, "enterOutputs2"): listener.enterOutputs2(self) def exitRule(self, listener): if hasattr(listener, "exitOutputs2"): listener.exitOutputs2(self) def outputs2(self): localctx = AutolevParser.Outputs2Context(self, self._ctx, self.state) self.enterRule(localctx, 46, self.RULE_outputs2) try: self.enterOuterAlt(localctx, 1) self.state = 318 self.expr(0) self.state = 320 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,36,self._ctx) if la_ == 1: self.state = 319 self.expr(0) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class CodegenContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.CodegenContext, self).__init__(parent, invokingState) self.parser = parser def ID(self, i=None): if i is None: return self.getTokens(AutolevParser.ID) else: return self.getToken(AutolevParser.ID, i) def functionCall(self): return self.getTypedRuleContext(AutolevParser.FunctionCallContext,0) def matrixInOutput(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.MatrixInOutputContext) else: return self.getTypedRuleContext(AutolevParser.MatrixInOutputContext,i) def getRuleIndex(self): return AutolevParser.RULE_codegen def enterRule(self, listener): if hasattr(listener, "enterCodegen"): listener.enterCodegen(self) def exitRule(self, listener): if hasattr(listener, "exitCodegen"): listener.exitCodegen(self) def codegen(self): localctx = AutolevParser.CodegenContext(self, self._ctx, self.state) self.enterRule(localctx, 48, self.RULE_codegen) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 322 self.match(AutolevParser.ID) self.state = 323 self.functionCall() self.state = 335 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.T__0: self.state = 324 self.match(AutolevParser.T__0) self.state = 325 self.matrixInOutput() self.state = 330 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 326 self.match(AutolevParser.T__9) self.state = 327 self.matrixInOutput() self.state = 332 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 333 self.match(AutolevParser.T__1) self.state = 337 self.match(AutolevParser.ID) self.state = 338 self.match(AutolevParser.T__19) self.state = 339 self.match(AutolevParser.ID) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class CommandsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.CommandsContext, self).__init__(parent, invokingState) self.parser = parser def Save(self): return self.getToken(AutolevParser.Save, 0) def ID(self, i=None): if i is None: return self.getTokens(AutolevParser.ID) else: return self.getToken(AutolevParser.ID, i) def Encode(self): return self.getToken(AutolevParser.Encode, 0) def getRuleIndex(self): return AutolevParser.RULE_commands def enterRule(self, listener): if hasattr(listener, "enterCommands"): listener.enterCommands(self) def exitRule(self, listener): if hasattr(listener, "exitCommands"): listener.exitCommands(self) def commands(self): localctx = AutolevParser.CommandsContext(self, self._ctx, self.state) self.enterRule(localctx, 50, self.RULE_commands) self._la = 0 # Token type try: self.state = 354 self._errHandler.sync(self) token = self._input.LA(1) if token in [AutolevParser.Save]: self.enterOuterAlt(localctx, 1) self.state = 341 self.match(AutolevParser.Save) self.state = 342 self.match(AutolevParser.ID) self.state = 343 self.match(AutolevParser.T__19) self.state = 344 self.match(AutolevParser.ID) pass elif token in [AutolevParser.Encode]: self.enterOuterAlt(localctx, 2) self.state = 345 self.match(AutolevParser.Encode) self.state = 346 self.match(AutolevParser.ID) self.state = 351 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 347 self.match(AutolevParser.T__9) self.state = 348 self.match(AutolevParser.ID) self.state = 353 self._errHandler.sync(self) _la = self._input.LA(1) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class VecContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.VecContext, self).__init__(parent, invokingState) self.parser = parser def ID(self): return self.getToken(AutolevParser.ID, 0) def getRuleIndex(self): return AutolevParser.RULE_vec def enterRule(self, listener): if hasattr(listener, "enterVec"): listener.enterVec(self) def exitRule(self, listener): if hasattr(listener, "exitVec"): listener.exitVec(self) def vec(self): localctx = AutolevParser.VecContext(self, self._ctx, self.state) self.enterRule(localctx, 52, self.RULE_vec) try: self.state = 364 self._errHandler.sync(self) token = self._input.LA(1) if token in [AutolevParser.ID]: self.enterOuterAlt(localctx, 1) self.state = 356 self.match(AutolevParser.ID) self.state = 358 self._errHandler.sync(self) _alt = 1 while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt == 1: self.state = 357 self.match(AutolevParser.T__20) else: raise NoViableAltException(self) self.state = 360 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,41,self._ctx) pass elif token in [AutolevParser.T__21]: self.enterOuterAlt(localctx, 2) self.state = 362 self.match(AutolevParser.T__21) pass elif token in [AutolevParser.T__22]: self.enterOuterAlt(localctx, 3) self.state = 363 self.match(AutolevParser.T__22) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class ExprContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(AutolevParser.ExprContext, self).__init__(parent, invokingState) self.parser = parser def getRuleIndex(self): return AutolevParser.RULE_expr def copyFrom(self, ctx): super(AutolevParser.ExprContext, self).copyFrom(ctx) class ParensContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.ParensContext, self).__init__(parser) self.copyFrom(ctx) def expr(self): return self.getTypedRuleContext(AutolevParser.ExprContext,0) def enterRule(self, listener): if hasattr(listener, "enterParens"): listener.enterParens(self) def exitRule(self, listener): if hasattr(listener, "exitParens"): listener.exitParens(self) class VectorOrDyadicContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.VectorOrDyadicContext, self).__init__(parser) self.copyFrom(ctx) def vec(self): return self.getTypedRuleContext(AutolevParser.VecContext,0) def enterRule(self, listener): if hasattr(listener, "enterVectorOrDyadic"): listener.enterVectorOrDyadic(self) def exitRule(self, listener): if hasattr(listener, "exitVectorOrDyadic"): listener.exitVectorOrDyadic(self) class ExponentContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.ExponentContext, self).__init__(parser) self.copyFrom(ctx) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def enterRule(self, listener): if hasattr(listener, "enterExponent"): listener.enterExponent(self) def exitRule(self, listener): if hasattr(listener, "exitExponent"): listener.exitExponent(self) class MulDivContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.MulDivContext, self).__init__(parser) self.copyFrom(ctx) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def enterRule(self, listener): if hasattr(listener, "enterMulDiv"): listener.enterMulDiv(self) def exitRule(self, listener): if hasattr(listener, "exitMulDiv"): listener.exitMulDiv(self) class AddSubContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.AddSubContext, self).__init__(parser) self.copyFrom(ctx) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def enterRule(self, listener): if hasattr(listener, "enterAddSub"): listener.enterAddSub(self) def exitRule(self, listener): if hasattr(listener, "exitAddSub"): listener.exitAddSub(self) class FloatContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.FloatContext, self).__init__(parser) self.copyFrom(ctx) def FLOAT(self): return self.getToken(AutolevParser.FLOAT, 0) def enterRule(self, listener): if hasattr(listener, "enterFloat"): listener.enterFloat(self) def exitRule(self, listener): if hasattr(listener, "exitFloat"): listener.exitFloat(self) class IntContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.IntContext, self).__init__(parser) self.copyFrom(ctx) def INT(self): return self.getToken(AutolevParser.INT, 0) def enterRule(self, listener): if hasattr(listener, "enterInt"): listener.enterInt(self) def exitRule(self, listener): if hasattr(listener, "exitInt"): listener.exitInt(self) class IdEqualsExprContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.IdEqualsExprContext, self).__init__(parser) self.copyFrom(ctx) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def enterRule(self, listener): if hasattr(listener, "enterIdEqualsExpr"): listener.enterIdEqualsExpr(self) def exitRule(self, listener): if hasattr(listener, "exitIdEqualsExpr"): listener.exitIdEqualsExpr(self) class NegativeOneContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.NegativeOneContext, self).__init__(parser) self.copyFrom(ctx) def expr(self): return self.getTypedRuleContext(AutolevParser.ExprContext,0) def enterRule(self, listener): if hasattr(listener, "enterNegativeOne"): listener.enterNegativeOne(self) def exitRule(self, listener): if hasattr(listener, "exitNegativeOne"): listener.exitNegativeOne(self) class FunctionContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.FunctionContext, self).__init__(parser) self.copyFrom(ctx) def functionCall(self): return self.getTypedRuleContext(AutolevParser.FunctionCallContext,0) def enterRule(self, listener): if hasattr(listener, "enterFunction"): listener.enterFunction(self) def exitRule(self, listener): if hasattr(listener, "exitFunction"): listener.exitFunction(self) class RangessContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.RangessContext, self).__init__(parser) self.copyFrom(ctx) def ranges(self): return self.getTypedRuleContext(AutolevParser.RangesContext,0) def ID(self): return self.getToken(AutolevParser.ID, 0) def enterRule(self, listener): if hasattr(listener, "enterRangess"): listener.enterRangess(self) def exitRule(self, listener): if hasattr(listener, "exitRangess"): listener.exitRangess(self) class ColonContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.ColonContext, self).__init__(parser) self.copyFrom(ctx) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def enterRule(self, listener): if hasattr(listener, "enterColon"): listener.enterColon(self) def exitRule(self, listener): if hasattr(listener, "exitColon"): listener.exitColon(self) class IdContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.IdContext, self).__init__(parser) self.copyFrom(ctx) def ID(self): return self.getToken(AutolevParser.ID, 0) def enterRule(self, listener): if hasattr(listener, "enterId"): listener.enterId(self) def exitRule(self, listener): if hasattr(listener, "exitId"): listener.exitId(self) class ExpContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.ExpContext, self).__init__(parser) self.copyFrom(ctx) def EXP(self): return self.getToken(AutolevParser.EXP, 0) def enterRule(self, listener): if hasattr(listener, "enterExp"): listener.enterExp(self) def exitRule(self, listener): if hasattr(listener, "exitExp"): listener.exitExp(self) class MatricesContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.MatricesContext, self).__init__(parser) self.copyFrom(ctx) def matrix(self): return self.getTypedRuleContext(AutolevParser.MatrixContext,0) def enterRule(self, listener): if hasattr(listener, "enterMatrices"): listener.enterMatrices(self) def exitRule(self, listener): if hasattr(listener, "exitMatrices"): listener.exitMatrices(self) class IndexingContext(ExprContext): def __init__(self, parser, ctx): # actually a AutolevParser.ExprContext) super(AutolevParser.IndexingContext, self).__init__(parser) self.copyFrom(ctx) def ID(self): return self.getToken(AutolevParser.ID, 0) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(AutolevParser.ExprContext) else: return self.getTypedRuleContext(AutolevParser.ExprContext,i) def enterRule(self, listener): if hasattr(listener, "enterIndexing"): listener.enterIndexing(self) def exitRule(self, listener): if hasattr(listener, "exitIndexing"): listener.exitIndexing(self) def expr(self, _p=0): _parentctx = self._ctx _parentState = self.state localctx = AutolevParser.ExprContext(self, self._ctx, _parentState) _prevctx = localctx _startState = 54 self.enterRecursionRule(localctx, 54, self.RULE_expr, _p) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 408 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,47,self._ctx) if la_ == 1: localctx = AutolevParser.ExpContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 367 self.match(AutolevParser.EXP) pass elif la_ == 2: localctx = AutolevParser.NegativeOneContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 368 self.match(AutolevParser.T__17) self.state = 369 self.expr(12) pass elif la_ == 3: localctx = AutolevParser.FloatContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 370 self.match(AutolevParser.FLOAT) pass elif la_ == 4: localctx = AutolevParser.IntContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 371 self.match(AutolevParser.INT) pass elif la_ == 5: localctx = AutolevParser.IdContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 372 self.match(AutolevParser.ID) self.state = 376 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,43,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: self.state = 373 self.match(AutolevParser.T__10) self.state = 378 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,43,self._ctx) pass elif la_ == 6: localctx = AutolevParser.VectorOrDyadicContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 379 self.vec() pass elif la_ == 7: localctx = AutolevParser.IndexingContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 380 self.match(AutolevParser.ID) self.state = 381 self.match(AutolevParser.T__0) self.state = 382 self.expr(0) self.state = 387 self._errHandler.sync(self) _la = self._input.LA(1) while _la==AutolevParser.T__9: self.state = 383 self.match(AutolevParser.T__9) self.state = 384 self.expr(0) self.state = 389 self._errHandler.sync(self) _la = self._input.LA(1) self.state = 390 self.match(AutolevParser.T__1) pass elif la_ == 8: localctx = AutolevParser.FunctionContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 392 self.functionCall() pass elif la_ == 9: localctx = AutolevParser.MatricesContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 393 self.matrix() pass elif la_ == 10: localctx = AutolevParser.ParensContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 394 self.match(AutolevParser.T__11) self.state = 395 self.expr(0) self.state = 396 self.match(AutolevParser.T__12) pass elif la_ == 11: localctx = AutolevParser.RangessContext(self, localctx) self._ctx = localctx _prevctx = localctx self.state = 399 self._errHandler.sync(self) _la = self._input.LA(1) if _la==AutolevParser.ID: self.state = 398 self.match(AutolevParser.ID) self.state = 401 self.ranges() self.state = 405 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,46,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: self.state = 402 self.match(AutolevParser.T__10) self.state = 407 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,46,self._ctx) pass self._ctx.stop = self._input.LT(-1) self.state = 427 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,49,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx self.state = 425 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,48,self._ctx) if la_ == 1: localctx = AutolevParser.ExponentContext(self, AutolevParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 410 if not self.precpred(self._ctx, 16): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 16)") self.state = 411 self.match(AutolevParser.T__23) self.state = 412 self.expr(17) pass elif la_ == 2: localctx = AutolevParser.MulDivContext(self, AutolevParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 413 if not self.precpred(self._ctx, 15): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 15)") self.state = 414 _la = self._input.LA(1) if not(_la==AutolevParser.T__24 or _la==AutolevParser.T__25): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 415 self.expr(16) pass elif la_ == 3: localctx = AutolevParser.AddSubContext(self, AutolevParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 416 if not self.precpred(self._ctx, 14): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 14)") self.state = 417 _la = self._input.LA(1) if not(_la==AutolevParser.T__16 or _la==AutolevParser.T__17): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 418 self.expr(15) pass elif la_ == 4: localctx = AutolevParser.IdEqualsExprContext(self, AutolevParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 419 if not self.precpred(self._ctx, 3): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 3)") self.state = 420 self.match(AutolevParser.T__2) self.state = 421 self.expr(4) pass elif la_ == 5: localctx = AutolevParser.ColonContext(self, AutolevParser.ExprContext(self, _parentctx, _parentState)) self.pushNewRecursionContext(localctx, _startState, self.RULE_expr) self.state = 422 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") self.state = 423 self.match(AutolevParser.T__15) self.state = 424 self.expr(3) pass self.state = 429 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,49,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.unrollRecursionContexts(_parentctx) return localctx def sempred(self, localctx, ruleIndex, predIndex): if self._predicates == None: self._predicates = dict() self._predicates[27] = self.expr_sempred pred = self._predicates.get(ruleIndex, None) if pred is None: raise Exception("No predicate with index:" + str(ruleIndex)) else: return pred(localctx, predIndex) def expr_sempred(self, localctx, predIndex): if predIndex == 0: return self.precpred(self._ctx, 16) if predIndex == 1: return self.precpred(self._ctx, 15) if predIndex == 2: return self.precpred(self._ctx, 14) if predIndex == 3: return self.precpred(self._ctx, 3) if predIndex == 4: return self.precpred(self._ctx, 2) sympy-sympy-1.9/sympy/parsing/autolev/_listener_autolev_antlr.py000066400000000000000000003144661412543434000255410ustar00rootroot00000000000000import collections import warnings from sympy.external import import_module autolevparser = import_module('sympy.parsing.autolev._antlr.autolevparser', import_kwargs={'fromlist': ['AutolevParser']}) autolevlexer = import_module('sympy.parsing.autolev._antlr.autolevlexer', import_kwargs={'fromlist': ['AutolevLexer']}) autolevlistener = import_module('sympy.parsing.autolev._antlr.autolevlistener', import_kwargs={'fromlist': ['AutolevListener']}) AutolevParser = getattr(autolevparser, 'AutolevParser', None) AutolevLexer = getattr(autolevlexer, 'AutolevLexer', None) AutolevListener = getattr(autolevlistener, 'AutolevListener', None) def strfunc(z): if z == 0: return "" elif z == 1: return "_d" else: return "_" + "d" * z def declare_phy_entities(self, ctx, phy_type, i, j=None): if phy_type in ("frame", "newtonian"): declare_frames(self, ctx, i, j) elif phy_type == "particle": declare_particles(self, ctx, i, j) elif phy_type == "point": declare_points(self, ctx, i, j) elif phy_type == "bodies": declare_bodies(self, ctx, i, j) def declare_frames(self, ctx, i, j=None): if "{" in ctx.getText(): if j: name1 = ctx.ID().getText().lower() + str(i) + str(j) else: name1 = ctx.ID().getText().lower() + str(i) else: name1 = ctx.ID().getText().lower() name2 = "frame_" + name1 if self.getValue(ctx.parentCtx.varType()) == "newtonian": self.newtonian = name2 self.symbol_table2.update({name1: name2}) self.symbol_table.update({name1 + "1>": name2 + ".x"}) self.symbol_table.update({name1 + "2>": name2 + ".y"}) self.symbol_table.update({name1 + "3>": name2 + ".z"}) self.type2.update({name1: "frame"}) self.write(name2 + " = " + "_me.ReferenceFrame('" + name1 + "')\n") def declare_points(self, ctx, i, j=None): if "{" in ctx.getText(): if j: name1 = ctx.ID().getText().lower() + str(i) + str(j) else: name1 = ctx.ID().getText().lower() + str(i) else: name1 = ctx.ID().getText().lower() name2 = "point_" + name1 self.symbol_table2.update({name1: name2}) self.type2.update({name1: "point"}) self.write(name2 + " = " + "_me.Point('" + name1 + "')\n") def declare_particles(self, ctx, i, j=None): if "{" in ctx.getText(): if j: name1 = ctx.ID().getText().lower() + str(i) + str(j) else: name1 = ctx.ID().getText().lower() + str(i) else: name1 = ctx.ID().getText().lower() name2 = "particle_" + name1 self.symbol_table2.update({name1: name2}) self.type2.update({name1: "particle"}) self.bodies.update({name1: name2}) self.write(name2 + " = " + "_me.Particle('" + name1 + "', " + "_me.Point('" + name1 + "_pt" + "'), " + "_sm.Symbol('m'))\n") def declare_bodies(self, ctx, i, j=None): if "{" in ctx.getText(): if j: name1 = ctx.ID().getText().lower() + str(i) + str(j) else: name1 = ctx.ID().getText().lower() + str(i) else: name1 = ctx.ID().getText().lower() name2 = "body_" + name1 self.bodies.update({name1: name2}) masscenter = name2 + "_cm" refFrame = name2 + "_f" self.symbol_table2.update({name1: name2}) self.symbol_table2.update({name1 + "o": masscenter}) self.symbol_table.update({name1 + "1>": refFrame+".x"}) self.symbol_table.update({name1 + "2>": refFrame+".y"}) self.symbol_table.update({name1 + "3>": refFrame+".z"}) self.type2.update({name1: "bodies"}) self.type2.update({name1+"o": "point"}) self.write(masscenter + " = " + "_me.Point('" + name1 + "_cm" + "')\n") if self.newtonian: self.write(masscenter + ".set_vel(" + self.newtonian + ", " + "0)\n") self.write(refFrame + " = " + "_me.ReferenceFrame('" + name1 + "_f" + "')\n") # We set a dummy mass and inertia here. # They will be reset using the setters later in the code anyway. self.write(name2 + " = " + "_me.RigidBody('" + name1 + "', " + masscenter + ", " + refFrame + ", " + "_sm.symbols('m'), (_me.outer(" + refFrame + ".x," + refFrame + ".x)," + masscenter + "))\n") def inertia_func(self, v1, v2, l, frame): if self.type2[v1] == "particle": l.append("_me.inertia_of_point_mass(" + self.bodies[v1] + ".mass, " + self.bodies[v1] + ".point.pos_from(" + self.symbol_table2[v2] + "), " + frame + ")") elif self.type2[v1] == "bodies": # Inertia has been defined about center of mass. if self.inertia_point[v1] == v1 + "o": # Asking point is cm as well if v2 == self.inertia_point[v1]: l.append(self.symbol_table2[v1] + ".inertia[0]") # Asking point is not cm else: l.append(self.bodies[v1] + ".inertia[0]" + " + " + "_me.inertia_of_point_mass(" + self.bodies[v1] + ".mass, " + self.bodies[v1] + ".masscenter" + ".pos_from(" + self.symbol_table2[v2] + "), " + frame + ")") # Inertia has been defined about another point else: # Asking point is the defined point if v2 == self.inertia_point[v1]: l.append(self.symbol_table2[v1] + ".inertia[0]") # Asking point is cm elif v2 == v1 + "o": l.append(self.bodies[v1] + ".inertia[0]" + " - " + "_me.inertia_of_point_mass(" + self.bodies[v1] + ".mass, " + self.bodies[v1] + ".masscenter" + ".pos_from(" + self.symbol_table2[self.inertia_point[v1]] + "), " + frame + ")") # Asking point is some other point else: l.append(self.bodies[v1] + ".inertia[0]" + " - " + "_me.inertia_of_point_mass(" + self.bodies[v1] + ".mass, " + self.bodies[v1] + ".masscenter" + ".pos_from(" + self.symbol_table2[self.inertia_point[v1]] + "), " + frame + ")" + " + " + "_me.inertia_of_point_mass(" + self.bodies[v1] + ".mass, " + self.bodies[v1] + ".masscenter" + ".pos_from(" + self.symbol_table2[v2] + "), " + frame + ")") def processConstants(self, ctx): # Process constant declarations of the type: Constants F = 3, g = 9.81 name = ctx.ID().getText().lower() if "=" in ctx.getText(): self.symbol_table.update({name: name}) # self.inputs.update({self.symbol_table[name]: self.getValue(ctx.getChild(2))}) self.write(self.symbol_table[name] + " = " + "_sm.S(" + self.getValue(ctx.getChild(2)) + ")\n") self.type.update({name: "constants"}) return # Constants declarations of the type: Constants A, B else: if "{" not in ctx.getText(): self.symbol_table[name] = name self.type[name] = "constants" # Process constant declarations of the type: Constants C+, D- if ctx.getChildCount() == 2: # This is set for declaring nonpositive=True and nonnegative=True if ctx.getChild(1).getText() == "+": self.sign[name] = "+" elif ctx.getChild(1).getText() == "-": self.sign[name] = "-" else: if "{" not in ctx.getText(): self.sign[name] = "o" # Process constant declarations of the type: Constants K{4}, a{1:2, 1:2}, b{1:2} if "{" in ctx.getText(): if ":" in ctx.getText(): num1 = int(ctx.INT(0).getText()) num2 = int(ctx.INT(1).getText()) + 1 else: num1 = 1 num2 = int(ctx.INT(0).getText()) + 1 if ":" in ctx.getText(): if "," in ctx.getText(): num3 = int(ctx.INT(2).getText()) num4 = int(ctx.INT(3).getText()) + 1 for i in range(num1, num2): for j in range(num3, num4): self.symbol_table[name + str(i) + str(j)] = name + str(i) + str(j) self.type[name + str(i) + str(j)] = "constants" self.var_list.append(name + str(i) + str(j)) self.sign[name + str(i) + str(j)] = "o" else: for i in range(num1, num2): self.symbol_table[name + str(i)] = name + str(i) self.type[name + str(i)] = "constants" self.var_list.append(name + str(i)) self.sign[name + str(i)] = "o" elif "," in ctx.getText(): for i in range(1, int(ctx.INT(0).getText()) + 1): for j in range(1, int(ctx.INT(1).getText()) + 1): self.symbol_table[name] = name + str(i) + str(j) self.type[name + str(i) + str(j)] = "constants" self.var_list.append(name + str(i) + str(j)) self.sign[name + str(i) + str(j)] = "o" else: for i in range(num1, num2): self.symbol_table[name + str(i)] = name + str(i) self.type[name + str(i)] = "constants" self.var_list.append(name + str(i)) self.sign[name + str(i)] = "o" if "{" not in ctx.getText(): self.var_list.append(name) def writeConstants(self, ctx): l1 = list(filter(lambda x: self.sign[x] == "o", self.var_list)) l2 = list(filter(lambda x: self.sign[x] == "+", self.var_list)) l3 = list(filter(lambda x: self.sign[x] == "-", self.var_list)) try: if self.settings["complex"] == "on": real = ", real=True" elif self.settings["complex"] == "off": real = "" except Exception: real = ", real=True" if l1: a = ", ".join(l1) + " = " + "_sm.symbols(" + "'" +\ " ".join(l1) + "'" + real + ")\n" self.write(a) if l2: a = ", ".join(l2) + " = " + "_sm.symbols(" + "'" +\ " ".join(l2) + "'" + real + ", nonnegative=True)\n" self.write(a) if l3: a = ", ".join(l3) + " = " + "_sm.symbols(" + "'" + \ " ".join(l3) + "'" + real + ", nonpositive=True)\n" self.write(a) self.var_list = [] def processVariables(self, ctx): # Specified F = x*N1> + y*N2> name = ctx.ID().getText().lower() if "=" in ctx.getText(): text = name + "'"*(ctx.getChildCount()-3) self.write(text + " = " + self.getValue(ctx.expr()) + "\n") return # Process variables of the type: Variables qA, qB if ctx.getChildCount() == 1: self.symbol_table[name] = name if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"): self.type.update({name: self.getValue(ctx.parentCtx.getChild(0))}) self.var_list.append(name) self.sign[name] = 0 # Process variables of the type: Variables x', y'' elif "'" in ctx.getText() and "{" not in ctx.getText(): if ctx.getText().count("'") > self.maxDegree: self.maxDegree = ctx.getText().count("'") for i in range(ctx.getChildCount()): self.sign[name + strfunc(i)] = i self.symbol_table[name + "'"*i] = name + strfunc(i) if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"): self.type.update({name + "'"*i: self.getValue(ctx.parentCtx.getChild(0))}) self.var_list.append(name + strfunc(i)) elif "{" in ctx.getText(): # Process variables of the type: Variales x{3}, y{2} if "'" in ctx.getText(): dash_count = ctx.getText().count("'") if dash_count > self.maxDegree: self.maxDegree = dash_count if ":" in ctx.getText(): # Variables C{1:2, 1:2} if "," in ctx.getText(): num1 = int(ctx.INT(0).getText()) num2 = int(ctx.INT(1).getText()) + 1 num3 = int(ctx.INT(2).getText()) num4 = int(ctx.INT(3).getText()) + 1 # Variables C{1:2} else: num1 = int(ctx.INT(0).getText()) num2 = int(ctx.INT(1).getText()) + 1 # Variables C{1,3} elif "," in ctx.getText(): num1 = 1 num2 = int(ctx.INT(0).getText()) + 1 num3 = 1 num4 = int(ctx.INT(1).getText()) + 1 else: num1 = 1 num2 = int(ctx.INT(0).getText()) + 1 for i in range(num1, num2): try: for j in range(num3, num4): try: for z in range(dash_count+1): self.symbol_table.update({name + str(i) + str(j) + "'"*z: name + str(i) + str(j) + strfunc(z)}) if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"): self.type.update({name + str(i) + str(j) + "'"*z: self.getValue(ctx.parentCtx.getChild(0))}) self.var_list.append(name + str(i) + str(j) + strfunc(z)) self.sign.update({name + str(i) + str(j) + strfunc(z): z}) if dash_count > self.maxDegree: self.maxDegree = dash_count except Exception: self.symbol_table.update({name + str(i) + str(j): name + str(i) + str(j)}) if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"): self.type.update({name + str(i) + str(j): self.getValue(ctx.parentCtx.getChild(0))}) self.var_list.append(name + str(i) + str(j)) self.sign.update({name + str(i) + str(j): 0}) except Exception: try: for z in range(dash_count+1): self.symbol_table.update({name + str(i) + "'"*z: name + str(i) + strfunc(z)}) if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"): self.type.update({name + str(i) + "'"*z: self.getValue(ctx.parentCtx.getChild(0))}) self.var_list.append(name + str(i) + strfunc(z)) self.sign.update({name + str(i) + strfunc(z): z}) if dash_count > self.maxDegree: self.maxDegree = dash_count except Exception: self.symbol_table.update({name + str(i): name + str(i)}) if self.getValue(ctx.parentCtx.getChild(0)) in ("variable", "specified", "motionvariable", "motionvariable'"): self.type.update({name + str(i): self.getValue(ctx.parentCtx.getChild(0))}) self.var_list.append(name + str(i)) self.sign.update({name + str(i): 0}) def writeVariables(self, ctx): #print(self.sign) #print(self.symbol_table) if self.var_list: for i in range(self.maxDegree+1): if i == 0: j = "" t = "" else: j = str(i) t = ", " l = [] for k in list(filter(lambda x: self.sign[x] == i, self.var_list)): if i == 0: l.append(k) if i == 1: l.append(k[:-1]) if i > 1: l.append(k[:-2]) a = ", ".join(list(filter(lambda x: self.sign[x] == i, self.var_list))) + " = " +\ "_me.dynamicsymbols(" + "'" + " ".join(l) + "'" + t + j + ")\n" l = [] self.write(a) self.maxDegree = 0 self.var_list = [] def processImaginary(self, ctx): name = ctx.ID().getText().lower() self.symbol_table[name] = name self.type[name] = "imaginary" self.var_list.append(name) def writeImaginary(self, ctx): a = ", ".join(self.var_list) + " = " + "_sm.symbols(" + "'" + \ " ".join(self.var_list) + "')\n" b = ", ".join(self.var_list) + " = " + "_sm.I\n" self.write(a) self.write(b) self.var_list = [] if AutolevListener: class MyListener(AutolevListener): # type: ignore def __init__(self, include_numeric=False): # Stores data in tree nodes(tree annotation). Especially useful for expr reconstruction. self.tree_property = {} # Stores the declared variables, constants etc as they are declared in Autolev and SymPy # {"": ""}. self.symbol_table = collections.OrderedDict() # Similar to symbol_table. Used for storing Physical entities like Frames, Points, # Particles, Bodies etc self.symbol_table2 = collections.OrderedDict() # Used to store nonpositive, nonnegative etc for constants and number of "'"s (order of diff) # in variables. self.sign = {} # Simple list used as a store to pass around variables between the 'process' and 'write' # methods. self.var_list = [] # Stores the type of a declared variable (constants, variables, specifieds etc) self.type = collections.OrderedDict() # Similar to self.type. Used for storing the type of Physical entities like Frames, Points, # Particles, Bodies etc self.type2 = collections.OrderedDict() # These lists are used to distinguish matrix, numeric and vector expressions. self.matrix_expr = [] self.numeric_expr = [] self.vector_expr = [] self.fr_expr = [] self.output_code = [] # Stores the variables and their rhs for substituting upon the Autolev command EXPLICIT. self.explicit = collections.OrderedDict() # Write code to import common dependencies. self.output_code.append("import sympy.physics.mechanics as _me\n") self.output_code.append("import sympy as _sm\n") self.output_code.append("import math as m\n") self.output_code.append("import numpy as _np\n") self.output_code.append("\n") # Just a store for the max degree variable in a line. self.maxDegree = 0 # Stores the input parameters which are then used for codegen and numerical analysis. self.inputs = collections.OrderedDict() # Stores the variables which appear in Output Autolev commands. self.outputs = [] # Stores the settings specified by the user. Ex: Complex on/off, Degrees on/off self.settings = {} # Boolean which changes the behaviour of some expression reconstruction # when parsing Input Autolev commands. self.in_inputs = False self.in_outputs = False # Stores for the physical entities. self.newtonian = None self.bodies = collections.OrderedDict() self.constants = [] self.forces = collections.OrderedDict() self.q_ind = [] self.q_dep = [] self.u_ind = [] self.u_dep = [] self.kd_eqs = [] self.dependent_variables = [] self.kd_equivalents = collections.OrderedDict() self.kd_equivalents2 = collections.OrderedDict() self.kd_eqs_supplied = None self.kane_type = "no_args" self.inertia_point = collections.OrderedDict() self.kane_parsed = False self.t = False # PyDy ode code will be included only if this flag is set to True. self.include_numeric = include_numeric def write(self, string): self.output_code.append(string) def getValue(self, node): return self.tree_property[node] def setValue(self, node, value): self.tree_property[node] = value def getSymbolTable(self): return self.symbol_table def getType(self): return self.type def exitVarDecl(self, ctx): # This event method handles variable declarations. The parse tree node varDecl contains # one or more varDecl2 nodes. Eg varDecl for 'Constants a{1:2, 1:2}, b{1:2}' has two varDecl2 # nodes(one for a{1:2, 1:2} and one for b{1:2}). # Variable declarations are processed and stored in the event method exitVarDecl2. # This stored information is used to write the final SymPy output code in the exitVarDecl event method. # determine the type of declaration if self.getValue(ctx.varType()) == "constant": writeConstants(self, ctx) elif self.getValue(ctx.varType()) in\ ("variable", "motionvariable", "motionvariable'", "specified"): writeVariables(self, ctx) elif self.getValue(ctx.varType()) == "imaginary": writeImaginary(self, ctx) def exitVarType(self, ctx): # Annotate the varType tree node with the type of the variable declaration. name = ctx.getChild(0).getText().lower() if name[-1] == "s" and name != "bodies": self.setValue(ctx, name[:-1]) else: self.setValue(ctx, name) def exitVarDecl2(self, ctx): # Variable declarations are processed and stored in the event method exitVarDecl2. # This stored information is used to write the final SymPy output code in the exitVarDecl event method. # This is the case for constants, variables, specifieds etc. # This isn't the case for all types of declarations though. For instance # Frames A, B, C, N cannot be defined on one line in SymPy. So we do not append A, B, C, N # to a var_list or use exitVarDecl. exitVarDecl2 directly writes out to the file. # determine the type of declaration if self.getValue(ctx.parentCtx.varType()) == "constant": processConstants(self, ctx) elif self.getValue(ctx.parentCtx.varType()) in \ ("variable", "motionvariable", "motionvariable'", "specified"): processVariables(self, ctx) elif self.getValue(ctx.parentCtx.varType()) == "imaginary": processImaginary(self, ctx) elif self.getValue(ctx.parentCtx.varType()) in ("frame", "newtonian", "point", "particle", "bodies"): if "{" in ctx.getText(): if ":" in ctx.getText() and "," not in ctx.getText(): num1 = int(ctx.INT(0).getText()) num2 = int(ctx.INT(1).getText()) + 1 elif ":" not in ctx.getText() and "," in ctx.getText(): num1 = 1 num2 = int(ctx.INT(0).getText()) + 1 num3 = 1 num4 = int(ctx.INT(1).getText()) + 1 elif ":" in ctx.getText() and "," in ctx.getText(): num1 = int(ctx.INT(0).getText()) num2 = int(ctx.INT(1).getText()) + 1 num3 = int(ctx.INT(2).getText()) num4 = int(ctx.INT(3).getText()) + 1 else: num1 = 1 num2 = int(ctx.INT(0).getText()) + 1 else: num1 = 1 num2 = 2 for i in range(num1, num2): try: for j in range(num3, num4): declare_phy_entities(self, ctx, self.getValue(ctx.parentCtx.varType()), i, j) except Exception: declare_phy_entities(self, ctx, self.getValue(ctx.parentCtx.varType()), i) # ================== Subrules of parser rule expr (Start) ====================== # def exitId(self, ctx): # Tree annotation for ID which is a labeled subrule of the parser rule expr. # A_C python_keywords = ["and", "as", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except",\ "exec", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "not", "or", "pass", "print",\ "raise", "return", "try", "while", "with", "yield"] if ctx.ID().getText().lower() in python_keywords: warnings.warn("Python keywords must not be used as identifiers. Please refer to the list of keywords at https://docs.python.org/2.5/ref/keywords.html", SyntaxWarning) if "_" in ctx.ID().getText() and ctx.ID().getText().count('_') == 1: e1, e2 = ctx.ID().getText().lower().split('_') try: if self.type2[e1] == "frame": e1 = self.symbol_table2[e1] elif self.type2[e1] == "bodies": e1 = self.symbol_table2[e1] + "_f" if self.type2[e2] == "frame": e2 = self.symbol_table2[e2] elif self.type2[e2] == "bodies": e2 = self.symbol_table2[e2] + "_f" self.setValue(ctx, e1 + ".dcm(" + e2 + ")") except Exception: self.setValue(ctx, ctx.ID().getText().lower()) else: # Reserved constant Pi if ctx.ID().getText().lower() == "pi": self.setValue(ctx, "_sm.pi") self.numeric_expr.append(ctx) # Reserved variable T (for time) elif ctx.ID().getText().lower() == "t": self.setValue(ctx, "_me.dynamicsymbols._t") if not self.in_inputs and not self.in_outputs: self.t = True else: idText = ctx.ID().getText().lower() + "'"*(ctx.getChildCount() - 1) if idText in self.type.keys() and self.type[idText] == "matrix": self.matrix_expr.append(ctx) if self.in_inputs: try: self.setValue(ctx, self.symbol_table[idText]) except Exception: self.setValue(ctx, idText.lower()) else: try: self.setValue(ctx, self.symbol_table[idText]) except Exception: pass def exitInt(self, ctx): # Tree annotation for int which is a labeled subrule of the parser rule expr. int_text = ctx.INT().getText() self.setValue(ctx, int_text) self.numeric_expr.append(ctx) def exitFloat(self, ctx): # Tree annotation for float which is a labeled subrule of the parser rule expr. floatText = ctx.FLOAT().getText() self.setValue(ctx, floatText) self.numeric_expr.append(ctx) def exitAddSub(self, ctx): # Tree annotation for AddSub which is a labeled subrule of the parser rule expr. # The subrule is expr = expr (+|-) expr if ctx.expr(0) in self.matrix_expr or ctx.expr(1) in self.matrix_expr: self.matrix_expr.append(ctx) if ctx.expr(0) in self.vector_expr or ctx.expr(1) in self.vector_expr: self.vector_expr.append(ctx) if ctx.expr(0) in self.numeric_expr and ctx.expr(1) in self.numeric_expr: self.numeric_expr.append(ctx) self.setValue(ctx, self.getValue(ctx.expr(0)) + ctx.getChild(1).getText() + self.getValue(ctx.expr(1))) def exitMulDiv(self, ctx): # Tree annotation for MulDiv which is a labeled subrule of the parser rule expr. # The subrule is expr = expr (*|/) expr try: if ctx.expr(0) in self.vector_expr and ctx.expr(1) in self.vector_expr: self.setValue(ctx, "_me.outer(" + self.getValue(ctx.expr(0)) + ", " + self.getValue(ctx.expr(1)) + ")") else: if ctx.expr(0) in self.matrix_expr or ctx.expr(1) in self.matrix_expr: self.matrix_expr.append(ctx) if ctx.expr(0) in self.vector_expr or ctx.expr(1) in self.vector_expr: self.vector_expr.append(ctx) if ctx.expr(0) in self.numeric_expr and ctx.expr(1) in self.numeric_expr: self.numeric_expr.append(ctx) self.setValue(ctx, self.getValue(ctx.expr(0)) + ctx.getChild(1).getText() + self.getValue(ctx.expr(1))) except Exception: pass def exitNegativeOne(self, ctx): # Tree annotation for negativeOne which is a labeled subrule of the parser rule expr. self.setValue(ctx, "-1*" + self.getValue(ctx.getChild(1))) if ctx.getChild(1) in self.matrix_expr: self.matrix_expr.append(ctx) if ctx.getChild(1) in self.numeric_expr: self.numeric_expr.append(ctx) def exitParens(self, ctx): # Tree annotation for parens which is a labeled subrule of the parser rule expr. # The subrule is expr = '(' expr ')' if ctx.expr() in self.matrix_expr: self.matrix_expr.append(ctx) if ctx.expr() in self.vector_expr: self.vector_expr.append(ctx) if ctx.expr() in self.numeric_expr: self.numeric_expr.append(ctx) self.setValue(ctx, "(" + self.getValue(ctx.expr()) + ")") def exitExponent(self, ctx): # Tree annotation for Exponent which is a labeled subrule of the parser rule expr. # The subrule is expr = expr ^ expr if ctx.expr(0) in self.matrix_expr or ctx.expr(1) in self.matrix_expr: self.matrix_expr.append(ctx) if ctx.expr(0) in self.vector_expr or ctx.expr(1) in self.vector_expr: self.vector_expr.append(ctx) if ctx.expr(0) in self.numeric_expr and ctx.expr(1) in self.numeric_expr: self.numeric_expr.append(ctx) self.setValue(ctx, self.getValue(ctx.expr(0)) + "**" + self.getValue(ctx.expr(1))) def exitExp(self, ctx): s = ctx.EXP().getText()[ctx.EXP().getText().index('E')+1:] if "-" in s: s = s[0] + s[1:].lstrip("0") else: s = s.lstrip("0") self.setValue(ctx, ctx.EXP().getText()[:ctx.EXP().getText().index('E')] + "*10**(" + s + ")") def exitFunction(self, ctx): # Tree annotation for function which is a labeled subrule of the parser rule expr. # The difference between this and FunctionCall is that this is used for non standalone functions # appearing in expressions and assignments. # Eg: # When we come across a standalone function say Expand(E, n:m) then it is categorized as FunctionCall # which is a parser rule in itself under rule stat. exitFunctionCall() takes care of it and writes to the file. # # On the other hand, while we come across E_diff = D(E, y), we annotate the tree node # of the function D(E, y) with the SymPy equivalent in exitFunction(). # In this case it is the method exitAssignment() that writes the code to the file and not exitFunction(). ch = ctx.getChild(0) func_name = ch.getChild(0).getText().lower() # Expand(y, n:m) * if func_name == "expand": expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) # _sm.Matrix([i.expand() for i in z]).reshape(z.shape[0], z.shape[1]) self.setValue(ctx, "_sm.Matrix([i.expand() for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: self.setValue(ctx, "(" + expr + ")" + "." + "expand()") # Factor(y, x) * elif func_name == "factor": expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) self.setValue(ctx, "_sm.Matrix([_sm.factor(i, " + self.getValue(ch.expr(1)) + ") for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: self.setValue(ctx, "_sm.factor(" + "(" + expr + ")" + ", " + self.getValue(ch.expr(1)) + ")") # D(y, x) elif func_name == "d": expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) self.setValue(ctx, "_sm.Matrix([i.diff(" + self.getValue(ch.expr(1)) + ") for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: if ch.getChildCount() == 8: frame = self.symbol_table2[ch.expr(2).getText().lower()] self.setValue(ctx, "(" + expr + ")" + "." + "diff(" + self.getValue(ch.expr(1)) + ", " + frame + ")") else: self.setValue(ctx, "(" + expr + ")" + "." + "diff(" + self.getValue(ch.expr(1)) + ")") # Dt(y) elif func_name == "dt": expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.vector_expr: text = "dt(" else: text = "diff(_sm.Symbol('t')" if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) self.setValue(ctx, "_sm.Matrix([i." + text + ") for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: if ch.getChildCount() == 6: frame = self.symbol_table2[ch.expr(1).getText().lower()] self.setValue(ctx, "(" + expr + ")" + "." + "dt(" + frame + ")") else: self.setValue(ctx, "(" + expr + ")" + "." + text + ")") # Explicit(EXPRESS(IMPLICIT>,C)) elif func_name == "explicit": if ch.expr(0) in self.vector_expr: self.vector_expr.append(ctx) expr = self.getValue(ch.expr(0)) if self.explicit.keys(): explicit_list = [] for i in self.explicit.keys(): explicit_list.append(i + ":" + self.explicit[i]) self.setValue(ctx, "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "})") else: self.setValue(ctx, expr) # Taylor(y, 0:2, w=a, x=0) # TODO: Currently only works with symbols. Make it work for dynamicsymbols. elif func_name == "taylor": exp = self.getValue(ch.expr(0)) order = self.getValue(ch.expr(1).expr(1)) x = (ch.getChildCount()-6)//2 l = [] for i in range(x): index = 2 + i child = ch.expr(index) l.append(".series(" + self.getValue(child.getChild(0)) + ", " + self.getValue(child.getChild(2)) + ", " + order + ").removeO()") self.setValue(ctx, "(" + exp + ")" + "".join(l)) # Evaluate(y, a=x, b=2) elif func_name == "evaluate": expr = self.getValue(ch.expr(0)) l = [] x = (ch.getChildCount()-4)//2 for i in range(x): index = 1 + i child = ch.expr(index) l.append(self.getValue(child.getChild(0)) + ":" + self.getValue(child.getChild(2))) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) self.setValue(ctx, "_sm.Matrix([i.subs({" + ",".join(l) + "}) for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: if self.explicit: explicit_list = [] for i in self.explicit.keys(): explicit_list.append(i + ":" + self.explicit[i]) self.setValue(ctx, "(" + expr + ")" + ".subs({" + ",".join(explicit_list) + "}).subs({" + ",".join(l) + "})") else: self.setValue(ctx, "(" + expr + ")" + ".subs({" + ",".join(l) + "})") # Polynomial([a, b, c], x) elif func_name == "polynomial": self.setValue(ctx, "_sm.Poly(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1)) + ")") # Roots(Poly, x, 2) # Roots([1; 2; 3; 4]) elif func_name == "roots": self.matrix_expr.append(ctx) expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.setValue(ctx, "[i.evalf() for i in " + "_sm.solve(" + "_sm.Poly(" + expr + ", " + "x),x)]") else: self.setValue(ctx, "[i.evalf() for i in " + "_sm.solve(" + expr + ", " + self.getValue(ch.expr(1)) + ")]") # Transpose(A), Inv(A) elif func_name in ("transpose", "inv", "inverse"): self.matrix_expr.append(ctx) if func_name == "transpose": e = ".T" elif func_name in ("inv", "inverse"): e = "**(-1)" self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + e) # Eig(A) elif func_name == "eig": # "_sm.Matrix([i.evalf() for i in " + self.setValue(ctx, "_sm.Matrix([i.evalf() for i in (" + self.getValue(ch.expr(0)) + ").eigenvals().keys()])") # Diagmat(n, m, x) # Diagmat(3, 1) elif func_name == "diagmat": self.matrix_expr.append(ctx) if ch.getChildCount() == 6: l = [] for i in range(int(self.getValue(ch.expr(0)))): l.append(self.getValue(ch.expr(1)) + ",") self.setValue(ctx, "_sm.diag(" + ("".join(l))[:-1] + ")") elif ch.getChildCount() == 8: # _sm.Matrix([x if i==j else 0 for i in range(n) for j in range(m)]).reshape(n, m) n = self.getValue(ch.expr(0)) m = self.getValue(ch.expr(1)) x = self.getValue(ch.expr(2)) self.setValue(ctx, "_sm.Matrix([" + x + " if i==j else 0 for i in range(" + n + ") for j in range(" + m + ")]).reshape(" + n + ", " + m + ")") # Cols(A) # Cols(A, 1) # Cols(A, 1, 2:4, 3) elif func_name in ("cols", "rows"): self.matrix_expr.append(ctx) if func_name == "cols": e1 = ".cols" e2 = ".T." else: e1 = ".rows" e2 = "." if ch.getChildCount() == 4: self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + e1) elif ch.getChildCount() == 6: self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + e1[:-1] + "(" + str(int(self.getValue(ch.expr(1))) - 1) + ")") else: l = [] for i in range(4, ch.getChildCount()): try: if ch.getChild(i).getChildCount() > 1 and ch.getChild(i).getChild(1).getText() == ":": for j in range(int(ch.getChild(i).getChild(0).getText()), int(ch.getChild(i).getChild(2).getText())+1): l.append("(" + self.getValue(ch.getChild(2)) + ")" + e2 + "row(" + str(j-1) + ")") else: l.append("(" + self.getValue(ch.getChild(2)) + ")" + e2 + "row(" + str(int(ch.getChild(i).getText())-1) + ")") except Exception: pass self.setValue(ctx, "_sm.Matrix([" + ",".join(l) + "])") # Det(A) Trace(A) elif func_name in ["det", "trace"]: self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + "." + func_name + "()") # Element(A, 2, 3) elif func_name == "element": self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + "[" + str(int(self.getValue(ch.expr(1)))-1) + "," + str(int(self.getValue(ch.expr(2)))-1) + "]") elif func_name in \ ["cos", "sin", "tan", "cosh", "sinh", "tanh", "acos", "asin", "atan", "log", "exp", "sqrt", "factorial", "floor", "sign"]: self.setValue(ctx, "_sm." + func_name + "(" + self.getValue(ch.expr(0)) + ")") elif func_name == "ceil": self.setValue(ctx, "_sm.ceiling" + "(" + self.getValue(ch.expr(0)) + ")") elif func_name == "sqr": self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + "**2") elif func_name == "log10": self.setValue(ctx, "_sm.log" + "(" + self.getValue(ch.expr(0)) + ", 10)") elif func_name == "atan2": self.setValue(ctx, "_sm.atan2" + "(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1)) + ")") elif func_name in ["int", "round"]: self.setValue(ctx, func_name + "(" + self.getValue(ch.expr(0)) + ")") elif func_name == "abs": self.setValue(ctx, "_sm.Abs(" + self.getValue(ch.expr(0)) + ")") elif func_name in ["max", "min"]: # max(x, y, z) l = [] for i in range(1, ch.getChildCount()): if ch.getChild(i) in self.tree_property.keys(): l.append(self.getValue(ch.getChild(i))) elif ch.getChild(i).getText() in [",", "(", ")"]: l.append(ch.getChild(i).getText()) self.setValue(ctx, "_sm." + ch.getChild(0).getText().capitalize() + "".join(l)) # Coef(y, x) elif func_name == "coef": #A41_A53=COEF([RHS(U4);RHS(U5)],[U1,U2,U3]) if ch.expr(0) in self.matrix_expr and ch.expr(1) in self.matrix_expr: icount = jcount = 0 for i in range(ch.expr(0).getChild(0).getChildCount()): try: ch.expr(0).getChild(0).getChild(i).getRuleIndex() icount+=1 except Exception: pass for j in range(ch.expr(1).getChild(0).getChildCount()): try: ch.expr(1).getChild(0).getChild(j).getRuleIndex() jcount+=1 except Exception: pass l = [] for i in range(icount): for j in range(jcount): # a41_a53[i,j] = u4.expand().coeff(u1) l.append(self.getValue(ch.expr(0).getChild(0).expr(i)) + ".expand().coeff(" + self.getValue(ch.expr(1).getChild(0).expr(j)) + ")") self.setValue(ctx, "_sm.Matrix([" + ", ".join(l) + "]).reshape(" + str(icount) + ", " + str(jcount) + ")") else: self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + ".expand().coeff(" + self.getValue(ch.expr(1)) + ")") # Exclude(y, x) Include(y, x) elif func_name in ("exclude", "include"): if func_name == "exclude": e = "0" else: e = "1" expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) self.setValue(ctx, "_sm.Matrix([i.collect(" + self.getValue(ch.expr(1)) + "])" + ".coeff(" + self.getValue(ch.expr(1)) + "," + e + ")" + "for i in " + expr + ")" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: self.setValue(ctx, "(" + expr + ")" + ".collect(" + self.getValue(ch.expr(1)) + ")" + ".coeff(" + self.getValue(ch.expr(1)) + "," + e + ")") # RHS(y) elif func_name == "rhs": self.setValue(ctx, self.explicit[self.getValue(ch.expr(0))]) # Arrange(y, n, x) * elif func_name == "arrange": expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) self.setValue(ctx, "_sm.Matrix([i.collect(" + self.getValue(ch.expr(2)) + ")" + "for i in " + expr + "])"+ ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: self.setValue(ctx, "(" + expr + ")" + ".collect(" + self.getValue(ch.expr(2)) + ")") # Replace(y, sin(x)=3) elif func_name == "replace": l = [] for i in range(1, ch.getChildCount()): try: if ch.getChild(i).getChild(1).getText() == "=": l.append(self.getValue(ch.getChild(i).getChild(0)) + ":" + self.getValue(ch.getChild(i).getChild(2))) except Exception: pass expr = self.getValue(ch.expr(0)) if ch.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.matrix_expr.append(ctx) self.setValue(ctx, "_sm.Matrix([i.subs({" + ",".join(l) + "}) for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])") else: self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + ".subs({" + ",".join(l) + "})") # Dot(Loop>, N1>) elif func_name == "dot": l = [] num = (ch.expr(1).getChild(0).getChildCount()-1)//2 if ch.expr(1) in self.matrix_expr: for i in range(num): l.append("_me.dot(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1).getChild(0).expr(i)) + ")") self.setValue(ctx, "_sm.Matrix([" + ",".join(l) + "]).reshape(" + str(num) + ", " + "1)") else: self.setValue(ctx, "_me.dot(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1)) + ")") # Cross(w_A_N>, P_NA_AB>) elif func_name == "cross": self.vector_expr.append(ctx) self.setValue(ctx, "_me.cross(" + self.getValue(ch.expr(0)) + ", " + self.getValue(ch.expr(1)) + ")") # Mag(P_O_Q>) elif func_name == "mag": self.setValue(ctx, self.getValue(ch.expr(0)) + "." + "magnitude()") # MATRIX(A, I_R>>) elif func_name == "matrix": if self.type2[ch.expr(0).getText().lower()] == "frame": text = "" elif self.type2[ch.expr(0).getText().lower()] == "bodies": text = "_f" self.setValue(ctx, "(" + self.getValue(ch.expr(1)) + ")" + ".to_matrix(" + self.symbol_table2[ch.expr(0).getText().lower()] + text + ")") # VECTOR(A, ROWS(EIGVECS,1)) elif func_name == "vector": if self.type2[ch.expr(0).getText().lower()] == "frame": text = "" elif self.type2[ch.expr(0).getText().lower()] == "bodies": text = "_f" v = self.getValue(ch.expr(1)) f = self.symbol_table2[ch.expr(0).getText().lower()] + text self.setValue(ctx, v + "[0]*" + f + ".x +" + v + "[1]*" + f + ".y +" + v + "[2]*" + f + ".z") # Express(A2>, B) # Here I am dealing with all the Inertia commands as I expect the users to use Inertia # commands only with Express because SymPy needs the Reference frame to be specified unlike Autolev. elif func_name == "express": self.vector_expr.append(ctx) if self.type2[ch.expr(1).getText().lower()] == "frame": frame = self.symbol_table2[ch.expr(1).getText().lower()] else: frame = self.symbol_table2[ch.expr(1).getText().lower()] + "_f" if ch.expr(0).getText().lower() == "1>>": self.setValue(ctx, "_me.inertia(" + frame + ", 1, 1, 1)") elif '_' in ch.expr(0).getText().lower() and ch.expr(0).getText().lower().count('_') == 2\ and ch.expr(0).getText().lower()[0] == "i" and ch.expr(0).getText().lower()[-2:] == ">>": v1 = ch.expr(0).getText().lower()[:-2].split('_')[1] v2 = ch.expr(0).getText().lower()[:-2].split('_')[2] l = [] inertia_func(self, v1, v2, l, frame) self.setValue(ctx, " + ".join(l)) elif ch.expr(0).getChild(0).getChild(0).getText().lower() == "inertia": if ch.expr(0).getChild(0).getChildCount() == 4: l = [] v2 = ch.expr(0).getChild(0).ID(0).getText().lower() for v1 in self.bodies: inertia_func(self, v1, v2, l, frame) self.setValue(ctx, " + ".join(l)) else: l = [] l2 = [] v2 = ch.expr(0).getChild(0).ID(0).getText().lower() for i in range(1, (ch.expr(0).getChild(0).getChildCount()-2)//2): l2.append(ch.expr(0).getChild(0).ID(i).getText().lower()) for v1 in l2: inertia_func(self, v1, v2, l, frame) self.setValue(ctx, " + ".join(l)) else: self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + ".express(" + self.symbol_table2[ch.expr(1).getText().lower()] + ")") # CM(P) elif func_name == "cm": if self.type2[ch.expr(0).getText().lower()] == "point": text = "" else: text = ".point" if ch.getChildCount() == 4: self.setValue(ctx, "_me.functions.center_of_mass(" + self.symbol_table2[ch.expr(0).getText().lower()] + text + "," + ", ".join(self.bodies.values()) + ")") else: bodies = [] for i in range(1, (ch.getChildCount()-1)//2): bodies.append(self.symbol_table2[ch.expr(i).getText().lower()]) self.setValue(ctx, "_me.functions.center_of_mass(" + self.symbol_table2[ch.expr(0).getText().lower()] + text + "," + ", ".join(bodies) + ")") # PARTIALS(V_P1_E>,U1) elif func_name == "partials": speeds = [] for i in range(1, (ch.getChildCount()-1)//2): if self.kd_equivalents2: speeds.append(self.kd_equivalents2[self.symbol_table[ch.expr(i).getText().lower()]]) else: speeds.append(self.symbol_table[ch.expr(i).getText().lower()]) v1, v2, v3 = ch.expr(0).getText().lower().replace(">","").split('_') if self.type2[v2] == "point": point = self.symbol_table2[v2] elif self.type2[v2] == "particle": point = self.symbol_table2[v2] + ".point" frame = self.symbol_table2[v3] self.setValue(ctx, point + ".partial_velocity(" + frame + ", " + ",".join(speeds) + ")") # UnitVec(A1>+A2>+A3>) elif func_name == "unitvec": self.setValue(ctx, "(" + self.getValue(ch.expr(0)) + ")" + ".normalize()") # Units(deg, rad) elif func_name == "units": if ch.expr(0).getText().lower() == "deg" and ch.expr(1).getText().lower() == "rad": factor = 0.0174533 elif ch.expr(0).getText().lower() == "rad" and ch.expr(1).getText().lower() == "deg": factor = 57.2958 self.setValue(ctx, str(factor)) # Mass(A) elif func_name == "mass": l = [] try: ch.ID(0).getText().lower() for i in range((ch.getChildCount()-1)//2): l.append(self.symbol_table2[ch.ID(i).getText().lower()] + ".mass") self.setValue(ctx, "+".join(l)) except Exception: for i in self.bodies.keys(): l.append(self.bodies[i] + ".mass") self.setValue(ctx, "+".join(l)) # Fr() FrStar() # _me.KanesMethod(n, q_ind, u_ind, kd, velocity_constraints).kanes_equations(pl, fl)[0] elif func_name in ["fr", "frstar"]: if not self.kane_parsed: if self.kd_eqs: for i in self.kd_eqs: self.q_ind.append(self.symbol_table[i.strip().split('-')[0].replace("'","")]) self.u_ind.append(self.symbol_table[i.strip().split('-')[1].replace("'","")]) for i in range(len(self.kd_eqs)): self.kd_eqs[i] = self.symbol_table[self.kd_eqs[i].strip().split('-')[0]] + " - " +\ self.symbol_table[self.kd_eqs[i].strip().split('-')[1]] # Do all of this if kd_eqs are not specified if not self.kd_eqs: self.kd_eqs_supplied = False self.matrix_expr.append(ctx) for i in self.type.keys(): if self.type[i] == "motionvariable": if self.sign[self.symbol_table[i.lower()]] == 0: self.q_ind.append(self.symbol_table[i.lower()]) elif self.sign[self.symbol_table[i.lower()]] == 1: name = "u_" + self.symbol_table[i.lower()] self.symbol_table.update({name: name}) self.write(name + " = " + "_me.dynamicsymbols('" + name + "')\n") if self.symbol_table[i.lower()] not in self.dependent_variables: self.u_ind.append(name) self.kd_equivalents.update({name: self.symbol_table[i.lower()]}) else: self.u_dep.append(name) self.kd_equivalents.update({name: self.symbol_table[i.lower()]}) for i in self.kd_equivalents.keys(): self.kd_eqs.append(self.kd_equivalents[i] + "-" + i) if not self.u_ind and not self.kd_eqs: self.u_ind = self.q_ind.copy() self.q_ind = [] # deal with velocity constraints if self.dependent_variables: for i in self.dependent_variables: self.u_dep.append(i) if i in self.u_ind: self.u_ind.remove(i) self.u_dep[:] = [i for i in self.u_dep if i not in self.kd_equivalents.values()] force_list = [] for i in self.forces.keys(): force_list.append("(" + i + "," + self.forces[i] + ")") if self.u_dep: u_dep_text = ", u_dependent=[" + ", ".join(self.u_dep) + "]" else: u_dep_text = "" if self.dependent_variables: velocity_constraints_text = ", velocity_constraints = velocity_constraints" else: velocity_constraints_text = "" if ctx.parentCtx not in self.fr_expr: self.write("kd_eqs = [" + ", ".join(self.kd_eqs) + "]\n") self.write("forceList = " + "[" + ", ".join(force_list) + "]\n") self.write("kane = _me.KanesMethod(" + self.newtonian + ", " + "q_ind=[" + ",".join(self.q_ind) + "], " + "u_ind=[" + ", ".join(self.u_ind) + "]" + u_dep_text + ", " + "kd_eqs = kd_eqs" + velocity_constraints_text + ")\n") self.write("fr, frstar = kane." + "kanes_equations([" + ", ".join(self.bodies.values()) + "], forceList)\n") self.fr_expr.append(ctx.parentCtx) self.kane_parsed = True self.setValue(ctx, func_name) def exitMatrices(self, ctx): # Tree annotation for Matrices which is a labeled subrule of the parser rule expr. # MO = [a, b; c, d] # we generate _sm.Matrix([a, b, c, d]).reshape(2, 2) # The reshape values are determined by counting the "," and ";" in the Autolev matrix # Eg: # [1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12] # semicolon_count = 3 and rows = 3+1 = 4 # comma_count = 8 and cols = 8/rows + 1 = 8/4 + 1 = 3 # TODO** Parse block matrices self.matrix_expr.append(ctx) l = [] semicolon_count = 0 comma_count = 0 for i in range(ctx.matrix().getChildCount()): child = ctx.matrix().getChild(i) if child == AutolevParser.ExprContext: l.append(self.getValue(child)) elif child.getText() == ";": semicolon_count += 1 l.append(",") elif child.getText() == ",": comma_count += 1 l.append(",") else: try: try: l.append(self.getValue(child)) except Exception: l.append(self.symbol_table[child.getText().lower()]) except Exception: l.append(child.getText().lower()) num_of_rows = semicolon_count + 1 num_of_cols = (comma_count//num_of_rows) + 1 self.setValue(ctx, "_sm.Matrix(" + "".join(l) + ")" + ".reshape(" + str(num_of_rows) + ", " + str(num_of_cols) + ")") def exitVectorOrDyadic(self, ctx): self.vector_expr.append(ctx) ch = ctx.vec() if ch.getChild(0).getText() == "0>": self.setValue(ctx, "0") elif ch.getChild(0).getText() == "1>>": self.setValue(ctx, "1>>") elif "_" in ch.ID().getText() and ch.ID().getText().count('_') == 2: vec_text = ch.getText().lower() v1, v2, v3 = ch.ID().getText().lower().split('_') if v1 == "p": if self.type2[v2] == "point": e2 = self.symbol_table2[v2] elif self.type2[v2] == "particle": e2 = self.symbol_table2[v2] + ".point" if self.type2[v3] == "point": e3 = self.symbol_table2[v3] elif self.type2[v3] == "particle": e3 = self.symbol_table2[v3] + ".point" get_vec = e3 + ".pos_from(" + e2 + ")" self.setValue(ctx, get_vec) elif v1 in ("w", "alf"): if v1 == "w": text = ".ang_vel_in(" elif v1 == "alf": text = ".ang_acc_in(" if self.type2[v2] == "bodies": e2 = self.symbol_table2[v2] + "_f" elif self.type2[v2] == "frame": e2 = self.symbol_table2[v2] if self.type2[v3] == "bodies": e3 = self.symbol_table2[v3] + "_f" elif self.type2[v3] == "frame": e3 = self.symbol_table2[v3] get_vec = e2 + text + e3 + ")" self.setValue(ctx, get_vec) elif v1 in ("v", "a"): if v1 == "v": text = ".vel(" elif v1 == "a": text = ".acc(" if self.type2[v2] == "point": e2 = self.symbol_table2[v2] elif self.type2[v2] == "particle": e2 = self.symbol_table2[v2] + ".point" get_vec = e2 + text + self.symbol_table2[v3] + ")" self.setValue(ctx, get_vec) else: self.setValue(ctx, vec_text.replace(">", "")) else: vec_text = ch.getText().lower() name = self.symbol_table[vec_text] self.setValue(ctx, name) def exitIndexing(self, ctx): if ctx.getChildCount() == 4: try: int_text = str(int(self.getValue(ctx.getChild(2))) - 1) except Exception: int_text = self.getValue(ctx.getChild(2)) + " - 1" self.setValue(ctx, ctx.ID().getText().lower() + "[" + int_text + "]") elif ctx.getChildCount() == 6: try: int_text1 = str(int(self.getValue(ctx.getChild(2))) - 1) except Exception: int_text1 = self.getValue(ctx.getChild(2)) + " - 1" try: int_text2 = str(int(self.getValue(ctx.getChild(4))) - 1) except Exception: int_text2 = self.getValue(ctx.getChild(2)) + " - 1" self.setValue(ctx, ctx.ID().getText().lower() + "[" + int_text1 + ", " + int_text2 + "]") # ================== Subrules of parser rule expr (End) ====================== # def exitRegularAssign(self, ctx): # Handle assignments of type ID = expr if ctx.equals().getText() in ["=", "+=", "-=", "*=", "/="]: equals = ctx.equals().getText() elif ctx.equals().getText() == ":=": equals = " = " elif ctx.equals().getText() == "^=": equals = "**=" try: a = ctx.ID().getText().lower() + "'"*ctx.diff().getText().count("'") except Exception: a = ctx.ID().getText().lower() if a in self.type.keys() and self.type[a] in ("motionvariable", "motionvariable'") and\ self.type[ctx.expr().getText().lower()] in ("motionvariable", "motionvariable'"): b = ctx.expr().getText().lower() if "'" in b and "'" not in a: a, b = b, a if not self.kane_parsed: self.kd_eqs.append(a + "-" + b) self.kd_equivalents.update({self.symbol_table[a]: self.symbol_table[b]}) self.kd_equivalents2.update({self.symbol_table[b]: self.symbol_table[a]}) if a in self.symbol_table.keys() and a in self.type.keys() and self.type[a] in ("variable", "motionvariable"): self.explicit.update({self.symbol_table[a]: self.getValue(ctx.expr())}) else: if ctx.expr() in self.matrix_expr: self.type.update({a: "matrix"}) try: b = self.symbol_table[a] except KeyError: self.symbol_table[a] = a if "_" in a and a.count("_") == 1: e1, e2 = a.split('_') if e1 in self.type2.keys() and self.type2[e1] in ("frame", "bodies")\ and e2 in self.type2.keys() and self.type2[e2] in ("frame", "bodies"): if self.type2[e1] == "bodies": t1 = "_f" else: t1 = "" if self.type2[e2] == "bodies": t2 = "_f" else: t2 = "" self.write(self.symbol_table2[e2] + t2 + ".orient(" + self.symbol_table2[e1] + t1 + ", 'DCM', " + self.getValue(ctx.expr()) + ")\n") else: self.write(self.symbol_table[a] + " " + equals + " " + self.getValue(ctx.expr()) + "\n") else: self.write(self.symbol_table[a] + " " + equals + " " + self.getValue(ctx.expr()) + "\n") def exitIndexAssign(self, ctx): # Handle assignments of type ID[index] = expr if ctx.equals().getText() in ["=", "+=", "-=", "*=", "/="]: equals = ctx.equals().getText() elif ctx.equals().getText() == ":=": equals = " = " elif ctx.equals().getText() == "^=": equals = "**=" text = ctx.ID().getText().lower() self.type.update({text: "matrix"}) # Handle assignments of type ID[2] = expr if ctx.index().getChildCount() == 1: if ctx.index().getChild(0).getText() == "1": self.type.update({text: "matrix"}) self.symbol_table.update({text: text}) self.write(text + " = " + "_sm.Matrix([[0]])\n") self.write(text + "[0] = " + self.getValue(ctx.expr()) + "\n") else: # m = m.row_insert(m.shape[0], _sm.Matrix([[0]])) self.write(text + " = " + text + ".row_insert(" + text + ".shape[0]" + ", " + "_sm.Matrix([[0]])" + ")\n") self.write(text + "[" + text + ".shape[0]-1" + "] = " + self.getValue(ctx.expr()) + "\n") # Handle assignments of type ID[2, 2] = expr elif ctx.index().getChildCount() == 3: l = [] try: l.append(str(int(self.getValue(ctx.index().getChild(0)))-1)) except Exception: l.append(self.getValue(ctx.index().getChild(0)) + "-1") l.append(",") try: l.append(str(int(self.getValue(ctx.index().getChild(2)))-1)) except Exception: l.append(self.getValue(ctx.index().getChild(2)) + "-1") self.write(self.symbol_table[ctx.ID().getText().lower()] + "[" + "".join(l) + "]" + " " + equals + " " + self.getValue(ctx.expr()) + "\n") def exitVecAssign(self, ctx): # Handle assignments of the type vec = expr ch = ctx.vec() vec_text = ch.getText().lower() if "_" in ch.ID().getText(): num = ch.ID().getText().count('_') if num == 2: v1, v2, v3 = ch.ID().getText().lower().split('_') if v1 == "p": if self.type2[v2] == "point": e2 = self.symbol_table2[v2] elif self.type2[v2] == "particle": e2 = self.symbol_table2[v2] + ".point" if self.type2[v3] == "point": e3 = self.symbol_table2[v3] elif self.type2[v3] == "particle": e3 = self.symbol_table2[v3] + ".point" # ab.set_pos(na, la*a.x) self.write(e3 + ".set_pos(" + e2 + ", " + self.getValue(ctx.expr()) + ")\n") elif v1 in ("w", "alf"): if v1 == "w": text = ".set_ang_vel(" elif v1 == "alf": text = ".set_ang_acc(" # a.set_ang_vel(n, qad*a.z) if self.type2[v2] == "bodies": e2 = self.symbol_table2[v2] + "_f" else: e2 = self.symbol_table2[v2] if self.type2[v3] == "bodies": e3 = self.symbol_table2[v3] + "_f" else: e3 = self.symbol_table2[v3] self.write(e2 + text + e3 + ", " + self.getValue(ctx.expr()) + ")\n") elif v1 in ("v", "a"): if v1 == "v": text = ".set_vel(" elif v1 == "a": text = ".set_acc(" if self.type2[v2] == "point": e2 = self.symbol_table2[v2] elif self.type2[v2] == "particle": e2 = self.symbol_table2[v2] + ".point" self.write(e2 + text + self.symbol_table2[v3] + ", " + self.getValue(ctx.expr()) + ")\n") elif v1 == "i": if v2 in self.type2.keys() and self.type2[v2] == "bodies": self.write(self.symbol_table2[v2] + ".inertia = (" + self.getValue(ctx.expr()) + ", " + self.symbol_table2[v3] + ")\n") self.inertia_point.update({v2: v3}) elif v2 in self.type2.keys() and self.type2[v2] == "particle": self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n") else: self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n") else: self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n") elif num == 1: v1, v2 = ch.ID().getText().lower().split('_') if v1 in ("force", "torque"): if self.type2[v2] in ("point", "frame"): e2 = self.symbol_table2[v2] elif self.type2[v2] == "particle": e2 = self.symbol_table2[v2] + ".point" self.symbol_table.update({vec_text: ch.ID().getText().lower()}) if e2 in self.forces.keys(): self.forces[e2] = self.forces[e2] + " + " + self.getValue(ctx.expr()) else: self.forces.update({e2: self.getValue(ctx.expr())}) self.write(ch.ID().getText().lower() + " = " + self.forces[e2] + "\n") else: name = ch.ID().getText().lower() self.symbol_table.update({vec_text: name}) self.write(ch.ID().getText().lower() + " = " + self.getValue(ctx.expr()) + "\n") else: name = ch.ID().getText().lower() self.symbol_table.update({vec_text: name}) self.write(name + " " + ctx.getChild(1).getText() + " " + self.getValue(ctx.expr()) + "\n") else: name = ch.ID().getText().lower() self.symbol_table.update({vec_text: name}) self.write(name + " " + ctx.getChild(1).getText() + " " + self.getValue(ctx.expr()) + "\n") def enterInputs2(self, ctx): self.in_inputs = True # Inputs def exitInputs2(self, ctx): # Stores numerical values given by the input command which # are used for codegen and numerical analysis. if ctx.getChildCount() == 3: try: self.inputs.update({self.symbol_table[ctx.id_diff().getText().lower()]: self.getValue(ctx.expr(0))}) except Exception: self.inputs.update({ctx.id_diff().getText().lower(): self.getValue(ctx.expr(0))}) elif ctx.getChildCount() == 4: try: self.inputs.update({self.symbol_table[ctx.id_diff().getText().lower()]: (self.getValue(ctx.expr(0)), self.getValue(ctx.expr(1)))}) except Exception: self.inputs.update({ctx.id_diff().getText().lower(): (self.getValue(ctx.expr(0)), self.getValue(ctx.expr(1)))}) self.in_inputs = False def enterOutputs(self, ctx): self.in_outputs = True def exitOutputs(self, ctx): self.in_outputs = False def exitOutputs2(self, ctx): try: if "[" in ctx.expr(1).getText(): self.outputs.append(self.symbol_table[ctx.expr(0).getText().lower()] + ctx.expr(1).getText().lower()) else: self.outputs.append(self.symbol_table[ctx.expr(0).getText().lower()]) except Exception: pass # Code commands def exitCodegen(self, ctx): # Handles the CODE() command ie the solvers and the codgen part. # Uses linsolve for the algebraic solvers and nsolve for non linear solvers. if ctx.functionCall().getChild(0).getText().lower() == "algebraic": matrix_name = self.getValue(ctx.functionCall().expr(0)) e = [] d = [] for i in range(1, (ctx.functionCall().getChildCount()-2)//2): a = self.getValue(ctx.functionCall().expr(i)) e.append(a) for i in self.inputs.keys(): d.append(i + ":" + self.inputs[i]) self.write(matrix_name + "_list" + " = " + "[]\n") self.write("for i in " + matrix_name + ": " + matrix_name + "_list" + ".append(i.subs({" + ", ".join(d) + "}))\n") self.write("print(_sm.linsolve(" + matrix_name + "_list" + ", " + ",".join(e) + "))\n") elif ctx.functionCall().getChild(0).getText().lower() == "nonlinear": e = [] d = [] guess = [] for i in range(1, (ctx.functionCall().getChildCount()-2)//2): a = self.getValue(ctx.functionCall().expr(i)) e.append(a) #print(self.inputs) for i in self.inputs.keys(): if i in self.symbol_table.keys(): if type(self.inputs[i]) is tuple: j, z = self.inputs[i] else: j = self.inputs[i] z = "" if i not in e: if z == "deg": d.append(i + ":" + "_np.deg2rad(" + j + ")") else: d.append(i + ":" + j) else: if z == "deg": guess.append("_np.deg2rad(" + j + ")") else: guess.append(j) self.write("matrix_list" + " = " + "[]\n") self.write("for i in " + self.getValue(ctx.functionCall().expr(0)) + ":") self.write("matrix_list" + ".append(i.subs({" + ", ".join(d) + "}))\n") self.write("print(_sm.nsolve(matrix_list," + "(" + ",".join(e) + ")" + ",(" + ",".join(guess) + ")" + "))\n") elif ctx.functionCall().getChild(0).getText().lower() in ["ode", "dynamics"] and self.include_numeric: if self.kane_type == "no_args": for i in self.symbol_table.keys(): try: if self.type[i] == "constants" or self.type[self.symbol_table[i]] == "constants": self.constants.append(self.symbol_table[i]) except Exception: pass q_add_u = self.q_ind + self.q_dep + self.u_ind + self.u_dep x0 = [] for i in q_add_u: try: if i in self.inputs.keys(): if type(self.inputs[i]) is tuple: if self.inputs[i][1] == "deg": x0.append(i + ":" + "_np.deg2rad(" + self.inputs[i][0] + ")") else: x0.append(i + ":" + self.inputs[i][0]) else: x0.append(i + ":" + self.inputs[i]) elif self.kd_equivalents[i] in self.inputs.keys(): if type(self.inputs[self.kd_equivalents[i]]) is tuple: x0.append(i + ":" + self.inputs[self.kd_equivalents[i]][0]) else: x0.append(i + ":" + self.inputs[self.kd_equivalents[i]]) except Exception: pass # numerical constants numerical_constants = [] for i in self.constants: if i in self.inputs.keys(): if type(self.inputs[i]) is tuple: numerical_constants.append(self.inputs[i][0]) else: numerical_constants.append(self.inputs[i]) # t = linspace t_final = self.inputs["tfinal"] integ_stp = self.inputs["integstp"] self.write("from pydy.system import System\n") const_list = [] if numerical_constants: for i in range(len(self.constants)): const_list.append(self.constants[i] + ":" + numerical_constants[i]) specifieds = [] if self.t: specifieds.append("_me.dynamicsymbols('t')" + ":" + "lambda x, t: t") for i in self.inputs: if i in self.symbol_table.keys() and self.symbol_table[i] not in\ self.constants + self.q_ind + self.q_dep + self.u_ind + self.u_dep: specifieds.append(self.symbol_table[i] + ":" + self.inputs[i]) self.write("sys = System(kane, constants = {" + ", ".join(const_list) + "},\n" + "specifieds={" + ", ".join(specifieds) + "},\n" + "initial_conditions={" + ", ".join(x0) + "},\n" + "times = _np.linspace(0.0, " + str(t_final) + ", " + str(t_final) + "/" + str(integ_stp) + "))\n\ny=sys.integrate()\n") # For outputs other than qs and us. other_outputs = [] for i in self.outputs: if i not in q_add_u: if "[" in i: other_outputs.append((i[:-3] + i[-2], i[:-3] + "[" + str(int(i[-2])-1) + "]")) else: other_outputs.append((i, i)) for i in other_outputs: self.write(i[0] + "_out" + " = " + "[]\n") if other_outputs: self.write("for i in y:\n") self.write(" q_u_dict = dict(zip(sys.coordinates+sys.speeds, i))\n") for i in other_outputs: self.write(" "*4 + i[0] + "_out" + ".append(" + i[1] + ".subs(q_u_dict)" + ".subs(sys.constants).evalf())\n") # Standalone function calls (used for dual functions) def exitFunctionCall(self, ctx): # Basically deals with standalone function calls ie functions which are not a part of # expressions and assignments. Autolev Dual functions can both appear in standalone # function calls and also on the right hand side as part of expr or assignment. # Dual functions are indicated by a * in the comments below # Checks if the function is a statement on its own if ctx.parentCtx.getRuleIndex() == AutolevParser.RULE_stat: func_name = ctx.getChild(0).getText().lower() # Expand(E, n:m) * if func_name == "expand": # If the first argument is a pre declared variable. expr = self.getValue(ctx.expr(0)) symbol = self.symbol_table[ctx.expr(0).getText().lower()] if ctx.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.write(symbol + " = " + "_sm.Matrix([i.expand() for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])\n") else: self.write(symbol + " = " + symbol + "." + "expand()\n") # Factor(E, x) * elif func_name == "factor": expr = self.getValue(ctx.expr(0)) symbol = self.symbol_table[ctx.expr(0).getText().lower()] if ctx.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.write(symbol + " = " + "_sm.Matrix([_sm.factor(i," + self.getValue(ctx.expr(1)) + ") for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])\n") else: self.write(expr + " = " + "_sm.factor(" + expr + ", " + self.getValue(ctx.expr(1)) + ")\n") # Solve(Zero, x, y) elif func_name == "solve": l = [] l2 = [] num = 0 for i in range(1, ctx.getChildCount()): if ctx.getChild(i).getText() == ",": num+=1 try: l.append(self.getValue(ctx.getChild(i))) except Exception: l.append(ctx.getChild(i).getText()) if i != 2: try: l2.append(self.getValue(ctx.getChild(i))) except Exception: pass for i in l2: self.explicit.update({i: "_sm.solve" + "".join(l) + "[" + i + "]"}) self.write("print(_sm.solve" + "".join(l) + ")\n") # Arrange(y, n, x) * elif func_name == "arrange": expr = self.getValue(ctx.expr(0)) symbol = self.symbol_table[ctx.expr(0).getText().lower()] if ctx.expr(0) in self.matrix_expr or (expr in self.type.keys() and self.type[expr] == "matrix"): self.write(symbol + " = " + "_sm.Matrix([i.collect(" + self.getValue(ctx.expr(2)) + ")" + "for i in " + expr + "])" + ".reshape((" + expr + ").shape[0], " + "(" + expr + ").shape[1])\n") else: self.write(self.getValue(ctx.expr(0)) + ".collect(" + self.getValue(ctx.expr(2)) + ")\n") # Eig(M, EigenValue, EigenVec) elif func_name == "eig": self.symbol_table.update({ctx.expr(1).getText().lower(): ctx.expr(1).getText().lower()}) self.symbol_table.update({ctx.expr(2).getText().lower(): ctx.expr(2).getText().lower()}) # _sm.Matrix([i.evalf() for i in (i_s_so).eigenvals().keys()]) self.write(ctx.expr(1).getText().lower() + " = " + "_sm.Matrix([i.evalf() for i in " + "(" + self.getValue(ctx.expr(0)) + ")" + ".eigenvals().keys()])\n") # _sm.Matrix([i[2][0].evalf() for i in (i_s_o).eigenvects()]).reshape(i_s_o.shape[0], i_s_o.shape[1]) self.write(ctx.expr(2).getText().lower() + " = " + "_sm.Matrix([i[2][0].evalf() for i in " + "(" + self.getValue(ctx.expr(0)) + ")" + ".eigenvects()]).reshape(" + self.getValue(ctx.expr(0)) + ".shape[0], " + self.getValue(ctx.expr(0)) + ".shape[1])\n") # Simprot(N, A, 3, qA) elif func_name == "simprot": # A.orient(N, 'Axis', qA, N.z) if self.type2[ctx.expr(0).getText().lower()] == "frame": frame1 = self.symbol_table2[ctx.expr(0).getText().lower()] elif self.type2[ctx.expr(0).getText().lower()] == "bodies": frame1 = self.symbol_table2[ctx.expr(0).getText().lower()] + "_f" if self.type2[ctx.expr(1).getText().lower()] == "frame": frame2 = self.symbol_table2[ctx.expr(1).getText().lower()] elif self.type2[ctx.expr(1).getText().lower()] == "bodies": frame2 = self.symbol_table2[ctx.expr(1).getText().lower()] + "_f" e2 = "" if ctx.expr(2).getText()[0] == "-": e2 = "-1*" if ctx.expr(2).getText() in ("1", "-1"): e = frame1 + ".x" elif ctx.expr(2).getText() in ("2", "-2"): e = frame1 + ".y" elif ctx.expr(2).getText() in ("3", "-3"): e = frame1 + ".z" else: e = self.getValue(ctx.expr(2)) e2 = "" if "degrees" in self.settings.keys() and self.settings["degrees"] == "off": value = self.getValue(ctx.expr(3)) else: if ctx.expr(3) in self.numeric_expr: value = "_np.deg2rad(" + self.getValue(ctx.expr(3)) + ")" else: value = self.getValue(ctx.expr(3)) self.write(frame2 + ".orient(" + frame1 + ", " + "'Axis'" + ", " + "[" + value + ", " + e2 + e + "]" + ")\n") # Express(A2>, B) * elif func_name == "express": if self.type2[ctx.expr(1).getText().lower()] == "bodies": f = "_f" else: f = "" if '_' in ctx.expr(0).getText().lower() and ctx.expr(0).getText().count('_') == 2: vec = ctx.expr(0).getText().lower().replace(">", "").split('_') v1 = self.symbol_table2[vec[1]] v2 = self.symbol_table2[vec[2]] if vec[0] == "p": self.write(v2 + ".set_pos(" + v1 + ", " + "(" + self.getValue(ctx.expr(0)) + ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + "))\n") elif vec[0] == "v": self.write(v1 + ".set_vel(" + v2 + ", " + "(" + self.getValue(ctx.expr(0)) + ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + "))\n") elif vec[0] == "a": self.write(v1 + ".set_acc(" + v2 + ", " + "(" + self.getValue(ctx.expr(0)) + ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + "))\n") else: self.write(self.getValue(ctx.expr(0)) + " = " + "(" + self.getValue(ctx.expr(0)) + ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + ")\n") else: self.write(self.getValue(ctx.expr(0)) + " = " + "(" + self.getValue(ctx.expr(0)) + ")" + ".express(" + self.symbol_table2[ctx.expr(1).getText().lower()] + f + ")\n") # Angvel(A, B) elif func_name == "angvel": self.write("print(" + self.symbol_table2[ctx.expr(1).getText().lower()] + ".ang_vel_in(" + self.symbol_table2[ctx.expr(0).getText().lower()] + "))\n") # v2pts(N, A, O, P) elif func_name in ("v2pts", "a2pts", "v2pt", "a1pt"): if func_name == "v2pts": text = ".v2pt_theory(" elif func_name == "a2pts": text = ".a2pt_theory(" elif func_name == "v1pt": text = ".v1pt_theory(" elif func_name == "a1pt": text = ".a1pt_theory(" if self.type2[ctx.expr(1).getText().lower()] == "frame": frame = self.symbol_table2[ctx.expr(1).getText().lower()] elif self.type2[ctx.expr(1).getText().lower()] == "bodies": frame = self.symbol_table2[ctx.expr(1).getText().lower()] + "_f" expr_list = [] for i in range(2, 4): if self.type2[ctx.expr(i).getText().lower()] == "point": expr_list.append(self.symbol_table2[ctx.expr(i).getText().lower()]) elif self.type2[ctx.expr(i).getText().lower()] == "particle": expr_list.append(self.symbol_table2[ctx.expr(i).getText().lower()] + ".point") self.write(expr_list[1] + text + expr_list[0] + "," + self.symbol_table2[ctx.expr(0).getText().lower()] + "," + frame + ")\n") # Gravity(g*N1>) elif func_name == "gravity": for i in self.bodies.keys(): if self.type2[i] == "bodies": e = self.symbol_table2[i] + ".masscenter" elif self.type2[i] == "particle": e = self.symbol_table2[i] + ".point" if e in self.forces.keys(): self.forces[e] = self.forces[e] + self.symbol_table2[i] +\ ".mass*(" + self.getValue(ctx.expr(0)) + ")" else: self.forces.update({e: self.symbol_table2[i] + ".mass*(" + self.getValue(ctx.expr(0)) + ")"}) self.write("force_" + i + " = " + self.forces[e] + "\n") # Explicit(EXPRESS(IMPLICIT>,C)) elif func_name == "explicit": if ctx.expr(0) in self.vector_expr: self.vector_expr.append(ctx) expr = self.getValue(ctx.expr(0)) if self.explicit.keys(): explicit_list = [] for i in self.explicit.keys(): explicit_list.append(i + ":" + self.explicit[i]) if '_' in ctx.expr(0).getText().lower() and ctx.expr(0).getText().count('_') == 2: vec = ctx.expr(0).getText().lower().replace(">", "").split('_') v1 = self.symbol_table2[vec[1]] v2 = self.symbol_table2[vec[2]] if vec[0] == "p": self.write(v2 + ".set_pos(" + v1 + ", " + "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "}))\n") elif vec[0] == "v": self.write(v2 + ".set_vel(" + v1 + ", " + "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "}))\n") elif vec[0] == "a": self.write(v2 + ".set_acc(" + v1 + ", " + "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "}))\n") else: self.write(expr + " = " + "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "})\n") else: self.write(expr + " = " + "(" + expr + ")" + ".subs({" + ", ".join(explicit_list) + "})\n") # Force(O/Q, -k*Stretch*Uvec>) elif func_name in ("force", "torque"): if "/" in ctx.expr(0).getText().lower(): p1 = ctx.expr(0).getText().lower().split('/')[0] p2 = ctx.expr(0).getText().lower().split('/')[1] if self.type2[p1] in ("point", "frame"): pt1 = self.symbol_table2[p1] elif self.type2[p1] == "particle": pt1 = self.symbol_table2[p1] + ".point" if self.type2[p2] in ("point", "frame"): pt2 = self.symbol_table2[p2] elif self.type2[p2] == "particle": pt2 = self.symbol_table2[p2] + ".point" if pt1 in self.forces.keys(): self.forces[pt1] = self.forces[pt1] + " + -1*("+self.getValue(ctx.expr(1)) + ")" self.write("force_" + p1 + " = " + self.forces[pt1] + "\n") else: self.forces.update({pt1: "-1*("+self.getValue(ctx.expr(1)) + ")"}) self.write("force_" + p1 + " = " + self.forces[pt1] + "\n") if pt2 in self.forces.keys(): self.forces[pt2] = self.forces[pt2] + "+ " + self.getValue(ctx.expr(1)) self.write("force_" + p2 + " = " + self.forces[pt2] + "\n") else: self.forces.update({pt2: self.getValue(ctx.expr(1))}) self.write("force_" + p2 + " = " + self.forces[pt2] + "\n") elif ctx.expr(0).getChildCount() == 1: p1 = ctx.expr(0).getText().lower() if self.type2[p1] in ("point", "frame"): pt1 = self.symbol_table2[p1] elif self.type2[p1] == "particle": pt1 = self.symbol_table2[p1] + ".point" if pt1 in self.forces.keys(): self.forces[pt1] = self.forces[pt1] + "+ -1*(" + self.getValue(ctx.expr(1)) + ")" else: self.forces.update({pt1: "-1*(" + self.getValue(ctx.expr(1)) + ")"}) # Constrain(Dependent[qB]) elif func_name == "constrain": if ctx.getChild(2).getChild(0).getText().lower() == "dependent": self.write("velocity_constraints = [i for i in dependent]\n") x = (ctx.expr(0).getChildCount()-2)//2 for i in range(x): self.dependent_variables.append(self.getValue(ctx.expr(0).expr(i))) # Kane() elif func_name == "kane": if ctx.getChildCount() == 3: self.kane_type = "no_args" # Settings def exitSettings(self, ctx): # Stores settings like Complex on/off, Degrees on/off etc in self.settings. try: self.settings.update({ctx.getChild(0).getText().lower(): ctx.getChild(1).getText().lower()}) except Exception: pass def exitMassDecl2(self, ctx): # Used for declaring the masses of particles and rigidbodies. particle = self.symbol_table2[ctx.getChild(0).getText().lower()] if ctx.getText().count("=") == 2: if ctx.expr().expr(1) in self.numeric_expr: e = "_sm.S(" + self.getValue(ctx.expr().expr(1)) + ")" else: e = self.getValue(ctx.expr().expr(1)) self.symbol_table.update({ctx.expr().expr(0).getText().lower(): ctx.expr().expr(0).getText().lower()}) self.write(ctx.expr().expr(0).getText().lower() + " = " + e + "\n") mass = ctx.expr().expr(0).getText().lower() else: try: if ctx.expr() in self.numeric_expr: mass = "_sm.S(" + self.getValue(ctx.expr()) + ")" else: mass = self.getValue(ctx.expr()) except Exception: a_text = ctx.expr().getText().lower() self.symbol_table.update({a_text: a_text}) self.type.update({a_text: "constants"}) self.write(a_text + " = " + "_sm.symbols('" + a_text + "')\n") mass = a_text self.write(particle + ".mass = " + mass + "\n") def exitInertiaDecl(self, ctx): inertia_list = [] try: ctx.ID(1).getText() num = 5 except Exception: num = 2 for i in range((ctx.getChildCount()-num)//2): try: if ctx.expr(i) in self.numeric_expr: inertia_list.append("_sm.S(" + self.getValue(ctx.expr(i)) + ")") else: inertia_list.append(self.getValue(ctx.expr(i))) except Exception: a_text = ctx.expr(i).getText().lower() self.symbol_table.update({a_text: a_text}) self.type.update({a_text: "constants"}) self.write(a_text + " = " + "_sm.symbols('" + a_text + "')\n") inertia_list.append(a_text) if len(inertia_list) < 6: for i in range(6-len(inertia_list)): inertia_list.append("0") # body_a.inertia = (_me.inertia(body_a, I1, I2, I3, 0, 0, 0), body_a_cm) try: frame = self.symbol_table2[ctx.ID(1).getText().lower()] point = self.symbol_table2[ctx.ID(0).getText().lower().split('_')[1]] body = self.symbol_table2[ctx.ID(0).getText().lower().split('_')[0]] self.inertia_point.update({ctx.ID(0).getText().lower().split('_')[0] : ctx.ID(0).getText().lower().split('_')[1]}) self.write(body + ".inertia" + " = " + "(_me.inertia(" + frame + ", " + ", ".join(inertia_list) + "), " + point + ")\n") except Exception: body_name = self.symbol_table2[ctx.ID(0).getText().lower()] body_name_cm = body_name + "_cm" self.inertia_point.update({ctx.ID(0).getText().lower(): ctx.ID(0).getText().lower() + "o"}) self.write(body_name + ".inertia" + " = " + "(_me.inertia(" + body_name + "_f" + ", " + ", ".join(inertia_list) + "), " + body_name_cm + ")\n") sympy-sympy-1.9/sympy/parsing/autolev/_parse_autolev_antlr.py000066400000000000000000000032521412543434000250120ustar00rootroot00000000000000from sympy.external import import_module autolevparser = import_module('sympy.parsing.autolev._antlr.autolevparser', import_kwargs={'fromlist': ['AutolevParser']}) autolevlexer = import_module('sympy.parsing.autolev._antlr.autolevlexer', import_kwargs={'fromlist': ['AutolevLexer']}) autolevlistener = import_module('sympy.parsing.autolev._antlr.autolevlistener', import_kwargs={'fromlist': ['AutolevListener']}) AutolevParser = getattr(autolevparser, 'AutolevParser', None) AutolevLexer = getattr(autolevlexer, 'AutolevLexer', None) AutolevListener = getattr(autolevlistener, 'AutolevListener', None) def parse_autolev(autolev_code, include_numeric): antlr4 = import_module('antlr4', warn_not_installed=True) if not antlr4: raise ImportError("Autolev parsing requires the antlr4 python package," " provided by pip (antlr4-python2-runtime or" " antlr4-python3-runtime) or" " conda (antlr-python-runtime)") try: l = autolev_code.readlines() input_stream = antlr4.InputStream("".join(l)) except Exception: input_stream = antlr4.InputStream(autolev_code) if AutolevListener: from ._listener_autolev_antlr import MyListener lexer = AutolevLexer(input_stream) token_stream = antlr4.CommonTokenStream(lexer) parser = AutolevParser(token_stream) tree = parser.prog() my_listener = MyListener(include_numeric) walker = antlr4.ParseTreeWalker() walker.walk(my_listener, tree) return "".join(my_listener.output_code) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/000077500000000000000000000000001412543434000230215ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/autolev/test-examples/README.txt000066400000000000000000000010201412543434000245100ustar00rootroot00000000000000# parsing/tests/test_autolev.py uses the .al files in this directory as inputs and checks # the equivalence of the parser generated codes and the respective .py files. # By default, this directory contains tests for all rules of the parser. # Additional tests consisting of full physics examples shall be made available soon in # the form of another repository. One shall be able to copy the contents of that repo # to this folder and use those tests after uncommenting the respective code in # parsing/tests/test_autolev.py. sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/000077500000000000000000000000001412543434000264025ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/chaos_pendulum.al000066400000000000000000000012621412543434000317270ustar00rootroot00000000000000CONSTANTS G,LB,W,H MOTIONVARIABLES' THETA'',PHI'',OMEGA',ALPHA' NEWTONIAN N BODIES A,B SIMPROT(N,A,2,THETA) SIMPROT(A,B,3,PHI) POINT O LA = (LB-H/2)/2 P_O_AO> = LA*A3> P_O_BO> = LB*A3> OMEGA = THETA' ALPHA = PHI' W_A_N> = OMEGA*N2> W_B_A> = ALPHA*A3> V_O_N> = 0> V2PTS(N, A, O, AO) V2PTS(N, A, O, BO) MASS A=MA, B=MB IAXX = 1/12*MA*(2*LA)^2 IAYY = IAXX IAZZ = 0 IBXX = 1/12*MB*H^2 IBYY = 1/12*MB*(W^2+H^2) IBZZ = 1/12*MB*W^2 INERTIA A, IAXX, IAYY, IAZZ INERTIA B, IBXX, IBYY, IBZZ GRAVITY(G*N3>) ZERO = FR() + FRSTAR() KANE() INPUT LB=0.2,H=0.1,W=0.2,MA=0.01,MB=0.1,G=9.81 INPUT THETA = 90 DEG, PHI = 0.5 DEG, OMEGA=0, ALPHA=0 INPUT TFINAL=10, INTEGSTP=0.02 CODE DYNAMICS() some_filename.c sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/chaos_pendulum.py000066400000000000000000000043421412543434000317650ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np g, lb, w, h = _sm.symbols('g lb w h', real=True) theta, phi, omega, alpha = _me.dynamicsymbols('theta phi omega alpha') theta_d, phi_d, omega_d, alpha_d = _me.dynamicsymbols('theta_ phi_ omega_ alpha_', 1) theta_dd, phi_dd = _me.dynamicsymbols('theta_ phi_', 2) frame_n = _me.ReferenceFrame('n') body_a_cm = _me.Point('a_cm') body_a_cm.set_vel(frame_n, 0) body_a_f = _me.ReferenceFrame('a_f') body_a = _me.RigidBody('a', body_a_cm, body_a_f, _sm.symbols('m'), (_me.outer(body_a_f.x,body_a_f.x),body_a_cm)) body_b_cm = _me.Point('b_cm') body_b_cm.set_vel(frame_n, 0) body_b_f = _me.ReferenceFrame('b_f') body_b = _me.RigidBody('b', body_b_cm, body_b_f, _sm.symbols('m'), (_me.outer(body_b_f.x,body_b_f.x),body_b_cm)) body_a_f.orient(frame_n, 'Axis', [theta, frame_n.y]) body_b_f.orient(body_a_f, 'Axis', [phi, body_a_f.z]) point_o = _me.Point('o') la = (lb-h/2)/2 body_a_cm.set_pos(point_o, la*body_a_f.z) body_b_cm.set_pos(point_o, lb*body_a_f.z) body_a_f.set_ang_vel(frame_n, omega*frame_n.y) body_b_f.set_ang_vel(body_a_f, alpha*body_a_f.z) point_o.set_vel(frame_n, 0) body_a_cm.v2pt_theory(point_o,frame_n,body_a_f) body_b_cm.v2pt_theory(point_o,frame_n,body_a_f) ma = _sm.symbols('ma') body_a.mass = ma mb = _sm.symbols('mb') body_b.mass = mb iaxx = 1/12*ma*(2*la)**2 iayy = iaxx iazz = 0 ibxx = 1/12*mb*h**2 ibyy = 1/12*mb*(w**2+h**2) ibzz = 1/12*mb*w**2 body_a.inertia = (_me.inertia(body_a_f, iaxx, iayy, iazz, 0, 0, 0), body_a_cm) body_b.inertia = (_me.inertia(body_b_f, ibxx, ibyy, ibzz, 0, 0, 0), body_b_cm) force_a = body_a.mass*(g*frame_n.z) force_b = body_b.mass*(g*frame_n.z) kd_eqs = [theta_d - omega, phi_d - alpha] forceList = [(body_a.masscenter,body_a.mass*(g*frame_n.z)), (body_b.masscenter,body_b.mass*(g*frame_n.z))] kane = _me.KanesMethod(frame_n, q_ind=[theta,phi], u_ind=[omega, alpha], kd_eqs = kd_eqs) fr, frstar = kane.kanes_equations([body_a, body_b], forceList) zero = fr+frstar from pydy.system import System sys = System(kane, constants = {g:9.81, lb:0.2, w:0.2, h:0.1, ma:0.01, mb:0.1}, specifieds={}, initial_conditions={theta:_np.deg2rad(90), phi:_np.deg2rad(0.5), omega:0, alpha:0}, times = _np.linspace(0.0, 10, 10/0.02)) y=sys.integrate() sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/double_pendulum.al000066400000000000000000000006531412543434000321070ustar00rootroot00000000000000MOTIONVARIABLES' Q{2}', U{2}' CONSTANTS L,M,G NEWTONIAN N FRAMES A,B SIMPROT(N, A, 3, Q1) SIMPROT(N, B, 3, Q2) W_A_N>=U1*N3> W_B_N>=U2*N3> POINT O PARTICLES P,R P_O_P> = L*A1> P_P_R> = L*B1> V_O_N> = 0> V2PTS(N, A, O, P) V2PTS(N, B, P, R) MASS P=M, R=M Q1' = U1 Q2' = U2 GRAVITY(G*N1>) ZERO = FR() + FRSTAR() KANE() INPUT M=1,G=9.81,L=1 INPUT Q1=.1,Q2=.2,U1=0,U2=0 INPUT TFINAL=10, INTEGSTP=.01 CODE DYNAMICS() some_filename.c sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/double_pendulum.py000066400000000000000000000030571412543434000321440ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np q1, q2, u1, u2 = _me.dynamicsymbols('q1 q2 u1 u2') q1_d, q2_d, u1_d, u2_d = _me.dynamicsymbols('q1_ q2_ u1_ u2_', 1) l, m, g = _sm.symbols('l m g', real=True) frame_n = _me.ReferenceFrame('n') frame_a = _me.ReferenceFrame('a') frame_b = _me.ReferenceFrame('b') frame_a.orient(frame_n, 'Axis', [q1, frame_n.z]) frame_b.orient(frame_n, 'Axis', [q2, frame_n.z]) frame_a.set_ang_vel(frame_n, u1*frame_n.z) frame_b.set_ang_vel(frame_n, u2*frame_n.z) point_o = _me.Point('o') particle_p = _me.Particle('p', _me.Point('p_pt'), _sm.Symbol('m')) particle_r = _me.Particle('r', _me.Point('r_pt'), _sm.Symbol('m')) particle_p.point.set_pos(point_o, l*frame_a.x) particle_r.point.set_pos(particle_p.point, l*frame_b.x) point_o.set_vel(frame_n, 0) particle_p.point.v2pt_theory(point_o,frame_n,frame_a) particle_r.point.v2pt_theory(particle_p.point,frame_n,frame_b) particle_p.mass = m particle_r.mass = m force_p = particle_p.mass*(g*frame_n.x) force_r = particle_r.mass*(g*frame_n.x) kd_eqs = [q1_d - u1, q2_d - u2] forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x)), (particle_r.point,particle_r.mass*(g*frame_n.x))] kane = _me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u1, u2], kd_eqs = kd_eqs) fr, frstar = kane.kanes_equations([particle_p, particle_r], forceList) zero = fr+frstar from pydy.system import System sys = System(kane, constants = {l:1, m:1, g:9.81}, specifieds={}, initial_conditions={q1:.1, q2:.2, u1:0, u2:0}, times = _np.linspace(0.0, 10, 10/.01)) y=sys.integrate() sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/mass_spring_damper.al000066400000000000000000000007711412543434000326020ustar00rootroot00000000000000CONSTANTS M,K,B,G MOTIONVARIABLES' POSITION',SPEED' VARIABLES O FORCE = O*SIN(T) NEWTONIAN CEILING POINTS ORIGIN V_ORIGIN_CEILING> = 0> PARTICLES BLOCK P_ORIGIN_BLOCK> = POSITION*CEILING1> MASS BLOCK=M V_BLOCK_CEILING>=SPEED*CEILING1> POSITION' = SPEED FORCE_MAGNITUDE = M*G-K*POSITION-B*SPEED+FORCE FORCE_BLOCK>=EXPLICIT(FORCE_MAGNITUDE*CEILING1>) ZERO = FR() + FRSTAR() KANE() INPUT TFINAL=10.0, INTEGSTP=0.01 INPUT M=1.0, K=1.0, B=0.2, G=9.8, POSITION=0.1, SPEED=-1.0, O=2 CODE DYNAMICS() dummy_file.c sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/mass_spring_damper.py000066400000000000000000000025261412543434000326360ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np m, k, b, g = _sm.symbols('m k b g', real=True) position, speed = _me.dynamicsymbols('position speed') position_d, speed_d = _me.dynamicsymbols('position_ speed_', 1) o = _me.dynamicsymbols('o') force = o*_sm.sin(_me.dynamicsymbols._t) frame_ceiling = _me.ReferenceFrame('ceiling') point_origin = _me.Point('origin') point_origin.set_vel(frame_ceiling, 0) particle_block = _me.Particle('block', _me.Point('block_pt'), _sm.Symbol('m')) particle_block.point.set_pos(point_origin, position*frame_ceiling.x) particle_block.mass = m particle_block.point.set_vel(frame_ceiling, speed*frame_ceiling.x) force_magnitude = m*g-k*position-b*speed+force force_block = (force_magnitude*frame_ceiling.x).subs({position_d:speed}) kd_eqs = [position_d - speed] forceList = [(particle_block.point,(force_magnitude*frame_ceiling.x).subs({position_d:speed}))] kane = _me.KanesMethod(frame_ceiling, q_ind=[position], u_ind=[speed], kd_eqs = kd_eqs) fr, frstar = kane.kanes_equations([particle_block], forceList) zero = fr+frstar from pydy.system import System sys = System(kane, constants = {m:1.0, k:1.0, b:0.2, g:9.8}, specifieds={_me.dynamicsymbols('t'):lambda x, t: t, o:2}, initial_conditions={position:0.1, speed:-1*1.0}, times = _np.linspace(0.0, 10.0, 10.0/0.01)) y=sys.integrate() sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/non_min_pendulum.al000066400000000000000000000005521412543434000322700ustar00rootroot00000000000000MOTIONVARIABLES' Q{2}'' CONSTANTS L,M,G NEWTONIAN N POINT PN V_PN_N> = 0> THETA1 = ATAN(Q2/Q1) FRAMES A SIMPROT(N, A, 3, THETA1) PARTICLES P P_PN_P> = Q1*N1>+Q2*N2> MASS P=M V_P_N>=DT(P_P_PN>, N) F_V = DOT(EXPRESS(V_P_N>,A), A1>) GRAVITY(G*N1>) DEPENDENT[1] = F_V CONSTRAIN(DEPENDENT[Q1']) ZERO=FR()+FRSTAR() F_C = MAG(P_P_PN>)-L CONFIG[1]=F_C ZERO[2]=CONFIG[1] sympy-sympy-1.9/sympy/parsing/autolev/test-examples/pydy-example-repo/non_min_pendulum.py000066400000000000000000000027371412543434000323330ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np q1, q2 = _me.dynamicsymbols('q1 q2') q1_d, q2_d = _me.dynamicsymbols('q1_ q2_', 1) q1_dd, q2_dd = _me.dynamicsymbols('q1_ q2_', 2) l, m, g = _sm.symbols('l m g', real=True) frame_n = _me.ReferenceFrame('n') point_pn = _me.Point('pn') point_pn.set_vel(frame_n, 0) theta1 = _sm.atan(q2/q1) frame_a = _me.ReferenceFrame('a') frame_a.orient(frame_n, 'Axis', [theta1, frame_n.z]) particle_p = _me.Particle('p', _me.Point('p_pt'), _sm.Symbol('m')) particle_p.point.set_pos(point_pn, q1*frame_n.x+q2*frame_n.y) particle_p.mass = m particle_p.point.set_vel(frame_n, (point_pn.pos_from(particle_p.point)).dt(frame_n)) f_v = _me.dot((particle_p.point.vel(frame_n)).express(frame_a), frame_a.x) force_p = particle_p.mass*(g*frame_n.x) dependent = _sm.Matrix([[0]]) dependent[0] = f_v velocity_constraints = [i for i in dependent] u_q1_d = _me.dynamicsymbols('u_q1_d') u_q2_d = _me.dynamicsymbols('u_q2_d') kd_eqs = [q1_d-u_q1_d, q2_d-u_q2_d] forceList = [(particle_p.point,particle_p.mass*(g*frame_n.x))] kane = _me.KanesMethod(frame_n, q_ind=[q1,q2], u_ind=[u_q2_d], u_dependent=[u_q1_d], kd_eqs = kd_eqs, velocity_constraints = velocity_constraints) fr, frstar = kane.kanes_equations([particle_p], forceList) zero = fr+frstar f_c = point_pn.pos_from(particle_p.point).magnitude()-l config = _sm.Matrix([[0]]) config[0] = f_c zero = zero.row_insert(zero.shape[0], _sm.Matrix([[0]])) zero[zero.shape[0]-1] = config[0] sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest1.al000066400000000000000000000002601412543434000252650ustar00rootroot00000000000000% ruletest1.al CONSTANTS F = 3, G = 9.81 CONSTANTS A, B CONSTANTS S, S1, S2+, S3+, S4- CONSTANTS K{4}, L{1:3}, P{1:2,1:3} CONSTANTS C{2,3} E1 = A*F + S2 - G E2 = F^2 + K3*K2*G sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest1.py000066400000000000000000000010531412543434000253220ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np f = _sm.S(3) g = _sm.S(9.81) a, b = _sm.symbols('a b', real=True) s, s1 = _sm.symbols('s s1', real=True) s2, s3 = _sm.symbols('s2 s3', real=True, nonnegative=True) s4 = _sm.symbols('s4', real=True, nonpositive=True) k1, k2, k3, k4, l1, l2, l3, p11, p12, p13, p21, p22, p23 = _sm.symbols('k1 k2 k3 k4 l1 l2 l3 p11 p12 p13 p21 p22 p23', real=True) c11, c12, c13, c21, c22, c23 = _sm.symbols('c11 c12 c13 c21 c22 c23', real=True) e1 = a*f+s2-g e2 = f**2+k3*k2*g sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest10.al000066400000000000000000000014151412543434000253500ustar00rootroot00000000000000% ruletest10.al VARIABLES X,Y COMPLEX ON CONSTANTS A,B E = A*(B*X+Y)^2 M = [E;E] EXPAND(E) EXPAND(M) FACTOR(E,X) FACTOR(M,X) EQN[1] = A*X + B*Y EQN[2] = 2*A*X - 3*B*Y SOLVE(EQN, X, Y) RHS_Y = RHS(Y) E = (X+Y)^2 + 2*X^2 ARRANGE(E, 2, X) CONSTANTS A,B,C M = [A,B;C,0] M2 = EVALUATE(M,A=1,B=2,C=3) EIG(M2, EIGVALUE, EIGVEC) NEWTONIAN N FRAMES A SIMPROT(N, A, N1>, X) DEGREES OFF SIMPROT(N, A, N1>, PI/2) CONSTANTS C{3} V> = C1*A1> + C2*A2> + C3*A3> POINTS O, P P_P_O> = C1*A1> EXPRESS(V>,N) EXPRESS(P_P_O>,N) W_A_N> = C3*A3> ANGVEL(A,N) V2PTS(N,A,O,P) PARTICLES P{2} V2PTS(N,A,P1,P2) A2PTS(N,A,P1,P) BODIES B{2} CONSTANT G GRAVITY(G*N1>) VARIABLE Z V> = X*A1> + Y*A3> P_P_O> = X*A1> + Y*A2> X = 2*Z Y = Z EXPLICIT(V>) EXPLICIT(P_P_O>) FORCE(O/P1, X*Y*A1>) FORCE(P2, X*Y*A1>) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest10.py000066400000000000000000000052461412543434000254120ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np x, y = _me.dynamicsymbols('x y') a, b = _sm.symbols('a b', real=True) e = a*(b*x+y)**2 m = _sm.Matrix([e,e]).reshape(2, 1) e = e.expand() m = _sm.Matrix([i.expand() for i in m]).reshape((m).shape[0], (m).shape[1]) e = _sm.factor(e, x) m = _sm.Matrix([_sm.factor(i,x) for i in m]).reshape((m).shape[0], (m).shape[1]) eqn = _sm.Matrix([[0]]) eqn[0] = a*x+b*y eqn = eqn.row_insert(eqn.shape[0], _sm.Matrix([[0]])) eqn[eqn.shape[0]-1] = 2*a*x-3*b*y print(_sm.solve(eqn,x,y)) rhs_y = _sm.solve(eqn,x,y)[y] e = (x+y)**2+2*x**2 e.collect(x) a, b, c = _sm.symbols('a b c', real=True) m = _sm.Matrix([a,b,c,0]).reshape(2, 2) m2 = _sm.Matrix([i.subs({a:1,b:2,c:3}) for i in m]).reshape((m).shape[0], (m).shape[1]) eigvalue = _sm.Matrix([i.evalf() for i in (m2).eigenvals().keys()]) eigvec = _sm.Matrix([i[2][0].evalf() for i in (m2).eigenvects()]).reshape(m2.shape[0], m2.shape[1]) frame_n = _me.ReferenceFrame('n') frame_a = _me.ReferenceFrame('a') frame_a.orient(frame_n, 'Axis', [x, frame_n.x]) frame_a.orient(frame_n, 'Axis', [_sm.pi/2, frame_n.x]) c1, c2, c3 = _sm.symbols('c1 c2 c3', real=True) v = c1*frame_a.x+c2*frame_a.y+c3*frame_a.z point_o = _me.Point('o') point_p = _me.Point('p') point_o.set_pos(point_p, c1*frame_a.x) v = (v).express(frame_n) point_o.set_pos(point_p, (point_o.pos_from(point_p)).express(frame_n)) frame_a.set_ang_vel(frame_n, c3*frame_a.z) print(frame_n.ang_vel_in(frame_a)) point_p.v2pt_theory(point_o,frame_n,frame_a) particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m')) particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m')) particle_p2.point.v2pt_theory(particle_p1.point,frame_n,frame_a) point_p.a2pt_theory(particle_p1.point,frame_n,frame_a) body_b1_cm = _me.Point('b1_cm') body_b1_cm.set_vel(frame_n, 0) body_b1_f = _me.ReferenceFrame('b1_f') body_b1 = _me.RigidBody('b1', body_b1_cm, body_b1_f, _sm.symbols('m'), (_me.outer(body_b1_f.x,body_b1_f.x),body_b1_cm)) body_b2_cm = _me.Point('b2_cm') body_b2_cm.set_vel(frame_n, 0) body_b2_f = _me.ReferenceFrame('b2_f') body_b2 = _me.RigidBody('b2', body_b2_cm, body_b2_f, _sm.symbols('m'), (_me.outer(body_b2_f.x,body_b2_f.x),body_b2_cm)) g = _sm.symbols('g', real=True) force_p1 = particle_p1.mass*(g*frame_n.x) force_p2 = particle_p2.mass*(g*frame_n.x) force_b1 = body_b1.mass*(g*frame_n.x) force_b2 = body_b2.mass*(g*frame_n.x) z = _me.dynamicsymbols('z') v = x*frame_a.x+y*frame_a.z point_o.set_pos(point_p, x*frame_a.x+y*frame_a.y) v = (v).subs({x:2*z, y:z}) point_o.set_pos(point_p, (point_o.pos_from(point_p)).subs({x:2*z, y:z})) force_o = -1*(x*y*frame_a.x) force_p1 = particle_p1.mass*(g*frame_n.x)+ x*y*frame_a.x sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest11.al000066400000000000000000000002741412543434000253530ustar00rootroot00000000000000VARIABLES X, Y CONSTANTS A{1:2, 1:2}, B{1:2} EQN[1] = A11*x + A12*y - B1 EQN[2] = A21*x + A22*y - B2 INPUT A11=2, A12=5, A21=3, A22=4, B1=7, B2=6 CODE ALGEBRAIC(EQN, X, Y) some_filename.c sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest11.py000066400000000000000000000007331412543434000254070ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np x, y = _me.dynamicsymbols('x y') a11, a12, a21, a22, b1, b2 = _sm.symbols('a11 a12 a21 a22 b1 b2', real=True) eqn = _sm.Matrix([[0]]) eqn[0] = a11*x+a12*y-b1 eqn = eqn.row_insert(eqn.shape[0], _sm.Matrix([[0]])) eqn[eqn.shape[0]-1] = a21*x+a22*y-b2 eqn_list = [] for i in eqn: eqn_list.append(i.subs({a11:2, a12:5, a21:3, a22:4, b1:7, b2:6})) print(_sm.linsolve(eqn_list, x,y)) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest12.al000066400000000000000000000002711412543434000253510ustar00rootroot00000000000000VARIABLES X,Y CONSTANTS A,B,R EQN[1] = A*X^3+B*Y^2-R EQN[2] = A*SIN(X)^2 + B*COS(2*Y) - R^2 INPUT A=2.0, B=3.0, R=1.0 INPUT X = 30 DEG, Y = 3.14 CODE NONLINEAR(EQN,X,Y) some_filename.c sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest12.py000066400000000000000000000007301412543434000254050ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np x, y = _me.dynamicsymbols('x y') a, b, r = _sm.symbols('a b r', real=True) eqn = _sm.Matrix([[0]]) eqn[0] = a*x**3+b*y**2-r eqn = eqn.row_insert(eqn.shape[0], _sm.Matrix([[0]])) eqn[eqn.shape[0]-1] = a*_sm.sin(x)**2+b*_sm.cos(2*y)-r**2 matrix_list = [] for i in eqn:matrix_list.append(i.subs({a:2.0, b:3.0, r:1.0})) print(_sm.nsolve(matrix_list,(x,y),(_np.deg2rad(30),3.14))) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest2.al000066400000000000000000000003551412543434000252730ustar00rootroot00000000000000% ruletest2.al VARIABLES X1,X2 SPECIFIED F1 = X1*X2 + 3*X1^2 SPECIFIED F2=X1*T+X2*T^2 VARIABLE X', Y'' MOTIONVARIABLES Q{3}, U{2} VARIABLES P{2}' VARIABLE W{3}', R{2}'' VARIABLES C{1:2, 1:2} VARIABLES D{1,3} VARIABLES J{1:2} IMAGINARY N sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest2.py000066400000000000000000000014641412543434000253310ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np x1, x2 = _me.dynamicsymbols('x1 x2') f1 = x1*x2+3*x1**2 f2 = x1*_me.dynamicsymbols._t+x2*_me.dynamicsymbols._t**2 x, y = _me.dynamicsymbols('x y') x_d, y_d = _me.dynamicsymbols('x_ y_', 1) y_dd = _me.dynamicsymbols('y_', 2) q1, q2, q3, u1, u2 = _me.dynamicsymbols('q1 q2 q3 u1 u2') p1, p2 = _me.dynamicsymbols('p1 p2') p1_d, p2_d = _me.dynamicsymbols('p1_ p2_', 1) w1, w2, w3, r1, r2 = _me.dynamicsymbols('w1 w2 w3 r1 r2') w1_d, w2_d, w3_d, r1_d, r2_d = _me.dynamicsymbols('w1_ w2_ w3_ r1_ r2_', 1) r1_dd, r2_dd = _me.dynamicsymbols('r1_ r2_', 2) c11, c12, c21, c22 = _me.dynamicsymbols('c11 c12 c21 c22') d11, d12, d13 = _me.dynamicsymbols('d11 d12 d13') j1, j2 = _me.dynamicsymbols('j1 j2') n = _sm.symbols('n') n = _sm.I sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest3.al000066400000000000000000000004641412543434000252750ustar00rootroot00000000000000% ruletest3.al FRAMES A, B NEWTONIAN N VARIABLES X{3} CONSTANTS L V1> = X1*A1> + X2*A2> + X3*A3> V2> = X1*B1> + X2*B2> + X3*B3> V3> = X1*N1> + X2*N2> + X3*N3> V> = V1> + V2> + V3> POINTS C, D POINTS PO{3} PARTICLES L PARTICLES P{3} BODIES S BODIES R{2} V4> = X1*S1> + X2*S2> + X3*S3> P_C_SO> = L*N1> sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest3.py000066400000000000000000000030461412543434000253300ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np frame_a = _me.ReferenceFrame('a') frame_b = _me.ReferenceFrame('b') frame_n = _me.ReferenceFrame('n') x1, x2, x3 = _me.dynamicsymbols('x1 x2 x3') l = _sm.symbols('l', real=True) v1 = x1*frame_a.x+x2*frame_a.y+x3*frame_a.z v2 = x1*frame_b.x+x2*frame_b.y+x3*frame_b.z v3 = x1*frame_n.x+x2*frame_n.y+x3*frame_n.z v = v1+v2+v3 point_c = _me.Point('c') point_d = _me.Point('d') point_po1 = _me.Point('po1') point_po2 = _me.Point('po2') point_po3 = _me.Point('po3') particle_l = _me.Particle('l', _me.Point('l_pt'), _sm.Symbol('m')) particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m')) particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m')) particle_p3 = _me.Particle('p3', _me.Point('p3_pt'), _sm.Symbol('m')) body_s_cm = _me.Point('s_cm') body_s_cm.set_vel(frame_n, 0) body_s_f = _me.ReferenceFrame('s_f') body_s = _me.RigidBody('s', body_s_cm, body_s_f, _sm.symbols('m'), (_me.outer(body_s_f.x,body_s_f.x),body_s_cm)) body_r1_cm = _me.Point('r1_cm') body_r1_cm.set_vel(frame_n, 0) body_r1_f = _me.ReferenceFrame('r1_f') body_r1 = _me.RigidBody('r1', body_r1_cm, body_r1_f, _sm.symbols('m'), (_me.outer(body_r1_f.x,body_r1_f.x),body_r1_cm)) body_r2_cm = _me.Point('r2_cm') body_r2_cm.set_vel(frame_n, 0) body_r2_f = _me.ReferenceFrame('r2_f') body_r2 = _me.RigidBody('r2', body_r2_cm, body_r2_f, _sm.symbols('m'), (_me.outer(body_r2_f.x,body_r2_f.x),body_r2_cm)) v4 = x1*body_s_f.x+x2*body_s_f.y+x3*body_s_f.z body_s_cm.set_pos(point_c, l*frame_n.x) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest4.al000066400000000000000000000004561412543434000252770ustar00rootroot00000000000000% ruletest4.al FRAMES A, B MOTIONVARIABLES Q{3} SIMPROT(A, B, 1, Q3) DCM = A_B M = DCM*3 - A_B VARIABLES R CIRCLE_AREA = PI*R^2 VARIABLES U, A VARIABLES X, Y S = U*T - 1/2*A*T^2 EXPR1 = 2*A*0.5 - 1.25 + 0.25 EXPR2 = -X^2 + Y^2 + 0.25*(X+Y)^2 EXPR3 = 0.5E-10 DYADIC>> = A1>*A1> + A2>*A2> + A3>*A3> sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest4.py000066400000000000000000000012521412543434000253260ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np frame_a = _me.ReferenceFrame('a') frame_b = _me.ReferenceFrame('b') q1, q2, q3 = _me.dynamicsymbols('q1 q2 q3') frame_b.orient(frame_a, 'Axis', [q3, frame_a.x]) dcm = frame_a.dcm(frame_b) m = dcm*3-frame_a.dcm(frame_b) r = _me.dynamicsymbols('r') circle_area = _sm.pi*r**2 u, a = _me.dynamicsymbols('u a') x, y = _me.dynamicsymbols('x y') s = u*_me.dynamicsymbols._t-1/2*a*_me.dynamicsymbols._t**2 expr1 = 2*a*0.5-1.25+0.25 expr2 = -1*x**2+y**2+0.25*(x+y)**2 expr3 = 0.5*10**(-10) dyadic = _me.outer(frame_a.x, frame_a.x)+_me.outer(frame_a.y, frame_a.y)+_me.outer(frame_a.z, frame_a.z) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest5.al000066400000000000000000000010041412543434000252660ustar00rootroot00000000000000% ruletest5.al VARIABLES X', Y' E1 = (X+Y)^2 + (X-Y)^3 E2 = (X-Y)^2 E3 = X^2 + Y^2 + 2*X*Y M1 = [E1;E2] M2 = [(X+Y)^2,(X-Y)^2] M3 = M1 + [X;Y] AM = EXPAND(M1) CM = EXPAND([(X+Y)^2,(X-Y)^2]) EM = EXPAND(M1 + [X;Y]) F = EXPAND(E1) G = EXPAND(E2) A = FACTOR(E3, X) BM = FACTOR(M1, X) CM = FACTOR(M1 + [X;Y], X) A = D(E3, X) B = D(E3, Y) CM = D(M2, X) DM = D(M1 + [X;Y], X) FRAMES A, B A_B = [1,0,0;1,0,0;1,0,0] V1> = X*A1> + Y*A2> + X*Y*A3> E> = D(V1>, X, B) FM = DT(M1) GM = DT([(X+Y)^2,(X-Y)^2]) H> = DT(V1>, B) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest5.py000066400000000000000000000037071412543434000253360ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np x, y = _me.dynamicsymbols('x y') x_d, y_d = _me.dynamicsymbols('x_ y_', 1) e1 = (x+y)**2+(x-y)**3 e2 = (x-y)**2 e3 = x**2+y**2+2*x*y m1 = _sm.Matrix([e1,e2]).reshape(2, 1) m2 = _sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2) m3 = m1+_sm.Matrix([x,y]).reshape(2, 1) am = _sm.Matrix([i.expand() for i in m1]).reshape((m1).shape[0], (m1).shape[1]) cm = _sm.Matrix([i.expand() for i in _sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)]).reshape((_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[0], (_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[1]) em = _sm.Matrix([i.expand() for i in m1+_sm.Matrix([x,y]).reshape(2, 1)]).reshape((m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[0], (m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[1]) f = (e1).expand() g = (e2).expand() a = _sm.factor((e3), x) bm = _sm.Matrix([_sm.factor(i, x) for i in m1]).reshape((m1).shape[0], (m1).shape[1]) cm = _sm.Matrix([_sm.factor(i, x) for i in m1+_sm.Matrix([x,y]).reshape(2, 1)]).reshape((m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[0], (m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[1]) a = (e3).diff(x) b = (e3).diff(y) cm = _sm.Matrix([i.diff(x) for i in m2]).reshape((m2).shape[0], (m2).shape[1]) dm = _sm.Matrix([i.diff(x) for i in m1+_sm.Matrix([x,y]).reshape(2, 1)]).reshape((m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[0], (m1+_sm.Matrix([x,y]).reshape(2, 1)).shape[1]) frame_a = _me.ReferenceFrame('a') frame_b = _me.ReferenceFrame('b') frame_b.orient(frame_a, 'DCM', _sm.Matrix([1,0,0,1,0,0,1,0,0]).reshape(3, 3)) v1 = x*frame_a.x+y*frame_a.y+x*y*frame_a.z e = (v1).diff(x, frame_b) fm = _sm.Matrix([i.diff(_sm.Symbol('t')) for i in m1]).reshape((m1).shape[0], (m1).shape[1]) gm = _sm.Matrix([i.diff(_sm.Symbol('t')) for i in _sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)]).reshape((_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[0], (_sm.Matrix([(x+y)**2,(x-y)**2]).reshape(1, 2)).shape[1]) h = (v1).dt(frame_b) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest6.al000066400000000000000000000012771412543434000253030ustar00rootroot00000000000000% ruletest6.al VARIABLES Q{2} VARIABLES X,Y,Z Q1 = X^2 + Y^2 Q2 = X-Y E = Q1 + Q2 A = EXPLICIT(E) E2 = COS(X) E3 = COS(X*Y) A = TAYLOR(E2, 0:2, X=0) B = TAYLOR(E3, 0:2, X=0, Y=0) E = EXPAND((X+Y)^2) A = EVALUATE(E, X=1, Y=Z) BM = EVALUATE([E;2*E], X=1, Y=Z) E = Q1 + Q2 A = EVALUATE(E, X=2, Y=Z^2) CONSTANTS J,K,L P1 = POLYNOMIAL([J,K,L],X) P2 = POLYNOMIAL(J*X+K,X,1) ROOT1 = ROOTS(P1, X, 2) ROOT2 = ROOTS([1;2;3]) M = [1,2,3,4;5,6,7,8;9,10,11,12;13,14,15,16] AM = TRANSPOSE(M) + M BM = EIG(M) C1 = DIAGMAT(4, 1) C2 = DIAGMAT(3, 4, 2) DM = INV(M+C1) E = DET(M+C1) + TRACE([1,0;0,1]) F = ELEMENT(M, 2, 3) A = COLS(M) BM = COLS(M, 1) CM = COLS(M, 1, 2:4, 3) DM = ROWS(M, 1) EM = ROWS(M, 1, 2:4, 3) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest6.py000066400000000000000000000027011412543434000253300ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np q1, q2 = _me.dynamicsymbols('q1 q2') x, y, z = _me.dynamicsymbols('x y z') e = q1+q2 a = (e).subs({q1:x**2+y**2, q2:x-y}) e2 = _sm.cos(x) e3 = _sm.cos(x*y) a = (e2).series(x, 0, 2).removeO() b = (e3).series(x, 0, 2).removeO().series(y, 0, 2).removeO() e = ((x+y)**2).expand() a = (e).subs({q1:x**2+y**2,q2:x-y}).subs({x:1,y:z}) bm = _sm.Matrix([i.subs({x:1,y:z}) for i in _sm.Matrix([e,2*e]).reshape(2, 1)]).reshape((_sm.Matrix([e,2*e]).reshape(2, 1)).shape[0], (_sm.Matrix([e,2*e]).reshape(2, 1)).shape[1]) e = q1+q2 a = (e).subs({q1:x**2+y**2,q2:x-y}).subs({x:2,y:z**2}) j, k, l = _sm.symbols('j k l', real=True) p1 = _sm.Poly(_sm.Matrix([j,k,l]).reshape(1, 3), x) p2 = _sm.Poly(j*x+k, x) root1 = [i.evalf() for i in _sm.solve(p1, x)] root2 = [i.evalf() for i in _sm.solve(_sm.Poly(_sm.Matrix([1,2,3]).reshape(3, 1), x),x)] m = _sm.Matrix([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]).reshape(4, 4) am = (m).T+m bm = _sm.Matrix([i.evalf() for i in (m).eigenvals().keys()]) c1 = _sm.diag(1,1,1,1) c2 = _sm.Matrix([2 if i==j else 0 for i in range(3) for j in range(4)]).reshape(3, 4) dm = (m+c1)**(-1) e = (m+c1).det()+(_sm.Matrix([1,0,0,1]).reshape(2, 2)).trace() f = (m)[1,2] a = (m).cols bm = (m).col(0) cm = _sm.Matrix([(m).T.row(0),(m).T.row(1),(m).T.row(2),(m).T.row(3),(m).T.row(2)]) dm = (m).row(0) em = _sm.Matrix([(m).row(0),(m).row(1),(m).row(2),(m).row(3),(m).row(2)]) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest7.al000066400000000000000000000014051412543434000252750ustar00rootroot00000000000000% ruletest7.al VARIABLES X', Y' E = COS(X) + SIN(X) + TAN(X)& + COSH(X) + SINH(X) + TANH(X)& + ACOS(X) + ASIN(X) + ATAN(X)& + LOG(X) + EXP(X) + SQRT(X)& + FACTORIAL(X) + CEIL(X) +& FLOOR(X) + SIGN(X) E = SQR(X) + LOG10(X) A = ABS(-1) + INT(1.5) + ROUND(1.9) E1 = 2*X + 3*Y E2 = X + Y AM = COEF([E1;E2], [X,Y]) B = COEF(E1, X) C = COEF(E2, Y) D1 = EXCLUDE(E1, X) D2 = INCLUDE(E1, X) FM = ARRANGE([E1,E2],2,X) F = ARRANGE(E1, 2, Y) G = REPLACE(E1, X=2*X) GM = REPLACE([E1;E2], X=3) FRAMES A, B VARIABLES THETA SIMPROT(A,B,3,THETA) V1> = 2*A1> - 3*A2> + A3> V2> = B1> + B2> + B3> A = DOT(V1>, V2>) BM = DOT(V1>, [V2>;2*V2>]) C> = CROSS(V1>,V2>) D = MAG(2*V1>) + MAG(3*V1>) DYADIC>> = 3*A1>*A1> + A2>*A2> + 2*A3>*A3> AM = MATRIX(B, DYADIC>>) M = [1;2;3] V> = VECTOR(A, M) sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest7.py000066400000000000000000000032401412543434000253300ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np x, y = _me.dynamicsymbols('x y') x_d, y_d = _me.dynamicsymbols('x_ y_', 1) e = _sm.cos(x)+_sm.sin(x)+_sm.tan(x)+_sm.cosh(x)+_sm.sinh(x)+_sm.tanh(x)+_sm.acos(x)+_sm.asin(x)+_sm.atan(x)+_sm.log(x)+_sm.exp(x)+_sm.sqrt(x)+_sm.factorial(x)+_sm.ceiling(x)+_sm.floor(x)+_sm.sign(x) e = (x)**2+_sm.log(x, 10) a = _sm.Abs(-1*1)+int(1.5)+round(1.9) e1 = 2*x+3*y e2 = x+y am = _sm.Matrix([e1.expand().coeff(x), e1.expand().coeff(y), e2.expand().coeff(x), e2.expand().coeff(y)]).reshape(2, 2) b = (e1).expand().coeff(x) c = (e2).expand().coeff(y) d1 = (e1).collect(x).coeff(x,0) d2 = (e1).collect(x).coeff(x,1) fm = _sm.Matrix([i.collect(x)for i in _sm.Matrix([e1,e2]).reshape(1, 2)]).reshape((_sm.Matrix([e1,e2]).reshape(1, 2)).shape[0], (_sm.Matrix([e1,e2]).reshape(1, 2)).shape[1]) f = (e1).collect(y) g = (e1).subs({x:2*x}) gm = _sm.Matrix([i.subs({x:3}) for i in _sm.Matrix([e1,e2]).reshape(2, 1)]).reshape((_sm.Matrix([e1,e2]).reshape(2, 1)).shape[0], (_sm.Matrix([e1,e2]).reshape(2, 1)).shape[1]) frame_a = _me.ReferenceFrame('a') frame_b = _me.ReferenceFrame('b') theta = _me.dynamicsymbols('theta') frame_b.orient(frame_a, 'Axis', [theta, frame_a.z]) v1 = 2*frame_a.x-3*frame_a.y+frame_a.z v2 = frame_b.x+frame_b.y+frame_b.z a = _me.dot(v1, v2) bm = _sm.Matrix([_me.dot(v1, v2),_me.dot(v1, 2*v2)]).reshape(2, 1) c = _me.cross(v1, v2) d = 2*v1.magnitude()+3*v1.magnitude() dyadic = _me.outer(3*frame_a.x, frame_a.x)+_me.outer(frame_a.y, frame_a.y)+_me.outer(2*frame_a.z, frame_a.z) am = (dyadic).to_matrix(frame_b) m = _sm.Matrix([1,2,3]).reshape(3, 1) v = m[0]*frame_a.x +m[1]*frame_a.y +m[2]*frame_a.z sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest8.al000066400000000000000000000012521412543434000252760ustar00rootroot00000000000000% ruletest8.al FRAMES A CONSTANTS C{3} A>> = EXPRESS(1>>,A) PARTICLES P1, P2 BODIES R R_A = [1,1,1;1,1,0;0,0,1] POINT O MASS P1=M1, P2=M2, R=MR INERTIA R, I1, I2, I3 P_P1_O> = C1*A1> P_P2_O> = C2*A2> P_RO_O> = C3*A3> A>> = EXPRESS(I_P1_O>>, A) A>> = EXPRESS(I_P2_O>>, A) A>> = EXPRESS(I_R_O>>, A) A>> = EXPRESS(INERTIA(O), A) A>> = EXPRESS(INERTIA(O, P1, R), A) A>> = EXPRESS(I_R_O>>, A) A>> = EXPRESS(I_R_RO>>, A) P_P1_P2> = C1*A1> + C2*A2> P_P1_RO> = C3*A1> P_P2_RO> = C3*A2> B> = CM(O) B> = CM(O, P1, R) B> = CM(P1) MOTIONVARIABLES U{3} V> = U1*A1> + U2*A2> + U3*A3> U> = UNITVEC(V> + C1*A1>) V_P1_A> = U1*A1> A> = PARTIALS(V_P1_A>, U1) M = MASS(P1,R) M = MASS(P2) M = MASS()sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest8.py000066400000000000000000000052021412543434000253310ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np frame_a = _me.ReferenceFrame('a') c1, c2, c3 = _sm.symbols('c1 c2 c3', real=True) a = _me.inertia(frame_a, 1, 1, 1) particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m')) particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m')) body_r_cm = _me.Point('r_cm') body_r_f = _me.ReferenceFrame('r_f') body_r = _me.RigidBody('r', body_r_cm, body_r_f, _sm.symbols('m'), (_me.outer(body_r_f.x,body_r_f.x),body_r_cm)) frame_a.orient(body_r_f, 'DCM', _sm.Matrix([1,1,1,1,1,0,0,0,1]).reshape(3, 3)) point_o = _me.Point('o') m1 = _sm.symbols('m1') particle_p1.mass = m1 m2 = _sm.symbols('m2') particle_p2.mass = m2 mr = _sm.symbols('mr') body_r.mass = mr i1 = _sm.symbols('i1') i2 = _sm.symbols('i2') i3 = _sm.symbols('i3') body_r.inertia = (_me.inertia(body_r_f, i1, i2, i3, 0, 0, 0), body_r_cm) point_o.set_pos(particle_p1.point, c1*frame_a.x) point_o.set_pos(particle_p2.point, c2*frame_a.y) point_o.set_pos(body_r_cm, c3*frame_a.z) a = _me.inertia_of_point_mass(particle_p1.mass, particle_p1.point.pos_from(point_o), frame_a) a = _me.inertia_of_point_mass(particle_p2.mass, particle_p2.point.pos_from(point_o), frame_a) a = body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a) a = _me.inertia_of_point_mass(particle_p1.mass, particle_p1.point.pos_from(point_o), frame_a) + _me.inertia_of_point_mass(particle_p2.mass, particle_p2.point.pos_from(point_o), frame_a) + body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a) a = _me.inertia_of_point_mass(particle_p1.mass, particle_p1.point.pos_from(point_o), frame_a) + body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a) a = body_r.inertia[0] + _me.inertia_of_point_mass(body_r.mass, body_r.masscenter.pos_from(point_o), frame_a) a = body_r.inertia[0] particle_p2.point.set_pos(particle_p1.point, c1*frame_a.x+c2*frame_a.y) body_r_cm.set_pos(particle_p1.point, c3*frame_a.x) body_r_cm.set_pos(particle_p2.point, c3*frame_a.y) b = _me.functions.center_of_mass(point_o,particle_p1, particle_p2, body_r) b = _me.functions.center_of_mass(point_o,particle_p1, body_r) b = _me.functions.center_of_mass(particle_p1.point,particle_p1, particle_p2, body_r) u1, u2, u3 = _me.dynamicsymbols('u1 u2 u3') v = u1*frame_a.x+u2*frame_a.y+u3*frame_a.z u = (v+c1*frame_a.x).normalize() particle_p1.point.set_vel(frame_a, u1*frame_a.x) a = particle_p1.point.partial_velocity(frame_a, u1) m = particle_p1.mass+body_r.mass m = particle_p2.mass m = particle_p1.mass+particle_p2.mass+body_r.mass sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest9.al000066400000000000000000000013631412543434000253020ustar00rootroot00000000000000% ruletest9.al NEWTONIAN N FRAMES A A> = 0> D>> = EXPRESS(1>>, A) POINTS PO{2} PARTICLES P{2} MOTIONVARIABLES' C{3}' BODIES R P_P1_PO2> = C1*A1> V> = 2*P_P1_PO2> + C2*A2> W_A_N> = C3*A3> V> = 2*W_A_N> + C2*A2> W_R_N> = C3*A3> V> = 2*W_R_N> + C2*A2> ALF_A_N> = DT(W_A_N>, A) V> = 2*ALF_A_N> + C2*A2> V_P1_A> = C1*A1> + C3*A2> A_RO_N> = C2*A2> V_A> = CROSS(A_RO_N>, V_P1_A>) X_B_C> = V_A> X_B_D> = 2*X_B_C> A_B_C_D_E> = X_B_D>*2 A_B_C = 2*C1*C2*C3 A_B_C += 2*C1 A_B_C := 3*C1 MOTIONVARIABLES' Q{2}', U{2}' Q1' = U1 Q2' = U2 VARIABLES X'', Y'' SPECIFIED YY Y'' = X*X'^2 + 1 YY = X*X'^2 + 1 M[1] = 2*X M[2] = 2*Y A = 2*M[1] M = [1,2,3;4,5,6;7,8,9] M[1, 2] = 5 A = M[1, 2]*2 FORCE_RO> = Q1*N1> TORQUE_A> = Q2*N3> FORCE_RO> = Q2*N2> F> = FORCE_RO>*2 sympy-sympy-1.9/sympy/parsing/autolev/test-examples/ruletest9.py000066400000000000000000000036551412543434000253440ustar00rootroot00000000000000import sympy.physics.mechanics as _me import sympy as _sm import math as m import numpy as _np frame_n = _me.ReferenceFrame('n') frame_a = _me.ReferenceFrame('a') a = 0 d = _me.inertia(frame_a, 1, 1, 1) point_po1 = _me.Point('po1') point_po2 = _me.Point('po2') particle_p1 = _me.Particle('p1', _me.Point('p1_pt'), _sm.Symbol('m')) particle_p2 = _me.Particle('p2', _me.Point('p2_pt'), _sm.Symbol('m')) c1, c2, c3 = _me.dynamicsymbols('c1 c2 c3') c1_d, c2_d, c3_d = _me.dynamicsymbols('c1_ c2_ c3_', 1) body_r_cm = _me.Point('r_cm') body_r_cm.set_vel(frame_n, 0) body_r_f = _me.ReferenceFrame('r_f') body_r = _me.RigidBody('r', body_r_cm, body_r_f, _sm.symbols('m'), (_me.outer(body_r_f.x,body_r_f.x),body_r_cm)) point_po2.set_pos(particle_p1.point, c1*frame_a.x) v = 2*point_po2.pos_from(particle_p1.point)+c2*frame_a.y frame_a.set_ang_vel(frame_n, c3*frame_a.z) v = 2*frame_a.ang_vel_in(frame_n)+c2*frame_a.y body_r_f.set_ang_vel(frame_n, c3*frame_a.z) v = 2*body_r_f.ang_vel_in(frame_n)+c2*frame_a.y frame_a.set_ang_acc(frame_n, (frame_a.ang_vel_in(frame_n)).dt(frame_a)) v = 2*frame_a.ang_acc_in(frame_n)+c2*frame_a.y particle_p1.point.set_vel(frame_a, c1*frame_a.x+c3*frame_a.y) body_r_cm.set_acc(frame_n, c2*frame_a.y) v_a = _me.cross(body_r_cm.acc(frame_n), particle_p1.point.vel(frame_a)) x_b_c = v_a x_b_d = 2*x_b_c a_b_c_d_e = x_b_d*2 a_b_c = 2*c1*c2*c3 a_b_c += 2*c1 a_b_c = 3*c1 q1, q2, u1, u2 = _me.dynamicsymbols('q1 q2 u1 u2') q1_d, q2_d, u1_d, u2_d = _me.dynamicsymbols('q1_ q2_ u1_ u2_', 1) x, y = _me.dynamicsymbols('x y') x_d, y_d = _me.dynamicsymbols('x_ y_', 1) x_dd, y_dd = _me.dynamicsymbols('x_ y_', 2) yy = _me.dynamicsymbols('yy') yy = x*x_d**2+1 m = _sm.Matrix([[0]]) m[0] = 2*x m = m.row_insert(m.shape[0], _sm.Matrix([[0]])) m[m.shape[0]-1] = 2*y a = 2*m[0] m = _sm.Matrix([1,2,3,4,5,6,7,8,9]).reshape(3, 3) m[0,1] = 5 a = m[0, 1]*2 force_ro = q1*frame_n.x torque_a = q2*frame_n.z force_ro = q1*frame_n.x + q2*frame_n.y f = force_ro*2 sympy-sympy-1.9/sympy/parsing/c/000077500000000000000000000000001412543434000167715ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/c/__init__.py000066400000000000000000000001011412543434000210720ustar00rootroot00000000000000"""Used for translating C source code into a SymPy expression""" sympy-sympy-1.9/sympy/parsing/c/c_parser.py000066400000000000000000001145541412543434000211530ustar00rootroot00000000000000from sympy.external import import_module import os cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) """ This module contains all the necessary Classes and Function used to Parse C and C++ code into SymPy expression The module serves as a backend for SymPyExpression to parse C code It is also dependent on Clang's AST and Sympy's Codegen AST. The module only supports the features currently supported by the Clang and codegen AST which will be updated as the development of codegen AST and this module progresses. You might find unexpected bugs and exceptions while using the module, feel free to report them to the SymPy Issue Tracker Features Supported ================== - Variable Declarations (integers and reals) - Assignment (using integer & floating literal and function calls) - Function Definitions nad Declaration - Function Calls - Compound statements, Return statements Notes ===== The module is dependent on an external dependency which needs to be installed to use the features of this module. Clang: The C and C++ compiler which is used to extract an AST from the provided C source code. Refrences ========= .. [1] https://github.com/sympy/sympy/issues .. [2] https://clang.llvm.org/docs/ .. [3] https://clang.llvm.org/docs/IntroductionToTheClangAST.html """ if cin: from sympy.codegen.ast import (Variable, Integer, Float, FunctionPrototype, FunctionDefinition, FunctionCall, none, Return, Assignment, intc, int8, int16, int64, uint8, uint16, uint32, uint64, float32, float64, float80, aug_assign, bool_, While, CodeBlock) from sympy.codegen.cnodes import (PreDecrement, PostDecrement, PreIncrement, PostIncrement) from sympy.core import Add, Mod, Mul, Pow, Rel from sympy.logic.boolalg import And, as_Boolean, Not, Or from sympy import Symbol, sympify, true, false import sys import tempfile class BaseParser: """Base Class for the C parser""" def __init__(self): """Initializes the Base parser creating a Clang AST index""" self.index = cin.Index.create() def diagnostics(self, out): """Diagostics function for the Clang AST""" for diag in self.tu.diagnostics: print('%s %s (line %s, col %s) %s' % ( { 4: 'FATAL', 3: 'ERROR', 2: 'WARNING', 1: 'NOTE', 0: 'IGNORED', }[diag.severity], diag.location.file, diag.location.line, diag.location.column, diag.spelling ), file=out) class CCodeConverter(BaseParser): """The Code Convereter for Clang AST The converter object takes the C source code or file as input and converts them to SymPy Expressions. """ def __init__(self): """Initializes the code converter""" super().__init__() self._py_nodes = [] self._data_types = { "void": { cin.TypeKind.VOID: none }, "bool": { cin.TypeKind.BOOL: bool_ }, "int": { cin.TypeKind.SCHAR: int8, cin.TypeKind.SHORT: int16, cin.TypeKind.INT: intc, cin.TypeKind.LONG: int64, cin.TypeKind.UCHAR: uint8, cin.TypeKind.USHORT: uint16, cin.TypeKind.UINT: uint32, cin.TypeKind.ULONG: uint64 }, "float": { cin.TypeKind.FLOAT: float32, cin.TypeKind.DOUBLE: float64, cin.TypeKind.LONGDOUBLE: float80 } } def parse(self, filenames, flags): """Function to parse a file with C source code It takes the filename as an attribute and creates a Clang AST Translation Unit parsing the file. Then the transformation function is called on the transaltion unit, whose reults are collected into a list which is returned by the function. Parameters ========== filenames : string Path to the C file to be parsed flags: list Arguments to be passed to Clang while parsing the C code Returns ======= py_nodes: list A list of sympy AST nodes """ filename = os.path.abspath(filenames) self.tu = self.index.parse( filename, args=flags, options=cin.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD ) for child in self.tu.cursor.get_children(): if child.kind == cin.CursorKind.VAR_DECL: self._py_nodes.append(self.transform(child)) elif (child.kind == cin.CursorKind.FUNCTION_DECL): self._py_nodes.append(self.transform(child)) else: pass return self._py_nodes def parse_str(self, source, flags): """Function to parse a string with C source code It takes the source code as an attribute, stores it in a temporary file and creates a Clang AST Translation Unit parsing the file. Then the transformation function is called on the transaltion unit, whose reults are collected into a list which is returned by the function. Parameters ========== source : string Path to the C file to be parsed flags: list Arguments to be passed to Clang while parsing the C code Returns ======= py_nodes: list A list of sympy AST nodes """ file = tempfile.NamedTemporaryFile(mode = 'w+', suffix = '.cpp') file.write(source) file.seek(0) self.tu = self.index.parse( file.name, args=flags, options=cin.TranslationUnit.PARSE_DETAILED_PROCESSING_RECORD ) file.close() for child in self.tu.cursor.get_children(): if child.kind == cin.CursorKind.VAR_DECL: self._py_nodes.append(self.transform(child)) elif (child.kind == cin.CursorKind.FUNCTION_DECL): self._py_nodes.append(self.transform(child)) else: pass return self._py_nodes def transform(self, node): """Transformation Function for Clang AST nodes It determines the kind of node and calls the respective transformation function for that node. Raises ====== NotImplementedError : if the transformation for the provided node is not implemented """ try: handler = getattr(self, 'transform_%s' % node.kind.name.lower()) except AttributeError: print( "Ignoring node of type %s (%s)" % ( node.kind, ' '.join( t.spelling for t in node.get_tokens()) ), file=sys.stderr ) handler = None if handler: result = handler(node) return result def transform_var_decl(self, node): """Transformation Function for Variable Declaration Used to create nodes for variable declarations and assignments with values or function call for the respective nodes in the clang AST Returns ======= A variable node as Declaration, with the initial value if given Raises ====== NotImplementedError : if called for data types not currently implemented Notes ===== The function currently supports following data types: Boolean: bool, _Bool Integer: 8-bit: signed char and unsigned char 16-bit: short, short int, signed short, signed short int, unsigned short, unsigned short int 32-bit: int, signed int, unsigned int 64-bit: long, long int, signed long, signed long int, unsigned long, unsigned long int Floating point: Single Precision: float Double Precision: double Extended Precision: long double """ if node.type.kind in self._data_types["int"]: type = self._data_types["int"][node.type.kind] elif node.type.kind in self._data_types["float"]: type = self._data_types["float"][node.type.kind] elif node.type.kind in self._data_types["bool"]: type = self._data_types["bool"][node.type.kind] else: raise NotImplementedError("Only bool, int " "and float are supported") try: children = node.get_children() child = next(children) #ignoring namespace and type details for the variable while child.kind == cin.CursorKind.NAMESPACE_REF: child = next(children) while child.kind == cin.CursorKind.TYPE_REF: child = next(children) val = self.transform(child) supported_rhs = [ cin.CursorKind.INTEGER_LITERAL, cin.CursorKind.FLOATING_LITERAL, cin.CursorKind.UNEXPOSED_EXPR, cin.CursorKind.BINARY_OPERATOR, cin.CursorKind.PAREN_EXPR, cin.CursorKind.UNARY_OPERATOR, cin.CursorKind.CXX_BOOL_LITERAL_EXPR ] if child.kind in supported_rhs: if isinstance(val, str): value = Symbol(val) elif isinstance(val, bool): if node.type.kind in self._data_types["int"]: value = Integer(0) if val == False else Integer(1) elif node.type.kind in self._data_types["float"]: value = Float(0.0) if val == False else Float(1.0) elif node.type.kind in self._data_types["bool"]: value = sympify(val) elif isinstance(val, (Integer, int, Float, float)): if node.type.kind in self._data_types["int"]: value = Integer(val) elif node.type.kind in self._data_types["float"]: value = Float(val) elif node.type.kind in self._data_types["bool"]: value = sympify(bool(val)) else: value = val return Variable( node.spelling ).as_Declaration( type = type, value = value ) elif child.kind == cin.CursorKind.CALL_EXPR: return Variable( node.spelling ).as_Declaration( value = val ) else: raise NotImplementedError("Given " "variable declaration \"{}\" " "is not possible to parse yet!" .format(" ".join( t.spelling for t in node.get_tokens() ) )) except StopIteration: return Variable( node.spelling ).as_Declaration( type = type ) def transform_function_decl(self, node): """Transformation Function For Function Declaration Used to create nodes for function declarations and definitions for the respective nodes in the clang AST Returns ======= function : Codegen AST node - FunctionPrototype node if function body is not present - FunctionDefinition node if the function body is present """ if node.result_type.kind in self._data_types["int"]: ret_type = self._data_types["int"][node.result_type.kind] elif node.result_type.kind in self._data_types["float"]: ret_type = self._data_types["float"][node.result_type.kind] elif node.result_type.kind in self._data_types["bool"]: ret_type = self._data_types["bool"][node.result_type.kind] elif node.result_type.kind in self._data_types["void"]: ret_type = self._data_types["void"][node.result_type.kind] else: raise NotImplementedError("Only void, bool, int " "and float are supported") body = [] param = [] try: children = node.get_children() child = next(children) # If the node has any children, the first children will be the # return type and namespace for the function declaration. These # nodes can be ignored. while child.kind == cin.CursorKind.NAMESPACE_REF: child = next(children) while child.kind == cin.CursorKind.TYPE_REF: child = next(children) # Subsequent nodes will be the parameters for the function. try: while True: decl = self.transform(child) if (child.kind == cin.CursorKind.PARM_DECL): param.append(decl) elif (child.kind == cin.CursorKind.COMPOUND_STMT): for val in decl: body.append(val) else: body.append(decl) child = next(children) except StopIteration: pass except StopIteration: pass if body == []: function = FunctionPrototype( return_type = ret_type, name = node.spelling, parameters = param ) else: function = FunctionDefinition( return_type = ret_type, name = node.spelling, parameters = param, body = body ) return function def transform_parm_decl(self, node): """Transformation function for Parameter Declaration Used to create parameter nodes for the required functions for the respective nodes in the clang AST Returns ======= param : Codegen AST Node Variable node with the value nad type of the variable Raises ====== ValueError if multiple children encountered in the parameter node """ if node.type.kind in self._data_types["int"]: type = self._data_types["int"][node.type.kind] elif node.type.kind in self._data_types["float"]: type = self._data_types["float"][node.type.kind] elif node.type.kind in self._data_types["bool"]: type = self._data_types["bool"][node.type.kind] else: raise NotImplementedError("Only bool, int " "and float are supported") try: children = node.get_children() child = next(children) # Any namespace nodes can be ignored while child.kind in [cin.CursorKind.NAMESPACE_REF, cin.CursorKind.TYPE_REF, cin.CursorKind.TEMPLATE_REF]: child = next(children) # If there is a child, it is the default value of the parameter. lit = self.transform(child) if node.type.kind in self._data_types["int"]: val = Integer(lit) elif node.type.kind in self._data_types["float"]: val = Float(lit) elif node.type.kind in self._data_types["bool"]: val = sympify(bool(lit)) else: raise NotImplementedError("Only bool, int " "and float are supported") param = Variable( node.spelling ).as_Declaration( type = type, value = val ) except StopIteration: param = Variable( node.spelling ).as_Declaration( type = type ) try: self.transform(next(children)) raise ValueError("Can't handle multiple children on parameter") except StopIteration: pass return param def transform_integer_literal(self, node): """Transformation function for integer literal Used to get the value and type of the given integer literal. Returns ======= val : list List with two arguments type and Value type contains the type of the integer value contains the value stored in the variable Notes ===== Only Base Integer type supported for now """ try: value = next(node.get_tokens()).spelling except StopIteration: # No tokens value = node.literal return int(value) def transform_floating_literal(self, node): """Transformation function for floating literal Used to get the value and type of the given floating literal. Returns ======= val : list List with two arguments type and Value type contains the type of float value contains the value stored in the variable Notes ===== Only Base Float type supported for now """ try: value = next(node.get_tokens()).spelling except (StopIteration, ValueError): # No tokens value = node.literal return float(value) def transform_string_literal(self, node): #TODO: No string type in AST #type = #try: # value = next(node.get_tokens()).spelling #except (StopIteration, ValueError): # No tokens # value = node.literal #val = [type, value] #return val pass def transform_character_literal(self, node): """Transformation function for character literal Used to get the value of the given character literal. Returns ======= val : int val contains the ascii value of the character literal Notes ===== Only for cases where character is assigned to a integer value, since character literal is not in sympy AST """ try: value = next(node.get_tokens()).spelling except (StopIteration, ValueError): # No tokens value = node.literal return ord(str(value[1])) def transform_cxx_bool_literal_expr(self, node): """Transformation function for boolean literal Used to get the value of the given boolean literal. Returns ======= value : bool value contains the boolean value of the variable """ try: value = next(node.get_tokens()).spelling except (StopIteration, ValueError): value = node.literal return True if value == 'true' else False def transform_unexposed_decl(self,node): """Transformation function for unexposed declarations""" pass def transform_unexposed_expr(self, node): """Transformation function for unexposed expression Unexposed expressions are used to wrap float, double literals and expressions Returns ======= expr : Codegen AST Node the result from the wrapped expression None : NoneType No childs are found for the node Raises ====== ValueError if the expression contains multiple children """ # Ignore unexposed nodes; pass whatever is the first # (and should be only) child unaltered. try: children = node.get_children() expr = self.transform(next(children)) except StopIteration: return None try: next(children) raise ValueError("Unexposed expression has > 1 children.") except StopIteration: pass return expr def transform_decl_ref_expr(self, node): """Returns the name of the declaration reference""" return node.spelling def transform_call_expr(self, node): """Transformation function for a call expression Used to create function call nodes for the function calls present in the C code Returns ======= FunctionCall : Codegen AST Node FunctionCall node with parameters if any parameters are present """ param = [] children = node.get_children() child = next(children) while child.kind == cin.CursorKind.NAMESPACE_REF: child = next(children) while child.kind == cin.CursorKind.TYPE_REF: child = next(children) first_child = self.transform(child) try: for child in children: arg = self.transform(child) if (child.kind == cin.CursorKind.INTEGER_LITERAL): param.append(Integer(arg)) elif (child.kind == cin.CursorKind.FLOATING_LITERAL): param.append(Float(arg)) else: param.append(arg) return FunctionCall(first_child, param) except StopIteration: return FunctionCall(first_child) def transform_return_stmt(self, node): """Returns the Return Node for a return statement""" return Return(next(node.get_children()).spelling) def transform_compound_stmt(self, node): """Transformation function for compond statemets Returns ======= expr : list list of Nodes for the expressions present in the statement None : NoneType if the compound statement is empty """ try: expr = [] children = node.get_children() for child in children: expr.append(self.transform(child)) except StopIteration: return None return expr def transform_decl_stmt(self, node): """Transformation function for declaration statements These statements are used to wrap different kinds of declararions like variable or function declaration The function calls the transformer function for the child of the given node Returns ======= statement : Codegen AST Node contains the node returned by the children node for the type of declaration Raises ====== ValueError if multiple children present """ try: children = node.get_children() statement = self.transform(next(children)) except StopIteration: pass try: self.transform(next(children)) raise ValueError("Don't know how to handle multiple statements") except StopIteration: pass return statement def transform_paren_expr(self, node): """Transformation function for Parenthesized expressions Returns the result from its children nodes """ return self.transform(next(node.get_children())) def transform_compound_assignment_operator(self, node): """Transformation function for handling shorthand operators Returns ======= augmented_assignment_expression: Codegen AST node shorthand assignment expression represented as Codegen AST Raises ====== NotImplementedError If the shorthand operator for bitwise operators (~=, ^=, &=, |=, <<=, >>=) is encountered """ return self.transform_binary_operator(node) def transform_unary_operator(self, node): """Transformation function for handling unary operators Returns ======= unary_expression: Codegen AST node simplified unary expression represented as Codegen AST Raises ====== NotImplementedError If dereferencing operator(*), address operator(&) or bitwise NOT operator(~) is encountered """ # supported operators list operators_list = ['+', '-', '++', '--', '!'] tokens = [token for token in node.get_tokens()] # it can be either pre increment/decrement or any other operator from the list if tokens[0].spelling in operators_list: child = self.transform(next(node.get_children())) # (decl_ref) e.g.; int a = ++b; or simply ++b; if isinstance(child, str): if tokens[0].spelling == '+': return Symbol(child) if tokens[0].spelling == '-': return Mul(Symbol(child), -1) if tokens[0].spelling == '++': return PreIncrement(Symbol(child)) if tokens[0].spelling == '--': return PreDecrement(Symbol(child)) if tokens[0].spelling == '!': return Not(Symbol(child)) # e.g.; int a = -1; or int b = -(1 + 2); else: if tokens[0].spelling == '+': return child if tokens[0].spelling == '-': return Mul(child, -1) if tokens[0].spelling == '!': return Not(sympify(bool(child))) # it can be either post increment/decrement # since variable name is obtained in token[0].spelling elif tokens[1].spelling in ['++', '--']: child = self.transform(next(node.get_children())) if tokens[1].spelling == '++': return PostIncrement(Symbol(child)) if tokens[1].spelling == '--': return PostDecrement(Symbol(child)) else: raise NotImplementedError("Dereferencing operator, " "Address operator and bitwise NOT operator " "have not been implemented yet!") def transform_binary_operator(self, node): """Transformation function for handling binary operators Returns ======= binary_expression: Codegen AST node simplified binary expression represented as Codegen AST Raises ====== NotImplementedError If a bitwise operator or unary operator(which is a child of any binary operator in Clang AST) is encountered """ # get all the tokens of assignment # and store it in the tokens list tokens = [token for token in node.get_tokens()] # supported operators list operators_list = ['+', '-', '*', '/', '%','=', '>', '>=', '<', '<=', '==', '!=', '&&', '||', '+=', '-=', '*=', '/=', '%='] # this stack will contain variable content # and type of variable in the rhs combined_variables_stack = [] # this stack will contain operators # to be processed in the rhs operators_stack = [] # iterate through every token for token in tokens: # token is either '(', ')' or # any of the supported operators from the operator list if token.kind == cin.TokenKind.PUNCTUATION: # push '(' to the operators stack if token.spelling == '(': operators_stack.append('(') elif token.spelling == ')': # keep adding the expression to the # combined variables stack unless # '(' is found while (operators_stack and operators_stack[-1] != '('): if len(combined_variables_stack) < 2: raise NotImplementedError( "Unary operators as a part of " "binary operators is not " "supported yet!") rhs = combined_variables_stack.pop() lhs = combined_variables_stack.pop() operator = operators_stack.pop() combined_variables_stack.append( self.perform_operation( lhs, rhs, operator)) # pop '(' operators_stack.pop() # token is an operator (supported) elif token.spelling in operators_list: while (operators_stack and self.priority_of(token.spelling) <= self.priority_of( operators_stack[-1])): if len(combined_variables_stack) < 2: raise NotImplementedError( "Unary operators as a part of " "binary operators is not " "supported yet!") rhs = combined_variables_stack.pop() lhs = combined_variables_stack.pop() operator = operators_stack.pop() combined_variables_stack.append( self.perform_operation( lhs, rhs, operator)) # push current operator operators_stack.append(token.spelling) # token is a bitwise operator elif token.spelling in ['&', '|', '^', '<<', '>>']: raise NotImplementedError( "Bitwise operator has not been " "implemented yet!") # token is a shorthand bitwise operator elif token.spelling in ['&=', '|=', '^=', '<<=', '>>=']: raise NotImplementedError( "Shorthand bitwise operator has not been " "implemented yet!") else: raise NotImplementedError( "Given token {} is not implemented yet!" .format(token.spelling)) # token is an identifier(variable) elif token.kind == cin.TokenKind.IDENTIFIER: combined_variables_stack.append( [token.spelling, 'identifier']) # token is a literal elif token.kind == cin.TokenKind.LITERAL: combined_variables_stack.append( [token.spelling, 'literal']) # token is a keyword, either true or false elif (token.kind == cin.TokenKind.KEYWORD and token.spelling in ['true', 'false']): combined_variables_stack.append( [token.spelling, 'boolean']) else: raise NotImplementedError( "Given token {} is not implemented yet!" .format(token.spelling)) # process remaining operators while operators_stack: if len(combined_variables_stack) < 2: raise NotImplementedError( "Unary operators as a part of " "binary operators is not " "supported yet!") rhs = combined_variables_stack.pop() lhs = combined_variables_stack.pop() operator = operators_stack.pop() combined_variables_stack.append( self.perform_operation(lhs, rhs, operator)) return combined_variables_stack[-1][0] def priority_of(self, op): """To get the priority of given operator""" if op in ['=', '+=', '-=', '*=', '/=', '%=']: return 1 if op in ['&&', '||']: return 2 if op in ['<', '<=', '>', '>=', '==', '!=']: return 3 if op in ['+', '-']: return 4 if op in ['*', '/', '%']: return 5 return 0 def perform_operation(self, lhs, rhs, op): """Performs operation supported by the sympy core Returns ======= combined_variable: list contains variable content and type of variable """ lhs_value = self.get_expr_for_operand(lhs) rhs_value = self.get_expr_for_operand(rhs) if op == '+': return [Add(lhs_value, rhs_value), 'expr'] if op == '-': return [Add(lhs_value, -rhs_value), 'expr'] if op == '*': return [Mul(lhs_value, rhs_value), 'expr'] if op == '/': return [Mul(lhs_value, Pow(rhs_value, Integer(-1))), 'expr'] if op == '%': return [Mod(lhs_value, rhs_value), 'expr'] if op in ['<', '<=', '>', '>=', '==', '!=']: return [Rel(lhs_value, rhs_value, op), 'expr'] if op == '&&': return [And(as_Boolean(lhs_value), as_Boolean(rhs_value)), 'expr'] if op == '||': return [Or(as_Boolean(lhs_value), as_Boolean(rhs_value)), 'expr'] if op == '=': return [Assignment(Variable(lhs_value), rhs_value), 'expr'] if op in ['+=', '-=', '*=', '/=', '%=']: return [aug_assign(Variable(lhs_value), op[0], rhs_value), 'expr'] def get_expr_for_operand(self, combined_variable): """Gives out SymPy Codegen AST node AST node returned is corresponding to combined variable passed.Combined variable contains variable content and type of variable """ if combined_variable[1] == 'identifier': return Symbol(combined_variable[0]) if combined_variable[1] == 'literal': if '.' in combined_variable[0]: return Float(float(combined_variable[0])) else: return Integer(int(combined_variable[0])) if combined_variable[1] == 'expr': return combined_variable[0] if combined_variable[1] == 'boolean': return true if combined_variable[0] == 'true' else false def transform_null_stmt(self, node): """Handles Null Statement and returns None""" return none def transform_while_stmt(self, node): """Transformation function for handling while statement Returns ======= while statement : Codegen AST Node contains the while statement node having condition and statement block """ children = node.get_children() condition = self.transform(next(children)) statements = self.transform(next(children)) if isinstance(statements, list): statement_block = CodeBlock(*statements) else: statement_block = CodeBlock(statements) return While(condition, statement_block) else: class CCodeConverter(): # type: ignore def __init__(self, *args, **kwargs): raise ImportError("Module not Installed") def parse_c(source): """Function for converting a C source code The function reads the source code present in the given file and parses it to give out SymPy Expressions Returns ======= src : list List of Python expression strings """ converter = CCodeConverter() if os.path.exists(source): src = converter.parse(source, flags = []) else: src = converter.parse_str(source, flags = []) return src sympy-sympy-1.9/sympy/parsing/fortran/000077500000000000000000000000001412543434000202225ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/fortran/__init__.py000066400000000000000000000001111412543434000223240ustar00rootroot00000000000000"""Used for translating Fortran source code into a SymPy expression. """ sympy-sympy-1.9/sympy/parsing/fortran/fortran_parser.py000066400000000000000000000265161412543434000236350ustar00rootroot00000000000000from sympy.external import import_module lfortran = import_module('lfortran') if lfortran: from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String, Return, FunctionDefinition, Assignment) from sympy.core import Add, Mul, Integer, Float from sympy import Symbol asr_mod = lfortran.asr asr = lfortran.asr.asr src_to_ast = lfortran.ast.src_to_ast ast_to_asr = lfortran.semantic.ast_to_asr.ast_to_asr """ This module contains all the necessary Classes and Function used to Parse Fortran code into SymPy expression The module and its API are currently under development and experimental. It is also dependent on LFortran for the ASR that is converted to SymPy syntax which is also under development. The module only supports the features currently supported by the LFortran ASR which will be updated as the development of LFortran and this module progresses You might find unexpected bugs and exceptions while using the module, feel free to report them to the SymPy Issue Tracker The API for the module might also change while in development if better and more effective ways are discovered for the process Features Supported ================== - Variable Declarations (integers and reals) - Function Definitions - Assignments and Basic Binary Operations Notes ===== The module depends on an external dependency LFortran : Required to parse Fortran source code into ASR Refrences ========= .. [1] https://github.com/sympy/sympy/issues .. [2] https://gitlab.com/lfortran/lfortran .. [3] https://docs.lfortran.org/ """ class ASR2PyVisitor(asr.ASTVisitor): # type: ignore """ Visitor Class for LFortran ASR It is a Visitor class derived from asr.ASRVisitor which visits all the nodes of the LFortran ASR and creates corresponding AST node for each ASR node """ def __init__(self): """Initialize the Parser""" self._py_ast = [] def visit_TranslationUnit(self, node): """ Function to visit all the elements of the Translation Unit created by LFortran ASR """ for s in node.global_scope.symbols: sym = node.global_scope.symbols[s] self.visit(sym) for item in node.items: self.visit(item) def visit_Assignment(self, node): """Visitor Function for Assignment Visits each Assignment is the LFortran ASR and creates corresponding assignment for SymPy. Notes ===== The function currently only supports variable assignment and binary operation assignments of varying multitudes. Any type of numberS or array is not supported. Raises ====== NotImplementedError() when called for Numeric assignments or Arrays """ # TODO: Arithmatic Assignment if isinstance(node.target, asr.Variable): target = node.target value = node.value if isinstance(value, asr.Variable): new_node = Assignment( Variable( target.name ), Variable( value.name ) ) elif (type(value) == asr.BinOp): exp_ast = call_visitor(value) for expr in exp_ast: new_node = Assignment( Variable(target.name), expr ) else: raise NotImplementedError("Numeric assignments not supported") else: raise NotImplementedError("Arrays not supported") self._py_ast.append(new_node) def visit_BinOp(self, node): """Visitor Function for Binary Operations Visits each binary operation present in the LFortran ASR like addition, subtraction, multiplication, division and creates the corresponding operation node in SymPy's AST In case of more than one binary operations, the function calls the call_visitor() function on the child nodes of the binary operations recursively until all the operations have been processed. Notes ===== The function currently only supports binary operations with Variables or other binary operations. Numerics are not supported as of yet. Raises ====== NotImplementedError() when called for Numeric assignments """ # TODO: Integer Binary Operations op = node.op lhs = node.left rhs = node.right if (type(lhs) == asr.Variable): left_value = Symbol(lhs.name) elif(type(lhs) == asr.BinOp): l_exp_ast = call_visitor(lhs) for exp in l_exp_ast: left_value = exp else: raise NotImplementedError("Numbers Currently not supported") if (type(rhs) == asr.Variable): right_value = Symbol(rhs.name) elif(type(rhs) == asr.BinOp): r_exp_ast = call_visitor(rhs) for exp in r_exp_ast: right_value = exp else: raise NotImplementedError("Numbers Currently not supported") if isinstance(op, asr.Add): new_node = Add(left_value, right_value) elif isinstance(op, asr.Sub): new_node = Add(left_value, -right_value) elif isinstance(op, asr.Div): new_node = Mul(left_value, 1/right_value) elif isinstance(op, asr.Mul): new_node = Mul(left_value, right_value) self._py_ast.append(new_node) def visit_Variable(self, node): """Visitor Function for Variable Declaration Visits each variable declaration present in the ASR and creates a Symbol declaration for each variable Notes ===== The functions currently only support declaration of integer and real variables. Other data types are still under development. Raises ====== NotImplementedError() when called for unsupported data types """ if isinstance(node.type, asr.Integer): var_type = IntBaseType(String('integer')) value = Integer(0) elif isinstance(node.type, asr.Real): var_type = FloatBaseType(String('real')) value = Float(0.0) else: raise NotImplementedError("Data type not supported") if not (node.intent == 'in'): new_node = Variable( node.name ).as_Declaration( type = var_type, value = value ) self._py_ast.append(new_node) def visit_Sequence(self, seq): """Visitor Function for code sequence Visits a code sequence/ block and calls the visitor function on all the children of the code block to create corresponding code in python """ if seq is not None: for node in seq: self._py_ast.append(call_visitor(node)) def visit_Num(self, node): """Visitor Function for Numbers in ASR This function is currently under development and will be updated with improvements in the LFortran ASR """ # TODO:Numbers when the LFortran ASR is updated # self._py_ast.append(Integer(node.n)) pass def visit_Function(self, node): """Visitor Function for function Definitions Visits each function definition present in the ASR and creates a function definition node in the Python AST with all the elements of the given function The functions declare all the variables required as SymPy symbols in the function before the function definition This function also the call_visior_function to parse the contents of the function body """ # TODO: Return statement, variable declaration fn_args =[] fn_body = [] fn_name = node.name for arg_iter in node.args: fn_args.append( Variable( arg_iter.name ) ) for i in node.body: fn_ast = call_visitor(i) try: fn_body_expr = fn_ast except UnboundLocalError: fn_body_expr = [] for sym in node.symtab.symbols: decl = call_visitor(node.symtab.symbols[sym]) for symbols in decl: fn_body.append(symbols) for elem in fn_body_expr: fn_body.append(elem) fn_body.append( Return( Variable( node.return_var.name ) ) ) if isinstance(node.return_var.type, asr.Integer): ret_type = IntBaseType(String('integer')) elif isinstance(node.return_var.type, asr.Real): ret_type = FloatBaseType(String('real')) else: raise NotImplementedError("Data type not supported") new_node = FunctionDefinition( return_type = ret_type, name = fn_name, parameters = fn_args, body = fn_body ) self._py_ast.append(new_node) def ret_ast(self): """Returns the AST nodes""" return self._py_ast else: class ASR2PyVisitor(): # type: ignore def __init__(self, *args, **kwargs): raise ImportError('lfortran not available') def call_visitor(fort_node): """Calls the AST Visitor on the Module This function is used to call the AST visitor for a program or module It imports all the required modules and calls the visit() function on the given node Parameters ========== fort_node : LFortran ASR object Node for the operation for which the NodeVisitor is called Returns ======= res_ast : list list of sympy AST Nodes """ v = ASR2PyVisitor() v.visit(fort_node) res_ast = v.ret_ast() return res_ast def src_to_sympy(src): """Wrapper function to convert the given Fortran source code to SymPy Expressions Parameters ========== src : string A string with the Fortran source code Returns ======= py_src : string A string with the python source code compatible with SymPy """ a_ast = src_to_ast(src, translation_unit=False) a = ast_to_asr(a_ast) py_src = call_visitor(a) return py_src sympy-sympy-1.9/sympy/parsing/latex/000077500000000000000000000000001412543434000176645ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/latex/LICENSE.txt000066400000000000000000000020631412543434000215100ustar00rootroot00000000000000The MIT License (MIT) Copyright 2016, latex2sympy Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sympy-sympy-1.9/sympy/parsing/latex/LaTeX.g4000066400000000000000000000127561412543434000211100ustar00rootroot00000000000000/* ANTLR4 LaTeX Math Grammar Ported from latex2sympy by @augustt198 https://github.com/augustt198/latex2sympy See license in LICENSE.txt */ /* After changing this file, it is necessary to run `python setup.py antlr` in the root directory of the repository. This will regenerate the code in `sympy/parsing/latex/_antlr/*.py`. */ grammar LaTeX; options { language = Python2; } WS: [ \t\r\n]+ -> skip; THINSPACE: ('\\,' | '\\thinspace') -> skip; MEDSPACE: ('\\:' | '\\medspace') -> skip; THICKSPACE: ('\\;' | '\\thickspace') -> skip; QUAD: '\\quad' -> skip; QQUAD: '\\qquad' -> skip; NEGTHINSPACE: ('\\!' | '\\negthinspace') -> skip; NEGMEDSPACE: '\\negmedspace' -> skip; NEGTHICKSPACE: '\\negthickspace' -> skip; CMD_LEFT: '\\left' -> skip; CMD_RIGHT: '\\right' -> skip; IGNORE: ( '\\vrule' | '\\vcenter' | '\\vbox' | '\\vskip' | '\\vspace' | '\\hfil' | '\\*' | '\\-' | '\\.' | '\\/' | '\\"' | '\\(' | '\\=' ) -> skip; ADD: '+'; SUB: '-'; MUL: '*'; DIV: '/'; L_PAREN: '('; R_PAREN: ')'; L_BRACE: '{'; R_BRACE: '}'; L_BRACE_LITERAL: '\\{'; R_BRACE_LITERAL: '\\}'; L_BRACKET: '['; R_BRACKET: ']'; BAR: '|'; R_BAR: '\\right|'; L_BAR: '\\left|'; L_ANGLE: '\\langle'; R_ANGLE: '\\rangle'; FUNC_LIM: '\\lim'; LIM_APPROACH_SYM: '\\to' | '\\rightarrow' | '\\Rightarrow' | '\\longrightarrow' | '\\Longrightarrow'; FUNC_INT: '\\int'; FUNC_SUM: '\\sum'; FUNC_PROD: '\\prod'; FUNC_EXP: '\\exp'; FUNC_LOG: '\\log'; FUNC_LN: '\\ln'; FUNC_SIN: '\\sin'; FUNC_COS: '\\cos'; FUNC_TAN: '\\tan'; FUNC_CSC: '\\csc'; FUNC_SEC: '\\sec'; FUNC_COT: '\\cot'; FUNC_ARCSIN: '\\arcsin'; FUNC_ARCCOS: '\\arccos'; FUNC_ARCTAN: '\\arctan'; FUNC_ARCCSC: '\\arccsc'; FUNC_ARCSEC: '\\arcsec'; FUNC_ARCCOT: '\\arccot'; FUNC_SINH: '\\sinh'; FUNC_COSH: '\\cosh'; FUNC_TANH: '\\tanh'; FUNC_ARSINH: '\\arsinh'; FUNC_ARCOSH: '\\arcosh'; FUNC_ARTANH: '\\artanh'; L_FLOOR: '\\lfloor'; R_FLOOR: '\\rfloor'; L_CEIL: '\\lceil'; R_CEIL: '\\rceil'; FUNC_SQRT: '\\sqrt'; FUNC_OVERLINE: '\\overline'; CMD_TIMES: '\\times'; CMD_CDOT: '\\cdot'; CMD_DIV: '\\div'; CMD_FRAC: '\\frac'; CMD_BINOM: '\\binom'; CMD_DBINOM: '\\dbinom'; CMD_TBINOM: '\\tbinom'; CMD_MATHIT: '\\mathit'; UNDERSCORE: '_'; CARET: '^'; COLON: ':'; fragment WS_CHAR: [ \t\r\n]; DIFFERENTIAL: 'd' WS_CHAR*? ([a-zA-Z] | '\\' [a-zA-Z]+); LETTER: [a-zA-Z]; fragment DIGIT: [0-9]; NUMBER: DIGIT+ (',' DIGIT DIGIT DIGIT)* | DIGIT* (',' DIGIT DIGIT DIGIT)* '.' DIGIT+; EQUAL: (('&' WS_CHAR*?)? '=') | ('=' (WS_CHAR*? '&')?); NEQ: '\\neq'; LT: '<'; LTE: ('\\leq' | '\\le' | LTE_Q | LTE_S); LTE_Q: '\\leqq'; LTE_S: '\\leqslant'; GT: '>'; GTE: ('\\geq' | '\\ge' | GTE_Q | GTE_S); GTE_Q: '\\geqq'; GTE_S: '\\geqslant'; BANG: '!'; SYMBOL: '\\' [a-zA-Z]+; math: relation; relation: relation (EQUAL | LT | LTE | GT | GTE | NEQ) relation | expr; equality: expr EQUAL expr; expr: additive; additive: additive (ADD | SUB) additive | mp; // mult part mp: mp (MUL | CMD_TIMES | CMD_CDOT | DIV | CMD_DIV | COLON) mp | unary; mp_nofunc: mp_nofunc ( MUL | CMD_TIMES | CMD_CDOT | DIV | CMD_DIV | COLON ) mp_nofunc | unary_nofunc; unary: (ADD | SUB) unary | postfix+; unary_nofunc: (ADD | SUB) unary_nofunc | postfix postfix_nofunc*; postfix: exp postfix_op*; postfix_nofunc: exp_nofunc postfix_op*; postfix_op: BANG | eval_at; eval_at: BAR (eval_at_sup | eval_at_sub | eval_at_sup eval_at_sub); eval_at_sub: UNDERSCORE L_BRACE (expr | equality) R_BRACE; eval_at_sup: CARET L_BRACE (expr | equality) R_BRACE; exp: exp CARET (atom | L_BRACE expr R_BRACE) subexpr? | comp; exp_nofunc: exp_nofunc CARET (atom | L_BRACE expr R_BRACE) subexpr? | comp_nofunc; comp: group | abs_group | func | atom | frac | binom | floor | ceil; comp_nofunc: group | abs_group | atom | frac | binom | floor | ceil; group: L_PAREN expr R_PAREN | L_BRACKET expr R_BRACKET | L_BRACE expr R_BRACE | L_BRACE_LITERAL expr R_BRACE_LITERAL; abs_group: BAR expr BAR; atom: (LETTER | SYMBOL) subexpr? | NUMBER | DIFFERENTIAL | mathit | bra | ket; bra: L_ANGLE expr (R_BAR | BAR); ket: (L_BAR | BAR) expr R_ANGLE; mathit: CMD_MATHIT L_BRACE mathit_text R_BRACE; mathit_text: LETTER*; frac: CMD_FRAC L_BRACE upper = expr R_BRACE L_BRACE lower = expr R_BRACE; binom: (CMD_BINOM | CMD_DBINOM | CMD_TBINOM) L_BRACE n = expr R_BRACE L_BRACE k = expr R_BRACE; floor: L_FLOOR val = expr R_FLOOR; ceil: L_CEIL val = expr R_CEIL; func_normal: FUNC_EXP | FUNC_LOG | FUNC_LN | FUNC_SIN | FUNC_COS | FUNC_TAN | FUNC_CSC | FUNC_SEC | FUNC_COT | FUNC_ARCSIN | FUNC_ARCCOS | FUNC_ARCTAN | FUNC_ARCCSC | FUNC_ARCSEC | FUNC_ARCCOT | FUNC_SINH | FUNC_COSH | FUNC_TANH | FUNC_ARSINH | FUNC_ARCOSH | FUNC_ARTANH; func: func_normal (subexpr? supexpr? | supexpr? subexpr?) ( L_PAREN func_arg R_PAREN | func_arg_noparens ) | (LETTER | SYMBOL) subexpr? // e.g. f(x) L_PAREN args R_PAREN | FUNC_INT (subexpr supexpr | supexpr subexpr)? ( additive? DIFFERENTIAL | frac | additive ) | FUNC_SQRT (L_BRACKET root = expr R_BRACKET)? L_BRACE base = expr R_BRACE | FUNC_OVERLINE L_BRACE base = expr R_BRACE | (FUNC_SUM | FUNC_PROD) (subeq supexpr | supexpr subeq) mp | FUNC_LIM limit_sub mp; args: (expr ',' args) | expr; limit_sub: UNDERSCORE L_BRACE (LETTER | SYMBOL) LIM_APPROACH_SYM expr ( CARET L_BRACE (ADD | SUB) R_BRACE )? R_BRACE; func_arg: expr | (expr ',' func_arg); func_arg_noparens: mp_nofunc; subexpr: UNDERSCORE (atom | L_BRACE expr R_BRACE); supexpr: CARET (atom | L_BRACE expr R_BRACE); subeq: UNDERSCORE L_BRACE equality R_BRACE; supeq: UNDERSCORE L_BRACE equality R_BRACE; sympy-sympy-1.9/sympy/parsing/latex/__init__.py000066400000000000000000000017371412543434000220050ustar00rootroot00000000000000from sympy.external import import_module from sympy.utilities.decorator import doctest_depends_on from .errors import LaTeXParsingError # noqa @doctest_depends_on(modules=('antlr4',)) def parse_latex(s): r"""Converts the string ``s`` to a SymPy ``Expr`` Parameters ========== s : str The LaTeX string to parse. In Python source containing LaTeX, *raw strings* (denoted with ``r"``, like this one) are preferred, as LaTeX makes liberal use of the ``\`` character, which would trigger escaping in normal Python strings. Examples ======== >>> from sympy.parsing.latex import parse_latex >>> expr = parse_latex(r"\frac {1 + \sqrt {\a}} {\b}") >>> expr (sqrt(a) + 1)/b >>> expr.evalf(4, subs=dict(a=5, b=2)) 1.618 """ _latex = import_module( 'sympy.parsing.latex._parse_latex_antlr', import_kwargs={'fromlist': ['X']}) if _latex is not None: return _latex.parse_latex(s) sympy-sympy-1.9/sympy/parsing/latex/_antlr/000077500000000000000000000000001412543434000211435ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/latex/_antlr/__init__.py000066400000000000000000000006241412543434000232560ustar00rootroot00000000000000 # encoding: utf-8 # *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND *** # # Generated from ../LaTeX.g4, derived from latex2sympy # latex2sympy is licensed under the MIT license # https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt sympy-sympy-1.9/sympy/parsing/latex/_antlr/latexlexer.py000066400000000000000000001112661412543434000237010ustar00rootroot00000000000000 # encoding: utf-8 # *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND *** # # Generated from ../LaTeX.g4, derived from latex2sympy # latex2sympy is licensed under the MIT license # https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt from __future__ import print_function from antlr4 import * from io import StringIO import sys def serializedATN(): with StringIO() as buf: buf.write(u"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\2") buf.write(u"Z\u0390\b\1\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4") buf.write(u"\7\t\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r") buf.write(u"\t\r\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22") buf.write(u"\4\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4") buf.write(u"\30\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35") buf.write(u"\t\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4") buf.write(u"$\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\4*\t*\4+\t+\4,\t") buf.write(u",\4-\t-\4.\t.\4/\t/\4\60\t\60\4\61\t\61\4\62\t\62\4\63") buf.write(u"\t\63\4\64\t\64\4\65\t\65\4\66\t\66\4\67\t\67\48\t8\4") buf.write(u"9\t9\4:\t:\4;\t;\4<\t<\4=\t=\4>\t>\4?\t?\4@\t@\4A\tA") buf.write(u"\4B\tB\4C\tC\4D\tD\4E\tE\4F\tF\4G\tG\4H\tH\4I\tI\4J\t") buf.write(u"J\4K\tK\4L\tL\4M\tM\4N\tN\4O\tO\4P\tP\4Q\tQ\4R\tR\4S") buf.write(u"\tS\4T\tT\4U\tU\4V\tV\4W\tW\4X\tX\4Y\tY\4Z\tZ\4[\t[\3") buf.write(u"\2\3\2\3\3\6\3\u00bb\n\3\r\3\16\3\u00bc\3\3\3\3\3\4\3") buf.write(u"\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\3\4\5\4\u00cd") buf.write(u"\n\4\3\4\3\4\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5\3\5") buf.write(u"\3\5\5\5\u00dc\n\5\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\3") buf.write(u"\6\3\6\3\6\3\6\3\6\3\6\3\6\5\6\u00ed\n\6\3\6\3\6\3\7") buf.write(u"\3\7\3\7\3\7\3\7\3\7\3\7\3\7\3\b\3\b\3\b\3\b\3\b\3\b") buf.write(u"\3\b\3\b\3\b\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t\3\t") buf.write(u"\3\t\3\t\3\t\3\t\3\t\5\t\u0111\n\t\3\t\3\t\3\n\3\n\3") buf.write(u"\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3\n\3") buf.write(u"\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13\3\13") buf.write(u"\3\13\3\13\3\13\3\13\3\13\3\13\3\f\3\f\3\f\3\f\3\f\3") buf.write(u"\f\3\f\3\f\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\r\3\16\3") buf.write(u"\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16") buf.write(u"\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3") buf.write(u"\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16") buf.write(u"\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\3") buf.write(u"\16\3\16\3\16\3\16\3\16\3\16\3\16\3\16\5\16\u0179\n\16") buf.write(u"\3\16\3\16\3\17\3\17\3\20\3\20\3\21\3\21\3\22\3\22\3") buf.write(u"\23\3\23\3\24\3\24\3\25\3\25\3\26\3\26\3\27\3\27\3\27") buf.write(u"\3\30\3\30\3\30\3\31\3\31\3\32\3\32\3\33\3\33\3\34\3") buf.write(u"\34\3\34\3\34\3\34\3\34\3\34\3\34\3\35\3\35\3\35\3\35") buf.write(u"\3\35\3\35\3\35\3\36\3\36\3\36\3\36\3\36\3\36\3\36\3") buf.write(u"\36\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3\37\3 \3 \3 ") buf.write(u"\3 \3 \3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3") buf.write(u"!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!") buf.write(u"\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3") buf.write(u"!\3!\3!\3!\3!\5!\u01f4\n!\3\"\3\"\3\"\3\"\3\"\3#\3#\3") buf.write(u"#\3#\3#\3$\3$\3$\3$\3$\3$\3%\3%\3%\3%\3%\3&\3&\3&\3&") buf.write(u"\3&\3\'\3\'\3\'\3\'\3(\3(\3(\3(\3(\3)\3)\3)\3)\3)\3*") buf.write(u"\3*\3*\3*\3*\3+\3+\3+\3+\3+\3,\3,\3,\3,\3,\3-\3-\3-\3") buf.write(u"-\3-\3.\3.\3.\3.\3.\3.\3.\3.\3/\3/\3/\3/\3/\3/\3/\3/") buf.write(u"\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\60\3\61\3\61\3") buf.write(u"\61\3\61\3\61\3\61\3\61\3\61\3\62\3\62\3\62\3\62\3\62") buf.write(u"\3\62\3\62\3\62\3\63\3\63\3\63\3\63\3\63\3\63\3\63\3") buf.write(u"\63\3\64\3\64\3\64\3\64\3\64\3\64\3\65\3\65\3\65\3\65") buf.write(u"\3\65\3\65\3\66\3\66\3\66\3\66\3\66\3\66\3\67\3\67\3") buf.write(u"\67\3\67\3\67\3\67\3\67\3\67\38\38\38\38\38\38\38\38") buf.write(u"\39\39\39\39\39\39\39\39\3:\3:\3:\3:\3:\3:\3:\3:\3;\3") buf.write(u";\3;\3;\3;\3;\3;\3;\3<\3<\3<\3<\3<\3<\3<\3=\3=\3=\3=") buf.write(u"\3=\3=\3=\3>\3>\3>\3>\3>\3>\3?\3?\3?\3?\3?\3?\3?\3?\3") buf.write(u"?\3?\3@\3@\3@\3@\3@\3@\3@\3A\3A\3A\3A\3A\3A\3B\3B\3B") buf.write(u"\3B\3B\3C\3C\3C\3C\3C\3C\3D\3D\3D\3D\3D\3D\3D\3E\3E\3") buf.write(u"E\3E\3E\3E\3E\3E\3F\3F\3F\3F\3F\3F\3F\3F\3G\3G\3G\3G") buf.write(u"\3G\3G\3G\3G\3H\3H\3I\3I\3J\3J\3K\3K\3L\3L\7L\u02fb\n") buf.write(u"L\fL\16L\u02fe\13L\3L\3L\3L\6L\u0303\nL\rL\16L\u0304") buf.write(u"\5L\u0307\nL\3M\3M\3N\3N\3O\6O\u030e\nO\rO\16O\u030f") buf.write(u"\3O\3O\3O\3O\3O\7O\u0317\nO\fO\16O\u031a\13O\3O\7O\u031d") buf.write(u"\nO\fO\16O\u0320\13O\3O\3O\3O\3O\3O\7O\u0327\nO\fO\16") buf.write(u"O\u032a\13O\3O\3O\6O\u032e\nO\rO\16O\u032f\5O\u0332\n") buf.write(u"O\3P\3P\7P\u0336\nP\fP\16P\u0339\13P\5P\u033b\nP\3P\3") buf.write(u"P\3P\7P\u0340\nP\fP\16P\u0343\13P\3P\5P\u0346\nP\5P\u0348") buf.write(u"\nP\3Q\3Q\3Q\3Q\3Q\3R\3R\3S\3S\3S\3S\3S\3S\3S\3S\3S\5") buf.write(u"S\u035a\nS\3T\3T\3T\3T\3T\3T\3U\3U\3U\3U\3U\3U\3U\3U") buf.write(u"\3U\3U\3V\3V\3W\3W\3W\3W\3W\3W\3W\3W\3W\5W\u0377\nW\3") buf.write(u"X\3X\3X\3X\3X\3X\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Y\3Z\3Z") buf.write(u"\3[\3[\6[\u038d\n[\r[\16[\u038e\5\u02fc\u0337\u0341\2") buf.write(u"\\\3\3\5\4\7\5\t\6\13\7\r\b\17\t\21\n\23\13\25\f\27\r") buf.write(u"\31\16\33\17\35\20\37\21!\22#\23%\24\'\25)\26+\27-\30") buf.write(u"/\31\61\32\63\33\65\34\67\359\36;\37= ?!A\"C#E$G%I&K") buf.write(u"\'M(O)Q*S+U,W-Y.[/]\60_\61a\62c\63e\64g\65i\66k\67m8") buf.write(u"o9q:s;u{?}@\177A\u0081B\u0083C\u0085D\u0087E\u0089") buf.write(u"F\u008bG\u008dH\u008fI\u0091J\u0093K\u0095\2\u0097L\u0099") buf.write(u"M\u009b\2\u009dN\u009fO\u00a1P\u00a3Q\u00a5R\u00a7S\u00a9") buf.write(u"T\u00abU\u00adV\u00afW\u00b1X\u00b3Y\u00b5Z\3\2\5\5\2") buf.write(u"\13\f\17\17\"\"\4\2C\\c|\3\2\62;\2\u03b7\2\3\3\2\2\2") buf.write(u"\2\5\3\2\2\2\2\7\3\2\2\2\2\t\3\2\2\2\2\13\3\2\2\2\2\r") buf.write(u"\3\2\2\2\2\17\3\2\2\2\2\21\3\2\2\2\2\23\3\2\2\2\2\25") buf.write(u"\3\2\2\2\2\27\3\2\2\2\2\31\3\2\2\2\2\33\3\2\2\2\2\35") buf.write(u"\3\2\2\2\2\37\3\2\2\2\2!\3\2\2\2\2#\3\2\2\2\2%\3\2\2") buf.write(u"\2\2\'\3\2\2\2\2)\3\2\2\2\2+\3\2\2\2\2-\3\2\2\2\2/\3") buf.write(u"\2\2\2\2\61\3\2\2\2\2\63\3\2\2\2\2\65\3\2\2\2\2\67\3") buf.write(u"\2\2\2\29\3\2\2\2\2;\3\2\2\2\2=\3\2\2\2\2?\3\2\2\2\2") buf.write(u"A\3\2\2\2\2C\3\2\2\2\2E\3\2\2\2\2G\3\2\2\2\2I\3\2\2\2") buf.write(u"\2K\3\2\2\2\2M\3\2\2\2\2O\3\2\2\2\2Q\3\2\2\2\2S\3\2\2") buf.write(u"\2\2U\3\2\2\2\2W\3\2\2\2\2Y\3\2\2\2\2[\3\2\2\2\2]\3\2") buf.write(u"\2\2\2_\3\2\2\2\2a\3\2\2\2\2c\3\2\2\2\2e\3\2\2\2\2g\3") buf.write(u"\2\2\2\2i\3\2\2\2\2k\3\2\2\2\2m\3\2\2\2\2o\3\2\2\2\2") buf.write(u"q\3\2\2\2\2s\3\2\2\2\2u\3\2\2\2\2w\3\2\2\2\2y\3\2\2\2") buf.write(u"\2{\3\2\2\2\2}\3\2\2\2\2\177\3\2\2\2\2\u0081\3\2\2\2") buf.write(u"\2\u0083\3\2\2\2\2\u0085\3\2\2\2\2\u0087\3\2\2\2\2\u0089") buf.write(u"\3\2\2\2\2\u008b\3\2\2\2\2\u008d\3\2\2\2\2\u008f\3\2") buf.write(u"\2\2\2\u0091\3\2\2\2\2\u0093\3\2\2\2\2\u0097\3\2\2\2") buf.write(u"\2\u0099\3\2\2\2\2\u009d\3\2\2\2\2\u009f\3\2\2\2\2\u00a1") buf.write(u"\3\2\2\2\2\u00a3\3\2\2\2\2\u00a5\3\2\2\2\2\u00a7\3\2") buf.write(u"\2\2\2\u00a9\3\2\2\2\2\u00ab\3\2\2\2\2\u00ad\3\2\2\2") buf.write(u"\2\u00af\3\2\2\2\2\u00b1\3\2\2\2\2\u00b3\3\2\2\2\2\u00b5") buf.write(u"\3\2\2\2\3\u00b7\3\2\2\2\5\u00ba\3\2\2\2\7\u00cc\3\2") buf.write(u"\2\2\t\u00db\3\2\2\2\13\u00ec\3\2\2\2\r\u00f0\3\2\2\2") buf.write(u"\17\u00f8\3\2\2\2\21\u0110\3\2\2\2\23\u0114\3\2\2\2\25") buf.write(u"\u0123\3\2\2\2\27\u0134\3\2\2\2\31\u013c\3\2\2\2\33\u0178") buf.write(u"\3\2\2\2\35\u017c\3\2\2\2\37\u017e\3\2\2\2!\u0180\3\2") buf.write(u"\2\2#\u0182\3\2\2\2%\u0184\3\2\2\2\'\u0186\3\2\2\2)\u0188") buf.write(u"\3\2\2\2+\u018a\3\2\2\2-\u018c\3\2\2\2/\u018f\3\2\2\2") buf.write(u"\61\u0192\3\2\2\2\63\u0194\3\2\2\2\65\u0196\3\2\2\2\67") buf.write(u"\u0198\3\2\2\29\u01a0\3\2\2\2;\u01a7\3\2\2\2=\u01af\3") buf.write(u"\2\2\2?\u01b7\3\2\2\2A\u01f3\3\2\2\2C\u01f5\3\2\2\2E") buf.write(u"\u01fa\3\2\2\2G\u01ff\3\2\2\2I\u0205\3\2\2\2K\u020a\3") buf.write(u"\2\2\2M\u020f\3\2\2\2O\u0213\3\2\2\2Q\u0218\3\2\2\2S") buf.write(u"\u021d\3\2\2\2U\u0222\3\2\2\2W\u0227\3\2\2\2Y\u022c\3") buf.write(u"\2\2\2[\u0231\3\2\2\2]\u0239\3\2\2\2_\u0241\3\2\2\2a") buf.write(u"\u0249\3\2\2\2c\u0251\3\2\2\2e\u0259\3\2\2\2g\u0261\3") buf.write(u"\2\2\2i\u0267\3\2\2\2k\u026d\3\2\2\2m\u0273\3\2\2\2o") buf.write(u"\u027b\3\2\2\2q\u0283\3\2\2\2s\u028b\3\2\2\2u\u0293\3") buf.write(u"\2\2\2w\u029b\3\2\2\2y\u02a2\3\2\2\2{\u02a9\3\2\2\2}") buf.write(u"\u02af\3\2\2\2\177\u02b9\3\2\2\2\u0081\u02c0\3\2\2\2") buf.write(u"\u0083\u02c6\3\2\2\2\u0085\u02cb\3\2\2\2\u0087\u02d1") buf.write(u"\3\2\2\2\u0089\u02d8\3\2\2\2\u008b\u02e0\3\2\2\2\u008d") buf.write(u"\u02e8\3\2\2\2\u008f\u02f0\3\2\2\2\u0091\u02f2\3\2\2") buf.write(u"\2\u0093\u02f4\3\2\2\2\u0095\u02f6\3\2\2\2\u0097\u02f8") buf.write(u"\3\2\2\2\u0099\u0308\3\2\2\2\u009b\u030a\3\2\2\2\u009d") buf.write(u"\u0331\3\2\2\2\u009f\u0347\3\2\2\2\u00a1\u0349\3\2\2") buf.write(u"\2\u00a3\u034e\3\2\2\2\u00a5\u0359\3\2\2\2\u00a7\u035b") buf.write(u"\3\2\2\2\u00a9\u0361\3\2\2\2\u00ab\u036b\3\2\2\2\u00ad") buf.write(u"\u0376\3\2\2\2\u00af\u0378\3\2\2\2\u00b1\u037e\3\2\2") buf.write(u"\2\u00b3\u0388\3\2\2\2\u00b5\u038a\3\2\2\2\u00b7\u00b8") buf.write(u"\7.\2\2\u00b8\4\3\2\2\2\u00b9\u00bb\t\2\2\2\u00ba\u00b9") buf.write(u"\3\2\2\2\u00bb\u00bc\3\2\2\2\u00bc\u00ba\3\2\2\2\u00bc") buf.write(u"\u00bd\3\2\2\2\u00bd\u00be\3\2\2\2\u00be\u00bf\b\3\2") buf.write(u"\2\u00bf\6\3\2\2\2\u00c0\u00c1\7^\2\2\u00c1\u00cd\7.") buf.write(u"\2\2\u00c2\u00c3\7^\2\2\u00c3\u00c4\7v\2\2\u00c4\u00c5") buf.write(u"\7j\2\2\u00c5\u00c6\7k\2\2\u00c6\u00c7\7p\2\2\u00c7\u00c8") buf.write(u"\7u\2\2\u00c8\u00c9\7r\2\2\u00c9\u00ca\7c\2\2\u00ca\u00cb") buf.write(u"\7e\2\2\u00cb\u00cd\7g\2\2\u00cc\u00c0\3\2\2\2\u00cc") buf.write(u"\u00c2\3\2\2\2\u00cd\u00ce\3\2\2\2\u00ce\u00cf\b\4\2") buf.write(u"\2\u00cf\b\3\2\2\2\u00d0\u00d1\7^\2\2\u00d1\u00dc\7<") buf.write(u"\2\2\u00d2\u00d3\7^\2\2\u00d3\u00d4\7o\2\2\u00d4\u00d5") buf.write(u"\7g\2\2\u00d5\u00d6\7f\2\2\u00d6\u00d7\7u\2\2\u00d7\u00d8") buf.write(u"\7r\2\2\u00d8\u00d9\7c\2\2\u00d9\u00da\7e\2\2\u00da\u00dc") buf.write(u"\7g\2\2\u00db\u00d0\3\2\2\2\u00db\u00d2\3\2\2\2\u00dc") buf.write(u"\u00dd\3\2\2\2\u00dd\u00de\b\5\2\2\u00de\n\3\2\2\2\u00df") buf.write(u"\u00e0\7^\2\2\u00e0\u00ed\7=\2\2\u00e1\u00e2\7^\2\2\u00e2") buf.write(u"\u00e3\7v\2\2\u00e3\u00e4\7j\2\2\u00e4\u00e5\7k\2\2\u00e5") buf.write(u"\u00e6\7e\2\2\u00e6\u00e7\7m\2\2\u00e7\u00e8\7u\2\2\u00e8") buf.write(u"\u00e9\7r\2\2\u00e9\u00ea\7c\2\2\u00ea\u00eb\7e\2\2\u00eb") buf.write(u"\u00ed\7g\2\2\u00ec\u00df\3\2\2\2\u00ec\u00e1\3\2\2\2") buf.write(u"\u00ed\u00ee\3\2\2\2\u00ee\u00ef\b\6\2\2\u00ef\f\3\2") buf.write(u"\2\2\u00f0\u00f1\7^\2\2\u00f1\u00f2\7s\2\2\u00f2\u00f3") buf.write(u"\7w\2\2\u00f3\u00f4\7c\2\2\u00f4\u00f5\7f\2\2\u00f5\u00f6") buf.write(u"\3\2\2\2\u00f6\u00f7\b\7\2\2\u00f7\16\3\2\2\2\u00f8\u00f9") buf.write(u"\7^\2\2\u00f9\u00fa\7s\2\2\u00fa\u00fb\7s\2\2\u00fb\u00fc") buf.write(u"\7w\2\2\u00fc\u00fd\7c\2\2\u00fd\u00fe\7f\2\2\u00fe\u00ff") buf.write(u"\3\2\2\2\u00ff\u0100\b\b\2\2\u0100\20\3\2\2\2\u0101\u0102") buf.write(u"\7^\2\2\u0102\u0111\7#\2\2\u0103\u0104\7^\2\2\u0104\u0105") buf.write(u"\7p\2\2\u0105\u0106\7g\2\2\u0106\u0107\7i\2\2\u0107\u0108") buf.write(u"\7v\2\2\u0108\u0109\7j\2\2\u0109\u010a\7k\2\2\u010a\u010b") buf.write(u"\7p\2\2\u010b\u010c\7u\2\2\u010c\u010d\7r\2\2\u010d\u010e") buf.write(u"\7c\2\2\u010e\u010f\7e\2\2\u010f\u0111\7g\2\2\u0110\u0101") buf.write(u"\3\2\2\2\u0110\u0103\3\2\2\2\u0111\u0112\3\2\2\2\u0112") buf.write(u"\u0113\b\t\2\2\u0113\22\3\2\2\2\u0114\u0115\7^\2\2\u0115") buf.write(u"\u0116\7p\2\2\u0116\u0117\7g\2\2\u0117\u0118\7i\2\2\u0118") buf.write(u"\u0119\7o\2\2\u0119\u011a\7g\2\2\u011a\u011b\7f\2\2\u011b") buf.write(u"\u011c\7u\2\2\u011c\u011d\7r\2\2\u011d\u011e\7c\2\2\u011e") buf.write(u"\u011f\7e\2\2\u011f\u0120\7g\2\2\u0120\u0121\3\2\2\2") buf.write(u"\u0121\u0122\b\n\2\2\u0122\24\3\2\2\2\u0123\u0124\7^") buf.write(u"\2\2\u0124\u0125\7p\2\2\u0125\u0126\7g\2\2\u0126\u0127") buf.write(u"\7i\2\2\u0127\u0128\7v\2\2\u0128\u0129\7j\2\2\u0129\u012a") buf.write(u"\7k\2\2\u012a\u012b\7e\2\2\u012b\u012c\7m\2\2\u012c\u012d") buf.write(u"\7u\2\2\u012d\u012e\7r\2\2\u012e\u012f\7c\2\2\u012f\u0130") buf.write(u"\7e\2\2\u0130\u0131\7g\2\2\u0131\u0132\3\2\2\2\u0132") buf.write(u"\u0133\b\13\2\2\u0133\26\3\2\2\2\u0134\u0135\7^\2\2\u0135") buf.write(u"\u0136\7n\2\2\u0136\u0137\7g\2\2\u0137\u0138\7h\2\2\u0138") buf.write(u"\u0139\7v\2\2\u0139\u013a\3\2\2\2\u013a\u013b\b\f\2\2") buf.write(u"\u013b\30\3\2\2\2\u013c\u013d\7^\2\2\u013d\u013e\7t\2") buf.write(u"\2\u013e\u013f\7k\2\2\u013f\u0140\7i\2\2\u0140\u0141") buf.write(u"\7j\2\2\u0141\u0142\7v\2\2\u0142\u0143\3\2\2\2\u0143") buf.write(u"\u0144\b\r\2\2\u0144\32\3\2\2\2\u0145\u0146\7^\2\2\u0146") buf.write(u"\u0147\7x\2\2\u0147\u0148\7t\2\2\u0148\u0149\7w\2\2\u0149") buf.write(u"\u014a\7n\2\2\u014a\u0179\7g\2\2\u014b\u014c\7^\2\2\u014c") buf.write(u"\u014d\7x\2\2\u014d\u014e\7e\2\2\u014e\u014f\7g\2\2\u014f") buf.write(u"\u0150\7p\2\2\u0150\u0151\7v\2\2\u0151\u0152\7g\2\2\u0152") buf.write(u"\u0179\7t\2\2\u0153\u0154\7^\2\2\u0154\u0155\7x\2\2\u0155") buf.write(u"\u0156\7d\2\2\u0156\u0157\7q\2\2\u0157\u0179\7z\2\2\u0158") buf.write(u"\u0159\7^\2\2\u0159\u015a\7x\2\2\u015a\u015b\7u\2\2\u015b") buf.write(u"\u015c\7m\2\2\u015c\u015d\7k\2\2\u015d\u0179\7r\2\2\u015e") buf.write(u"\u015f\7^\2\2\u015f\u0160\7x\2\2\u0160\u0161\7u\2\2\u0161") buf.write(u"\u0162\7r\2\2\u0162\u0163\7c\2\2\u0163\u0164\7e\2\2\u0164") buf.write(u"\u0179\7g\2\2\u0165\u0166\7^\2\2\u0166\u0167\7j\2\2\u0167") buf.write(u"\u0168\7h\2\2\u0168\u0169\7k\2\2\u0169\u0179\7n\2\2\u016a") buf.write(u"\u016b\7^\2\2\u016b\u0179\7,\2\2\u016c\u016d\7^\2\2\u016d") buf.write(u"\u0179\7/\2\2\u016e\u016f\7^\2\2\u016f\u0179\7\60\2\2") buf.write(u"\u0170\u0171\7^\2\2\u0171\u0179\7\61\2\2\u0172\u0173") buf.write(u"\7^\2\2\u0173\u0179\7$\2\2\u0174\u0175\7^\2\2\u0175\u0179") buf.write(u"\7*\2\2\u0176\u0177\7^\2\2\u0177\u0179\7?\2\2\u0178\u0145") buf.write(u"\3\2\2\2\u0178\u014b\3\2\2\2\u0178\u0153\3\2\2\2\u0178") buf.write(u"\u0158\3\2\2\2\u0178\u015e\3\2\2\2\u0178\u0165\3\2\2") buf.write(u"\2\u0178\u016a\3\2\2\2\u0178\u016c\3\2\2\2\u0178\u016e") buf.write(u"\3\2\2\2\u0178\u0170\3\2\2\2\u0178\u0172\3\2\2\2\u0178") buf.write(u"\u0174\3\2\2\2\u0178\u0176\3\2\2\2\u0179\u017a\3\2\2") buf.write(u"\2\u017a\u017b\b\16\2\2\u017b\34\3\2\2\2\u017c\u017d") buf.write(u"\7-\2\2\u017d\36\3\2\2\2\u017e\u017f\7/\2\2\u017f \3") buf.write(u"\2\2\2\u0180\u0181\7,\2\2\u0181\"\3\2\2\2\u0182\u0183") buf.write(u"\7\61\2\2\u0183$\3\2\2\2\u0184\u0185\7*\2\2\u0185&\3") buf.write(u"\2\2\2\u0186\u0187\7+\2\2\u0187(\3\2\2\2\u0188\u0189") buf.write(u"\7}\2\2\u0189*\3\2\2\2\u018a\u018b\7\177\2\2\u018b,\3") buf.write(u"\2\2\2\u018c\u018d\7^\2\2\u018d\u018e\7}\2\2\u018e.\3") buf.write(u"\2\2\2\u018f\u0190\7^\2\2\u0190\u0191\7\177\2\2\u0191") buf.write(u"\60\3\2\2\2\u0192\u0193\7]\2\2\u0193\62\3\2\2\2\u0194") buf.write(u"\u0195\7_\2\2\u0195\64\3\2\2\2\u0196\u0197\7~\2\2\u0197") buf.write(u"\66\3\2\2\2\u0198\u0199\7^\2\2\u0199\u019a\7t\2\2\u019a") buf.write(u"\u019b\7k\2\2\u019b\u019c\7i\2\2\u019c\u019d\7j\2\2\u019d") buf.write(u"\u019e\7v\2\2\u019e\u019f\7~\2\2\u019f8\3\2\2\2\u01a0") buf.write(u"\u01a1\7^\2\2\u01a1\u01a2\7n\2\2\u01a2\u01a3\7g\2\2\u01a3") buf.write(u"\u01a4\7h\2\2\u01a4\u01a5\7v\2\2\u01a5\u01a6\7~\2\2\u01a6") buf.write(u":\3\2\2\2\u01a7\u01a8\7^\2\2\u01a8\u01a9\7n\2\2\u01a9") buf.write(u"\u01aa\7c\2\2\u01aa\u01ab\7p\2\2\u01ab\u01ac\7i\2\2\u01ac") buf.write(u"\u01ad\7n\2\2\u01ad\u01ae\7g\2\2\u01ae<\3\2\2\2\u01af") buf.write(u"\u01b0\7^\2\2\u01b0\u01b1\7t\2\2\u01b1\u01b2\7c\2\2\u01b2") buf.write(u"\u01b3\7p\2\2\u01b3\u01b4\7i\2\2\u01b4\u01b5\7n\2\2\u01b5") buf.write(u"\u01b6\7g\2\2\u01b6>\3\2\2\2\u01b7\u01b8\7^\2\2\u01b8") buf.write(u"\u01b9\7n\2\2\u01b9\u01ba\7k\2\2\u01ba\u01bb\7o\2\2\u01bb") buf.write(u"@\3\2\2\2\u01bc\u01bd\7^\2\2\u01bd\u01be\7v\2\2\u01be") buf.write(u"\u01f4\7q\2\2\u01bf\u01c0\7^\2\2\u01c0\u01c1\7t\2\2\u01c1") buf.write(u"\u01c2\7k\2\2\u01c2\u01c3\7i\2\2\u01c3\u01c4\7j\2\2\u01c4") buf.write(u"\u01c5\7v\2\2\u01c5\u01c6\7c\2\2\u01c6\u01c7\7t\2\2\u01c7") buf.write(u"\u01c8\7t\2\2\u01c8\u01c9\7q\2\2\u01c9\u01f4\7y\2\2\u01ca") buf.write(u"\u01cb\7^\2\2\u01cb\u01cc\7T\2\2\u01cc\u01cd\7k\2\2\u01cd") buf.write(u"\u01ce\7i\2\2\u01ce\u01cf\7j\2\2\u01cf\u01d0\7v\2\2\u01d0") buf.write(u"\u01d1\7c\2\2\u01d1\u01d2\7t\2\2\u01d2\u01d3\7t\2\2\u01d3") buf.write(u"\u01d4\7q\2\2\u01d4\u01f4\7y\2\2\u01d5\u01d6\7^\2\2\u01d6") buf.write(u"\u01d7\7n\2\2\u01d7\u01d8\7q\2\2\u01d8\u01d9\7p\2\2\u01d9") buf.write(u"\u01da\7i\2\2\u01da\u01db\7t\2\2\u01db\u01dc\7k\2\2\u01dc") buf.write(u"\u01dd\7i\2\2\u01dd\u01de\7j\2\2\u01de\u01df\7v\2\2\u01df") buf.write(u"\u01e0\7c\2\2\u01e0\u01e1\7t\2\2\u01e1\u01e2\7t\2\2\u01e2") buf.write(u"\u01e3\7q\2\2\u01e3\u01f4\7y\2\2\u01e4\u01e5\7^\2\2\u01e5") buf.write(u"\u01e6\7N\2\2\u01e6\u01e7\7q\2\2\u01e7\u01e8\7p\2\2\u01e8") buf.write(u"\u01e9\7i\2\2\u01e9\u01ea\7t\2\2\u01ea\u01eb\7k\2\2\u01eb") buf.write(u"\u01ec\7i\2\2\u01ec\u01ed\7j\2\2\u01ed\u01ee\7v\2\2\u01ee") buf.write(u"\u01ef\7c\2\2\u01ef\u01f0\7t\2\2\u01f0\u01f1\7t\2\2\u01f1") buf.write(u"\u01f2\7q\2\2\u01f2\u01f4\7y\2\2\u01f3\u01bc\3\2\2\2") buf.write(u"\u01f3\u01bf\3\2\2\2\u01f3\u01ca\3\2\2\2\u01f3\u01d5") buf.write(u"\3\2\2\2\u01f3\u01e4\3\2\2\2\u01f4B\3\2\2\2\u01f5\u01f6") buf.write(u"\7^\2\2\u01f6\u01f7\7k\2\2\u01f7\u01f8\7p\2\2\u01f8\u01f9") buf.write(u"\7v\2\2\u01f9D\3\2\2\2\u01fa\u01fb\7^\2\2\u01fb\u01fc") buf.write(u"\7u\2\2\u01fc\u01fd\7w\2\2\u01fd\u01fe\7o\2\2\u01feF") buf.write(u"\3\2\2\2\u01ff\u0200\7^\2\2\u0200\u0201\7r\2\2\u0201") buf.write(u"\u0202\7t\2\2\u0202\u0203\7q\2\2\u0203\u0204\7f\2\2\u0204") buf.write(u"H\3\2\2\2\u0205\u0206\7^\2\2\u0206\u0207\7g\2\2\u0207") buf.write(u"\u0208\7z\2\2\u0208\u0209\7r\2\2\u0209J\3\2\2\2\u020a") buf.write(u"\u020b\7^\2\2\u020b\u020c\7n\2\2\u020c\u020d\7q\2\2\u020d") buf.write(u"\u020e\7i\2\2\u020eL\3\2\2\2\u020f\u0210\7^\2\2\u0210") buf.write(u"\u0211\7n\2\2\u0211\u0212\7p\2\2\u0212N\3\2\2\2\u0213") buf.write(u"\u0214\7^\2\2\u0214\u0215\7u\2\2\u0215\u0216\7k\2\2\u0216") buf.write(u"\u0217\7p\2\2\u0217P\3\2\2\2\u0218\u0219\7^\2\2\u0219") buf.write(u"\u021a\7e\2\2\u021a\u021b\7q\2\2\u021b\u021c\7u\2\2\u021c") buf.write(u"R\3\2\2\2\u021d\u021e\7^\2\2\u021e\u021f\7v\2\2\u021f") buf.write(u"\u0220\7c\2\2\u0220\u0221\7p\2\2\u0221T\3\2\2\2\u0222") buf.write(u"\u0223\7^\2\2\u0223\u0224\7e\2\2\u0224\u0225\7u\2\2\u0225") buf.write(u"\u0226\7e\2\2\u0226V\3\2\2\2\u0227\u0228\7^\2\2\u0228") buf.write(u"\u0229\7u\2\2\u0229\u022a\7g\2\2\u022a\u022b\7e\2\2\u022b") buf.write(u"X\3\2\2\2\u022c\u022d\7^\2\2\u022d\u022e\7e\2\2\u022e") buf.write(u"\u022f\7q\2\2\u022f\u0230\7v\2\2\u0230Z\3\2\2\2\u0231") buf.write(u"\u0232\7^\2\2\u0232\u0233\7c\2\2\u0233\u0234\7t\2\2\u0234") buf.write(u"\u0235\7e\2\2\u0235\u0236\7u\2\2\u0236\u0237\7k\2\2\u0237") buf.write(u"\u0238\7p\2\2\u0238\\\3\2\2\2\u0239\u023a\7^\2\2\u023a") buf.write(u"\u023b\7c\2\2\u023b\u023c\7t\2\2\u023c\u023d\7e\2\2\u023d") buf.write(u"\u023e\7e\2\2\u023e\u023f\7q\2\2\u023f\u0240\7u\2\2\u0240") buf.write(u"^\3\2\2\2\u0241\u0242\7^\2\2\u0242\u0243\7c\2\2\u0243") buf.write(u"\u0244\7t\2\2\u0244\u0245\7e\2\2\u0245\u0246\7v\2\2\u0246") buf.write(u"\u0247\7c\2\2\u0247\u0248\7p\2\2\u0248`\3\2\2\2\u0249") buf.write(u"\u024a\7^\2\2\u024a\u024b\7c\2\2\u024b\u024c\7t\2\2\u024c") buf.write(u"\u024d\7e\2\2\u024d\u024e\7e\2\2\u024e\u024f\7u\2\2\u024f") buf.write(u"\u0250\7e\2\2\u0250b\3\2\2\2\u0251\u0252\7^\2\2\u0252") buf.write(u"\u0253\7c\2\2\u0253\u0254\7t\2\2\u0254\u0255\7e\2\2\u0255") buf.write(u"\u0256\7u\2\2\u0256\u0257\7g\2\2\u0257\u0258\7e\2\2\u0258") buf.write(u"d\3\2\2\2\u0259\u025a\7^\2\2\u025a\u025b\7c\2\2\u025b") buf.write(u"\u025c\7t\2\2\u025c\u025d\7e\2\2\u025d\u025e\7e\2\2\u025e") buf.write(u"\u025f\7q\2\2\u025f\u0260\7v\2\2\u0260f\3\2\2\2\u0261") buf.write(u"\u0262\7^\2\2\u0262\u0263\7u\2\2\u0263\u0264\7k\2\2\u0264") buf.write(u"\u0265\7p\2\2\u0265\u0266\7j\2\2\u0266h\3\2\2\2\u0267") buf.write(u"\u0268\7^\2\2\u0268\u0269\7e\2\2\u0269\u026a\7q\2\2\u026a") buf.write(u"\u026b\7u\2\2\u026b\u026c\7j\2\2\u026cj\3\2\2\2\u026d") buf.write(u"\u026e\7^\2\2\u026e\u026f\7v\2\2\u026f\u0270\7c\2\2\u0270") buf.write(u"\u0271\7p\2\2\u0271\u0272\7j\2\2\u0272l\3\2\2\2\u0273") buf.write(u"\u0274\7^\2\2\u0274\u0275\7c\2\2\u0275\u0276\7t\2\2\u0276") buf.write(u"\u0277\7u\2\2\u0277\u0278\7k\2\2\u0278\u0279\7p\2\2\u0279") buf.write(u"\u027a\7j\2\2\u027an\3\2\2\2\u027b\u027c\7^\2\2\u027c") buf.write(u"\u027d\7c\2\2\u027d\u027e\7t\2\2\u027e\u027f\7e\2\2\u027f") buf.write(u"\u0280\7q\2\2\u0280\u0281\7u\2\2\u0281\u0282\7j\2\2\u0282") buf.write(u"p\3\2\2\2\u0283\u0284\7^\2\2\u0284\u0285\7c\2\2\u0285") buf.write(u"\u0286\7t\2\2\u0286\u0287\7v\2\2\u0287\u0288\7c\2\2\u0288") buf.write(u"\u0289\7p\2\2\u0289\u028a\7j\2\2\u028ar\3\2\2\2\u028b") buf.write(u"\u028c\7^\2\2\u028c\u028d\7n\2\2\u028d\u028e\7h\2\2\u028e") buf.write(u"\u028f\7n\2\2\u028f\u0290\7q\2\2\u0290\u0291\7q\2\2\u0291") buf.write(u"\u0292\7t\2\2\u0292t\3\2\2\2\u0293\u0294\7^\2\2\u0294") buf.write(u"\u0295\7t\2\2\u0295\u0296\7h\2\2\u0296\u0297\7n\2\2\u0297") buf.write(u"\u0298\7q\2\2\u0298\u0299\7q\2\2\u0299\u029a\7t\2\2\u029a") buf.write(u"v\3\2\2\2\u029b\u029c\7^\2\2\u029c\u029d\7n\2\2\u029d") buf.write(u"\u029e\7e\2\2\u029e\u029f\7g\2\2\u029f\u02a0\7k\2\2\u02a0") buf.write(u"\u02a1\7n\2\2\u02a1x\3\2\2\2\u02a2\u02a3\7^\2\2\u02a3") buf.write(u"\u02a4\7t\2\2\u02a4\u02a5\7e\2\2\u02a5\u02a6\7g\2\2\u02a6") buf.write(u"\u02a7\7k\2\2\u02a7\u02a8\7n\2\2\u02a8z\3\2\2\2\u02a9") buf.write(u"\u02aa\7^\2\2\u02aa\u02ab\7u\2\2\u02ab\u02ac\7s\2\2\u02ac") buf.write(u"\u02ad\7t\2\2\u02ad\u02ae\7v\2\2\u02ae|\3\2\2\2\u02af") buf.write(u"\u02b0\7^\2\2\u02b0\u02b1\7q\2\2\u02b1\u02b2\7x\2\2\u02b2") buf.write(u"\u02b3\7g\2\2\u02b3\u02b4\7t\2\2\u02b4\u02b5\7n\2\2\u02b5") buf.write(u"\u02b6\7k\2\2\u02b6\u02b7\7p\2\2\u02b7\u02b8\7g\2\2\u02b8") buf.write(u"~\3\2\2\2\u02b9\u02ba\7^\2\2\u02ba\u02bb\7v\2\2\u02bb") buf.write(u"\u02bc\7k\2\2\u02bc\u02bd\7o\2\2\u02bd\u02be\7g\2\2\u02be") buf.write(u"\u02bf\7u\2\2\u02bf\u0080\3\2\2\2\u02c0\u02c1\7^\2\2") buf.write(u"\u02c1\u02c2\7e\2\2\u02c2\u02c3\7f\2\2\u02c3\u02c4\7") buf.write(u"q\2\2\u02c4\u02c5\7v\2\2\u02c5\u0082\3\2\2\2\u02c6\u02c7") buf.write(u"\7^\2\2\u02c7\u02c8\7f\2\2\u02c8\u02c9\7k\2\2\u02c9\u02ca") buf.write(u"\7x\2\2\u02ca\u0084\3\2\2\2\u02cb\u02cc\7^\2\2\u02cc") buf.write(u"\u02cd\7h\2\2\u02cd\u02ce\7t\2\2\u02ce\u02cf\7c\2\2\u02cf") buf.write(u"\u02d0\7e\2\2\u02d0\u0086\3\2\2\2\u02d1\u02d2\7^\2\2") buf.write(u"\u02d2\u02d3\7d\2\2\u02d3\u02d4\7k\2\2\u02d4\u02d5\7") buf.write(u"p\2\2\u02d5\u02d6\7q\2\2\u02d6\u02d7\7o\2\2\u02d7\u0088") buf.write(u"\3\2\2\2\u02d8\u02d9\7^\2\2\u02d9\u02da\7f\2\2\u02da") buf.write(u"\u02db\7d\2\2\u02db\u02dc\7k\2\2\u02dc\u02dd\7p\2\2\u02dd") buf.write(u"\u02de\7q\2\2\u02de\u02df\7o\2\2\u02df\u008a\3\2\2\2") buf.write(u"\u02e0\u02e1\7^\2\2\u02e1\u02e2\7v\2\2\u02e2\u02e3\7") buf.write(u"d\2\2\u02e3\u02e4\7k\2\2\u02e4\u02e5\7p\2\2\u02e5\u02e6") buf.write(u"\7q\2\2\u02e6\u02e7\7o\2\2\u02e7\u008c\3\2\2\2\u02e8") buf.write(u"\u02e9\7^\2\2\u02e9\u02ea\7o\2\2\u02ea\u02eb\7c\2\2\u02eb") buf.write(u"\u02ec\7v\2\2\u02ec\u02ed\7j\2\2\u02ed\u02ee\7k\2\2\u02ee") buf.write(u"\u02ef\7v\2\2\u02ef\u008e\3\2\2\2\u02f0\u02f1\7a\2\2") buf.write(u"\u02f1\u0090\3\2\2\2\u02f2\u02f3\7`\2\2\u02f3\u0092\3") buf.write(u"\2\2\2\u02f4\u02f5\7<\2\2\u02f5\u0094\3\2\2\2\u02f6\u02f7") buf.write(u"\t\2\2\2\u02f7\u0096\3\2\2\2\u02f8\u02fc\7f\2\2\u02f9") buf.write(u"\u02fb\5\u0095K\2\u02fa\u02f9\3\2\2\2\u02fb\u02fe\3\2") buf.write(u"\2\2\u02fc\u02fd\3\2\2\2\u02fc\u02fa\3\2\2\2\u02fd\u0306") buf.write(u"\3\2\2\2\u02fe\u02fc\3\2\2\2\u02ff\u0307\t\3\2\2\u0300") buf.write(u"\u0302\7^\2\2\u0301\u0303\t\3\2\2\u0302\u0301\3\2\2\2") buf.write(u"\u0303\u0304\3\2\2\2\u0304\u0302\3\2\2\2\u0304\u0305") buf.write(u"\3\2\2\2\u0305\u0307\3\2\2\2\u0306\u02ff\3\2\2\2\u0306") buf.write(u"\u0300\3\2\2\2\u0307\u0098\3\2\2\2\u0308\u0309\t\3\2") buf.write(u"\2\u0309\u009a\3\2\2\2\u030a\u030b\t\4\2\2\u030b\u009c") buf.write(u"\3\2\2\2\u030c\u030e\5\u009bN\2\u030d\u030c\3\2\2\2\u030e") buf.write(u"\u030f\3\2\2\2\u030f\u030d\3\2\2\2\u030f\u0310\3\2\2") buf.write(u"\2\u0310\u0318\3\2\2\2\u0311\u0312\7.\2\2\u0312\u0313") buf.write(u"\5\u009bN\2\u0313\u0314\5\u009bN\2\u0314\u0315\5\u009b") buf.write(u"N\2\u0315\u0317\3\2\2\2\u0316\u0311\3\2\2\2\u0317\u031a") buf.write(u"\3\2\2\2\u0318\u0316\3\2\2\2\u0318\u0319\3\2\2\2\u0319") buf.write(u"\u0332\3\2\2\2\u031a\u0318\3\2\2\2\u031b\u031d\5\u009b") buf.write(u"N\2\u031c\u031b\3\2\2\2\u031d\u0320\3\2\2\2\u031e\u031c") buf.write(u"\3\2\2\2\u031e\u031f\3\2\2\2\u031f\u0328\3\2\2\2\u0320") buf.write(u"\u031e\3\2\2\2\u0321\u0322\7.\2\2\u0322\u0323\5\u009b") buf.write(u"N\2\u0323\u0324\5\u009bN\2\u0324\u0325\5\u009bN\2\u0325") buf.write(u"\u0327\3\2\2\2\u0326\u0321\3\2\2\2\u0327\u032a\3\2\2") buf.write(u"\2\u0328\u0326\3\2\2\2\u0328\u0329\3\2\2\2\u0329\u032b") buf.write(u"\3\2\2\2\u032a\u0328\3\2\2\2\u032b\u032d\7\60\2\2\u032c") buf.write(u"\u032e\5\u009bN\2\u032d\u032c\3\2\2\2\u032e\u032f\3\2") buf.write(u"\2\2\u032f\u032d\3\2\2\2\u032f\u0330\3\2\2\2\u0330\u0332") buf.write(u"\3\2\2\2\u0331\u030d\3\2\2\2\u0331\u031e\3\2\2\2\u0332") buf.write(u"\u009e\3\2\2\2\u0333\u0337\7(\2\2\u0334\u0336\5\u0095") buf.write(u"K\2\u0335\u0334\3\2\2\2\u0336\u0339\3\2\2\2\u0337\u0338") buf.write(u"\3\2\2\2\u0337\u0335\3\2\2\2\u0338\u033b\3\2\2\2\u0339") buf.write(u"\u0337\3\2\2\2\u033a\u0333\3\2\2\2\u033a\u033b\3\2\2") buf.write(u"\2\u033b\u033c\3\2\2\2\u033c\u0348\7?\2\2\u033d\u0345") buf.write(u"\7?\2\2\u033e\u0340\5\u0095K\2\u033f\u033e\3\2\2\2\u0340") buf.write(u"\u0343\3\2\2\2\u0341\u0342\3\2\2\2\u0341\u033f\3\2\2") buf.write(u"\2\u0342\u0344\3\2\2\2\u0343\u0341\3\2\2\2\u0344\u0346") buf.write(u"\7(\2\2\u0345\u0341\3\2\2\2\u0345\u0346\3\2\2\2\u0346") buf.write(u"\u0348\3\2\2\2\u0347\u033a\3\2\2\2\u0347\u033d\3\2\2") buf.write(u"\2\u0348\u00a0\3\2\2\2\u0349\u034a\7^\2\2\u034a\u034b") buf.write(u"\7p\2\2\u034b\u034c\7g\2\2\u034c\u034d\7s\2\2\u034d\u00a2") buf.write(u"\3\2\2\2\u034e\u034f\7>\2\2\u034f\u00a4\3\2\2\2\u0350") buf.write(u"\u0351\7^\2\2\u0351\u0352\7n\2\2\u0352\u0353\7g\2\2\u0353") buf.write(u"\u035a\7s\2\2\u0354\u0355\7^\2\2\u0355\u0356\7n\2\2\u0356") buf.write(u"\u035a\7g\2\2\u0357\u035a\5\u00a7T\2\u0358\u035a\5\u00a9") buf.write(u"U\2\u0359\u0350\3\2\2\2\u0359\u0354\3\2\2\2\u0359\u0357") buf.write(u"\3\2\2\2\u0359\u0358\3\2\2\2\u035a\u00a6\3\2\2\2\u035b") buf.write(u"\u035c\7^\2\2\u035c\u035d\7n\2\2\u035d\u035e\7g\2\2\u035e") buf.write(u"\u035f\7s\2\2\u035f\u0360\7s\2\2\u0360\u00a8\3\2\2\2") buf.write(u"\u0361\u0362\7^\2\2\u0362\u0363\7n\2\2\u0363\u0364\7") buf.write(u"g\2\2\u0364\u0365\7s\2\2\u0365\u0366\7u\2\2\u0366\u0367") buf.write(u"\7n\2\2\u0367\u0368\7c\2\2\u0368\u0369\7p\2\2\u0369\u036a") buf.write(u"\7v\2\2\u036a\u00aa\3\2\2\2\u036b\u036c\7@\2\2\u036c") buf.write(u"\u00ac\3\2\2\2\u036d\u036e\7^\2\2\u036e\u036f\7i\2\2") buf.write(u"\u036f\u0370\7g\2\2\u0370\u0377\7s\2\2\u0371\u0372\7") buf.write(u"^\2\2\u0372\u0373\7i\2\2\u0373\u0377\7g\2\2\u0374\u0377") buf.write(u"\5\u00afX\2\u0375\u0377\5\u00b1Y\2\u0376\u036d\3\2\2") buf.write(u"\2\u0376\u0371\3\2\2\2\u0376\u0374\3\2\2\2\u0376\u0375") buf.write(u"\3\2\2\2\u0377\u00ae\3\2\2\2\u0378\u0379\7^\2\2\u0379") buf.write(u"\u037a\7i\2\2\u037a\u037b\7g\2\2\u037b\u037c\7s\2\2\u037c") buf.write(u"\u037d\7s\2\2\u037d\u00b0\3\2\2\2\u037e\u037f\7^\2\2") buf.write(u"\u037f\u0380\7i\2\2\u0380\u0381\7g\2\2\u0381\u0382\7") buf.write(u"s\2\2\u0382\u0383\7u\2\2\u0383\u0384\7n\2\2\u0384\u0385") buf.write(u"\7c\2\2\u0385\u0386\7p\2\2\u0386\u0387\7v\2\2\u0387\u00b2") buf.write(u"\3\2\2\2\u0388\u0389\7#\2\2\u0389\u00b4\3\2\2\2\u038a") buf.write(u"\u038c\7^\2\2\u038b\u038d\t\3\2\2\u038c\u038b\3\2\2\2") buf.write(u"\u038d\u038e\3\2\2\2\u038e\u038c\3\2\2\2\u038e\u038f") buf.write(u"\3\2\2\2\u038f\u00b6\3\2\2\2\33\2\u00bc\u00cc\u00db\u00ec") buf.write(u"\u0110\u0178\u01f3\u02fc\u0304\u0306\u030f\u0318\u031e") buf.write(u"\u0328\u032f\u0331\u0337\u033a\u0341\u0345\u0347\u0359") buf.write(u"\u0376\u038e\3\b\2\2") return buf.getvalue() class LaTeXLexer(Lexer): atn = ATNDeserializer().deserialize(serializedATN()) decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] T__0 = 1 WS = 2 THINSPACE = 3 MEDSPACE = 4 THICKSPACE = 5 QUAD = 6 QQUAD = 7 NEGTHINSPACE = 8 NEGMEDSPACE = 9 NEGTHICKSPACE = 10 CMD_LEFT = 11 CMD_RIGHT = 12 IGNORE = 13 ADD = 14 SUB = 15 MUL = 16 DIV = 17 L_PAREN = 18 R_PAREN = 19 L_BRACE = 20 R_BRACE = 21 L_BRACE_LITERAL = 22 R_BRACE_LITERAL = 23 L_BRACKET = 24 R_BRACKET = 25 BAR = 26 R_BAR = 27 L_BAR = 28 L_ANGLE = 29 R_ANGLE = 30 FUNC_LIM = 31 LIM_APPROACH_SYM = 32 FUNC_INT = 33 FUNC_SUM = 34 FUNC_PROD = 35 FUNC_EXP = 36 FUNC_LOG = 37 FUNC_LN = 38 FUNC_SIN = 39 FUNC_COS = 40 FUNC_TAN = 41 FUNC_CSC = 42 FUNC_SEC = 43 FUNC_COT = 44 FUNC_ARCSIN = 45 FUNC_ARCCOS = 46 FUNC_ARCTAN = 47 FUNC_ARCCSC = 48 FUNC_ARCSEC = 49 FUNC_ARCCOT = 50 FUNC_SINH = 51 FUNC_COSH = 52 FUNC_TANH = 53 FUNC_ARSINH = 54 FUNC_ARCOSH = 55 FUNC_ARTANH = 56 L_FLOOR = 57 R_FLOOR = 58 L_CEIL = 59 R_CEIL = 60 FUNC_SQRT = 61 FUNC_OVERLINE = 62 CMD_TIMES = 63 CMD_CDOT = 64 CMD_DIV = 65 CMD_FRAC = 66 CMD_BINOM = 67 CMD_DBINOM = 68 CMD_TBINOM = 69 CMD_MATHIT = 70 UNDERSCORE = 71 CARET = 72 COLON = 73 DIFFERENTIAL = 74 LETTER = 75 NUMBER = 76 EQUAL = 77 NEQ = 78 LT = 79 LTE = 80 LTE_Q = 81 LTE_S = 82 GT = 83 GTE = 84 GTE_Q = 85 GTE_S = 86 BANG = 87 SYMBOL = 88 channelNames = [ u"DEFAULT_TOKEN_CHANNEL", u"HIDDEN" ] modeNames = [ u"DEFAULT_MODE" ] literalNames = [ u"", u"','", u"'\\quad'", u"'\\qquad'", u"'\\negmedspace'", u"'\\negthickspace'", u"'\\left'", u"'\\right'", u"'+'", u"'-'", u"'*'", u"'/'", u"'('", u"')'", u"'{'", u"'}'", u"'\\{'", u"'\\}'", u"'['", u"']'", u"'|'", u"'\\right|'", u"'\\left|'", u"'\\langle'", u"'\\rangle'", u"'\\lim'", u"'\\int'", u"'\\sum'", u"'\\prod'", u"'\\exp'", u"'\\log'", u"'\\ln'", u"'\\sin'", u"'\\cos'", u"'\\tan'", u"'\\csc'", u"'\\sec'", u"'\\cot'", u"'\\arcsin'", u"'\\arccos'", u"'\\arctan'", u"'\\arccsc'", u"'\\arcsec'", u"'\\arccot'", u"'\\sinh'", u"'\\cosh'", u"'\\tanh'", u"'\\arsinh'", u"'\\arcosh'", u"'\\artanh'", u"'\\lfloor'", u"'\\rfloor'", u"'\\lceil'", u"'\\rceil'", u"'\\sqrt'", u"'\\overline'", u"'\\times'", u"'\\cdot'", u"'\\div'", u"'\\frac'", u"'\\binom'", u"'\\dbinom'", u"'\\tbinom'", u"'\\mathit'", u"'_'", u"'^'", u"':'", u"'\\neq'", u"'<'", u"'\\leqq'", u"'\\leqslant'", u"'>'", u"'\\geqq'", u"'\\geqslant'", u"'!'" ] symbolicNames = [ u"", u"WS", u"THINSPACE", u"MEDSPACE", u"THICKSPACE", u"QUAD", u"QQUAD", u"NEGTHINSPACE", u"NEGMEDSPACE", u"NEGTHICKSPACE", u"CMD_LEFT", u"CMD_RIGHT", u"IGNORE", u"ADD", u"SUB", u"MUL", u"DIV", u"L_PAREN", u"R_PAREN", u"L_BRACE", u"R_BRACE", u"L_BRACE_LITERAL", u"R_BRACE_LITERAL", u"L_BRACKET", u"R_BRACKET", u"BAR", u"R_BAR", u"L_BAR", u"L_ANGLE", u"R_ANGLE", u"FUNC_LIM", u"LIM_APPROACH_SYM", u"FUNC_INT", u"FUNC_SUM", u"FUNC_PROD", u"FUNC_EXP", u"FUNC_LOG", u"FUNC_LN", u"FUNC_SIN", u"FUNC_COS", u"FUNC_TAN", u"FUNC_CSC", u"FUNC_SEC", u"FUNC_COT", u"FUNC_ARCSIN", u"FUNC_ARCCOS", u"FUNC_ARCTAN", u"FUNC_ARCCSC", u"FUNC_ARCSEC", u"FUNC_ARCCOT", u"FUNC_SINH", u"FUNC_COSH", u"FUNC_TANH", u"FUNC_ARSINH", u"FUNC_ARCOSH", u"FUNC_ARTANH", u"L_FLOOR", u"R_FLOOR", u"L_CEIL", u"R_CEIL", u"FUNC_SQRT", u"FUNC_OVERLINE", u"CMD_TIMES", u"CMD_CDOT", u"CMD_DIV", u"CMD_FRAC", u"CMD_BINOM", u"CMD_DBINOM", u"CMD_TBINOM", u"CMD_MATHIT", u"UNDERSCORE", u"CARET", u"COLON", u"DIFFERENTIAL", u"LETTER", u"NUMBER", u"EQUAL", u"NEQ", u"LT", u"LTE", u"LTE_Q", u"LTE_S", u"GT", u"GTE", u"GTE_Q", u"GTE_S", u"BANG", u"SYMBOL" ] ruleNames = [ u"T__0", u"WS", u"THINSPACE", u"MEDSPACE", u"THICKSPACE", u"QUAD", u"QQUAD", u"NEGTHINSPACE", u"NEGMEDSPACE", u"NEGTHICKSPACE", u"CMD_LEFT", u"CMD_RIGHT", u"IGNORE", u"ADD", u"SUB", u"MUL", u"DIV", u"L_PAREN", u"R_PAREN", u"L_BRACE", u"R_BRACE", u"L_BRACE_LITERAL", u"R_BRACE_LITERAL", u"L_BRACKET", u"R_BRACKET", u"BAR", u"R_BAR", u"L_BAR", u"L_ANGLE", u"R_ANGLE", u"FUNC_LIM", u"LIM_APPROACH_SYM", u"FUNC_INT", u"FUNC_SUM", u"FUNC_PROD", u"FUNC_EXP", u"FUNC_LOG", u"FUNC_LN", u"FUNC_SIN", u"FUNC_COS", u"FUNC_TAN", u"FUNC_CSC", u"FUNC_SEC", u"FUNC_COT", u"FUNC_ARCSIN", u"FUNC_ARCCOS", u"FUNC_ARCTAN", u"FUNC_ARCCSC", u"FUNC_ARCSEC", u"FUNC_ARCCOT", u"FUNC_SINH", u"FUNC_COSH", u"FUNC_TANH", u"FUNC_ARSINH", u"FUNC_ARCOSH", u"FUNC_ARTANH", u"L_FLOOR", u"R_FLOOR", u"L_CEIL", u"R_CEIL", u"FUNC_SQRT", u"FUNC_OVERLINE", u"CMD_TIMES", u"CMD_CDOT", u"CMD_DIV", u"CMD_FRAC", u"CMD_BINOM", u"CMD_DBINOM", u"CMD_TBINOM", u"CMD_MATHIT", u"UNDERSCORE", u"CARET", u"COLON", u"WS_CHAR", u"DIFFERENTIAL", u"LETTER", u"DIGIT", u"NUMBER", u"EQUAL", u"NEQ", u"LT", u"LTE", u"LTE_Q", u"LTE_S", u"GT", u"GTE", u"GTE_Q", u"GTE_S", u"BANG", u"SYMBOL" ] grammarFileName = u"LaTeX.g4" def __init__(self, input=None, output=sys.stdout): super(LaTeXLexer, self).__init__(input, output=output) self.checkVersion("4.7.2") self._interp = LexerATNSimulator(self, self.atn, self.decisionsToDFA, PredictionContextCache()) self._actions = None self._predicates = None sympy-sympy-1.9/sympy/parsing/latex/_antlr/latexparser.py000066400000000000000000003633321412543434000240610ustar00rootroot00000000000000 # encoding: utf-8 # *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND *** # # Generated from ../LaTeX.g4, derived from latex2sympy # latex2sympy is licensed under the MIT license # https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt from __future__ import print_function from antlr4 import * from io import StringIO import sys def serializedATN(): with StringIO() as buf: buf.write(u"\3\u608b\ua72a\u8133\ub9ed\u417c\u3be7\u7786\u5964\3") buf.write(u"Z\u01d5\4\2\t\2\4\3\t\3\4\4\t\4\4\5\t\5\4\6\t\6\4\7\t") buf.write(u"\7\4\b\t\b\4\t\t\t\4\n\t\n\4\13\t\13\4\f\t\f\4\r\t\r") buf.write(u"\4\16\t\16\4\17\t\17\4\20\t\20\4\21\t\21\4\22\t\22\4") buf.write(u"\23\t\23\4\24\t\24\4\25\t\25\4\26\t\26\4\27\t\27\4\30") buf.write(u"\t\30\4\31\t\31\4\32\t\32\4\33\t\33\4\34\t\34\4\35\t") buf.write(u"\35\4\36\t\36\4\37\t\37\4 \t \4!\t!\4\"\t\"\4#\t#\4$") buf.write(u"\t$\4%\t%\4&\t&\4\'\t\'\4(\t(\4)\t)\3\2\3\2\3\3\3\3\3") buf.write(u"\3\3\3\3\3\3\3\7\3[\n\3\f\3\16\3^\13\3\3\4\3\4\3\4\3") buf.write(u"\4\3\5\3\5\3\6\3\6\3\6\3\6\3\6\3\6\7\6l\n\6\f\6\16\6") buf.write(u"o\13\6\3\7\3\7\3\7\3\7\3\7\3\7\7\7w\n\7\f\7\16\7z\13") buf.write(u"\7\3\b\3\b\3\b\3\b\3\b\3\b\7\b\u0082\n\b\f\b\16\b\u0085") buf.write(u"\13\b\3\t\3\t\3\t\6\t\u008a\n\t\r\t\16\t\u008b\5\t\u008e") buf.write(u"\n\t\3\n\3\n\3\n\3\n\7\n\u0094\n\n\f\n\16\n\u0097\13") buf.write(u"\n\5\n\u0099\n\n\3\13\3\13\7\13\u009d\n\13\f\13\16\13") buf.write(u"\u00a0\13\13\3\f\3\f\7\f\u00a4\n\f\f\f\16\f\u00a7\13") buf.write(u"\f\3\r\3\r\5\r\u00ab\n\r\3\16\3\16\3\16\3\16\3\16\3\16") buf.write(u"\5\16\u00b3\n\16\3\17\3\17\3\17\3\17\5\17\u00b9\n\17") buf.write(u"\3\17\3\17\3\20\3\20\3\20\3\20\5\20\u00c1\n\20\3\20\3") buf.write(u"\20\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21\3\21") buf.write(u"\5\21\u00cf\n\21\3\21\5\21\u00d2\n\21\7\21\u00d4\n\21") buf.write(u"\f\21\16\21\u00d7\13\21\3\22\3\22\3\22\3\22\3\22\3\22") buf.write(u"\3\22\3\22\3\22\3\22\5\22\u00e3\n\22\3\22\5\22\u00e6") buf.write(u"\n\22\7\22\u00e8\n\22\f\22\16\22\u00eb\13\22\3\23\3\23") buf.write(u"\3\23\3\23\3\23\3\23\3\23\3\23\5\23\u00f5\n\23\3\24\3") buf.write(u"\24\3\24\3\24\3\24\3\24\3\24\5\24\u00fe\n\24\3\25\3\25") buf.write(u"\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3\25\3") buf.write(u"\25\3\25\3\25\3\25\5\25\u0110\n\25\3\26\3\26\3\26\3\26") buf.write(u"\3\27\3\27\5\27\u0118\n\27\3\27\3\27\3\27\3\27\3\27\5") buf.write(u"\27\u011f\n\27\3\30\3\30\3\30\3\30\3\31\3\31\3\31\3\31") buf.write(u"\3\32\3\32\3\32\3\32\3\32\3\33\7\33\u012f\n\33\f\33\16") buf.write(u"\33\u0132\13\33\3\34\3\34\3\34\3\34\3\34\3\34\3\34\3") buf.write(u"\34\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\35\3\36\3\36") buf.write(u"\3\36\3\36\3\37\3\37\3\37\3\37\3 \3 \3!\3!\5!\u0150\n") buf.write(u"!\3!\5!\u0153\n!\3!\5!\u0156\n!\3!\5!\u0159\n!\5!\u015b") buf.write(u"\n!\3!\3!\3!\3!\3!\5!\u0162\n!\3!\3!\5!\u0166\n!\3!\3") buf.write(u"!\3!\3!\3!\3!\3!\3!\3!\3!\3!\5!\u0173\n!\3!\5!\u0176") buf.write(u"\n!\3!\3!\3!\5!\u017b\n!\3!\3!\3!\3!\3!\5!\u0182\n!\3") buf.write(u"!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\3!\5!\u0194") buf.write(u"\n!\3!\3!\3!\3!\3!\3!\5!\u019c\n!\3\"\3\"\3\"\3\"\3\"") buf.write(u"\5\"\u01a3\n\"\3#\3#\3#\3#\3#\3#\3#\3#\3#\5#\u01ae\n") buf.write(u"#\3#\3#\3$\3$\3$\3$\3$\5$\u01b7\n$\3%\3%\3&\3&\3&\3&") buf.write(u"\3&\3&\5&\u01c1\n&\3\'\3\'\3\'\3\'\3\'\3\'\5\'\u01c9") buf.write(u"\n\'\3(\3(\3(\3(\3(\3)\3)\3)\3)\3)\3)\2\b\4\n\f\16 \"") buf.write(u"*\2\4\6\b\n\f\16\20\22\24\26\30\32\34\36 \"$&(*,.\60") buf.write(u"\62\64\668:<>@BDFHJLNP\2\13\4\2ORUV\3\2\20\21\5\2\22") buf.write(u"\23ACKK\4\2MMZZ\3\2\34\35\4\2\34\34\36\36\3\2EG\3\2&") buf.write(u":\3\2$%\2\u01f1\2R\3\2\2\2\4T\3\2\2\2\6_\3\2\2\2\bc\3") buf.write(u"\2\2\2\ne\3\2\2\2\fp\3\2\2\2\16{\3\2\2\2\20\u008d\3\2") buf.write(u"\2\2\22\u0098\3\2\2\2\24\u009a\3\2\2\2\26\u00a1\3\2\2") buf.write(u"\2\30\u00aa\3\2\2\2\32\u00ac\3\2\2\2\34\u00b4\3\2\2\2") buf.write(u"\36\u00bc\3\2\2\2 \u00c4\3\2\2\2\"\u00d8\3\2\2\2$\u00f4") buf.write(u"\3\2\2\2&\u00fd\3\2\2\2(\u010f\3\2\2\2*\u0111\3\2\2\2") buf.write(u",\u011e\3\2\2\2.\u0120\3\2\2\2\60\u0124\3\2\2\2\62\u0128") buf.write(u"\3\2\2\2\64\u0130\3\2\2\2\66\u0133\3\2\2\28\u013b\3\2") buf.write(u"\2\2:\u0143\3\2\2\2<\u0147\3\2\2\2>\u014b\3\2\2\2@\u019b") buf.write(u"\3\2\2\2B\u01a2\3\2\2\2D\u01a4\3\2\2\2F\u01b6\3\2\2\2") buf.write(u"H\u01b8\3\2\2\2J\u01ba\3\2\2\2L\u01c2\3\2\2\2N\u01ca") buf.write(u"\3\2\2\2P\u01cf\3\2\2\2RS\5\4\3\2S\3\3\2\2\2TU\b\3\1") buf.write(u"\2UV\5\b\5\2V\\\3\2\2\2WX\f\4\2\2XY\t\2\2\2Y[\5\4\3\5") buf.write(u"ZW\3\2\2\2[^\3\2\2\2\\Z\3\2\2\2\\]\3\2\2\2]\5\3\2\2\2") buf.write(u"^\\\3\2\2\2_`\5\b\5\2`a\7O\2\2ab\5\b\5\2b\7\3\2\2\2c") buf.write(u"d\5\n\6\2d\t\3\2\2\2ef\b\6\1\2fg\5\f\7\2gm\3\2\2\2hi") buf.write(u"\f\4\2\2ij\t\3\2\2jl\5\n\6\5kh\3\2\2\2lo\3\2\2\2mk\3") buf.write(u"\2\2\2mn\3\2\2\2n\13\3\2\2\2om\3\2\2\2pq\b\7\1\2qr\5") buf.write(u"\20\t\2rx\3\2\2\2st\f\4\2\2tu\t\4\2\2uw\5\f\7\5vs\3\2") buf.write(u"\2\2wz\3\2\2\2xv\3\2\2\2xy\3\2\2\2y\r\3\2\2\2zx\3\2\2") buf.write(u"\2{|\b\b\1\2|}\5\22\n\2}\u0083\3\2\2\2~\177\f\4\2\2\177") buf.write(u"\u0080\t\4\2\2\u0080\u0082\5\16\b\5\u0081~\3\2\2\2\u0082") buf.write(u"\u0085\3\2\2\2\u0083\u0081\3\2\2\2\u0083\u0084\3\2\2") buf.write(u"\2\u0084\17\3\2\2\2\u0085\u0083\3\2\2\2\u0086\u0087\t") buf.write(u"\3\2\2\u0087\u008e\5\20\t\2\u0088\u008a\5\24\13\2\u0089") buf.write(u"\u0088\3\2\2\2\u008a\u008b\3\2\2\2\u008b\u0089\3\2\2") buf.write(u"\2\u008b\u008c\3\2\2\2\u008c\u008e\3\2\2\2\u008d\u0086") buf.write(u"\3\2\2\2\u008d\u0089\3\2\2\2\u008e\21\3\2\2\2\u008f\u0090") buf.write(u"\t\3\2\2\u0090\u0099\5\22\n\2\u0091\u0095\5\24\13\2\u0092") buf.write(u"\u0094\5\26\f\2\u0093\u0092\3\2\2\2\u0094\u0097\3\2\2") buf.write(u"\2\u0095\u0093\3\2\2\2\u0095\u0096\3\2\2\2\u0096\u0099") buf.write(u"\3\2\2\2\u0097\u0095\3\2\2\2\u0098\u008f\3\2\2\2\u0098") buf.write(u"\u0091\3\2\2\2\u0099\23\3\2\2\2\u009a\u009e\5 \21\2\u009b") buf.write(u"\u009d\5\30\r\2\u009c\u009b\3\2\2\2\u009d\u00a0\3\2\2") buf.write(u"\2\u009e\u009c\3\2\2\2\u009e\u009f\3\2\2\2\u009f\25\3") buf.write(u"\2\2\2\u00a0\u009e\3\2\2\2\u00a1\u00a5\5\"\22\2\u00a2") buf.write(u"\u00a4\5\30\r\2\u00a3\u00a2\3\2\2\2\u00a4\u00a7\3\2\2") buf.write(u"\2\u00a5\u00a3\3\2\2\2\u00a5\u00a6\3\2\2\2\u00a6\27\3") buf.write(u"\2\2\2\u00a7\u00a5\3\2\2\2\u00a8\u00ab\7Y\2\2\u00a9\u00ab") buf.write(u"\5\32\16\2\u00aa\u00a8\3\2\2\2\u00aa\u00a9\3\2\2\2\u00ab") buf.write(u"\31\3\2\2\2\u00ac\u00b2\7\34\2\2\u00ad\u00b3\5\36\20") buf.write(u"\2\u00ae\u00b3\5\34\17\2\u00af\u00b0\5\36\20\2\u00b0") buf.write(u"\u00b1\5\34\17\2\u00b1\u00b3\3\2\2\2\u00b2\u00ad\3\2") buf.write(u"\2\2\u00b2\u00ae\3\2\2\2\u00b2\u00af\3\2\2\2\u00b3\33") buf.write(u"\3\2\2\2\u00b4\u00b5\7I\2\2\u00b5\u00b8\7\26\2\2\u00b6") buf.write(u"\u00b9\5\b\5\2\u00b7\u00b9\5\6\4\2\u00b8\u00b6\3\2\2") buf.write(u"\2\u00b8\u00b7\3\2\2\2\u00b9\u00ba\3\2\2\2\u00ba\u00bb") buf.write(u"\7\27\2\2\u00bb\35\3\2\2\2\u00bc\u00bd\7J\2\2\u00bd\u00c0") buf.write(u"\7\26\2\2\u00be\u00c1\5\b\5\2\u00bf\u00c1\5\6\4\2\u00c0") buf.write(u"\u00be\3\2\2\2\u00c0\u00bf\3\2\2\2\u00c1\u00c2\3\2\2") buf.write(u"\2\u00c2\u00c3\7\27\2\2\u00c3\37\3\2\2\2\u00c4\u00c5") buf.write(u"\b\21\1\2\u00c5\u00c6\5$\23\2\u00c6\u00d5\3\2\2\2\u00c7") buf.write(u"\u00c8\f\4\2\2\u00c8\u00ce\7J\2\2\u00c9\u00cf\5,\27\2") buf.write(u"\u00ca\u00cb\7\26\2\2\u00cb\u00cc\5\b\5\2\u00cc\u00cd") buf.write(u"\7\27\2\2\u00cd\u00cf\3\2\2\2\u00ce\u00c9\3\2\2\2\u00ce") buf.write(u"\u00ca\3\2\2\2\u00cf\u00d1\3\2\2\2\u00d0\u00d2\5J&\2") buf.write(u"\u00d1\u00d0\3\2\2\2\u00d1\u00d2\3\2\2\2\u00d2\u00d4") buf.write(u"\3\2\2\2\u00d3\u00c7\3\2\2\2\u00d4\u00d7\3\2\2\2\u00d5") buf.write(u"\u00d3\3\2\2\2\u00d5\u00d6\3\2\2\2\u00d6!\3\2\2\2\u00d7") buf.write(u"\u00d5\3\2\2\2\u00d8\u00d9\b\22\1\2\u00d9\u00da\5&\24") buf.write(u"\2\u00da\u00e9\3\2\2\2\u00db\u00dc\f\4\2\2\u00dc\u00e2") buf.write(u"\7J\2\2\u00dd\u00e3\5,\27\2\u00de\u00df\7\26\2\2\u00df") buf.write(u"\u00e0\5\b\5\2\u00e0\u00e1\7\27\2\2\u00e1\u00e3\3\2\2") buf.write(u"\2\u00e2\u00dd\3\2\2\2\u00e2\u00de\3\2\2\2\u00e3\u00e5") buf.write(u"\3\2\2\2\u00e4\u00e6\5J&\2\u00e5\u00e4\3\2\2\2\u00e5") buf.write(u"\u00e6\3\2\2\2\u00e6\u00e8\3\2\2\2\u00e7\u00db\3\2\2") buf.write(u"\2\u00e8\u00eb\3\2\2\2\u00e9\u00e7\3\2\2\2\u00e9\u00ea") buf.write(u"\3\2\2\2\u00ea#\3\2\2\2\u00eb\u00e9\3\2\2\2\u00ec\u00f5") buf.write(u"\5(\25\2\u00ed\u00f5\5*\26\2\u00ee\u00f5\5@!\2\u00ef") buf.write(u"\u00f5\5,\27\2\u00f0\u00f5\5\66\34\2\u00f1\u00f5\58\35") buf.write(u"\2\u00f2\u00f5\5:\36\2\u00f3\u00f5\5<\37\2\u00f4\u00ec") buf.write(u"\3\2\2\2\u00f4\u00ed\3\2\2\2\u00f4\u00ee\3\2\2\2\u00f4") buf.write(u"\u00ef\3\2\2\2\u00f4\u00f0\3\2\2\2\u00f4\u00f1\3\2\2") buf.write(u"\2\u00f4\u00f2\3\2\2\2\u00f4\u00f3\3\2\2\2\u00f5%\3\2") buf.write(u"\2\2\u00f6\u00fe\5(\25\2\u00f7\u00fe\5*\26\2\u00f8\u00fe") buf.write(u"\5,\27\2\u00f9\u00fe\5\66\34\2\u00fa\u00fe\58\35\2\u00fb") buf.write(u"\u00fe\5:\36\2\u00fc\u00fe\5<\37\2\u00fd\u00f6\3\2\2") buf.write(u"\2\u00fd\u00f7\3\2\2\2\u00fd\u00f8\3\2\2\2\u00fd\u00f9") buf.write(u"\3\2\2\2\u00fd\u00fa\3\2\2\2\u00fd\u00fb\3\2\2\2\u00fd") buf.write(u"\u00fc\3\2\2\2\u00fe\'\3\2\2\2\u00ff\u0100\7\24\2\2\u0100") buf.write(u"\u0101\5\b\5\2\u0101\u0102\7\25\2\2\u0102\u0110\3\2\2") buf.write(u"\2\u0103\u0104\7\32\2\2\u0104\u0105\5\b\5\2\u0105\u0106") buf.write(u"\7\33\2\2\u0106\u0110\3\2\2\2\u0107\u0108\7\26\2\2\u0108") buf.write(u"\u0109\5\b\5\2\u0109\u010a\7\27\2\2\u010a\u0110\3\2\2") buf.write(u"\2\u010b\u010c\7\30\2\2\u010c\u010d\5\b\5\2\u010d\u010e") buf.write(u"\7\31\2\2\u010e\u0110\3\2\2\2\u010f\u00ff\3\2\2\2\u010f") buf.write(u"\u0103\3\2\2\2\u010f\u0107\3\2\2\2\u010f\u010b\3\2\2") buf.write(u"\2\u0110)\3\2\2\2\u0111\u0112\7\34\2\2\u0112\u0113\5") buf.write(u"\b\5\2\u0113\u0114\7\34\2\2\u0114+\3\2\2\2\u0115\u0117") buf.write(u"\t\5\2\2\u0116\u0118\5J&\2\u0117\u0116\3\2\2\2\u0117") buf.write(u"\u0118\3\2\2\2\u0118\u011f\3\2\2\2\u0119\u011f\7N\2\2") buf.write(u"\u011a\u011f\7L\2\2\u011b\u011f\5\62\32\2\u011c\u011f") buf.write(u"\5.\30\2\u011d\u011f\5\60\31\2\u011e\u0115\3\2\2\2\u011e") buf.write(u"\u0119\3\2\2\2\u011e\u011a\3\2\2\2\u011e\u011b\3\2\2") buf.write(u"\2\u011e\u011c\3\2\2\2\u011e\u011d\3\2\2\2\u011f-\3\2") buf.write(u"\2\2\u0120\u0121\7\37\2\2\u0121\u0122\5\b\5\2\u0122\u0123") buf.write(u"\t\6\2\2\u0123/\3\2\2\2\u0124\u0125\t\7\2\2\u0125\u0126") buf.write(u"\5\b\5\2\u0126\u0127\7 \2\2\u0127\61\3\2\2\2\u0128\u0129") buf.write(u"\7H\2\2\u0129\u012a\7\26\2\2\u012a\u012b\5\64\33\2\u012b") buf.write(u"\u012c\7\27\2\2\u012c\63\3\2\2\2\u012d\u012f\7M\2\2\u012e") buf.write(u"\u012d\3\2\2\2\u012f\u0132\3\2\2\2\u0130\u012e\3\2\2") buf.write(u"\2\u0130\u0131\3\2\2\2\u0131\65\3\2\2\2\u0132\u0130\3") buf.write(u"\2\2\2\u0133\u0134\7D\2\2\u0134\u0135\7\26\2\2\u0135") buf.write(u"\u0136\5\b\5\2\u0136\u0137\7\27\2\2\u0137\u0138\7\26") buf.write(u"\2\2\u0138\u0139\5\b\5\2\u0139\u013a\7\27\2\2\u013a\67") buf.write(u"\3\2\2\2\u013b\u013c\t\b\2\2\u013c\u013d\7\26\2\2\u013d") buf.write(u"\u013e\5\b\5\2\u013e\u013f\7\27\2\2\u013f\u0140\7\26") buf.write(u"\2\2\u0140\u0141\5\b\5\2\u0141\u0142\7\27\2\2\u01429") buf.write(u"\3\2\2\2\u0143\u0144\7;\2\2\u0144\u0145\5\b\5\2\u0145") buf.write(u"\u0146\7<\2\2\u0146;\3\2\2\2\u0147\u0148\7=\2\2\u0148") buf.write(u"\u0149\5\b\5\2\u0149\u014a\7>\2\2\u014a=\3\2\2\2\u014b") buf.write(u"\u014c\t\t\2\2\u014c?\3\2\2\2\u014d\u015a\5> \2\u014e") buf.write(u"\u0150\5J&\2\u014f\u014e\3\2\2\2\u014f\u0150\3\2\2\2") buf.write(u"\u0150\u0152\3\2\2\2\u0151\u0153\5L\'\2\u0152\u0151\3") buf.write(u"\2\2\2\u0152\u0153\3\2\2\2\u0153\u015b\3\2\2\2\u0154") buf.write(u"\u0156\5L\'\2\u0155\u0154\3\2\2\2\u0155\u0156\3\2\2\2") buf.write(u"\u0156\u0158\3\2\2\2\u0157\u0159\5J&\2\u0158\u0157\3") buf.write(u"\2\2\2\u0158\u0159\3\2\2\2\u0159\u015b\3\2\2\2\u015a") buf.write(u"\u014f\3\2\2\2\u015a\u0155\3\2\2\2\u015b\u0161\3\2\2") buf.write(u"\2\u015c\u015d\7\24\2\2\u015d\u015e\5F$\2\u015e\u015f") buf.write(u"\7\25\2\2\u015f\u0162\3\2\2\2\u0160\u0162\5H%\2\u0161") buf.write(u"\u015c\3\2\2\2\u0161\u0160\3\2\2\2\u0162\u019c\3\2\2") buf.write(u"\2\u0163\u0165\t\5\2\2\u0164\u0166\5J&\2\u0165\u0164") buf.write(u"\3\2\2\2\u0165\u0166\3\2\2\2\u0166\u0167\3\2\2\2\u0167") buf.write(u"\u0168\7\24\2\2\u0168\u0169\5B\"\2\u0169\u016a\7\25\2") buf.write(u"\2\u016a\u019c\3\2\2\2\u016b\u0172\7#\2\2\u016c\u016d") buf.write(u"\5J&\2\u016d\u016e\5L\'\2\u016e\u0173\3\2\2\2\u016f\u0170") buf.write(u"\5L\'\2\u0170\u0171\5J&\2\u0171\u0173\3\2\2\2\u0172\u016c") buf.write(u"\3\2\2\2\u0172\u016f\3\2\2\2\u0172\u0173\3\2\2\2\u0173") buf.write(u"\u017a\3\2\2\2\u0174\u0176\5\n\6\2\u0175\u0174\3\2\2") buf.write(u"\2\u0175\u0176\3\2\2\2\u0176\u0177\3\2\2\2\u0177\u017b") buf.write(u"\7L\2\2\u0178\u017b\5\66\34\2\u0179\u017b\5\n\6\2\u017a") buf.write(u"\u0175\3\2\2\2\u017a\u0178\3\2\2\2\u017a\u0179\3\2\2") buf.write(u"\2\u017b\u019c\3\2\2\2\u017c\u0181\7?\2\2\u017d\u017e") buf.write(u"\7\32\2\2\u017e\u017f\5\b\5\2\u017f\u0180\7\33\2\2\u0180") buf.write(u"\u0182\3\2\2\2\u0181\u017d\3\2\2\2\u0181\u0182\3\2\2") buf.write(u"\2\u0182\u0183\3\2\2\2\u0183\u0184\7\26\2\2\u0184\u0185") buf.write(u"\5\b\5\2\u0185\u0186\7\27\2\2\u0186\u019c\3\2\2\2\u0187") buf.write(u"\u0188\7@\2\2\u0188\u0189\7\26\2\2\u0189\u018a\5\b\5") buf.write(u"\2\u018a\u018b\7\27\2\2\u018b\u019c\3\2\2\2\u018c\u0193") buf.write(u"\t\n\2\2\u018d\u018e\5N(\2\u018e\u018f\5L\'\2\u018f\u0194") buf.write(u"\3\2\2\2\u0190\u0191\5L\'\2\u0191\u0192\5N(\2\u0192\u0194") buf.write(u"\3\2\2\2\u0193\u018d\3\2\2\2\u0193\u0190\3\2\2\2\u0194") buf.write(u"\u0195\3\2\2\2\u0195\u0196\5\f\7\2\u0196\u019c\3\2\2") buf.write(u"\2\u0197\u0198\7!\2\2\u0198\u0199\5D#\2\u0199\u019a\5") buf.write(u"\f\7\2\u019a\u019c\3\2\2\2\u019b\u014d\3\2\2\2\u019b") buf.write(u"\u0163\3\2\2\2\u019b\u016b\3\2\2\2\u019b\u017c\3\2\2") buf.write(u"\2\u019b\u0187\3\2\2\2\u019b\u018c\3\2\2\2\u019b\u0197") buf.write(u"\3\2\2\2\u019cA\3\2\2\2\u019d\u019e\5\b\5\2\u019e\u019f") buf.write(u"\7\3\2\2\u019f\u01a0\5B\"\2\u01a0\u01a3\3\2\2\2\u01a1") buf.write(u"\u01a3\5\b\5\2\u01a2\u019d\3\2\2\2\u01a2\u01a1\3\2\2") buf.write(u"\2\u01a3C\3\2\2\2\u01a4\u01a5\7I\2\2\u01a5\u01a6\7\26") buf.write(u"\2\2\u01a6\u01a7\t\5\2\2\u01a7\u01a8\7\"\2\2\u01a8\u01ad") buf.write(u"\5\b\5\2\u01a9\u01aa\7J\2\2\u01aa\u01ab\7\26\2\2\u01ab") buf.write(u"\u01ac\t\3\2\2\u01ac\u01ae\7\27\2\2\u01ad\u01a9\3\2\2") buf.write(u"\2\u01ad\u01ae\3\2\2\2\u01ae\u01af\3\2\2\2\u01af\u01b0") buf.write(u"\7\27\2\2\u01b0E\3\2\2\2\u01b1\u01b7\5\b\5\2\u01b2\u01b3") buf.write(u"\5\b\5\2\u01b3\u01b4\7\3\2\2\u01b4\u01b5\5F$\2\u01b5") buf.write(u"\u01b7\3\2\2\2\u01b6\u01b1\3\2\2\2\u01b6\u01b2\3\2\2") buf.write(u"\2\u01b7G\3\2\2\2\u01b8\u01b9\5\16\b\2\u01b9I\3\2\2\2") buf.write(u"\u01ba\u01c0\7I\2\2\u01bb\u01c1\5,\27\2\u01bc\u01bd\7") buf.write(u"\26\2\2\u01bd\u01be\5\b\5\2\u01be\u01bf\7\27\2\2\u01bf") buf.write(u"\u01c1\3\2\2\2\u01c0\u01bb\3\2\2\2\u01c0\u01bc\3\2\2") buf.write(u"\2\u01c1K\3\2\2\2\u01c2\u01c8\7J\2\2\u01c3\u01c9\5,\27") buf.write(u"\2\u01c4\u01c5\7\26\2\2\u01c5\u01c6\5\b\5\2\u01c6\u01c7") buf.write(u"\7\27\2\2\u01c7\u01c9\3\2\2\2\u01c8\u01c3\3\2\2\2\u01c8") buf.write(u"\u01c4\3\2\2\2\u01c9M\3\2\2\2\u01ca\u01cb\7I\2\2\u01cb") buf.write(u"\u01cc\7\26\2\2\u01cc\u01cd\5\6\4\2\u01cd\u01ce\7\27") buf.write(u"\2\2\u01ceO\3\2\2\2\u01cf\u01d0\7I\2\2\u01d0\u01d1\7") buf.write(u"\26\2\2\u01d1\u01d2\5\6\4\2\u01d2\u01d3\7\27\2\2\u01d3") buf.write(u"Q\3\2\2\2.\\mx\u0083\u008b\u008d\u0095\u0098\u009e\u00a5") buf.write(u"\u00aa\u00b2\u00b8\u00c0\u00ce\u00d1\u00d5\u00e2\u00e5") buf.write(u"\u00e9\u00f4\u00fd\u010f\u0117\u011e\u0130\u014f\u0152") buf.write(u"\u0155\u0158\u015a\u0161\u0165\u0172\u0175\u017a\u0181") buf.write(u"\u0193\u019b\u01a2\u01ad\u01b6\u01c0\u01c8") return buf.getvalue() class LaTeXParser ( Parser ): grammarFileName = "LaTeX.g4" atn = ATNDeserializer().deserialize(serializedATN()) decisionsToDFA = [ DFA(ds, i) for i, ds in enumerate(atn.decisionToState) ] sharedContextCache = PredictionContextCache() literalNames = [ u"", u"','", u"", u"", u"", u"", u"'\\quad'", u"'\\qquad'", u"", u"'\\negmedspace'", u"'\\negthickspace'", u"'\\left'", u"'\\right'", u"", u"'+'", u"'-'", u"'*'", u"'/'", u"'('", u"')'", u"'{'", u"'}'", u"'\\{'", u"'\\}'", u"'['", u"']'", u"'|'", u"'\\right|'", u"'\\left|'", u"'\\langle'", u"'\\rangle'", u"'\\lim'", u"", u"'\\int'", u"'\\sum'", u"'\\prod'", u"'\\exp'", u"'\\log'", u"'\\ln'", u"'\\sin'", u"'\\cos'", u"'\\tan'", u"'\\csc'", u"'\\sec'", u"'\\cot'", u"'\\arcsin'", u"'\\arccos'", u"'\\arctan'", u"'\\arccsc'", u"'\\arcsec'", u"'\\arccot'", u"'\\sinh'", u"'\\cosh'", u"'\\tanh'", u"'\\arsinh'", u"'\\arcosh'", u"'\\artanh'", u"'\\lfloor'", u"'\\rfloor'", u"'\\lceil'", u"'\\rceil'", u"'\\sqrt'", u"'\\overline'", u"'\\times'", u"'\\cdot'", u"'\\div'", u"'\\frac'", u"'\\binom'", u"'\\dbinom'", u"'\\tbinom'", u"'\\mathit'", u"'_'", u"'^'", u"':'", u"", u"", u"", u"", u"'\\neq'", u"'<'", u"", u"'\\leqq'", u"'\\leqslant'", u"'>'", u"", u"'\\geqq'", u"'\\geqslant'", u"'!'" ] symbolicNames = [ u"", u"", u"WS", u"THINSPACE", u"MEDSPACE", u"THICKSPACE", u"QUAD", u"QQUAD", u"NEGTHINSPACE", u"NEGMEDSPACE", u"NEGTHICKSPACE", u"CMD_LEFT", u"CMD_RIGHT", u"IGNORE", u"ADD", u"SUB", u"MUL", u"DIV", u"L_PAREN", u"R_PAREN", u"L_BRACE", u"R_BRACE", u"L_BRACE_LITERAL", u"R_BRACE_LITERAL", u"L_BRACKET", u"R_BRACKET", u"BAR", u"R_BAR", u"L_BAR", u"L_ANGLE", u"R_ANGLE", u"FUNC_LIM", u"LIM_APPROACH_SYM", u"FUNC_INT", u"FUNC_SUM", u"FUNC_PROD", u"FUNC_EXP", u"FUNC_LOG", u"FUNC_LN", u"FUNC_SIN", u"FUNC_COS", u"FUNC_TAN", u"FUNC_CSC", u"FUNC_SEC", u"FUNC_COT", u"FUNC_ARCSIN", u"FUNC_ARCCOS", u"FUNC_ARCTAN", u"FUNC_ARCCSC", u"FUNC_ARCSEC", u"FUNC_ARCCOT", u"FUNC_SINH", u"FUNC_COSH", u"FUNC_TANH", u"FUNC_ARSINH", u"FUNC_ARCOSH", u"FUNC_ARTANH", u"L_FLOOR", u"R_FLOOR", u"L_CEIL", u"R_CEIL", u"FUNC_SQRT", u"FUNC_OVERLINE", u"CMD_TIMES", u"CMD_CDOT", u"CMD_DIV", u"CMD_FRAC", u"CMD_BINOM", u"CMD_DBINOM", u"CMD_TBINOM", u"CMD_MATHIT", u"UNDERSCORE", u"CARET", u"COLON", u"DIFFERENTIAL", u"LETTER", u"NUMBER", u"EQUAL", u"NEQ", u"LT", u"LTE", u"LTE_Q", u"LTE_S", u"GT", u"GTE", u"GTE_Q", u"GTE_S", u"BANG", u"SYMBOL" ] RULE_math = 0 RULE_relation = 1 RULE_equality = 2 RULE_expr = 3 RULE_additive = 4 RULE_mp = 5 RULE_mp_nofunc = 6 RULE_unary = 7 RULE_unary_nofunc = 8 RULE_postfix = 9 RULE_postfix_nofunc = 10 RULE_postfix_op = 11 RULE_eval_at = 12 RULE_eval_at_sub = 13 RULE_eval_at_sup = 14 RULE_exp = 15 RULE_exp_nofunc = 16 RULE_comp = 17 RULE_comp_nofunc = 18 RULE_group = 19 RULE_abs_group = 20 RULE_atom = 21 RULE_bra = 22 RULE_ket = 23 RULE_mathit = 24 RULE_mathit_text = 25 RULE_frac = 26 RULE_binom = 27 RULE_floor = 28 RULE_ceil = 29 RULE_func_normal = 30 RULE_func = 31 RULE_args = 32 RULE_limit_sub = 33 RULE_func_arg = 34 RULE_func_arg_noparens = 35 RULE_subexpr = 36 RULE_supexpr = 37 RULE_subeq = 38 RULE_supeq = 39 ruleNames = [ u"math", u"relation", u"equality", u"expr", u"additive", u"mp", u"mp_nofunc", u"unary", u"unary_nofunc", u"postfix", u"postfix_nofunc", u"postfix_op", u"eval_at", u"eval_at_sub", u"eval_at_sup", u"exp", u"exp_nofunc", u"comp", u"comp_nofunc", u"group", u"abs_group", u"atom", u"bra", u"ket", u"mathit", u"mathit_text", u"frac", u"binom", u"floor", u"ceil", u"func_normal", u"func", u"args", u"limit_sub", u"func_arg", u"func_arg_noparens", u"subexpr", u"supexpr", u"subeq", u"supeq" ] EOF = Token.EOF T__0=1 WS=2 THINSPACE=3 MEDSPACE=4 THICKSPACE=5 QUAD=6 QQUAD=7 NEGTHINSPACE=8 NEGMEDSPACE=9 NEGTHICKSPACE=10 CMD_LEFT=11 CMD_RIGHT=12 IGNORE=13 ADD=14 SUB=15 MUL=16 DIV=17 L_PAREN=18 R_PAREN=19 L_BRACE=20 R_BRACE=21 L_BRACE_LITERAL=22 R_BRACE_LITERAL=23 L_BRACKET=24 R_BRACKET=25 BAR=26 R_BAR=27 L_BAR=28 L_ANGLE=29 R_ANGLE=30 FUNC_LIM=31 LIM_APPROACH_SYM=32 FUNC_INT=33 FUNC_SUM=34 FUNC_PROD=35 FUNC_EXP=36 FUNC_LOG=37 FUNC_LN=38 FUNC_SIN=39 FUNC_COS=40 FUNC_TAN=41 FUNC_CSC=42 FUNC_SEC=43 FUNC_COT=44 FUNC_ARCSIN=45 FUNC_ARCCOS=46 FUNC_ARCTAN=47 FUNC_ARCCSC=48 FUNC_ARCSEC=49 FUNC_ARCCOT=50 FUNC_SINH=51 FUNC_COSH=52 FUNC_TANH=53 FUNC_ARSINH=54 FUNC_ARCOSH=55 FUNC_ARTANH=56 L_FLOOR=57 R_FLOOR=58 L_CEIL=59 R_CEIL=60 FUNC_SQRT=61 FUNC_OVERLINE=62 CMD_TIMES=63 CMD_CDOT=64 CMD_DIV=65 CMD_FRAC=66 CMD_BINOM=67 CMD_DBINOM=68 CMD_TBINOM=69 CMD_MATHIT=70 UNDERSCORE=71 CARET=72 COLON=73 DIFFERENTIAL=74 LETTER=75 NUMBER=76 EQUAL=77 NEQ=78 LT=79 LTE=80 LTE_Q=81 LTE_S=82 GT=83 GTE=84 GTE_Q=85 GTE_S=86 BANG=87 SYMBOL=88 def __init__(self, input, output=sys.stdout): super(LaTeXParser, self).__init__(input, output=output) self.checkVersion("4.7.2") self._interp = ParserATNSimulator(self, self.atn, self.decisionsToDFA, self.sharedContextCache) self._predicates = None class MathContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.MathContext, self).__init__(parent, invokingState) self.parser = parser def relation(self): return self.getTypedRuleContext(LaTeXParser.RelationContext,0) def getRuleIndex(self): return LaTeXParser.RULE_math def math(self): localctx = LaTeXParser.MathContext(self, self._ctx, self.state) self.enterRule(localctx, 0, self.RULE_math) try: self.enterOuterAlt(localctx, 1) self.state = 80 self.relation(0) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class RelationContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.RelationContext, self).__init__(parent, invokingState) self.parser = parser def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def relation(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.RelationContext) else: return self.getTypedRuleContext(LaTeXParser.RelationContext,i) def EQUAL(self): return self.getToken(LaTeXParser.EQUAL, 0) def LT(self): return self.getToken(LaTeXParser.LT, 0) def LTE(self): return self.getToken(LaTeXParser.LTE, 0) def GT(self): return self.getToken(LaTeXParser.GT, 0) def GTE(self): return self.getToken(LaTeXParser.GTE, 0) def NEQ(self): return self.getToken(LaTeXParser.NEQ, 0) def getRuleIndex(self): return LaTeXParser.RULE_relation def relation(self, _p=0): _parentctx = self._ctx _parentState = self.state localctx = LaTeXParser.RelationContext(self, self._ctx, _parentState) _prevctx = localctx _startState = 2 self.enterRecursionRule(localctx, 2, self.RULE_relation, _p) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 83 self.expr() self._ctx.stop = self._input.LT(-1) self.state = 90 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,0,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx localctx = LaTeXParser.RelationContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_relation) self.state = 85 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") self.state = 86 _la = self._input.LA(1) if not(((((_la - 77)) & ~0x3f) == 0 and ((1 << (_la - 77)) & ((1 << (LaTeXParser.EQUAL - 77)) | (1 << (LaTeXParser.NEQ - 77)) | (1 << (LaTeXParser.LT - 77)) | (1 << (LaTeXParser.LTE - 77)) | (1 << (LaTeXParser.GT - 77)) | (1 << (LaTeXParser.GTE - 77)))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 87 self.relation(3) self.state = 92 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,0,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.unrollRecursionContexts(_parentctx) return localctx class EqualityContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.EqualityContext, self).__init__(parent, invokingState) self.parser = parser def expr(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.ExprContext) else: return self.getTypedRuleContext(LaTeXParser.ExprContext,i) def EQUAL(self): return self.getToken(LaTeXParser.EQUAL, 0) def getRuleIndex(self): return LaTeXParser.RULE_equality def equality(self): localctx = LaTeXParser.EqualityContext(self, self._ctx, self.state) self.enterRule(localctx, 4, self.RULE_equality) try: self.enterOuterAlt(localctx, 1) self.state = 93 self.expr() self.state = 94 self.match(LaTeXParser.EQUAL) self.state = 95 self.expr() except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class ExprContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.ExprContext, self).__init__(parent, invokingState) self.parser = parser def additive(self): return self.getTypedRuleContext(LaTeXParser.AdditiveContext,0) def getRuleIndex(self): return LaTeXParser.RULE_expr def expr(self): localctx = LaTeXParser.ExprContext(self, self._ctx, self.state) self.enterRule(localctx, 6, self.RULE_expr) try: self.enterOuterAlt(localctx, 1) self.state = 97 self.additive(0) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class AdditiveContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.AdditiveContext, self).__init__(parent, invokingState) self.parser = parser def mp(self): return self.getTypedRuleContext(LaTeXParser.MpContext,0) def additive(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.AdditiveContext) else: return self.getTypedRuleContext(LaTeXParser.AdditiveContext,i) def ADD(self): return self.getToken(LaTeXParser.ADD, 0) def SUB(self): return self.getToken(LaTeXParser.SUB, 0) def getRuleIndex(self): return LaTeXParser.RULE_additive def additive(self, _p=0): _parentctx = self._ctx _parentState = self.state localctx = LaTeXParser.AdditiveContext(self, self._ctx, _parentState) _prevctx = localctx _startState = 8 self.enterRecursionRule(localctx, 8, self.RULE_additive, _p) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 100 self.mp(0) self._ctx.stop = self._input.LT(-1) self.state = 107 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,1,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx localctx = LaTeXParser.AdditiveContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_additive) self.state = 102 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") self.state = 103 _la = self._input.LA(1) if not(_la==LaTeXParser.ADD or _la==LaTeXParser.SUB): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 104 self.additive(3) self.state = 109 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,1,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.unrollRecursionContexts(_parentctx) return localctx class MpContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.MpContext, self).__init__(parent, invokingState) self.parser = parser def unary(self): return self.getTypedRuleContext(LaTeXParser.UnaryContext,0) def mp(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.MpContext) else: return self.getTypedRuleContext(LaTeXParser.MpContext,i) def MUL(self): return self.getToken(LaTeXParser.MUL, 0) def CMD_TIMES(self): return self.getToken(LaTeXParser.CMD_TIMES, 0) def CMD_CDOT(self): return self.getToken(LaTeXParser.CMD_CDOT, 0) def DIV(self): return self.getToken(LaTeXParser.DIV, 0) def CMD_DIV(self): return self.getToken(LaTeXParser.CMD_DIV, 0) def COLON(self): return self.getToken(LaTeXParser.COLON, 0) def getRuleIndex(self): return LaTeXParser.RULE_mp def mp(self, _p=0): _parentctx = self._ctx _parentState = self.state localctx = LaTeXParser.MpContext(self, self._ctx, _parentState) _prevctx = localctx _startState = 10 self.enterRecursionRule(localctx, 10, self.RULE_mp, _p) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 111 self.unary() self._ctx.stop = self._input.LT(-1) self.state = 118 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,2,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx localctx = LaTeXParser.MpContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_mp) self.state = 113 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") self.state = 114 _la = self._input.LA(1) if not(((((_la - 16)) & ~0x3f) == 0 and ((1 << (_la - 16)) & ((1 << (LaTeXParser.MUL - 16)) | (1 << (LaTeXParser.DIV - 16)) | (1 << (LaTeXParser.CMD_TIMES - 16)) | (1 << (LaTeXParser.CMD_CDOT - 16)) | (1 << (LaTeXParser.CMD_DIV - 16)) | (1 << (LaTeXParser.COLON - 16)))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 115 self.mp(3) self.state = 120 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,2,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.unrollRecursionContexts(_parentctx) return localctx class Mp_nofuncContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Mp_nofuncContext, self).__init__(parent, invokingState) self.parser = parser def unary_nofunc(self): return self.getTypedRuleContext(LaTeXParser.Unary_nofuncContext,0) def mp_nofunc(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.Mp_nofuncContext) else: return self.getTypedRuleContext(LaTeXParser.Mp_nofuncContext,i) def MUL(self): return self.getToken(LaTeXParser.MUL, 0) def CMD_TIMES(self): return self.getToken(LaTeXParser.CMD_TIMES, 0) def CMD_CDOT(self): return self.getToken(LaTeXParser.CMD_CDOT, 0) def DIV(self): return self.getToken(LaTeXParser.DIV, 0) def CMD_DIV(self): return self.getToken(LaTeXParser.CMD_DIV, 0) def COLON(self): return self.getToken(LaTeXParser.COLON, 0) def getRuleIndex(self): return LaTeXParser.RULE_mp_nofunc def mp_nofunc(self, _p=0): _parentctx = self._ctx _parentState = self.state localctx = LaTeXParser.Mp_nofuncContext(self, self._ctx, _parentState) _prevctx = localctx _startState = 12 self.enterRecursionRule(localctx, 12, self.RULE_mp_nofunc, _p) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 122 self.unary_nofunc() self._ctx.stop = self._input.LT(-1) self.state = 129 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,3,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx localctx = LaTeXParser.Mp_nofuncContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_mp_nofunc) self.state = 124 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") self.state = 125 _la = self._input.LA(1) if not(((((_la - 16)) & ~0x3f) == 0 and ((1 << (_la - 16)) & ((1 << (LaTeXParser.MUL - 16)) | (1 << (LaTeXParser.DIV - 16)) | (1 << (LaTeXParser.CMD_TIMES - 16)) | (1 << (LaTeXParser.CMD_CDOT - 16)) | (1 << (LaTeXParser.CMD_DIV - 16)) | (1 << (LaTeXParser.COLON - 16)))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 126 self.mp_nofunc(3) self.state = 131 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,3,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.unrollRecursionContexts(_parentctx) return localctx class UnaryContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.UnaryContext, self).__init__(parent, invokingState) self.parser = parser def unary(self): return self.getTypedRuleContext(LaTeXParser.UnaryContext,0) def ADD(self): return self.getToken(LaTeXParser.ADD, 0) def SUB(self): return self.getToken(LaTeXParser.SUB, 0) def postfix(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.PostfixContext) else: return self.getTypedRuleContext(LaTeXParser.PostfixContext,i) def getRuleIndex(self): return LaTeXParser.RULE_unary def unary(self): localctx = LaTeXParser.UnaryContext(self, self._ctx, self.state) self.enterRule(localctx, 14, self.RULE_unary) self._la = 0 # Token type try: self.state = 139 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.ADD, LaTeXParser.SUB]: self.enterOuterAlt(localctx, 1) self.state = 132 _la = self._input.LA(1) if not(_la==LaTeXParser.ADD or _la==LaTeXParser.SUB): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 133 self.unary() pass elif token in [LaTeXParser.L_PAREN, LaTeXParser.L_BRACE, LaTeXParser.L_BRACE_LITERAL, LaTeXParser.L_BRACKET, LaTeXParser.BAR, LaTeXParser.L_BAR, LaTeXParser.L_ANGLE, LaTeXParser.FUNC_LIM, LaTeXParser.FUNC_INT, LaTeXParser.FUNC_SUM, LaTeXParser.FUNC_PROD, LaTeXParser.FUNC_EXP, LaTeXParser.FUNC_LOG, LaTeXParser.FUNC_LN, LaTeXParser.FUNC_SIN, LaTeXParser.FUNC_COS, LaTeXParser.FUNC_TAN, LaTeXParser.FUNC_CSC, LaTeXParser.FUNC_SEC, LaTeXParser.FUNC_COT, LaTeXParser.FUNC_ARCSIN, LaTeXParser.FUNC_ARCCOS, LaTeXParser.FUNC_ARCTAN, LaTeXParser.FUNC_ARCCSC, LaTeXParser.FUNC_ARCSEC, LaTeXParser.FUNC_ARCCOT, LaTeXParser.FUNC_SINH, LaTeXParser.FUNC_COSH, LaTeXParser.FUNC_TANH, LaTeXParser.FUNC_ARSINH, LaTeXParser.FUNC_ARCOSH, LaTeXParser.FUNC_ARTANH, LaTeXParser.L_FLOOR, LaTeXParser.L_CEIL, LaTeXParser.FUNC_SQRT, LaTeXParser.FUNC_OVERLINE, LaTeXParser.CMD_FRAC, LaTeXParser.CMD_BINOM, LaTeXParser.CMD_DBINOM, LaTeXParser.CMD_TBINOM, LaTeXParser.CMD_MATHIT, LaTeXParser.DIFFERENTIAL, LaTeXParser.LETTER, LaTeXParser.NUMBER, LaTeXParser.SYMBOL]: self.enterOuterAlt(localctx, 2) self.state = 135 self._errHandler.sync(self) _alt = 1 while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt == 1: self.state = 134 self.postfix() else: raise NoViableAltException(self) self.state = 137 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,4,self._ctx) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Unary_nofuncContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Unary_nofuncContext, self).__init__(parent, invokingState) self.parser = parser def unary_nofunc(self): return self.getTypedRuleContext(LaTeXParser.Unary_nofuncContext,0) def ADD(self): return self.getToken(LaTeXParser.ADD, 0) def SUB(self): return self.getToken(LaTeXParser.SUB, 0) def postfix(self): return self.getTypedRuleContext(LaTeXParser.PostfixContext,0) def postfix_nofunc(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.Postfix_nofuncContext) else: return self.getTypedRuleContext(LaTeXParser.Postfix_nofuncContext,i) def getRuleIndex(self): return LaTeXParser.RULE_unary_nofunc def unary_nofunc(self): localctx = LaTeXParser.Unary_nofuncContext(self, self._ctx, self.state) self.enterRule(localctx, 16, self.RULE_unary_nofunc) self._la = 0 # Token type try: self.state = 150 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.ADD, LaTeXParser.SUB]: self.enterOuterAlt(localctx, 1) self.state = 141 _la = self._input.LA(1) if not(_la==LaTeXParser.ADD or _la==LaTeXParser.SUB): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 142 self.unary_nofunc() pass elif token in [LaTeXParser.L_PAREN, LaTeXParser.L_BRACE, LaTeXParser.L_BRACE_LITERAL, LaTeXParser.L_BRACKET, LaTeXParser.BAR, LaTeXParser.L_BAR, LaTeXParser.L_ANGLE, LaTeXParser.FUNC_LIM, LaTeXParser.FUNC_INT, LaTeXParser.FUNC_SUM, LaTeXParser.FUNC_PROD, LaTeXParser.FUNC_EXP, LaTeXParser.FUNC_LOG, LaTeXParser.FUNC_LN, LaTeXParser.FUNC_SIN, LaTeXParser.FUNC_COS, LaTeXParser.FUNC_TAN, LaTeXParser.FUNC_CSC, LaTeXParser.FUNC_SEC, LaTeXParser.FUNC_COT, LaTeXParser.FUNC_ARCSIN, LaTeXParser.FUNC_ARCCOS, LaTeXParser.FUNC_ARCTAN, LaTeXParser.FUNC_ARCCSC, LaTeXParser.FUNC_ARCSEC, LaTeXParser.FUNC_ARCCOT, LaTeXParser.FUNC_SINH, LaTeXParser.FUNC_COSH, LaTeXParser.FUNC_TANH, LaTeXParser.FUNC_ARSINH, LaTeXParser.FUNC_ARCOSH, LaTeXParser.FUNC_ARTANH, LaTeXParser.L_FLOOR, LaTeXParser.L_CEIL, LaTeXParser.FUNC_SQRT, LaTeXParser.FUNC_OVERLINE, LaTeXParser.CMD_FRAC, LaTeXParser.CMD_BINOM, LaTeXParser.CMD_DBINOM, LaTeXParser.CMD_TBINOM, LaTeXParser.CMD_MATHIT, LaTeXParser.DIFFERENTIAL, LaTeXParser.LETTER, LaTeXParser.NUMBER, LaTeXParser.SYMBOL]: self.enterOuterAlt(localctx, 2) self.state = 143 self.postfix() self.state = 147 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,6,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: self.state = 144 self.postfix_nofunc() self.state = 149 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,6,self._ctx) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class PostfixContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.PostfixContext, self).__init__(parent, invokingState) self.parser = parser def exp(self): return self.getTypedRuleContext(LaTeXParser.ExpContext,0) def postfix_op(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.Postfix_opContext) else: return self.getTypedRuleContext(LaTeXParser.Postfix_opContext,i) def getRuleIndex(self): return LaTeXParser.RULE_postfix def postfix(self): localctx = LaTeXParser.PostfixContext(self, self._ctx, self.state) self.enterRule(localctx, 18, self.RULE_postfix) try: self.enterOuterAlt(localctx, 1) self.state = 152 self.exp(0) self.state = 156 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,8,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: self.state = 153 self.postfix_op() self.state = 158 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,8,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Postfix_nofuncContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Postfix_nofuncContext, self).__init__(parent, invokingState) self.parser = parser def exp_nofunc(self): return self.getTypedRuleContext(LaTeXParser.Exp_nofuncContext,0) def postfix_op(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.Postfix_opContext) else: return self.getTypedRuleContext(LaTeXParser.Postfix_opContext,i) def getRuleIndex(self): return LaTeXParser.RULE_postfix_nofunc def postfix_nofunc(self): localctx = LaTeXParser.Postfix_nofuncContext(self, self._ctx, self.state) self.enterRule(localctx, 20, self.RULE_postfix_nofunc) try: self.enterOuterAlt(localctx, 1) self.state = 159 self.exp_nofunc(0) self.state = 163 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,9,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: self.state = 160 self.postfix_op() self.state = 165 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,9,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Postfix_opContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Postfix_opContext, self).__init__(parent, invokingState) self.parser = parser def BANG(self): return self.getToken(LaTeXParser.BANG, 0) def eval_at(self): return self.getTypedRuleContext(LaTeXParser.Eval_atContext,0) def getRuleIndex(self): return LaTeXParser.RULE_postfix_op def postfix_op(self): localctx = LaTeXParser.Postfix_opContext(self, self._ctx, self.state) self.enterRule(localctx, 22, self.RULE_postfix_op) try: self.state = 168 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.BANG]: self.enterOuterAlt(localctx, 1) self.state = 166 self.match(LaTeXParser.BANG) pass elif token in [LaTeXParser.BAR]: self.enterOuterAlt(localctx, 2) self.state = 167 self.eval_at() pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Eval_atContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Eval_atContext, self).__init__(parent, invokingState) self.parser = parser def BAR(self): return self.getToken(LaTeXParser.BAR, 0) def eval_at_sup(self): return self.getTypedRuleContext(LaTeXParser.Eval_at_supContext,0) def eval_at_sub(self): return self.getTypedRuleContext(LaTeXParser.Eval_at_subContext,0) def getRuleIndex(self): return LaTeXParser.RULE_eval_at def eval_at(self): localctx = LaTeXParser.Eval_atContext(self, self._ctx, self.state) self.enterRule(localctx, 24, self.RULE_eval_at) try: self.enterOuterAlt(localctx, 1) self.state = 170 self.match(LaTeXParser.BAR) self.state = 176 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,11,self._ctx) if la_ == 1: self.state = 171 self.eval_at_sup() pass elif la_ == 2: self.state = 172 self.eval_at_sub() pass elif la_ == 3: self.state = 173 self.eval_at_sup() self.state = 174 self.eval_at_sub() pass except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Eval_at_subContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Eval_at_subContext, self).__init__(parent, invokingState) self.parser = parser def UNDERSCORE(self): return self.getToken(LaTeXParser.UNDERSCORE, 0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def equality(self): return self.getTypedRuleContext(LaTeXParser.EqualityContext,0) def getRuleIndex(self): return LaTeXParser.RULE_eval_at_sub def eval_at_sub(self): localctx = LaTeXParser.Eval_at_subContext(self, self._ctx, self.state) self.enterRule(localctx, 26, self.RULE_eval_at_sub) try: self.enterOuterAlt(localctx, 1) self.state = 178 self.match(LaTeXParser.UNDERSCORE) self.state = 179 self.match(LaTeXParser.L_BRACE) self.state = 182 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,12,self._ctx) if la_ == 1: self.state = 180 self.expr() pass elif la_ == 2: self.state = 181 self.equality() pass self.state = 184 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Eval_at_supContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Eval_at_supContext, self).__init__(parent, invokingState) self.parser = parser def CARET(self): return self.getToken(LaTeXParser.CARET, 0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def equality(self): return self.getTypedRuleContext(LaTeXParser.EqualityContext,0) def getRuleIndex(self): return LaTeXParser.RULE_eval_at_sup def eval_at_sup(self): localctx = LaTeXParser.Eval_at_supContext(self, self._ctx, self.state) self.enterRule(localctx, 28, self.RULE_eval_at_sup) try: self.enterOuterAlt(localctx, 1) self.state = 186 self.match(LaTeXParser.CARET) self.state = 187 self.match(LaTeXParser.L_BRACE) self.state = 190 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,13,self._ctx) if la_ == 1: self.state = 188 self.expr() pass elif la_ == 2: self.state = 189 self.equality() pass self.state = 192 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class ExpContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.ExpContext, self).__init__(parent, invokingState) self.parser = parser def comp(self): return self.getTypedRuleContext(LaTeXParser.CompContext,0) def exp(self): return self.getTypedRuleContext(LaTeXParser.ExpContext,0) def CARET(self): return self.getToken(LaTeXParser.CARET, 0) def atom(self): return self.getTypedRuleContext(LaTeXParser.AtomContext,0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def subexpr(self): return self.getTypedRuleContext(LaTeXParser.SubexprContext,0) def getRuleIndex(self): return LaTeXParser.RULE_exp def exp(self, _p=0): _parentctx = self._ctx _parentState = self.state localctx = LaTeXParser.ExpContext(self, self._ctx, _parentState) _prevctx = localctx _startState = 30 self.enterRecursionRule(localctx, 30, self.RULE_exp, _p) try: self.enterOuterAlt(localctx, 1) self.state = 195 self.comp() self._ctx.stop = self._input.LT(-1) self.state = 211 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,16,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx localctx = LaTeXParser.ExpContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_exp) self.state = 197 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") self.state = 198 self.match(LaTeXParser.CARET) self.state = 204 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.BAR, LaTeXParser.L_BAR, LaTeXParser.L_ANGLE, LaTeXParser.CMD_MATHIT, LaTeXParser.DIFFERENTIAL, LaTeXParser.LETTER, LaTeXParser.NUMBER, LaTeXParser.SYMBOL]: self.state = 199 self.atom() pass elif token in [LaTeXParser.L_BRACE]: self.state = 200 self.match(LaTeXParser.L_BRACE) self.state = 201 self.expr() self.state = 202 self.match(LaTeXParser.R_BRACE) pass else: raise NoViableAltException(self) self.state = 207 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,15,self._ctx) if la_ == 1: self.state = 206 self.subexpr() self.state = 213 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,16,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.unrollRecursionContexts(_parentctx) return localctx class Exp_nofuncContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Exp_nofuncContext, self).__init__(parent, invokingState) self.parser = parser def comp_nofunc(self): return self.getTypedRuleContext(LaTeXParser.Comp_nofuncContext,0) def exp_nofunc(self): return self.getTypedRuleContext(LaTeXParser.Exp_nofuncContext,0) def CARET(self): return self.getToken(LaTeXParser.CARET, 0) def atom(self): return self.getTypedRuleContext(LaTeXParser.AtomContext,0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def subexpr(self): return self.getTypedRuleContext(LaTeXParser.SubexprContext,0) def getRuleIndex(self): return LaTeXParser.RULE_exp_nofunc def exp_nofunc(self, _p=0): _parentctx = self._ctx _parentState = self.state localctx = LaTeXParser.Exp_nofuncContext(self, self._ctx, _parentState) _prevctx = localctx _startState = 32 self.enterRecursionRule(localctx, 32, self.RULE_exp_nofunc, _p) try: self.enterOuterAlt(localctx, 1) self.state = 215 self.comp_nofunc() self._ctx.stop = self._input.LT(-1) self.state = 231 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,19,self._ctx) while _alt!=2 and _alt!=ATN.INVALID_ALT_NUMBER: if _alt==1: if self._parseListeners is not None: self.triggerExitRuleEvent() _prevctx = localctx localctx = LaTeXParser.Exp_nofuncContext(self, _parentctx, _parentState) self.pushNewRecursionContext(localctx, _startState, self.RULE_exp_nofunc) self.state = 217 if not self.precpred(self._ctx, 2): from antlr4.error.Errors import FailedPredicateException raise FailedPredicateException(self, "self.precpred(self._ctx, 2)") self.state = 218 self.match(LaTeXParser.CARET) self.state = 224 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.BAR, LaTeXParser.L_BAR, LaTeXParser.L_ANGLE, LaTeXParser.CMD_MATHIT, LaTeXParser.DIFFERENTIAL, LaTeXParser.LETTER, LaTeXParser.NUMBER, LaTeXParser.SYMBOL]: self.state = 219 self.atom() pass elif token in [LaTeXParser.L_BRACE]: self.state = 220 self.match(LaTeXParser.L_BRACE) self.state = 221 self.expr() self.state = 222 self.match(LaTeXParser.R_BRACE) pass else: raise NoViableAltException(self) self.state = 227 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,18,self._ctx) if la_ == 1: self.state = 226 self.subexpr() self.state = 233 self._errHandler.sync(self) _alt = self._interp.adaptivePredict(self._input,19,self._ctx) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.unrollRecursionContexts(_parentctx) return localctx class CompContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.CompContext, self).__init__(parent, invokingState) self.parser = parser def group(self): return self.getTypedRuleContext(LaTeXParser.GroupContext,0) def abs_group(self): return self.getTypedRuleContext(LaTeXParser.Abs_groupContext,0) def func(self): return self.getTypedRuleContext(LaTeXParser.FuncContext,0) def atom(self): return self.getTypedRuleContext(LaTeXParser.AtomContext,0) def frac(self): return self.getTypedRuleContext(LaTeXParser.FracContext,0) def binom(self): return self.getTypedRuleContext(LaTeXParser.BinomContext,0) def floor(self): return self.getTypedRuleContext(LaTeXParser.FloorContext,0) def ceil(self): return self.getTypedRuleContext(LaTeXParser.CeilContext,0) def getRuleIndex(self): return LaTeXParser.RULE_comp def comp(self): localctx = LaTeXParser.CompContext(self, self._ctx, self.state) self.enterRule(localctx, 34, self.RULE_comp) try: self.state = 242 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,20,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) self.state = 234 self.group() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) self.state = 235 self.abs_group() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) self.state = 236 self.func() pass elif la_ == 4: self.enterOuterAlt(localctx, 4) self.state = 237 self.atom() pass elif la_ == 5: self.enterOuterAlt(localctx, 5) self.state = 238 self.frac() pass elif la_ == 6: self.enterOuterAlt(localctx, 6) self.state = 239 self.binom() pass elif la_ == 7: self.enterOuterAlt(localctx, 7) self.state = 240 self.floor() pass elif la_ == 8: self.enterOuterAlt(localctx, 8) self.state = 241 self.ceil() pass except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Comp_nofuncContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Comp_nofuncContext, self).__init__(parent, invokingState) self.parser = parser def group(self): return self.getTypedRuleContext(LaTeXParser.GroupContext,0) def abs_group(self): return self.getTypedRuleContext(LaTeXParser.Abs_groupContext,0) def atom(self): return self.getTypedRuleContext(LaTeXParser.AtomContext,0) def frac(self): return self.getTypedRuleContext(LaTeXParser.FracContext,0) def binom(self): return self.getTypedRuleContext(LaTeXParser.BinomContext,0) def floor(self): return self.getTypedRuleContext(LaTeXParser.FloorContext,0) def ceil(self): return self.getTypedRuleContext(LaTeXParser.CeilContext,0) def getRuleIndex(self): return LaTeXParser.RULE_comp_nofunc def comp_nofunc(self): localctx = LaTeXParser.Comp_nofuncContext(self, self._ctx, self.state) self.enterRule(localctx, 36, self.RULE_comp_nofunc) try: self.state = 251 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,21,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) self.state = 244 self.group() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) self.state = 245 self.abs_group() pass elif la_ == 3: self.enterOuterAlt(localctx, 3) self.state = 246 self.atom() pass elif la_ == 4: self.enterOuterAlt(localctx, 4) self.state = 247 self.frac() pass elif la_ == 5: self.enterOuterAlt(localctx, 5) self.state = 248 self.binom() pass elif la_ == 6: self.enterOuterAlt(localctx, 6) self.state = 249 self.floor() pass elif la_ == 7: self.enterOuterAlt(localctx, 7) self.state = 250 self.ceil() pass except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class GroupContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.GroupContext, self).__init__(parent, invokingState) self.parser = parser def L_PAREN(self): return self.getToken(LaTeXParser.L_PAREN, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_PAREN(self): return self.getToken(LaTeXParser.R_PAREN, 0) def L_BRACKET(self): return self.getToken(LaTeXParser.L_BRACKET, 0) def R_BRACKET(self): return self.getToken(LaTeXParser.R_BRACKET, 0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def L_BRACE_LITERAL(self): return self.getToken(LaTeXParser.L_BRACE_LITERAL, 0) def R_BRACE_LITERAL(self): return self.getToken(LaTeXParser.R_BRACE_LITERAL, 0) def getRuleIndex(self): return LaTeXParser.RULE_group def group(self): localctx = LaTeXParser.GroupContext(self, self._ctx, self.state) self.enterRule(localctx, 38, self.RULE_group) try: self.state = 269 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.L_PAREN]: self.enterOuterAlt(localctx, 1) self.state = 253 self.match(LaTeXParser.L_PAREN) self.state = 254 self.expr() self.state = 255 self.match(LaTeXParser.R_PAREN) pass elif token in [LaTeXParser.L_BRACKET]: self.enterOuterAlt(localctx, 2) self.state = 257 self.match(LaTeXParser.L_BRACKET) self.state = 258 self.expr() self.state = 259 self.match(LaTeXParser.R_BRACKET) pass elif token in [LaTeXParser.L_BRACE]: self.enterOuterAlt(localctx, 3) self.state = 261 self.match(LaTeXParser.L_BRACE) self.state = 262 self.expr() self.state = 263 self.match(LaTeXParser.R_BRACE) pass elif token in [LaTeXParser.L_BRACE_LITERAL]: self.enterOuterAlt(localctx, 4) self.state = 265 self.match(LaTeXParser.L_BRACE_LITERAL) self.state = 266 self.expr() self.state = 267 self.match(LaTeXParser.R_BRACE_LITERAL) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Abs_groupContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Abs_groupContext, self).__init__(parent, invokingState) self.parser = parser def BAR(self, i=None): if i is None: return self.getTokens(LaTeXParser.BAR) else: return self.getToken(LaTeXParser.BAR, i) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def getRuleIndex(self): return LaTeXParser.RULE_abs_group def abs_group(self): localctx = LaTeXParser.Abs_groupContext(self, self._ctx, self.state) self.enterRule(localctx, 40, self.RULE_abs_group) try: self.enterOuterAlt(localctx, 1) self.state = 271 self.match(LaTeXParser.BAR) self.state = 272 self.expr() self.state = 273 self.match(LaTeXParser.BAR) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class AtomContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.AtomContext, self).__init__(parent, invokingState) self.parser = parser def LETTER(self): return self.getToken(LaTeXParser.LETTER, 0) def SYMBOL(self): return self.getToken(LaTeXParser.SYMBOL, 0) def subexpr(self): return self.getTypedRuleContext(LaTeXParser.SubexprContext,0) def NUMBER(self): return self.getToken(LaTeXParser.NUMBER, 0) def DIFFERENTIAL(self): return self.getToken(LaTeXParser.DIFFERENTIAL, 0) def mathit(self): return self.getTypedRuleContext(LaTeXParser.MathitContext,0) def bra(self): return self.getTypedRuleContext(LaTeXParser.BraContext,0) def ket(self): return self.getTypedRuleContext(LaTeXParser.KetContext,0) def getRuleIndex(self): return LaTeXParser.RULE_atom def atom(self): localctx = LaTeXParser.AtomContext(self, self._ctx, self.state) self.enterRule(localctx, 42, self.RULE_atom) self._la = 0 # Token type try: self.state = 284 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.LETTER, LaTeXParser.SYMBOL]: self.enterOuterAlt(localctx, 1) self.state = 275 _la = self._input.LA(1) if not(_la==LaTeXParser.LETTER or _la==LaTeXParser.SYMBOL): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 277 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,23,self._ctx) if la_ == 1: self.state = 276 self.subexpr() pass elif token in [LaTeXParser.NUMBER]: self.enterOuterAlt(localctx, 2) self.state = 279 self.match(LaTeXParser.NUMBER) pass elif token in [LaTeXParser.DIFFERENTIAL]: self.enterOuterAlt(localctx, 3) self.state = 280 self.match(LaTeXParser.DIFFERENTIAL) pass elif token in [LaTeXParser.CMD_MATHIT]: self.enterOuterAlt(localctx, 4) self.state = 281 self.mathit() pass elif token in [LaTeXParser.L_ANGLE]: self.enterOuterAlt(localctx, 5) self.state = 282 self.bra() pass elif token in [LaTeXParser.BAR, LaTeXParser.L_BAR]: self.enterOuterAlt(localctx, 6) self.state = 283 self.ket() pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class BraContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.BraContext, self).__init__(parent, invokingState) self.parser = parser def L_ANGLE(self): return self.getToken(LaTeXParser.L_ANGLE, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_BAR(self): return self.getToken(LaTeXParser.R_BAR, 0) def BAR(self): return self.getToken(LaTeXParser.BAR, 0) def getRuleIndex(self): return LaTeXParser.RULE_bra def bra(self): localctx = LaTeXParser.BraContext(self, self._ctx, self.state) self.enterRule(localctx, 44, self.RULE_bra) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 286 self.match(LaTeXParser.L_ANGLE) self.state = 287 self.expr() self.state = 288 _la = self._input.LA(1) if not(_la==LaTeXParser.BAR or _la==LaTeXParser.R_BAR): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class KetContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.KetContext, self).__init__(parent, invokingState) self.parser = parser def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_ANGLE(self): return self.getToken(LaTeXParser.R_ANGLE, 0) def L_BAR(self): return self.getToken(LaTeXParser.L_BAR, 0) def BAR(self): return self.getToken(LaTeXParser.BAR, 0) def getRuleIndex(self): return LaTeXParser.RULE_ket def ket(self): localctx = LaTeXParser.KetContext(self, self._ctx, self.state) self.enterRule(localctx, 46, self.RULE_ket) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 290 _la = self._input.LA(1) if not(_la==LaTeXParser.BAR or _la==LaTeXParser.L_BAR): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 291 self.expr() self.state = 292 self.match(LaTeXParser.R_ANGLE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class MathitContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.MathitContext, self).__init__(parent, invokingState) self.parser = parser def CMD_MATHIT(self): return self.getToken(LaTeXParser.CMD_MATHIT, 0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def mathit_text(self): return self.getTypedRuleContext(LaTeXParser.Mathit_textContext,0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def getRuleIndex(self): return LaTeXParser.RULE_mathit def mathit(self): localctx = LaTeXParser.MathitContext(self, self._ctx, self.state) self.enterRule(localctx, 48, self.RULE_mathit) try: self.enterOuterAlt(localctx, 1) self.state = 294 self.match(LaTeXParser.CMD_MATHIT) self.state = 295 self.match(LaTeXParser.L_BRACE) self.state = 296 self.mathit_text() self.state = 297 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Mathit_textContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Mathit_textContext, self).__init__(parent, invokingState) self.parser = parser def LETTER(self, i=None): if i is None: return self.getTokens(LaTeXParser.LETTER) else: return self.getToken(LaTeXParser.LETTER, i) def getRuleIndex(self): return LaTeXParser.RULE_mathit_text def mathit_text(self): localctx = LaTeXParser.Mathit_textContext(self, self._ctx, self.state) self.enterRule(localctx, 50, self.RULE_mathit_text) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 302 self._errHandler.sync(self) _la = self._input.LA(1) while _la==LaTeXParser.LETTER: self.state = 299 self.match(LaTeXParser.LETTER) self.state = 304 self._errHandler.sync(self) _la = self._input.LA(1) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class FracContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.FracContext, self).__init__(parent, invokingState) self.parser = parser self.upper = None # ExprContext self.lower = None # ExprContext def CMD_FRAC(self): return self.getToken(LaTeXParser.CMD_FRAC, 0) def L_BRACE(self, i=None): if i is None: return self.getTokens(LaTeXParser.L_BRACE) else: return self.getToken(LaTeXParser.L_BRACE, i) def R_BRACE(self, i=None): if i is None: return self.getTokens(LaTeXParser.R_BRACE) else: return self.getToken(LaTeXParser.R_BRACE, i) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.ExprContext) else: return self.getTypedRuleContext(LaTeXParser.ExprContext,i) def getRuleIndex(self): return LaTeXParser.RULE_frac def frac(self): localctx = LaTeXParser.FracContext(self, self._ctx, self.state) self.enterRule(localctx, 52, self.RULE_frac) try: self.enterOuterAlt(localctx, 1) self.state = 305 self.match(LaTeXParser.CMD_FRAC) self.state = 306 self.match(LaTeXParser.L_BRACE) self.state = 307 localctx.upper = self.expr() self.state = 308 self.match(LaTeXParser.R_BRACE) self.state = 309 self.match(LaTeXParser.L_BRACE) self.state = 310 localctx.lower = self.expr() self.state = 311 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class BinomContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.BinomContext, self).__init__(parent, invokingState) self.parser = parser self.n = None # ExprContext self.k = None # ExprContext def L_BRACE(self, i=None): if i is None: return self.getTokens(LaTeXParser.L_BRACE) else: return self.getToken(LaTeXParser.L_BRACE, i) def R_BRACE(self, i=None): if i is None: return self.getTokens(LaTeXParser.R_BRACE) else: return self.getToken(LaTeXParser.R_BRACE, i) def CMD_BINOM(self): return self.getToken(LaTeXParser.CMD_BINOM, 0) def CMD_DBINOM(self): return self.getToken(LaTeXParser.CMD_DBINOM, 0) def CMD_TBINOM(self): return self.getToken(LaTeXParser.CMD_TBINOM, 0) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.ExprContext) else: return self.getTypedRuleContext(LaTeXParser.ExprContext,i) def getRuleIndex(self): return LaTeXParser.RULE_binom def binom(self): localctx = LaTeXParser.BinomContext(self, self._ctx, self.state) self.enterRule(localctx, 54, self.RULE_binom) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 313 _la = self._input.LA(1) if not(((((_la - 67)) & ~0x3f) == 0 and ((1 << (_la - 67)) & ((1 << (LaTeXParser.CMD_BINOM - 67)) | (1 << (LaTeXParser.CMD_DBINOM - 67)) | (1 << (LaTeXParser.CMD_TBINOM - 67)))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 314 self.match(LaTeXParser.L_BRACE) self.state = 315 localctx.n = self.expr() self.state = 316 self.match(LaTeXParser.R_BRACE) self.state = 317 self.match(LaTeXParser.L_BRACE) self.state = 318 localctx.k = self.expr() self.state = 319 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class FloorContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.FloorContext, self).__init__(parent, invokingState) self.parser = parser self.val = None # ExprContext def L_FLOOR(self): return self.getToken(LaTeXParser.L_FLOOR, 0) def R_FLOOR(self): return self.getToken(LaTeXParser.R_FLOOR, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def getRuleIndex(self): return LaTeXParser.RULE_floor def floor(self): localctx = LaTeXParser.FloorContext(self, self._ctx, self.state) self.enterRule(localctx, 56, self.RULE_floor) try: self.enterOuterAlt(localctx, 1) self.state = 321 self.match(LaTeXParser.L_FLOOR) self.state = 322 localctx.val = self.expr() self.state = 323 self.match(LaTeXParser.R_FLOOR) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class CeilContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.CeilContext, self).__init__(parent, invokingState) self.parser = parser self.val = None # ExprContext def L_CEIL(self): return self.getToken(LaTeXParser.L_CEIL, 0) def R_CEIL(self): return self.getToken(LaTeXParser.R_CEIL, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def getRuleIndex(self): return LaTeXParser.RULE_ceil def ceil(self): localctx = LaTeXParser.CeilContext(self, self._ctx, self.state) self.enterRule(localctx, 58, self.RULE_ceil) try: self.enterOuterAlt(localctx, 1) self.state = 325 self.match(LaTeXParser.L_CEIL) self.state = 326 localctx.val = self.expr() self.state = 327 self.match(LaTeXParser.R_CEIL) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Func_normalContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Func_normalContext, self).__init__(parent, invokingState) self.parser = parser def FUNC_EXP(self): return self.getToken(LaTeXParser.FUNC_EXP, 0) def FUNC_LOG(self): return self.getToken(LaTeXParser.FUNC_LOG, 0) def FUNC_LN(self): return self.getToken(LaTeXParser.FUNC_LN, 0) def FUNC_SIN(self): return self.getToken(LaTeXParser.FUNC_SIN, 0) def FUNC_COS(self): return self.getToken(LaTeXParser.FUNC_COS, 0) def FUNC_TAN(self): return self.getToken(LaTeXParser.FUNC_TAN, 0) def FUNC_CSC(self): return self.getToken(LaTeXParser.FUNC_CSC, 0) def FUNC_SEC(self): return self.getToken(LaTeXParser.FUNC_SEC, 0) def FUNC_COT(self): return self.getToken(LaTeXParser.FUNC_COT, 0) def FUNC_ARCSIN(self): return self.getToken(LaTeXParser.FUNC_ARCSIN, 0) def FUNC_ARCCOS(self): return self.getToken(LaTeXParser.FUNC_ARCCOS, 0) def FUNC_ARCTAN(self): return self.getToken(LaTeXParser.FUNC_ARCTAN, 0) def FUNC_ARCCSC(self): return self.getToken(LaTeXParser.FUNC_ARCCSC, 0) def FUNC_ARCSEC(self): return self.getToken(LaTeXParser.FUNC_ARCSEC, 0) def FUNC_ARCCOT(self): return self.getToken(LaTeXParser.FUNC_ARCCOT, 0) def FUNC_SINH(self): return self.getToken(LaTeXParser.FUNC_SINH, 0) def FUNC_COSH(self): return self.getToken(LaTeXParser.FUNC_COSH, 0) def FUNC_TANH(self): return self.getToken(LaTeXParser.FUNC_TANH, 0) def FUNC_ARSINH(self): return self.getToken(LaTeXParser.FUNC_ARSINH, 0) def FUNC_ARCOSH(self): return self.getToken(LaTeXParser.FUNC_ARCOSH, 0) def FUNC_ARTANH(self): return self.getToken(LaTeXParser.FUNC_ARTANH, 0) def getRuleIndex(self): return LaTeXParser.RULE_func_normal def func_normal(self): localctx = LaTeXParser.Func_normalContext(self, self._ctx, self.state) self.enterRule(localctx, 60, self.RULE_func_normal) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 329 _la = self._input.LA(1) if not((((_la) & ~0x3f) == 0 and ((1 << _la) & ((1 << LaTeXParser.FUNC_EXP) | (1 << LaTeXParser.FUNC_LOG) | (1 << LaTeXParser.FUNC_LN) | (1 << LaTeXParser.FUNC_SIN) | (1 << LaTeXParser.FUNC_COS) | (1 << LaTeXParser.FUNC_TAN) | (1 << LaTeXParser.FUNC_CSC) | (1 << LaTeXParser.FUNC_SEC) | (1 << LaTeXParser.FUNC_COT) | (1 << LaTeXParser.FUNC_ARCSIN) | (1 << LaTeXParser.FUNC_ARCCOS) | (1 << LaTeXParser.FUNC_ARCTAN) | (1 << LaTeXParser.FUNC_ARCCSC) | (1 << LaTeXParser.FUNC_ARCSEC) | (1 << LaTeXParser.FUNC_ARCCOT) | (1 << LaTeXParser.FUNC_SINH) | (1 << LaTeXParser.FUNC_COSH) | (1 << LaTeXParser.FUNC_TANH) | (1 << LaTeXParser.FUNC_ARSINH) | (1 << LaTeXParser.FUNC_ARCOSH) | (1 << LaTeXParser.FUNC_ARTANH))) != 0)): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class FuncContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.FuncContext, self).__init__(parent, invokingState) self.parser = parser self.root = None # ExprContext self.base = None # ExprContext def func_normal(self): return self.getTypedRuleContext(LaTeXParser.Func_normalContext,0) def L_PAREN(self): return self.getToken(LaTeXParser.L_PAREN, 0) def func_arg(self): return self.getTypedRuleContext(LaTeXParser.Func_argContext,0) def R_PAREN(self): return self.getToken(LaTeXParser.R_PAREN, 0) def func_arg_noparens(self): return self.getTypedRuleContext(LaTeXParser.Func_arg_noparensContext,0) def subexpr(self): return self.getTypedRuleContext(LaTeXParser.SubexprContext,0) def supexpr(self): return self.getTypedRuleContext(LaTeXParser.SupexprContext,0) def args(self): return self.getTypedRuleContext(LaTeXParser.ArgsContext,0) def LETTER(self): return self.getToken(LaTeXParser.LETTER, 0) def SYMBOL(self): return self.getToken(LaTeXParser.SYMBOL, 0) def FUNC_INT(self): return self.getToken(LaTeXParser.FUNC_INT, 0) def DIFFERENTIAL(self): return self.getToken(LaTeXParser.DIFFERENTIAL, 0) def frac(self): return self.getTypedRuleContext(LaTeXParser.FracContext,0) def additive(self): return self.getTypedRuleContext(LaTeXParser.AdditiveContext,0) def FUNC_SQRT(self): return self.getToken(LaTeXParser.FUNC_SQRT, 0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def expr(self, i=None): if i is None: return self.getTypedRuleContexts(LaTeXParser.ExprContext) else: return self.getTypedRuleContext(LaTeXParser.ExprContext,i) def L_BRACKET(self): return self.getToken(LaTeXParser.L_BRACKET, 0) def R_BRACKET(self): return self.getToken(LaTeXParser.R_BRACKET, 0) def FUNC_OVERLINE(self): return self.getToken(LaTeXParser.FUNC_OVERLINE, 0) def mp(self): return self.getTypedRuleContext(LaTeXParser.MpContext,0) def FUNC_SUM(self): return self.getToken(LaTeXParser.FUNC_SUM, 0) def FUNC_PROD(self): return self.getToken(LaTeXParser.FUNC_PROD, 0) def subeq(self): return self.getTypedRuleContext(LaTeXParser.SubeqContext,0) def FUNC_LIM(self): return self.getToken(LaTeXParser.FUNC_LIM, 0) def limit_sub(self): return self.getTypedRuleContext(LaTeXParser.Limit_subContext,0) def getRuleIndex(self): return LaTeXParser.RULE_func def func(self): localctx = LaTeXParser.FuncContext(self, self._ctx, self.state) self.enterRule(localctx, 62, self.RULE_func) self._la = 0 # Token type try: self.state = 409 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.FUNC_EXP, LaTeXParser.FUNC_LOG, LaTeXParser.FUNC_LN, LaTeXParser.FUNC_SIN, LaTeXParser.FUNC_COS, LaTeXParser.FUNC_TAN, LaTeXParser.FUNC_CSC, LaTeXParser.FUNC_SEC, LaTeXParser.FUNC_COT, LaTeXParser.FUNC_ARCSIN, LaTeXParser.FUNC_ARCCOS, LaTeXParser.FUNC_ARCTAN, LaTeXParser.FUNC_ARCCSC, LaTeXParser.FUNC_ARCSEC, LaTeXParser.FUNC_ARCCOT, LaTeXParser.FUNC_SINH, LaTeXParser.FUNC_COSH, LaTeXParser.FUNC_TANH, LaTeXParser.FUNC_ARSINH, LaTeXParser.FUNC_ARCOSH, LaTeXParser.FUNC_ARTANH]: self.enterOuterAlt(localctx, 1) self.state = 331 self.func_normal() self.state = 344 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,30,self._ctx) if la_ == 1: self.state = 333 self._errHandler.sync(self) _la = self._input.LA(1) if _la==LaTeXParser.UNDERSCORE: self.state = 332 self.subexpr() self.state = 336 self._errHandler.sync(self) _la = self._input.LA(1) if _la==LaTeXParser.CARET: self.state = 335 self.supexpr() pass elif la_ == 2: self.state = 339 self._errHandler.sync(self) _la = self._input.LA(1) if _la==LaTeXParser.CARET: self.state = 338 self.supexpr() self.state = 342 self._errHandler.sync(self) _la = self._input.LA(1) if _la==LaTeXParser.UNDERSCORE: self.state = 341 self.subexpr() pass self.state = 351 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,31,self._ctx) if la_ == 1: self.state = 346 self.match(LaTeXParser.L_PAREN) self.state = 347 self.func_arg() self.state = 348 self.match(LaTeXParser.R_PAREN) pass elif la_ == 2: self.state = 350 self.func_arg_noparens() pass pass elif token in [LaTeXParser.LETTER, LaTeXParser.SYMBOL]: self.enterOuterAlt(localctx, 2) self.state = 353 _la = self._input.LA(1) if not(_la==LaTeXParser.LETTER or _la==LaTeXParser.SYMBOL): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 355 self._errHandler.sync(self) _la = self._input.LA(1) if _la==LaTeXParser.UNDERSCORE: self.state = 354 self.subexpr() self.state = 357 self.match(LaTeXParser.L_PAREN) self.state = 358 self.args() self.state = 359 self.match(LaTeXParser.R_PAREN) pass elif token in [LaTeXParser.FUNC_INT]: self.enterOuterAlt(localctx, 3) self.state = 361 self.match(LaTeXParser.FUNC_INT) self.state = 368 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.UNDERSCORE]: self.state = 362 self.subexpr() self.state = 363 self.supexpr() pass elif token in [LaTeXParser.CARET]: self.state = 365 self.supexpr() self.state = 366 self.subexpr() pass elif token in [LaTeXParser.ADD, LaTeXParser.SUB, LaTeXParser.L_PAREN, LaTeXParser.L_BRACE, LaTeXParser.L_BRACE_LITERAL, LaTeXParser.L_BRACKET, LaTeXParser.BAR, LaTeXParser.L_BAR, LaTeXParser.L_ANGLE, LaTeXParser.FUNC_LIM, LaTeXParser.FUNC_INT, LaTeXParser.FUNC_SUM, LaTeXParser.FUNC_PROD, LaTeXParser.FUNC_EXP, LaTeXParser.FUNC_LOG, LaTeXParser.FUNC_LN, LaTeXParser.FUNC_SIN, LaTeXParser.FUNC_COS, LaTeXParser.FUNC_TAN, LaTeXParser.FUNC_CSC, LaTeXParser.FUNC_SEC, LaTeXParser.FUNC_COT, LaTeXParser.FUNC_ARCSIN, LaTeXParser.FUNC_ARCCOS, LaTeXParser.FUNC_ARCTAN, LaTeXParser.FUNC_ARCCSC, LaTeXParser.FUNC_ARCSEC, LaTeXParser.FUNC_ARCCOT, LaTeXParser.FUNC_SINH, LaTeXParser.FUNC_COSH, LaTeXParser.FUNC_TANH, LaTeXParser.FUNC_ARSINH, LaTeXParser.FUNC_ARCOSH, LaTeXParser.FUNC_ARTANH, LaTeXParser.L_FLOOR, LaTeXParser.L_CEIL, LaTeXParser.FUNC_SQRT, LaTeXParser.FUNC_OVERLINE, LaTeXParser.CMD_FRAC, LaTeXParser.CMD_BINOM, LaTeXParser.CMD_DBINOM, LaTeXParser.CMD_TBINOM, LaTeXParser.CMD_MATHIT, LaTeXParser.DIFFERENTIAL, LaTeXParser.LETTER, LaTeXParser.NUMBER, LaTeXParser.SYMBOL]: pass else: pass self.state = 376 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,35,self._ctx) if la_ == 1: self.state = 371 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,34,self._ctx) if la_ == 1: self.state = 370 self.additive(0) self.state = 373 self.match(LaTeXParser.DIFFERENTIAL) pass elif la_ == 2: self.state = 374 self.frac() pass elif la_ == 3: self.state = 375 self.additive(0) pass pass elif token in [LaTeXParser.FUNC_SQRT]: self.enterOuterAlt(localctx, 4) self.state = 378 self.match(LaTeXParser.FUNC_SQRT) self.state = 383 self._errHandler.sync(self) _la = self._input.LA(1) if _la==LaTeXParser.L_BRACKET: self.state = 379 self.match(LaTeXParser.L_BRACKET) self.state = 380 localctx.root = self.expr() self.state = 381 self.match(LaTeXParser.R_BRACKET) self.state = 385 self.match(LaTeXParser.L_BRACE) self.state = 386 localctx.base = self.expr() self.state = 387 self.match(LaTeXParser.R_BRACE) pass elif token in [LaTeXParser.FUNC_OVERLINE]: self.enterOuterAlt(localctx, 5) self.state = 389 self.match(LaTeXParser.FUNC_OVERLINE) self.state = 390 self.match(LaTeXParser.L_BRACE) self.state = 391 localctx.base = self.expr() self.state = 392 self.match(LaTeXParser.R_BRACE) pass elif token in [LaTeXParser.FUNC_SUM, LaTeXParser.FUNC_PROD]: self.enterOuterAlt(localctx, 6) self.state = 394 _la = self._input.LA(1) if not(_la==LaTeXParser.FUNC_SUM or _la==LaTeXParser.FUNC_PROD): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 401 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.UNDERSCORE]: self.state = 395 self.subeq() self.state = 396 self.supexpr() pass elif token in [LaTeXParser.CARET]: self.state = 398 self.supexpr() self.state = 399 self.subeq() pass else: raise NoViableAltException(self) self.state = 403 self.mp(0) pass elif token in [LaTeXParser.FUNC_LIM]: self.enterOuterAlt(localctx, 7) self.state = 405 self.match(LaTeXParser.FUNC_LIM) self.state = 406 self.limit_sub() self.state = 407 self.mp(0) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class ArgsContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.ArgsContext, self).__init__(parent, invokingState) self.parser = parser def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def args(self): return self.getTypedRuleContext(LaTeXParser.ArgsContext,0) def getRuleIndex(self): return LaTeXParser.RULE_args def args(self): localctx = LaTeXParser.ArgsContext(self, self._ctx, self.state) self.enterRule(localctx, 64, self.RULE_args) try: self.state = 416 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,39,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) self.state = 411 self.expr() self.state = 412 self.match(LaTeXParser.T__0) self.state = 413 self.args() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) self.state = 415 self.expr() pass except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Limit_subContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Limit_subContext, self).__init__(parent, invokingState) self.parser = parser def UNDERSCORE(self): return self.getToken(LaTeXParser.UNDERSCORE, 0) def L_BRACE(self, i=None): if i is None: return self.getTokens(LaTeXParser.L_BRACE) else: return self.getToken(LaTeXParser.L_BRACE, i) def LIM_APPROACH_SYM(self): return self.getToken(LaTeXParser.LIM_APPROACH_SYM, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_BRACE(self, i=None): if i is None: return self.getTokens(LaTeXParser.R_BRACE) else: return self.getToken(LaTeXParser.R_BRACE, i) def LETTER(self): return self.getToken(LaTeXParser.LETTER, 0) def SYMBOL(self): return self.getToken(LaTeXParser.SYMBOL, 0) def CARET(self): return self.getToken(LaTeXParser.CARET, 0) def ADD(self): return self.getToken(LaTeXParser.ADD, 0) def SUB(self): return self.getToken(LaTeXParser.SUB, 0) def getRuleIndex(self): return LaTeXParser.RULE_limit_sub def limit_sub(self): localctx = LaTeXParser.Limit_subContext(self, self._ctx, self.state) self.enterRule(localctx, 66, self.RULE_limit_sub) self._la = 0 # Token type try: self.enterOuterAlt(localctx, 1) self.state = 418 self.match(LaTeXParser.UNDERSCORE) self.state = 419 self.match(LaTeXParser.L_BRACE) self.state = 420 _la = self._input.LA(1) if not(_la==LaTeXParser.LETTER or _la==LaTeXParser.SYMBOL): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 421 self.match(LaTeXParser.LIM_APPROACH_SYM) self.state = 422 self.expr() self.state = 427 self._errHandler.sync(self) _la = self._input.LA(1) if _la==LaTeXParser.CARET: self.state = 423 self.match(LaTeXParser.CARET) self.state = 424 self.match(LaTeXParser.L_BRACE) self.state = 425 _la = self._input.LA(1) if not(_la==LaTeXParser.ADD or _la==LaTeXParser.SUB): self._errHandler.recoverInline(self) else: self._errHandler.reportMatch(self) self.consume() self.state = 426 self.match(LaTeXParser.R_BRACE) self.state = 429 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Func_argContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Func_argContext, self).__init__(parent, invokingState) self.parser = parser def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def func_arg(self): return self.getTypedRuleContext(LaTeXParser.Func_argContext,0) def getRuleIndex(self): return LaTeXParser.RULE_func_arg def func_arg(self): localctx = LaTeXParser.Func_argContext(self, self._ctx, self.state) self.enterRule(localctx, 68, self.RULE_func_arg) try: self.state = 436 self._errHandler.sync(self) la_ = self._interp.adaptivePredict(self._input,41,self._ctx) if la_ == 1: self.enterOuterAlt(localctx, 1) self.state = 431 self.expr() pass elif la_ == 2: self.enterOuterAlt(localctx, 2) self.state = 432 self.expr() self.state = 433 self.match(LaTeXParser.T__0) self.state = 434 self.func_arg() pass except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class Func_arg_noparensContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.Func_arg_noparensContext, self).__init__(parent, invokingState) self.parser = parser def mp_nofunc(self): return self.getTypedRuleContext(LaTeXParser.Mp_nofuncContext,0) def getRuleIndex(self): return LaTeXParser.RULE_func_arg_noparens def func_arg_noparens(self): localctx = LaTeXParser.Func_arg_noparensContext(self, self._ctx, self.state) self.enterRule(localctx, 70, self.RULE_func_arg_noparens) try: self.enterOuterAlt(localctx, 1) self.state = 438 self.mp_nofunc(0) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class SubexprContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.SubexprContext, self).__init__(parent, invokingState) self.parser = parser def UNDERSCORE(self): return self.getToken(LaTeXParser.UNDERSCORE, 0) def atom(self): return self.getTypedRuleContext(LaTeXParser.AtomContext,0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def getRuleIndex(self): return LaTeXParser.RULE_subexpr def subexpr(self): localctx = LaTeXParser.SubexprContext(self, self._ctx, self.state) self.enterRule(localctx, 72, self.RULE_subexpr) try: self.enterOuterAlt(localctx, 1) self.state = 440 self.match(LaTeXParser.UNDERSCORE) self.state = 446 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.BAR, LaTeXParser.L_BAR, LaTeXParser.L_ANGLE, LaTeXParser.CMD_MATHIT, LaTeXParser.DIFFERENTIAL, LaTeXParser.LETTER, LaTeXParser.NUMBER, LaTeXParser.SYMBOL]: self.state = 441 self.atom() pass elif token in [LaTeXParser.L_BRACE]: self.state = 442 self.match(LaTeXParser.L_BRACE) self.state = 443 self.expr() self.state = 444 self.match(LaTeXParser.R_BRACE) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class SupexprContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.SupexprContext, self).__init__(parent, invokingState) self.parser = parser def CARET(self): return self.getToken(LaTeXParser.CARET, 0) def atom(self): return self.getTypedRuleContext(LaTeXParser.AtomContext,0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def expr(self): return self.getTypedRuleContext(LaTeXParser.ExprContext,0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def getRuleIndex(self): return LaTeXParser.RULE_supexpr def supexpr(self): localctx = LaTeXParser.SupexprContext(self, self._ctx, self.state) self.enterRule(localctx, 74, self.RULE_supexpr) try: self.enterOuterAlt(localctx, 1) self.state = 448 self.match(LaTeXParser.CARET) self.state = 454 self._errHandler.sync(self) token = self._input.LA(1) if token in [LaTeXParser.BAR, LaTeXParser.L_BAR, LaTeXParser.L_ANGLE, LaTeXParser.CMD_MATHIT, LaTeXParser.DIFFERENTIAL, LaTeXParser.LETTER, LaTeXParser.NUMBER, LaTeXParser.SYMBOL]: self.state = 449 self.atom() pass elif token in [LaTeXParser.L_BRACE]: self.state = 450 self.match(LaTeXParser.L_BRACE) self.state = 451 self.expr() self.state = 452 self.match(LaTeXParser.R_BRACE) pass else: raise NoViableAltException(self) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class SubeqContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.SubeqContext, self).__init__(parent, invokingState) self.parser = parser def UNDERSCORE(self): return self.getToken(LaTeXParser.UNDERSCORE, 0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def equality(self): return self.getTypedRuleContext(LaTeXParser.EqualityContext,0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def getRuleIndex(self): return LaTeXParser.RULE_subeq def subeq(self): localctx = LaTeXParser.SubeqContext(self, self._ctx, self.state) self.enterRule(localctx, 76, self.RULE_subeq) try: self.enterOuterAlt(localctx, 1) self.state = 456 self.match(LaTeXParser.UNDERSCORE) self.state = 457 self.match(LaTeXParser.L_BRACE) self.state = 458 self.equality() self.state = 459 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx class SupeqContext(ParserRuleContext): def __init__(self, parser, parent=None, invokingState=-1): super(LaTeXParser.SupeqContext, self).__init__(parent, invokingState) self.parser = parser def UNDERSCORE(self): return self.getToken(LaTeXParser.UNDERSCORE, 0) def L_BRACE(self): return self.getToken(LaTeXParser.L_BRACE, 0) def equality(self): return self.getTypedRuleContext(LaTeXParser.EqualityContext,0) def R_BRACE(self): return self.getToken(LaTeXParser.R_BRACE, 0) def getRuleIndex(self): return LaTeXParser.RULE_supeq def supeq(self): localctx = LaTeXParser.SupeqContext(self, self._ctx, self.state) self.enterRule(localctx, 78, self.RULE_supeq) try: self.enterOuterAlt(localctx, 1) self.state = 461 self.match(LaTeXParser.UNDERSCORE) self.state = 462 self.match(LaTeXParser.L_BRACE) self.state = 463 self.equality() self.state = 464 self.match(LaTeXParser.R_BRACE) except RecognitionException as re: localctx.exception = re self._errHandler.reportError(self, re) self._errHandler.recover(self, re) finally: self.exitRule() return localctx def sempred(self, localctx, ruleIndex, predIndex): if self._predicates == None: self._predicates = dict() self._predicates[1] = self.relation_sempred self._predicates[4] = self.additive_sempred self._predicates[5] = self.mp_sempred self._predicates[6] = self.mp_nofunc_sempred self._predicates[15] = self.exp_sempred self._predicates[16] = self.exp_nofunc_sempred pred = self._predicates.get(ruleIndex, None) if pred is None: raise Exception("No predicate with index:" + str(ruleIndex)) else: return pred(localctx, predIndex) def relation_sempred(self, localctx, predIndex): if predIndex == 0: return self.precpred(self._ctx, 2) def additive_sempred(self, localctx, predIndex): if predIndex == 1: return self.precpred(self._ctx, 2) def mp_sempred(self, localctx, predIndex): if predIndex == 2: return self.precpred(self._ctx, 2) def mp_nofunc_sempred(self, localctx, predIndex): if predIndex == 3: return self.precpred(self._ctx, 2) def exp_sempred(self, localctx, predIndex): if predIndex == 4: return self.precpred(self._ctx, 2) def exp_nofunc_sempred(self, localctx, predIndex): if predIndex == 5: return self.precpred(self._ctx, 2) sympy-sympy-1.9/sympy/parsing/latex/_build_latex_antlr.py000066400000000000000000000052351412543434000240760ustar00rootroot00000000000000import os import subprocess import glob from sympy.utilities.misc import debug here = os.path.dirname(__file__) grammar_file = os.path.abspath(os.path.join(here, "LaTeX.g4")) dir_latex_antlr = os.path.join(here, "_antlr") header = ''' # encoding: utf-8 # *** GENERATED BY `setup.py antlr`, DO NOT EDIT BY HAND *** # # Generated from ../LaTeX.g4, derived from latex2sympy # latex2sympy is licensed under the MIT license # https://github.com/augustt198/latex2sympy/blob/master/LICENSE.txt # # Generated with antlr4 # antlr4 is licensed under the BSD-3-Clause License # https://github.com/antlr/antlr4/blob/master/LICENSE.txt ''' def check_antlr_version(): debug("Checking antlr4 version...") try: debug(subprocess.check_output(["antlr4"]) .decode('utf-8').split("\n")[0]) return True except (subprocess.CalledProcessError, FileNotFoundError): debug("The 'antlr4' command line tool is not installed, " "or not on your PATH.\n" "> Please refer to the README.md file for more information.") return False def build_parser(output_dir=dir_latex_antlr): check_antlr_version() debug("Updating ANTLR-generated code in {}".format(output_dir)) if not os.path.exists(output_dir): os.makedirs(output_dir) with open(os.path.join(output_dir, "__init__.py"), "w+") as fp: fp.write(header) args = [ "antlr4", grammar_file, "-o", output_dir, # for now, not generating these as latex2sympy did not use them "-no-visitor", "-no-listener", ] debug("Running code generation...\n\t$ {}".format(" ".join(args))) subprocess.check_output(args, cwd=output_dir) debug("Applying headers, removing unnecessary files and renaming...") # Handle case insensitive file systems. If the files are already # generated, they will be written to latex* but LaTeX*.* won't match them. for path in (glob.glob(os.path.join(output_dir, "LaTeX*.*")) + glob.glob(os.path.join(output_dir, "latex*.*"))): # Remove files ending in .interp or .tokens as they are not needed. if not path.endswith(".py"): os.unlink(path) continue new_path = os.path.join(output_dir, os.path.basename(path).lower()) with open(path, 'r') as f: lines = [line.rstrip() + '\n' for line in f.readlines()] os.unlink(path) with open(new_path, "w") as out_file: offset = 2 out_file.write(header) out_file.writelines(lines[offset:]) debug("\t{}".format(new_path)) return True if __name__ == "__main__": build_parser() sympy-sympy-1.9/sympy/parsing/latex/_parse_latex_antlr.py000066400000000000000000000466321412543434000241170ustar00rootroot00000000000000# Ported from latex2sympy by @augustt198 # https://github.com/augustt198/latex2sympy # See license in LICENSE.txt import sympy from sympy.external import import_module from sympy.printing.str import StrPrinter from sympy.physics.quantum.state import Bra, Ket from .errors import LaTeXParsingError LaTeXParser = LaTeXLexer = MathErrorListener = None try: LaTeXParser = import_module('sympy.parsing.latex._antlr.latexparser', import_kwargs={'fromlist': ['LaTeXParser']}).LaTeXParser LaTeXLexer = import_module('sympy.parsing.latex._antlr.latexlexer', import_kwargs={'fromlist': ['LaTeXLexer']}).LaTeXLexer except Exception: pass ErrorListener = import_module('antlr4.error.ErrorListener', warn_not_installed=True, import_kwargs={'fromlist': ['ErrorListener']} ) if ErrorListener: class MathErrorListener(ErrorListener.ErrorListener): # type: ignore def __init__(self, src): super(ErrorListener.ErrorListener, self).__init__() self.src = src def syntaxError(self, recog, symbol, line, col, msg, e): fmt = "%s\n%s\n%s" marker = "~" * col + "^" if msg.startswith("missing"): err = fmt % (msg, self.src, marker) elif msg.startswith("no viable"): err = fmt % ("I expected something else here", self.src, marker) elif msg.startswith("mismatched"): names = LaTeXParser.literalNames expected = [ names[i] for i in e.getExpectedTokens() if i < len(names) ] if len(expected) < 10: expected = " ".join(expected) err = (fmt % ("I expected one of these: " + expected, self.src, marker)) else: err = (fmt % ("I expected something else here", self.src, marker)) else: err = fmt % ("I don't understand this", self.src, marker) raise LaTeXParsingError(err) def parse_latex(sympy): antlr4 = import_module('antlr4', warn_not_installed=True) if None in [antlr4, MathErrorListener]: raise ImportError("LaTeX parsing requires the antlr4 python package," " provided by pip (antlr4-python2-runtime or" " antlr4-python3-runtime) or" " conda (antlr-python-runtime)") matherror = MathErrorListener(sympy) stream = antlr4.InputStream(sympy) lex = LaTeXLexer(stream) lex.removeErrorListeners() lex.addErrorListener(matherror) tokens = antlr4.CommonTokenStream(lex) parser = LaTeXParser(tokens) # remove default console error listener parser.removeErrorListeners() parser.addErrorListener(matherror) relation = parser.math().relation() expr = convert_relation(relation) return expr def convert_relation(rel): if rel.expr(): return convert_expr(rel.expr()) lh = convert_relation(rel.relation(0)) rh = convert_relation(rel.relation(1)) if rel.LT(): return sympy.StrictLessThan(lh, rh) elif rel.LTE(): return sympy.LessThan(lh, rh) elif rel.GT(): return sympy.StrictGreaterThan(lh, rh) elif rel.GTE(): return sympy.GreaterThan(lh, rh) elif rel.EQUAL(): return sympy.Eq(lh, rh) elif rel.NEQ(): return sympy.Ne(lh, rh) def convert_expr(expr): return convert_add(expr.additive()) def convert_add(add): if add.ADD(): lh = convert_add(add.additive(0)) rh = convert_add(add.additive(1)) return sympy.Add(lh, rh, evaluate=False) elif add.SUB(): lh = convert_add(add.additive(0)) rh = convert_add(add.additive(1)) return sympy.Add(lh, sympy.Mul(-1, rh, evaluate=False), evaluate=False) else: return convert_mp(add.mp()) def convert_mp(mp): if hasattr(mp, 'mp'): mp_left = mp.mp(0) mp_right = mp.mp(1) else: mp_left = mp.mp_nofunc(0) mp_right = mp.mp_nofunc(1) if mp.MUL() or mp.CMD_TIMES() or mp.CMD_CDOT(): lh = convert_mp(mp_left) rh = convert_mp(mp_right) return sympy.Mul(lh, rh, evaluate=False) elif mp.DIV() or mp.CMD_DIV() or mp.COLON(): lh = convert_mp(mp_left) rh = convert_mp(mp_right) return sympy.Mul(lh, sympy.Pow(rh, -1, evaluate=False), evaluate=False) else: if hasattr(mp, 'unary'): return convert_unary(mp.unary()) else: return convert_unary(mp.unary_nofunc()) def convert_unary(unary): if hasattr(unary, 'unary'): nested_unary = unary.unary() else: nested_unary = unary.unary_nofunc() if hasattr(unary, 'postfix_nofunc'): first = unary.postfix() tail = unary.postfix_nofunc() postfix = [first] + tail else: postfix = unary.postfix() if unary.ADD(): return convert_unary(nested_unary) elif unary.SUB(): numabs = convert_unary(nested_unary) # Use Integer(-n) instead of Mul(-1, n) return -numabs elif postfix: return convert_postfix_list(postfix) def convert_postfix_list(arr, i=0): if i >= len(arr): raise LaTeXParsingError("Index out of bounds") res = convert_postfix(arr[i]) if isinstance(res, sympy.Expr): if i == len(arr) - 1: return res # nothing to multiply by else: if i > 0: left = convert_postfix(arr[i - 1]) right = convert_postfix(arr[i + 1]) if isinstance(left, sympy.Expr) and isinstance( right, sympy.Expr): left_syms = convert_postfix(arr[i - 1]).atoms(sympy.Symbol) right_syms = convert_postfix(arr[i + 1]).atoms( sympy.Symbol) # if the left and right sides contain no variables and the # symbol in between is 'x', treat as multiplication. if len(left_syms) == 0 and len(right_syms) == 0 and str( res) == "x": return convert_postfix_list(arr, i + 1) # multiply by next return sympy.Mul( res, convert_postfix_list(arr, i + 1), evaluate=False) else: # must be derivative wrt = res[0] if i == len(arr) - 1: raise LaTeXParsingError("Expected expression for derivative") else: expr = convert_postfix_list(arr, i + 1) return sympy.Derivative(expr, wrt) def do_subs(expr, at): if at.expr(): at_expr = convert_expr(at.expr()) syms = at_expr.atoms(sympy.Symbol) if len(syms) == 0: return expr elif len(syms) > 0: sym = next(iter(syms)) return expr.subs(sym, at_expr) elif at.equality(): lh = convert_expr(at.equality().expr(0)) rh = convert_expr(at.equality().expr(1)) return expr.subs(lh, rh) def convert_postfix(postfix): if hasattr(postfix, 'exp'): exp_nested = postfix.exp() else: exp_nested = postfix.exp_nofunc() exp = convert_exp(exp_nested) for op in postfix.postfix_op(): if op.BANG(): if isinstance(exp, list): raise LaTeXParsingError("Cannot apply postfix to derivative") exp = sympy.factorial(exp, evaluate=False) elif op.eval_at(): ev = op.eval_at() at_b = None at_a = None if ev.eval_at_sup(): at_b = do_subs(exp, ev.eval_at_sup()) if ev.eval_at_sub(): at_a = do_subs(exp, ev.eval_at_sub()) if at_b is not None and at_a is not None: exp = sympy.Add(at_b, -1 * at_a, evaluate=False) elif at_b is not None: exp = at_b elif at_a is not None: exp = at_a return exp def convert_exp(exp): if hasattr(exp, 'exp'): exp_nested = exp.exp() else: exp_nested = exp.exp_nofunc() if exp_nested: base = convert_exp(exp_nested) if isinstance(base, list): raise LaTeXParsingError("Cannot raise derivative to power") if exp.atom(): exponent = convert_atom(exp.atom()) elif exp.expr(): exponent = convert_expr(exp.expr()) return sympy.Pow(base, exponent, evaluate=False) else: if hasattr(exp, 'comp'): return convert_comp(exp.comp()) else: return convert_comp(exp.comp_nofunc()) def convert_comp(comp): if comp.group(): return convert_expr(comp.group().expr()) elif comp.abs_group(): return sympy.Abs(convert_expr(comp.abs_group().expr()), evaluate=False) elif comp.atom(): return convert_atom(comp.atom()) elif comp.frac(): return convert_frac(comp.frac()) elif comp.binom(): return convert_binom(comp.binom()) elif comp.floor(): return convert_floor(comp.floor()) elif comp.ceil(): return convert_ceil(comp.ceil()) elif comp.func(): return convert_func(comp.func()) def convert_atom(atom): if atom.LETTER(): subscriptName = '' if atom.subexpr(): subscript = None if atom.subexpr().expr(): # subscript is expr subscript = convert_expr(atom.subexpr().expr()) else: # subscript is atom subscript = convert_atom(atom.subexpr().atom()) subscriptName = '_{' + StrPrinter().doprint(subscript) + '}' return sympy.Symbol(atom.LETTER().getText() + subscriptName) elif atom.SYMBOL(): s = atom.SYMBOL().getText()[1:] if s == "infty": return sympy.oo else: if atom.subexpr(): subscript = None if atom.subexpr().expr(): # subscript is expr subscript = convert_expr(atom.subexpr().expr()) else: # subscript is atom subscript = convert_atom(atom.subexpr().atom()) subscriptName = StrPrinter().doprint(subscript) s += '_{' + subscriptName + '}' return sympy.Symbol(s) elif atom.NUMBER(): s = atom.NUMBER().getText().replace(",", "") return sympy.Number(s) elif atom.DIFFERENTIAL(): var = get_differential_var(atom.DIFFERENTIAL()) return sympy.Symbol('d' + var.name) elif atom.mathit(): text = rule2text(atom.mathit().mathit_text()) return sympy.Symbol(text) elif atom.bra(): val = convert_expr(atom.bra().expr()) return Bra(val) elif atom.ket(): val = convert_expr(atom.ket().expr()) return Ket(val) def rule2text(ctx): stream = ctx.start.getInputStream() # starting index of starting token startIdx = ctx.start.start # stopping index of stopping token stopIdx = ctx.stop.stop return stream.getText(startIdx, stopIdx) def convert_frac(frac): diff_op = False partial_op = False lower_itv = frac.lower.getSourceInterval() lower_itv_len = lower_itv[1] - lower_itv[0] + 1 if (frac.lower.start == frac.lower.stop and frac.lower.start.type == LaTeXLexer.DIFFERENTIAL): wrt = get_differential_var_str(frac.lower.start.text) diff_op = True elif (lower_itv_len == 2 and frac.lower.start.type == LaTeXLexer.SYMBOL and frac.lower.start.text == '\\partial' and (frac.lower.stop.type == LaTeXLexer.LETTER or frac.lower.stop.type == LaTeXLexer.SYMBOL)): partial_op = True wrt = frac.lower.stop.text if frac.lower.stop.type == LaTeXLexer.SYMBOL: wrt = wrt[1:] if diff_op or partial_op: wrt = sympy.Symbol(wrt) if (diff_op and frac.upper.start == frac.upper.stop and frac.upper.start.type == LaTeXLexer.LETTER and frac.upper.start.text == 'd'): return [wrt] elif (partial_op and frac.upper.start == frac.upper.stop and frac.upper.start.type == LaTeXLexer.SYMBOL and frac.upper.start.text == '\\partial'): return [wrt] upper_text = rule2text(frac.upper) expr_top = None if diff_op and upper_text.startswith('d'): expr_top = parse_latex(upper_text[1:]) elif partial_op and frac.upper.start.text == '\\partial': expr_top = parse_latex(upper_text[len('\\partial'):]) if expr_top: return sympy.Derivative(expr_top, wrt) expr_top = convert_expr(frac.upper) expr_bot = convert_expr(frac.lower) inverse_denom = sympy.Pow(expr_bot, -1, evaluate=False) if expr_top == 1: return inverse_denom else: return sympy.Mul(expr_top, inverse_denom, evaluate=False) def convert_binom(binom): expr_n = convert_expr(binom.n) expr_k = convert_expr(binom.k) return sympy.binomial(expr_n, expr_k, evaluate=False) def convert_floor(floor): val = convert_expr(floor.val) return sympy.floor(val, evaluate=False) def convert_ceil(ceil): val = convert_expr(ceil.val) return sympy.ceiling(val, evaluate=False) def convert_func(func): if func.func_normal(): if func.L_PAREN(): # function called with parenthesis arg = convert_func_arg(func.func_arg()) else: arg = convert_func_arg(func.func_arg_noparens()) name = func.func_normal().start.text[1:] # change arc -> a if name in [ "arcsin", "arccos", "arctan", "arccsc", "arcsec", "arccot" ]: name = "a" + name[3:] expr = getattr(sympy.functions, name)(arg, evaluate=False) if name in ["arsinh", "arcosh", "artanh"]: name = "a" + name[2:] expr = getattr(sympy.functions, name)(arg, evaluate=False) if name == "exp": expr = sympy.exp(arg, evaluate=False) if (name == "log" or name == "ln"): if func.subexpr(): if func.subexpr().expr(): base = convert_expr(func.subexpr().expr()) else: base = convert_atom(func.subexpr().atom()) elif name == "log": base = 10 elif name == "ln": base = sympy.E expr = sympy.log(arg, base, evaluate=False) func_pow = None should_pow = True if func.supexpr(): if func.supexpr().expr(): func_pow = convert_expr(func.supexpr().expr()) else: func_pow = convert_atom(func.supexpr().atom()) if name in [ "sin", "cos", "tan", "csc", "sec", "cot", "sinh", "cosh", "tanh" ]: if func_pow == -1: name = "a" + name should_pow = False expr = getattr(sympy.functions, name)(arg, evaluate=False) if func_pow and should_pow: expr = sympy.Pow(expr, func_pow, evaluate=False) return expr elif func.LETTER() or func.SYMBOL(): if func.LETTER(): fname = func.LETTER().getText() elif func.SYMBOL(): fname = func.SYMBOL().getText()[1:] fname = str(fname) # can't be unicode if func.subexpr(): subscript = None if func.subexpr().expr(): # subscript is expr subscript = convert_expr(func.subexpr().expr()) else: # subscript is atom subscript = convert_atom(func.subexpr().atom()) subscriptName = StrPrinter().doprint(subscript) fname += '_{' + subscriptName + '}' input_args = func.args() output_args = [] while input_args.args(): # handle multiple arguments to function output_args.append(convert_expr(input_args.expr())) input_args = input_args.args() output_args.append(convert_expr(input_args.expr())) return sympy.Function(fname)(*output_args) elif func.FUNC_INT(): return handle_integral(func) elif func.FUNC_SQRT(): expr = convert_expr(func.base) if func.root: r = convert_expr(func.root) return sympy.root(expr, r, evaluate=False) else: return sympy.sqrt(expr, evaluate=False) elif func.FUNC_OVERLINE(): expr = convert_expr(func.base) return sympy.conjugate(expr, evaluate=False) elif func.FUNC_SUM(): return handle_sum_or_prod(func, "summation") elif func.FUNC_PROD(): return handle_sum_or_prod(func, "product") elif func.FUNC_LIM(): return handle_limit(func) def convert_func_arg(arg): if hasattr(arg, 'expr'): return convert_expr(arg.expr()) else: return convert_mp(arg.mp_nofunc()) def handle_integral(func): if func.additive(): integrand = convert_add(func.additive()) elif func.frac(): integrand = convert_frac(func.frac()) else: integrand = 1 int_var = None if func.DIFFERENTIAL(): int_var = get_differential_var(func.DIFFERENTIAL()) else: for sym in integrand.atoms(sympy.Symbol): s = str(sym) if len(s) > 1 and s[0] == 'd': if s[1] == '\\': int_var = sympy.Symbol(s[2:]) else: int_var = sympy.Symbol(s[1:]) int_sym = sym if int_var: integrand = integrand.subs(int_sym, 1) else: # Assume dx by default int_var = sympy.Symbol('x') if func.subexpr(): if func.subexpr().atom(): lower = convert_atom(func.subexpr().atom()) else: lower = convert_expr(func.subexpr().expr()) if func.supexpr().atom(): upper = convert_atom(func.supexpr().atom()) else: upper = convert_expr(func.supexpr().expr()) return sympy.Integral(integrand, (int_var, lower, upper)) else: return sympy.Integral(integrand, int_var) def handle_sum_or_prod(func, name): val = convert_mp(func.mp()) iter_var = convert_expr(func.subeq().equality().expr(0)) start = convert_expr(func.subeq().equality().expr(1)) if func.supexpr().expr(): # ^{expr} end = convert_expr(func.supexpr().expr()) else: # ^atom end = convert_atom(func.supexpr().atom()) if name == "summation": return sympy.Sum(val, (iter_var, start, end)) elif name == "product": return sympy.Product(val, (iter_var, start, end)) def handle_limit(func): sub = func.limit_sub() if sub.LETTER(): var = sympy.Symbol(sub.LETTER().getText()) elif sub.SYMBOL(): var = sympy.Symbol(sub.SYMBOL().getText()[1:]) else: var = sympy.Symbol('x') if sub.SUB(): direction = "-" else: direction = "+" approaching = convert_expr(sub.expr()) content = convert_mp(func.mp()) return sympy.Limit(content, var, approaching, direction) def get_differential_var(d): text = get_differential_var_str(d.getText()) return sympy.Symbol(text) def get_differential_var_str(text): for i in range(1, len(text)): c = text[i] if not (c == " " or c == "\r" or c == "\n" or c == "\t"): idx = i break text = text[idx:] if text[0] == "\\": text = text[1:] return text sympy-sympy-1.9/sympy/parsing/latex/errors.py000066400000000000000000000000551412543434000215520ustar00rootroot00000000000000class LaTeXParsingError(Exception): pass sympy-sympy-1.9/sympy/parsing/mathematica.py000066400000000000000000000312731412543434000214040ustar00rootroot00000000000000from typing import Any, Dict, Tuple from itertools import product import re from sympy import sympify def mathematica(s, additional_translations=None): ''' Users can add their own translation dictionary. variable-length argument needs '*' character. Examples ======== >>> from sympy.parsing.mathematica import mathematica >>> mathematica('Log3[9]', {'Log3[x]':'log(x,3)'}) 2 >>> mathematica('F[7,5,3]', {'F[*x]':'Max(*x)*Min(*x)'}) 21 ''' parser = MathematicaParser(additional_translations) return sympify(parser.parse(s)) def _deco(cls): cls._initialize_class() return cls @_deco class MathematicaParser: '''An instance of this class converts a string of a basic Mathematica expression to SymPy style. Output is string type.''' # left: Mathematica, right: SymPy CORRESPONDENCES = { 'Sqrt[x]': 'sqrt(x)', 'Exp[x]': 'exp(x)', 'Log[x]': 'log(x)', 'Log[x,y]': 'log(y,x)', 'Log2[x]': 'log(x,2)', 'Log10[x]': 'log(x,10)', 'Mod[x,y]': 'Mod(x,y)', 'Max[*x]': 'Max(*x)', 'Min[*x]': 'Min(*x)', 'Pochhammer[x,y]':'rf(x,y)', 'ArcTan[x,y]':'atan2(y,x)', 'ExpIntegralEi[x]': 'Ei(x)', 'SinIntegral[x]': 'Si(x)', 'CosIntegral[x]': 'Ci(x)', 'AiryAi[x]': 'airyai(x)', 'AiryAiPrime[x]': 'airyaiprime(x)', 'AiryBi[x]' :'airybi(x)', 'AiryBiPrime[x]' :'airybiprime(x)', 'LogIntegral[x]':' li(x)', 'PrimePi[x]': 'primepi(x)', 'Prime[x]': 'prime(x)', 'PrimeQ[x]': 'isprime(x)' } # trigonometric, e.t.c. for arc, tri, h in product(('', 'Arc'), ( 'Sin', 'Cos', 'Tan', 'Cot', 'Sec', 'Csc'), ('', 'h')): fm = arc + tri + h + '[x]' if arc: # arc func fs = 'a' + tri.lower() + h + '(x)' else: # non-arc func fs = tri.lower() + h + '(x)' CORRESPONDENCES.update({fm: fs}) REPLACEMENTS = { ' ': '', '^': '**', '{': '[', '}': ']', } RULES = { # a single whitespace to '*' 'whitespace': ( re.compile(r''' (?<=[a-zA-Z\d]) # a letter or a number \ # a whitespace (?=[a-zA-Z\d]) # a letter or a number ''', re.VERBOSE), '*'), # add omitted '*' character 'add*_1': ( re.compile(r''' (?<=[])\d]) # ], ) or a number # '' (?=[(a-zA-Z]) # ( or a single letter ''', re.VERBOSE), '*'), # add omitted '*' character (variable letter preceding) 'add*_2': ( re.compile(r''' (?<=[a-zA-Z]) # a letter \( # ( as a character (?=.) # any characters ''', re.VERBOSE), '*('), # convert 'Pi' to 'pi' 'Pi': ( re.compile(r''' (?: \A|(?<=[^a-zA-Z]) ) Pi # 'Pi' is 3.14159... in Mathematica (?=[^a-zA-Z]) ''', re.VERBOSE), 'pi'), } # Mathematica function name pattern FM_PATTERN = re.compile(r''' (?: \A|(?<=[^a-zA-Z]) # at the top or a non-letter ) [A-Z][a-zA-Z\d]* # Function (?=\[) # [ as a character ''', re.VERBOSE) # list or matrix pattern (for future usage) ARG_MTRX_PATTERN = re.compile(r''' \{.*\} ''', re.VERBOSE) # regex string for function argument pattern ARGS_PATTERN_TEMPLATE = r''' (?: \A|(?<=[^a-zA-Z]) ) {arguments} # model argument like x, y,... (?=[^a-zA-Z]) ''' # will contain transformed CORRESPONDENCES dictionary TRANSLATIONS = {} # type: Dict[Tuple[str, int], Dict[str, Any]] # cache for a raw users' translation dictionary cache_original = {} # type: Dict[Tuple[str, int], Dict[str, Any]] # cache for a compiled users' translation dictionary cache_compiled = {} # type: Dict[Tuple[str, int], Dict[str, Any]] @classmethod def _initialize_class(cls): # get a transformed CORRESPONDENCES dictionary d = cls._compile_dictionary(cls.CORRESPONDENCES) cls.TRANSLATIONS.update(d) def __init__(self, additional_translations=None): self.translations = {} # update with TRANSLATIONS (class constant) self.translations.update(self.TRANSLATIONS) if additional_translations is None: additional_translations = {} # check the latest added translations if self.__class__.cache_original != additional_translations: if not isinstance(additional_translations, dict): raise ValueError('The argument must be dict type') # get a transformed additional_translations dictionary d = self._compile_dictionary(additional_translations) # update cache self.__class__.cache_original = additional_translations self.__class__.cache_compiled = d # merge user's own translations self.translations.update(self.__class__.cache_compiled) @classmethod def _compile_dictionary(cls, dic): # for return d = {} for fm, fs in dic.items(): # check function form cls._check_input(fm) cls._check_input(fs) # uncover '*' hiding behind a whitespace fm = cls._apply_rules(fm, 'whitespace') fs = cls._apply_rules(fs, 'whitespace') # remove whitespace(s) fm = cls._replace(fm, ' ') fs = cls._replace(fs, ' ') # search Mathematica function name m = cls.FM_PATTERN.search(fm) # if no-hit if m is None: err = "'{f}' function form is invalid.".format(f=fm) raise ValueError(err) # get Mathematica function name like 'Log' fm_name = m.group() # get arguments of Mathematica function args, end = cls._get_args(m) # function side check. (e.g.) '2*Func[x]' is invalid. if m.start() != 0 or end != len(fm): err = "'{f}' function form is invalid.".format(f=fm) raise ValueError(err) # check the last argument's 1st character if args[-1][0] == '*': key_arg = '*' else: key_arg = len(args) key = (fm_name, key_arg) # convert '*x' to '\\*x' for regex re_args = [x if x[0] != '*' else '\\' + x for x in args] # for regex. Example: (?:(x|y|z)) xyz = '(?:(' + '|'.join(re_args) + '))' # string for regex compile patStr = cls.ARGS_PATTERN_TEMPLATE.format(arguments=xyz) pat = re.compile(patStr, re.VERBOSE) # update dictionary d[key] = {} d[key]['fs'] = fs # SymPy function template d[key]['args'] = args # args are ['x', 'y'] for example d[key]['pat'] = pat return d def _convert_function(self, s): '''Parse Mathematica function to SymPy one''' # compiled regex object pat = self.FM_PATTERN scanned = '' # converted string cur = 0 # position cursor while True: m = pat.search(s) if m is None: # append the rest of string scanned += s break # get Mathematica function name fm = m.group() # get arguments, and the end position of fm function args, end = self._get_args(m) # the start position of fm function bgn = m.start() # convert Mathematica function to SymPy one s = self._convert_one_function(s, fm, args, bgn, end) # update cursor cur = bgn # append converted part scanned += s[:cur] # shrink s s = s[cur:] return scanned def _convert_one_function(self, s, fm, args, bgn, end): # no variable-length argument if (fm, len(args)) in self.translations: key = (fm, len(args)) # x, y,... model arguments x_args = self.translations[key]['args'] # make CORRESPONDENCES between model arguments and actual ones d = {k: v for k, v in zip(x_args, args)} # with variable-length argument elif (fm, '*') in self.translations: key = (fm, '*') # x, y,..*args (model arguments) x_args = self.translations[key]['args'] # make CORRESPONDENCES between model arguments and actual ones d = {} for i, x in enumerate(x_args): if x[0] == '*': d[x] = ','.join(args[i:]) break d[x] = args[i] # out of self.translations else: err = "'{f}' is out of the whitelist.".format(f=fm) raise ValueError(err) # template string of converted function template = self.translations[key]['fs'] # regex pattern for x_args pat = self.translations[key]['pat'] scanned = '' cur = 0 while True: m = pat.search(template) if m is None: scanned += template break # get model argument x = m.group() # get a start position of the model argument xbgn = m.start() # add the corresponding actual argument scanned += template[:xbgn] + d[x] # update cursor to the end of the model argument cur = m.end() # shrink template template = template[cur:] # update to swapped string s = s[:bgn] + scanned + s[end:] return s @classmethod def _get_args(cls, m): '''Get arguments of a Mathematica function''' s = m.string # whole string anc = m.end() + 1 # pointing the first letter of arguments square, curly = [], [] # stack for brakets args = [] # current cursor cur = anc for i, c in enumerate(s[anc:], anc): # extract one argument if c == ',' and (not square) and (not curly): args.append(s[cur:i]) # add an argument cur = i + 1 # move cursor # handle list or matrix (for future usage) if c == '{': curly.append(c) elif c == '}': curly.pop() # seek corresponding ']' with skipping irrevant ones if c == '[': square.append(c) elif c == ']': if square: square.pop() else: # empty stack args.append(s[cur:i]) break # the next position to ']' bracket (the function end) func_end = i + 1 return args, func_end @classmethod def _replace(cls, s, bef): aft = cls.REPLACEMENTS[bef] s = s.replace(bef, aft) return s @classmethod def _apply_rules(cls, s, bef): pat, aft = cls.RULES[bef] return pat.sub(aft, s) @classmethod def _check_input(cls, s): for bracket in (('[', ']'), ('{', '}'), ('(', ')')): if s.count(bracket[0]) != s.count(bracket[1]): err = "'{f}' function form is invalid.".format(f=s) raise ValueError(err) if '{' in s: err = "Currently list is not supported." raise ValueError(err) def parse(self, s): # input check self._check_input(s) # uncover '*' hiding behind a whitespace s = self._apply_rules(s, 'whitespace') # remove whitespace(s) s = self._replace(s, ' ') # add omitted '*' character s = self._apply_rules(s, 'add*_1') s = self._apply_rules(s, 'add*_2') # translate function s = self._convert_function(s) # '^' to '**' s = self._replace(s, '^') # 'Pi' to 'pi' s = self._apply_rules(s, 'Pi') # '{', '}' to '[', ']', respectively # s = cls._replace(s, '{') # currently list is not taken into account # s = cls._replace(s, '}') return s sympy-sympy-1.9/sympy/parsing/maxima.py000066400000000000000000000032401412543434000203740ustar00rootroot00000000000000import re from sympy import sympify, Sum, product, sin, cos class MaximaHelpers: def maxima_expand(expr): return expr.expand() def maxima_float(expr): return expr.evalf() def maxima_trigexpand(expr): return expr.expand(trig=True) def maxima_sum(a1, a2, a3, a4): return Sum(a1, (a2, a3, a4)).doit() def maxima_product(a1, a2, a3, a4): return product(a1, (a2, a3, a4)) def maxima_csc(expr): return 1/sin(expr) def maxima_sec(expr): return 1/cos(expr) sub_dict = { 'pi': re.compile(r'%pi'), 'E': re.compile(r'%e'), 'I': re.compile(r'%i'), '**': re.compile(r'\^'), 'oo': re.compile(r'\binf\b'), '-oo': re.compile(r'\bminf\b'), "'-'": re.compile(r'\bminus\b'), 'maxima_expand': re.compile(r'\bexpand\b'), 'maxima_float': re.compile(r'\bfloat\b'), 'maxima_trigexpand': re.compile(r'\btrigexpand'), 'maxima_sum': re.compile(r'\bsum\b'), 'maxima_product': re.compile(r'\bproduct\b'), 'cancel': re.compile(r'\bratsimp\b'), 'maxima_csc': re.compile(r'\bcsc\b'), 'maxima_sec': re.compile(r'\bsec\b') } var_name = re.compile(r'^\s*(\w+)\s*:') def parse_maxima(str, globals=None, name_dict={}): str = str.strip() str = str.rstrip('; ') for k, v in sub_dict.items(): str = v.sub(k, str) assign_var = None var_match = var_name.search(str) if var_match: assign_var = var_match.group(1) str = str[var_match.end():].strip() dct = MaximaHelpers.__dict__.copy() dct.update(name_dict) obj = sympify(str, locals=dct) if assign_var and globals: globals[assign_var] = obj return obj sympy-sympy-1.9/sympy/parsing/sym_expr.py000066400000000000000000000212761412543434000207770ustar00rootroot00000000000000from sympy.printing import pycode, ccode, fcode from sympy.external import import_module from sympy.utilities.decorator import doctest_depends_on lfortran = import_module('lfortran') cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) if lfortran: from sympy.parsing.fortran.fortran_parser import src_to_sympy if cin: from sympy.parsing.c.c_parser import parse_c @doctest_depends_on(modules=['lfortran', 'clang.cindex']) class SymPyExpression: # type: ignore """Class to store and handle SymPy expressions This class will hold SymPy Expressions and handle the API for the conversion to and from different languages. It works with the C and the Fortran Parser to generate SymPy expressions which are stored here and which can be converted to multiple language's source code. Notes ===== The module and its API are currently under development and experimental and can be changed during development. The Fortran parser does not support numeric assignments, so all the variables have been Initialized to zero. The module also depends on external dependencies: - LFortran which is required to use the Fortran parser - Clang which is required for the C parser Examples ======== Example of parsing C code: >>> from sympy.parsing.sym_expr import SymPyExpression >>> src = ''' ... int a,b; ... float c = 2, d =4; ... ''' >>> a = SymPyExpression(src, 'c') >>> a.return_expr() [Declaration(Variable(a, type=intc)), Declaration(Variable(b, type=intc)), Declaration(Variable(c, type=float32, value=2.0)), Declaration(Variable(d, type=float32, value=4.0))] An example of variable definiton: >>> from sympy.parsing.sym_expr import SymPyExpression >>> src2 = ''' ... integer :: a, b, c, d ... real :: p, q, r, s ... ''' >>> p = SymPyExpression() >>> p.convert_to_expr(src2, 'f') >>> p.convert_to_c() ['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0'] An example of Assignment: >>> from sympy.parsing.sym_expr import SymPyExpression >>> src3 = ''' ... integer :: a, b, c, d, e ... d = a + b - c ... e = b * d + c * e / a ... ''' >>> p = SymPyExpression(src3, 'f') >>> p.convert_to_python() ['a = 0', 'b = 0', 'c = 0', 'd = 0', 'e = 0', 'd = a + b - c', 'e = b*d + c*e/a'] An example of function definition: >>> from sympy.parsing.sym_expr import SymPyExpression >>> src = ''' ... integer function f(a,b) ... integer, intent(in) :: a, b ... integer :: r ... end function ... ''' >>> a = SymPyExpression(src, 'f') >>> a.convert_to_python() ['def f(a, b):\\n f = 0\\n r = 0\\n return f'] """ def __init__(self, source_code = None, mode = None): """Constructor for SymPyExpression class""" super().__init__() if not(mode or source_code): self._expr = [] elif mode: if source_code: if mode.lower() == 'f': if lfortran: self._expr = src_to_sympy(source_code) else: raise ImportError("LFortran is not installed, cannot parse Fortran code") elif mode.lower() == 'c': if cin: self._expr = parse_c(source_code) else: raise ImportError("Clang is not installed, cannot parse C code") else: raise NotImplementedError( 'Parser for specified language is not implemented' ) else: raise ValueError('Source code not present') else: raise ValueError('Please specify a mode for conversion') def convert_to_expr(self, src_code, mode): """Converts the given source code to sympy Expressions Attributes ========== src_code : String the source code or filename of the source code that is to be converted mode: String the mode to determine which parser is to be used according to the language of the source code f or F for Fortran c or C for C/C++ Examples ======== >>> from sympy.parsing.sym_expr import SymPyExpression >>> src3 = ''' ... integer function f(a,b) result(r) ... integer, intent(in) :: a, b ... integer :: x ... r = a + b -x ... end function ... ''' >>> p = SymPyExpression() >>> p.convert_to_expr(src3, 'f') >>> p.return_expr() [FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock( Declaration(Variable(r, type=integer, value=0)), Declaration(Variable(x, type=integer, value=0)), Assignment(Variable(r), a + b - x), Return(Variable(r)) ))] """ if mode.lower() == 'f': if lfortran: self._expr = src_to_sympy(src_code) else: raise ImportError("LFortran is not installed, cannot parse Fortran code") elif mode.lower() == 'c': if cin: self._expr = parse_c(src_code) else: raise ImportError("Clang is not installed, cannot parse C code") else: raise NotImplementedError( "Parser for specified language has not been implemented" ) def convert_to_python(self): """Returns a list with python code for the sympy expressions Examples ======== >>> from sympy.parsing.sym_expr import SymPyExpression >>> src2 = ''' ... integer :: a, b, c, d ... real :: p, q, r, s ... c = a/b ... d = c/a ... s = p/q ... r = q/p ... ''' >>> p = SymPyExpression(src2, 'f') >>> p.convert_to_python() ['a = 0', 'b = 0', 'c = 0', 'd = 0', 'p = 0.0', 'q = 0.0', 'r = 0.0', 's = 0.0', 'c = a/b', 'd = c/a', 's = p/q', 'r = q/p'] """ self._pycode = [] for iter in self._expr: self._pycode.append(pycode(iter)) return self._pycode def convert_to_c(self): """Returns a list with the c source code for the sympy expressions Examples ======== >>> from sympy.parsing.sym_expr import SymPyExpression >>> src2 = ''' ... integer :: a, b, c, d ... real :: p, q, r, s ... c = a/b ... d = c/a ... s = p/q ... r = q/p ... ''' >>> p = SymPyExpression() >>> p.convert_to_expr(src2, 'f') >>> p.convert_to_c() ['int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0', 'c = a/b;', 'd = c/a;', 's = p/q;', 'r = q/p;'] """ self._ccode = [] for iter in self._expr: self._ccode.append(ccode(iter)) return self._ccode def convert_to_fortran(self): """Returns a list with the fortran source code for the sympy expressions Examples ======== >>> from sympy.parsing.sym_expr import SymPyExpression >>> src2 = ''' ... integer :: a, b, c, d ... real :: p, q, r, s ... c = a/b ... d = c/a ... s = p/q ... r = q/p ... ''' >>> p = SymPyExpression(src2, 'f') >>> p.convert_to_fortran() [' integer*4 a', ' integer*4 b', ' integer*4 c', ' integer*4 d', ' real*8 p', ' real*8 q', ' real*8 r', ' real*8 s', ' c = a/b', ' d = c/a', ' s = p/q', ' r = q/p'] """ self._fcode = [] for iter in self._expr: self._fcode.append(fcode(iter)) return self._fcode def return_expr(self): """Returns the expression list Examples ======== >>> from sympy.parsing.sym_expr import SymPyExpression >>> src3 = ''' ... integer function f(a,b) ... integer, intent(in) :: a, b ... integer :: r ... r = a+b ... f = r ... end function ... ''' >>> p = SymPyExpression() >>> p.convert_to_expr(src3, 'f') >>> p.return_expr() [FunctionDefinition(integer, name=f, parameters=(Variable(a), Variable(b)), body=CodeBlock( Declaration(Variable(f, type=integer, value=0)), Declaration(Variable(r, type=integer, value=0)), Assignment(Variable(f), Variable(r)), Return(Variable(f)) ))] """ return self._expr sympy-sympy-1.9/sympy/parsing/sympy_parser.py000066400000000000000000001135051412543434000216630ustar00rootroot00000000000000"""Transform a string with Python-like source code into SymPy expression. """ from tokenize import (generate_tokens, untokenize, TokenError, NUMBER, STRING, NAME, OP, ENDMARKER, ERRORTOKEN, NEWLINE) from keyword import iskeyword import ast import unicodedata from io import StringIO from sympy.assumptions.ask import AssumptionKeys from sympy.core.compatibility import iterable from sympy.core.basic import Basic from sympy.core import Symbol from sympy.core.function import arity, Function from sympy.utilities.misc import filldedent, func_name def _token_splittable(token): """ Predicate for whether a token name can be split into multiple tokens. A token is splittable if it does not contain an underscore character and it is not the name of a Greek letter. This is used to implicitly convert expressions like 'xyz' into 'x*y*z'. """ if '_' in token: return False else: try: return not unicodedata.lookup('GREEK SMALL LETTER ' + token) except KeyError: pass if len(token) > 1: return True return False def _token_callable(token, local_dict, global_dict, nextToken=None): """ Predicate for whether a token name represents a callable function. Essentially wraps ``callable``, but looks up the token name in the locals and globals. """ func = local_dict.get(token[1]) if not func: func = global_dict.get(token[1]) return callable(func) and not isinstance(func, Symbol) def _add_factorial_tokens(name, result): if result == [] or result[-1][1] == '(': raise TokenError() beginning = [(NAME, name), (OP, '(')] end = [(OP, ')')] diff = 0 length = len(result) for index, token in enumerate(result[::-1]): toknum, tokval = token i = length - index - 1 if tokval == ')': diff += 1 elif tokval == '(': diff -= 1 if diff == 0: if i - 1 >= 0 and result[i - 1][0] == NAME: return result[:i - 1] + beginning + result[i - 1:] + end else: return result[:i] + beginning + result[i:] + end return result class AppliedFunction: """ A group of tokens representing a function and its arguments. `exponent` is for handling the shorthand sin^2, ln^2, etc. """ def __init__(self, function, args, exponent=None): if exponent is None: exponent = [] self.function = function self.args = args self.exponent = exponent self.items = ['function', 'args', 'exponent'] def expand(self): """Return a list of tokens representing the function""" result = [] result.append(self.function) result.extend(self.args) return result def __getitem__(self, index): return getattr(self, self.items[index]) def __repr__(self): return "AppliedFunction(%s, %s, %s)" % (self.function, self.args, self.exponent) class ParenthesisGroup(list): """List of tokens representing an expression in parentheses.""" pass def _flatten(result): result2 = [] for tok in result: if isinstance(tok, AppliedFunction): result2.extend(tok.expand()) else: result2.append(tok) return result2 def _group_parentheses(recursor): def _inner(tokens, local_dict, global_dict): """Group tokens between parentheses with ParenthesisGroup. Also processes those tokens recursively. """ result = [] stacks = [] stacklevel = 0 for token in tokens: if token[0] == OP: if token[1] == '(': stacks.append(ParenthesisGroup([])) stacklevel += 1 elif token[1] == ')': stacks[-1].append(token) stack = stacks.pop() if len(stacks) > 0: # We don't recurse here since the upper-level stack # would reprocess these tokens stacks[-1].extend(stack) else: # Recurse here to handle nested parentheses # Strip off the outer parentheses to avoid an infinite loop inner = stack[1:-1] inner = recursor(inner, local_dict, global_dict) parenGroup = [stack[0]] + inner + [stack[-1]] result.append(ParenthesisGroup(parenGroup)) stacklevel -= 1 continue if stacklevel: stacks[-1].append(token) else: result.append(token) if stacklevel: raise TokenError("Mismatched parentheses") return result return _inner def _apply_functions(tokens, local_dict, global_dict): """Convert a NAME token + ParenthesisGroup into an AppliedFunction. Note that ParenthesisGroups, if not applied to any function, are converted back into lists of tokens. """ result = [] symbol = None for tok in tokens: if tok[0] == NAME: symbol = tok result.append(tok) elif isinstance(tok, ParenthesisGroup): if symbol and _token_callable(symbol, local_dict, global_dict): result[-1] = AppliedFunction(symbol, tok) symbol = None else: result.extend(tok) else: symbol = None result.append(tok) return result def _implicit_multiplication(tokens, local_dict, global_dict): """Implicitly adds '*' tokens. Cases: - Two AppliedFunctions next to each other ("sin(x)cos(x)") - AppliedFunction next to an open parenthesis ("sin x (cos x + 1)") - A close parenthesis next to an AppliedFunction ("(x+2)sin x")\ - A close parenthesis next to an open parenthesis ("(x+2)(x+3)") - AppliedFunction next to an implicitly applied function ("sin(x)cos x") """ result = [] skip = False for tok, nextTok in zip(tokens, tokens[1:]): result.append(tok) if skip: skip = False continue if tok[0] == OP and tok[1] == '.' and nextTok[0] == NAME: # Dotted name. Do not do implicit multiplication skip = True continue if (isinstance(tok, AppliedFunction) and isinstance(nextTok, AppliedFunction)): result.append((OP, '*')) elif (isinstance(tok, AppliedFunction) and nextTok[0] == OP and nextTok[1] == '('): # Applied function followed by an open parenthesis if tok.function[1] == "Function": result[-1].function = (result[-1].function[0], 'Symbol') result.append((OP, '*')) elif (tok[0] == OP and tok[1] == ')' and isinstance(nextTok, AppliedFunction)): # Close parenthesis followed by an applied function result.append((OP, '*')) elif (tok[0] == OP and tok[1] == ')' and nextTok[0] == NAME): # Close parenthesis followed by an implicitly applied function result.append((OP, '*')) elif (tok[0] == nextTok[0] == OP and tok[1] == ')' and nextTok[1] == '('): # Close parenthesis followed by an open parenthesis result.append((OP, '*')) elif (isinstance(tok, AppliedFunction) and nextTok[0] == NAME): # Applied function followed by implicitly applied function result.append((OP, '*')) elif (tok[0] == NAME and not _token_callable(tok, local_dict, global_dict) and nextTok[0] == OP and nextTok[1] == '('): # Constant followed by parenthesis result.append((OP, '*')) elif (tok[0] == NAME and not _token_callable(tok, local_dict, global_dict) and nextTok[0] == NAME and not _token_callable(nextTok, local_dict, global_dict)): # Constant followed by constant result.append((OP, '*')) elif (tok[0] == NAME and not _token_callable(tok, local_dict, global_dict) and (isinstance(nextTok, AppliedFunction) or nextTok[0] == NAME)): # Constant followed by (implicitly applied) function result.append((OP, '*')) if tokens: result.append(tokens[-1]) return result def _implicit_application(tokens, local_dict, global_dict): """Adds parentheses as needed after functions.""" result = [] appendParen = 0 # number of closing parentheses to add skip = 0 # number of tokens to delay before adding a ')' (to # capture **, ^, etc.) exponentSkip = False # skipping tokens before inserting parentheses to # work with function exponentiation for tok, nextTok in zip(tokens, tokens[1:]): result.append(tok) if (tok[0] == NAME and nextTok[0] not in [OP, ENDMARKER, NEWLINE]): if _token_callable(tok, local_dict, global_dict, nextTok): result.append((OP, '(')) appendParen += 1 # name followed by exponent - function exponentiation elif (tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**'): if _token_callable(tok, local_dict, global_dict): exponentSkip = True elif exponentSkip: # if the last token added was an applied function (i.e. the # power of the function exponent) OR a multiplication (as # implicit multiplication would have added an extraneous # multiplication) if (isinstance(tok, AppliedFunction) or (tok[0] == OP and tok[1] == '*')): # don't add anything if the next token is a multiplication # or if there's already a parenthesis (if parenthesis, still # stop skipping tokens) if not (nextTok[0] == OP and nextTok[1] == '*'): if not(nextTok[0] == OP and nextTok[1] == '('): result.append((OP, '(')) appendParen += 1 exponentSkip = False elif appendParen: if nextTok[0] == OP and nextTok[1] in ('^', '**', '*'): skip = 1 continue if skip: skip -= 1 continue result.append((OP, ')')) appendParen -= 1 if tokens: result.append(tokens[-1]) if appendParen: result.extend([(OP, ')')] * appendParen) return result def function_exponentiation(tokens, local_dict, global_dict): """Allows functions to be exponentiated, e.g. ``cos**2(x)``. Examples ======== >>> from sympy.parsing.sympy_parser import (parse_expr, ... standard_transformations, function_exponentiation) >>> transformations = standard_transformations + (function_exponentiation,) >>> parse_expr('sin**4(x)', transformations=transformations) sin(x)**4 """ result = [] exponent = [] consuming_exponent = False level = 0 for tok, nextTok in zip(tokens, tokens[1:]): if tok[0] == NAME and nextTok[0] == OP and nextTok[1] == '**': if _token_callable(tok, local_dict, global_dict): consuming_exponent = True elif consuming_exponent: if tok[0] == NAME and tok[1] == 'Function': tok = (NAME, 'Symbol') exponent.append(tok) # only want to stop after hitting ) if tok[0] == nextTok[0] == OP and tok[1] == ')' and nextTok[1] == '(': consuming_exponent = False # if implicit multiplication was used, we may have )*( instead if tok[0] == nextTok[0] == OP and tok[1] == '*' and nextTok[1] == '(': consuming_exponent = False del exponent[-1] continue elif exponent and not consuming_exponent: if tok[0] == OP: if tok[1] == '(': level += 1 elif tok[1] == ')': level -= 1 if level == 0: result.append(tok) result.extend(exponent) exponent = [] continue result.append(tok) if tokens: result.append(tokens[-1]) if exponent: result.extend(exponent) return result def split_symbols_custom(predicate): """Creates a transformation that splits symbol names. ``predicate`` should return True if the symbol name is to be split. For instance, to retain the default behavior but avoid splitting certain symbol names, a predicate like this would work: >>> from sympy.parsing.sympy_parser import (parse_expr, _token_splittable, ... standard_transformations, implicit_multiplication, ... split_symbols_custom) >>> def can_split(symbol): ... if symbol not in ('list', 'of', 'unsplittable', 'names'): ... return _token_splittable(symbol) ... return False ... >>> transformation = split_symbols_custom(can_split) >>> parse_expr('unsplittable', transformations=standard_transformations + ... (transformation, implicit_multiplication)) unsplittable """ def _split_symbols(tokens, local_dict, global_dict): result = [] split = False split_previous=False for tok in tokens: if split_previous: # throw out closing parenthesis of Symbol that was split split_previous=False continue split_previous=False if tok[0] == NAME and tok[1] in ['Symbol', 'Function']: split = True elif split and tok[0] == NAME: symbol = tok[1][1:-1] if predicate(symbol): tok_type = result[-2][1] # Symbol or Function del result[-2:] # Get rid of the call to Symbol i = 0 while i < len(symbol): char = symbol[i] if char in local_dict or char in global_dict: result.extend([(NAME, "%s" % char)]) elif char.isdigit(): char = [char] for i in range(i + 1, len(symbol)): if not symbol[i].isdigit(): i -= 1 break char.append(symbol[i]) char = ''.join(char) result.extend([(NAME, 'Number'), (OP, '('), (NAME, "'%s'" % char), (OP, ')')]) else: use = tok_type if i == len(symbol) else 'Symbol' result.extend([(NAME, use), (OP, '('), (NAME, "'%s'" % char), (OP, ')')]) i += 1 # Set split_previous=True so will skip # the closing parenthesis of the original Symbol split = False split_previous = True continue else: split = False result.append(tok) return result return _split_symbols #: Splits symbol names for implicit multiplication. #: #: Intended to let expressions like ``xyz`` be parsed as ``x*y*z``. Does not #: split Greek character names, so ``theta`` will *not* become #: ``t*h*e*t*a``. Generally this should be used with #: ``implicit_multiplication``. split_symbols = split_symbols_custom(_token_splittable) def implicit_multiplication(result, local_dict, global_dict): """Makes the multiplication operator optional in most cases. Use this before :func:`implicit_application`, otherwise expressions like ``sin 2x`` will be parsed as ``x * sin(2)`` rather than ``sin(2*x)``. Examples ======== >>> from sympy.parsing.sympy_parser import (parse_expr, ... standard_transformations, implicit_multiplication) >>> transformations = standard_transformations + (implicit_multiplication,) >>> parse_expr('3 x y', transformations=transformations) 3*x*y """ # These are interdependent steps, so we don't expose them separately for step in (_group_parentheses(implicit_multiplication), _apply_functions, _implicit_multiplication): result = step(result, local_dict, global_dict) result = _flatten(result) return result def implicit_application(result, local_dict, global_dict): """Makes parentheses optional in some cases for function calls. Use this after :func:`implicit_multiplication`, otherwise expressions like ``sin 2x`` will be parsed as ``x * sin(2)`` rather than ``sin(2*x)``. Examples ======== >>> from sympy.parsing.sympy_parser import (parse_expr, ... standard_transformations, implicit_application) >>> transformations = standard_transformations + (implicit_application,) >>> parse_expr('cot z + csc z', transformations=transformations) cot(z) + csc(z) """ for step in (_group_parentheses(implicit_application), _apply_functions, _implicit_application,): result = step(result, local_dict, global_dict) result = _flatten(result) return result def implicit_multiplication_application(result, local_dict, global_dict): """Allows a slightly relaxed syntax. - Parentheses for single-argument method calls are optional. - Multiplication is implicit. - Symbol names can be split (i.e. spaces are not needed between symbols). - Functions can be exponentiated. Examples ======== >>> from sympy.parsing.sympy_parser import (parse_expr, ... standard_transformations, implicit_multiplication_application) >>> parse_expr("10sin**2 x**2 + 3xyz + tan theta", ... transformations=(standard_transformations + ... (implicit_multiplication_application,))) 3*x*y*z + 10*sin(x**2)**2 + tan(theta) """ for step in (split_symbols, implicit_multiplication, implicit_application, function_exponentiation): result = step(result, local_dict, global_dict) return result def auto_symbol(tokens, local_dict, global_dict): """Inserts calls to ``Symbol``/``Function`` for undefined variables.""" result = [] prevTok = (None, None) tokens.append((None, None)) # so zip traverses all tokens for tok, nextTok in zip(tokens, tokens[1:]): tokNum, tokVal = tok nextTokNum, nextTokVal = nextTok if tokNum == NAME: name = tokVal if (name in ['True', 'False', 'None'] or iskeyword(name) # Don't convert attribute access or (prevTok[0] == OP and prevTok[1] == '.') # Don't convert keyword arguments or (prevTok[0] == OP and prevTok[1] in ('(', ',') and nextTokNum == OP and nextTokVal == '=') # the name has already been defined or name in local_dict and local_dict[name] is not None): result.append((NAME, name)) continue elif name in local_dict: local_dict.setdefault(None, set()).add(name) if nextTokVal == '(': local_dict[name] = Function(name) else: local_dict[name] = Symbol(name) result.append((NAME, name)) continue elif name in global_dict: obj = global_dict[name] if isinstance(obj, (AssumptionKeys, Basic, type)) or callable(obj): result.append((NAME, name)) continue result.extend([ (NAME, 'Symbol' if nextTokVal != '(' else 'Function'), (OP, '('), (NAME, repr(str(name))), (OP, ')'), ]) else: result.append((tokNum, tokVal)) prevTok = (tokNum, tokVal) return result def lambda_notation(tokens, local_dict, global_dict): """Substitutes "lambda" with its Sympy equivalent Lambda(). However, the conversion doesn't take place if only "lambda" is passed because that is a syntax error. """ result = [] flag = False toknum, tokval = tokens[0] tokLen = len(tokens) if toknum == NAME and tokval == 'lambda': if tokLen == 2 or tokLen == 3 and tokens[1][0] == NEWLINE: # In Python 3.6.7+, inputs without a newline get NEWLINE added to # the tokens result.extend(tokens) elif tokLen > 2: result.extend([ (NAME, 'Lambda'), (OP, '('), (OP, '('), (OP, ')'), (OP, ')'), ]) for tokNum, tokVal in tokens[1:]: if tokNum == OP and tokVal == ':': tokVal = ',' flag = True if not flag and tokNum == OP and tokVal in ['*', '**']: raise TokenError("Starred arguments in lambda not supported") if flag: result.insert(-1, (tokNum, tokVal)) else: result.insert(-2, (tokNum, tokVal)) else: result.extend(tokens) return result def factorial_notation(tokens, local_dict, global_dict): """Allows standard notation for factorial.""" result = [] nfactorial = 0 for toknum, tokval in tokens: if toknum == ERRORTOKEN: op = tokval if op == '!': nfactorial += 1 else: nfactorial = 0 result.append((OP, op)) else: if nfactorial == 1: result = _add_factorial_tokens('factorial', result) elif nfactorial == 2: result = _add_factorial_tokens('factorial2', result) elif nfactorial > 2: raise TokenError nfactorial = 0 result.append((toknum, tokval)) return result def convert_xor(tokens, local_dict, global_dict): """Treats XOR, ``^``, as exponentiation, ``**``.""" result = [] for toknum, tokval in tokens: if toknum == OP: if tokval == '^': result.append((OP, '**')) else: result.append((toknum, tokval)) else: result.append((toknum, tokval)) return result def repeated_decimals(tokens, local_dict, global_dict): """ Allows 0.2[1] notation to represent the repeated decimal 0.2111... (19/90) Run this before auto_number. """ result = [] def is_digit(s): return all(i in '0123456789_' for i in s) # num will running match any DECIMAL [ INTEGER ] num = [] for toknum, tokval in tokens: if toknum == NUMBER: if (not num and '.' in tokval and 'e' not in tokval.lower() and 'j' not in tokval.lower()): num.append((toknum, tokval)) elif is_digit(tokval)and len(num) == 2: num.append((toknum, tokval)) elif is_digit(tokval) and len(num) == 3 and is_digit(num[-1][1]): # Python 2 tokenizes 00123 as '00', '123' # Python 3 tokenizes 01289 as '012', '89' num.append((toknum, tokval)) else: num = [] elif toknum == OP: if tokval == '[' and len(num) == 1: num.append((OP, tokval)) elif tokval == ']' and len(num) >= 3: num.append((OP, tokval)) elif tokval == '.' and not num: # handle .[1] num.append((NUMBER, '0.')) else: num = [] else: num = [] result.append((toknum, tokval)) if num and num[-1][1] == ']': # pre.post[repetend] = a + b/c + d/e where a = pre, b/c = post, # and d/e = repetend result = result[:-len(num)] pre, post = num[0][1].split('.') repetend = num[2][1] if len(num) == 5: repetend += num[3][1] pre = pre.replace('_', '') post = post.replace('_', '') repetend = repetend.replace('_', '') zeros = '0'*len(post) post, repetends = [w.lstrip('0') for w in [post, repetend]] # or else interpreted as octal a = pre or '0' b, c = post or '0', '1' + zeros d, e = repetends, ('9'*len(repetend)) + zeros seq = [ (OP, '('), (NAME, 'Integer'), (OP, '('), (NUMBER, a), (OP, ')'), (OP, '+'), (NAME, 'Rational'), (OP, '('), (NUMBER, b), (OP, ','), (NUMBER, c), (OP, ')'), (OP, '+'), (NAME, 'Rational'), (OP, '('), (NUMBER, d), (OP, ','), (NUMBER, e), (OP, ')'), (OP, ')'), ] result.extend(seq) num = [] return result def auto_number(tokens, local_dict, global_dict): """ Converts numeric literals to use SymPy equivalents. Complex numbers use ``I``, integer literals use ``Integer``, and float literals use ``Float``. """ result = [] for toknum, tokval in tokens: if toknum == NUMBER: number = tokval postfix = [] if number.endswith('j') or number.endswith('J'): number = number[:-1] postfix = [(OP, '*'), (NAME, 'I')] if '.' in number or (('e' in number or 'E' in number) and not (number.startswith('0x') or number.startswith('0X'))): seq = [(NAME, 'Float'), (OP, '('), (NUMBER, repr(str(number))), (OP, ')')] else: seq = [(NAME, 'Integer'), (OP, '('), ( NUMBER, number), (OP, ')')] result.extend(seq + postfix) else: result.append((toknum, tokval)) return result def rationalize(tokens, local_dict, global_dict): """Converts floats into ``Rational``. Run AFTER ``auto_number``.""" result = [] passed_float = False for toknum, tokval in tokens: if toknum == NAME: if tokval == 'Float': passed_float = True tokval = 'Rational' result.append((toknum, tokval)) elif passed_float == True and toknum == NUMBER: passed_float = False result.append((STRING, tokval)) else: result.append((toknum, tokval)) return result def _transform_equals_sign(tokens, local_dict, global_dict): """Transforms the equals sign ``=`` to instances of Eq. This is a helper function for `convert_equals_signs`. Works with expressions containing one equals sign and no nesting. Expressions like `(1=2)=False` won't work with this and should be used with `convert_equals_signs`. Examples: 1=2 to Eq(1,2) 1*2=x to Eq(1*2, x) This does not deal with function arguments yet. """ result = [] if (OP, "=") in tokens: result.append((NAME, "Eq")) result.append((OP, "(")) for index, token in enumerate(tokens): if token == (OP, "="): result.append((OP, ",")) continue result.append(token) result.append((OP, ")")) else: result = tokens return result def convert_equals_signs(result, local_dict, global_dict): """ Transforms all the equals signs ``=`` to instances of Eq. Parses the equals signs in the expression and replaces them with appropriate Eq instances.Also works with nested equals signs. Does not yet play well with function arguments. For example, the expression `(x=y)` is ambiguous and can be interpreted as x being an argument to a function and `convert_equals_signs` won't work for this. See also ======== convert_equality_operators Examples ======== >>> from sympy.parsing.sympy_parser import (parse_expr, ... standard_transformations, convert_equals_signs) >>> parse_expr("1*2=x", transformations=( ... standard_transformations + (convert_equals_signs,))) Eq(2, x) >>> parse_expr("(1*2=x)=False", transformations=( ... standard_transformations + (convert_equals_signs,))) Eq(Eq(2, x), False) """ for step in (_group_parentheses(convert_equals_signs), _apply_functions, _transform_equals_sign): result = step(result, local_dict, global_dict) result = _flatten(result) return result #: Standard transformations for :func:`parse_expr`. #: Inserts calls to :class:`~.Symbol`, :class:`~.Integer`, and other SymPy #: datatypes and allows the use of standard factorial notation (e.g. ``x!``). standard_transformations = (lambda_notation, auto_symbol, repeated_decimals, auto_number, factorial_notation) def stringify_expr(s, local_dict, global_dict, transformations): """ Converts the string ``s`` to Python code, in ``local_dict`` Generally, ``parse_expr`` should be used. """ tokens = [] input_code = StringIO(s.strip()) for toknum, tokval, _, _, _ in generate_tokens(input_code.readline): tokens.append((toknum, tokval)) for transform in transformations: tokens = transform(tokens, local_dict, global_dict) return untokenize(tokens) def eval_expr(code, local_dict, global_dict): """ Evaluate Python code generated by ``stringify_expr``. Generally, ``parse_expr`` should be used. """ expr = eval( code, global_dict, local_dict) # take local objects in preference return expr def parse_expr(s, local_dict=None, transformations=standard_transformations, global_dict=None, evaluate=True): """Converts the string ``s`` to a SymPy expression, in ``local_dict`` Parameters ========== s : str The string to parse. local_dict : dict, optional A dictionary of local variables to use when parsing. global_dict : dict, optional A dictionary of global variables. By default, this is initialized with ``from sympy import *``; provide this parameter to override this behavior (for instance, to parse ``"Q & S"``). transformations : tuple, optional A tuple of transformation functions used to modify the tokens of the parsed expression before evaluation. The default transformations convert numeric literals into their SymPy equivalents, convert undefined variables into SymPy symbols, and allow the use of standard mathematical factorial notation (e.g. ``x!``). evaluate : bool, optional When False, the order of the arguments will remain as they were in the string and automatic simplification that would normally occur is suppressed. (see examples) Examples ======== >>> from sympy.parsing.sympy_parser import parse_expr >>> parse_expr("1/2") 1/2 >>> type(_) >>> from sympy.parsing.sympy_parser import standard_transformations,\\ ... implicit_multiplication_application >>> transformations = (standard_transformations + ... (implicit_multiplication_application,)) >>> parse_expr("2x", transformations=transformations) 2*x When evaluate=False, some automatic simplifications will not occur: >>> parse_expr("2**3"), parse_expr("2**3", evaluate=False) (8, 2**3) In addition the order of the arguments will not be made canonical. This feature allows one to tell exactly how the expression was entered: >>> a = parse_expr('1 + x', evaluate=False) >>> b = parse_expr('x + 1', evaluate=0) >>> a == b False >>> a.args (1, x) >>> b.args (x, 1) See Also ======== stringify_expr, eval_expr, standard_transformations, implicit_multiplication_application """ if local_dict is None: local_dict = {} elif not isinstance(local_dict, dict): raise TypeError('expecting local_dict to be a dict') if global_dict is None: global_dict = {} exec('from sympy import *', global_dict) elif not isinstance(global_dict, dict): raise TypeError('expecting global_dict to be a dict') transformations = transformations or () if transformations: if not iterable(transformations): raise TypeError( '`transformations` should be a list of functions.') for _ in transformations: if not callable(_): raise TypeError(filldedent(''' expected a function in `transformations`, not %s''' % func_name(_))) if arity(_) != 3: raise TypeError(filldedent(''' a transformation should be function that takes 3 arguments''')) code = stringify_expr(s, local_dict, global_dict, transformations) if not evaluate: code = compile(evaluateFalse(code), '', 'eval') try: rv = eval_expr(code, local_dict, global_dict) # restore neutral definitions for names for i in local_dict.pop(None, ()): local_dict[i] = None return rv except Exception as e: # restore neutral definitions for names for i in local_dict.pop(None, ()): local_dict[i] = None raise e from ValueError(f"Error from parse_expr with transformed code: {code!r}") def evaluateFalse(s): """ Replaces operators with the SymPy equivalent and sets evaluate=False. """ node = ast.parse(s) node = EvaluateFalseTransformer().visit(node) # node is a Module, we want an Expression node = ast.Expression(node.body[0].value) return ast.fix_missing_locations(node) class EvaluateFalseTransformer(ast.NodeTransformer): operators = { ast.Add: 'Add', ast.Mult: 'Mul', ast.Pow: 'Pow', ast.Sub: 'Add', ast.Div: 'Mul', ast.BitOr: 'Or', ast.BitAnd: 'And', ast.BitXor: 'Not', } functions = ( 'Abs', 'im', 're', 'sign', 'arg', 'conjugate', 'acos', 'acot', 'acsc', 'asec', 'asin', 'atan', 'acosh', 'acoth', 'acsch', 'asech', 'asinh', 'atanh', 'cos', 'cot', 'csc', 'sec', 'sin', 'tan', 'cosh', 'coth', 'csch', 'sech', 'sinh', 'tanh', 'exp', 'ln', 'log', 'sqrt', 'cbrt', ) def flatten(self, args, func): result = [] for arg in args: if isinstance(arg, ast.Call): arg_func = arg.func if isinstance(arg_func, ast.Call): arg_func = arg_func.func if arg_func.id == func: result.extend(self.flatten(arg.args, func)) else: result.append(arg) else: result.append(arg) return result def visit_BinOp(self, node): if node.op.__class__ in self.operators: sympy_class = self.operators[node.op.__class__] right = self.visit(node.right) left = self.visit(node.left) rev = False if isinstance(node.op, ast.Sub): right = ast.Call( func=ast.Name(id='Mul', ctx=ast.Load()), args=[ast.UnaryOp(op=ast.USub(), operand=ast.Num(1)), right], keywords=[ast.keyword(arg='evaluate', value=ast.NameConstant(value=False, ctx=ast.Load()))], starargs=None, kwargs=None ) elif isinstance(node.op, ast.Div): if isinstance(node.left, ast.UnaryOp): left, right = right, left rev = True left = ast.Call( func=ast.Name(id='Pow', ctx=ast.Load()), args=[left, ast.UnaryOp(op=ast.USub(), operand=ast.Num(1))], keywords=[ast.keyword(arg='evaluate', value=ast.NameConstant(value=False, ctx=ast.Load()))], starargs=None, kwargs=None ) else: right = ast.Call( func=ast.Name(id='Pow', ctx=ast.Load()), args=[right, ast.UnaryOp(op=ast.USub(), operand=ast.Num(1))], keywords=[ast.keyword(arg='evaluate', value=ast.NameConstant(value=False, ctx=ast.Load()))], starargs=None, kwargs=None ) if rev: # undo reversal left, right = right, left new_node = ast.Call( func=ast.Name(id=sympy_class, ctx=ast.Load()), args=[left, right], keywords=[ast.keyword(arg='evaluate', value=ast.NameConstant(value=False, ctx=ast.Load()))], starargs=None, kwargs=None ) if sympy_class in ('Add', 'Mul'): # Denest Add or Mul as appropriate new_node.args = self.flatten(new_node.args, sympy_class) return new_node return node def visit_Call(self, node): new_node = self.generic_visit(node) if isinstance(node.func, ast.Name) and node.func.id in self.functions: new_node.keywords.append(ast.keyword(arg='evaluate', value=ast.NameConstant(value=False, ctx=ast.Load()))) return new_node sympy-sympy-1.9/sympy/parsing/tests/000077500000000000000000000000001412543434000177115ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/tests/__init__.py000066400000000000000000000000001412543434000220100ustar00rootroot00000000000000sympy-sympy-1.9/sympy/parsing/tests/test_ast_parser.py000066400000000000000000000010531412543434000234640ustar00rootroot00000000000000from sympy import symbols, S from sympy.parsing.ast_parser import parse_expr from sympy.testing.pytest import raises from sympy.core.sympify import SympifyError def test_parse_expr(): a, b = symbols('a, b') # tests issue_16393 parse_expr('a + b', {}) == a + b raises(SympifyError, lambda: parse_expr('a + ', {})) # tests Transform.visit_Num parse_expr('1 + 2', {}) == S(3) parse_expr('1 + 2.0', {}) == S(3.0) # tests Transform.visit_Name parse_expr('Rational(1, 2)', {}) == S(1)/2 parse_expr('a', {'a': a}) == a sympy-sympy-1.9/sympy/parsing/tests/test_autolev.py000066400000000000000000000147221412543434000230070ustar00rootroot00000000000000import os from sympy import sin, cos from sympy.external import import_module from sympy.testing.pytest import skip from sympy.parsing.autolev import parse_autolev antlr4 = import_module("antlr4") if not antlr4: disabled = True FILE_DIR = os.path.dirname( os.path.dirname(os.path.abspath(os.path.realpath(__file__)))) def _test_examples(in_filename, out_filename, test_name=""): in_file_path = os.path.join(FILE_DIR, 'autolev', 'test-examples', in_filename) correct_file_path = os.path.join(FILE_DIR, 'autolev', 'test-examples', out_filename) with open(in_file_path) as f: generated_code = parse_autolev(f, include_numeric=True) with open(correct_file_path) as f: for idx, line1 in enumerate(f): if line1.startswith("#"): break try: line2 = generated_code.split('\n')[idx] assert line1.rstrip() == line2.rstrip() except Exception: msg = 'mismatch in ' + test_name + ' in line no: {0}' raise AssertionError(msg.format(idx+1)) def test_rule_tests(): l = ["ruletest1", "ruletest2", "ruletest3", "ruletest4", "ruletest5", "ruletest6", "ruletest7", "ruletest8", "ruletest9", "ruletest10", "ruletest11", "ruletest12"] for i in l: in_filepath = i + ".al" out_filepath = i + ".py" _test_examples(in_filepath, out_filepath, i) def test_pydy_examples(): l = ["mass_spring_damper", "chaos_pendulum", "double_pendulum", "non_min_pendulum"] for i in l: in_filepath = os.path.join("pydy-example-repo", i + ".al") out_filepath = os.path.join("pydy-example-repo", i + ".py") _test_examples(in_filepath, out_filepath, i) def test_autolev_tutorial(): dir_path = os.path.join(FILE_DIR, 'autolev', 'test-examples', 'autolev-tutorial') if os.path.isdir(dir_path): l = ["tutor1", "tutor2", "tutor3", "tutor4", "tutor5", "tutor6", "tutor7"] for i in l: in_filepath = os.path.join("autolev-tutorial", i + ".al") out_filepath = os.path.join("autolev-tutorial", i + ".py") _test_examples(in_filepath, out_filepath, i) def test_dynamics_online(): dir_path = os.path.join(FILE_DIR, 'autolev', 'test-examples', 'dynamics-online') if os.path.isdir(dir_path): ch1 = ["1-4", "1-5", "1-6", "1-7", "1-8", "1-9_1", "1-9_2", "1-9_3"] ch2 = ["2-1", "2-2", "2-3", "2-4", "2-5", "2-6", "2-7", "2-8", "2-9", "circular"] ch3 = ["3-1_1", "3-1_2", "3-2_1", "3-2_2", "3-2_3", "3-2_4", "3-2_5", "3-3"] ch4 = ["4-1_1", "4-2_1", "4-4_1", "4-4_2", "4-5_1", "4-5_2"] chapters = [(ch1, "ch1"), (ch2, "ch2"), (ch3, "ch3"), (ch4, "ch4")] for ch, name in chapters: for i in ch: in_filepath = os.path.join("dynamics-online", name, i + ".al") out_filepath = os.path.join("dynamics-online", name, i + ".py") _test_examples(in_filepath, out_filepath, i) def test_output_01(): """Autolev example calculates the position, velocity, and acceleration of a point and expresses in a single reference frame:: (1) FRAMES C,D,F (2) VARIABLES FD'',DC'' (3) CONSTANTS R,L (4) POINTS O,E (5) SIMPROT(F,D,1,FD) -> (6) F_D = [1, 0, 0; 0, COS(FD), -SIN(FD); 0, SIN(FD), COS(FD)] (7) SIMPROT(D,C,2,DC) -> (8) D_C = [COS(DC), 0, SIN(DC); 0, 1, 0; -SIN(DC), 0, COS(DC)] (9) W_C_F> = EXPRESS(W_C_F>, F) -> (10) W_C_F> = FD'*F1> + COS(FD)*DC'*F2> + SIN(FD)*DC'*F3> (11) P_O_E>=R*D2>-L*C1> (12) P_O_E>=EXPRESS(P_O_E>, D) -> (13) P_O_E> = -L*COS(DC)*D1> + R*D2> + L*SIN(DC)*D3> (14) V_E_F>=EXPRESS(DT(P_O_E>,F),D) -> (15) V_E_F> = L*SIN(DC)*DC'*D1> - L*SIN(DC)*FD'*D2> + (R*FD'+L*COS(DC)*DC')*D3> (16) A_E_F>=EXPRESS(DT(V_E_F>,F),D) -> (17) A_E_F> = L*(COS(DC)*DC'^2+SIN(DC)*DC'')*D1> + (-R*FD'^2-2*L*COS(DC)*DC'*FD'-L*SIN(DC)*FD'')*D2> + (R*FD''+L*COS(DC)*DC''-L*SIN(DC)*DC'^2-L*SIN(DC)*FD'^2)*D3> """ if not antlr4: skip('Test skipped: antlr4 is not installed.') autolev_input = """\ FRAMES C,D,F VARIABLES FD'',DC'' CONSTANTS R,L POINTS O,E SIMPROT(F,D,1,FD) SIMPROT(D,C,2,DC) W_C_F>=EXPRESS(W_C_F>,F) P_O_E>=R*D2>-L*C1> P_O_E>=EXPRESS(P_O_E>,D) V_E_F>=EXPRESS(DT(P_O_E>,F),D) A_E_F>=EXPRESS(DT(V_E_F>,F),D)\ """ sympy_input = parse_autolev(autolev_input) g = {} l = {} exec(sympy_input, g, l) w_c_f = l['frame_c'].ang_vel_in(l['frame_f']) # P_O_E> means "the position of point E wrt to point O" p_o_e = l['point_e'].pos_from(l['point_o']) v_e_f = l['point_e'].vel(l['frame_f']) a_e_f = l['point_e'].acc(l['frame_f']) # NOTE : The Autolev outputs above were manually transformed into # equivalent SymPy physics vector expressions. Would be nice to automate # this transformation. expected_w_c_f = (l['fd'].diff()*l['frame_f'].x + cos(l['fd'])*l['dc'].diff()*l['frame_f'].y + sin(l['fd'])*l['dc'].diff()*l['frame_f'].z) assert (w_c_f - expected_w_c_f).simplify() == 0 expected_p_o_e = (-l['l']*cos(l['dc'])*l['frame_d'].x + l['r']*l['frame_d'].y + l['l']*sin(l['dc'])*l['frame_d'].z) assert (p_o_e - expected_p_o_e).simplify() == 0 expected_v_e_f = (l['l']*sin(l['dc'])*l['dc'].diff()*l['frame_d'].x - l['l']*sin(l['dc'])*l['fd'].diff()*l['frame_d'].y + (l['r']*l['fd'].diff() + l['l']*cos(l['dc'])*l['dc'].diff())*l['frame_d'].z) assert (v_e_f - expected_v_e_f).simplify() == 0 expected_a_e_f = (l['l']*(cos(l['dc'])*l['dc'].diff()**2 + sin(l['dc'])*l['dc'].diff().diff())*l['frame_d'].x + (-l['r']*l['fd'].diff()**2 - 2*l['l']*cos(l['dc'])*l['dc'].diff()*l['fd'].diff() - l['l']*sin(l['dc'])*l['fd'].diff().diff())*l['frame_d'].y + (l['r']*l['fd'].diff().diff() + l['l']*cos(l['dc'])*l['dc'].diff().diff() - l['l']*sin(l['dc'])*l['dc'].diff()**2 - l['l']*sin(l['dc'])*l['fd'].diff()**2)*l['frame_d'].z) assert (a_e_f - expected_a_e_f).simplify() == 0 sympy-sympy-1.9/sympy/parsing/tests/test_c_parser.py000066400000000000000000004557701412543434000231420ustar00rootroot00000000000000from sympy.parsing.sym_expr import SymPyExpression from sympy.testing.pytest import raises, XFAIL from sympy.external import import_module cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) if cin: from sympy.codegen.ast import (Variable, String, Return, FunctionDefinition, Integer, Float, Declaration, CodeBlock, FunctionPrototype, FunctionCall, NoneToken, Assignment, Type, IntBaseType, SignedIntType, UnsignedIntType, FloatType, AddAugmentedAssignment, SubAugmentedAssignment, MulAugmentedAssignment, DivAugmentedAssignment, ModAugmentedAssignment, While) from sympy.codegen.cnodes import (PreDecrement, PostDecrement, PreIncrement, PostIncrement) from sympy.core import (Add, Mul, Mod, Pow, Rational, StrictLessThan, LessThan, StrictGreaterThan, GreaterThan, Equality, Unequality) from sympy.logic.boolalg import And, Not, Or from sympy import Symbol, true, false import os def test_variable(): c_src1 = ( 'int a;' + '\n' + 'int b;' + '\n' ) c_src2 = ( 'float a;' + '\n' + 'float b;' + '\n' ) c_src3 = ( 'int a;' + '\n' + 'float b;' + '\n' + 'int c;' ) c_src4 = ( 'int x = 1, y = 6.78;' + '\n' + 'float p = 2, q = 9.67;' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() assert res1[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ) assert res1[1] == Declaration( Variable( Symbol('b'), type=IntBaseType(String('intc')) ) ) assert res2[0] == Declaration( Variable( Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ) assert res2[1] == Declaration( Variable( Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ) assert res3[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ) assert res3[1] == Declaration( Variable( Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ) assert res3[2] == Declaration( Variable( Symbol('c'), type=IntBaseType(String('intc')) ) ) assert res4[0] == Declaration( Variable( Symbol('x'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res4[1] == Declaration( Variable( Symbol('y'), type=IntBaseType(String('intc')), value=Integer(6) ) ) assert res4[2] == Declaration( Variable( Symbol('p'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.0', precision=53) ) ) assert res4[3] == Declaration( Variable( Symbol('q'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('9.67', precision=53) ) ) @XFAIL def test_int(): c_src1 = 'int a = 1;' c_src2 = ( 'int a = 1;' + '\n' + 'int b = 2;' + '\n' ) c_src3 = 'int a = 2.345, b = 5.67;' c_src4 = 'int p = 6, q = 23.45;' c_src5 = "int x = '0', y = 'a';" c_src6 = "int r = true, s = false;" # cin.TypeKind.UCHAR c_src_type1 = ( "signed char a = 1, b = 5.1;" ) # cin.TypeKind.SHORT c_src_type2 = ( "short a = 1, b = 5.1;" "signed short c = 1, d = 5.1;" "short int e = 1, f = 5.1;" "signed short int g = 1, h = 5.1;" ) # cin.TypeKind.INT c_src_type3 = ( "signed int a = 1, b = 5.1;" "int c = 1, d = 5.1;" ) # cin.TypeKind.LONG c_src_type4 = ( "long a = 1, b = 5.1;" "long int c = 1, d = 5.1;" ) # cin.TypeKind.UCHAR c_src_type5 = "unsigned char a = 1, b = 5.1;" # cin.TypeKind.USHORT c_src_type6 = ( "unsigned short a = 1, b = 5.1;" "unsigned short int c = 1, d = 5.1;" ) # cin.TypeKind.UINT c_src_type7 = "unsigned int a = 1, b = 5.1;" # cin.TypeKind.ULONG c_src_type8 = ( "unsigned long a = 1, b = 5.1;" "unsigned long int c = 1, d = 5.1;" ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() res5 = SymPyExpression(c_src5, 'c').return_expr() res6 = SymPyExpression(c_src6, 'c').return_expr() res_type1 = SymPyExpression(c_src_type1, 'c').return_expr() res_type2 = SymPyExpression(c_src_type2, 'c').return_expr() res_type3 = SymPyExpression(c_src_type3, 'c').return_expr() res_type4 = SymPyExpression(c_src_type4, 'c').return_expr() res_type5 = SymPyExpression(c_src_type5, 'c').return_expr() res_type6 = SymPyExpression(c_src_type6, 'c').return_expr() res_type7 = SymPyExpression(c_src_type7, 'c').return_expr() res_type8 = SymPyExpression(c_src_type8, 'c').return_expr() assert res1[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res2[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res2[1] == Declaration( Variable( Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res3[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res3[1] == Declaration( Variable( Symbol('b'), type=IntBaseType(String('intc')), value=Integer(5) ) ) assert res4[0] == Declaration( Variable( Symbol('p'), type=IntBaseType(String('intc')), value=Integer(6) ) ) assert res4[1] == Declaration( Variable( Symbol('q'), type=IntBaseType(String('intc')), value=Integer(23) ) ) assert res5[0] == Declaration( Variable( Symbol('x'), type=IntBaseType(String('intc')), value=Integer(48) ) ) assert res5[1] == Declaration( Variable( Symbol('y'), type=IntBaseType(String('intc')), value=Integer(97) ) ) assert res6[0] == Declaration( Variable( Symbol('r'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res6[1] == Declaration( Variable( Symbol('s'), type=IntBaseType(String('intc')), value=Integer(0) ) ) assert res_type1[0] == Declaration( Variable( Symbol('a'), type=SignedIntType( String('int8'), nbits=Integer(8) ), value=Integer(1) ) ) assert res_type1[1] == Declaration( Variable( Symbol('b'), type=SignedIntType( String('int8'), nbits=Integer(8) ), value=Integer(5) ) ) assert res_type2[0] == Declaration( Variable( Symbol('a'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(1) ) ) assert res_type2[1] == Declaration( Variable( Symbol('b'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(5) ) ) assert res_type2[2] == Declaration( Variable(Symbol('c'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(1) ) ) assert res_type2[3] == Declaration( Variable( Symbol('d'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(5) ) ) assert res_type2[4] == Declaration( Variable( Symbol('e'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(1) ) ) assert res_type2[5] == Declaration( Variable( Symbol('f'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(5) ) ) assert res_type2[6] == Declaration( Variable( Symbol('g'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(1) ) ) assert res_type2[7] == Declaration( Variable( Symbol('h'), type=SignedIntType( String('int16'), nbits=Integer(16) ), value=Integer(5) ) ) assert res_type3[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res_type3[1] == Declaration( Variable( Symbol('b'), type=IntBaseType(String('intc')), value=Integer(5) ) ) assert res_type3[2] == Declaration( Variable( Symbol('c'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res_type3[3] == Declaration( Variable( Symbol('d'), type=IntBaseType(String('intc')), value=Integer(5) ) ) assert res_type4[0] == Declaration( Variable( Symbol('a'), type=SignedIntType( String('int64'), nbits=Integer(64) ), value=Integer(1) ) ) assert res_type4[1] == Declaration( Variable( Symbol('b'), type=SignedIntType( String('int64'), nbits=Integer(64) ), value=Integer(5) ) ) assert res_type4[2] == Declaration( Variable( Symbol('c'), type=SignedIntType( String('int64'), nbits=Integer(64) ), value=Integer(1) ) ) assert res_type4[3] == Declaration( Variable( Symbol('d'), type=SignedIntType( String('int64'), nbits=Integer(64) ), value=Integer(5) ) ) assert res_type5[0] == Declaration( Variable( Symbol('a'), type=UnsignedIntType( String('uint8'), nbits=Integer(8) ), value=Integer(1) ) ) assert res_type5[1] == Declaration( Variable( Symbol('b'), type=UnsignedIntType( String('uint8'), nbits=Integer(8) ), value=Integer(5) ) ) assert res_type6[0] == Declaration( Variable( Symbol('a'), type=UnsignedIntType( String('uint16'), nbits=Integer(16) ), value=Integer(1) ) ) assert res_type6[1] == Declaration( Variable( Symbol('b'), type=UnsignedIntType( String('uint16'), nbits=Integer(16) ), value=Integer(5) ) ) assert res_type6[2] == Declaration( Variable( Symbol('c'), type=UnsignedIntType( String('uint16'), nbits=Integer(16) ), value=Integer(1) ) ) assert res_type6[3] == Declaration( Variable( Symbol('d'), type=UnsignedIntType( String('uint16'), nbits=Integer(16) ), value=Integer(5) ) ) assert res_type7[0] == Declaration( Variable( Symbol('a'), type=UnsignedIntType( String('uint32'), nbits=Integer(32) ), value=Integer(1) ) ) assert res_type7[1] == Declaration( Variable( Symbol('b'), type=UnsignedIntType( String('uint32'), nbits=Integer(32) ), value=Integer(5) ) ) assert res_type8[0] == Declaration( Variable( Symbol('a'), type=UnsignedIntType( String('uint64'), nbits=Integer(64) ), value=Integer(1) ) ) assert res_type8[1] == Declaration( Variable( Symbol('b'), type=UnsignedIntType( String('uint64'), nbits=Integer(64) ), value=Integer(5) ) ) assert res_type8[2] == Declaration( Variable( Symbol('c'), type=UnsignedIntType( String('uint64'), nbits=Integer(64) ), value=Integer(1) ) ) assert res_type8[3] == Declaration( Variable( Symbol('d'), type=UnsignedIntType( String('uint64'), nbits=Integer(64) ), value=Integer(5) ) ) @XFAIL def test_float(): c_src1 = 'float a = 1.0;' c_src2 = ( 'float a = 1.25;' + '\n' + 'float b = 2.39;' + '\n' ) c_src3 = 'float x = 1, y = 2;' c_src4 = 'float p = 5, e = 7.89;' c_src5 = 'float r = true, s = false;' # cin.TypeKind.FLOAT c_src_type1 = 'float x = 1, y = 2.5;' # cin.TypeKind.DOUBLE c_src_type2 = 'double x = 1, y = 2.5;' # cin.TypeKind.LONGDOUBLE c_src_type3 = 'long double x = 1, y = 2.5;' res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() res5 = SymPyExpression(c_src5, 'c').return_expr() res_type1 = SymPyExpression(c_src_type1, 'c').return_expr() res_type2 = SymPyExpression(c_src_type2, 'c').return_expr() res_type3 = SymPyExpression(c_src_type3, 'c').return_expr() assert res1[0] == Declaration( Variable( Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.0', precision=53) ) ) assert res2[0] == Declaration( Variable( Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.25', precision=53) ) ) assert res2[1] == Declaration( Variable( Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.3900000000000001', precision=53) ) ) assert res3[0] == Declaration( Variable( Symbol('x'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.0', precision=53) ) ) assert res3[1] == Declaration( Variable( Symbol('y'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.0', precision=53) ) ) assert res4[0] == Declaration( Variable( Symbol('p'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('5.0', precision=53) ) ) assert res4[1] == Declaration( Variable( Symbol('e'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('7.89', precision=53) ) ) assert res5[0] == Declaration( Variable( Symbol('r'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.0', precision=53) ) ) assert res5[1] == Declaration( Variable( Symbol('s'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('0.0', precision=53) ) ) assert res_type1[0] == Declaration( Variable( Symbol('x'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.0', precision=53) ) ) assert res_type1[1] == Declaration( Variable( Symbol('y'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.5', precision=53) ) ) assert res_type2[0] == Declaration( Variable( Symbol('x'), type=FloatType( String('float64'), nbits=Integer(64), nmant=Integer(52), nexp=Integer(11) ), value=Float('1.0', precision=53) ) ) assert res_type2[1] == Declaration( Variable( Symbol('y'), type=FloatType( String('float64'), nbits=Integer(64), nmant=Integer(52), nexp=Integer(11) ), value=Float('2.5', precision=53) ) ) assert res_type3[0] == Declaration( Variable( Symbol('x'), type=FloatType( String('float80'), nbits=Integer(80), nmant=Integer(63), nexp=Integer(15) ), value=Float('1.0', precision=53) ) ) assert res_type3[1] == Declaration( Variable( Symbol('y'), type=FloatType( String('float80'), nbits=Integer(80), nmant=Integer(63), nexp=Integer(15) ), value=Float('2.5', precision=53) ) ) @XFAIL def test_bool(): c_src1 = ( 'bool a = true, b = false;' ) c_src2 = ( 'bool a = 1, b = 0;' ) c_src3 = ( 'bool a = 10, b = 20;' ) c_src4 = ( 'bool a = 19.1, b = 9.0, c = 0.0;' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() assert res1[0] == Declaration( Variable(Symbol('a'), type=Type(String('bool')), value=true ) ) assert res1[1] == Declaration( Variable(Symbol('b'), type=Type(String('bool')), value=false ) ) assert res2[0] == Declaration( Variable(Symbol('a'), type=Type(String('bool')), value=true) ) assert res2[1] == Declaration( Variable(Symbol('b'), type=Type(String('bool')), value=false ) ) assert res3[0] == Declaration( Variable(Symbol('a'), type=Type(String('bool')), value=true ) ) assert res3[1] == Declaration( Variable(Symbol('b'), type=Type(String('bool')), value=true ) ) assert res4[0] == Declaration( Variable(Symbol('a'), type=Type(String('bool')), value=true) ) assert res4[1] == Declaration( Variable(Symbol('b'), type=Type(String('bool')), value=true ) ) assert res4[2] == Declaration( Variable(Symbol('c'), type=Type(String('bool')), value=false ) ) def test_function(): c_src1 = ( 'void fun1()' + '\n' + '{' + '\n' + 'int a;' + '\n' + '}' ) c_src2 = ( 'int fun2()' + '\n' + '{'+ '\n' + 'int a;' + '\n' + 'return a;' + '\n' + '}' ) c_src3 = ( 'float fun3()' + '\n' + '{' + '\n' + 'float b;' + '\n' + 'return b;' + '\n' + '}' ) c_src4 = ( 'float fun4()' + '\n' + '{}' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() assert res1[0] == FunctionDefinition( NoneToken(), name=String('fun1'), parameters=(), body=CodeBlock( Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ) ) ) assert res2[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('fun2'), parameters=(), body=CodeBlock( Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ), Return('a') ) ) assert res3[0] == FunctionDefinition( FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), name=String('fun3'), parameters=(), body=CodeBlock( Declaration( Variable( Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Return('b') ) ) assert res4[0] == FunctionPrototype( FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), name=String('fun4'), parameters=() ) def test_parameters(): c_src1 = ( 'void fun1( int a)' + '\n' + '{' + '\n' + 'int i;' + '\n' + '}' ) c_src2 = ( 'int fun2(float x, float y)' + '\n' + '{'+ '\n' + 'int a;' + '\n' + 'return a;' + '\n' + '}' ) c_src3 = ( 'float fun3(int p, float q, int r)' + '\n' + '{' + '\n' + 'float b;' + '\n' + 'return b;' + '\n' + '}' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() assert res1[0] == FunctionDefinition( NoneToken(), name=String('fun1'), parameters=( Variable( Symbol('a'), type=IntBaseType(String('intc')) ), ), body=CodeBlock( Declaration( Variable( Symbol('i'), type=IntBaseType(String('intc')) ) ) ) ) assert res2[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('fun2'), parameters=( Variable( Symbol('x'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ), Variable( Symbol('y'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), body=CodeBlock( Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ), Return('a') ) ) assert res3[0] == FunctionDefinition( FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), name=String('fun3'), parameters=( Variable( Symbol('p'), type=IntBaseType(String('intc')) ), Variable( Symbol('q'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ), Variable( Symbol('r'), type=IntBaseType(String('intc')) ) ), body=CodeBlock( Declaration( Variable( Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Return('b') ) ) def test_function_call(): c_src1 = ( 'int fun1(int x)' + '\n' + '{' + '\n' + 'return x;' + '\n' + '}' + '\n' + 'void caller()' + '\n' + '{' + '\n' + 'int x = fun1(2);' + '\n' + '}' ) c_src2 = ( 'int fun2(int a, int b, int c)' + '\n' + '{' + '\n' + 'return a;' + '\n' + '}' + '\n' + 'void caller()' + '\n' + '{' + '\n' + 'int y = fun2(2, 3, 4);' + '\n' + '}' ) c_src3 = ( 'int fun3(int a, int b, int c)' + '\n' + '{' + '\n' + 'return b;' + '\n' + '}' + '\n' + 'void caller()' + '\n' + '{' + '\n' + 'int p;' + '\n' + 'int q;' + '\n' + 'int r;' + '\n' + 'int z = fun3(p, q, r);' + '\n' + '}' ) c_src4 = ( 'int fun4(float a, float b, int c)' + '\n' + '{' + '\n' + 'return c;' + '\n' + '}' + '\n' + 'void caller()' + '\n' + '{' + '\n' + 'float x;' + '\n' + 'float y;' + '\n' + 'int z;' + '\n' + 'int i = fun4(x, y, z)' + '\n' + '}' ) c_src5 = ( 'int fun()' + '\n' + '{' + '\n' + 'return 1;' + '\n' + '}' + '\n' + 'void caller()' + '\n' + '{' + '\n' + 'int a = fun()' + '\n' + '}' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() res5 = SymPyExpression(c_src5, 'c').return_expr() assert res1[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('fun1'), parameters=(Variable(Symbol('x'), type=IntBaseType(String('intc')) ), ), body=CodeBlock( Return('x') ) ) assert res1[1] == FunctionDefinition( NoneToken(), name=String('caller'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('x'), value=FunctionCall(String('fun1'), function_args=( Integer(2), ) ) ) ) ) ) assert res2[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('fun2'), parameters=(Variable(Symbol('a'), type=IntBaseType(String('intc')) ), Variable(Symbol('b'), type=IntBaseType(String('intc')) ), Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), body=CodeBlock( Return('a') ) ) assert res2[1] == FunctionDefinition( NoneToken(), name=String('caller'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('y'), value=FunctionCall( String('fun2'), function_args=( Integer(2), Integer(3), Integer(4) ) ) ) ) ) ) assert res3[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('fun3'), parameters=( Variable(Symbol('a'), type=IntBaseType(String('intc')) ), Variable(Symbol('b'), type=IntBaseType(String('intc')) ), Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), body=CodeBlock( Return('b') ) ) assert res3[1] == FunctionDefinition( NoneToken(), name=String('caller'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('p'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('q'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('r'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('z'), value=FunctionCall( String('fun3'), function_args=( Symbol('p'), Symbol('q'), Symbol('r') ) ) ) ) ) ) assert res4[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('fun4'), parameters=(Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ), Variable(Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ), Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), body=CodeBlock( Return('c') ) ) assert res4[1] == FunctionDefinition( NoneToken(), name=String('caller'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('x'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Declaration( Variable(Symbol('y'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Declaration( Variable(Symbol('z'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('i'), value=FunctionCall(String('fun4'), function_args=( Symbol('x'), Symbol('y'), Symbol('z') ) ) ) ) ) ) assert res5[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('fun'), parameters=(), body=CodeBlock( Return('') ) ) assert res5[1] == FunctionDefinition( NoneToken(), name=String('caller'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), value=FunctionCall(String('fun'), function_args=() ) ) ) ) ) def test_parse(): c_src1 = ( 'int a;' + '\n' + 'int b;' + '\n' ) c_src2 = ( 'void fun1()' + '\n' + '{' + '\n' + 'int a;' + '\n' + '}' ) f1 = open('..a.h', 'w') f2 = open('..b.h', 'w') f1.write(c_src1) f2. write(c_src2) f1.close() f2.close() res1 = SymPyExpression('..a.h', 'c').return_expr() res2 = SymPyExpression('..b.h', 'c').return_expr() os.remove('..a.h') os.remove('..b.h') assert res1[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ) assert res1[1] == Declaration( Variable( Symbol('b'), type=IntBaseType(String('intc')) ) ) assert res2[0] == FunctionDefinition( NoneToken(), name=String('fun1'), parameters=(), body=CodeBlock( Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ) ) ) def test_binary_operators(): c_src1 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = 1;' + '\n' + '}' ) c_src2 = ( 'void func()'+ '{' + '\n' + 'int a = 0;' + '\n' + 'a = a + 1;' + '\n' + 'a = 3*a - 10;' + '\n' + '}' ) c_src3 = ( 'void func()'+ '{' + '\n' + 'int a = 10;' + '\n' + 'a = 1 + a - 3 * 6;' + '\n' + '}' ) c_src4 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'int b;' + '\n' + 'a = 100;' + '\n' + 'b = a*a + a*a + a + 19*a + 1 + 24;' + '\n' + '}' ) c_src5 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'int b;' + '\n' + 'int c;' + '\n' + 'int d;' + '\n' + 'a = 1;' + '\n' + 'b = 2;' + '\n' + 'c = b;' + '\n' + 'd = ((a+b)*(a+c))*((c-d)*(a+c));' + '\n' + '}' ) c_src6 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'int b;' + '\n' + 'int c;' + '\n' + 'int d;' + '\n' + 'a = 1;' + '\n' + 'b = 2;' + '\n' + 'c = 3;' + '\n' + 'd = (a*a*a*a + 3*b*b + b + b + c*d);' + '\n' + '}' ) c_src7 = ( 'void func()'+ '{' + '\n' + 'float a;' + '\n' + 'a = 1.01;' + '\n' + '}' ) c_src8 = ( 'void func()'+ '{' + '\n' + 'float a;' + '\n' + 'a = 10.0 + 2.5;' + '\n' + '}' ) c_src9 = ( 'void func()'+ '{' + '\n' + 'float a;' + '\n' + 'a = 10.0 / 2.5;' + '\n' + '}' ) c_src10 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = 100 / 4;' + '\n' + '}' ) c_src11 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = 20 - 100 / 4 * 5 + 10;' + '\n' + '}' ) c_src12 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = (20 - 100) / 4 * (5 + 10);' + '\n' + '}' ) c_src13 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'int b;' + '\n' + 'float c;' + '\n' + 'c = b/a;' + '\n' + '}' ) c_src14 = ( 'void func()'+ '{' + '\n' + 'int a = 2;' + '\n' + 'int d = 5;' + '\n' + 'int n = 10;' + '\n' + 'int s;' + '\n' + 's = (a/2)*(2*a + (n-1)*d);' + '\n' + '}' ) c_src15 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = 1 % 2;' + '\n' + '}' ) c_src16 = ( 'void func()'+ '{' + '\n' + 'int a = 2;' + '\n' + 'int b;' + '\n' + 'b = a % 3;' + '\n' + '}' ) c_src17 = ( 'void func()'+ '{' + '\n' + 'int a = 100;' + '\n' + 'int b = 3;' + '\n' + 'int c;' + '\n' + 'c = a % b;' + '\n' + '}' ) c_src18 = ( 'void func()'+ '{' + '\n' + 'int a = 100;' + '\n' + 'int b = 3;' + '\n' + 'int mod = 1000000007;' + '\n' + 'int c;' + '\n' + 'c = (a + b * (100/a)) % mod;' + '\n' + '}' ) c_src19 = ( 'void func()'+ '{' + '\n' + 'int a = 100;' + '\n' + 'int b = 3;' + '\n' + 'int mod = 1000000007;' + '\n' + 'int c;' + '\n' + 'c = ((a % mod + b % mod) % mod *(' \ 'a % mod - b % mod) % mod) % mod;' + '\n' + '}' ) c_src20 = ( 'void func()'+ '{' + '\n' + 'bool a' + '\n' + 'bool b;' + '\n' + 'a = 1 == 2;' + '\n' + 'b = 1 != 2;' + '\n' + '}' ) c_src21 = ( 'void func()'+ '{' + '\n' + 'bool a;' + '\n' + 'bool b;' + '\n' + 'bool c;' + '\n' + 'bool d;' + '\n' + 'a = 1 == 2;' + '\n' + 'b = 1 <= 2;' + '\n' + 'c = 1 > 2;' + '\n' + 'd = 1 >= 2;' + '\n' + '}' ) c_src22 = ( 'void func()'+ '{' + '\n' + 'int a = 1;' + '\n' + 'int b = 2;' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'bool c5;' + '\n' + 'bool c6;' + '\n' + 'bool c7;' + '\n' + 'bool c8;' + '\n' + 'c1 = a == 1;' + '\n' + 'c2 = b == 2;' + '\n' + 'c3 = 1 != a;' + '\n' + 'c4 = 1 != b;' + '\n' + 'c5 = a < 0;' + '\n' + 'c6 = b <= 10;' + '\n' + 'c7 = a > 0;' + '\n' + 'c8 = b >= 11;' + '\n' + '}' ) c_src23 = ( 'void func()'+ '{' + '\n' + 'int a = 3;' + '\n' + 'int b = 4;' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'bool c5;' + '\n' + 'bool c6;' + '\n' + 'c1 = a == b;' + '\n' + 'c2 = a != b;' + '\n' + 'c3 = a < b;' + '\n' + 'c4 = a <= b;' + '\n' + 'c5 = a > b;' + '\n' + 'c6 = a >= b;' + '\n' + '}' ) c_src24 = ( 'void func()'+ '{' + '\n' + 'float a = 1.25' 'float b = 2.5;' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'c1 = a == 1.25;' + '\n' + 'c2 = b == 2.54;' + '\n' + 'c3 = 1.2 != a;' + '\n' + 'c4 = 1.5 != b;' + '\n' + '}' ) c_src25 = ( 'void func()'+ '{' + '\n' + 'float a = 1.25' + '\n' + 'float b = 2.5;' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'bool c5;' + '\n' + 'bool c6;' + '\n' + 'c1 = a == b;' + '\n' + 'c2 = a != b;' + '\n' + 'c3 = a < b;' + '\n' + 'c4 = a <= b;' + '\n' + 'c5 = a > b;' + '\n' + 'c6 = a >= b;' + '\n' + '}' ) c_src26 = ( 'void func()'+ '{' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'bool c5;' + '\n' + 'bool c6;' + '\n' + 'c1 = true == true;' + '\n' + 'c2 = true == false;' + '\n' + 'c3 = false == false;' + '\n' + 'c4 = true != true;' + '\n' + 'c5 = true != false;' + '\n' + 'c6 = false != false;' + '\n' + '}' ) c_src27 = ( 'void func()'+ '{' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'bool c5;' + '\n' + 'bool c6;' + '\n' + 'c1 = true && true;' + '\n' + 'c2 = true && false;' + '\n' + 'c3 = false && false;' + '\n' + 'c4 = true || true;' + '\n' + 'c5 = true || false;' + '\n' + 'c6 = false || false;' + '\n' + '}' ) c_src28 = ( 'void func()'+ '{' + '\n' + 'bool a;' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'c1 = a && true;' + '\n' + 'c2 = false && a;' + '\n' + 'c3 = true || a;' + '\n' + 'c4 = a || false;' + '\n' + '}' ) c_src29 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'c1 = a && 1;' + '\n' + 'c2 = a && 0;' + '\n' + 'c3 = a || 1;' + '\n' + 'c4 = 0 || a;' + '\n' + '}' ) c_src30 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'int b;' + '\n' + 'bool c;'+ '\n' + 'bool d;'+ '\n' + 'bool c1;' + '\n' + 'bool c2;' + '\n' + 'bool c3;' + '\n' + 'bool c4;' + '\n' + 'bool c5;' + '\n' + 'bool c6;' + '\n' + 'c1 = a && b;' + '\n' + 'c2 = a && c;' + '\n' + 'c3 = c && d;' + '\n' + 'c4 = a || b;' + '\n' + 'c5 = a || c;' + '\n' + 'c6 = c || d;' + '\n' + '}' ) c_src_raise1 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = -1;' + '\n' + '}' ) c_src_raise2 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = -+1;' + '\n' + '}' ) c_src_raise3 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = 2*-2;' + '\n' + '}' ) c_src_raise4 = ( 'void func()'+ '{' + '\n' + 'int a;' + '\n' + 'a = (int)2.0;' + '\n' + '}' ) c_src_raise5 = ( 'void func()'+ '{' + '\n' + 'int a=100;' + '\n' + 'a = (a==100)?(1):(0);' + '\n' + '}' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() res5 = SymPyExpression(c_src5, 'c').return_expr() res6 = SymPyExpression(c_src6, 'c').return_expr() res7 = SymPyExpression(c_src7, 'c').return_expr() res8 = SymPyExpression(c_src8, 'c').return_expr() res9 = SymPyExpression(c_src9, 'c').return_expr() res10 = SymPyExpression(c_src10, 'c').return_expr() res11 = SymPyExpression(c_src11, 'c').return_expr() res12 = SymPyExpression(c_src12, 'c').return_expr() res13 = SymPyExpression(c_src13, 'c').return_expr() res14 = SymPyExpression(c_src14, 'c').return_expr() res15 = SymPyExpression(c_src15, 'c').return_expr() res16 = SymPyExpression(c_src16, 'c').return_expr() res17 = SymPyExpression(c_src17, 'c').return_expr() res18 = SymPyExpression(c_src18, 'c').return_expr() res19 = SymPyExpression(c_src19, 'c').return_expr() res20 = SymPyExpression(c_src20, 'c').return_expr() res21 = SymPyExpression(c_src21, 'c').return_expr() res22 = SymPyExpression(c_src22, 'c').return_expr() res23 = SymPyExpression(c_src23, 'c').return_expr() res24 = SymPyExpression(c_src24, 'c').return_expr() res25 = SymPyExpression(c_src25, 'c').return_expr() res26 = SymPyExpression(c_src26, 'c').return_expr() res27 = SymPyExpression(c_src27, 'c').return_expr() res28 = SymPyExpression(c_src28, 'c').return_expr() res29 = SymPyExpression(c_src29, 'c').return_expr() res30 = SymPyExpression(c_src30, 'c').return_expr() assert res1[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Assignment(Variable(Symbol('a')), Integer(1)) ) ) assert res2[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(0))), Assignment( Variable(Symbol('a')), Add(Symbol('a'), Integer(1)) ), Assignment(Variable(Symbol('a')), Add( Mul( Integer(3), Symbol('a')), Integer(-10) ) ) ) ) assert res3[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(10) ) ), Assignment( Variable(Symbol('a')), Add( Symbol('a'), Integer(-17) ) ) ) ) assert res4[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('a')), Integer(100)), Assignment( Variable(Symbol('b')), Add( Mul( Integer(2), Pow( Symbol('a'), Integer(2)) ), Mul( Integer(20), Symbol('a')), Integer(25) ) ) ) ) assert res5[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('d'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('a')), Integer(1)), Assignment( Variable(Symbol('b')), Integer(2) ), Assignment( Variable(Symbol('c')), Symbol('b')), Assignment( Variable(Symbol('d')), Mul( Add( Symbol('a'), Symbol('b')), Pow( Add( Symbol('a'), Symbol('c') ), Integer(2) ), Add( Symbol('c'), Mul( Integer(-1), Symbol('d') ) ) ) ) ) ) assert res6[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('d'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('a')), Integer(1) ), Assignment( Variable(Symbol('b')), Integer(2) ), Assignment( Variable(Symbol('c')), Integer(3) ), Assignment( Variable(Symbol('d')), Add( Pow( Symbol('a'), Integer(4) ), Mul( Integer(3), Pow( Symbol('b'), Integer(2) ) ), Mul( Integer(2), Symbol('b') ), Mul( Symbol('c'), Symbol('d') ) ) ) ) ) assert res7[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Assignment( Variable(Symbol('a')), Float('1.01', precision=53) ) ) ) assert res8[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Assignment( Variable(Symbol('a')), Float('12.5', precision=53) ) ) ) assert res9[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Assignment( Variable(Symbol('a')), Float('4.0', precision=53) ) ) ) assert res10[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('a')), Integer(25) ) ) ) assert res11[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('a')), Integer(-95) ) ) ) assert res12[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('a')), Integer(-300) ) ) ) assert res13[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('c'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Assignment( Variable(Symbol('c')), Mul( Pow( Symbol('a'), Integer(-1) ), Symbol('b') ) ) ) ) assert res14[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(2) ) ), Declaration( Variable(Symbol('d'), type=IntBaseType(String('intc')), value=Integer(5) ) ), Declaration( Variable(Symbol('n'), type=IntBaseType(String('intc')), value=Integer(10) ) ), Declaration( Variable(Symbol('s'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('s')), Mul( Rational(1, 2), Symbol('a'), Add( Mul( Integer(2), Symbol('a') ), Mul( Symbol('d'), Add( Symbol('n'), Integer(-1) ) ) ) ) ) ) ) assert res15[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('a')), Integer(1) ) ) ) assert res16[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(2) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('b')), Mod( Symbol('a'), Integer(3) ) ) ) ) assert res17[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(100) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(3) ) ), Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('c')), Mod( Symbol('a'), Symbol('b') ) ) ) ) assert res18[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(100) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(3) ) ), Declaration( Variable(Symbol('mod'), type=IntBaseType(String('intc')), value=Integer(1000000007) ) ), Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('c')), Mod( Add( Symbol('a'), Mul( Integer(100), Pow( Symbol('a'), Integer(-1) ), Symbol('b') ) ), Symbol('mod') ) ) ) ) assert res19[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(100) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(3) ) ), Declaration( Variable(Symbol('mod'), type=IntBaseType(String('intc')), value=Integer(1000000007) ) ), Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')) ) ), Assignment( Variable(Symbol('c')), Mod( Mul( Add( Symbol('a'), Mul(Integer(-1), Symbol('b') ) ), Add( Symbol('a'), Symbol('b') ) ), Symbol('mod') ) ) ) ) assert res20[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('b'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('a')), false ), Assignment( Variable(Symbol('b')), true ) ) ) assert res21[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('b'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('d'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('a')), false ), Assignment( Variable(Symbol('b')), true ), Assignment( Variable(Symbol('c')), false ), Assignment( Variable(Symbol('d')), false ) ) ) assert res22[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ), Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c5'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c6'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c7'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c8'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), Equality( Symbol('a'), Integer(1) ) ), Assignment( Variable(Symbol('c2')), Equality( Symbol('b'), Integer(2) ) ), Assignment( Variable(Symbol('c3')), Unequality( Integer(1), Symbol('a') ) ), Assignment( Variable(Symbol('c4')), Unequality( Integer(1), Symbol('b') ) ), Assignment( Variable(Symbol('c5')), StrictLessThan( Symbol('a'), Integer(0) ) ), Assignment( Variable(Symbol('c6')), LessThan( Symbol('b'), Integer(10) ) ), Assignment( Variable(Symbol('c7')), StrictGreaterThan( Symbol('a'), Integer(0) ) ), Assignment( Variable(Symbol('c8')), GreaterThan( Symbol('b'), Integer(11) ) ) ) ) assert res23[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(3) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(4) ) ), Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c5'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c6'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), Equality( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c2')), Unequality( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c3')), StrictLessThan( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c4')), LessThan( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c5')), StrictGreaterThan( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c6')), GreaterThan( Symbol('a'), Symbol('b') ) ) ) ) assert res24[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ), Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), Equality( Symbol('a'), Float('1.25', precision=53) ) ), Assignment( Variable(Symbol('c3')), Unequality( Float('1.2', precision=53), Symbol('a') ) ) ) ) assert res25[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.25', precision=53) ) ), Declaration( Variable(Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.5', precision=53) ) ), Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool') ) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c5'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c6'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), Equality( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c2')), Unequality( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c3')), StrictLessThan( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c4')), LessThan( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c5')), StrictGreaterThan( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c6')), GreaterThan( Symbol('a'), Symbol('b') ) ) ) ) assert res26[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c5'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c6'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), true ), Assignment( Variable(Symbol('c2')), false ), Assignment( Variable(Symbol('c3')), true ), Assignment( Variable(Symbol('c4')), false ), Assignment( Variable(Symbol('c5')), true ), Assignment( Variable(Symbol('c6')), false ) ) ) assert res27[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c5'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c6'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), true ), Assignment( Variable(Symbol('c2')), false ), Assignment( Variable(Symbol('c3')), false ), Assignment( Variable(Symbol('c4')), true ), Assignment( Variable(Symbol('c5')), true ), Assignment( Variable(Symbol('c6')), false) ) ) assert res28[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), Symbol('a') ), Assignment( Variable(Symbol('c2')), false ), Assignment( Variable(Symbol('c3')), true ), Assignment( Variable(Symbol('c4')), Symbol('a') ) ) ) assert res29[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), Symbol('a') ), Assignment( Variable(Symbol('c2')), false ), Assignment( Variable(Symbol('c3')), true ), Assignment( Variable(Symbol('c4')), Symbol('a') ) ) ) assert res30[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')) ) ), Declaration( Variable(Symbol('c'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('d'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c1'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c2'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c3'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c4'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c5'), type=Type(String('bool')) ) ), Declaration( Variable(Symbol('c6'), type=Type(String('bool')) ) ), Assignment( Variable(Symbol('c1')), And( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c2')), And( Symbol('a'), Symbol('c') ) ), Assignment( Variable(Symbol('c3')), And( Symbol('c'), Symbol('d') ) ), Assignment( Variable(Symbol('c4')), Or( Symbol('a'), Symbol('b') ) ), Assignment( Variable(Symbol('c5')), Or( Symbol('a'), Symbol('c') ) ), Assignment( Variable(Symbol('c6')), Or( Symbol('c'), Symbol('d') ) ) ) ) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise1, 'c')) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise2, 'c')) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise3, 'c')) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise4, 'c')) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise5, 'c')) @XFAIL def test_var_decl(): c_src1 = ( 'int b = 100;' + '\n' + 'int a = b;' + '\n' ) c_src2 = ( 'int a = 1;' + '\n' + 'int b = a + 1;' + '\n' ) c_src3 = ( 'float a = 10.0 + 2.5;' + '\n' + 'float b = a * 20.0;' + '\n' ) c_src4 = ( 'int a = 1 + 100 - 3 * 6;' + '\n' ) c_src5 = ( 'int a = (((1 + 100) * 12) - 3) * (6 - 10);' + '\n' ) c_src6 = ( 'int b = 2;' + '\n' + 'int c = 3;' + '\n' + 'int a = b + c * 4;' + '\n' ) c_src7 = ( 'int b = 1;' + '\n' + 'int c = b + 2;' + '\n' + 'int a = 10 * b * b * c;' + '\n' ) c_src8 = ( 'void func()'+ '{' + '\n' + 'int a = 1;' + '\n' + 'int b = 2;' + '\n' + 'int temp = a;' + '\n' + 'a = b;' + '\n' + 'b = temp;' + '\n' + '}' ) c_src9 = ( 'int a = 1;' + '\n' + 'int b = 2;' + '\n' + 'int c = a;' + '\n' + 'int d = a + b + c;' + '\n' + 'int e = a*a*a + 3*a*a*b + 3*a*b*b + b*b*b;' + '\n' 'int f = (a + b + c) * (a + b - c);' + '\n' + 'int g = (a + b + c + d)*(a + b + c + d)*(a * (b - c));' + '\n' ) c_src10 = ( 'float a = 10.0;' + '\n' + 'float b = 2.5;' + '\n' + 'float c = a*a + 2*a*b + b*b;' + '\n' ) c_src11 = ( 'float a = 10.0 / 2.5;' + '\n' ) c_src12 = ( 'int a = 100 / 4;' + '\n' ) c_src13 = ( 'int a = 20 - 100 / 4 * 5 + 10;' + '\n' ) c_src14 = ( 'int a = (20 - 100) / 4 * (5 + 10);' + '\n' ) c_src15 = ( 'int a = 4;' + '\n' + 'int b = 2;' + '\n' + 'float c = b/a;' + '\n' ) c_src16 = ( 'int a = 2;' + '\n' + 'int d = 5;' + '\n' + 'int n = 10;' + '\n' + 'int s = (a/2)*(2*a + (n-1)*d);' + '\n' ) c_src17 = ( 'int a = 1 % 2;' + '\n' ) c_src18 = ( 'int a = 2;' + '\n' + 'int b = a % 3;' + '\n' ) c_src19 = ( 'int a = 100;' + '\n' + 'int b = 3;' + '\n' + 'int c = a % b;' + '\n' ) c_src20 = ( 'int a = 100;' + '\n' + 'int b = 3;' + '\n' + 'int mod = 1000000007;' + '\n' + 'int c = (a + b * (100/a)) % mod;' + '\n' ) c_src21 = ( 'int a = 100;' + '\n' + 'int b = 3;' + '\n' + 'int mod = 1000000007;' + '\n' + 'int c = ((a % mod + b % mod) % mod *(' \ 'a % mod - b % mod) % mod) % mod;' + '\n' ) c_src22 = ( 'bool a = 1 == 2, b = 1 != 2;' ) c_src23 = ( 'bool a = 1 < 2, b = 1 <= 2, c = 1 > 2, d = 1 >= 2;' ) c_src24 = ( 'int a = 1, b = 2;' + '\n' + 'bool c1 = a == 1;' + '\n' + 'bool c2 = b == 2;' + '\n' + 'bool c3 = 1 != a;' + '\n' + 'bool c4 = 1 != b;' + '\n' + 'bool c5 = a < 0;' + '\n' + 'bool c6 = b <= 10;' + '\n' + 'bool c7 = a > 0;' + '\n' + 'bool c8 = b >= 11;' ) c_src25 = ( 'int a = 3, b = 4;' + '\n' + 'bool c1 = a == b;' + '\n' + 'bool c2 = a != b;' + '\n' + 'bool c3 = a < b;' + '\n' + 'bool c4 = a <= b;' + '\n' + 'bool c5 = a > b;' + '\n' + 'bool c6 = a >= b;' ) c_src26 = ( 'float a = 1.25, b = 2.5;' + '\n' + 'bool c1 = a == 1.25;' + '\n' + 'bool c2 = b == 2.54;' + '\n' + 'bool c3 = 1.2 != a;' + '\n' + 'bool c4 = 1.5 != b;' ) c_src27 = ( 'float a = 1.25, b = 2.5;' + '\n' + 'bool c1 = a == b;' + '\n' + 'bool c2 = a != b;' + '\n' + 'bool c3 = a < b;' + '\n' + 'bool c4 = a <= b;' + '\n' + 'bool c5 = a > b;' + '\n' + 'bool c6 = a >= b;' ) c_src28 = ( 'bool c1 = true == true;' + '\n' + 'bool c2 = true == false;' + '\n' + 'bool c3 = false == false;' + '\n' + 'bool c4 = true != true;' + '\n' + 'bool c5 = true != false;' + '\n' + 'bool c6 = false != false;' ) c_src29 = ( 'bool c1 = true && true;' + '\n' + 'bool c2 = true && false;' + '\n' + 'bool c3 = false && false;' + '\n' + 'bool c4 = true || true;' + '\n' + 'bool c5 = true || false;' + '\n' + 'bool c6 = false || false;' ) c_src30 = ( 'bool a = false;' + '\n' + 'bool c1 = a && true;' + '\n' + 'bool c2 = false && a;' + '\n' + 'bool c3 = true || a;' + '\n' + 'bool c4 = a || false;' ) c_src31 = ( 'int a = 1;' + '\n' + 'bool c1 = a && 1;' + '\n' + 'bool c2 = a && 0;' + '\n' + 'bool c3 = a || 1;' + '\n' + 'bool c4 = 0 || a;' ) c_src32 = ( 'int a = 1, b = 0;' + '\n' + 'bool c = false, d = true;'+ '\n' + 'bool c1 = a && b;' + '\n' + 'bool c2 = a && c;' + '\n' + 'bool c3 = c && d;' + '\n' + 'bool c4 = a || b;' + '\n' + 'bool c5 = a || c;' + '\n' + 'bool c6 = c || d;' ) c_src_raise1 = ( "char a = 'b';" ) c_src_raise2 = ( 'int a[] = {10, 20};' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() res5 = SymPyExpression(c_src5, 'c').return_expr() res6 = SymPyExpression(c_src6, 'c').return_expr() res7 = SymPyExpression(c_src7, 'c').return_expr() res8 = SymPyExpression(c_src8, 'c').return_expr() res9 = SymPyExpression(c_src9, 'c').return_expr() res10 = SymPyExpression(c_src10, 'c').return_expr() res11 = SymPyExpression(c_src11, 'c').return_expr() res12 = SymPyExpression(c_src12, 'c').return_expr() res13 = SymPyExpression(c_src13, 'c').return_expr() res14 = SymPyExpression(c_src14, 'c').return_expr() res15 = SymPyExpression(c_src15, 'c').return_expr() res16 = SymPyExpression(c_src16, 'c').return_expr() res17 = SymPyExpression(c_src17, 'c').return_expr() res18 = SymPyExpression(c_src18, 'c').return_expr() res19 = SymPyExpression(c_src19, 'c').return_expr() res20 = SymPyExpression(c_src20, 'c').return_expr() res21 = SymPyExpression(c_src21, 'c').return_expr() res22 = SymPyExpression(c_src22, 'c').return_expr() res23 = SymPyExpression(c_src23, 'c').return_expr() res24 = SymPyExpression(c_src24, 'c').return_expr() res25 = SymPyExpression(c_src25, 'c').return_expr() res26 = SymPyExpression(c_src26, 'c').return_expr() res27 = SymPyExpression(c_src27, 'c').return_expr() res28 = SymPyExpression(c_src28, 'c').return_expr() res29 = SymPyExpression(c_src29, 'c').return_expr() res30 = SymPyExpression(c_src30, 'c').return_expr() res31 = SymPyExpression(c_src31, 'c').return_expr() res32 = SymPyExpression(c_src32, 'c').return_expr() assert res1[0] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(100) ) ) assert res1[1] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Symbol('b') ) ) assert res2[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res2[1] == Declaration(Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Add( Symbol('a'), Integer(1) ) ) ) assert res3[0] == Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('12.5', precision=53) ) ) assert res3[1] == Declaration( Variable(Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Mul( Float('20.0', precision=53), Symbol('a') ) ) ) assert res4[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(83) ) ) assert res5[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(-4836) ) ) assert res6[0] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res6[1] == Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Integer(3) ) ) assert res6[2] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Add( Symbol('b'), Mul( Integer(4), Symbol('c') ) ) ) ) assert res7[0] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res7[1] == Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Add( Symbol('b'), Integer(2) ) ) ) assert res7[2] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Mul( Integer(10), Pow( Symbol('b'), Integer(2) ), Symbol('c') ) ) ) assert res8[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ), Declaration( Variable(Symbol('temp'), type=IntBaseType(String('intc')), value=Symbol('a') ) ), Assignment( Variable(Symbol('a')), Symbol('b') ), Assignment( Variable(Symbol('b')), Symbol('temp') ) ) ) assert res9[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res9[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res9[2] == Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Symbol('a') ) ) assert res9[3] == Declaration( Variable(Symbol('d'), type=IntBaseType(String('intc')), value=Add( Symbol('a'), Symbol('b'), Symbol('c') ) ) ) assert res9[4] == Declaration( Variable(Symbol('e'), type=IntBaseType(String('intc')), value=Add( Pow( Symbol('a'), Integer(3) ), Mul( Integer(3), Pow( Symbol('a'), Integer(2) ), Symbol('b') ), Mul( Integer(3), Symbol('a'), Pow( Symbol('b'), Integer(2) ) ), Pow( Symbol('b'), Integer(3) ) ) ) ) assert res9[5] == Declaration( Variable(Symbol('f'), type=IntBaseType(String('intc')), value=Mul( Add( Symbol('a'), Symbol('b'), Mul( Integer(-1), Symbol('c') ) ), Add( Symbol('a'), Symbol('b'), Symbol('c') ) ) ) ) assert res9[6] == Declaration( Variable(Symbol('g'), type=IntBaseType(String('intc')), value=Mul( Symbol('a'), Add( Symbol('b'), Mul( Integer(-1), Symbol('c') ) ), Pow( Add( Symbol('a'), Symbol('b'), Symbol('c'), Symbol('d') ), Integer(2) ) ) ) ) assert res10[0] == Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('10.0', precision=53) ) ) assert res10[1] == Declaration( Variable(Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.5', precision=53) ) ) assert res10[2] == Declaration( Variable(Symbol('c'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Add( Pow( Symbol('a'), Integer(2) ), Mul( Integer(2), Symbol('a'), Symbol('b') ), Pow( Symbol('b'), Integer(2) ) ) ) ) assert res11[0] == Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('4.0', precision=53) ) ) assert res12[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(25) ) ) assert res13[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(-95) ) ) assert res14[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(-300) ) ) assert res15[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(4) ) ) assert res15[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res15[2] == Declaration( Variable(Symbol('c'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Mul( Pow( Symbol('a'), Integer(-1) ), Symbol('b') ) ) ) assert res16[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res16[1] == Declaration( Variable(Symbol('d'), type=IntBaseType(String('intc')), value=Integer(5) ) ) assert res16[2] == Declaration( Variable(Symbol('n'), type=IntBaseType(String('intc')), value=Integer(10) ) ) assert res16[3] == Declaration( Variable(Symbol('s'), type=IntBaseType(String('intc')), value=Mul( Rational(1, 2), Symbol('a'), Add( Mul( Integer(2), Symbol('a') ), Mul( Symbol('d'), Add( Symbol('n'), Integer(-1) ) ) ) ) ) ) assert res17[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res18[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res18[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Mod( Symbol('a'), Integer(3) ) ) ) assert res19[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(100) ) ) assert res19[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(3) ) ) assert res19[2] == Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Mod( Symbol('a'), Symbol('b') ) ) ) assert res20[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(100) ) ) assert res20[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(3) ) ) assert res20[2] == Declaration( Variable(Symbol('mod'), type=IntBaseType(String('intc')), value=Integer(1000000007) ) ) assert res20[3] == Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Mod( Add( Symbol('a'), Mul( Integer(100), Pow( Symbol('a'), Integer(-1) ), Symbol('b') ) ), Symbol('mod') ) ) ) assert res21[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(100) ) ) assert res21[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(3) ) ) assert res21[2] == Declaration( Variable(Symbol('mod'), type=IntBaseType(String('intc')), value=Integer(1000000007) ) ) assert res21[3] == Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Mod( Mul( Add( Symbol('a'), Mul( Integer(-1), Symbol('b') ) ), Add( Symbol('a'), Symbol('b') ) ), Symbol('mod') ) ) ) assert res22[0] == Declaration( Variable(Symbol('a'), type=Type(String('bool')), value=false ) ) assert res22[1] == Declaration( Variable(Symbol('b'), type=Type(String('bool')), value=true ) ) assert res23[0] == Declaration( Variable(Symbol('a'), type=Type(String('bool')), value=true ) ) assert res23[1] == Declaration( Variable(Symbol('b'), type=Type(String('bool')), value=true ) ) assert res23[2] == Declaration( Variable(Symbol('c'), type=Type(String('bool')), value=false ) ) assert res23[3] == Declaration( Variable(Symbol('d'), type=Type(String('bool')), value=false ) ) assert res24[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res24[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res24[2] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=Equality( Symbol('a'), Integer(1) ) ) ) assert res24[3] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=Equality( Symbol('b'), Integer(2) ) ) ) assert res24[4] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=Unequality( Integer(1), Symbol('a') ) ) ) assert res24[5] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=Unequality( Integer(1), Symbol('b') ) ) ) assert res24[6] == Declaration( Variable(Symbol('c5'), type=Type(String('bool')), value=StrictLessThan(Symbol('a'), Integer(0) ) ) ) assert res24[7] == Declaration( Variable(Symbol('c6'), type=Type(String('bool')), value=LessThan( Symbol('b'), Integer(10) ) ) ) assert res24[8] == Declaration( Variable(Symbol('c7'), type=Type(String('bool')), value=StrictGreaterThan( Symbol('a'), Integer(0) ) ) ) assert res24[9] == Declaration( Variable(Symbol('c8'), type=Type(String('bool')), value=GreaterThan( Symbol('b'), Integer(11) ) ) ) assert res25[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(3) ) ) assert res25[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(4) ) ) assert res25[2] == Declaration(Variable(Symbol('c1'), type=Type(String('bool')), value=Equality( Symbol('a'), Symbol('b') ) ) ) assert res25[3] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=Unequality( Symbol('a'), Symbol('b') ) ) ) assert res25[4] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=StrictLessThan( Symbol('a'), Symbol('b') ) ) ) assert res25[5] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=LessThan( Symbol('a'), Symbol('b') ) ) ) assert res25[6] == Declaration( Variable(Symbol('c5'), type=Type(String('bool')), value=StrictGreaterThan( Symbol('a'), Symbol('b') ) ) ) assert res25[7] == Declaration( Variable(Symbol('c6'), type=Type(String('bool')), value=GreaterThan( Symbol('a'), Symbol('b') ) ) ) assert res26[0] == Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.25', precision=53) ) ) assert res26[1] == Declaration( Variable(Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.5', precision=53) ) ) assert res26[2] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=Equality( Symbol('a'), Float('1.25', precision=53) ) ) ) assert res26[3] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=Equality( Symbol('b'), Float('2.54', precision=53) ) ) ) assert res26[4] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=Unequality( Float('1.2', precision=53), Symbol('a') ) ) ) assert res26[5] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=Unequality( Float('1.5', precision=53), Symbol('b') ) ) ) assert res27[0] == Declaration( Variable(Symbol('a'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('1.25', precision=53) ) ) assert res27[1] == Declaration( Variable(Symbol('b'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.5', precision=53) ) ) assert res27[2] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=Equality( Symbol('a'), Symbol('b') ) ) ) assert res27[3] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=Unequality( Symbol('a'), Symbol('b') ) ) ) assert res27[4] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=StrictLessThan( Symbol('a'), Symbol('b') ) ) ) assert res27[5] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=LessThan( Symbol('a'), Symbol('b') ) ) ) assert res27[6] == Declaration( Variable(Symbol('c5'), type=Type(String('bool')), value=StrictGreaterThan( Symbol('a'), Symbol('b') ) ) ) assert res27[7] == Declaration( Variable(Symbol('c6'), type=Type(String('bool')), value=GreaterThan( Symbol('a'), Symbol('b') ) ) ) assert res28[0] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=true ) ) assert res28[1] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=false ) ) assert res28[2] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=true ) ) assert res28[3] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=false ) ) assert res28[4] == Declaration( Variable(Symbol('c5'), type=Type(String('bool')), value=true ) ) assert res28[5] == Declaration( Variable(Symbol('c6'), type=Type(String('bool')), value=false ) ) assert res29[0] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=true ) ) assert res29[1] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=false ) ) assert res29[2] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=false ) ) assert res29[3] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=true ) ) assert res29[4] == Declaration( Variable(Symbol('c5'), type=Type(String('bool')), value=true ) ) assert res29[5] == Declaration( Variable(Symbol('c6'), type=Type(String('bool')), value=false ) ) assert res30[0] == Declaration( Variable(Symbol('a'), type=Type(String('bool')), value=false ) ) assert res30[1] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=Symbol('a') ) ) assert res30[2] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=false ) ) assert res30[3] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=true ) ) assert res30[4] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=Symbol('a') ) ) assert res31[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res31[1] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=Symbol('a') ) ) assert res31[2] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=false ) ) assert res31[3] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=true ) ) assert res31[4] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=Symbol('a') ) ) assert res32[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res32[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(0) ) ) assert res32[2] == Declaration( Variable(Symbol('c'), type=Type(String('bool')), value=false ) ) assert res32[3] == Declaration( Variable(Symbol('d'), type=Type(String('bool')), value=true ) ) assert res32[4] == Declaration( Variable(Symbol('c1'), type=Type(String('bool')), value=And( Symbol('a'), Symbol('b') ) ) ) assert res32[5] == Declaration( Variable(Symbol('c2'), type=Type(String('bool')), value=And( Symbol('a'), Symbol('c') ) ) ) assert res32[6] == Declaration( Variable(Symbol('c3'), type=Type(String('bool')), value=And( Symbol('c'), Symbol('d') ) ) ) assert res32[7] == Declaration( Variable(Symbol('c4'), type=Type(String('bool')), value=Or( Symbol('a'), Symbol('b') ) ) ) assert res32[8] == Declaration( Variable(Symbol('c5'), type=Type(String('bool')), value=Or( Symbol('a'), Symbol('c') ) ) ) assert res32[9] == Declaration( Variable(Symbol('c6'), type=Type(String('bool')), value=Or( Symbol('c'), Symbol('d') ) ) ) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise1, 'c')) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise2, 'c')) def test_paren_expr(): c_src1 = ( 'int a = (1);' 'int b = (1 + 2 * 3);' ) c_src2 = ( 'int a = 1, b = 2, c = 3;' 'int d = (a);' 'int e = (a + 1);' 'int f = (a + b * c - d / e);' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() assert res1[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res1[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(7) ) ) assert res2[0] == Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(1) ) ) assert res2[1] == Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(2) ) ) assert res2[2] == Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Integer(3) ) ) assert res2[3] == Declaration( Variable(Symbol('d'), type=IntBaseType(String('intc')), value=Symbol('a') ) ) assert res2[4] == Declaration( Variable(Symbol('e'), type=IntBaseType(String('intc')), value=Add( Symbol('a'), Integer(1) ) ) ) assert res2[5] == Declaration( Variable(Symbol('f'), type=IntBaseType(String('intc')), value=Add( Symbol('a'), Mul( Symbol('b'), Symbol('c') ), Mul( Integer(-1), Symbol('d'), Pow( Symbol('e'), Integer(-1) ) ) ) ) ) def test_unary_operators(): c_src1 = ( 'void func()'+ '{' + '\n' + 'int a = 10;' + '\n' + 'int b = 20;' + '\n' + '++a;' + '\n' + '--b;' + '\n' + 'a++;' + '\n' + 'b--;' + '\n' + '}' ) c_src2 = ( 'void func()'+ '{' + '\n' + 'int a = 10;' + '\n' + 'int b = -100;' + '\n' + 'int c = +19;' + '\n' + 'int d = ++a;' + '\n' + 'int e = --b;' + '\n' + 'int f = a++;' + '\n' + 'int g = b--;' + '\n' + 'bool h = !false;' + '\n' + 'bool i = !d;' + '\n' + 'bool j = !0;' + '\n' + 'bool k = !10.0;' + '\n' + '}' ) c_src_raise1 = ( 'void func()'+ '{' + '\n' + 'int a = 10;' + '\n' + 'int b = ~a;' + '\n' + '}' ) c_src_raise2 = ( 'void func()'+ '{' + '\n' + 'int a = 10;' + '\n' + 'int b = *&a;' + '\n' + '}' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() assert res1[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(10) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(20) ) ), PreIncrement(Symbol('a')), PreDecrement(Symbol('b')), PostIncrement(Symbol('a')), PostDecrement(Symbol('b')) ) ) assert res2[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('a'), type=IntBaseType(String('intc')), value=Integer(10) ) ), Declaration( Variable(Symbol('b'), type=IntBaseType(String('intc')), value=Integer(-100) ) ), Declaration( Variable(Symbol('c'), type=IntBaseType(String('intc')), value=Integer(19) ) ), Declaration( Variable(Symbol('d'), type=IntBaseType(String('intc')), value=PreIncrement(Symbol('a')) ) ), Declaration( Variable(Symbol('e'), type=IntBaseType(String('intc')), value=PreDecrement(Symbol('b')) ) ), Declaration( Variable(Symbol('f'), type=IntBaseType(String('intc')), value=PostIncrement(Symbol('a')) ) ), Declaration( Variable(Symbol('g'), type=IntBaseType(String('intc')), value=PostDecrement(Symbol('b')) ) ), Declaration( Variable(Symbol('h'), type=Type(String('bool')), value=true ) ), Declaration( Variable(Symbol('i'), type=Type(String('bool')), value=Not(Symbol('d')) ) ), Declaration( Variable(Symbol('j'), type=Type(String('bool')), value=true ) ), Declaration( Variable(Symbol('k'), type=Type(String('bool')), value=false ) ) ) ) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise1, 'c')) raises(NotImplementedError, lambda: SymPyExpression(c_src_raise2, 'c')) def test_compound_assignment_operator(): c_src = ( 'void func()'+ '{' + '\n' + 'int a = 100;' + '\n' + 'a += 10;' + '\n' + 'a -= 10;' + '\n' + 'a *= 10;' + '\n' + 'a /= 10;' + '\n' + 'a %= 10;' + '\n' + '}' ) res = SymPyExpression(c_src, 'c').return_expr() assert res[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')), value=Integer(100) ) ), AddAugmentedAssignment( Variable(Symbol('a')), Integer(10) ), SubAugmentedAssignment( Variable(Symbol('a')), Integer(10) ), MulAugmentedAssignment( Variable(Symbol('a')), Integer(10) ), DivAugmentedAssignment( Variable(Symbol('a')), Integer(10) ), ModAugmentedAssignment( Variable(Symbol('a')), Integer(10) ) ) ) def test_while_stmt(): c_src1 = ( 'void func()'+ '{' + '\n' + 'int i = 0;' + '\n' + 'while(i < 10)' + '\n' + '{' + '\n' + 'i++;' + '\n' + '}' '}' ) c_src2 = ( 'void func()'+ '{' + '\n' + 'int i = 0;' + '\n' + 'while(i < 10)' + '\n' + 'i++;' + '\n' + '}' ) c_src3 = ( 'void func()'+ '{' + '\n' + 'int i = 10;' + '\n' + 'int cnt = 0;' + '\n' + 'while(i > 0)' + '\n' + '{' + '\n' + 'i--;' + '\n' + 'cnt++;' + '\n' + '}' + '\n' + '}' ) c_src4 = ( 'int digit_sum(int n)'+ '{' + '\n' + 'int sum = 0;' + '\n' + 'while(n > 0)' + '\n' + '{' + '\n' + 'sum += (n % 10);' + '\n' + 'n /= 10;' + '\n' + '}' + '\n' + 'return sum;' + '\n' + '}' ) c_src5 = ( 'void func()'+ '{' + '\n' + 'while(1);' + '\n' + '}' ) res1 = SymPyExpression(c_src1, 'c').return_expr() res2 = SymPyExpression(c_src2, 'c').return_expr() res3 = SymPyExpression(c_src3, 'c').return_expr() res4 = SymPyExpression(c_src4, 'c').return_expr() res5 = SymPyExpression(c_src5, 'c').return_expr() assert res1[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable(Symbol('i'), type=IntBaseType(String('intc')), value=Integer(0) ) ), While( StrictLessThan( Symbol('i'), Integer(10) ), body=CodeBlock( PostIncrement( Symbol('i') ) ) ) ) ) assert res2[0] == res1[0] assert res3[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( Declaration( Variable( Symbol('i'), type=IntBaseType(String('intc')), value=Integer(10) ) ), Declaration( Variable( Symbol('cnt'), type=IntBaseType(String('intc')), value=Integer(0) ) ), While( StrictGreaterThan( Symbol('i'), Integer(0) ), body=CodeBlock( PostDecrement( Symbol('i') ), PostIncrement( Symbol('cnt') ) ) ) ) ) assert res4[0] == FunctionDefinition( IntBaseType(String('intc')), name=String('digit_sum'), parameters=( Variable( Symbol('n'), type=IntBaseType(String('intc')) ), ), body=CodeBlock( Declaration( Variable( Symbol('sum'), type=IntBaseType(String('intc')), value=Integer(0) ) ), While( StrictGreaterThan( Symbol('n'), Integer(0) ), body=CodeBlock( AddAugmentedAssignment( Variable( Symbol('sum') ), Mod( Symbol('n'), Integer(10) ) ), DivAugmentedAssignment( Variable( Symbol('n') ), Integer(10) ) ) ), Return('sum') ) ) assert res5[0] == FunctionDefinition( NoneToken(), name=String('func'), parameters=(), body=CodeBlock( While( Integer(1), body=CodeBlock( NoneToken() ) ) ) ) else: def test_raise(): from sympy.parsing.c.c_parser import CCodeConverter raises(ImportError, lambda: CCodeConverter()) raises(ImportError, lambda: SymPyExpression(' ', mode = 'c')) sympy-sympy-1.9/sympy/parsing/tests/test_fortran_parser.py000066400000000000000000000270501412543434000243550ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy.parsing.sym_expr import SymPyExpression from sympy.external import import_module lfortran = import_module('lfortran') if lfortran: from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String, Return, FunctionDefinition, Assignment, Declaration, CodeBlock) from sympy.core import Integer, Float, Add from sympy import Symbol expr1 = SymPyExpression() expr2 = SymPyExpression() src = """\ integer :: a, b, c, d real :: p, q, r, s """ def test_sym_expr(): src1 = ( src + """\ d = a + b -c """ ) expr3 = SymPyExpression(src,'f') expr4 = SymPyExpression(src1,'f') ls1 = expr3.return_expr() ls2 = expr4.return_expr() for i in range(0, 7): assert isinstance(ls1[i], Declaration) assert isinstance(ls2[i], Declaration) assert isinstance(ls2[8], Assignment) assert ls1[0] == Declaration( Variable( Symbol('a'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls1[1] == Declaration( Variable( Symbol('b'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls1[2] == Declaration( Variable( Symbol('c'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls1[3] == Declaration( Variable( Symbol('d'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls1[4] == Declaration( Variable( Symbol('p'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) assert ls1[5] == Declaration( Variable( Symbol('q'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) assert ls1[6] == Declaration( Variable( Symbol('r'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) assert ls1[7] == Declaration( Variable( Symbol('s'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) assert ls2[8] == Assignment( Variable(Symbol('d')), Symbol('a') + Symbol('b') - Symbol('c') ) def test_assignment(): src1 = ( src + """\ a = b c = d p = q r = s """ ) expr1.convert_to_expr(src1, 'f') ls1 = expr1.return_expr() for iter in range(0, 12): if iter < 8: assert isinstance(ls1[iter], Declaration) else: assert isinstance(ls1[iter], Assignment) assert ls1[8] == Assignment( Variable(Symbol('a')), Variable(Symbol('b')) ) assert ls1[9] == Assignment( Variable(Symbol('c')), Variable(Symbol('d')) ) assert ls1[10] == Assignment( Variable(Symbol('p')), Variable(Symbol('q')) ) assert ls1[11] == Assignment( Variable(Symbol('r')), Variable(Symbol('s')) ) def test_binop_add(): src1 = ( src + """\ c = a + b d = a + c s = p + q + r """ ) expr1.convert_to_expr(src1, 'f') ls1 = expr1.return_expr() for iter in range(8, 11): assert isinstance(ls1[iter], Assignment) assert ls1[8] == Assignment( Variable(Symbol('c')), Symbol('a') + Symbol('b') ) assert ls1[9] == Assignment( Variable(Symbol('d')), Symbol('a') + Symbol('c') ) assert ls1[10] == Assignment( Variable(Symbol('s')), Symbol('p') + Symbol('q') + Symbol('r') ) def test_binop_sub(): src1 = ( src + """\ c = a - b d = a - c s = p - q - r """ ) expr1.convert_to_expr(src1, 'f') ls1 = expr1.return_expr() for iter in range(8, 11): assert isinstance(ls1[iter], Assignment) assert ls1[8] == Assignment( Variable(Symbol('c')), Symbol('a') - Symbol('b') ) assert ls1[9] == Assignment( Variable(Symbol('d')), Symbol('a') - Symbol('c') ) assert ls1[10] == Assignment( Variable(Symbol('s')), Symbol('p') - Symbol('q') - Symbol('r') ) def test_binop_mul(): src1 = ( src + """\ c = a * b d = a * c s = p * q * r """ ) expr1.convert_to_expr(src1, 'f') ls1 = expr1.return_expr() for iter in range(8, 11): assert isinstance(ls1[iter], Assignment) assert ls1[8] == Assignment( Variable(Symbol('c')), Symbol('a') * Symbol('b') ) assert ls1[9] == Assignment( Variable(Symbol('d')), Symbol('a') * Symbol('c') ) assert ls1[10] == Assignment( Variable(Symbol('s')), Symbol('p') * Symbol('q') * Symbol('r') ) def test_binop_div(): src1 = ( src + """\ c = a / b d = a / c s = p / q r = q / p """ ) expr1.convert_to_expr(src1, 'f') ls1 = expr1.return_expr() for iter in range(8, 12): assert isinstance(ls1[iter], Assignment) assert ls1[8] == Assignment( Variable(Symbol('c')), Symbol('a') / Symbol('b') ) assert ls1[9] == Assignment( Variable(Symbol('d')), Symbol('a') / Symbol('c') ) assert ls1[10] == Assignment( Variable(Symbol('s')), Symbol('p') / Symbol('q') ) assert ls1[11] == Assignment( Variable(Symbol('r')), Symbol('q') / Symbol('p') ) def test_mul_binop(): src1 = ( src + """\ d = a + b - c c = a * b + d s = p * q / r r = p * s + q / p """ ) expr1.convert_to_expr(src1, 'f') ls1 = expr1.return_expr() for iter in range(8, 12): assert isinstance(ls1[iter], Assignment) assert ls1[8] == Assignment( Variable(Symbol('d')), Symbol('a') + Symbol('b') - Symbol('c') ) assert ls1[9] == Assignment( Variable(Symbol('c')), Symbol('a') * Symbol('b') + Symbol('d') ) assert ls1[10] == Assignment( Variable(Symbol('s')), Symbol('p') * Symbol('q') / Symbol('r') ) assert ls1[11] == Assignment( Variable(Symbol('r')), Symbol('p') * Symbol('s') + Symbol('q') / Symbol('p') ) def test_function(): src1 = """\ integer function f(a,b) integer :: x, y f = x + y end function """ expr1.convert_to_expr(src1, 'f') for iter in expr1.return_expr(): assert isinstance(iter, FunctionDefinition) assert iter == FunctionDefinition( IntBaseType(String('integer')), name=String('f'), parameters=( Variable(Symbol('a')), Variable(Symbol('b')) ), body=CodeBlock( Declaration( Variable( Symbol('a'), type=IntBaseType(String('integer')), value=Integer(0) ) ), Declaration( Variable( Symbol('b'), type=IntBaseType(String('integer')), value=Integer(0) ) ), Declaration( Variable( Symbol('f'), type=IntBaseType(String('integer')), value=Integer(0) ) ), Declaration( Variable( Symbol('x'), type=IntBaseType(String('integer')), value=Integer(0) ) ), Declaration( Variable( Symbol('y'), type=IntBaseType(String('integer')), value=Integer(0) ) ), Assignment( Variable(Symbol('f')), Add(Symbol('x'), Symbol('y')) ), Return(Variable(Symbol('f'))) ) ) def test_var(): expr1.convert_to_expr(src, 'f') ls = expr1.return_expr() for iter in expr1.return_expr(): assert isinstance(iter, Declaration) assert ls[0] == Declaration( Variable( Symbol('a'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls[1] == Declaration( Variable( Symbol('b'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls[2] == Declaration( Variable( Symbol('c'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls[3] == Declaration( Variable( Symbol('d'), type = IntBaseType(String('integer')), value = Integer(0) ) ) assert ls[4] == Declaration( Variable( Symbol('p'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) assert ls[5] == Declaration( Variable( Symbol('q'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) assert ls[6] == Declaration( Variable( Symbol('r'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) assert ls[7] == Declaration( Variable( Symbol('s'), type = FloatBaseType(String('real')), value = Float(0.0) ) ) else: def test_raise(): from sympy.parsing.fortran.fortran_parser import ASR2PyVisitor raises(ImportError, lambda: ASR2PyVisitor()) raises(ImportError, lambda: SymPyExpression(' ', mode = 'f')) sympy-sympy-1.9/sympy/parsing/tests/test_implicit_multiplication_application.py000066400000000000000000000164311412543434000306410ustar00rootroot00000000000000import sympy from sympy.parsing.sympy_parser import ( parse_expr, standard_transformations, convert_xor, implicit_multiplication_application, implicit_multiplication, implicit_application, function_exponentiation, split_symbols, split_symbols_custom, _token_splittable ) from sympy.testing.pytest import raises def test_implicit_multiplication(): cases = { '5x': '5*x', 'abc': 'a*b*c', '3sin(x)': '3*sin(x)', '(x+1)(x+2)': '(x+1)*(x+2)', '(5 x**2)sin(x)': '(5*x**2)*sin(x)', '2 sin(x) cos(x)': '2*sin(x)*cos(x)', 'pi x': 'pi*x', 'x pi': 'x*pi', 'E x': 'E*x', 'EulerGamma y': 'EulerGamma*y', 'E pi': 'E*pi', 'pi (x + 2)': 'pi*(x+2)', '(x + 2) pi': '(x+2)*pi', 'pi sin(x)': 'pi*sin(x)', } transformations = standard_transformations + (convert_xor,) transformations2 = transformations + (split_symbols, implicit_multiplication) for case in cases: implicit = parse_expr(case, transformations=transformations2) normal = parse_expr(cases[case], transformations=transformations) assert(implicit == normal) application = ['sin x', 'cos 2*x', 'sin cos x'] for case in application: raises(SyntaxError, lambda: parse_expr(case, transformations=transformations2)) raises(TypeError, lambda: parse_expr('sin**2(x)', transformations=transformations2)) def test_implicit_application(): cases = { 'factorial': 'factorial', 'sin x': 'sin(x)', 'tan y**3': 'tan(y**3)', 'cos 2*x': 'cos(2*x)', '(cot)': 'cot', 'sin cos tan x': 'sin(cos(tan(x)))' } transformations = standard_transformations + (convert_xor,) transformations2 = transformations + (implicit_application,) for case in cases: implicit = parse_expr(case, transformations=transformations2) normal = parse_expr(cases[case], transformations=transformations) assert(implicit == normal), (implicit, normal) multiplication = ['x y', 'x sin x', '2x'] for case in multiplication: raises(SyntaxError, lambda: parse_expr(case, transformations=transformations2)) raises(TypeError, lambda: parse_expr('sin**2(x)', transformations=transformations2)) def test_function_exponentiation(): cases = { 'sin**2(x)': 'sin(x)**2', 'exp^y(z)': 'exp(z)^y', 'sin**2(E^(x))': 'sin(E^(x))**2' } transformations = standard_transformations + (convert_xor,) transformations2 = transformations + (function_exponentiation,) for case in cases: implicit = parse_expr(case, transformations=transformations2) normal = parse_expr(cases[case], transformations=transformations) assert(implicit == normal) other_implicit = ['x y', 'x sin x', '2x', 'sin x', 'cos 2*x', 'sin cos x'] for case in other_implicit: raises(SyntaxError, lambda: parse_expr(case, transformations=transformations2)) assert parse_expr('x**2', local_dict={ 'x': sympy.Symbol('x') }, transformations=transformations2) == parse_expr('x**2') def test_symbol_splitting(): # By default Greek letter names should not be split (lambda is a keyword # so skip it) transformations = standard_transformations + (split_symbols,) greek_letters = ('alpha', 'beta', 'gamma', 'delta', 'epsilon', 'zeta', 'eta', 'theta', 'iota', 'kappa', 'mu', 'nu', 'xi', 'omicron', 'pi', 'rho', 'sigma', 'tau', 'upsilon', 'phi', 'chi', 'psi', 'omega') for letter in greek_letters: assert(parse_expr(letter, transformations=transformations) == parse_expr(letter)) # Make sure symbol splitting resolves names transformations += (implicit_multiplication,) local_dict = { 'e': sympy.E } cases = { 'xe': 'E*x', 'Iy': 'I*y', 'ee': 'E*E', } for case, expected in cases.items(): assert(parse_expr(case, local_dict=local_dict, transformations=transformations) == parse_expr(expected)) # Make sure custom splitting works def can_split(symbol): if symbol not in ('unsplittable', 'names'): return _token_splittable(symbol) return False transformations = standard_transformations transformations += (split_symbols_custom(can_split), implicit_multiplication) assert(parse_expr('unsplittable', transformations=transformations) == parse_expr('unsplittable')) assert(parse_expr('names', transformations=transformations) == parse_expr('names')) assert(parse_expr('xy', transformations=transformations) == parse_expr('x*y')) for letter in greek_letters: assert(parse_expr(letter, transformations=transformations) == parse_expr(letter)) def test_all_implicit_steps(): cases = { '2x': '2*x', # implicit multiplication 'x y': 'x*y', 'xy': 'x*y', 'sin x': 'sin(x)', # add parentheses '2sin x': '2*sin(x)', 'x y z': 'x*y*z', 'sin(2 * 3x)': 'sin(2 * 3 * x)', 'sin(x) (1 + cos(x))': 'sin(x) * (1 + cos(x))', '(x + 2) sin(x)': '(x + 2) * sin(x)', '(x + 2) sin x': '(x + 2) * sin(x)', 'sin(sin x)': 'sin(sin(x))', 'sin x!': 'sin(factorial(x))', 'sin x!!': 'sin(factorial2(x))', 'factorial': 'factorial', # don't apply a bare function 'x sin x': 'x * sin(x)', # both application and multiplication 'xy sin x': 'x * y * sin(x)', '(x+2)(x+3)': '(x + 2) * (x+3)', 'x**2 + 2xy + y**2': 'x**2 + 2 * x * y + y**2', # split the xy 'pi': 'pi', # don't mess with constants 'None': 'None', 'ln sin x': 'ln(sin(x))', # multiple implicit function applications 'factorial': 'factorial', # don't add parentheses 'sin x**2': 'sin(x**2)', # implicit application to an exponential 'alpha': 'Symbol("alpha")', # don't split Greek letters/subscripts 'x_2': 'Symbol("x_2")', 'sin^2 x**2': 'sin(x**2)**2', # function raised to a power 'sin**3(x)': 'sin(x)**3', '(factorial)': 'factorial', 'tan 3x': 'tan(3*x)', 'sin^2(3*E^(x))': 'sin(3*E**(x))**2', 'sin**2(E^(3x))': 'sin(E**(3*x))**2', 'sin^2 (3x*E^(x))': 'sin(3*x*E^x)**2', 'pi sin x': 'pi*sin(x)', } transformations = standard_transformations + (convert_xor,) transformations2 = transformations + (implicit_multiplication_application,) for case in cases: implicit = parse_expr(case, transformations=transformations2) normal = parse_expr(cases[case], transformations=transformations) assert(implicit == normal) def test_no_methods_implicit_multiplication(): # Issue 21020 u = sympy.Symbol('u') transformations = standard_transformations + \ (implicit_multiplication,) expr = parse_expr('x.is_polynomial(x)', transformations=transformations) assert expr == True expr = parse_expr('(exp(x) / (1 + exp(2x))).subs(exp(x), u)', transformations=transformations) assert expr == u/(u**2 + 1) sympy-sympy-1.9/sympy/parsing/tests/test_latex.py000066400000000000000000000233601412543434000224430ustar00rootroot00000000000000from sympy.testing.pytest import raises, XFAIL from sympy.external import import_module from sympy import ( Symbol, Mul, Add, Abs, sin, asin, cos, Pow, csc, sec, Limit, oo, Derivative, Integral, factorial, sqrt, root, conjugate, StrictLessThan, LessThan, StrictGreaterThan, GreaterThan, Sum, Product, E, log, tan, Function, binomial, exp, floor, ceiling, Unequality ) from sympy.core.relational import Eq, Ne, Lt, Le, Gt, Ge from sympy.physics.quantum.state import Bra, Ket from sympy.abc import x, y, z, a, b, c, t, k, n antlr4 = import_module("antlr4") # disable tests if antlr4-python*-runtime is not present if not antlr4: disabled = True theta = Symbol('theta') f = Function('f') # shorthand definitions def _Add(a, b): return Add(a, b, evaluate=False) def _Mul(a, b): return Mul(a, b, evaluate=False) def _Pow(a, b): return Pow(a, b, evaluate=False) def _Sqrt(a): return sqrt(a, evaluate=False) def _Conjugate(a): return conjugate(a, evaluate=False) def _Abs(a): return Abs(a, evaluate=False) def _factorial(a): return factorial(a, evaluate=False) def _exp(a): return exp(a, evaluate=False) def _log(a, b): return log(a, b, evaluate=False) def _binomial(n, k): return binomial(n, k, evaluate=False) def test_import(): from sympy.parsing.latex._build_latex_antlr import ( build_parser, check_antlr_version, dir_latex_antlr ) # XXX: It would be better to come up with a test for these... del build_parser, check_antlr_version, dir_latex_antlr # These LaTeX strings should parse to the corresponding SymPy expression GOOD_PAIRS = [ (r"0", 0), (r"1", 1), (r"-3.14", -3.14), (r"(-7.13)(1.5)", _Mul(-7.13, 1.5)), (r"x", x), (r"2x", 2*x), (r"x^2", x**2), (r"x^{3 + 1}", x**_Add(3, 1)), (r"-c", -c), (r"a \cdot b", a * b), (r"a / b", a / b), (r"a \div b", a / b), (r"a + b", a + b), (r"a + b - a", _Add(a+b, -a)), (r"a^2 + b^2 = c^2", Eq(a**2 + b**2, c**2)), (r"(x + y) z", _Mul(_Add(x, y), z)), (r"\left(x + y\right) z", _Mul(_Add(x, y), z)), (r"\left( x + y\right ) z", _Mul(_Add(x, y), z)), (r"\left( x + y\right ) z", _Mul(_Add(x, y), z)), (r"\left[x + y\right] z", _Mul(_Add(x, y), z)), (r"\left\{x + y\right\} z", _Mul(_Add(x, y), z)), (r"1+1", _Add(1, 1)), (r"0+1", _Add(0, 1)), (r"1*2", _Mul(1, 2)), (r"0*1", _Mul(0, 1)), (r"x = y", Eq(x, y)), (r"x \neq y", Ne(x, y)), (r"x < y", Lt(x, y)), (r"x > y", Gt(x, y)), (r"x \leq y", Le(x, y)), (r"x \geq y", Ge(x, y)), (r"x \le y", Le(x, y)), (r"x \ge y", Ge(x, y)), (r"\lfloor x \rfloor", floor(x)), (r"\lceil x \rceil", ceiling(x)), (r"\langle x |", Bra('x')), (r"| x \rangle", Ket('x')), (r"\sin \theta", sin(theta)), (r"\sin(\theta)", sin(theta)), (r"\sin^{-1} a", asin(a)), (r"\sin a \cos b", _Mul(sin(a), cos(b))), (r"\sin \cos \theta", sin(cos(theta))), (r"\sin(\cos \theta)", sin(cos(theta))), (r"\frac{a}{b}", a / b), (r"\frac{a + b}{c}", _Mul(a + b, _Pow(c, -1))), (r"\frac{7}{3}", _Mul(7, _Pow(3, -1))), (r"(\csc x)(\sec y)", csc(x)*sec(y)), (r"\lim_{x \to 3} a", Limit(a, x, 3)), (r"\lim_{x \rightarrow 3} a", Limit(a, x, 3)), (r"\lim_{x \Rightarrow 3} a", Limit(a, x, 3)), (r"\lim_{x \longrightarrow 3} a", Limit(a, x, 3)), (r"\lim_{x \Longrightarrow 3} a", Limit(a, x, 3)), (r"\lim_{x \to 3^{+}} a", Limit(a, x, 3, dir='+')), (r"\lim_{x \to 3^{-}} a", Limit(a, x, 3, dir='-')), (r"\infty", oo), (r"\lim_{x \to \infty} \frac{1}{x}", Limit(_Pow(x, -1), x, oo)), (r"\frac{d}{dx} x", Derivative(x, x)), (r"\frac{d}{dt} x", Derivative(x, t)), (r"f(x)", f(x)), (r"f(x, y)", f(x, y)), (r"f(x, y, z)", f(x, y, z)), (r"\frac{d f(x)}{dx}", Derivative(f(x), x)), (r"\frac{d\theta(x)}{dx}", Derivative(Function('theta')(x), x)), (r"x \neq y", Unequality(x, y)), (r"|x|", _Abs(x)), (r"||x||", _Abs(Abs(x))), (r"|x||y|", _Abs(x)*_Abs(y)), (r"||x||y||", _Abs(_Abs(x)*_Abs(y))), (r"\pi^{|xy|}", Symbol('pi')**_Abs(x*y)), (r"\int x dx", Integral(x, x)), (r"\int x d\theta", Integral(x, theta)), (r"\int (x^2 - y)dx", Integral(x**2 - y, x)), (r"\int x + a dx", Integral(_Add(x, a), x)), (r"\int da", Integral(1, a)), (r"\int_0^7 dx", Integral(1, (x, 0, 7))), (r"\int_a^b x dx", Integral(x, (x, a, b))), (r"\int^b_a x dx", Integral(x, (x, a, b))), (r"\int_{a}^b x dx", Integral(x, (x, a, b))), (r"\int^{b}_a x dx", Integral(x, (x, a, b))), (r"\int_{a}^{b} x dx", Integral(x, (x, a, b))), (r"\int^{b}_{a} x dx", Integral(x, (x, a, b))), (r"\int_{f(a)}^{f(b)} f(z) dz", Integral(f(z), (z, f(a), f(b)))), (r"\int (x+a)", Integral(_Add(x, a), x)), (r"\int a + b + c dx", Integral(_Add(_Add(a, b), c), x)), (r"\int \frac{dz}{z}", Integral(Pow(z, -1), z)), (r"\int \frac{3 dz}{z}", Integral(3*Pow(z, -1), z)), (r"\int \frac{1}{x} dx", Integral(Pow(x, -1), x)), (r"\int \frac{1}{a} + \frac{1}{b} dx", Integral(_Add(_Pow(a, -1), Pow(b, -1)), x)), (r"\int \frac{3 \cdot d\theta}{\theta}", Integral(3*_Pow(theta, -1), theta)), (r"\int \frac{1}{x} + 1 dx", Integral(_Add(_Pow(x, -1), 1), x)), (r"x_0", Symbol('x_{0}')), (r"x_{1}", Symbol('x_{1}')), (r"x_a", Symbol('x_{a}')), (r"x_{b}", Symbol('x_{b}')), (r"h_\theta", Symbol('h_{theta}')), (r"h_{\theta}", Symbol('h_{theta}')), (r"h_{\theta}(x_0, x_1)", Function('h_{theta}')(Symbol('x_{0}'), Symbol('x_{1}'))), (r"x!", _factorial(x)), (r"100!", _factorial(100)), (r"\theta!", _factorial(theta)), (r"(x + 1)!", _factorial(_Add(x, 1))), (r"(x!)!", _factorial(_factorial(x))), (r"x!!!", _factorial(_factorial(_factorial(x)))), (r"5!7!", _Mul(_factorial(5), _factorial(7))), (r"\sqrt{x}", sqrt(x)), (r"\sqrt{x + b}", sqrt(_Add(x, b))), (r"\sqrt[3]{\sin x}", root(sin(x), 3)), (r"\sqrt[y]{\sin x}", root(sin(x), y)), (r"\sqrt[\theta]{\sin x}", root(sin(x), theta)), (r"\sqrt{\frac{12}{6}}", _Sqrt(_Mul(12, _Pow(6, -1)))), (r"\overline{z}", _Conjugate(z)), (r"\overline{\overline{z}}", _Conjugate(_Conjugate(z))), (r"\overline{x + y}", _Conjugate(_Add(x, y))), (r"\overline{x} + \overline{y}", _Conjugate(x) + _Conjugate(y)), (r"x < y", StrictLessThan(x, y)), (r"x \leq y", LessThan(x, y)), (r"x > y", StrictGreaterThan(x, y)), (r"x \geq y", GreaterThan(x, y)), (r"\mathit{x}", Symbol('x')), (r"\mathit{test}", Symbol('test')), (r"\mathit{TEST}", Symbol('TEST')), (r"\mathit{HELLO world}", Symbol('HELLO world')), (r"\sum_{k = 1}^{3} c", Sum(c, (k, 1, 3))), (r"\sum_{k = 1}^3 c", Sum(c, (k, 1, 3))), (r"\sum^{3}_{k = 1} c", Sum(c, (k, 1, 3))), (r"\sum^3_{k = 1} c", Sum(c, (k, 1, 3))), (r"\sum_{k = 1}^{10} k^2", Sum(k**2, (k, 1, 10))), (r"\sum_{n = 0}^{\infty} \frac{1}{n!}", Sum(_Pow(_factorial(n), -1), (n, 0, oo))), (r"\prod_{a = b}^{c} x", Product(x, (a, b, c))), (r"\prod_{a = b}^c x", Product(x, (a, b, c))), (r"\prod^{c}_{a = b} x", Product(x, (a, b, c))), (r"\prod^c_{a = b} x", Product(x, (a, b, c))), (r"\exp x", _exp(x)), (r"\exp(x)", _exp(x)), (r"\ln x", _log(x, E)), (r"\ln xy", _log(x*y, E)), (r"\log x", _log(x, 10)), (r"\log xy", _log(x*y, 10)), (r"\log_{2} x", _log(x, 2)), (r"\log_{a} x", _log(x, a)), (r"\log_{11} x", _log(x, 11)), (r"\log_{a^2} x", _log(x, _Pow(a, 2))), (r"[x]", x), (r"[a + b]", _Add(a, b)), (r"\frac{d}{dx} [ \tan x ]", Derivative(tan(x), x)), (r"\binom{n}{k}", _binomial(n, k)), (r"\tbinom{n}{k}", _binomial(n, k)), (r"\dbinom{n}{k}", _binomial(n, k)), (r"\binom{n}{0}", _binomial(n, 0)), (r"a \, b", _Mul(a, b)), (r"a \thinspace b", _Mul(a, b)), (r"a \: b", _Mul(a, b)), (r"a \medspace b", _Mul(a, b)), (r"a \; b", _Mul(a, b)), (r"a \thickspace b", _Mul(a, b)), (r"a \quad b", _Mul(a, b)), (r"a \qquad b", _Mul(a, b)), (r"a \! b", _Mul(a, b)), (r"a \negthinspace b", _Mul(a, b)), (r"a \negmedspace b", _Mul(a, b)), (r"a \negthickspace b", _Mul(a, b)), (r"\int x \, dx", Integral(x, x)), (r"\log_2 x", _log(x, 2)), (r"\log_a x", _log(x, a)), (r"5^0 - 4^0", _Add(_Pow(5, 0), _Mul(-1, _Pow(4, 0)))), ] def test_parseable(): from sympy.parsing.latex import parse_latex for latex_str, sympy_expr in GOOD_PAIRS: assert parse_latex(latex_str) == sympy_expr, latex_str # These bad LaTeX strings should raise a LaTeXParsingError when parsed BAD_STRINGS = [ r"(", r")", r"\frac{d}{dx}", r"(\frac{d}{dx})", r"\sqrt{}", r"\sqrt", r"\overline{}", r"\overline", r"{", r"}", r"\mathit{x + y}", r"\mathit{21}", r"\frac{2}{}", r"\frac{}{2}", r"\int", r"!", r"!0", r"_", r"^", r"|", r"||x|", r"()", r"((((((((((((((((()))))))))))))))))", r"-", r"\frac{d}{dx} + \frac{d}{dt}", r"f(x,,y)", r"f(x,y,", r"\sin^x", r"\cos^2", r"@", r"#", r"$", r"%", r"&", r"*", r"" "\\", r"~", r"\frac{(2 + x}{1 - x)}", ] def test_not_parseable(): from sympy.parsing.latex import parse_latex, LaTeXParsingError for latex_str in BAD_STRINGS: with raises(LaTeXParsingError): parse_latex(latex_str) # At time of migration from latex2sympy, should fail but doesn't FAILING_BAD_STRINGS = [ r"\cos 1 \cos", r"f(,", r"f()", r"a \div \div b", r"a \cdot \cdot b", r"a // b", r"a +", r"1.1.1", r"1 +", r"a / b /", ] @XFAIL def test_failing_not_parseable(): from sympy.parsing.latex import parse_latex, LaTeXParsingError for latex_str in FAILING_BAD_STRINGS: with raises(LaTeXParsingError): parse_latex(latex_str) sympy-sympy-1.9/sympy/parsing/tests/test_latex_deps.py000066400000000000000000000006521412543434000234550ustar00rootroot00000000000000from sympy.external import import_module from sympy.testing.pytest import ignore_warnings, raises antlr4 = import_module("antlr4", warn_not_installed=False) # disable tests if antlr4-python*-runtime is not present if antlr4: disabled = True def test_no_import(): from sympy.parsing.latex import parse_latex with ignore_warnings(UserWarning): with raises(ImportError): parse_latex('1 + 1') sympy-sympy-1.9/sympy/parsing/tests/test_mathematica.py000066400000000000000000000043601412543434000236020ustar00rootroot00000000000000from sympy.parsing.mathematica import mathematica from sympy import sympify def test_mathematica(): d = { '- 6x': '-6*x', 'Sin[x]^2': 'sin(x)**2', '2(x-1)': '2*(x-1)', '3y+8': '3*y+8', 'ArcSin[2x+9(4-x)^2]/x': 'asin(2*x+9*(4-x)**2)/x', 'x+y': 'x+y', '355/113': '355/113', '2.718281828': '2.718281828', 'Sin[12]': 'sin(12)', 'Exp[Log[4]]': 'exp(log(4))', '(x+1)(x+3)': '(x+1)*(x+3)', 'Cos[ArcCos[3.6]]': 'cos(acos(3.6))', 'Cos[x]==Sin[y]': 'cos(x)==sin(y)', '2*Sin[x+y]': '2*sin(x+y)', 'Sin[x]+Cos[y]': 'sin(x)+cos(y)', 'Sin[Cos[x]]': 'sin(cos(x))', '2*Sqrt[x+y]': '2*sqrt(x+y)', # Test case from the issue 4259 '+Sqrt[2]': 'sqrt(2)', '-Sqrt[2]': '-sqrt(2)', '-1/Sqrt[2]': '-1/sqrt(2)', '-(1/Sqrt[3])': '-(1/sqrt(3))', '1/(2*Sqrt[5])': '1/(2*sqrt(5))', 'Mod[5,3]': 'Mod(5,3)', '-Mod[5,3]': '-Mod(5,3)', '(x+1)y': '(x+1)*y', 'x(y+1)': 'x*(y+1)', 'Sin[x]Cos[y]': 'sin(x)*cos(y)', 'Sin[x]**2Cos[y]**2': 'sin(x)**2*cos(y)**2', 'Cos[x]^2(1 - Cos[y]^2)': 'cos(x)**2*(1-cos(y)**2)', 'x y': 'x*y', '2 x': '2*x', 'x 8': 'x*8', '2 8': '2*8', '1 2 3': '1*2*3', ' - 2 * Sqrt[ 2 3 * ( 1 + 5 ) ] ': '-2*sqrt(2*3*(1+5))', 'Log[2,4]': 'log(4,2)', 'Log[Log[2,4],4]': 'log(4,log(4,2))', 'Exp[Sqrt[2]^2Log[2, 8]]': 'exp(sqrt(2)**2*log(8,2))', 'ArcSin[Cos[0]]': 'asin(cos(0))', 'Log2[16]': 'log(16,2)', 'Max[1,-2,3,-4]': 'Max(1,-2,3,-4)', 'Min[1,-2,3]': 'Min(1,-2,3)', 'Exp[I Pi/2]': 'exp(I*pi/2)', 'ArcTan[x,y]': 'atan2(y,x)', 'Pochhammer[x,y]': 'rf(x,y)', 'ExpIntegralEi[x]': 'Ei(x)', 'SinIntegral[x]': 'Si(x)', 'CosIntegral[x]': 'Ci(x)', 'AiryAi[x]': 'airyai(x)', 'AiryAiPrime[5]': 'airyaiprime(5)', 'AiryBi[x]' :'airybi(x)', 'AiryBiPrime[7]' :'airybiprime(7)', 'LogIntegral[4]':' li(4)', 'PrimePi[7]': 'primepi(7)', 'Prime[5]': 'prime(5)', 'PrimeQ[5]': 'isprime(5)' } for e in d: assert mathematica(e) == sympify(d[e]) sympy-sympy-1.9/sympy/parsing/tests/test_maxima.py000066400000000000000000000033071412543434000226010ustar00rootroot00000000000000from sympy.parsing.maxima import parse_maxima from sympy import Rational, Abs, Symbol, sin, cos, E, oo, log, factorial from sympy.abc import x n = Symbol('n', integer=True) def test_parser(): assert Abs(parse_maxima('float(1/3)') - 0.333333333) < 10**(-5) assert parse_maxima('13^26') == 91733330193268616658399616009 assert parse_maxima('sin(%pi/2) + cos(%pi/3)') == Rational(3, 2) assert parse_maxima('log(%e)') == 1 def test_injection(): parse_maxima('c: x+1', globals=globals()) # c created by parse_maxima assert c == x + 1 # noqa:F821 parse_maxima('g: sqrt(81)', globals=globals()) # g created by parse_maxima assert g == 9 # noqa:F821 def test_maxima_functions(): assert parse_maxima('expand( (x+1)^2)') == x**2 + 2*x + 1 assert parse_maxima('factor( x**2 + 2*x + 1)') == (x + 1)**2 assert parse_maxima('2*cos(x)^2 + sin(x)^2') == 2*cos(x)**2 + sin(x)**2 assert parse_maxima('trigexpand(sin(2*x)+cos(2*x))') == \ -1 + 2*cos(x)**2 + 2*cos(x)*sin(x) assert parse_maxima('solve(x^2-4,x)') == [-2, 2] assert parse_maxima('limit((1+1/x)^x,x,inf)') == E assert parse_maxima('limit(sqrt(-x)/x,x,0,minus)') is -oo assert parse_maxima('diff(x^x, x)') == x**x*(1 + log(x)) assert parse_maxima('sum(k, k, 1, n)', name_dict=dict( n=Symbol('n', integer=True), k=Symbol('k', integer=True) )) == (n**2 + n)/2 assert parse_maxima('product(k, k, 1, n)', name_dict=dict( n=Symbol('n', integer=True), k=Symbol('k', integer=True) )) == factorial(n) assert parse_maxima('ratsimp((x^2-1)/(x+1))') == x - 1 assert Abs( parse_maxima( 'float(sec(%pi/3) + csc(%pi/3))') - 3.154700538379252) < 10**(-5) sympy-sympy-1.9/sympy/parsing/tests/test_sym_expr.py000066400000000000000000000130311412543434000231660ustar00rootroot00000000000000from sympy.parsing.sym_expr import SymPyExpression from sympy.testing.pytest import raises from sympy.external import import_module lfortran = import_module('lfortran') cin = import_module('clang.cindex', import_kwargs = {'fromlist': ['cindex']}) if lfortran and cin: from sympy.codegen.ast import (Variable, IntBaseType, FloatBaseType, String, Declaration, FloatType) from sympy.core import Integer, Float from sympy import Symbol expr1 = SymPyExpression() src = """\ integer :: a, b, c, d real :: p, q, r, s """ def test_c_parse(): src1 = """\ int a, b = 4; float c, d = 2.4; """ expr1.convert_to_expr(src1, 'c') ls = expr1.return_expr() assert ls[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('intc')) ) ) assert ls[1] == Declaration( Variable( Symbol('b'), type=IntBaseType(String('intc')), value=Integer(4) ) ) assert ls[2] == Declaration( Variable( Symbol('c'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ) ) ) assert ls[3] == Declaration( Variable( Symbol('d'), type=FloatType( String('float32'), nbits=Integer(32), nmant=Integer(23), nexp=Integer(8) ), value=Float('2.3999999999999999', precision=53) ) ) def test_fortran_parse(): expr = SymPyExpression(src, 'f') ls = expr.return_expr() assert ls[0] == Declaration( Variable( Symbol('a'), type=IntBaseType(String('integer')), value=Integer(0) ) ) assert ls[1] == Declaration( Variable( Symbol('b'), type=IntBaseType(String('integer')), value=Integer(0) ) ) assert ls[2] == Declaration( Variable( Symbol('c'), type=IntBaseType(String('integer')), value=Integer(0) ) ) assert ls[3] == Declaration( Variable( Symbol('d'), type=IntBaseType(String('integer')), value=Integer(0) ) ) assert ls[4] == Declaration( Variable( Symbol('p'), type=FloatBaseType(String('real')), value=Float('0.0', precision=53) ) ) assert ls[5] == Declaration( Variable( Symbol('q'), type=FloatBaseType(String('real')), value=Float('0.0', precision=53) ) ) assert ls[6] == Declaration( Variable( Symbol('r'), type=FloatBaseType(String('real')), value=Float('0.0', precision=53) ) ) assert ls[7] == Declaration( Variable( Symbol('s'), type=FloatBaseType(String('real')), value=Float('0.0', precision=53) ) ) def test_convert_py(): src1 = ( src + """\ a = b + c s = p * q / r """ ) expr1.convert_to_expr(src1, 'f') exp_py = expr1.convert_to_python() assert exp_py == [ 'a = 0', 'b = 0', 'c = 0', 'd = 0', 'p = 0.0', 'q = 0.0', 'r = 0.0', 's = 0.0', 'a = b + c', 's = p*q/r' ] def test_convert_fort(): src1 = ( src + """\ a = b + c s = p * q / r """ ) expr1.convert_to_expr(src1, 'f') exp_fort = expr1.convert_to_fortran() assert exp_fort == [ ' integer*4 a', ' integer*4 b', ' integer*4 c', ' integer*4 d', ' real*8 p', ' real*8 q', ' real*8 r', ' real*8 s', ' a = b + c', ' s = p*q/r' ] def test_convert_c(): src1 = ( src + """\ a = b + c s = p * q / r """ ) expr1.convert_to_expr(src1, 'f') exp_c = expr1.convert_to_c() assert exp_c == [ 'int a = 0', 'int b = 0', 'int c = 0', 'int d = 0', 'double p = 0.0', 'double q = 0.0', 'double r = 0.0', 'double s = 0.0', 'a = b + c;', 's = p*q/r;' ] def test_exceptions(): src = 'int a;' raises(ValueError, lambda: SymPyExpression(src)) raises(ValueError, lambda: SymPyExpression(mode = 'c')) raises(NotImplementedError, lambda: SymPyExpression(src, mode = 'd')) elif not lfortran and not cin: def test_raise(): raises(ImportError, lambda: SymPyExpression('int a;', 'c')) raises(ImportError, lambda: SymPyExpression('integer :: a', 'f')) sympy-sympy-1.9/sympy/parsing/tests/test_sympy_parser.py000066400000000000000000000222371412543434000240650ustar00rootroot00000000000000# -*- coding: utf-8 -*- import sys from sympy.assumptions import Q from sympy.core import Symbol, Function, Float, Rational, Integer, I, Mul, Pow, Eq from sympy.functions import exp, factorial, factorial2, sin from sympy.logic import And from sympy.series import Limit from sympy.testing.pytest import raises, skip from sympy.parsing.sympy_parser import ( parse_expr, standard_transformations, rationalize, TokenError, split_symbols, implicit_multiplication, convert_equals_signs, convert_xor, function_exponentiation, implicit_multiplication_application, ) def test_sympy_parser(): x = Symbol('x') inputs = { '2*x': 2 * x, '3.00': Float(3), '22/7': Rational(22, 7), '2+3j': 2 + 3*I, 'exp(x)': exp(x), 'x!': factorial(x), 'x!!': factorial2(x), '(x + 1)! - 1': factorial(x + 1) - 1, '3.[3]': Rational(10, 3), '.0[3]': Rational(1, 30), '3.2[3]': Rational(97, 30), '1.3[12]': Rational(433, 330), '1 + 3.[3]': Rational(13, 3), '1 + .0[3]': Rational(31, 30), '1 + 3.2[3]': Rational(127, 30), '.[0011]': Rational(1, 909), '0.1[00102] + 1': Rational(366697, 333330), '1.[0191]': Rational(10190, 9999), '10!': 3628800, '-(2)': -Integer(2), '[-1, -2, 3]': [Integer(-1), Integer(-2), Integer(3)], 'Symbol("x").free_symbols': x.free_symbols, "S('S(3).n(n=3)')": 3.00, 'factorint(12, visual=True)': Mul( Pow(2, 2, evaluate=False), Pow(3, 1, evaluate=False), evaluate=False), 'Limit(sin(x), x, 0, dir="-")': Limit(sin(x), x, 0, dir='-'), 'Q.even(x)': Q.even(x), } for text, result in inputs.items(): assert parse_expr(text) == result raises(TypeError, lambda: parse_expr('x', standard_transformations)) raises(TypeError, lambda: parse_expr('x', transformations=lambda x,y: 1)) raises(TypeError, lambda: parse_expr('x', transformations=(lambda x,y: 1,))) raises(TypeError, lambda: parse_expr('x', transformations=((),))) raises(TypeError, lambda: parse_expr('x', {}, [], [])) raises(TypeError, lambda: parse_expr('x', [], [], {})) raises(TypeError, lambda: parse_expr('x', [], [], {})) def test_rationalize(): inputs = { '0.123': Rational(123, 1000) } transformations = standard_transformations + (rationalize,) for text, result in inputs.items(): assert parse_expr(text, transformations=transformations) == result def test_factorial_fail(): inputs = ['x!!!', 'x!!!!', '(!)'] for text in inputs: try: parse_expr(text) assert False except TokenError: assert True def test_repeated_fail(): inputs = ['1[1]', '.1e1[1]', '0x1[1]', '1.1j[1]', '1.1[1 + 1]', '0.1[[1]]', '0x1.1[1]'] # All are valid Python, so only raise TypeError for invalid indexing for text in inputs: raises(TypeError, lambda: parse_expr(text)) inputs = ['0.1[', '0.1[1', '0.1[]'] for text in inputs: raises((TokenError, SyntaxError), lambda: parse_expr(text)) def test_repeated_dot_only(): assert parse_expr('.[1]') == Rational(1, 9) assert parse_expr('1 + .[1]') == Rational(10, 9) def test_local_dict(): local_dict = { 'my_function': lambda x: x + 2 } inputs = { 'my_function(2)': Integer(4) } for text, result in inputs.items(): assert parse_expr(text, local_dict=local_dict) == result def test_local_dict_split_implmult(): t = standard_transformations + (split_symbols, implicit_multiplication,) w = Symbol('w', real=True) y = Symbol('y') assert parse_expr('yx', local_dict={'x':w}, transformations=t) == y*w def test_local_dict_symbol_to_fcn(): x = Symbol('x') d = {'foo': Function('bar')} assert parse_expr('foo(x)', local_dict=d) == d['foo'](x) d = {'foo': Symbol('baz')} raises(TypeError, lambda: parse_expr('foo(x)', local_dict=d)) def test_global_dict(): global_dict = { 'Symbol': Symbol } inputs = { 'Q & S': And(Symbol('Q'), Symbol('S')) } for text, result in inputs.items(): assert parse_expr(text, global_dict=global_dict) == result def test_issue_2515(): raises(TokenError, lambda: parse_expr('(()')) raises(TokenError, lambda: parse_expr('"""')) def test_issue_7663(): x = Symbol('x') e = '2*(x+1)' assert parse_expr(e, evaluate=0) == parse_expr(e, evaluate=False) assert parse_expr(e, evaluate=0).equals(2*(x+1)) def test_recursive_evaluate_false_10560(): inputs = { '4*-3' : '4*-3', '-4*3' : '(-4)*3', "-2*x*y": '(-2)*x*y', "x*-4*x": "x*(-4)*x" } for text, result in inputs.items(): assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False) def test_function_evaluate_false(): inputs = [ 'Abs(0)', 'im(0)', 're(0)', 'sign(0)', 'arg(0)', 'conjugate(0)', 'acos(0)', 'acot(0)', 'acsc(0)', 'asec(0)', 'asin(0)', 'atan(0)', 'acosh(0)', 'acoth(0)', 'acsch(0)', 'asech(0)', 'asinh(0)', 'atanh(0)', 'cos(0)', 'cot(0)', 'csc(0)', 'sec(0)', 'sin(0)', 'tan(0)', 'cosh(0)', 'coth(0)', 'csch(0)', 'sech(0)', 'sinh(0)', 'tanh(0)', 'exp(0)', 'log(0)', 'sqrt(0)', ] for case in inputs: expr = parse_expr(case, evaluate=False) assert case == str(expr) != str(expr.doit()) assert str(parse_expr('ln(0)', evaluate=False)) == 'log(0)' assert str(parse_expr('cbrt(0)', evaluate=False)) == '0**(1/3)' def test_issue_10773(): inputs = { '-10/5': '(-10)/5', '-10/-5' : '(-10)/(-5)', } for text, result in inputs.items(): assert parse_expr(text, evaluate=False) == parse_expr(result, evaluate=False) def test_split_symbols(): transformations = standard_transformations + \ (split_symbols, implicit_multiplication,) x = Symbol('x') y = Symbol('y') xy = Symbol('xy') assert parse_expr("xy") == xy assert parse_expr("xy", transformations=transformations) == x*y def test_split_symbols_function(): transformations = standard_transformations + \ (split_symbols, implicit_multiplication,) x = Symbol('x') y = Symbol('y') a = Symbol('a') f = Function('f') assert parse_expr("ay(x+1)", transformations=transformations) == a*y*(x+1) assert parse_expr("af(x+1)", transformations=transformations, local_dict={'f':f}) == a*f(x+1) def test_functional_exponent(): t = standard_transformations + (convert_xor, function_exponentiation) x = Symbol('x') y = Symbol('y') a = Symbol('a') yfcn = Function('y') assert parse_expr("sin^2(x)", transformations=t) == (sin(x))**2 assert parse_expr("sin^y(x)", transformations=t) == (sin(x))**y assert parse_expr("exp^y(x)", transformations=t) == (exp(x))**y assert parse_expr("E^y(x)", transformations=t) == exp(yfcn(x)) assert parse_expr("a^y(x)", transformations=t) == a**(yfcn(x)) def test_match_parentheses_implicit_multiplication(): transformations = standard_transformations + \ (implicit_multiplication,) raises(TokenError, lambda: parse_expr('(1,2),(3,4]',transformations=transformations)) def test_convert_equals_signs(): transformations = standard_transformations + \ (convert_equals_signs, ) x = Symbol('x') y = Symbol('y') assert parse_expr("1*2=x", transformations=transformations) == Eq(2, x) assert parse_expr("y = x", transformations=transformations) == Eq(y, x) assert parse_expr("(2*y = x) = False", transformations=transformations) == Eq(Eq(2*y, x), False) def test_parse_function_issue_3539(): x = Symbol('x') f = Function('f') assert parse_expr('f(x)') == f(x) def test_split_symbols_numeric(): transformations = ( standard_transformations + (implicit_multiplication_application,)) n = Symbol('n') expr1 = parse_expr('2**n * 3**n') expr2 = parse_expr('2**n3**n', transformations=transformations) assert expr1 == expr2 == 2**n*3**n expr1 = parse_expr('n12n34', transformations=transformations) assert expr1 == n*12*n*34 def test_unicode_names(): assert parse_expr('α') == Symbol('α') def test_python3_features(): # Make sure the tokenizer can handle Python 3-only features if sys.version_info < (3, 6): skip("test_python3_features requires Python 3.6 or newer") assert parse_expr("123_456") == 123456 assert parse_expr("1.2[3_4]") == parse_expr("1.2[34]") == Rational(611, 495) assert parse_expr("1.2[012_012]") == parse_expr("1.2[012012]") == Rational(400, 333) assert parse_expr('.[3_4]') == parse_expr('.[34]') == Rational(34, 99) assert parse_expr('.1[3_4]') == parse_expr('.1[34]') == Rational(133, 990) assert parse_expr('123_123.123_123[3_4]') == parse_expr('123123.123123[34]') == Rational(12189189189211, 99000000) def test_issue_19501(): x = Symbol('x') eq = parse_expr('E**x(1+x)', local_dict={'x': x}, transformations=( standard_transformations + (implicit_multiplication_application,))) assert eq.free_symbols == {x} sympy-sympy-1.9/sympy/physics/000077500000000000000000000000001412543434000165665ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/__init__.py000066400000000000000000000003331412543434000206760ustar00rootroot00000000000000""" A module that helps solving problems in physics """ from . import units from .matrices import mgamma, msigma, minkowski_tensor, mdft __all__ = [ 'units', 'mgamma', 'msigma', 'minkowski_tensor', 'mdft', ] sympy-sympy-1.9/sympy/physics/continuum_mechanics/000077500000000000000000000000001412543434000226215ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/continuum_mechanics/__init__.py000066400000000000000000000000531412543434000247300ustar00rootroot00000000000000__all__ = ['Beam'] from .beam import Beam sympy-sympy-1.9/sympy/physics/continuum_mechanics/beam.py000066400000000000000000004333241412543434000241100ustar00rootroot00000000000000""" This module can be used to solve 2D beam bending problems with singularity functions in mechanics. """ from sympy.core import S, Symbol, diff, symbols from sympy.solvers import linsolve from sympy.printing import sstr from sympy.functions import SingularityFunction, Piecewise, factorial from sympy.core import sympify from sympy.integrals import integrate from sympy.series import limit from sympy.plotting import plot, PlotGrid from sympy.geometry.entity import GeometryEntity from sympy.external import import_module from sympy import lambdify, Add from sympy.core.compatibility import iterable from sympy.utilities.decorator import doctest_depends_on numpy = import_module('numpy', import_kwargs={'fromlist':['arange']}) class Beam: """ A Beam is a structural element that is capable of withstanding load primarily by resisting against bending. Beams are characterized by their cross sectional profile(Second moment of area), their length and their material. .. note:: While solving a beam bending problem, a user should choose its own sign convention and should stick to it. The results will automatically follow the chosen sign convention. However, the chosen sign convention must respect the rule that, on the positive side of beam's axis (in respect to current section), a loading force giving positive shear yields a negative moment, as below (the curved arrow shows the positive moment and rotation): .. image:: allowed-sign-conventions.png Examples ======== There is a beam of length 4 meters. A constant distributed load of 6 N/m is applied from half of the beam till the end. There are two simple supports below the beam, one at the starting point and another at the ending point of the beam. The deflection of the beam at the end is restricted. Using the sign convention of downwards forces being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols, Piecewise >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(4, E, I) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(6, 2, 0) >>> b.apply_load(R2, 4, -1) >>> b.bc_deflection = [(0, 0), (4, 0)] >>> b.boundary_conditions {'deflection': [(0, 0), (4, 0)], 'slope': []} >>> b.load R1*SingularityFunction(x, 0, -1) + R2*SingularityFunction(x, 4, -1) + 6*SingularityFunction(x, 2, 0) >>> b.solve_for_reaction_loads(R1, R2) >>> b.load -3*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 2, 0) - 9*SingularityFunction(x, 4, -1) >>> b.shear_force() 3*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 2, 1) + 9*SingularityFunction(x, 4, 0) >>> b.bending_moment() 3*SingularityFunction(x, 0, 1) - 3*SingularityFunction(x, 2, 2) + 9*SingularityFunction(x, 4, 1) >>> b.slope() (-3*SingularityFunction(x, 0, 2)/2 + SingularityFunction(x, 2, 3) - 9*SingularityFunction(x, 4, 2)/2 + 7)/(E*I) >>> b.deflection() (7*x - SingularityFunction(x, 0, 3)/2 + SingularityFunction(x, 2, 4)/4 - 3*SingularityFunction(x, 4, 3)/2)/(E*I) >>> b.deflection().rewrite(Piecewise) (7*x - Piecewise((x**3, x > 0), (0, True))/2 - 3*Piecewise(((x - 4)**3, x - 4 > 0), (0, True))/2 + Piecewise(((x - 2)**4, x - 2 > 0), (0, True))/4)/(E*I) """ def __init__(self, length, elastic_modulus, second_moment, area=Symbol('A'), variable=Symbol('x'), base_char='C'): """Initializes the class. Parameters ========== length : Sympifyable A Symbol or value representing the Beam's length. elastic_modulus : Sympifyable A SymPy expression representing the Beam's Modulus of Elasticity. It is a measure of the stiffness of the Beam material. It can also be a continuous function of position along the beam. second_moment : Sympifyable or Geometry object Describes the cross-section of the beam via a SymPy expression representing the Beam's second moment of area. It is a geometrical property of an area which reflects how its points are distributed with respect to its neutral axis. It can also be a continuous function of position along the beam. Alternatively ``second_moment`` can be a shape object such as a ``Polygon`` from the geometry module representing the shape of the cross-section of the beam. In such cases, it is assumed that the x-axis of the shape object is aligned with the bending axis of the beam. The second moment of area will be computed from the shape object internally. area : Symbol/float Represents the cross-section area of beam variable : Symbol, optional A Symbol object that will be used as the variable along the beam while representing the load, shear, moment, slope and deflection curve. By default, it is set to ``Symbol('x')``. base_char : String, optional A String that will be used as base character to generate sequential symbols for integration constants in cases where boundary conditions are not sufficient to solve them. """ self.length = length self.elastic_modulus = elastic_modulus if isinstance(second_moment, GeometryEntity): self.cross_section = second_moment else: self.cross_section = None self.second_moment = second_moment self.variable = variable self._base_char = base_char self._boundary_conditions = {'deflection': [], 'slope': []} self._load = 0 self._area = area self._applied_supports = [] self._support_as_loads = [] self._applied_loads = [] self._reaction_loads = {} self._ild_reactions = {} self._ild_shear = 0 self._ild_moment = 0 # _original_load is a copy of _load equations with unsubstituted reaction # forces. It is used for calculating reaction forces in case of I.L.D. self._original_load = 0 self._composite_type = None self._hinge_position = None def __str__(self): shape_description = self._cross_section if self._cross_section else self._second_moment str_sol = 'Beam({}, {}, {})'.format(sstr(self._length), sstr(self._elastic_modulus), sstr(shape_description)) return str_sol @property def reaction_loads(self): """ Returns the reaction forces in a dictionary.""" return self._reaction_loads @property def ild_shear(self): """ Returns the I.L.D. shear equation.""" return self._ild_shear @property def ild_reactions(self): """ Returns the I.L.D. reaction forces in a dictionary.""" return self._ild_reactions @property def ild_moment(self): """ Returns the I.L.D. moment equation.""" return self._ild_moment @property def length(self): """Length of the Beam.""" return self._length @length.setter def length(self, l): self._length = sympify(l) @property def area(self): """Cross-sectional area of the Beam. """ return self._area @area.setter def area(self, a): self._area = sympify(a) @property def variable(self): """ A symbol that can be used as a variable along the length of the beam while representing load distribution, shear force curve, bending moment, slope curve and the deflection curve. By default, it is set to ``Symbol('x')``, but this property is mutable. Examples ======== >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I, A = symbols('E, I, A') >>> x, y, z = symbols('x, y, z') >>> b = Beam(4, E, I) >>> b.variable x >>> b.variable = y >>> b.variable y >>> b = Beam(4, E, I, A, z) >>> b.variable z """ return self._variable @variable.setter def variable(self, v): if isinstance(v, Symbol): self._variable = v else: raise TypeError("""The variable should be a Symbol object.""") @property def elastic_modulus(self): """Young's Modulus of the Beam. """ return self._elastic_modulus @elastic_modulus.setter def elastic_modulus(self, e): self._elastic_modulus = sympify(e) @property def second_moment(self): """Second moment of area of the Beam. """ return self._second_moment @second_moment.setter def second_moment(self, i): self._cross_section = None if isinstance(i, GeometryEntity): raise ValueError("To update cross-section geometry use `cross_section` attribute") else: self._second_moment = sympify(i) @property def cross_section(self): """Cross-section of the beam""" return self._cross_section @cross_section.setter def cross_section(self, s): if s: self._second_moment = s.second_moment_of_area()[0] self._cross_section = s @property def boundary_conditions(self): """ Returns a dictionary of boundary conditions applied on the beam. The dictionary has three keywords namely moment, slope and deflection. The value of each keyword is a list of tuple, where each tuple contains location and value of a boundary condition in the format (location, value). Examples ======== There is a beam of length 4 meters. The bending moment at 0 should be 4 and at 4 it should be 0. The slope of the beam should be 1 at 0. The deflection should be 2 at 0. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> b = Beam(4, E, I) >>> b.bc_deflection = [(0, 2)] >>> b.bc_slope = [(0, 1)] >>> b.boundary_conditions {'deflection': [(0, 2)], 'slope': [(0, 1)]} Here the deflection of the beam should be ``2`` at ``0``. Similarly, the slope of the beam should be ``1`` at ``0``. """ return self._boundary_conditions @property def bc_slope(self): return self._boundary_conditions['slope'] @bc_slope.setter def bc_slope(self, s_bcs): self._boundary_conditions['slope'] = s_bcs @property def bc_deflection(self): return self._boundary_conditions['deflection'] @bc_deflection.setter def bc_deflection(self, d_bcs): self._boundary_conditions['deflection'] = d_bcs def join(self, beam, via="fixed"): """ This method joins two beams to make a new composite beam system. Passed Beam class instance is attached to the right end of calling object. This method can be used to form beams having Discontinuous values of Elastic modulus or Second moment. Parameters ========== beam : Beam class object The Beam object which would be connected to the right of calling object. via : String States the way two Beam object would get connected - For axially fixed Beams, via="fixed" - For Beams connected via hinge, via="hinge" Examples ======== There is a cantilever beam of length 4 meters. For first 2 meters its moment of inertia is `1.5*I` and `I` for the other end. A pointload of magnitude 4 N is applied from the top at its free end. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b1 = Beam(2, E, 1.5*I) >>> b2 = Beam(2, E, I) >>> b = b1.join(b2, "fixed") >>> b.apply_load(20, 4, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 0, -2) >>> b.bc_slope = [(0, 0)] >>> b.bc_deflection = [(0, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.load 80*SingularityFunction(x, 0, -2) - 20*SingularityFunction(x, 0, -1) + 20*SingularityFunction(x, 4, -1) >>> b.slope() (-((-80*SingularityFunction(x, 0, 1) + 10*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 4, 2))/I + 120/I)/E + 80.0/(E*I))*SingularityFunction(x, 2, 0) - 0.666666666666667*(-80*SingularityFunction(x, 0, 1) + 10*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 4, 2))*SingularityFunction(x, 0, 0)/(E*I) + 0.666666666666667*(-80*SingularityFunction(x, 0, 1) + 10*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 4, 2))*SingularityFunction(x, 2, 0)/(E*I) """ x = self.variable E = self.elastic_modulus new_length = self.length + beam.length if self.second_moment != beam.second_moment: new_second_moment = Piecewise((self.second_moment, x<=self.length), (beam.second_moment, x<=new_length)) else: new_second_moment = self.second_moment if via == "fixed": new_beam = Beam(new_length, E, new_second_moment, x) new_beam._composite_type = "fixed" return new_beam if via == "hinge": new_beam = Beam(new_length, E, new_second_moment, x) new_beam._composite_type = "hinge" new_beam._hinge_position = self.length return new_beam def apply_support(self, loc, type="fixed"): """ This method applies support to a particular beam object. Parameters ========== loc : Sympifyable Location of point at which support is applied. type : String Determines type of Beam support applied. To apply support structure with - zero degree of freedom, type = "fixed" - one degree of freedom, type = "pin" - two degrees of freedom, type = "roller" Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> b = Beam(30, E, I) >>> b.apply_support(10, 'roller') >>> b.apply_support(30, 'roller') >>> b.apply_load(-8, 0, -1) >>> b.apply_load(120, 30, -2) >>> R_10, R_30 = symbols('R_10, R_30') >>> b.solve_for_reaction_loads(R_10, R_30) >>> b.load -8*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 10, -1) + 120*SingularityFunction(x, 30, -2) + 2*SingularityFunction(x, 30, -1) >>> b.slope() (-4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) + 4000/3)/(E*I) """ loc = sympify(loc) self._applied_supports.append((loc, type)) if type in ("pin", "roller"): reaction_load = Symbol('R_'+str(loc)) self.apply_load(reaction_load, loc, -1) self.bc_deflection.append((loc, 0)) else: reaction_load = Symbol('R_'+str(loc)) reaction_moment = Symbol('M_'+str(loc)) self.apply_load(reaction_load, loc, -1) self.apply_load(reaction_moment, loc, -2) self.bc_deflection.append((loc, 0)) self.bc_slope.append((loc, 0)) self._support_as_loads.append((reaction_moment, loc, -2, None)) self._support_as_loads.append((reaction_load, loc, -1, None)) def apply_load(self, value, start, order, end=None): """ This method adds up the loads given to a particular beam object. Parameters ========== value : Sympifyable The value inserted should have the units [Force/(Distance**(n+1)] where n is the order of applied load. Units for applied loads: - For moments, unit = kN*m - For point loads, unit = kN - For constant distributed load, unit = kN/m - For ramp loads, unit = kN/m/m - For parabolic ramp loads, unit = kN/m/m/m - ... so on. start : Sympifyable The starting point of the applied load. For point moments and point forces this is the location of application. order : Integer The order of the applied load. - For moments, order = -2 - For point loads, order =-1 - For constant distributed load, order = 0 - For ramp loads, order = 1 - For parabolic ramp loads, order = 2 - ... so on. end : Sympifyable, optional An optional argument that can be used if the load has an end point within the length of the beam. Examples ======== There is a beam of length 4 meters. A moment of magnitude 3 Nm is applied in the clockwise direction at the starting point of the beam. A point load of magnitude 4 N is applied from the top of the beam at 2 meters from the starting point and a parabolic ramp load of magnitude 2 N/m is applied below the beam starting from 2 meters to 3 meters away from the starting point of the beam. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> b = Beam(4, E, I) >>> b.apply_load(-3, 0, -2) >>> b.apply_load(4, 2, -1) >>> b.apply_load(-2, 2, 2, end=3) >>> b.load -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) - 2*SingularityFunction(x, 2, 2) + 2*SingularityFunction(x, 3, 0) + 4*SingularityFunction(x, 3, 1) + 2*SingularityFunction(x, 3, 2) """ x = self.variable value = sympify(value) start = sympify(start) order = sympify(order) self._applied_loads.append((value, start, order, end)) self._load += value*SingularityFunction(x, start, order) self._original_load += value*SingularityFunction(x, start, order) if end: # load has an end point within the length of the beam. self._handle_end(x, value, start, order, end, type="apply") def remove_load(self, value, start, order, end=None): """ This method removes a particular load present on the beam object. Returns a ValueError if the load passed as an argument is not present on the beam. Parameters ========== value : Sympifyable The magnitude of an applied load. start : Sympifyable The starting point of the applied load. For point moments and point forces this is the location of application. order : Integer The order of the applied load. - For moments, order= -2 - For point loads, order=-1 - For constant distributed load, order=0 - For ramp loads, order=1 - For parabolic ramp loads, order=2 - ... so on. end : Sympifyable, optional An optional argument that can be used if the load has an end point within the length of the beam. Examples ======== There is a beam of length 4 meters. A moment of magnitude 3 Nm is applied in the clockwise direction at the starting point of the beam. A pointload of magnitude 4 N is applied from the top of the beam at 2 meters from the starting point and a parabolic ramp load of magnitude 2 N/m is applied below the beam starting from 2 meters to 3 meters away from the starting point of the beam. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> b = Beam(4, E, I) >>> b.apply_load(-3, 0, -2) >>> b.apply_load(4, 2, -1) >>> b.apply_load(-2, 2, 2, end=3) >>> b.load -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) - 2*SingularityFunction(x, 2, 2) + 2*SingularityFunction(x, 3, 0) + 4*SingularityFunction(x, 3, 1) + 2*SingularityFunction(x, 3, 2) >>> b.remove_load(-2, 2, 2, end = 3) >>> b.load -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) """ x = self.variable value = sympify(value) start = sympify(start) order = sympify(order) if (value, start, order, end) in self._applied_loads: self._load -= value*SingularityFunction(x, start, order) self._original_load -= value*SingularityFunction(x, start, order) self._applied_loads.remove((value, start, order, end)) else: msg = "No such load distribution exists on the beam object." raise ValueError(msg) if end: # load has an end point within the length of the beam. self._handle_end(x, value, start, order, end, type="remove") def _handle_end(self, x, value, start, order, end, type): """ This functions handles the optional `end` value in the `apply_load` and `remove_load` functions. When the value of end is not NULL, this function will be executed. """ if order.is_negative: msg = ("If 'end' is provided the 'order' of the load cannot " "be negative, i.e. 'end' is only valid for distributed " "loads.") raise ValueError(msg) # NOTE : A Taylor series can be used to define the summation of # singularity functions that subtract from the load past the end # point such that it evaluates to zero past 'end'. f = value*x**order if type == "apply": # iterating for "apply_load" method for i in range(0, order + 1): self._load -= (f.diff(x, i).subs(x, end - start) * SingularityFunction(x, end, i)/factorial(i)) self._original_load -= (f.diff(x, i).subs(x, end - start) * SingularityFunction(x, end, i)/factorial(i)) elif type == "remove": # iterating for "remove_load" method for i in range(0, order + 1): self._load += (f.diff(x, i).subs(x, end - start) * SingularityFunction(x, end, i)/factorial(i)) self._original_load += (f.diff(x, i).subs(x, end - start) * SingularityFunction(x, end, i)/factorial(i)) @property def load(self): """ Returns a Singularity Function expression which represents the load distribution curve of the Beam object. Examples ======== There is a beam of length 4 meters. A moment of magnitude 3 Nm is applied in the clockwise direction at the starting point of the beam. A point load of magnitude 4 N is applied from the top of the beam at 2 meters from the starting point and a parabolic ramp load of magnitude 2 N/m is applied below the beam starting from 3 meters away from the starting point of the beam. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> b = Beam(4, E, I) >>> b.apply_load(-3, 0, -2) >>> b.apply_load(4, 2, -1) >>> b.apply_load(-2, 3, 2) >>> b.load -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) - 2*SingularityFunction(x, 3, 2) """ return self._load @property def applied_loads(self): """ Returns a list of all loads applied on the beam object. Each load in the list is a tuple of form (value, start, order, end). Examples ======== There is a beam of length 4 meters. A moment of magnitude 3 Nm is applied in the clockwise direction at the starting point of the beam. A pointload of magnitude 4 N is applied from the top of the beam at 2 meters from the starting point. Another pointload of magnitude 5 N is applied at same position. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> b = Beam(4, E, I) >>> b.apply_load(-3, 0, -2) >>> b.apply_load(4, 2, -1) >>> b.apply_load(5, 2, -1) >>> b.load -3*SingularityFunction(x, 0, -2) + 9*SingularityFunction(x, 2, -1) >>> b.applied_loads [(-3, 0, -2, None), (4, 2, -1, None), (5, 2, -1, None)] """ return self._applied_loads def _solve_hinge_beams(self, *reactions): """Method to find integration constants and reactional variables in a composite beam connected via hinge. This method resolves the composite Beam into its sub-beams and then equations of shear force, bending moment, slope and deflection are evaluated for both of them separately. These equations are then solved for unknown reactions and integration constants using the boundary conditions applied on the Beam. Equal deflection of both sub-beams at the hinge joint gives us another equation to solve the system. Examples ======== A combined beam, with constant fkexural rigidity E*I, is formed by joining a Beam of length 2*l to the right of another Beam of length l. The whole beam is fixed at both of its both end. A point load of magnitude P is also applied from the top at a distance of 2*l from starting point. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> l=symbols('l', positive=True) >>> b1=Beam(l ,E,I) >>> b2=Beam(2*l ,E,I) >>> b=b1.join(b2,"hinge") >>> M1, A1, M2, A2, P = symbols('M1 A1 M2 A2 P') >>> b.apply_load(A1,0,-1) >>> b.apply_load(M1,0,-2) >>> b.apply_load(P,2*l,-1) >>> b.apply_load(A2,3*l,-1) >>> b.apply_load(M2,3*l,-2) >>> b.bc_slope=[(0,0), (3*l, 0)] >>> b.bc_deflection=[(0,0), (3*l, 0)] >>> b.solve_for_reaction_loads(M1, A1, M2, A2) >>> b.reaction_loads {A1: -5*P/18, A2: -13*P/18, M1: 5*P*l/18, M2: -4*P*l/9} >>> b.slope() (5*P*l*SingularityFunction(x, 0, 1)/18 - 5*P*SingularityFunction(x, 0, 2)/36 + 5*P*SingularityFunction(x, l, 2)/36)*SingularityFunction(x, 0, 0)/(E*I) - (5*P*l*SingularityFunction(x, 0, 1)/18 - 5*P*SingularityFunction(x, 0, 2)/36 + 5*P*SingularityFunction(x, l, 2)/36)*SingularityFunction(x, l, 0)/(E*I) + (P*l**2/18 - 4*P*l*SingularityFunction(-l + x, 2*l, 1)/9 - 5*P*SingularityFunction(-l + x, 0, 2)/36 + P*SingularityFunction(-l + x, l, 2)/2 - 13*P*SingularityFunction(-l + x, 2*l, 2)/36)*SingularityFunction(x, l, 0)/(E*I) >>> b.deflection() (5*P*l*SingularityFunction(x, 0, 2)/36 - 5*P*SingularityFunction(x, 0, 3)/108 + 5*P*SingularityFunction(x, l, 3)/108)*SingularityFunction(x, 0, 0)/(E*I) - (5*P*l*SingularityFunction(x, 0, 2)/36 - 5*P*SingularityFunction(x, 0, 3)/108 + 5*P*SingularityFunction(x, l, 3)/108)*SingularityFunction(x, l, 0)/(E*I) + (5*P*l**3/54 + P*l**2*(-l + x)/18 - 2*P*l*SingularityFunction(-l + x, 2*l, 2)/9 - 5*P*SingularityFunction(-l + x, 0, 3)/108 + P*SingularityFunction(-l + x, l, 3)/6 - 13*P*SingularityFunction(-l + x, 2*l, 3)/108)*SingularityFunction(x, l, 0)/(E*I) """ x = self.variable l = self._hinge_position E = self._elastic_modulus I = self._second_moment if isinstance(I, Piecewise): I1 = I.args[0][0] I2 = I.args[1][0] else: I1 = I2 = I load_1 = 0 # Load equation on first segment of composite beam load_2 = 0 # Load equation on second segment of composite beam # Distributing load on both segments for load in self.applied_loads: if load[1] < l: load_1 += load[0]*SingularityFunction(x, load[1], load[2]) if load[2] == 0: load_1 -= load[0]*SingularityFunction(x, load[3], load[2]) elif load[2] > 0: load_1 -= load[0]*SingularityFunction(x, load[3], load[2]) + load[0]*SingularityFunction(x, load[3], 0) elif load[1] == l: load_1 += load[0]*SingularityFunction(x, load[1], load[2]) load_2 += load[0]*SingularityFunction(x, load[1] - l, load[2]) elif load[1] > l: load_2 += load[0]*SingularityFunction(x, load[1] - l, load[2]) if load[2] == 0: load_2 -= load[0]*SingularityFunction(x, load[3] - l, load[2]) elif load[2] > 0: load_2 -= load[0]*SingularityFunction(x, load[3] - l, load[2]) + load[0]*SingularityFunction(x, load[3] - l, 0) h = Symbol('h') # Force due to hinge load_1 += h*SingularityFunction(x, l, -1) load_2 -= h*SingularityFunction(x, 0, -1) eq = [] shear_1 = integrate(load_1, x) shear_curve_1 = limit(shear_1, x, l) eq.append(shear_curve_1) bending_1 = integrate(shear_1, x) moment_curve_1 = limit(bending_1, x, l) eq.append(moment_curve_1) shear_2 = integrate(load_2, x) shear_curve_2 = limit(shear_2, x, self.length - l) eq.append(shear_curve_2) bending_2 = integrate(shear_2, x) moment_curve_2 = limit(bending_2, x, self.length - l) eq.append(moment_curve_2) C1 = Symbol('C1') C2 = Symbol('C2') C3 = Symbol('C3') C4 = Symbol('C4') slope_1 = S.One/(E*I1)*(integrate(bending_1, x) + C1) def_1 = S.One/(E*I1)*(integrate((E*I)*slope_1, x) + C1*x + C2) slope_2 = S.One/(E*I2)*(integrate(integrate(integrate(load_2, x), x), x) + C3) def_2 = S.One/(E*I2)*(integrate((E*I)*slope_2, x) + C4) for position, value in self.bc_slope: if position>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) # Reaction force at x = 10 >>> b.apply_load(R2, 30, -1) # Reaction force at x = 30 >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.load R1*SingularityFunction(x, 10, -1) + R2*SingularityFunction(x, 30, -1) - 8*SingularityFunction(x, 0, -1) + 120*SingularityFunction(x, 30, -2) >>> b.solve_for_reaction_loads(R1, R2) >>> b.reaction_loads {R1: 6, R2: 2} >>> b.load -8*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 10, -1) + 120*SingularityFunction(x, 30, -2) + 2*SingularityFunction(x, 30, -1) """ if self._composite_type == "hinge": return self._solve_hinge_beams(*reactions) x = self.variable l = self.length C3 = Symbol('C3') C4 = Symbol('C4') shear_curve = limit(self.shear_force(), x, l) moment_curve = limit(self.bending_moment(), x, l) slope_eqs = [] deflection_eqs = [] slope_curve = integrate(self.bending_moment(), x) + C3 for position, value in self._boundary_conditions['slope']: eqs = slope_curve.subs(x, position) - value slope_eqs.append(eqs) deflection_curve = integrate(slope_curve, x) + C4 for position, value in self._boundary_conditions['deflection']: eqs = deflection_curve.subs(x, position) - value deflection_eqs.append(eqs) solution = list((linsolve([shear_curve, moment_curve] + slope_eqs + deflection_eqs, (C3, C4) + reactions).args)[0]) solution = solution[2:] self._reaction_loads = dict(zip(reactions, solution)) self._load = self._load.subs(self._reaction_loads) def shear_force(self): """ Returns a Singularity Function expression which represents the shear force curve of the Beam object. Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.shear_force() 8*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 10, 0) - 120*SingularityFunction(x, 30, -1) - 2*SingularityFunction(x, 30, 0) """ x = self.variable return -integrate(self.load, x) def max_shear_force(self): """Returns maximum Shear force and its coordinate in the Beam object.""" from sympy import solve, Mul, Interval shear_curve = self.shear_force() x = self.variable terms = shear_curve.args singularity = [] # Points at which shear function changes for term in terms: if isinstance(term, Mul): term = term.args[-1] # SingularityFunction in the term singularity.append(term.args[1]) singularity.sort() singularity = list(set(singularity)) intervals = [] # List of Intervals with discrete value of shear force shear_values = [] # List of values of shear force in each interval for i, s in enumerate(singularity): if s == 0: continue try: shear_slope = Piecewise((float("nan"), x<=singularity[i-1]),(self._load.rewrite(Piecewise), x>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.bending_moment() 8*SingularityFunction(x, 0, 1) - 6*SingularityFunction(x, 10, 1) - 120*SingularityFunction(x, 30, 0) - 2*SingularityFunction(x, 30, 1) """ x = self.variable return integrate(self.shear_force(), x) def max_bmoment(self): """Returns maximum Shear force and its coordinate in the Beam object.""" from sympy import solve, Mul, Interval bending_curve = self.bending_moment() x = self.variable terms = bending_curve.args singularity = [] # Points at which bending moment changes for term in terms: if isinstance(term, Mul): term = term.args[-1] # SingularityFunction in the term singularity.append(term.args[1]) singularity.sort() singularity = list(set(singularity)) intervals = [] # List of Intervals with discrete value of bending moment moment_values = [] # List of values of bending moment in each interval for i, s in enumerate(singularity): if s == 0: continue try: moment_slope = Piecewise((float("nan"), x<=singularity[i-1]),(self.shear_force().rewrite(Piecewise), x>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> b = Beam(10, E, I) >>> b.apply_load(-4, 0, -1) >>> b.apply_load(-46, 6, -1) >>> b.apply_load(10, 2, -1) >>> b.apply_load(20, 4, -1) >>> b.apply_load(3, 6, 0) >>> b.point_cflexure() [10/3] """ from sympy import solve # To restrict the range within length of the Beam moment_curve = Piecewise((float("nan"), self.variable<=0), (self.bending_moment(), self.variable>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.slope() (-4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) + 4000/3)/(E*I) """ x = self.variable E = self.elastic_modulus I = self.second_moment if self._composite_type == "hinge": return self._hinge_beam_slope if not self._boundary_conditions['slope']: return diff(self.deflection(), x) if isinstance(I, Piecewise) and self._composite_type == "fixed": args = I.args slope = 0 prev_slope = 0 prev_end = 0 for i in range(len(args)): if i != 0: prev_end = args[i-1][1].args[1] slope_value = -S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) if i != len(args) - 1: slope += (prev_slope + slope_value)*SingularityFunction(x, prev_end, 0) - \ (prev_slope + slope_value)*SingularityFunction(x, args[i][1].args[1], 0) else: slope += (prev_slope + slope_value)*SingularityFunction(x, prev_end, 0) prev_slope = slope_value.subs(x, args[i][1].args[1]) return slope C3 = Symbol('C3') slope_curve = -integrate(S.One/(E*I)*self.bending_moment(), x) + C3 bc_eqs = [] for position, value in self._boundary_conditions['slope']: eqs = slope_curve.subs(x, position) - value bc_eqs.append(eqs) constants = list(linsolve(bc_eqs, C3)) slope_curve = slope_curve.subs({C3: constants[0][0]}) return slope_curve def deflection(self): """ Returns a Singularity Function expression which represents the elastic curve or deflection of the Beam object. Examples ======== There is a beam of length 30 meters. A moment of magnitude 120 Nm is applied in the clockwise direction at the end of the beam. A pointload of magnitude 8 N is applied from the top of the beam at the starting point. There are two simple supports below the beam. One at the end and another one at a distance of 10 meters from the start. The deflection is restricted at both the supports. Using the sign convention of upward forces and clockwise moment being positive. >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> E, I = symbols('E, I') >>> R1, R2 = symbols('R1, R2') >>> b = Beam(30, E, I) >>> b.apply_load(-8, 0, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(120, 30, -2) >>> b.bc_deflection = [(10, 0), (30, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.deflection() (4000*x/3 - 4*SingularityFunction(x, 0, 3)/3 + SingularityFunction(x, 10, 3) + 60*SingularityFunction(x, 30, 2) + SingularityFunction(x, 30, 3)/3 - 12000)/(E*I) """ x = self.variable E = self.elastic_modulus I = self.second_moment if self._composite_type == "hinge": return self._hinge_beam_deflection if not self._boundary_conditions['deflection'] and not self._boundary_conditions['slope']: if isinstance(I, Piecewise) and self._composite_type == "fixed": args = I.args prev_slope = 0 prev_def = 0 prev_end = 0 deflection = 0 for i in range(len(args)): if i != 0: prev_end = args[i-1][1].args[1] slope_value = -S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) recent_segment_slope = prev_slope + slope_value deflection_value = integrate(recent_segment_slope, (x, prev_end, x)) if i != len(args) - 1: deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) \ - (prev_def + deflection_value)*SingularityFunction(x, args[i][1].args[1], 0) else: deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) prev_slope = slope_value.subs(x, args[i][1].args[1]) prev_def = deflection_value.subs(x, args[i][1].args[1]) return deflection base_char = self._base_char constants = symbols(base_char + '3:5') return S.One/(E*I)*integrate(-integrate(self.bending_moment(), x), x) + constants[0]*x + constants[1] elif not self._boundary_conditions['deflection']: base_char = self._base_char constant = symbols(base_char + '4') return integrate(self.slope(), x) + constant elif not self._boundary_conditions['slope'] and self._boundary_conditions['deflection']: if isinstance(I, Piecewise) and self._composite_type == "fixed": args = I.args prev_slope = 0 prev_def = 0 prev_end = 0 deflection = 0 for i in range(len(args)): if i != 0: prev_end = args[i-1][1].args[1] slope_value = -S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) recent_segment_slope = prev_slope + slope_value deflection_value = integrate(recent_segment_slope, (x, prev_end, x)) if i != len(args) - 1: deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) \ - (prev_def + deflection_value)*SingularityFunction(x, args[i][1].args[1], 0) else: deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) prev_slope = slope_value.subs(x, args[i][1].args[1]) prev_def = deflection_value.subs(x, args[i][1].args[1]) return deflection base_char = self._base_char C3, C4 = symbols(base_char + '3:5') # Integration constants slope_curve = -integrate(self.bending_moment(), x) + C3 deflection_curve = integrate(slope_curve, x) + C4 bc_eqs = [] for position, value in self._boundary_conditions['deflection']: eqs = deflection_curve.subs(x, position) - value bc_eqs.append(eqs) constants = list(linsolve(bc_eqs, (C3, C4))) deflection_curve = deflection_curve.subs({C3: constants[0][0], C4: constants[0][1]}) return S.One/(E*I)*deflection_curve if isinstance(I, Piecewise) and self._composite_type == "fixed": args = I.args prev_slope = 0 prev_def = 0 prev_end = 0 deflection = 0 for i in range(len(args)): if i != 0: prev_end = args[i-1][1].args[1] slope_value = S.One/E*integrate(self.bending_moment()/args[i][0], (x, prev_end, x)) recent_segment_slope = prev_slope + slope_value deflection_value = integrate(recent_segment_slope, (x, prev_end, x)) if i != len(args) - 1: deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) \ - (prev_def + deflection_value)*SingularityFunction(x, args[i][1].args[1], 0) else: deflection += (prev_def + deflection_value)*SingularityFunction(x, prev_end, 0) prev_slope = slope_value.subs(x, args[i][1].args[1]) prev_def = deflection_value.subs(x, args[i][1].args[1]) return deflection C4 = Symbol('C4') deflection_curve = integrate(self.slope(), x) + C4 bc_eqs = [] for position, value in self._boundary_conditions['deflection']: eqs = deflection_curve.subs(x, position) - value bc_eqs.append(eqs) constants = list(linsolve(bc_eqs, C4)) deflection_curve = deflection_curve.subs({C4: constants[0][0]}) return deflection_curve def max_deflection(self): """ Returns point of max deflection and its corresponding deflection value in a Beam object. """ from sympy import solve # To restrict the range within length of the Beam slope_curve = Piecewise((float("nan"), self.variable<=0), (self.slope(), self.variable>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> b = Beam(8, 200*(10**9), 400*(10**-6), 2) >>> b.apply_load(5000, 2, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 8, -1) >>> b.apply_load(10000, 4, 0, end=8) >>> b.bc_deflection = [(0, 0), (8, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.plot_shear_stress() Plot object containing: [0]: cartesian line: 6875*SingularityFunction(x, 0, 0) - 2500*SingularityFunction(x, 2, 0) - 5000*SingularityFunction(x, 4, 1) + 15625*SingularityFunction(x, 8, 0) + 5000*SingularityFunction(x, 8, 1) for x over (0.0, 8.0) """ shear_stress = self.shear_stress() x = self.variable length = self.length if subs is None: subs = {} for sym in shear_stress.atoms(Symbol): if sym != x and sym not in subs: raise ValueError('value of %s was not passed.' %sym) if length in subs: length = subs[length] # Returns Plot of Shear Stress return plot (shear_stress.subs(subs), (x, 0, length), title='Shear Stress', xlabel=r'$\mathrm{x}$', ylabel=r'$\tau$', line_color='r') def plot_shear_force(self, subs=None): """ Returns a plot for Shear force present in the Beam object. Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 8 meters. A constant distributed load of 10 KN/m is applied from half of the beam till the end. There are two simple supports below the beam, one at the starting point and another at the ending point of the beam. A pointload of magnitude 5 KN is also applied from top of the beam, at a distance of 4 meters from the starting point. Take E = 200 GPa and I = 400*(10**-6) meter**4. Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> b = Beam(8, 200*(10**9), 400*(10**-6)) >>> b.apply_load(5000, 2, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 8, -1) >>> b.apply_load(10000, 4, 0, end=8) >>> b.bc_deflection = [(0, 0), (8, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.plot_shear_force() Plot object containing: [0]: cartesian line: 13750*SingularityFunction(x, 0, 0) - 5000*SingularityFunction(x, 2, 0) - 10000*SingularityFunction(x, 4, 1) + 31250*SingularityFunction(x, 8, 0) + 10000*SingularityFunction(x, 8, 1) for x over (0.0, 8.0) """ shear_force = self.shear_force() if subs is None: subs = {} for sym in shear_force.atoms(Symbol): if sym == self.variable: continue if sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(shear_force.subs(subs), (self.variable, 0, length), title='Shear Force', xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{V}$', line_color='g') def plot_bending_moment(self, subs=None): """ Returns a plot for Bending moment present in the Beam object. Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 8 meters. A constant distributed load of 10 KN/m is applied from half of the beam till the end. There are two simple supports below the beam, one at the starting point and another at the ending point of the beam. A pointload of magnitude 5 KN is also applied from top of the beam, at a distance of 4 meters from the starting point. Take E = 200 GPa and I = 400*(10**-6) meter**4. Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> b = Beam(8, 200*(10**9), 400*(10**-6)) >>> b.apply_load(5000, 2, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 8, -1) >>> b.apply_load(10000, 4, 0, end=8) >>> b.bc_deflection = [(0, 0), (8, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.plot_bending_moment() Plot object containing: [0]: cartesian line: 13750*SingularityFunction(x, 0, 1) - 5000*SingularityFunction(x, 2, 1) - 5000*SingularityFunction(x, 4, 2) + 31250*SingularityFunction(x, 8, 1) + 5000*SingularityFunction(x, 8, 2) for x over (0.0, 8.0) """ bending_moment = self.bending_moment() if subs is None: subs = {} for sym in bending_moment.atoms(Symbol): if sym == self.variable: continue if sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(bending_moment.subs(subs), (self.variable, 0, length), title='Bending Moment', xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{M}$', line_color='b') def plot_slope(self, subs=None): """ Returns a plot for slope of deflection curve of the Beam object. Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 8 meters. A constant distributed load of 10 KN/m is applied from half of the beam till the end. There are two simple supports below the beam, one at the starting point and another at the ending point of the beam. A pointload of magnitude 5 KN is also applied from top of the beam, at a distance of 4 meters from the starting point. Take E = 200 GPa and I = 400*(10**-6) meter**4. Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> b = Beam(8, 200*(10**9), 400*(10**-6)) >>> b.apply_load(5000, 2, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 8, -1) >>> b.apply_load(10000, 4, 0, end=8) >>> b.bc_deflection = [(0, 0), (8, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.plot_slope() Plot object containing: [0]: cartesian line: -8.59375e-5*SingularityFunction(x, 0, 2) + 3.125e-5*SingularityFunction(x, 2, 2) + 2.08333333333333e-5*SingularityFunction(x, 4, 3) - 0.0001953125*SingularityFunction(x, 8, 2) - 2.08333333333333e-5*SingularityFunction(x, 8, 3) + 0.00138541666666667 for x over (0.0, 8.0) """ slope = self.slope() if subs is None: subs = {} for sym in slope.atoms(Symbol): if sym == self.variable: continue if sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(slope.subs(subs), (self.variable, 0, length), title='Slope', xlabel=r'$\mathrm{x}$', ylabel=r'$\theta$', line_color='m') def plot_deflection(self, subs=None): """ Returns a plot for deflection curve of the Beam object. Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 8 meters. A constant distributed load of 10 KN/m is applied from half of the beam till the end. There are two simple supports below the beam, one at the starting point and another at the ending point of the beam. A pointload of magnitude 5 KN is also applied from top of the beam, at a distance of 4 meters from the starting point. Take E = 200 GPa and I = 400*(10**-6) meter**4. Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> b = Beam(8, 200*(10**9), 400*(10**-6)) >>> b.apply_load(5000, 2, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 8, -1) >>> b.apply_load(10000, 4, 0, end=8) >>> b.bc_deflection = [(0, 0), (8, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> b.plot_deflection() Plot object containing: [0]: cartesian line: 0.00138541666666667*x - 2.86458333333333e-5*SingularityFunction(x, 0, 3) + 1.04166666666667e-5*SingularityFunction(x, 2, 3) + 5.20833333333333e-6*SingularityFunction(x, 4, 4) - 6.51041666666667e-5*SingularityFunction(x, 8, 3) - 5.20833333333333e-6*SingularityFunction(x, 8, 4) for x over (0.0, 8.0) """ deflection = self.deflection() if subs is None: subs = {} for sym in deflection.atoms(Symbol): if sym == self.variable: continue if sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(deflection.subs(subs), (self.variable, 0, length), title='Deflection', xlabel=r'$\mathrm{x}$', ylabel=r'$\delta$', line_color='r') def plot_loading_results(self, subs=None): """ Returns a subplot of Shear Force, Bending Moment, Slope and Deflection of the Beam object. Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 8 meters. A constant distributed load of 10 KN/m is applied from half of the beam till the end. There are two simple supports below the beam, one at the starting point and another at the ending point of the beam. A pointload of magnitude 5 KN is also applied from top of the beam, at a distance of 4 meters from the starting point. Take E = 200 GPa and I = 400*(10**-6) meter**4. Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> b = Beam(8, 200*(10**9), 400*(10**-6)) >>> b.apply_load(5000, 2, -1) >>> b.apply_load(R1, 0, -1) >>> b.apply_load(R2, 8, -1) >>> b.apply_load(10000, 4, 0, end=8) >>> b.bc_deflection = [(0, 0), (8, 0)] >>> b.solve_for_reaction_loads(R1, R2) >>> axes = b.plot_loading_results() """ length = self.length variable = self.variable if subs is None: subs = {} for sym in self.deflection().atoms(Symbol): if sym == self.variable: continue if sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if length in subs: length = subs[length] ax1 = plot(self.shear_force().subs(subs), (variable, 0, length), title="Shear Force", xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{V}$', line_color='g', show=False) ax2 = plot(self.bending_moment().subs(subs), (variable, 0, length), title="Bending Moment", xlabel=r'$\mathrm{x}$', ylabel=r'$\mathrm{M}$', line_color='b', show=False) ax3 = plot(self.slope().subs(subs), (variable, 0, length), title="Slope", xlabel=r'$\mathrm{x}$', ylabel=r'$\theta$', line_color='m', show=False) ax4 = plot(self.deflection().subs(subs), (variable, 0, length), title="Deflection", xlabel=r'$\mathrm{x}$', ylabel=r'$\delta$', line_color='r', show=False) return PlotGrid(4, 1, ax1, ax2, ax3, ax4) def _solve_for_ild_equations(self): """ Helper function for I.L.D. It takes the unsubstituted copy of the load equation and uses it to calculate shear force and bending moment equations. """ x = self.variable shear_force = -integrate(self._original_load, x) bending_moment = integrate(shear_force, x) return shear_force, bending_moment def solve_for_ild_reactions(self, value, *reactions): """ Determines the Influence Line Diagram equations for reaction forces under the effect of a moving load. Parameters ========== value : Integer Magnitude of moving load reactions : The reaction forces applied on the beam. Examples ======== There is a beam of length 10 meters. There are two simple supports below the beam, one at the starting point and another at the ending point of the beam. Calculate the I.L.D. equations for reaction forces under the effect of a moving load of magnitude 1kN. .. image:: ildreaction.png Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.physics.continuum_mechanics.beam import Beam >>> E, I = symbols('E, I') >>> R_0, R_10 = symbols('R_0, R_10') >>> b = Beam(10, E, I) >>> b.apply_support(0, 'roller') >>> b.apply_support(10, 'roller') >>> b.solve_for_ild_reactions(1,R_0,R_10) >>> b.ild_reactions {R_0: x/10 - 1, R_10: -x/10} """ shear_force, bending_moment = self._solve_for_ild_equations() x = self.variable l = self.length C3 = Symbol('C3') C4 = Symbol('C4') shear_curve = limit(shear_force, x, l) - value moment_curve = limit(bending_moment, x, l) - value*(l-x) slope_eqs = [] deflection_eqs = [] slope_curve = integrate(bending_moment, x) + C3 for position, value in self._boundary_conditions['slope']: eqs = slope_curve.subs(x, position) - value slope_eqs.append(eqs) deflection_curve = integrate(slope_curve, x) + C4 for position, value in self._boundary_conditions['deflection']: eqs = deflection_curve.subs(x, position) - value deflection_eqs.append(eqs) solution = list((linsolve([shear_curve, moment_curve] + slope_eqs + deflection_eqs, (C3, C4) + reactions).args)[0]) solution = solution[2:] # Determining the equations and solving them. self._ild_reactions = dict(zip(reactions, solution)) def plot_ild_reactions(self, subs=None): """ Plots the Influence Line Diagram of Reaction Forces under the effect of a moving load. This function should be called after calling solve_for_ild_reactions(). Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 10 meters. A point load of magnitude 5KN is also applied from top of the beam, at a distance of 4 meters from the starting point. There are two simple supports below the beam, located at the starting point and at a distance of 7 meters from the starting point. Plot the I.L.D. equations for reactions at both support points under the effect of a moving load of magnitude 1kN. Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.physics.continuum_mechanics.beam import Beam >>> E, I = symbols('E, I') >>> R_0, R_7 = symbols('R_0, R_7') >>> b = Beam(10, E, I) >>> b.apply_support(0, 'roller') >>> b.apply_support(7, 'roller') >>> b.apply_load(5,4,-1) >>> b.solve_for_ild_reactions(1,R_0,R_7) >>> b.ild_reactions {R_0: x/7 - 22/7, R_7: -x/7 - 20/7} >>> b.plot_ild_reactions() PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: x/7 - 22/7 for x over (0.0, 10.0) Plot[1]:Plot object containing: [0]: cartesian line: -x/7 - 20/7 for x over (0.0, 10.0) """ if not self._ild_reactions: raise ValueError("I.L.D. reaction equations not found. Please use solve_for_ild_reactions() to generate the I.L.D. reaction equations.") x = self.variable ildplots = [] if subs is None: subs = {} for reaction in self._ild_reactions: for sym in self._ild_reactions[reaction].atoms(Symbol): if sym != x and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) for sym in self._length.atoms(Symbol): if sym != x and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) for reaction in self._ild_reactions: ildplots.append(plot(self._ild_reactions[reaction].subs(subs), (x, 0, self._length.subs(subs)), title='I.L.D. for Reactions', xlabel=x, ylabel=reaction, line_color='blue', show=False)) return PlotGrid(len(ildplots), 1, *ildplots) def solve_for_ild_shear(self, distance, value, *reactions): """ Determines the Influence Line Diagram equations for shear at a specified point under the effect of a moving load. Parameters ========== distance : Integer Distance of the point from the start of the beam for which equations are to be determined value : Integer Magnitude of moving load reactions : The reaction forces applied on the beam. Examples ======== There is a beam of length 12 meters. There are two simple supports below the beam, one at the starting point and another at a distance of 8 meters. Calculate the I.L.D. equations for Shear at a distance of 4 meters under the effect of a moving load of magnitude 1kN. .. image:: ildshear.png Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.physics.continuum_mechanics.beam import Beam >>> E, I = symbols('E, I') >>> R_0, R_8 = symbols('R_0, R_8') >>> b = Beam(12, E, I) >>> b.apply_support(0, 'roller') >>> b.apply_support(8, 'roller') >>> b.solve_for_ild_reactions(1, R_0, R_8) >>> b.solve_for_ild_shear(4, 1, R_0, R_8) >>> b.ild_shear Piecewise((x/8, x < 4), (x/8 - 1, x > 4)) """ x = self.variable l = self.length shear_force, _ = self._solve_for_ild_equations() shear_curve1 = value - limit(shear_force, x, distance) shear_curve2 = (limit(shear_force, x, l) - limit(shear_force, x, distance)) - value for reaction in reactions: shear_curve1 = shear_curve1.subs(reaction,self._ild_reactions[reaction]) shear_curve2 = shear_curve2.subs(reaction,self._ild_reactions[reaction]) shear_eq = Piecewise((shear_curve1, x < distance), (shear_curve2, x > distance)) self._ild_shear = shear_eq def plot_ild_shear(self,subs=None): """ Plots the Influence Line Diagram for Shear under the effect of a moving load. This function should be called after calling solve_for_ild_shear(). Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 12 meters. There are two simple supports below the beam, one at the starting point and another at a distance of 8 meters. Plot the I.L.D. for Shear at a distance of 4 meters under the effect of a moving load of magnitude 1kN. .. image:: ildshear.png Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.physics.continuum_mechanics.beam import Beam >>> E, I = symbols('E, I') >>> R_0, R_8 = symbols('R_0, R_8') >>> b = Beam(12, E, I) >>> b.apply_support(0, 'roller') >>> b.apply_support(8, 'roller') >>> b.solve_for_ild_reactions(1, R_0, R_8) >>> b.solve_for_ild_shear(4, 1, R_0, R_8) >>> b.ild_shear Piecewise((x/8, x < 4), (x/8 - 1, x > 4)) >>> b.plot_ild_shear() Plot object containing: [0]: cartesian line: Piecewise((x/8, x < 4), (x/8 - 1, x > 4)) for x over (0.0, 12.0) """ if not self._ild_shear: raise ValueError("I.L.D. shear equation not found. Please use solve_for_ild_shear() to generate the I.L.D. shear equations.") x = self.variable l = self._length if subs is None: subs = {} for sym in self._ild_shear.atoms(Symbol): if sym != x and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) for sym in self._length.atoms(Symbol): if sym != x and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) return plot(self._ild_shear.subs(subs), (x, 0, l), title='I.L.D. for Shear', xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{V}$', line_color='blue',show=True) def solve_for_ild_moment(self, distance, value, *reactions): """ Determines the Influence Line Diagram equations for moment at a specified point under the effect of a moving load. Parameters ========== distance : Integer Distance of the point from the start of the beam for which equations are to be determined value : Integer Magnitude of moving load reactions : The reaction forces applied on the beam. Examples ======== There is a beam of length 12 meters. There are two simple supports below the beam, one at the starting point and another at a distance of 8 meters. Calculate the I.L.D. equations for Moment at a distance of 4 meters under the effect of a moving load of magnitude 1kN. .. image:: ildshear.png Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.physics.continuum_mechanics.beam import Beam >>> E, I = symbols('E, I') >>> R_0, R_8 = symbols('R_0, R_8') >>> b = Beam(12, E, I) >>> b.apply_support(0, 'roller') >>> b.apply_support(8, 'roller') >>> b.solve_for_ild_reactions(1, R_0, R_8) >>> b.solve_for_ild_moment(4, 1, R_0, R_8) >>> b.ild_moment Piecewise((-x/2, x < 4), (x/2 - 4, x > 4)) """ x = self.variable l = self.length _ , moment = self._solve_for_ild_equations() moment_curve1 = value*(distance-x) - limit(moment, x, distance) moment_curve2= (limit(moment, x, l)-limit(moment, x, distance))-value*(l-x) for reaction in reactions: moment_curve1 = moment_curve1.subs(reaction, self._ild_reactions[reaction]) moment_curve2 = moment_curve2.subs(reaction, self._ild_reactions[reaction]) moment_eq = Piecewise((moment_curve1, x < distance), (moment_curve2, x > distance)) self._ild_moment = moment_eq def plot_ild_moment(self,subs=None): """ Plots the Influence Line Diagram for Moment under the effect of a moving load. This function should be called after calling solve_for_ild_moment(). Parameters ========== subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 12 meters. There are two simple supports below the beam, one at the starting point and another at a distance of 8 meters. Plot the I.L.D. for Moment at a distance of 4 meters under the effect of a moving load of magnitude 1kN. .. image:: ildshear.png Using the sign convention of downwards forces being positive. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.physics.continuum_mechanics.beam import Beam >>> E, I = symbols('E, I') >>> R_0, R_8 = symbols('R_0, R_8') >>> b = Beam(12, E, I) >>> b.apply_support(0, 'roller') >>> b.apply_support(8, 'roller') >>> b.solve_for_ild_reactions(1, R_0, R_8) >>> b.solve_for_ild_moment(4, 1, R_0, R_8) >>> b.ild_moment Piecewise((-x/2, x < 4), (x/2 - 4, x > 4)) >>> b.plot_ild_moment() Plot object containing: [0]: cartesian line: Piecewise((-x/2, x < 4), (x/2 - 4, x > 4)) for x over (0.0, 12.0) """ if not self._ild_moment: raise ValueError("I.L.D. moment equation not found. Please use solve_for_ild_moment() to generate the I.L.D. moment equations.") x = self.variable if subs is None: subs = {} for sym in self._ild_moment.atoms(Symbol): if sym != x and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) for sym in self._length.atoms(Symbol): if sym != x and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) return plot(self._ild_moment.subs(subs), (x, 0, self._length), title='I.L.D. for Moment', xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{M}$', line_color='blue', show=True) @doctest_depends_on(modules=('numpy',)) def draw(self, pictorial=True): """ Returns a plot object representing the beam diagram of the beam. .. note:: The user must be careful while entering load values. The draw function assumes a sign convention which is used for plotting loads. Given a right handed coordinate system with XYZ coordinates, the beam's length is assumed to be along the positive X axis. The draw function recognizes positve loads(with n>-2) as loads acting along negative Y direction and positve moments acting along positive Z direction. Parameters ========== pictorial: Boolean (default=True) Setting ``pictorial=True`` would simply create a pictorial (scaled) view of the beam diagram not with the exact dimensions. Although setting ``pictorial=False`` would create a beam diagram with the exact dimensions on the plot Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam >>> from sympy import symbols >>> R1, R2 = symbols('R1, R2') >>> E, I = symbols('E, I') >>> b = Beam(50, 20, 30) >>> b.apply_load(10, 2, -1) >>> b.apply_load(R1, 10, -1) >>> b.apply_load(R2, 30, -1) >>> b.apply_load(90, 5, 0, 23) >>> b.apply_load(10, 30, 1, 50) >>> b.apply_support(50, "pin") >>> b.apply_support(0, "fixed") >>> b.apply_support(20, "roller") >>> p = b.draw() >>> p Plot object containing: [0]: cartesian line: 25*SingularityFunction(x, 5, 0) - 25*SingularityFunction(x, 23, 0) + SingularityFunction(x, 30, 1) - 20*SingularityFunction(x, 50, 0) - SingularityFunction(x, 50, 1) + 5 for x over (0.0, 50.0) [1]: cartesian line: 5 for x over (0.0, 50.0) >>> p.show() """ if not numpy: raise ImportError("To use this function numpy module is required") x = self.variable # checking whether length is an expression in terms of any Symbol. from sympy import Expr if isinstance(self.length, Expr): l = list(self.length.atoms(Symbol)) # assigning every Symbol a default value of 10 l = {i:10 for i in l} length = self.length.subs(l) else: l = {} length = self.length height = length/10 rectangles = [] rectangles.append({'xy':(0, 0), 'width':length, 'height': height, 'facecolor':"brown"}) annotations, markers, load_eq,load_eq1, fill = self._draw_load(pictorial, length, l) support_markers, support_rectangles = self._draw_supports(length, l) rectangles += support_rectangles markers += support_markers sing_plot = plot(height + load_eq, height + load_eq1, (x, 0, length), xlim=(-height, length + height), ylim=(-length, 1.25*length), annotations=annotations, markers=markers, rectangles=rectangles, line_color='brown', fill=fill, axis=False, show=False) return sing_plot def _draw_load(self, pictorial, length, l): loads = list(set(self.applied_loads) - set(self._support_as_loads)) height = length/10 x = self.variable annotations = [] markers = [] load_args = [] scaled_load = 0 load_args1 = [] scaled_load1 = 0 load_eq = 0 # For positive valued higher order loads load_eq1 = 0 # For negative valued higher order loads fill = None plus = 0 # For positive valued higher order loads minus = 0 # For negative valued higher order loads for load in loads: # check if the position of load is in terms of the beam length. if l: pos = load[1].subs(l) else: pos = load[1] # point loads if load[2] == -1: if isinstance(load[0], Symbol) or load[0].is_negative: annotations.append({'text':'', 'xy':(pos, 0), 'xytext':(pos, height - 4*height), 'arrowprops':dict(width= 1.5, headlength=5, headwidth=5, facecolor='black')}) else: annotations.append({'text':'', 'xy':(pos, height), 'xytext':(pos, height*4), 'arrowprops':dict(width= 1.5, headlength=4, headwidth=4, facecolor='black')}) # moment loads elif load[2] == -2: if load[0].is_negative: markers.append({'args':[[pos], [height/2]], 'marker': r'$\circlearrowright$', 'markersize':15}) else: markers.append({'args':[[pos], [height/2]], 'marker': r'$\circlearrowleft$', 'markersize':15}) # higher order loads elif load[2] >= 0: # `fill` will be assigned only when higher order loads are present value, start, order, end = load # Positive loads have their seperate equations if(value>0): plus = 1 # if pictorial is True we remake the load equation again with # some constant magnitude values. if pictorial: value = 10**(1-order) if order > 0 else length/2 scaled_load += value*SingularityFunction(x, start, order) if end: f2 = 10**(1-order)*x**order if order > 0 else length/2*x**order for i in range(0, order + 1): scaled_load -= (f2.diff(x, i).subs(x, end - start)* SingularityFunction(x, end, i)/factorial(i)) if pictorial: if isinstance(scaled_load, Add): load_args = scaled_load.args else: # when the load equation consists of only a single term load_args = (scaled_load,) load_eq = [i.subs(l) for i in load_args] else: if isinstance(self.load, Add): load_args = self.load.args else: load_args = (self.load,) load_eq = [i.subs(l) for i in load_args if list(i.atoms(SingularityFunction))[0].args[2] >= 0] load_eq = Add(*load_eq) # filling higher order loads with colour expr = height + load_eq.rewrite(Piecewise) y1 = lambdify(x, expr, 'numpy') # For loads with negative value else: minus = 1 # if pictorial is True we remake the load equation again with # some constant magnitude values. if pictorial: value = 10**(1-order) if order > 0 else length/2 scaled_load1 += value*SingularityFunction(x, start, order) if end: f2 = 10**(1-order)*x**order if order > 0 else length/2*x**order for i in range(0, order + 1): scaled_load1 -= (f2.diff(x, i).subs(x, end - start)* SingularityFunction(x, end, i)/factorial(i)) if pictorial: if isinstance(scaled_load1, Add): load_args1 = scaled_load1.args else: # when the load equation consists of only a single term load_args1 = (scaled_load1,) load_eq1 = [i.subs(l) for i in load_args1] else: if isinstance(self.load, Add): load_args1 = self.load.args1 else: load_args1 = (self.load,) load_eq1 = [i.subs(l) for i in load_args if list(i.atoms(SingularityFunction))[0].args[2] >= 0] load_eq1 = -Add(*load_eq1)-height # filling higher order loads with colour expr = height + load_eq1.rewrite(Piecewise) y1_ = lambdify(x, expr, 'numpy') y = numpy.arange(0, float(length), 0.001) y2 = float(height) if(plus == 1 and minus == 1): fill = {'x': y, 'y1': y1(y), 'y2': y1_(y), 'color':'darkkhaki'} elif(plus == 1): fill = {'x': y, 'y1': y1(y), 'y2': y2, 'color':'darkkhaki'} else: fill = {'x': y, 'y1': y1_(y), 'y2': y2 , 'color':'darkkhaki'} return annotations, markers, load_eq, load_eq1, fill def _draw_supports(self, length, l): height = float(length/10) support_markers = [] support_rectangles = [] for support in self._applied_supports: if l: pos = support[0].subs(l) else: pos = support[0] if support[1] == "pin": support_markers.append({'args':[pos, [0]], 'marker':6, 'markersize':13, 'color':"black"}) elif support[1] == "roller": support_markers.append({'args':[pos, [-height/2.5]], 'marker':'o', 'markersize':11, 'color':"black"}) elif support[1] == "fixed": if pos == 0: support_rectangles.append({'xy':(0, -3*height), 'width':-length/20, 'height':6*height + height, 'fill':False, 'hatch':'/////'}) else: support_rectangles.append({'xy':(length, -3*height), 'width':length/20, 'height': 6*height + height, 'fill':False, 'hatch':'/////'}) return support_markers, support_rectangles class Beam3D(Beam): """ This class handles loads applied in any direction of a 3D space along with unequal values of Second moment along different axes. .. note:: While solving a beam bending problem, a user should choose its own sign convention and should stick to it. The results will automatically follow the chosen sign convention. This class assumes that any kind of distributed load/moment is applied through out the span of a beam. Examples ======== There is a beam of l meters long. A constant distributed load of magnitude q is applied along y-axis from start till the end of beam. A constant distributed moment of magnitude m is also applied along z-axis from start till the end of beam. Beam is fixed at both of its end. So, deflection of the beam at the both ends is restricted. >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols, simplify, collect, factor >>> l, E, G, I, A = symbols('l, E, G, I, A') >>> b = Beam3D(l, E, G, I, A) >>> x, q, m = symbols('x, q, m') >>> b.apply_load(q, 0, 0, dir="y") >>> b.apply_moment_load(m, 0, -1, dir="z") >>> b.shear_force() [0, -q*x, 0] >>> b.bending_moment() [0, 0, -m*x + q*x**2/2] >>> b.bc_slope = [(0, [0, 0, 0]), (l, [0, 0, 0])] >>> b.bc_deflection = [(0, [0, 0, 0]), (l, [0, 0, 0])] >>> b.solve_slope_deflection() >>> factor(b.slope()) [0, 0, x*(-l + x)*(-A*G*l**3*q + 2*A*G*l**2*q*x - 12*E*I*l*q - 72*E*I*m + 24*E*I*q*x)/(12*E*I*(A*G*l**2 + 12*E*I))] >>> dx, dy, dz = b.deflection() >>> dy = collect(simplify(dy), x) >>> dx == dz == 0 True >>> dy == (x*(12*E*I*l*(A*G*l**2*q - 2*A*G*l*m + 12*E*I*q) ... + x*(A*G*l*(3*l*(A*G*l**2*q - 2*A*G*l*m + 12*E*I*q) + x*(-2*A*G*l**2*q + 4*A*G*l*m - 24*E*I*q)) ... + A*G*(A*G*l**2 + 12*E*I)*(-2*l**2*q + 6*l*m - 4*m*x + q*x**2) ... - 12*E*I*q*(A*G*l**2 + 12*E*I)))/(24*A*E*G*I*(A*G*l**2 + 12*E*I))) True References ========== .. [1] http://homes.civil.aau.dk/jc/FemteSemester/Beams3D.pdf """ def __init__(self, length, elastic_modulus, shear_modulus , second_moment, area, variable=Symbol('x')): """Initializes the class. Parameters ========== length : Sympifyable A Symbol or value representing the Beam's length. elastic_modulus : Sympifyable A SymPy expression representing the Beam's Modulus of Elasticity. It is a measure of the stiffness of the Beam material. shear_modulus : Sympifyable A SymPy expression representing the Beam's Modulus of rigidity. It is a measure of rigidity of the Beam material. second_moment : Sympifyable or list A list of two elements having SymPy expression representing the Beam's Second moment of area. First value represent Second moment across y-axis and second across z-axis. Single SymPy expression can be passed if both values are same area : Sympifyable A SymPy expression representing the Beam's cross-sectional area in a plane prependicular to length of the Beam. variable : Symbol, optional A Symbol object that will be used as the variable along the beam while representing the load, shear, moment, slope and deflection curve. By default, it is set to ``Symbol('x')``. """ super().__init__(length, elastic_modulus, second_moment, variable) self.shear_modulus = shear_modulus self._area = area self._load_vector = [0, 0, 0] self._moment_load_vector = [0, 0, 0] self._load_Singularity = [0, 0, 0] self._slope = [0, 0, 0] self._deflection = [0, 0, 0] @property def shear_modulus(self): """Young's Modulus of the Beam. """ return self._shear_modulus @shear_modulus.setter def shear_modulus(self, e): self._shear_modulus = sympify(e) @property def second_moment(self): """Second moment of area of the Beam. """ return self._second_moment @second_moment.setter def second_moment(self, i): if isinstance(i, list): i = [sympify(x) for x in i] self._second_moment = i else: self._second_moment = sympify(i) @property def area(self): """Cross-sectional area of the Beam. """ return self._area @area.setter def area(self, a): self._area = sympify(a) @property def load_vector(self): """ Returns a three element list representing the load vector. """ return self._load_vector @property def moment_load_vector(self): """ Returns a three element list representing moment loads on Beam. """ return self._moment_load_vector @property def boundary_conditions(self): """ Returns a dictionary of boundary conditions applied on the beam. The dictionary has two keywords namely slope and deflection. The value of each keyword is a list of tuple, where each tuple contains location and value of a boundary condition in the format (location, value). Further each value is a list corresponding to slope or deflection(s) values along three axes at that location. Examples ======== There is a beam of length 4 meters. The slope at 0 should be 4 along the x-axis and 0 along others. At the other end of beam, deflection along all the three axes should be zero. >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(30, E, G, I, A, x) >>> b.bc_slope = [(0, (4, 0, 0))] >>> b.bc_deflection = [(4, [0, 0, 0])] >>> b.boundary_conditions {'deflection': [(4, [0, 0, 0])], 'slope': [(0, (4, 0, 0))]} Here the deflection of the beam should be ``0`` along all the three axes at ``4``. Similarly, the slope of the beam should be ``4`` along x-axis and ``0`` along y and z axis at ``0``. """ return self._boundary_conditions def polar_moment(self): """ Returns the polar moment of area of the beam about the X axis with respect to the centroid. Examples ======== >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A = symbols('l, E, G, I, A') >>> b = Beam3D(l, E, G, I, A) >>> b.polar_moment() 2*I >>> I1 = [9, 15] >>> b = Beam3D(l, E, G, I1, A) >>> b.polar_moment() 24 """ if not iterable(self.second_moment): return 2*self.second_moment return sum(self.second_moment) def apply_load(self, value, start, order, dir="y"): """ This method adds up the force load to a particular beam object. Parameters ========== value : Sympifyable The magnitude of an applied load. dir : String Axis along which load is applied. order : Integer The order of the applied load. - For point loads, order=-1 - For constant distributed load, order=0 - For ramp loads, order=1 - For parabolic ramp loads, order=2 - ... so on. """ x = self.variable value = sympify(value) start = sympify(start) order = sympify(order) if dir == "x": if not order == -1: self._load_vector[0] += value self._load_Singularity[0] += value*SingularityFunction(x, start, order) elif dir == "y": if not order == -1: self._load_vector[1] += value self._load_Singularity[1] += value*SingularityFunction(x, start, order) else: if not order == -1: self._load_vector[2] += value self._load_Singularity[2] += value*SingularityFunction(x, start, order) def apply_moment_load(self, value, start, order, dir="y"): """ This method adds up the moment loads to a particular beam object. Parameters ========== value : Sympifyable The magnitude of an applied moment. dir : String Axis along which moment is applied. order : Integer The order of the applied load. - For point moments, order=-2 - For constant distributed moment, order=-1 - For ramp moments, order=0 - For parabolic ramp moments, order=1 - ... so on. """ x = self.variable value = sympify(value) start = sympify(start) order = sympify(order) if dir == "x": if not order == -2: self._moment_load_vector[0] += value self._load_Singularity[0] += value*SingularityFunction(x, start, order) elif dir == "y": if not order == -2: self._moment_load_vector[1] += value self._load_Singularity[0] += value*SingularityFunction(x, start, order) else: if not order == -2: self._moment_load_vector[2] += value self._load_Singularity[0] += value*SingularityFunction(x, start, order) def apply_support(self, loc, type="fixed"): if type in ("pin", "roller"): reaction_load = Symbol('R_'+str(loc)) self._reaction_loads[reaction_load] = reaction_load self.bc_deflection.append((loc, [0, 0, 0])) else: reaction_load = Symbol('R_'+str(loc)) reaction_moment = Symbol('M_'+str(loc)) self._reaction_loads[reaction_load] = [reaction_load, reaction_moment] self.bc_deflection.append((loc, [0, 0, 0])) self.bc_slope.append((loc, [0, 0, 0])) def solve_for_reaction_loads(self, *reaction): """ Solves for the reaction forces. Examples ======== There is a beam of length 30 meters. It it supported by rollers at of its end. A constant distributed load of magnitude 8 N is applied from start till its end along y-axis. Another linear load having slope equal to 9 is applied along z-axis. >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(30, E, G, I, A, x) >>> b.apply_load(8, start=0, order=0, dir="y") >>> b.apply_load(9*x, start=0, order=0, dir="z") >>> b.bc_deflection = [(0, [0, 0, 0]), (30, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="y") >>> b.apply_load(R2, start=30, order=-1, dir="y") >>> b.apply_load(R3, start=0, order=-1, dir="z") >>> b.apply_load(R4, start=30, order=-1, dir="z") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.reaction_loads {R1: -120, R2: -120, R3: -1350, R4: -2700} """ x = self.variable l = self.length q = self._load_Singularity shear_curves = [integrate(load, x) for load in q] moment_curves = [integrate(shear, x) for shear in shear_curves] for i in range(3): react = [r for r in reaction if (shear_curves[i].has(r) or moment_curves[i].has(r))] if len(react) == 0: continue shear_curve = limit(shear_curves[i], x, l) moment_curve = limit(moment_curves[i], x, l) sol = list((linsolve([shear_curve, moment_curve], react).args)[0]) sol_dict = dict(zip(react, sol)) reaction_loads = self._reaction_loads # Check if any of the evaluated rection exists in another direction # and if it exists then it should have same value. for key in sol_dict: if key in reaction_loads and sol_dict[key] != reaction_loads[key]: raise ValueError("Ambiguous solution for %s in different directions." % key) self._reaction_loads.update(sol_dict) def shear_force(self): """ Returns a list of three expressions which represents the shear force curve of the Beam object along all three axes. """ x = self.variable q = self._load_vector return [integrate(-q[0], x), integrate(-q[1], x), integrate(-q[2], x)] def axial_force(self): """ Returns expression of Axial shear force present inside the Beam object. """ return self.shear_force()[0] def shear_stress(self): """ Returns a list of three expressions which represents the shear stress curve of the Beam object along all three axes. """ return [self.shear_force()[0]/self._area, self.shear_force()[1]/self._area, self.shear_force()[2]/self._area] def axial_stress(self): """ Returns expression of Axial stress present inside the Beam object. """ return self.axial_force()/self._area def bending_moment(self): """ Returns a list of three expressions which represents the bending moment curve of the Beam object along all three axes. """ x = self.variable m = self._moment_load_vector shear = self.shear_force() return [integrate(-m[0], x), integrate(-m[1] + shear[2], x), integrate(-m[2] - shear[1], x) ] def torsional_moment(self): """ Returns expression of Torsional moment present inside the Beam object. """ return self.bending_moment()[0] def solve_slope_deflection(self): from sympy import dsolve, Function, Derivative, Eq x = self.variable l = self.length E = self.elastic_modulus G = self.shear_modulus I = self.second_moment if isinstance(I, list): I_y, I_z = I[0], I[1] else: I_y = I_z = I A = self._area load = self._load_vector moment = self._moment_load_vector defl = Function('defl') theta = Function('theta') # Finding deflection along x-axis(and corresponding slope value by differentiating it) # Equation used: Derivative(E*A*Derivative(def_x(x), x), x) + load_x = 0 eq = Derivative(E*A*Derivative(defl(x), x), x) + load[0] def_x = dsolve(Eq(eq, 0), defl(x)).args[1] # Solving constants originated from dsolve C1 = Symbol('C1') C2 = Symbol('C2') constants = list((linsolve([def_x.subs(x, 0), def_x.subs(x, l)], C1, C2).args)[0]) def_x = def_x.subs({C1:constants[0], C2:constants[1]}) slope_x = def_x.diff(x) self._deflection[0] = def_x self._slope[0] = slope_x # Finding deflection along y-axis and slope across z-axis. System of equation involved: # 1: Derivative(E*I_z*Derivative(theta_z(x), x), x) + G*A*(Derivative(defl_y(x), x) - theta_z(x)) + moment_z = 0 # 2: Derivative(G*A*(Derivative(defl_y(x), x) - theta_z(x)), x) + load_y = 0 C_i = Symbol('C_i') # Substitute value of `G*A*(Derivative(defl_y(x), x) - theta_z(x))` from (2) in (1) eq1 = Derivative(E*I_z*Derivative(theta(x), x), x) + (integrate(-load[1], x) + C_i) + moment[2] slope_z = dsolve(Eq(eq1, 0)).args[1] # Solve for constants originated from using dsolve on eq1 constants = list((linsolve([slope_z.subs(x, 0), slope_z.subs(x, l)], C1, C2).args)[0]) slope_z = slope_z.subs({C1:constants[0], C2:constants[1]}) # Put value of slope obtained back in (2) to solve for `C_i` and find deflection across y-axis eq2 = G*A*(Derivative(defl(x), x)) + load[1]*x - C_i - G*A*slope_z def_y = dsolve(Eq(eq2, 0), defl(x)).args[1] # Solve for constants originated from using dsolve on eq2 constants = list((linsolve([def_y.subs(x, 0), def_y.subs(x, l)], C1, C_i).args)[0]) self._deflection[1] = def_y.subs({C1:constants[0], C_i:constants[1]}) self._slope[2] = slope_z.subs(C_i, constants[1]) # Finding deflection along z-axis and slope across y-axis. System of equation involved: # 1: Derivative(E*I_y*Derivative(theta_y(x), x), x) - G*A*(Derivative(defl_z(x), x) + theta_y(x)) + moment_y = 0 # 2: Derivative(G*A*(Derivative(defl_z(x), x) + theta_y(x)), x) + load_z = 0 # Substitute value of `G*A*(Derivative(defl_y(x), x) + theta_z(x))` from (2) in (1) eq1 = Derivative(E*I_y*Derivative(theta(x), x), x) + (integrate(load[2], x) - C_i) + moment[1] slope_y = dsolve(Eq(eq1, 0)).args[1] # Solve for constants originated from using dsolve on eq1 constants = list((linsolve([slope_y.subs(x, 0), slope_y.subs(x, l)], C1, C2).args)[0]) slope_y = slope_y.subs({C1:constants[0], C2:constants[1]}) # Put value of slope obtained back in (2) to solve for `C_i` and find deflection across z-axis eq2 = G*A*(Derivative(defl(x), x)) + load[2]*x - C_i + G*A*slope_y def_z = dsolve(Eq(eq2,0)).args[1] # Solve for constants originated from using dsolve on eq2 constants = list((linsolve([def_z.subs(x, 0), def_z.subs(x, l)], C1, C_i).args)[0]) self._deflection[2] = def_z.subs({C1:constants[0], C_i:constants[1]}) self._slope[1] = slope_y.subs(C_i, constants[1]) def slope(self): """ Returns a three element list representing slope of deflection curve along all the three axes. """ return self._slope def deflection(self): """ Returns a three element list representing deflection curve along all the three axes. """ return self._deflection def _plot_shear_force(self, dir, subs=None): shear_force = self.shear_force() if dir == 'x': dir_num = 0 color = 'r' elif dir == 'y': dir_num = 1 color = 'g' elif dir == 'z': dir_num = 2 color = 'b' if subs is None: subs = {} for sym in shear_force[dir_num].atoms(Symbol): if sym != self.variable and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(shear_force[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Shear Force along %c direction'%dir, xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{V(%c)}$'%dir, line_color=color) def plot_shear_force(self, dir="all", subs=None): """ Returns a plot for Shear force along all three directions present in the Beam object. Parameters ========== dir : string (default : "all") Direction along which shear force plot is required. If no direction is specified, all plots are displayed. subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 20 meters. It it supported by rollers at of its end. A linear load having slope equal to 12 is applied along y-axis. A constant distributed load of magnitude 15 N is applied from start till its end along z-axis. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, E, G, I, A, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.plot_shear_force() PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: 0 for x over (0.0, 20.0) Plot[1]:Plot object containing: [0]: cartesian line: -6*x**2 for x over (0.0, 20.0) Plot[2]:Plot object containing: [0]: cartesian line: -15*x for x over (0.0, 20.0) """ dir = dir.lower() # For shear force along x direction if dir == "x": Px = self._plot_shear_force('x', subs) return Px.show() # For shear force along y direction elif dir == "y": Py = self._plot_shear_force('y', subs) return Py.show() # For shear force along z direction elif dir == "z": Pz = self._plot_shear_force('z', subs) return Pz.show() # For shear force along all direction else: Px = self._plot_shear_force('x', subs) Py = self._plot_shear_force('y', subs) Pz = self._plot_shear_force('z', subs) return PlotGrid(3, 1, Px, Py, Pz) def _plot_bending_moment(self, dir, subs=None): bending_moment = self.bending_moment() if dir == 'x': dir_num = 0 color = 'g' elif dir == 'y': dir_num = 1 color = 'c' elif dir == 'z': dir_num = 2 color = 'm' if subs is None: subs = {} for sym in bending_moment[dir_num].atoms(Symbol): if sym != self.variable and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(bending_moment[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Bending Moment along %c direction'%dir, xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{M(%c)}$'%dir, line_color=color) def plot_bending_moment(self, dir="all", subs=None): """ Returns a plot for bending moment along all three directions present in the Beam object. Parameters ========== dir : string (default : "all") Direction along which bending moment plot is required. If no direction is specified, all plots are displayed. subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 20 meters. It it supported by rollers at of its end. A linear load having slope equal to 12 is applied along y-axis. A constant distributed load of magnitude 15 N is applied from start till its end along z-axis. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, E, G, I, A, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.plot_bending_moment() PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: 0 for x over (0.0, 20.0) Plot[1]:Plot object containing: [0]: cartesian line: -15*x**2/2 for x over (0.0, 20.0) Plot[2]:Plot object containing: [0]: cartesian line: 2*x**3 for x over (0.0, 20.0) """ dir = dir.lower() # For bending moment along x direction if dir == "x": Px = self._plot_bending_moment('x', subs) return Px.show() # For bending moment along y direction elif dir == "y": Py = self._plot_bending_moment('y', subs) return Py.show() # For bending moment along z direction elif dir == "z": Pz = self._plot_bending_moment('z', subs) return Pz.show() # For bending moment along all direction else: Px = self._plot_bending_moment('x', subs) Py = self._plot_bending_moment('y', subs) Pz = self._plot_bending_moment('z', subs) return PlotGrid(3, 1, Px, Py, Pz) def _plot_slope(self, dir, subs=None): slope = self.slope() if dir == 'x': dir_num = 0 color = 'b' elif dir == 'y': dir_num = 1 color = 'm' elif dir == 'z': dir_num = 2 color = 'g' if subs is None: subs = {} for sym in slope[dir_num].atoms(Symbol): if sym != self.variable and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(slope[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Slope along %c direction'%dir, xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{\theta(%c)}$'%dir, line_color=color) def plot_slope(self, dir="all", subs=None): """ Returns a plot for Slope along all three directions present in the Beam object. Parameters ========== dir : string (default : "all") Direction along which Slope plot is required. If no direction is specified, all plots are displayed. subs : dictionary Python dictionary containing Symbols as keys and their corresponding values. Examples ======== There is a beam of length 20 meters. It it supported by rollers at of its end. A linear load having slope equal to 12 is applied along y-axis. A constant distributed load of magnitude 15 N is applied from start till its end along z-axis. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, 40, 21, 100, 25, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.solve_slope_deflection() >>> b.plot_slope() PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: 0 for x over (0.0, 20.0) Plot[1]:Plot object containing: [0]: cartesian line: -x**3/1600 + 3*x**2/160 - x/8 for x over (0.0, 20.0) Plot[2]:Plot object containing: [0]: cartesian line: x**4/8000 - 19*x**2/172 + 52*x/43 for x over (0.0, 20.0) """ dir = dir.lower() # For Slope along x direction if dir == "x": Px = self._plot_slope('x', subs) return Px.show() # For Slope along y direction elif dir == "y": Py = self._plot_slope('y', subs) return Py.show() # For Slope along z direction elif dir == "z": Pz = self._plot_slope('z', subs) return Pz.show() # For Slope along all direction else: Px = self._plot_slope('x', subs) Py = self._plot_slope('y', subs) Pz = self._plot_slope('z', subs) return PlotGrid(3, 1, Px, Py, Pz) def _plot_deflection(self, dir, subs=None): deflection = self.deflection() if dir == 'x': dir_num = 0 color = 'm' elif dir == 'y': dir_num = 1 color = 'r' elif dir == 'z': dir_num = 2 color = 'c' if subs is None: subs = {} for sym in deflection[dir_num].atoms(Symbol): if sym != self.variable and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(deflection[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Deflection along %c direction'%dir, xlabel=r'$\mathrm{X}$', ylabel=r'$\mathrm{\delta(%c)}$'%dir, line_color=color) def plot_deflection(self, dir="all", subs=None): """ Returns a plot for Deflection along all three directions present in the Beam object. Parameters ========== dir : string (default : "all") Direction along which deflection plot is required. If no direction is specified, all plots are displayed. subs : dictionary Python dictionary containing Symbols as keys and their corresponding values. Examples ======== There is a beam of length 20 meters. It it supported by rollers at of its end. A linear load having slope equal to 12 is applied along y-axis. A constant distributed load of magnitude 15 N is applied from start till its end along z-axis. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, 40, 21, 100, 25, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.solve_slope_deflection() >>> b.plot_deflection() PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: 0 for x over (0.0, 20.0) Plot[1]:Plot object containing: [0]: cartesian line: x**5/40000 - 4013*x**3/90300 + 26*x**2/43 + 1520*x/903 for x over (0.0, 20.0) Plot[2]:Plot object containing: [0]: cartesian line: x**4/6400 - x**3/160 + 27*x**2/560 + 2*x/7 for x over (0.0, 20.0) """ dir = dir.lower() # For deflection along x direction if dir == "x": Px = self._plot_deflection('x', subs) return Px.show() # For deflection along y direction elif dir == "y": Py = self._plot_deflection('y', subs) return Py.show() # For deflection along z direction elif dir == "z": Pz = self._plot_deflection('z', subs) return Pz.show() # For deflection along all direction else: Px = self._plot_deflection('x', subs) Py = self._plot_deflection('y', subs) Pz = self._plot_deflection('z', subs) return PlotGrid(3, 1, Px, Py, Pz) def plot_loading_results(self, dir='x', subs=None): """ Returns a subplot of Shear Force, Bending Moment, Slope and Deflection of the Beam object along the direction specified. Parameters ========== dir : string (default : "x") Direction along which plots are required. If no direction is specified, plots along x-axis are displayed. subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 20 meters. It it supported by rollers at of its end. A linear load having slope equal to 12 is applied along y-axis. A constant distributed load of magnitude 15 N is applied from start till its end along z-axis. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, E, G, I, A, x) >>> subs = {E:40, G:21, I:100, A:25} >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.solve_slope_deflection() >>> b.plot_loading_results('y',subs) PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: -6*x**2 for x over (0.0, 20.0) Plot[1]:Plot object containing: [0]: cartesian line: -15*x**2/2 for x over (0.0, 20.0) Plot[2]:Plot object containing: [0]: cartesian line: -x**3/1600 + 3*x**2/160 - x/8 for x over (0.0, 20.0) Plot[3]:Plot object containing: [0]: cartesian line: x**5/40000 - 4013*x**3/90300 + 26*x**2/43 + 1520*x/903 for x over (0.0, 20.0) """ dir = dir.lower() if subs is None: subs = {} ax1 = self._plot_shear_force(dir, subs) ax2 = self._plot_bending_moment(dir, subs) ax3 = self._plot_slope(dir, subs) ax4 = self._plot_deflection(dir, subs) return PlotGrid(4, 1, ax1, ax2, ax3, ax4) def _plot_shear_stress(self, dir, subs=None): shear_stress = self.shear_stress() if dir == 'x': dir_num = 0 color = 'r' elif dir == 'y': dir_num = 1 color = 'g' elif dir == 'z': dir_num = 2 color = 'b' if subs is None: subs = {} for sym in shear_stress[dir_num].atoms(Symbol): if sym != self.variable and sym not in subs: raise ValueError('Value of %s was not passed.' %sym) if self.length in subs: length = subs[self.length] else: length = self.length return plot(shear_stress[dir_num].subs(subs), (self.variable, 0, length), show = False, title='Shear stress along %c direction'%dir, xlabel=r'$\mathrm{X}$', ylabel=r'$\tau(%c)$'%dir, line_color=color) def plot_shear_stress(self, dir="all", subs=None): """ Returns a plot for Shear Stress along all three directions present in the Beam object. Parameters ========== dir : string (default : "all") Direction along which shear stress plot is required. If no direction is specified, all plots are displayed. subs : dictionary Python dictionary containing Symbols as key and their corresponding values. Examples ======== There is a beam of length 20 meters and area of cross section 2 square meters. It it supported by rollers at of its end. A linear load having slope equal to 12 is applied along y-axis. A constant distributed load of magnitude 15 N is applied from start till its end along z-axis. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, E, G, I, 2, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.plot_shear_stress() PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: 0 for x over (0.0, 20.0) Plot[1]:Plot object containing: [0]: cartesian line: -3*x**2 for x over (0.0, 20.0) Plot[2]:Plot object containing: [0]: cartesian line: -15*x/2 for x over (0.0, 20.0) """ dir = dir.lower() # For shear stress along x direction if dir == "x": Px = self._plot_shear_stress('x', subs) return Px.show() # For shear stress along y direction elif dir == "y": Py = self._plot_shear_stress('y', subs) return Py.show() # For shear stress along z direction elif dir == "z": Pz = self._plot_shear_stress('z', subs) return Pz.show() # For shear stress along all direction else: Px = self._plot_shear_stress('x', subs) Py = self._plot_shear_stress('y', subs) Pz = self._plot_shear_stress('z', subs) return PlotGrid(3, 1, Px, Py, Pz) def _max_shear_force(self, dir): """ Helper function for max_shear_force(). """ dir = dir.lower() if dir == 'x': dir_num = 0 elif dir == 'y': dir_num = 1 elif dir == 'z': dir_num = 2 from sympy import solve if not self.shear_force()[dir_num]: return (0,0) # To restrict the range within length of the Beam load_curve = Piecewise((float("nan"), self.variable<=0), (self._load_vector[dir_num], self.variable>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, 40, 21, 100, 25, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.max_shear_force() [(0, 0), (20, 2400), (20, 300)] """ max_shear = [] max_shear.append(self._max_shear_force('x')) max_shear.append(self._max_shear_force('y')) max_shear.append(self._max_shear_force('z')) return max_shear def _max_bending_moment(self, dir): """ Helper function for max_bending_moment(). """ dir = dir.lower() if dir == 'x': dir_num = 0 elif dir == 'y': dir_num = 1 elif dir == 'z': dir_num = 2 from sympy import solve if not self.bending_moment()[dir_num]: return (0,0) # To restrict the range within length of the Beam shear_curve = Piecewise((float("nan"), self.variable<=0), (self.shear_force()[dir_num], self.variable>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, 40, 21, 100, 25, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.max_bending_moment() [(0, 0), (20, 3000), (20, 16000)] """ max_bmoment = [] max_bmoment.append(self._max_bending_moment('x')) max_bmoment.append(self._max_bending_moment('y')) max_bmoment.append(self._max_bending_moment('z')) return max_bmoment max_bmoment = max_bending_moment def _max_deflection(self, dir): """ Helper function for max_Deflection() """ dir = dir.lower() if dir == 'x': dir_num = 0 elif dir == 'y': dir_num = 1 elif dir == 'z': dir_num = 2 from sympy import solve if not self.deflection()[dir_num]: return (0,0) # To restrict the range within length of the Beam slope_curve = Piecewise((float("nan"), self.variable<=0), (self.slope()[dir_num], self.variable>> from sympy.physics.continuum_mechanics.beam import Beam3D >>> from sympy import symbols >>> l, E, G, I, A, x = symbols('l, E, G, I, A, x') >>> b = Beam3D(20, 40, 21, 100, 25, x) >>> b.apply_load(15, start=0, order=0, dir="z") >>> b.apply_load(12*x, start=0, order=0, dir="y") >>> b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] >>> R1, R2, R3, R4 = symbols('R1, R2, R3, R4') >>> b.apply_load(R1, start=0, order=-1, dir="z") >>> b.apply_load(R2, start=20, order=-1, dir="z") >>> b.apply_load(R3, start=0, order=-1, dir="y") >>> b.apply_load(R4, start=20, order=-1, dir="y") >>> b.solve_for_reaction_loads(R1, R2, R3, R4) >>> b.solve_slope_deflection() >>> b.max_deflection() [(0, 0), (10, 495/14), (-10 + 10*sqrt(10793)/43, (10 - 10*sqrt(10793)/43)**3/160 - 20/7 + (10 - 10*sqrt(10793)/43)**4/6400 + 20*sqrt(10793)/301 + 27*(10 - 10*sqrt(10793)/43)**2/560)] """ max_def = [] max_def.append(self._max_deflection('x')) max_def.append(self._max_deflection('y')) max_def.append(self._max_deflection('z')) return max_def sympy-sympy-1.9/sympy/physics/continuum_mechanics/tests/000077500000000000000000000000001412543434000237635ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/continuum_mechanics/tests/__init__.py000066400000000000000000000000001412543434000260620ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/continuum_mechanics/tests/test_beam.py000066400000000000000000000630131412543434000263030ustar00rootroot00000000000000from sympy import expand, Symbol, symbols, S, Interval, pi, Rational, simplify from sympy.physics.continuum_mechanics.beam import Beam from sympy.functions import SingularityFunction, Piecewise, meijerg, Abs, log from sympy.testing.pytest import raises from sympy.physics.units import meter, newton, kilo, giga, milli from sympy.physics.continuum_mechanics.beam import Beam3D from sympy.geometry import Circle, Polygon, Point2D, Triangle from sympy import sympify x = Symbol('x') y = Symbol('y') R1, R2 = symbols('R1, R2') def test_Beam(): E = Symbol('E') E_1 = Symbol('E_1') I = Symbol('I') I_1 = Symbol('I_1') A = Symbol('A') b = Beam(1, E, I) assert b.length == 1 assert b.elastic_modulus == E assert b.second_moment == I assert b.variable == x # Test the length setter b.length = 4 assert b.length == 4 # Test the E setter b.elastic_modulus = E_1 assert b.elastic_modulus == E_1 # Test the I setter b.second_moment = I_1 assert b.second_moment is I_1 # Test the variable setter b.variable = y assert b.variable is y # Test for all boundary conditions. b.bc_deflection = [(0, 2)] b.bc_slope = [(0, 1)] assert b.boundary_conditions == {'deflection': [(0, 2)], 'slope': [(0, 1)]} # Test for slope boundary condition method b.bc_slope.extend([(4, 3), (5, 0)]) s_bcs = b.bc_slope assert s_bcs == [(0, 1), (4, 3), (5, 0)] # Test for deflection boundary condition method b.bc_deflection.extend([(4, 3), (5, 0)]) d_bcs = b.bc_deflection assert d_bcs == [(0, 2), (4, 3), (5, 0)] # Test for updated boundary conditions bcs_new = b.boundary_conditions assert bcs_new == { 'deflection': [(0, 2), (4, 3), (5, 0)], 'slope': [(0, 1), (4, 3), (5, 0)]} b1 = Beam(30, E, I) b1.apply_load(-8, 0, -1) b1.apply_load(R1, 10, -1) b1.apply_load(R2, 30, -1) b1.apply_load(120, 30, -2) b1.bc_deflection = [(10, 0), (30, 0)] b1.solve_for_reaction_loads(R1, R2) # Test for finding reaction forces p = b1.reaction_loads q = {R1: 6, R2: 2} assert p == q # Test for load distribution function. p = b1.load q = -8*SingularityFunction(x, 0, -1) + 6*SingularityFunction(x, 10, -1) \ + 120*SingularityFunction(x, 30, -2) + 2*SingularityFunction(x, 30, -1) assert p == q # Test for shear force distribution function p = b1.shear_force() q = 8*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 10, 0) \ - 120*SingularityFunction(x, 30, -1) - 2*SingularityFunction(x, 30, 0) assert p == q # Test for shear stress distribution function p = b1.shear_stress() q = (8*SingularityFunction(x, 0, 0) - 6*SingularityFunction(x, 10, 0) \ - 120*SingularityFunction(x, 30, -1) \ - 2*SingularityFunction(x, 30, 0))/A assert p==q # Test for bending moment distribution function p = b1.bending_moment() q = 8*SingularityFunction(x, 0, 1) - 6*SingularityFunction(x, 10, 1) \ - 120*SingularityFunction(x, 30, 0) - 2*SingularityFunction(x, 30, 1) assert p == q # Test for slope distribution function p = b1.slope() q = -4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) \ + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) \ + Rational(4000, 3) assert p == q/(E*I) # Test for deflection distribution function p = b1.deflection() q = x*Rational(4000, 3) - 4*SingularityFunction(x, 0, 3)/3 \ + SingularityFunction(x, 10, 3) + 60*SingularityFunction(x, 30, 2) \ + SingularityFunction(x, 30, 3)/3 - 12000 assert p == q/(E*I) # Test using symbols l = Symbol('l') w0 = Symbol('w0') w2 = Symbol('w2') a1 = Symbol('a1') c = Symbol('c') c1 = Symbol('c1') d = Symbol('d') e = Symbol('e') f = Symbol('f') b2 = Beam(l, E, I) b2.apply_load(w0, a1, 1) b2.apply_load(w2, c1, -1) b2.bc_deflection = [(c, d)] b2.bc_slope = [(e, f)] # Test for load distribution function. p = b2.load q = w0*SingularityFunction(x, a1, 1) + w2*SingularityFunction(x, c1, -1) assert p == q # Test for shear force distribution function p = b2.shear_force() q = -w0*SingularityFunction(x, a1, 2)/2 \ - w2*SingularityFunction(x, c1, 0) assert p == q # Test for shear stress distribution function p = b2.shear_stress() q = (-w0*SingularityFunction(x, a1, 2)/2 \ - w2*SingularityFunction(x, c1, 0))/A assert p == q # Test for bending moment distribution function p = b2.bending_moment() q = -w0*SingularityFunction(x, a1, 3)/6 - w2*SingularityFunction(x, c1, 1) assert p == q # Test for slope distribution function p = b2.slope() q = (w0*SingularityFunction(x, a1, 4)/24 + w2*SingularityFunction(x, c1, 2)/2)/(E*I) + (E*I*f - w0*SingularityFunction(e, a1, 4)/24 - w2*SingularityFunction(e, c1, 2)/2)/(E*I) assert expand(p) == expand(q) # Test for deflection distribution function p = b2.deflection() q = x*(E*I*f - w0*SingularityFunction(e, a1, 4)/24 \ - w2*SingularityFunction(e, c1, 2)/2)/(E*I) \ + (w0*SingularityFunction(x, a1, 5)/120 \ + w2*SingularityFunction(x, c1, 3)/6)/(E*I) \ + (E*I*(-c*f + d) + c*w0*SingularityFunction(e, a1, 4)/24 \ + c*w2*SingularityFunction(e, c1, 2)/2 \ - w0*SingularityFunction(c, a1, 5)/120 \ - w2*SingularityFunction(c, c1, 3)/6)/(E*I) assert simplify(p - q) == 0 b3 = Beam(9, E, I, 2) b3.apply_load(value=-2, start=2, order=2, end=3) b3.bc_slope.append((0, 2)) C3 = symbols('C3') C4 = symbols('C4') p = b3.load q = -2*SingularityFunction(x, 2, 2) + 2*SingularityFunction(x, 3, 0) \ + 4*SingularityFunction(x, 3, 1) + 2*SingularityFunction(x, 3, 2) assert p == q p = b3.shear_force() q = 2*SingularityFunction(x, 2, 3)/3 - 2*SingularityFunction(x, 3, 1) \ - 2*SingularityFunction(x, 3, 2) - 2*SingularityFunction(x, 3, 3)/3 assert p == q p = b3.shear_stress() q = SingularityFunction(x, 2, 3)/3 - 1*SingularityFunction(x, 3, 1) \ - 1*SingularityFunction(x, 3, 2) - 1*SingularityFunction(x, 3, 3)/3 assert p == q p = b3.slope() q = 2 - (SingularityFunction(x, 2, 5)/30 - SingularityFunction(x, 3, 3)/3 \ - SingularityFunction(x, 3, 4)/6 - SingularityFunction(x, 3, 5)/30)/(E*I) assert p == q p = b3.deflection() q = 2*x - (SingularityFunction(x, 2, 6)/180 \ - SingularityFunction(x, 3, 4)/12 - SingularityFunction(x, 3, 5)/30 \ - SingularityFunction(x, 3, 6)/180)/(E*I) assert p == q + C4 b4 = Beam(4, E, I, 3) b4.apply_load(-3, 0, 0, end=3) p = b4.load q = -3*SingularityFunction(x, 0, 0) + 3*SingularityFunction(x, 3, 0) assert p == q p = b4.shear_force() q = 3*SingularityFunction(x, 0, 1) \ - 3*SingularityFunction(x, 3, 1) assert p == q p = b4.shear_stress() q = SingularityFunction(x, 0, 1) - SingularityFunction(x, 3, 1) assert p == q p = b4.slope() q = -3*SingularityFunction(x, 0, 3)/6 + 3*SingularityFunction(x, 3, 3)/6 assert p == q/(E*I) + C3 p = b4.deflection() q = -3*SingularityFunction(x, 0, 4)/24 + 3*SingularityFunction(x, 3, 4)/24 assert p == q/(E*I) + C3*x + C4 # can't use end with point loads raises(ValueError, lambda: b4.apply_load(-3, 0, -1, end=3)) with raises(TypeError): b4.variable = 1 def test_insufficient_bconditions(): # Test cases when required number of boundary conditions # are not provided to solve the integration constants. L = symbols('L', positive=True) E, I, P, a3, a4 = symbols('E I P a3 a4') b = Beam(L, E, I, base_char='a') b.apply_load(R2, L, -1) b.apply_load(R1, 0, -1) b.apply_load(-P, L/2, -1) b.solve_for_reaction_loads(R1, R2) p = b.slope() q = P*SingularityFunction(x, 0, 2)/4 - P*SingularityFunction(x, L/2, 2)/2 + P*SingularityFunction(x, L, 2)/4 assert p == q/(E*I) + a3 p = b.deflection() q = P*SingularityFunction(x, 0, 3)/12 - P*SingularityFunction(x, L/2, 3)/6 + P*SingularityFunction(x, L, 3)/12 assert p == q/(E*I) + a3*x + a4 b.bc_deflection = [(0, 0)] p = b.deflection() q = a3*x + P*SingularityFunction(x, 0, 3)/12 - P*SingularityFunction(x, L/2, 3)/6 + P*SingularityFunction(x, L, 3)/12 assert p == q/(E*I) b.bc_deflection = [(0, 0), (L, 0)] p = b.deflection() q = -L**2*P*x/16 + P*SingularityFunction(x, 0, 3)/12 - P*SingularityFunction(x, L/2, 3)/6 + P*SingularityFunction(x, L, 3)/12 assert p == q/(E*I) def test_statically_indeterminate(): E = Symbol('E') I = Symbol('I') M1, M2 = symbols('M1, M2') F = Symbol('F') l = Symbol('l', positive=True) b5 = Beam(l, E, I) b5.bc_deflection = [(0, 0),(l, 0)] b5.bc_slope = [(0, 0),(l, 0)] b5.apply_load(R1, 0, -1) b5.apply_load(M1, 0, -2) b5.apply_load(R2, l, -1) b5.apply_load(M2, l, -2) b5.apply_load(-F, l/2, -1) b5.solve_for_reaction_loads(R1, R2, M1, M2) p = b5.reaction_loads q = {R1: F/2, R2: F/2, M1: -F*l/8, M2: F*l/8} assert p == q def test_beam_units(): E = Symbol('E') I = Symbol('I') R1, R2 = symbols('R1, R2') kN = kilo*newton gN = giga*newton b = Beam(8*meter, 200*gN/meter**2, 400*1000000*(milli*meter)**4) b.apply_load(5*kN, 2*meter, -1) b.apply_load(R1, 0*meter, -1) b.apply_load(R2, 8*meter, -1) b.apply_load(10*kN/meter, 4*meter, 0, end=8*meter) b.bc_deflection = [(0*meter, 0*meter), (8*meter, 0*meter)] b.solve_for_reaction_loads(R1, R2) assert b.reaction_loads == {R1: -13750*newton, R2: -31250*newton} b = Beam(3*meter, E*newton/meter**2, I*meter**4) b.apply_load(8*kN, 1*meter, -1) b.apply_load(R1, 0*meter, -1) b.apply_load(R2, 3*meter, -1) b.apply_load(12*kN*meter, 2*meter, -2) b.bc_deflection = [(0*meter, 0*meter), (3*meter, 0*meter)] b.solve_for_reaction_loads(R1, R2) assert b.reaction_loads == {R1: newton*Rational(-28000, 3), R2: newton*Rational(4000, 3)} assert b.deflection().subs(x, 1*meter) == 62000*meter/(9*E*I) def test_variable_moment(): E = Symbol('E') I = Symbol('I') b = Beam(4, E, 2*(4 - x)) b.apply_load(20, 4, -1) R, M = symbols('R, M') b.apply_load(R, 0, -1) b.apply_load(M, 0, -2) b.bc_deflection = [(0, 0)] b.bc_slope = [(0, 0)] b.solve_for_reaction_loads(R, M) assert b.slope().expand() == ((10*x*SingularityFunction(x, 0, 0) - 10*(x - 4)*SingularityFunction(x, 4, 0))/E).expand() assert b.deflection().expand() == ((5*x**2*SingularityFunction(x, 0, 0) - 10*Piecewise((0, Abs(x)/4 < 1), (16*meijerg(((3, 1), ()), ((), (2, 0)), x/4), True)) + 40*SingularityFunction(x, 4, 1))/E).expand() b = Beam(4, E - x, I) b.apply_load(20, 4, -1) R, M = symbols('R, M') b.apply_load(R, 0, -1) b.apply_load(M, 0, -2) b.bc_deflection = [(0, 0)] b.bc_slope = [(0, 0)] b.solve_for_reaction_loads(R, M) assert b.slope().expand() == ((-80*(-log(-E) + log(-E + x))*SingularityFunction(x, 0, 0) + 80*(-log(-E + 4) + log(-E + x))*SingularityFunction(x, 4, 0) + 20*(-E*log(-E) + E*log(-E + x) + x)*SingularityFunction(x, 0, 0) - 20*(-E*log(-E + 4) + E*log(-E + x) + x - 4)*SingularityFunction(x, 4, 0))/I).expand() def test_composite_beam(): E = Symbol('E') I = Symbol('I') b1 = Beam(2, E, 1.5*I) b2 = Beam(2, E, I) b = b1.join(b2, "fixed") b.apply_load(-20, 0, -1) b.apply_load(80, 0, -2) b.apply_load(20, 4, -1) b.bc_slope = [(0, 0)] b.bc_deflection = [(0, 0)] assert b.length == 4 assert b.second_moment == Piecewise((1.5*I, x <= 2), (I, x <= 4)) assert b.slope().subs(x, 4) == 120.0/(E*I) assert b.slope().subs(x, 2) == 80.0/(E*I) assert int(b.deflection().subs(x, 4).args[0]) == -302 # Coefficient of 1/(E*I) l = symbols('l', positive=True) R1, M1, R2, R3, P = symbols('R1 M1 R2 R3 P') b1 = Beam(2*l, E, I) b2 = Beam(2*l, E, I) b = b1.join(b2,"hinge") b.apply_load(M1, 0, -2) b.apply_load(R1, 0, -1) b.apply_load(R2, l, -1) b.apply_load(R3, 4*l, -1) b.apply_load(P, 3*l, -1) b.bc_slope = [(0, 0)] b.bc_deflection = [(0, 0), (l, 0), (4*l, 0)] b.solve_for_reaction_loads(M1, R1, R2, R3) assert b.reaction_loads == {R3: -P/2, R2: P*Rational(-5, 4), M1: -P*l/4, R1: P*Rational(3, 4)} assert b.slope().subs(x, 3*l) == -7*P*l**2/(48*E*I) assert b.deflection().subs(x, 2*l) == 7*P*l**3/(24*E*I) assert b.deflection().subs(x, 3*l) == 5*P*l**3/(16*E*I) # When beams having same second moment are joined. b1 = Beam(2, 500, 10) b2 = Beam(2, 500, 10) b = b1.join(b2, "fixed") b.apply_load(M1, 0, -2) b.apply_load(R1, 0, -1) b.apply_load(R2, 1, -1) b.apply_load(R3, 4, -1) b.apply_load(10, 3, -1) b.bc_slope = [(0, 0)] b.bc_deflection = [(0, 0), (1, 0), (4, 0)] b.solve_for_reaction_loads(M1, R1, R2, R3) assert b.slope() == -2*SingularityFunction(x, 0, 1)/5625 + SingularityFunction(x, 0, 2)/1875\ - 133*SingularityFunction(x, 1, 2)/135000 + SingularityFunction(x, 3, 2)/1000\ - 37*SingularityFunction(x, 4, 2)/67500 assert b.deflection() == -SingularityFunction(x, 0, 2)/5625 + SingularityFunction(x, 0, 3)/5625\ - 133*SingularityFunction(x, 1, 3)/405000 + SingularityFunction(x, 3, 3)/3000\ - 37*SingularityFunction(x, 4, 3)/202500 def test_point_cflexure(): E = Symbol('E') I = Symbol('I') b = Beam(10, E, I) b.apply_load(-4, 0, -1) b.apply_load(-46, 6, -1) b.apply_load(10, 2, -1) b.apply_load(20, 4, -1) b.apply_load(3, 6, 0) assert b.point_cflexure() == [Rational(10, 3)] def test_remove_load(): E = Symbol('E') I = Symbol('I') b = Beam(4, E, I) try: b.remove_load(2, 1, -1) # As no load is applied on beam, ValueError should be returned. except ValueError: assert True else: assert False b.apply_load(-3, 0, -2) b.apply_load(4, 2, -1) b.apply_load(-2, 2, 2, end = 3) b.remove_load(-2, 2, 2, end = 3) assert b.load == -3*SingularityFunction(x, 0, -2) + 4*SingularityFunction(x, 2, -1) assert b.applied_loads == [(-3, 0, -2, None), (4, 2, -1, None)] try: b.remove_load(1, 2, -1) # As load of this magnitude was never applied at # this position, method should return a ValueError. except ValueError: assert True else: assert False b.remove_load(-3, 0, -2) b.remove_load(4, 2, -1) assert b.load == 0 assert b.applied_loads == [] def test_apply_support(): E = Symbol('E') I = Symbol('I') b = Beam(4, E, I) b.apply_support(0, "cantilever") b.apply_load(20, 4, -1) M_0, R_0 = symbols('M_0, R_0') b.solve_for_reaction_loads(R_0, M_0) assert simplify(b.slope()) == simplify((80*SingularityFunction(x, 0, 1) - 10*SingularityFunction(x, 0, 2) + 10*SingularityFunction(x, 4, 2))/(E*I)) assert simplify(b.deflection()) == simplify((40*SingularityFunction(x, 0, 2) - 10*SingularityFunction(x, 0, 3)/3 + 10*SingularityFunction(x, 4, 3)/3)/(E*I)) b = Beam(30, E, I) b.apply_support(10, "pin") b.apply_support(30, "roller") b.apply_load(-8, 0, -1) b.apply_load(120, 30, -2) R_10, R_30 = symbols('R_10, R_30') b.solve_for_reaction_loads(R_10, R_30) assert b.slope() == (-4*SingularityFunction(x, 0, 2) + 3*SingularityFunction(x, 10, 2) + 120*SingularityFunction(x, 30, 1) + SingularityFunction(x, 30, 2) + Rational(4000, 3))/(E*I) assert b.deflection() == (x*Rational(4000, 3) - 4*SingularityFunction(x, 0, 3)/3 + SingularityFunction(x, 10, 3) + 60*SingularityFunction(x, 30, 2) + SingularityFunction(x, 30, 3)/3 - 12000)/(E*I) P = Symbol('P', positive=True) L = Symbol('L', positive=True) b = Beam(L, E, I) b.apply_support(0, type='fixed') b.apply_support(L, type='fixed') b.apply_load(-P, L/2, -1) R_0, R_L, M_0, M_L = symbols('R_0, R_L, M_0, M_L') b.solve_for_reaction_loads(R_0, R_L, M_0, M_L) assert b.reaction_loads == {R_0: P/2, R_L: P/2, M_0: -L*P/8, M_L: L*P/8} def test_max_shear_force(): E = Symbol('E') I = Symbol('I') b = Beam(3, E, I) R, M = symbols('R, M') b.apply_load(R, 0, -1) b.apply_load(M, 0, -2) b.apply_load(2, 3, -1) b.apply_load(4, 2, -1) b.apply_load(2, 2, 0, end=3) b.solve_for_reaction_loads(R, M) assert b.max_shear_force() == (Interval(0, 2), 8) l = symbols('l', positive=True) P = Symbol('P') b = Beam(l, E, I) R1, R2 = symbols('R1, R2') b.apply_load(R1, 0, -1) b.apply_load(R2, l, -1) b.apply_load(P, 0, 0, end=l) b.solve_for_reaction_loads(R1, R2) assert b.max_shear_force() == (0, l*Abs(P)/2) def test_max_bmoment(): E = Symbol('E') I = Symbol('I') l, P = symbols('l, P', positive=True) b = Beam(l, E, I) R1, R2 = symbols('R1, R2') b.apply_load(R1, 0, -1) b.apply_load(R2, l, -1) b.apply_load(P, l/2, -1) b.solve_for_reaction_loads(R1, R2) b.reaction_loads assert b.max_bmoment() == (l/2, P*l/4) b = Beam(l, E, I) R1, R2 = symbols('R1, R2') b.apply_load(R1, 0, -1) b.apply_load(R2, l, -1) b.apply_load(P, 0, 0, end=l) b.solve_for_reaction_loads(R1, R2) assert b.max_bmoment() == (l/2, P*l**2/8) def test_max_deflection(): E, I, l, F = symbols('E, I, l, F', positive=True) b = Beam(l, E, I) b.bc_deflection = [(0, 0),(l, 0)] b.bc_slope = [(0, 0),(l, 0)] b.apply_load(F/2, 0, -1) b.apply_load(-F*l/8, 0, -2) b.apply_load(F/2, l, -1) b.apply_load(F*l/8, l, -2) b.apply_load(-F, l/2, -1) assert b.max_deflection() == (l/2, F*l**3/(192*E*I)) def test_Beam3D(): l, E, G, I, A = symbols('l, E, G, I, A') R1, R2, R3, R4 = symbols('R1, R2, R3, R4') b = Beam3D(l, E, G, I, A) m, q = symbols('m, q') b.apply_load(q, 0, 0, dir="y") b.apply_moment_load(m, 0, 0, dir="z") b.bc_slope = [(0, [0, 0, 0]), (l, [0, 0, 0])] b.bc_deflection = [(0, [0, 0, 0]), (l, [0, 0, 0])] b.solve_slope_deflection() assert b.polar_moment() == 2*I assert b.shear_force() == [0, -q*x, 0] assert b.shear_stress() == [0, -q*x/A, 0] assert b.axial_stress() == 0 assert b.bending_moment() == [0, 0, -m*x + q*x**2/2] expected_deflection = (x*(A*G*q*x**3/4 + A*G*x**2*(-l*(A*G*l*(l*q - 2*m) + 12*E*I*q)/(A*G*l**2 + 12*E*I)/2 - m) + 3*E*I*l*(A*G*l*(l*q - 2*m) + 12*E*I*q)/(A*G*l**2 + 12*E*I) + x*(-A*G*l**2*q/2 + 3*A*G*l**2*(A*G*l*(l*q - 2*m) + 12*E*I*q)/(A*G*l**2 + 12*E*I)/4 + A*G*l*m*Rational(3, 2) - 3*E*I*q))/(6*A*E*G*I)) dx, dy, dz = b.deflection() assert dx == dz == 0 assert simplify(dy - expected_deflection) == 0 b2 = Beam3D(30, E, G, I, A, x) b2.apply_load(50, start=0, order=0, dir="y") b2.bc_deflection = [(0, [0, 0, 0]), (30, [0, 0, 0])] b2.apply_load(R1, start=0, order=-1, dir="y") b2.apply_load(R2, start=30, order=-1, dir="y") b2.solve_for_reaction_loads(R1, R2) assert b2.reaction_loads == {R1: -750, R2: -750} b2.solve_slope_deflection() assert b2.slope() == [0, 0, 25*x**3/(3*E*I) - 375*x**2/(E*I) + 3750*x/(E*I)] expected_deflection = 25*x**4/(12*E*I) - 125*x**3/(E*I) + 1875*x**2/(E*I) - \ 25*x**2/(A*G) + 750*x/(A*G) dx, dy, dz = b2.deflection() assert dx == dz == 0 assert dy == expected_deflection # Test for solve_for_reaction_loads b3 = Beam3D(30, E, G, I, A, x) b3.apply_load(8, start=0, order=0, dir="y") b3.apply_load(9*x, start=0, order=0, dir="z") b3.apply_load(R1, start=0, order=-1, dir="y") b3.apply_load(R2, start=30, order=-1, dir="y") b3.apply_load(R3, start=0, order=-1, dir="z") b3.apply_load(R4, start=30, order=-1, dir="z") b3.solve_for_reaction_loads(R1, R2, R3, R4) assert b3.reaction_loads == {R1: -120, R2: -120, R3: -1350, R4: -2700} def test_polar_moment_Beam3D(): l, E, G, A, I1, I2 = symbols('l, E, G, A, I1, I2') I = [I1, I2] b = Beam3D(l, E, G, I, A) assert b.polar_moment() == I1 + I2 def test_parabolic_loads(): E, I, L = symbols('E, I, L', positive=True, real=True) R, M, P = symbols('R, M, P', real=True) # cantilever beam fixed at x=0 and parabolic distributed loading across # length of beam beam = Beam(L, E, I) beam.bc_deflection.append((0, 0)) beam.bc_slope.append((0, 0)) beam.apply_load(R, 0, -1) beam.apply_load(M, 0, -2) # parabolic load beam.apply_load(1, 0, 2) beam.solve_for_reaction_loads(R, M) assert beam.reaction_loads[R] == -L**3/3 # cantilever beam fixed at x=0 and parabolic distributed loading across # first half of beam beam = Beam(2*L, E, I) beam.bc_deflection.append((0, 0)) beam.bc_slope.append((0, 0)) beam.apply_load(R, 0, -1) beam.apply_load(M, 0, -2) # parabolic load from x=0 to x=L beam.apply_load(1, 0, 2, end=L) beam.solve_for_reaction_loads(R, M) # result should be the same as the prior example assert beam.reaction_loads[R] == -L**3/3 # check constant load beam = Beam(2*L, E, I) beam.apply_load(P, 0, 0, end=L) loading = beam.load.xreplace({L: 10, E: 20, I: 30, P: 40}) assert loading.xreplace({x: 5}) == 40 assert loading.xreplace({x: 15}) == 0 # check ramp load beam = Beam(2*L, E, I) beam.apply_load(P, 0, 1, end=L) assert beam.load == (P*SingularityFunction(x, 0, 1) - P*SingularityFunction(x, L, 1) - P*L*SingularityFunction(x, L, 0)) # check higher order load: x**8 load from x=0 to x=L beam = Beam(2*L, E, I) beam.apply_load(P, 0, 8, end=L) loading = beam.load.xreplace({L: 10, E: 20, I: 30, P: 40}) assert loading.xreplace({x: 5}) == 40*5**8 assert loading.xreplace({x: 15}) == 0 def test_cross_section(): I = Symbol('I') l = Symbol('l') E = Symbol('E') C3, C4 = symbols('C3, C4') a, c, g, h, r, n = symbols('a, c, g, h, r, n') # test for second_moment and cross_section setter b0 = Beam(l, E, I) assert b0.second_moment == I assert b0.cross_section == None b0.cross_section = Circle((0, 0), 5) assert b0.second_moment == pi*Rational(625, 4) assert b0.cross_section == Circle((0, 0), 5) b0.second_moment = 2*n - 6 assert b0.second_moment == 2*n-6 assert b0.cross_section == None with raises(ValueError): b0.second_moment = Circle((0, 0), 5) # beam with a circular cross-section b1 = Beam(50, E, Circle((0, 0), r)) assert b1.cross_section == Circle((0, 0), r) assert b1.second_moment == pi*r*Abs(r)**3/4 b1.apply_load(-10, 0, -1) b1.apply_load(R1, 5, -1) b1.apply_load(R2, 50, -1) b1.apply_load(90, 45, -2) b1.solve_for_reaction_loads(R1, R2) assert b1.load == (-10*SingularityFunction(x, 0, -1) + 82*SingularityFunction(x, 5, -1)/S(9) + 90*SingularityFunction(x, 45, -2) + 8*SingularityFunction(x, 50, -1)/9) assert b1.bending_moment() == (10*SingularityFunction(x, 0, 1) - 82*SingularityFunction(x, 5, 1)/9 - 90*SingularityFunction(x, 45, 0) - 8*SingularityFunction(x, 50, 1)/9) q = (-5*SingularityFunction(x, 0, 2) + 41*SingularityFunction(x, 5, 2)/S(9) + 90*SingularityFunction(x, 45, 1) + 4*SingularityFunction(x, 50, 2)/S(9))/(pi*E*r*Abs(r)**3) assert b1.slope() == C3 + 4*q q = (-5*SingularityFunction(x, 0, 3)/3 + 41*SingularityFunction(x, 5, 3)/27 + 45*SingularityFunction(x, 45, 2) + 4*SingularityFunction(x, 50, 3)/27)/(pi*E*r*Abs(r)**3) assert b1.deflection() == C3*x + C4 + 4*q # beam with a recatangular cross-section b2 = Beam(20, E, Polygon((0, 0), (a, 0), (a, c), (0, c))) assert b2.cross_section == Polygon((0, 0), (a, 0), (a, c), (0, c)) assert b2.second_moment == a*c**3/12 # beam with a triangular cross-section b3 = Beam(15, E, Triangle((0, 0), (g, 0), (g/2, h))) assert b3.cross_section == Triangle(Point2D(0, 0), Point2D(g, 0), Point2D(g/2, h)) assert b3.second_moment == g*h**3/36 # composite beam b = b2.join(b3, "fixed") b.apply_load(-30, 0, -1) b.apply_load(65, 0, -2) b.apply_load(40, 0, -1) b.bc_slope = [(0, 0)] b.bc_deflection = [(0, 0)] assert b.second_moment == Piecewise((a*c**3/12, x <= 20), (g*h**3/36, x <= 35)) assert b.cross_section == None assert b.length == 35 assert b.slope().subs(x, 7) == 8400/(E*a*c**3) assert b.slope().subs(x, 25) == 52200/(E*g*h**3) + 39600/(E*a*c**3) assert b.deflection().subs(x, 30) == -537000/(E*g*h**3) - 712000/(E*a*c**3) def test_max_shear_force_Beam3D(): x = symbols('x') b = Beam3D(20, 40, 21, 100, 25) b.apply_load(15, start=0, order=0, dir="z") b.apply_load(12*x, start=0, order=0, dir="y") b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] assert b.max_shear_force() == [(0, 0), (20, 2400), (20, 300)] def test_max_bending_moment_Beam3D(): x = symbols('x') b = Beam3D(20, 40, 21, 100, 25) b.apply_load(15, start=0, order=0, dir="z") b.apply_load(12*x, start=0, order=0, dir="y") b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] assert b.max_bmoment() == [(0, 0), (20, 3000), (20, 16000)] def test_max_deflection_Beam3D(): x = symbols('x') b = Beam3D(20, 40, 21, 100, 25) b.apply_load(15, start=0, order=0, dir="z") b.apply_load(12*x, start=0, order=0, dir="y") b.bc_deflection = [(0, [0, 0, 0]), (20, [0, 0, 0])] b.solve_slope_deflection() c = sympify("495/14") p = sympify("-10 + 10*sqrt(10793)/43") q = sympify("(10 - 10*sqrt(10793)/43)**3/160 - 20/7 + (10 - 10*sqrt(10793)/43)**4/6400 + 20*sqrt(10793)/301 + 27*(10 - 10*sqrt(10793)/43)**2/560") assert b.max_deflection() == [(0, 0), (10, c), (p, q)] sympy-sympy-1.9/sympy/physics/control/000077500000000000000000000000001412543434000202465ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/control/__init__.py000066400000000000000000000017161412543434000223640ustar00rootroot00000000000000from .lti import (TransferFunction, Series, MIMOSeries, Parallel, MIMOParallel, Feedback, MIMOFeedback, TransferFunctionMatrix) from .control_plots import (pole_zero_numerical_data, pole_zero_plot, step_response_numerical_data, step_response_plot, impulse_response_numerical_data, impulse_response_plot, ramp_response_numerical_data, ramp_response_plot, bode_magnitude_numerical_data, bode_phase_numerical_data, bode_magnitude_plot, bode_phase_plot, bode_plot) __all__ = ['TransferFunction', 'Series', 'MIMOSeries', 'Parallel', 'MIMOParallel', 'Feedback', 'MIMOFeedback', 'TransferFunctionMatrix', 'pole_zero_numerical_data', 'pole_zero_plot', 'step_response_numerical_data', 'step_response_plot', 'impulse_response_numerical_data', 'impulse_response_plot', 'ramp_response_numerical_data', 'ramp_response_plot', 'bode_magnitude_numerical_data', 'bode_phase_numerical_data', 'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot'] sympy-sympy-1.9/sympy/physics/control/control_plots.py000066400000000000000000000726261412543434000235360ustar00rootroot00000000000000from sympy import I, log, apart, exp from sympy.core.symbol import Dummy from sympy.external import import_module from sympy.functions import arg, Abs from sympy.integrals.transforms import _fast_inverse_laplace from sympy.physics.control.lti import SISOLinearTimeInvariant from sympy.plotting.plot import LineOver1DRangeSeries from sympy.polys.polytools import Poly from sympy.printing.latex import latex __all__ = ['pole_zero_numerical_data', 'pole_zero_plot', 'step_response_numerical_data', 'step_response_plot', 'impulse_response_numerical_data', 'impulse_response_plot', 'ramp_response_numerical_data', 'ramp_response_plot', 'bode_magnitude_numerical_data', 'bode_phase_numerical_data', 'bode_magnitude_plot', 'bode_phase_plot', 'bode_plot'] matplotlib = import_module( 'matplotlib', import_kwargs={'fromlist': ['pyplot']}, catch=(RuntimeError,)) numpy = import_module('numpy') if matplotlib: plt = matplotlib.pyplot if numpy: np = numpy # Matplotlib already has numpy as a compulsory dependency. No need to install it separately. def _check_system(system): """Function to check whether the dynamical system passed for plots is compatible or not.""" if not isinstance(system, SISOLinearTimeInvariant): raise NotImplementedError("Only SISO LTI systems are currently supported.") sys = system.to_expr() len_free_symbols = len(sys.free_symbols) if len_free_symbols > 1: raise ValueError("Extra degree of freedom found. Make sure" " that there are no free symbols in the dynamical system other" " than the variable of Laplace transform.") if sys.has(exp): raise NotImplementedError("Time delay terms are not supported.") def pole_zero_numerical_data(system): """ Returns the numerical data of poles and zeros of the system. It is internally used by ``pole_zero_plot`` to get the data for plotting poles and zeros. Users can use this data to further analyse the dynamics of the system or plot using a different backend/plotting-module. Parameters ========== system : SISOLinearTimeInvariant The system for which the pole-zero data is to be computed. Returns ======= tuple : (zeros, poles) zeros = Zeros of the system. NumPy array of complex numbers. poles = Poles of the system. NumPy array of complex numbers. Raises ====== NotImplementedError When a SISO LTI system is not passed. When time delay terms are present in the system. ValueError When more than one free symbol is present in the system. The only variable in the transfer function should be the variable of the Laplace transform. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import pole_zero_numerical_data >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) >>> pole_zero_numerical_data(tf1) # doctest: +SKIP ([-0.+1.j 0.-1.j], [-2. +0.j -0.5+0.8660254j -0.5-0.8660254j -1. +0.j ]) See Also ======== pole_zero_plot """ _check_system(system) system = system.doit() # Get the equivalent TransferFunction object. num_poly = Poly(system.num, system.var).all_coeffs() den_poly = Poly(system.den, system.var).all_coeffs() num_poly = np.array(num_poly, dtype=np.float64) den_poly = np.array(den_poly, dtype=np.float64) zeros = np.roots(num_poly) poles = np.roots(den_poly) return zeros, poles def pole_zero_plot(system, pole_color='blue', pole_markersize=10, zero_color='orange', zero_markersize=7, grid=True, show_axes=True, show=True, **kwargs): r""" Returns the Pole-Zero plot (also known as PZ Plot or PZ Map) of a system. A Pole-Zero plot is a graphical representation of a system's poles and zeros. It is plotted on a complex plane, with circular markers representing the system's zeros and 'x' shaped markers representing the system's poles. Parameters ========== system : SISOLinearTimeInvariant type systems The system for which the pole-zero plot is to be computed. pole_color : str, tuple, optional The color of the pole points on the plot. Default color is blue. The color can be provided as a matplotlib color string, or a 3-tuple of floats each in the 0-1 range. pole_markersize : Number, optional The size of the markers used to mark the poles in the plot. Default pole markersize is 10. zero_color : str, tuple, optional The color of the zero points on the plot. Default color is orange. The color can be provided as a matplotlib color string, or a 3-tuple of floats each in the 0-1 range. zero_markersize : Number, optional The size of the markers used to mark the zeros in the plot. Default zero markersize is 7. grid : boolean, optional If ``True``, the plot will have a grid. Defaults to True. show_axes : boolean, optional If ``True``, the coordinate axes will be shown. Defaults to False. show : boolean, optional If ``True``, the plot will be displayed otherwise the equivalent matplotlib ``plot`` object will be returned. Defaults to True. Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import pole_zero_plot >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) >>> pole_zero_plot(tf1) # doctest: +SKIP See Also ======== pole_zero_numerical_data References ========== .. [1] https://en.wikipedia.org/wiki/Pole%E2%80%93zero_plot """ zeros, poles = pole_zero_numerical_data(system) zero_real = np.real(zeros) zero_imag = np.imag(zeros) pole_real = np.real(poles) pole_imag = np.imag(poles) plt.plot(pole_real, pole_imag, 'x', mfc='none', markersize=pole_markersize, color=pole_color) plt.plot(zero_real, zero_imag, 'o', markersize=zero_markersize, color=zero_color) plt.xlabel('Real Axis') plt.ylabel('Imaginary Axis') plt.title(f'Poles and Zeros of ${latex(system)}$', pad=20) if grid: plt.grid() if show_axes: plt.axhline(0, color='black') plt.axvline(0, color='black') if show: plt.show() return return plt def step_response_numerical_data(system, prec=8, lower_limit=0, upper_limit=10, **kwargs): """ Returns the numerical values of the points in the step response plot of a SISO continuous-time system. By default, adaptive sampling is used. If the user wants to instead get an uniformly sampled response, then ``adaptive`` kwarg should be passed ``False`` and ``nb_of_points`` must be passed as additional kwargs. Refer to the parameters of class :class:`sympy.plotting.plot.LineOver1DRangeSeries` for more details. Parameters ========== system : SISOLinearTimeInvariant The system for which the unit step response data is to be computed. prec : int, optional The decimal point precision for the point coordinate values. Defaults to 8. lower_limit : Number, optional The lower limit of the plot range. Defaults to 0. upper_limit : Number, optional The upper limit of the plot range. Defaults to 10. kwargs : Additional keyword arguments are passed to the underlying :class:`sympy.plotting.plot.LineOver1DRangeSeries` class. Returns ======= tuple : (x, y) x = Time-axis values of the points in the step response. NumPy array. y = Amplitude-axis values of the points in the step response. NumPy array. Raises ====== NotImplementedError When a SISO LTI system is not passed. When time delay terms are present in the system. ValueError When more than one free symbol is present in the system. The only variable in the transfer function should be the variable of the Laplace transform. When ``lower_limit`` parameter is less than 0. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import step_response_numerical_data >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s) >>> step_response_numerical_data(tf1) # doctest: +SKIP ([0.0, 0.025413462339411542, 0.0484508722725343, ... , 9.670250533855183, 9.844291913708725, 10.0], [0.0, 0.023844582399907256, 0.042894276802320226, ..., 6.828770759094287e-12, 6.456457160755703e-12]) See Also ======== step_response_plot """ if lower_limit < 0: raise ValueError("Lower limit of time must be greater " "than or equal to zero.") _check_system(system) _x = Dummy("x") expr = system.to_expr()/(system.var) expr = apart(expr, system.var, full=True) _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec) return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit), **kwargs).get_points() def step_response_plot(system, color='b', prec=8, lower_limit=0, upper_limit=10, show_axes=False, grid=True, show=True, **kwargs): r""" Returns the unit step response of a continuous-time system. It is the response of the system when the input signal is a step function. Parameters ========== system : SISOLinearTimeInvariant type The LTI SISO system for which the Step Response is to be computed. color : str, tuple, optional The color of the line. Default is Blue. show : boolean, optional If ``True``, the plot will be displayed otherwise the equivalent matplotlib ``plot`` object will be returned. Defaults to True. lower_limit : Number, optional The lower limit of the plot range. Defaults to 0. upper_limit : Number, optional The upper limit of the plot range. Defaults to 10. prec : int, optional The decimal point precision for the point coordinate values. Defaults to 8. show_axes : boolean, optional If ``True``, the coordinate axes will be shown. Defaults to False. grid : boolean, optional If ``True``, the plot will have a grid. Defaults to True. Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import step_response_plot >>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s) >>> step_response_plot(tf1) # doctest: +SKIP See Also ======== impulse_response_plot, ramp_response_plot References ========== .. [1] https://www.mathworks.com/help/control/ref/lti.step.html """ x, y = step_response_numerical_data(system, prec=prec, lower_limit=lower_limit, upper_limit=upper_limit, **kwargs) plt.plot(x, y, color=color) plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.title(f'Unit Step Response of ${latex(system)}$', pad=20) if grid: plt.grid() if show_axes: plt.axhline(0, color='black') plt.axvline(0, color='black') if show: plt.show() return return plt def impulse_response_numerical_data(system, prec=8, lower_limit=0, upper_limit=10, **kwargs): """ Returns the numerical values of the points in the impulse response plot of a SISO continuous-time system. By default, adaptive sampling is used. If the user wants to instead get an uniformly sampled response, then ``adaptive`` kwarg should be passed ``False`` and ``nb_of_points`` must be passed as additional kwargs. Refer to the parameters of class :class:`sympy.plotting.plot.LineOver1DRangeSeries` for more details. Parameters ========== system : SISOLinearTimeInvariant The system for which the impulse response data is to be computed. prec : int, optional The decimal point precision for the point coordinate values. Defaults to 8. lower_limit : Number, optional The lower limit of the plot range. Defaults to 0. upper_limit : Number, optional The upper limit of the plot range. Defaults to 10. kwargs : Additional keyword arguments are passed to the underlying :class:`sympy.plotting.plot.LineOver1DRangeSeries` class. Returns ======= tuple : (x, y) x = Time-axis values of the points in the impulse response. NumPy array. y = Amplitude-axis values of the points in the impulse response. NumPy array. Raises ====== NotImplementedError When a SISO LTI system is not passed. When time delay terms are present in the system. ValueError When more than one free symbol is present in the system. The only variable in the transfer function should be the variable of the Laplace transform. When ``lower_limit`` parameter is less than 0. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import impulse_response_numerical_data >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s) >>> impulse_response_numerical_data(tf1) # doctest: +SKIP ([0.0, 0.06616480200395854,... , 9.854500743565858, 10.0], [0.9999999799999999, 0.7042848373025861,...,7.170748906965121e-13, -5.1901263495547205e-12]) See Also ======== impulse_response_plot """ if lower_limit < 0: raise ValueError("Lower limit of time must be greater " "than or equal to zero.") _check_system(system) _x = Dummy("x") expr = system.to_expr() expr = apart(expr, system.var, full=True) _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec) return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit), **kwargs).get_points() def impulse_response_plot(system, color='b', prec=8, lower_limit=0, upper_limit=10, show_axes=False, grid=True, show=True, **kwargs): r""" Returns the unit impulse response (Input is the Dirac-Delta Function) of a continuous-time system. Parameters ========== system : SISOLinearTimeInvariant type The LTI SISO system for which the Impulse Response is to be computed. color : str, tuple, optional The color of the line. Default is Blue. show : boolean, optional If ``True``, the plot will be displayed otherwise the equivalent matplotlib ``plot`` object will be returned. Defaults to True. lower_limit : Number, optional The lower limit of the plot range. Defaults to 0. upper_limit : Number, optional The upper limit of the plot range. Defaults to 10. prec : int, optional The decimal point precision for the point coordinate values. Defaults to 8. show_axes : boolean, optional If ``True``, the coordinate axes will be shown. Defaults to False. grid : boolean, optional If ``True``, the plot will have a grid. Defaults to True. Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import impulse_response_plot >>> tf1 = TransferFunction(8*s**2 + 18*s + 32, s**3 + 6*s**2 + 14*s + 24, s) >>> impulse_response_plot(tf1) # doctest: +SKIP See Also ======== step_response_plot, ramp_response_plot References ========== .. [1] https://www.mathworks.com/help/control/ref/lti.impulse.html """ x, y = impulse_response_numerical_data(system, prec=prec, lower_limit=lower_limit, upper_limit=upper_limit, **kwargs) plt.plot(x, y, color=color) plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.title(f'Impulse Response of ${latex(system)}$', pad=20) if grid: plt.grid() if show_axes: plt.axhline(0, color='black') plt.axvline(0, color='black') if show: plt.show() return return plt def ramp_response_numerical_data(system, slope=1, prec=8, lower_limit=0, upper_limit=10, **kwargs): """ Returns the numerical values of the points in the ramp response plot of a SISO continuous-time system. By default, adaptive sampling is used. If the user wants to instead get an uniformly sampled response, then ``adaptive`` kwarg should be passed ``False`` and ``nb_of_points`` must be passed as additional kwargs. Refer to the parameters of class :class:`sympy.plotting.plot.LineOver1DRangeSeries` for more details. Parameters ========== system : SISOLinearTimeInvariant The system for which the ramp response data is to be computed. slope : Number, optional The slope of the input ramp function. Defaults to 1. prec : int, optional The decimal point precision for the point coordinate values. Defaults to 8. lower_limit : Number, optional The lower limit of the plot range. Defaults to 0. upper_limit : Number, optional The upper limit of the plot range. Defaults to 10. kwargs : Additional keyword arguments are passed to the underlying :class:`sympy.plotting.plot.LineOver1DRangeSeries` class. Returns ======= tuple : (x, y) x = Time-axis values of the points in the ramp response plot. NumPy array. y = Amplitude-axis values of the points in the ramp response plot. NumPy array. Raises ====== NotImplementedError When a SISO LTI system is not passed. When time delay terms are present in the system. ValueError When more than one free symbol is present in the system. The only variable in the transfer function should be the variable of the Laplace transform. When ``lower_limit`` parameter is less than 0. When ``slope`` is negative. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import ramp_response_numerical_data >>> tf1 = TransferFunction(s, s**2 + 5*s + 8, s) >>> ramp_response_numerical_data(tf1) # doctest: +SKIP (([0.0, 0.12166980856813935,..., 9.861246379582118, 10.0], [1.4504508011325967e-09, 0.006046440489058766,..., 0.12499999999568202, 0.12499999999661349])) See Also ======== ramp_response_plot """ if slope < 0: raise ValueError("Slope must be greater than or equal" " to zero.") if lower_limit < 0: raise ValueError("Lower limit of time must be greater " "than or equal to zero.") _check_system(system) _x = Dummy("x") expr = (slope*system.to_expr())/((system.var)**2) expr = apart(expr, system.var, full=True) _y = _fast_inverse_laplace(expr, system.var, _x).evalf(prec) return LineOver1DRangeSeries(_y, (_x, lower_limit, upper_limit), **kwargs).get_points() def ramp_response_plot(system, slope=1, color='b', prec=8, lower_limit=0, upper_limit=10, show_axes=False, grid=True, show=True, **kwargs): r""" Returns the ramp response of a continuous-time system. Ramp function is defined as the straight line passing through origin ($f(x) = mx$). The slope of the ramp function can be varied by the user and the default value is 1. Parameters ========== system : SISOLinearTimeInvariant type The LTI SISO system for which the Ramp Response is to be computed. slope : Number, optional The slope of the input ramp function. Defaults to 1. color : str, tuple, optional The color of the line. Default is Blue. show : boolean, optional If ``True``, the plot will be displayed otherwise the equivalent matplotlib ``plot`` object will be returned. Defaults to True. lower_limit : Number, optional The lower limit of the plot range. Defaults to 0. upper_limit : Number, optional The upper limit of the plot range. Defaults to 10. prec : int, optional The decimal point precision for the point coordinate values. Defaults to 8. show_axes : boolean, optional If ``True``, the coordinate axes will be shown. Defaults to False. grid : boolean, optional If ``True``, the plot will have a grid. Defaults to True. Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import ramp_response_plot >>> tf1 = TransferFunction(s, (s+4)*(s+8), s) >>> ramp_response_plot(tf1, upper_limit=2) # doctest: +SKIP See Also ======== step_response_plot, ramp_response_plot References ========== .. [1] https://en.wikipedia.org/wiki/Ramp_function """ x, y = ramp_response_numerical_data(system, slope=slope, prec=prec, lower_limit=lower_limit, upper_limit=upper_limit, **kwargs) plt.plot(x, y, color=color) plt.xlabel('Time (s)') plt.ylabel('Amplitude') plt.title(f'Ramp Response of ${latex(system)}$ [Slope = {slope}]', pad=20) if grid: plt.grid() if show_axes: plt.axhline(0, color='black') plt.axvline(0, color='black') if show: plt.show() return return plt def bode_magnitude_numerical_data(system, initial_exp=-5, final_exp=5, **kwargs): """ Returns the numerical data of the Bode magnitude plot of the system. It is internally used by ``bode_magnitude_plot`` to get the data for plotting Bode magnitude plot. Users can use this data to further analyse the dynamics of the system or plot using a different backend/plotting-module. Parameters ========== system : SISOLinearTimeInvariant The system for which the data is to be computed. initial_exp : Number, optional The initial exponent of 10 of the semilog plot. Defaults to -5. final_exp : Number, optional The final exponent of 10 of the semilog plot. Defaults to 5. Returns ======= tuple : (x, y) x = x-axis values of the Bode magnitude plot. y = y-axis values of the Bode magnitude plot. Raises ====== NotImplementedError When a SISO LTI system is not passed. When time delay terms are present in the system. ValueError When more than one free symbol is present in the system. The only variable in the transfer function should be the variable of the Laplace transform. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import bode_magnitude_numerical_data >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) >>> bode_magnitude_numerical_data(tf1) # doctest: +SKIP ([1e-05, 1.5148378120533502e-05,..., 68437.36188804005, 100000.0], [-6.020599914256786, -6.0205999155219505,..., -193.4117304087953, -200.00000000260573]) See Also ======== bode_magnitude_plot, bode_phase_numerical_data """ _check_system(system) expr = system.to_expr() _w = Dummy("w", real=True) w_expr = expr.subs({system.var: I*_w}) mag = 20*log(Abs(w_expr), 10) return LineOver1DRangeSeries(mag, (_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points() def bode_magnitude_plot(system, initial_exp=-5, final_exp=5, color='b', show_axes=False, grid=True, show=True, **kwargs): r""" Returns the Bode magnitude plot of a continuous-time system. See ``bode_plot`` for all the parameters. """ x, y = bode_magnitude_numerical_data(system, initial_exp=initial_exp, final_exp=final_exp) plt.plot(x, y, color=color, **kwargs) plt.xscale('log') plt.xlabel('Frequency (Hz) [Log Scale]') plt.ylabel('Magnitude (dB)') plt.title(f'Bode Plot (Magnitude) of ${latex(system)}$', pad=20) if grid: plt.grid(True) if show_axes: plt.axhline(0, color='black') plt.axvline(0, color='black') if show: plt.show() return return plt def bode_phase_numerical_data(system, initial_exp=-5, final_exp=5, **kwargs): """ Returns the numerical data of the Bode phase plot of the system. It is internally used by ``bode_phase_plot`` to get the data for plotting Bode phase plot. Users can use this data to further analyse the dynamics of the system or plot using a different backend/plotting-module. Parameters ========== system : SISOLinearTimeInvariant The system for which the Bode phase plot data is to be computed. initial_exp : Number, optional The initial exponent of 10 of the semilog plot. Defaults to -5. final_exp : Number, optional The final exponent of 10 of the semilog plot. Defaults to 5. Returns ======= tuple : (x, y) x = x-axis values of the Bode phase plot. y = y-axis values of the Bode phase plot. Raises ====== NotImplementedError When a SISO LTI system is not passed. When time delay terms are present in the system. ValueError When more than one free symbol is present in the system. The only variable in the transfer function should be the variable of the Laplace transform. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import bode_phase_numerical_data >>> tf1 = TransferFunction(s**2 + 1, s**4 + 4*s**3 + 6*s**2 + 5*s + 2, s) >>> bode_phase_numerical_data(tf1) # doctest: +SKIP ([1e-05, 1.4472354033813751e-05, 2.035581932165858e-05,..., 47577.3248186011, 67884.09326036123, 100000.0], [-2.5000000000291665e-05, -3.6180885085e-05, -5.08895483066e-05,...,-3.1415085799262523, -3.14155265358979]) See Also ======== bode_magnitude_plot, bode_phase_numerical_data """ _check_system(system) expr = system.to_expr() _w = Dummy("w", real=True) w_expr = expr.subs({system.var: I*_w}) phase = arg(w_expr) return LineOver1DRangeSeries(phase, (_w, 10**initial_exp, 10**final_exp), xscale='log', **kwargs).get_points() def bode_phase_plot(system, initial_exp=-5, final_exp=5, color='b', show_axes=False, grid=True, show=True, **kwargs): r""" Returns the Bode phase plot of a continuous-time system. See ``bode_plot`` for all the parameters. """ x, y = bode_phase_numerical_data(system, initial_exp=initial_exp, final_exp=final_exp) plt.plot(x, y, color=color, **kwargs) plt.xscale('log') plt.xlabel('Frequency (Hz) [Log Scale]') plt.ylabel('Phase (rad)') plt.title(f'Bode Plot (Phase) of ${latex(system)}$', pad=20) if grid: plt.grid(True) if show_axes: plt.axhline(0, color='black') plt.axvline(0, color='black') if show: plt.show() return return plt def bode_plot(system, initial_exp=-5, final_exp=5, grid=True, show_axes=False, show=True, **kwargs): r""" Returns the Bode phase and magnitude plots of a continuous-time system. Parameters ========== system : SISOLinearTimeInvariant type The LTI SISO system for which the Bode Plot is to be computed. initial_exp : Number, optional The initial exponent of 10 of the semilog plot. Defaults to -5. final_exp : Number, optional The final exponent of 10 of the semilog plot. Defaults to 5. show : boolean, optional If ``True``, the plot will be displayed otherwise the equivalent matplotlib ``plot`` object will be returned. Defaults to True. prec : int, optional The decimal point precision for the point coordinate values. Defaults to 8. grid : boolean, optional If ``True``, the plot will have a grid. Defaults to True. show_axes : boolean, optional If ``True``, the coordinate axes will be shown. Defaults to False. Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction >>> from sympy.physics.control.control_plots import bode_plot >>> tf1 = TransferFunction(1*s**2 + 0.1*s + 7.5, 1*s**4 + 0.12*s**3 + 9*s**2, s) >>> bode_plot(tf1, initial_exp=0.2, final_exp=0.7) # doctest: +SKIP See Also ======== bode_magnitude_plot, bode_phase_plot """ plt.subplot(211) bode_magnitude_plot(system, initial_exp=initial_exp, final_exp=final_exp, show=False, grid=grid, show_axes=show_axes, **kwargs).title(f'Bode Plot of ${latex(system)}$', pad=20) plt.subplot(212) bode_phase_plot(system, initial_exp=initial_exp, final_exp=final_exp, show=False, grid=grid, show_axes=show_axes, **kwargs).title(None) if show: plt.show() return return plt sympy-sympy-1.9/sympy/physics/control/lti.py000066400000000000000000003317621412543434000214240ustar00rootroot00000000000000from sympy import Basic, Add, Mul, Pow, degree, Symbol, expand, cancel, Expr, roots from sympy.core.containers import Tuple from sympy.core.evalf import EvalfMixin, prec_to_dps from sympy.core.logic import fuzzy_and from sympy.core.numbers import Integer, ComplexInfinity from sympy.core.symbol import Dummy from sympy.core.sympify import sympify, _sympify from sympy.polys import Poly, rootof from sympy.series import limit from sympy.matrices import ImmutableMatrix, eye from sympy.matrices.expressions import MatMul, MatAdd __all__ = ['TransferFunction', 'Series', 'MIMOSeries', 'Parallel', 'MIMOParallel', 'Feedback', 'MIMOFeedback', 'TransferFunctionMatrix'] def _roots(poly, var): """ like roots, but works on higher-order polynomials. """ r = roots(poly, var, multiple=True) n = degree(poly) if len(r) != n: r = [rootof(poly, var, k) for k in range(n)] return r class LinearTimeInvariant(Basic, EvalfMixin): """A common class for all the Linear Time-Invariant Dynamical Systems.""" # Users should not directly interact with this class. def __new__(cls, *system, **kwargs): if cls is LinearTimeInvariant: raise NotImplementedError('The LTICommon class is not meant to be used directly.') return super(LinearTimeInvariant, cls).__new__(cls, *system, **kwargs) @classmethod def _check_args(cls, args): if not args: raise ValueError("Atleast 1 argument must be passed.") if not all(isinstance(arg, cls._clstype) for arg in args): raise TypeError(f"All arguments must be of type {cls._clstype}.") var_set = {arg.var for arg in args} if len(var_set) != 1: raise ValueError("All transfer functions should use the same complex variable" f" of the Laplace transform. {len(var_set)} different values found.") @property def is_SISO(self): """Returns `True` if the passed LTI system is SISO else returns False.""" return self._is_SISO class SISOLinearTimeInvariant(LinearTimeInvariant): """A common class for all the SISO Linear Time-Invariant Dynamical Systems.""" # Users should not directly interact with this class. _is_SISO = True class MIMOLinearTimeInvariant(LinearTimeInvariant): """A common class for all the MIMO Linear Time-Invariant Dynamical Systems.""" # Users should not directly interact with this class. _is_SISO = False SISOLinearTimeInvariant._clstype = SISOLinearTimeInvariant MIMOLinearTimeInvariant._clstype = MIMOLinearTimeInvariant def _check_other_SISO(func): def wrapper(*args, **kwargs): if not isinstance(args[-1], SISOLinearTimeInvariant): return NotImplemented else: return func(*args, **kwargs) return wrapper def _check_other_MIMO(func): def wrapper(*args, **kwargs): if not isinstance(args[-1], MIMOLinearTimeInvariant): return NotImplemented else: return func(*args, **kwargs) return wrapper class TransferFunction(SISOLinearTimeInvariant): r""" A class for representing LTI (Linear, time-invariant) systems that can be strictly described by ratio of polynomials in the Laplace transform complex variable. The arguments are ``num``, ``den``, and ``var``, where ``num`` and ``den`` are numerator and denominator polynomials of the ``TransferFunction`` respectively, and the third argument is a complex variable of the Laplace transform used by these polynomials of the transfer function. ``num`` and ``den`` can be either polynomials or numbers, whereas ``var`` has to be a Symbol. Explanation =========== Generally, a dynamical system representing a physical model can be described in terms of Linear Ordinary Differential Equations like - $\small{b_{m}y^{\left(m\right)}+b_{m-1}y^{\left(m-1\right)}+\dots+b_{1}y^{\left(1\right)}+b_{0}y= a_{n}x^{\left(n\right)}+a_{n-1}x^{\left(n-1\right)}+\dots+a_{1}x^{\left(1\right)}+a_{0}x}$ Here, $x$ is the input signal and $y$ is the output signal and superscript on both is the order of derivative (not exponent). Derivative is taken with respect to the independent variable, $t$. Also, generally $m$ is greater than $n$. It is not feasible to analyse the properties of such systems in their native form therefore, we use mathematical tools like Laplace transform to get a better perspective. Taking the Laplace transform of both the sides in the equation (at zero initial conditions), we get - $\small{\mathcal{L}[b_{m}y^{\left(m\right)}+b_{m-1}y^{\left(m-1\right)}+\dots+b_{1}y^{\left(1\right)}+b_{0}y]= \mathcal{L}[a_{n}x^{\left(n\right)}+a_{n-1}x^{\left(n-1\right)}+\dots+a_{1}x^{\left(1\right)}+a_{0}x]}$ Using the linearity property of Laplace transform and also considering zero initial conditions (i.e. $\small{y(0^{-}) = 0}$, $\small{y'(0^{-}) = 0}$ and so on), the equation above gets translated to - $\small{b_{m}\mathcal{L}[y^{\left(m\right)}]+\dots+b_{1}\mathcal{L}[y^{\left(1\right)}]+b_{0}\mathcal{L}[y]= a_{n}\mathcal{L}[x^{\left(n\right)}]+\dots+a_{1}\mathcal{L}[x^{\left(1\right)}]+a_{0}\mathcal{L}[x]}$ Now, applying Derivative property of Laplace transform, $\small{b_{m}s^{m}\mathcal{L}[y]+\dots+b_{1}s\mathcal{L}[y]+b_{0}\mathcal{L}[y]= a_{n}s^{n}\mathcal{L}[x]+\dots+a_{1}s\mathcal{L}[x]+a_{0}\mathcal{L}[x]}$ Here, the superscript on $s$ is **exponent**. Note that the zero initial conditions assumption, mentioned above, is very important and cannot be ignored otherwise the dynamical system cannot be considered time-independent and the simplified equation above cannot be reached. Collecting $\mathcal{L}[y]$ and $\mathcal{L}[x]$ terms from both the sides and taking the ratio $\frac{ \mathcal{L}\left\{y\right\} }{ \mathcal{L}\left\{x\right\} }$, we get the typical rational form of transfer function. The numerator of the transfer function is, therefore, the Laplace transform of the output signal (The signals are represented as functions of time) and similarly, the denominator of the transfer function is the Laplace transform of the input signal. It is also a convention to denote the input and output signal's Laplace transform with capital alphabets like shown below. $H(s) = \frac{Y(s)}{X(s)} = \frac{ \mathcal{L}\left\{y(t)\right\} }{ \mathcal{L}\left\{x(t)\right\} }$ $s$, also known as complex frequency, is a complex variable in the Laplace domain. It corresponds to the equivalent variable $t$, in the time domain. Transfer functions are sometimes also referred to as the Laplace transform of the system's impulse response. Transfer function, $H$, is represented as a rational function in $s$ like, $H(s) =\ \frac{a_{n}s^{n}+a_{n-1}s^{n-1}+\dots+a_{1}s+a_{0}}{b_{m}s^{m}+b_{m-1}s^{m-1}+\dots+b_{1}s+b_{0}}$ Parameters ========== num : Expr, Number The numerator polynomial of the transfer function. den : Expr, Number The denominator polynomial of the transfer function. var : Symbol Complex variable of the Laplace transform used by the polynomials of the transfer function. Raises ====== TypeError When ``var`` is not a Symbol or when ``num`` or ``den`` is not a number or a polynomial. ValueError When ``den`` is zero. Examples ======== >>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(s + a, s**2 + s + 1, s) >>> tf1 TransferFunction(a + s, s**2 + s + 1, s) >>> tf1.num a + s >>> tf1.den s**2 + s + 1 >>> tf1.var s >>> tf1.args (a + s, s**2 + s + 1, s) Any complex variable can be used for ``var``. >>> tf2 = TransferFunction(a*p**3 - a*p**2 + s*p, p + a**2, p) >>> tf2 TransferFunction(a*p**3 - a*p**2 + p*s, a**2 + p, p) >>> tf3 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) >>> tf3 TransferFunction((p - 1)*(p + 3), (p - 1)*(p + 5), p) To negate a transfer function the ``-`` operator can be prepended: >>> tf4 = TransferFunction(-a + s, p**2 + s, p) >>> -tf4 TransferFunction(a - s, p**2 + s, p) >>> tf5 = TransferFunction(s**4 - 2*s**3 + 5*s + 4, s + 4, s) >>> -tf5 TransferFunction(-s**4 + 2*s**3 - 5*s - 4, s + 4, s) You can use a Float or an Integer (or other constants) as numerator and denominator: >>> tf6 = TransferFunction(1/2, 4, s) >>> tf6.num 0.500000000000000 >>> tf6.den 4 >>> tf6.var s >>> tf6.args (0.5, 4, s) You can take the integer power of a transfer function using the ``**`` operator: >>> tf7 = TransferFunction(s + a, s - a, s) >>> tf7**3 TransferFunction((a + s)**3, (-a + s)**3, s) >>> tf7**0 TransferFunction(1, 1, s) >>> tf8 = TransferFunction(p + 4, p - 3, p) >>> tf8**-1 TransferFunction(p - 3, p + 4, p) Addition, subtraction, and multiplication of transfer functions can form unevaluated ``Series`` or ``Parallel`` objects. >>> tf9 = TransferFunction(s + 1, s**2 + s + 1, s) >>> tf10 = TransferFunction(s - p, s + 3, s) >>> tf11 = TransferFunction(4*s**2 + 2*s - 4, s - 1, s) >>> tf12 = TransferFunction(1 - s, s**2 + 4, s) >>> tf9 + tf10 Parallel(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-p + s, s + 3, s)) >>> tf10 - tf11 Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(-4*s**2 - 2*s + 4, s - 1, s)) >>> tf9 * tf10 Series(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-p + s, s + 3, s)) >>> tf10 - (tf9 + tf12) Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(-s - 1, s**2 + s + 1, s), TransferFunction(s - 1, s**2 + 4, s)) >>> tf10 - (tf9 * tf12) Parallel(TransferFunction(-p + s, s + 3, s), Series(TransferFunction(-1, 1, s), TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(1 - s, s**2 + 4, s))) >>> tf11 * tf10 * tf9 Series(TransferFunction(4*s**2 + 2*s - 4, s - 1, s), TransferFunction(-p + s, s + 3, s), TransferFunction(s + 1, s**2 + s + 1, s)) >>> tf9 * tf11 + tf10 * tf12 Parallel(Series(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(4*s**2 + 2*s - 4, s - 1, s)), Series(TransferFunction(-p + s, s + 3, s), TransferFunction(1 - s, s**2 + 4, s))) >>> (tf9 + tf12) * (tf10 + tf11) Series(Parallel(TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(1 - s, s**2 + 4, s)), Parallel(TransferFunction(-p + s, s + 3, s), TransferFunction(4*s**2 + 2*s - 4, s - 1, s))) These unevaluated ``Series`` or ``Parallel`` objects can convert into the resultant transfer function using ``.doit()`` method or by ``.rewrite(TransferFunction)``. >>> ((tf9 + tf10) * tf12).doit() TransferFunction((1 - s)*((-p + s)*(s**2 + s + 1) + (s + 1)*(s + 3)), (s + 3)*(s**2 + 4)*(s**2 + s + 1), s) >>> (tf9 * tf10 - tf11 * tf12).rewrite(TransferFunction) TransferFunction(-(1 - s)*(s + 3)*(s**2 + s + 1)*(4*s**2 + 2*s - 4) + (-p + s)*(s - 1)*(s + 1)*(s**2 + 4), (s - 1)*(s + 3)*(s**2 + 4)*(s**2 + s + 1), s) See Also ======== Feedback, Series, Parallel References ========== .. [1] https://en.wikipedia.org/wiki/Transfer_function .. [2] https://en.wikipedia.org/wiki/Laplace_transform """ def __new__(cls, num, den, var): num, den = _sympify(num), _sympify(den) if not isinstance(var, Symbol): raise TypeError("Variable input must be a Symbol.") if den == 0: raise ValueError("TransferFunction can't have a zero denominator.") if (((isinstance(num, Expr) and num.has(Symbol)) or num.is_number) and ((isinstance(den, Expr) and den.has(Symbol)) or den.is_number)): obj = super(TransferFunction, cls).__new__(cls, num, den, var) obj._num = num obj._den = den obj._var = var return obj else: raise TypeError("Unsupported type for numerator or denominator of TransferFunction.") @classmethod def from_rational_expression(cls, expr, var=None): r""" Creates a new ``TransferFunction`` efficiently from a rational expression. Parameters ========== expr : Expr, Number The rational expression representing the ``TransferFunction``. var : Symbol, optional Complex variable of the Laplace transform used by the polynomials of the transfer function. Raises ====== ValueError When ``expr`` is of type ``Number`` and optional parameter ``var`` is not passed. When ``expr`` has more than one variables and an optional parameter ``var`` is not passed. ZeroDivisionError When denominator of ``expr`` is zero or it has ``ComplexInfinity`` in its numerator. Examples ======== >>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> expr1 = (s + 5)/(3*s**2 + 2*s + 1) >>> tf1 = TransferFunction.from_rational_expression(expr1) >>> tf1 TransferFunction(s + 5, 3*s**2 + 2*s + 1, s) >>> expr2 = (a*p**3 - a*p**2 + s*p)/(p + a**2) # Expr with more than one variables >>> tf2 = TransferFunction.from_rational_expression(expr2, p) >>> tf2 TransferFunction(a*p**3 - a*p**2 + p*s, a**2 + p, p) In case of conflict between two or more variables in a expression, SymPy will raise a ``ValueError``, if ``var`` is not passed by the user. >>> tf = TransferFunction.from_rational_expression((a + a*s)/(s**2 + s + 1)) Traceback (most recent call last): ... ValueError: Conflicting values found for positional argument `var` ({a, s}). Specify it manually. This can be corrected by specifying the ``var`` parameter manually. >>> tf = TransferFunction.from_rational_expression((a + a*s)/(s**2 + s + 1), s) >>> tf TransferFunction(a*s + a, s**2 + s + 1, s) ``var`` also need to be specified when ``expr`` is a ``Number`` >>> tf3 = TransferFunction.from_rational_expression(10, s) >>> tf3 TransferFunction(10, 1, s) """ expr = _sympify(expr) if var is None: _free_symbols = expr.free_symbols _len_free_symbols = len(_free_symbols) if _len_free_symbols == 1: var = list(_free_symbols)[0] elif _len_free_symbols == 0: raise ValueError("Positional argument `var` not found in the TransferFunction defined. Specify it manually.") else: raise ValueError("Conflicting values found for positional argument `var` ({}). Specify it manually.".format(_free_symbols)) _num, _den = expr.as_numer_denom() if _den == 0 or _num.has(ComplexInfinity): raise ZeroDivisionError("TransferFunction can't have a zero denominator.") return cls(_num, _den, var) @property def num(self): """ Returns the numerator polynomial of the transfer function. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction >>> G1 = TransferFunction(s**2 + p*s + 3, s - 4, s) >>> G1.num p*s + s**2 + 3 >>> G2 = TransferFunction((p + 5)*(p - 3), (p - 3)*(p + 1), p) >>> G2.num (p - 3)*(p + 5) """ return self._num @property def den(self): """ Returns the denominator polynomial of the transfer function. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction >>> G1 = TransferFunction(s + 4, p**3 - 2*p + 4, s) >>> G1.den p**3 - 2*p + 4 >>> G2 = TransferFunction(3, 4, s) >>> G2.den 4 """ return self._den @property def var(self): """ Returns the complex variable of the Laplace transform used by the polynomials of the transfer function. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G1.var p >>> G2 = TransferFunction(0, s - 5, s) >>> G2.var s """ return self._var def _eval_subs(self, old, new): arg_num = self.num.subs(old, new) arg_den = self.den.subs(old, new) argnew = TransferFunction(arg_num, arg_den, self.var) return self if old == self.var else argnew def _eval_evalf(self, prec): return TransferFunction( self.num._eval_evalf(prec), self.den._eval_evalf(prec), self.var) def _eval_simplify(self, **kwargs): tf = cancel(Mul(self.num, 1/self.den, evaluate=False), expand=False).as_numer_denom() num_, den_ = tf[0], tf[1] return TransferFunction(num_, den_, self.var) def expand(self): """ Returns the transfer function with numerator and denominator in expanded form. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> G1 = TransferFunction((a - s)**2, (s**2 + a)**2, s) >>> G1.expand() TransferFunction(a**2 - 2*a*s + s**2, a**2 + 2*a*s**2 + s**4, s) >>> G2 = TransferFunction((p + 3*b)*(p - b), (p - b)*(p + 2*b), p) >>> G2.expand() TransferFunction(-3*b**2 + 2*b*p + p**2, -2*b**2 + b*p + p**2, p) """ return TransferFunction(expand(self.num), expand(self.den), self.var) def dc_gain(self): """ Computes the gain of the response as the frequency approaches zero. The DC gain is infinite for systems with pure integrators. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(s + 3, s**2 - 9, s) >>> tf1.dc_gain() -1/3 >>> tf2 = TransferFunction(p**2, p - 3 + p**3, p) >>> tf2.dc_gain() 0 >>> tf3 = TransferFunction(a*p**2 - b, s + b, s) >>> tf3.dc_gain() (a*p**2 - b)/b >>> tf4 = TransferFunction(1, s, s) >>> tf4.dc_gain() oo """ m = Mul(self.num, Pow(self.den, -1, evaluate=False), evaluate=False) return limit(m, self.var, 0) def poles(self): """ Returns the poles of a transfer function. Examples ======== >>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) >>> tf1.poles() [-5, 1] >>> tf2 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) >>> tf2.poles() [I, I, -I, -I] >>> tf3 = TransferFunction(s**2, a*s + p, s) >>> tf3.poles() [-p/a] """ return _roots(Poly(self.den, self.var), self.var) def zeros(self): """ Returns the zeros of a transfer function. Examples ======== >>> from sympy.abc import s, p, a >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) >>> tf1.zeros() [-3, 1] >>> tf2 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) >>> tf2.zeros() [1, 1] >>> tf3 = TransferFunction(s**2, a*s + p, s) >>> tf3.zeros() [0, 0] """ return _roots(Poly(self.num, self.var), self.var) def is_stable(self): """ Returns True if the transfer function is asymptotically stable; else False. This would not check the marginal or conditional stability of the system. Examples ======== >>> from sympy.abc import s, p, a >>> from sympy import symbols >>> from sympy.physics.control.lti import TransferFunction >>> q, r = symbols('q, r', negative=True) >>> tf1 = TransferFunction((1 - s)**2, (s + 1)**2, s) >>> tf1.is_stable() True >>> tf2 = TransferFunction((1 - p)**2, (s**2 + 1)**2, s) >>> tf2.is_stable() False >>> tf3 = TransferFunction(4, q*s - r, s) >>> tf3.is_stable() False >>> tf4 = TransferFunction(p + 1, a*p - s**2, p) >>> tf4.is_stable() is None # Not enough info about the symbols to determine stability True """ return fuzzy_and(pole.as_real_imag()[0].is_negative for pole in self.poles()) def __add__(self, other): if isinstance(other, (TransferFunction, Series)): if not self.var == other.var: raise ValueError("All the transfer functions should use the same complex variable " "of the Laplace transform.") return Parallel(self, other) elif isinstance(other, Parallel): if not self.var == other.var: raise ValueError("All the transfer functions should use the same complex variable " "of the Laplace transform.") arg_list = list(other.args) return Parallel(self, *arg_list) else: raise ValueError("TransferFunction cannot be added with {}.". format(type(other))) def __radd__(self, other): return self + other def __sub__(self, other): if isinstance(other, (TransferFunction, Series)): if not self.var == other.var: raise ValueError("All the transfer functions should use the same complex variable " "of the Laplace transform.") return Parallel(self, -other) elif isinstance(other, Parallel): if not self.var == other.var: raise ValueError("All the transfer functions should use the same complex variable " "of the Laplace transform.") arg_list = [-i for i in list(other.args)] return Parallel(self, *arg_list) else: raise ValueError("{} cannot be subtracted from a TransferFunction." .format(type(other))) def __rsub__(self, other): return -self + other def __mul__(self, other): if isinstance(other, (TransferFunction, Parallel)): if not self.var == other.var: raise ValueError("All the transfer functions should use the same complex variable " "of the Laplace transform.") return Series(self, other) elif isinstance(other, Series): if not self.var == other.var: raise ValueError("All the transfer functions should use the same complex variable " "of the Laplace transform.") arg_list = list(other.args) return Series(self, *arg_list) else: raise ValueError("TransferFunction cannot be multiplied with {}." .format(type(other))) __rmul__ = __mul__ def __truediv__(self, other): if (isinstance(other, Parallel) and len(other.args) == 2 and isinstance(other.args[0], TransferFunction) and isinstance(other.args[1], (Series, TransferFunction))): if not self.var == other.var: raise ValueError("Both TransferFunction and Parallel should use the" " same complex variable of the Laplace transform.") if other.args[1] == self: # plant and controller with unit feedback. return Feedback(self, other.args[0]) other_arg_list = list(other.args[1].args) if isinstance(other.args[1], Series) else other.args[1] if other_arg_list == other.args[1]: return Feedback(self, other_arg_list) elif self in other_arg_list: other_arg_list.remove(self) else: return Feedback(self, Series(*other_arg_list)) if len(other_arg_list) == 1: return Feedback(self, *other_arg_list) else: return Feedback(self, Series(*other_arg_list)) else: raise ValueError("TransferFunction cannot be divided by {}.". format(type(other))) __rtruediv__ = __truediv__ def __pow__(self, p): p = sympify(p) if not isinstance(p, Integer): raise ValueError("Exponent must be an Integer.") if p == 0: return TransferFunction(1, 1, self.var) elif p > 0: num_, den_ = self.num**p, self.den**p else: p = abs(p) num_, den_ = self.den**p, self.num**p return TransferFunction(num_, den_, self.var) def __neg__(self): return TransferFunction(-self.num, self.den, self.var) @property def is_proper(self): """ Returns True if degree of the numerator polynomial is less than or equal to degree of the denominator polynomial, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) >>> tf1.is_proper False >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*p + 2, p) >>> tf2.is_proper True """ return degree(self.num, self.var) <= degree(self.den, self.var) @property def is_strictly_proper(self): """ Returns True if degree of the numerator polynomial is strictly less than degree of the denominator polynomial, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf1.is_strictly_proper False >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf2.is_strictly_proper True """ return degree(self.num, self.var) < degree(self.den, self.var) @property def is_biproper(self): """ Returns True if degree of the numerator polynomial is equal to degree of the denominator polynomial, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf1.is_biproper True >>> tf2 = TransferFunction(p**2, p + a, p) >>> tf2.is_biproper False """ return degree(self.num, self.var) == degree(self.den, self.var) def to_expr(self): """ Converts a ``TransferFunction`` object to SymPy Expr. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction >>> from sympy import Expr >>> tf1 = TransferFunction(s, a*s**2 + 1, s) >>> tf1.to_expr() s/(a*s**2 + 1) >>> isinstance(_, Expr) True >>> tf2 = TransferFunction(1, (p + 3*b)*(b - p), p) >>> tf2.to_expr() 1/((b - p)*(3*b + p)) >>> tf3 = TransferFunction((s - 2)*(s - 3), (s - 1)*(s - 2)*(s - 3), s) >>> tf3.to_expr() ((s - 3)*(s - 2))/(((s - 3)*(s - 2)*(s - 1))) """ if self.num != 1: return Mul(self.num, Pow(self.den, -1, evaluate=False), evaluate=False) else: return Pow(self.den, -1, evaluate=False) def _flatten_args(args, _cls): temp_args = [] for arg in args: if isinstance(arg, _cls): temp_args.extend(arg.args) else: temp_args.append(arg) return tuple(temp_args) def _dummify_args(_arg, var): dummy_dict = {} dummy_arg_list = [] for arg in _arg: _s = Dummy() dummy_dict[_s] = var dummy_arg = arg.subs({var: _s}) dummy_arg_list.append(dummy_arg) return dummy_arg_list, dummy_dict class Series(SISOLinearTimeInvariant): r""" A class for representing a series configuration of SISO systems. Parameters ========== args : SISOLinearTimeInvariant SISO systems in a series configuration. evaluate : Boolean, Keyword When passed ``True``, returns the equivalent ``Series(*args).doit()``. Set to ``False`` by default. Raises ====== ValueError When no argument is passed. ``var`` attribute is not same for every system. TypeError Any of the passed ``*args`` has unsupported type A combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed, SISO in this case. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series, Parallel >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf3 = TransferFunction(p**2, p + s, s) >>> S1 = Series(tf1, tf2) >>> S1 Series(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)) >>> S1.var s >>> S2 = Series(tf2, Parallel(tf3, -tf1)) >>> S2 Series(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), Parallel(TransferFunction(p**2, p + s, s), TransferFunction(-a*p**2 - b*s, -p + s, s))) >>> S2.var s >>> S3 = Series(Parallel(tf1, tf2), Parallel(tf2, tf3)) >>> S3 Series(Parallel(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)), Parallel(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), TransferFunction(p**2, p + s, s))) >>> S3.var s You can get the resultant transfer function by using ``.doit()`` method: >>> S3 = Series(tf1, tf2, -tf3) >>> S3.doit() TransferFunction(-p**2*(s**3 - 2)*(a*p**2 + b*s), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) >>> S4 = Series(tf2, Parallel(tf1, -tf3)) >>> S4.doit() TransferFunction((s**3 - 2)*(-p**2*(-p + s) + (p + s)*(a*p**2 + b*s)), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) Notes ===== All the transfer functions should use the same complex variable ``var`` of the Laplace transform. See Also ======== MIMOSeries, Parallel, TransferFunction, Feedback """ def __new__(cls, *args, evaluate=False): args = _flatten_args(args, Series) cls._check_args(args) obj = super().__new__(cls, *args) return obj.doit() if evaluate else obj @property def var(self): """ Returns the complex variable used by all the transfer functions. Examples ======== >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, Series, Parallel >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> Series(G1, G2).var p >>> Series(-G3, Parallel(G1, G2)).var p """ return self.args[0].var def doit(self, **kwargs): """ Returns the resultant transfer function obtained after evaluating the transfer functions in series configuration. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> Series(tf2, tf1).doit() TransferFunction((s**3 - 2)*(a*p**2 + b*s), (-p + s)*(s**4 + 5*s + 6), s) >>> Series(-tf1, -tf2).doit() TransferFunction((2 - s**3)*(-a*p**2 - b*s), (-p + s)*(s**4 + 5*s + 6), s) """ _num_arg = (arg.doit().num for arg in self.args) _den_arg = (arg.doit().den for arg in self.args) res_num = Mul(*_num_arg, evaluate=True) res_den = Mul(*_den_arg, evaluate=True) return TransferFunction(res_num, res_den, self.var) def _eval_rewrite_as_TransferFunction(self, *args, **kwargs): return self.doit() @_check_other_SISO def __add__(self, other): if isinstance(other, Parallel): arg_list = list(other.args) return Parallel(self, *arg_list) return Parallel(self, other) __radd__ = __add__ @_check_other_SISO def __sub__(self, other): return self + (-other) def __rsub__(self, other): return -self + other @_check_other_SISO def __mul__(self, other): arg_list = list(self.args) return Series(*arg_list, other) def __truediv__(self, other): if (isinstance(other, Parallel) and len(other.args) == 2 and isinstance(other.args[0], TransferFunction) and isinstance(other.args[1], Series)): if not self.var == other.var: raise ValueError("All the transfer functions should use the same complex variable " "of the Laplace transform.") self_arg_list = set(list(self.args)) other_arg_list = set(list(other.args[1].args)) res = list(self_arg_list ^ other_arg_list) if len(res) == 0: return Feedback(self, other.args[0]) elif len(res) == 1: return Feedback(self, *res) else: return Feedback(self, Series(*res)) else: raise ValueError("This transfer function expression is invalid.") def __neg__(self): return Series(TransferFunction(-1, 1, self.var), self) def to_expr(self): """Returns the equivalent ``Expr`` object.""" return Mul(*(arg.to_expr() for arg in self.args), evaluate=False) @property def is_proper(self): """ Returns True if degree of the numerator polynomial of the resultant transfer function is less than or equal to degree of the denominator polynomial of the same, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*s + 2, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> S1 = Series(-tf2, tf1) >>> S1.is_proper False >>> S2 = Series(tf1, tf2, tf3) >>> S2.is_proper True """ return self.doit().is_proper @property def is_strictly_proper(self): """ Returns True if degree of the numerator polynomial of the resultant transfer function is strictly less than degree of the denominator polynomial of the same, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**2 + 5*s + 6, s) >>> tf3 = TransferFunction(1, s**2 + s + 1, s) >>> S1 = Series(tf1, tf2) >>> S1.is_strictly_proper False >>> S2 = Series(tf1, tf2, tf3) >>> S2.is_strictly_proper True """ return self.doit().is_strictly_proper @property def is_biproper(self): r""" Returns True if degree of the numerator polynomial of the resultant transfer function is equal to degree of the denominator polynomial of the same, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Series >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(p, s**2, s) >>> tf3 = TransferFunction(s**2, 1, s) >>> S1 = Series(tf1, -tf2) >>> S1.is_biproper False >>> S2 = Series(tf2, tf3) >>> S2.is_biproper True """ return self.doit().is_biproper def _mat_mul_compatible(*args): """To check whether shapes are compatible for matrix mul.""" return all(args[i].num_outputs == args[i+1].num_inputs for i in range(len(args)-1)) class MIMOSeries(MIMOLinearTimeInvariant): r""" A class for representing a series configuration of MIMO systems. Parameters ========== args : MIMOLinearTimeInvariant MIMO systems in a series configuration. evaluate : Boolean, Keyword When passed ``True``, returns the equivalent ``MIMOSeries(*args).doit()``. Set to ``False`` by default. Raises ====== ValueError When no argument is passed. ``var`` attribute is not same for every system. ``num_outputs`` of the MIMO system is not equal to the ``num_inputs`` of its adjacent MIMO system. (Matrix multiplication constraint, basically) TypeError Any of the passed ``*args`` has unsupported type A combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed, MIMO in this case. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import MIMOSeries, TransferFunctionMatrix >>> from sympy import Matrix, pprint >>> mat_a = Matrix([[5*s], [5]]) # 2 Outputs 1 Input >>> mat_b = Matrix([[5, 1/(6*s**2)]]) # 1 Output 2 Inputs >>> mat_c = Matrix([[1, s], [5/s, 1]]) # 2 Outputs 2 Inputs >>> tfm_a = TransferFunctionMatrix.from_Matrix(mat_a, s) >>> tfm_b = TransferFunctionMatrix.from_Matrix(mat_b, s) >>> tfm_c = TransferFunctionMatrix.from_Matrix(mat_c, s) >>> MIMOSeries(tfm_c, tfm_b, tfm_a) MIMOSeries(TransferFunctionMatrix(((TransferFunction(1, 1, s), TransferFunction(s, 1, s)), (TransferFunction(5, s, s), TransferFunction(1, 1, s)))), TransferFunctionMatrix(((TransferFunction(5, 1, s), TransferFunction(1, 6*s**2, s)),)), TransferFunctionMatrix(((TransferFunction(5*s, 1, s),), (TransferFunction(5, 1, s),)))) >>> pprint(_, use_unicode=False) # For Better Visualization [5*s] [1 s] [---] [5 1 ] [- -] [ 1 ] [- ----] [1 1] [ ] *[1 2] *[ ] [ 5 ] [ 6*s ]{t} [5 1] [ - ] [- -] [ 1 ]{t} [s 1]{t} >>> MIMOSeries(tfm_c, tfm_b, tfm_a).doit() TransferFunctionMatrix(((TransferFunction(150*s**4 + 25*s, 6*s**3, s), TransferFunction(150*s**4 + 5*s, 6*s**2, s)), (TransferFunction(150*s**3 + 25, 6*s**3, s), TransferFunction(150*s**3 + 5, 6*s**2, s)))) >>> pprint(_, use_unicode=False) # (2 Inputs -A-> 2 Outputs) -> (2 Inputs -B-> 1 Output) -> (1 Input -C-> 2 Outputs) is equivalent to (2 Inputs -Series Equivalent-> 2 Outputs). [ 4 4 ] [150*s + 25*s 150*s + 5*s] [------------- ------------] [ 3 2 ] [ 6*s 6*s ] [ ] [ 3 3 ] [ 150*s + 25 150*s + 5 ] [ ----------- ---------- ] [ 3 2 ] [ 6*s 6*s ]{t} Notes ===== All the transfer function matrices should use the same complex variable ``var`` of the Laplace transform. ``MIMOSeries(A, B)`` is not equivalent to ``A*B``. It is always in the reverse order, that is ``B*A``. See Also ======== Series, MIMOParallel """ def __new__(cls, *args, evaluate=False): cls._check_args(args) if _mat_mul_compatible(*args): obj = super().__new__(cls, *args) else: raise ValueError("Number of input signals do not match the number" " of output signals of adjacent systems for some args.") return obj.doit() if evaluate else obj @property def var(self): """ Returns the complex variable used by all the transfer functions. Examples ======== >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, MIMOSeries, TransferFunctionMatrix >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> tfm_1 = TransferFunctionMatrix([[G1, G2, G3]]) >>> tfm_2 = TransferFunctionMatrix([[G1], [G2], [G3]]) >>> MIMOSeries(tfm_2, tfm_1).var p """ return self.args[0].var @property def num_inputs(self): """Returns the number of input signals of the series system.""" return self.args[0].num_inputs @property def num_outputs(self): """Returns the number of output signals of the series system.""" return self.args[-1].num_outputs @property def shape(self): """Returns the shape of the equivalent MIMO system.""" return self.num_outputs, self.num_inputs def doit(self, cancel=False, **kwargs): """ Returns the resultant transfer function matrix obtained after evaluating the MIMO systems arranged in a series configuration. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, MIMOSeries, TransferFunctionMatrix >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tfm1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf2]]) >>> tfm2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf1]]) >>> MIMOSeries(tfm2, tfm1).doit() TransferFunctionMatrix(((TransferFunction(2*(-p + s)*(s**3 - 2)*(a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)**2*(s**4 + 5*s + 6)**2, s), TransferFunction((-p + s)**2*(s**3 - 2)*(a*p**2 + b*s) + (-p + s)*(a*p**2 + b*s)**2*(s**4 + 5*s + 6), (-p + s)**3*(s**4 + 5*s + 6), s)), (TransferFunction((-p + s)*(s**3 - 2)**2*(s**4 + 5*s + 6) + (s**3 - 2)*(a*p**2 + b*s)*(s**4 + 5*s + 6)**2, (-p + s)*(s**4 + 5*s + 6)**3, s), TransferFunction(2*(s**3 - 2)*(a*p**2 + b*s), (-p + s)*(s**4 + 5*s + 6), s)))) """ _arg = (arg.doit()._expr_mat for arg in reversed(self.args)) if cancel: res = MatMul(*_arg, evaluate=True) return TransferFunctionMatrix.from_Matrix(res, self.var) _dummy_args, _dummy_dict = _dummify_args(_arg, self.var) res = MatMul(*_dummy_args, evaluate=True) temp_tfm = TransferFunctionMatrix.from_Matrix(res, self.var) return temp_tfm.subs(_dummy_dict) def _eval_rewrite_as_TransferFunctionMatrix(self, *args, **kwargs): return self.doit() @_check_other_MIMO def __add__(self, other): if isinstance(other, MIMOParallel): arg_list = list(other.args) return MIMOParallel(self, *arg_list) return MIMOParallel(self, other) __radd__ = __add__ @_check_other_MIMO def __sub__(self, other): return self + (-other) def __rsub__(self, other): return -self + other @_check_other_MIMO def __mul__(self, other): if isinstance(other, MIMOSeries): self_arg_list = list(self.args) other_arg_list = list(other.args) return MIMOSeries(*other_arg_list, *self_arg_list) # A*B = MIMOSeries(B, A) arg_list = list(self.args) return MIMOSeries(other, *arg_list) def __neg__(self): arg_list = list(self.args) arg_list[0] = -arg_list[0] return MIMOSeries(*arg_list) class Parallel(SISOLinearTimeInvariant): r""" A class for representing a parallel configuration of SISO systems. Parameters ========== args : SISOLinearTimeInvariant SISO systems in a parallel arrangement. evaluate : Boolean, Keyword When passed ``True``, returns the equivalent ``Parallel(*args).doit()``. Set to ``False`` by default. Raises ====== ValueError When no argument is passed. ``var`` attribute is not same for every system. TypeError Any of the passed ``*args`` has unsupported type A combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel, Series >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf3 = TransferFunction(p**2, p + s, s) >>> P1 = Parallel(tf1, tf2) >>> P1 Parallel(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)) >>> P1.var s >>> P2 = Parallel(tf2, Series(tf3, -tf1)) >>> P2 Parallel(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), Series(TransferFunction(p**2, p + s, s), TransferFunction(-a*p**2 - b*s, -p + s, s))) >>> P2.var s >>> P3 = Parallel(Series(tf1, tf2), Series(tf2, tf3)) >>> P3 Parallel(Series(TransferFunction(a*p**2 + b*s, -p + s, s), TransferFunction(s**3 - 2, s**4 + 5*s + 6, s)), Series(TransferFunction(s**3 - 2, s**4 + 5*s + 6, s), TransferFunction(p**2, p + s, s))) >>> P3.var s You can get the resultant transfer function by using ``.doit()`` method: >>> Parallel(tf1, tf2, -tf3).doit() TransferFunction(-p**2*(-p + s)*(s**4 + 5*s + 6) + (-p + s)*(p + s)*(s**3 - 2) + (p + s)*(a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) >>> Parallel(tf2, Series(tf1, -tf3)).doit() TransferFunction(-p**2*(a*p**2 + b*s)*(s**4 + 5*s + 6) + (-p + s)*(p + s)*(s**3 - 2), (-p + s)*(p + s)*(s**4 + 5*s + 6), s) Notes ===== All the transfer functions should use the same complex variable ``var`` of the Laplace transform. See Also ======== Series, TransferFunction, Feedback """ def __new__(cls, *args, evaluate=False): args = _flatten_args(args, Parallel) cls._check_args(args) obj = super().__new__(cls, *args) return obj.doit() if evaluate else obj @property def var(self): """ Returns the complex variable used by all the transfer functions. Examples ======== >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, Parallel, Series >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> Parallel(G1, G2).var p >>> Parallel(-G3, Series(G1, G2)).var p """ return self.args[0].var def doit(self, **kwargs): """ Returns the resultant transfer function obtained after evaluating the transfer functions in parallel configuration. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> Parallel(tf2, tf1).doit() TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s) >>> Parallel(-tf1, -tf2).doit() TransferFunction((2 - s**3)*(-p + s) + (-a*p**2 - b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s) """ _arg = (arg.doit().to_expr() for arg in self.args) res = Add(*_arg).as_numer_denom() return TransferFunction(*res, self.var) def _eval_rewrite_as_TransferFunction(self, *args, **kwargs): return self.doit() @_check_other_SISO def __add__(self, other): self_arg_list = list(self.args) return Parallel(*self_arg_list, other) __radd__ = __add__ @_check_other_SISO def __sub__(self, other): return self + (-other) def __rsub__(self, other): return -self + other @_check_other_SISO def __mul__(self, other): if isinstance(other, Series): arg_list = list(other.args) return Series(self, *arg_list) return Series(self, other) def __neg__(self): return Series(TransferFunction(-1, 1, self.var), self) def to_expr(self): """Returns the equivalent ``Expr`` object.""" return Add(*(arg.to_expr() for arg in self.args), evaluate=False) @property def is_proper(self): """ Returns True if degree of the numerator polynomial of the resultant transfer function is less than or equal to degree of the denominator polynomial of the same, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) >>> tf2 = TransferFunction(p**2 - 4*p, p**3 + 3*s + 2, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> P1 = Parallel(-tf2, tf1) >>> P1.is_proper False >>> P2 = Parallel(tf2, tf3) >>> P2.is_proper True """ return self.doit().is_proper @property def is_strictly_proper(self): """ Returns True if degree of the numerator polynomial of the resultant transfer function is strictly less than degree of the denominator polynomial of the same, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> P1 = Parallel(tf1, tf2) >>> P1.is_strictly_proper False >>> P2 = Parallel(tf2, tf3) >>> P2.is_strictly_proper True """ return self.doit().is_strictly_proper @property def is_biproper(self): """ Returns True if degree of the numerator polynomial of the resultant transfer function is equal to degree of the denominator polynomial of the same, else False. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, Parallel >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(p**2, p + s, s) >>> tf3 = TransferFunction(s, s**2 + s + 1, s) >>> P1 = Parallel(tf1, -tf2) >>> P1.is_biproper True >>> P2 = Parallel(tf2, tf3) >>> P2.is_biproper False """ return self.doit().is_biproper class MIMOParallel(MIMOLinearTimeInvariant): r""" A class for representing a parallel configuration of MIMO systems. Parameters ========== args : MIMOLinearTimeInvariant MIMO Systems in a parallel arrangement. evaluate : Boolean, Keyword When passed ``True``, returns the equivalent ``MIMOParallel(*args).doit()``. Set to ``False`` by default. Raises ====== ValueError When no argument is passed. ``var`` attribute is not same for every system. All MIMO systems passed don't have same shape. TypeError Any of the passed ``*args`` has unsupported type A combination of SISO and MIMO systems is passed. There should be homogeneity in the type of systems passed, MIMO in this case. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunctionMatrix, MIMOParallel >>> from sympy import Matrix, pprint >>> expr_1 = 1/s >>> expr_2 = s/(s**2-1) >>> expr_3 = (2 + s)/(s**2 - 1) >>> expr_4 = 5 >>> tfm_a = TransferFunctionMatrix.from_Matrix(Matrix([[expr_1, expr_2], [expr_3, expr_4]]), s) >>> tfm_b = TransferFunctionMatrix.from_Matrix(Matrix([[expr_2, expr_1], [expr_4, expr_3]]), s) >>> tfm_c = TransferFunctionMatrix.from_Matrix(Matrix([[expr_3, expr_4], [expr_1, expr_2]]), s) >>> MIMOParallel(tfm_a, tfm_b, tfm_c) MIMOParallel(TransferFunctionMatrix(((TransferFunction(1, s, s), TransferFunction(s, s**2 - 1, s)), (TransferFunction(s + 2, s**2 - 1, s), TransferFunction(5, 1, s)))), TransferFunctionMatrix(((TransferFunction(s, s**2 - 1, s), TransferFunction(1, s, s)), (TransferFunction(5, 1, s), TransferFunction(s + 2, s**2 - 1, s)))), TransferFunctionMatrix(((TransferFunction(s + 2, s**2 - 1, s), TransferFunction(5, 1, s)), (TransferFunction(1, s, s), TransferFunction(s, s**2 - 1, s))))) >>> pprint(_, use_unicode=False) # For Better Visualization [ 1 s ] [ s 1 ] [s + 2 5 ] [ - ------] [------ - ] [------ - ] [ s 2 ] [ 2 s ] [ 2 1 ] [ s - 1] [s - 1 ] [s - 1 ] [ ] + [ ] + [ ] [s + 2 5 ] [ 5 s + 2 ] [ 1 s ] [------ - ] [ - ------] [ - ------] [ 2 1 ] [ 1 2 ] [ s 2 ] [s - 1 ]{t} [ s - 1]{t} [ s - 1]{t} >>> MIMOParallel(tfm_a, tfm_b, tfm_c).doit() TransferFunctionMatrix(((TransferFunction(s**2 + s*(2*s + 2) - 1, s*(s**2 - 1), s), TransferFunction(2*s**2 + 5*s*(s**2 - 1) - 1, s*(s**2 - 1), s)), (TransferFunction(s**2 + s*(s + 2) + 5*s*(s**2 - 1) - 1, s*(s**2 - 1), s), TransferFunction(5*s**2 + 2*s - 3, s**2 - 1, s)))) >>> pprint(_, use_unicode=False) [ 2 2 / 2 \ ] [ s + s*(2*s + 2) - 1 2*s + 5*s*\s - 1/ - 1] [ -------------------- -----------------------] [ / 2 \ / 2 \ ] [ s*\s - 1/ s*\s - 1/ ] [ ] [ 2 / 2 \ 2 ] [s + s*(s + 2) + 5*s*\s - 1/ - 1 5*s + 2*s - 3 ] [--------------------------------- -------------- ] [ / 2 \ 2 ] [ s*\s - 1/ s - 1 ]{t} Notes ===== All the transfer function matrices should use the same complex variable ``var`` of the Laplace transform. See Also ======== Parallel, MIMOSeries """ def __new__(cls, *args, evaluate=False): args = _flatten_args(args, MIMOParallel) cls._check_args(args) if any(arg.shape != args[0].shape for arg in args): raise TypeError("Shape of all the args is not equal.") obj = super().__new__(cls, *args) return obj.doit() if evaluate else obj @property def var(self): """ Returns the complex variable used by all the systems. Examples ======== >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOParallel >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> G4 = TransferFunction(p**2, p**2 - 1, p) >>> tfm_a = TransferFunctionMatrix([[G1, G2], [G3, G4]]) >>> tfm_b = TransferFunctionMatrix([[G2, G1], [G4, G3]]) >>> MIMOParallel(tfm_a, tfm_b).var p """ return self.args[0].var @property def num_inputs(self): """Returns the number of input signals of the parallel system.""" return self.args[0].num_inputs @property def num_outputs(self): """Returns the number of output signals of the parallel system.""" return self.args[0].num_outputs @property def shape(self): """Returns the shape of the equivalent MIMO system.""" return self.num_outputs, self.num_inputs def doit(self, **kwargs): """ Returns the resultant transfer function matrix obtained after evaluating the MIMO systems arranged in a parallel configuration. Examples ======== >>> from sympy.abc import s, p, a, b >>> from sympy.physics.control.lti import TransferFunction, MIMOParallel, TransferFunctionMatrix >>> tf1 = TransferFunction(a*p**2 + b*s, s - p, s) >>> tf2 = TransferFunction(s**3 - 2, s**4 + 5*s + 6, s) >>> tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) >>> MIMOParallel(tfm_1, tfm_2).doit() TransferFunctionMatrix(((TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s), TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s)), (TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s), TransferFunction((-p + s)*(s**3 - 2) + (a*p**2 + b*s)*(s**4 + 5*s + 6), (-p + s)*(s**4 + 5*s + 6), s)))) """ _arg = (arg.doit()._expr_mat for arg in self.args) res = MatAdd(*_arg, evaluate=True) return TransferFunctionMatrix.from_Matrix(res, self.var) def _eval_rewrite_as_TransferFunctionMatrix(self, *args, **kwargs): return self.doit() @_check_other_MIMO def __add__(self, other): self_arg_list = list(self.args) return MIMOParallel(*self_arg_list, other) __radd__ = __add__ @_check_other_MIMO def __sub__(self, other): return self + (-other) def __rsub__(self, other): return -self + other @_check_other_MIMO def __mul__(self, other): if isinstance(other, MIMOSeries): arg_list = list(other.args) return MIMOSeries(*arg_list, self) return MIMOSeries(other, self) def __neg__(self): arg_list = [-arg for arg in list(self.args)] return MIMOParallel(*arg_list) class Feedback(SISOLinearTimeInvariant): r""" A class for representing closed-loop feedback interconnection between two SISO input/output systems. The first argument, ``sys1``, is the feedforward part of the closed-loop system or in simple words, the dynamical model representing the process to be controlled. The second argument, ``sys2``, is the feedback system and controls the fed back signal to ``sys1``. Both ``sys1`` and ``sys2`` can either be ``Series`` or ``TransferFunction`` objects. Parameters ========== sys1 : Series, TransferFunction The feedforward path system. sys2 : Series, TransferFunction, optional The feedback path system (often a feedback controller). It is the model sitting on the feedback path. If not specified explicitly, the sys2 is assumed to be unit (1.0) transfer function. sign : int, optional The sign of feedback. Can either be ``1`` (for positive feedback) or ``-1`` (for negative feedback). Default value is `-1`. Raises ====== ValueError When ``sys1`` and ``sys2`` are not using the same complex variable of the Laplace transform. When a combination of ``sys1`` and ``sys2`` yields zero denominator. TypeError When either ``sys1`` or ``sys2`` is not a ``Series`` or a ``TransferFunction`` object. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1 Feedback(TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s), TransferFunction(5*s - 10, s + 7, s), -1) >>> F1.var s >>> F1.args (TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s), TransferFunction(5*s - 10, s + 7, s), -1) You can get the feedforward and feedback path systems by using ``.sys1`` and ``.sys2`` respectively. >>> F1.sys1 TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> F1.sys2 TransferFunction(5*s - 10, s + 7, s) You can get the resultant closed loop transfer function obtained by negative feedback interconnection using ``.doit()`` method. >>> F1.doit() TransferFunction((s + 7)*(s**2 - 4*s + 2)*(3*s**2 + 7*s - 3), ((s + 7)*(s**2 - 4*s + 2) + (5*s - 10)*(3*s**2 + 7*s - 3))*(s**2 - 4*s + 2), s) >>> G = TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s) >>> C = TransferFunction(5*s + 10, s + 10, s) >>> F2 = Feedback(G*C, TransferFunction(1, 1, s)) >>> F2.doit() TransferFunction((s + 10)*(5*s + 10)*(s**2 + 2*s + 3)*(2*s**2 + 5*s + 1), (s + 10)*((s + 10)*(s**2 + 2*s + 3) + (5*s + 10)*(2*s**2 + 5*s + 1))*(s**2 + 2*s + 3), s) To negate a ``Feedback`` object, the ``-`` operator can be prepended: >>> -F1 Feedback(TransferFunction(-3*s**2 - 7*s + 3, s**2 - 4*s + 2, s), TransferFunction(10 - 5*s, s + 7, s), -1) >>> -F2 Feedback(Series(TransferFunction(-1, 1, s), TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s), TransferFunction(5*s + 10, s + 10, s)), TransferFunction(-1, 1, s), -1) See Also ======== MIMOFeedback, Series, Parallel """ def __new__(cls, sys1, sys2=None, sign=-1): if not sys2: sys2 = TransferFunction(1, 1, sys1.var) if not (isinstance(sys1, (TransferFunction, Series)) and isinstance(sys2, (TransferFunction, Series))): raise TypeError("Unsupported type for `sys1` or `sys2` of Feedback.") if sign not in [-1, 1]: raise ValueError("Unsupported type for feedback. `sign` arg should " "either be 1 (positive feedback loop) or -1 (negative feedback loop).") if Mul(sys1.to_expr(), sys2.to_expr()).simplify() == sign: raise ValueError("The equivalent system will have zero denominator.") if sys1.var != sys2.var: raise ValueError("Both `sys1` and `sys2` should be using the" " same complex variable.") return super().__new__(cls, sys1, sys2, _sympify(sign)) @property def sys1(self): """ Returns the feedforward system of the feedback interconnection. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.sys1 TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - s, p + 2, p) >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) >>> F2.sys1 TransferFunction(1, 1, p) """ return self.args[0] @property def sys2(self): """ Returns the feedback controller of the feedback interconnection. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.sys2 TransferFunction(5*s - 10, s + 7, s) >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - s, p + 2, p) >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) >>> F2.sys2 Series(TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p), TransferFunction(5*p + 10, p + 10, p), TransferFunction(1 - s, p + 2, p)) """ return self.args[1] @property def var(self): """ Returns the complex variable of the Laplace transform used by all the transfer functions involved in the feedback interconnection. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.var s >>> G = TransferFunction(2*s**2 + 5*s + 1, p**2 + 2*p + 3, p) >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - s, p + 2, p) >>> F2 = Feedback(TransferFunction(1, 1, p), G*C*P) >>> F2.var p """ return self.sys1.var @property def sign(self): """ Returns the type of MIMO Feedback model. ``1`` for Positive and ``-1`` for Negative. """ return self.args[2] @property def sensitivity(self): """ Returns the sensitivity function of the feedback loop. Sensitivity of a Feedback system is the ratio of change in the open loop gain to the change in the closed loop gain. .. note:: This method would not return the complementary sensitivity function. Examples ======== >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> C = TransferFunction(5*p + 10, p + 10, p) >>> P = TransferFunction(1 - p, p + 2, p) >>> F_1 = Feedback(P, C) >>> F_1.sensitivity 1/((1 - p)*(5*p + 10)/((p + 2)*(p + 10)) + 1) """ return 1/(1 - self.sign*self.sys1.to_expr()*self.sys2.to_expr()) def doit(self, cancel=False, expand=False, **kwargs): """ Returns the resultant transfer function obtained by the feedback interconnection. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, Feedback >>> plant = TransferFunction(3*s**2 + 7*s - 3, s**2 - 4*s + 2, s) >>> controller = TransferFunction(5*s - 10, s + 7, s) >>> F1 = Feedback(plant, controller) >>> F1.doit() TransferFunction((s + 7)*(s**2 - 4*s + 2)*(3*s**2 + 7*s - 3), ((s + 7)*(s**2 - 4*s + 2) + (5*s - 10)*(3*s**2 + 7*s - 3))*(s**2 - 4*s + 2), s) >>> G = TransferFunction(2*s**2 + 5*s + 1, s**2 + 2*s + 3, s) >>> F2 = Feedback(G, TransferFunction(1, 1, s)) >>> F2.doit() TransferFunction((s**2 + 2*s + 3)*(2*s**2 + 5*s + 1), (s**2 + 2*s + 3)*(3*s**2 + 7*s + 4), s) Use kwarg ``expand=True`` to expand the resultant transfer function. Use ``cancel=True`` to cancel out the common terms in numerator and denominator. >>> F2.doit(cancel=True, expand=True) TransferFunction(2*s**2 + 5*s + 1, 3*s**2 + 7*s + 4, s) >>> F2.doit(expand=True) TransferFunction(2*s**4 + 9*s**3 + 17*s**2 + 17*s + 3, 3*s**4 + 13*s**3 + 27*s**2 + 29*s + 12, s) """ arg_list = list(self.sys1.args) if isinstance(self.sys1, Series) else [self.sys1] # F_n and F_d are resultant TFs of num and den of Feedback. F_n, unit = self.sys1.doit(), TransferFunction(1, 1, self.sys1.var) if self.sign == -1: F_d = Parallel(unit, Series(self.sys2, *arg_list)).doit() else: F_d = Parallel(unit, -Series(self.sys2, *arg_list)).doit() _resultant_tf = TransferFunction(F_n.num * F_d.den, F_n.den * F_d.num, F_n.var) if cancel: _resultant_tf = _resultant_tf.simplify() if expand: _resultant_tf = _resultant_tf.expand() return _resultant_tf def _eval_rewrite_as_TransferFunction(self, num, den, sign, **kwargs): return self.doit() def __neg__(self): return Feedback(-self.sys1, -self.sys2, self.sign) def _is_invertible(a, b, sign): """ Checks whether a given pair of MIMO systems passed is invertible or not. """ _mat = eye(a.num_outputs) - sign*(a.doit()._expr_mat)*(b.doit()._expr_mat) _det = _mat.det() return _det != 0 class MIMOFeedback(MIMOLinearTimeInvariant): r""" A class for representing closed-loop feedback interconnection between two MIMO input/output systems. Parameters ========== sys1 : MIMOSeries, TransferFunctionMatrix The MIMO system placed on the feedforward path. sys2 : MIMOSeries, TransferFunctionMatrix The system placed on the feedback path (often a feedback controller). sign : int, optional The sign of feedback. Can either be ``1`` (for positive feedback) or ``-1`` (for negative feedback). Default value is `-1`. Raises ====== ValueError When ``sys1`` and ``sys2`` are not using the same complex variable of the Laplace transform. Forward path model should have an equal number of inputs/outputs to the feedback path outputs/inputs. When product of ``sys1`` and ``sys2`` is not a square matrix. When the equivalent MIMO system is not invertible. TypeError When either ``sys1`` or ``sys2`` is not a ``MIMOSeries`` or a ``TransferFunctionMatrix`` object. Examples ======== >>> from sympy import Matrix, pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunctionMatrix, MIMOFeedback >>> plant_mat = Matrix([[1, 1/s], [0, 1]]) >>> controller_mat = Matrix([[10, 0], [0, 10]]) # Constant Gain >>> plant = TransferFunctionMatrix.from_Matrix(plant_mat, s) >>> controller = TransferFunctionMatrix.from_Matrix(controller_mat, s) >>> feedback = MIMOFeedback(plant, controller) # Negative Feedback (default) >>> pprint(feedback, use_unicode=False) / [1 1] [10 0 ] \-1 [1 1] | [- -] [-- - ] | [- -] | [1 s] [1 1 ] | [1 s] |I + [ ] *[ ] | * [ ] | [0 1] [0 10] | [0 1] | [- -] [- --] | [- -] \ [1 1]{t} [1 1 ]{t}/ [1 1]{t} To get the equivalent system matrix, use either ``doit`` or ``rewrite`` method. >>> pprint(feedback.doit(), use_unicode=False) [1 1 ] [-- -----] [11 121*s] [ ] [0 1 ] [- -- ] [1 11 ]{t} To negate the ``MIMOFeedback`` object, use ``-`` operator. >>> neg_feedback = -feedback >>> pprint(neg_feedback.doit(), use_unicode=False) [-1 -1 ] [--- -----] [ 11 121*s] [ ] [ 0 -1 ] [ - --- ] [ 1 11 ]{t} See Also ======== Feedback, MIMOSeries, MIMOParallel """ def __new__(cls, sys1, sys2, sign=-1): if not (isinstance(sys1, (TransferFunctionMatrix, MIMOSeries)) and isinstance(sys2, (TransferFunctionMatrix, MIMOSeries))): raise TypeError("Unsupported type for `sys1` or `sys2` of MIMO Feedback.") if sys1.num_inputs != sys2.num_outputs or \ sys1.num_outputs != sys2.num_inputs: raise ValueError("Product of `sys1` and `sys2` " "must yield a square matrix.") if sign not in [-1, 1]: raise ValueError("Unsupported type for feedback. `sign` arg should " "either be 1 (positive feedback loop) or -1 (negative feedback loop).") if not _is_invertible(sys1, sys2, sign): raise ValueError("Non-Invertible system inputted.") if sys1.var != sys2.var: raise ValueError("Both `sys1` and `sys2` should be using the" " same complex variable.") return super().__new__(cls, sys1, sys2, _sympify(sign)) @property def sys1(self): r""" Returns the system placed on the feedforward path of the MIMO feedback interconnection. Examples ======== >>> from sympy import pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(s**2 + s + 1, s**2 - s + 1, s) >>> tf2 = TransferFunction(1, s, s) >>> tf3 = TransferFunction(1, 1, s) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf3, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) >>> F_1.sys1 TransferFunctionMatrix(((TransferFunction(s**2 + s + 1, s**2 - s + 1, s), TransferFunction(1, s, s)), (TransferFunction(1, s, s), TransferFunction(s**2 + s + 1, s**2 - s + 1, s)))) >>> pprint(_, use_unicode=False) [ 2 ] [s + s + 1 1 ] [---------- - ] [ 2 s ] [s - s + 1 ] [ ] [ 2 ] [ 1 s + s + 1] [ - ----------] [ s 2 ] [ s - s + 1]{t} """ return self.args[0] @property def sys2(self): r""" Returns the feedback controller of the MIMO feedback interconnection. Examples ======== >>> from sympy import pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(s**2, s**3 - s + 1, s) >>> tf2 = TransferFunction(1, s, s) >>> tf3 = TransferFunction(1, 1, s) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2) >>> F_1.sys2 TransferFunctionMatrix(((TransferFunction(s**2, s**3 - s + 1, s), TransferFunction(1, 1, s)), (TransferFunction(1, 1, s), TransferFunction(1, s, s)))) >>> pprint(_, use_unicode=False) [ 2 ] [ s 1] [---------- -] [ 3 1] [s - s + 1 ] [ ] [ 1 1] [ - -] [ 1 s]{t} """ return self.args[1] @property def var(self): r""" Returns the complex variable of the Laplace transform used by all the transfer functions involved in the MIMO feedback loop. Examples ======== >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(p, 1 - p, p) >>> tf2 = TransferFunction(1, p, p) >>> tf3 = TransferFunction(1, 1, p) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) # Positive feedback >>> F_1.var p """ return self.sys1.var @property def sign(self): r""" Returns the type of feedback interconnection of two models. ``1`` for Positive and ``-1`` for Negative. """ return self.args[2] @property def sensitivity(self): r""" Returns the sensitivity function matrix of the feedback loop. Sensitivity of a closed-loop system is the ratio of change in the open loop gain to the change in the closed loop gain. .. note:: This method would not return the complementary sensitivity function. Examples ======== >>> from sympy import pprint >>> from sympy.abc import p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(p, 1 - p, p) >>> tf2 = TransferFunction(1, p, p) >>> tf3 = TransferFunction(1, 1, p) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) >>> sys2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf2]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) # Positive feedback >>> F_2 = MIMOFeedback(sys1, sys2) # Negative feedback >>> pprint(F_1.sensitivity, use_unicode=False) [ 4 3 2 5 4 2 ] [- p + 3*p - 4*p + 3*p - 1 p - 2*p + 3*p - 3*p + 1 ] [---------------------------- -----------------------------] [ 4 3 2 5 4 3 2 ] [ p + 3*p - 8*p + 8*p - 3 p + 3*p - 8*p + 8*p - 3*p] [ ] [ 4 3 2 3 2 ] [ p - p - p + p 3*p - 6*p + 4*p - 1 ] [ -------------------------- -------------------------- ] [ 4 3 2 4 3 2 ] [ p + 3*p - 8*p + 8*p - 3 p + 3*p - 8*p + 8*p - 3 ] >>> pprint(F_2.sensitivity, use_unicode=False) [ 4 3 2 5 4 2 ] [p - 3*p + 2*p + p - 1 p - 2*p + 3*p - 3*p + 1] [------------------------ --------------------------] [ 4 3 5 4 2 ] [ p - 3*p + 2*p - 1 p - 3*p + 2*p - p ] [ ] [ 4 3 2 4 3 ] [ p - p - p + p 2*p - 3*p + 2*p - 1 ] [ ------------------- --------------------- ] [ 4 3 4 3 ] [ p - 3*p + 2*p - 1 p - 3*p + 2*p - 1 ] """ _sys1_mat = self.sys1.doit()._expr_mat _sys2_mat = self.sys2.doit()._expr_mat return (eye(self.sys1.num_inputs) - \ self.sign*_sys1_mat*_sys2_mat).inv() def doit(self, cancel=True, expand=False, **kwargs): r""" Returns the resultant transfer function matrix obtained by the feedback interconnection. Examples ======== >>> from sympy import pprint >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, MIMOFeedback >>> tf1 = TransferFunction(s, 1 - s, s) >>> tf2 = TransferFunction(1, s, s) >>> tf3 = TransferFunction(5, 1, s) >>> tf4 = TransferFunction(s - 1, s, s) >>> tf5 = TransferFunction(0, 1, s) >>> sys1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) >>> sys2 = TransferFunctionMatrix([[tf3, tf5], [tf5, tf5]]) >>> F_1 = MIMOFeedback(sys1, sys2, 1) >>> pprint(F_1, use_unicode=False) / [ s 1 ] [5 0] \-1 [ s 1 ] | [----- - ] [- -] | [----- - ] | [1 - s s ] [1 1] | [1 - s s ] |I - [ ] *[ ] | * [ ] | [ 5 s - 1] [0 0] | [ 5 s - 1] | [ - -----] [- -] | [ - -----] \ [ 1 s ]{t} [1 1]{t}/ [ 1 s ]{t} >>> pprint(F_1.doit(), use_unicode=False) [ -s 1 - s ] [ ------- ----------- ] [ 6*s - 1 s*(1 - 6*s) ] [ ] [25*s*(s - 1) + 5*(1 - s)*(6*s - 1) (s - 1)*(6*s + 24)] [---------------------------------- ------------------] [ (1 - s)*(6*s - 1) s*(6*s - 1) ]{t} If the user wants the resultant ``TransferFunctionMatrix`` object without canceling the common factors then the ``cancel`` kwarg should be passed ``False``. >>> pprint(F_1.doit(cancel=False), use_unicode=False) [ 25*s*(1 - s) 25 - 25*s ] [ -------------------- -------------- ] [ 25*(1 - 6*s)*(1 - s) 25*s*(1 - 6*s) ] [ ] [s*(25*s - 25) + 5*(1 - s)*(6*s - 1) s*(s - 1)*(6*s - 1) + s*(25*s - 25)] [----------------------------------- -----------------------------------] [ (1 - s)*(6*s - 1) 2 ] [ s *(6*s - 1) ]{t} If the user wants the expanded form of the resultant transfer function matrix, the ``expand`` kwarg should be passed as ``True``. >>> pprint(F_1.doit(expand=True), use_unicode=False) [ -s 1 - s ] [ ------- ---------- ] [ 6*s - 1 2 ] [ - 6*s + s ] [ ] [ 2 2 ] [- 5*s + 10*s - 5 6*s + 18*s - 24] [----------------- ----------------] [ 2 2 ] [ - 6*s + 7*s - 1 6*s - s ]{t} """ _mat = self.sensitivity * self.sys1.doit()._expr_mat _resultant_tfm = _to_TFM(_mat, self.var) if cancel: _resultant_tfm = _resultant_tfm.simplify() if expand: _resultant_tfm = _resultant_tfm.expand() return _resultant_tfm def _eval_rewrite_as_TransferFunctionMatrix(self, sys1, sys2, sign, **kwargs): return self.doit() def __neg__(self): return MIMOFeedback(-self.sys1, -self.sys2, self.sign) def _to_TFM(mat, var): """Private method to convert ImmutableMatrix to TransferFunctionMatrix efficiently""" to_tf = lambda expr: TransferFunction.from_rational_expression(expr, var) arg = [[to_tf(expr) for expr in row] for row in mat.tolist()] return TransferFunctionMatrix(arg) class TransferFunctionMatrix(MIMOLinearTimeInvariant): r""" A class for representing the MIMO (multiple-input and multiple-output) generalization of the SISO (single-input and single-output) transfer function. It is a matrix of transfer functions (``TransferFunction``, SISO-``Series`` or SISO-``Parallel``). There is only one argument, ``arg`` which is also the compulsory argument. ``arg`` is expected to be strictly of the type list of lists which holds the transfer functions or reducible to transfer functions. Parameters ========== arg : Nested ``List`` (strictly). Users are expected to input a nested list of ``TransferFunction``, ``Series`` and/or ``Parallel`` objects. Examples ======== .. note:: ``pprint()`` can be used for better visualization of ``TransferFunctionMatrix`` objects. >>> from sympy.abc import s, p, a >>> from sympy import pprint >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, Series, Parallel >>> tf_1 = TransferFunction(s + a, s**2 + s + 1, s) >>> tf_2 = TransferFunction(p**4 - 3*p + 2, s + p, s) >>> tf_3 = TransferFunction(3, s + 2, s) >>> tf_4 = TransferFunction(-a + p, 9*s - 9, s) >>> tfm_1 = TransferFunctionMatrix([[tf_1], [tf_2], [tf_3]]) >>> tfm_1 TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(3, s + 2, s),))) >>> tfm_1.var s >>> tfm_1.num_inputs 1 >>> tfm_1.num_outputs 3 >>> tfm_1.shape (3, 1) >>> tfm_1.args (((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(3, s + 2, s),)),) >>> tfm_2 = TransferFunctionMatrix([[tf_1, -tf_3], [tf_2, -tf_1], [tf_3, -tf_2]]) >>> tfm_2 TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(p**4 - 3*p + 2, p + s, s), TransferFunction(-a - s, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)))) >>> pprint(tfm_2, use_unicode=False) # pretty-printing for better visualization [ a + s -3 ] [ ---------- ----- ] [ 2 s + 2 ] [ s + s + 1 ] [ ] [ 4 ] [p - 3*p + 2 -a - s ] [------------ ---------- ] [ p + s 2 ] [ s + s + 1 ] [ ] [ 4 ] [ 3 - p + 3*p - 2] [ ----- --------------] [ s + 2 p + s ]{t} TransferFunctionMatrix can be transposed, if user wants to switch the input and output transfer functions >>> tfm_2.transpose() TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(p**4 - 3*p + 2, p + s, s), TransferFunction(3, s + 2, s)), (TransferFunction(-3, s + 2, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)))) >>> pprint(_, use_unicode=False) [ 4 ] [ a + s p - 3*p + 2 3 ] [---------- ------------ ----- ] [ 2 p + s s + 2 ] [s + s + 1 ] [ ] [ 4 ] [ -3 -a - s - p + 3*p - 2] [ ----- ---------- --------------] [ s + 2 2 p + s ] [ s + s + 1 ]{t} >>> tf_5 = TransferFunction(5, s, s) >>> tf_6 = TransferFunction(5*s, (2 + s**2), s) >>> tf_7 = TransferFunction(5, (s*(2 + s**2)), s) >>> tf_8 = TransferFunction(5, 1, s) >>> tfm_3 = TransferFunctionMatrix([[tf_5, tf_6], [tf_7, tf_8]]) >>> tfm_3 TransferFunctionMatrix(((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)), (TransferFunction(5, s*(s**2 + 2), s), TransferFunction(5, 1, s)))) >>> pprint(tfm_3, use_unicode=False) [ 5 5*s ] [ - ------] [ s 2 ] [ s + 2] [ ] [ 5 5 ] [---------- - ] [ / 2 \ 1 ] [s*\s + 2/ ]{t} >>> tfm_3.var s >>> tfm_3.shape (2, 2) >>> tfm_3.num_outputs 2 >>> tfm_3.num_inputs 2 >>> tfm_3.args (((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)), (TransferFunction(5, s*(s**2 + 2), s), TransferFunction(5, 1, s))),) To access the ``TransferFunction`` at any index in the ``TransferFunctionMatrix``, use the index notation. >>> tfm_3[1, 0] # gives the TransferFunction present at 2nd Row and 1st Col. Similar to that in Matrix classes TransferFunction(5, s*(s**2 + 2), s) >>> tfm_3[0, 0] # gives the TransferFunction present at 1st Row and 1st Col. TransferFunction(5, s, s) >>> tfm_3[:, 0] # gives the first column TransferFunctionMatrix(((TransferFunction(5, s, s),), (TransferFunction(5, s*(s**2 + 2), s),))) >>> pprint(_, use_unicode=False) [ 5 ] [ - ] [ s ] [ ] [ 5 ] [----------] [ / 2 \] [s*\s + 2/]{t} >>> tfm_3[0, :] # gives the first row TransferFunctionMatrix(((TransferFunction(5, s, s), TransferFunction(5*s, s**2 + 2, s)),)) >>> pprint(_, use_unicode=False) [5 5*s ] [- ------] [s 2 ] [ s + 2]{t} To negate a transfer function matrix, ``-`` operator can be prepended: >>> tfm_4 = TransferFunctionMatrix([[tf_2], [-tf_1], [tf_3]]) >>> -tfm_4 TransferFunctionMatrix(((TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(-3, s + 2, s),))) >>> tfm_5 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, -tf_1]]) >>> -tfm_5 TransferFunctionMatrix(((TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(-p**4 + 3*p - 2, p + s, s)), (TransferFunction(-3, s + 2, s), TransferFunction(a + s, s**2 + s + 1, s)))) ``subs()`` returns the ``TransferFunctionMatrix`` object with the value substituted in the expression. This will not mutate your original ``TransferFunctionMatrix``. >>> tfm_2.subs(p, 2) # substituting p everywhere in tfm_2 with 2. TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(12, s + 2, s), TransferFunction(-a - s, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-12, s + 2, s)))) >>> pprint(_, use_unicode=False) [ a + s -3 ] [---------- ----- ] [ 2 s + 2 ] [s + s + 1 ] [ ] [ 12 -a - s ] [ ----- ----------] [ s + 2 2 ] [ s + s + 1] [ ] [ 3 -12 ] [ ----- ----- ] [ s + 2 s + 2 ]{t} >>> pprint(tfm_2, use_unicode=False) # State of tfm_2 is unchanged after substitution [ a + s -3 ] [ ---------- ----- ] [ 2 s + 2 ] [ s + s + 1 ] [ ] [ 4 ] [p - 3*p + 2 -a - s ] [------------ ---------- ] [ p + s 2 ] [ s + s + 1 ] [ ] [ 4 ] [ 3 - p + 3*p - 2] [ ----- --------------] [ s + 2 p + s ]{t} ``subs()`` also supports multiple substitutions. >>> tfm_2.subs({p: 2, a: 1}) # substituting p with 2 and a with 1 TransferFunctionMatrix(((TransferFunction(s + 1, s**2 + s + 1, s), TransferFunction(-3, s + 2, s)), (TransferFunction(12, s + 2, s), TransferFunction(-s - 1, s**2 + s + 1, s)), (TransferFunction(3, s + 2, s), TransferFunction(-12, s + 2, s)))) >>> pprint(_, use_unicode=False) [ s + 1 -3 ] [---------- ----- ] [ 2 s + 2 ] [s + s + 1 ] [ ] [ 12 -s - 1 ] [ ----- ----------] [ s + 2 2 ] [ s + s + 1] [ ] [ 3 -12 ] [ ----- ----- ] [ s + 2 s + 2 ]{t} Users can reduce the ``Series`` and ``Parallel`` elements of the matrix to ``TransferFunction`` by using ``doit()``. >>> tfm_6 = TransferFunctionMatrix([[Series(tf_3, tf_4), Parallel(tf_3, tf_4)]]) >>> tfm_6 TransferFunctionMatrix(((Series(TransferFunction(3, s + 2, s), TransferFunction(-a + p, 9*s - 9, s)), Parallel(TransferFunction(3, s + 2, s), TransferFunction(-a + p, 9*s - 9, s))),)) >>> pprint(tfm_6, use_unicode=False) [ -a + p 3 -a + p 3 ] [-------*----- ------- + -----] [9*s - 9 s + 2 9*s - 9 s + 2]{t} >>> tfm_6.doit() TransferFunctionMatrix(((TransferFunction(-3*a + 3*p, (s + 2)*(9*s - 9), s), TransferFunction(27*s + (-a + p)*(s + 2) - 27, (s + 2)*(9*s - 9), s)),)) >>> pprint(_, use_unicode=False) [ -3*a + 3*p 27*s + (-a + p)*(s + 2) - 27] [----------------- ----------------------------] [(s + 2)*(9*s - 9) (s + 2)*(9*s - 9) ]{t} >>> tf_9 = TransferFunction(1, s, s) >>> tf_10 = TransferFunction(1, s**2, s) >>> tfm_7 = TransferFunctionMatrix([[Series(tf_9, tf_10), tf_9], [tf_10, Parallel(tf_9, tf_10)]]) >>> tfm_7 TransferFunctionMatrix(((Series(TransferFunction(1, s, s), TransferFunction(1, s**2, s)), TransferFunction(1, s, s)), (TransferFunction(1, s**2, s), Parallel(TransferFunction(1, s, s), TransferFunction(1, s**2, s))))) >>> pprint(tfm_7, use_unicode=False) [ 1 1 ] [---- - ] [ 2 s ] [s*s ] [ ] [ 1 1 1] [ -- -- + -] [ 2 2 s] [ s s ]{t} >>> tfm_7.doit() TransferFunctionMatrix(((TransferFunction(1, s**3, s), TransferFunction(1, s, s)), (TransferFunction(1, s**2, s), TransferFunction(s**2 + s, s**3, s)))) >>> pprint(_, use_unicode=False) [1 1 ] [-- - ] [ 3 s ] [s ] [ ] [ 2 ] [1 s + s] [-- ------] [ 2 3 ] [s s ]{t} Addition, subtraction, and multiplication of transfer function matrices can form unevaluated ``Series`` or ``Parallel`` objects. - For addition and subtraction: All the transfer function matrices must have the same shape. - For multiplication (C = A * B): The number of inputs of the first transfer function matrix (A) must be equal to the number of outputs of the second transfer function matrix (B). Also, use pretty-printing (``pprint``) to analyse better. >>> tfm_8 = TransferFunctionMatrix([[tf_3], [tf_2], [-tf_1]]) >>> tfm_9 = TransferFunctionMatrix([[-tf_3]]) >>> tfm_10 = TransferFunctionMatrix([[tf_1], [tf_2], [tf_4]]) >>> tfm_11 = TransferFunctionMatrix([[tf_4], [-tf_1]]) >>> tfm_12 = TransferFunctionMatrix([[tf_4, -tf_1, tf_3], [-tf_2, -tf_4, -tf_3]]) >>> tfm_8 + tfm_10 MIMOParallel(TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a + p, 9*s - 9, s),)))) >>> pprint(_, use_unicode=False) [ 3 ] [ a + s ] [ ----- ] [ ---------- ] [ s + 2 ] [ 2 ] [ ] [ s + s + 1 ] [ 4 ] [ ] [p - 3*p + 2] [ 4 ] [------------] + [p - 3*p + 2] [ p + s ] [------------] [ ] [ p + s ] [ -a - s ] [ ] [ ---------- ] [ -a + p ] [ 2 ] [ ------- ] [ s + s + 1 ]{t} [ 9*s - 9 ]{t} >>> -tfm_10 - tfm_8 MIMOParallel(TransferFunctionMatrix(((TransferFunction(-a - s, s**2 + s + 1, s),), (TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a - p, 9*s - 9, s),))), TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),), (TransferFunction(-p**4 + 3*p - 2, p + s, s),), (TransferFunction(a + s, s**2 + s + 1, s),)))) >>> pprint(_, use_unicode=False) [ -a - s ] [ -3 ] [ ---------- ] [ ----- ] [ 2 ] [ s + 2 ] [ s + s + 1 ] [ ] [ ] [ 4 ] [ 4 ] [- p + 3*p - 2] [- p + 3*p - 2] + [--------------] [--------------] [ p + s ] [ p + s ] [ ] [ ] [ a + s ] [ a - p ] [ ---------- ] [ ------- ] [ 2 ] [ 9*s - 9 ]{t} [ s + s + 1 ]{t} >>> tfm_12 * tfm_8 MIMOSeries(TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(-a + p, 9*s - 9, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(3, s + 2, s)), (TransferFunction(-p**4 + 3*p - 2, p + s, s), TransferFunction(a - p, 9*s - 9, s), TransferFunction(-3, s + 2, s))))) >>> pprint(_, use_unicode=False) [ 3 ] [ ----- ] [ -a + p -a - s 3 ] [ s + 2 ] [ ------- ---------- -----] [ ] [ 9*s - 9 2 s + 2] [ 4 ] [ s + s + 1 ] [p - 3*p + 2] [ ] *[------------] [ 4 ] [ p + s ] [- p + 3*p - 2 a - p -3 ] [ ] [-------------- ------- -----] [ -a - s ] [ p + s 9*s - 9 s + 2]{t} [ ---------- ] [ 2 ] [ s + s + 1 ]{t} >>> tfm_12 * tfm_8 * tfm_9 MIMOSeries(TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),),)), TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))), TransferFunctionMatrix(((TransferFunction(-a + p, 9*s - 9, s), TransferFunction(-a - s, s**2 + s + 1, s), TransferFunction(3, s + 2, s)), (TransferFunction(-p**4 + 3*p - 2, p + s, s), TransferFunction(a - p, 9*s - 9, s), TransferFunction(-3, s + 2, s))))) >>> pprint(_, use_unicode=False) [ 3 ] [ ----- ] [ -a + p -a - s 3 ] [ s + 2 ] [ ------- ---------- -----] [ ] [ 9*s - 9 2 s + 2] [ 4 ] [ s + s + 1 ] [p - 3*p + 2] [ -3 ] [ ] *[------------] *[-----] [ 4 ] [ p + s ] [s + 2]{t} [- p + 3*p - 2 a - p -3 ] [ ] [-------------- ------- -----] [ -a - s ] [ p + s 9*s - 9 s + 2]{t} [ ---------- ] [ 2 ] [ s + s + 1 ]{t} >>> tfm_10 + tfm_8*tfm_9 MIMOParallel(TransferFunctionMatrix(((TransferFunction(a + s, s**2 + s + 1, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a + p, 9*s - 9, s),))), MIMOSeries(TransferFunctionMatrix(((TransferFunction(-3, s + 2, s),),)), TransferFunctionMatrix(((TransferFunction(3, s + 2, s),), (TransferFunction(p**4 - 3*p + 2, p + s, s),), (TransferFunction(-a - s, s**2 + s + 1, s),))))) >>> pprint(_, use_unicode=False) [ a + s ] [ 3 ] [ ---------- ] [ ----- ] [ 2 ] [ s + 2 ] [ s + s + 1 ] [ ] [ ] [ 4 ] [ 4 ] [p - 3*p + 2] [ -3 ] [p - 3*p + 2] + [------------] *[-----] [------------] [ p + s ] [s + 2]{t} [ p + s ] [ ] [ ] [ -a - s ] [ -a + p ] [ ---------- ] [ ------- ] [ 2 ] [ 9*s - 9 ]{t} [ s + s + 1 ]{t} These unevaluated ``Series`` or ``Parallel`` objects can convert into the resultant transfer function matrix using ``.doit()`` method or by ``.rewrite(TransferFunctionMatrix)``. >>> (-tfm_8 + tfm_10 + tfm_8*tfm_9).doit() TransferFunctionMatrix(((TransferFunction((a + s)*(s + 2)**3 - 3*(s + 2)**2*(s**2 + s + 1) - 9*(s + 2)*(s**2 + s + 1), (s + 2)**3*(s**2 + s + 1), s),), (TransferFunction((p + s)*(-3*p**4 + 9*p - 6), (p + s)**2*(s + 2), s),), (TransferFunction((-a + p)*(s + 2)*(s**2 + s + 1)**2 + (a + s)*(s + 2)*(9*s - 9)*(s**2 + s + 1) + (3*a + 3*s)*(9*s - 9)*(s**2 + s + 1), (s + 2)*(9*s - 9)*(s**2 + s + 1)**2, s),))) >>> (-tfm_12 * -tfm_8 * -tfm_9).rewrite(TransferFunctionMatrix) TransferFunctionMatrix(((TransferFunction(3*(-3*a + 3*p)*(p + s)*(s + 2)*(s**2 + s + 1)**2 + 3*(-3*a - 3*s)*(p + s)*(s + 2)*(9*s - 9)*(s**2 + s + 1) + 3*(a + s)*(s + 2)**2*(9*s - 9)*(-p**4 + 3*p - 2)*(s**2 + s + 1), (p + s)*(s + 2)**3*(9*s - 9)*(s**2 + s + 1)**2, s),), (TransferFunction(3*(-a + p)*(p + s)*(s + 2)**2*(-p**4 + 3*p - 2)*(s**2 + s + 1) + 3*(3*a + 3*s)*(p + s)**2*(s + 2)*(9*s - 9) + 3*(p + s)*(s + 2)*(9*s - 9)*(-3*p**4 + 9*p - 6)*(s**2 + s + 1), (p + s)**2*(s + 2)**3*(9*s - 9)*(s**2 + s + 1), s),))) See Also ======== TransferFunction, MIMOSeries, MIMOParallel, Feedback """ def __new__(cls, arg): expr_mat_arg = [] try: var = arg[0][0].var except TypeError: raise ValueError("`arg` param in TransferFunctionMatrix should " "strictly be a nested list containing TransferFunction objects.") for row_index, row in enumerate(arg): temp = [] for col_index, element in enumerate(row): if not isinstance(element, SISOLinearTimeInvariant): raise TypeError("Each element is expected to be of type `SISOLinearTimeInvariant`.") if var != element.var: raise ValueError("Conflicting value(s) found for `var`. All TransferFunction instances in " "TransferFunctionMatrix should use the same complex variable in Laplace domain.") temp.append(element.to_expr()) expr_mat_arg.append(temp) if isinstance(arg, (list, Tuple)): # Making nested Tuple (sympy.core.containers.Tuple) from nested list or nested python tuple arg = Tuple(*(Tuple(*r, sympify=False) for r in arg), sympify=False) obj = super(TransferFunctionMatrix, cls).__new__(cls, arg) obj._expr_mat = ImmutableMatrix(expr_mat_arg) return obj @classmethod def from_Matrix(cls, matrix, var): """ Creates a new ``TransferFunctionMatrix`` efficiently from a SymPy Matrix of ``Expr`` objects. Parameters ========== matrix : ``ImmutableMatrix`` having ``Expr``/``Number`` elements. var : Symbol Complex variable of the Laplace transform which will be used by the all the ``TransferFunction`` objects in the ``TransferFunctionMatrix``. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunctionMatrix >>> from sympy import Matrix, pprint >>> M = Matrix([[s, 1/s], [1/(s+1), s]]) >>> M_tf = TransferFunctionMatrix.from_Matrix(M, s) >>> pprint(M_tf, use_unicode=False) [ s 1] [ - -] [ 1 s] [ ] [ 1 s] [----- -] [s + 1 1]{t} >>> M_tf.elem_poles() [[[], [0]], [[-1], []]] >>> M_tf.elem_zeros() [[[0], []], [[], [0]]] """ return _to_TFM(matrix, var) @property def var(self): """ Returns the complex variable used by all the transfer functions or ``Series``/``Parallel`` objects in a transfer function matrix. Examples ======== >>> from sympy.abc import p, s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix, Series, Parallel >>> G1 = TransferFunction(p**2 + 2*p + 4, p - 6, p) >>> G2 = TransferFunction(p, 4 - p, p) >>> G3 = TransferFunction(0, p**4 - 1, p) >>> G4 = TransferFunction(s + 1, s**2 + s + 1, s) >>> S1 = Series(G1, G2) >>> S2 = Series(-G3, Parallel(G2, -G1)) >>> tfm1 = TransferFunctionMatrix([[G1], [G2], [G3]]) >>> tfm1.var p >>> tfm2 = TransferFunctionMatrix([[-S1, -S2], [S1, S2]]) >>> tfm2.var p >>> tfm3 = TransferFunctionMatrix([[G4]]) >>> tfm3.var s """ return self.args[0][0][0].var @property def num_inputs(self): """ Returns the number of inputs of the system. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> G1 = TransferFunction(s + 3, s**2 - 3, s) >>> G2 = TransferFunction(4, s**2, s) >>> G3 = TransferFunction(p**2 + s**2, p - 3, s) >>> tfm_1 = TransferFunctionMatrix([[G2, -G1, G3], [-G2, -G1, -G3]]) >>> tfm_1.num_inputs 3 See Also ======== num_outputs """ return self._expr_mat.shape[1] @property def num_outputs(self): """ Returns the number of outputs of the system. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunctionMatrix >>> from sympy import Matrix >>> M_1 = Matrix([[s], [1/s]]) >>> TFM = TransferFunctionMatrix.from_Matrix(M_1, s) >>> print(TFM) TransferFunctionMatrix(((TransferFunction(s, 1, s),), (TransferFunction(1, s, s),))) >>> TFM.num_outputs 2 See Also ======== num_inputs """ return self._expr_mat.shape[0] @property def shape(self): """ Returns the shape of the transfer function matrix, that is, ``(# of outputs, # of inputs)``. Examples ======== >>> from sympy.abc import s, p >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> tf1 = TransferFunction(p**2 - 1, s**4 + s**3 - p, p) >>> tf2 = TransferFunction(1 - p, p**2 - 3*p + 7, p) >>> tf3 = TransferFunction(3, 4, p) >>> tfm1 = TransferFunctionMatrix([[tf1, -tf2]]) >>> tfm1.shape (1, 2) >>> tfm2 = TransferFunctionMatrix([[-tf2, tf3], [tf1, -tf1]]) >>> tfm2.shape (2, 2) """ return self._expr_mat.shape def __neg__(self): neg = -self._expr_mat return _to_TFM(neg, self.var) @_check_other_MIMO def __add__(self, other): if not isinstance(other, MIMOParallel): return MIMOParallel(self, other) other_arg_list = list(other.args) return MIMOParallel(self, *other_arg_list) @_check_other_MIMO def __sub__(self, other): return self + (-other) @_check_other_MIMO def __mul__(self, other): if not isinstance(other, MIMOSeries): return MIMOSeries(other, self) other_arg_list = list(other.args) return MIMOSeries(*other_arg_list, self) def __getitem__(self, key): trunc = self._expr_mat.__getitem__(key) if isinstance(trunc, ImmutableMatrix): return _to_TFM(trunc, self.var) return TransferFunction.from_rational_expression(trunc, self.var) def transpose(self): """Returns the transpose of the ``TransferFunctionMatrix`` (switched input and output layers).""" transposed_mat = self._expr_mat.transpose() return _to_TFM(transposed_mat, self.var) def elem_poles(self): """ Returns the poles of each element of the ``TransferFunctionMatrix``. .. note:: Actual poles of a MIMO system are NOT the poles of individual elements. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> tf_1 = TransferFunction(3, (s + 1), s) >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) >>> tf_4 = TransferFunction(s + 2, s**2 + 5*s - 10, s) >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) >>> tfm_1 TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s + 2, s**2 + 5*s - 10, s)))) >>> tfm_1.elem_poles() [[[-1], [-2, -1]], [[-2, -1], [-5/2 + sqrt(65)/2, -sqrt(65)/2 - 5/2]]] See Also ======== elem_zeros """ return [[element.poles() for element in row] for row in self.doit().args[0]] def elem_zeros(self): """ Returns the zeros of each element of the ``TransferFunctionMatrix``. .. note:: Actual zeros of a MIMO system are NOT the zeros of individual elements. Examples ======== >>> from sympy.abc import s >>> from sympy.physics.control.lti import TransferFunction, TransferFunctionMatrix >>> tf_1 = TransferFunction(3, (s + 1), s) >>> tf_2 = TransferFunction(s + 6, (s + 1)*(s + 2), s) >>> tf_3 = TransferFunction(s + 3, s**2 + 3*s + 2, s) >>> tf_4 = TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s) >>> tfm_1 = TransferFunctionMatrix([[tf_1, tf_2], [tf_3, tf_4]]) >>> tfm_1 TransferFunctionMatrix(((TransferFunction(3, s + 1, s), TransferFunction(s + 6, (s + 1)*(s + 2), s)), (TransferFunction(s + 3, s**2 + 3*s + 2, s), TransferFunction(s**2 - 9*s + 20, s**2 + 5*s - 10, s)))) >>> tfm_1.elem_zeros() [[[], [-6]], [[-3], [4, 5]]] See Also ======== elem_poles """ return [[element.zeros() for element in row] for row in self.doit().args[0]] def _flat(self): """Returns flattened list of args in TransferFunctionMatrix""" return [elem for tup in self.args[0] for elem in tup] def _eval_evalf(self, prec): """Calls evalf() on each transfer function in the transfer function matrix""" mat = self._expr_mat.applyfunc(lambda a: a.evalf(n=prec_to_dps(prec))) return _to_TFM(mat, self.var) def _eval_simplify(self, **kwargs): """Simplifies the transfer function matrix""" simp_mat = self._expr_mat.applyfunc(lambda a: cancel(a, expand=False)) return _to_TFM(simp_mat, self.var) def expand(self, **hints): """Expands the transfer function matrix""" expand_mat = self._expr_mat.expand(**hints) return _to_TFM(expand_mat, self.var) sympy-sympy-1.9/sympy/physics/control/tests/000077500000000000000000000000001412543434000214105ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/control/tests/__init__.py000066400000000000000000000000001412543434000235070ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/control/tests/test_control_plots.py000066400000000000000000000363251412543434000257330ustar00rootroot00000000000000from sympy import Dummy, arg, I, Abs, log from sympy.abc import s, p, a from sympy.external import import_module from sympy.physics.control.control_plots import \ (pole_zero_numerical_data, pole_zero_plot, step_response_numerical_data, step_response_plot, impulse_response_numerical_data, impulse_response_plot, ramp_response_numerical_data, ramp_response_plot, bode_magnitude_numerical_data, bode_phase_numerical_data, bode_plot) from sympy.physics.control.lti import (TransferFunction, Series, Parallel, TransferFunctionMatrix) from sympy.testing.pytest import raises, skip matplotlib = import_module( 'matplotlib', import_kwargs={'fromlist': ['pyplot']}, catch=(RuntimeError,)) numpy = import_module('numpy') tf1 = TransferFunction(1, p**2 + 0.5*p + 2, p) tf2 = TransferFunction(p, 6*p**2 + 3*p + 1, p) tf3 = TransferFunction(p, p**3 - 1, p) tf4 = TransferFunction(10, p**3, p) tf5 = TransferFunction(5, s**2 + 2*s + 10, s) tf6 = TransferFunction(1, 1, s) tf7 = TransferFunction(4*s*3 + 9*s**2 + 0.1*s + 11, 8*s**6 + 9*s**4 + 11, s) ser1 = Series(tf4, TransferFunction(1, p - 5, p)) ser2 = Series(tf3, TransferFunction(p, p + 2, p)) par1 = Parallel(tf1, tf2) par2 = Parallel(tf1, tf2, tf3) def _to_tuple(a, b): return tuple(a), tuple(b) def _trim_tuple(a, b): a, b = _to_tuple(a, b) return tuple(a[0: 2] + a[len(a)//2 : len(a)//2 + 1] + a[-2:]), \ tuple(b[0: 2] + b[len(b)//2 : len(b)//2 + 1] + b[-2:]) def y_coordinate_equality(plot_data_func, evalf_func, system): """Checks whether the y-coordinate value of the plotted data point is equal to the value of the function at a particular x.""" x, y = plot_data_func(system) x, y = _trim_tuple(x, y) y_exp = tuple(evalf_func(system, x_i) for x_i in x) return all(Abs(y_exp_i - y_i) < 1e-8 for y_exp_i, y_i in zip(y_exp, y)) def test_errors(): if not matplotlib: skip("Matplotlib not the default backend") # Invalid `system` check tfm = TransferFunctionMatrix([[tf6, tf5], [tf5, tf6]]) expr = 1/(s**2 - 1) raises(NotImplementedError, lambda: pole_zero_plot(tfm)) raises(NotImplementedError, lambda: pole_zero_numerical_data(expr)) raises(NotImplementedError, lambda: impulse_response_plot(expr)) raises(NotImplementedError, lambda: impulse_response_numerical_data(tfm)) raises(NotImplementedError, lambda: step_response_plot(tfm)) raises(NotImplementedError, lambda: step_response_numerical_data(expr)) raises(NotImplementedError, lambda: ramp_response_plot(expr)) raises(NotImplementedError, lambda: ramp_response_numerical_data(tfm)) raises(NotImplementedError, lambda: bode_plot(tfm)) # More than 1 variables tf_a = TransferFunction(a, s + 1, s) raises(ValueError, lambda: pole_zero_plot(tf_a)) raises(ValueError, lambda: pole_zero_numerical_data(tf_a)) raises(ValueError, lambda: impulse_response_plot(tf_a)) raises(ValueError, lambda: impulse_response_numerical_data(tf_a)) raises(ValueError, lambda: step_response_plot(tf_a)) raises(ValueError, lambda: step_response_numerical_data(tf_a)) raises(ValueError, lambda: ramp_response_plot(tf_a)) raises(ValueError, lambda: ramp_response_numerical_data(tf_a)) raises(ValueError, lambda: bode_plot(tf_a)) # lower_limit > 0 for response plots raises(ValueError, lambda: impulse_response_plot(tf1, lower_limit=-1)) raises(ValueError, lambda: step_response_plot(tf1, lower_limit=-0.1)) raises(ValueError, lambda: ramp_response_plot(tf1, lower_limit=-4/3)) # slope in ramp_response_plot() is negative raises(ValueError, lambda: ramp_response_plot(tf1, slope=-0.1)) def test_pole_zero(): if not matplotlib: skip("Matplotlib not the default backend") assert _to_tuple(*pole_zero_numerical_data(tf1)) == \ ((), ((-0.24999999999999994+1.3919410907075054j), (-0.24999999999999994-1.3919410907075054j))) assert _to_tuple(*pole_zero_numerical_data(tf2)) == \ ((0.0,), ((-0.25+0.3227486121839514j), (-0.25-0.3227486121839514j))) assert _to_tuple(*pole_zero_numerical_data(tf3)) == \ ((0.0,), ((-0.5000000000000004+0.8660254037844395j), (-0.5000000000000004-0.8660254037844395j), (0.9999999999999998+0j))) assert _to_tuple(*pole_zero_numerical_data(tf7)) == \ (((-0.6722222222222222+0.8776898690157247j), (-0.6722222222222222-0.8776898690157247j)), ((2.220446049250313e-16+1.2797182176061541j), (2.220446049250313e-16-1.2797182176061541j), (-0.7657146670186428+0.5744385024099056j), (-0.7657146670186428-0.5744385024099056j), (0.7657146670186427+0.5744385024099052j), (0.7657146670186427-0.5744385024099052j))) assert _to_tuple(*pole_zero_numerical_data(ser1)) == \ ((), (5.0, 0.0, 0.0, 0.0)) assert _to_tuple(*pole_zero_numerical_data(par1)) == \ ((-5.645751311064592, -0.5000000000000008, -0.3542486889354093), ((-0.24999999999999986+1.3919410907075052j), (-0.24999999999999986-1.3919410907075052j), (-0.2499999999999998+0.32274861218395134j), (-0.2499999999999998-0.32274861218395134j))) def test_bode(): if not matplotlib: skip("Matplotlib not the default backend") def bode_phase_evalf(system, point): expr = system.to_expr() _w = Dummy("w", real=True) w_expr = expr.subs({system.var: I*_w}) return arg(w_expr).subs({_w: point}).evalf() def bode_mag_evalf(system, point): expr = system.to_expr() _w = Dummy("w", real=True) w_expr = expr.subs({system.var: I*_w}) return 20*log(Abs(w_expr), 10).subs({_w: point}).evalf() def test_bode_data(sys): return y_coordinate_equality(bode_magnitude_numerical_data, bode_mag_evalf, sys) \ and y_coordinate_equality(bode_phase_numerical_data, bode_phase_evalf, sys) assert test_bode_data(tf1) assert test_bode_data(tf2) assert test_bode_data(tf3) assert test_bode_data(tf4) assert test_bode_data(tf5) def check_point_accuracy(a, b): return all(Abs(a_i - b_i) < 1e-12 for \ a_i, b_i in zip(a, b)) def test_impulse_response(): if not matplotlib: skip("Matplotlib not the default backend") def impulse_res_tester(sys, expected_value): x, y = _to_tuple(*impulse_response_numerical_data(sys, adaptive=False, nb_of_points=10)) x_check = check_point_accuracy(x, expected_value[0]) y_check = check_point_accuracy(y, expected_value[1]) return x_check and y_check exp1 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 0.544019738507865, 0.01993849743234938, -0.31140243360893216, -0.022852779906491996, 0.1778306498155759, 0.01962941084328499, -0.1013115194573652, -0.014975541213105696, 0.0575789724730714)) exp2 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.1666666675, 0.08389223412935855, 0.02338051973475047, -0.014966807776379383, -0.034645954223054234, -0.040560075735512804, -0.037658628907103885, -0.030149507719590022, -0.021162090730736834, -0.012721292737437523)) exp3 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (4.369893391586999e-09, 1.1750333000630964, 3.2922404058312473, 9.432290008148343, 28.37098083007151, 86.18577464367974, 261.90356653762115, 795.6538758627842, 2416.9920942096983, 7342.159505206647)) exp4 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 6.17283950617284, 24.69135802469136, 55.555555555555564, 98.76543209876544, 154.320987654321, 222.22222222222226, 302.46913580246917, 395.0617283950618, 500.0)) exp5 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, -0.10455606138085417, 0.06757671513476461, -0.03234567568833768, 0.013582514927757873, -0.005273419510705473, 0.0019364083003354075, -0.000680070134067832, 0.00022969845960406913, -7.476094359583917e-05)) exp6 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (-6.016699583000218e-09, 0.35039802056107394, 3.3728423827689884, 12.119846079276684, 25.86101014293389, 29.352480635282088, -30.49475907497664, -273.8717189554019, -863.2381702029659, -1747.0262164682233)) exp7 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 18.934638095560974, 5346.93244680907, 1384609.8718249386, 358161126.65801865, 92645770015.70108, 23964739753087.42, 6198974342083139.0, 1.603492601616059e+18, 4.147764422869658e+20)) assert impulse_res_tester(tf1, exp1) assert impulse_res_tester(tf2, exp2) assert impulse_res_tester(tf3, exp3) assert impulse_res_tester(tf4, exp4) assert impulse_res_tester(tf5, exp5) assert impulse_res_tester(tf7, exp6) assert impulse_res_tester(ser1, exp7) def test_step_response(): if not matplotlib: skip("Matplotlib not the default backend") def step_res_tester(sys, expected_value): x, y = _to_tuple(*step_response_numerical_data(sys, adaptive=False, nb_of_points=10)) x_check = check_point_accuracy(x, expected_value[0]) y_check = check_point_accuracy(y, expected_value[1]) return x_check and y_check exp1 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (-1.9193285738516863e-08, 0.42283495488246126, 0.7840485977945262, 0.5546841805655717, 0.33903033806932087, 0.4627251747410237, 0.5909907598988051, 0.5247213989553071, 0.4486997874319281, 0.4839358435839171)) exp2 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 0.13728409095645816, 0.19474559355325086, 0.1974909129243011, 0.16841657696573073, 0.12559777736159378, 0.08153828016664713, 0.04360471317348958, 0.015072994568868221, -0.003636420058445484)) exp3 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 0.6314542141914303, 2.9356520038101035, 9.37731009663807, 28.452300356688376, 86.25721933273988, 261.9236645044672, 795.6435410577224, 2416.9786984578764, 7342.154119725917)) exp4 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 2.286236899862826, 18.28989519890261, 61.72839629629631, 146.31916159122088, 285.7796124828532, 493.8271703703705, 784.1792566529494, 1170.553292729767, 1666.6667)) exp5 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (-3.999999997894577e-09, 0.6720357068882895, 0.4429938256137113, 0.5182010838004518, 0.4944139147159695, 0.5016379853883338, 0.4995466896527733, 0.5001154784851325, 0.49997448824584123, 0.5000039745919259)) exp6 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (-1.5433688493882158e-09, 0.3428705539937336, 1.1253619102202777, 3.1849962651016517, 9.47532757182671, 28.727231099148135, 87.29426924860557, 265.2138681048606, 805.6636260007757, 2447.387582370878)) assert step_res_tester(tf1, exp1) assert step_res_tester(tf2, exp2) assert step_res_tester(tf3, exp3) assert step_res_tester(tf4, exp4) assert step_res_tester(tf5, exp5) assert step_res_tester(ser2, exp6) def test_ramp_response(): if not matplotlib: skip("Matplotlib not the default backend") def ramp_res_tester(sys, num_points, expected_value, slope=1): x, y = _to_tuple(*ramp_response_numerical_data(sys, slope=slope, adaptive=False, nb_of_points=num_points)) x_check = check_point_accuracy(x, expected_value[0]) y_check = check_point_accuracy(y, expected_value[1]) return x_check and y_check exp1 = ((0.0, 2.0, 4.0, 6.0, 8.0, 10.0), (0.0, 0.7324667795033895, 1.9909720978650398, 2.7956587704217783, 3.9224897567931514, 4.85022655284895)) exp2 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (2.4360213402019326e-08, 0.10175320182493253, 0.33057612497658406, 0.5967937263298935, 0.8431511866718248, 1.0398805391471613, 1.1776043125035738, 1.2600994825747305, 1.2981042689274653, 1.304684417610106)) exp3 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (-3.9329040468771836e-08, 0.34686634635794555, 2.9998828170537903, 12.33303690737476, 40.993913948137795, 127.84145222317912, 391.41713691996, 1192.0006858708389, 3623.9808672503405, 11011.728034546572)) exp4 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 1.9051973784484078, 30.483158055174524, 154.32098765432104, 487.7305288827924, 1190.7483615302544, 2469.1358024691367, 4574.3789056546275, 7803.688462124678, 12500.0)) exp5 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 3.8844361856975635, 9.141792069209865, 14.096349157657231, 19.09783068994694, 24.10179770390321, 29.09907319114121, 34.10040420185154, 39.09983919254265, 44.10006013058409)) exp6 = ((0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0), (0.0, 1.1111111111111112, 2.2222222222222223, 3.3333333333333335, 4.444444444444445, 5.555555555555555, 6.666666666666667, 7.777777777777779, 8.88888888888889, 10.0)) assert ramp_res_tester(tf1, 6, exp1) assert ramp_res_tester(tf2, 10, exp2, 1.2) assert ramp_res_tester(tf3, 10, exp3, 1.5) assert ramp_res_tester(tf4, 10, exp4, 3) assert ramp_res_tester(tf5, 10, exp5, 9) assert ramp_res_tester(tf6, 10, exp6) sympy-sympy-1.9/sympy/physics/control/tests/test_lti.py000066400000000000000000001621251412543434000236200ustar00rootroot00000000000000from sympy import (symbols, factor, Function, simplify, exp, oo, I, S, Mul, Pow, Add, Rational, sqrt, CRootOf, eye) from sympy.core.containers import Tuple from sympy.matrices import ImmutableMatrix, Matrix from sympy.physics.control import (TransferFunction, Series, Parallel, Feedback, TransferFunctionMatrix, MIMOSeries, MIMOParallel, MIMOFeedback) from sympy.testing.pytest import raises a, x, b, s, g, d, p, k, a0, a1, a2, b0, b1, b2, tau, zeta, wn = symbols('a, x, b, s, g, d, p, k,\ a0:3, b0:3, tau, zeta, wn') TF1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) TF2 = TransferFunction(k, 1, s) TF3 = TransferFunction(a2*p - s, a2*s + p, s) def test_TransferFunction_construction(): tf = TransferFunction(s + 1, s**2 + s + 1, s) assert tf.num == (s + 1) assert tf.den == (s**2 + s + 1) assert tf.args == (s + 1, s**2 + s + 1, s) tf1 = TransferFunction(s + 4, s - 5, s) assert tf1.num == (s + 4) assert tf1.den == (s - 5) assert tf1.args == (s + 4, s - 5, s) # using different polynomial variables. tf2 = TransferFunction(p + 3, p**2 - 9, p) assert tf2.num == (p + 3) assert tf2.den == (p**2 - 9) assert tf2.args == (p + 3, p**2 - 9, p) tf3 = TransferFunction(p**3 + 5*p**2 + 4, p**4 + 3*p + 1, p) assert tf3.args == (p**3 + 5*p**2 + 4, p**4 + 3*p + 1, p) # no pole-zero cancellation on its own. tf4 = TransferFunction((s + 3)*(s - 1), (s - 1)*(s + 5), s) assert tf4.den == (s - 1)*(s + 5) assert tf4.args == ((s + 3)*(s - 1), (s - 1)*(s + 5), s) tf4_ = TransferFunction(p + 2, p + 2, p) assert tf4_.args == (p + 2, p + 2, p) tf5 = TransferFunction(s - 1, 4 - p, s) assert tf5.args == (s - 1, 4 - p, s) tf5_ = TransferFunction(s - 1, s - 1, s) assert tf5_.args == (s - 1, s - 1, s) tf6 = TransferFunction(5, 6, s) assert tf6.num == 5 assert tf6.den == 6 assert tf6.args == (5, 6, s) tf6_ = TransferFunction(1/2, 4, s) assert tf6_.num == 0.5 assert tf6_.den == 4 assert tf6_.args == (0.500000000000000, 4, s) tf7 = TransferFunction(3*s**2 + 2*p + 4*s, 8*p**2 + 7*s, s) tf8 = TransferFunction(3*s**2 + 2*p + 4*s, 8*p**2 + 7*s, p) assert not tf7 == tf8 tf7_ = TransferFunction(a0*s + a1*s**2 + a2*s**3, b0*p - b1*s, s) tf8_ = TransferFunction(a0*s + a1*s**2 + a2*s**3, b0*p - b1*s, s) assert tf7_ == tf8_ assert -(-tf7_) == tf7_ == -(-(-(-tf7_))) tf9 = TransferFunction(a*s**3 + b*s**2 + g*s + d, d*p + g*p**2 + g*s, s) assert tf9.args == (a*s**3 + b*s**2 + d + g*s, d*p + g*p**2 + g*s, s) tf10 = TransferFunction(p**3 + d, g*s**2 + d*s + a, p) tf10_ = TransferFunction(p**3 + d, g*s**2 + d*s + a, p) assert tf10.args == (d + p**3, a + d*s + g*s**2, p) assert tf10_ == tf10 tf11 = TransferFunction(a1*s + a0, b2*s**2 + b1*s + b0, s) assert tf11.num == (a0 + a1*s) assert tf11.den == (b0 + b1*s + b2*s**2) assert tf11.args == (a0 + a1*s, b0 + b1*s + b2*s**2, s) # when just the numerator is 0, leave the denominator alone. tf12 = TransferFunction(0, p**2 - p + 1, p) assert tf12.args == (0, p**2 - p + 1, p) tf13 = TransferFunction(0, 1, s) assert tf13.args == (0, 1, s) # float exponents tf14 = TransferFunction(a0*s**0.5 + a2*s**0.6 - a1, a1*p**(-8.7), s) assert tf14.args == (a0*s**0.5 - a1 + a2*s**0.6, a1*p**(-8.7), s) tf15 = TransferFunction(a2**2*p**(1/4) + a1*s**(-4/5), a0*s - p, p) assert tf15.args == (a1*s**(-0.8) + a2**2*p**0.25, a0*s - p, p) omega_o, k_p, k_o, k_i = symbols('omega_o, k_p, k_o, k_i') tf18 = TransferFunction((k_p + k_o*s + k_i/s), s**2 + 2*omega_o*s + omega_o**2, s) assert tf18.num == k_i/s + k_o*s + k_p assert tf18.args == (k_i/s + k_o*s + k_p, omega_o**2 + 2*omega_o*s + s**2, s) # ValueError when denominator is zero. raises(ValueError, lambda: TransferFunction(4, 0, s)) raises(ValueError, lambda: TransferFunction(s, 0, s)) raises(ValueError, lambda: TransferFunction(0, 0, s)) raises(TypeError, lambda: TransferFunction(Matrix([1, 2, 3]), s, s)) raises(TypeError, lambda: TransferFunction(s**2 + 2*s - 1, s + 3, 3)) raises(TypeError, lambda: TransferFunction(p + 1, 5 - p, 4)) raises(TypeError, lambda: TransferFunction(3, 4, 8)) def test_TransferFunction_functions(): # classmethod from_rational_expression expr_1 = Mul(0, Pow(s, -1, evaluate=False), evaluate=False) expr_2 = s/0 expr_3 = (p*s**2 + 5*s)/(s + 1)**3 expr_4 = 6 expr_5 = ((2 + 3*s)*(5 + 2*s))/((9 + 3*s)*(5 + 2*s**2)) expr_6 = (9*s**4 + 4*s**2 + 8)/((s + 1)*(s + 9)) tf = TransferFunction(s + 1, s**2 + 2, s) delay = exp(-s/tau) expr_7 = delay*tf.to_expr() H1 = TransferFunction.from_rational_expression(expr_7, s) H2 = TransferFunction(s + 1, (s**2 + 2)*exp(s/tau), s) expr_8 = Add(2, 3*s/(s**2 + 1), evaluate=False) assert TransferFunction.from_rational_expression(expr_1) == TransferFunction(0, s, s) raises(ZeroDivisionError, lambda: TransferFunction.from_rational_expression(expr_2)) raises(ValueError, lambda: TransferFunction.from_rational_expression(expr_3)) assert TransferFunction.from_rational_expression(expr_3, s) == TransferFunction((p*s**2 + 5*s), (s + 1)**3, s) assert TransferFunction.from_rational_expression(expr_3, p) == TransferFunction((p*s**2 + 5*s), (s + 1)**3, p) raises(ValueError, lambda: TransferFunction.from_rational_expression(expr_4)) assert TransferFunction.from_rational_expression(expr_4, s) == TransferFunction(6, 1, s) assert TransferFunction.from_rational_expression(expr_5, s) == \ TransferFunction((2 + 3*s)*(5 + 2*s), (9 + 3*s)*(5 + 2*s**2), s) assert TransferFunction.from_rational_expression(expr_6, s) == \ TransferFunction((9*s**4 + 4*s**2 + 8), (s + 1)*(s + 9), s) assert H1 == H2 assert TransferFunction.from_rational_expression(expr_8, s) == \ TransferFunction(2*s**2 + 3*s + 2, s**2 + 1, s) # explicitly cancel poles and zeros. tf0 = TransferFunction(s**5 + s**3 + s, s - s**2, s) a = TransferFunction(-(s**4 + s**2 + 1), s - 1, s) assert tf0.simplify() == simplify(tf0) == a tf1 = TransferFunction((p + 3)*(p - 1), (p - 1)*(p + 5), p) b = TransferFunction(p + 3, p + 5, p) assert tf1.simplify() == simplify(tf1) == b # expand the numerator and the denominator. G1 = TransferFunction((1 - s)**2, (s**2 + 1)**2, s) G2 = TransferFunction(1, -3, p) c = (a2*s**p + a1*s**s + a0*p**p)*(p**s + s**p) d = (b0*s**s + b1*p**s)*(b2*s*p + p**p) e = a0*p**p*p**s + a0*p**p*s**p + a1*p**s*s**s + a1*s**p*s**s + a2*p**s*s**p + a2*s**(2*p) f = b0*b2*p*s*s**s + b0*p**p*s**s + b1*b2*p*p**s*s + b1*p**p*p**s g = a1*a2*s*s**p + a1*p*s + a2*b1*p*s*s**p + b1*p**2*s G3 = TransferFunction(c, d, s) G4 = TransferFunction(a0*s**s - b0*p**p, (a1*s + b1*s*p)*(a2*s**p + p), p) assert G1.expand() == TransferFunction(s**2 - 2*s + 1, s**4 + 2*s**2 + 1, s) assert tf1.expand() == TransferFunction(p**2 + 2*p - 3, p**2 + 4*p - 5, p) assert G2.expand() == G2 assert G3.expand() == TransferFunction(e, f, s) assert G4.expand() == TransferFunction(a0*s**s - b0*p**p, g, p) # purely symbolic polynomials. p1 = a1*s + a0 p2 = b2*s**2 + b1*s + b0 SP1 = TransferFunction(p1, p2, s) expect1 = TransferFunction(2.0*s + 1.0, 5.0*s**2 + 4.0*s + 3.0, s) expect1_ = TransferFunction(2*s + 1, 5*s**2 + 4*s + 3, s) assert SP1.subs({a0: 1, a1: 2, b0: 3, b1: 4, b2: 5}) == expect1_ assert SP1.subs({a0: 1, a1: 2, b0: 3, b1: 4, b2: 5}).evalf() == expect1 assert expect1_.evalf() == expect1 c1, d0, d1, d2 = symbols('c1, d0:3') p3, p4 = c1*p, d2*p**3 + d1*p**2 - d0 SP2 = TransferFunction(p3, p4, p) expect2 = TransferFunction(2.0*p, 5.0*p**3 + 2.0*p**2 - 3.0, p) expect2_ = TransferFunction(2*p, 5*p**3 + 2*p**2 - 3, p) assert SP2.subs({c1: 2, d0: 3, d1: 2, d2: 5}) == expect2_ assert SP2.subs({c1: 2, d0: 3, d1: 2, d2: 5}).evalf() == expect2 assert expect2_.evalf() == expect2 SP3 = TransferFunction(a0*p**3 + a1*s**2 - b0*s + b1, a1*s + p, s) expect3 = TransferFunction(2.0*p**3 + 4.0*s**2 - s + 5.0, p + 4.0*s, s) expect3_ = TransferFunction(2*p**3 + 4*s**2 - s + 5, p + 4*s, s) assert SP3.subs({a0: 2, a1: 4, b0: 1, b1: 5}) == expect3_ assert SP3.subs({a0: 2, a1: 4, b0: 1, b1: 5}).evalf() == expect3 assert expect3_.evalf() == expect3 SP4 = TransferFunction(s - a1*p**3, a0*s + p, p) expect4 = TransferFunction(7.0*p**3 + s, p - s, p) expect4_ = TransferFunction(7*p**3 + s, p - s, p) assert SP4.subs({a0: -1, a1: -7}) == expect4_ assert SP4.subs({a0: -1, a1: -7}).evalf() == expect4 assert expect4_.evalf() == expect4 # Low-frequency (or DC) gain. assert tf0.dc_gain() == 1 assert tf1.dc_gain() == Rational(3, 5) assert SP2.dc_gain() == 0 assert expect4.dc_gain() == -1 assert expect2_.dc_gain() == 0 assert TransferFunction(1, s, s).dc_gain() == oo # Poles of a transfer function. tf_ = TransferFunction(x**3 - k, k, x) _tf = TransferFunction(k, x**4 - k, x) TF_ = TransferFunction(x**2, x**10 + x + x**2, x) _TF = TransferFunction(x**10 + x + x**2, x**2, x) assert G1.poles() == [I, I, -I, -I] assert G2.poles() == [] assert tf1.poles() == [-5, 1] assert expect4_.poles() == [s] assert SP4.poles() == [-a0*s] assert expect3.poles() == [-0.25*p] assert str(expect2.poles()) == str([0.729001428685125, -0.564500714342563 - 0.710198984796332*I, -0.564500714342563 + 0.710198984796332*I]) assert str(expect1.poles()) == str([-0.4 - 0.66332495807108*I, -0.4 + 0.66332495807108*I]) assert _tf.poles() == [k**(Rational(1, 4)), -k**(Rational(1, 4)), I*k**(Rational(1, 4)), -I*k**(Rational(1, 4))] assert TF_.poles() == [CRootOf(x**9 + x + 1, 0), 0, CRootOf(x**9 + x + 1, 1), CRootOf(x**9 + x + 1, 2), CRootOf(x**9 + x + 1, 3), CRootOf(x**9 + x + 1, 4), CRootOf(x**9 + x + 1, 5), CRootOf(x**9 + x + 1, 6), CRootOf(x**9 + x + 1, 7), CRootOf(x**9 + x + 1, 8)] raises(NotImplementedError, lambda: TransferFunction(x**2, a0*x**10 + x + x**2, x).poles()) # Stability of a transfer function. q, r = symbols('q, r', negative=True) t = symbols('t', positive=True) TF_ = TransferFunction(s**2 + a0 - a1*p, q*s - r, s) stable_tf = TransferFunction(s**2 + a0 - a1*p, q*s - 1, s) stable_tf_ = TransferFunction(s**2 + a0 - a1*p, q*s - t, s) assert G1.is_stable() is False assert G2.is_stable() is True assert tf1.is_stable() is False # as one pole is +ve, and the other is -ve. assert expect2.is_stable() is False assert expect1.is_stable() is True assert stable_tf.is_stable() is True assert stable_tf_.is_stable() is True assert TF_.is_stable() is False assert expect4_.is_stable() is None # no assumption provided for the only pole 's'. assert SP4.is_stable() is None # Zeros of a transfer function. assert G1.zeros() == [1, 1] assert G2.zeros() == [] assert tf1.zeros() == [-3, 1] assert expect4_.zeros() == [7**(Rational(2, 3))*(-s)**(Rational(1, 3))/7, -7**(Rational(2, 3))*(-s)**(Rational(1, 3))/14 - sqrt(3)*7**(Rational(2, 3))*I*(-s)**(Rational(1, 3))/14, -7**(Rational(2, 3))*(-s)**(Rational(1, 3))/14 + sqrt(3)*7**(Rational(2, 3))*I*(-s)**(Rational(1, 3))/14] assert SP4.zeros() == [(s/a1)**(Rational(1, 3)), -(s/a1)**(Rational(1, 3))/2 - sqrt(3)*I*(s/a1)**(Rational(1, 3))/2, -(s/a1)**(Rational(1, 3))/2 + sqrt(3)*I*(s/a1)**(Rational(1, 3))/2] assert str(expect3.zeros()) == str([0.125 - 1.11102430216445*sqrt(-0.405063291139241*p**3 - 1.0), 1.11102430216445*sqrt(-0.405063291139241*p**3 - 1.0) + 0.125]) assert tf_.zeros() == [k**(Rational(1, 3)), -k**(Rational(1, 3))/2 - sqrt(3)*I*k**(Rational(1, 3))/2, -k**(Rational(1, 3))/2 + sqrt(3)*I*k**(Rational(1, 3))/2] assert _TF.zeros() == [CRootOf(x**9 + x + 1, 0), 0, CRootOf(x**9 + x + 1, 1), CRootOf(x**9 + x + 1, 2), CRootOf(x**9 + x + 1, 3), CRootOf(x**9 + x + 1, 4), CRootOf(x**9 + x + 1, 5), CRootOf(x**9 + x + 1, 6), CRootOf(x**9 + x + 1, 7), CRootOf(x**9 + x + 1, 8)] raises(NotImplementedError, lambda: TransferFunction(a0*x**10 + x + x**2, x**2, x).zeros()) # negation of TF. tf2 = TransferFunction(s + 3, s**2 - s**3 + 9, s) tf3 = TransferFunction(-3*p + 3, 1 - p, p) assert -tf2 == TransferFunction(-s - 3, s**2 - s**3 + 9, s) assert -tf3 == TransferFunction(3*p - 3, 1 - p, p) # taking power of a TF. tf4 = TransferFunction(p + 4, p - 3, p) tf5 = TransferFunction(s**2 + 1, 1 - s, s) expect2 = TransferFunction((s**2 + 1)**3, (1 - s)**3, s) expect1 = TransferFunction((p + 4)**2, (p - 3)**2, p) assert (tf4*tf4).doit() == tf4**2 == pow(tf4, 2) == expect1 assert (tf5*tf5*tf5).doit() == tf5**3 == pow(tf5, 3) == expect2 assert tf5**0 == pow(tf5, 0) == TransferFunction(1, 1, s) assert Series(tf4).doit()**-1 == tf4**-1 == pow(tf4, -1) == TransferFunction(p - 3, p + 4, p) assert (tf5*tf5).doit()**-1 == tf5**-2 == pow(tf5, -2) == TransferFunction((1 - s)**2, (s**2 + 1)**2, s) raises(ValueError, lambda: tf4**(s**2 + s - 1)) raises(ValueError, lambda: tf5**s) raises(ValueError, lambda: tf4**tf5) # sympy's own functions. tf = TransferFunction(s - 1, s**2 - 2*s + 1, s) tf6 = TransferFunction(s + p, p**2 - 5, s) assert factor(tf) == TransferFunction(s - 1, (s - 1)**2, s) assert tf.num.subs(s, 2) == tf.den.subs(s, 2) == 1 # subs & xreplace assert tf.subs(s, 2) == TransferFunction(s - 1, s**2 - 2*s + 1, s) assert tf6.subs(p, 3) == TransferFunction(s + 3, 4, s) assert tf3.xreplace({p: s}) == TransferFunction(-3*s + 3, 1 - s, s) raises(TypeError, lambda: tf3.xreplace({p: exp(2)})) assert tf3.subs(p, exp(2)) == tf3 tf7 = TransferFunction(a0*s**p + a1*p**s, a2*p - s, s) assert tf7.xreplace({s: k}) == TransferFunction(a0*k**p + a1*p**k, a2*p - k, k) assert tf7.subs(s, k) == TransferFunction(a0*s**p + a1*p**s, a2*p - s, s) # Conversion to Expr with to_expr() tf8 = TransferFunction(a0*s**5 + 5*s**2 + 3, s**6 - 3, s) tf9 = TransferFunction((5 + s), (5 + s)*(6 + s), s) tf10 = TransferFunction(0, 1, s) tf11 = TransferFunction(1, 1, s) assert tf8.to_expr() == Mul((a0*s**5 + 5*s**2 + 3), Pow((s**6 - 3), -1, evaluate=False), evaluate=False) assert tf9.to_expr() == Mul((s + 5), Pow((5 + s)*(6 + s), -1, evaluate=False), evaluate=False) assert tf10.to_expr() == Mul(S(0), Pow(1, -1, evaluate=False), evaluate=False) assert tf11.to_expr() == Pow(1, -1, evaluate=False) def test_TransferFunction_addition_and_subtraction(): tf1 = TransferFunction(s + 6, s - 5, s) tf2 = TransferFunction(s + 3, s + 1, s) tf3 = TransferFunction(s + 1, s**2 + s + 1, s) tf4 = TransferFunction(p, 2 - p, p) # addition assert tf1 + tf2 == Parallel(tf1, tf2) assert tf3 + tf1 == Parallel(tf3, tf1) assert -tf1 + tf2 + tf3 == Parallel(-tf1, tf2, tf3) assert tf1 + (tf2 + tf3) == Parallel(tf1, tf2, tf3) c = symbols("c", commutative=False) raises(ValueError, lambda: tf1 + Matrix([1, 2, 3])) raises(ValueError, lambda: tf2 + c) raises(ValueError, lambda: tf3 + tf4) raises(ValueError, lambda: tf1 + (s - 1)) raises(ValueError, lambda: tf1 + 8) raises(ValueError, lambda: (1 - p**3) + tf1) # subtraction assert tf1 - tf2 == Parallel(tf1, -tf2) assert tf3 - tf2 == Parallel(tf3, -tf2) assert -tf1 - tf3 == Parallel(-tf1, -tf3) assert tf1 - tf2 + tf3 == Parallel(tf1, -tf2, tf3) raises(ValueError, lambda: tf1 - Matrix([1, 2, 3])) raises(ValueError, lambda: tf3 - tf4) raises(ValueError, lambda: tf1 - (s - 1)) raises(ValueError, lambda: tf1 - 8) raises(ValueError, lambda: (s + 5) - tf2) raises(ValueError, lambda: (1 + p**4) - tf1) def test_TransferFunction_multiplication_and_division(): G1 = TransferFunction(s + 3, -s**3 + 9, s) G2 = TransferFunction(s + 1, s - 5, s) G3 = TransferFunction(p, p**4 - 6, p) G4 = TransferFunction(p + 4, p - 5, p) G5 = TransferFunction(s + 6, s - 5, s) G6 = TransferFunction(s + 3, s + 1, s) G7 = TransferFunction(1, 1, s) # multiplication assert G1*G2 == Series(G1, G2) assert -G1*G5 == Series(-G1, G5) assert -G2*G5*-G6 == Series(-G2, G5, -G6) assert -G1*-G2*-G5*-G6 == Series(-G1, -G2, -G5, -G6) assert G3*G4 == Series(G3, G4) assert (G1*G2)*-(G5*G6) == \ Series(G1, G2, TransferFunction(-1, 1, s), Series(G5, G6)) assert G1*G2*(G5 + G6) == Series(G1, G2, Parallel(G5, G6)) c = symbols("c", commutative=False) raises(ValueError, lambda: G3 * Matrix([1, 2, 3])) raises(ValueError, lambda: G1 * c) raises(ValueError, lambda: G3 * G5) raises(ValueError, lambda: G5 * (s - 1)) raises(ValueError, lambda: 9 * G5) raises(ValueError, lambda: G3 / Matrix([1, 2, 3])) raises(ValueError, lambda: G6 / 0) raises(ValueError, lambda: G3 / G5) raises(ValueError, lambda: G5 / 2) raises(ValueError, lambda: G5 / s**2) raises(ValueError, lambda: (s - 4*s**2) / G2) raises(ValueError, lambda: 0 / G4) raises(ValueError, lambda: G5 / G6) raises(ValueError, lambda: -G3 /G4) raises(ValueError, lambda: G7 / (1 + G6)) raises(ValueError, lambda: G7 / (G5 * G6)) raises(ValueError, lambda: G7 / (G7 + (G5 + G6))) def test_TransferFunction_is_proper(): omega_o, zeta, tau = symbols('omega_o, zeta, tau') G1 = TransferFunction(omega_o**2, s**2 + p*omega_o*zeta*s + omega_o**2, omega_o) G2 = TransferFunction(tau - s**3, tau + p**4, tau) G3 = TransferFunction(a*b*s**3 + s**2 - a*p + s, b - s*p**2, p) G4 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) assert G1.is_proper assert G2.is_proper assert G3.is_proper assert not G4.is_proper def test_TransferFunction_is_strictly_proper(): omega_o, zeta, tau = symbols('omega_o, zeta, tau') tf1 = TransferFunction(omega_o**2, s**2 + p*omega_o*zeta*s + omega_o**2, omega_o) tf2 = TransferFunction(tau - s**3, tau + p**4, tau) tf3 = TransferFunction(a*b*s**3 + s**2 - a*p + s, b - s*p**2, p) tf4 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) assert not tf1.is_strictly_proper assert not tf2.is_strictly_proper assert tf3.is_strictly_proper assert not tf4.is_strictly_proper def test_TransferFunction_is_biproper(): tau, omega_o, zeta = symbols('tau, omega_o, zeta') tf1 = TransferFunction(omega_o**2, s**2 + p*omega_o*zeta*s + omega_o**2, omega_o) tf2 = TransferFunction(tau - s**3, tau + p**4, tau) tf3 = TransferFunction(a*b*s**3 + s**2 - a*p + s, b - s*p**2, p) tf4 = TransferFunction(b*s**2 + p**2 - a*p + s, b - p**2, s) assert tf1.is_biproper assert tf2.is_biproper assert not tf3.is_biproper assert not tf4.is_biproper def test_Series_construction(): tf = TransferFunction(a0*s**3 + a1*s**2 - a2*s, b0*p**4 + b1*p**3 - b2*s*p, s) tf2 = TransferFunction(a2*p - s, a2*s + p, s) tf3 = TransferFunction(a0*p + p**a1 - s, p, p) tf4 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) inp = Function('X_d')(s) out = Function('X')(s) s0 = Series(tf, tf2) assert s0.args == (tf, tf2) assert s0.var == s s1 = Series(Parallel(tf, -tf2), tf2) assert s1.args == (Parallel(tf, -tf2), tf2) assert s1.var == s tf3_ = TransferFunction(inp, 1, s) tf4_ = TransferFunction(-out, 1, s) s2 = Series(tf, Parallel(tf3_, tf4_), tf2) assert s2.args == (tf, Parallel(tf3_, tf4_), tf2) s3 = Series(tf, tf2, tf4) assert s3.args == (tf, tf2, tf4) s4 = Series(tf3_, tf4_) assert s4.args == (tf3_, tf4_) assert s4.var == s s6 = Series(tf2, tf4, Parallel(tf2, -tf), tf4) assert s6.args == (tf2, tf4, Parallel(tf2, -tf), tf4) s7 = Series(tf, tf2) assert s0 == s7 assert not s0 == s2 raises(ValueError, lambda: Series(tf, tf3)) raises(ValueError, lambda: Series(tf, tf2, tf3, tf4)) raises(ValueError, lambda: Series(-tf3, tf2)) raises(TypeError, lambda: Series(2, tf, tf4)) raises(TypeError, lambda: Series(s**2 + p*s, tf3, tf2)) raises(TypeError, lambda: Series(tf3, Matrix([1, 2, 3, 4]))) def test_MIMOSeries_construction(): tf_1 = TransferFunction(a0*s**3 + a1*s**2 - a2*s, b0*p**4 + b1*p**3 - b2*s*p, s) tf_2 = TransferFunction(a2*p - s, a2*s + p, s) tf_3 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) tfm_1 = TransferFunctionMatrix([[tf_1, tf_2, tf_3], [-tf_3, -tf_2, tf_1]]) tfm_2 = TransferFunctionMatrix([[-tf_2], [-tf_2], [-tf_3]]) tfm_3 = TransferFunctionMatrix([[-tf_3]]) tfm_4 = TransferFunctionMatrix([[TF3], [TF2], [-TF1]]) tfm_5 = TransferFunctionMatrix.from_Matrix(Matrix([1/p]), p) s8 = MIMOSeries(tfm_2, tfm_1) assert s8.args == (tfm_2, tfm_1) assert s8.var == s assert s8.shape == (s8.num_outputs, s8.num_inputs) == (2, 1) s9 = MIMOSeries(tfm_3, tfm_2, tfm_1) assert s9.args == (tfm_3, tfm_2, tfm_1) assert s9.var == s assert s9.shape == (s9.num_outputs, s9.num_inputs) == (2, 1) s11 = MIMOSeries(tfm_3, MIMOParallel(-tfm_2, -tfm_4), tfm_1) assert s11.args == (tfm_3, MIMOParallel(-tfm_2, -tfm_4), tfm_1) assert s11.shape == (s11.num_outputs, s11.num_inputs) == (2, 1) # arg cannot be empty tuple. raises(ValueError, lambda: MIMOSeries()) # arg cannot contain SISO as well as MIMO systems. raises(TypeError, lambda: MIMOSeries(tfm_1, tf_1)) # for all the adjascent transfer function matrices: # no. of inputs of first TFM must be equal to the no. of outputs of the second TFM. raises(ValueError, lambda: MIMOSeries(tfm_1, tfm_2, -tfm_1)) # all the TFMs must use the same complex variable. raises(ValueError, lambda: MIMOSeries(tfm_3, tfm_5)) # Number or expression not allowed in the arguments. raises(TypeError, lambda: MIMOSeries(2, tfm_2, tfm_3)) raises(TypeError, lambda: MIMOSeries(s**2 + p*s, -tfm_2, tfm_3)) raises(TypeError, lambda: MIMOSeries(Matrix([1/p]), tfm_3)) def test_Series_functions(): tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) tf2 = TransferFunction(k, 1, s) tf3 = TransferFunction(a2*p - s, a2*s + p, s) tf4 = TransferFunction(a0*p + p**a1 - s, p, p) tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) assert tf1*tf2*tf3 == Series(tf1, tf2, tf3) == Series(Series(tf1, tf2), tf3) \ == Series(tf1, Series(tf2, tf3)) assert tf1*(tf2 + tf3) == Series(tf1, Parallel(tf2, tf3)) assert tf1*tf2 + tf5 == Parallel(Series(tf1, tf2), tf5) assert tf1*tf2 - tf5 == Parallel(Series(tf1, tf2), -tf5) assert tf1*tf2 + tf3 + tf5 == Parallel(Series(tf1, tf2), tf3, tf5) assert tf1*tf2 - tf3 - tf5 == Parallel(Series(tf1, tf2), -tf3, -tf5) assert tf1*tf2 - tf3 + tf5 == Parallel(Series(tf1, tf2), -tf3, tf5) assert tf1*tf2 + tf3*tf5 == Parallel(Series(tf1, tf2), Series(tf3, tf5)) assert tf1*tf2 - tf3*tf5 == Parallel(Series(tf1, tf2), Series(TransferFunction(-1, 1, s), Series(tf3, tf5))) assert tf2*tf3*(tf2 - tf1)*tf3 == Series(tf2, tf3, Parallel(tf2, -tf1), tf3) assert -tf1*tf2 == Series(-tf1, tf2) assert -(tf1*tf2) == Series(TransferFunction(-1, 1, s), Series(tf1, tf2)) raises(ValueError, lambda: tf1*tf2*tf4) raises(ValueError, lambda: tf1*(tf2 - tf4)) raises(ValueError, lambda: tf3*Matrix([1, 2, 3])) # evaluate=True -> doit() assert Series(tf1, tf2, evaluate=True) == Series(tf1, tf2).doit() == \ TransferFunction(k, s**2 + 2*s*wn*zeta + wn**2, s) assert Series(tf1, tf2, Parallel(tf1, -tf3), evaluate=True) == Series(tf1, tf2, Parallel(tf1, -tf3)).doit() == \ TransferFunction(k*(a2*s + p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2)), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)**2, s) assert Series(tf2, tf1, -tf3, evaluate=True) == Series(tf2, tf1, -tf3).doit() == \ TransferFunction(k*(-a2*p + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert not Series(tf1, -tf2, evaluate=False) == Series(tf1, -tf2).doit() assert Series(Parallel(tf1, tf2), Parallel(tf2, -tf3)).doit() == \ TransferFunction((k*(s**2 + 2*s*wn*zeta + wn**2) + 1)*(-a2*p + k*(a2*s + p) + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert Series(-tf1, -tf2, -tf3).doit() == \ TransferFunction(k*(-a2*p + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert -Series(tf1, tf2, tf3).doit() == \ TransferFunction(-k*(a2*p - s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert Series(tf2, tf3, Parallel(tf2, -tf1), tf3).doit() == \ TransferFunction(k*(a2*p - s)**2*(k*(s**2 + 2*s*wn*zeta + wn**2) - 1), (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2), s) assert Series(tf1, tf2).rewrite(TransferFunction) == TransferFunction(k, s**2 + 2*s*wn*zeta + wn**2, s) assert Series(tf2, tf1, -tf3).rewrite(TransferFunction) == \ TransferFunction(k*(-a2*p + s), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) S1 = Series(Parallel(tf1, tf2), Parallel(tf2, -tf3)) assert S1.is_proper assert not S1.is_strictly_proper assert S1.is_biproper S2 = Series(tf1, tf2, tf3) assert S2.is_proper assert S2.is_strictly_proper assert not S2.is_biproper S3 = Series(tf1, -tf2, Parallel(tf1, -tf3)) assert S3.is_proper assert S3.is_strictly_proper assert not S3.is_biproper def test_MIMOSeries_functions(): tfm1 = TransferFunctionMatrix([[TF1, TF2, TF3], [-TF3, -TF2, TF1]]) tfm2 = TransferFunctionMatrix([[-TF1], [-TF2], [-TF3]]) tfm3 = TransferFunctionMatrix([[-TF1]]) tfm4 = TransferFunctionMatrix([[-TF2, -TF3], [-TF1, TF2]]) tfm5 = TransferFunctionMatrix([[TF2, -TF2], [-TF3, -TF2]]) tfm6 = TransferFunctionMatrix([[-TF3], [TF1]]) tfm7 = TransferFunctionMatrix([[TF1], [-TF2]]) assert tfm1*tfm2 + tfm6 == MIMOParallel(MIMOSeries(tfm2, tfm1), tfm6) assert tfm1*tfm2 + tfm7 + tfm6 == MIMOParallel(MIMOSeries(tfm2, tfm1), tfm7, tfm6) assert tfm1*tfm2 - tfm6 - tfm7 == MIMOParallel(MIMOSeries(tfm2, tfm1), -tfm6, -tfm7) assert tfm4*tfm5 + (tfm4 - tfm5) == MIMOParallel(MIMOSeries(tfm5, tfm4), tfm4, -tfm5) assert tfm4*-tfm6 + (-tfm4*tfm6) == MIMOParallel(MIMOSeries(-tfm6, tfm4), MIMOSeries(tfm6, -tfm4)) raises(ValueError, lambda: tfm1*tfm2 + TF1) raises(TypeError, lambda: tfm1*tfm2 + a0) raises(TypeError, lambda: tfm4*tfm6 - (s - 1)) raises(TypeError, lambda: tfm4*-tfm6 - 8) raises(TypeError, lambda: (-1 + p**5) + tfm1*tfm2) # Shape criteria. raises(TypeError, lambda: -tfm1*tfm2 + tfm4) raises(TypeError, lambda: tfm1*tfm2 - tfm4 + tfm5) raises(TypeError, lambda: tfm1*tfm2 - tfm4*tfm5) assert tfm1*tfm2*-tfm3 == MIMOSeries(-tfm3, tfm2, tfm1) assert (tfm1*-tfm2)*tfm3 == MIMOSeries(tfm3, -tfm2, tfm1) # Multiplication of a Series object with a SISO TF not allowed. raises(ValueError, lambda: tfm4*tfm5*TF1) raises(TypeError, lambda: tfm4*tfm5*a1) raises(TypeError, lambda: tfm4*-tfm5*(s - 2)) raises(TypeError, lambda: tfm5*tfm4*9) raises(TypeError, lambda: (-p**3 + 1)*tfm5*tfm4) # Transfer function matrix in the arguments. assert (MIMOSeries(tfm2, tfm1, evaluate=True) == MIMOSeries(tfm2, tfm1).doit() == TransferFunctionMatrix(((TransferFunction(-k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (-a2*p + s)*(a2*p - s)*(s**2 + 2*s*wn*zeta + wn**2)**2 - (a2*s + p)**2, (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2, s),), (TransferFunction(k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (-a2*p + s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + (a2*p - s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2, s),)))) # doit() should not cancel poles and zeros. mat_1 = Matrix([[1/(1+s), (1+s)/(1+s**2+2*s)**3]]) mat_2 = Matrix([[(1+s)], [(1+s**2+2*s)**3/(1+s)]]) tm_1, tm_2 = TransferFunctionMatrix.from_Matrix(mat_1, s), TransferFunctionMatrix.from_Matrix(mat_2, s) assert (MIMOSeries(tm_2, tm_1).doit() == TransferFunctionMatrix(((TransferFunction(2*(s + 1)**2*(s**2 + 2*s + 1)**3, (s + 1)**2*(s**2 + 2*s + 1)**3, s),),))) assert MIMOSeries(tm_2, tm_1).doit().simplify() == TransferFunctionMatrix(((TransferFunction(2, 1, s),),)) # calling doit() will expand the internal Series and Parallel objects. assert (MIMOSeries(-tfm3, -tfm2, tfm1, evaluate=True) == MIMOSeries(-tfm3, -tfm2, tfm1).doit() == TransferFunctionMatrix(((TransferFunction(k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (a2*p - s)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (a2*s + p)**2, (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**3, s),), (TransferFunction(-k**2*(a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**2 + (-a2*p + s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + (a2*p - s)*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), (a2*s + p)**2*(s**2 + 2*s*wn*zeta + wn**2)**3, s),)))) assert (MIMOSeries(MIMOParallel(tfm4, tfm5), tfm5, evaluate=True) == MIMOSeries(MIMOParallel(tfm4, tfm5), tfm5).doit() == TransferFunctionMatrix(((TransferFunction(-k*(-a2*s - p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2)), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s), TransferFunction(k*(-a2*p - \ k*(a2*s + p) + s), a2*s + p, s)), (TransferFunction(-k*(-a2*s - p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2)), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s), \ TransferFunction((-a2*p + s)*(-a2*p - k*(a2*s + p) + s), (a2*s + p)**2, s)))) == MIMOSeries(MIMOParallel(tfm4, tfm5), tfm5).rewrite(TransferFunctionMatrix)) def test_Parallel_construction(): tf = TransferFunction(a0*s**3 + a1*s**2 - a2*s, b0*p**4 + b1*p**3 - b2*s*p, s) tf2 = TransferFunction(a2*p - s, a2*s + p, s) tf3 = TransferFunction(a0*p + p**a1 - s, p, p) tf4 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) inp = Function('X_d')(s) out = Function('X')(s) p0 = Parallel(tf, tf2) assert p0.args == (tf, tf2) assert p0.var == s p1 = Parallel(Series(tf, -tf2), tf2) assert p1.args == (Series(tf, -tf2), tf2) assert p1.var == s tf3_ = TransferFunction(inp, 1, s) tf4_ = TransferFunction(-out, 1, s) p2 = Parallel(tf, Series(tf3_, -tf4_), tf2) assert p2.args == (tf, Series(tf3_, -tf4_), tf2) p3 = Parallel(tf, tf2, tf4) assert p3.args == (tf, tf2, tf4) p4 = Parallel(tf3_, tf4_) assert p4.args == (tf3_, tf4_) assert p4.var == s p5 = Parallel(tf, tf2) assert p0 == p5 assert not p0 == p1 p6 = Parallel(tf2, tf4, Series(tf2, -tf4)) assert p6.args == (tf2, tf4, Series(tf2, -tf4)) p7 = Parallel(tf2, tf4, Series(tf2, -tf), tf4) assert p7.args == (tf2, tf4, Series(tf2, -tf), tf4) raises(ValueError, lambda: Parallel(tf, tf3)) raises(ValueError, lambda: Parallel(tf, tf2, tf3, tf4)) raises(ValueError, lambda: Parallel(-tf3, tf4)) raises(TypeError, lambda: Parallel(2, tf, tf4)) raises(TypeError, lambda: Parallel(s**2 + p*s, tf3, tf2)) raises(TypeError, lambda: Parallel(tf3, Matrix([1, 2, 3, 4]))) def test_MIMOParallel_construction(): tfm1 = TransferFunctionMatrix([[TF1], [TF2], [TF3]]) tfm2 = TransferFunctionMatrix([[-TF3], [TF2], [TF1]]) tfm3 = TransferFunctionMatrix([[TF1]]) tfm4 = TransferFunctionMatrix([[TF2], [TF1], [TF3]]) tfm5 = TransferFunctionMatrix([[TF1, TF2], [TF2, TF1]]) tfm6 = TransferFunctionMatrix([[TF2, TF1], [TF1, TF2]]) tfm7 = TransferFunctionMatrix.from_Matrix(Matrix([[1/p]]), p) p8 = MIMOParallel(tfm1, tfm2) assert p8.args == (tfm1, tfm2) assert p8.var == s assert p8.shape == (p8.num_outputs, p8.num_inputs) == (3, 1) p9 = MIMOParallel(MIMOSeries(tfm3, tfm1), tfm2) assert p9.args == (MIMOSeries(tfm3, tfm1), tfm2) assert p9.var == s assert p9.shape == (p9.num_outputs, p9.num_inputs) == (3, 1) p10 = MIMOParallel(tfm1, MIMOSeries(tfm3, tfm4), tfm2) assert p10.args == (tfm1, MIMOSeries(tfm3, tfm4), tfm2) assert p10.var == s assert p10.shape == (p10.num_outputs, p10.num_inputs) == (3, 1) p11 = MIMOParallel(tfm2, tfm1, tfm4) assert p11.args == (tfm2, tfm1, tfm4) assert p11.shape == (p11.num_outputs, p11.num_inputs) == (3, 1) p12 = MIMOParallel(tfm6, tfm5) assert p12.args == (tfm6, tfm5) assert p12.shape == (p12.num_outputs, p12.num_inputs) == (2, 2) p13 = MIMOParallel(tfm2, tfm4, MIMOSeries(-tfm3, tfm4), -tfm4) assert p13.args == (tfm2, tfm4, MIMOSeries(-tfm3, tfm4), -tfm4) assert p13.shape == (p13.num_outputs, p13.num_inputs) == (3, 1) # arg cannot be empty tuple. raises(TypeError, lambda: MIMOParallel(())) # arg cannot contain SISO as well as MIMO systems. raises(TypeError, lambda: MIMOParallel(tfm1, tfm2, TF1)) # all TFMs must have same shapes. raises(TypeError, lambda: MIMOParallel(tfm1, tfm3, tfm4)) # all TFMs must be using the same complex variable. raises(ValueError, lambda: MIMOParallel(tfm3, tfm7)) # Number or expression not allowed in the arguments. raises(TypeError, lambda: MIMOParallel(2, tfm1, tfm4)) raises(TypeError, lambda: MIMOParallel(s**2 + p*s, -tfm4, tfm2)) def test_Parallel_functions(): tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) tf2 = TransferFunction(k, 1, s) tf3 = TransferFunction(a2*p - s, a2*s + p, s) tf4 = TransferFunction(a0*p + p**a1 - s, p, p) tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) assert tf1 + tf2 + tf3 == Parallel(tf1, tf2, tf3) assert tf1 + tf2 + tf3 + tf5 == Parallel(tf1, tf2, tf3, tf5) assert tf1 + tf2 - tf3 - tf5 == Parallel(tf1, tf2, -tf3, -tf5) assert tf1 + tf2*tf3 == Parallel(tf1, Series(tf2, tf3)) assert tf1 - tf2*tf3 == Parallel(tf1, -Series(tf2,tf3)) assert -tf1 - tf2 == Parallel(-tf1, -tf2) assert -(tf1 + tf2) == Series(TransferFunction(-1, 1, s), Parallel(tf1, tf2)) assert (tf2 + tf3)*tf1 == Series(Parallel(tf2, tf3), tf1) assert (tf1 + tf2)*(tf3*tf5) == Series(Parallel(tf1, tf2), tf3, tf5) assert -(tf2 + tf3)*-tf5 == Series(TransferFunction(-1, 1, s), Parallel(tf2, tf3), -tf5) assert tf2 + tf3 + tf2*tf1 + tf5 == Parallel(tf2, tf3, Series(tf2, tf1), tf5) assert tf2 + tf3 + tf2*tf1 - tf3 == Parallel(tf2, tf3, Series(tf2, tf1), -tf3) assert (tf1 + tf2 + tf5)*(tf3 + tf5) == Series(Parallel(tf1, tf2, tf5), Parallel(tf3, tf5)) raises(ValueError, lambda: tf1 + tf2 + tf4) raises(ValueError, lambda: tf1 - tf2*tf4) raises(ValueError, lambda: tf3 + Matrix([1, 2, 3])) # evaluate=True -> doit() assert Parallel(tf1, tf2, evaluate=True) == Parallel(tf1, tf2).doit() == \ TransferFunction(k*(s**2 + 2*s*wn*zeta + wn**2) + 1, s**2 + 2*s*wn*zeta + wn**2, s) assert Parallel(tf1, tf2, Series(-tf1, tf3), evaluate=True) == \ Parallel(tf1, tf2, Series(-tf1, tf3)).doit() == TransferFunction(k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)**2 + \ (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2) + (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), (a2*s + p)*(s**2 + \ 2*s*wn*zeta + wn**2)**2, s) assert Parallel(tf2, tf1, -tf3, evaluate=True) == Parallel(tf2, tf1, -tf3).doit() == \ TransferFunction(a2*s + k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2) \ , (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert not Parallel(tf1, -tf2, evaluate=False) == Parallel(tf1, -tf2).doit() assert Parallel(Series(tf1, tf2), Series(tf2, tf3)).doit() == \ TransferFunction(k*(a2*p - s)*(s**2 + 2*s*wn*zeta + wn**2) + k*(a2*s + p), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert Parallel(-tf1, -tf2, -tf3).doit() == \ TransferFunction(-a2*s - k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) - p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + wn**2), \ (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert -Parallel(tf1, tf2, tf3).doit() == \ TransferFunction(-a2*s - k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) - p - (a2*p - s)*(s**2 + 2*s*wn*zeta + wn**2), \ (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert Parallel(tf2, tf3, Series(tf2, -tf1), tf3).doit() == \ TransferFunction(k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) - k*(a2*s + p) + (2*a2*p - 2*s)*(s**2 + 2*s*wn*zeta \ + wn**2), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert Parallel(tf1, tf2).rewrite(TransferFunction) == \ TransferFunction(k*(s**2 + 2*s*wn*zeta + wn**2) + 1, s**2 + 2*s*wn*zeta + wn**2, s) assert Parallel(tf2, tf1, -tf3).rewrite(TransferFunction) == \ TransferFunction(a2*s + k*(a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2) + p + (-a2*p + s)*(s**2 + 2*s*wn*zeta + \ wn**2), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert Parallel(tf1, Parallel(tf2, tf3)) == Parallel(tf1, tf2, tf3) == Parallel(Parallel(tf1, tf2), tf3) P1 = Parallel(Series(tf1, tf2), Series(tf2, tf3)) assert P1.is_proper assert not P1.is_strictly_proper assert P1.is_biproper P2 = Parallel(tf1, -tf2, -tf3) assert P2.is_proper assert not P2.is_strictly_proper assert P2.is_biproper P3 = Parallel(tf1, -tf2, Series(tf1, tf3)) assert P3.is_proper assert not P3.is_strictly_proper assert P3.is_biproper def test_MIMOParallel_functions(): tf4 = TransferFunction(a0*p + p**a1 - s, p, p) tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) tfm1 = TransferFunctionMatrix([[TF1], [TF2], [TF3]]) tfm2 = TransferFunctionMatrix([[-TF2], [tf5], [-TF1]]) tfm3 = TransferFunctionMatrix([[tf5], [-tf5], [TF2]]) tfm4 = TransferFunctionMatrix([[TF2, -tf5], [TF1, tf5]]) tfm5 = TransferFunctionMatrix([[TF1, TF2], [TF3, -tf5]]) tfm6 = TransferFunctionMatrix([[-TF2]]) tfm7 = TransferFunctionMatrix([[tf4], [-tf4], [tf4]]) assert tfm1 + tfm2 + tfm3 == MIMOParallel(tfm1, tfm2, tfm3) == MIMOParallel(MIMOParallel(tfm1, tfm2), tfm3) assert tfm2 - tfm1 - tfm3 == MIMOParallel(tfm2, -tfm1, -tfm3) assert tfm2 - tfm3 + (-tfm1*tfm6*-tfm6) == MIMOParallel(tfm2, -tfm3, MIMOSeries(-tfm6, tfm6, -tfm1)) assert tfm1 + tfm1 - (-tfm1*tfm6) == MIMOParallel(tfm1, tfm1, -MIMOSeries(tfm6, -tfm1)) assert tfm2 - tfm3 - tfm1 + tfm2 == MIMOParallel(tfm2, -tfm3, -tfm1, tfm2) assert tfm1 + tfm2 - tfm3 - tfm1 == MIMOParallel(tfm1, tfm2, -tfm3, -tfm1) raises(ValueError, lambda: tfm1 + tfm2 + TF2) raises(TypeError, lambda: tfm1 - tfm2 - a1) raises(TypeError, lambda: tfm2 - tfm3 - (s - 1)) raises(TypeError, lambda: -tfm3 - tfm2 - 9) raises(TypeError, lambda: (1 - p**3) - tfm3 - tfm2) # All TFMs must use the same complex var. tfm7 uses 'p'. raises(ValueError, lambda: tfm3 - tfm2 - tfm7) raises(ValueError, lambda: tfm2 - tfm1 + tfm7) # (tfm1 +/- tfm2) has (3, 1) shape while tfm4 has (2, 2) shape. raises(TypeError, lambda: tfm1 + tfm2 + tfm4) raises(TypeError, lambda: (tfm1 - tfm2) - tfm4) assert (tfm1 + tfm2)*tfm6 == MIMOSeries(tfm6, MIMOParallel(tfm1, tfm2)) assert (tfm2 - tfm3)*tfm6*-tfm6 == MIMOSeries(-tfm6, tfm6, MIMOParallel(tfm2, -tfm3)) assert (tfm2 - tfm1 - tfm3)*(tfm6 + tfm6) == MIMOSeries(MIMOParallel(tfm6, tfm6), MIMOParallel(tfm2, -tfm1, -tfm3)) raises(ValueError, lambda: (tfm4 + tfm5)*TF1) raises(TypeError, lambda: (tfm2 - tfm3)*a2) raises(TypeError, lambda: (tfm3 + tfm2)*(s - 6)) raises(TypeError, lambda: (tfm1 + tfm2 + tfm3)*0) raises(TypeError, lambda: (1 - p**3)*(tfm1 + tfm3)) # (tfm3 - tfm2) has (3, 1) shape while tfm4*tfm5 has (2, 2) shape. raises(ValueError, lambda: (tfm3 - tfm2)*tfm4*tfm5) # (tfm1 - tfm2) has (3, 1) shape while tfm5 has (2, 2) shape. raises(ValueError, lambda: (tfm1 - tfm2)*tfm5) # TFM in the arguments. assert (MIMOParallel(tfm1, tfm2, evaluate=True) == MIMOParallel(tfm1, tfm2).doit() == MIMOParallel(tfm1, tfm2).rewrite(TransferFunctionMatrix) == TransferFunctionMatrix(((TransferFunction(-k*(s**2 + 2*s*wn*zeta + wn**2) + 1, s**2 + 2*s*wn*zeta + wn**2, s),), \ (TransferFunction(-a0 + a1*s**2 + a2*s + k*(a0 + s), a0 + s, s),), (TransferFunction(-a2*s - p + (a2*p - s)* \ (s**2 + 2*s*wn*zeta + wn**2), (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s),)))) def test_Feedback_construction(): tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) tf2 = TransferFunction(k, 1, s) tf3 = TransferFunction(a2*p - s, a2*s + p, s) tf4 = TransferFunction(a0*p + p**a1 - s, p, p) tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) tf6 = TransferFunction(s - p, p + s, p) f1 = Feedback(TransferFunction(1, 1, s), tf1*tf2*tf3) assert f1.args == (TransferFunction(1, 1, s), Series(tf1, tf2, tf3), -1) assert f1.sys1 == TransferFunction(1, 1, s) assert f1.sys2 == Series(tf1, tf2, tf3) assert f1.var == s f2 = Feedback(tf1, tf2*tf3) assert f2.args == (tf1, Series(tf2, tf3), -1) assert f2.sys1 == tf1 assert f2.sys2 == Series(tf2, tf3) assert f2.var == s f3 = Feedback(tf1*tf2, tf5) assert f3.args == (Series(tf1, tf2), tf5, -1) assert f3.sys1 == Series(tf1, tf2) f4 = Feedback(tf4, tf6) assert f4.args == (tf4, tf6, -1) assert f4.sys1 == tf4 assert f4.var == p f5 = Feedback(tf5, TransferFunction(1, 1, s)) assert f5.args == (tf5, TransferFunction(1, 1, s), -1) assert f5.var == s assert f5 == Feedback(tf5) # When sys2 is not passed explicitly, it is assumed to be unit tf. f6 = Feedback(TransferFunction(1, 1, p), tf4) assert f6.args == (TransferFunction(1, 1, p), tf4, -1) assert f6.var == p f7 = -Feedback(tf4*tf6, TransferFunction(1, 1, p)) assert f7.args == (Series(TransferFunction(-1, 1, p), Series(tf4, tf6)), -TransferFunction(1, 1, p), -1) assert f7.sys1 == Series(TransferFunction(-1, 1, p), Series(tf4, tf6)) # denominator can't be a Parallel instance raises(TypeError, lambda: Feedback(tf1, tf2 + tf3)) raises(TypeError, lambda: Feedback(tf1, Matrix([1, 2, 3]))) raises(TypeError, lambda: Feedback(TransferFunction(1, 1, s), s - 1)) raises(TypeError, lambda: Feedback(1, 1)) # raises(ValueError, lambda: Feedback(TransferFunction(1, 1, s), TransferFunction(1, 1, s))) raises(ValueError, lambda: Feedback(tf2, tf4*tf5)) raises(ValueError, lambda: Feedback(tf2, tf1, 1.5)) # `sign` can only be -1 or 1 raises(ValueError, lambda: Feedback(tf1, -tf1**-1)) # denominator can't be zero raises(ValueError, lambda: Feedback(tf4, tf5)) # Both systems should use the same `var` def test_Feedback_functions(): tf = TransferFunction(1, 1, s) tf1 = TransferFunction(1, s**2 + 2*zeta*wn*s + wn**2, s) tf2 = TransferFunction(k, 1, s) tf3 = TransferFunction(a2*p - s, a2*s + p, s) tf4 = TransferFunction(a0*p + p**a1 - s, p, p) tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) tf6 = TransferFunction(s - p, p + s, p) assert tf / (tf + tf1) == Feedback(tf, tf1) assert tf / (tf + tf1*tf2*tf3) == Feedback(tf, tf1*tf2*tf3) assert tf1 / (tf + tf1*tf2*tf3) == Feedback(tf1, tf2*tf3) assert (tf1*tf2) / (tf + tf1*tf2) == Feedback(tf1*tf2, tf) assert (tf1*tf2) / (tf + tf1*tf2*tf5) == Feedback(tf1*tf2, tf5) assert (tf1*tf2) / (tf + tf1*tf2*tf5*tf3) in (Feedback(tf1*tf2, tf5*tf3), Feedback(tf1*tf2, tf3*tf5)) assert tf4 / (TransferFunction(1, 1, p) + tf4*tf6) == Feedback(tf4, tf6) assert tf5 / (tf + tf5) == Feedback(tf5, tf) raises(TypeError, lambda: tf1*tf2*tf3 / (1 + tf1*tf2*tf3)) raises(ValueError, lambda: tf1*tf2*tf3 / tf3*tf5) raises(ValueError, lambda: tf2*tf3 / (tf + tf2*tf3*tf4)) assert Feedback(tf, tf1*tf2*tf3).doit() == \ TransferFunction((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), k*(a2*p - s) + \ (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), s) assert Feedback(tf, tf1*tf2*tf3).sensitivity == \ 1/(k*(a2*p - s)/((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)) + 1) assert Feedback(tf1, tf2*tf3).doit() == \ TransferFunction((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2), (k*(a2*p - s) + \ (a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2))*(s**2 + 2*s*wn*zeta + wn**2), s) assert Feedback(tf1, tf2*tf3).sensitivity == \ 1/(k*(a2*p - s)/((a2*s + p)*(s**2 + 2*s*wn*zeta + wn**2)) + 1) assert Feedback(tf1*tf2, tf5).doit() == \ TransferFunction(k*(a0 + s)*(s**2 + 2*s*wn*zeta + wn**2), (k*(-a0 + a1*s**2 + a2*s) + \ (a0 + s)*(s**2 + 2*s*wn*zeta + wn**2))*(s**2 + 2*s*wn*zeta + wn**2), s) assert Feedback(tf1*tf2, tf5, 1).sensitivity == \ 1/(-k*(-a0 + a1*s**2 + a2*s)/((a0 + s)*(s**2 + 2*s*wn*zeta + wn**2)) + 1) assert Feedback(tf4, tf6).doit() == \ TransferFunction(p*(p + s)*(a0*p + p**a1 - s), p*(p*(p + s) + (-p + s)*(a0*p + p**a1 - s)), p) assert -Feedback(tf4*tf6, TransferFunction(1, 1, p)).doit() == \ TransferFunction(-p*(-p + s)*(p + s)*(a0*p + p**a1 - s), p*(p + s)*(p*(p + s) + (-p + s)*(a0*p + p**a1 - s)), p) assert Feedback(tf, tf).doit() == TransferFunction(1, 2, s) assert Feedback(tf1, tf2*tf5).rewrite(TransferFunction) == \ TransferFunction((a0 + s)*(s**2 + 2*s*wn*zeta + wn**2), (k*(-a0 + a1*s**2 + a2*s) + \ (a0 + s)*(s**2 + 2*s*wn*zeta + wn**2))*(s**2 + 2*s*wn*zeta + wn**2), s) assert Feedback(TransferFunction(1, 1, p), tf4).rewrite(TransferFunction) == \ TransferFunction(p, a0*p + p + p**a1 - s, p) def test_MIMOFeedback_construction(): tf1 = TransferFunction(1, s, s) tf2 = TransferFunction(s, s**3 - 1, s) tf3 = TransferFunction(s, s + 1, s) tf4 = TransferFunction(s, s**2 + 1, s) tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) tfm_2 = TransferFunctionMatrix([[tf2, tf3], [tf4, tf1]]) tfm_3 = TransferFunctionMatrix([[tf3, tf4], [tf1, tf2]]) f1 = MIMOFeedback(tfm_1, tfm_2) assert f1.args == (tfm_1, tfm_2, -1) assert f1.sys1 == tfm_1 assert f1.sys2 == tfm_2 assert f1.var == s assert f1.sign == -1 assert -(-f1) == f1 f2 = MIMOFeedback(tfm_2, tfm_1, 1) assert f2.args == (tfm_2, tfm_1, 1) assert f2.sys1 == tfm_2 assert f2.sys2 == tfm_1 assert f2.var == s assert f2.sign == 1 f3 = MIMOFeedback(tfm_1, MIMOSeries(tfm_3, tfm_2)) assert f3.args == (tfm_1, MIMOSeries(tfm_3, tfm_2), -1) assert f3.sys1 == tfm_1 assert f3.sys2 == MIMOSeries(tfm_3, tfm_2) assert f3.var == s assert f3.sign == -1 mat = Matrix([[1, 1/s], [0, 1]]) sys1 = controller = TransferFunctionMatrix.from_Matrix(mat, s) f4 = MIMOFeedback(sys1, controller) assert f4.args == (sys1, controller, -1) assert f4.sys1 == f4.sys2 == sys1 def test_MIMOFeedback_errors(): tf1 = TransferFunction(1, s, s) tf2 = TransferFunction(s, s**3 - 1, s) tf3 = TransferFunction(s, s - 1, s) tf4 = TransferFunction(s, s**2 + 1, s) tf5 = TransferFunction(1, 1, s) tf6 = TransferFunction(-1, s - 1, s) tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) tfm_2 = TransferFunctionMatrix([[tf2, tf3], [tf4, tf1]]) tfm_3 = TransferFunctionMatrix.from_Matrix(eye(2), var=s) tfm_4 = TransferFunctionMatrix([[tf1, tf5], [tf5, tf5]]) tfm_5 = TransferFunctionMatrix([[-tf3, tf3], [tf3, tf6]]) # tfm_4 is inverse of tfm_5. Therefore tfm_5*tfm_4 = I tfm_6 = TransferFunctionMatrix([[-tf3]]) tfm_7 = TransferFunctionMatrix([[tf3, tf4]]) # Unsupported Types raises(TypeError, lambda: MIMOFeedback(tf1, tf2)) raises(TypeError, lambda: MIMOFeedback(MIMOParallel(tfm_1, tfm_2), tfm_3)) # Shape Errors raises(ValueError, lambda: MIMOFeedback(tfm_1, tfm_6, 1)) raises(ValueError, lambda: MIMOFeedback(tfm_7, tfm_7)) # sign not 1/-1 raises(ValueError, lambda: MIMOFeedback(tfm_1, tfm_2, -2)) # Non-Invertible Systems raises(ValueError, lambda: MIMOFeedback(tfm_5, tfm_4, 1)) raises(ValueError, lambda: MIMOFeedback(tfm_4, -tfm_5)) raises(ValueError, lambda: MIMOFeedback(tfm_3, tfm_3, 1)) # Variable not same in both the systems tfm_8 = TransferFunctionMatrix.from_Matrix(eye(2), var=p) raises(ValueError, lambda: MIMOFeedback(tfm_1, tfm_8, 1)) def test_MIMOFeedback_functions(): tf1 = TransferFunction(1, s, s) tf2 = TransferFunction(s, s - 1, s) tf3 = TransferFunction(1, 1, s) tf4 = TransferFunction(-1, s - 1, s) tfm_1 = TransferFunctionMatrix.from_Matrix(eye(2), var=s) tfm_2 = TransferFunctionMatrix([[tf1, tf3], [tf3, tf3]]) tfm_3 = TransferFunctionMatrix([[-tf2, tf2], [tf2, tf4]]) tfm_4 = TransferFunctionMatrix([[tf1, tf2], [-tf2, tf1]]) # sensitivity, doit(), rewrite() F_1 = MIMOFeedback(tfm_2, tfm_3) F_2 = MIMOFeedback(tfm_2, MIMOSeries(tfm_4, -tfm_1), 1) assert F_1.sensitivity == Matrix([[1/2, 0], [0, 1/2]]) assert F_2.sensitivity == Matrix([[(-2*s**4 + s**2)/(s**2 - s + 1), (2*s**3 - s**2)/(s**2 - s + 1)], [-s**2, s]]) assert F_1.doit() == \ TransferFunctionMatrix(((TransferFunction(1, 2*s, s), TransferFunction(1, 2, s)), (TransferFunction(1, 2, s), TransferFunction(1, 2, s)))) == F_1.rewrite(TransferFunctionMatrix) assert F_2.doit(cancel=False, expand=True) == \ TransferFunctionMatrix(((TransferFunction(-s**5 + 2*s**4 - 2*s**3 + s**2, s**5 - 2*s**4 + 3*s**3 - 2*s**2 + s, s), TransferFunction(-2*s**4 + 2*s**3, s**2 - s + 1, s)), (TransferFunction(0, 1, s), TransferFunction(-s**2 + s, 1, s)))) assert F_2.doit(cancel=False) == \ TransferFunctionMatrix(((TransferFunction(s*(2*s**3 - s**2)*(s**2 - s + 1) + \ (-2*s**4 + s**2)*(s**2 - s + 1), s*(s**2 - s + 1)**2, s), TransferFunction(-2*s**4 + 2*s**3, s**2 - s + 1, s)), (TransferFunction(0, 1, s), TransferFunction(-s**2 + s, 1, s)))) assert F_2.doit() == \ TransferFunctionMatrix(((TransferFunction(s*(-2*s**2 + s*(2*s - 1) + 1), s**2 - s + 1, s), TransferFunction(2*s**3*(1 - s), s**2 - s + 1, s)), (TransferFunction(0, 1, s), TransferFunction(s*(1 - s), 1, s)))) assert F_2.doit(expand=True) == \ TransferFunctionMatrix(((TransferFunction(-s**2 + s, s**2 - s + 1, s), TransferFunction(-2*s**4 + 2*s**3, s**2 - s + 1, s)), (TransferFunction(0, 1, s), TransferFunction(-s**2 + s, 1, s)))) assert -(F_1.doit()) == (-F_1).doit() # First negating then calculating vs calculating then negating. def test_TransferFunctionMatrix_construction(): tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) tf4 = TransferFunction(a0*p + p**a1 - s, p, p) tfm3_ = TransferFunctionMatrix([[-TF3]]) assert tfm3_.shape == (tfm3_.num_outputs, tfm3_.num_inputs) == (1, 1) assert tfm3_.args == Tuple(Tuple(Tuple(-TF3))) assert tfm3_.var == s tfm5 = TransferFunctionMatrix([[TF1, -TF2], [TF3, tf5]]) assert tfm5.shape == (tfm5.num_outputs, tfm5.num_inputs) == (2, 2) assert tfm5.args == Tuple(Tuple(Tuple(TF1, -TF2), Tuple(TF3, tf5))) assert tfm5.var == s tfm7 = TransferFunctionMatrix([[TF1, TF2], [TF3, -tf5], [-tf5, TF2]]) assert tfm7.shape == (tfm7.num_outputs, tfm7.num_inputs) == (3, 2) assert tfm7.args == Tuple(Tuple(Tuple(TF1, TF2), Tuple(TF3, -tf5), Tuple(-tf5, TF2))) assert tfm7.var == s # all transfer functions will use the same complex variable. tf4 uses 'p'. raises(ValueError, lambda: TransferFunctionMatrix([[TF1], [TF2], [tf4]])) raises(ValueError, lambda: TransferFunctionMatrix([[TF1, tf4], [TF3, tf5]])) # length of all the lists in the TFM should be equal. raises(ValueError, lambda: TransferFunctionMatrix([[TF1], [TF3, tf5]])) raises(ValueError, lambda: TransferFunctionMatrix([[TF1, TF3], [tf5]])) # lists should only support transfer functions in them. raises(TypeError, lambda: TransferFunctionMatrix([[TF1, TF2], [TF3, Matrix([1, 2])]])) raises(TypeError, lambda: TransferFunctionMatrix([[TF1, Matrix([1, 2])], [TF3, TF2]])) # `arg` should strictly be nested list of TransferFunction raises(ValueError, lambda: TransferFunctionMatrix([TF1, TF2, tf5])) raises(ValueError, lambda: TransferFunctionMatrix([TF1])) def test_TransferFunctionMatrix_functions(): tf5 = TransferFunction(a1*s**2 + a2*s - a0, s + a0, s) # Classmethod (from_matrix) mat_1 = ImmutableMatrix([ [s*(s + 1)*(s - 3)/(s**4 + 1), 2], [p, p*(s + 1)/(s*(s**1 + 1))] ]) mat_2 = ImmutableMatrix([[(2*s + 1)/(s**2 - 9)]]) mat_3 = ImmutableMatrix([[1, 2], [3, 4]]) assert TransferFunctionMatrix.from_Matrix(mat_1, s) == \ TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], [TransferFunction(p, 1, s), TransferFunction(p, s, s)]]) assert TransferFunctionMatrix.from_Matrix(mat_2, s) == \ TransferFunctionMatrix([[TransferFunction(2*s + 1, s**2 - 9, s)]]) assert TransferFunctionMatrix.from_Matrix(mat_3, p) == \ TransferFunctionMatrix([[TransferFunction(1, 1, p), TransferFunction(2, 1, p)], [TransferFunction(3, 1, p), TransferFunction(4, 1, p)]]) # Negating a TFM tfm1 = TransferFunctionMatrix([[TF1], [TF2]]) assert -tfm1 == TransferFunctionMatrix([[-TF1], [-TF2]]) tfm2 = TransferFunctionMatrix([[TF1, TF2, TF3], [tf5, -TF1, -TF3]]) assert -tfm2 == TransferFunctionMatrix([[-TF1, -TF2, -TF3], [-tf5, TF1, TF3]]) # subs() H_1 = TransferFunctionMatrix.from_Matrix(mat_1, s) H_2 = TransferFunctionMatrix([[TransferFunction(a*p*s, k*s**2, s), TransferFunction(p*s, k*(s**2 - a), s)]]) assert H_1.subs(p, 1) == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], [TransferFunction(1, 1, s), TransferFunction(1, s, s)]]) assert H_1.subs({p: 1}) == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], [TransferFunction(1, 1, s), TransferFunction(1, s, s)]]) assert H_1.subs({p: 1, s: 1}) == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s)], [TransferFunction(1, 1, s), TransferFunction(1, s, s)]]) # This should ignore `s` as it is `var` assert H_2.subs(p, 2) == TransferFunctionMatrix([[TransferFunction(2*a*s, k*s**2, s), TransferFunction(2*s, k*(-a + s**2), s)]]) assert H_2.subs(k, 1) == TransferFunctionMatrix([[TransferFunction(a*p*s, s**2, s), TransferFunction(p*s, -a + s**2, s)]]) assert H_2.subs(a, 0) == TransferFunctionMatrix([[TransferFunction(0, k*s**2, s), TransferFunction(p*s, k*s**2, s)]]) assert H_2.subs({p: 1, k: 1, a: a0}) == TransferFunctionMatrix([[TransferFunction(a0*s, s**2, s), TransferFunction(s, -a0 + s**2, s)]]) # transpose() assert H_1.transpose() == TransferFunctionMatrix([[TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(p, 1, s)], [TransferFunction(2, 1, s), TransferFunction(p, s, s)]]) assert H_2.transpose() == TransferFunctionMatrix([[TransferFunction(a*p*s, k*s**2, s)], [TransferFunction(p*s, k*(-a + s**2), s)]]) assert H_1.transpose().transpose() == H_1 assert H_2.transpose().transpose() == H_2 # elem_poles() assert H_1.elem_poles() == [[[-sqrt(2)/2 - sqrt(2)*I/2, -sqrt(2)/2 + sqrt(2)*I/2, sqrt(2)/2 - sqrt(2)*I/2, sqrt(2)/2 + sqrt(2)*I/2], []], [[], [0]]] assert H_2.elem_poles() == [[[0, 0], [sqrt(a), -sqrt(a)]]] assert tfm2.elem_poles() == [[[wn*(-zeta + sqrt((zeta - 1)*(zeta + 1))), wn*(-zeta - sqrt((zeta - 1)*(zeta + 1)))], [], [-p/a2]], [[-a0], [wn*(-zeta + sqrt((zeta - 1)*(zeta + 1))), wn*(-zeta - sqrt((zeta - 1)*(zeta + 1)))], [-p/a2]]] # elem_zeros() assert H_1.elem_zeros() == [[[-1, 0, 3], []], [[], []]] assert H_2.elem_zeros() == [[[0], [0]]] assert tfm2.elem_zeros() == [[[], [], [a2*p]], [[-a2/(2*a1) - sqrt(4*a0*a1 + a2**2)/(2*a1), -a2/(2*a1) + sqrt(4*a0*a1 + a2**2)/(2*a1)], [], [a2*p]]] # doit() H_3 = TransferFunctionMatrix([[Series(TransferFunction(1, s**3 - 3, s), TransferFunction(s**2 - 2*s + 5, 1, s), TransferFunction(1, s, s))]]) H_4 = TransferFunctionMatrix([[Parallel(TransferFunction(s**3 - 3, 4*s**4 - s**2 - 2*s + 5, s), TransferFunction(4 - s**3, 4*s**4 - s**2 - 2*s + 5, s))]]) assert H_3.doit() == TransferFunctionMatrix([[TransferFunction(s**2 - 2*s + 5, s*(s**3 - 3), s)]]) assert H_4.doit() == TransferFunctionMatrix([[TransferFunction(1, 4*s**4 - s**2 - 2*s + 5, s)]]) # _flat() assert H_1._flat() == [TransferFunction(s*(s - 3)*(s + 1), s**4 + 1, s), TransferFunction(2, 1, s), TransferFunction(p, 1, s), TransferFunction(p, s, s)] assert H_2._flat() == [TransferFunction(a*p*s, k*s**2, s), TransferFunction(p*s, k*(-a + s**2), s)] assert H_3._flat() == [Series(TransferFunction(1, s**3 - 3, s), TransferFunction(s**2 - 2*s + 5, 1, s), TransferFunction(1, s, s))] assert H_4._flat() == [Parallel(TransferFunction(s**3 - 3, 4*s**4 - s**2 - 2*s + 5, s), TransferFunction(4 - s**3, 4*s**4 - s**2 - 2*s + 5, s))] # evalf() assert H_1.evalf() == \ TransferFunctionMatrix(((TransferFunction(s*(s - 3.0)*(s + 1.0), s**4 + 1.0, s), TransferFunction(2.0, 1, s)), (TransferFunction(1.0*p, 1, s), TransferFunction(p, s, s)))) assert H_2.subs({a:3.141, p:2.88, k:2}).evalf() == \ TransferFunctionMatrix(((TransferFunction(4.5230399999999999494093572138808667659759521484375, s, s), TransferFunction(2.87999999999999989341858963598497211933135986328125*s, 2.0*s**2 - 6.282000000000000028421709430404007434844970703125, s)),)) # simplify() H_5 = TransferFunctionMatrix([[TransferFunction(s**5 + s**3 + s, s - s**2, s), TransferFunction((s + 3)*(s - 1), (s - 1)*(s + 5), s)]]) assert H_5.simplify() == simplify(H_5) == \ TransferFunctionMatrix(((TransferFunction(-s**4 - s**2 - 1, s - 1, s), TransferFunction(s + 3, s + 5, s)),)) # expand() assert (H_1.expand() == TransferFunctionMatrix(((TransferFunction(s**3 - 2*s**2 - 3*s, s**4 + 1, s), TransferFunction(2, 1, s)), (TransferFunction(p, 1, s), TransferFunction(p, s, s))))) assert H_5.expand() == \ TransferFunctionMatrix(((TransferFunction(s**5 + s**3 + s, -s**2 + s, s), TransferFunction(s**2 + 2*s - 3, s**2 + 4*s - 5, s)),)) sympy-sympy-1.9/sympy/physics/gaussopt.py000066400000000000000000000015571412543434000210150ustar00rootroot00000000000000from sympy.physics.optics.gaussopt import RayTransferMatrix, FreeSpace,\ FlatRefraction, CurvedRefraction, FlatMirror, CurvedMirror, ThinLens,\ GeometricRay, BeamParameter, waist2rayleigh, rayleigh2waist, geometric_conj_ab,\ geometric_conj_af, geometric_conj_bf, gaussian_conj, conjugate_gauss_beams __all__ = [ 'RayTransferMatrix', 'FreeSpace', 'FlatRefraction', 'CurvedRefraction', 'FlatMirror', 'CurvedMirror', 'ThinLens', 'GeometricRay', 'BeamParameter', 'waist2rayleigh', 'rayleigh2waist', 'geometric_conj_ab', 'geometric_conj_af', 'geometric_conj_bf', 'gaussian_conj', 'conjugate_gauss_beams', ] from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning(feature="Module sympy.physics.gaussopt", useinstead="sympy.physics.optics.gaussopt", deprecated_since_version="0.7.6", issue=7659).warn() sympy-sympy-1.9/sympy/physics/hep/000077500000000000000000000000001412543434000173425ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/hep/__init__.py000066400000000000000000000000001412543434000214410ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/hep/gamma_matrices.py000066400000000000000000000571701412543434000226770ustar00rootroot00000000000000""" Module to handle gamma matrices expressed as tensor objects. Examples ======== >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, LorentzIndex >>> from sympy.tensor.tensor import tensor_indices >>> i = tensor_indices('i', LorentzIndex) >>> G(i) GammaMatrix(i) Note that there is already an instance of GammaMatrixHead in four dimensions: GammaMatrix, which is simply declare as >>> from sympy.physics.hep.gamma_matrices import GammaMatrix >>> from sympy.tensor.tensor import tensor_indices >>> i = tensor_indices('i', LorentzIndex) >>> GammaMatrix(i) GammaMatrix(i) To access the metric tensor >>> LorentzIndex.metric metric(LorentzIndex,LorentzIndex) """ from sympy import S, Mul, eye, trace from sympy.tensor.tensor import TensorIndexType, TensorIndex,\ TensMul, TensAdd, tensor_mul, Tensor, TensorHead, TensorSymmetry # DiracSpinorIndex = TensorIndexType('DiracSpinorIndex', dim=4, dummy_name="S") LorentzIndex = TensorIndexType('LorentzIndex', dim=4, dummy_name="L") GammaMatrix = TensorHead("GammaMatrix", [LorentzIndex], TensorSymmetry.no_symmetry(1), comm=None) def extract_type_tens(expression, component): """ Extract from a ``TensExpr`` all tensors with `component`. Returns two tensor expressions: * the first contains all ``Tensor`` of having `component`. * the second contains all remaining. """ if isinstance(expression, Tensor): sp = [expression] elif isinstance(expression, TensMul): sp = expression.args else: raise ValueError('wrong type') # Collect all gamma matrices of the same dimension new_expr = S.One residual_expr = S.One for i in sp: if isinstance(i, Tensor) and i.component == component: new_expr *= i else: residual_expr *= i return new_expr, residual_expr def simplify_gamma_expression(expression): extracted_expr, residual_expr = extract_type_tens(expression, GammaMatrix) res_expr = _simplify_single_line(extracted_expr) return res_expr * residual_expr def simplify_gpgp(ex, sort=True): """ simplify products ``G(i)*p(-i)*G(j)*p(-j) -> p(i)*p(-i)`` Examples ======== >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ LorentzIndex, simplify_gpgp >>> from sympy.tensor.tensor import tensor_indices, tensor_heads >>> p, q = tensor_heads('p, q', [LorentzIndex]) >>> i0,i1,i2,i3,i4,i5 = tensor_indices('i0:6', LorentzIndex) >>> ps = p(i0)*G(-i0) >>> qs = q(i0)*G(-i0) >>> simplify_gpgp(ps*qs*qs) GammaMatrix(-L_0)*p(L_0)*q(L_1)*q(-L_1) """ def _simplify_gpgp(ex): components = ex.components a = [] comp_map = [] for i, comp in enumerate(components): comp_map.extend([i]*comp.rank) dum = [(i[0], i[1], comp_map[i[0]], comp_map[i[1]]) for i in ex.dum] for i in range(len(components)): if components[i] != GammaMatrix: continue for dx in dum: if dx[2] == i: p_pos1 = dx[3] elif dx[3] == i: p_pos1 = dx[2] else: continue comp1 = components[p_pos1] if comp1.comm == 0 and comp1.rank == 1: a.append((i, p_pos1)) if not a: return ex elim = set() tv = [] hit = True coeff = S.One ta = None while hit: hit = False for i, ai in enumerate(a[:-1]): if ai[0] in elim: continue if ai[0] != a[i + 1][0] - 1: continue if components[ai[1]] != components[a[i + 1][1]]: continue elim.add(ai[0]) elim.add(ai[1]) elim.add(a[i + 1][0]) elim.add(a[i + 1][1]) if not ta: ta = ex.split() mu = TensorIndex('mu', LorentzIndex) hit = True if i == 0: coeff = ex.coeff tx = components[ai[1]](mu)*components[ai[1]](-mu) if len(a) == 2: tx *= 4 # eye(4) tv.append(tx) break if tv: a = [x for j, x in enumerate(ta) if j not in elim] a.extend(tv) t = tensor_mul(*a)*coeff # t = t.replace(lambda x: x.is_Matrix, lambda x: 1) return t else: return ex if sort: ex = ex.sorted_components() # this would be better off with pattern matching while 1: t = _simplify_gpgp(ex) if t != ex: ex = t else: return t def gamma_trace(t): """ trace of a single line of gamma matrices Examples ======== >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ gamma_trace, LorentzIndex >>> from sympy.tensor.tensor import tensor_indices, tensor_heads >>> p, q = tensor_heads('p, q', [LorentzIndex]) >>> i0,i1,i2,i3,i4,i5 = tensor_indices('i0:6', LorentzIndex) >>> ps = p(i0)*G(-i0) >>> qs = q(i0)*G(-i0) >>> gamma_trace(G(i0)*G(i1)) 4*metric(i0, i1) >>> gamma_trace(ps*ps) - 4*p(i0)*p(-i0) 0 >>> gamma_trace(ps*qs + ps*ps) - 4*p(i0)*p(-i0) - 4*p(i0)*q(-i0) 0 """ if isinstance(t, TensAdd): res = TensAdd(*[_trace_single_line(x) for x in t.args]) return res t = _simplify_single_line(t) res = _trace_single_line(t) return res def _simplify_single_line(expression): """ Simplify single-line product of gamma matrices. Examples ======== >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ LorentzIndex, _simplify_single_line >>> from sympy.tensor.tensor import tensor_indices, TensorHead >>> p = TensorHead('p', [LorentzIndex]) >>> i0,i1 = tensor_indices('i0:2', LorentzIndex) >>> _simplify_single_line(G(i0)*G(i1)*p(-i1)*G(-i0)) + 2*G(i0)*p(-i0) 0 """ t1, t2 = extract_type_tens(expression, GammaMatrix) if t1 != 1: t1 = kahane_simplify(t1) res = t1*t2 return res def _trace_single_line(t): """ Evaluate the trace of a single gamma matrix line inside a ``TensExpr``. Notes ===== If there are ``DiracSpinorIndex.auto_left`` and ``DiracSpinorIndex.auto_right`` indices trace over them; otherwise traces are not implied (explain) Examples ======== >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, \ LorentzIndex, _trace_single_line >>> from sympy.tensor.tensor import tensor_indices, TensorHead >>> p = TensorHead('p', [LorentzIndex]) >>> i0,i1,i2,i3,i4,i5 = tensor_indices('i0:6', LorentzIndex) >>> _trace_single_line(G(i0)*G(i1)) 4*metric(i0, i1) >>> _trace_single_line(G(i0)*p(-i0)*G(i1)*p(-i1)) - 4*p(i0)*p(-i0) 0 """ def _trace_single_line1(t): t = t.sorted_components() components = t.components ncomps = len(components) g = LorentzIndex.metric # gamma matirices are in a[i:j] hit = 0 for i in range(ncomps): if components[i] == GammaMatrix: hit = 1 break for j in range(i + hit, ncomps): if components[j] != GammaMatrix: break else: j = ncomps numG = j - i if numG == 0: tcoeff = t.coeff return t.nocoeff if tcoeff else t if numG % 2 == 1: return TensMul.from_data(S.Zero, [], [], []) elif numG > 4: # find the open matrix indices and connect them: a = t.split() ind1 = a[i].get_indices()[0] ind2 = a[i + 1].get_indices()[0] aa = a[:i] + a[i + 2:] t1 = tensor_mul(*aa)*g(ind1, ind2) t1 = t1.contract_metric(g) args = [t1] sign = 1 for k in range(i + 2, j): sign = -sign ind2 = a[k].get_indices()[0] aa = a[:i] + a[i + 1:k] + a[k + 1:] t2 = sign*tensor_mul(*aa)*g(ind1, ind2) t2 = t2.contract_metric(g) t2 = simplify_gpgp(t2, False) args.append(t2) t3 = TensAdd(*args) t3 = _trace_single_line(t3) return t3 else: a = t.split() t1 = _gamma_trace1(*a[i:j]) a2 = a[:i] + a[j:] t2 = tensor_mul(*a2) t3 = t1*t2 if not t3: return t3 t3 = t3.contract_metric(g) return t3 t = t.expand() if isinstance(t, TensAdd): a = [_trace_single_line1(x)*x.coeff for x in t.args] return TensAdd(*a) elif isinstance(t, (Tensor, TensMul)): r = t.coeff*_trace_single_line1(t) return r else: return trace(t) def _gamma_trace1(*a): gctr = 4 # FIXME specific for d=4 g = LorentzIndex.metric if not a: return gctr n = len(a) if n%2 == 1: #return TensMul.from_data(S.Zero, [], [], []) return S.Zero if n == 2: ind0 = a[0].get_indices()[0] ind1 = a[1].get_indices()[0] return gctr*g(ind0, ind1) if n == 4: ind0 = a[0].get_indices()[0] ind1 = a[1].get_indices()[0] ind2 = a[2].get_indices()[0] ind3 = a[3].get_indices()[0] return gctr*(g(ind0, ind1)*g(ind2, ind3) - \ g(ind0, ind2)*g(ind1, ind3) + g(ind0, ind3)*g(ind1, ind2)) def kahane_simplify(expression): r""" This function cancels contracted elements in a product of four dimensional gamma matrices, resulting in an expression equal to the given one, without the contracted gamma matrices. Parameters ========== `expression` the tensor expression containing the gamma matrices to simplify. Notes ===== If spinor indices are given, the matrices must be given in the order given in the product. Algorithm ========= The idea behind the algorithm is to use some well-known identities, i.e., for contractions enclosing an even number of `\gamma` matrices `\gamma^\mu \gamma_{a_1} \cdots \gamma_{a_{2N}} \gamma_\mu = 2 (\gamma_{a_{2N}} \gamma_{a_1} \cdots \gamma_{a_{2N-1}} + \gamma_{a_{2N-1}} \cdots \gamma_{a_1} \gamma_{a_{2N}} )` for an odd number of `\gamma` matrices `\gamma^\mu \gamma_{a_1} \cdots \gamma_{a_{2N+1}} \gamma_\mu = -2 \gamma_{a_{2N+1}} \gamma_{a_{2N}} \cdots \gamma_{a_{1}}` Instead of repeatedly applying these identities to cancel out all contracted indices, it is possible to recognize the links that would result from such an operation, the problem is thus reduced to a simple rearrangement of free gamma matrices. Examples ======== When using, always remember that the original expression coefficient has to be handled separately >>> from sympy.physics.hep.gamma_matrices import GammaMatrix as G, LorentzIndex >>> from sympy.physics.hep.gamma_matrices import kahane_simplify >>> from sympy.tensor.tensor import tensor_indices >>> i0, i1, i2 = tensor_indices('i0:3', LorentzIndex) >>> ta = G(i0)*G(-i0) >>> kahane_simplify(ta) Matrix([ [4, 0, 0, 0], [0, 4, 0, 0], [0, 0, 4, 0], [0, 0, 0, 4]]) >>> tb = G(i0)*G(i1)*G(-i0) >>> kahane_simplify(tb) -2*GammaMatrix(i1) >>> t = G(i0)*G(-i0) >>> kahane_simplify(t) Matrix([ [4, 0, 0, 0], [0, 4, 0, 0], [0, 0, 4, 0], [0, 0, 0, 4]]) >>> t = G(i0)*G(-i0) >>> kahane_simplify(t) Matrix([ [4, 0, 0, 0], [0, 4, 0, 0], [0, 0, 4, 0], [0, 0, 0, 4]]) If there are no contractions, the same expression is returned >>> tc = G(i0)*G(i1) >>> kahane_simplify(tc) GammaMatrix(i0)*GammaMatrix(i1) References ========== [1] Algorithm for Reducing Contracted Products of gamma Matrices, Joseph Kahane, Journal of Mathematical Physics, Vol. 9, No. 10, October 1968. """ if isinstance(expression, Mul): return expression if isinstance(expression, TensAdd): return TensAdd(*[kahane_simplify(arg) for arg in expression.args]) if isinstance(expression, Tensor): return expression assert isinstance(expression, TensMul) gammas = expression.args for gamma in gammas: assert gamma.component == GammaMatrix free = expression.free # spinor_free = [_ for _ in expression.free_in_args if _[1] != 0] # if len(spinor_free) == 2: # spinor_free.sort(key=lambda x: x[2]) # assert spinor_free[0][1] == 1 and spinor_free[-1][1] == 2 # assert spinor_free[0][2] == 0 # elif spinor_free: # raise ValueError('spinor indices do not match') dum = [] for dum_pair in expression.dum: if expression.index_types[dum_pair[0]] == LorentzIndex: dum.append((dum_pair[0], dum_pair[1])) dum = sorted(dum) if len(dum) == 0: # or GammaMatrixHead: # no contractions in `expression`, just return it. return expression # find the `first_dum_pos`, i.e. the position of the first contracted # gamma matrix, Kahane's algorithm as described in his paper requires the # gamma matrix expression to start with a contracted gamma matrix, this is # a workaround which ignores possible initial free indices, and re-adds # them later. first_dum_pos = min(map(min, dum)) # for p1, p2, a1, a2 in expression.dum_in_args: # if p1 != 0 or p2 != 0: # # only Lorentz indices, skip Dirac indices: # continue # first_dum_pos = min(p1, p2) # break total_number = len(free) + len(dum)*2 number_of_contractions = len(dum) free_pos = [None]*total_number for i in free: free_pos[i[1]] = i[0] # `index_is_free` is a list of booleans, to identify index position # and whether that index is free or dummy. index_is_free = [False]*total_number for i, indx in enumerate(free): index_is_free[indx[1]] = True # `links` is a dictionary containing the graph described in Kahane's paper, # to every key correspond one or two values, representing the linked indices. # All values in `links` are integers, negative numbers are used in the case # where it is necessary to insert gamma matrices between free indices, in # order to make Kahane's algorithm work (see paper). links = dict() for i in range(first_dum_pos, total_number): links[i] = [] # `cum_sign` is a step variable to mark the sign of every index, see paper. cum_sign = -1 # `cum_sign_list` keeps storage for all `cum_sign` (every index). cum_sign_list = [None]*total_number block_free_count = 0 # multiply `resulting_coeff` by the coefficient parameter, the rest # of the algorithm ignores a scalar coefficient. resulting_coeff = S.One # initialize a list of lists of indices. The outer list will contain all # additive tensor expressions, while the inner list will contain the # free indices (rearranged according to the algorithm). resulting_indices = [[]] # start to count the `connected_components`, which together with the number # of contractions, determines a -1 or +1 factor to be multiplied. connected_components = 1 # First loop: here we fill `cum_sign_list`, and draw the links # among consecutive indices (they are stored in `links`). Links among # non-consecutive indices will be drawn later. for i, is_free in enumerate(index_is_free): # if `expression` starts with free indices, they are ignored here; # they are later added as they are to the beginning of all # `resulting_indices` list of lists of indices. if i < first_dum_pos: continue if is_free: block_free_count += 1 # if previous index was free as well, draw an arch in `links`. if block_free_count > 1: links[i - 1].append(i) links[i].append(i - 1) else: # Change the sign of the index (`cum_sign`) if the number of free # indices preceding it is even. cum_sign *= 1 if (block_free_count % 2) else -1 if block_free_count == 0 and i != first_dum_pos: # check if there are two consecutive dummy indices: # in this case create virtual indices with negative position, # these "virtual" indices represent the insertion of two # gamma^0 matrices to separate consecutive dummy indices, as # Kahane's algorithm requires dummy indices to be separated by # free indices. The product of two gamma^0 matrices is unity, # so the new expression being examined is the same as the # original one. if cum_sign == -1: links[-1-i] = [-1-i+1] links[-1-i+1] = [-1-i] if (i - cum_sign) in links: if i != first_dum_pos: links[i].append(i - cum_sign) if block_free_count != 0: if i - cum_sign < len(index_is_free): if index_is_free[i - cum_sign]: links[i - cum_sign].append(i) block_free_count = 0 cum_sign_list[i] = cum_sign # The previous loop has only created links between consecutive free indices, # it is necessary to properly create links among dummy (contracted) indices, # according to the rules described in Kahane's paper. There is only one exception # to Kahane's rules: the negative indices, which handle the case of some # consecutive free indices (Kahane's paper just describes dummy indices # separated by free indices, hinting that free indices can be added without # altering the expression result). for i in dum: # get the positions of the two contracted indices: pos1 = i[0] pos2 = i[1] # create Kahane's upper links, i.e. the upper arcs between dummy # (i.e. contracted) indices: links[pos1].append(pos2) links[pos2].append(pos1) # create Kahane's lower links, this corresponds to the arcs below # the line described in the paper: # first we move `pos1` and `pos2` according to the sign of the indices: linkpos1 = pos1 + cum_sign_list[pos1] linkpos2 = pos2 + cum_sign_list[pos2] # otherwise, perform some checks before creating the lower arcs: # make sure we are not exceeding the total number of indices: if linkpos1 >= total_number: continue if linkpos2 >= total_number: continue # make sure we are not below the first dummy index in `expression`: if linkpos1 < first_dum_pos: continue if linkpos2 < first_dum_pos: continue # check if the previous loop created "virtual" indices between dummy # indices, in such a case relink `linkpos1` and `linkpos2`: if (-1-linkpos1) in links: linkpos1 = -1-linkpos1 if (-1-linkpos2) in links: linkpos2 = -1-linkpos2 # move only if not next to free index: if linkpos1 >= 0 and not index_is_free[linkpos1]: linkpos1 = pos1 if linkpos2 >=0 and not index_is_free[linkpos2]: linkpos2 = pos2 # create the lower arcs: if linkpos2 not in links[linkpos1]: links[linkpos1].append(linkpos2) if linkpos1 not in links[linkpos2]: links[linkpos2].append(linkpos1) # This loop starts from the `first_dum_pos` index (first dummy index) # walks through the graph deleting the visited indices from `links`, # it adds a gamma matrix for every free index in encounters, while it # completely ignores dummy indices and virtual indices. pointer = first_dum_pos previous_pointer = 0 while True: if pointer in links: next_ones = links.pop(pointer) else: break if previous_pointer in next_ones: next_ones.remove(previous_pointer) previous_pointer = pointer if next_ones: pointer = next_ones[0] else: break if pointer == previous_pointer: break if pointer >=0 and free_pos[pointer] is not None: for ri in resulting_indices: ri.append(free_pos[pointer]) # The following loop removes the remaining connected components in `links`. # If there are free indices inside a connected component, it gives a # contribution to the resulting expression given by the factor # `gamma_a gamma_b ... gamma_z + gamma_z ... gamma_b gamma_a`, in Kahanes's # paper represented as {gamma_a, gamma_b, ... , gamma_z}, # virtual indices are ignored. The variable `connected_components` is # increased by one for every connected component this loop encounters. # If the connected component has virtual and dummy indices only # (no free indices), it contributes to `resulting_indices` by a factor of two. # The multiplication by two is a result of the # factor {gamma^0, gamma^0} = 2 I, as it appears in Kahane's paper. # Note: curly brackets are meant as in the paper, as a generalized # multi-element anticommutator! while links: connected_components += 1 pointer = min(links.keys()) previous_pointer = pointer # the inner loop erases the visited indices from `links`, and it adds # all free indices to `prepend_indices` list, virtual indices are # ignored. prepend_indices = [] while True: if pointer in links: next_ones = links.pop(pointer) else: break if previous_pointer in next_ones: if len(next_ones) > 1: next_ones.remove(previous_pointer) previous_pointer = pointer if next_ones: pointer = next_ones[0] if pointer >= first_dum_pos and free_pos[pointer] is not None: prepend_indices.insert(0, free_pos[pointer]) # if `prepend_indices` is void, it means there are no free indices # in the loop (and it can be shown that there must be a virtual index), # loops of virtual indices only contribute by a factor of two: if len(prepend_indices) == 0: resulting_coeff *= 2 # otherwise, add the free indices in `prepend_indices` to # the `resulting_indices`: else: expr1 = prepend_indices expr2 = list(reversed(prepend_indices)) resulting_indices = [expri + ri for ri in resulting_indices for expri in (expr1, expr2)] # sign correction, as described in Kahane's paper: resulting_coeff *= -1 if (number_of_contractions - connected_components + 1) % 2 else 1 # power of two factor, as described in Kahane's paper: resulting_coeff *= 2**(number_of_contractions) # If `first_dum_pos` is not zero, it means that there are trailing free gamma # matrices in front of `expression`, so multiply by them: for i in range(0, first_dum_pos): [ri.insert(0, free_pos[i]) for ri in resulting_indices] resulting_expr = S.Zero for i in resulting_indices: temp_expr = S.One for j in i: temp_expr *= GammaMatrix(j) resulting_expr += temp_expr t = resulting_coeff * resulting_expr t1 = None if isinstance(t, TensAdd): t1 = t.args[0] elif isinstance(t, TensMul): t1 = t if t1: pass else: t = eye(4)*t return t sympy-sympy-1.9/sympy/physics/hep/tests/000077500000000000000000000000001412543434000205045ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/hep/tests/__init__.py000066400000000000000000000000001412543434000226030ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/hep/tests/test_gamma_matrices.py000066400000000000000000000327641412543434000251020ustar00rootroot00000000000000from sympy import Matrix from sympy.tensor.tensor import tensor_indices, TensorHead, tensor_heads, \ TensExpr, canon_bp from sympy import eye from sympy.physics.hep.gamma_matrices import GammaMatrix as G, LorentzIndex, \ kahane_simplify, gamma_trace, _simplify_single_line, simplify_gamma_expression def _is_tensor_eq(arg1, arg2): arg1 = canon_bp(arg1) arg2 = canon_bp(arg2) if isinstance(arg1, TensExpr): return arg1.equals(arg2) elif isinstance(arg2, TensExpr): return arg2.equals(arg1) return arg1 == arg2 def execute_gamma_simplify_tests_for_function(tfunc, D): """ Perform tests to check if sfunc is able to simplify gamma matrix expressions. Parameters ========== `sfunc` a function to simplify a `TIDS`, shall return the simplified `TIDS`. `D` the number of dimension (in most cases `D=4`). """ mu, nu, rho, sigma = tensor_indices("mu, nu, rho, sigma", LorentzIndex) a1, a2, a3, a4, a5, a6 = tensor_indices("a1:7", LorentzIndex) mu11, mu12, mu21, mu31, mu32, mu41, mu51, mu52 = tensor_indices("mu11, mu12, mu21, mu31, mu32, mu41, mu51, mu52", LorentzIndex) mu61, mu71, mu72 = tensor_indices("mu61, mu71, mu72", LorentzIndex) m0, m1, m2, m3, m4, m5, m6 = tensor_indices("m0:7", LorentzIndex) def g(xx, yy): return (G(xx)*G(yy) + G(yy)*G(xx))/2 # Some examples taken from Kahane's paper, 4 dim only: if D == 4: t = (G(a1)*G(mu11)*G(a2)*G(mu21)*G(-a1)*G(mu31)*G(-a2)) assert _is_tensor_eq(tfunc(t), -4*G(mu11)*G(mu31)*G(mu21) - 4*G(mu31)*G(mu11)*G(mu21)) t = (G(a1)*G(mu11)*G(mu12)*\ G(a2)*G(mu21)*\ G(a3)*G(mu31)*G(mu32)*\ G(a4)*G(mu41)*\ G(-a2)*G(mu51)*G(mu52)*\ G(-a1)*G(mu61)*\ G(-a3)*G(mu71)*G(mu72)*\ G(-a4)) assert _is_tensor_eq(tfunc(t), \ 16*G(mu31)*G(mu32)*G(mu72)*G(mu71)*G(mu11)*G(mu52)*G(mu51)*G(mu12)*G(mu61)*G(mu21)*G(mu41) + 16*G(mu31)*G(mu32)*G(mu72)*G(mu71)*G(mu12)*G(mu51)*G(mu52)*G(mu11)*G(mu61)*G(mu21)*G(mu41) + 16*G(mu71)*G(mu72)*G(mu32)*G(mu31)*G(mu11)*G(mu52)*G(mu51)*G(mu12)*G(mu61)*G(mu21)*G(mu41) + 16*G(mu71)*G(mu72)*G(mu32)*G(mu31)*G(mu12)*G(mu51)*G(mu52)*G(mu11)*G(mu61)*G(mu21)*G(mu41)) # Fully Lorentz-contracted expressions, these return scalars: def add_delta(ne): return ne * eye(4) # DiracSpinorIndex.delta(DiracSpinorIndex.auto_left, -DiracSpinorIndex.auto_right) t = (G(mu)*G(-mu)) ts = add_delta(D) assert _is_tensor_eq(tfunc(t), ts) t = (G(mu)*G(nu)*G(-mu)*G(-nu)) ts = add_delta(2*D - D**2) # -8 assert _is_tensor_eq(tfunc(t), ts) t = (G(mu)*G(nu)*G(-nu)*G(-mu)) ts = add_delta(D**2) # 16 assert _is_tensor_eq(tfunc(t), ts) t = (G(mu)*G(nu)*G(-rho)*G(-nu)*G(-mu)*G(rho)) ts = add_delta(4*D - 4*D**2 + D**3) # 16 assert _is_tensor_eq(tfunc(t), ts) t = (G(mu)*G(nu)*G(rho)*G(-rho)*G(-nu)*G(-mu)) ts = add_delta(D**3) # 64 assert _is_tensor_eq(tfunc(t), ts) t = (G(a1)*G(a2)*G(a3)*G(a4)*G(-a3)*G(-a1)*G(-a2)*G(-a4)) ts = add_delta(-8*D + 16*D**2 - 8*D**3 + D**4) # -32 assert _is_tensor_eq(tfunc(t), ts) t = (G(-mu)*G(-nu)*G(-rho)*G(-sigma)*G(nu)*G(mu)*G(sigma)*G(rho)) ts = add_delta(-16*D + 24*D**2 - 8*D**3 + D**4) # 64 assert _is_tensor_eq(tfunc(t), ts) t = (G(-mu)*G(nu)*G(-rho)*G(sigma)*G(rho)*G(-nu)*G(mu)*G(-sigma)) ts = add_delta(8*D - 12*D**2 + 6*D**3 - D**4) # -32 assert _is_tensor_eq(tfunc(t), ts) t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(-a3)*G(-a2)*G(-a1)*G(-a5)*G(-a4)) ts = add_delta(64*D - 112*D**2 + 60*D**3 - 12*D**4 + D**5) # 256 assert _is_tensor_eq(tfunc(t), ts) t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(-a3)*G(-a1)*G(-a2)*G(-a4)*G(-a5)) ts = add_delta(64*D - 120*D**2 + 72*D**3 - 16*D**4 + D**5) # -128 assert _is_tensor_eq(tfunc(t), ts) t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(a6)*G(-a3)*G(-a2)*G(-a1)*G(-a6)*G(-a5)*G(-a4)) ts = add_delta(416*D - 816*D**2 + 528*D**3 - 144*D**4 + 18*D**5 - D**6) # -128 assert _is_tensor_eq(tfunc(t), ts) t = (G(a1)*G(a2)*G(a3)*G(a4)*G(a5)*G(a6)*G(-a2)*G(-a3)*G(-a1)*G(-a6)*G(-a4)*G(-a5)) ts = add_delta(416*D - 848*D**2 + 584*D**3 - 172*D**4 + 22*D**5 - D**6) # -128 assert _is_tensor_eq(tfunc(t), ts) # Expressions with free indices: t = (G(mu)*G(nu)*G(rho)*G(sigma)*G(-mu)) assert _is_tensor_eq(tfunc(t), (-2*G(sigma)*G(rho)*G(nu) + (4-D)*G(nu)*G(rho)*G(sigma))) t = (G(mu)*G(nu)*G(-mu)) assert _is_tensor_eq(tfunc(t), (2-D)*G(nu)) t = (G(mu)*G(nu)*G(rho)*G(-mu)) assert _is_tensor_eq(tfunc(t), 2*G(nu)*G(rho) + 2*G(rho)*G(nu) - (4-D)*G(nu)*G(rho)) t = 2*G(m2)*G(m0)*G(m1)*G(-m0)*G(-m1) st = tfunc(t) assert _is_tensor_eq(st, (D*(-2*D + 4))*G(m2)) t = G(m2)*G(m0)*G(m1)*G(-m0)*G(-m2) st = tfunc(t) assert _is_tensor_eq(st, ((-D + 2)**2)*G(m1)) t = G(m0)*G(m1)*G(m2)*G(m3)*G(-m1) st = tfunc(t) assert _is_tensor_eq(st, (D - 4)*G(m0)*G(m2)*G(m3) + 4*G(m0)*g(m2, m3)) t = G(m0)*G(m1)*G(m2)*G(m3)*G(-m1)*G(-m0) st = tfunc(t) assert _is_tensor_eq(st, ((D - 4)**2)*G(m2)*G(m3) + (8*D - 16)*g(m2, m3)) t = G(m2)*G(m0)*G(m1)*G(-m2)*G(-m0) st = tfunc(t) assert _is_tensor_eq(st, ((-D + 2)*(D - 4) + 4)*G(m1)) t = G(m3)*G(m1)*G(m0)*G(m2)*G(-m3)*G(-m0)*G(-m2) st = tfunc(t) assert _is_tensor_eq(st, (-4*D + (-D + 2)**2*(D - 4) + 8)*G(m1)) t = 2*G(m0)*G(m1)*G(m2)*G(m3)*G(-m0) st = tfunc(t) assert _is_tensor_eq(st, ((-2*D + 8)*G(m1)*G(m2)*G(m3) - 4*G(m3)*G(m2)*G(m1))) t = G(m5)*G(m0)*G(m1)*G(m4)*G(m2)*G(-m4)*G(m3)*G(-m0) st = tfunc(t) assert _is_tensor_eq(st, (((-D + 2)*(-D + 4))*G(m5)*G(m1)*G(m2)*G(m3) + (2*D - 4)*G(m5)*G(m3)*G(m2)*G(m1))) t = -G(m0)*G(m1)*G(m2)*G(m3)*G(-m0)*G(m4) st = tfunc(t) assert _is_tensor_eq(st, ((D - 4)*G(m1)*G(m2)*G(m3)*G(m4) + 2*G(m3)*G(m2)*G(m1)*G(m4))) t = G(-m5)*G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(-m0)*G(m5) st = tfunc(t) result1 = ((-D + 4)**2 + 4)*G(m1)*G(m2)*G(m3)*G(m4) +\ (4*D - 16)*G(m3)*G(m2)*G(m1)*G(m4) + (4*D - 16)*G(m4)*G(m1)*G(m2)*G(m3)\ + 4*G(m2)*G(m1)*G(m4)*G(m3) + 4*G(m3)*G(m4)*G(m1)*G(m2) +\ 4*G(m4)*G(m3)*G(m2)*G(m1) # Kahane's algorithm yields this result, which is equivalent to `result1` # in four dimensions, but is not automatically recognized as equal: result2 = 8*G(m1)*G(m2)*G(m3)*G(m4) + 8*G(m4)*G(m3)*G(m2)*G(m1) if D == 4: assert _is_tensor_eq(st, (result1)) or _is_tensor_eq(st, (result2)) else: assert _is_tensor_eq(st, (result1)) # and a few very simple cases, with no contracted indices: t = G(m0) st = tfunc(t) assert _is_tensor_eq(st, t) t = -7*G(m0) st = tfunc(t) assert _is_tensor_eq(st, t) t = 224*G(m0)*G(m1)*G(-m2)*G(m3) st = tfunc(t) assert _is_tensor_eq(st, t) def test_kahane_algorithm(): # Wrap this function to convert to and from TIDS: def tfunc(e): return _simplify_single_line(e) execute_gamma_simplify_tests_for_function(tfunc, D=4) def test_kahane_simplify1(): i0,i1,i2,i3,i4,i5,i6,i7,i8,i9,i10,i11,i12,i13,i14,i15 = tensor_indices('i0:16', LorentzIndex) mu, nu, rho, sigma = tensor_indices("mu, nu, rho, sigma", LorentzIndex) D = 4 t = G(i0)*G(i1) r = kahane_simplify(t) assert r.equals(t) t = G(i0)*G(i1)*G(-i0) r = kahane_simplify(t) assert r.equals(-2*G(i1)) t = G(i0)*G(i1)*G(-i0) r = kahane_simplify(t) assert r.equals(-2*G(i1)) t = G(i0)*G(i1) r = kahane_simplify(t) assert r.equals(t) t = G(i0)*G(i1) r = kahane_simplify(t) assert r.equals(t) t = G(i0)*G(-i0) r = kahane_simplify(t) assert r.equals(4*eye(4)) t = G(i0)*G(-i0) r = kahane_simplify(t) assert r.equals(4*eye(4)) t = G(i0)*G(-i0) r = kahane_simplify(t) assert r.equals(4*eye(4)) t = G(i0)*G(i1)*G(-i0) r = kahane_simplify(t) assert r.equals(-2*G(i1)) t = G(i0)*G(i1)*G(-i0)*G(-i1) r = kahane_simplify(t) assert r.equals((2*D - D**2)*eye(4)) t = G(i0)*G(i1)*G(-i0)*G(-i1) r = kahane_simplify(t) assert r.equals((2*D - D**2)*eye(4)) t = G(i0)*G(-i0)*G(i1)*G(-i1) r = kahane_simplify(t) assert r.equals(16*eye(4)) t = (G(mu)*G(nu)*G(-nu)*G(-mu)) r = kahane_simplify(t) assert r.equals(D**2*eye(4)) t = (G(mu)*G(nu)*G(-nu)*G(-mu)) r = kahane_simplify(t) assert r.equals(D**2*eye(4)) t = (G(mu)*G(nu)*G(-nu)*G(-mu)) r = kahane_simplify(t) assert r.equals(D**2*eye(4)) t = (G(mu)*G(nu)*G(-rho)*G(-nu)*G(-mu)*G(rho)) r = kahane_simplify(t) assert r.equals((4*D - 4*D**2 + D**3)*eye(4)) t = (G(-mu)*G(-nu)*G(-rho)*G(-sigma)*G(nu)*G(mu)*G(sigma)*G(rho)) r = kahane_simplify(t) assert r.equals((-16*D + 24*D**2 - 8*D**3 + D**4)*eye(4)) t = (G(-mu)*G(nu)*G(-rho)*G(sigma)*G(rho)*G(-nu)*G(mu)*G(-sigma)) r = kahane_simplify(t) assert r.equals((8*D - 12*D**2 + 6*D**3 - D**4)*eye(4)) # Expressions with free indices: t = (G(mu)*G(nu)*G(rho)*G(sigma)*G(-mu)) r = kahane_simplify(t) assert r.equals(-2*G(sigma)*G(rho)*G(nu)) t = (G(mu)*G(nu)*G(rho)*G(sigma)*G(-mu)) r = kahane_simplify(t) assert r.equals(-2*G(sigma)*G(rho)*G(nu)) def test_gamma_matrix_class(): i, j, k = tensor_indices('i,j,k', LorentzIndex) # define another type of TensorHead to see if exprs are correctly handled: A = TensorHead('A', [LorentzIndex]) t = A(k)*G(i)*G(-i) ts = simplify_gamma_expression(t) assert _is_tensor_eq(ts, Matrix([ [4, 0, 0, 0], [0, 4, 0, 0], [0, 0, 4, 0], [0, 0, 0, 4]])*A(k)) t = G(i)*A(k)*G(j) ts = simplify_gamma_expression(t) assert _is_tensor_eq(ts, A(k)*G(i)*G(j)) execute_gamma_simplify_tests_for_function(simplify_gamma_expression, D=4) def test_gamma_matrix_trace(): g = LorentzIndex.metric m0, m1, m2, m3, m4, m5, m6 = tensor_indices('m0:7', LorentzIndex) n0, n1, n2, n3, n4, n5 = tensor_indices('n0:6', LorentzIndex) # working in D=4 dimensions D = 4 # traces of odd number of gamma matrices are zero: t = G(m0) t1 = gamma_trace(t) assert t1.equals(0) t = G(m0)*G(m1)*G(m2) t1 = gamma_trace(t) assert t1.equals(0) t = G(m0)*G(m1)*G(-m0) t1 = gamma_trace(t) assert t1.equals(0) t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4) t1 = gamma_trace(t) assert t1.equals(0) # traces without internal contractions: t = G(m0)*G(m1) t1 = gamma_trace(t) assert _is_tensor_eq(t1, 4*g(m0, m1)) t = G(m0)*G(m1)*G(m2)*G(m3) t1 = gamma_trace(t) t2 = -4*g(m0, m2)*g(m1, m3) + 4*g(m0, m1)*g(m2, m3) + 4*g(m0, m3)*g(m1, m2) assert _is_tensor_eq(t1, t2) t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(m5) t1 = gamma_trace(t) t2 = t1*g(-m0, -m5) t2 = t2.contract_metric(g) assert _is_tensor_eq(t2, D*gamma_trace(G(m1)*G(m2)*G(m3)*G(m4))) # traces of expressions with internal contractions: t = G(m0)*G(-m0) t1 = gamma_trace(t) assert t1.equals(4*D) t = G(m0)*G(m1)*G(-m0)*G(-m1) t1 = gamma_trace(t) assert t1.equals(8*D - 4*D**2) t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(-m0) t1 = gamma_trace(t) t2 = (-4*D)*g(m1, m3)*g(m2, m4) + (4*D)*g(m1, m2)*g(m3, m4) + \ (4*D)*g(m1, m4)*g(m2, m3) assert _is_tensor_eq(t1, t2) t = G(-m5)*G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(-m0)*G(m5) t1 = gamma_trace(t) t2 = (32*D + 4*(-D + 4)**2 - 64)*(g(m1, m2)*g(m3, m4) - \ g(m1, m3)*g(m2, m4) + g(m1, m4)*g(m2, m3)) assert _is_tensor_eq(t1, t2) t = G(m0)*G(m1)*G(-m0)*G(m3) t1 = gamma_trace(t) assert t1.equals((-4*D + 8)*g(m1, m3)) # p, q = S1('p,q') # ps = p(m0)*G(-m0) # qs = q(m0)*G(-m0) # t = ps*qs*ps*qs # t1 = gamma_trace(t) # assert t1 == 8*p(m0)*q(-m0)*p(m1)*q(-m1) - 4*p(m0)*p(-m0)*q(m1)*q(-m1) t = G(m0)*G(m1)*G(m2)*G(m3)*G(m4)*G(m5)*G(-m0)*G(-m1)*G(-m2)*G(-m3)*G(-m4)*G(-m5) t1 = gamma_trace(t) assert t1.equals(-4*D**6 + 120*D**5 - 1040*D**4 + 3360*D**3 - 4480*D**2 + 2048*D) t = G(m0)*G(m1)*G(n1)*G(m2)*G(n2)*G(m3)*G(m4)*G(-n2)*G(-n1)*G(-m0)*G(-m1)*G(-m2)*G(-m3)*G(-m4) t1 = gamma_trace(t) tresu = -7168*D + 16768*D**2 - 14400*D**3 + 5920*D**4 - 1232*D**5 + 120*D**6 - 4*D**7 assert t1.equals(tresu) # checked with Mathematica # In[1]:= <>> from sympy.physics.hydrogen import R_nl >>> from sympy.abc import r, Z >>> R_nl(1, 0, r, Z) 2*sqrt(Z**3)*exp(-Z*r) >>> R_nl(2, 0, r, Z) sqrt(2)*(-Z*r + 2)*sqrt(Z**3)*exp(-Z*r/2)/4 >>> R_nl(2, 1, r, Z) sqrt(6)*Z*r*sqrt(Z**3)*exp(-Z*r/2)/12 For Hydrogen atom, you can just use the default value of Z=1: >>> R_nl(1, 0, r) 2*exp(-r) >>> R_nl(2, 0, r) sqrt(2)*(2 - r)*exp(-r/2)/4 >>> R_nl(3, 0, r) 2*sqrt(3)*(2*r**2/9 - 2*r + 3)*exp(-r/3)/27 For Silver atom, you would use Z=47: >>> R_nl(1, 0, r, Z=47) 94*sqrt(47)*exp(-47*r) >>> R_nl(2, 0, r, Z=47) 47*sqrt(94)*(2 - 47*r)*exp(-47*r/2)/4 >>> R_nl(3, 0, r, Z=47) 94*sqrt(141)*(4418*r**2/9 - 94*r + 3)*exp(-47*r/3)/27 The normalization of the radial wavefunction is: >>> from sympy import integrate, oo >>> integrate(R_nl(1, 0, r)**2 * r**2, (r, 0, oo)) 1 >>> integrate(R_nl(2, 0, r)**2 * r**2, (r, 0, oo)) 1 >>> integrate(R_nl(2, 1, r)**2 * r**2, (r, 0, oo)) 1 It holds for any atomic number: >>> integrate(R_nl(1, 0, r, Z=2)**2 * r**2, (r, 0, oo)) 1 >>> integrate(R_nl(2, 0, r, Z=3)**2 * r**2, (r, 0, oo)) 1 >>> integrate(R_nl(2, 1, r, Z=4)**2 * r**2, (r, 0, oo)) 1 """ # sympify arguments n, l, r, Z = map(S, [n, l, r, Z]) # radial quantum number n_r = n - l - 1 # rescaled "r" a = 1/Z # Bohr radius r0 = 2 * r / (n * a) # normalization coefficient C = sqrt((S(2)/(n*a))**3 * factorial(n_r) / (2*n*factorial(n + l))) # This is an equivalent normalization coefficient, that can be found in # some books. Both coefficients seem to be the same fast: # C = S(2)/n**2 * sqrt(1/a**3 * factorial(n_r) / (factorial(n+l))) return C * r0**l * assoc_laguerre(n_r, 2*l + 1, r0).expand() * exp(-r0/2) def Psi_nlm(n, l, m, r, phi, theta, Z=1): """ Returns the Hydrogen wave function psi_{nlm}. It's the product of the radial wavefunction R_{nl} and the spherical harmonic Y_{l}^{m}. Parameters ========== n : integer Principal Quantum Number which is an integer with possible values as 1, 2, 3, 4,... l : integer ``l`` is the Angular Momentum Quantum Number with values ranging from 0 to ``n-1``. m : integer ``m`` is the Magnetic Quantum Number with values ranging from ``-l`` to ``l``. r : radial coordinate phi : azimuthal angle theta : polar angle Z : atomic number (1 for Hydrogen, 2 for Helium, ...) Everything is in Hartree atomic units. Examples ======== >>> from sympy.physics.hydrogen import Psi_nlm >>> from sympy import Symbol >>> r=Symbol("r", real=True, positive=True) >>> phi=Symbol("phi", real=True) >>> theta=Symbol("theta", real=True) >>> Z=Symbol("Z", positive=True, integer=True, nonzero=True) >>> Psi_nlm(1,0,0,r,phi,theta,Z) Z**(3/2)*exp(-Z*r)/sqrt(pi) >>> Psi_nlm(2,1,1,r,phi,theta,Z) -Z**(5/2)*r*exp(I*phi)*exp(-Z*r/2)*sin(theta)/(8*sqrt(pi)) Integrating the absolute square of a hydrogen wavefunction psi_{nlm} over the whole space leads 1. The normalization of the hydrogen wavefunctions Psi_nlm is: >>> from sympy import integrate, conjugate, pi, oo, sin >>> wf=Psi_nlm(2,1,1,r,phi,theta,Z) >>> abs_sqrd=wf*conjugate(wf) >>> jacobi=r**2*sin(theta) >>> integrate(abs_sqrd*jacobi, (r,0,oo), (phi,0,2*pi), (theta,0,pi)) 1 """ # sympify arguments n, l, m, r, phi, theta, Z = map(S, [n, l, m, r, phi, theta, Z]) # check if values for n,l,m make physically sense if n.is_integer and n < 1: raise ValueError("'n' must be positive integer") if l.is_integer and not (n > l): raise ValueError("'n' must be greater than 'l'") if m.is_integer and not (abs(m) <= l): raise ValueError("|'m'| must be less or equal 'l'") # return the hydrogen wave function return R_nl(n, l, r, Z)*Ynm(l, m, theta, phi).expand(func=True) def E_nl(n, Z=1): """ Returns the energy of the state (n, l) in Hartree atomic units. The energy doesn't depend on "l". Parameters ========== n : integer Principal Quantum Number which is an integer with possible values as 1, 2, 3, 4,... Z : Atomic number (1 for Hydrogen, 2 for Helium, ...) Examples ======== >>> from sympy.physics.hydrogen import E_nl >>> from sympy.abc import n, Z >>> E_nl(n, Z) -Z**2/(2*n**2) >>> E_nl(1) -1/2 >>> E_nl(2) -1/8 >>> E_nl(3) -1/18 >>> E_nl(3, 47) -2209/18 """ n, Z = S(n), S(Z) if n.is_integer and (n < 1): raise ValueError("'n' must be positive integer") return -Z**2/(2*n**2) def E_nl_dirac(n, l, spin_up=True, Z=1, c=Float("137.035999037")): """ Returns the relativistic energy of the state (n, l, spin) in Hartree atomic units. The energy is calculated from the Dirac equation. The rest mass energy is *not* included. Parameters ========== n : integer Principal Quantum Number which is an integer with possible values as 1, 2, 3, 4,... l : integer ``l`` is the Angular Momentum Quantum Number with values ranging from 0 to ``n-1``. spin_up : True if the electron spin is up (default), otherwise down Z : Atomic number (1 for Hydrogen, 2 for Helium, ...) c : Speed of light in atomic units. Default value is 137.035999037, taken from http://arxiv.org/abs/1012.3627 Examples ======== >>> from sympy.physics.hydrogen import E_nl_dirac >>> E_nl_dirac(1, 0) -0.500006656595360 >>> E_nl_dirac(2, 0) -0.125002080189006 >>> E_nl_dirac(2, 1) -0.125000416028342 >>> E_nl_dirac(2, 1, False) -0.125002080189006 >>> E_nl_dirac(3, 0) -0.0555562951740285 >>> E_nl_dirac(3, 1) -0.0555558020932949 >>> E_nl_dirac(3, 1, False) -0.0555562951740285 >>> E_nl_dirac(3, 2) -0.0555556377366884 >>> E_nl_dirac(3, 2, False) -0.0555558020932949 """ n, l, Z, c = map(S, [n, l, Z, c]) if not (l >= 0): raise ValueError("'l' must be positive or zero") if not (n > l): raise ValueError("'n' must be greater than 'l'") if (l == 0 and spin_up is False): raise ValueError("Spin must be up for l==0.") # skappa is sign*kappa, where sign contains the correct sign if spin_up: skappa = -l - 1 else: skappa = -l beta = sqrt(skappa**2 - Z**2/c**2) return c**2/sqrt(1 + Z**2/(n + skappa + beta)**2/c**2) - c**2 sympy-sympy-1.9/sympy/physics/matrices.py000066400000000000000000000075001412543434000207510ustar00rootroot00000000000000"""Known matrices related to physics""" from sympy import Matrix, I, pi, sqrt from sympy.functions import exp from sympy.core.decorators import deprecated def msigma(i): r"""Returns a Pauli matrix `\sigma_i` with ``i=1,2,3``. References ========== .. [1] https://en.wikipedia.org/wiki/Pauli_matrices Examples ======== >>> from sympy.physics.matrices import msigma >>> msigma(1) Matrix([ [0, 1], [1, 0]]) """ if i == 1: mat = ( ( (0, 1), (1, 0) ) ) elif i == 2: mat = ( ( (0, -I), (I, 0) ) ) elif i == 3: mat = ( ( (1, 0), (0, -1) ) ) else: raise IndexError("Invalid Pauli index") return Matrix(mat) def pat_matrix(m, dx, dy, dz): """Returns the Parallel Axis Theorem matrix to translate the inertia matrix a distance of `(dx, dy, dz)` for a body of mass m. Examples ======== To translate a body having a mass of 2 units a distance of 1 unit along the `x`-axis we get: >>> from sympy.physics.matrices import pat_matrix >>> pat_matrix(2, 1, 0, 0) Matrix([ [0, 0, 0], [0, 2, 0], [0, 0, 2]]) """ dxdy = -dx*dy dydz = -dy*dz dzdx = -dz*dx dxdx = dx**2 dydy = dy**2 dzdz = dz**2 mat = ((dydy + dzdz, dxdy, dzdx), (dxdy, dxdx + dzdz, dydz), (dzdx, dydz, dydy + dxdx)) return m*Matrix(mat) def mgamma(mu, lower=False): r"""Returns a Dirac gamma matrix `\gamma^\mu` in the standard (Dirac) representation. Explanation =========== If you want `\gamma_\mu`, use ``gamma(mu, True)``. We use a convention: `\gamma^5 = i \cdot \gamma^0 \cdot \gamma^1 \cdot \gamma^2 \cdot \gamma^3` `\gamma_5 = i \cdot \gamma_0 \cdot \gamma_1 \cdot \gamma_2 \cdot \gamma_3 = - \gamma^5` References ========== .. [1] https://en.wikipedia.org/wiki/Gamma_matrices Examples ======== >>> from sympy.physics.matrices import mgamma >>> mgamma(1) Matrix([ [ 0, 0, 0, 1], [ 0, 0, 1, 0], [ 0, -1, 0, 0], [-1, 0, 0, 0]]) """ if not mu in [0, 1, 2, 3, 5]: raise IndexError("Invalid Dirac index") if mu == 0: mat = ( (1, 0, 0, 0), (0, 1, 0, 0), (0, 0, -1, 0), (0, 0, 0, -1) ) elif mu == 1: mat = ( (0, 0, 0, 1), (0, 0, 1, 0), (0, -1, 0, 0), (-1, 0, 0, 0) ) elif mu == 2: mat = ( (0, 0, 0, -I), (0, 0, I, 0), (0, I, 0, 0), (-I, 0, 0, 0) ) elif mu == 3: mat = ( (0, 0, 1, 0), (0, 0, 0, -1), (-1, 0, 0, 0), (0, 1, 0, 0) ) elif mu == 5: mat = ( (0, 0, 1, 0), (0, 0, 0, 1), (1, 0, 0, 0), (0, 1, 0, 0) ) m = Matrix(mat) if lower: if mu in [1, 2, 3, 5]: m = -m return m #Minkowski tensor using the convention (+,-,-,-) used in the Quantum Field #Theory minkowski_tensor = Matrix( ( (1, 0, 0, 0), (0, -1, 0, 0), (0, 0, -1, 0), (0, 0, 0, -1) )) @deprecated(issue=20246, useinstead="DFT(n).as_mutable(), DFT(n), DFT(n).as_explicit()", deprecated_since_version="1.9") def mdft(n): r""" Deprecated. Use DFT from sympy.matrices.expressions.fourier instead. To get identical behavior to ``mdft(n)``, use ``DFT(n).as_mutable()``. """ mat = [[None for x in range(n)] for y in range(n)] base = exp(-2*pi*I/n) mat[0] = [1]*n for i in range(n): mat[i][0] = 1 for i in range(1, n): for j in range(i, n): mat[i][j] = mat[j][i] = base**(i*j) return (1/sqrt(n))*Matrix(mat) sympy-sympy-1.9/sympy/physics/mechanics/000077500000000000000000000000001412543434000205205ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/mechanics/__init__.py000066400000000000000000000035331412543434000226350ustar00rootroot00000000000000__all__ = [ 'vector', 'CoordinateSym', 'ReferenceFrame', 'Dyadic', 'Vector', 'Point', 'cross', 'dot', 'express', 'time_derivative', 'outer', 'kinematic_equations', 'get_motion_params', 'partial_velocity', 'dynamicsymbols', 'vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex', 'init_vprinting', 'curl', 'divergence', 'gradient', 'is_conservative', 'is_solenoidal', 'scalar_potential', 'scalar_potential_difference', 'KanesMethod', 'RigidBody', 'inertia', 'inertia_of_point_mass', 'linear_momentum', 'angular_momentum', 'kinetic_energy', 'potential_energy', 'Lagrangian', 'mechanics_printing', 'mprint', 'msprint', 'mpprint', 'mlatex', 'msubs', 'find_dynamicsymbols', 'Particle', 'LagrangesMethod', 'Linearizer', 'Body', 'SymbolicSystem', 'PinJoint', 'PrismaticJoint', 'JointsMethod' ] from sympy.physics import vector from sympy.physics.vector import (CoordinateSym, ReferenceFrame, Dyadic, Vector, Point, cross, dot, express, time_derivative, outer, kinematic_equations, get_motion_params, partial_velocity, dynamicsymbols, vprint, vsstrrepr, vsprint, vpprint, vlatex, init_vprinting, curl, divergence, gradient, is_conservative, is_solenoidal, scalar_potential, scalar_potential_difference) from .kane import KanesMethod from .rigidbody import RigidBody from .functions import (inertia, inertia_of_point_mass, linear_momentum, angular_momentum, kinetic_energy, potential_energy, Lagrangian, mechanics_printing, mprint, msprint, mpprint, mlatex, msubs, find_dynamicsymbols) from .particle import Particle from .lagrange import LagrangesMethod from .linearize import Linearizer from .body import Body from .system import SymbolicSystem from .jointsmethod import JointsMethod from .joint import PinJoint, PrismaticJoint sympy-sympy-1.9/sympy/physics/mechanics/body.py000066400000000000000000000422401412543434000220310ustar00rootroot00000000000000from sympy.core.backend import Symbol from sympy.physics.vector import Point, Vector, ReferenceFrame from sympy.physics.mechanics import RigidBody, Particle, inertia __all__ = ['Body'] # XXX: We use type:ignore because the classes RigidBody and Particle have # inconsistent parallel axis methods that take different numbers of arguments. class Body(RigidBody, Particle): # type: ignore """ Body is a common representation of either a RigidBody or a Particle SymPy object depending on what is passed in during initialization. If a mass is passed in and central_inertia is left as None, the Particle object is created. Otherwise a RigidBody object will be created. Explanation =========== The attributes that Body possesses will be the same as a Particle instance or a Rigid Body instance depending on which was created. Additional attributes are listed below. Attributes ========== name : string The body's name masscenter : Point The point which represents the center of mass of the rigid body frame : ReferenceFrame The reference frame which the body is fixed in mass : Sympifyable The body's mass inertia : (Dyadic, Point) The body's inertia around its center of mass. This attribute is specific to the rigid body form of Body and is left undefined for the Particle form loads : iterable This list contains information on the different loads acting on the Body. Forces are listed as a (point, vector) tuple and torques are listed as (reference frame, vector) tuples. Parameters ========== name : String Defines the name of the body. It is used as the base for defining body specific properties. masscenter : Point, optional A point that represents the center of mass of the body or particle. If no point is given, a point is generated. mass : Sympifyable, optional A Sympifyable object which represents the mass of the body. If no mass is passed, one is generated. frame : ReferenceFrame, optional The ReferenceFrame that represents the reference frame of the body. If no frame is given, a frame is generated. central_inertia : Dyadic, optional Central inertia dyadic of the body. If none is passed while creating RigidBody, a default inertia is generated. Examples ======== Default behaviour. This results in the creation of a RigidBody object for which the mass, mass center, frame and inertia attributes are given default values. :: >>> from sympy.physics.mechanics import Body >>> body = Body('name_of_body') This next example demonstrates the code required to specify all of the values of the Body object. Note this will also create a RigidBody version of the Body object. :: >>> from sympy import Symbol >>> from sympy.physics.mechanics import ReferenceFrame, Point, inertia >>> from sympy.physics.mechanics import Body >>> mass = Symbol('mass') >>> masscenter = Point('masscenter') >>> frame = ReferenceFrame('frame') >>> ixx = Symbol('ixx') >>> body_inertia = inertia(frame, ixx, 0, 0) >>> body = Body('name_of_body', masscenter, mass, frame, body_inertia) The minimal code required to create a Particle version of the Body object involves simply passing in a name and a mass. :: >>> from sympy import Symbol >>> from sympy.physics.mechanics import Body >>> mass = Symbol('mass') >>> body = Body('name_of_body', mass=mass) The Particle version of the Body object can also receive a masscenter point and a reference frame, just not an inertia. """ def __init__(self, name, masscenter=None, mass=None, frame=None, central_inertia=None): self.name = name self._loads = [] if frame is None: frame = ReferenceFrame(name + '_frame') if masscenter is None: masscenter = Point(name + '_masscenter') if central_inertia is None and mass is None: ixx = Symbol(name + '_ixx') iyy = Symbol(name + '_iyy') izz = Symbol(name + '_izz') izx = Symbol(name + '_izx') ixy = Symbol(name + '_ixy') iyz = Symbol(name + '_iyz') _inertia = (inertia(frame, ixx, iyy, izz, ixy, iyz, izx), masscenter) else: _inertia = (central_inertia, masscenter) if mass is None: _mass = Symbol(name + '_mass') else: _mass = mass masscenter.set_vel(frame, 0) # If user passes masscenter and mass then a particle is created # otherwise a rigidbody. As a result a body may or may not have inertia. if central_inertia is None and mass is not None: self.frame = frame self.masscenter = masscenter Particle.__init__(self, name, masscenter, _mass) self._central_inertia = None else: RigidBody.__init__(self, name, masscenter, frame, _mass, _inertia) @property def loads(self): return self._loads @property def x(self): """The basis Vector for the Body, in the x direction. """ return self.frame.x @property def y(self): """The basis Vector for the Body, in the y direction. """ return self.frame.y @property def z(self): """The basis Vector for the Body, in the z direction. """ return self.frame.z @property def is_rigidbody(self): if self.central_inertia is not None: return True return False def kinetic_energy(self, frame): """Kinetic energy of the body. Parameters ========== frame : ReferenceFrame or Body The Body's angular velocity and the velocity of it's mass center are typically defined with respect to an inertial frame but any relevant frame in which the velocities are known can be supplied. Examples ======== >>> from sympy.physics.mechanics import Body, ReferenceFrame, Point >>> from sympy import symbols >>> m, v, r, omega = symbols('m v r omega') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> P = Body('P', masscenter=O, mass=m) >>> P.masscenter.set_vel(N, v * N.y) >>> P.kinetic_energy(N) m*v**2/2 >>> N = ReferenceFrame('N') >>> b = ReferenceFrame('b') >>> b.set_ang_vel(N, omega * b.x) >>> P = Point('P') >>> P.set_vel(N, v * N.x) >>> B = Body('B', masscenter=P, frame=b) >>> B.kinetic_energy(N) B_ixx*omega**2/2 + B_mass*v**2/2 See Also ======== sympy.physics.mechanics : Particle, RigidBody """ if isinstance(frame, Body): frame = Body.frame if self.is_rigidbody: return RigidBody(self.name, self.masscenter, self.frame, self.mass, (self.central_inertia, self.masscenter)).kinetic_energy(frame) return Particle(self.name, self.masscenter, self.mass).kinetic_energy(frame) def apply_force(self, force, point=None, reaction_body=None, reaction_point=None): """Add force to the body(s). Explanation =========== Applies the force on self or equal and oppposite forces on self and other body if both are given on the desried point on the bodies. The force applied on other body is taken opposite of self, i.e, -force. Parameters ========== force: Vector The force to be applied. point: Point, optional The point on self on which force is applied. By default self's masscenter. reaction_body: Body, optional Second body on which equal and opposite force is to be applied. reaction_point : Point, optional The point on other body on which equal and opposite force is applied. By default masscenter of other body. Example ======= >>> from sympy import symbols >>> from sympy.physics.mechanics import Body, Point, dynamicsymbols >>> m, g = symbols('m g') >>> B = Body('B') >>> force1 = m*g*B.z >>> B.apply_force(force1) #Applying force on B's masscenter >>> B.loads [(B_masscenter, g*m*B_frame.z)] We can also remove some part of force from any point on the body by adding the opposite force to the body on that point. >>> f1, f2 = dynamicsymbols('f1 f2') >>> P = Point('P') #Considering point P on body B >>> B.apply_force(f1*B.x + f2*B.y, P) >>> B.loads [(B_masscenter, g*m*B_frame.z), (P, f1(t)*B_frame.x + f2(t)*B_frame.y)] Let's remove f1 from point P on body B. >>> B.apply_force(-f1*B.x, P) >>> B.loads [(B_masscenter, g*m*B_frame.z), (P, f2(t)*B_frame.y)] To further demonstrate the use of ``apply_force`` attribute, consider two bodies connected through a spring. >>> from sympy.physics.mechanics import Body, dynamicsymbols >>> N = Body('N') #Newtonion Frame >>> x = dynamicsymbols('x') >>> B1 = Body('B1') >>> B2 = Body('B2') >>> spring_force = x*N.x Now let's apply equal and opposite spring force to the bodies. >>> P1 = Point('P1') >>> P2 = Point('P2') >>> B1.apply_force(spring_force, point=P1, reaction_body=B2, reaction_point=P2) We can check the loads(forces) applied to bodies now. >>> B1.loads [(P1, x(t)*N_frame.x)] >>> B2.loads [(P2, - x(t)*N_frame.x)] Notes ===== If a new force is applied to a body on a point which already has some force applied on it, then the new force is added to the already applied force on that point. """ if not isinstance(point, Point): if point is None: point = self.masscenter # masscenter else: raise TypeError("Force must be applied to a point on the body.") if not isinstance(force, Vector): raise TypeError("Force must be a vector.") if reaction_body is not None: reaction_body.apply_force(-force, point=reaction_point) for load in self._loads: if point in load: force += load[1] self._loads.remove(load) break self._loads.append((point, force)) def apply_torque(self, torque, reaction_body=None): """Add torque to the body(s). Explanation =========== Applies the torque on self or equal and oppposite torquess on self and other body if both are given. The torque applied on other body is taken opposite of self, i.e, -torque. Parameters ========== torque: Vector The torque to be applied. reaction_body: Body, optional Second body on which equal and opposite torque is to be applied. Example ======= >>> from sympy import symbols >>> from sympy.physics.mechanics import Body, dynamicsymbols >>> t = symbols('t') >>> B = Body('B') >>> torque1 = t*B.z >>> B.apply_torque(torque1) >>> B.loads [(B_frame, t*B_frame.z)] We can also remove some part of torque from the body by adding the opposite torque to the body. >>> t1, t2 = dynamicsymbols('t1 t2') >>> B.apply_torque(t1*B.x + t2*B.y) >>> B.loads [(B_frame, t1(t)*B_frame.x + t2(t)*B_frame.y + t*B_frame.z)] Let's remove t1 from Body B. >>> B.apply_torque(-t1*B.x) >>> B.loads [(B_frame, t2(t)*B_frame.y + t*B_frame.z)] To further demonstrate the use, let us consider two bodies such that a torque `T` is acting on one body, and `-T` on the other. >>> from sympy.physics.mechanics import Body, dynamicsymbols >>> N = Body('N') #Newtonion frame >>> B1 = Body('B1') >>> B2 = Body('B2') >>> v = dynamicsymbols('v') >>> T = v*N.y #Torque Now let's apply equal and opposite torque to the bodies. >>> B1.apply_torque(T, B2) We can check the loads (torques) applied to bodies now. >>> B1.loads [(B1_frame, v(t)*N_frame.y)] >>> B2.loads [(B2_frame, - v(t)*N_frame.y)] Notes ===== If a new torque is applied on body which already has some torque applied on it, then the new torque is added to the previous torque about the body's frame. """ if not isinstance(torque, Vector): raise TypeError("A Vector must be supplied to add torque.") if reaction_body is not None: reaction_body.apply_torque(-torque) for load in self._loads: if self.frame in load: torque += load[1] self._loads.remove(load) break self._loads.append((self.frame, torque)) def clear_loads(self): """ Clears the Body's loads list. Example ======= >>> from sympy.physics.mechanics import Body >>> B = Body('B') >>> force = B.x + B.y >>> B.apply_force(force) >>> B.loads [(B_masscenter, B_frame.x + B_frame.y)] >>> B.clear_loads() >>> B.loads [] """ self._loads = [] def remove_load(self, about=None): """ Remove load about a point or frame. Parameters ========== about : Point or ReferenceFrame, optional The point about which force is applied, and is to be removed. If about is None, then the torque about self's frame is removed. Example ======= >>> from sympy.physics.mechanics import Body, Point >>> B = Body('B') >>> P = Point('P') >>> f1 = B.x >>> f2 = B.y >>> B.apply_force(f1) >>> B.apply_force(f2, P) >>> B.loads [(B_masscenter, B_frame.x), (P, B_frame.y)] >>> B.remove_load(P) >>> B.loads [(B_masscenter, B_frame.x)] """ if about is not None: if not isinstance(about, Point): raise TypeError('Load is applied about Point or ReferenceFrame.') else: about = self.frame for load in self._loads: if about in load: self._loads.remove(load) break def masscenter_vel(self, body): """ Returns the velocity of the mass center with respect to the provided rigid body or reference frame. Parameters ========== body: Body or ReferenceFrame The rigid body or reference frame to calculate the velocity in. Example ======= >>> from sympy.physics.mechanics import Body >>> A = Body('A') >>> B = Body('B') >>> A.masscenter.set_vel(B.frame, 5*B.frame.x) >>> A.masscenter_vel(B) 5*B_frame.x >>> A.masscenter_vel(B.frame) 5*B_frame.x """ if isinstance(body, ReferenceFrame): frame=body elif isinstance(body, Body): frame = body.frame return self.masscenter.vel(frame) def ang_vel_in(self, body): """ Returns this body's angular velocity with respect to the provided rigid body or reference frame. Parameters ========== body: Body or ReferenceFrame The rigid body or reference frame to calculate the angular velocity in. Example ======= >>> from sympy.physics.mechanics import Body, ReferenceFrame >>> A = Body('A') >>> N = ReferenceFrame('N') >>> B = Body('B', frame=N) >>> A.frame.set_ang_vel(N, 5*N.x) >>> A.ang_vel_in(B) 5*N.x >>> A.ang_vel_in(N) 5*N.x """ if isinstance(body, ReferenceFrame): frame=body elif isinstance(body, Body): frame = body.frame return self.frame.ang_vel_in(frame) def dcm(self, body): """ Returns the direction cosine matrix of this body relative to the provided rigid body or reference frame. Parameters ========== body: Body or ReferenceFrame The rigid body or reference frame to calculate the dcm. Example ======= >>> from sympy.physics.mechanics import Body >>> A = Body('A') >>> B = Body('B') >>> A.frame.orient_axis(B.frame, B.frame.x, 5) >>> A.dcm(B) Matrix([ [1, 0, 0], [0, cos(5), sin(5)], [0, -sin(5), cos(5)]]) >>> A.dcm(B.frame) Matrix([ [1, 0, 0], [0, cos(5), sin(5)], [0, -sin(5), cos(5)]]) """ if isinstance(body, ReferenceFrame): frame=body elif isinstance(body, Body): frame = body.frame return self.frame.dcm(frame) sympy-sympy-1.9/sympy/physics/mechanics/functions.py000066400000000000000000000556431412543434000231170ustar00rootroot00000000000000from sympy.utilities import dict_merge from sympy.utilities.iterables import iterable from sympy.physics.vector import (Dyadic, Vector, ReferenceFrame, Point, dynamicsymbols) from sympy.physics.vector.printing import (vprint, vsprint, vpprint, vlatex, init_vprinting) from sympy.physics.mechanics.particle import Particle from sympy.physics.mechanics.rigidbody import RigidBody from sympy import simplify from sympy.core.backend import (Matrix, sympify, Mul, Derivative, sin, cos, tan, AppliedUndef, S) __all__ = ['inertia', 'inertia_of_point_mass', 'linear_momentum', 'angular_momentum', 'kinetic_energy', 'potential_energy', 'Lagrangian', 'mechanics_printing', 'mprint', 'msprint', 'mpprint', 'mlatex', 'msubs', 'find_dynamicsymbols'] # These are functions that we've moved and renamed during extracting the # basic vector calculus code from the mechanics packages. mprint = vprint msprint = vsprint mpprint = vpprint mlatex = vlatex def mechanics_printing(**kwargs): """ Initializes time derivative printing for all SymPy objects in mechanics module. """ init_vprinting(**kwargs) mechanics_printing.__doc__ = init_vprinting.__doc__ def inertia(frame, ixx, iyy, izz, ixy=0, iyz=0, izx=0): """Simple way to create inertia Dyadic object. Explanation =========== If you don't know what a Dyadic is, just treat this like the inertia tensor. Then, do the easy thing and define it in a body-fixed frame. Parameters ========== frame : ReferenceFrame The frame the inertia is defined in ixx : Sympifyable the xx element in the inertia dyadic iyy : Sympifyable the yy element in the inertia dyadic izz : Sympifyable the zz element in the inertia dyadic ixy : Sympifyable the xy element in the inertia dyadic iyz : Sympifyable the yz element in the inertia dyadic izx : Sympifyable the zx element in the inertia dyadic Examples ======== >>> from sympy.physics.mechanics import ReferenceFrame, inertia >>> N = ReferenceFrame('N') >>> inertia(N, 1, 2, 3) (N.x|N.x) + 2*(N.y|N.y) + 3*(N.z|N.z) """ if not isinstance(frame, ReferenceFrame): raise TypeError('Need to define the inertia in a frame') ol = sympify(ixx) * (frame.x | frame.x) ol += sympify(ixy) * (frame.x | frame.y) ol += sympify(izx) * (frame.x | frame.z) ol += sympify(ixy) * (frame.y | frame.x) ol += sympify(iyy) * (frame.y | frame.y) ol += sympify(iyz) * (frame.y | frame.z) ol += sympify(izx) * (frame.z | frame.x) ol += sympify(iyz) * (frame.z | frame.y) ol += sympify(izz) * (frame.z | frame.z) return ol def inertia_of_point_mass(mass, pos_vec, frame): """Inertia dyadic of a point mass relative to point O. Parameters ========== mass : Sympifyable Mass of the point mass pos_vec : Vector Position from point O to point mass frame : ReferenceFrame Reference frame to express the dyadic in Examples ======== >>> from sympy import symbols >>> from sympy.physics.mechanics import ReferenceFrame, inertia_of_point_mass >>> N = ReferenceFrame('N') >>> r, m = symbols('r m') >>> px = r * N.x >>> inertia_of_point_mass(m, px, N) m*r**2*(N.y|N.y) + m*r**2*(N.z|N.z) """ return mass * (((frame.x | frame.x) + (frame.y | frame.y) + (frame.z | frame.z)) * (pos_vec & pos_vec) - (pos_vec | pos_vec)) def linear_momentum(frame, *body): """Linear momentum of the system. Explanation =========== This function returns the linear momentum of a system of Particle's and/or RigidBody's. The linear momentum of a system is equal to the vector sum of the linear momentum of its constituents. Consider a system, S, comprised of a rigid body, A, and a particle, P. The linear momentum of the system, L, is equal to the vector sum of the linear momentum of the particle, L1, and the linear momentum of the rigid body, L2, i.e. L = L1 + L2 Parameters ========== frame : ReferenceFrame The frame in which linear momentum is desired. body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose linear momentum is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, linear_momentum >>> N = ReferenceFrame('N') >>> P = Point('P') >>> P.set_vel(N, 10 * N.x) >>> Pa = Particle('Pa', P, 1) >>> Ac = Point('Ac') >>> Ac.set_vel(N, 25 * N.y) >>> I = outer(N.x, N.x) >>> A = RigidBody('A', Ac, N, 20, (I, Ac)) >>> linear_momentum(N, A, Pa) 10*N.x + 500*N.y """ if not isinstance(frame, ReferenceFrame): raise TypeError('Please specify a valid ReferenceFrame') else: linear_momentum_sys = Vector(0) for e in body: if isinstance(e, (RigidBody, Particle)): linear_momentum_sys += e.linear_momentum(frame) else: raise TypeError('*body must have only Particle or RigidBody') return linear_momentum_sys def angular_momentum(point, frame, *body): """Angular momentum of a system. Explanation =========== This function returns the angular momentum of a system of Particle's and/or RigidBody's. The angular momentum of such a system is equal to the vector sum of the angular momentum of its constituents. Consider a system, S, comprised of a rigid body, A, and a particle, P. The angular momentum of the system, H, is equal to the vector sum of the angular momentum of the particle, H1, and the angular momentum of the rigid body, H2, i.e. H = H1 + H2 Parameters ========== point : Point The point about which angular momentum of the system is desired. frame : ReferenceFrame The frame in which angular momentum is desired. body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose angular momentum is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, angular_momentum >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> P = O.locatenew('P', 1 * N.x) >>> P.set_vel(N, 10 * N.x) >>> Pa = Particle('Pa', P, 1) >>> Ac = O.locatenew('Ac', 2 * N.y) >>> Ac.set_vel(N, 5 * N.y) >>> a = ReferenceFrame('a') >>> a.set_ang_vel(N, 10 * N.z) >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) >>> angular_momentum(O, N, Pa, A) 10*N.z """ if not isinstance(frame, ReferenceFrame): raise TypeError('Please enter a valid ReferenceFrame') if not isinstance(point, Point): raise TypeError('Please specify a valid Point') else: angular_momentum_sys = Vector(0) for e in body: if isinstance(e, (RigidBody, Particle)): angular_momentum_sys += e.angular_momentum(point, frame) else: raise TypeError('*body must have only Particle or RigidBody') return angular_momentum_sys def kinetic_energy(frame, *body): """Kinetic energy of a multibody system. Explanation =========== This function returns the kinetic energy of a system of Particle's and/or RigidBody's. The kinetic energy of such a system is equal to the sum of the kinetic energies of its constituents. Consider a system, S, comprising a rigid body, A, and a particle, P. The kinetic energy of the system, T, is equal to the vector sum of the kinetic energy of the particle, T1, and the kinetic energy of the rigid body, T2, i.e. T = T1 + T2 Kinetic energy is a scalar. Parameters ========== frame : ReferenceFrame The frame in which the velocity or angular velocity of the body is defined. body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose kinetic energy is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, kinetic_energy >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> P = O.locatenew('P', 1 * N.x) >>> P.set_vel(N, 10 * N.x) >>> Pa = Particle('Pa', P, 1) >>> Ac = O.locatenew('Ac', 2 * N.y) >>> Ac.set_vel(N, 5 * N.y) >>> a = ReferenceFrame('a') >>> a.set_ang_vel(N, 10 * N.z) >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) >>> kinetic_energy(N, Pa, A) 350 """ if not isinstance(frame, ReferenceFrame): raise TypeError('Please enter a valid ReferenceFrame') ke_sys = S.Zero for e in body: if isinstance(e, (RigidBody, Particle)): ke_sys += e.kinetic_energy(frame) else: raise TypeError('*body must have only Particle or RigidBody') return ke_sys def potential_energy(*body): """Potential energy of a multibody system. Explanation =========== This function returns the potential energy of a system of Particle's and/or RigidBody's. The potential energy of such a system is equal to the sum of the potential energy of its constituents. Consider a system, S, comprising a rigid body, A, and a particle, P. The potential energy of the system, V, is equal to the vector sum of the potential energy of the particle, V1, and the potential energy of the rigid body, V2, i.e. V = V1 + V2 Potential energy is a scalar. Parameters ========== body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose potential energy is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, potential_energy >>> from sympy import symbols >>> M, m, g, h = symbols('M m g h') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> P = O.locatenew('P', 1 * N.x) >>> Pa = Particle('Pa', P, m) >>> Ac = O.locatenew('Ac', 2 * N.y) >>> a = ReferenceFrame('a') >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, M, (I, Ac)) >>> Pa.potential_energy = m * g * h >>> A.potential_energy = M * g * h >>> potential_energy(Pa, A) M*g*h + g*h*m """ pe_sys = S.Zero for e in body: if isinstance(e, (RigidBody, Particle)): pe_sys += e.potential_energy else: raise TypeError('*body must have only Particle or RigidBody') return pe_sys def gravity(acceleration, *bodies): """ Returns a list of gravity forces given the acceleration due to gravity and any number of particles or rigidbodies. Example ======= >>> from sympy.physics.mechanics import ReferenceFrame, Point, Particle, outer, RigidBody >>> from sympy.physics.mechanics.functions import gravity >>> from sympy import symbols >>> N = ReferenceFrame('N') >>> m, M, g = symbols('m M g') >>> F1, F2 = symbols('F1 F2') >>> po = Point('po') >>> pa = Particle('pa', po, m) >>> A = ReferenceFrame('A') >>> P = Point('P') >>> I = outer(A.x, A.x) >>> B = RigidBody('B', P, A, M, (I, P)) >>> forceList = [(po, F1), (P, F2)] >>> forceList.extend(gravity(g*N.y, pa, B)) >>> forceList [(po, F1), (P, F2), (po, g*m*N.y), (P, M*g*N.y)] """ gravity_force = [] if not bodies: raise TypeError("No bodies(instances of Particle or Rigidbody) were passed.") for e in bodies: point = getattr(e, 'masscenter', None) if point is None: point = e.point gravity_force.append((point, e.mass*acceleration)) return gravity_force def center_of_mass(point, *bodies): """ Returns the position vector from the given point to the center of mass of the given bodies(particles or rigidbodies). Example ======= >>> from sympy import symbols, S >>> from sympy.physics.vector import Point >>> from sympy.physics.mechanics import Particle, ReferenceFrame, RigidBody, outer >>> from sympy.physics.mechanics.functions import center_of_mass >>> a = ReferenceFrame('a') >>> m = symbols('m', real=True) >>> p1 = Particle('p1', Point('p1_pt'), S(1)) >>> p2 = Particle('p2', Point('p2_pt'), S(2)) >>> p3 = Particle('p3', Point('p3_pt'), S(3)) >>> p4 = Particle('p4', Point('p4_pt'), m) >>> b_f = ReferenceFrame('b_f') >>> b_cm = Point('b_cm') >>> mb = symbols('mb') >>> b = RigidBody('b', b_cm, b_f, mb, (outer(b_f.x, b_f.x), b_cm)) >>> p2.point.set_pos(p1.point, a.x) >>> p3.point.set_pos(p1.point, a.x + a.y) >>> p4.point.set_pos(p1.point, a.y) >>> b.masscenter.set_pos(p1.point, a.y + a.z) >>> point_o=Point('o') >>> point_o.set_pos(p1.point, center_of_mass(p1.point, p1, p2, p3, p4, b)) >>> expr = 5/(m + mb + 6)*a.x + (m + mb + 3)/(m + mb + 6)*a.y + mb/(m + mb + 6)*a.z >>> point_o.pos_from(p1.point) 5/(m + mb + 6)*a.x + (m + mb + 3)/(m + mb + 6)*a.y + mb/(m + mb + 6)*a.z """ if not bodies: raise TypeError("No bodies(instances of Particle or Rigidbody) were passed.") total_mass = 0 vec = Vector(0) for i in bodies: total_mass += i.mass masscenter = getattr(i, 'masscenter', None) if masscenter is None: masscenter = i.point vec += i.mass*masscenter.pos_from(point) return vec/total_mass def Lagrangian(frame, *body): """Lagrangian of a multibody system. Explanation =========== This function returns the Lagrangian of a system of Particle's and/or RigidBody's. The Lagrangian of such a system is equal to the difference between the kinetic energies and potential energies of its constituents. If T and V are the kinetic and potential energies of a system then it's Lagrangian, L, is defined as L = T - V The Lagrangian is a scalar. Parameters ========== frame : ReferenceFrame The frame in which the velocity or angular velocity of the body is defined to determine the kinetic energy. body1, body2, body3... : Particle and/or RigidBody The body (or bodies) whose Lagrangian is required. Examples ======== >>> from sympy.physics.mechanics import Point, Particle, ReferenceFrame >>> from sympy.physics.mechanics import RigidBody, outer, Lagrangian >>> from sympy import symbols >>> M, m, g, h = symbols('M m g h') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> O.set_vel(N, 0 * N.x) >>> P = O.locatenew('P', 1 * N.x) >>> P.set_vel(N, 10 * N.x) >>> Pa = Particle('Pa', P, 1) >>> Ac = O.locatenew('Ac', 2 * N.y) >>> Ac.set_vel(N, 5 * N.y) >>> a = ReferenceFrame('a') >>> a.set_ang_vel(N, 10 * N.z) >>> I = outer(N.z, N.z) >>> A = RigidBody('A', Ac, a, 20, (I, Ac)) >>> Pa.potential_energy = m * g * h >>> A.potential_energy = M * g * h >>> Lagrangian(N, Pa, A) -M*g*h - g*h*m + 350 """ if not isinstance(frame, ReferenceFrame): raise TypeError('Please supply a valid ReferenceFrame') for e in body: if not isinstance(e, (RigidBody, Particle)): raise TypeError('*body must have only Particle or RigidBody') return kinetic_energy(frame, *body) - potential_energy(*body) def find_dynamicsymbols(expression, exclude=None, reference_frame=None): """Find all dynamicsymbols in expression. Explanation =========== If the optional ``exclude`` kwarg is used, only dynamicsymbols not in the iterable ``exclude`` are returned. If we intend to apply this function on a vector, the optional ``reference_frame`` is also used to inform about the corresponding frame with respect to which the dynamic symbols of the given vector is to be determined. Parameters ========== expression : sympy expression exclude : iterable of dynamicsymbols, optional reference_frame : ReferenceFrame, optional The frame with respect to which the dynamic symbols of the given vector is to be determined. Examples ======== >>> from sympy.physics.mechanics import dynamicsymbols, find_dynamicsymbols >>> from sympy.physics.mechanics import ReferenceFrame >>> x, y = dynamicsymbols('x, y') >>> expr = x + x.diff()*y >>> find_dynamicsymbols(expr) {x(t), y(t), Derivative(x(t), t)} >>> find_dynamicsymbols(expr, exclude=[x, y]) {Derivative(x(t), t)} >>> a, b, c = dynamicsymbols('a, b, c') >>> A = ReferenceFrame('A') >>> v = a * A.x + b * A.y + c * A.z >>> find_dynamicsymbols(v, reference_frame=A) {a(t), b(t), c(t)} """ t_set = {dynamicsymbols._t} if exclude: if iterable(exclude): exclude_set = set(exclude) else: raise TypeError("exclude kwarg must be iterable") else: exclude_set = set() if isinstance(expression, Vector): if reference_frame is None: raise ValueError("You must provide reference_frame when passing a " "vector expression, got %s." % reference_frame) else: expression = expression.to_matrix(reference_frame) return {i for i in expression.atoms(AppliedUndef, Derivative) if i.free_symbols == t_set} - exclude_set def msubs(expr, *sub_dicts, smart=False, **kwargs): """A custom subs for use on expressions derived in physics.mechanics. Traverses the expression tree once, performing the subs found in sub_dicts. Terms inside ``Derivative`` expressions are ignored: Examples ======== >>> from sympy.physics.mechanics import dynamicsymbols, msubs >>> x = dynamicsymbols('x') >>> msubs(x.diff() + x, {x: 1}) Derivative(x(t), t) + 1 Note that sub_dicts can be a single dictionary, or several dictionaries: >>> x, y, z = dynamicsymbols('x, y, z') >>> sub1 = {x: 1, y: 2} >>> sub2 = {z: 3, x.diff(): 4} >>> msubs(x.diff() + x + y + z, sub1, sub2) 10 If smart=True (default False), also checks for conditions that may result in ``nan``, but if simplified would yield a valid expression. For example: >>> from sympy import sin, tan >>> (sin(x)/tan(x)).subs(x, 0) nan >>> msubs(sin(x)/tan(x), {x: 0}, smart=True) 1 It does this by first replacing all ``tan`` with ``sin/cos``. Then each node is traversed. If the node is a fraction, subs is first evaluated on the denominator. If this results in 0, simplification of the entire fraction is attempted. Using this selective simplification, only subexpressions that result in 1/0 are targeted, resulting in faster performance. """ sub_dict = dict_merge(*sub_dicts) if smart: func = _smart_subs elif hasattr(expr, 'msubs'): return expr.msubs(sub_dict) else: func = lambda expr, sub_dict: _crawl(expr, _sub_func, sub_dict) if isinstance(expr, (Matrix, Vector, Dyadic)): return expr.applyfunc(lambda x: func(x, sub_dict)) else: return func(expr, sub_dict) def _crawl(expr, func, *args, **kwargs): """Crawl the expression tree, and apply func to every node.""" val = func(expr, *args, **kwargs) if val is not None: return val new_args = (_crawl(arg, func, *args, **kwargs) for arg in expr.args) return expr.func(*new_args) def _sub_func(expr, sub_dict): """Perform direct matching substitution, ignoring derivatives.""" if expr in sub_dict: return sub_dict[expr] elif not expr.args or expr.is_Derivative: return expr def _tan_repl_func(expr): """Replace tan with sin/cos.""" if isinstance(expr, tan): return sin(*expr.args) / cos(*expr.args) elif not expr.args or expr.is_Derivative: return expr def _smart_subs(expr, sub_dict): """Performs subs, checking for conditions that may result in `nan` or `oo`, and attempts to simplify them out. The expression tree is traversed twice, and the following steps are performed on each expression node: - First traverse: Replace all `tan` with `sin/cos`. - Second traverse: If node is a fraction, check if the denominator evaluates to 0. If so, attempt to simplify it out. Then if node is in sub_dict, sub in the corresponding value.""" expr = _crawl(expr, _tan_repl_func) def _recurser(expr, sub_dict): # Decompose the expression into num, den num, den = _fraction_decomp(expr) if den != 1: # If there is a non trivial denominator, we need to handle it denom_subbed = _recurser(den, sub_dict) if denom_subbed.evalf() == 0: # If denom is 0 after this, attempt to simplify the bad expr expr = simplify(expr) else: # Expression won't result in nan, find numerator num_subbed = _recurser(num, sub_dict) return num_subbed / denom_subbed # We have to crawl the tree manually, because `expr` may have been # modified in the simplify step. First, perform subs as normal: val = _sub_func(expr, sub_dict) if val is not None: return val new_args = (_recurser(arg, sub_dict) for arg in expr.args) return expr.func(*new_args) return _recurser(expr, sub_dict) def _fraction_decomp(expr): """Return num, den such that expr = num/den""" if not isinstance(expr, Mul): return expr, 1 num = [] den = [] for a in expr.args: if a.is_Pow and a.args[1] < 0: den.append(1 / a) else: num.append(a) if not den: return expr, 1 num = Mul(*num) den = Mul(*den) return num, den def _f_list_parser(fl, ref_frame): """Parses the provided forcelist composed of items of the form (obj, force). Returns a tuple containing: vel_list: The velocity (ang_vel for Frames, vel for Points) in the provided reference frame. f_list: The forces. Used internally in the KanesMethod and LagrangesMethod classes. """ def flist_iter(): for pair in fl: obj, force = pair if isinstance(obj, ReferenceFrame): yield obj.ang_vel_in(ref_frame), force elif isinstance(obj, Point): yield obj.vel(ref_frame), force else: raise TypeError('First entry in each forcelist pair must ' 'be a point or frame.') if not fl: vel_list, f_list = (), () else: unzip = lambda l: list(zip(*l)) if l[0] else [(), ()] vel_list, f_list = unzip(list(flist_iter())) return vel_list, f_list sympy-sympy-1.9/sympy/physics/mechanics/joint.py000066400000000000000000000575651412543434000222370ustar00rootroot00000000000000# coding=utf-8 from abc import ABC, abstractmethod from sympy import pi from sympy.physics.mechanics.body import Body from sympy.physics.vector import Vector, dynamicsymbols, cross from sympy.physics.vector.frame import ReferenceFrame import warnings __all__ = ['Joint', 'PinJoint', 'PrismaticJoint'] class Joint(ABC): """Abstract base class for all specific joints. Explanation =========== A joint subtracts degrees of freedom from a body. This is the base class for all specific joints and holds all common methods acting as an interface for all joints. Custom joint can be created by inheriting Joint class and defining all abstract functions. The abstract methods are: - ``_generate_coordinates`` - ``_generate_speeds`` - ``_orient_frames`` - ``_set_angular_velocity`` - ``_set_linar_velocity`` Parameters ========== name : string A unique name for the joint. parent : Body The parent body of joint. child : Body The child body of joint. coordinates: List of dynamicsymbols, optional Generalized coordinates of the joint. speeds : List of dynamicsymbols, optional Generalized speeds of joint. parent_joint_pos : Vector, optional Vector from the parent body's mass center to the point where the parent and child are connected. The default value is the zero vector. child_joint_pos : Vector, optional Vector from the child body's mass center to the point where the parent and child are connected. The default value is the zero vector. parent_axis : Vector, optional Axis fixed in the parent body which aligns with an axis fixed in the child body. The default is x axis in parent's reference frame. child_axis : Vector, optional Axis fixed in the child body which aligns with an axis fixed in the parent body. The default is x axis in child's reference frame. Attributes ========== name : string The joint's name. parent : Body The joint's parent body. child : Body The joint's child body. coordinates : list List of the joint's generalized coordinates. speeds : list List of the joint's generalized speeds. parent_point : Point The point fixed in the parent body that represents the joint. child_point : Point The point fixed in the child body that represents the joint. parent_axis : Vector The axis fixed in the parent frame that represents the joint. child_axis : Vector The axis fixed in the child frame that represents the joint. kdes : list Kinematical differential equations of the joint. Notes ===== The direction cosine matrix between the child and parent is formed using a simple rotation about an axis that is normal to both ``child_axis`` and ``parent_axis``. In general, the normal axis is formed by crossing the ``child_axis`` into the ``parent_axis`` except if the child and parent axes are in exactly opposite directions. In that case the rotation vector is chosen using the rules in the following table where ``C`` is the child reference frame and ``P`` is the parent reference frame: .. list-table:: :header-rows: 1 * - ``child_axis`` - ``parent_axis`` - ``rotation_axis`` * - ``-C.x`` - ``P.x`` - ``P.z`` * - ``-C.y`` - ``P.y`` - ``P.x`` * - ``-C.z`` - ``P.z`` - ``P.y`` * - ``-C.x-C.y`` - ``P.x+P.y`` - ``P.z`` * - ``-C.y-C.z`` - ``P.y+P.z`` - ``P.x`` * - ``-C.x-C.z`` - ``P.x+P.z`` - ``P.y`` * - ``-C.x-C.y-C.z`` - ``P.x+P.y+P.z`` - ``(P.x+P.y+P.z) × P.x`` """ def __init__(self, name, parent, child, coordinates=None, speeds=None, parent_joint_pos=None, child_joint_pos=None, parent_axis=None, child_axis=None): if not isinstance(name, str): raise TypeError('Supply a valid name.') self._name = name if not isinstance(parent, Body): raise TypeError('Parent must be an instance of Body.') self._parent = parent if not isinstance(child, Body): raise TypeError('Parent must be an instance of Body.') self._child = child self._coordinates = self._generate_coordinates(coordinates) self._speeds = self._generate_speeds(speeds) self._kdes = self._generate_kdes() self._parent_axis = self._axis(parent, parent_axis) self._child_axis = self._axis(child, child_axis) self._parent_point = self._locate_joint_pos(parent, parent_joint_pos) self._child_point = self._locate_joint_pos(child, child_joint_pos) self._orient_frames() self._set_angular_velocity() self._set_linear_velocity() def __str__(self): return self.name def __repr__(self): return self.__str__() @property def name(self): return self._name @property def parent(self): """Parent body of Joint.""" return self._parent @property def child(self): """Child body of Joint.""" return self._child @property def coordinates(self): """List generalized coordinates of the joint.""" return self._coordinates @property def speeds(self): """List generalized coordinates of the joint..""" return self._speeds @property def kdes(self): """Kinematical differential equations of the joint.""" return self._kdes @property def parent_axis(self): """The axis of parent frame.""" return self._parent_axis @property def child_axis(self): """The axis of child frame.""" return self._child_axis @property def parent_point(self): """The joint's point where parent body is connected to the joint.""" return self._parent_point @property def child_point(self): """The joint's point where child body is connected to the joint.""" return self._child_point @abstractmethod def _generate_coordinates(self, coordinates): """Generate list generalized coordinates of the joint.""" pass @abstractmethod def _generate_speeds(self, speeds): """Generate list generalized speeds of the joint.""" pass @abstractmethod def _orient_frames(self): """Orient frames as per the joint.""" pass @abstractmethod def _set_angular_velocity(self): pass @abstractmethod def _set_linear_velocity(self): pass def _generate_kdes(self): kdes = [] t = dynamicsymbols._t for i in range(len(self.coordinates)): kdes.append(-self.coordinates[i].diff(t) + self.speeds[i]) return kdes def _axis(self, body, ax): if ax is None: ax = body.frame.x return ax if not isinstance(ax, Vector): raise TypeError("Axis must be of type Vector.") if not ax.dt(body.frame) == 0: msg = ('Axis cannot be time-varying when viewed from the ' 'associated body.') raise ValueError(msg) return ax def _locate_joint_pos(self, body, joint_pos): if joint_pos is None: joint_pos = Vector(0) if not isinstance(joint_pos, Vector): raise ValueError('Joint Position must be supplied as Vector.') if not joint_pos.dt(body.frame) == 0: msg = ('Position Vector cannot be time-varying when viewed from ' 'the associated body.') raise ValueError(msg) point_name = self._name + '_' + body.name + '_joint' return body.masscenter.locatenew(point_name, joint_pos) def _alignment_rotation(self, parent, child): # Returns the axis and angle between two axis(vectors). angle = parent.angle_between(child) axis = cross(child, parent).normalize() return angle, axis def _generate_vector(self): parent_frame = self.parent.frame components = self.parent_axis.to_matrix(parent_frame) x, y, z = components[0], components[1], components[2] if x != 0: if y!=0: if z!=0: return cross(self.parent_axis, parent_frame.x) if z!=0: return parent_frame.y return parent_frame.z if x == 0: if y!=0: if z!=0: return parent_frame.x return parent_frame.x return parent_frame.y def _set_orientation(self): #Helper method for `orient_axis()` self.child.frame.orient_axis(self.parent.frame, self.parent_axis, 0) angle, axis = self._alignment_rotation(self.parent_axis, self.child_axis) with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=UserWarning) if axis != Vector(0) or angle == pi: if angle == pi: axis = self._generate_vector() int_frame = ReferenceFrame('int_frame') int_frame.orient_axis(self.child.frame, self.child_axis, 0) int_frame.orient_axis(self.parent.frame, axis, angle) return int_frame return self.parent.frame class PinJoint(Joint): """Pin (Revolute) Joint. Explanation =========== A pin joint is defined such that the joint rotation axis is fixed in both the child and parent and the location of the joint is relative to the mass center of each body. The child rotates an angle, θ, from the parent about the rotation axis and has a simple angular speed, ω, relative to the parent. The direction cosine matrix between the child and parent is formed using a simple rotation about an axis that is normal to both ``child_axis`` and ``parent_axis``, see the Notes section for a detailed explanation of this. Parameters ========== name : string A unique name for the joint. parent : Body The parent body of joint. child : Body The child body of joint. coordinates: dynamicsymbol, optional Generalized coordinates of the joint. speeds : dynamicsymbol, optional Generalized speeds of joint. parent_joint_pos : Vector, optional Vector from the parent body's mass center to the point where the parent and child are connected. The default value is the zero vector. child_joint_pos : Vector, optional Vector from the child body's mass center to the point where the parent and child are connected. The default value is the zero vector. parent_axis : Vector, optional Axis fixed in the parent body which aligns with an axis fixed in the child body. The default is x axis in parent's reference frame. child_axis : Vector, optional Axis fixed in the child body which aligns with an axis fixed in the parent body. The default is x axis in child's reference frame. Attributes ========== name : string The joint's name. parent : Body The joint's parent body. child : Body The joint's child body. coordinates : list List of the joint's generalized coordinates. speeds : list List of the joint's generalized speeds. parent_point : Point The point fixed in the parent body that represents the joint. child_point : Point The point fixed in the child body that represents the joint. parent_axis : Vector The axis fixed in the parent frame that represents the joint. child_axis : Vector The axis fixed in the child frame that represents the joint. kdes : list Kinematical differential equations of the joint. Examples ========= A single pin joint is created from two bodies and has the following basic attributes: >>> from sympy.physics.mechanics import Body, PinJoint >>> parent = Body('P') >>> parent P >>> child = Body('C') >>> child C >>> joint = PinJoint('PC', parent, child) >>> joint PinJoint: PC parent: P child: C >>> joint.name 'PC' >>> joint.parent P >>> joint.child C >>> joint.parent_point PC_P_joint >>> joint.child_point PC_C_joint >>> joint.parent_axis P_frame.x >>> joint.child_axis C_frame.x >>> joint.coordinates [theta_PC(t)] >>> joint.speeds [omega_PC(t)] >>> joint.child.frame.ang_vel_in(joint.parent.frame) omega_PC(t)*P_frame.x >>> joint.child.frame.dcm(joint.parent.frame) Matrix([ [1, 0, 0], [0, cos(theta_PC(t)), sin(theta_PC(t))], [0, -sin(theta_PC(t)), cos(theta_PC(t))]]) >>> joint.child_point.pos_from(joint.parent_point) 0 To further demonstrate the use of the pin joint, the kinematics of simple double pendulum that rotates about the Z axis of each connected body can be created as follows. >>> from sympy import symbols, trigsimp >>> from sympy.physics.mechanics import Body, PinJoint >>> l1, l2 = symbols('l1 l2') First create bodies to represent the fixed ceiling and one to represent each pendulum bob. >>> ceiling = Body('C') >>> upper_bob = Body('U') >>> lower_bob = Body('L') The first joint will connect the upper bob to the ceiling by a distance of ``l1`` and the joint axis will be about the Z axis for each body. >>> ceiling_joint = PinJoint('P1', ceiling, upper_bob, ... child_joint_pos=-l1*upper_bob.frame.x, ... parent_axis=ceiling.frame.z, ... child_axis=upper_bob.frame.z) The second joint will connect the lower bob to the upper bob by a distance of ``l2`` and the joint axis will also be about the Z axis for each body. >>> pendulum_joint = PinJoint('P2', upper_bob, lower_bob, ... child_joint_pos=-l2*lower_bob.frame.x, ... parent_axis=upper_bob.frame.z, ... child_axis=lower_bob.frame.z) Once the joints are established the kinematics of the connected bodies can be accessed. First the direction cosine matrices of pendulum link relative to the ceiling are found: >>> upper_bob.frame.dcm(ceiling.frame) Matrix([ [ cos(theta_P1(t)), sin(theta_P1(t)), 0], [-sin(theta_P1(t)), cos(theta_P1(t)), 0], [ 0, 0, 1]]) >>> trigsimp(lower_bob.frame.dcm(ceiling.frame)) Matrix([ [ cos(theta_P1(t) + theta_P2(t)), sin(theta_P1(t) + theta_P2(t)), 0], [-sin(theta_P1(t) + theta_P2(t)), cos(theta_P1(t) + theta_P2(t)), 0], [ 0, 0, 1]]) The position of the lower bob's masscenter is found with: >>> lower_bob.masscenter.pos_from(ceiling.masscenter) l1*U_frame.x + l2*L_frame.x The angular velocities of the two pendulum links can be computed with respect to the ceiling. >>> upper_bob.frame.ang_vel_in(ceiling.frame) omega_P1(t)*C_frame.z >>> lower_bob.frame.ang_vel_in(ceiling.frame) omega_P1(t)*C_frame.z + omega_P2(t)*U_frame.z And finally, the linear velocities of the two pendulum bobs can be computed with respect to the ceiling. >>> upper_bob.masscenter.vel(ceiling.frame) l1*omega_P1(t)*U_frame.y >>> lower_bob.masscenter.vel(ceiling.frame) l1*omega_P1(t)*U_frame.y + l2*(omega_P1(t) + omega_P2(t))*L_frame.y """ def __init__(self, name, parent, child, coordinates=None, speeds=None, parent_joint_pos=None, child_joint_pos=None, parent_axis=None, child_axis=None): super().__init__(name, parent, child, coordinates, speeds, parent_joint_pos, child_joint_pos, parent_axis, child_axis) def __str__(self): return (f'PinJoint: {self.name} parent: {self.parent} ' f'child: {self.child}') def _generate_coordinates(self, coordinate): coordinates = [] if coordinate is None: theta = dynamicsymbols('theta' + '_' + self._name) coordinate = theta coordinates.append(coordinate) return coordinates def _generate_speeds(self, speed): speeds = [] if speed is None: omega = dynamicsymbols('omega' + '_' + self._name) speed = omega speeds.append(speed) return speeds def _orient_frames(self): frame = self._set_orientation() self.child.frame.orient_axis(frame, self.parent_axis, self.coordinates[0]) def _set_angular_velocity(self): self.child.frame.set_ang_vel(self.parent.frame, self.speeds[0] * self.parent_axis.normalize()) def _set_linear_velocity(self): self.parent_point.set_vel(self.parent.frame, 0) self.child_point.set_vel(self.parent.frame, 0) self.child_point.set_pos(self.parent_point, 0) self.child.masscenter.v2pt_theory(self.parent.masscenter, self.parent.frame, self.child.frame) class PrismaticJoint(Joint): """Prismatic (Sliding) Joint. Explanation =========== It is defined such that the child body translates with respect to the parent body along the body fixed parent axis. The location of the joint is defined by two points in each body which coincides when the generalized coordinate is zero. The direction cosine matrix between the child and parent is formed using a simple rotation about an axis that is normal to both ``child_axis`` and ``parent_axis``, see the Notes section for a detailed explanation of this. Parameters ========== name : string A unique name for the joint. parent : Body The parent body of joint. child : Body The child body of joint. coordinates: dynamicsymbol, optional Generalized coordinates of the joint. speeds : dynamicsymbol, optional Generalized speeds of joint. parent_joint_pos : Vector, optional Vector from the parent body's mass center to the point where the parent and child are connected. The default value is the zero vector. child_joint_pos : Vector, optional Vector from the child body's mass center to the point where the parent and child are connected. The default value is the zero vector. parent_axis : Vector, optional Axis fixed in the parent body which aligns with an axis fixed in the child body. The default is x axis in parent's reference frame. child_axis : Vector, optional Axis fixed in the child body which aligns with an axis fixed in the parent body. The default is x axis in child's reference frame. Attributes ========== name : string The joint's name. parent : Body The joint's parent body. child : Body The joint's child body. coordinates : list List of the joint's generalized coordinates. speeds : list List of the joint's generalized speeds. parent_point : Point The point fixed in the parent body that represents the joint. child_point : Point The point fixed in the child body that represents the joint. parent_axis : Vector The axis fixed in the parent frame that represents the joint. child_axis : Vector The axis fixed in the child frame that represents the joint. kdes : list Kinematical differential equations of the joint. Examples ========= A single prismatic joint is created from two bodies and has the following basic attributes: >>> from sympy.physics.mechanics import Body, PrismaticJoint >>> parent = Body('P') >>> parent P >>> child = Body('C') >>> child C >>> joint = PrismaticJoint('PC', parent, child) >>> joint PrismaticJoint: PC parent: P child: C >>> joint.name 'PC' >>> joint.parent P >>> joint.child C >>> joint.parent_point PC_P_joint >>> joint.child_point PC_C_joint >>> joint.parent_axis P_frame.x >>> joint.child_axis C_frame.x >>> joint.coordinates [x_PC(t)] >>> joint.speeds [v_PC(t)] >>> joint.child.frame.ang_vel_in(joint.parent.frame) 0 >>> joint.child.frame.dcm(joint.parent.frame) Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> joint.child_point.pos_from(joint.parent_point) x_PC(t)*P_frame.x To further demonstrate the use of the prismatic joint, the kinematics of two masses sliding, one moving relative to a fixed body and the other relative to the moving body. about the X axis of each connected body can be created as follows. >>> from sympy.physics.mechanics import PrismaticJoint, Body First create bodies to represent the fixed ceiling and one to represent a particle. >>> wall = Body('W') >>> Part1 = Body('P1') >>> Part2 = Body('P2') The first joint will connect the particle to the ceiling and the joint axis will be about the X axis for each body. >>> J1 = PrismaticJoint('J1', wall, Part1) The second joint will connect the second particle to the first particle and the joint axis will also be about the X axis for each body. >>> J2 = PrismaticJoint('J2', Part1, Part2) Once the joint is established the kinematics of the connected bodies can be accessed. First the direction cosine matrices of Part relative to the ceiling are found: >>> Part1.dcm(wall) Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) >>> Part2.dcm(wall) Matrix([ [1, 0, 0], [0, 1, 0], [0, 0, 1]]) The position of the particles' masscenter is found with: >>> Part1.masscenter.pos_from(wall.masscenter) x_J1(t)*W_frame.x >>> Part2.masscenter.pos_from(wall.masscenter) x_J1(t)*W_frame.x + x_J2(t)*P1_frame.x The angular velocities of the two particle links can be computed with respect to the ceiling. >>> Part1.ang_vel_in(wall) 0 >>> Part2.ang_vel_in(wall) 0 And finally, the linear velocities of the two particles can be computed with respect to the ceiling. >>> Part1.masscenter_vel(wall) v_J1(t)*W_frame.x >>> Part2.masscenter.vel(wall.frame) v_J1(t)*W_frame.x + v_J2(t)*P1_frame.x """ def __init__(self, name, parent, child, coordinates=None, speeds=None, parent_joint_pos=None, child_joint_pos=None, parent_axis=None, child_axis=None): super().__init__(name, parent, child, coordinates, speeds, parent_joint_pos, child_joint_pos, parent_axis, child_axis) def __str__(self): return (f'PrismaticJoint: {self.name} parent: {self.parent} ' f'child: {self.child}') def _generate_coordinates(self, coordinate): coordinates = [] if coordinate is None: x = dynamicsymbols('x' + '_' + self._name) coordinate = x coordinates.append(coordinate) return coordinates def _generate_speeds(self, speed): speeds = [] if speed is None: y = dynamicsymbols('v' + '_' + self._name) speed = y speeds.append(speed) return speeds def _orient_frames(self): frame = self._set_orientation() self.child.frame.orient_axis(frame, self.parent_axis, 0) def _set_angular_velocity(self): self.child.frame.set_ang_vel(self.parent.frame, 0) def _set_linear_velocity(self): self.parent_point.set_vel(self.parent.frame, 0) self.child_point.set_vel(self.child.frame, 0) self.child_point.set_pos(self.parent_point, self.coordinates[0] * self.parent_axis.normalize()) self.child_point.set_vel(self.parent.frame, self.speeds[0] * self.parent_axis.normalize()) self.child.masscenter.set_vel(self.parent.frame, self.speeds[0] * self.parent_axis.normalize()) sympy-sympy-1.9/sympy/physics/mechanics/jointsmethod.py000066400000000000000000000203701412543434000236030ustar00rootroot00000000000000from sympy.physics.mechanics import (Body, Lagrangian, KanesMethod, LagrangesMethod, RigidBody, Particle) from sympy.physics.mechanics.method import _Methods __all__ = ['JointsMethod'] class JointsMethod(_Methods): """Method for formulating the equations of motion using a set of interconnected bodies with joints. Parameters ========== newtonion : Body or ReferenceFrame The newtonion(inertial) frame. *joints : Joint The joints in the system Attributes ========== q, u : iterable Iterable of the generalized coordinates and speeds bodies : iterable Iterable of Body objects in the system. loads : iterable Iterable of (Point, vector) or (ReferenceFrame, vector) tuples describing the forces on the system. mass_matrix : Matrix, shape(n, n) The system's mass matrix forcing : Matrix, shape(n, 1) The system's forcing vector mass_matrix_full : Matrix, shape(2*n, 2*n) The "mass matrix" for the u's and q's forcing_full : Matrix, shape(2*n, 1) The "forcing vector" for the u's and q's method : KanesMethod or Lagrange's method Method's object. kdes : iterable Iterable of kde in they system. Examples ======== This is a simple example for a one degree of freedom translational spring-mass-damper. >>> from sympy import symbols >>> from sympy.physics.mechanics import Body, JointsMethod, PrismaticJoint >>> from sympy.physics.vector import dynamicsymbols >>> c, k = symbols('c k') >>> x, v = dynamicsymbols('x v') >>> wall = Body('W') >>> body = Body('B') >>> J = PrismaticJoint('J', wall, body, coordinates=x, speeds=v) >>> wall.apply_force(c*v*wall.x, reaction_body=body) >>> wall.apply_force(k*x*wall.x, reaction_body=body) >>> method = JointsMethod(wall, J) >>> method.form_eoms() Matrix([[-B_mass*Derivative(v(t), t) - c*v(t) - k*x(t)]]) >>> M = method.mass_matrix_full >>> F = method.forcing_full >>> rhs = M.LUsolve(F) >>> rhs Matrix([ [ v(t)], [(-c*v(t) - k*x(t))/B_mass]]) Notes ===== ``JointsMethod`` currently only works with systems that do not have any configuration or motion constraints. """ def __init__(self, newtonion, *joints): if isinstance(newtonion, Body): self.frame = newtonion.frame else: self.frame = newtonion self._joints = joints self._bodies = self._generate_bodylist() self._loads = self._generate_loadlist() self._q = self._generate_q() self._u = self._generate_u() self._kdes = self._generate_kdes() self._method = None @property def bodies(self): """List of bodies in they system.""" return self._bodies @property def loads(self): """List of loads on the system.""" return self._loads @property def q(self): """List of the generalized coordinates.""" return self._q @property def u(self): """List of the generalized speeds.""" return self._u @property def kdes(self): """List of the generalized coordinates.""" return self._kdes @property def forcing_full(self): """The "forcing vector" for the u's and q's.""" return self.method.forcing_full @property def mass_matrix_full(self): """The "mass matrix" for the u's and q's.""" return self.method.mass_matrix_full @property def mass_matrix(self): """The system's mass matrix.""" return self.method.mass_matrix @property def forcing(self): """The system's forcing vector.""" return self.method.forcing @property def method(self): """Object of method used to form equations of systems.""" return self._method def _generate_bodylist(self): bodies = [] for joint in self._joints: if joint.child not in bodies: bodies.append(joint.child) if joint.parent not in bodies: bodies.append(joint.parent) return bodies def _generate_loadlist(self): load_list = [] for body in self.bodies: load_list.extend(body.loads) return load_list def _generate_q(self): q_ind = [] for joint in self._joints: for coordinate in joint.coordinates: if coordinate in q_ind: raise ValueError('Coordinates of joints should be unique.') q_ind.append(coordinate) return q_ind def _generate_u(self): u_ind = [] for joint in self._joints: for speed in joint.speeds: if speed in u_ind: raise ValueError('Speeds of joints should be unique.') u_ind.append(speed) return u_ind def _generate_kdes(self): kd_ind = [] for joint in self._joints: kd_ind.extend(joint.kdes) return kd_ind def _convert_bodies(self): # Convert `Body` to `Particle` and `RigidBody` bodylist = [] for body in self.bodies: if body.is_rigidbody: rb = RigidBody(body.name, body.masscenter, body.frame, body.mass, (body.central_inertia, body.masscenter)) rb.potential_energy = body.potential_energy bodylist.append(rb) else: part = Particle(body.name, body.masscenter, body.mass) part.potential_energy = body.potential_energy bodylist.append(part) return bodylist def form_eoms(self, method=KanesMethod): """Method to form system's equation of motions. Parameters ========== method : Class Class name of method. Returns ======== Matrix Vector of equations of motions. Examples ======== This is a simple example for a one degree of freedom translational spring-mass-damper. >>> from sympy import S, symbols >>> from sympy.physics.mechanics import LagrangesMethod, dynamicsymbols, Body >>> from sympy.physics.mechanics import PrismaticJoint, JointsMethod >>> q = dynamicsymbols('q') >>> qd = dynamicsymbols('q', 1) >>> m, k, b = symbols('m k b') >>> wall = Body('W') >>> part = Body('P', mass=m) >>> part.potential_energy = k * q**2 / S(2) >>> J = PrismaticJoint('J', wall, part, coordinates=q, speeds=qd) >>> wall.apply_force(b * qd * wall.x, reaction_body=part) >>> method = JointsMethod(wall, J) >>> method.form_eoms(LagrangesMethod) Matrix([[b*Derivative(q(t), t) + k*q(t) + m*Derivative(q(t), (t, 2))]]) We can also solve for the states using the 'rhs' method. >>> method.rhs() Matrix([ [ Derivative(q(t), t)], [(-b*Derivative(q(t), t) - k*q(t))/m]]) """ bodylist = self._convert_bodies() if issubclass(method, LagrangesMethod): #LagrangesMethod or similar L = Lagrangian(self.frame, *bodylist) self._method = method(L, self.q, self.loads, bodylist, self.frame) else: #KanesMethod or similar self._method = method(self.frame, q_ind=self.q, u_ind=self.u, kd_eqs=self.kdes, forcelist=self.loads, bodies=bodylist) soln = self.method._form_eoms() return soln def rhs(self, inv_method=None): """Returns equations that can be solved numerically. Parameters ========== inv_method : str The specific sympy inverse matrix calculation method to use. For a list of valid methods, see :meth:`~sympy.matrices.matrices.MatrixBase.inv` Returns ======== Matrix Numerically solveable equations. See Also ======== sympy.physics.mechanics.KanesMethod.rhs(): KanesMethod's rhs function. sympy.physics.mechanics.LagrangesMethod.rhs(): LagrangesMethod's rhs function. """ return self.method.rhs(inv_method=inv_method) sympy-sympy-1.9/sympy/physics/mechanics/kane.py000066400000000000000000000651771412543434000220300ustar00rootroot00000000000000from sympy.core.backend import zeros, Matrix, diff, eye from sympy import solve_linear_system_LU from sympy.utilities import default_sort_key from sympy.physics.vector import (ReferenceFrame, dynamicsymbols, partial_velocity) from sympy.physics.mechanics.method import _Methods from sympy.physics.mechanics.particle import Particle from sympy.physics.mechanics.rigidbody import RigidBody from sympy.physics.mechanics.functions import (msubs, find_dynamicsymbols, _f_list_parser) from sympy.physics.mechanics.linearize import Linearizer from sympy.utilities.iterables import iterable __all__ = ['KanesMethod'] class KanesMethod(_Methods): """Kane's method object. Explanation =========== This object is used to do the "book-keeping" as you go through and form equations of motion in the way Kane presents in: Kane, T., Levinson, D. Dynamics Theory and Applications. 1985 McGraw-Hill The attributes are for equations in the form [M] udot = forcing. Attributes ========== q, u : Matrix Matrices of the generalized coordinates and speeds bodies : iterable Iterable of Point and RigidBody objects in the system. loads : iterable Iterable of (Point, vector) or (ReferenceFrame, vector) tuples describing the forces on the system. auxiliary : Matrix If applicable, the set of auxiliary Kane's equations used to solve for non-contributing forces. mass_matrix : Matrix The system's mass matrix forcing : Matrix The system's forcing vector mass_matrix_full : Matrix The "mass matrix" for the u's and q's forcing_full : Matrix The "forcing vector" for the u's and q's Examples ======== This is a simple example for a one degree of freedom translational spring-mass-damper. In this example, we first need to do the kinematics. This involves creating generalized speeds and coordinates and their derivatives. Then we create a point and set its velocity in a frame. >>> from sympy import symbols >>> from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame >>> from sympy.physics.mechanics import Point, Particle, KanesMethod >>> q, u = dynamicsymbols('q u') >>> qd, ud = dynamicsymbols('q u', 1) >>> m, c, k = symbols('m c k') >>> N = ReferenceFrame('N') >>> P = Point('P') >>> P.set_vel(N, u * N.x) Next we need to arrange/store information in the way that KanesMethod requires. The kinematic differential equations need to be stored in a dict. A list of forces/torques must be constructed, where each entry in the list is a (Point, Vector) or (ReferenceFrame, Vector) tuple, where the Vectors represent the Force or Torque. Next a particle needs to be created, and it needs to have a point and mass assigned to it. Finally, a list of all bodies and particles needs to be created. >>> kd = [qd - u] >>> FL = [(P, (-k * q - c * u) * N.x)] >>> pa = Particle('pa', P, m) >>> BL = [pa] Finally we can generate the equations of motion. First we create the KanesMethod object and supply an inertial frame, coordinates, generalized speeds, and the kinematic differential equations. Additional quantities such as configuration and motion constraints, dependent coordinates and speeds, and auxiliary speeds are also supplied here (see the online documentation). Next we form FR* and FR to complete: Fr + Fr* = 0. We have the equations of motion at this point. It makes sense to rearrange them though, so we calculate the mass matrix and the forcing terms, for E.o.M. in the form: [MM] udot = forcing, where MM is the mass matrix, udot is a vector of the time derivatives of the generalized speeds, and forcing is a vector representing "forcing" terms. >>> KM = KanesMethod(N, q_ind=[q], u_ind=[u], kd_eqs=kd) >>> (fr, frstar) = KM.kanes_equations(BL, FL) >>> MM = KM.mass_matrix >>> forcing = KM.forcing >>> rhs = MM.inv() * forcing >>> rhs Matrix([[(-c*u(t) - k*q(t))/m]]) >>> KM.linearize(A_and_B=True)[0] Matrix([ [ 0, 1], [-k/m, -c/m]]) Please look at the documentation pages for more information on how to perform linearization and how to deal with dependent coordinates & speeds, and how do deal with bringing non-contributing forces into evidence. """ def __init__(self, frame, q_ind, u_ind, kd_eqs=None, q_dependent=None, configuration_constraints=None, u_dependent=None, velocity_constraints=None, acceleration_constraints=None, u_auxiliary=None, bodies=None, forcelist=None): """Please read the online documentation. """ if not q_ind: q_ind = [dynamicsymbols('dummy_q')] kd_eqs = [dynamicsymbols('dummy_kd')] if not isinstance(frame, ReferenceFrame): raise TypeError('An inertial ReferenceFrame must be supplied') self._inertial = frame self._fr = None self._frstar = None self._forcelist = forcelist self._bodylist = bodies self._initialize_vectors(q_ind, q_dependent, u_ind, u_dependent, u_auxiliary) self._initialize_kindiffeq_matrices(kd_eqs) self._initialize_constraint_matrices(configuration_constraints, velocity_constraints, acceleration_constraints) def _initialize_vectors(self, q_ind, q_dep, u_ind, u_dep, u_aux): """Initialize the coordinate and speed vectors.""" none_handler = lambda x: Matrix(x) if x else Matrix() # Initialize generalized coordinates q_dep = none_handler(q_dep) if not iterable(q_ind): raise TypeError('Generalized coordinates must be an iterable.') if not iterable(q_dep): raise TypeError('Dependent coordinates must be an iterable.') q_ind = Matrix(q_ind) self._qdep = q_dep self._q = Matrix([q_ind, q_dep]) self._qdot = self.q.diff(dynamicsymbols._t) # Initialize generalized speeds u_dep = none_handler(u_dep) if not iterable(u_ind): raise TypeError('Generalized speeds must be an iterable.') if not iterable(u_dep): raise TypeError('Dependent speeds must be an iterable.') u_ind = Matrix(u_ind) self._udep = u_dep self._u = Matrix([u_ind, u_dep]) self._udot = self.u.diff(dynamicsymbols._t) self._uaux = none_handler(u_aux) def _initialize_constraint_matrices(self, config, vel, acc): """Initializes constraint matrices.""" # Define vector dimensions o = len(self.u) m = len(self._udep) p = o - m none_handler = lambda x: Matrix(x) if x else Matrix() # Initialize configuration constraints config = none_handler(config) if len(self._qdep) != len(config): raise ValueError('There must be an equal number of dependent ' 'coordinates and configuration constraints.') self._f_h = none_handler(config) # Initialize velocity and acceleration constraints vel = none_handler(vel) acc = none_handler(acc) if len(vel) != m: raise ValueError('There must be an equal number of dependent ' 'speeds and velocity constraints.') if acc and (len(acc) != m): raise ValueError('There must be an equal number of dependent ' 'speeds and acceleration constraints.') if vel: u_zero = {i: 0 for i in self.u} udot_zero = {i: 0 for i in self._udot} # When calling kanes_equations, another class instance will be # created if auxiliary u's are present. In this case, the # computation of kinetic differential equation matrices will be # skipped as this was computed during the original KanesMethod # object, and the qd_u_map will not be available. if self._qdot_u_map is not None: vel = msubs(vel, self._qdot_u_map) self._f_nh = msubs(vel, u_zero) self._k_nh = (vel - self._f_nh).jacobian(self.u) # If no acceleration constraints given, calculate them. if not acc: _f_dnh = (self._k_nh.diff(dynamicsymbols._t) * self.u + self._f_nh.diff(dynamicsymbols._t)) if self._qdot_u_map is not None: _f_dnh = msubs(_f_dnh, self._qdot_u_map) self._f_dnh = _f_dnh self._k_dnh = self._k_nh else: if self._qdot_u_map is not None: acc = msubs(acc, self._qdot_u_map) self._f_dnh = msubs(acc, udot_zero) self._k_dnh = (acc - self._f_dnh).jacobian(self._udot) # Form of non-holonomic constraints is B*u + C = 0. # We partition B into independent and dependent columns: # Ars is then -B_dep.inv() * B_ind, and it relates dependent speeds # to independent speeds as: udep = Ars*uind, neglecting the C term. B_ind = self._k_nh[:, :p] B_dep = self._k_nh[:, p:o] self._Ars = -B_dep.LUsolve(B_ind) else: self._f_nh = Matrix() self._k_nh = Matrix() self._f_dnh = Matrix() self._k_dnh = Matrix() self._Ars = Matrix() def _initialize_kindiffeq_matrices(self, kdeqs): """Initialize the kinematic differential equation matrices.""" if kdeqs: if len(self.q) != len(kdeqs): raise ValueError('There must be an equal number of kinematic ' 'differential equations and coordinates.') kdeqs = Matrix(kdeqs) u = self.u qdot = self._qdot # Dictionaries setting things to zero u_zero = {i: 0 for i in u} uaux_zero = {i: 0 for i in self._uaux} qdot_zero = {i: 0 for i in qdot} f_k = msubs(kdeqs, u_zero, qdot_zero) k_ku = (msubs(kdeqs, qdot_zero) - f_k).jacobian(u) k_kqdot = (msubs(kdeqs, u_zero) - f_k).jacobian(qdot) f_k = k_kqdot.LUsolve(f_k) k_ku = k_kqdot.LUsolve(k_ku) k_kqdot = eye(len(qdot)) self._qdot_u_map = solve_linear_system_LU( Matrix([k_kqdot.T, -(k_ku * u + f_k).T]).T, qdot) self._f_k = msubs(f_k, uaux_zero) self._k_ku = msubs(k_ku, uaux_zero) self._k_kqdot = k_kqdot else: self._qdot_u_map = None self._f_k = Matrix() self._k_ku = Matrix() self._k_kqdot = Matrix() def _form_fr(self, fl): """Form the generalized active force.""" if fl is not None and (len(fl) == 0 or not iterable(fl)): raise ValueError('Force pairs must be supplied in an ' 'non-empty iterable or None.') N = self._inertial # pull out relevant velocities for constructing partial velocities vel_list, f_list = _f_list_parser(fl, N) vel_list = [msubs(i, self._qdot_u_map) for i in vel_list] f_list = [msubs(i, self._qdot_u_map) for i in f_list] # Fill Fr with dot product of partial velocities and forces o = len(self.u) b = len(f_list) FR = zeros(o, 1) partials = partial_velocity(vel_list, self.u, N) for i in range(o): FR[i] = sum(partials[j][i] & f_list[j] for j in range(b)) # In case there are dependent speeds if self._udep: p = o - len(self._udep) FRtilde = FR[:p, 0] FRold = FR[p:o, 0] FRtilde += self._Ars.T * FRold FR = FRtilde self._forcelist = fl self._fr = FR return FR def _form_frstar(self, bl): """Form the generalized inertia force.""" if not iterable(bl): raise TypeError('Bodies must be supplied in an iterable.') t = dynamicsymbols._t N = self._inertial # Dicts setting things to zero udot_zero = {i: 0 for i in self._udot} uaux_zero = {i: 0 for i in self._uaux} uauxdot = [diff(i, t) for i in self._uaux] uauxdot_zero = {i: 0 for i in uauxdot} # Dictionary of q' and q'' to u and u' q_ddot_u_map = {k.diff(t): v.diff(t) for (k, v) in self._qdot_u_map.items()} q_ddot_u_map.update(self._qdot_u_map) # Fill up the list of partials: format is a list with num elements # equal to number of entries in body list. Each of these elements is a # list - either of length 1 for the translational components of # particles or of length 2 for the translational and rotational # components of rigid bodies. The inner most list is the list of # partial velocities. def get_partial_velocity(body): if isinstance(body, RigidBody): vlist = [body.masscenter.vel(N), body.frame.ang_vel_in(N)] elif isinstance(body, Particle): vlist = [body.point.vel(N),] else: raise TypeError('The body list may only contain either ' 'RigidBody or Particle as list elements.') v = [msubs(vel, self._qdot_u_map) for vel in vlist] return partial_velocity(v, self.u, N) partials = [get_partial_velocity(body) for body in bl] # Compute fr_star in two components: # fr_star = -(MM*u' + nonMM) o = len(self.u) MM = zeros(o, o) nonMM = zeros(o, 1) zero_uaux = lambda expr: msubs(expr, uaux_zero) zero_udot_uaux = lambda expr: msubs(msubs(expr, udot_zero), uaux_zero) for i, body in enumerate(bl): if isinstance(body, RigidBody): M = zero_uaux(body.mass) I = zero_uaux(body.central_inertia) vel = zero_uaux(body.masscenter.vel(N)) omega = zero_uaux(body.frame.ang_vel_in(N)) acc = zero_udot_uaux(body.masscenter.acc(N)) inertial_force = (M.diff(t) * vel + M * acc) inertial_torque = zero_uaux((I.dt(body.frame) & omega) + msubs(I & body.frame.ang_acc_in(N), udot_zero) + (omega ^ (I & omega))) for j in range(o): tmp_vel = zero_uaux(partials[i][0][j]) tmp_ang = zero_uaux(I & partials[i][1][j]) for k in range(o): # translational MM[j, k] += M * (tmp_vel & partials[i][0][k]) # rotational MM[j, k] += (tmp_ang & partials[i][1][k]) nonMM[j] += inertial_force & partials[i][0][j] nonMM[j] += inertial_torque & partials[i][1][j] else: M = zero_uaux(body.mass) vel = zero_uaux(body.point.vel(N)) acc = zero_udot_uaux(body.point.acc(N)) inertial_force = (M.diff(t) * vel + M * acc) for j in range(o): temp = zero_uaux(partials[i][0][j]) for k in range(o): MM[j, k] += M * (temp & partials[i][0][k]) nonMM[j] += inertial_force & partials[i][0][j] # Compose fr_star out of MM and nonMM MM = zero_uaux(msubs(MM, q_ddot_u_map)) nonMM = msubs(msubs(nonMM, q_ddot_u_map), udot_zero, uauxdot_zero, uaux_zero) fr_star = -(MM * msubs(Matrix(self._udot), uauxdot_zero) + nonMM) # If there are dependent speeds, we need to find fr_star_tilde if self._udep: p = o - len(self._udep) fr_star_ind = fr_star[:p, 0] fr_star_dep = fr_star[p:o, 0] fr_star = fr_star_ind + (self._Ars.T * fr_star_dep) # Apply the same to MM MMi = MM[:p, :] MMd = MM[p:o, :] MM = MMi + (self._Ars.T * MMd) self._bodylist = bl self._frstar = fr_star self._k_d = MM self._f_d = -msubs(self._fr + self._frstar, udot_zero) return fr_star def to_linearizer(self): """Returns an instance of the Linearizer class, initiated from the data in the KanesMethod class. This may be more desirable than using the linearize class method, as the Linearizer object will allow more efficient recalculation (i.e. about varying operating points).""" if (self._fr is None) or (self._frstar is None): raise ValueError('Need to compute Fr, Fr* first.') # Get required equation components. The Kane's method class breaks # these into pieces. Need to reassemble f_c = self._f_h if self._f_nh and self._k_nh: f_v = self._f_nh + self._k_nh*Matrix(self.u) else: f_v = Matrix() if self._f_dnh and self._k_dnh: f_a = self._f_dnh + self._k_dnh*Matrix(self._udot) else: f_a = Matrix() # Dicts to sub to zero, for splitting up expressions u_zero = {i: 0 for i in self.u} ud_zero = {i: 0 for i in self._udot} qd_zero = {i: 0 for i in self._qdot} qd_u_zero = {i: 0 for i in Matrix([self._qdot, self.u])} # Break the kinematic differential eqs apart into f_0 and f_1 f_0 = msubs(self._f_k, u_zero) + self._k_kqdot*Matrix(self._qdot) f_1 = msubs(self._f_k, qd_zero) + self._k_ku*Matrix(self.u) # Break the dynamic differential eqs into f_2 and f_3 f_2 = msubs(self._frstar, qd_u_zero) f_3 = msubs(self._frstar, ud_zero) + self._fr f_4 = zeros(len(f_2), 1) # Get the required vector components q = self.q u = self.u if self._qdep: q_i = q[:-len(self._qdep)] else: q_i = q q_d = self._qdep if self._udep: u_i = u[:-len(self._udep)] else: u_i = u u_d = self._udep # Form dictionary to set auxiliary speeds & their derivatives to 0. uaux = self._uaux uauxdot = uaux.diff(dynamicsymbols._t) uaux_zero = {i: 0 for i in Matrix([uaux, uauxdot])} # Checking for dynamic symbols outside the dynamic differential # equations; throws error if there is. sym_list = set(Matrix([q, self._qdot, u, self._udot, uaux, uauxdot])) if any(find_dynamicsymbols(i, sym_list) for i in [self._k_kqdot, self._k_ku, self._f_k, self._k_dnh, self._f_dnh, self._k_d]): raise ValueError('Cannot have dynamicsymbols outside dynamic \ forcing vector.') # Find all other dynamic symbols, forming the forcing vector r. # Sort r to make it canonical. r = list(find_dynamicsymbols(msubs(self._f_d, uaux_zero), sym_list)) r.sort(key=default_sort_key) # Check for any derivatives of variables in r that are also found in r. for i in r: if diff(i, dynamicsymbols._t) in r: raise ValueError('Cannot have derivatives of specified \ quantities when linearizing forcing terms.') return Linearizer(f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a, q, u, q_i, q_d, u_i, u_d, r) # TODO : Remove `new_method` after 1.1 has been released. def linearize(self, *, new_method=None, **kwargs): """ Linearize the equations of motion about a symbolic operating point. Explanation =========== If kwarg A_and_B is False (default), returns M, A, B, r for the linearized form, M*[q', u']^T = A*[q_ind, u_ind]^T + B*r. If kwarg A_and_B is True, returns A, B, r for the linearized form dx = A*x + B*r, where x = [q_ind, u_ind]^T. Note that this is computationally intensive if there are many symbolic parameters. For this reason, it may be more desirable to use the default A_and_B=False, returning M, A, and B. Values may then be substituted in to these matrices, and the state space form found as A = P.T*M.inv()*A, B = P.T*M.inv()*B, where P = Linearizer.perm_mat. In both cases, r is found as all dynamicsymbols in the equations of motion that are not part of q, u, q', or u'. They are sorted in canonical form. The operating points may be also entered using the ``op_point`` kwarg. This takes a dictionary of {symbol: value}, or a an iterable of such dictionaries. The values may be numeric or symbolic. The more values you can specify beforehand, the faster this computation will run. For more documentation, please see the ``Linearizer`` class.""" linearizer = self.to_linearizer() result = linearizer.linearize(**kwargs) return result + (linearizer.r,) def kanes_equations(self, bodies=None, loads=None): """ Method to form Kane's equations, Fr + Fr* = 0. Explanation =========== Returns (Fr, Fr*). In the case where auxiliary generalized speeds are present (say, s auxiliary speeds, o generalized speeds, and m motion constraints) the length of the returned vectors will be o - m + s in length. The first o - m equations will be the constrained Kane's equations, then the s auxiliary Kane's equations. These auxiliary equations can be accessed with the auxiliary_eqs(). Parameters ========== bodies : iterable An iterable of all RigidBody's and Particle's in the system. A system must have at least one body. loads : iterable Takes in an iterable of (Particle, Vector) or (ReferenceFrame, Vector) tuples which represent the force at a point or torque on a frame. Must be either a non-empty iterable of tuples or None which corresponds to a system with no constraints. """ if bodies is None: bodies = self.bodies if loads is None and self._forcelist is not None: loads = self._forcelist if loads == []: loads = None if not self._k_kqdot: raise AttributeError('Create an instance of KanesMethod with ' 'kinematic differential equations to use this method.') fr = self._form_fr(loads) frstar = self._form_frstar(bodies) if self._uaux: if not self._udep: km = KanesMethod(self._inertial, self.q, self._uaux, u_auxiliary=self._uaux) else: km = KanesMethod(self._inertial, self.q, self._uaux, u_auxiliary=self._uaux, u_dependent=self._udep, velocity_constraints=(self._k_nh * self.u + self._f_nh)) km._qdot_u_map = self._qdot_u_map self._km = km fraux = km._form_fr(loads) frstaraux = km._form_frstar(bodies) self._aux_eq = fraux + frstaraux self._fr = fr.col_join(fraux) self._frstar = frstar.col_join(frstaraux) return (self._fr, self._frstar) def _form_eoms(self): fr, frstar = self.kanes_equations(self.bodylist, self.forcelist) return fr + frstar def rhs(self, inv_method=None): """Returns the system's equations of motion in first order form. The output is the right hand side of:: x' = |q'| =: f(q, u, r, p, t) |u'| The right hand side is what is needed by most numerical ODE integrators. Parameters ========== inv_method : str The specific sympy inverse matrix calculation method to use. For a list of valid methods, see :meth:`~sympy.matrices.matrices.MatrixBase.inv` """ rhs = zeros(len(self.q) + len(self.u), 1) kdes = self.kindiffdict() for i, q_i in enumerate(self.q): rhs[i] = kdes[q_i.diff()] if inv_method is None: rhs[len(self.q):, 0] = self.mass_matrix.LUsolve(self.forcing) else: rhs[len(self.q):, 0] = (self.mass_matrix.inv(inv_method, try_block_diag=True) * self.forcing) return rhs def kindiffdict(self): """Returns a dictionary mapping q' to u.""" if not self._qdot_u_map: raise AttributeError('Create an instance of KanesMethod with ' 'kinematic differential equations to use this method.') return self._qdot_u_map @property def auxiliary_eqs(self): """A matrix containing the auxiliary equations.""" if not self._fr or not self._frstar: raise ValueError('Need to compute Fr, Fr* first.') if not self._uaux: raise ValueError('No auxiliary speeds have been declared.') return self._aux_eq @property def mass_matrix(self): """The mass matrix of the system.""" if not self._fr or not self._frstar: raise ValueError('Need to compute Fr, Fr* first.') return Matrix([self._k_d, self._k_dnh]) @property def mass_matrix_full(self): """The mass matrix of the system, augmented by the kinematic differential equations.""" if not self._fr or not self._frstar: raise ValueError('Need to compute Fr, Fr* first.') o = len(self.u) n = len(self.q) return ((self._k_kqdot).row_join(zeros(n, o))).col_join((zeros(o, n)).row_join(self.mass_matrix)) @property def forcing(self): """The forcing vector of the system.""" if not self._fr or not self._frstar: raise ValueError('Need to compute Fr, Fr* first.') return -Matrix([self._f_d, self._f_dnh]) @property def forcing_full(self): """The forcing vector of the system, augmented by the kinematic differential equations.""" if not self._fr or not self._frstar: raise ValueError('Need to compute Fr, Fr* first.') f1 = self._k_ku * Matrix(self.u) + self._f_k return -Matrix([f1, self._f_d, self._f_dnh]) @property def q(self): return self._q @property def u(self): return self._u @property def bodylist(self): return self._bodylist @property def forcelist(self): return self._forcelist @property def bodies(self): return self._bodylist @property def loads(self): return self._forcelist sympy-sympy-1.9/sympy/physics/mechanics/lagrange.py000066400000000000000000000436141412543434000226620ustar00rootroot00000000000000from sympy.core.backend import diff, zeros, Matrix, eye, sympify from sympy.physics.vector import dynamicsymbols, ReferenceFrame from sympy.physics.mechanics.method import _Methods from sympy.physics.mechanics.functions import (find_dynamicsymbols, msubs, _f_list_parser) from sympy.physics.mechanics.linearize import Linearizer from sympy.utilities import default_sort_key from sympy.utilities.iterables import iterable __all__ = ['LagrangesMethod'] class LagrangesMethod(_Methods): """Lagrange's method object. Explanation =========== This object generates the equations of motion in a two step procedure. The first step involves the initialization of LagrangesMethod by supplying the Lagrangian and the generalized coordinates, at the bare minimum. If there are any constraint equations, they can be supplied as keyword arguments. The Lagrange multipliers are automatically generated and are equal in number to the constraint equations. Similarly any non-conservative forces can be supplied in an iterable (as described below and also shown in the example) along with a ReferenceFrame. This is also discussed further in the __init__ method. Attributes ========== q, u : Matrix Matrices of the generalized coordinates and speeds loads : iterable Iterable of (Point, vector) or (ReferenceFrame, vector) tuples describing the forces on the system. bodies : iterable Iterable containing the rigid bodies and particles of the system. mass_matrix : Matrix The system's mass matrix forcing : Matrix The system's forcing vector mass_matrix_full : Matrix The "mass matrix" for the qdot's, qdoubledot's, and the lagrange multipliers (lam) forcing_full : Matrix The forcing vector for the qdot's, qdoubledot's and lagrange multipliers (lam) Examples ======== This is a simple example for a one degree of freedom translational spring-mass-damper. In this example, we first need to do the kinematics. This involves creating generalized coordinates and their derivatives. Then we create a point and set its velocity in a frame. >>> from sympy.physics.mechanics import LagrangesMethod, Lagrangian >>> from sympy.physics.mechanics import ReferenceFrame, Particle, Point >>> from sympy.physics.mechanics import dynamicsymbols >>> from sympy import symbols >>> q = dynamicsymbols('q') >>> qd = dynamicsymbols('q', 1) >>> m, k, b = symbols('m k b') >>> N = ReferenceFrame('N') >>> P = Point('P') >>> P.set_vel(N, qd * N.x) We need to then prepare the information as required by LagrangesMethod to generate equations of motion. First we create the Particle, which has a point attached to it. Following this the lagrangian is created from the kinetic and potential energies. Then, an iterable of nonconservative forces/torques must be constructed, where each item is a (Point, Vector) or (ReferenceFrame, Vector) tuple, with the Vectors representing the nonconservative forces or torques. >>> Pa = Particle('Pa', P, m) >>> Pa.potential_energy = k * q**2 / 2.0 >>> L = Lagrangian(N, Pa) >>> fl = [(P, -b * qd * N.x)] Finally we can generate the equations of motion. First we create the LagrangesMethod object. To do this one must supply the Lagrangian, and the generalized coordinates. The constraint equations, the forcelist, and the inertial frame may also be provided, if relevant. Next we generate Lagrange's equations of motion, such that: Lagrange's equations of motion = 0. We have the equations of motion at this point. >>> l = LagrangesMethod(L, [q], forcelist = fl, frame = N) >>> print(l.form_lagranges_equations()) Matrix([[b*Derivative(q(t), t) + 1.0*k*q(t) + m*Derivative(q(t), (t, 2))]]) We can also solve for the states using the 'rhs' method. >>> print(l.rhs()) Matrix([[Derivative(q(t), t)], [(-b*Derivative(q(t), t) - 1.0*k*q(t))/m]]) Please refer to the docstrings on each method for more details. """ def __init__(self, Lagrangian, qs, forcelist=None, bodies=None, frame=None, hol_coneqs=None, nonhol_coneqs=None): """Supply the following for the initialization of LagrangesMethod. Lagrangian : Sympifyable qs : array_like The generalized coordinates hol_coneqs : array_like, optional The holonomic constraint equations nonhol_coneqs : array_like, optional The nonholonomic constraint equations forcelist : iterable, optional Takes an iterable of (Point, Vector) or (ReferenceFrame, Vector) tuples which represent the force at a point or torque on a frame. This feature is primarily to account for the nonconservative forces and/or moments. bodies : iterable, optional Takes an iterable containing the rigid bodies and particles of the system. frame : ReferenceFrame, optional Supply the inertial frame. This is used to determine the generalized forces due to non-conservative forces. """ self._L = Matrix([sympify(Lagrangian)]) self.eom = None self._m_cd = Matrix() # Mass Matrix of differentiated coneqs self._m_d = Matrix() # Mass Matrix of dynamic equations self._f_cd = Matrix() # Forcing part of the diff coneqs self._f_d = Matrix() # Forcing part of the dynamic equations self.lam_coeffs = Matrix() # The coeffecients of the multipliers forcelist = forcelist if forcelist else [] if not iterable(forcelist): raise TypeError('Force pairs must be supplied in an iterable.') self._forcelist = forcelist if frame and not isinstance(frame, ReferenceFrame): raise TypeError('frame must be a valid ReferenceFrame') self._bodies = bodies self.inertial = frame self.lam_vec = Matrix() self._term1 = Matrix() self._term2 = Matrix() self._term3 = Matrix() self._term4 = Matrix() # Creating the qs, qdots and qdoubledots if not iterable(qs): raise TypeError('Generalized coordinates must be an iterable') self._q = Matrix(qs) self._qdots = self.q.diff(dynamicsymbols._t) self._qdoubledots = self._qdots.diff(dynamicsymbols._t) mat_build = lambda x: Matrix(x) if x else Matrix() hol_coneqs = mat_build(hol_coneqs) nonhol_coneqs = mat_build(nonhol_coneqs) self.coneqs = Matrix([hol_coneqs.diff(dynamicsymbols._t), nonhol_coneqs]) self._hol_coneqs = hol_coneqs def form_lagranges_equations(self): """Method to form Lagrange's equations of motion. Returns a vector of equations of motion using Lagrange's equations of the second kind. """ qds = self._qdots qdd_zero = {i: 0 for i in self._qdoubledots} n = len(self.q) # Internally we represent the EOM as four terms: # EOM = term1 - term2 - term3 - term4 = 0 # First term self._term1 = self._L.jacobian(qds) self._term1 = self._term1.diff(dynamicsymbols._t).T # Second term self._term2 = self._L.jacobian(self.q).T # Third term if self.coneqs: coneqs = self.coneqs m = len(coneqs) # Creating the multipliers self.lam_vec = Matrix(dynamicsymbols('lam1:' + str(m + 1))) self.lam_coeffs = -coneqs.jacobian(qds) self._term3 = self.lam_coeffs.T * self.lam_vec # Extracting the coeffecients of the qdds from the diff coneqs diffconeqs = coneqs.diff(dynamicsymbols._t) self._m_cd = diffconeqs.jacobian(self._qdoubledots) # The remaining terms i.e. the 'forcing' terms in diff coneqs self._f_cd = -diffconeqs.subs(qdd_zero) else: self._term3 = zeros(n, 1) # Fourth term if self.forcelist: N = self.inertial self._term4 = zeros(n, 1) for i, qd in enumerate(qds): flist = zip(*_f_list_parser(self.forcelist, N)) self._term4[i] = sum(v.diff(qd, N) & f for (v, f) in flist) else: self._term4 = zeros(n, 1) # Form the dynamic mass and forcing matrices without_lam = self._term1 - self._term2 - self._term4 self._m_d = without_lam.jacobian(self._qdoubledots) self._f_d = -without_lam.subs(qdd_zero) # Form the EOM self.eom = without_lam - self._term3 return self.eom def _form_eoms(self): return self.form_lagranges_equations() @property def mass_matrix(self): """Returns the mass matrix, which is augmented by the Lagrange multipliers, if necessary. Explanation =========== If the system is described by 'n' generalized coordinates and there are no constraint equations then an n X n matrix is returned. If there are 'n' generalized coordinates and 'm' constraint equations have been supplied during initialization then an n X (n+m) matrix is returned. The (n + m - 1)th and (n + m)th columns contain the coefficients of the Lagrange multipliers. """ if self.eom is None: raise ValueError('Need to compute the equations of motion first') if self.coneqs: return (self._m_d).row_join(self.lam_coeffs.T) else: return self._m_d @property def mass_matrix_full(self): """Augments the coefficients of qdots to the mass_matrix.""" if self.eom is None: raise ValueError('Need to compute the equations of motion first') n = len(self.q) m = len(self.coneqs) row1 = eye(n).row_join(zeros(n, n + m)) row2 = zeros(n, n).row_join(self.mass_matrix) if self.coneqs: row3 = zeros(m, n).row_join(self._m_cd).row_join(zeros(m, m)) return row1.col_join(row2).col_join(row3) else: return row1.col_join(row2) @property def forcing(self): """Returns the forcing vector from 'lagranges_equations' method.""" if self.eom is None: raise ValueError('Need to compute the equations of motion first') return self._f_d @property def forcing_full(self): """Augments qdots to the forcing vector above.""" if self.eom is None: raise ValueError('Need to compute the equations of motion first') if self.coneqs: return self._qdots.col_join(self.forcing).col_join(self._f_cd) else: return self._qdots.col_join(self.forcing) def to_linearizer(self, q_ind=None, qd_ind=None, q_dep=None, qd_dep=None): """Returns an instance of the Linearizer class, initiated from the data in the LagrangesMethod class. This may be more desirable than using the linearize class method, as the Linearizer object will allow more efficient recalculation (i.e. about varying operating points). Parameters ========== q_ind, qd_ind : array_like, optional The independent generalized coordinates and speeds. q_dep, qd_dep : array_like, optional The dependent generalized coordinates and speeds. """ # Compose vectors t = dynamicsymbols._t q = self.q u = self._qdots ud = u.diff(t) # Get vector of lagrange multipliers lams = self.lam_vec mat_build = lambda x: Matrix(x) if x else Matrix() q_i = mat_build(q_ind) q_d = mat_build(q_dep) u_i = mat_build(qd_ind) u_d = mat_build(qd_dep) # Compose general form equations f_c = self._hol_coneqs f_v = self.coneqs f_a = f_v.diff(t) f_0 = u f_1 = -u f_2 = self._term1 f_3 = -(self._term2 + self._term4) f_4 = -self._term3 # Check that there are an appropriate number of independent and # dependent coordinates if len(q_d) != len(f_c) or len(u_d) != len(f_v): raise ValueError(("Must supply {:} dependent coordinates, and " + "{:} dependent speeds").format(len(f_c), len(f_v))) if set(Matrix([q_i, q_d])) != set(q): raise ValueError("Must partition q into q_ind and q_dep, with " + "no extra or missing symbols.") if set(Matrix([u_i, u_d])) != set(u): raise ValueError("Must partition qd into qd_ind and qd_dep, " + "with no extra or missing symbols.") # Find all other dynamic symbols, forming the forcing vector r. # Sort r to make it canonical. insyms = set(Matrix([q, u, ud, lams])) r = list(find_dynamicsymbols(f_3, insyms)) r.sort(key=default_sort_key) # Check for any derivatives of variables in r that are also found in r. for i in r: if diff(i, dynamicsymbols._t) in r: raise ValueError('Cannot have derivatives of specified \ quantities when linearizing forcing terms.') return Linearizer(f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a, q, u, q_i, q_d, u_i, u_d, r, lams) def linearize(self, q_ind=None, qd_ind=None, q_dep=None, qd_dep=None, **kwargs): """Linearize the equations of motion about a symbolic operating point. Explanation =========== If kwarg A_and_B is False (default), returns M, A, B, r for the linearized form, M*[q', u']^T = A*[q_ind, u_ind]^T + B*r. If kwarg A_and_B is True, returns A, B, r for the linearized form dx = A*x + B*r, where x = [q_ind, u_ind]^T. Note that this is computationally intensive if there are many symbolic parameters. For this reason, it may be more desirable to use the default A_and_B=False, returning M, A, and B. Values may then be substituted in to these matrices, and the state space form found as A = P.T*M.inv()*A, B = P.T*M.inv()*B, where P = Linearizer.perm_mat. In both cases, r is found as all dynamicsymbols in the equations of motion that are not part of q, u, q', or u'. They are sorted in canonical form. The operating points may be also entered using the ``op_point`` kwarg. This takes a dictionary of {symbol: value}, or a an iterable of such dictionaries. The values may be numeric or symbolic. The more values you can specify beforehand, the faster this computation will run. For more documentation, please see the ``Linearizer`` class.""" linearizer = self.to_linearizer(q_ind, qd_ind, q_dep, qd_dep) result = linearizer.linearize(**kwargs) return result + (linearizer.r,) def solve_multipliers(self, op_point=None, sol_type='dict'): """Solves for the values of the lagrange multipliers symbolically at the specified operating point. Parameters ========== op_point : dict or iterable of dicts, optional Point at which to solve at. The operating point is specified as a dictionary or iterable of dictionaries of {symbol: value}. The value may be numeric or symbolic itself. sol_type : str, optional Solution return type. Valid options are: - 'dict': A dict of {symbol : value} (default) - 'Matrix': An ordered column matrix of the solution """ # Determine number of multipliers k = len(self.lam_vec) if k == 0: raise ValueError("System has no lagrange multipliers to solve for.") # Compose dict of operating conditions if isinstance(op_point, dict): op_point_dict = op_point elif iterable(op_point): op_point_dict = {} for op in op_point: op_point_dict.update(op) elif op_point is None: op_point_dict = {} else: raise TypeError("op_point must be either a dictionary or an " "iterable of dictionaries.") # Compose the system to be solved mass_matrix = self.mass_matrix.col_join(-self.lam_coeffs.row_join( zeros(k, k))) force_matrix = self.forcing.col_join(self._f_cd) # Sub in the operating point mass_matrix = msubs(mass_matrix, op_point_dict) force_matrix = msubs(force_matrix, op_point_dict) # Solve for the multipliers sol_list = mass_matrix.LUsolve(-force_matrix)[-k:] if sol_type == 'dict': return dict(zip(self.lam_vec, sol_list)) elif sol_type == 'Matrix': return Matrix(sol_list) else: raise ValueError("Unknown sol_type {:}.".format(sol_type)) def rhs(self, inv_method=None, **kwargs): """Returns equations that can be solved numerically. Parameters ========== inv_method : str The specific sympy inverse matrix calculation method to use. For a list of valid methods, see :meth:`~sympy.matrices.matrices.MatrixBase.inv` """ if inv_method is None: self._rhs = self.mass_matrix_full.LUsolve(self.forcing_full) else: self._rhs = (self.mass_matrix_full.inv(inv_method, try_block_diag=True) * self.forcing_full) return self._rhs @property def q(self): return self._q @property def u(self): return self._qdots @property def bodies(self): return self._bodies @property def forcelist(self): return self._forcelist @property def loads(self): return self._forcelist sympy-sympy-1.9/sympy/physics/mechanics/linearize.py000066400000000000000000000357651412543434000230740ustar00rootroot00000000000000__all__ = ['Linearizer'] from sympy.core.backend import Matrix, eye, zeros from sympy import Dummy from sympy.utilities.iterables import flatten from sympy.physics.vector import dynamicsymbols from sympy.physics.mechanics.functions import msubs from collections import namedtuple from collections.abc import Iterable class Linearizer: """This object holds the general model form for a dynamic system. This model is used for computing the linearized form of the system, while properly dealing with constraints leading to dependent coordinates and speeds. Attributes ========== f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a : Matrix Matrices holding the general system form. q, u, r : Matrix Matrices holding the generalized coordinates, speeds, and input vectors. q_i, u_i : Matrix Matrices of the independent generalized coordinates and speeds. q_d, u_d : Matrix Matrices of the dependent generalized coordinates and speeds. perm_mat : Matrix Permutation matrix such that [q_ind, u_ind]^T = perm_mat*[q, u]^T """ def __init__(self, f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a, q, u, q_i=None, q_d=None, u_i=None, u_d=None, r=None, lams=None): """ Parameters ========== f_0, f_1, f_2, f_3, f_4, f_c, f_v, f_a : array_like System of equations holding the general system form. Supply empty array or Matrix if the parameter doesn't exist. q : array_like The generalized coordinates. u : array_like The generalized speeds q_i, u_i : array_like, optional The independent generalized coordinates and speeds. q_d, u_d : array_like, optional The dependent generalized coordinates and speeds. r : array_like, optional The input variables. lams : array_like, optional The lagrange multipliers """ # Generalized equation form self.f_0 = Matrix(f_0) self.f_1 = Matrix(f_1) self.f_2 = Matrix(f_2) self.f_3 = Matrix(f_3) self.f_4 = Matrix(f_4) self.f_c = Matrix(f_c) self.f_v = Matrix(f_v) self.f_a = Matrix(f_a) # Generalized equation variables self.q = Matrix(q) self.u = Matrix(u) none_handler = lambda x: Matrix(x) if x else Matrix() self.q_i = none_handler(q_i) self.q_d = none_handler(q_d) self.u_i = none_handler(u_i) self.u_d = none_handler(u_d) self.r = none_handler(r) self.lams = none_handler(lams) # Derivatives of generalized equation variables self._qd = self.q.diff(dynamicsymbols._t) self._ud = self.u.diff(dynamicsymbols._t) # If the user doesn't actually use generalized variables, and the # qd and u vectors have any intersecting variables, this can cause # problems. We'll fix this with some hackery, and Dummy variables dup_vars = set(self._qd).intersection(self.u) self._qd_dup = Matrix([var if var not in dup_vars else Dummy() for var in self._qd]) # Derive dimesion terms l = len(self.f_c) m = len(self.f_v) n = len(self.q) o = len(self.u) s = len(self.r) k = len(self.lams) dims = namedtuple('dims', ['l', 'm', 'n', 'o', 's', 'k']) self._dims = dims(l, m, n, o, s, k) self._setup_done = False def _setup(self): # Calculations here only need to be run once. They are moved out of # the __init__ method to increase the speed of Linearizer creation. self._form_permutation_matrices() self._form_block_matrices() self._form_coefficient_matrices() self._setup_done = True def _form_permutation_matrices(self): """Form the permutation matrices Pq and Pu.""" # Extract dimension variables l, m, n, o, s, k = self._dims # Compute permutation matrices if n != 0: self._Pq = permutation_matrix(self.q, Matrix([self.q_i, self.q_d])) if l > 0: self._Pqi = self._Pq[:, :-l] self._Pqd = self._Pq[:, -l:] else: self._Pqi = self._Pq self._Pqd = Matrix() if o != 0: self._Pu = permutation_matrix(self.u, Matrix([self.u_i, self.u_d])) if m > 0: self._Pui = self._Pu[:, :-m] self._Pud = self._Pu[:, -m:] else: self._Pui = self._Pu self._Pud = Matrix() # Compute combination permutation matrix for computing A and B P_col1 = Matrix([self._Pqi, zeros(o + k, n - l)]) P_col2 = Matrix([zeros(n, o - m), self._Pui, zeros(k, o - m)]) if P_col1: if P_col2: self.perm_mat = P_col1.row_join(P_col2) else: self.perm_mat = P_col1 else: self.perm_mat = P_col2 def _form_coefficient_matrices(self): """Form the coefficient matrices C_0, C_1, and C_2.""" # Extract dimension variables l, m, n, o, s, k = self._dims # Build up the coefficient matrices C_0, C_1, and C_2 # If there are configuration constraints (l > 0), form C_0 as normal. # If not, C_0 is I_(nxn). Note that this works even if n=0 if l > 0: f_c_jac_q = self.f_c.jacobian(self.q) self._C_0 = (eye(n) - self._Pqd * (f_c_jac_q * self._Pqd).LUsolve(f_c_jac_q)) * self._Pqi else: self._C_0 = eye(n) # If there are motion constraints (m > 0), form C_1 and C_2 as normal. # If not, C_1 is 0, and C_2 is I_(oxo). Note that this works even if # o = 0. if m > 0: f_v_jac_u = self.f_v.jacobian(self.u) temp = f_v_jac_u * self._Pud if n != 0: f_v_jac_q = self.f_v.jacobian(self.q) self._C_1 = -self._Pud * temp.LUsolve(f_v_jac_q) else: self._C_1 = zeros(o, n) self._C_2 = (eye(o) - self._Pud * temp.LUsolve(f_v_jac_u)) * self._Pui else: self._C_1 = zeros(o, n) self._C_2 = eye(o) def _form_block_matrices(self): """Form the block matrices for composing M, A, and B.""" # Extract dimension variables l, m, n, o, s, k = self._dims # Block Matrix Definitions. These are only defined if under certain # conditions. If undefined, an empty matrix is used instead if n != 0: self._M_qq = self.f_0.jacobian(self._qd) self._A_qq = -(self.f_0 + self.f_1).jacobian(self.q) else: self._M_qq = Matrix() self._A_qq = Matrix() if n != 0 and m != 0: self._M_uqc = self.f_a.jacobian(self._qd_dup) self._A_uqc = -self.f_a.jacobian(self.q) else: self._M_uqc = Matrix() self._A_uqc = Matrix() if n != 0 and o - m + k != 0: self._M_uqd = self.f_3.jacobian(self._qd_dup) self._A_uqd = -(self.f_2 + self.f_3 + self.f_4).jacobian(self.q) else: self._M_uqd = Matrix() self._A_uqd = Matrix() if o != 0 and m != 0: self._M_uuc = self.f_a.jacobian(self._ud) self._A_uuc = -self.f_a.jacobian(self.u) else: self._M_uuc = Matrix() self._A_uuc = Matrix() if o != 0 and o - m + k != 0: self._M_uud = self.f_2.jacobian(self._ud) self._A_uud = -(self.f_2 + self.f_3).jacobian(self.u) else: self._M_uud = Matrix() self._A_uud = Matrix() if o != 0 and n != 0: self._A_qu = -self.f_1.jacobian(self.u) else: self._A_qu = Matrix() if k != 0 and o - m + k != 0: self._M_uld = self.f_4.jacobian(self.lams) else: self._M_uld = Matrix() if s != 0 and o - m + k != 0: self._B_u = -self.f_3.jacobian(self.r) else: self._B_u = Matrix() def linearize(self, op_point=None, A_and_B=False, simplify=False): """Linearize the system about the operating point. Note that q_op, u_op, qd_op, ud_op must satisfy the equations of motion. These may be either symbolic or numeric. Parameters ========== op_point : dict or iterable of dicts, optional Dictionary or iterable of dictionaries containing the operating point conditions. These will be substituted in to the linearized system before the linearization is complete. Leave blank if you want a completely symbolic form. Note that any reduction in symbols (whether substituted for numbers or expressions with a common parameter) will result in faster runtime. A_and_B : bool, optional If A_and_B=False (default), (M, A, B) is returned for forming [M]*[q, u]^T = [A]*[q_ind, u_ind]^T + [B]r. If A_and_B=True, (A, B) is returned for forming dx = [A]x + [B]r, where x = [q_ind, u_ind]^T. simplify : bool, optional Determines if returned values are simplified before return. For large expressions this may be time consuming. Default is False. Potential Issues ================ Note that the process of solving with A_and_B=True is computationally intensive if there are many symbolic parameters. For this reason, it may be more desirable to use the default A_and_B=False, returning M, A, and B. More values may then be substituted in to these matrices later on. The state space form can then be found as A = P.T*M.LUsolve(A), B = P.T*M.LUsolve(B), where P = Linearizer.perm_mat. """ # Run the setup if needed: if not self._setup_done: self._setup() # Compose dict of operating conditions if isinstance(op_point, dict): op_point_dict = op_point elif isinstance(op_point, Iterable): op_point_dict = {} for op in op_point: op_point_dict.update(op) else: op_point_dict = {} # Extract dimension variables l, m, n, o, s, k = self._dims # Rename terms to shorten expressions M_qq = self._M_qq M_uqc = self._M_uqc M_uqd = self._M_uqd M_uuc = self._M_uuc M_uud = self._M_uud M_uld = self._M_uld A_qq = self._A_qq A_uqc = self._A_uqc A_uqd = self._A_uqd A_qu = self._A_qu A_uuc = self._A_uuc A_uud = self._A_uud B_u = self._B_u C_0 = self._C_0 C_1 = self._C_1 C_2 = self._C_2 # Build up Mass Matrix # |M_qq 0_nxo 0_nxk| # M = |M_uqc M_uuc 0_mxk| # |M_uqd M_uud M_uld| if o != 0: col2 = Matrix([zeros(n, o), M_uuc, M_uud]) if k != 0: col3 = Matrix([zeros(n + m, k), M_uld]) if n != 0: col1 = Matrix([M_qq, M_uqc, M_uqd]) if o != 0 and k != 0: M = col1.row_join(col2).row_join(col3) elif o != 0: M = col1.row_join(col2) else: M = col1 elif k != 0: M = col2.row_join(col3) else: M = col2 M_eq = msubs(M, op_point_dict) # Build up state coefficient matrix A # |(A_qq + A_qu*C_1)*C_0 A_qu*C_2| # A = |(A_uqc + A_uuc*C_1)*C_0 A_uuc*C_2| # |(A_uqd + A_uud*C_1)*C_0 A_uud*C_2| # Col 1 is only defined if n != 0 if n != 0: r1c1 = A_qq if o != 0: r1c1 += (A_qu * C_1) r1c1 = r1c1 * C_0 if m != 0: r2c1 = A_uqc if o != 0: r2c1 += (A_uuc * C_1) r2c1 = r2c1 * C_0 else: r2c1 = Matrix() if o - m + k != 0: r3c1 = A_uqd if o != 0: r3c1 += (A_uud * C_1) r3c1 = r3c1 * C_0 else: r3c1 = Matrix() col1 = Matrix([r1c1, r2c1, r3c1]) else: col1 = Matrix() # Col 2 is only defined if o != 0 if o != 0: if n != 0: r1c2 = A_qu * C_2 else: r1c2 = Matrix() if m != 0: r2c2 = A_uuc * C_2 else: r2c2 = Matrix() if o - m + k != 0: r3c2 = A_uud * C_2 else: r3c2 = Matrix() col2 = Matrix([r1c2, r2c2, r3c2]) else: col2 = Matrix() if col1: if col2: Amat = col1.row_join(col2) else: Amat = col1 else: Amat = col2 Amat_eq = msubs(Amat, op_point_dict) # Build up the B matrix if there are forcing variables # |0_(n + m)xs| # B = |B_u | if s != 0 and o - m + k != 0: Bmat = zeros(n + m, s).col_join(B_u) Bmat_eq = msubs(Bmat, op_point_dict) else: Bmat_eq = Matrix() # kwarg A_and_B indicates to return A, B for forming the equation # dx = [A]x + [B]r, where x = [q_indnd, u_indnd]^T, if A_and_B: A_cont = self.perm_mat.T * M_eq.LUsolve(Amat_eq) if Bmat_eq: B_cont = self.perm_mat.T * M_eq.LUsolve(Bmat_eq) else: # Bmat = Matrix([]), so no need to sub B_cont = Bmat_eq if simplify: A_cont.simplify() B_cont.simplify() return A_cont, B_cont # Otherwise return M, A, B for forming the equation # [M]dx = [A]x + [B]r, where x = [q, u]^T else: if simplify: M_eq.simplify() Amat_eq.simplify() Bmat_eq.simplify() return M_eq, Amat_eq, Bmat_eq def permutation_matrix(orig_vec, per_vec): """Compute the permutation matrix to change order of orig_vec into order of per_vec. Parameters ========== orig_vec : array_like Symbols in original ordering. per_vec : array_like Symbols in new ordering. Returns ======= p_matrix : Matrix Permutation matrix such that orig_vec == (p_matrix * per_vec). """ if not isinstance(orig_vec, (list, tuple)): orig_vec = flatten(orig_vec) if not isinstance(per_vec, (list, tuple)): per_vec = flatten(per_vec) if set(orig_vec) != set(per_vec): raise ValueError("orig_vec and per_vec must be the same length, " + "and contain the same symbols.") ind_list = [orig_vec.index(i) for i in per_vec] p_matrix = zeros(len(orig_vec)) for i, j in enumerate(ind_list): p_matrix[i, j] = 1 return p_matrix sympy-sympy-1.9/sympy/physics/mechanics/method.py000066400000000000000000000012241412543434000223510ustar00rootroot00000000000000from abc import ABC, abstractmethod class _Methods(ABC): """Abstract Base Class for all methods.""" @abstractmethod def q(self): pass @abstractmethod def u(self): pass @abstractmethod def bodies(self): pass @abstractmethod def loads(self): pass @abstractmethod def mass_matrix(self): pass @abstractmethod def forcing(self): pass @abstractmethod def mass_matrix_full(self): pass @abstractmethod def forcing_full(self): pass def _form_eoms(self): raise NotImplementedError("Subclasses must implement this.") sympy-sympy-1.9/sympy/physics/mechanics/models.py000066400000000000000000000144771412543434000223720ustar00rootroot00000000000000#!/usr/bin/env python """This module contains some sample symbolic models used for testing and examples.""" # Internal imports from sympy.core import backend as sm import sympy.physics.mechanics as me def multi_mass_spring_damper(n=1, apply_gravity=False, apply_external_forces=False): r"""Returns a system containing the symbolic equations of motion and associated variables for a simple multi-degree of freedom point mass, spring, damper system with optional gravitational and external specified forces. For example, a two mass system under the influence of gravity and external forces looks like: :: ---------------- | | | | g \ | | | V k0 / --- c0 | | | | x0, v0 --------- V | m0 | ----- --------- | | | | | \ v | | | k1 / f0 --- c1 | | | | x1, v1 --------- V | m1 | ----- --------- | f1 V Parameters ========== n : integer The number of masses in the serial chain. apply_gravity : boolean If true, gravity will be applied to each mass. apply_external_forces : boolean If true, a time varying external force will be applied to each mass. Returns ======= kane : sympy.physics.mechanics.kane.KanesMethod A KanesMethod object. """ mass = sm.symbols('m:{}'.format(n)) stiffness = sm.symbols('k:{}'.format(n)) damping = sm.symbols('c:{}'.format(n)) acceleration_due_to_gravity = sm.symbols('g') coordinates = me.dynamicsymbols('x:{}'.format(n)) speeds = me.dynamicsymbols('v:{}'.format(n)) specifieds = me.dynamicsymbols('f:{}'.format(n)) ceiling = me.ReferenceFrame('N') origin = me.Point('origin') origin.set_vel(ceiling, 0) points = [origin] kinematic_equations = [] particles = [] forces = [] for i in range(n): center = points[-1].locatenew('center{}'.format(i), coordinates[i] * ceiling.x) center.set_vel(ceiling, points[-1].vel(ceiling) + speeds[i] * ceiling.x) points.append(center) block = me.Particle('block{}'.format(i), center, mass[i]) kinematic_equations.append(speeds[i] - coordinates[i].diff()) total_force = (-stiffness[i] * coordinates[i] - damping[i] * speeds[i]) try: total_force += (stiffness[i + 1] * coordinates[i + 1] + damping[i + 1] * speeds[i + 1]) except IndexError: # no force from below on last mass pass if apply_gravity: total_force += mass[i] * acceleration_due_to_gravity if apply_external_forces: total_force += specifieds[i] forces.append((center, total_force * ceiling.x)) particles.append(block) kane = me.KanesMethod(ceiling, q_ind=coordinates, u_ind=speeds, kd_eqs=kinematic_equations) kane.kanes_equations(particles, forces) return kane def n_link_pendulum_on_cart(n=1, cart_force=True, joint_torques=False): r"""Returns the system containing the symbolic first order equations of motion for a 2D n-link pendulum on a sliding cart under the influence of gravity. :: | o y v \ 0 ^ g \ | --\-|---- | \| | F-> | o --|---> x | | --------- o o Parameters ========== n : integer The number of links in the pendulum. cart_force : boolean, default=True If true an external specified lateral force is applied to the cart. joint_torques : boolean, default=False If true joint torques will be added as specified inputs at each joint. Returns ======= kane : sympy.physics.mechanics.kane.KanesMethod A KanesMethod object. Notes ===== The degrees of freedom of the system are n + 1, i.e. one for each pendulum link and one for the lateral motion of the cart. M x' = F, where x = [u0, ..., un+1, q0, ..., qn+1] The joint angles are all defined relative to the ground where the x axis defines the ground line and the y axis points up. The joint torques are applied between each adjacent link and the between the cart and the lower link where a positive torque corresponds to positive angle. """ if n <= 0: raise ValueError('The number of links must be a positive integer.') q = me.dynamicsymbols('q:{}'.format(n + 1)) u = me.dynamicsymbols('u:{}'.format(n + 1)) if joint_torques is True: T = me.dynamicsymbols('T1:{}'.format(n + 1)) m = sm.symbols('m:{}'.format(n + 1)) l = sm.symbols('l:{}'.format(n)) g, t = sm.symbols('g t') I = me.ReferenceFrame('I') O = me.Point('O') O.set_vel(I, 0) P0 = me.Point('P0') P0.set_pos(O, q[0] * I.x) P0.set_vel(I, u[0] * I.x) Pa0 = me.Particle('Pa0', P0, m[0]) frames = [I] points = [P0] particles = [Pa0] forces = [(P0, -m[0] * g * I.y)] kindiffs = [q[0].diff(t) - u[0]] if cart_force is True or joint_torques is True: specified = [] else: specified = None for i in range(n): Bi = I.orientnew('B{}'.format(i), 'Axis', [q[i + 1], I.z]) Bi.set_ang_vel(I, u[i + 1] * I.z) frames.append(Bi) Pi = points[-1].locatenew('P{}'.format(i + 1), l[i] * Bi.y) Pi.v2pt_theory(points[-1], I, Bi) points.append(Pi) Pai = me.Particle('Pa' + str(i + 1), Pi, m[i + 1]) particles.append(Pai) forces.append((Pi, -m[i + 1] * g * I.y)) if joint_torques is True: specified.append(T[i]) if i == 0: forces.append((I, -T[i] * I.z)) if i == n - 1: forces.append((Bi, T[i] * I.z)) else: forces.append((Bi, T[i] * I.z - T[i + 1] * I.z)) kindiffs.append(q[i + 1].diff(t) - u[i + 1]) if cart_force is True: F = me.dynamicsymbols('F') forces.append((P0, F * I.x)) specified.append(F) kane = me.KanesMethod(I, q_ind=q, u_ind=u, kd_eqs=kindiffs) kane.kanes_equations(particles, forces) return kane sympy-sympy-1.9/sympy/physics/mechanics/particle.py000066400000000000000000000166311412543434000227040ustar00rootroot00000000000000from sympy.core.backend import sympify from sympy.physics.vector import Point from sympy.utilities.exceptions import SymPyDeprecationWarning __all__ = ['Particle'] class Particle: """A particle. Explanation =========== Particles have a non-zero mass and lack spatial extension; they take up no space. Values need to be supplied on initialization, but can be changed later. Parameters ========== name : str Name of particle point : Point A physics/mechanics Point which represents the position, velocity, and acceleration of this Particle mass : sympifyable A SymPy expression representing the Particle's mass Examples ======== >>> from sympy.physics.mechanics import Particle, Point >>> from sympy import Symbol >>> po = Point('po') >>> m = Symbol('m') >>> pa = Particle('pa', po, m) >>> # Or you could change these later >>> pa.mass = m >>> pa.point = po """ def __init__(self, name, point, mass): if not isinstance(name, str): raise TypeError('Supply a valid name.') self._name = name self.mass = mass self.point = point self.potential_energy = 0 def __str__(self): return self._name def __repr__(self): return self.__str__() @property def mass(self): """Mass of the particle.""" return self._mass @mass.setter def mass(self, value): self._mass = sympify(value) @property def point(self): """Point of the particle.""" return self._point @point.setter def point(self, p): if not isinstance(p, Point): raise TypeError("Particle point attribute must be a Point object.") self._point = p def linear_momentum(self, frame): """Linear momentum of the particle. Explanation =========== The linear momentum L, of a particle P, with respect to frame N is given by L = m * v where m is the mass of the particle, and v is the velocity of the particle in the frame N. Parameters ========== frame : ReferenceFrame The frame in which linear momentum is desired. Examples ======== >>> from sympy.physics.mechanics import Particle, Point, ReferenceFrame >>> from sympy.physics.mechanics import dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> m, v = dynamicsymbols('m v') >>> N = ReferenceFrame('N') >>> P = Point('P') >>> A = Particle('A', P, m) >>> P.set_vel(N, v * N.x) >>> A.linear_momentum(N) m*v*N.x """ return self.mass * self.point.vel(frame) def angular_momentum(self, point, frame): """Angular momentum of the particle about the point. Explanation =========== The angular momentum H, about some point O of a particle, P, is given by: H = r x m * v where r is the position vector from point O to the particle P, m is the mass of the particle, and v is the velocity of the particle in the inertial frame, N. Parameters ========== point : Point The point about which angular momentum of the particle is desired. frame : ReferenceFrame The frame in which angular momentum is desired. Examples ======== >>> from sympy.physics.mechanics import Particle, Point, ReferenceFrame >>> from sympy.physics.mechanics import dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> m, v, r = dynamicsymbols('m v r') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> A = O.locatenew('A', r * N.x) >>> P = Particle('P', A, m) >>> P.point.set_vel(N, v * N.y) >>> P.angular_momentum(O, N) m*r*v*N.z """ return self.point.pos_from(point) ^ (self.mass * self.point.vel(frame)) def kinetic_energy(self, frame): """Kinetic energy of the particle. Explanation =========== The kinetic energy, T, of a particle, P, is given by 'T = 1/2 m v^2' where m is the mass of particle P, and v is the velocity of the particle in the supplied ReferenceFrame. Parameters ========== frame : ReferenceFrame The Particle's velocity is typically defined with respect to an inertial frame but any relevant frame in which the velocity is known can be supplied. Examples ======== >>> from sympy.physics.mechanics import Particle, Point, ReferenceFrame >>> from sympy import symbols >>> m, v, r = symbols('m v r') >>> N = ReferenceFrame('N') >>> O = Point('O') >>> P = Particle('P', O, m) >>> P.point.set_vel(N, v * N.y) >>> P.kinetic_energy(N) m*v**2/2 """ return (self.mass / sympify(2) * self.point.vel(frame) & self.point.vel(frame)) @property def potential_energy(self): """The potential energy of the Particle. Examples ======== >>> from sympy.physics.mechanics import Particle, Point >>> from sympy import symbols >>> m, g, h = symbols('m g h') >>> O = Point('O') >>> P = Particle('P', O, m) >>> P.potential_energy = m * g * h >>> P.potential_energy g*h*m """ return self._pe @potential_energy.setter def potential_energy(self, scalar): """Used to set the potential energy of the Particle. Parameters ========== scalar : Sympifyable The potential energy (a scalar) of the Particle. Examples ======== >>> from sympy.physics.mechanics import Particle, Point >>> from sympy import symbols >>> m, g, h = symbols('m g h') >>> O = Point('O') >>> P = Particle('P', O, m) >>> P.potential_energy = m * g * h """ self._pe = sympify(scalar) def set_potential_energy(self, scalar): SymPyDeprecationWarning( feature="Method sympy.physics.mechanics." + "Particle.set_potential_energy(self, scalar)", useinstead="property sympy.physics.mechanics." + "Particle.potential_energy", deprecated_since_version="1.5", issue=9800).warn() self.potential_energy = scalar def parallel_axis(self, point, frame): """Returns an inertia dyadic of the particle with respect to another point and frame. Parameters ========== point : sympy.physics.vector.Point The point to express the inertia dyadic about. frame : sympy.physics.vector.ReferenceFrame The reference frame used to construct the dyadic. Returns ======= inertia : sympy.physics.vector.Dyadic The inertia dyadic of the particle expressed about the provided point and frame. """ # circular import issue from sympy.physics.mechanics import inertia_of_point_mass return inertia_of_point_mass(self.mass, self.point.pos_from(point), frame) sympy-sympy-1.9/sympy/physics/mechanics/rigidbody.py000066400000000000000000000250671412543434000230600ustar00rootroot00000000000000from sympy.core.backend import sympify from sympy.physics.vector import Point, ReferenceFrame, Dyadic from sympy.utilities.exceptions import SymPyDeprecationWarning __all__ = ['RigidBody'] class RigidBody: """An idealized rigid body. Explanation =========== This is essentially a container which holds the various components which describe a rigid body: a name, mass, center of mass, reference frame, and inertia. All of these need to be supplied on creation, but can be changed afterwards. Attributes ========== name : string The body's name. masscenter : Point The point which represents the center of mass of the rigid body. frame : ReferenceFrame The ReferenceFrame which the rigid body is fixed in. mass : Sympifyable The body's mass. inertia : (Dyadic, Point) The body's inertia about a point; stored in a tuple as shown above. Examples ======== >>> from sympy import Symbol >>> from sympy.physics.mechanics import ReferenceFrame, Point, RigidBody >>> from sympy.physics.mechanics import outer >>> m = Symbol('m') >>> A = ReferenceFrame('A') >>> P = Point('P') >>> I = outer (A.x, A.x) >>> inertia_tuple = (I, P) >>> B = RigidBody('B', P, A, m, inertia_tuple) >>> # Or you could change them afterwards >>> m2 = Symbol('m2') >>> B.mass = m2 """ def __init__(self, name, masscenter, frame, mass, inertia): if not isinstance(name, str): raise TypeError('Supply a valid name.') self._name = name self.masscenter = masscenter self.mass = mass self.frame = frame self.inertia = inertia self.potential_energy = 0 def __str__(self): return self._name def __repr__(self): return self.__str__() @property def frame(self): return self._frame @frame.setter def frame(self, F): if not isinstance(F, ReferenceFrame): raise TypeError("RigdBody frame must be a ReferenceFrame object.") self._frame = F @property def masscenter(self): return self._masscenter @masscenter.setter def masscenter(self, p): if not isinstance(p, Point): raise TypeError("RigidBody center of mass must be a Point object.") self._masscenter = p @property def mass(self): return self._mass @mass.setter def mass(self, m): self._mass = sympify(m) @property def inertia(self): return (self._inertia, self._inertia_point) @inertia.setter def inertia(self, I): if not isinstance(I[0], Dyadic): raise TypeError("RigidBody inertia must be a Dyadic object.") if not isinstance(I[1], Point): raise TypeError("RigidBody inertia must be about a Point.") self._inertia = I[0] self._inertia_point = I[1] # have I S/O, want I S/S* # I S/O = I S/S* + I S*/O; I S/S* = I S/O - I S*/O # I_S/S* = I_S/O - I_S*/O from sympy.physics.mechanics.functions import inertia_of_point_mass I_Ss_O = inertia_of_point_mass(self.mass, self.masscenter.pos_from(I[1]), self.frame) self._central_inertia = I[0] - I_Ss_O @property def central_inertia(self): """The body's central inertia dyadic.""" return self._central_inertia def linear_momentum(self, frame): """ Linear momentum of the rigid body. Explanation =========== The linear momentum L, of a rigid body B, with respect to frame N is given by L = M * v* where M is the mass of the rigid body and v* is the velocity of the mass center of B in the frame, N. Parameters ========== frame : ReferenceFrame The frame in which linear momentum is desired. Examples ======== >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer >>> from sympy.physics.mechanics import RigidBody, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> M, v = dynamicsymbols('M v') >>> N = ReferenceFrame('N') >>> P = Point('P') >>> P.set_vel(N, v * N.x) >>> I = outer (N.x, N.x) >>> Inertia_tuple = (I, P) >>> B = RigidBody('B', P, N, M, Inertia_tuple) >>> B.linear_momentum(N) M*v*N.x """ return self.mass * self.masscenter.vel(frame) def angular_momentum(self, point, frame): """Returns the angular momentum of the rigid body about a point in the given frame. Explanation =========== The angular momentum H of a rigid body B about some point O in a frame N is given by: H = I . w + r x Mv where I is the central inertia dyadic of B, w is the angular velocity of body B in the frame, N, r is the position vector from point O to the mass center of B, and v is the velocity of the mass center in the frame, N. Parameters ========== point : Point The point about which angular momentum is desired. frame : ReferenceFrame The frame in which angular momentum is desired. Examples ======== >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer >>> from sympy.physics.mechanics import RigidBody, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> M, v, r, omega = dynamicsymbols('M v r omega') >>> N = ReferenceFrame('N') >>> b = ReferenceFrame('b') >>> b.set_ang_vel(N, omega * b.x) >>> P = Point('P') >>> P.set_vel(N, 1 * N.x) >>> I = outer(b.x, b.x) >>> B = RigidBody('B', P, b, M, (I, P)) >>> B.angular_momentum(P, N) omega*b.x """ I = self.central_inertia w = self.frame.ang_vel_in(frame) m = self.mass r = self.masscenter.pos_from(point) v = self.masscenter.vel(frame) return I.dot(w) + r.cross(m * v) def kinetic_energy(self, frame): """Kinetic energy of the rigid body. Explanation =========== The kinetic energy, T, of a rigid body, B, is given by 'T = 1/2 (I omega^2 + m v^2)' where I and m are the central inertia dyadic and mass of rigid body B, respectively, omega is the body's angular velocity and v is the velocity of the body's mass center in the supplied ReferenceFrame. Parameters ========== frame : ReferenceFrame The RigidBody's angular velocity and the velocity of it's mass center are typically defined with respect to an inertial frame but any relevant frame in which the velocities are known can be supplied. Examples ======== >>> from sympy.physics.mechanics import Point, ReferenceFrame, outer >>> from sympy.physics.mechanics import RigidBody >>> from sympy import symbols >>> M, v, r, omega = symbols('M v r omega') >>> N = ReferenceFrame('N') >>> b = ReferenceFrame('b') >>> b.set_ang_vel(N, omega * b.x) >>> P = Point('P') >>> P.set_vel(N, v * N.x) >>> I = outer (b.x, b.x) >>> inertia_tuple = (I, P) >>> B = RigidBody('B', P, b, M, inertia_tuple) >>> B.kinetic_energy(N) M*v**2/2 + omega**2/2 """ rotational_KE = (self.frame.ang_vel_in(frame) & (self.central_inertia & self.frame.ang_vel_in(frame)) / sympify(2)) translational_KE = (self.mass * (self.masscenter.vel(frame) & self.masscenter.vel(frame)) / sympify(2)) return rotational_KE + translational_KE @property def potential_energy(self): """The potential energy of the RigidBody. Examples ======== >>> from sympy.physics.mechanics import RigidBody, Point, outer, ReferenceFrame >>> from sympy import symbols >>> M, g, h = symbols('M g h') >>> b = ReferenceFrame('b') >>> P = Point('P') >>> I = outer (b.x, b.x) >>> Inertia_tuple = (I, P) >>> B = RigidBody('B', P, b, M, Inertia_tuple) >>> B.potential_energy = M * g * h >>> B.potential_energy M*g*h """ return self._pe @potential_energy.setter def potential_energy(self, scalar): """Used to set the potential energy of this RigidBody. Parameters ========== scalar: Sympifyable The potential energy (a scalar) of the RigidBody. Examples ======== >>> from sympy.physics.mechanics import Point, outer >>> from sympy.physics.mechanics import RigidBody, ReferenceFrame >>> from sympy import symbols >>> b = ReferenceFrame('b') >>> M, g, h = symbols('M g h') >>> P = Point('P') >>> I = outer (b.x, b.x) >>> Inertia_tuple = (I, P) >>> B = RigidBody('B', P, b, M, Inertia_tuple) >>> B.potential_energy = M * g * h """ self._pe = sympify(scalar) def set_potential_energy(self, scalar): SymPyDeprecationWarning( feature="Method sympy.physics.mechanics." + "RigidBody.set_potential_energy(self, scalar)", useinstead="property sympy.physics.mechanics." + "RigidBody.potential_energy", deprecated_since_version="1.5", issue=9800).warn() self.potential_energy = scalar # XXX: To be consistent with the parallel_axis method in Particle this # should have a frame argument... def parallel_axis(self, point): """Returns the inertia dyadic of the body with respect to another point. Parameters ========== point : sympy.physics.vector.Point The point to express the inertia dyadic about. Returns ======= inertia : sympy.physics.vector.Dyadic The inertia dyadic of the rigid body expressed about the provided point. """ # circular import issue from sympy.physics.mechanics.functions import inertia a, b, c = self.masscenter.pos_from(point).to_matrix(self.frame) I = self.mass * inertia(self.frame, b**2 + c**2, c**2 + a**2, a**2 + b**2, -a * b, -b * c, -a * c) return self.central_inertia + I sympy-sympy-1.9/sympy/physics/mechanics/system.py000066400000000000000000000443371412543434000224310ustar00rootroot00000000000000from sympy.core.backend import eye, Matrix, zeros from sympy.physics.mechanics import dynamicsymbols from sympy.physics.mechanics.functions import find_dynamicsymbols __all__ = ['SymbolicSystem'] class SymbolicSystem: """SymbolicSystem is a class that contains all the information about a system in a symbolic format such as the equations of motions and the bodies and loads in the system. There are three ways that the equations of motion can be described for Symbolic System: [1] Explicit form where the kinematics and dynamics are combined x' = F_1(x, t, r, p) [2] Implicit form where the kinematics and dynamics are combined M_2(x, p) x' = F_2(x, t, r, p) [3] Implicit form where the kinematics and dynamics are separate M_3(q, p) u' = F_3(q, u, t, r, p) q' = G(q, u, t, r, p) where x : states, e.g. [q, u] t : time r : specified (exogenous) inputs p : constants q : generalized coordinates u : generalized speeds F_1 : right hand side of the combined equations in explicit form F_2 : right hand side of the combined equations in implicit form F_3 : right hand side of the dynamical equations in implicit form M_2 : mass matrix of the combined equations in implicit form M_3 : mass matrix of the dynamical equations in implicit form G : right hand side of the kinematical differential equations Parameters ========== coord_states : ordered iterable of functions of time This input will either be a collection of the coordinates or states of the system depending on whether or not the speeds are also given. If speeds are specified this input will be assumed to be the coordinates otherwise this input will be assumed to be the states. right_hand_side : Matrix This variable is the right hand side of the equations of motion in any of the forms. The specific form will be assumed depending on whether a mass matrix or coordinate derivatives are given. speeds : ordered iterable of functions of time, optional This is a collection of the generalized speeds of the system. If given it will be assumed that the first argument (coord_states) will represent the generalized coordinates of the system. mass_matrix : Matrix, optional The matrix of the implicit forms of the equations of motion (forms [2] and [3]). The distinction between the forms is determined by whether or not the coordinate derivatives are passed in. If they are given form [3] will be assumed otherwise form [2] is assumed. coordinate_derivatives : Matrix, optional The right hand side of the kinematical equations in explicit form. If given it will be assumed that the equations of motion are being entered in form [3]. alg_con : Iterable, optional The indexes of the rows in the equations of motion that contain algebraic constraints instead of differential equations. If the equations are input in form [3], it will be assumed the indexes are referencing the mass_matrix/right_hand_side combination and not the coordinate_derivatives. output_eqns : Dictionary, optional Any output equations that are desired to be tracked are stored in a dictionary where the key corresponds to the name given for the specific equation and the value is the equation itself in symbolic form coord_idxs : Iterable, optional If coord_states corresponds to the states rather than the coordinates this variable will tell SymbolicSystem which indexes of the states correspond to generalized coordinates. speed_idxs : Iterable, optional If coord_states corresponds to the states rather than the coordinates this variable will tell SymbolicSystem which indexes of the states correspond to generalized speeds. bodies : iterable of Body/Rigidbody objects, optional Iterable containing the bodies of the system loads : iterable of load instances (described below), optional Iterable containing the loads of the system where forces are given by (point of application, force vector) and torques are given by (reference frame acting upon, torque vector). Ex [(point, force), (ref_frame, torque)] Attributes ========== coordinates : Matrix, shape(n, 1) This is a matrix containing the generalized coordinates of the system speeds : Matrix, shape(m, 1) This is a matrix containing the generalized speeds of the system states : Matrix, shape(o, 1) This is a matrix containing the state variables of the system alg_con : List This list contains the indices of the algebraic constraints in the combined equations of motion. The presence of these constraints requires that a DAE solver be used instead of an ODE solver. If the system is given in form [3] the alg_con variable will be adjusted such that it is a representation of the combined kinematics and dynamics thus make sure it always matches the mass matrix entered. dyn_implicit_mat : Matrix, shape(m, m) This is the M matrix in form [3] of the equations of motion (the mass matrix or generalized inertia matrix of the dynamical equations of motion in implicit form). dyn_implicit_rhs : Matrix, shape(m, 1) This is the F vector in form [3] of the equations of motion (the right hand side of the dynamical equations of motion in implicit form). comb_implicit_mat : Matrix, shape(o, o) This is the M matrix in form [2] of the equations of motion. This matrix contains a block diagonal structure where the top left block (the first rows) represent the matrix in the implicit form of the kinematical equations and the bottom right block (the last rows) represent the matrix in the implicit form of the dynamical equations. comb_implicit_rhs : Matrix, shape(o, 1) This is the F vector in form [2] of the equations of motion. The top part of the vector represents the right hand side of the implicit form of the kinemaical equations and the bottom of the vector represents the right hand side of the implicit form of the dynamical equations of motion. comb_explicit_rhs : Matrix, shape(o, 1) This vector represents the right hand side of the combined equations of motion in explicit form (form [1] from above). kin_explicit_rhs : Matrix, shape(m, 1) This is the right hand side of the explicit form of the kinematical equations of motion as can be seen in form [3] (the G matrix). output_eqns : Dictionary If output equations were given they are stored in a dictionary where the key corresponds to the name given for the specific equation and the value is the equation itself in symbolic form bodies : Tuple If the bodies in the system were given they are stored in a tuple for future access loads : Tuple If the loads in the system were given they are stored in a tuple for future access. This includes forces and torques where forces are given by (point of application, force vector) and torques are given by (reference frame acted upon, torque vector). Example ======= As a simple example, the dynamics of a simple pendulum will be input into a SymbolicSystem object manually. First some imports will be needed and then symbols will be set up for the length of the pendulum (l), mass at the end of the pendulum (m), and a constant for gravity (g). :: >>> from sympy import Matrix, sin, symbols >>> from sympy.physics.mechanics import dynamicsymbols, SymbolicSystem >>> l, m, g = symbols('l m g') The system will be defined by an angle of theta from the vertical and a generalized speed of omega will be used where omega = theta_dot. :: >>> theta, omega = dynamicsymbols('theta omega') Now the equations of motion are ready to be formed and passed to the SymbolicSystem object. :: >>> kin_explicit_rhs = Matrix([omega]) >>> dyn_implicit_mat = Matrix([l**2 * m]) >>> dyn_implicit_rhs = Matrix([-g * l * m * sin(theta)]) >>> symsystem = SymbolicSystem([theta], dyn_implicit_rhs, [omega], ... dyn_implicit_mat) Notes ===== m : number of generalized speeds n : number of generalized coordinates o : number of states """ def __init__(self, coord_states, right_hand_side, speeds=None, mass_matrix=None, coordinate_derivatives=None, alg_con=None, output_eqns={}, coord_idxs=None, speed_idxs=None, bodies=None, loads=None): """Initializes a SymbolicSystem object""" # Extract information on speeds, coordinates and states if speeds is None: self._states = Matrix(coord_states) if coord_idxs is None: self._coordinates = None else: coords = [coord_states[i] for i in coord_idxs] self._coordinates = Matrix(coords) if speed_idxs is None: self._speeds = None else: speeds_inter = [coord_states[i] for i in speed_idxs] self._speeds = Matrix(speeds_inter) else: self._coordinates = Matrix(coord_states) self._speeds = Matrix(speeds) self._states = self._coordinates.col_join(self._speeds) # Extract equations of motion form if coordinate_derivatives is not None: self._kin_explicit_rhs = coordinate_derivatives self._dyn_implicit_rhs = right_hand_side self._dyn_implicit_mat = mass_matrix self._comb_implicit_rhs = None self._comb_implicit_mat = None self._comb_explicit_rhs = None elif mass_matrix is not None: self._kin_explicit_rhs = None self._dyn_implicit_rhs = None self._dyn_implicit_mat = None self._comb_implicit_rhs = right_hand_side self._comb_implicit_mat = mass_matrix self._comb_explicit_rhs = None else: self._kin_explicit_rhs = None self._dyn_implicit_rhs = None self._dyn_implicit_mat = None self._comb_implicit_rhs = None self._comb_implicit_mat = None self._comb_explicit_rhs = right_hand_side # Set the remainder of the inputs as instance attributes if alg_con is not None and coordinate_derivatives is not None: alg_con = [i + len(coordinate_derivatives) for i in alg_con] self._alg_con = alg_con self.output_eqns = output_eqns # Change the body and loads iterables to tuples if they are not tuples # already if type(bodies) != tuple and bodies is not None: bodies = tuple(bodies) if type(loads) != tuple and loads is not None: loads = tuple(loads) self._bodies = bodies self._loads = loads @property def coordinates(self): """Returns the column matrix of the generalized coordinates""" if self._coordinates is None: raise AttributeError("The coordinates were not specified.") else: return self._coordinates @property def speeds(self): """Returns the column matrix of generalized speeds""" if self._speeds is None: raise AttributeError("The speeds were not specified.") else: return self._speeds @property def states(self): """Returns the column matrix of the state variables""" return self._states @property def alg_con(self): """Returns a list with the indices of the rows containing algebraic constraints in the combined form of the equations of motion""" return self._alg_con @property def dyn_implicit_mat(self): """Returns the matrix, M, corresponding to the dynamic equations in implicit form, M x' = F, where the kinematical equations are not included""" if self._dyn_implicit_mat is None: raise AttributeError("dyn_implicit_mat is not specified for " "equations of motion form [1] or [2].") else: return self._dyn_implicit_mat @property def dyn_implicit_rhs(self): """Returns the column matrix, F, corresponding to the dynamic equations in implicit form, M x' = F, where the kinematical equations are not included""" if self._dyn_implicit_rhs is None: raise AttributeError("dyn_implicit_rhs is not specified for " "equations of motion form [1] or [2].") else: return self._dyn_implicit_rhs @property def comb_implicit_mat(self): """Returns the matrix, M, corresponding to the equations of motion in implicit form (form [2]), M x' = F, where the kinematical equations are included""" if self._comb_implicit_mat is None: if self._dyn_implicit_mat is not None: num_kin_eqns = len(self._kin_explicit_rhs) num_dyn_eqns = len(self._dyn_implicit_rhs) zeros1 = zeros(num_kin_eqns, num_dyn_eqns) zeros2 = zeros(num_dyn_eqns, num_kin_eqns) inter1 = eye(num_kin_eqns).row_join(zeros1) inter2 = zeros2.row_join(self._dyn_implicit_mat) self._comb_implicit_mat = inter1.col_join(inter2) return self._comb_implicit_mat else: raise AttributeError("comb_implicit_mat is not specified for " "equations of motion form [1].") else: return self._comb_implicit_mat @property def comb_implicit_rhs(self): """Returns the column matrix, F, corresponding to the equations of motion in implicit form (form [2]), M x' = F, where the kinematical equations are included""" if self._comb_implicit_rhs is None: if self._dyn_implicit_rhs is not None: kin_inter = self._kin_explicit_rhs dyn_inter = self._dyn_implicit_rhs self._comb_implicit_rhs = kin_inter.col_join(dyn_inter) return self._comb_implicit_rhs else: raise AttributeError("comb_implicit_mat is not specified for " "equations of motion in form [1].") else: return self._comb_implicit_rhs def compute_explicit_form(self): """If the explicit right hand side of the combined equations of motion is to provided upon initialization, this method will calculate it. This calculation can potentially take awhile to compute.""" if self._comb_explicit_rhs is not None: raise AttributeError("comb_explicit_rhs is already formed.") inter1 = getattr(self, 'kin_explicit_rhs', None) if inter1 is not None: inter2 = self._dyn_implicit_mat.LUsolve(self._dyn_implicit_rhs) out = inter1.col_join(inter2) else: out = self._comb_implicit_mat.LUsolve(self._comb_implicit_rhs) self._comb_explicit_rhs = out @property def comb_explicit_rhs(self): """Returns the right hand side of the equations of motion in explicit form, x' = F, where the kinematical equations are included""" if self._comb_explicit_rhs is None: raise AttributeError("Please run .combute_explicit_form before " "attempting to access comb_explicit_rhs.") else: return self._comb_explicit_rhs @property def kin_explicit_rhs(self): """Returns the right hand side of the kinematical equations in explicit form, q' = G""" if self._kin_explicit_rhs is None: raise AttributeError("kin_explicit_rhs is not specified for " "equations of motion form [1] or [2].") else: return self._kin_explicit_rhs def dynamic_symbols(self): """Returns a column matrix containing all of the symbols in the system that depend on time""" # Create a list of all of the expressions in the equations of motion if self._comb_explicit_rhs is None: eom_expressions = (self.comb_implicit_mat[:] + self.comb_implicit_rhs[:]) else: eom_expressions = (self._comb_explicit_rhs[:]) functions_of_time = set() for expr in eom_expressions: functions_of_time = functions_of_time.union( find_dynamicsymbols(expr)) functions_of_time = functions_of_time.union(self._states) return tuple(functions_of_time) def constant_symbols(self): """Returns a column matrix containing all of the symbols in the system that do not depend on time""" # Create a list of all of the expressions in the equations of motion if self._comb_explicit_rhs is None: eom_expressions = (self.comb_implicit_mat[:] + self.comb_implicit_rhs[:]) else: eom_expressions = (self._comb_explicit_rhs[:]) constants = set() for expr in eom_expressions: constants = constants.union(expr.free_symbols) constants.remove(dynamicsymbols._t) return tuple(constants) @property def bodies(self): """Returns the bodies in the system""" if self._bodies is None: raise AttributeError("bodies were not specified for the system.") else: return self._bodies @property def loads(self): """Returns the loads in the system""" if self._loads is None: raise AttributeError("loads were not specified for the system.") else: return self._loads sympy-sympy-1.9/sympy/physics/mechanics/tests/000077500000000000000000000000001412543434000216625ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/mechanics/tests/__init__.py000066400000000000000000000000001412543434000237610ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/mechanics/tests/test_body.py000066400000000000000000000221101412543434000242240ustar00rootroot00000000000000from sympy.core.backend import Symbol, symbols, sin, cos, Matrix from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols from sympy.physics.mechanics import inertia, Body from sympy.testing.pytest import raises def test_default(): body = Body('body') assert body.name == 'body' assert body.loads == [] point = Point('body_masscenter') point.set_vel(body.frame, 0) com = body.masscenter frame = body.frame assert com.vel(frame) == point.vel(frame) assert body.mass == Symbol('body_mass') ixx, iyy, izz = symbols('body_ixx body_iyy body_izz') ixy, iyz, izx = symbols('body_ixy body_iyz body_izx') assert body.inertia == (inertia(body.frame, ixx, iyy, izz, ixy, iyz, izx), body.masscenter) def test_custom_rigid_body(): # Body with RigidBody. rigidbody_masscenter = Point('rigidbody_masscenter') rigidbody_mass = Symbol('rigidbody_mass') rigidbody_frame = ReferenceFrame('rigidbody_frame') body_inertia = inertia(rigidbody_frame, 1, 0, 0) rigid_body = Body('rigidbody_body', rigidbody_masscenter, rigidbody_mass, rigidbody_frame, body_inertia) com = rigid_body.masscenter frame = rigid_body.frame rigidbody_masscenter.set_vel(rigidbody_frame, 0) assert com.vel(frame) == rigidbody_masscenter.vel(frame) assert com.pos_from(com) == rigidbody_masscenter.pos_from(com) assert rigid_body.mass == rigidbody_mass assert rigid_body.inertia == (body_inertia, rigidbody_masscenter) assert rigid_body.is_rigidbody assert hasattr(rigid_body, 'masscenter') assert hasattr(rigid_body, 'mass') assert hasattr(rigid_body, 'frame') assert hasattr(rigid_body, 'inertia') def test_particle_body(): # Body with Particle particle_masscenter = Point('particle_masscenter') particle_mass = Symbol('particle_mass') particle_frame = ReferenceFrame('particle_frame') particle_body = Body('particle_body', particle_masscenter, particle_mass, particle_frame) com = particle_body.masscenter frame = particle_body.frame particle_masscenter.set_vel(particle_frame, 0) assert com.vel(frame) == particle_masscenter.vel(frame) assert com.pos_from(com) == particle_masscenter.pos_from(com) assert particle_body.mass == particle_mass assert not hasattr(particle_body, "_inertia") assert hasattr(particle_body, 'frame') assert hasattr(particle_body, 'masscenter') assert hasattr(particle_body, 'mass') assert not particle_body.is_rigidbody def test_particle_body_add_force(): # Body with Particle particle_masscenter = Point('particle_masscenter') particle_mass = Symbol('particle_mass') particle_frame = ReferenceFrame('particle_frame') particle_body = Body('particle_body', particle_masscenter, particle_mass, particle_frame) a = Symbol('a') force_vector = a * particle_body.frame.x particle_body.apply_force(force_vector, particle_body.masscenter) assert len(particle_body.loads) == 1 point = particle_body.masscenter.locatenew( particle_body._name + '_point0', 0) point.set_vel(particle_body.frame, 0) force_point = particle_body.loads[0][0] frame = particle_body.frame assert force_point.vel(frame) == point.vel(frame) assert force_point.pos_from(force_point) == point.pos_from(force_point) assert particle_body.loads[0][1] == force_vector def test_body_add_force(): # Body with RigidBody. rigidbody_masscenter = Point('rigidbody_masscenter') rigidbody_mass = Symbol('rigidbody_mass') rigidbody_frame = ReferenceFrame('rigidbody_frame') body_inertia = inertia(rigidbody_frame, 1, 0, 0) rigid_body = Body('rigidbody_body', rigidbody_masscenter, rigidbody_mass, rigidbody_frame, body_inertia) l = Symbol('l') Fa = Symbol('Fa') point = rigid_body.masscenter.locatenew( 'rigidbody_body_point0', l * rigid_body.frame.x) point.set_vel(rigid_body.frame, 0) force_vector = Fa * rigid_body.frame.z # apply_force with point rigid_body.apply_force(force_vector, point) assert len(rigid_body.loads) == 1 force_point = rigid_body.loads[0][0] frame = rigid_body.frame assert force_point.vel(frame) == point.vel(frame) assert force_point.pos_from(force_point) == point.pos_from(force_point) assert rigid_body.loads[0][1] == force_vector # apply_force without point rigid_body.apply_force(force_vector) assert len(rigid_body.loads) == 2 assert rigid_body.loads[1][1] == force_vector # passing something else than point raises(TypeError, lambda: rigid_body.apply_force(force_vector, 0)) raises(TypeError, lambda: rigid_body.apply_force(0)) def test_body_add_torque(): body = Body('body') torque_vector = body.frame.x body.apply_torque(torque_vector) assert len(body.loads) == 1 assert body.loads[0] == (body.frame, torque_vector) raises(TypeError, lambda: body.apply_torque(0)) def test_body_masscenter_vel(): A = Body('A') N = ReferenceFrame('N') B = Body('B', frame=N) A.masscenter.set_vel(N, N.z) assert A.masscenter_vel(B) == N.z assert A.masscenter_vel(N) == N.z def test_body_ang_vel(): A = Body('A') N = ReferenceFrame('N') B = Body('B', frame=N) A.frame.set_ang_vel(N, N.y) assert A.ang_vel_in(B) == N.y assert B.ang_vel_in(A) == -N.y assert A.ang_vel_in(N) == N.y def test_body_dcm(): A = Body('A') B = Body('B') A.frame.orient_axis(B.frame, B.frame.z, 10) assert A.dcm(B) == Matrix([[cos(10), sin(10), 0], [-sin(10), cos(10), 0], [0, 0, 1]]) assert A.dcm(B.frame) == Matrix([[cos(10), sin(10), 0], [-sin(10), cos(10), 0], [0, 0, 1]]) def test_body_axis(): N = ReferenceFrame('N') B = Body('B', frame=N) assert B.x == N.x assert B.y == N.y assert B.z == N.z def test_apply_force_multiple_one_point(): a, b = symbols('a b') P = Point('P') B = Body('B') f1 = a*B.x f2 = b*B.y B.apply_force(f1, P) assert B.loads == [(P, f1)] B.apply_force(f2, P) assert B.loads == [(P, f1+f2)] def test_apply_force(): f, g = symbols('f g') q, x, v1, v2 = dynamicsymbols('q x v1 v2') P1 = Point('P1') P2 = Point('P2') B1 = Body('B1') B2 = Body('B2') N = ReferenceFrame('N') P1.set_vel(B1.frame, v1*B1.x) P2.set_vel(B2.frame, v2*B2.x) force = f*q*N.z # time varying force B1.apply_force(force, P1, B2, P2) #applying equal and opposite force on moving points assert B1.loads == [(P1, force)] assert B2.loads == [(P2, -force)] g1 = B1.mass*g*N.y g2 = B2.mass*g*N.y B1.apply_force(g1) #applying gravity on B1 masscenter B2.apply_force(g2) #applying gravity on B2 masscenter assert B1.loads == [(P1,force), (B1.masscenter, g1)] assert B2.loads == [(P2, -force), (B2.masscenter, g2)] force2 = x*N.x B1.apply_force(force2, reaction_body=B2) #Applying time varying force on masscenter assert B1.loads == [(P1, force), (B1.masscenter, force2+g1)] assert B2.loads == [(P2, -force), (B2.masscenter, -force2+g2)] def test_apply_torque(): t = symbols('t') q = dynamicsymbols('q') B1 = Body('B1') B2 = Body('B2') N = ReferenceFrame('N') torque = t*q*N.x B1.apply_torque(torque, B2) #Applying equal and opposite torque assert B1.loads == [(B1.frame, torque)] assert B2.loads == [(B2.frame, -torque)] torque2 = t*N.y B1.apply_torque(torque2) assert B1.loads == [(B1.frame, torque+torque2)] def test_clear_load(): a = symbols('a') P = Point('P') B = Body('B') force = a*B.z B.apply_force(force, P) assert B.loads == [(P, force)] B.clear_loads() assert B.loads == [] def test_remove_load(): P1 = Point('P1') P2 = Point('P2') B = Body('B') f1 = B.x f2 = B.y B.apply_force(f1, P1) B.apply_force(f2, P2) B.loads == [(P1, f1), (P2, f2)] B.remove_load(P2) B.loads == [(P1, f1)] B.apply_torque(f1.cross(f2)) B.loads == [(P1, f1), (B.frame, f1.cross(f2))] B.remove_load() B.loads == [(P1, f1)] def test_apply_loads_on_multi_degree_freedom_holonomic_system(): """Example based on: https://pydy.readthedocs.io/en/latest/examples/multidof-holonomic.html""" W = Body('W') #Wall B = Body('B') #Block P = Body('P') #Pendulum b = Body('b') #bob q1, q2 = dynamicsymbols('q1 q2') #generalized coordinates k, c, g, kT = symbols('k c g kT') #constants F, T = dynamicsymbols('F T') #Specified forces #Applying forces B.apply_force(F*W.x) W.apply_force(k*q1*W.x, reaction_body=B) #Spring force W.apply_force(c*q1.diff()*W.x, reaction_body=B) #dampner P.apply_force(P.mass*g*W.y) b.apply_force(b.mass*g*W.y) #Applying torques P.apply_torque(kT*q2*W.z, reaction_body=b) P.apply_torque(T*W.z) assert B.loads == [(B.masscenter, (F - k*q1 - c*q1.diff())*W.x)] assert P.loads == [(P.masscenter, P.mass*g*W.y), (P.frame, (T + kT*q2)*W.z)] assert b.loads == [(b.masscenter, b.mass*g*W.y), (b.frame, -kT*q2*W.z)] assert W.loads == [(W.masscenter, (c*q1.diff() + k*q1)*W.x)] sympy-sympy-1.9/sympy/physics/mechanics/tests/test_functions.py000066400000000000000000000216151412543434000253100ustar00rootroot00000000000000from sympy.core.backend import sin, cos, tan, pi, symbols, Matrix, S from sympy.physics.mechanics import (Particle, Point, ReferenceFrame, RigidBody) from sympy.physics.mechanics import (angular_momentum, dynamicsymbols, inertia, inertia_of_point_mass, kinetic_energy, linear_momentum, outer, potential_energy, msubs, find_dynamicsymbols, Lagrangian) from sympy.physics.mechanics.functions import gravity, center_of_mass from sympy.physics.vector.vector import Vector from sympy.testing.pytest import raises Vector.simp = True q1, q2, q3, q4, q5 = symbols('q1 q2 q3 q4 q5') N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q1, N.z]) B = A.orientnew('B', 'Axis', [q2, A.x]) C = B.orientnew('C', 'Axis', [q3, B.y]) def test_inertia(): N = ReferenceFrame('N') ixx, iyy, izz = symbols('ixx iyy izz') ixy, iyz, izx = symbols('ixy iyz izx') assert inertia(N, ixx, iyy, izz) == (ixx * (N.x | N.x) + iyy * (N.y | N.y) + izz * (N.z | N.z)) assert inertia(N, 0, 0, 0) == 0 * (N.x | N.x) raises(TypeError, lambda: inertia(0, 0, 0, 0)) assert inertia(N, ixx, iyy, izz, ixy, iyz, izx) == (ixx * (N.x | N.x) + ixy * (N.x | N.y) + izx * (N.x | N.z) + ixy * (N.y | N.x) + iyy * (N.y | N.y) + iyz * (N.y | N.z) + izx * (N.z | N.x) + iyz * (N.z | N.y) + izz * (N.z | N.z)) def test_inertia_of_point_mass(): r, s, t, m = symbols('r s t m') N = ReferenceFrame('N') px = r * N.x I = inertia_of_point_mass(m, px, N) assert I == m * r**2 * (N.y | N.y) + m * r**2 * (N.z | N.z) py = s * N.y I = inertia_of_point_mass(m, py, N) assert I == m * s**2 * (N.x | N.x) + m * s**2 * (N.z | N.z) pz = t * N.z I = inertia_of_point_mass(m, pz, N) assert I == m * t**2 * (N.x | N.x) + m * t**2 * (N.y | N.y) p = px + py + pz I = inertia_of_point_mass(m, p, N) assert I == (m * (s**2 + t**2) * (N.x | N.x) - m * r * s * (N.x | N.y) - m * r * t * (N.x | N.z) - m * r * s * (N.y | N.x) + m * (r**2 + t**2) * (N.y | N.y) - m * s * t * (N.y | N.z) - m * r * t * (N.z | N.x) - m * s * t * (N.z | N.y) + m * (r**2 + s**2) * (N.z | N.z)) def test_linear_momentum(): N = ReferenceFrame('N') Ac = Point('Ac') Ac.set_vel(N, 25 * N.y) I = outer(N.x, N.x) A = RigidBody('A', Ac, N, 20, (I, Ac)) P = Point('P') Pa = Particle('Pa', P, 1) Pa.point.set_vel(N, 10 * N.x) raises(TypeError, lambda: linear_momentum(A, A, Pa)) raises(TypeError, lambda: linear_momentum(N, N, Pa)) assert linear_momentum(N, A, Pa) == 10 * N.x + 500 * N.y def test_angular_momentum_and_linear_momentum(): """A rod with length 2l, centroidal inertia I, and mass M along with a particle of mass m fixed to the end of the rod rotate with an angular rate of omega about point O which is fixed to the non-particle end of the rod. The rod's reference frame is A and the inertial frame is N.""" m, M, l, I = symbols('m, M, l, I') omega = dynamicsymbols('omega') N = ReferenceFrame('N') a = ReferenceFrame('a') O = Point('O') Ac = O.locatenew('Ac', l * N.x) P = Ac.locatenew('P', l * N.x) O.set_vel(N, 0 * N.x) a.set_ang_vel(N, omega * N.z) Ac.v2pt_theory(O, N, a) P.v2pt_theory(O, N, a) Pa = Particle('Pa', P, m) A = RigidBody('A', Ac, a, M, (I * outer(N.z, N.z), Ac)) expected = 2 * m * omega * l * N.y + M * l * omega * N.y assert linear_momentum(N, A, Pa) == expected raises(TypeError, lambda: angular_momentum(N, N, A, Pa)) raises(TypeError, lambda: angular_momentum(O, O, A, Pa)) raises(TypeError, lambda: angular_momentum(O, N, O, Pa)) expected = (I + M * l**2 + 4 * m * l**2) * omega * N.z assert angular_momentum(O, N, A, Pa) == expected def test_kinetic_energy(): m, M, l1 = symbols('m M l1') omega = dynamicsymbols('omega') N = ReferenceFrame('N') O = Point('O') O.set_vel(N, 0 * N.x) Ac = O.locatenew('Ac', l1 * N.x) P = Ac.locatenew('P', l1 * N.x) a = ReferenceFrame('a') a.set_ang_vel(N, omega * N.z) Ac.v2pt_theory(O, N, a) P.v2pt_theory(O, N, a) Pa = Particle('Pa', P, m) I = outer(N.z, N.z) A = RigidBody('A', Ac, a, M, (I, Ac)) raises(TypeError, lambda: kinetic_energy(Pa, Pa, A)) raises(TypeError, lambda: kinetic_energy(N, N, A)) assert 0 == (kinetic_energy(N, Pa, A) - (M*l1**2*omega**2/2 + 2*l1**2*m*omega**2 + omega**2/2)).expand() def test_potential_energy(): m, M, l1, g, h, H = symbols('m M l1 g h H') omega = dynamicsymbols('omega') N = ReferenceFrame('N') O = Point('O') O.set_vel(N, 0 * N.x) Ac = O.locatenew('Ac', l1 * N.x) P = Ac.locatenew('P', l1 * N.x) a = ReferenceFrame('a') a.set_ang_vel(N, omega * N.z) Ac.v2pt_theory(O, N, a) P.v2pt_theory(O, N, a) Pa = Particle('Pa', P, m) I = outer(N.z, N.z) A = RigidBody('A', Ac, a, M, (I, Ac)) Pa.potential_energy = m * g * h A.potential_energy = M * g * H assert potential_energy(A, Pa) == m * g * h + M * g * H def test_Lagrangian(): M, m, g, h = symbols('M m g h') N = ReferenceFrame('N') O = Point('O') O.set_vel(N, 0 * N.x) P = O.locatenew('P', 1 * N.x) P.set_vel(N, 10 * N.x) Pa = Particle('Pa', P, 1) Ac = O.locatenew('Ac', 2 * N.y) Ac.set_vel(N, 5 * N.y) a = ReferenceFrame('a') a.set_ang_vel(N, 10 * N.z) I = outer(N.z, N.z) A = RigidBody('A', Ac, a, 20, (I, Ac)) Pa.potential_energy = m * g * h A.potential_energy = M * g * h raises(TypeError, lambda: Lagrangian(A, A, Pa)) raises(TypeError, lambda: Lagrangian(N, N, Pa)) def test_msubs(): a, b = symbols('a, b') x, y, z = dynamicsymbols('x, y, z') # Test simple substitution expr = Matrix([[a*x + b, x*y.diff() + y], [x.diff().diff(), z + sin(z.diff())]]) sol = Matrix([[a + b, y], [x.diff().diff(), 1]]) sd = {x: 1, z: 1, z.diff(): 0, y.diff(): 0} assert msubs(expr, sd) == sol # Test smart substitution expr = cos(x + y)*tan(x + y) + b*x.diff() sd = {x: 0, y: pi/2, x.diff(): 1} assert msubs(expr, sd, smart=True) == b + 1 N = ReferenceFrame('N') v = x*N.x + y*N.y d = x*(N.x|N.x) + y*(N.y|N.y) v_sol = 1*N.y d_sol = 1*(N.y|N.y) sd = {x: 0, y: 1} assert msubs(v, sd) == v_sol assert msubs(d, sd) == d_sol def test_find_dynamicsymbols(): a, b = symbols('a, b') x, y, z = dynamicsymbols('x, y, z') expr = Matrix([[a*x + b, x*y.diff() + y], [x.diff().diff(), z + sin(z.diff())]]) # Test finding all dynamicsymbols sol = {x, y.diff(), y, x.diff().diff(), z, z.diff()} assert find_dynamicsymbols(expr) == sol # Test finding all but those in sym_list exclude_list = [x, y, z] sol = {y.diff(), x.diff().diff(), z.diff()} assert find_dynamicsymbols(expr, exclude=exclude_list) == sol # Test finding all dynamicsymbols in a vector with a given reference frame d, e, f = dynamicsymbols('d, e, f') A = ReferenceFrame('A') v = d * A.x + e * A.y + f * A.z sol = {d, e, f} assert find_dynamicsymbols(v, reference_frame=A) == sol # Test if a ValueError is raised on supplying only a vector as input raises(ValueError, lambda: find_dynamicsymbols(v)) def test_gravity(): N = ReferenceFrame('N') m, M, g = symbols('m M g') F1, F2 = dynamicsymbols('F1 F2') po = Point('po') pa = Particle('pa', po, m) A = ReferenceFrame('A') P = Point('P') I = outer(A.x, A.x) B = RigidBody('B', P, A, M, (I, P)) forceList = [(po, F1), (P, F2)] forceList.extend(gravity(g*N.y, pa, B)) l = [(po, F1), (P, F2), (po, g*m*N.y), (P, g*M*N.y)] for i in range(len(l)): for j in range(len(l[i])): assert forceList[i][j] == l[i][j] # This function tests the center_of_mass() function # that was added in PR #14758 to compute the center of # mass of a system of bodies. def test_center_of_mass(): a = ReferenceFrame('a') m = symbols('m', real=True) p1 = Particle('p1', Point('p1_pt'), S.One) p2 = Particle('p2', Point('p2_pt'), S(2)) p3 = Particle('p3', Point('p3_pt'), S(3)) p4 = Particle('p4', Point('p4_pt'), m) b_f = ReferenceFrame('b_f') b_cm = Point('b_cm') mb = symbols('mb') b = RigidBody('b', b_cm, b_f, mb, (outer(b_f.x, b_f.x), b_cm)) p2.point.set_pos(p1.point, a.x) p3.point.set_pos(p1.point, a.x + a.y) p4.point.set_pos(p1.point, a.y) b.masscenter.set_pos(p1.point, a.y + a.z) point_o=Point('o') point_o.set_pos(p1.point, center_of_mass(p1.point, p1, p2, p3, p4, b)) expr = 5/(m + mb + 6)*a.x + (m + mb + 3)/(m + mb + 6)*a.y + mb/(m + mb + 6)*a.z assert point_o.pos_from(p1.point)-expr == 0 sympy-sympy-1.9/sympy/physics/mechanics/tests/test_joint.py000066400000000000000000000501401412543434000244160ustar00rootroot00000000000000from sympy import sin, cos, Matrix, sqrt, pi, expand_mul, S from sympy.core.backend import _simplify_matrix from sympy.core.symbol import symbols from sympy.physics.mechanics import dynamicsymbols, Body, PinJoint, PrismaticJoint from sympy.physics.mechanics.joint import Joint from sympy.physics.vector import Vector, ReferenceFrame from sympy.testing.pytest import raises t = dynamicsymbols._t def _generate_body(): N = ReferenceFrame('N') A = ReferenceFrame('A') P = Body('P', frame=N) C = Body('C', frame=A) return N, A, P, C def test_Joint(): parent = Body('parent') child = Body('child') raises(TypeError, lambda: Joint('J', parent, child)) def test_pinjoint(): P = Body('P') C = Body('C') l, m = symbols('l m') theta, omega = dynamicsymbols('theta_J, omega_J') Pj = PinJoint('J', P, C) assert Pj.name == 'J' assert Pj.parent == P assert Pj.child == C assert Pj.coordinates == [theta] assert Pj.speeds == [omega] assert Pj.kdes == [omega - theta.diff(t)] assert Pj.parent_axis == P.frame.x assert Pj.child_point.pos_from(C.masscenter) == Vector(0) assert Pj.parent_point.pos_from(P.masscenter) == Vector(0) assert Pj.parent_point.pos_from(Pj._child_point) == Vector(0) assert C.masscenter.pos_from(P.masscenter) == Vector(0) assert Pj.__str__() == 'PinJoint: J parent: P child: C' P1 = Body('P1') C1 = Body('C1') J1 = PinJoint('J1', P1, C1, parent_joint_pos=l*P1.frame.x, child_joint_pos=m*C1.frame.y, parent_axis=P1.frame.z) assert J1._parent_axis == P1.frame.z assert J1._child_point.pos_from(C1.masscenter) == m * C1.frame.y assert J1._parent_point.pos_from(P1.masscenter) == l * P1.frame.x assert J1._parent_point.pos_from(J1._child_point) == Vector(0) assert (P1.masscenter.pos_from(C1.masscenter) == -l*P1.frame.x + m*C1.frame.y) def test_pin_joint_double_pendulum(): q1, q2 = dynamicsymbols('q1 q2') u1, u2 = dynamicsymbols('u1 u2') m, l = symbols('m l') N = ReferenceFrame('N') A = ReferenceFrame('A') B = ReferenceFrame('B') C = Body('C', frame=N) # ceiling PartP = Body('P', frame=A, mass=m) PartR = Body('R', frame=B, mass=m) J1 = PinJoint('J1', C, PartP, speeds=u1, coordinates=q1, child_joint_pos=-l*A.x, parent_axis=C.frame.z, child_axis=PartP.frame.z) J2 = PinJoint('J2', PartP, PartR, speeds=u2, coordinates=q2, child_joint_pos=-l*B.x, parent_axis=PartP.frame.z, child_axis=PartR.frame.z) # Check orientation assert N.dcm(A) == Matrix([[cos(q1), -sin(q1), 0], [sin(q1), cos(q1), 0], [0, 0, 1]]) assert A.dcm(B) == Matrix([[cos(q2), -sin(q2), 0], [sin(q2), cos(q2), 0], [0, 0, 1]]) assert _simplify_matrix(N.dcm(B)) == Matrix([[cos(q1 + q2), -sin(q1 + q2), 0], [sin(q1 + q2), cos(q1 + q2), 0], [0, 0, 1]]) # Check Angular Velocity assert A.ang_vel_in(N) == u1 * N.z assert B.ang_vel_in(A) == u2 * A.z assert B.ang_vel_in(N) == u1 * N.z + u2 * A.z # Check kde assert J1.kdes == [u1 - q1.diff(t)] assert J2.kdes == [u2 - q2.diff(t)] # Check Linear Velocity assert PartP.masscenter.vel(N) == l*u1*A.y assert PartR.masscenter.vel(A) == l*u2*B.y assert PartR.masscenter.vel(N) == l*u1*A.y + l*(u1 + u2)*B.y def test_pin_joint_chaos_pendulum(): mA, mB, lA, lB, h = symbols('mA, mB, lA, lB, h') theta, phi, omega, alpha = dynamicsymbols('theta phi omega alpha') N = ReferenceFrame('N') A = ReferenceFrame('A') B = ReferenceFrame('B') lA = (lB - h / 2) / 2 lC = (lB/2 + h/4) rod = Body('rod', frame=A, mass=mA) plate = Body('plate', mass=mB, frame=B) C = Body('C', frame=N) J1 = PinJoint('J1', C, rod, coordinates=theta, speeds=omega, child_joint_pos=lA*A.z, parent_axis=N.y, child_axis=A.y) J2 = PinJoint('J2', rod, plate, coordinates=phi, speeds=alpha, parent_joint_pos=lC*A.z, parent_axis=A.z, child_axis=B.z) # Check orientation assert A.dcm(N) == Matrix([[cos(theta), 0, -sin(theta)], [0, 1, 0], [sin(theta), 0, cos(theta)]]) assert A.dcm(B) == Matrix([[cos(phi), -sin(phi), 0], [sin(phi), cos(phi), 0], [0, 0, 1]]) assert B.dcm(N) == Matrix([ [cos(phi)*cos(theta), sin(phi), -sin(theta)*cos(phi)], [-sin(phi)*cos(theta), cos(phi), sin(phi)*sin(theta)], [sin(theta), 0, cos(theta)]]) # Check Angular Velocity assert A.ang_vel_in(N) == omega*N.y assert A.ang_vel_in(B) == -alpha*A.z assert N.ang_vel_in(B) == -omega*N.y - alpha*A.z # Check kde assert J1.kdes == [omega - theta.diff(t)] assert J2.kdes == [alpha - phi.diff(t)] # Check pos of masscenters assert C.masscenter.pos_from(rod.masscenter) == lA*A.z assert rod.masscenter.pos_from(plate.masscenter) == - lC * A.z # Check Linear Velocities assert rod.masscenter.vel(N) == (h/4 - lB/2)*omega*A.x assert plate.masscenter.vel(N) == ((h/4 - lB/2)*omega + (h/4 + lB/2)*omega)*A.x def test_pinjoint_arbitrary_axis(): theta, omega = dynamicsymbols('theta_J, omega_J') # When the bodies are attached though masscenters but axess are opposite. N, A, P, C = _generate_body() PinJoint('J', P, C, child_axis=-A.x) assert (-A.x).angle_between(N.x) == 0 assert -A.x.express(N) == N.x assert A.dcm(N) == Matrix([[-1, 0, 0], [0, -cos(theta), -sin(theta)], [0, -sin(theta), cos(theta)]]) assert A.ang_vel_in(N) == omega*N.x assert A.ang_vel_in(N).magnitude() == sqrt(omega**2) assert C.masscenter.pos_from(P.masscenter) == 0 assert C.masscenter.pos_from(P.masscenter).express(N).simplify() == 0 assert C.masscenter.vel(N) == 0 # When axes are different and parent joint is at masscenter but child joint # is at a unit vector from child masscenter. N, A, P, C = _generate_body() PinJoint('J', P, C, child_axis=A.y, child_joint_pos=A.x) assert A.y.angle_between(N.x) == 0 # Axis are aligned assert A.y.express(N) == N.x assert A.dcm(N) == Matrix([[0, -cos(theta), -sin(theta)], [1, 0, 0], [0, -sin(theta), cos(theta)]]) assert A.ang_vel_in(N) == omega*N.x assert A.ang_vel_in(N).express(A) == omega * A.y assert A.ang_vel_in(N).magnitude() == sqrt(omega**2) angle = A.ang_vel_in(N).angle_between(A.y) assert angle.xreplace({omega: 1}) == 0 assert C.masscenter.vel(N) == omega*A.z assert C.masscenter.pos_from(P.masscenter) == -A.x assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == cos(theta)*N.y + sin(theta)*N.z) assert C.masscenter.vel(N).angle_between(A.x) == pi/2 # Similar to previous case but wrt parent body N, A, P, C = _generate_body() PinJoint('J', P, C, parent_axis=N.y, parent_joint_pos=N.x) assert N.y.angle_between(A.x) == 0 # Axis are aligned assert N.y.express(A) == A.x assert A.dcm(N) == Matrix([[0, 1, 0], [-cos(theta), 0, sin(theta)], [sin(theta), 0, cos(theta)]]) assert A.ang_vel_in(N) == omega*N.y assert A.ang_vel_in(N).express(A) == omega*A.x assert A.ang_vel_in(N).magnitude() == sqrt(omega**2) angle = A.ang_vel_in(N).angle_between(A.x) assert angle.xreplace({omega: 1}) == 0 assert C.masscenter.vel(N).simplify() == - omega*N.z assert C.masscenter.pos_from(P.masscenter) == N.x # Both joint pos id defined but different axes N, A, P, C = _generate_body() PinJoint('J', P, C, parent_joint_pos=N.x, child_joint_pos=A.x, child_axis=A.x+A.y) assert expand_mul(N.x.angle_between(A.x + A.y)) == 0 # Axis are aligned assert (A.x + A.y).express(N).simplify() == sqrt(2)*N.x assert _simplify_matrix(A.dcm(N)) == Matrix([ [sqrt(2)/2, -sqrt(2)*cos(theta)/2, -sqrt(2)*sin(theta)/2], [sqrt(2)/2, sqrt(2)*cos(theta)/2, sqrt(2)*sin(theta)/2], [0, -sin(theta), cos(theta)]]) assert A.ang_vel_in(N) == omega*N.x assert (A.ang_vel_in(N).express(A).simplify() == (omega*A.x + omega*A.y)/sqrt(2)) assert A.ang_vel_in(N).magnitude() == sqrt(omega**2) angle = A.ang_vel_in(N).angle_between(A.x + A.y) assert angle.xreplace({omega: 1}) == 0 assert C.masscenter.vel(N).simplify() == (omega * A.z)/sqrt(2) assert C.masscenter.pos_from(P.masscenter) == N.x - A.x assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == (1 - sqrt(2)/2)*N.x + sqrt(2)*cos(theta)/2*N.y + sqrt(2)*sin(theta)/2*N.z) assert (C.masscenter.vel(N).express(N).simplify() == -sqrt(2)*omega*sin(theta)/2*N.y + sqrt(2)*omega*cos(theta)/2*N.z) assert C.masscenter.vel(N).angle_between(A.x) == pi/2 N, A, P, C = _generate_body() PinJoint('J', P, C, parent_joint_pos=N.x, child_joint_pos=A.x, child_axis=A.x+A.y-A.z) assert expand_mul(N.x.angle_between(A.x + A.y - A.z)) == 0 # Axis aligned assert (A.x + A.y - A.z).express(N).simplify() == sqrt(3)*N.x assert _simplify_matrix(A.dcm(N)) == Matrix([ [sqrt(3)/3, -sqrt(6)*sin(theta + pi/4)/3, sqrt(6)*cos(theta + pi/4)/3], [sqrt(3)/3, sqrt(6)*cos(theta + pi/12)/3, sqrt(6)*sin(theta + pi/12)/3], [-sqrt(3)/3, sqrt(6)*cos(theta + 5*pi/12)/3, sqrt(6)*sin(theta + 5*pi/12)/3]]) assert A.ang_vel_in(N) == omega*N.x assert A.ang_vel_in(N).express(A).simplify() == (omega*A.x + omega*A.y - omega*A.z)/sqrt(3) assert A.ang_vel_in(N).magnitude() == sqrt(omega**2) angle = A.ang_vel_in(N).angle_between(A.x + A.y-A.z) assert angle.xreplace({omega: 1}) == 0 assert C.masscenter.vel(N).simplify() == (omega*A.y + omega*A.z)/sqrt(3) assert C.masscenter.pos_from(P.masscenter) == N.x - A.x assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == (1 - sqrt(3)/3)*N.x + sqrt(6)*sin(theta + pi/4)/3*N.y - sqrt(6)*cos(theta + pi/4)/3*N.z) assert (C.masscenter.vel(N).express(N).simplify() == sqrt(6)*omega*cos(theta + pi/4)/3*N.y + sqrt(6)*omega*sin(theta + pi/4)/3*N.z) assert C.masscenter.vel(N).angle_between(A.x) == pi/2 N, A, P, C = _generate_body() m, n = symbols('m n') PinJoint('J', P, C, parent_joint_pos=m*N.x, child_joint_pos=n*A.x, child_axis=A.x+A.y-A.z, parent_axis=N.x-N.y+N.z) angle = (N.x-N.y+N.z).angle_between(A.x+A.y-A.z) assert expand_mul(angle) == 0 # Axis are aligned assert ((A.x-A.y+A.z).express(N).simplify() == (-4*cos(theta)/3 - S(1)/3)*N.x + (S(1)/3 - 4*sin(theta + pi/6)/3)*N.y + (4*cos(theta + pi/3)/3 - S(1)/3)*N.z) assert _simplify_matrix(A.dcm(N)) == Matrix([ [S(1)/3 - 2*cos(theta)/3, -2*sin(theta + pi/6)/3 - S(1)/3, 2*cos(theta + pi/3)/3 + S(1)/3], [2*cos(theta + pi/3)/3 + S(1)/3, 2*cos(theta)/3 - S(1)/3, 2*sin(theta + pi/6)/3 + S(1)/3], [-2*sin(theta + pi/6)/3 - S(1)/3, 2*cos(theta + pi/3)/3 + S(1)/3, 2*cos(theta)/3 - S(1)/3]]) assert A.ang_vel_in(N) == (omega*N.x - omega*N.y + omega*N.z)/sqrt(3) assert A.ang_vel_in(N).express(A).simplify() == (omega*A.x + omega*A.y - omega*A.z)/sqrt(3) assert A.ang_vel_in(N).magnitude() == sqrt(omega**2) angle = A.ang_vel_in(N).angle_between(A.x+A.y-A.z) assert angle.xreplace({omega: 1}) == 0 assert (C.masscenter.vel(N).simplify() == (m*omega*N.y + m*omega*N.z + n*omega*A.y + n*omega*A.z)/sqrt(3)) assert C.masscenter.pos_from(P.masscenter) == m*N.x - n*A.x assert (C.masscenter.pos_from(P.masscenter).express(N).simplify() == (m + n*(2*cos(theta) - 1)/3)*N.x + n*(2*sin(theta + pi/6) + 1)/3*N.y - n*(2*cos(theta + pi/3) + 1)/3*N.z) assert (C.masscenter.vel(N).express(N).simplify() == -2*n*omega*sin(theta)/3*N.x + (sqrt(3)*m + 2*n*cos(theta + pi/6))*omega/3*N.y + (sqrt(3)*m + 2*n*sin(theta + pi/3))*omega/3*N.z) assert expand_mul(C.masscenter.vel(N).angle_between(m*N.x - n*A.x)) == pi/2 def test_pinjoint_pi(): _, _, P, C = _generate_body() J = PinJoint('J', P, C, child_axis=-C.frame.x) assert J._generate_vector() == P.frame.z _, _, P, C = _generate_body() J = PinJoint('J', P, C, parent_axis=P.frame.y, child_axis=-C.frame.y) assert J._generate_vector() == P.frame.x _, _, P, C = _generate_body() J = PinJoint('J', P, C, parent_axis=P.frame.z, child_axis=-C.frame.z) assert J._generate_vector() == P.frame.y _, _, P, C = _generate_body() J = PinJoint('J', P, C, parent_axis=P.frame.x+P.frame.y, child_axis=-C.frame.y-C.frame.x) assert J._generate_vector() == P.frame.z _, _, P, C = _generate_body() J = PinJoint('J', P, C, parent_axis=P.frame.y+P.frame.z, child_axis=-C.frame.y-C.frame.z) assert J._generate_vector() == P.frame.x _, _, P, C = _generate_body() J = PinJoint('J', P, C, parent_axis=P.frame.x+P.frame.z, child_axis=-C.frame.z-C.frame.x) assert J._generate_vector() == P.frame.y _, _, P, C = _generate_body() J = PinJoint('J', P, C, parent_axis=P.frame.x+P.frame.y+P.frame.z, child_axis=-C.frame.x-C.frame.y-C.frame.z) assert J._generate_vector() == P.frame.y - P.frame.z def test_slidingjoint(): _, _, P, C = _generate_body() x, v = dynamicsymbols('x_S, v_S') S = PrismaticJoint('S', P, C) assert S.name == 'S' assert S.parent == P assert S.child == C assert S.coordinates == [x] assert S.speeds == [v] assert S.kdes == [v - x.diff(t)] assert S.parent_axis == P.frame.x assert S.child_axis == C.frame.x assert S.child_point.pos_from(C.masscenter) == Vector(0) assert S.parent_point.pos_from(P.masscenter) == Vector(0) assert S.parent_point.pos_from(S.child_point) == - x * P.frame.x assert P.masscenter.pos_from(C.masscenter) == - x * P.frame.x assert C.masscenter.vel(P.frame) == v * P.frame.x assert P.ang_vel_in(C) == 0 assert C.ang_vel_in(P) == 0 assert S.__str__() == 'PrismaticJoint: S parent: P child: C' N, A, P, C = _generate_body() l, m = symbols('l m') S = PrismaticJoint('S', P, C, parent_joint_pos= l * P.frame.x, child_joint_pos= m * C.frame.y, parent_axis = P.frame.z) assert S.parent_axis == P.frame.z assert S.child_point.pos_from(C.masscenter) == m * C.frame.y assert S.parent_point.pos_from(P.masscenter) == l * P.frame.x assert S.parent_point.pos_from(S.child_point) == - x * P.frame.z assert P.masscenter.pos_from(C.masscenter) == - l*N.x - x*N.z + m*A.y assert C.masscenter.vel(P.frame) == v * P.frame.z assert C.ang_vel_in(P) == 0 assert P.ang_vel_in(C) == 0 _, _, P, C = _generate_body() S = PrismaticJoint('S', P, C, parent_joint_pos= l * P.frame.z, child_joint_pos= m * C.frame.x, parent_axis = P.frame.z) assert S.parent_axis == P.frame.z assert S.child_point.pos_from(C.masscenter) == m * C.frame.x assert S.parent_point.pos_from(P.masscenter) == l * P.frame.z assert S.parent_point.pos_from(S.child_point) == - x * P.frame.z assert P.masscenter.pos_from(C.masscenter) == (-l - x)*P.frame.z + m*C.frame.x assert C.masscenter.vel(P.frame) == v * P.frame.z assert C.ang_vel_in(P) == 0 assert P.ang_vel_in(C) == 0 def test_slidingjoint_arbitrary_axis(): x, v = dynamicsymbols('x_S, v_S') N, A, P, C = _generate_body() PrismaticJoint('S', P, C, child_axis=-A.x) assert (-A.x).angle_between(N.x) == 0 assert -A.x.express(N) == N.x assert A.dcm(N) == Matrix([[-1, 0, 0], [0, -1, 0], [0, 0, 1]]) assert C.masscenter.pos_from(P.masscenter) == x * N.x assert C.masscenter.pos_from(P.masscenter).express(A).simplify() == -x * A.x assert C.masscenter.vel(N) == v * N.x assert C.masscenter.vel(N).express(A) == -v * A.x assert A.ang_vel_in(N) == 0 assert N.ang_vel_in(A) == 0 #When axes are different and parent joint is at masscenter but child joint is at a unit vector from #child masscenter. N, A, P, C = _generate_body() PrismaticJoint('S', P, C, child_axis=A.y, child_joint_pos=A.x) assert A.y.angle_between(N.x) == 0 #Axis are aligned assert A.y.express(N) == N.x assert A.dcm(N) == Matrix([[0, -1, 0], [1, 0, 0], [0, 0, 1]]) assert C.masscenter.vel(N) == v * N.x assert C.masscenter.vel(N).express(A) == v * A.y assert C.masscenter.pos_from(P.masscenter) == x*N.x - A.x assert C.masscenter.pos_from(P.masscenter).express(N).simplify() == x*N.x + N.y assert A.ang_vel_in(N) == 0 assert N.ang_vel_in(A) == 0 #Similar to previous case but wrt parent body N, A, P, C = _generate_body() PrismaticJoint('S', P, C, parent_axis=N.y, parent_joint_pos=N.x) assert N.y.angle_between(A.x) == 0 #Axis are aligned assert N.y.express(A) == A.x assert A.dcm(N) == Matrix([[0, 1, 0], [-1, 0, 0], [0, 0, 1]]) assert C.masscenter.vel(N) == v * N.y assert C.masscenter.vel(N).express(A) == v * A.x assert C.masscenter.pos_from(P.masscenter) == N.x + x*N.y assert A.ang_vel_in(N) == 0 assert N.ang_vel_in(A) == 0 #Both joint pos is defined but different axes N, A, P, C = _generate_body() PrismaticJoint('S', P, C, parent_joint_pos=N.x, child_joint_pos=A.x, child_axis=A.x+A.y) assert N.x.angle_between(A.x + A.y) == 0 #Axis are aligned assert (A.x + A.y).express(N) == sqrt(2)*N.x assert A.dcm(N) == Matrix([[sqrt(2)/2, -sqrt(2)/2, 0], [sqrt(2)/2, sqrt(2)/2, 0], [0, 0, 1]]) assert C.masscenter.pos_from(P.masscenter) == (x + 1)*N.x - A.x assert C.masscenter.pos_from(P.masscenter).express(N) == (x - sqrt(2)/2 + 1)*N.x + sqrt(2)/2*N.y assert C.masscenter.vel(N).express(A) == v * (A.x + A.y)/sqrt(2) assert C.masscenter.vel(N) == v*N.x assert A.ang_vel_in(N) == 0 assert N.ang_vel_in(A) == 0 N, A, P, C = _generate_body() PrismaticJoint('S', P, C, parent_joint_pos=N.x, child_joint_pos=A.x, child_axis=A.x+A.y-A.z) assert N.x.angle_between(A.x + A.y - A.z) == 0 #Axis are aligned assert (A.x + A.y - A.z).express(N) == sqrt(3)*N.x assert _simplify_matrix(A.dcm(N)) == Matrix([[sqrt(3)/3, -sqrt(3)/3, sqrt(3)/3], [sqrt(3)/3, sqrt(3)/6 + S(1)/2, S(1)/2 - sqrt(3)/6], [-sqrt(3)/3, S(1)/2 - sqrt(3)/6, sqrt(3)/6 + S(1)/2]]) assert C.masscenter.pos_from(P.masscenter) == (x + 1)*N.x - A.x assert C.masscenter.pos_from(P.masscenter).express(N) == \ (x - sqrt(3)/3 + 1)*N.x + sqrt(3)/3*N.y - sqrt(3)/3*N.z assert C.masscenter.vel(N) == v*N.x assert C.masscenter.vel(N).express(A) == sqrt(3)*v/3*A.x + sqrt(3)*v/3*A.y - sqrt(3)*v/3*A.z assert A.ang_vel_in(N) == 0 assert N.ang_vel_in(A) == 0 N, A, P, C = _generate_body() m, n = symbols('m n') PrismaticJoint('S', P, C, parent_joint_pos=m*N.x, child_joint_pos=n*A.x, child_axis=A.x+A.y-A.z, parent_axis=N.x-N.y+N.z) assert (N.x-N.y+N.z).angle_between(A.x+A.y-A.z) == 0 #Axis are aligned assert (A.x+A.y-A.z).express(N) == N.x - N.y + N.z assert _simplify_matrix(A.dcm(N)) == Matrix([[-S(1)/3, -S(2)/3, S(2)/3], [S(2)/3, S(1)/3, S(2)/3], [-S(2)/3, S(2)/3, S(1)/3]]) assert C.masscenter.pos_from(P.masscenter) == \ (m + sqrt(3)*x/3)*N.x - sqrt(3)*x/3*N.y + sqrt(3)*x/3*N.z - n*A.x assert C.masscenter.pos_from(P.masscenter).express(N) == \ (m + n/3 + sqrt(3)*x/3)*N.x + (2*n/3 - sqrt(3)*x/3)*N.y + (-2*n/3 + sqrt(3)*x/3)*N.z assert C.masscenter.vel(N) == sqrt(3)*v/3*N.x - sqrt(3)*v/3*N.y + sqrt(3)*v/3*N.z assert C.masscenter.vel(N).express(A) == sqrt(3)*v/3*A.x + sqrt(3)*v/3*A.y - sqrt(3)*v/3*A.z assert A.ang_vel_in(N) == 0 assert N.ang_vel_in(A) == 0 sympy-sympy-1.9/sympy/physics/mechanics/tests/test_jointsmethod.py000066400000000000000000000131161412543434000260040ustar00rootroot00000000000000from sympy import symbols, Matrix, cos, sin, expand, trigsimp from sympy.physics.mechanics import (PinJoint, JointsMethod, Body, KanesMethod, PrismaticJoint, LagrangesMethod, inertia) from sympy.physics.vector import dynamicsymbols, ReferenceFrame from sympy.testing.pytest import raises t = dynamicsymbols._t def test_jointsmethod(): P = Body('P') C = Body('C') Pin = PinJoint('P1', P, C) C_ixx, g = symbols('C_ixx g') theta, omega = dynamicsymbols('theta_P1, omega_P1') P.apply_force(g*P.y) method = JointsMethod(P, Pin) assert method.frame == P.frame assert method.bodies == [C, P] assert method.loads == [(P.masscenter, g*P.frame.y)] assert method.q == [theta] assert method.u == [omega] assert method.kdes == [omega - theta.diff()] soln = method.form_eoms() assert soln == Matrix([[-C_ixx*omega.diff()]]) assert method.forcing_full == Matrix([[omega], [0]]) assert method.mass_matrix_full == Matrix([[1, 0], [0, C_ixx]]) assert isinstance(method.method, KanesMethod) def test_jointmethod_duplicate_coordinates_speeds(): P = Body('P') C = Body('C') T = Body('T') q, u = dynamicsymbols('q u') P1 = PinJoint('P1', P, C, q) P2 = PrismaticJoint('P2', C, T, q) raises(ValueError, lambda: JointsMethod(P, P1, P2)) P1 = PinJoint('P1', P, C, speeds=u) P2 = PrismaticJoint('P2', C, T, speeds=u) raises(ValueError, lambda: JointsMethod(P, P1, P2)) P1 = PinJoint('P1', P, C, q, u) P2 = PrismaticJoint('P2', C, T, q, u) raises(ValueError, lambda: JointsMethod(P, P1, P2)) def test_complete_simple_double_pendulum(): q1, q2 = dynamicsymbols('q1 q2') u1, u2 = dynamicsymbols('u1 u2') m, l, g = symbols('m l g') C = Body('C') # ceiling PartP = Body('P', mass=m) PartR = Body('R', mass=m) J1 = PinJoint('J1', C, PartP, speeds=u1, coordinates=q1, child_joint_pos=-l*PartP.x, parent_axis=C.z, child_axis=PartP.z) J2 = PinJoint('J2', PartP, PartR, speeds=u2, coordinates=q2, child_joint_pos=-l*PartR.x, parent_axis=PartP.z, child_axis=PartR.z) PartP.apply_force(m*g*C.x) PartR.apply_force(m*g*C.x) method = JointsMethod(C, J1, J2) method.form_eoms() assert expand(method.mass_matrix_full) == Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 2*l**2*m*cos(q2) + 3*l**2*m, l**2*m*cos(q2) + l**2*m], [0, 0, l**2*m*cos(q2) + l**2*m, l**2*m]]) assert trigsimp(method.forcing_full) == trigsimp(Matrix([[u1], [u2], [-g*l*m*(sin(q1 + q2) + sin(q1)) - g*l*m*sin(q1) + l**2*m*(2*u1 + u2)*u2*sin(q2)], [-g*l*m*sin(q1 + q2) - l**2*m*u1**2*sin(q2)]])) def test_two_dof_joints(): q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') m, c1, c2, k1, k2 = symbols('m c1 c2 k1 k2') W = Body('W') B1 = Body('B1', mass=m) B2 = Body('B2', mass=m) J1 = PrismaticJoint('J1', W, B1, coordinates=q1, speeds=u1) J2 = PrismaticJoint('J2', B1, B2, coordinates=q2, speeds=u2) W.apply_force(k1*q1*W.x, reaction_body=B1) W.apply_force(c1*u1*W.x, reaction_body=B1) B1.apply_force(k2*q2*W.x, reaction_body=B2) B1.apply_force(c2*u2*W.x, reaction_body=B2) method = JointsMethod(W, J1, J2) method.form_eoms() MM = method.mass_matrix forcing = method.forcing rhs = MM.LUsolve(forcing) assert expand(rhs[0]) == expand((-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2)/m) assert expand(rhs[1]) == expand((k1 * q1 + c1 * u1 - 2 * k2 * q2 - 2 * c2 * u2) / m) def test_simple_pedulum(): l, m, g = symbols('l m g') C = Body('C') b = Body('b', mass=m) q = dynamicsymbols('q') P = PinJoint('P', C, b, speeds=q.diff(t), coordinates=q, child_joint_pos = -l*b.x, parent_axis=C.z, child_axis=b.z) b.potential_energy = - m * g * l * cos(q) method = JointsMethod(C, P) method.form_eoms(LagrangesMethod) rhs = method.rhs() assert rhs[1] == -g*sin(q)/l def test_chaos_pendulum(): #https://www.pydy.org/examples/chaos_pendulum.html mA, mB, lA, lB, IAxx, IBxx, IByy, IBzz, g = symbols('mA, mB, lA, lB, IAxx, IBxx, IByy, IBzz, g') theta, phi, omega, alpha = dynamicsymbols('theta phi omega alpha') A = ReferenceFrame('A') B = ReferenceFrame('B') rod = Body('rod', mass=mA, frame=A, central_inertia=inertia(A, IAxx, IAxx, 0)) plate = Body('plate', mass=mB, frame=B, central_inertia=inertia(B, IBxx, IByy, IBzz)) C = Body('C') J1 = PinJoint('J1', C, rod, coordinates=theta, speeds=omega, child_joint_pos=-lA*rod.z, parent_axis=C.y, child_axis=rod.y) J2 = PinJoint('J2', rod, plate, coordinates=phi, speeds=alpha, parent_joint_pos=(lB-lA)*rod.z, parent_axis=rod.z, child_axis=plate.z) rod.apply_force(mA*g*C.z) plate.apply_force(mB*g*C.z) method = JointsMethod(C, J1, J2) method.form_eoms() MM = method.mass_matrix forcing = method.forcing rhs = MM.LUsolve(forcing) xd = (-2 * IBxx * alpha * omega * sin(phi) * cos(phi) + 2 * IByy * alpha * omega * sin(phi) * cos(phi) - g * lA * mA * sin(theta) - g * lB * mB * sin(theta)) / (IAxx + IBxx * sin(phi)**2 + IByy * cos(phi)**2 + lA**2 * mA + lB**2 * mB) assert (rhs[0] - xd).simplify() == 0 xd = (IBxx - IByy) * omega**2 * sin(phi) * cos(phi) / IBzz assert (rhs[1] - xd).simplify() == 0 sympy-sympy-1.9/sympy/physics/mechanics/tests/test_kane.py000066400000000000000000000321561412543434000242200ustar00rootroot00000000000000from sympy.core.backend import (cos, expand, Matrix, sin, symbols, tan, sqrt, S, zeros) from sympy import simplify from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, RigidBody, KanesMethod, inertia, Particle, dot) def test_one_dof(): # This is for a 1 dof spring-mass-damper case. # It is described in more detail in the KanesMethod docstring. q, u = dynamicsymbols('q u') qd, ud = dynamicsymbols('q u', 1) m, c, k = symbols('m c k') N = ReferenceFrame('N') P = Point('P') P.set_vel(N, u * N.x) kd = [qd - u] FL = [(P, (-k * q - c * u) * N.x)] pa = Particle('pa', P, m) BL = [pa] KM = KanesMethod(N, [q], [u], kd) KM.kanes_equations(BL, FL) assert KM.bodies == BL assert KM.loads == FL MM = KM.mass_matrix forcing = KM.forcing rhs = MM.inv() * forcing assert expand(rhs[0]) == expand(-(q * k + u * c) / m) assert simplify(KM.rhs() - KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(2, 1) assert (KM.linearize(A_and_B=True, )[0] == Matrix([[0, 1], [-k/m, -c/m]])) def test_two_dof(): # This is for a 2 d.o.f., 2 particle spring-mass-damper. # The first coordinate is the displacement of the first particle, and the # second is the relative displacement between the first and second # particles. Speeds are defined as the time derivatives of the particles. q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') q1d, q2d, u1d, u2d = dynamicsymbols('q1 q2 u1 u2', 1) m, c1, c2, k1, k2 = symbols('m c1 c2 k1 k2') N = ReferenceFrame('N') P1 = Point('P1') P2 = Point('P2') P1.set_vel(N, u1 * N.x) P2.set_vel(N, (u1 + u2) * N.x) kd = [q1d - u1, q2d - u2] # Now we create the list of forces, then assign properties to each # particle, then create a list of all particles. FL = [(P1, (-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2) * N.x), (P2, (-k2 * q2 - c2 * u2) * N.x)] pa1 = Particle('pa1', P1, m) pa2 = Particle('pa2', P2, m) BL = [pa1, pa2] # Finally we create the KanesMethod object, specify the inertial frame, # pass relevant information, and form Fr & Fr*. Then we calculate the mass # matrix and forcing terms, and finally solve for the udots. KM = KanesMethod(N, q_ind=[q1, q2], u_ind=[u1, u2], kd_eqs=kd) KM.kanes_equations(BL, FL) MM = KM.mass_matrix forcing = KM.forcing rhs = MM.inv() * forcing assert expand(rhs[0]) == expand((-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2)/m) assert expand(rhs[1]) == expand((k1 * q1 + c1 * u1 - 2 * k2 * q2 - 2 * c2 * u2) / m) assert simplify(KM.rhs() - KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(4, 1) def test_pend(): q, u = dynamicsymbols('q u') qd, ud = dynamicsymbols('q u', 1) m, l, g = symbols('m l g') N = ReferenceFrame('N') P = Point('P') P.set_vel(N, -l * u * sin(q) * N.x + l * u * cos(q) * N.y) kd = [qd - u] FL = [(P, m * g * N.x)] pa = Particle('pa', P, m) BL = [pa] KM = KanesMethod(N, [q], [u], kd) KM.kanes_equations(BL, FL) MM = KM.mass_matrix forcing = KM.forcing rhs = MM.inv() * forcing rhs.simplify() assert expand(rhs[0]) == expand(-g / l * sin(q)) assert simplify(KM.rhs() - KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(2, 1) def test_rolling_disc(): # Rolling Disc Example # Here the rolling disc is formed from the contact point up, removing the # need to introduce generalized speeds. Only 3 configuration and three # speed variables are need to describe this system, along with the disc's # mass and radius, and the local gravity (note that mass will drop out). q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) r, m, g = symbols('r m g') # The kinematics are formed by a series of simple rotations. Each simple # rotation creates a new frame, and the next rotation is defined by the new # frame's basis vectors. This example uses a 3-1-2 series of rotations, or # Z, X, Y series of rotations. Angular velocity for this is defined using # the second frame's basis (the lean frame). N = ReferenceFrame('N') Y = N.orientnew('Y', 'Axis', [q1, N.z]) L = Y.orientnew('L', 'Axis', [q2, Y.x]) R = L.orientnew('R', 'Axis', [q3, L.y]) w_R_N_qd = R.ang_vel_in(N) R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) # This is the translational kinematics. We create a point with no velocity # in N; this is the contact point between the disc and ground. Next we form # the position vector from the contact point to the disc's center of mass. # Finally we form the velocity and acceleration of the disc. C = Point('C') C.set_vel(N, 0) Dmc = C.locatenew('Dmc', r * L.z) Dmc.v2pt_theory(C, N, R) # This is a simple way to form the inertia dyadic. I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) # Kinematic differential equations; how the generalized coordinate time # derivatives relate to generalized speeds. kd = [dot(R.ang_vel_in(N) - w_R_N_qd, uv) for uv in L] # Creation of the force list; it is the gravitational force at the mass # center of the disc. Then we create the disc by assigning a Point to the # center of mass attribute, a ReferenceFrame to the frame attribute, and mass # and inertia. Then we form the body list. ForceList = [(Dmc, - m * g * Y.z)] BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) BodyList = [BodyD] # Finally we form the equations of motion, using the same steps we did # before. Specify inertial frame, supply generalized speeds, supply # kinematic differential equation dictionary, compute Fr from the force # list and Fr* from the body list, compute the mass matrix and forcing # terms, then solve for the u dots (time derivatives of the generalized # speeds). KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd) KM.kanes_equations(BodyList, ForceList) MM = KM.mass_matrix forcing = KM.forcing rhs = MM.inv() * forcing kdd = KM.kindiffdict() rhs = rhs.subs(kdd) rhs.simplify() assert rhs.expand() == Matrix([(6*u2*u3*r - u3**2*r*tan(q2) + 4*g*sin(q2))/(5*r), -2*u1*u3/3, u1*(-2*u2 + u3*tan(q2))]).expand() assert simplify(KM.rhs() - KM.mass_matrix_full.LUsolve(KM.forcing_full)) == zeros(6, 1) # This code tests our output vs. benchmark values. When r=g=m=1, the # critical speed (where all eigenvalues of the linearized equations are 0) # is 1 / sqrt(3) for the upright case. A = KM.linearize(A_and_B=True)[0] A_upright = A.subs({r: 1, g: 1, m: 1}).subs({q1: 0, q2: 0, q3: 0, u1: 0, u3: 0}) import sympy assert sympy.sympify(A_upright.subs({u2: 1 / sqrt(3)})).eigenvals() == {S.Zero: 6} def test_aux(): # Same as above, except we have 2 auxiliary speeds for the ground contact # point, which is known to be zero. In one case, we go through then # substitute the aux. speeds in at the end (they are zero, as well as their # derivative), in the other case, we use the built-in auxiliary speed part # of KanesMethod. The equations from each should be the same. q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') q1d, q2d, q3d, u1d, u2d, u3d = dynamicsymbols('q1 q2 q3 u1 u2 u3', 1) u4, u5, f1, f2 = dynamicsymbols('u4, u5, f1, f2') u4d, u5d = dynamicsymbols('u4, u5', 1) r, m, g = symbols('r m g') N = ReferenceFrame('N') Y = N.orientnew('Y', 'Axis', [q1, N.z]) L = Y.orientnew('L', 'Axis', [q2, Y.x]) R = L.orientnew('R', 'Axis', [q3, L.y]) w_R_N_qd = R.ang_vel_in(N) R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) C = Point('C') C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x)) Dmc = C.locatenew('Dmc', r * L.z) Dmc.v2pt_theory(C, N, R) Dmc.a2pt_theory(C, N, R) I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) kd = [dot(R.ang_vel_in(N) - w_R_N_qd, uv) for uv in L] ForceList = [(Dmc, - m * g * Y.z), (C, f1 * L.x + f2 * (Y.z ^ L.x))] BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) BodyList = [BodyD] KM = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3, u4, u5], kd_eqs=kd) (fr, frstar) = KM.kanes_equations(BodyList, ForceList) fr = fr.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) frstar = frstar.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) KM2 = KanesMethod(N, q_ind=[q1, q2, q3], u_ind=[u1, u2, u3], kd_eqs=kd, u_auxiliary=[u4, u5]) (fr2, frstar2) = KM2.kanes_equations(BodyList, ForceList) fr2 = fr2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) frstar2 = frstar2.subs({u4d: 0, u5d: 0}).subs({u4: 0, u5: 0}) frstar.simplify() frstar2.simplify() assert (fr - fr2).expand() == Matrix([0, 0, 0, 0, 0]) assert (frstar - frstar2).expand() == Matrix([0, 0, 0, 0, 0]) def test_parallel_axis(): # This is for a 2 dof inverted pendulum on a cart. # This tests the parallel axis code in KanesMethod. The inertia of the # pendulum is defined about the hinge, not about the center of mass. # Defining the constants and knowns of the system gravity = symbols('g') k, ls = symbols('k ls') a, mA, mC = symbols('a mA mC') F = dynamicsymbols('F') Ix, Iy, Iz = symbols('Ix Iy Iz') # Declaring the Generalized coordinates and speeds q1, q2 = dynamicsymbols('q1 q2') q1d, q2d = dynamicsymbols('q1 q2', 1) u1, u2 = dynamicsymbols('u1 u2') u1d, u2d = dynamicsymbols('u1 u2', 1) # Creating reference frames N = ReferenceFrame('N') A = ReferenceFrame('A') A.orient(N, 'Axis', [-q2, N.z]) A.set_ang_vel(N, -u2 * N.z) # Origin of Newtonian reference frame O = Point('O') # Creating and Locating the positions of the cart, C, and the # center of mass of the pendulum, A C = O.locatenew('C', q1 * N.x) Ao = C.locatenew('Ao', a * A.y) # Defining velocities of the points O.set_vel(N, 0) C.set_vel(N, u1 * N.x) Ao.v2pt_theory(C, N, A) Cart = Particle('Cart', C, mC) Pendulum = RigidBody('Pendulum', Ao, A, mA, (inertia(A, Ix, Iy, Iz), C)) # kinematical differential equations kindiffs = [q1d - u1, q2d - u2] bodyList = [Cart, Pendulum] forceList = [(Ao, -N.y * gravity * mA), (C, -N.y * gravity * mC), (C, -N.x * k * (q1 - ls)), (C, N.x * F)] km = KanesMethod(N, [q1, q2], [u1, u2], kindiffs) (fr, frstar) = km.kanes_equations(bodyList, forceList) mm = km.mass_matrix_full assert mm[3, 3] == Iz def test_input_format(): # 1 dof problem from test_one_dof q, u = dynamicsymbols('q u') qd, ud = dynamicsymbols('q u', 1) m, c, k = symbols('m c k') N = ReferenceFrame('N') P = Point('P') P.set_vel(N, u * N.x) kd = [qd - u] FL = [(P, (-k * q - c * u) * N.x)] pa = Particle('pa', P, m) BL = [pa] KM = KanesMethod(N, [q], [u], kd) # test for input format kane.kanes_equations((body1, body2, particle1)) assert KM.kanes_equations(BL)[0] == Matrix([0]) # test for input format kane.kanes_equations(bodies=(body1, body 2), loads=(load1,load2)) assert KM.kanes_equations(bodies=BL, loads=None)[0] == Matrix([0]) # test for input format kane.kanes_equations(bodies=(body1, body 2), loads=None) assert KM.kanes_equations(BL, loads=None)[0] == Matrix([0]) # test for input format kane.kanes_equations(bodies=(body1, body 2)) assert KM.kanes_equations(BL)[0] == Matrix([0]) # test for input format kane.kanes_equations(bodies=(body1, body2), loads=[]) assert KM.kanes_equations(BL, [])[0] == Matrix([0]) # test for error raised when a wrong force list (in this case a string) is provided from sympy.testing.pytest import raises raises(ValueError, lambda: KM._form_fr('bad input')) # 1 dof problem from test_one_dof with FL & BL in instance KM = KanesMethod(N, [q], [u], kd, bodies=BL, forcelist=FL) assert KM.kanes_equations()[0] == Matrix([-c*u - k*q]) # 2 dof problem from test_two_dof q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') q1d, q2d, u1d, u2d = dynamicsymbols('q1 q2 u1 u2', 1) m, c1, c2, k1, k2 = symbols('m c1 c2 k1 k2') N = ReferenceFrame('N') P1 = Point('P1') P2 = Point('P2') P1.set_vel(N, u1 * N.x) P2.set_vel(N, (u1 + u2) * N.x) kd = [q1d - u1, q2d - u2] FL = ((P1, (-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2) * N.x), (P2, (-k2 * q2 - c2 * u2) * N.x)) pa1 = Particle('pa1', P1, m) pa2 = Particle('pa2', P2, m) BL = (pa1, pa2) KM = KanesMethod(N, q_ind=[q1, q2], u_ind=[u1, u2], kd_eqs=kd) # test for input format # kane.kanes_equations((body1, body2), (load1, load2)) KM.kanes_equations(BL, FL) MM = KM.mass_matrix forcing = KM.forcing rhs = MM.inv() * forcing assert expand(rhs[0]) == expand((-k1 * q1 - c1 * u1 + k2 * q2 + c2 * u2)/m) assert expand(rhs[1]) == expand((k1 * q1 + c1 * u1 - 2 * k2 * q2 - 2 * c2 * u2) / m) sympy-sympy-1.9/sympy/physics/mechanics/tests/test_kane2.py000066400000000000000000000451211412543434000242760ustar00rootroot00000000000000from sympy.core.backend import cos, Matrix, sin, zeros, tan, pi, symbols from sympy import trigsimp, simplify, solve from sympy.physics.mechanics import (cross, dot, dynamicsymbols, find_dynamicsymbols, KanesMethod, inertia, inertia_of_point_mass, Point, ReferenceFrame, RigidBody) def test_aux_dep(): # This test is about rolling disc dynamics, comparing the results found # with KanesMethod to those found when deriving the equations "manually" # with SymPy. # The terms Fr, Fr*, and Fr*_steady are all compared between the two # methods. Here, Fr*_steady refers to the generalized inertia forces for an # equilibrium configuration. # Note: comparing to the test of test_rolling_disc() in test_kane.py, this # test also tests auxiliary speeds and configuration and motion constraints #, seen in the generalized dependent coordinates q[3], and depend speeds # u[3], u[4] and u[5]. # First, manual derivation of Fr, Fr_star, Fr_star_steady. # Symbols for time and constant parameters. # Symbols for contact forces: Fx, Fy, Fz. t, r, m, g, I, J = symbols('t r m g I J') Fx, Fy, Fz = symbols('Fx Fy Fz') # Configuration variables and their time derivatives: # q[0] -- yaw # q[1] -- lean # q[2] -- spin # q[3] -- dot(-r*B.z, A.z) -- distance from ground plane to disc center in # A.z direction # Generalized speeds and their time derivatives: # u[0] -- disc angular velocity component, disc fixed x direction # u[1] -- disc angular velocity component, disc fixed y direction # u[2] -- disc angular velocity component, disc fixed z direction # u[3] -- disc velocity component, A.x direction # u[4] -- disc velocity component, A.y direction # u[5] -- disc velocity component, A.z direction # Auxiliary generalized speeds: # ua[0] -- contact point auxiliary generalized speed, A.x direction # ua[1] -- contact point auxiliary generalized speed, A.y direction # ua[2] -- contact point auxiliary generalized speed, A.z direction q = dynamicsymbols('q:4') qd = [qi.diff(t) for qi in q] u = dynamicsymbols('u:6') ud = [ui.diff(t) for ui in u] ud_zero = dict(zip(ud, [0.]*len(ud))) ua = dynamicsymbols('ua:3') ua_zero = dict(zip(ua, [0.]*len(ua))) # noqa:F841 # Reference frames: # Yaw intermediate frame: A. # Lean intermediate frame: B. # Disc fixed frame: C. N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q[0], N.z]) B = A.orientnew('B', 'Axis', [q[1], A.x]) C = B.orientnew('C', 'Axis', [q[2], B.y]) # Angular velocity and angular acceleration of disc fixed frame # u[0], u[1] and u[2] are generalized independent speeds. C.set_ang_vel(N, u[0]*B.x + u[1]*B.y + u[2]*B.z) C.set_ang_acc(N, C.ang_vel_in(N).diff(t, B) + cross(B.ang_vel_in(N), C.ang_vel_in(N))) # Velocity and acceleration of points: # Disc-ground contact point: P. # Center of disc: O, defined from point P with depend coordinate: q[3] # u[3], u[4] and u[5] are generalized dependent speeds. P = Point('P') P.set_vel(N, ua[0]*A.x + ua[1]*A.y + ua[2]*A.z) O = P.locatenew('O', q[3]*A.z + r*sin(q[1])*A.y) O.set_vel(N, u[3]*A.x + u[4]*A.y + u[5]*A.z) O.set_acc(N, O.vel(N).diff(t, A) + cross(A.ang_vel_in(N), O.vel(N))) # Kinematic differential equations: # Two equalities: one is w_c_n_qd = C.ang_vel_in(N) in three coordinates # directions of B, for qd0, qd1 and qd2. # the other is v_o_n_qd = O.vel(N) in A.z direction for qd3. # Then, solve for dq/dt's in terms of u's: qd_kd. w_c_n_qd = qd[0]*A.z + qd[1]*B.x + qd[2]*B.y v_o_n_qd = O.pos_from(P).diff(t, A) + cross(A.ang_vel_in(N), O.pos_from(P)) kindiffs = Matrix([dot(w_c_n_qd - C.ang_vel_in(N), uv) for uv in B] + [dot(v_o_n_qd - O.vel(N), A.z)]) qd_kd = solve(kindiffs, qd) # noqa:F841 # Values of generalized speeds during a steady turn for later substitution # into the Fr_star_steady. steady_conditions = solve(kindiffs.subs({qd[1] : 0, qd[3] : 0}), u) steady_conditions.update({qd[1] : 0, qd[3] : 0}) # Partial angular velocities and velocities. partial_w_C = [C.ang_vel_in(N).diff(ui, N) for ui in u + ua] partial_v_O = [O.vel(N).diff(ui, N) for ui in u + ua] partial_v_P = [P.vel(N).diff(ui, N) for ui in u + ua] # Configuration constraint: f_c, the projection of radius r in A.z direction # is q[3]. # Velocity constraints: f_v, for u3, u4 and u5. # Acceleration constraints: f_a. f_c = Matrix([dot(-r*B.z, A.z) - q[3]]) f_v = Matrix([dot(O.vel(N) - (P.vel(N) + cross(C.ang_vel_in(N), O.pos_from(P))), ai).expand() for ai in A]) v_o_n = cross(C.ang_vel_in(N), O.pos_from(P)) a_o_n = v_o_n.diff(t, A) + cross(A.ang_vel_in(N), v_o_n) f_a = Matrix([dot(O.acc(N) - a_o_n, ai) for ai in A]) # noqa:F841 # Solve for constraint equations in the form of # u_dependent = A_rs * [u_i; u_aux]. # First, obtain constraint coefficient matrix: M_v * [u; ua] = 0; # Second, taking u[0], u[1], u[2] as independent, # taking u[3], u[4], u[5] as dependent, # rearranging the matrix of M_v to be A_rs for u_dependent. # Third, u_aux ==0 for u_dep, and resulting dictionary of u_dep_dict. M_v = zeros(3, 9) for i in range(3): for j, ui in enumerate(u + ua): M_v[i, j] = f_v[i].diff(ui) M_v_i = M_v[:, :3] M_v_d = M_v[:, 3:6] M_v_aux = M_v[:, 6:] M_v_i_aux = M_v_i.row_join(M_v_aux) A_rs = - M_v_d.inv() * M_v_i_aux u_dep = A_rs[:, :3] * Matrix(u[:3]) u_dep_dict = dict(zip(u[3:], u_dep)) # Active forces: F_O acting on point O; F_P acting on point P. # Generalized active forces (unconstrained): Fr_u = F_point * pv_point. F_O = m*g*A.z F_P = Fx * A.x + Fy * A.y + Fz * A.z Fr_u = Matrix([dot(F_O, pv_o) + dot(F_P, pv_p) for pv_o, pv_p in zip(partial_v_O, partial_v_P)]) # Inertia force: R_star_O. # Inertia of disc: I_C_O, where J is a inertia component about principal axis. # Inertia torque: T_star_C. # Generalized inertia forces (unconstrained): Fr_star_u. R_star_O = -m*O.acc(N) I_C_O = inertia(B, I, J, I) T_star_C = -(dot(I_C_O, C.ang_acc_in(N)) \ + cross(C.ang_vel_in(N), dot(I_C_O, C.ang_vel_in(N)))) Fr_star_u = Matrix([dot(R_star_O, pv) + dot(T_star_C, pav) for pv, pav in zip(partial_v_O, partial_w_C)]) # Form nonholonomic Fr: Fr_c, and nonholonomic Fr_star: Fr_star_c. # Also, nonholonomic Fr_star in steady turning condition: Fr_star_steady. Fr_c = Fr_u[:3, :].col_join(Fr_u[6:, :]) + A_rs.T * Fr_u[3:6, :] Fr_star_c = Fr_star_u[:3, :].col_join(Fr_star_u[6:, :])\ + A_rs.T * Fr_star_u[3:6, :] Fr_star_steady = Fr_star_c.subs(ud_zero).subs(u_dep_dict)\ .subs(steady_conditions).subs({q[3]: -r*cos(q[1])}).expand() # Second, using KaneMethod in mechanics for fr, frstar and frstar_steady. # Rigid Bodies: disc, with inertia I_C_O. iner_tuple = (I_C_O, O) disc = RigidBody('disc', O, C, m, iner_tuple) bodyList = [disc] # Generalized forces: Gravity: F_o; Auxiliary forces: F_p. F_o = (O, F_O) F_p = (P, F_P) forceList = [F_o, F_p] # KanesMethod. kane = KanesMethod( N, q_ind= q[:3], u_ind= u[:3], kd_eqs=kindiffs, q_dependent=q[3:], configuration_constraints = f_c, u_dependent=u[3:], velocity_constraints= f_v, u_auxiliary=ua ) # fr, frstar, frstar_steady and kdd(kinematic differential equations). (fr, frstar)= kane.kanes_equations(bodyList, forceList) frstar_steady = frstar.subs(ud_zero).subs(u_dep_dict).subs(steady_conditions)\ .subs({q[3]: -r*cos(q[1])}).expand() kdd = kane.kindiffdict() assert Matrix(Fr_c).expand() == fr.expand() assert Matrix(Fr_star_c.subs(kdd)).expand() == frstar.expand() assert (simplify(Matrix(Fr_star_steady).expand()) == simplify(frstar_steady.expand())) syms_in_forcing = find_dynamicsymbols(kane.forcing) for qdi in qd: assert qdi not in syms_in_forcing def test_non_central_inertia(): # This tests that the calculation of Fr* does not depend the point # about which the inertia of a rigid body is defined. This test solves # exercises 8.12, 8.17 from Kane 1985. # Declare symbols q1, q2, q3 = dynamicsymbols('q1:4') q1d, q2d, q3d = dynamicsymbols('q1:4', level=1) u1, u2, u3, u4, u5 = dynamicsymbols('u1:6') u_prime, R, M, g, e, f, theta = symbols('u\' R, M, g, e, f, theta') a, b, mA, mB, IA, J, K, t = symbols('a b mA mB IA J K t') Q1, Q2, Q3 = symbols('Q1, Q2 Q3') IA22, IA23, IA33 = symbols('IA22 IA23 IA33') # Reference Frames F = ReferenceFrame('F') P = F.orientnew('P', 'axis', [-theta, F.y]) A = P.orientnew('A', 'axis', [q1, P.x]) A.set_ang_vel(F, u1*A.x + u3*A.z) # define frames for wheels B = A.orientnew('B', 'axis', [q2, A.z]) C = A.orientnew('C', 'axis', [q3, A.z]) B.set_ang_vel(A, u4 * A.z) C.set_ang_vel(A, u5 * A.z) # define points D, S*, Q on frame A and their velocities pD = Point('D') pD.set_vel(A, 0) # u3 will not change v_D_F since wheels are still assumed to roll without slip. pD.set_vel(F, u2 * A.y) pS_star = pD.locatenew('S*', e*A.y) pQ = pD.locatenew('Q', f*A.y - R*A.x) for p in [pS_star, pQ]: p.v2pt_theory(pD, F, A) # masscenters of bodies A, B, C pA_star = pD.locatenew('A*', a*A.y) pB_star = pD.locatenew('B*', b*A.z) pC_star = pD.locatenew('C*', -b*A.z) for p in [pA_star, pB_star, pC_star]: p.v2pt_theory(pD, F, A) # points of B, C touching the plane P pB_hat = pB_star.locatenew('B^', -R*A.x) pC_hat = pC_star.locatenew('C^', -R*A.x) pB_hat.v2pt_theory(pB_star, F, B) pC_hat.v2pt_theory(pC_star, F, C) # the velocities of B^, C^ are zero since B, C are assumed to roll without slip kde = [q1d - u1, q2d - u4, q3d - u5] vc = [dot(p.vel(F), A.y) for p in [pB_hat, pC_hat]] # inertias of bodies A, B, C # IA22, IA23, IA33 are not specified in the problem statement, but are # necessary to define an inertia object. Although the values of # IA22, IA23, IA33 are not known in terms of the variables given in the # problem statement, they do not appear in the general inertia terms. inertia_A = inertia(A, IA, IA22, IA33, 0, IA23, 0) inertia_B = inertia(B, K, K, J) inertia_C = inertia(C, K, K, J) # define the rigid bodies A, B, C rbA = RigidBody('rbA', pA_star, A, mA, (inertia_A, pA_star)) rbB = RigidBody('rbB', pB_star, B, mB, (inertia_B, pB_star)) rbC = RigidBody('rbC', pC_star, C, mB, (inertia_C, pC_star)) km = KanesMethod(F, q_ind=[q1, q2, q3], u_ind=[u1, u2], kd_eqs=kde, u_dependent=[u4, u5], velocity_constraints=vc, u_auxiliary=[u3]) forces = [(pS_star, -M*g*F.x), (pQ, Q1*A.x + Q2*A.y + Q3*A.z)] bodies = [rbA, rbB, rbC] fr, fr_star = km.kanes_equations(bodies, forces) vc_map = solve(vc, [u4, u5]) # KanesMethod returns the negative of Fr, Fr* as defined in Kane1985. fr_star_expected = Matrix([ -(IA + 2*J*b**2/R**2 + 2*K + mA*a**2 + 2*mB*b**2) * u1.diff(t) - mA*a*u1*u2, -(mA + 2*mB +2*J/R**2) * u2.diff(t) + mA*a*u1**2, 0]) t = trigsimp(fr_star.subs(vc_map).subs({u3: 0})).doit().expand() assert ((fr_star_expected - t).expand() == zeros(3, 1)) # define inertias of rigid bodies A, B, C about point D # I_S/O = I_S/S* + I_S*/O bodies2 = [] for rb, I_star in zip([rbA, rbB, rbC], [inertia_A, inertia_B, inertia_C]): I = I_star + inertia_of_point_mass(rb.mass, rb.masscenter.pos_from(pD), rb.frame) bodies2.append(RigidBody('', rb.masscenter, rb.frame, rb.mass, (I, pD))) fr2, fr_star2 = km.kanes_equations(bodies2, forces) t = trigsimp(fr_star2.subs(vc_map).subs({u3: 0})).doit() assert (fr_star_expected - t).expand() == zeros(3, 1) def test_sub_qdot(): # This test solves exercises 8.12, 8.17 from Kane 1985 and defines # some velocities in terms of q, qdot. ## --- Declare symbols --- q1, q2, q3 = dynamicsymbols('q1:4') q1d, q2d, q3d = dynamicsymbols('q1:4', level=1) u1, u2, u3 = dynamicsymbols('u1:4') u_prime, R, M, g, e, f, theta = symbols('u\' R, M, g, e, f, theta') a, b, mA, mB, IA, J, K, t = symbols('a b mA mB IA J K t') IA22, IA23, IA33 = symbols('IA22 IA23 IA33') Q1, Q2, Q3 = symbols('Q1 Q2 Q3') # --- Reference Frames --- F = ReferenceFrame('F') P = F.orientnew('P', 'axis', [-theta, F.y]) A = P.orientnew('A', 'axis', [q1, P.x]) A.set_ang_vel(F, u1*A.x + u3*A.z) # define frames for wheels B = A.orientnew('B', 'axis', [q2, A.z]) C = A.orientnew('C', 'axis', [q3, A.z]) ## --- define points D, S*, Q on frame A and their velocities --- pD = Point('D') pD.set_vel(A, 0) # u3 will not change v_D_F since wheels are still assumed to roll w/o slip pD.set_vel(F, u2 * A.y) pS_star = pD.locatenew('S*', e*A.y) pQ = pD.locatenew('Q', f*A.y - R*A.x) # masscenters of bodies A, B, C pA_star = pD.locatenew('A*', a*A.y) pB_star = pD.locatenew('B*', b*A.z) pC_star = pD.locatenew('C*', -b*A.z) for p in [pS_star, pQ, pA_star, pB_star, pC_star]: p.v2pt_theory(pD, F, A) # points of B, C touching the plane P pB_hat = pB_star.locatenew('B^', -R*A.x) pC_hat = pC_star.locatenew('C^', -R*A.x) pB_hat.v2pt_theory(pB_star, F, B) pC_hat.v2pt_theory(pC_star, F, C) # --- relate qdot, u --- # the velocities of B^, C^ are zero since B, C are assumed to roll w/o slip kde = [dot(p.vel(F), A.y) for p in [pB_hat, pC_hat]] kde += [u1 - q1d] kde_map = solve(kde, [q1d, q2d, q3d]) for k, v in list(kde_map.items()): kde_map[k.diff(t)] = v.diff(t) # inertias of bodies A, B, C # IA22, IA23, IA33 are not specified in the problem statement, but are # necessary to define an inertia object. Although the values of # IA22, IA23, IA33 are not known in terms of the variables given in the # problem statement, they do not appear in the general inertia terms. inertia_A = inertia(A, IA, IA22, IA33, 0, IA23, 0) inertia_B = inertia(B, K, K, J) inertia_C = inertia(C, K, K, J) # define the rigid bodies A, B, C rbA = RigidBody('rbA', pA_star, A, mA, (inertia_A, pA_star)) rbB = RigidBody('rbB', pB_star, B, mB, (inertia_B, pB_star)) rbC = RigidBody('rbC', pC_star, C, mB, (inertia_C, pC_star)) ## --- use kanes method --- km = KanesMethod(F, [q1, q2, q3], [u1, u2], kd_eqs=kde, u_auxiliary=[u3]) forces = [(pS_star, -M*g*F.x), (pQ, Q1*A.x + Q2*A.y + Q3*A.z)] bodies = [rbA, rbB, rbC] # Q2 = -u_prime * u2 * Q1 / sqrt(u2**2 + f**2 * u1**2) # -u_prime * R * u2 / sqrt(u2**2 + f**2 * u1**2) = R / Q1 * Q2 fr_expected = Matrix([ f*Q3 + M*g*e*sin(theta)*cos(q1), Q2 + M*g*sin(theta)*sin(q1), e*M*g*cos(theta) - Q1*f - Q2*R]) #Q1 * (f - u_prime * R * u2 / sqrt(u2**2 + f**2 * u1**2)))]) fr_star_expected = Matrix([ -(IA + 2*J*b**2/R**2 + 2*K + mA*a**2 + 2*mB*b**2) * u1.diff(t) - mA*a*u1*u2, -(mA + 2*mB +2*J/R**2) * u2.diff(t) + mA*a*u1**2, 0]) fr, fr_star = km.kanes_equations(bodies, forces) assert (fr.expand() == fr_expected.expand()) assert ((fr_star_expected - trigsimp(fr_star)).expand() == zeros(3, 1)) def test_sub_qdot2(): # This test solves exercises 8.3 from Kane 1985 and defines # all velocities in terms of q, qdot. We check that the generalized active # forces are correctly computed if u terms are only defined in the # kinematic differential equations. # # This functionality was added in PR 8948. Without qdot/u substitution, the # KanesMethod constructor will fail during the constraint initialization as # the B matrix will be poorly formed and inversion of the dependent part # will fail. g, m, Px, Py, Pz, R, t = symbols('g m Px Py Pz R t') q = dynamicsymbols('q:5') qd = dynamicsymbols('q:5', level=1) u = dynamicsymbols('u:5') ## Define inertial, intermediate, and rigid body reference frames A = ReferenceFrame('A') B_prime = A.orientnew('B_prime', 'Axis', [q[0], A.z]) B = B_prime.orientnew('B', 'Axis', [pi/2 - q[1], B_prime.x]) C = B.orientnew('C', 'Axis', [q[2], B.z]) ## Define points of interest and their velocities pO = Point('O') pO.set_vel(A, 0) # R is the point in plane H that comes into contact with disk C. pR = pO.locatenew('R', q[3]*A.x + q[4]*A.y) pR.set_vel(A, pR.pos_from(pO).diff(t, A)) pR.set_vel(B, 0) # C^ is the point in disk C that comes into contact with plane H. pC_hat = pR.locatenew('C^', 0) pC_hat.set_vel(C, 0) # C* is the point at the center of disk C. pCs = pC_hat.locatenew('C*', R*B.y) pCs.set_vel(C, 0) pCs.set_vel(B, 0) # calculate velocites of points C* and C^ in frame A pCs.v2pt_theory(pR, A, B) # points C* and R are fixed in frame B pC_hat.v2pt_theory(pCs, A, C) # points C* and C^ are fixed in frame C ## Define forces on each point of the system R_C_hat = Px*A.x + Py*A.y + Pz*A.z R_Cs = -m*g*A.z forces = [(pC_hat, R_C_hat), (pCs, R_Cs)] ## Define kinematic differential equations # let ui = omega_C_A & bi (i = 1, 2, 3) # u4 = qd4, u5 = qd5 u_expr = [C.ang_vel_in(A) & uv for uv in B] u_expr += qd[3:] kde = [ui - e for ui, e in zip(u, u_expr)] km1 = KanesMethod(A, q, u, kde) fr1, _ = km1.kanes_equations([], forces) ## Calculate generalized active forces if we impose the condition that the # disk C is rolling without slipping u_indep = u[:3] u_dep = list(set(u) - set(u_indep)) vc = [pC_hat.vel(A) & uv for uv in [A.x, A.y]] km2 = KanesMethod(A, q, u_indep, kde, u_dependent=u_dep, velocity_constraints=vc) fr2, _ = km2.kanes_equations([], forces) fr1_expected = Matrix([ -R*g*m*sin(q[1]), -R*(Px*cos(q[0]) + Py*sin(q[0]))*tan(q[1]), R*(Px*cos(q[0]) + Py*sin(q[0])), Px, Py]) fr2_expected = Matrix([ -R*g*m*sin(q[1]), 0, 0]) assert (trigsimp(fr1.expand()) == trigsimp(fr1_expected.expand())) assert (trigsimp(fr2.expand()) == trigsimp(fr2_expected.expand())) sympy-sympy-1.9/sympy/physics/mechanics/tests/test_kane3.py000066400000000000000000000336771412543434000243140ustar00rootroot00000000000000from sympy import evalf, symbols, pi, sin, cos, sqrt, acos, Matrix from sympy.physics.mechanics import (ReferenceFrame, dynamicsymbols, inertia, KanesMethod, RigidBody, Point, dot, msubs) from sympy.testing.pytest import slow, ON_TRAVIS, skip @slow def test_bicycle(): if ON_TRAVIS: skip("Too slow for travis.") # Code to get equations of motion for a bicycle modeled as in: # J.P Meijaard, Jim M Papadopoulos, Andy Ruina and A.L Schwab. Linearized # dynamics equations for the balance and steer of a bicycle: a benchmark # and review. Proceedings of The Royal Society (2007) 463, 1955-1982 # doi: 10.1098/rspa.2007.1857 # Note that this code has been crudely ported from Autolev, which is the # reason for some of the unusual naming conventions. It was purposefully as # similar as possible in order to aide debugging. # Declare Coordinates & Speeds # Simple definitions for qdots - qd = u # Speeds are: yaw frame ang. rate, roll frame ang. rate, rear wheel frame # ang. rate (spinning motion), frame ang. rate (pitching motion), steering # frame ang. rate, and front wheel ang. rate (spinning motion). # Wheel positions are ignorable coordinates, so they are not introduced. q1, q2, q4, q5 = dynamicsymbols('q1 q2 q4 q5') q1d, q2d, q4d, q5d = dynamicsymbols('q1 q2 q4 q5', 1) u1, u2, u3, u4, u5, u6 = dynamicsymbols('u1 u2 u3 u4 u5 u6') u1d, u2d, u3d, u4d, u5d, u6d = dynamicsymbols('u1 u2 u3 u4 u5 u6', 1) # Declare System's Parameters WFrad, WRrad, htangle, forkoffset = symbols('WFrad WRrad htangle forkoffset') forklength, framelength, forkcg1 = symbols('forklength framelength forkcg1') forkcg3, framecg1, framecg3, Iwr11 = symbols('forkcg3 framecg1 framecg3 Iwr11') Iwr22, Iwf11, Iwf22, Iframe11 = symbols('Iwr22 Iwf11 Iwf22 Iframe11') Iframe22, Iframe33, Iframe31, Ifork11 = symbols('Iframe22 Iframe33 Iframe31 Ifork11') Ifork22, Ifork33, Ifork31, g = symbols('Ifork22 Ifork33 Ifork31 g') mframe, mfork, mwf, mwr = symbols('mframe mfork mwf mwr') # Set up reference frames for the system # N - inertial # Y - yaw # R - roll # WR - rear wheel, rotation angle is ignorable coordinate so not oriented # Frame - bicycle frame # TempFrame - statically rotated frame for easier reference inertia definition # Fork - bicycle fork # TempFork - statically rotated frame for easier reference inertia definition # WF - front wheel, again posses a ignorable coordinate N = ReferenceFrame('N') Y = N.orientnew('Y', 'Axis', [q1, N.z]) R = Y.orientnew('R', 'Axis', [q2, Y.x]) Frame = R.orientnew('Frame', 'Axis', [q4 + htangle, R.y]) WR = ReferenceFrame('WR') TempFrame = Frame.orientnew('TempFrame', 'Axis', [-htangle, Frame.y]) Fork = Frame.orientnew('Fork', 'Axis', [q5, Frame.x]) TempFork = Fork.orientnew('TempFork', 'Axis', [-htangle, Fork.y]) WF = ReferenceFrame('WF') # Kinematics of the Bicycle First block of code is forming the positions of # the relevant points # rear wheel contact -> rear wheel mass center -> frame mass center + # frame/fork connection -> fork mass center + front wheel mass center -> # front wheel contact point WR_cont = Point('WR_cont') WR_mc = WR_cont.locatenew('WR_mc', WRrad * R.z) Steer = WR_mc.locatenew('Steer', framelength * Frame.z) Frame_mc = WR_mc.locatenew('Frame_mc', - framecg1 * Frame.x + framecg3 * Frame.z) Fork_mc = Steer.locatenew('Fork_mc', - forkcg1 * Fork.x + forkcg3 * Fork.z) WF_mc = Steer.locatenew('WF_mc', forklength * Fork.x + forkoffset * Fork.z) WF_cont = WF_mc.locatenew('WF_cont', WFrad * (dot(Fork.y, Y.z) * Fork.y - Y.z).normalize()) # Set the angular velocity of each frame. # Angular accelerations end up being calculated automatically by # differentiating the angular velocities when first needed. # u1 is yaw rate # u2 is roll rate # u3 is rear wheel rate # u4 is frame pitch rate # u5 is fork steer rate # u6 is front wheel rate Y.set_ang_vel(N, u1 * Y.z) R.set_ang_vel(Y, u2 * R.x) WR.set_ang_vel(Frame, u3 * Frame.y) Frame.set_ang_vel(R, u4 * Frame.y) Fork.set_ang_vel(Frame, u5 * Fork.x) WF.set_ang_vel(Fork, u6 * Fork.y) # Form the velocities of the previously defined points, using the 2 - point # theorem (written out by hand here). Accelerations again are calculated # automatically when first needed. WR_cont.set_vel(N, 0) WR_mc.v2pt_theory(WR_cont, N, WR) Steer.v2pt_theory(WR_mc, N, Frame) Frame_mc.v2pt_theory(WR_mc, N, Frame) Fork_mc.v2pt_theory(Steer, N, Fork) WF_mc.v2pt_theory(Steer, N, Fork) WF_cont.v2pt_theory(WF_mc, N, WF) # Sets the inertias of each body. Uses the inertia frame to construct the # inertia dyadics. Wheel inertias are only defined by principle moments of # inertia, and are in fact constant in the frame and fork reference frames; # it is for this reason that the orientations of the wheels does not need # to be defined. The frame and fork inertias are defined in the 'Temp' # frames which are fixed to the appropriate body frames; this is to allow # easier input of the reference values of the benchmark paper. Note that # due to slightly different orientations, the products of inertia need to # have their signs flipped; this is done later when entering the numerical # value. Frame_I = (inertia(TempFrame, Iframe11, Iframe22, Iframe33, 0, 0, Iframe31), Frame_mc) Fork_I = (inertia(TempFork, Ifork11, Ifork22, Ifork33, 0, 0, Ifork31), Fork_mc) WR_I = (inertia(Frame, Iwr11, Iwr22, Iwr11), WR_mc) WF_I = (inertia(Fork, Iwf11, Iwf22, Iwf11), WF_mc) # Declaration of the RigidBody containers. :: BodyFrame = RigidBody('BodyFrame', Frame_mc, Frame, mframe, Frame_I) BodyFork = RigidBody('BodyFork', Fork_mc, Fork, mfork, Fork_I) BodyWR = RigidBody('BodyWR', WR_mc, WR, mwr, WR_I) BodyWF = RigidBody('BodyWF', WF_mc, WF, mwf, WF_I) # The kinematic differential equations; they are defined quite simply. Each # entry in this list is equal to zero. kd = [q1d - u1, q2d - u2, q4d - u4, q5d - u5] # The nonholonomic constraints are the velocity of the front wheel contact # point dotted into the X, Y, and Z directions; the yaw frame is used as it # is "closer" to the front wheel (1 less DCM connecting them). These # constraints force the velocity of the front wheel contact point to be 0 # in the inertial frame; the X and Y direction constraints enforce a # "no-slip" condition, and the Z direction constraint forces the front # wheel contact point to not move away from the ground frame, essentially # replicating the holonomic constraint which does not allow the frame pitch # to change in an invalid fashion. conlist_speed = [WF_cont.vel(N) & Y.x, WF_cont.vel(N) & Y.y, WF_cont.vel(N) & Y.z] # The holonomic constraint is that the position from the rear wheel contact # point to the front wheel contact point when dotted into the # normal-to-ground plane direction must be zero; effectively that the front # and rear wheel contact points are always touching the ground plane. This # is actually not part of the dynamic equations, but instead is necessary # for the lineraization process. conlist_coord = [WF_cont.pos_from(WR_cont) & Y.z] # The force list; each body has the appropriate gravitational force applied # at its mass center. FL = [(Frame_mc, -mframe * g * Y.z), (Fork_mc, -mfork * g * Y.z), (WF_mc, -mwf * g * Y.z), (WR_mc, -mwr * g * Y.z)] BL = [BodyFrame, BodyFork, BodyWR, BodyWF] # The N frame is the inertial frame, coordinates are supplied in the order # of independent, dependent coordinates, as are the speeds. The kinematic # differential equation are also entered here. Here the dependent speeds # are specified, in the same order they were provided in earlier, along # with the non-holonomic constraints. The dependent coordinate is also # provided, with the holonomic constraint. Again, this is only provided # for the linearization process. KM = KanesMethod(N, q_ind=[q1, q2, q5], q_dependent=[q4], configuration_constraints=conlist_coord, u_ind=[u2, u3, u5], u_dependent=[u1, u4, u6], velocity_constraints=conlist_speed, kd_eqs=kd) (fr, frstar) = KM.kanes_equations(BL, FL) # This is the start of entering in the numerical values from the benchmark # paper to validate the eigen values of the linearized equations from this # model to the reference eigen values. Look at the aforementioned paper for # more information. Some of these are intermediate values, used to # transform values from the paper into the coordinate systems used in this # model. PaperRadRear = 0.3 PaperRadFront = 0.35 HTA = evalf.N(pi / 2 - pi / 10) TrailPaper = 0.08 rake = evalf.N(-(TrailPaper*sin(HTA)-(PaperRadFront*cos(HTA)))) PaperWb = 1.02 PaperFrameCgX = 0.3 PaperFrameCgZ = 0.9 PaperForkCgX = 0.9 PaperForkCgZ = 0.7 FrameLength = evalf.N(PaperWb*sin(HTA)-(rake-(PaperRadFront-PaperRadRear)*cos(HTA))) FrameCGNorm = evalf.N((PaperFrameCgZ - PaperRadRear-(PaperFrameCgX/sin(HTA))*cos(HTA))*sin(HTA)) FrameCGPar = evalf.N(PaperFrameCgX / sin(HTA) + (PaperFrameCgZ - PaperRadRear - PaperFrameCgX / sin(HTA) * cos(HTA)) * cos(HTA)) tempa = evalf.N(PaperForkCgZ - PaperRadFront) tempb = evalf.N(PaperWb-PaperForkCgX) tempc = evalf.N(sqrt(tempa**2+tempb**2)) PaperForkL = evalf.N(PaperWb*cos(HTA)-(PaperRadFront-PaperRadRear)*sin(HTA)) ForkCGNorm = evalf.N(rake+(tempc * sin(pi/2-HTA-acos(tempa/tempc)))) ForkCGPar = evalf.N(tempc * cos((pi/2-HTA)-acos(tempa/tempc))-PaperForkL) # Here is the final assembly of the numerical values. The symbol 'v' is the # forward speed of the bicycle (a concept which only makes sense in the # upright, static equilibrium case?). These are in a dictionary which will # later be substituted in. Again the sign on the *product* of inertia # values is flipped here, due to different orientations of coordinate # systems. v = symbols('v') val_dict = {WFrad: PaperRadFront, WRrad: PaperRadRear, htangle: HTA, forkoffset: rake, forklength: PaperForkL, framelength: FrameLength, forkcg1: ForkCGPar, forkcg3: ForkCGNorm, framecg1: FrameCGNorm, framecg3: FrameCGPar, Iwr11: 0.0603, Iwr22: 0.12, Iwf11: 0.1405, Iwf22: 0.28, Ifork11: 0.05892, Ifork22: 0.06, Ifork33: 0.00708, Ifork31: 0.00756, Iframe11: 9.2, Iframe22: 11, Iframe33: 2.8, Iframe31: -2.4, mfork: 4, mframe: 85, mwf: 3, mwr: 2, g: 9.81, q1: 0, q2: 0, q4: 0, q5: 0, u1: 0, u2: 0, u3: v / PaperRadRear, u4: 0, u5: 0, u6: v / PaperRadFront} # Linearizes the forcing vector; the equations are set up as MM udot = # forcing, where MM is the mass matrix, udot is the vector representing the # time derivatives of the generalized speeds, and forcing is a vector which # contains both external forcing terms and internal forcing terms, such as # centripital or coriolis forces. This actually returns a matrix with as # many rows as *total* coordinates and speeds, but only as many columns as # independent coordinates and speeds. forcing_lin = KM.linearize()[0] # As mentioned above, the size of the linearized forcing terms is expanded # to include both q's and u's, so the mass matrix must have this done as # well. This will likely be changed to be part of the linearized process, # for future reference. MM_full = KM.mass_matrix_full MM_full_s = msubs(MM_full, val_dict) forcing_lin_s = msubs(forcing_lin, KM.kindiffdict(), val_dict) MM_full_s = MM_full_s.evalf() forcing_lin_s = forcing_lin_s.evalf() # Finally, we construct an "A" matrix for the form xdot = A x (x being the # state vector, although in this case, the sizes are a little off). The # following line extracts only the minimum entries required for eigenvalue # analysis, which correspond to rows and columns for lean, steer, lean # rate, and steer rate. Amat = MM_full_s.inv() * forcing_lin_s A = Amat.extract([1, 2, 4, 6], [1, 2, 3, 5]) # Precomputed for comparison Res = Matrix([[ 0, 0, 1.0, 0], [ 0, 0, 0, 1.0], [9.48977444677355, -0.891197738059089*v**2 - 0.571523173729245, -0.105522449805691*v, -0.330515398992311*v], [11.7194768719633, -1.97171508499972*v**2 + 30.9087533932407, 3.67680523332152*v, -3.08486552743311*v]]) # Actual eigenvalue comparison eps = 1.e-12 for i in range(6): error = Res.subs(v, i) - A.subs(v, i) assert all(abs(x) < eps for x in error) sympy-sympy-1.9/sympy/physics/mechanics/tests/test_kane4.py000066400000000000000000000111621412543434000242760ustar00rootroot00000000000000from sympy.core.backend import (cos, sin, Matrix, symbols) from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, KanesMethod, Particle) def test_replace_qdots_in_force(): # Test PR 16700 "Replaces qdots with us in force-list in kanes.py" # The new functionality allows one to specify forces in qdots which will # automatically be replaced with u:s which are defined by the kde supplied # to KanesMethod. The test case is the double pendulum with interacting # forces in the example of chapter 4.7 "CONTRIBUTING INTERACTION FORCES" # in Ref. [1]. Reference list at end test function. q1, q2 = dynamicsymbols('q1, q2') qd1, qd2 = dynamicsymbols('q1, q2', level=1) u1, u2 = dynamicsymbols('u1, u2') l, m = symbols('l, m') N = ReferenceFrame('N') # Inertial frame A = N.orientnew('A', 'Axis', (q1, N.z)) # Rod A frame B = A.orientnew('B', 'Axis', (q2, N.z)) # Rod B frame O = Point('O') # Origo O.set_vel(N, 0) P = O.locatenew('P', ( l * A.x )) # Point @ end of rod A P.v2pt_theory(O, N, A) Q = P.locatenew('Q', ( l * B.x )) # Point @ end of rod B Q.v2pt_theory(P, N, B) Ap = Particle('Ap', P, m) Bp = Particle('Bp', Q, m) # The forces are specified below. sigma is the torsional spring stiffness # and delta is the viscous damping coefficient acting between the two # bodies. Here, we specify the viscous damper as function of qdots prior # forming the kde. In more complex systems it not might be obvious which # kde is most efficient, why it is convenient to specify viscous forces in # qdots independently of the kde. sig, delta = symbols('sigma, delta') Ta = (sig * q2 + delta * qd2) * N.z forces = [(A, Ta), (B, -Ta)] # Try different kdes. kde1 = [u1 - qd1, u2 - qd2] kde2 = [u1 - qd1, u2 - (qd1 + qd2)] KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1) fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces) KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2) fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces) # Check EOM for KM2: # Mass and force matrix from p.6 in Ref. [2] with added forces from # example of chapter 4.7 in [1] and without gravity. forcing_matrix_expected = Matrix( [ [ m * l**2 * sin(q2) * u2**2 + sig * q2 + delta * (u2 - u1)], [ m * l**2 * sin(q2) * -u1**2 - sig * q2 - delta * (u2 - u1)] ] ) mass_matrix_expected = Matrix( [ [ 2 * m * l**2, m * l**2 * cos(q2) ], [ m * l**2 * cos(q2), m * l**2 ] ] ) assert (KM2.mass_matrix.expand() == mass_matrix_expected.expand()) assert (KM2.forcing.expand() == forcing_matrix_expected.expand()) # Check fr1 with reference fr_expected from [1] with u:s instead of qdots. fr1_expected = Matrix([ 0, -(sig*q2 + delta * u2) ]) assert fr1.expand() == fr1_expected.expand() # Check fr2 fr2_expected = Matrix([sig * q2 + delta * (u2 - u1), - sig * q2 - delta * (u2 - u1)]) assert fr2.expand() == fr2_expected.expand() # Specifying forces in u:s should stay the same: Ta = (sig * q2 + delta * u2) * N.z forces = [(A, Ta), (B, -Ta)] KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1) fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces) assert fr1.expand() == fr1_expected.expand() Ta = (sig * q2 + delta * (u2-u1)) * N.z forces = [(A, Ta), (B, -Ta)] KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2) fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces) assert fr2.expand() == fr2_expected.expand() # Test if we have a qubic qdot force: Ta = (sig * q2 + delta * qd2**3) * N.z forces = [(A, Ta), (B, -Ta)] KM1 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde1) fr1, fstar1 = KM1.kanes_equations([Ap, Bp], forces) fr1_cubic_expected = Matrix([ 0, -(sig*q2 + delta * u2**3) ]) assert fr1.expand() == fr1_cubic_expected.expand() KM2 = KanesMethod(N, [q1, q2], [u1, u2], kd_eqs=kde2) fr2, fstar2 = KM2.kanes_equations([Ap, Bp], forces) fr2_cubic_expected = Matrix([sig * q2 + delta * (u2 - u1)**3, - sig * q2 - delta * (u2 - u1)**3]) assert fr2.expand() == fr2_cubic_expected.expand() # References: # [1] T.R. Kane, D. a Levinson, Dynamics Theory and Applications, 2005. # [2] Arun K Banerjee, Flexible Multibody Dynamics:Efficient Formulations # and Applications, John Wiley and Sons, Ltd, 2016. # doi:http://dx.doi.org/10.1002/9781119015635. sympy-sympy-1.9/sympy/physics/mechanics/tests/test_lagrange.py000066400000000000000000000222771412543434000250650ustar00rootroot00000000000000from sympy.physics.mechanics import (dynamicsymbols, ReferenceFrame, Point, RigidBody, LagrangesMethod, Particle, inertia, Lagrangian) from sympy import symbols, pi, sin, cos, tan, simplify, Function, \ Derivative, Matrix def test_disc_on_an_incline_plane(): # Disc rolling on an inclined plane # First the generalized coordinates are created. The mass center of the # disc is located from top vertex of the inclined plane by the generalized # coordinate 'y'. The orientation of the disc is defined by the angle # 'theta'. The mass of the disc is 'm' and its radius is 'R'. The length of # the inclined path is 'l', the angle of inclination is 'alpha'. 'g' is the # gravitational constant. y, theta = dynamicsymbols('y theta') yd, thetad = dynamicsymbols('y theta', 1) m, g, R, l, alpha = symbols('m g R l alpha') # Next, we create the inertial reference frame 'N'. A reference frame 'A' # is attached to the inclined plane. Finally a frame is created which is attached to the disk. N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [pi/2 - alpha, N.z]) B = A.orientnew('B', 'Axis', [-theta, A.z]) # Creating the disc 'D'; we create the point that represents the mass # center of the disc and set its velocity. The inertia dyadic of the disc # is created. Finally, we create the disc. Do = Point('Do') Do.set_vel(N, yd * A.x) I = m * R**2/2 * B.z | B.z D = RigidBody('D', Do, B, m, (I, Do)) # To construct the Lagrangian, 'L', of the disc, we determine its kinetic # and potential energies, T and U, respectively. L is defined as the # difference between T and U. D.potential_energy = m * g * (l - y) * sin(alpha) L = Lagrangian(N, D) # We then create the list of generalized coordinates and constraint # equations. The constraint arises due to the disc rolling without slip on # on the inclined path. We then invoke the 'LagrangesMethod' class and # supply it the necessary arguments and generate the equations of motion. # The'rhs' method solves for the q_double_dots (i.e. the second derivative # with respect to time of the generalized coordinates and the lagrange # multipliers. q = [y, theta] hol_coneqs = [y - R * theta] m = LagrangesMethod(L, q, hol_coneqs=hol_coneqs) m.form_lagranges_equations() rhs = m.rhs() rhs.simplify() assert rhs[2] == 2*g*sin(alpha)/3 def test_simp_pen(): # This tests that the equations generated by LagrangesMethod are identical # to those obtained by hand calculations. The system under consideration is # the simple pendulum. # We begin by creating the generalized coordinates as per the requirements # of LagrangesMethod. Also we created the associate symbols # that characterize the system: 'm' is the mass of the bob, l is the length # of the massless rigid rod connecting the bob to a point O fixed in the # inertial frame. q, u = dynamicsymbols('q u') qd, ud = dynamicsymbols('q u ', 1) l, m, g = symbols('l m g') # We then create the inertial frame and a frame attached to the massless # string following which we define the inertial angular velocity of the # string. N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q, N.z]) A.set_ang_vel(N, qd * N.z) # Next, we create the point O and fix it in the inertial frame. We then # locate the point P to which the bob is attached. Its corresponding # velocity is then determined by the 'two point formula'. O = Point('O') O.set_vel(N, 0) P = O.locatenew('P', l * A.x) P.v2pt_theory(O, N, A) # The 'Particle' which represents the bob is then created and its # Lagrangian generated. Pa = Particle('Pa', P, m) Pa.potential_energy = - m * g * l * cos(q) L = Lagrangian(N, Pa) # The 'LagrangesMethod' class is invoked to obtain equations of motion. lm = LagrangesMethod(L, [q]) lm.form_lagranges_equations() RHS = lm.rhs() assert RHS[1] == -g*sin(q)/l def test_nonminimal_pendulum(): q1, q2 = dynamicsymbols('q1:3') q1d, q2d = dynamicsymbols('q1:3', level=1) L, m, t = symbols('L, m, t') g = 9.8 # Compose World Frame N = ReferenceFrame('N') pN = Point('N*') pN.set_vel(N, 0) # Create point P, the pendulum mass P = pN.locatenew('P1', q1*N.x + q2*N.y) P.set_vel(N, P.pos_from(pN).dt(N)) pP = Particle('pP', P, m) # Constraint Equations f_c = Matrix([q1**2 + q2**2 - L**2]) # Calculate the lagrangian, and form the equations of motion Lag = Lagrangian(N, pP) LM = LagrangesMethod(Lag, [q1, q2], hol_coneqs=f_c, forcelist=[(P, m*g*N.x)], frame=N) LM.form_lagranges_equations() # Check solution lam1 = LM.lam_vec[0, 0] eom_sol = Matrix([[m*Derivative(q1, t, t) - 9.8*m + 2*lam1*q1], [m*Derivative(q2, t, t) + 2*lam1*q2]]) assert LM.eom == eom_sol # Check multiplier solution lam_sol = Matrix([(19.6*q1 + 2*q1d**2 + 2*q2d**2)/(4*q1**2/m + 4*q2**2/m)]) assert simplify(LM.solve_multipliers(sol_type='Matrix')) == simplify(lam_sol) def test_dub_pen(): # The system considered is the double pendulum. Like in the # test of the simple pendulum above, we begin by creating the generalized # coordinates and the simple generalized speeds and accelerations which # will be used later. Following this we create frames and points necessary # for the kinematics. The procedure isn't explicitly explained as this is # similar to the simple pendulum. Also this is documented on the pydy.org # website. q1, q2 = dynamicsymbols('q1 q2') q1d, q2d = dynamicsymbols('q1 q2', 1) q1dd, q2dd = dynamicsymbols('q1 q2', 2) u1, u2 = dynamicsymbols('u1 u2') u1d, u2d = dynamicsymbols('u1 u2', 1) l, m, g = symbols('l m g') N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q1, N.z]) B = N.orientnew('B', 'Axis', [q2, N.z]) A.set_ang_vel(N, q1d * A.z) B.set_ang_vel(N, q2d * A.z) O = Point('O') P = O.locatenew('P', l * A.x) R = P.locatenew('R', l * B.x) O.set_vel(N, 0) P.v2pt_theory(O, N, A) R.v2pt_theory(P, N, B) ParP = Particle('ParP', P, m) ParR = Particle('ParR', R, m) ParP.potential_energy = - m * g * l * cos(q1) ParR.potential_energy = - m * g * l * cos(q1) - m * g * l * cos(q2) L = Lagrangian(N, ParP, ParR) lm = LagrangesMethod(L, [q1, q2], bodies=[ParP, ParR]) lm.form_lagranges_equations() assert simplify(l*m*(2*g*sin(q1) + l*sin(q1)*sin(q2)*q2dd + l*sin(q1)*cos(q2)*q2d**2 - l*sin(q2)*cos(q1)*q2d**2 + l*cos(q1)*cos(q2)*q2dd + 2*l*q1dd) - lm.eom[0]) == 0 assert simplify(l*m*(g*sin(q2) + l*sin(q1)*sin(q2)*q1dd - l*sin(q1)*cos(q2)*q1d**2 + l*sin(q2)*cos(q1)*q1d**2 + l*cos(q1)*cos(q2)*q1dd + l*q2dd) - lm.eom[1]) == 0 assert lm.bodies == [ParP, ParR] def test_rolling_disc(): # Rolling Disc Example # Here the rolling disc is formed from the contact point up, removing the # need to introduce generalized speeds. Only 3 configuration and 3 # speed variables are need to describe this system, along with the # disc's mass and radius, and the local gravity. q1, q2, q3 = dynamicsymbols('q1 q2 q3') q1d, q2d, q3d = dynamicsymbols('q1 q2 q3', 1) r, m, g = symbols('r m g') # The kinematics are formed by a series of simple rotations. Each simple # rotation creates a new frame, and the next rotation is defined by the new # frame's basis vectors. This example uses a 3-1-2 series of rotations, or # Z, X, Y series of rotations. Angular velocity for this is defined using # the second frame's basis (the lean frame). N = ReferenceFrame('N') Y = N.orientnew('Y', 'Axis', [q1, N.z]) L = Y.orientnew('L', 'Axis', [q2, Y.x]) R = L.orientnew('R', 'Axis', [q3, L.y]) # This is the translational kinematics. We create a point with no velocity # in N; this is the contact point between the disc and ground. Next we form # the position vector from the contact point to the disc's center of mass. # Finally we form the velocity and acceleration of the disc. C = Point('C') C.set_vel(N, 0) Dmc = C.locatenew('Dmc', r * L.z) Dmc.v2pt_theory(C, N, R) # Forming the inertia dyadic. I = inertia(L, m/4 * r**2, m/2 * r**2, m/4 * r**2) BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) # Finally we form the equations of motion, using the same steps we did # before. Supply the Lagrangian, the generalized speeds. BodyD.potential_energy = - m * g * r * cos(q2) Lag = Lagrangian(N, BodyD) q = [q1, q2, q3] q1 = Function('q1') q2 = Function('q2') q3 = Function('q3') l = LagrangesMethod(Lag, q) l.form_lagranges_equations() RHS = l.rhs() RHS.simplify() t = symbols('t') assert (l.mass_matrix[3:6] == [0, 5*m*r**2/4, 0]) assert RHS[4].simplify() == ( (-8*g*sin(q2(t)) + r*(5*sin(2*q2(t))*Derivative(q1(t), t) + 12*cos(q2(t))*Derivative(q3(t), t))*Derivative(q1(t), t))/(10*r)) assert RHS[5] == (-5*cos(q2(t))*Derivative(q1(t), t) + 6*tan(q2(t) )*Derivative(q3(t), t) + 4*Derivative(q1(t), t)/cos(q2(t)) )*Derivative(q2(t), t) sympy-sympy-1.9/sympy/physics/mechanics/tests/test_lagrange2.py000066400000000000000000000026051412543434000251400ustar00rootroot00000000000000from sympy.core.backend import symbols from sympy.physics.mechanics import dynamicsymbols from sympy.physics.mechanics import ReferenceFrame, Point, Particle from sympy.physics.mechanics import LagrangesMethod, Lagrangian ### This test asserts that a system with more than one external forces ### is acurately formed with Lagrange method (see issue #8626) def test_lagrange_2forces(): ### Equations for two damped springs in serie with two forces ### generalized coordinates q1, q2 = dynamicsymbols('q1, q2') ### generalized speeds q1d, q2d = dynamicsymbols('q1, q2', 1) ### Mass, spring strength, friction coefficient m, k, nu = symbols('m, k, nu') N = ReferenceFrame('N') O = Point('O') ### Two points P1 = O.locatenew('P1', q1 * N.x) P1.set_vel(N, q1d * N.x) P2 = O.locatenew('P1', q2 * N.x) P2.set_vel(N, q2d * N.x) pP1 = Particle('pP1', P1, m) pP1.potential_energy = k * q1**2 / 2 pP2 = Particle('pP2', P2, m) pP2.potential_energy = k * (q1 - q2)**2 / 2 #### Friction forces forcelist = [(P1, - nu * q1d * N.x), (P2, - nu * q2d * N.x)] lag = Lagrangian(N, pP1, pP2) l_method = LagrangesMethod(lag, (q1, q2), forcelist=forcelist, frame=N) l_method.form_lagranges_equations() eq1 = l_method.eom[0] assert eq1.diff(q1d) == nu eq2 = l_method.eom[1] assert eq2.diff(q2d) == nu sympy-sympy-1.9/sympy/physics/mechanics/tests/test_linearize.py000066400000000000000000000267411412543434000252670ustar00rootroot00000000000000from sympy.core.backend import (symbols, Matrix, cos, sin, atan, sqrt, Rational, _simplify_matrix) from sympy import solve, simplify, sympify from sympy.physics.mechanics import dynamicsymbols, ReferenceFrame, Point,\ dot, cross, inertia, KanesMethod, Particle, RigidBody, Lagrangian,\ LagrangesMethod from sympy.testing.pytest import slow @slow def test_linearize_rolling_disc_kane(): # Symbols for time and constant parameters t, r, m, g, v = symbols('t r m g v') # Configuration variables and their time derivatives q1, q2, q3, q4, q5, q6 = q = dynamicsymbols('q1:7') q1d, q2d, q3d, q4d, q5d, q6d = qd = [qi.diff(t) for qi in q] # Generalized speeds and their time derivatives u = dynamicsymbols('u:6') u1, u2, u3, u4, u5, u6 = u = dynamicsymbols('u1:7') u1d, u2d, u3d, u4d, u5d, u6d = [ui.diff(t) for ui in u] # Reference frames N = ReferenceFrame('N') # Inertial frame NO = Point('NO') # Inertial origin A = N.orientnew('A', 'Axis', [q1, N.z]) # Yaw intermediate frame B = A.orientnew('B', 'Axis', [q2, A.x]) # Lean intermediate frame C = B.orientnew('C', 'Axis', [q3, B.y]) # Disc fixed frame CO = NO.locatenew('CO', q4*N.x + q5*N.y + q6*N.z) # Disc center # Disc angular velocity in N expressed using time derivatives of coordinates w_c_n_qd = C.ang_vel_in(N) w_b_n_qd = B.ang_vel_in(N) # Inertial angular velocity and angular acceleration of disc fixed frame C.set_ang_vel(N, u1*B.x + u2*B.y + u3*B.z) # Disc center velocity in N expressed using time derivatives of coordinates v_co_n_qd = CO.pos_from(NO).dt(N) # Disc center velocity in N expressed using generalized speeds CO.set_vel(N, u4*C.x + u5*C.y + u6*C.z) # Disc Ground Contact Point P = CO.locatenew('P', r*B.z) P.v2pt_theory(CO, N, C) # Configuration constraint f_c = Matrix([q6 - dot(CO.pos_from(P), N.z)]) # Velocity level constraints f_v = Matrix([dot(P.vel(N), uv) for uv in C]) # Kinematic differential equations kindiffs = Matrix([dot(w_c_n_qd - C.ang_vel_in(N), uv) for uv in B] + [dot(v_co_n_qd - CO.vel(N), uv) for uv in N]) qdots = solve(kindiffs, qd) # Set angular velocity of remaining frames B.set_ang_vel(N, w_b_n_qd.subs(qdots)) C.set_ang_acc(N, C.ang_vel_in(N).dt(B) + cross(B.ang_vel_in(N), C.ang_vel_in(N))) # Active forces F_CO = m*g*A.z # Create inertia dyadic of disc C about point CO I = (m * r**2) / 4 J = (m * r**2) / 2 I_C_CO = inertia(C, I, J, I) Disc = RigidBody('Disc', CO, C, m, (I_C_CO, CO)) BL = [Disc] FL = [(CO, F_CO)] KM = KanesMethod(N, [q1, q2, q3, q4, q5], [u1, u2, u3], kd_eqs=kindiffs, q_dependent=[q6], configuration_constraints=f_c, u_dependent=[u4, u5, u6], velocity_constraints=f_v) (fr, fr_star) = KM.kanes_equations(BL, FL) # Test generalized form equations linearizer = KM.to_linearizer() assert linearizer.f_c == f_c assert linearizer.f_v == f_v assert linearizer.f_a == f_v.diff(t).subs(KM.kindiffdict()) sol = solve(linearizer.f_0 + linearizer.f_1, qd) for qi in qdots.keys(): assert sol[qi] == qdots[qi] assert simplify(linearizer.f_2 + linearizer.f_3 - fr - fr_star) == Matrix([0, 0, 0]) # Perform the linearization # Precomputed operating point q_op = {q6: -r*cos(q2)} u_op = {u1: 0, u2: sin(q2)*q1d + q3d, u3: cos(q2)*q1d, u4: -r*(sin(q2)*q1d + q3d)*cos(q3), u5: 0, u6: -r*(sin(q2)*q1d + q3d)*sin(q3)} qd_op = {q2d: 0, q4d: -r*(sin(q2)*q1d + q3d)*cos(q1), q5d: -r*(sin(q2)*q1d + q3d)*sin(q1), q6d: 0} ud_op = {u1d: 4*g*sin(q2)/(5*r) + sin(2*q2)*q1d**2/2 + 6*cos(q2)*q1d*q3d/5, u2d: 0, u3d: 0, u4d: r*(sin(q2)*sin(q3)*q1d*q3d + sin(q3)*q3d**2), u5d: r*(4*g*sin(q2)/(5*r) + sin(2*q2)*q1d**2/2 + 6*cos(q2)*q1d*q3d/5), u6d: -r*(sin(q2)*cos(q3)*q1d*q3d + cos(q3)*q3d**2)} A, B = linearizer.linearize(op_point=[q_op, u_op, qd_op, ud_op], A_and_B=True, simplify=True) upright_nominal = {q1d: 0, q2: 0, m: 1, r: 1, g: 1} # Precomputed solution A_sol = Matrix([[0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 1, 0], [sin(q1)*q3d, 0, 0, 0, 0, -sin(q1), -cos(q1), 0], [-cos(q1)*q3d, 0, 0, 0, 0, cos(q1), -sin(q1), 0], [0, Rational(4, 5), 0, 0, 0, 0, 0, 6*q3d/5], [0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, -2*q3d, 0, 0]]) B_sol = Matrix([]) # Check that linearization is correct assert A.subs(upright_nominal) == A_sol assert B.subs(upright_nominal) == B_sol # Check eigenvalues at critical speed are all zero: assert sympify(A.subs(upright_nominal).subs(q3d, 1/sqrt(3))).eigenvals() == {0: 8} def test_linearize_pendulum_kane_minimal(): q1 = dynamicsymbols('q1') # angle of pendulum u1 = dynamicsymbols('u1') # Angular velocity q1d = dynamicsymbols('q1', 1) # Angular velocity L, m, t = symbols('L, m, t') g = 9.8 # Compose world frame N = ReferenceFrame('N') pN = Point('N*') pN.set_vel(N, 0) # A.x is along the pendulum A = N.orientnew('A', 'axis', [q1, N.z]) A.set_ang_vel(N, u1*N.z) # Locate point P relative to the origin N* P = pN.locatenew('P', L*A.x) P.v2pt_theory(pN, N, A) pP = Particle('pP', P, m) # Create Kinematic Differential Equations kde = Matrix([q1d - u1]) # Input the force resultant at P R = m*g*N.x # Solve for eom with kanes method KM = KanesMethod(N, q_ind=[q1], u_ind=[u1], kd_eqs=kde) (fr, frstar) = KM.kanes_equations([pP], [(P, R)]) # Linearize A, B, inp_vec = KM.linearize(A_and_B=True, simplify=True) assert A == Matrix([[0, 1], [-9.8*cos(q1)/L, 0]]) assert B == Matrix([]) def test_linearize_pendulum_kane_nonminimal(): # Create generalized coordinates and speeds for this non-minimal realization # q1, q2 = N.x and N.y coordinates of pendulum # u1, u2 = N.x and N.y velocities of pendulum q1, q2 = dynamicsymbols('q1:3') q1d, q2d = dynamicsymbols('q1:3', level=1) u1, u2 = dynamicsymbols('u1:3') u1d, u2d = dynamicsymbols('u1:3', level=1) L, m, t = symbols('L, m, t') g = 9.8 # Compose world frame N = ReferenceFrame('N') pN = Point('N*') pN.set_vel(N, 0) # A.x is along the pendulum theta1 = atan(q2/q1) A = N.orientnew('A', 'axis', [theta1, N.z]) # Locate the pendulum mass P = pN.locatenew('P1', q1*N.x + q2*N.y) pP = Particle('pP', P, m) # Calculate the kinematic differential equations kde = Matrix([q1d - u1, q2d - u2]) dq_dict = solve(kde, [q1d, q2d]) # Set velocity of point P P.set_vel(N, P.pos_from(pN).dt(N).subs(dq_dict)) # Configuration constraint is length of pendulum f_c = Matrix([P.pos_from(pN).magnitude() - L]) # Velocity constraint is that the velocity in the A.x direction is # always zero (the pendulum is never getting longer). f_v = Matrix([P.vel(N).express(A).dot(A.x)]) f_v.simplify() # Acceleration constraints is the time derivative of the velocity constraint f_a = f_v.diff(t) f_a.simplify() # Input the force resultant at P R = m*g*N.x # Derive the equations of motion using the KanesMethod class. KM = KanesMethod(N, q_ind=[q2], u_ind=[u2], q_dependent=[q1], u_dependent=[u1], configuration_constraints=f_c, velocity_constraints=f_v, acceleration_constraints=f_a, kd_eqs=kde) (fr, frstar) = KM.kanes_equations([pP], [(P, R)]) # Set the operating point to be straight down, and non-moving q_op = {q1: L, q2: 0} u_op = {u1: 0, u2: 0} ud_op = {u1d: 0, u2d: 0} A, B, inp_vec = KM.linearize(op_point=[q_op, u_op, ud_op], A_and_B=True, simplify=True) assert A.expand() == Matrix([[0, 1], [-9.8/L, 0]]) assert B == Matrix([]) def test_linearize_pendulum_lagrange_minimal(): q1 = dynamicsymbols('q1') # angle of pendulum q1d = dynamicsymbols('q1', 1) # Angular velocity L, m, t = symbols('L, m, t') g = 9.8 # Compose world frame N = ReferenceFrame('N') pN = Point('N*') pN.set_vel(N, 0) # A.x is along the pendulum A = N.orientnew('A', 'axis', [q1, N.z]) A.set_ang_vel(N, q1d*N.z) # Locate point P relative to the origin N* P = pN.locatenew('P', L*A.x) P.v2pt_theory(pN, N, A) pP = Particle('pP', P, m) # Solve for eom with Lagranges method Lag = Lagrangian(N, pP) LM = LagrangesMethod(Lag, [q1], forcelist=[(P, m*g*N.x)], frame=N) LM.form_lagranges_equations() # Linearize A, B, inp_vec = LM.linearize([q1], [q1d], A_and_B=True) assert _simplify_matrix(A) == Matrix([[0, 1], [-9.8*cos(q1)/L, 0]]) assert B == Matrix([]) def test_linearize_pendulum_lagrange_nonminimal(): q1, q2 = dynamicsymbols('q1:3') q1d, q2d = dynamicsymbols('q1:3', level=1) L, m, t = symbols('L, m, t') g = 9.8 # Compose World Frame N = ReferenceFrame('N') pN = Point('N*') pN.set_vel(N, 0) # A.x is along the pendulum theta1 = atan(q2/q1) A = N.orientnew('A', 'axis', [theta1, N.z]) # Create point P, the pendulum mass P = pN.locatenew('P1', q1*N.x + q2*N.y) P.set_vel(N, P.pos_from(pN).dt(N)) pP = Particle('pP', P, m) # Constraint Equations f_c = Matrix([q1**2 + q2**2 - L**2]) # Calculate the lagrangian, and form the equations of motion Lag = Lagrangian(N, pP) LM = LagrangesMethod(Lag, [q1, q2], hol_coneqs=f_c, forcelist=[(P, m*g*N.x)], frame=N) LM.form_lagranges_equations() # Compose operating point op_point = {q1: L, q2: 0, q1d: 0, q2d: 0, q1d.diff(t): 0, q2d.diff(t): 0} # Solve for multiplier operating point lam_op = LM.solve_multipliers(op_point=op_point) op_point.update(lam_op) # Perform the Linearization A, B, inp_vec = LM.linearize([q2], [q2d], [q1], [q1d], op_point=op_point, A_and_B=True) assert _simplify_matrix(A) == Matrix([[0, 1], [-9.8/L, 0]]) assert B == Matrix([]) def test_linearize_rolling_disc_lagrange(): q1, q2, q3 = q = dynamicsymbols('q1 q2 q3') q1d, q2d, q3d = qd = dynamicsymbols('q1 q2 q3', 1) r, m, g = symbols('r m g') N = ReferenceFrame('N') Y = N.orientnew('Y', 'Axis', [q1, N.z]) L = Y.orientnew('L', 'Axis', [q2, Y.x]) R = L.orientnew('R', 'Axis', [q3, L.y]) C = Point('C') C.set_vel(N, 0) Dmc = C.locatenew('Dmc', r * L.z) Dmc.v2pt_theory(C, N, R) I = inertia(L, m / 4 * r**2, m / 2 * r**2, m / 4 * r**2) BodyD = RigidBody('BodyD', Dmc, R, m, (I, Dmc)) BodyD.potential_energy = - m * g * r * cos(q2) Lag = Lagrangian(N, BodyD) l = LagrangesMethod(Lag, q) l.form_lagranges_equations() # Linearize about steady-state upright rolling op_point = {q1: 0, q2: 0, q3: 0, q1d: 0, q2d: 0, q1d.diff(): 0, q2d.diff(): 0, q3d.diff(): 0} A = l.linearize(q_ind=q, qd_ind=qd, op_point=op_point, A_and_B=True)[0] sol = Matrix([[0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1], [0, 0, 0, 0, -6*q3d, 0], [0, -4*g/(5*r), 0, 6*q3d/5, 0, 0], [0, 0, 0, 0, 0, 0]]) assert A == sol sympy-sympy-1.9/sympy/physics/mechanics/tests/test_method.py000066400000000000000000000002321412543434000245500ustar00rootroot00000000000000from sympy.physics.mechanics.method import _Methods from sympy.testing.pytest import raises def test_method(): raises(TypeError, lambda: _Methods()) sympy-sympy-1.9/sympy/physics/mechanics/tests/test_models.py000066400000000000000000000117211412543434000245600ustar00rootroot00000000000000import sympy.physics.mechanics.models as models from sympy.core.backend import (cos, sin, Matrix, symbols, zeros) from sympy import simplify from sympy.physics.mechanics import (dynamicsymbols) def test_multi_mass_spring_damper_inputs(): c0, k0, m0 = symbols("c0 k0 m0") g = symbols("g") v0, x0, f0 = dynamicsymbols("v0 x0 f0") kane1 = models.multi_mass_spring_damper(1) massmatrix1 = Matrix([[m0]]) forcing1 = Matrix([[-c0*v0 - k0*x0]]) assert simplify(massmatrix1 - kane1.mass_matrix) == Matrix([0]) assert simplify(forcing1 - kane1.forcing) == Matrix([0]) kane2 = models.multi_mass_spring_damper(1, True) massmatrix2 = Matrix([[m0]]) forcing2 = Matrix([[-c0*v0 + g*m0 - k0*x0]]) assert simplify(massmatrix2 - kane2.mass_matrix) == Matrix([0]) assert simplify(forcing2 - kane2.forcing) == Matrix([0]) kane3 = models.multi_mass_spring_damper(1, True, True) massmatrix3 = Matrix([[m0]]) forcing3 = Matrix([[-c0*v0 + g*m0 - k0*x0 + f0]]) assert simplify(massmatrix3 - kane3.mass_matrix) == Matrix([0]) assert simplify(forcing3 - kane3.forcing) == Matrix([0]) kane4 = models.multi_mass_spring_damper(1, False, True) massmatrix4 = Matrix([[m0]]) forcing4 = Matrix([[-c0*v0 - k0*x0 + f0]]) assert simplify(massmatrix4 - kane4.mass_matrix) == Matrix([0]) assert simplify(forcing4 - kane4.forcing) == Matrix([0]) def test_multi_mass_spring_damper_higher_order(): c0, k0, m0 = symbols("c0 k0 m0") c1, k1, m1 = symbols("c1 k1 m1") c2, k2, m2 = symbols("c2 k2 m2") v0, x0 = dynamicsymbols("v0 x0") v1, x1 = dynamicsymbols("v1 x1") v2, x2 = dynamicsymbols("v2 x2") kane1 = models.multi_mass_spring_damper(3) massmatrix1 = Matrix([[m0 + m1 + m2, m1 + m2, m2], [m1 + m2, m1 + m2, m2], [m2, m2, m2]]) forcing1 = Matrix([[-c0*v0 - k0*x0], [-c1*v1 - k1*x1], [-c2*v2 - k2*x2]]) assert simplify(massmatrix1 - kane1.mass_matrix) == zeros(3) assert simplify(forcing1 - kane1.forcing) == Matrix([0, 0, 0]) def test_n_link_pendulum_on_cart_inputs(): l0, m0 = symbols("l0 m0") m1 = symbols("m1") g = symbols("g") q0, q1, F, T1 = dynamicsymbols("q0 q1 F T1") u0, u1 = dynamicsymbols("u0 u1") kane1 = models.n_link_pendulum_on_cart(1) massmatrix1 = Matrix([[m0 + m1, -l0*m1*cos(q1)], [-l0*m1*cos(q1), l0**2*m1]]) forcing1 = Matrix([[-l0*m1*u1**2*sin(q1) + F], [g*l0*m1*sin(q1)]]) assert simplify(massmatrix1 - kane1.mass_matrix) == zeros(2) assert simplify(forcing1 - kane1.forcing) == Matrix([0, 0]) kane2 = models.n_link_pendulum_on_cart(1, False) massmatrix2 = Matrix([[m0 + m1, -l0*m1*cos(q1)], [-l0*m1*cos(q1), l0**2*m1]]) forcing2 = Matrix([[-l0*m1*u1**2*sin(q1)], [g*l0*m1*sin(q1)]]) assert simplify(massmatrix2 - kane2.mass_matrix) == zeros(2) assert simplify(forcing2 - kane2.forcing) == Matrix([0, 0]) kane3 = models.n_link_pendulum_on_cart(1, False, True) massmatrix3 = Matrix([[m0 + m1, -l0*m1*cos(q1)], [-l0*m1*cos(q1), l0**2*m1]]) forcing3 = Matrix([[-l0*m1*u1**2*sin(q1)], [g*l0*m1*sin(q1) + T1]]) assert simplify(massmatrix3 - kane3.mass_matrix) == zeros(2) assert simplify(forcing3 - kane3.forcing) == Matrix([0, 0]) kane4 = models.n_link_pendulum_on_cart(1, True, False) massmatrix4 = Matrix([[m0 + m1, -l0*m1*cos(q1)], [-l0*m1*cos(q1), l0**2*m1]]) forcing4 = Matrix([[-l0*m1*u1**2*sin(q1) + F], [g*l0*m1*sin(q1)]]) assert simplify(massmatrix4 - kane4.mass_matrix) == zeros(2) assert simplify(forcing4 - kane4.forcing) == Matrix([0, 0]) def test_n_link_pendulum_on_cart_higher_order(): l0, m0 = symbols("l0 m0") l1, m1 = symbols("l1 m1") m2 = symbols("m2") g = symbols("g") q0, q1, q2 = dynamicsymbols("q0 q1 q2") u0, u1, u2 = dynamicsymbols("u0 u1 u2") F, T1 = dynamicsymbols("F T1") kane1 = models.n_link_pendulum_on_cart(2) massmatrix1 = Matrix([[m0 + m1 + m2, -l0*m1*cos(q1) - l0*m2*cos(q1), -l1*m2*cos(q2)], [-l0*m1*cos(q1) - l0*m2*cos(q1), l0**2*m1 + l0**2*m2, l0*l1*m2*(sin(q1)*sin(q2) + cos(q1)*cos(q2))], [-l1*m2*cos(q2), l0*l1*m2*(sin(q1)*sin(q2) + cos(q1)*cos(q2)), l1**2*m2]]) forcing1 = Matrix([[-l0*m1*u1**2*sin(q1) - l0*m2*u1**2*sin(q1) - l1*m2*u2**2*sin(q2) + F], [g*l0*m1*sin(q1) + g*l0*m2*sin(q1) - l0*l1*m2*(sin(q1)*cos(q2) - sin(q2)*cos(q1))*u2**2], [g*l1*m2*sin(q2) - l0*l1*m2*(-sin(q1)*cos(q2) + sin(q2)*cos(q1))*u1**2]]) assert simplify(massmatrix1 - kane1.mass_matrix) == zeros(3) assert simplify(forcing1 - kane1.forcing) == Matrix([0, 0, 0]) sympy-sympy-1.9/sympy/physics/mechanics/tests/test_particle.py000066400000000000000000000036001412543434000250750ustar00rootroot00000000000000from sympy import symbols from sympy.physics.mechanics import Point, Particle, ReferenceFrame, inertia from sympy.testing.pytest import raises def test_particle(): m, m2, v1, v2, v3, r, g, h = symbols('m m2 v1 v2 v3 r g h') P = Point('P') P2 = Point('P2') p = Particle('pa', P, m) assert p.__str__() == 'pa' assert p.mass == m assert p.point == P # Test the mass setter p.mass = m2 assert p.mass == m2 # Test the point setter p.point = P2 assert p.point == P2 # Test the linear momentum function N = ReferenceFrame('N') O = Point('O') P2.set_pos(O, r * N.y) P2.set_vel(N, v1 * N.x) raises(TypeError, lambda: Particle(P, P, m)) raises(TypeError, lambda: Particle('pa', m, m)) assert p.linear_momentum(N) == m2 * v1 * N.x assert p.angular_momentum(O, N) == -m2 * r *v1 * N.z P2.set_vel(N, v2 * N.y) assert p.linear_momentum(N) == m2 * v2 * N.y assert p.angular_momentum(O, N) == 0 P2.set_vel(N, v3 * N.z) assert p.linear_momentum(N) == m2 * v3 * N.z assert p.angular_momentum(O, N) == m2 * r * v3 * N.x P2.set_vel(N, v1 * N.x + v2 * N.y + v3 * N.z) assert p.linear_momentum(N) == m2 * (v1 * N.x + v2 * N.y + v3 * N.z) assert p.angular_momentum(O, N) == m2 * r * (v3 * N.x - v1 * N.z) p.potential_energy = m * g * h assert p.potential_energy == m * g * h # TODO make the result not be system-dependent assert p.kinetic_energy( N) in [m2*(v1**2 + v2**2 + v3**2)/2, m2 * v1**2 / 2 + m2 * v2**2 / 2 + m2 * v3**2 / 2] def test_parallel_axis(): N = ReferenceFrame('N') m, a, b = symbols('m, a, b') o = Point('o') p = o.locatenew('p', a * N.x + b * N.y) P = Particle('P', o, m) Ip = P.parallel_axis(p, N) Ip_expected = inertia(N, m * b**2, m * a**2, m * (a**2 + b**2), ixy=-m * a * b) assert Ip == Ip_expected sympy-sympy-1.9/sympy/physics/mechanics/tests/test_rigidbody.py000066400000000000000000000077251412543434000252620ustar00rootroot00000000000000from sympy import symbols from sympy.physics.mechanics import Point, ReferenceFrame, Dyadic, RigidBody from sympy.physics.mechanics import dynamicsymbols, outer, inertia from sympy.physics.mechanics import inertia_of_point_mass from sympy.core.backend import expand from sympy.testing.pytest import raises def test_rigidbody(): m, m2, v1, v2, v3, omega = symbols('m m2 v1 v2 v3 omega') A = ReferenceFrame('A') A2 = ReferenceFrame('A2') P = Point('P') P2 = Point('P2') I = Dyadic(0) I2 = Dyadic(0) B = RigidBody('B', P, A, m, (I, P)) assert B.mass == m assert B.frame == A assert B.masscenter == P assert B.inertia == (I, B.masscenter) B.mass = m2 B.frame = A2 B.masscenter = P2 B.inertia = (I2, B.masscenter) raises(TypeError, lambda: RigidBody(P, P, A, m, (I, P))) raises(TypeError, lambda: RigidBody('B', P, P, m, (I, P))) raises(TypeError, lambda: RigidBody('B', P, A, m, (P, P))) raises(TypeError, lambda: RigidBody('B', P, A, m, (I, I))) assert B.__str__() == 'B' assert B.mass == m2 assert B.frame == A2 assert B.masscenter == P2 assert B.inertia == (I2, B.masscenter) assert B.masscenter == P2 assert B.inertia == (I2, B.masscenter) # Testing linear momentum function assuming A2 is the inertial frame N = ReferenceFrame('N') P2.set_vel(N, v1 * N.x + v2 * N.y + v3 * N.z) assert B.linear_momentum(N) == m2 * (v1 * N.x + v2 * N.y + v3 * N.z) def test_rigidbody2(): M, v, r, omega, g, h = dynamicsymbols('M v r omega g h') N = ReferenceFrame('N') b = ReferenceFrame('b') b.set_ang_vel(N, omega * b.x) P = Point('P') I = outer(b.x, b.x) Inertia_tuple = (I, P) B = RigidBody('B', P, b, M, Inertia_tuple) P.set_vel(N, v * b.x) assert B.angular_momentum(P, N) == omega * b.x O = Point('O') O.set_vel(N, v * b.x) P.set_pos(O, r * b.y) assert B.angular_momentum(O, N) == omega * b.x - M*v*r*b.z B.potential_energy = M * g * h assert B.potential_energy == M * g * h assert expand(2 * B.kinetic_energy(N)) == omega**2 + M * v**2 def test_rigidbody3(): q1, q2, q3, q4 = dynamicsymbols('q1:5') p1, p2, p3 = symbols('p1:4') m = symbols('m') A = ReferenceFrame('A') B = A.orientnew('B', 'axis', [q1, A.x]) O = Point('O') O.set_vel(A, q2*A.x + q3*A.y + q4*A.z) P = O.locatenew('P', p1*B.x + p2*B.y + p3*B.z) P.v2pt_theory(O, A, B) I = outer(B.x, B.x) rb1 = RigidBody('rb1', P, B, m, (I, P)) # I_S/O = I_S/S* + I_S*/O rb2 = RigidBody('rb2', P, B, m, (I + inertia_of_point_mass(m, P.pos_from(O), B), O)) assert rb1.central_inertia == rb2.central_inertia assert rb1.angular_momentum(O, A) == rb2.angular_momentum(O, A) def test_pendulum_angular_momentum(): """Consider a pendulum of length OA = 2a, of mass m as a rigid body of center of mass G (OG = a) which turn around (O,z). The angle between the reference frame R and the rod is q. The inertia of the body is I = (G,0,ma^2/3,ma^2/3). """ m, a = symbols('m, a') q = dynamicsymbols('q') R = ReferenceFrame('R') R1 = R.orientnew('R1', 'Axis', [q, R.z]) R1.set_ang_vel(R, q.diff() * R.z) I = inertia(R1, 0, m * a**2 / 3, m * a**2 / 3) O = Point('O') A = O.locatenew('A', 2*a * R1.x) G = O.locatenew('G', a * R1.x) S = RigidBody('S', G, R1, m, (I, G)) O.set_vel(R, 0) A.v2pt_theory(O, R, R1) G.v2pt_theory(O, R, R1) assert (4 * m * a**2 / 3 * q.diff() * R.z - S.angular_momentum(O, R).express(R)) == 0 def test_parallel_axis(): N = ReferenceFrame('N') m, Ix, Iy, Iz, a, b = symbols('m, I_x, I_y, I_z, a, b') Io = inertia(N, Ix, Iy, Iz) o = Point('o') p = o.locatenew('p', a * N.x + b * N.y) R = RigidBody('R', o, N, m, (Io, o)) Ip = R.parallel_axis(p) Ip_expected = inertia(N, Ix + m * b**2, Iy + m * a**2, Iz + m * (a**2 + b**2), ixy=-m * a * b) assert Ip == Ip_expected sympy-sympy-1.9/sympy/physics/mechanics/tests/test_system.py000066400000000000000000000207671412543434000246330ustar00rootroot00000000000000from sympy.core.backend import symbols, Matrix, atan, zeros from sympy import simplify from sympy.physics.mechanics import (dynamicsymbols, Particle, Point, ReferenceFrame, SymbolicSystem) from sympy.testing.pytest import raises # This class is going to be tested using a simple pendulum set up in x and y # coordinates x, y, u, v, lam = dynamicsymbols('x y u v lambda') m, l, g = symbols('m l g') # Set up the different forms the equations can take # [1] Explicit form where the kinematics and dynamics are combined # x' = F(x, t, r, p) # # [2] Implicit form where the kinematics and dynamics are combined # M(x, p) x' = F(x, t, r, p) # # [3] Implicit form where the kinematics and dynamics are separate # M(q, p) u' = F(q, u, t, r, p) # q' = G(q, u, t, r, p) dyn_implicit_mat = Matrix([[1, 0, -x/m], [0, 1, -y/m], [0, 0, l**2/m]]) dyn_implicit_rhs = Matrix([0, 0, u**2 + v**2 - g*y]) comb_implicit_mat = Matrix([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [0, 0, 1, 0, -x/m], [0, 0, 0, 1, -y/m], [0, 0, 0, 0, l**2/m]]) comb_implicit_rhs = Matrix([u, v, 0, 0, u**2 + v**2 - g*y]) kin_explicit_rhs = Matrix([u, v]) comb_explicit_rhs = comb_implicit_mat.LUsolve(comb_implicit_rhs) # Set up a body and load to pass into the system theta = atan(x/y) N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [theta, N.z]) O = Point('O') P = O.locatenew('P', l * A.x) Pa = Particle('Pa', P, m) bodies = [Pa] loads = [(P, g * m * N.x)] # Set up some output equations to be given to SymbolicSystem # Change to make these fit the pendulum PE = symbols("PE") out_eqns = {PE: m*g*(l+y)} # Set up remaining arguments that can be passed to SymbolicSystem alg_con = [2] alg_con_full = [4] coordinates = (x, y, lam) speeds = (u, v) states = (x, y, u, v, lam) coord_idxs = (0, 1) speed_idxs = (2, 3) def test_form_1(): symsystem1 = SymbolicSystem(states, comb_explicit_rhs, alg_con=alg_con_full, output_eqns=out_eqns, coord_idxs=coord_idxs, speed_idxs=speed_idxs, bodies=bodies, loads=loads) assert symsystem1.coordinates == Matrix([x, y]) assert symsystem1.speeds == Matrix([u, v]) assert symsystem1.states == Matrix([x, y, u, v, lam]) assert symsystem1.alg_con == [4] inter = comb_explicit_rhs assert simplify(symsystem1.comb_explicit_rhs - inter) == zeros(5, 1) assert set(symsystem1.dynamic_symbols()) == {y, v, lam, u, x} assert type(symsystem1.dynamic_symbols()) == tuple assert set(symsystem1.constant_symbols()) == {l, g, m} assert type(symsystem1.constant_symbols()) == tuple assert symsystem1.output_eqns == out_eqns assert symsystem1.bodies == (Pa,) assert symsystem1.loads == ((P, g * m * N.x),) def test_form_2(): symsystem2 = SymbolicSystem(coordinates, comb_implicit_rhs, speeds=speeds, mass_matrix=comb_implicit_mat, alg_con=alg_con_full, output_eqns=out_eqns, bodies=bodies, loads=loads) assert symsystem2.coordinates == Matrix([x, y, lam]) assert symsystem2.speeds == Matrix([u, v]) assert symsystem2.states == Matrix([x, y, lam, u, v]) assert symsystem2.alg_con == [4] inter = comb_implicit_rhs assert simplify(symsystem2.comb_implicit_rhs - inter) == zeros(5, 1) assert simplify(symsystem2.comb_implicit_mat-comb_implicit_mat) == zeros(5) assert set(symsystem2.dynamic_symbols()) == {y, v, lam, u, x} assert type(symsystem2.dynamic_symbols()) == tuple assert set(symsystem2.constant_symbols()) == {l, g, m} assert type(symsystem2.constant_symbols()) == tuple inter = comb_explicit_rhs symsystem2.compute_explicit_form() assert simplify(symsystem2.comb_explicit_rhs - inter) == zeros(5, 1) assert symsystem2.output_eqns == out_eqns assert symsystem2.bodies == (Pa,) assert symsystem2.loads == ((P, g * m * N.x),) def test_form_3(): symsystem3 = SymbolicSystem(states, dyn_implicit_rhs, mass_matrix=dyn_implicit_mat, coordinate_derivatives=kin_explicit_rhs, alg_con=alg_con, coord_idxs=coord_idxs, speed_idxs=speed_idxs, bodies=bodies, loads=loads) assert symsystem3.coordinates == Matrix([x, y]) assert symsystem3.speeds == Matrix([u, v]) assert symsystem3.states == Matrix([x, y, u, v, lam]) assert symsystem3.alg_con == [4] inter1 = kin_explicit_rhs inter2 = dyn_implicit_rhs assert simplify(symsystem3.kin_explicit_rhs - inter1) == zeros(2, 1) assert simplify(symsystem3.dyn_implicit_mat - dyn_implicit_mat) == zeros(3) assert simplify(symsystem3.dyn_implicit_rhs - inter2) == zeros(3, 1) inter = comb_implicit_rhs assert simplify(symsystem3.comb_implicit_rhs - inter) == zeros(5, 1) assert simplify(symsystem3.comb_implicit_mat-comb_implicit_mat) == zeros(5) inter = comb_explicit_rhs symsystem3.compute_explicit_form() assert simplify(symsystem3.comb_explicit_rhs - inter) == zeros(5, 1) assert set(symsystem3.dynamic_symbols()) == {y, v, lam, u, x} assert type(symsystem3.dynamic_symbols()) == tuple assert set(symsystem3.constant_symbols()) == {l, g, m} assert type(symsystem3.constant_symbols()) == tuple assert symsystem3.output_eqns == {} assert symsystem3.bodies == (Pa,) assert symsystem3.loads == ((P, g * m * N.x),) def test_property_attributes(): symsystem = SymbolicSystem(states, comb_explicit_rhs, alg_con=alg_con_full, output_eqns=out_eqns, coord_idxs=coord_idxs, speed_idxs=speed_idxs, bodies=bodies, loads=loads) with raises(AttributeError): symsystem.bodies = 42 with raises(AttributeError): symsystem.coordinates = 42 with raises(AttributeError): symsystem.dyn_implicit_rhs = 42 with raises(AttributeError): symsystem.comb_implicit_rhs = 42 with raises(AttributeError): symsystem.loads = 42 with raises(AttributeError): symsystem.dyn_implicit_mat = 42 with raises(AttributeError): symsystem.comb_implicit_mat = 42 with raises(AttributeError): symsystem.kin_explicit_rhs = 42 with raises(AttributeError): symsystem.comb_explicit_rhs = 42 with raises(AttributeError): symsystem.speeds = 42 with raises(AttributeError): symsystem.states = 42 with raises(AttributeError): symsystem.alg_con = 42 def test_not_specified_errors(): """This test will cover errors that arise from trying to access attributes that were not specified upon object creation or were specified on creation and the user tries to recalculate them.""" # Trying to access form 2 when form 1 given # Trying to access form 3 when form 2 given symsystem1 = SymbolicSystem(states, comb_explicit_rhs) with raises(AttributeError): symsystem1.comb_implicit_mat with raises(AttributeError): symsystem1.comb_implicit_rhs with raises(AttributeError): symsystem1.dyn_implicit_mat with raises(AttributeError): symsystem1.dyn_implicit_rhs with raises(AttributeError): symsystem1.kin_explicit_rhs with raises(AttributeError): symsystem1.compute_explicit_form() symsystem2 = SymbolicSystem(coordinates, comb_implicit_rhs, speeds=speeds, mass_matrix=comb_implicit_mat) with raises(AttributeError): symsystem2.dyn_implicit_mat with raises(AttributeError): symsystem2.dyn_implicit_rhs with raises(AttributeError): symsystem2.kin_explicit_rhs # Attribute error when trying to access coordinates and speeds when only the # states were given. with raises(AttributeError): symsystem1.coordinates with raises(AttributeError): symsystem1.speeds # Attribute error when trying to access bodies and loads when they are not # given with raises(AttributeError): symsystem1.bodies with raises(AttributeError): symsystem1.loads # Attribute error when trying to access comb_explicit_rhs before it was # calculated with raises(AttributeError): symsystem2.comb_explicit_rhs sympy-sympy-1.9/sympy/physics/optics/000077500000000000000000000000001412543434000200675ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/optics/__init__.py000066400000000000000000000031571412543434000222060ustar00rootroot00000000000000__all__ = [ 'TWave', 'RayTransferMatrix', 'FreeSpace', 'FlatRefraction', 'CurvedRefraction', 'FlatMirror', 'CurvedMirror', 'ThinLens', 'GeometricRay', 'BeamParameter', 'waist2rayleigh', 'rayleigh2waist', 'geometric_conj_ab', 'geometric_conj_af', 'geometric_conj_bf', 'gaussian_conj', 'conjugate_gauss_beams', 'Medium', 'refraction_angle', 'deviation', 'fresnel_coefficients', 'brewster_angle', 'critical_angle', 'lens_makers_formula', 'mirror_formula', 'lens_formula', 'hyperfocal_distance', 'transverse_magnification', 'jones_vector', 'stokes_vector', 'jones_2_stokes', 'linear_polarizer', 'phase_retarder', 'half_wave_retarder', 'quarter_wave_retarder', 'transmissive_filter', 'reflective_filter', 'mueller_matrix', 'polarizing_beam_splitter', ] from .waves import TWave from .gaussopt import (RayTransferMatrix, FreeSpace, FlatRefraction, CurvedRefraction, FlatMirror, CurvedMirror, ThinLens, GeometricRay, BeamParameter, waist2rayleigh, rayleigh2waist, geometric_conj_ab, geometric_conj_af, geometric_conj_bf, gaussian_conj, conjugate_gauss_beams) from .medium import Medium from .utils import (refraction_angle, deviation, fresnel_coefficients, brewster_angle, critical_angle, lens_makers_formula, mirror_formula, lens_formula, hyperfocal_distance, transverse_magnification) from .polarization import (jones_vector, stokes_vector, jones_2_stokes, linear_polarizer, phase_retarder, half_wave_retarder, quarter_wave_retarder, transmissive_filter, reflective_filter, mueller_matrix, polarizing_beam_splitter) sympy-sympy-1.9/sympy/physics/optics/gaussopt.py000066400000000000000000000475311412543434000223200ustar00rootroot00000000000000""" Gaussian optics. The module implements: - Ray transfer matrices for geometrical and gaussian optics. See RayTransferMatrix, GeometricRay and BeamParameter - Conjugation relations for geometrical and gaussian optics. See geometric_conj*, gauss_conj and conjugate_gauss_beams The conventions for the distances are as follows: focal distance positive for convergent lenses object distance positive for real objects image distance positive for real images """ __all__ = [ 'RayTransferMatrix', 'FreeSpace', 'FlatRefraction', 'CurvedRefraction', 'FlatMirror', 'CurvedMirror', 'ThinLens', 'GeometricRay', 'BeamParameter', 'waist2rayleigh', 'rayleigh2waist', 'geometric_conj_ab', 'geometric_conj_af', 'geometric_conj_bf', 'gaussian_conj', 'conjugate_gauss_beams', ] from sympy import (atan2, Expr, I, im, Matrix, pi, re, sqrt, sympify, together, MutableDenseMatrix) from sympy.utilities.misc import filldedent ### # A, B, C, D matrices ### class RayTransferMatrix(MutableDenseMatrix): """ Base class for a Ray Transfer Matrix. It should be used if there isn't already a more specific subclass mentioned in See Also. Parameters ========== parameters : A, B, C and D or 2x2 matrix (Matrix(2, 2, [A, B, C, D])) Examples ======== >>> from sympy.physics.optics import RayTransferMatrix, ThinLens >>> from sympy import Symbol, Matrix >>> mat = RayTransferMatrix(1, 2, 3, 4) >>> mat Matrix([ [1, 2], [3, 4]]) >>> RayTransferMatrix(Matrix([[1, 2], [3, 4]])) Matrix([ [1, 2], [3, 4]]) >>> mat.A 1 >>> f = Symbol('f') >>> lens = ThinLens(f) >>> lens Matrix([ [ 1, 0], [-1/f, 1]]) >>> lens.C -1/f See Also ======== GeometricRay, BeamParameter, FreeSpace, FlatRefraction, CurvedRefraction, FlatMirror, CurvedMirror, ThinLens References ========== .. [1] https://en.wikipedia.org/wiki/Ray_transfer_matrix_analysis """ def __new__(cls, *args): if len(args) == 4: temp = ((args[0], args[1]), (args[2], args[3])) elif len(args) == 1 \ and isinstance(args[0], Matrix) \ and args[0].shape == (2, 2): temp = args[0] else: raise ValueError(filldedent(''' Expecting 2x2 Matrix or the 4 elements of the Matrix but got %s''' % str(args))) return Matrix.__new__(cls, temp) def __mul__(self, other): if isinstance(other, RayTransferMatrix): return RayTransferMatrix(Matrix.__mul__(self, other)) elif isinstance(other, GeometricRay): return GeometricRay(Matrix.__mul__(self, other)) elif isinstance(other, BeamParameter): temp = self*Matrix(((other.q,), (1,))) q = (temp[0]/temp[1]).expand(complex=True) return BeamParameter(other.wavelen, together(re(q)), z_r=together(im(q))) else: return Matrix.__mul__(self, other) @property def A(self): """ The A parameter of the Matrix. Examples ======== >>> from sympy.physics.optics import RayTransferMatrix >>> mat = RayTransferMatrix(1, 2, 3, 4) >>> mat.A 1 """ return self[0, 0] @property def B(self): """ The B parameter of the Matrix. Examples ======== >>> from sympy.physics.optics import RayTransferMatrix >>> mat = RayTransferMatrix(1, 2, 3, 4) >>> mat.B 2 """ return self[0, 1] @property def C(self): """ The C parameter of the Matrix. Examples ======== >>> from sympy.physics.optics import RayTransferMatrix >>> mat = RayTransferMatrix(1, 2, 3, 4) >>> mat.C 3 """ return self[1, 0] @property def D(self): """ The D parameter of the Matrix. Examples ======== >>> from sympy.physics.optics import RayTransferMatrix >>> mat = RayTransferMatrix(1, 2, 3, 4) >>> mat.D 4 """ return self[1, 1] class FreeSpace(RayTransferMatrix): """ Ray Transfer Matrix for free space. Parameters ========== distance See Also ======== RayTransferMatrix Examples ======== >>> from sympy.physics.optics import FreeSpace >>> from sympy import symbols >>> d = symbols('d') >>> FreeSpace(d) Matrix([ [1, d], [0, 1]]) """ def __new__(cls, d): return RayTransferMatrix.__new__(cls, 1, d, 0, 1) class FlatRefraction(RayTransferMatrix): """ Ray Transfer Matrix for refraction. Parameters ========== n1 : Refractive index of one medium. n2 : Refractive index of other medium. See Also ======== RayTransferMatrix Examples ======== >>> from sympy.physics.optics import FlatRefraction >>> from sympy import symbols >>> n1, n2 = symbols('n1 n2') >>> FlatRefraction(n1, n2) Matrix([ [1, 0], [0, n1/n2]]) """ def __new__(cls, n1, n2): n1, n2 = map(sympify, (n1, n2)) return RayTransferMatrix.__new__(cls, 1, 0, 0, n1/n2) class CurvedRefraction(RayTransferMatrix): """ Ray Transfer Matrix for refraction on curved interface. Parameters ========== R : Radius of curvature (positive for concave). n1 : Refractive index of one medium. n2 : Refractive index of other medium. See Also ======== RayTransferMatrix Examples ======== >>> from sympy.physics.optics import CurvedRefraction >>> from sympy import symbols >>> R, n1, n2 = symbols('R n1 n2') >>> CurvedRefraction(R, n1, n2) Matrix([ [ 1, 0], [(n1 - n2)/(R*n2), n1/n2]]) """ def __new__(cls, R, n1, n2): R, n1, n2 = map(sympify, (R, n1, n2)) return RayTransferMatrix.__new__(cls, 1, 0, (n1 - n2)/R/n2, n1/n2) class FlatMirror(RayTransferMatrix): """ Ray Transfer Matrix for reflection. See Also ======== RayTransferMatrix Examples ======== >>> from sympy.physics.optics import FlatMirror >>> FlatMirror() Matrix([ [1, 0], [0, 1]]) """ def __new__(cls): return RayTransferMatrix.__new__(cls, 1, 0, 0, 1) class CurvedMirror(RayTransferMatrix): """ Ray Transfer Matrix for reflection from curved surface. Parameters ========== R : radius of curvature (positive for concave) See Also ======== RayTransferMatrix Examples ======== >>> from sympy.physics.optics import CurvedMirror >>> from sympy import symbols >>> R = symbols('R') >>> CurvedMirror(R) Matrix([ [ 1, 0], [-2/R, 1]]) """ def __new__(cls, R): R = sympify(R) return RayTransferMatrix.__new__(cls, 1, 0, -2/R, 1) class ThinLens(RayTransferMatrix): """ Ray Transfer Matrix for a thin lens. Parameters ========== f : The focal distance. See Also ======== RayTransferMatrix Examples ======== >>> from sympy.physics.optics import ThinLens >>> from sympy import symbols >>> f = symbols('f') >>> ThinLens(f) Matrix([ [ 1, 0], [-1/f, 1]]) """ def __new__(cls, f): f = sympify(f) return RayTransferMatrix.__new__(cls, 1, 0, -1/f, 1) ### # Representation for geometric ray ### class GeometricRay(MutableDenseMatrix): """ Representation for a geometric ray in the Ray Transfer Matrix formalism. Parameters ========== h : height, and angle : angle, or matrix : a 2x1 matrix (Matrix(2, 1, [height, angle])) Examples ======== >>> from sympy.physics.optics import GeometricRay, FreeSpace >>> from sympy import symbols, Matrix >>> d, h, angle = symbols('d, h, angle') >>> GeometricRay(h, angle) Matrix([ [ h], [angle]]) >>> FreeSpace(d)*GeometricRay(h, angle) Matrix([ [angle*d + h], [ angle]]) >>> GeometricRay( Matrix( ((h,), (angle,)) ) ) Matrix([ [ h], [angle]]) See Also ======== RayTransferMatrix """ def __new__(cls, *args): if len(args) == 1 and isinstance(args[0], Matrix) \ and args[0].shape == (2, 1): temp = args[0] elif len(args) == 2: temp = ((args[0],), (args[1],)) else: raise ValueError(filldedent(''' Expecting 2x1 Matrix or the 2 elements of the Matrix but got %s''' % str(args))) return Matrix.__new__(cls, temp) @property def height(self): """ The distance from the optical axis. Examples ======== >>> from sympy.physics.optics import GeometricRay >>> from sympy import symbols >>> h, angle = symbols('h, angle') >>> gRay = GeometricRay(h, angle) >>> gRay.height h """ return self[0] @property def angle(self): """ The angle with the optical axis. Examples ======== >>> from sympy.physics.optics import GeometricRay >>> from sympy import symbols >>> h, angle = symbols('h, angle') >>> gRay = GeometricRay(h, angle) >>> gRay.angle angle """ return self[1] ### # Representation for gauss beam ### class BeamParameter(Expr): """ Representation for a gaussian ray in the Ray Transfer Matrix formalism. Parameters ========== wavelen : the wavelength, z : the distance to waist, and w : the waist, or z_r : the rayleigh range. Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.q 1 + 1.88679245283019*I*pi >>> p.q.n() 1.0 + 5.92753330865999*I >>> p.w_0.n() 0.00100000000000000 >>> p.z_r.n() 5.92753330865999 >>> from sympy.physics.optics import FreeSpace >>> fs = FreeSpace(10) >>> p1 = fs*p >>> p.w.n() 0.00101413072159615 >>> p1.w.n() 0.00210803120913829 See Also ======== RayTransferMatrix References ========== .. [1] https://en.wikipedia.org/wiki/Complex_beam_parameter .. [2] https://en.wikipedia.org/wiki/Gaussian_beam """ #TODO A class Complex may be implemented. The BeamParameter may # subclass it. See: # https://groups.google.com/d/topic/sympy/7XkU07NRBEs/discussion def __new__(cls, wavelen, z, z_r=None, w=None): wavelen = sympify(wavelen) z = sympify(z) if z_r is not None and w is None: z_r = sympify(z_r) elif w is not None and z_r is None: z_r = waist2rayleigh(sympify(w), wavelen) else: raise ValueError('Constructor expects exactly one named argument.') return Expr.__new__(cls, wavelen, z, z_r) @property def wavelen(self): return self.args[0] @property def z(self): return self.args[1] @property def z_r(self): return self.args[2] @property def q(self): """ The complex parameter representing the beam. Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.q 1 + 1.88679245283019*I*pi """ return self.z + I*self.z_r @property def radius(self): """ The radius of curvature of the phase front. Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.radius 1 + 3.55998576005696*pi**2 """ return self.z*(1 + (self.z_r/self.z)**2) @property def w(self): """ The beam radius at `1/e^2` intensity. See Also ======== w_0 : The minimal radius of beam. Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.w 0.001*sqrt(0.2809/pi**2 + 1) """ return self.w_0*sqrt(1 + (self.z/self.z_r)**2) @property def w_0(self): """ The beam waist (minimal radius). See Also ======== w : the beam radius at `1/e^2` intensity Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.w_0 0.00100000000000000 """ return sqrt(self.z_r/pi*self.wavelen) @property def divergence(self): """ Half of the total angular spread. Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.divergence 0.00053/pi """ return self.wavelen/pi/self.w_0 @property def gouy(self): """ The Gouy phase. Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.gouy atan(0.53/pi) """ return atan2(self.z, self.z_r) @property def waist_approximation_limit(self): """ The minimal waist for which the gauss beam approximation is valid. Explanation =========== The gauss beam is a solution to the paraxial equation. For curvatures that are too great it is not a valid approximation. Examples ======== >>> from sympy.physics.optics import BeamParameter >>> p = BeamParameter(530e-9, 1, w=1e-3) >>> p.waist_approximation_limit 1.06e-6/pi """ return 2*self.wavelen/pi ### # Utilities ### def waist2rayleigh(w, wavelen): """ Calculate the rayleigh range from the waist of a gaussian beam. See Also ======== rayleigh2waist, BeamParameter Examples ======== >>> from sympy.physics.optics import waist2rayleigh >>> from sympy import symbols >>> w, wavelen = symbols('w wavelen') >>> waist2rayleigh(w, wavelen) pi*w**2/wavelen """ w, wavelen = map(sympify, (w, wavelen)) return w**2*pi/wavelen def rayleigh2waist(z_r, wavelen): """Calculate the waist from the rayleigh range of a gaussian beam. See Also ======== waist2rayleigh, BeamParameter Examples ======== >>> from sympy.physics.optics import rayleigh2waist >>> from sympy import symbols >>> z_r, wavelen = symbols('z_r wavelen') >>> rayleigh2waist(z_r, wavelen) sqrt(wavelen*z_r)/sqrt(pi) """ z_r, wavelen = map(sympify, (z_r, wavelen)) return sqrt(z_r/pi*wavelen) def geometric_conj_ab(a, b): """ Conjugation relation for geometrical beams under paraxial conditions. Explanation =========== Takes the distances to the optical element and returns the needed focal distance. See Also ======== geometric_conj_af, geometric_conj_bf Examples ======== >>> from sympy.physics.optics import geometric_conj_ab >>> from sympy import symbols >>> a, b = symbols('a b') >>> geometric_conj_ab(a, b) a*b/(a + b) """ a, b = map(sympify, (a, b)) if a.is_infinite or b.is_infinite: return a if b.is_infinite else b else: return a*b/(a + b) def geometric_conj_af(a, f): """ Conjugation relation for geometrical beams under paraxial conditions. Explanation =========== Takes the object distance (for geometric_conj_af) or the image distance (for geometric_conj_bf) to the optical element and the focal distance. Then it returns the other distance needed for conjugation. See Also ======== geometric_conj_ab Examples ======== >>> from sympy.physics.optics.gaussopt import geometric_conj_af, geometric_conj_bf >>> from sympy import symbols >>> a, b, f = symbols('a b f') >>> geometric_conj_af(a, f) a*f/(a - f) >>> geometric_conj_bf(b, f) b*f/(b - f) """ a, f = map(sympify, (a, f)) return -geometric_conj_ab(a, -f) geometric_conj_bf = geometric_conj_af def gaussian_conj(s_in, z_r_in, f): """ Conjugation relation for gaussian beams. Parameters ========== s_in : The distance to optical element from the waist. z_r_in : The rayleigh range of the incident beam. f : The focal length of the optical element. Returns ======= a tuple containing (s_out, z_r_out, m) s_out : The distance between the new waist and the optical element. z_r_out : The rayleigh range of the emergent beam. m : The ration between the new and the old waists. Examples ======== >>> from sympy.physics.optics import gaussian_conj >>> from sympy import symbols >>> s_in, z_r_in, f = symbols('s_in z_r_in f') >>> gaussian_conj(s_in, z_r_in, f)[0] 1/(-1/(s_in + z_r_in**2/(-f + s_in)) + 1/f) >>> gaussian_conj(s_in, z_r_in, f)[1] z_r_in/(1 - s_in**2/f**2 + z_r_in**2/f**2) >>> gaussian_conj(s_in, z_r_in, f)[2] 1/sqrt(1 - s_in**2/f**2 + z_r_in**2/f**2) """ s_in, z_r_in, f = map(sympify, (s_in, z_r_in, f)) s_out = 1 / ( -1/(s_in + z_r_in**2/(s_in - f)) + 1/f ) m = 1/sqrt((1 - (s_in/f)**2) + (z_r_in/f)**2) z_r_out = z_r_in / ((1 - (s_in/f)**2) + (z_r_in/f)**2) return (s_out, z_r_out, m) def conjugate_gauss_beams(wavelen, waist_in, waist_out, **kwargs): """ Find the optical setup conjugating the object/image waists. Parameters ========== wavelen : The wavelength of the beam. waist_in and waist_out : The waists to be conjugated. f : The focal distance of the element used in the conjugation. Returns ======= a tuple containing (s_in, s_out, f) s_in : The distance before the optical element. s_out : The distance after the optical element. f : The focal distance of the optical element. Examples ======== >>> from sympy.physics.optics import conjugate_gauss_beams >>> from sympy import symbols, factor >>> l, w_i, w_o, f = symbols('l w_i w_o f') >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[0] f*(1 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2))) >>> factor(conjugate_gauss_beams(l, w_i, w_o, f=f)[1]) f*w_o**2*(w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)))/w_i**2 >>> conjugate_gauss_beams(l, w_i, w_o, f=f)[2] f """ #TODO add the other possible arguments wavelen, waist_in, waist_out = map(sympify, (wavelen, waist_in, waist_out)) m = waist_out / waist_in z = waist2rayleigh(waist_in, wavelen) if len(kwargs) != 1: raise ValueError("The function expects only one named argument") elif 'dist' in kwargs: raise NotImplementedError(filldedent(''' Currently only focal length is supported as a parameter''')) elif 'f' in kwargs: f = sympify(kwargs['f']) s_in = f * (1 - sqrt(1/m**2 - z**2/f**2)) s_out = gaussian_conj(s_in, z, f)[0] elif 's_in' in kwargs: raise NotImplementedError(filldedent(''' Currently only focal length is supported as a parameter''')) else: raise ValueError(filldedent(''' The functions expects the focal length as a named argument''')) return (s_in, s_out, f) #TODO #def plot_beam(): # """Plot the beam radius as it propagates in space.""" # pass #TODO #def plot_beam_conjugation(): # """ # Plot the intersection of two beams. # # Represents the conjugation relation. # # See Also # ======== # # conjugate_gauss_beams # """ # pass sympy-sympy-1.9/sympy/physics/optics/medium.py000066400000000000000000000126451412543434000217310ustar00rootroot00000000000000""" **Contains** * Medium """ from sympy.physics.units import second, meter, kilogram, ampere __all__ = ['Medium'] from sympy import Symbol, sympify, sqrt from sympy.physics.units import speed_of_light, u0, e0 c = speed_of_light.convert_to(meter/second) _e0mksa = e0.convert_to(ampere**2*second**4/(kilogram*meter**3)) _u0mksa = u0.convert_to(meter*kilogram/(ampere**2*second**2)) class Medium(Symbol): """ This class represents an optical medium. The prime reason to implement this is to facilitate refraction, Fermat's principle, etc. Explanation =========== An optical medium is a material through which electromagnetic waves propagate. The permittivity and permeability of the medium define how electromagnetic waves propagate in it. Parameters ========== name: string The display name of the Medium. permittivity: Sympifyable Electric permittivity of the space. permeability: Sympifyable Magnetic permeability of the space. n: Sympifyable Index of refraction of the medium. Examples ======== >>> from sympy.abc import epsilon, mu >>> from sympy.physics.optics import Medium >>> m1 = Medium('m1') >>> m2 = Medium('m2', epsilon, mu) >>> m1.intrinsic_impedance 149896229*pi*kilogram*meter**2/(1250000*ampere**2*second**3) >>> m2.refractive_index 299792458*meter*sqrt(epsilon*mu)/second References ========== .. [1] https://en.wikipedia.org/wiki/Optical_medium """ def __new__(cls, name, permittivity=None, permeability=None, n=None): obj = super().__new__(cls, name) obj._permittivity = sympify(permittivity) obj._permeability = sympify(permeability) obj._n = sympify(n) if n is not None: if permittivity is not None and permeability is None: obj._permeability = n**2/(c**2*obj._permittivity) if permeability is not None and permittivity is None: obj._permittivity = n**2/(c**2*obj._permeability) if permittivity is not None and permittivity is not None: if abs(n - c*sqrt(obj._permittivity*obj._permeability)) > 1e-6: raise ValueError("Values are not consistent.") elif permittivity is not None and permeability is not None: obj._n = c*sqrt(permittivity*permeability) elif permittivity is None and permeability is None: obj._permittivity = _e0mksa obj._permeability = _u0mksa return obj @property def intrinsic_impedance(self): """ Returns intrinsic impedance of the medium. Explanation =========== The intrinsic impedance of a medium is the ratio of the transverse components of the electric and magnetic fields of the electromagnetic wave travelling in the medium. In a region with no electrical conductivity it simplifies to the square root of ratio of magnetic permeability to electric permittivity. Examples ======== >>> from sympy.physics.optics import Medium >>> m = Medium('m') >>> m.intrinsic_impedance 149896229*pi*kilogram*meter**2/(1250000*ampere**2*second**3) """ return sqrt(self._permeability/self._permittivity) @property def speed(self): """ Returns speed of the electromagnetic wave travelling in the medium. Examples ======== >>> from sympy.physics.optics import Medium >>> m = Medium('m') >>> m.speed 299792458*meter/second >>> m2 = Medium('m2', n=1) >>> m.speed == m2.speed True """ if self._permittivity is not None and self._permeability is not None: return 1/sqrt(self._permittivity*self._permeability) else: return c/self._n @property def refractive_index(self): """ Returns refractive index of the medium. Examples ======== >>> from sympy.physics.optics import Medium >>> m = Medium('m') >>> m.refractive_index 1 """ return (c/self.speed) @property def permittivity(self): """ Returns electric permittivity of the medium. Examples ======== >>> from sympy.physics.optics import Medium >>> m = Medium('m') >>> m.permittivity 625000*ampere**2*second**4/(22468879468420441*pi*kilogram*meter**3) """ return self._permittivity @property def permeability(self): """ Returns magnetic permeability of the medium. Examples ======== >>> from sympy.physics.optics import Medium >>> m = Medium('m') >>> m.permeability pi*kilogram*meter/(2500000*ampere**2*second**2) """ return self._permeability def __str__(self): from sympy.printing import sstr return type(self).__name__ + ': ' + sstr([self._permittivity, self._permeability, self._n]) def __lt__(self, other): """ Compares based on refractive index of the medium. """ return self.refractive_index < other.refractive_index def __gt__(self, other): return not self < other def __eq__(self, other): return self.refractive_index == other.refractive_index def __ne__(self, other): return not self == other sympy-sympy-1.9/sympy/physics/optics/polarization.py000066400000000000000000000513211412543434000231560ustar00rootroot00000000000000#!/usr/bin/env python # -*- coding: utf-8 -*- """ The module implements routines to model the polarization of optical fields and can be used to calculate the effects of polarization optical elements on the fields. - Jones vectors. - Stokes vectors. - Jones matrices. - Mueller matrices. Examples ======== We calculate a generic Jones vector: >>> from sympy import symbols, pprint, zeros, simplify >>> from sympy.physics.optics.polarization import (jones_vector, stokes_vector, ... half_wave_retarder, polarizing_beam_splitter, jones_2_stokes) >>> psi, chi, p, I0 = symbols("psi, chi, p, I0", real=True) >>> x0 = jones_vector(psi, chi) >>> pprint(x0, use_unicode=True) ⎡-ⅈ⋅sin(χ)⋅sin(ψ) + cos(χ)⋅cos(ψ)⎤ ⎢ ⎥ ⎣ⅈ⋅sin(χ)⋅cos(ψ) + sin(ψ)⋅cos(χ) ⎦ And the more general Stokes vector: >>> s0 = stokes_vector(psi, chi, p, I0) >>> pprint(s0, use_unicode=True) ⎡ I₀ ⎤ ⎢ ⎥ ⎢I₀⋅p⋅cos(2⋅χ)⋅cos(2⋅ψ)⎥ ⎢ ⎥ ⎢I₀⋅p⋅sin(2⋅ψ)⋅cos(2⋅χ)⎥ ⎢ ⎥ ⎣ I₀⋅p⋅sin(2⋅χ) ⎦ We calculate how the Jones vector is modified by a half-wave plate: >>> alpha = symbols("alpha", real=True) >>> HWP = half_wave_retarder(alpha) >>> x1 = simplify(HWP*x0) We calculate the very common operation of passing a beam through a half-wave plate and then through a polarizing beam-splitter. We do this by putting this Jones vector as the first entry of a two-Jones-vector state that is transformed by a 4x4 Jones matrix modelling the polarizing beam-splitter to get the transmitted and reflected Jones vectors: >>> PBS = polarizing_beam_splitter() >>> X1 = zeros(4, 1) >>> X1[:2, :] = x1 >>> X2 = PBS*X1 >>> transmitted_port = X2[:2, :] >>> reflected_port = X2[2:, :] This allows us to calculate how the power in both ports depends on the initial polarization: >>> transmitted_power = jones_2_stokes(transmitted_port)[0] >>> reflected_power = jones_2_stokes(reflected_port)[0] >>> print(transmitted_power) cos(-2*alpha + chi + psi)**2/2 + cos(2*alpha + chi - psi)**2/2 >>> print(reflected_power) sin(-2*alpha + chi + psi)**2/2 + sin(2*alpha + chi - psi)**2/2 Please see the description of the individual functions for further details and examples. References ========== .. [1] https://en.wikipedia.org/wiki/Jones_calculus .. [2] https://en.wikipedia.org/wiki/Mueller_calculus .. [3] https://en.wikipedia.org/wiki/Stokes_parameters """ from sympy import sin, cos, exp, I, pi, sqrt, Matrix, Abs, re, im, simplify from sympy.physics.quantum import TensorProduct def jones_vector(psi, chi): """A Jones vector corresponding to a polarization ellipse with `psi` tilt, and `chi` circularity. Parameters ========== ``psi`` : numeric type or sympy Symbol The tilt of the polarization relative to the `x` axis. ``chi`` : numeric type or sympy Symbol The angle adjacent to the mayor axis of the polarization ellipse. Returns ======= Matrix : A Jones vector. Examples ======== The axes on the Poincaré sphere. >>> from sympy import pprint, symbols, pi >>> from sympy.physics.optics.polarization import jones_vector >>> psi, chi = symbols("psi, chi", real=True) A general Jones vector. >>> pprint(jones_vector(psi, chi), use_unicode=True) ⎡-ⅈ⋅sin(χ)⋅sin(ψ) + cos(χ)⋅cos(ψ)⎤ ⎢ ⎥ ⎣ⅈ⋅sin(χ)⋅cos(ψ) + sin(ψ)⋅cos(χ) ⎦ Horizontal polarization. >>> pprint(jones_vector(0, 0), use_unicode=True) ⎡1⎤ ⎢ ⎥ ⎣0⎦ Vertical polarization. >>> pprint(jones_vector(pi/2, 0), use_unicode=True) ⎡0⎤ ⎢ ⎥ ⎣1⎦ Diagonal polarization. >>> pprint(jones_vector(pi/4, 0), use_unicode=True) ⎡√2⎤ ⎢──⎥ ⎢2 ⎥ ⎢ ⎥ ⎢√2⎥ ⎢──⎥ ⎣2 ⎦ Anti-diagonal polarization. >>> pprint(jones_vector(-pi/4, 0), use_unicode=True) ⎡ √2 ⎤ ⎢ ── ⎥ ⎢ 2 ⎥ ⎢ ⎥ ⎢-√2 ⎥ ⎢────⎥ ⎣ 2 ⎦ Right-hand circular polarization. >>> pprint(jones_vector(0, pi/4), use_unicode=True) ⎡ √2 ⎤ ⎢ ── ⎥ ⎢ 2 ⎥ ⎢ ⎥ ⎢√2⋅ⅈ⎥ ⎢────⎥ ⎣ 2 ⎦ Left-hand circular polarization. >>> pprint(jones_vector(0, -pi/4), use_unicode=True) ⎡ √2 ⎤ ⎢ ── ⎥ ⎢ 2 ⎥ ⎢ ⎥ ⎢-√2⋅ⅈ ⎥ ⎢──────⎥ ⎣ 2 ⎦ """ return Matrix([-I*sin(chi)*sin(psi) + cos(chi)*cos(psi), I*sin(chi)*cos(psi) + sin(psi)*cos(chi)]) def stokes_vector(psi, chi, p=1, I=1): """A Stokes vector corresponding to a polarization ellipse with ``psi`` tilt, and ``chi`` circularity. Parameters ========== ``psi`` : numeric type or sympy Symbol The tilt of the polarization relative to the ``x`` axis. ``chi`` : numeric type or sympy Symbol The angle adjacent to the mayor axis of the polarization ellipse. ``p`` : numeric type or sympy Symbol The degree of polarization. ``I`` : numeric type or sympy Symbol The intensity of the field. Returns ======= Matrix : A Stokes vector. Examples ======== The axes on the Poincaré sphere. >>> from sympy import pprint, symbols, pi >>> from sympy.physics.optics.polarization import stokes_vector >>> psi, chi, p, I = symbols("psi, chi, p, I", real=True) >>> pprint(stokes_vector(psi, chi, p, I), use_unicode=True) ⎡ I ⎤ ⎢ ⎥ ⎢I⋅p⋅cos(2⋅χ)⋅cos(2⋅ψ)⎥ ⎢ ⎥ ⎢I⋅p⋅sin(2⋅ψ)⋅cos(2⋅χ)⎥ ⎢ ⎥ ⎣ I⋅p⋅sin(2⋅χ) ⎦ Horizontal polarization >>> pprint(stokes_vector(0, 0), use_unicode=True) ⎡1⎤ ⎢ ⎥ ⎢1⎥ ⎢ ⎥ ⎢0⎥ ⎢ ⎥ ⎣0⎦ Vertical polarization >>> pprint(stokes_vector(pi/2, 0), use_unicode=True) ⎡1 ⎤ ⎢ ⎥ ⎢-1⎥ ⎢ ⎥ ⎢0 ⎥ ⎢ ⎥ ⎣0 ⎦ Diagonal polarization >>> pprint(stokes_vector(pi/4, 0), use_unicode=True) ⎡1⎤ ⎢ ⎥ ⎢0⎥ ⎢ ⎥ ⎢1⎥ ⎢ ⎥ ⎣0⎦ Anti-diagonal polarization >>> pprint(stokes_vector(-pi/4, 0), use_unicode=True) ⎡1 ⎤ ⎢ ⎥ ⎢0 ⎥ ⎢ ⎥ ⎢-1⎥ ⎢ ⎥ ⎣0 ⎦ Right-hand circular polarization >>> pprint(stokes_vector(0, pi/4), use_unicode=True) ⎡1⎤ ⎢ ⎥ ⎢0⎥ ⎢ ⎥ ⎢0⎥ ⎢ ⎥ ⎣1⎦ Left-hand circular polarization >>> pprint(stokes_vector(0, -pi/4), use_unicode=True) ⎡1 ⎤ ⎢ ⎥ ⎢0 ⎥ ⎢ ⎥ ⎢0 ⎥ ⎢ ⎥ ⎣-1⎦ Unpolarized light >>> pprint(stokes_vector(0, 0, 0), use_unicode=True) ⎡1⎤ ⎢ ⎥ ⎢0⎥ ⎢ ⎥ ⎢0⎥ ⎢ ⎥ ⎣0⎦ """ S0 = I S1 = I*p*cos(2*psi)*cos(2*chi) S2 = I*p*sin(2*psi)*cos(2*chi) S3 = I*p*sin(2*chi) return Matrix([S0, S1, S2, S3]) def jones_2_stokes(e): """Return the Stokes vector for a Jones vector `e`. Parameters ========== ``e`` : sympy Matrix A Jones vector. Returns ======= sympy Matrix A Jones vector. Examples ======== The axes on the Poincaré sphere. >>> from sympy import pprint, pi >>> from sympy.physics.optics.polarization import jones_vector >>> from sympy.physics.optics.polarization import jones_2_stokes >>> H = jones_vector(0, 0) >>> V = jones_vector(pi/2, 0) >>> D = jones_vector(pi/4, 0) >>> A = jones_vector(-pi/4, 0) >>> R = jones_vector(0, pi/4) >>> L = jones_vector(0, -pi/4) >>> pprint([jones_2_stokes(e) for e in [H, V, D, A, R, L]], ... use_unicode=True) ⎡⎡1⎤ ⎡1 ⎤ ⎡1⎤ ⎡1 ⎤ ⎡1⎤ ⎡1 ⎤⎤ ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ ⎢⎢1⎥ ⎢-1⎥ ⎢0⎥ ⎢0 ⎥ ⎢0⎥ ⎢0 ⎥⎥ ⎢⎢ ⎥, ⎢ ⎥, ⎢ ⎥, ⎢ ⎥, ⎢ ⎥, ⎢ ⎥⎥ ⎢⎢0⎥ ⎢0 ⎥ ⎢1⎥ ⎢-1⎥ ⎢0⎥ ⎢0 ⎥⎥ ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ ⎣⎣0⎦ ⎣0 ⎦ ⎣0⎦ ⎣0 ⎦ ⎣1⎦ ⎣-1⎦⎦ """ ex, ey = e return Matrix([Abs(ex)**2 + Abs(ey)**2, Abs(ex)**2 - Abs(ey)**2, 2*re(ex*ey.conjugate()), -2*im(ex*ey.conjugate())]) def linear_polarizer(theta=0): """A linear polarizer Jones matrix with transmission axis at an angle ``theta``. Parameters ========== ``theta`` : numeric type or sympy Symbol The angle of the transmission axis relative to the horizontal plane. Returns ======= sympy Matrix A Jones matrix representing the polarizer. Examples ======== A generic polarizer. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import linear_polarizer >>> theta = symbols("theta", real=True) >>> J = linear_polarizer(theta) >>> pprint(J, use_unicode=True) ⎡ 2 ⎤ ⎢ cos (θ) sin(θ)⋅cos(θ)⎥ ⎢ ⎥ ⎢ 2 ⎥ ⎣sin(θ)⋅cos(θ) sin (θ) ⎦ """ M = Matrix([[cos(theta)**2, sin(theta)*cos(theta)], [sin(theta)*cos(theta), sin(theta)**2]]) return M def phase_retarder(theta=0, delta=0): """A phase retarder Jones matrix with retardance `delta` at angle `theta`. Parameters ========== ``theta`` : numeric type or sympy Symbol The angle of the fast axis relative to the horizontal plane. ``delta`` : numeric type or sympy Symbol The phase difference between the fast and slow axes of the transmitted light. Returns ======= sympy Matrix : A Jones matrix representing the retarder. Examples ======== A generic retarder. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import phase_retarder >>> theta, delta = symbols("theta, delta", real=True) >>> R = phase_retarder(theta, delta) >>> pprint(R, use_unicode=True) ⎡ -ⅈ⋅δ -ⅈ⋅δ ⎤ ⎢ ───── ───── ⎥ ⎢⎛ ⅈ⋅δ 2 2 ⎞ 2 ⎛ ⅈ⋅δ⎞ 2 ⎥ ⎢⎝ℯ ⋅sin (θ) + cos (θ)⎠⋅ℯ ⎝1 - ℯ ⎠⋅ℯ ⋅sin(θ)⋅cos(θ)⎥ ⎢ ⎥ ⎢ -ⅈ⋅δ -ⅈ⋅δ ⎥ ⎢ ───── ─────⎥ ⎢⎛ ⅈ⋅δ⎞ 2 ⎛ ⅈ⋅δ 2 2 ⎞ 2 ⎥ ⎣⎝1 - ℯ ⎠⋅ℯ ⋅sin(θ)⋅cos(θ) ⎝ℯ ⋅cos (θ) + sin (θ)⎠⋅ℯ ⎦ """ R = Matrix([[cos(theta)**2 + exp(I*delta)*sin(theta)**2, (1-exp(I*delta))*cos(theta)*sin(theta)], [(1-exp(I*delta))*cos(theta)*sin(theta), sin(theta)**2 + exp(I*delta)*cos(theta)**2]]) return R*exp(-I*delta/2) def half_wave_retarder(theta): """A half-wave retarder Jones matrix at angle `theta`. Parameters ========== ``theta`` : numeric type or sympy Symbol The angle of the fast axis relative to the horizontal plane. Returns ======= sympy Matrix A Jones matrix representing the retarder. Examples ======== A generic half-wave plate. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import half_wave_retarder >>> theta= symbols("theta", real=True) >>> HWP = half_wave_retarder(theta) >>> pprint(HWP, use_unicode=True) ⎡ ⎛ 2 2 ⎞ ⎤ ⎢-ⅈ⋅⎝- sin (θ) + cos (θ)⎠ -2⋅ⅈ⋅sin(θ)⋅cos(θ) ⎥ ⎢ ⎥ ⎢ ⎛ 2 2 ⎞⎥ ⎣ -2⋅ⅈ⋅sin(θ)⋅cos(θ) -ⅈ⋅⎝sin (θ) - cos (θ)⎠⎦ """ return phase_retarder(theta, pi) def quarter_wave_retarder(theta): """A quarter-wave retarder Jones matrix at angle `theta`. Parameters ========== ``theta`` : numeric type or sympy Symbol The angle of the fast axis relative to the horizontal plane. Returns ======= sympy Matrix A Jones matrix representing the retarder. Examples ======== A generic quarter-wave plate. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import quarter_wave_retarder >>> theta= symbols("theta", real=True) >>> QWP = quarter_wave_retarder(theta) >>> pprint(QWP, use_unicode=True) ⎡ -ⅈ⋅π -ⅈ⋅π ⎤ ⎢ ───── ───── ⎥ ⎢⎛ 2 2 ⎞ 4 4 ⎥ ⎢⎝ⅈ⋅sin (θ) + cos (θ)⎠⋅ℯ (1 - ⅈ)⋅ℯ ⋅sin(θ)⋅cos(θ)⎥ ⎢ ⎥ ⎢ -ⅈ⋅π -ⅈ⋅π ⎥ ⎢ ───── ─────⎥ ⎢ 4 ⎛ 2 2 ⎞ 4 ⎥ ⎣(1 - ⅈ)⋅ℯ ⋅sin(θ)⋅cos(θ) ⎝sin (θ) + ⅈ⋅cos (θ)⎠⋅ℯ ⎦ """ return phase_retarder(theta, pi/2) def transmissive_filter(T): """An attenuator Jones matrix with transmittance `T`. Parameters ========== ``T`` : numeric type or sympy Symbol The transmittance of the attenuator. Returns ======= sympy Matrix A Jones matrix representing the filter. Examples ======== A generic filter. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import transmissive_filter >>> T = symbols("T", real=True) >>> NDF = transmissive_filter(T) >>> pprint(NDF, use_unicode=True) ⎡√T 0 ⎤ ⎢ ⎥ ⎣0 √T⎦ """ return Matrix([[sqrt(T), 0], [0, sqrt(T)]]) def reflective_filter(R): """A reflective filter Jones matrix with reflectance `R`. Parameters ========== ``R`` : numeric type or sympy Symbol The reflectance of the filter. Returns ======= sympy Matrix A Jones matrix representing the filter. Examples ======== A generic filter. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import reflective_filter >>> R = symbols("R", real=True) >>> pprint(reflective_filter(R), use_unicode=True) ⎡√R 0 ⎤ ⎢ ⎥ ⎣0 -√R⎦ """ return Matrix([[sqrt(R), 0], [0, -sqrt(R)]]) def mueller_matrix(J): """The Mueller matrix corresponding to Jones matrix `J`. Parameters ========== ``J`` : sympy Matrix A Jones matrix. Returns ======= sympy Matrix The corresponding Mueller matrix. Examples ======== Generic optical components. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import (mueller_matrix, ... linear_polarizer, half_wave_retarder, quarter_wave_retarder) >>> theta = symbols("theta", real=True) A linear_polarizer >>> pprint(mueller_matrix(linear_polarizer(theta)), use_unicode=True) ⎡ cos(2⋅θ) sin(2⋅θ) ⎤ ⎢ 1/2 ──────── ──────── 0⎥ ⎢ 2 2 ⎥ ⎢ ⎥ ⎢cos(2⋅θ) cos(4⋅θ) 1 sin(4⋅θ) ⎥ ⎢──────── ──────── + ─ ──────── 0⎥ ⎢ 2 4 4 4 ⎥ ⎢ ⎥ ⎢sin(2⋅θ) sin(4⋅θ) 1 cos(4⋅θ) ⎥ ⎢──────── ──────── ─ - ──────── 0⎥ ⎢ 2 4 4 4 ⎥ ⎢ ⎥ ⎣ 0 0 0 0⎦ A half-wave plate >>> pprint(mueller_matrix(half_wave_retarder(theta)), use_unicode=True) ⎡1 0 0 0 ⎤ ⎢ ⎥ ⎢ 4 2 ⎥ ⎢0 8⋅sin (θ) - 8⋅sin (θ) + 1 sin(4⋅θ) 0 ⎥ ⎢ ⎥ ⎢ 4 2 ⎥ ⎢0 sin(4⋅θ) - 8⋅sin (θ) + 8⋅sin (θ) - 1 0 ⎥ ⎢ ⎥ ⎣0 0 0 -1⎦ A quarter-wave plate >>> pprint(mueller_matrix(quarter_wave_retarder(theta)), use_unicode=True) ⎡1 0 0 0 ⎤ ⎢ ⎥ ⎢ cos(4⋅θ) 1 sin(4⋅θ) ⎥ ⎢0 ──────── + ─ ──────── -sin(2⋅θ)⎥ ⎢ 2 2 2 ⎥ ⎢ ⎥ ⎢ sin(4⋅θ) 1 cos(4⋅θ) ⎥ ⎢0 ──────── ─ - ──────── cos(2⋅θ) ⎥ ⎢ 2 2 2 ⎥ ⎢ ⎥ ⎣0 sin(2⋅θ) -cos(2⋅θ) 0 ⎦ """ A = Matrix([[1, 0, 0, 1], [1, 0, 0, -1], [0, 1, 1, 0], [0, -I, I, 0]]) return simplify(A*TensorProduct(J, J.conjugate())*A.inv()) def polarizing_beam_splitter(Tp=1, Rs=1, Ts=0, Rp=0, phia=0, phib=0): r"""A polarizing beam splitter Jones matrix at angle `theta`. Parameters ========== ``J`` : sympy Matrix A Jones matrix. ``Tp`` : numeric type or sympy Symbol The transmissivity of the P-polarized component. ``Rs`` : numeric type or sympy Symbol The reflectivity of the S-polarized component. ``Ts`` : numeric type or sympy Symbol The transmissivity of the S-polarized component. ``Rp`` : numeric type or sympy Symbol The reflectivity of the P-polarized component. ``phia`` : numeric type or sympy Symbol The phase difference between transmitted and reflected component for output mode a. ``phib`` : numeric type or sympy Symbol The phase difference between transmitted and reflected component for output mode b. Returns ======= sympy Matrix A 4x4 matrix representing the PBS. This matrix acts on a 4x1 vector whose first two entries are the Jones vector on one of the PBS ports, and the last two entries the Jones vector on the other port. Examples ======== Generic polarizing beam-splitter. >>> from sympy import pprint, symbols >>> from sympy.physics.optics.polarization import polarizing_beam_splitter >>> Ts, Rs, Tp, Rp = symbols(r"Ts, Rs, Tp, Rp", positive=True) >>> phia, phib = symbols("phi_a, phi_b", real=True) >>> PBS = polarizing_beam_splitter(Tp, Rs, Ts, Rp, phia, phib) >>> pprint(PBS, use_unicode=False) [ ____ ____ ] [ \/ Tp 0 I*\/ Rp 0 ] [ ] [ ____ ____ I*phi_a] [ 0 \/ Ts 0 -I*\/ Rs *e ] [ ] [ ____ ____ ] [I*\/ Rp 0 \/ Tp 0 ] [ ] [ ____ I*phi_b ____ ] [ 0 -I*\/ Rs *e 0 \/ Ts ] """ PBS = Matrix([[sqrt(Tp), 0, I*sqrt(Rp), 0], [0, sqrt(Ts), 0, -I*sqrt(Rs)*exp(I*phia)], [I*sqrt(Rp), 0, sqrt(Tp), 0], [0, -I*sqrt(Rs)*exp(I*phib), 0, sqrt(Ts)]]) return PBS sympy-sympy-1.9/sympy/physics/optics/tests/000077500000000000000000000000001412543434000212315ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/optics/tests/__init__.py000066400000000000000000000000001412543434000233300ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/optics/tests/test_gaussopt.py000066400000000000000000000072601412543434000245140ustar00rootroot00000000000000from sympy import atan2, factor, Float, I, Matrix, N, oo, pi, sqrt, symbols from sympy.physics.optics import (BeamParameter, CurvedMirror, CurvedRefraction, FlatMirror, FlatRefraction, FreeSpace, GeometricRay, RayTransferMatrix, ThinLens, conjugate_gauss_beams, gaussian_conj, geometric_conj_ab, geometric_conj_af, geometric_conj_bf, rayleigh2waist, waist2rayleigh) def streq(a, b): return str(a) == str(b) def test_gauss_opt(): mat = RayTransferMatrix(1, 2, 3, 4) assert mat == Matrix([[1, 2], [3, 4]]) assert mat == RayTransferMatrix( Matrix([[1, 2], [3, 4]]) ) assert [mat.A, mat.B, mat.C, mat.D] == [1, 2, 3, 4] d, f, h, n1, n2, R = symbols('d f h n1 n2 R') lens = ThinLens(f) assert lens == Matrix([[ 1, 0], [-1/f, 1]]) assert lens.C == -1/f assert FreeSpace(d) == Matrix([[ 1, d], [0, 1]]) assert FlatRefraction(n1, n2) == Matrix([[1, 0], [0, n1/n2]]) assert CurvedRefraction( R, n1, n2) == Matrix([[1, 0], [(n1 - n2)/(R*n2), n1/n2]]) assert FlatMirror() == Matrix([[1, 0], [0, 1]]) assert CurvedMirror(R) == Matrix([[ 1, 0], [-2/R, 1]]) assert ThinLens(f) == Matrix([[ 1, 0], [-1/f, 1]]) mul = CurvedMirror(R)*FreeSpace(d) mul_mat = Matrix([[ 1, 0], [-2/R, 1]])*Matrix([[ 1, d], [0, 1]]) assert mul.A == mul_mat[0, 0] assert mul.B == mul_mat[0, 1] assert mul.C == mul_mat[1, 0] assert mul.D == mul_mat[1, 1] angle = symbols('angle') assert GeometricRay(h, angle) == Matrix([[ h], [angle]]) assert FreeSpace( d)*GeometricRay(h, angle) == Matrix([[angle*d + h], [angle]]) assert GeometricRay( Matrix( ((h,), (angle,)) ) ) == Matrix([[h], [angle]]) assert (FreeSpace(d)*GeometricRay(h, angle)).height == angle*d + h assert (FreeSpace(d)*GeometricRay(h, angle)).angle == angle p = BeamParameter(530e-9, 1, w=1e-3) assert streq(p.q, 1 + 1.88679245283019*I*pi) assert streq(N(p.q), 1.0 + 5.92753330865999*I) assert streq(N(p.w_0), Float(0.00100000000000000)) assert streq(N(p.z_r), Float(5.92753330865999)) fs = FreeSpace(10) p1 = fs*p assert streq(N(p.w), Float(0.00101413072159615)) assert streq(N(p1.w), Float(0.00210803120913829)) w, wavelen = symbols('w wavelen') assert waist2rayleigh(w, wavelen) == pi*w**2/wavelen z_r, wavelen = symbols('z_r wavelen') assert rayleigh2waist(z_r, wavelen) == sqrt(wavelen*z_r)/sqrt(pi) a, b, f = symbols('a b f') assert geometric_conj_ab(a, b) == a*b/(a + b) assert geometric_conj_af(a, f) == a*f/(a - f) assert geometric_conj_bf(b, f) == b*f/(b - f) assert geometric_conj_ab(oo, b) == b assert geometric_conj_ab(a, oo) == a s_in, z_r_in, f = symbols('s_in z_r_in f') assert gaussian_conj( s_in, z_r_in, f)[0] == 1/(-1/(s_in + z_r_in**2/(-f + s_in)) + 1/f) assert gaussian_conj( s_in, z_r_in, f)[1] == z_r_in/(1 - s_in**2/f**2 + z_r_in**2/f**2) assert gaussian_conj( s_in, z_r_in, f)[2] == 1/sqrt(1 - s_in**2/f**2 + z_r_in**2/f**2) l, w_i, w_o, f = symbols('l w_i w_o f') assert conjugate_gauss_beams(l, w_i, w_o, f=f)[0] == f*( -sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)) + 1) assert factor(conjugate_gauss_beams(l, w_i, w_o, f=f)[1]) == f*w_o**2*( w_i**2/w_o**2 - sqrt(w_i**2/w_o**2 - pi**2*w_i**4/(f**2*l**2)))/w_i**2 assert conjugate_gauss_beams(l, w_i, w_o, f=f)[2] == f z, l, w = symbols('z l r', positive=True) p = BeamParameter(l, z, w=w) assert p.radius == z*(pi**2*w**4/(l**2*z**2) + 1) assert p.w == w*sqrt(l**2*z**2/(pi**2*w**4) + 1) assert p.w_0 == w assert p.divergence == l/(pi*w) assert p.gouy == atan2(z, pi*w**2/l) assert p.waist_approximation_limit == 2*l/pi sympy-sympy-1.9/sympy/physics/optics/tests/test_medium.py000066400000000000000000000041311412543434000241210ustar00rootroot00000000000000from sympy import sqrt from sympy.physics.optics import Medium from sympy.abc import epsilon, mu, n from sympy.physics.units import speed_of_light, u0, e0, m, kg, s, A from sympy.testing.pytest import raises c = speed_of_light.convert_to(m/s) e0 = e0.convert_to(A**2*s**4/(kg*m**3)) u0 = u0.convert_to(m*kg/(A**2*s**2)) def test_medium(): m1 = Medium('m1') assert m1.intrinsic_impedance == sqrt(u0/e0) assert m1.speed == 1/sqrt(e0*u0) assert m1.refractive_index == c*sqrt(e0*u0) assert m1.permittivity == e0 assert m1.permeability == u0 m2 = Medium('m2', epsilon, mu) assert m2.intrinsic_impedance == sqrt(mu/epsilon) assert m2.speed == 1/sqrt(epsilon*mu) assert m2.refractive_index == c*sqrt(epsilon*mu) assert m2.permittivity == epsilon assert m2.permeability == mu # Increasing electric permittivity and magnetic permeability # by small amount from its value in vacuum. m3 = Medium('m3', 9.0*10**(-12)*s**4*A**2/(m**3*kg), 1.45*10**(-6)*kg*m/(A**2*s**2)) assert m3.refractive_index > m1.refractive_index assert m3 > m1 assert m3 != m1 # Decreasing electric permittivity and magnetic permeability # by small amount from its value in vacuum. m4 = Medium('m4', 7.0*10**(-12)*s**4*A**2/(m**3*kg), 1.15*10**(-6)*kg*m/(A**2*s**2)) assert m4.refractive_index < m1.refractive_index assert m4 < m1 m5 = Medium('m5', permittivity=710*10**(-12)*s**4*A**2/(m**3*kg), n=1.33) assert abs(m5.intrinsic_impedance - 6.24845417765552*kg*m**2/(A**2*s**3)) \ < 1e-12*kg*m**2/(A**2*s**3) assert abs(m5.speed - 225407863.157895*m/s) < 1e-6*m/s assert abs(m5.refractive_index - 1.33000000000000) < 1e-12 assert abs(m5.permittivity - 7.1e-10*A**2*s**4/(kg*m**3)) \ < 1e-20*A**2*s**4/(kg*m**3) assert abs(m5.permeability - 2.77206575232851e-8*kg*m/(A**2*s**2)) \ < 1e-20*kg*m/(A**2*s**2) m6 = Medium('m6', None, mu, n) assert m6.permittivity == n**2/(c**2*mu) assert Medium('m7') == Medium('m8', e0, u0) # test for equality raises(ValueError, lambda:Medium('m9', e0, u0, 2)) sympy-sympy-1.9/sympy/physics/optics/tests/test_polarization.py000066400000000000000000000046171412543434000253650ustar00rootroot00000000000000from sympy.physics.optics.polarization import (jones_vector, stokes_vector, jones_2_stokes, linear_polarizer, phase_retarder, half_wave_retarder, quarter_wave_retarder, transmissive_filter, reflective_filter, mueller_matrix, polarizing_beam_splitter) from sympy import Matrix, pi, symbols, exp, I, S def test_polarization(): assert jones_vector(0, 0) == Matrix([1, 0]) assert jones_vector(pi/2, 0) == Matrix([0, 1]) ################################################################# assert stokes_vector(0, 0) == Matrix([1, 1, 0, 0]) assert stokes_vector(pi/2, 0) == Matrix([1, -1, 0, 0]) ################################################################# H = jones_vector(0, 0) V = jones_vector(pi/2, 0) D = jones_vector(pi/4, 0) A = jones_vector(-pi/4, 0) R = jones_vector(0, pi/4) L = jones_vector(0, -pi/4) res = [Matrix([1, 1, 0, 0]), Matrix([1, -1, 0, 0]), Matrix([1, 0, 1, 0]), Matrix([1, 0, -1, 0]), Matrix([1, 0, 0, 1]), Matrix([1, 0, 0, -1])] assert [jones_2_stokes(e) for e in [H, V, D, A, R, L]] == res ################################################################# assert linear_polarizer(0) == Matrix([[1, 0], [0, 0]]) ################################################################# delta = symbols("delta", real=True) res = Matrix([[exp(-I*delta/2), 0], [0, exp(I*delta/2)]]) assert phase_retarder(0, delta) == res ################################################################# assert half_wave_retarder(0) == Matrix([[-I, 0], [0, I]]) ################################################################# res = Matrix([[exp(-I*pi/4), 0], [0, I*exp(-I*pi/4)]]) assert quarter_wave_retarder(0) == res ################################################################# assert transmissive_filter(1) == Matrix([[1, 0], [0, 1]]) ################################################################# assert reflective_filter(1) == Matrix([[1, 0], [0, -1]]) res = Matrix([[S(1)/2, S(1)/2, 0, 0], [S(1)/2, S(1)/2, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) assert mueller_matrix(linear_polarizer(0)) == res ################################################################# res = Matrix([[1, 0, 0, 0], [0, 0, 0, -I], [0, 0, 1, 0], [0, -I, 0, 0]]) assert polarizing_beam_splitter() == res sympy-sympy-1.9/sympy/physics/optics/tests/test_utils.py000066400000000000000000000171561412543434000240140ustar00rootroot00000000000000from sympy.core.numbers import comp, Rational from sympy.physics.optics.utils import (refraction_angle, fresnel_coefficients, deviation, brewster_angle, critical_angle, lens_makers_formula, mirror_formula, lens_formula, hyperfocal_distance, transverse_magnification) from sympy.physics.optics.medium import Medium from sympy.physics.units import e0 from sympy import symbols, sqrt, Matrix, oo from sympy.geometry.point import Point3D from sympy.geometry.line import Ray3D from sympy.geometry.plane import Plane from sympy.testing.pytest import raises ae = lambda a, b, n: comp(a, b, 10**-n) def test_refraction_angle(): n1, n2 = symbols('n1, n2') m1 = Medium('m1') m2 = Medium('m2') r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) i = Matrix([1, 1, 1]) n = Matrix([0, 0, 1]) normal_ray = Ray3D(Point3D(0, 0, 0), Point3D(0, 0, 1)) P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) assert refraction_angle(r1, 1, 1, n) == Matrix([ [ 1], [ 1], [-1]]) assert refraction_angle([1, 1, 1], 1, 1, n) == Matrix([ [ 1], [ 1], [-1]]) assert refraction_angle((1, 1, 1), 1, 1, n) == Matrix([ [ 1], [ 1], [-1]]) assert refraction_angle(i, 1, 1, [0, 0, 1]) == Matrix([ [ 1], [ 1], [-1]]) assert refraction_angle(i, 1, 1, (0, 0, 1)) == Matrix([ [ 1], [ 1], [-1]]) assert refraction_angle(i, 1, 1, normal_ray) == Matrix([ [ 1], [ 1], [-1]]) assert refraction_angle(i, 1, 1, plane=P) == Matrix([ [ 1], [ 1], [-1]]) assert refraction_angle(r1, 1, 1, plane=P) == \ Ray3D(Point3D(0, 0, 0), Point3D(1, 1, -1)) assert refraction_angle(r1, m1, 1.33, plane=P) == \ Ray3D(Point3D(0, 0, 0), Point3D(Rational(100, 133), Rational(100, 133), -789378201649271*sqrt(3)/1000000000000000)) assert refraction_angle(r1, 1, m2, plane=P) == \ Ray3D(Point3D(0, 0, 0), Point3D(1, 1, -1)) assert refraction_angle(r1, n1, n2, plane=P) == \ Ray3D(Point3D(0, 0, 0), Point3D(n1/n2, n1/n2, -sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1))) assert refraction_angle(r1, 1.33, 1, plane=P) == 0 # TIR assert refraction_angle(r1, 1, 1, normal_ray) == \ Ray3D(Point3D(0, 0, 0), direction_ratio=[1, 1, -1]) assert ae(refraction_angle(0.5, 1, 2), 0.24207, 5) assert ae(refraction_angle(0.5, 2, 1), 1.28293, 5) raises(ValueError, lambda: refraction_angle(r1, m1, m2, normal_ray, P)) raises(TypeError, lambda: refraction_angle(m1, m1, m2)) # can add other values for arg[0] raises(TypeError, lambda: refraction_angle(r1, m1, m2, None, i)) raises(TypeError, lambda: refraction_angle(r1, m1, m2, m2)) def test_fresnel_coefficients(): assert all(ae(i, j, 5) for i, j in zip( fresnel_coefficients(0.5, 1, 1.33), [0.11163, -0.17138, 0.83581, 0.82862])) assert all(ae(i, j, 5) for i, j in zip( fresnel_coefficients(0.5, 1.33, 1), [-0.07726, 0.20482, 1.22724, 1.20482])) m1 = Medium('m1') m2 = Medium('m2', n=2) assert all(ae(i, j, 5) for i, j in zip( fresnel_coefficients(0.3, m1, m2), [0.31784, -0.34865, 0.65892, 0.65135])) ans = [[-0.23563, -0.97184], [0.81648, -0.57738]] got = fresnel_coefficients(0.6, m2, m1) for i, j in zip(got, ans): for a, b in zip(i.as_real_imag(), j): assert ae(a, b, 5) def test_deviation(): n1, n2 = symbols('n1, n2') r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) n = Matrix([0, 0, 1]) i = Matrix([-1, -1, -1]) normal_ray = Ray3D(Point3D(0, 0, 0), Point3D(0, 0, 1)) P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) assert deviation(r1, 1, 1, normal=n) == 0 assert deviation(r1, 1, 1, plane=P) == 0 assert deviation(r1, 1, 1.1, plane=P).evalf(3) + 0.119 < 1e-3 assert deviation(i, 1, 1.1, normal=normal_ray).evalf(3) + 0.119 < 1e-3 assert deviation(r1, 1.33, 1, plane=P) is None # TIR assert deviation(r1, 1, 1, normal=[0, 0, 1]) == 0 assert deviation([-1, -1, -1], 1, 1, normal=[0, 0, 1]) == 0 assert ae(deviation(0.5, 1, 2), -0.25793, 5) assert ae(deviation(0.5, 2, 1), 0.78293, 5) def test_brewster_angle(): m1 = Medium('m1', n=1) m2 = Medium('m2', n=1.33) assert ae(brewster_angle(m1, m2), 0.93, 2) m1 = Medium('m1', permittivity=e0, n=1) m2 = Medium('m2', permittivity=e0, n=1.33) assert ae(brewster_angle(m1, m2), 0.93, 2) assert ae(brewster_angle(1, 1.33), 0.93, 2) def test_critical_angle(): m1 = Medium('m1', n=1) m2 = Medium('m2', n=1.33) assert ae(critical_angle(m2, m1), 0.85, 2) def test_lens_makers_formula(): n1, n2 = symbols('n1, n2') m1 = Medium('m1', permittivity=e0, n=1) m2 = Medium('m2', permittivity=e0, n=1.33) assert lens_makers_formula(n1, n2, 10, -10) == 5*n2/(n1 - n2) assert ae(lens_makers_formula(m1, m2, 10, -10), -20.15, 2) assert ae(lens_makers_formula(1.33, 1, 10, -10), 15.15, 2) def test_mirror_formula(): u, v, f = symbols('u, v, f') assert mirror_formula(focal_length=f, u=u) == f*u/(-f + u) assert mirror_formula(focal_length=f, v=v) == f*v/(-f + v) assert mirror_formula(u=u, v=v) == u*v/(u + v) assert mirror_formula(u=oo, v=v) == v assert mirror_formula(u=oo, v=oo) is oo assert mirror_formula(focal_length=oo, u=u) == -u assert mirror_formula(u=u, v=oo) == u assert mirror_formula(focal_length=oo, v=oo) is oo assert mirror_formula(focal_length=f, v=oo) == f assert mirror_formula(focal_length=oo, v=v) == -v assert mirror_formula(focal_length=oo, u=oo) is oo assert mirror_formula(focal_length=f, u=oo) == f assert mirror_formula(focal_length=oo, u=u) == -u raises(ValueError, lambda: mirror_formula(focal_length=f, u=u, v=v)) def test_lens_formula(): u, v, f = symbols('u, v, f') assert lens_formula(focal_length=f, u=u) == f*u/(f + u) assert lens_formula(focal_length=f, v=v) == f*v/(f - v) assert lens_formula(u=u, v=v) == u*v/(u - v) assert lens_formula(u=oo, v=v) == v assert lens_formula(u=oo, v=oo) is oo assert lens_formula(focal_length=oo, u=u) == u assert lens_formula(u=u, v=oo) == -u assert lens_formula(focal_length=oo, v=oo) is -oo assert lens_formula(focal_length=oo, v=v) == v assert lens_formula(focal_length=f, v=oo) == -f assert lens_formula(focal_length=oo, u=oo) is oo assert lens_formula(focal_length=oo, u=u) == u assert lens_formula(focal_length=f, u=oo) == f raises(ValueError, lambda: lens_formula(focal_length=f, u=u, v=v)) def test_hyperfocal_distance(): f, N, c = symbols('f, N, c') assert hyperfocal_distance(f=f, N=N, c=c) == f**2/(N*c) assert ae(hyperfocal_distance(f=0.5, N=8, c=0.0033), 9.47, 2) def test_transverse_magnification(): si, so = symbols('si, so') assert transverse_magnification(si, so) == -si/so assert transverse_magnification(30, 15) == -2 sympy-sympy-1.9/sympy/physics/optics/tests/test_waves.py000066400000000000000000000061571412543434000240000ustar00rootroot00000000000000from sympy import (symbols, Symbol, pi, sqrt, cos, sin, Derivative, Function, simplify, I, atan2) from sympy.abc import epsilon, mu from sympy.functions.elementary.exponential import exp from sympy.physics.units import speed_of_light, m, s from sympy.physics.optics import TWave from sympy.testing.pytest import raises c = speed_of_light.convert_to(m/s) def test_twave(): A1, phi1, A2, phi2, f = symbols('A1, phi1, A2, phi2, f') n = Symbol('n') # Refractive index t = Symbol('t') # Time x = Symbol('x') # Spatial variable E = Function('E') w1 = TWave(A1, f, phi1) w2 = TWave(A2, f, phi2) assert w1.amplitude == A1 assert w1.frequency == f assert w1.phase == phi1 assert w1.wavelength == c/(f*n) assert w1.time_period == 1/f assert w1.angular_velocity == 2*pi*f assert w1.wavenumber == 2*pi*f*n/c assert w1.speed == c/n w3 = w1 + w2 assert w3.amplitude == sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2) assert w3.frequency == f assert w3.phase == atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2)) assert w3.wavelength == c/(f*n) assert w3.time_period == 1/f assert w3.angular_velocity == 2*pi*f assert w3.wavenumber == 2*pi*f*n/c assert w3.speed == c/n assert simplify(w3.rewrite(sin) - w2.rewrite(sin) - w1.rewrite(sin)) == 0 assert w3.rewrite('pde') == epsilon*mu*Derivative(E(x, t), t, t) + Derivative(E(x, t), x, x) assert w3.rewrite(cos) == sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2)*cos(pi*f*n*x*s/(149896229*m) - 2*pi*f*t + atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2))) assert w3.rewrite(exp) == sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2)*exp(I*(-2*pi*f*t + atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2)) + pi*s*f*n*x/(149896229*m))) w4 = TWave(A1, None, 0, 1/f) assert w4.frequency == f w5 = w1 - w2 assert w5.amplitude == sqrt(A1**2 - 2*A1*A2*cos(phi1 - phi2) + A2**2) assert w5.frequency == f assert w5.phase == atan2(A1*sin(phi1) - A2*sin(phi2), A1*cos(phi1) - A2*cos(phi2)) assert w5.wavelength == c/(f*n) assert w5.time_period == 1/f assert w5.angular_velocity == 2*pi*f assert w5.wavenumber == 2*pi*f*n/c assert w5.speed == c/n assert simplify(w5.rewrite(sin) - w1.rewrite(sin) + w2.rewrite(sin)) == 0 assert w5.rewrite('pde') == epsilon*mu*Derivative(E(x, t), t, t) + Derivative(E(x, t), x, x) assert w5.rewrite(cos) == sqrt(A1**2 - 2*A1*A2*cos(phi1 - phi2) + A2**2)*cos(-2*pi*f*t + atan2(A1*sin(phi1) - A2*sin(phi2), A1*cos(phi1) - A2*cos(phi2)) + pi*s*f*n*x/(149896229*m)) assert w5.rewrite(exp) == sqrt(A1**2 - 2*A1*A2*cos(phi1 - phi2) + A2**2)*exp(I*(-2*pi*f*t + atan2(A1*sin(phi1) - A2*sin(phi2), A1*cos(phi1) - A2*cos(phi2)) + pi*s*f*n*x/(149896229*m))) w6 = 2*w1 assert w6.amplitude == 2*A1 assert w6.frequency == f assert w6.phase == phi1 w7 = -w6 assert w7.amplitude == -2*A1 assert w7.frequency == f assert w7.phase == phi1 raises(ValueError, lambda:TWave(A1)) raises(ValueError, lambda:TWave(A1, f, phi1, t)) sympy-sympy-1.9/sympy/physics/optics/utils.py000066400000000000000000000517341412543434000216130ustar00rootroot00000000000000""" **Contains** * refraction_angle * fresnel_coefficients * deviation * brewster_angle * critical_angle * lens_makers_formula * mirror_formula * lens_formula * hyperfocal_distance * transverse_magnification """ __all__ = ['refraction_angle', 'deviation', 'fresnel_coefficients', 'brewster_angle', 'critical_angle', 'lens_makers_formula', 'mirror_formula', 'lens_formula', 'hyperfocal_distance', 'transverse_magnification' ] from sympy import Symbol, sympify, sqrt, Matrix, acos, oo, Limit, atan2, asin,\ cos, sin, tan, I, cancel, pi, Float from sympy.core.compatibility import is_sequence from sympy.geometry.line import Ray3D from sympy.geometry.util import intersection from sympy.geometry.plane import Plane from .medium import Medium def refractive_index_of_medium(medium): """ Helper function that returns refractive index, given a medium """ if isinstance(medium, Medium): n = medium.refractive_index else: n = sympify(medium) return n def refraction_angle(incident, medium1, medium2, normal=None, plane=None): """ This function calculates transmitted vector after refraction at planar surface. ``medium1`` and ``medium2`` can be ``Medium`` or any sympifiable object. If ``incident`` is a number then treated as angle of incidence (in radians) in which case refraction angle is returned. If ``incident`` is an object of `Ray3D`, `normal` also has to be an instance of `Ray3D` in order to get the output as a `Ray3D`. Please note that if plane of separation is not provided and normal is an instance of `Ray3D`, ``normal`` will be assumed to be intersecting incident ray at the plane of separation. This will not be the case when `normal` is a `Matrix` or any other sequence. If ``incident`` is an instance of `Ray3D` and `plane` has not been provided and ``normal`` is not `Ray3D`, output will be a `Matrix`. Parameters ========== incident : Matrix, Ray3D, sequence or a number Incident vector or angle of incidence medium1 : sympy.physics.optics.medium.Medium or sympifiable Medium 1 or its refractive index medium2 : sympy.physics.optics.medium.Medium or sympifiable Medium 2 or its refractive index normal : Matrix, Ray3D, or sequence Normal vector plane : Plane Plane of separation of the two media. Returns ======= Returns an angle of refraction or a refracted ray depending on inputs. Examples ======== >>> from sympy.physics.optics import refraction_angle >>> from sympy.geometry import Point3D, Ray3D, Plane >>> from sympy.matrices import Matrix >>> from sympy import symbols, pi >>> n = Matrix([0, 0, 1]) >>> P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) >>> r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) >>> refraction_angle(r1, 1, 1, n) Matrix([ [ 1], [ 1], [-1]]) >>> refraction_angle(r1, 1, 1, plane=P) Ray3D(Point3D(0, 0, 0), Point3D(1, 1, -1)) With different index of refraction of the two media >>> n1, n2 = symbols('n1, n2') >>> refraction_angle(r1, n1, n2, n) Matrix([ [ n1/n2], [ n1/n2], [-sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1)]]) >>> refraction_angle(r1, n1, n2, plane=P) Ray3D(Point3D(0, 0, 0), Point3D(n1/n2, n1/n2, -sqrt(3)*sqrt(-2*n1**2/(3*n2**2) + 1))) >>> round(refraction_angle(pi/6, 1.2, 1.5), 5) 0.41152 """ n1 = refractive_index_of_medium(medium1) n2 = refractive_index_of_medium(medium2) # check if an incidence angle was supplied instead of a ray try: angle_of_incidence = float(incident) except TypeError: angle_of_incidence = None try: critical_angle_ = critical_angle(medium1, medium2) except (ValueError, TypeError): critical_angle_ = None if angle_of_incidence is not None: if normal is not None or plane is not None: raise ValueError('Normal/plane not allowed if incident is an angle') if not 0.0 <= angle_of_incidence < pi*0.5: raise ValueError('Angle of incidence not in range [0:pi/2)') if critical_angle_ and angle_of_incidence > critical_angle_: raise ValueError('Ray undergoes total internal reflection') return asin(n1*sin(angle_of_incidence)/n2) # Treat the incident as ray below # A flag to check whether to return Ray3D or not return_ray = False if plane is not None and normal is not None: raise ValueError("Either plane or normal is acceptable.") if not isinstance(incident, Matrix): if is_sequence(incident): _incident = Matrix(incident) elif isinstance(incident, Ray3D): _incident = Matrix(incident.direction_ratio) else: raise TypeError( "incident should be a Matrix, Ray3D, or sequence") else: _incident = incident # If plane is provided, get direction ratios of the normal # to the plane from the plane else go with `normal` param. if plane is not None: if not isinstance(plane, Plane): raise TypeError("plane should be an instance of geometry.plane.Plane") # If we have the plane, we can get the intersection # point of incident ray and the plane and thus return # an instance of Ray3D. if isinstance(incident, Ray3D): return_ray = True intersection_pt = plane.intersection(incident)[0] _normal = Matrix(plane.normal_vector) else: if not isinstance(normal, Matrix): if is_sequence(normal): _normal = Matrix(normal) elif isinstance(normal, Ray3D): _normal = Matrix(normal.direction_ratio) if isinstance(incident, Ray3D): intersection_pt = intersection(incident, normal) if len(intersection_pt) == 0: raise ValueError( "Normal isn't concurrent with the incident ray.") else: return_ray = True intersection_pt = intersection_pt[0] else: raise TypeError( "Normal should be a Matrix, Ray3D, or sequence") else: _normal = normal eta = n1/n2 # Relative index of refraction # Calculating magnitude of the vectors mag_incident = sqrt(sum([i**2 for i in _incident])) mag_normal = sqrt(sum([i**2 for i in _normal])) # Converting vectors to unit vectors by dividing # them with their magnitudes _incident /= mag_incident _normal /= mag_normal c1 = -_incident.dot(_normal) # cos(angle_of_incidence) cs2 = 1 - eta**2*(1 - c1**2) # cos(angle_of_refraction)**2 if cs2.is_negative: # This is the case of total internal reflection(TIR). return 0 drs = eta*_incident + (eta*c1 - sqrt(cs2))*_normal # Multiplying unit vector by its magnitude drs = drs*mag_incident if not return_ray: return drs else: return Ray3D(intersection_pt, direction_ratio=drs) def fresnel_coefficients(angle_of_incidence, medium1, medium2): """ This function uses Fresnel equations to calculate reflection and transmission coefficients. Those are obtained for both polarisations when the electric field vector is in the plane of incidence (labelled 'p') and when the electric field vector is perpendicular to the plane of incidence (labelled 's'). There are four real coefficients unless the incident ray reflects in total internal in which case there are two complex ones. Angle of incidence is the angle between the incident ray and the surface normal. ``medium1`` and ``medium2`` can be ``Medium`` or any sympifiable object. Parameters ========== angle_of_incidence : sympifiable medium1 : Medium or sympifiable Medium 1 or its refractive index medium2 : Medium or sympifiable Medium 2 or its refractive index Returns ======= Returns a list with four real Fresnel coefficients: [reflection p (TM), reflection s (TE), transmission p (TM), transmission s (TE)] If the ray is undergoes total internal reflection then returns a list of two complex Fresnel coefficients: [reflection p (TM), reflection s (TE)] Examples ======== >>> from sympy.physics.optics import fresnel_coefficients >>> fresnel_coefficients(0.3, 1, 2) [0.317843553417859, -0.348645229818821, 0.658921776708929, 0.651354770181179] >>> fresnel_coefficients(0.6, 2, 1) [-0.235625382192159 - 0.971843958291041*I, 0.816477005968898 - 0.577377951366403*I] References ========== .. [1] https://en.wikipedia.org/wiki/Fresnel_equations """ if not 0 <= 2*angle_of_incidence < pi: raise ValueError('Angle of incidence not in range [0:pi/2)') n1 = refractive_index_of_medium(medium1) n2 = refractive_index_of_medium(medium2) angle_of_refraction = asin(n1*sin(angle_of_incidence)/n2) try: angle_of_total_internal_reflection_onset = critical_angle(n1, n2) except ValueError: angle_of_total_internal_reflection_onset = None if angle_of_total_internal_reflection_onset is None or\ angle_of_total_internal_reflection_onset > angle_of_incidence: R_s = -sin(angle_of_incidence - angle_of_refraction)\ /sin(angle_of_incidence + angle_of_refraction) R_p = tan(angle_of_incidence - angle_of_refraction)\ /tan(angle_of_incidence + angle_of_refraction) T_s = 2*sin(angle_of_refraction)*cos(angle_of_incidence)\ /sin(angle_of_incidence + angle_of_refraction) T_p = 2*sin(angle_of_refraction)*cos(angle_of_incidence)\ /(sin(angle_of_incidence + angle_of_refraction)\ *cos(angle_of_incidence - angle_of_refraction)) return [R_p, R_s, T_p, T_s] else: n = n2/n1 R_s = cancel((cos(angle_of_incidence)-\ I*sqrt(sin(angle_of_incidence)**2 - n**2))\ /(cos(angle_of_incidence)+\ I*sqrt(sin(angle_of_incidence)**2 - n**2))) R_p = cancel((n**2*cos(angle_of_incidence)-\ I*sqrt(sin(angle_of_incidence)**2 - n**2))\ /(n**2*cos(angle_of_incidence)+\ I*sqrt(sin(angle_of_incidence)**2 - n**2))) return [R_p, R_s] def deviation(incident, medium1, medium2, normal=None, plane=None): """ This function calculates the angle of deviation of a ray due to refraction at planar surface. Parameters ========== incident : Matrix, Ray3D, sequence or float Incident vector or angle of incidence medium1 : sympy.physics.optics.medium.Medium or sympifiable Medium 1 or its refractive index medium2 : sympy.physics.optics.medium.Medium or sympifiable Medium 2 or its refractive index normal : Matrix, Ray3D, or sequence Normal vector plane : Plane Plane of separation of the two media. Returns angular deviation between incident and refracted rays Examples ======== >>> from sympy.physics.optics import deviation >>> from sympy.geometry import Point3D, Ray3D, Plane >>> from sympy.matrices import Matrix >>> from sympy import symbols >>> n1, n2 = symbols('n1, n2') >>> n = Matrix([0, 0, 1]) >>> P = Plane(Point3D(0, 0, 0), normal_vector=[0, 0, 1]) >>> r1 = Ray3D(Point3D(-1, -1, 1), Point3D(0, 0, 0)) >>> deviation(r1, 1, 1, n) 0 >>> deviation(r1, n1, n2, plane=P) -acos(-sqrt(-2*n1**2/(3*n2**2) + 1)) + acos(-sqrt(3)/3) >>> round(deviation(0.1, 1.2, 1.5), 5) -0.02005 """ refracted = refraction_angle(incident, medium1, medium2, normal=normal, plane=plane) try: angle_of_incidence = Float(incident) except TypeError: angle_of_incidence = None if angle_of_incidence is not None: return float(refracted) - angle_of_incidence if refracted != 0: if isinstance(refracted, Ray3D): refracted = Matrix(refracted.direction_ratio) if not isinstance(incident, Matrix): if is_sequence(incident): _incident = Matrix(incident) elif isinstance(incident, Ray3D): _incident = Matrix(incident.direction_ratio) else: raise TypeError( "incident should be a Matrix, Ray3D, or sequence") else: _incident = incident if plane is None: if not isinstance(normal, Matrix): if is_sequence(normal): _normal = Matrix(normal) elif isinstance(normal, Ray3D): _normal = Matrix(normal.direction_ratio) else: raise TypeError( "normal should be a Matrix, Ray3D, or sequence") else: _normal = normal else: _normal = Matrix(plane.normal_vector) mag_incident = sqrt(sum([i**2 for i in _incident])) mag_normal = sqrt(sum([i**2 for i in _normal])) mag_refracted = sqrt(sum([i**2 for i in refracted])) _incident /= mag_incident _normal /= mag_normal refracted /= mag_refracted i = acos(_incident.dot(_normal)) r = acos(refracted.dot(_normal)) return i - r def brewster_angle(medium1, medium2): """ This function calculates the Brewster's angle of incidence to Medium 2 from Medium 1 in radians. Parameters ========== medium 1 : Medium or sympifiable Refractive index of Medium 1 medium 2 : Medium or sympifiable Refractive index of Medium 1 Examples ======== >>> from sympy.physics.optics import brewster_angle >>> brewster_angle(1, 1.33) 0.926093295503462 """ n1 = refractive_index_of_medium(medium1) n2 = refractive_index_of_medium(medium2) return atan2(n2, n1) def critical_angle(medium1, medium2): """ This function calculates the critical angle of incidence (marking the onset of total internal) to Medium 2 from Medium 1 in radians. Parameters ========== medium 1 : Medium or sympifiable Refractive index of Medium 1. medium 2 : Medium or sympifiable Refractive index of Medium 1. Examples ======== >>> from sympy.physics.optics import critical_angle >>> critical_angle(1.33, 1) 0.850908514477849 """ n1 = refractive_index_of_medium(medium1) n2 = refractive_index_of_medium(medium2) if n2 > n1: raise ValueError('Total internal reflection impossible for n1 < n2') else: return asin(n2/n1) def lens_makers_formula(n_lens, n_surr, r1, r2): """ This function calculates focal length of a thin lens. It follows cartesian sign convention. Parameters ========== n_lens : Medium or sympifiable Index of refraction of lens. n_surr : Medium or sympifiable Index of reflection of surrounding. r1 : sympifiable Radius of curvature of first surface. r2 : sympifiable Radius of curvature of second surface. Examples ======== >>> from sympy.physics.optics import lens_makers_formula >>> lens_makers_formula(1.33, 1, 10, -10) 15.1515151515151 """ if isinstance(n_lens, Medium): n_lens = n_lens.refractive_index else: n_lens = sympify(n_lens) if isinstance(n_surr, Medium): n_surr = n_surr.refractive_index else: n_surr = sympify(n_surr) r1 = sympify(r1) r2 = sympify(r2) return 1/((n_lens - n_surr)/n_surr*(1/r1 - 1/r2)) def mirror_formula(focal_length=None, u=None, v=None): """ This function provides one of the three parameters when two of them are supplied. This is valid only for paraxial rays. Parameters ========== focal_length : sympifiable Focal length of the mirror. u : sympifiable Distance of object from the pole on the principal axis. v : sympifiable Distance of the image from the pole on the principal axis. Examples ======== >>> from sympy.physics.optics import mirror_formula >>> from sympy.abc import f, u, v >>> mirror_formula(focal_length=f, u=u) f*u/(-f + u) >>> mirror_formula(focal_length=f, v=v) f*v/(-f + v) >>> mirror_formula(u=u, v=v) u*v/(u + v) """ if focal_length and u and v: raise ValueError("Please provide only two parameters") focal_length = sympify(focal_length) u = sympify(u) v = sympify(v) if u is oo: _u = Symbol('u') if v is oo: _v = Symbol('v') if focal_length is oo: _f = Symbol('f') if focal_length is None: if u is oo and v is oo: return Limit(Limit(_v*_u/(_v + _u), _u, oo), _v, oo).doit() if u is oo: return Limit(v*_u/(v + _u), _u, oo).doit() if v is oo: return Limit(_v*u/(_v + u), _v, oo).doit() return v*u/(v + u) if u is None: if v is oo and focal_length is oo: return Limit(Limit(_v*_f/(_v - _f), _v, oo), _f, oo).doit() if v is oo: return Limit(_v*focal_length/(_v - focal_length), _v, oo).doit() if focal_length is oo: return Limit(v*_f/(v - _f), _f, oo).doit() return v*focal_length/(v - focal_length) if v is None: if u is oo and focal_length is oo: return Limit(Limit(_u*_f/(_u - _f), _u, oo), _f, oo).doit() if u is oo: return Limit(_u*focal_length/(_u - focal_length), _u, oo).doit() if focal_length is oo: return Limit(u*_f/(u - _f), _f, oo).doit() return u*focal_length/(u - focal_length) def lens_formula(focal_length=None, u=None, v=None): """ This function provides one of the three parameters when two of them are supplied. This is valid only for paraxial rays. Parameters ========== focal_length : sympifiable Focal length of the mirror. u : sympifiable Distance of object from the optical center on the principal axis. v : sympifiable Distance of the image from the optical center on the principal axis. Examples ======== >>> from sympy.physics.optics import lens_formula >>> from sympy.abc import f, u, v >>> lens_formula(focal_length=f, u=u) f*u/(f + u) >>> lens_formula(focal_length=f, v=v) f*v/(f - v) >>> lens_formula(u=u, v=v) u*v/(u - v) """ if focal_length and u and v: raise ValueError("Please provide only two parameters") focal_length = sympify(focal_length) u = sympify(u) v = sympify(v) if u is oo: _u = Symbol('u') if v is oo: _v = Symbol('v') if focal_length is oo: _f = Symbol('f') if focal_length is None: if u is oo and v is oo: return Limit(Limit(_v*_u/(_u - _v), _u, oo), _v, oo).doit() if u is oo: return Limit(v*_u/(_u - v), _u, oo).doit() if v is oo: return Limit(_v*u/(u - _v), _v, oo).doit() return v*u/(u - v) if u is None: if v is oo and focal_length is oo: return Limit(Limit(_v*_f/(_f - _v), _v, oo), _f, oo).doit() if v is oo: return Limit(_v*focal_length/(focal_length - _v), _v, oo).doit() if focal_length is oo: return Limit(v*_f/(_f - v), _f, oo).doit() return v*focal_length/(focal_length - v) if v is None: if u is oo and focal_length is oo: return Limit(Limit(_u*_f/(_u + _f), _u, oo), _f, oo).doit() if u is oo: return Limit(_u*focal_length/(_u + focal_length), _u, oo).doit() if focal_length is oo: return Limit(u*_f/(u + _f), _f, oo).doit() return u*focal_length/(u + focal_length) def hyperfocal_distance(f, N, c): """ Parameters ========== f: sympifiable Focal length of a given lens. N: sympifiable F-number of a given lens. c: sympifiable Circle of Confusion (CoC) of a given image format. Example ======= >>> from sympy.physics.optics import hyperfocal_distance >>> round(hyperfocal_distance(f = 0.5, N = 8, c = 0.0033), 2) 9.47 """ f = sympify(f) N = sympify(N) c = sympify(c) return (1/(N * c))*(f**2) def transverse_magnification(si, so): """ Calculates the transverse magnification, which is the ratio of the image size to the object size. Parameters ========== so: sympifiable Lens-object distance. si: sympifiable Lens-image distance. Example ======= >>> from sympy.physics.optics import transverse_magnification >>> transverse_magnification(30, 15) -2 """ si = sympify(si) so = sympify(so) return (-(si/so)) sympy-sympy-1.9/sympy/physics/optics/waves.py000066400000000000000000000225471412543434000216000ustar00rootroot00000000000000""" This module has all the classes and functions related to waves in optics. **Contains** * TWave """ __all__ = ['TWave'] from sympy import (sympify, pi, sin, cos, sqrt, Number, Symbol, S, symbols, Derivative, atan2) from sympy.core.expr import Expr from sympy.physics.units import speed_of_light, meter, second c = speed_of_light.convert_to(meter/second) class TWave(Expr): r""" This is a simple transverse sine wave travelling in a one-dimensional space. Basic properties are required at the time of creation of the object, but they can be changed later with respective methods provided. Explanation =========== It is represented as :math:`A \times cos(k*x - \omega \times t + \phi )`, where :math:`A` is the amplitude, :math:`\omega` is the angular frequency, :math:`k` is the wavenumber (spatial frequency), :math:`x` is a spatial variable to represent the position on the dimension on which the wave propagates, and :math:`\phi` is the phase angle of the wave. Arguments ========= amplitude : Sympifyable Amplitude of the wave. frequency : Sympifyable Frequency of the wave. phase : Sympifyable Phase angle of the wave. time_period : Sympifyable Time period of the wave. n : Sympifyable Refractive index of the medium. Raises ======= ValueError : When neither frequency nor time period is provided or they are not consistent. TypeError : When anything other than TWave objects is added. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A1, phi1, A2, phi2, f = symbols('A1, phi1, A2, phi2, f') >>> w1 = TWave(A1, f, phi1) >>> w2 = TWave(A2, f, phi2) >>> w3 = w1 + w2 # Superposition of two waves >>> w3 TWave(sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2), f, atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2))) >>> w3.amplitude sqrt(A1**2 + 2*A1*A2*cos(phi1 - phi2) + A2**2) >>> w3.phase atan2(A1*sin(phi1) + A2*sin(phi2), A1*cos(phi1) + A2*cos(phi2)) >>> w3.speed 299792458*meter/(second*n) >>> w3.angular_velocity 2*pi*f """ def __init__( self, amplitude, frequency=None, phase=S.Zero, time_period=None, n=Symbol('n')): frequency = sympify(frequency) amplitude = sympify(amplitude) phase = sympify(phase) time_period = sympify(time_period) n = sympify(n) self._frequency = frequency self._amplitude = amplitude self._phase = phase self._time_period = time_period self._n = n if time_period is not None: self._frequency = 1/self._time_period if frequency is not None: self._time_period = 1/self._frequency if time_period is not None: if frequency != 1/time_period: raise ValueError("frequency and time_period should be consistent.") if frequency is None and time_period is None: raise ValueError("Either frequency or time period is needed.") @property def frequency(self): """ Returns the frequency of the wave, in cycles per second. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.frequency f """ return self._frequency @property def time_period(self): """ Returns the temporal period of the wave, in seconds per cycle. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.time_period 1/f """ return self._time_period @property def wavelength(self): """ Returns the wavelength (spatial period) of the wave, in meters per cycle. It depends on the medium of the wave. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.wavelength 299792458*meter/(second*f*n) """ return c/(self._frequency*self._n) @property def amplitude(self): """ Returns the amplitude of the wave. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.amplitude A """ return self._amplitude @property def phase(self): """ Returns the phase angle of the wave, in radians. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.phase phi """ return self._phase @property def speed(self): """ Returns the propagation speed of the wave, in meters per second. It is dependent on the propagation medium. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.speed 299792458*meter/(second*n) """ return self.wavelength*self._frequency @property def angular_velocity(self): """ Returns the angular velocity of the wave, in radians per second. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.angular_velocity 2*pi*f """ return 2*pi*self._frequency @property def wavenumber(self): """ Returns the wavenumber of the wave, in radians per meter. Examples ======== >>> from sympy import symbols >>> from sympy.physics.optics import TWave >>> A, phi, f = symbols('A, phi, f') >>> w = TWave(A, f, phi) >>> w.wavenumber pi*second*f*n/(149896229*meter) """ return 2*pi/self.wavelength def __str__(self): """String representation of a TWave.""" from sympy.printing import sstr return type(self).__name__ + sstr(self.args) __repr__ = __str__ def __add__(self, other): """ Addition of two waves will result in their superposition. The type of interference will depend on their phase angles. """ if isinstance(other, TWave): if self._frequency == other._frequency and self.wavelength == other.wavelength: return TWave(sqrt(self._amplitude**2 + other._amplitude**2 + 2 * self._amplitude*other._amplitude*cos( self._phase - other.phase)), self._frequency, atan2(self._amplitude*sin(self._phase) + other._amplitude*sin(other._phase), self._amplitude*cos(self._phase) + other._amplitude*cos(other._phase)) ) else: raise NotImplementedError("Interference of waves with different frequencies" " has not been implemented.") else: raise TypeError(type(other).__name__ + " and TWave objects can't be added.") def __mul__(self, other): """ Multiplying a wave by a scalar rescales the amplitude of the wave. """ other = sympify(other) if isinstance(other, Number): return TWave(self._amplitude*other, *self.args[1:]) else: raise TypeError(type(other).__name__ + " and TWave objects can't be multiplied.") def __sub__(self, other): return self.__add__(-1*other) def __neg__(self): return self.__mul__(-1) def __radd__(self, other): return self.__add__(other) def __rmul__(self, other): return self.__mul__(other) def __rsub__(self, other): return (-self).__radd__(other) def _eval_rewrite_as_sin(self, *args, **kwargs): return self._amplitude*sin(self.wavenumber*Symbol('x') - self.angular_velocity*Symbol('t') + self._phase + pi/2, evaluate=False) def _eval_rewrite_as_cos(self, *args, **kwargs): return self._amplitude*cos(self.wavenumber*Symbol('x') - self.angular_velocity*Symbol('t') + self._phase) def _eval_rewrite_as_pde(self, *args, **kwargs): from sympy import Function mu, epsilon, x, t = symbols('mu, epsilon, x, t') E = Function('E') return Derivative(E(x, t), x, 2) + mu*epsilon*Derivative(E(x, t), t, 2) def _eval_rewrite_as_exp(self, *args, **kwargs): from sympy import exp, I return self._amplitude*exp(I*(self.wavenumber*Symbol('x') - self.angular_velocity*Symbol('t') + self._phase)) sympy-sympy-1.9/sympy/physics/paulialgebra.py000066400000000000000000000134021412543434000215700ustar00rootroot00000000000000""" This module implements Pauli algebra by subclassing Symbol. Only algebraic properties of Pauli matrices are used (we don't use the Matrix class). See the documentation to the class Pauli for examples. References ========== .. [1] https://en.wikipedia.org/wiki/Pauli_matrices """ from sympy import Symbol, I, Mul, Pow, Add from sympy.physics.quantum import TensorProduct __all__ = ['evaluate_pauli_product'] def delta(i, j): """ Returns 1 if ``i == j``, else 0. This is used in the multiplication of Pauli matrices. Examples ======== >>> from sympy.physics.paulialgebra import delta >>> delta(1, 1) 1 >>> delta(2, 3) 0 """ if i == j: return 1 else: return 0 def epsilon(i, j, k): """ Return 1 if i,j,k is equal to (1,2,3), (2,3,1), or (3,1,2); -1 if ``i``,``j``,``k`` is equal to (1,3,2), (3,2,1), or (2,1,3); else return 0. This is used in the multiplication of Pauli matrices. Examples ======== >>> from sympy.physics.paulialgebra import epsilon >>> epsilon(1, 2, 3) 1 >>> epsilon(1, 3, 2) -1 """ if (i, j, k) in [(1, 2, 3), (2, 3, 1), (3, 1, 2)]: return 1 elif (i, j, k) in [(1, 3, 2), (3, 2, 1), (2, 1, 3)]: return -1 else: return 0 class Pauli(Symbol): """ The class representing algebraic properties of Pauli matrices. Explanation =========== The symbol used to display the Pauli matrices can be changed with an optional parameter ``label="sigma"``. Pauli matrices with different ``label`` attributes cannot multiply together. If the left multiplication of symbol or number with Pauli matrix is needed, please use parentheses to separate Pauli and symbolic multiplication (for example: 2*I*(Pauli(3)*Pauli(2))). Another variant is to use evaluate_pauli_product function to evaluate the product of Pauli matrices and other symbols (with commutative multiply rules). See Also ======== evaluate_pauli_product Examples ======== >>> from sympy.physics.paulialgebra import Pauli >>> Pauli(1) sigma1 >>> Pauli(1)*Pauli(2) I*sigma3 >>> Pauli(1)*Pauli(1) 1 >>> Pauli(3)**4 1 >>> Pauli(1)*Pauli(2)*Pauli(3) I >>> from sympy.physics.paulialgebra import Pauli >>> Pauli(1, label="tau") tau1 >>> Pauli(1)*Pauli(2, label="tau") sigma1*tau2 >>> Pauli(1, label="tau")*Pauli(2, label="tau") I*tau3 >>> from sympy import I >>> I*(Pauli(2)*Pauli(3)) -sigma1 >>> from sympy.physics.paulialgebra import evaluate_pauli_product >>> f = I*Pauli(2)*Pauli(3) >>> f I*sigma2*sigma3 >>> evaluate_pauli_product(f) -sigma1 """ __slots__ = ("i", "label") def __new__(cls, i, label="sigma"): if not i in [1, 2, 3]: raise IndexError("Invalid Pauli index") obj = Symbol.__new__(cls, "%s%d" %(label,i), commutative=False, hermitian=True) obj.i = i obj.label = label return obj def __getnewargs_ex__(self): return (self.i, self.label), {} def _hashable_content(self): return (self.i, self.label) # FIXME don't work for -I*Pauli(2)*Pauli(3) def __mul__(self, other): if isinstance(other, Pauli): j = self.i k = other.i jlab = self.label klab = other.label if jlab == klab: return delta(j, k) \ + I*epsilon(j, k, 1)*Pauli(1,jlab) \ + I*epsilon(j, k, 2)*Pauli(2,jlab) \ + I*epsilon(j, k, 3)*Pauli(3,jlab) return super().__mul__(other) def _eval_power(b, e): if e.is_Integer and e.is_positive: return super().__pow__(int(e) % 2) def evaluate_pauli_product(arg): '''Help function to evaluate Pauli matrices product with symbolic objects. Parameters ========== arg: symbolic expression that contains Paulimatrices Examples ======== >>> from sympy.physics.paulialgebra import Pauli, evaluate_pauli_product >>> from sympy import I >>> evaluate_pauli_product(I*Pauli(1)*Pauli(2)) -sigma3 >>> from sympy.abc import x >>> evaluate_pauli_product(x**2*Pauli(2)*Pauli(1)) -I*x**2*sigma3 ''' start = arg end = arg if isinstance(arg, Pow) and isinstance(arg.args[0], Pauli): if arg.args[1].is_odd: return arg.args[0] else: return 1 if isinstance(arg, Add): return Add(*[evaluate_pauli_product(part) for part in arg.args]) if isinstance(arg, TensorProduct): return TensorProduct(*[evaluate_pauli_product(part) for part in arg.args]) elif not(isinstance(arg, Mul)): return arg while ((not(start == end)) | ((start == arg) & (end == arg))): start = end tmp = start.as_coeff_mul() sigma_product = 1 com_product = 1 keeper = 1 for el in tmp[1]: if isinstance(el, Pauli): sigma_product *= el elif not(el.is_commutative): if isinstance(el, Pow) and isinstance(el.args[0], Pauli): if el.args[1].is_odd: sigma_product *= el.args[0] elif isinstance(el, TensorProduct): keeper = keeper*sigma_product*\ TensorProduct( *[evaluate_pauli_product(part) for part in el.args] ) sigma_product = 1 else: keeper = keeper*sigma_product*el sigma_product = 1 else: com_product *= el end = (tmp[0]*keeper*sigma_product*com_product) if end == arg: break return end sympy-sympy-1.9/sympy/physics/pring.py000066400000000000000000000040531412543434000202610ustar00rootroot00000000000000from sympy import sqrt, exp, S, pi, I from sympy.physics.quantum.constants import hbar def wavefunction(n, x): """ Returns the wavefunction for particle on ring. Parameters ========== n : The quantum number. Here ``n`` can be positive as well as negative which can be used to describe the direction of motion of particle. x : The angle. Examples ======== >>> from sympy.physics.pring import wavefunction >>> from sympy import Symbol, integrate, pi >>> x=Symbol("x") >>> wavefunction(1, x) sqrt(2)*exp(I*x)/(2*sqrt(pi)) >>> wavefunction(2, x) sqrt(2)*exp(2*I*x)/(2*sqrt(pi)) >>> wavefunction(3, x) sqrt(2)*exp(3*I*x)/(2*sqrt(pi)) The normalization of the wavefunction is: >>> integrate(wavefunction(2, x)*wavefunction(-2, x), (x, 0, 2*pi)) 1 >>> integrate(wavefunction(4, x)*wavefunction(-4, x), (x, 0, 2*pi)) 1 References ========== .. [1] Atkins, Peter W.; Friedman, Ronald (2005). Molecular Quantum Mechanics (4th ed.). Pages 71-73. """ # sympify arguments n, x = S(n), S(x) return exp(n * I * x) / sqrt(2 * pi) def energy(n, m, r): """ Returns the energy of the state corresponding to quantum number ``n``. E=(n**2 * (hcross)**2) / (2 * m * r**2) Parameters ========== n : The quantum number. m : Mass of the particle. r : Radius of circle. Examples ======== >>> from sympy.physics.pring import energy >>> from sympy import Symbol >>> m=Symbol("m") >>> r=Symbol("r") >>> energy(1, m, r) hbar**2/(2*m*r**2) >>> energy(2, m, r) 2*hbar**2/(m*r**2) >>> energy(-2, 2.0, 3.0) 0.111111111111111*hbar**2 References ========== .. [1] Atkins, Peter W.; Friedman, Ronald (2005). Molecular Quantum Mechanics (4th ed.). Pages 71-73. """ n, m, r = S(n), S(m), S(r) if n.is_integer: return (n**2 * hbar**2) / (2 * m * r**2) else: raise ValueError("'n' must be integer") sympy-sympy-1.9/sympy/physics/qho_1d.py000066400000000000000000000037651412543434000203260ustar00rootroot00000000000000from sympy.core import S, pi, Rational from sympy.functions import hermite, sqrt, exp, factorial, Abs from sympy.physics.quantum.constants import hbar def psi_n(n, x, m, omega): """ Returns the wavefunction psi_{n} for the One-dimensional harmonic oscillator. Parameters ========== ``n`` : the "nodal" quantum number. Corresponds to the number of nodes in the wavefunction. ``n >= 0`` ``x`` : x coordinate. ``m`` : Mass of the particle. ``omega`` : Angular frequency of the oscillator. Examples ======== >>> from sympy.physics.qho_1d import psi_n >>> from sympy.abc import m, x, omega >>> psi_n(0, x, m, omega) (m*omega)**(1/4)*exp(-m*omega*x**2/(2*hbar))/(hbar**(1/4)*pi**(1/4)) """ # sympify arguments n, x, m, omega = map(S, [n, x, m, omega]) nu = m * omega / hbar # normalization coefficient C = (nu/pi)**Rational(1, 4) * sqrt(1/(2**n*factorial(n))) return C * exp(-nu* x**2 /2) * hermite(n, sqrt(nu)*x) def E_n(n, omega): """ Returns the Energy of the One-dimensional harmonic oscillator. Parameters ========== ``n`` : The "nodal" quantum number. ``omega`` : The harmonic oscillator angular frequency. Notes ===== The unit of the returned value matches the unit of hw, since the energy is calculated as: E_n = hbar * omega*(n + 1/2) Examples ======== >>> from sympy.physics.qho_1d import E_n >>> from sympy.abc import x, omega >>> E_n(x, omega) hbar*omega*(x + 1/2) """ return hbar * omega * (n + S.Half) def coherent_state(n, alpha): """ Returns for the coherent states of 1D harmonic oscillator. See https://en.wikipedia.org/wiki/Coherent_states Parameters ========== ``n`` : The "nodal" quantum number. ``alpha`` : The eigen value of annihilation operator. """ return exp(- Abs(alpha)**2/2)*(alpha**n)/sqrt(factorial(n)) sympy-sympy-1.9/sympy/physics/quantum/000077500000000000000000000000001412543434000202605ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/quantum/__init__.py000066400000000000000000000032511412543434000223720ustar00rootroot00000000000000# Names exposed by 'from sympy.physics.quantum import *' __all__ = [ 'AntiCommutator', 'qapply', 'Commutator', 'Dagger', 'HilbertSpaceError', 'HilbertSpace', 'TensorProductHilbertSpace', 'TensorPowerHilbertSpace', 'DirectSumHilbertSpace', 'ComplexSpace', 'L2', 'FockSpace', 'InnerProduct', 'Operator', 'HermitianOperator', 'UnitaryOperator', 'IdentityOperator', 'OuterProduct', 'DifferentialOperator', 'represent', 'rep_innerproduct', 'rep_expectation', 'integrate_result', 'get_basis', 'enumerate_states', 'KetBase', 'BraBase', 'StateBase', 'State', 'Ket', 'Bra', 'TimeDepState', 'TimeDepBra', 'TimeDepKet', 'OrthogonalKet', 'OrthogonalBra', 'OrthogonalState', 'Wavefunction', 'TensorProduct', 'tensor_product_simp', 'hbar', 'HBar', ] from .anticommutator import AntiCommutator from .qapply import qapply from .commutator import Commutator from .dagger import Dagger from .hilbert import (HilbertSpaceError, HilbertSpace, TensorProductHilbertSpace, TensorPowerHilbertSpace, DirectSumHilbertSpace, ComplexSpace, L2, FockSpace) from .innerproduct import InnerProduct from .operator import (Operator, HermitianOperator, UnitaryOperator, IdentityOperator, OuterProduct, DifferentialOperator) from .represent import (represent, rep_innerproduct, rep_expectation, integrate_result, get_basis, enumerate_states) from .state import (KetBase, BraBase, StateBase, State, Ket, Bra, TimeDepState, TimeDepBra, TimeDepKet, OrthogonalKet, OrthogonalBra, OrthogonalState, Wavefunction) from .tensorproduct import TensorProduct, tensor_product_simp from .constants import hbar, HBar sympy-sympy-1.9/sympy/physics/quantum/anticommutator.py000066400000000000000000000103741412543434000237050ustar00rootroot00000000000000"""The anti-commutator: ``{A,B} = A*B + B*A``.""" from sympy import S, Expr, Mul, Integer from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.operator import Operator from sympy.physics.quantum.dagger import Dagger __all__ = [ 'AntiCommutator' ] #----------------------------------------------------------------------------- # Anti-commutator #----------------------------------------------------------------------------- class AntiCommutator(Expr): """The standard anticommutator, in an unevaluated state. Explanation =========== Evaluating an anticommutator is defined [1]_ as: ``{A, B} = A*B + B*A``. This class returns the anticommutator in an unevaluated form. To evaluate the anticommutator, use the ``.doit()`` method. Canonical ordering of an anticommutator is ``{A, B}`` for ``A < B``. The arguments of the anticommutator are put into canonical order using ``__cmp__``. If ``B < A``, then ``{A, B}`` is returned as ``{B, A}``. Parameters ========== A : Expr The first argument of the anticommutator {A,B}. B : Expr The second argument of the anticommutator {A,B}. Examples ======== >>> from sympy import symbols >>> from sympy.physics.quantum import AntiCommutator >>> from sympy.physics.quantum import Operator, Dagger >>> x, y = symbols('x,y') >>> A = Operator('A') >>> B = Operator('B') Create an anticommutator and use ``doit()`` to multiply them out. >>> ac = AntiCommutator(A,B); ac {A,B} >>> ac.doit() A*B + B*A The commutator orders it arguments in canonical order: >>> ac = AntiCommutator(B,A); ac {A,B} Commutative constants are factored out: >>> AntiCommutator(3*x*A,x*y*B) 3*x**2*y*{A,B} Adjoint operations applied to the anticommutator are properly applied to the arguments: >>> Dagger(AntiCommutator(A,B)) {Dagger(A),Dagger(B)} References ========== .. [1] https://en.wikipedia.org/wiki/Commutator """ is_commutative = False def __new__(cls, A, B): r = cls.eval(A, B) if r is not None: return r obj = Expr.__new__(cls, A, B) return obj @classmethod def eval(cls, a, b): if not (a and b): return S.Zero if a == b: return Integer(2)*a**2 if a.is_commutative or b.is_commutative: return Integer(2)*a*b # [xA,yB] -> xy*[A,B] ca, nca = a.args_cnc() cb, ncb = b.args_cnc() c_part = ca + cb if c_part: return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb))) # Canonical ordering of arguments #The Commutator [A,B] is on canonical form if A < B. if a.compare(b) == 1: return cls(b, a) def doit(self, **hints): """ Evaluate anticommutator """ A = self.args[0] B = self.args[1] if isinstance(A, Operator) and isinstance(B, Operator): try: comm = A._eval_anticommutator(B, **hints) except NotImplementedError: try: comm = B._eval_anticommutator(A, **hints) except NotImplementedError: comm = None if comm is not None: return comm.doit(**hints) return (A*B + B*A).doit(**hints) def _eval_adjoint(self): return AntiCommutator(Dagger(self.args[0]), Dagger(self.args[1])) def _sympyrepr(self, printer, *args): return "%s(%s,%s)" % ( self.__class__.__name__, printer._print( self.args[0]), printer._print(self.args[1]) ) def _sympystr(self, printer, *args): return "{%s,%s}" % ( printer._print(self.args[0]), printer._print(self.args[1])) def _pretty(self, printer, *args): pform = printer._print(self.args[0], *args) pform = prettyForm(*pform.right(prettyForm(','))) pform = prettyForm(*pform.right(printer._print(self.args[1], *args))) pform = prettyForm(*pform.parens(left='{', right='}')) return pform def _latex(self, printer, *args): return "\\left\\{%s,%s\\right\\}" % tuple([ printer._print(arg, *args) for arg in self.args]) sympy-sympy-1.9/sympy/physics/quantum/boson.py000066400000000000000000000137171412543434000217630ustar00rootroot00000000000000"""Bosonic quantum operators.""" from sympy import Mul, Integer, exp, sqrt, conjugate from sympy.physics.quantum import Operator from sympy.physics.quantum import HilbertSpace, FockSpace, Ket, Bra, IdentityOperator from sympy.functions.special.tensor_functions import KroneckerDelta __all__ = [ 'BosonOp', 'BosonFockKet', 'BosonFockBra', 'BosonCoherentKet', 'BosonCoherentBra' ] class BosonOp(Operator): """A bosonic operator that satisfies [a, Dagger(a)] == 1. Parameters ========== name : str A string that labels the bosonic mode. annihilation : bool A bool that indicates if the bosonic operator is an annihilation (True, default value) or creation operator (False) Examples ======== >>> from sympy.physics.quantum import Dagger, Commutator >>> from sympy.physics.quantum.boson import BosonOp >>> a = BosonOp("a") >>> Commutator(a, Dagger(a)).doit() 1 """ @property def name(self): return self.args[0] @property def is_annihilation(self): return bool(self.args[1]) @classmethod def default_args(self): return ("a", True) def __new__(cls, *args, **hints): if not len(args) in [1, 2]: raise ValueError('1 or 2 parameters expected, got %s' % args) if len(args) == 1: args = (args[0], Integer(1)) if len(args) == 2: args = (args[0], Integer(args[1])) return Operator.__new__(cls, *args) def _eval_commutator_BosonOp(self, other, **hints): if self.name == other.name: # [a^\dagger, a] = -1 if not self.is_annihilation and other.is_annihilation: return Integer(-1) elif 'independent' in hints and hints['independent']: # [a, b] = 0 return Integer(0) return None def _eval_commutator_FermionOp(self, other, **hints): return Integer(0) def _eval_anticommutator_BosonOp(self, other, **hints): if 'independent' in hints and hints['independent']: # {a, b} = 2 * a * b, because [a, b] = 0 return 2 * self * other return None def _eval_adjoint(self): return BosonOp(str(self.name), not self.is_annihilation) def __mul__(self, other): if other == IdentityOperator(2): return self if isinstance(other, Mul): args1 = tuple(arg for arg in other.args if arg.is_commutative) args2 = tuple(arg for arg in other.args if not arg.is_commutative) x = self for y in args2: x = x * y return Mul(*args1) * x return Mul(self, other) def _print_contents_latex(self, printer, *args): if self.is_annihilation: return r'{%s}' % str(self.name) else: return r'{{%s}^\dagger}' % str(self.name) def _print_contents(self, printer, *args): if self.is_annihilation: return r'%s' % str(self.name) else: return r'Dagger(%s)' % str(self.name) def _print_contents_pretty(self, printer, *args): from sympy.printing.pretty.stringpict import prettyForm pform = printer._print(self.args[0], *args) if self.is_annihilation: return pform else: return pform**prettyForm('\N{DAGGER}') class BosonFockKet(Ket): """Fock state ket for a bosonic mode. Parameters ========== n : Number The Fock state number. """ def __new__(cls, n): return Ket.__new__(cls, n) @property def n(self): return self.label[0] @classmethod def dual_class(self): return BosonFockBra @classmethod def _eval_hilbert_space(cls, label): return FockSpace() def _eval_innerproduct_BosonFockBra(self, bra, **hints): return KroneckerDelta(self.n, bra.n) def _apply_operator_BosonOp(self, op, **options): if op.is_annihilation: return sqrt(self.n) * BosonFockKet(self.n - 1) else: return sqrt(self.n + 1) * BosonFockKet(self.n + 1) class BosonFockBra(Bra): """Fock state bra for a bosonic mode. Parameters ========== n : Number The Fock state number. """ def __new__(cls, n): return Bra.__new__(cls, n) @property def n(self): return self.label[0] @classmethod def dual_class(self): return BosonFockKet @classmethod def _eval_hilbert_space(cls, label): return FockSpace() class BosonCoherentKet(Ket): """Coherent state ket for a bosonic mode. Parameters ========== alpha : Number, Symbol The complex amplitude of the coherent state. """ def __new__(cls, alpha): return Ket.__new__(cls, alpha) @property def alpha(self): return self.label[0] @classmethod def dual_class(self): return BosonCoherentBra @classmethod def _eval_hilbert_space(cls, label): return HilbertSpace() def _eval_innerproduct_BosonCoherentBra(self, bra, **hints): if self.alpha == bra.alpha: return Integer(1) else: return exp(-(abs(self.alpha)**2 + abs(bra.alpha)**2 - 2 * conjugate(bra.alpha) * self.alpha)/2) def _apply_operator_BosonOp(self, op, **options): if op.is_annihilation: return self.alpha * self else: return None class BosonCoherentBra(Bra): """Coherent state bra for a bosonic mode. Parameters ========== alpha : Number, Symbol The complex amplitude of the coherent state. """ def __new__(cls, alpha): return Bra.__new__(cls, alpha) @property def alpha(self): return self.label[0] @classmethod def dual_class(self): return BosonCoherentKet def _apply_operator_BosonOp(self, op, **options): if not op.is_annihilation: return self.alpha * self else: return None sympy-sympy-1.9/sympy/physics/quantum/cartesian.py000066400000000000000000000211521412543434000226040ustar00rootroot00000000000000"""Operators and states for 1D cartesian position and momentum. TODO: * Add 3D classes to mappings in operatorset.py """ from sympy import DiracDelta, exp, I, Interval, pi, S, sqrt from sympy.physics.quantum.constants import hbar from sympy.physics.quantum.hilbert import L2 from sympy.physics.quantum.operator import DifferentialOperator, HermitianOperator from sympy.physics.quantum.state import Ket, Bra, State __all__ = [ 'XOp', 'YOp', 'ZOp', 'PxOp', 'X', 'Y', 'Z', 'Px', 'XKet', 'XBra', 'PxKet', 'PxBra', 'PositionState3D', 'PositionKet3D', 'PositionBra3D' ] #------------------------------------------------------------------------- # Position operators #------------------------------------------------------------------------- class XOp(HermitianOperator): """1D cartesian position operator.""" @classmethod def default_args(self): return ("X",) @classmethod def _eval_hilbert_space(self, args): return L2(Interval(S.NegativeInfinity, S.Infinity)) def _eval_commutator_PxOp(self, other): return I*hbar def _apply_operator_XKet(self, ket): return ket.position*ket def _apply_operator_PositionKet3D(self, ket): return ket.position_x*ket def _represent_PxKet(self, basis, *, index=1, **options): states = basis._enumerate_state(2, start_index=index) coord1 = states[0].momentum coord2 = states[1].momentum d = DifferentialOperator(coord1) delta = DiracDelta(coord1 - coord2) return I*hbar*(d*delta) class YOp(HermitianOperator): """ Y cartesian coordinate operator (for 2D or 3D systems) """ @classmethod def default_args(self): return ("Y",) @classmethod def _eval_hilbert_space(self, args): return L2(Interval(S.NegativeInfinity, S.Infinity)) def _apply_operator_PositionKet3D(self, ket): return ket.position_y*ket class ZOp(HermitianOperator): """ Z cartesian coordinate operator (for 3D systems) """ @classmethod def default_args(self): return ("Z",) @classmethod def _eval_hilbert_space(self, args): return L2(Interval(S.NegativeInfinity, S.Infinity)) def _apply_operator_PositionKet3D(self, ket): return ket.position_z*ket #------------------------------------------------------------------------- # Momentum operators #------------------------------------------------------------------------- class PxOp(HermitianOperator): """1D cartesian momentum operator.""" @classmethod def default_args(self): return ("Px",) @classmethod def _eval_hilbert_space(self, args): return L2(Interval(S.NegativeInfinity, S.Infinity)) def _apply_operator_PxKet(self, ket): return ket.momentum*ket def _represent_XKet(self, basis, *, index=1, **options): states = basis._enumerate_state(2, start_index=index) coord1 = states[0].position coord2 = states[1].position d = DifferentialOperator(coord1) delta = DiracDelta(coord1 - coord2) return -I*hbar*(d*delta) X = XOp('X') Y = YOp('Y') Z = ZOp('Z') Px = PxOp('Px') #------------------------------------------------------------------------- # Position eigenstates #------------------------------------------------------------------------- class XKet(Ket): """1D cartesian position eigenket.""" @classmethod def _operators_to_state(self, op, **options): return self.__new__(self, *_lowercase_labels(op), **options) def _state_to_operators(self, op_class, **options): return op_class.__new__(op_class, *_uppercase_labels(self), **options) @classmethod def default_args(self): return ("x",) @classmethod def dual_class(self): return XBra @property def position(self): """The position of the state.""" return self.label[0] def _enumerate_state(self, num_states, **options): return _enumerate_continuous_1D(self, num_states, **options) def _eval_innerproduct_XBra(self, bra, **hints): return DiracDelta(self.position - bra.position) def _eval_innerproduct_PxBra(self, bra, **hints): return exp(-I*self.position*bra.momentum/hbar)/sqrt(2*pi*hbar) class XBra(Bra): """1D cartesian position eigenbra.""" @classmethod def default_args(self): return ("x",) @classmethod def dual_class(self): return XKet @property def position(self): """The position of the state.""" return self.label[0] class PositionState3D(State): """ Base class for 3D cartesian position eigenstates """ @classmethod def _operators_to_state(self, op, **options): return self.__new__(self, *_lowercase_labels(op), **options) def _state_to_operators(self, op_class, **options): return op_class.__new__(op_class, *_uppercase_labels(self), **options) @classmethod def default_args(self): return ("x", "y", "z") @property def position_x(self): """ The x coordinate of the state """ return self.label[0] @property def position_y(self): """ The y coordinate of the state """ return self.label[1] @property def position_z(self): """ The z coordinate of the state """ return self.label[2] class PositionKet3D(Ket, PositionState3D): """ 3D cartesian position eigenket """ def _eval_innerproduct_PositionBra3D(self, bra, **options): x_diff = self.position_x - bra.position_x y_diff = self.position_y - bra.position_y z_diff = self.position_z - bra.position_z return DiracDelta(x_diff)*DiracDelta(y_diff)*DiracDelta(z_diff) @classmethod def dual_class(self): return PositionBra3D # XXX: The type:ignore here is because mypy gives Definition of # "_state_to_operators" in base class "PositionState3D" is incompatible with # definition in base class "BraBase" class PositionBra3D(Bra, PositionState3D): # type: ignore """ 3D cartesian position eigenbra """ @classmethod def dual_class(self): return PositionKet3D #------------------------------------------------------------------------- # Momentum eigenstates #------------------------------------------------------------------------- class PxKet(Ket): """1D cartesian momentum eigenket.""" @classmethod def _operators_to_state(self, op, **options): return self.__new__(self, *_lowercase_labels(op), **options) def _state_to_operators(self, op_class, **options): return op_class.__new__(op_class, *_uppercase_labels(self), **options) @classmethod def default_args(self): return ("px",) @classmethod def dual_class(self): return PxBra @property def momentum(self): """The momentum of the state.""" return self.label[0] def _enumerate_state(self, *args, **options): return _enumerate_continuous_1D(self, *args, **options) def _eval_innerproduct_XBra(self, bra, **hints): return exp(I*self.momentum*bra.position/hbar)/sqrt(2*pi*hbar) def _eval_innerproduct_PxBra(self, bra, **hints): return DiracDelta(self.momentum - bra.momentum) class PxBra(Bra): """1D cartesian momentum eigenbra.""" @classmethod def default_args(self): return ("px",) @classmethod def dual_class(self): return PxKet @property def momentum(self): """The momentum of the state.""" return self.label[0] #------------------------------------------------------------------------- # Global helper functions #------------------------------------------------------------------------- def _enumerate_continuous_1D(*args, **options): state = args[0] num_states = args[1] state_class = state.__class__ index_list = options.pop('index_list', []) if len(index_list) == 0: start_index = options.pop('start_index', 1) index_list = list(range(start_index, start_index + num_states)) enum_states = [0 for i in range(len(index_list))] for i, ind in enumerate(index_list): label = state.args[0] enum_states[i] = state_class(str(label) + "_" + str(ind), **options) return enum_states def _lowercase_labels(ops): if not isinstance(ops, set): ops = [ops] return [str(arg.label[0]).lower() for arg in ops] def _uppercase_labels(ops): if not isinstance(ops, set): ops = [ops] new_args = [str(arg.label[0])[0].upper() + str(arg.label[0])[1:] for arg in ops] return new_args sympy-sympy-1.9/sympy/physics/quantum/cg.py000066400000000000000000000547711412543434000212410ustar00rootroot00000000000000#TODO: # -Implement Clebsch-Gordan symmetries # -Improve simplification method # -Implement new simpifications """Clebsch-Gordon Coefficients.""" from sympy import (Add, expand, Eq, Expr, Mul, Piecewise, Pow, sqrt, Sum, symbols, sympify, Wild) from sympy.printing.pretty.stringpict import prettyForm, stringPict from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.physics.wigner import clebsch_gordan, wigner_3j, wigner_6j, wigner_9j from sympy.printing.precedence import PRECEDENCE __all__ = [ 'CG', 'Wigner3j', 'Wigner6j', 'Wigner9j', 'cg_simp' ] #----------------------------------------------------------------------------- # CG Coefficients #----------------------------------------------------------------------------- class Wigner3j(Expr): """Class for the Wigner-3j symbols. Explanation =========== Wigner 3j-symbols are coefficients determined by the coupling of two angular momenta. When created, they are expressed as symbolic quantities that, for numerical parameters, can be evaluated using the ``.doit()`` method [1]_. Parameters ========== j1, m1, j2, m2, j3, m3 : Number, Symbol Terms determining the angular momentum of coupled angular momentum systems. Examples ======== Declare a Wigner-3j coefficient and calculate its value >>> from sympy.physics.quantum.cg import Wigner3j >>> w3j = Wigner3j(6,0,4,0,2,0) >>> w3j Wigner3j(6, 0, 4, 0, 2, 0) >>> w3j.doit() sqrt(715)/143 See Also ======== CG: Clebsch-Gordan coefficients References ========== .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. """ is_commutative = True def __new__(cls, j1, m1, j2, m2, j3, m3): args = map(sympify, (j1, m1, j2, m2, j3, m3)) return Expr.__new__(cls, *args) @property def j1(self): return self.args[0] @property def m1(self): return self.args[1] @property def j2(self): return self.args[2] @property def m2(self): return self.args[3] @property def j3(self): return self.args[4] @property def m3(self): return self.args[5] @property def is_symbolic(self): return not all([arg.is_number for arg in self.args]) # This is modified from the _print_Matrix method def _pretty(self, printer, *args): m = ((printer._print(self.j1), printer._print(self.m1)), (printer._print(self.j2), printer._print(self.m2)), (printer._print(self.j3), printer._print(self.m3))) hsep = 2 vsep = 1 maxw = [-1]*3 for j in range(3): maxw[j] = max([ m[j][i].width() for i in range(2) ]) D = None for i in range(2): D_row = None for j in range(3): s = m[j][i] wdelta = maxw[j] - s.width() wleft = wdelta //2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) s = prettyForm(*s.left(' '*wleft)) if D_row is None: D_row = s continue D_row = prettyForm(*D_row.right(' '*hsep)) D_row = prettyForm(*D_row.right(s)) if D is None: D = D_row continue for _ in range(vsep): D = prettyForm(*D.below(' ')) D = prettyForm(*D.below(D_row)) D = prettyForm(*D.parens()) return D def _latex(self, printer, *args): label = map(printer._print, (self.j1, self.j2, self.j3, self.m1, self.m2, self.m3)) return r'\left(\begin{array}{ccc} %s & %s & %s \\ %s & %s & %s \end{array}\right)' % \ tuple(label) def doit(self, **hints): if self.is_symbolic: raise ValueError("Coefficients must be numerical") return wigner_3j(self.j1, self.j2, self.j3, self.m1, self.m2, self.m3) class CG(Wigner3j): r"""Class for Clebsch-Gordan coefficient. Explanation =========== Clebsch-Gordan coefficients describe the angular momentum coupling between two systems. The coefficients give the expansion of a coupled total angular momentum state and an uncoupled tensor product state. The Clebsch-Gordan coefficients are defined as [1]_: .. math :: C^{j_3,m_3}_{j_1,m_1,j_2,m_2} = \left\langle j_1,m_1;j_2,m_2 | j_3,m_3\right\rangle Parameters ========== j1, m1, j2, m2 : Number, Symbol Angular momenta of states 1 and 2. j3, m3: Number, Symbol Total angular momentum of the coupled system. Examples ======== Define a Clebsch-Gordan coefficient and evaluate its value >>> from sympy.physics.quantum.cg import CG >>> from sympy import S >>> cg = CG(S(3)/2, S(3)/2, S(1)/2, -S(1)/2, 1, 1) >>> cg CG(3/2, 3/2, 1/2, -1/2, 1, 1) >>> cg.doit() sqrt(3)/2 >>> CG(j1=S(1)/2, m1=-S(1)/2, j2=S(1)/2, m2=+S(1)/2, j3=1, m3=0).doit() sqrt(2)/2 Compare [2]_. See Also ======== Wigner3j: Wigner-3j symbols References ========== .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. .. [2] `Clebsch-Gordan Coefficients, Spherical Harmonics, and d Functions `_ in P.A. Zyla *et al.* (Particle Data Group), Prog. Theor. Exp. Phys. 2020, 083C01 (2020). """ precedence = PRECEDENCE["Pow"] - 1 def doit(self, **hints): if self.is_symbolic: raise ValueError("Coefficients must be numerical") return clebsch_gordan(self.j1, self.j2, self.j3, self.m1, self.m2, self.m3) def _pretty(self, printer, *args): bot = printer._print_seq( (self.j1, self.m1, self.j2, self.m2), delimiter=',') top = printer._print_seq((self.j3, self.m3), delimiter=',') pad = max(top.width(), bot.width()) bot = prettyForm(*bot.left(' ')) top = prettyForm(*top.left(' ')) if not pad == bot.width(): bot = prettyForm(*bot.right(' '*(pad - bot.width()))) if not pad == top.width(): top = prettyForm(*top.right(' '*(pad - top.width()))) s = stringPict('C' + ' '*pad) s = prettyForm(*s.below(bot)) s = prettyForm(*s.above(top)) return s def _latex(self, printer, *args): label = map(printer._print, (self.j3, self.m3, self.j1, self.m1, self.j2, self.m2)) return r'C^{%s,%s}_{%s,%s,%s,%s}' % tuple(label) class Wigner6j(Expr): """Class for the Wigner-6j symbols See Also ======== Wigner3j: Wigner-3j symbols """ def __new__(cls, j1, j2, j12, j3, j, j23): args = map(sympify, (j1, j2, j12, j3, j, j23)) return Expr.__new__(cls, *args) @property def j1(self): return self.args[0] @property def j2(self): return self.args[1] @property def j12(self): return self.args[2] @property def j3(self): return self.args[3] @property def j(self): return self.args[4] @property def j23(self): return self.args[5] @property def is_symbolic(self): return not all([arg.is_number for arg in self.args]) # This is modified from the _print_Matrix method def _pretty(self, printer, *args): m = ((printer._print(self.j1), printer._print(self.j3)), (printer._print(self.j2), printer._print(self.j)), (printer._print(self.j12), printer._print(self.j23))) hsep = 2 vsep = 1 maxw = [-1]*3 for j in range(3): maxw[j] = max([ m[j][i].width() for i in range(2) ]) D = None for i in range(2): D_row = None for j in range(3): s = m[j][i] wdelta = maxw[j] - s.width() wleft = wdelta //2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) s = prettyForm(*s.left(' '*wleft)) if D_row is None: D_row = s continue D_row = prettyForm(*D_row.right(' '*hsep)) D_row = prettyForm(*D_row.right(s)) if D is None: D = D_row continue for _ in range(vsep): D = prettyForm(*D.below(' ')) D = prettyForm(*D.below(D_row)) D = prettyForm(*D.parens(left='{', right='}')) return D def _latex(self, printer, *args): label = map(printer._print, (self.j1, self.j2, self.j12, self.j3, self.j, self.j23)) return r'\left\{\begin{array}{ccc} %s & %s & %s \\ %s & %s & %s \end{array}\right\}' % \ tuple(label) def doit(self, **hints): if self.is_symbolic: raise ValueError("Coefficients must be numerical") return wigner_6j(self.j1, self.j2, self.j12, self.j3, self.j, self.j23) class Wigner9j(Expr): """Class for the Wigner-9j symbols See Also ======== Wigner3j: Wigner-3j symbols """ def __new__(cls, j1, j2, j12, j3, j4, j34, j13, j24, j): args = map(sympify, (j1, j2, j12, j3, j4, j34, j13, j24, j)) return Expr.__new__(cls, *args) @property def j1(self): return self.args[0] @property def j2(self): return self.args[1] @property def j12(self): return self.args[2] @property def j3(self): return self.args[3] @property def j4(self): return self.args[4] @property def j34(self): return self.args[5] @property def j13(self): return self.args[6] @property def j24(self): return self.args[7] @property def j(self): return self.args[8] @property def is_symbolic(self): return not all([arg.is_number for arg in self.args]) # This is modified from the _print_Matrix method def _pretty(self, printer, *args): m = ( (printer._print( self.j1), printer._print(self.j3), printer._print(self.j13)), (printer._print( self.j2), printer._print(self.j4), printer._print(self.j24)), (printer._print(self.j12), printer._print(self.j34), printer._print(self.j))) hsep = 2 vsep = 1 maxw = [-1]*3 for j in range(3): maxw[j] = max([ m[j][i].width() for i in range(3) ]) D = None for i in range(3): D_row = None for j in range(3): s = m[j][i] wdelta = maxw[j] - s.width() wleft = wdelta //2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) s = prettyForm(*s.left(' '*wleft)) if D_row is None: D_row = s continue D_row = prettyForm(*D_row.right(' '*hsep)) D_row = prettyForm(*D_row.right(s)) if D is None: D = D_row continue for _ in range(vsep): D = prettyForm(*D.below(' ')) D = prettyForm(*D.below(D_row)) D = prettyForm(*D.parens(left='{', right='}')) return D def _latex(self, printer, *args): label = map(printer._print, (self.j1, self.j2, self.j12, self.j3, self.j4, self.j34, self.j13, self.j24, self.j)) return r'\left\{\begin{array}{ccc} %s & %s & %s \\ %s & %s & %s \\ %s & %s & %s \end{array}\right\}' % \ tuple(label) def doit(self, **hints): if self.is_symbolic: raise ValueError("Coefficients must be numerical") return wigner_9j(self.j1, self.j2, self.j12, self.j3, self.j4, self.j34, self.j13, self.j24, self.j) def cg_simp(e): """Simplify and combine CG coefficients. Explanation =========== This function uses various symmetry and properties of sums and products of Clebsch-Gordan coefficients to simplify statements involving these terms [1]_. Examples ======== Simplify the sum over CG(a,alpha,0,0,a,alpha) for all alpha to 2*a+1 >>> from sympy.physics.quantum.cg import CG, cg_simp >>> a = CG(1,1,0,0,1,1) >>> b = CG(1,0,0,0,1,0) >>> c = CG(1,-1,0,0,1,-1) >>> cg_simp(a+b+c) 3 See Also ======== CG: Clebsh-Gordan coefficients References ========== .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. """ if isinstance(e, Add): return _cg_simp_add(e) elif isinstance(e, Sum): return _cg_simp_sum(e) elif isinstance(e, Mul): return Mul(*[cg_simp(arg) for arg in e.args]) elif isinstance(e, Pow): return Pow(cg_simp(e.base), e.exp) else: return e def _cg_simp_add(e): #TODO: Improve simplification method """Takes a sum of terms involving Clebsch-Gordan coefficients and simplifies the terms. Explanation =========== First, we create two lists, cg_part, which is all the terms involving CG coefficients, and other_part, which is all other terms. The cg_part list is then passed to the simplification methods, which return the new cg_part and any additional terms that are added to other_part """ cg_part = [] other_part = [] e = expand(e) for arg in e.args: if arg.has(CG): if isinstance(arg, Sum): other_part.append(_cg_simp_sum(arg)) elif isinstance(arg, Mul): terms = 1 for term in arg.args: if isinstance(term, Sum): terms *= _cg_simp_sum(term) else: terms *= term if terms.has(CG): cg_part.append(terms) else: other_part.append(terms) else: cg_part.append(arg) else: other_part.append(arg) cg_part, other = _check_varsh_871_1(cg_part) other_part.append(other) cg_part, other = _check_varsh_871_2(cg_part) other_part.append(other) cg_part, other = _check_varsh_872_9(cg_part) other_part.append(other) return Add(*cg_part) + Add(*other_part) def _check_varsh_871_1(term_list): # Sum( CG(a,alpha,b,0,a,alpha), (alpha, -a, a)) == KroneckerDelta(b,0) a, alpha, b, lt = map(Wild, ('a', 'alpha', 'b', 'lt')) expr = lt*CG(a, alpha, b, 0, a, alpha) simp = (2*a + 1)*KroneckerDelta(b, 0) sign = lt/abs(lt) build_expr = 2*a + 1 index_expr = a + alpha return _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, b, lt), (a, b), build_expr, index_expr) def _check_varsh_871_2(term_list): # Sum((-1)**(a-alpha)*CG(a,alpha,a,-alpha,c,0),(alpha,-a,a)) a, alpha, c, lt = map(Wild, ('a', 'alpha', 'c', 'lt')) expr = lt*CG(a, alpha, a, -alpha, c, 0) simp = sqrt(2*a + 1)*KroneckerDelta(c, 0) sign = (-1)**(a - alpha)*lt/abs(lt) build_expr = 2*a + 1 index_expr = a + alpha return _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, c, lt), (a, c), build_expr, index_expr) def _check_varsh_872_9(term_list): # Sum( CG(a,alpha,b,beta,c,gamma)*CG(a,alpha',b,beta',c,gamma), (gamma, -c, c), (c, abs(a-b), a+b)) a, alpha, alphap, b, beta, betap, c, gamma, lt = map(Wild, ( 'a', 'alpha', 'alphap', 'b', 'beta', 'betap', 'c', 'gamma', 'lt')) # Case alpha==alphap, beta==betap # For numerical alpha,beta expr = lt*CG(a, alpha, b, beta, c, gamma)**2 simp = 1 sign = lt/abs(lt) x = abs(a - b) y = abs(alpha + beta) build_expr = a + b + 1 - Piecewise((x, x > y), (0, Eq(x, y)), (y, y > x)) index_expr = a + b - c term_list, other1 = _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, b, beta, c, gamma, lt), (a, alpha, b, beta), build_expr, index_expr) # For symbolic alpha,beta x = abs(a - b) y = a + b build_expr = (y + 1 - x)*(x + y + 1) index_expr = (c - x)*(x + c) + c + gamma term_list, other2 = _check_cg_simp(expr, simp, sign, lt, term_list, (a, alpha, b, beta, c, gamma, lt), (a, alpha, b, beta), build_expr, index_expr) # Case alpha!=alphap or beta!=betap # Note: this only works with leading term of 1, pattern matching is unable to match when there is a Wild leading term # For numerical alpha,alphap,beta,betap expr = CG(a, alpha, b, beta, c, gamma)*CG(a, alphap, b, betap, c, gamma) simp = KroneckerDelta(alpha, alphap)*KroneckerDelta(beta, betap) sign = sympify(1) x = abs(a - b) y = abs(alpha + beta) build_expr = a + b + 1 - Piecewise((x, x > y), (0, Eq(x, y)), (y, y > x)) index_expr = a + b - c term_list, other3 = _check_cg_simp(expr, simp, sign, sympify(1), term_list, (a, alpha, alphap, b, beta, betap, c, gamma), (a, alpha, alphap, b, beta, betap), build_expr, index_expr) # For symbolic alpha,alphap,beta,betap x = abs(a - b) y = a + b build_expr = (y + 1 - x)*(x + y + 1) index_expr = (c - x)*(x + c) + c + gamma term_list, other4 = _check_cg_simp(expr, simp, sign, sympify(1), term_list, (a, alpha, alphap, b, beta, betap, c, gamma), (a, alpha, alphap, b, beta, betap), build_expr, index_expr) return term_list, other1 + other2 + other4 def _check_cg_simp(expr, simp, sign, lt, term_list, variables, dep_variables, build_index_expr, index_expr): """ Checks for simplifications that can be made, returning a tuple of the simplified list of terms and any terms generated by simplification. Parameters ========== expr: expression The expression with Wild terms that will be matched to the terms in the sum simp: expression The expression with Wild terms that is substituted in place of the CG terms in the case of simplification sign: expression The expression with Wild terms denoting the sign that is on expr that must match lt: expression The expression with Wild terms that gives the leading term of the matched expr term_list: list A list of all of the terms is the sum to be simplified variables: list A list of all the variables that appears in expr dep_variables: list A list of the variables that must match for all the terms in the sum, i.e. the dependent variables build_index_expr: expression Expression with Wild terms giving the number of elements in cg_index index_expr: expression Expression with Wild terms giving the index terms have when storing them to cg_index """ other_part = 0 i = 0 while i < len(term_list): sub_1 = _check_cg(term_list[i], expr, len(variables)) if sub_1 is None: i += 1 continue if not sympify(build_index_expr.subs(sub_1)).is_number: i += 1 continue sub_dep = [(x, sub_1[x]) for x in dep_variables] cg_index = [None]*build_index_expr.subs(sub_1) for j in range(i, len(term_list)): sub_2 = _check_cg(term_list[j], expr.subs(sub_dep), len(variables) - len(dep_variables), sign=(sign.subs(sub_1), sign.subs(sub_dep))) if sub_2 is None: continue if not sympify(index_expr.subs(sub_dep).subs(sub_2)).is_number: continue cg_index[index_expr.subs(sub_dep).subs(sub_2)] = j, expr.subs(lt, 1).subs(sub_dep).subs(sub_2), lt.subs(sub_2), sign.subs(sub_dep).subs(sub_2) if all(i is not None for i in cg_index): min_lt = min(*[ abs(term[2]) for term in cg_index ]) indices = [ term[0] for term in cg_index] indices.sort() indices.reverse() [ term_list.pop(j) for j in indices ] for term in cg_index: if abs(term[2]) > min_lt: term_list.append( (term[2] - min_lt*term[3])*term[1] ) other_part += min_lt*(sign*simp).subs(sub_1) else: i += 1 return term_list, other_part def _check_cg(cg_term, expr, length, sign=None): """Checks whether a term matches the given expression""" # TODO: Check for symmetries matches = cg_term.match(expr) if matches is None: return if sign is not None: if not isinstance(sign, tuple): raise TypeError('sign must be a tuple') if not sign[0] == (sign[1]).subs(matches): return if len(matches) == length: return matches def _cg_simp_sum(e): e = _check_varsh_sum_871_1(e) e = _check_varsh_sum_871_2(e) e = _check_varsh_sum_872_4(e) return e def _check_varsh_sum_871_1(e): a = Wild('a') alpha = symbols('alpha') b = Wild('b') match = e.match(Sum(CG(a, alpha, b, 0, a, alpha), (alpha, -a, a))) if match is not None and len(match) == 2: return ((2*a + 1)*KroneckerDelta(b, 0)).subs(match) return e def _check_varsh_sum_871_2(e): a = Wild('a') alpha = symbols('alpha') c = Wild('c') match = e.match( Sum((-1)**(a - alpha)*CG(a, alpha, a, -alpha, c, 0), (alpha, -a, a))) if match is not None and len(match) == 2: return (sqrt(2*a + 1)*KroneckerDelta(c, 0)).subs(match) return e def _check_varsh_sum_872_4(e): alpha = symbols('alpha') beta = symbols('beta') a = Wild('a') b = Wild('b') c = Wild('c') cp = Wild('cp') gamma = Wild('gamma') gammap = Wild('gammap') cg1 = CG(a, alpha, b, beta, c, gamma) cg2 = CG(a, alpha, b, beta, cp, gammap) match1 = e.match(Sum(cg1*cg2, (alpha, -a, a), (beta, -b, b))) if match1 is not None and len(match1) == 6: return (KroneckerDelta(c, cp)*KroneckerDelta(gamma, gammap)).subs(match1) match2 = e.match(Sum(cg1**2, (alpha, -a, a), (beta, -b, b))) if match2 is not None and len(match2) == 4: return 1 return e def _cg_list(term): if isinstance(term, CG): return (term,), 1, 1 cg = [] coeff = 1 if not (isinstance(term, Mul) or isinstance(term, Pow)): raise NotImplementedError('term must be CG, Add, Mul or Pow') if isinstance(term, Pow) and sympify(term.exp).is_number: if sympify(term.exp).is_number: [ cg.append(term.base) for _ in range(term.exp) ] else: return (term,), 1, 1 if isinstance(term, Mul): for arg in term.args: if isinstance(arg, CG): cg.append(arg) else: coeff *= arg return cg, coeff, coeff/abs(coeff) sympy-sympy-1.9/sympy/physics/quantum/circuitplot.py000066400000000000000000000272511412543434000232020ustar00rootroot00000000000000"""Matplotlib based plotting of quantum circuits. Todo: * Optimize printing of large circuits. * Get this to work with single gates. * Do a better job checking the form of circuits to make sure it is a Mul of Gates. * Get multi-target gates plotting. * Get initial and final states to plot. * Get measurements to plot. Might need to rethink measurement as a gate issue. * Get scale and figsize to be handled in a better way. * Write some tests/examples! """ from typing import List, Dict from sympy import Mul from sympy.external import import_module from sympy.physics.quantum.gate import Gate, OneQubitGate, CGate, CGateS from sympy.core.core import BasicMeta from sympy.core.assumptions import ManagedProperties __all__ = [ 'CircuitPlot', 'circuit_plot', 'labeller', 'Mz', 'Mx', 'CreateOneQubitGate', 'CreateCGate', ] np = import_module('numpy') matplotlib = import_module( 'matplotlib', import_kwargs={'fromlist': ['pyplot']}, catch=(RuntimeError,)) # This is raised in environments that have no display. if np and matplotlib: pyplot = matplotlib.pyplot Line2D = matplotlib.lines.Line2D Circle = matplotlib.patches.Circle #from matplotlib import rc #rc('text',usetex=True) class CircuitPlot: """A class for managing a circuit plot.""" scale = 1.0 fontsize = 20.0 linewidth = 1.0 control_radius = 0.05 not_radius = 0.15 swap_delta = 0.05 labels = [] # type: List[str] inits = {} # type: Dict[str, str] label_buffer = 0.5 def __init__(self, c, nqubits, **kwargs): if not np or not matplotlib: raise ImportError('numpy or matplotlib not available.') self.circuit = c self.ngates = len(self.circuit.args) self.nqubits = nqubits self.update(kwargs) self._create_grid() self._create_figure() self._plot_wires() self._plot_gates() self._finish() def update(self, kwargs): """Load the kwargs into the instance dict.""" self.__dict__.update(kwargs) def _create_grid(self): """Create the grid of wires.""" scale = self.scale wire_grid = np.arange(0.0, self.nqubits*scale, scale, dtype=float) gate_grid = np.arange(0.0, self.ngates*scale, scale, dtype=float) self._wire_grid = wire_grid self._gate_grid = gate_grid def _create_figure(self): """Create the main matplotlib figure.""" self._figure = pyplot.figure( figsize=(self.ngates*self.scale, self.nqubits*self.scale), facecolor='w', edgecolor='w' ) ax = self._figure.add_subplot( 1, 1, 1, frameon=True ) ax.set_axis_off() offset = 0.5*self.scale ax.set_xlim(self._gate_grid[0] - offset, self._gate_grid[-1] + offset) ax.set_ylim(self._wire_grid[0] - offset, self._wire_grid[-1] + offset) ax.set_aspect('equal') self._axes = ax def _plot_wires(self): """Plot the wires of the circuit diagram.""" xstart = self._gate_grid[0] xstop = self._gate_grid[-1] xdata = (xstart - self.scale, xstop + self.scale) for i in range(self.nqubits): ydata = (self._wire_grid[i], self._wire_grid[i]) line = Line2D( xdata, ydata, color='k', lw=self.linewidth ) self._axes.add_line(line) if self.labels: init_label_buffer = 0 if self.inits.get(self.labels[i]): init_label_buffer = 0.25 self._axes.text( xdata[0]-self.label_buffer-init_label_buffer,ydata[0], render_label(self.labels[i],self.inits), size=self.fontsize, color='k',ha='center',va='center') self._plot_measured_wires() def _plot_measured_wires(self): ismeasured = self._measurements() xstop = self._gate_grid[-1] dy = 0.04 # amount to shift wires when doubled # Plot doubled wires after they are measured for im in ismeasured: xdata = (self._gate_grid[ismeasured[im]],xstop+self.scale) ydata = (self._wire_grid[im]+dy,self._wire_grid[im]+dy) line = Line2D( xdata, ydata, color='k', lw=self.linewidth ) self._axes.add_line(line) # Also double any controlled lines off these wires for i,g in enumerate(self._gates()): if isinstance(g, CGate) or isinstance(g, CGateS): wires = g.controls + g.targets for wire in wires: if wire in ismeasured and \ self._gate_grid[i] > self._gate_grid[ismeasured[wire]]: ydata = min(wires), max(wires) xdata = self._gate_grid[i]-dy, self._gate_grid[i]-dy line = Line2D( xdata, ydata, color='k', lw=self.linewidth ) self._axes.add_line(line) def _gates(self): """Create a list of all gates in the circuit plot.""" gates = [] if isinstance(self.circuit, Mul): for g in reversed(self.circuit.args): if isinstance(g, Gate): gates.append(g) elif isinstance(self.circuit, Gate): gates.append(self.circuit) return gates def _plot_gates(self): """Iterate through the gates and plot each of them.""" for i, gate in enumerate(self._gates()): gate.plot_gate(self, i) def _measurements(self): """Return a dict {i:j} where i is the index of the wire that has been measured, and j is the gate where the wire is measured. """ ismeasured = {} for i,g in enumerate(self._gates()): if getattr(g,'measurement',False): for target in g.targets: if target in ismeasured: if ismeasured[target] > i: ismeasured[target] = i else: ismeasured[target] = i return ismeasured def _finish(self): # Disable clipping to make panning work well for large circuits. for o in self._figure.findobj(): o.set_clip_on(False) def one_qubit_box(self, t, gate_idx, wire_idx): """Draw a box for a single qubit gate.""" x = self._gate_grid[gate_idx] y = self._wire_grid[wire_idx] self._axes.text( x, y, t, color='k', ha='center', va='center', bbox=dict(ec='k', fc='w', fill=True, lw=self.linewidth), size=self.fontsize ) def two_qubit_box(self, t, gate_idx, wire_idx): """Draw a box for a two qubit gate. Doesn't work yet. """ # x = self._gate_grid[gate_idx] # y = self._wire_grid[wire_idx]+0.5 print(self._gate_grid) print(self._wire_grid) # unused: # obj = self._axes.text( # x, y, t, # color='k', # ha='center', # va='center', # bbox=dict(ec='k', fc='w', fill=True, lw=self.linewidth), # size=self.fontsize # ) def control_line(self, gate_idx, min_wire, max_wire): """Draw a vertical control line.""" xdata = (self._gate_grid[gate_idx], self._gate_grid[gate_idx]) ydata = (self._wire_grid[min_wire], self._wire_grid[max_wire]) line = Line2D( xdata, ydata, color='k', lw=self.linewidth ) self._axes.add_line(line) def control_point(self, gate_idx, wire_idx): """Draw a control point.""" x = self._gate_grid[gate_idx] y = self._wire_grid[wire_idx] radius = self.control_radius c = Circle( (x, y), radius*self.scale, ec='k', fc='k', fill=True, lw=self.linewidth ) self._axes.add_patch(c) def not_point(self, gate_idx, wire_idx): """Draw a NOT gates as the circle with plus in the middle.""" x = self._gate_grid[gate_idx] y = self._wire_grid[wire_idx] radius = self.not_radius c = Circle( (x, y), radius, ec='k', fc='w', fill=False, lw=self.linewidth ) self._axes.add_patch(c) l = Line2D( (x, x), (y - radius, y + radius), color='k', lw=self.linewidth ) self._axes.add_line(l) def swap_point(self, gate_idx, wire_idx): """Draw a swap point as a cross.""" x = self._gate_grid[gate_idx] y = self._wire_grid[wire_idx] d = self.swap_delta l1 = Line2D( (x - d, x + d), (y - d, y + d), color='k', lw=self.linewidth ) l2 = Line2D( (x - d, x + d), (y + d, y - d), color='k', lw=self.linewidth ) self._axes.add_line(l1) self._axes.add_line(l2) def circuit_plot(c, nqubits, **kwargs): """Draw the circuit diagram for the circuit with nqubits. Parameters ========== c : circuit The circuit to plot. Should be a product of Gate instances. nqubits : int The number of qubits to include in the circuit. Must be at least as big as the largest `min_qubits`` of the gates. """ return CircuitPlot(c, nqubits, **kwargs) def render_label(label, inits={}): """Slightly more flexible way to render labels. >>> from sympy.physics.quantum.circuitplot import render_label >>> render_label('q0') '$\\\\left|q0\\\\right\\\\rangle$' >>> render_label('q0', {'q0':'0'}) '$\\\\left|q0\\\\right\\\\rangle=\\\\left|0\\\\right\\\\rangle$' """ init = inits.get(label) if init: return r'$\left|%s\right\rangle=\left|%s\right\rangle$' % (label, init) return r'$\left|%s\right\rangle$' % label def labeller(n, symbol='q'): """Autogenerate labels for wires of quantum circuits. Parameters ========== n : int number of qubits in the circuit. symbol : string A character string to precede all gate labels. E.g. 'q_0', 'q_1', etc. >>> from sympy.physics.quantum.circuitplot import labeller >>> labeller(2) ['q_1', 'q_0'] >>> labeller(3,'j') ['j_2', 'j_1', 'j_0'] """ return ['%s_%d' % (symbol,n-i-1) for i in range(n)] class Mz(OneQubitGate): """Mock-up of a z measurement gate. This is in circuitplot rather than gate.py because it's not a real gate, it just draws one. """ measurement = True gate_name='Mz' gate_name_latex='M_z' class Mx(OneQubitGate): """Mock-up of an x measurement gate. This is in circuitplot rather than gate.py because it's not a real gate, it just draws one. """ measurement = True gate_name='Mx' gate_name_latex='M_x' class CreateOneQubitGate(ManagedProperties): def __new__(mcl, name, latexname=None): if not latexname: latexname = name return BasicMeta.__new__(mcl, name + "Gate", (OneQubitGate,), {'gate_name': name, 'gate_name_latex': latexname}) def CreateCGate(name, latexname=None): """Use a lexical closure to make a controlled gate. """ if not latexname: latexname = name onequbitgate = CreateOneQubitGate(name, latexname) def ControlledGate(ctrls,target): return CGate(tuple(ctrls),onequbitgate(target)) return ControlledGate sympy-sympy-1.9/sympy/physics/quantum/circuitutils.py000066400000000000000000000327571412543434000233730ustar00rootroot00000000000000"""Primitive circuit operations on quantum circuits.""" from functools import reduce from sympy import Symbol, Tuple, Mul, sympify, default_sort_key from sympy.utilities import numbered_symbols from sympy.physics.quantum.gate import Gate __all__ = [ 'kmp_table', 'find_subcircuit', 'replace_subcircuit', 'convert_to_symbolic_indices', 'convert_to_real_indices', 'random_reduce', 'random_insert' ] def kmp_table(word): """Build the 'partial match' table of the Knuth-Morris-Pratt algorithm. Note: This is applicable to strings or quantum circuits represented as tuples. """ # Current position in subcircuit pos = 2 # Beginning position of candidate substring that # may reappear later in word cnd = 0 # The 'partial match' table that helps one determine # the next location to start substring search table = list() table.append(-1) table.append(0) while pos < len(word): if word[pos - 1] == word[cnd]: cnd = cnd + 1 table.append(cnd) pos = pos + 1 elif cnd > 0: cnd = table[cnd] else: table.append(0) pos = pos + 1 return table def find_subcircuit(circuit, subcircuit, start=0, end=0): """Finds the subcircuit in circuit, if it exists. Explanation =========== If the subcircuit exists, the index of the start of the subcircuit in circuit is returned; otherwise, -1 is returned. The algorithm that is implemented is the Knuth-Morris-Pratt algorithm. Parameters ========== circuit : tuple, Gate or Mul A tuple of Gates or Mul representing a quantum circuit subcircuit : tuple, Gate or Mul A tuple of Gates or Mul to find in circuit start : int The location to start looking for subcircuit. If start is the same or past end, -1 is returned. end : int The last place to look for a subcircuit. If end is less than 1 (one), then the length of circuit is taken to be end. Examples ======== Find the first instance of a subcircuit: >>> from sympy.physics.quantum.circuitutils import find_subcircuit >>> from sympy.physics.quantum.gate import X, Y, Z, H >>> circuit = X(0)*Z(0)*Y(0)*H(0) >>> subcircuit = Z(0)*Y(0) >>> find_subcircuit(circuit, subcircuit) 1 Find the first instance starting at a specific position: >>> find_subcircuit(circuit, subcircuit, start=1) 1 >>> find_subcircuit(circuit, subcircuit, start=2) -1 >>> circuit = circuit*subcircuit >>> find_subcircuit(circuit, subcircuit, start=2) 4 Find the subcircuit within some interval: >>> find_subcircuit(circuit, subcircuit, start=2, end=2) -1 """ if isinstance(circuit, Mul): circuit = circuit.args if isinstance(subcircuit, Mul): subcircuit = subcircuit.args if len(subcircuit) == 0 or len(subcircuit) > len(circuit): return -1 if end < 1: end = len(circuit) # Location in circuit pos = start # Location in the subcircuit index = 0 # 'Partial match' table table = kmp_table(subcircuit) while (pos + index) < end: if subcircuit[index] == circuit[pos + index]: index = index + 1 else: pos = pos + index - table[index] index = table[index] if table[index] > -1 else 0 if index == len(subcircuit): return pos return -1 def replace_subcircuit(circuit, subcircuit, replace=None, pos=0): """Replaces a subcircuit with another subcircuit in circuit, if it exists. Explanation =========== If multiple instances of subcircuit exists, the first instance is replaced. The position to being searching from (if different from 0) may be optionally given. If subcircuit can't be found, circuit is returned. Parameters ========== circuit : tuple, Gate or Mul A quantum circuit. subcircuit : tuple, Gate or Mul The circuit to be replaced. replace : tuple, Gate or Mul The replacement circuit. pos : int The location to start search and replace subcircuit, if it exists. This may be used if it is known beforehand that multiple instances exist, and it is desirable to replace a specific instance. If a negative number is given, pos will be defaulted to 0. Examples ======== Find and remove the subcircuit: >>> from sympy.physics.quantum.circuitutils import replace_subcircuit >>> from sympy.physics.quantum.gate import X, Y, Z, H >>> circuit = X(0)*Z(0)*Y(0)*H(0)*X(0)*H(0)*Y(0) >>> subcircuit = Z(0)*Y(0) >>> replace_subcircuit(circuit, subcircuit) (X(0), H(0), X(0), H(0), Y(0)) Remove the subcircuit given a starting search point: >>> replace_subcircuit(circuit, subcircuit, pos=1) (X(0), H(0), X(0), H(0), Y(0)) >>> replace_subcircuit(circuit, subcircuit, pos=2) (X(0), Z(0), Y(0), H(0), X(0), H(0), Y(0)) Replace the subcircuit: >>> replacement = H(0)*Z(0) >>> replace_subcircuit(circuit, subcircuit, replace=replacement) (X(0), H(0), Z(0), H(0), X(0), H(0), Y(0)) """ if pos < 0: pos = 0 if isinstance(circuit, Mul): circuit = circuit.args if isinstance(subcircuit, Mul): subcircuit = subcircuit.args if isinstance(replace, Mul): replace = replace.args elif replace is None: replace = () # Look for the subcircuit starting at pos loc = find_subcircuit(circuit, subcircuit, start=pos) # If subcircuit was found if loc > -1: # Get the gates to the left of subcircuit left = circuit[0:loc] # Get the gates to the right of subcircuit right = circuit[loc + len(subcircuit):len(circuit)] # Recombine the left and right side gates into a circuit circuit = left + replace + right return circuit def _sympify_qubit_map(mapping): new_map = {} for key in mapping: new_map[key] = sympify(mapping[key]) return new_map def convert_to_symbolic_indices(seq, start=None, gen=None, qubit_map=None): """Returns the circuit with symbolic indices and the dictionary mapping symbolic indices to real indices. The mapping is 1 to 1 and onto (bijective). Parameters ========== seq : tuple, Gate/Integer/tuple or Mul A tuple of Gate, Integer, or tuple objects, or a Mul start : Symbol An optional starting symbolic index gen : object An optional numbered symbol generator qubit_map : dict An existing mapping of symbolic indices to real indices All symbolic indices have the format 'i#', where # is some number >= 0. """ if isinstance(seq, Mul): seq = seq.args # A numbered symbol generator index_gen = numbered_symbols(prefix='i', start=-1) cur_ndx = next(index_gen) # keys are symbolic indices; values are real indices ndx_map = {} def create_inverse_map(symb_to_real_map): rev_items = lambda item: tuple([item[1], item[0]]) return dict(map(rev_items, symb_to_real_map.items())) if start is not None: if not isinstance(start, Symbol): msg = 'Expected Symbol for starting index, got %r.' % start raise TypeError(msg) cur_ndx = start if gen is not None: if not isinstance(gen, numbered_symbols().__class__): msg = 'Expected a generator, got %r.' % gen raise TypeError(msg) index_gen = gen if qubit_map is not None: if not isinstance(qubit_map, dict): msg = ('Expected dict for existing map, got ' + '%r.' % qubit_map) raise TypeError(msg) ndx_map = qubit_map ndx_map = _sympify_qubit_map(ndx_map) # keys are real indices; keys are symbolic indices inv_map = create_inverse_map(ndx_map) sym_seq = () for item in seq: # Nested items, so recurse if isinstance(item, Gate): result = convert_to_symbolic_indices(item.args, qubit_map=ndx_map, start=cur_ndx, gen=index_gen) sym_item, new_map, cur_ndx, index_gen = result ndx_map.update(new_map) inv_map = create_inverse_map(ndx_map) elif isinstance(item, tuple) or isinstance(item, Tuple): result = convert_to_symbolic_indices(item, qubit_map=ndx_map, start=cur_ndx, gen=index_gen) sym_item, new_map, cur_ndx, index_gen = result ndx_map.update(new_map) inv_map = create_inverse_map(ndx_map) elif item in inv_map: sym_item = inv_map[item] else: cur_ndx = next(gen) ndx_map[cur_ndx] = item inv_map[item] = cur_ndx sym_item = cur_ndx if isinstance(item, Gate): sym_item = item.__class__(*sym_item) sym_seq = sym_seq + (sym_item,) return sym_seq, ndx_map, cur_ndx, index_gen def convert_to_real_indices(seq, qubit_map): """Returns the circuit with real indices. Parameters ========== seq : tuple, Gate/Integer/tuple or Mul A tuple of Gate, Integer, or tuple objects or a Mul qubit_map : dict A dictionary mapping symbolic indices to real indices. Examples ======== Change the symbolic indices to real integers: >>> from sympy import symbols >>> from sympy.physics.quantum.circuitutils import convert_to_real_indices >>> from sympy.physics.quantum.gate import X, Y, H >>> i0, i1 = symbols('i:2') >>> index_map = {i0 : 0, i1 : 1} >>> convert_to_real_indices(X(i0)*Y(i1)*H(i0)*X(i1), index_map) (X(0), Y(1), H(0), X(1)) """ if isinstance(seq, Mul): seq = seq.args if not isinstance(qubit_map, dict): msg = 'Expected dict for qubit_map, got %r.' % qubit_map raise TypeError(msg) qubit_map = _sympify_qubit_map(qubit_map) real_seq = () for item in seq: # Nested items, so recurse if isinstance(item, Gate): real_item = convert_to_real_indices(item.args, qubit_map) elif isinstance(item, tuple) or isinstance(item, Tuple): real_item = convert_to_real_indices(item, qubit_map) else: real_item = qubit_map[item] if isinstance(item, Gate): real_item = item.__class__(*real_item) real_seq = real_seq + (real_item,) return real_seq def random_reduce(circuit, gate_ids, seed=None): """Shorten the length of a quantum circuit. Explanation =========== random_reduce looks for circuit identities in circuit, randomly chooses one to remove, and returns a shorter yet equivalent circuit. If no identities are found, the same circuit is returned. Parameters ========== circuit : Gate tuple of Mul A tuple of Gates representing a quantum circuit gate_ids : list, GateIdentity List of gate identities to find in circuit seed : int or list seed used for _randrange; to override the random selection, provide a list of integers: the elements of gate_ids will be tested in the order given by the list """ from sympy.testing.randtest import _randrange if not gate_ids: return circuit if isinstance(circuit, Mul): circuit = circuit.args ids = flatten_ids(gate_ids) # Create the random integer generator with the seed randrange = _randrange(seed) # Look for an identity in the circuit while ids: i = randrange(len(ids)) id = ids.pop(i) if find_subcircuit(circuit, id) != -1: break else: # no identity was found return circuit # return circuit with the identity removed return replace_subcircuit(circuit, id) def random_insert(circuit, choices, seed=None): """Insert a circuit into another quantum circuit. Explanation =========== random_insert randomly chooses a location in the circuit to insert a randomly selected circuit from amongst the given choices. Parameters ========== circuit : Gate tuple or Mul A tuple or Mul of Gates representing a quantum circuit choices : list Set of circuit choices seed : int or list seed used for _randrange; to override the random selections, give a list two integers, [i, j] where i is the circuit location where choice[j] will be inserted. Notes ===== Indices for insertion should be [0, n] if n is the length of the circuit. """ from sympy.testing.randtest import _randrange if not choices: return circuit if isinstance(circuit, Mul): circuit = circuit.args # get the location in the circuit and the element to insert from choices randrange = _randrange(seed) loc = randrange(len(circuit) + 1) choice = choices[randrange(len(choices))] circuit = list(circuit) circuit[loc: loc] = choice return tuple(circuit) # Flatten the GateIdentity objects (with gate rules) into one single list def flatten_ids(ids): collapse = lambda acc, an_id: acc + sorted(an_id.equivalent_ids, key=default_sort_key) ids = reduce(collapse, ids, []) ids.sort(key=default_sort_key) return ids sympy-sympy-1.9/sympy/physics/quantum/commutator.py000066400000000000000000000163471412543434000230370ustar00rootroot00000000000000"""The commutator: [A,B] = A*B - B*A.""" from sympy import S, Expr, Mul, Add, Pow from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.operator import Operator __all__ = [ 'Commutator' ] #----------------------------------------------------------------------------- # Commutator #----------------------------------------------------------------------------- class Commutator(Expr): """The standard commutator, in an unevaluated state. Explanation =========== Evaluating a commutator is defined [1]_ as: ``[A, B] = A*B - B*A``. This class returns the commutator in an unevaluated form. To evaluate the commutator, use the ``.doit()`` method. Canonical ordering of a commutator is ``[A, B]`` for ``A < B``. The arguments of the commutator are put into canonical order using ``__cmp__``. If ``B < A``, then ``[B, A]`` is returned as ``-[A, B]``. Parameters ========== A : Expr The first argument of the commutator [A,B]. B : Expr The second argument of the commutator [A,B]. Examples ======== >>> from sympy.physics.quantum import Commutator, Dagger, Operator >>> from sympy.abc import x, y >>> A = Operator('A') >>> B = Operator('B') >>> C = Operator('C') Create a commutator and use ``.doit()`` to evaluate it: >>> comm = Commutator(A, B) >>> comm [A,B] >>> comm.doit() A*B - B*A The commutator orders it arguments in canonical order: >>> comm = Commutator(B, A); comm -[A,B] Commutative constants are factored out: >>> Commutator(3*x*A, x*y*B) 3*x**2*y*[A,B] Using ``.expand(commutator=True)``, the standard commutator expansion rules can be applied: >>> Commutator(A+B, C).expand(commutator=True) [A,C] + [B,C] >>> Commutator(A, B+C).expand(commutator=True) [A,B] + [A,C] >>> Commutator(A*B, C).expand(commutator=True) [A,C]*B + A*[B,C] >>> Commutator(A, B*C).expand(commutator=True) [A,B]*C + B*[A,C] Adjoint operations applied to the commutator are properly applied to the arguments: >>> Dagger(Commutator(A, B)) -[Dagger(A),Dagger(B)] References ========== .. [1] https://en.wikipedia.org/wiki/Commutator """ is_commutative = False def __new__(cls, A, B): r = cls.eval(A, B) if r is not None: return r obj = Expr.__new__(cls, A, B) return obj @classmethod def eval(cls, a, b): if not (a and b): return S.Zero if a == b: return S.Zero if a.is_commutative or b.is_commutative: return S.Zero # [xA,yB] -> xy*[A,B] ca, nca = a.args_cnc() cb, ncb = b.args_cnc() c_part = ca + cb if c_part: return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb))) # Canonical ordering of arguments # The Commutator [A, B] is in canonical form if A < B. if a.compare(b) == 1: return S.NegativeOne*cls(b, a) def _expand_pow(self, A, B, sign): exp = A.exp if not exp.is_integer or not exp.is_constant() or abs(exp) <= 1: # nothing to do return self base = A.base if exp.is_negative: base = A.base**-1 exp = -exp comm = Commutator(base, B).expand(commutator=True) result = base**(exp - 1) * comm for i in range(1, exp): result += base**(exp - 1 - i) * comm * base**i return sign*result.expand() def _eval_expand_commutator(self, **hints): A = self.args[0] B = self.args[1] if isinstance(A, Add): # [A + B, C] -> [A, C] + [B, C] sargs = [] for term in A.args: comm = Commutator(term, B) if isinstance(comm, Commutator): comm = comm._eval_expand_commutator() sargs.append(comm) return Add(*sargs) elif isinstance(B, Add): # [A, B + C] -> [A, B] + [A, C] sargs = [] for term in B.args: comm = Commutator(A, term) if isinstance(comm, Commutator): comm = comm._eval_expand_commutator() sargs.append(comm) return Add(*sargs) elif isinstance(A, Mul): # [A*B, C] -> A*[B, C] + [A, C]*B a = A.args[0] b = Mul(*A.args[1:]) c = B comm1 = Commutator(b, c) comm2 = Commutator(a, c) if isinstance(comm1, Commutator): comm1 = comm1._eval_expand_commutator() if isinstance(comm2, Commutator): comm2 = comm2._eval_expand_commutator() first = Mul(a, comm1) second = Mul(comm2, b) return Add(first, second) elif isinstance(B, Mul): # [A, B*C] -> [A, B]*C + B*[A, C] a = A b = B.args[0] c = Mul(*B.args[1:]) comm1 = Commutator(a, b) comm2 = Commutator(a, c) if isinstance(comm1, Commutator): comm1 = comm1._eval_expand_commutator() if isinstance(comm2, Commutator): comm2 = comm2._eval_expand_commutator() first = Mul(comm1, c) second = Mul(b, comm2) return Add(first, second) elif isinstance(A, Pow): # [A**n, C] -> A**(n - 1)*[A, C] + A**(n - 2)*[A, C]*A + ... + [A, C]*A**(n-1) return self._expand_pow(A, B, 1) elif isinstance(B, Pow): # [A, C**n] -> C**(n - 1)*[C, A] + C**(n - 2)*[C, A]*C + ... + [C, A]*C**(n-1) return self._expand_pow(B, A, -1) # No changes, so return self return self def doit(self, **hints): """ Evaluate commutator """ A = self.args[0] B = self.args[1] if isinstance(A, Operator) and isinstance(B, Operator): try: comm = A._eval_commutator(B, **hints) except NotImplementedError: try: comm = -1*B._eval_commutator(A, **hints) except NotImplementedError: comm = None if comm is not None: return comm.doit(**hints) return (A*B - B*A).doit(**hints) def _eval_adjoint(self): return Commutator(Dagger(self.args[1]), Dagger(self.args[0])) def _sympyrepr(self, printer, *args): return "%s(%s,%s)" % ( self.__class__.__name__, printer._print( self.args[0]), printer._print(self.args[1]) ) def _sympystr(self, printer, *args): return "[%s,%s]" % ( printer._print(self.args[0]), printer._print(self.args[1])) def _pretty(self, printer, *args): pform = printer._print(self.args[0], *args) pform = prettyForm(*pform.right(prettyForm(','))) pform = prettyForm(*pform.right(printer._print(self.args[1], *args))) pform = prettyForm(*pform.parens(left='[', right=']')) return pform def _latex(self, printer, *args): return "\\left[%s,%s\\right]" % tuple([ printer._print(arg, *args) for arg in self.args]) sympy-sympy-1.9/sympy/physics/quantum/constants.py000066400000000000000000000026141412543434000226510ustar00rootroot00000000000000"""Constants (like hbar) related to quantum mechanics.""" from sympy.core.numbers import NumberSymbol from sympy.core.singleton import Singleton from sympy.printing.pretty.stringpict import prettyForm import mpmath.libmp as mlib #----------------------------------------------------------------------------- # Constants #----------------------------------------------------------------------------- __all__ = [ 'hbar', 'HBar', ] class HBar(NumberSymbol, metaclass=Singleton): """Reduced Plank's constant in numerical and symbolic form [1]_. Examples ======== >>> from sympy.physics.quantum.constants import hbar >>> hbar.evalf() 1.05457162000000e-34 References ========== .. [1] https://en.wikipedia.org/wiki/Planck_constant """ is_real = True is_positive = True is_negative = False is_irrational = True __slots__ = () def _as_mpf_val(self, prec): return mlib.from_float(1.05457162e-34, prec) def _sympyrepr(self, printer, *args): return 'HBar()' def _sympystr(self, printer, *args): return 'hbar' def _pretty(self, printer, *args): if printer._use_unicode: return prettyForm('\N{PLANCK CONSTANT OVER TWO PI}') return prettyForm('hbar') def _latex(self, printer, *args): return r'\hbar' # Create an instance for everyone to use. hbar = HBar() sympy-sympy-1.9/sympy/physics/quantum/dagger.py000066400000000000000000000045741412543434000220750ustar00rootroot00000000000000"""Hermitian conjugation.""" from sympy.core import Expr, Mul from sympy.functions.elementary.complexes import adjoint __all__ = [ 'Dagger' ] class Dagger(adjoint): """General Hermitian conjugate operation. Explanation =========== Take the Hermetian conjugate of an argument [1]_. For matrices this operation is equivalent to transpose and complex conjugate [2]_. Parameters ========== arg : Expr The sympy expression that we want to take the dagger of. Examples ======== Daggering various quantum objects: >>> from sympy.physics.quantum.dagger import Dagger >>> from sympy.physics.quantum.state import Ket, Bra >>> from sympy.physics.quantum.operator import Operator >>> Dagger(Ket('psi')) >> Dagger(Bra('phi')) |phi> >>> Dagger(Operator('A')) Dagger(A) Inner and outer products:: >>> from sympy.physics.quantum import InnerProduct, OuterProduct >>> Dagger(InnerProduct(Bra('a'), Ket('b'))) >>> Dagger(OuterProduct(Ket('a'), Bra('b'))) |b>>> A = Operator('A') >>> B = Operator('B') >>> Dagger(A*B) Dagger(B)*Dagger(A) >>> Dagger(A+B) Dagger(A) + Dagger(B) >>> Dagger(A**2) Dagger(A)**2 Dagger also seamlessly handles complex numbers and matrices:: >>> from sympy import Matrix, I >>> m = Matrix([[1,I],[2,I]]) >>> m Matrix([ [1, I], [2, I]]) >>> Dagger(m) Matrix([ [ 1, 2], [-I, -I]]) References ========== .. [1] https://en.wikipedia.org/wiki/Hermitian_adjoint .. [2] https://en.wikipedia.org/wiki/Hermitian_transpose """ def __new__(cls, arg): if hasattr(arg, 'adjoint'): obj = arg.adjoint() elif hasattr(arg, 'conjugate') and hasattr(arg, 'transpose'): obj = arg.conjugate().transpose() if obj is not None: return obj return Expr.__new__(cls, arg) def __mul__(self, other): from sympy.physics.quantum import IdentityOperator if isinstance(other, IdentityOperator): return self return Mul(self, other) adjoint.__name__ = "Dagger" adjoint._sympyrepr = lambda a, b: "Dagger(%s)" % b._print(a.args[0]) sympy-sympy-1.9/sympy/physics/quantum/density.py000066400000000000000000000224311412543434000223130ustar00rootroot00000000000000from itertools import product from sympy import Tuple, Add, Mul, Matrix, log, expand, S from sympy.core.trace import Tr from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.operator import HermitianOperator from sympy.physics.quantum.represent import represent from sympy.physics.quantum.matrixutils import numpy_ndarray, scipy_sparse_matrix, to_numpy from sympy.physics.quantum.tensorproduct import TensorProduct, tensor_product_simp class Density(HermitianOperator): """Density operator for representing mixed states. TODO: Density operator support for Qubits Parameters ========== values : tuples/lists Each tuple/list should be of form (state, prob) or [state,prob] Examples ======== Create a density operator with 2 states represented by Kets. >>> from sympy.physics.quantum.state import Ket >>> from sympy.physics.quantum.density import Density >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) >>> d Density((|0>, 0.5),(|1>, 0.5)) """ @classmethod def _eval_args(cls, args): # call this to qsympify the args args = super()._eval_args(args) for arg in args: # Check if arg is a tuple if not (isinstance(arg, Tuple) and len(arg) == 2): raise ValueError("Each argument should be of form [state,prob]" " or ( state, prob )") return args def states(self): """Return list of all states. Examples ======== >>> from sympy.physics.quantum.state import Ket >>> from sympy.physics.quantum.density import Density >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) >>> d.states() (|0>, |1>) """ return Tuple(*[arg[0] for arg in self.args]) def probs(self): """Return list of all probabilities. Examples ======== >>> from sympy.physics.quantum.state import Ket >>> from sympy.physics.quantum.density import Density >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) >>> d.probs() (0.5, 0.5) """ return Tuple(*[arg[1] for arg in self.args]) def get_state(self, index): """Return specific state by index. Parameters ========== index : index of state to be returned Examples ======== >>> from sympy.physics.quantum.state import Ket >>> from sympy.physics.quantum.density import Density >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) >>> d.states()[1] |1> """ state = self.args[index][0] return state def get_prob(self, index): """Return probability of specific state by index. Parameters =========== index : index of states whose probability is returned. Examples ======== >>> from sympy.physics.quantum.state import Ket >>> from sympy.physics.quantum.density import Density >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) >>> d.probs()[1] 0.500000000000000 """ prob = self.args[index][1] return prob def apply_op(self, op): """op will operate on each individual state. Parameters ========== op : Operator Examples ======== >>> from sympy.physics.quantum.state import Ket >>> from sympy.physics.quantum.density import Density >>> from sympy.physics.quantum.operator import Operator >>> A = Operator('A') >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) >>> d.apply_op(A) Density((A*|0>, 0.5),(A*|1>, 0.5)) """ new_args = [(op*state, prob) for (state, prob) in self.args] return Density(*new_args) def doit(self, **hints): """Expand the density operator into an outer product format. Examples ======== >>> from sympy.physics.quantum.state import Ket >>> from sympy.physics.quantum.density import Density >>> from sympy.physics.quantum.operator import Operator >>> A = Operator('A') >>> d = Density([Ket(0), 0.5], [Ket(1),0.5]) >>> d.doit() 0.5*|0><0| + 0.5*|1><1| """ terms = [] for (state, prob) in self.args: state = state.expand() # needed to break up (a+b)*c if (isinstance(state, Add)): for arg in product(state.args, repeat=2): terms.append(prob*self._generate_outer_prod(arg[0], arg[1])) else: terms.append(prob*self._generate_outer_prod(state, state)) return Add(*terms) def _generate_outer_prod(self, arg1, arg2): c_part1, nc_part1 = arg1.args_cnc() c_part2, nc_part2 = arg2.args_cnc() if (len(nc_part1) == 0 or len(nc_part2) == 0): raise ValueError('Atleast one-pair of' ' Non-commutative instance required' ' for outer product.') # Muls of Tensor Products should be expanded # before this function is called if (isinstance(nc_part1[0], TensorProduct) and len(nc_part1) == 1 and len(nc_part2) == 1): op = tensor_product_simp(nc_part1[0]*Dagger(nc_part2[0])) else: op = Mul(*nc_part1)*Dagger(Mul(*nc_part2)) return Mul(*c_part1)*Mul(*c_part2) * op def _represent(self, **options): return represent(self.doit(), **options) def _print_operator_name_latex(self, printer, *args): return r'\rho' def _print_operator_name_pretty(self, printer, *args): return prettyForm('\N{GREEK SMALL LETTER RHO}') def _eval_trace(self, **kwargs): indices = kwargs.get('indices', []) return Tr(self.doit(), indices).doit() def entropy(self): """ Compute the entropy of a density matrix. Refer to density.entropy() method for examples. """ return entropy(self) def entropy(density): """Compute the entropy of a matrix/density object. This computes -Tr(density*ln(density)) using the eigenvalue decomposition of density, which is given as either a Density instance or a matrix (numpy.ndarray, sympy.Matrix or scipy.sparse). Parameters ========== density : density matrix of type Density, sympy matrix, scipy.sparse or numpy.ndarray Examples ======== >>> from sympy.physics.quantum.density import Density, entropy >>> from sympy.physics.quantum.spin import JzKet >>> from sympy import S >>> up = JzKet(S(1)/2,S(1)/2) >>> down = JzKet(S(1)/2,-S(1)/2) >>> d = Density((up,S(1)/2),(down,S(1)/2)) >>> entropy(d) log(2)/2 """ if isinstance(density, Density): density = represent(density) # represent in Matrix if isinstance(density, scipy_sparse_matrix): density = to_numpy(density) if isinstance(density, Matrix): eigvals = density.eigenvals().keys() return expand(-sum(e*log(e) for e in eigvals)) elif isinstance(density, numpy_ndarray): import numpy as np eigvals = np.linalg.eigvals(density) return -np.sum(eigvals*np.log(eigvals)) else: raise ValueError( "numpy.ndarray, scipy.sparse or sympy matrix expected") def fidelity(state1, state2): """ Computes the fidelity [1]_ between two quantum states The arguments provided to this function should be a square matrix or a Density object. If it is a square matrix, it is assumed to be diagonalizable. Parameters ========== state1, state2 : a density matrix or Matrix Examples ======== >>> from sympy import S, sqrt >>> from sympy.physics.quantum.dagger import Dagger >>> from sympy.physics.quantum.spin import JzKet >>> from sympy.physics.quantum.density import fidelity >>> from sympy.physics.quantum.represent import represent >>> >>> up = JzKet(S(1)/2,S(1)/2) >>> down = JzKet(S(1)/2,-S(1)/2) >>> amp = 1/sqrt(2) >>> updown = (amp*up) + (amp*down) >>> >>> # represent turns Kets into matrices >>> up_dm = represent(up*Dagger(up)) >>> down_dm = represent(down*Dagger(down)) >>> updown_dm = represent(updown*Dagger(updown)) >>> >>> fidelity(up_dm, up_dm) 1 >>> fidelity(up_dm, down_dm) #orthogonal states 0 >>> fidelity(up_dm, updown_dm).evalf().round(3) 0.707 References ========== .. [1] https://en.wikipedia.org/wiki/Fidelity_of_quantum_states """ state1 = represent(state1) if isinstance(state1, Density) else state1 state2 = represent(state2) if isinstance(state2, Density) else state2 if not isinstance(state1, Matrix) or not isinstance(state2, Matrix): raise ValueError("state1 and state2 must be of type Density or Matrix " "received type=%s for state1 and type=%s for state2" % (type(state1), type(state2))) if state1.shape != state2.shape and state1.is_square: raise ValueError("The dimensions of both args should be equal and the " "matrix obtained should be a square matrix") sqrt_state1 = state1**S.Half return Tr((sqrt_state1*state2*sqrt_state1)**S.Half).doit() sympy-sympy-1.9/sympy/physics/quantum/fermion.py000066400000000000000000000105771412543434000223030ustar00rootroot00000000000000"""Fermionic quantum operators.""" from sympy import Integer from sympy.physics.quantum import Operator from sympy.physics.quantum import HilbertSpace, Ket, Bra from sympy.functions.special.tensor_functions import KroneckerDelta __all__ = [ 'FermionOp', 'FermionFockKet', 'FermionFockBra' ] class FermionOp(Operator): """A fermionic operator that satisfies {c, Dagger(c)} == 1. Parameters ========== name : str A string that labels the fermionic mode. annihilation : bool A bool that indicates if the fermionic operator is an annihilation (True, default value) or creation operator (False) Examples ======== >>> from sympy.physics.quantum import Dagger, AntiCommutator >>> from sympy.physics.quantum.fermion import FermionOp >>> c = FermionOp("c") >>> AntiCommutator(c, Dagger(c)).doit() 1 """ @property def name(self): return self.args[0] @property def is_annihilation(self): return bool(self.args[1]) @classmethod def default_args(self): return ("c", True) def __new__(cls, *args, **hints): if not len(args) in [1, 2]: raise ValueError('1 or 2 parameters expected, got %s' % args) if len(args) == 1: args = (args[0], Integer(1)) if len(args) == 2: args = (args[0], Integer(args[1])) return Operator.__new__(cls, *args) def _eval_commutator_FermionOp(self, other, **hints): if 'independent' in hints and hints['independent']: # [c, d] = 0 return Integer(0) return None def _eval_anticommutator_FermionOp(self, other, **hints): if self.name == other.name: # {a^\dagger, a} = 1 if not self.is_annihilation and other.is_annihilation: return Integer(1) elif 'independent' in hints and hints['independent']: # {c, d} = 2 * c * d, because [c, d] = 0 for independent operators return 2 * self * other return None def _eval_anticommutator_BosonOp(self, other, **hints): # because fermions and bosons commute return 2 * self * other def _eval_commutator_BosonOp(self, other, **hints): return Integer(0) def _eval_adjoint(self): return FermionOp(str(self.name), not self.is_annihilation) def _print_contents_latex(self, printer, *args): if self.is_annihilation: return r'{%s}' % str(self.name) else: return r'{{%s}^\dagger}' % str(self.name) def _print_contents(self, printer, *args): if self.is_annihilation: return r'%s' % str(self.name) else: return r'Dagger(%s)' % str(self.name) def _print_contents_pretty(self, printer, *args): from sympy.printing.pretty.stringpict import prettyForm pform = printer._print(self.args[0], *args) if self.is_annihilation: return pform else: return pform**prettyForm('\N{DAGGER}') class FermionFockKet(Ket): """Fock state ket for a fermionic mode. Parameters ========== n : Number The Fock state number. """ def __new__(cls, n): if n not in [0, 1]: raise ValueError("n must be 0 or 1") return Ket.__new__(cls, n) @property def n(self): return self.label[0] @classmethod def dual_class(self): return FermionFockBra @classmethod def _eval_hilbert_space(cls, label): return HilbertSpace() def _eval_innerproduct_FermionFockBra(self, bra, **hints): return KroneckerDelta(self.n, bra.n) def _apply_operator_FermionOp(self, op, **options): if op.is_annihilation: if self.n == 1: return FermionFockKet(0) else: return Integer(0) else: if self.n == 0: return FermionFockKet(1) else: return Integer(0) class FermionFockBra(Bra): """Fock state bra for a fermionic mode. Parameters ========== n : Number The Fock state number. """ def __new__(cls, n): if n not in [0, 1]: raise ValueError("n must be 0 or 1") return Bra.__new__(cls, n) @property def n(self): return self.label[0] @classmethod def dual_class(self): return FermionFockKet sympy-sympy-1.9/sympy/physics/quantum/gate.py000066400000000000000000001213271412543434000215600ustar00rootroot00000000000000"""An implementation of gates that act on qubits. Gates are unitary operators that act on the space of qubits. Medium Term Todo: * Optimize Gate._apply_operators_Qubit to remove the creation of many intermediate Qubit objects. * Add commutation relationships to all operators and use this in gate_sort. * Fix gate_sort and gate_simp. * Get multi-target UGates plotting properly. * Get UGate to work with either sympy/numpy matrices and output either format. This should also use the matrix slots. """ from itertools import chain import random from sympy import Add, I, Integer, Mul, Pow, sqrt, Tuple from sympy.core.numbers import Number from sympy.core.compatibility import is_sequence from sympy.printing.pretty.stringpict import prettyForm, stringPict from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.qexpr import QuantumError from sympy.physics.quantum.hilbert import ComplexSpace from sympy.physics.quantum.operator import (UnitaryOperator, Operator, HermitianOperator) from sympy.physics.quantum.matrixutils import matrix_tensor_product, matrix_eye from sympy.physics.quantum.matrixcache import matrix_cache from sympy.matrices.matrices import MatrixBase from sympy.utilities import default_sort_key __all__ = [ 'Gate', 'CGate', 'UGate', 'OneQubitGate', 'TwoQubitGate', 'IdentityGate', 'HadamardGate', 'XGate', 'YGate', 'ZGate', 'TGate', 'PhaseGate', 'SwapGate', 'CNotGate', # Aliased gate names 'CNOT', 'SWAP', 'H', 'X', 'Y', 'Z', 'T', 'S', 'Phase', 'normalized', 'gate_sort', 'gate_simp', 'random_circuit', 'CPHASE', 'CGateS', ] #----------------------------------------------------------------------------- # Gate Super-Classes #----------------------------------------------------------------------------- _normalized = True def _max(*args, **kwargs): if "key" not in kwargs: kwargs["key"] = default_sort_key return max(*args, **kwargs) def _min(*args, **kwargs): if "key" not in kwargs: kwargs["key"] = default_sort_key return min(*args, **kwargs) def normalized(normalize): """Set flag controlling normalization of Hadamard gates by 1/sqrt(2). This is a global setting that can be used to simplify the look of various expressions, by leaving off the leading 1/sqrt(2) of the Hadamard gate. Parameters ---------- normalize : bool Should the Hadamard gate include the 1/sqrt(2) normalization factor? When True, the Hadamard gate will have the 1/sqrt(2). When False, the Hadamard gate will not have this factor. """ global _normalized _normalized = normalize def _validate_targets_controls(tandc): tandc = list(tandc) # Check for integers for bit in tandc: if not bit.is_Integer and not bit.is_Symbol: raise TypeError('Integer expected, got: %r' % tandc[bit]) # Detect duplicates if len(list(set(tandc))) != len(tandc): raise QuantumError( 'Target/control qubits in a gate cannot be duplicated' ) class Gate(UnitaryOperator): """Non-controlled unitary gate operator that acts on qubits. This is a general abstract gate that needs to be subclassed to do anything useful. Parameters ---------- label : tuple, int A list of the target qubits (as ints) that the gate will apply to. Examples ======== """ _label_separator = ',' gate_name = 'G' gate_name_latex = 'G' #------------------------------------------------------------------------- # Initialization/creation #------------------------------------------------------------------------- @classmethod def _eval_args(cls, args): args = Tuple(*UnitaryOperator._eval_args(args)) _validate_targets_controls(args) return args @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" return ComplexSpace(2)**(_max(args) + 1) #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def nqubits(self): """The total number of qubits this gate acts on. For controlled gate subclasses this includes both target and control qubits, so that, for examples the CNOT gate acts on 2 qubits. """ return len(self.targets) @property def min_qubits(self): """The minimum number of qubits this gate needs to act on.""" return _max(self.targets) + 1 @property def targets(self): """A tuple of target qubits.""" return self.label @property def gate_name_plot(self): return r'$%s$' % self.gate_name_latex #------------------------------------------------------------------------- # Gate methods #------------------------------------------------------------------------- def get_target_matrix(self, format='sympy'): """The matrix rep. of the target part of the gate. Parameters ---------- format : str The format string ('sympy','numpy', etc.) """ raise NotImplementedError( 'get_target_matrix is not implemented in Gate.') #------------------------------------------------------------------------- # Apply #------------------------------------------------------------------------- def _apply_operator_IntQubit(self, qubits, **options): """Redirect an apply from IntQubit to Qubit""" return self._apply_operator_Qubit(qubits, **options) def _apply_operator_Qubit(self, qubits, **options): """Apply this gate to a Qubit.""" # Check number of qubits this gate acts on. if qubits.nqubits < self.min_qubits: raise QuantumError( 'Gate needs a minimum of %r qubits to act on, got: %r' % (self.min_qubits, qubits.nqubits) ) # If the controls are not met, just return if isinstance(self, CGate): if not self.eval_controls(qubits): return qubits targets = self.targets target_matrix = self.get_target_matrix(format='sympy') # Find which column of the target matrix this applies to. column_index = 0 n = 1 for target in targets: column_index += n*qubits[target] n = n << 1 column = target_matrix[:, int(column_index)] # Now apply each column element to the qubit. result = 0 for index in range(column.rows): # TODO: This can be optimized to reduce the number of Qubit # creations. We should simply manipulate the raw list of qubit # values and then build the new Qubit object once. # Make a copy of the incoming qubits. new_qubit = qubits.__class__(*qubits.args) # Flip the bits that need to be flipped. for bit in range(len(targets)): if new_qubit[targets[bit]] != (index >> bit) & 1: new_qubit = new_qubit.flip(targets[bit]) # The value in that row and column times the flipped-bit qubit # is the result for that part. result += column[index]*new_qubit return result #------------------------------------------------------------------------- # Represent #------------------------------------------------------------------------- def _represent_default_basis(self, **options): return self._represent_ZGate(None, **options) def _represent_ZGate(self, basis, **options): format = options.get('format', 'sympy') nqubits = options.get('nqubits', 0) if nqubits == 0: raise QuantumError( 'The number of qubits must be given as nqubits.') # Make sure we have enough qubits for the gate. if nqubits < self.min_qubits: raise QuantumError( 'The number of qubits %r is too small for the gate.' % nqubits ) target_matrix = self.get_target_matrix(format) targets = self.targets if isinstance(self, CGate): controls = self.controls else: controls = [] m = represent_zbasis( controls, targets, target_matrix, nqubits, format ) return m #------------------------------------------------------------------------- # Print methods #------------------------------------------------------------------------- def _sympystr(self, printer, *args): label = self._print_label(printer, *args) return '%s(%s)' % (self.gate_name, label) def _pretty(self, printer, *args): a = stringPict(self.gate_name) b = self._print_label_pretty(printer, *args) return self._print_subscript_pretty(a, b) def _latex(self, printer, *args): label = self._print_label(printer, *args) return '%s_{%s}' % (self.gate_name_latex, label) def plot_gate(self, axes, gate_idx, gate_grid, wire_grid): raise NotImplementedError('plot_gate is not implemented.') class CGate(Gate): """A general unitary gate with control qubits. A general control gate applies a target gate to a set of targets if all of the control qubits have a particular values (set by ``CGate.control_value``). Parameters ---------- label : tuple The label in this case has the form (controls, gate), where controls is a tuple/list of control qubits (as ints) and gate is a ``Gate`` instance that is the target operator. Examples ======== """ gate_name = 'C' gate_name_latex = 'C' # The values this class controls for. control_value = Integer(1) simplify_cgate=False #------------------------------------------------------------------------- # Initialization #------------------------------------------------------------------------- @classmethod def _eval_args(cls, args): # _eval_args has the right logic for the controls argument. controls = args[0] gate = args[1] if not is_sequence(controls): controls = (controls,) controls = UnitaryOperator._eval_args(controls) _validate_targets_controls(chain(controls, gate.targets)) return (Tuple(*controls), gate) @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" return ComplexSpace(2)**_max(_max(args[0]) + 1, args[1].min_qubits) #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def nqubits(self): """The total number of qubits this gate acts on. For controlled gate subclasses this includes both target and control qubits, so that, for examples the CNOT gate acts on 2 qubits. """ return len(self.targets) + len(self.controls) @property def min_qubits(self): """The minimum number of qubits this gate needs to act on.""" return _max(_max(self.controls), _max(self.targets)) + 1 @property def targets(self): """A tuple of target qubits.""" return self.gate.targets @property def controls(self): """A tuple of control qubits.""" return tuple(self.label[0]) @property def gate(self): """The non-controlled gate that will be applied to the targets.""" return self.label[1] #------------------------------------------------------------------------- # Gate methods #------------------------------------------------------------------------- def get_target_matrix(self, format='sympy'): return self.gate.get_target_matrix(format) def eval_controls(self, qubit): """Return True/False to indicate if the controls are satisfied.""" return all(qubit[bit] == self.control_value for bit in self.controls) def decompose(self, **options): """Decompose the controlled gate into CNOT and single qubits gates.""" if len(self.controls) == 1: c = self.controls[0] t = self.gate.targets[0] if isinstance(self.gate, YGate): g1 = PhaseGate(t) g2 = CNotGate(c, t) g3 = PhaseGate(t) g4 = ZGate(t) return g1*g2*g3*g4 if isinstance(self.gate, ZGate): g1 = HadamardGate(t) g2 = CNotGate(c, t) g3 = HadamardGate(t) return g1*g2*g3 else: return self #------------------------------------------------------------------------- # Print methods #------------------------------------------------------------------------- def _print_label(self, printer, *args): controls = self._print_sequence(self.controls, ',', printer, *args) gate = printer._print(self.gate, *args) return '(%s),%s' % (controls, gate) def _pretty(self, printer, *args): controls = self._print_sequence_pretty( self.controls, ',', printer, *args) gate = printer._print(self.gate) gate_name = stringPict(self.gate_name) first = self._print_subscript_pretty(gate_name, controls) gate = self._print_parens_pretty(gate) final = prettyForm(*first.right(gate)) return final def _latex(self, printer, *args): controls = self._print_sequence(self.controls, ',', printer, *args) gate = printer._print(self.gate, *args) return r'%s_{%s}{\left(%s\right)}' % \ (self.gate_name_latex, controls, gate) def plot_gate(self, circ_plot, gate_idx): """ Plot the controlled gate. If *simplify_cgate* is true, simplify C-X and C-Z gates into their more familiar forms. """ min_wire = int(_min(chain(self.controls, self.targets))) max_wire = int(_max(chain(self.controls, self.targets))) circ_plot.control_line(gate_idx, min_wire, max_wire) for c in self.controls: circ_plot.control_point(gate_idx, int(c)) if self.simplify_cgate: if self.gate.gate_name == 'X': self.gate.plot_gate_plus(circ_plot, gate_idx) elif self.gate.gate_name == 'Z': circ_plot.control_point(gate_idx, self.targets[0]) else: self.gate.plot_gate(circ_plot, gate_idx) else: self.gate.plot_gate(circ_plot, gate_idx) #------------------------------------------------------------------------- # Miscellaneous #------------------------------------------------------------------------- def _eval_dagger(self): if isinstance(self.gate, HermitianOperator): return self else: return Gate._eval_dagger(self) def _eval_inverse(self): if isinstance(self.gate, HermitianOperator): return self else: return Gate._eval_inverse(self) def _eval_power(self, exp): if isinstance(self.gate, HermitianOperator): if exp == -1: return Gate._eval_power(self, exp) elif abs(exp) % 2 == 0: return self*(Gate._eval_inverse(self)) else: return self else: return Gate._eval_power(self, exp) class CGateS(CGate): """Version of CGate that allows gate simplifications. I.e. cnot looks like an oplus, cphase has dots, etc. """ simplify_cgate=True class UGate(Gate): """General gate specified by a set of targets and a target matrix. Parameters ---------- label : tuple A tuple of the form (targets, U), where targets is a tuple of the target qubits and U is a unitary matrix with dimension of len(targets). """ gate_name = 'U' gate_name_latex = 'U' #------------------------------------------------------------------------- # Initialization #------------------------------------------------------------------------- @classmethod def _eval_args(cls, args): targets = args[0] if not is_sequence(targets): targets = (targets,) targets = Gate._eval_args(targets) _validate_targets_controls(targets) mat = args[1] if not isinstance(mat, MatrixBase): raise TypeError('Matrix expected, got: %r' % mat) dim = 2**len(targets) if not all(dim == shape for shape in mat.shape): raise IndexError( 'Number of targets must match the matrix size: %r %r' % (targets, mat) ) return (targets, mat) @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" return ComplexSpace(2)**(_max(args[0]) + 1) #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def targets(self): """A tuple of target qubits.""" return tuple(self.label[0]) #------------------------------------------------------------------------- # Gate methods #------------------------------------------------------------------------- def get_target_matrix(self, format='sympy'): """The matrix rep. of the target part of the gate. Parameters ---------- format : str The format string ('sympy','numpy', etc.) """ return self.label[1] #------------------------------------------------------------------------- # Print methods #------------------------------------------------------------------------- def _pretty(self, printer, *args): targets = self._print_sequence_pretty( self.targets, ',', printer, *args) gate_name = stringPict(self.gate_name) return self._print_subscript_pretty(gate_name, targets) def _latex(self, printer, *args): targets = self._print_sequence(self.targets, ',', printer, *args) return r'%s_{%s}' % (self.gate_name_latex, targets) def plot_gate(self, circ_plot, gate_idx): circ_plot.one_qubit_box( self.gate_name_plot, gate_idx, int(self.targets[0]) ) class OneQubitGate(Gate): """A single qubit unitary gate base class.""" nqubits = Integer(1) def plot_gate(self, circ_plot, gate_idx): circ_plot.one_qubit_box( self.gate_name_plot, gate_idx, int(self.targets[0]) ) def _eval_commutator(self, other, **hints): if isinstance(other, OneQubitGate): if self.targets != other.targets or self.__class__ == other.__class__: return Integer(0) return Operator._eval_commutator(self, other, **hints) def _eval_anticommutator(self, other, **hints): if isinstance(other, OneQubitGate): if self.targets != other.targets or self.__class__ == other.__class__: return Integer(2)*self*other return Operator._eval_anticommutator(self, other, **hints) class TwoQubitGate(Gate): """A two qubit unitary gate base class.""" nqubits = Integer(2) #----------------------------------------------------------------------------- # Single Qubit Gates #----------------------------------------------------------------------------- class IdentityGate(OneQubitGate): """The single qubit identity gate. Parameters ---------- target : int The target qubit this gate will apply to. Examples ======== """ gate_name = '1' gate_name_latex = '1' def get_target_matrix(self, format='sympy'): return matrix_cache.get_matrix('eye2', format) def _eval_commutator(self, other, **hints): return Integer(0) def _eval_anticommutator(self, other, **hints): return Integer(2)*other class HadamardGate(HermitianOperator, OneQubitGate): """The single qubit Hadamard gate. Parameters ---------- target : int The target qubit this gate will apply to. Examples ======== >>> from sympy import sqrt >>> from sympy.physics.quantum.qubit import Qubit >>> from sympy.physics.quantum.gate import HadamardGate >>> from sympy.physics.quantum.qapply import qapply >>> qapply(HadamardGate(0)*Qubit('1')) sqrt(2)*|0>/2 - sqrt(2)*|1>/2 >>> # Hadamard on bell state, applied on 2 qubits. >>> psi = 1/sqrt(2)*(Qubit('00')+Qubit('11')) >>> qapply(HadamardGate(0)*HadamardGate(1)*psi) sqrt(2)*|00>/2 + sqrt(2)*|11>/2 """ gate_name = 'H' gate_name_latex = 'H' def get_target_matrix(self, format='sympy'): if _normalized: return matrix_cache.get_matrix('H', format) else: return matrix_cache.get_matrix('Hsqrt2', format) def _eval_commutator_XGate(self, other, **hints): return I*sqrt(2)*YGate(self.targets[0]) def _eval_commutator_YGate(self, other, **hints): return I*sqrt(2)*(ZGate(self.targets[0]) - XGate(self.targets[0])) def _eval_commutator_ZGate(self, other, **hints): return -I*sqrt(2)*YGate(self.targets[0]) def _eval_anticommutator_XGate(self, other, **hints): return sqrt(2)*IdentityGate(self.targets[0]) def _eval_anticommutator_YGate(self, other, **hints): return Integer(0) def _eval_anticommutator_ZGate(self, other, **hints): return sqrt(2)*IdentityGate(self.targets[0]) class XGate(HermitianOperator, OneQubitGate): """The single qubit X, or NOT, gate. Parameters ---------- target : int The target qubit this gate will apply to. Examples ======== """ gate_name = 'X' gate_name_latex = 'X' def get_target_matrix(self, format='sympy'): return matrix_cache.get_matrix('X', format) def plot_gate(self, circ_plot, gate_idx): OneQubitGate.plot_gate(self,circ_plot,gate_idx) def plot_gate_plus(self, circ_plot, gate_idx): circ_plot.not_point( gate_idx, int(self.label[0]) ) def _eval_commutator_YGate(self, other, **hints): return Integer(2)*I*ZGate(self.targets[0]) def _eval_anticommutator_XGate(self, other, **hints): return Integer(2)*IdentityGate(self.targets[0]) def _eval_anticommutator_YGate(self, other, **hints): return Integer(0) def _eval_anticommutator_ZGate(self, other, **hints): return Integer(0) class YGate(HermitianOperator, OneQubitGate): """The single qubit Y gate. Parameters ---------- target : int The target qubit this gate will apply to. Examples ======== """ gate_name = 'Y' gate_name_latex = 'Y' def get_target_matrix(self, format='sympy'): return matrix_cache.get_matrix('Y', format) def _eval_commutator_ZGate(self, other, **hints): return Integer(2)*I*XGate(self.targets[0]) def _eval_anticommutator_YGate(self, other, **hints): return Integer(2)*IdentityGate(self.targets[0]) def _eval_anticommutator_ZGate(self, other, **hints): return Integer(0) class ZGate(HermitianOperator, OneQubitGate): """The single qubit Z gate. Parameters ---------- target : int The target qubit this gate will apply to. Examples ======== """ gate_name = 'Z' gate_name_latex = 'Z' def get_target_matrix(self, format='sympy'): return matrix_cache.get_matrix('Z', format) def _eval_commutator_XGate(self, other, **hints): return Integer(2)*I*YGate(self.targets[0]) def _eval_anticommutator_YGate(self, other, **hints): return Integer(0) class PhaseGate(OneQubitGate): """The single qubit phase, or S, gate. This gate rotates the phase of the state by pi/2 if the state is ``|1>`` and does nothing if the state is ``|0>``. Parameters ---------- target : int The target qubit this gate will apply to. Examples ======== """ gate_name = 'S' gate_name_latex = 'S' def get_target_matrix(self, format='sympy'): return matrix_cache.get_matrix('S', format) def _eval_commutator_ZGate(self, other, **hints): return Integer(0) def _eval_commutator_TGate(self, other, **hints): return Integer(0) class TGate(OneQubitGate): """The single qubit pi/8 gate. This gate rotates the phase of the state by pi/4 if the state is ``|1>`` and does nothing if the state is ``|0>``. Parameters ---------- target : int The target qubit this gate will apply to. Examples ======== """ gate_name = 'T' gate_name_latex = 'T' def get_target_matrix(self, format='sympy'): return matrix_cache.get_matrix('T', format) def _eval_commutator_ZGate(self, other, **hints): return Integer(0) def _eval_commutator_PhaseGate(self, other, **hints): return Integer(0) # Aliases for gate names. H = HadamardGate X = XGate Y = YGate Z = ZGate T = TGate Phase = S = PhaseGate #----------------------------------------------------------------------------- # 2 Qubit Gates #----------------------------------------------------------------------------- class CNotGate(HermitianOperator, CGate, TwoQubitGate): """Two qubit controlled-NOT. This gate performs the NOT or X gate on the target qubit if the control qubits all have the value 1. Parameters ---------- label : tuple A tuple of the form (control, target). Examples ======== >>> from sympy.physics.quantum.gate import CNOT >>> from sympy.physics.quantum.qapply import qapply >>> from sympy.physics.quantum.qubit import Qubit >>> c = CNOT(1,0) >>> qapply(c*Qubit('10')) # note that qubits are indexed from right to left |11> """ gate_name = 'CNOT' gate_name_latex = 'CNOT' simplify_cgate = True #------------------------------------------------------------------------- # Initialization #------------------------------------------------------------------------- @classmethod def _eval_args(cls, args): args = Gate._eval_args(args) return args @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" return ComplexSpace(2)**(_max(args) + 1) #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def min_qubits(self): """The minimum number of qubits this gate needs to act on.""" return _max(self.label) + 1 @property def targets(self): """A tuple of target qubits.""" return (self.label[1],) @property def controls(self): """A tuple of control qubits.""" return (self.label[0],) @property def gate(self): """The non-controlled gate that will be applied to the targets.""" return XGate(self.label[1]) #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- # The default printing of Gate works better than those of CGate, so we # go around the overridden methods in CGate. def _print_label(self, printer, *args): return Gate._print_label(self, printer, *args) def _pretty(self, printer, *args): return Gate._pretty(self, printer, *args) def _latex(self, printer, *args): return Gate._latex(self, printer, *args) #------------------------------------------------------------------------- # Commutator/AntiCommutator #------------------------------------------------------------------------- def _eval_commutator_ZGate(self, other, **hints): """[CNOT(i, j), Z(i)] == 0.""" if self.controls[0] == other.targets[0]: return Integer(0) else: raise NotImplementedError('Commutator not implemented: %r' % other) def _eval_commutator_TGate(self, other, **hints): """[CNOT(i, j), T(i)] == 0.""" return self._eval_commutator_ZGate(other, **hints) def _eval_commutator_PhaseGate(self, other, **hints): """[CNOT(i, j), S(i)] == 0.""" return self._eval_commutator_ZGate(other, **hints) def _eval_commutator_XGate(self, other, **hints): """[CNOT(i, j), X(j)] == 0.""" if self.targets[0] == other.targets[0]: return Integer(0) else: raise NotImplementedError('Commutator not implemented: %r' % other) def _eval_commutator_CNotGate(self, other, **hints): """[CNOT(i, j), CNOT(i,k)] == 0.""" if self.controls[0] == other.controls[0]: return Integer(0) else: raise NotImplementedError('Commutator not implemented: %r' % other) class SwapGate(TwoQubitGate): """Two qubit SWAP gate. This gate swap the values of the two qubits. Parameters ---------- label : tuple A tuple of the form (target1, target2). Examples ======== """ gate_name = 'SWAP' gate_name_latex = 'SWAP' def get_target_matrix(self, format='sympy'): return matrix_cache.get_matrix('SWAP', format) def decompose(self, **options): """Decompose the SWAP gate into CNOT gates.""" i, j = self.targets[0], self.targets[1] g1 = CNotGate(i, j) g2 = CNotGate(j, i) return g1*g2*g1 def plot_gate(self, circ_plot, gate_idx): min_wire = int(_min(self.targets)) max_wire = int(_max(self.targets)) circ_plot.control_line(gate_idx, min_wire, max_wire) circ_plot.swap_point(gate_idx, min_wire) circ_plot.swap_point(gate_idx, max_wire) def _represent_ZGate(self, basis, **options): """Represent the SWAP gate in the computational basis. The following representation is used to compute this: SWAP = |1><1|x|1><1| + |0><0|x|0><0| + |1><0|x|0><1| + |0><1|x|1><0| """ format = options.get('format', 'sympy') targets = [int(t) for t in self.targets] min_target = _min(targets) max_target = _max(targets) nqubits = options.get('nqubits', self.min_qubits) op01 = matrix_cache.get_matrix('op01', format) op10 = matrix_cache.get_matrix('op10', format) op11 = matrix_cache.get_matrix('op11', format) op00 = matrix_cache.get_matrix('op00', format) eye2 = matrix_cache.get_matrix('eye2', format) result = None for i, j in ((op01, op10), (op10, op01), (op00, op00), (op11, op11)): product = nqubits*[eye2] product[nqubits - min_target - 1] = i product[nqubits - max_target - 1] = j new_result = matrix_tensor_product(*product) if result is None: result = new_result else: result = result + new_result return result # Aliases for gate names. CNOT = CNotGate SWAP = SwapGate def CPHASE(a,b): return CGateS((a,),Z(b)) #----------------------------------------------------------------------------- # Represent #----------------------------------------------------------------------------- def represent_zbasis(controls, targets, target_matrix, nqubits, format='sympy'): """Represent a gate with controls, targets and target_matrix. This function does the low-level work of representing gates as matrices in the standard computational basis (ZGate). Currently, we support two main cases: 1. One target qubit and no control qubits. 2. One target qubits and multiple control qubits. For the base of multiple controls, we use the following expression [1]: 1_{2**n} + (|1><1|)^{(n-1)} x (target-matrix - 1_{2}) Parameters ---------- controls : list, tuple A sequence of control qubits. targets : list, tuple A sequence of target qubits. target_matrix : sympy.Matrix, numpy.matrix, scipy.sparse The matrix form of the transformation to be performed on the target qubits. The format of this matrix must match that passed into the `format` argument. nqubits : int The total number of qubits used for the representation. format : str The format of the final matrix ('sympy', 'numpy', 'scipy.sparse'). Examples ======== References ---------- [1] http://www.johnlapeyre.com/qinf/qinf_html/node6.html. """ controls = [int(x) for x in controls] targets = [int(x) for x in targets] nqubits = int(nqubits) # This checks for the format as well. op11 = matrix_cache.get_matrix('op11', format) eye2 = matrix_cache.get_matrix('eye2', format) # Plain single qubit case if len(controls) == 0 and len(targets) == 1: product = [] bit = targets[0] # Fill product with [I1,Gate,I2] such that the unitaries, # I, cause the gate to be applied to the correct Qubit if bit != nqubits - 1: product.append(matrix_eye(2**(nqubits - bit - 1), format=format)) product.append(target_matrix) if bit != 0: product.append(matrix_eye(2**bit, format=format)) return matrix_tensor_product(*product) # Single target, multiple controls. elif len(targets) == 1 and len(controls) >= 1: target = targets[0] # Build the non-trivial part. product2 = [] for i in range(nqubits): product2.append(matrix_eye(2, format=format)) for control in controls: product2[nqubits - 1 - control] = op11 product2[nqubits - 1 - target] = target_matrix - eye2 return matrix_eye(2**nqubits, format=format) + \ matrix_tensor_product(*product2) # Multi-target, multi-control is not yet implemented. else: raise NotImplementedError( 'The representation of multi-target, multi-control gates ' 'is not implemented.' ) #----------------------------------------------------------------------------- # Gate manipulation functions. #----------------------------------------------------------------------------- def gate_simp(circuit): """Simplifies gates symbolically It first sorts gates using gate_sort. It then applies basic simplification rules to the circuit, e.g., XGate**2 = Identity """ # Bubble sort out gates that commute. circuit = gate_sort(circuit) # Do simplifications by subing a simplification into the first element # which can be simplified. We recursively call gate_simp with new circuit # as input more simplifications exist. if isinstance(circuit, Add): return sum(gate_simp(t) for t in circuit.args) elif isinstance(circuit, Mul): circuit_args = circuit.args elif isinstance(circuit, Pow): b, e = circuit.as_base_exp() circuit_args = (gate_simp(b)**e,) else: return circuit # Iterate through each element in circuit, simplify if possible. for i in range(len(circuit_args)): # H,X,Y or Z squared is 1. # T**2 = S, S**2 = Z if isinstance(circuit_args[i], Pow): if isinstance(circuit_args[i].base, (HadamardGate, XGate, YGate, ZGate)) \ and isinstance(circuit_args[i].exp, Number): # Build a new circuit taking replacing the # H,X,Y,Z squared with one. newargs = (circuit_args[:i] + (circuit_args[i].base**(circuit_args[i].exp % 2),) + circuit_args[i + 1:]) # Recursively simplify the new circuit. circuit = gate_simp(Mul(*newargs)) break elif isinstance(circuit_args[i].base, PhaseGate): # Build a new circuit taking old circuit but splicing # in simplification. newargs = circuit_args[:i] # Replace PhaseGate**2 with ZGate. newargs = newargs + (ZGate(circuit_args[i].base.args[0])** (Integer(circuit_args[i].exp/2)), circuit_args[i].base** (circuit_args[i].exp % 2)) # Append the last elements. newargs = newargs + circuit_args[i + 1:] # Recursively simplify the new circuit. circuit = gate_simp(Mul(*newargs)) break elif isinstance(circuit_args[i].base, TGate): # Build a new circuit taking all the old elements. newargs = circuit_args[:i] # Put an Phasegate in place of any TGate**2. newargs = newargs + (PhaseGate(circuit_args[i].base.args[0])** Integer(circuit_args[i].exp/2), circuit_args[i].base** (circuit_args[i].exp % 2)) # Append the last elements. newargs = newargs + circuit_args[i + 1:] # Recursively simplify the new circuit. circuit = gate_simp(Mul(*newargs)) break return circuit def gate_sort(circuit): """Sorts the gates while keeping track of commutation relations This function uses a bubble sort to rearrange the order of gate application. Keeps track of Quantum computations special commutation relations (e.g. things that apply to the same Qubit do not commute with each other) circuit is the Mul of gates that are to be sorted. """ # Make sure we have an Add or Mul. if isinstance(circuit, Add): return sum(gate_sort(t) for t in circuit.args) if isinstance(circuit, Pow): return gate_sort(circuit.base)**circuit.exp elif isinstance(circuit, Gate): return circuit if not isinstance(circuit, Mul): return circuit changes = True while changes: changes = False circ_array = circuit.args for i in range(len(circ_array) - 1): # Go through each element and switch ones that are in wrong order if isinstance(circ_array[i], (Gate, Pow)) and \ isinstance(circ_array[i + 1], (Gate, Pow)): # If we have a Pow object, look at only the base first_base, first_exp = circ_array[i].as_base_exp() second_base, second_exp = circ_array[i + 1].as_base_exp() # Use sympy's hash based sorting. This is not mathematical # sorting, but is rather based on comparing hashes of objects. # See Basic.compare for details. if first_base.compare(second_base) > 0: if Commutator(first_base, second_base).doit() == 0: new_args = (circuit.args[:i] + (circuit.args[i + 1],) + (circuit.args[i],) + circuit.args[i + 2:]) circuit = Mul(*new_args) changes = True break if AntiCommutator(first_base, second_base).doit() == 0: new_args = (circuit.args[:i] + (circuit.args[i + 1],) + (circuit.args[i],) + circuit.args[i + 2:]) sign = Integer(-1)**(first_exp*second_exp) circuit = sign*Mul(*new_args) changes = True break return circuit #----------------------------------------------------------------------------- # Utility functions #----------------------------------------------------------------------------- def random_circuit(ngates, nqubits, gate_space=(X, Y, Z, S, T, H, CNOT, SWAP)): """Return a random circuit of ngates and nqubits. This uses an equally weighted sample of (X, Y, Z, S, T, H, CNOT, SWAP) gates. Parameters ---------- ngates : int The number of gates in the circuit. nqubits : int The number of qubits in the circuit. gate_space : tuple A tuple of the gate classes that will be used in the circuit. Repeating gate classes multiple times in this tuple will increase the frequency they appear in the random circuit. """ qubit_space = range(nqubits) result = [] for i in range(ngates): g = random.choice(gate_space) if g == CNotGate or g == SwapGate: qubits = random.sample(qubit_space, 2) g = g(*qubits) else: qubit = random.choice(qubit_space) g = g(qubit) result.append(g) return Mul(*result) def zx_basis_transform(self, format='sympy'): """Transformation matrix from Z to X basis.""" return matrix_cache.get_matrix('ZX', format) def zy_basis_transform(self, format='sympy'): """Transformation matrix from Z to Y basis.""" return matrix_cache.get_matrix('ZY', format) sympy-sympy-1.9/sympy/physics/quantum/grover.py000066400000000000000000000231141412543434000221370ustar00rootroot00000000000000"""Grover's algorithm and helper functions. Todo: * W gate construction (or perhaps -W gate based on Mermin's book) * Generalize the algorithm for an unknown function that returns 1 on multiple qubit states, not just one. * Implement _represent_ZGate in OracleGate """ from sympy import floor, pi, sqrt, sympify, eye from sympy.core.numbers import NegativeOne from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qexpr import QuantumError from sympy.physics.quantum.hilbert import ComplexSpace from sympy.physics.quantum.operator import UnitaryOperator from sympy.physics.quantum.gate import Gate from sympy.physics.quantum.qubit import IntQubit __all__ = [ 'OracleGate', 'WGate', 'superposition_basis', 'grover_iteration', 'apply_grover' ] def superposition_basis(nqubits): """Creates an equal superposition of the computational basis. Parameters ========== nqubits : int The number of qubits. Returns ======= state : Qubit An equal superposition of the computational basis with nqubits. Examples ======== Create an equal superposition of 2 qubits:: >>> from sympy.physics.quantum.grover import superposition_basis >>> superposition_basis(2) |0>/2 + |1>/2 + |2>/2 + |3>/2 """ amp = 1/sqrt(2**nqubits) return sum([amp*IntQubit(n, nqubits=nqubits) for n in range(2**nqubits)]) class OracleGate(Gate): """A black box gate. The gate marks the desired qubits of an unknown function by flipping the sign of the qubits. The unknown function returns true when it finds its desired qubits and false otherwise. Parameters ========== qubits : int Number of qubits. oracle : callable A callable function that returns a boolean on a computational basis. Examples ======== Apply an Oracle gate that flips the sign of ``|2>`` on different qubits:: >>> from sympy.physics.quantum.qubit import IntQubit >>> from sympy.physics.quantum.qapply import qapply >>> from sympy.physics.quantum.grover import OracleGate >>> f = lambda qubits: qubits == IntQubit(2) >>> v = OracleGate(2, f) >>> qapply(v*IntQubit(2)) -|2> >>> qapply(v*IntQubit(3)) |3> """ gate_name = 'V' gate_name_latex = 'V' #------------------------------------------------------------------------- # Initialization/creation #------------------------------------------------------------------------- @classmethod def _eval_args(cls, args): # TODO: args[1] is not a subclass of Basic if len(args) != 2: raise QuantumError( 'Insufficient/excessive arguments to Oracle. Please ' + 'supply the number of qubits and an unknown function.' ) sub_args = (args[0],) sub_args = UnitaryOperator._eval_args(sub_args) if not sub_args[0].is_Integer: raise TypeError('Integer expected, got: %r' % sub_args[0]) if not callable(args[1]): raise TypeError('Callable expected, got: %r' % args[1]) return (sub_args[0], args[1]) @classmethod def _eval_hilbert_space(cls, args): """This returns the smallest possible Hilbert space.""" return ComplexSpace(2)**args[0] #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def search_function(self): """The unknown function that helps find the sought after qubits.""" return self.label[1] @property def targets(self): """A tuple of target qubits.""" return sympify(tuple(range(self.args[0]))) #------------------------------------------------------------------------- # Apply #------------------------------------------------------------------------- def _apply_operator_Qubit(self, qubits, **options): """Apply this operator to a Qubit subclass. Parameters ========== qubits : Qubit The qubit subclass to apply this operator to. Returns ======= state : Expr The resulting quantum state. """ if qubits.nqubits != self.nqubits: raise QuantumError( 'OracleGate operates on %r qubits, got: %r' % (self.nqubits, qubits.nqubits) ) # If function returns 1 on qubits # return the negative of the qubits (flip the sign) if self.search_function(qubits): return -qubits else: return qubits #------------------------------------------------------------------------- # Represent #------------------------------------------------------------------------- def _represent_ZGate(self, basis, **options): """ Represent the OracleGate in the computational basis. """ nbasis = 2**self.nqubits # compute it only once matrixOracle = eye(nbasis) # Flip the sign given the output of the oracle function for i in range(nbasis): if self.search_function(IntQubit(i, nqubits=self.nqubits)): matrixOracle[i, i] = NegativeOne() return matrixOracle class WGate(Gate): """General n qubit W Gate in Grover's algorithm. The gate performs the operation ``2|phi> = (tensor product of n Hadamards)*(|0> with n qubits)`` Parameters ========== nqubits : int The number of qubits to operate on """ gate_name = 'W' gate_name_latex = 'W' @classmethod def _eval_args(cls, args): if len(args) != 1: raise QuantumError( 'Insufficient/excessive arguments to W gate. Please ' + 'supply the number of qubits to operate on.' ) args = UnitaryOperator._eval_args(args) if not args[0].is_Integer: raise TypeError('Integer expected, got: %r' % args[0]) return args #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def targets(self): return sympify(tuple(reversed(range(self.args[0])))) #------------------------------------------------------------------------- # Apply #------------------------------------------------------------------------- def _apply_operator_Qubit(self, qubits, **options): """ qubits: a set of qubits (Qubit) Returns: quantum object (quantum expression - QExpr) """ if qubits.nqubits != self.nqubits: raise QuantumError( 'WGate operates on %r qubits, got: %r' % (self.nqubits, qubits.nqubits) ) # See 'Quantum Computer Science' by David Mermin p.92 -> W|a> result # Return (2/(sqrt(2^n)))|phi> - |a> where |a> is the current basis # state and phi is the superposition of basis states (see function # create_computational_basis above) basis_states = superposition_basis(self.nqubits) change_to_basis = (2/sqrt(2**self.nqubits))*basis_states return change_to_basis - qubits def grover_iteration(qstate, oracle): """Applies one application of the Oracle and W Gate, WV. Parameters ========== qstate : Qubit A superposition of qubits. oracle : OracleGate The black box operator that flips the sign of the desired basis qubits. Returns ======= Qubit : The qubits after applying the Oracle and W gate. Examples ======== Perform one iteration of grover's algorithm to see a phase change:: >>> from sympy.physics.quantum.qapply import qapply >>> from sympy.physics.quantum.qubit import IntQubit >>> from sympy.physics.quantum.grover import OracleGate >>> from sympy.physics.quantum.grover import superposition_basis >>> from sympy.physics.quantum.grover import grover_iteration >>> numqubits = 2 >>> basis_states = superposition_basis(numqubits) >>> f = lambda qubits: qubits == IntQubit(2) >>> v = OracleGate(numqubits, f) >>> qapply(grover_iteration(basis_states, v)) |2> """ wgate = WGate(oracle.nqubits) return wgate*oracle*qstate def apply_grover(oracle, nqubits, iterations=None): """Applies grover's algorithm. Parameters ========== oracle : callable The unknown callable function that returns true when applied to the desired qubits and false otherwise. Returns ======= state : Expr The resulting state after Grover's algorithm has been iterated. Examples ======== Apply grover's algorithm to an even superposition of 2 qubits:: >>> from sympy.physics.quantum.qapply import qapply >>> from sympy.physics.quantum.qubit import IntQubit >>> from sympy.physics.quantum.grover import apply_grover >>> f = lambda qubits: qubits == IntQubit(2) >>> qapply(apply_grover(f, 2)) |2> """ if nqubits <= 0: raise QuantumError( 'Grover\'s algorithm needs nqubits > 0, received %r qubits' % nqubits ) if iterations is None: iterations = floor(sqrt(2**nqubits)*(pi/4)) v = OracleGate(nqubits, oracle) iterated = superposition_basis(nqubits) for iter in range(iterations): iterated = grover_iteration(iterated, v) iterated = qapply(iterated) return iterated sympy-sympy-1.9/sympy/physics/quantum/hilbert.py000066400000000000000000000457711412543434000223010ustar00rootroot00000000000000"""Hilbert spaces for quantum mechanics. Authors: * Brian Granger * Matt Curry """ from functools import reduce from sympy import Basic, Interval, oo, sympify from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.qexpr import QuantumError __all__ = [ 'HilbertSpaceError', 'HilbertSpace', 'TensorProductHilbertSpace', 'TensorPowerHilbertSpace', 'DirectSumHilbertSpace', 'ComplexSpace', 'L2', 'FockSpace' ] #----------------------------------------------------------------------------- # Main objects #----------------------------------------------------------------------------- class HilbertSpaceError(QuantumError): pass #----------------------------------------------------------------------------- # Main objects #----------------------------------------------------------------------------- class HilbertSpace(Basic): """An abstract Hilbert space for quantum mechanics. In short, a Hilbert space is an abstract vector space that is complete with inner products defined [1]_. Examples ======== >>> from sympy.physics.quantum.hilbert import HilbertSpace >>> hs = HilbertSpace() >>> hs H References ========== .. [1] https://en.wikipedia.org/wiki/Hilbert_space """ def __new__(cls): obj = Basic.__new__(cls) return obj @property def dimension(self): """Return the Hilbert dimension of the space.""" raise NotImplementedError('This Hilbert space has no dimension.') def __add__(self, other): return DirectSumHilbertSpace(self, other) def __radd__(self, other): return DirectSumHilbertSpace(other, self) def __mul__(self, other): return TensorProductHilbertSpace(self, other) def __rmul__(self, other): return TensorProductHilbertSpace(other, self) def __pow__(self, other, mod=None): if mod is not None: raise ValueError('The third argument to __pow__ is not supported \ for Hilbert spaces.') return TensorPowerHilbertSpace(self, other) def __contains__(self, other): """Is the operator or state in this Hilbert space. This is checked by comparing the classes of the Hilbert spaces, not the instances. This is to allow Hilbert Spaces with symbolic dimensions. """ if other.hilbert_space.__class__ == self.__class__: return True else: return False def _sympystr(self, printer, *args): return 'H' def _pretty(self, printer, *args): ustr = '\N{LATIN CAPITAL LETTER H}' return prettyForm(ustr) def _latex(self, printer, *args): return r'\mathcal{H}' class ComplexSpace(HilbertSpace): """Finite dimensional Hilbert space of complex vectors. The elements of this Hilbert space are n-dimensional complex valued vectors with the usual inner product that takes the complex conjugate of the vector on the right. A classic example of this type of Hilbert space is spin-1/2, which is ``ComplexSpace(2)``. Generalizing to spin-s, the space is ``ComplexSpace(2*s+1)``. Quantum computing with N qubits is done with the direct product space ``ComplexSpace(2)**N``. Examples ======== >>> from sympy import symbols >>> from sympy.physics.quantum.hilbert import ComplexSpace >>> c1 = ComplexSpace(2) >>> c1 C(2) >>> c1.dimension 2 >>> n = symbols('n') >>> c2 = ComplexSpace(n) >>> c2 C(n) >>> c2.dimension n """ def __new__(cls, dimension): dimension = sympify(dimension) r = cls.eval(dimension) if isinstance(r, Basic): return r obj = Basic.__new__(cls, dimension) return obj @classmethod def eval(cls, dimension): if len(dimension.atoms()) == 1: if not (dimension.is_Integer and dimension > 0 or dimension is oo or dimension.is_Symbol): raise TypeError('The dimension of a ComplexSpace can only' 'be a positive integer, oo, or a Symbol: %r' % dimension) else: for dim in dimension.atoms(): if not (dim.is_Integer or dim is oo or dim.is_Symbol): raise TypeError('The dimension of a ComplexSpace can only' ' contain integers, oo, or a Symbol: %r' % dim) @property def dimension(self): return self.args[0] def _sympyrepr(self, printer, *args): return "%s(%s)" % (self.__class__.__name__, printer._print(self.dimension, *args)) def _sympystr(self, printer, *args): return "C(%s)" % printer._print(self.dimension, *args) def _pretty(self, printer, *args): ustr = '\N{LATIN CAPITAL LETTER C}' pform_exp = printer._print(self.dimension, *args) pform_base = prettyForm(ustr) return pform_base**pform_exp def _latex(self, printer, *args): return r'\mathcal{C}^{%s}' % printer._print(self.dimension, *args) class L2(HilbertSpace): """The Hilbert space of square integrable functions on an interval. An L2 object takes in a single sympy Interval argument which represents the interval its functions (vectors) are defined on. Examples ======== >>> from sympy import Interval, oo >>> from sympy.physics.quantum.hilbert import L2 >>> hs = L2(Interval(0,oo)) >>> hs L2(Interval(0, oo)) >>> hs.dimension oo >>> hs.interval Interval(0, oo) """ def __new__(cls, interval): if not isinstance(interval, Interval): raise TypeError('L2 interval must be an Interval instance: %r' % interval) obj = Basic.__new__(cls, interval) return obj @property def dimension(self): return oo @property def interval(self): return self.args[0] def _sympyrepr(self, printer, *args): return "L2(%s)" % printer._print(self.interval, *args) def _sympystr(self, printer, *args): return "L2(%s)" % printer._print(self.interval, *args) def _pretty(self, printer, *args): pform_exp = prettyForm('2') pform_base = prettyForm('L') return pform_base**pform_exp def _latex(self, printer, *args): interval = printer._print(self.interval, *args) return r'{\mathcal{L}^2}\left( %s \right)' % interval class FockSpace(HilbertSpace): """The Hilbert space for second quantization. Technically, this Hilbert space is a infinite direct sum of direct products of single particle Hilbert spaces [1]_. This is a mess, so we have a class to represent it directly. Examples ======== >>> from sympy.physics.quantum.hilbert import FockSpace >>> hs = FockSpace() >>> hs F >>> hs.dimension oo References ========== .. [1] https://en.wikipedia.org/wiki/Fock_space """ def __new__(cls): obj = Basic.__new__(cls) return obj @property def dimension(self): return oo def _sympyrepr(self, printer, *args): return "FockSpace()" def _sympystr(self, printer, *args): return "F" def _pretty(self, printer, *args): ustr = '\N{LATIN CAPITAL LETTER F}' return prettyForm(ustr) def _latex(self, printer, *args): return r'\mathcal{F}' class TensorProductHilbertSpace(HilbertSpace): """A tensor product of Hilbert spaces [1]_. The tensor product between Hilbert spaces is represented by the operator ``*`` Products of the same Hilbert space will be combined into tensor powers. A ``TensorProductHilbertSpace`` object takes in an arbitrary number of ``HilbertSpace`` objects as its arguments. In addition, multiplication of ``HilbertSpace`` objects will automatically return this tensor product object. Examples ======== >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace >>> from sympy import symbols >>> c = ComplexSpace(2) >>> f = FockSpace() >>> hs = c*f >>> hs C(2)*F >>> hs.dimension oo >>> hs.spaces (C(2), F) >>> c1 = ComplexSpace(2) >>> n = symbols('n') >>> c2 = ComplexSpace(n) >>> hs = c1*c2 >>> hs C(2)*C(n) >>> hs.dimension 2*n References ========== .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products """ def __new__(cls, *args): r = cls.eval(args) if isinstance(r, Basic): return r obj = Basic.__new__(cls, *args) return obj @classmethod def eval(cls, args): """Evaluates the direct product.""" new_args = [] recall = False #flatten arguments for arg in args: if isinstance(arg, TensorProductHilbertSpace): new_args.extend(arg.args) recall = True elif isinstance(arg, (HilbertSpace, TensorPowerHilbertSpace)): new_args.append(arg) else: raise TypeError('Hilbert spaces can only be multiplied by \ other Hilbert spaces: %r' % arg) #combine like arguments into direct powers comb_args = [] prev_arg = None for new_arg in new_args: if prev_arg is not None: if isinstance(new_arg, TensorPowerHilbertSpace) and \ isinstance(prev_arg, TensorPowerHilbertSpace) and \ new_arg.base == prev_arg.base: prev_arg = new_arg.base**(new_arg.exp + prev_arg.exp) elif isinstance(new_arg, TensorPowerHilbertSpace) and \ new_arg.base == prev_arg: prev_arg = prev_arg**(new_arg.exp + 1) elif isinstance(prev_arg, TensorPowerHilbertSpace) and \ new_arg == prev_arg.base: prev_arg = new_arg**(prev_arg.exp + 1) elif new_arg == prev_arg: prev_arg = new_arg**2 else: comb_args.append(prev_arg) prev_arg = new_arg elif prev_arg is None: prev_arg = new_arg comb_args.append(prev_arg) if recall: return TensorProductHilbertSpace(*comb_args) elif len(comb_args) == 1: return TensorPowerHilbertSpace(comb_args[0].base, comb_args[0].exp) else: return None @property def dimension(self): arg_list = [arg.dimension for arg in self.args] if oo in arg_list: return oo else: return reduce(lambda x, y: x*y, arg_list) @property def spaces(self): """A tuple of the Hilbert spaces in this tensor product.""" return self.args def _spaces_printer(self, printer, *args): spaces_strs = [] for arg in self.args: s = printer._print(arg, *args) if isinstance(arg, DirectSumHilbertSpace): s = '(%s)' % s spaces_strs.append(s) return spaces_strs def _sympyrepr(self, printer, *args): spaces_reprs = self._spaces_printer(printer, *args) return "TensorProductHilbertSpace(%s)" % ','.join(spaces_reprs) def _sympystr(self, printer, *args): spaces_strs = self._spaces_printer(printer, *args) return '*'.join(spaces_strs) def _pretty(self, printer, *args): length = len(self.args) pform = printer._print('', *args) for i in range(length): next_pform = printer._print(self.args[i], *args) if isinstance(self.args[i], (DirectSumHilbertSpace, TensorProductHilbertSpace)): next_pform = prettyForm( *next_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(next_pform)) if i != length - 1: if printer._use_unicode: pform = prettyForm(*pform.right(' ' + '\N{N-ARY CIRCLED TIMES OPERATOR}' + ' ')) else: pform = prettyForm(*pform.right(' x ')) return pform def _latex(self, printer, *args): length = len(self.args) s = '' for i in range(length): arg_s = printer._print(self.args[i], *args) if isinstance(self.args[i], (DirectSumHilbertSpace, TensorProductHilbertSpace)): arg_s = r'\left(%s\right)' % arg_s s = s + arg_s if i != length - 1: s = s + r'\otimes ' return s class DirectSumHilbertSpace(HilbertSpace): """A direct sum of Hilbert spaces [1]_. This class uses the ``+`` operator to represent direct sums between different Hilbert spaces. A ``DirectSumHilbertSpace`` object takes in an arbitrary number of ``HilbertSpace`` objects as its arguments. Also, addition of ``HilbertSpace`` objects will automatically return a direct sum object. Examples ======== >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace >>> c = ComplexSpace(2) >>> f = FockSpace() >>> hs = c+f >>> hs C(2)+F >>> hs.dimension oo >>> list(hs.spaces) [C(2), F] References ========== .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Direct_sums """ def __new__(cls, *args): r = cls.eval(args) if isinstance(r, Basic): return r obj = Basic.__new__(cls, *args) return obj @classmethod def eval(cls, args): """Evaluates the direct product.""" new_args = [] recall = False #flatten arguments for arg in args: if isinstance(arg, DirectSumHilbertSpace): new_args.extend(arg.args) recall = True elif isinstance(arg, HilbertSpace): new_args.append(arg) else: raise TypeError('Hilbert spaces can only be summed with other \ Hilbert spaces: %r' % arg) if recall: return DirectSumHilbertSpace(*new_args) else: return None @property def dimension(self): arg_list = [arg.dimension for arg in self.args] if oo in arg_list: return oo else: return reduce(lambda x, y: x + y, arg_list) @property def spaces(self): """A tuple of the Hilbert spaces in this direct sum.""" return self.args def _sympyrepr(self, printer, *args): spaces_reprs = [printer._print(arg, *args) for arg in self.args] return "DirectSumHilbertSpace(%s)" % ','.join(spaces_reprs) def _sympystr(self, printer, *args): spaces_strs = [printer._print(arg, *args) for arg in self.args] return '+'.join(spaces_strs) def _pretty(self, printer, *args): length = len(self.args) pform = printer._print('', *args) for i in range(length): next_pform = printer._print(self.args[i], *args) if isinstance(self.args[i], (DirectSumHilbertSpace, TensorProductHilbertSpace)): next_pform = prettyForm( *next_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(next_pform)) if i != length - 1: if printer._use_unicode: pform = prettyForm(*pform.right(' \N{CIRCLED PLUS} ')) else: pform = prettyForm(*pform.right(' + ')) return pform def _latex(self, printer, *args): length = len(self.args) s = '' for i in range(length): arg_s = printer._print(self.args[i], *args) if isinstance(self.args[i], (DirectSumHilbertSpace, TensorProductHilbertSpace)): arg_s = r'\left(%s\right)' % arg_s s = s + arg_s if i != length - 1: s = s + r'\oplus ' return s class TensorPowerHilbertSpace(HilbertSpace): """An exponentiated Hilbert space [1]_. Tensor powers (repeated tensor products) are represented by the operator ``**`` Identical Hilbert spaces that are multiplied together will be automatically combined into a single tensor power object. Any Hilbert space, product, or sum may be raised to a tensor power. The ``TensorPowerHilbertSpace`` takes two arguments: the Hilbert space; and the tensor power (number). Examples ======== >>> from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace >>> from sympy import symbols >>> n = symbols('n') >>> c = ComplexSpace(2) >>> hs = c**n >>> hs C(2)**n >>> hs.dimension 2**n >>> c = ComplexSpace(2) >>> c*c C(2)**2 >>> f = FockSpace() >>> c*f*f C(2)*F**2 References ========== .. [1] https://en.wikipedia.org/wiki/Hilbert_space#Tensor_products """ def __new__(cls, *args): r = cls.eval(args) if isinstance(r, Basic): return r return Basic.__new__(cls, *r) @classmethod def eval(cls, args): new_args = args[0], sympify(args[1]) exp = new_args[1] #simplify hs**1 -> hs if exp == 1: return args[0] #simplify hs**0 -> 1 if exp == 0: return sympify(1) #check (and allow) for hs**(x+42+y...) case if len(exp.atoms()) == 1: if not (exp.is_Integer and exp >= 0 or exp.is_Symbol): raise ValueError('Hilbert spaces can only be raised to \ positive integers or Symbols: %r' % exp) else: for power in exp.atoms(): if not (power.is_Integer or power.is_Symbol): raise ValueError('Tensor powers can only contain integers \ or Symbols: %r' % power) return new_args @property def base(self): return self.args[0] @property def exp(self): return self.args[1] @property def dimension(self): if self.base.dimension is oo: return oo else: return self.base.dimension**self.exp def _sympyrepr(self, printer, *args): return "TensorPowerHilbertSpace(%s,%s)" % (printer._print(self.base, *args), printer._print(self.exp, *args)) def _sympystr(self, printer, *args): return "%s**%s" % (printer._print(self.base, *args), printer._print(self.exp, *args)) def _pretty(self, printer, *args): pform_exp = printer._print(self.exp, *args) if printer._use_unicode: pform_exp = prettyForm(*pform_exp.left(prettyForm('\N{N-ARY CIRCLED TIMES OPERATOR}'))) else: pform_exp = prettyForm(*pform_exp.left(prettyForm('x'))) pform_base = printer._print(self.base, *args) return pform_base**pform_exp def _latex(self, printer, *args): base = printer._print(self.base, *args) exp = printer._print(self.exp, *args) return r'{%s}^{\otimes %s}' % (base, exp) sympy-sympy-1.9/sympy/physics/quantum/identitysearch.py000066400000000000000000000655121412543434000236620ustar00rootroot00000000000000from collections import deque from random import randint from sympy.external import import_module from sympy import Mul, Basic, Number, Pow, Integer from sympy.physics.quantum.represent import represent from sympy.physics.quantum.dagger import Dagger __all__ = [ # Public interfaces 'generate_gate_rules', 'generate_equivalent_ids', 'GateIdentity', 'bfs_identity_search', 'random_identity_search', # "Private" functions 'is_scalar_sparse_matrix', 'is_scalar_nonsparse_matrix', 'is_degenerate', 'is_reducible', ] np = import_module('numpy') scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) def is_scalar_sparse_matrix(circuit, nqubits, identity_only, eps=1e-11): """Checks if a given scipy.sparse matrix is a scalar matrix. A scalar matrix is such that B = bI, where B is the scalar matrix, b is some scalar multiple, and I is the identity matrix. A scalar matrix would have only the element b along it's main diagonal and zeroes elsewhere. Parameters ========== circuit : Gate tuple Sequence of quantum gates representing a quantum circuit nqubits : int Number of qubits in the circuit identity_only : bool Check for only identity matrices eps : number The tolerance value for zeroing out elements in the matrix. Values in the range [-eps, +eps] will be changed to a zero. """ if not np or not scipy: pass matrix = represent(Mul(*circuit), nqubits=nqubits, format='scipy.sparse') # In some cases, represent returns a 1D scalar value in place # of a multi-dimensional scalar matrix if (isinstance(matrix, int)): return matrix == 1 if identity_only else True # If represent returns a matrix, check if the matrix is diagonal # and if every item along the diagonal is the same else: # Due to floating pointing operations, must zero out # elements that are "very" small in the dense matrix # See parameter for default value. # Get the ndarray version of the dense matrix dense_matrix = matrix.todense().getA() # Since complex values can't be compared, must split # the matrix into real and imaginary components # Find the real values in between -eps and eps bool_real = np.logical_and(dense_matrix.real > -eps, dense_matrix.real < eps) # Find the imaginary values between -eps and eps bool_imag = np.logical_and(dense_matrix.imag > -eps, dense_matrix.imag < eps) # Replaces values between -eps and eps with 0 corrected_real = np.where(bool_real, 0.0, dense_matrix.real) corrected_imag = np.where(bool_imag, 0.0, dense_matrix.imag) # Convert the matrix with real values into imaginary values corrected_imag = corrected_imag * complex(1j) # Recombine the real and imaginary components corrected_dense = corrected_real + corrected_imag # Check if it's diagonal row_indices = corrected_dense.nonzero()[0] col_indices = corrected_dense.nonzero()[1] # Check if the rows indices and columns indices are the same # If they match, then matrix only contains elements along diagonal bool_indices = row_indices == col_indices is_diagonal = bool_indices.all() first_element = corrected_dense[0][0] # If the first element is a zero, then can't rescale matrix # and definitely not diagonal if (first_element == 0.0 + 0.0j): return False # The dimensions of the dense matrix should still # be 2^nqubits if there are elements all along the # the main diagonal trace_of_corrected = (corrected_dense/first_element).trace() expected_trace = pow(2, nqubits) has_correct_trace = trace_of_corrected == expected_trace # If only looking for identity matrices # first element must be a 1 real_is_one = abs(first_element.real - 1.0) < eps imag_is_zero = abs(first_element.imag) < eps is_one = real_is_one and imag_is_zero is_identity = is_one if identity_only else True return bool(is_diagonal and has_correct_trace and is_identity) def is_scalar_nonsparse_matrix(circuit, nqubits, identity_only, eps=None): """Checks if a given circuit, in matrix form, is equivalent to a scalar value. Parameters ========== circuit : Gate tuple Sequence of quantum gates representing a quantum circuit nqubits : int Number of qubits in the circuit identity_only : bool Check for only identity matrices eps : number This argument is ignored. It is just for signature compatibility with is_scalar_sparse_matrix. Note: Used in situations when is_scalar_sparse_matrix has bugs """ matrix = represent(Mul(*circuit), nqubits=nqubits) # In some cases, represent returns a 1D scalar value in place # of a multi-dimensional scalar matrix if (isinstance(matrix, Number)): return matrix == 1 if identity_only else True # If represent returns a matrix, check if the matrix is diagonal # and if every item along the diagonal is the same else: # Added up the diagonal elements matrix_trace = matrix.trace() # Divide the trace by the first element in the matrix # if matrix is not required to be the identity matrix adjusted_matrix_trace = (matrix_trace/matrix[0] if not identity_only else matrix_trace) is_identity = matrix[0] == 1.0 if identity_only else True has_correct_trace = adjusted_matrix_trace == pow(2, nqubits) # The matrix is scalar if it's diagonal and the adjusted trace # value is equal to 2^nqubits return bool( matrix.is_diagonal() and has_correct_trace and is_identity) if np and scipy: is_scalar_matrix = is_scalar_sparse_matrix else: is_scalar_matrix = is_scalar_nonsparse_matrix def _get_min_qubits(a_gate): if isinstance(a_gate, Pow): return a_gate.base.min_qubits else: return a_gate.min_qubits def ll_op(left, right): """Perform a LL operation. A LL operation multiplies both left and right circuits with the dagger of the left circuit's leftmost gate, and the dagger is multiplied on the left side of both circuits. If a LL is possible, it returns the new gate rule as a 2-tuple (LHS, RHS), where LHS is the left circuit and and RHS is the right circuit of the new rule. If a LL is not possible, None is returned. Parameters ========== left : Gate tuple The left circuit of a gate rule expression. right : Gate tuple The right circuit of a gate rule expression. Examples ======== Generate a new gate rule using a LL operation: >>> from sympy.physics.quantum.identitysearch import ll_op >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> ll_op((x, y, z), ()) ((Y(0), Z(0)), (X(0),)) >>> ll_op((y, z), (x,)) ((Z(0),), (Y(0), X(0))) """ if (len(left) > 0): ll_gate = left[0] ll_gate_is_unitary = is_scalar_matrix( (Dagger(ll_gate), ll_gate), _get_min_qubits(ll_gate), True) if (len(left) > 0 and ll_gate_is_unitary): # Get the new left side w/o the leftmost gate new_left = left[1:len(left)] # Add the leftmost gate to the left position on the right side new_right = (Dagger(ll_gate),) + right # Return the new gate rule return (new_left, new_right) return None def lr_op(left, right): """Perform a LR operation. A LR operation multiplies both left and right circuits with the dagger of the left circuit's rightmost gate, and the dagger is multiplied on the right side of both circuits. If a LR is possible, it returns the new gate rule as a 2-tuple (LHS, RHS), where LHS is the left circuit and and RHS is the right circuit of the new rule. If a LR is not possible, None is returned. Parameters ========== left : Gate tuple The left circuit of a gate rule expression. right : Gate tuple The right circuit of a gate rule expression. Examples ======== Generate a new gate rule using a LR operation: >>> from sympy.physics.quantum.identitysearch import lr_op >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> lr_op((x, y, z), ()) ((X(0), Y(0)), (Z(0),)) >>> lr_op((x, y), (z,)) ((X(0),), (Z(0), Y(0))) """ if (len(left) > 0): lr_gate = left[len(left) - 1] lr_gate_is_unitary = is_scalar_matrix( (Dagger(lr_gate), lr_gate), _get_min_qubits(lr_gate), True) if (len(left) > 0 and lr_gate_is_unitary): # Get the new left side w/o the rightmost gate new_left = left[0:len(left) - 1] # Add the rightmost gate to the right position on the right side new_right = right + (Dagger(lr_gate),) # Return the new gate rule return (new_left, new_right) return None def rl_op(left, right): """Perform a RL operation. A RL operation multiplies both left and right circuits with the dagger of the right circuit's leftmost gate, and the dagger is multiplied on the left side of both circuits. If a RL is possible, it returns the new gate rule as a 2-tuple (LHS, RHS), where LHS is the left circuit and and RHS is the right circuit of the new rule. If a RL is not possible, None is returned. Parameters ========== left : Gate tuple The left circuit of a gate rule expression. right : Gate tuple The right circuit of a gate rule expression. Examples ======== Generate a new gate rule using a RL operation: >>> from sympy.physics.quantum.identitysearch import rl_op >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> rl_op((x,), (y, z)) ((Y(0), X(0)), (Z(0),)) >>> rl_op((x, y), (z,)) ((Z(0), X(0), Y(0)), ()) """ if (len(right) > 0): rl_gate = right[0] rl_gate_is_unitary = is_scalar_matrix( (Dagger(rl_gate), rl_gate), _get_min_qubits(rl_gate), True) if (len(right) > 0 and rl_gate_is_unitary): # Get the new right side w/o the leftmost gate new_right = right[1:len(right)] # Add the leftmost gate to the left position on the left side new_left = (Dagger(rl_gate),) + left # Return the new gate rule return (new_left, new_right) return None def rr_op(left, right): """Perform a RR operation. A RR operation multiplies both left and right circuits with the dagger of the right circuit's rightmost gate, and the dagger is multiplied on the right side of both circuits. If a RR is possible, it returns the new gate rule as a 2-tuple (LHS, RHS), where LHS is the left circuit and and RHS is the right circuit of the new rule. If a RR is not possible, None is returned. Parameters ========== left : Gate tuple The left circuit of a gate rule expression. right : Gate tuple The right circuit of a gate rule expression. Examples ======== Generate a new gate rule using a RR operation: >>> from sympy.physics.quantum.identitysearch import rr_op >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> rr_op((x, y), (z,)) ((X(0), Y(0), Z(0)), ()) >>> rr_op((x,), (y, z)) ((X(0), Z(0)), (Y(0),)) """ if (len(right) > 0): rr_gate = right[len(right) - 1] rr_gate_is_unitary = is_scalar_matrix( (Dagger(rr_gate), rr_gate), _get_min_qubits(rr_gate), True) if (len(right) > 0 and rr_gate_is_unitary): # Get the new right side w/o the rightmost gate new_right = right[0:len(right) - 1] # Add the rightmost gate to the right position on the right side new_left = left + (Dagger(rr_gate),) # Return the new gate rule return (new_left, new_right) return None def generate_gate_rules(gate_seq, return_as_muls=False): """Returns a set of gate rules. Each gate rules is represented as a 2-tuple of tuples or Muls. An empty tuple represents an arbitrary scalar value. This function uses the four operations (LL, LR, RL, RR) to generate the gate rules. A gate rule is an expression such as ABC = D or AB = CD, where A, B, C, and D are gates. Each value on either side of the equal sign represents a circuit. The four operations allow one to find a set of equivalent circuits from a gate identity. The letters denoting the operation tell the user what activities to perform on each expression. The first letter indicates which side of the equal sign to focus on. The second letter indicates which gate to focus on given the side. Once this information is determined, the inverse of the gate is multiplied on both circuits to create a new gate rule. For example, given the identity, ABCD = 1, a LL operation means look at the left value and multiply both left sides by the inverse of the leftmost gate A. If A is Hermitian, the inverse of A is still A. The resulting new rule is BCD = A. The following is a summary of the four operations. Assume that in the examples, all gates are Hermitian. LL : left circuit, left multiply ABCD = E -> AABCD = AE -> BCD = AE LR : left circuit, right multiply ABCD = E -> ABCDD = ED -> ABC = ED RL : right circuit, left multiply ABC = ED -> EABC = EED -> EABC = D RR : right circuit, right multiply AB = CD -> ABD = CDD -> ABD = C The number of gate rules generated is n*(n+1), where n is the number of gates in the sequence (unproven). Parameters ========== gate_seq : Gate tuple, Mul, or Number A variable length tuple or Mul of Gates whose product is equal to a scalar matrix return_as_muls : bool True to return a set of Muls; False to return a set of tuples Examples ======== Find the gate rules of the current circuit using tuples: >>> from sympy.physics.quantum.identitysearch import generate_gate_rules >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> generate_gate_rules((x, x)) {((X(0),), (X(0),)), ((X(0), X(0)), ())} >>> generate_gate_rules((x, y, z)) {((), (X(0), Z(0), Y(0))), ((), (Y(0), X(0), Z(0))), ((), (Z(0), Y(0), X(0))), ((X(0),), (Z(0), Y(0))), ((Y(0),), (X(0), Z(0))), ((Z(0),), (Y(0), X(0))), ((X(0), Y(0)), (Z(0),)), ((Y(0), Z(0)), (X(0),)), ((Z(0), X(0)), (Y(0),)), ((X(0), Y(0), Z(0)), ()), ((Y(0), Z(0), X(0)), ()), ((Z(0), X(0), Y(0)), ())} Find the gate rules of the current circuit using Muls: >>> generate_gate_rules(x*x, return_as_muls=True) {(1, 1)} >>> generate_gate_rules(x*y*z, return_as_muls=True) {(1, X(0)*Z(0)*Y(0)), (1, Y(0)*X(0)*Z(0)), (1, Z(0)*Y(0)*X(0)), (X(0)*Y(0), Z(0)), (Y(0)*Z(0), X(0)), (Z(0)*X(0), Y(0)), (X(0)*Y(0)*Z(0), 1), (Y(0)*Z(0)*X(0), 1), (Z(0)*X(0)*Y(0), 1), (X(0), Z(0)*Y(0)), (Y(0), X(0)*Z(0)), (Z(0), Y(0)*X(0))} """ if isinstance(gate_seq, Number): if return_as_muls: return {(Integer(1), Integer(1))} else: return {((), ())} elif isinstance(gate_seq, Mul): gate_seq = gate_seq.args # Each item in queue is a 3-tuple: # i) first item is the left side of an equality # ii) second item is the right side of an equality # iii) third item is the number of operations performed # The argument, gate_seq, will start on the left side, and # the right side will be empty, implying the presence of an # identity. queue = deque() # A set of gate rules rules = set() # Maximum number of operations to perform max_ops = len(gate_seq) def process_new_rule(new_rule, ops): if new_rule is not None: new_left, new_right = new_rule if new_rule not in rules and (new_right, new_left) not in rules: rules.add(new_rule) # If haven't reached the max limit on operations if ops + 1 < max_ops: queue.append(new_rule + (ops + 1,)) queue.append((gate_seq, (), 0)) rules.add((gate_seq, ())) while len(queue) > 0: left, right, ops = queue.popleft() # Do a LL new_rule = ll_op(left, right) process_new_rule(new_rule, ops) # Do a LR new_rule = lr_op(left, right) process_new_rule(new_rule, ops) # Do a RL new_rule = rl_op(left, right) process_new_rule(new_rule, ops) # Do a RR new_rule = rr_op(left, right) process_new_rule(new_rule, ops) if return_as_muls: # Convert each rule as tuples into a rule as muls mul_rules = set() for rule in rules: left, right = rule mul_rules.add((Mul(*left), Mul(*right))) rules = mul_rules return rules def generate_equivalent_ids(gate_seq, return_as_muls=False): """Returns a set of equivalent gate identities. A gate identity is a quantum circuit such that the product of the gates in the circuit is equal to a scalar value. For example, XYZ = i, where X, Y, Z are the Pauli gates and i is the imaginary value, is considered a gate identity. This function uses the four operations (LL, LR, RL, RR) to generate the gate rules and, subsequently, to locate equivalent gate identities. Note that all equivalent identities are reachable in n operations from the starting gate identity, where n is the number of gates in the sequence. The max number of gate identities is 2n, where n is the number of gates in the sequence (unproven). Parameters ========== gate_seq : Gate tuple, Mul, or Number A variable length tuple or Mul of Gates whose product is equal to a scalar matrix. return_as_muls: bool True to return as Muls; False to return as tuples Examples ======== Find equivalent gate identities from the current circuit with tuples: >>> from sympy.physics.quantum.identitysearch import generate_equivalent_ids >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> generate_equivalent_ids((x, x)) {(X(0), X(0))} >>> generate_equivalent_ids((x, y, z)) {(X(0), Y(0), Z(0)), (X(0), Z(0), Y(0)), (Y(0), X(0), Z(0)), (Y(0), Z(0), X(0)), (Z(0), X(0), Y(0)), (Z(0), Y(0), X(0))} Find equivalent gate identities from the current circuit with Muls: >>> generate_equivalent_ids(x*x, return_as_muls=True) {1} >>> generate_equivalent_ids(x*y*z, return_as_muls=True) {X(0)*Y(0)*Z(0), X(0)*Z(0)*Y(0), Y(0)*X(0)*Z(0), Y(0)*Z(0)*X(0), Z(0)*X(0)*Y(0), Z(0)*Y(0)*X(0)} """ if isinstance(gate_seq, Number): return {Integer(1)} elif isinstance(gate_seq, Mul): gate_seq = gate_seq.args # Filter through the gate rules and keep the rules # with an empty tuple either on the left or right side # A set of equivalent gate identities eq_ids = set() gate_rules = generate_gate_rules(gate_seq) for rule in gate_rules: l, r = rule if l == (): eq_ids.add(r) elif r == (): eq_ids.add(l) if return_as_muls: convert_to_mul = lambda id_seq: Mul(*id_seq) eq_ids = set(map(convert_to_mul, eq_ids)) return eq_ids class GateIdentity(Basic): """Wrapper class for circuits that reduce to a scalar value. A gate identity is a quantum circuit such that the product of the gates in the circuit is equal to a scalar value. For example, XYZ = i, where X, Y, Z are the Pauli gates and i is the imaginary value, is considered a gate identity. Parameters ========== args : Gate tuple A variable length tuple of Gates that form an identity. Examples ======== Create a GateIdentity and look at its attributes: >>> from sympy.physics.quantum.identitysearch import GateIdentity >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> an_identity = GateIdentity(x, y, z) >>> an_identity.circuit X(0)*Y(0)*Z(0) >>> an_identity.equivalent_ids {(X(0), Y(0), Z(0)), (X(0), Z(0), Y(0)), (Y(0), X(0), Z(0)), (Y(0), Z(0), X(0)), (Z(0), X(0), Y(0)), (Z(0), Y(0), X(0))} """ def __new__(cls, *args): # args should be a tuple - a variable length argument list obj = Basic.__new__(cls, *args) obj._circuit = Mul(*args) obj._rules = generate_gate_rules(args) obj._eq_ids = generate_equivalent_ids(args) return obj @property def circuit(self): return self._circuit @property def gate_rules(self): return self._rules @property def equivalent_ids(self): return self._eq_ids @property def sequence(self): return self.args def __str__(self): """Returns the string of gates in a tuple.""" return str(self.circuit) def is_degenerate(identity_set, gate_identity): """Checks if a gate identity is a permutation of another identity. Parameters ========== identity_set : set A Python set with GateIdentity objects. gate_identity : GateIdentity The GateIdentity to check for existence in the set. Examples ======== Check if the identity is a permutation of another identity: >>> from sympy.physics.quantum.identitysearch import ( ... GateIdentity, is_degenerate) >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> an_identity = GateIdentity(x, y, z) >>> id_set = {an_identity} >>> another_id = (y, z, x) >>> is_degenerate(id_set, another_id) True >>> another_id = (x, x) >>> is_degenerate(id_set, another_id) False """ # For now, just iteratively go through the set and check if the current # gate_identity is a permutation of an identity in the set for an_id in identity_set: if (gate_identity in an_id.equivalent_ids): return True return False def is_reducible(circuit, nqubits, begin, end): """Determines if a circuit is reducible by checking if its subcircuits are scalar values. Parameters ========== circuit : Gate tuple A tuple of Gates representing a circuit. The circuit to check if a gate identity is contained in a subcircuit. nqubits : int The number of qubits the circuit operates on. begin : int The leftmost gate in the circuit to include in a subcircuit. end : int The rightmost gate in the circuit to include in a subcircuit. Examples ======== Check if the circuit can be reduced: >>> from sympy.physics.quantum.identitysearch import is_reducible >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> is_reducible((x, y, z), 1, 0, 3) True Check if an interval in the circuit can be reduced: >>> is_reducible((x, y, z), 1, 1, 3) False >>> is_reducible((x, y, y), 1, 1, 3) True """ current_circuit = () # Start from the gate at "end" and go down to almost the gate at "begin" for ndx in reversed(range(begin, end)): next_gate = circuit[ndx] current_circuit = (next_gate,) + current_circuit # If a circuit as a matrix is equivalent to a scalar value if (is_scalar_matrix(current_circuit, nqubits, False)): return True return False def bfs_identity_search(gate_list, nqubits, max_depth=None, identity_only=False): """Constructs a set of gate identities from the list of possible gates. Performs a breadth first search over the space of gate identities. This allows the finding of the shortest gate identities first. Parameters ========== gate_list : list, Gate A list of Gates from which to search for gate identities. nqubits : int The number of qubits the quantum circuit operates on. max_depth : int The longest quantum circuit to construct from gate_list. identity_only : bool True to search for gate identities that reduce to identity; False to search for gate identities that reduce to a scalar. Examples ======== Find a list of gate identities: >>> from sympy.physics.quantum.identitysearch import bfs_identity_search >>> from sympy.physics.quantum.gate import X, Y, Z >>> x = X(0); y = Y(0); z = Z(0) >>> bfs_identity_search([x], 1, max_depth=2) {GateIdentity(X(0), X(0))} >>> bfs_identity_search([x, y, z], 1) {GateIdentity(X(0), X(0)), GateIdentity(Y(0), Y(0)), GateIdentity(Z(0), Z(0)), GateIdentity(X(0), Y(0), Z(0))} Find a list of identities that only equal to 1: >>> bfs_identity_search([x, y, z], 1, identity_only=True) {GateIdentity(X(0), X(0)), GateIdentity(Y(0), Y(0)), GateIdentity(Z(0), Z(0))} """ if max_depth is None or max_depth <= 0: max_depth = len(gate_list) id_only = identity_only # Start with an empty sequence (implicitly contains an IdentityGate) queue = deque([()]) # Create an empty set of gate identities ids = set() # Begin searching for gate identities in given space. while (len(queue) > 0): current_circuit = queue.popleft() for next_gate in gate_list: new_circuit = current_circuit + (next_gate,) # Determines if a (strict) subcircuit is a scalar matrix circuit_reducible = is_reducible(new_circuit, nqubits, 1, len(new_circuit)) # In many cases when the matrix is a scalar value, # the evaluated matrix will actually be an integer if (is_scalar_matrix(new_circuit, nqubits, id_only) and not is_degenerate(ids, new_circuit) and not circuit_reducible): ids.add(GateIdentity(*new_circuit)) elif (len(new_circuit) < max_depth and not circuit_reducible): queue.append(new_circuit) return ids def random_identity_search(gate_list, numgates, nqubits): """Randomly selects numgates from gate_list and checks if it is a gate identity. If the circuit is a gate identity, the circuit is returned; Otherwise, None is returned. """ gate_size = len(gate_list) circuit = () for i in range(numgates): next_gate = gate_list[randint(0, gate_size - 1)] circuit = circuit + (next_gate,) is_scalar = is_scalar_matrix(circuit, nqubits, False) return circuit if is_scalar else None sympy-sympy-1.9/sympy/physics/quantum/innerproduct.py000066400000000000000000000101751412543434000233520ustar00rootroot00000000000000"""Symbolic inner product.""" from sympy import Expr, conjugate from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.state import KetBase, BraBase __all__ = [ 'InnerProduct' ] # InnerProduct is not an QExpr because it is really just a regular commutative # number. We have gone back and forth about this, but we gain a lot by having # it subclass Expr. The main challenges were getting Dagger to work # (we use _eval_conjugate) and represent (we can use atoms and subs). Having # it be an Expr, mean that there are no commutative QExpr subclasses, # which simplifies the design of everything. class InnerProduct(Expr): """An unevaluated inner product between a Bra and a Ket [1]. Parameters ========== bra : BraBase or subclass The bra on the left side of the inner product. ket : KetBase or subclass The ket on the right side of the inner product. Examples ======== Create an InnerProduct and check its properties: >>> from sympy.physics.quantum import Bra, Ket >>> b = Bra('b') >>> k = Ket('k') >>> ip = b*k >>> ip >>> ip.bra >> ip.ket |k> In simple products of kets and bras inner products will be automatically identified and created:: >>> b*k But in more complex expressions, there is ambiguity in whether inner or outer products should be created:: >>> k*b*k*b |k>*>> k*(b*k)*b *|k>* moved to the left of the expression because inner products are commutative complex numbers. References ========== .. [1] https://en.wikipedia.org/wiki/Inner_product """ is_complex = True def __new__(cls, bra, ket): if not isinstance(ket, KetBase): raise TypeError('KetBase subclass expected, got: %r' % ket) if not isinstance(bra, BraBase): raise TypeError('BraBase subclass expected, got: %r' % ket) obj = Expr.__new__(cls, bra, ket) return obj @property def bra(self): return self.args[0] @property def ket(self): return self.args[1] def _eval_conjugate(self): return InnerProduct(Dagger(self.ket), Dagger(self.bra)) def _sympyrepr(self, printer, *args): return '%s(%s,%s)' % (self.__class__.__name__, printer._print(self.bra, *args), printer._print(self.ket, *args)) def _sympystr(self, printer, *args): sbra = printer._print(self.bra) sket = printer._print(self.ket) return '%s|%s' % (sbra[:-1], sket[1:]) def _pretty(self, printer, *args): # Print state contents bra = self.bra._print_contents_pretty(printer, *args) ket = self.ket._print_contents_pretty(printer, *args) # Print brackets height = max(bra.height(), ket.height()) use_unicode = printer._use_unicode lbracket, _ = self.bra._pretty_brackets(height, use_unicode) cbracket, rbracket = self.ket._pretty_brackets(height, use_unicode) # Build innerproduct pform = prettyForm(*bra.left(lbracket)) pform = prettyForm(*pform.right(cbracket)) pform = prettyForm(*pform.right(ket)) pform = prettyForm(*pform.right(rbracket)) return pform def _latex(self, printer, *args): bra_label = self.bra._print_contents_latex(printer, *args) ket = printer._print(self.ket, *args) return r'\left\langle %s \right. %s' % (bra_label, ket) def doit(self, **hints): try: r = self.ket._eval_innerproduct(self.bra, **hints) except NotImplementedError: try: r = conjugate( self.bra.dual._eval_innerproduct(self.ket.dual, **hints) ) except NotImplementedError: r = None if r is not None: return r return self sympy-sympy-1.9/sympy/physics/quantum/matrixcache.py000066400000000000000000000066061412543434000231320ustar00rootroot00000000000000"""A cache for storing small matrices in multiple formats.""" from sympy import Matrix, I, Pow, Rational, exp, pi from sympy.physics.quantum.matrixutils import ( to_sympy, to_numpy, to_scipy_sparse ) class MatrixCache: """A cache for small matrices in different formats. This class takes small matrices in the standard ``sympy.Matrix`` format, and then converts these to both ``numpy.matrix`` and ``scipy.sparse.csr_matrix`` matrices. These matrices are then stored for future recovery. """ def __init__(self, dtype='complex'): self._cache = {} self.dtype = dtype def cache_matrix(self, name, m): """Cache a matrix by its name. Parameters ---------- name : str A descriptive name for the matrix, like "identity2". m : list of lists The raw matrix data as a sympy Matrix. """ try: self._sympy_matrix(name, m) except ImportError: pass try: self._numpy_matrix(name, m) except ImportError: pass try: self._scipy_sparse_matrix(name, m) except ImportError: pass def get_matrix(self, name, format): """Get a cached matrix by name and format. Parameters ---------- name : str A descriptive name for the matrix, like "identity2". format : str The format desired ('sympy', 'numpy', 'scipy.sparse') """ m = self._cache.get((name, format)) if m is not None: return m raise NotImplementedError( 'Matrix with name %s and format %s is not available.' % (name, format) ) def _store_matrix(self, name, format, m): self._cache[(name, format)] = m def _sympy_matrix(self, name, m): self._store_matrix(name, 'sympy', to_sympy(m)) def _numpy_matrix(self, name, m): m = to_numpy(m, dtype=self.dtype) self._store_matrix(name, 'numpy', m) def _scipy_sparse_matrix(self, name, m): # TODO: explore different sparse formats. But sparse.kron will use # coo in most cases, so we use that here. m = to_scipy_sparse(m, dtype=self.dtype) self._store_matrix(name, 'scipy.sparse', m) sqrt2_inv = Pow(2, Rational(-1, 2), evaluate=False) # Save the common matrices that we will need matrix_cache = MatrixCache() matrix_cache.cache_matrix('eye2', Matrix([[1, 0], [0, 1]])) matrix_cache.cache_matrix('op11', Matrix([[0, 0], [0, 1]])) # |1><1| matrix_cache.cache_matrix('op00', Matrix([[1, 0], [0, 0]])) # |0><0| matrix_cache.cache_matrix('op10', Matrix([[0, 0], [1, 0]])) # |1><0| matrix_cache.cache_matrix('op01', Matrix([[0, 1], [0, 0]])) # |0><1| matrix_cache.cache_matrix('X', Matrix([[0, 1], [1, 0]])) matrix_cache.cache_matrix('Y', Matrix([[0, -I], [I, 0]])) matrix_cache.cache_matrix('Z', Matrix([[1, 0], [0, -1]])) matrix_cache.cache_matrix('S', Matrix([[1, 0], [0, I]])) matrix_cache.cache_matrix('T', Matrix([[1, 0], [0, exp(I*pi/4)]])) matrix_cache.cache_matrix('H', sqrt2_inv*Matrix([[1, 1], [1, -1]])) matrix_cache.cache_matrix('Hsqrt2', Matrix([[1, 1], [1, -1]])) matrix_cache.cache_matrix( 'SWAP', Matrix([[1, 0, 0, 0], [0, 0, 1, 0], [0, 1, 0, 0], [0, 0, 0, 1]])) matrix_cache.cache_matrix('ZX', sqrt2_inv*Matrix([[1, 1], [1, -1]])) matrix_cache.cache_matrix('ZY', Matrix([[I, 0], [0, -I]])) sympy-sympy-1.9/sympy/physics/quantum/matrixutils.py000066400000000000000000000203341412543434000232210ustar00rootroot00000000000000"""Utilities to deal with sympy.Matrix, numpy and scipy.sparse.""" from sympy import MatrixBase, I, Expr, Integer from sympy.matrices import eye, zeros from sympy.external import import_module __all__ = [ 'numpy_ndarray', 'scipy_sparse_matrix', 'sympy_to_numpy', 'sympy_to_scipy_sparse', 'numpy_to_sympy', 'scipy_sparse_to_sympy', 'flatten_scalar', 'matrix_dagger', 'to_sympy', 'to_numpy', 'to_scipy_sparse', 'matrix_tensor_product', 'matrix_zeros' ] # Conditionally define the base classes for numpy and scipy.sparse arrays # for use in isinstance tests. np = import_module('numpy') if not np: class numpy_ndarray: pass else: numpy_ndarray = np.ndarray # type: ignore scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) if not scipy: class scipy_sparse_matrix: pass sparse = None else: sparse = scipy.sparse # Try to find spmatrix. if hasattr(sparse, 'base'): # Newer versions have it under scipy.sparse.base. scipy_sparse_matrix = sparse.base.spmatrix # type: ignore elif hasattr(sparse, 'sparse'): # Older versions have it under scipy.sparse.sparse. scipy_sparse_matrix = sparse.sparse.spmatrix # type: ignore def sympy_to_numpy(m, **options): """Convert a sympy Matrix/complex number to a numpy matrix or scalar.""" if not np: raise ImportError dtype = options.get('dtype', 'complex') if isinstance(m, MatrixBase): return np.matrix(m.tolist(), dtype=dtype) elif isinstance(m, Expr): if m.is_Number or m.is_NumberSymbol or m == I: return complex(m) raise TypeError('Expected MatrixBase or complex scalar, got: %r' % m) def sympy_to_scipy_sparse(m, **options): """Convert a sympy Matrix/complex number to a numpy matrix or scalar.""" if not np or not sparse: raise ImportError dtype = options.get('dtype', 'complex') if isinstance(m, MatrixBase): return sparse.csr_matrix(np.matrix(m.tolist(), dtype=dtype)) elif isinstance(m, Expr): if m.is_Number or m.is_NumberSymbol or m == I: return complex(m) raise TypeError('Expected MatrixBase or complex scalar, got: %r' % m) def scipy_sparse_to_sympy(m, **options): """Convert a scipy.sparse matrix to a sympy matrix.""" return MatrixBase(m.todense()) def numpy_to_sympy(m, **options): """Convert a numpy matrix to a sympy matrix.""" return MatrixBase(m) def to_sympy(m, **options): """Convert a numpy/scipy.sparse matrix to a sympy matrix.""" if isinstance(m, MatrixBase): return m elif isinstance(m, numpy_ndarray): return numpy_to_sympy(m) elif isinstance(m, scipy_sparse_matrix): return scipy_sparse_to_sympy(m) elif isinstance(m, Expr): return m raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % m) def to_numpy(m, **options): """Convert a sympy/scipy.sparse matrix to a numpy matrix.""" dtype = options.get('dtype', 'complex') if isinstance(m, (MatrixBase, Expr)): return sympy_to_numpy(m, dtype=dtype) elif isinstance(m, numpy_ndarray): return m elif isinstance(m, scipy_sparse_matrix): return m.todense() raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % m) def to_scipy_sparse(m, **options): """Convert a sympy/numpy matrix to a scipy.sparse matrix.""" dtype = options.get('dtype', 'complex') if isinstance(m, (MatrixBase, Expr)): return sympy_to_scipy_sparse(m, dtype=dtype) elif isinstance(m, numpy_ndarray): if not sparse: raise ImportError return sparse.csr_matrix(m) elif isinstance(m, scipy_sparse_matrix): return m raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % m) def flatten_scalar(e): """Flatten a 1x1 matrix to a scalar, return larger matrices unchanged.""" if isinstance(e, MatrixBase): if e.shape == (1, 1): e = e[0] if isinstance(e, (numpy_ndarray, scipy_sparse_matrix)): if e.shape == (1, 1): e = complex(e[0, 0]) return e def matrix_dagger(e): """Return the dagger of a sympy/numpy/scipy.sparse matrix.""" if isinstance(e, MatrixBase): return e.H elif isinstance(e, (numpy_ndarray, scipy_sparse_matrix)): return e.conjugate().transpose() raise TypeError('Expected sympy/numpy/scipy.sparse matrix, got: %r' % e) # TODO: Move this into sympy.matricies. def _sympy_tensor_product(*matrices): """Compute the kronecker product of a sequence of sympy Matrices. """ from sympy.matrices.expressions.kronecker import matrix_kronecker_product return matrix_kronecker_product(*matrices) def _numpy_tensor_product(*product): """numpy version of tensor product of multiple arguments.""" if not np: raise ImportError answer = product[0] for item in product[1:]: answer = np.kron(answer, item) return answer def _scipy_sparse_tensor_product(*product): """scipy.sparse version of tensor product of multiple arguments.""" if not sparse: raise ImportError answer = product[0] for item in product[1:]: answer = sparse.kron(answer, item) # The final matrices will just be multiplied, so csr is a good final # sparse format. return sparse.csr_matrix(answer) def matrix_tensor_product(*product): """Compute the matrix tensor product of sympy/numpy/scipy.sparse matrices.""" if isinstance(product[0], MatrixBase): return _sympy_tensor_product(*product) elif isinstance(product[0], numpy_ndarray): return _numpy_tensor_product(*product) elif isinstance(product[0], scipy_sparse_matrix): return _scipy_sparse_tensor_product(*product) def _numpy_eye(n): """numpy version of complex eye.""" if not np: raise ImportError return np.matrix(np.eye(n, dtype='complex')) def _scipy_sparse_eye(n): """scipy.sparse version of complex eye.""" if not sparse: raise ImportError return sparse.eye(n, n, dtype='complex') def matrix_eye(n, **options): """Get the version of eye and tensor_product for a given format.""" format = options.get('format', 'sympy') if format == 'sympy': return eye(n) elif format == 'numpy': return _numpy_eye(n) elif format == 'scipy.sparse': return _scipy_sparse_eye(n) raise NotImplementedError('Invalid format: %r' % format) def _numpy_zeros(m, n, **options): """numpy version of zeros.""" dtype = options.get('dtype', 'float64') if not np: raise ImportError return np.zeros((m, n), dtype=dtype) def _scipy_sparse_zeros(m, n, **options): """scipy.sparse version of zeros.""" spmatrix = options.get('spmatrix', 'csr') dtype = options.get('dtype', 'float64') if not sparse: raise ImportError if spmatrix == 'lil': return sparse.lil_matrix((m, n), dtype=dtype) elif spmatrix == 'csr': return sparse.csr_matrix((m, n), dtype=dtype) def matrix_zeros(m, n, **options): """"Get a zeros matrix for a given format.""" format = options.get('format', 'sympy') if format == 'sympy': return zeros(m, n) elif format == 'numpy': return _numpy_zeros(m, n, **options) elif format == 'scipy.sparse': return _scipy_sparse_zeros(m, n, **options) raise NotImplementedError('Invaild format: %r' % format) def _numpy_matrix_to_zero(e): """Convert a numpy zero matrix to the zero scalar.""" if not np: raise ImportError test = np.zeros_like(e) if np.allclose(e, test): return 0.0 else: return e def _scipy_sparse_matrix_to_zero(e): """Convert a scipy.sparse zero matrix to the zero scalar.""" if not np: raise ImportError edense = e.todense() test = np.zeros_like(edense) if np.allclose(edense, test): return 0.0 else: return e def matrix_to_zero(e): """Convert a zero matrix to the scalar zero.""" if isinstance(e, MatrixBase): if zeros(*e.shape) == e: e = Integer(0) elif isinstance(e, numpy_ndarray): e = _numpy_matrix_to_zero(e) elif isinstance(e, scipy_sparse_matrix): e = _scipy_sparse_matrix_to_zero(e) return e sympy-sympy-1.9/sympy/physics/quantum/operator.py000066400000000000000000000451171412543434000224750ustar00rootroot00000000000000"""Quantum mechanical operators. TODO: * Fix early 0 in apply_operators. * Debug and test apply_operators. * Get cse working with classes in this file. * Doctests and documentation of special methods for InnerProduct, Commutator, AntiCommutator, represent, apply_operators. """ from sympy import Derivative, Expr, Integer, oo, Mul, expand, Add from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.qexpr import QExpr, dispatch_method from sympy.matrices import eye __all__ = [ 'Operator', 'HermitianOperator', 'UnitaryOperator', 'IdentityOperator', 'OuterProduct', 'DifferentialOperator' ] #----------------------------------------------------------------------------- # Operators and outer products #----------------------------------------------------------------------------- class Operator(QExpr): """Base class for non-commuting quantum operators. An operator maps between quantum states [1]_. In quantum mechanics, observables (including, but not limited to, measured physical values) are represented as Hermitian operators [2]_. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the operator. For time-dependent operators, this will include the time. Examples ======== Create an operator and examine its attributes:: >>> from sympy.physics.quantum import Operator >>> from sympy import I >>> A = Operator('A') >>> A A >>> A.hilbert_space H >>> A.label (A,) >>> A.is_commutative False Create another operator and do some arithmetic operations:: >>> B = Operator('B') >>> C = 2*A*A + I*B >>> C 2*A**2 + I*B Operators don't commute:: >>> A.is_commutative False >>> B.is_commutative False >>> A*B == B*A False Polymonials of operators respect the commutation properties:: >>> e = (A+B)**3 >>> e.expand() A*B*A + A*B**2 + A**2*B + A**3 + B*A*B + B*A**2 + B**2*A + B**3 Operator inverses are handle symbolically:: >>> A.inv() A**(-1) >>> A*A.inv() 1 References ========== .. [1] https://en.wikipedia.org/wiki/Operator_%28physics%29 .. [2] https://en.wikipedia.org/wiki/Observable """ @classmethod def default_args(self): return ("O",) #------------------------------------------------------------------------- # Printing #------------------------------------------------------------------------- _label_separator = ',' def _print_operator_name(self, printer, *args): return self.__class__.__name__ _print_operator_name_latex = _print_operator_name def _print_operator_name_pretty(self, printer, *args): return prettyForm(self.__class__.__name__) def _print_contents(self, printer, *args): if len(self.label) == 1: return self._print_label(printer, *args) else: return '%s(%s)' % ( self._print_operator_name(printer, *args), self._print_label(printer, *args) ) def _print_contents_pretty(self, printer, *args): if len(self.label) == 1: return self._print_label_pretty(printer, *args) else: pform = self._print_operator_name_pretty(printer, *args) label_pform = self._print_label_pretty(printer, *args) label_pform = prettyForm( *label_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(label_pform)) return pform def _print_contents_latex(self, printer, *args): if len(self.label) == 1: return self._print_label_latex(printer, *args) else: return r'%s\left(%s\right)' % ( self._print_operator_name_latex(printer, *args), self._print_label_latex(printer, *args) ) #------------------------------------------------------------------------- # _eval_* methods #------------------------------------------------------------------------- def _eval_commutator(self, other, **options): """Evaluate [self, other] if known, return None if not known.""" return dispatch_method(self, '_eval_commutator', other, **options) def _eval_anticommutator(self, other, **options): """Evaluate [self, other] if known.""" return dispatch_method(self, '_eval_anticommutator', other, **options) #------------------------------------------------------------------------- # Operator application #------------------------------------------------------------------------- def _apply_operator(self, ket, **options): return dispatch_method(self, '_apply_operator', ket, **options) def matrix_element(self, *args): raise NotImplementedError('matrix_elements is not defined') def inverse(self): return self._eval_inverse() inv = inverse def _eval_inverse(self): return self**(-1) def __mul__(self, other): if isinstance(other, IdentityOperator): return self return Mul(self, other) class HermitianOperator(Operator): """A Hermitian operator that satisfies H == Dagger(H). Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the operator. For time-dependent operators, this will include the time. Examples ======== >>> from sympy.physics.quantum import Dagger, HermitianOperator >>> H = HermitianOperator('H') >>> Dagger(H) H """ is_hermitian = True def _eval_inverse(self): if isinstance(self, UnitaryOperator): return self else: return Operator._eval_inverse(self) def _eval_power(self, exp): if isinstance(self, UnitaryOperator): if exp == -1: return Operator._eval_power(self, exp) elif abs(exp) % 2 == 0: return self*(Operator._eval_inverse(self)) else: return self else: return Operator._eval_power(self, exp) class UnitaryOperator(Operator): """A unitary operator that satisfies U*Dagger(U) == 1. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the operator. For time-dependent operators, this will include the time. Examples ======== >>> from sympy.physics.quantum import Dagger, UnitaryOperator >>> U = UnitaryOperator('U') >>> U*Dagger(U) 1 """ def _eval_adjoint(self): return self._eval_inverse() class IdentityOperator(Operator): """An identity operator I that satisfies op * I == I * op == op for any operator op. Parameters ========== N : Integer Optional parameter that specifies the dimension of the Hilbert space of operator. This is used when generating a matrix representation. Examples ======== >>> from sympy.physics.quantum import IdentityOperator >>> IdentityOperator() I """ @property def dimension(self): return self.N @classmethod def default_args(self): return (oo,) def __init__(self, *args, **hints): if not len(args) in [0, 1]: raise ValueError('0 or 1 parameters expected, got %s' % args) self.N = args[0] if (len(args) == 1 and args[0]) else oo def _eval_commutator(self, other, **hints): return Integer(0) def _eval_anticommutator(self, other, **hints): return 2 * other def _eval_inverse(self): return self def _eval_adjoint(self): return self def _apply_operator(self, ket, **options): return ket def _eval_power(self, exp): return self def _print_contents(self, printer, *args): return 'I' def _print_contents_pretty(self, printer, *args): return prettyForm('I') def _print_contents_latex(self, printer, *args): return r'{\mathcal{I}}' def __mul__(self, other): if isinstance(other, (Operator, Dagger)): return other return Mul(self, other) def _represent_default_basis(self, **options): if not self.N or self.N == oo: raise NotImplementedError('Cannot represent infinite dimensional' + ' identity operator as a matrix') format = options.get('format', 'sympy') if format != 'sympy': raise NotImplementedError('Representation in format ' + '%s not implemented.' % format) return eye(self.N) class OuterProduct(Operator): """An unevaluated outer product between a ket and bra. This constructs an outer product between any subclass of ``KetBase`` and ``BraBase`` as ``|a>>> from sympy.physics.quantum import Ket, Bra, OuterProduct, Dagger >>> from sympy.physics.quantum import Operator >>> k = Ket('k') >>> b = Bra('b') >>> op = OuterProduct(k, b) >>> op |k>>> op.hilbert_space H >>> op.ket |k> >>> op.bra >> Dagger(op) |b>>> k*b |k>>> A = Operator('A') >>> A*k*b A*|k>*>> A*(k*b) A*|k>>> from sympy import Derivative, Function, Symbol >>> from sympy.physics.quantum.operator import DifferentialOperator >>> from sympy.physics.quantum.state import Wavefunction >>> from sympy.physics.quantum.qapply import qapply >>> f = Function('f') >>> x = Symbol('x') >>> d = DifferentialOperator(1/x*Derivative(f(x), x), f(x)) >>> w = Wavefunction(x**2, x) >>> d.function f(x) >>> d.variables (x,) >>> qapply(d*w) Wavefunction(2, x) """ @property def variables(self): """ Returns the variables with which the function in the specified arbitrary expression is evaluated Examples ======== >>> from sympy.physics.quantum.operator import DifferentialOperator >>> from sympy import Symbol, Function, Derivative >>> x = Symbol('x') >>> f = Function('f') >>> d = DifferentialOperator(1/x*Derivative(f(x), x), f(x)) >>> d.variables (x,) >>> y = Symbol('y') >>> d = DifferentialOperator(Derivative(f(x, y), x) + ... Derivative(f(x, y), y), f(x, y)) >>> d.variables (x, y) """ return self.args[-1].args @property def function(self): """ Returns the function which is to be replaced with the Wavefunction Examples ======== >>> from sympy.physics.quantum.operator import DifferentialOperator >>> from sympy import Function, Symbol, Derivative >>> x = Symbol('x') >>> f = Function('f') >>> d = DifferentialOperator(Derivative(f(x), x), f(x)) >>> d.function f(x) >>> y = Symbol('y') >>> d = DifferentialOperator(Derivative(f(x, y), x) + ... Derivative(f(x, y), y), f(x, y)) >>> d.function f(x, y) """ return self.args[-1] @property def expr(self): """ Returns the arbitrary expression which is to have the Wavefunction substituted into it Examples ======== >>> from sympy.physics.quantum.operator import DifferentialOperator >>> from sympy import Function, Symbol, Derivative >>> x = Symbol('x') >>> f = Function('f') >>> d = DifferentialOperator(Derivative(f(x), x), f(x)) >>> d.expr Derivative(f(x), x) >>> y = Symbol('y') >>> d = DifferentialOperator(Derivative(f(x, y), x) + ... Derivative(f(x, y), y), f(x, y)) >>> d.expr Derivative(f(x, y), x) + Derivative(f(x, y), y) """ return self.args[0] @property def free_symbols(self): """ Return the free symbols of the expression. """ return self.expr.free_symbols def _apply_operator_Wavefunction(self, func): from sympy.physics.quantum.state import Wavefunction var = self.variables wf_vars = func.args[1:] f = self.function new_expr = self.expr.subs(f, func(*var)) new_expr = new_expr.doit() return Wavefunction(new_expr, *wf_vars) def _eval_derivative(self, symbol): new_expr = Derivative(self.expr, symbol) return DifferentialOperator(new_expr, self.args[-1]) #------------------------------------------------------------------------- # Printing #------------------------------------------------------------------------- def _print(self, printer, *args): return '%s(%s)' % ( self._print_operator_name(printer, *args), self._print_label(printer, *args) ) def _print_pretty(self, printer, *args): pform = self._print_operator_name_pretty(printer, *args) label_pform = self._print_label_pretty(printer, *args) label_pform = prettyForm( *label_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(label_pform)) return pform sympy-sympy-1.9/sympy/physics/quantum/operatorordering.py000066400000000000000000000263601412543434000242260ustar00rootroot00000000000000"""Functions for reordering operator expressions.""" import warnings from sympy import Add, Mul, Pow, Integer from sympy.physics.quantum import Operator, Commutator, AntiCommutator from sympy.physics.quantum.boson import BosonOp from sympy.physics.quantum.fermion import FermionOp __all__ = [ 'normal_order', 'normal_ordered_form' ] def _expand_powers(factors): """ Helper function for normal_ordered_form and normal_order: Expand a power expression to a multiplication expression so that that the expression can be handled by the normal ordering functions. """ new_factors = [] for factor in factors.args: if (isinstance(factor, Pow) and isinstance(factor.args[1], Integer) and factor.args[1] > 0): for n in range(factor.args[1]): new_factors.append(factor.args[0]) else: new_factors.append(factor) return new_factors def _normal_ordered_form_factor(product, independent=False, recursive_limit=10, _recursive_depth=0): """ Helper function for normal_ordered_form_factor: Write multiplication expression with bosonic or fermionic operators on normally ordered form, using the bosonic and fermionic commutation relations. The resulting operator expression is equivalent to the argument, but will in general be a sum of operator products instead of a simple product. """ factors = _expand_powers(product) new_factors = [] n = 0 while n < len(factors) - 1: if isinstance(factors[n], BosonOp): # boson if not isinstance(factors[n + 1], BosonOp): new_factors.append(factors[n]) elif factors[n].is_annihilation == factors[n + 1].is_annihilation: if (independent and str(factors[n].name) > str(factors[n + 1].name)): new_factors.append(factors[n + 1]) new_factors.append(factors[n]) n += 1 else: new_factors.append(factors[n]) elif not factors[n].is_annihilation: new_factors.append(factors[n]) else: if factors[n + 1].is_annihilation: new_factors.append(factors[n]) else: if factors[n].args[0] != factors[n + 1].args[0]: if independent: c = 0 else: c = Commutator(factors[n], factors[n + 1]) new_factors.append(factors[n + 1] * factors[n] + c) else: c = Commutator(factors[n], factors[n + 1]) new_factors.append( factors[n + 1] * factors[n] + c.doit()) n += 1 elif isinstance(factors[n], FermionOp): # fermion if not isinstance(factors[n + 1], FermionOp): new_factors.append(factors[n]) elif factors[n].is_annihilation == factors[n + 1].is_annihilation: if (independent and str(factors[n].name) > str(factors[n + 1].name)): new_factors.append(factors[n + 1]) new_factors.append(factors[n]) n += 1 else: new_factors.append(factors[n]) elif not factors[n].is_annihilation: new_factors.append(factors[n]) else: if factors[n + 1].is_annihilation: new_factors.append(factors[n]) else: if factors[n].args[0] != factors[n + 1].args[0]: if independent: c = 0 else: c = AntiCommutator(factors[n], factors[n + 1]) new_factors.append(-factors[n + 1] * factors[n] + c) else: c = AntiCommutator(factors[n], factors[n + 1]) new_factors.append( -factors[n + 1] * factors[n] + c.doit()) n += 1 elif isinstance(factors[n], Operator): if isinstance(factors[n + 1], (BosonOp, FermionOp)): new_factors.append(factors[n + 1]) new_factors.append(factors[n]) n += 1 else: new_factors.append(factors[n]) else: new_factors.append(factors[n]) n += 1 if n == len(factors) - 1: new_factors.append(factors[-1]) if new_factors == factors: return product else: expr = Mul(*new_factors).expand() return normal_ordered_form(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth + 1, independent=independent) def _normal_ordered_form_terms(expr, independent=False, recursive_limit=10, _recursive_depth=0): """ Helper function for normal_ordered_form: loop through each term in an addition expression and call _normal_ordered_form_factor to perform the factor to an normally ordered expression. """ new_terms = [] for term in expr.args: if isinstance(term, Mul): new_term = _normal_ordered_form_factor( term, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth, independent=independent) new_terms.append(new_term) else: new_terms.append(term) return Add(*new_terms) def normal_ordered_form(expr, independent=False, recursive_limit=10, _recursive_depth=0): """Write an expression with bosonic or fermionic operators on normal ordered form, where each term is normally ordered. Note that this normal ordered form is equivalent to the original expression. Parameters ========== expr : expression The expression write on normal ordered form. recursive_limit : int (default 10) The number of allowed recursive applications of the function. Examples ======== >>> from sympy.physics.quantum import Dagger >>> from sympy.physics.quantum.boson import BosonOp >>> from sympy.physics.quantum.operatorordering import normal_ordered_form >>> a = BosonOp("a") >>> normal_ordered_form(a * Dagger(a)) 1 + Dagger(a)*a """ if _recursive_depth > recursive_limit: warnings.warn("Too many recursions, aborting") return expr if isinstance(expr, Add): return _normal_ordered_form_terms(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth, independent=independent) elif isinstance(expr, Mul): return _normal_ordered_form_factor(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth, independent=independent) else: return expr def _normal_order_factor(product, recursive_limit=10, _recursive_depth=0): """ Helper function for normal_order: Normal order a multiplication expression with bosonic or fermionic operators. In general the resulting operator expression will not be equivalent to original product. """ factors = _expand_powers(product) n = 0 new_factors = [] while n < len(factors) - 1: if (isinstance(factors[n], BosonOp) and factors[n].is_annihilation): # boson if not isinstance(factors[n + 1], BosonOp): new_factors.append(factors[n]) else: if factors[n + 1].is_annihilation: new_factors.append(factors[n]) else: if factors[n].args[0] != factors[n + 1].args[0]: new_factors.append(factors[n + 1] * factors[n]) else: new_factors.append(factors[n + 1] * factors[n]) n += 1 elif (isinstance(factors[n], FermionOp) and factors[n].is_annihilation): # fermion if not isinstance(factors[n + 1], FermionOp): new_factors.append(factors[n]) else: if factors[n + 1].is_annihilation: new_factors.append(factors[n]) else: if factors[n].args[0] != factors[n + 1].args[0]: new_factors.append(-factors[n + 1] * factors[n]) else: new_factors.append(-factors[n + 1] * factors[n]) n += 1 else: new_factors.append(factors[n]) n += 1 if n == len(factors) - 1: new_factors.append(factors[-1]) if new_factors == factors: return product else: expr = Mul(*new_factors).expand() return normal_order(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth + 1) def _normal_order_terms(expr, recursive_limit=10, _recursive_depth=0): """ Helper function for normal_order: look through each term in an addition expression and call _normal_order_factor to perform the normal ordering on the factors. """ new_terms = [] for term in expr.args: if isinstance(term, Mul): new_term = _normal_order_factor(term, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth) new_terms.append(new_term) else: new_terms.append(term) return Add(*new_terms) def normal_order(expr, recursive_limit=10, _recursive_depth=0): """Normal order an expression with bosonic or fermionic operators. Note that this normal order is not equivalent to the original expression, but the creation and annihilation operators in each term in expr is reordered so that the expression becomes normal ordered. Parameters ========== expr : expression The expression to normal order. recursive_limit : int (default 10) The number of allowed recursive applications of the function. Examples ======== >>> from sympy.physics.quantum import Dagger >>> from sympy.physics.quantum.boson import BosonOp >>> from sympy.physics.quantum.operatorordering import normal_order >>> a = BosonOp("a") >>> normal_order(a * Dagger(a)) Dagger(a)*a """ if _recursive_depth > recursive_limit: warnings.warn("Too many recursions, aborting") return expr if isinstance(expr, Add): return _normal_order_terms(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth) elif isinstance(expr, Mul): return _normal_order_factor(expr, recursive_limit=recursive_limit, _recursive_depth=_recursive_depth) else: return expr sympy-sympy-1.9/sympy/physics/quantum/operatorset.py000066400000000000000000000225761412543434000232150ustar00rootroot00000000000000""" A module for mapping operators to their corresponding eigenstates and vice versa It contains a global dictionary with eigenstate-operator pairings. If a new state-operator pair is created, this dictionary should be updated as well. It also contains functions operators_to_state and state_to_operators for mapping between the two. These can handle both classes and instances of operators and states. See the individual function descriptions for details. TODO List: - Update the dictionary with a complete list of state-operator pairs """ from sympy.physics.quantum.cartesian import (XOp, YOp, ZOp, XKet, PxOp, PxKet, PositionKet3D) from sympy.physics.quantum.operator import Operator from sympy.physics.quantum.state import StateBase, BraBase, Ket from sympy.physics.quantum.spin import (JxOp, JyOp, JzOp, J2Op, JxKet, JyKet, JzKet) __all__ = [ 'operators_to_state', 'state_to_operators' ] #state_mapping stores the mappings between states and their associated #operators or tuples of operators. This should be updated when new #classes are written! Entries are of the form PxKet : PxOp or #something like 3DKet : (ROp, ThetaOp, PhiOp) #frozenset is used so that the reverse mapping can be made #(regular sets are not hashable because they are mutable state_mapping = { JxKet: frozenset((J2Op, JxOp)), JyKet: frozenset((J2Op, JyOp)), JzKet: frozenset((J2Op, JzOp)), Ket: Operator, PositionKet3D: frozenset((XOp, YOp, ZOp)), PxKet: PxOp, XKet: XOp } op_mapping = {v: k for k, v in state_mapping.items()} def operators_to_state(operators, **options): """ Returns the eigenstate of the given operator or set of operators A global function for mapping operator classes to their associated states. It takes either an Operator or a set of operators and returns the state associated with these. This function can handle both instances of a given operator or just the class itself (i.e. both XOp() and XOp) There are multiple use cases to consider: 1) A class or set of classes is passed: First, we try to instantiate default instances for these operators. If this fails, then the class is simply returned. If we succeed in instantiating default instances, then we try to call state._operators_to_state on the operator instances. If this fails, the class is returned. Otherwise, the instance returned by _operators_to_state is returned. 2) An instance or set of instances is passed: In this case, state._operators_to_state is called on the instances passed. If this fails, a state class is returned. If the method returns an instance, that instance is returned. In both cases, if the operator class or set does not exist in the state_mapping dictionary, None is returned. Parameters ========== arg: Operator or set The class or instance of the operator or set of operators to be mapped to a state Examples ======== >>> from sympy.physics.quantum.cartesian import XOp, PxOp >>> from sympy.physics.quantum.operatorset import operators_to_state >>> from sympy.physics.quantum.operator import Operator >>> operators_to_state(XOp) |x> >>> operators_to_state(XOp()) |x> >>> operators_to_state(PxOp) |px> >>> operators_to_state(PxOp()) |px> >>> operators_to_state(Operator) |psi> >>> operators_to_state(Operator()) |psi> """ if not (isinstance(operators, Operator) or isinstance(operators, set) or issubclass(operators, Operator)): raise NotImplementedError("Argument is not an Operator or a set!") if isinstance(operators, set): for s in operators: if not (isinstance(s, Operator) or issubclass(s, Operator)): raise NotImplementedError("Set is not all Operators!") ops = frozenset(operators) if ops in op_mapping: # ops is a list of classes in this case #Try to get an object from default instances of the #operators...if this fails, return the class try: op_instances = [op() for op in ops] ret = _get_state(op_mapping[ops], set(op_instances), **options) except NotImplementedError: ret = op_mapping[ops] return ret else: tmp = [type(o) for o in ops] classes = frozenset(tmp) if classes in op_mapping: ret = _get_state(op_mapping[classes], ops, **options) else: ret = None return ret else: if operators in op_mapping: try: op_instance = operators() ret = _get_state(op_mapping[operators], op_instance, **options) except NotImplementedError: ret = op_mapping[operators] return ret elif type(operators) in op_mapping: return _get_state(op_mapping[type(operators)], operators, **options) else: return None def state_to_operators(state, **options): """ Returns the operator or set of operators corresponding to the given eigenstate A global function for mapping state classes to their associated operators or sets of operators. It takes either a state class or instance. This function can handle both instances of a given state or just the class itself (i.e. both XKet() and XKet) There are multiple use cases to consider: 1) A state class is passed: In this case, we first try instantiating a default instance of the class. If this succeeds, then we try to call state._state_to_operators on that instance. If the creation of the default instance or if the calling of _state_to_operators fails, then either an operator class or set of operator classes is returned. Otherwise, the appropriate operator instances are returned. 2) A state instance is returned: Here, state._state_to_operators is called for the instance. If this fails, then a class or set of operator classes is returned. Otherwise, the instances are returned. In either case, if the state's class does not exist in state_mapping, None is returned. Parameters ========== arg: StateBase class or instance (or subclasses) The class or instance of the state to be mapped to an operator or set of operators Examples ======== >>> from sympy.physics.quantum.cartesian import XKet, PxKet, XBra, PxBra >>> from sympy.physics.quantum.operatorset import state_to_operators >>> from sympy.physics.quantum.state import Ket, Bra >>> state_to_operators(XKet) X >>> state_to_operators(XKet()) X >>> state_to_operators(PxKet) Px >>> state_to_operators(PxKet()) Px >>> state_to_operators(PxBra) Px >>> state_to_operators(XBra) X >>> state_to_operators(Ket) O >>> state_to_operators(Bra) O """ if not (isinstance(state, StateBase) or issubclass(state, StateBase)): raise NotImplementedError("Argument is not a state!") if state in state_mapping: # state is a class state_inst = _make_default(state) try: ret = _get_ops(state_inst, _make_set(state_mapping[state]), **options) except (NotImplementedError, TypeError): ret = state_mapping[state] elif type(state) in state_mapping: ret = _get_ops(state, _make_set(state_mapping[type(state)]), **options) elif isinstance(state, BraBase) and state.dual_class() in state_mapping: ret = _get_ops(state, _make_set(state_mapping[state.dual_class()])) elif issubclass(state, BraBase) and state.dual_class() in state_mapping: state_inst = _make_default(state) try: ret = _get_ops(state_inst, _make_set(state_mapping[state.dual_class()])) except (NotImplementedError, TypeError): ret = state_mapping[state.dual_class()] else: ret = None return _make_set(ret) def _make_default(expr): # XXX: Catching TypeError like this is a bad way of distinguishing between # classes and instances. The logic using this function should be rewritten # somehow. try: ret = expr() except TypeError: ret = expr return ret def _get_state(state_class, ops, **options): # Try to get a state instance from the operator INSTANCES. # If this fails, get the class try: ret = state_class._operators_to_state(ops, **options) except NotImplementedError: ret = _make_default(state_class) return ret def _get_ops(state_inst, op_classes, **options): # Try to get operator instances from the state INSTANCE. # If this fails, just return the classes try: ret = state_inst._state_to_operators(op_classes, **options) except NotImplementedError: if isinstance(op_classes, (set, tuple, frozenset)): ret = tuple(_make_default(x) for x in op_classes) else: ret = _make_default(op_classes) if isinstance(ret, set) and len(ret) == 1: return ret[0] return ret def _make_set(ops): if isinstance(ops, (tuple, list, frozenset)): return set(ops) else: return ops sympy-sympy-1.9/sympy/physics/quantum/pauli.py000066400000000000000000000415561412543434000217570ustar00rootroot00000000000000"""Pauli operators and states""" from sympy import I, Mul, Add, Pow, exp, Integer from sympy.physics.quantum import Operator, Ket, Bra from sympy.physics.quantum import ComplexSpace from sympy.matrices import Matrix from sympy.functions.special.tensor_functions import KroneckerDelta __all__ = [ 'SigmaX', 'SigmaY', 'SigmaZ', 'SigmaMinus', 'SigmaPlus', 'SigmaZKet', 'SigmaZBra', 'qsimplify_pauli' ] class SigmaOpBase(Operator): """Pauli sigma operator, base class""" @property def name(self): return self.args[0] @property def use_name(self): return bool(self.args[0]) is not False @classmethod def default_args(self): return (False,) def __new__(cls, *args, **hints): return Operator.__new__(cls, *args, **hints) def _eval_commutator_BosonOp(self, other, **hints): return Integer(0) class SigmaX(SigmaOpBase): """Pauli sigma x operator Parameters ========== name : str An optional string that labels the operator. Pauli operators with different names commute. Examples ======== >>> from sympy.physics.quantum import represent >>> from sympy.physics.quantum.pauli import SigmaX >>> sx = SigmaX() >>> sx SigmaX() >>> represent(sx) Matrix([ [0, 1], [1, 0]]) """ def __new__(cls, *args, **hints): return SigmaOpBase.__new__(cls, *args, **hints) def _eval_commutator_SigmaY(self, other, **hints): if self.name != other.name: return Integer(0) else: return 2 * I * SigmaZ(self.name) def _eval_commutator_SigmaZ(self, other, **hints): if self.name != other.name: return Integer(0) else: return - 2 * I * SigmaY(self.name) def _eval_commutator_BosonOp(self, other, **hints): return Integer(0) def _eval_anticommutator_SigmaY(self, other, **hints): return Integer(0) def _eval_anticommutator_SigmaZ(self, other, **hints): return Integer(0) def _eval_adjoint(self): return self def _print_contents_latex(self, printer, *args): if self.use_name: return r'{\sigma_x^{(%s)}}' % str(self.name) else: return r'{\sigma_x}' def _print_contents(self, printer, *args): return 'SigmaX()' def _eval_power(self, e): if e.is_Integer and e.is_positive: return SigmaX(self.name).__pow__(int(e) % 2) def _represent_default_basis(self, **options): format = options.get('format', 'sympy') if format == 'sympy': return Matrix([[0, 1], [1, 0]]) else: raise NotImplementedError('Representation in format ' + format + ' not implemented.') class SigmaY(SigmaOpBase): """Pauli sigma y operator Parameters ========== name : str An optional string that labels the operator. Pauli operators with different names commute. Examples ======== >>> from sympy.physics.quantum import represent >>> from sympy.physics.quantum.pauli import SigmaY >>> sy = SigmaY() >>> sy SigmaY() >>> represent(sy) Matrix([ [0, -I], [I, 0]]) """ def __new__(cls, *args, **hints): return SigmaOpBase.__new__(cls, *args) def _eval_commutator_SigmaZ(self, other, **hints): if self.name != other.name: return Integer(0) else: return 2 * I * SigmaX(self.name) def _eval_commutator_SigmaX(self, other, **hints): if self.name != other.name: return Integer(0) else: return - 2 * I * SigmaZ(self.name) def _eval_anticommutator_SigmaX(self, other, **hints): return Integer(0) def _eval_anticommutator_SigmaZ(self, other, **hints): return Integer(0) def _eval_adjoint(self): return self def _print_contents_latex(self, printer, *args): if self.use_name: return r'{\sigma_y^{(%s)}}' % str(self.name) else: return r'{\sigma_y}' def _print_contents(self, printer, *args): return 'SigmaY()' def _eval_power(self, e): if e.is_Integer and e.is_positive: return SigmaY(self.name).__pow__(int(e) % 2) def _represent_default_basis(self, **options): format = options.get('format', 'sympy') if format == 'sympy': return Matrix([[0, -I], [I, 0]]) else: raise NotImplementedError('Representation in format ' + format + ' not implemented.') class SigmaZ(SigmaOpBase): """Pauli sigma z operator Parameters ========== name : str An optional string that labels the operator. Pauli operators with different names commute. Examples ======== >>> from sympy.physics.quantum import represent >>> from sympy.physics.quantum.pauli import SigmaZ >>> sz = SigmaZ() >>> sz ** 3 SigmaZ() >>> represent(sz) Matrix([ [1, 0], [0, -1]]) """ def __new__(cls, *args, **hints): return SigmaOpBase.__new__(cls, *args) def _eval_commutator_SigmaX(self, other, **hints): if self.name != other.name: return Integer(0) else: return 2 * I * SigmaY(self.name) def _eval_commutator_SigmaY(self, other, **hints): if self.name != other.name: return Integer(0) else: return - 2 * I * SigmaX(self.name) def _eval_anticommutator_SigmaX(self, other, **hints): return Integer(0) def _eval_anticommutator_SigmaY(self, other, **hints): return Integer(0) def _eval_adjoint(self): return self def _print_contents_latex(self, printer, *args): if self.use_name: return r'{\sigma_z^{(%s)}}' % str(self.name) else: return r'{\sigma_z}' def _print_contents(self, printer, *args): return 'SigmaZ()' def _eval_power(self, e): if e.is_Integer and e.is_positive: return SigmaZ(self.name).__pow__(int(e) % 2) def _represent_default_basis(self, **options): format = options.get('format', 'sympy') if format == 'sympy': return Matrix([[1, 0], [0, -1]]) else: raise NotImplementedError('Representation in format ' + format + ' not implemented.') class SigmaMinus(SigmaOpBase): """Pauli sigma minus operator Parameters ========== name : str An optional string that labels the operator. Pauli operators with different names commute. Examples ======== >>> from sympy.physics.quantum import represent, Dagger >>> from sympy.physics.quantum.pauli import SigmaMinus >>> sm = SigmaMinus() >>> sm SigmaMinus() >>> Dagger(sm) SigmaPlus() >>> represent(sm) Matrix([ [0, 0], [1, 0]]) """ def __new__(cls, *args, **hints): return SigmaOpBase.__new__(cls, *args) def _eval_commutator_SigmaX(self, other, **hints): if self.name != other.name: return Integer(0) else: return -SigmaZ(self.name) def _eval_commutator_SigmaY(self, other, **hints): if self.name != other.name: return Integer(0) else: return I * SigmaZ(self.name) def _eval_commutator_SigmaZ(self, other, **hints): return 2 * self def _eval_commutator_SigmaMinus(self, other, **hints): return SigmaZ(self.name) def _eval_anticommutator_SigmaZ(self, other, **hints): return Integer(0) def _eval_anticommutator_SigmaX(self, other, **hints): return Integer(1) def _eval_anticommutator_SigmaY(self, other, **hints): return - I * Integer(1) def _eval_anticommutator_SigmaPlus(self, other, **hints): return Integer(1) def _eval_adjoint(self): return SigmaPlus(self.name) def _eval_power(self, e): if e.is_Integer and e.is_positive: return Integer(0) def _print_contents_latex(self, printer, *args): if self.use_name: return r'{\sigma_-^{(%s)}}' % str(self.name) else: return r'{\sigma_-}' def _print_contents(self, printer, *args): return 'SigmaMinus()' def _represent_default_basis(self, **options): format = options.get('format', 'sympy') if format == 'sympy': return Matrix([[0, 0], [1, 0]]) else: raise NotImplementedError('Representation in format ' + format + ' not implemented.') class SigmaPlus(SigmaOpBase): """Pauli sigma plus operator Parameters ========== name : str An optional string that labels the operator. Pauli operators with different names commute. Examples ======== >>> from sympy.physics.quantum import represent, Dagger >>> from sympy.physics.quantum.pauli import SigmaPlus >>> sp = SigmaPlus() >>> sp SigmaPlus() >>> Dagger(sp) SigmaMinus() >>> represent(sp) Matrix([ [0, 1], [0, 0]]) """ def __new__(cls, *args, **hints): return SigmaOpBase.__new__(cls, *args) def _eval_commutator_SigmaX(self, other, **hints): if self.name != other.name: return Integer(0) else: return SigmaZ(self.name) def _eval_commutator_SigmaY(self, other, **hints): if self.name != other.name: return Integer(0) else: return I * SigmaZ(self.name) def _eval_commutator_SigmaZ(self, other, **hints): if self.name != other.name: return Integer(0) else: return -2 * self def _eval_commutator_SigmaMinus(self, other, **hints): return SigmaZ(self.name) def _eval_anticommutator_SigmaZ(self, other, **hints): return Integer(0) def _eval_anticommutator_SigmaX(self, other, **hints): return Integer(1) def _eval_anticommutator_SigmaY(self, other, **hints): return I * Integer(1) def _eval_anticommutator_SigmaMinus(self, other, **hints): return Integer(1) def _eval_adjoint(self): return SigmaMinus(self.name) def _eval_mul(self, other): return self * other def _eval_power(self, e): if e.is_Integer and e.is_positive: return Integer(0) def _print_contents_latex(self, printer, *args): if self.use_name: return r'{\sigma_+^{(%s)}}' % str(self.name) else: return r'{\sigma_+}' def _print_contents(self, printer, *args): return 'SigmaPlus()' def _represent_default_basis(self, **options): format = options.get('format', 'sympy') if format == 'sympy': return Matrix([[0, 1], [0, 0]]) else: raise NotImplementedError('Representation in format ' + format + ' not implemented.') class SigmaZKet(Ket): """Ket for a two-level system quantum system. Parameters ========== n : Number The state number (0 or 1). """ def __new__(cls, n): if n not in [0, 1]: raise ValueError("n must be 0 or 1") return Ket.__new__(cls, n) @property def n(self): return self.label[0] @classmethod def dual_class(self): return SigmaZBra @classmethod def _eval_hilbert_space(cls, label): return ComplexSpace(2) def _eval_innerproduct_SigmaZBra(self, bra, **hints): return KroneckerDelta(self.n, bra.n) def _apply_operator_SigmaZ(self, op, **options): if self.n == 0: return self else: return Integer(-1) * self def _apply_operator_SigmaX(self, op, **options): return SigmaZKet(1) if self.n == 0 else SigmaZKet(0) def _apply_operator_SigmaY(self, op, **options): return I * SigmaZKet(1) if self.n == 0 else (-I) * SigmaZKet(0) def _apply_operator_SigmaMinus(self, op, **options): if self.n == 0: return SigmaZKet(1) else: return Integer(0) def _apply_operator_SigmaPlus(self, op, **options): if self.n == 0: return Integer(0) else: return SigmaZKet(0) def _represent_default_basis(self, **options): format = options.get('format', 'sympy') if format == 'sympy': return Matrix([[1], [0]]) if self.n == 0 else Matrix([[0], [1]]) else: raise NotImplementedError('Representation in format ' + format + ' not implemented.') class SigmaZBra(Bra): """Bra for a two-level quantum system. Parameters ========== n : Number The state number (0 or 1). """ def __new__(cls, n): if n not in [0, 1]: raise ValueError("n must be 0 or 1") return Bra.__new__(cls, n) @property def n(self): return self.label[0] @classmethod def dual_class(self): return SigmaZKet def _qsimplify_pauli_product(a, b): """ Internal helper function for simplifying products of Pauli operators. """ if not (isinstance(a, SigmaOpBase) and isinstance(b, SigmaOpBase)): return Mul(a, b) if a.name != b.name: # Pauli matrices with different labels commute; sort by name if a.name < b.name: return Mul(a, b) else: return Mul(b, a) elif isinstance(a, SigmaX): if isinstance(b, SigmaX): return Integer(1) if isinstance(b, SigmaY): return I * SigmaZ(a.name) if isinstance(b, SigmaZ): return - I * SigmaY(a.name) if isinstance(b, SigmaMinus): return (Integer(1)/2 + SigmaZ(a.name)/2) if isinstance(b, SigmaPlus): return (Integer(1)/2 - SigmaZ(a.name)/2) elif isinstance(a, SigmaY): if isinstance(b, SigmaX): return - I * SigmaZ(a.name) if isinstance(b, SigmaY): return Integer(1) if isinstance(b, SigmaZ): return I * SigmaX(a.name) if isinstance(b, SigmaMinus): return -I * (Integer(1) + SigmaZ(a.name))/2 if isinstance(b, SigmaPlus): return I * (Integer(1) - SigmaZ(a.name))/2 elif isinstance(a, SigmaZ): if isinstance(b, SigmaX): return I * SigmaY(a.name) if isinstance(b, SigmaY): return - I * SigmaX(a.name) if isinstance(b, SigmaZ): return Integer(1) if isinstance(b, SigmaMinus): return - SigmaMinus(a.name) if isinstance(b, SigmaPlus): return SigmaPlus(a.name) elif isinstance(a, SigmaMinus): if isinstance(b, SigmaX): return (Integer(1) - SigmaZ(a.name))/2 if isinstance(b, SigmaY): return - I * (Integer(1) - SigmaZ(a.name))/2 if isinstance(b, SigmaZ): # (SigmaX(a.name) - I * SigmaY(a.name))/2 return SigmaMinus(b.name) if isinstance(b, SigmaMinus): return Integer(0) if isinstance(b, SigmaPlus): return Integer(1)/2 - SigmaZ(a.name)/2 elif isinstance(a, SigmaPlus): if isinstance(b, SigmaX): return (Integer(1) + SigmaZ(a.name))/2 if isinstance(b, SigmaY): return I * (Integer(1) + SigmaZ(a.name))/2 if isinstance(b, SigmaZ): #-(SigmaX(a.name) + I * SigmaY(a.name))/2 return -SigmaPlus(a.name) if isinstance(b, SigmaMinus): return (Integer(1) + SigmaZ(a.name))/2 if isinstance(b, SigmaPlus): return Integer(0) else: return a * b def qsimplify_pauli(e): """ Simplify an expression that includes products of pauli operators. Parameters ========== e : expression An expression that contains products of Pauli operators that is to be simplified. Examples ======== >>> from sympy.physics.quantum.pauli import SigmaX, SigmaY >>> from sympy.physics.quantum.pauli import qsimplify_pauli >>> sx, sy = SigmaX(), SigmaY() >>> sx * sy SigmaX()*SigmaY() >>> qsimplify_pauli(sx * sy) I*SigmaZ() """ if isinstance(e, Operator): return e if isinstance(e, (Add, Pow, exp)): t = type(e) return t(*(qsimplify_pauli(arg) for arg in e.args)) if isinstance(e, Mul): c, nc = e.args_cnc() nc_s = [] while nc: curr = nc.pop(0) while (len(nc) and isinstance(curr, SigmaOpBase) and isinstance(nc[0], SigmaOpBase) and curr.name == nc[0].name): x = nc.pop(0) y = _qsimplify_pauli_product(curr, x) c1, nc1 = y.args_cnc() curr = Mul(*nc1) c = c + c1 nc_s.append(curr) return Mul(*c) * Mul(*nc_s) return e sympy-sympy-1.9/sympy/physics/quantum/piab.py000066400000000000000000000032531412543434000215500ustar00rootroot00000000000000"""1D quantum particle in a box.""" from sympy import Symbol, pi, sqrt, sin, Interval, S from sympy.physics.quantum.operator import HermitianOperator from sympy.physics.quantum.state import Ket, Bra from sympy.physics.quantum.constants import hbar from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.physics.quantum.hilbert import L2 m = Symbol('m') L = Symbol('L') __all__ = [ 'PIABHamiltonian', 'PIABKet', 'PIABBra' ] class PIABHamiltonian(HermitianOperator): """Particle in a box Hamiltonian operator.""" @classmethod def _eval_hilbert_space(cls, label): return L2(Interval(S.NegativeInfinity, S.Infinity)) def _apply_operator_PIABKet(self, ket, **options): n = ket.label[0] return (n**2*pi**2*hbar**2)/(2*m*L**2)*ket class PIABKet(Ket): """Particle in a box eigenket.""" @classmethod def _eval_hilbert_space(cls, args): return L2(Interval(S.NegativeInfinity, S.Infinity)) @classmethod def dual_class(self): return PIABBra def _represent_default_basis(self, **options): return self._represent_XOp(None, **options) def _represent_XOp(self, basis, **options): x = Symbol('x') n = Symbol('n') subs_info = options.get('subs', {}) return sqrt(2/L)*sin(n*pi*x/L).subs(subs_info) def _eval_innerproduct_PIABBra(self, bra): return KroneckerDelta(bra.label[0], self.label[0]) class PIABBra(Bra): """Particle in a box eigenbra.""" @classmethod def _eval_hilbert_space(cls, label): return L2(Interval(S.NegativeInfinity, S.Infinity)) @classmethod def dual_class(self): return PIABKet sympy-sympy-1.9/sympy/physics/quantum/qapply.py000066400000000000000000000155551412543434000221530ustar00rootroot00000000000000"""Logic for applying operators to states. Todo: * Sometimes the final result needs to be expanded, we should do this by hand. """ from sympy import Add, Mul, Pow, sympify, S from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.innerproduct import InnerProduct from sympy.physics.quantum.operator import OuterProduct, Operator from sympy.physics.quantum.state import State, KetBase, BraBase, Wavefunction from sympy.physics.quantum.tensorproduct import TensorProduct __all__ = [ 'qapply' ] #----------------------------------------------------------------------------- # Main code #----------------------------------------------------------------------------- def qapply(e, **options): """Apply operators to states in a quantum expression. Parameters ========== e : Expr The expression containing operators and states. This expression tree will be walked to find operators acting on states symbolically. options : dict A dict of key/value pairs that determine how the operator actions are carried out. The following options are valid: * ``dagger``: try to apply Dagger operators to the left (default: False). * ``ip_doit``: call ``.doit()`` in inner products when they are encountered (default: True). Returns ======= e : Expr The original expression, but with the operators applied to states. Examples ======== >>> from sympy.physics.quantum import qapply, Ket, Bra >>> b = Bra('b') >>> k = Ket('k') >>> A = k * b >>> A |k>>> qapply(A * b.dual / (b * b.dual)) |k> >>> qapply(k.dual * A / (k.dual * k), dagger=True) >> qapply(k.dual * A / (k.dual * k)) """ from sympy.physics.quantum.density import Density dagger = options.get('dagger', False) if e == 0: return S.Zero # This may be a bit aggressive but ensures that everything gets expanded # to its simplest form before trying to apply operators. This includes # things like (A+B+C)*|a> and A*(|a>+|b>) and all Commutators and # TensorProducts. The only problem with this is that if we can't apply # all the Operators, we have just expanded everything. # TODO: don't expand the scalars in front of each Mul. e = e.expand(commutator=True, tensorproduct=True) # If we just have a raw ket, return it. if isinstance(e, KetBase): return e # We have an Add(a, b, c, ...) and compute # Add(qapply(a), qapply(b), ...) elif isinstance(e, Add): result = 0 for arg in e.args: result += qapply(arg, **options) return result.expand() # For a Density operator call qapply on its state elif isinstance(e, Density): new_args = [(qapply(state, **options), prob) for (state, prob) in e.args] return Density(*new_args) # For a raw TensorProduct, call qapply on its args. elif isinstance(e, TensorProduct): return TensorProduct(*[qapply(t, **options) for t in e.args]) # For a Pow, call qapply on its base. elif isinstance(e, Pow): return qapply(e.base, **options)**e.exp # We have a Mul where there might be actual operators to apply to kets. elif isinstance(e, Mul): c_part, nc_part = e.args_cnc() c_mul = Mul(*c_part) nc_mul = Mul(*nc_part) if isinstance(nc_mul, Mul): result = c_mul*qapply_Mul(nc_mul, **options) else: result = c_mul*qapply(nc_mul, **options) if result == e and dagger: return Dagger(qapply_Mul(Dagger(e), **options)) else: return result # In all other cases (State, Operator, Pow, Commutator, InnerProduct, # OuterProduct) we won't ever have operators to apply to kets. else: return e def qapply_Mul(e, **options): ip_doit = options.get('ip_doit', True) args = list(e.args) # If we only have 0 or 1 args, we have nothing to do and return. if len(args) <= 1 or not isinstance(e, Mul): return e rhs = args.pop() lhs = args.pop() # Make sure we have two non-commutative objects before proceeding. if (sympify(rhs).is_commutative and not isinstance(rhs, Wavefunction)) or \ (sympify(lhs).is_commutative and not isinstance(lhs, Wavefunction)): return e # For a Pow with an integer exponent, apply one of them and reduce the # exponent by one. if isinstance(lhs, Pow) and lhs.exp.is_Integer: args.append(lhs.base**(lhs.exp - 1)) lhs = lhs.base # Pull OuterProduct apart if isinstance(lhs, OuterProduct): args.append(lhs.ket) lhs = lhs.bra # Call .doit() on Commutator/AntiCommutator. if isinstance(lhs, (Commutator, AntiCommutator)): comm = lhs.doit() if isinstance(comm, Add): return qapply( e.func(*(args + [comm.args[0], rhs])) + e.func(*(args + [comm.args[1], rhs])), **options ) else: return qapply(e.func(*args)*comm*rhs, **options) # Apply tensor products of operators to states if isinstance(lhs, TensorProduct) and all([isinstance(arg, (Operator, State, Mul, Pow)) or arg == 1 for arg in lhs.args]) and \ isinstance(rhs, TensorProduct) and all([isinstance(arg, (Operator, State, Mul, Pow)) or arg == 1 for arg in rhs.args]) and \ len(lhs.args) == len(rhs.args): result = TensorProduct(*[qapply(lhs.args[n]*rhs.args[n], **options) for n in range(len(lhs.args))]).expand(tensorproduct=True) return qapply_Mul(e.func(*args), **options)*result # Now try to actually apply the operator and build an inner product. try: result = lhs._apply_operator(rhs, **options) except (NotImplementedError, AttributeError): try: result = rhs._apply_operator(lhs, **options) except (NotImplementedError, AttributeError): if isinstance(lhs, BraBase) and isinstance(rhs, KetBase): result = InnerProduct(lhs, rhs) if ip_doit: result = result.doit() else: result = None # TODO: I may need to expand before returning the final result. if result == 0: return S.Zero elif result is None: if len(args) == 0: # We had two args to begin with so args=[]. return e else: return qapply_Mul(e.func(*(args + [lhs])), **options)*rhs elif isinstance(result, InnerProduct): return result*qapply_Mul(e.func(*args), **options) else: # result is a scalar times a Mul, Add or TensorProduct return qapply(e.func(*args)*result, **options) sympy-sympy-1.9/sympy/physics/quantum/qasm.py000066400000000000000000000142231412543434000215750ustar00rootroot00000000000000""" qasm.py - Functions to parse a set of qasm commands into a Sympy Circuit. Examples taken from Chuang's page: http://www.media.mit.edu/quanta/qasm2circ/ The code returns a circuit and an associated list of labels. >>> from sympy.physics.quantum.qasm import Qasm >>> q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1') >>> q.get_circuit() CNOT(1,0)*H(1) >>> q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1') >>> q.get_circuit() CNOT(1,0)*CNOT(0,1)*CNOT(1,0) """ __all__ = [ 'Qasm', ] from sympy.physics.quantum.gate import H, CNOT, X, Z, CGate, CGateS, SWAP, S, T,CPHASE from sympy.physics.quantum.circuitplot import Mz def read_qasm(lines): return Qasm(*lines.splitlines()) def read_qasm_file(filename): return Qasm(*open(filename).readlines()) def prod(c): p = 1 for ci in c: p *= ci return p def flip_index(i, n): """Reorder qubit indices from largest to smallest. >>> from sympy.physics.quantum.qasm import flip_index >>> flip_index(0, 2) 1 >>> flip_index(1, 2) 0 """ return n-i-1 def trim(line): """Remove everything following comment # characters in line. >>> from sympy.physics.quantum.qasm import trim >>> trim('nothing happens here') 'nothing happens here' >>> trim('something #happens here') 'something ' """ if not '#' in line: return line return line.split('#')[0] def get_index(target, labels): """Get qubit labels from the rest of the line,and return indices >>> from sympy.physics.quantum.qasm import get_index >>> get_index('q0', ['q0', 'q1']) 1 >>> get_index('q1', ['q0', 'q1']) 0 """ nq = len(labels) return flip_index(labels.index(target), nq) def get_indices(targets, labels): return [get_index(t, labels) for t in targets] def nonblank(args): for line in args: line = trim(line) if line.isspace(): continue yield line return def fullsplit(line): words = line.split() rest = ' '.join(words[1:]) return fixcommand(words[0]), [s.strip() for s in rest.split(',')] def fixcommand(c): """Fix Qasm command names. Remove all of forbidden characters from command c, and replace 'def' with 'qdef'. """ forbidden_characters = ['-'] c = c.lower() for char in forbidden_characters: c = c.replace(char, '') if c == 'def': return 'qdef' return c def stripquotes(s): """Replace explicit quotes in a string. >>> from sympy.physics.quantum.qasm import stripquotes >>> stripquotes("'S'") == 'S' True >>> stripquotes('"S"') == 'S' True >>> stripquotes('S') == 'S' True """ s = s.replace('"', '') # Remove second set of quotes? s = s.replace("'", '') return s class Qasm: """Class to form objects from Qasm lines >>> from sympy.physics.quantum.qasm import Qasm >>> q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1') >>> q.get_circuit() CNOT(1,0)*H(1) >>> q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1') >>> q.get_circuit() CNOT(1,0)*CNOT(0,1)*CNOT(1,0) """ def __init__(self, *args, **kwargs): self.defs = {} self.circuit = [] self.labels = [] self.inits = {} self.add(*args) self.kwargs = kwargs def add(self, *lines): for line in nonblank(lines): command, rest = fullsplit(line) if self.defs.get(command): #defs come first, since you can override built-in function = self.defs.get(command) indices = self.indices(rest) if len(indices) == 1: self.circuit.append(function(indices[0])) else: self.circuit.append(function(indices[:-1], indices[-1])) elif hasattr(self, command): function = getattr(self, command) function(*rest) else: print("Function %s not defined. Skipping" % command) def get_circuit(self): return prod(reversed(self.circuit)) def get_labels(self): return list(reversed(self.labels)) def plot(self): from sympy.physics.quantum.circuitplot import CircuitPlot circuit, labels = self.get_circuit(), self.get_labels() CircuitPlot(circuit, len(labels), labels=labels, inits=self.inits) def qubit(self, arg, init=None): self.labels.append(arg) if init: self.inits[arg] = init def indices(self, args): return get_indices(args, self.labels) def index(self, arg): return get_index(arg, self.labels) def nop(self, *args): pass def x(self, arg): self.circuit.append(X(self.index(arg))) def z(self, arg): self.circuit.append(Z(self.index(arg))) def h(self, arg): self.circuit.append(H(self.index(arg))) def s(self, arg): self.circuit.append(S(self.index(arg))) def t(self, arg): self.circuit.append(T(self.index(arg))) def measure(self, arg): self.circuit.append(Mz(self.index(arg))) def cnot(self, a1, a2): self.circuit.append(CNOT(*self.indices([a1, a2]))) def swap(self, a1, a2): self.circuit.append(SWAP(*self.indices([a1, a2]))) def cphase(self, a1, a2): self.circuit.append(CPHASE(*self.indices([a1, a2]))) def toffoli(self, a1, a2, a3): i1, i2, i3 = self.indices([a1, a2, a3]) self.circuit.append(CGateS((i1, i2), X(i3))) def cx(self, a1, a2): fi, fj = self.indices([a1, a2]) self.circuit.append(CGate(fi, X(fj))) def cz(self, a1, a2): fi, fj = self.indices([a1, a2]) self.circuit.append(CGate(fi, Z(fj))) def defbox(self, *args): print("defbox not supported yet. Skipping: ", args) def qdef(self, name, ncontrols, symbol): from sympy.physics.quantum.circuitplot import CreateOneQubitGate, CreateCGate ncontrols = int(ncontrols) command = fixcommand(name) symbol = stripquotes(symbol) if ncontrols > 0: self.defs[command] = CreateCGate(symbol) else: self.defs[command] = CreateOneQubitGate(symbol) sympy-sympy-1.9/sympy/physics/quantum/qexpr.py000066400000000000000000000335001412543434000217720ustar00rootroot00000000000000from sympy import Expr, sympify, Symbol, Matrix from sympy.printing.pretty.stringpict import prettyForm from sympy.core.containers import Tuple from sympy.core.compatibility import is_sequence from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.matrixutils import ( numpy_ndarray, scipy_sparse_matrix, to_sympy, to_numpy, to_scipy_sparse ) __all__ = [ 'QuantumError', 'QExpr' ] #----------------------------------------------------------------------------- # Error handling #----------------------------------------------------------------------------- class QuantumError(Exception): pass def _qsympify_sequence(seq): """Convert elements of a sequence to standard form. This is like sympify, but it performs special logic for arguments passed to QExpr. The following conversions are done: * (list, tuple, Tuple) => _qsympify_sequence each element and convert sequence to a Tuple. * basestring => Symbol * Matrix => Matrix * other => sympify Strings are passed to Symbol, not sympify to make sure that variables like 'pi' are kept as Symbols, not the SymPy built-in number subclasses. Examples ======== >>> from sympy.physics.quantum.qexpr import _qsympify_sequence >>> _qsympify_sequence((1,2,[3,4,[1,]])) (1, 2, (3, 4, (1,))) """ return tuple(__qsympify_sequence_helper(seq)) def __qsympify_sequence_helper(seq): """ Helper function for _qsympify_sequence This function does the actual work. """ #base case. If not a list, do Sympification if not is_sequence(seq): if isinstance(seq, Matrix): return seq elif isinstance(seq, str): return Symbol(seq) else: return sympify(seq) # base condition, when seq is QExpr and also # is iterable. if isinstance(seq, QExpr): return seq #if list, recurse on each item in the list result = [__qsympify_sequence_helper(item) for item in seq] return Tuple(*result) #----------------------------------------------------------------------------- # Basic Quantum Expression from which all objects descend #----------------------------------------------------------------------------- class QExpr(Expr): """A base class for all quantum object like operators and states.""" # In sympy, slots are for instance attributes that are computed # dynamically by the __new__ method. They are not part of args, but they # derive from args. # The Hilbert space a quantum Object belongs to. __slots__ = ('hilbert_space') is_commutative = False # The separator used in printing the label. _label_separator = '' @property def free_symbols(self): return {self} def __new__(cls, *args, **kwargs): """Construct a new quantum object. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the quantum object. For a state, this will be its symbol or its set of quantum numbers. Examples ======== >>> from sympy.physics.quantum.qexpr import QExpr >>> q = QExpr(0) >>> q 0 >>> q.label (0,) >>> q.hilbert_space H >>> q.args (0,) >>> q.is_commutative False """ # First compute args and call Expr.__new__ to create the instance args = cls._eval_args(args, **kwargs) if len(args) == 0: args = cls._eval_args(tuple(cls.default_args()), **kwargs) inst = Expr.__new__(cls, *args) # Now set the slots on the instance inst.hilbert_space = cls._eval_hilbert_space(args) return inst @classmethod def _new_rawargs(cls, hilbert_space, *args, **old_assumptions): """Create new instance of this class with hilbert_space and args. This is used to bypass the more complex logic in the ``__new__`` method in cases where you already have the exact ``hilbert_space`` and ``args``. This should be used when you are positive these arguments are valid, in their final, proper form and want to optimize the creation of the object. """ obj = Expr.__new__(cls, *args, **old_assumptions) obj.hilbert_space = hilbert_space return obj #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def label(self): """The label is the unique set of identifiers for the object. Usually, this will include all of the information about the state *except* the time (in the case of time-dependent objects). This must be a tuple, rather than a Tuple. """ if len(self.args) == 0: # If there is no label specified, return the default return self._eval_args(list(self.default_args())) else: return self.args @property def is_symbolic(self): return True @classmethod def default_args(self): """If no arguments are specified, then this will return a default set of arguments to be run through the constructor. NOTE: Any classes that override this MUST return a tuple of arguments. Should be overridden by subclasses to specify the default arguments for kets and operators """ raise NotImplementedError("No default arguments for this class!") #------------------------------------------------------------------------- # _eval_* methods #------------------------------------------------------------------------- def _eval_adjoint(self): obj = Expr._eval_adjoint(self) if obj is None: obj = Expr.__new__(Dagger, self) if isinstance(obj, QExpr): obj.hilbert_space = self.hilbert_space return obj @classmethod def _eval_args(cls, args): """Process the args passed to the __new__ method. This simply runs args through _qsympify_sequence. """ return _qsympify_sequence(args) @classmethod def _eval_hilbert_space(cls, args): """Compute the Hilbert space instance from the args. """ from sympy.physics.quantum.hilbert import HilbertSpace return HilbertSpace() #------------------------------------------------------------------------- # Printing #------------------------------------------------------------------------- # Utilities for printing: these operate on raw sympy objects def _print_sequence(self, seq, sep, printer, *args): result = [] for item in seq: result.append(printer._print(item, *args)) return sep.join(result) def _print_sequence_pretty(self, seq, sep, printer, *args): pform = printer._print(seq[0], *args) for item in seq[1:]: pform = prettyForm(*pform.right(sep)) pform = prettyForm(*pform.right(printer._print(item, *args))) return pform # Utilities for printing: these operate prettyForm objects def _print_subscript_pretty(self, a, b): top = prettyForm(*b.left(' '*a.width())) bot = prettyForm(*a.right(' '*b.width())) return prettyForm(binding=prettyForm.POW, *bot.below(top)) def _print_superscript_pretty(self, a, b): return a**b def _print_parens_pretty(self, pform, left='(', right=')'): return prettyForm(*pform.parens(left=left, right=right)) # Printing of labels (i.e. args) def _print_label(self, printer, *args): """Prints the label of the QExpr This method prints self.label, using self._label_separator to separate the elements. This method should not be overridden, instead, override _print_contents to change printing behavior. """ return self._print_sequence( self.label, self._label_separator, printer, *args ) def _print_label_repr(self, printer, *args): return self._print_sequence( self.label, ',', printer, *args ) def _print_label_pretty(self, printer, *args): return self._print_sequence_pretty( self.label, self._label_separator, printer, *args ) def _print_label_latex(self, printer, *args): return self._print_sequence( self.label, self._label_separator, printer, *args ) # Printing of contents (default to label) def _print_contents(self, printer, *args): """Printer for contents of QExpr Handles the printing of any unique identifying contents of a QExpr to print as its contents, such as any variables or quantum numbers. The default is to print the label, which is almost always the args. This should not include printing of any brackets or parenteses. """ return self._print_label(printer, *args) def _print_contents_pretty(self, printer, *args): return self._print_label_pretty(printer, *args) def _print_contents_latex(self, printer, *args): return self._print_label_latex(printer, *args) # Main printing methods def _sympystr(self, printer, *args): """Default printing behavior of QExpr objects Handles the default printing of a QExpr. To add other things to the printing of the object, such as an operator name to operators or brackets to states, the class should override the _print/_pretty/_latex functions directly and make calls to _print_contents where appropriate. This allows things like InnerProduct to easily control its printing the printing of contents. """ return self._print_contents(printer, *args) def _sympyrepr(self, printer, *args): classname = self.__class__.__name__ label = self._print_label_repr(printer, *args) return '%s(%s)' % (classname, label) def _pretty(self, printer, *args): pform = self._print_contents_pretty(printer, *args) return pform def _latex(self, printer, *args): return self._print_contents_latex(printer, *args) #------------------------------------------------------------------------- # Methods from Basic and Expr #------------------------------------------------------------------------- def doit(self, **kw_args): return self #------------------------------------------------------------------------- # Represent #------------------------------------------------------------------------- def _represent_default_basis(self, **options): raise NotImplementedError('This object does not have a default basis') def _represent(self, *, basis=None, **options): """Represent this object in a given basis. This method dispatches to the actual methods that perform the representation. Subclases of QExpr should define various methods to determine how the object will be represented in various bases. The format of these methods is:: def _represent_BasisName(self, basis, **options): Thus to define how a quantum object is represented in the basis of the operator Position, you would define:: def _represent_Position(self, basis, **options): Usually, basis object will be instances of Operator subclasses, but there is a chance we will relax this in the future to accommodate other types of basis sets that are not associated with an operator. If the ``format`` option is given it can be ("sympy", "numpy", "scipy.sparse"). This will ensure that any matrices that result from representing the object are returned in the appropriate matrix format. Parameters ========== basis : Operator The Operator whose basis functions will be used as the basis for representation. options : dict A dictionary of key/value pairs that give options and hints for the representation, such as the number of basis functions to be used. """ if basis is None: result = self._represent_default_basis(**options) else: result = dispatch_method(self, '_represent', basis, **options) # If we get a matrix representation, convert it to the right format. format = options.get('format', 'sympy') result = self._format_represent(result, format) return result def _format_represent(self, result, format): if format == 'sympy' and not isinstance(result, Matrix): return to_sympy(result) elif format == 'numpy' and not isinstance(result, numpy_ndarray): return to_numpy(result) elif format == 'scipy.sparse' and \ not isinstance(result, scipy_sparse_matrix): return to_scipy_sparse(result) return result def split_commutative_parts(e): """Split into commutative and non-commutative parts.""" c_part, nc_part = e.args_cnc() c_part = list(c_part) return c_part, nc_part def split_qexpr_parts(e): """Split an expression into Expr and noncommutative QExpr parts.""" expr_part = [] qexpr_part = [] for arg in e.args: if not isinstance(arg, QExpr): expr_part.append(arg) else: qexpr_part.append(arg) return expr_part, qexpr_part def dispatch_method(self, basename, arg, **options): """Dispatch a method to the proper handlers.""" method_name = '%s_%s' % (basename, arg.__class__.__name__) if hasattr(self, method_name): f = getattr(self, method_name) # This can raise and we will allow it to propagate. result = f(arg, **options) if result is not None: return result raise NotImplementedError( "%s.%s can't handle: %r" % (self.__class__.__name__, basename, arg) ) sympy-sympy-1.9/sympy/physics/quantum/qft.py000066400000000000000000000140671412543434000214340ustar00rootroot00000000000000"""An implementation of qubits and gates acting on them. Todo: * Update docstrings. * Update tests. * Implement apply using decompose. * Implement represent using decompose or something smarter. For this to work we first have to implement represent for SWAP. * Decide if we want upper index to be inclusive in the constructor. * Fix the printing of Rk gates in plotting. """ from sympy import Expr, Matrix, exp, I, pi, Integer, Symbol from sympy.functions import sqrt from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qexpr import QuantumError, QExpr from sympy.matrices import eye from sympy.physics.quantum.tensorproduct import matrix_tensor_product from sympy.physics.quantum.gate import ( Gate, HadamardGate, SwapGate, OneQubitGate, CGate, PhaseGate, TGate, ZGate ) __all__ = [ 'QFT', 'IQFT', 'RkGate', 'Rk' ] #----------------------------------------------------------------------------- # Fourier stuff #----------------------------------------------------------------------------- class RkGate(OneQubitGate): """This is the R_k gate of the QTF.""" gate_name = 'Rk' gate_name_latex = 'R' def __new__(cls, *args): if len(args) != 2: raise QuantumError( 'Rk gates only take two arguments, got: %r' % args ) # For small k, Rk gates simplify to other gates, using these # substitutions give us familiar results for the QFT for small numbers # of qubits. target = args[0] k = args[1] if k == 1: return ZGate(target) elif k == 2: return PhaseGate(target) elif k == 3: return TGate(target) args = cls._eval_args(args) inst = Expr.__new__(cls, *args) inst.hilbert_space = cls._eval_hilbert_space(args) return inst @classmethod def _eval_args(cls, args): # Fall back to this, because Gate._eval_args assumes that args is # all targets and can't contain duplicates. return QExpr._eval_args(args) @property def k(self): return self.label[1] @property def targets(self): return self.label[:1] @property def gate_name_plot(self): return r'$%s_%s$' % (self.gate_name_latex, str(self.k)) def get_target_matrix(self, format='sympy'): if format == 'sympy': return Matrix([[1, 0], [0, exp(Integer(2)*pi*I/(Integer(2)**self.k))]]) raise NotImplementedError( 'Invalid format for the R_k gate: %r' % format) Rk = RkGate class Fourier(Gate): """Superclass of Quantum Fourier and Inverse Quantum Fourier Gates.""" @classmethod def _eval_args(self, args): if len(args) != 2: raise QuantumError( 'QFT/IQFT only takes two arguments, got: %r' % args ) if args[0] >= args[1]: raise QuantumError("Start must be smaller than finish") return Gate._eval_args(args) def _represent_default_basis(self, **options): return self._represent_ZGate(None, **options) def _represent_ZGate(self, basis, **options): """ Represents the (I)QFT In the Z Basis """ nqubits = options.get('nqubits', 0) if nqubits == 0: raise QuantumError( 'The number of qubits must be given as nqubits.') if nqubits < self.min_qubits: raise QuantumError( 'The number of qubits %r is too small for the gate.' % nqubits ) size = self.size omega = self.omega #Make a matrix that has the basic Fourier Transform Matrix arrayFT = [[omega**( i*j % size)/sqrt(size) for i in range(size)] for j in range(size)] matrixFT = Matrix(arrayFT) #Embed the FT Matrix in a higher space, if necessary if self.label[0] != 0: matrixFT = matrix_tensor_product(eye(2**self.label[0]), matrixFT) if self.min_qubits < nqubits: matrixFT = matrix_tensor_product( matrixFT, eye(2**(nqubits - self.min_qubits))) return matrixFT @property def targets(self): return range(self.label[0], self.label[1]) @property def min_qubits(self): return self.label[1] @property def size(self): """Size is the size of the QFT matrix""" return 2**(self.label[1] - self.label[0]) @property def omega(self): return Symbol('omega') class QFT(Fourier): """The forward quantum Fourier transform.""" gate_name = 'QFT' gate_name_latex = 'QFT' def decompose(self): """Decomposes QFT into elementary gates.""" start = self.label[0] finish = self.label[1] circuit = 1 for level in reversed(range(start, finish)): circuit = HadamardGate(level)*circuit for i in range(level - start): circuit = CGate(level - i - 1, RkGate(level, i + 2))*circuit for i in range((finish - start)//2): circuit = SwapGate(i + start, finish - i - 1)*circuit return circuit def _apply_operator_Qubit(self, qubits, **options): return qapply(self.decompose()*qubits) def _eval_inverse(self): return IQFT(*self.args) @property def omega(self): return exp(2*pi*I/self.size) class IQFT(Fourier): """The inverse quantum Fourier transform.""" gate_name = 'IQFT' gate_name_latex = '{QFT^{-1}}' def decompose(self): """Decomposes IQFT into elementary gates.""" start = self.args[0] finish = self.args[1] circuit = 1 for i in range((finish - start)//2): circuit = SwapGate(i + start, finish - i - 1)*circuit for level in range(start, finish): for i in reversed(range(level - start)): circuit = CGate(level - i - 1, RkGate(level, -i - 2))*circuit circuit = HadamardGate(level)*circuit return circuit def _eval_inverse(self): return QFT(*self.args) @property def omega(self): return exp(-2*pi*I/self.size) sympy-sympy-1.9/sympy/physics/quantum/qubit.py000066400000000000000000000620341412543434000217630ustar00rootroot00000000000000"""Qubits for quantum computing. Todo: * Finish implementing measurement logic. This should include POVM. * Update docstrings. * Update tests. """ import math from sympy import Integer, log, Mul, Add, Pow, conjugate from sympy.core.basic import sympify from sympy.core.compatibility import SYMPY_INTS from sympy.matrices import Matrix, zeros from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.hilbert import ComplexSpace from sympy.physics.quantum.state import Ket, Bra, State from sympy.physics.quantum.qexpr import QuantumError from sympy.physics.quantum.represent import represent from sympy.physics.quantum.matrixutils import ( numpy_ndarray, scipy_sparse_matrix ) from mpmath.libmp.libintmath import bitcount __all__ = [ 'Qubit', 'QubitBra', 'IntQubit', 'IntQubitBra', 'qubit_to_matrix', 'matrix_to_qubit', 'matrix_to_density', 'measure_all', 'measure_partial', 'measure_partial_oneshot', 'measure_all_oneshot' ] #----------------------------------------------------------------------------- # Qubit Classes #----------------------------------------------------------------------------- class QubitState(State): """Base class for Qubit and QubitBra.""" #------------------------------------------------------------------------- # Initialization/creation #------------------------------------------------------------------------- @classmethod def _eval_args(cls, args): # If we are passed a QubitState or subclass, we just take its qubit # values directly. if len(args) == 1 and isinstance(args[0], QubitState): return args[0].qubit_values # Turn strings into tuple of strings if len(args) == 1 and isinstance(args[0], str): args = tuple(args[0]) args = sympify(args) # Validate input (must have 0 or 1 input) for element in args: if not (element == 1 or element == 0): raise ValueError( "Qubit values must be 0 or 1, got: %r" % element) return args @classmethod def _eval_hilbert_space(cls, args): return ComplexSpace(2)**len(args) #------------------------------------------------------------------------- # Properties #------------------------------------------------------------------------- @property def dimension(self): """The number of Qubits in the state.""" return len(self.qubit_values) @property def nqubits(self): return self.dimension @property def qubit_values(self): """Returns the values of the qubits as a tuple.""" return self.label #------------------------------------------------------------------------- # Special methods #------------------------------------------------------------------------- def __len__(self): return self.dimension def __getitem__(self, bit): return self.qubit_values[int(self.dimension - bit - 1)] #------------------------------------------------------------------------- # Utility methods #------------------------------------------------------------------------- def flip(self, *bits): """Flip the bit(s) given.""" newargs = list(self.qubit_values) for i in bits: bit = int(self.dimension - i - 1) if newargs[bit] == 1: newargs[bit] = 0 else: newargs[bit] = 1 return self.__class__(*tuple(newargs)) class Qubit(QubitState, Ket): """A multi-qubit ket in the computational (z) basis. We use the normal convention that the least significant qubit is on the right, so ``|00001>`` has a 1 in the least significant qubit. Parameters ========== values : list, str The qubit values as a list of ints ([0,0,0,1,1,]) or a string ('011'). Examples ======== Create a qubit in a couple of different ways and look at their attributes: >>> from sympy.physics.quantum.qubit import Qubit >>> Qubit(0,0,0) |000> >>> q = Qubit('0101') >>> q |0101> >>> q.nqubits 4 >>> len(q) 4 >>> q.dimension 4 >>> q.qubit_values (0, 1, 0, 1) We can flip the value of an individual qubit: >>> q.flip(1) |0111> We can take the dagger of a Qubit to get a bra: >>> from sympy.physics.quantum.dagger import Dagger >>> Dagger(q) <0101| >>> type(Dagger(q)) Inner products work as expected: >>> ip = Dagger(q)*q >>> ip <0101|0101> >>> ip.doit() 1 """ @classmethod def dual_class(self): return QubitBra def _eval_innerproduct_QubitBra(self, bra, **hints): if self.label == bra.label: return Integer(1) else: return Integer(0) def _represent_default_basis(self, **options): return self._represent_ZGate(None, **options) def _represent_ZGate(self, basis, **options): """Represent this qubits in the computational basis (ZGate). """ _format = options.get('format', 'sympy') n = 1 definite_state = 0 for it in reversed(self.qubit_values): definite_state += n*it n = n*2 result = [0]*(2**self.dimension) result[int(definite_state)] = 1 if _format == 'sympy': return Matrix(result) elif _format == 'numpy': import numpy as np return np.matrix(result, dtype='complex').transpose() elif _format == 'scipy.sparse': from scipy import sparse return sparse.csr_matrix(result, dtype='complex').transpose() def _eval_trace(self, bra, **kwargs): indices = kwargs.get('indices', []) #sort index list to begin trace from most-significant #qubit sorted_idx = list(indices) if len(sorted_idx) == 0: sorted_idx = list(range(0, self.nqubits)) sorted_idx.sort() #trace out for each of index new_mat = self*bra for i in range(len(sorted_idx) - 1, -1, -1): # start from tracing out from leftmost qubit new_mat = self._reduced_density(new_mat, int(sorted_idx[i])) if (len(sorted_idx) == self.nqubits): #in case full trace was requested return new_mat[0] else: return matrix_to_density(new_mat) def _reduced_density(self, matrix, qubit, **options): """Compute the reduced density matrix by tracing out one qubit. The qubit argument should be of type python int, since it is used in bit operations """ def find_index_that_is_projected(j, k, qubit): bit_mask = 2**qubit - 1 return ((j >> qubit) << (1 + qubit)) + (j & bit_mask) + (k << qubit) old_matrix = represent(matrix, **options) old_size = old_matrix.cols #we expect the old_size to be even new_size = old_size//2 new_matrix = Matrix().zeros(new_size) for i in range(new_size): for j in range(new_size): for k in range(2): col = find_index_that_is_projected(j, k, qubit) row = find_index_that_is_projected(i, k, qubit) new_matrix[i, j] += old_matrix[row, col] return new_matrix class QubitBra(QubitState, Bra): """A multi-qubit bra in the computational (z) basis. We use the normal convention that the least significant qubit is on the right, so ``|00001>`` has a 1 in the least significant qubit. Parameters ========== values : list, str The qubit values as a list of ints ([0,0,0,1,1,]) or a string ('011'). See also ======== Qubit: Examples using qubits """ @classmethod def dual_class(self): return Qubit class IntQubitState(QubitState): """A base class for qubits that work with binary representations.""" @classmethod def _eval_args(cls, args, nqubits=None): # The case of a QubitState instance if len(args) == 1 and isinstance(args[0], QubitState): return QubitState._eval_args(args) # otherwise, args should be integer elif not all(isinstance(a, (int, Integer)) for a in args): raise ValueError('values must be integers, got (%s)' % (tuple(type(a) for a in args),)) # use nqubits if specified if nqubits is not None: if not isinstance(nqubits, (int, Integer)): raise ValueError('nqubits must be an integer, got (%s)' % type(nqubits)) if len(args) != 1: raise ValueError( 'too many positional arguments (%s). should be (number, nqubits=n)' % (args,)) return cls._eval_args_with_nqubits(args[0], nqubits) # For a single argument, we construct the binary representation of # that integer with the minimal number of bits. if len(args) == 1 and args[0] > 1: #rvalues is the minimum number of bits needed to express the number rvalues = reversed(range(bitcount(abs(args[0])))) qubit_values = [(args[0] >> i) & 1 for i in rvalues] return QubitState._eval_args(qubit_values) # For two numbers, the second number is the number of bits # on which it is expressed, so IntQubit(0,5) == |00000>. elif len(args) == 2 and args[1] > 1: return cls._eval_args_with_nqubits(args[0], args[1]) else: return QubitState._eval_args(args) @classmethod def _eval_args_with_nqubits(cls, number, nqubits): need = bitcount(abs(number)) if nqubits < need: raise ValueError( 'cannot represent %s with %s bits' % (number, nqubits)) qubit_values = [(number >> i) & 1 for i in reversed(range(nqubits))] return QubitState._eval_args(qubit_values) def as_int(self): """Return the numerical value of the qubit.""" number = 0 n = 1 for i in reversed(self.qubit_values): number += n*i n = n << 1 return number def _print_label(self, printer, *args): return str(self.as_int()) def _print_label_pretty(self, printer, *args): label = self._print_label(printer, *args) return prettyForm(label) _print_label_repr = _print_label _print_label_latex = _print_label class IntQubit(IntQubitState, Qubit): """A qubit ket that store integers as binary numbers in qubit values. The differences between this class and ``Qubit`` are: * The form of the constructor. * The qubit values are printed as their corresponding integer, rather than the raw qubit values. The internal storage format of the qubit values in the same as ``Qubit``. Parameters ========== values : int, tuple If a single argument, the integer we want to represent in the qubit values. This integer will be represented using the fewest possible number of qubits. If a pair of integers and the second value is more than one, the first integer gives the integer to represent in binary form and the second integer gives the number of qubits to use. List of zeros and ones is also accepted to generate qubit by bit pattern. nqubits : int The integer that represents the number of qubits. This number should be passed with keyword ``nqubits=N``. You can use this in order to avoid ambiguity of Qubit-style tuple of bits. Please see the example below for more details. Examples ======== Create a qubit for the integer 5: >>> from sympy.physics.quantum.qubit import IntQubit >>> from sympy.physics.quantum.qubit import Qubit >>> q = IntQubit(5) >>> q |5> We can also create an ``IntQubit`` by passing a ``Qubit`` instance. >>> q = IntQubit(Qubit('101')) >>> q |5> >>> q.as_int() 5 >>> q.nqubits 3 >>> q.qubit_values (1, 0, 1) We can go back to the regular qubit form. >>> Qubit(q) |101> Please note that ``IntQubit`` also accepts a ``Qubit``-style list of bits. So, the code below yields qubits 3, not a single bit ``1``. >>> IntQubit(1, 1) |3> To avoid ambiguity, use ``nqubits`` parameter. Use of this keyword is recommended especially when you provide the values by variables. >>> IntQubit(1, nqubits=1) |1> >>> a = 1 >>> IntQubit(a, nqubits=1) |1> """ @classmethod def dual_class(self): return IntQubitBra def _eval_innerproduct_IntQubitBra(self, bra, **hints): return Qubit._eval_innerproduct_QubitBra(self, bra) class IntQubitBra(IntQubitState, QubitBra): """A qubit bra that store integers as binary numbers in qubit values.""" @classmethod def dual_class(self): return IntQubit #----------------------------------------------------------------------------- # Qubit <---> Matrix conversion functions #----------------------------------------------------------------------------- def matrix_to_qubit(matrix): """Convert from the matrix repr. to a sum of Qubit objects. Parameters ---------- matrix : Matrix, numpy.matrix, scipy.sparse The matrix to build the Qubit representation of. This works with sympy matrices, numpy matrices and scipy.sparse sparse matrices. Examples ======== Represent a state and then go back to its qubit form: >>> from sympy.physics.quantum.qubit import matrix_to_qubit, Qubit >>> from sympy.physics.quantum.represent import represent >>> q = Qubit('01') >>> matrix_to_qubit(represent(q)) |01> """ # Determine the format based on the type of the input matrix format = 'sympy' if isinstance(matrix, numpy_ndarray): format = 'numpy' if isinstance(matrix, scipy_sparse_matrix): format = 'scipy.sparse' # Make sure it is of correct dimensions for a Qubit-matrix representation. # This logic should work with sympy, numpy or scipy.sparse matrices. if matrix.shape[0] == 1: mlistlen = matrix.shape[1] nqubits = log(mlistlen, 2) ket = False cls = QubitBra elif matrix.shape[1] == 1: mlistlen = matrix.shape[0] nqubits = log(mlistlen, 2) ket = True cls = Qubit else: raise QuantumError( 'Matrix must be a row/column vector, got %r' % matrix ) if not isinstance(nqubits, Integer): raise QuantumError('Matrix must be a row/column vector of size ' '2**nqubits, got: %r' % matrix) # Go through each item in matrix, if element is non-zero, make it into a # Qubit item times the element. result = 0 for i in range(mlistlen): if ket: element = matrix[i, 0] else: element = matrix[0, i] if format == 'numpy' or format == 'scipy.sparse': element = complex(element) if element != 0.0: # Form Qubit array; 0 in bit-locations where i is 0, 1 in # bit-locations where i is 1 qubit_array = [int(i & (1 << x) != 0) for x in range(nqubits)] qubit_array.reverse() result = result + element*cls(*qubit_array) # If sympy simplified by pulling out a constant coefficient, undo that. if isinstance(result, (Mul, Add, Pow)): result = result.expand() return result def matrix_to_density(mat): """ Works by finding the eigenvectors and eigenvalues of the matrix. We know we can decompose rho by doing: sum(EigenVal*|Eigenvect>>> from sympy.physics.quantum.qubit import Qubit, measure_all >>> from sympy.physics.quantum.gate import H >>> from sympy.physics.quantum.qapply import qapply >>> c = H(0)*H(1)*Qubit('00') >>> c H(0)*H(1)*|00> >>> q = qapply(c) >>> measure_all(q) [(|00>, 1/4), (|01>, 1/4), (|10>, 1/4), (|11>, 1/4)] """ m = qubit_to_matrix(qubit, format) if format == 'sympy': results = [] if normalize: m = m.normalized() size = max(m.shape) # Max of shape to account for bra or ket nqubits = int(math.log(size)/math.log(2)) for i in range(size): if m[i] != 0.0: results.append( (Qubit(IntQubit(i, nqubits=nqubits)), m[i]*conjugate(m[i])) ) return results else: raise NotImplementedError( "This function can't handle non-sympy matrix formats yet" ) def measure_partial(qubit, bits, format='sympy', normalize=True): """Perform a partial ensemble measure on the specified qubits. Parameters ========== qubits : Qubit The qubit to measure. This can be any Qubit or a linear combination of them. bits : tuple The qubits to measure. format : str The format of the intermediate matrices to use. Possible values are ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is implemented. Returns ======= result : list A list that consists of primitive states and their probabilities. Examples ======== >>> from sympy.physics.quantum.qubit import Qubit, measure_partial >>> from sympy.physics.quantum.gate import H >>> from sympy.physics.quantum.qapply import qapply >>> c = H(0)*H(1)*Qubit('00') >>> c H(0)*H(1)*|00> >>> q = qapply(c) >>> measure_partial(q, (0,)) [(sqrt(2)*|00>/2 + sqrt(2)*|10>/2, 1/2), (sqrt(2)*|01>/2 + sqrt(2)*|11>/2, 1/2)] """ m = qubit_to_matrix(qubit, format) if isinstance(bits, (SYMPY_INTS, Integer)): bits = (int(bits),) if format == 'sympy': if normalize: m = m.normalized() possible_outcomes = _get_possible_outcomes(m, bits) # Form output from function. output = [] for outcome in possible_outcomes: # Calculate probability of finding the specified bits with # given values. prob_of_outcome = 0 prob_of_outcome += (outcome.H*outcome)[0] # If the output has a chance, append it to output with found # probability. if prob_of_outcome != 0: if normalize: next_matrix = matrix_to_qubit(outcome.normalized()) else: next_matrix = matrix_to_qubit(outcome) output.append(( next_matrix, prob_of_outcome )) return output else: raise NotImplementedError( "This function can't handle non-sympy matrix formats yet" ) def measure_partial_oneshot(qubit, bits, format='sympy'): """Perform a partial oneshot measurement on the specified qubits. A oneshot measurement is equivalent to performing a measurement on a quantum system. This type of measurement does not return the probabilities like an ensemble measurement does, but rather returns *one* of the possible resulting states. The exact state that is returned is determined by picking a state randomly according to the ensemble probabilities. Parameters ---------- qubits : Qubit The qubit to measure. This can be any Qubit or a linear combination of them. bits : tuple The qubits to measure. format : str The format of the intermediate matrices to use. Possible values are ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is implemented. Returns ------- result : Qubit The qubit that the system collapsed to upon measurement. """ import random m = qubit_to_matrix(qubit, format) if format == 'sympy': m = m.normalized() possible_outcomes = _get_possible_outcomes(m, bits) # Form output from function random_number = random.random() total_prob = 0 for outcome in possible_outcomes: # Calculate probability of finding the specified bits # with given values total_prob += (outcome.H*outcome)[0] if total_prob >= random_number: return matrix_to_qubit(outcome.normalized()) else: raise NotImplementedError( "This function can't handle non-sympy matrix formats yet" ) def _get_possible_outcomes(m, bits): """Get the possible states that can be produced in a measurement. Parameters ---------- m : Matrix The matrix representing the state of the system. bits : tuple, list Which bits will be measured. Returns ------- result : list The list of possible states which can occur given this measurement. These are un-normalized so we can derive the probability of finding this state by taking the inner product with itself """ # This is filled with loads of dirty binary tricks...You have been warned size = max(m.shape) # Max of shape to account for bra or ket nqubits = int(math.log(size, 2) + .1) # Number of qubits possible # Make the output states and put in output_matrices, nothing in them now. # Each state will represent a possible outcome of the measurement # Thus, output_matrices[0] is the matrix which we get when all measured # bits return 0. and output_matrices[1] is the matrix for only the 0th # bit being true output_matrices = [] for i in range(1 << len(bits)): output_matrices.append(zeros(2**nqubits, 1)) # Bitmasks will help sort how to determine possible outcomes. # When the bit mask is and-ed with a matrix-index, # it will determine which state that index belongs to bit_masks = [] for bit in bits: bit_masks.append(1 << bit) # Make possible outcome states for i in range(2**nqubits): trueness = 0 # This tells us to which output_matrix this value belongs # Find trueness for j in range(len(bit_masks)): if i & bit_masks[j]: trueness += j + 1 # Put the value in the correct output matrix output_matrices[trueness][i] = m[i] return output_matrices def measure_all_oneshot(qubit, format='sympy'): """Perform a oneshot ensemble measurement on all qubits. A oneshot measurement is equivalent to performing a measurement on a quantum system. This type of measurement does not return the probabilities like an ensemble measurement does, but rather returns *one* of the possible resulting states. The exact state that is returned is determined by picking a state randomly according to the ensemble probabilities. Parameters ---------- qubits : Qubit The qubit to measure. This can be any Qubit or a linear combination of them. format : str The format of the intermediate matrices to use. Possible values are ('sympy','numpy','scipy.sparse'). Currently only 'sympy' is implemented. Returns ------- result : Qubit The qubit that the system collapsed to upon measurement. """ import random m = qubit_to_matrix(qubit) if format == 'sympy': m = m.normalized() random_number = random.random() total = 0 result = 0 for i in m: total += i*i.conjugate() if total > random_number: break result += 1 return Qubit(IntQubit(result, int(math.log(max(m.shape), 2) + .1))) else: raise NotImplementedError( "This function can't handle non-sympy matrix formats yet" ) sympy-sympy-1.9/sympy/physics/quantum/represent.py000066400000000000000000000435451412543434000226540ustar00rootroot00000000000000"""Logic for representing operators in state in various bases. TODO: * Get represent working with continuous hilbert spaces. * Document default basis functionality. """ from sympy import Add, Expr, I, integrate, Mul, Pow from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.innerproduct import InnerProduct from sympy.physics.quantum.qexpr import QExpr from sympy.physics.quantum.tensorproduct import TensorProduct from sympy.physics.quantum.matrixutils import flatten_scalar from sympy.physics.quantum.state import KetBase, BraBase, StateBase from sympy.physics.quantum.operator import Operator, OuterProduct from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.operatorset import operators_to_state, state_to_operators __all__ = [ 'represent', 'rep_innerproduct', 'rep_expectation', 'integrate_result', 'get_basis', 'enumerate_states' ] #----------------------------------------------------------------------------- # Represent #----------------------------------------------------------------------------- def _sympy_to_scalar(e): """Convert from a sympy scalar to a Python scalar.""" if isinstance(e, Expr): if e.is_Integer: return int(e) elif e.is_Float: return float(e) elif e.is_Rational: return float(e) elif e.is_Number or e.is_NumberSymbol or e == I: return complex(e) raise TypeError('Expected number, got: %r' % e) def represent(expr, **options): """Represent the quantum expression in the given basis. In quantum mechanics abstract states and operators can be represented in various basis sets. Under this operation the follow transforms happen: * Ket -> column vector or function * Bra -> row vector of function * Operator -> matrix or differential operator This function is the top-level interface for this action. This function walks the sympy expression tree looking for ``QExpr`` instances that have a ``_represent`` method. This method is then called and the object is replaced by the representation returned by this method. By default, the ``_represent`` method will dispatch to other methods that handle the representation logic for a particular basis set. The naming convention for these methods is the following:: def _represent_FooBasis(self, e, basis, **options) This function will have the logic for representing instances of its class in the basis set having a class named ``FooBasis``. Parameters ========== expr : Expr The expression to represent. basis : Operator, basis set An object that contains the information about the basis set. If an operator is used, the basis is assumed to be the orthonormal eigenvectors of that operator. In general though, the basis argument can be any object that contains the basis set information. options : dict Key/value pairs of options that are passed to the underlying method that finds the representation. These options can be used to control how the representation is done. For example, this is where the size of the basis set would be set. Returns ======= e : Expr The SymPy expression of the represented quantum expression. Examples ======== Here we subclass ``Operator`` and ``Ket`` to create the z-spin operator and its spin 1/2 up eigenstate. By defining the ``_represent_SzOp`` method, the ket can be represented in the z-spin basis. >>> from sympy.physics.quantum import Operator, represent, Ket >>> from sympy import Matrix >>> class SzUpKet(Ket): ... def _represent_SzOp(self, basis, **options): ... return Matrix([1,0]) ... >>> class SzOp(Operator): ... pass ... >>> sz = SzOp('Sz') >>> up = SzUpKet('up') >>> represent(up, basis=sz) Matrix([ [1], [0]]) Here we see an example of representations in a continuous basis. We see that the result of representing various combinations of cartesian position operators and kets give us continuous expressions involving DiracDelta functions. >>> from sympy.physics.quantum.cartesian import XOp, XKet, XBra >>> X = XOp() >>> x = XKet() >>> y = XBra('y') >>> represent(X*x) x*DiracDelta(x - x_2) >>> represent(X*x*y) x*DiracDelta(x - x_3)*DiracDelta(x_1 - y) """ format = options.get('format', 'sympy') if isinstance(expr, QExpr) and not isinstance(expr, OuterProduct): options['replace_none'] = False temp_basis = get_basis(expr, **options) if temp_basis is not None: options['basis'] = temp_basis try: return expr._represent(**options) except NotImplementedError as strerr: #If no _represent_FOO method exists, map to the #appropriate basis state and try #the other methods of representation options['replace_none'] = True if isinstance(expr, (KetBase, BraBase)): try: return rep_innerproduct(expr, **options) except NotImplementedError: raise NotImplementedError(strerr) elif isinstance(expr, Operator): try: return rep_expectation(expr, **options) except NotImplementedError: raise NotImplementedError(strerr) else: raise NotImplementedError(strerr) elif isinstance(expr, Add): result = represent(expr.args[0], **options) for args in expr.args[1:]: # scipy.sparse doesn't support += so we use plain = here. result = result + represent(args, **options) return result elif isinstance(expr, Pow): base, exp = expr.as_base_exp() if format == 'numpy' or format == 'scipy.sparse': exp = _sympy_to_scalar(exp) base = represent(base, **options) # scipy.sparse doesn't support negative exponents # and warns when inverting a matrix in csr format. if format == 'scipy.sparse' and exp < 0: from scipy.sparse.linalg import inv exp = - exp base = inv(base.tocsc()).tocsr() return base ** exp elif isinstance(expr, TensorProduct): new_args = [represent(arg, **options) for arg in expr.args] return TensorProduct(*new_args) elif isinstance(expr, Dagger): return Dagger(represent(expr.args[0], **options)) elif isinstance(expr, Commutator): A = represent(expr.args[0], **options) B = represent(expr.args[1], **options) return A*B - B*A elif isinstance(expr, AntiCommutator): A = represent(expr.args[0], **options) B = represent(expr.args[1], **options) return A*B + B*A elif isinstance(expr, InnerProduct): return represent(Mul(expr.bra, expr.ket), **options) elif not (isinstance(expr, Mul) or isinstance(expr, OuterProduct)): # For numpy and scipy.sparse, we can only handle numerical prefactors. if format == 'numpy' or format == 'scipy.sparse': return _sympy_to_scalar(expr) return expr if not (isinstance(expr, Mul) or isinstance(expr, OuterProduct)): raise TypeError('Mul expected, got: %r' % expr) if "index" in options: options["index"] += 1 else: options["index"] = 1 if not "unities" in options: options["unities"] = [] result = represent(expr.args[-1], **options) last_arg = expr.args[-1] for arg in reversed(expr.args[:-1]): if isinstance(last_arg, Operator): options["index"] += 1 options["unities"].append(options["index"]) elif isinstance(last_arg, BraBase) and isinstance(arg, KetBase): options["index"] += 1 elif isinstance(last_arg, KetBase) and isinstance(arg, Operator): options["unities"].append(options["index"]) elif isinstance(last_arg, KetBase) and isinstance(arg, BraBase): options["unities"].append(options["index"]) result = represent(arg, **options)*result last_arg = arg # All three matrix formats create 1 by 1 matrices when inner products of # vectors are taken. In these cases, we simply return a scalar. result = flatten_scalar(result) result = integrate_result(expr, result, **options) return result def rep_innerproduct(expr, **options): """ Returns an innerproduct like representation (e.g. ````) for the given state. Attempts to calculate inner product with a bra from the specified basis. Should only be passed an instance of KetBase or BraBase Parameters ========== expr : KetBase or BraBase The expression to be represented Examples ======== >>> from sympy.physics.quantum.represent import rep_innerproduct >>> from sympy.physics.quantum.cartesian import XOp, XKet, PxOp, PxKet >>> rep_innerproduct(XKet()) DiracDelta(x - x_1) >>> rep_innerproduct(XKet(), basis=PxOp()) sqrt(2)*exp(-I*px_1*x/hbar)/(2*sqrt(hbar)*sqrt(pi)) >>> rep_innerproduct(PxKet(), basis=XOp()) sqrt(2)*exp(I*px*x_1/hbar)/(2*sqrt(hbar)*sqrt(pi)) """ if not isinstance(expr, (KetBase, BraBase)): raise TypeError("expr passed is not a Bra or Ket") basis = get_basis(expr, **options) if not isinstance(basis, StateBase): raise NotImplementedError("Can't form this representation!") if not "index" in options: options["index"] = 1 basis_kets = enumerate_states(basis, options["index"], 2) if isinstance(expr, BraBase): bra = expr ket = (basis_kets[1] if basis_kets[0].dual == expr else basis_kets[0]) else: bra = (basis_kets[1].dual if basis_kets[0] == expr else basis_kets[0].dual) ket = expr prod = InnerProduct(bra, ket) result = prod.doit() format = options.get('format', 'sympy') return expr._format_represent(result, format) def rep_expectation(expr, **options): """ Returns an ```` type representation for the given operator. Parameters ========== expr : Operator Operator to be represented in the specified basis Examples ======== >>> from sympy.physics.quantum.cartesian import XOp, PxOp, PxKet >>> from sympy.physics.quantum.represent import rep_expectation >>> rep_expectation(XOp()) x_1*DiracDelta(x_1 - x_2) >>> rep_expectation(XOp(), basis=PxOp()) >>> rep_expectation(XOp(), basis=PxKet()) """ if not "index" in options: options["index"] = 1 if not isinstance(expr, Operator): raise TypeError("The passed expression is not an operator") basis_state = get_basis(expr, **options) if basis_state is None or not isinstance(basis_state, StateBase): raise NotImplementedError("Could not get basis kets for this operator") basis_kets = enumerate_states(basis_state, options["index"], 2) bra = basis_kets[1].dual ket = basis_kets[0] return qapply(bra*expr*ket) def integrate_result(orig_expr, result, **options): """ Returns the result of integrating over any unities ``(|x>>> from sympy import symbols, DiracDelta >>> from sympy.physics.quantum.represent import integrate_result >>> from sympy.physics.quantum.cartesian import XOp, XKet >>> x_ket = XKet() >>> X_op = XOp() >>> x, x_1, x_2 = symbols('x, x_1, x_2') >>> integrate_result(X_op*x_ket, x*DiracDelta(x-x_1)*DiracDelta(x_1-x_2)) x*DiracDelta(x - x_1)*DiracDelta(x_1 - x_2) >>> integrate_result(X_op*x_ket, x*DiracDelta(x-x_1)*DiracDelta(x_1-x_2), ... unities=[1]) x*DiracDelta(x - x_2) """ if not isinstance(result, Expr): return result options['replace_none'] = True if not "basis" in options: arg = orig_expr.args[-1] options["basis"] = get_basis(arg, **options) elif not isinstance(options["basis"], StateBase): options["basis"] = get_basis(orig_expr, **options) basis = options.pop("basis", None) if basis is None: return result unities = options.pop("unities", []) if len(unities) == 0: return result kets = enumerate_states(basis, unities) coords = [k.label[0] for k in kets] for coord in coords: if coord in result.free_symbols: #TODO: Add support for sets of operators basis_op = state_to_operators(basis) start = basis_op.hilbert_space.interval.start end = basis_op.hilbert_space.interval.end result = integrate(result, (coord, start, end)) return result def get_basis(expr, *, basis=None, replace_none=True, **options): """ Returns a basis state instance corresponding to the basis specified in options=s. If no basis is specified, the function tries to form a default basis state of the given expression. There are three behaviors: 1. The basis specified in options is already an instance of StateBase. If this is the case, it is simply returned. If the class is specified but not an instance, a default instance is returned. 2. The basis specified is an operator or set of operators. If this is the case, the operator_to_state mapping method is used. 3. No basis is specified. If expr is a state, then a default instance of its class is returned. If expr is an operator, then it is mapped to the corresponding state. If it is neither, then we cannot obtain the basis state. If the basis cannot be mapped, then it is not changed. This will be called from within represent, and represent will only pass QExpr's. TODO (?): Support for Muls and other types of expressions? Parameters ========== expr : Operator or StateBase Expression whose basis is sought Examples ======== >>> from sympy.physics.quantum.represent import get_basis >>> from sympy.physics.quantum.cartesian import XOp, XKet, PxOp, PxKet >>> x = XKet() >>> X = XOp() >>> get_basis(x) |x> >>> get_basis(X) |x> >>> get_basis(x, basis=PxOp()) |px> >>> get_basis(x, basis=PxKet) |px> """ if basis is None and not replace_none: return None if basis is None: if isinstance(expr, KetBase): return _make_default(expr.__class__) elif isinstance(expr, BraBase): return _make_default(expr.dual_class()) elif isinstance(expr, Operator): state_inst = operators_to_state(expr) return (state_inst if state_inst is not None else None) else: return None elif (isinstance(basis, Operator) or (not isinstance(basis, StateBase) and issubclass(basis, Operator))): state = operators_to_state(basis) if state is None: return None elif isinstance(state, StateBase): return state else: return _make_default(state) elif isinstance(basis, StateBase): return basis elif issubclass(basis, StateBase): return _make_default(basis) else: return None def _make_default(expr): # XXX: Catching TypeError like this is a bad way of distinguishing # instances from classes. The logic using this function should be # rewritten somehow. try: expr = expr() except TypeError: return expr return expr def enumerate_states(*args, **options): """ Returns instances of the given state with dummy indices appended Operates in two different modes: 1. Two arguments are passed to it. The first is the base state which is to be indexed, and the second argument is a list of indices to append. 2. Three arguments are passed. The first is again the base state to be indexed. The second is the start index for counting. The final argument is the number of kets you wish to receive. Tries to call state._enumerate_state. If this fails, returns an empty list Parameters ========== args : list See list of operation modes above for explanation Examples ======== >>> from sympy.physics.quantum.cartesian import XBra, XKet >>> from sympy.physics.quantum.represent import enumerate_states >>> test = XKet('foo') >>> enumerate_states(test, 1, 3) [|foo_1>, |foo_2>, |foo_3>] >>> test2 = XBra('bar') >>> enumerate_states(test2, [4, 5, 10]) [>> from sympy.physics.quantum.sho1d import RaisingOp >>> from sympy.physics.quantum import Dagger >>> ad = RaisingOp('a') >>> ad.rewrite('xp').doit() sqrt(2)*(m*omega*X - I*Px)/(2*sqrt(hbar)*sqrt(m*omega)) >>> Dagger(ad) a Taking the commutator of a^dagger with other Operators: >>> from sympy.physics.quantum import Commutator >>> from sympy.physics.quantum.sho1d import RaisingOp, LoweringOp >>> from sympy.physics.quantum.sho1d import NumberOp >>> ad = RaisingOp('a') >>> a = LoweringOp('a') >>> N = NumberOp('N') >>> Commutator(ad, a).doit() -1 >>> Commutator(ad, N).doit() -RaisingOp(a) Apply a^dagger to a state: >>> from sympy.physics.quantum import qapply >>> from sympy.physics.quantum.sho1d import RaisingOp, SHOKet >>> ad = RaisingOp('a') >>> k = SHOKet('k') >>> qapply(ad*k) sqrt(k + 1)*|k + 1> Matrix Representation >>> from sympy.physics.quantum.sho1d import RaisingOp >>> from sympy.physics.quantum.represent import represent >>> ad = RaisingOp('a') >>> represent(ad, basis=N, ndim=4, format='sympy') Matrix([ [0, 0, 0, 0], [1, 0, 0, 0], [0, sqrt(2), 0, 0], [0, 0, sqrt(3), 0]]) """ def _eval_rewrite_as_xp(self, *args, **kwargs): return (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*( Integer(-1)*I*Px + m*omega*X) def _eval_adjoint(self): return LoweringOp(*self.args) def _eval_commutator_LoweringOp(self, other): return Integer(-1) def _eval_commutator_NumberOp(self, other): return Integer(-1)*self def _apply_operator_SHOKet(self, ket): temp = ket.n + Integer(1) return sqrt(temp)*SHOKet(temp) def _represent_default_basis(self, **options): return self._represent_NumberOp(None, **options) def _represent_XOp(self, basis, **options): # This logic is good but the underlying position # representation logic is broken. # temp = self.rewrite('xp').doit() # result = represent(temp, basis=X) # return result raise NotImplementedError('Position representation is not implemented') def _represent_NumberOp(self, basis, **options): ndim_info = options.get('ndim', 4) format = options.get('format','sympy') matrix = matrix_zeros(ndim_info, ndim_info, **options) for i in range(ndim_info - 1): value = sqrt(i + 1) if format == 'scipy.sparse': value = float(value) matrix[i + 1, i] = value if format == 'scipy.sparse': matrix = matrix.tocsr() return matrix #-------------------------------------------------------------------------- # Printing Methods #-------------------------------------------------------------------------- def _print_contents(self, printer, *args): arg0 = printer._print(self.args[0], *args) return '%s(%s)' % (self.__class__.__name__, arg0) def _print_contents_pretty(self, printer, *args): from sympy.printing.pretty.stringpict import prettyForm pform = printer._print(self.args[0], *args) pform = pform**prettyForm('\N{DAGGER}') return pform def _print_contents_latex(self, printer, *args): arg = printer._print(self.args[0]) return '%s^{\\dagger}' % arg class LoweringOp(SHOOp): """The Lowering Operator or 'a'. When 'a' acts on a state it lowers the state up by one. Taking the adjoint of 'a' returns a^dagger, the Raising Operator. 'a' can be rewritten in terms of position and momentum. We can represent 'a' as a matrix, which will be its default basis. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the operator. Examples ======== Create a Lowering Operator and rewrite it in terms of position and momentum, and show that taking its adjoint returns a^dagger: >>> from sympy.physics.quantum.sho1d import LoweringOp >>> from sympy.physics.quantum import Dagger >>> a = LoweringOp('a') >>> a.rewrite('xp').doit() sqrt(2)*(m*omega*X + I*Px)/(2*sqrt(hbar)*sqrt(m*omega)) >>> Dagger(a) RaisingOp(a) Taking the commutator of 'a' with other Operators: >>> from sympy.physics.quantum import Commutator >>> from sympy.physics.quantum.sho1d import LoweringOp, RaisingOp >>> from sympy.physics.quantum.sho1d import NumberOp >>> a = LoweringOp('a') >>> ad = RaisingOp('a') >>> N = NumberOp('N') >>> Commutator(a, ad).doit() 1 >>> Commutator(a, N).doit() a Apply 'a' to a state: >>> from sympy.physics.quantum import qapply >>> from sympy.physics.quantum.sho1d import LoweringOp, SHOKet >>> a = LoweringOp('a') >>> k = SHOKet('k') >>> qapply(a*k) sqrt(k)*|k - 1> Taking 'a' of the lowest state will return 0: >>> from sympy.physics.quantum import qapply >>> from sympy.physics.quantum.sho1d import LoweringOp, SHOKet >>> a = LoweringOp('a') >>> k = SHOKet(0) >>> qapply(a*k) 0 Matrix Representation >>> from sympy.physics.quantum.sho1d import LoweringOp >>> from sympy.physics.quantum.represent import represent >>> a = LoweringOp('a') >>> represent(a, basis=N, ndim=4, format='sympy') Matrix([ [0, 1, 0, 0], [0, 0, sqrt(2), 0], [0, 0, 0, sqrt(3)], [0, 0, 0, 0]]) """ def _eval_rewrite_as_xp(self, *args, **kwargs): return (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*( I*Px + m*omega*X) def _eval_adjoint(self): return RaisingOp(*self.args) def _eval_commutator_RaisingOp(self, other): return Integer(1) def _eval_commutator_NumberOp(self, other): return Integer(1)*self def _apply_operator_SHOKet(self, ket): temp = ket.n - Integer(1) if ket.n == Integer(0): return Integer(0) else: return sqrt(ket.n)*SHOKet(temp) def _represent_default_basis(self, **options): return self._represent_NumberOp(None, **options) def _represent_XOp(self, basis, **options): # This logic is good but the underlying position # representation logic is broken. # temp = self.rewrite('xp').doit() # result = represent(temp, basis=X) # return result raise NotImplementedError('Position representation is not implemented') def _represent_NumberOp(self, basis, **options): ndim_info = options.get('ndim', 4) format = options.get('format', 'sympy') matrix = matrix_zeros(ndim_info, ndim_info, **options) for i in range(ndim_info - 1): value = sqrt(i + 1) if format == 'scipy.sparse': value = float(value) matrix[i,i + 1] = value if format == 'scipy.sparse': matrix = matrix.tocsr() return matrix class NumberOp(SHOOp): """The Number Operator is simply a^dagger*a It is often useful to write a^dagger*a as simply the Number Operator because the Number Operator commutes with the Hamiltonian. And can be expressed using the Number Operator. Also the Number Operator can be applied to states. We can represent the Number Operator as a matrix, which will be its default basis. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the operator. Examples ======== Create a Number Operator and rewrite it in terms of the ladder operators, position and momentum operators, and Hamiltonian: >>> from sympy.physics.quantum.sho1d import NumberOp >>> N = NumberOp('N') >>> N.rewrite('a').doit() RaisingOp(a)*a >>> N.rewrite('xp').doit() -1/2 + (m**2*omega**2*X**2 + Px**2)/(2*hbar*m*omega) >>> N.rewrite('H').doit() -1/2 + H/(hbar*omega) Take the Commutator of the Number Operator with other Operators: >>> from sympy.physics.quantum import Commutator >>> from sympy.physics.quantum.sho1d import NumberOp, Hamiltonian >>> from sympy.physics.quantum.sho1d import RaisingOp, LoweringOp >>> N = NumberOp('N') >>> H = Hamiltonian('H') >>> ad = RaisingOp('a') >>> a = LoweringOp('a') >>> Commutator(N,H).doit() 0 >>> Commutator(N,ad).doit() RaisingOp(a) >>> Commutator(N,a).doit() -a Apply the Number Operator to a state: >>> from sympy.physics.quantum import qapply >>> from sympy.physics.quantum.sho1d import NumberOp, SHOKet >>> N = NumberOp('N') >>> k = SHOKet('k') >>> qapply(N*k) k*|k> Matrix Representation >>> from sympy.physics.quantum.sho1d import NumberOp >>> from sympy.physics.quantum.represent import represent >>> N = NumberOp('N') >>> represent(N, basis=N, ndim=4, format='sympy') Matrix([ [0, 0, 0, 0], [0, 1, 0, 0], [0, 0, 2, 0], [0, 0, 0, 3]]) """ def _eval_rewrite_as_a(self, *args, **kwargs): return ad*a def _eval_rewrite_as_xp(self, *args, **kwargs): return (Integer(1)/(Integer(2)*m*hbar*omega))*(Px**2 + ( m*omega*X)**2) - Integer(1)/Integer(2) def _eval_rewrite_as_H(self, *args, **kwargs): return H/(hbar*omega) - Integer(1)/Integer(2) def _apply_operator_SHOKet(self, ket): return ket.n*ket def _eval_commutator_Hamiltonian(self, other): return Integer(0) def _eval_commutator_RaisingOp(self, other): return other def _eval_commutator_LoweringOp(self, other): return Integer(-1)*other def _represent_default_basis(self, **options): return self._represent_NumberOp(None, **options) def _represent_XOp(self, basis, **options): # This logic is good but the underlying position # representation logic is broken. # temp = self.rewrite('xp').doit() # result = represent(temp, basis=X) # return result raise NotImplementedError('Position representation is not implemented') def _represent_NumberOp(self, basis, **options): ndim_info = options.get('ndim', 4) format = options.get('format', 'sympy') matrix = matrix_zeros(ndim_info, ndim_info, **options) for i in range(ndim_info): value = i if format == 'scipy.sparse': value = float(value) matrix[i,i] = value if format == 'scipy.sparse': matrix = matrix.tocsr() return matrix class Hamiltonian(SHOOp): """The Hamiltonian Operator. The Hamiltonian is used to solve the time-independent Schrodinger equation. The Hamiltonian can be expressed using the ladder operators, as well as by position and momentum. We can represent the Hamiltonian Operator as a matrix, which will be its default basis. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the operator. Examples ======== Create a Hamiltonian Operator and rewrite it in terms of the ladder operators, position and momentum, and the Number Operator: >>> from sympy.physics.quantum.sho1d import Hamiltonian >>> H = Hamiltonian('H') >>> H.rewrite('a').doit() hbar*omega*(1/2 + RaisingOp(a)*a) >>> H.rewrite('xp').doit() (m**2*omega**2*X**2 + Px**2)/(2*m) >>> H.rewrite('N').doit() hbar*omega*(1/2 + N) Take the Commutator of the Hamiltonian and the Number Operator: >>> from sympy.physics.quantum import Commutator >>> from sympy.physics.quantum.sho1d import Hamiltonian, NumberOp >>> H = Hamiltonian('H') >>> N = NumberOp('N') >>> Commutator(H,N).doit() 0 Apply the Hamiltonian Operator to a state: >>> from sympy.physics.quantum import qapply >>> from sympy.physics.quantum.sho1d import Hamiltonian, SHOKet >>> H = Hamiltonian('H') >>> k = SHOKet('k') >>> qapply(H*k) hbar*k*omega*|k> + hbar*omega*|k>/2 Matrix Representation >>> from sympy.physics.quantum.sho1d import Hamiltonian >>> from sympy.physics.quantum.represent import represent >>> H = Hamiltonian('H') >>> represent(H, basis=N, ndim=4, format='sympy') Matrix([ [hbar*omega/2, 0, 0, 0], [ 0, 3*hbar*omega/2, 0, 0], [ 0, 0, 5*hbar*omega/2, 0], [ 0, 0, 0, 7*hbar*omega/2]]) """ def _eval_rewrite_as_a(self, *args, **kwargs): return hbar*omega*(ad*a + Integer(1)/Integer(2)) def _eval_rewrite_as_xp(self, *args, **kwargs): return (Integer(1)/(Integer(2)*m))*(Px**2 + (m*omega*X)**2) def _eval_rewrite_as_N(self, *args, **kwargs): return hbar*omega*(N + Integer(1)/Integer(2)) def _apply_operator_SHOKet(self, ket): return (hbar*omega*(ket.n + Integer(1)/Integer(2)))*ket def _eval_commutator_NumberOp(self, other): return Integer(0) def _represent_default_basis(self, **options): return self._represent_NumberOp(None, **options) def _represent_XOp(self, basis, **options): # This logic is good but the underlying position # representation logic is broken. # temp = self.rewrite('xp').doit() # result = represent(temp, basis=X) # return result raise NotImplementedError('Position representation is not implemented') def _represent_NumberOp(self, basis, **options): ndim_info = options.get('ndim', 4) format = options.get('format', 'sympy') matrix = matrix_zeros(ndim_info, ndim_info, **options) for i in range(ndim_info): value = i + Integer(1)/Integer(2) if format == 'scipy.sparse': value = float(value) matrix[i,i] = value if format == 'scipy.sparse': matrix = matrix.tocsr() return hbar*omega*matrix #------------------------------------------------------------------------------ class SHOState(State): """State class for SHO states""" @classmethod def _eval_hilbert_space(cls, label): return ComplexSpace(S.Infinity) @property def n(self): return self.args[0] class SHOKet(SHOState, Ket): """1D eigenket. Inherits from SHOState and Ket. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the ket This is usually its quantum numbers or its symbol. Examples ======== Ket's know about their associated bra: >>> from sympy.physics.quantum.sho1d import SHOKet >>> k = SHOKet('k') >>> k.dual >> k.dual_class() Take the Inner Product with a bra: >>> from sympy.physics.quantum import InnerProduct >>> from sympy.physics.quantum.sho1d import SHOKet, SHOBra >>> k = SHOKet('k') >>> b = SHOBra('b') >>> InnerProduct(b,k).doit() KroneckerDelta(b, k) Vector representation of a numerical state ket: >>> from sympy.physics.quantum.sho1d import SHOKet, NumberOp >>> from sympy.physics.quantum.represent import represent >>> k = SHOKet(3) >>> N = NumberOp('N') >>> represent(k, basis=N, ndim=4) Matrix([ [0], [0], [0], [1]]) """ @classmethod def dual_class(self): return SHOBra def _eval_innerproduct_SHOBra(self, bra, **hints): result = KroneckerDelta(self.n, bra.n) return result def _represent_default_basis(self, **options): return self._represent_NumberOp(None, **options) def _represent_NumberOp(self, basis, **options): ndim_info = options.get('ndim', 4) format = options.get('format', 'sympy') options['spmatrix'] = 'lil' vector = matrix_zeros(ndim_info, 1, **options) if isinstance(self.n, Integer): if self.n >= ndim_info: return ValueError("N-Dimension too small") if format == 'scipy.sparse': vector[int(self.n), 0] = 1.0 vector = vector.tocsr() elif format == 'numpy': vector[int(self.n), 0] = 1.0 else: vector[self.n, 0] = Integer(1) return vector else: return ValueError("Not Numerical State") class SHOBra(SHOState, Bra): """A time-independent Bra in SHO. Inherits from SHOState and Bra. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the ket This is usually its quantum numbers or its symbol. Examples ======== Bra's know about their associated ket: >>> from sympy.physics.quantum.sho1d import SHOBra >>> b = SHOBra('b') >>> b.dual |b> >>> b.dual_class() Vector representation of a numerical state bra: >>> from sympy.physics.quantum.sho1d import SHOBra, NumberOp >>> from sympy.physics.quantum.represent import represent >>> b = SHOBra(3) >>> N = NumberOp('N') >>> represent(b, basis=N, ndim=4) Matrix([[0, 0, 0, 1]]) """ @classmethod def dual_class(self): return SHOKet def _represent_default_basis(self, **options): return self._represent_NumberOp(None, **options) def _represent_NumberOp(self, basis, **options): ndim_info = options.get('ndim', 4) format = options.get('format', 'sympy') options['spmatrix'] = 'lil' vector = matrix_zeros(1, ndim_info, **options) if isinstance(self.n, Integer): if self.n >= ndim_info: return ValueError("N-Dimension too small") if format == 'scipy.sparse': vector[0, int(self.n)] = 1.0 vector = vector.tocsr() elif format == 'numpy': vector[0, int(self.n)] = 1.0 else: vector[0, self.n] = Integer(1) return vector else: return ValueError("Not Numerical State") ad = RaisingOp('a') a = LoweringOp('a') H = Hamiltonian('H') N = NumberOp('N') omega = Symbol('omega') m = Symbol('m') sympy-sympy-1.9/sympy/physics/quantum/shor.py000066400000000000000000000123731412543434000216130ustar00rootroot00000000000000"""Shor's algorithm and helper functions. Todo: * Get the CMod gate working again using the new Gate API. * Fix everything. * Update docstrings and reformat. """ import math import random from sympy import Mul, S from sympy import log, sqrt from sympy.core.numbers import igcd from sympy.ntheory import continued_fraction_periodic as continued_fraction from sympy.utilities.iterables import variations from sympy.physics.quantum.gate import Gate from sympy.physics.quantum.qubit import Qubit, measure_partial_oneshot from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qft import QFT from sympy.physics.quantum.qexpr import QuantumError class OrderFindingException(QuantumError): pass class CMod(Gate): """A controlled mod gate. This is black box controlled Mod function for use by shor's algorithm. TODO: implement a decompose property that returns how to do this in terms of elementary gates """ @classmethod def _eval_args(cls, args): # t = args[0] # a = args[1] # N = args[2] raise NotImplementedError('The CMod gate has not been completed.') @property def t(self): """Size of 1/2 input register. First 1/2 holds output.""" return self.label[0] @property def a(self): """Base of the controlled mod function.""" return self.label[1] @property def N(self): """N is the type of modular arithmetic we are doing.""" return self.label[2] def _apply_operator_Qubit(self, qubits, **options): """ This directly calculates the controlled mod of the second half of the register and puts it in the second This will look pretty when we get Tensor Symbolically working """ n = 1 k = 0 # Determine the value stored in high memory. for i in range(self.t): k += n*qubits[self.t + i] n *= 2 # The value to go in low memory will be out. out = int(self.a**k % self.N) # Create array for new qbit-ket which will have high memory unaffected outarray = list(qubits.args[0][:self.t]) # Place out in low memory for i in reversed(range(self.t)): outarray.append((out >> i) & 1) return Qubit(*outarray) def shor(N): """This function implements Shor's factoring algorithm on the Integer N The algorithm starts by picking a random number (a) and seeing if it is coprime with N. If it isn't, then the gcd of the two numbers is a factor and we are done. Otherwise, it begins the period_finding subroutine which finds the period of a in modulo N arithmetic. This period, if even, can be used to calculate factors by taking a**(r/2)-1 and a**(r/2)+1. These values are returned. """ a = random.randrange(N - 2) + 2 if igcd(N, a) != 1: return igcd(N, a) r = period_find(a, N) if r % 2 == 1: shor(N) answer = (igcd(a**(r/2) - 1, N), igcd(a**(r/2) + 1, N)) return answer def getr(x, y, N): fraction = continued_fraction(x, y) # Now convert into r total = ratioize(fraction, N) return total def ratioize(list, N): if list[0] > N: return S.Zero if len(list) == 1: return list[0] return list[0] + ratioize(list[1:], N) def period_find(a, N): """Finds the period of a in modulo N arithmetic This is quantum part of Shor's algorithm. It takes two registers, puts first in superposition of states with Hadamards so: ``|k>|0>`` with k being all possible choices. It then does a controlled mod and a QFT to determine the order of a. """ epsilon = .5 # picks out t's such that maintains accuracy within epsilon t = int(2*math.ceil(log(N, 2))) # make the first half of register be 0's |000...000> start = [0 for x in range(t)] # Put second half into superposition of states so we have |1>x|0> + |2>x|0> + ... |k>x>|0> + ... + |2**n-1>x|0> factor = 1/sqrt(2**t) qubits = 0 for arr in variations(range(2), t, repetition=True): qbitArray = arr + start qubits = qubits + Qubit(*qbitArray) circuit = (factor*qubits).expand() # Controlled second half of register so that we have: # |1>x|a**1 %N> + |2>x|a**2 %N> + ... + |k>x|a**k %N >+ ... + |2**n-1=k>x|a**k % n> circuit = CMod(t, a, N)*circuit # will measure first half of register giving one of the a**k%N's circuit = qapply(circuit) for i in range(t): circuit = measure_partial_oneshot(circuit, i) # Now apply Inverse Quantum Fourier Transform on the second half of the register circuit = qapply(QFT(t, t*2).decompose()*circuit, floatingPoint=True) for i in range(t): circuit = measure_partial_oneshot(circuit, i + t) if isinstance(circuit, Qubit): register = circuit elif isinstance(circuit, Mul): register = circuit.args[-1] else: register = circuit.args[-1].args[-1] n = 1 answer = 0 for i in range(len(register)/2): answer += n*register[i + t] n = n << 1 if answer == 0: raise OrderFindingException( "Order finder returned 0. Happens with chance %f" % epsilon) #turn answer into r using continued fractions g = getr(answer, 2**t, N) return g sympy-sympy-1.9/sympy/physics/quantum/spin.py000066400000000000000000002161211412543434000216060ustar00rootroot00000000000000"""Quantum mechanical angular momemtum.""" from sympy import (Add, binomial, cos, exp, Expr, factorial, I, Integer, Mul, pi, Rational, S, sin, simplify, sqrt, Sum, symbols, sympify, Tuple, Dummy) from sympy.matrices import zeros from sympy.printing.pretty.stringpict import prettyForm, stringPict from sympy.printing.pretty.pretty_symbology import pretty_symbol from sympy.physics.quantum.qexpr import QExpr from sympy.physics.quantum.operator import (HermitianOperator, Operator, UnitaryOperator) from sympy.physics.quantum.state import Bra, Ket, State from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.physics.quantum.constants import hbar from sympy.physics.quantum.hilbert import ComplexSpace, DirectSumHilbertSpace from sympy.physics.quantum.tensorproduct import TensorProduct from sympy.physics.quantum.cg import CG from sympy.physics.quantum.qapply import qapply __all__ = [ 'm_values', 'Jplus', 'Jminus', 'Jx', 'Jy', 'Jz', 'J2', 'Rotation', 'WignerD', 'JxKet', 'JxBra', 'JyKet', 'JyBra', 'JzKet', 'JzBra', 'JzOp', 'J2Op', 'JxKetCoupled', 'JxBraCoupled', 'JyKetCoupled', 'JyBraCoupled', 'JzKetCoupled', 'JzBraCoupled', 'couple', 'uncouple' ] def m_values(j): j = sympify(j) size = 2*j + 1 if not size.is_Integer or not size > 0: raise ValueError( 'Only integer or half-integer values allowed for j, got: : %r' % j ) return size, [j - i for i in range(int(2*j + 1))] #----------------------------------------------------------------------------- # Spin Operators #----------------------------------------------------------------------------- class SpinOpBase: """Base class for spin operators.""" @classmethod def _eval_hilbert_space(cls, label): # We consider all j values so our space is infinite. return ComplexSpace(S.Infinity) @property def name(self): return self.args[0] def _print_contents(self, printer, *args): return '%s%s' % (self.name, self._coord) def _print_contents_pretty(self, printer, *args): a = stringPict(str(self.name)) b = stringPict(self._coord) return self._print_subscript_pretty(a, b) def _print_contents_latex(self, printer, *args): return r'%s_%s' % ((self.name, self._coord)) def _represent_base(self, basis, **options): j = options.get('j', S.Half) size, mvals = m_values(j) result = zeros(size, size) for p in range(size): for q in range(size): me = self.matrix_element(j, mvals[p], j, mvals[q]) result[p, q] = me return result def _apply_op(self, ket, orig_basis, **options): state = ket.rewrite(self.basis) # If the state has only one term if isinstance(state, State): ret = (hbar*state.m)*state # state is a linear combination of states elif isinstance(state, Sum): ret = self._apply_operator_Sum(state, **options) else: ret = qapply(self*state) if ret == self*state: raise NotImplementedError return ret.rewrite(orig_basis) def _apply_operator_JxKet(self, ket, **options): return self._apply_op(ket, 'Jx', **options) def _apply_operator_JxKetCoupled(self, ket, **options): return self._apply_op(ket, 'Jx', **options) def _apply_operator_JyKet(self, ket, **options): return self._apply_op(ket, 'Jy', **options) def _apply_operator_JyKetCoupled(self, ket, **options): return self._apply_op(ket, 'Jy', **options) def _apply_operator_JzKet(self, ket, **options): return self._apply_op(ket, 'Jz', **options) def _apply_operator_JzKetCoupled(self, ket, **options): return self._apply_op(ket, 'Jz', **options) def _apply_operator_TensorProduct(self, tp, **options): # Uncoupling operator is only easily found for coordinate basis spin operators # TODO: add methods for uncoupling operators if not (isinstance(self, JxOp) or isinstance(self, JyOp) or isinstance(self, JzOp)): raise NotImplementedError result = [] for n in range(len(tp.args)): arg = [] arg.extend(tp.args[:n]) arg.append(self._apply_operator(tp.args[n])) arg.extend(tp.args[n + 1:]) result.append(tp.__class__(*arg)) return Add(*result).expand() # TODO: move this to qapply_Mul def _apply_operator_Sum(self, s, **options): new_func = qapply(self*s.function) if new_func == self*s.function: raise NotImplementedError return Sum(new_func, *s.limits) def _eval_trace(self, **options): #TODO: use options to use different j values #For now eval at default basis # is it efficient to represent each time # to do a trace? return self._represent_default_basis().trace() class JplusOp(SpinOpBase, Operator): """The J+ operator.""" _coord = '+' basis = 'Jz' def _eval_commutator_JminusOp(self, other): return 2*hbar*JzOp(self.name) def _apply_operator_JzKet(self, ket, **options): j = ket.j m = ket.m if m.is_Number and j.is_Number: if m >= j: return S.Zero return hbar*sqrt(j*(j + S.One) - m*(m + S.One))*JzKet(j, m + S.One) def _apply_operator_JzKetCoupled(self, ket, **options): j = ket.j m = ket.m jn = ket.jn coupling = ket.coupling if m.is_Number and j.is_Number: if m >= j: return S.Zero return hbar*sqrt(j*(j + S.One) - m*(m + S.One))*JzKetCoupled(j, m + S.One, jn, coupling) def matrix_element(self, j, m, jp, mp): result = hbar*sqrt(j*(j + S.One) - mp*(mp + S.One)) result *= KroneckerDelta(m, mp + 1) result *= KroneckerDelta(j, jp) return result def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JzOp(self, basis, **options): return self._represent_base(basis, **options) def _eval_rewrite_as_xyz(self, *args, **kwargs): return JxOp(args[0]) + I*JyOp(args[0]) class JminusOp(SpinOpBase, Operator): """The J- operator.""" _coord = '-' basis = 'Jz' def _apply_operator_JzKet(self, ket, **options): j = ket.j m = ket.m if m.is_Number and j.is_Number: if m <= -j: return S.Zero return hbar*sqrt(j*(j + S.One) - m*(m - S.One))*JzKet(j, m - S.One) def _apply_operator_JzKetCoupled(self, ket, **options): j = ket.j m = ket.m jn = ket.jn coupling = ket.coupling if m.is_Number and j.is_Number: if m <= -j: return S.Zero return hbar*sqrt(j*(j + S.One) - m*(m - S.One))*JzKetCoupled(j, m - S.One, jn, coupling) def matrix_element(self, j, m, jp, mp): result = hbar*sqrt(j*(j + S.One) - mp*(mp - S.One)) result *= KroneckerDelta(m, mp - 1) result *= KroneckerDelta(j, jp) return result def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JzOp(self, basis, **options): return self._represent_base(basis, **options) def _eval_rewrite_as_xyz(self, *args, **kwargs): return JxOp(args[0]) - I*JyOp(args[0]) class JxOp(SpinOpBase, HermitianOperator): """The Jx operator.""" _coord = 'x' basis = 'Jx' def _eval_commutator_JyOp(self, other): return I*hbar*JzOp(self.name) def _eval_commutator_JzOp(self, other): return -I*hbar*JyOp(self.name) def _apply_operator_JzKet(self, ket, **options): jp = JplusOp(self.name)._apply_operator_JzKet(ket, **options) jm = JminusOp(self.name)._apply_operator_JzKet(ket, **options) return (jp + jm)/Integer(2) def _apply_operator_JzKetCoupled(self, ket, **options): jp = JplusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) jm = JminusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) return (jp + jm)/Integer(2) def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JzOp(self, basis, **options): jp = JplusOp(self.name)._represent_JzOp(basis, **options) jm = JminusOp(self.name)._represent_JzOp(basis, **options) return (jp + jm)/Integer(2) def _eval_rewrite_as_plusminus(self, *args, **kwargs): return (JplusOp(args[0]) + JminusOp(args[0]))/2 class JyOp(SpinOpBase, HermitianOperator): """The Jy operator.""" _coord = 'y' basis = 'Jy' def _eval_commutator_JzOp(self, other): return I*hbar*JxOp(self.name) def _eval_commutator_JxOp(self, other): return -I*hbar*J2Op(self.name) def _apply_operator_JzKet(self, ket, **options): jp = JplusOp(self.name)._apply_operator_JzKet(ket, **options) jm = JminusOp(self.name)._apply_operator_JzKet(ket, **options) return (jp - jm)/(Integer(2)*I) def _apply_operator_JzKetCoupled(self, ket, **options): jp = JplusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) jm = JminusOp(self.name)._apply_operator_JzKetCoupled(ket, **options) return (jp - jm)/(Integer(2)*I) def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JzOp(self, basis, **options): jp = JplusOp(self.name)._represent_JzOp(basis, **options) jm = JminusOp(self.name)._represent_JzOp(basis, **options) return (jp - jm)/(Integer(2)*I) def _eval_rewrite_as_plusminus(self, *args, **kwargs): return (JplusOp(args[0]) - JminusOp(args[0]))/(2*I) class JzOp(SpinOpBase, HermitianOperator): """The Jz operator.""" _coord = 'z' basis = 'Jz' def _eval_commutator_JxOp(self, other): return I*hbar*JyOp(self.name) def _eval_commutator_JyOp(self, other): return -I*hbar*JxOp(self.name) def _eval_commutator_JplusOp(self, other): return hbar*JplusOp(self.name) def _eval_commutator_JminusOp(self, other): return -hbar*JminusOp(self.name) def matrix_element(self, j, m, jp, mp): result = hbar*mp result *= KroneckerDelta(m, mp) result *= KroneckerDelta(j, jp) return result def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JzOp(self, basis, **options): return self._represent_base(basis, **options) class J2Op(SpinOpBase, HermitianOperator): """The J^2 operator.""" _coord = '2' def _eval_commutator_JxOp(self, other): return S.Zero def _eval_commutator_JyOp(self, other): return S.Zero def _eval_commutator_JzOp(self, other): return S.Zero def _eval_commutator_JplusOp(self, other): return S.Zero def _eval_commutator_JminusOp(self, other): return S.Zero def _apply_operator_JxKet(self, ket, **options): j = ket.j return hbar**2*j*(j + 1)*ket def _apply_operator_JxKetCoupled(self, ket, **options): j = ket.j return hbar**2*j*(j + 1)*ket def _apply_operator_JyKet(self, ket, **options): j = ket.j return hbar**2*j*(j + 1)*ket def _apply_operator_JyKetCoupled(self, ket, **options): j = ket.j return hbar**2*j*(j + 1)*ket def _apply_operator_JzKet(self, ket, **options): j = ket.j return hbar**2*j*(j + 1)*ket def _apply_operator_JzKetCoupled(self, ket, **options): j = ket.j return hbar**2*j*(j + 1)*ket def matrix_element(self, j, m, jp, mp): result = (hbar**2)*j*(j + 1) result *= KroneckerDelta(m, mp) result *= KroneckerDelta(j, jp) return result def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JzOp(self, basis, **options): return self._represent_base(basis, **options) def _print_contents_pretty(self, printer, *args): a = prettyForm(str(self.name)) b = prettyForm('2') return a**b def _print_contents_latex(self, printer, *args): return r'%s^2' % str(self.name) def _eval_rewrite_as_xyz(self, *args, **kwargs): return JxOp(args[0])**2 + JyOp(args[0])**2 + JzOp(args[0])**2 def _eval_rewrite_as_plusminus(self, *args, **kwargs): a = args[0] return JzOp(a)**2 + \ S.Half*(JplusOp(a)*JminusOp(a) + JminusOp(a)*JplusOp(a)) class Rotation(UnitaryOperator): """Wigner D operator in terms of Euler angles. Defines the rotation operator in terms of the Euler angles defined by the z-y-z convention for a passive transformation. That is the coordinate axes are rotated first about the z-axis, giving the new x'-y'-z' axes. Then this new coordinate system is rotated about the new y'-axis, giving new x''-y''-z'' axes. Then this new coordinate system is rotated about the z''-axis. Conventions follow those laid out in [1]_. Parameters ========== alpha : Number, Symbol First Euler Angle beta : Number, Symbol Second Euler angle gamma : Number, Symbol Third Euler angle Examples ======== A simple example rotation operator: >>> from sympy import pi >>> from sympy.physics.quantum.spin import Rotation >>> Rotation(pi, 0, pi/2) R(pi,0,pi/2) With symbolic Euler angles and calculating the inverse rotation operator: >>> from sympy import symbols >>> a, b, c = symbols('a b c') >>> Rotation(a, b, c) R(a,b,c) >>> Rotation(a, b, c).inverse() R(-c,-b,-a) See Also ======== WignerD: Symbolic Wigner-D function D: Wigner-D function d: Wigner small-d function References ========== .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. """ @classmethod def _eval_args(cls, args): args = QExpr._eval_args(args) if len(args) != 3: raise ValueError('3 Euler angles required, got: %r' % args) return args @classmethod def _eval_hilbert_space(cls, label): # We consider all j values so our space is infinite. return ComplexSpace(S.Infinity) @property def alpha(self): return self.label[0] @property def beta(self): return self.label[1] @property def gamma(self): return self.label[2] def _print_operator_name(self, printer, *args): return 'R' def _print_operator_name_pretty(self, printer, *args): if printer._use_unicode: return prettyForm('\N{SCRIPT CAPITAL R}' + ' ') else: return prettyForm("R ") def _print_operator_name_latex(self, printer, *args): return r'\mathcal{R}' def _eval_inverse(self): return Rotation(-self.gamma, -self.beta, -self.alpha) @classmethod def D(cls, j, m, mp, alpha, beta, gamma): """Wigner D-function. Returns an instance of the WignerD class corresponding to the Wigner-D function specified by the parameters. Parameters =========== j : Number Total angular momentum m : Number Eigenvalue of angular momentum along axis after rotation mp : Number Eigenvalue of angular momentum along rotated axis alpha : Number, Symbol First Euler angle of rotation beta : Number, Symbol Second Euler angle of rotation gamma : Number, Symbol Third Euler angle of rotation Examples ======== Return the Wigner-D matrix element for a defined rotation, both numerical and symbolic: >>> from sympy.physics.quantum.spin import Rotation >>> from sympy import pi, symbols >>> alpha, beta, gamma = symbols('alpha beta gamma') >>> Rotation.D(1, 1, 0,pi, pi/2,-pi) WignerD(1, 1, 0, pi, pi/2, -pi) See Also ======== WignerD: Symbolic Wigner-D function """ return WignerD(j, m, mp, alpha, beta, gamma) @classmethod def d(cls, j, m, mp, beta): """Wigner small-d function. Returns an instance of the WignerD class corresponding to the Wigner-D function specified by the parameters with the alpha and gamma angles given as 0. Parameters =========== j : Number Total angular momentum m : Number Eigenvalue of angular momentum along axis after rotation mp : Number Eigenvalue of angular momentum along rotated axis beta : Number, Symbol Second Euler angle of rotation Examples ======== Return the Wigner-D matrix element for a defined rotation, both numerical and symbolic: >>> from sympy.physics.quantum.spin import Rotation >>> from sympy import pi, symbols >>> beta = symbols('beta') >>> Rotation.d(1, 1, 0, pi/2) WignerD(1, 1, 0, 0, pi/2, 0) See Also ======== WignerD: Symbolic Wigner-D function """ return WignerD(j, m, mp, 0, beta, 0) def matrix_element(self, j, m, jp, mp): result = self.__class__.D( jp, m, mp, self.alpha, self.beta, self.gamma ) result *= KroneckerDelta(j, jp) return result def _represent_base(self, basis, **options): j = sympify(options.get('j', S.Half)) # TODO: move evaluation up to represent function/implement elsewhere evaluate = sympify(options.get('doit')) size, mvals = m_values(j) result = zeros(size, size) for p in range(size): for q in range(size): me = self.matrix_element(j, mvals[p], j, mvals[q]) if evaluate: result[p, q] = me.doit() else: result[p, q] = me return result def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JzOp(self, basis, **options): return self._represent_base(basis, **options) def _apply_operator_uncoupled(self, state, ket, *, dummy=True, **options): a = self.alpha b = self.beta g = self.gamma j = ket.j m = ket.m if j.is_number: s = [] size = m_values(j) sz = size[1] for mp in sz: r = Rotation.D(j, m, mp, a, b, g) z = r.doit() s.append(z*state(j, mp)) return Add(*s) else: if dummy: mp = Dummy('mp') else: mp = symbols('mp') return Sum(Rotation.D(j, m, mp, a, b, g)*state(j, mp), (mp, -j, j)) def _apply_operator_JxKet(self, ket, **options): return self._apply_operator_uncoupled(JxKet, ket, **options) def _apply_operator_JyKet(self, ket, **options): return self._apply_operator_uncoupled(JyKet, ket, **options) def _apply_operator_JzKet(self, ket, **options): return self._apply_operator_uncoupled(JzKet, ket, **options) def _apply_operator_coupled(self, state, ket, *, dummy=True, **options): a = self.alpha b = self.beta g = self.gamma j = ket.j m = ket.m jn = ket.jn coupling = ket.coupling if j.is_number: s = [] size = m_values(j) sz = size[1] for mp in sz: r = Rotation.D(j, m, mp, a, b, g) z = r.doit() s.append(z*state(j, mp, jn, coupling)) return Add(*s) else: if dummy: mp = Dummy('mp') else: mp = symbols('mp') return Sum(Rotation.D(j, m, mp, a, b, g)*state( j, mp, jn, coupling), (mp, -j, j)) def _apply_operator_JxKetCoupled(self, ket, **options): return self._apply_operator_coupled(JxKetCoupled, ket, **options) def _apply_operator_JyKetCoupled(self, ket, **options): return self._apply_operator_coupled(JyKetCoupled, ket, **options) def _apply_operator_JzKetCoupled(self, ket, **options): return self._apply_operator_coupled(JzKetCoupled, ket, **options) class WignerD(Expr): r"""Wigner-D function The Wigner D-function gives the matrix elements of the rotation operator in the jm-representation. For the Euler angles `\alpha`, `\beta`, `\gamma`, the D-function is defined such that: .. math :: = \delta_{jj'} D(j, m, m', \alpha, \beta, \gamma) Where the rotation operator is as defined by the Rotation class [1]_. The Wigner D-function defined in this way gives: .. math :: D(j, m, m', \alpha, \beta, \gamma) = e^{-i m \alpha} d(j, m, m', \beta) e^{-i m' \gamma} Where d is the Wigner small-d function, which is given by Rotation.d. The Wigner small-d function gives the component of the Wigner D-function that is determined by the second Euler angle. That is the Wigner D-function is: .. math :: D(j, m, m', \alpha, \beta, \gamma) = e^{-i m \alpha} d(j, m, m', \beta) e^{-i m' \gamma} Where d is the small-d function. The Wigner D-function is given by Rotation.D. Note that to evaluate the D-function, the j, m and mp parameters must be integer or half integer numbers. Parameters ========== j : Number Total angular momentum m : Number Eigenvalue of angular momentum along axis after rotation mp : Number Eigenvalue of angular momentum along rotated axis alpha : Number, Symbol First Euler angle of rotation beta : Number, Symbol Second Euler angle of rotation gamma : Number, Symbol Third Euler angle of rotation Examples ======== Evaluate the Wigner-D matrix elements of a simple rotation: >>> from sympy.physics.quantum.spin import Rotation >>> from sympy import pi >>> rot = Rotation.D(1, 1, 0, pi, pi/2, 0) >>> rot WignerD(1, 1, 0, pi, pi/2, 0) >>> rot.doit() sqrt(2)/2 Evaluate the Wigner-d matrix elements of a simple rotation >>> rot = Rotation.d(1, 1, 0, pi/2) >>> rot WignerD(1, 1, 0, 0, pi/2, 0) >>> rot.doit() -sqrt(2)/2 See Also ======== Rotation: Rotation operator References ========== .. [1] Varshalovich, D A, Quantum Theory of Angular Momentum. 1988. """ is_commutative = True def __new__(cls, *args, **hints): if not len(args) == 6: raise ValueError('6 parameters expected, got %s' % args) args = sympify(args) evaluate = hints.get('evaluate', False) if evaluate: return Expr.__new__(cls, *args)._eval_wignerd() return Expr.__new__(cls, *args) @property def j(self): return self.args[0] @property def m(self): return self.args[1] @property def mp(self): return self.args[2] @property def alpha(self): return self.args[3] @property def beta(self): return self.args[4] @property def gamma(self): return self.args[5] def _latex(self, printer, *args): if self.alpha == 0 and self.gamma == 0: return r'd^{%s}_{%s,%s}\left(%s\right)' % \ ( printer._print(self.j), printer._print( self.m), printer._print(self.mp), printer._print(self.beta) ) return r'D^{%s}_{%s,%s}\left(%s,%s,%s\right)' % \ ( printer._print( self.j), printer._print(self.m), printer._print(self.mp), printer._print(self.alpha), printer._print(self.beta), printer._print(self.gamma) ) def _pretty(self, printer, *args): top = printer._print(self.j) bot = printer._print(self.m) bot = prettyForm(*bot.right(',')) bot = prettyForm(*bot.right(printer._print(self.mp))) pad = max(top.width(), bot.width()) top = prettyForm(*top.left(' ')) bot = prettyForm(*bot.left(' ')) if pad > top.width(): top = prettyForm(*top.right(' '*(pad - top.width()))) if pad > bot.width(): bot = prettyForm(*bot.right(' '*(pad - bot.width()))) if self.alpha == 0 and self.gamma == 0: args = printer._print(self.beta) s = stringPict('d' + ' '*pad) else: args = printer._print(self.alpha) args = prettyForm(*args.right(',')) args = prettyForm(*args.right(printer._print(self.beta))) args = prettyForm(*args.right(',')) args = prettyForm(*args.right(printer._print(self.gamma))) s = stringPict('D' + ' '*pad) args = prettyForm(*args.parens()) s = prettyForm(*s.above(top)) s = prettyForm(*s.below(bot)) s = prettyForm(*s.right(args)) return s def doit(self, **hints): hints['evaluate'] = True return WignerD(*self.args, **hints) def _eval_wignerd(self): j = sympify(self.j) m = sympify(self.m) mp = sympify(self.mp) alpha = sympify(self.alpha) beta = sympify(self.beta) gamma = sympify(self.gamma) if alpha == 0 and beta == 0 and gamma == 0: return KroneckerDelta(m, mp) if not j.is_number: raise ValueError( 'j parameter must be numerical to evaluate, got %s' % j) r = 0 if beta == pi/2: # Varshalovich Equation (5), Section 4.16, page 113, setting # alpha=gamma=0. for k in range(2*j + 1): if k > j + mp or k > j - m or k < mp - m: continue r += (S.NegativeOne)**k*binomial(j + mp, k)*binomial(j - mp, k + m - mp) r *= (S.NegativeOne)**(m - mp) / 2**j*sqrt(factorial(j + m) * factorial(j - m) / (factorial(j + mp)*factorial(j - mp))) else: # Varshalovich Equation(5), Section 4.7.2, page 87, where we set # beta1=beta2=pi/2, and we get alpha=gamma=pi/2 and beta=phi+pi, # then we use the Eq. (1), Section 4.4. page 79, to simplify: # d(j, m, mp, beta+pi) = (-1)**(j-mp)*d(j, m, -mp, beta) # This happens to be almost the same as in Eq.(10), Section 4.16, # except that we need to substitute -mp for mp. size, mvals = m_values(j) for mpp in mvals: r += Rotation.d(j, m, mpp, pi/2).doit()*(cos(-mpp*beta) + I*sin(-mpp*beta))*\ Rotation.d(j, mpp, -mp, pi/2).doit() # Empirical normalization factor so results match Varshalovich # Tables 4.3-4.12 # Note that this exact normalization does not follow from the # above equations r = r*I**(2*j - m - mp)*(-1)**(2*m) # Finally, simplify the whole expression r = simplify(r) r *= exp(-I*m*alpha)*exp(-I*mp*gamma) return r Jx = JxOp('J') Jy = JyOp('J') Jz = JzOp('J') J2 = J2Op('J') Jplus = JplusOp('J') Jminus = JminusOp('J') #----------------------------------------------------------------------------- # Spin States #----------------------------------------------------------------------------- class SpinState(State): """Base class for angular momentum states.""" _label_separator = ',' def __new__(cls, j, m): j = sympify(j) m = sympify(m) if j.is_number: if 2*j != int(2*j): raise ValueError( 'j must be integer or half-integer, got: %s' % j) if j < 0: raise ValueError('j must be >= 0, got: %s' % j) if m.is_number: if 2*m != int(2*m): raise ValueError( 'm must be integer or half-integer, got: %s' % m) if j.is_number and m.is_number: if abs(m) > j: raise ValueError('Allowed values for m are -j <= m <= j, got j, m: %s, %s' % (j, m)) if int(j - m) != j - m: raise ValueError('Both j and m must be integer or half-integer, got j, m: %s, %s' % (j, m)) return State.__new__(cls, j, m) @property def j(self): return self.label[0] @property def m(self): return self.label[1] @classmethod def _eval_hilbert_space(cls, label): return ComplexSpace(2*label[0] + 1) def _represent_base(self, **options): j = self.j m = self.m alpha = sympify(options.get('alpha', 0)) beta = sympify(options.get('beta', 0)) gamma = sympify(options.get('gamma', 0)) size, mvals = m_values(j) result = zeros(size, 1) # breaks finding angles on L930 for p, mval in enumerate(mvals): if m.is_number: result[p, 0] = Rotation.D( self.j, mval, self.m, alpha, beta, gamma).doit() else: result[p, 0] = Rotation.D(self.j, mval, self.m, alpha, beta, gamma) return result def _eval_rewrite_as_Jx(self, *args, **options): if isinstance(self, Bra): return self._rewrite_basis(Jx, JxBra, **options) return self._rewrite_basis(Jx, JxKet, **options) def _eval_rewrite_as_Jy(self, *args, **options): if isinstance(self, Bra): return self._rewrite_basis(Jy, JyBra, **options) return self._rewrite_basis(Jy, JyKet, **options) def _eval_rewrite_as_Jz(self, *args, **options): if isinstance(self, Bra): return self._rewrite_basis(Jz, JzBra, **options) return self._rewrite_basis(Jz, JzKet, **options) def _rewrite_basis(self, basis, evect, **options): from sympy.physics.quantum.represent import represent j = self.j args = self.args[2:] if j.is_number: if isinstance(self, CoupledSpinState): if j == int(j): start = j**2 else: start = (2*j - 1)*(2*j + 1)/4 else: start = 0 vect = represent(self, basis=basis, **options) result = Add( *[vect[start + i]*evect(j, j - i, *args) for i in range(2*j + 1)]) if isinstance(self, CoupledSpinState) and options.get('coupled') is False: return uncouple(result) return result else: i = 0 mi = symbols('mi') # make sure not to introduce a symbol already in the state while self.subs(mi, 0) != self: i += 1 mi = symbols('mi%d' % i) break # TODO: better way to get angles of rotation if isinstance(self, CoupledSpinState): test_args = (0, mi, (0, 0)) else: test_args = (0, mi) if isinstance(self, Ket): angles = represent( self.__class__(*test_args), basis=basis)[0].args[3:6] else: angles = represent(self.__class__( *test_args), basis=basis)[0].args[0].args[3:6] if angles == (0, 0, 0): return self else: state = evect(j, mi, *args) lt = Rotation.D(j, mi, self.m, *angles) return Sum(lt*state, (mi, -j, j)) def _eval_innerproduct_JxBra(self, bra, **hints): result = KroneckerDelta(self.j, bra.j) if bra.dual_class() is not self.__class__: result *= self._represent_JxOp(None)[bra.j - bra.m] else: result *= KroneckerDelta( self.j, bra.j)*KroneckerDelta(self.m, bra.m) return result def _eval_innerproduct_JyBra(self, bra, **hints): result = KroneckerDelta(self.j, bra.j) if bra.dual_class() is not self.__class__: result *= self._represent_JyOp(None)[bra.j - bra.m] else: result *= KroneckerDelta( self.j, bra.j)*KroneckerDelta(self.m, bra.m) return result def _eval_innerproduct_JzBra(self, bra, **hints): result = KroneckerDelta(self.j, bra.j) if bra.dual_class() is not self.__class__: result *= self._represent_JzOp(None)[bra.j - bra.m] else: result *= KroneckerDelta( self.j, bra.j)*KroneckerDelta(self.m, bra.m) return result def _eval_trace(self, bra, **hints): # One way to implement this method is to assume the basis set k is # passed. # Then we can apply the discrete form of Trace formula here # Tr(|i> #then we do qapply() on each each inner product and sum over them. # OR # Inner product of |i>>> from sympy.physics.quantum.spin import JzKet, JxKet >>> from sympy import symbols >>> JzKet(1, 0) |1,0> >>> j, m = symbols('j m') >>> JzKet(j, m) |j,m> Rewriting the JzKet in terms of eigenkets of the Jx operator: Note: that the resulting eigenstates are JxKet's >>> JzKet(1,1).rewrite("Jx") |1,-1>/2 - sqrt(2)*|1,0>/2 + |1,1>/2 Get the vector representation of a state in terms of the basis elements of the Jx operator: >>> from sympy.physics.quantum.represent import represent >>> from sympy.physics.quantum.spin import Jx, Jz >>> represent(JzKet(1,-1), basis=Jx) Matrix([ [ 1/2], [sqrt(2)/2], [ 1/2]]) Apply innerproducts between states: >>> from sympy.physics.quantum.innerproduct import InnerProduct >>> from sympy.physics.quantum.spin import JxBra >>> i = InnerProduct(JxBra(1,1), JzKet(1,1)) >>> i <1,1|1,1> >>> i.doit() 1/2 *Uncoupled States:* Define an uncoupled state as a TensorProduct between two Jz eigenkets: >>> from sympy.physics.quantum.tensorproduct import TensorProduct >>> j1,m1,j2,m2 = symbols('j1 m1 j2 m2') >>> TensorProduct(JzKet(1,0), JzKet(1,1)) |1,0>x|1,1> >>> TensorProduct(JzKet(j1,m1), JzKet(j2,m2)) |j1,m1>x|j2,m2> A TensorProduct can be rewritten, in which case the eigenstates that make up the tensor product is rewritten to the new basis: >>> TensorProduct(JzKet(1,1),JxKet(1,1)).rewrite('Jz') |1,1>x|1,-1>/2 + sqrt(2)*|1,1>x|1,0>/2 + |1,1>x|1,1>/2 The represent method for TensorProduct's gives the vector representation of the state. Note that the state in the product basis is the equivalent of the tensor product of the vector representation of the component eigenstates: >>> represent(TensorProduct(JzKet(1,0),JzKet(1,1))) Matrix([ [0], [0], [0], [1], [0], [0], [0], [0], [0]]) >>> represent(TensorProduct(JzKet(1,1),JxKet(1,1)), basis=Jz) Matrix([ [ 1/2], [sqrt(2)/2], [ 1/2], [ 0], [ 0], [ 0], [ 0], [ 0], [ 0]]) See Also ======== JzKetCoupled: Coupled eigenstates sympy.physics.quantum.tensorproduct.TensorProduct: Used to specify uncoupled states uncouple: Uncouples states given coupling parameters couple: Couples uncoupled states """ @classmethod def dual_class(self): return JzBra @classmethod def coupled_class(self): return JzKetCoupled def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JxOp(self, basis, **options): return self._represent_base(beta=pi*Rational(3, 2), **options) def _represent_JyOp(self, basis, **options): return self._represent_base(alpha=pi*Rational(3, 2), beta=pi/2, gamma=pi/2, **options) def _represent_JzOp(self, basis, **options): return self._represent_base(**options) class JzBra(SpinState, Bra): """Eigenbra of Jz. See the JzKet for the usage of spin eigenstates. See Also ======== JzKet: Usage of spin states """ @classmethod def dual_class(self): return JzKet @classmethod def coupled_class(self): return JzBraCoupled # Method used primarily to create coupled_n and coupled_jn by __new__ in # CoupledSpinState # This same method is also used by the uncouple method, and is separated from # the CoupledSpinState class to maintain consistency in defining coupling def _build_coupled(jcoupling, length): n_list = [ [n + 1] for n in range(length) ] coupled_jn = [] coupled_n = [] for n1, n2, j_new in jcoupling: coupled_jn.append(j_new) coupled_n.append( (n_list[n1 - 1], n_list[n2 - 1]) ) n_sort = sorted(n_list[n1 - 1] + n_list[n2 - 1]) n_list[n_sort[0] - 1] = n_sort return coupled_n, coupled_jn class CoupledSpinState(SpinState): """Base class for coupled angular momentum states.""" def __new__(cls, j, m, jn, *jcoupling): # Check j and m values using SpinState SpinState(j, m) # Build and check coupling scheme from arguments if len(jcoupling) == 0: # Use default coupling scheme jcoupling = [] for n in range(2, len(jn)): jcoupling.append( (1, n, Add(*[jn[i] for i in range(n)])) ) jcoupling.append( (1, len(jn), j) ) elif len(jcoupling) == 1: # Use specified coupling scheme jcoupling = jcoupling[0] else: raise TypeError("CoupledSpinState only takes 3 or 4 arguments, got: %s" % (len(jcoupling) + 3) ) # Check arguments have correct form if not (isinstance(jn, list) or isinstance(jn, tuple) or isinstance(jn, Tuple)): raise TypeError('jn must be Tuple, list or tuple, got %s' % jn.__class__.__name__) if not (isinstance(jcoupling, list) or isinstance(jcoupling, tuple) or isinstance(jcoupling, Tuple)): raise TypeError('jcoupling must be Tuple, list or tuple, got %s' % jcoupling.__class__.__name__) if not all(isinstance(term, list) or isinstance(term, tuple) or isinstance(term, Tuple) for term in jcoupling): raise TypeError( 'All elements of jcoupling must be list, tuple or Tuple') if not len(jn) - 1 == len(jcoupling): raise ValueError('jcoupling must have length of %d, got %d' % (len(jn) - 1, len(jcoupling))) if not all(len(x) == 3 for x in jcoupling): raise ValueError('All elements of jcoupling must have length 3') # Build sympified args j = sympify(j) m = sympify(m) jn = Tuple( *[sympify(ji) for ji in jn] ) jcoupling = Tuple( *[Tuple(sympify( n1), sympify(n2), sympify(ji)) for (n1, n2, ji) in jcoupling] ) # Check values in coupling scheme give physical state if any(2*ji != int(2*ji) for ji in jn if ji.is_number): raise ValueError('All elements of jn must be integer or half-integer, got: %s' % jn) if any(n1 != int(n1) or n2 != int(n2) for (n1, n2, _) in jcoupling): raise ValueError('Indices in jcoupling must be integers') if any(n1 < 1 or n2 < 1 or n1 > len(jn) or n2 > len(jn) for (n1, n2, _) in jcoupling): raise ValueError('Indices must be between 1 and the number of coupled spin spaces') if any(2*ji != int(2*ji) for (_, _, ji) in jcoupling if ji.is_number): raise ValueError('All coupled j values in coupling scheme must be integer or half-integer') coupled_n, coupled_jn = _build_coupled(jcoupling, len(jn)) jvals = list(jn) for n, (n1, n2) in enumerate(coupled_n): j1 = jvals[min(n1) - 1] j2 = jvals[min(n2) - 1] j3 = coupled_jn[n] if sympify(j1).is_number and sympify(j2).is_number and sympify(j3).is_number: if j1 + j2 < j3: raise ValueError('All couplings must have j1+j2 >= j3, ' 'in coupling number %d got j1,j2,j3: %d,%d,%d' % (n + 1, j1, j2, j3)) if abs(j1 - j2) > j3: raise ValueError("All couplings must have |j1+j2| <= j3, " "in coupling number %d got j1,j2,j3: %d,%d,%d" % (n + 1, j1, j2, j3)) if int(j1 + j2) == j1 + j2: pass jvals[min(n1 + n2) - 1] = j3 if len(jcoupling) > 0 and jcoupling[-1][2] != j: raise ValueError('Last j value coupled together must be the final j of the state') # Return state return State.__new__(cls, j, m, jn, jcoupling) def _print_label(self, printer, *args): label = [printer._print(self.j), printer._print(self.m)] for i, ji in enumerate(self.jn, start=1): label.append('j%d=%s' % ( i, printer._print(ji) )) for jn, (n1, n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): label.append('j(%s)=%s' % ( ','.join(str(i) for i in sorted(n1 + n2)), printer._print(jn) )) return ','.join(label) def _print_label_pretty(self, printer, *args): label = [self.j, self.m] for i, ji in enumerate(self.jn, start=1): symb = 'j%d' % i symb = pretty_symbol(symb) symb = prettyForm(symb + '=') item = prettyForm(*symb.right(printer._print(ji))) label.append(item) for jn, (n1, n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): n = ','.join(pretty_symbol("j%d" % i)[-1] for i in sorted(n1 + n2)) symb = prettyForm('j' + n + '=') item = prettyForm(*symb.right(printer._print(jn))) label.append(item) return self._print_sequence_pretty( label, self._label_separator, printer, *args ) def _print_label_latex(self, printer, *args): label = [ printer._print(self.j, *args), printer._print(self.m, *args) ] for i, ji in enumerate(self.jn, start=1): label.append('j_{%d}=%s' % (i, printer._print(ji, *args)) ) for jn, (n1, n2) in zip(self.coupled_jn[:-1], self.coupled_n[:-1]): n = ','.join(str(i) for i in sorted(n1 + n2)) label.append('j_{%s}=%s' % (n, printer._print(jn, *args)) ) return self._label_separator.join(label) @property def jn(self): return self.label[2] @property def coupling(self): return self.label[3] @property def coupled_jn(self): return _build_coupled(self.label[3], len(self.label[2]))[1] @property def coupled_n(self): return _build_coupled(self.label[3], len(self.label[2]))[0] @classmethod def _eval_hilbert_space(cls, label): j = Add(*label[2]) if j.is_number: return DirectSumHilbertSpace(*[ ComplexSpace(x) for x in range(int(2*j + 1), 0, -2) ]) else: # TODO: Need hilbert space fix, see issue 5732 # Desired behavior: #ji = symbols('ji') #ret = Sum(ComplexSpace(2*ji + 1), (ji, 0, j)) # Temporary fix: return ComplexSpace(2*j + 1) def _represent_coupled_base(self, **options): evect = self.uncoupled_class() if not self.j.is_number: raise ValueError( 'State must not have symbolic j value to represent') if not self.hilbert_space.dimension.is_number: raise ValueError( 'State must not have symbolic j values to represent') result = zeros(self.hilbert_space.dimension, 1) if self.j == int(self.j): start = self.j**2 else: start = (2*self.j - 1)*(1 + 2*self.j)/4 result[start:start + 2*self.j + 1, 0] = evect( self.j, self.m)._represent_base(**options) return result def _eval_rewrite_as_Jx(self, *args, **options): if isinstance(self, Bra): return self._rewrite_basis(Jx, JxBraCoupled, **options) return self._rewrite_basis(Jx, JxKetCoupled, **options) def _eval_rewrite_as_Jy(self, *args, **options): if isinstance(self, Bra): return self._rewrite_basis(Jy, JyBraCoupled, **options) return self._rewrite_basis(Jy, JyKetCoupled, **options) def _eval_rewrite_as_Jz(self, *args, **options): if isinstance(self, Bra): return self._rewrite_basis(Jz, JzBraCoupled, **options) return self._rewrite_basis(Jz, JzKetCoupled, **options) class JxKetCoupled(CoupledSpinState, Ket): """Coupled eigenket of Jx. See JzKetCoupled for the usage of coupled spin eigenstates. See Also ======== JzKetCoupled: Usage of coupled spin states """ @classmethod def dual_class(self): return JxBraCoupled @classmethod def uncoupled_class(self): return JxKet def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JxOp(self, basis, **options): return self._represent_coupled_base(**options) def _represent_JyOp(self, basis, **options): return self._represent_coupled_base(alpha=pi*Rational(3, 2), **options) def _represent_JzOp(self, basis, **options): return self._represent_coupled_base(beta=pi/2, **options) class JxBraCoupled(CoupledSpinState, Bra): """Coupled eigenbra of Jx. See JzKetCoupled for the usage of coupled spin eigenstates. See Also ======== JzKetCoupled: Usage of coupled spin states """ @classmethod def dual_class(self): return JxKetCoupled @classmethod def uncoupled_class(self): return JxBra class JyKetCoupled(CoupledSpinState, Ket): """Coupled eigenket of Jy. See JzKetCoupled for the usage of coupled spin eigenstates. See Also ======== JzKetCoupled: Usage of coupled spin states """ @classmethod def dual_class(self): return JyBraCoupled @classmethod def uncoupled_class(self): return JyKet def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JxOp(self, basis, **options): return self._represent_coupled_base(gamma=pi/2, **options) def _represent_JyOp(self, basis, **options): return self._represent_coupled_base(**options) def _represent_JzOp(self, basis, **options): return self._represent_coupled_base(alpha=pi*Rational(3, 2), beta=-pi/2, gamma=pi/2, **options) class JyBraCoupled(CoupledSpinState, Bra): """Coupled eigenbra of Jy. See JzKetCoupled for the usage of coupled spin eigenstates. See Also ======== JzKetCoupled: Usage of coupled spin states """ @classmethod def dual_class(self): return JyKetCoupled @classmethod def uncoupled_class(self): return JyBra class JzKetCoupled(CoupledSpinState, Ket): r"""Coupled eigenket of Jz Spin state that is an eigenket of Jz which represents the coupling of separate spin spaces. The arguments for creating instances of JzKetCoupled are ``j``, ``m``, ``jn`` and an optional ``jcoupling`` argument. The ``j`` and ``m`` options are the total angular momentum quantum numbers, as used for normal states (e.g. JzKet). The other required parameter in ``jn``, which is a tuple defining the `j_n` angular momentum quantum numbers of the product spaces. So for example, if a state represented the coupling of the product basis state `\left|j_1,m_1\right\rangle\times\left|j_2,m_2\right\rangle`, the ``jn`` for this state would be ``(j1,j2)``. The final option is ``jcoupling``, which is used to define how the spaces specified by ``jn`` are coupled, which includes both the order these spaces are coupled together and the quantum numbers that arise from these couplings. The ``jcoupling`` parameter itself is a list of lists, such that each of the sublists defines a single coupling between the spin spaces. If there are N coupled angular momentum spaces, that is ``jn`` has N elements, then there must be N-1 sublists. Each of these sublists making up the ``jcoupling`` parameter have length 3. The first two elements are the indices of the product spaces that are considered to be coupled together. For example, if we want to couple `j_1` and `j_4`, the indices would be 1 and 4. If a state has already been coupled, it is referenced by the smallest index that is coupled, so if `j_2` and `j_4` has already been coupled to some `j_{24}`, then this value can be coupled by referencing it with index 2. The final element of the sublist is the quantum number of the coupled state. So putting everything together, into a valid sublist for ``jcoupling``, if `j_1` and `j_2` are coupled to an angular momentum space with quantum number `j_{12}` with the value ``j12``, the sublist would be ``(1,2,j12)``, N-1 of these sublists are used in the list for ``jcoupling``. Note the ``jcoupling`` parameter is optional, if it is not specified, the default coupling is taken. This default value is to coupled the spaces in order and take the quantum number of the coupling to be the maximum value. For example, if the spin spaces are `j_1`, `j_2`, `j_3`, `j_4`, then the default coupling couples `j_1` and `j_2` to `j_{12}=j_1+j_2`, then, `j_{12}` and `j_3` are coupled to `j_{123}=j_{12}+j_3`, and finally `j_{123}` and `j_4` to `j=j_{123}+j_4`. The jcoupling value that would correspond to this is: ``((1,2,j1+j2),(1,3,j1+j2+j3))`` Parameters ========== args : tuple The arguments that must be passed are ``j``, ``m``, ``jn``, and ``jcoupling``. The ``j`` value is the total angular momentum. The ``m`` value is the eigenvalue of the Jz spin operator. The ``jn`` list are the j values of argular momentum spaces coupled together. The ``jcoupling`` parameter is an optional parameter defining how the spaces are coupled together. See the above description for how these coupling parameters are defined. Examples ======== Defining simple spin states, both numerical and symbolic: >>> from sympy.physics.quantum.spin import JzKetCoupled >>> from sympy import symbols >>> JzKetCoupled(1, 0, (1, 1)) |1,0,j1=1,j2=1> >>> j, m, j1, j2 = symbols('j m j1 j2') >>> JzKetCoupled(j, m, (j1, j2)) |j,m,j1=j1,j2=j2> Defining coupled spin states for more than 2 coupled spaces with various coupling parameters: >>> JzKetCoupled(2, 1, (1, 1, 1)) |2,1,j1=1,j2=1,j3=1,j(1,2)=2> >>> JzKetCoupled(2, 1, (1, 1, 1), ((1,2,2),(1,3,2)) ) |2,1,j1=1,j2=1,j3=1,j(1,2)=2> >>> JzKetCoupled(2, 1, (1, 1, 1), ((2,3,1),(1,2,2)) ) |2,1,j1=1,j2=1,j3=1,j(2,3)=1> Rewriting the JzKetCoupled in terms of eigenkets of the Jx operator: Note: that the resulting eigenstates are JxKetCoupled >>> JzKetCoupled(1,1,(1,1)).rewrite("Jx") |1,-1,j1=1,j2=1>/2 - sqrt(2)*|1,0,j1=1,j2=1>/2 + |1,1,j1=1,j2=1>/2 The rewrite method can be used to convert a coupled state to an uncoupled state. This is done by passing coupled=False to the rewrite function: >>> JzKetCoupled(1, 0, (1, 1)).rewrite('Jz', coupled=False) -sqrt(2)*|1,-1>x|1,1>/2 + sqrt(2)*|1,1>x|1,-1>/2 Get the vector representation of a state in terms of the basis elements of the Jx operator: >>> from sympy.physics.quantum.represent import represent >>> from sympy.physics.quantum.spin import Jx >>> from sympy import S >>> represent(JzKetCoupled(1,-1,(S(1)/2,S(1)/2)), basis=Jx) Matrix([ [ 0], [ 1/2], [sqrt(2)/2], [ 1/2]]) See Also ======== JzKet: Normal spin eigenstates uncouple: Uncoupling of coupling spin states couple: Coupling of uncoupled spin states """ @classmethod def dual_class(self): return JzBraCoupled @classmethod def uncoupled_class(self): return JzKet def _represent_default_basis(self, **options): return self._represent_JzOp(None, **options) def _represent_JxOp(self, basis, **options): return self._represent_coupled_base(beta=pi*Rational(3, 2), **options) def _represent_JyOp(self, basis, **options): return self._represent_coupled_base(alpha=pi*Rational(3, 2), beta=pi/2, gamma=pi/2, **options) def _represent_JzOp(self, basis, **options): return self._represent_coupled_base(**options) class JzBraCoupled(CoupledSpinState, Bra): """Coupled eigenbra of Jz. See the JzKetCoupled for the usage of coupled spin eigenstates. See Also ======== JzKetCoupled: Usage of coupled spin states """ @classmethod def dual_class(self): return JzKetCoupled @classmethod def uncoupled_class(self): return JzBra #----------------------------------------------------------------------------- # Coupling/uncoupling #----------------------------------------------------------------------------- def couple(expr, jcoupling_list=None): """ Couple a tensor product of spin states This function can be used to couple an uncoupled tensor product of spin states. All of the eigenstates to be coupled must be of the same class. It will return a linear combination of eigenstates that are subclasses of CoupledSpinState determined by Clebsch-Gordan angular momentum coupling coefficients. Parameters ========== expr : Expr An expression involving TensorProducts of spin states to be coupled. Each state must be a subclass of SpinState and they all must be the same class. jcoupling_list : list or tuple Elements of this list are sub-lists of length 2 specifying the order of the coupling of the spin spaces. The length of this must be N-1, where N is the number of states in the tensor product to be coupled. The elements of this sublist are the same as the first two elements of each sublist in the ``jcoupling`` parameter defined for JzKetCoupled. If this parameter is not specified, the default value is taken, which couples the first and second product basis spaces, then couples this new coupled space to the third product space, etc Examples ======== Couple a tensor product of numerical states for two spaces: >>> from sympy.physics.quantum.spin import JzKet, couple >>> from sympy.physics.quantum.tensorproduct import TensorProduct >>> couple(TensorProduct(JzKet(1,0), JzKet(1,1))) -sqrt(2)*|1,1,j1=1,j2=1>/2 + sqrt(2)*|2,1,j1=1,j2=1>/2 Numerical coupling of three spaces using the default coupling method, i.e. first and second spaces couple, then this couples to the third space: >>> couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0))) sqrt(6)*|2,2,j1=1,j2=1,j3=1,j(1,2)=2>/3 + sqrt(3)*|3,2,j1=1,j2=1,j3=1,j(1,2)=2>/3 Perform this same coupling, but we define the coupling to first couple the first and third spaces: >>> couple(TensorProduct(JzKet(1,1), JzKet(1,1), JzKet(1,0)), ((1,3),(1,2)) ) sqrt(2)*|2,2,j1=1,j2=1,j3=1,j(1,3)=1>/2 - sqrt(6)*|2,2,j1=1,j2=1,j3=1,j(1,3)=2>/6 + sqrt(3)*|3,2,j1=1,j2=1,j3=1,j(1,3)=2>/3 Couple a tensor product of symbolic states: >>> from sympy import symbols >>> j1,m1,j2,m2 = symbols('j1 m1 j2 m2') >>> couple(TensorProduct(JzKet(j1,m1), JzKet(j2,m2))) Sum(CG(j1, m1, j2, m2, j, m1 + m2)*|j,m1 + m2,j1=j1,j2=j2>, (j, m1 + m2, j1 + j2)) """ a = expr.atoms(TensorProduct) for tp in a: # Allow other tensor products to be in expression if not all([ isinstance(state, SpinState) for state in tp.args]): continue # If tensor product has all spin states, raise error for invalid tensor product state if not all([state.__class__ is tp.args[0].__class__ for state in tp.args]): raise TypeError('All states must be the same basis') expr = expr.subs(tp, _couple(tp, jcoupling_list)) return expr def _couple(tp, jcoupling_list): states = tp.args coupled_evect = states[0].coupled_class() # Define default coupling if none is specified if jcoupling_list is None: jcoupling_list = [] for n in range(1, len(states)): jcoupling_list.append( (1, n + 1) ) # Check jcoupling_list valid if not len(jcoupling_list) == len(states) - 1: raise TypeError('jcoupling_list must be length %d, got %d' % (len(states) - 1, len(jcoupling_list))) if not all( len(coupling) == 2 for coupling in jcoupling_list): raise ValueError('Each coupling must define 2 spaces') if any([n1 == n2 for n1, n2 in jcoupling_list]): raise ValueError('Spin spaces cannot couple to themselves') if all([sympify(n1).is_number and sympify(n2).is_number for n1, n2 in jcoupling_list]): j_test = [0]*len(states) for n1, n2 in jcoupling_list: if j_test[n1 - 1] == -1 or j_test[n2 - 1] == -1: raise ValueError('Spaces coupling j_n\'s are referenced by smallest n value') j_test[max(n1, n2) - 1] = -1 # j values of states to be coupled together jn = [state.j for state in states] mn = [state.m for state in states] # Create coupling_list, which defines all the couplings between all # the spaces from jcoupling_list coupling_list = [] n_list = [ [i + 1] for i in range(len(states)) ] for j_coupling in jcoupling_list: # Least n for all j_n which is coupled as first and second spaces n1, n2 = j_coupling # List of all n's coupled in first and second spaces j1_n = list(n_list[n1 - 1]) j2_n = list(n_list[n2 - 1]) coupling_list.append( (j1_n, j2_n) ) # Set new j_n to be coupling of all j_n in both first and second spaces n_list[ min(n1, n2) - 1 ] = sorted(j1_n + j2_n) if all(state.j.is_number and state.m.is_number for state in states): # Numerical coupling # Iterate over difference between maximum possible j value of each coupling and the actual value diff_max = [ Add( *[ jn[n - 1] - mn[n - 1] for n in coupling[0] + coupling[1] ] ) for coupling in coupling_list ] result = [] for diff in range(diff_max[-1] + 1): # Determine available configurations n = len(coupling_list) tot = binomial(diff + n - 1, diff) for config_num in range(tot): diff_list = _confignum_to_difflist(config_num, diff, n) # Skip the configuration if non-physical # This is a lazy check for physical states given the loose restrictions of diff_max if any( [ d > m for d, m in zip(diff_list, diff_max) ] ): continue # Determine term cg_terms = [] coupled_j = list(jn) jcoupling = [] for (j1_n, j2_n), coupling_diff in zip(coupling_list, diff_list): j1 = coupled_j[ min(j1_n) - 1 ] j2 = coupled_j[ min(j2_n) - 1 ] j3 = j1 + j2 - coupling_diff coupled_j[ min(j1_n + j2_n) - 1 ] = j3 m1 = Add( *[ mn[x - 1] for x in j1_n] ) m2 = Add( *[ mn[x - 1] for x in j2_n] ) m3 = m1 + m2 cg_terms.append( (j1, m1, j2, m2, j3, m3) ) jcoupling.append( (min(j1_n), min(j2_n), j3) ) # Better checks that state is physical if any([ abs(term[5]) > term[4] for term in cg_terms ]): continue if any([ term[0] + term[2] < term[4] for term in cg_terms ]): continue if any([ abs(term[0] - term[2]) > term[4] for term in cg_terms ]): continue coeff = Mul( *[ CG(*term).doit() for term in cg_terms] ) state = coupled_evect(j3, m3, jn, jcoupling) result.append(coeff*state) return Add(*result) else: # Symbolic coupling cg_terms = [] jcoupling = [] sum_terms = [] coupled_j = list(jn) for j1_n, j2_n in coupling_list: j1 = coupled_j[ min(j1_n) - 1 ] j2 = coupled_j[ min(j2_n) - 1 ] if len(j1_n + j2_n) == len(states): j3 = symbols('j') else: j3_name = 'j' + ''.join(["%s" % n for n in j1_n + j2_n]) j3 = symbols(j3_name) coupled_j[ min(j1_n + j2_n) - 1 ] = j3 m1 = Add( *[ mn[x - 1] for x in j1_n] ) m2 = Add( *[ mn[x - 1] for x in j2_n] ) m3 = m1 + m2 cg_terms.append( (j1, m1, j2, m2, j3, m3) ) jcoupling.append( (min(j1_n), min(j2_n), j3) ) sum_terms.append((j3, m3, j1 + j2)) coeff = Mul( *[ CG(*term) for term in cg_terms] ) state = coupled_evect(j3, m3, jn, jcoupling) return Sum(coeff*state, *sum_terms) def uncouple(expr, jn=None, jcoupling_list=None): """ Uncouple a coupled spin state Gives the uncoupled representation of a coupled spin state. Arguments must be either a spin state that is a subclass of CoupledSpinState or a spin state that is a subclass of SpinState and an array giving the j values of the spaces that are to be coupled Parameters ========== expr : Expr The expression containing states that are to be coupled. If the states are a subclass of SpinState, the ``jn`` and ``jcoupling`` parameters must be defined. If the states are a subclass of CoupledSpinState, ``jn`` and ``jcoupling`` will be taken from the state. jn : list or tuple The list of the j-values that are coupled. If state is a CoupledSpinState, this parameter is ignored. This must be defined if state is not a subclass of CoupledSpinState. The syntax of this parameter is the same as the ``jn`` parameter of JzKetCoupled. jcoupling_list : list or tuple The list defining how the j-values are coupled together. If state is a CoupledSpinState, this parameter is ignored. This must be defined if state is not a subclass of CoupledSpinState. The syntax of this parameter is the same as the ``jcoupling`` parameter of JzKetCoupled. Examples ======== Uncouple a numerical state using a CoupledSpinState state: >>> from sympy.physics.quantum.spin import JzKetCoupled, uncouple >>> from sympy import S >>> uncouple(JzKetCoupled(1, 0, (S(1)/2, S(1)/2))) sqrt(2)*|1/2,-1/2>x|1/2,1/2>/2 + sqrt(2)*|1/2,1/2>x|1/2,-1/2>/2 Perform the same calculation using a SpinState state: >>> from sympy.physics.quantum.spin import JzKet >>> uncouple(JzKet(1, 0), (S(1)/2, S(1)/2)) sqrt(2)*|1/2,-1/2>x|1/2,1/2>/2 + sqrt(2)*|1/2,1/2>x|1/2,-1/2>/2 Uncouple a numerical state of three coupled spaces using a CoupledSpinState state: >>> uncouple(JzKetCoupled(1, 1, (1, 1, 1), ((1,3,1),(1,2,1)) )) |1,-1>x|1,1>x|1,1>/2 - |1,0>x|1,0>x|1,1>/2 + |1,1>x|1,0>x|1,0>/2 - |1,1>x|1,1>x|1,-1>/2 Perform the same calculation using a SpinState state: >>> uncouple(JzKet(1, 1), (1, 1, 1), ((1,3,1),(1,2,1)) ) |1,-1>x|1,1>x|1,1>/2 - |1,0>x|1,0>x|1,1>/2 + |1,1>x|1,0>x|1,0>/2 - |1,1>x|1,1>x|1,-1>/2 Uncouple a symbolic state using a CoupledSpinState state: >>> from sympy import symbols >>> j,m,j1,j2 = symbols('j m j1 j2') >>> uncouple(JzKetCoupled(j, m, (j1, j2))) Sum(CG(j1, m1, j2, m2, j, m)*|j1,m1>x|j2,m2>, (m1, -j1, j1), (m2, -j2, j2)) Perform the same calculation using a SpinState state >>> uncouple(JzKet(j, m), (j1, j2)) Sum(CG(j1, m1, j2, m2, j, m)*|j1,m1>x|j2,m2>, (m1, -j1, j1), (m2, -j2, j2)) """ a = expr.atoms(SpinState) for state in a: expr = expr.subs(state, _uncouple(state, jn, jcoupling_list)) return expr def _uncouple(state, jn, jcoupling_list): if isinstance(state, CoupledSpinState): jn = state.jn coupled_n = state.coupled_n coupled_jn = state.coupled_jn evect = state.uncoupled_class() elif isinstance(state, SpinState): if jn is None: raise ValueError("Must specify j-values for coupled state") if not (isinstance(jn, list) or isinstance(jn, tuple)): raise TypeError("jn must be list or tuple") if jcoupling_list is None: # Use default jcoupling_list = [] for i in range(1, len(jn)): jcoupling_list.append( (1, 1 + i, Add(*[jn[j] for j in range(i + 1)])) ) if not (isinstance(jcoupling_list, list) or isinstance(jcoupling_list, tuple)): raise TypeError("jcoupling must be a list or tuple") if not len(jcoupling_list) == len(jn) - 1: raise ValueError("Must specify 2 fewer coupling terms than the number of j values") coupled_n, coupled_jn = _build_coupled(jcoupling_list, len(jn)) evect = state.__class__ else: raise TypeError("state must be a spin state") j = state.j m = state.m coupling_list = [] j_list = list(jn) # Create coupling, which defines all the couplings between all the spaces for j3, (n1, n2) in zip(coupled_jn, coupled_n): # j's which are coupled as first and second spaces j1 = j_list[n1[0] - 1] j2 = j_list[n2[0] - 1] # Build coupling list coupling_list.append( (n1, n2, j1, j2, j3) ) # Set new value in j_list j_list[min(n1 + n2) - 1] = j3 if j.is_number and m.is_number: diff_max = [ 2*x for x in jn ] diff = Add(*jn) - m n = len(jn) tot = binomial(diff + n - 1, diff) result = [] for config_num in range(tot): diff_list = _confignum_to_difflist(config_num, diff, n) if any( [ d > p for d, p in zip(diff_list, diff_max) ] ): continue cg_terms = [] for coupling in coupling_list: j1_n, j2_n, j1, j2, j3 = coupling m1 = Add( *[ jn[x - 1] - diff_list[x - 1] for x in j1_n ] ) m2 = Add( *[ jn[x - 1] - diff_list[x - 1] for x in j2_n ] ) m3 = m1 + m2 cg_terms.append( (j1, m1, j2, m2, j3, m3) ) coeff = Mul( *[ CG(*term).doit() for term in cg_terms ] ) state = TensorProduct( *[ evect(j, j - d) for j, d in zip(jn, diff_list) ] ) result.append(coeff*state) return Add(*result) else: # Symbolic coupling m_str = "m1:%d" % (len(jn) + 1) mvals = symbols(m_str) cg_terms = [(j1, Add(*[mvals[n - 1] for n in j1_n]), j2, Add(*[mvals[n - 1] for n in j2_n]), j3, Add(*[mvals[n - 1] for n in j1_n + j2_n])) for j1_n, j2_n, j1, j2, j3 in coupling_list[:-1] ] cg_terms.append(*[(j1, Add(*[mvals[n - 1] for n in j1_n]), j2, Add(*[mvals[n - 1] for n in j2_n]), j, m) for j1_n, j2_n, j1, j2, j3 in [coupling_list[-1]] ]) cg_coeff = Mul(*[CG(*cg_term) for cg_term in cg_terms]) sum_terms = [ (m, -j, j) for j, m in zip(jn, mvals) ] state = TensorProduct( *[ evect(j, m) for j, m in zip(jn, mvals) ] ) return Sum(cg_coeff*state, *sum_terms) def _confignum_to_difflist(config_num, diff, list_len): # Determines configuration of diffs into list_len number of slots diff_list = [] for n in range(list_len): prev_diff = diff # Number of spots after current one rem_spots = list_len - n - 1 # Number of configurations of distributing diff among the remaining spots rem_configs = binomial(diff + rem_spots - 1, diff) while config_num >= rem_configs: config_num -= rem_configs diff -= 1 rem_configs = binomial(diff + rem_spots - 1, diff) diff_list.append(prev_diff - diff) return diff_list sympy-sympy-1.9/sympy/physics/quantum/state.py000066400000000000000000000733401412543434000217610ustar00rootroot00000000000000"""Dirac notation for states.""" from sympy import (cacheit, conjugate, Expr, Function, integrate, oo, sqrt, Tuple) from sympy.printing.pretty.stringpict import stringPict from sympy.physics.quantum.qexpr import QExpr, dispatch_method __all__ = [ 'KetBase', 'BraBase', 'StateBase', 'State', 'Ket', 'Bra', 'TimeDepState', 'TimeDepBra', 'TimeDepKet', 'OrthogonalKet', 'OrthogonalBra', 'OrthogonalState', 'Wavefunction' ] #----------------------------------------------------------------------------- # States, bras and kets. #----------------------------------------------------------------------------- # ASCII brackets _lbracket = "<" _rbracket = ">" _straight_bracket = "|" # Unicode brackets # MATHEMATICAL ANGLE BRACKETS _lbracket_ucode = "\N{MATHEMATICAL LEFT ANGLE BRACKET}" _rbracket_ucode = "\N{MATHEMATICAL RIGHT ANGLE BRACKET}" # LIGHT VERTICAL BAR _straight_bracket_ucode = "\N{LIGHT VERTICAL BAR}" # Other options for unicode printing of <, > and | for Dirac notation. # LEFT-POINTING ANGLE BRACKET # _lbracket = "\u2329" # _rbracket = "\u232A" # LEFT ANGLE BRACKET # _lbracket = "\u3008" # _rbracket = "\u3009" # VERTICAL LINE # _straight_bracket = "\u007C" class StateBase(QExpr): """Abstract base class for general abstract states in quantum mechanics. All other state classes defined will need to inherit from this class. It carries the basic structure for all other states such as dual, _eval_adjoint and label. This is an abstract base class and you should not instantiate it directly, instead use State. """ @classmethod def _operators_to_state(self, ops, **options): """ Returns the eigenstate instance for the passed operators. This method should be overridden in subclasses. It will handle being passed either an Operator instance or set of Operator instances. It should return the corresponding state INSTANCE or simply raise a NotImplementedError. See cartesian.py for an example. """ raise NotImplementedError("Cannot map operators to states in this class. Method not implemented!") def _state_to_operators(self, op_classes, **options): """ Returns the operators which this state instance is an eigenstate of. This method should be overridden in subclasses. It will be called on state instances and be passed the operator classes that we wish to make into instances. The state instance will then transform the classes appropriately, or raise a NotImplementedError if it cannot return operator instances. See cartesian.py for examples, """ raise NotImplementedError( "Cannot map this state to operators. Method not implemented!") @property def operators(self): """Return the operator(s) that this state is an eigenstate of""" from .operatorset import state_to_operators # import internally to avoid circular import errors return state_to_operators(self) def _enumerate_state(self, num_states, **options): raise NotImplementedError("Cannot enumerate this state!") def _represent_default_basis(self, **options): return self._represent(basis=self.operators) #------------------------------------------------------------------------- # Dagger/dual #------------------------------------------------------------------------- @property def dual(self): """Return the dual state of this one.""" return self.dual_class()._new_rawargs(self.hilbert_space, *self.args) @classmethod def dual_class(self): """Return the class used to construct the dual.""" raise NotImplementedError( 'dual_class must be implemented in a subclass' ) def _eval_adjoint(self): """Compute the dagger of this state using the dual.""" return self.dual #------------------------------------------------------------------------- # Printing #------------------------------------------------------------------------- def _pretty_brackets(self, height, use_unicode=True): # Return pretty printed brackets for the state # Ideally, this could be done by pform.parens but it does not support the angled < and > # Setup for unicode vs ascii if use_unicode: lbracket, rbracket = self.lbracket_ucode, self.rbracket_ucode slash, bslash, vert = '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT}', \ '\N{BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT}', \ '\N{BOX DRAWINGS LIGHT VERTICAL}' else: lbracket, rbracket = self.lbracket, self.rbracket slash, bslash, vert = '/', '\\', '|' # If height is 1, just return brackets if height == 1: return stringPict(lbracket), stringPict(rbracket) # Make height even height += (height % 2) brackets = [] for bracket in lbracket, rbracket: # Create left bracket if bracket in {_lbracket, _lbracket_ucode}: bracket_args = [ ' ' * (height//2 - i - 1) + slash for i in range(height // 2)] bracket_args.extend( [ ' ' * i + bslash for i in range(height // 2)]) # Create right bracket elif bracket in {_rbracket, _rbracket_ucode}: bracket_args = [ ' ' * i + bslash for i in range(height // 2)] bracket_args.extend([ ' ' * ( height//2 - i - 1) + slash for i in range(height // 2)]) # Create straight bracket elif bracket in {_straight_bracket, _straight_bracket_ucode}: bracket_args = [vert for i in range(height)] else: raise ValueError(bracket) brackets.append( stringPict('\n'.join(bracket_args), baseline=height//2)) return brackets def _sympystr(self, printer, *args): contents = self._print_contents(printer, *args) return '%s%s%s' % (self.lbracket, contents, self.rbracket) def _pretty(self, printer, *args): from sympy.printing.pretty.stringpict import prettyForm # Get brackets pform = self._print_contents_pretty(printer, *args) lbracket, rbracket = self._pretty_brackets( pform.height(), printer._use_unicode) # Put together state pform = prettyForm(*pform.left(lbracket)) pform = prettyForm(*pform.right(rbracket)) return pform def _latex(self, printer, *args): contents = self._print_contents_latex(printer, *args) # The extra {} brackets are needed to get matplotlib's latex # rendered to render this properly. return '{%s%s%s}' % (self.lbracket_latex, contents, self.rbracket_latex) class KetBase(StateBase): """Base class for Kets. This class defines the dual property and the brackets for printing. This is an abstract base class and you should not instantiate it directly, instead use Ket. """ lbracket = _straight_bracket rbracket = _rbracket lbracket_ucode = _straight_bracket_ucode rbracket_ucode = _rbracket_ucode lbracket_latex = r'\left|' rbracket_latex = r'\right\rangle ' @classmethod def default_args(self): return ("psi",) @classmethod def dual_class(self): return BraBase def __mul__(self, other): """KetBase*other""" from sympy.physics.quantum.operator import OuterProduct if isinstance(other, BraBase): return OuterProduct(self, other) else: return Expr.__mul__(self, other) def __rmul__(self, other): """other*KetBase""" from sympy.physics.quantum.innerproduct import InnerProduct if isinstance(other, BraBase): return InnerProduct(other, self) else: return Expr.__rmul__(self, other) #------------------------------------------------------------------------- # _eval_* methods #------------------------------------------------------------------------- def _eval_innerproduct(self, bra, **hints): """Evaluate the inner product between this ket and a bra. This is called to compute , where the ket is ``self``. This method will dispatch to sub-methods having the format:: ``def _eval_innerproduct_BraClass(self, **hints):`` Subclasses should define these methods (one for each BraClass) to teach the ket how to take inner products with bras. """ return dispatch_method(self, '_eval_innerproduct', bra, **hints) def _apply_operator(self, op, **options): """Apply an Operator to this Ket. This method will dispatch to methods having the format:: ``def _apply_operator_OperatorName(op, **options):`` Subclasses should define these methods (one for each OperatorName) to teach the Ket how operators act on it. Parameters ========== op : Operator The Operator that is acting on the Ket. options : dict A dict of key/value pairs that control how the operator is applied to the Ket. """ return dispatch_method(self, '_apply_operator', op, **options) class BraBase(StateBase): """Base class for Bras. This class defines the dual property and the brackets for printing. This is an abstract base class and you should not instantiate it directly, instead use Bra. """ lbracket = _lbracket rbracket = _straight_bracket lbracket_ucode = _lbracket_ucode rbracket_ucode = _straight_bracket_ucode lbracket_latex = r'\left\langle ' rbracket_latex = r'\right|' @classmethod def _operators_to_state(self, ops, **options): state = self.dual_class()._operators_to_state(ops, **options) return state.dual def _state_to_operators(self, op_classes, **options): return self.dual._state_to_operators(op_classes, **options) def _enumerate_state(self, num_states, **options): dual_states = self.dual._enumerate_state(num_states, **options) return [x.dual for x in dual_states] @classmethod def default_args(self): return self.dual_class().default_args() @classmethod def dual_class(self): return KetBase def __mul__(self, other): """BraBase*other""" from sympy.physics.quantum.innerproduct import InnerProduct if isinstance(other, KetBase): return InnerProduct(self, other) else: return Expr.__mul__(self, other) def __rmul__(self, other): """other*BraBase""" from sympy.physics.quantum.operator import OuterProduct if isinstance(other, KetBase): return OuterProduct(other, self) else: return Expr.__rmul__(self, other) def _represent(self, **options): """A default represent that uses the Ket's version.""" from sympy.physics.quantum.dagger import Dagger return Dagger(self.dual._represent(**options)) class State(StateBase): """General abstract quantum state used as a base class for Ket and Bra.""" pass class Ket(State, KetBase): """A general time-independent Ket in quantum mechanics. Inherits from State and KetBase. This class should be used as the base class for all physical, time-independent Kets in a system. This class and its subclasses will be the main classes that users will use for expressing Kets in Dirac notation [1]_. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the ket. This will usually be its symbol or its quantum numbers. For time-dependent state, this will include the time. Examples ======== Create a simple Ket and looking at its properties:: >>> from sympy.physics.quantum import Ket >>> from sympy import symbols, I >>> k = Ket('psi') >>> k |psi> >>> k.hilbert_space H >>> k.is_commutative False >>> k.label (psi,) Ket's know about their associated bra:: >>> k.dual >> k.dual_class() Take a linear combination of two kets:: >>> k0 = Ket(0) >>> k1 = Ket(1) >>> 2*I*k0 - 4*k1 2*I*|0> - 4*|1> Compound labels are passed as tuples:: >>> n, m = symbols('n,m') >>> k = Ket(n,m) >>> k |nm> References ========== .. [1] https://en.wikipedia.org/wiki/Bra-ket_notation """ @classmethod def dual_class(self): return Bra class Bra(State, BraBase): """A general time-independent Bra in quantum mechanics. Inherits from State and BraBase. A Bra is the dual of a Ket [1]_. This class and its subclasses will be the main classes that users will use for expressing Bras in Dirac notation. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the ket. This will usually be its symbol or its quantum numbers. For time-dependent state, this will include the time. Examples ======== Create a simple Bra and look at its properties:: >>> from sympy.physics.quantum import Bra >>> from sympy import symbols, I >>> b = Bra('psi') >>> b >> b.hilbert_space H >>> b.is_commutative False Bra's know about their dual Ket's:: >>> b.dual |psi> >>> b.dual_class() Like Kets, Bras can have compound labels and be manipulated in a similar manner:: >>> n, m = symbols('n,m') >>> b = Bra(n,m) - I*Bra(m,n) >>> b -I*>> b.subs(n,m) >> from sympy.physics.quantum import TimeDepKet >>> k = TimeDepKet('psi', 't') >>> k |psi;t> >>> k.time t >>> k.label (psi,) >>> k.hilbert_space H TimeDepKets know about their dual bra:: >>> k.dual >> k.dual_class() """ @classmethod def dual_class(self): return TimeDepBra class TimeDepBra(TimeDepState, BraBase): """General time-dependent Bra in quantum mechanics. This inherits from TimeDepState and BraBase and is the main class that should be used for Bras that vary with time. Its dual is a TimeDepBra. Parameters ========== args : tuple The list of numbers or parameters that uniquely specify the ket. This will usually be its symbol or its quantum numbers. For time-dependent state, this will include the time as the final argument. Examples ======== >>> from sympy.physics.quantum import TimeDepBra >>> b = TimeDepBra('psi', 't') >>> b >> b.time t >>> b.label (psi,) >>> b.hilbert_space H >>> b.dual |psi;t> """ @classmethod def dual_class(self): return TimeDepKet class OrthogonalState(State, StateBase): """General abstract quantum state used as a base class for Ket and Bra.""" pass class OrthogonalKet(OrthogonalState, KetBase): """Orthogonal Ket in quantum mechanics. The inner product of two states with different labels will give zero, states with the same label will give one. >>> from sympy.physics.quantum import OrthogonalBra, OrthogonalKet >>> from sympy.abc import m, n >>> (OrthogonalBra(n)*OrthogonalKet(n)).doit() 1 >>> (OrthogonalBra(n)*OrthogonalKet(n+1)).doit() 0 >>> (OrthogonalBra(n)*OrthogonalKet(m)).doit() """ @classmethod def dual_class(self): return OrthogonalBra def _eval_innerproduct(self, bra, **hints): if len(self.args) != len(bra.args): raise ValueError('Cannot multiply a ket that has a different number of labels.') for i in range(len(self.args)): diff = self.args[i] - bra.args[i] diff = diff.expand() if diff.is_zero is False: return 0 if diff.is_zero is None: return None return 1 class OrthogonalBra(OrthogonalState, BraBase): """Orthogonal Bra in quantum mechanics. """ @classmethod def dual_class(self): return OrthogonalKet class Wavefunction(Function): """Class for representations in continuous bases This class takes an expression and coordinates in its constructor. It can be used to easily calculate normalizations and probabilities. Parameters ========== expr : Expr The expression representing the functional form of the w.f. coords : Symbol or tuple The coordinates to be integrated over, and their bounds Examples ======== Particle in a box, specifying bounds in the more primitive way of using Piecewise: >>> from sympy import Symbol, Piecewise, pi, N >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction >>> x = Symbol('x', real=True) >>> n = 1 >>> L = 1 >>> g = Piecewise((0, x < 0), (0, x > L), (sqrt(2//L)*sin(n*pi*x/L), True)) >>> f = Wavefunction(g, x) >>> f.norm 1 >>> f.is_normalized True >>> p = f.prob() >>> p(0) 0 >>> p(L) 0 >>> p(0.5) 2 >>> p(0.85*L) 2*sin(0.85*pi)**2 >>> N(p(0.85*L)) 0.412214747707527 Additionally, you can specify the bounds of the function and the indices in a more compact way: >>> from sympy import symbols, pi, diff >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction >>> x, L = symbols('x,L', positive=True) >>> n = symbols('n', integer=True, positive=True) >>> g = sqrt(2/L)*sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.norm 1 >>> f(L+1) 0 >>> f(L-1) sqrt(2)*sin(pi*n*(L - 1)/L)/sqrt(L) >>> f(-1) 0 >>> f(0.85) sqrt(2)*sin(0.85*pi*n/L)/sqrt(L) >>> f(0.85, n=1, L=1) sqrt(2)*sin(0.85*pi) >>> f.is_commutative False All arguments are automatically sympified, so you can define the variables as strings rather than symbols: >>> expr = x**2 >>> f = Wavefunction(expr, 'x') >>> type(f.variables[0]) Derivatives of Wavefunctions will return Wavefunctions: >>> diff(f, x) Wavefunction(2*x, x) """ #Any passed tuples for coordinates and their bounds need to be #converted to Tuples before Function's constructor is called, to #avoid errors from calling is_Float in the constructor def __new__(cls, *args, **options): new_args = [None for i in args] ct = 0 for arg in args: if isinstance(arg, tuple): new_args[ct] = Tuple(*arg) else: new_args[ct] = arg ct += 1 return super().__new__(cls, *new_args, **options) def __call__(self, *args, **options): var = self.variables if len(args) != len(var): raise NotImplementedError( "Incorrect number of arguments to function!") ct = 0 #If the passed value is outside the specified bounds, return 0 for v in var: lower, upper = self.limits[v] #Do the comparison to limits only if the passed symbol is actually #a symbol present in the limits; #Had problems with a comparison of x > L if isinstance(args[ct], Expr) and \ not (lower in args[ct].free_symbols or upper in args[ct].free_symbols): continue if (args[ct] < lower) == True or (args[ct] > upper) == True: return 0 ct += 1 expr = self.expr #Allows user to make a call like f(2, 4, m=1, n=1) for symbol in list(expr.free_symbols): if str(symbol) in options.keys(): val = options[str(symbol)] expr = expr.subs(symbol, val) return expr.subs(zip(var, args)) def _eval_derivative(self, symbol): expr = self.expr deriv = expr._eval_derivative(symbol) return Wavefunction(deriv, *self.args[1:]) def _eval_conjugate(self): return Wavefunction(conjugate(self.expr), *self.args[1:]) def _eval_transpose(self): return self @property def free_symbols(self): return self.expr.free_symbols @property def is_commutative(self): """ Override Function's is_commutative so that order is preserved in represented expressions """ return False @classmethod def eval(self, *args): return None @property def variables(self): """ Return the coordinates which the wavefunction depends on Examples ======== >>> from sympy.physics.quantum.state import Wavefunction >>> from sympy import symbols >>> x,y = symbols('x,y') >>> f = Wavefunction(x*y, x, y) >>> f.variables (x, y) >>> g = Wavefunction(x*y, x) >>> g.variables (x,) """ var = [g[0] if isinstance(g, Tuple) else g for g in self._args[1:]] return tuple(var) @property def limits(self): """ Return the limits of the coordinates which the w.f. depends on If no limits are specified, defaults to ``(-oo, oo)``. Examples ======== >>> from sympy.physics.quantum.state import Wavefunction >>> from sympy import symbols >>> x, y = symbols('x, y') >>> f = Wavefunction(x**2, (x, 0, 1)) >>> f.limits {x: (0, 1)} >>> f = Wavefunction(x**2, x) >>> f.limits {x: (-oo, oo)} >>> f = Wavefunction(x**2 + y**2, x, (y, -1, 2)) >>> f.limits {x: (-oo, oo), y: (-1, 2)} """ limits = [(g[1], g[2]) if isinstance(g, Tuple) else (-oo, oo) for g in self._args[1:]] return dict(zip(self.variables, tuple(limits))) @property def expr(self): """ Return the expression which is the functional form of the Wavefunction Examples ======== >>> from sympy.physics.quantum.state import Wavefunction >>> from sympy import symbols >>> x, y = symbols('x, y') >>> f = Wavefunction(x**2, x) >>> f.expr x**2 """ return self._args[0] @property def is_normalized(self): """ Returns true if the Wavefunction is properly normalized Examples ======== >>> from sympy import symbols, pi >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction >>> x, L = symbols('x,L', positive=True) >>> n = symbols('n', integer=True, positive=True) >>> g = sqrt(2/L)*sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.is_normalized True """ return (self.norm == 1.0) @property # type: ignore @cacheit def norm(self): """ Return the normalization of the specified functional form. This function integrates over the coordinates of the Wavefunction, with the bounds specified. Examples ======== >>> from sympy import symbols, pi >>> from sympy.functions import sqrt, sin >>> from sympy.physics.quantum.state import Wavefunction >>> x, L = symbols('x,L', positive=True) >>> n = symbols('n', integer=True, positive=True) >>> g = sqrt(2/L)*sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.norm 1 >>> g = sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.norm sqrt(2)*sqrt(L)/2 """ exp = self.expr*conjugate(self.expr) var = self.variables limits = self.limits for v in var: curr_limits = limits[v] exp = integrate(exp, (v, curr_limits[0], curr_limits[1])) return sqrt(exp) def normalize(self): """ Return a normalized version of the Wavefunction Examples ======== >>> from sympy import symbols, pi >>> from sympy.functions import sin >>> from sympy.physics.quantum.state import Wavefunction >>> x = symbols('x', real=True) >>> L = symbols('L', positive=True) >>> n = symbols('n', integer=True, positive=True) >>> g = sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.normalize() Wavefunction(sqrt(2)*sin(pi*n*x/L)/sqrt(L), (x, 0, L)) """ const = self.norm if const is oo: raise NotImplementedError("The function is not normalizable!") else: return Wavefunction((const)**(-1)*self.expr, *self.args[1:]) def prob(self): r""" Return the absolute magnitude of the w.f., `|\psi(x)|^2` Examples ======== >>> from sympy import symbols, pi >>> from sympy.functions import sin >>> from sympy.physics.quantum.state import Wavefunction >>> x, L = symbols('x,L', real=True) >>> n = symbols('n', integer=True) >>> g = sin(n*pi*x/L) >>> f = Wavefunction(g, (x, 0, L)) >>> f.prob() Wavefunction(sin(pi*n*x/L)**2, x) """ return Wavefunction(self.expr*conjugate(self.expr), *self.variables) sympy-sympy-1.9/sympy/physics/quantum/tensorproduct.py000066400000000000000000000342221412543434000235500ustar00rootroot00000000000000"""Abstract tensor product.""" from sympy import Expr, Add, Mul, Matrix, Pow, sympify from sympy.core.trace import Tr from sympy.printing.pretty.stringpict import prettyForm from sympy.physics.quantum.qexpr import QuantumError from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.state import Ket, Bra from sympy.physics.quantum.matrixutils import ( numpy_ndarray, scipy_sparse_matrix, matrix_tensor_product ) __all__ = [ 'TensorProduct', 'tensor_product_simp' ] #----------------------------------------------------------------------------- # Tensor product #----------------------------------------------------------------------------- _combined_printing = False def combined_tensor_printing(combined): """Set flag controlling whether tensor products of states should be printed as a combined bra/ket or as an explicit tensor product of different bra/kets. This is a global setting for all TensorProduct class instances. Parameters ---------- combine : bool When true, tensor product states are combined into one ket/bra, and when false explicit tensor product notation is used between each ket/bra. """ global _combined_printing _combined_printing = combined class TensorProduct(Expr): """The tensor product of two or more arguments. For matrices, this uses ``matrix_tensor_product`` to compute the Kronecker or tensor product matrix. For other objects a symbolic ``TensorProduct`` instance is returned. The tensor product is a non-commutative multiplication that is used primarily with operators and states in quantum mechanics. Currently, the tensor product distinguishes between commutative and non-commutative arguments. Commutative arguments are assumed to be scalars and are pulled out in front of the ``TensorProduct``. Non-commutative arguments remain in the resulting ``TensorProduct``. Parameters ========== args : tuple A sequence of the objects to take the tensor product of. Examples ======== Start with a simple tensor product of sympy matrices:: >>> from sympy import Matrix >>> from sympy.physics.quantum import TensorProduct >>> m1 = Matrix([[1,2],[3,4]]) >>> m2 = Matrix([[1,0],[0,1]]) >>> TensorProduct(m1, m2) Matrix([ [1, 0, 2, 0], [0, 1, 0, 2], [3, 0, 4, 0], [0, 3, 0, 4]]) >>> TensorProduct(m2, m1) Matrix([ [1, 2, 0, 0], [3, 4, 0, 0], [0, 0, 1, 2], [0, 0, 3, 4]]) We can also construct tensor products of non-commutative symbols: >>> from sympy import Symbol >>> A = Symbol('A',commutative=False) >>> B = Symbol('B',commutative=False) >>> tp = TensorProduct(A, B) >>> tp AxB We can take the dagger of a tensor product (note the order does NOT reverse like the dagger of a normal product): >>> from sympy.physics.quantum import Dagger >>> Dagger(tp) Dagger(A)xDagger(B) Expand can be used to distribute a tensor product across addition: >>> C = Symbol('C',commutative=False) >>> tp = TensorProduct(A+B,C) >>> tp (A + B)xC >>> tp.expand(tensorproduct=True) AxC + BxC """ is_commutative = False def __new__(cls, *args): if isinstance(args[0], (Matrix, numpy_ndarray, scipy_sparse_matrix)): return matrix_tensor_product(*args) c_part, new_args = cls.flatten(sympify(args)) c_part = Mul(*c_part) if len(new_args) == 0: return c_part elif len(new_args) == 1: return c_part * new_args[0] else: tp = Expr.__new__(cls, *new_args) return c_part * tp @classmethod def flatten(cls, args): # TODO: disallow nested TensorProducts. c_part = [] nc_parts = [] for arg in args: cp, ncp = arg.args_cnc() c_part.extend(list(cp)) nc_parts.append(Mul._from_args(ncp)) return c_part, nc_parts def _eval_adjoint(self): return TensorProduct(*[Dagger(i) for i in self.args]) def _eval_rewrite(self, rule, args, **hints): return TensorProduct(*args).expand(tensorproduct=True) def _sympystr(self, printer, *args): length = len(self.args) s = '' for i in range(length): if isinstance(self.args[i], (Add, Pow, Mul)): s = s + '(' s = s + printer._print(self.args[i]) if isinstance(self.args[i], (Add, Pow, Mul)): s = s + ')' if i != length - 1: s = s + 'x' return s def _pretty(self, printer, *args): if (_combined_printing and (all([isinstance(arg, Ket) for arg in self.args]) or all([isinstance(arg, Bra) for arg in self.args]))): length = len(self.args) pform = printer._print('', *args) for i in range(length): next_pform = printer._print('', *args) length_i = len(self.args[i].args) for j in range(length_i): part_pform = printer._print(self.args[i].args[j], *args) next_pform = prettyForm(*next_pform.right(part_pform)) if j != length_i - 1: next_pform = prettyForm(*next_pform.right(', ')) if len(self.args[i].args) > 1: next_pform = prettyForm( *next_pform.parens(left='{', right='}')) pform = prettyForm(*pform.right(next_pform)) if i != length - 1: pform = prettyForm(*pform.right(',' + ' ')) pform = prettyForm(*pform.left(self.args[0].lbracket)) pform = prettyForm(*pform.right(self.args[0].rbracket)) return pform length = len(self.args) pform = printer._print('', *args) for i in range(length): next_pform = printer._print(self.args[i], *args) if isinstance(self.args[i], (Add, Mul)): next_pform = prettyForm( *next_pform.parens(left='(', right=')') ) pform = prettyForm(*pform.right(next_pform)) if i != length - 1: if printer._use_unicode: pform = prettyForm(*pform.right('\N{N-ARY CIRCLED TIMES OPERATOR}' + ' ')) else: pform = prettyForm(*pform.right('x' + ' ')) return pform def _latex(self, printer, *args): if (_combined_printing and (all([isinstance(arg, Ket) for arg in self.args]) or all([isinstance(arg, Bra) for arg in self.args]))): def _label_wrap(label, nlabels): return label if nlabels == 1 else r"\left\{%s\right\}" % label s = r", ".join([_label_wrap(arg._print_label_latex(printer, *args), len(arg.args)) for arg in self.args]) return r"{%s%s%s}" % (self.args[0].lbracket_latex, s, self.args[0].rbracket_latex) length = len(self.args) s = '' for i in range(length): if isinstance(self.args[i], (Add, Mul)): s = s + '\\left(' # The extra {} brackets are needed to get matplotlib's latex # rendered to render this properly. s = s + '{' + printer._print(self.args[i], *args) + '}' if isinstance(self.args[i], (Add, Mul)): s = s + '\\right)' if i != length - 1: s = s + '\\otimes ' return s def doit(self, **hints): return TensorProduct(*[item.doit(**hints) for item in self.args]) def _eval_expand_tensorproduct(self, **hints): """Distribute TensorProducts across addition.""" args = self.args add_args = [] for i in range(len(args)): if isinstance(args[i], Add): for aa in args[i].args: tp = TensorProduct(*args[:i] + (aa,) + args[i + 1:]) if isinstance(tp, TensorProduct): tp = tp._eval_expand_tensorproduct() add_args.append(tp) break if add_args: return Add(*add_args) else: return self def _eval_trace(self, **kwargs): indices = kwargs.get('indices', None) exp = tensor_product_simp(self) if indices is None or len(indices) == 0: return Mul(*[Tr(arg).doit() for arg in exp.args]) else: return Mul(*[Tr(value).doit() if idx in indices else value for idx, value in enumerate(exp.args)]) def tensor_product_simp_Mul(e): """Simplify a Mul with TensorProducts. Current the main use of this is to simplify a ``Mul`` of ``TensorProduct``s to a ``TensorProduct`` of ``Muls``. It currently only works for relatively simple cases where the initial ``Mul`` only has scalars and raw ``TensorProduct``s, not ``Add``, ``Pow``, ``Commutator``s of ``TensorProduct``s. Parameters ========== e : Expr A ``Mul`` of ``TensorProduct``s to be simplified. Returns ======= e : Expr A ``TensorProduct`` of ``Mul``s. Examples ======== This is an example of the type of simplification that this function performs:: >>> from sympy.physics.quantum.tensorproduct import \ tensor_product_simp_Mul, TensorProduct >>> from sympy import Symbol >>> A = Symbol('A',commutative=False) >>> B = Symbol('B',commutative=False) >>> C = Symbol('C',commutative=False) >>> D = Symbol('D',commutative=False) >>> e = TensorProduct(A,B)*TensorProduct(C,D) >>> e AxB*CxD >>> tensor_product_simp_Mul(e) (A*C)x(B*D) """ # TODO: This won't work with Muls that have other composites of # TensorProducts, like an Add, Commutator, etc. # TODO: This only works for the equivalent of single Qbit gates. if not isinstance(e, Mul): return e c_part, nc_part = e.args_cnc() n_nc = len(nc_part) if n_nc == 0: return e elif n_nc == 1: if isinstance(nc_part[0], Pow): return Mul(*c_part) * tensor_product_simp_Pow(nc_part[0]) return e elif e.has(TensorProduct): current = nc_part[0] if not isinstance(current, TensorProduct): if isinstance(current, Pow): if isinstance(current.base, TensorProduct): current = tensor_product_simp_Pow(current) else: raise TypeError('TensorProduct expected, got: %r' % current) n_terms = len(current.args) new_args = list(current.args) for next in nc_part[1:]: # TODO: check the hilbert spaces of next and current here. if isinstance(next, TensorProduct): if n_terms != len(next.args): raise QuantumError( 'TensorProducts of different lengths: %r and %r' % (current, next) ) for i in range(len(new_args)): new_args[i] = new_args[i] * next.args[i] else: if isinstance(next, Pow): if isinstance(next.base, TensorProduct): new_tp = tensor_product_simp_Pow(next) for i in range(len(new_args)): new_args[i] = new_args[i] * new_tp.args[i] else: raise TypeError('TensorProduct expected, got: %r' % next) else: raise TypeError('TensorProduct expected, got: %r' % next) current = next return Mul(*c_part) * TensorProduct(*new_args) elif e.has(Pow): new_args = [ tensor_product_simp_Pow(nc) for nc in nc_part ] return tensor_product_simp_Mul(Mul(*c_part) * TensorProduct(*new_args)) else: return e def tensor_product_simp_Pow(e): """Evaluates ``Pow`` expressions whose base is ``TensorProduct``""" if not isinstance(e, Pow): return e if isinstance(e.base, TensorProduct): return TensorProduct(*[ b**e.exp for b in e.base.args]) else: return e def tensor_product_simp(e, **hints): """Try to simplify and combine TensorProducts. In general this will try to pull expressions inside of ``TensorProducts``. It currently only works for relatively simple cases where the products have only scalars, raw ``TensorProducts``, not ``Add``, ``Pow``, ``Commutators`` of ``TensorProducts``. It is best to see what it does by showing examples. Examples ======== >>> from sympy.physics.quantum import tensor_product_simp >>> from sympy.physics.quantum import TensorProduct >>> from sympy import Symbol >>> A = Symbol('A',commutative=False) >>> B = Symbol('B',commutative=False) >>> C = Symbol('C',commutative=False) >>> D = Symbol('D',commutative=False) First see what happens to products of tensor products: >>> e = TensorProduct(A,B)*TensorProduct(C,D) >>> e AxB*CxD >>> tensor_product_simp(e) (A*C)x(B*D) This is the core logic of this function, and it works inside, powers, sums, commutators and anticommutators as well: >>> tensor_product_simp(e**2) (A*C)x(B*D)**2 """ if isinstance(e, Add): return Add(*[tensor_product_simp(arg) for arg in e.args]) elif isinstance(e, Pow): if isinstance(e.base, TensorProduct): return tensor_product_simp_Pow(e) else: return tensor_product_simp(e.base) ** e.exp elif isinstance(e, Mul): return tensor_product_simp_Mul(e) elif isinstance(e, Commutator): return Commutator(*[tensor_product_simp(arg) for arg in e.args]) elif isinstance(e, AntiCommutator): return AntiCommutator(*[tensor_product_simp(arg) for arg in e.args]) else: return e sympy-sympy-1.9/sympy/physics/quantum/tests/000077500000000000000000000000001412543434000214225ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/quantum/tests/__init__.py000066400000000000000000000000001412543434000235210ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/quantum/tests/test_anticommutator.py000066400000000000000000000023561412543434000261070ustar00rootroot00000000000000from sympy import symbols, Integer from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.anticommutator import AntiCommutator as AComm from sympy.physics.quantum.operator import Operator a, b, c = symbols('a,b,c') A, B, C, D = symbols('A,B,C,D', commutative=False) def test_anticommutator(): ac = AComm(A, B) assert isinstance(ac, AComm) assert ac.is_commutative is False assert ac.subs(A, C) == AComm(C, B) def test_commutator_identities(): assert AComm(a*A, b*B) == a*b*AComm(A, B) assert AComm(A, A) == 2*A**2 assert AComm(A, B) == AComm(B, A) assert AComm(a, b) == 2*a*b assert AComm(A, B).doit() == A*B + B*A def test_anticommutator_dagger(): assert Dagger(AComm(A, B)) == AComm(Dagger(A), Dagger(B)) class Foo(Operator): def _eval_anticommutator_Bar(self, bar): return Integer(0) class Bar(Operator): pass class Tam(Operator): def _eval_anticommutator_Foo(self, foo): return Integer(1) def test_eval_commutator(): F = Foo('F') B = Bar('B') T = Tam('T') assert AComm(F, B).doit() == 0 assert AComm(B, F).doit() == 0 assert AComm(F, T).doit() == 1 assert AComm(T, F).doit() == 1 assert AComm(B, T).doit() == B*T + T*B sympy-sympy-1.9/sympy/physics/quantum/tests/test_boson.py000066400000000000000000000030101412543434000241450ustar00rootroot00000000000000from sympy import sqrt, exp, prod, Rational from sympy.physics.quantum import Dagger, Commutator, qapply from sympy.physics.quantum.boson import BosonOp from sympy.physics.quantum.boson import ( BosonFockKet, BosonFockBra, BosonCoherentKet, BosonCoherentBra) def test_bosonoperator(): a = BosonOp('a') b = BosonOp('b') assert isinstance(a, BosonOp) assert isinstance(Dagger(a), BosonOp) assert a.is_annihilation assert not Dagger(a).is_annihilation assert BosonOp("a") == BosonOp("a", True) assert BosonOp("a") != BosonOp("c") assert BosonOp("a", True) != BosonOp("a", False) assert Commutator(a, Dagger(a)).doit() == 1 assert Commutator(a, Dagger(b)).doit() == a * Dagger(b) - Dagger(b) * a assert Dagger(exp(a)) == exp(Dagger(a)) def test_boson_states(): a = BosonOp("a") # Fock states n = 3 assert (BosonFockBra(0) * BosonFockKet(1)).doit() == 0 assert (BosonFockBra(1) * BosonFockKet(1)).doit() == 1 assert qapply(BosonFockBra(n) * Dagger(a)**n * BosonFockKet(0)) \ == sqrt(prod(range(1, n+1))) # Coherent states alpha1, alpha2 = 1.2, 4.3 assert (BosonCoherentBra(alpha1) * BosonCoherentKet(alpha1)).doit() == 1 assert (BosonCoherentBra(alpha2) * BosonCoherentKet(alpha2)).doit() == 1 assert abs((BosonCoherentBra(alpha1) * BosonCoherentKet(alpha2)).doit() - exp((alpha1 - alpha2) ** 2 * Rational(-1, 2))) < 1e-12 assert qapply(a * BosonCoherentKet(alpha1)) == \ alpha1 * BosonCoherentKet(alpha1) sympy-sympy-1.9/sympy/physics/quantum/tests/test_cartesian.py000066400000000000000000000074201412543434000250070ustar00rootroot00000000000000"""Tests for cartesian.py""" from sympy import S, Interval, symbols, I, DiracDelta, exp, sqrt, pi from sympy.physics.quantum import qapply, represent, L2, Dagger from sympy.physics.quantum import Commutator, hbar from sympy.physics.quantum.cartesian import ( XOp, YOp, ZOp, PxOp, X, Y, Z, Px, XKet, XBra, PxKet, PxBra, PositionKet3D, PositionBra3D ) from sympy.physics.quantum.operator import DifferentialOperator x, y, z, x_1, x_2, x_3, y_1, z_1 = symbols('x,y,z,x_1,x_2,x_3,y_1,z_1') px, py, px_1, px_2 = symbols('px py px_1 px_2') def test_x(): assert X.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) assert Commutator(X, Px).doit() == I*hbar assert qapply(X*XKet(x)) == x*XKet(x) assert XKet(x).dual_class() == XBra assert XBra(x).dual_class() == XKet assert (Dagger(XKet(y))*XKet(x)).doit() == DiracDelta(x - y) assert (PxBra(px)*XKet(x)).doit() == \ exp(-I*x*px/hbar)/sqrt(2*pi*hbar) assert represent(XKet(x)) == DiracDelta(x - x_1) assert represent(XBra(x)) == DiracDelta(-x + x_1) assert XBra(x).position == x assert represent(XOp()*XKet()) == x*DiracDelta(x - x_2) assert represent(XOp()*XKet()*XBra('y')) == \ x*DiracDelta(x - x_3)*DiracDelta(x_1 - y) assert represent(XBra("y")*XKet()) == DiracDelta(x - y) assert represent( XKet()*XBra()) == DiracDelta(x - x_2) * DiracDelta(x_1 - x) rep_p = represent(XOp(), basis=PxOp) assert rep_p == hbar*I*DiracDelta(px_1 - px_2)*DifferentialOperator(px_1) assert rep_p == represent(XOp(), basis=PxOp()) assert rep_p == represent(XOp(), basis=PxKet) assert rep_p == represent(XOp(), basis=PxKet()) assert represent(XOp()*PxKet(), basis=PxKet) == \ hbar*I*DiracDelta(px - px_2)*DifferentialOperator(px) def test_p(): assert Px.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) assert qapply(Px*PxKet(px)) == px*PxKet(px) assert PxKet(px).dual_class() == PxBra assert PxBra(x).dual_class() == PxKet assert (Dagger(PxKet(py))*PxKet(px)).doit() == DiracDelta(px - py) assert (XBra(x)*PxKet(px)).doit() == \ exp(I*x*px/hbar)/sqrt(2*pi*hbar) assert represent(PxKet(px)) == DiracDelta(px - px_1) rep_x = represent(PxOp(), basis=XOp) assert rep_x == -hbar*I*DiracDelta(x_1 - x_2)*DifferentialOperator(x_1) assert rep_x == represent(PxOp(), basis=XOp()) assert rep_x == represent(PxOp(), basis=XKet) assert rep_x == represent(PxOp(), basis=XKet()) assert represent(PxOp()*XKet(), basis=XKet) == \ -hbar*I*DiracDelta(x - x_2)*DifferentialOperator(x) assert represent(XBra("y")*PxOp()*XKet(), basis=XKet) == \ -hbar*I*DiracDelta(x - y)*DifferentialOperator(x) def test_3dpos(): assert Y.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) assert Z.hilbert_space == L2(Interval(S.NegativeInfinity, S.Infinity)) test_ket = PositionKet3D(x, y, z) assert qapply(X*test_ket) == x*test_ket assert qapply(Y*test_ket) == y*test_ket assert qapply(Z*test_ket) == z*test_ket assert qapply(X*Y*test_ket) == x*y*test_ket assert qapply(X*Y*Z*test_ket) == x*y*z*test_ket assert qapply(Y*Z*test_ket) == y*z*test_ket assert PositionKet3D() == test_ket assert YOp() == Y assert ZOp() == Z assert PositionKet3D.dual_class() == PositionBra3D assert PositionBra3D.dual_class() == PositionKet3D other_ket = PositionKet3D(x_1, y_1, z_1) assert (Dagger(other_ket)*test_ket).doit() == \ DiracDelta(x - x_1)*DiracDelta(y - y_1)*DiracDelta(z - z_1) assert test_ket.position_x == x assert test_ket.position_y == y assert test_ket.position_z == z assert other_ket.position_x == x_1 assert other_ket.position_y == y_1 assert other_ket.position_z == z_1 # TODO: Add tests for representations sympy-sympy-1.9/sympy/physics/quantum/tests/test_cg.py000066400000000000000000000210131412543434000234210ustar00rootroot00000000000000from sympy import S, sqrt, Sum, symbols, Rational from sympy.physics.quantum.cg import Wigner3j, Wigner6j, Wigner9j, CG, cg_simp from sympy.functions.special.tensor_functions import KroneckerDelta def test_cg_simp_add(): j, m1, m1p, m2, m2p = symbols('j m1 m1p m2 m2p') # Test Varshalovich 8.7.1 Eq 1 a = CG(S.Half, S.Half, 0, 0, S.Half, S.Half) b = CG(S.Half, Rational(-1, 2), 0, 0, S.Half, Rational(-1, 2)) c = CG(1, 1, 0, 0, 1, 1) d = CG(1, 0, 0, 0, 1, 0) e = CG(1, -1, 0, 0, 1, -1) assert cg_simp(a + b) == 2 assert cg_simp(c + d + e) == 3 assert cg_simp(a + b + c + d + e) == 5 assert cg_simp(a + b + c) == 2 + c assert cg_simp(2*a + b) == 2 + a assert cg_simp(2*c + d + e) == 3 + c assert cg_simp(5*a + 5*b) == 10 assert cg_simp(5*c + 5*d + 5*e) == 15 assert cg_simp(-a - b) == -2 assert cg_simp(-c - d - e) == -3 assert cg_simp(-6*a - 6*b) == -12 assert cg_simp(-4*c - 4*d - 4*e) == -12 a = CG(S.Half, S.Half, j, 0, S.Half, S.Half) b = CG(S.Half, Rational(-1, 2), j, 0, S.Half, Rational(-1, 2)) c = CG(1, 1, j, 0, 1, 1) d = CG(1, 0, j, 0, 1, 0) e = CG(1, -1, j, 0, 1, -1) assert cg_simp(a + b) == 2*KroneckerDelta(j, 0) assert cg_simp(c + d + e) == 3*KroneckerDelta(j, 0) assert cg_simp(a + b + c + d + e) == 5*KroneckerDelta(j, 0) assert cg_simp(a + b + c) == 2*KroneckerDelta(j, 0) + c assert cg_simp(2*a + b) == 2*KroneckerDelta(j, 0) + a assert cg_simp(2*c + d + e) == 3*KroneckerDelta(j, 0) + c assert cg_simp(5*a + 5*b) == 10*KroneckerDelta(j, 0) assert cg_simp(5*c + 5*d + 5*e) == 15*KroneckerDelta(j, 0) assert cg_simp(-a - b) == -2*KroneckerDelta(j, 0) assert cg_simp(-c - d - e) == -3*KroneckerDelta(j, 0) assert cg_simp(-6*a - 6*b) == -12*KroneckerDelta(j, 0) assert cg_simp(-4*c - 4*d - 4*e) == -12*KroneckerDelta(j, 0) # Test Varshalovich 8.7.1 Eq 2 a = CG(S.Half, S.Half, S.Half, Rational(-1, 2), 0, 0) b = CG(S.Half, Rational(-1, 2), S.Half, S.Half, 0, 0) c = CG(1, 1, 1, -1, 0, 0) d = CG(1, 0, 1, 0, 0, 0) e = CG(1, -1, 1, 1, 0, 0) assert cg_simp(a - b) == sqrt(2) assert cg_simp(c - d + e) == sqrt(3) assert cg_simp(a - b + c - d + e) == sqrt(2) + sqrt(3) assert cg_simp(a - b + c) == sqrt(2) + c assert cg_simp(2*a - b) == sqrt(2) + a assert cg_simp(2*c - d + e) == sqrt(3) + c assert cg_simp(5*a - 5*b) == 5*sqrt(2) assert cg_simp(5*c - 5*d + 5*e) == 5*sqrt(3) assert cg_simp(-a + b) == -sqrt(2) assert cg_simp(-c + d - e) == -sqrt(3) assert cg_simp(-6*a + 6*b) == -6*sqrt(2) assert cg_simp(-4*c + 4*d - 4*e) == -4*sqrt(3) a = CG(S.Half, S.Half, S.Half, Rational(-1, 2), j, 0) b = CG(S.Half, Rational(-1, 2), S.Half, S.Half, j, 0) c = CG(1, 1, 1, -1, j, 0) d = CG(1, 0, 1, 0, j, 0) e = CG(1, -1, 1, 1, j, 0) assert cg_simp(a - b) == sqrt(2)*KroneckerDelta(j, 0) assert cg_simp(c - d + e) == sqrt(3)*KroneckerDelta(j, 0) assert cg_simp(a - b + c - d + e) == sqrt( 2)*KroneckerDelta(j, 0) + sqrt(3)*KroneckerDelta(j, 0) assert cg_simp(a - b + c) == sqrt(2)*KroneckerDelta(j, 0) + c assert cg_simp(2*a - b) == sqrt(2)*KroneckerDelta(j, 0) + a assert cg_simp(2*c - d + e) == sqrt(3)*KroneckerDelta(j, 0) + c assert cg_simp(5*a - 5*b) == 5*sqrt(2)*KroneckerDelta(j, 0) assert cg_simp(5*c - 5*d + 5*e) == 5*sqrt(3)*KroneckerDelta(j, 0) assert cg_simp(-a + b) == -sqrt(2)*KroneckerDelta(j, 0) assert cg_simp(-c + d - e) == -sqrt(3)*KroneckerDelta(j, 0) assert cg_simp(-6*a + 6*b) == -6*sqrt(2)*KroneckerDelta(j, 0) assert cg_simp(-4*c + 4*d - 4*e) == -4*sqrt(3)*KroneckerDelta(j, 0) # Test Varshalovich 8.7.2 Eq 9 # alpha=alphap,beta=betap case # numerical a = CG(S.Half, S.Half, S.Half, Rational(-1, 2), 1, 0)**2 b = CG(S.Half, S.Half, S.Half, Rational(-1, 2), 0, 0)**2 c = CG(1, 0, 1, 1, 1, 1)**2 d = CG(1, 0, 1, 1, 2, 1)**2 assert cg_simp(a + b) == 1 assert cg_simp(c + d) == 1 assert cg_simp(a + b + c + d) == 2 assert cg_simp(4*a + 4*b) == 4 assert cg_simp(4*c + 4*d) == 4 assert cg_simp(5*a + 3*b) == 3 + 2*a assert cg_simp(5*c + 3*d) == 3 + 2*c assert cg_simp(-a - b) == -1 assert cg_simp(-c - d) == -1 # symbolic a = CG(S.Half, m1, S.Half, m2, 1, 1)**2 b = CG(S.Half, m1, S.Half, m2, 1, 0)**2 c = CG(S.Half, m1, S.Half, m2, 1, -1)**2 d = CG(S.Half, m1, S.Half, m2, 0, 0)**2 assert cg_simp(a + b + c + d) == 1 assert cg_simp(4*a + 4*b + 4*c + 4*d) == 4 assert cg_simp(3*a + 5*b + 3*c + 4*d) == 3 + 2*b + d assert cg_simp(-a - b - c - d) == -1 a = CG(1, m1, 1, m2, 2, 2)**2 b = CG(1, m1, 1, m2, 2, 1)**2 c = CG(1, m1, 1, m2, 2, 0)**2 d = CG(1, m1, 1, m2, 2, -1)**2 e = CG(1, m1, 1, m2, 2, -2)**2 f = CG(1, m1, 1, m2, 1, 1)**2 g = CG(1, m1, 1, m2, 1, 0)**2 h = CG(1, m1, 1, m2, 1, -1)**2 i = CG(1, m1, 1, m2, 0, 0)**2 assert cg_simp(a + b + c + d + e + f + g + h + i) == 1 assert cg_simp(4*(a + b + c + d + e + f + g + h + i)) == 4 assert cg_simp(a + b + 2*c + d + 4*e + f + g + h + i) == 1 + c + 3*e assert cg_simp(-a - b - c - d - e - f - g - h - i) == -1 # alpha!=alphap or beta!=betap case # numerical a = CG(S.Half, S( 1)/2, S.Half, Rational(-1, 2), 1, 0)*CG(S.Half, Rational(-1, 2), S.Half, S.Half, 1, 0) b = CG(S.Half, S( 1)/2, S.Half, Rational(-1, 2), 0, 0)*CG(S.Half, Rational(-1, 2), S.Half, S.Half, 0, 0) c = CG(1, 1, 1, 0, 2, 1)*CG(1, 0, 1, 1, 2, 1) d = CG(1, 1, 1, 0, 1, 1)*CG(1, 0, 1, 1, 1, 1) assert cg_simp(a + b) == 0 assert cg_simp(c + d) == 0 # symbolic a = CG(S.Half, m1, S.Half, m2, 1, 1)*CG(S.Half, m1p, S.Half, m2p, 1, 1) b = CG(S.Half, m1, S.Half, m2, 1, 0)*CG(S.Half, m1p, S.Half, m2p, 1, 0) c = CG(S.Half, m1, S.Half, m2, 1, -1)*CG(S.Half, m1p, S.Half, m2p, 1, -1) d = CG(S.Half, m1, S.Half, m2, 0, 0)*CG(S.Half, m1p, S.Half, m2p, 0, 0) assert cg_simp(a + b + c + d) == KroneckerDelta(m1, m1p)*KroneckerDelta(m2, m2p) a = CG(1, m1, 1, m2, 2, 2)*CG(1, m1p, 1, m2p, 2, 2) b = CG(1, m1, 1, m2, 2, 1)*CG(1, m1p, 1, m2p, 2, 1) c = CG(1, m1, 1, m2, 2, 0)*CG(1, m1p, 1, m2p, 2, 0) d = CG(1, m1, 1, m2, 2, -1)*CG(1, m1p, 1, m2p, 2, -1) e = CG(1, m1, 1, m2, 2, -2)*CG(1, m1p, 1, m2p, 2, -2) f = CG(1, m1, 1, m2, 1, 1)*CG(1, m1p, 1, m2p, 1, 1) g = CG(1, m1, 1, m2, 1, 0)*CG(1, m1p, 1, m2p, 1, 0) h = CG(1, m1, 1, m2, 1, -1)*CG(1, m1p, 1, m2p, 1, -1) i = CG(1, m1, 1, m2, 0, 0)*CG(1, m1p, 1, m2p, 0, 0) assert cg_simp( a + b + c + d + e + f + g + h + i) == KroneckerDelta(m1, m1p)*KroneckerDelta(m2, m2p) def test_cg_simp_sum(): x, a, b, c, cp, alpha, beta, gamma, gammap = symbols( 'x a b c cp alpha beta gamma gammap') # Varshalovich 8.7.1 Eq 1 assert cg_simp(x * Sum(CG(a, alpha, b, 0, a, alpha), (alpha, -a, a) )) == x*(2*a + 1)*KroneckerDelta(b, 0) assert cg_simp(x * Sum(CG(a, alpha, b, 0, a, alpha), (alpha, -a, a)) + CG(1, 0, 1, 0, 1, 0)) == x*(2*a + 1)*KroneckerDelta(b, 0) + CG(1, 0, 1, 0, 1, 0) assert cg_simp(2 * Sum(CG(1, alpha, 0, 0, 1, alpha), (alpha, -1, 1))) == 6 # Varshalovich 8.7.1 Eq 2 assert cg_simp(x*Sum((-1)**(a - alpha) * CG(a, alpha, a, -alpha, c, 0), (alpha, -a, a))) == x*sqrt(2*a + 1)*KroneckerDelta(c, 0) assert cg_simp(3*Sum((-1)**(2 - alpha) * CG( 2, alpha, 2, -alpha, 0, 0), (alpha, -2, 2))) == 3*sqrt(5) # Varshalovich 8.7.2 Eq 4 assert cg_simp(Sum(CG(a, alpha, b, beta, c, gamma)*CG(a, alpha, b, beta, cp, gammap), (alpha, -a, a), (beta, -b, b))) == KroneckerDelta(c, cp)*KroneckerDelta(gamma, gammap) assert cg_simp(Sum(CG(a, alpha, b, beta, c, gamma)*CG(a, alpha, b, beta, c, gammap), (alpha, -a, a), (beta, -b, b))) == KroneckerDelta(gamma, gammap) assert cg_simp(Sum(CG(a, alpha, b, beta, c, gamma)*CG(a, alpha, b, beta, cp, gamma), (alpha, -a, a), (beta, -b, b))) == KroneckerDelta(c, cp) assert cg_simp(Sum(CG( a, alpha, b, beta, c, gamma)**2, (alpha, -a, a), (beta, -b, b))) == 1 assert cg_simp(Sum(CG(2, alpha, 1, beta, 2, gamma)*CG(2, alpha, 1, beta, 2, gammap), (alpha, -2, 2), (beta, -1, 1))) == KroneckerDelta(gamma, gammap) def test_doit(): assert Wigner3j(S.Half, Rational(-1, 2), S.Half, S.Half, 0, 0).doit() == -sqrt(2)/2 assert Wigner6j(1, 2, 3, 2, 1, 2).doit() == sqrt(21)/105 assert Wigner6j(3, 1, 2, 2, 2, 1).doit() == sqrt(21) / 105 assert Wigner9j( 2, 1, 1, Rational(3, 2), S.Half, 1, S.Half, S.Half, 0).doit() == sqrt(2)/12 assert CG(S.Half, S.Half, S.Half, Rational(-1, 2), 1, 0).doit() == sqrt(2)/2 sympy-sympy-1.9/sympy/physics/quantum/tests/test_circuitplot.py000066400000000000000000000040601412543434000253740ustar00rootroot00000000000000from sympy.physics.quantum.circuitplot import labeller, render_label, Mz, CreateOneQubitGate,\ CreateCGate from sympy.physics.quantum.gate import CNOT, H, SWAP, CGate, S, T from sympy.external import import_module from sympy.testing.pytest import skip mpl = import_module('matplotlib') def test_render_label(): assert render_label('q0') == r'$\left|q0\right\rangle$' assert render_label('q0', {'q0': '0'}) == r'$\left|q0\right\rangle=\left|0\right\rangle$' def test_Mz(): assert str(Mz(0)) == 'Mz(0)' def test_create1(): Qgate = CreateOneQubitGate('Q') assert str(Qgate(0)) == 'Q(0)' def test_createc(): Qgate = CreateCGate('Q') assert str(Qgate([1],0)) == 'C((1),Q(0))' def test_labeller(): """Test the labeller utility""" assert labeller(2) == ['q_1', 'q_0'] assert labeller(3,'j') == ['j_2', 'j_1', 'j_0'] def test_cnot(): """Test a simple cnot circuit. Right now this only makes sure the code doesn't raise an exception, and some simple properties """ if not mpl: skip("matplotlib not installed") else: from sympy.physics.quantum.circuitplot import CircuitPlot c = CircuitPlot(CNOT(1,0),2,labels=labeller(2)) assert c.ngates == 2 assert c.nqubits == 2 assert c.labels == ['q_1', 'q_0'] c = CircuitPlot(CNOT(1,0),2) assert c.ngates == 2 assert c.nqubits == 2 assert c.labels == [] def test_ex1(): if not mpl: skip("matplotlib not installed") else: from sympy.physics.quantum.circuitplot import CircuitPlot c = CircuitPlot(CNOT(1,0)*H(1),2,labels=labeller(2)) assert c.ngates == 2 assert c.nqubits == 2 assert c.labels == ['q_1', 'q_0'] def test_ex4(): if not mpl: skip("matplotlib not installed") else: from sympy.physics.quantum.circuitplot import CircuitPlot c = CircuitPlot(SWAP(0,2)*H(0)* CGate((0,),S(1)) *H(1)*CGate((0,),T(2))\ *CGate((1,),S(2))*H(2),3,labels=labeller(3,'j')) assert c.ngates == 7 assert c.nqubits == 3 assert c.labels == ['j_2', 'j_1', 'j_0'] sympy-sympy-1.9/sympy/physics/quantum/tests/test_circuitutils.py000066400000000000000000000314771412543434000255720ustar00rootroot00000000000000from sympy import Symbol, Integer, Mul from sympy.utilities import numbered_symbols from sympy.physics.quantum.gate import X, Y, Z, H, CNOT, CGate from sympy.physics.quantum.identitysearch import bfs_identity_search from sympy.physics.quantum.circuitutils import (kmp_table, find_subcircuit, replace_subcircuit, convert_to_symbolic_indices, convert_to_real_indices, random_reduce, random_insert, flatten_ids) from sympy.testing.pytest import slow def create_gate_sequence(qubit=0): gates = (X(qubit), Y(qubit), Z(qubit), H(qubit)) return gates def test_kmp_table(): word = ('a', 'b', 'c', 'd', 'a', 'b', 'd') expected_table = [-1, 0, 0, 0, 0, 1, 2] assert expected_table == kmp_table(word) word = ('P', 'A', 'R', 'T', 'I', 'C', 'I', 'P', 'A', 'T', 'E', ' ', 'I', 'N', ' ', 'P', 'A', 'R', 'A', 'C', 'H', 'U', 'T', 'E') expected_table = [-1, 0, 0, 0, 0, 0, 0, 0, 1, 2, 0, 0, 0, 0, 0, 0, 1, 2, 3, 0, 0, 0, 0, 0] assert expected_table == kmp_table(word) x = X(0) y = Y(0) z = Z(0) h = H(0) word = (x, y, y, x, z) expected_table = [-1, 0, 0, 0, 1] assert expected_table == kmp_table(word) word = (x, x, y, h, z) expected_table = [-1, 0, 1, 0, 0] assert expected_table == kmp_table(word) def test_find_subcircuit(): x = X(0) y = Y(0) z = Z(0) h = H(0) x1 = X(1) y1 = Y(1) i0 = Symbol('i0') x_i0 = X(i0) y_i0 = Y(i0) z_i0 = Z(i0) h_i0 = H(i0) circuit = (x, y, z) assert find_subcircuit(circuit, (x,)) == 0 assert find_subcircuit(circuit, (x1,)) == -1 assert find_subcircuit(circuit, (y,)) == 1 assert find_subcircuit(circuit, (h,)) == -1 assert find_subcircuit(circuit, Mul(x, h)) == -1 assert find_subcircuit(circuit, Mul(x, y, z)) == 0 assert find_subcircuit(circuit, Mul(y, z)) == 1 assert find_subcircuit(Mul(*circuit), (x, y, z, h)) == -1 assert find_subcircuit(Mul(*circuit), (z, y, x)) == -1 assert find_subcircuit(circuit, (x,), start=2, end=1) == -1 circuit = (x, y, x, y, z) assert find_subcircuit(Mul(*circuit), Mul(x, y, z)) == 2 assert find_subcircuit(circuit, (x,), start=1) == 2 assert find_subcircuit(circuit, (x, y), start=1, end=2) == -1 assert find_subcircuit(Mul(*circuit), (x, y), start=1, end=3) == -1 assert find_subcircuit(circuit, (x, y), start=1, end=4) == 2 assert find_subcircuit(circuit, (x, y), start=2, end=4) == 2 circuit = (x, y, z, x1, x, y, z, h, x, y, x1, x, y, z, h, y1, h) assert find_subcircuit(circuit, (x, y, z, h, y1)) == 11 circuit = (x, y, x_i0, y_i0, z_i0, z) assert find_subcircuit(circuit, (x_i0, y_i0, z_i0)) == 2 circuit = (x_i0, y_i0, z_i0, x_i0, y_i0, h_i0) subcircuit = (x_i0, y_i0, z_i0) result = find_subcircuit(circuit, subcircuit) assert result == 0 def test_replace_subcircuit(): x = X(0) y = Y(0) z = Z(0) h = H(0) cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) # Standard cases circuit = (z, y, x, x) remove = (z, y, x) assert replace_subcircuit(circuit, Mul(*remove)) == (x,) assert replace_subcircuit(circuit, remove + (x,)) == () assert replace_subcircuit(circuit, remove, pos=1) == circuit assert replace_subcircuit(circuit, remove, pos=0) == (x,) assert replace_subcircuit(circuit, (x, x), pos=2) == (z, y) assert replace_subcircuit(circuit, (h,)) == circuit circuit = (x, y, x, y, z) remove = (x, y, z) assert replace_subcircuit(Mul(*circuit), Mul(*remove)) == (x, y) remove = (x, y, x, y) assert replace_subcircuit(circuit, remove) == (z,) circuit = (x, h, cgate_z, h, cnot) remove = (x, h, cgate_z) assert replace_subcircuit(circuit, Mul(*remove), pos=-1) == (h, cnot) assert replace_subcircuit(circuit, remove, pos=1) == circuit remove = (h, h) assert replace_subcircuit(circuit, remove) == circuit remove = (h, cgate_z, h, cnot) assert replace_subcircuit(circuit, remove) == (x,) replace = (h, x) actual = replace_subcircuit(circuit, remove, replace=replace) assert actual == (x, h, x) circuit = (x, y, h, x, y, z) remove = (x, y) replace = (cnot, cgate_z) actual = replace_subcircuit(circuit, remove, replace=Mul(*replace)) assert actual == (cnot, cgate_z, h, x, y, z) actual = replace_subcircuit(circuit, remove, replace=replace, pos=1) assert actual == (x, y, h, cnot, cgate_z, z) def test_convert_to_symbolic_indices(): (x, y, z, h) = create_gate_sequence() i0 = Symbol('i0') exp_map = {i0: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x,)) assert actual == (X(i0),) assert act_map == exp_map expected = (X(i0), Y(i0), Z(i0), H(i0)) exp_map = {i0: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x, y, z, h)) assert actual == expected assert exp_map == act_map (x1, y1, z1, h1) = create_gate_sequence(1) i1 = Symbol('i1') expected = (X(i0), Y(i0), Z(i0), H(i0)) exp_map = {i0: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x1, y1, z1, h1)) assert actual == expected assert act_map == exp_map expected = (X(i0), Y(i0), Z(i0), H(i0), X(i1), Y(i1), Z(i1), H(i1)) exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x, y, z, h, x1, y1, z1, h1)) assert actual == expected assert act_map == exp_map exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(Mul(x1, y1, z1, h1, x, y, z, h)) assert actual == expected assert act_map == exp_map expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1)) exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices(Mul(x, x1, y, y1, z, z1, h, h1)) assert actual == expected assert act_map == exp_map exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices((x1, x, y1, y, z1, z, h1, h)) assert actual == expected assert act_map == exp_map cnot_10 = CNOT(1, 0) cnot_01 = CNOT(0, 1) cgate_z_10 = CGate(1, Z(0)) cgate_z_01 = CGate(0, Z(1)) expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1), CNOT(i1, i0), CNOT(i0, i1), CGate(i1, Z(i0)), CGate(i0, Z(i1))) exp_map = {i0: Integer(0), i1: Integer(1)} args = (x, x1, y, y1, z, z1, h, h1, cnot_10, cnot_01, cgate_z_10, cgate_z_01) actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (x1, x, y1, y, z1, z, h1, h, cnot_10, cnot_01, cgate_z_10, cgate_z_01) expected = (X(i0), X(i1), Y(i0), Y(i1), Z(i0), Z(i1), H(i0), H(i1), CNOT(i0, i1), CNOT(i1, i0), CGate(i0, Z(i1)), CGate(i1, Z(i0))) exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_10, h, cgate_z_01, h) expected = (CNOT(i0, i1), H(i1), CGate(i1, Z(i0)), H(i1)) exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_01, h1, cgate_z_10, h1) exp_map = {i0: Integer(0), i1: Integer(1)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map args = (cnot_10, h1, cgate_z_01, h1) expected = (CNOT(i0, i1), H(i0), CGate(i1, Z(i0)), H(i0)) exp_map = {i0: Integer(1), i1: Integer(0)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map i2 = Symbol('i2') ccgate_z = CGate(0, CGate(1, Z(2))) ccgate_x = CGate(1, CGate(2, X(0))) args = (ccgate_z, ccgate_x) expected = (CGate(i0, CGate(i1, Z(i2))), CGate(i1, CGate(i2, X(i0)))) exp_map = {i0: Integer(0), i1: Integer(1), i2: Integer(2)} actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map ndx_map = {i0: Integer(0)} index_gen = numbered_symbols(prefix='i', start=1) actual, act_map, sndx, gen = convert_to_symbolic_indices(args, qubit_map=ndx_map, start=i0, gen=index_gen) assert actual == expected assert act_map == exp_map i3 = Symbol('i3') cgate_x0_c321 = CGate((3, 2, 1), X(0)) exp_map = {i0: Integer(3), i1: Integer(2), i2: Integer(1), i3: Integer(0)} expected = (CGate((i0, i1, i2), X(i3)),) args = (cgate_x0_c321,) actual, act_map, sndx, gen = convert_to_symbolic_indices(args) assert actual == expected assert act_map == exp_map def test_convert_to_real_indices(): i0 = Symbol('i0') i1 = Symbol('i1') (x, y, z, h) = create_gate_sequence() x_i0 = X(i0) y_i0 = Y(i0) z_i0 = Z(i0) qubit_map = {i0: 0} args = (z_i0, y_i0, x_i0) expected = (z, y, x) actual = convert_to_real_indices(args, qubit_map) assert actual == expected cnot_10 = CNOT(1, 0) cnot_01 = CNOT(0, 1) cgate_z_10 = CGate(1, Z(0)) cgate_z_01 = CGate(0, Z(1)) cnot_i1_i0 = CNOT(i1, i0) cnot_i0_i1 = CNOT(i0, i1) cgate_z_i1_i0 = CGate(i1, Z(i0)) qubit_map = {i0: 0, i1: 1} args = (cnot_i1_i0,) expected = (cnot_10,) actual = convert_to_real_indices(args, qubit_map) assert actual == expected args = (cgate_z_i1_i0,) expected = (cgate_z_10,) actual = convert_to_real_indices(args, qubit_map) assert actual == expected args = (cnot_i0_i1,) expected = (cnot_01,) actual = convert_to_real_indices(args, qubit_map) assert actual == expected qubit_map = {i0: 1, i1: 0} args = (cgate_z_i1_i0,) expected = (cgate_z_01,) actual = convert_to_real_indices(args, qubit_map) assert actual == expected i2 = Symbol('i2') ccgate_z = CGate(i0, CGate(i1, Z(i2))) ccgate_x = CGate(i1, CGate(i2, X(i0))) qubit_map = {i0: 0, i1: 1, i2: 2} args = (ccgate_z, ccgate_x) expected = (CGate(0, CGate(1, Z(2))), CGate(1, CGate(2, X(0)))) actual = convert_to_real_indices(Mul(*args), qubit_map) assert actual == expected qubit_map = {i0: 1, i2: 0, i1: 2} args = (ccgate_x, ccgate_z) expected = (CGate(2, CGate(0, X(1))), CGate(1, CGate(2, Z(0)))) actual = convert_to_real_indices(args, qubit_map) assert actual == expected @slow def test_random_reduce(): x = X(0) y = Y(0) z = Z(0) h = H(0) cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) gate_list = [x, y, z] ids = list(bfs_identity_search(gate_list, 1, max_depth=4)) circuit = (x, y, h, z, cnot) assert random_reduce(circuit, []) == circuit assert random_reduce(circuit, ids) == circuit seq = [2, 11, 9, 3, 5] circuit = (x, y, z, x, y, h) assert random_reduce(circuit, ids, seed=seq) == (x, y, h) circuit = (x, x, y, y, z, z) assert random_reduce(circuit, ids, seed=seq) == (x, x, y, y) seq = [14, 13, 0] assert random_reduce(circuit, ids, seed=seq) == (y, y, z, z) gate_list = [x, y, z, h, cnot, cgate_z] ids = list(bfs_identity_search(gate_list, 2, max_depth=4)) seq = [25] circuit = (x, y, z, y, h, y, h, cgate_z, h, cnot) expected = (x, y, z, cgate_z, h, cnot) assert random_reduce(circuit, ids, seed=seq) == expected circuit = Mul(*circuit) assert random_reduce(circuit, ids, seed=seq) == expected @slow def test_random_insert(): x = X(0) y = Y(0) z = Z(0) h = H(0) cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) choices = [(x, x)] circuit = (y, y) loc, choice = 0, 0 actual = random_insert(circuit, choices, seed=[loc, choice]) assert actual == (x, x, y, y) circuit = (x, y, z, h) choices = [(h, h), (x, y, z)] expected = (x, x, y, z, y, z, h) loc, choice = 1, 1 actual = random_insert(circuit, choices, seed=[loc, choice]) assert actual == expected gate_list = [x, y, z, h, cnot, cgate_z] ids = list(bfs_identity_search(gate_list, 2, max_depth=4)) eq_ids = flatten_ids(ids) circuit = (x, y, h, cnot, cgate_z) expected = (x, z, x, z, x, y, h, cnot, cgate_z) loc, choice = 1, 30 actual = random_insert(circuit, eq_ids, seed=[loc, choice]) assert actual == expected circuit = Mul(*circuit) actual = random_insert(circuit, eq_ids, seed=[loc, choice]) assert actual == expected sympy-sympy-1.9/sympy/physics/quantum/tests/test_commutator.py000066400000000000000000000051751412543434000252350ustar00rootroot00000000000000from sympy import symbols, Integer from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.commutator import Commutator as Comm from sympy.physics.quantum.operator import Operator a, b, c = symbols('a,b,c') n = symbols('n', integer=True) A, B, C, D = symbols('A,B,C,D', commutative=False) def test_commutator(): c = Comm(A, B) assert c.is_commutative is False assert isinstance(c, Comm) assert c.subs(A, C) == Comm(C, B) def test_commutator_identities(): assert Comm(a*A, b*B) == a*b*Comm(A, B) assert Comm(A, A) == 0 assert Comm(a, b) == 0 assert Comm(A, B) == -Comm(B, A) assert Comm(A, B).doit() == A*B - B*A assert Comm(A, B*C).expand(commutator=True) == Comm(A, B)*C + B*Comm(A, C) assert Comm(A*B, C*D).expand(commutator=True) == \ A*C*Comm(B, D) + A*Comm(B, C)*D + C*Comm(A, D)*B + Comm(A, C)*D*B assert Comm(A, B**2).expand(commutator=True) == Comm(A, B)*B + B*Comm(A, B) assert Comm(A**2, C**2).expand(commutator=True) == \ Comm(A*B, C*D).expand(commutator=True).replace(B, A).replace(D, C) == \ A*C*Comm(A, C) + A*Comm(A, C)*C + C*Comm(A, C)*A + Comm(A, C)*C*A assert Comm(A, C**-2).expand(commutator=True) == \ Comm(A, (1/C)*(1/D)).expand(commutator=True).replace(D, C) assert Comm(A + B, C + D).expand(commutator=True) == \ Comm(A, C) + Comm(A, D) + Comm(B, C) + Comm(B, D) assert Comm(A, B + C).expand(commutator=True) == Comm(A, B) + Comm(A, C) assert Comm(A**n, B).expand(commutator=True) == Comm(A**n, B) e = Comm(A, Comm(B, C)) + Comm(B, Comm(C, A)) + Comm(C, Comm(A, B)) assert e.doit().expand() == 0 def test_commutator_dagger(): comm = Comm(A*B, C) assert Dagger(comm).expand(commutator=True) == \ - Comm(Dagger(B), Dagger(C))*Dagger(A) - \ Dagger(B)*Comm(Dagger(A), Dagger(C)) class Foo(Operator): def _eval_commutator_Bar(self, bar): return Integer(0) class Bar(Operator): pass class Tam(Operator): def _eval_commutator_Foo(self, foo): return Integer(1) def test_eval_commutator(): F = Foo('F') B = Bar('B') T = Tam('T') assert Comm(F, B).doit() == 0 assert Comm(B, F).doit() == 0 assert Comm(F, T).doit() == -1 assert Comm(T, F).doit() == 1 assert Comm(B, T).doit() == B*T - T*B assert Comm(F**2, B).expand(commutator=True).doit() == 0 assert Comm(F**2, T).expand(commutator=True).doit() == -2*F assert Comm(F, T**2).expand(commutator=True).doit() == -2*T assert Comm(T**2, F).expand(commutator=True).doit() == 2*T assert Comm(T**2, F**3).expand(commutator=True).doit() == 2*F*T*F + 2*F**2*T + 2*T*F**2 sympy-sympy-1.9/sympy/physics/quantum/tests/test_constants.py000066400000000000000000000005051412543434000250470ustar00rootroot00000000000000from sympy import Float from sympy.physics.quantum.constants import hbar def test_hbar(): assert hbar.is_commutative is True assert hbar.is_real is True assert hbar.is_positive is True assert hbar.is_negative is False assert hbar.is_irrational is True assert hbar.evalf() == Float(1.05457162e-34) sympy-sympy-1.9/sympy/physics/quantum/tests/test_dagger.py000066400000000000000000000034511412543434000242670ustar00rootroot00000000000000from sympy import I, Matrix, symbols, conjugate, Expr, Integer, Mul from sympy.physics.quantum.dagger import adjoint, Dagger from sympy.external import import_module from sympy.testing.pytest import skip from sympy.physics.quantum.operator import Operator, IdentityOperator def test_scalars(): x = symbols('x', complex=True) assert Dagger(x) == conjugate(x) assert Dagger(I*x) == -I*conjugate(x) i = symbols('i', real=True) assert Dagger(i) == i p = symbols('p') assert isinstance(Dagger(p), adjoint) i = Integer(3) assert Dagger(i) == i A = symbols('A', commutative=False) assert Dagger(A).is_commutative is False def test_matrix(): x = symbols('x') m = Matrix([[I, x*I], [2, 4]]) assert Dagger(m) == m.H def test_dagger_mul(): O = Operator('O') I = IdentityOperator() assert Dagger(O)*O == Dagger(O)*O assert Dagger(O)*O*I == Mul(Dagger(O), O)*I assert Dagger(O)*Dagger(O) == Dagger(O)**2 assert Dagger(O)*Dagger(I) == Dagger(O) class Foo(Expr): def _eval_adjoint(self): return I def test_eval_adjoint(): f = Foo() d = Dagger(f) assert d == I np = import_module('numpy') def test_numpy_dagger(): if not np: skip("numpy not installed.") a = np.matrix([[1.0, 2.0j], [-1.0j, 2.0]]) adag = a.copy().transpose().conjugate() assert (Dagger(a) == adag).all() scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) def test_scipy_sparse_dagger(): if not np: skip("numpy not installed.") if not scipy: skip("scipy not installed.") else: sparse = scipy.sparse a = sparse.csr_matrix([[1.0 + 0.0j, 2.0j], [-1.0j, 2.0 + 0.0j]]) adag = a.copy().transpose().conjugate() assert np.linalg.norm((Dagger(a) - adag).todense()) == 0.0 sympy-sympy-1.9/sympy/physics/quantum/tests/test_density.py000066400000000000000000000225761412543434000245260ustar00rootroot00000000000000from sympy import symbols, S, log, Rational from sympy.core.trace import Tr from sympy.external import import_module from sympy.physics.quantum.density import Density, entropy, fidelity from sympy.physics.quantum.state import Ket, TimeDepKet from sympy.physics.quantum.qubit import Qubit from sympy.physics.quantum.represent import represent from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.cartesian import XKet, PxKet, PxOp, XOp from sympy.physics.quantum.spin import JzKet from sympy.physics.quantum.operator import OuterProduct from sympy.functions import sqrt from sympy.testing.pytest import raises from sympy.physics.quantum.matrixutils import scipy_sparse_matrix from sympy.physics.quantum.tensorproduct import TensorProduct def test_eval_args(): # check instance created assert isinstance(Density([Ket(0), 0.5], [Ket(1), 0.5]), Density) assert isinstance(Density([Qubit('00'), 1/sqrt(2)], [Qubit('11'), 1/sqrt(2)]), Density) #test if Qubit object type preserved d = Density([Qubit('00'), 1/sqrt(2)], [Qubit('11'), 1/sqrt(2)]) for (state, prob) in d.args: assert isinstance(state, Qubit) # check for value error, when prob is not provided raises(ValueError, lambda: Density([Ket(0)], [Ket(1)])) def test_doit(): x, y = symbols('x y') A, B, C, D, E, F = symbols('A B C D E F', commutative=False) d = Density([XKet(), 0.5], [PxKet(), 0.5]) assert (0.5*(PxKet()*Dagger(PxKet())) + 0.5*(XKet()*Dagger(XKet()))) == d.doit() # check for kets with expr in them d_with_sym = Density([XKet(x*y), 0.5], [PxKet(x*y), 0.5]) assert (0.5*(PxKet(x*y)*Dagger(PxKet(x*y))) + 0.5*(XKet(x*y)*Dagger(XKet(x*y)))) == d_with_sym.doit() d = Density([(A + B)*C, 1.0]) assert d.doit() == (1.0*A*C*Dagger(C)*Dagger(A) + 1.0*A*C*Dagger(C)*Dagger(B) + 1.0*B*C*Dagger(C)*Dagger(A) + 1.0*B*C*Dagger(C)*Dagger(B)) # With TensorProducts as args # Density with simple tensor products as args t = TensorProduct(A, B, C) d = Density([t, 1.0]) assert d.doit() == \ 1.0 * TensorProduct(A*Dagger(A), B*Dagger(B), C*Dagger(C)) # Density with multiple Tensorproducts as states t2 = TensorProduct(A, B) t3 = TensorProduct(C, D) d = Density([t2, 0.5], [t3, 0.5]) assert d.doit() == (0.5 * TensorProduct(A*Dagger(A), B*Dagger(B)) + 0.5 * TensorProduct(C*Dagger(C), D*Dagger(D))) #Density with mixed states d = Density([t2 + t3, 1.0]) assert d.doit() == (1.0 * TensorProduct(A*Dagger(A), B*Dagger(B)) + 1.0 * TensorProduct(A*Dagger(C), B*Dagger(D)) + 1.0 * TensorProduct(C*Dagger(A), D*Dagger(B)) + 1.0 * TensorProduct(C*Dagger(C), D*Dagger(D))) #Density operators with spin states tp1 = TensorProduct(JzKet(1, 1), JzKet(1, -1)) d = Density([tp1, 1]) # full trace t = Tr(d) assert t.doit() == 1 #Partial trace on density operators with spin states t = Tr(d, [0]) assert t.doit() == JzKet(1, -1) * Dagger(JzKet(1, -1)) t = Tr(d, [1]) assert t.doit() == JzKet(1, 1) * Dagger(JzKet(1, 1)) # with another spin state tp2 = TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) d = Density([tp2, 1]) #full trace t = Tr(d) assert t.doit() == 1 #Partial trace on density operators with spin states t = Tr(d, [0]) assert t.doit() == JzKet(S.Half, Rational(-1, 2)) * Dagger(JzKet(S.Half, Rational(-1, 2))) t = Tr(d, [1]) assert t.doit() == JzKet(S.Half, S.Half) * Dagger(JzKet(S.Half, S.Half)) def test_apply_op(): d = Density([Ket(0), 0.5], [Ket(1), 0.5]) assert d.apply_op(XOp()) == Density([XOp()*Ket(0), 0.5], [XOp()*Ket(1), 0.5]) def test_represent(): x, y = symbols('x y') d = Density([XKet(), 0.5], [PxKet(), 0.5]) assert (represent(0.5*(PxKet()*Dagger(PxKet()))) + represent(0.5*(XKet()*Dagger(XKet())))) == represent(d) # check for kets with expr in them d_with_sym = Density([XKet(x*y), 0.5], [PxKet(x*y), 0.5]) assert (represent(0.5*(PxKet(x*y)*Dagger(PxKet(x*y)))) + represent(0.5*(XKet(x*y)*Dagger(XKet(x*y))))) == \ represent(d_with_sym) # check when given explicit basis assert (represent(0.5*(XKet()*Dagger(XKet())), basis=PxOp()) + represent(0.5*(PxKet()*Dagger(PxKet())), basis=PxOp())) == \ represent(d, basis=PxOp()) def test_states(): d = Density([Ket(0), 0.5], [Ket(1), 0.5]) states = d.states() assert states[0] == Ket(0) and states[1] == Ket(1) def test_probs(): d = Density([Ket(0), .75], [Ket(1), 0.25]) probs = d.probs() assert probs[0] == 0.75 and probs[1] == 0.25 #probs can be symbols x, y = symbols('x y') d = Density([Ket(0), x], [Ket(1), y]) probs = d.probs() assert probs[0] == x and probs[1] == y def test_get_state(): x, y = symbols('x y') d = Density([Ket(0), x], [Ket(1), y]) states = (d.get_state(0), d.get_state(1)) assert states[0] == Ket(0) and states[1] == Ket(1) def test_get_prob(): x, y = symbols('x y') d = Density([Ket(0), x], [Ket(1), y]) probs = (d.get_prob(0), d.get_prob(1)) assert probs[0] == x and probs[1] == y def test_entropy(): up = JzKet(S.Half, S.Half) down = JzKet(S.Half, Rational(-1, 2)) d = Density((up, S.Half), (down, S.Half)) # test for density object ent = entropy(d) assert entropy(d) == log(2)/2 assert d.entropy() == log(2)/2 np = import_module('numpy', min_module_version='1.4.0') if np: #do this test only if 'numpy' is available on test machine np_mat = represent(d, format='numpy') ent = entropy(np_mat) assert isinstance(np_mat, np.matrixlib.defmatrix.matrix) assert ent.real == 0.69314718055994529 assert ent.imag == 0 scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) if scipy and np: #do this test only if numpy and scipy are available mat = represent(d, format="scipy.sparse") assert isinstance(mat, scipy_sparse_matrix) assert ent.real == 0.69314718055994529 assert ent.imag == 0 def test_eval_trace(): up = JzKet(S.Half, S.Half) down = JzKet(S.Half, Rational(-1, 2)) d = Density((up, 0.5), (down, 0.5)) t = Tr(d) assert t.doit() == 1 #test dummy time dependent states class TestTimeDepKet(TimeDepKet): def _eval_trace(self, bra, **options): return 1 x, t = symbols('x t') k1 = TestTimeDepKet(0, 0.5) k2 = TestTimeDepKet(0, 1) d = Density([k1, 0.5], [k2, 0.5]) assert d.doit() == (0.5 * OuterProduct(k1, k1.dual) + 0.5 * OuterProduct(k2, k2.dual)) t = Tr(d) assert t.doit() == 1 def test_fidelity(): #test with kets up = JzKet(S.Half, S.Half) down = JzKet(S.Half, Rational(-1, 2)) updown = (S.One/sqrt(2))*up + (S.One/sqrt(2))*down #check with matrices up_dm = represent(up * Dagger(up)) down_dm = represent(down * Dagger(down)) updown_dm = represent(updown * Dagger(updown)) assert abs(fidelity(up_dm, up_dm) - 1) < 1e-3 assert fidelity(up_dm, down_dm) < 1e-3 assert abs(fidelity(up_dm, updown_dm) - (S.One/sqrt(2))) < 1e-3 assert abs(fidelity(updown_dm, down_dm) - (S.One/sqrt(2))) < 1e-3 #check with density up_dm = Density([up, 1.0]) down_dm = Density([down, 1.0]) updown_dm = Density([updown, 1.0]) assert abs(fidelity(up_dm, up_dm) - 1) < 1e-3 assert abs(fidelity(up_dm, down_dm)) < 1e-3 assert abs(fidelity(up_dm, updown_dm) - (S.One/sqrt(2))) < 1e-3 assert abs(fidelity(updown_dm, down_dm) - (S.One/sqrt(2))) < 1e-3 #check mixed states with density updown2 = sqrt(3)/2*up + S.Half*down d1 = Density([updown, 0.25], [updown2, 0.75]) d2 = Density([updown, 0.75], [updown2, 0.25]) assert abs(fidelity(d1, d2) - 0.991) < 1e-3 assert abs(fidelity(d2, d1) - fidelity(d1, d2)) < 1e-3 #using qubits/density(pure states) state1 = Qubit('0') state2 = Qubit('1') state3 = S.One/sqrt(2)*state1 + S.One/sqrt(2)*state2 state4 = sqrt(Rational(2, 3))*state1 + S.One/sqrt(3)*state2 state1_dm = Density([state1, 1]) state2_dm = Density([state2, 1]) state3_dm = Density([state3, 1]) assert fidelity(state1_dm, state1_dm) == 1 assert fidelity(state1_dm, state2_dm) == 0 assert abs(fidelity(state1_dm, state3_dm) - 1/sqrt(2)) < 1e-3 assert abs(fidelity(state3_dm, state2_dm) - 1/sqrt(2)) < 1e-3 #using qubits/density(mixed states) d1 = Density([state3, 0.70], [state4, 0.30]) d2 = Density([state3, 0.20], [state4, 0.80]) assert abs(fidelity(d1, d1) - 1) < 1e-3 assert abs(fidelity(d1, d2) - 0.996) < 1e-3 assert abs(fidelity(d1, d2) - fidelity(d2, d1)) < 1e-3 #TODO: test for invalid arguments # non-square matrix mat1 = [[0, 0], [0, 0], [0, 0]] mat2 = [[0, 0], [0, 0]] raises(ValueError, lambda: fidelity(mat1, mat2)) # unequal dimensions mat1 = [[0, 0], [0, 0]] mat2 = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] raises(ValueError, lambda: fidelity(mat1, mat2)) # unsupported data-type x, y = 1, 2 # random values that is not a matrix raises(ValueError, lambda: fidelity(x, y)) sympy-sympy-1.9/sympy/physics/quantum/tests/test_fermion.py000066400000000000000000000021571412543434000244770ustar00rootroot00000000000000from sympy.physics.quantum import Dagger, AntiCommutator, qapply from sympy.physics.quantum.fermion import FermionOp from sympy.physics.quantum.fermion import FermionFockKet, FermionFockBra def test_fermionoperator(): c = FermionOp('c') d = FermionOp('d') assert isinstance(c, FermionOp) assert isinstance(Dagger(c), FermionOp) assert c.is_annihilation assert not Dagger(c).is_annihilation assert FermionOp("c") == FermionOp("c", True) assert FermionOp("c") != FermionOp("d") assert FermionOp("c", True) != FermionOp("c", False) assert AntiCommutator(c, Dagger(c)).doit() == 1 assert AntiCommutator(c, Dagger(d)).doit() == c * Dagger(d) + Dagger(d) * c def test_fermion_states(): c = FermionOp("c") # Fock states assert (FermionFockBra(0) * FermionFockKet(1)).doit() == 0 assert (FermionFockBra(1) * FermionFockKet(1)).doit() == 1 assert qapply(c * FermionFockKet(1)) == FermionFockKet(0) assert qapply(c * FermionFockKet(0)) == 0 assert qapply(Dagger(c) * FermionFockKet(0)) == FermionFockKet(1) assert qapply(Dagger(c) * FermionFockKet(1)) == 0 sympy-sympy-1.9/sympy/physics/quantum/tests/test_gate.py000066400000000000000000000300421412543434000237520ustar00rootroot00000000000000from sympy import exp, symbols, sqrt, I, pi, Mul, Integer, Wild, Rational from sympy.matrices import Matrix, ImmutableMatrix from sympy.physics.quantum.gate import (XGate, YGate, ZGate, random_circuit, CNOT, IdentityGate, H, X, Y, S, T, Z, SwapGate, gate_simp, gate_sort, CNotGate, TGate, HadamardGate, PhaseGate, UGate, CGate) from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.represent import represent from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qubit import Qubit, IntQubit, qubit_to_matrix, \ matrix_to_qubit from sympy.physics.quantum.matrixutils import matrix_to_zero from sympy.physics.quantum.matrixcache import sqrt2_inv from sympy.physics.quantum import Dagger def test_gate(): """Test a basic gate.""" h = HadamardGate(1) assert h.min_qubits == 2 assert h.nqubits == 1 i0 = Wild('i0') i1 = Wild('i1') h0_w1 = HadamardGate(i0) h0_w2 = HadamardGate(i0) h1_w1 = HadamardGate(i1) assert h0_w1 == h0_w2 assert h0_w1 != h1_w1 assert h1_w1 != h0_w2 cnot_10_w1 = CNOT(i1, i0) cnot_10_w2 = CNOT(i1, i0) cnot_01_w1 = CNOT(i0, i1) assert cnot_10_w1 == cnot_10_w2 assert cnot_10_w1 != cnot_01_w1 assert cnot_10_w2 != cnot_01_w1 def test_UGate(): a, b, c, d = symbols('a,b,c,d') uMat = Matrix([[a, b], [c, d]]) # Test basic case where gate exists in 1-qubit space u1 = UGate((0,), uMat) assert represent(u1, nqubits=1) == uMat assert qapply(u1*Qubit('0')) == a*Qubit('0') + c*Qubit('1') assert qapply(u1*Qubit('1')) == b*Qubit('0') + d*Qubit('1') # Test case where gate exists in a larger space u2 = UGate((1,), uMat) u2Rep = represent(u2, nqubits=2) for i in range(4): assert u2Rep*qubit_to_matrix(IntQubit(i, 2)) == \ qubit_to_matrix(qapply(u2*IntQubit(i, 2))) def test_cgate(): """Test the general CGate.""" # Test single control functionality CNOTMatrix = Matrix( [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) assert represent(CGate(1, XGate(0)), nqubits=2) == CNOTMatrix # Test multiple control bit functionality ToffoliGate = CGate((1, 2), XGate(0)) assert represent(ToffoliGate, nqubits=3) == \ Matrix( [[1, 0, 0, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0, 0, 0], [0, 0, 0, 0, 1, 0, 0, 0], [0, 0, 0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 0, 1, 0]]) ToffoliGate = CGate((3, 0), XGate(1)) assert qapply(ToffoliGate*Qubit('1001')) == \ matrix_to_qubit(represent(ToffoliGate*Qubit('1001'), nqubits=4)) assert qapply(ToffoliGate*Qubit('0000')) == \ matrix_to_qubit(represent(ToffoliGate*Qubit('0000'), nqubits=4)) CYGate = CGate(1, YGate(0)) CYGate_matrix = Matrix( ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 0, -I), (0, 0, I, 0))) # Test 2 qubit controlled-Y gate decompose method. assert represent(CYGate.decompose(), nqubits=2) == CYGate_matrix CZGate = CGate(0, ZGate(1)) CZGate_matrix = Matrix( ((1, 0, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, -1))) assert qapply(CZGate*Qubit('11')) == -Qubit('11') assert matrix_to_qubit(represent(CZGate*Qubit('11'), nqubits=2)) == \ -Qubit('11') # Test 2 qubit controlled-Z gate decompose method. assert represent(CZGate.decompose(), nqubits=2) == CZGate_matrix CPhaseGate = CGate(0, PhaseGate(1)) assert qapply(CPhaseGate*Qubit('11')) == \ I*Qubit('11') assert matrix_to_qubit(represent(CPhaseGate*Qubit('11'), nqubits=2)) == \ I*Qubit('11') # Test that the dagger, inverse, and power of CGate is evaluated properly assert Dagger(CZGate) == CZGate assert pow(CZGate, 1) == Dagger(CZGate) assert Dagger(CZGate) == CZGate.inverse() assert Dagger(CPhaseGate) != CPhaseGate assert Dagger(CPhaseGate) == CPhaseGate.inverse() assert Dagger(CPhaseGate) == pow(CPhaseGate, -1) assert pow(CPhaseGate, -1) == CPhaseGate.inverse() def test_UGate_CGate_combo(): a, b, c, d = symbols('a,b,c,d') uMat = Matrix([[a, b], [c, d]]) cMat = Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, a, b], [0, 0, c, d]]) # Test basic case where gate exists in 1-qubit space. u1 = UGate((0,), uMat) cu1 = CGate(1, u1) assert represent(cu1, nqubits=2) == cMat assert qapply(cu1*Qubit('10')) == a*Qubit('10') + c*Qubit('11') assert qapply(cu1*Qubit('11')) == b*Qubit('10') + d*Qubit('11') assert qapply(cu1*Qubit('01')) == Qubit('01') assert qapply(cu1*Qubit('00')) == Qubit('00') # Test case where gate exists in a larger space. u2 = UGate((1,), uMat) u2Rep = represent(u2, nqubits=2) for i in range(4): assert u2Rep*qubit_to_matrix(IntQubit(i, 2)) == \ qubit_to_matrix(qapply(u2*IntQubit(i, 2))) def test_UGate_OneQubitGate_combo(): v, w, f, g = symbols('v w f g') uMat1 = ImmutableMatrix([[v, w], [f, g]]) cMat1 = Matrix([[v, w + 1, 0, 0], [f + 1, g, 0, 0], [0, 0, v, w + 1], [0, 0, f + 1, g]]) u1 = X(0) + UGate(0, uMat1) assert represent(u1, nqubits=2) == cMat1 uMat2 = ImmutableMatrix([[1/sqrt(2), 1/sqrt(2)], [I/sqrt(2), -I/sqrt(2)]]) cMat2_1 = Matrix([[Rational(1, 2) + I/2, Rational(1, 2) - I/2], [Rational(1, 2) - I/2, Rational(1, 2) + I/2]]) cMat2_2 = Matrix([[1, 0], [0, I]]) u2 = UGate(0, uMat2) assert represent(H(0)*u2, nqubits=1) == cMat2_1 assert represent(u2*H(0), nqubits=1) == cMat2_2 def test_represent_hadamard(): """Test the representation of the hadamard gate.""" circuit = HadamardGate(0)*Qubit('00') answer = represent(circuit, nqubits=2) # Check that the answers are same to within an epsilon. assert answer == Matrix([sqrt2_inv, sqrt2_inv, 0, 0]) def test_represent_xgate(): """Test the representation of the X gate.""" circuit = XGate(0)*Qubit('00') answer = represent(circuit, nqubits=2) assert Matrix([0, 1, 0, 0]) == answer def test_represent_ygate(): """Test the representation of the Y gate.""" circuit = YGate(0)*Qubit('00') answer = represent(circuit, nqubits=2) assert answer[0] == 0 and answer[1] == I and \ answer[2] == 0 and answer[3] == 0 def test_represent_zgate(): """Test the representation of the Z gate.""" circuit = ZGate(0)*Qubit('00') answer = represent(circuit, nqubits=2) assert Matrix([1, 0, 0, 0]) == answer def test_represent_phasegate(): """Test the representation of the S gate.""" circuit = PhaseGate(0)*Qubit('01') answer = represent(circuit, nqubits=2) assert Matrix([0, I, 0, 0]) == answer def test_represent_tgate(): """Test the representation of the T gate.""" circuit = TGate(0)*Qubit('01') assert Matrix([0, exp(I*pi/4), 0, 0]) == represent(circuit, nqubits=2) def test_compound_gates(): """Test a compound gate representation.""" circuit = YGate(0)*ZGate(0)*XGate(0)*HadamardGate(0)*Qubit('00') answer = represent(circuit, nqubits=2) assert Matrix([I/sqrt(2), I/sqrt(2), 0, 0]) == answer def test_cnot_gate(): """Test the CNOT gate.""" circuit = CNotGate(1, 0) assert represent(circuit, nqubits=2) == \ Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]) circuit = circuit*Qubit('111') assert matrix_to_qubit(represent(circuit, nqubits=3)) == \ qapply(circuit) circuit = CNotGate(1, 0) assert Dagger(circuit) == circuit assert Dagger(Dagger(circuit)) == circuit assert circuit*circuit == 1 def test_gate_sort(): """Test gate_sort.""" for g in (X, Y, Z, H, S, T): assert gate_sort(g(2)*g(1)*g(0)) == g(0)*g(1)*g(2) e = gate_sort(X(1)*H(0)**2*CNOT(0, 1)*X(1)*X(0)) assert e == H(0)**2*CNOT(0, 1)*X(0)*X(1)**2 assert gate_sort(Z(0)*X(0)) == -X(0)*Z(0) assert gate_sort(Z(0)*X(0)**2) == X(0)**2*Z(0) assert gate_sort(Y(0)*H(0)) == -H(0)*Y(0) assert gate_sort(Y(0)*X(0)) == -X(0)*Y(0) assert gate_sort(Z(0)*Y(0)) == -Y(0)*Z(0) assert gate_sort(T(0)*S(0)) == S(0)*T(0) assert gate_sort(Z(0)*S(0)) == S(0)*Z(0) assert gate_sort(Z(0)*T(0)) == T(0)*Z(0) assert gate_sort(Z(0)*CNOT(0, 1)) == CNOT(0, 1)*Z(0) assert gate_sort(S(0)*CNOT(0, 1)) == CNOT(0, 1)*S(0) assert gate_sort(T(0)*CNOT(0, 1)) == CNOT(0, 1)*T(0) assert gate_sort(X(1)*CNOT(0, 1)) == CNOT(0, 1)*X(1) # This takes a long time and should only be uncommented once in a while. # nqubits = 5 # ngates = 10 # trials = 10 # for i in range(trials): # c = random_circuit(ngates, nqubits) # assert represent(c, nqubits=nqubits) == \ # represent(gate_sort(c), nqubits=nqubits) def test_gate_simp(): """Test gate_simp.""" e = H(0)*X(1)*H(0)**2*CNOT(0, 1)*X(1)**3*X(0)*Z(3)**2*S(4)**3 assert gate_simp(e) == H(0)*CNOT(0, 1)*S(4)*X(0)*Z(4) assert gate_simp(X(0)*X(0)) == 1 assert gate_simp(Y(0)*Y(0)) == 1 assert gate_simp(Z(0)*Z(0)) == 1 assert gate_simp(H(0)*H(0)) == 1 assert gate_simp(T(0)*T(0)) == S(0) assert gate_simp(S(0)*S(0)) == Z(0) assert gate_simp(Integer(1)) == Integer(1) assert gate_simp(X(0)**2 + Y(0)**2) == Integer(2) def test_swap_gate(): """Test the SWAP gate.""" swap_gate_matrix = Matrix( ((1, 0, 0, 0), (0, 0, 1, 0), (0, 1, 0, 0), (0, 0, 0, 1))) assert represent(SwapGate(1, 0).decompose(), nqubits=2) == swap_gate_matrix assert qapply(SwapGate(1, 3)*Qubit('0010')) == Qubit('1000') nqubits = 4 for i in range(nqubits): for j in range(i): assert represent(SwapGate(i, j), nqubits=nqubits) == \ represent(SwapGate(i, j).decompose(), nqubits=nqubits) def test_one_qubit_commutators(): """Test single qubit gate commutation relations.""" for g1 in (IdentityGate, X, Y, Z, H, T, S): for g2 in (IdentityGate, X, Y, Z, H, T, S): e = Commutator(g1(0), g2(0)) a = matrix_to_zero(represent(e, nqubits=1, format='sympy')) b = matrix_to_zero(represent(e.doit(), nqubits=1, format='sympy')) assert a == b e = Commutator(g1(0), g2(1)) assert e.doit() == 0 def test_one_qubit_anticommutators(): """Test single qubit gate anticommutation relations.""" for g1 in (IdentityGate, X, Y, Z, H): for g2 in (IdentityGate, X, Y, Z, H): e = AntiCommutator(g1(0), g2(0)) a = matrix_to_zero(represent(e, nqubits=1, format='sympy')) b = matrix_to_zero(represent(e.doit(), nqubits=1, format='sympy')) assert a == b e = AntiCommutator(g1(0), g2(1)) a = matrix_to_zero(represent(e, nqubits=2, format='sympy')) b = matrix_to_zero(represent(e.doit(), nqubits=2, format='sympy')) assert a == b def test_cnot_commutators(): """Test commutators of involving CNOT gates.""" assert Commutator(CNOT(0, 1), Z(0)).doit() == 0 assert Commutator(CNOT(0, 1), T(0)).doit() == 0 assert Commutator(CNOT(0, 1), S(0)).doit() == 0 assert Commutator(CNOT(0, 1), X(1)).doit() == 0 assert Commutator(CNOT(0, 1), CNOT(0, 1)).doit() == 0 assert Commutator(CNOT(0, 1), CNOT(0, 2)).doit() == 0 assert Commutator(CNOT(0, 2), CNOT(0, 1)).doit() == 0 assert Commutator(CNOT(1, 2), CNOT(1, 0)).doit() == 0 def test_random_circuit(): c = random_circuit(10, 3) assert isinstance(c, Mul) m = represent(c, nqubits=3) assert m.shape == (8, 8) assert isinstance(m, Matrix) def test_hermitian_XGate(): x = XGate(1, 2) x_dagger = Dagger(x) assert (x == x_dagger) def test_hermitian_YGate(): y = YGate(1, 2) y_dagger = Dagger(y) assert (y == y_dagger) def test_hermitian_ZGate(): z = ZGate(1, 2) z_dagger = Dagger(z) assert (z == z_dagger) def test_unitary_XGate(): x = XGate(1, 2) x_dagger = Dagger(x) assert (x*x_dagger == 1) def test_unitary_YGate(): y = YGate(1, 2) y_dagger = Dagger(y) assert (y*y_dagger == 1) def test_unitary_ZGate(): z = ZGate(1, 2) z_dagger = Dagger(z) assert (z*z_dagger == 1) sympy-sympy-1.9/sympy/physics/quantum/tests/test_grover.py000066400000000000000000000067651412543434000243550ustar00rootroot00000000000000from sympy import sqrt, Matrix from sympy.physics.quantum.represent import represent from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qubit import IntQubit from sympy.physics.quantum.grover import (apply_grover, superposition_basis, OracleGate, grover_iteration, WGate) def return_one_on_two(qubits): return qubits == IntQubit(2, qubits.nqubits) def return_one_on_one(qubits): return qubits == IntQubit(1, nqubits=qubits.nqubits) def test_superposition_basis(): nbits = 2 first_half_state = IntQubit(0, nqubits=nbits)/2 + IntQubit(1, nqubits=nbits)/2 second_half_state = IntQubit(2, nbits)/2 + IntQubit(3, nbits)/2 assert first_half_state + second_half_state == superposition_basis(nbits) nbits = 3 firstq = (1/sqrt(8))*IntQubit(0, nqubits=nbits) + (1/sqrt(8))*IntQubit(1, nqubits=nbits) secondq = (1/sqrt(8))*IntQubit(2, nbits) + (1/sqrt(8))*IntQubit(3, nbits) thirdq = (1/sqrt(8))*IntQubit(4, nbits) + (1/sqrt(8))*IntQubit(5, nbits) fourthq = (1/sqrt(8))*IntQubit(6, nbits) + (1/sqrt(8))*IntQubit(7, nbits) assert firstq + secondq + thirdq + fourthq == superposition_basis(nbits) def test_OracleGate(): v = OracleGate(1, lambda qubits: qubits == IntQubit(0)) assert qapply(v*IntQubit(0)) == -IntQubit(0) assert qapply(v*IntQubit(1)) == IntQubit(1) nbits = 2 v = OracleGate(2, return_one_on_two) assert qapply(v*IntQubit(0, nbits)) == IntQubit(0, nqubits=nbits) assert qapply(v*IntQubit(1, nbits)) == IntQubit(1, nqubits=nbits) assert qapply(v*IntQubit(2, nbits)) == -IntQubit(2, nbits) assert qapply(v*IntQubit(3, nbits)) == IntQubit(3, nbits) assert represent(OracleGate(1, lambda qubits: qubits == IntQubit(0)), nqubits=1) == \ Matrix([[-1, 0], [0, 1]]) assert represent(v, nqubits=2) == Matrix([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]]) def test_WGate(): nqubits = 2 basis_states = superposition_basis(nqubits) assert qapply(WGate(nqubits)*basis_states) == basis_states expected = ((2/sqrt(pow(2, nqubits)))*basis_states) - IntQubit(1, nqubits=nqubits) assert qapply(WGate(nqubits)*IntQubit(1, nqubits=nqubits)) == expected def test_grover_iteration_1(): numqubits = 2 basis_states = superposition_basis(numqubits) v = OracleGate(numqubits, return_one_on_one) expected = IntQubit(1, nqubits=numqubits) assert qapply(grover_iteration(basis_states, v)) == expected def test_grover_iteration_2(): numqubits = 4 basis_states = superposition_basis(numqubits) v = OracleGate(numqubits, return_one_on_two) # After (pi/4)sqrt(pow(2, n)), IntQubit(2) should have highest prob # In this case, after around pi times (3 or 4) iterated = grover_iteration(basis_states, v) iterated = qapply(iterated) iterated = grover_iteration(iterated, v) iterated = qapply(iterated) iterated = grover_iteration(iterated, v) iterated = qapply(iterated) # In this case, probability was highest after 3 iterations # Probability of Qubit('0010') was 251/256 (3) vs 781/1024 (4) # Ask about measurement expected = (-13*basis_states)/64 + 264*IntQubit(2, numqubits)/256 assert qapply(expected) == iterated def test_grover(): nqubits = 2 assert apply_grover(return_one_on_one, nqubits) == IntQubit(1, nqubits=nqubits) nqubits = 4 basis_states = superposition_basis(nqubits) expected = (-13*basis_states)/64 + 264*IntQubit(2, nqubits)/256 assert apply_grover(return_one_on_two, 4) == qapply(expected) sympy-sympy-1.9/sympy/physics/quantum/tests/test_hilbert.py000066400000000000000000000047211412543434000244700ustar00rootroot00000000000000from sympy.physics.quantum.hilbert import ( HilbertSpace, ComplexSpace, L2, FockSpace, TensorProductHilbertSpace, DirectSumHilbertSpace, TensorPowerHilbertSpace ) from sympy import Interval, oo, Symbol, sstr, srepr def test_hilbert_space(): hs = HilbertSpace() assert isinstance(hs, HilbertSpace) assert sstr(hs) == 'H' assert srepr(hs) == 'HilbertSpace()' def test_complex_space(): c1 = ComplexSpace(2) assert isinstance(c1, ComplexSpace) assert c1.dimension == 2 assert sstr(c1) == 'C(2)' assert srepr(c1) == 'ComplexSpace(Integer(2))' n = Symbol('n') c2 = ComplexSpace(n) assert isinstance(c2, ComplexSpace) assert c2.dimension == n assert sstr(c2) == 'C(n)' assert srepr(c2) == "ComplexSpace(Symbol('n'))" assert c2.subs(n, 2) == ComplexSpace(2) def test_L2(): b1 = L2(Interval(-oo, 1)) assert isinstance(b1, L2) assert b1.dimension is oo assert b1.interval == Interval(-oo, 1) x = Symbol('x', real=True) y = Symbol('y', real=True) b2 = L2(Interval(x, y)) assert b2.dimension is oo assert b2.interval == Interval(x, y) assert b2.subs(x, -1) == L2(Interval(-1, y)) def test_fock_space(): f1 = FockSpace() f2 = FockSpace() assert isinstance(f1, FockSpace) assert f1.dimension is oo assert f1 == f2 def test_tensor_product(): n = Symbol('n') hs1 = ComplexSpace(2) hs2 = ComplexSpace(n) h = hs1*hs2 assert isinstance(h, TensorProductHilbertSpace) assert h.dimension == 2*n assert h.spaces == (hs1, hs2) h = hs2*hs2 assert isinstance(h, TensorPowerHilbertSpace) assert h.base == hs2 assert h.exp == 2 assert h.dimension == n**2 f = FockSpace() h = hs1*hs2*f assert h.dimension is oo def test_tensor_power(): n = Symbol('n') hs1 = ComplexSpace(2) hs2 = ComplexSpace(n) h = hs1**2 assert isinstance(h, TensorPowerHilbertSpace) assert h.base == hs1 assert h.exp == 2 assert h.dimension == 4 h = hs2**3 assert isinstance(h, TensorPowerHilbertSpace) assert h.base == hs2 assert h.exp == 3 assert h.dimension == n**3 def test_direct_sum(): n = Symbol('n') hs1 = ComplexSpace(2) hs2 = ComplexSpace(n) h = hs1 + hs2 assert isinstance(h, DirectSumHilbertSpace) assert h.dimension == 2 + n assert h.spaces == (hs1, hs2) f = FockSpace() h = hs1 + f + hs2 assert h.dimension is oo assert h.spaces == (hs1, f, hs2) sympy-sympy-1.9/sympy/physics/quantum/tests/test_identitysearch.py000066400000000000000000000424521412543434000260610ustar00rootroot00000000000000from sympy.external import import_module from sympy import Mul, Integer from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.gate import (X, Y, Z, H, CNOT, IdentityGate, CGate, PhaseGate, TGate) from sympy.physics.quantum.identitysearch import (generate_gate_rules, generate_equivalent_ids, GateIdentity, bfs_identity_search, is_scalar_sparse_matrix, is_scalar_nonsparse_matrix, is_degenerate, is_reducible) from sympy.testing.pytest import skip def create_gate_sequence(qubit=0): gates = (X(qubit), Y(qubit), Z(qubit), H(qubit)) return gates def test_generate_gate_rules_1(): # Test with tuples (x, y, z, h) = create_gate_sequence() ph = PhaseGate(0) cgate_t = CGate(0, TGate(1)) assert generate_gate_rules((x,)) == {((x,), ())} gate_rules = {((x, x), ()), ((x,), (x,))} assert generate_gate_rules((x, x)) == gate_rules gate_rules = {((x, y, x), ()), ((y, x, x), ()), ((x, x, y), ()), ((y, x), (x,)), ((x, y), (x,)), ((y,), (x, x))} assert generate_gate_rules((x, y, x)) == gate_rules gate_rules = {((x, y, z), ()), ((y, z, x), ()), ((z, x, y), ()), ((), (x, z, y)), ((), (y, x, z)), ((), (z, y, x)), ((x,), (z, y)), ((y, z), (x,)), ((y,), (x, z)), ((z, x), (y,)), ((z,), (y, x)), ((x, y), (z,))} actual = generate_gate_rules((x, y, z)) assert actual == gate_rules gate_rules = { ((), (h, z, y, x)), ((), (x, h, z, y)), ((), (y, x, h, z)), ((), (z, y, x, h)), ((h,), (z, y, x)), ((x,), (h, z, y)), ((y,), (x, h, z)), ((z,), (y, x, h)), ((h, x), (z, y)), ((x, y), (h, z)), ((y, z), (x, h)), ((z, h), (y, x)), ((h, x, y), (z,)), ((x, y, z), (h,)), ((y, z, h), (x,)), ((z, h, x), (y,)), ((h, x, y, z), ()), ((x, y, z, h), ()), ((y, z, h, x), ()), ((z, h, x, y), ())} actual = generate_gate_rules((x, y, z, h)) assert actual == gate_rules gate_rules = {((), (cgate_t**(-1), ph**(-1), x)), ((), (ph**(-1), x, cgate_t**(-1))), ((), (x, cgate_t**(-1), ph**(-1))), ((cgate_t,), (ph**(-1), x)), ((ph,), (x, cgate_t**(-1))), ((x,), (cgate_t**(-1), ph**(-1))), ((cgate_t, x), (ph**(-1),)), ((ph, cgate_t), (x,)), ((x, ph), (cgate_t**(-1),)), ((cgate_t, x, ph), ()), ((ph, cgate_t, x), ()), ((x, ph, cgate_t), ())} actual = generate_gate_rules((x, ph, cgate_t)) assert actual == gate_rules gate_rules = {(Integer(1), cgate_t**(-1)*ph**(-1)*x), (Integer(1), ph**(-1)*x*cgate_t**(-1)), (Integer(1), x*cgate_t**(-1)*ph**(-1)), (cgate_t, ph**(-1)*x), (ph, x*cgate_t**(-1)), (x, cgate_t**(-1)*ph**(-1)), (cgate_t*x, ph**(-1)), (ph*cgate_t, x), (x*ph, cgate_t**(-1)), (cgate_t*x*ph, Integer(1)), (ph*cgate_t*x, Integer(1)), (x*ph*cgate_t, Integer(1))} actual = generate_gate_rules((x, ph, cgate_t), return_as_muls=True) assert actual == gate_rules def test_generate_gate_rules_2(): # Test with Muls (x, y, z, h) = create_gate_sequence() ph = PhaseGate(0) cgate_t = CGate(0, TGate(1)) # Note: 1 (type int) is not the same as 1 (type One) expected = {(x, Integer(1))} assert generate_gate_rules((x,), return_as_muls=True) == expected expected = {(Integer(1), Integer(1))} assert generate_gate_rules(x*x, return_as_muls=True) == expected expected = {((), ())} assert generate_gate_rules(x*x, return_as_muls=False) == expected gate_rules = {(x*y*x, Integer(1)), (y, Integer(1)), (y*x, x), (x*y, x)} assert generate_gate_rules(x*y*x, return_as_muls=True) == gate_rules gate_rules = {(x*y*z, Integer(1)), (y*z*x, Integer(1)), (z*x*y, Integer(1)), (Integer(1), x*z*y), (Integer(1), y*x*z), (Integer(1), z*y*x), (x, z*y), (y*z, x), (y, x*z), (z*x, y), (z, y*x), (x*y, z)} actual = generate_gate_rules(x*y*z, return_as_muls=True) assert actual == gate_rules gate_rules = {(Integer(1), h*z*y*x), (Integer(1), x*h*z*y), (Integer(1), y*x*h*z), (Integer(1), z*y*x*h), (h, z*y*x), (x, h*z*y), (y, x*h*z), (z, y*x*h), (h*x, z*y), (z*h, y*x), (x*y, h*z), (y*z, x*h), (h*x*y, z), (x*y*z, h), (y*z*h, x), (z*h*x, y), (h*x*y*z, Integer(1)), (x*y*z*h, Integer(1)), (y*z*h*x, Integer(1)), (z*h*x*y, Integer(1))} actual = generate_gate_rules(x*y*z*h, return_as_muls=True) assert actual == gate_rules gate_rules = {(Integer(1), cgate_t**(-1)*ph**(-1)*x), (Integer(1), ph**(-1)*x*cgate_t**(-1)), (Integer(1), x*cgate_t**(-1)*ph**(-1)), (cgate_t, ph**(-1)*x), (ph, x*cgate_t**(-1)), (x, cgate_t**(-1)*ph**(-1)), (cgate_t*x, ph**(-1)), (ph*cgate_t, x), (x*ph, cgate_t**(-1)), (cgate_t*x*ph, Integer(1)), (ph*cgate_t*x, Integer(1)), (x*ph*cgate_t, Integer(1))} actual = generate_gate_rules(x*ph*cgate_t, return_as_muls=True) assert actual == gate_rules gate_rules = {((), (cgate_t**(-1), ph**(-1), x)), ((), (ph**(-1), x, cgate_t**(-1))), ((), (x, cgate_t**(-1), ph**(-1))), ((cgate_t,), (ph**(-1), x)), ((ph,), (x, cgate_t**(-1))), ((x,), (cgate_t**(-1), ph**(-1))), ((cgate_t, x), (ph**(-1),)), ((ph, cgate_t), (x,)), ((x, ph), (cgate_t**(-1),)), ((cgate_t, x, ph), ()), ((ph, cgate_t, x), ()), ((x, ph, cgate_t), ())} actual = generate_gate_rules(x*ph*cgate_t) assert actual == gate_rules def test_generate_equivalent_ids_1(): # Test with tuples (x, y, z, h) = create_gate_sequence() assert generate_equivalent_ids((x,)) == {(x,)} assert generate_equivalent_ids((x, x)) == {(x, x)} assert generate_equivalent_ids((x, y)) == {(x, y), (y, x)} gate_seq = (x, y, z) gate_ids = {(x, y, z), (y, z, x), (z, x, y), (z, y, x), (y, x, z), (x, z, y)} assert generate_equivalent_ids(gate_seq) == gate_ids gate_ids = {Mul(x, y, z), Mul(y, z, x), Mul(z, x, y), Mul(z, y, x), Mul(y, x, z), Mul(x, z, y)} assert generate_equivalent_ids(gate_seq, return_as_muls=True) == gate_ids gate_seq = (x, y, z, h) gate_ids = {(x, y, z, h), (y, z, h, x), (h, x, y, z), (h, z, y, x), (z, y, x, h), (y, x, h, z), (z, h, x, y), (x, h, z, y)} assert generate_equivalent_ids(gate_seq) == gate_ids gate_seq = (x, y, x, y) gate_ids = {(x, y, x, y), (y, x, y, x)} assert generate_equivalent_ids(gate_seq) == gate_ids cgate_y = CGate((1,), y) gate_seq = (y, cgate_y, y, cgate_y) gate_ids = {(y, cgate_y, y, cgate_y), (cgate_y, y, cgate_y, y)} assert generate_equivalent_ids(gate_seq) == gate_ids cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) gate_seq = (cnot, h, cgate_z, h) gate_ids = {(cnot, h, cgate_z, h), (h, cgate_z, h, cnot), (h, cnot, h, cgate_z), (cgate_z, h, cnot, h)} assert generate_equivalent_ids(gate_seq) == gate_ids def test_generate_equivalent_ids_2(): # Test with Muls (x, y, z, h) = create_gate_sequence() assert generate_equivalent_ids((x,), return_as_muls=True) == {x} gate_ids = {Integer(1)} assert generate_equivalent_ids(x*x, return_as_muls=True) == gate_ids gate_ids = {x*y, y*x} assert generate_equivalent_ids(x*y, return_as_muls=True) == gate_ids gate_ids = {(x, y), (y, x)} assert generate_equivalent_ids(x*y) == gate_ids circuit = Mul(*(x, y, z)) gate_ids = {x*y*z, y*z*x, z*x*y, z*y*x, y*x*z, x*z*y} assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids circuit = Mul(*(x, y, z, h)) gate_ids = {x*y*z*h, y*z*h*x, h*x*y*z, h*z*y*x, z*y*x*h, y*x*h*z, z*h*x*y, x*h*z*y} assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids circuit = Mul(*(x, y, x, y)) gate_ids = {x*y*x*y, y*x*y*x} assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids cgate_y = CGate((1,), y) circuit = Mul(*(y, cgate_y, y, cgate_y)) gate_ids = {y*cgate_y*y*cgate_y, cgate_y*y*cgate_y*y} assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids cnot = CNOT(1, 0) cgate_z = CGate((0,), Z(1)) circuit = Mul(*(cnot, h, cgate_z, h)) gate_ids = {cnot*h*cgate_z*h, h*cgate_z*h*cnot, h*cnot*h*cgate_z, cgate_z*h*cnot*h} assert generate_equivalent_ids(circuit, return_as_muls=True) == gate_ids def test_is_scalar_nonsparse_matrix(): numqubits = 2 id_only = False id_gate = (IdentityGate(1),) actual = is_scalar_nonsparse_matrix(id_gate, numqubits, id_only) assert actual is True x0 = X(0) xx_circuit = (x0, x0) actual = is_scalar_nonsparse_matrix(xx_circuit, numqubits, id_only) assert actual is True x1 = X(1) y1 = Y(1) xy_circuit = (x1, y1) actual = is_scalar_nonsparse_matrix(xy_circuit, numqubits, id_only) assert actual is False z1 = Z(1) xyz_circuit = (x1, y1, z1) actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) assert actual is True cnot = CNOT(1, 0) cnot_circuit = (cnot, cnot) actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) assert actual is True h = H(0) hh_circuit = (h, h) actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) assert actual is True h1 = H(1) xhzh_circuit = (x1, h1, z1, h1) actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only) assert actual is True id_only = True actual = is_scalar_nonsparse_matrix(xhzh_circuit, numqubits, id_only) assert actual is True actual = is_scalar_nonsparse_matrix(xyz_circuit, numqubits, id_only) assert actual is False actual = is_scalar_nonsparse_matrix(cnot_circuit, numqubits, id_only) assert actual is True actual = is_scalar_nonsparse_matrix(hh_circuit, numqubits, id_only) assert actual is True def test_is_scalar_sparse_matrix(): np = import_module('numpy') if not np: skip("numpy not installed.") scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) if not scipy: skip("scipy not installed.") numqubits = 2 id_only = False id_gate = (IdentityGate(1),) assert is_scalar_sparse_matrix(id_gate, numqubits, id_only) is True x0 = X(0) xx_circuit = (x0, x0) assert is_scalar_sparse_matrix(xx_circuit, numqubits, id_only) is True x1 = X(1) y1 = Y(1) xy_circuit = (x1, y1) assert is_scalar_sparse_matrix(xy_circuit, numqubits, id_only) is False z1 = Z(1) xyz_circuit = (x1, y1, z1) assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) is True cnot = CNOT(1, 0) cnot_circuit = (cnot, cnot) assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) is True h = H(0) hh_circuit = (h, h) assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) is True # NOTE: # The elements of the sparse matrix for the following circuit # is actually 1.0000000000000002+0.0j. h1 = H(1) xhzh_circuit = (x1, h1, z1, h1) assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) is True id_only = True assert is_scalar_sparse_matrix(xhzh_circuit, numqubits, id_only) is True assert is_scalar_sparse_matrix(xyz_circuit, numqubits, id_only) is False assert is_scalar_sparse_matrix(cnot_circuit, numqubits, id_only) is True assert is_scalar_sparse_matrix(hh_circuit, numqubits, id_only) is True def test_is_degenerate(): (x, y, z, h) = create_gate_sequence() gate_id = GateIdentity(x, y, z) ids = {gate_id} another_id = (z, y, x) assert is_degenerate(ids, another_id) is True def test_is_reducible(): nqubits = 2 (x, y, z, h) = create_gate_sequence() circuit = (x, y, y) assert is_reducible(circuit, nqubits, 1, 3) is True circuit = (x, y, x) assert is_reducible(circuit, nqubits, 1, 3) is False circuit = (x, y, y, x) assert is_reducible(circuit, nqubits, 0, 4) is True circuit = (x, y, y, x) assert is_reducible(circuit, nqubits, 1, 3) is True circuit = (x, y, z, y, y) assert is_reducible(circuit, nqubits, 1, 5) is True def test_bfs_identity_search(): assert bfs_identity_search([], 1) == set() (x, y, z, h) = create_gate_sequence() gate_list = [x] id_set = {GateIdentity(x, x)} assert bfs_identity_search(gate_list, 1, max_depth=2) == id_set # Set should not contain degenerate quantum circuits gate_list = [x, y, z] id_set = {GateIdentity(x, x), GateIdentity(y, y), GateIdentity(z, z), GateIdentity(x, y, z)} assert bfs_identity_search(gate_list, 1) == id_set id_set = {GateIdentity(x, x), GateIdentity(y, y), GateIdentity(z, z), GateIdentity(x, y, z), GateIdentity(x, y, x, y), GateIdentity(x, z, x, z), GateIdentity(y, z, y, z)} assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set assert bfs_identity_search(gate_list, 1, max_depth=5) == id_set gate_list = [x, y, z, h] id_set = {GateIdentity(x, x), GateIdentity(y, y), GateIdentity(z, z), GateIdentity(h, h), GateIdentity(x, y, z), GateIdentity(x, y, x, y), GateIdentity(x, z, x, z), GateIdentity(x, h, z, h), GateIdentity(y, z, y, z), GateIdentity(y, h, y, h)} assert bfs_identity_search(gate_list, 1) == id_set id_set = {GateIdentity(x, x), GateIdentity(y, y), GateIdentity(z, z), GateIdentity(h, h)} assert id_set == bfs_identity_search(gate_list, 1, max_depth=3, identity_only=True) id_set = {GateIdentity(x, x), GateIdentity(y, y), GateIdentity(z, z), GateIdentity(h, h), GateIdentity(x, y, z), GateIdentity(x, y, x, y), GateIdentity(x, z, x, z), GateIdentity(x, h, z, h), GateIdentity(y, z, y, z), GateIdentity(y, h, y, h), GateIdentity(x, y, h, x, h), GateIdentity(x, z, h, y, h), GateIdentity(y, z, h, z, h)} assert bfs_identity_search(gate_list, 1, max_depth=5) == id_set id_set = {GateIdentity(x, x), GateIdentity(y, y), GateIdentity(z, z), GateIdentity(h, h), GateIdentity(x, h, z, h)} assert id_set == bfs_identity_search(gate_list, 1, max_depth=4, identity_only=True) cnot = CNOT(1, 0) gate_list = [x, cnot] id_set = {GateIdentity(x, x), GateIdentity(cnot, cnot), GateIdentity(x, cnot, x, cnot)} assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set cgate_x = CGate((1,), x) gate_list = [x, cgate_x] id_set = {GateIdentity(x, x), GateIdentity(cgate_x, cgate_x), GateIdentity(x, cgate_x, x, cgate_x)} assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set cgate_z = CGate((0,), Z(1)) gate_list = [cnot, cgate_z, h] id_set = {GateIdentity(h, h), GateIdentity(cgate_z, cgate_z), GateIdentity(cnot, cnot), GateIdentity(cnot, h, cgate_z, h)} assert bfs_identity_search(gate_list, 2, max_depth=4) == id_set s = PhaseGate(0) t = TGate(0) gate_list = [s, t] id_set = {GateIdentity(s, s, s, s)} assert bfs_identity_search(gate_list, 1, max_depth=4) == id_set def test_bfs_identity_search_xfail(): s = PhaseGate(0) t = TGate(0) gate_list = [Dagger(s), t] id_set = {GateIdentity(Dagger(s), t, t)} assert bfs_identity_search(gate_list, 1, max_depth=3) == id_set sympy-sympy-1.9/sympy/physics/quantum/tests/test_innerproduct.py000066400000000000000000000026741412543434000255600ustar00rootroot00000000000000from sympy import I, Integer from sympy.physics.quantum.innerproduct import InnerProduct from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.state import Bra, Ket, StateBase def test_innerproduct(): k = Ket('k') b = Bra('b') ip = InnerProduct(b, k) assert isinstance(ip, InnerProduct) assert ip.bra == b assert ip.ket == k assert b*k == InnerProduct(b, k) assert k*(b*k)*b == k*InnerProduct(b, k)*b assert InnerProduct(b, k).subs(b, Dagger(k)) == Dagger(k)*k def test_innerproduct_dagger(): k = Ket('k') b = Bra('b') ip = b*k assert Dagger(ip) == Dagger(k)*Dagger(b) class FooState(StateBase): pass class FooKet(Ket, FooState): @classmethod def dual_class(self): return FooBra def _eval_innerproduct_FooBra(self, bra): return Integer(1) def _eval_innerproduct_BarBra(self, bra): return I class FooBra(Bra, FooState): @classmethod def dual_class(self): return FooKet class BarState(StateBase): pass class BarKet(Ket, BarState): @classmethod def dual_class(self): return BarBra class BarBra(Bra, BarState): @classmethod def dual_class(self): return BarKet def test_doit(): f = FooKet('foo') b = BarBra('bar') assert InnerProduct(b, f).doit() == I assert InnerProduct(Dagger(f), Dagger(b)).doit() == -I assert InnerProduct(Dagger(f), f).doit() == Integer(1) sympy-sympy-1.9/sympy/physics/quantum/tests/test_matrixutils.py000066400000000000000000000077371412543434000254360ustar00rootroot00000000000000from random import randint from sympy import Matrix, zeros, ones, Integer from sympy.physics.quantum.matrixutils import ( to_sympy, to_numpy, to_scipy_sparse, matrix_tensor_product, matrix_to_zero, matrix_zeros, numpy_ndarray, scipy_sparse_matrix ) from sympy.external import import_module from sympy.testing.pytest import skip m = Matrix([[1, 2], [3, 4]]) def test_sympy_to_sympy(): assert to_sympy(m) == m def test_matrix_to_zero(): assert matrix_to_zero(m) == m assert matrix_to_zero(Matrix([[0, 0], [0, 0]])) == Integer(0) np = import_module('numpy') def test_to_numpy(): if not np: skip("numpy not installed.") result = np.matrix([[1, 2], [3, 4]], dtype='complex') assert (to_numpy(m) == result).all() def test_matrix_tensor_product(): if not np: skip("numpy not installed.") l1 = zeros(4) for i in range(16): l1[i] = 2**i l2 = zeros(4) for i in range(16): l2[i] = i l3 = zeros(2) for i in range(4): l3[i] = i vec = Matrix([1, 2, 3]) #test for Matrix known 4x4 matricies numpyl1 = np.matrix(l1.tolist()) numpyl2 = np.matrix(l2.tolist()) numpy_product = np.kron(numpyl1, numpyl2) args = [l1, l2] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() numpy_product = np.kron(numpyl2, numpyl1) args = [l2, l1] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() #test for other known matrix of different dimensions numpyl2 = np.matrix(l3.tolist()) numpy_product = np.kron(numpyl1, numpyl2) args = [l1, l3] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() numpy_product = np.kron(numpyl2, numpyl1) args = [l3, l1] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() #test for non square matrix numpyl2 = np.matrix(vec.tolist()) numpy_product = np.kron(numpyl1, numpyl2) args = [l1, vec] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() numpy_product = np.kron(numpyl2, numpyl1) args = [vec, l1] sympy_product = matrix_tensor_product(*args) assert numpy_product.tolist() == sympy_product.tolist() #test for random matrix with random values that are floats random_matrix1 = np.random.rand(randint(1, 5), randint(1, 5)) random_matrix2 = np.random.rand(randint(1, 5), randint(1, 5)) numpy_product = np.kron(random_matrix1, random_matrix2) args = [Matrix(random_matrix1.tolist()), Matrix(random_matrix2.tolist())] sympy_product = matrix_tensor_product(*args) assert not (sympy_product - Matrix(numpy_product.tolist())).tolist() > \ (ones(sympy_product.rows, sympy_product.cols)*epsilon).tolist() #test for three matrix kronecker sympy_product = matrix_tensor_product(l1, vec, l2) numpy_product = np.kron(l1, np.kron(vec, l2)) assert numpy_product.tolist() == sympy_product.tolist() scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) def test_to_scipy_sparse(): if not np: skip("numpy not installed.") if not scipy: skip("scipy not installed.") else: sparse = scipy.sparse result = sparse.csr_matrix([[1, 2], [3, 4]], dtype='complex') assert np.linalg.norm((to_scipy_sparse(m) - result).todense()) == 0.0 epsilon = .000001 def test_matrix_zeros_sympy(): sym = matrix_zeros(4, 4, format='sympy') assert isinstance(sym, Matrix) def test_matrix_zeros_numpy(): if not np: skip("numpy not installed.") num = matrix_zeros(4, 4, format='numpy') assert isinstance(num, numpy_ndarray) def test_matrix_zeros_scipy(): if not np: skip("numpy not installed.") if not scipy: skip("scipy not installed.") sci = matrix_zeros(4, 4, format='scipy.sparse') assert isinstance(sci, scipy_sparse_matrix) sympy-sympy-1.9/sympy/physics/quantum/tests/test_operator.py000066400000000000000000000154421412543434000246740ustar00rootroot00000000000000from sympy import (Derivative, diff, Function, Integer, Mul, pi, sin, Symbol, symbols) from sympy.physics.quantum.qexpr import QExpr from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.hilbert import HilbertSpace from sympy.physics.quantum.operator import (Operator, UnitaryOperator, HermitianOperator, OuterProduct, DifferentialOperator, IdentityOperator) from sympy.physics.quantum.state import Ket, Bra, Wavefunction from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.represent import represent from sympy.core.trace import Tr from sympy.physics.quantum.spin import JzKet, JzBra from sympy.matrices import eye class CustomKet(Ket): @classmethod def default_args(self): return ("t",) class CustomOp(HermitianOperator): @classmethod def default_args(self): return ("T",) t_ket = CustomKet() t_op = CustomOp() def test_operator(): A = Operator('A') B = Operator('B') C = Operator('C') assert isinstance(A, Operator) assert isinstance(A, QExpr) assert A.label == (Symbol('A'),) assert A.is_commutative is False assert A.hilbert_space == HilbertSpace() assert A*B != B*A assert (A*(B + C)).expand() == A*B + A*C assert ((A + B)**2).expand() == A**2 + A*B + B*A + B**2 assert t_op.label[0] == Symbol(t_op.default_args()[0]) assert Operator() == Operator("O") assert A*IdentityOperator() == A def test_operator_inv(): A = Operator('A') assert A*A.inv() == 1 assert A.inv()*A == 1 def test_hermitian(): H = HermitianOperator('H') assert isinstance(H, HermitianOperator) assert isinstance(H, Operator) assert Dagger(H) == H assert H.inv() != H assert H.is_commutative is False assert Dagger(H).is_commutative is False def test_unitary(): U = UnitaryOperator('U') assert isinstance(U, UnitaryOperator) assert isinstance(U, Operator) assert U.inv() == Dagger(U) assert U*Dagger(U) == 1 assert Dagger(U)*U == 1 assert U.is_commutative is False assert Dagger(U).is_commutative is False def test_identity(): I = IdentityOperator() O = Operator('O') x = Symbol("x") assert isinstance(I, IdentityOperator) assert isinstance(I, Operator) assert I * O == O assert O * I == O assert I * Dagger(O) == Dagger(O) assert Dagger(O) * I == Dagger(O) assert isinstance(I * I, IdentityOperator) assert isinstance(3 * I, Mul) assert isinstance(I * x, Mul) assert I.inv() == I assert Dagger(I) == I assert qapply(I * O) == O assert qapply(O * I) == O for n in [2, 3, 5]: assert represent(IdentityOperator(n)) == eye(n) def test_outer_product(): k = Ket('k') b = Bra('b') op = OuterProduct(k, b) assert isinstance(op, OuterProduct) assert isinstance(op, Operator) assert op.ket == k assert op.bra == b assert op.label == (k, b) assert op.is_commutative is False op = k*b assert isinstance(op, OuterProduct) assert isinstance(op, Operator) assert op.ket == k assert op.bra == b assert op.label == (k, b) assert op.is_commutative is False op = 2*k*b assert op == Mul(Integer(2), k, b) op = 2*(k*b) assert op == Mul(Integer(2), OuterProduct(k, b)) assert Dagger(k*b) == OuterProduct(Dagger(b), Dagger(k)) assert Dagger(k*b).is_commutative is False #test the _eval_trace assert Tr(OuterProduct(JzKet(1, 1), JzBra(1, 1))).doit() == 1 # test scaled kets and bras assert OuterProduct(2 * k, b) == 2 * OuterProduct(k, b) assert OuterProduct(k, 2 * b) == 2 * OuterProduct(k, b) # test sums of kets and bras k1, k2 = Ket('k1'), Ket('k2') b1, b2 = Bra('b1'), Bra('b2') assert (OuterProduct(k1 + k2, b1) == OuterProduct(k1, b1) + OuterProduct(k2, b1)) assert (OuterProduct(k1, b1 + b2) == OuterProduct(k1, b1) + OuterProduct(k1, b2)) assert (OuterProduct(1 * k1 + 2 * k2, 3 * b1 + 4 * b2) == 3 * OuterProduct(k1, b1) + 4 * OuterProduct(k1, b2) + 6 * OuterProduct(k2, b1) + 8 * OuterProduct(k2, b2)) def test_operator_dagger(): A = Operator('A') B = Operator('B') assert Dagger(A*B) == Dagger(B)*Dagger(A) assert Dagger(A + B) == Dagger(A) + Dagger(B) assert Dagger(A**2) == Dagger(A)**2 def test_differential_operator(): x = Symbol('x') f = Function('f') d = DifferentialOperator(Derivative(f(x), x), f(x)) g = Wavefunction(x**2, x) assert qapply(d*g) == Wavefunction(2*x, x) assert d.expr == Derivative(f(x), x) assert d.function == f(x) assert d.variables == (x,) assert diff(d, x) == DifferentialOperator(Derivative(f(x), x, 2), f(x)) d = DifferentialOperator(Derivative(f(x), x, 2), f(x)) g = Wavefunction(x**3, x) assert qapply(d*g) == Wavefunction(6*x, x) assert d.expr == Derivative(f(x), x, 2) assert d.function == f(x) assert d.variables == (x,) assert diff(d, x) == DifferentialOperator(Derivative(f(x), x, 3), f(x)) d = DifferentialOperator(1/x*Derivative(f(x), x), f(x)) assert d.expr == 1/x*Derivative(f(x), x) assert d.function == f(x) assert d.variables == (x,) assert diff(d, x) == \ DifferentialOperator(Derivative(1/x*Derivative(f(x), x), x), f(x)) assert qapply(d*g) == Wavefunction(3*x, x) # 2D cartesian Laplacian y = Symbol('y') d = DifferentialOperator(Derivative(f(x, y), x, 2) + Derivative(f(x, y), y, 2), f(x, y)) w = Wavefunction(x**3*y**2 + y**3*x**2, x, y) assert d.expr == Derivative(f(x, y), x, 2) + Derivative(f(x, y), y, 2) assert d.function == f(x, y) assert d.variables == (x, y) assert diff(d, x) == \ DifferentialOperator(Derivative(d.expr, x), f(x, y)) assert diff(d, y) == \ DifferentialOperator(Derivative(d.expr, y), f(x, y)) assert qapply(d*w) == Wavefunction(2*x**3 + 6*x*y**2 + 6*x**2*y + 2*y**3, x, y) # 2D polar Laplacian (th = theta) r, th = symbols('r th') d = DifferentialOperator(1/r*Derivative(r*Derivative(f(r, th), r), r) + 1/(r**2)*Derivative(f(r, th), th, 2), f(r, th)) w = Wavefunction(r**2*sin(th), r, (th, 0, pi)) assert d.expr == \ 1/r*Derivative(r*Derivative(f(r, th), r), r) + \ 1/(r**2)*Derivative(f(r, th), th, 2) assert d.function == f(r, th) assert d.variables == (r, th) assert diff(d, r) == \ DifferentialOperator(Derivative(d.expr, r), f(r, th)) assert diff(d, th) == \ DifferentialOperator(Derivative(d.expr, th), f(r, th)) assert qapply(d*w) == Wavefunction(3*sin(th), r, (th, 0, pi)) sympy-sympy-1.9/sympy/physics/quantum/tests/test_operatorordering.py000066400000000000000000000025721412543434000264260ustar00rootroot00000000000000from sympy.physics.quantum import Dagger from sympy.physics.quantum.boson import BosonOp from sympy.physics.quantum.fermion import FermionOp from sympy.physics.quantum.operatorordering import (normal_order, normal_ordered_form) def test_normal_order(): a = BosonOp('a') c = FermionOp('c') assert normal_order(a * Dagger(a)) == Dagger(a) * a assert normal_order(Dagger(a) * a) == Dagger(a) * a assert normal_order(a * Dagger(a) ** 2) == Dagger(a) ** 2 * a assert normal_order(c * Dagger(c)) == - Dagger(c) * c assert normal_order(Dagger(c) * c) == Dagger(c) * c assert normal_order(c * Dagger(c) ** 2) == Dagger(c) ** 2 * c def test_normal_ordered_form(): a = BosonOp('a') c = FermionOp('c') assert normal_ordered_form(Dagger(a) * a) == Dagger(a) * a assert normal_ordered_form(a * Dagger(a)) == 1 + Dagger(a) * a assert normal_ordered_form(a ** 2 * Dagger(a)) == \ 2 * a + Dagger(a) * a ** 2 assert normal_ordered_form(a ** 3 * Dagger(a)) == \ 3 * a ** 2 + Dagger(a) * a ** 3 assert normal_ordered_form(Dagger(c) * c) == Dagger(c) * c assert normal_ordered_form(c * Dagger(c)) == 1 - Dagger(c) * c assert normal_ordered_form(c ** 2 * Dagger(c)) == Dagger(c) * c ** 2 assert normal_ordered_form(c ** 3 * Dagger(c)) == \ c ** 2 - Dagger(c) * c ** 3 sympy-sympy-1.9/sympy/physics/quantum/tests/test_operatorset.py000066400000000000000000000050651412543434000254100ustar00rootroot00000000000000from sympy import S from sympy.physics.quantum.operatorset import ( operators_to_state, state_to_operators ) from sympy.physics.quantum.cartesian import ( XOp, XKet, PxOp, PxKet, XBra, PxBra ) from sympy.physics.quantum.state import Ket, Bra from sympy.physics.quantum.operator import Operator from sympy.physics.quantum.spin import ( JxKet, JyKet, JzKet, JxBra, JyBra, JzBra, JxOp, JyOp, JzOp, J2Op ) from sympy.testing.pytest import raises def test_spin(): assert operators_to_state({J2Op, JxOp}) == JxKet assert operators_to_state({J2Op, JyOp}) == JyKet assert operators_to_state({J2Op, JzOp}) == JzKet assert operators_to_state({J2Op(), JxOp()}) == JxKet assert operators_to_state({J2Op(), JyOp()}) == JyKet assert operators_to_state({J2Op(), JzOp()}) == JzKet assert state_to_operators(JxKet) == {J2Op, JxOp} assert state_to_operators(JyKet) == {J2Op, JyOp} assert state_to_operators(JzKet) == {J2Op, JzOp} assert state_to_operators(JxBra) == {J2Op, JxOp} assert state_to_operators(JyBra) == {J2Op, JyOp} assert state_to_operators(JzBra) == {J2Op, JzOp} assert state_to_operators(JxKet(S.Half, S.Half)) == {J2Op(), JxOp()} assert state_to_operators(JyKet(S.Half, S.Half)) == {J2Op(), JyOp()} assert state_to_operators(JzKet(S.Half, S.Half)) == {J2Op(), JzOp()} assert state_to_operators(JxBra(S.Half, S.Half)) == {J2Op(), JxOp()} assert state_to_operators(JyBra(S.Half, S.Half)) == {J2Op(), JyOp()} assert state_to_operators(JzBra(S.Half, S.Half)) == {J2Op(), JzOp()} def test_op_to_state(): assert operators_to_state(XOp) == XKet() assert operators_to_state(PxOp) == PxKet() assert operators_to_state(Operator) == Ket() assert state_to_operators(operators_to_state(XOp("Q"))) == XOp("Q") assert state_to_operators(operators_to_state(XOp())) == XOp() raises(NotImplementedError, lambda: operators_to_state(XKet)) def test_state_to_op(): assert state_to_operators(XKet) == XOp() assert state_to_operators(PxKet) == PxOp() assert state_to_operators(XBra) == XOp() assert state_to_operators(PxBra) == PxOp() assert state_to_operators(Ket) == Operator() assert state_to_operators(Bra) == Operator() assert operators_to_state(state_to_operators(XKet("test"))) == XKet("test") assert operators_to_state(state_to_operators(XBra("test"))) == XKet("test") assert operators_to_state(state_to_operators(XKet())) == XKet() assert operators_to_state(state_to_operators(XBra())) == XKet() raises(NotImplementedError, lambda: state_to_operators(XOp)) sympy-sympy-1.9/sympy/physics/quantum/tests/test_pauli.py000066400000000000000000000113021412543434000241420ustar00rootroot00000000000000from sympy import I, Mul, latex, Matrix from sympy.physics.quantum import (Dagger, Commutator, AntiCommutator, qapply, Operator, represent) from sympy.physics.quantum.pauli import (SigmaOpBase, SigmaX, SigmaY, SigmaZ, SigmaMinus, SigmaPlus, qsimplify_pauli) from sympy.physics.quantum.pauli import SigmaZKet, SigmaZBra from sympy.testing.pytest import raises sx, sy, sz = SigmaX(), SigmaY(), SigmaZ() sx1, sy1, sz1 = SigmaX(1), SigmaY(1), SigmaZ(1) sx2, sy2, sz2 = SigmaX(2), SigmaY(2), SigmaZ(2) sm, sp = SigmaMinus(), SigmaPlus() sm1, sp1 = SigmaMinus(1), SigmaPlus(1) A, B = Operator("A"), Operator("B") def test_pauli_operators_types(): assert isinstance(sx, SigmaOpBase) and isinstance(sx, SigmaX) assert isinstance(sy, SigmaOpBase) and isinstance(sy, SigmaY) assert isinstance(sz, SigmaOpBase) and isinstance(sz, SigmaZ) assert isinstance(sm, SigmaOpBase) and isinstance(sm, SigmaMinus) assert isinstance(sp, SigmaOpBase) and isinstance(sp, SigmaPlus) def test_pauli_operators_commutator(): assert Commutator(sx, sy).doit() == 2 * I * sz assert Commutator(sy, sz).doit() == 2 * I * sx assert Commutator(sz, sx).doit() == 2 * I * sy def test_pauli_operators_commutator_with_labels(): assert Commutator(sx1, sy1).doit() == 2 * I * sz1 assert Commutator(sy1, sz1).doit() == 2 * I * sx1 assert Commutator(sz1, sx1).doit() == 2 * I * sy1 assert Commutator(sx2, sy2).doit() == 2 * I * sz2 assert Commutator(sy2, sz2).doit() == 2 * I * sx2 assert Commutator(sz2, sx2).doit() == 2 * I * sy2 assert Commutator(sx1, sy2).doit() == 0 assert Commutator(sy1, sz2).doit() == 0 assert Commutator(sz1, sx2).doit() == 0 def test_pauli_operators_anticommutator(): assert AntiCommutator(sy, sz).doit() == 0 assert AntiCommutator(sz, sx).doit() == 0 assert AntiCommutator(sx, sm).doit() == 1 assert AntiCommutator(sx, sp).doit() == 1 def test_pauli_operators_adjoint(): assert Dagger(sx) == sx assert Dagger(sy) == sy assert Dagger(sz) == sz def test_pauli_operators_adjoint_with_labels(): assert Dagger(sx1) == sx1 assert Dagger(sy1) == sy1 assert Dagger(sz1) == sz1 assert Dagger(sx1) != sx2 assert Dagger(sy1) != sy2 assert Dagger(sz1) != sz2 def test_pauli_operators_multiplication(): assert qsimplify_pauli(sx * sx) == 1 assert qsimplify_pauli(sy * sy) == 1 assert qsimplify_pauli(sz * sz) == 1 assert qsimplify_pauli(sx * sy) == I * sz assert qsimplify_pauli(sy * sz) == I * sx assert qsimplify_pauli(sz * sx) == I * sy assert qsimplify_pauli(sy * sx) == - I * sz assert qsimplify_pauli(sz * sy) == - I * sx assert qsimplify_pauli(sx * sz) == - I * sy def test_pauli_operators_multiplication_with_labels(): assert qsimplify_pauli(sx1 * sx1) == 1 assert qsimplify_pauli(sy1 * sy1) == 1 assert qsimplify_pauli(sz1 * sz1) == 1 assert isinstance(sx1 * sx2, Mul) assert isinstance(sy1 * sy2, Mul) assert isinstance(sz1 * sz2, Mul) assert qsimplify_pauli(sx1 * sy1 * sx2 * sy2) == - sz1 * sz2 assert qsimplify_pauli(sy1 * sz1 * sz2 * sx2) == - sx1 * sy2 def test_pauli_states(): sx, sz = SigmaX(), SigmaZ() up = SigmaZKet(0) down = SigmaZKet(1) assert qapply(sx * up) == down assert qapply(sx * down) == up assert qapply(sz * up) == up assert qapply(sz * down) == - down up = SigmaZBra(0) down = SigmaZBra(1) assert qapply(up * sx, dagger=True) == down assert qapply(down * sx, dagger=True) == up assert qapply(up * sz, dagger=True) == up assert qapply(down * sz, dagger=True) == - down assert Dagger(SigmaZKet(0)) == SigmaZBra(0) assert Dagger(SigmaZBra(1)) == SigmaZKet(1) raises(ValueError, lambda: SigmaZBra(2)) raises(ValueError, lambda: SigmaZKet(2)) def test_use_name(): assert sm.use_name is False assert sm1.use_name is True assert sx.use_name is False assert sx1.use_name is True def test_printing(): assert latex(sx) == r'{\sigma_x}' assert latex(sx1) == r'{\sigma_x^{(1)}}' assert latex(sy) == r'{\sigma_y}' assert latex(sy1) == r'{\sigma_y^{(1)}}' assert latex(sz) == r'{\sigma_z}' assert latex(sz1) == r'{\sigma_z^{(1)}}' assert latex(sm) == r'{\sigma_-}' assert latex(sm1) == r'{\sigma_-^{(1)}}' assert latex(sp) == r'{\sigma_+}' assert latex(sp1) == r'{\sigma_+^{(1)}}' def test_represent(): represent(sx) == Matrix([[0, 1], [1, 0]]) represent(sy) == Matrix([[0, -I], [I, 0]]) represent(sz) == Matrix([[1, 0], [0, -1]]) represent(sm) == Matrix([[0, 0], [1, 0]]) represent(sp) == Matrix([[0, 1], [0, 0]]) sympy-sympy-1.9/sympy/physics/quantum/tests/test_piab.py000066400000000000000000000015611412543434000237510ustar00rootroot00000000000000"""Tests for piab.py""" from sympy import Interval, pi, S, sin, sqrt, symbols from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.physics.quantum import L2, qapply, hbar, represent from sympy.physics.quantum.piab import PIABHamiltonian, PIABKet, PIABBra, m, L i, j, n, x = symbols('i j n x') def test_H(): assert PIABHamiltonian('H').hilbert_space == \ L2(Interval(S.NegativeInfinity, S.Infinity)) assert qapply(PIABHamiltonian('H')*PIABKet(n)) == \ (n**2*pi**2*hbar**2)/(2*m*L**2)*PIABKet(n) def test_states(): assert PIABKet(n).dual_class() == PIABBra assert PIABKet(n).hilbert_space == \ L2(Interval(S.NegativeInfinity, S.Infinity)) assert represent(PIABKet(n)) == sqrt(2/L)*sin(n*pi*x/L) assert (PIABBra(i)*PIABKet(j)).doit() == KroneckerDelta(i, j) assert PIABBra(n).dual_class() == PIABKet sympy-sympy-1.9/sympy/physics/quantum/tests/test_printing.py000066400000000000000000000725641412543434000247030ustar00rootroot00000000000000# -*- encoding: utf-8 -*- """ TODO: * Address Issue 2251, printing of spin states """ from typing import Dict, Any from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.cg import CG, Wigner3j, Wigner6j, Wigner9j from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.constants import hbar from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.gate import CGate, CNotGate, IdentityGate, UGate, XGate from sympy.physics.quantum.hilbert import ComplexSpace, FockSpace, HilbertSpace, L2 from sympy.physics.quantum.innerproduct import InnerProduct from sympy.physics.quantum.operator import Operator, OuterProduct, DifferentialOperator from sympy.physics.quantum.qexpr import QExpr from sympy.physics.quantum.qubit import Qubit, IntQubit from sympy.physics.quantum.spin import Jz, J2, JzBra, JzBraCoupled, JzKet, JzKetCoupled, Rotation, WignerD from sympy.physics.quantum.state import Bra, Ket, TimeDepBra, TimeDepKet from sympy.physics.quantum.tensorproduct import TensorProduct from sympy.physics.quantum.sho1d import RaisingOp from sympy import Derivative, Function, Interval, Matrix, Pow, S, symbols, Symbol, oo from sympy.testing.pytest import XFAIL # Imports used in srepr strings from sympy.physics.quantum.spin import JzOp from sympy.printing import srepr from sympy.printing.pretty import pretty as xpretty from sympy.printing.latex import latex MutableDenseMatrix = Matrix ENV = {} # type: Dict[str, Any] exec('from sympy import *', ENV) exec('from sympy.physics.quantum import *', ENV) exec('from sympy.physics.quantum.cg import *', ENV) exec('from sympy.physics.quantum.spin import *', ENV) exec('from sympy.physics.quantum.hilbert import *', ENV) exec('from sympy.physics.quantum.qubit import *', ENV) exec('from sympy.physics.quantum.qexpr import *', ENV) exec('from sympy.physics.quantum.gate import *', ENV) exec('from sympy.physics.quantum.constants import *', ENV) def sT(expr, string): """ sT := sreprTest from sympy/printing/tests/test_repr.py """ assert srepr(expr) == string assert eval(string, ENV) == expr def pretty(expr): """ASCII pretty-printing""" return xpretty(expr, use_unicode=False, wrap_line=False) def upretty(expr): """Unicode pretty-printing""" return xpretty(expr, use_unicode=True, wrap_line=False) def test_anticommutator(): A = Operator('A') B = Operator('B') ac = AntiCommutator(A, B) ac_tall = AntiCommutator(A**2, B) assert str(ac) == '{A,B}' assert pretty(ac) == '{A,B}' assert upretty(ac) == '{A,B}' assert latex(ac) == r'\left\{A,B\right\}' sT(ac, "AntiCommutator(Operator(Symbol('A')),Operator(Symbol('B')))") assert str(ac_tall) == '{A**2,B}' ascii_str = \ """\ / 2 \\\n\ \n\ \\ /\ """ ucode_str = \ """\ ⎧ 2 ⎫\n\ ⎨A ,B⎬\n\ ⎩ ⎭\ """ assert pretty(ac_tall) == ascii_str assert upretty(ac_tall) == ucode_str assert latex(ac_tall) == r'\left\{A^{2},B\right\}' sT(ac_tall, "AntiCommutator(Pow(Operator(Symbol('A')), Integer(2)),Operator(Symbol('B')))") def test_cg(): cg = CG(1, 2, 3, 4, 5, 6) wigner3j = Wigner3j(1, 2, 3, 4, 5, 6) wigner6j = Wigner6j(1, 2, 3, 4, 5, 6) wigner9j = Wigner9j(1, 2, 3, 4, 5, 6, 7, 8, 9) assert str(cg) == 'CG(1, 2, 3, 4, 5, 6)' ascii_str = \ """\ 5,6 \n\ C \n\ 1,2,3,4\ """ ucode_str = \ """\ 5,6 \n\ C \n\ 1,2,3,4\ """ assert pretty(cg) == ascii_str assert upretty(cg) == ucode_str assert latex(cg) == 'C^{5,6}_{1,2,3,4}' assert latex(cg ** 2) == R'\left(C^{5,6}_{1,2,3,4}\right)^{2}' sT(cg, "CG(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") assert str(wigner3j) == 'Wigner3j(1, 2, 3, 4, 5, 6)' ascii_str = \ """\ /1 3 5\\\n\ | |\n\ \\2 4 6/\ """ ucode_str = \ """\ ⎛1 3 5⎞\n\ ⎜ ⎟\n\ ⎝2 4 6⎠\ """ assert pretty(wigner3j) == ascii_str assert upretty(wigner3j) == ucode_str assert latex(wigner3j) == \ r'\left(\begin{array}{ccc} 1 & 3 & 5 \\ 2 & 4 & 6 \end{array}\right)' sT(wigner3j, "Wigner3j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") assert str(wigner6j) == 'Wigner6j(1, 2, 3, 4, 5, 6)' ascii_str = \ """\ /1 2 3\\\n\ < >\n\ \\4 5 6/\ """ ucode_str = \ """\ ⎧1 2 3⎫\n\ ⎨ ⎬\n\ ⎩4 5 6⎭\ """ assert pretty(wigner6j) == ascii_str assert upretty(wigner6j) == ucode_str assert latex(wigner6j) == \ r'\left\{\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \end{array}\right\}' sT(wigner6j, "Wigner6j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") assert str(wigner9j) == 'Wigner9j(1, 2, 3, 4, 5, 6, 7, 8, 9)' ascii_str = \ """\ /1 2 3\\\n\ | |\n\ <4 5 6>\n\ | |\n\ \\7 8 9/\ """ ucode_str = \ """\ ⎧1 2 3⎫\n\ ⎪ ⎪\n\ ⎨4 5 6⎬\n\ ⎪ ⎪\n\ ⎩7 8 9⎭\ """ assert pretty(wigner9j) == ascii_str assert upretty(wigner9j) == ucode_str assert latex(wigner9j) == \ r'\left\{\begin{array}{ccc} 1 & 2 & 3 \\ 4 & 5 & 6 \\ 7 & 8 & 9 \end{array}\right\}' sT(wigner9j, "Wigner9j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6), Integer(7), Integer(8), Integer(9))") def test_commutator(): A = Operator('A') B = Operator('B') c = Commutator(A, B) c_tall = Commutator(A**2, B) assert str(c) == '[A,B]' assert pretty(c) == '[A,B]' assert upretty(c) == '[A,B]' assert latex(c) == r'\left[A,B\right]' sT(c, "Commutator(Operator(Symbol('A')),Operator(Symbol('B')))") assert str(c_tall) == '[A**2,B]' ascii_str = \ """\ [ 2 ]\n\ [A ,B]\ """ ucode_str = \ """\ ⎡ 2 ⎤\n\ ⎣A ,B⎦\ """ assert pretty(c_tall) == ascii_str assert upretty(c_tall) == ucode_str assert latex(c_tall) == r'\left[A^{2},B\right]' sT(c_tall, "Commutator(Pow(Operator(Symbol('A')), Integer(2)),Operator(Symbol('B')))") def test_constants(): assert str(hbar) == 'hbar' assert pretty(hbar) == 'hbar' assert upretty(hbar) == 'ℏ' assert latex(hbar) == r'\hbar' sT(hbar, "HBar()") def test_dagger(): x = symbols('x') expr = Dagger(x) assert str(expr) == 'Dagger(x)' ascii_str = \ """\ +\n\ x \ """ ucode_str = \ """\ †\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str assert latex(expr) == r'x^{\dagger}' sT(expr, "Dagger(Symbol('x'))") @XFAIL def test_gate_failing(): a, b, c, d = symbols('a,b,c,d') uMat = Matrix([[a, b], [c, d]]) g = UGate((0,), uMat) assert str(g) == 'U(0)' def test_gate(): a, b, c, d = symbols('a,b,c,d') uMat = Matrix([[a, b], [c, d]]) q = Qubit(1, 0, 1, 0, 1) g1 = IdentityGate(2) g2 = CGate((3, 0), XGate(1)) g3 = CNotGate(1, 0) g4 = UGate((0,), uMat) assert str(g1) == '1(2)' assert pretty(g1) == '1 \n 2' assert upretty(g1) == '1 \n 2' assert latex(g1) == r'1_{2}' sT(g1, "IdentityGate(Integer(2))") assert str(g1*q) == '1(2)*|10101>' ascii_str = \ """\ 1 *|10101>\n\ 2 \ """ ucode_str = \ """\ 1 ⋅❘10101⟩\n\ 2 \ """ assert pretty(g1*q) == ascii_str assert upretty(g1*q) == ucode_str assert latex(g1*q) == r'1_{2} {\left|10101\right\rangle }' sT(g1*q, "Mul(IdentityGate(Integer(2)), Qubit(Integer(1),Integer(0),Integer(1),Integer(0),Integer(1)))") assert str(g2) == 'C((3,0),X(1))' ascii_str = \ """\ C /X \\\n\ 3,0\\ 1/\ """ ucode_str = \ """\ C ⎛X ⎞\n\ 3,0⎝ 1⎠\ """ assert pretty(g2) == ascii_str assert upretty(g2) == ucode_str assert latex(g2) == r'C_{3,0}{\left(X_{1}\right)}' sT(g2, "CGate(Tuple(Integer(3), Integer(0)),XGate(Integer(1)))") assert str(g3) == 'CNOT(1,0)' ascii_str = \ """\ CNOT \n\ 1,0\ """ ucode_str = \ """\ CNOT \n\ 1,0\ """ assert pretty(g3) == ascii_str assert upretty(g3) == ucode_str assert latex(g3) == r'CNOT_{1,0}' sT(g3, "CNotGate(Integer(1),Integer(0))") ascii_str = \ """\ U \n\ 0\ """ ucode_str = \ """\ U \n\ 0\ """ assert str(g4) == \ """\ U((0,),Matrix([\n\ [a, b],\n\ [c, d]]))\ """ assert pretty(g4) == ascii_str assert upretty(g4) == ucode_str assert latex(g4) == r'U_{0}' sT(g4, "UGate(Tuple(Integer(0)),MutableDenseMatrix([[Symbol('a'), Symbol('b')], [Symbol('c'), Symbol('d')]]))") def test_hilbert(): h1 = HilbertSpace() h2 = ComplexSpace(2) h3 = FockSpace() h4 = L2(Interval(0, oo)) assert str(h1) == 'H' assert pretty(h1) == 'H' assert upretty(h1) == 'H' assert latex(h1) == r'\mathcal{H}' sT(h1, "HilbertSpace()") assert str(h2) == 'C(2)' ascii_str = \ """\ 2\n\ C \ """ ucode_str = \ """\ 2\n\ C \ """ assert pretty(h2) == ascii_str assert upretty(h2) == ucode_str assert latex(h2) == r'\mathcal{C}^{2}' sT(h2, "ComplexSpace(Integer(2))") assert str(h3) == 'F' assert pretty(h3) == 'F' assert upretty(h3) == 'F' assert latex(h3) == r'\mathcal{F}' sT(h3, "FockSpace()") assert str(h4) == 'L2(Interval(0, oo))' ascii_str = \ """\ 2\n\ L \ """ ucode_str = \ """\ 2\n\ L \ """ assert pretty(h4) == ascii_str assert upretty(h4) == ucode_str assert latex(h4) == r'{\mathcal{L}^2}\left( \left[0, \infty\right) \right)' sT(h4, "L2(Interval(Integer(0), oo, false, true))") assert str(h1 + h2) == 'H+C(2)' ascii_str = \ """\ 2\n\ H + C \ """ ucode_str = \ """\ 2\n\ H ⊕ C \ """ assert pretty(h1 + h2) == ascii_str assert upretty(h1 + h2) == ucode_str assert latex(h1 + h2) sT(h1 + h2, "DirectSumHilbertSpace(HilbertSpace(),ComplexSpace(Integer(2)))") assert str(h1*h2) == "H*C(2)" ascii_str = \ """\ 2\n\ H x C \ """ ucode_str = \ """\ 2\n\ H ⨂ C \ """ assert pretty(h1*h2) == ascii_str assert upretty(h1*h2) == ucode_str assert latex(h1*h2) sT(h1*h2, "TensorProductHilbertSpace(HilbertSpace(),ComplexSpace(Integer(2)))") assert str(h1**2) == 'H**2' ascii_str = \ """\ x2\n\ H \ """ ucode_str = \ """\ ⨂2\n\ H \ """ assert pretty(h1**2) == ascii_str assert upretty(h1**2) == ucode_str assert latex(h1**2) == r'{\mathcal{H}}^{\otimes 2}' sT(h1**2, "TensorPowerHilbertSpace(HilbertSpace(),Integer(2))") def test_innerproduct(): x = symbols('x') ip1 = InnerProduct(Bra(), Ket()) ip2 = InnerProduct(TimeDepBra(), TimeDepKet()) ip3 = InnerProduct(JzBra(1, 1), JzKet(1, 1)) ip4 = InnerProduct(JzBraCoupled(1, 1, (1, 1)), JzKetCoupled(1, 1, (1, 1))) ip_tall1 = InnerProduct(Bra(x/2), Ket(x/2)) ip_tall2 = InnerProduct(Bra(x), Ket(x/2)) ip_tall3 = InnerProduct(Bra(x/2), Ket(x)) assert str(ip1) == '' assert pretty(ip1) == '' assert upretty(ip1) == '⟨ψ❘ψ⟩' assert latex( ip1) == r'\left\langle \psi \right. {\left|\psi\right\rangle }' sT(ip1, "InnerProduct(Bra(Symbol('psi')),Ket(Symbol('psi')))") assert str(ip2) == '' assert pretty(ip2) == '' assert upretty(ip2) == '⟨ψ;t❘ψ;t⟩' assert latex(ip2) == \ r'\left\langle \psi;t \right. {\left|\psi;t\right\rangle }' sT(ip2, "InnerProduct(TimeDepBra(Symbol('psi'),Symbol('t')),TimeDepKet(Symbol('psi'),Symbol('t')))") assert str(ip3) == "<1,1|1,1>" assert pretty(ip3) == '<1,1|1,1>' assert upretty(ip3) == '⟨1,1❘1,1⟩' assert latex(ip3) == r'\left\langle 1,1 \right. {\left|1,1\right\rangle }' sT(ip3, "InnerProduct(JzBra(Integer(1),Integer(1)),JzKet(Integer(1),Integer(1)))") assert str(ip4) == "<1,1,j1=1,j2=1|1,1,j1=1,j2=1>" assert pretty(ip4) == '<1,1,j1=1,j2=1|1,1,j1=1,j2=1>' assert upretty(ip4) == '⟨1,1,j₁=1,j₂=1❘1,1,j₁=1,j₂=1⟩' assert latex(ip4) == \ r'\left\langle 1,1,j_{1}=1,j_{2}=1 \right. {\left|1,1,j_{1}=1,j_{2}=1\right\rangle }' sT(ip4, "InnerProduct(JzBraCoupled(Integer(1),Integer(1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1)))),JzKetCoupled(Integer(1),Integer(1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1)))))") assert str(ip_tall1) == '' ascii_str = \ """\ / | \\ \n\ / x|x \\\n\ \\ -|- /\n\ \\2|2/ \ """ ucode_str = \ """\ ╱ │ ╲ \n\ ╱ x│x ╲\n\ ╲ ─│─ ╱\n\ ╲2│2╱ \ """ assert pretty(ip_tall1) == ascii_str assert upretty(ip_tall1) == ucode_str assert latex(ip_tall1) == \ r'\left\langle \frac{x}{2} \right. {\left|\frac{x}{2}\right\rangle }' sT(ip_tall1, "InnerProduct(Bra(Mul(Rational(1, 2), Symbol('x'))),Ket(Mul(Rational(1, 2), Symbol('x'))))") assert str(ip_tall2) == '' ascii_str = \ """\ / | \\ \n\ / |x \\\n\ \\ x|- /\n\ \\ |2/ \ """ ucode_str = \ """\ ╱ │ ╲ \n\ ╱ │x ╲\n\ ╲ x│─ ╱\n\ ╲ │2╱ \ """ assert pretty(ip_tall2) == ascii_str assert upretty(ip_tall2) == ucode_str assert latex(ip_tall2) == \ r'\left\langle x \right. {\left|\frac{x}{2}\right\rangle }' sT(ip_tall2, "InnerProduct(Bra(Symbol('x')),Ket(Mul(Rational(1, 2), Symbol('x'))))") assert str(ip_tall3) == '' ascii_str = \ """\ / | \\ \n\ / x| \\\n\ \\ -|x /\n\ \\2| / \ """ ucode_str = \ """\ ╱ │ ╲ \n\ ╱ x│ ╲\n\ ╲ ─│x ╱\n\ ╲2│ ╱ \ """ assert pretty(ip_tall3) == ascii_str assert upretty(ip_tall3) == ucode_str assert latex(ip_tall3) == \ r'\left\langle \frac{x}{2} \right. {\left|x\right\rangle }' sT(ip_tall3, "InnerProduct(Bra(Mul(Rational(1, 2), Symbol('x'))),Ket(Symbol('x')))") def test_operator(): a = Operator('A') b = Operator('B', Symbol('t'), S.Half) inv = a.inv() f = Function('f') x = symbols('x') d = DifferentialOperator(Derivative(f(x), x), f(x)) op = OuterProduct(Ket(), Bra()) assert str(a) == 'A' assert pretty(a) == 'A' assert upretty(a) == 'A' assert latex(a) == 'A' sT(a, "Operator(Symbol('A'))") assert str(inv) == 'A**(-1)' ascii_str = \ """\ -1\n\ A \ """ ucode_str = \ """\ -1\n\ A \ """ assert pretty(inv) == ascii_str assert upretty(inv) == ucode_str assert latex(inv) == r'A^{-1}' sT(inv, "Pow(Operator(Symbol('A')), Integer(-1))") assert str(d) == 'DifferentialOperator(Derivative(f(x), x),f(x))' ascii_str = \ """\ /d \\\n\ DifferentialOperator|--(f(x)),f(x)|\n\ \\dx /\ """ ucode_str = \ """\ ⎛d ⎞\n\ DifferentialOperator⎜──(f(x)),f(x)⎟\n\ ⎝dx ⎠\ """ assert pretty(d) == ascii_str assert upretty(d) == ucode_str assert latex(d) == \ r'DifferentialOperator\left(\frac{d}{d x} f{\left(x \right)},f{\left(x \right)}\right)' sT(d, "DifferentialOperator(Derivative(Function('f')(Symbol('x')), Tuple(Symbol('x'), Integer(1))),Function('f')(Symbol('x')))") assert str(b) == 'Operator(B,t,1/2)' assert pretty(b) == 'Operator(B,t,1/2)' assert upretty(b) == 'Operator(B,t,1/2)' assert latex(b) == r'Operator\left(B,t,\frac{1}{2}\right)' sT(b, "Operator(Symbol('B'),Symbol('t'),Rational(1, 2))") assert str(op) == '|psi>' assert pretty(q1) == '|0101>' assert upretty(q1) == '❘0101⟩' assert latex(q1) == r'{\left|0101\right\rangle }' sT(q1, "Qubit(Integer(0),Integer(1),Integer(0),Integer(1))") assert str(q2) == '|8>' assert pretty(q2) == '|8>' assert upretty(q2) == '❘8⟩' assert latex(q2) == r'{\left|8\right\rangle }' sT(q2, "IntQubit(8)") def test_spin(): lz = JzOp('L') ket = JzKet(1, 0) bra = JzBra(1, 0) cket = JzKetCoupled(1, 0, (1, 2)) cbra = JzBraCoupled(1, 0, (1, 2)) cket_big = JzKetCoupled(1, 0, (1, 2, 3)) cbra_big = JzBraCoupled(1, 0, (1, 2, 3)) rot = Rotation(1, 2, 3) bigd = WignerD(1, 2, 3, 4, 5, 6) smalld = WignerD(1, 2, 3, 0, 4, 0) assert str(lz) == 'Lz' ascii_str = \ """\ L \n\ z\ """ ucode_str = \ """\ L \n\ z\ """ assert pretty(lz) == ascii_str assert upretty(lz) == ucode_str assert latex(lz) == 'L_z' sT(lz, "JzOp(Symbol('L'))") assert str(J2) == 'J2' ascii_str = \ """\ 2\n\ J \ """ ucode_str = \ """\ 2\n\ J \ """ assert pretty(J2) == ascii_str assert upretty(J2) == ucode_str assert latex(J2) == r'J^2' sT(J2, "J2Op(Symbol('J'))") assert str(Jz) == 'Jz' ascii_str = \ """\ J \n\ z\ """ ucode_str = \ """\ J \n\ z\ """ assert pretty(Jz) == ascii_str assert upretty(Jz) == ucode_str assert latex(Jz) == 'J_z' sT(Jz, "JzOp(Symbol('J'))") assert str(ket) == '|1,0>' assert pretty(ket) == '|1,0>' assert upretty(ket) == '❘1,0⟩' assert latex(ket) == r'{\left|1,0\right\rangle }' sT(ket, "JzKet(Integer(1),Integer(0))") assert str(bra) == '<1,0|' assert pretty(bra) == '<1,0|' assert upretty(bra) == '⟨1,0❘' assert latex(bra) == r'{\left\langle 1,0\right|}' sT(bra, "JzBra(Integer(1),Integer(0))") assert str(cket) == '|1,0,j1=1,j2=2>' assert pretty(cket) == '|1,0,j1=1,j2=2>' assert upretty(cket) == '❘1,0,j₁=1,j₂=2⟩' assert latex(cket) == r'{\left|1,0,j_{1}=1,j_{2}=2\right\rangle }' sT(cket, "JzKetCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))") assert str(cbra) == '<1,0,j1=1,j2=2|' assert pretty(cbra) == '<1,0,j1=1,j2=2|' assert upretty(cbra) == '⟨1,0,j₁=1,j₂=2❘' assert latex(cbra) == r'{\left\langle 1,0,j_{1}=1,j_{2}=2\right|}' sT(cbra, "JzBraCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))") assert str(cket_big) == '|1,0,j1=1,j2=2,j3=3,j(1,2)=3>' # TODO: Fix non-unicode pretty printing # i.e. j1,2 -> j(1,2) assert pretty(cket_big) == '|1,0,j1=1,j2=2,j3=3,j1,2=3>' assert upretty(cket_big) == '❘1,0,j₁=1,j₂=2,j₃=3,j₁,₂=3⟩' assert latex(cket_big) == \ r'{\left|1,0,j_{1}=1,j_{2}=2,j_{3}=3,j_{1,2}=3\right\rangle }' sT(cket_big, "JzKetCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2), Integer(3)),Tuple(Tuple(Integer(1), Integer(2), Integer(3)), Tuple(Integer(1), Integer(3), Integer(1))))") assert str(cbra_big) == '<1,0,j1=1,j2=2,j3=3,j(1,2)=3|' assert pretty(cbra_big) == '<1,0,j1=1,j2=2,j3=3,j1,2=3|' assert upretty(cbra_big) == '⟨1,0,j₁=1,j₂=2,j₃=3,j₁,₂=3❘' assert latex(cbra_big) == \ r'{\left\langle 1,0,j_{1}=1,j_{2}=2,j_{3}=3,j_{1,2}=3\right|}' sT(cbra_big, "JzBraCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(2), Integer(3)),Tuple(Tuple(Integer(1), Integer(2), Integer(3)), Tuple(Integer(1), Integer(3), Integer(1))))") assert str(rot) == 'R(1,2,3)' assert pretty(rot) == 'R (1,2,3)' assert upretty(rot) == 'ℛ (1,2,3)' assert latex(rot) == r'\mathcal{R}\left(1,2,3\right)' sT(rot, "Rotation(Integer(1),Integer(2),Integer(3))") assert str(bigd) == 'WignerD(1, 2, 3, 4, 5, 6)' ascii_str = \ """\ 1 \n\ D (4,5,6)\n\ 2,3 \ """ ucode_str = \ """\ 1 \n\ D (4,5,6)\n\ 2,3 \ """ assert pretty(bigd) == ascii_str assert upretty(bigd) == ucode_str assert latex(bigd) == r'D^{1}_{2,3}\left(4,5,6\right)' sT(bigd, "WignerD(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6))") assert str(smalld) == 'WignerD(1, 2, 3, 0, 4, 0)' ascii_str = \ """\ 1 \n\ d (4)\n\ 2,3 \ """ ucode_str = \ """\ 1 \n\ d (4)\n\ 2,3 \ """ assert pretty(smalld) == ascii_str assert upretty(smalld) == ucode_str assert latex(smalld) == r'd^{1}_{2,3}\left(4\right)' sT(smalld, "WignerD(Integer(1), Integer(2), Integer(3), Integer(0), Integer(4), Integer(0))") def test_state(): x = symbols('x') bra = Bra() ket = Ket() bra_tall = Bra(x/2) ket_tall = Ket(x/2) tbra = TimeDepBra() tket = TimeDepKet() assert str(bra) == '' assert pretty(ket) == '|psi>' assert upretty(ket) == '❘ψ⟩' assert latex(ket) == r'{\left|\psi\right\rangle }' sT(ket, "Ket(Symbol('psi'))") assert str(bra_tall) == '' ascii_str = \ """\ | \\ \n\ |x \\\n\ |- /\n\ |2/ \ """ ucode_str = \ """\ │ ╲ \n\ │x ╲\n\ │─ ╱\n\ │2╱ \ """ assert pretty(ket_tall) == ascii_str assert upretty(ket_tall) == ucode_str assert latex(ket_tall) == r'{\left|\frac{x}{2}\right\rangle }' sT(ket_tall, "Ket(Mul(Rational(1, 2), Symbol('x')))") assert str(tbra) == '' assert pretty(tket) == '|psi;t>' assert upretty(tket) == '❘ψ;t⟩' assert latex(tket) == r'{\left|\psi;t\right\rangle }' sT(tket, "TimeDepKet(Symbol('psi'),Symbol('t'))") def test_tensorproduct(): tp = TensorProduct(JzKet(1, 1), JzKet(1, 0)) assert str(tp) == '|1,1>x|1,0>' assert pretty(tp) == '|1,1>x |1,0>' assert upretty(tp) == '❘1,1⟩⨂ ❘1,0⟩' assert latex(tp) == \ r'{{\left|1,1\right\rangle }}\otimes {{\left|1,0\right\rangle }}' sT(tp, "TensorProduct(JzKet(Integer(1),Integer(1)), JzKet(Integer(1),Integer(0)))") def test_big_expr(): f = Function('f') x = symbols('x') e1 = Dagger(AntiCommutator(Operator('A') + Operator('B'), Pow(DifferentialOperator(Derivative(f(x), x), f(x)), 3))*TensorProduct(Jz**2, Operator('A') + Operator('B')))*(JzBra(1, 0) + JzBra(1, 1))*(JzKet(0, 0) + JzKet(1, -1)) e2 = Commutator(Jz**2, Operator('A') + Operator('B'))*AntiCommutator(Dagger(Operator('C')*Operator('D')), Operator('E').inv()**2)*Dagger(Commutator(Jz, J2)) e3 = Wigner3j(1, 2, 3, 4, 5, 6)*TensorProduct(Commutator(Operator('A') + Dagger(Operator('B')), Operator('C') + Operator('D')), Jz - J2)*Dagger(OuterProduct(Dagger(JzBra(1, 1)), JzBra(1, 0)))*TensorProduct(JzKetCoupled(1, 1, (1, 1)) + JzKetCoupled(1, 0, (1, 1)), JzKetCoupled(1, -1, (1, 1))) e4 = (ComplexSpace(1)*ComplexSpace(2) + FockSpace()**2)*(L2(Interval( 0, oo)) + HilbertSpace()) assert str(e1) == '(Jz**2)x(Dagger(A) + Dagger(B))*{Dagger(DifferentialOperator(Derivative(f(x), x),f(x)))**3,Dagger(A) + Dagger(B)}*(<1,0| + <1,1|)*(|0,0> + |1,-1>)' ascii_str = \ """\ / 3 \\ \n\ |/ +\\ | \n\ 2 / + +\\ <| /d \\ | + +> \n\ /J \\ x \\A + B /*||DifferentialOperator|--(f(x)),f(x)| | ,A + B |*(<1,0| + <1,1|)*(|0,0> + |1,-1>)\n\ \\ z/ \\\\ \\dx / / / \ """ ucode_str = \ """\ ⎧ 3 ⎫ \n\ ⎪⎛ †⎞ ⎪ \n\ 2 ⎛ † †⎞ ⎨⎜ ⎛d ⎞ ⎟ † †⎬ \n\ ⎛J ⎞ ⨂ ⎝A + B ⎠⋅⎪⎜DifferentialOperator⎜──(f(x)),f(x)⎟ ⎟ ,A + B ⎪⋅(⟨1,0❘ + ⟨1,1❘)⋅(❘0,0⟩ + ❘1,-1⟩)\n\ ⎝ z⎠ ⎩⎝ ⎝dx ⎠ ⎠ ⎭ \ """ assert pretty(e1) == ascii_str assert upretty(e1) == ucode_str assert latex(e1) == \ r'{J_z^{2}}\otimes \left({A^{\dagger} + B^{\dagger}}\right) \left\{\left(DifferentialOperator\left(\frac{d}{d x} f{\left(x \right)},f{\left(x \right)}\right)^{\dagger}\right)^{3},A^{\dagger} + B^{\dagger}\right\} \left({\left\langle 1,0\right|} + {\left\langle 1,1\right|}\right) \left({\left|0,0\right\rangle } + {\left|1,-1\right\rangle }\right)' sT(e1, "Mul(TensorProduct(Pow(JzOp(Symbol('J')), Integer(2)), Add(Dagger(Operator(Symbol('A'))), Dagger(Operator(Symbol('B'))))), AntiCommutator(Pow(Dagger(DifferentialOperator(Derivative(Function('f')(Symbol('x')), Tuple(Symbol('x'), Integer(1))),Function('f')(Symbol('x')))), Integer(3)),Add(Dagger(Operator(Symbol('A'))), Dagger(Operator(Symbol('B'))))), Add(JzBra(Integer(1),Integer(0)), JzBra(Integer(1),Integer(1))), Add(JzKet(Integer(0),Integer(0)), JzKet(Integer(1),Integer(-1))))") assert str(e2) == '[Jz**2,A + B]*{E**(-2),Dagger(D)*Dagger(C)}*[J2,Jz]' ascii_str = \ """\ [ 2 ] / -2 + +\\ [ 2 ]\n\ [/J \\ ,A + B]**[J ,J ]\n\ [\\ z/ ] \\ / [ z]\ """ ucode_str = \ """\ ⎡ 2 ⎤ ⎧ -2 † †⎫ ⎡ 2 ⎤\n\ ⎢⎛J ⎞ ,A + B⎥⋅⎨E ,D ⋅C ⎬⋅⎢J ,J ⎥\n\ ⎣⎝ z⎠ ⎦ ⎩ ⎭ ⎣ z⎦\ """ assert pretty(e2) == ascii_str assert upretty(e2) == ucode_str assert latex(e2) == \ r'\left[J_z^{2},A + B\right] \left\{E^{-2},D^{\dagger} C^{\dagger}\right\} \left[J^2,J_z\right]' sT(e2, "Mul(Commutator(Pow(JzOp(Symbol('J')), Integer(2)),Add(Operator(Symbol('A')), Operator(Symbol('B')))), AntiCommutator(Pow(Operator(Symbol('E')), Integer(-2)),Mul(Dagger(Operator(Symbol('D'))), Dagger(Operator(Symbol('C'))))), Commutator(J2Op(Symbol('J')),JzOp(Symbol('J'))))") assert str(e3) == \ "Wigner3j(1, 2, 3, 4, 5, 6)*[Dagger(B) + A,C + D]x(-J2 + Jz)*|1,0><1,1|*(|1,0,j1=1,j2=1> + |1,1,j1=1,j2=1>)x|1,-1,j1=1,j2=1>" ascii_str = \ """\ [ + ] / 2 \\ \n\ /1 3 5\\*[B + A,C + D]x |- J + J |*|1,0><1,1|*(|1,0,j1=1,j2=1> + |1,1,j1=1,j2=1>)x |1,-1,j1=1,j2=1>\n\ | | \\ z/ \n\ \\2 4 6/ \ """ ucode_str = \ """\ ⎡ † ⎤ ⎛ 2 ⎞ \n\ ⎛1 3 5⎞⋅⎣B + A,C + D⎦⨂ ⎜- J + J ⎟⋅❘1,0⟩⟨1,1❘⋅(❘1,0,j₁=1,j₂=1⟩ + ❘1,1,j₁=1,j₂=1⟩)⨂ ❘1,-1,j₁=1,j₂=1⟩\n\ ⎜ ⎟ ⎝ z⎠ \n\ ⎝2 4 6⎠ \ """ assert pretty(e3) == ascii_str assert upretty(e3) == ucode_str assert latex(e3) == \ r'\left(\begin{array}{ccc} 1 & 3 & 5 \\ 2 & 4 & 6 \end{array}\right) {\left[B^{\dagger} + A,C + D\right]}\otimes \left({- J^2 + J_z}\right) {\left|1,0\right\rangle }{\left\langle 1,1\right|} \left({{\left|1,0,j_{1}=1,j_{2}=1\right\rangle } + {\left|1,1,j_{1}=1,j_{2}=1\right\rangle }}\right)\otimes {{\left|1,-1,j_{1}=1,j_{2}=1\right\rangle }}' sT(e3, "Mul(Wigner3j(Integer(1), Integer(2), Integer(3), Integer(4), Integer(5), Integer(6)), TensorProduct(Commutator(Add(Dagger(Operator(Symbol('B'))), Operator(Symbol('A'))),Add(Operator(Symbol('C')), Operator(Symbol('D')))), Add(Mul(Integer(-1), J2Op(Symbol('J'))), JzOp(Symbol('J')))), OuterProduct(JzKet(Integer(1),Integer(0)),JzBra(Integer(1),Integer(1))), TensorProduct(Add(JzKetCoupled(Integer(1),Integer(0),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1)))), JzKetCoupled(Integer(1),Integer(1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))), JzKetCoupled(Integer(1),Integer(-1),Tuple(Integer(1), Integer(1)),Tuple(Tuple(Integer(1), Integer(2), Integer(1))))))") assert str(e4) == '(C(1)*C(2)+F**2)*(L2(Interval(0, oo))+H)' ascii_str = \ """\ // 1 2\\ x2\\ / 2 \\\n\ \\\\C x C / + F / x \\L + H/\ """ ucode_str = \ """\ ⎛⎛ 1 2⎞ ⨂2⎞ ⎛ 2 ⎞\n\ ⎝⎝C ⨂ C ⎠ ⊕ F ⎠ ⨂ ⎝L ⊕ H⎠\ """ assert pretty(e4) == ascii_str assert upretty(e4) == ucode_str assert latex(e4) == \ r'\left(\left(\mathcal{C}^{1}\otimes \mathcal{C}^{2}\right)\oplus {\mathcal{F}}^{\otimes 2}\right)\otimes \left({\mathcal{L}^2}\left( \left[0, \infty\right) \right)\oplus \mathcal{H}\right)' sT(e4, "TensorProductHilbertSpace((DirectSumHilbertSpace(TensorProductHilbertSpace(ComplexSpace(Integer(1)),ComplexSpace(Integer(2))),TensorPowerHilbertSpace(FockSpace(),Integer(2)))),(DirectSumHilbertSpace(L2(Interval(Integer(0), oo, false, true)),HilbertSpace())))") def _test_sho1d(): ad = RaisingOp('a') assert pretty(ad) == ' \N{DAGGER}\na ' assert latex(ad) == 'a^{\\dagger}' sympy-sympy-1.9/sympy/physics/quantum/tests/test_qapply.py000066400000000000000000000105261412543434000243450ustar00rootroot00000000000000from sympy import I, Integer, sqrt, symbols, S, Mul, Rational from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.constants import hbar from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.gate import H from sympy.physics.quantum.operator import Operator from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.spin import Jx, Jy, Jz, Jplus, Jminus, J2, JzKet from sympy.physics.quantum.tensorproduct import TensorProduct from sympy.physics.quantum.state import Ket from sympy.physics.quantum.density import Density from sympy.physics.quantum.qubit import Qubit from sympy.physics.quantum.boson import BosonOp, BosonFockKet, BosonFockBra j, jp, m, mp = symbols("j j' m m'") z = JzKet(1, 0) po = JzKet(1, 1) mo = JzKet(1, -1) A = Operator('A') class Foo(Operator): def _apply_operator_JzKet(self, ket, **options): return ket def test_basic(): assert qapply(Jz*po) == hbar*po assert qapply(Jx*z) == hbar*po/sqrt(2) + hbar*mo/sqrt(2) assert qapply((Jplus + Jminus)*z/sqrt(2)) == hbar*po + hbar*mo assert qapply(Jz*(po + mo)) == hbar*po - hbar*mo assert qapply(Jz*po + Jz*mo) == hbar*po - hbar*mo assert qapply(Jminus*Jminus*po) == 2*hbar**2*mo assert qapply(Jplus**2*mo) == 2*hbar**2*po assert qapply(Jplus**2*Jminus**2*po) == 4*hbar**4*po def test_extra(): extra = z.dual*A*z assert qapply(Jz*po*extra) == hbar*po*extra assert qapply(Jx*z*extra) == (hbar*po/sqrt(2) + hbar*mo/sqrt(2))*extra assert qapply( (Jplus + Jminus)*z/sqrt(2)*extra) == hbar*po*extra + hbar*mo*extra assert qapply(Jz*(po + mo)*extra) == hbar*po*extra - hbar*mo*extra assert qapply(Jz*po*extra + Jz*mo*extra) == hbar*po*extra - hbar*mo*extra assert qapply(Jminus*Jminus*po*extra) == 2*hbar**2*mo*extra assert qapply(Jplus**2*mo*extra) == 2*hbar**2*po*extra assert qapply(Jplus**2*Jminus**2*po*extra) == 4*hbar**4*po*extra def test_innerproduct(): assert qapply(po.dual*Jz*po, ip_doit=False) == hbar*(po.dual*po) assert qapply(po.dual*Jz*po) == hbar def test_zero(): assert qapply(0) == 0 assert qapply(Integer(0)) == 0 def test_commutator(): assert qapply(Commutator(Jx, Jy)*Jz*po) == I*hbar**3*po assert qapply(Commutator(J2, Jz)*Jz*po) == 0 assert qapply(Commutator(Jz, Foo('F'))*po) == 0 assert qapply(Commutator(Foo('F'), Jz)*po) == 0 def test_anticommutator(): assert qapply(AntiCommutator(Jz, Foo('F'))*po) == 2*hbar*po assert qapply(AntiCommutator(Foo('F'), Jz)*po) == 2*hbar*po def test_outerproduct(): e = Jz*(mo*po.dual)*Jz*po assert qapply(e) == -hbar**2*mo assert qapply(e, ip_doit=False) == -hbar**2*(po.dual*po)*mo assert qapply(e).doit() == -hbar**2*mo def test_tensorproduct(): a = BosonOp("a") b = BosonOp("b") ket1 = TensorProduct(BosonFockKet(1), BosonFockKet(2)) ket2 = TensorProduct(BosonFockKet(0), BosonFockKet(0)) ket3 = TensorProduct(BosonFockKet(0), BosonFockKet(2)) bra1 = TensorProduct(BosonFockBra(0), BosonFockBra(0)) bra2 = TensorProduct(BosonFockBra(1), BosonFockBra(2)) assert qapply(TensorProduct(a, b ** 2) * ket1) == sqrt(2) * ket2 assert qapply(TensorProduct(a, Dagger(b) * b) * ket1) == 2 * ket3 assert qapply(bra1 * TensorProduct(a, b * b), dagger=True) == sqrt(2) * bra2 assert qapply(bra2 * ket1).doit() == TensorProduct(1, 1) assert qapply(TensorProduct(a, b * b) * ket1) == sqrt(2) * ket2 assert qapply(Dagger(TensorProduct(a, b * b) * ket1), dagger=True) == sqrt(2) * Dagger(ket2) def test_dagger(): lhs = Dagger(Qubit(0))*Dagger(H(0)) rhs = Dagger(Qubit(1))/sqrt(2) + Dagger(Qubit(0))/sqrt(2) assert qapply(lhs, dagger=True) == rhs def test_issue_6073(): x, y = symbols('x y', commutative=False) A = Ket(x, y) B = Operator('B') assert qapply(A) == A assert qapply(A.dual*B) == A.dual*B def test_density(): d = Density([Jz*mo, 0.5], [Jz*po, 0.5]) assert qapply(d) == Density([-hbar*mo, 0.5], [hbar*po, 0.5]) def test_issue3044(): expr1 = TensorProduct(Jz*JzKet(S(2),S.NegativeOne)/sqrt(2), Jz*JzKet(S.Half,S.Half)) result = Mul(S.NegativeOne, Rational(1, 4), 2**S.Half, hbar**2) result *= TensorProduct(JzKet(2,-1), JzKet(S.Half,S.Half)) assert qapply(expr1) == result sympy-sympy-1.9/sympy/physics/quantum/tests/test_qasm.py000066400000000000000000000060071412543434000237770ustar00rootroot00000000000000from sympy.physics.quantum.qasm import Qasm, prod, flip_index, trim,\ get_index, nonblank, fullsplit, fixcommand, stripquotes, read_qasm from sympy.physics.quantum.gate import X, Z, H, S, T from sympy.physics.quantum.gate import CNOT, SWAP, CPHASE, CGate, CGateS from sympy.physics.quantum.circuitplot import Mz def test_qasm_readqasm(): qasm_lines = """\ qubit q_0 qubit q_1 h q_0 cnot q_0,q_1 """ q = read_qasm(qasm_lines) assert q.get_circuit() == CNOT(1,0)*H(1) def test_qasm_ex1(): q = Qasm('qubit q0', 'qubit q1', 'h q0', 'cnot q0,q1') assert q.get_circuit() == CNOT(1,0)*H(1) def test_qasm_ex1_methodcalls(): q = Qasm() q.qubit('q_0') q.qubit('q_1') q.h('q_0') q.cnot('q_0', 'q_1') assert q.get_circuit() == CNOT(1,0)*H(1) def test_qasm_swap(): q = Qasm('qubit q0', 'qubit q1', 'cnot q0,q1', 'cnot q1,q0', 'cnot q0,q1') assert q.get_circuit() == CNOT(1,0)*CNOT(0,1)*CNOT(1,0) def test_qasm_ex2(): q = Qasm('qubit q_0', 'qubit q_1', 'qubit q_2', 'h q_1', 'cnot q_1,q_2', 'cnot q_0,q_1', 'h q_0', 'measure q_1', 'measure q_0', 'c-x q_1,q_2', 'c-z q_0,q_2') assert q.get_circuit() == CGate(2,Z(0))*CGate(1,X(0))*Mz(2)*Mz(1)*H(2)*CNOT(2,1)*CNOT(1,0)*H(1) def test_qasm_1q(): for symbol, gate in [('x', X), ('z', Z), ('h', H), ('s', S), ('t', T), ('measure', Mz)]: q = Qasm('qubit q_0', '%s q_0' % symbol) assert q.get_circuit() == gate(0) def test_qasm_2q(): for symbol, gate in [('cnot', CNOT), ('swap', SWAP), ('cphase', CPHASE)]: q = Qasm('qubit q_0', 'qubit q_1', '%s q_0,q_1' % symbol) assert q.get_circuit() == gate(1,0) def test_qasm_3q(): q = Qasm('qubit q0', 'qubit q1', 'qubit q2', 'toffoli q2,q1,q0') assert q.get_circuit() == CGateS((0,1),X(2)) def test_qasm_prod(): assert prod([1, 2, 3]) == 6 assert prod([H(0), X(1)])== H(0)*X(1) def test_qasm_flip_index(): assert flip_index(0, 2) == 1 assert flip_index(1, 2) == 0 def test_qasm_trim(): assert trim('nothing happens here') == 'nothing happens here' assert trim("Something #happens here") == "Something " def test_qasm_get_index(): assert get_index('q0', ['q0', 'q1']) == 1 assert get_index('q1', ['q0', 'q1']) == 0 def test_qasm_nonblank(): assert list(nonblank('abcd')) == list('abcd') assert list(nonblank('abc ')) == list('abc') def test_qasm_fullsplit(): assert fullsplit('g q0,q1,q2, q3') == ('g', ['q0', 'q1', 'q2', 'q3']) def test_qasm_fixcommand(): assert fixcommand('foo') == 'foo' assert fixcommand('def') == 'qdef' def test_qasm_stripquotes(): assert stripquotes("'S'") == 'S' assert stripquotes('"S"') == 'S' assert stripquotes('S') == 'S' def test_qasm_qdef(): # weaker test condition (str) since we don't have access to the actual class q = Qasm("def Q,0,Q",'qubit q0','Q q0') assert str(q.get_circuit()) == 'Q(0)' q = Qasm("def CQ,1,Q", 'qubit q0', 'qubit q1', 'CQ q0,q1') assert str(q.get_circuit()) == 'C((1),Q(0))' sympy-sympy-1.9/sympy/physics/quantum/tests/test_qexpr.py000066400000000000000000000026611412543434000241770ustar00rootroot00000000000000from sympy import Symbol, Integer from sympy.physics.quantum.qexpr import QExpr, _qsympify_sequence from sympy.physics.quantum.hilbert import HilbertSpace from sympy.core.containers import Tuple x = Symbol('x') y = Symbol('y') def test_qexpr_new(): q = QExpr(0) assert q.label == (0,) assert q.hilbert_space == HilbertSpace() assert q.is_commutative is False q = QExpr(0, 1) assert q.label == (Integer(0), Integer(1)) q = QExpr._new_rawargs(HilbertSpace(), Integer(0), Integer(1)) assert q.label == (Integer(0), Integer(1)) assert q.hilbert_space == HilbertSpace() def test_qexpr_commutative(): q1 = QExpr(x) q2 = QExpr(y) assert q1.is_commutative is False assert q2.is_commutative is False assert q1*q2 != q2*q1 q = QExpr._new_rawargs(0, 1, HilbertSpace()) assert q.is_commutative is False def test_qexpr_commutative_free_symbols(): q1 = QExpr(x) assert q1.free_symbols.pop().is_commutative is False q2 = QExpr('q2') assert q2.free_symbols.pop().is_commutative is False def test_qexpr_subs(): q1 = QExpr(x, y) assert q1.subs(x, y) == QExpr(y, y) assert q1.subs({x: 1, y: 2}) == QExpr(1, 2) def test_qsympify(): assert _qsympify_sequence([[1, 2], [1, 3]]) == (Tuple(1, 2), Tuple(1, 3)) assert _qsympify_sequence(([1, 2, [3, 4, [2, ]], 1], 3)) == \ (Tuple(1, 2, Tuple(3, 4, Tuple(2,)), 1), 3) assert _qsympify_sequence((1,)) == (1,) sympy-sympy-1.9/sympy/physics/quantum/tests/test_qft.py000066400000000000000000000032231412543434000236250ustar00rootroot00000000000000from sympy import exp, I, Matrix, pi, sqrt, Symbol from sympy.physics.quantum.qft import QFT, IQFT, RkGate from sympy.physics.quantum.gate import (ZGate, SwapGate, HadamardGate, CGate, PhaseGate, TGate) from sympy.physics.quantum.qubit import Qubit from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.represent import represent def test_RkGate(): x = Symbol('x') assert RkGate(1, x).k == x assert RkGate(1, x).targets == (1,) assert RkGate(1, 1) == ZGate(1) assert RkGate(2, 2) == PhaseGate(2) assert RkGate(3, 3) == TGate(3) assert represent( RkGate(0, x), nqubits=1) == Matrix([[1, 0], [0, exp(2*I*pi/2**x)]]) def test_quantum_fourier(): assert QFT(0, 3).decompose() == \ SwapGate(0, 2)*HadamardGate(0)*CGate((0,), PhaseGate(1)) * \ HadamardGate(1)*CGate((0,), TGate(2))*CGate((1,), PhaseGate(2)) * \ HadamardGate(2) assert IQFT(0, 3).decompose() == \ HadamardGate(2)*CGate((1,), RkGate(2, -2))*CGate((0,), RkGate(2, -3)) * \ HadamardGate(1)*CGate((0,), RkGate(1, -2))*HadamardGate(0)*SwapGate(0, 2) assert represent(QFT(0, 3), nqubits=3) == \ Matrix([[exp(2*pi*I/8)**(i*j % 8)/sqrt(8) for i in range(8)] for j in range(8)]) assert QFT(0, 4).decompose() # non-trivial decomposition assert qapply(QFT(0, 3).decompose()*Qubit(0, 0, 0)).expand() == qapply( HadamardGate(0)*HadamardGate(1)*HadamardGate(2)*Qubit(0, 0, 0) ).expand() def test_qft_represent(): c = QFT(0, 3) a = represent(c, nqubits=3) b = represent(c.decompose(), nqubits=3) assert a.evalf(n=10) == b.evalf(n=10) sympy-sympy-1.9/sympy/physics/quantum/tests/test_qubit.py000066400000000000000000000211161412543434000241600ustar00rootroot00000000000000import random from sympy import Integer, Matrix, Rational, sqrt, symbols, S from sympy.physics.quantum.qubit import (measure_all, measure_partial, matrix_to_qubit, matrix_to_density, qubit_to_matrix, IntQubit, IntQubitBra, QubitBra) from sympy.physics.quantum.gate import (HadamardGate, CNOT, XGate, YGate, ZGate, PhaseGate) from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.represent import represent from sympy.physics.quantum.shor import Qubit from sympy.testing.pytest import raises from sympy.physics.quantum.density import Density from sympy.core.trace import Tr x, y = symbols('x,y') epsilon = .000001 def test_Qubit(): array = [0, 0, 1, 1, 0] qb = Qubit('00110') assert qb.flip(0) == Qubit('00111') assert qb.flip(1) == Qubit('00100') assert qb.flip(4) == Qubit('10110') assert qb.qubit_values == (0, 0, 1, 1, 0) assert qb.dimension == 5 for i in range(5): assert qb[i] == array[4 - i] assert len(qb) == 5 qb = Qubit('110') def test_QubitBra(): qb = Qubit(0) qb_bra = QubitBra(0) assert qb.dual_class() == QubitBra assert qb_bra.dual_class() == Qubit qb = Qubit(1, 1, 0) qb_bra = QubitBra(1, 1, 0) assert represent(qb, nqubits=3).H == represent(qb_bra, nqubits=3) qb = Qubit(0, 1) qb_bra = QubitBra(1,0) assert qb._eval_innerproduct_QubitBra(qb_bra) == Integer(0) qb_bra = QubitBra(0, 1) assert qb._eval_innerproduct_QubitBra(qb_bra) == Integer(1) def test_IntQubit(): # issue 9136 iqb = IntQubit(0, nqubits=1) assert qubit_to_matrix(Qubit('0')) == qubit_to_matrix(iqb) qb = Qubit('1010') assert qubit_to_matrix(IntQubit(qb)) == qubit_to_matrix(qb) iqb = IntQubit(1, nqubits=1) assert qubit_to_matrix(Qubit('1')) == qubit_to_matrix(iqb) assert qubit_to_matrix(IntQubit(1)) == qubit_to_matrix(iqb) iqb = IntQubit(7, nqubits=4) assert qubit_to_matrix(Qubit('0111')) == qubit_to_matrix(iqb) assert qubit_to_matrix(IntQubit(7, 4)) == qubit_to_matrix(iqb) iqb = IntQubit(8) assert iqb.as_int() == 8 assert iqb.qubit_values == (1, 0, 0, 0) iqb = IntQubit(7, 4) assert iqb.qubit_values == (0, 1, 1, 1) assert IntQubit(3) == IntQubit(3, 2) #test Dual Classes iqb = IntQubit(3) iqb_bra = IntQubitBra(3) assert iqb.dual_class() == IntQubitBra assert iqb_bra.dual_class() == IntQubit iqb = IntQubit(5) iqb_bra = IntQubitBra(5) assert iqb._eval_innerproduct_IntQubitBra(iqb_bra) == Integer(1) iqb = IntQubit(4) iqb_bra = IntQubitBra(5) assert iqb._eval_innerproduct_IntQubitBra(iqb_bra) == Integer(0) raises(ValueError, lambda: IntQubit(4, 1)) raises(ValueError, lambda: IntQubit('5')) raises(ValueError, lambda: IntQubit(5, '5')) raises(ValueError, lambda: IntQubit(5, nqubits='5')) raises(TypeError, lambda: IntQubit(5, bad_arg=True)) def test_superposition_of_states(): state = 1/sqrt(2)*Qubit('01') + 1/sqrt(2)*Qubit('10') state_gate = CNOT(0, 1)*HadamardGate(0)*state state_expanded = Qubit('01')/2 + Qubit('00')/2 - Qubit('11')/2 + Qubit('10')/2 assert qapply(state_gate).expand() == state_expanded assert matrix_to_qubit(represent(state_gate, nqubits=2)) == state_expanded #test apply methods def test_apply_represent_equality(): gates = [HadamardGate(int(3*random.random())), XGate(int(3*random.random())), ZGate(int(3*random.random())), YGate(int(3*random.random())), ZGate(int(3*random.random())), PhaseGate(int(3*random.random()))] circuit = Qubit(int(random.random()*2), int(random.random()*2), int(random.random()*2), int(random.random()*2), int(random.random()*2), int(random.random()*2)) for i in range(int(random.random()*6)): circuit = gates[int(random.random()*6)]*circuit mat = represent(circuit, nqubits=6) states = qapply(circuit) state_rep = matrix_to_qubit(mat) states = states.expand() state_rep = state_rep.expand() assert state_rep == states def test_matrix_to_qubits(): qb = Qubit(0, 0, 0, 0) mat = Matrix([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) assert matrix_to_qubit(mat) == qb assert qubit_to_matrix(qb) == mat state = 2*sqrt(2)*(Qubit(0, 0, 0) + Qubit(0, 0, 1) + Qubit(0, 1, 0) + Qubit(0, 1, 1) + Qubit(1, 0, 0) + Qubit(1, 0, 1) + Qubit(1, 1, 0) + Qubit(1, 1, 1)) ones = sqrt(2)*2*Matrix([1, 1, 1, 1, 1, 1, 1, 1]) assert matrix_to_qubit(ones) == state.expand() assert qubit_to_matrix(state) == ones def test_measure_normalize(): a, b = symbols('a b') state = a*Qubit('110') + b*Qubit('111') assert measure_partial(state, (0,), normalize=False) == \ [(a*Qubit('110'), a*a.conjugate()), (b*Qubit('111'), b*b.conjugate())] assert measure_all(state, normalize=False) == \ [(Qubit('110'), a*a.conjugate()), (Qubit('111'), b*b.conjugate())] def test_measure_partial(): #Basic test of collapse of entangled two qubits (Bell States) state = Qubit('01') + Qubit('10') assert measure_partial(state, (0,)) == \ [(Qubit('10'), S.Half), (Qubit('01'), S.Half)] assert measure_partial(state, int(0)) == \ [(Qubit('10'), S.Half), (Qubit('01'), S.Half)] assert measure_partial(state, (0,)) == \ measure_partial(state, (1,))[::-1] #Test of more complex collapse and probability calculation state1 = sqrt(2)/sqrt(3)*Qubit('00001') + 1/sqrt(3)*Qubit('11111') assert measure_partial(state1, (0,)) == \ [(sqrt(2)/sqrt(3)*Qubit('00001') + 1/sqrt(3)*Qubit('11111'), 1)] assert measure_partial(state1, (1, 2)) == measure_partial(state1, (3, 4)) assert measure_partial(state1, (1, 2, 3)) == \ [(Qubit('00001'), Rational(2, 3)), (Qubit('11111'), Rational(1, 3))] #test of measuring multiple bits at once state2 = Qubit('1111') + Qubit('1101') + Qubit('1011') + Qubit('1000') assert measure_partial(state2, (0, 1, 3)) == \ [(Qubit('1000'), Rational(1, 4)), (Qubit('1101'), Rational(1, 4)), (Qubit('1011')/sqrt(2) + Qubit('1111')/sqrt(2), S.Half)] assert measure_partial(state2, (0,)) == \ [(Qubit('1000'), Rational(1, 4)), (Qubit('1111')/sqrt(3) + Qubit('1101')/sqrt(3) + Qubit('1011')/sqrt(3), Rational(3, 4))] def test_measure_all(): assert measure_all(Qubit('11')) == [(Qubit('11'), 1)] state = Qubit('11') + Qubit('10') assert measure_all(state) == [(Qubit('10'), S.Half), (Qubit('11'), S.Half)] state2 = Qubit('11')/sqrt(5) + 2*Qubit('00')/sqrt(5) assert measure_all(state2) == \ [(Qubit('00'), Rational(4, 5)), (Qubit('11'), Rational(1, 5))] # from issue #12585 assert measure_all(qapply(Qubit('0'))) == [(Qubit('0'), 1)] def test_eval_trace(): q1 = Qubit('10110') q2 = Qubit('01010') d = Density([q1, 0.6], [q2, 0.4]) t = Tr(d) assert t.doit() == 1 # extreme bits t = Tr(d, 0) assert t.doit() == (0.4*Density([Qubit('0101'), 1]) + 0.6*Density([Qubit('1011'), 1])) t = Tr(d, 4) assert t.doit() == (0.4*Density([Qubit('1010'), 1]) + 0.6*Density([Qubit('0110'), 1])) # index somewhere in between t = Tr(d, 2) assert t.doit() == (0.4*Density([Qubit('0110'), 1]) + 0.6*Density([Qubit('1010'), 1])) #trace all indices t = Tr(d, [0, 1, 2, 3, 4]) assert t.doit() == 1 # trace some indices, initialized in # non-canonical order t = Tr(d, [2, 1, 3]) assert t.doit() == (0.4*Density([Qubit('00'), 1]) + 0.6*Density([Qubit('10'), 1])) # mixed states q = (1/sqrt(2)) * (Qubit('00') + Qubit('11')) d = Density( [q, 1.0] ) t = Tr(d, 0) assert t.doit() == (0.5*Density([Qubit('0'), 1]) + 0.5*Density([Qubit('1'), 1])) def test_matrix_to_density(): mat = Matrix([[0, 0], [0, 1]]) assert matrix_to_density(mat) == Density([Qubit('1'), 1]) mat = Matrix([[1, 0], [0, 0]]) assert matrix_to_density(mat) == Density([Qubit('0'), 1]) mat = Matrix([[0, 0], [0, 0]]) assert matrix_to_density(mat) == 0 mat = Matrix([[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 0]]) assert matrix_to_density(mat) == Density([Qubit('10'), 1]) mat = Matrix([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]) assert matrix_to_density(mat) == Density([Qubit('00'), 1]) sympy-sympy-1.9/sympy/physics/quantum/tests/test_represent.py000066400000000000000000000117771412543434000250570ustar00rootroot00000000000000from sympy import Float, I, Integer, Matrix from sympy.external import import_module from sympy.testing.pytest import skip from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.represent import (represent, rep_innerproduct, rep_expectation, enumerate_states) from sympy.physics.quantum.state import Bra, Ket from sympy.physics.quantum.operator import Operator, OuterProduct from sympy.physics.quantum.tensorproduct import TensorProduct from sympy.physics.quantum.tensorproduct import matrix_tensor_product from sympy.physics.quantum.commutator import Commutator from sympy.physics.quantum.anticommutator import AntiCommutator from sympy.physics.quantum.innerproduct import InnerProduct from sympy.physics.quantum.matrixutils import (numpy_ndarray, scipy_sparse_matrix, to_numpy, to_scipy_sparse, to_sympy) from sympy.physics.quantum.cartesian import XKet, XOp, XBra from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.operatorset import operators_to_state Amat = Matrix([[1, I], [-I, 1]]) Bmat = Matrix([[1, 2], [3, 4]]) Avec = Matrix([[1], [I]]) class AKet(Ket): @classmethod def dual_class(self): return ABra def _represent_default_basis(self, **options): return self._represent_AOp(None, **options) def _represent_AOp(self, basis, **options): return Avec class ABra(Bra): @classmethod def dual_class(self): return AKet class AOp(Operator): def _represent_default_basis(self, **options): return self._represent_AOp(None, **options) def _represent_AOp(self, basis, **options): return Amat class BOp(Operator): def _represent_default_basis(self, **options): return self._represent_AOp(None, **options) def _represent_AOp(self, basis, **options): return Bmat k = AKet('a') b = ABra('a') A = AOp('A') B = BOp('B') _tests = [ # Bra (b, Dagger(Avec)), (Dagger(b), Avec), # Ket (k, Avec), (Dagger(k), Dagger(Avec)), # Operator (A, Amat), (Dagger(A), Dagger(Amat)), # OuterProduct (OuterProduct(k, b), Avec*Avec.H), # TensorProduct (TensorProduct(A, B), matrix_tensor_product(Amat, Bmat)), # Pow (A**2, Amat**2), # Add/Mul (A*B + 2*A, Amat*Bmat + 2*Amat), # Commutator (Commutator(A, B), Amat*Bmat - Bmat*Amat), # AntiCommutator (AntiCommutator(A, B), Amat*Bmat + Bmat*Amat), # InnerProduct (InnerProduct(b, k), (Avec.H*Avec)[0]) ] def test_format_sympy(): for test in _tests: lhs = represent(test[0], basis=A, format='sympy') rhs = to_sympy(test[1]) assert lhs == rhs def test_scalar_sympy(): assert represent(Integer(1)) == Integer(1) assert represent(Float(1.0)) == Float(1.0) assert represent(1.0 + I) == 1.0 + I np = import_module('numpy') def test_format_numpy(): if not np: skip("numpy not installed.") for test in _tests: lhs = represent(test[0], basis=A, format='numpy') rhs = to_numpy(test[1]) if isinstance(lhs, numpy_ndarray): assert (lhs == rhs).all() else: assert lhs == rhs def test_scalar_numpy(): if not np: skip("numpy not installed.") assert represent(Integer(1), format='numpy') == 1 assert represent(Float(1.0), format='numpy') == 1.0 assert represent(1.0 + I, format='numpy') == 1.0 + 1.0j scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) def test_format_scipy_sparse(): if not np: skip("numpy not installed.") if not scipy: skip("scipy not installed.") for test in _tests: lhs = represent(test[0], basis=A, format='scipy.sparse') rhs = to_scipy_sparse(test[1]) if isinstance(lhs, scipy_sparse_matrix): assert np.linalg.norm((lhs - rhs).todense()) == 0.0 else: assert lhs == rhs def test_scalar_scipy_sparse(): if not np: skip("numpy not installed.") if not scipy: skip("scipy not installed.") assert represent(Integer(1), format='scipy.sparse') == 1 assert represent(Float(1.0), format='scipy.sparse') == 1.0 assert represent(1.0 + I, format='scipy.sparse') == 1.0 + 1.0j x_ket = XKet('x') x_bra = XBra('x') x_op = XOp('X') def test_innerprod_represent(): assert rep_innerproduct(x_ket) == InnerProduct(XBra("x_1"), x_ket).doit() assert rep_innerproduct(x_bra) == InnerProduct(x_bra, XKet("x_1")).doit() try: rep_innerproduct(x_op) except TypeError: return True def test_operator_represent(): basis_kets = enumerate_states(operators_to_state(x_op), 1, 2) assert rep_expectation( x_op) == qapply(basis_kets[1].dual*x_op*basis_kets[0]) def test_enumerate_states(): test = XKet("foo") assert enumerate_states(test, 1, 1) == [XKet("foo_1")] assert enumerate_states( test, [1, 2, 4]) == [XKet("foo_1"), XKet("foo_2"), XKet("foo_4")] sympy-sympy-1.9/sympy/physics/quantum/tests/test_sho1d.py000066400000000000000000000107141412543434000240540ustar00rootroot00000000000000"""Tests for sho1d.py""" from sympy import Integer, Symbol, sqrt, I, S from sympy.physics.quantum import Dagger from sympy.physics.quantum.constants import hbar from sympy.physics.quantum import Commutator from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.innerproduct import InnerProduct from sympy.physics.quantum.cartesian import X, Px from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.physics.quantum.hilbert import ComplexSpace from sympy.physics.quantum.represent import represent from sympy.external import import_module from sympy.testing.pytest import skip from sympy.physics.quantum.sho1d import (RaisingOp, LoweringOp, SHOKet, SHOBra, Hamiltonian, NumberOp) ad = RaisingOp('a') a = LoweringOp('a') k = SHOKet('k') kz = SHOKet(0) kf = SHOKet(1) k3 = SHOKet(3) b = SHOBra('b') b3 = SHOBra(3) H = Hamiltonian('H') N = NumberOp('N') omega = Symbol('omega') m = Symbol('m') ndim = Integer(4) np = import_module('numpy') scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) ad_rep_sympy = represent(ad, basis=N, ndim=4, format='sympy') a_rep = represent(a, basis=N, ndim=4, format='sympy') N_rep = represent(N, basis=N, ndim=4, format='sympy') H_rep = represent(H, basis=N, ndim=4, format='sympy') k3_rep = represent(k3, basis=N, ndim=4, format='sympy') b3_rep = represent(b3, basis=N, ndim=4, format='sympy') def test_RaisingOp(): assert Dagger(ad) == a assert Commutator(ad, a).doit() == Integer(-1) assert Commutator(ad, N).doit() == Integer(-1)*ad assert qapply(ad*k) == (sqrt(k.n + 1)*SHOKet(k.n + 1)).expand() assert qapply(ad*kz) == (sqrt(kz.n + 1)*SHOKet(kz.n + 1)).expand() assert qapply(ad*kf) == (sqrt(kf.n + 1)*SHOKet(kf.n + 1)).expand() assert ad.rewrite('xp').doit() == \ (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*(Integer(-1)*I*Px + m*omega*X) assert ad.hilbert_space == ComplexSpace(S.Infinity) for i in range(ndim - 1): assert ad_rep_sympy[i + 1,i] == sqrt(i + 1) if not np: skip("numpy not installed.") ad_rep_numpy = represent(ad, basis=N, ndim=4, format='numpy') for i in range(ndim - 1): assert ad_rep_numpy[i + 1,i] == float(sqrt(i + 1)) if not np: skip("numpy not installed.") if not scipy: skip("scipy not installed.") ad_rep_scipy = represent(ad, basis=N, ndim=4, format='scipy.sparse', spmatrix='lil') for i in range(ndim - 1): assert ad_rep_scipy[i + 1,i] == float(sqrt(i + 1)) assert ad_rep_numpy.dtype == 'float64' assert ad_rep_scipy.dtype == 'float64' def test_LoweringOp(): assert Dagger(a) == ad assert Commutator(a, ad).doit() == Integer(1) assert Commutator(a, N).doit() == a assert qapply(a*k) == (sqrt(k.n)*SHOKet(k.n-Integer(1))).expand() assert qapply(a*kz) == Integer(0) assert qapply(a*kf) == (sqrt(kf.n)*SHOKet(kf.n-Integer(1))).expand() assert a.rewrite('xp').doit() == \ (Integer(1)/sqrt(Integer(2)*hbar*m*omega))*(I*Px + m*omega*X) for i in range(ndim - 1): assert a_rep[i,i + 1] == sqrt(i + 1) def test_NumberOp(): assert Commutator(N, ad).doit() == ad assert Commutator(N, a).doit() == Integer(-1)*a assert Commutator(N, H).doit() == Integer(0) assert qapply(N*k) == (k.n*k).expand() assert N.rewrite('a').doit() == ad*a assert N.rewrite('xp').doit() == (Integer(1)/(Integer(2)*m*hbar*omega))*( Px**2 + (m*omega*X)**2) - Integer(1)/Integer(2) assert N.rewrite('H').doit() == H/(hbar*omega) - Integer(1)/Integer(2) for i in range(ndim): assert N_rep[i,i] == i assert N_rep == ad_rep_sympy*a_rep def test_Hamiltonian(): assert Commutator(H, N).doit() == Integer(0) assert qapply(H*k) == ((hbar*omega*(k.n + Integer(1)/Integer(2)))*k).expand() assert H.rewrite('a').doit() == hbar*omega*(ad*a + Integer(1)/Integer(2)) assert H.rewrite('xp').doit() == \ (Integer(1)/(Integer(2)*m))*(Px**2 + (m*omega*X)**2) assert H.rewrite('N').doit() == hbar*omega*(N + Integer(1)/Integer(2)) for i in range(ndim): assert H_rep[i,i] == hbar*omega*(i + Integer(1)/Integer(2)) def test_SHOKet(): assert SHOKet('k').dual_class() == SHOBra assert SHOBra('b').dual_class() == SHOKet assert InnerProduct(b,k).doit() == KroneckerDelta(k.n, b.n) assert k.hilbert_space == ComplexSpace(S.Infinity) assert k3_rep[k3.n, 0] == Integer(1) assert b3_rep[0, b3.n] == Integer(1) sympy-sympy-1.9/sympy/physics/quantum/tests/test_shor.py000066400000000000000000000012321412543434000240040ustar00rootroot00000000000000from sympy.testing.pytest import XFAIL from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.qubit import Qubit from sympy.physics.quantum.shor import CMod, getr @XFAIL def test_CMod(): assert qapply(CMod(4, 2, 2)*Qubit(0, 0, 1, 0, 0, 0, 0, 0)) == \ Qubit(0, 0, 1, 0, 0, 0, 0, 0) assert qapply(CMod(5, 5, 7)*Qubit(0, 0, 1, 0, 0, 0, 0, 0, 0, 0)) == \ Qubit(0, 0, 1, 0, 0, 0, 0, 0, 1, 0) assert qapply(CMod(3, 2, 3)*Qubit(0, 1, 0, 0, 0, 0)) == \ Qubit(0, 1, 0, 0, 0, 1) def test_continued_frac(): assert getr(513, 1024, 10) == 2 assert getr(169, 1024, 11) == 6 assert getr(314, 4096, 16) == 13 sympy-sympy-1.9/sympy/physics/quantum/tests/test_spin.py000066400000000000000000012406331412543434000240150ustar00rootroot00000000000000from sympy import cos, exp, expand, I, Matrix, pi, S, sin, sqrt, Sum, symbols, Rational from sympy.abc import alpha, beta, gamma, j, m from sympy.physics.quantum import hbar, represent, Commutator, InnerProduct from sympy.physics.quantum.qapply import qapply from sympy.physics.quantum.tensorproduct import TensorProduct from sympy.physics.quantum.cg import CG from sympy.physics.quantum.spin import ( Jx, Jy, Jz, Jplus, Jminus, J2, JxBra, JyBra, JzBra, JxKet, JyKet, JzKet, JxKetCoupled, JyKetCoupled, JzKetCoupled, couple, uncouple, Rotation, WignerD ) from sympy.testing.pytest import raises, slow j1, j2, j3, j4, m1, m2, m3, m4 = symbols('j1:5 m1:5') j12, j13, j24, j34, j123, j134, mi, mi1, mp = symbols( 'j12 j13 j24 j34 j123 j134 mi mi1 mp') def test_represent_spin_operators(): assert represent(Jx) == hbar*Matrix([[0, 1], [1, 0]])/2 assert represent( Jx, j=1) == hbar*sqrt(2)*Matrix([[0, 1, 0], [1, 0, 1], [0, 1, 0]])/2 assert represent(Jy) == hbar*I*Matrix([[0, -1], [1, 0]])/2 assert represent(Jy, j=1) == hbar*I*sqrt(2)*Matrix([[0, -1, 0], [1, 0, -1], [0, 1, 0]])/2 assert represent(Jz) == hbar*Matrix([[1, 0], [0, -1]])/2 assert represent( Jz, j=1) == hbar*Matrix([[1, 0, 0], [0, 0, 0], [0, 0, -1]]) def test_represent_spin_states(): # Jx basis assert represent(JxKet(S.Half, S.Half), basis=Jx) == Matrix([1, 0]) assert represent(JxKet(S.Half, Rational(-1, 2)), basis=Jx) == Matrix([0, 1]) assert represent(JxKet(1, 1), basis=Jx) == Matrix([1, 0, 0]) assert represent(JxKet(1, 0), basis=Jx) == Matrix([0, 1, 0]) assert represent(JxKet(1, -1), basis=Jx) == Matrix([0, 0, 1]) assert represent( JyKet(S.Half, S.Half), basis=Jx) == Matrix([exp(-I*pi/4), 0]) assert represent( JyKet(S.Half, Rational(-1, 2)), basis=Jx) == Matrix([0, exp(I*pi/4)]) assert represent(JyKet(1, 1), basis=Jx) == Matrix([-I, 0, 0]) assert represent(JyKet(1, 0), basis=Jx) == Matrix([0, 1, 0]) assert represent(JyKet(1, -1), basis=Jx) == Matrix([0, 0, I]) assert represent( JzKet(S.Half, S.Half), basis=Jx) == sqrt(2)*Matrix([-1, 1])/2 assert represent( JzKet(S.Half, Rational(-1, 2)), basis=Jx) == sqrt(2)*Matrix([-1, -1])/2 assert represent(JzKet(1, 1), basis=Jx) == Matrix([1, -sqrt(2), 1])/2 assert represent(JzKet(1, 0), basis=Jx) == sqrt(2)*Matrix([1, 0, -1])/2 assert represent(JzKet(1, -1), basis=Jx) == Matrix([1, sqrt(2), 1])/2 # Jy basis assert represent( JxKet(S.Half, S.Half), basis=Jy) == Matrix([exp(I*pi*Rational(-3, 4)), 0]) assert represent( JxKet(S.Half, Rational(-1, 2)), basis=Jy) == Matrix([0, exp(I*pi*Rational(3, 4))]) assert represent(JxKet(1, 1), basis=Jy) == Matrix([I, 0, 0]) assert represent(JxKet(1, 0), basis=Jy) == Matrix([0, 1, 0]) assert represent(JxKet(1, -1), basis=Jy) == Matrix([0, 0, -I]) assert represent(JyKet(S.Half, S.Half), basis=Jy) == Matrix([1, 0]) assert represent(JyKet(S.Half, Rational(-1, 2)), basis=Jy) == Matrix([0, 1]) assert represent(JyKet(1, 1), basis=Jy) == Matrix([1, 0, 0]) assert represent(JyKet(1, 0), basis=Jy) == Matrix([0, 1, 0]) assert represent(JyKet(1, -1), basis=Jy) == Matrix([0, 0, 1]) assert represent( JzKet(S.Half, S.Half), basis=Jy) == sqrt(2)*Matrix([-1, I])/2 assert represent( JzKet(S.Half, Rational(-1, 2)), basis=Jy) == sqrt(2)*Matrix([I, -1])/2 assert represent(JzKet(1, 1), basis=Jy) == Matrix([1, -I*sqrt(2), -1])/2 assert represent( JzKet(1, 0), basis=Jy) == Matrix([-sqrt(2)*I, 0, -sqrt(2)*I])/2 assert represent(JzKet(1, -1), basis=Jy) == Matrix([-1, -sqrt(2)*I, 1])/2 # Jz basis assert represent( JxKet(S.Half, S.Half), basis=Jz) == sqrt(2)*Matrix([1, 1])/2 assert represent( JxKet(S.Half, Rational(-1, 2)), basis=Jz) == sqrt(2)*Matrix([-1, 1])/2 assert represent(JxKet(1, 1), basis=Jz) == Matrix([1, sqrt(2), 1])/2 assert represent(JxKet(1, 0), basis=Jz) == sqrt(2)*Matrix([-1, 0, 1])/2 assert represent(JxKet(1, -1), basis=Jz) == Matrix([1, -sqrt(2), 1])/2 assert represent( JyKet(S.Half, S.Half), basis=Jz) == sqrt(2)*Matrix([-1, -I])/2 assert represent( JyKet(S.Half, Rational(-1, 2)), basis=Jz) == sqrt(2)*Matrix([-I, -1])/2 assert represent(JyKet(1, 1), basis=Jz) == Matrix([1, sqrt(2)*I, -1])/2 assert represent(JyKet(1, 0), basis=Jz) == sqrt(2)*Matrix([I, 0, I])/2 assert represent(JyKet(1, -1), basis=Jz) == Matrix([-1, sqrt(2)*I, 1])/2 assert represent(JzKet(S.Half, S.Half), basis=Jz) == Matrix([1, 0]) assert represent(JzKet(S.Half, Rational(-1, 2)), basis=Jz) == Matrix([0, 1]) assert represent(JzKet(1, 1), basis=Jz) == Matrix([1, 0, 0]) assert represent(JzKet(1, 0), basis=Jz) == Matrix([0, 1, 0]) assert represent(JzKet(1, -1), basis=Jz) == Matrix([0, 0, 1]) def test_represent_uncoupled_states(): # Jx basis assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, S.Half)), basis=Jx) == \ Matrix([1, 0, 0, 0]) assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, Rational(-1, 2))), basis=Jx) == \ Matrix([0, 1, 0, 0]) assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, S.Half)), basis=Jx) == \ Matrix([0, 0, 1, 0]) assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, Rational(-1, 2))), basis=Jx) == \ Matrix([0, 0, 0, 1]) assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, S.Half)), basis=Jx) == \ Matrix([-I, 0, 0, 0]) assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, Rational(-1, 2))), basis=Jx) == \ Matrix([0, 1, 0, 0]) assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, S.Half)), basis=Jx) == \ Matrix([0, 0, 1, 0]) assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, Rational(-1, 2))), basis=Jx) == \ Matrix([0, 0, 0, I]) assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), basis=Jx) == \ Matrix([S.Half, Rational(-1, 2), Rational(-1, 2), S.Half]) assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), basis=Jx) == \ Matrix([S.Half, S.Half, Rational(-1, 2), Rational(-1, 2)]) assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), basis=Jx) == \ Matrix([S.Half, Rational(-1, 2), S.Half, Rational(-1, 2)]) assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), basis=Jx) == \ Matrix([S.Half, S.Half, S.Half, S.Half]) # Jy basis assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, S.Half)), basis=Jy) == \ Matrix([I, 0, 0, 0]) assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, Rational(-1, 2))), basis=Jy) == \ Matrix([0, 1, 0, 0]) assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, S.Half)), basis=Jy) == \ Matrix([0, 0, 1, 0]) assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, Rational(-1, 2))), basis=Jy) == \ Matrix([0, 0, 0, -I]) assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, S.Half)), basis=Jy) == \ Matrix([1, 0, 0, 0]) assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, Rational(-1, 2))), basis=Jy) == \ Matrix([0, 1, 0, 0]) assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, S.Half)), basis=Jy) == \ Matrix([0, 0, 1, 0]) assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, Rational(-1, 2))), basis=Jy) == \ Matrix([0, 0, 0, 1]) assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), basis=Jy) == \ Matrix([S.Half, -I/2, -I/2, Rational(-1, 2)]) assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), basis=Jy) == \ Matrix([-I/2, S.Half, Rational(-1, 2), -I/2]) assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), basis=Jy) == \ Matrix([-I/2, Rational(-1, 2), S.Half, -I/2]) assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), basis=Jy) == \ Matrix([Rational(-1, 2), -I/2, -I/2, S.Half]) # Jz basis assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, S.Half)), basis=Jz) == \ Matrix([S.Half, S.Half, S.Half, S.Half]) assert represent(TensorProduct(JxKet(S.Half, S.Half), JxKet(S.Half, Rational(-1, 2))), basis=Jz) == \ Matrix([Rational(-1, 2), S.Half, Rational(-1, 2), S.Half]) assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, S.Half)), basis=Jz) == \ Matrix([Rational(-1, 2), Rational(-1, 2), S.Half, S.Half]) assert represent(TensorProduct(JxKet(S.Half, Rational(-1, 2)), JxKet(S.Half, Rational(-1, 2))), basis=Jz) == \ Matrix([S.Half, Rational(-1, 2), Rational(-1, 2), S.Half]) assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, S.Half)), basis=Jz) == \ Matrix([S.Half, I/2, I/2, Rational(-1, 2)]) assert represent(TensorProduct(JyKet(S.Half, S.Half), JyKet(S.Half, Rational(-1, 2))), basis=Jz) == \ Matrix([I/2, S.Half, Rational(-1, 2), I/2]) assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, S.Half)), basis=Jz) == \ Matrix([I/2, Rational(-1, 2), S.Half, I/2]) assert represent(TensorProduct(JyKet(S.Half, Rational(-1, 2)), JyKet(S.Half, Rational(-1, 2))), basis=Jz) == \ Matrix([Rational(-1, 2), I/2, I/2, S.Half]) assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), basis=Jz) == \ Matrix([1, 0, 0, 0]) assert represent(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), basis=Jz) == \ Matrix([0, 1, 0, 0]) assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), basis=Jz) == \ Matrix([0, 0, 1, 0]) assert represent(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), basis=Jz) == \ Matrix([0, 0, 0, 1]) def test_represent_coupled_states(): # Jx basis assert represent(JxKetCoupled(0, 0, (S.Half, S.Half)), basis=Jx) == \ Matrix([1, 0, 0, 0]) assert represent(JxKetCoupled(1, 1, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, 1, 0, 0]) assert represent(JxKetCoupled(1, 0, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, 0, 1, 0]) assert represent(JxKetCoupled(1, -1, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, 0, 0, 1]) assert represent(JyKetCoupled(0, 0, (S.Half, S.Half)), basis=Jx) == \ Matrix([1, 0, 0, 0]) assert represent(JyKetCoupled(1, 1, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, -I, 0, 0]) assert represent(JyKetCoupled(1, 0, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, 0, 1, 0]) assert represent(JyKetCoupled(1, -1, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, 0, 0, I]) assert represent(JzKetCoupled(0, 0, (S.Half, S.Half)), basis=Jx) == \ Matrix([1, 0, 0, 0]) assert represent(JzKetCoupled(1, 1, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, S.Half, -sqrt(2)/2, S.Half]) assert represent(JzKetCoupled(1, 0, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, sqrt(2)/2, 0, -sqrt(2)/2]) assert represent(JzKetCoupled(1, -1, (S.Half, S.Half)), basis=Jx) == \ Matrix([0, S.Half, sqrt(2)/2, S.Half]) # Jy basis assert represent(JxKetCoupled(0, 0, (S.Half, S.Half)), basis=Jy) == \ Matrix([1, 0, 0, 0]) assert represent(JxKetCoupled(1, 1, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, I, 0, 0]) assert represent(JxKetCoupled(1, 0, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, 0, 1, 0]) assert represent(JxKetCoupled(1, -1, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, 0, 0, -I]) assert represent(JyKetCoupled(0, 0, (S.Half, S.Half)), basis=Jy) == \ Matrix([1, 0, 0, 0]) assert represent(JyKetCoupled(1, 1, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, 1, 0, 0]) assert represent(JyKetCoupled(1, 0, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, 0, 1, 0]) assert represent(JyKetCoupled(1, -1, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, 0, 0, 1]) assert represent(JzKetCoupled(0, 0, (S.Half, S.Half)), basis=Jy) == \ Matrix([1, 0, 0, 0]) assert represent(JzKetCoupled(1, 1, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, S.Half, -I*sqrt(2)/2, Rational(-1, 2)]) assert represent(JzKetCoupled(1, 0, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, -I*sqrt(2)/2, 0, -I*sqrt(2)/2]) assert represent(JzKetCoupled(1, -1, (S.Half, S.Half)), basis=Jy) == \ Matrix([0, Rational(-1, 2), -I*sqrt(2)/2, S.Half]) # Jz basis assert represent(JxKetCoupled(0, 0, (S.Half, S.Half)), basis=Jz) == \ Matrix([1, 0, 0, 0]) assert represent(JxKetCoupled(1, 1, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, S.Half, sqrt(2)/2, S.Half]) assert represent(JxKetCoupled(1, 0, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, -sqrt(2)/2, 0, sqrt(2)/2]) assert represent(JxKetCoupled(1, -1, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, S.Half, -sqrt(2)/2, S.Half]) assert represent(JyKetCoupled(0, 0, (S.Half, S.Half)), basis=Jz) == \ Matrix([1, 0, 0, 0]) assert represent(JyKetCoupled(1, 1, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, S.Half, I*sqrt(2)/2, Rational(-1, 2)]) assert represent(JyKetCoupled(1, 0, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, I*sqrt(2)/2, 0, I*sqrt(2)/2]) assert represent(JyKetCoupled(1, -1, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, Rational(-1, 2), I*sqrt(2)/2, S.Half]) assert represent(JzKetCoupled(0, 0, (S.Half, S.Half)), basis=Jz) == \ Matrix([1, 0, 0, 0]) assert represent(JzKetCoupled(1, 1, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, 1, 0, 0]) assert represent(JzKetCoupled(1, 0, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, 0, 1, 0]) assert represent(JzKetCoupled(1, -1, (S.Half, S.Half)), basis=Jz) == \ Matrix([0, 0, 0, 1]) def test_represent_rotation(): assert represent(Rotation(0, pi/2, 0)) == \ Matrix( [[WignerD( S( 1)/2, S( 1)/2, S( 1)/2, 0, pi/2, 0), WignerD( S.Half, S.Half, Rational(-1, 2), 0, pi/2, 0)], [WignerD(S.Half, Rational(-1, 2), S.Half, 0, pi/2, 0), WignerD(S.Half, Rational(-1, 2), Rational(-1, 2), 0, pi/2, 0)]]) assert represent(Rotation(0, pi/2, 0), doit=True) == \ Matrix([[sqrt(2)/2, -sqrt(2)/2], [sqrt(2)/2, sqrt(2)/2]]) def test_rewrite_same(): # Rewrite to same basis assert JxBra(1, 1).rewrite('Jx') == JxBra(1, 1) assert JxBra(j, m).rewrite('Jx') == JxBra(j, m) assert JxKet(1, 1).rewrite('Jx') == JxKet(1, 1) assert JxKet(j, m).rewrite('Jx') == JxKet(j, m) def test_rewrite_Bra(): # Numerical assert JxBra(1, 1).rewrite('Jy') == -I*JyBra(1, 1) assert JxBra(1, 0).rewrite('Jy') == JyBra(1, 0) assert JxBra(1, -1).rewrite('Jy') == I*JyBra(1, -1) assert JxBra(1, 1).rewrite( 'Jz') == JzBra(1, 1)/2 + JzBra(1, 0)/sqrt(2) + JzBra(1, -1)/2 assert JxBra( 1, 0).rewrite('Jz') == -sqrt(2)*JzBra(1, 1)/2 + sqrt(2)*JzBra(1, -1)/2 assert JxBra(1, -1).rewrite( 'Jz') == JzBra(1, 1)/2 - JzBra(1, 0)/sqrt(2) + JzBra(1, -1)/2 assert JyBra(1, 1).rewrite('Jx') == I*JxBra(1, 1) assert JyBra(1, 0).rewrite('Jx') == JxBra(1, 0) assert JyBra(1, -1).rewrite('Jx') == -I*JxBra(1, -1) assert JyBra(1, 1).rewrite( 'Jz') == JzBra(1, 1)/2 - sqrt(2)*I*JzBra(1, 0)/2 - JzBra(1, -1)/2 assert JyBra(1, 0).rewrite( 'Jz') == -sqrt(2)*I*JzBra(1, 1)/2 - sqrt(2)*I*JzBra(1, -1)/2 assert JyBra(1, -1).rewrite( 'Jz') == -JzBra(1, 1)/2 - sqrt(2)*I*JzBra(1, 0)/2 + JzBra(1, -1)/2 assert JzBra(1, 1).rewrite( 'Jx') == JxBra(1, 1)/2 - sqrt(2)*JxBra(1, 0)/2 + JxBra(1, -1)/2 assert JzBra( 1, 0).rewrite('Jx') == sqrt(2)*JxBra(1, 1)/2 - sqrt(2)*JxBra(1, -1)/2 assert JzBra(1, -1).rewrite( 'Jx') == JxBra(1, 1)/2 + sqrt(2)*JxBra(1, 0)/2 + JxBra(1, -1)/2 assert JzBra(1, 1).rewrite( 'Jy') == JyBra(1, 1)/2 + sqrt(2)*I*JyBra(1, 0)/2 - JyBra(1, -1)/2 assert JzBra(1, 0).rewrite( 'Jy') == sqrt(2)*I*JyBra(1, 1)/2 + sqrt(2)*I*JyBra(1, -1)/2 assert JzBra(1, -1).rewrite( 'Jy') == -JyBra(1, 1)/2 + sqrt(2)*I*JyBra(1, 0)/2 + JyBra(1, -1)/2 # Symbolic assert JxBra(j, m).rewrite('Jy') == Sum( WignerD(j, mi, m, pi*Rational(3, 2), 0, 0) * JyBra(j, mi), (mi, -j, j)) assert JxBra(j, m).rewrite('Jz') == Sum( WignerD(j, mi, m, 0, pi/2, 0) * JzBra(j, mi), (mi, -j, j)) assert JyBra(j, m).rewrite('Jx') == Sum( WignerD(j, mi, m, 0, 0, pi/2) * JxBra(j, mi), (mi, -j, j)) assert JyBra(j, m).rewrite('Jz') == Sum( WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2) * JzBra(j, mi), (mi, -j, j)) assert JzBra(j, m).rewrite('Jx') == Sum( WignerD(j, mi, m, 0, pi*Rational(3, 2), 0) * JxBra(j, mi), (mi, -j, j)) assert JzBra(j, m).rewrite('Jy') == Sum( WignerD(j, mi, m, pi*Rational(3, 2), pi/2, pi/2) * JyBra(j, mi), (mi, -j, j)) def test_rewrite_Ket(): # Numerical assert JxKet(1, 1).rewrite('Jy') == I*JyKet(1, 1) assert JxKet(1, 0).rewrite('Jy') == JyKet(1, 0) assert JxKet(1, -1).rewrite('Jy') == -I*JyKet(1, -1) assert JxKet(1, 1).rewrite( 'Jz') == JzKet(1, 1)/2 + JzKet(1, 0)/sqrt(2) + JzKet(1, -1)/2 assert JxKet( 1, 0).rewrite('Jz') == -sqrt(2)*JzKet(1, 1)/2 + sqrt(2)*JzKet(1, -1)/2 assert JxKet(1, -1).rewrite( 'Jz') == JzKet(1, 1)/2 - JzKet(1, 0)/sqrt(2) + JzKet(1, -1)/2 assert JyKet(1, 1).rewrite('Jx') == -I*JxKet(1, 1) assert JyKet(1, 0).rewrite('Jx') == JxKet(1, 0) assert JyKet(1, -1).rewrite('Jx') == I*JxKet(1, -1) assert JyKet(1, 1).rewrite( 'Jz') == JzKet(1, 1)/2 + sqrt(2)*I*JzKet(1, 0)/2 - JzKet(1, -1)/2 assert JyKet(1, 0).rewrite( 'Jz') == sqrt(2)*I*JzKet(1, 1)/2 + sqrt(2)*I*JzKet(1, -1)/2 assert JyKet(1, -1).rewrite( 'Jz') == -JzKet(1, 1)/2 + sqrt(2)*I*JzKet(1, 0)/2 + JzKet(1, -1)/2 assert JzKet(1, 1).rewrite( 'Jx') == JxKet(1, 1)/2 - sqrt(2)*JxKet(1, 0)/2 + JxKet(1, -1)/2 assert JzKet( 1, 0).rewrite('Jx') == sqrt(2)*JxKet(1, 1)/2 - sqrt(2)*JxKet(1, -1)/2 assert JzKet(1, -1).rewrite( 'Jx') == JxKet(1, 1)/2 + sqrt(2)*JxKet(1, 0)/2 + JxKet(1, -1)/2 assert JzKet(1, 1).rewrite( 'Jy') == JyKet(1, 1)/2 - sqrt(2)*I*JyKet(1, 0)/2 - JyKet(1, -1)/2 assert JzKet(1, 0).rewrite( 'Jy') == -sqrt(2)*I*JyKet(1, 1)/2 - sqrt(2)*I*JyKet(1, -1)/2 assert JzKet(1, -1).rewrite( 'Jy') == -JyKet(1, 1)/2 - sqrt(2)*I*JyKet(1, 0)/2 + JyKet(1, -1)/2 # Symbolic assert JxKet(j, m).rewrite('Jy') == Sum( WignerD(j, mi, m, pi*Rational(3, 2), 0, 0) * JyKet(j, mi), (mi, -j, j)) assert JxKet(j, m).rewrite('Jz') == Sum( WignerD(j, mi, m, 0, pi/2, 0) * JzKet(j, mi), (mi, -j, j)) assert JyKet(j, m).rewrite('Jx') == Sum( WignerD(j, mi, m, 0, 0, pi/2) * JxKet(j, mi), (mi, -j, j)) assert JyKet(j, m).rewrite('Jz') == Sum( WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2) * JzKet(j, mi), (mi, -j, j)) assert JzKet(j, m).rewrite('Jx') == Sum( WignerD(j, mi, m, 0, pi*Rational(3, 2), 0) * JxKet(j, mi), (mi, -j, j)) assert JzKet(j, m).rewrite('Jy') == Sum( WignerD(j, mi, m, pi*Rational(3, 2), pi/2, pi/2) * JyKet(j, mi), (mi, -j, j)) def test_rewrite_uncoupled_state(): # Numerical assert TensorProduct(JyKet(1, 1), JxKet( 1, 1)).rewrite('Jx') == -I*TensorProduct(JxKet(1, 1), JxKet(1, 1)) assert TensorProduct(JyKet(1, 0), JxKet( 1, 1)).rewrite('Jx') == TensorProduct(JxKet(1, 0), JxKet(1, 1)) assert TensorProduct(JyKet(1, -1), JxKet( 1, 1)).rewrite('Jx') == I*TensorProduct(JxKet(1, -1), JxKet(1, 1)) assert TensorProduct(JzKet(1, 1), JxKet(1, 1)).rewrite('Jx') == \ TensorProduct(JxKet(1, -1), JxKet(1, 1))/2 - sqrt(2)*TensorProduct(JxKet( 1, 0), JxKet(1, 1))/2 + TensorProduct(JxKet(1, 1), JxKet(1, 1))/2 assert TensorProduct(JzKet(1, 0), JxKet(1, 1)).rewrite('Jx') == \ -sqrt(2)*TensorProduct(JxKet(1, -1), JxKet(1, 1))/2 + sqrt( 2)*TensorProduct(JxKet(1, 1), JxKet(1, 1))/2 assert TensorProduct(JzKet(1, -1), JxKet(1, 1)).rewrite('Jx') == \ TensorProduct(JxKet(1, -1), JxKet(1, 1))/2 + sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, 1))/2 + TensorProduct(JxKet(1, 1), JxKet(1, 1))/2 assert TensorProduct(JxKet(1, 1), JyKet( 1, 1)).rewrite('Jy') == I*TensorProduct(JyKet(1, 1), JyKet(1, 1)) assert TensorProduct(JxKet(1, 0), JyKet( 1, 1)).rewrite('Jy') == TensorProduct(JyKet(1, 0), JyKet(1, 1)) assert TensorProduct(JxKet(1, -1), JyKet( 1, 1)).rewrite('Jy') == -I*TensorProduct(JyKet(1, -1), JyKet(1, 1)) assert TensorProduct(JzKet(1, 1), JyKet(1, 1)).rewrite('Jy') == \ -TensorProduct(JyKet(1, -1), JyKet(1, 1))/2 - sqrt(2)*I*TensorProduct(JyKet(1, 0), JyKet(1, 1))/2 + TensorProduct(JyKet(1, 1), JyKet(1, 1))/2 assert TensorProduct(JzKet(1, 0), JyKet(1, 1)).rewrite('Jy') == \ -sqrt(2)*I*TensorProduct(JyKet(1, -1), JyKet( 1, 1))/2 - sqrt(2)*I*TensorProduct(JyKet(1, 1), JyKet(1, 1))/2 assert TensorProduct(JzKet(1, -1), JyKet(1, 1)).rewrite('Jy') == \ TensorProduct(JyKet(1, -1), JyKet(1, 1))/2 - sqrt(2)*I*TensorProduct(JyKet(1, 0), JyKet(1, 1))/2 - TensorProduct(JyKet(1, 1), JyKet(1, 1))/2 assert TensorProduct(JxKet(1, 1), JzKet(1, 1)).rewrite('Jz') == \ TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 + sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 assert TensorProduct(JxKet(1, 0), JzKet(1, 1)).rewrite('Jz') == \ sqrt(2)*TensorProduct(JzKet(1, -1), JzKet( 1, 1))/2 - sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 assert TensorProduct(JxKet(1, -1), JzKet(1, 1)).rewrite('Jz') == \ TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 - sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 assert TensorProduct(JyKet(1, 1), JzKet(1, 1)).rewrite('Jz') == \ -TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 + sqrt(2)*I*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 + TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 assert TensorProduct(JyKet(1, 0), JzKet(1, 1)).rewrite('Jz') == \ sqrt(2)*I*TensorProduct(JzKet(1, -1), JzKet( 1, 1))/2 + sqrt(2)*I*TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 assert TensorProduct(JyKet(1, -1), JzKet(1, 1)).rewrite('Jz') == \ TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 + sqrt(2)*I*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 - TensorProduct(JzKet(1, 1), JzKet(1, 1))/2 # Symbolic assert TensorProduct(JyKet(j1, m1), JxKet(j2, m2)).rewrite('Jy') == \ TensorProduct(JyKet(j1, m1), Sum( WignerD(j2, mi, m2, pi*Rational(3, 2), 0, 0) * JyKet(j2, mi), (mi, -j2, j2))) assert TensorProduct(JzKet(j1, m1), JxKet(j2, m2)).rewrite('Jz') == \ TensorProduct(JzKet(j1, m1), Sum( WignerD(j2, mi, m2, 0, pi/2, 0) * JzKet(j2, mi), (mi, -j2, j2))) assert TensorProduct(JxKet(j1, m1), JyKet(j2, m2)).rewrite('Jx') == \ TensorProduct(JxKet(j1, m1), Sum( WignerD(j2, mi, m2, 0, 0, pi/2) * JxKet(j2, mi), (mi, -j2, j2))) assert TensorProduct(JzKet(j1, m1), JyKet(j2, m2)).rewrite('Jz') == \ TensorProduct(JzKet(j1, m1), Sum(WignerD( j2, mi, m2, pi*Rational(3, 2), -pi/2, pi/2) * JzKet(j2, mi), (mi, -j2, j2))) assert TensorProduct(JxKet(j1, m1), JzKet(j2, m2)).rewrite('Jx') == \ TensorProduct(JxKet(j1, m1), Sum( WignerD(j2, mi, m2, 0, pi*Rational(3, 2), 0) * JxKet(j2, mi), (mi, -j2, j2))) assert TensorProduct(JyKet(j1, m1), JzKet(j2, m2)).rewrite('Jy') == \ TensorProduct(JyKet(j1, m1), Sum(WignerD( j2, mi, m2, pi*Rational(3, 2), pi/2, pi/2) * JyKet(j2, mi), (mi, -j2, j2))) def test_rewrite_coupled_state(): # Numerical assert JyKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jx') == \ JxKetCoupled(0, 0, (S.Half, S.Half)) assert JyKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jx') == \ -I*JxKetCoupled(1, 1, (S.Half, S.Half)) assert JyKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jx') == \ JxKetCoupled(1, 0, (S.Half, S.Half)) assert JyKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jx') == \ I*JxKetCoupled(1, -1, (S.Half, S.Half)) assert JzKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jx') == \ JxKetCoupled(0, 0, (S.Half, S.Half)) assert JzKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jx') == \ JxKetCoupled(1, 1, (S.Half, S.Half))/2 - sqrt(2)*JxKetCoupled(1, 0, ( S.Half, S.Half))/2 + JxKetCoupled(1, -1, (S.Half, S.Half))/2 assert JzKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jx') == \ sqrt(2)*JxKetCoupled(1, 1, (S( 1)/2, S.Half))/2 - sqrt(2)*JxKetCoupled(1, -1, (S.Half, S.Half))/2 assert JzKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jx') == \ JxKetCoupled(1, 1, (S.Half, S.Half))/2 + sqrt(2)*JxKetCoupled(1, 0, ( S.Half, S.Half))/2 + JxKetCoupled(1, -1, (S.Half, S.Half))/2 assert JxKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jy') == \ JyKetCoupled(0, 0, (S.Half, S.Half)) assert JxKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jy') == \ I*JyKetCoupled(1, 1, (S.Half, S.Half)) assert JxKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jy') == \ JyKetCoupled(1, 0, (S.Half, S.Half)) assert JxKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jy') == \ -I*JyKetCoupled(1, -1, (S.Half, S.Half)) assert JzKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jy') == \ JyKetCoupled(0, 0, (S.Half, S.Half)) assert JzKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jy') == \ JyKetCoupled(1, 1, (S.Half, S.Half))/2 - I*sqrt(2)*JyKetCoupled(1, 0, ( S.Half, S.Half))/2 - JyKetCoupled(1, -1, (S.Half, S.Half))/2 assert JzKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jy') == \ -I*sqrt(2)*JyKetCoupled(1, 1, (S.Half, S.Half))/2 - I*sqrt( 2)*JyKetCoupled(1, -1, (S.Half, S.Half))/2 assert JzKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jy') == \ -JyKetCoupled(1, 1, (S.Half, S.Half))/2 - I*sqrt(2)*JyKetCoupled(1, 0, (S.Half, S.Half))/2 + JyKetCoupled(1, -1, (S.Half, S.Half))/2 assert JxKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jz') == \ JzKetCoupled(0, 0, (S.Half, S.Half)) assert JxKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jz') == \ JzKetCoupled(1, 1, (S.Half, S.Half))/2 + sqrt(2)*JzKetCoupled(1, 0, ( S.Half, S.Half))/2 + JzKetCoupled(1, -1, (S.Half, S.Half))/2 assert JxKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jz') == \ -sqrt(2)*JzKetCoupled(1, 1, (S( 1)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half))/2 assert JxKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jz') == \ JzKetCoupled(1, 1, (S.Half, S.Half))/2 - sqrt(2)*JzKetCoupled(1, 0, ( S.Half, S.Half))/2 + JzKetCoupled(1, -1, (S.Half, S.Half))/2 assert JyKetCoupled(0, 0, (S.Half, S.Half)).rewrite('Jz') == \ JzKetCoupled(0, 0, (S.Half, S.Half)) assert JyKetCoupled(1, 1, (S.Half, S.Half)).rewrite('Jz') == \ JzKetCoupled(1, 1, (S.Half, S.Half))/2 + I*sqrt(2)*JzKetCoupled(1, 0, ( S.Half, S.Half))/2 - JzKetCoupled(1, -1, (S.Half, S.Half))/2 assert JyKetCoupled(1, 0, (S.Half, S.Half)).rewrite('Jz') == \ I*sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half))/2 + I*sqrt( 2)*JzKetCoupled(1, -1, (S.Half, S.Half))/2 assert JyKetCoupled(1, -1, (S.Half, S.Half)).rewrite('Jz') == \ -JzKetCoupled(1, 1, (S.Half, S.Half))/2 + I*sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half))/2 + JzKetCoupled(1, -1, (S.Half, S.Half))/2 # Symbolic assert JyKetCoupled(j, m, (j1, j2)).rewrite('Jx') == \ Sum(WignerD(j, mi, m, 0, 0, pi/2) * JxKetCoupled(j, mi, ( j1, j2)), (mi, -j, j)) assert JzKetCoupled(j, m, (j1, j2)).rewrite('Jx') == \ Sum(WignerD(j, mi, m, 0, pi*Rational(3, 2), 0) * JxKetCoupled(j, mi, ( j1, j2)), (mi, -j, j)) assert JxKetCoupled(j, m, (j1, j2)).rewrite('Jy') == \ Sum(WignerD(j, mi, m, pi*Rational(3, 2), 0, 0) * JyKetCoupled(j, mi, ( j1, j2)), (mi, -j, j)) assert JzKetCoupled(j, m, (j1, j2)).rewrite('Jy') == \ Sum(WignerD(j, mi, m, pi*Rational(3, 2), pi/2, pi/2) * JyKetCoupled(j, mi, (j1, j2)), (mi, -j, j)) assert JxKetCoupled(j, m, (j1, j2)).rewrite('Jz') == \ Sum(WignerD(j, mi, m, 0, pi/2, 0) * JzKetCoupled(j, mi, ( j1, j2)), (mi, -j, j)) assert JyKetCoupled(j, m, (j1, j2)).rewrite('Jz') == \ Sum(WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2) * JzKetCoupled( j, mi, (j1, j2)), (mi, -j, j)) def test_innerproducts_of_rewritten_states(): # Numerical assert qapply(JxBra(1, 1)*JxKet(1, 1).rewrite('Jy')).doit() == 1 assert qapply(JxBra(1, 0)*JxKet(1, 0).rewrite('Jy')).doit() == 1 assert qapply(JxBra(1, -1)*JxKet(1, -1).rewrite('Jy')).doit() == 1 assert qapply(JxBra(1, 1)*JxKet(1, 1).rewrite('Jz')).doit() == 1 assert qapply(JxBra(1, 0)*JxKet(1, 0).rewrite('Jz')).doit() == 1 assert qapply(JxBra(1, -1)*JxKet(1, -1).rewrite('Jz')).doit() == 1 assert qapply(JyBra(1, 1)*JyKet(1, 1).rewrite('Jx')).doit() == 1 assert qapply(JyBra(1, 0)*JyKet(1, 0).rewrite('Jx')).doit() == 1 assert qapply(JyBra(1, -1)*JyKet(1, -1).rewrite('Jx')).doit() == 1 assert qapply(JyBra(1, 1)*JyKet(1, 1).rewrite('Jz')).doit() == 1 assert qapply(JyBra(1, 0)*JyKet(1, 0).rewrite('Jz')).doit() == 1 assert qapply(JyBra(1, -1)*JyKet(1, -1).rewrite('Jz')).doit() == 1 assert qapply(JyBra(1, 1)*JyKet(1, 1).rewrite('Jz')).doit() == 1 assert qapply(JyBra(1, 0)*JyKet(1, 0).rewrite('Jz')).doit() == 1 assert qapply(JyBra(1, -1)*JyKet(1, -1).rewrite('Jz')).doit() == 1 assert qapply(JzBra(1, 1)*JzKet(1, 1).rewrite('Jy')).doit() == 1 assert qapply(JzBra(1, 0)*JzKet(1, 0).rewrite('Jy')).doit() == 1 assert qapply(JzBra(1, -1)*JzKet(1, -1).rewrite('Jy')).doit() == 1 assert qapply(JxBra(1, 1)*JxKet(1, 0).rewrite('Jy')).doit() == 0 assert qapply(JxBra(1, 1)*JxKet(1, -1).rewrite('Jy')) == 0 assert qapply(JxBra(1, 1)*JxKet(1, 0).rewrite('Jz')).doit() == 0 assert qapply(JxBra(1, 1)*JxKet(1, -1).rewrite('Jz')) == 0 assert qapply(JyBra(1, 1)*JyKet(1, 0).rewrite('Jx')).doit() == 0 assert qapply(JyBra(1, 1)*JyKet(1, -1).rewrite('Jx')) == 0 assert qapply(JyBra(1, 1)*JyKet(1, 0).rewrite('Jz')).doit() == 0 assert qapply(JyBra(1, 1)*JyKet(1, -1).rewrite('Jz')) == 0 assert qapply(JzBra(1, 1)*JzKet(1, 0).rewrite('Jx')).doit() == 0 assert qapply(JzBra(1, 1)*JzKet(1, -1).rewrite('Jx')) == 0 assert qapply(JzBra(1, 1)*JzKet(1, 0).rewrite('Jy')).doit() == 0 assert qapply(JzBra(1, 1)*JzKet(1, -1).rewrite('Jy')) == 0 assert qapply(JxBra(1, 0)*JxKet(1, 1).rewrite('Jy')) == 0 assert qapply(JxBra(1, 0)*JxKet(1, -1).rewrite('Jy')) == 0 assert qapply(JxBra(1, 0)*JxKet(1, 1).rewrite('Jz')) == 0 assert qapply(JxBra(1, 0)*JxKet(1, -1).rewrite('Jz')) == 0 assert qapply(JyBra(1, 0)*JyKet(1, 1).rewrite('Jx')) == 0 assert qapply(JyBra(1, 0)*JyKet(1, -1).rewrite('Jx')) == 0 assert qapply(JyBra(1, 0)*JyKet(1, 1).rewrite('Jz')) == 0 assert qapply(JyBra(1, 0)*JyKet(1, -1).rewrite('Jz')) == 0 assert qapply(JzBra(1, 0)*JzKet(1, 1).rewrite('Jx')) == 0 assert qapply(JzBra(1, 0)*JzKet(1, -1).rewrite('Jx')) == 0 assert qapply(JzBra(1, 0)*JzKet(1, 1).rewrite('Jy')) == 0 assert qapply(JzBra(1, 0)*JzKet(1, -1).rewrite('Jy')) == 0 assert qapply(JxBra(1, -1)*JxKet(1, 1).rewrite('Jy')) == 0 assert qapply(JxBra(1, -1)*JxKet(1, 0).rewrite('Jy')).doit() == 0 assert qapply(JxBra(1, -1)*JxKet(1, 1).rewrite('Jz')) == 0 assert qapply(JxBra(1, -1)*JxKet(1, 0).rewrite('Jz')).doit() == 0 assert qapply(JyBra(1, -1)*JyKet(1, 1).rewrite('Jx')) == 0 assert qapply(JyBra(1, -1)*JyKet(1, 0).rewrite('Jx')).doit() == 0 assert qapply(JyBra(1, -1)*JyKet(1, 1).rewrite('Jz')) == 0 assert qapply(JyBra(1, -1)*JyKet(1, 0).rewrite('Jz')).doit() == 0 assert qapply(JzBra(1, -1)*JzKet(1, 1).rewrite('Jx')) == 0 assert qapply(JzBra(1, -1)*JzKet(1, 0).rewrite('Jx')).doit() == 0 assert qapply(JzBra(1, -1)*JzKet(1, 1).rewrite('Jy')) == 0 assert qapply(JzBra(1, -1)*JzKet(1, 0).rewrite('Jy')).doit() == 0 def test_uncouple_2_coupled_states(): # j1=1/2, j2=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) # j1=1/2, j2=1 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1)) == \ expand(uncouple( couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0)) == \ expand(uncouple( couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1)) == \ expand(uncouple( couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)) == \ expand(uncouple( couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)) == \ expand(uncouple( couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)) == \ expand(uncouple( couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)) ))) # j1=1, j2=1 assert TensorProduct(JzKet(1, 1), JzKet(1, 1)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, 1), JzKet(1, 1)) ))) assert TensorProduct(JzKet(1, 1), JzKet(1, 0)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, 1), JzKet(1, 0)) ))) assert TensorProduct(JzKet(1, 1), JzKet(1, -1)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, 1), JzKet(1, -1)) ))) assert TensorProduct(JzKet(1, 0), JzKet(1, 1)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, 0), JzKet(1, 1)) ))) assert TensorProduct(JzKet(1, 0), JzKet(1, 0)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, 0), JzKet(1, 0)) ))) assert TensorProduct(JzKet(1, 0), JzKet(1, -1)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, 0), JzKet(1, -1)) ))) assert TensorProduct(JzKet(1, -1), JzKet(1, 1)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, -1), JzKet(1, 1)) ))) assert TensorProduct(JzKet(1, -1), JzKet(1, 0)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, -1), JzKet(1, 0)) ))) assert TensorProduct(JzKet(1, -1), JzKet(1, -1)) == \ expand(uncouple(couple( TensorProduct(JzKet(1, -1), JzKet(1, -1)) ))) def test_uncouple_3_coupled_states(): # Default coupling # j1=1/2, j2=1/2, j3=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet( S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.NegativeOne/ 2), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) # j1=1/2, j2=1, j3=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) # Coupling j1+j3=j13, j13+j2=j # j1=1/2, j2=1/2, j3=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) # j1=1/2, j2=1, j3=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( 1)/2), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( 1)/2), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( 1)/2), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( 1)/2), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( 1)/2), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( 1)/2), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( -1)/2), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( -1)/2), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( -1)/2), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( -1)/2), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S( -1)/2), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.NegativeOne/ 2), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ))) @slow def test_uncouple_4_coupled_states(): # j1=1/2, j2=1/2, j3=1/2, j4=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( 1)/2, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S( 1)/2, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) ))) # j1=1/2, j2=1/2, j3=1, j4=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet( S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet( S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) ))) # Couple j1+j3=j13, j2+j4=j24, j13+j24=j # j1=1/2, j2=1/2, j3=1/2, j4=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) # j1=1/2, j2=1/2, j3=1, j4=1/2 assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, S.Half)), ((1, 3), (2, 4), (1, 2)) ))) assert TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) == \ expand(uncouple(couple( TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (2, 4), (1, 2)) ))) def test_uncouple_2_coupled_states_numerical(): # j1=1/2, j2=1/2 assert uncouple(JzKetCoupled(0, 0, (S.Half, S.Half))) == \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/2 - \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/2 assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half))) == \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half))) == \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/2 + \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/2 assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half))) == \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) # j1=1, j2=1/2 assert uncouple(JzKetCoupled(S.Half, S.Half, (1, S.Half))) == \ -sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(S.Half, S.Half))/3 + \ sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(S.Half, Rational(-1, 2)))/3 assert uncouple(JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half))) == \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(S.Half, Rational(-1, 2)))/3 - \ sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(S.Half, S.Half))/3 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half))) == \ TensorProduct(JzKet(1, 1), JzKet(S.Half, S.Half)) assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half))) == \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(S.Half, Rational(-1, 2)))/3 + \ sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(S.Half, S.Half))/3 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half))) == \ sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(S.Half, Rational(-1, 2)))/3 + \ sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(S.Half, S.Half))/3 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half))) == \ TensorProduct(JzKet(1, -1), JzKet(S.Half, Rational(-1, 2))) # j1=1, j2=1 assert uncouple(JzKetCoupled(0, 0, (1, 1))) == \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1))/3 - \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 0))/3 + \ sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1))/3 assert uncouple(JzKetCoupled(1, 1, (1, 1))) == \ sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 - \ sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 assert uncouple(JzKetCoupled(1, 0, (1, 1))) == \ sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, -1))/2 - \ sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, 1))/2 assert uncouple(JzKetCoupled(1, -1, (1, 1))) == \ sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 - \ sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(2, 2, (1, 1))) == \ TensorProduct(JzKet(1, 1), JzKet(1, 1)) assert uncouple(JzKetCoupled(2, 1, (1, 1))) == \ sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + \ sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 assert uncouple(JzKetCoupled(2, 0, (1, 1))) == \ sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(1, -1))/6 + \ sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(1, 0))/3 + \ sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(1, 1))/6 assert uncouple(JzKetCoupled(2, -1, (1, 1))) == \ sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 + \ sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(2, -2, (1, 1))) == \ TensorProduct(JzKet(1, -1), JzKet(1, -1)) def test_uncouple_3_coupled_states_numerical(): # Default coupling # j1=1/2, j2=1/2, j3=1/2 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half))) == \ TensorProduct(JzKet( S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)) assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half))) == \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))/3 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/3 + \ sqrt(3)*TensorProduct(JzKet( S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/3 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half))) == \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))/3 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))/3 + \ sqrt(3)*TensorProduct(JzKet( S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))/3 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half))) == \ TensorProduct(JzKet( S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))) # j1=1/2, j2=1/2, j3=1 assert uncouple(JzKetCoupled(2, 2, (S.Half, S.Half, 1))) == \ TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)) assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1))) == \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))/2 + \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/2 + \ sqrt(2)*TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1))) == \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))/3 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/3 + \ sqrt(6)*TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1))) == \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/2 + \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))/2 + \ TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1))) == \ TensorProduct( JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)) assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1))) == \ -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))/2 - \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/2 + \ sqrt(2)*TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1))) == \ -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/2 + \ sqrt(2)*TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1))) == \ -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/2 + \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))/2 + \ TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))/2 # j1=1/2, j2=1, j3=1 assert uncouple(JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, 1, 1))) == \ TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)) assert uncouple(JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, 1, 1))) == \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/5 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/5 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/5 assert uncouple(JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1))) == \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/5 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/5 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/5 + \ sqrt(10)*TensorProduct( JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1))) == \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/5 + \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/5 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/5 assert uncouple(JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1))) == \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/5 + \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/5 + \ sqrt(5)*TensorProduct( JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/5 assert uncouple(JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, 1, 1))) == \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)) assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1))) == \ -sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/15 - \ 2*sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/5 assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1))) == \ -4*sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/15 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 - \ 2*sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/15 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/5 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1))) == \ -sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/5 - \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ 2*sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/15 - \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ 4*sqrt(5)*TensorProduct( JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1))) == \ -sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/5 + \ 2*sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/15 + \ sqrt(30)*TensorProduct( JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1))) == \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/3 - \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/3 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 - \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/3 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1))) == \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/2 - \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/3 + \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 - \ TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/3 + \ TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/3 # j1=1, j2=1, j3=1 assert uncouple(JzKetCoupled(3, 3, (1, 1, 1))) == \ TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 1)) assert uncouple(JzKetCoupled(3, 2, (1, 1, 1))) == \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))/3 + \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1))/3 + \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))/3 assert uncouple(JzKetCoupled(3, 1, (1, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(3, 0, (1, 1, 1))) == \ sqrt(10)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/10 + \ sqrt(10)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/10 + \ sqrt(10)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/10 + \ sqrt(10)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0))/5 + \ sqrt(10)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/10 + \ sqrt(10)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/10 + \ sqrt(10)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(3, -1, (1, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/15 + \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(3, -2, (1, 1, 1))) == \ sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))/3 + \ sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1))/3 + \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(3, -3, (1, 1, 1))) == \ TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, -1)) assert uncouple(JzKetCoupled(2, 2, (1, 1, 1))) == \ -sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))/6 - \ sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))/3 assert uncouple(JzKetCoupled(2, 1, (1, 1, 1))) == \ -sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/6 - \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/3 + \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))/6 - \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(2, 0, (1, 1, 1))) == \ -TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/2 - \ TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/2 + \ TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/2 + \ TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, -1, (1, 1, 1))) == \ -sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/3 - \ sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))/6 - \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/3 + \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(2, -2, (1, 1, 1))) == \ -sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))/3 + \ sqrt(6)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1))/6 + \ sqrt(6)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(1, 1, (1, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/30 + \ sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/15 - \ sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))/10 + \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))/30 - \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/10 + \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/5 assert uncouple(JzKetCoupled(1, 0, (1, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/10 - \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/10 - \ 2*sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/10 - \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(1, -1, (1, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/5 - \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/10 + \ sqrt(15)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))/30 - \ sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))/10 + \ sqrt(15)*TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/15 + \ sqrt(15)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/30 # Defined j13 # j1=1/2, j2=1/2, j3=1, j13=1/2 assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )) == \ -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))/3 + \ sqrt(3)*TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))/3 assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))/3 - \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))/3 + \ sqrt(6)*TensorProduct( JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))/3 # j1=1/2, j2=1, j3=1, j13=1/2 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/3 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/3 assert uncouple(JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ -2*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/3 - \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/3 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/3 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/3 - \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/3 + \ TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/3 + \ 2*TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ sqrt(6)*TensorProduct( JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/3 # j1=1, j2=1, j3=1, j13=1 assert uncouple(JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ -sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))/2 + \ sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ -TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/2 - \ TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/2 + \ TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/2 + \ TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ -sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))/3 - \ sqrt(3)*TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/6 - \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/6 + \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ -TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/2 - \ TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/2 + \ TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/2 + \ TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)))) == \ -sqrt(2)*TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))/2 + \ sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)))) == \ TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))/2 - \ TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))/2 + \ TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))/2 - \ TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)))) == \ TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))/2 - \ TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))/2 - \ TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))/2 + \ TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)))) == \ -TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))/2 + \ TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))/2 - \ TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))/2 + \ TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))/2 def test_uncouple_4_coupled_states_numerical(): # j1=1/2, j2=1/2, j3=1, j4=1, default coupling assert uncouple(JzKetCoupled(3, 3, (S.Half, S.Half, 1, 1))) == \ TensorProduct(JzKet( S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)) assert uncouple(JzKetCoupled(3, 2, (S.Half, S.Half, 1, 1))) == \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/3 + \ sqrt(3)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/3 assert uncouple(JzKetCoupled(3, 1, (S.Half, S.Half, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(3, 0, (S.Half, S.Half, 1, 1))) == \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/5 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/5 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(3, -1, (S.Half, S.Half, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(3, -2, (S.Half, S.Half, 1, 1))) == \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/3 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(3, -3, (S.Half, S.Half, 1, 1))) == \ TensorProduct(JzKet(S.Half, -S( 1)/2), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)) assert uncouple(JzKetCoupled(2, 2, (S.Half, S.Half, 1, 1))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/6 - \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 - \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/3 assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1, 1))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 - \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/12 - \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/12 - \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1, 1))) == \ -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/2 - \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/4 - \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/4 + \ TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1, 1))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/3 - \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 - \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/12 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/6 - \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/12 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1, 1))) == \ -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/30 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/20 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/20 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/30 - \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/10 + \ sqrt(15)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/5 assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 - \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/20 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/20 - \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1, 1))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/5 - \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/10 + \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/20 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/20 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/30 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/30 # j1=1/2, j2=1/2, j3=1, j4=1, j12=1, j34=1 assert uncouple(JzKetCoupled(2, 2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ -sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/2 + \ sqrt(2)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/2 assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/4 - \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/4 - \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/2 + \ TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/6 - \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/6 - \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 - \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/6 + \ sqrt(3)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/2 + \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/2 - \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/4 - \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/4 assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 2)))) == \ -sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/2 + \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/4 - \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/4 - \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/4 - \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/2 + \ TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/2 - \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/2 - \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/2 + \ TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 1), (1, 3, 1)))) == \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/2 - \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/2 - \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/4 - \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/4 + \ sqrt(2)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/4 # j1=1/2, j2=1/2, j3=1, j4=1, j12=1, j34=2 assert uncouple(JzKetCoupled(3, 3, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ TensorProduct(JzKet( S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)) assert uncouple(JzKetCoupled(3, 2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/3 + \ sqrt(3)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/3 assert uncouple(JzKetCoupled(3, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(3, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/5 + \ sqrt(5)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/10 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/5 + \ sqrt(5)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/10 + \ sqrt(10)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(3, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/15 + \ 2*sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/15 + \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/15 assert uncouple(JzKetCoupled(3, -2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/3 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/3 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(3, -3, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 3)))) == \ TensorProduct(JzKet(S.Half, -S( 1)/2), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)) assert uncouple(JzKetCoupled(2, 2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))/3 - \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/3 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/6 + \ sqrt(6)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/6 assert uncouple(JzKetCoupled(2, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/3 - \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/12 - \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/12 - \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/12 - \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/12 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/3 + \ sqrt(3)*TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/6 assert uncouple(JzKetCoupled(2, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ -TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/2 - \ TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/2 + \ TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/2 + \ TensorProduct(JzKet(S( 1)/2, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/2 assert uncouple(JzKetCoupled(2, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ -sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/6 - \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/3 - \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/6 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/12 + \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/12 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/12 + \ sqrt(6)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/12 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(2, -2, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 2)))) == \ -sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/6 - \ sqrt(6)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/6 + \ sqrt(3)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/3 + \ sqrt(3)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))/3 assert uncouple(JzKetCoupled(1, 1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))/5 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/20 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/30 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/30 assert uncouple(JzKetCoupled(1, 0, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))/10 + \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))/10 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))/15 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/30 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/10 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/10 assert uncouple(JzKetCoupled(1, -1, (S.Half, S.Half, 1, 1), ((1, 2, 1), (3, 4, 2), (1, 3, 1)))) == \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))/30 + \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))/15 + \ sqrt(15)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))/30 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))/20 - \ sqrt(30)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))/20 + \ sqrt(15)*TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))/5 def test_uncouple_symbolic(): assert uncouple(JzKetCoupled(j, m, (j1, j2) )) == \ Sum(CG(j1, m1, j2, m2, j, m) * TensorProduct(JzKet(j1, m1), JzKet(j2, m2)), (m1, -j1, j1), (m2, -j2, j2)) assert uncouple(JzKetCoupled(j, m, (j1, j2, j3) )) == \ Sum(CG(j1, m1, j2, m2, j1 + j2, m1 + m2) * CG(j1 + j2, m1 + m2, j3, m3, j, m) * TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3)), (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3)) assert uncouple(JzKetCoupled(j, m, (j1, j2, j3), ((1, 3, j13), (1, 2, j)) )) == \ Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j13, m1 + m3, j2, m2, j, m) * TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3)), (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3)) assert uncouple(JzKetCoupled(j, m, (j1, j2, j3, j4) )) == \ Sum(CG(j1, m1, j2, m2, j1 + j2, m1 + m2) * CG(j1 + j2, m1 + m2, j3, m3, j1 + j2 + j3, m1 + m2 + m3) * CG(j1 + j2 + j3, m1 + m2 + m3, j4, m4, j, m) * TensorProduct( JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3), (m4, -j4, j4)) assert uncouple(JzKetCoupled(j, m, (j1, j2, j3, j4), ((1, 3, j13), (2, 4, j24), (1, 2, j)) )) == \ Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j2, m2, j4, m4, j24, m2 + m4) * CG(j13, m1 + m3, j24, m2 + m4, j, m) * TensorProduct( JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), (m1, -j1, j1), (m2, -j2, j2), (m3, -j3, j3), (m4, -j4, j4)) def test_couple_2_states(): # j1=1/2, j2=1/2 assert JzKetCoupled(0, 0, (S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(0, 0, (S.Half, S.Half)) ))) assert JzKetCoupled(1, 1, (S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, S.Half)) ))) assert JzKetCoupled(1, 0, (S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, S.Half)) ))) assert JzKetCoupled(1, -1, (S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, S.Half)) ))) # j1=1, j2=1/2 assert JzKetCoupled(S.Half, S.Half, (1, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (1, S.Half)) ))) assert JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half)) ))) # j1=1, j2=1 assert JzKetCoupled(0, 0, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(0, 0, (1, 1)) ))) assert JzKetCoupled(1, 1, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(1, 1, (1, 1)) ))) assert JzKetCoupled(1, 0, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(1, 0, (1, 1)) ))) assert JzKetCoupled(1, -1, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (1, 1)) ))) assert JzKetCoupled(2, 2, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, 2, (1, 1)) ))) assert JzKetCoupled(2, 1, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, 1, (1, 1)) ))) assert JzKetCoupled(2, 0, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, 0, (1, 1)) ))) assert JzKetCoupled(2, -1, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, -1, (1, 1)) ))) assert JzKetCoupled(2, -2, (1, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, -2, (1, 1)) ))) # j1=1/2, j2=3/2 assert JzKetCoupled(1, 1, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, Rational(3, 2))) ))) assert JzKetCoupled(1, 0, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, Rational(3, 2))) ))) assert JzKetCoupled(1, -1, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, Rational(3, 2))) ))) assert JzKetCoupled(2, 2, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(2, 2, (S.Half, Rational(3, 2))) ))) assert JzKetCoupled(2, 1, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(2, 1, (S.Half, Rational(3, 2))) ))) assert JzKetCoupled(2, 0, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(2, 0, (S.Half, Rational(3, 2))) ))) assert JzKetCoupled(2, -1, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(2, -1, (S.Half, Rational(3, 2))) ))) assert JzKetCoupled(2, -2, (S.Half, Rational(3, 2))) == \ expand(couple(uncouple( JzKetCoupled(2, -2, (S.Half, Rational(3, 2))) ))) def test_couple_3_states(): # Default coupling # j1=1/2, j2=1/2, j3=1/2 assert JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half)) ))) # j1=1/2, j2=1/2, j3=1 assert JzKetCoupled(0, 0, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(0, 0, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(1, 1, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(1, 0, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(1, -1, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(2, 2, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, 2, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(2, 1, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, 1, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(2, 0, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, 0, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(2, -1, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, -1, (S.Half, S.Half, 1)) ))) assert JzKetCoupled(2, -2, (S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(2, -2, (S.Half, S.Half, 1)) ))) # Couple j1+j3=j13, j13+j2=j # j1=1/2, j2=1/2, j3=1/2, j13=0 assert JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half))) == \ expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (S.Half, S( 1)/2, S.Half), ((1, 3, 0), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half))) == \ expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S( 1)/2, S.Half), ((1, 3, 0), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) # j1=1, j2=1/2, j3=1, j13=1 assert JzKetCoupled(S.Half, S.Half, (1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) == \ expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, ( 1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) assert JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) == \ expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), ( 1, S.Half, 1), ((1, 3, 1), (1, 2, S.Half))) ), ((1, 3), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), ( 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) ), ((1, 3), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, ( 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) ), ((1, 3), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), ( 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) ), ((1, 3), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), ( 1, S.Half, 1), ((1, 3, 1), (1, 2, Rational(3, 2)))) ), ((1, 3), (1, 2)) )) def test_couple_4_states(): # Default coupling # j1=1/2, j2=1/2, j3=1/2, j4=1/2 assert JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple( uncouple( JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple( uncouple( JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(2, 2, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple( uncouple( JzKetCoupled(2, 2, (S.Half, S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(2, 1, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple( uncouple( JzKetCoupled(2, 1, (S.Half, S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple( uncouple( JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(2, -1, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(2, -1, (S.Half, S.Half, S.Half, S.Half)) ))) assert JzKetCoupled(2, -2, (S.Half, S.Half, S.Half, S.Half)) == \ expand(couple(uncouple( JzKetCoupled(2, -2, (S.Half, S.Half, S.Half, S.Half)) ))) # j1=1/2, j2=1/2, j3=1/2, j4=1 assert JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1)) ))) assert JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S.Half, S.Half, 1)) == \ expand(couple(uncouple( JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S.Half, S.Half, 1)) ))) # Coupling j1+j3=j13, j2+j4=j24, j13+j24=j # j1=1/2, j2=1/2, j3=1/2, j4=1/2, j13=1, j24=0 assert JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 3, 1), (2, 4, 0), (1, 2, 1)) ) ), ((1, 3), (2, 4), (1, 2)) )) # j1=1/2, j2=1/2, j3=1/2, j4=1, j13=1, j24=1/2 assert JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) ) == \ expand(couple(uncouple( JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) )), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) ) == \ expand(couple(uncouple( JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, S.Half)) ) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) == \ expand(couple(uncouple( JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 3, 1), (2, 4, S.Half), (1, 2, Rational(3, 2))) ) ), ((1, 3), (2, 4), (1, 2)) )) # j1=1/2, j2=1, j3=1/2, j4=1, j13=0, j24=1 assert JzKetCoupled(1, 1, (S.Half, 1, S.Half, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, 1, S.Half, 1), ( (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ( (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(1, -1, (S.Half, 1, S.Half, 1), ((1, 3, 0), (2, 4, 1), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, 1, S.Half, 1), ( (1, 3, 0), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) # j1=1/2, j2=1, j3=1/2, j4=1, j13=1, j24=1 assert JzKetCoupled(0, 0, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 0)) ) == \ expand(couple(uncouple( JzKetCoupled(0, 0, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 0))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(1, 1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, 1, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, 0, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(1, -1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 1)) ) == \ expand(couple(uncouple( JzKetCoupled(1, -1, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 1))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(2, 2, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ expand(couple(uncouple( JzKetCoupled(2, 2, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(2, 1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ expand(couple(uncouple( JzKetCoupled(2, 1, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(2, 0, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ expand(couple(uncouple( JzKetCoupled(2, 0, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(2, -1, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ expand(couple(uncouple( JzKetCoupled(2, -1, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) assert JzKetCoupled(2, -2, (S.Half, 1, S.Half, 1), ((1, 3, 1), (2, 4, 1), (1, 2, 2)) ) == \ expand(couple(uncouple( JzKetCoupled(2, -2, (S.Half, 1, S.Half, 1), ( (1, 3, 1), (2, 4, 1), (1, 2, 2))) ), ((1, 3), (2, 4), (1, 2)) )) def test_couple_2_states_numerical(): # j1=1/2, j2=1/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ JzKetCoupled(1, 1, (S.Half, S.Half)) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(2)*JzKetCoupled(0, 0, (S( 1)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half))/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ -sqrt(2)*JzKetCoupled(0, 0, (S( 1)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half))/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ JzKetCoupled(1, -1, (S.Half, S.Half)) # j1=1, j2=1/2 assert couple(TensorProduct(JzKet(1, 1), JzKet(S.Half, S.Half))) == \ JzKetCoupled(Rational(3, 2), Rational(3, 2), (1, S.Half)) assert couple(TensorProduct(JzKet(1, 1), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (1, S.Half))/3 + sqrt( 3)*JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half))/3 assert couple(TensorProduct(JzKet(1, 0), JzKet(S.Half, S.Half))) == \ -sqrt(3)*JzKetCoupled(S.Half, S.Half, (1, S.Half))/3 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (1, S.Half))/3 assert couple(TensorProduct(JzKet(1, 0), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (1, S.Half))/3 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half))/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(S.Half, S.Half))) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (1, S( 1)/2))/3 + sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (1, S.Half))/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(S.Half, Rational(-1, 2)))) == \ JzKetCoupled(Rational(3, 2), Rational(-3, 2), (1, S.Half)) # j1=1, j2=1 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ JzKetCoupled(2, 2, (1, 1)) assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0))) == \ sqrt(2)*JzKetCoupled( 1, 1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, 1, (1, 1))/2 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ sqrt(3)*JzKetCoupled(0, 0, (1, 1))/3 + sqrt(2)*JzKetCoupled( 1, 0, (1, 1))/2 + sqrt(6)*JzKetCoupled(2, 0, (1, 1))/6 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1))) == \ -sqrt(2)*JzKetCoupled( 1, 1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, 1, (1, 1))/2 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0))) == \ -sqrt(3)*JzKetCoupled( 0, 0, (1, 1))/3 + sqrt(6)*JzKetCoupled(2, 0, (1, 1))/3 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1))) == \ sqrt(2)*JzKetCoupled( 1, -1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, -1, (1, 1))/2 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1))) == \ sqrt(3)*JzKetCoupled(0, 0, (1, 1))/3 - sqrt(2)*JzKetCoupled( 1, 0, (1, 1))/2 + sqrt(6)*JzKetCoupled(2, 0, (1, 1))/6 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0))) == \ -sqrt(2)*JzKetCoupled( 1, -1, (1, 1))/2 + sqrt(2)*JzKetCoupled(2, -1, (1, 1))/2 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1))) == \ JzKetCoupled(2, -2, (1, 1)) # j1=3/2, j2=1/2 assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(3, 2)), JzKet(S.Half, S.Half))) == \ JzKetCoupled(2, 2, (Rational(3, 2), S.Half)) assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(3, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(3)*JzKetCoupled( 1, 1, (Rational(3, 2), S.Half))/2 + JzKetCoupled(2, 1, (Rational(3, 2), S.Half))/2 assert couple(TensorProduct(JzKet(Rational(3, 2), S.Half), JzKet(S.Half, S.Half))) == \ -JzKetCoupled(1, 1, (S( 3)/2, S.Half))/2 + sqrt(3)*JzKetCoupled(2, 1, (Rational(3, 2), S.Half))/2 assert couple(TensorProduct(JzKet(Rational(3, 2), S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(2)*JzKetCoupled(1, 0, (S( 3)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(2, 0, (Rational(3, 2), S.Half))/2 assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ -sqrt(2)*JzKetCoupled(1, 0, (S( 3)/2, S.Half))/2 + sqrt(2)*JzKetCoupled(2, 0, (Rational(3, 2), S.Half))/2 assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ JzKetCoupled(1, -1, (S( 3)/2, S.Half))/2 + sqrt(3)*JzKetCoupled(2, -1, (Rational(3, 2), S.Half))/2 assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-3, 2)), JzKet(S.Half, S.Half))) == \ -sqrt(3)*JzKetCoupled(1, -1, (Rational(3, 2), S.Half))/2 + \ JzKetCoupled(2, -1, (Rational(3, 2), S.Half))/2 assert couple(TensorProduct(JzKet(Rational(3, 2), Rational(-3, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ JzKetCoupled(2, -2, (Rational(3, 2), S.Half)) def test_couple_3_states_numerical(): # Default coupling # j1=1/2,j2=1/2,j3=1/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ JzKetCoupled(Rational(3, 2), S( 3)/2, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ 2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 - \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ 2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 + \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One /2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 - \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ 2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half)) )/2 + \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One /2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One /2), ((1, 2, 1), (1, 3, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ JzKetCoupled(Rational(3, 2), -S( 3)/2, (S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2))) ) # j1=S.Half, j2=S.Half, j3=1 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ JzKetCoupled(2, 2, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(2)*JzKetCoupled( 2, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/3 + \ sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 - \ JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ -sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ sqrt(3)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/3 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 - \ JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ -sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/6 - \ sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ sqrt(3)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 0), (1, 3, 1)) )/2 + \ JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 0)) )/3 - \ sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(2)*JzKetCoupled( 2, -1, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ JzKetCoupled(2, -2, (S.Half, S.Half, 1), ((1, 2, 1), (1, 3, 2)) ) # j1=S.Half, j2=1, j3=1 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1))) == \ JzKetCoupled( Rational(5, 2), Rational(5, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0))) == \ sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(S( 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1))) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/2 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1))) == \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(S( 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0))) == \ JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(S( 5)/2, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1))) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ 4*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1))) == \ -2*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0))) == \ -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ 2*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1))) == \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1))) == \ -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(S( 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0))) == \ -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ 2*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(S( 5)/2, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1))) == \ -2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1))) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ 4*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(S( 5)/2, S.Half, (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0))) == \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1))) == \ -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, S.Half), (1, 3, Rational(3, 2))) )/3 + \ 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1))) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, S.Half)) )/2 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0))) == \ -sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1))) == \ JzKetCoupled(S( 5)/2, Rational(-5, 2), (S.Half, 1, 1), ((1, 2, Rational(3, 2)), (1, 3, Rational(5, 2))) ) # j1=1, j2=1, j3=1 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 1))) == \ JzKetCoupled(3, 3, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) ) assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0))) == \ sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1))) == \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/5 + \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1))) == \ sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0))) == \ JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1))) == \ sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 + \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1))) == \ sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 + \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0))) == \ -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 + \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/3 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1))) == \ sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 + \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1))) == \ -sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0))) == \ -JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1))) == \ -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 - \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 + \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1))) == \ -sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 - \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0))) == \ -sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ 2*sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/5 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1))) == \ -sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 + \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1))) == \ sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 - \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 - \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0))) == \ -JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 + \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1))) == \ sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1))) == \ sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 + \ JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 - \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0))) == \ sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/15 - \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/3 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1))) == \ sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 0), (1, 3, 1)) )/3 - \ JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/30 - \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1))) == \ -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 0)) )/6 + \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/6 - \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/10 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0))) == \ JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/10 - \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1))) == \ -sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 1), (1, 3, 2)) )/2 + \ sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1))) == \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 1)) )/5 - \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0))) == \ -sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 2)) )/3 + \ sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) )/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, -1))) == \ JzKetCoupled(3, -3, (1, 1, 1), ((1, 2, 2), (1, 3, 3)) ) # j1=S.Half, j2=S.Half, j3=Rational(3, 2) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2)))) == \ JzKetCoupled(Rational(5, 2), S( 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half))) == \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3) /2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ 2*sqrt(30)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/15 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/2 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2)))) == \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ 2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half))) == \ -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) /2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2)))) == \ -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ 2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half))) == \ -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/30 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 0), (1, 3, Rational(3, 2))) )/2 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) /2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2)))) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/2 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half))) == \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, S.Half)) )/6 - \ 2*sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/15 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2)))) == \ -sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(3, 2))) )/5 + \ sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S( 3)/2), ((1, 2, 1), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2)))) == \ JzKetCoupled(Rational(5, 2), -S( 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 2, 1), (1, 3, Rational(5, 2))) ) # Couple j1 to j3 # j1=1/2, j2=1/2, j3=1/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(Rational(3, 2), S( 3)/2, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, Rational(3, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 - \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ 2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ 2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 + \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One /2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 - \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.One/ 2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One /2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 0), (1, 2, S.Half)) )/2 + \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.One /2), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ JzKetCoupled(Rational(3, 2), -S( 3)/2, (S.Half, S.Half, S.Half), ((1, 3, 1), (1, 2, Rational(3, 2))) ) # j1=1/2, j2=1/2, j3=1 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(2, 2, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 - \ sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ sqrt(2)*JzKetCoupled( 2, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/3 + \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 - \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ sqrt(6)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/6 + \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/6 + \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/3 + \ sqrt(3)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/3 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 + \ sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ JzKetCoupled( 2, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 - \ sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ JzKetCoupled(2, 1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/6 - \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/6 - \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/3 + \ sqrt(3)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/3 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/2 + \ JzKetCoupled( 2, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 0)) )/3 - \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 + \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ sqrt(6)*JzKetCoupled( 2, 0, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, S.Half), (1, 2, 1)) )/3 + \ sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 1)) )/6 + \ sqrt(2)*JzKetCoupled( 2, -1, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(2, -2, (S.Half, S.Half, 1), ((1, 3, Rational(3, 2)), (1, 2, 2)) ) # j 1=1/2, j 2=1, j 3=1 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ JzKetCoupled( Rational(5, 2), Rational(5, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(S( 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -2*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(S( 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(S( 5)/2, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 + \ 2*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/2 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 + \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ 4*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(S( 5)/2, Rational(3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 - \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ 4*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(S( 5)/2, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/2 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ JzKetCoupled(S.Half, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 - \ 2*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(S( 5)/2, S.Half, (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, S.Half), (1, 2, Rational(3, 2))) )/3 + \ 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(S( 5)/2, Rational(-5, 2), (S.Half, 1, 1), ((1, 3, Rational(3, 2)), (1, 2, Rational(5, 2))) ) # j1=1, 1, 1 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(3, 3, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) ) assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 + \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 + \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/3 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/5 + \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 + \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 assert couple(TensorProduct(JzKet(1, 1), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 + \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ sqrt(6)*JzKetCoupled(2, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, 2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 - \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 - \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 - \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ 2*sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/5 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 + \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 - \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 + \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 + \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, 0), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 + \ JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 - \ JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, 1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/6 - \ JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/2 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/5 - \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(0, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 0)) )/6 + \ sqrt(3)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ sqrt(15)*JzKetCoupled(1, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/15 - \ sqrt(3)*JzKetCoupled(2, 0, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/3 + \ sqrt(10)*JzKetCoupled(3, 0, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/10 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 - \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/10 - \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 - \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ 2*sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, 0), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/3 + \ sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 1)), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 0), (1, 2, 1)) )/3 - \ JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 1)) )/2 + \ sqrt(15)*JzKetCoupled(1, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 1)) )/30 - \ JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ sqrt(3)*JzKetCoupled(2, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(15)*JzKetCoupled(3, -1, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/15 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, 0)), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 1), (1, 2, 2)) )/2 + \ sqrt(6)*JzKetCoupled(2, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 2)) )/6 + \ sqrt(3)*JzKetCoupled(3, -2, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) )/3 assert couple(TensorProduct(JzKet(1, -1), JzKet(1, -1), JzKet(1, -1)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(3, -3, (1, 1, 1), ((1, 3, 2), (1, 2, 3)) ) # j1=1/2, j2=1/2, j3=3/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ JzKetCoupled(Rational(5, 2), S( 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 - \ sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3) /2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/2 + \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 - \ sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ 2*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ 2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/6 + \ 3*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) /2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S.Half, S(3)/ 2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 - \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 - \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/6 - \ 3*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ -2*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S(3) /2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(3, 2))), ((1, 3), (1, 2)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/2 - \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 + \ sqrt(15)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), S.Half)), ((1, 3), (1, 2)) ) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, S.Half)) )/6 - \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/5 + \ sqrt(30)*JzKetCoupled(Rational(5, 2), -S( 1)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-1, 2))), ((1, 3), (1, 2)) ) == \ -JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 1), (1, 2, Rational(3, 2))) )/2 + \ sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(3, 2))) )/10 + \ sqrt(15)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S.Half, S( 3)/2), ((1, 3, 2), (1, 2, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(Rational(3, 2), Rational(-3, 2))), ((1, 3), (1, 2)) ) == \ JzKetCoupled(Rational(5, 2), -S( 5)/2, (S.Half, S.Half, Rational(3, 2)), ((1, 3, 2), (1, 2, Rational(5, 2))) ) def test_couple_4_states_numerical(): # Default coupling # j1=1/2, j2=1/2, j3=1/2, j4=1/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ JzKetCoupled(2, 2, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 - \ sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/3 + \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 + \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 - \ sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)))/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)))/6 + \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)))/2 - \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)))/6 + \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)))/6 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)))/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)) )/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/6 + \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 + \ sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 - \ sqrt(6)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ sqrt(3)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)) )/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/6 - \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 - \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 + \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 0)) )/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/6 - \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 - \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (1, 3, S.Half), (1, 4, 1)) )/2 + \ sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/6 + \ sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half))) == \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 0)) )/3 - \ sqrt(3)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 - \ sqrt(6)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)))) == \ -sqrt(6)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, S.Half), (1, 4, 1)) )/3 + \ sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/6 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half))) == \ -sqrt(3)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 1)) )/2 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)))) == \ JzKetCoupled(2, -2, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, 2)) ) # j1=S.Half, S.Half, S.Half, 1 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/2 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 + \ 2*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ 2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 - \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ -sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 - \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 - \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ -sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 - \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 - \ sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 - \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/6 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 - \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/2 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/6 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1))) == \ 2*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0))) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, S.Half)) )/3 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/3 - \ 2*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1))) == \ -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, S.Half), (1, 4, Rational(3, 2))) )/3 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1))) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, S.Half)) )/2 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0))) == \ -sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1))) == \ JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (1, 3, Rational(3, 2)), (1, 4, Rational(5, 2))) ) # Couple j1 to j2, j3 to j4 # j1=1/2, j2=1/2, j3=1/2, j4=1/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ JzKetCoupled(2, 2, (S( 1)/2, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/3 + \ sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 + \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 + \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ JzKetCoupled(1, 1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, 1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ -JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 - \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 0), (1, 3, 0)) )/2 - \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/6 - \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 - \ JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 0), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(3)*JzKetCoupled(0, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 0)) )/3 - \ sqrt(2)*JzKetCoupled(1, 0, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ sqrt(6)*JzKetCoupled(2, 0, (S.Half, S.Half, S.Half, S.One/ 2), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/6 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 - \ JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 0), (1, 3, 1)) )/2 - \ JzKetCoupled(1, -1, (S.Half, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 1)) )/2 + \ JzKetCoupled(2, -1, (S.Half, S( 1)/2, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) )/2 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2))), ((1, 2), (3, 4), (1, 3)) ) == \ JzKetCoupled(2, -2, (S( 1)/2, S.Half, S.Half, S.Half), ((1, 2, 1), (3, 4, 1), (1, 3, 2)) ) # j1=S.Half, S.Half, S.Half, 1 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ JzKetCoupled(Rational(5, 2), Rational(5, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) ) assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ 2*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ 4*sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/2 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 + \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 + \ sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 - \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(6)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ sqrt(3)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 + \ JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(5)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(3)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 + \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(3)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 - \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ sqrt(6)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/30 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(6)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/6 - \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 - \ sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/3 - \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 + \ sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 0), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/2 + \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/10 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(2)*JzKetCoupled(S.Half, S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/2 - \ sqrt(10)*JzKetCoupled(Rational(3, 2), S.Half, (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/5 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), S.Half, (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/3 + \ JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ 4*sqrt(5)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, S.Half), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ sqrt(6)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ sqrt(30)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(5)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 1)), ((1, 2), (3, 4), (1, 3)) ) == \ 2*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, S.Half)) )/3 + \ sqrt(2)*JzKetCoupled(S.Half, Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, S.Half)) )/6 - \ sqrt(2)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ 2*sqrt(10)*JzKetCoupled(Rational(3, 2), Rational(-1, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-1, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/10 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, 0)), ((1, 2), (3, 4), (1, 3)) ) == \ -sqrt(3)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, S.Half), (1, 3, Rational(3, 2))) )/3 - \ 2*sqrt(15)*JzKetCoupled(Rational(3, 2), Rational(-3, 2), (S.Half, S.Half, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(3, 2))) )/15 + \ sqrt(10)*JzKetCoupled(Rational(5, 2), Rational(-3, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) )/5 assert couple(TensorProduct(JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(S.Half, Rational(-1, 2)), JzKet(1, -1)), ((1, 2), (3, 4), (1, 3)) ) == \ JzKetCoupled(Rational(5, 2), Rational(-5, 2), (S.Half, S( 1)/2, S.Half, 1), ((1, 2, 1), (3, 4, Rational(3, 2)), (1, 3, Rational(5, 2))) ) def test_couple_symbolic(): assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ Sum(CG(j1, m1, j2, m2, j, m1 + m2) * JzKetCoupled(j, m1 + m2, ( j1, j2)), (j, m1 + m2, j1 + j2)) assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3))) == \ Sum(CG(j1, m1, j2, m2, j12, m1 + m2) * CG(j12, m1 + m2, j3, m3, j, m1 + m2 + m3) * JzKetCoupled(j, m1 + m2 + m3, (j1, j2, j3), ((1, 2, j12), (1, 3, j)) ), (j12, m1 + m2, j1 + j2), (j, m1 + m2 + m3, j12 + j3)) assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3)), ((1, 3), (1, 2)) ) == \ Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j13, m1 + m3, j2, m2, j, m1 + m2 + m3) * JzKetCoupled(j, m1 + m2 + m3, (j1, j2, j3), ((1, 3, j13), (1, 2, j)) ), (j13, m1 + m3, j1 + j3), (j, m1 + m2 + m3, j13 + j2)) assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4))) == \ Sum(CG(j1, m1, j2, m2, j12, m1 + m2) * CG(j12, m1 + m2, j3, m3, j123, m1 + m2 + m3) * CG(j123, m1 + m2 + m3, j4, m4, j, m1 + m2 + m3 + m4) * JzKetCoupled(j, m1 + m2 + m3 + m4, ( j1, j2, j3, j4), ((1, 2, j12), (1, 3, j123), (1, 4, j)) ), (j12, m1 + m2, j1 + j2), (j123, m1 + m2 + m3, j12 + j3), (j, m1 + m2 + m3 + m4, j123 + j4)) assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), ((1, 2), (3, 4), (1, 3)) ) == \ Sum(CG(j1, m1, j2, m2, j12, m1 + m2) * CG(j3, m3, j4, m4, j34, m3 + m4) * CG(j12, m1 + m2, j34, m3 + m4, j, m1 + m2 + m3 + m4) * JzKetCoupled(j, m1 + m2 + m3 + m4, ( j1, j2, j3, j4), ((1, 2, j12), (3, 4, j34), (1, 3, j)) ), (j12, m1 + m2, j1 + j2), (j34, m3 + m4, j3 + j4), (j, m1 + m2 + m3 + m4, j12 + j34)) assert couple(TensorProduct(JzKet(j1, m1), JzKet(j2, m2), JzKet(j3, m3), JzKet(j4, m4)), ((1, 3), (1, 4), (1, 2)) ) == \ Sum(CG(j1, m1, j3, m3, j13, m1 + m3) * CG(j13, m1 + m3, j4, m4, j134, m1 + m3 + m4) * CG(j134, m1 + m3 + m4, j2, m2, j, m1 + m2 + m3 + m4) * JzKetCoupled(j, m1 + m2 + m3 + m4, ( j1, j2, j3, j4), ((1, 3, j13), (1, 4, j134), (1, 2, j)) ), (j13, m1 + m3, j1 + j3), (j134, m1 + m3 + m4, j13 + j4), (j, m1 + m2 + m3 + m4, j134 + j2)) def test_innerproduct(): assert InnerProduct(JzBra(1, 1), JzKet(1, 1)).doit() == 1 assert InnerProduct( JzBra(S.Half, S.Half), JzKet(S.Half, Rational(-1, 2))).doit() == 0 assert InnerProduct(JzBra(j, m), JzKet(j, m)).doit() == 1 assert InnerProduct(JzBra(1, 0), JyKet(1, 1)).doit() == I/sqrt(2) assert InnerProduct( JxBra(S.Half, S.Half), JzKet(S.Half, S.Half)).doit() == -sqrt(2)/2 assert InnerProduct(JyBra(1, 1), JzKet(1, 1)).doit() == S.Half assert InnerProduct(JxBra(1, -1), JyKet(1, 1)).doit() == 0 def test_rotation_small_d(): # Symbolic tests # j = 1/2 assert Rotation.d(S.Half, S.Half, S.Half, beta).doit() == cos(beta/2) assert Rotation.d(S.Half, S.Half, Rational(-1, 2), beta).doit() == -sin(beta/2) assert Rotation.d(S.Half, Rational(-1, 2), S.Half, beta).doit() == sin(beta/2) assert Rotation.d(S.Half, Rational(-1, 2), Rational(-1, 2), beta).doit() == cos(beta/2) # j = 1 assert Rotation.d(1, 1, 1, beta).doit() == (1 + cos(beta))/2 assert Rotation.d(1, 1, 0, beta).doit() == -sin(beta)/sqrt(2) assert Rotation.d(1, 1, -1, beta).doit() == (1 - cos(beta))/2 assert Rotation.d(1, 0, 1, beta).doit() == sin(beta)/sqrt(2) assert Rotation.d(1, 0, 0, beta).doit() == cos(beta) assert Rotation.d(1, 0, -1, beta).doit() == -sin(beta)/sqrt(2) assert Rotation.d(1, -1, 1, beta).doit() == (1 - cos(beta))/2 assert Rotation.d(1, -1, 0, beta).doit() == sin(beta)/sqrt(2) assert Rotation.d(1, -1, -1, beta).doit() == (1 + cos(beta))/2 # j = 3/2 assert Rotation.d(S( 3)/2, Rational(3, 2), Rational(3, 2), beta).doit() == (3*cos(beta/2) + cos(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), S( 3)/2, S.Half, beta).doit() == -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), S( 3)/2, Rational(-1, 2), beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), S( 3)/2, Rational(-3, 2), beta).doit() == (-3*sin(beta/2) + sin(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), S( 1)/2, Rational(3, 2), beta).doit() == sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 assert Rotation.d(S( 3)/2, S.Half, S.Half, beta).doit() == (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4 assert Rotation.d(S( 3)/2, S.Half, Rational(-1, 2), beta).doit() == (sin(beta/2) - 3*sin(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), S( 1)/2, Rational(-3, 2), beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), -S( 1)/2, Rational(3, 2), beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), -S( 1)/2, S.Half, beta).doit() == (-sin(beta/2) + 3*sin(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), -S( 1)/2, Rational(-1, 2), beta).doit() == (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), -S( 1)/2, Rational(-3, 2), beta).doit() == -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 assert Rotation.d(S( 3)/2, Rational(-3, 2), Rational(3, 2), beta).doit() == (3*sin(beta/2) - sin(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), -S( 3)/2, S.Half, beta).doit() == sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), -S( 3)/2, Rational(-1, 2), beta).doit() == sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4 assert Rotation.d(Rational(3, 2), -S( 3)/2, Rational(-3, 2), beta).doit() == (3*cos(beta/2) + cos(beta*Rational(3, 2)))/4 # j = 2 assert Rotation.d(2, 2, 2, beta).doit() == (3 + 4*cos(beta) + cos(2*beta))/8 assert Rotation.d(2, 2, 1, beta).doit() == -((cos(beta) + 1)*sin(beta))/2 assert Rotation.d(2, 2, 0, beta).doit() == sqrt(6)*sin(beta)**2/4 assert Rotation.d(2, 2, -1, beta).doit() == (cos(beta) - 1)*sin(beta)/2 assert Rotation.d(2, 2, -2, beta).doit() == (3 - 4*cos(beta) + cos(2*beta))/8 assert Rotation.d(2, 1, 2, beta).doit() == (cos(beta) + 1)*sin(beta)/2 assert Rotation.d(2, 1, 1, beta).doit() == (cos(beta) + cos(2*beta))/2 assert Rotation.d(2, 1, 0, beta).doit() == -sqrt(6)*sin(2*beta)/4 assert Rotation.d(2, 1, -1, beta).doit() == (cos(beta) - cos(2*beta))/2 assert Rotation.d(2, 1, -2, beta).doit() == (cos(beta) - 1)*sin(beta)/2 assert Rotation.d(2, 0, 2, beta).doit() == sqrt(6)*sin(beta)**2/4 assert Rotation.d(2, 0, 1, beta).doit() == sqrt(6)*sin(2*beta)/4 assert Rotation.d(2, 0, 0, beta).doit() == (1 + 3*cos(2*beta))/4 assert Rotation.d(2, 0, -1, beta).doit() == -sqrt(6)*sin(2*beta)/4 assert Rotation.d(2, 0, -2, beta).doit() == sqrt(6)*sin(beta)**2/4 assert Rotation.d(2, -1, 2, beta).doit() == (2*sin(beta) - sin(2*beta))/4 assert Rotation.d(2, -1, 1, beta).doit() == (cos(beta) - cos(2*beta))/2 assert Rotation.d(2, -1, 0, beta).doit() == sqrt(6)*sin(2*beta)/4 assert Rotation.d(2, -1, -1, beta).doit() == (cos(beta) + cos(2*beta))/2 assert Rotation.d(2, -1, -2, beta).doit() == -((cos(beta) + 1)*sin(beta))/2 assert Rotation.d(2, -2, 2, beta).doit() == (3 - 4*cos(beta) + cos(2*beta))/8 assert Rotation.d(2, -2, 1, beta).doit() == (2*sin(beta) - sin(2*beta))/4 assert Rotation.d(2, -2, 0, beta).doit() == sqrt(6)*sin(beta)**2/4 assert Rotation.d(2, -2, -1, beta).doit() == (cos(beta) + 1)*sin(beta)/2 assert Rotation.d(2, -2, -2, beta).doit() == (3 + 4*cos(beta) + cos(2*beta))/8 # Numerical tests # j = 1/2 assert Rotation.d(S.Half, S.Half, S.Half, pi/2).doit() == sqrt(2)/2 assert Rotation.d(S.Half, S.Half, Rational(-1, 2), pi/2).doit() == -sqrt(2)/2 assert Rotation.d(S.Half, Rational(-1, 2), S.Half, pi/2).doit() == sqrt(2)/2 assert Rotation.d(S.Half, Rational(-1, 2), Rational(-1, 2), pi/2).doit() == sqrt(2)/2 # j = 1 assert Rotation.d(1, 1, 1, pi/2).doit() == S.Half assert Rotation.d(1, 1, 0, pi/2).doit() == -sqrt(2)/2 assert Rotation.d(1, 1, -1, pi/2).doit() == S.Half assert Rotation.d(1, 0, 1, pi/2).doit() == sqrt(2)/2 assert Rotation.d(1, 0, 0, pi/2).doit() == 0 assert Rotation.d(1, 0, -1, pi/2).doit() == -sqrt(2)/2 assert Rotation.d(1, -1, 1, pi/2).doit() == S.Half assert Rotation.d(1, -1, 0, pi/2).doit() == sqrt(2)/2 assert Rotation.d(1, -1, -1, pi/2).doit() == S.Half # j = 3/2 assert Rotation.d(Rational(3, 2), Rational(3, 2), Rational(3, 2), pi/2).doit() == sqrt(2)/4 assert Rotation.d(Rational(3, 2), Rational(3, 2), S.Half, pi/2).doit() == -sqrt(6)/4 assert Rotation.d(Rational(3, 2), Rational(3, 2), Rational(-1, 2), pi/2).doit() == sqrt(6)/4 assert Rotation.d(Rational(3, 2), Rational(3, 2), Rational(-3, 2), pi/2).doit() == -sqrt(2)/4 assert Rotation.d(Rational(3, 2), S.Half, Rational(3, 2), pi/2).doit() == sqrt(6)/4 assert Rotation.d(Rational(3, 2), S.Half, S.Half, pi/2).doit() == -sqrt(2)/4 assert Rotation.d(Rational(3, 2), S.Half, Rational(-1, 2), pi/2).doit() == -sqrt(2)/4 assert Rotation.d(Rational(3, 2), S.Half, Rational(-3, 2), pi/2).doit() == sqrt(6)/4 assert Rotation.d(Rational(3, 2), Rational(-1, 2), Rational(3, 2), pi/2).doit() == sqrt(6)/4 assert Rotation.d(Rational(3, 2), Rational(-1, 2), S.Half, pi/2).doit() == sqrt(2)/4 assert Rotation.d(Rational(3, 2), Rational(-1, 2), Rational(-1, 2), pi/2).doit() == -sqrt(2)/4 assert Rotation.d(Rational(3, 2), Rational(-1, 2), Rational(-3, 2), pi/2).doit() == -sqrt(6)/4 assert Rotation.d(Rational(3, 2), Rational(-3, 2), Rational(3, 2), pi/2).doit() == sqrt(2)/4 assert Rotation.d(Rational(3, 2), Rational(-3, 2), S.Half, pi/2).doit() == sqrt(6)/4 assert Rotation.d(Rational(3, 2), Rational(-3, 2), Rational(-1, 2), pi/2).doit() == sqrt(6)/4 assert Rotation.d(Rational(3, 2), Rational(-3, 2), Rational(-3, 2), pi/2).doit() == sqrt(2)/4 # j = 2 assert Rotation.d(2, 2, 2, pi/2).doit() == Rational(1, 4) assert Rotation.d(2, 2, 1, pi/2).doit() == Rational(-1, 2) assert Rotation.d(2, 2, 0, pi/2).doit() == sqrt(6)/4 assert Rotation.d(2, 2, -1, pi/2).doit() == Rational(-1, 2) assert Rotation.d(2, 2, -2, pi/2).doit() == Rational(1, 4) assert Rotation.d(2, 1, 2, pi/2).doit() == S.Half assert Rotation.d(2, 1, 1, pi/2).doit() == Rational(-1, 2) assert Rotation.d(2, 1, 0, pi/2).doit() == 0 assert Rotation.d(2, 1, -1, pi/2).doit() == S.Half assert Rotation.d(2, 1, -2, pi/2).doit() == Rational(-1, 2) assert Rotation.d(2, 0, 2, pi/2).doit() == sqrt(6)/4 assert Rotation.d(2, 0, 1, pi/2).doit() == 0 assert Rotation.d(2, 0, 0, pi/2).doit() == Rational(-1, 2) assert Rotation.d(2, 0, -1, pi/2).doit() == 0 assert Rotation.d(2, 0, -2, pi/2).doit() == sqrt(6)/4 assert Rotation.d(2, -1, 2, pi/2).doit() == S.Half assert Rotation.d(2, -1, 1, pi/2).doit() == S.Half assert Rotation.d(2, -1, 0, pi/2).doit() == 0 assert Rotation.d(2, -1, -1, pi/2).doit() == Rational(-1, 2) assert Rotation.d(2, -1, -2, pi/2).doit() == Rational(-1, 2) assert Rotation.d(2, -2, 2, pi/2).doit() == Rational(1, 4) assert Rotation.d(2, -2, 1, pi/2).doit() == S.Half assert Rotation.d(2, -2, 0, pi/2).doit() == sqrt(6)/4 assert Rotation.d(2, -2, -1, pi/2).doit() == S.Half assert Rotation.d(2, -2, -2, pi/2).doit() == Rational(1, 4) def test_rotation_d(): # Symbolic tests # j = 1/2 assert Rotation.D(S.Half, S.Half, S.Half, alpha, beta, gamma).doit() == \ cos(beta/2)*exp(-I*alpha/2)*exp(-I*gamma/2) assert Rotation.D(S.Half, S.Half, Rational(-1, 2), alpha, beta, gamma).doit() == \ -sin(beta/2)*exp(-I*alpha/2)*exp(I*gamma/2) assert Rotation.D(S.Half, Rational(-1, 2), S.Half, alpha, beta, gamma).doit() == \ sin(beta/2)*exp(I*alpha/2)*exp(-I*gamma/2) assert Rotation.D(S.Half, Rational(-1, 2), Rational(-1, 2), alpha, beta, gamma).doit() == \ cos(beta/2)*exp(I*alpha/2)*exp(I*gamma/2) # j = 1 assert Rotation.D(1, 1, 1, alpha, beta, gamma).doit() == \ (1 + cos(beta))/2*exp(-I*alpha)*exp(-I*gamma) assert Rotation.D(1, 1, 0, alpha, beta, gamma).doit() == -sin( beta)/sqrt(2)*exp(-I*alpha) assert Rotation.D(1, 1, -1, alpha, beta, gamma).doit() == \ (1 - cos(beta))/2*exp(-I*alpha)*exp(I*gamma) assert Rotation.D(1, 0, 1, alpha, beta, gamma).doit() == \ sin(beta)/sqrt(2)*exp(-I*gamma) assert Rotation.D(1, 0, 0, alpha, beta, gamma).doit() == cos(beta) assert Rotation.D(1, 0, -1, alpha, beta, gamma).doit() == \ -sin(beta)/sqrt(2)*exp(I*gamma) assert Rotation.D(1, -1, 1, alpha, beta, gamma).doit() == \ (1 - cos(beta))/2*exp(I*alpha)*exp(-I*gamma) assert Rotation.D(1, -1, 0, alpha, beta, gamma).doit() == \ sin(beta)/sqrt(2)*exp(I*alpha) assert Rotation.D(1, -1, -1, alpha, beta, gamma).doit() == \ (1 + cos(beta))/2*exp(I*alpha)*exp(I*gamma) # j = 3/2 assert Rotation.D(Rational(3, 2), Rational(3, 2), Rational(3, 2), alpha, beta, gamma).doit() == \ (3*cos(beta/2) + cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(I*gamma*Rational(-3, 2)) assert Rotation.D(Rational(3, 2), Rational(3, 2), S.Half, alpha, beta, gamma).doit() == \ -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(-I*gamma/2) assert Rotation.D(Rational(3, 2), Rational(3, 2), Rational(-1, 2), alpha, beta, gamma).doit() == \ sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(I*gamma/2) assert Rotation.D(Rational(3, 2), Rational(3, 2), Rational(-3, 2), alpha, beta, gamma).doit() == \ (-3*sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(-3, 2))*exp(I*gamma*Rational(3, 2)) assert Rotation.D(Rational(3, 2), S.Half, Rational(3, 2), alpha, beta, gamma).doit() == \ sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(I*gamma*Rational(-3, 2)) assert Rotation.D(Rational(3, 2), S.Half, S.Half, alpha, beta, gamma).doit() == \ (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(-I*gamma/2) assert Rotation.D(Rational(3, 2), S.Half, Rational(-1, 2), alpha, beta, gamma).doit() == \ (sin(beta/2) - 3*sin(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(I*gamma/2) assert Rotation.D(Rational(3, 2), S.Half, Rational(-3, 2), alpha, beta, gamma).doit() == \ sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(-I*alpha/2)*exp(I*gamma*Rational(3, 2)) assert Rotation.D(Rational(3, 2), Rational(-1, 2), Rational(3, 2), alpha, beta, gamma).doit() == \ sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(I*gamma*Rational(-3, 2)) assert Rotation.D(Rational(3, 2), Rational(-1, 2), S.Half, alpha, beta, gamma).doit() == \ (-sin(beta/2) + 3*sin(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(-I*gamma/2) assert Rotation.D(Rational(3, 2), Rational(-1, 2), Rational(-1, 2), alpha, beta, gamma).doit() == \ (cos(beta/2) + 3*cos(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(I*gamma/2) assert Rotation.D(Rational(3, 2), Rational(-1, 2), Rational(-3, 2), alpha, beta, gamma).doit() == \ -sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha/2)*exp(I*gamma*Rational(3, 2)) assert Rotation.D(Rational(3, 2), Rational(-3, 2), Rational(3, 2), alpha, beta, gamma).doit() == \ (3*sin(beta/2) - sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(I*gamma*Rational(-3, 2)) assert Rotation.D(Rational(3, 2), Rational(-3, 2), S.Half, alpha, beta, gamma).doit() == \ sqrt(3)*(cos(beta/2) - cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(-I*gamma/2) assert Rotation.D(Rational(3, 2), Rational(-3, 2), Rational(-1, 2), alpha, beta, gamma).doit() == \ sqrt(3)*(sin(beta/2) + sin(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(I*gamma/2) assert Rotation.D(Rational(3, 2), Rational(-3, 2), Rational(-3, 2), alpha, beta, gamma).doit() == \ (3*cos(beta/2) + cos(beta*Rational(3, 2)))/4*exp(I*alpha*Rational(3, 2))*exp(I*gamma*Rational(3, 2)) # j = 2 assert Rotation.D(2, 2, 2, alpha, beta, gamma).doit() == \ (3 + 4*cos(beta) + cos(2*beta))/8*exp(-2*I*alpha)*exp(-2*I*gamma) assert Rotation.D(2, 2, 1, alpha, beta, gamma).doit() == \ -((cos(beta) + 1)*exp(-2*I*alpha)*exp(-I*gamma)*sin(beta))/2 assert Rotation.D(2, 2, 0, alpha, beta, gamma).doit() == \ sqrt(6)*sin(beta)**2/4*exp(-2*I*alpha) assert Rotation.D(2, 2, -1, alpha, beta, gamma).doit() == \ (cos(beta) - 1)*sin(beta)/2*exp(-2*I*alpha)*exp(I*gamma) assert Rotation.D(2, 2, -2, alpha, beta, gamma).doit() == \ (3 - 4*cos(beta) + cos(2*beta))/8*exp(-2*I*alpha)*exp(2*I*gamma) assert Rotation.D(2, 1, 2, alpha, beta, gamma).doit() == \ (cos(beta) + 1)*sin(beta)/2*exp(-I*alpha)*exp(-2*I*gamma) assert Rotation.D(2, 1, 1, alpha, beta, gamma).doit() == \ (cos(beta) + cos(2*beta))/2*exp(-I*alpha)*exp(-I*gamma) assert Rotation.D(2, 1, 0, alpha, beta, gamma).doit() == -sqrt(6)* \ sin(2*beta)/4*exp(-I*alpha) assert Rotation.D(2, 1, -1, alpha, beta, gamma).doit() == \ (cos(beta) - cos(2*beta))/2*exp(-I*alpha)*exp(I*gamma) assert Rotation.D(2, 1, -2, alpha, beta, gamma).doit() == \ (cos(beta) - 1)*sin(beta)/2*exp(-I*alpha)*exp(2*I*gamma) assert Rotation.D(2, 0, 2, alpha, beta, gamma).doit() == \ sqrt(6)*sin(beta)**2/4*exp(-2*I*gamma) assert Rotation.D(2, 0, 1, alpha, beta, gamma).doit() == sqrt(6)* \ sin(2*beta)/4*exp(-I*gamma) assert Rotation.D( 2, 0, 0, alpha, beta, gamma).doit() == (1 + 3*cos(2*beta))/4 assert Rotation.D(2, 0, -1, alpha, beta, gamma).doit() == -sqrt(6)* \ sin(2*beta)/4*exp(I*gamma) assert Rotation.D(2, 0, -2, alpha, beta, gamma).doit() == \ sqrt(6)*sin(beta)**2/4*exp(2*I*gamma) assert Rotation.D(2, -1, 2, alpha, beta, gamma).doit() == \ (2*sin(beta) - sin(2*beta))/4*exp(I*alpha)*exp(-2*I*gamma) assert Rotation.D(2, -1, 1, alpha, beta, gamma).doit() == \ (cos(beta) - cos(2*beta))/2*exp(I*alpha)*exp(-I*gamma) assert Rotation.D(2, -1, 0, alpha, beta, gamma).doit() == sqrt(6)* \ sin(2*beta)/4*exp(I*alpha) assert Rotation.D(2, -1, -1, alpha, beta, gamma).doit() == \ (cos(beta) + cos(2*beta))/2*exp(I*alpha)*exp(I*gamma) assert Rotation.D(2, -1, -2, alpha, beta, gamma).doit() == \ -((cos(beta) + 1)*sin(beta))/2*exp(I*alpha)*exp(2*I*gamma) assert Rotation.D(2, -2, 2, alpha, beta, gamma).doit() == \ (3 - 4*cos(beta) + cos(2*beta))/8*exp(2*I*alpha)*exp(-2*I*gamma) assert Rotation.D(2, -2, 1, alpha, beta, gamma).doit() == \ (2*sin(beta) - sin(2*beta))/4*exp(2*I*alpha)*exp(-I*gamma) assert Rotation.D(2, -2, 0, alpha, beta, gamma).doit() == \ sqrt(6)*sin(beta)**2/4*exp(2*I*alpha) assert Rotation.D(2, -2, -1, alpha, beta, gamma).doit() == \ (cos(beta) + 1)*sin(beta)/2*exp(2*I*alpha)*exp(I*gamma) assert Rotation.D(2, -2, -2, alpha, beta, gamma).doit() == \ (3 + 4*cos(beta) + cos(2*beta))/8*exp(2*I*alpha)*exp(2*I*gamma) # Numerical tests # j = 1/2 assert Rotation.D( S.Half, S.Half, S.Half, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/2 assert Rotation.D( S.Half, S.Half, Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -sqrt(2)/2 assert Rotation.D( S.Half, Rational(-1, 2), S.Half, pi/2, pi/2, pi/2).doit() == sqrt(2)/2 assert Rotation.D( S.Half, Rational(-1, 2), Rational(-1, 2), pi/2, pi/2, pi/2).doit() == I*sqrt(2)/2 # j = 1 assert Rotation.D(1, 1, 1, pi/2, pi/2, pi/2).doit() == Rational(-1, 2) assert Rotation.D(1, 1, 0, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/2 assert Rotation.D(1, 1, -1, pi/2, pi/2, pi/2).doit() == S.Half assert Rotation.D(1, 0, 1, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/2 assert Rotation.D(1, 0, 0, pi/2, pi/2, pi/2).doit() == 0 assert Rotation.D(1, 0, -1, pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/2 assert Rotation.D(1, -1, 1, pi/2, pi/2, pi/2).doit() == S.Half assert Rotation.D(1, -1, 0, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/2 assert Rotation.D(1, -1, -1, pi/2, pi/2, pi/2).doit() == Rational(-1, 2) # j = 3/2 assert Rotation.D( Rational(3, 2), Rational(3, 2), Rational(3, 2), pi/2, pi/2, pi/2).doit() == I*sqrt(2)/4 assert Rotation.D( Rational(3, 2), Rational(3, 2), S.Half, pi/2, pi/2, pi/2).doit() == sqrt(6)/4 assert Rotation.D( Rational(3, 2), Rational(3, 2), Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -I*sqrt(6)/4 assert Rotation.D( Rational(3, 2), Rational(3, 2), Rational(-3, 2), pi/2, pi/2, pi/2).doit() == -sqrt(2)/4 assert Rotation.D( Rational(3, 2), S.Half, Rational(3, 2), pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 assert Rotation.D( Rational(3, 2), S.Half, S.Half, pi/2, pi/2, pi/2).doit() == I*sqrt(2)/4 assert Rotation.D( Rational(3, 2), S.Half, Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -sqrt(2)/4 assert Rotation.D( Rational(3, 2), S.Half, Rational(-3, 2), pi/2, pi/2, pi/2).doit() == I*sqrt(6)/4 assert Rotation.D( Rational(3, 2), Rational(-1, 2), Rational(3, 2), pi/2, pi/2, pi/2).doit() == -I*sqrt(6)/4 assert Rotation.D( Rational(3, 2), Rational(-1, 2), S.Half, pi/2, pi/2, pi/2).doit() == sqrt(2)/4 assert Rotation.D( Rational(3, 2), Rational(-1, 2), Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/4 assert Rotation.D( Rational(3, 2), Rational(-1, 2), Rational(-3, 2), pi/2, pi/2, pi/2).doit() == sqrt(6)/4 assert Rotation.D( Rational(3, 2), Rational(-3, 2), Rational(3, 2), pi/2, pi/2, pi/2).doit() == sqrt(2)/4 assert Rotation.D( Rational(3, 2), Rational(-3, 2), S.Half, pi/2, pi/2, pi/2).doit() == I*sqrt(6)/4 assert Rotation.D( Rational(3, 2), Rational(-3, 2), Rational(-1, 2), pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 assert Rotation.D( Rational(3, 2), Rational(-3, 2), Rational(-3, 2), pi/2, pi/2, pi/2).doit() == -I*sqrt(2)/4 # j = 2 assert Rotation.D(2, 2, 2, pi/2, pi/2, pi/2).doit() == Rational(1, 4) assert Rotation.D(2, 2, 1, pi/2, pi/2, pi/2).doit() == -I/2 assert Rotation.D(2, 2, 0, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 assert Rotation.D(2, 2, -1, pi/2, pi/2, pi/2).doit() == I/2 assert Rotation.D(2, 2, -2, pi/2, pi/2, pi/2).doit() == Rational(1, 4) assert Rotation.D(2, 1, 2, pi/2, pi/2, pi/2).doit() == I/2 assert Rotation.D(2, 1, 1, pi/2, pi/2, pi/2).doit() == S.Half assert Rotation.D(2, 1, 0, pi/2, pi/2, pi/2).doit() == 0 assert Rotation.D(2, 1, -1, pi/2, pi/2, pi/2).doit() == S.Half assert Rotation.D(2, 1, -2, pi/2, pi/2, pi/2).doit() == -I/2 assert Rotation.D(2, 0, 2, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 assert Rotation.D(2, 0, 1, pi/2, pi/2, pi/2).doit() == 0 assert Rotation.D(2, 0, 0, pi/2, pi/2, pi/2).doit() == Rational(-1, 2) assert Rotation.D(2, 0, -1, pi/2, pi/2, pi/2).doit() == 0 assert Rotation.D(2, 0, -2, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 assert Rotation.D(2, -1, 2, pi/2, pi/2, pi/2).doit() == -I/2 assert Rotation.D(2, -1, 1, pi/2, pi/2, pi/2).doit() == S.Half assert Rotation.D(2, -1, 0, pi/2, pi/2, pi/2).doit() == 0 assert Rotation.D(2, -1, -1, pi/2, pi/2, pi/2).doit() == S.Half assert Rotation.D(2, -1, -2, pi/2, pi/2, pi/2).doit() == I/2 assert Rotation.D(2, -2, 2, pi/2, pi/2, pi/2).doit() == Rational(1, 4) assert Rotation.D(2, -2, 1, pi/2, pi/2, pi/2).doit() == I/2 assert Rotation.D(2, -2, 0, pi/2, pi/2, pi/2).doit() == -sqrt(6)/4 assert Rotation.D(2, -2, -1, pi/2, pi/2, pi/2).doit() == -I/2 assert Rotation.D(2, -2, -2, pi/2, pi/2, pi/2).doit() == Rational(1, 4) def test_wignerd(): assert Rotation.D( j, m, mp, alpha, beta, gamma) == WignerD(j, m, mp, alpha, beta, gamma) assert Rotation.d(j, m, mp, beta) == WignerD(j, m, mp, 0, beta, 0) def test_wignerD(): i,j=symbols('i j') assert Rotation.D(1, 1, 1, 0, 0, 0) == WignerD(1, 1, 1, 0, 0, 0) assert Rotation.D(1, 1, 2, 0, 0, 0) == WignerD(1, 1, 2, 0, 0, 0) assert Rotation.D(1, i**2 - j**2, i**2 - j**2, 0, 0, 0) == WignerD(1, i**2 - j**2, i**2 - j**2, 0, 0, 0) assert Rotation.D(1, i, i, 0, 0, 0) == WignerD(1, i, i, 0, 0, 0) assert Rotation.D(1, i, i+1, 0, 0, 0) == WignerD(1, i, i+1, 0, 0, 0) assert Rotation.D(1, 0, 0, 0, 0, 0) == WignerD(1, 0, 0, 0, 0, 0) def test_jplus(): assert Commutator(Jplus, Jminus).doit() == 2*hbar*Jz assert Jplus.matrix_element(1, 1, 1, 1) == 0 assert Jplus.rewrite('xyz') == Jx + I*Jy # Normal operators, normal states # Numerical assert qapply(Jplus*JxKet(1, 1)) == \ -hbar*sqrt(2)*JxKet(1, 0)/2 + hbar*JxKet(1, 1) assert qapply(Jplus*JyKet(1, 1)) == \ hbar*sqrt(2)*JyKet(1, 0)/2 + I*hbar*JyKet(1, 1) assert qapply(Jplus*JzKet(1, 1)) == 0 # Symbolic assert qapply(Jplus*JxKet(j, m)) == \ Sum(hbar * sqrt(-mi**2 - mi + j**2 + j) * WignerD(j, mi, m, 0, pi/2, 0) * Sum(WignerD(j, mi1, mi + 1, 0, pi*Rational(3, 2), 0) * JxKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jplus*JyKet(j, m)) == \ Sum(hbar * sqrt(j**2 + j - mi**2 - mi) * WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2) * Sum(WignerD(j, mi1, mi + 1, pi*Rational(3, 2), pi/2, pi/2) * JyKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jplus*JzKet(j, m)) == \ hbar*sqrt(j**2 + j - m**2 - m)*JzKet(j, m + 1) # Normal operators, coupled states # Numerical assert qapply(Jplus*JxKetCoupled(1, 1, (1, 1))) == -hbar*sqrt(2) * \ JxKetCoupled(1, 0, (1, 1))/2 + hbar*JxKetCoupled(1, 1, (1, 1)) assert qapply(Jplus*JyKetCoupled(1, 1, (1, 1))) == hbar*sqrt(2) * \ JyKetCoupled(1, 0, (1, 1))/2 + I*hbar*JyKetCoupled(1, 1, (1, 1)) assert qapply(Jplus*JzKet(1, 1)) == 0 # Symbolic assert qapply(Jplus*JxKetCoupled(j, m, (j1, j2))) == \ Sum(hbar * sqrt(-mi**2 - mi + j**2 + j) * WignerD(j, mi, m, 0, pi/2, 0) * Sum( WignerD( j, mi1, mi + 1, 0, pi*Rational(3, 2), 0) * JxKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jplus*JyKetCoupled(j, m, (j1, j2))) == \ Sum(hbar * sqrt(j**2 + j - mi**2 - mi) * WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2) * Sum( WignerD(j, mi1, mi + 1, pi*Rational(3, 2), pi/2, pi/2) * JyKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jplus*JzKetCoupled(j, m, (j1, j2))) == \ hbar*sqrt(j**2 + j - m**2 - m)*JzKetCoupled(j, m + 1, (j1, j2)) # Uncoupled operators, uncoupled states # Numerical assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ -hbar*sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 + \ hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(1, Jplus)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) + \ hbar*sqrt(2)*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ hbar*sqrt(2)*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 + \ hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(1, Jplus)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ -hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + \ hbar*sqrt(2)*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 assert qapply( TensorProduct(Jplus, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == 0 assert qapply(TensorProduct(1, Jplus)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ hbar*sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0)) # Symbolic assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(Sum(hbar * sqrt(-mi**2 - mi + j1**2 + j1) * WignerD(j1, mi, m1, 0, pi/2, 0) * Sum(WignerD(j1, mi1, mi + 1, 0, pi*Rational(3, 2), 0) * JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) assert qapply(TensorProduct(1, Jplus)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(JxKet(j1, m1), Sum(hbar * sqrt(-mi**2 - mi + j2**2 + j2) * WignerD(j2, mi, m2, 0, pi/2, 0) * Sum(WignerD(j2, mi1, mi + 1, 0, pi*Rational(3, 2), 0) * JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(Sum(hbar * sqrt(j1**2 + j1 - mi**2 - mi) * WignerD(j1, mi, m1, pi*Rational(3, 2), -pi/2, pi/2) * Sum(WignerD(j1, mi1, mi + 1, pi*Rational(3, 2), pi/2, pi/2) * JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) assert qapply(TensorProduct(1, Jplus)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(JyKet(j1, m1), Sum(hbar * sqrt(j2**2 + j2 - mi**2 - mi) * WignerD(j2, mi, m2, pi*Rational(3, 2), -pi/2, pi/2) * Sum(WignerD(j2, mi1, mi + 1, pi*Rational(3, 2), pi/2, pi/2) * JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jplus, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*sqrt( j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2)) assert qapply(TensorProduct(1, Jplus)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*sqrt( j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1)) def test_jminus(): assert qapply(Jminus*JzKet(1, -1)) == 0 assert Jminus.matrix_element(1, 0, 1, 1) == sqrt(2)*hbar assert Jminus.rewrite('xyz') == Jx - I*Jy # Normal operators, normal states # Numerical assert qapply(Jminus*JxKet(1, 1)) == \ hbar*sqrt(2)*JxKet(1, 0)/2 + hbar*JxKet(1, 1) assert qapply(Jminus*JyKet(1, 1)) == \ hbar*sqrt(2)*JyKet(1, 0)/2 - hbar*I*JyKet(1, 1) assert qapply(Jminus*JzKet(1, 1)) == sqrt(2)*hbar*JzKet(1, 0) # Symbolic assert qapply(Jminus*JxKet(j, m)) == \ Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, 0, pi/2, 0) * Sum(WignerD(j, mi1, mi - 1, 0, pi*Rational(3, 2), 0)*JxKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jminus*JyKet(j, m)) == \ Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2) * Sum(WignerD(j, mi1, mi - 1, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jminus*JzKet(j, m)) == \ hbar*sqrt(j**2 + j - m**2 + m)*JzKet(j, m - 1) # Normal operators, coupled states # Numerical assert qapply(Jminus*JxKetCoupled(1, 1, (1, 1))) == \ hbar*sqrt(2)*JxKetCoupled(1, 0, (1, 1))/2 + \ hbar*JxKetCoupled(1, 1, (1, 1)) assert qapply(Jminus*JyKetCoupled(1, 1, (1, 1))) == \ hbar*sqrt(2)*JyKetCoupled(1, 0, (1, 1))/2 - \ hbar*I*JyKetCoupled(1, 1, (1, 1)) assert qapply(Jminus*JzKetCoupled(1, 1, (1, 1))) == \ sqrt(2)*hbar*JzKetCoupled(1, 0, (1, 1)) # Symbolic assert qapply(Jminus*JxKetCoupled(j, m, (j1, j2))) == \ Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, 0, pi/2, 0) * Sum(WignerD(j, mi1, mi - 1, 0, pi*Rational(3, 2), 0)*JxKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jminus*JyKetCoupled(j, m, (j1, j2))) == \ Sum(hbar*sqrt(j**2 + j - mi**2 + mi)*WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2) * Sum( WignerD(j, mi1, mi - 1, pi*Rational(3, 2), pi/2, pi/2)* JyKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jminus*JzKetCoupled(j, m, (j1, j2))) == \ hbar*sqrt(j**2 + j - m**2 + m)*JzKetCoupled(j, m - 1, (j1, j2)) # Uncoupled operators, uncoupled states # Numerical assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ hbar*sqrt(2)*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 + \ hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(1, Jminus)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) - \ hbar*sqrt(2)*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ hbar*sqrt(2)*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 - \ hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(1, Jminus)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, -1)) + \ hbar*sqrt(2)*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ sqrt(2)*hbar*TensorProduct(JzKet(1, 0), JzKet(1, -1)) assert qapply(TensorProduct( 1, Jminus)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == 0 # Symbolic assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(Sum(hbar*sqrt(j1**2 + j1 - mi**2 + mi)*WignerD(j1, mi, m1, 0, pi/2, 0) * Sum(WignerD(j1, mi1, mi - 1, 0, pi*Rational(3, 2), 0)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) assert qapply(TensorProduct(1, Jminus)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(JxKet(j1, m1), Sum(hbar*sqrt(j2**2 + j2 - mi**2 + mi)*WignerD(j2, mi, m2, 0, pi/2, 0) * Sum(WignerD(j2, mi1, mi - 1, 0, pi*Rational(3, 2), 0)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(Sum(hbar*sqrt(j1**2 + j1 - mi**2 + mi)*WignerD(j1, mi, m1, pi*Rational(3, 2), -pi/2, pi/2) * Sum(WignerD(j1, mi1, mi - 1, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) assert qapply(TensorProduct(1, Jminus)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(JyKet(j1, m1), Sum(hbar*sqrt(j2**2 + j2 - mi**2 + mi)*WignerD(j2, mi, m2, pi*Rational(3, 2), -pi/2, pi/2) * Sum(WignerD(j2, mi1, mi - 1, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jminus, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*sqrt( j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2)) assert qapply(TensorProduct(1, Jminus)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*sqrt( j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1)) def test_j2(): assert Commutator(J2, Jz).doit() == 0 assert J2.matrix_element(1, 1, 1, 1) == 2*hbar**2 # Normal operators, normal states # Numerical assert qapply(J2*JxKet(1, 1)) == 2*hbar**2*JxKet(1, 1) assert qapply(J2*JyKet(1, 1)) == 2*hbar**2*JyKet(1, 1) assert qapply(J2*JzKet(1, 1)) == 2*hbar**2*JzKet(1, 1) # Symbolic assert qapply(J2*JxKet(j, m)) == \ hbar**2*j**2*JxKet(j, m) + hbar**2*j*JxKet(j, m) assert qapply(J2*JyKet(j, m)) == \ hbar**2*j**2*JyKet(j, m) + hbar**2*j*JyKet(j, m) assert qapply(J2*JzKet(j, m)) == \ hbar**2*j**2*JzKet(j, m) + hbar**2*j*JzKet(j, m) # Normal operators, coupled states # Numerical assert qapply(J2*JxKetCoupled(1, 1, (1, 1))) == \ 2*hbar**2*JxKetCoupled(1, 1, (1, 1)) assert qapply(J2*JyKetCoupled(1, 1, (1, 1))) == \ 2*hbar**2*JyKetCoupled(1, 1, (1, 1)) assert qapply(J2*JzKetCoupled(1, 1, (1, 1))) == \ 2*hbar**2*JzKetCoupled(1, 1, (1, 1)) # Symbolic assert qapply(J2*JxKetCoupled(j, m, (j1, j2))) == \ hbar**2*j**2*JxKetCoupled(j, m, (j1, j2)) + \ hbar**2*j*JxKetCoupled(j, m, (j1, j2)) assert qapply(J2*JyKetCoupled(j, m, (j1, j2))) == \ hbar**2*j**2*JyKetCoupled(j, m, (j1, j2)) + \ hbar**2*j*JyKetCoupled(j, m, (j1, j2)) assert qapply(J2*JzKetCoupled(j, m, (j1, j2))) == \ hbar**2*j**2*JzKetCoupled(j, m, (j1, j2)) + \ hbar**2*j*JzKetCoupled(j, m, (j1, j2)) # Uncoupled operators, uncoupled states # Numerical assert qapply(TensorProduct(J2, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ 2*hbar**2*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(1, J2)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ 2*hbar**2*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(J2, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ 2*hbar**2*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(1, J2)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ 2*hbar**2*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(J2, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ 2*hbar**2*TensorProduct(JzKet(1, 1), JzKet(1, -1)) assert qapply(TensorProduct(1, J2)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ 2*hbar**2*TensorProduct(JzKet(1, 1), JzKet(1, -1)) # Symbolic assert qapply(TensorProduct(J2, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ hbar**2*j1**2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ hbar**2*j1*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) assert qapply(TensorProduct(1, J2)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ hbar**2*j2**2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ hbar**2*j2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) assert qapply(TensorProduct(J2, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ hbar**2*j1**2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + \ hbar**2*j1*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) assert qapply(TensorProduct(1, J2)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ hbar**2*j2**2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) + \ hbar**2*j2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) assert qapply(TensorProduct(J2, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar**2*j1**2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + \ hbar**2*j1*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) assert qapply(TensorProduct(1, J2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar**2*j2**2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) + \ hbar**2*j2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) def test_jx(): assert Commutator(Jx, Jz).doit() == -I*hbar*Jy assert Jx.rewrite('plusminus') == (Jminus + Jplus)/2 assert represent(Jx, basis=Jz, j=1) == ( represent(Jplus, basis=Jz, j=1) + represent(Jminus, basis=Jz, j=1))/2 # Normal operators, normal states # Numerical assert qapply(Jx*JxKet(1, 1)) == hbar*JxKet(1, 1) assert qapply(Jx*JyKet(1, 1)) == hbar*JyKet(1, 1) assert qapply(Jx*JzKet(1, 1)) == sqrt(2)*hbar*JzKet(1, 0)/2 # Symbolic assert qapply(Jx*JxKet(j, m)) == hbar*m*JxKet(j, m) assert qapply(Jx*JyKet(j, m)) == \ Sum(hbar*mi*WignerD(j, mi, m, 0, 0, pi/2)*Sum(WignerD(j, mi1, mi, pi*Rational(3, 2), 0, 0)*JyKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jx*JzKet(j, m)) == \ hbar*sqrt(j**2 + j - m**2 - m)*JzKet(j, m + 1)/2 + hbar*sqrt(j**2 + j - m**2 + m)*JzKet(j, m - 1)/2 # Normal operators, coupled states # Numerical assert qapply(Jx*JxKetCoupled(1, 1, (1, 1))) == \ hbar*JxKetCoupled(1, 1, (1, 1)) assert qapply(Jx*JyKetCoupled(1, 1, (1, 1))) == \ hbar*JyKetCoupled(1, 1, (1, 1)) assert qapply(Jx*JzKetCoupled(1, 1, (1, 1))) == \ sqrt(2)*hbar*JzKetCoupled(1, 0, (1, 1))/2 # Symbolic assert qapply(Jx*JxKetCoupled(j, m, (j1, j2))) == \ hbar*m*JxKetCoupled(j, m, (j1, j2)) assert qapply(Jx*JyKetCoupled(j, m, (j1, j2))) == \ Sum(hbar*mi*WignerD(j, mi, m, 0, 0, pi/2)*Sum(WignerD(j, mi1, mi, pi*Rational(3, 2), 0, 0)*JyKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jx*JzKetCoupled(j, m, (j1, j2))) == \ hbar*sqrt(j**2 + j - m**2 - m)*JzKetCoupled(j, m + 1, (j1, j2))/2 + \ hbar*sqrt(j**2 + j - m**2 + m)*JzKetCoupled(j, m - 1, (j1, j2))/2 # Normal operators, uncoupled states # Numerical assert qapply(Jx*TensorProduct(JxKet(1, 1), JxKet(1, 1))) == \ 2*hbar*TensorProduct(JxKet(1, 1), JxKet(1, 1)) assert qapply(Jx*TensorProduct(JyKet(1, 1), JyKet(1, 1))) == \ hbar*TensorProduct(JyKet(1, 1), JyKet(1, 1)) + \ hbar*TensorProduct(JyKet(1, 1), JyKet(1, 1)) assert qapply(Jx*TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ sqrt(2)*hbar*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + \ sqrt(2)*hbar*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 assert qapply(Jx*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == 0 # Symbolic assert qapply(Jx*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ hbar*m1*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) + \ hbar*m2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) assert qapply(Jx*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, 0, pi/2)*Sum(WignerD(j1, mi1, mi, pi*Rational(3, 2), 0, 0)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) + \ TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, 0, pi/2)*Sum(WignerD(j2, mi1, mi, pi*Rational(3, 2), 0, 0)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(Jx*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ hbar*sqrt(j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 + \ hbar*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ hbar*sqrt( j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 # Uncoupled operators, uncoupled states # Numerical assert qapply(TensorProduct(Jx, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(1, Jx)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(Jx, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(1, Jx)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ -hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(Jx, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ hbar*sqrt(2)*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 assert qapply(TensorProduct(1, Jx)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ hbar*sqrt(2)*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 # Symbolic assert qapply(TensorProduct(Jx, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ hbar*m1*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) assert qapply(TensorProduct(1, Jx)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ hbar*m2*TensorProduct(JxKet(j1, m1), JxKet(j2, m2)) assert qapply(TensorProduct(Jx, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, 0, pi/2) * Sum(WignerD(j1, mi1, mi, pi*Rational(3, 2), 0, 0)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) assert qapply(TensorProduct(1, Jx)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, 0, pi/2) * Sum(WignerD(j2, mi1, mi, pi*Rational(3, 2), 0, 0)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jx, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ hbar*sqrt( j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 assert qapply(TensorProduct(1, Jx)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ hbar*sqrt( j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 def test_jy(): assert Commutator(Jy, Jz).doit() == I*hbar*Jx assert Jy.rewrite('plusminus') == (Jplus - Jminus)/(2*I) assert represent(Jy, basis=Jz) == ( represent(Jplus, basis=Jz) - represent(Jminus, basis=Jz))/(2*I) # Normal operators, normal states # Numerical assert qapply(Jy*JxKet(1, 1)) == hbar*JxKet(1, 1) assert qapply(Jy*JyKet(1, 1)) == hbar*JyKet(1, 1) assert qapply(Jy*JzKet(1, 1)) == sqrt(2)*hbar*I*JzKet(1, 0)/2 # Symbolic assert qapply(Jy*JxKet(j, m)) == \ Sum(hbar*mi*WignerD(j, mi, m, pi*Rational(3, 2), 0, 0)*Sum(WignerD( j, mi1, mi, 0, 0, pi/2)*JxKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jy*JyKet(j, m)) == hbar*m*JyKet(j, m) assert qapply(Jy*JzKet(j, m)) == \ -hbar*I*sqrt(j**2 + j - m**2 - m)*JzKet( j, m + 1)/2 + hbar*I*sqrt(j**2 + j - m**2 + m)*JzKet(j, m - 1)/2 # Normal operators, coupled states # Numerical assert qapply(Jy*JxKetCoupled(1, 1, (1, 1))) == \ hbar*JxKetCoupled(1, 1, (1, 1)) assert qapply(Jy*JyKetCoupled(1, 1, (1, 1))) == \ hbar*JyKetCoupled(1, 1, (1, 1)) assert qapply(Jy*JzKetCoupled(1, 1, (1, 1))) == \ sqrt(2)*hbar*I*JzKetCoupled(1, 0, (1, 1))/2 # Symbolic assert qapply(Jy*JxKetCoupled(j, m, (j1, j2))) == \ Sum(hbar*mi*WignerD(j, mi, m, pi*Rational(3, 2), 0, 0)*Sum(WignerD(j, mi1, mi, 0, 0, pi/2)*JxKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jy*JyKetCoupled(j, m, (j1, j2))) == \ hbar*m*JyKetCoupled(j, m, (j1, j2)) assert qapply(Jy*JzKetCoupled(j, m, (j1, j2))) == \ -hbar*I*sqrt(j**2 + j - m**2 - m)*JzKetCoupled(j, m + 1, (j1, j2))/2 + \ hbar*I*sqrt(j**2 + j - m**2 + m)*JzKetCoupled(j, m - 1, (j1, j2))/2 # Normal operators, uncoupled states # Numerical assert qapply(Jy*TensorProduct(JxKet(1, 1), JxKet(1, 1))) == \ hbar*TensorProduct(JxKet(1, 1), JxKet(1, 1)) + \ hbar*TensorProduct(JxKet(1, 1), JxKet(1, 1)) assert qapply(Jy*TensorProduct(JyKet(1, 1), JyKet(1, 1))) == \ 2*hbar*TensorProduct(JyKet(1, 1), JyKet(1, 1)) assert qapply(Jy*TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ sqrt(2)*hbar*I*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 + \ sqrt(2)*hbar*I*TensorProduct(JzKet(1, 0), JzKet(1, 1))/2 assert qapply(Jy*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == 0 # Symbolic assert qapply(Jy*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, pi*Rational(3, 2), 0, 0)*Sum(WignerD(j2, mi1, mi, 0, 0, pi/2)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, pi*Rational(3, 2), 0, 0)*Sum(WignerD(j1, mi1, mi, 0, 0, pi/2)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) assert qapply(Jy*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ hbar*m1*TensorProduct(JyKet(j1, m1), JyKet( j2, m2)) + hbar*m2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) assert qapply(Jy*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ -hbar*I*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ hbar*I*sqrt(j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 + \ -hbar*I*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ hbar*I*sqrt( j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 # Uncoupled operators, uncoupled states # Numerical assert qapply(TensorProduct(Jy, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(1, Jy)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ -hbar*TensorProduct(JxKet(1, 1), JxKet(1, -1)) assert qapply(TensorProduct(Jy, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(1, Jy)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ -hbar*TensorProduct(JyKet(1, 1), JyKet(1, -1)) assert qapply(TensorProduct(Jy, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ hbar*sqrt(2)*I*TensorProduct(JzKet(1, 0), JzKet(1, -1))/2 assert qapply(TensorProduct(1, Jy)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ -hbar*sqrt(2)*I*TensorProduct(JzKet(1, 1), JzKet(1, 0))/2 # Symbolic assert qapply(TensorProduct(Jy, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, pi*Rational(3, 2), 0, 0) * Sum(WignerD(j1, mi1, mi, 0, 0, pi/2)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) assert qapply(TensorProduct(1, Jy)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, pi*Rational(3, 2), 0, 0) * Sum(WignerD(j2, mi1, mi, 0, 0, pi/2)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jy, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ hbar*m1*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) assert qapply(TensorProduct(1, Jy)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ hbar*m2*TensorProduct(JyKet(j1, m1), JyKet(j2, m2)) assert qapply(TensorProduct(Jy, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ -hbar*I*sqrt(j1**2 + j1 - m1**2 - m1)*TensorProduct(JzKet(j1, m1 + 1), JzKet(j2, m2))/2 + \ hbar*I*sqrt( j1**2 + j1 - m1**2 + m1)*TensorProduct(JzKet(j1, m1 - 1), JzKet(j2, m2))/2 assert qapply(TensorProduct(1, Jy)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ -hbar*I*sqrt(j2**2 + j2 - m2**2 - m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 + 1))/2 + \ hbar*I*sqrt( j2**2 + j2 - m2**2 + m2)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2 - 1))/2 def test_jz(): assert Commutator(Jz, Jminus).doit() == -hbar*Jminus # Normal operators, normal states # Numerical assert qapply(Jz*JxKet(1, 1)) == -sqrt(2)*hbar*JxKet(1, 0)/2 assert qapply(Jz*JyKet(1, 1)) == -sqrt(2)*hbar*I*JyKet(1, 0)/2 assert qapply(Jz*JzKet(2, 1)) == hbar*JzKet(2, 1) # Symbolic assert qapply(Jz*JxKet(j, m)) == \ Sum(hbar*mi*WignerD(j, mi, m, 0, pi/2, 0)*Sum(WignerD(j, mi1, mi, 0, pi*Rational(3, 2), 0)*JxKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jz*JyKet(j, m)) == \ Sum(hbar*mi*WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j, mi1, mi, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j, mi1), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jz*JzKet(j, m)) == hbar*m*JzKet(j, m) # Normal operators, coupled states # Numerical assert qapply(Jz*JxKetCoupled(1, 1, (1, 1))) == \ -sqrt(2)*hbar*JxKetCoupled(1, 0, (1, 1))/2 assert qapply(Jz*JyKetCoupled(1, 1, (1, 1))) == \ -sqrt(2)*hbar*I*JyKetCoupled(1, 0, (1, 1))/2 assert qapply(Jz*JzKetCoupled(1, 1, (1, 1))) == \ hbar*JzKetCoupled(1, 1, (1, 1)) # Symbolic assert qapply(Jz*JxKetCoupled(j, m, (j1, j2))) == \ Sum(hbar*mi*WignerD(j, mi, m, 0, pi/2, 0)*Sum(WignerD(j, mi1, mi, 0, pi*Rational(3, 2), 0)*JxKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jz*JyKetCoupled(j, m, (j1, j2))) == \ Sum(hbar*mi*WignerD(j, mi, m, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j, mi1, mi, pi*Rational(3, 2), pi/2, pi/2)*JyKetCoupled(j, mi1, (j1, j2)), (mi1, -j, j)), (mi, -j, j)) assert qapply(Jz*JzKetCoupled(j, m, (j1, j2))) == \ hbar*m*JzKetCoupled(j, m, (j1, j2)) # Normal operators, uncoupled states # Numerical assert qapply(Jz*TensorProduct(JxKet(1, 1), JxKet(1, 1))) == \ -sqrt(2)*hbar*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 - \ sqrt(2)*hbar*TensorProduct(JxKet(1, 0), JxKet(1, 1))/2 assert qapply(Jz*TensorProduct(JyKet(1, 1), JyKet(1, 1))) == \ -sqrt(2)*hbar*I*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 - \ sqrt(2)*hbar*I*TensorProduct(JyKet(1, 0), JyKet(1, 1))/2 assert qapply(Jz*TensorProduct(JzKet(1, 1), JzKet(1, 1))) == \ 2*hbar*TensorProduct(JzKet(1, 1), JzKet(1, 1)) assert qapply(Jz*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == 0 # Symbolic assert qapply(Jz*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, pi/2, 0)*Sum(WignerD(j2, mi1, mi, 0, pi*Rational(3, 2), 0)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, pi/2, 0)*Sum(WignerD(j1, mi1, mi, 0, pi*Rational(3, 2), 0)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) assert qapply(Jz*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j2, mi1, mi, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) + \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j1, mi1, mi, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) assert qapply(Jz*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*m1*TensorProduct(JzKet(j1, m1), JzKet( j2, m2)) + hbar*m2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) # Uncoupled Operators # Numerical assert qapply(TensorProduct(Jz, 1)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ -sqrt(2)*hbar*TensorProduct(JxKet(1, 0), JxKet(1, -1))/2 assert qapply(TensorProduct(1, Jz)*TensorProduct(JxKet(1, 1), JxKet(1, -1))) == \ -sqrt(2)*hbar*TensorProduct(JxKet(1, 1), JxKet(1, 0))/2 assert qapply(TensorProduct(Jz, 1)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ -sqrt(2)*I*hbar*TensorProduct(JyKet(1, 0), JyKet(1, -1))/2 assert qapply(TensorProduct(1, Jz)*TensorProduct(JyKet(1, 1), JyKet(1, -1))) == \ sqrt(2)*I*hbar*TensorProduct(JyKet(1, 1), JyKet(1, 0))/2 assert qapply(TensorProduct(Jz, 1)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ hbar*TensorProduct(JzKet(1, 1), JzKet(1, -1)) assert qapply(TensorProduct(1, Jz)*TensorProduct(JzKet(1, 1), JzKet(1, -1))) == \ -hbar*TensorProduct(JzKet(1, 1), JzKet(1, -1)) # Symbolic assert qapply(TensorProduct(Jz, 1)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, 0, pi/2, 0)*Sum(WignerD(j1, mi1, mi, 0, pi*Rational(3, 2), 0)*JxKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JxKet(j2, m2)) assert qapply(TensorProduct(1, Jz)*TensorProduct(JxKet(j1, m1), JxKet(j2, m2))) == \ TensorProduct(JxKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, 0, pi/2, 0)*Sum(WignerD(j2, mi1, mi, 0, pi*Rational(3, 2), 0)*JxKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jz, 1)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(Sum(hbar*mi*WignerD(j1, mi, m1, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j1, mi1, mi, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j1, mi1), (mi1, -j1, j1)), (mi, -j1, j1)), JyKet(j2, m2)) assert qapply(TensorProduct(1, Jz)*TensorProduct(JyKet(j1, m1), JyKet(j2, m2))) == \ TensorProduct(JyKet(j1, m1), Sum(hbar*mi*WignerD(j2, mi, m2, pi*Rational(3, 2), -pi/2, pi/2)*Sum(WignerD(j2, mi1, mi, pi*Rational(3, 2), pi/2, pi/2)*JyKet(j2, mi1), (mi1, -j2, j2)), (mi, -j2, j2))) assert qapply(TensorProduct(Jz, 1)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*m1*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) assert qapply(TensorProduct(1, Jz)*TensorProduct(JzKet(j1, m1), JzKet(j2, m2))) == \ hbar*m2*TensorProduct(JzKet(j1, m1), JzKet(j2, m2)) def test_rotation(): a, b, g = symbols('a b g') j, m = symbols('j m') #Uncoupled answ = [JxKet(1,-1)/2 - sqrt(2)*JxKet(1,0)/2 + JxKet(1,1)/2 , JyKet(1,-1)/2 - sqrt(2)*JyKet(1,0)/2 + JyKet(1,1)/2 , JzKet(1,-1)/2 - sqrt(2)*JzKet(1,0)/2 + JzKet(1,1)/2] fun = [state(1, 1) for state in (JxKet, JyKet, JzKet)] for state in fun: got = qapply(Rotation(0, pi/2, 0)*state) assert got in answ answ.remove(got) assert not answ arg = Rotation(a, b, g)*fun[0] assert qapply(arg) == (-exp(-I*a)*exp(I*g)*cos(b)*JxKet(1,-1)/2 + exp(-I*a)*exp(I*g)*JxKet(1,-1)/2 - sqrt(2)*exp(-I*a)*sin(b)*JxKet(1,0)/2 + exp(-I*a)*exp(-I*g)*cos(b)*JxKet(1,1)/2 + exp(-I*a)*exp(-I*g)*JxKet(1,1)/2) #dummy effective assert str(qapply(Rotation(a, b, g)*JzKet(j, m), dummy=False)) == str( qapply(Rotation(a, b, g)*JzKet(j, m), dummy=True)).replace('_','') #Coupled ans = [JxKetCoupled(1,-1,(1,1))/2 - sqrt(2)*JxKetCoupled(1,0,(1,1))/2 + JxKetCoupled(1,1,(1,1))/2 , JyKetCoupled(1,-1,(1,1))/2 - sqrt(2)*JyKetCoupled(1,0,(1,1))/2 + JyKetCoupled(1,1,(1,1))/2 , JzKetCoupled(1,-1,(1,1))/2 - sqrt(2)*JzKetCoupled(1,0,(1,1))/2 + JzKetCoupled(1,1,(1,1))/2] fun = [state(1, 1, (1,1)) for state in (JxKetCoupled, JyKetCoupled, JzKetCoupled)] for state in fun: got = qapply(Rotation(0, pi/2, 0)*state) assert got in ans ans.remove(got) assert not ans arg = Rotation(a, b, g)*fun[0] assert qapply(arg) == ( -exp(-I*a)*exp(I*g)*cos(b)*JxKetCoupled(1,-1,(1,1))/2 + exp(-I*a)*exp(I*g)*JxKetCoupled(1,-1,(1,1))/2 - sqrt(2)*exp(-I*a)*sin(b)*JxKetCoupled(1,0,(1,1))/2 + exp(-I*a)*exp(-I*g)*cos(b)*JxKetCoupled(1,1,(1,1))/2 + exp(-I*a)*exp(-I*g)*JxKetCoupled(1,1,(1,1))/2) #dummy effective assert str(qapply(Rotation(a,b,g)*JzKetCoupled(j,m,(j1,j2)), dummy=False)) == str( qapply(Rotation(a,b,g)*JzKetCoupled(j,m,(j1,j2)), dummy=True)).replace('_','') def test_jzket(): j, m = symbols('j m') # j not integer or half integer raises(ValueError, lambda: JzKet(Rational(2, 3), Rational(-1, 3))) raises(ValueError, lambda: JzKet(Rational(2, 3), m)) # j < 0 raises(ValueError, lambda: JzKet(-1, 1)) raises(ValueError, lambda: JzKet(-1, m)) # m not integer or half integer raises(ValueError, lambda: JzKet(j, Rational(-1, 3))) # abs(m) > j raises(ValueError, lambda: JzKet(1, 2)) raises(ValueError, lambda: JzKet(1, -2)) # j-m not integer raises(ValueError, lambda: JzKet(1, S.Half)) def test_jzketcoupled(): j, m = symbols('j m') # j not integer or half integer raises(ValueError, lambda: JzKetCoupled(Rational(2, 3), Rational(-1, 3), (1,))) raises(ValueError, lambda: JzKetCoupled(Rational(2, 3), m, (1,))) # j < 0 raises(ValueError, lambda: JzKetCoupled(-1, 1, (1,))) raises(ValueError, lambda: JzKetCoupled(-1, m, (1,))) # m not integer or half integer raises(ValueError, lambda: JzKetCoupled(j, Rational(-1, 3), (1,))) # abs(m) > j raises(ValueError, lambda: JzKetCoupled(1, 2, (1,))) raises(ValueError, lambda: JzKetCoupled(1, -2, (1,))) # j-m not integer raises(ValueError, lambda: JzKetCoupled(1, S.Half, (1,))) # checks types on coupling scheme raises(TypeError, lambda: JzKetCoupled(1, 1, 1)) raises(TypeError, lambda: JzKetCoupled(1, 1, (1,), 1)) raises(TypeError, lambda: JzKetCoupled(1, 1, (1, 1), (1,))) raises(TypeError, lambda: JzKetCoupled(1, 1, (1, 1, 1), (1, 2, 1), (1, 3, 1))) # checks length of coupling terms raises(ValueError, lambda: JzKetCoupled(1, 1, (1,), ((1, 2, 1),))) raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 2),))) # all jn are integer or half-integer raises(ValueError, lambda: JzKetCoupled(1, 1, (Rational(1, 3), Rational(2, 3)))) # indices in coupling scheme must be integers raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((S.Half, 1, 2),) )) raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, S.Half, 2),) )) # indices out of range raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((0, 2, 1),) )) raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((3, 2, 1),) )) raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 0, 1),) )) raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 3, 1),) )) # all j values in coupling scheme must by integer or half-integer raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1, 1), ((1, 2, S( 4)/3), (1, 3, 1)) )) # each coupling must satisfy |j1-j2| <= j3 <= j1+j2 raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 5))) raises(ValueError, lambda: JzKetCoupled(5, 1, (1, 1))) # final j of coupling must be j of the state raises(ValueError, lambda: JzKetCoupled(1, 1, (1, 1), ((1, 2, 2),) )) sympy-sympy-1.9/sympy/physics/quantum/tests/test_state.py000066400000000000000000000143671412543434000241660ustar00rootroot00000000000000from sympy import (Add, conjugate, diff, I, Integer, Mul, oo, pi, Pow, Rational, sin, sqrt, Symbol, symbols, sympify, S) from sympy.testing.pytest import raises from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.qexpr import QExpr from sympy.physics.quantum.state import ( Ket, Bra, TimeDepKet, TimeDepBra, KetBase, BraBase, StateBase, Wavefunction, OrthogonalKet, OrthogonalBra ) from sympy.physics.quantum.hilbert import HilbertSpace x, y, t = symbols('x,y,t') class CustomKet(Ket): @classmethod def default_args(self): return ("test",) class CustomKetMultipleLabels(Ket): @classmethod def default_args(self): return ("r", "theta", "phi") class CustomTimeDepKet(TimeDepKet): @classmethod def default_args(self): return ("test", "t") class CustomTimeDepKetMultipleLabels(TimeDepKet): @classmethod def default_args(self): return ("r", "theta", "phi", "t") def test_ket(): k = Ket('0') assert isinstance(k, Ket) assert isinstance(k, KetBase) assert isinstance(k, StateBase) assert isinstance(k, QExpr) assert k.label == (Symbol('0'),) assert k.hilbert_space == HilbertSpace() assert k.is_commutative is False # Make sure this doesn't get converted to the number pi. k = Ket('pi') assert k.label == (Symbol('pi'),) k = Ket(x, y) assert k.label == (x, y) assert k.hilbert_space == HilbertSpace() assert k.is_commutative is False assert k.dual_class() == Bra assert k.dual == Bra(x, y) assert k.subs(x, y) == Ket(y, y) k = CustomKet() assert k == CustomKet("test") k = CustomKetMultipleLabels() assert k == CustomKetMultipleLabels("r", "theta", "phi") assert Ket() == Ket('psi') def test_bra(): b = Bra('0') assert isinstance(b, Bra) assert isinstance(b, BraBase) assert isinstance(b, StateBase) assert isinstance(b, QExpr) assert b.label == (Symbol('0'),) assert b.hilbert_space == HilbertSpace() assert b.is_commutative is False # Make sure this doesn't get converted to the number pi. b = Bra('pi') assert b.label == (Symbol('pi'),) b = Bra(x, y) assert b.label == (x, y) assert b.hilbert_space == HilbertSpace() assert b.is_commutative is False assert b.dual_class() == Ket assert b.dual == Ket(x, y) assert b.subs(x, y) == Bra(y, y) assert Bra() == Bra('psi') def test_ops(): k0 = Ket(0) k1 = Ket(1) k = 2*I*k0 - (x/sqrt(2))*k1 assert k == Add(Mul(2, I, k0), Mul(Rational(-1, 2), x, Pow(2, S.Half), k1)) def test_time_dep_ket(): k = TimeDepKet(0, t) assert isinstance(k, TimeDepKet) assert isinstance(k, KetBase) assert isinstance(k, StateBase) assert isinstance(k, QExpr) assert k.label == (Integer(0),) assert k.args == (Integer(0), t) assert k.time == t assert k.dual_class() == TimeDepBra assert k.dual == TimeDepBra(0, t) assert k.subs(t, 2) == TimeDepKet(0, 2) k = TimeDepKet(x, 0.5) assert k.label == (x,) assert k.args == (x, sympify(0.5)) k = CustomTimeDepKet() assert k.label == (Symbol("test"),) assert k.time == Symbol("t") assert k == CustomTimeDepKet("test", "t") k = CustomTimeDepKetMultipleLabels() assert k.label == (Symbol("r"), Symbol("theta"), Symbol("phi")) assert k.time == Symbol("t") assert k == CustomTimeDepKetMultipleLabels("r", "theta", "phi", "t") assert TimeDepKet() == TimeDepKet("psi", "t") def test_time_dep_bra(): b = TimeDepBra(0, t) assert isinstance(b, TimeDepBra) assert isinstance(b, BraBase) assert isinstance(b, StateBase) assert isinstance(b, QExpr) assert b.label == (Integer(0),) assert b.args == (Integer(0), t) assert b.time == t assert b.dual_class() == TimeDepKet assert b.dual == TimeDepKet(0, t) k = TimeDepBra(x, 0.5) assert k.label == (x,) assert k.args == (x, sympify(0.5)) assert TimeDepBra() == TimeDepBra("psi", "t") def test_bra_ket_dagger(): x = symbols('x', complex=True) k = Ket('k') b = Bra('b') assert Dagger(k) == Bra('k') assert Dagger(b) == Ket('b') assert Dagger(k).is_commutative is False k2 = Ket('k2') e = 2*I*k + x*k2 assert Dagger(e) == conjugate(x)*Dagger(k2) - 2*I*Dagger(k) def test_wavefunction(): x, y = symbols('x y', real=True) L = symbols('L', positive=True) n = symbols('n', integer=True, positive=True) f = Wavefunction(x**2, x) p = f.prob() lims = f.limits assert f.is_normalized is False assert f.norm is oo assert f(10) == 100 assert p(10) == 10000 assert lims[x] == (-oo, oo) assert diff(f, x) == Wavefunction(2*x, x) raises(NotImplementedError, lambda: f.normalize()) assert conjugate(f) == Wavefunction(conjugate(f.expr), x) assert conjugate(f) == Dagger(f) g = Wavefunction(x**2*y + y**2*x, (x, 0, 1), (y, 0, 2)) lims_g = g.limits assert lims_g[x] == (0, 1) assert lims_g[y] == (0, 2) assert g.is_normalized is False assert g.norm == sqrt(42)/3 assert g(2, 4) == 0 assert g(1, 1) == 2 assert diff(diff(g, x), y) == Wavefunction(2*x + 2*y, (x, 0, 1), (y, 0, 2)) assert conjugate(g) == Wavefunction(conjugate(g.expr), *g.args[1:]) assert conjugate(g) == Dagger(g) h = Wavefunction(sqrt(5)*x**2, (x, 0, 1)) assert h.is_normalized is True assert h.normalize() == h assert conjugate(h) == Wavefunction(conjugate(h.expr), (x, 0, 1)) assert conjugate(h) == Dagger(h) piab = Wavefunction(sin(n*pi*x/L), (x, 0, L)) assert piab.norm == sqrt(L/2) assert piab(L + 1) == 0 assert piab(0.5) == sin(0.5*n*pi/L) assert piab(0.5, n=1, L=1) == sin(0.5*pi) assert piab.normalize() == \ Wavefunction(sqrt(2)/sqrt(L)*sin(n*pi*x/L), (x, 0, L)) assert conjugate(piab) == Wavefunction(conjugate(piab.expr), (x, 0, L)) assert conjugate(piab) == Dagger(piab) k = Wavefunction(x**2, 'x') assert type(k.variables[0]) == Symbol def test_orthogonal_states(): braket = OrthogonalBra(x) * OrthogonalKet(x) assert braket.doit() == 1 braket = OrthogonalBra(x) * OrthogonalKet(x+1) assert braket.doit() == 0 braket = OrthogonalBra(x) * OrthogonalKet(y) assert braket.doit() == braket sympy-sympy-1.9/sympy/physics/quantum/tests/test_tensorproduct.py000066400000000000000000000102431412543434000257460ustar00rootroot00000000000000from sympy import I, symbols from sympy.core.expr import unchanged from sympy.matrices import Matrix, SparseMatrix from sympy.physics.quantum.commutator import Commutator as Comm from sympy.physics.quantum.tensorproduct import TensorProduct from sympy.physics.quantum.tensorproduct import TensorProduct as TP from sympy.physics.quantum.tensorproduct import tensor_product_simp from sympy.physics.quantum.dagger import Dagger from sympy.physics.quantum.qubit import Qubit, QubitBra from sympy.physics.quantum.operator import OuterProduct from sympy.physics.quantum.density import Density from sympy.core.trace import Tr A, B, C, D = symbols('A,B,C,D', commutative=False) x = symbols('x') mat1 = Matrix([[1, 2*I], [1 + I, 3]]) mat2 = Matrix([[2*I, 3], [4*I, 2]]) def test_sparse_matrices(): spm = SparseMatrix.diag(1, 0) assert unchanged(TensorProduct, spm, spm) def test_tensor_product_dagger(): assert Dagger(TensorProduct(I*A, B)) == \ -I*TensorProduct(Dagger(A), Dagger(B)) assert Dagger(TensorProduct(mat1, mat2)) == \ TensorProduct(Dagger(mat1), Dagger(mat2)) def test_tensor_product_abstract(): assert TP(x*A, 2*B) == x*2*TP(A, B) assert TP(A, B) != TP(B, A) assert TP(A, B).is_commutative is False assert isinstance(TP(A, B), TP) assert TP(A, B).subs(A, C) == TP(C, B) def test_tensor_product_expand(): assert TP(A + B, B + C).expand(tensorproduct=True) == \ TP(A, B) + TP(A, C) + TP(B, B) + TP(B, C) def test_tensor_product_commutator(): assert TP(Comm(A, B), C).doit().expand(tensorproduct=True) == \ TP(A*B, C) - TP(B*A, C) assert Comm(TP(A, B), TP(B, C)).doit() == \ TP(A, B)*TP(B, C) - TP(B, C)*TP(A, B) def test_tensor_product_simp(): assert tensor_product_simp(TP(A, B)*TP(B, C)) == TP(A*B, B*C) # tests for Pow-expressions assert tensor_product_simp(TP(A, B)**x) == TP(A**x, B**x) assert tensor_product_simp(x*TP(A, B)**2) == x*TP(A**2,B**2) assert tensor_product_simp(x*(TP(A, B)**2)*TP(C,D)) == x*TP(A**2*C,B**2*D) assert tensor_product_simp(TP(A,B)-TP(C,D)**x) == TP(A,B)-TP(C**x,D**x) def test_issue_5923(): # most of the issue regarding sympification of args has been handled # and is tested internally by the use of args_cnc through the quantum # module, but the following is a test from the issue that used to raise. assert TensorProduct(1, Qubit('1')*Qubit('1').dual) == \ TensorProduct(1, OuterProduct(Qubit(1), QubitBra(1))) def test_eval_trace(): # This test includes tests with dependencies between TensorProducts #and density operators. Since, the test is more to test the behavior of #TensorProducts it remains here A, B, C, D, E, F = symbols('A B C D E F', commutative=False) # Density with simple tensor products as args t = TensorProduct(A, B) d = Density([t, 1.0]) tr = Tr(d) assert tr.doit() == 1.0*Tr(A*Dagger(A))*Tr(B*Dagger(B)) ## partial trace with simple tensor products as args t = TensorProduct(A, B, C) d = Density([t, 1.0]) tr = Tr(d, [1]) assert tr.doit() == 1.0*A*Dagger(A)*Tr(B*Dagger(B))*C*Dagger(C) tr = Tr(d, [0, 2]) assert tr.doit() == 1.0*Tr(A*Dagger(A))*B*Dagger(B)*Tr(C*Dagger(C)) # Density with multiple Tensorproducts as states t2 = TensorProduct(A, B) t3 = TensorProduct(C, D) d = Density([t2, 0.5], [t3, 0.5]) t = Tr(d) assert t.doit() == (0.5*Tr(A*Dagger(A))*Tr(B*Dagger(B)) + 0.5*Tr(C*Dagger(C))*Tr(D*Dagger(D))) t = Tr(d, [0]) assert t.doit() == (0.5*Tr(A*Dagger(A))*B*Dagger(B) + 0.5*Tr(C*Dagger(C))*D*Dagger(D)) #Density with mixed states d = Density([t2 + t3, 1.0]) t = Tr(d) assert t.doit() == ( 1.0*Tr(A*Dagger(A))*Tr(B*Dagger(B)) + 1.0*Tr(A*Dagger(C))*Tr(B*Dagger(D)) + 1.0*Tr(C*Dagger(A))*Tr(D*Dagger(B)) + 1.0*Tr(C*Dagger(C))*Tr(D*Dagger(D))) t = Tr(d, [1] ) assert t.doit() == ( 1.0*A*Dagger(A)*Tr(B*Dagger(B)) + 1.0*A*Dagger(C)*Tr(B*Dagger(D)) + 1.0*C*Dagger(A)*Tr(D*Dagger(B)) + 1.0*C*Dagger(C)*Tr(D*Dagger(D))) sympy-sympy-1.9/sympy/physics/secondquant.py000066400000000000000000002574501412543434000215010ustar00rootroot00000000000000""" Second quantization operators and states for bosons. This follow the formulation of Fetter and Welecka, "Quantum Theory of Many-Particle Systems." """ from collections import defaultdict from sympy import (Add, Basic, cacheit, Dummy, Expr, Function, I, KroneckerDelta, Mul, Pow, S, sqrt, Symbol, sympify, Tuple, zeros) from sympy.printing.str import StrPrinter from sympy.utilities.iterables import has_dups from sympy.utilities import default_sort_key __all__ = [ 'Dagger', 'KroneckerDelta', 'BosonicOperator', 'AnnihilateBoson', 'CreateBoson', 'AnnihilateFermion', 'CreateFermion', 'FockState', 'FockStateBra', 'FockStateKet', 'FockStateBosonKet', 'FockStateBosonBra', 'FockStateFermionKet', 'FockStateFermionBra', 'BBra', 'BKet', 'FBra', 'FKet', 'F', 'Fd', 'B', 'Bd', 'apply_operators', 'InnerProduct', 'BosonicBasis', 'VarBosonicBasis', 'FixedBosonicBasis', 'Commutator', 'matrix_rep', 'contraction', 'wicks', 'NO', 'evaluate_deltas', 'AntiSymmetricTensor', 'substitute_dummies', 'PermutationOperator', 'simplify_index_permutations', ] class SecondQuantizationError(Exception): pass class AppliesOnlyToSymbolicIndex(SecondQuantizationError): pass class ContractionAppliesOnlyToFermions(SecondQuantizationError): pass class ViolationOfPauliPrinciple(SecondQuantizationError): pass class SubstitutionOfAmbigousOperatorFailed(SecondQuantizationError): pass class WicksTheoremDoesNotApply(SecondQuantizationError): pass class Dagger(Expr): """ Hermitian conjugate of creation/annihilation operators. Examples ======== >>> from sympy import I >>> from sympy.physics.secondquant import Dagger, B, Bd >>> Dagger(2*I) -2*I >>> Dagger(B(0)) CreateBoson(0) >>> Dagger(Bd(0)) AnnihilateBoson(0) """ def __new__(cls, arg): arg = sympify(arg) r = cls.eval(arg) if isinstance(r, Basic): return r obj = Basic.__new__(cls, arg) return obj @classmethod def eval(cls, arg): """ Evaluates the Dagger instance. Examples ======== >>> from sympy import I >>> from sympy.physics.secondquant import Dagger, B, Bd >>> Dagger(2*I) -2*I >>> Dagger(B(0)) CreateBoson(0) >>> Dagger(Bd(0)) AnnihilateBoson(0) The eval() method is called automatically. """ dagger = getattr(arg, '_dagger_', None) if dagger is not None: return dagger() if isinstance(arg, Basic): if arg.is_Add: return Add(*tuple(map(Dagger, arg.args))) if arg.is_Mul: return Mul(*tuple(map(Dagger, reversed(arg.args)))) if arg.is_Number: return arg if arg.is_Pow: return Pow(Dagger(arg.args[0]), arg.args[1]) if arg == I: return -arg else: return None def _dagger_(self): return self.args[0] class TensorSymbol(Expr): is_commutative = True class AntiSymmetricTensor(TensorSymbol): """Stores upper and lower indices in separate Tuple's. Each group of indices is assumed to be antisymmetric. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import AntiSymmetricTensor >>> i, j = symbols('i j', below_fermi=True) >>> a, b = symbols('a b', above_fermi=True) >>> AntiSymmetricTensor('v', (a, i), (b, j)) AntiSymmetricTensor(v, (a, i), (b, j)) >>> AntiSymmetricTensor('v', (i, a), (b, j)) -AntiSymmetricTensor(v, (a, i), (b, j)) As you can see, the indices are automatically sorted to a canonical form. """ def __new__(cls, symbol, upper, lower): try: upper, signu = _sort_anticommuting_fermions( upper, key=cls._sortkey) lower, signl = _sort_anticommuting_fermions( lower, key=cls._sortkey) except ViolationOfPauliPrinciple: return S.Zero symbol = sympify(symbol) upper = Tuple(*upper) lower = Tuple(*lower) if (signu + signl) % 2: return -TensorSymbol.__new__(cls, symbol, upper, lower) else: return TensorSymbol.__new__(cls, symbol, upper, lower) @classmethod def _sortkey(cls, index): """Key for sorting of indices. particle < hole < general FIXME: This is a bottle-neck, can we do it faster? """ h = hash(index) label = str(index) if isinstance(index, Dummy): if index.assumptions0.get('above_fermi'): return (20, label, h) elif index.assumptions0.get('below_fermi'): return (21, label, h) else: return (22, label, h) if index.assumptions0.get('above_fermi'): return (10, label, h) elif index.assumptions0.get('below_fermi'): return (11, label, h) else: return (12, label, h) def _latex(self, printer): return "{%s^{%s}_{%s}}" % ( self.symbol, "".join([ i.name for i in self.args[1]]), "".join([ i.name for i in self.args[2]]) ) @property def symbol(self): """ Returns the symbol of the tensor. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import AntiSymmetricTensor >>> i, j = symbols('i,j', below_fermi=True) >>> a, b = symbols('a,b', above_fermi=True) >>> AntiSymmetricTensor('v', (a, i), (b, j)) AntiSymmetricTensor(v, (a, i), (b, j)) >>> AntiSymmetricTensor('v', (a, i), (b, j)).symbol v """ return self.args[0] @property def upper(self): """ Returns the upper indices. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import AntiSymmetricTensor >>> i, j = symbols('i,j', below_fermi=True) >>> a, b = symbols('a,b', above_fermi=True) >>> AntiSymmetricTensor('v', (a, i), (b, j)) AntiSymmetricTensor(v, (a, i), (b, j)) >>> AntiSymmetricTensor('v', (a, i), (b, j)).upper (a, i) """ return self.args[1] @property def lower(self): """ Returns the lower indices. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import AntiSymmetricTensor >>> i, j = symbols('i,j', below_fermi=True) >>> a, b = symbols('a,b', above_fermi=True) >>> AntiSymmetricTensor('v', (a, i), (b, j)) AntiSymmetricTensor(v, (a, i), (b, j)) >>> AntiSymmetricTensor('v', (a, i), (b, j)).lower (b, j) """ return self.args[2] def __str__(self): return "%s(%s,%s)" % self.args def doit(self, **kw_args): """ Returns self. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import AntiSymmetricTensor >>> i, j = symbols('i,j', below_fermi=True) >>> a, b = symbols('a,b', above_fermi=True) >>> AntiSymmetricTensor('v', (a, i), (b, j)).doit() AntiSymmetricTensor(v, (a, i), (b, j)) """ return self class SqOperator(Expr): """ Base class for Second Quantization operators. """ op_symbol = 'sq' is_commutative = False def __new__(cls, k): obj = Basic.__new__(cls, sympify(k)) return obj @property def state(self): """ Returns the state index related to this operator. Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F, Fd, B, Bd >>> p = Symbol('p') >>> F(p).state p >>> Fd(p).state p >>> B(p).state p >>> Bd(p).state p """ return self.args[0] @property def is_symbolic(self): """ Returns True if the state is a symbol (as opposed to a number). Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> p = Symbol('p') >>> F(p).is_symbolic True >>> F(1).is_symbolic False """ if self.state.is_Integer: return False else: return True def doit(self, **kw_args): """ FIXME: hack to prevent crash further up... """ return self def __repr__(self): return NotImplemented def __str__(self): return "%s(%r)" % (self.op_symbol, self.state) def apply_operator(self, state): """ Applies an operator to itself. """ raise NotImplementedError('implement apply_operator in a subclass') class BosonicOperator(SqOperator): pass class Annihilator(SqOperator): pass class Creator(SqOperator): pass class AnnihilateBoson(BosonicOperator, Annihilator): """ Bosonic annihilation operator. Examples ======== >>> from sympy.physics.secondquant import B >>> from sympy.abc import x >>> B(x) AnnihilateBoson(x) """ op_symbol = 'b' def _dagger_(self): return CreateBoson(self.state) def apply_operator(self, state): """ Apply state to self if self is not symbolic and state is a FockStateKet, else multiply self by state. Examples ======== >>> from sympy.physics.secondquant import B, BKet >>> from sympy.abc import x, y, n >>> B(x).apply_operator(y) y*AnnihilateBoson(x) >>> B(0).apply_operator(BKet((n,))) sqrt(n)*FockStateBosonKet((n - 1,)) """ if not self.is_symbolic and isinstance(state, FockStateKet): element = self.state amp = sqrt(state[element]) return amp*state.down(element) else: return Mul(self, state) def __repr__(self): return "AnnihilateBoson(%s)" % self.state def _latex(self, printer): return "b_{%s}" % self.state.name class CreateBoson(BosonicOperator, Creator): """ Bosonic creation operator. """ op_symbol = 'b+' def _dagger_(self): return AnnihilateBoson(self.state) def apply_operator(self, state): """ Apply state to self if self is not symbolic and state is a FockStateKet, else multiply self by state. Examples ======== >>> from sympy.physics.secondquant import B, Dagger, BKet >>> from sympy.abc import x, y, n >>> Dagger(B(x)).apply_operator(y) y*CreateBoson(x) >>> B(0).apply_operator(BKet((n,))) sqrt(n)*FockStateBosonKet((n - 1,)) """ if not self.is_symbolic and isinstance(state, FockStateKet): element = self.state amp = sqrt(state[element] + 1) return amp*state.up(element) else: return Mul(self, state) def __repr__(self): return "CreateBoson(%s)" % self.state def _latex(self, printer): return "{b^\\dagger_{%s}}" % self.state.name B = AnnihilateBoson Bd = CreateBoson class FermionicOperator(SqOperator): @property def is_restricted(self): """ Is this FermionicOperator restricted with respect to fermi level? Returns ======= 1 : restricted to orbits above fermi 0 : no restriction -1 : restricted to orbits below fermi Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F, Fd >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_restricted 1 >>> Fd(a).is_restricted 1 >>> F(i).is_restricted -1 >>> Fd(i).is_restricted -1 >>> F(p).is_restricted 0 >>> Fd(p).is_restricted 0 """ ass = self.args[0].assumptions0 if ass.get("below_fermi"): return -1 if ass.get("above_fermi"): return 1 return 0 @property def is_above_fermi(self): """ Does the index of this FermionicOperator allow values above fermi? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_above_fermi True >>> F(i).is_above_fermi False >>> F(p).is_above_fermi True Note ==== The same applies to creation operators Fd """ return not self.args[0].assumptions0.get("below_fermi") @property def is_below_fermi(self): """ Does the index of this FermionicOperator allow values below fermi? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_below_fermi False >>> F(i).is_below_fermi True >>> F(p).is_below_fermi True The same applies to creation operators Fd """ return not self.args[0].assumptions0.get("above_fermi") @property def is_only_below_fermi(self): """ Is the index of this FermionicOperator restricted to values below fermi? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_only_below_fermi False >>> F(i).is_only_below_fermi True >>> F(p).is_only_below_fermi False The same applies to creation operators Fd """ return self.is_below_fermi and not self.is_above_fermi @property def is_only_above_fermi(self): """ Is the index of this FermionicOperator restricted to values above fermi? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_only_above_fermi True >>> F(i).is_only_above_fermi False >>> F(p).is_only_above_fermi False The same applies to creation operators Fd """ return self.is_above_fermi and not self.is_below_fermi def _sortkey(self): h = hash(self) label = str(self.args[0]) if self.is_only_q_creator: return 1, label, h if self.is_only_q_annihilator: return 4, label, h if isinstance(self, Annihilator): return 3, label, h if isinstance(self, Creator): return 2, label, h class AnnihilateFermion(FermionicOperator, Annihilator): """ Fermionic annihilation operator. """ op_symbol = 'f' def _dagger_(self): return CreateFermion(self.state) def apply_operator(self, state): """ Apply state to self if self is not symbolic and state is a FockStateKet, else multiply self by state. Examples ======== >>> from sympy.physics.secondquant import B, Dagger, BKet >>> from sympy.abc import x, y, n >>> Dagger(B(x)).apply_operator(y) y*CreateBoson(x) >>> B(0).apply_operator(BKet((n,))) sqrt(n)*FockStateBosonKet((n - 1,)) """ if isinstance(state, FockStateFermionKet): element = self.state return state.down(element) elif isinstance(state, Mul): c_part, nc_part = state.args_cnc() if isinstance(nc_part[0], FockStateFermionKet): element = self.state return Mul(*(c_part + [nc_part[0].down(element)] + nc_part[1:])) else: return Mul(self, state) else: return Mul(self, state) @property def is_q_creator(self): """ Can we create a quasi-particle? (create hole or create particle) If so, would that be above or below the fermi surface? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_q_creator 0 >>> F(i).is_q_creator -1 >>> F(p).is_q_creator -1 """ if self.is_below_fermi: return -1 return 0 @property def is_q_annihilator(self): """ Can we destroy a quasi-particle? (annihilate hole or annihilate particle) If so, would that be above or below the fermi surface? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=1) >>> i = Symbol('i', below_fermi=1) >>> p = Symbol('p') >>> F(a).is_q_annihilator 1 >>> F(i).is_q_annihilator 0 >>> F(p).is_q_annihilator 1 """ if self.is_above_fermi: return 1 return 0 @property def is_only_q_creator(self): """ Always create a quasi-particle? (create hole or create particle) Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_only_q_creator False >>> F(i).is_only_q_creator True >>> F(p).is_only_q_creator False """ return self.is_only_below_fermi @property def is_only_q_annihilator(self): """ Always destroy a quasi-particle? (annihilate hole or annihilate particle) Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import F >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> F(a).is_only_q_annihilator True >>> F(i).is_only_q_annihilator False >>> F(p).is_only_q_annihilator False """ return self.is_only_above_fermi def __repr__(self): return "AnnihilateFermion(%s)" % self.state def _latex(self, printer): return "a_{%s}" % self.state.name class CreateFermion(FermionicOperator, Creator): """ Fermionic creation operator. """ op_symbol = 'f+' def _dagger_(self): return AnnihilateFermion(self.state) def apply_operator(self, state): """ Apply state to self if self is not symbolic and state is a FockStateKet, else multiply self by state. Examples ======== >>> from sympy.physics.secondquant import B, Dagger, BKet >>> from sympy.abc import x, y, n >>> Dagger(B(x)).apply_operator(y) y*CreateBoson(x) >>> B(0).apply_operator(BKet((n,))) sqrt(n)*FockStateBosonKet((n - 1,)) """ if isinstance(state, FockStateFermionKet): element = self.state return state.up(element) elif isinstance(state, Mul): c_part, nc_part = state.args_cnc() if isinstance(nc_part[0], FockStateFermionKet): element = self.state return Mul(*(c_part + [nc_part[0].up(element)] + nc_part[1:])) return Mul(self, state) @property def is_q_creator(self): """ Can we create a quasi-particle? (create hole or create particle) If so, would that be above or below the fermi surface? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import Fd >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> Fd(a).is_q_creator 1 >>> Fd(i).is_q_creator 0 >>> Fd(p).is_q_creator 1 """ if self.is_above_fermi: return 1 return 0 @property def is_q_annihilator(self): """ Can we destroy a quasi-particle? (annihilate hole or annihilate particle) If so, would that be above or below the fermi surface? Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import Fd >>> a = Symbol('a', above_fermi=1) >>> i = Symbol('i', below_fermi=1) >>> p = Symbol('p') >>> Fd(a).is_q_annihilator 0 >>> Fd(i).is_q_annihilator -1 >>> Fd(p).is_q_annihilator -1 """ if self.is_below_fermi: return -1 return 0 @property def is_only_q_creator(self): """ Always create a quasi-particle? (create hole or create particle) Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import Fd >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> Fd(a).is_only_q_creator True >>> Fd(i).is_only_q_creator False >>> Fd(p).is_only_q_creator False """ return self.is_only_above_fermi @property def is_only_q_annihilator(self): """ Always destroy a quasi-particle? (annihilate hole or annihilate particle) Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import Fd >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> Fd(a).is_only_q_annihilator False >>> Fd(i).is_only_q_annihilator True >>> Fd(p).is_only_q_annihilator False """ return self.is_only_below_fermi def __repr__(self): return "CreateFermion(%s)" % self.state def _latex(self, printer): return "{a^\\dagger_{%s}}" % self.state.name Fd = CreateFermion F = AnnihilateFermion class FockState(Expr): """ Many particle Fock state with a sequence of occupation numbers. Anywhere you can have a FockState, you can also have S.Zero. All code must check for this! Base class to represent FockStates. """ is_commutative = False def __new__(cls, occupations): """ occupations is a list with two possible meanings: - For bosons it is a list of occupation numbers. Element i is the number of particles in state i. - For fermions it is a list of occupied orbits. Element 0 is the state that was occupied first, element i is the i'th occupied state. """ occupations = list(map(sympify, occupations)) obj = Basic.__new__(cls, Tuple(*occupations)) return obj def __getitem__(self, i): i = int(i) return self.args[0][i] def __repr__(self): return ("FockState(%r)") % (self.args) def __str__(self): return "%s%r%s" % (self.lbracket, self._labels(), self.rbracket) def _labels(self): return self.args[0] def __len__(self): return len(self.args[0]) class BosonState(FockState): """ Base class for FockStateBoson(Ket/Bra). """ def up(self, i): """ Performs the action of a creation operator. Examples ======== >>> from sympy.physics.secondquant import BBra >>> b = BBra([1, 2]) >>> b FockStateBosonBra((1, 2)) >>> b.up(1) FockStateBosonBra((1, 3)) """ i = int(i) new_occs = list(self.args[0]) new_occs[i] = new_occs[i] + S.One return self.__class__(new_occs) def down(self, i): """ Performs the action of an annihilation operator. Examples ======== >>> from sympy.physics.secondquant import BBra >>> b = BBra([1, 2]) >>> b FockStateBosonBra((1, 2)) >>> b.down(1) FockStateBosonBra((1, 1)) """ i = int(i) new_occs = list(self.args[0]) if new_occs[i] == S.Zero: return S.Zero else: new_occs[i] = new_occs[i] - S.One return self.__class__(new_occs) class FermionState(FockState): """ Base class for FockStateFermion(Ket/Bra). """ fermi_level = 0 def __new__(cls, occupations, fermi_level=0): occupations = list(map(sympify, occupations)) if len(occupations) > 1: try: (occupations, sign) = _sort_anticommuting_fermions( occupations, key=hash) except ViolationOfPauliPrinciple: return S.Zero else: sign = 0 cls.fermi_level = fermi_level if cls._count_holes(occupations) > fermi_level: return S.Zero if sign % 2: return S.NegativeOne*FockState.__new__(cls, occupations) else: return FockState.__new__(cls, occupations) def up(self, i): """ Performs the action of a creation operator. Explanation =========== If below fermi we try to remove a hole, if above fermi we try to create a particle. If general index p we return ``Kronecker(p,i)*self`` where ``i`` is a new symbol with restriction above or below. Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import FKet >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') >>> FKet([]).up(a) FockStateFermionKet((a,)) A creator acting on vacuum below fermi vanishes >>> FKet([]).up(i) 0 """ present = i in self.args[0] if self._only_above_fermi(i): if present: return S.Zero else: return self._add_orbit(i) elif self._only_below_fermi(i): if present: return self._remove_orbit(i) else: return S.Zero else: if present: hole = Dummy("i", below_fermi=True) return KroneckerDelta(i, hole)*self._remove_orbit(i) else: particle = Dummy("a", above_fermi=True) return KroneckerDelta(i, particle)*self._add_orbit(i) def down(self, i): """ Performs the action of an annihilation operator. Explanation =========== If below fermi we try to create a hole, If above fermi we try to remove a particle. If general index p we return ``Kronecker(p,i)*self`` where ``i`` is a new symbol with restriction above or below. Examples ======== >>> from sympy import Symbol >>> from sympy.physics.secondquant import FKet >>> a = Symbol('a', above_fermi=True) >>> i = Symbol('i', below_fermi=True) >>> p = Symbol('p') An annihilator acting on vacuum above fermi vanishes >>> FKet([]).down(a) 0 Also below fermi, it vanishes, unless we specify a fermi level > 0 >>> FKet([]).down(i) 0 >>> FKet([],4).down(i) FockStateFermionKet((i,)) """ present = i in self.args[0] if self._only_above_fermi(i): if present: return self._remove_orbit(i) else: return S.Zero elif self._only_below_fermi(i): if present: return S.Zero else: return self._add_orbit(i) else: if present: hole = Dummy("i", below_fermi=True) return KroneckerDelta(i, hole)*self._add_orbit(i) else: particle = Dummy("a", above_fermi=True) return KroneckerDelta(i, particle)*self._remove_orbit(i) @classmethod def _only_below_fermi(cls, i): """ Tests if given orbit is only below fermi surface. If nothing can be concluded we return a conservative False. """ if i.is_number: return i <= cls.fermi_level if i.assumptions0.get('below_fermi'): return True return False @classmethod def _only_above_fermi(cls, i): """ Tests if given orbit is only above fermi surface. If fermi level has not been set we return True. If nothing can be concluded we return a conservative False. """ if i.is_number: return i > cls.fermi_level if i.assumptions0.get('above_fermi'): return True return not cls.fermi_level def _remove_orbit(self, i): """ Removes particle/fills hole in orbit i. No input tests performed here. """ new_occs = list(self.args[0]) pos = new_occs.index(i) del new_occs[pos] if (pos) % 2: return S.NegativeOne*self.__class__(new_occs, self.fermi_level) else: return self.__class__(new_occs, self.fermi_level) def _add_orbit(self, i): """ Adds particle/creates hole in orbit i. No input tests performed here. """ return self.__class__((i,) + self.args[0], self.fermi_level) @classmethod def _count_holes(cls, list): """ Returns the number of identified hole states in list. """ return len([i for i in list if cls._only_below_fermi(i)]) def _negate_holes(self, list): return tuple([-i if i <= self.fermi_level else i for i in list]) def __repr__(self): if self.fermi_level: return "FockStateKet(%r, fermi_level=%s)" % (self.args[0], self.fermi_level) else: return "FockStateKet(%r)" % (self.args[0],) def _labels(self): return self._negate_holes(self.args[0]) class FockStateKet(FockState): """ Representation of a ket. """ lbracket = '|' rbracket = '>' class FockStateBra(FockState): """ Representation of a bra. """ lbracket = '<' rbracket = '|' def __mul__(self, other): if isinstance(other, FockStateKet): return InnerProduct(self, other) else: return Expr.__mul__(self, other) class FockStateBosonKet(BosonState, FockStateKet): """ Many particle Fock state with a sequence of occupation numbers. Occupation numbers can be any integer >= 0. Examples ======== >>> from sympy.physics.secondquant import BKet >>> BKet([1, 2]) FockStateBosonKet((1, 2)) """ def _dagger_(self): return FockStateBosonBra(*self.args) class FockStateBosonBra(BosonState, FockStateBra): """ Describes a collection of BosonBra particles. Examples ======== >>> from sympy.physics.secondquant import BBra >>> BBra([1, 2]) FockStateBosonBra((1, 2)) """ def _dagger_(self): return FockStateBosonKet(*self.args) class FockStateFermionKet(FermionState, FockStateKet): """ Many-particle Fock state with a sequence of occupied orbits. Explanation =========== Each state can only have one particle, so we choose to store a list of occupied orbits rather than a tuple with occupation numbers (zeros and ones). states below fermi level are holes, and are represented by negative labels in the occupation list. For symbolic state labels, the fermi_level caps the number of allowed hole- states. Examples ======== >>> from sympy.physics.secondquant import FKet >>> FKet([1, 2]) FockStateFermionKet((1, 2)) """ def _dagger_(self): return FockStateFermionBra(*self.args) class FockStateFermionBra(FermionState, FockStateBra): """ See Also ======== FockStateFermionKet Examples ======== >>> from sympy.physics.secondquant import FBra >>> FBra([1, 2]) FockStateFermionBra((1, 2)) """ def _dagger_(self): return FockStateFermionKet(*self.args) BBra = FockStateBosonBra BKet = FockStateBosonKet FBra = FockStateFermionBra FKet = FockStateFermionKet def _apply_Mul(m): """ Take a Mul instance with operators and apply them to states. Explanation =========== This method applies all operators with integer state labels to the actual states. For symbolic state labels, nothing is done. When inner products of FockStates are encountered (like ), they are converted to instances of InnerProduct. This does not currently work on double inner products like, . If the argument is not a Mul, it is simply returned as is. """ if not isinstance(m, Mul): return m c_part, nc_part = m.args_cnc() n_nc = len(nc_part) if n_nc == 0 or n_nc == 1: return m else: last = nc_part[-1] next_to_last = nc_part[-2] if isinstance(last, FockStateKet): if isinstance(next_to_last, SqOperator): if next_to_last.is_symbolic: return m else: result = next_to_last.apply_operator(last) if result == 0: return S.Zero else: return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) elif isinstance(next_to_last, Pow): if isinstance(next_to_last.base, SqOperator) and \ next_to_last.exp.is_Integer: if next_to_last.base.is_symbolic: return m else: result = last for i in range(next_to_last.exp): result = next_to_last.base.apply_operator(result) if result == 0: break if result == 0: return S.Zero else: return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) else: return m elif isinstance(next_to_last, FockStateBra): result = InnerProduct(next_to_last, last) if result == 0: return S.Zero else: return _apply_Mul(Mul(*(c_part + nc_part[:-2] + [result]))) else: return m else: return m def apply_operators(e): """ Take a sympy expression with operators and states and apply the operators. Examples ======== >>> from sympy.physics.secondquant import apply_operators >>> from sympy import sympify >>> apply_operators(sympify(3)+4) 7 """ e = e.expand() muls = e.atoms(Mul) subs_list = [(m, _apply_Mul(m)) for m in iter(muls)] return e.subs(subs_list) class InnerProduct(Basic): """ An unevaluated inner product between a bra and ket. Explanation =========== Currently this class just reduces things to a product of Kronecker Deltas. In the future, we could introduce abstract states like ``|a>`` and ``|b>``, and leave the inner product unevaluated as ````. """ is_commutative = True def __new__(cls, bra, ket): if not isinstance(bra, FockStateBra): raise TypeError("must be a bra") if not isinstance(ket, FockStateKet): raise TypeError("must be a key") return cls.eval(bra, ket) @classmethod def eval(cls, bra, ket): result = S.One for i, j in zip(bra.args[0], ket.args[0]): result *= KroneckerDelta(i, j) if result == 0: break return result @property def bra(self): """Returns the bra part of the state""" return self.args[0] @property def ket(self): """Returns the ket part of the state""" return self.args[1] def __repr__(self): sbra = repr(self.bra) sket = repr(self.ket) return "%s|%s" % (sbra[:-1], sket[1:]) def __str__(self): return self.__repr__() def matrix_rep(op, basis): """ Find the representation of an operator in a basis. Examples ======== >>> from sympy.physics.secondquant import VarBosonicBasis, B, matrix_rep >>> b = VarBosonicBasis(5) >>> o = B(0) >>> matrix_rep(o, b) Matrix([ [0, 1, 0, 0, 0], [0, 0, sqrt(2), 0, 0], [0, 0, 0, sqrt(3), 0], [0, 0, 0, 0, 2], [0, 0, 0, 0, 0]]) """ a = zeros(len(basis)) for i in range(len(basis)): for j in range(len(basis)): a[i, j] = apply_operators(Dagger(basis[i])*op*basis[j]) return a class BosonicBasis: """ Base class for a basis set of bosonic Fock states. """ pass class VarBosonicBasis: """ A single state, variable particle number basis set. Examples ======== >>> from sympy.physics.secondquant import VarBosonicBasis >>> b = VarBosonicBasis(5) >>> b [FockState((0,)), FockState((1,)), FockState((2,)), FockState((3,)), FockState((4,))] """ def __init__(self, n_max): self.n_max = n_max self._build_states() def _build_states(self): self.basis = [] for i in range(self.n_max): self.basis.append(FockStateBosonKet([i])) self.n_basis = len(self.basis) def index(self, state): """ Returns the index of state in basis. Examples ======== >>> from sympy.physics.secondquant import VarBosonicBasis >>> b = VarBosonicBasis(3) >>> state = b.state(1) >>> b [FockState((0,)), FockState((1,)), FockState((2,))] >>> state FockStateBosonKet((1,)) >>> b.index(state) 1 """ return self.basis.index(state) def state(self, i): """ The state of a single basis. Examples ======== >>> from sympy.physics.secondquant import VarBosonicBasis >>> b = VarBosonicBasis(5) >>> b.state(3) FockStateBosonKet((3,)) """ return self.basis[i] def __getitem__(self, i): return self.state(i) def __len__(self): return len(self.basis) def __repr__(self): return repr(self.basis) class FixedBosonicBasis(BosonicBasis): """ Fixed particle number basis set. Examples ======== >>> from sympy.physics.secondquant import FixedBosonicBasis >>> b = FixedBosonicBasis(2, 2) >>> state = b.state(1) >>> b [FockState((2, 0)), FockState((1, 1)), FockState((0, 2))] >>> state FockStateBosonKet((1, 1)) >>> b.index(state) 1 """ def __init__(self, n_particles, n_levels): self.n_particles = n_particles self.n_levels = n_levels self._build_particle_locations() self._build_states() def _build_particle_locations(self): tup = ["i%i" % i for i in range(self.n_particles)] first_loop = "for i0 in range(%i)" % self.n_levels other_loops = '' for cur, prev in zip(tup[1:], tup): temp = "for %s in range(%s + 1) " % (cur, prev) other_loops = other_loops + temp tup_string = "(%s)" % ", ".join(tup) list_comp = "[%s %s %s]" % (tup_string, first_loop, other_loops) result = eval(list_comp) if self.n_particles == 1: result = [(item,) for item in result] self.particle_locations = result def _build_states(self): self.basis = [] for tuple_of_indices in self.particle_locations: occ_numbers = self.n_levels*[0] for level in tuple_of_indices: occ_numbers[level] += 1 self.basis.append(FockStateBosonKet(occ_numbers)) self.n_basis = len(self.basis) def index(self, state): """Returns the index of state in basis. Examples ======== >>> from sympy.physics.secondquant import FixedBosonicBasis >>> b = FixedBosonicBasis(2, 3) >>> b.index(b.state(3)) 3 """ return self.basis.index(state) def state(self, i): """Returns the state that lies at index i of the basis Examples ======== >>> from sympy.physics.secondquant import FixedBosonicBasis >>> b = FixedBosonicBasis(2, 3) >>> b.state(3) FockStateBosonKet((1, 0, 1)) """ return self.basis[i] def __getitem__(self, i): return self.state(i) def __len__(self): return len(self.basis) def __repr__(self): return repr(self.basis) class Commutator(Function): """ The Commutator: [A, B] = A*B - B*A The arguments are ordered according to .__cmp__() Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import Commutator >>> A, B = symbols('A,B', commutative=False) >>> Commutator(B, A) -Commutator(A, B) Evaluate the commutator with .doit() >>> comm = Commutator(A,B); comm Commutator(A, B) >>> comm.doit() A*B - B*A For two second quantization operators the commutator is evaluated immediately: >>> from sympy.physics.secondquant import Fd, F >>> a = symbols('a', above_fermi=True) >>> i = symbols('i', below_fermi=True) >>> p,q = symbols('p,q') >>> Commutator(Fd(a),Fd(i)) 2*NO(CreateFermion(a)*CreateFermion(i)) But for more complicated expressions, the evaluation is triggered by a call to .doit() >>> comm = Commutator(Fd(p)*Fd(q),F(i)); comm Commutator(CreateFermion(p)*CreateFermion(q), AnnihilateFermion(i)) >>> comm.doit(wicks=True) -KroneckerDelta(i, p)*CreateFermion(q) + KroneckerDelta(i, q)*CreateFermion(p) """ is_commutative = False @classmethod def eval(cls, a, b): """ The Commutator [A,B] is on canonical form if A < B. Examples ======== >>> from sympy.physics.secondquant import Commutator, F, Fd >>> from sympy.abc import x >>> c1 = Commutator(F(x), Fd(x)) >>> c2 = Commutator(Fd(x), F(x)) >>> Commutator.eval(c1, c2) 0 """ if not (a and b): return S.Zero if a == b: return S.Zero if a.is_commutative or b.is_commutative: return S.Zero # # [A+B,C] -> [A,C] + [B,C] # a = a.expand() if isinstance(a, Add): return Add(*[cls(term, b) for term in a.args]) b = b.expand() if isinstance(b, Add): return Add(*[cls(a, term) for term in b.args]) # # [xA,yB] -> xy*[A,B] # ca, nca = a.args_cnc() cb, ncb = b.args_cnc() c_part = list(ca) + list(cb) if c_part: return Mul(Mul(*c_part), cls(Mul._from_args(nca), Mul._from_args(ncb))) # # single second quantization operators # if isinstance(a, BosonicOperator) and isinstance(b, BosonicOperator): if isinstance(b, CreateBoson) and isinstance(a, AnnihilateBoson): return KroneckerDelta(a.state, b.state) if isinstance(a, CreateBoson) and isinstance(b, AnnihilateBoson): return S.NegativeOne*KroneckerDelta(a.state, b.state) else: return S.Zero if isinstance(a, FermionicOperator) and isinstance(b, FermionicOperator): return wicks(a*b) - wicks(b*a) # # Canonical ordering of arguments # if a.sort_key() > b.sort_key(): return S.NegativeOne*cls(b, a) def doit(self, **hints): """ Enables the computation of complex expressions. Examples ======== >>> from sympy.physics.secondquant import Commutator, F, Fd >>> from sympy import symbols >>> i, j = symbols('i,j', below_fermi=True) >>> a, b = symbols('a,b', above_fermi=True) >>> c = Commutator(Fd(a)*F(i),Fd(b)*F(j)) >>> c.doit(wicks=True) 0 """ a = self.args[0] b = self.args[1] if hints.get("wicks"): a = a.doit(**hints) b = b.doit(**hints) try: return wicks(a*b) - wicks(b*a) except ContractionAppliesOnlyToFermions: pass except WicksTheoremDoesNotApply: pass return (a*b - b*a).doit(**hints) def __repr__(self): return "Commutator(%s,%s)" % (self.args[0], self.args[1]) def __str__(self): return "[%s,%s]" % (self.args[0], self.args[1]) def _latex(self, printer): return "\\left[%s,%s\\right]" % tuple([ printer._print(arg) for arg in self.args]) class NO(Expr): """ This Object is used to represent normal ordering brackets. i.e. {abcd} sometimes written :abcd: Explanation =========== Applying the function NO(arg) to an argument means that all operators in the argument will be assumed to anticommute, and have vanishing contractions. This allows an immediate reordering to canonical form upon object creation. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import NO, F, Fd >>> p,q = symbols('p,q') >>> NO(Fd(p)*F(q)) NO(CreateFermion(p)*AnnihilateFermion(q)) >>> NO(F(q)*Fd(p)) -NO(CreateFermion(p)*AnnihilateFermion(q)) Note ==== If you want to generate a normal ordered equivalent of an expression, you should use the function wicks(). This class only indicates that all operators inside the brackets anticommute, and have vanishing contractions. Nothing more, nothing less. """ is_commutative = False def __new__(cls, arg): """ Use anticommutation to get canonical form of operators. Explanation =========== Employ associativity of normal ordered product: {ab{cd}} = {abcd} but note that {ab}{cd} /= {abcd}. We also employ distributivity: {ab + cd} = {ab} + {cd}. Canonical form also implies expand() {ab(c+d)} = {abc} + {abd}. """ # {ab + cd} = {ab} + {cd} arg = sympify(arg) arg = arg.expand() if arg.is_Add: return Add(*[ cls(term) for term in arg.args]) if arg.is_Mul: # take coefficient outside of normal ordering brackets c_part, seq = arg.args_cnc() if c_part: coeff = Mul(*c_part) if not seq: return coeff else: coeff = S.One # {ab{cd}} = {abcd} newseq = [] foundit = False for fac in seq: if isinstance(fac, NO): newseq.extend(fac.args) foundit = True else: newseq.append(fac) if foundit: return coeff*cls(Mul(*newseq)) # We assume that the user don't mix B and F operators if isinstance(seq[0], BosonicOperator): raise NotImplementedError try: newseq, sign = _sort_anticommuting_fermions(seq) except ViolationOfPauliPrinciple: return S.Zero if sign % 2: return (S.NegativeOne*coeff)*cls(Mul(*newseq)) elif sign: return coeff*cls(Mul(*newseq)) else: pass # since sign==0, no permutations was necessary # if we couldn't do anything with Mul object, we just # mark it as normal ordered if coeff != S.One: return coeff*cls(Mul(*newseq)) return Expr.__new__(cls, Mul(*newseq)) if isinstance(arg, NO): return arg # if object was not Mul or Add, normal ordering does not apply return arg @property def has_q_creators(self): """ Return 0 if the leftmost argument of the first argument is a not a q_creator, else 1 if it is above fermi or -1 if it is below fermi. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import NO, F, Fd >>> a = symbols('a', above_fermi=True) >>> i = symbols('i', below_fermi=True) >>> NO(Fd(a)*Fd(i)).has_q_creators 1 >>> NO(F(i)*F(a)).has_q_creators -1 >>> NO(Fd(i)*F(a)).has_q_creators #doctest: +SKIP 0 """ return self.args[0].args[0].is_q_creator @property def has_q_annihilators(self): """ Return 0 if the rightmost argument of the first argument is a not a q_annihilator, else 1 if it is above fermi or -1 if it is below fermi. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import NO, F, Fd >>> a = symbols('a', above_fermi=True) >>> i = symbols('i', below_fermi=True) >>> NO(Fd(a)*Fd(i)).has_q_annihilators -1 >>> NO(F(i)*F(a)).has_q_annihilators 1 >>> NO(Fd(a)*F(i)).has_q_annihilators 0 """ return self.args[0].args[-1].is_q_annihilator def doit(self, **kw_args): """ Either removes the brackets or enables complex computations in its arguments. Examples ======== >>> from sympy.physics.secondquant import NO, Fd, F >>> from textwrap import fill >>> from sympy import symbols, Dummy >>> p,q = symbols('p,q', cls=Dummy) >>> print(fill(str(NO(Fd(p)*F(q)).doit()))) KroneckerDelta(_a, _p)*KroneckerDelta(_a, _q)*CreateFermion(_a)*AnnihilateFermion(_a) + KroneckerDelta(_a, _p)*KroneckerDelta(_i, _q)*CreateFermion(_a)*AnnihilateFermion(_i) - KroneckerDelta(_a, _q)*KroneckerDelta(_i, _p)*AnnihilateFermion(_a)*CreateFermion(_i) - KroneckerDelta(_i, _p)*KroneckerDelta(_i, _q)*AnnihilateFermion(_i)*CreateFermion(_i) """ if kw_args.get("remove_brackets", True): return self._remove_brackets() else: return self.__new__(type(self), self.args[0].doit(**kw_args)) def _remove_brackets(self): """ Returns the sorted string without normal order brackets. The returned string have the property that no nonzero contractions exist. """ # check if any creator is also an annihilator subslist = [] for i in self.iter_q_creators(): if self[i].is_q_annihilator: assume = self[i].state.assumptions0 # only operators with a dummy index can be split in two terms if isinstance(self[i].state, Dummy): # create indices with fermi restriction assume.pop("above_fermi", None) assume["below_fermi"] = True below = Dummy('i', **assume) assume.pop("below_fermi", None) assume["above_fermi"] = True above = Dummy('a', **assume) cls = type(self[i]) split = ( self[i].__new__(cls, below) * KroneckerDelta(below, self[i].state) + self[i].__new__(cls, above) * KroneckerDelta(above, self[i].state) ) subslist.append((self[i], split)) else: raise SubstitutionOfAmbigousOperatorFailed(self[i]) if subslist: result = NO(self.subs(subslist)) if isinstance(result, Add): return Add(*[term.doit() for term in result.args]) else: return self.args[0] def _expand_operators(self): """ Returns a sum of NO objects that contain no ambiguous q-operators. Explanation =========== If an index q has range both above and below fermi, the operator F(q) is ambiguous in the sense that it can be both a q-creator and a q-annihilator. If q is dummy, it is assumed to be a summation variable and this method rewrites it into a sum of NO terms with unambiguous operators: {Fd(p)*F(q)} = {Fd(a)*F(b)} + {Fd(a)*F(i)} + {Fd(j)*F(b)} -{F(i)*Fd(j)} where a,b are above and i,j are below fermi level. """ return NO(self._remove_brackets) def __getitem__(self, i): if isinstance(i, slice): indices = i.indices(len(self)) return [self.args[0].args[i] for i in range(*indices)] else: return self.args[0].args[i] def __len__(self): return len(self.args[0].args) def iter_q_annihilators(self): """ Iterates over the annihilation operators. Examples ======== >>> from sympy import symbols >>> i, j = symbols('i j', below_fermi=True) >>> a, b = symbols('a b', above_fermi=True) >>> from sympy.physics.secondquant import NO, F, Fd >>> no = NO(Fd(a)*F(i)*F(b)*Fd(j)) >>> no.iter_q_creators() >>> list(no.iter_q_creators()) [0, 1] >>> list(no.iter_q_annihilators()) [3, 2] """ ops = self.args[0].args iter = range(len(ops) - 1, -1, -1) for i in iter: if ops[i].is_q_annihilator: yield i else: break def iter_q_creators(self): """ Iterates over the creation operators. Examples ======== >>> from sympy import symbols >>> i, j = symbols('i j', below_fermi=True) >>> a, b = symbols('a b', above_fermi=True) >>> from sympy.physics.secondquant import NO, F, Fd >>> no = NO(Fd(a)*F(i)*F(b)*Fd(j)) >>> no.iter_q_creators() >>> list(no.iter_q_creators()) [0, 1] >>> list(no.iter_q_annihilators()) [3, 2] """ ops = self.args[0].args iter = range(0, len(ops)) for i in iter: if ops[i].is_q_creator: yield i else: break def get_subNO(self, i): """ Returns a NO() without FermionicOperator at index i. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import F, NO >>> p, q, r = symbols('p,q,r') >>> NO(F(p)*F(q)*F(r)).get_subNO(1) NO(AnnihilateFermion(p)*AnnihilateFermion(r)) """ arg0 = self.args[0] # it's a Mul by definition of how it's created mul = arg0._new_rawargs(*(arg0.args[:i] + arg0.args[i + 1:])) return NO(mul) def _latex(self, printer): return "\\left\\{%s\\right\\}" % printer._print(self.args[0]) def __repr__(self): return "NO(%s)" % self.args[0] def __str__(self): return ":%s:" % self.args[0] def contraction(a, b): """ Calculates contraction of Fermionic operators a and b. Examples ======== >>> from sympy import symbols >>> from sympy.physics.secondquant import F, Fd, contraction >>> p, q = symbols('p,q') >>> a, b = symbols('a,b', above_fermi=True) >>> i, j = symbols('i,j', below_fermi=True) A contraction is non-zero only if a quasi-creator is to the right of a quasi-annihilator: >>> contraction(F(a),Fd(b)) KroneckerDelta(a, b) >>> contraction(Fd(i),F(j)) KroneckerDelta(i, j) For general indices a non-zero result restricts the indices to below/above the fermi surface: >>> contraction(Fd(p),F(q)) KroneckerDelta(_i, q)*KroneckerDelta(p, q) >>> contraction(F(p),Fd(q)) KroneckerDelta(_a, q)*KroneckerDelta(p, q) Two creators or two annihilators always vanishes: >>> contraction(F(p),F(q)) 0 >>> contraction(Fd(p),Fd(q)) 0 """ if isinstance(b, FermionicOperator) and isinstance(a, FermionicOperator): if isinstance(a, AnnihilateFermion) and isinstance(b, CreateFermion): if b.state.assumptions0.get("below_fermi"): return S.Zero if a.state.assumptions0.get("below_fermi"): return S.Zero if b.state.assumptions0.get("above_fermi"): return KroneckerDelta(a.state, b.state) if a.state.assumptions0.get("above_fermi"): return KroneckerDelta(a.state, b.state) return (KroneckerDelta(a.state, b.state)* KroneckerDelta(b.state, Dummy('a', above_fermi=True))) if isinstance(b, AnnihilateFermion) and isinstance(a, CreateFermion): if b.state.assumptions0.get("above_fermi"): return S.Zero if a.state.assumptions0.get("above_fermi"): return S.Zero if b.state.assumptions0.get("below_fermi"): return KroneckerDelta(a.state, b.state) if a.state.assumptions0.get("below_fermi"): return KroneckerDelta(a.state, b.state) return (KroneckerDelta(a.state, b.state)* KroneckerDelta(b.state, Dummy('i', below_fermi=True))) # vanish if 2xAnnihilator or 2xCreator return S.Zero else: #not fermion operators t = ( isinstance(i, FermionicOperator) for i in (a, b) ) raise ContractionAppliesOnlyToFermions(*t) def _sqkey(sq_operator): """Generates key for canonical sorting of SQ operators.""" return sq_operator._sortkey() def _sort_anticommuting_fermions(string1, key=_sqkey): """Sort fermionic operators to canonical order, assuming all pairs anticommute. Explanation =========== Uses a bidirectional bubble sort. Items in string1 are not referenced so in principle they may be any comparable objects. The sorting depends on the operators '>' and '=='. If the Pauli principle is violated, an exception is raised. Returns ======= tuple (sorted_str, sign) sorted_str: list containing the sorted operators sign: int telling how many times the sign should be changed (if sign==0 the string was already sorted) """ verified = False sign = 0 rng = list(range(len(string1) - 1)) rev = list(range(len(string1) - 3, -1, -1)) keys = list(map(key, string1)) key_val = dict(list(zip(keys, string1))) while not verified: verified = True for i in rng: left = keys[i] right = keys[i + 1] if left == right: raise ViolationOfPauliPrinciple([left, right]) if left > right: verified = False keys[i:i + 2] = [right, left] sign = sign + 1 if verified: break for i in rev: left = keys[i] right = keys[i + 1] if left == right: raise ViolationOfPauliPrinciple([left, right]) if left > right: verified = False keys[i:i + 2] = [right, left] sign = sign + 1 string1 = [ key_val[k] for k in keys ] return (string1, sign) def evaluate_deltas(e): """ We evaluate KroneckerDelta symbols in the expression assuming Einstein summation. Explanation =========== If one index is repeated it is summed over and in effect substituted with the other one. If both indices are repeated we substitute according to what is the preferred index. this is determined by KroneckerDelta.preferred_index and KroneckerDelta.killable_index. In case there are no possible substitutions or if a substitution would imply a loss of information, nothing is done. In case an index appears in more than one KroneckerDelta, the resulting substitution depends on the order of the factors. Since the ordering is platform dependent, the literal expression resulting from this function may be hard to predict. Examples ======== We assume the following: >>> from sympy import symbols, Function, Dummy, KroneckerDelta >>> from sympy.physics.secondquant import evaluate_deltas >>> i,j = symbols('i j', below_fermi=True, cls=Dummy) >>> a,b = symbols('a b', above_fermi=True, cls=Dummy) >>> p,q = symbols('p q', cls=Dummy) >>> f = Function('f') >>> t = Function('t') The order of preference for these indices according to KroneckerDelta is (a, b, i, j, p, q). Trivial cases: >>> evaluate_deltas(KroneckerDelta(i,j)*f(i)) # d_ij f(i) -> f(j) f(_j) >>> evaluate_deltas(KroneckerDelta(i,j)*f(j)) # d_ij f(j) -> f(i) f(_i) >>> evaluate_deltas(KroneckerDelta(i,p)*f(p)) # d_ip f(p) -> f(i) f(_i) >>> evaluate_deltas(KroneckerDelta(q,p)*f(p)) # d_qp f(p) -> f(q) f(_q) >>> evaluate_deltas(KroneckerDelta(q,p)*f(q)) # d_qp f(q) -> f(p) f(_p) More interesting cases: >>> evaluate_deltas(KroneckerDelta(i,p)*t(a,i)*f(p,q)) f(_i, _q)*t(_a, _i) >>> evaluate_deltas(KroneckerDelta(a,p)*t(a,i)*f(p,q)) f(_a, _q)*t(_a, _i) >>> evaluate_deltas(KroneckerDelta(p,q)*f(p,q)) f(_p, _p) Finally, here are some cases where nothing is done, because that would imply a loss of information: >>> evaluate_deltas(KroneckerDelta(i,p)*f(q)) f(_q)*KroneckerDelta(_i, _p) >>> evaluate_deltas(KroneckerDelta(i,p)*f(i)) f(_i)*KroneckerDelta(_i, _p) """ # We treat Deltas only in mul objects # for general function objects we don't evaluate KroneckerDeltas in arguments, # but here we hard code exceptions to this rule accepted_functions = ( Add, ) if isinstance(e, accepted_functions): return e.func(*[evaluate_deltas(arg) for arg in e.args]) elif isinstance(e, Mul): # find all occurrences of delta function and count each index present in # expression. deltas = [] indices = {} for i in e.args: for s in i.free_symbols: if s in indices: indices[s] += 1 else: indices[s] = 0 # geek counting simplifies logic below if isinstance(i, KroneckerDelta): deltas.append(i) for d in deltas: # If we do something, and there are more deltas, we should recurse # to treat the resulting expression properly if d.killable_index.is_Symbol and indices[d.killable_index]: e = e.subs(d.killable_index, d.preferred_index) if len(deltas) > 1: return evaluate_deltas(e) elif (d.preferred_index.is_Symbol and indices[d.preferred_index] and d.indices_contain_equal_information): e = e.subs(d.preferred_index, d.killable_index) if len(deltas) > 1: return evaluate_deltas(e) else: pass return e # nothing to do, maybe we hit a Symbol or a number else: return e def substitute_dummies(expr, new_indices=False, pretty_indices={}): """ Collect terms by substitution of dummy variables. Explanation =========== This routine allows simplification of Add expressions containing terms which differ only due to dummy variables. The idea is to substitute all dummy variables consistently depending on the structure of the term. For each term, we obtain a sequence of all dummy variables, where the order is determined by the index range, what factors the index belongs to and its position in each factor. See _get_ordered_dummies() for more information about the sorting of dummies. The index sequence is then substituted consistently in each term. Examples ======== >>> from sympy import symbols, Function, Dummy >>> from sympy.physics.secondquant import substitute_dummies >>> a,b,c,d = symbols('a b c d', above_fermi=True, cls=Dummy) >>> i,j = symbols('i j', below_fermi=True, cls=Dummy) >>> f = Function('f') >>> expr = f(a,b) + f(c,d); expr f(_a, _b) + f(_c, _d) Since a, b, c and d are equivalent summation indices, the expression can be simplified to a single term (for which the dummy indices are still summed over) >>> substitute_dummies(expr) 2*f(_a, _b) Controlling output: By default the dummy symbols that are already present in the expression will be reused in a different permutation. However, if new_indices=True, new dummies will be generated and inserted. The keyword 'pretty_indices' can be used to control this generation of new symbols. By default the new dummies will be generated on the form i_1, i_2, a_1, etc. If you supply a dictionary with key:value pairs in the form: { index_group: string_of_letters } The letters will be used as labels for the new dummy symbols. The index_groups must be one of 'above', 'below' or 'general'. >>> expr = f(a,b,i,j) >>> my_dummies = { 'above':'st', 'below':'uv' } >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies) f(_s, _t, _u, _v) If we run out of letters, or if there is no keyword for some index_group the default dummy generator will be used as a fallback: >>> p,q = symbols('p q', cls=Dummy) # general indices >>> expr = f(p,q) >>> substitute_dummies(expr, new_indices=True, pretty_indices=my_dummies) f(_p_0, _p_1) """ # setup the replacing dummies if new_indices: letters_above = pretty_indices.get('above', "") letters_below = pretty_indices.get('below', "") letters_general = pretty_indices.get('general', "") len_above = len(letters_above) len_below = len(letters_below) len_general = len(letters_general) def _i(number): try: return letters_below[number] except IndexError: return 'i_' + str(number - len_below) def _a(number): try: return letters_above[number] except IndexError: return 'a_' + str(number - len_above) def _p(number): try: return letters_general[number] except IndexError: return 'p_' + str(number - len_general) aboves = [] belows = [] generals = [] dummies = expr.atoms(Dummy) if not new_indices: dummies = sorted(dummies, key=default_sort_key) # generate lists with the dummies we will insert a = i = p = 0 for d in dummies: assum = d.assumptions0 if assum.get("above_fermi"): if new_indices: sym = _a(a) a += 1 l1 = aboves elif assum.get("below_fermi"): if new_indices: sym = _i(i) i += 1 l1 = belows else: if new_indices: sym = _p(p) p += 1 l1 = generals if new_indices: l1.append(Dummy(sym, **assum)) else: l1.append(d) expr = expr.expand() terms = Add.make_args(expr) new_terms = [] for term in terms: i = iter(belows) a = iter(aboves) p = iter(generals) ordered = _get_ordered_dummies(term) subsdict = {} for d in ordered: if d.assumptions0.get('below_fermi'): subsdict[d] = next(i) elif d.assumptions0.get('above_fermi'): subsdict[d] = next(a) else: subsdict[d] = next(p) subslist = [] final_subs = [] for k, v in subsdict.items(): if k == v: continue if v in subsdict: # We check if the sequence of substitutions end quickly. In # that case, we can avoid temporary symbols if we ensure the # correct substitution order. if subsdict[v] in subsdict: # (x, y) -> (y, x), we need a temporary variable x = Dummy('x') subslist.append((k, x)) final_subs.append((x, v)) else: # (x, y) -> (y, a), x->y must be done last # but before temporary variables are resolved final_subs.insert(0, (k, v)) else: subslist.append((k, v)) subslist.extend(final_subs) new_terms.append(term.subs(subslist)) return Add(*new_terms) class KeyPrinter(StrPrinter): """Printer for which only equal objects are equal in print""" def _print_Dummy(self, expr): return "(%s_%i)" % (expr.name, expr.dummy_index) def __kprint(expr): p = KeyPrinter() return p.doprint(expr) def _get_ordered_dummies(mul, verbose=False): """Returns all dummies in the mul sorted in canonical order. Explanation =========== The purpose of the canonical ordering is that dummies can be substituted consistently across terms with the result that equivalent terms can be simplified. It is not possible to determine if two terms are equivalent based solely on the dummy order. However, a consistent substitution guided by the ordered dummies should lead to trivially (non-)equivalent terms, thereby revealing the equivalence. This also means that if two terms have identical sequences of dummies, the (non-)equivalence should already be apparent. Strategy -------- The canoncial order is given by an arbitrary sorting rule. A sort key is determined for each dummy as a tuple that depends on all factors where the index is present. The dummies are thereby sorted according to the contraction structure of the term, instead of sorting based solely on the dummy symbol itself. After all dummies in the term has been assigned a key, we check for identical keys, i.e. unorderable dummies. If any are found, we call a specialized method, _determine_ambiguous(), that will determine a unique order based on recursive calls to _get_ordered_dummies(). Key description --------------- A high level description of the sort key: 1. Range of the dummy index 2. Relation to external (non-dummy) indices 3. Position of the index in the first factor 4. Position of the index in the second factor The sort key is a tuple with the following components: 1. A single character indicating the range of the dummy (above, below or general.) 2. A list of strings with fully masked string representations of all factors where the dummy is present. By masked, we mean that dummies are represented by a symbol to indicate either below fermi, above or general. No other information is displayed about the dummies at this point. The list is sorted stringwise. 3. An integer number indicating the position of the index, in the first factor as sorted in 2. 4. An integer number indicating the position of the index, in the second factor as sorted in 2. If a factor is either of type AntiSymmetricTensor or SqOperator, the index position in items 3 and 4 is indicated as 'upper' or 'lower' only. (Creation operators are considered upper and annihilation operators lower.) If the masked factors are identical, the two factors cannot be ordered unambiguously in item 2. In this case, items 3, 4 are left out. If several indices are contracted between the unorderable factors, it will be handled by _determine_ambiguous() """ # setup dicts to avoid repeated calculations in key() args = Mul.make_args(mul) fac_dum = { fac: fac.atoms(Dummy) for fac in args } fac_repr = { fac: __kprint(fac) for fac in args } all_dums = set().union(*fac_dum.values()) mask = {} for d in all_dums: if d.assumptions0.get('below_fermi'): mask[d] = '0' elif d.assumptions0.get('above_fermi'): mask[d] = '1' else: mask[d] = '2' dum_repr = {d: __kprint(d) for d in all_dums} def _key(d): dumstruct = [ fac for fac in fac_dum if d in fac_dum[fac] ] other_dums = set().union(*[fac_dum[fac] for fac in dumstruct]) fac = dumstruct[-1] if other_dums is fac_dum[fac]: other_dums = fac_dum[fac].copy() other_dums.remove(d) masked_facs = [ fac_repr[fac] for fac in dumstruct ] for d2 in other_dums: masked_facs = [ fac.replace(dum_repr[d2], mask[d2]) for fac in masked_facs ] all_masked = [ fac.replace(dum_repr[d], mask[d]) for fac in masked_facs ] masked_facs = dict(list(zip(dumstruct, masked_facs))) # dummies for which the ordering cannot be determined if has_dups(all_masked): all_masked.sort() return mask[d], tuple(all_masked) # positions are ambiguous # sort factors according to fully masked strings keydict = dict(list(zip(dumstruct, all_masked))) dumstruct.sort(key=lambda x: keydict[x]) all_masked.sort() pos_val = [] for fac in dumstruct: if isinstance(fac, AntiSymmetricTensor): if d in fac.upper: pos_val.append('u') if d in fac.lower: pos_val.append('l') elif isinstance(fac, Creator): pos_val.append('u') elif isinstance(fac, Annihilator): pos_val.append('l') elif isinstance(fac, NO): ops = [ op for op in fac if op.has(d) ] for op in ops: if isinstance(op, Creator): pos_val.append('u') else: pos_val.append('l') else: # fallback to position in string representation facpos = -1 while 1: facpos = masked_facs[fac].find(dum_repr[d], facpos + 1) if facpos == -1: break pos_val.append(facpos) return (mask[d], tuple(all_masked), pos_val[0], pos_val[-1]) dumkey = dict(list(zip(all_dums, list(map(_key, all_dums))))) result = sorted(all_dums, key=lambda x: dumkey[x]) if has_dups(iter(dumkey.values())): # We have ambiguities unordered = defaultdict(set) for d, k in dumkey.items(): unordered[k].add(d) for k in [ k for k in unordered if len(unordered[k]) < 2 ]: del unordered[k] unordered = [ unordered[k] for k in sorted(unordered) ] result = _determine_ambiguous(mul, result, unordered) return result def _determine_ambiguous(term, ordered, ambiguous_groups): # We encountered a term for which the dummy substitution is ambiguous. # This happens for terms with 2 or more contractions between factors that # cannot be uniquely ordered independent of summation indices. For # example: # # Sum(p, q) v^{p, .}_{q, .}v^{q, .}_{p, .} # # Assuming that the indices represented by . are dummies with the # same range, the factors cannot be ordered, and there is no # way to determine a consistent ordering of p and q. # # The strategy employed here, is to relabel all unambiguous dummies with # non-dummy symbols and call _get_ordered_dummies again. This procedure is # applied to the entire term so there is a possibility that # _determine_ambiguous() is called again from a deeper recursion level. # break recursion if there are no ordered dummies all_ambiguous = set() for dummies in ambiguous_groups: all_ambiguous |= dummies all_ordered = set(ordered) - all_ambiguous if not all_ordered: # FIXME: If we arrive here, there are no ordered dummies. A method to # handle this needs to be implemented. In order to return something # useful nevertheless, we choose arbitrarily the first dummy and # determine the rest from this one. This method is dependent on the # actual dummy labels which violates an assumption for the # canonicalization procedure. A better implementation is needed. group = [ d for d in ordered if d in ambiguous_groups[0] ] d = group[0] all_ordered.add(d) ambiguous_groups[0].remove(d) stored_counter = _symbol_factory._counter subslist = [] for d in [ d for d in ordered if d in all_ordered ]: nondum = _symbol_factory._next() subslist.append((d, nondum)) newterm = term.subs(subslist) neworder = _get_ordered_dummies(newterm) _symbol_factory._set_counter(stored_counter) # update ordered list with new information for group in ambiguous_groups: ordered_group = [ d for d in neworder if d in group ] ordered_group.reverse() result = [] for d in ordered: if d in group: result.append(ordered_group.pop()) else: result.append(d) ordered = result return ordered class _SymbolFactory: def __init__(self, label): self._counterVar = 0 self._label = label def _set_counter(self, value): """ Sets counter to value. """ self._counterVar = value @property def _counter(self): """ What counter is currently at. """ return self._counterVar def _next(self): """ Generates the next symbols and increments counter by 1. """ s = Symbol("%s%i" % (self._label, self._counterVar)) self._counterVar += 1 return s _symbol_factory = _SymbolFactory('_]"]_') # most certainly a unique label @cacheit def _get_contractions(string1, keep_only_fully_contracted=False): """ Returns Add-object with contracted terms. Uses recursion to find all contractions. -- Internal helper function -- Will find nonzero contractions in string1 between indices given in leftrange and rightrange. """ # Should we store current level of contraction? if keep_only_fully_contracted and string1: result = [] else: result = [NO(Mul(*string1))] for i in range(len(string1) - 1): for j in range(i + 1, len(string1)): c = contraction(string1[i], string1[j]) if c: sign = (j - i + 1) % 2 if sign: coeff = S.NegativeOne*c else: coeff = c # # Call next level of recursion # ============================ # # We now need to find more contractions among operators # # oplist = string1[:i]+ string1[i+1:j] + string1[j+1:] # # To prevent overcounting, we don't allow contractions # we have already encountered. i.e. contractions between # string1[:i] <---> string1[i+1:j] # and string1[:i] <---> string1[j+1:]. # # This leaves the case: oplist = string1[i + 1:j] + string1[j + 1:] if oplist: result.append(coeff*NO( Mul(*string1[:i])*_get_contractions( oplist, keep_only_fully_contracted=keep_only_fully_contracted))) else: result.append(coeff*NO( Mul(*string1[:i]))) if keep_only_fully_contracted: break # next iteration over i leaves leftmost operator string1[0] uncontracted return Add(*result) def wicks(e, **kw_args): """ Returns the normal ordered equivalent of an expression using Wicks Theorem. Examples ======== >>> from sympy import symbols, Dummy >>> from sympy.physics.secondquant import wicks, F, Fd >>> p, q, r = symbols('p,q,r') >>> wicks(Fd(p)*F(q)) KroneckerDelta(_i, q)*KroneckerDelta(p, q) + NO(CreateFermion(p)*AnnihilateFermion(q)) By default, the expression is expanded: >>> wicks(F(p)*(F(q)+F(r))) NO(AnnihilateFermion(p)*AnnihilateFermion(q)) + NO(AnnihilateFermion(p)*AnnihilateFermion(r)) With the keyword 'keep_only_fully_contracted=True', only fully contracted terms are returned. By request, the result can be simplified in the following order: -- KroneckerDelta functions are evaluated -- Dummy variables are substituted consistently across terms >>> p, q, r = symbols('p q r', cls=Dummy) >>> wicks(Fd(p)*(F(q)+F(r)), keep_only_fully_contracted=True) KroneckerDelta(_i, _q)*KroneckerDelta(_p, _q) + KroneckerDelta(_i, _r)*KroneckerDelta(_p, _r) """ if not e: return S.Zero opts = { 'simplify_kronecker_deltas': False, 'expand': True, 'simplify_dummies': False, 'keep_only_fully_contracted': False } opts.update(kw_args) # check if we are already normally ordered if isinstance(e, NO): if opts['keep_only_fully_contracted']: return S.Zero else: return e elif isinstance(e, FermionicOperator): if opts['keep_only_fully_contracted']: return S.Zero else: return e # break up any NO-objects, and evaluate commutators e = e.doit(wicks=True) # make sure we have only one term to consider e = e.expand() if isinstance(e, Add): if opts['simplify_dummies']: return substitute_dummies(Add(*[ wicks(term, **kw_args) for term in e.args])) else: return Add(*[ wicks(term, **kw_args) for term in e.args]) # For Mul-objects we can actually do something if isinstance(e, Mul): # we don't want to mess around with commuting part of Mul # so we factorize it out before starting recursion c_part = [] string1 = [] for factor in e.args: if factor.is_commutative: c_part.append(factor) else: string1.append(factor) n = len(string1) # catch trivial cases if n == 0: result = e elif n == 1: if opts['keep_only_fully_contracted']: return S.Zero else: result = e else: # non-trivial if isinstance(string1[0], BosonicOperator): raise NotImplementedError string1 = tuple(string1) # recursion over higher order contractions result = _get_contractions(string1, keep_only_fully_contracted=opts['keep_only_fully_contracted'] ) result = Mul(*c_part)*result if opts['expand']: result = result.expand() if opts['simplify_kronecker_deltas']: result = evaluate_deltas(result) return result # there was nothing to do return e class PermutationOperator(Expr): """ Represents the index permutation operator P(ij). P(ij)*f(i)*g(j) = f(i)*g(j) - f(j)*g(i) """ is_commutative = True def __new__(cls, i, j): i, j = sorted(map(sympify, (i, j)), key=default_sort_key) obj = Basic.__new__(cls, i, j) return obj def get_permuted(self, expr): """ Returns -expr with permuted indices. Explanation =========== >>> from sympy import symbols, Function >>> from sympy.physics.secondquant import PermutationOperator >>> p,q = symbols('p,q') >>> f = Function('f') >>> PermutationOperator(p,q).get_permuted(f(p,q)) -f(q, p) """ i = self.args[0] j = self.args[1] if expr.has(i) and expr.has(j): tmp = Dummy() expr = expr.subs(i, tmp) expr = expr.subs(j, i) expr = expr.subs(tmp, j) return S.NegativeOne*expr else: return expr def _latex(self, printer): return "P(%s%s)" % self.args def simplify_index_permutations(expr, permutation_operators): """ Performs simplification by introducing PermutationOperators where appropriate. Explanation =========== Schematically: [abij] - [abji] - [baij] + [baji] -> P(ab)*P(ij)*[abij] permutation_operators is a list of PermutationOperators to consider. If permutation_operators=[P(ab),P(ij)] we will try to introduce the permutation operators P(ij) and P(ab) in the expression. If there are other possible simplifications, we ignore them. >>> from sympy import symbols, Function >>> from sympy.physics.secondquant import simplify_index_permutations >>> from sympy.physics.secondquant import PermutationOperator >>> p,q,r,s = symbols('p,q,r,s') >>> f = Function('f') >>> g = Function('g') >>> expr = f(p)*g(q) - f(q)*g(p); expr f(p)*g(q) - f(q)*g(p) >>> simplify_index_permutations(expr,[PermutationOperator(p,q)]) f(p)*g(q)*PermutationOperator(p, q) >>> PermutList = [PermutationOperator(p,q),PermutationOperator(r,s)] >>> expr = f(p,r)*g(q,s) - f(q,r)*g(p,s) + f(q,s)*g(p,r) - f(p,s)*g(q,r) >>> simplify_index_permutations(expr,PermutList) f(p, r)*g(q, s)*PermutationOperator(p, q)*PermutationOperator(r, s) """ def _get_indices(expr, ind): """ Collects indices recursively in predictable order. """ result = [] for arg in expr.args: if arg in ind: result.append(arg) else: if arg.args: result.extend(_get_indices(arg, ind)) return result def _choose_one_to_keep(a, b, ind): # we keep the one where indices in ind are in order ind[0] < ind[1] return min(a, b, key=lambda x: default_sort_key(_get_indices(x, ind))) expr = expr.expand() if isinstance(expr, Add): terms = set(expr.args) for P in permutation_operators: new_terms = set() on_hold = set() while terms: term = terms.pop() permuted = P.get_permuted(term) if permuted in terms | on_hold: try: terms.remove(permuted) except KeyError: on_hold.remove(permuted) keep = _choose_one_to_keep(term, permuted, P.args) new_terms.add(P*keep) else: # Some terms must get a second chance because the permuted # term may already have canonical dummy ordering. Then # substitute_dummies() does nothing. However, the other # term, if it exists, will be able to match with us. permuted1 = permuted permuted = substitute_dummies(permuted) if permuted1 == permuted: on_hold.add(term) elif permuted in terms | on_hold: try: terms.remove(permuted) except KeyError: on_hold.remove(permuted) keep = _choose_one_to_keep(term, permuted, P.args) new_terms.add(P*keep) else: new_terms.add(term) terms = new_terms | on_hold return Add(*terms) return expr sympy-sympy-1.9/sympy/physics/sho.py000066400000000000000000000047141412543434000177370ustar00rootroot00000000000000from sympy.core import S, pi, Rational from sympy.functions import assoc_laguerre, sqrt, exp, factorial, factorial2 def R_nl(n, l, nu, r): """ Returns the radial wavefunction R_{nl} for a 3d isotropic harmonic oscillator. Parameters ========== ``n`` : The "nodal" quantum number. Corresponds to the number of nodes in the wavefunction. ``n >= 0`` ``l`` : The quantum number for orbital angular momentum. ``nu`` : mass-scaled frequency: nu = m*omega/(2*hbar) where `m` is the mass and `omega` the frequency of the oscillator. (in atomic units ``nu == omega/2``) ``r`` : Radial coordinate. Examples ======== >>> from sympy.physics.sho import R_nl >>> from sympy.abc import r, nu, l >>> R_nl(0, 0, 1, r) 2*2**(3/4)*exp(-r**2)/pi**(1/4) >>> R_nl(1, 0, 1, r) 4*2**(1/4)*sqrt(3)*(3/2 - 2*r**2)*exp(-r**2)/(3*pi**(1/4)) l, nu and r may be symbolic: >>> R_nl(0, 0, nu, r) 2*2**(3/4)*sqrt(nu**(3/2))*exp(-nu*r**2)/pi**(1/4) >>> R_nl(0, l, 1, r) r**l*sqrt(2**(l + 3/2)*2**(l + 2)/factorial2(2*l + 1))*exp(-r**2)/pi**(1/4) The normalization of the radial wavefunction is: >>> from sympy import Integral, oo >>> Integral(R_nl(0, 0, 1, r)**2*r**2, (r, 0, oo)).n() 1.00000000000000 >>> Integral(R_nl(1, 0, 1, r)**2*r**2, (r, 0, oo)).n() 1.00000000000000 >>> Integral(R_nl(1, 1, 1, r)**2*r**2, (r, 0, oo)).n() 1.00000000000000 """ n, l, nu, r = map(S, [n, l, nu, r]) # formula uses n >= 1 (instead of nodal n >= 0) n = n + 1 C = sqrt( ((2*nu)**(l + Rational(3, 2))*2**(n + l + 1)*factorial(n - 1))/ (sqrt(pi)*(factorial2(2*n + 2*l - 1))) ) return C*r**(l)*exp(-nu*r**2)*assoc_laguerre(n - 1, l + S.Half, 2*nu*r**2) def E_nl(n, l, hw): """ Returns the Energy of an isotropic harmonic oscillator. Parameters ========== ``n`` : The "nodal" quantum number. ``l`` : The orbital angular momentum. ``hw`` : The harmonic oscillator parameter. Notes ===== The unit of the returned value matches the unit of hw, since the energy is calculated as: E_nl = (2*n + l + 3/2)*hw Examples ======== >>> from sympy.physics.sho import E_nl >>> from sympy import symbols >>> x, y, z = symbols('x, y, z') >>> E_nl(x, y, z) z*(2*x + y + 3/2) """ return (2*n + l + Rational(3, 2))*hw sympy-sympy-1.9/sympy/physics/tests/000077500000000000000000000000001412543434000177305ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/tests/__init__.py000066400000000000000000000000001412543434000220270ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/tests/test_clebsch_gordan.py000066400000000000000000000220311412543434000242740ustar00rootroot00000000000000from sympy import (S, sqrt, pi, Ynm, symbols, exp, sin, cos, I, Matrix) from sympy.physics.wigner import (clebsch_gordan, wigner_9j, wigner_6j, gaunt, racah, dot_rot_grad_Ynm, wigner_3j, wigner_d_small, wigner_d) from sympy.core.numbers import Rational # for test cases, refer : https://en.wikipedia.org/wiki/Table_of_Clebsch%E2%80%93Gordan_coefficients def test_clebsch_gordan_docs(): assert clebsch_gordan(Rational(3, 2), S.Half, 2, Rational(3, 2), S.Half, 2) == 1 assert clebsch_gordan(Rational(3, 2), S.Half, 1, Rational(3, 2), Rational(-1, 2), 1) == sqrt(3)/2 assert clebsch_gordan(Rational(3, 2), S.Half, 1, Rational(-1, 2), S.Half, 0) == -sqrt(2)/2 def test_clebsch_gordan1(): j_1 = S.Half j_2 = S.Half m = 1 j = 1 m_1 = S.Half m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S.Half j_2 = S.Half m = -1 j = 1 m_1 = Rational(-1, 2) m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S.Half j_2 = S.Half m = 0 j = 1 m_1 = S.Half m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 0 j_1 = S.Half j_2 = S.Half m = 0 j = 1 m_1 = S.Half m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/2 j_1 = S.Half j_2 = S.Half m = 0 j = 0 m_1 = S.Half m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/2 j_1 = S.Half j_2 = S.Half m = 0 j = 1 m_1 = Rational(-1, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/2 j_1 = S.Half j_2 = S.Half m = 0 j = 0 m_1 = Rational(-1, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -sqrt(2)/2 def test_clebsch_gordan2(): j_1 = S.One j_2 = S.Half m = Rational(3, 2) j = Rational(3, 2) m_1 = 1 m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S.One j_2 = S.Half m = S.Half j = Rational(3, 2) m_1 = 1 m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(3) j_1 = S.One j_2 = S.Half m = S.Half j = S.Half m_1 = 1 m_2 = Rational(-1, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/sqrt(3) j_1 = S.One j_2 = S.Half m = S.Half j = S.Half m_1 = 0 m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -1/sqrt(3) j_1 = S.One j_2 = S.Half m = S.Half j = Rational(3, 2) m_1 = 0 m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(2)/sqrt(3) j_1 = S.One j_2 = S.One m = S(2) j = S(2) m_1 = 1 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S.One j_2 = S.One m = 1 j = S(2) m_1 = 1 m_2 = 0 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) j_1 = S.One j_2 = S.One m = 1 j = S(2) m_1 = 0 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) j_1 = S.One j_2 = S.One m = 1 j = 1 m_1 = 1 m_2 = 0 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) j_1 = S.One j_2 = S.One m = 1 j = 1 m_1 = 0 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == -1/sqrt(2) def test_clebsch_gordan3(): j_1 = Rational(3, 2) j_2 = Rational(3, 2) m = S(3) j = S(3) m_1 = Rational(3, 2) m_2 = Rational(3, 2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = Rational(3, 2) j_2 = Rational(3, 2) m = S(2) j = S(2) m_1 = Rational(3, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) j_1 = Rational(3, 2) j_2 = Rational(3, 2) m = S(2) j = S(3) m_1 = Rational(3, 2) m_2 = S.Half assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) def test_clebsch_gordan4(): j_1 = S(2) j_2 = S(2) m = S(4) j = S(4) m_1 = S(2) m_2 = S(2) assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = S(2) j_2 = S(2) m = S(3) j = S(3) m_1 = S(2) m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(2) j_1 = S(2) j_2 = S(2) m = S(2) j = S(3) m_1 = 1 m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 0 def test_clebsch_gordan5(): j_1 = Rational(5, 2) j_2 = S.One m = Rational(7, 2) j = Rational(7, 2) m_1 = Rational(5, 2) m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1 j_1 = Rational(5, 2) j_2 = S.One m = Rational(5, 2) j = Rational(5, 2) m_1 = Rational(5, 2) m_2 = 0 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == sqrt(5)/sqrt(7) j_1 = Rational(5, 2) j_2 = S.One m = Rational(3, 2) j = Rational(3, 2) m_1 = S.Half m_2 = 1 assert clebsch_gordan(j_1, j_2, j, m_1, m_2, m) == 1/sqrt(15) def test_wigner(): def tn(a, b): return (a - b).n(64) < S('1e-64') assert tn(wigner_9j(1, 1, 1, 1, 1, 1, 1, 1, 0, prec=64), Rational(1, 18)) assert wigner_9j(3, 3, 2, 3, 3, 2, 3, 3, 2) == 3221*sqrt( 70)/(246960*sqrt(105)) - 365/(3528*sqrt(70)*sqrt(105)) assert wigner_6j(5, 5, 5, 5, 5, 5) == Rational(1, 52) assert tn(wigner_6j(8, 8, 8, 8, 8, 8, prec=64), Rational(-12219, 965770)) # regression test for #8747 half = S.Half assert wigner_9j(0, 0, 0, 0, half, half, 0, half, half) == half assert (wigner_9j(3, 5, 4, 7 * half, 5 * half, 4, 9 * half, 9 * half, 0) == -sqrt(Rational(361, 205821000))) assert (wigner_9j(1, 4, 3, 5 * half, 4, 5 * half, 5 * half, 2, 7 * half) == -sqrt(Rational(3971, 373403520))) assert (wigner_9j(4, 9 * half, 5 * half, 2, 4, 4, 5, 7 * half, 7 * half) == -sqrt(Rational(3481, 5042614500))) def test_gaunt(): def tn(a, b): return (a - b).n(64) < S('1e-64') assert gaunt(1, 0, 1, 1, 0, -1) == -1/(2*sqrt(pi)) assert isinstance(gaunt(1, 1, 0, -1, 1, 0).args[0], Rational) assert isinstance(gaunt(0, 1, 1, 0, -1, 1).args[0], Rational) assert tn(gaunt( 10, 10, 12, 9, 3, -12, prec=64), (Rational(-98, 62031)) * sqrt(6279)/sqrt(pi)) def gaunt_ref(l1, l2, l3, m1, m2, m3): return ( sqrt((2 * l1 + 1) * (2 * l2 + 1) * (2 * l3 + 1) / (4 * pi)) * wigner_3j(l1, l2, l3, 0, 0, 0) * wigner_3j(l1, l2, l3, m1, m2, m3) ) threshold = 1e-10 l_max = 3 l3_max = 24 for l1 in range(l_max + 1): for l2 in range(l_max + 1): for l3 in range(l3_max + 1): for m1 in range(-l1, l1 + 1): for m2 in range(-l2, l2 + 1): for m3 in range(-l3, l3 + 1): args = l1, l2, l3, m1, m2, m3 g = gaunt(*args) g0 = gaunt_ref(*args) assert abs(g - g0) < threshold if m1 + m2 + m3 != 0: assert abs(g) < threshold if (l1 + l2 + l3) % 2: assert abs(g) < threshold def test_racah(): assert racah(3,3,3,3,3,3) == Rational(-1,14) assert racah(2,2,2,2,2,2) == Rational(-3,70) assert racah(7,8,7,1,7,7, prec=4).is_Float assert racah(5.5,7.5,9.5,6.5,8,9) == -719*sqrt(598)/1158924 assert abs(racah(5.5,7.5,9.5,6.5,8,9, prec=4) - (-0.01517)) < S('1e-4') def test_dot_rota_grad_SH(): theta, phi = symbols("theta phi") assert dot_rot_grad_Ynm(1, 1, 1, 1, 1, 0) != \ sqrt(30)*Ynm(2, 2, 1, 0)/(10*sqrt(pi)) assert dot_rot_grad_Ynm(1, 1, 1, 1, 1, 0).doit() == \ sqrt(30)*Ynm(2, 2, 1, 0)/(10*sqrt(pi)) assert dot_rot_grad_Ynm(1, 5, 1, 1, 1, 2) != \ 0 assert dot_rot_grad_Ynm(1, 5, 1, 1, 1, 2).doit() == \ 0 assert dot_rot_grad_Ynm(3, 3, 3, 3, theta, phi).doit() == \ 15*sqrt(3003)*Ynm(6, 6, theta, phi)/(143*sqrt(pi)) assert dot_rot_grad_Ynm(3, 3, 1, 1, theta, phi).doit() == \ sqrt(3)*Ynm(4, 4, theta, phi)/sqrt(pi) assert dot_rot_grad_Ynm(3, 2, 2, 0, theta, phi).doit() == \ 3*sqrt(55)*Ynm(5, 2, theta, phi)/(11*sqrt(pi)) assert dot_rot_grad_Ynm(3, 2, 3, 2, theta, phi).doit().expand() == \ -sqrt(70)*Ynm(4, 4, theta, phi)/(11*sqrt(pi)) + \ 45*sqrt(182)*Ynm(6, 4, theta, phi)/(143*sqrt(pi)) def test_wigner_d(): half = S(1)/2 alpha, beta, gamma = symbols("alpha, beta, gamma", real=True) d = wigner_d_small(half, beta).subs({beta: pi/2}) d_ = Matrix([[1, 1], [-1, 1]])/sqrt(2) assert d == d_ D = wigner_d(half, alpha, beta, gamma) assert D[0, 0] == exp(I*alpha/2)*exp(I*gamma/2)*cos(beta/2) assert D[0, 1] == exp(I*alpha/2)*exp(-I*gamma/2)*sin(beta/2) assert D[1, 0] == -exp(-I*alpha/2)*exp(I*gamma/2)*sin(beta/2) assert D[1, 1] == exp(-I*alpha/2)*exp(-I*gamma/2)*cos(beta/2) sympy-sympy-1.9/sympy/physics/tests/test_hydrogen.py000066400000000000000000000111211412543434000231540ustar00rootroot00000000000000from sympy import exp, integrate, oo, S, simplify, sqrt, symbols, pi, sin, \ cos, I, Rational from sympy.physics.hydrogen import R_nl, E_nl, E_nl_dirac, Psi_nlm from sympy.testing.pytest import raises n, r, Z = symbols('n r Z') def feq(a, b, max_relative_error=1e-12, max_absolute_error=1e-12): a = float(a) b = float(b) # if the numbers are close enough (absolutely), then they are equal if abs(a - b) < max_absolute_error: return True # if not, they can still be equal if their relative error is small if abs(b) > abs(a): relative_error = abs((a - b)/b) else: relative_error = abs((a - b)/a) return relative_error <= max_relative_error def test_wavefunction(): a = 1/Z R = { (1, 0): 2*sqrt(1/a**3) * exp(-r/a), (2, 0): sqrt(1/(2*a**3)) * exp(-r/(2*a)) * (1 - r/(2*a)), (2, 1): S.Half * sqrt(1/(6*a**3)) * exp(-r/(2*a)) * r/a, (3, 0): Rational(2, 3) * sqrt(1/(3*a**3)) * exp(-r/(3*a)) * (1 - 2*r/(3*a) + Rational(2, 27) * (r/a)**2), (3, 1): Rational(4, 27) * sqrt(2/(3*a**3)) * exp(-r/(3*a)) * (1 - r/(6*a)) * r/a, (3, 2): Rational(2, 81) * sqrt(2/(15*a**3)) * exp(-r/(3*a)) * (r/a)**2, (4, 0): Rational(1, 4) * sqrt(1/a**3) * exp(-r/(4*a)) * (1 - 3*r/(4*a) + Rational(1, 8) * (r/a)**2 - Rational(1, 192) * (r/a)**3), (4, 1): Rational(1, 16) * sqrt(5/(3*a**3)) * exp(-r/(4*a)) * (1 - r/(4*a) + Rational(1, 80) * (r/a)**2) * (r/a), (4, 2): Rational(1, 64) * sqrt(1/(5*a**3)) * exp(-r/(4*a)) * (1 - r/(12*a)) * (r/a)**2, (4, 3): Rational(1, 768) * sqrt(1/(35*a**3)) * exp(-r/(4*a)) * (r/a)**3, } for n, l in R: assert simplify(R_nl(n, l, r, Z) - R[(n, l)]) == 0 def test_norm(): # Maximum "n" which is tested: n_max = 2 # it works, but is slow, for n_max > 2 for n in range(n_max + 1): for l in range(n): assert integrate(R_nl(n, l, r)**2 * r**2, (r, 0, oo)) == 1 def test_psi_nlm(): r=S('r') phi=S('phi') theta=S('theta') assert (Psi_nlm(1, 0, 0, r, phi, theta) == exp(-r) / sqrt(pi)) assert (Psi_nlm(2, 1, -1, r, phi, theta)) == S.Half * exp(-r / (2)) * r \ * (sin(theta) * exp(-I * phi) / (4 * sqrt(pi))) assert (Psi_nlm(3, 2, 1, r, phi, theta, 2) == -sqrt(2) * sin(theta) \ * exp(I * phi) * cos(theta) / (4 * sqrt(pi)) * S(2) / 81 \ * sqrt(2 * 2 ** 3) * exp(-2 * r / (3)) * (r * 2) ** 2) def test_hydrogen_energies(): assert E_nl(n, Z) == -Z**2/(2*n**2) assert E_nl(n) == -1/(2*n**2) assert E_nl(1, 47) == -S(47)**2/(2*1**2) assert E_nl(2, 47) == -S(47)**2/(2*2**2) assert E_nl(1) == -S.One/(2*1**2) assert E_nl(2) == -S.One/(2*2**2) assert E_nl(3) == -S.One/(2*3**2) assert E_nl(4) == -S.One/(2*4**2) assert E_nl(100) == -S.One/(2*100**2) raises(ValueError, lambda: E_nl(0)) def test_hydrogen_energies_relat(): # First test exact formulas for small "c" so that we get nice expressions: assert E_nl_dirac(2, 0, Z=1, c=1) == 1/sqrt(2) - 1 assert simplify(E_nl_dirac(2, 0, Z=1, c=2) - ( (8*sqrt(3) + 16) / sqrt(16*sqrt(3) + 32) - 4)) == 0 assert simplify(E_nl_dirac(2, 0, Z=1, c=3) - ( (54*sqrt(2) + 81) / sqrt(108*sqrt(2) + 162) - 9)) == 0 # Now test for almost the correct speed of light, without floating point # numbers: assert simplify(E_nl_dirac(2, 0, Z=1, c=137) - ( (352275361 + 10285412 * sqrt(1173)) / sqrt(704550722 + 20570824 * sqrt(1173)) - 18769)) == 0 assert simplify(E_nl_dirac(2, 0, Z=82, c=137) - ( (352275361 + 2571353 * sqrt(12045)) / sqrt(704550722 + 5142706*sqrt(12045)) - 18769)) == 0 # Test using exact speed of light, and compare against the nonrelativistic # energies: for n in range(1, 5): for l in range(n): assert feq(E_nl_dirac(n, l), E_nl(n), 1e-5, 1e-5) if l > 0: assert feq(E_nl_dirac(n, l, False), E_nl(n), 1e-5, 1e-5) Z = 2 for n in range(1, 5): for l in range(n): assert feq(E_nl_dirac(n, l, Z=Z), E_nl(n, Z), 1e-4, 1e-4) if l > 0: assert feq(E_nl_dirac(n, l, False, Z), E_nl(n, Z), 1e-4, 1e-4) Z = 3 for n in range(1, 5): for l in range(n): assert feq(E_nl_dirac(n, l, Z=Z), E_nl(n, Z), 1e-3, 1e-3) if l > 0: assert feq(E_nl_dirac(n, l, False, Z), E_nl(n, Z), 1e-3, 1e-3) # Test the exceptions: raises(ValueError, lambda: E_nl_dirac(0, 0)) raises(ValueError, lambda: E_nl_dirac(1, -1)) raises(ValueError, lambda: E_nl_dirac(1, 0, False)) sympy-sympy-1.9/sympy/physics/tests/test_paulialgebra.py000066400000000000000000000026331412543434000237750ustar00rootroot00000000000000from sympy import I, symbols from sympy.physics.paulialgebra import Pauli from sympy.testing.pytest import XFAIL from sympy.physics.quantum import TensorProduct sigma1 = Pauli(1) sigma2 = Pauli(2) sigma3 = Pauli(3) tau1 = symbols("tau1", commutative = False) def test_Pauli(): assert sigma1 == sigma1 assert sigma1 != sigma2 assert sigma1*sigma2 == I*sigma3 assert sigma3*sigma1 == I*sigma2 assert sigma2*sigma3 == I*sigma1 assert sigma1*sigma1 == 1 assert sigma2*sigma2 == 1 assert sigma3*sigma3 == 1 assert sigma1**0 == 1 assert sigma1**1 == sigma1 assert sigma1**2 == 1 assert sigma1**3 == sigma1 assert sigma1**4 == 1 assert sigma3**2 == 1 assert sigma1*2*sigma1 == 2 def test_evaluate_pauli_product(): from sympy.physics.paulialgebra import evaluate_pauli_product assert evaluate_pauli_product(I*sigma2*sigma3) == -sigma1 # Check issue 6471 assert evaluate_pauli_product(-I*4*sigma1*sigma2) == 4*sigma3 assert evaluate_pauli_product( 1 + I*sigma1*sigma2*sigma1*sigma2 + \ I*sigma1*sigma2*tau1*sigma1*sigma3 + \ ((tau1**2).subs(tau1, I*sigma1)) + \ sigma3*((tau1**2).subs(tau1, I*sigma1)) + \ TensorProduct(I*sigma1*sigma2*sigma1*sigma2, 1) ) == 1 -I + I*sigma3*tau1*sigma2 - 1 - sigma3 - I*TensorProduct(1,1) @XFAIL def test_Pauli_should_work(): assert sigma1*sigma3*sigma1 == -sigma3 sympy-sympy-1.9/sympy/physics/tests/test_physics_matrices.py000066400000000000000000000053771412543434000247260ustar00rootroot00000000000000from sympy.physics.matrices import msigma, mgamma, minkowski_tensor, pat_matrix, mdft from sympy import zeros, eye, I, Matrix, sqrt, Rational, S from sympy.testing.pytest import warns_deprecated_sympy def test_parallel_axis_theorem(): # This tests the parallel axis theorem matrix by comparing to test # matrices. # First case, 1 in all directions. mat1 = Matrix(((2, -1, -1), (-1, 2, -1), (-1, -1, 2))) assert pat_matrix(1, 1, 1, 1) == mat1 assert pat_matrix(2, 1, 1, 1) == 2*mat1 # Second case, 1 in x, 0 in all others mat2 = Matrix(((0, 0, 0), (0, 1, 0), (0, 0, 1))) assert pat_matrix(1, 1, 0, 0) == mat2 assert pat_matrix(2, 1, 0, 0) == 2*mat2 # Third case, 1 in y, 0 in all others mat3 = Matrix(((1, 0, 0), (0, 0, 0), (0, 0, 1))) assert pat_matrix(1, 0, 1, 0) == mat3 assert pat_matrix(2, 0, 1, 0) == 2*mat3 # Fourth case, 1 in z, 0 in all others mat4 = Matrix(((1, 0, 0), (0, 1, 0), (0, 0, 0))) assert pat_matrix(1, 0, 0, 1) == mat4 assert pat_matrix(2, 0, 0, 1) == 2*mat4 def test_Pauli(): #this and the following test are testing both Pauli and Dirac matrices #and also that the general Matrix class works correctly in a real world #situation sigma1 = msigma(1) sigma2 = msigma(2) sigma3 = msigma(3) assert sigma1 == sigma1 assert sigma1 != sigma2 # sigma*I -> I*sigma (see #354) assert sigma1*sigma2 == sigma3*I assert sigma3*sigma1 == sigma2*I assert sigma2*sigma3 == sigma1*I assert sigma1*sigma1 == eye(2) assert sigma2*sigma2 == eye(2) assert sigma3*sigma3 == eye(2) assert sigma1*2*sigma1 == 2*eye(2) assert sigma1*sigma3*sigma1 == -sigma3 def test_Dirac(): gamma0 = mgamma(0) gamma1 = mgamma(1) gamma2 = mgamma(2) gamma3 = mgamma(3) gamma5 = mgamma(5) # gamma*I -> I*gamma (see #354) assert gamma5 == gamma0 * gamma1 * gamma2 * gamma3 * I assert gamma1 * gamma2 + gamma2 * gamma1 == zeros(4) assert gamma0 * gamma0 == eye(4) * minkowski_tensor[0, 0] assert gamma2 * gamma2 != eye(4) * minkowski_tensor[0, 0] assert gamma2 * gamma2 == eye(4) * minkowski_tensor[2, 2] assert mgamma(5, True) == \ mgamma(0, True)*mgamma(1, True)*mgamma(2, True)*mgamma(3, True)*I def test_mdft(): with warns_deprecated_sympy(): assert mdft(1) == Matrix([[1]]) with warns_deprecated_sympy(): assert mdft(2) == 1/sqrt(2)*Matrix([[1,1],[1,-1]]) with warns_deprecated_sympy(): assert mdft(4) == Matrix([[S.Half, S.Half, S.Half, S.Half], [S.Half, -I/2, Rational(-1,2), I/2], [S.Half, Rational(-1,2), S.Half, Rational(-1,2)], [S.Half, I/2, Rational(-1,2), -I/2]]) sympy-sympy-1.9/sympy/physics/tests/test_pring.py000066400000000000000000000020601412543434000224560ustar00rootroot00000000000000from sympy.physics.pring import wavefunction, energy from sympy import pi, integrate, sqrt, exp, simplify, I from sympy.abc import m, x, r from sympy.physics.quantum.constants import hbar def test_wavefunction(): Psi = { 0: (1/sqrt(2 * pi)), 1: (1/sqrt(2 * pi)) * exp(I * x), 2: (1/sqrt(2 * pi)) * exp(2 * I * x), 3: (1/sqrt(2 * pi)) * exp(3 * I * x) } for n in Psi: assert simplify(wavefunction(n, x) - Psi[n]) == 0 def test_norm(n=1): # Maximum "n" which is tested: for i in range(n + 1): assert integrate( wavefunction(i, x) * wavefunction(-i, x), (x, 0, 2 * pi)) == 1 def test_orthogonality(n=1): # Maximum "n" which is tested: for i in range(n + 1): for j in range(i+1, n+1): assert integrate( wavefunction(i, x) * wavefunction(j, x), (x, 0, 2 * pi)) == 0 def test_energy(n=1): # Maximum "n" which is tested: for i in range(n+1): assert simplify( energy(i, m, r) - ((i**2 * hbar**2) / (2 * m * r**2))) == 0 sympy-sympy-1.9/sympy/physics/tests/test_qho_1d.py000066400000000000000000000027651412543434000225260ustar00rootroot00000000000000from sympy import exp, integrate, oo, Rational, pi, S, simplify, sqrt, Symbol from sympy.abc import omega, m, x from sympy.physics.qho_1d import psi_n, E_n, coherent_state from sympy.physics.quantum.constants import hbar nu = m * omega / hbar def test_wavefunction(): Psi = { 0: (nu/pi)**Rational(1, 4) * exp(-nu * x**2 /2), 1: (nu/pi)**Rational(1, 4) * sqrt(2*nu) * x * exp(-nu * x**2 /2), 2: (nu/pi)**Rational(1, 4) * (2 * nu * x**2 - 1)/sqrt(2) * exp(-nu * x**2 /2), 3: (nu/pi)**Rational(1, 4) * sqrt(nu/3) * (2 * nu * x**3 - 3 * x) * exp(-nu * x**2 /2) } for n in Psi: assert simplify(psi_n(n, x, m, omega) - Psi[n]) == 0 def test_norm(n=1): # Maximum "n" which is tested: for i in range(n + 1): assert integrate(psi_n(i, x, 1, 1)**2, (x, -oo, oo)) == 1 def test_orthogonality(n=1): # Maximum "n" which is tested: for i in range(n + 1): for j in range(i + 1, n + 1): assert integrate( psi_n(i, x, 1, 1)*psi_n(j, x, 1, 1), (x, -oo, oo)) == 0 def test_energies(n=1): # Maximum "n" which is tested: for i in range(n + 1): assert E_n(i, omega) == hbar * omega * (i + S.Half) def test_coherent_state(n=10): # Maximum "n" which is tested: # test whether coherent state is the eigenstate of annihilation operator alpha = Symbol("alpha") for i in range(n + 1): assert simplify(sqrt(n + 1) * coherent_state(n + 1, alpha)) == simplify(alpha * coherent_state(n, alpha)) sympy-sympy-1.9/sympy/physics/tests/test_secondquant.py000066400000000000000000001361471412543434000237010ustar00rootroot00000000000000from sympy.physics.secondquant import ( Dagger, Bd, VarBosonicBasis, BBra, B, BKet, FixedBosonicBasis, matrix_rep, apply_operators, InnerProduct, Commutator, KroneckerDelta, AnnihilateBoson, CreateBoson, BosonicOperator, F, Fd, FKet, BosonState, CreateFermion, AnnihilateFermion, evaluate_deltas, AntiSymmetricTensor, contraction, NO, wicks, PermutationOperator, simplify_index_permutations, _sort_anticommuting_fermions, _get_ordered_dummies, substitute_dummies, FockStateBosonKet, ContractionAppliesOnlyToFermions ) from sympy import (Dummy, expand, Function, I, S, simplify, sqrt, Sum, Symbol, symbols, srepr, Rational) from sympy.testing.pytest import slow, raises from sympy.printing.latex import latex def test_PermutationOperator(): p, q, r, s = symbols('p,q,r,s') f, g, h, i = map(Function, 'fghi') P = PermutationOperator assert P(p, q).get_permuted(f(p)*g(q)) == -f(q)*g(p) assert P(p, q).get_permuted(f(p, q)) == -f(q, p) assert P(p, q).get_permuted(f(p)) == f(p) expr = (f(p)*g(q)*h(r)*i(s) - f(q)*g(p)*h(r)*i(s) - f(p)*g(q)*h(s)*i(r) + f(q)*g(p)*h(s)*i(r)) perms = [P(p, q), P(r, s)] assert (simplify_index_permutations(expr, perms) == P(p, q)*P(r, s)*f(p)*g(q)*h(r)*i(s)) assert latex(P(p, q)) == 'P(pq)' def test_index_permutations_with_dummies(): a, b, c, d = symbols('a b c d') p, q, r, s = symbols('p q r s', cls=Dummy) f, g = map(Function, 'fg') P = PermutationOperator # No dummy substitution necessary expr = f(a, b, p, q) - f(b, a, p, q) assert simplify_index_permutations( expr, [P(a, b)]) == P(a, b)*f(a, b, p, q) # Cases where dummy substitution is needed expected = P(a, b)*substitute_dummies(f(a, b, p, q)) expr = f(a, b, p, q) - f(b, a, q, p) result = simplify_index_permutations(expr, [P(a, b)]) assert expected == substitute_dummies(result) expr = f(a, b, q, p) - f(b, a, p, q) result = simplify_index_permutations(expr, [P(a, b)]) assert expected == substitute_dummies(result) # A case where nothing can be done expr = f(a, b, q, p) - g(b, a, p, q) result = simplify_index_permutations(expr, [P(a, b)]) assert expr == result def test_dagger(): i, j, n, m = symbols('i,j,n,m') assert Dagger(1) == 1 assert Dagger(1.0) == 1.0 assert Dagger(2*I) == -2*I assert Dagger(S.Half*I/3.0) == I*Rational(-1, 2)/3.0 assert Dagger(BKet([n])) == BBra([n]) assert Dagger(B(0)) == Bd(0) assert Dagger(Bd(0)) == B(0) assert Dagger(B(n)) == Bd(n) assert Dagger(Bd(n)) == B(n) assert Dagger(B(0) + B(1)) == Bd(0) + Bd(1) assert Dagger(n*m) == Dagger(n)*Dagger(m) # n, m commute assert Dagger(B(n)*B(m)) == Bd(m)*Bd(n) assert Dagger(B(n)**10) == Dagger(B(n))**10 assert Dagger('a') == Dagger(Symbol('a')) assert Dagger(Dagger('a')) == Symbol('a') def test_operator(): i, j = symbols('i,j') o = BosonicOperator(i) assert o.state == i assert o.is_symbolic o = BosonicOperator(1) assert o.state == 1 assert not o.is_symbolic def test_create(): i, j, n, m = symbols('i,j,n,m') o = Bd(i) assert latex(o) == "{b^\\dagger_{i}}" assert isinstance(o, CreateBoson) o = o.subs(i, j) assert o.atoms(Symbol) == {j} o = Bd(0) assert o.apply_operator(BKet([n])) == sqrt(n + 1)*BKet([n + 1]) o = Bd(n) assert o.apply_operator(BKet([n])) == o*BKet([n]) def test_annihilate(): i, j, n, m = symbols('i,j,n,m') o = B(i) assert latex(o) == "b_{i}" assert isinstance(o, AnnihilateBoson) o = o.subs(i, j) assert o.atoms(Symbol) == {j} o = B(0) assert o.apply_operator(BKet([n])) == sqrt(n)*BKet([n - 1]) o = B(n) assert o.apply_operator(BKet([n])) == o*BKet([n]) def test_basic_state(): i, j, n, m = symbols('i,j,n,m') s = BosonState([0, 1, 2, 3, 4]) assert len(s) == 5 assert s.args[0] == tuple(range(5)) assert s.up(0) == BosonState([1, 1, 2, 3, 4]) assert s.down(4) == BosonState([0, 1, 2, 3, 3]) for i in range(5): assert s.up(i).down(i) == s assert s.down(0) == 0 for i in range(5): assert s[i] == i s = BosonState([n, m]) assert s.down(0) == BosonState([n - 1, m]) assert s.up(0) == BosonState([n + 1, m]) def test_basic_apply(): n = symbols("n") e = B(0)*BKet([n]) assert apply_operators(e) == sqrt(n)*BKet([n - 1]) e = Bd(0)*BKet([n]) assert apply_operators(e) == sqrt(n + 1)*BKet([n + 1]) def test_complex_apply(): n, m = symbols("n,m") o = Bd(0)*B(0)*Bd(1)*B(0) e = apply_operators(o*BKet([n, m])) answer = sqrt(n)*sqrt(m + 1)*(-1 + n)*BKet([-1 + n, 1 + m]) assert expand(e) == expand(answer) def test_number_operator(): n = symbols("n") o = Bd(0)*B(0) e = apply_operators(o*BKet([n])) assert e == n*BKet([n]) def test_inner_product(): i, j, k, l = symbols('i,j,k,l') s1 = BBra([0]) s2 = BKet([1]) assert InnerProduct(s1, Dagger(s1)) == 1 assert InnerProduct(s1, s2) == 0 s1 = BBra([i, j]) s2 = BKet([k, l]) r = InnerProduct(s1, s2) assert r == KroneckerDelta(i, k)*KroneckerDelta(j, l) def test_symbolic_matrix_elements(): n, m = symbols('n,m') s1 = BBra([n]) s2 = BKet([m]) o = B(0) e = apply_operators(s1*o*s2) assert e == sqrt(m)*KroneckerDelta(n, m - 1) def test_matrix_elements(): b = VarBosonicBasis(5) o = B(0) m = matrix_rep(o, b) for i in range(4): assert m[i, i + 1] == sqrt(i + 1) o = Bd(0) m = matrix_rep(o, b) for i in range(4): assert m[i + 1, i] == sqrt(i + 1) def test_fixed_bosonic_basis(): b = FixedBosonicBasis(2, 2) # assert b == [FockState((2, 0)), FockState((1, 1)), FockState((0, 2))] state = b.state(1) assert state == FockStateBosonKet((1, 1)) assert b.index(state) == 1 assert b.state(1) == b[1] assert len(b) == 3 assert str(b) == '[FockState((2, 0)), FockState((1, 1)), FockState((0, 2))]' assert repr(b) == '[FockState((2, 0)), FockState((1, 1)), FockState((0, 2))]' assert srepr(b) == '[FockState((2, 0)), FockState((1, 1)), FockState((0, 2))]' @slow def test_sho(): n, m = symbols('n,m') h_n = Bd(n)*B(n)*(n + S.Half) H = Sum(h_n, (n, 0, 5)) o = H.doit(deep=False) b = FixedBosonicBasis(2, 6) m = matrix_rep(o, b) # We need to double check these energy values to make sure that they # are correct and have the proper degeneracies! diag = [1, 2, 3, 3, 4, 5, 4, 5, 6, 7, 5, 6, 7, 8, 9, 6, 7, 8, 9, 10, 11] for i in range(len(diag)): assert diag[i] == m[i, i] def test_commutation(): n, m = symbols("n,m", above_fermi=True) c = Commutator(B(0), Bd(0)) assert c == 1 c = Commutator(Bd(0), B(0)) assert c == -1 c = Commutator(B(n), Bd(0)) assert c == KroneckerDelta(n, 0) c = Commutator(B(0), B(0)) assert c == 0 c = Commutator(B(0), Bd(0)) e = simplify(apply_operators(c*BKet([n]))) assert e == BKet([n]) c = Commutator(B(0), B(1)) e = simplify(apply_operators(c*BKet([n, m]))) assert e == 0 c = Commutator(F(m), Fd(m)) assert c == +1 - 2*NO(Fd(m)*F(m)) c = Commutator(Fd(m), F(m)) assert c.expand() == -1 + 2*NO(Fd(m)*F(m)) C = Commutator X, Y, Z = symbols('X,Y,Z', commutative=False) assert C(C(X, Y), Z) != 0 assert C(C(X, Z), Y) != 0 assert C(Y, C(X, Z)) != 0 i, j, k, l = symbols('i,j,k,l', below_fermi=True) a, b, c, d = symbols('a,b,c,d', above_fermi=True) p, q, r, s = symbols('p,q,r,s') D = KroneckerDelta assert C(Fd(a), F(i)) == -2*NO(F(i)*Fd(a)) assert C(Fd(j), NO(Fd(a)*F(i))).doit(wicks=True) == -D(j, i)*Fd(a) assert C(Fd(a)*F(i), Fd(b)*F(j)).doit(wicks=True) == 0 c1 = Commutator(F(a), Fd(a)) assert Commutator.eval(c1, c1) == 0 c = Commutator(Fd(a)*F(i),Fd(b)*F(j)) assert latex(c) == r'\left[{a^\dagger_{a}} a_{i},{a^\dagger_{b}} a_{j}\right]' assert repr(c) == 'Commutator(CreateFermion(a)*AnnihilateFermion(i),CreateFermion(b)*AnnihilateFermion(j))' assert str(c) == '[CreateFermion(a)*AnnihilateFermion(i),CreateFermion(b)*AnnihilateFermion(j)]' def test_create_f(): i, j, n, m = symbols('i,j,n,m') o = Fd(i) assert isinstance(o, CreateFermion) o = o.subs(i, j) assert o.atoms(Symbol) == {j} o = Fd(1) assert o.apply_operator(FKet([n])) == FKet([1, n]) assert o.apply_operator(FKet([n])) == -FKet([n, 1]) o = Fd(n) assert o.apply_operator(FKet([])) == FKet([n]) vacuum = FKet([], fermi_level=4) assert vacuum == FKet([], fermi_level=4) i, j, k, l = symbols('i,j,k,l', below_fermi=True) a, b, c, d = symbols('a,b,c,d', above_fermi=True) p, q, r, s = symbols('p,q,r,s') assert Fd(i).apply_operator(FKet([i, j, k], 4)) == FKet([j, k], 4) assert Fd(a).apply_operator(FKet([i, b, k], 4)) == FKet([a, i, b, k], 4) assert Dagger(B(p)).apply_operator(q) == q*CreateBoson(p) assert repr(Fd(p)) == 'CreateFermion(p)' assert srepr(Fd(p)) == "CreateFermion(Symbol('p'))" assert latex(Fd(p)) == r'{a^\dagger_{p}}' def test_annihilate_f(): i, j, n, m = symbols('i,j,n,m') o = F(i) assert isinstance(o, AnnihilateFermion) o = o.subs(i, j) assert o.atoms(Symbol) == {j} o = F(1) assert o.apply_operator(FKet([1, n])) == FKet([n]) assert o.apply_operator(FKet([n, 1])) == -FKet([n]) o = F(n) assert o.apply_operator(FKet([n])) == FKet([]) i, j, k, l = symbols('i,j,k,l', below_fermi=True) a, b, c, d = symbols('a,b,c,d', above_fermi=True) p, q, r, s = symbols('p,q,r,s') assert F(i).apply_operator(FKet([i, j, k], 4)) == 0 assert F(a).apply_operator(FKet([i, b, k], 4)) == 0 assert F(l).apply_operator(FKet([i, j, k], 3)) == 0 assert F(l).apply_operator(FKet([i, j, k], 4)) == FKet([l, i, j, k], 4) assert str(F(p)) == 'f(p)' assert repr(F(p)) == 'AnnihilateFermion(p)' assert srepr(F(p)) == "AnnihilateFermion(Symbol('p'))" assert latex(F(p)) == 'a_{p}' def test_create_b(): i, j, n, m = symbols('i,j,n,m') o = Bd(i) assert isinstance(o, CreateBoson) o = o.subs(i, j) assert o.atoms(Symbol) == {j} o = Bd(0) assert o.apply_operator(BKet([n])) == sqrt(n + 1)*BKet([n + 1]) o = Bd(n) assert o.apply_operator(BKet([n])) == o*BKet([n]) def test_annihilate_b(): i, j, n, m = symbols('i,j,n,m') o = B(i) assert isinstance(o, AnnihilateBoson) o = o.subs(i, j) assert o.atoms(Symbol) == {j} o = B(0) def test_wicks(): p, q, r, s = symbols('p,q,r,s', above_fermi=True) # Testing for particles only str = F(p)*Fd(q) assert wicks(str) == NO(F(p)*Fd(q)) + KroneckerDelta(p, q) str = Fd(p)*F(q) assert wicks(str) == NO(Fd(p)*F(q)) str = F(p)*Fd(q)*F(r)*Fd(s) nstr = wicks(str) fasit = NO( KroneckerDelta(p, q)*KroneckerDelta(r, s) + KroneckerDelta(p, q)*AnnihilateFermion(r)*CreateFermion(s) + KroneckerDelta(r, s)*AnnihilateFermion(p)*CreateFermion(q) - KroneckerDelta(p, s)*AnnihilateFermion(r)*CreateFermion(q) - AnnihilateFermion(p)*AnnihilateFermion(r)*CreateFermion(q)*CreateFermion(s)) assert nstr == fasit assert (p*q*nstr).expand() == wicks(p*q*str) assert (nstr*p*q*2).expand() == wicks(str*p*q*2) # Testing CC equations particles and holes i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) p, q, r, s = symbols('p q r s', cls=Dummy) assert (wicks(F(a)*NO(F(i)*F(j))*Fd(b)) == NO(F(a)*F(i)*F(j)*Fd(b)) + KroneckerDelta(a, b)*NO(F(i)*F(j))) assert (wicks(F(a)*NO(F(i)*F(j)*F(k))*Fd(b)) == NO(F(a)*F(i)*F(j)*F(k)*Fd(b)) - KroneckerDelta(a, b)*NO(F(i)*F(j)*F(k))) expr = wicks(Fd(i)*NO(Fd(j)*F(k))*F(l)) assert (expr == -KroneckerDelta(i, k)*NO(Fd(j)*F(l)) - KroneckerDelta(j, l)*NO(Fd(i)*F(k)) - KroneckerDelta(i, k)*KroneckerDelta(j, l) + KroneckerDelta(i, l)*NO(Fd(j)*F(k)) + NO(Fd(i)*Fd(j)*F(k)*F(l))) expr = wicks(F(a)*NO(F(b)*Fd(c))*Fd(d)) assert (expr == -KroneckerDelta(a, c)*NO(F(b)*Fd(d)) - KroneckerDelta(b, d)*NO(F(a)*Fd(c)) - KroneckerDelta(a, c)*KroneckerDelta(b, d) + KroneckerDelta(a, d)*NO(F(b)*Fd(c)) + NO(F(a)*F(b)*Fd(c)*Fd(d))) def test_NO(): i, j, k, l = symbols('i j k l', below_fermi=True) a, b, c, d = symbols('a b c d', above_fermi=True) p, q, r, s = symbols('p q r s', cls=Dummy) assert (NO(Fd(p)*F(q) + Fd(a)*F(b)) == NO(Fd(p)*F(q)) + NO(Fd(a)*F(b))) assert (NO(Fd(i)*NO(F(j)*Fd(a))) == NO(Fd(i)*F(j)*Fd(a))) assert NO(1) == 1 assert NO(i) == i assert (NO(Fd(a)*Fd(b)*(F(c) + F(d))) == NO(Fd(a)*Fd(b)*F(c)) + NO(Fd(a)*Fd(b)*F(d))) assert NO(Fd(a)*F(b))._remove_brackets() == Fd(a)*F(b) assert NO(F(j)*Fd(i))._remove_brackets() == F(j)*Fd(i) assert (NO(Fd(p)*F(q)).subs(Fd(p), Fd(a) + Fd(i)) == NO(Fd(a)*F(q)) + NO(Fd(i)*F(q))) assert (NO(Fd(p)*F(q)).subs(F(q), F(a) + F(i)) == NO(Fd(p)*F(a)) + NO(Fd(p)*F(i))) expr = NO(Fd(p)*F(q))._remove_brackets() assert wicks(expr) == NO(expr) assert NO(Fd(a)*F(b)) == - NO(F(b)*Fd(a)) no = NO(Fd(a)*F(i)*F(b)*Fd(j)) l1 = [ ind for ind in no.iter_q_creators() ] assert l1 == [0, 1] l2 = [ ind for ind in no.iter_q_annihilators() ] assert l2 == [3, 2] no = NO(Fd(a)*Fd(i)) assert no.has_q_creators == 1 assert no.has_q_annihilators == -1 assert str(no) == ':CreateFermion(a)*CreateFermion(i):' assert repr(no) == 'NO(CreateFermion(a)*CreateFermion(i))' assert latex(no) == r'\left\{{a^\dagger_{a}} {a^\dagger_{i}}\right\}' raises(NotImplementedError, lambda: NO(Bd(p)*F(q))) def test_sorting(): i, j = symbols('i,j', below_fermi=True) a, b = symbols('a,b', above_fermi=True) p, q = symbols('p,q') # p, q assert _sort_anticommuting_fermions([Fd(p), F(q)]) == ([Fd(p), F(q)], 0) assert _sort_anticommuting_fermions([F(p), Fd(q)]) == ([Fd(q), F(p)], 1) # i, p assert _sort_anticommuting_fermions([F(p), Fd(i)]) == ([F(p), Fd(i)], 0) assert _sort_anticommuting_fermions([Fd(i), F(p)]) == ([F(p), Fd(i)], 1) assert _sort_anticommuting_fermions([Fd(p), Fd(i)]) == ([Fd(p), Fd(i)], 0) assert _sort_anticommuting_fermions([Fd(i), Fd(p)]) == ([Fd(p), Fd(i)], 1) assert _sort_anticommuting_fermions([F(p), F(i)]) == ([F(i), F(p)], 1) assert _sort_anticommuting_fermions([F(i), F(p)]) == ([F(i), F(p)], 0) assert _sort_anticommuting_fermions([Fd(p), F(i)]) == ([F(i), Fd(p)], 1) assert _sort_anticommuting_fermions([F(i), Fd(p)]) == ([F(i), Fd(p)], 0) # a, p assert _sort_anticommuting_fermions([F(p), Fd(a)]) == ([Fd(a), F(p)], 1) assert _sort_anticommuting_fermions([Fd(a), F(p)]) == ([Fd(a), F(p)], 0) assert _sort_anticommuting_fermions([Fd(p), Fd(a)]) == ([Fd(a), Fd(p)], 1) assert _sort_anticommuting_fermions([Fd(a), Fd(p)]) == ([Fd(a), Fd(p)], 0) assert _sort_anticommuting_fermions([F(p), F(a)]) == ([F(p), F(a)], 0) assert _sort_anticommuting_fermions([F(a), F(p)]) == ([F(p), F(a)], 1) assert _sort_anticommuting_fermions([Fd(p), F(a)]) == ([Fd(p), F(a)], 0) assert _sort_anticommuting_fermions([F(a), Fd(p)]) == ([Fd(p), F(a)], 1) # i, a assert _sort_anticommuting_fermions([F(i), Fd(j)]) == ([F(i), Fd(j)], 0) assert _sort_anticommuting_fermions([Fd(j), F(i)]) == ([F(i), Fd(j)], 1) assert _sort_anticommuting_fermions([Fd(a), Fd(i)]) == ([Fd(a), Fd(i)], 0) assert _sort_anticommuting_fermions([Fd(i), Fd(a)]) == ([Fd(a), Fd(i)], 1) assert _sort_anticommuting_fermions([F(a), F(i)]) == ([F(i), F(a)], 1) assert _sort_anticommuting_fermions([F(i), F(a)]) == ([F(i), F(a)], 0) def test_contraction(): i, j, k, l = symbols('i,j,k,l', below_fermi=True) a, b, c, d = symbols('a,b,c,d', above_fermi=True) p, q, r, s = symbols('p,q,r,s') assert contraction(Fd(i), F(j)) == KroneckerDelta(i, j) assert contraction(F(a), Fd(b)) == KroneckerDelta(a, b) assert contraction(F(a), Fd(i)) == 0 assert contraction(Fd(a), F(i)) == 0 assert contraction(F(i), Fd(a)) == 0 assert contraction(Fd(i), F(a)) == 0 assert contraction(Fd(i), F(p)) == KroneckerDelta(i, p) restr = evaluate_deltas(contraction(Fd(p), F(q))) assert restr.is_only_below_fermi restr = evaluate_deltas(contraction(F(p), Fd(q))) assert restr.is_only_above_fermi raises(ContractionAppliesOnlyToFermions, lambda: contraction(B(a), Fd(b))) def test_evaluate_deltas(): i, j, k = symbols('i,j,k') r = KroneckerDelta(i, j) * KroneckerDelta(j, k) assert evaluate_deltas(r) == KroneckerDelta(i, k) r = KroneckerDelta(i, 0) * KroneckerDelta(j, k) assert evaluate_deltas(r) == KroneckerDelta(i, 0) * KroneckerDelta(j, k) r = KroneckerDelta(1, j) * KroneckerDelta(j, k) assert evaluate_deltas(r) == KroneckerDelta(1, k) r = KroneckerDelta(j, 2) * KroneckerDelta(k, j) assert evaluate_deltas(r) == KroneckerDelta(2, k) r = KroneckerDelta(i, 0) * KroneckerDelta(i, j) * KroneckerDelta(j, 1) assert evaluate_deltas(r) == 0 r = (KroneckerDelta(0, i) * KroneckerDelta(0, j) * KroneckerDelta(1, j) * KroneckerDelta(1, j)) assert evaluate_deltas(r) == 0 def test_Tensors(): i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) p, q, r, s = symbols('p q r s') AT = AntiSymmetricTensor assert AT('t', (a, b), (i, j)) == -AT('t', (b, a), (i, j)) assert AT('t', (a, b), (i, j)) == AT('t', (b, a), (j, i)) assert AT('t', (a, b), (i, j)) == -AT('t', (a, b), (j, i)) assert AT('t', (a, a), (i, j)) == 0 assert AT('t', (a, b), (i, i)) == 0 assert AT('t', (a, b, c), (i, j)) == -AT('t', (b, a, c), (i, j)) assert AT('t', (a, b, c), (i, j, k)) == AT('t', (b, a, c), (i, k, j)) tabij = AT('t', (a, b), (i, j)) assert tabij.has(a) assert tabij.has(b) assert tabij.has(i) assert tabij.has(j) assert tabij.subs(b, c) == AT('t', (a, c), (i, j)) assert (2*tabij).subs(i, c) == 2*AT('t', (a, b), (c, j)) assert tabij.symbol == Symbol('t') assert latex(tabij) == '{t^{ab}_{ij}}' assert str(tabij) == 't((_a, _b),(_i, _j))' assert AT('t', (a, a), (i, j)).subs(a, b) == AT('t', (b, b), (i, j)) assert AT('t', (a, i), (a, j)).subs(a, b) == AT('t', (b, i), (b, j)) def test_fully_contracted(): i, j, k, l = symbols('i j k l', below_fermi=True) a, b, c, d = symbols('a b c d', above_fermi=True) p, q, r, s = symbols('p q r s', cls=Dummy) Fock = (AntiSymmetricTensor('f', (p,), (q,))* NO(Fd(p)*F(q))) V = (AntiSymmetricTensor('v', (p, q), (r, s))* NO(Fd(p)*Fd(q)*F(s)*F(r)))/4 Fai = wicks(NO(Fd(i)*F(a))*Fock, keep_only_fully_contracted=True, simplify_kronecker_deltas=True) assert Fai == AntiSymmetricTensor('f', (a,), (i,)) Vabij = wicks(NO(Fd(i)*Fd(j)*F(b)*F(a))*V, keep_only_fully_contracted=True, simplify_kronecker_deltas=True) assert Vabij == AntiSymmetricTensor('v', (a, b), (i, j)) def test_substitute_dummies_without_dummies(): i, j = symbols('i,j') assert substitute_dummies(att(i, j) + 2) == att(i, j) + 2 assert substitute_dummies(att(i, j) + 1) == att(i, j) + 1 def test_substitute_dummies_NO_operator(): i, j = symbols('i j', cls=Dummy) assert substitute_dummies(att(i, j)*NO(Fd(i)*F(j)) - att(j, i)*NO(Fd(j)*F(i))) == 0 def test_substitute_dummies_SQ_operator(): i, j = symbols('i j', cls=Dummy) assert substitute_dummies(att(i, j)*Fd(i)*F(j) - att(j, i)*Fd(j)*F(i)) == 0 def test_substitute_dummies_new_indices(): i, j = symbols('i j', below_fermi=True, cls=Dummy) a, b = symbols('a b', above_fermi=True, cls=Dummy) p, q = symbols('p q', cls=Dummy) f = Function('f') assert substitute_dummies(f(i, a, p) - f(j, b, q), new_indices=True) == 0 def test_substitute_dummies_substitution_order(): i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) f = Function('f') from sympy.utilities.iterables import variations for permut in variations([i, j, k, l], 4): assert substitute_dummies(f(*permut) - f(i, j, k, l)) == 0 def test_dummy_order_inner_outer_lines_VT1T1T1(): ii = symbols('i', below_fermi=True) aa = symbols('a', above_fermi=True) k, l = symbols('k l', below_fermi=True, cls=Dummy) c, d = symbols('c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies # Coupled-Cluster T1 terms with V*T1*T1*T1 # t^{a}_{k} t^{c}_{i} t^{d}_{l} v^{lk}_{dc} exprs = [ # permut v and t <=> swapping internal lines, equivalent # irrespective of symmetries in v v(k, l, c, d)*t(c, ii)*t(d, l)*t(aa, k), v(l, k, c, d)*t(c, ii)*t(d, k)*t(aa, l), v(k, l, d, c)*t(d, ii)*t(c, l)*t(aa, k), v(l, k, d, c)*t(d, ii)*t(c, k)*t(aa, l), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_dummy_order_inner_outer_lines_VT1T1T1T1(): ii, jj = symbols('i j', below_fermi=True) aa, bb = symbols('a b', above_fermi=True) k, l = symbols('k l', below_fermi=True, cls=Dummy) c, d = symbols('c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies # Coupled-Cluster T2 terms with V*T1*T1*T1*T1 exprs = [ # permut t <=> swapping external lines, not equivalent # except if v has certain symmetries. v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), v(k, l, c, d)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), v(k, l, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), v(k, l, c, d)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permut v <=> swapping external lines, not equivalent # except if v has certain symmetries. # # Note that in contrast to above, these permutations have identical # dummy order. That is because the proximity to external indices # has higher influence on the canonical dummy ordering than the # position of a dummy on the factors. In fact, the terms here are # similar in structure as the result of the dummy substitutions above. v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), v(l, k, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), v(k, l, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), v(l, k, d, c)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), ] for permut in exprs[1:]: assert dums(exprs[0]) == dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permut t and v <=> swapping internal lines, equivalent. # Canonical dummy order is different, and a consistent # substitution reveals the equivalence. v(k, l, c, d)*t(c, ii)*t(d, jj)*t(aa, k)*t(bb, l), v(k, l, d, c)*t(c, jj)*t(d, ii)*t(aa, k)*t(bb, l), v(l, k, c, d)*t(c, ii)*t(d, jj)*t(bb, k)*t(aa, l), v(l, k, d, c)*t(c, jj)*t(d, ii)*t(bb, k)*t(aa, l), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_get_subNO(): p, q, r = symbols('p,q,r') assert NO(F(p)*F(q)*F(r)).get_subNO(1) == NO(F(p)*F(r)) assert NO(F(p)*F(q)*F(r)).get_subNO(0) == NO(F(q)*F(r)) assert NO(F(p)*F(q)*F(r)).get_subNO(2) == NO(F(p)*F(q)) def test_equivalent_internal_lines_VT1T1(): i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies exprs = [ # permute v. Different dummy order. Not equivalent. v(i, j, a, b)*t(a, i)*t(b, j), v(j, i, a, b)*t(a, i)*t(b, j), v(i, j, b, a)*t(a, i)*t(b, j), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute v. Different dummy order. Equivalent v(i, j, a, b)*t(a, i)*t(b, j), v(j, i, b, a)*t(a, i)*t(b, j), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ # permute t. Same dummy order, not equivalent. v(i, j, a, b)*t(a, i)*t(b, j), v(i, j, a, b)*t(b, i)*t(a, j), ] for permut in exprs[1:]: assert dums(exprs[0]) == dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute v and t. Different dummy order, equivalent v(i, j, a, b)*t(a, i)*t(b, j), v(j, i, a, b)*t(a, j)*t(b, i), v(i, j, b, a)*t(b, i)*t(a, j), v(j, i, b, a)*t(b, j)*t(a, i), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_equivalent_internal_lines_VT2conjT2(): # this diagram requires special handling in TCE i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations v = Function('v') t = Function('t') dums = _get_ordered_dummies # v(abcd)t(abij)t(ijcd) template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(i, j, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(j, i, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) # v(abcd)t(abij)t(jicd) template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(j, i, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(i, j, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) def test_equivalent_internal_lines_VT2conjT2_ambiguous_order(): # These diagrams invokes _determine_ambiguous() because the # dummies can not be ordered unambiguously by the key alone i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations v = Function('v') t = Function('t') dums = _get_ordered_dummies # v(abcd)t(abij)t(cdij) template = v(p1, p2, p3, p4)*t(p1, p2, i, j)*t(p3, p4, i, j) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) template = v(p1, p2, p3, p4)*t(p1, p2, j, i)*t(p3, p4, i, j) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert dums(base) != dums(expr) assert substitute_dummies(expr) == substitute_dummies(base) def test_equivalent_internal_lines_VT2(): i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies exprs = [ # permute v. Same dummy order, not equivalent. # # This test show that the dummy order may not be sensitive to all # index permutations. The following expressions have identical # structure as the resulting terms from of the dummy substitutions # in the test above. Here, all expressions have the same dummy # order, so they cannot be simplified by means of dummy # substitution. In order to simplify further, it is necessary to # exploit symmetries in the objects, for instance if t or v is # antisymmetric. v(i, j, a, b)*t(a, b, i, j), v(j, i, a, b)*t(a, b, i, j), v(i, j, b, a)*t(a, b, i, j), v(j, i, b, a)*t(a, b, i, j), ] for permut in exprs[1:]: assert dums(exprs[0]) == dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute t. v(i, j, a, b)*t(a, b, i, j), v(i, j, a, b)*t(b, a, i, j), v(i, j, a, b)*t(a, b, j, i), v(i, j, a, b)*t(b, a, j, i), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute v and t. Relabelling of dummies should be equivalent. v(i, j, a, b)*t(a, b, i, j), v(j, i, a, b)*t(a, b, j, i), v(i, j, b, a)*t(b, a, i, j), v(j, i, b, a)*t(b, a, j, i), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_internal_external_VT2T2(): ii, jj = symbols('i j', below_fermi=True) aa, bb = symbols('a b', above_fermi=True) k, l = symbols('k l', below_fermi=True, cls=Dummy) c, d = symbols('c d', above_fermi=True, cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies exprs = [ v(k, l, c, d)*t(aa, c, ii, k)*t(bb, d, jj, l), v(l, k, c, d)*t(aa, c, ii, l)*t(bb, d, jj, k), v(k, l, d, c)*t(aa, d, ii, k)*t(bb, c, jj, l), v(l, k, d, c)*t(aa, d, ii, l)*t(bb, c, jj, k), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ v(k, l, c, d)*t(aa, c, ii, k)*t(d, bb, jj, l), v(l, k, c, d)*t(aa, c, ii, l)*t(d, bb, jj, k), v(k, l, d, c)*t(aa, d, ii, k)*t(c, bb, jj, l), v(l, k, d, c)*t(aa, d, ii, l)*t(c, bb, jj, k), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ v(k, l, c, d)*t(c, aa, ii, k)*t(bb, d, jj, l), v(l, k, c, d)*t(c, aa, ii, l)*t(bb, d, jj, k), v(k, l, d, c)*t(d, aa, ii, k)*t(bb, c, jj, l), v(l, k, d, c)*t(d, aa, ii, l)*t(bb, c, jj, k), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_internal_external_pqrs(): ii, jj = symbols('i j') aa, bb = symbols('a b') k, l = symbols('k l', cls=Dummy) c, d = symbols('c d', cls=Dummy) v = Function('v') t = Function('t') dums = _get_ordered_dummies exprs = [ v(k, l, c, d)*t(aa, c, ii, k)*t(bb, d, jj, l), v(l, k, c, d)*t(aa, c, ii, l)*t(bb, d, jj, k), v(k, l, d, c)*t(aa, d, ii, k)*t(bb, c, jj, l), v(l, k, d, c)*t(aa, d, ii, l)*t(bb, c, jj, k), ] for permut in exprs[1:]: assert dums(exprs[0]) != dums(permut) assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_dummy_order_well_defined(): aa, bb = symbols('a b', above_fermi=True) k, l, m = symbols('k l m', below_fermi=True, cls=Dummy) c, d = symbols('c d', above_fermi=True, cls=Dummy) p, q = symbols('p q', cls=Dummy) A = Function('A') B = Function('B') C = Function('C') dums = _get_ordered_dummies # We go through all key components in the order of increasing priority, # and consider only fully orderable expressions. Non-orderable expressions # are tested elsewhere. # pos in first factor determines sort order assert dums(A(k, l)*B(l, k)) == [k, l] assert dums(A(l, k)*B(l, k)) == [l, k] assert dums(A(k, l)*B(k, l)) == [k, l] assert dums(A(l, k)*B(k, l)) == [l, k] # factors involving the index assert dums(A(k, l)*B(l, m)*C(k, m)) == [l, k, m] assert dums(A(k, l)*B(l, m)*C(m, k)) == [l, k, m] assert dums(A(l, k)*B(l, m)*C(k, m)) == [l, k, m] assert dums(A(l, k)*B(l, m)*C(m, k)) == [l, k, m] assert dums(A(k, l)*B(m, l)*C(k, m)) == [l, k, m] assert dums(A(k, l)*B(m, l)*C(m, k)) == [l, k, m] assert dums(A(l, k)*B(m, l)*C(k, m)) == [l, k, m] assert dums(A(l, k)*B(m, l)*C(m, k)) == [l, k, m] # same, but with factor order determined by non-dummies assert dums(A(k, aa, l)*A(l, bb, m)*A(bb, k, m)) == [l, k, m] assert dums(A(k, aa, l)*A(l, bb, m)*A(bb, m, k)) == [l, k, m] assert dums(A(k, aa, l)*A(m, bb, l)*A(bb, k, m)) == [l, k, m] assert dums(A(k, aa, l)*A(m, bb, l)*A(bb, m, k)) == [l, k, m] assert dums(A(l, aa, k)*A(l, bb, m)*A(bb, k, m)) == [l, k, m] assert dums(A(l, aa, k)*A(l, bb, m)*A(bb, m, k)) == [l, k, m] assert dums(A(l, aa, k)*A(m, bb, l)*A(bb, k, m)) == [l, k, m] assert dums(A(l, aa, k)*A(m, bb, l)*A(bb, m, k)) == [l, k, m] # index range assert dums(A(p, c, k)*B(p, c, k)) == [k, c, p] assert dums(A(p, k, c)*B(p, c, k)) == [k, c, p] assert dums(A(c, k, p)*B(p, c, k)) == [k, c, p] assert dums(A(c, p, k)*B(p, c, k)) == [k, c, p] assert dums(A(k, c, p)*B(p, c, k)) == [k, c, p] assert dums(A(k, p, c)*B(p, c, k)) == [k, c, p] assert dums(B(p, c, k)*A(p, c, k)) == [k, c, p] assert dums(B(p, k, c)*A(p, c, k)) == [k, c, p] assert dums(B(c, k, p)*A(p, c, k)) == [k, c, p] assert dums(B(c, p, k)*A(p, c, k)) == [k, c, p] assert dums(B(k, c, p)*A(p, c, k)) == [k, c, p] assert dums(B(k, p, c)*A(p, c, k)) == [k, c, p] def test_dummy_order_ambiguous(): aa, bb = symbols('a b', above_fermi=True) i, j, k, l, m = symbols('i j k l m', below_fermi=True, cls=Dummy) a, b, c, d, e = symbols('a b c d e', above_fermi=True, cls=Dummy) p, q = symbols('p q', cls=Dummy) p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) p5, p6, p7, p8 = symbols('p5 p6 p7 p8', above_fermi=True, cls=Dummy) h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) h5, h6, h7, h8 = symbols('h5 h6 h7 h8', below_fermi=True, cls=Dummy) A = Function('A') B = Function('B') from sympy.utilities.iterables import variations # A*A*A*A*B -- ordering of p5 and p4 is used to figure out the rest template = A(p1, p2)*A(p4, p1)*A(p2, p3)*A(p3, p5)*B(p5, p4) permutator = variations([a, b, c, d, e], 5) base = template.subs(zip([p1, p2, p3, p4, p5], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4, p5], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) # A*A*A*A*A -- an arbitrary index is assigned and the rest are figured out template = A(p1, p2)*A(p4, p1)*A(p2, p3)*A(p3, p5)*A(p5, p4) permutator = variations([a, b, c, d, e], 5) base = template.subs(zip([p1, p2, p3, p4, p5], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4, p5], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) # A*A*A -- ordering of p5 and p4 is used to figure out the rest template = A(p1, p2, p4, p1)*A(p2, p3, p3, p5)*A(p5, p4) permutator = variations([a, b, c, d, e], 5) base = template.subs(zip([p1, p2, p3, p4, p5], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4, p5], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) def atv(*args): return AntiSymmetricTensor('v', args[:2], args[2:] ) def att(*args): if len(args) == 4: return AntiSymmetricTensor('t', args[:2], args[2:] ) elif len(args) == 2: return AntiSymmetricTensor('t', (args[0],), (args[1],)) def test_dummy_order_inner_outer_lines_VT1T1T1_AT(): ii = symbols('i', below_fermi=True) aa = symbols('a', above_fermi=True) k, l = symbols('k l', below_fermi=True, cls=Dummy) c, d = symbols('c d', above_fermi=True, cls=Dummy) # Coupled-Cluster T1 terms with V*T1*T1*T1 # t^{a}_{k} t^{c}_{i} t^{d}_{l} v^{lk}_{dc} exprs = [ # permut v and t <=> swapping internal lines, equivalent # irrespective of symmetries in v atv(k, l, c, d)*att(c, ii)*att(d, l)*att(aa, k), atv(l, k, c, d)*att(c, ii)*att(d, k)*att(aa, l), atv(k, l, d, c)*att(d, ii)*att(c, l)*att(aa, k), atv(l, k, d, c)*att(d, ii)*att(c, k)*att(aa, l), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_dummy_order_inner_outer_lines_VT1T1T1T1_AT(): ii, jj = symbols('i j', below_fermi=True) aa, bb = symbols('a b', above_fermi=True) k, l = symbols('k l', below_fermi=True, cls=Dummy) c, d = symbols('c d', above_fermi=True, cls=Dummy) # Coupled-Cluster T2 terms with V*T1*T1*T1*T1 # non-equivalent substitutions (change of sign) exprs = [ # permut t <=> swapping external lines atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(aa, k)*att(bb, l), atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(bb, k)*att(aa, l), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == -substitute_dummies(permut) # equivalent substitutions exprs = [ atv(k, l, c, d)*att(c, ii)*att(d, jj)*att(aa, k)*att(bb, l), # permut t <=> swapping external lines atv(k, l, c, d)*att(c, jj)*att(d, ii)*att(bb, k)*att(aa, l), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_equivalent_internal_lines_VT1T1_AT(): i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) exprs = [ # permute v. Different dummy order. Not equivalent. atv(i, j, a, b)*att(a, i)*att(b, j), atv(j, i, a, b)*att(a, i)*att(b, j), atv(i, j, b, a)*att(a, i)*att(b, j), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute v. Different dummy order. Equivalent atv(i, j, a, b)*att(a, i)*att(b, j), atv(j, i, b, a)*att(a, i)*att(b, j), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ # permute t. Same dummy order, not equivalent. atv(i, j, a, b)*att(a, i)*att(b, j), atv(i, j, a, b)*att(b, i)*att(a, j), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute v and t. Different dummy order, equivalent atv(i, j, a, b)*att(a, i)*att(b, j), atv(j, i, a, b)*att(a, j)*att(b, i), atv(i, j, b, a)*att(b, i)*att(a, j), atv(j, i, b, a)*att(b, j)*att(a, i), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_equivalent_internal_lines_VT2conjT2_AT(): # this diagram requires special handling in TCE i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations # atv(abcd)att(abij)att(ijcd) template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(i, j, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(j, i, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) # atv(abcd)att(abij)att(jicd) template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(j, i, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(i, j, p3, p4) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) def test_equivalent_internal_lines_VT2conjT2_ambiguous_order_AT(): # These diagrams invokes _determine_ambiguous() because the # dummies can not be ordered unambiguously by the key alone i, j, k, l, m, n = symbols('i j k l m n', below_fermi=True, cls=Dummy) a, b, c, d, e, f = symbols('a b c d e f', above_fermi=True, cls=Dummy) p1, p2, p3, p4 = symbols('p1 p2 p3 p4', above_fermi=True, cls=Dummy) h1, h2, h3, h4 = symbols('h1 h2 h3 h4', below_fermi=True, cls=Dummy) from sympy.utilities.iterables import variations # atv(abcd)att(abij)att(cdij) template = atv(p1, p2, p3, p4)*att(p1, p2, i, j)*att(p3, p4, i, j) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) template = atv(p1, p2, p3, p4)*att(p1, p2, j, i)*att(p3, p4, i, j) permutator = variations([a, b, c, d], 4) base = template.subs(zip([p1, p2, p3, p4], next(permutator))) for permut in permutator: subslist = zip([p1, p2, p3, p4], permut) expr = template.subs(subslist) assert substitute_dummies(expr) == substitute_dummies(base) def test_equivalent_internal_lines_VT2_AT(): i, j, k, l = symbols('i j k l', below_fermi=True, cls=Dummy) a, b, c, d = symbols('a b c d', above_fermi=True, cls=Dummy) exprs = [ # permute v. Same dummy order, not equivalent. atv(i, j, a, b)*att(a, b, i, j), atv(j, i, a, b)*att(a, b, i, j), atv(i, j, b, a)*att(a, b, i, j), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute t. atv(i, j, a, b)*att(a, b, i, j), atv(i, j, a, b)*att(b, a, i, j), atv(i, j, a, b)*att(a, b, j, i), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) != substitute_dummies(permut) exprs = [ # permute v and t. Relabelling of dummies should be equivalent. atv(i, j, a, b)*att(a, b, i, j), atv(j, i, a, b)*att(a, b, j, i), atv(i, j, b, a)*att(b, a, i, j), atv(j, i, b, a)*att(b, a, j, i), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_internal_external_VT2T2_AT(): ii, jj = symbols('i j', below_fermi=True) aa, bb = symbols('a b', above_fermi=True) k, l = symbols('k l', below_fermi=True, cls=Dummy) c, d = symbols('c d', above_fermi=True, cls=Dummy) exprs = [ atv(k, l, c, d)*att(aa, c, ii, k)*att(bb, d, jj, l), atv(l, k, c, d)*att(aa, c, ii, l)*att(bb, d, jj, k), atv(k, l, d, c)*att(aa, d, ii, k)*att(bb, c, jj, l), atv(l, k, d, c)*att(aa, d, ii, l)*att(bb, c, jj, k), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ atv(k, l, c, d)*att(aa, c, ii, k)*att(d, bb, jj, l), atv(l, k, c, d)*att(aa, c, ii, l)*att(d, bb, jj, k), atv(k, l, d, c)*att(aa, d, ii, k)*att(c, bb, jj, l), atv(l, k, d, c)*att(aa, d, ii, l)*att(c, bb, jj, k), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) exprs = [ atv(k, l, c, d)*att(c, aa, ii, k)*att(bb, d, jj, l), atv(l, k, c, d)*att(c, aa, ii, l)*att(bb, d, jj, k), atv(k, l, d, c)*att(d, aa, ii, k)*att(bb, c, jj, l), atv(l, k, d, c)*att(d, aa, ii, l)*att(bb, c, jj, k), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_internal_external_pqrs_AT(): ii, jj = symbols('i j') aa, bb = symbols('a b') k, l = symbols('k l', cls=Dummy) c, d = symbols('c d', cls=Dummy) exprs = [ atv(k, l, c, d)*att(aa, c, ii, k)*att(bb, d, jj, l), atv(l, k, c, d)*att(aa, c, ii, l)*att(bb, d, jj, k), atv(k, l, d, c)*att(aa, d, ii, k)*att(bb, c, jj, l), atv(l, k, d, c)*att(aa, d, ii, l)*att(bb, c, jj, k), ] for permut in exprs[1:]: assert substitute_dummies(exprs[0]) == substitute_dummies(permut) def test_issue_19661(): a = Symbol('0') assert latex(Commutator(Bd(a)**2, B(a)) ) == '- \\left[b_{0},{b^\\dagger_{0}}^{2}\\right]' def test_canonical_ordering_AntiSymmetricTensor(): v = symbols("v") c, d = symbols(('c','d'), above_fermi=True, cls=Dummy) k, l = symbols(('k','l'), below_fermi=True, cls=Dummy) # formerly, the left gave either the left or the right assert AntiSymmetricTensor(v, (k, l), (d, c) ) == -AntiSymmetricTensor(v, (l, k), (d, c)) sympy-sympy-1.9/sympy/physics/tests/test_sho.py000066400000000000000000000012431412543434000221320ustar00rootroot00000000000000from sympy.core import symbols, Rational, Function, diff from sympy.physics.sho import R_nl, E_nl from sympy import simplify def test_sho_R_nl(): omega, r = symbols('omega r') l = symbols('l', integer=True) u = Function('u') # check that it obeys the Schrodinger equation for n in range(5): schreq = ( -diff(u(r), r, 2)/2 + ((l*(l + 1))/(2*r**2) + omega**2*r**2/2 - E_nl(n, l, omega))*u(r) ) result = schreq.subs(u(r), r*R_nl(n, l, omega/2, r)) assert simplify(result.doit()) == 0 def test_energy(): n, l, hw = symbols('n l hw') assert simplify(E_nl(n, l, hw) - (2*n + l + Rational(3, 2))*hw) == 0 sympy-sympy-1.9/sympy/physics/units/000077500000000000000000000000001412543434000177305ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/units/__init__.py000066400000000000000000000273531412543434000220530ustar00rootroot00000000000000# isort:skip_file """ Dimensional analysis and unit systems. This module defines dimension/unit systems and physical quantities. It is based on a group-theoretical construction where dimensions are represented as vectors (coefficients being the exponents), and units are defined as a dimension to which we added a scale. Quantities are built from a factor and a unit, and are the basic objects that one will use when doing computations. All objects except systems and prefixes can be used in sympy expressions. Note that as part of a CAS, various objects do not combine automatically under operations. Details about the implementation can be found in the documentation, and we will not repeat all the explanations we gave there concerning our approach. Ideas about future developments can be found on the `Github wiki `_, and you should consult this page if you are willing to help. Useful functions: - ``find_unit``: easily lookup pre-defined units. - ``convert_to(expr, newunit)``: converts an expression into the same expression expressed in another unit. """ from .dimensions import Dimension, DimensionSystem from .unitsystem import UnitSystem from .util import convert_to from .quantities import Quantity from .definitions.dimension_definitions import ( amount_of_substance, acceleration, action, capacitance, charge, conductance, current, energy, force, frequency, impedance, inductance, length, luminous_intensity, magnetic_density, magnetic_flux, mass, momentum, power, pressure, temperature, time, velocity, voltage, volume ) Unit = Quantity speed = velocity luminosity = luminous_intensity magnetic_flux_density = magnetic_density amount = amount_of_substance from .prefixes import ( # 10-power based: yotta, zetta, exa, peta, tera, giga, mega, kilo, hecto, deca, deci, centi, milli, micro, nano, pico, femto, atto, zepto, yocto, # 2-power based: kibi, mebi, gibi, tebi, pebi, exbi, ) from .definitions import ( percent, percents, permille, rad, radian, radians, deg, degree, degrees, sr, steradian, steradians, mil, angular_mil, angular_mils, m, meter, meters, kg, kilogram, kilograms, s, second, seconds, A, ampere, amperes, K, kelvin, kelvins, mol, mole, moles, cd, candela, candelas, g, gram, grams, mg, milligram, milligrams, ug, microgram, micrograms, newton, newtons, N, joule, joules, J, watt, watts, W, pascal, pascals, Pa, pa, hertz, hz, Hz, coulomb, coulombs, C, volt, volts, v, V, ohm, ohms, siemens, S, mho, mhos, farad, farads, F, henry, henrys, H, tesla, teslas, T, weber, webers, Wb, wb, optical_power, dioptre, D, lux, lx, katal, kat, gray, Gy, becquerel, Bq, km, kilometer, kilometers, dm, decimeter, decimeters, cm, centimeter, centimeters, mm, millimeter, millimeters, um, micrometer, micrometers, micron, microns, nm, nanometer, nanometers, pm, picometer, picometers, ft, foot, feet, inch, inches, yd, yard, yards, mi, mile, miles, nmi, nautical_mile, nautical_miles, l, liter, liters, dl, deciliter, deciliters, cl, centiliter, centiliters, ml, milliliter, milliliters, ms, millisecond, milliseconds, us, microsecond, microseconds, ns, nanosecond, nanoseconds, ps, picosecond, picoseconds, minute, minutes, h, hour, hours, day, days, anomalistic_year, anomalistic_years, sidereal_year, sidereal_years, tropical_year, tropical_years, common_year, common_years, julian_year, julian_years, draconic_year, draconic_years, gaussian_year, gaussian_years, full_moon_cycle, full_moon_cycles, year, years, G, gravitational_constant, c, speed_of_light, elementary_charge, hbar, planck, eV, electronvolt, electronvolts, avogadro_number, avogadro, avogadro_constant, boltzmann, boltzmann_constant, stefan, stefan_boltzmann_constant, R, molar_gas_constant, faraday_constant, josephson_constant, von_klitzing_constant, amu, amus, atomic_mass_unit, atomic_mass_constant, gee, gees, acceleration_due_to_gravity, u0, magnetic_constant, vacuum_permeability, e0, electric_constant, vacuum_permittivity, Z0, vacuum_impedance, coulomb_constant, electric_force_constant, atmosphere, atmospheres, atm, kPa, bar, bars, pound, pounds, psi, dHg0, mmHg, torr, mmu, mmus, milli_mass_unit, quart, quarts, ly, lightyear, lightyears, au, astronomical_unit, astronomical_units, planck_mass, planck_time, planck_temperature, planck_length, planck_charge, planck_area, planck_volume, planck_momentum, planck_energy, planck_force, planck_power, planck_density, planck_energy_density, planck_intensity, planck_angular_frequency, planck_pressure, planck_current, planck_voltage, planck_impedance, planck_acceleration, bit, bits, byte, kibibyte, kibibytes, mebibyte, mebibytes, gibibyte, gibibytes, tebibyte, tebibytes, pebibyte, pebibytes, exbibyte, exbibytes, ) from .systems import ( mks, mksa, si ) def find_unit(quantity, unit_system="SI"): """ Return a list of matching units or dimension names. - If ``quantity`` is a string -- units/dimensions containing the string `quantity`. - If ``quantity`` is a unit or dimension -- units having matching base units or dimensions. Examples ======== >>> from sympy.physics import units as u >>> u.find_unit('charge') ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] >>> u.find_unit(u.charge) ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] >>> u.find_unit("ampere") ['ampere', 'amperes'] >>> u.find_unit('volt') ['volt', 'volts', 'electronvolt', 'electronvolts', 'planck_voltage'] >>> u.find_unit(u.inch**3)[:5] ['l', 'cl', 'dl', 'ml', 'liter'] """ unit_system = UnitSystem.get_unit_system(unit_system) import sympy.physics.units as u rv = [] if isinstance(quantity, str): rv = [i for i in dir(u) if quantity in i and isinstance(getattr(u, i), Quantity)] dim = getattr(u, quantity) if isinstance(dim, Dimension): rv.extend(find_unit(dim)) else: for i in sorted(dir(u)): other = getattr(u, i) if not isinstance(other, Quantity): continue if isinstance(quantity, Quantity): if quantity.dimension == other.dimension: rv.append(str(i)) elif isinstance(quantity, Dimension): if other.dimension == quantity: rv.append(str(i)) elif other.dimension == Dimension(unit_system.get_dimensional_expr(quantity)): rv.append(str(i)) return sorted(set(rv), key=lambda x: (len(x), x)) # NOTE: the old units module had additional variables: # 'density', 'illuminance', 'resistance'. # They were not dimensions, but units (old Unit class). __all__ = [ 'Dimension', 'DimensionSystem', 'UnitSystem', 'convert_to', 'Quantity', 'amount_of_substance', 'acceleration', 'action', 'capacitance', 'charge', 'conductance', 'current', 'energy', 'force', 'frequency', 'impedance', 'inductance', 'length', 'luminous_intensity', 'magnetic_density', 'magnetic_flux', 'mass', 'momentum', 'power', 'pressure', 'temperature', 'time', 'velocity', 'voltage', 'volume', 'Unit', 'speed', 'luminosity', 'magnetic_flux_density', 'amount', 'yotta', 'zetta', 'exa', 'peta', 'tera', 'giga', 'mega', 'kilo', 'hecto', 'deca', 'deci', 'centi', 'milli', 'micro', 'nano', 'pico', 'femto', 'atto', 'zepto', 'yocto', 'kibi', 'mebi', 'gibi', 'tebi', 'pebi', 'exbi', 'percent', 'percents', 'permille', 'rad', 'radian', 'radians', 'deg', 'degree', 'degrees', 'sr', 'steradian', 'steradians', 'mil', 'angular_mil', 'angular_mils', 'm', 'meter', 'meters', 'kg', 'kilogram', 'kilograms', 's', 'second', 'seconds', 'A', 'ampere', 'amperes', 'K', 'kelvin', 'kelvins', 'mol', 'mole', 'moles', 'cd', 'candela', 'candelas', 'g', 'gram', 'grams', 'mg', 'milligram', 'milligrams', 'ug', 'microgram', 'micrograms', 'newton', 'newtons', 'N', 'joule', 'joules', 'J', 'watt', 'watts', 'W', 'pascal', 'pascals', 'Pa', 'pa', 'hertz', 'hz', 'Hz', 'coulomb', 'coulombs', 'C', 'volt', 'volts', 'v', 'V', 'ohm', 'ohms', 'siemens', 'S', 'mho', 'mhos', 'farad', 'farads', 'F', 'henry', 'henrys', 'H', 'tesla', 'teslas', 'T', 'weber', 'webers', 'Wb', 'wb', 'optical_power', 'dioptre', 'D', 'lux', 'lx', 'katal', 'kat', 'gray', 'Gy', 'becquerel', 'Bq', 'km', 'kilometer', 'kilometers', 'dm', 'decimeter', 'decimeters', 'cm', 'centimeter', 'centimeters', 'mm', 'millimeter', 'millimeters', 'um', 'micrometer', 'micrometers', 'micron', 'microns', 'nm', 'nanometer', 'nanometers', 'pm', 'picometer', 'picometers', 'ft', 'foot', 'feet', 'inch', 'inches', 'yd', 'yard', 'yards', 'mi', 'mile', 'miles', 'nmi', 'nautical_mile', 'nautical_miles', 'l', 'liter', 'liters', 'dl', 'deciliter', 'deciliters', 'cl', 'centiliter', 'centiliters', 'ml', 'milliliter', 'milliliters', 'ms', 'millisecond', 'milliseconds', 'us', 'microsecond', 'microseconds', 'ns', 'nanosecond', 'nanoseconds', 'ps', 'picosecond', 'picoseconds', 'minute', 'minutes', 'h', 'hour', 'hours', 'day', 'days', 'anomalistic_year', 'anomalistic_years', 'sidereal_year', 'sidereal_years', 'tropical_year', 'tropical_years', 'common_year', 'common_years', 'julian_year', 'julian_years', 'draconic_year', 'draconic_years', 'gaussian_year', 'gaussian_years', 'full_moon_cycle', 'full_moon_cycles', 'year', 'years', 'G', 'gravitational_constant', 'c', 'speed_of_light', 'elementary_charge', 'hbar', 'planck', 'eV', 'electronvolt', 'electronvolts', 'avogadro_number', 'avogadro', 'avogadro_constant', 'boltzmann', 'boltzmann_constant', 'stefan', 'stefan_boltzmann_constant', 'R', 'molar_gas_constant', 'faraday_constant', 'josephson_constant', 'von_klitzing_constant', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant', 'gee', 'gees', 'acceleration_due_to_gravity', 'u0', 'magnetic_constant', 'vacuum_permeability', 'e0', 'electric_constant', 'vacuum_permittivity', 'Z0', 'vacuum_impedance', 'coulomb_constant', 'electric_force_constant', 'atmosphere', 'atmospheres', 'atm', 'kPa', 'bar', 'bars', 'pound', 'pounds', 'psi', 'dHg0', 'mmHg', 'torr', 'mmu', 'mmus', 'milli_mass_unit', 'quart', 'quarts', 'ly', 'lightyear', 'lightyears', 'au', 'astronomical_unit', 'astronomical_units', 'planck_mass', 'planck_time', 'planck_temperature', 'planck_length', 'planck_charge', 'planck_area', 'planck_volume', 'planck_momentum', 'planck_energy', 'planck_force', 'planck_power', 'planck_density', 'planck_energy_density', 'planck_intensity', 'planck_angular_frequency', 'planck_pressure', 'planck_current', 'planck_voltage', 'planck_impedance', 'planck_acceleration', 'bit', 'bits', 'byte', 'kibibyte', 'kibibytes', 'mebibyte', 'mebibytes', 'gibibyte', 'gibibytes', 'tebibyte', 'tebibytes', 'pebibyte', 'pebibytes', 'exbibyte', 'exbibytes', 'mks', 'mksa', 'si', ] sympy-sympy-1.9/sympy/physics/units/definitions/000077500000000000000000000000001412543434000222435ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/units/definitions/__init__.py000066400000000000000000000160321412543434000243560ustar00rootroot00000000000000from .unit_definitions import ( percent, percents, permille, rad, radian, radians, deg, degree, degrees, sr, steradian, steradians, mil, angular_mil, angular_mils, m, meter, meters, kg, kilogram, kilograms, s, second, seconds, A, ampere, amperes, K, kelvin, kelvins, mol, mole, moles, cd, candela, candelas, g, gram, grams, mg, milligram, milligrams, ug, microgram, micrograms, newton, newtons, N, joule, joules, J, watt, watts, W, pascal, pascals, Pa, pa, hertz, hz, Hz, coulomb, coulombs, C, volt, volts, v, V, ohm, ohms, siemens, S, mho, mhos, farad, farads, F, henry, henrys, H, tesla, teslas, T, weber, webers, Wb, wb, optical_power, dioptre, D, lux, lx, katal, kat, gray, Gy, becquerel, Bq, km, kilometer, kilometers, dm, decimeter, decimeters, cm, centimeter, centimeters, mm, millimeter, millimeters, um, micrometer, micrometers, micron, microns, nm, nanometer, nanometers, pm, picometer, picometers, ft, foot, feet, inch, inches, yd, yard, yards, mi, mile, miles, nmi, nautical_mile, nautical_miles, l, liter, liters, dl, deciliter, deciliters, cl, centiliter, centiliters, ml, milliliter, milliliters, ms, millisecond, milliseconds, us, microsecond, microseconds, ns, nanosecond, nanoseconds, ps, picosecond, picoseconds, minute, minutes, h, hour, hours, day, days, anomalistic_year, anomalistic_years, sidereal_year, sidereal_years, tropical_year, tropical_years, common_year, common_years, julian_year, julian_years, draconic_year, draconic_years, gaussian_year, gaussian_years, full_moon_cycle, full_moon_cycles, year, years, G, gravitational_constant, c, speed_of_light, elementary_charge, hbar, planck, eV, electronvolt, electronvolts, avogadro_number, avogadro, avogadro_constant, boltzmann, boltzmann_constant, stefan, stefan_boltzmann_constant, R, molar_gas_constant, faraday_constant, josephson_constant, von_klitzing_constant, amu, amus, atomic_mass_unit, atomic_mass_constant, gee, gees, acceleration_due_to_gravity, u0, magnetic_constant, vacuum_permeability, e0, electric_constant, vacuum_permittivity, Z0, vacuum_impedance, coulomb_constant, coulombs_constant, electric_force_constant, atmosphere, atmospheres, atm, kPa, kilopascal, bar, bars, pound, pounds, psi, dHg0, mmHg, torr, mmu, mmus, milli_mass_unit, quart, quarts, ly, lightyear, lightyears, au, astronomical_unit, astronomical_units, planck_mass, planck_time, planck_temperature, planck_length, planck_charge, planck_area, planck_volume, planck_momentum, planck_energy, planck_force, planck_power, planck_density, planck_energy_density, planck_intensity, planck_angular_frequency, planck_pressure, planck_current, planck_voltage, planck_impedance, planck_acceleration, bit, bits, byte, kibibyte, kibibytes, mebibyte, mebibytes, gibibyte, gibibytes, tebibyte, tebibytes, pebibyte, pebibytes, exbibyte, exbibytes, curie, rutherford ) __all__ = [ 'percent', 'percents', 'permille', 'rad', 'radian', 'radians', 'deg', 'degree', 'degrees', 'sr', 'steradian', 'steradians', 'mil', 'angular_mil', 'angular_mils', 'm', 'meter', 'meters', 'kg', 'kilogram', 'kilograms', 's', 'second', 'seconds', 'A', 'ampere', 'amperes', 'K', 'kelvin', 'kelvins', 'mol', 'mole', 'moles', 'cd', 'candela', 'candelas', 'g', 'gram', 'grams', 'mg', 'milligram', 'milligrams', 'ug', 'microgram', 'micrograms', 'newton', 'newtons', 'N', 'joule', 'joules', 'J', 'watt', 'watts', 'W', 'pascal', 'pascals', 'Pa', 'pa', 'hertz', 'hz', 'Hz', 'coulomb', 'coulombs', 'C', 'volt', 'volts', 'v', 'V', 'ohm', 'ohms', 'siemens', 'S', 'mho', 'mhos', 'farad', 'farads', 'F', 'henry', 'henrys', 'H', 'tesla', 'teslas', 'T', 'weber', 'webers', 'Wb', 'wb', 'optical_power', 'dioptre', 'D', 'lux', 'lx', 'katal', 'kat', 'gray', 'Gy', 'becquerel', 'Bq', 'km', 'kilometer', 'kilometers', 'dm', 'decimeter', 'decimeters', 'cm', 'centimeter', 'centimeters', 'mm', 'millimeter', 'millimeters', 'um', 'micrometer', 'micrometers', 'micron', 'microns', 'nm', 'nanometer', 'nanometers', 'pm', 'picometer', 'picometers', 'ft', 'foot', 'feet', 'inch', 'inches', 'yd', 'yard', 'yards', 'mi', 'mile', 'miles', 'nmi', 'nautical_mile', 'nautical_miles', 'l', 'liter', 'liters', 'dl', 'deciliter', 'deciliters', 'cl', 'centiliter', 'centiliters', 'ml', 'milliliter', 'milliliters', 'ms', 'millisecond', 'milliseconds', 'us', 'microsecond', 'microseconds', 'ns', 'nanosecond', 'nanoseconds', 'ps', 'picosecond', 'picoseconds', 'minute', 'minutes', 'h', 'hour', 'hours', 'day', 'days', 'anomalistic_year', 'anomalistic_years', 'sidereal_year', 'sidereal_years', 'tropical_year', 'tropical_years', 'common_year', 'common_years', 'julian_year', 'julian_years', 'draconic_year', 'draconic_years', 'gaussian_year', 'gaussian_years', 'full_moon_cycle', 'full_moon_cycles', 'year', 'years', 'G', 'gravitational_constant', 'c', 'speed_of_light', 'elementary_charge', 'hbar', 'planck', 'eV', 'electronvolt', 'electronvolts', 'avogadro_number', 'avogadro', 'avogadro_constant', 'boltzmann', 'boltzmann_constant', 'stefan', 'stefan_boltzmann_constant', 'R', 'molar_gas_constant', 'faraday_constant', 'josephson_constant', 'von_klitzing_constant', 'amu', 'amus', 'atomic_mass_unit', 'atomic_mass_constant', 'gee', 'gees', 'acceleration_due_to_gravity', 'u0', 'magnetic_constant', 'vacuum_permeability', 'e0', 'electric_constant', 'vacuum_permittivity', 'Z0', 'vacuum_impedance', 'coulomb_constant', 'coulombs_constant', 'electric_force_constant', 'atmosphere', 'atmospheres', 'atm', 'kPa', 'kilopascal', 'bar', 'bars', 'pound', 'pounds', 'psi', 'dHg0', 'mmHg', 'torr', 'mmu', 'mmus', 'milli_mass_unit', 'quart', 'quarts', 'ly', 'lightyear', 'lightyears', 'au', 'astronomical_unit', 'astronomical_units', 'planck_mass', 'planck_time', 'planck_temperature', 'planck_length', 'planck_charge', 'planck_area', 'planck_volume', 'planck_momentum', 'planck_energy', 'planck_force', 'planck_power', 'planck_density', 'planck_energy_density', 'planck_intensity', 'planck_angular_frequency', 'planck_pressure', 'planck_current', 'planck_voltage', 'planck_impedance', 'planck_acceleration', 'bit', 'bits', 'byte', 'kibibyte', 'kibibytes', 'mebibyte', 'mebibytes', 'gibibyte', 'gibibytes', 'tebibyte', 'tebibytes', 'pebibyte', 'pebibytes', 'exbibyte', 'exbibytes', 'curie', 'rutherford', ] sympy-sympy-1.9/sympy/physics/units/definitions/dimension_definitions.py000066400000000000000000000032701412543434000271770ustar00rootroot00000000000000from sympy.physics.units import Dimension angle = Dimension(name="angle") # type: Dimension # base dimensions (MKS) length = Dimension(name="length", symbol="L") mass = Dimension(name="mass", symbol="M") time = Dimension(name="time", symbol="T") # base dimensions (MKSA not in MKS) current = Dimension(name='current', symbol='I') # type: Dimension # other base dimensions: temperature = Dimension("temperature", "T") # type: Dimension amount_of_substance = Dimension("amount_of_substance") # type: Dimension luminous_intensity = Dimension("luminous_intensity") # type: Dimension # derived dimensions (MKS) velocity = Dimension(name="velocity") acceleration = Dimension(name="acceleration") momentum = Dimension(name="momentum") force = Dimension(name="force", symbol="F") energy = Dimension(name="energy", symbol="E") power = Dimension(name="power") pressure = Dimension(name="pressure") frequency = Dimension(name="frequency", symbol="f") action = Dimension(name="action", symbol="A") volume = Dimension("volume") # derived dimensions (MKSA not in MKS) voltage = Dimension(name='voltage', symbol='U') # type: Dimension impedance = Dimension(name='impedance', symbol='Z') # type: Dimension conductance = Dimension(name='conductance', symbol='G') # type: Dimension capacitance = Dimension(name='capacitance') # type: Dimension inductance = Dimension(name='inductance') # type: Dimension charge = Dimension(name='charge', symbol='Q') # type: Dimension magnetic_density = Dimension(name='magnetic_density', symbol='B') # type: Dimension magnetic_flux = Dimension(name='magnetic_flux') # type: Dimension # Dimensions in information theory: information = Dimension(name='information') # type: Dimension sympy-sympy-1.9/sympy/physics/units/definitions/unit_definitions.py000066400000000000000000000325771412543434000262050ustar00rootroot00000000000000from sympy.physics.units.definitions.dimension_definitions import current, temperature, amount_of_substance, \ luminous_intensity, angle, charge, voltage, impedance, conductance, capacitance, inductance, magnetic_density, \ magnetic_flux, information from sympy import Rational, pi, S as S_singleton from sympy.physics.units.prefixes import kilo, milli, micro, deci, centi, nano, pico, kibi, mebi, gibi, tebi, pebi, exbi from sympy.physics.units.quantities import Quantity One = S_singleton.One #### UNITS #### # Dimensionless: percent = percents = Quantity("percent", latex_repr=r"\%") percent.set_global_relative_scale_factor(Rational(1, 100), One) permille = Quantity("permille") permille.set_global_relative_scale_factor(Rational(1, 1000), One) # Angular units (dimensionless) rad = radian = radians = Quantity("radian", abbrev="rad") radian.set_global_dimension(angle) deg = degree = degrees = Quantity("degree", abbrev="deg", latex_repr=r"^\circ") degree.set_global_relative_scale_factor(pi/180, radian) sr = steradian = steradians = Quantity("steradian", abbrev="sr") mil = angular_mil = angular_mils = Quantity("angular_mil", abbrev="mil") # Base units: m = meter = meters = Quantity("meter", abbrev="m") # gram; used to define its prefixed units g = gram = grams = Quantity("gram", abbrev="g") # NOTE: the `kilogram` has scale factor 1000. In SI, kg is a base unit, but # nonetheless we are trying to be compatible with the `kilo` prefix. In a # similar manner, people using CGS or gaussian units could argue that the # `centimeter` rather than `meter` is the fundamental unit for length, but the # scale factor of `centimeter` will be kept as 1/100 to be compatible with the # `centi` prefix. The current state of the code assumes SI unit dimensions, in # the future this module will be modified in order to be unit system-neutral # (that is, support all kinds of unit systems). kg = kilogram = kilograms = Quantity("kilogram", abbrev="kg") kg.set_global_relative_scale_factor(kilo, gram) s = second = seconds = Quantity("second", abbrev="s") A = ampere = amperes = Quantity("ampere", abbrev='A') ampere.set_global_dimension(current) K = kelvin = kelvins = Quantity("kelvin", abbrev='K') kelvin.set_global_dimension(temperature) mol = mole = moles = Quantity("mole", abbrev="mol") mole.set_global_dimension(amount_of_substance) cd = candela = candelas = Quantity("candela", abbrev="cd") candela.set_global_dimension(luminous_intensity) mg = milligram = milligrams = Quantity("milligram", abbrev="mg") mg.set_global_relative_scale_factor(milli, gram) ug = microgram = micrograms = Quantity("microgram", abbrev="ug", latex_repr=r"\mu\text{g}") ug.set_global_relative_scale_factor(micro, gram) # derived units newton = newtons = N = Quantity("newton", abbrev="N") joule = joules = J = Quantity("joule", abbrev="J") watt = watts = W = Quantity("watt", abbrev="W") pascal = pascals = Pa = pa = Quantity("pascal", abbrev="Pa") hertz = hz = Hz = Quantity("hertz", abbrev="Hz") # CGS derived units: dyne = Quantity("dyne") dyne.set_global_relative_scale_factor(One/10**5, newton) erg = Quantity("erg") erg.set_global_relative_scale_factor(One/10**7, joule) # MKSA extension to MKS: derived units coulomb = coulombs = C = Quantity("coulomb", abbrev='C') coulomb.set_global_dimension(charge) volt = volts = v = V = Quantity("volt", abbrev='V') volt.set_global_dimension(voltage) ohm = ohms = Quantity("ohm", abbrev='ohm', latex_repr=r"\Omega") ohm.set_global_dimension(impedance) siemens = S = mho = mhos = Quantity("siemens", abbrev='S') siemens.set_global_dimension(conductance) farad = farads = F = Quantity("farad", abbrev='F') farad.set_global_dimension(capacitance) henry = henrys = H = Quantity("henry", abbrev='H') henry.set_global_dimension(inductance) tesla = teslas = T = Quantity("tesla", abbrev='T') tesla.set_global_dimension(magnetic_density) weber = webers = Wb = wb = Quantity("weber", abbrev='Wb') weber.set_global_dimension(magnetic_flux) # CGS units for electromagnetic quantities: statampere = Quantity("statampere") statcoulomb = statC = franklin = Quantity("statcoulomb", abbrev="statC") statvolt = Quantity("statvolt") gauss = Quantity("gauss") maxwell = Quantity("maxwell") debye = Quantity("debye") oersted = Quantity("oersted") # Other derived units: optical_power = dioptre = diopter = D = Quantity("dioptre") lux = lx = Quantity("lux", abbrev="lx") # katal is the SI unit of catalytic activity katal = kat = Quantity("katal", abbrev="kat") # gray is the SI unit of absorbed dose gray = Gy = Quantity("gray") # becquerel is the SI unit of radioactivity becquerel = Bq = Quantity("becquerel", abbrev="Bq") # Common length units km = kilometer = kilometers = Quantity("kilometer", abbrev="km") km.set_global_relative_scale_factor(kilo, meter) dm = decimeter = decimeters = Quantity("decimeter", abbrev="dm") dm.set_global_relative_scale_factor(deci, meter) cm = centimeter = centimeters = Quantity("centimeter", abbrev="cm") cm.set_global_relative_scale_factor(centi, meter) mm = millimeter = millimeters = Quantity("millimeter", abbrev="mm") mm.set_global_relative_scale_factor(milli, meter) um = micrometer = micrometers = micron = microns = \ Quantity("micrometer", abbrev="um", latex_repr=r'\mu\text{m}') um.set_global_relative_scale_factor(micro, meter) nm = nanometer = nanometers = Quantity("nanometer", abbrev="nm") nm.set_global_relative_scale_factor(nano, meter) pm = picometer = picometers = Quantity("picometer", abbrev="pm") pm.set_global_relative_scale_factor(pico, meter) ft = foot = feet = Quantity("foot", abbrev="ft") ft.set_global_relative_scale_factor(Rational(3048, 10000), meter) inch = inches = Quantity("inch") inch.set_global_relative_scale_factor(Rational(1, 12), foot) yd = yard = yards = Quantity("yard", abbrev="yd") yd.set_global_relative_scale_factor(3, feet) mi = mile = miles = Quantity("mile") mi.set_global_relative_scale_factor(5280, feet) nmi = nautical_mile = nautical_miles = Quantity("nautical_mile") nmi.set_global_relative_scale_factor(6076, feet) # Common volume and area units l = liter = liters = Quantity("liter") dl = deciliter = deciliters = Quantity("deciliter") dl.set_global_relative_scale_factor(Rational(1, 10), liter) cl = centiliter = centiliters = Quantity("centiliter") cl.set_global_relative_scale_factor(Rational(1, 100), liter) ml = milliliter = milliliters = Quantity("milliliter") ml.set_global_relative_scale_factor(Rational(1, 1000), liter) # Common time units ms = millisecond = milliseconds = Quantity("millisecond", abbrev="ms") millisecond.set_global_relative_scale_factor(milli, second) us = microsecond = microseconds = Quantity("microsecond", abbrev="us", latex_repr=r'\mu\text{s}') microsecond.set_global_relative_scale_factor(micro, second) ns = nanosecond = nanoseconds = Quantity("nanosecond", abbrev="ns") nanosecond.set_global_relative_scale_factor(nano, second) ps = picosecond = picoseconds = Quantity("picosecond", abbrev="ps") picosecond.set_global_relative_scale_factor(pico, second) minute = minutes = Quantity("minute") minute.set_global_relative_scale_factor(60, second) h = hour = hours = Quantity("hour") hour.set_global_relative_scale_factor(60, minute) day = days = Quantity("day") day.set_global_relative_scale_factor(24, hour) anomalistic_year = anomalistic_years = Quantity("anomalistic_year") anomalistic_year.set_global_relative_scale_factor(365.259636, day) sidereal_year = sidereal_years = Quantity("sidereal_year") sidereal_year.set_global_relative_scale_factor(31558149.540, seconds) tropical_year = tropical_years = Quantity("tropical_year") tropical_year.set_global_relative_scale_factor(365.24219, day) common_year = common_years = Quantity("common_year") common_year.set_global_relative_scale_factor(365, day) julian_year = julian_years = Quantity("julian_year") julian_year.set_global_relative_scale_factor((365 + One/4), day) draconic_year = draconic_years = Quantity("draconic_year") draconic_year.set_global_relative_scale_factor(346.62, day) gaussian_year = gaussian_years = Quantity("gaussian_year") gaussian_year.set_global_relative_scale_factor(365.2568983, day) full_moon_cycle = full_moon_cycles = Quantity("full_moon_cycle") full_moon_cycle.set_global_relative_scale_factor(411.78443029, day) year = years = tropical_year #### CONSTANTS #### # Newton constant G = gravitational_constant = Quantity("gravitational_constant", abbrev="G") # speed of light c = speed_of_light = Quantity("speed_of_light", abbrev="c") # elementary charge elementary_charge = Quantity("elementary_charge", abbrev="e") # Planck constant planck = Quantity("planck", abbrev="h") # Reduced Planck constant hbar = Quantity("hbar", abbrev="hbar") # Electronvolt eV = electronvolt = electronvolts = Quantity("electronvolt", abbrev="eV") # Avogadro number avogadro_number = Quantity("avogadro_number") # Avogadro constant avogadro = avogadro_constant = Quantity("avogadro_constant") # Boltzmann constant boltzmann = boltzmann_constant = Quantity("boltzmann_constant") # Stefan-Boltzmann constant stefan = stefan_boltzmann_constant = Quantity("stefan_boltzmann_constant") # Atomic mass amu = amus = atomic_mass_unit = atomic_mass_constant = Quantity("atomic_mass_constant") # Molar gas constant R = molar_gas_constant = Quantity("molar_gas_constant", abbrev="R") # Faraday constant faraday_constant = Quantity("faraday_constant") # Josephson constant josephson_constant = Quantity("josephson_constant", abbrev="K_j") # Von Klitzing constant von_klitzing_constant = Quantity("von_klitzing_constant", abbrev="R_k") # Acceleration due to gravity (on the Earth surface) gee = gees = acceleration_due_to_gravity = Quantity("acceleration_due_to_gravity", abbrev="g") # magnetic constant: u0 = magnetic_constant = vacuum_permeability = Quantity("magnetic_constant") # electric constat: e0 = electric_constant = vacuum_permittivity = Quantity("vacuum_permittivity") # vacuum impedance: Z0 = vacuum_impedance = Quantity("vacuum_impedance", abbrev='Z_0', latex_repr=r'Z_{0}') # Coulomb's constant: coulomb_constant = coulombs_constant = electric_force_constant = \ Quantity("coulomb_constant", abbrev="k_e") atmosphere = atmospheres = atm = Quantity("atmosphere", abbrev="atm") kPa = kilopascal = Quantity("kilopascal", abbrev="kPa") kilopascal.set_global_relative_scale_factor(kilo, Pa) bar = bars = Quantity("bar", abbrev="bar") pound = pounds = Quantity("pound") # exact psi = Quantity("psi") dHg0 = 13.5951 # approx value at 0 C mmHg = torr = Quantity("mmHg") atmosphere.set_global_relative_scale_factor(101325, pascal) bar.set_global_relative_scale_factor(100, kPa) pound.set_global_relative_scale_factor(Rational(45359237, 100000000), kg) mmu = mmus = milli_mass_unit = Quantity("milli_mass_unit") quart = quarts = Quantity("quart") # Other convenient units and magnitudes ly = lightyear = lightyears = Quantity("lightyear", abbrev="ly") au = astronomical_unit = astronomical_units = Quantity("astronomical_unit", abbrev="AU") # Fundamental Planck units: planck_mass = Quantity("planck_mass", abbrev="m_P", latex_repr=r'm_\text{P}') planck_time = Quantity("planck_time", abbrev="t_P", latex_repr=r't_\text{P}') planck_temperature = Quantity("planck_temperature", abbrev="T_P", latex_repr=r'T_\text{P}') planck_length = Quantity("planck_length", abbrev="l_P", latex_repr=r'l_\text{P}') planck_charge = Quantity("planck_charge", abbrev="q_P", latex_repr=r'q_\text{P}') # Derived Planck units: planck_area = Quantity("planck_area") planck_volume = Quantity("planck_volume") planck_momentum = Quantity("planck_momentum") planck_energy = Quantity("planck_energy", abbrev="E_P", latex_repr=r'E_\text{P}') planck_force = Quantity("planck_force", abbrev="F_P", latex_repr=r'F_\text{P}') planck_power = Quantity("planck_power", abbrev="P_P", latex_repr=r'P_\text{P}') planck_density = Quantity("planck_density", abbrev="rho_P", latex_repr=r'\rho_\text{P}') planck_energy_density = Quantity("planck_energy_density", abbrev="rho^E_P") planck_intensity = Quantity("planck_intensity", abbrev="I_P", latex_repr=r'I_\text{P}') planck_angular_frequency = Quantity("planck_angular_frequency", abbrev="omega_P", latex_repr=r'\omega_\text{P}') planck_pressure = Quantity("planck_pressure", abbrev="p_P", latex_repr=r'p_\text{P}') planck_current = Quantity("planck_current", abbrev="I_P", latex_repr=r'I_\text{P}') planck_voltage = Quantity("planck_voltage", abbrev="V_P", latex_repr=r'V_\text{P}') planck_impedance = Quantity("planck_impedance", abbrev="Z_P", latex_repr=r'Z_\text{P}') planck_acceleration = Quantity("planck_acceleration", abbrev="a_P", latex_repr=r'a_\text{P}') # Information theory units: bit = bits = Quantity("bit") bit.set_global_dimension(information) byte = bytes = Quantity("byte") kibibyte = kibibytes = Quantity("kibibyte") mebibyte = mebibytes = Quantity("mebibyte") gibibyte = gibibytes = Quantity("gibibyte") tebibyte = tebibytes = Quantity("tebibyte") pebibyte = pebibytes = Quantity("pebibyte") exbibyte = exbibytes = Quantity("exbibyte") byte.set_global_relative_scale_factor(8, bit) kibibyte.set_global_relative_scale_factor(kibi, byte) mebibyte.set_global_relative_scale_factor(mebi, byte) gibibyte.set_global_relative_scale_factor(gibi, byte) tebibyte.set_global_relative_scale_factor(tebi, byte) pebibyte.set_global_relative_scale_factor(pebi, byte) exbibyte.set_global_relative_scale_factor(exbi, byte) # Older units for radioactivity curie = Ci = Quantity("curie", abbrev="Ci") rutherford = Rd = Quantity("rutherford", abbrev="Rd") sympy-sympy-1.9/sympy/physics/units/dimensions.py000066400000000000000000000557751412543434000224750ustar00rootroot00000000000000""" Definition of physical dimensions. Unit systems will be constructed on top of these dimensions. Most of the examples in the doc use MKS system and are presented from the computer point of view: from a human point, adding length to time is not legal in MKS but it is in natural system; for a computer in natural system there is no time dimension (but a velocity dimension instead) - in the basis - so the question of adding time to length has no meaning. """ from typing import Dict as tDict import collections from functools import reduce from sympy import (Integer, Matrix, S, Symbol, sympify, Basic, Tuple, Dict, default_sort_key) from sympy.functions.elementary.trigonometric import TrigonometricFunction from sympy.core.expr import Expr from sympy.core.power import Pow from sympy.utilities.exceptions import SymPyDeprecationWarning class _QuantityMapper: _quantity_scale_factors_global = {} # type: tDict[Expr, Expr] _quantity_dimensional_equivalence_map_global = {} # type: tDict[Expr, Expr] _quantity_dimension_global = {} # type: tDict[Expr, Expr] def __init__(self, *args, **kwargs): self._quantity_dimension_map = {} self._quantity_scale_factors = {} def set_quantity_dimension(self, unit, dimension): from sympy.physics.units import Quantity dimension = sympify(dimension) if not isinstance(dimension, Dimension): if dimension == 1: dimension = Dimension(1) else: raise ValueError("expected dimension or 1") elif isinstance(dimension, Quantity): dimension = self.get_quantity_dimension(dimension) self._quantity_dimension_map[unit] = dimension def set_quantity_scale_factor(self, unit, scale_factor): from sympy.physics.units import Quantity from sympy.physics.units.prefixes import Prefix scale_factor = sympify(scale_factor) # replace all prefixes by their ratio to canonical units: scale_factor = scale_factor.replace( lambda x: isinstance(x, Prefix), lambda x: x.scale_factor ) # replace all quantities by their ratio to canonical units: scale_factor = scale_factor.replace( lambda x: isinstance(x, Quantity), lambda x: self.get_quantity_scale_factor(x) ) self._quantity_scale_factors[unit] = scale_factor def get_quantity_dimension(self, unit): from sympy.physics.units import Quantity # First look-up the local dimension map, then the global one: if unit in self._quantity_dimension_map: return self._quantity_dimension_map[unit] if unit in self._quantity_dimension_global: return self._quantity_dimension_global[unit] if unit in self._quantity_dimensional_equivalence_map_global: dep_unit = self._quantity_dimensional_equivalence_map_global[unit] if isinstance(dep_unit, Quantity): return self.get_quantity_dimension(dep_unit) else: return Dimension(self.get_dimensional_expr(dep_unit)) if isinstance(unit, Quantity): return Dimension(unit.name) else: return Dimension(1) def get_quantity_scale_factor(self, unit): if unit in self._quantity_scale_factors: return self._quantity_scale_factors[unit] if unit in self._quantity_scale_factors_global: mul_factor, other_unit = self._quantity_scale_factors_global[unit] return mul_factor*self.get_quantity_scale_factor(other_unit) return S.One class Dimension(Expr): """ This class represent the dimension of a physical quantities. The ``Dimension`` constructor takes as parameters a name and an optional symbol. For example, in classical mechanics we know that time is different from temperature and dimensions make this difference (but they do not provide any measure of these quantites. >>> from sympy.physics.units import Dimension >>> length = Dimension('length') >>> length Dimension(length) >>> time = Dimension('time') >>> time Dimension(time) Dimensions can be composed using multiplication, division and exponentiation (by a number) to give new dimensions. Addition and subtraction is defined only when the two objects are the same dimension. >>> velocity = length / time >>> velocity Dimension(length/time) It is possible to use a dimension system object to get the dimensionsal dependencies of a dimension, for example the dimension system used by the SI units convention can be used: >>> from sympy.physics.units.systems.si import dimsys_SI >>> dimsys_SI.get_dimensional_dependencies(velocity) {'length': 1, 'time': -1} >>> length + length Dimension(length) >>> l2 = length**2 >>> l2 Dimension(length**2) >>> dimsys_SI.get_dimensional_dependencies(l2) {'length': 2} """ _op_priority = 13.0 # XXX: This doesn't seem to be used anywhere... _dimensional_dependencies = dict() # type: ignore is_commutative = True is_number = False # make sqrt(M**2) --> M is_positive = True is_real = True def __new__(cls, name, symbol=None): if isinstance(name, str): name = Symbol(name) else: name = sympify(name) if not isinstance(name, Expr): raise TypeError("Dimension name needs to be a valid math expression") if isinstance(symbol, str): symbol = Symbol(symbol) elif symbol is not None: assert isinstance(symbol, Symbol) if symbol is not None: obj = Expr.__new__(cls, name, symbol) else: obj = Expr.__new__(cls, name) obj._name = name obj._symbol = symbol return obj @property def name(self): return self._name @property def symbol(self): return self._symbol def __hash__(self): return Expr.__hash__(self) def __eq__(self, other): if isinstance(other, Dimension): return self.name == other.name return False def __str__(self): """ Display the string representation of the dimension. """ if self.symbol is None: return "Dimension(%s)" % (self.name) else: return "Dimension(%s, %s)" % (self.name, self.symbol) def __repr__(self): return self.__str__() def __neg__(self): return self def __add__(self, other): from sympy.physics.units.quantities import Quantity other = sympify(other) if isinstance(other, Basic): if other.has(Quantity): raise TypeError("cannot sum dimension and quantity") if isinstance(other, Dimension) and self == other: return self return super().__add__(other) return self def __radd__(self, other): return self.__add__(other) def __sub__(self, other): # there is no notion of ordering (or magnitude) among dimension, # subtraction is equivalent to addition when the operation is legal return self + other def __rsub__(self, other): # there is no notion of ordering (or magnitude) among dimension, # subtraction is equivalent to addition when the operation is legal return self + other def __pow__(self, other): return self._eval_power(other) def _eval_power(self, other): other = sympify(other) return Dimension(self.name**other) def __mul__(self, other): from sympy.physics.units.quantities import Quantity if isinstance(other, Basic): if other.has(Quantity): raise TypeError("cannot sum dimension and quantity") if isinstance(other, Dimension): return Dimension(self.name*other.name) if not other.free_symbols: # other.is_number cannot be used return self return super().__mul__(other) return self def __rmul__(self, other): return self.__mul__(other) def __truediv__(self, other): return self*Pow(other, -1) def __rtruediv__(self, other): return other * pow(self, -1) @classmethod def _from_dimensional_dependencies(cls, dependencies): return reduce(lambda x, y: x * y, ( Dimension(d)**e for d, e in dependencies.items() ), 1) @classmethod def _get_dimensional_dependencies_for_name(cls, name): from sympy.physics.units.systems.si import dimsys_default SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, feature="do not call from `Dimension` objects.", useinstead="DimensionSystem" ).warn() return dimsys_default.get_dimensional_dependencies(name) @property def is_dimensionless(self): """ Check if the dimension object really has a dimension. A dimension should have at least one component with non-zero power. """ if self.name == 1: return True from sympy.physics.units.systems.si import dimsys_default SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, feature="wrong class", ).warn() dimensional_dependencies=dimsys_default return dimensional_dependencies.get_dimensional_dependencies(self) == {} def has_integer_powers(self, dim_sys): """ Check if the dimension object has only integer powers. All the dimension powers should be integers, but rational powers may appear in intermediate steps. This method may be used to check that the final result is well-defined. """ for dpow in dim_sys.get_dimensional_dependencies(self).values(): if not isinstance(dpow, (int, Integer)): return False return True # Create dimensions according the the base units in MKSA. # For other unit systems, they can be derived by transforming the base # dimensional dependency dictionary. class DimensionSystem(Basic, _QuantityMapper): r""" DimensionSystem represents a coherent set of dimensions. The constructor takes three parameters: - base dimensions; - derived dimensions: these are defined in terms of the base dimensions (for example velocity is defined from the division of length by time); - dependency of dimensions: how the derived dimensions depend on the base dimensions. Optionally either the ``derived_dims`` or the ``dimensional_dependencies`` may be omitted. """ def __new__(cls, base_dims, derived_dims=[], dimensional_dependencies={}, name=None, descr=None): dimensional_dependencies = dict(dimensional_dependencies) if (name is not None) or (descr is not None): SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, useinstead="do not define a `name` or `descr`", ).warn() def parse_dim(dim): if isinstance(dim, str): dim = Dimension(Symbol(dim)) elif isinstance(dim, Dimension): pass elif isinstance(dim, Symbol): dim = Dimension(dim) else: raise TypeError("%s wrong type" % dim) return dim base_dims = [parse_dim(i) for i in base_dims] derived_dims = [parse_dim(i) for i in derived_dims] for dim in base_dims: dim = dim.name if (dim in dimensional_dependencies and (len(dimensional_dependencies[dim]) != 1 or dimensional_dependencies[dim].get(dim, None) != 1)): raise IndexError("Repeated value in base dimensions") dimensional_dependencies[dim] = Dict({dim: 1}) def parse_dim_name(dim): if isinstance(dim, Dimension): return dim.name elif isinstance(dim, str): return Symbol(dim) elif isinstance(dim, Symbol): return dim else: raise TypeError("unrecognized type %s for %s" % (type(dim), dim)) for dim in dimensional_dependencies.keys(): dim = parse_dim(dim) if (dim not in derived_dims) and (dim not in base_dims): derived_dims.append(dim) def parse_dict(d): return Dict({parse_dim_name(i): j for i, j in d.items()}) # Make sure everything is a SymPy type: dimensional_dependencies = {parse_dim_name(i): parse_dict(j) for i, j in dimensional_dependencies.items()} for dim in derived_dims: if dim in base_dims: raise ValueError("Dimension %s both in base and derived" % dim) if dim.name not in dimensional_dependencies: # TODO: should this raise a warning? dimensional_dependencies[dim.name] = Dict({dim.name: 1}) base_dims.sort(key=default_sort_key) derived_dims.sort(key=default_sort_key) base_dims = Tuple(*base_dims) derived_dims = Tuple(*derived_dims) dimensional_dependencies = Dict({i: Dict(j) for i, j in dimensional_dependencies.items()}) obj = Basic.__new__(cls, base_dims, derived_dims, dimensional_dependencies) return obj @property def base_dims(self): return self.args[0] @property def derived_dims(self): return self.args[1] @property def dimensional_dependencies(self): return self.args[2] def _get_dimensional_dependencies_for_name(self, name): if isinstance(name, Dimension): name = name.name if isinstance(name, str): name = Symbol(name) if name.is_Symbol: # Dimensions not included in the dependencies are considered # as base dimensions: return dict(self.dimensional_dependencies.get(name, {name: 1})) if name.is_number or name.is_NumberSymbol: return {} get_for_name = self._get_dimensional_dependencies_for_name if name.is_Mul: ret = collections.defaultdict(int) dicts = [get_for_name(i) for i in name.args] for d in dicts: for k, v in d.items(): ret[k] += v return {k: v for (k, v) in ret.items() if v != 0} if name.is_Add: dicts = [get_for_name(i) for i in name.args] if all([d == dicts[0] for d in dicts[1:]]): return dicts[0] raise TypeError("Only equivalent dimensions can be added or subtracted.") if name.is_Pow: dim_base = get_for_name(name.base) dim_exp = get_for_name(name.exp) if dim_exp == {} or name.exp.is_Symbol: return {k: v*name.exp for (k, v) in dim_base.items()} else: raise TypeError("The exponent for the power operator must be a Symbol or dimensionless.") if name.is_Function: args = (Dimension._from_dimensional_dependencies( get_for_name(arg)) for arg in name.args) result = name.func(*args) dicts = [get_for_name(i) for i in name.args] if isinstance(result, Dimension): return self.get_dimensional_dependencies(result) elif result.func == name.func: if isinstance(name, TrigonometricFunction): if dicts[0] == {} or dicts[0] == {Symbol('angle'): 1}: return {} else: raise TypeError("The input argument for the function {} must be dimensionless or have dimensions of angle.".format(name.func)) else: if all( (item == {} for item in dicts) ): return {} else: raise TypeError("The input arguments for the function {} must be dimensionless.".format(name.func)) else: return get_for_name(result) raise TypeError("Type {} not implemented for get_dimensional_dependencies".format(type(name))) def get_dimensional_dependencies(self, name, mark_dimensionless=False): dimdep = self._get_dimensional_dependencies_for_name(name) if mark_dimensionless and dimdep == {}: return {'dimensionless': 1} return {str(i): j for i, j in dimdep.items()} def equivalent_dims(self, dim1, dim2): deps1 = self.get_dimensional_dependencies(dim1) deps2 = self.get_dimensional_dependencies(dim2) return deps1 == deps2 def extend(self, new_base_dims, new_derived_dims=[], new_dim_deps={}, name=None, description=None): if (name is not None) or (description is not None): SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, feature="name and descriptions of DimensionSystem", useinstead="do not specify `name` or `description`", ).warn() deps = dict(self.dimensional_dependencies) deps.update(new_dim_deps) new_dim_sys = DimensionSystem( tuple(self.base_dims) + tuple(new_base_dims), tuple(self.derived_dims) + tuple(new_derived_dims), deps ) new_dim_sys._quantity_dimension_map.update(self._quantity_dimension_map) new_dim_sys._quantity_scale_factors.update(self._quantity_scale_factors) return new_dim_sys @staticmethod def sort_dims(dims): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Sort dimensions given in argument using their str function. This function will ensure that we get always the same tuple for a given set of dimensions. """ SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, feature="sort_dims", useinstead="sorted(..., key=default_sort_key)", ).warn() return tuple(sorted(dims, key=str)) def __getitem__(self, key): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Shortcut to the get_dim method, using key access. """ SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, feature="the get [ ] operator", useinstead="the dimension definition", ).warn() d = self.get_dim(key) #TODO: really want to raise an error? if d is None: raise KeyError(key) return d def __call__(self, unit): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Wrapper to the method print_dim_base """ SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, feature="call DimensionSystem", useinstead="the dimension definition", ).warn() return self.print_dim_base(unit) def is_dimensionless(self, dimension): """ Check if the dimension object really has a dimension. A dimension should have at least one component with non-zero power. """ if dimension.name == 1: return True return self.get_dimensional_dependencies(dimension) == {} @property def list_can_dims(self): """ Useless method, kept for compatibility with previous versions. DO NOT USE. List all canonical dimension names. """ dimset = set() for i in self.base_dims: dimset.update(set(self.get_dimensional_dependencies(i).keys())) return tuple(sorted(dimset, key=str)) @property def inv_can_transf_matrix(self): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Compute the inverse transformation matrix from the base to the canonical dimension basis. It corresponds to the matrix where columns are the vector of base dimensions in canonical basis. This matrix will almost never be used because dimensions are always defined with respect to the canonical basis, so no work has to be done to get them in this basis. Nonetheless if this matrix is not square (or not invertible) it means that we have chosen a bad basis. """ matrix = reduce(lambda x, y: x.row_join(y), [self.dim_can_vector(d) for d in self.base_dims]) return matrix @property def can_transf_matrix(self): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Return the canonical transformation matrix from the canonical to the base dimension basis. It is the inverse of the matrix computed with inv_can_transf_matrix(). """ #TODO: the inversion will fail if the system is inconsistent, for # example if the matrix is not a square return reduce(lambda x, y: x.row_join(y), [self.dim_can_vector(d) for d in sorted(self.base_dims, key=str)] ).inv() def dim_can_vector(self, dim): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Dimensional representation in terms of the canonical base dimensions. """ vec = [] for d in self.list_can_dims: vec.append(self.get_dimensional_dependencies(dim).get(d, 0)) return Matrix(vec) def dim_vector(self, dim): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Vector representation in terms of the base dimensions. """ return self.can_transf_matrix * Matrix(self.dim_can_vector(dim)) def print_dim_base(self, dim): """ Give the string expression of a dimension in term of the basis symbols. """ dims = self.dim_vector(dim) symbols = [i.symbol if i.symbol is not None else i.name for i in self.base_dims] res = S.One for (s, p) in zip(symbols, dims): res *= s**p return res @property def dim(self): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Give the dimension of the system. That is return the number of dimensions forming the basis. """ return len(self.base_dims) @property def is_consistent(self): """ Useless method, kept for compatibility with previous versions. DO NOT USE. Check if the system is well defined. """ # not enough or too many base dimensions compared to independent # dimensions # in vector language: the set of vectors do not form a basis return self.inv_can_transf_matrix.is_square sympy-sympy-1.9/sympy/physics/units/prefixes.py000066400000000000000000000134621412543434000221350ustar00rootroot00000000000000""" Module defining unit prefixe class and some constants. Constant dict for SI and binary prefixes are defined as PREFIXES and BIN_PREFIXES. """ from sympy import Expr, sympify class Prefix(Expr): """ This class represent prefixes, with their name, symbol and factor. Prefixes are used to create derived units from a given unit. They should always be encapsulated into units. The factor is constructed from a base (default is 10) to some power, and it gives the total multiple or fraction. For example the kilometer km is constructed from the meter (factor 1) and the kilo (10 to the power 3, i.e. 1000). The base can be changed to allow e.g. binary prefixes. A prefix multiplied by something will always return the product of this other object times the factor, except if the other object: - is a prefix and they can be combined into a new prefix; - defines multiplication with prefixes (which is the case for the Unit class). """ _op_priority = 13.0 is_commutative = True def __new__(cls, name, abbrev, exponent, base=sympify(10)): name = sympify(name) abbrev = sympify(abbrev) exponent = sympify(exponent) base = sympify(base) obj = Expr.__new__(cls, name, abbrev, exponent, base) obj._name = name obj._abbrev = abbrev obj._scale_factor = base**exponent obj._exponent = exponent obj._base = base return obj @property def name(self): return self._name @property def abbrev(self): return self._abbrev @property def scale_factor(self): return self._scale_factor @property def base(self): return self._base def __str__(self): # TODO: add proper printers and tests: if self.base == 10: return "Prefix(%r, %r, %r)" % ( str(self.name), str(self.abbrev), self._exponent) else: return "Prefix(%r, %r, %r, %r)" % ( str(self.name), str(self.abbrev), self._exponent, self.base) __repr__ = __str__ def __mul__(self, other): from sympy.physics.units import Quantity if not isinstance(other, (Quantity, Prefix)): return super().__mul__(other) fact = self.scale_factor * other.scale_factor if fact == 1: return 1 elif isinstance(other, Prefix): # simplify prefix for p in PREFIXES: if PREFIXES[p].scale_factor == fact: return PREFIXES[p] return fact return self.scale_factor * other def __truediv__(self, other): if not hasattr(other, "scale_factor"): return super().__truediv__(other) fact = self.scale_factor / other.scale_factor if fact == 1: return 1 elif isinstance(other, Prefix): for p in PREFIXES: if PREFIXES[p].scale_factor == fact: return PREFIXES[p] return fact return self.scale_factor / other def __rtruediv__(self, other): if other == 1: for p in PREFIXES: if PREFIXES[p].scale_factor == 1 / self.scale_factor: return PREFIXES[p] return other / self.scale_factor def prefix_unit(unit, prefixes): """ Return a list of all units formed by unit and the given prefixes. You can use the predefined PREFIXES or BIN_PREFIXES, but you can also pass as argument a subdict of them if you don't want all prefixed units. >>> from sympy.physics.units.prefixes import (PREFIXES, ... prefix_unit) >>> from sympy.physics.units import m >>> pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]} >>> prefix_unit(m, pref) # doctest: +SKIP [millimeter, centimeter, decimeter] """ from sympy.physics.units.quantities import Quantity from sympy.physics.units import UnitSystem prefixed_units = [] for prefix_abbr, prefix in prefixes.items(): quantity = Quantity( "%s%s" % (prefix.name, unit.name), abbrev=("%s%s" % (prefix.abbrev, unit.abbrev)) ) UnitSystem._quantity_dimensional_equivalence_map_global[quantity] = unit UnitSystem._quantity_scale_factors_global[quantity] = (prefix.scale_factor, unit) prefixed_units.append(quantity) return prefixed_units yotta = Prefix('yotta', 'Y', 24) zetta = Prefix('zetta', 'Z', 21) exa = Prefix('exa', 'E', 18) peta = Prefix('peta', 'P', 15) tera = Prefix('tera', 'T', 12) giga = Prefix('giga', 'G', 9) mega = Prefix('mega', 'M', 6) kilo = Prefix('kilo', 'k', 3) hecto = Prefix('hecto', 'h', 2) deca = Prefix('deca', 'da', 1) deci = Prefix('deci', 'd', -1) centi = Prefix('centi', 'c', -2) milli = Prefix('milli', 'm', -3) micro = Prefix('micro', 'mu', -6) nano = Prefix('nano', 'n', -9) pico = Prefix('pico', 'p', -12) femto = Prefix('femto', 'f', -15) atto = Prefix('atto', 'a', -18) zepto = Prefix('zepto', 'z', -21) yocto = Prefix('yocto', 'y', -24) # http://physics.nist.gov/cuu/Units/prefixes.html PREFIXES = { 'Y': yotta, 'Z': zetta, 'E': exa, 'P': peta, 'T': tera, 'G': giga, 'M': mega, 'k': kilo, 'h': hecto, 'da': deca, 'd': deci, 'c': centi, 'm': milli, 'mu': micro, 'n': nano, 'p': pico, 'f': femto, 'a': atto, 'z': zepto, 'y': yocto, } kibi = Prefix('kibi', 'Y', 10, 2) mebi = Prefix('mebi', 'Y', 20, 2) gibi = Prefix('gibi', 'Y', 30, 2) tebi = Prefix('tebi', 'Y', 40, 2) pebi = Prefix('pebi', 'Y', 50, 2) exbi = Prefix('exbi', 'Y', 60, 2) # http://physics.nist.gov/cuu/Units/binary.html BIN_PREFIXES = { 'Ki': kibi, 'Mi': mebi, 'Gi': gibi, 'Ti': tebi, 'Pi': pebi, 'Ei': exbi, } sympy-sympy-1.9/sympy/physics/units/quantities.py000066400000000000000000000163251412543434000224770ustar00rootroot00000000000000""" Physical quantities. """ from sympy import AtomicExpr, Symbol, sympify from sympy.physics.units.dimensions import _QuantityMapper from sympy.physics.units.prefixes import Prefix from sympy.utilities.exceptions import SymPyDeprecationWarning class Quantity(AtomicExpr): """ Physical quantity: can be a unit of measure, a constant or a generic quantity. """ is_commutative = True is_real = True is_number = False is_nonzero = True _diff_wrt = True def __new__(cls, name, abbrev=None, dimension=None, scale_factor=None, latex_repr=None, pretty_unicode_repr=None, pretty_ascii_repr=None, mathml_presentation_repr=None, **assumptions): if not isinstance(name, Symbol): name = Symbol(name) # For Quantity(name, dim, scale, abbrev) to work like in the # old version of Sympy: if not isinstance(abbrev, str) and not \ isinstance(abbrev, Symbol): dimension, scale_factor, abbrev = abbrev, dimension, scale_factor if dimension is not None: SymPyDeprecationWarning( deprecated_since_version="1.3", issue=14319, feature="Quantity arguments", useinstead="unit_system.set_quantity_dimension_map", ).warn() if scale_factor is not None: SymPyDeprecationWarning( deprecated_since_version="1.3", issue=14319, feature="Quantity arguments", useinstead="SI_quantity_scale_factors", ).warn() if abbrev is None: abbrev = name elif isinstance(abbrev, str): abbrev = Symbol(abbrev) obj = AtomicExpr.__new__(cls, name, abbrev) obj._name = name obj._abbrev = abbrev obj._latex_repr = latex_repr obj._unicode_repr = pretty_unicode_repr obj._ascii_repr = pretty_ascii_repr obj._mathml_repr = mathml_presentation_repr if dimension is not None: # TODO: remove after deprecation: obj.set_dimension(dimension) if scale_factor is not None: # TODO: remove after deprecation: obj.set_scale_factor(scale_factor) return obj def set_dimension(self, dimension, unit_system="SI"): SymPyDeprecationWarning( deprecated_since_version="1.5", issue=17765, feature="Moving method to UnitSystem class", useinstead="unit_system.set_quantity_dimension or {}.set_global_relative_scale_factor".format(self), ).warn() from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) unit_system.set_quantity_dimension(self, dimension) def set_scale_factor(self, scale_factor, unit_system="SI"): SymPyDeprecationWarning( deprecated_since_version="1.5", issue=17765, feature="Moving method to UnitSystem class", useinstead="unit_system.set_quantity_scale_factor or {}.set_global_relative_scale_factor".format(self), ).warn() from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) unit_system.set_quantity_scale_factor(self, scale_factor) def set_global_dimension(self, dimension): _QuantityMapper._quantity_dimension_global[self] = dimension def set_global_relative_scale_factor(self, scale_factor, reference_quantity): """ Setting a scale factor that is valid across all unit system. """ from sympy.physics.units import UnitSystem scale_factor = sympify(scale_factor) # replace all prefixes by their ratio to canonical units: scale_factor = scale_factor.replace( lambda x: isinstance(x, Prefix), lambda x: x.scale_factor ) scale_factor = sympify(scale_factor) UnitSystem._quantity_scale_factors_global[self] = (scale_factor, reference_quantity) UnitSystem._quantity_dimensional_equivalence_map_global[self] = reference_quantity @property def name(self): return self._name @property def dimension(self): from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_default_unit_system() return unit_system.get_quantity_dimension(self) @property def abbrev(self): """ Symbol representing the unit name. Prepend the abbreviation with the prefix symbol if it is defines. """ return self._abbrev @property def scale_factor(self): """ Overall magnitude of the quantity as compared to the canonical units. """ from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_default_unit_system() return unit_system.get_quantity_scale_factor(self) def _eval_is_positive(self): return True def _eval_is_constant(self): return True def _eval_Abs(self): return self def _eval_subs(self, old, new): if isinstance(new, Quantity) and self != old: return self @staticmethod def get_dimensional_expr(expr, unit_system="SI"): SymPyDeprecationWarning( deprecated_since_version="1.5", issue=17765, feature="get_dimensional_expr() is now associated with UnitSystem objects. " \ "The dimensional relations depend on the unit system used.", useinstead="unit_system.get_dimensional_expr" ).warn() from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) return unit_system.get_dimensional_expr(expr) @staticmethod def _collect_factor_and_dimension(expr, unit_system="SI"): """Return tuple with scale factor expression and dimension expression.""" SymPyDeprecationWarning( deprecated_since_version="1.5", issue=17765, feature="This method has been moved to the UnitSystem class.", useinstead="unit_system._collect_factor_and_dimension", ).warn() from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) return unit_system._collect_factor_and_dimension(expr) def _latex(self, printer): if self._latex_repr: return self._latex_repr else: return r'\text{{{}}}'.format(self.args[1] \ if len(self.args) >= 2 else self.args[0]) def convert_to(self, other, unit_system="SI"): """ Convert the quantity to another quantity of same dimensions. Examples ======== >>> from sympy.physics.units import speed_of_light, meter, second >>> speed_of_light speed_of_light >>> speed_of_light.convert_to(meter/second) 299792458*meter/second >>> from sympy.physics.units import liter >>> liter.convert_to(meter**3) meter**3/1000 """ from .util import convert_to return convert_to(self, other, unit_system) @property def free_symbols(self): """Return free symbols from quantity.""" return set() sympy-sympy-1.9/sympy/physics/units/systems/000077500000000000000000000000001412543434000214375ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/units/systems/__init__.py000066400000000000000000000003641412543434000235530ustar00rootroot00000000000000from sympy.physics.units.systems.mks import MKS from sympy.physics.units.systems.mksa import MKSA from sympy.physics.units.systems.natural import natural from sympy.physics.units.systems.si import SI __all__ = ['MKS', 'MKSA', 'natural', 'SI'] sympy-sympy-1.9/sympy/physics/units/systems/cgs.py000066400000000000000000000067761412543434000226050ustar00rootroot00000000000000from sympy import sqrt, S from sympy.physics.units import UnitSystem, centimeter, gram, second, coulomb, charge, speed_of_light, current, mass, \ length, voltage, magnetic_density, magnetic_flux from sympy.physics.units.definitions import coulombs_constant from sympy.physics.units.definitions.unit_definitions import statcoulomb, statampere, statvolt, volt, tesla, gauss, \ weber, maxwell, debye, oersted, ohm, farad, henry, erg, ampere, coulomb_constant from sympy.physics.units.systems.mks import dimsys_length_weight_time One = S.One dimsys_cgs = dimsys_length_weight_time.extend( [], new_dim_deps=dict( # Dimensional dependencies for derived dimensions impedance=dict(time=1, length=-1), conductance=dict(time=-1, length=1), capacitance=dict(length=1), inductance=dict(time=2, length=-1), charge=dict(mass=S.Half, length=S(3)/2, time=-1), current=dict(mass=One/2, length=3*One/2, time=-2), voltage=dict(length=-One/2, mass=One/2, time=-1), magnetic_density=dict(length=-One/2, mass=One/2, time=-1), magnetic_flux=dict(length=3*One/2, mass=One/2, time=-1), ) ) cgs_gauss = UnitSystem( base_units=[centimeter, gram, second], units=[], name="cgs_gauss", dimension_system=dimsys_cgs) cgs_gauss.set_quantity_scale_factor(coulombs_constant, 1) cgs_gauss.set_quantity_dimension(statcoulomb, charge) cgs_gauss.set_quantity_scale_factor(statcoulomb, centimeter**(S(3)/2)*gram**(S(1)/2)/second) cgs_gauss.set_quantity_dimension(coulomb, charge) cgs_gauss.set_quantity_dimension(statampere, current) cgs_gauss.set_quantity_scale_factor(statampere, statcoulomb/second) cgs_gauss.set_quantity_dimension(statvolt, voltage) cgs_gauss.set_quantity_scale_factor(statvolt, erg/statcoulomb) cgs_gauss.set_quantity_dimension(volt, voltage) cgs_gauss.set_quantity_dimension(gauss, magnetic_density) cgs_gauss.set_quantity_scale_factor(gauss, sqrt(gram/centimeter)/second) cgs_gauss.set_quantity_dimension(tesla, magnetic_density) cgs_gauss.set_quantity_dimension(maxwell, magnetic_flux) cgs_gauss.set_quantity_scale_factor(maxwell, sqrt(centimeter**3*gram)/second) # SI units expressed in CGS-gaussian units: cgs_gauss.set_quantity_scale_factor(coulomb, speed_of_light*statcoulomb/10) cgs_gauss.set_quantity_scale_factor(ampere, speed_of_light*statcoulomb/second/10) cgs_gauss.set_quantity_scale_factor(volt, speed_of_light*statvolt/10**6) cgs_gauss.set_quantity_scale_factor(weber, 10**8*maxwell) cgs_gauss.set_quantity_scale_factor(tesla, 10**4*gauss) cgs_gauss.set_quantity_scale_factor(debye, One/10**18*statcoulomb*centimeter) cgs_gauss.set_quantity_scale_factor(oersted, sqrt(gram/centimeter)/second) cgs_gauss.set_quantity_scale_factor(ohm, 10**9/speed_of_light**2*second/centimeter) cgs_gauss.set_quantity_scale_factor(farad, One/10**9*speed_of_light**2*centimeter) cgs_gauss.set_quantity_scale_factor(henry, 10**9/speed_of_light**2/centimeter*second**2) # Coulomb's constant: cgs_gauss.set_quantity_dimension(coulomb_constant, 1) cgs_gauss.set_quantity_scale_factor(coulomb_constant, 1) __all__ = [ 'ohm', 'tesla', 'maxwell', 'speed_of_light', 'volt', 'second', 'voltage', 'debye', 'dimsys_length_weight_time', 'centimeter', 'coulomb_constant', 'farad', 'sqrt', 'UnitSystem', 'current', 'charge', 'weber', 'gram', 'statcoulomb', 'gauss', 'S', 'statvolt', 'oersted', 'statampere', 'dimsys_cgs', 'coulomb', 'magnetic_density', 'magnetic_flux', 'One', 'length', 'erg', 'mass', 'coulombs_constant', 'henry', 'ampere', 'cgs_gauss', ] sympy-sympy-1.9/sympy/physics/units/systems/length_weight_time.py000066400000000000000000000151061412543434000256620ustar00rootroot00000000000000from sympy import S from sympy.core.numbers import pi from sympy.physics.units import DimensionSystem, hertz, kilogram from sympy.physics.units.definitions import ( G, Hz, J, N, Pa, W, c, g, kg, m, s, meter, gram, second, newton, joule, watt, pascal) from sympy.physics.units.definitions.dimension_definitions import ( acceleration, action, energy, force, frequency, momentum, power, pressure, velocity, length, mass, time) from sympy.physics.units.prefixes import PREFIXES, prefix_unit from sympy.physics.units.prefixes import ( kibi, mebi, gibi, tebi, pebi, exbi ) from sympy.physics.units.definitions import ( cd, K, coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre, lux, katal, gray, becquerel, inch, liter, julian_year, gravitational_constant, speed_of_light, elementary_charge, planck, hbar, electronvolt, avogadro_number, avogadro_constant, boltzmann_constant, stefan_boltzmann_constant, atomic_mass_constant, molar_gas_constant, faraday_constant, josephson_constant, von_klitzing_constant, acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity, vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg, milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass, planck_time, planck_temperature, planck_length, planck_charge, planck_area, planck_volume, planck_momentum, planck_energy, planck_force, planck_power, planck_density, planck_energy_density, planck_intensity, planck_angular_frequency, planck_pressure, planck_current, planck_voltage, planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte, gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree, steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, kelvin, mol, mole, candela, electric_constant, boltzmann ) dimsys_length_weight_time = DimensionSystem([ # Dimensional dependencies for MKS base dimensions length, mass, time, ], dimensional_dependencies=dict( # Dimensional dependencies for derived dimensions velocity=dict(length=1, time=-1), acceleration=dict(length=1, time=-2), momentum=dict(mass=1, length=1, time=-1), force=dict(mass=1, length=1, time=-2), energy=dict(mass=1, length=2, time=-2), power=dict(length=2, mass=1, time=-3), pressure=dict(mass=1, length=-1, time=-2), frequency=dict(time=-1), action=dict(length=2, mass=1, time=-1), volume=dict(length=3), )) One = S.One # Base units: dimsys_length_weight_time.set_quantity_dimension(meter, length) dimsys_length_weight_time.set_quantity_scale_factor(meter, One) # gram; used to define its prefixed units dimsys_length_weight_time.set_quantity_dimension(gram, mass) dimsys_length_weight_time.set_quantity_scale_factor(gram, One) dimsys_length_weight_time.set_quantity_dimension(second, time) dimsys_length_weight_time.set_quantity_scale_factor(second, One) # derived units dimsys_length_weight_time.set_quantity_dimension(newton, force) dimsys_length_weight_time.set_quantity_scale_factor(newton, kilogram*meter/second**2) dimsys_length_weight_time.set_quantity_dimension(joule, energy) dimsys_length_weight_time.set_quantity_scale_factor(joule, newton*meter) dimsys_length_weight_time.set_quantity_dimension(watt, power) dimsys_length_weight_time.set_quantity_scale_factor(watt, joule/second) dimsys_length_weight_time.set_quantity_dimension(pascal, pressure) dimsys_length_weight_time.set_quantity_scale_factor(pascal, newton/meter**2) dimsys_length_weight_time.set_quantity_dimension(hertz, frequency) dimsys_length_weight_time.set_quantity_scale_factor(hertz, One) # Other derived units: dimsys_length_weight_time.set_quantity_dimension(dioptre, 1 / length) dimsys_length_weight_time.set_quantity_scale_factor(dioptre, 1/meter) # Common volume and area units dimsys_length_weight_time.set_quantity_dimension(liter, length ** 3) dimsys_length_weight_time.set_quantity_scale_factor(liter, meter**3 / 1000) # Newton constant # REF: NIST SP 959 (June 2019) dimsys_length_weight_time.set_quantity_dimension(gravitational_constant, length ** 3 * mass ** -1 * time ** -2) dimsys_length_weight_time.set_quantity_scale_factor(gravitational_constant, 6.67430e-11*m**3/(kg*s**2)) # speed of light dimsys_length_weight_time.set_quantity_dimension(speed_of_light, velocity) dimsys_length_weight_time.set_quantity_scale_factor(speed_of_light, 299792458*meter/second) # Planck constant # REF: NIST SP 959 (June 2019) dimsys_length_weight_time.set_quantity_dimension(planck, action) dimsys_length_weight_time.set_quantity_scale_factor(planck, 6.62607015e-34*joule*second) # Reduced Planck constant # REF: NIST SP 959 (June 2019) dimsys_length_weight_time.set_quantity_dimension(hbar, action) dimsys_length_weight_time.set_quantity_scale_factor(hbar, planck / (2 * pi)) __all__ = [ 'mmHg', 'atmosphere', 'newton', 'meter', 'vacuum_permittivity', 'pascal', 'magnetic_constant', 'angular_mil', 'julian_year', 'weber', 'exbibyte', 'liter', 'molar_gas_constant', 'faraday_constant', 'avogadro_constant', 'planck_momentum', 'planck_density', 'gee', 'mol', 'bit', 'gray', 'kibi', 'bar', 'curie', 'prefix_unit', 'PREFIXES', 'planck_time', 'gram', 'candela', 'force', 'planck_intensity', 'energy', 'becquerel', 'planck_acceleration', 'speed_of_light', 'dioptre', 'second', 'frequency', 'Hz', 'power', 'lux', 'planck_current', 'momentum', 'tebibyte', 'planck_power', 'degree', 'mebi', 'K', 'planck_volume', 'quart', 'pressure', 'W', 'joule', 'boltzmann_constant', 'c', 'g', 'planck_force', 'exbi', 's', 'watt', 'action', 'hbar', 'gibibyte', 'DimensionSystem', 'cd', 'volt', 'planck_charge', 'dimsys_length_weight_time', 'pebi', 'vacuum_impedance', 'planck', 'farad', 'gravitational_constant', 'u0', 'hertz', 'tesla', 'steradian', 'josephson_constant', 'planck_area', 'stefan_boltzmann_constant', 'astronomical_unit', 'J', 'N', 'planck_voltage', 'planck_energy', 'atomic_mass_constant', 'rutherford', 'elementary_charge', 'Pa', 'planck_mass', 'henry', 'planck_angular_frequency', 'ohm', 'pound', 'planck_pressure', 'G', 'avogadro_number', 'psi', 'von_klitzing_constant', 'planck_length', 'radian', 'mole', 'acceleration', 'planck_energy_density', 'mebibyte', 'length', 'acceleration_due_to_gravity', 'planck_temperature', 'tebi', 'inch', 'electronvolt', 'coulomb_constant', 'kelvin', 'kPa', 'boltzmann', 'milli_mass_unit', 'gibi', 'planck_impedance', 'electric_constant', 'kg', 'coulomb', 'siemens', 'byte', 'atomic_mass_unit', 'm', 'kibibyte', 'kilogram', 'lightyear', 'mass', 'time', 'pebibyte', 'velocity', 'ampere', 'katal', ] sympy-sympy-1.9/sympy/physics/units/systems/mks.py000066400000000000000000000026331412543434000226070ustar00rootroot00000000000000""" MKS unit system. MKS stands for "meter, kilogram, second". """ from sympy.physics.units import UnitSystem, DimensionSystem from sympy.physics.units.definitions import G, Hz, J, N, Pa, W, c, g, kg, m, s from sympy.physics.units.definitions.dimension_definitions import ( acceleration, action, energy, force, frequency, momentum, power, pressure, velocity, length, mass, time) from sympy.physics.units.prefixes import PREFIXES, prefix_unit from sympy.physics.units.systems.length_weight_time import dimsys_length_weight_time dims = (velocity, acceleration, momentum, force, energy, power, pressure, frequency, action) units = [m, g, s, J, N, W, Pa, Hz] all_units = [] # Prefixes of units like g, J, N etc get added using `prefix_unit` # in the for loop, but the actual units have to be added manually. all_units.extend([g, J, N, W, Pa, Hz]) for u in units: all_units.extend(prefix_unit(u, PREFIXES)) all_units.extend([G, c]) # unit system MKS = UnitSystem(base_units=(m, kg, s), units=all_units, name="MKS", dimension_system=dimsys_length_weight_time) __all__ = [ 'force', 'DimensionSystem', 'energy', 'Pa', 'MKS', 'dimsys_length_weight_time', 'Hz', 'power', 's', 'UnitSystem', 'units', 'mass', 'momentum', 'acceleration', 'G', 'J', 'N', 'pressure', 'W', 'all_units', 'c', 'kg', 'g', 'dims', 'prefix_unit', 'm', 'PREFIXES', 'length', 'frequency', 'u', 'time', 'action', 'velocity', ] sympy-sympy-1.9/sympy/physics/units/systems/mksa.py000066400000000000000000000030771412543434000227530ustar00rootroot00000000000000""" MKS unit system. MKS stands for "meter, kilogram, second, ampere". """ from typing import List from sympy.physics.units.definitions import Z0, A, C, F, H, S, T, V, Wb, ohm from sympy.physics.units.definitions.dimension_definitions import ( capacitance, charge, conductance, current, impedance, inductance, magnetic_density, magnetic_flux, voltage) from sympy.physics.units.prefixes import PREFIXES, prefix_unit from sympy.physics.units.systems.mks import MKS, dimsys_length_weight_time from sympy.physics.units.quantities import Quantity dims = (voltage, impedance, conductance, current, capacitance, inductance, charge, magnetic_density, magnetic_flux) units = [A, V, ohm, S, F, H, C, T, Wb] all_units = [] # type: List[Quantity] for u in units: all_units.extend(prefix_unit(u, PREFIXES)) all_units.extend([Z0]) dimsys_MKSA = dimsys_length_weight_time.extend([ # Dimensional dependencies for base dimensions (MKSA not in MKS) current, ], new_dim_deps=dict( # Dimensional dependencies for derived dimensions voltage=dict(mass=1, length=2, current=-1, time=-3), impedance=dict(mass=1, length=2, current=-2, time=-3), conductance=dict(mass=-1, length=-2, current=2, time=3), capacitance=dict(mass=-1, length=-2, current=2, time=4), inductance=dict(mass=1, length=2, current=-2, time=-2), charge=dict(current=1, time=1), magnetic_density=dict(mass=1, current=-1, time=-2), magnetic_flux=dict(length=2, mass=1, current=-1, time=-2), )) MKSA = MKS.extend(base=(A,), units=all_units, name='MKSA', dimension_system=dimsys_MKSA) sympy-sympy-1.9/sympy/physics/units/systems/natural.py000066400000000000000000000016151412543434000234620ustar00rootroot00000000000000""" Naturalunit system. The natural system comes from "setting c = 1, hbar = 1". From the computer point of view it means that we use velocity and action instead of length and time. Moreover instead of mass we use energy. """ from sympy.physics.units import DimensionSystem from sympy.physics.units.definitions import c, eV, hbar from sympy.physics.units.definitions.dimension_definitions import ( action, energy, force, frequency, length, mass, momentum, power, time, velocity) from sympy.physics.units.prefixes import PREFIXES, prefix_unit from sympy.physics.units.unitsystem import UnitSystem # dimension system _natural_dim = DimensionSystem( base_dims=(action, energy, velocity), derived_dims=(length, mass, time, momentum, force, power, frequency) ) units = prefix_unit(eV, PREFIXES) # unit system natural = UnitSystem(base_units=(hbar, eV, c), units=units, name="Natural system") sympy-sympy-1.9/sympy/physics/units/systems/si.py000066400000000000000000000325211412543434000224270ustar00rootroot00000000000000""" SI unit system. Based on MKSA, which stands for "meter, kilogram, second, ampere". Added kelvin, candela and mole. """ from typing import List from sympy.physics.units import DimensionSystem, Dimension, dHg0 from sympy.physics.units.quantities import Quantity from sympy import Rational, pi, sqrt, S from sympy.physics.units.definitions.dimension_definitions import ( acceleration, action, current, impedance, length, mass, time, velocity, amount_of_substance, temperature, information, frequency, force, pressure, energy, power, charge, voltage, capacitance, conductance, magnetic_flux, magnetic_density, inductance, luminous_intensity ) from sympy.physics.units.definitions import ( kilogram, newton, second, meter, gram, cd, K, joule, watt, pascal, hertz, coulomb, volt, ohm, siemens, farad, henry, tesla, weber, dioptre, lux, katal, gray, becquerel, inch, liter, julian_year, gravitational_constant, speed_of_light, elementary_charge, planck, hbar, electronvolt, avogadro_number, avogadro_constant, boltzmann_constant, stefan_boltzmann_constant, atomic_mass_constant, molar_gas_constant, faraday_constant, josephson_constant, von_klitzing_constant, acceleration_due_to_gravity, magnetic_constant, vacuum_permittivity, vacuum_impedance, coulomb_constant, atmosphere, bar, pound, psi, mmHg, milli_mass_unit, quart, lightyear, astronomical_unit, planck_mass, planck_time, planck_temperature, planck_length, planck_charge, planck_area, planck_volume, planck_momentum, planck_energy, planck_force, planck_power, planck_density, planck_energy_density, planck_intensity, planck_angular_frequency, planck_pressure, planck_current, planck_voltage, planck_impedance, planck_acceleration, bit, byte, kibibyte, mebibyte, gibibyte, tebibyte, pebibyte, exbibyte, curie, rutherford, radian, degree, steradian, angular_mil, atomic_mass_unit, gee, kPa, ampere, u0, c, kelvin, mol, mole, candela, m, kg, s, electric_constant, G, boltzmann ) from sympy.physics.units.prefixes import PREFIXES, prefix_unit from sympy.physics.units.systems.mksa import MKSA, dimsys_MKSA derived_dims = (frequency, force, pressure, energy, power, charge, voltage, capacitance, conductance, magnetic_flux, magnetic_density, inductance, luminous_intensity) base_dims = (amount_of_substance, luminous_intensity, temperature) units = [mol, cd, K, lux, hertz, newton, pascal, joule, watt, coulomb, volt, farad, ohm, siemens, weber, tesla, henry, candela, lux, becquerel, gray, katal] all_units = [] # type: List[Quantity] for u in units: all_units.extend(prefix_unit(u, PREFIXES)) all_units.extend([mol, cd, K, lux]) dimsys_SI = dimsys_MKSA.extend( [ # Dimensional dependencies for other base dimensions: temperature, amount_of_substance, luminous_intensity, ]) dimsys_default = dimsys_SI.extend( [information], ) SI = MKSA.extend(base=(mol, cd, K), units=all_units, name='SI', dimension_system=dimsys_SI) One = S.One SI.set_quantity_dimension(radian, One) SI.set_quantity_scale_factor(ampere, One) SI.set_quantity_scale_factor(kelvin, One) SI.set_quantity_scale_factor(mole, One) SI.set_quantity_scale_factor(candela, One) # MKSA extension to MKS: derived units SI.set_quantity_scale_factor(coulomb, One) SI.set_quantity_scale_factor(volt, joule/coulomb) SI.set_quantity_scale_factor(ohm, volt/ampere) SI.set_quantity_scale_factor(siemens, ampere/volt) SI.set_quantity_scale_factor(farad, coulomb/volt) SI.set_quantity_scale_factor(henry, volt*second/ampere) SI.set_quantity_scale_factor(tesla, volt*second/meter**2) SI.set_quantity_scale_factor(weber, joule/ampere) SI.set_quantity_dimension(lux, luminous_intensity / length ** 2) SI.set_quantity_scale_factor(lux, steradian*candela/meter**2) # katal is the SI unit of catalytic activity SI.set_quantity_dimension(katal, amount_of_substance / time) SI.set_quantity_scale_factor(katal, mol/second) # gray is the SI unit of absorbed dose SI.set_quantity_dimension(gray, energy / mass) SI.set_quantity_scale_factor(gray, meter**2/second**2) # becquerel is the SI unit of radioactivity SI.set_quantity_dimension(becquerel, 1 / time) SI.set_quantity_scale_factor(becquerel, 1/second) #### CONSTANTS #### # elementary charge # REF: NIST SP 959 (June 2019) SI.set_quantity_dimension(elementary_charge, charge) SI.set_quantity_scale_factor(elementary_charge, 1.602176634e-19*coulomb) # Electronvolt # REF: NIST SP 959 (June 2019) SI.set_quantity_dimension(electronvolt, energy) SI.set_quantity_scale_factor(electronvolt, 1.602176634e-19*joule) # Avogadro number # REF: NIST SP 959 (June 2019) SI.set_quantity_dimension(avogadro_number, One) SI.set_quantity_scale_factor(avogadro_number, 6.02214076e23) # Avogadro constant SI.set_quantity_dimension(avogadro_constant, amount_of_substance ** -1) SI.set_quantity_scale_factor(avogadro_constant, avogadro_number / mol) # Boltzmann constant # REF: NIST SP 959 (June 2019) SI.set_quantity_dimension(boltzmann_constant, energy / temperature) SI.set_quantity_scale_factor(boltzmann_constant, 1.380649e-23*joule/kelvin) # Stefan-Boltzmann constant # REF: NIST SP 959 (June 2019) SI.set_quantity_dimension(stefan_boltzmann_constant, energy * time ** -1 * length ** -2 * temperature ** -4) SI.set_quantity_scale_factor(stefan_boltzmann_constant, pi**2 * boltzmann_constant**4 / (60 * hbar**3 * speed_of_light ** 2)) # Atomic mass # REF: NIST SP 959 (June 2019) SI.set_quantity_dimension(atomic_mass_constant, mass) SI.set_quantity_scale_factor(atomic_mass_constant, 1.66053906660e-24*gram) # Molar gas constant # REF: NIST SP 959 (June 2019) SI.set_quantity_dimension(molar_gas_constant, energy / (temperature * amount_of_substance)) SI.set_quantity_scale_factor(molar_gas_constant, boltzmann_constant * avogadro_constant) # Faraday constant SI.set_quantity_dimension(faraday_constant, charge / amount_of_substance) SI.set_quantity_scale_factor(faraday_constant, elementary_charge * avogadro_constant) # Josephson constant SI.set_quantity_dimension(josephson_constant, frequency / voltage) SI.set_quantity_scale_factor(josephson_constant, 0.5 * planck / elementary_charge) # Von Klitzing constant SI.set_quantity_dimension(von_klitzing_constant, voltage / current) SI.set_quantity_scale_factor(von_klitzing_constant, hbar / elementary_charge ** 2) # Acceleration due to gravity (on the Earth surface) SI.set_quantity_dimension(acceleration_due_to_gravity, acceleration) SI.set_quantity_scale_factor(acceleration_due_to_gravity, 9.80665*meter/second**2) # magnetic constant: SI.set_quantity_dimension(magnetic_constant, force / current ** 2) SI.set_quantity_scale_factor(magnetic_constant, 4*pi/10**7 * newton/ampere**2) # electric constant: SI.set_quantity_dimension(vacuum_permittivity, capacitance / length) SI.set_quantity_scale_factor(vacuum_permittivity, 1/(u0 * c**2)) # vacuum impedance: SI.set_quantity_dimension(vacuum_impedance, impedance) SI.set_quantity_scale_factor(vacuum_impedance, u0 * c) # Coulomb's constant: SI.set_quantity_dimension(coulomb_constant, force * length ** 2 / charge ** 2) SI.set_quantity_scale_factor(coulomb_constant, 1/(4*pi*vacuum_permittivity)) SI.set_quantity_dimension(psi, pressure) SI.set_quantity_scale_factor(psi, pound * gee / inch ** 2) SI.set_quantity_dimension(mmHg, pressure) SI.set_quantity_scale_factor(mmHg, dHg0 * acceleration_due_to_gravity * kilogram / meter**2) SI.set_quantity_dimension(milli_mass_unit, mass) SI.set_quantity_scale_factor(milli_mass_unit, atomic_mass_unit/1000) SI.set_quantity_dimension(quart, length ** 3) SI.set_quantity_scale_factor(quart, Rational(231, 4) * inch**3) # Other convenient units and magnitudes SI.set_quantity_dimension(lightyear, length) SI.set_quantity_scale_factor(lightyear, speed_of_light*julian_year) SI.set_quantity_dimension(astronomical_unit, length) SI.set_quantity_scale_factor(astronomical_unit, 149597870691*meter) # Fundamental Planck units: SI.set_quantity_dimension(planck_mass, mass) SI.set_quantity_scale_factor(planck_mass, sqrt(hbar*speed_of_light/G)) SI.set_quantity_dimension(planck_time, time) SI.set_quantity_scale_factor(planck_time, sqrt(hbar*G/speed_of_light**5)) SI.set_quantity_dimension(planck_temperature, temperature) SI.set_quantity_scale_factor(planck_temperature, sqrt(hbar*speed_of_light**5/G/boltzmann**2)) SI.set_quantity_dimension(planck_length, length) SI.set_quantity_scale_factor(planck_length, sqrt(hbar*G/speed_of_light**3)) SI.set_quantity_dimension(planck_charge, charge) SI.set_quantity_scale_factor(planck_charge, sqrt(4*pi*electric_constant*hbar*speed_of_light)) # Derived Planck units: SI.set_quantity_dimension(planck_area, length ** 2) SI.set_quantity_scale_factor(planck_area, planck_length**2) SI.set_quantity_dimension(planck_volume, length ** 3) SI.set_quantity_scale_factor(planck_volume, planck_length**3) SI.set_quantity_dimension(planck_momentum, mass * velocity) SI.set_quantity_scale_factor(planck_momentum, planck_mass * speed_of_light) SI.set_quantity_dimension(planck_energy, energy) SI.set_quantity_scale_factor(planck_energy, planck_mass * speed_of_light**2) SI.set_quantity_dimension(planck_force, force) SI.set_quantity_scale_factor(planck_force, planck_energy / planck_length) SI.set_quantity_dimension(planck_power, power) SI.set_quantity_scale_factor(planck_power, planck_energy / planck_time) SI.set_quantity_dimension(planck_density, mass / length ** 3) SI.set_quantity_scale_factor(planck_density, planck_mass / planck_length**3) SI.set_quantity_dimension(planck_energy_density, energy / length ** 3) SI.set_quantity_scale_factor(planck_energy_density, planck_energy / planck_length**3) SI.set_quantity_dimension(planck_intensity, mass * time ** (-3)) SI.set_quantity_scale_factor(planck_intensity, planck_energy_density * speed_of_light) SI.set_quantity_dimension(planck_angular_frequency, 1 / time) SI.set_quantity_scale_factor(planck_angular_frequency, 1 / planck_time) SI.set_quantity_dimension(planck_pressure, pressure) SI.set_quantity_scale_factor(planck_pressure, planck_force / planck_length**2) SI.set_quantity_dimension(planck_current, current) SI.set_quantity_scale_factor(planck_current, planck_charge / planck_time) SI.set_quantity_dimension(planck_voltage, voltage) SI.set_quantity_scale_factor(planck_voltage, planck_energy / planck_charge) SI.set_quantity_dimension(planck_impedance, impedance) SI.set_quantity_scale_factor(planck_impedance, planck_voltage / planck_current) SI.set_quantity_dimension(planck_acceleration, acceleration) SI.set_quantity_scale_factor(planck_acceleration, speed_of_light / planck_time) # Older units for radioactivity SI.set_quantity_dimension(curie, 1 / time) SI.set_quantity_scale_factor(curie, 37000000000*becquerel) SI.set_quantity_dimension(rutherford, 1 / time) SI.set_quantity_scale_factor(rutherford, 1000000*becquerel) # check that scale factors are the right SI dimensions: for _scale_factor, _dimension in zip( SI._quantity_scale_factors.values(), SI._quantity_dimension_map.values() ): dimex = SI.get_dimensional_expr(_scale_factor) if dimex != 1: # XXX: equivalent_dims is an instance method taking two arguments in # addition to self so this can not work: if not DimensionSystem.equivalent_dims(_dimension, Dimension(dimex)): # type: ignore raise ValueError("quantity value and dimension mismatch") del _scale_factor, _dimension __all__ = [ 'mmHg', 'atmosphere', 'inductance', 'newton', 'meter', 'vacuum_permittivity', 'pascal', 'magnetic_constant', 'voltage', 'angular_mil', 'luminous_intensity', 'all_units', 'julian_year', 'weber', 'exbibyte', 'liter', 'molar_gas_constant', 'faraday_constant', 'avogadro_constant', 'lightyear', 'planck_density', 'gee', 'mol', 'bit', 'gray', 'planck_momentum', 'bar', 'magnetic_density', 'prefix_unit', 'PREFIXES', 'planck_time', 'dimex', 'gram', 'candela', 'force', 'planck_intensity', 'energy', 'becquerel', 'planck_acceleration', 'speed_of_light', 'conductance', 'frequency', 'coulomb_constant', 'degree', 'lux', 'planck', 'current', 'planck_current', 'tebibyte', 'planck_power', 'MKSA', 'power', 'K', 'planck_volume', 'quart', 'pressure', 'amount_of_substance', 'joule', 'boltzmann_constant', 'Dimension', 'c', 'planck_force', 'length', 'watt', 'action', 'hbar', 'gibibyte', 'DimensionSystem', 'cd', 'volt', 'planck_charge', 'dioptre', 'vacuum_impedance', 'dimsys_default', 'farad', 'charge', 'gravitational_constant', 'temperature', 'u0', 'hertz', 'capacitance', 'tesla', 'steradian', 'planck_mass', 'josephson_constant', 'planck_area', 'stefan_boltzmann_constant', 'base_dims', 'astronomical_unit', 'radian', 'planck_voltage', 'impedance', 'planck_energy', 'atomic_mass_constant', 'rutherford', 'second', 'inch', 'elementary_charge', 'SI', 'electronvolt', 'dimsys_SI', 'henry', 'planck_angular_frequency', 'ohm', 'pound', 'planck_pressure', 'G', 'psi', 'dHg0', 'von_klitzing_constant', 'planck_length', 'avogadro_number', 'mole', 'acceleration', 'information', 'planck_energy_density', 'mebibyte', 's', 'acceleration_due_to_gravity', 'planck_temperature', 'units', 'mass', 'dimsys_MKSA', 'kelvin', 'kPa', 'boltzmann', 'milli_mass_unit', 'planck_impedance', 'electric_constant', 'derived_dims', 'kg', 'coulomb', 'siemens', 'byte', 'magnetic_flux', 'atomic_mass_unit', 'm', 'kibibyte', 'kilogram', 'One', 'curie', 'u', 'time', 'pebibyte', 'velocity', 'ampere', 'katal', ] sympy-sympy-1.9/sympy/physics/units/tests/000077500000000000000000000000001412543434000210725ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/units/tests/__init__.py000066400000000000000000000000001412543434000231710ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/units/tests/test_dimensions.py000066400000000000000000000134061412543434000246570ustar00rootroot00000000000000from sympy.physics.units.systems.si import dimsys_SI from sympy import S, Symbol, sqrt, cos, acos, log, atan2, pi, Abs from sympy.physics.units.dimensions import Dimension from sympy.physics.units.definitions.dimension_definitions import ( length, time, mass, force, pressure, angle ) from sympy.physics.units import foot from sympy.testing.pytest import raises def test_Dimension_definition(): assert dimsys_SI.get_dimensional_dependencies(length) == {"length": 1} assert length.name == Symbol("length") assert length.symbol == Symbol("L") halflength = sqrt(length) assert dimsys_SI.get_dimensional_dependencies(halflength) == {"length": S.Half} def test_Dimension_error_definition(): # tuple with more or less than two entries raises(TypeError, lambda: Dimension(("length", 1, 2))) raises(TypeError, lambda: Dimension(["length"])) # non-number power raises(TypeError, lambda: Dimension({"length": "a"})) # non-number with named argument raises(TypeError, lambda: Dimension({"length": (1, 2)})) # symbol should by Symbol or str raises(AssertionError, lambda: Dimension("length", symbol=1)) def test_str(): assert str(Dimension("length")) == "Dimension(length)" assert str(Dimension("length", "L")) == "Dimension(length, L)" def test_Dimension_properties(): assert dimsys_SI.is_dimensionless(length) is False assert dimsys_SI.is_dimensionless(length/length) is True assert dimsys_SI.is_dimensionless(Dimension("undefined")) is False assert length.has_integer_powers(dimsys_SI) is True assert (length**(-1)).has_integer_powers(dimsys_SI) is True assert (length**1.5).has_integer_powers(dimsys_SI) is False def test_Dimension_add_sub(): assert length + length == length assert length - length == length assert -length == length raises(TypeError, lambda: length + foot) raises(TypeError, lambda: foot + length) raises(TypeError, lambda: length - foot) raises(TypeError, lambda: foot - length) # issue 14547 - only raise error for dimensional args; allow # others to pass x = Symbol('x') e = length + x assert e == x + length and e.is_Add and set(e.args) == {length, x} e = length + 1 assert e == 1 + length == 1 - length and e.is_Add and set(e.args) == {length, 1} assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force) == \ {'length': 1, 'mass': 1, 'time': -2} assert dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + force - pressure * length**2) == \ {'length': 1, 'mass': 1, 'time': -2} raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(mass * length / time**2 + pressure)) def test_Dimension_mul_div_exp(): assert 2*length == length*2 == length/2 == length assert 2/length == 1/length x = Symbol('x') m = x*length assert m == length*x and m.is_Mul and set(m.args) == {x, length} d = x/length assert d == x*length**-1 and d.is_Mul and set(d.args) == {x, 1/length} d = length/x assert d == length*x**-1 and d.is_Mul and set(d.args) == {1/x, length} velo = length / time assert (length * length) == length ** 2 assert dimsys_SI.get_dimensional_dependencies(length * length) == {"length": 2} assert dimsys_SI.get_dimensional_dependencies(length ** 2) == {"length": 2} assert dimsys_SI.get_dimensional_dependencies(length * time) == { "length": 1, "time": 1} assert dimsys_SI.get_dimensional_dependencies(velo) == { "length": 1, "time": -1} assert dimsys_SI.get_dimensional_dependencies(velo ** 2) == {"length": 2, "time": -2} assert dimsys_SI.get_dimensional_dependencies(length / length) == {} assert dimsys_SI.get_dimensional_dependencies(velo / length * time) == {} assert dimsys_SI.get_dimensional_dependencies(length ** -1) == {"length": -1} assert dimsys_SI.get_dimensional_dependencies(velo ** -1.5) == {"length": -1.5, "time": 1.5} length_a = length**"a" assert dimsys_SI.get_dimensional_dependencies(length_a) == {"length": Symbol("a")} assert dimsys_SI.get_dimensional_dependencies(length**pi) == {"length": pi} assert dimsys_SI.get_dimensional_dependencies(length**(length/length)) == {"length": Dimension(1)} raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(length**length)) assert length != 1 assert length / length != 1 length_0 = length ** 0 assert dimsys_SI.get_dimensional_dependencies(length_0) == {} # issue 18738 a = Symbol('a') b = Symbol('b') c = sqrt(a**2 + b**2) c_dim = c.subs({a: length, b: length}) assert dimsys_SI.equivalent_dims(c_dim, length) def test_Dimension_functions(): raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(cos(length))) raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(acos(angle))) raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(atan2(length, time))) raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length))) raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(100, length))) raises(TypeError, lambda: dimsys_SI.get_dimensional_dependencies(log(length, 10))) assert dimsys_SI.get_dimensional_dependencies(pi) == {} assert dimsys_SI.get_dimensional_dependencies(cos(1)) == {} assert dimsys_SI.get_dimensional_dependencies(cos(angle)) == {} assert dimsys_SI.get_dimensional_dependencies(atan2(length, length)) == {} assert dimsys_SI.get_dimensional_dependencies(log(length / length, length / length)) == {} assert dimsys_SI.get_dimensional_dependencies(Abs(length)) == {"length": 1} assert dimsys_SI.get_dimensional_dependencies(Abs(length / length)) == {} assert dimsys_SI.get_dimensional_dependencies(sqrt(-1)) == {} sympy-sympy-1.9/sympy/physics/units/tests/test_dimensionsystem.py000066400000000000000000000060461412543434000257430ustar00rootroot00000000000000from sympy.testing.pytest import warns_deprecated_sympy from sympy import Matrix, eye, symbols from sympy.physics.units.definitions.dimension_definitions import ( action, current, length, mass, time, velocity) from sympy.physics.units.dimensions import DimensionSystem def test_call(): mksa = DimensionSystem((length, time, mass, current), (action,)) with warns_deprecated_sympy(): assert mksa(action) == mksa.print_dim_base(action) def test_extend(): ms = DimensionSystem((length, time), (velocity,)) mks = ms.extend((mass,), (action,)) res = DimensionSystem((length, time, mass), (velocity, action)) assert mks.base_dims == res.base_dims assert mks.derived_dims == res.derived_dims def test_sort_dims(): with warns_deprecated_sympy(): assert (DimensionSystem.sort_dims((length, velocity, time)) == (length, time, velocity)) def test_list_dims(): dimsys = DimensionSystem((length, time, mass)) assert dimsys.list_can_dims == ("length", "mass", "time") def test_dim_can_vector(): dimsys = DimensionSystem( [length, mass, time], [velocity, action], { velocity: {length: 1, time: -1} } ) assert dimsys.dim_can_vector(length) == Matrix([1, 0, 0]) assert dimsys.dim_can_vector(velocity) == Matrix([1, 0, -1]) dimsys = DimensionSystem( (length, velocity, action), (mass, time), { time: {length: 1, velocity: -1} } ) assert dimsys.dim_can_vector(length) == Matrix([0, 1, 0]) assert dimsys.dim_can_vector(velocity) == Matrix([0, 0, 1]) assert dimsys.dim_can_vector(time) == Matrix([0, 1, -1]) dimsys = DimensionSystem( (length, mass, time), (velocity, action), {velocity: {length: 1, time: -1}, action: {mass: 1, length: 2, time: -1}}) assert dimsys.dim_vector(length) == Matrix([1, 0, 0]) assert dimsys.dim_vector(velocity) == Matrix([1, 0, -1]) def test_inv_can_transf_matrix(): dimsys = DimensionSystem((length, mass, time)) assert dimsys.inv_can_transf_matrix == eye(3) def test_can_transf_matrix(): dimsys = DimensionSystem((length, mass, time)) assert dimsys.can_transf_matrix == eye(3) dimsys = DimensionSystem((length, velocity, action)) assert dimsys.can_transf_matrix == eye(3) dimsys = DimensionSystem((length, time), (velocity,), {velocity: {length: 1, time: -1}}) assert dimsys.can_transf_matrix == eye(2) def test_is_consistent(): assert DimensionSystem((length, time)).is_consistent is True def test_print_dim_base(): mksa = DimensionSystem( (length, time, mass, current), (action,), {action: {mass: 1, length: 2, time: -1}}) L, M, T = symbols("L M T") assert mksa.print_dim_base(action) == L**2*M/T def test_dim(): dimsys = DimensionSystem( (length, mass, time), (velocity, action), {velocity: {length: 1, time: -1}, action: {mass: 1, length: 2, time: -1}} ) assert dimsys.dim == 3 sympy-sympy-1.9/sympy/physics/units/tests/test_prefixes.py000066400000000000000000000040721412543434000243330ustar00rootroot00000000000000from sympy import symbols, Mul, Symbol, S, Rational from sympy.physics.units import Quantity, length, meter from sympy.physics.units.prefixes import PREFIXES, Prefix, prefix_unit, kilo, \ kibi from sympy.physics.units.systems import SI x = Symbol('x') def test_prefix_operations(): m = PREFIXES['m'] k = PREFIXES['k'] M = PREFIXES['M'] dodeca = Prefix('dodeca', 'dd', 1, base=12) assert m * k == 1 assert k * k == M assert 1 / m == k assert k / m == M assert dodeca * dodeca == 144 assert 1 / dodeca == S.One / 12 assert k / dodeca == S(1000) / 12 assert dodeca / dodeca == 1 m = Quantity("fake_meter") SI.set_quantity_dimension(m, S.One) SI.set_quantity_scale_factor(m, S.One) assert dodeca * m == 12 * m assert dodeca / m == 12 / m expr1 = kilo * 3 assert isinstance(expr1, Mul) assert expr1.args == (3, kilo) expr2 = kilo * x assert isinstance(expr2, Mul) assert expr2.args == (x, kilo) expr3 = kilo / 3 assert isinstance(expr3, Mul) assert expr3.args == (Rational(1, 3), kilo) assert expr3.args == (S.One/3, kilo) expr4 = kilo / x assert isinstance(expr4, Mul) assert expr4.args == (1/x, kilo) def test_prefix_unit(): m = Quantity("fake_meter", abbrev="m") m.set_global_relative_scale_factor(1, meter) pref = {"m": PREFIXES["m"], "c": PREFIXES["c"], "d": PREFIXES["d"]} q1 = Quantity("millifake_meter", abbrev="mm") q2 = Quantity("centifake_meter", abbrev="cm") q3 = Quantity("decifake_meter", abbrev="dm") SI.set_quantity_dimension(q1, length) SI.set_quantity_scale_factor(q1, PREFIXES["m"]) SI.set_quantity_scale_factor(q1, PREFIXES["c"]) SI.set_quantity_scale_factor(q1, PREFIXES["d"]) res = [q1, q2, q3] prefs = prefix_unit(m, pref) assert set(prefs) == set(res) assert set(map(lambda v: v.abbrev, prefs)) == set(symbols("mm,cm,dm")) def test_bases(): assert kilo.base == 10 assert kibi.base == 2 def test_repr(): assert eval(repr(kilo)) == kilo assert eval(repr(kibi)) == kibi sympy-sympy-1.9/sympy/physics/units/tests/test_quantities.py000066400000000000000000000373311412543434000247000ustar00rootroot00000000000000from sympy import (Abs, Add, Function, Number, Rational, S, Symbol, diff, exp, integrate, log, sin, sqrt, symbols) from sympy.physics.units import (amount_of_substance, convert_to, find_unit, volume, kilometer, joule) from sympy.physics.units.definitions import (amu, au, centimeter, coulomb, day, foot, grams, hour, inch, kg, km, m, meter, millimeter, minute, quart, s, second, speed_of_light, bit, byte, kibibyte, mebibyte, gibibyte, tebibyte, pebibyte, exbibyte, kilogram, gravitational_constant) from sympy.physics.units.definitions.dimension_definitions import ( Dimension, charge, length, time, temperature, pressure, energy ) from sympy.physics.units.prefixes import PREFIXES, kilo from sympy.physics.units.quantities import Quantity from sympy.physics.units.systems import SI from sympy.testing.pytest import XFAIL, raises, warns_deprecated_sympy k = PREFIXES["k"] def test_str_repr(): assert str(kg) == "kilogram" def test_eq(): # simple test assert 10*m == 10*m assert 10*m != 10*s def test_convert_to(): q = Quantity("q1") q.set_global_relative_scale_factor(S(5000), meter) assert q.convert_to(m) == 5000*m assert speed_of_light.convert_to(m / s) == 299792458 * m / s # TODO: eventually support this kind of conversion: # assert (2*speed_of_light).convert_to(m / s) == 2 * 299792458 * m / s assert day.convert_to(s) == 86400*s # Wrong dimension to convert: assert q.convert_to(s) == q assert speed_of_light.convert_to(m) == speed_of_light expr = joule*second conv = convert_to(expr, joule) assert conv == joule*second def test_Quantity_definition(): q = Quantity("s10", abbrev="sabbr") q.set_global_relative_scale_factor(10, second) u = Quantity("u", abbrev="dam") u.set_global_relative_scale_factor(10, meter) km = Quantity("km") km.set_global_relative_scale_factor(kilo, meter) v = Quantity("u") v.set_global_relative_scale_factor(5*kilo, meter) assert q.scale_factor == 10 assert q.dimension == time assert q.abbrev == Symbol("sabbr") assert u.dimension == length assert u.scale_factor == 10 assert u.abbrev == Symbol("dam") assert km.scale_factor == 1000 assert km.func(*km.args) == km assert km.func(*km.args).args == km.args assert v.dimension == length assert v.scale_factor == 5000 with warns_deprecated_sympy(): Quantity('invalid', 'dimension', 1) with warns_deprecated_sympy(): Quantity('mismatch', dimension=length, scale_factor=kg) def test_abbrev(): u = Quantity("u") u.set_global_relative_scale_factor(S.One, meter) assert u.name == Symbol("u") assert u.abbrev == Symbol("u") u = Quantity("u", abbrev="om") u.set_global_relative_scale_factor(S(2), meter) assert u.name == Symbol("u") assert u.abbrev == Symbol("om") assert u.scale_factor == 2 assert isinstance(u.scale_factor, Number) u = Quantity("u", abbrev="ikm") u.set_global_relative_scale_factor(3*kilo, meter) assert u.abbrev == Symbol("ikm") assert u.scale_factor == 3000 def test_print(): u = Quantity("unitname", abbrev="dam") assert repr(u) == "unitname" assert str(u) == "unitname" def test_Quantity_eq(): u = Quantity("u", abbrev="dam") v = Quantity("v1") assert u != v v = Quantity("v2", abbrev="ds") assert u != v v = Quantity("v3", abbrev="dm") assert u != v def test_add_sub(): u = Quantity("u") v = Quantity("v") w = Quantity("w") u.set_global_relative_scale_factor(S(10), meter) v.set_global_relative_scale_factor(S(5), meter) w.set_global_relative_scale_factor(S(2), second) assert isinstance(u + v, Add) assert (u + v.convert_to(u)) == (1 + S.Half)*u # TODO: eventually add this: # assert (u + v).convert_to(u) == (1 + S.Half)*u assert isinstance(u - v, Add) assert (u - v.convert_to(u)) == S.Half*u # TODO: eventually add this: # assert (u - v).convert_to(u) == S.Half*u def test_quantity_abs(): v_w1 = Quantity('v_w1') v_w2 = Quantity('v_w2') v_w3 = Quantity('v_w3') v_w1.set_global_relative_scale_factor(1, meter/second) v_w2.set_global_relative_scale_factor(1, meter/second) v_w3.set_global_relative_scale_factor(1, meter/second) expr = v_w3 - Abs(v_w1 - v_w2) assert SI.get_dimensional_expr(v_w1) == (length/time).name Dq = Dimension(SI.get_dimensional_expr(expr)) with warns_deprecated_sympy(): Dq1 = Dimension(Quantity.get_dimensional_expr(expr)) assert Dq == Dq1 assert SI.get_dimension_system().get_dimensional_dependencies(Dq) == { 'length': 1, 'time': -1, } assert meter == sqrt(meter**2) def test_check_unit_consistency(): u = Quantity("u") v = Quantity("v") w = Quantity("w") u.set_global_relative_scale_factor(S(10), meter) v.set_global_relative_scale_factor(S(5), meter) w.set_global_relative_scale_factor(S(2), second) def check_unit_consistency(expr): SI._collect_factor_and_dimension(expr) raises(ValueError, lambda: check_unit_consistency(u + w)) raises(ValueError, lambda: check_unit_consistency(u - w)) raises(ValueError, lambda: check_unit_consistency(u + 1)) raises(ValueError, lambda: check_unit_consistency(u - 1)) raises(ValueError, lambda: check_unit_consistency(1 - exp(u / w))) def test_mul_div(): u = Quantity("u") v = Quantity("v") t = Quantity("t") ut = Quantity("ut") v2 = Quantity("v") u.set_global_relative_scale_factor(S(10), meter) v.set_global_relative_scale_factor(S(5), meter) t.set_global_relative_scale_factor(S(2), second) ut.set_global_relative_scale_factor(S(20), meter*second) v2.set_global_relative_scale_factor(S(5), meter/second) assert 1 / u == u**(-1) assert u / 1 == u v1 = u / t v2 = v # Pow only supports structural equality: assert v1 != v2 assert v1 == v2.convert_to(v1) # TODO: decide whether to allow such expression in the future # (requires somehow manipulating the core). # assert u / Quantity('l2', dimension=length, scale_factor=2) == 5 assert u * 1 == u ut1 = u * t ut2 = ut # Mul only supports structural equality: assert ut1 != ut2 assert ut1 == ut2.convert_to(ut1) # Mul only supports structural equality: lp1 = Quantity("lp1") lp1.set_global_relative_scale_factor(S(2), 1/meter) assert u * lp1 != 20 assert u**0 == 1 assert u**1 == u # TODO: Pow only support structural equality: u2 = Quantity("u2") u3 = Quantity("u3") u2.set_global_relative_scale_factor(S(100), meter**2) u3.set_global_relative_scale_factor(Rational(1, 10), 1/meter) assert u ** 2 != u2 assert u ** -1 != u3 assert u ** 2 == u2.convert_to(u) assert u ** -1 == u3.convert_to(u) def test_units(): assert convert_to((5*m/s * day) / km, 1) == 432 assert convert_to(foot / meter, meter) == Rational(3048, 10000) # amu is a pure mass so mass/mass gives a number, not an amount (mol) # TODO: need better simplification routine: assert str(convert_to(grams/amu, grams).n(2)) == '6.0e+23' # Light from the sun needs about 8.3 minutes to reach earth t = (1*au / speed_of_light) / minute # TODO: need a better way to simplify expressions containing units: t = convert_to(convert_to(t, meter / minute), meter) assert t.simplify() == Rational(49865956897, 5995849160) # TODO: fix this, it should give `m` without `Abs` assert sqrt(m**2) == m assert (sqrt(m))**2 == m t = Symbol('t') assert integrate(t*m/s, (t, 1*s, 5*s)) == 12*m*s assert (t * m/s).integrate((t, 1*s, 5*s)) == 12*m*s def test_issue_quart(): assert convert_to(4 * quart / inch ** 3, meter) == 231 assert convert_to(4 * quart / inch ** 3, millimeter) == 231 def test_issue_5565(): assert (m < s).is_Relational def test_find_unit(): assert find_unit('coulomb') == ['coulomb', 'coulombs', 'coulomb_constant'] assert find_unit(coulomb) == ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] assert find_unit(charge) == ['C', 'coulomb', 'coulombs', 'planck_charge', 'elementary_charge'] assert find_unit(inch) == [ 'm', 'au', 'cm', 'dm', 'ft', 'km', 'ly', 'mi', 'mm', 'nm', 'pm', 'um', 'yd', 'nmi', 'feet', 'foot', 'inch', 'mile', 'yard', 'meter', 'miles', 'yards', 'inches', 'meters', 'micron', 'microns', 'decimeter', 'kilometer', 'lightyear', 'nanometer', 'picometer', 'centimeter', 'decimeters', 'kilometers', 'lightyears', 'micrometer', 'millimeter', 'nanometers', 'picometers', 'centimeters', 'micrometers', 'millimeters', 'nautical_mile', 'planck_length', 'nautical_miles', 'astronomical_unit', 'astronomical_units'] assert find_unit(inch**-1) == ['D', 'dioptre', 'optical_power'] assert find_unit(length**-1) == ['D', 'dioptre', 'optical_power'] assert find_unit(inch ** 3) == [ 'l', 'cl', 'dl', 'ml', 'liter', 'quart', 'liters', 'quarts', 'deciliter', 'centiliter', 'deciliters', 'milliliter', 'centiliters', 'milliliters', 'planck_volume'] assert find_unit('voltage') == ['V', 'v', 'volt', 'volts', 'planck_voltage'] def test_Quantity_derivative(): x = symbols("x") assert diff(x*meter, x) == meter assert diff(x**3*meter**2, x) == 3*x**2*meter**2 assert diff(meter, meter) == 1 assert diff(meter**2, meter) == 2*meter def test_quantity_postprocessing(): q1 = Quantity('q1') q2 = Quantity('q2') SI.set_quantity_dimension(q1, length*pressure**2*temperature/time) SI.set_quantity_dimension(q2, energy*pressure*temperature/(length**2*time)) assert q1 + q2 q = q1 + q2 Dq = Dimension(SI.get_dimensional_expr(q)) assert SI.get_dimension_system().get_dimensional_dependencies(Dq) == { 'length': -1, 'mass': 2, 'temperature': 1, 'time': -5, } def test_factor_and_dimension(): assert (3000, Dimension(1)) == SI._collect_factor_and_dimension(3000) assert (1001, length) == SI._collect_factor_and_dimension(meter + km) assert (2, length/time) == SI._collect_factor_and_dimension( meter/second + 36*km/(10*hour)) x, y = symbols('x y') assert (x + y/100, length) == SI._collect_factor_and_dimension( x*m + y*centimeter) cH = Quantity('cH') SI.set_quantity_dimension(cH, amount_of_substance/volume) pH = -log(cH) assert (1, volume/amount_of_substance) == SI._collect_factor_and_dimension( exp(pH)) v_w1 = Quantity('v_w1') v_w2 = Quantity('v_w2') v_w1.set_global_relative_scale_factor(Rational(3, 2), meter/second) v_w2.set_global_relative_scale_factor(2, meter/second) expr = Abs(v_w1/2 - v_w2) assert (Rational(5, 4), length/time) == \ SI._collect_factor_and_dimension(expr) expr = Rational(5, 2)*second/meter*v_w1 - 3000 assert (-(2996 + Rational(1, 4)), Dimension(1)) == \ SI._collect_factor_and_dimension(expr) expr = v_w1**(v_w2/v_w1) assert ((Rational(3, 2))**Rational(4, 3), (length/time)**Rational(4, 3)) == \ SI._collect_factor_and_dimension(expr) with warns_deprecated_sympy(): assert (3000, Dimension(1)) == Quantity._collect_factor_and_dimension(3000) @XFAIL def test_factor_and_dimension_with_Abs(): with warns_deprecated_sympy(): v_w1 = Quantity('v_w1', length/time, Rational(3, 2)*meter/second) v_w1.set_global_relative_scale_factor(Rational(3, 2), meter/second) expr = v_w1 - Abs(v_w1) assert (0, length/time) == Quantity._collect_factor_and_dimension(expr) def test_dimensional_expr_of_derivative(): l = Quantity('l') t = Quantity('t') t1 = Quantity('t1') l.set_global_relative_scale_factor(36, km) t.set_global_relative_scale_factor(1, hour) t1.set_global_relative_scale_factor(1, second) x = Symbol('x') y = Symbol('y') f = Function('f') dfdx = f(x, y).diff(x, y) dl_dt = dfdx.subs({f(x, y): l, x: t, y: t1}) assert SI.get_dimensional_expr(dl_dt) ==\ SI.get_dimensional_expr(l / t / t1) ==\ Symbol("length")/Symbol("time")**2 assert SI._collect_factor_and_dimension(dl_dt) ==\ SI._collect_factor_and_dimension(l / t / t1) ==\ (10, length/time**2) def test_get_dimensional_expr_with_function(): v_w1 = Quantity('v_w1') v_w2 = Quantity('v_w2') v_w1.set_global_relative_scale_factor(1, meter/second) v_w2.set_global_relative_scale_factor(1, meter/second) assert SI.get_dimensional_expr(sin(v_w1)) == \ sin(SI.get_dimensional_expr(v_w1)) assert SI.get_dimensional_expr(sin(v_w1/v_w2)) == 1 def test_binary_information(): assert convert_to(kibibyte, byte) == 1024*byte assert convert_to(mebibyte, byte) == 1024**2*byte assert convert_to(gibibyte, byte) == 1024**3*byte assert convert_to(tebibyte, byte) == 1024**4*byte assert convert_to(pebibyte, byte) == 1024**5*byte assert convert_to(exbibyte, byte) == 1024**6*byte assert kibibyte.convert_to(bit) == 8*1024*bit assert byte.convert_to(bit) == 8*bit a = 10*kibibyte*hour assert convert_to(a, byte) == 10240*byte*hour assert convert_to(a, minute) == 600*kibibyte*minute assert convert_to(a, [byte, minute]) == 614400*byte*minute def test_conversion_with_2_nonstandard_dimensions(): good_grade = Quantity("good_grade") kilo_good_grade = Quantity("kilo_good_grade") centi_good_grade = Quantity("centi_good_grade") kilo_good_grade.set_global_relative_scale_factor(1000, good_grade) centi_good_grade.set_global_relative_scale_factor(S.One/10**5, kilo_good_grade) charity_points = Quantity("charity_points") milli_charity_points = Quantity("milli_charity_points") missions = Quantity("missions") milli_charity_points.set_global_relative_scale_factor(S.One/1000, charity_points) missions.set_global_relative_scale_factor(251, charity_points) assert convert_to( kilo_good_grade*milli_charity_points*millimeter, [centi_good_grade, missions, centimeter] ) == S.One * 10**5 / (251*1000) / 10 * centi_good_grade*missions*centimeter def test_eval_subs(): energy, mass, force = symbols('energy mass force') expr1 = energy/mass units = {energy: kilogram*meter**2/second**2, mass: kilogram} assert expr1.subs(units) == meter**2/second**2 expr2 = force/mass units = {force:gravitational_constant*kilogram**2/meter**2, mass:kilogram} assert expr2.subs(units) == gravitational_constant*kilogram/meter**2 def test_issue_14932(): assert (log(inch) - log(2)).simplify() == log(inch/2) assert (log(inch) - log(foot)).simplify() == -log(12) p = symbols('p', positive=True) assert (log(inch) - log(p)).simplify() == log(inch/p) def test_issue_14547(): # the root issue is that an argument with dimensions should # not raise an error when the the `arg - 1` calculation is # performed in the assumptions system from sympy.physics.units import foot, inch from sympy import Eq assert log(foot).is_zero is None assert log(foot).is_positive is None assert log(foot).is_nonnegative is None assert log(foot).is_negative is None assert log(foot).is_algebraic is None assert log(foot).is_rational is None # doesn't raise error assert Eq(log(foot), log(inch)) is not None # might be False or unevaluated x = Symbol('x') e = foot + x assert e.is_Add and set(e.args) == {foot, x} e = foot + 1 assert e.is_Add and set(e.args) == {foot, 1} def test_deprecated_quantity_methods(): step = Quantity("step") with warns_deprecated_sympy(): step.set_dimension(length) step.set_scale_factor(2*meter) assert convert_to(step, centimeter) == 200*centimeter assert convert_to(1000*step/second, kilometer/second) == 2*kilometer/second sympy-sympy-1.9/sympy/physics/units/tests/test_unit_system_cgs_gauss.py000066400000000000000000000051141412543434000271250ustar00rootroot00000000000000from sympy.concrete.tests.test_sums_products import NS from sympy import sqrt, S from sympy.physics.units import convert_to, coulomb_constant, elementary_charge, gravitational_constant, planck from sympy.physics.units.definitions.unit_definitions import statcoulomb, coulomb, second, gram, centimeter, erg, \ newton, joule, dyne, speed_of_light, meter from sympy.physics.units.systems import SI from sympy.physics.units.systems.cgs import cgs_gauss def test_conversion_to_from_si(): assert convert_to(statcoulomb, coulomb, cgs_gauss) == 5*coulomb/149896229 assert convert_to(coulomb, statcoulomb, cgs_gauss) == 149896229*statcoulomb/5 assert convert_to(statcoulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == centimeter**(S(3)/2)*sqrt(gram)/second assert convert_to(coulomb, sqrt(gram*centimeter**3)/second, cgs_gauss) == 149896229*centimeter**(S(3)/2)*sqrt(gram)/(5*second) # SI units have an additional base unit, no conversion in case of electromagnetism: assert convert_to(coulomb, statcoulomb, SI) == coulomb assert convert_to(statcoulomb, coulomb, SI) == statcoulomb # SI without electromagnetism: assert convert_to(erg, joule, SI) == joule/10**7 assert convert_to(erg, joule, cgs_gauss) == joule/10**7 assert convert_to(joule, erg, SI) == 10**7*erg assert convert_to(joule, erg, cgs_gauss) == 10**7*erg assert convert_to(dyne, newton, SI) == newton/10**5 assert convert_to(dyne, newton, cgs_gauss) == newton/10**5 assert convert_to(newton, dyne, SI) == 10**5*dyne assert convert_to(newton, dyne, cgs_gauss) == 10**5*dyne def test_cgs_gauss_convert_constants(): assert convert_to(speed_of_light, centimeter/second, cgs_gauss) == 29979245800*centimeter/second assert convert_to(coulomb_constant, 1, cgs_gauss) == 1 assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, cgs_gauss) == 22468879468420441*meter**2*newton/(25000000000*coulomb**2) assert convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI) == 22468879468420441*meter**2*newton/(2500000*coulomb**2) assert convert_to(coulomb_constant, dyne*centimeter**2/statcoulomb**2, cgs_gauss) == centimeter**2*dyne/statcoulomb**2 assert convert_to(coulomb_constant, 1, SI) == coulomb_constant assert NS(convert_to(coulomb_constant, newton*meter**2/coulomb**2, SI)) == '8987551787.36818*meter**2*newton/coulomb**2' assert convert_to(elementary_charge, statcoulomb, cgs_gauss) assert convert_to(gravitational_constant, dyne*centimeter**2/gram**2, cgs_gauss) assert NS(convert_to(planck, erg*second, cgs_gauss)) == '6.62607015e-27*erg*second' sympy-sympy-1.9/sympy/physics/units/tests/test_unitsystem.py000066400000000000000000000040621412543434000247310ustar00rootroot00000000000000from sympy.physics.units import DimensionSystem, joule, second, ampere from sympy.testing.pytest import warns_deprecated_sympy from sympy import Rational, S from sympy.physics.units.definitions import c, kg, m, s from sympy.physics.units.definitions.dimension_definitions import length, time from sympy.physics.units.quantities import Quantity from sympy.physics.units.unitsystem import UnitSystem def test_definition(): # want to test if the system can have several units of the same dimension dm = Quantity("dm") base = (m, s) # base_dim = (m.dimension, s.dimension) ms = UnitSystem(base, (c, dm), "MS", "MS system") ms.set_quantity_dimension(dm, length) ms.set_quantity_scale_factor(dm, Rational(1, 10)) assert set(ms._base_units) == set(base) assert set(ms._units) == {m, s, c, dm} # assert ms._units == DimensionSystem._sort_dims(base + (velocity,)) assert ms.name == "MS" assert ms.descr == "MS system" def test_str_repr(): assert str(UnitSystem((m, s), name="MS")) == "MS" assert str(UnitSystem((m, s))) == "UnitSystem((meter, second))" assert repr(UnitSystem((m, s))) == "" % (m, s) def test_print_unit_base(): A = Quantity("A") A.set_global_relative_scale_factor(S.One, ampere) Js = Quantity("Js") Js.set_global_relative_scale_factor(S.One, joule*second) mksa = UnitSystem((m, kg, s, A), (Js,)) with warns_deprecated_sympy(): assert mksa.print_unit_base(Js) == m**2*kg*s**-1/1000 def test_extend(): ms = UnitSystem((m, s), (c,)) Js = Quantity("Js") Js.set_global_relative_scale_factor(1, joule*second) mks = ms.extend((kg,), (Js,)) res = UnitSystem((m, s, kg), (c, Js)) assert set(mks._base_units) == set(res._base_units) assert set(mks._units) == set(res._units) def test_dim(): dimsys = UnitSystem((m, kg, s), (c,)) assert dimsys.dim == 3 def test_is_consistent(): dimension_system = DimensionSystem([length, time]) us = UnitSystem([m, s], dimension_system=dimension_system) assert us.is_consistent == True sympy-sympy-1.9/sympy/physics/units/tests/test_util.py000066400000000000000000000142521412543434000234640ustar00rootroot00000000000000from sympy import Pow, Tuple, pi, sstr, sympify, symbols from sympy.physics.units import ( G, centimeter, coulomb, day, degree, gram, hbar, hour, inch, joule, kelvin, kilogram, kilometer, length, meter, mile, minute, newton, planck, planck_length, planck_mass, planck_temperature, planck_time, radians, second, speed_of_light, steradian, time, km) from sympy.physics.units.util import convert_to, check_dimensions from sympy.testing.pytest import raises def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) L = length T = time def test_dim_simplify_add(): # assert Add(L, L) == L assert L + L == L def test_dim_simplify_mul(): # assert Mul(L, T) == L*T assert L*T == L*T def test_dim_simplify_pow(): assert Pow(L, 2) == L**2 def test_dim_simplify_rec(): # assert Mul(Add(L, L), T) == L*T assert (L + L) * T == L*T def test_convert_to_quantities(): assert convert_to(3, meter) == 3 assert convert_to(mile, kilometer) == 25146*kilometer/15625 assert convert_to(meter/second, speed_of_light) == speed_of_light/299792458 assert convert_to(299792458*meter/second, speed_of_light) == speed_of_light assert convert_to(2*299792458*meter/second, speed_of_light) == 2*speed_of_light assert convert_to(speed_of_light, meter/second) == 299792458*meter/second assert convert_to(2*speed_of_light, meter/second) == 599584916*meter/second assert convert_to(day, second) == 86400*second assert convert_to(2*hour, minute) == 120*minute assert convert_to(mile, meter) == 201168*meter/125 assert convert_to(mile/hour, kilometer/hour) == 25146*kilometer/(15625*hour) assert convert_to(3*newton, meter/second) == 3*newton assert convert_to(3*newton, kilogram*meter/second**2) == 3*meter*kilogram/second**2 assert convert_to(kilometer + mile, meter) == 326168*meter/125 assert convert_to(2*kilometer + 3*mile, meter) == 853504*meter/125 assert convert_to(inch**2, meter**2) == 16129*meter**2/25000000 assert convert_to(3*inch**2, meter) == 48387*meter**2/25000000 assert convert_to(2*kilometer/hour + 3*mile/hour, meter/second) == 53344*meter/(28125*second) assert convert_to(2*kilometer/hour + 3*mile/hour, centimeter/second) == 213376*centimeter/(1125*second) assert convert_to(kilometer * (mile + kilometer), meter) == 2609344 * meter ** 2 assert convert_to(steradian, coulomb) == steradian assert convert_to(radians, degree) == 180*degree/pi assert convert_to(radians, [meter, degree]) == 180*degree/pi assert convert_to(pi*radians, degree) == 180*degree assert convert_to(pi, degree) == 180*degree def test_convert_to_tuples_of_quantities(): assert convert_to(speed_of_light, [meter, second]) == 299792458 * meter / second assert convert_to(speed_of_light, (meter, second)) == 299792458 * meter / second assert convert_to(speed_of_light, Tuple(meter, second)) == 299792458 * meter / second assert convert_to(joule, [meter, kilogram, second]) == kilogram*meter**2/second**2 assert convert_to(joule, [centimeter, gram, second]) == 10000000*centimeter**2*gram/second**2 assert convert_to(299792458*meter/second, [speed_of_light]) == speed_of_light assert convert_to(speed_of_light / 2, [meter, second, kilogram]) == meter/second*299792458 / 2 # This doesn't make physically sense, but let's keep it as a conversion test: assert convert_to(2 * speed_of_light, [meter, second, kilogram]) == 2 * 299792458 * meter / second assert convert_to(G, [G, speed_of_light, planck]) == 1.0*G assert NS(convert_to(meter, [G, speed_of_light, hbar]), n=7) == '6.187142e+34*gravitational_constant**0.5000000*hbar**0.5000000/speed_of_light**1.500000' assert NS(convert_to(planck_mass, kilogram), n=7) == '2.176434e-8*kilogram' assert NS(convert_to(planck_length, meter), n=7) == '1.616255e-35*meter' assert NS(convert_to(planck_time, second), n=6) == '5.39125e-44*second' assert NS(convert_to(planck_temperature, kelvin), n=7) == '1.416784e+32*kelvin' assert NS(convert_to(convert_to(meter, [G, speed_of_light, planck]), meter), n=10) == '1.000000000*meter' def test_eval_simplify(): from sympy.physics.units import cm, mm, km, m, K, kilo from sympy.core.symbol import symbols x, y = symbols('x y') assert (cm/mm).simplify() == 10 assert (km/m).simplify() == 1000 assert (km/cm).simplify() == 100000 assert (10*x*K*km**2/m/cm).simplify() == 1000000000*x*kelvin assert (cm/km/m).simplify() == 1/(10000000*centimeter) assert (3*kilo*meter).simplify() == 3000*meter assert (4*kilo*meter/(2*kilometer)).simplify() == 2 assert (4*kilometer**2/(kilo*meter)**2).simplify() == 4 def test_quantity_simplify(): from sympy.physics.units.util import quantity_simplify from sympy.physics.units import kilo, foot from sympy.core.symbol import symbols x, y = symbols('x y') assert quantity_simplify(x*(8*kilo*newton*meter + y)) == x*(8000*meter*newton + y) assert quantity_simplify(foot*inch*(foot + inch)) == foot**2*(foot + foot/12)/12 assert quantity_simplify(foot*inch*(foot*foot + inch*(foot + inch))) == foot**2*(foot**2 + foot/12*(foot + foot/12))/12 assert quantity_simplify(2**(foot/inch*kilo/1000)*inch) == 4096*foot/12 assert quantity_simplify(foot**2*inch + inch**2*foot) == 13*foot**3/144 def test_check_dimensions(): x = symbols('x') assert check_dimensions(inch + x) == inch + x assert check_dimensions(length + x) == length + x # after subs we get 2*length; check will clear the constant assert check_dimensions((length + x).subs(x, length)) == length assert check_dimensions(newton*meter + joule) == joule + meter*newton raises(ValueError, lambda: check_dimensions(inch + 1)) raises(ValueError, lambda: check_dimensions(length + 1)) raises(ValueError, lambda: check_dimensions(length + time)) raises(ValueError, lambda: check_dimensions(meter + second)) raises(ValueError, lambda: check_dimensions(2 * meter + second)) raises(ValueError, lambda: check_dimensions(2 * meter + 3 * second)) raises(ValueError, lambda: check_dimensions(1 / second + 1 / meter)) raises(ValueError, lambda: check_dimensions(2 * meter*(mile + centimeter) + km)) sympy-sympy-1.9/sympy/physics/units/unitsystem.py000066400000000000000000000164351412543434000225370ustar00rootroot00000000000000""" Unit system for physical quantities; include definition of constants. """ from typing import Dict from sympy import S, Mul, Pow, Add, Function, Derivative from sympy.physics.units.dimensions import _QuantityMapper from sympy.utilities.exceptions import SymPyDeprecationWarning from .dimensions import Dimension class UnitSystem(_QuantityMapper): """ UnitSystem represents a coherent set of units. A unit system is basically a dimension system with notions of scales. Many of the methods are defined in the same way. It is much better if all base units have a symbol. """ _unit_systems = {} # type: Dict[str, UnitSystem] def __init__(self, base_units, units=(), name="", descr="", dimension_system=None): UnitSystem._unit_systems[name] = self self.name = name self.descr = descr self._base_units = base_units self._dimension_system = dimension_system self._units = tuple(set(base_units) | set(units)) self._base_units = tuple(base_units) super().__init__() def __str__(self): """ Return the name of the system. If it does not exist, then it makes a list of symbols (or names) of the base dimensions. """ if self.name != "": return self.name else: return "UnitSystem((%s))" % ", ".join( str(d) for d in self._base_units) def __repr__(self): return '' % repr(self._base_units) def extend(self, base, units=(), name="", description="", dimension_system=None): """Extend the current system into a new one. Take the base and normal units of the current system to merge them to the base and normal units given in argument. If not provided, name and description are overridden by empty strings. """ base = self._base_units + tuple(base) units = self._units + tuple(units) return UnitSystem(base, units, name, description, dimension_system) def print_unit_base(self, unit): """ Useless method. DO NOT USE, use instead ``convert_to``. Give the string expression of a unit in term of the basis. Units are displayed by decreasing power. """ SymPyDeprecationWarning( deprecated_since_version="1.2", issue=13336, feature="print_unit_base", useinstead="convert_to", ).warn() from sympy.physics.units import convert_to return convert_to(unit, self._base_units) def get_dimension_system(self): return self._dimension_system def get_quantity_dimension(self, unit): qdm = self.get_dimension_system()._quantity_dimension_map if unit in qdm: return qdm[unit] return super().get_quantity_dimension(unit) def get_quantity_scale_factor(self, unit): qsfm = self.get_dimension_system()._quantity_scale_factors if unit in qsfm: return qsfm[unit] return super().get_quantity_scale_factor(unit) @staticmethod def get_unit_system(unit_system): if isinstance(unit_system, UnitSystem): return unit_system if unit_system not in UnitSystem._unit_systems: raise ValueError( "Unit system is not supported. Currently" "supported unit systems are {}".format( ", ".join(sorted(UnitSystem._unit_systems)) ) ) return UnitSystem._unit_systems[unit_system] @staticmethod def get_default_unit_system(): return UnitSystem._unit_systems["SI"] @property def dim(self): """ Give the dimension of the system. That is return the number of units forming the basis. """ return len(self._base_units) @property def is_consistent(self): """ Check if the underlying dimension system is consistent. """ # test is performed in DimensionSystem return self.get_dimension_system().is_consistent def get_dimensional_expr(self, expr): from sympy import Mul, Add, Pow, Derivative from sympy import Function from sympy.physics.units import Quantity if isinstance(expr, Mul): return Mul(*[self.get_dimensional_expr(i) for i in expr.args]) elif isinstance(expr, Pow): return self.get_dimensional_expr(expr.base) ** expr.exp elif isinstance(expr, Add): return self.get_dimensional_expr(expr.args[0]) elif isinstance(expr, Derivative): dim = self.get_dimensional_expr(expr.expr) for independent, count in expr.variable_count: dim /= self.get_dimensional_expr(independent)**count return dim elif isinstance(expr, Function): args = [self.get_dimensional_expr(arg) for arg in expr.args] if all(i == 1 for i in args): return S.One return expr.func(*args) elif isinstance(expr, Quantity): return self.get_quantity_dimension(expr).name return S.One def _collect_factor_and_dimension(self, expr): """ Return tuple with scale factor expression and dimension expression. """ from sympy.physics.units import Quantity if isinstance(expr, Quantity): return expr.scale_factor, expr.dimension elif isinstance(expr, Mul): factor = 1 dimension = Dimension(1) for arg in expr.args: arg_factor, arg_dim = self._collect_factor_and_dimension(arg) factor *= arg_factor dimension *= arg_dim return factor, dimension elif isinstance(expr, Pow): factor, dim = self._collect_factor_and_dimension(expr.base) exp_factor, exp_dim = self._collect_factor_and_dimension(expr.exp) if exp_dim.is_dimensionless: exp_dim = 1 return factor ** exp_factor, dim ** (exp_factor * exp_dim) elif isinstance(expr, Add): factor, dim = self._collect_factor_and_dimension(expr.args[0]) for addend in expr.args[1:]: addend_factor, addend_dim = \ self._collect_factor_and_dimension(addend) if dim != addend_dim: raise ValueError( 'Dimension of "{}" is {}, ' 'but it should be {}'.format( addend, addend_dim, dim)) factor += addend_factor return factor, dim elif isinstance(expr, Derivative): factor, dim = self._collect_factor_and_dimension(expr.args[0]) for independent, count in expr.variable_count: ifactor, idim = self._collect_factor_and_dimension(independent) factor /= ifactor**count dim /= idim**count return factor, dim elif isinstance(expr, Function): fds = [self._collect_factor_and_dimension( arg) for arg in expr.args] return (expr.func(*(f[0] for f in fds)), expr.func(*(d[1] for d in fds))) elif isinstance(expr, Dimension): return 1, expr else: return expr, Dimension(1) sympy-sympy-1.9/sympy/physics/units/util.py000066400000000000000000000170751412543434000212710ustar00rootroot00000000000000""" Several methods to simplify expressions involving unit objects. """ from functools import reduce from collections.abc import Iterable from sympy import Add, Mul, Pow, Tuple, sympify from sympy.core.compatibility import ordered from sympy.matrices.common import NonInvertibleMatrixError from sympy.physics.units.dimensions import Dimension from sympy.physics.units.prefixes import Prefix from sympy.physics.units.quantities import Quantity from sympy.utilities.iterables import sift def _get_conversion_matrix_for_expr(expr, target_units, unit_system): from sympy import Matrix dimension_system = unit_system.get_dimension_system() expr_dim = Dimension(unit_system.get_dimensional_expr(expr)) dim_dependencies = dimension_system.get_dimensional_dependencies(expr_dim, mark_dimensionless=True) target_dims = [Dimension(unit_system.get_dimensional_expr(x)) for x in target_units] canon_dim_units = [i for x in target_dims for i in dimension_system.get_dimensional_dependencies(x, mark_dimensionless=True)] canon_expr_units = {i for i in dim_dependencies} if not canon_expr_units.issubset(set(canon_dim_units)): return None seen = set() canon_dim_units = [i for i in canon_dim_units if not (i in seen or seen.add(i))] camat = Matrix([[dimension_system.get_dimensional_dependencies(i, mark_dimensionless=True).get(j, 0) for i in target_dims] for j in canon_dim_units]) exprmat = Matrix([dim_dependencies.get(k, 0) for k in canon_dim_units]) try: res_exponents = camat.solve(exprmat) except NonInvertibleMatrixError: return None return res_exponents def convert_to(expr, target_units, unit_system="SI"): """ Convert ``expr`` to the same expression with all of its units and quantities represented as factors of ``target_units``, whenever the dimension is compatible. ``target_units`` may be a single unit/quantity, or a collection of units/quantities. Examples ======== >>> from sympy.physics.units import speed_of_light, meter, gram, second, day >>> from sympy.physics.units import mile, newton, kilogram, atomic_mass_constant >>> from sympy.physics.units import kilometer, centimeter >>> from sympy.physics.units import gravitational_constant, hbar >>> from sympy.physics.units import convert_to >>> convert_to(mile, kilometer) 25146*kilometer/15625 >>> convert_to(mile, kilometer).n() 1.609344*kilometer >>> convert_to(speed_of_light, meter/second) 299792458*meter/second >>> convert_to(day, second) 86400*second >>> 3*newton 3*newton >>> convert_to(3*newton, kilogram*meter/second**2) 3*kilogram*meter/second**2 >>> convert_to(atomic_mass_constant, gram) 1.660539060e-24*gram Conversion to multiple units: >>> convert_to(speed_of_light, [meter, second]) 299792458*meter/second >>> convert_to(3*newton, [centimeter, gram, second]) 300000*centimeter*gram/second**2 Conversion to Planck units: >>> convert_to(atomic_mass_constant, [gravitational_constant, speed_of_light, hbar]).n() 7.62963087839509e-20*hbar**0.5*speed_of_light**0.5/gravitational_constant**0.5 """ from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) if not isinstance(target_units, (Iterable, Tuple)): target_units = [target_units] if isinstance(expr, Add): return Add.fromiter(convert_to(i, target_units, unit_system) for i in expr.args) expr = sympify(expr) if not isinstance(expr, Quantity) and expr.has(Quantity): expr = expr.replace(lambda x: isinstance(x, Quantity), lambda x: x.convert_to(target_units, unit_system)) def get_total_scale_factor(expr): if isinstance(expr, Mul): return reduce(lambda x, y: x * y, [get_total_scale_factor(i) for i in expr.args]) elif isinstance(expr, Pow): return get_total_scale_factor(expr.base) ** expr.exp elif isinstance(expr, Quantity): return unit_system.get_quantity_scale_factor(expr) return expr depmat = _get_conversion_matrix_for_expr(expr, target_units, unit_system) if depmat is None: return expr expr_scale_factor = get_total_scale_factor(expr) return expr_scale_factor * Mul.fromiter((1/get_total_scale_factor(u) * u) ** p for u, p in zip(target_units, depmat)) def quantity_simplify(expr): """Return an equivalent expression in which prefixes are replaced with numerical values and all units of a given dimension are the unified in a canonical manner. Examples ======== >>> from sympy.physics.units.util import quantity_simplify >>> from sympy.physics.units.prefixes import kilo >>> from sympy.physics.units import foot, inch >>> quantity_simplify(kilo*foot*inch) 250*foot**2/3 >>> quantity_simplify(foot - 6*inch) foot/2 """ if expr.is_Atom or not expr.has(Prefix, Quantity): return expr # replace all prefixes with numerical values p = expr.atoms(Prefix) expr = expr.xreplace({p: p.scale_factor for p in p}) # replace all quantities of given dimension with a canonical # quantity, chosen from those in the expression d = sift(expr.atoms(Quantity), lambda i: i.dimension) for k in d: if len(d[k]) == 1: continue v = list(ordered(d[k])) ref = v[0]/v[0].scale_factor expr = expr.xreplace({vi: ref*vi.scale_factor for vi in v[1:]}) return expr def check_dimensions(expr, unit_system="SI"): """Return expr if units in addends have the same base dimensions, else raise a ValueError.""" # the case of adding a number to a dimensional quantity # is ignored for the sake of SymPy core routines, so this # function will raise an error now if such an addend is # found. # Also, when doing substitutions, multiplicative constants # might be introduced, so remove those now from sympy.physics.units import UnitSystem unit_system = UnitSystem.get_unit_system(unit_system) def addDict(dict1, dict2): """Merge dictionaries by adding values of common keys and removing keys with value of 0.""" dict3 = {**dict1, **dict2} for key, value in dict3.items(): if key in dict1 and key in dict2: dict3[key] = value + dict1[key] return {key:val for key, val in dict3.items() if val != 0} adds = expr.atoms(Add) DIM_OF = unit_system.get_dimension_system().get_dimensional_dependencies for a in adds: deset = set() for ai in a.args: if ai.is_number: deset.add(()) continue dims = [] skip = False dimdict = {} for i in Mul.make_args(ai): if i.has(Quantity): i = Dimension(unit_system.get_dimensional_expr(i)) if i.has(Dimension): dimdict = addDict(dimdict, DIM_OF(i)) elif i.free_symbols: skip = True break dims.extend(dimdict.items()) if not skip: deset.add(tuple(sorted(dims))) if len(deset) > 1: raise ValueError( "addends have incompatible dimensions: {}".format(deset)) # clear multiplicative constants on Dimensions which may be # left after substitution reps = {} for m in expr.atoms(Mul): if any(isinstance(i, Dimension) for i in m.args): reps[m] = m.func(*[ i for i in m.args if not i.is_number]) return expr.xreplace(reps) sympy-sympy-1.9/sympy/physics/vector/000077500000000000000000000000001412543434000200705ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/vector/__init__.py000066400000000000000000000017311412543434000222030ustar00rootroot00000000000000__all__ = [ 'CoordinateSym', 'ReferenceFrame', 'Dyadic', 'Vector', 'Point', 'cross', 'dot', 'express', 'time_derivative', 'outer', 'kinematic_equations', 'get_motion_params', 'partial_velocity', 'dynamicsymbols', 'vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex', 'init_vprinting', 'curl', 'divergence', 'gradient', 'is_conservative', 'is_solenoidal', 'scalar_potential', 'scalar_potential_difference', ] from .frame import CoordinateSym, ReferenceFrame from .dyadic import Dyadic from .vector import Vector from .point import Point from .functions import (cross, dot, express, time_derivative, outer, kinematic_equations, get_motion_params, partial_velocity, dynamicsymbols) from .printing import (vprint, vsstrrepr, vsprint, vpprint, vlatex, init_vprinting) from .fieldfunctions import (curl, divergence, gradient, is_conservative, is_solenoidal, scalar_potential, scalar_potential_difference) sympy-sympy-1.9/sympy/physics/vector/dyadic.py000066400000000000000000000456661412543434000217200ustar00rootroot00000000000000from sympy.core.backend import sympify, Add, ImmutableMatrix as Matrix from sympy.core.evalf import EvalfMixin, prec_to_dps from sympy.printing.defaults import Printable __all__ = ['Dyadic'] class Dyadic(Printable, EvalfMixin): """A Dyadic object. See: https://en.wikipedia.org/wiki/Dyadic_tensor Kane, T., Levinson, D. Dynamics Theory and Applications. 1985 McGraw-Hill A more powerful way to represent a rigid body's inertia. While it is more complex, by choosing Dyadic components to be in body fixed basis vectors, the resulting matrix is equivalent to the inertia tensor. """ is_number = False def __init__(self, inlist): """ Just like Vector's init, you shouldn't call this unless creating a zero dyadic. zd = Dyadic(0) Stores a Dyadic as a list of lists; the inner list has the measure number and the two unit vectors; the outerlist holds each unique unit vector pair. """ self.args = [] if inlist == 0: inlist = [] while len(inlist) != 0: added = 0 for i, v in enumerate(self.args): if ((str(inlist[0][1]) == str(self.args[i][1])) and (str(inlist[0][2]) == str(self.args[i][2]))): self.args[i] = (self.args[i][0] + inlist[0][0], inlist[0][1], inlist[0][2]) inlist.remove(inlist[0]) added = 1 break if added != 1: self.args.append(inlist[0]) inlist.remove(inlist[0]) i = 0 # This code is to remove empty parts from the list while i < len(self.args): if ((self.args[i][0] == 0) | (self.args[i][1] == 0) | (self.args[i][2] == 0)): self.args.remove(self.args[i]) i -= 1 i += 1 @property def func(self): """Returns the class Dyadic. """ return Dyadic def __add__(self, other): """The add operator for Dyadic. """ other = _check_dyadic(other) return Dyadic(self.args + other.args) def __and__(self, other): """The inner product operator for a Dyadic and a Dyadic or Vector. Parameters ========== other : Dyadic or Vector The other Dyadic or Vector to take the inner product with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer >>> N = ReferenceFrame('N') >>> D1 = outer(N.x, N.y) >>> D2 = outer(N.y, N.y) >>> D1.dot(D2) (N.x|N.y) >>> D1.dot(N.y) N.x """ from sympy.physics.vector.vector import Vector, _check_vector if isinstance(other, Dyadic): other = _check_dyadic(other) ol = Dyadic(0) for i, v in enumerate(self.args): for i2, v2 in enumerate(other.args): ol += v[0] * v2[0] * (v[2] & v2[1]) * (v[1] | v2[2]) else: other = _check_vector(other) ol = Vector(0) for i, v in enumerate(self.args): ol += v[0] * v[1] * (v[2] & other) return ol def __truediv__(self, other): """Divides the Dyadic by a sympifyable expression. """ return self.__mul__(1 / other) def __eq__(self, other): """Tests for equality. Is currently weak; needs stronger comparison testing """ if other == 0: other = Dyadic(0) other = _check_dyadic(other) if (self.args == []) and (other.args == []): return True elif (self.args == []) or (other.args == []): return False return set(self.args) == set(other.args) def __mul__(self, other): """Multiplies the Dyadic by a sympifyable expression. Parameters ========== other : Sympafiable The scalar to multiply this Dyadic with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer >>> N = ReferenceFrame('N') >>> d = outer(N.x, N.x) >>> 5 * d 5*(N.x|N.x) """ newlist = [v for v in self.args] for i, v in enumerate(newlist): newlist[i] = (sympify(other) * newlist[i][0], newlist[i][1], newlist[i][2]) return Dyadic(newlist) def __ne__(self, other): return not self == other def __neg__(self): return self * -1 def _latex(self, printer): ar = self.args # just to shorten things if len(ar) == 0: return str(0) ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): # if the coef of the dyadic is 1, we skip the 1 if ar[i][0] == 1: ol.append(' + ' + printer._print(ar[i][1]) + r"\otimes " + printer._print(ar[i][2])) # if the coef of the dyadic is -1, we skip the 1 elif ar[i][0] == -1: ol.append(' - ' + printer._print(ar[i][1]) + r"\otimes " + printer._print(ar[i][2])) # If the coefficient of the dyadic is not 1 or -1, # we might wrap it in parentheses, for readability. elif ar[i][0] != 0: arg_str = printer._print(ar[i][0]) if isinstance(ar[i][0], Add): arg_str = '(%s)' % arg_str if arg_str.startswith('-'): arg_str = arg_str[1:] str_start = ' - ' else: str_start = ' + ' ol.append(str_start + arg_str + printer._print(ar[i][1]) + r"\otimes " + printer._print(ar[i][2])) outstr = ''.join(ol) if outstr.startswith(' + '): outstr = outstr[3:] elif outstr.startswith(' '): outstr = outstr[1:] return outstr def _pretty(self, printer): e = self class Fake: baseline = 0 def render(self, *args, **kwargs): ar = e.args # just to shorten things mpp = printer if len(ar) == 0: return str(0) bar = "\N{CIRCLED TIMES}" if printer._use_unicode else "|" ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): # if the coef of the dyadic is 1, we skip the 1 if ar[i][0] == 1: ol.extend([" + ", mpp.doprint(ar[i][1]), bar, mpp.doprint(ar[i][2])]) # if the coef of the dyadic is -1, we skip the 1 elif ar[i][0] == -1: ol.extend([" - ", mpp.doprint(ar[i][1]), bar, mpp.doprint(ar[i][2])]) # If the coefficient of the dyadic is not 1 or -1, # we might wrap it in parentheses, for readability. elif ar[i][0] != 0: if isinstance(ar[i][0], Add): arg_str = mpp._print( ar[i][0]).parens()[0] else: arg_str = mpp.doprint(ar[i][0]) if arg_str.startswith("-"): arg_str = arg_str[1:] str_start = " - " else: str_start = " + " ol.extend([str_start, arg_str, " ", mpp.doprint(ar[i][1]), bar, mpp.doprint(ar[i][2])]) outstr = "".join(ol) if outstr.startswith(" + "): outstr = outstr[3:] elif outstr.startswith(" "): outstr = outstr[1:] return outstr return Fake() def __rand__(self, other): """The inner product operator for a Vector or Dyadic, and a Dyadic This is for: Vector dot Dyadic Parameters ========== other : Vector The vector we are dotting with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, dot, outer >>> N = ReferenceFrame('N') >>> d = outer(N.x, N.x) >>> dot(N.x, d) N.x """ from sympy.physics.vector.vector import Vector, _check_vector other = _check_vector(other) ol = Vector(0) for i, v in enumerate(self.args): ol += v[0] * v[2] * (v[1] & other) return ol def __rsub__(self, other): return (-1 * self) + other def __rxor__(self, other): """For a cross product in the form: Vector x Dyadic Parameters ========== other : Vector The Vector that we are crossing this Dyadic with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer, cross >>> N = ReferenceFrame('N') >>> d = outer(N.x, N.x) >>> cross(N.y, d) - (N.z|N.x) """ from sympy.physics.vector.vector import _check_vector other = _check_vector(other) ol = Dyadic(0) for i, v in enumerate(self.args): ol += v[0] * ((other ^ v[1]) | v[2]) return ol def _sympystr(self, printer): """Printing method. """ ar = self.args # just to shorten things if len(ar) == 0: return printer._print(0) ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): # if the coef of the dyadic is 1, we skip the 1 if ar[i][0] == 1: ol.append(' + (' + printer._print(ar[i][1]) + '|' + printer._print(ar[i][2]) + ')') # if the coef of the dyadic is -1, we skip the 1 elif ar[i][0] == -1: ol.append(' - (' + printer._print(ar[i][1]) + '|' + printer._print(ar[i][2]) + ')') # If the coefficient of the dyadic is not 1 or -1, # we might wrap it in parentheses, for readability. elif ar[i][0] != 0: arg_str = printer._print(ar[i][0]) if isinstance(ar[i][0], Add): arg_str = "(%s)" % arg_str if arg_str[0] == '-': arg_str = arg_str[1:] str_start = ' - ' else: str_start = ' + ' ol.append(str_start + arg_str + '*(' + printer._print(ar[i][1]) + '|' + printer._print(ar[i][2]) + ')') outstr = ''.join(ol) if outstr.startswith(' + '): outstr = outstr[3:] elif outstr.startswith(' '): outstr = outstr[1:] return outstr def __sub__(self, other): """The subtraction operator. """ return self.__add__(other * -1) def __xor__(self, other): """For a cross product in the form: Dyadic x Vector. Parameters ========== other : Vector The Vector that we are crossing this Dyadic with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer, cross >>> N = ReferenceFrame('N') >>> d = outer(N.x, N.x) >>> cross(d, N.y) (N.x|N.z) """ from sympy.physics.vector.vector import _check_vector other = _check_vector(other) ol = Dyadic(0) for i, v in enumerate(self.args): ol += v[0] * (v[1] | (v[2] ^ other)) return ol __radd__ = __add__ __rmul__ = __mul__ def express(self, frame1, frame2=None): """Expresses this Dyadic in alternate frame(s) The first frame is the list side expression, the second frame is the right side; if Dyadic is in form A.x|B.y, you can express it in two different frames. If no second frame is given, the Dyadic is expressed in only one frame. Calls the global express function Parameters ========== frame1 : ReferenceFrame The frame to express the left side of the Dyadic in frame2 : ReferenceFrame If provided, the frame to express the right side of the Dyadic in Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> N = ReferenceFrame('N') >>> q = dynamicsymbols('q') >>> B = N.orientnew('B', 'Axis', [q, N.z]) >>> d = outer(N.x, N.x) >>> d.express(B, N) cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x) """ from sympy.physics.vector.functions import express return express(self, frame1, frame2) def to_matrix(self, reference_frame, second_reference_frame=None): """Returns the matrix form of the dyadic with respect to one or two reference frames. Parameters ---------- reference_frame : ReferenceFrame The reference frame that the rows and columns of the matrix correspond to. If a second reference frame is provided, this only corresponds to the rows of the matrix. second_reference_frame : ReferenceFrame, optional, default=None The reference frame that the columns of the matrix correspond to. Returns ------- matrix : ImmutableMatrix, shape(3,3) The matrix that gives the 2D tensor form. Examples ======== >>> from sympy import symbols >>> from sympy.physics.vector import ReferenceFrame, Vector >>> Vector.simp = True >>> from sympy.physics.mechanics import inertia >>> Ixx, Iyy, Izz, Ixy, Iyz, Ixz = symbols('Ixx, Iyy, Izz, Ixy, Iyz, Ixz') >>> N = ReferenceFrame('N') >>> inertia_dyadic = inertia(N, Ixx, Iyy, Izz, Ixy, Iyz, Ixz) >>> inertia_dyadic.to_matrix(N) Matrix([ [Ixx, Ixy, Ixz], [Ixy, Iyy, Iyz], [Ixz, Iyz, Izz]]) >>> beta = symbols('beta') >>> A = N.orientnew('A', 'Axis', (beta, N.x)) >>> inertia_dyadic.to_matrix(A) Matrix([ [ Ixx, Ixy*cos(beta) + Ixz*sin(beta), -Ixy*sin(beta) + Ixz*cos(beta)], [ Ixy*cos(beta) + Ixz*sin(beta), Iyy*cos(2*beta)/2 + Iyy/2 + Iyz*sin(2*beta) - Izz*cos(2*beta)/2 + Izz/2, -Iyy*sin(2*beta)/2 + Iyz*cos(2*beta) + Izz*sin(2*beta)/2], [-Ixy*sin(beta) + Ixz*cos(beta), -Iyy*sin(2*beta)/2 + Iyz*cos(2*beta) + Izz*sin(2*beta)/2, -Iyy*cos(2*beta)/2 + Iyy/2 - Iyz*sin(2*beta) + Izz*cos(2*beta)/2 + Izz/2]]) """ if second_reference_frame is None: second_reference_frame = reference_frame return Matrix([i.dot(self).dot(j) for i in reference_frame for j in second_reference_frame]).reshape(3, 3) def doit(self, **hints): """Calls .doit() on each term in the Dyadic""" return sum([Dyadic([(v[0].doit(**hints), v[1], v[2])]) for v in self.args], Dyadic(0)) def dt(self, frame): """Take the time derivative of this Dyadic in a frame. This function calls the global time_derivative method Parameters ========== frame : ReferenceFrame The frame to take the time derivative in Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> N = ReferenceFrame('N') >>> q = dynamicsymbols('q') >>> B = N.orientnew('B', 'Axis', [q, N.z]) >>> d = outer(N.x, N.x) >>> d.dt(B) - q'*(N.y|N.x) - q'*(N.x|N.y) """ from sympy.physics.vector.functions import time_derivative return time_derivative(self, frame) def simplify(self): """Returns a simplified Dyadic.""" out = Dyadic(0) for v in self.args: out += Dyadic([(v[0].simplify(), v[1], v[2])]) return out def subs(self, *args, **kwargs): """Substitution on the Dyadic. Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy import Symbol >>> N = ReferenceFrame('N') >>> s = Symbol('s') >>> a = s*(N.x|N.x) >>> a.subs({s: 2}) 2*(N.x|N.x) """ return sum([Dyadic([(v[0].subs(*args, **kwargs), v[1], v[2])]) for v in self.args], Dyadic(0)) def applyfunc(self, f): """Apply a function to each component of a Dyadic.""" if not callable(f): raise TypeError("`f` must be callable.") out = Dyadic(0) for a, b, c in self.args: out += f(a) * (b|c) return out dot = __and__ cross = __xor__ def _eval_evalf(self, prec): if not self.args: return self new_args = [] for inlist in self.args: new_inlist = list(inlist) new_inlist[0] = inlist[0].evalf(n=prec_to_dps(prec)) new_args.append(tuple(new_inlist)) return Dyadic(new_args) def xreplace(self, rule): """ Replace occurrences of objects within the measure numbers of the Dyadic. Parameters ========== rule : dict-like Expresses a replacement rule. Returns ======= Dyadic Result of the replacement. Examples ======== >>> from sympy import symbols, pi >>> from sympy.physics.vector import ReferenceFrame, outer >>> N = ReferenceFrame('N') >>> D = outer(N.x, N.x) >>> x, y, z = symbols('x y z') >>> ((1 + x*y) * D).xreplace({x: pi}) (pi*y + 1)*(N.x|N.x) >>> ((1 + x*y) * D).xreplace({x: pi, y: 2}) (1 + 2*pi)*(N.x|N.x) Replacements occur only if an entire node in the expression tree is matched: >>> ((x*y + z) * D).xreplace({x*y: pi}) (z + pi)*(N.x|N.x) >>> ((x*y*z) * D).xreplace({x*y: pi}) x*y*z*(N.x|N.x) """ new_args = [] for inlist in self.args: new_inlist = list(inlist) new_inlist[0] = new_inlist[0].xreplace(rule) new_args.append(tuple(new_inlist)) return Dyadic(new_args) def _check_dyadic(other): if not isinstance(other, Dyadic): raise TypeError('A Dyadic must be supplied') return other sympy-sympy-1.9/sympy/physics/vector/fieldfunctions.py000066400000000000000000000205011412543434000234540ustar00rootroot00000000000000from sympy import diff, integrate, S from sympy.physics.vector import Vector, express from sympy.physics.vector.frame import _check_frame from sympy.physics.vector.vector import _check_vector __all__ = ['curl', 'divergence', 'gradient', 'is_conservative', 'is_solenoidal', 'scalar_potential', 'scalar_potential_difference'] def curl(vect, frame): """ Returns the curl of a vector field computed wrt the coordinate symbols of the given frame. Parameters ========== vect : Vector The vector operand frame : ReferenceFrame The reference frame to calculate the curl in Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy.physics.vector import curl >>> R = ReferenceFrame('R') >>> v1 = R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z >>> curl(v1, R) 0 >>> v2 = R[0]*R[1]*R[2]*R.x >>> curl(v2, R) R_x*R_y*R.y - R_x*R_z*R.z """ _check_vector(vect) if vect == 0: return Vector(0) vect = express(vect, frame, variables=True) #A mechanical approach to avoid looping overheads vectx = vect.dot(frame.x) vecty = vect.dot(frame.y) vectz = vect.dot(frame.z) outvec = Vector(0) outvec += (diff(vectz, frame[1]) - diff(vecty, frame[2])) * frame.x outvec += (diff(vectx, frame[2]) - diff(vectz, frame[0])) * frame.y outvec += (diff(vecty, frame[0]) - diff(vectx, frame[1])) * frame.z return outvec def divergence(vect, frame): """ Returns the divergence of a vector field computed wrt the coordinate symbols of the given frame. Parameters ========== vect : Vector The vector operand frame : ReferenceFrame The reference frame to calculate the divergence in Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy.physics.vector import divergence >>> R = ReferenceFrame('R') >>> v1 = R[0]*R[1]*R[2] * (R.x+R.y+R.z) >>> divergence(v1, R) R_x*R_y + R_x*R_z + R_y*R_z >>> v2 = 2*R[1]*R[2]*R.y >>> divergence(v2, R) 2*R_z """ _check_vector(vect) if vect == 0: return S.Zero vect = express(vect, frame, variables=True) vectx = vect.dot(frame.x) vecty = vect.dot(frame.y) vectz = vect.dot(frame.z) out = S.Zero out += diff(vectx, frame[0]) out += diff(vecty, frame[1]) out += diff(vectz, frame[2]) return out def gradient(scalar, frame): """ Returns the vector gradient of a scalar field computed wrt the coordinate symbols of the given frame. Parameters ========== scalar : sympifiable The scalar field to take the gradient of frame : ReferenceFrame The frame to calculate the gradient in Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy.physics.vector import gradient >>> R = ReferenceFrame('R') >>> s1 = R[0]*R[1]*R[2] >>> gradient(s1, R) R_y*R_z*R.x + R_x*R_z*R.y + R_x*R_y*R.z >>> s2 = 5*R[0]**2*R[2] >>> gradient(s2, R) 10*R_x*R_z*R.x + 5*R_x**2*R.z """ _check_frame(frame) outvec = Vector(0) scalar = express(scalar, frame, variables=True) for i, x in enumerate(frame): outvec += diff(scalar, frame[i]) * x return outvec def is_conservative(field): """ Checks if a field is conservative. Parameters ========== field : Vector The field to check for conservative property Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy.physics.vector import is_conservative >>> R = ReferenceFrame('R') >>> is_conservative(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) True >>> is_conservative(R[2] * R.y) False """ #Field is conservative irrespective of frame #Take the first frame in the result of the #separate method of Vector if field == Vector(0): return True frame = list(field.separate())[0] return curl(field, frame).simplify() == Vector(0) def is_solenoidal(field): """ Checks if a field is solenoidal. Parameters ========== field : Vector The field to check for solenoidal property Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy.physics.vector import is_solenoidal >>> R = ReferenceFrame('R') >>> is_solenoidal(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) True >>> is_solenoidal(R[1] * R.y) False """ #Field is solenoidal irrespective of frame #Take the first frame in the result of the #separate method in Vector if field == Vector(0): return True frame = list(field.separate())[0] return divergence(field, frame).simplify() is S.Zero def scalar_potential(field, frame): """ Returns the scalar potential function of a field in a given frame (without the added integration constant). Parameters ========== field : Vector The vector field whose scalar potential function is to be calculated frame : ReferenceFrame The frame to do the calculation in Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy.physics.vector import scalar_potential, gradient >>> R = ReferenceFrame('R') >>> scalar_potential(R.z, R) == R[2] True >>> scalar_field = 2*R[0]**2*R[1]*R[2] >>> grad_field = gradient(scalar_field, R) >>> scalar_potential(grad_field, R) 2*R_x**2*R_y*R_z """ #Check whether field is conservative if not is_conservative(field): raise ValueError("Field is not conservative") if field == Vector(0): return S.Zero #Express the field exntirely in frame #Substitute coordinate variables also _check_frame(frame) field = express(field, frame, variables=True) #Make a list of dimensions of the frame dimensions = [x for x in frame] #Calculate scalar potential function temp_function = integrate(field.dot(dimensions[0]), frame[0]) for i, dim in enumerate(dimensions[1:]): partial_diff = diff(temp_function, frame[i + 1]) partial_diff = field.dot(dim) - partial_diff temp_function += integrate(partial_diff, frame[i + 1]) return temp_function def scalar_potential_difference(field, frame, point1, point2, origin): """ Returns the scalar potential difference between two points in a certain frame, wrt a given field. If a scalar field is provided, its values at the two points are considered. If a conservative vector field is provided, the values of its scalar potential function at the two points are used. Returns (potential at position 2) - (potential at position 1) Parameters ========== field : Vector/sympyfiable The field to calculate wrt frame : ReferenceFrame The frame to do the calculations in point1 : Point The initial Point in given frame position2 : Point The second Point in the given frame origin : Point The Point to use as reference point for position vector calculation Examples ======== >>> from sympy.physics.vector import ReferenceFrame, Point >>> from sympy.physics.vector import scalar_potential_difference >>> R = ReferenceFrame('R') >>> O = Point('O') >>> P = O.locatenew('P', R[0]*R.x + R[1]*R.y + R[2]*R.z) >>> vectfield = 4*R[0]*R[1]*R.x + 2*R[0]**2*R.y >>> scalar_potential_difference(vectfield, R, O, P, O) 2*R_x**2*R_y >>> Q = O.locatenew('O', 3*R.x + R.y + 2*R.z) >>> scalar_potential_difference(vectfield, R, P, Q, O) -2*R_x**2*R_y + 18 """ _check_frame(frame) if isinstance(field, Vector): #Get the scalar potential function scalar_fn = scalar_potential(field, frame) else: #Field is a scalar scalar_fn = field #Express positions in required frame position1 = express(point1.pos_from(origin), frame, variables=True) position2 = express(point2.pos_from(origin), frame, variables=True) #Get the two positions as substitution dicts for coordinate variables subs_dict1 = {} subs_dict2 = {} for i, x in enumerate(frame): subs_dict1[frame[i]] = x.dot(position1) subs_dict2[frame[i]] = x.dot(position2) return scalar_fn.subs(subs_dict2) - scalar_fn.subs(subs_dict1) sympy-sympy-1.9/sympy/physics/vector/frame.py000066400000000000000000001470501412543434000215430ustar00rootroot00000000000000from sympy.core.backend import (diff, expand, sin, cos, sympify, eye, symbols, ImmutableMatrix as Matrix, MatrixBase) from sympy import (trigsimp, solve, Symbol, Dummy) from sympy.physics.vector.vector import Vector, _check_vector from sympy.utilities.misc import translate from warnings import warn __all__ = ['CoordinateSym', 'ReferenceFrame'] class CoordinateSym(Symbol): """ A coordinate symbol/base scalar associated wrt a Reference Frame. Ideally, users should not instantiate this class. Instances of this class must only be accessed through the corresponding frame as 'frame[index]'. CoordinateSyms having the same frame and index parameters are equal (even though they may be instantiated separately). Parameters ========== name : string The display name of the CoordinateSym frame : ReferenceFrame The reference frame this base scalar belongs to index : 0, 1 or 2 The index of the dimension denoted by this coordinate variable Examples ======== >>> from sympy.physics.vector import ReferenceFrame, CoordinateSym >>> A = ReferenceFrame('A') >>> A[1] A_y >>> type(A[0]) >>> a_y = CoordinateSym('a_y', A, 1) >>> a_y == A[1] True """ def __new__(cls, name, frame, index): # We can't use the cached Symbol.__new__ because this class depends on # frame and index, which are not passed to Symbol.__xnew__. assumptions = {} super()._sanitize(assumptions, cls) obj = super().__xnew__(cls, name, **assumptions) _check_frame(frame) if index not in range(0, 3): raise ValueError("Invalid index specified") obj._id = (frame, index) return obj @property def frame(self): return self._id[0] def __eq__(self, other): #Check if the other object is a CoordinateSym of the same frame #and same index if isinstance(other, CoordinateSym): if other._id == self._id: return True return False def __ne__(self, other): return not self == other def __hash__(self): return tuple((self._id[0].__hash__(), self._id[1])).__hash__() class ReferenceFrame: """A reference frame in classical mechanics. ReferenceFrame is a class used to represent a reference frame in classical mechanics. It has a standard basis of three unit vectors in the frame's x, y, and z directions. It also can have a rotation relative to a parent frame; this rotation is defined by a direction cosine matrix relating this frame's basis vectors to the parent frame's basis vectors. It can also have an angular velocity vector, defined in another frame. """ _count = 0 def __init__(self, name, indices=None, latexs=None, variables=None): """ReferenceFrame initialization method. A ReferenceFrame has a set of orthonormal basis vectors, along with orientations relative to other ReferenceFrames and angular velocities relative to other ReferenceFrames. Parameters ========== indices : tuple of str Enables the reference frame's basis unit vectors to be accessed by Python's square bracket indexing notation using the provided three indice strings and alters the printing of the unit vectors to reflect this choice. latexs : tuple of str Alters the LaTeX printing of the reference frame's basis unit vectors to the provided three valid LaTeX strings. Examples ======== >>> from sympy.physics.vector import ReferenceFrame, vlatex >>> N = ReferenceFrame('N') >>> N.x N.x >>> O = ReferenceFrame('O', indices=('1', '2', '3')) >>> O.x O['1'] >>> O['1'] O['1'] >>> P = ReferenceFrame('P', latexs=('A1', 'A2', 'A3')) >>> vlatex(P.x) 'A1' symbols() can be used to create multiple Reference Frames in one step, for example: >>> from sympy.physics.vector import ReferenceFrame >>> from sympy import symbols >>> A, B, C = symbols('A B C', cls=ReferenceFrame) >>> D, E = symbols('D E', cls=ReferenceFrame, indices=('1', '2', '3')) >>> A[0] A_x >>> D.x D['1'] >>> E.y E['2'] >>> type(A) == type(D) True """ if not isinstance(name, str): raise TypeError('Need to supply a valid name') # The if statements below are for custom printing of basis-vectors for # each frame. # First case, when custom indices are supplied if indices is not None: if not isinstance(indices, (tuple, list)): raise TypeError('Supply the indices as a list') if len(indices) != 3: raise ValueError('Supply 3 indices') for i in indices: if not isinstance(i, str): raise TypeError('Indices must be strings') self.str_vecs = [(name + '[\'' + indices[0] + '\']'), (name + '[\'' + indices[1] + '\']'), (name + '[\'' + indices[2] + '\']')] self.pretty_vecs = [(name.lower() + "_" + indices[0]), (name.lower() + "_" + indices[1]), (name.lower() + "_" + indices[2])] self.latex_vecs = [(r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), indices[0])), (r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), indices[1])), (r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), indices[2]))] self.indices = indices # Second case, when no custom indices are supplied else: self.str_vecs = [(name + '.x'), (name + '.y'), (name + '.z')] self.pretty_vecs = [name.lower() + "_x", name.lower() + "_y", name.lower() + "_z"] self.latex_vecs = [(r"\mathbf{\hat{%s}_x}" % name.lower()), (r"\mathbf{\hat{%s}_y}" % name.lower()), (r"\mathbf{\hat{%s}_z}" % name.lower())] self.indices = ['x', 'y', 'z'] # Different step, for custom latex basis vectors if latexs is not None: if not isinstance(latexs, (tuple, list)): raise TypeError('Supply the indices as a list') if len(latexs) != 3: raise ValueError('Supply 3 indices') for i in latexs: if not isinstance(i, str): raise TypeError('Latex entries must be strings') self.latex_vecs = latexs self.name = name self._var_dict = {} #The _dcm_dict dictionary will only store the dcms of adjacent parent-child #relationships. The _dcm_cache dictionary will store calculated dcm along with #all content of _dcm_dict for faster retrieval of dcms. self._dcm_dict = {} self._dcm_cache = {} self._ang_vel_dict = {} self._ang_acc_dict = {} self._dlist = [self._dcm_dict, self._ang_vel_dict, self._ang_acc_dict] self._cur = 0 self._x = Vector([(Matrix([1, 0, 0]), self)]) self._y = Vector([(Matrix([0, 1, 0]), self)]) self._z = Vector([(Matrix([0, 0, 1]), self)]) #Associate coordinate symbols wrt this frame if variables is not None: if not isinstance(variables, (tuple, list)): raise TypeError('Supply the variable names as a list/tuple') if len(variables) != 3: raise ValueError('Supply 3 variable names') for i in variables: if not isinstance(i, str): raise TypeError('Variable names must be strings') else: variables = [name + '_x', name + '_y', name + '_z'] self.varlist = (CoordinateSym(variables[0], self, 0), \ CoordinateSym(variables[1], self, 1), \ CoordinateSym(variables[2], self, 2)) ReferenceFrame._count += 1 self.index = ReferenceFrame._count def __getitem__(self, ind): """ Returns basis vector for the provided index, if the index is a string. If the index is a number, returns the coordinate variable correspon- -ding to that index. """ if not isinstance(ind, str): if ind < 3: return self.varlist[ind] else: raise ValueError("Invalid index provided") if self.indices[0] == ind: return self.x if self.indices[1] == ind: return self.y if self.indices[2] == ind: return self.z else: raise ValueError('Not a defined index') def __iter__(self): return iter([self.x, self.y, self.z]) def __str__(self): """Returns the name of the frame. """ return self.name __repr__ = __str__ def _dict_list(self, other, num): """Returns an inclusive list of reference frames that connect this reference frame to the provided reference frame. Parameters ========== other : ReferenceFrame The other reference frame to look for a connecting relationship to. num : integer ``0``, ``1``, and ``2`` will look for orientation, angular velocity, and angular acceleration relationships between the two frames, respectively. Returns ======= list Inclusive list of reference frames that connect this reference frame to the other reference frame. Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> A = ReferenceFrame('A') >>> B = ReferenceFrame('B') >>> C = ReferenceFrame('C') >>> D = ReferenceFrame('D') >>> B.orient_axis(A, A.x, 1.0) >>> C.orient_axis(B, B.x, 1.0) >>> D.orient_axis(C, C.x, 1.0) >>> D._dict_list(A, 0) [D, C, B, A] Raises ====== ValueError When no path is found between the two reference frames or ``num`` is an incorrect value. """ connect_type = {0: 'orientation', 1: 'angular velocity', 2: 'angular acceleration'} if num not in connect_type.keys(): raise ValueError('Valid values for num are 0, 1, or 2.') possible_connecting_paths = [[self]] oldlist = [[]] while possible_connecting_paths != oldlist: oldlist = possible_connecting_paths[:] # make a copy for frame_list in possible_connecting_paths: frames_adjacent_to_last = frame_list[-1]._dlist[num].keys() for adjacent_frame in frames_adjacent_to_last: if adjacent_frame not in frame_list: connecting_path = frame_list + [adjacent_frame] if connecting_path not in possible_connecting_paths: possible_connecting_paths.append(connecting_path) for connecting_path in oldlist: if connecting_path[-1] != other: possible_connecting_paths.remove(connecting_path) possible_connecting_paths.sort(key=len) if len(possible_connecting_paths) != 0: return possible_connecting_paths[0] # selects the shortest path msg = 'No connecting {} path found between {} and {}.' raise ValueError(msg.format(connect_type[num], self.name, other.name)) def _w_diff_dcm(self, otherframe): """Angular velocity from time differentiating the DCM. """ from sympy.physics.vector.functions import dynamicsymbols dcm2diff = otherframe.dcm(self) diffed = dcm2diff.diff(dynamicsymbols._t) angvelmat = diffed * dcm2diff.T w1 = trigsimp(expand(angvelmat[7]), recursive=True) w2 = trigsimp(expand(angvelmat[2]), recursive=True) w3 = trigsimp(expand(angvelmat[3]), recursive=True) return Vector([(Matrix([w1, w2, w3]), otherframe)]) def variable_map(self, otherframe): """ Returns a dictionary which expresses the coordinate variables of this frame in terms of the variables of otherframe. If Vector.simp is True, returns a simplified version of the mapped values. Else, returns them without simplification. Simplification of the expressions may take time. Parameters ========== otherframe : ReferenceFrame The other frame to map the variables to Examples ======== >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols >>> A = ReferenceFrame('A') >>> q = dynamicsymbols('q') >>> B = A.orientnew('B', 'Axis', [q, A.z]) >>> A.variable_map(B) {A_x: B_x*cos(q(t)) - B_y*sin(q(t)), A_y: B_x*sin(q(t)) + B_y*cos(q(t)), A_z: B_z} """ _check_frame(otherframe) if (otherframe, Vector.simp) in self._var_dict: return self._var_dict[(otherframe, Vector.simp)] else: vars_matrix = self.dcm(otherframe) * Matrix(otherframe.varlist) mapping = {} for i, x in enumerate(self): if Vector.simp: mapping[self.varlist[i]] = trigsimp(vars_matrix[i], method='fu') else: mapping[self.varlist[i]] = vars_matrix[i] self._var_dict[(otherframe, Vector.simp)] = mapping return mapping def ang_acc_in(self, otherframe): """Returns the angular acceleration Vector of the ReferenceFrame. Effectively returns the Vector: ^N alpha ^B which represent the angular acceleration of B in N, where B is self, and N is otherframe. Parameters ========== otherframe : ReferenceFrame The ReferenceFrame which the angular acceleration is returned in. Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A') >>> V = 10 * N.x >>> A.set_ang_acc(N, V) >>> A.ang_acc_in(N) 10*N.x """ _check_frame(otherframe) if otherframe in self._ang_acc_dict: return self._ang_acc_dict[otherframe] else: return self.ang_vel_in(otherframe).dt(otherframe) def ang_vel_in(self, otherframe): """Returns the angular velocity Vector of the ReferenceFrame. Effectively returns the Vector: ^N omega ^B which represent the angular velocity of B in N, where B is self, and N is otherframe. Parameters ========== otherframe : ReferenceFrame The ReferenceFrame which the angular velocity is returned in. Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A') >>> V = 10 * N.x >>> A.set_ang_vel(N, V) >>> A.ang_vel_in(N) 10*N.x """ _check_frame(otherframe) flist = self._dict_list(otherframe, 1) outvec = Vector(0) for i in range(len(flist) - 1): outvec += flist[i]._ang_vel_dict[flist[i + 1]] return outvec def dcm(self, otherframe): r"""Returns the direction cosine matrix relative to the provided reference frame. The returned matrix can be used to express the orthogonal unit vectors of this frame in terms of the orthogonal unit vectors of ``otherframe``. Parameters ========== otherframe : ReferenceFrame The reference frame which the direction cosine matrix of this frame is formed relative to. Examples ======== The following example rotates the reference frame A relative to N by a simple rotation and then calculates the direction cosine matrix of N relative to A. >>> from sympy import symbols, sin, cos >>> from sympy.physics.vector import ReferenceFrame >>> q1 = symbols('q1') >>> N = ReferenceFrame('N') >>> A = N.orientnew('A', 'Axis', (q1, N.x)) >>> N.dcm(A) Matrix([ [1, 0, 0], [0, cos(q1), -sin(q1)], [0, sin(q1), cos(q1)]]) The second row of the above direction cosine matrix represents the ``N.y`` unit vector in N expressed in A. Like so: >>> Ny = 0*A.x + cos(q1)*A.y - sin(q1)*A.z Thus, expressing ``N.y`` in A should return the same result: >>> N.y.express(A) cos(q1)*A.y - sin(q1)*A.z Notes ===== It is import to know what form of the direction cosine matrix is returned. If ``B.dcm(A)`` is called, it means the "direction cosine matrix of B relative to A". This is the matrix :math:`^{\mathbf{A}} \mathbf{R} ^{\mathbf{B}}` shown in the following relationship: .. math:: \begin{bmatrix} \hat{\mathbf{b}}_1 \\ \hat{\mathbf{b}}_2 \\ \hat{\mathbf{b}}_3 \end{bmatrix} = {}^A\mathbf{R}^B \begin{bmatrix} \hat{\mathbf{a}}_1 \\ \hat{\mathbf{a}}_2 \\ \hat{\mathbf{a}}_3 \end{bmatrix}. :math:`{}^A\mathbf{R}^B` is the matrix that expresses the B unit vectors in terms of the A unit vectors. """ _check_frame(otherframe) # Check if the dcm wrt that frame has already been calculated if otherframe in self._dcm_cache: return self._dcm_cache[otherframe] flist = self._dict_list(otherframe, 0) outdcm = eye(3) for i in range(len(flist) - 1): outdcm = outdcm * flist[i]._dcm_dict[flist[i + 1]] # After calculation, store the dcm in dcm cache for faster future # retrieval self._dcm_cache[otherframe] = outdcm otherframe._dcm_cache[self] = outdcm.T return outdcm def _dcm(self, parent, parent_orient): # If parent.oreint(self) is already defined,then # update the _dcm_dict of parent while over write # all content of self._dcm_dict and self._dcm_cache # with new dcm relation. # Else update _dcm_cache and _dcm_dict of both # self and parent. frames = self._dcm_cache.keys() dcm_dict_del = [] dcm_cache_del = [] if parent in frames: for frame in frames: if frame in self._dcm_dict: dcm_dict_del += [frame] dcm_cache_del += [frame] # Reset the _dcm_cache of this frame, and remove it from the # _dcm_caches of the frames it is linked to. Also remove it from the # _dcm_dict of its parent for frame in dcm_dict_del: del frame._dcm_dict[self] for frame in dcm_cache_del: del frame._dcm_cache[self] # Reset the _dcm_dict self._dcm_dict = self._dlist[0] = {} # Reset the _dcm_cache self._dcm_cache = {} else: #Check for loops and raise warning accordingly. visited = [] queue = list(frames) cont = True #Flag to control queue loop. while queue and cont: node = queue.pop(0) if node not in visited: visited.append(node) neighbors = node._dcm_dict.keys() for neighbor in neighbors: if neighbor == parent: warn('Loops are defined among the orientation of frames.' + \ ' This is likely not desired and may cause errors in your calculations.') cont = False break queue.append(neighbor) # Add the dcm relationship to _dcm_dict self._dcm_dict.update({parent: parent_orient.T}) parent._dcm_dict.update({self: parent_orient}) # Update the dcm cache self._dcm_cache.update({parent: parent_orient.T}) parent._dcm_cache.update({self: parent_orient}) def orient_axis(self, parent, axis, angle): """Sets the orientation of this reference frame with respect to a parent reference frame by rotating through an angle about an axis fixed in the parent reference frame. Parameters ========== parent : ReferenceFrame Reference frame that this reference frame will be rotated relative to. axis : Vector Vector fixed in the parent frame about about which this frame is rotated. It need not be a unit vector and the rotation follows the right hand rule. angle : sympifiable Angle in radians by which it the frame is to be rotated. Warns ====== UserWarning If the orientation creates a kinematic loop. Examples ======== Setup variables for the examples: >>> from sympy import symbols >>> from sympy.physics.vector import ReferenceFrame >>> q1 = symbols('q1') >>> N = ReferenceFrame('N') >>> B = ReferenceFrame('B') >>> B.orient_axis(N, N.x, q1) The ``orient_axis()`` method generates a direction cosine matrix and its transpose which defines the orientation of B relative to N and vice versa. Once orient is called, ``dcm()`` outputs the appropriate direction cosine matrix: >>> B.dcm(N) Matrix([ [1, 0, 0], [0, cos(q1), sin(q1)], [0, -sin(q1), cos(q1)]]) >>> N.dcm(B) Matrix([ [1, 0, 0], [0, cos(q1), -sin(q1)], [0, sin(q1), cos(q1)]]) The following two lines show that the sense of the rotation can be defined by negating the vector direction or the angle. Both lines produce the same result. >>> B.orient_axis(N, -N.x, q1) >>> B.orient_axis(N, N.x, -q1) """ from sympy.physics.vector.functions import dynamicsymbols _check_frame(parent) if not isinstance(axis, Vector) and isinstance(angle, Vector): axis, angle = angle, axis axis = _check_vector(axis) amount = sympify(angle) theta = amount parent_orient_axis = [] if not axis.dt(parent) == 0: raise ValueError('Axis cannot be time-varying.') unit_axis = axis.express(parent).normalize() unit_col = unit_axis.args[0][0] parent_orient_axis = ( (eye(3) - unit_col * unit_col.T) * cos(theta) + Matrix([[0, -unit_col[2], unit_col[1]], [unit_col[2], 0, -unit_col[0]], [-unit_col[1], unit_col[0], 0]]) * sin(theta) + unit_col * unit_col.T) self._dcm(parent, parent_orient_axis) thetad = (amount).diff(dynamicsymbols._t) wvec = thetad*axis.express(parent).normalize() self._ang_vel_dict.update({parent: wvec}) parent._ang_vel_dict.update({self: -wvec}) self._var_dict = {} def orient_explicit(self, parent, dcm): """Sets the orientation of this reference frame relative to a parent reference frame by explicitly setting the direction cosine matrix. Parameters ========== parent : ReferenceFrame Reference frame that this reference frame will be rotated relative to. dcm : Matrix, shape(3, 3) Direction cosine matrix that specifies the relative rotation between the two reference frames. Warns ====== UserWarning If the orientation creates a kinematic loop. Examples ======== Setup variables for the examples: >>> from sympy import symbols, Matrix, sin, cos >>> from sympy.physics.vector import ReferenceFrame >>> q1 = symbols('q1') >>> A = ReferenceFrame('A') >>> B = ReferenceFrame('B') >>> N = ReferenceFrame('N') A simple rotation of ``A`` relative to ``N`` about ``N.x`` is defined by the following direction cosine matrix: >>> dcm = Matrix([[1, 0, 0], ... [0, cos(q1), -sin(q1)], ... [0, sin(q1), cos(q1)]]) >>> A.orient_explicit(N, dcm) >>> A.dcm(N) Matrix([ [1, 0, 0], [0, cos(q1), sin(q1)], [0, -sin(q1), cos(q1)]]) This is equivalent to using ``orient_axis()``: >>> B.orient_axis(N, N.x, q1) >>> B.dcm(N) Matrix([ [1, 0, 0], [0, cos(q1), sin(q1)], [0, -sin(q1), cos(q1)]]) **Note carefully that** ``N.dcm(B)`` **(the transpose) would be passed into** ``orient_explicit()`` **for** ``A.dcm(N)`` **to match** ``B.dcm(N)``: >>> A.orient_explicit(N, N.dcm(B)) >>> A.dcm(N) Matrix([ [1, 0, 0], [0, cos(q1), sin(q1)], [0, -sin(q1), cos(q1)]]) """ _check_frame(parent) # amounts must be a Matrix type object # (e.g. sympy.matrices.dense.MutableDenseMatrix). if not isinstance(dcm, MatrixBase): raise TypeError("Amounts must be a sympy Matrix type object.") parent_orient_dcm = [] parent_orient_dcm = dcm self._dcm(parent, parent_orient_dcm) wvec = self._w_diff_dcm(parent) self._ang_vel_dict.update({parent: wvec}) parent._ang_vel_dict.update({self: -wvec}) self._var_dict = {} def _rot(self, axis, angle): """DCM for simple axis 1,2,or 3 rotations.""" if axis == 1: return Matrix([[1, 0, 0], [0, cos(angle), -sin(angle)], [0, sin(angle), cos(angle)]]) elif axis == 2: return Matrix([[cos(angle), 0, sin(angle)], [0, 1, 0], [-sin(angle), 0, cos(angle)]]) elif axis == 3: return Matrix([[cos(angle), -sin(angle), 0], [sin(angle), cos(angle), 0], [0, 0, 1]]) def orient_body_fixed(self, parent, angles, rotation_order): """Rotates this reference frame relative to the parent reference frame by right hand rotating through three successive body fixed simple axis rotations. Each subsequent axis of rotation is about the "body fixed" unit vectors of a new intermediate reference frame. This type of rotation is also referred to rotating through the `Euler and Tait-Bryan Angles`_. .. _Euler and Tait-Bryan Angles: https://en.wikipedia.org/wiki/Euler_angles Parameters ========== parent : ReferenceFrame Reference frame that this reference frame will be rotated relative to. angles : 3-tuple of sympifiable Three angles in radians used for the successive rotations. rotation_order : 3 character string or 3 digit integer Order of the rotations about each intermediate reference frames' unit vectors. The Euler rotation about the X, Z', X'' axes can be specified by the strings ``'XZX'``, ``'131'``, or the integer ``131``. There are 12 unique valid rotation orders (6 Euler and 6 Tait-Bryan): zxz, xyx, yzy, zyz, xzx, yxy, xyz, yzx, zxy, xzy, zyx, and yxz. Warns ====== UserWarning If the orientation creates a kinematic loop. Examples ======== Setup variables for the examples: >>> from sympy import symbols >>> from sympy.physics.vector import ReferenceFrame >>> q1, q2, q3 = symbols('q1, q2, q3') >>> N = ReferenceFrame('N') >>> B = ReferenceFrame('B') >>> B1 = ReferenceFrame('B1') >>> B2 = ReferenceFrame('B2') >>> B3 = ReferenceFrame('B3') For example, a classic Euler Angle rotation can be done by: >>> B.orient_body_fixed(N, (q1, q2, q3), 'XYX') >>> B.dcm(N) Matrix([ [ cos(q2), sin(q1)*sin(q2), -sin(q2)*cos(q1)], [sin(q2)*sin(q3), -sin(q1)*sin(q3)*cos(q2) + cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q3)*cos(q1)*cos(q2)], [sin(q2)*cos(q3), -sin(q1)*cos(q2)*cos(q3) - sin(q3)*cos(q1), -sin(q1)*sin(q3) + cos(q1)*cos(q2)*cos(q3)]]) This rotates reference frame B relative to reference frame N through ``q1`` about ``N.x``, then rotates B again through ``q2`` about ``B.y``, and finally through ``q3`` about ``B.x``. It is equivalent to three successive ``orient_axis()`` calls: >>> B1.orient_axis(N, N.x, q1) >>> B2.orient_axis(B1, B1.y, q2) >>> B3.orient_axis(B2, B2.x, q3) >>> B3.dcm(N) Matrix([ [ cos(q2), sin(q1)*sin(q2), -sin(q2)*cos(q1)], [sin(q2)*sin(q3), -sin(q1)*sin(q3)*cos(q2) + cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q3)*cos(q1)*cos(q2)], [sin(q2)*cos(q3), -sin(q1)*cos(q2)*cos(q3) - sin(q3)*cos(q1), -sin(q1)*sin(q3) + cos(q1)*cos(q2)*cos(q3)]]) Acceptable rotation orders are of length 3, expressed in as a string ``'XYZ'`` or ``'123'`` or integer ``123``. Rotations about an axis twice in a row are prohibited. >>> B.orient_body_fixed(N, (q1, q2, 0), 'ZXZ') >>> B.orient_body_fixed(N, (q1, q2, 0), '121') >>> B.orient_body_fixed(N, (q1, q2, q3), 123) """ _check_frame(parent) amounts = list(angles) for i, v in enumerate(amounts): if not isinstance(v, Vector): amounts[i] = sympify(v) approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '') # make sure XYZ => 123 rot_order = translate(str(rotation_order), 'XYZxyz', '123123') if rot_order not in approved_orders: raise TypeError('The rotation order is not a valid order.') parent_orient_body = [] if not (len(amounts) == 3 & len(rot_order) == 3): raise TypeError('Body orientation takes 3 values & 3 orders') a1 = int(rot_order[0]) a2 = int(rot_order[1]) a3 = int(rot_order[2]) parent_orient_body = (self._rot(a1, amounts[0]) * self._rot(a2, amounts[1]) * self._rot(a3, amounts[2])) self._dcm(parent, parent_orient_body) try: from sympy.polys.polyerrors import CoercionFailed from sympy.physics.vector.functions import kinematic_equations q1, q2, q3 = amounts u1, u2, u3 = symbols('u1, u2, u3', cls=Dummy) templist = kinematic_equations([u1, u2, u3], [q1, q2, q3], 'body', rot_order) templist = [expand(i) for i in templist] td = solve(templist, [u1, u2, u3]) u1 = expand(td[u1]) u2 = expand(td[u2]) u3 = expand(td[u3]) wvec = u1 * self.x + u2 * self.y + u3 * self.z except (CoercionFailed, AssertionError): wvec = self._w_diff_dcm(parent) self._ang_vel_dict.update({parent: wvec}) parent._ang_vel_dict.update({self: -wvec}) self._var_dict = {} def orient_space_fixed(self, parent, angles, rotation_order): """Rotates this reference frame relative to the parent reference frame by right hand rotating through three successive space fixed simple axis rotations. Each subsequent axis of rotation is about the "space fixed" unit vectors of the parent reference frame. Parameters ========== parent : ReferenceFrame Reference frame that this reference frame will be rotated relative to. angles : 3-tuple of sympifiable Three angles in radians used for the successive rotations. rotation_order : 3 character string or 3 digit integer Order of the rotations about the parent reference frame's unit vectors. The order can be specified by the strings ``'XZX'``, ``'131'``, or the integer ``131``. There are 12 unique valid rotation orders. Warns ====== UserWarning If the orientation creates a kinematic loop. Examples ======== Setup variables for the examples: >>> from sympy import symbols >>> from sympy.physics.vector import ReferenceFrame >>> q1, q2, q3 = symbols('q1, q2, q3') >>> N = ReferenceFrame('N') >>> B = ReferenceFrame('B') >>> B1 = ReferenceFrame('B1') >>> B2 = ReferenceFrame('B2') >>> B3 = ReferenceFrame('B3') >>> B.orient_space_fixed(N, (q1, q2, q3), '312') >>> B.dcm(N) Matrix([ [ sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1)], [-sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3)], [ sin(q3)*cos(q2), -sin(q2), cos(q2)*cos(q3)]]) is equivalent to: >>> B1.orient_axis(N, N.z, q1) >>> B2.orient_axis(B1, N.x, q2) >>> B3.orient_axis(B2, N.y, q3) >>> B3.dcm(N).simplify() Matrix([ [ sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1)], [-sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3)], [ sin(q3)*cos(q2), -sin(q2), cos(q2)*cos(q3)]]) It is worth noting that space-fixed and body-fixed rotations are related by the order of the rotations, i.e. the reverse order of body fixed will give space fixed and vice versa. >>> B.orient_space_fixed(N, (q1, q2, q3), '231') >>> B.dcm(N) Matrix([ [cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3), -sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)], [ -sin(q2), cos(q2)*cos(q3), sin(q3)*cos(q2)], [sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3)]]) >>> B.orient_body_fixed(N, (q3, q2, q1), '132') >>> B.dcm(N) Matrix([ [cos(q1)*cos(q2), sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3), -sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)], [ -sin(q2), cos(q2)*cos(q3), sin(q3)*cos(q2)], [sin(q1)*cos(q2), sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3)]]) """ _check_frame(parent) amounts = list(angles) for i, v in enumerate(amounts): if not isinstance(v, Vector): amounts[i] = sympify(v) approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '') # make sure XYZ => 123 rot_order = translate(str(rotation_order), 'XYZxyz', '123123') if rot_order not in approved_orders: raise TypeError('The supplied order is not an approved type') parent_orient_space = [] if not (len(amounts) == 3 & len(rot_order) == 3): raise TypeError('Space orientation takes 3 values & 3 orders') a1 = int(rot_order[0]) a2 = int(rot_order[1]) a3 = int(rot_order[2]) parent_orient_space = (self._rot(a3, amounts[2]) * self._rot(a2, amounts[1]) * self._rot(a1, amounts[0])) self._dcm(parent, parent_orient_space) try: from sympy.polys.polyerrors import CoercionFailed from sympy.physics.vector.functions import kinematic_equations q1, q2, q3 = amounts u1, u2, u3 = symbols('u1, u2, u3', cls=Dummy) templist = kinematic_equations([u1, u2, u3], [q1, q2, q3], 'space', rot_order) templist = [expand(i) for i in templist] td = solve(templist, [u1, u2, u3]) u1 = expand(td[u1]) u2 = expand(td[u2]) u3 = expand(td[u3]) wvec = u1 * self.x + u2 * self.y + u3 * self.z except (CoercionFailed, AssertionError): wvec = self._w_diff_dcm(parent) self._ang_vel_dict.update({parent: wvec}) parent._ang_vel_dict.update({self: -wvec}) self._var_dict = {} def orient_quaternion(self, parent, numbers): """Sets the orientation of this reference frame relative to a parent reference frame via an orientation quaternion. An orientation quaternion is defined as a finite rotation a unit vector, ``(lambda_x, lambda_y, lambda_z)``, by an angle ``theta``. The orientation quaternion is described by four parameters: - ``q0 = cos(theta/2)`` - ``q1 = lambda_x*sin(theta/2)`` - ``q2 = lambda_y*sin(theta/2)`` - ``q3 = lambda_z*sin(theta/2)`` See `Quaternions and Spatial Rotation `_ on Wikipedia for more information. Parameters ========== parent : ReferenceFrame Reference frame that this reference frame will be rotated relative to. numbers : 4-tuple of sympifiable The four quaternion scalar numbers as defined above: ``q0``, ``q1``, ``q2``, ``q3``. Warns ====== UserWarning If the orientation creates a kinematic loop. Examples ======== Setup variables for the examples: >>> from sympy import symbols >>> from sympy.physics.vector import ReferenceFrame >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') >>> N = ReferenceFrame('N') >>> B = ReferenceFrame('B') Set the orientation: >>> B.orient_quaternion(N, (q0, q1, q2, q3)) >>> B.dcm(N) Matrix([ [q0**2 + q1**2 - q2**2 - q3**2, 2*q0*q3 + 2*q1*q2, -2*q0*q2 + 2*q1*q3], [ -2*q0*q3 + 2*q1*q2, q0**2 - q1**2 + q2**2 - q3**2, 2*q0*q1 + 2*q2*q3], [ 2*q0*q2 + 2*q1*q3, -2*q0*q1 + 2*q2*q3, q0**2 - q1**2 - q2**2 + q3**2]]) """ from sympy.physics.vector.functions import dynamicsymbols _check_frame(parent) numbers = list(numbers) for i, v in enumerate(numbers): if not isinstance(v, Vector): numbers[i] = sympify(v) parent_orient_quaternion = [] if not (isinstance(numbers, (list, tuple)) & (len(numbers) == 4)): raise TypeError('Amounts are a list or tuple of length 4') q0, q1, q2, q3 = numbers parent_orient_quaternion = ( Matrix([[q0**2 + q1**2 - q2**2 - q3**2, 2 * (q1 * q2 - q0 * q3), 2 * (q0 * q2 + q1 * q3)], [2 * (q1 * q2 + q0 * q3), q0**2 - q1**2 + q2**2 - q3**2, 2 * (q2 * q3 - q0 * q1)], [2 * (q1 * q3 - q0 * q2), 2 * (q0 * q1 + q2 * q3), q0**2 - q1**2 - q2**2 + q3**2]])) self._dcm(parent, parent_orient_quaternion) t = dynamicsymbols._t q0, q1, q2, q3 = numbers q0d = diff(q0, t) q1d = diff(q1, t) q2d = diff(q2, t) q3d = diff(q3, t) w1 = 2 * (q1d * q0 + q2d * q3 - q3d * q2 - q0d * q1) w2 = 2 * (q2d * q0 + q3d * q1 - q1d * q3 - q0d * q2) w3 = 2 * (q3d * q0 + q1d * q2 - q2d * q1 - q0d * q3) wvec = Vector([(Matrix([w1, w2, w3]), self)]) self._ang_vel_dict.update({parent: wvec}) parent._ang_vel_dict.update({self: -wvec}) self._var_dict = {} def orient(self, parent, rot_type, amounts, rot_order=''): """Sets the orientation of this reference frame relative to another (parent) reference frame. .. note:: It is now recommended to use the ``.orient_axis, .orient_body_fixed, .orient_space_fixed, .orient_quaternion`` methods for the different rotation types. Parameters ========== parent : ReferenceFrame Reference frame that this reference frame will be rotated relative to. rot_type : str The method used to generate the direction cosine matrix. Supported methods are: - ``'Axis'``: simple rotations about a single common axis - ``'DCM'``: for setting the direction cosine matrix directly - ``'Body'``: three successive rotations about new intermediate axes, also called "Euler and Tait-Bryan angles" - ``'Space'``: three successive rotations about the parent frames' unit vectors - ``'Quaternion'``: rotations defined by four parameters which result in a singularity free direction cosine matrix amounts : Expressions defining the rotation angles or direction cosine matrix. These must match the ``rot_type``. See examples below for details. The input types are: - ``'Axis'``: 2-tuple (expr/sym/func, Vector) - ``'DCM'``: Matrix, shape(3,3) - ``'Body'``: 3-tuple of expressions, symbols, or functions - ``'Space'``: 3-tuple of expressions, symbols, or functions - ``'Quaternion'``: 4-tuple of expressions, symbols, or functions rot_order : str or int, optional If applicable, the order of the successive of rotations. The string ``'123'`` and integer ``123`` are equivalent, for example. Required for ``'Body'`` and ``'Space'``. Warns ====== UserWarning If the orientation creates a kinematic loop. """ _check_frame(parent) approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '') rot_order = translate(str(rot_order), 'XYZxyz', '123123') rot_type = rot_type.upper() if rot_order not in approved_orders: raise TypeError('The supplied order is not an approved type') if rot_type == 'AXIS': self.orient_axis(parent, amounts[1], amounts[0]) elif rot_type == 'DCM': self.orient_explicit(parent, amounts) elif rot_type == 'BODY': self.orient_body_fixed(parent, amounts, rot_order) elif rot_type == 'SPACE': self.orient_space_fixed(parent, amounts, rot_order) elif rot_type == 'QUATERNION': self.orient_quaternion(parent, amounts) else: raise NotImplementedError('That is not an implemented rotation') def orientnew(self, newname, rot_type, amounts, rot_order='', variables=None, indices=None, latexs=None): r"""Returns a new reference frame oriented with respect to this reference frame. See ``ReferenceFrame.orient()`` for detailed examples of how to orient reference frames. Parameters ========== newname : str Name for the new reference frame. rot_type : str The method used to generate the direction cosine matrix. Supported methods are: - ``'Axis'``: simple rotations about a single common axis - ``'DCM'``: for setting the direction cosine matrix directly - ``'Body'``: three successive rotations about new intermediate axes, also called "Euler and Tait-Bryan angles" - ``'Space'``: three successive rotations about the parent frames' unit vectors - ``'Quaternion'``: rotations defined by four parameters which result in a singularity free direction cosine matrix amounts : Expressions defining the rotation angles or direction cosine matrix. These must match the ``rot_type``. See examples below for details. The input types are: - ``'Axis'``: 2-tuple (expr/sym/func, Vector) - ``'DCM'``: Matrix, shape(3,3) - ``'Body'``: 3-tuple of expressions, symbols, or functions - ``'Space'``: 3-tuple of expressions, symbols, or functions - ``'Quaternion'``: 4-tuple of expressions, symbols, or functions rot_order : str or int, optional If applicable, the order of the successive of rotations. The string ``'123'`` and integer ``123`` are equivalent, for example. Required for ``'Body'`` and ``'Space'``. indices : tuple of str Enables the reference frame's basis unit vectors to be accessed by Python's square bracket indexing notation using the provided three indice strings and alters the printing of the unit vectors to reflect this choice. latexs : tuple of str Alters the LaTeX printing of the reference frame's basis unit vectors to the provided three valid LaTeX strings. Examples ======== >>> from sympy import symbols >>> from sympy.physics.vector import ReferenceFrame, vlatex >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') >>> N = ReferenceFrame('N') Create a new reference frame A rotated relative to N through a simple rotation. >>> A = N.orientnew('A', 'Axis', (q0, N.x)) Create a new reference frame B rotated relative to N through body-fixed rotations. >>> B = N.orientnew('B', 'Body', (q1, q2, q3), '123') Create a new reference frame C rotated relative to N through a simple rotation with unique indices and LaTeX printing. >>> C = N.orientnew('C', 'Axis', (q0, N.x), indices=('1', '2', '3'), ... latexs=(r'\hat{\mathbf{c}}_1',r'\hat{\mathbf{c}}_2', ... r'\hat{\mathbf{c}}_3')) >>> C['1'] C['1'] >>> print(vlatex(C['1'])) \hat{\mathbf{c}}_1 """ newframe = self.__class__(newname, variables=variables, indices=indices, latexs=latexs) approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '') rot_order = translate(str(rot_order), 'XYZxyz', '123123') rot_type = rot_type.upper() if rot_order not in approved_orders: raise TypeError('The supplied order is not an approved type') if rot_type == 'AXIS': newframe.orient_axis(self, amounts[1], amounts[0]) elif rot_type == 'DCM': newframe.orient_explicit(self, amounts) elif rot_type == 'BODY': newframe.orient_body_fixed(self, amounts, rot_order) elif rot_type == 'SPACE': newframe.orient_space_fixed(self, amounts, rot_order) elif rot_type == 'QUATERNION': newframe.orient_quaternion(self, amounts) else: raise NotImplementedError('That is not an implemented rotation') return newframe def set_ang_acc(self, otherframe, value): """Define the angular acceleration Vector in a ReferenceFrame. Defines the angular acceleration of this ReferenceFrame, in another. Angular acceleration can be defined with respect to multiple different ReferenceFrames. Care must be taken to not create loops which are inconsistent. Parameters ========== otherframe : ReferenceFrame A ReferenceFrame to define the angular acceleration in value : Vector The Vector representing angular acceleration Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A') >>> V = 10 * N.x >>> A.set_ang_acc(N, V) >>> A.ang_acc_in(N) 10*N.x """ if value == 0: value = Vector(0) value = _check_vector(value) _check_frame(otherframe) self._ang_acc_dict.update({otherframe: value}) otherframe._ang_acc_dict.update({self: -value}) def set_ang_vel(self, otherframe, value): """Define the angular velocity vector in a ReferenceFrame. Defines the angular velocity of this ReferenceFrame, in another. Angular velocity can be defined with respect to multiple different ReferenceFrames. Care must be taken to not create loops which are inconsistent. Parameters ========== otherframe : ReferenceFrame A ReferenceFrame to define the angular velocity in value : Vector The Vector representing angular velocity Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A') >>> V = 10 * N.x >>> A.set_ang_vel(N, V) >>> A.ang_vel_in(N) 10*N.x """ if value == 0: value = Vector(0) value = _check_vector(value) _check_frame(otherframe) self._ang_vel_dict.update({otherframe: value}) otherframe._ang_vel_dict.update({self: -value}) @property def x(self): """The basis Vector for the ReferenceFrame, in the x direction. """ return self._x @property def y(self): """The basis Vector for the ReferenceFrame, in the y direction. """ return self._y @property def z(self): """The basis Vector for the ReferenceFrame, in the z direction. """ return self._z def partial_velocity(self, frame, *gen_speeds): """Returns the partial angular velocities of this frame in the given frame with respect to one or more provided generalized speeds. Parameters ========== frame : ReferenceFrame The frame with which the angular velocity is defined in. gen_speeds : functions of time The generalized speeds. Returns ======= partial_velocities : tuple of Vector The partial angular velocity vectors corresponding to the provided generalized speeds. Examples ======== >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols >>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A') >>> u1, u2 = dynamicsymbols('u1, u2') >>> A.set_ang_vel(N, u1 * A.x + u2 * N.y) >>> A.partial_velocity(N, u1) A.x >>> A.partial_velocity(N, u1, u2) (A.x, N.y) """ partials = [self.ang_vel_in(frame).diff(speed, frame, var_in_dcm=False) for speed in gen_speeds] if len(partials) == 1: return partials[0] else: return tuple(partials) def _check_frame(other): from .vector import VectorTypeError if not isinstance(other, ReferenceFrame): raise VectorTypeError(other, ReferenceFrame('A')) sympy-sympy-1.9/sympy/physics/vector/functions.py000066400000000000000000000576761412543434000224770ustar00rootroot00000000000000from functools import reduce from sympy.core.backend import (sympify, diff, sin, cos, Matrix, symbols, Function, S, Symbol) from sympy import integrate, trigsimp from .vector import Vector, _check_vector from .frame import CoordinateSym, _check_frame from .dyadic import Dyadic from .printing import vprint, vsprint, vpprint, vlatex, init_vprinting from sympy.utilities.iterables import iterable from sympy.utilities.misc import translate __all__ = ['cross', 'dot', 'express', 'time_derivative', 'outer', 'kinematic_equations', 'get_motion_params', 'partial_velocity', 'dynamicsymbols', 'vprint', 'vsprint', 'vpprint', 'vlatex', 'init_vprinting'] def cross(vec1, vec2): """Cross product convenience wrapper for Vector.cross(): \n""" if not isinstance(vec1, (Vector, Dyadic)): raise TypeError('Cross product is between two vectors') return vec1 ^ vec2 cross.__doc__ += Vector.cross.__doc__ # type: ignore def dot(vec1, vec2): """Dot product convenience wrapper for Vector.dot(): \n""" if not isinstance(vec1, (Vector, Dyadic)): raise TypeError('Dot product is between two vectors') return vec1 & vec2 dot.__doc__ += Vector.dot.__doc__ # type: ignore def express(expr, frame, frame2=None, variables=False): """ Global function for 'express' functionality. Re-expresses a Vector, scalar(sympyfiable) or Dyadic in given frame. Refer to the local methods of Vector and Dyadic for details. If 'variables' is True, then the coordinate variables (CoordinateSym instances) of other frames present in the vector/scalar field or dyadic expression are also substituted in terms of the base scalars of this frame. Parameters ========== expr : Vector/Dyadic/scalar(sympyfiable) The expression to re-express in ReferenceFrame 'frame' frame: ReferenceFrame The reference frame to express expr in frame2 : ReferenceFrame The other frame required for re-expression(only for Dyadic expr) variables : boolean Specifies whether to substitute the coordinate variables present in expr, in terms of those of frame Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> N = ReferenceFrame('N') >>> q = dynamicsymbols('q') >>> B = N.orientnew('B', 'Axis', [q, N.z]) >>> d = outer(N.x, N.x) >>> from sympy.physics.vector import express >>> express(d, B, N) cos(q)*(B.x|N.x) - sin(q)*(B.y|N.x) >>> express(B.x, N) cos(q)*N.x + sin(q)*N.y >>> express(N[0], B, variables=True) B_x*cos(q) - B_y*sin(q) """ _check_frame(frame) if expr == 0: return expr if isinstance(expr, Vector): #Given expr is a Vector if variables: #If variables attribute is True, substitute #the coordinate variables in the Vector frame_list = [x[-1] for x in expr.args] subs_dict = {} for f in frame_list: subs_dict.update(f.variable_map(frame)) expr = expr.subs(subs_dict) #Re-express in this frame outvec = Vector([]) for i, v in enumerate(expr.args): if v[1] != frame: temp = frame.dcm(v[1]) * v[0] if Vector.simp: temp = temp.applyfunc(lambda x: trigsimp(x, method='fu')) outvec += Vector([(temp, frame)]) else: outvec += Vector([v]) return outvec if isinstance(expr, Dyadic): if frame2 is None: frame2 = frame _check_frame(frame2) ol = Dyadic(0) for i, v in enumerate(expr.args): ol += express(v[0], frame, variables=variables) * \ (express(v[1], frame, variables=variables) | express(v[2], frame2, variables=variables)) return ol else: if variables: #Given expr is a scalar field frame_set = set() expr = sympify(expr) #Substitute all the coordinate variables for x in expr.free_symbols: if isinstance(x, CoordinateSym)and x.frame != frame: frame_set.add(x.frame) subs_dict = {} for f in frame_set: subs_dict.update(f.variable_map(frame)) return expr.subs(subs_dict) return expr def time_derivative(expr, frame, order=1): """ Calculate the time derivative of a vector/scalar field function or dyadic expression in given frame. References ========== https://en.wikipedia.org/wiki/Rotating_reference_frame#Time_derivatives_in_the_two_frames Parameters ========== expr : Vector/Dyadic/sympifyable The expression whose time derivative is to be calculated frame : ReferenceFrame The reference frame to calculate the time derivative in order : integer The order of the derivative to be calculated Examples ======== >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> from sympy import Symbol >>> q1 = Symbol('q1') >>> u1 = dynamicsymbols('u1') >>> N = ReferenceFrame('N') >>> A = N.orientnew('A', 'Axis', [q1, N.x]) >>> v = u1 * N.x >>> A.set_ang_vel(N, 10*A.x) >>> from sympy.physics.vector import time_derivative >>> time_derivative(v, N) u1'*N.x >>> time_derivative(u1*A[0], N) N_x*u1' >>> B = N.orientnew('B', 'Axis', [u1, N.z]) >>> from sympy.physics.vector import outer >>> d = outer(N.x, N.x) >>> time_derivative(d, B) - u1'*(N.y|N.x) - u1'*(N.x|N.y) """ t = dynamicsymbols._t _check_frame(frame) if order == 0: return expr if order % 1 != 0 or order < 0: raise ValueError("Unsupported value of order entered") if isinstance(expr, Vector): outlist = [] for i, v in enumerate(expr.args): if v[1] == frame: outlist += [(express(v[0], frame, variables=True).diff(t), frame)] else: outlist += (time_derivative(Vector([v]), v[1]) + \ (v[1].ang_vel_in(frame) ^ Vector([v]))).args outvec = Vector(outlist) return time_derivative(outvec, frame, order - 1) if isinstance(expr, Dyadic): ol = Dyadic(0) for i, v in enumerate(expr.args): ol += (v[0].diff(t) * (v[1] | v[2])) ol += (v[0] * (time_derivative(v[1], frame) | v[2])) ol += (v[0] * (v[1] | time_derivative(v[2], frame))) return time_derivative(ol, frame, order - 1) else: return diff(express(expr, frame, variables=True), t, order) def outer(vec1, vec2): """Outer product convenience wrapper for Vector.outer():\n""" if not isinstance(vec1, Vector): raise TypeError('Outer product is between two Vectors') return vec1 | vec2 outer.__doc__ += Vector.outer.__doc__ # type: ignore def kinematic_equations(speeds, coords, rot_type, rot_order=''): """Gives equations relating the qdot's to u's for a rotation type. Supply rotation type and order as in orient. Speeds are assumed to be body-fixed; if we are defining the orientation of B in A using by rot_type, the angular velocity of B in A is assumed to be in the form: speed[0]*B.x + speed[1]*B.y + speed[2]*B.z Parameters ========== speeds : list of length 3 The body fixed angular velocity measure numbers. coords : list of length 3 or 4 The coordinates used to define the orientation of the two frames. rot_type : str The type of rotation used to create the equations. Body, Space, or Quaternion only rot_order : str or int If applicable, the order of a series of rotations. Examples ======== >>> from sympy.physics.vector import dynamicsymbols >>> from sympy.physics.vector import kinematic_equations, vprint >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') >>> q1, q2, q3 = dynamicsymbols('q1 q2 q3') >>> vprint(kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313'), ... order=None) [-(u1*sin(q3) + u2*cos(q3))/sin(q2) + q1', -u1*cos(q3) + u2*sin(q3) + q2', (u1*sin(q3) + u2*cos(q3))*cos(q2)/sin(q2) - u3 + q3'] """ # Code below is checking and sanitizing input approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '1', '2', '3', '') # make sure XYZ => 123 and rot_type is in lower case rot_order = translate(str(rot_order), 'XYZxyz', '123123') rot_type = rot_type.lower() if not isinstance(speeds, (list, tuple)): raise TypeError('Need to supply speeds in a list') if len(speeds) != 3: raise TypeError('Need to supply 3 body-fixed speeds') if not isinstance(coords, (list, tuple)): raise TypeError('Need to supply coordinates in a list') if rot_type in ['body', 'space']: if rot_order not in approved_orders: raise ValueError('Not an acceptable rotation order') if len(coords) != 3: raise ValueError('Need 3 coordinates for body or space') # Actual hard-coded kinematic differential equations w1, w2, w3 = speeds if w1 == w2 == w3 == 0: return [S.Zero]*3 q1, q2, q3 = coords q1d, q2d, q3d = [diff(i, dynamicsymbols._t) for i in coords] s1, s2, s3 = [sin(q1), sin(q2), sin(q3)] c1, c2, c3 = [cos(q1), cos(q2), cos(q3)] if rot_type == 'body': if rot_order == '123': return [q1d - (w1 * c3 - w2 * s3) / c2, q2d - w1 * s3 - w2 * c3, q3d - (-w1 * c3 + w2 * s3) * s2 / c2 - w3] if rot_order == '231': return [q1d - (w2 * c3 - w3 * s3) / c2, q2d - w2 * s3 - w3 * c3, q3d - w1 - (- w2 * c3 + w3 * s3) * s2 / c2] if rot_order == '312': return [q1d - (-w1 * s3 + w3 * c3) / c2, q2d - w1 * c3 - w3 * s3, q3d - (w1 * s3 - w3 * c3) * s2 / c2 - w2] if rot_order == '132': return [q1d - (w1 * c3 + w3 * s3) / c2, q2d + w1 * s3 - w3 * c3, q3d - (w1 * c3 + w3 * s3) * s2 / c2 - w2] if rot_order == '213': return [q1d - (w1 * s3 + w2 * c3) / c2, q2d - w1 * c3 + w2 * s3, q3d - (w1 * s3 + w2 * c3) * s2 / c2 - w3] if rot_order == '321': return [q1d - (w2 * s3 + w3 * c3) / c2, q2d - w2 * c3 + w3 * s3, q3d - w1 - (w2 * s3 + w3 * c3) * s2 / c2] if rot_order == '121': return [q1d - (w2 * s3 + w3 * c3) / s2, q2d - w2 * c3 + w3 * s3, q3d - w1 + (w2 * s3 + w3 * c3) * c2 / s2] if rot_order == '131': return [q1d - (-w2 * c3 + w3 * s3) / s2, q2d - w2 * s3 - w3 * c3, q3d - w1 - (w2 * c3 - w3 * s3) * c2 / s2] if rot_order == '212': return [q1d - (w1 * s3 - w3 * c3) / s2, q2d - w1 * c3 - w3 * s3, q3d - (-w1 * s3 + w3 * c3) * c2 / s2 - w2] if rot_order == '232': return [q1d - (w1 * c3 + w3 * s3) / s2, q2d + w1 * s3 - w3 * c3, q3d + (w1 * c3 + w3 * s3) * c2 / s2 - w2] if rot_order == '313': return [q1d - (w1 * s3 + w2 * c3) / s2, q2d - w1 * c3 + w2 * s3, q3d + (w1 * s3 + w2 * c3) * c2 / s2 - w3] if rot_order == '323': return [q1d - (-w1 * c3 + w2 * s3) / s2, q2d - w1 * s3 - w2 * c3, q3d - (w1 * c3 - w2 * s3) * c2 / s2 - w3] if rot_type == 'space': if rot_order == '123': return [q1d - w1 - (w2 * s1 + w3 * c1) * s2 / c2, q2d - w2 * c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / c2] if rot_order == '231': return [q1d - (w1 * c1 + w3 * s1) * s2 / c2 - w2, q2d + w1 * s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / c2] if rot_order == '312': return [q1d - (w1 * s1 + w2 * c1) * s2 / c2 - w3, q2d - w1 * c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / c2] if rot_order == '132': return [q1d - w1 - (-w2 * c1 + w3 * s1) * s2 / c2, q2d - w2 * s1 - w3 * c1, q3d - (w2 * c1 - w3 * s1) / c2] if rot_order == '213': return [q1d - (w1 * s1 - w3 * c1) * s2 / c2 - w2, q2d - w1 * c1 - w3 * s1, q3d - (-w1 * s1 + w3 * c1) / c2] if rot_order == '321': return [q1d - (-w1 * c1 + w2 * s1) * s2 / c2 - w3, q2d - w1 * s1 - w2 * c1, q3d - (w1 * c1 - w2 * s1) / c2] if rot_order == '121': return [q1d - w1 + (w2 * s1 + w3 * c1) * c2 / s2, q2d - w2 * c1 + w3 * s1, q3d - (w2 * s1 + w3 * c1) / s2] if rot_order == '131': return [q1d - w1 - (w2 * c1 - w3 * s1) * c2 / s2, q2d - w2 * s1 - w3 * c1, q3d - (-w2 * c1 + w3 * s1) / s2] if rot_order == '212': return [q1d - (-w1 * s1 + w3 * c1) * c2 / s2 - w2, q2d - w1 * c1 - w3 * s1, q3d - (w1 * s1 - w3 * c1) / s2] if rot_order == '232': return [q1d + (w1 * c1 + w3 * s1) * c2 / s2 - w2, q2d + w1 * s1 - w3 * c1, q3d - (w1 * c1 + w3 * s1) / s2] if rot_order == '313': return [q1d + (w1 * s1 + w2 * c1) * c2 / s2 - w3, q2d - w1 * c1 + w2 * s1, q3d - (w1 * s1 + w2 * c1) / s2] if rot_order == '323': return [q1d - (w1 * c1 - w2 * s1) * c2 / s2 - w3, q2d - w1 * s1 - w2 * c1, q3d - (-w1 * c1 + w2 * s1) / s2] elif rot_type == 'quaternion': if rot_order != '': raise ValueError('Cannot have rotation order for quaternion') if len(coords) != 4: raise ValueError('Need 4 coordinates for quaternion') # Actual hard-coded kinematic differential equations e0, e1, e2, e3 = coords w = Matrix(speeds + [0]) E = Matrix([[e0, -e3, e2, e1], [e3, e0, -e1, e2], [-e2, e1, e0, e3], [-e1, -e2, -e3, e0]]) edots = Matrix([diff(i, dynamicsymbols._t) for i in [e1, e2, e3, e0]]) return list(edots.T - 0.5 * w.T * E.T) else: raise ValueError('Not an approved rotation type for this function') def get_motion_params(frame, **kwargs): """ Returns the three motion parameters - (acceleration, velocity, and position) as vectorial functions of time in the given frame. If a higher order differential function is provided, the lower order functions are used as boundary conditions. For example, given the acceleration, the velocity and position parameters are taken as boundary conditions. The values of time at which the boundary conditions are specified are taken from timevalue1(for position boundary condition) and timevalue2(for velocity boundary condition). If any of the boundary conditions are not provided, they are taken to be zero by default (zero vectors, in case of vectorial inputs). If the boundary conditions are also functions of time, they are converted to constants by substituting the time values in the dynamicsymbols._t time Symbol. This function can also be used for calculating rotational motion parameters. Have a look at the Parameters and Examples for more clarity. Parameters ========== frame : ReferenceFrame The frame to express the motion parameters in acceleration : Vector Acceleration of the object/frame as a function of time velocity : Vector Velocity as function of time or as boundary condition of velocity at time = timevalue1 position : Vector Velocity as function of time or as boundary condition of velocity at time = timevalue1 timevalue1 : sympyfiable Value of time for position boundary condition timevalue2 : sympyfiable Value of time for velocity boundary condition Examples ======== >>> from sympy.physics.vector import ReferenceFrame, get_motion_params, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> from sympy import symbols >>> R = ReferenceFrame('R') >>> v1, v2, v3 = dynamicsymbols('v1 v2 v3') >>> v = v1*R.x + v2*R.y + v3*R.z >>> get_motion_params(R, position = v) (v1''*R.x + v2''*R.y + v3''*R.z, v1'*R.x + v2'*R.y + v3'*R.z, v1*R.x + v2*R.y + v3*R.z) >>> a, b, c = symbols('a b c') >>> v = a*R.x + b*R.y + c*R.z >>> get_motion_params(R, velocity = v) (0, a*R.x + b*R.y + c*R.z, a*t*R.x + b*t*R.y + c*t*R.z) >>> parameters = get_motion_params(R, acceleration = v) >>> parameters[1] a*t*R.x + b*t*R.y + c*t*R.z >>> parameters[2] a*t**2/2*R.x + b*t**2/2*R.y + c*t**2/2*R.z """ ##Helper functions def _process_vector_differential(vectdiff, condition, \ variable, ordinate, frame): """ Helper function for get_motion methods. Finds derivative of vectdiff wrt variable, and its integral using the specified boundary condition at value of variable = ordinate. Returns a tuple of - (derivative, function and integral) wrt vectdiff """ #Make sure boundary condition is independent of 'variable' if condition != 0: condition = express(condition, frame, variables=True) #Special case of vectdiff == 0 if vectdiff == Vector(0): return (0, 0, condition) #Express vectdiff completely in condition's frame to give vectdiff1 vectdiff1 = express(vectdiff, frame) #Find derivative of vectdiff vectdiff2 = time_derivative(vectdiff, frame) #Integrate and use boundary condition vectdiff0 = Vector(0) lims = (variable, ordinate, variable) for dim in frame: function1 = vectdiff1.dot(dim) abscissa = dim.dot(condition).subs({variable : ordinate}) # Indefinite integral of 'function1' wrt 'variable', using # the given initial condition (ordinate, abscissa). vectdiff0 += (integrate(function1, lims) + abscissa) * dim #Return tuple return (vectdiff2, vectdiff, vectdiff0) ##Function body _check_frame(frame) #Decide mode of operation based on user's input if 'acceleration' in kwargs: mode = 2 elif 'velocity' in kwargs: mode = 1 else: mode = 0 #All the possible parameters in kwargs #Not all are required for every case #If not specified, set to default values(may or may not be used in #calculations) conditions = ['acceleration', 'velocity', 'position', 'timevalue', 'timevalue1', 'timevalue2'] for i, x in enumerate(conditions): if x not in kwargs: if i < 3: kwargs[x] = Vector(0) else: kwargs[x] = S.Zero elif i < 3: _check_vector(kwargs[x]) else: kwargs[x] = sympify(kwargs[x]) if mode == 2: vel = _process_vector_differential(kwargs['acceleration'], kwargs['velocity'], dynamicsymbols._t, kwargs['timevalue2'], frame)[2] pos = _process_vector_differential(vel, kwargs['position'], dynamicsymbols._t, kwargs['timevalue1'], frame)[2] return (kwargs['acceleration'], vel, pos) elif mode == 1: return _process_vector_differential(kwargs['velocity'], kwargs['position'], dynamicsymbols._t, kwargs['timevalue1'], frame) else: vel = time_derivative(kwargs['position'], frame) acc = time_derivative(vel, frame) return (acc, vel, kwargs['position']) def partial_velocity(vel_vecs, gen_speeds, frame): """Returns a list of partial velocities with respect to the provided generalized speeds in the given reference frame for each of the supplied velocity vectors. The output is a list of lists. The outer list has a number of elements equal to the number of supplied velocity vectors. The inner lists are, for each velocity vector, the partial derivatives of that velocity vector with respect to the generalized speeds supplied. Parameters ========== vel_vecs : iterable An iterable of velocity vectors (angular or linear). gen_speeds : iterable An iterable of generalized speeds. frame : ReferenceFrame The reference frame that the partial derivatives are going to be taken in. Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> from sympy.physics.vector import dynamicsymbols >>> from sympy.physics.vector import partial_velocity >>> u = dynamicsymbols('u') >>> N = ReferenceFrame('N') >>> P = Point('P') >>> P.set_vel(N, u * N.x) >>> vel_vecs = [P.vel(N)] >>> gen_speeds = [u] >>> partial_velocity(vel_vecs, gen_speeds, N) [[N.x]] """ if not iterable(vel_vecs): raise TypeError('Velocity vectors must be contained in an iterable.') if not iterable(gen_speeds): raise TypeError('Generalized speeds must be contained in an iterable') vec_partials = [] for vec in vel_vecs: partials = [] for speed in gen_speeds: partials.append(vec.diff(speed, frame, var_in_dcm=False)) vec_partials.append(partials) return vec_partials def dynamicsymbols(names, level=0,**assumptions): """Uses symbols and Function for functions of time. Creates a SymPy UndefinedFunction, which is then initialized as a function of a variable, the default being Symbol('t'). Parameters ========== names : str Names of the dynamic symbols you want to create; works the same way as inputs to symbols level : int Level of differentiation of the returned function; d/dt once of t, twice of t, etc. assumptions : - real(bool) : This is used to set the dynamicsymbol as real, by default is False. - positive(bool) : This is used to set the dynamicsymbol as positive, by default is False. - commutative(bool) : This is used to set the commutative property of a dynamicsymbol, by default is True. - integer(bool) : This is used to set the dynamicsymbol as integer, by default is False. Examples ======== >>> from sympy.physics.vector import dynamicsymbols >>> from sympy import diff, Symbol >>> q1 = dynamicsymbols('q1') >>> q1 q1(t) >>> q2 = dynamicsymbols('q2', real=True) >>> q2.is_real True >>> q3 = dynamicsymbols('q3', positive=True) >>> q3.is_positive True >>> q4, q5 = dynamicsymbols('q4,q5', commutative=False) >>> bool(q4*q5 != q5*q4) True >>> q6 = dynamicsymbols('q6', integer=True) >>> q6.is_integer True >>> diff(q1, Symbol('t')) Derivative(q1(t), t) """ esses = symbols(names, cls=Function,**assumptions) t = dynamicsymbols._t if iterable(esses): esses = [reduce(diff, [t] * level, e(t)) for e in esses] return esses else: return reduce(diff, [t] * level, esses(t)) dynamicsymbols._t = Symbol('t') # type: ignore dynamicsymbols._str = '\'' # type: ignore sympy-sympy-1.9/sympy/physics/vector/point.py000066400000000000000000000501721412543434000216000ustar00rootroot00000000000000from .vector import Vector, _check_vector from .frame import _check_frame from warnings import warn __all__ = ['Point'] class Point: """This object represents a point in a dynamic system. It stores the: position, velocity, and acceleration of a point. The position is a vector defined as the vector distance from a parent point to this point. Parameters ========== name : string The display name of the Point Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> N = ReferenceFrame('N') >>> O = Point('O') >>> P = Point('P') >>> u1, u2, u3 = dynamicsymbols('u1 u2 u3') >>> O.set_vel(N, u1 * N.x + u2 * N.y + u3 * N.z) >>> O.acc(N) u1'*N.x + u2'*N.y + u3'*N.z symbols() can be used to create multiple Points in a single step, for example: >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> from sympy import symbols >>> N = ReferenceFrame('N') >>> u1, u2 = dynamicsymbols('u1 u2') >>> A, B = symbols('A B', cls=Point) >>> type(A) >>> A.set_vel(N, u1 * N.x + u2 * N.y) >>> B.set_vel(N, u2 * N.x + u1 * N.y) >>> A.acc(N) - B.acc(N) (u1' - u2')*N.x + (-u1' + u2')*N.y """ def __init__(self, name): """Initialization of a Point object. """ self.name = name self._pos_dict = {} self._vel_dict = {} self._acc_dict = {} self._pdlist = [self._pos_dict, self._vel_dict, self._acc_dict] def __str__(self): return self.name __repr__ = __str__ def _check_point(self, other): if not isinstance(other, Point): raise TypeError('A Point must be supplied') def _pdict_list(self, other, num): """Returns a list of points that gives the shortest path with respect to position, velocity, or acceleration from this point to the provided point. Parameters ========== other : Point A point that may be related to this point by position, velocity, or acceleration. num : integer 0 for searching the position tree, 1 for searching the velocity tree, and 2 for searching the acceleration tree. Returns ======= list of Points A sequence of points from self to other. Notes ===== It isn't clear if num = 1 or num = 2 actually works because the keys to ``_vel_dict`` and ``_acc_dict`` are :class:`ReferenceFrame` objects which do not have the ``_pdlist`` attribute. """ outlist = [[self]] oldlist = [[]] while outlist != oldlist: oldlist = outlist[:] for i, v in enumerate(outlist): templist = v[-1]._pdlist[num].keys() for i2, v2 in enumerate(templist): if not v.__contains__(v2): littletemplist = v + [v2] if not outlist.__contains__(littletemplist): outlist.append(littletemplist) for i, v in enumerate(oldlist): if v[-1] != other: outlist.remove(v) outlist.sort(key=len) if len(outlist) != 0: return outlist[0] raise ValueError('No Connecting Path found between ' + other.name + ' and ' + self.name) def a1pt_theory(self, otherpoint, outframe, interframe): """Sets the acceleration of this point with the 1-point theory. The 1-point theory for point acceleration looks like this: ^N a^P = ^B a^P + ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B x r^OP) + 2 ^N omega^B x ^B v^P where O is a point fixed in B, P is a point moving in B, and B is rotating in frame N. Parameters ========== otherpoint : Point The first point of the 1-point theory (O) outframe : ReferenceFrame The frame we want this point's acceleration defined in (N) fixedframe : ReferenceFrame The intermediate frame in this calculation (B) Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> from sympy.physics.vector import dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> q = dynamicsymbols('q') >>> q2 = dynamicsymbols('q2') >>> qd = dynamicsymbols('q', 1) >>> q2d = dynamicsymbols('q2', 1) >>> N = ReferenceFrame('N') >>> B = ReferenceFrame('B') >>> B.set_ang_vel(N, 5 * B.y) >>> O = Point('O') >>> P = O.locatenew('P', q * B.x) >>> P.set_vel(B, qd * B.x + q2d * B.y) >>> O.set_vel(N, 0) >>> P.a1pt_theory(O, N, B) (-25*q + q'')*B.x + q2''*B.y - 10*q'*B.z """ _check_frame(outframe) _check_frame(interframe) self._check_point(otherpoint) dist = self.pos_from(otherpoint) v = self.vel(interframe) a1 = otherpoint.acc(outframe) a2 = self.acc(interframe) omega = interframe.ang_vel_in(outframe) alpha = interframe.ang_acc_in(outframe) self.set_acc(outframe, a2 + 2 * (omega ^ v) + a1 + (alpha ^ dist) + (omega ^ (omega ^ dist))) return self.acc(outframe) def a2pt_theory(self, otherpoint, outframe, fixedframe): """Sets the acceleration of this point with the 2-point theory. The 2-point theory for point acceleration looks like this: ^N a^P = ^N a^O + ^N alpha^B x r^OP + ^N omega^B x (^N omega^B x r^OP) where O and P are both points fixed in frame B, which is rotating in frame N. Parameters ========== otherpoint : Point The first point of the 2-point theory (O) outframe : ReferenceFrame The frame we want this point's acceleration defined in (N) fixedframe : ReferenceFrame The frame in which both points are fixed (B) Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> q = dynamicsymbols('q') >>> qd = dynamicsymbols('q', 1) >>> N = ReferenceFrame('N') >>> B = N.orientnew('B', 'Axis', [q, N.z]) >>> O = Point('O') >>> P = O.locatenew('P', 10 * B.x) >>> O.set_vel(N, 5 * N.x) >>> P.a2pt_theory(O, N, B) - 10*q'**2*B.x + 10*q''*B.y """ _check_frame(outframe) _check_frame(fixedframe) self._check_point(otherpoint) dist = self.pos_from(otherpoint) a = otherpoint.acc(outframe) omega = fixedframe.ang_vel_in(outframe) alpha = fixedframe.ang_acc_in(outframe) self.set_acc(outframe, a + (alpha ^ dist) + (omega ^ (omega ^ dist))) return self.acc(outframe) def acc(self, frame): """The acceleration Vector of this Point in a ReferenceFrame. Parameters ========== frame : ReferenceFrame The frame in which the returned acceleration vector will be defined in Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> N = ReferenceFrame('N') >>> p1 = Point('p1') >>> p1.set_acc(N, 10 * N.x) >>> p1.acc(N) 10*N.x """ _check_frame(frame) if not (frame in self._acc_dict): if self._vel_dict[frame] != 0: return (self._vel_dict[frame]).dt(frame) else: return Vector(0) return self._acc_dict[frame] def locatenew(self, name, value): """Creates a new point with a position defined from this point. Parameters ========== name : str The name for the new point value : Vector The position of the new point relative to this point Examples ======== >>> from sympy.physics.vector import ReferenceFrame, Point >>> N = ReferenceFrame('N') >>> P1 = Point('P1') >>> P2 = P1.locatenew('P2', 10 * N.x) """ if not isinstance(name, str): raise TypeError('Must supply a valid name') if value == 0: value = Vector(0) value = _check_vector(value) p = Point(name) p.set_pos(self, value) self.set_pos(p, -value) return p def pos_from(self, otherpoint): """Returns a Vector distance between this Point and the other Point. Parameters ========== otherpoint : Point The otherpoint we are locating this one relative to Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> N = ReferenceFrame('N') >>> p1 = Point('p1') >>> p2 = Point('p2') >>> p1.set_pos(p2, 10 * N.x) >>> p1.pos_from(p2) 10*N.x """ outvec = Vector(0) plist = self._pdict_list(otherpoint, 0) for i in range(len(plist) - 1): outvec += plist[i]._pos_dict[plist[i + 1]] return outvec def set_acc(self, frame, value): """Used to set the acceleration of this Point in a ReferenceFrame. Parameters ========== frame : ReferenceFrame The frame in which this point's acceleration is defined value : Vector The vector value of this point's acceleration in the frame Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> N = ReferenceFrame('N') >>> p1 = Point('p1') >>> p1.set_acc(N, 10 * N.x) >>> p1.acc(N) 10*N.x """ if value == 0: value = Vector(0) value = _check_vector(value) _check_frame(frame) self._acc_dict.update({frame: value}) def set_pos(self, otherpoint, value): """Used to set the position of this point w.r.t. another point. Parameters ========== otherpoint : Point The other point which this point's location is defined relative to value : Vector The vector which defines the location of this point Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> N = ReferenceFrame('N') >>> p1 = Point('p1') >>> p2 = Point('p2') >>> p1.set_pos(p2, 10 * N.x) >>> p1.pos_from(p2) 10*N.x """ if value == 0: value = Vector(0) value = _check_vector(value) self._check_point(otherpoint) self._pos_dict.update({otherpoint: value}) otherpoint._pos_dict.update({self: -value}) def set_vel(self, frame, value): """Sets the velocity Vector of this Point in a ReferenceFrame. Parameters ========== frame : ReferenceFrame The frame in which this point's velocity is defined value : Vector The vector value of this point's velocity in the frame Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> N = ReferenceFrame('N') >>> p1 = Point('p1') >>> p1.set_vel(N, 10 * N.x) >>> p1.vel(N) 10*N.x """ if value == 0: value = Vector(0) value = _check_vector(value) _check_frame(frame) self._vel_dict.update({frame: value}) def v1pt_theory(self, otherpoint, outframe, interframe): """Sets the velocity of this point with the 1-point theory. The 1-point theory for point velocity looks like this: ^N v^P = ^B v^P + ^N v^O + ^N omega^B x r^OP where O is a point fixed in B, P is a point moving in B, and B is rotating in frame N. Parameters ========== otherpoint : Point The first point of the 1-point theory (O) outframe : ReferenceFrame The frame we want this point's velocity defined in (N) interframe : ReferenceFrame The intermediate frame in this calculation (B) Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame >>> from sympy.physics.vector import dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> q = dynamicsymbols('q') >>> q2 = dynamicsymbols('q2') >>> qd = dynamicsymbols('q', 1) >>> q2d = dynamicsymbols('q2', 1) >>> N = ReferenceFrame('N') >>> B = ReferenceFrame('B') >>> B.set_ang_vel(N, 5 * B.y) >>> O = Point('O') >>> P = O.locatenew('P', q * B.x) >>> P.set_vel(B, qd * B.x + q2d * B.y) >>> O.set_vel(N, 0) >>> P.v1pt_theory(O, N, B) q'*B.x + q2'*B.y - 5*q*B.z """ _check_frame(outframe) _check_frame(interframe) self._check_point(otherpoint) dist = self.pos_from(otherpoint) v1 = self.vel(interframe) v2 = otherpoint.vel(outframe) omega = interframe.ang_vel_in(outframe) self.set_vel(outframe, v1 + v2 + (omega ^ dist)) return self.vel(outframe) def v2pt_theory(self, otherpoint, outframe, fixedframe): """Sets the velocity of this point with the 2-point theory. The 2-point theory for point velocity looks like this: ^N v^P = ^N v^O + ^N omega^B x r^OP where O and P are both points fixed in frame B, which is rotating in frame N. Parameters ========== otherpoint : Point The first point of the 2-point theory (O) outframe : ReferenceFrame The frame we want this point's velocity defined in (N) fixedframe : ReferenceFrame The frame in which both points are fixed (B) Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> q = dynamicsymbols('q') >>> qd = dynamicsymbols('q', 1) >>> N = ReferenceFrame('N') >>> B = N.orientnew('B', 'Axis', [q, N.z]) >>> O = Point('O') >>> P = O.locatenew('P', 10 * B.x) >>> O.set_vel(N, 5 * N.x) >>> P.v2pt_theory(O, N, B) 5*N.x + 10*q'*B.y """ _check_frame(outframe) _check_frame(fixedframe) self._check_point(otherpoint) dist = self.pos_from(otherpoint) v = otherpoint.vel(outframe) omega = fixedframe.ang_vel_in(outframe) self.set_vel(outframe, v + (omega ^ dist)) return self.vel(outframe) def vel(self, frame): """The velocity Vector of this Point in the ReferenceFrame. Parameters ========== frame : ReferenceFrame The frame in which the returned velocity vector will be defined in Examples ======== >>> from sympy.physics.vector import Point, ReferenceFrame, dynamicsymbols >>> N = ReferenceFrame('N') >>> p1 = Point('p1') >>> p1.set_vel(N, 10 * N.x) >>> p1.vel(N) 10*N.x Velocities will be automatically calculated if possible, otherwise a ``ValueError`` will be returned. If it is possible to calculate multiple different velocities from the relative points, the points defined most directly relative to this point will be used. In the case of inconsistent relative positions of points, incorrect velocities may be returned. It is up to the user to define prior relative positions and velocities of points in a self-consistent way. >>> p = Point('p') >>> q = dynamicsymbols('q') >>> p.set_vel(N, 10 * N.x) >>> p2 = Point('p2') >>> p2.set_pos(p, q*N.x) >>> p2.vel(N) (Derivative(q(t), t) + 10)*N.x """ _check_frame(frame) if not (frame in self._vel_dict): valid_neighbor_found = False is_cyclic = False visited = [] queue = [self] candidate_neighbor = [] while queue: #BFS to find nearest point node = queue.pop(0) if node not in visited: visited.append(node) for neighbor, neighbor_pos in node._pos_dict.items(): if neighbor in visited: continue try: neighbor_pos.express(frame) #Checks if pos vector is valid except ValueError: continue if neighbor in queue: is_cyclic = True try : neighbor_velocity = neighbor._vel_dict[frame] #Checks if point has its vel defined in req frame except KeyError: queue.append(neighbor) continue candidate_neighbor.append(neighbor) if not valid_neighbor_found: vel = None for f in self.pos_from(neighbor).args: if f[1] in self._vel_dict.keys(): if self._vel_dict[f[1]] != 0: vel = self._vel_dict[f[1]] break if vel is None: vel = self.pos_from(neighbor).dt(frame) self.set_vel(frame, vel + neighbor_velocity) valid_neighbor_found = True if is_cyclic: warn('Kinematic loops are defined among the positions of points. This is likely not desired and may cause errors in your calculations.') if len(candidate_neighbor) > 1: warn('Velocity automatically calculated based on point ' + candidate_neighbor[0].name + ' but it is also possible from points(s):' + str(candidate_neighbor[1:]) + '. Velocities from these points are not necessarily the same. This may cause errors in your calculations.') if valid_neighbor_found: return self._vel_dict[frame] else: raise ValueError('Velocity of point ' + self.name + ' has not been' ' defined in ReferenceFrame ' + frame.name) return self._vel_dict[frame] def partial_velocity(self, frame, *gen_speeds): """Returns the partial velocities of the linear velocity vector of this point in the given frame with respect to one or more provided generalized speeds. Parameters ========== frame : ReferenceFrame The frame with which the velocity is defined in. gen_speeds : functions of time The generalized speeds. Returns ======= partial_velocities : tuple of Vector The partial velocity vectors corresponding to the provided generalized speeds. Examples ======== >>> from sympy.physics.vector import ReferenceFrame, Point >>> from sympy.physics.vector import dynamicsymbols >>> N = ReferenceFrame('N') >>> A = ReferenceFrame('A') >>> p = Point('p') >>> u1, u2 = dynamicsymbols('u1, u2') >>> p.set_vel(N, u1 * N.x + u2 * A.y) >>> p.partial_velocity(N, u1) N.x >>> p.partial_velocity(N, u1, u2) (N.x, A.y) """ partials = [self.vel(frame).diff(speed, frame, var_in_dcm=False) for speed in gen_speeds] if len(partials) == 1: return partials[0] else: return tuple(partials) sympy-sympy-1.9/sympy/physics/vector/printing.py000066400000000000000000000270001412543434000222730ustar00rootroot00000000000000from sympy import Derivative from sympy.core.function import UndefinedFunction, AppliedUndef from sympy.core.symbol import Symbol from sympy.interactive.printing import init_printing from sympy.printing.latex import LatexPrinter from sympy.printing.pretty.pretty import PrettyPrinter from sympy.printing.pretty.pretty_symbology import center_accent from sympy.printing.str import StrPrinter from sympy.printing.precedence import PRECEDENCE __all__ = ['vprint', 'vsstrrepr', 'vsprint', 'vpprint', 'vlatex', 'init_vprinting'] class VectorStrPrinter(StrPrinter): """String Printer for vector expressions. """ def _print_Derivative(self, e): from sympy.physics.vector.functions import dynamicsymbols t = dynamicsymbols._t if (bool(sum([i == t for i in e.variables])) & isinstance(type(e.args[0]), UndefinedFunction)): ol = str(e.args[0].func) for i, v in enumerate(e.variables): ol += dynamicsymbols._str return ol else: return StrPrinter().doprint(e) def _print_Function(self, e): from sympy.physics.vector.functions import dynamicsymbols t = dynamicsymbols._t if isinstance(type(e), UndefinedFunction): return StrPrinter().doprint(e).replace("(%s)" % t, '') return e.func.__name__ + "(%s)" % self.stringify(e.args, ", ") class VectorStrReprPrinter(VectorStrPrinter): """String repr printer for vector expressions.""" def _print_str(self, s): return repr(s) class VectorLatexPrinter(LatexPrinter): """Latex Printer for vector expressions. """ def _print_Function(self, expr, exp=None): from sympy.physics.vector.functions import dynamicsymbols func = expr.func.__name__ t = dynamicsymbols._t if hasattr(self, '_print_' + func) and \ not isinstance(type(expr), UndefinedFunction): return getattr(self, '_print_' + func)(expr, exp) elif isinstance(type(expr), UndefinedFunction) and (expr.args == (t,)): # treat this function like a symbol expr = Symbol(func) if exp is not None: # copied from LatexPrinter._helper_print_standard_power, which # we can't call because we only have exp as a string. base = self.parenthesize(expr, PRECEDENCE['Pow']) base = self.parenthesize_super(base) return r"%s^{%s}" % (base, exp) else: return super()._print(expr) else: return super()._print_Function(expr, exp) def _print_Derivative(self, der_expr): from sympy.physics.vector.functions import dynamicsymbols # make sure it is in the right form der_expr = der_expr.doit() if not isinstance(der_expr, Derivative): return r"\left(%s\right)" % self.doprint(der_expr) # check if expr is a dynamicsymbol t = dynamicsymbols._t expr = der_expr.expr red = expr.atoms(AppliedUndef) syms = der_expr.variables test1 = not all([True for i in red if i.free_symbols == {t}]) test2 = not all([(t == i) for i in syms]) if test1 or test2: return super()._print_Derivative(der_expr) # done checking dots = len(syms) base = self._print_Function(expr) base_split = base.split('_', 1) base = base_split[0] if dots == 1: base = r"\dot{%s}" % base elif dots == 2: base = r"\ddot{%s}" % base elif dots == 3: base = r"\dddot{%s}" % base elif dots == 4: base = r"\ddddot{%s}" % base else: # Fallback to standard printing return super()._print_Derivative(der_expr) if len(base_split) != 1: base += '_' + base_split[1] return base class VectorPrettyPrinter(PrettyPrinter): """Pretty Printer for vectorialexpressions. """ def _print_Derivative(self, deriv): from sympy.physics.vector.functions import dynamicsymbols # XXX use U('PARTIAL DIFFERENTIAL') here ? t = dynamicsymbols._t dot_i = 0 syms = list(reversed(deriv.variables)) while len(syms) > 0: if syms[-1] == t: syms.pop() dot_i += 1 else: return super()._print_Derivative(deriv) if not (isinstance(type(deriv.expr), UndefinedFunction) and (deriv.expr.args == (t,))): return super()._print_Derivative(deriv) else: pform = self._print_Function(deriv.expr) # the following condition would happen with some sort of non-standard # dynamic symbol I guess, so we'll just print the SymPy way if len(pform.picture) > 1: return super()._print_Derivative(deriv) # There are only special symbols up to fourth-order derivatives if dot_i >= 5: return super()._print_Derivative(deriv) # Deal with special symbols dots = {0 : "", 1 : "\N{COMBINING DOT ABOVE}", 2 : "\N{COMBINING DIAERESIS}", 3 : "\N{COMBINING THREE DOTS ABOVE}", 4 : "\N{COMBINING FOUR DOTS ABOVE}"} d = pform.__dict__ #if unicode is false then calculate number of apostrophes needed and add to output if not self._use_unicode: apostrophes = "" for i in range(0, dot_i): apostrophes += "'" d['picture'][0] += apostrophes + "(t)" else: d['picture'] = [center_accent(d['picture'][0], dots[dot_i])] return pform def _print_Function(self, e): from sympy.physics.vector.functions import dynamicsymbols t = dynamicsymbols._t # XXX works only for applied functions func = e.func args = e.args func_name = func.__name__ pform = self._print_Symbol(Symbol(func_name)) # If this function is an Undefined function of t, it is probably a # dynamic symbol, so we'll skip the (t). The rest of the code is # identical to the normal PrettyPrinter code if not (isinstance(func, UndefinedFunction) and (args == (t,))): return super()._print_Function(e) return pform def vprint(expr, **settings): r"""Function for printing of expressions generated in the sympy.physics vector package. Extends SymPy's StrPrinter, takes the same setting accepted by SymPy's :func:`~.sstr`, and is equivalent to ``print(sstr(foo))``. Parameters ========== expr : valid SymPy object SymPy expression to print. settings : args Same as the settings accepted by SymPy's sstr(). Examples ======== >>> from sympy.physics.vector import vprint, dynamicsymbols >>> u1 = dynamicsymbols('u1') >>> print(u1) u1(t) >>> vprint(u1) u1 """ outstr = vsprint(expr, **settings) import builtins if (outstr != 'None'): builtins._ = outstr print(outstr) def vsstrrepr(expr, **settings): """Function for displaying expression representation's with vector printing enabled. Parameters ========== expr : valid SymPy object SymPy expression to print. settings : args Same as the settings accepted by SymPy's sstrrepr(). """ p = VectorStrReprPrinter(settings) return p.doprint(expr) def vsprint(expr, **settings): r"""Function for displaying expressions generated in the sympy.physics vector package. Returns the output of vprint() as a string. Parameters ========== expr : valid SymPy object SymPy expression to print settings : args Same as the settings accepted by SymPy's sstr(). Examples ======== >>> from sympy.physics.vector import vsprint, dynamicsymbols >>> u1, u2 = dynamicsymbols('u1 u2') >>> u2d = dynamicsymbols('u2', level=1) >>> print("%s = %s" % (u1, u2 + u2d)) u1(t) = u2(t) + Derivative(u2(t), t) >>> print("%s = %s" % (vsprint(u1), vsprint(u2 + u2d))) u1 = u2 + u2' """ string_printer = VectorStrPrinter(settings) return string_printer.doprint(expr) def vpprint(expr, **settings): r"""Function for pretty printing of expressions generated in the sympy.physics vector package. Mainly used for expressions not inside a vector; the output of running scripts and generating equations of motion. Takes the same options as SymPy's :func:`~.pretty_print`; see that function for more information. Parameters ========== expr : valid SymPy object SymPy expression to pretty print settings : args Same as those accepted by SymPy's pretty_print. """ pp = VectorPrettyPrinter(settings) # Note that this is copied from sympy.printing.pretty.pretty_print: # XXX: this is an ugly hack, but at least it works use_unicode = pp._settings['use_unicode'] from sympy.printing.pretty.pretty_symbology import pretty_use_unicode uflag = pretty_use_unicode(use_unicode) try: return pp.doprint(expr) finally: pretty_use_unicode(uflag) def vlatex(expr, **settings): r"""Function for printing latex representation of sympy.physics.vector objects. For latex representation of Vectors, Dyadics, and dynamicsymbols. Takes the same options as SymPy's :func:`~.latex`; see that function for more information; Parameters ========== expr : valid SymPy object SymPy expression to represent in LaTeX form settings : args Same as latex() Examples ======== >>> from sympy.physics.vector import vlatex, ReferenceFrame, dynamicsymbols >>> N = ReferenceFrame('N') >>> q1, q2 = dynamicsymbols('q1 q2') >>> q1d, q2d = dynamicsymbols('q1 q2', 1) >>> q1dd, q2dd = dynamicsymbols('q1 q2', 2) >>> vlatex(N.x + N.y) '\\mathbf{\\hat{n}_x} + \\mathbf{\\hat{n}_y}' >>> vlatex(q1 + q2) 'q_{1} + q_{2}' >>> vlatex(q1d) '\\dot{q}_{1}' >>> vlatex(q1 * q2d) 'q_{1} \\dot{q}_{2}' >>> vlatex(q1dd * q1 / q1d) '\\frac{q_{1} \\ddot{q}_{1}}{\\dot{q}_{1}}' """ latex_printer = VectorLatexPrinter(settings) return latex_printer.doprint(expr) def init_vprinting(**kwargs): """Initializes time derivative printing for all SymPy objects, i.e. any functions of time will be displayed in a more compact notation. The main benefit of this is for printing of time derivatives; instead of displaying as ``Derivative(f(t),t)``, it will display ``f'``. This is only actually needed for when derivatives are present and are not in a physics.vector.Vector or physics.vector.Dyadic object. This function is a light wrapper to :func:`~.init_printing`. Any keyword arguments for it are valid here. {0} Examples ======== >>> from sympy import Function, symbols >>> t, x = symbols('t, x') >>> omega = Function('omega') >>> omega(x).diff() Derivative(omega(x), x) >>> omega(t).diff() Derivative(omega(t), t) Now use the string printer: >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> omega(x).diff() Derivative(omega(x), x) >>> omega(t).diff() omega' """ kwargs['str_printer'] = vsstrrepr kwargs['pretty_printer'] = vpprint kwargs['latex_printer'] = vlatex init_printing(**kwargs) params = init_printing.__doc__.split('Examples\n ========')[0] # type: ignore init_vprinting.__doc__ = init_vprinting.__doc__.format(params) # type: ignore sympy-sympy-1.9/sympy/physics/vector/tests/000077500000000000000000000000001412543434000212325ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/vector/tests/__init__.py000066400000000000000000000000001412543434000233310ustar00rootroot00000000000000sympy-sympy-1.9/sympy/physics/vector/tests/test_dyadic.py000066400000000000000000000100711412543434000240770ustar00rootroot00000000000000from sympy import sin, cos, symbols, pi, Float, ImmutableMatrix as Matrix from sympy.physics.vector import ReferenceFrame, Vector, dynamicsymbols, outer from sympy.physics.vector.dyadic import _check_dyadic from sympy.testing.pytest import raises Vector.simp = True A = ReferenceFrame('A') def test_dyadic(): d1 = A.x | A.x d2 = A.y | A.y d3 = A.x | A.y assert d1 * 0 == 0 assert d1 != 0 assert d1 * 2 == 2 * A.x | A.x assert d1 / 2. == 0.5 * d1 assert d1 & (0 * d1) == 0 assert d1 & d2 == 0 assert d1 & A.x == A.x assert d1 ^ A.x == 0 assert d1 ^ A.y == A.x | A.z assert d1 ^ A.z == - A.x | A.y assert d2 ^ A.x == - A.y | A.z assert A.x ^ d1 == 0 assert A.y ^ d1 == - A.z | A.x assert A.z ^ d1 == A.y | A.x assert A.x & d1 == A.x assert A.y & d1 == 0 assert A.y & d2 == A.y assert d1 & d3 == A.x | A.y assert d3 & d1 == 0 assert d1.dt(A) == 0 q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) B = A.orientnew('B', 'Axis', [q, A.z]) assert d1.express(B) == d1.express(B, B) assert d1.express(B) == ((cos(q)**2) * (B.x | B.x) + (-sin(q) * cos(q)) * (B.x | B.y) + (-sin(q) * cos(q)) * (B.y | B.x) + (sin(q)**2) * (B.y | B.y)) assert d1.express(B, A) == (cos(q)) * (B.x | A.x) + (-sin(q)) * (B.y | A.x) assert d1.express(A, B) == (cos(q)) * (A.x | B.x) + (-sin(q)) * (A.x | B.y) assert d1.dt(B) == (-qd) * (A.y | A.x) + (-qd) * (A.x | A.y) assert d1.to_matrix(A) == Matrix([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) assert d1.to_matrix(A, B) == Matrix([[cos(q), -sin(q), 0], [0, 0, 0], [0, 0, 0]]) assert d3.to_matrix(A) == Matrix([[0, 1, 0], [0, 0, 0], [0, 0, 0]]) a, b, c, d, e, f = symbols('a, b, c, d, e, f') v1 = a * A.x + b * A.y + c * A.z v2 = d * A.x + e * A.y + f * A.z d4 = v1.outer(v2) assert d4.to_matrix(A) == Matrix([[a * d, a * e, a * f], [b * d, b * e, b * f], [c * d, c * e, c * f]]) d5 = v1.outer(v1) C = A.orientnew('C', 'Axis', [q, A.x]) for expected, actual in zip(C.dcm(A) * d5.to_matrix(A) * C.dcm(A).T, d5.to_matrix(C)): assert (expected - actual).simplify() == 0 raises(TypeError, lambda: d1.applyfunc(0)) def test_dyadic_simplify(): x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A') N = ReferenceFrame('N') dy = N.x | N.x test1 = (1 / x + 1 / y) * dy assert (N.x & test1 & N.x) != (x + y) / (x * y) test1 = test1.simplify() assert (N.x & test1 & N.x) == (x + y) / (x * y) test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * dy test2 = test2.simplify() assert (N.x & test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3)) test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * dy test3 = test3.simplify() assert (N.x & test3 & N.x) == 0 test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * dy test4 = test4.simplify() assert (N.x & test4 & N.x) == -2 * y def test_dyadic_subs(): N = ReferenceFrame('N') s = symbols('s') a = s*(N.x | N.x) assert a.subs({s: 2}) == 2*(N.x | N.x) def test_check_dyadic(): raises(TypeError, lambda: _check_dyadic(0)) def test_dyadic_evalf(): N = ReferenceFrame('N') a = pi * (N.x | N.x) assert a.evalf(3) == Float('3.1416', 3) * (N.x | N.x) s = symbols('s') a = 5 * s * pi* (N.x | N.x) assert a.evalf(2) == Float('5', 2) * Float('3.1416', 2) * s * (N.x | N.x) assert a.evalf(9, subs={s: 5.124}) == Float('80.48760378', 9) * (N.x | N.x) def test_dyadic_xreplace(): x, y, z = symbols('x y z') N = ReferenceFrame('N') D = outer(N.x, N.x) v = x*y * D assert v.xreplace({x : cos(x)}) == cos(x)*y * D assert v.xreplace({x*y : pi}) == pi * D v = (x*y)**z * D assert v.xreplace({(x*y)**z : 1}) == D assert v.xreplace({x:1, z:0}) == D raises(TypeError, lambda: v.xreplace()) raises(TypeError, lambda: v.xreplace([x, y])) sympy-sympy-1.9/sympy/physics/vector/tests/test_fieldfunctions.py000066400000000000000000000131371412543434000256640ustar00rootroot00000000000000from sympy import S, Symbol, sin, cos from sympy.physics.vector import ReferenceFrame, Vector, Point, \ dynamicsymbols from sympy.physics.vector.fieldfunctions import divergence, \ gradient, curl, is_conservative, is_solenoidal, \ scalar_potential, scalar_potential_difference from sympy.testing.pytest import raises R = ReferenceFrame('R') q = dynamicsymbols('q') P = R.orientnew('P', 'Axis', [q, R.z]) def test_curl(): assert curl(Vector(0), R) == Vector(0) assert curl(R.x, R) == Vector(0) assert curl(2*R[1]**2*R.y, R) == Vector(0) assert curl(R[0]*R[1]*R.z, R) == R[0]*R.x - R[1]*R.y assert curl(R[0]*R[1]*R[2] * (R.x+R.y+R.z), R) == \ (-R[0]*R[1] + R[0]*R[2])*R.x + (R[0]*R[1] - R[1]*R[2])*R.y + \ (-R[0]*R[2] + R[1]*R[2])*R.z assert curl(2*R[0]**2*R.y, R) == 4*R[0]*R.z assert curl(P[0]**2*R.x + P.y, R) == \ - 2*(R[0]*cos(q) + R[1]*sin(q))*sin(q)*R.z assert curl(P[0]*R.y, P) == cos(q)*P.z def test_divergence(): assert divergence(Vector(0), R) is S.Zero assert divergence(R.x, R) is S.Zero assert divergence(R[0]**2*R.x, R) == 2*R[0] assert divergence(R[0]*R[1]*R[2] * (R.x+R.y+R.z), R) == \ R[0]*R[1] + R[0]*R[2] + R[1]*R[2] assert divergence((1/(R[0]*R[1]*R[2])) * (R.x+R.y+R.z), R) == \ -1/(R[0]*R[1]*R[2]**2) - 1/(R[0]*R[1]**2*R[2]) - \ 1/(R[0]**2*R[1]*R[2]) v = P[0]*P.x + P[1]*P.y + P[2]*P.z assert divergence(v, P) == 3 assert divergence(v, R).simplify() == 3 assert divergence(P[0]*R.x + R[0]*P.x, R) == 2*cos(q) def test_gradient(): a = Symbol('a') assert gradient(0, R) == Vector(0) assert gradient(R[0], R) == R.x assert gradient(R[0]*R[1]*R[2], R) == \ R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z assert gradient(2*R[0]**2, R) == 4*R[0]*R.x assert gradient(a*sin(R[1])/R[0], R) == \ - a*sin(R[1])/R[0]**2*R.x + a*cos(R[1])/R[0]*R.y assert gradient(P[0]*P[1], R) == \ ((-R[0]*sin(q) + R[1]*cos(q))*cos(q) - (R[0]*cos(q) + R[1]*sin(q))*sin(q))*R.x + \ ((-R[0]*sin(q) + R[1]*cos(q))*sin(q) + (R[0]*cos(q) + R[1]*sin(q))*cos(q))*R.y assert gradient(P[0]*R[2], P) == P[2]*P.x + P[0]*P.z scalar_field = 2*R[0]**2*R[1]*R[2] grad_field = gradient(scalar_field, R) vector_field = R[1]**2*R.x + 3*R[0]*R.y + 5*R[1]*R[2]*R.z curl_field = curl(vector_field, R) def test_conservative(): assert is_conservative(0) is True assert is_conservative(R.x) is True assert is_conservative(2 * R.x + 3 * R.y + 4 * R.z) is True assert is_conservative(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) is \ True assert is_conservative(R[0] * R.y) is False assert is_conservative(grad_field) is True assert is_conservative(curl_field) is False assert is_conservative(4*R[0]*R[1]*R[2]*R.x + 2*R[0]**2*R[2]*R.y) is \ False assert is_conservative(R[2]*P.x + P[0]*R.z) is True def test_solenoidal(): assert is_solenoidal(0) is True assert is_solenoidal(R.x) is True assert is_solenoidal(2 * R.x + 3 * R.y + 4 * R.z) is True assert is_solenoidal(R[1]*R[2]*R.x + R[0]*R[2]*R.y + R[0]*R[1]*R.z) is \ True assert is_solenoidal(R[1] * R.y) is False assert is_solenoidal(grad_field) is False assert is_solenoidal(curl_field) is True assert is_solenoidal((-2*R[1] + 3)*R.z) is True assert is_solenoidal(cos(q)*R.x + sin(q)*R.y + cos(q)*P.z) is True assert is_solenoidal(R[2]*P.x + P[0]*R.z) is True def test_scalar_potential(): assert scalar_potential(0, R) == 0 assert scalar_potential(R.x, R) == R[0] assert scalar_potential(R.y, R) == R[1] assert scalar_potential(R.z, R) == R[2] assert scalar_potential(R[1]*R[2]*R.x + R[0]*R[2]*R.y + \ R[0]*R[1]*R.z, R) == R[0]*R[1]*R[2] assert scalar_potential(grad_field, R) == scalar_field assert scalar_potential(R[2]*P.x + P[0]*R.z, R) == \ R[0]*R[2]*cos(q) + R[1]*R[2]*sin(q) assert scalar_potential(R[2]*P.x + P[0]*R.z, P) == P[0]*P[2] raises(ValueError, lambda: scalar_potential(R[0] * R.y, R)) def test_scalar_potential_difference(): origin = Point('O') point1 = origin.locatenew('P1', 1*R.x + 2*R.y + 3*R.z) point2 = origin.locatenew('P2', 4*R.x + 5*R.y + 6*R.z) genericpointR = origin.locatenew('RP', R[0]*R.x + R[1]*R.y + R[2]*R.z) genericpointP = origin.locatenew('PP', P[0]*P.x + P[1]*P.y + P[2]*P.z) assert scalar_potential_difference(S.Zero, R, point1, point2, \ origin) == 0 assert scalar_potential_difference(scalar_field, R, origin, \ genericpointR, origin) == \ scalar_field assert scalar_potential_difference(grad_field, R, origin, \ genericpointR, origin) == \ scalar_field assert scalar_potential_difference(grad_field, R, point1, point2, origin) == 948 assert scalar_potential_difference(R[1]*R[2]*R.x + R[0]*R[2]*R.y + \ R[0]*R[1]*R.z, R, point1, genericpointR, origin) == \ R[0]*R[1]*R[2] - 6 potential_diff_P = 2*P[2]*(P[0]*sin(q) + P[1]*cos(q))*\ (P[0]*cos(q) - P[1]*sin(q))**2 assert scalar_potential_difference(grad_field, P, origin, \ genericpointP, \ origin).simplify() == \ potential_diff_P sympy-sympy-1.9/sympy/physics/vector/tests/test_frame.py000066400000000000000000000523431412543434000237440ustar00rootroot00000000000000from sympy import (symbols, sin, cos, pi, zeros, eye, simplify, ImmutableMatrix as Matrix) from sympy.physics.vector import (ReferenceFrame, Vector, CoordinateSym, dynamicsymbols, time_derivative, express, dot) from sympy.physics.vector.frame import _check_frame from sympy.physics.vector.vector import VectorTypeError from sympy.testing.pytest import raises import warnings Vector.simp = True def test_dict_list(): A = ReferenceFrame('A') B = ReferenceFrame('B') C = ReferenceFrame('C') D = ReferenceFrame('D') E = ReferenceFrame('E') F = ReferenceFrame('F') B.orient_axis(A, A.x, 1.0) C.orient_axis(B, B.x, 1.0) D.orient_axis(C, C.x, 1.0) assert D._dict_list(A, 0) == [D, C, B, A] E.orient_axis(D, D.x, 1.0) assert C._dict_list(A, 0) == [C, B, A] assert C._dict_list(E, 0) == [C, D, E] # only 0, 1, 2 permitted for second argument raises(ValueError, lambda: C._dict_list(E, 5)) # no connecting path raises(ValueError, lambda: F._dict_list(A, 0)) def test_coordinate_vars(): """Tests the coordinate variables functionality""" A = ReferenceFrame('A') assert CoordinateSym('Ax', A, 0) == A[0] assert CoordinateSym('Ax', A, 1) == A[1] assert CoordinateSym('Ax', A, 2) == A[2] raises(ValueError, lambda: CoordinateSym('Ax', A, 3)) q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) assert isinstance(A[0], CoordinateSym) and \ isinstance(A[0], CoordinateSym) and \ isinstance(A[0], CoordinateSym) assert A.variable_map(A) == {A[0]:A[0], A[1]:A[1], A[2]:A[2]} assert A[0].frame == A B = A.orientnew('B', 'Axis', [q, A.z]) assert B.variable_map(A) == {B[2]: A[2], B[1]: -A[0]*sin(q) + A[1]*cos(q), B[0]: A[0]*cos(q) + A[1]*sin(q)} assert A.variable_map(B) == {A[0]: B[0]*cos(q) - B[1]*sin(q), A[1]: B[0]*sin(q) + B[1]*cos(q), A[2]: B[2]} assert time_derivative(B[0], A) == -A[0]*sin(q)*qd + A[1]*cos(q)*qd assert time_derivative(B[1], A) == -A[0]*cos(q)*qd - A[1]*sin(q)*qd assert time_derivative(B[2], A) == 0 assert express(B[0], A, variables=True) == A[0]*cos(q) + A[1]*sin(q) assert express(B[1], A, variables=True) == -A[0]*sin(q) + A[1]*cos(q) assert express(B[2], A, variables=True) == A[2] assert time_derivative(A[0]*A.x + A[1]*A.y + A[2]*A.z, B) == A[1]*qd*A.x - A[0]*qd*A.y assert time_derivative(B[0]*B.x + B[1]*B.y + B[2]*B.z, A) == - B[1]*qd*B.x + B[0]*qd*B.y assert express(B[0]*B[1]*B[2], A, variables=True) == \ A[2]*(-A[0]*sin(q) + A[1]*cos(q))*(A[0]*cos(q) + A[1]*sin(q)) assert (time_derivative(B[0]*B[1]*B[2], A) - (A[2]*(-A[0]**2*cos(2*q) - 2*A[0]*A[1]*sin(2*q) + A[1]**2*cos(2*q))*qd)).trigsimp() == 0 assert express(B[0]*B.x + B[1]*B.y + B[2]*B.z, A) == \ (B[0]*cos(q) - B[1]*sin(q))*A.x + (B[0]*sin(q) + \ B[1]*cos(q))*A.y + B[2]*A.z assert express(B[0]*B.x + B[1]*B.y + B[2]*B.z, A, variables=True) == \ A[0]*A.x + A[1]*A.y + A[2]*A.z assert express(A[0]*A.x + A[1]*A.y + A[2]*A.z, B) == \ (A[0]*cos(q) + A[1]*sin(q))*B.x + \ (-A[0]*sin(q) + A[1]*cos(q))*B.y + A[2]*B.z assert express(A[0]*A.x + A[1]*A.y + A[2]*A.z, B, variables=True) == \ B[0]*B.x + B[1]*B.y + B[2]*B.z N = B.orientnew('N', 'Axis', [-q, B.z]) assert N.variable_map(A) == {N[0]: A[0], N[2]: A[2], N[1]: A[1]} C = A.orientnew('C', 'Axis', [q, A.x + A.y + A.z]) mapping = A.variable_map(C) assert mapping[A[0]] == 2*C[0]*cos(q)/3 + C[0]/3 - 2*C[1]*sin(q + pi/6)/3 +\ C[1]/3 - 2*C[2]*cos(q + pi/3)/3 + C[2]/3 assert mapping[A[1]] == -2*C[0]*cos(q + pi/3)/3 + \ C[0]/3 + 2*C[1]*cos(q)/3 + C[1]/3 - 2*C[2]*sin(q + pi/6)/3 + C[2]/3 assert mapping[A[2]] == -2*C[0]*sin(q + pi/6)/3 + C[0]/3 - \ 2*C[1]*cos(q + pi/3)/3 + C[1]/3 + 2*C[2]*cos(q)/3 + C[2]/3 def test_ang_vel(): q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q1, N.z]) B = A.orientnew('B', 'Axis', [q2, A.x]) C = B.orientnew('C', 'Axis', [q3, B.y]) D = N.orientnew('D', 'Axis', [q4, N.y]) u1, u2, u3 = dynamicsymbols('u1 u2 u3') assert A.ang_vel_in(N) == (q1d)*A.z assert B.ang_vel_in(N) == (q2d)*B.x + (q1d)*A.z assert C.ang_vel_in(N) == (q3d)*C.y + (q2d)*B.x + (q1d)*A.z A2 = N.orientnew('A2', 'Axis', [q4, N.y]) assert N.ang_vel_in(N) == 0 assert N.ang_vel_in(A) == -q1d*N.z assert N.ang_vel_in(B) == -q1d*A.z - q2d*B.x assert N.ang_vel_in(C) == -q1d*A.z - q2d*B.x - q3d*B.y assert N.ang_vel_in(A2) == -q4d*N.y assert A.ang_vel_in(N) == q1d*N.z assert A.ang_vel_in(A) == 0 assert A.ang_vel_in(B) == - q2d*B.x assert A.ang_vel_in(C) == - q2d*B.x - q3d*B.y assert A.ang_vel_in(A2) == q1d*N.z - q4d*N.y assert B.ang_vel_in(N) == q1d*A.z + q2d*A.x assert B.ang_vel_in(A) == q2d*A.x assert B.ang_vel_in(B) == 0 assert B.ang_vel_in(C) == -q3d*B.y assert B.ang_vel_in(A2) == q1d*A.z + q2d*A.x - q4d*N.y assert C.ang_vel_in(N) == q1d*A.z + q2d*A.x + q3d*B.y assert C.ang_vel_in(A) == q2d*A.x + q3d*C.y assert C.ang_vel_in(B) == q3d*B.y assert C.ang_vel_in(C) == 0 assert C.ang_vel_in(A2) == q1d*A.z + q2d*A.x + q3d*B.y - q4d*N.y assert A2.ang_vel_in(N) == q4d*A2.y assert A2.ang_vel_in(A) == q4d*A2.y - q1d*N.z assert A2.ang_vel_in(B) == q4d*N.y - q1d*A.z - q2d*A.x assert A2.ang_vel_in(C) == q4d*N.y - q1d*A.z - q2d*A.x - q3d*B.y assert A2.ang_vel_in(A2) == 0 C.set_ang_vel(N, u1*C.x + u2*C.y + u3*C.z) assert C.ang_vel_in(N) == (u1)*C.x + (u2)*C.y + (u3)*C.z assert N.ang_vel_in(C) == (-u1)*C.x + (-u2)*C.y + (-u3)*C.z assert C.ang_vel_in(D) == (u1)*C.x + (u2)*C.y + (u3)*C.z + (-q4d)*D.y assert D.ang_vel_in(C) == (-u1)*C.x + (-u2)*C.y + (-u3)*C.z + (q4d)*D.y q0 = dynamicsymbols('q0') q0d = dynamicsymbols('q0', 1) E = N.orientnew('E', 'Quaternion', (q0, q1, q2, q3)) assert E.ang_vel_in(N) == ( 2 * (q1d * q0 + q2d * q3 - q3d * q2 - q0d * q1) * E.x + 2 * (q2d * q0 + q3d * q1 - q1d * q3 - q0d * q2) * E.y + 2 * (q3d * q0 + q1d * q2 - q2d * q1 - q0d * q3) * E.z) F = N.orientnew('F', 'Body', (q1, q2, q3), 313) assert F.ang_vel_in(N) == ((sin(q2)*sin(q3)*q1d + cos(q3)*q2d)*F.x + (sin(q2)*cos(q3)*q1d - sin(q3)*q2d)*F.y + (cos(q2)*q1d + q3d)*F.z) G = N.orientnew('G', 'Axis', (q1, N.x + N.y)) assert G.ang_vel_in(N) == q1d * (N.x + N.y).normalize() assert N.ang_vel_in(G) == -q1d * (N.x + N.y).normalize() def test_dcm(): q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q1, N.z]) B = A.orientnew('B', 'Axis', [q2, A.x]) C = B.orientnew('C', 'Axis', [q3, B.y]) D = N.orientnew('D', 'Axis', [q4, N.y]) E = N.orientnew('E', 'Space', [q1, q2, q3], '123') assert N.dcm(C) == Matrix([ [- sin(q1) * sin(q2) * sin(q3) + cos(q1) * cos(q3), - sin(q1) * cos(q2), sin(q1) * sin(q2) * cos(q3) + sin(q3) * cos(q1)], [sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2), sin(q1) * sin(q3) - sin(q2) * cos(q1) * cos(q3)], [- sin(q3) * cos(q2), sin(q2), cos(q2) * cos(q3)]]) # This is a little touchy. Is it ok to use simplify in assert? test_mat = D.dcm(C) - Matrix( [[cos(q1) * cos(q3) * cos(q4) - sin(q3) * (- sin(q4) * cos(q2) + sin(q1) * sin(q2) * cos(q4)), - sin(q2) * sin(q4) - sin(q1) * cos(q2) * cos(q4), sin(q3) * cos(q1) * cos(q4) + cos(q3) * (- sin(q4) * cos(q2) + sin(q1) * sin(q2) * cos(q4))], [sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * cos(q2), sin(q1) * sin(q3) - sin(q2) * cos(q1) * cos(q3)], [sin(q4) * cos(q1) * cos(q3) - sin(q3) * (cos(q2) * cos(q4) + sin(q1) * sin(q2) * sin(q4)), sin(q2) * cos(q4) - sin(q1) * sin(q4) * cos(q2), sin(q3) * sin(q4) * cos(q1) + cos(q3) * (cos(q2) * cos(q4) + sin(q1) * sin(q2) * sin(q4))]]) assert test_mat.expand() == zeros(3, 3) assert E.dcm(N) == Matrix( [[cos(q2)*cos(q3), sin(q3)*cos(q2), -sin(q2)], [sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q2)], [sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3), - sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]]) def test_w_diff_dcm1(): # Ref: # Dynamics Theory and Applications, Kane 1985 # Sec. 2.1 ANGULAR VELOCITY A = ReferenceFrame('A') B = ReferenceFrame('B') c11, c12, c13 = dynamicsymbols('C11 C12 C13') c21, c22, c23 = dynamicsymbols('C21 C22 C23') c31, c32, c33 = dynamicsymbols('C31 C32 C33') c11d, c12d, c13d = dynamicsymbols('C11 C12 C13', level=1) c21d, c22d, c23d = dynamicsymbols('C21 C22 C23', level=1) c31d, c32d, c33d = dynamicsymbols('C31 C32 C33', level=1) DCM = Matrix([ [c11, c12, c13], [c21, c22, c23], [c31, c32, c33] ]) B.orient(A, 'DCM', DCM) b1a = (B.x).express(A) b2a = (B.y).express(A) b3a = (B.z).express(A) # Equation (2.1.1) B.set_ang_vel(A, B.x*(dot((b3a).dt(A), B.y)) + B.y*(dot((b1a).dt(A), B.z)) + B.z*(dot((b2a).dt(A), B.x))) # Equation (2.1.21) expr = ( (c12*c13d + c22*c23d + c32*c33d)*B.x + (c13*c11d + c23*c21d + c33*c31d)*B.y + (c11*c12d + c21*c22d + c31*c32d)*B.z) assert B.ang_vel_in(A) - expr == 0 def test_w_diff_dcm2(): q1, q2, q3 = dynamicsymbols('q1:4') N = ReferenceFrame('N') A = N.orientnew('A', 'axis', [q1, N.x]) B = A.orientnew('B', 'axis', [q2, A.y]) C = B.orientnew('C', 'axis', [q3, B.z]) DCM = C.dcm(N).T D = N.orientnew('D', 'DCM', DCM) # Frames D and C are the same ReferenceFrame, # since they have equal DCM respect to frame N. # Therefore, D and C should have same angle velocity in N. assert D.dcm(N) == C.dcm(N) == Matrix([ [cos(q2)*cos(q3), sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3)], [-sin(q3)*cos(q2), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)], [sin(q2), -sin(q1)*cos(q2), cos(q1)*cos(q2)]]) assert (D.ang_vel_in(N) - C.ang_vel_in(N)).express(N).simplify() == 0 def test_orientnew_respects_parent_class(): class MyReferenceFrame(ReferenceFrame): pass B = MyReferenceFrame('B') C = B.orientnew('C', 'Axis', [0, B.x]) assert isinstance(C, MyReferenceFrame) def test_orientnew_respects_input_indices(): N = ReferenceFrame('N') q1 = dynamicsymbols('q1') A = N.orientnew('a', 'Axis', [q1, N.z]) #modify default indices: minds = [x+'1' for x in N.indices] B = N.orientnew('b', 'Axis', [q1, N.z], indices=minds) assert N.indices == A.indices assert B.indices == minds def test_orientnew_respects_input_latexs(): N = ReferenceFrame('N') q1 = dynamicsymbols('q1') A = N.orientnew('a', 'Axis', [q1, N.z]) #build default and alternate latex_vecs: def_latex_vecs = [(r"\mathbf{\hat{%s}_%s}" % (A.name.lower(), A.indices[0])), (r"\mathbf{\hat{%s}_%s}" % (A.name.lower(), A.indices[1])), (r"\mathbf{\hat{%s}_%s}" % (A.name.lower(), A.indices[2]))] name = 'b' indices = [x+'1' for x in N.indices] new_latex_vecs = [(r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), indices[0])), (r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), indices[1])), (r"\mathbf{\hat{%s}_{%s}}" % (name.lower(), indices[2]))] B = N.orientnew(name, 'Axis', [q1, N.z], latexs=new_latex_vecs) assert A.latex_vecs == def_latex_vecs assert B.latex_vecs == new_latex_vecs assert B.indices != indices def test_orientnew_respects_input_variables(): N = ReferenceFrame('N') q1 = dynamicsymbols('q1') A = N.orientnew('a', 'Axis', [q1, N.z]) #build non-standard variable names name = 'b' new_variables = ['notb_'+x+'1' for x in N.indices] B = N.orientnew(name, 'Axis', [q1, N.z], variables=new_variables) for j,var in enumerate(A.varlist): assert var.name == A.name + '_' + A.indices[j] for j,var in enumerate(B.varlist): assert var.name == new_variables[j] def test_issue_10348(): u = dynamicsymbols('u:3') I = ReferenceFrame('I') I.orientnew('A', 'space', u, 'XYZ') def test_issue_11503(): A = ReferenceFrame("A") A.orientnew("B", "Axis", [35, A.y]) C = ReferenceFrame("C") A.orient(C, "Axis", [70, C.z]) def test_partial_velocity(): N = ReferenceFrame('N') A = ReferenceFrame('A') u1, u2 = dynamicsymbols('u1, u2') A.set_ang_vel(N, u1 * A.x + u2 * N.y) assert N.partial_velocity(A, u1) == -A.x assert N.partial_velocity(A, u1, u2) == (-A.x, -N.y) assert A.partial_velocity(N, u1) == A.x assert A.partial_velocity(N, u1, u2) == (A.x, N.y) assert N.partial_velocity(N, u1) == 0 assert A.partial_velocity(A, u1) == 0 def test_issue_11498(): A = ReferenceFrame('A') B = ReferenceFrame('B') # Identity transformation A.orient(B, 'DCM', eye(3)) assert A.dcm(B) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) assert B.dcm(A) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) # x -> y # y -> -z # z -> -x A.orient(B, 'DCM', Matrix([[0, 1, 0], [0, 0, -1], [-1, 0, 0]])) assert B.dcm(A) == Matrix([[0, 1, 0], [0, 0, -1], [-1, 0, 0]]) assert A.dcm(B) == Matrix([[0, 0, -1], [1, 0, 0], [0, -1, 0]]) assert B.dcm(A).T == A.dcm(B) def test_reference_frame(): raises(TypeError, lambda: ReferenceFrame(0)) raises(TypeError, lambda: ReferenceFrame('N', 0)) raises(ValueError, lambda: ReferenceFrame('N', [0, 1])) raises(TypeError, lambda: ReferenceFrame('N', [0, 1, 2])) raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], 0)) raises(ValueError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], [0, 1])) raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], [0, 1, 2])) raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], ['a', 'b', 'c'], 0)) raises(ValueError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], ['a', 'b', 'c'], [0, 1])) raises(TypeError, lambda: ReferenceFrame('N', ['a', 'b', 'c'], ['a', 'b', 'c'], [0, 1, 2])) N = ReferenceFrame('N') assert N[0] == CoordinateSym('N_x', N, 0) assert N[1] == CoordinateSym('N_y', N, 1) assert N[2] == CoordinateSym('N_z', N, 2) raises(ValueError, lambda: N[3]) N = ReferenceFrame('N', ['a', 'b', 'c']) assert N['a'] == N.x assert N['b'] == N.y assert N['c'] == N.z raises(ValueError, lambda: N['d']) assert str(N) == 'N' A = ReferenceFrame('A') B = ReferenceFrame('B') q0, q1, q2, q3 = symbols('q0 q1 q2 q3') raises(TypeError, lambda: A.orient(B, 'DCM', 0)) raises(TypeError, lambda: B.orient(N, 'Space', [q1, q2, q3], '222')) raises(TypeError, lambda: B.orient(N, 'Axis', [q1, N.x + 2 * N.y], '222')) raises(TypeError, lambda: B.orient(N, 'Axis', q1)) raises(IndexError, lambda: B.orient(N, 'Axis', [q1])) raises(TypeError, lambda: B.orient(N, 'Quaternion', [q0, q1, q2, q3], '222')) raises(TypeError, lambda: B.orient(N, 'Quaternion', q0)) raises(TypeError, lambda: B.orient(N, 'Quaternion', [q0, q1, q2])) raises(NotImplementedError, lambda: B.orient(N, 'Foo', [q0, q1, q2])) raises(TypeError, lambda: B.orient(N, 'Body', [q1, q2], '232')) raises(TypeError, lambda: B.orient(N, 'Space', [q1, q2], '232')) N.set_ang_acc(B, 0) assert N.ang_acc_in(B) == Vector(0) N.set_ang_vel(B, 0) assert N.ang_vel_in(B) == Vector(0) def test_check_frame(): raises(VectorTypeError, lambda: _check_frame(0)) def test_dcm_diff_16824(): # NOTE : This is a regression test for the bug introduced in PR 14758, # identified in 16824, and solved by PR 16828. # This is the solution to Problem 2.2 on page 264 in Kane & Lenvinson's # 1985 book. q1, q2, q3 = dynamicsymbols('q1:4') s1 = sin(q1) c1 = cos(q1) s2 = sin(q2) c2 = cos(q2) s3 = sin(q3) c3 = cos(q3) dcm = Matrix([[c2*c3, s1*s2*c3 - s3*c1, c1*s2*c3 + s3*s1], [c2*s3, s1*s2*s3 + c3*c1, c1*s2*s3 - c3*s1], [-s2, s1*c2, c1*c2]]) A = ReferenceFrame('A') B = ReferenceFrame('B') B.orient(A, 'DCM', dcm) AwB = B.ang_vel_in(A) alpha2 = s3*c2*q1.diff() + c3*q2.diff() beta2 = s1*c2*q3.diff() + c1*q2.diff() assert simplify(AwB.dot(A.y) - alpha2) == 0 assert simplify(AwB.dot(B.y) - beta2) == 0 def test_orient_explicit(): A = ReferenceFrame('A') B = ReferenceFrame('B') A.orient_explicit(B, eye(3)) assert A.dcm(B) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) def test_orient_axis(): A = ReferenceFrame('A') B = ReferenceFrame('B') A.orient_axis(B,-B.x, 1) A1 = A.dcm(B) A.orient_axis(B, B.x, -1) A2 = A.dcm(B) A.orient_axis(B, 1, -B.x) A3 = A.dcm(B) assert A1 == A2 assert A2 == A3 raises(TypeError, lambda: A.orient_axis(B, 1, 1)) def test_orient_body(): A = ReferenceFrame('A') B = ReferenceFrame('B') B.orient_body_fixed(A, (1,1,0), 'XYX') assert B.dcm(A) == Matrix([[cos(1), sin(1)**2, -sin(1)*cos(1)], [0, cos(1), sin(1)], [sin(1), -sin(1)*cos(1), cos(1)**2]]) def test_orient_space(): A = ReferenceFrame('A') B = ReferenceFrame('B') B.orient_space_fixed(A, (0,0,0), '123') assert B.dcm(A) == Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) def test_orient_quaternion(): A = ReferenceFrame('A') B = ReferenceFrame('B') B.orient_quaternion(A, (0,0,0,0)) assert B.dcm(A) == Matrix([[0, 0, 0], [0, 0, 0], [0, 0, 0]]) def test_looped_frame_warning(): A = ReferenceFrame('A') B = ReferenceFrame('B') C = ReferenceFrame('C') a, b, c = symbols('a b c') B.orient_axis(A, A.x, a) C.orient_axis(B, B.x, b) with warnings.catch_warnings(record = True) as w: warnings.simplefilter("always") A.orient_axis(C, C.x, c) assert issubclass(w[-1].category, UserWarning) assert 'Loops are defined among the orientation of frames. ' + \ 'This is likely not desired and may cause errors in your calculations.' in str(w[-1].message) def test_frame_dict(): A = ReferenceFrame('A') B = ReferenceFrame('B') C = ReferenceFrame('C') a, b, c = symbols('a b c') B.orient_axis(A, A.x, a) assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])} assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]])} assert C._dcm_dict == {} B.orient_axis(C, C.x, b) # Previous relation is not wiped assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])} assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]]), \ C: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]])} assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} A.orient_axis(B, B.x, c) # Previous relation is updated assert B._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]]),\ A: Matrix([[1, 0, 0],[0, cos(c), -sin(c)],[0, sin(c), cos(c)]])} assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(c), sin(c)],[0, -sin(c), cos(c)]])} assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} def test_dcm_cache_dict(): A = ReferenceFrame('A') B = ReferenceFrame('B') C = ReferenceFrame('C') D = ReferenceFrame('D') a, b, c = symbols('a b c') B.orient_axis(A, A.x, a) C.orient_axis(B, B.x, b) D.orient_axis(C, C.x, c) assert D._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(c), sin(c)],[0, -sin(c), cos(c)]])} assert C._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]]), \ D: Matrix([[1, 0, 0],[0, cos(c), -sin(c)],[0, sin(c), cos(c)]])} assert B._dcm_dict == {A: Matrix([[1, 0, 0],[0, cos(a), sin(a)],[0, -sin(a), cos(a)]]), \ C: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(a), -sin(a)],[0, sin(a), cos(a)]])} assert D._dcm_dict == D._dcm_cache D.dcm(A) # Check calculated dcm relation is stored in _dcm_cache and not in _dcm_dict assert list(A._dcm_cache.keys()) == [A, B, D] assert list(D._dcm_cache.keys()) == [C, A] assert list(A._dcm_dict.keys()) == [B] assert list(D._dcm_dict.keys()) == [C] assert A._dcm_dict != A._dcm_cache A.orient_axis(B, B.x, b) # _dcm_cache of A is wiped out and new relation is stored. assert A._dcm_dict == {B: Matrix([[1, 0, 0],[0, cos(b), sin(b)],[0, -sin(b), cos(b)]])} assert A._dcm_dict == A._dcm_cache assert B._dcm_dict == {C: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]]), \ A: Matrix([[1, 0, 0],[0, cos(b), -sin(b)],[0, sin(b), cos(b)]])} sympy-sympy-1.9/sympy/physics/vector/tests/test_functions.py000066400000000000000000000501021412543434000246510ustar00rootroot00000000000000from sympy import S, Integral, sin, cos, pi, sqrt, symbols from sympy.physics.vector import Dyadic, Point, ReferenceFrame, Vector from sympy.physics.vector.functions import (cross, dot, express, time_derivative, kinematic_equations, outer, partial_velocity, get_motion_params, dynamicsymbols) from sympy.testing.pytest import raises Vector.simp = True q1, q2, q3, q4, q5 = symbols('q1 q2 q3 q4 q5') N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q1, N.z]) B = A.orientnew('B', 'Axis', [q2, A.x]) C = B.orientnew('C', 'Axis', [q3, B.y]) def test_dot(): assert dot(A.x, A.x) == 1 assert dot(A.x, A.y) == 0 assert dot(A.x, A.z) == 0 assert dot(A.y, A.x) == 0 assert dot(A.y, A.y) == 1 assert dot(A.y, A.z) == 0 assert dot(A.z, A.x) == 0 assert dot(A.z, A.y) == 0 assert dot(A.z, A.z) == 1 def test_dot_different_frames(): assert dot(N.x, A.x) == cos(q1) assert dot(N.x, A.y) == -sin(q1) assert dot(N.x, A.z) == 0 assert dot(N.y, A.x) == sin(q1) assert dot(N.y, A.y) == cos(q1) assert dot(N.y, A.z) == 0 assert dot(N.z, A.x) == 0 assert dot(N.z, A.y) == 0 assert dot(N.z, A.z) == 1 assert dot(N.x, A.x + A.y) == sqrt(2)*cos(q1 + pi/4) == dot(A.x + A.y, N.x) assert dot(A.x, C.x) == cos(q3) assert dot(A.x, C.y) == 0 assert dot(A.x, C.z) == sin(q3) assert dot(A.y, C.x) == sin(q2)*sin(q3) assert dot(A.y, C.y) == cos(q2) assert dot(A.y, C.z) == -sin(q2)*cos(q3) assert dot(A.z, C.x) == -cos(q2)*sin(q3) assert dot(A.z, C.y) == sin(q2) assert dot(A.z, C.z) == cos(q2)*cos(q3) def test_cross(): assert cross(A.x, A.x) == 0 assert cross(A.x, A.y) == A.z assert cross(A.x, A.z) == -A.y assert cross(A.y, A.x) == -A.z assert cross(A.y, A.y) == 0 assert cross(A.y, A.z) == A.x assert cross(A.z, A.x) == A.y assert cross(A.z, A.y) == -A.x assert cross(A.z, A.z) == 0 def test_cross_different_frames(): assert cross(N.x, A.x) == sin(q1)*A.z assert cross(N.x, A.y) == cos(q1)*A.z assert cross(N.x, A.z) == -sin(q1)*A.x - cos(q1)*A.y assert cross(N.y, A.x) == -cos(q1)*A.z assert cross(N.y, A.y) == sin(q1)*A.z assert cross(N.y, A.z) == cos(q1)*A.x - sin(q1)*A.y assert cross(N.z, A.x) == A.y assert cross(N.z, A.y) == -A.x assert cross(N.z, A.z) == 0 assert cross(N.x, A.x) == sin(q1)*A.z assert cross(N.x, A.y) == cos(q1)*A.z assert cross(N.x, A.x + A.y) == sin(q1)*A.z + cos(q1)*A.z assert cross(A.x + A.y, N.x) == -sin(q1)*A.z - cos(q1)*A.z assert cross(A.x, C.x) == sin(q3)*C.y assert cross(A.x, C.y) == -sin(q3)*C.x + cos(q3)*C.z assert cross(A.x, C.z) == -cos(q3)*C.y assert cross(C.x, A.x) == -sin(q3)*C.y assert cross(C.y, A.x) == sin(q3)*C.x - cos(q3)*C.z assert cross(C.z, A.x) == cos(q3)*C.y def test_operator_match(): """Test that the output of dot, cross, outer functions match operator behavior. """ A = ReferenceFrame('A') v = A.x + A.y d = v | v zerov = Vector(0) zerod = Dyadic(0) # dot products assert d & d == dot(d, d) assert d & zerod == dot(d, zerod) assert zerod & d == dot(zerod, d) assert d & v == dot(d, v) assert v & d == dot(v, d) assert d & zerov == dot(d, zerov) assert zerov & d == dot(zerov, d) raises(TypeError, lambda: dot(d, S.Zero)) raises(TypeError, lambda: dot(S.Zero, d)) raises(TypeError, lambda: dot(d, 0)) raises(TypeError, lambda: dot(0, d)) assert v & v == dot(v, v) assert v & zerov == dot(v, zerov) assert zerov & v == dot(zerov, v) raises(TypeError, lambda: dot(v, S.Zero)) raises(TypeError, lambda: dot(S.Zero, v)) raises(TypeError, lambda: dot(v, 0)) raises(TypeError, lambda: dot(0, v)) # cross products raises(TypeError, lambda: cross(d, d)) raises(TypeError, lambda: cross(d, zerod)) raises(TypeError, lambda: cross(zerod, d)) assert d ^ v == cross(d, v) assert v ^ d == cross(v, d) assert d ^ zerov == cross(d, zerov) assert zerov ^ d == cross(zerov, d) assert zerov ^ d == cross(zerov, d) raises(TypeError, lambda: cross(d, S.Zero)) raises(TypeError, lambda: cross(S.Zero, d)) raises(TypeError, lambda: cross(d, 0)) raises(TypeError, lambda: cross(0, d)) assert v ^ v == cross(v, v) assert v ^ zerov == cross(v, zerov) assert zerov ^ v == cross(zerov, v) raises(TypeError, lambda: cross(v, S.Zero)) raises(TypeError, lambda: cross(S.Zero, v)) raises(TypeError, lambda: cross(v, 0)) raises(TypeError, lambda: cross(0, v)) # outer products raises(TypeError, lambda: outer(d, d)) raises(TypeError, lambda: outer(d, zerod)) raises(TypeError, lambda: outer(zerod, d)) raises(TypeError, lambda: outer(d, v)) raises(TypeError, lambda: outer(v, d)) raises(TypeError, lambda: outer(d, zerov)) raises(TypeError, lambda: outer(zerov, d)) raises(TypeError, lambda: outer(zerov, d)) raises(TypeError, lambda: outer(d, S.Zero)) raises(TypeError, lambda: outer(S.Zero, d)) raises(TypeError, lambda: outer(d, 0)) raises(TypeError, lambda: outer(0, d)) assert v | v == outer(v, v) assert v | zerov == outer(v, zerov) assert zerov | v == outer(zerov, v) raises(TypeError, lambda: outer(v, S.Zero)) raises(TypeError, lambda: outer(S.Zero, v)) raises(TypeError, lambda: outer(v, 0)) raises(TypeError, lambda: outer(0, v)) def test_express(): assert express(Vector(0), N) == Vector(0) assert express(S.Zero, N) is S.Zero assert express(A.x, C) == cos(q3)*C.x + sin(q3)*C.z assert express(A.y, C) == sin(q2)*sin(q3)*C.x + cos(q2)*C.y - \ sin(q2)*cos(q3)*C.z assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \ cos(q2)*cos(q3)*C.z assert express(A.x, N) == cos(q1)*N.x + sin(q1)*N.y assert express(A.y, N) == -sin(q1)*N.x + cos(q1)*N.y assert express(A.z, N) == N.z assert express(A.x, A) == A.x assert express(A.y, A) == A.y assert express(A.z, A) == A.z assert express(A.x, B) == B.x assert express(A.y, B) == cos(q2)*B.y - sin(q2)*B.z assert express(A.z, B) == sin(q2)*B.y + cos(q2)*B.z assert express(A.x, C) == cos(q3)*C.x + sin(q3)*C.z assert express(A.y, C) == sin(q2)*sin(q3)*C.x + cos(q2)*C.y - \ sin(q2)*cos(q3)*C.z assert express(A.z, C) == -sin(q3)*cos(q2)*C.x + sin(q2)*C.y + \ cos(q2)*cos(q3)*C.z # Check to make sure UnitVectors get converted properly assert express(N.x, N) == N.x assert express(N.y, N) == N.y assert express(N.z, N) == N.z assert express(N.x, A) == (cos(q1)*A.x - sin(q1)*A.y) assert express(N.y, A) == (sin(q1)*A.x + cos(q1)*A.y) assert express(N.z, A) == A.z assert express(N.x, B) == (cos(q1)*B.x - sin(q1)*cos(q2)*B.y + sin(q1)*sin(q2)*B.z) assert express(N.y, B) == (sin(q1)*B.x + cos(q1)*cos(q2)*B.y - sin(q2)*cos(q1)*B.z) assert express(N.z, B) == (sin(q2)*B.y + cos(q2)*B.z) assert express(N.x, C) == ( (cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*C.x - sin(q1)*cos(q2)*C.y + (sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*C.z) assert express(N.y, C) == ( (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*C.x + cos(q1)*cos(q2)*C.y + (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*C.z) assert express(N.z, C) == (-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + cos(q2)*cos(q3)*C.z) assert express(A.x, N) == (cos(q1)*N.x + sin(q1)*N.y) assert express(A.y, N) == (-sin(q1)*N.x + cos(q1)*N.y) assert express(A.z, N) == N.z assert express(A.x, A) == A.x assert express(A.y, A) == A.y assert express(A.z, A) == A.z assert express(A.x, B) == B.x assert express(A.y, B) == (cos(q2)*B.y - sin(q2)*B.z) assert express(A.z, B) == (sin(q2)*B.y + cos(q2)*B.z) assert express(A.x, C) == (cos(q3)*C.x + sin(q3)*C.z) assert express(A.y, C) == (sin(q2)*sin(q3)*C.x + cos(q2)*C.y - sin(q2)*cos(q3)*C.z) assert express(A.z, C) == (-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + cos(q2)*cos(q3)*C.z) assert express(B.x, N) == (cos(q1)*N.x + sin(q1)*N.y) assert express(B.y, N) == (-sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z) assert express(B.z, N) == (sin(q1)*sin(q2)*N.x - sin(q2)*cos(q1)*N.y + cos(q2)*N.z) assert express(B.x, A) == A.x assert express(B.y, A) == (cos(q2)*A.y + sin(q2)*A.z) assert express(B.z, A) == (-sin(q2)*A.y + cos(q2)*A.z) assert express(B.x, B) == B.x assert express(B.y, B) == B.y assert express(B.z, B) == B.z assert express(B.x, C) == (cos(q3)*C.x + sin(q3)*C.z) assert express(B.y, C) == C.y assert express(B.z, C) == (-sin(q3)*C.x + cos(q3)*C.z) assert express(C.x, N) == ( (cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*N.x + (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*N.y - sin(q3)*cos(q2)*N.z) assert express(C.y, N) == ( -sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z) assert express(C.z, N) == ( (sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*N.x + (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*N.y + cos(q2)*cos(q3)*N.z) assert express(C.x, A) == (cos(q3)*A.x + sin(q2)*sin(q3)*A.y - sin(q3)*cos(q2)*A.z) assert express(C.y, A) == (cos(q2)*A.y + sin(q2)*A.z) assert express(C.z, A) == (sin(q3)*A.x - sin(q2)*cos(q3)*A.y + cos(q2)*cos(q3)*A.z) assert express(C.x, B) == (cos(q3)*B.x - sin(q3)*B.z) assert express(C.y, B) == B.y assert express(C.z, B) == (sin(q3)*B.x + cos(q3)*B.z) assert express(C.x, C) == C.x assert express(C.y, C) == C.y assert express(C.z, C) == C.z == (C.z) # Check to make sure Vectors get converted back to UnitVectors assert N.x == express((cos(q1)*A.x - sin(q1)*A.y), N) assert N.y == express((sin(q1)*A.x + cos(q1)*A.y), N) assert N.x == express((cos(q1)*B.x - sin(q1)*cos(q2)*B.y + sin(q1)*sin(q2)*B.z), N) assert N.y == express((sin(q1)*B.x + cos(q1)*cos(q2)*B.y - sin(q2)*cos(q1)*B.z), N) assert N.z == express((sin(q2)*B.y + cos(q2)*B.z), N) """ These don't really test our code, they instead test the auto simplification (or lack thereof) of SymPy. assert N.x == express(( (cos(q1)*cos(q3)-sin(q1)*sin(q2)*sin(q3))*C.x - sin(q1)*cos(q2)*C.y + (sin(q3)*cos(q1)+sin(q1)*sin(q2)*cos(q3))*C.z), N) assert N.y == express(( (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*C.x + cos(q1)*cos(q2)*C.y + (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*C.z), N) assert N.z == express((-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + cos(q2)*cos(q3)*C.z), N) """ assert A.x == express((cos(q1)*N.x + sin(q1)*N.y), A) assert A.y == express((-sin(q1)*N.x + cos(q1)*N.y), A) assert A.y == express((cos(q2)*B.y - sin(q2)*B.z), A) assert A.z == express((sin(q2)*B.y + cos(q2)*B.z), A) assert A.x == express((cos(q3)*C.x + sin(q3)*C.z), A) # Tripsimp messes up here too. #print express((sin(q2)*sin(q3)*C.x + cos(q2)*C.y - # sin(q2)*cos(q3)*C.z), A) assert A.y == express((sin(q2)*sin(q3)*C.x + cos(q2)*C.y - sin(q2)*cos(q3)*C.z), A) assert A.z == express((-sin(q3)*cos(q2)*C.x + sin(q2)*C.y + cos(q2)*cos(q3)*C.z), A) assert B.x == express((cos(q1)*N.x + sin(q1)*N.y), B) assert B.y == express((-sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z), B) assert B.z == express((sin(q1)*sin(q2)*N.x - sin(q2)*cos(q1)*N.y + cos(q2)*N.z), B) assert B.y == express((cos(q2)*A.y + sin(q2)*A.z), B) assert B.z == express((-sin(q2)*A.y + cos(q2)*A.z), B) assert B.x == express((cos(q3)*C.x + sin(q3)*C.z), B) assert B.z == express((-sin(q3)*C.x + cos(q3)*C.z), B) """ assert C.x == express(( (cos(q1)*cos(q3)-sin(q1)*sin(q2)*sin(q3))*N.x + (sin(q1)*cos(q3)+sin(q2)*sin(q3)*cos(q1))*N.y - sin(q3)*cos(q2)*N.z), C) assert C.y == express(( -sin(q1)*cos(q2)*N.x + cos(q1)*cos(q2)*N.y + sin(q2)*N.z), C) assert C.z == express(( (sin(q3)*cos(q1)+sin(q1)*sin(q2)*cos(q3))*N.x + (sin(q1)*sin(q3)-sin(q2)*cos(q1)*cos(q3))*N.y + cos(q2)*cos(q3)*N.z), C) """ assert C.x == express((cos(q3)*A.x + sin(q2)*sin(q3)*A.y - sin(q3)*cos(q2)*A.z), C) assert C.y == express((cos(q2)*A.y + sin(q2)*A.z), C) assert C.z == express((sin(q3)*A.x - sin(q2)*cos(q3)*A.y + cos(q2)*cos(q3)*A.z), C) assert C.x == express((cos(q3)*B.x - sin(q3)*B.z), C) assert C.z == express((sin(q3)*B.x + cos(q3)*B.z), C) def test_time_derivative(): #The use of time_derivative for calculations pertaining to scalar #fields has been tested in test_coordinate_vars in test_essential.py A = ReferenceFrame('A') q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) B = A.orientnew('B', 'Axis', [q, A.z]) d = A.x | A.x assert time_derivative(d, B) == (-qd) * (A.y | A.x) + \ (-qd) * (A.x | A.y) d1 = A.x | B.y assert time_derivative(d1, A) == - qd*(A.x|B.x) assert time_derivative(d1, B) == - qd*(A.y|B.y) d2 = A.x | B.x assert time_derivative(d2, A) == qd*(A.x|B.y) assert time_derivative(d2, B) == - qd*(A.y|B.x) d3 = A.x | B.z assert time_derivative(d3, A) == 0 assert time_derivative(d3, B) == - qd*(A.y|B.z) q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2) C = B.orientnew('C', 'Axis', [q4, B.x]) v1 = q1 * A.z v2 = q2*A.x + q3*B.y v3 = q1*A.x + q2*A.y + q3*A.z assert time_derivative(B.x, C) == 0 assert time_derivative(B.y, C) == - q4d*B.z assert time_derivative(B.z, C) == q4d*B.y assert time_derivative(v1, B) == q1d*A.z assert time_derivative(v1, C) == - q1*sin(q)*q4d*A.x + \ q1*cos(q)*q4d*A.y + q1d*A.z assert time_derivative(v2, A) == q2d*A.x - q3*qd*B.x + q3d*B.y assert time_derivative(v2, C) == q2d*A.x - q2*qd*A.y + \ q2*sin(q)*q4d*A.z + q3d*B.y - q3*q4d*B.z assert time_derivative(v3, B) == (q2*qd + q1d)*A.x + \ (-q1*qd + q2d)*A.y + q3d*A.z assert time_derivative(d, C) == - qd*(A.y|A.x) + \ sin(q)*q4d*(A.z|A.x) - qd*(A.x|A.y) + sin(q)*q4d*(A.x|A.z) raises(ValueError, lambda: time_derivative(B.x, C, order=0.5)) raises(ValueError, lambda: time_derivative(B.x, C, order=-1)) def test_get_motion_methods(): #Initialization t = dynamicsymbols._t s1, s2, s3 = symbols('s1 s2 s3') S1, S2, S3 = symbols('S1 S2 S3') S4, S5, S6 = symbols('S4 S5 S6') t1, t2 = symbols('t1 t2') a, b, c = dynamicsymbols('a b c') ad, bd, cd = dynamicsymbols('a b c', 1) a2d, b2d, c2d = dynamicsymbols('a b c', 2) v0 = S1*N.x + S2*N.y + S3*N.z v01 = S4*N.x + S5*N.y + S6*N.z v1 = s1*N.x + s2*N.y + s3*N.z v2 = a*N.x + b*N.y + c*N.z v2d = ad*N.x + bd*N.y + cd*N.z v2dd = a2d*N.x + b2d*N.y + c2d*N.z #Test position parameter assert get_motion_params(frame = N) == (0, 0, 0) assert get_motion_params(N, position=v1) == (0, 0, v1) assert get_motion_params(N, position=v2) == (v2dd, v2d, v2) #Test velocity parameter assert get_motion_params(N, velocity=v1) == (0, v1, v1 * t) assert get_motion_params(N, velocity=v1, position=v0, timevalue1=t1) == \ (0, v1, v0 + v1*(t - t1)) answer = get_motion_params(N, velocity=v1, position=v2, timevalue1=t1) answer_expected = (0, v1, v1*t - v1*t1 + v2.subs(t, t1)) assert answer == answer_expected answer = get_motion_params(N, velocity=v2, position=v0, timevalue1=t1) integral_vector = Integral(a, (t, t1, t))*N.x + Integral(b, (t, t1, t))*N.y \ + Integral(c, (t, t1, t))*N.z answer_expected = (v2d, v2, v0 + integral_vector) assert answer == answer_expected #Test acceleration parameter assert get_motion_params(N, acceleration=v1) == \ (v1, v1 * t, v1 * t**2/2) assert get_motion_params(N, acceleration=v1, velocity=v0, position=v2, timevalue1=t1, timevalue2=t2) == \ (v1, (v0 + v1*t - v1*t2), -v0*t1 + v1*t**2/2 + v1*t2*t1 - \ v1*t1**2/2 + t*(v0 - v1*t2) + \ v2.subs(t, t1)) assert get_motion_params(N, acceleration=v1, velocity=v0, position=v01, timevalue1=t1, timevalue2=t2) == \ (v1, v0 + v1*t - v1*t2, -v0*t1 + v01 + v1*t**2/2 + \ v1*t2*t1 - v1*t1**2/2 + \ t*(v0 - v1*t2)) answer = get_motion_params(N, acceleration=a*N.x, velocity=S1*N.x, position=S2*N.x, timevalue1=t1, timevalue2=t2) i1 = Integral(a, (t, t2, t)) answer_expected = (a*N.x, (S1 + i1)*N.x, \ (S2 + Integral(S1 + i1, (t, t1, t)))*N.x) assert answer == answer_expected def test_kin_eqs(): q0, q1, q2, q3 = dynamicsymbols('q0 q1 q2 q3') q0d, q1d, q2d, q3d = dynamicsymbols('q0 q1 q2 q3', 1) u1, u2, u3 = dynamicsymbols('u1 u2 u3') ke = kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', 313) assert ke == kinematic_equations([u1,u2,u3], [q1,q2,q3], 'body', '313') kds = kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'quaternion') assert kds == [-0.5 * q0 * u1 - 0.5 * q2 * u3 + 0.5 * q3 * u2 + q1d, -0.5 * q0 * u2 + 0.5 * q1 * u3 - 0.5 * q3 * u1 + q2d, -0.5 * q0 * u3 - 0.5 * q1 * u2 + 0.5 * q2 * u1 + q3d, 0.5 * q1 * u1 + 0.5 * q2 * u2 + 0.5 * q3 * u3 + q0d] raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2], 'quaternion')) raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'quaternion', '123')) raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'foo')) raises(TypeError, lambda: kinematic_equations(u1, [q0, q1, q2, q3], 'quaternion')) raises(TypeError, lambda: kinematic_equations([u1], [q0, q1, q2, q3], 'quaternion')) raises(TypeError, lambda: kinematic_equations([u1, u2, u3], q0, 'quaternion')) raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'body')) raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2, q3], 'space')) raises(ValueError, lambda: kinematic_equations([u1, u2, u3], [q0, q1, q2], 'body', '222')) assert kinematic_equations([0, 0, 0], [q0, q1, q2], 'space') == [S.Zero, S.Zero, S.Zero] def test_partial_velocity(): q1, q2, q3, u1, u2, u3 = dynamicsymbols('q1 q2 q3 u1 u2 u3') u4, u5 = dynamicsymbols('u4, u5') r = symbols('r') N = ReferenceFrame('N') Y = N.orientnew('Y', 'Axis', [q1, N.z]) L = Y.orientnew('L', 'Axis', [q2, Y.x]) R = L.orientnew('R', 'Axis', [q3, L.y]) R.set_ang_vel(N, u1 * L.x + u2 * L.y + u3 * L.z) C = Point('C') C.set_vel(N, u4 * L.x + u5 * (Y.z ^ L.x)) Dmc = C.locatenew('Dmc', r * L.z) Dmc.v2pt_theory(C, N, R) vel_list = [Dmc.vel(N), C.vel(N), R.ang_vel_in(N)] u_list = [u1, u2, u3, u4, u5] assert (partial_velocity(vel_list, u_list, N) == [[- r*L.y, r*L.x, 0, L.x, cos(q2)*L.y - sin(q2)*L.z], [0, 0, 0, L.x, cos(q2)*L.y - sin(q2)*L.z], [L.x, L.y, L.z, 0, 0]]) # Make sure that partial velocities can be computed regardless if the # orientation between frames is defined or not. A = ReferenceFrame('A') B = ReferenceFrame('B') v = u4 * A.x + u5 * B.y assert partial_velocity((v, ), (u4, u5), A) == [[A.x, B.y]] raises(TypeError, lambda: partial_velocity(Dmc.vel(N), u_list, N)) raises(TypeError, lambda: partial_velocity(vel_list, u1, N)) def test_dynamicsymbols(): #Tests to check the assumptions applied to dynamicsymbols f1 = dynamicsymbols('f1') f2 = dynamicsymbols('f2', real=True) f3 = dynamicsymbols('f3', positive=True) f4, f5 = dynamicsymbols('f4,f5', commutative=False) f6 = dynamicsymbols('f6', integer=True) assert f1.is_real is None assert f2.is_real assert f3.is_positive assert f4*f5 != f5*f4 assert f6.is_integer sympy-sympy-1.9/sympy/physics/vector/tests/test_output.py000066400000000000000000000050701412543434000242050ustar00rootroot00000000000000from sympy import S from sympy.physics.vector import Vector, ReferenceFrame, Dyadic from sympy.testing.pytest import raises Vector.simp = True A = ReferenceFrame('A') def test_output_type(): A = ReferenceFrame('A') v = A.x + A.y d = v | v zerov = Vector(0) zerod = Dyadic(0) # dot products assert isinstance(d & d, Dyadic) assert isinstance(d & zerod, Dyadic) assert isinstance(zerod & d, Dyadic) assert isinstance(d & v, Vector) assert isinstance(v & d, Vector) assert isinstance(d & zerov, Vector) assert isinstance(zerov & d, Vector) raises(TypeError, lambda: d & S.Zero) raises(TypeError, lambda: S.Zero & d) raises(TypeError, lambda: d & 0) raises(TypeError, lambda: 0 & d) assert not isinstance(v & v, (Vector, Dyadic)) assert not isinstance(v & zerov, (Vector, Dyadic)) assert not isinstance(zerov & v, (Vector, Dyadic)) raises(TypeError, lambda: v & S.Zero) raises(TypeError, lambda: S.Zero & v) raises(TypeError, lambda: v & 0) raises(TypeError, lambda: 0 & v) # cross products raises(TypeError, lambda: d ^ d) raises(TypeError, lambda: d ^ zerod) raises(TypeError, lambda: zerod ^ d) assert isinstance(d ^ v, Dyadic) assert isinstance(v ^ d, Dyadic) assert isinstance(d ^ zerov, Dyadic) assert isinstance(zerov ^ d, Dyadic) assert isinstance(zerov ^ d, Dyadic) raises(TypeError, lambda: d ^ S.Zero) raises(TypeError, lambda: S.Zero ^ d) raises(TypeError, lambda: d ^ 0) raises(TypeError, lambda: 0 ^ d) assert isinstance(v ^ v, Vector) assert isinstance(v ^ zerov, Vector) assert isinstance(zerov ^ v, Vector) raises(TypeError, lambda: v ^ S.Zero) raises(TypeError, lambda: S.Zero ^ v) raises(TypeError, lambda: v ^ 0) raises(TypeError, lambda: 0 ^ v) # outer products raises(TypeError, lambda: d | d) raises(TypeError, lambda: d | zerod) raises(TypeError, lambda: zerod | d) raises(TypeError, lambda: d | v) raises(TypeError, lambda: v | d) raises(TypeError, lambda: d | zerov) raises(TypeError, lambda: zerov | d) raises(TypeError, lambda: zerov | d) raises(TypeError, lambda: d | S.Zero) raises(TypeError, lambda: S.Zero | d) raises(TypeError, lambda: d | 0) raises(TypeError, lambda: 0 | d) assert isinstance(v | v, Dyadic) assert isinstance(v | zerov, Dyadic) assert isinstance(zerov | v, Dyadic) raises(TypeError, lambda: v | S.Zero) raises(TypeError, lambda: S.Zero | v) raises(TypeError, lambda: v | 0) raises(TypeError, lambda: 0 | v) sympy-sympy-1.9/sympy/physics/vector/tests/test_point.py000066400000000000000000000236231412543434000240020ustar00rootroot00000000000000from sympy.physics.vector import dynamicsymbols, Point, ReferenceFrame from sympy.testing.pytest import raises, ignore_warnings import warnings def test_point_v1pt_theorys(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) qdd, q2dd = dynamicsymbols('q q2', 2) N = ReferenceFrame('N') B = ReferenceFrame('B') B.set_ang_vel(N, qd * B.z) O = Point('O') P = O.locatenew('P', B.x) P.set_vel(B, 0) O.set_vel(N, 0) assert P.v1pt_theory(O, N, B) == qd * B.y O.set_vel(N, N.x) assert P.v1pt_theory(O, N, B) == N.x + qd * B.y P.set_vel(B, B.z) assert P.v1pt_theory(O, N, B) == B.z + N.x + qd * B.y def test_point_a1pt_theorys(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) qdd, q2dd = dynamicsymbols('q q2', 2) N = ReferenceFrame('N') B = ReferenceFrame('B') B.set_ang_vel(N, qd * B.z) O = Point('O') P = O.locatenew('P', B.x) P.set_vel(B, 0) O.set_vel(N, 0) assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y P.set_vel(B, q2d * B.z) assert P.a1pt_theory(O, N, B) == -(qd**2) * B.x + qdd * B.y + q2dd * B.z O.set_vel(N, q2d * B.x) assert P.a1pt_theory(O, N, B) == ((q2dd - qd**2) * B.x + (q2d * qd + qdd) * B.y + q2dd * B.z) def test_point_v2pt_theorys(): q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) N = ReferenceFrame('N') B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 0) O.set_vel(N, 0) assert P.v2pt_theory(O, N, B) == 0 P = O.locatenew('P', B.x) assert P.v2pt_theory(O, N, B) == (qd * B.z ^ B.x) O.set_vel(N, N.x) assert P.v2pt_theory(O, N, B) == N.x + qd * B.y def test_point_a2pt_theorys(): q = dynamicsymbols('q') qd = dynamicsymbols('q', 1) qdd = dynamicsymbols('q', 2) N = ReferenceFrame('N') B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 0) O.set_vel(N, 0) assert P.a2pt_theory(O, N, B) == 0 P.set_pos(O, B.x) assert P.a2pt_theory(O, N, B) == (-qd**2) * B.x + (qdd) * B.y def test_point_funcs(): q, q2 = dynamicsymbols('q q2') qd, q2d = dynamicsymbols('q q2', 1) qdd, q2dd = dynamicsymbols('q q2', 2) N = ReferenceFrame('N') B = ReferenceFrame('B') B.set_ang_vel(N, 5 * B.y) O = Point('O') P = O.locatenew('P', q * B.x) assert P.pos_from(O) == q * B.x P.set_vel(B, qd * B.x + q2d * B.y) assert P.vel(B) == qd * B.x + q2d * B.y O.set_vel(N, 0) assert O.vel(N) == 0 assert P.a1pt_theory(O, N, B) == ((-25 * q + qdd) * B.x + (q2dd) * B.y + (-10 * qd) * B.z) B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 10 * B.x) O.set_vel(N, 5 * N.x) assert O.vel(N) == 5 * N.x assert P.a2pt_theory(O, N, B) == (-10 * qd**2) * B.x + (10 * qdd) * B.y B.set_ang_vel(N, 5 * B.y) O = Point('O') P = O.locatenew('P', q * B.x) P.set_vel(B, qd * B.x + q2d * B.y) O.set_vel(N, 0) assert P.v1pt_theory(O, N, B) == qd * B.x + q2d * B.y - 5 * q * B.z def test_point_pos(): q = dynamicsymbols('q') N = ReferenceFrame('N') B = N.orientnew('B', 'Axis', [q, N.z]) O = Point('O') P = O.locatenew('P', 10 * N.x + 5 * B.x) assert P.pos_from(O) == 10 * N.x + 5 * B.x Q = P.locatenew('Q', 10 * N.y + 5 * B.y) assert Q.pos_from(P) == 10 * N.y + 5 * B.y assert Q.pos_from(O) == 10 * N.x + 10 * N.y + 5 * B.x + 5 * B.y assert O.pos_from(Q) == -10 * N.x - 10 * N.y - 5 * B.x - 5 * B.y def test_point_partial_velocity(): N = ReferenceFrame('N') A = ReferenceFrame('A') p = Point('p') u1, u2 = dynamicsymbols('u1, u2') p.set_vel(N, u1 * A.x + u2 * N.y) assert p.partial_velocity(N, u1) == A.x assert p.partial_velocity(N, u1, u2) == (A.x, N.y) raises(ValueError, lambda: p.partial_velocity(A, u1)) def test_point_vel(): #Basic functionality q1, q2 = dynamicsymbols('q1 q2') N = ReferenceFrame('N') B = ReferenceFrame('B') Q = Point('Q') O = Point('O') Q.set_pos(O, q1 * N.x) raises(ValueError , lambda: Q.vel(N)) # Velocity of O in N is not defined O.set_vel(N, q2 * N.y) assert O.vel(N) == q2 * N.y raises(ValueError , lambda : O.vel(B)) #Velocity of O is not defined in B def test_auto_point_vel(): t = dynamicsymbols._t q1, q2 = dynamicsymbols('q1 q2') N = ReferenceFrame('N') B = ReferenceFrame('B') O = Point('O') Q = Point('Q') Q.set_pos(O, q1 * N.x) O.set_vel(N, q2 * N.y) assert Q.vel(N) == q1.diff(t) * N.x + q2 * N.y # Velocity of Q using O P1 = Point('P1') P1.set_pos(O, q1 * B.x) P2 = Point('P2') P2.set_pos(P1, q2 * B.z) raises(ValueError, lambda : P2.vel(B)) # O's velocity is defined in different frame, and no #point in between has its velocity defined raises(ValueError, lambda: P2.vel(N)) # Velocity of O not defined in N def test_auto_point_vel_multiple_point_path(): t = dynamicsymbols._t q1, q2 = dynamicsymbols('q1 q2') B = ReferenceFrame('B') P = Point('P') P.set_vel(B, q1 * B.x) P1 = Point('P1') P1.set_pos(P, q2 * B.y) P1.set_vel(B, q1 * B.z) P2 = Point('P2') P2.set_pos(P1, q1 * B.z) P3 = Point('P3') P3.set_pos(P2, 10 * q1 * B.y) assert P3.vel(B) == 10 * q1.diff(t) * B.y + (q1 + q1.diff(t)) * B.z def test_auto_vel_dont_overwrite(): t = dynamicsymbols._t q1, q2, u1 = dynamicsymbols('q1, q2, u1') N = ReferenceFrame('N') P = Point('P1') P.set_vel(N, u1 * N.x) P1 = Point('P1') P1.set_pos(P, q2 * N.y) assert P1.vel(N) == q2.diff(t) * N.y + u1 * N.x assert P.vel(N) == u1 * N.x P1.set_vel(N, u1 * N.z) assert P1.vel(N) == u1 * N.z def test_auto_point_vel_if_tree_has_vel_but_inappropriate_pos_vector(): q1, q2 = dynamicsymbols('q1 q2') B = ReferenceFrame('B') S = ReferenceFrame('S') P = Point('P') P.set_vel(B, q1 * B.x) P1 = Point('P1') P1.set_pos(P, S.y) raises(ValueError, lambda : P1.vel(B)) # P1.pos_from(P) can't be expressed in B raises(ValueError, lambda : P1.vel(S)) # P.vel(S) not defined def test_auto_point_vel_shortest_path(): t = dynamicsymbols._t q1, q2, u1, u2 = dynamicsymbols('q1 q2 u1 u2') B = ReferenceFrame('B') P = Point('P') P.set_vel(B, u1 * B.x) P1 = Point('P1') P1.set_pos(P, q2 * B.y) P1.set_vel(B, q1 * B.z) P2 = Point('P2') P2.set_pos(P1, q1 * B.z) P3 = Point('P3') P3.set_pos(P2, 10 * q1 * B.y) P4 = Point('P4') P4.set_pos(P3, q1 * B.x) O = Point('O') O.set_vel(B, u2 * B.y) O1 = Point('O1') O1.set_pos(O, q2 * B.z) P4.set_pos(O1, q1 * B.x + q2 * B.z) with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised warnings.simplefilter('error') with ignore_warnings(UserWarning): assert P4.vel(B) == q1.diff(t) * B.x + u2 * B.y + 2 * q2.diff(t) * B.z def test_auto_point_vel_connected_frames(): t = dynamicsymbols._t q, q1, q2, u = dynamicsymbols('q q1 q2 u') N = ReferenceFrame('N') B = ReferenceFrame('B') O = Point('O') O.set_vel(N, u * N.x) P = Point('P') P.set_pos(O, q1 * N.x + q2 * B.y) raises(ValueError, lambda: P.vel(N)) N.orient(B, 'Axis', (q, B.x)) assert P.vel(N) == (u + q1.diff(t)) * N.x + q2.diff(t) * B.y - q2 * q.diff(t) * B.z def test_auto_point_vel_multiple_paths_warning_arises(): q, u = dynamicsymbols('q u') N = ReferenceFrame('N') O = Point('O') P = Point('P') Q = Point('Q') R = Point('R') P.set_vel(N, u * N.x) Q.set_vel(N, u *N.y) R.set_vel(N, u * N.z) O.set_pos(P, q * N.z) O.set_pos(Q, q * N.y) O.set_pos(R, q * N.x) with warnings.catch_warnings(): #There are two possible paths in this point tree, thus a warning is raised warnings.simplefilter("error") raises(UserWarning ,lambda: O.vel(N)) def test_auto_vel_cyclic_warning_arises(): P = Point('P') P1 = Point('P1') P2 = Point('P2') P3 = Point('P3') N = ReferenceFrame('N') P.set_vel(N, N.x) P1.set_pos(P, N.x) P2.set_pos(P1, N.y) P3.set_pos(P2, N.z) P1.set_pos(P3, N.x + N.y) with warnings.catch_warnings(): #The path is cyclic at P1, thus a warning is raised warnings.simplefilter("error") raises(UserWarning ,lambda: P2.vel(N)) def test_auto_vel_cyclic_warning_msg(): P = Point('P') P1 = Point('P1') P2 = Point('P2') P3 = Point('P3') N = ReferenceFrame('N') P.set_vel(N, N.x) P1.set_pos(P, N.x) P2.set_pos(P1, N.y) P3.set_pos(P2, N.z) P1.set_pos(P3, N.x + N.y) with warnings.catch_warnings(record = True) as w: #The path is cyclic at P1, thus a warning is raised warnings.simplefilter("always") P2.vel(N) assert issubclass(w[-1].category, UserWarning) assert 'Kinematic loops are defined among the positions of points. This is likely not desired and may cause errors in your calculations.' in str(w[-1].message) def test_auto_vel_multiple_path_warning_msg(): N = ReferenceFrame('N') O = Point('O') P = Point('P') Q = Point('Q') P.set_vel(N, N.x) Q.set_vel(N, N.y) O.set_pos(P, N.z) O.set_pos(Q, N.y) with warnings.catch_warnings(record = True) as w: #There are two possible paths in this point tree, thus a warning is raised warnings.simplefilter("always") O.vel(N) assert issubclass(w[-1].category, UserWarning) assert 'Velocity automatically calculated based on point' in str(w[-1].message) assert 'Velocities from these points are not necessarily the same. This may cause errors in your calculations.' in str(w[-1].message) def test_vel_frame(): N = ReferenceFrame('N') A = ReferenceFrame('A') A.orient_axis(N, N.x, 0) P = Point('P') P.set_vel(N, 5*N.x) P1 = Point('P1') P1.set_pos(P, A.x+N.x) P1.set_vel(A, 10*A.x) assert P1.vel(N) == 5*N.x + 10*A.x sympy-sympy-1.9/sympy/physics/vector/tests/test_printing.py000066400000000000000000000240541412543434000245020ustar00rootroot00000000000000# -*- coding: utf-8 -*- from sympy import symbols, sin, asin, cos, sqrt, Function from sympy.physics.vector import ReferenceFrame, dynamicsymbols, Dyadic from sympy.physics.vector.printing import (VectorLatexPrinter, vpprint, vsprint, vsstrrepr, vlatex) a, b, c = symbols('a, b, c') alpha, omega, beta = dynamicsymbols('alpha, omega, beta') A = ReferenceFrame('A') N = ReferenceFrame('N') v = a ** 2 * N.x + b * N.y + c * sin(alpha) * N.z w = alpha * N.x + sin(omega) * N.y + alpha * beta * N.z ww = alpha * N.x + asin(omega) * N.y - alpha.diff() * beta * N.z o = a/b * N.x + (c+b)/a * N.y + c**2/b * N.z y = a ** 2 * (N.x | N.y) + b * (N.y | N.y) + c * sin(alpha) * (N.z | N.y) x = alpha * (N.x | N.x) + sin(omega) * (N.y | N.z) + alpha * beta * (N.z | N.x) xx = N.x | (-N.y - N.z) xx2 = N.x | (N.y + N.z) def ascii_vpretty(expr): return vpprint(expr, use_unicode=False, wrap_line=False) def unicode_vpretty(expr): return vpprint(expr, use_unicode=True, wrap_line=False) def test_latex_printer(): r = Function('r')('t') assert VectorLatexPrinter().doprint(r ** 2) == "r^{2}" r2 = Function('r^2')('t') assert VectorLatexPrinter().doprint(r2.diff()) == r'\dot{r^{2}}' ra = Function('r__a')('t') assert VectorLatexPrinter().doprint(ra.diff().diff()) == r'\ddot{r^{a}}' def test_vector_pretty_print(): # TODO : The unit vectors should print with subscripts but they just # print as `n_x` instead of making `x` a subscript with unicode. # TODO : The pretty print division does not print correctly here: # w = alpha * N.x + sin(omega) * N.y + alpha / beta * N.z expected = """\ 2 a n_x + b n_y + c*sin(alpha) n_z\ """ uexpected = """\ 2 a n_x + b n_y + c⋅sin(α) n_z\ """ assert ascii_vpretty(v) == expected assert unicode_vpretty(v) == uexpected expected = 'alpha n_x + sin(omega) n_y + alpha*beta n_z' uexpected = 'α n_x + sin(ω) n_y + α⋅β n_z' assert ascii_vpretty(w) == expected assert unicode_vpretty(w) == uexpected expected = """\ 2 a b + c c - n_x + ----- n_y + -- n_z b a b\ """ uexpected = """\ 2 a b + c c ─ n_x + ───── n_y + ── n_z b a b\ """ assert ascii_vpretty(o) == expected assert unicode_vpretty(o) == uexpected def test_vector_latex(): a, b, c, d, omega = symbols('a, b, c, d, omega') v = (a ** 2 + b / c) * A.x + sqrt(d) * A.y + cos(omega) * A.z assert vlatex(v) == (r'(a^{2} + \frac{b}{c})\mathbf{\hat{a}_x} + ' r'\sqrt{d}\mathbf{\hat{a}_y} + ' r'\cos{\left(\omega \right)}' r'\mathbf{\hat{a}_z}') theta, omega, alpha, q = dynamicsymbols('theta, omega, alpha, q') v = theta * A.x + omega * omega * A.y + (q * alpha) * A.z assert vlatex(v) == (r'\theta\mathbf{\hat{a}_x} + ' r'\omega^{2}\mathbf{\hat{a}_y} + ' r'\alpha q\mathbf{\hat{a}_z}') phi1, phi2, phi3 = dynamicsymbols('phi1, phi2, phi3') theta1, theta2, theta3 = symbols('theta1, theta2, theta3') v = (sin(theta1) * A.x + cos(phi1) * cos(phi2) * A.y + cos(theta1 + phi3) * A.z) assert vlatex(v) == (r'\sin{\left(\theta_{1} \right)}' r'\mathbf{\hat{a}_x} + \cos{' r'\left(\phi_{1} \right)} \cos{' r'\left(\phi_{2} \right)}\mathbf{\hat{a}_y} + ' r'\cos{\left(\theta_{1} + ' r'\phi_{3} \right)}\mathbf{\hat{a}_z}') N = ReferenceFrame('N') a, b, c, d, omega = symbols('a, b, c, d, omega') v = (a ** 2 + b / c) * N.x + sqrt(d) * N.y + cos(omega) * N.z expected = (r'(a^{2} + \frac{b}{c})\mathbf{\hat{n}_x} + ' r'\sqrt{d}\mathbf{\hat{n}_y} + ' r'\cos{\left(\omega \right)}' r'\mathbf{\hat{n}_z}') assert vlatex(v) == expected # Try custom unit vectors. N = ReferenceFrame('N', latexs=(r'\hat{i}', r'\hat{j}', r'\hat{k}')) v = (a ** 2 + b / c) * N.x + sqrt(d) * N.y + cos(omega) * N.z expected = (r'(a^{2} + \frac{b}{c})\hat{i} + ' r'\sqrt{d}\hat{j} + ' r'\cos{\left(\omega \right)}\hat{k}') assert vlatex(v) == expected expected = r'\alpha\mathbf{\hat{n}_x} + \operatorname{asin}{\left(\omega ' \ r'\right)}\mathbf{\hat{n}_y} - \beta \dot{\alpha}\mathbf{\hat{n}_z}' assert vlatex(ww) == expected expected = r'- \mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} - ' \ r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_z}' assert vlatex(xx) == expected expected = r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} + ' \ r'\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_z}' assert vlatex(xx2) == expected def test_vector_latex_arguments(): assert vlatex(N.x * 3.0, full_prec=False) == r'3.0\mathbf{\hat{n}_x}' assert vlatex(N.x * 3.0, full_prec=True) == r'3.00000000000000\mathbf{\hat{n}_x}' def test_vector_latex_with_functions(): N = ReferenceFrame('N') omega, alpha = dynamicsymbols('omega, alpha') v = omega.diff() * N.x assert vlatex(v) == r'\dot{\omega}\mathbf{\hat{n}_x}' v = omega.diff() ** alpha * N.x assert vlatex(v) == (r'\dot{\omega}^{\alpha}' r'\mathbf{\hat{n}_x}') def test_dyadic_pretty_print(): expected = """\ 2 a n_x|n_y + b n_y|n_y + c*sin(alpha) n_z|n_y\ """ uexpected = """\ 2 a n_x⊗n_y + b n_y⊗n_y + c⋅sin(α) n_z⊗n_y\ """ assert ascii_vpretty(y) == expected assert unicode_vpretty(y) == uexpected expected = 'alpha n_x|n_x + sin(omega) n_y|n_z + alpha*beta n_z|n_x' uexpected = 'α n_x⊗n_x + sin(ω) n_y⊗n_z + α⋅β n_z⊗n_x' assert ascii_vpretty(x) == expected assert unicode_vpretty(x) == uexpected assert ascii_vpretty(Dyadic([])) == '0' assert unicode_vpretty(Dyadic([])) == '0' assert ascii_vpretty(xx) == '- n_x|n_y - n_x|n_z' assert unicode_vpretty(xx) == '- n_x⊗n_y - n_x⊗n_z' assert ascii_vpretty(xx2) == 'n_x|n_y + n_x|n_z' assert unicode_vpretty(xx2) == 'n_x⊗n_y + n_x⊗n_z' def test_dyadic_latex(): expected = (r'a^{2}\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_y} + ' r'b\mathbf{\hat{n}_y}\otimes \mathbf{\hat{n}_y} + ' r'c \sin{\left(\alpha \right)}' r'\mathbf{\hat{n}_z}\otimes \mathbf{\hat{n}_y}') assert vlatex(y) == expected expected = (r'\alpha\mathbf{\hat{n}_x}\otimes \mathbf{\hat{n}_x} + ' r'\sin{\left(\omega \right)}\mathbf{\hat{n}_y}' r'\otimes \mathbf{\hat{n}_z} + ' r'\alpha \beta\mathbf{\hat{n}_z}\otimes \mathbf{\hat{n}_x}') assert vlatex(x) == expected assert vlatex(Dyadic([])) == '0' def test_dyadic_str(): assert vsprint(Dyadic([])) == '0' assert vsprint(y) == 'a**2*(N.x|N.y) + b*(N.y|N.y) + c*sin(alpha)*(N.z|N.y)' assert vsprint(x) == 'alpha*(N.x|N.x) + sin(omega)*(N.y|N.z) + alpha*beta*(N.z|N.x)' assert vsprint(ww) == "alpha*N.x + asin(omega)*N.y - beta*alpha'*N.z" assert vsprint(xx) == '- (N.x|N.y) - (N.x|N.z)' assert vsprint(xx2) == '(N.x|N.y) + (N.x|N.z)' def test_vlatex(): # vlatex is broken #12078 from sympy.physics.vector import vlatex x = symbols('x') J = symbols('J') f = Function('f') g = Function('g') h = Function('h') expected = r'J \left(\frac{d}{d x} g{\left(x \right)} - \frac{d}{d x} h{\left(x \right)}\right)' expr = J*f(x).diff(x).subs(f(x), g(x)-h(x)) assert vlatex(expr) == expected def test_issue_13354(): """ Test for proper pretty printing of physics vectors with ADD instances in arguments. Test is exactly the one suggested in the original bug report by @moorepants. """ a, b, c = symbols('a, b, c') A = ReferenceFrame('A') v = a * A.x + b * A.y + c * A.z w = b * A.x + c * A.y + a * A.z z = w + v expected = """(a + b) a_x + (b + c) a_y + (a + c) a_z""" assert ascii_vpretty(z) == expected def test_vector_derivative_printing(): # First order v = omega.diff() * N.x assert unicode_vpretty(v) == 'ω̇ n_x' assert ascii_vpretty(v) == "omega'(t) n_x" # Second order v = omega.diff().diff() * N.x assert vlatex(v) == r'\ddot{\omega}\mathbf{\hat{n}_x}' assert unicode_vpretty(v) == 'ω̈ n_x' assert ascii_vpretty(v) == "omega''(t) n_x" # Third order v = omega.diff().diff().diff() * N.x assert vlatex(v) == r'\dddot{\omega}\mathbf{\hat{n}_x}' assert unicode_vpretty(v) == 'ω⃛ n_x' assert ascii_vpretty(v) == "omega'''(t) n_x" # Fourth order v = omega.diff().diff().diff().diff() * N.x assert vlatex(v) == r'\ddddot{\omega}\mathbf{\hat{n}_x}' assert unicode_vpretty(v) == 'ω⃜ n_x' assert ascii_vpretty(v) == "omega''''(t) n_x" # Fifth order v = omega.diff().diff().diff().diff().diff() * N.x assert vlatex(v) == r'\frac{d^{5}}{d t^{5}} \omega\mathbf{\hat{n}_x}' assert unicode_vpretty(v) == ' 5\n d\n───(ω) n_x\n 5\ndt' assert ascii_vpretty(v) == ' 5\n d\n---(omega) n_x\n 5\ndt' def test_vector_str_printing(): assert vsprint(w) == 'alpha*N.x + sin(omega)*N.y + alpha*beta*N.z' assert vsprint(omega.diff() * N.x) == "omega'*N.x" assert vsstrrepr(w) == 'alpha*N.x + sin(omega)*N.y + alpha*beta*N.z' def test_vector_str_arguments(): assert vsprint(N.x * 3.0, full_prec=False) == '3.0*N.x' assert vsprint(N.x * 3.0, full_prec=True) == '3.00000000000000*N.x' def test_issue_14041(): import sympy.physics.mechanics as me A_frame = me.ReferenceFrame('A') thetad, phid = me.dynamicsymbols('theta, phi', 1) L = symbols('L') assert vlatex(L*(phid + thetad)**2*A_frame.x) == \ r"L \left(\dot{\phi} + \dot{\theta}\right)^{2}\mathbf{\hat{a}_x}" assert vlatex((phid + thetad)**2*A_frame.x) == \ r"\left(\dot{\phi} + \dot{\theta}\right)^{2}\mathbf{\hat{a}_x}" assert vlatex((phid*thetad)**a*A_frame.x) == \ r"\left(\dot{\phi} \dot{\theta}\right)^{a}\mathbf{\hat{a}_x}" sympy-sympy-1.9/sympy/physics/vector/tests/test_vector.py000066400000000000000000000171221412543434000241500ustar00rootroot00000000000000from sympy import symbols, pi, sin, cos, Float, ImmutableMatrix as Matrix from sympy.physics.vector import ReferenceFrame, Vector, dynamicsymbols, dot from sympy.abc import x, y, z from sympy.testing.pytest import raises Vector.simp = True A = ReferenceFrame('A') def test_Vector(): assert A.x != A.y assert A.y != A.z assert A.z != A.x assert A.x + 0 == A.x v1 = x*A.x + y*A.y + z*A.z v2 = x**2*A.x + y**2*A.y + z**2*A.z v3 = v1 + v2 v4 = v1 - v2 assert isinstance(v1, Vector) assert dot(v1, A.x) == x assert dot(v1, A.y) == y assert dot(v1, A.z) == z assert isinstance(v2, Vector) assert dot(v2, A.x) == x**2 assert dot(v2, A.y) == y**2 assert dot(v2, A.z) == z**2 assert isinstance(v3, Vector) # We probably shouldn't be using simplify in dot... assert dot(v3, A.x) == x**2 + x assert dot(v3, A.y) == y**2 + y assert dot(v3, A.z) == z**2 + z assert isinstance(v4, Vector) # We probably shouldn't be using simplify in dot... assert dot(v4, A.x) == x - x**2 assert dot(v4, A.y) == y - y**2 assert dot(v4, A.z) == z - z**2 assert v1.to_matrix(A) == Matrix([[x], [y], [z]]) q = symbols('q') B = A.orientnew('B', 'Axis', (q, A.x)) assert v1.to_matrix(B) == Matrix([[x], [ y * cos(q) + z * sin(q)], [-y * sin(q) + z * cos(q)]]) #Test the separate method B = ReferenceFrame('B') v5 = x*A.x + y*A.y + z*B.z assert Vector(0).separate() == {} assert v1.separate() == {A: v1} assert v5.separate() == {A: x*A.x + y*A.y, B: z*B.z} #Test the free_symbols property v6 = x*A.x + y*A.y + z*A.z assert v6.free_symbols(A) == {x,y,z} raises(TypeError, lambda: v3.applyfunc(v1)) def test_Vector_diffs(): q1, q2, q3, q4 = dynamicsymbols('q1 q2 q3 q4') q1d, q2d, q3d, q4d = dynamicsymbols('q1 q2 q3 q4', 1) q1dd, q2dd, q3dd, q4dd = dynamicsymbols('q1 q2 q3 q4', 2) N = ReferenceFrame('N') A = N.orientnew('A', 'Axis', [q3, N.z]) B = A.orientnew('B', 'Axis', [q2, A.x]) v1 = q2 * A.x + q3 * N.y v2 = q3 * B.x + v1 v3 = v1.dt(B) v4 = v2.dt(B) v5 = q1*A.x + q2*A.y + q3*A.z assert v1.dt(N) == q2d * A.x + q2 * q3d * A.y + q3d * N.y assert v1.dt(A) == q2d * A.x + q3 * q3d * N.x + q3d * N.y assert v1.dt(B) == (q2d * A.x + q3 * q3d * N.x + q3d *\ N.y - q3 * cos(q3) * q2d * N.z) assert v2.dt(N) == (q2d * A.x + (q2 + q3) * q3d * A.y + q3d * B.x + q3d * N.y) assert v2.dt(A) == q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y assert v2.dt(B) == (q2d * A.x + q3d * B.x + q3 * q3d * N.x + q3d * N.y - q3 * cos(q3) * q2d * N.z) assert v3.dt(N) == (q2dd * A.x + q2d * q3d * A.y + (q3d**2 + q3 * q3dd) * N.x + q3dd * N.y + (q3 * sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) assert v3.dt(A) == (q2dd * A.x + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd - q3 * q3d**2) * N.y + (q3 * sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) assert v3.dt(B) == (q2dd * A.x - q3 * cos(q3) * q2d**2 * A.y + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd - q3 * q3d**2) * N.y + (2 * q3 * sin(q3) * q2d * q3d - 2 * cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) assert v4.dt(N) == (q2dd * A.x + q3d * (q2d + q3d) * A.y + q3dd * B.x + (q3d**2 + q3 * q3dd) * N.x + q3dd * N.y + (q3 * sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) assert v4.dt(A) == (q2dd * A.x + q3dd * B.x + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd - q3 * q3d**2) * N.y + (q3 * sin(q3) * q2d * q3d - cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) assert v4.dt(B) == (q2dd * A.x - q3 * cos(q3) * q2d**2 * A.y + q3dd * B.x + (2 * q3d**2 + q3 * q3dd) * N.x + (q3dd - q3 * q3d**2) * N.y + (2 * q3 * sin(q3) * q2d * q3d - 2 * cos(q3) * q2d * q3d - q3 * cos(q3) * q2dd) * N.z) assert v5.dt(B) == q1d*A.x + (q3*q2d + q2d)*A.y + (-q2*q2d + q3d)*A.z assert v5.dt(A) == q1d*A.x + q2d*A.y + q3d*A.z assert v5.dt(N) == (-q2*q3d + q1d)*A.x + (q1*q3d + q2d)*A.y + q3d*A.z assert v3.diff(q1d, N) == 0 assert v3.diff(q2d, N) == A.x - q3 * cos(q3) * N.z assert v3.diff(q3d, N) == q3 * N.x + N.y assert v3.diff(q1d, A) == 0 assert v3.diff(q2d, A) == A.x - q3 * cos(q3) * N.z assert v3.diff(q3d, A) == q3 * N.x + N.y assert v3.diff(q1d, B) == 0 assert v3.diff(q2d, B) == A.x - q3 * cos(q3) * N.z assert v3.diff(q3d, B) == q3 * N.x + N.y assert v4.diff(q1d, N) == 0 assert v4.diff(q2d, N) == A.x - q3 * cos(q3) * N.z assert v4.diff(q3d, N) == B.x + q3 * N.x + N.y assert v4.diff(q1d, A) == 0 assert v4.diff(q2d, A) == A.x - q3 * cos(q3) * N.z assert v4.diff(q3d, A) == B.x + q3 * N.x + N.y assert v4.diff(q1d, B) == 0 assert v4.diff(q2d, B) == A.x - q3 * cos(q3) * N.z assert v4.diff(q3d, B) == B.x + q3 * N.x + N.y def test_vector_var_in_dcm(): N = ReferenceFrame('N') A = ReferenceFrame('A') B = ReferenceFrame('B') u1, u2, u3, u4 = dynamicsymbols('u1 u2 u3 u4') v = u1 * u2 * A.x + u3 * N.y + u4**2 * N.z assert v.diff(u1, N, var_in_dcm=False) == u2 * A.x assert v.diff(u1, A, var_in_dcm=False) == u2 * A.x assert v.diff(u3, N, var_in_dcm=False) == N.y assert v.diff(u3, A, var_in_dcm=False) == N.y assert v.diff(u3, B, var_in_dcm=False) == N.y assert v.diff(u4, N, var_in_dcm=False) == 2 * u4 * N.z raises(ValueError, lambda: v.diff(u1, N)) def test_vector_simplify(): x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A') N = ReferenceFrame('N') test1 = (1 / x + 1 / y) * N.x assert (test1 & N.x) != (x + y) / (x * y) test1 = test1.simplify() assert (test1 & N.x) == (x + y) / (x * y) test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * N.x test2 = test2.simplify() assert (test2 & N.x) == (A**2 * s**4 / (4 * pi * k * m**3)) test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * N.x test3 = test3.simplify() assert (test3 & N.x) == 0 test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * N.x test4 = test4.simplify() assert (test4 & N.x) == -2 * y def test_vector_evalf(): a, b = symbols('a b') v = pi * A.x assert v.evalf(2) == Float('3.1416', 2) * A.x v = pi * A.x + 5 * a * A.y - b * A.z assert v.evalf(3) == Float('3.1416', 3) * A.x + Float('5', 3) * a * A.y - b * A.z assert v.evalf(5, subs={a: 1.234, b:5.8973}) == Float('3.1415926536', 5) * A.x + Float('6.17', 5) * A.y - Float('5.8973', 5) * A.z def test_vector_angle(): A = ReferenceFrame('A') v1 = A.x + A.y v2 = A.z assert v1.angle_between(v2) == pi/2 B = ReferenceFrame('B') B.orient_axis(A, A.x, pi) v3 = A.x v4 = B.x assert v3.angle_between(v4) == 0 def test_vector_xreplace(): x, y, z = symbols('x y z') v = x**2 * A.x + x*y * A.y + x*y*z * A.z assert v.xreplace({x : cos(x)}) == cos(x)**2 * A.x + y*cos(x) * A.y + y*z*cos(x) * A.z assert v.xreplace({x*y : pi}) == x**2 * A.x + pi * A.y + x*y*z * A.z assert v.xreplace({x*y*z : 1}) == x**2*A.x + x*y*A.y + A.z assert v.xreplace({x:1, z:0}) == A.x + y * A.y raises(TypeError, lambda: v.xreplace()) raises(TypeError, lambda: v.xreplace([x, y])) sympy-sympy-1.9/sympy/physics/vector/vector.py000066400000000000000000000635041412543434000217540ustar00rootroot00000000000000from sympy.core.backend import (S, sympify, expand, sqrt, Add, zeros, acos, ImmutableMatrix as Matrix, _simplify_matrix) from sympy import trigsimp from sympy.printing.defaults import Printable from sympy.utilities.misc import filldedent from sympy.core.evalf import EvalfMixin, prec_to_dps __all__ = ['Vector'] class Vector(Printable, EvalfMixin): """The class used to define vectors. It along with ReferenceFrame are the building blocks of describing a classical mechanics system in PyDy and sympy.physics.vector. Attributes ========== simp : Boolean Let certain methods use trigsimp on their outputs """ simp = False is_number = False def __init__(self, inlist): """This is the constructor for the Vector class. You shouldn't be calling this, it should only be used by other functions. You should be treating Vectors like you would with if you were doing the math by hand, and getting the first 3 from the standard basis vectors from a ReferenceFrame. The only exception is to create a zero vector: zv = Vector(0) """ self.args = [] if inlist == 0: inlist = [] if isinstance(inlist, dict): d = inlist else: d = {} for inp in inlist: if inp[1] in d: d[inp[1]] += inp[0] else: d[inp[1]] = inp[0] for k, v in d.items(): if v != Matrix([0, 0, 0]): self.args.append((v, k)) @property def func(self): """Returns the class Vector. """ return Vector def __hash__(self): return hash(tuple(self.args)) def __add__(self, other): """The add operator for Vector. """ if other == 0: return self other = _check_vector(other) return Vector(self.args + other.args) def __and__(self, other): """Dot product of two vectors. Returns a scalar, the dot product of the two Vectors Parameters ========== other : Vector The Vector which we are dotting with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, dot >>> from sympy import symbols >>> q1 = symbols('q1') >>> N = ReferenceFrame('N') >>> dot(N.x, N.x) 1 >>> dot(N.x, N.y) 0 >>> A = N.orientnew('A', 'Axis', [q1, N.x]) >>> dot(N.y, A.y) cos(q1) """ from sympy.physics.vector.dyadic import Dyadic if isinstance(other, Dyadic): return NotImplemented other = _check_vector(other) out = S.Zero for i, v1 in enumerate(self.args): for j, v2 in enumerate(other.args): out += ((v2[0].T) * (v2[1].dcm(v1[1])) * (v1[0]))[0] if Vector.simp: return trigsimp(sympify(out), recursive=True) else: return sympify(out) def __truediv__(self, other): """This uses mul and inputs self and 1 divided by other. """ return self.__mul__(sympify(1) / other) def __eq__(self, other): """Tests for equality. It is very import to note that this is only as good as the SymPy equality test; False does not always mean they are not equivalent Vectors. If other is 0, and self is empty, returns True. If other is 0 and self is not empty, returns False. If none of the above, only accepts other as a Vector. """ if other == 0: other = Vector(0) try: other = _check_vector(other) except TypeError: return False if (self.args == []) and (other.args == []): return True elif (self.args == []) or (other.args == []): return False frame = self.args[0][1] for v in frame: if expand((self - other) & v) != 0: return False return True def __mul__(self, other): """Multiplies the Vector by a sympifyable expression. Parameters ========== other : Sympifyable The scalar to multiply this Vector with Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy import Symbol >>> N = ReferenceFrame('N') >>> b = Symbol('b') >>> V = 10 * b * N.x >>> print(V) 10*b*N.x """ newlist = [v for v in self.args] for i, v in enumerate(newlist): newlist[i] = (sympify(other) * newlist[i][0], newlist[i][1]) return Vector(newlist) def __ne__(self, other): return not self == other def __neg__(self): return self * -1 def __or__(self, other): """Outer product between two Vectors. A rank increasing operation, which returns a Dyadic from two Vectors Parameters ========== other : Vector The Vector to take the outer product with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer >>> N = ReferenceFrame('N') >>> outer(N.x, N.x) (N.x|N.x) """ from sympy.physics.vector.dyadic import Dyadic other = _check_vector(other) ol = Dyadic(0) for i, v in enumerate(self.args): for i2, v2 in enumerate(other.args): # it looks this way because if we are in the same frame and # use the enumerate function on the same frame in a nested # fashion, then bad things happen ol += Dyadic([(v[0][0] * v2[0][0], v[1].x, v2[1].x)]) ol += Dyadic([(v[0][0] * v2[0][1], v[1].x, v2[1].y)]) ol += Dyadic([(v[0][0] * v2[0][2], v[1].x, v2[1].z)]) ol += Dyadic([(v[0][1] * v2[0][0], v[1].y, v2[1].x)]) ol += Dyadic([(v[0][1] * v2[0][1], v[1].y, v2[1].y)]) ol += Dyadic([(v[0][1] * v2[0][2], v[1].y, v2[1].z)]) ol += Dyadic([(v[0][2] * v2[0][0], v[1].z, v2[1].x)]) ol += Dyadic([(v[0][2] * v2[0][1], v[1].z, v2[1].y)]) ol += Dyadic([(v[0][2] * v2[0][2], v[1].z, v2[1].z)]) return ol def _latex(self, printer): """Latex Printing method. """ ar = self.args # just to shorten things if len(ar) == 0: return str(0) ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): for j in 0, 1, 2: # if the coef of the basis vector is 1, we skip the 1 if ar[i][0][j] == 1: ol.append(' + ' + ar[i][1].latex_vecs[j]) # if the coef of the basis vector is -1, we skip the 1 elif ar[i][0][j] == -1: ol.append(' - ' + ar[i][1].latex_vecs[j]) elif ar[i][0][j] != 0: # If the coefficient of the basis vector is not 1 or -1; # also, we might wrap it in parentheses, for readability. arg_str = printer._print(ar[i][0][j]) if isinstance(ar[i][0][j], Add): arg_str = "(%s)" % arg_str if arg_str[0] == '-': arg_str = arg_str[1:] str_start = ' - ' else: str_start = ' + ' ol.append(str_start + arg_str + ar[i][1].latex_vecs[j]) outstr = ''.join(ol) if outstr.startswith(' + '): outstr = outstr[3:] elif outstr.startswith(' '): outstr = outstr[1:] return outstr def _pretty(self, printer): """Pretty Printing method. """ from sympy.printing.pretty.stringpict import prettyForm e = self class Fake: def render(self, *args, **kwargs): ar = e.args # just to shorten things if len(ar) == 0: return str(0) pforms = [] # output list, to be concatenated to a string for i, v in enumerate(ar): for j in 0, 1, 2: # if the coef of the basis vector is 1, we skip the 1 if ar[i][0][j] == 1: pform = printer._print(ar[i][1].pretty_vecs[j]) # if the coef of the basis vector is -1, we skip the 1 elif ar[i][0][j] == -1: pform = printer._print(ar[i][1].pretty_vecs[j]) pform = prettyForm(*pform.left(" - ")) bin = prettyForm.NEG pform = prettyForm(binding=bin, *pform) elif ar[i][0][j] != 0: # If the basis vector coeff is not 1 or -1, # we might wrap it in parentheses, for readability. pform = printer._print(ar[i][0][j]) if isinstance(ar[i][0][j], Add): tmp = pform.parens() pform = prettyForm(tmp[0], tmp[1]) pform = prettyForm(*pform.right(" ", ar[i][1].pretty_vecs[j])) else: continue pforms.append(pform) pform = prettyForm.__add__(*pforms) kwargs["wrap_line"] = kwargs.get("wrap_line") kwargs["num_columns"] = kwargs.get("num_columns") out_str = pform.render(*args, **kwargs) mlines = [line.rstrip() for line in out_str.split("\n")] return "\n".join(mlines) return Fake() def __ror__(self, other): """Outer product between two Vectors. A rank increasing operation, which returns a Dyadic from two Vectors Parameters ========== other : Vector The Vector to take the outer product with Examples ======== >>> from sympy.physics.vector import ReferenceFrame, outer >>> N = ReferenceFrame('N') >>> outer(N.x, N.x) (N.x|N.x) """ from sympy.physics.vector.dyadic import Dyadic other = _check_vector(other) ol = Dyadic(0) for i, v in enumerate(other.args): for i2, v2 in enumerate(self.args): # it looks this way because if we are in the same frame and # use the enumerate function on the same frame in a nested # fashion, then bad things happen ol += Dyadic([(v[0][0] * v2[0][0], v[1].x, v2[1].x)]) ol += Dyadic([(v[0][0] * v2[0][1], v[1].x, v2[1].y)]) ol += Dyadic([(v[0][0] * v2[0][2], v[1].x, v2[1].z)]) ol += Dyadic([(v[0][1] * v2[0][0], v[1].y, v2[1].x)]) ol += Dyadic([(v[0][1] * v2[0][1], v[1].y, v2[1].y)]) ol += Dyadic([(v[0][1] * v2[0][2], v[1].y, v2[1].z)]) ol += Dyadic([(v[0][2] * v2[0][0], v[1].z, v2[1].x)]) ol += Dyadic([(v[0][2] * v2[0][1], v[1].z, v2[1].y)]) ol += Dyadic([(v[0][2] * v2[0][2], v[1].z, v2[1].z)]) return ol def __rsub__(self, other): return (-1 * self) + other def _sympystr(self, printer, order=True): """Printing method. """ if not order or len(self.args) == 1: ar = list(self.args) elif len(self.args) == 0: return printer._print(0) else: d = {v[1]: v[0] for v in self.args} keys = sorted(d.keys(), key=lambda x: x.index) ar = [] for key in keys: ar.append((d[key], key)) ol = [] # output list, to be concatenated to a string for i, v in enumerate(ar): for j in 0, 1, 2: # if the coef of the basis vector is 1, we skip the 1 if ar[i][0][j] == 1: ol.append(' + ' + ar[i][1].str_vecs[j]) # if the coef of the basis vector is -1, we skip the 1 elif ar[i][0][j] == -1: ol.append(' - ' + ar[i][1].str_vecs[j]) elif ar[i][0][j] != 0: # If the coefficient of the basis vector is not 1 or -1; # also, we might wrap it in parentheses, for readability. arg_str = printer._print(ar[i][0][j]) if isinstance(ar[i][0][j], Add): arg_str = "(%s)" % arg_str if arg_str[0] == '-': arg_str = arg_str[1:] str_start = ' - ' else: str_start = ' + ' ol.append(str_start + arg_str + '*' + ar[i][1].str_vecs[j]) outstr = ''.join(ol) if outstr.startswith(' + '): outstr = outstr[3:] elif outstr.startswith(' '): outstr = outstr[1:] return outstr def __sub__(self, other): """The subtraction operator. """ return self.__add__(other * -1) def __xor__(self, other): """The cross product operator for two Vectors. Returns a Vector, expressed in the same ReferenceFrames as self. Parameters ========== other : Vector The Vector which we are crossing with Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy import symbols >>> q1 = symbols('q1') >>> N = ReferenceFrame('N') >>> N.x ^ N.y N.z >>> A = N.orientnew('A', 'Axis', [q1, N.x]) >>> A.x ^ N.y N.z >>> N.y ^ A.x - sin(q1)*A.y - cos(q1)*A.z """ from sympy.physics.vector.dyadic import Dyadic if isinstance(other, Dyadic): return NotImplemented other = _check_vector(other) if other.args == []: return Vector(0) def _det(mat): """This is needed as a little method for to find the determinant of a list in python; needs to work for a 3x3 list. SymPy's Matrix won't take in Vector, so need a custom function. You shouldn't be calling this. """ return (mat[0][0] * (mat[1][1] * mat[2][2] - mat[1][2] * mat[2][1]) + mat[0][1] * (mat[1][2] * mat[2][0] - mat[1][0] * mat[2][2]) + mat[0][2] * (mat[1][0] * mat[2][1] - mat[1][1] * mat[2][0])) outlist = [] ar = other.args # For brevity for i, v in enumerate(ar): tempx = v[1].x tempy = v[1].y tempz = v[1].z tempm = ([[tempx, tempy, tempz], [self & tempx, self & tempy, self & tempz], [Vector([ar[i]]) & tempx, Vector([ar[i]]) & tempy, Vector([ar[i]]) & tempz]]) outlist += _det(tempm).args return Vector(outlist) __radd__ = __add__ __rand__ = __and__ __rmul__ = __mul__ def separate(self): """ The constituents of this vector in different reference frames, as per its definition. Returns a dict mapping each ReferenceFrame to the corresponding constituent Vector. Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> R1 = ReferenceFrame('R1') >>> R2 = ReferenceFrame('R2') >>> v = R1.x + R2.x >>> v.separate() == {R1: R1.x, R2: R2.x} True """ components = {} for x in self.args: components[x[1]] = Vector([x]) return components def dot(self, other): return self & other dot.__doc__ = __and__.__doc__ def cross(self, other): return self ^ other cross.__doc__ = __xor__.__doc__ def outer(self, other): return self | other outer.__doc__ = __or__.__doc__ def diff(self, var, frame, var_in_dcm=True): """Returns the partial derivative of the vector with respect to a variable in the provided reference frame. Parameters ========== var : Symbol What the partial derivative is taken with respect to. frame : ReferenceFrame The reference frame that the partial derivative is taken in. var_in_dcm : boolean If true, the differentiation algorithm assumes that the variable may be present in any of the direction cosine matrices that relate the frame to the frames of any component of the vector. But if it is known that the variable is not present in the direction cosine matrices, false can be set to skip full reexpression in the desired frame. Examples ======== >>> from sympy import Symbol >>> from sympy.physics.vector import dynamicsymbols, ReferenceFrame >>> from sympy.physics.vector import Vector >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> Vector.simp = True >>> t = Symbol('t') >>> q1 = dynamicsymbols('q1') >>> N = ReferenceFrame('N') >>> A = N.orientnew('A', 'Axis', [q1, N.y]) >>> A.x.diff(t, N) - q1'*A.z >>> B = ReferenceFrame('B') >>> u1, u2 = dynamicsymbols('u1, u2') >>> v = u1 * A.x + u2 * B.y >>> v.diff(u2, N, var_in_dcm=False) B.y """ from sympy.physics.vector.frame import _check_frame var = sympify(var) _check_frame(frame) inlist = [] for vector_component in self.args: measure_number = vector_component[0] component_frame = vector_component[1] if component_frame == frame: inlist += [(measure_number.diff(var), frame)] else: # If the direction cosine matrix relating the component frame # with the derivative frame does not contain the variable. if not var_in_dcm or (frame.dcm(component_frame).diff(var) == zeros(3, 3)): inlist += [(measure_number.diff(var), component_frame)] else: # else express in the frame reexp_vec_comp = Vector([vector_component]).express(frame) deriv = reexp_vec_comp.args[0][0].diff(var) inlist += Vector([(deriv, frame)]).express(component_frame).args return Vector(inlist) def express(self, otherframe, variables=False): """ Returns a Vector equivalent to this one, expressed in otherframe. Uses the global express method. Parameters ========== otherframe : ReferenceFrame The frame for this Vector to be described in variables : boolean If True, the coordinate symbols(if present) in this Vector are re-expressed in terms otherframe Examples ======== >>> from sympy.physics.vector import ReferenceFrame, dynamicsymbols >>> from sympy.physics.vector import init_vprinting >>> init_vprinting(pretty_print=False) >>> q1 = dynamicsymbols('q1') >>> N = ReferenceFrame('N') >>> A = N.orientnew('A', 'Axis', [q1, N.y]) >>> A.x.express(N) cos(q1)*N.x - sin(q1)*N.z """ from sympy.physics.vector import express return express(self, otherframe, variables=variables) def to_matrix(self, reference_frame): """Returns the matrix form of the vector with respect to the given frame. Parameters ---------- reference_frame : ReferenceFrame The reference frame that the rows of the matrix correspond to. Returns ------- matrix : ImmutableMatrix, shape(3,1) The matrix that gives the 1D vector. Examples ======== >>> from sympy import symbols >>> from sympy.physics.vector import ReferenceFrame >>> a, b, c = symbols('a, b, c') >>> N = ReferenceFrame('N') >>> vector = a * N.x + b * N.y + c * N.z >>> vector.to_matrix(N) Matrix([ [a], [b], [c]]) >>> beta = symbols('beta') >>> A = N.orientnew('A', 'Axis', (beta, N.x)) >>> vector.to_matrix(A) Matrix([ [ a], [ b*cos(beta) + c*sin(beta)], [-b*sin(beta) + c*cos(beta)]]) """ return Matrix([self.dot(unit_vec) for unit_vec in reference_frame]).reshape(3, 1) def doit(self, **hints): """Calls .doit() on each term in the Vector""" d = {} for v in self.args: d[v[1]] = v[0].applyfunc(lambda x: x.doit(**hints)) return Vector(d) def dt(self, otherframe): """ Returns a Vector which is the time derivative of the self Vector, taken in frame otherframe. Calls the global time_derivative method Parameters ========== otherframe : ReferenceFrame The frame to calculate the time derivative in """ from sympy.physics.vector import time_derivative return time_derivative(self, otherframe) def simplify(self): """Returns a simplified Vector.""" d = {} for v in self.args: d[v[1]] = _simplify_matrix(v[0]) return Vector(d) def subs(self, *args, **kwargs): """Substitution on the Vector. Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> from sympy import Symbol >>> N = ReferenceFrame('N') >>> s = Symbol('s') >>> a = N.x * s >>> a.subs({s: 2}) 2*N.x """ d = {} for v in self.args: d[v[1]] = v[0].subs(*args, **kwargs) return Vector(d) def magnitude(self): """Returns the magnitude (Euclidean norm) of self. Warnings ======== Python ignores the leading negative sign so that might give wrong results. ``-A.x.magnitude()`` would be treated as ``-(A.x.magnitude())``, instead of ``(-A.x).magnitude()``. """ return sqrt(self & self) def normalize(self): """Returns a Vector of magnitude 1, codirectional with self.""" return Vector(self.args + []) / self.magnitude() def applyfunc(self, f): """Apply a function to each component of a vector.""" if not callable(f): raise TypeError("`f` must be callable.") d = {} for v in self.args: d[v[1]] = v[0].applyfunc(f) return Vector(d) def angle_between(self, vec): """ Returns the smallest angle between Vector 'vec' and self. Parameter ========= vec : Vector The Vector between which angle is needed. Examples ======== >>> from sympy.physics.vector import ReferenceFrame >>> A = ReferenceFrame("A") >>> v1 = A.x >>> v2 = A.y >>> v1.angle_between(v2) pi/2 >>> v3 = A.x + A.y + A.z >>> v1.angle_between(v3) acos(sqrt(3)/3) Warnings ======== Python ignores the leading negative sign so that might give wrong results. ``-A.x.angle_between()`` would be treated as ``-(A.x.angle_between())``, instead of ``(-A.x).angle_between()``. """ vec1 = self.normalize() vec2 = vec.normalize() angle = acos(vec1.dot(vec2)) return angle def free_symbols(self, reference_frame): """ Returns the free symbols in the measure numbers of the vector expressed in the given reference frame. Parameter ========= reference_frame : ReferenceFrame The frame with respect to which the free symbols of the given vector is to be determined. """ return self.to_matrix(reference_frame).free_symbols def _eval_evalf(self, prec): if not self.args: return self new_args = [] for mat, frame in self.args: new_args.append([mat.evalf(n=prec_to_dps(prec)), frame]) return Vector(new_args) def xreplace(self, rule): """ Replace occurrences of objects within the measure numbers of the vector. Parameters ========== rule : dict-like Expresses a replacement rule. Returns ======= Vector Result of the replacement. Examples ======== >>> from sympy import symbols, pi >>> from sympy.physics.vector import ReferenceFrame >>> A = ReferenceFrame('A') >>> x, y, z = symbols('x y z') >>> ((1 + x*y) * A.x).xreplace({x: pi}) (pi*y + 1)*A.x >>> ((1 + x*y) * A.x).xreplace({x: pi, y: 2}) (1 + 2*pi)*A.x Replacements occur only if an entire node in the expression tree is matched: >>> ((x*y + z) * A.x).xreplace({x*y: pi}) (z + pi)*A.x >>> ((x*y*z) * A.x).xreplace({x*y: pi}) x*y*z*A.x """ new_args = [] for mat, frame in self.args: mat = mat.xreplace(rule) new_args.append([mat, frame]) return Vector(new_args) class VectorTypeError(TypeError): def __init__(self, other, want): msg = filldedent("Expected an instance of %s, but received object " "'%s' of %s." % (type(want), other, type(other))) super().__init__(msg) def _check_vector(other): if not isinstance(other, Vector): raise TypeError('A Vector must be supplied') return other sympy-sympy-1.9/sympy/physics/wigner.py000066400000000000000000000752261412543434000204470ustar00rootroot00000000000000# -*- coding: utf-8 -*- r""" Wigner, Clebsch-Gordan, Racah, and Gaunt coefficients Collection of functions for calculating Wigner 3j, 6j, 9j, Clebsch-Gordan, Racah as well as Gaunt coefficients exactly, all evaluating to a rational number times the square root of a rational number [Rasch03]_. Please see the description of the individual functions for further details and examples. References ========== .. [Regge58] 'Symmetry Properties of Clebsch-Gordan Coefficients', T. Regge, Nuovo Cimento, Volume 10, pp. 544 (1958) .. [Regge59] 'Symmetry Properties of Racah Coefficients', T. Regge, Nuovo Cimento, Volume 11, pp. 116 (1959) .. [Edmonds74] A. R. Edmonds. Angular momentum in quantum mechanics. Investigations in physics, 4.; Investigations in physics, no. 4. Princeton, N.J., Princeton University Press, 1957. .. [Rasch03] J. Rasch and A. C. H. Yu, 'Efficient Storage Scheme for Pre-calculated Wigner 3j, 6j and Gaunt Coefficients', SIAM J. Sci. Comput. Volume 25, Issue 4, pp. 1416-1428 (2003) .. [Liberatodebrito82] 'FORTRAN program for the integral of three spherical harmonics', A. Liberato de Brito, Comput. Phys. Commun., Volume 25, pp. 81-85 (1982) Credits and Copyright ===================== This code was taken from Sage with the permission of all authors: https://groups.google.com/forum/#!topic/sage-devel/M4NZdu-7O38 Authors ======= - Jens Rasch (2009-03-24): initial version for Sage - Jens Rasch (2009-05-31): updated to sage-4.0 - Oscar Gerardo Lazo Arjona (2017-06-18): added Wigner D matrices Copyright (C) 2008 Jens Rasch """ from sympy import (Integer, pi, sqrt, sympify, Dummy, S, Sum, Ynm, zeros, Function, sin, cos, exp, I, factorial, binomial, Add, ImmutableMatrix) # This list of precomputed factorials is needed to massively # accelerate future calculations of the various coefficients _Factlist = [1] def _calc_factlist(nn): r""" Function calculates a list of precomputed factorials in order to massively accelerate future calculations of the various coefficients. Parameters ========== nn : integer Highest factorial to be computed. Returns ======= list of integers : The list of precomputed factorials. Examples ======== Calculate list of factorials:: sage: from sage.functions.wigner import _calc_factlist sage: _calc_factlist(10) [1, 1, 2, 6, 24, 120, 720, 5040, 40320, 362880, 3628800] """ if nn >= len(_Factlist): for ii in range(len(_Factlist), int(nn + 1)): _Factlist.append(_Factlist[ii - 1] * ii) return _Factlist[:int(nn) + 1] def wigner_3j(j_1, j_2, j_3, m_1, m_2, m_3): r""" Calculate the Wigner 3j symbol `\operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3)`. Parameters ========== j_1, j_2, j_3, m_1, m_2, m_3 : Integer or half integer. Returns ======= Rational number times the square root of a rational number. Examples ======== >>> from sympy.physics.wigner import wigner_3j >>> wigner_3j(2, 6, 4, 0, 0, 0) sqrt(715)/143 >>> wigner_3j(2, 6, 4, 0, 0, 1) 0 It is an error to have arguments that are not integer or half integer values:: sage: wigner_3j(2.1, 6, 4, 0, 0, 0) Traceback (most recent call last): ... ValueError: j values must be integer or half integer sage: wigner_3j(2, 6, 4, 1, 0, -1.1) Traceback (most recent call last): ... ValueError: m values must be integer or half integer Notes ===== The Wigner 3j symbol obeys the following symmetry rules: - invariant under any permutation of the columns (with the exception of a sign change where `J:=j_1+j_2+j_3`): .. math:: \begin{aligned} \operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3) &=\operatorname{Wigner3j}(j_3,j_1,j_2,m_3,m_1,m_2) \\ &=\operatorname{Wigner3j}(j_2,j_3,j_1,m_2,m_3,m_1) \\ &=(-1)^J \operatorname{Wigner3j}(j_3,j_2,j_1,m_3,m_2,m_1) \\ &=(-1)^J \operatorname{Wigner3j}(j_1,j_3,j_2,m_1,m_3,m_2) \\ &=(-1)^J \operatorname{Wigner3j}(j_2,j_1,j_3,m_2,m_1,m_3) \end{aligned} - invariant under space inflection, i.e. .. math:: \operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,m_3) =(-1)^J \operatorname{Wigner3j}(j_1,j_2,j_3,-m_1,-m_2,-m_3) - symmetric with respect to the 72 additional symmetries based on the work by [Regge58]_ - zero for `j_1`, `j_2`, `j_3` not fulfilling triangle relation - zero for `m_1 + m_2 + m_3 \neq 0` - zero for violating any one of the conditions `j_1 \ge |m_1|`, `j_2 \ge |m_2|`, `j_3 \ge |m_3|` Algorithm ========= This function uses the algorithm of [Edmonds74]_ to calculate the value of the 3j symbol exactly. Note that the formula contains alternating sums over large factorials and is therefore unsuitable for finite precision arithmetic and only useful for a computer algebra system [Rasch03]_. Authors ======= - 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: 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: raise ValueError("m values must be integer or half integer") if m_1 + m_2 + m_3 != 0: return 0 prefid = Integer((-1) ** int(j_1 - j_2 - m_3)) m_3 = -m_3 a1 = j_1 + j_2 - j_3 if a1 < 0: return 0 a2 = j_1 - j_2 + j_3 if a2 < 0: return 0 a3 = -j_1 + j_2 + j_3 if a3 < 0: return 0 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)) _calc_factlist(int(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)] ressqrt = sqrt(argsqrt) if ressqrt.is_complex or ressqrt.is_infinite: ressqrt = ressqrt.as_real_imag()[0] imin = max(-j_3 + j_1 + m_2, -j_3 + j_2 - m_1, 0) imax = min(j_2 + m_2, j_1 - m_1, j_1 + j_2 - j_3) sumres = 0 for ii in range(int(imin), int(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)] sumres = sumres + Integer((-1) ** ii) / den res = ressqrt * sumres * prefid return res def clebsch_gordan(j_1, j_2, j_3, m_1, m_2, m_3): r""" Calculates the Clebsch-Gordan coefficient. `\left\langle j_1 m_1 \; j_2 m_2 | j_3 m_3 \right\rangle`. The reference for this function is [Edmonds74]_. Parameters ========== j_1, j_2, j_3, m_1, m_2, m_3 : Integer or half integer. Returns ======= Rational number times the square root of a rational number. Examples ======== >>> from sympy import S >>> from sympy.physics.wigner import clebsch_gordan >>> clebsch_gordan(S(3)/2, S(1)/2, 2, S(3)/2, S(1)/2, 2) 1 >>> clebsch_gordan(S(3)/2, S(1)/2, 1, S(3)/2, -S(1)/2, 1) sqrt(3)/2 >>> clebsch_gordan(S(3)/2, S(1)/2, 1, -S(1)/2, S(1)/2, 0) -sqrt(2)/2 Notes ===== The Clebsch-Gordan coefficient will be evaluated via its relation to Wigner 3j symbols: .. math:: \left\langle j_1 m_1 \; j_2 m_2 | j_3 m_3 \right\rangle =(-1)^{j_1-j_2+m_3} \sqrt{2j_3+1} \operatorname{Wigner3j}(j_1,j_2,j_3,m_1,m_2,-m_3) See also the documentation on Wigner 3j symbols which exhibit much higher symmetry relations than the Clebsch-Gordan coefficient. Authors ======= - Jens Rasch (2009-03-24): initial version """ res = (-1) ** sympify(j_1 - j_2 + m_3) * sqrt(2 * j_3 + 1) * \ wigner_3j(j_1, j_2, j_3, m_1, m_2, -m_3) return res def _big_delta_coeff(aa, bb, cc, prec=None): r""" Calculates the Delta coefficient of the 3 angular momenta for Racah symbols. Also checks that the differences are of integer value. Parameters ========== aa : First angular momentum, integer or half integer. bb : Second angular momentum, integer or half integer. cc : Third angular momentum, integer or half integer. prec : Precision of the ``sqrt()`` calculation. Returns ======= double : Value of the Delta coefficient. Examples ======== sage: from sage.functions.wigner import _big_delta_coeff sage: _big_delta_coeff(1,1,1) 1/2*sqrt(1/6) """ if int(aa + bb - cc) != (aa + bb - cc): raise ValueError("j values must be integer or half integer and fulfill the triangle relation") if int(aa + cc - bb) != (aa + cc - bb): raise ValueError("j values must be integer or half integer and fulfill the triangle relation") if int(bb + cc - aa) != (bb + cc - aa): raise ValueError("j values must be integer or half integer and fulfill the triangle relation") if (aa + bb - cc) < 0: return 0 if (aa + cc - bb) < 0: return 0 if (bb + cc - aa) < 0: return 0 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)]) ressqrt = sqrt(argsqrt) if prec: ressqrt = ressqrt.evalf(prec).as_real_imag()[0] return ressqrt def racah(aa, bb, cc, dd, ee, ff, prec=None): r""" Calculate the Racah symbol `W(a,b,c,d;e,f)`. Parameters ========== a, ..., f : Integer or half integer. prec : Precision, default: ``None``. Providing a precision can drastically speed up the calculation. Returns ======= Rational number times the square root of a rational number (if ``prec=None``), or real number if a precision is given. Examples ======== >>> from sympy.physics.wigner import racah >>> racah(3,3,3,3,3,3) -1/14 Notes ===== The Racah symbol is related to the Wigner 6j symbol: .. math:: \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) =(-1)^{j_1+j_2+j_4+j_5} W(j_1,j_2,j_5,j_4,j_3,j_6) Please see the 6j symbol for its much richer symmetries and for additional properties. Algorithm ========= This function uses the algorithm of [Edmonds74]_ to calculate the value of the 6j symbol exactly. Note that the formula contains alternating sums over large factorials and is therefore unsuitable for finite precision arithmetic and only useful for a computer algebra system [Rasch03]_. Authors ======= - 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) if prefac == 0: return 0 imin = max(aa + bb + ee, cc + dd + ee, aa + cc + ff, bb + dd + ff) imax = 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) _calc_factlist(maxfact) sumres = 0 for kk in range(int(imin), int(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)] sumres = sumres + Integer((-1) ** kk * _Factlist[kk + 1]) / den res = prefac * sumres * (-1) ** int(aa + bb + cc + dd) return res def wigner_6j(j_1, j_2, j_3, j_4, j_5, j_6, prec=None): r""" Calculate the Wigner 6j symbol `\operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6)`. Parameters ========== j_1, ..., j_6 : Integer or half integer. prec : Precision, default: ``None``. Providing a precision can drastically speed up the calculation. Returns ======= Rational number times the square root of a rational number (if ``prec=None``), or real number if a precision is given. Examples ======== >>> from sympy.physics.wigner import wigner_6j >>> wigner_6j(3,3,3,3,3,3) -1/14 >>> wigner_6j(5,5,5,5,5,5) 1/52 It is an error to have arguments that are not integer or half integer values or do not fulfill the triangle relation:: sage: wigner_6j(2.5,2.5,2.5,2.5,2.5,2.5) Traceback (most recent call last): ... ValueError: j values must be integer or half integer and fulfill the triangle relation sage: wigner_6j(0.5,0.5,1.1,0.5,0.5,1.1) Traceback (most recent call last): ... ValueError: j values must be integer or half integer and fulfill the triangle relation Notes ===== The Wigner 6j symbol is related to the Racah symbol but exhibits more symmetries as detailed below. .. math:: \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) =(-1)^{j_1+j_2+j_4+j_5} W(j_1,j_2,j_5,j_4,j_3,j_6) The Wigner 6j symbol obeys the following symmetry rules: - Wigner 6j symbols are left invariant under any permutation of the columns: .. math:: \begin{aligned} \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) &=\operatorname{Wigner6j}(j_3,j_1,j_2,j_6,j_4,j_5) \\ &=\operatorname{Wigner6j}(j_2,j_3,j_1,j_5,j_6,j_4) \\ &=\operatorname{Wigner6j}(j_3,j_2,j_1,j_6,j_5,j_4) \\ &=\operatorname{Wigner6j}(j_1,j_3,j_2,j_4,j_6,j_5) \\ &=\operatorname{Wigner6j}(j_2,j_1,j_3,j_5,j_4,j_6) \end{aligned} - They are invariant under the exchange of the upper and lower arguments in each of any two columns, i.e. .. math:: \operatorname{Wigner6j}(j_1,j_2,j_3,j_4,j_5,j_6) =\operatorname{Wigner6j}(j_1,j_5,j_6,j_4,j_2,j_3) =\operatorname{Wigner6j}(j_4,j_2,j_6,j_1,j_5,j_3) =\operatorname{Wigner6j}(j_4,j_5,j_3,j_1,j_2,j_6) - additional 6 symmetries [Regge59]_ giving rise to 144 symmetries in total - only non-zero if any triple of `j`'s fulfill a triangle relation Algorithm ========= This function uses the algorithm of [Edmonds74]_ to calculate the value of the 6j symbol exactly. Note that the formula contains alternating sums over large factorials and is therefore unsuitable for finite precision arithmetic and only useful for a computer algebra system [Rasch03]_. """ 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 def wigner_9j(j_1, j_2, j_3, j_4, j_5, j_6, j_7, j_8, j_9, prec=None): r""" Calculate the Wigner 9j symbol `\operatorname{Wigner9j}(j_1,j_2,j_3,j_4,j_5,j_6,j_7,j_8,j_9)`. Parameters ========== j_1, ..., j_9 : Integer or half integer. prec : precision, default ``None``. Providing a precision can drastically speed up the calculation. Returns ======= Rational number times the square root of a rational number (if ``prec=None``), or real number if a precision is given. Examples ======== >>> from sympy.physics.wigner import wigner_9j >>> wigner_9j(1,1,1, 1,1,1, 1,1,0 ,prec=64) # ==1/18 0.05555555... >>> wigner_9j(1/2,1/2,0, 1/2,3/2,1, 0,1,1 ,prec=64) # ==1/6 0.1666666... It is an error to have arguments that are not integer or half integer values or do not fulfill the triangle relation:: sage: wigner_9j(0.5,0.5,0.5, 0.5,0.5,0.5, 0.5,0.5,0.5,prec=64) Traceback (most recent call last): ... ValueError: j values must be integer or half integer and fulfill the triangle relation sage: wigner_9j(1,1,1, 0.5,1,1.5, 0.5,1,2.5,prec=64) Traceback (most recent call last): ... ValueError: j values must be integer or half integer and fulfill the triangle relation Algorithm ========= This function uses the algorithm of [Edmonds74]_ to calculate the value of the 3j symbol exactly. Note that the formula contains alternating sums over large factorials and is therefore unsuitable for finite precision arithmetic and only useful for a computer algebra system [Rasch03]_. """ imax = int(min(j_1 + j_9, j_2 + j_6, j_4 + j_8) * 2) imin = imax % 2 sumres = 0 for kk in range(imin, int(imax) + 1, 2): sumres = sumres + (kk + 1) * \ racah(j_1, j_2, j_9, j_6, j_3, kk / 2, prec) * \ racah(j_4, j_6, j_8, j_2, j_5, kk / 2, prec) * \ racah(j_1, j_4, j_9, j_8, j_7, kk / 2, prec) return sumres def gaunt(l_1, l_2, l_3, m_1, m_2, m_3, prec=None): r""" Calculate the Gaunt coefficient. Explanation =========== The Gaunt coefficient is defined as the integral over three spherical harmonics: .. math:: \begin{aligned} \operatorname{Gaunt}(l_1,l_2,l_3,m_1,m_2,m_3) &=\int Y_{l_1,m_1}(\Omega) Y_{l_2,m_2}(\Omega) Y_{l_3,m_3}(\Omega) \,d\Omega \\ &=\sqrt{\frac{(2l_1+1)(2l_2+1)(2l_3+1)}{4\pi}} \operatorname{Wigner3j}(l_1,l_2,l_3,0,0,0) \operatorname{Wigner3j}(l_1,l_2,l_3,m_1,m_2,m_3) \end{aligned} Parameters ========== l_1, l_2, l_3, m_1, m_2, m_3 : Integer. prec - precision, default: ``None``. Providing a precision can drastically speed up the calculation. Returns ======= Rational number times the square root of a rational number (if ``prec=None``), or real number if a precision is given. Examples ======== >>> from sympy.physics.wigner import gaunt >>> gaunt(1,0,1,1,0,-1) -1/(2*sqrt(pi)) >>> gaunt(1000,1000,1200,9,3,-12).n(64) 0.00689500421922113448... It is an error to use non-integer values for `l` and `m`:: sage: gaunt(1.2,0,1.2,0,0,0) Traceback (most recent call last): ... ValueError: l values must be integer sage: gaunt(1,0,1,1.1,0,-1.1) Traceback (most recent call last): ... ValueError: m values must be integer Notes ===== The Gaunt coefficient obeys the following symmetry rules: - invariant under any permutation of the columns .. math:: \begin{aligned} Y(l_1,l_2,l_3,m_1,m_2,m_3) &=Y(l_3,l_1,l_2,m_3,m_1,m_2) \\ &=Y(l_2,l_3,l_1,m_2,m_3,m_1) \\ &=Y(l_3,l_2,l_1,m_3,m_2,m_1) \\ &=Y(l_1,l_3,l_2,m_1,m_3,m_2) \\ &=Y(l_2,l_1,l_3,m_2,m_1,m_3) \end{aligned} - invariant under space inflection, i.e. .. math:: Y(l_1,l_2,l_3,m_1,m_2,m_3) =Y(l_1,l_2,l_3,-m_1,-m_2,-m_3) - symmetric with respect to the 72 Regge symmetries as inherited for the `3j` symbols [Regge58]_ - zero for `l_1`, `l_2`, `l_3` not fulfilling triangle relation - zero for violating any one of the conditions: `l_1 \ge |m_1|`, `l_2 \ge |m_2|`, `l_3 \ge |m_3|` - non-zero only for an even sum of the `l_i`, i.e. `L = l_1 + l_2 + l_3 = 2n` for `n` in `\mathbb{N}` Algorithms ========== This function uses the algorithm of [Liberatodebrito82]_ to calculate the value of the Gaunt coefficient exactly. Note that the formula contains alternating sums over large factorials and is therefore unsuitable for finite precision arithmetic and only useful for a computer algebra system [Rasch03]_. Authors ======= Jens Rasch (2009-03-24): initial version for Sage. """ if int(l_1) != l_1 or int(l_2) != l_2 or int(l_3) != l_3: raise ValueError("l values must be integer") if int(m_1) != m_1 or int(m_2) != m_2 or int(m_3) != m_3: raise ValueError("m values must be integer") sumL = l_1 + l_2 + l_3 bigL = sumL // 2 a1 = l_1 + l_2 - l_3 if a1 < 0: return 0 a2 = l_1 - l_2 + l_3 if a2 < 0: return 0 a3 = -l_1 + l_2 + l_3 if a3 < 0: return 0 if sumL % 2: return 0 if (m_1 + m_2 + m_3) != 0: return 0 if (abs(m_1) > l_1) or (abs(m_2) > l_2) or (abs(m_3) > l_3): return 0 imin = max(-l_3 + l_1 + m_2, -l_3 + l_2 - m_1, 0) imax = min(l_2 + m_2, l_1 - m_1, l_1 + l_2 - l_3) 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) ressqrt = sqrt(argsqrt) 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(int(imin), int(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] sumres = sumres + Integer((-1) ** ii) / den res = ressqrt * prefac * sumres * Integer((-1) ** (bigL + l_3 + m_1 - m_2)) if prec is not None: res = res.n(prec) return res class Wigner3j(Function): def doit(self, **hints): if all(obj.is_number for obj in self.args): return wigner_3j(*self.args) else: return self def dot_rot_grad_Ynm(j, p, l, m, theta, phi): r""" Returns dot product of rotational gradients of spherical harmonics. Explanation =========== This function returns the right hand side of the following expression: .. math :: \vec{R}Y{_j^{p}} \cdot \vec{R}Y{_l^{m}} = (-1)^{m+p} \sum\limits_{k=|l-j|}^{l+j}Y{_k^{m+p}} * \alpha_{l,m,j,p,k} * \frac{1}{2} (k^2-j^2-l^2+k-j-l) Arguments ========= j, p, l, m .... indices in spherical harmonics (expressions or integers) theta, phi .... angle arguments in spherical harmonics Example ======= >>> from sympy import symbols >>> from sympy.physics.wigner import dot_rot_grad_Ynm >>> theta, phi = symbols("theta phi") >>> dot_rot_grad_Ynm(3, 2, 2, 0, theta, phi).doit() 3*sqrt(55)*Ynm(5, 2, theta, phi)/(11*sqrt(pi)) """ j = sympify(j) p = sympify(p) l = sympify(l) m = sympify(m) theta = sympify(theta) phi = sympify(phi) k = Dummy("k") def alpha(l,m,j,p,k): return sqrt((2*l+1)*(2*j+1)*(2*k+1)/(4*pi)) * \ Wigner3j(j, l, k, S.Zero, S.Zero, S.Zero) * \ Wigner3j(j, l, k, p, m, -m-p) return (S.NegativeOne)**(m+p) * Sum(Ynm(k, m+p, theta, phi) * alpha(l,m,j,p,k) / 2 \ *(k**2-j**2-l**2+k-j-l), (k, abs(l-j), l+j)) def wigner_d_small(J, beta): """Return the small Wigner d matrix for angular momentum J. Explanation =========== J : An integer, half-integer, or sympy symbol for the total angular momentum of the angular momentum space being rotated. beta : A real number representing the Euler angle of rotation about the so-called line of nodes. See [Edmonds74]_. Returns ======= A matrix representing the corresponding Euler angle rotation( in the basis of eigenvectors of `J_z`). .. math :: \\mathcal{d}_{\\beta} = \\exp\\big( \\frac{i\\beta}{\\hbar} J_y\\big) The components are calculated using the general form [Edmonds74]_, equation 4.1.15. Examples ======== >>> from sympy import Integer, symbols, pi, pprint >>> from sympy.physics.wigner import wigner_d_small >>> half = 1/Integer(2) >>> beta = symbols("beta", real=True) >>> pprint(wigner_d_small(half, beta), use_unicode=True) ⎡ ⎛β⎞ ⎛β⎞⎤ ⎢cos⎜─⎟ sin⎜─⎟⎥ ⎢ ⎝2⎠ ⎝2⎠⎥ ⎢ ⎥ ⎢ ⎛β⎞ ⎛β⎞⎥ ⎢-sin⎜─⎟ cos⎜─⎟⎥ ⎣ ⎝2⎠ ⎝2⎠⎦ >>> pprint(wigner_d_small(2*half, beta), use_unicode=True) ⎡ 2⎛β⎞ ⎛β⎞ ⎛β⎞ 2⎛β⎞ ⎤ ⎢ cos ⎜─⎟ √2⋅sin⎜─⎟⋅cos⎜─⎟ sin ⎜─⎟ ⎥ ⎢ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎥ ⎢ ⎥ ⎢ ⎛β⎞ ⎛β⎞ 2⎛β⎞ 2⎛β⎞ ⎛β⎞ ⎛β⎞⎥ ⎢-√2⋅sin⎜─⎟⋅cos⎜─⎟ - sin ⎜─⎟ + cos ⎜─⎟ √2⋅sin⎜─⎟⋅cos⎜─⎟⎥ ⎢ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠⎥ ⎢ ⎥ ⎢ 2⎛β⎞ ⎛β⎞ ⎛β⎞ 2⎛β⎞ ⎥ ⎢ sin ⎜─⎟ -√2⋅sin⎜─⎟⋅cos⎜─⎟ cos ⎜─⎟ ⎥ ⎣ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎝2⎠ ⎦ From table 4 in [Edmonds74]_ >>> pprint(wigner_d_small(half, beta).subs({beta:pi/2}), use_unicode=True) ⎡ √2 √2⎤ ⎢ ── ──⎥ ⎢ 2 2 ⎥ ⎢ ⎥ ⎢-√2 √2⎥ ⎢──── ──⎥ ⎣ 2 2 ⎦ >>> pprint(wigner_d_small(2*half, beta).subs({beta:pi/2}), ... use_unicode=True) ⎡ √2 ⎤ ⎢1/2 ── 1/2⎥ ⎢ 2 ⎥ ⎢ ⎥ ⎢-√2 √2 ⎥ ⎢──── 0 ── ⎥ ⎢ 2 2 ⎥ ⎢ ⎥ ⎢ -√2 ⎥ ⎢1/2 ──── 1/2⎥ ⎣ 2 ⎦ >>> pprint(wigner_d_small(3*half, beta).subs({beta:pi/2}), ... use_unicode=True) ⎡ √2 √6 √6 √2⎤ ⎢ ── ── ── ──⎥ ⎢ 4 4 4 4 ⎥ ⎢ ⎥ ⎢-√6 -√2 √2 √6⎥ ⎢──── ──── ── ──⎥ ⎢ 4 4 4 4 ⎥ ⎢ ⎥ ⎢ √6 -√2 -√2 √6⎥ ⎢ ── ──── ──── ──⎥ ⎢ 4 4 4 4 ⎥ ⎢ ⎥ ⎢-√2 √6 -√6 √2⎥ ⎢──── ── ──── ──⎥ ⎣ 4 4 4 4 ⎦ >>> pprint(wigner_d_small(4*half, beta).subs({beta:pi/2}), ... use_unicode=True) ⎡ √6 ⎤ ⎢1/4 1/2 ── 1/2 1/4⎥ ⎢ 4 ⎥ ⎢ ⎥ ⎢-1/2 -1/2 0 1/2 1/2⎥ ⎢ ⎥ ⎢ √6 √6 ⎥ ⎢ ── 0 -1/2 0 ── ⎥ ⎢ 4 4 ⎥ ⎢ ⎥ ⎢-1/2 1/2 0 -1/2 1/2⎥ ⎢ ⎥ ⎢ √6 ⎥ ⎢1/4 -1/2 ── -1/2 1/4⎥ ⎣ 4 ⎦ """ M = [J-i for i in range(2*J+1)] d = zeros(2*J+1) for i, Mi in enumerate(M): for j, Mj in enumerate(M): # We get the maximum and minimum value of sigma. sigmamax = max([-Mi-Mj, J-Mj]) sigmamin = min([0, J-Mi]) dij = sqrt(factorial(J+Mi)*factorial(J-Mi) / factorial(J+Mj)/factorial(J-Mj)) terms = [(-1)**(J-Mi-s) * binomial(J+Mj, J-Mi-s) * binomial(J-Mj, s) * cos(beta/2)**(2*s+Mi+Mj) * sin(beta/2)**(2*J-2*s-Mj-Mi) for s in range(sigmamin, sigmamax+1)] d[i, j] = dij*Add(*terms) return ImmutableMatrix(d) def wigner_d(J, alpha, beta, gamma): """Return the Wigner D matrix for angular momentum J. Explanation =========== J : An integer, half-integer, or sympy symbol for the total angular momentum of the angular momentum space being rotated. alpha, beta, gamma - Real numbers representing the Euler. Angles of rotation about the so-called vertical, line of nodes, and figure axes. See [Edmonds74]_. Returns ======= A matrix representing the corresponding Euler angle rotation( in the basis of eigenvectors of `J_z`). .. math :: \\mathcal{D}_{\\alpha \\beta \\gamma} = \\exp\\big( \\frac{i\\alpha}{\\hbar} J_z\\big) \\exp\\big( \\frac{i\\beta}{\\hbar} J_y\\big) \\exp\\big( \\frac{i\\gamma}{\\hbar} J_z\\big) The components are calculated using the general form [Edmonds74]_, equation 4.1.12. Examples ======== The simplest possible example: >>> from sympy.physics.wigner import wigner_d >>> from sympy import Integer, symbols, pprint >>> half = 1/Integer(2) >>> alpha, beta, gamma = symbols("alpha, beta, gamma", real=True) >>> pprint(wigner_d(half, alpha, beta, gamma), use_unicode=True) ⎡ ⅈ⋅α ⅈ⋅γ ⅈ⋅α -ⅈ⋅γ ⎤ ⎢ ─── ─── ─── ───── ⎥ ⎢ 2 2 ⎛β⎞ 2 2 ⎛β⎞ ⎥ ⎢ ℯ ⋅ℯ ⋅cos⎜─⎟ ℯ ⋅ℯ ⋅sin⎜─⎟ ⎥ ⎢ ⎝2⎠ ⎝2⎠ ⎥ ⎢ ⎥ ⎢ -ⅈ⋅α ⅈ⋅γ -ⅈ⋅α -ⅈ⋅γ ⎥ ⎢ ───── ─── ───── ───── ⎥ ⎢ 2 2 ⎛β⎞ 2 2 ⎛β⎞⎥ ⎢-ℯ ⋅ℯ ⋅sin⎜─⎟ ℯ ⋅ℯ ⋅cos⎜─⎟⎥ ⎣ ⎝2⎠ ⎝2⎠⎦ """ d = wigner_d_small(J, beta) M = [J-i for i in range(2*J+1)] D = [[exp(I*Mi*alpha)*d[i, j]*exp(I*Mj*gamma) for j, Mj in enumerate(M)] for i, Mi in enumerate(M)] return ImmutableMatrix(D) sympy-sympy-1.9/sympy/plotting/000077500000000000000000000000001412543434000167445ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/__init__.py000066400000000000000000000007611412543434000210610ustar00rootroot00000000000000from .plot import plot_backends from .plot_implicit import plot_implicit from .textplot import textplot from .pygletplot import PygletPlot from .plot import PlotGrid from .plot import (plot, plot_parametric, plot3d, plot3d_parametric_surface, plot3d_parametric_line) __all__ = [ 'plot_backends', 'plot_implicit', 'textplot', 'PygletPlot', 'PlotGrid', 'plot', 'plot_parametric', 'plot3d', 'plot3d_parametric_surface', 'plot3d_parametric_line', ] sympy-sympy-1.9/sympy/plotting/experimental_lambdify.py000066400000000000000000000545541412543434000236770ustar00rootroot00000000000000""" rewrite of lambdify - This stuff is not stable at all. It is for internal use in the new plotting module. It may (will! see the Q'n'A in the source) be rewritten. It's completely self contained. Especially it does not use lambdarepr. It does not aim to replace the current lambdify. Most importantly it will never ever support anything else than sympy expressions (no Matrices, dictionaries and so on). """ import re from sympy import Symbol, NumberSymbol, I, zoo, oo from sympy.utilities.iterables import numbered_symbols # We parse the expression string into a tree that identifies functions. Then # we translate the names of the functions and we translate also some strings # that are not names of functions (all this according to translation # dictionaries). # If the translation goes to another module (like numpy) the # module is imported and 'func' is translated to 'module.func'. # If a function can not be translated, the inner nodes of that part of the # tree are not translated. So if we have Integral(sqrt(x)), sqrt is not # translated to np.sqrt and the Integral does not crash. # A namespace for all this is generated by crawling the (func, args) tree of # the expression. The creation of this namespace involves many ugly # workarounds. # The namespace consists of all the names needed for the sympy expression and # all the name of modules used for translation. Those modules are imported only # as a name (import numpy as np) in order to keep the namespace small and # manageable. # Please, if there is a bug, do not try to fix it here! Rewrite this by using # the method proposed in the last Q'n'A below. That way the new function will # work just as well, be just as simple, but it wont need any new workarounds. # If you insist on fixing it here, look at the workarounds in the function # sympy_expression_namespace and in lambdify. # Q: Why are you not using python abstract syntax tree? # A: Because it is more complicated and not much more powerful in this case. # Q: What if I have Symbol('sin') or g=Function('f')? # A: You will break the algorithm. We should use srepr to defend against this? # The problem with Symbol('sin') is that it will be printed as 'sin'. The # parser will distinguish it from the function 'sin' because functions are # detected thanks to the opening parenthesis, but the lambda expression won't # understand the difference if we have also the sin function. # The solution (complicated) is to use srepr and maybe ast. # The problem with the g=Function('f') is that it will be printed as 'f' but in # the global namespace we have only 'g'. But as the same printer is used in the # constructor of the namespace there will be no problem. # Q: What if some of the printers are not printing as expected? # A: The algorithm wont work. You must use srepr for those cases. But even # srepr may not print well. All problems with printers should be considered # bugs. # Q: What about _imp_ functions? # A: Those are taken care for by evalf. A special case treatment will work # faster but it's not worth the code complexity. # Q: Will ast fix all possible problems? # A: No. You will always have to use some printer. Even srepr may not work in # some cases. But if the printer does not work, that should be considered a # bug. # Q: Is there same way to fix all possible problems? # A: Probably by constructing our strings ourself by traversing the (func, # args) tree and creating the namespace at the same time. That actually sounds # good. from sympy.external import import_module import warnings #TODO debugging output class vectorized_lambdify: """ Return a sufficiently smart, vectorized and lambdified function. Returns only reals. Explanation =========== This function uses experimental_lambdify to created a lambdified expression ready to be used with numpy. Many of the functions in sympy are not implemented in numpy so in some cases we resort to python cmath or even to evalf. The following translations are tried: only numpy complex - on errors raised by sympy trying to work with ndarray: only python cmath and then vectorize complex128 When using python cmath there is no need for evalf or float/complex because python cmath calls those. This function never tries to mix numpy directly with evalf because numpy does not understand sympy Float. If this is needed one can use the float_wrap_evalf/complex_wrap_evalf options of experimental_lambdify or better one can be explicit about the dtypes that numpy works with. Check numpy bug http://projects.scipy.org/numpy/ticket/1013 to know what types of errors to expect. """ def __init__(self, args, expr): self.args = args self.expr = expr self.np = import_module('numpy') self.lambda_func_1 = experimental_lambdify( args, expr, use_np=True) self.vector_func_1 = self.lambda_func_1 self.lambda_func_2 = experimental_lambdify( args, expr, use_python_cmath=True) self.vector_func_2 = self.np.vectorize( self.lambda_func_2, otypes=[complex]) self.vector_func = self.vector_func_1 self.failure = False def __call__(self, *args): np = self.np try: temp_args = (np.array(a, dtype=complex) for a in args) results = self.vector_func(*temp_args) results = np.ma.masked_where( np.abs(results.imag) > 1e-7 * np.abs(results), results.real, copy=False) return results except ValueError: if self.failure: raise self.failure = True self.vector_func = self.vector_func_2 warnings.warn( 'The evaluation of the expression is problematic. ' 'We are trying a failback method that may still work. ' 'Please report this as a bug.') return self.__call__(*args) class lambdify: """Returns the lambdified function. Explanation =========== This function uses experimental_lambdify to create a lambdified expression. It uses cmath to lambdify the expression. If the function is not implemented in python cmath, python cmath calls evalf on those functions. """ def __init__(self, args, expr): self.args = args self.expr = expr self.lambda_func_1 = experimental_lambdify( args, expr, use_python_cmath=True, use_evalf=True) self.lambda_func_2 = experimental_lambdify( args, expr, use_python_math=True, use_evalf=True) self.lambda_func_3 = experimental_lambdify( args, expr, use_evalf=True, complex_wrap_evalf=True) self.lambda_func = self.lambda_func_1 self.failure = False def __call__(self, args): try: #The result can be sympy.Float. Hence wrap it with complex type. result = complex(self.lambda_func(args)) if abs(result.imag) > 1e-7 * abs(result): return None return result.real except (ZeroDivisionError, OverflowError, TypeError) as e: if isinstance(e, ZeroDivisionError) or isinstance(e, OverflowError): return None if self.failure: raise e if self.lambda_func == self.lambda_func_1: self.lambda_func = self.lambda_func_2 return self.__call__(args) self.failure = True self.lambda_func = self.lambda_func_3 warnings.warn( 'The evaluation of the expression is problematic. ' 'We are trying a failback method that may still work. ' 'Please report this as a bug.') return self.__call__(args) def experimental_lambdify(*args, **kwargs): l = Lambdifier(*args, **kwargs) return l class Lambdifier: def __init__(self, args, expr, print_lambda=False, use_evalf=False, float_wrap_evalf=False, complex_wrap_evalf=False, use_np=False, use_python_math=False, use_python_cmath=False, use_interval=False): self.print_lambda = print_lambda self.use_evalf = use_evalf self.float_wrap_evalf = float_wrap_evalf self.complex_wrap_evalf = complex_wrap_evalf self.use_np = use_np self.use_python_math = use_python_math self.use_python_cmath = use_python_cmath self.use_interval = use_interval # Constructing the argument string # - check if not all([isinstance(a, Symbol) for a in args]): raise ValueError('The arguments must be Symbols.') # - use numbered symbols syms = numbered_symbols(exclude=expr.free_symbols) newargs = [next(syms) for _ in args] expr = expr.xreplace(dict(zip(args, newargs))) argstr = ', '.join([str(a) for a in newargs]) del syms, newargs, args # Constructing the translation dictionaries and making the translation self.dict_str = self.get_dict_str() self.dict_fun = self.get_dict_fun() exprstr = str(expr) newexpr = self.tree2str_translate(self.str2tree(exprstr)) # Constructing the namespaces namespace = {} namespace.update(self.sympy_atoms_namespace(expr)) namespace.update(self.sympy_expression_namespace(expr)) # XXX Workaround # Ugly workaround because Pow(a,Half) prints as sqrt(a) # and sympy_expression_namespace can not catch it. from sympy import sqrt namespace.update({'sqrt': sqrt}) namespace.update({'Eq': lambda x, y: x == y}) namespace.update({'Ne': lambda x, y: x != y}) # End workaround. if use_python_math: namespace.update({'math': __import__('math')}) if use_python_cmath: namespace.update({'cmath': __import__('cmath')}) if use_np: try: namespace.update({'np': __import__('numpy')}) except ImportError: raise ImportError( 'experimental_lambdify failed to import numpy.') if use_interval: namespace.update({'imath': __import__( 'sympy.plotting.intervalmath', fromlist=['intervalmath'])}) namespace.update({'math': __import__('math')}) # Construct the lambda if self.print_lambda: print(newexpr) eval_str = 'lambda %s : ( %s )' % (argstr, newexpr) self.eval_str = eval_str exec("from __future__ import division; MYNEWLAMBDA = %s" % eval_str, namespace) self.lambda_func = namespace['MYNEWLAMBDA'] def __call__(self, *args, **kwargs): return self.lambda_func(*args, **kwargs) ############################################################################## # Dicts for translating from sympy to other modules ############################################################################## ### # builtins ### # Functions with different names in builtins builtin_functions_different = { 'Min': 'min', 'Max': 'max', 'Abs': 'abs', } # Strings that should be translated builtin_not_functions = { 'I': '1j', # 'oo': '1e400', } ### # numpy ### # Functions that are the same in numpy numpy_functions_same = [ 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'exp', 'log', 'sqrt', 'floor', 'conjugate', ] # Functions with different names in numpy numpy_functions_different = { "acos": "arccos", "acosh": "arccosh", "arg": "angle", "asin": "arcsin", "asinh": "arcsinh", "atan": "arctan", "atan2": "arctan2", "atanh": "arctanh", "ceiling": "ceil", "im": "imag", "ln": "log", "Max": "amax", "Min": "amin", "re": "real", "Abs": "abs", } # Strings that should be translated numpy_not_functions = { 'pi': 'np.pi', 'oo': 'np.inf', 'E': 'np.e', } ### # python math ### # Functions that are the same in math math_functions_same = [ 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', 'exp', 'log', 'erf', 'sqrt', 'floor', 'factorial', 'gamma', ] # Functions with different names in math math_functions_different = { 'ceiling': 'ceil', 'ln': 'log', 'loggamma': 'lgamma' } # Strings that should be translated math_not_functions = { 'pi': 'math.pi', 'E': 'math.e', } ### # python cmath ### # Functions that are the same in cmath cmath_functions_same = [ 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'sinh', 'cosh', 'tanh', 'asinh', 'acosh', 'atanh', 'exp', 'log', 'sqrt', ] # Functions with different names in cmath cmath_functions_different = { 'ln': 'log', 'arg': 'phase', } # Strings that should be translated cmath_not_functions = { 'pi': 'cmath.pi', 'E': 'cmath.e', } ### # intervalmath ### interval_not_functions = { 'pi': 'math.pi', 'E': 'math.e' } interval_functions_same = [ 'sin', 'cos', 'exp', 'tan', 'atan', 'log', 'sqrt', 'cosh', 'sinh', 'tanh', 'floor', 'acos', 'asin', 'acosh', 'asinh', 'atanh', 'Abs', 'And', 'Or' ] interval_functions_different = { 'Min': 'imin', 'Max': 'imax', 'ceiling': 'ceil', } ### # mpmath, etc ### #TODO ### # Create the final ordered tuples of dictionaries ### # For strings def get_dict_str(self): dict_str = dict(self.builtin_not_functions) if self.use_np: dict_str.update(self.numpy_not_functions) if self.use_python_math: dict_str.update(self.math_not_functions) if self.use_python_cmath: dict_str.update(self.cmath_not_functions) if self.use_interval: dict_str.update(self.interval_not_functions) return dict_str # For functions def get_dict_fun(self): dict_fun = dict(self.builtin_functions_different) if self.use_np: for s in self.numpy_functions_same: dict_fun[s] = 'np.' + s for k, v in self.numpy_functions_different.items(): dict_fun[k] = 'np.' + v if self.use_python_math: for s in self.math_functions_same: dict_fun[s] = 'math.' + s for k, v in self.math_functions_different.items(): dict_fun[k] = 'math.' + v if self.use_python_cmath: for s in self.cmath_functions_same: dict_fun[s] = 'cmath.' + s for k, v in self.cmath_functions_different.items(): dict_fun[k] = 'cmath.' + v if self.use_interval: for s in self.interval_functions_same: dict_fun[s] = 'imath.' + s for k, v in self.interval_functions_different.items(): dict_fun[k] = 'imath.' + v return dict_fun ############################################################################## # The translator functions, tree parsers, etc. ############################################################################## def str2tree(self, exprstr): """Converts an expression string to a tree. Explanation =========== Functions are represented by ('func_name(', tree_of_arguments). Other expressions are (head_string, mid_tree, tail_str). Expressions that do not contain functions are directly returned. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy import Integral, sin >>> from sympy.plotting.experimental_lambdify import Lambdifier >>> str2tree = Lambdifier([x], x).str2tree >>> str2tree(str(Integral(x, (x, 1, y)))) ('', ('Integral(', 'x, (x, 1, y)'), ')') >>> str2tree(str(x+y)) 'x + y' >>> str2tree(str(x+y*sin(z)+1)) ('x + y*', ('sin(', 'z'), ') + 1') >>> str2tree('sin(y*(y + 1.1) + (sin(y)))') ('', ('sin(', ('y*(y + 1.1) + (', ('sin(', 'y'), '))')), ')') """ #matches the first 'function_name(' first_par = re.search(r'(\w+\()', exprstr) if first_par is None: return exprstr else: start = first_par.start() end = first_par.end() head = exprstr[:start] func = exprstr[start:end] tail = exprstr[end:] count = 0 for i, c in enumerate(tail): if c == '(': count += 1 elif c == ')': count -= 1 if count == -1: break func_tail = self.str2tree(tail[:i]) tail = self.str2tree(tail[i:]) return (head, (func, func_tail), tail) @classmethod def tree2str(cls, tree): """Converts a tree to string without translations. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy import sin >>> from sympy.plotting.experimental_lambdify import Lambdifier >>> str2tree = Lambdifier([x], x).str2tree >>> tree2str = Lambdifier([x], x).tree2str >>> tree2str(str2tree(str(x+y*sin(z)+1))) 'x + y*sin(z) + 1' """ if isinstance(tree, str): return tree else: return ''.join(map(cls.tree2str, tree)) def tree2str_translate(self, tree): """Converts a tree to string with translations. Explanation =========== Function names are translated by translate_func. Other strings are translated by translate_str. """ if isinstance(tree, str): return self.translate_str(tree) elif isinstance(tree, tuple) and len(tree) == 2: return self.translate_func(tree[0][:-1], tree[1]) else: return ''.join([self.tree2str_translate(t) for t in tree]) def translate_str(self, estr): """Translate substrings of estr using in order the dictionaries in dict_tuple_str.""" for pattern, repl in self.dict_str.items(): estr = re.sub(pattern, repl, estr) return estr def translate_func(self, func_name, argtree): """Translate function names and the tree of arguments. Explanation =========== If the function name is not in the dictionaries of dict_tuple_fun then the function is surrounded by a float((...).evalf()). The use of float is necessary as np.(sympy.Float(..)) raises an error.""" if func_name in self.dict_fun: new_name = self.dict_fun[func_name] argstr = self.tree2str_translate(argtree) return new_name + '(' + argstr elif func_name in ['Eq', 'Ne']: op = {'Eq': '==', 'Ne': '!='} return "(lambda x, y: x {} y)({}".format(op[func_name], self.tree2str_translate(argtree)) else: template = '(%s(%s)).evalf(' if self.use_evalf else '%s(%s' if self.float_wrap_evalf: template = 'float(%s)' % template elif self.complex_wrap_evalf: template = 'complex(%s)' % template # Wrapping should only happen on the outermost expression, which # is the only thing we know will be a number. float_wrap_evalf = self.float_wrap_evalf complex_wrap_evalf = self.complex_wrap_evalf self.float_wrap_evalf = False self.complex_wrap_evalf = False ret = template % (func_name, self.tree2str_translate(argtree)) self.float_wrap_evalf = float_wrap_evalf self.complex_wrap_evalf = complex_wrap_evalf return ret ############################################################################## # The namespace constructors ############################################################################## @classmethod def sympy_expression_namespace(cls, expr): """Traverses the (func, args) tree of an expression and creates a sympy namespace. All other modules are imported only as a module name. That way the namespace is not polluted and rests quite small. It probably causes much more variable lookups and so it takes more time, but there are no tests on that for the moment.""" if expr is None: return {} else: funcname = str(expr.func) # XXX Workaround # Here we add an ugly workaround because str(func(x)) # is not always the same as str(func). Eg # >>> str(Integral(x)) # "Integral(x)" # >>> str(Integral) # "" # >>> str(sqrt(x)) # "sqrt(x)" # >>> str(sqrt) # "" # >>> str(sin(x)) # "sin(x)" # >>> str(sin) # "sin" # Either one of those can be used but not all at the same time. # The code considers the sin example as the right one. regexlist = [ r'$', # the example Integral r'$', # the example sqrt ] for r in regexlist: m = re.match(r, funcname) if m is not None: funcname = m.groups()[0] # End of the workaround # XXX debug: print funcname args_dict = {} for a in expr.args: if (isinstance(a, Symbol) or isinstance(a, NumberSymbol) or a in [I, zoo, oo]): continue else: args_dict.update(cls.sympy_expression_namespace(a)) args_dict.update({funcname: expr.func}) return args_dict @staticmethod def sympy_atoms_namespace(expr): """For no real reason this function is separated from sympy_expression_namespace. It can be moved to it.""" atoms = expr.atoms(Symbol, NumberSymbol, I, zoo, oo) d = {} for a in atoms: # XXX debug: print 'atom:' + str(a) d[str(a)] = a return d sympy-sympy-1.9/sympy/plotting/intervalmath/000077500000000000000000000000001412543434000214425ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/intervalmath/__init__.py000066400000000000000000000007371412543434000235620ustar00rootroot00000000000000from .interval_arithmetic import interval from .lib_interval import (Abs, exp, log, log10, sin, cos, tan, sqrt, imin, imax, sinh, cosh, tanh, acosh, asinh, atanh, asin, acos, atan, ceil, floor, And, Or) __all__ = [ 'interval', 'Abs', 'exp', 'log', 'log10', 'sin', 'cos', 'tan', 'sqrt', 'imin', 'imax', 'sinh', 'cosh', 'tanh', 'acosh', 'asinh', 'atanh', 'asin', 'acos', 'atan', 'ceil', 'floor', 'And', 'Or', ] sympy-sympy-1.9/sympy/plotting/intervalmath/interval_arithmetic.py000066400000000000000000000362521412543434000260610ustar00rootroot00000000000000""" Interval Arithmetic for plotting. This module does not implement interval arithmetic accurately and hence cannot be used for purposes other than plotting. If you want to use interval arithmetic, use mpmath's interval arithmetic. The module implements interval arithmetic using numpy and python floating points. The rounding up and down is not handled and hence this is not an accurate implementation of interval arithmetic. The module uses numpy for speed which cannot be achieved with mpmath. """ # Q: Why use numpy? Why not simply use mpmath's interval arithmetic? # A: mpmath's interval arithmetic simulates a floating point unit # and hence is slow, while numpy evaluations are orders of magnitude # faster. # Q: Why create a separate class for intervals? Why not use sympy's # Interval Sets? # A: The functionalities that will be required for plotting is quite # different from what Interval Sets implement. # Q: Why is rounding up and down according to IEEE754 not handled? # A: It is not possible to do it in both numpy and python. An external # library has to used, which defeats the whole purpose i.e., speed. Also # rounding is handled for very few functions in those libraries. # Q Will my plots be affected? # A It will not affect most of the plots. The interval arithmetic # module based suffers the same problems as that of floating point # arithmetic. from sympy.core.logic import fuzzy_and from sympy.simplify.simplify import nsimplify from .interval_membership import intervalMembership class interval: """ Represents an interval containing floating points as start and end of the interval The is_valid variable tracks whether the interval obtained as the result of the function is in the domain and is continuous. - True: Represents the interval result of a function is continuous and in the domain of the function. - False: The interval argument of the function was not in the domain of the function, hence the is_valid of the result interval is False - None: The function was not continuous over the interval or the function's argument interval is partly in the domain of the function A comparison between an interval and a real number, or a comparison between two intervals may return ``intervalMembership`` of two 3-valued logic values. """ def __init__(self, *args, is_valid=True, **kwargs): self.is_valid = is_valid if len(args) == 1: if isinstance(args[0], interval): self.start, self.end = args[0].start, args[0].end else: self.start = float(args[0]) self.end = float(args[0]) elif len(args) == 2: if args[0] < args[1]: self.start = float(args[0]) self.end = float(args[1]) else: self.start = float(args[1]) self.end = float(args[0]) else: raise ValueError("interval takes a maximum of two float values " "as arguments") @property def mid(self): return (self.start + self.end) / 2.0 @property def width(self): return self.end - self.start def __repr__(self): return "interval(%f, %f)" % (self.start, self.end) def __str__(self): return "[%f, %f]" % (self.start, self.end) def __lt__(self, other): if isinstance(other, (int, float)): if self.end < other: return intervalMembership(True, self.is_valid) elif self.start > other: return intervalMembership(False, self.is_valid) else: return intervalMembership(None, self.is_valid) elif isinstance(other, interval): valid = fuzzy_and([self.is_valid, other.is_valid]) if self.end < other. start: return intervalMembership(True, valid) if self.start > other.end: return intervalMembership(False, valid) return intervalMembership(None, valid) else: return NotImplemented def __gt__(self, other): if isinstance(other, (int, float)): if self.start > other: return intervalMembership(True, self.is_valid) elif self.end < other: return intervalMembership(False, self.is_valid) else: return intervalMembership(None, self.is_valid) elif isinstance(other, interval): return other.__lt__(self) else: return NotImplemented def __eq__(self, other): if isinstance(other, (int, float)): if self.start == other and self.end == other: return intervalMembership(True, self.is_valid) if other in self: return intervalMembership(None, self.is_valid) else: return intervalMembership(False, self.is_valid) if isinstance(other, interval): valid = fuzzy_and([self.is_valid, other.is_valid]) if self.start == other.start and self.end == other.end: return intervalMembership(True, valid) elif self.__lt__(other)[0] is not None: return intervalMembership(False, valid) else: return intervalMembership(None, valid) else: return NotImplemented def __ne__(self, other): if isinstance(other, (int, float)): if self.start == other and self.end == other: return intervalMembership(False, self.is_valid) if other in self: return intervalMembership(None, self.is_valid) else: return intervalMembership(True, self.is_valid) if isinstance(other, interval): valid = fuzzy_and([self.is_valid, other.is_valid]) if self.start == other.start and self.end == other.end: return intervalMembership(False, valid) if not self.__lt__(other)[0] is None: return intervalMembership(True, valid) return intervalMembership(None, valid) else: return NotImplemented def __le__(self, other): if isinstance(other, (int, float)): if self.end <= other: return intervalMembership(True, self.is_valid) if self.start > other: return intervalMembership(False, self.is_valid) else: return intervalMembership(None, self.is_valid) if isinstance(other, interval): valid = fuzzy_and([self.is_valid, other.is_valid]) if self.end <= other.start: return intervalMembership(True, valid) if self.start > other.end: return intervalMembership(False, valid) return intervalMembership(None, valid) else: return NotImplemented def __ge__(self, other): if isinstance(other, (int, float)): if self.start >= other: return intervalMembership(True, self.is_valid) elif self.end < other: return intervalMembership(False, self.is_valid) else: return intervalMembership(None, self.is_valid) elif isinstance(other, interval): return other.__le__(self) def __add__(self, other): if isinstance(other, (int, float)): if self.is_valid: return interval(self.start + other, self.end + other) else: start = self.start + other end = self.end + other return interval(start, end, is_valid=self.is_valid) elif isinstance(other, interval): start = self.start + other.start end = self.end + other.end valid = fuzzy_and([self.is_valid, other.is_valid]) return interval(start, end, is_valid=valid) else: return NotImplemented __radd__ = __add__ def __sub__(self, other): if isinstance(other, (int, float)): start = self.start - other end = self.end - other return interval(start, end, is_valid=self.is_valid) elif isinstance(other, interval): start = self.start - other.end end = self.end - other.start valid = fuzzy_and([self.is_valid, other.is_valid]) return interval(start, end, is_valid=valid) else: return NotImplemented def __rsub__(self, other): if isinstance(other, (int, float)): start = other - self.end end = other - self.start return interval(start, end, is_valid=self.is_valid) elif isinstance(other, interval): return other.__sub__(self) else: return NotImplemented def __neg__(self): if self.is_valid: return interval(-self.end, -self.start) else: return interval(-self.end, -self.start, is_valid=self.is_valid) def __mul__(self, other): if isinstance(other, interval): if self.is_valid is False or other.is_valid is False: return interval(-float('inf'), float('inf'), is_valid=False) elif self.is_valid is None or other.is_valid is None: return interval(-float('inf'), float('inf'), is_valid=None) else: inters = [] inters.append(self.start * other.start) inters.append(self.end * other.start) inters.append(self.start * other.end) inters.append(self.end * other.end) start = min(inters) end = max(inters) return interval(start, end) elif isinstance(other, (int, float)): return interval(self.start*other, self.end*other, is_valid=self.is_valid) else: return NotImplemented __rmul__ = __mul__ def __contains__(self, other): if isinstance(other, (int, float)): return self.start <= other and self.end >= other else: return self.start <= other.start and other.end <= self.end def __rtruediv__(self, other): if isinstance(other, (int, float)): other = interval(other) return other.__truediv__(self) elif isinstance(other, interval): return other.__truediv__(self) else: return NotImplemented def __truediv__(self, other): # Both None and False are handled if not self.is_valid: # Don't divide as the value is not valid return interval(-float('inf'), float('inf'), is_valid=self.is_valid) if isinstance(other, (int, float)): if other == 0: # Divide by zero encountered. valid nowhere return interval(-float('inf'), float('inf'), is_valid=False) else: return interval(self.start / other, self.end / other) elif isinstance(other, interval): if other.is_valid is False or self.is_valid is False: return interval(-float('inf'), float('inf'), is_valid=False) elif other.is_valid is None or self.is_valid is None: return interval(-float('inf'), float('inf'), is_valid=None) else: # denominator contains both signs, i.e. being divided by zero # return the whole real line with is_valid = None if 0 in other: return interval(-float('inf'), float('inf'), is_valid=None) # denominator negative this = self if other.end < 0: this = -this other = -other # denominator positive inters = [] inters.append(this.start / other.start) inters.append(this.end / other.start) inters.append(this.start / other.end) inters.append(this.end / other.end) start = max(inters) end = min(inters) return interval(start, end) else: return NotImplemented def __pow__(self, other): # Implements only power to an integer. from .lib_interval import exp, log if not self.is_valid: return self if isinstance(other, interval): return exp(other * log(self)) elif isinstance(other, (float, int)): if other < 0: return 1 / self.__pow__(abs(other)) else: if int(other) == other: return _pow_int(self, other) else: return _pow_float(self, other) else: return NotImplemented def __rpow__(self, other): if isinstance(other, (float, int)): if not self.is_valid: #Don't do anything return self elif other < 0: if self.width > 0: return interval(-float('inf'), float('inf'), is_valid=False) else: power_rational = nsimplify(self.start) num, denom = power_rational.as_numer_denom() if denom % 2 == 0: return interval(-float('inf'), float('inf'), is_valid=False) else: start = -abs(other)**self.start end = start return interval(start, end) else: return interval(other**self.start, other**self.end) elif isinstance(other, interval): return other.__pow__(self) else: return NotImplemented def __hash__(self): return hash((self.is_valid, self.start, self.end)) def _pow_float(inter, power): """Evaluates an interval raised to a floating point.""" power_rational = nsimplify(power) num, denom = power_rational.as_numer_denom() if num % 2 == 0: start = abs(inter.start)**power end = abs(inter.end)**power if start < 0: ret = interval(0, max(start, end)) else: ret = interval(start, end) return ret elif denom % 2 == 0: if inter.end < 0: return interval(-float('inf'), float('inf'), is_valid=False) elif inter.start < 0: return interval(0, inter.end**power, is_valid=None) else: return interval(inter.start**power, inter.end**power) else: if inter.start < 0: start = -abs(inter.start)**power else: start = inter.start**power if inter.end < 0: end = -abs(inter.end)**power else: end = inter.end**power return interval(start, end, is_valid=inter.is_valid) def _pow_int(inter, power): """Evaluates an interval raised to an integer power""" power = int(power) if power & 1: return interval(inter.start**power, inter.end**power) else: if inter.start < 0 and inter.end > 0: start = 0 end = max(inter.start**power, inter.end**power) return interval(start, end) else: return interval(inter.start**power, inter.end**power) sympy-sympy-1.9/sympy/plotting/intervalmath/interval_membership.py000066400000000000000000000045211412543434000260550ustar00rootroot00000000000000from sympy.core.logic import fuzzy_and, fuzzy_or, fuzzy_not, fuzzy_xor class intervalMembership: """Represents a boolean expression returned by the comparison of the interval object. Parameters ========== (a, b) : (bool, bool) The first value determines the comparison as follows: - True: If the comparison is True throughout the intervals. - False: If the comparison is False throughout the intervals. - None: If the comparison is True for some part of the intervals. The second value is determined as follows: - True: If both the intervals in comparison are valid. - False: If at least one of the intervals is False, else - None """ def __init__(self, a, b): self._wrapped = (a, b) def __getitem__(self, i): try: return self._wrapped[i] except IndexError: raise IndexError( "{} must be a valid indexing for the 2-tuple." .format(i)) def __len__(self): return 2 def __iter__(self): return iter(self._wrapped) def __str__(self): return "intervalMembership({}, {})".format(*self) __repr__ = __str__ def __and__(self, other): if not isinstance(other, intervalMembership): raise ValueError( "The comparison is not supported for {}.".format(other)) a1, b1 = self a2, b2 = other return intervalMembership(fuzzy_and([a1, a2]), fuzzy_and([b1, b2])) def __or__(self, other): if not isinstance(other, intervalMembership): raise ValueError( "The comparison is not supported for {}.".format(other)) a1, b1 = self a2, b2 = other return intervalMembership(fuzzy_or([a1, a2]), fuzzy_and([b1, b2])) def __invert__(self): a, b = self return intervalMembership(fuzzy_not(a), b) def __xor__(self, other): if not isinstance(other, intervalMembership): raise ValueError( "The comparison is not supported for {}.".format(other)) a1, b1 = self a2, b2 = other return intervalMembership(fuzzy_xor([a1, a2]), fuzzy_and([b1, b2])) def __eq__(self, other): return self._wrapped == other def __ne__(self, other): return self._wrapped != other sympy-sympy-1.9/sympy/plotting/intervalmath/lib_interval.py000066400000000000000000000347311412543434000244760ustar00rootroot00000000000000""" The module contains implemented functions for interval arithmetic.""" from functools import reduce from sympy.plotting.intervalmath import interval from sympy.external import import_module def Abs(x): if isinstance(x, (int, float)): return interval(abs(x)) elif isinstance(x, interval): if x.start < 0 and x.end > 0: return interval(0, max(abs(x.start), abs(x.end)), is_valid=x.is_valid) else: return interval(abs(x.start), abs(x.end)) else: raise NotImplementedError #Monotonic def exp(x): """evaluates the exponential of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.exp(x), np.exp(x)) elif isinstance(x, interval): return interval(np.exp(x.start), np.exp(x.end), is_valid=x.is_valid) else: raise NotImplementedError #Monotonic def log(x): """evaluates the natural logarithm of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): if x <= 0: return interval(-np.inf, np.inf, is_valid=False) else: return interval(np.log(x)) elif isinstance(x, interval): if not x.is_valid: return interval(-np.inf, np.inf, is_valid=x.is_valid) elif x.end <= 0: return interval(-np.inf, np.inf, is_valid=False) elif x.start <= 0: return interval(-np.inf, np.inf, is_valid=None) return interval(np.log(x.start), np.log(x.end)) else: raise NotImplementedError #Monotonic def log10(x): """evaluates the logarithm to the base 10 of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): if x <= 0: return interval(-np.inf, np.inf, is_valid=False) else: return interval(np.log10(x)) elif isinstance(x, interval): if not x.is_valid: return interval(-np.inf, np.inf, is_valid=x.is_valid) elif x.end <= 0: return interval(-np.inf, np.inf, is_valid=False) elif x.start <= 0: return interval(-np.inf, np.inf, is_valid=None) return interval(np.log10(x.start), np.log10(x.end)) else: raise NotImplementedError #Monotonic def atan(x): """evaluates the tan inverse of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.arctan(x)) elif isinstance(x, interval): start = np.arctan(x.start) end = np.arctan(x.end) return interval(start, end, is_valid=x.is_valid) else: raise NotImplementedError #periodic def sin(x): """evaluates the sine of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.sin(x)) elif isinstance(x, interval): if not x.is_valid: return interval(-1, 1, is_valid=x.is_valid) na, __ = divmod(x.start, np.pi / 2.0) nb, __ = divmod(x.end, np.pi / 2.0) start = min(np.sin(x.start), np.sin(x.end)) end = max(np.sin(x.start), np.sin(x.end)) if nb - na > 4: return interval(-1, 1, is_valid=x.is_valid) elif na == nb: return interval(start, end, is_valid=x.is_valid) else: if (na - 1) // 4 != (nb - 1) // 4: #sin has max end = 1 if (na - 3) // 4 != (nb - 3) // 4: #sin has min start = -1 return interval(start, end) else: raise NotImplementedError #periodic def cos(x): """Evaluates the cos of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.sin(x)) elif isinstance(x, interval): if not (np.isfinite(x.start) and np.isfinite(x.end)): return interval(-1, 1, is_valid=x.is_valid) na, __ = divmod(x.start, np.pi / 2.0) nb, __ = divmod(x.end, np.pi / 2.0) start = min(np.cos(x.start), np.cos(x.end)) end = max(np.cos(x.start), np.cos(x.end)) if nb - na > 4: #differ more than 2*pi return interval(-1, 1, is_valid=x.is_valid) elif na == nb: #in the same quadarant return interval(start, end, is_valid=x.is_valid) else: if (na) // 4 != (nb) // 4: #cos has max end = 1 if (na - 2) // 4 != (nb - 2) // 4: #cos has min start = -1 return interval(start, end, is_valid=x.is_valid) else: raise NotImplementedError def tan(x): """Evaluates the tan of an interval""" return sin(x) / cos(x) #Monotonic def sqrt(x): """Evaluates the square root of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): if x > 0: return interval(np.sqrt(x)) else: return interval(-np.inf, np.inf, is_valid=False) elif isinstance(x, interval): #Outside the domain if x.end < 0: return interval(-np.inf, np.inf, is_valid=False) #Partially outside the domain elif x.start < 0: return interval(-np.inf, np.inf, is_valid=None) else: return interval(np.sqrt(x.start), np.sqrt(x.end), is_valid=x.is_valid) else: raise NotImplementedError def imin(*args): """Evaluates the minimum of a list of intervals""" np = import_module('numpy') if not all(isinstance(arg, (int, float, interval)) for arg in args): return NotImplementedError else: new_args = [a for a in args if isinstance(a, (int, float)) or a.is_valid] if len(new_args) == 0: if all(a.is_valid is False for a in args): return interval(-np.inf, np.inf, is_valid=False) else: return interval(-np.inf, np.inf, is_valid=None) start_array = [a if isinstance(a, (int, float)) else a.start for a in new_args] end_array = [a if isinstance(a, (int, float)) else a.end for a in new_args] return interval(min(start_array), min(end_array)) def imax(*args): """Evaluates the maximum of a list of intervals""" np = import_module('numpy') if not all(isinstance(arg, (int, float, interval)) for arg in args): return NotImplementedError else: new_args = [a for a in args if isinstance(a, (int, float)) or a.is_valid] if len(new_args) == 0: if all(a.is_valid is False for a in args): return interval(-np.inf, np.inf, is_valid=False) else: return interval(-np.inf, np.inf, is_valid=None) start_array = [a if isinstance(a, (int, float)) else a.start for a in new_args] end_array = [a if isinstance(a, (int, float)) else a.end for a in new_args] return interval(max(start_array), max(end_array)) #Monotonic def sinh(x): """Evaluates the hyperbolic sine of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.sinh(x), np.sinh(x)) elif isinstance(x, interval): return interval(np.sinh(x.start), np.sinh(x.end), is_valid=x.is_valid) else: raise NotImplementedError def cosh(x): """Evaluates the hyperbolic cos of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.cosh(x), np.cosh(x)) elif isinstance(x, interval): #both signs if x.start < 0 and x.end > 0: end = max(np.cosh(x.start), np.cosh(x.end)) return interval(1, end, is_valid=x.is_valid) else: #Monotonic start = np.cosh(x.start) end = np.cosh(x.end) return interval(start, end, is_valid=x.is_valid) else: raise NotImplementedError #Monotonic def tanh(x): """Evaluates the hyperbolic tan of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.tanh(x), np.tanh(x)) elif isinstance(x, interval): return interval(np.tanh(x.start), np.tanh(x.end), is_valid=x.is_valid) else: raise NotImplementedError def asin(x): """Evaluates the inverse sine of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): #Outside the domain if abs(x) > 1: return interval(-np.inf, np.inf, is_valid=False) else: return interval(np.arcsin(x), np.arcsin(x)) elif isinstance(x, interval): #Outside the domain if x.is_valid is False or x.start > 1 or x.end < -1: return interval(-np.inf, np.inf, is_valid=False) #Partially outside the domain elif x.start < -1 or x.end > 1: return interval(-np.inf, np.inf, is_valid=None) else: start = np.arcsin(x.start) end = np.arcsin(x.end) return interval(start, end, is_valid=x.is_valid) def acos(x): """Evaluates the inverse cos of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): if abs(x) > 1: #Outside the domain return interval(-np.inf, np.inf, is_valid=False) else: return interval(np.arccos(x), np.arccos(x)) elif isinstance(x, interval): #Outside the domain if x.is_valid is False or x.start > 1 or x.end < -1: return interval(-np.inf, np.inf, is_valid=False) #Partially outside the domain elif x.start < -1 or x.end > 1: return interval(-np.inf, np.inf, is_valid=None) else: start = np.arccos(x.start) end = np.arccos(x.end) return interval(start, end, is_valid=x.is_valid) def ceil(x): """Evaluates the ceiling of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.ceil(x)) elif isinstance(x, interval): if x.is_valid is False: return interval(-np.inf, np.inf, is_valid=False) else: start = np.ceil(x.start) end = np.ceil(x.end) #Continuous over the interval if start == end: return interval(start, end, is_valid=x.is_valid) else: #Not continuous over the interval return interval(start, end, is_valid=None) else: return NotImplementedError def floor(x): """Evaluates the floor of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.floor(x)) elif isinstance(x, interval): if x.is_valid is False: return interval(-np.inf, np.inf, is_valid=False) else: start = np.floor(x.start) end = np.floor(x.end) #continuous over the argument if start == end: return interval(start, end, is_valid=x.is_valid) else: #not continuous over the interval return interval(start, end, is_valid=None) else: return NotImplementedError def acosh(x): """Evaluates the inverse hyperbolic cosine of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): #Outside the domain if x < 1: return interval(-np.inf, np.inf, is_valid=False) else: return interval(np.arccosh(x)) elif isinstance(x, interval): #Outside the domain if x.end < 1: return interval(-np.inf, np.inf, is_valid=False) #Partly outside the domain elif x.start < 1: return interval(-np.inf, np.inf, is_valid=None) else: start = np.arccosh(x.start) end = np.arccosh(x.end) return interval(start, end, is_valid=x.is_valid) else: return NotImplementedError #Monotonic def asinh(x): """Evaluates the inverse hyperbolic sine of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): return interval(np.arcsinh(x)) elif isinstance(x, interval): start = np.arcsinh(x.start) end = np.arcsinh(x.end) return interval(start, end, is_valid=x.is_valid) else: return NotImplementedError def atanh(x): """Evaluates the inverse hyperbolic tangent of an interval""" np = import_module('numpy') if isinstance(x, (int, float)): #Outside the domain if abs(x) >= 1: return interval(-np.inf, np.inf, is_valid=False) else: return interval(np.arctanh(x)) elif isinstance(x, interval): #outside the domain if x.is_valid is False or x.start >= 1 or x.end <= -1: return interval(-np.inf, np.inf, is_valid=False) #partly outside the domain elif x.start <= -1 or x.end >= 1: return interval(-np.inf, np.inf, is_valid=None) else: start = np.arctanh(x.start) end = np.arctanh(x.end) return interval(start, end, is_valid=x.is_valid) else: return NotImplementedError #Three valued logic for interval plotting. def And(*args): """Defines the three valued ``And`` behaviour for a 2-tuple of three valued logic values""" def reduce_and(cmp_intervala, cmp_intervalb): if cmp_intervala[0] is False or cmp_intervalb[0] is False: first = False elif cmp_intervala[0] is None or cmp_intervalb[0] is None: first = None else: first = True if cmp_intervala[1] is False or cmp_intervalb[1] is False: second = False elif cmp_intervala[1] is None or cmp_intervalb[1] is None: second = None else: second = True return (first, second) return reduce(reduce_and, args) def Or(*args): """Defines the three valued ``Or`` behaviour for a 2-tuple of three valued logic values""" def reduce_or(cmp_intervala, cmp_intervalb): if cmp_intervala[0] is True or cmp_intervalb[0] is True: first = True elif cmp_intervala[0] is None or cmp_intervalb[0] is None: first = None else: first = False if cmp_intervala[1] is True or cmp_intervalb[1] is True: second = True elif cmp_intervala[1] is None or cmp_intervalb[1] is None: second = None else: second = False return (first, second) return reduce(reduce_or, args) sympy-sympy-1.9/sympy/plotting/intervalmath/tests/000077500000000000000000000000001412543434000226045ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/intervalmath/tests/__init__.py000066400000000000000000000000001412543434000247030ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/intervalmath/tests/test_interval_functions.py000066400000000000000000000232061412543434000301340ustar00rootroot00000000000000from sympy.external import import_module from sympy.plotting.intervalmath import ( Abs, acos, acosh, And, asin, asinh, atan, atanh, ceil, cos, cosh, exp, floor, imax, imin, interval, log, log10, Or, sin, sinh, sqrt, tan, tanh, ) np = import_module('numpy') if not np: disabled = True #requires Numpy. Hence included in interval_functions def test_interval_pow(): a = 2**interval(1, 2) == interval(2, 4) assert a == (True, True) a = interval(1, 2)**interval(1, 2) == interval(1, 4) assert a == (True, True) a = interval(-1, 1)**interval(0.5, 2) assert a.is_valid is None a = interval(-2, -1) ** interval(1, 2) assert a.is_valid is False a = interval(-2, -1) ** (1.0 / 2) assert a.is_valid is False a = interval(-1, 1)**(1.0 / 2) assert a.is_valid is None a = interval(-1, 1)**(1.0 / 3) == interval(-1, 1) assert a == (True, True) a = interval(-1, 1)**2 == interval(0, 1) assert a == (True, True) a = interval(-1, 1) ** (1.0 / 29) == interval(-1, 1) assert a == (True, True) a = -2**interval(1, 1) == interval(-2, -2) assert a == (True, True) a = interval(1, 2, is_valid=False)**2 assert a.is_valid is False a = (-3)**interval(1, 2) assert a.is_valid is False a = (-4)**interval(0.5, 0.5) assert a.is_valid is False assert ((-3)**interval(1, 1) == interval(-3, -3)) == (True, True) a = interval(8, 64)**(2.0 / 3) assert abs(a.start - 4) < 1e-10 # eps assert abs(a.end - 16) < 1e-10 a = interval(-8, 64)**(2.0 / 3) assert abs(a.start - 4) < 1e-10 # eps assert abs(a.end - 16) < 1e-10 def test_exp(): a = exp(interval(-np.inf, 0)) assert a.start == np.exp(-np.inf) assert a.end == np.exp(0) a = exp(interval(1, 2)) assert a.start == np.exp(1) assert a.end == np.exp(2) a = exp(1) assert a.start == np.exp(1) assert a.end == np.exp(1) def test_log(): a = log(interval(1, 2)) assert a.start == 0 assert a.end == np.log(2) a = log(interval(-1, 1)) assert a.is_valid is None a = log(interval(-3, -1)) assert a.is_valid is False a = log(-3) assert a.is_valid is False a = log(2) assert a.start == np.log(2) assert a.end == np.log(2) def test_log10(): a = log10(interval(1, 2)) assert a.start == 0 assert a.end == np.log10(2) a = log10(interval(-1, 1)) assert a.is_valid is None a = log10(interval(-3, -1)) assert a.is_valid is False a = log10(-3) assert a.is_valid is False a = log10(2) assert a.start == np.log10(2) assert a.end == np.log10(2) def test_atan(): a = atan(interval(0, 1)) assert a.start == np.arctan(0) assert a.end == np.arctan(1) a = atan(1) assert a.start == np.arctan(1) assert a.end == np.arctan(1) def test_sin(): a = sin(interval(0, np.pi / 4)) assert a.start == np.sin(0) assert a.end == np.sin(np.pi / 4) a = sin(interval(-np.pi / 4, np.pi / 4)) assert a.start == np.sin(-np.pi / 4) assert a.end == np.sin(np.pi / 4) a = sin(interval(np.pi / 4, 3 * np.pi / 4)) assert a.start == np.sin(np.pi / 4) assert a.end == 1 a = sin(interval(7 * np.pi / 6, 7 * np.pi / 4)) assert a.start == -1 assert a.end == np.sin(7 * np.pi / 6) a = sin(interval(0, 3 * np.pi)) assert a.start == -1 assert a.end == 1 a = sin(interval(np.pi / 3, 7 * np.pi / 4)) assert a.start == -1 assert a.end == 1 a = sin(np.pi / 4) assert a.start == np.sin(np.pi / 4) assert a.end == np.sin(np.pi / 4) a = sin(interval(1, 2, is_valid=False)) assert a.is_valid is False def test_cos(): a = cos(interval(0, np.pi / 4)) assert a.start == np.cos(np.pi / 4) assert a.end == 1 a = cos(interval(-np.pi / 4, np.pi / 4)) assert a.start == np.cos(-np.pi / 4) assert a.end == 1 a = cos(interval(np.pi / 4, 3 * np.pi / 4)) assert a.start == np.cos(3 * np.pi / 4) assert a.end == np.cos(np.pi / 4) a = cos(interval(3 * np.pi / 4, 5 * np.pi / 4)) assert a.start == -1 assert a.end == np.cos(3 * np.pi / 4) a = cos(interval(0, 3 * np.pi)) assert a.start == -1 assert a.end == 1 a = cos(interval(- np.pi / 3, 5 * np.pi / 4)) assert a.start == -1 assert a.end == 1 a = cos(interval(1, 2, is_valid=False)) assert a.is_valid is False def test_tan(): a = tan(interval(0, np.pi / 4)) assert a.start == 0 # must match lib_interval definition of tan: assert a.end == np.sin(np.pi / 4)/np.cos(np.pi / 4) a = tan(interval(np.pi / 4, 3 * np.pi / 4)) #discontinuity assert a.is_valid is None def test_sqrt(): a = sqrt(interval(1, 4)) assert a.start == 1 assert a.end == 2 a = sqrt(interval(0.01, 1)) assert a.start == np.sqrt(0.01) assert a.end == 1 a = sqrt(interval(-1, 1)) assert a.is_valid is None a = sqrt(interval(-3, -1)) assert a.is_valid is False a = sqrt(4) assert (a == interval(2, 2)) == (True, True) a = sqrt(-3) assert a.is_valid is False def test_imin(): a = imin(interval(1, 3), interval(2, 5), interval(-1, 3)) assert a.start == -1 assert a.end == 3 a = imin(-2, interval(1, 4)) assert a.start == -2 assert a.end == -2 a = imin(5, interval(3, 4), interval(-2, 2, is_valid=False)) assert a.start == 3 assert a.end == 4 def test_imax(): a = imax(interval(-2, 2), interval(2, 7), interval(-3, 9)) assert a.start == 2 assert a.end == 9 a = imax(8, interval(1, 4)) assert a.start == 8 assert a.end == 8 a = imax(interval(1, 2), interval(3, 4), interval(-2, 2, is_valid=False)) assert a.start == 3 assert a.end == 4 def test_sinh(): a = sinh(interval(-1, 1)) assert a.start == np.sinh(-1) assert a.end == np.sinh(1) a = sinh(1) assert a.start == np.sinh(1) assert a.end == np.sinh(1) def test_cosh(): a = cosh(interval(1, 2)) assert a.start == np.cosh(1) assert a.end == np.cosh(2) a = cosh(interval(-2, -1)) assert a.start == np.cosh(-1) assert a.end == np.cosh(-2) a = cosh(interval(-2, 1)) assert a.start == 1 assert a.end == np.cosh(-2) a = cosh(1) assert a.start == np.cosh(1) assert a.end == np.cosh(1) def test_tanh(): a = tanh(interval(-3, 3)) assert a.start == np.tanh(-3) assert a.end == np.tanh(3) a = tanh(3) assert a.start == np.tanh(3) assert a.end == np.tanh(3) def test_asin(): a = asin(interval(-0.5, 0.5)) assert a.start == np.arcsin(-0.5) assert a.end == np.arcsin(0.5) a = asin(interval(-1.5, 1.5)) assert a.is_valid is None a = asin(interval(-2, -1.5)) assert a.is_valid is False a = asin(interval(0, 2)) assert a.is_valid is None a = asin(interval(2, 5)) assert a.is_valid is False a = asin(0.5) assert a.start == np.arcsin(0.5) assert a.end == np.arcsin(0.5) a = asin(1.5) assert a.is_valid is False def test_acos(): a = acos(interval(-0.5, 0.5)) assert a.start == np.arccos(0.5) assert a.end == np.arccos(-0.5) a = acos(interval(-1.5, 1.5)) assert a.is_valid is None a = acos(interval(-2, -1.5)) assert a.is_valid is False a = acos(interval(0, 2)) assert a.is_valid is None a = acos(interval(2, 5)) assert a.is_valid is False a = acos(0.5) assert a.start == np.arccos(0.5) assert a.end == np.arccos(0.5) a = acos(1.5) assert a.is_valid is False def test_ceil(): a = ceil(interval(0.2, 0.5)) assert a.start == 1 assert a.end == 1 a = ceil(interval(0.5, 1.5)) assert a.start == 1 assert a.end == 2 assert a.is_valid is None a = ceil(interval(-5, 5)) assert a.is_valid is None a = ceil(5.4) assert a.start == 6 assert a.end == 6 def test_floor(): a = floor(interval(0.2, 0.5)) assert a.start == 0 assert a.end == 0 a = floor(interval(0.5, 1.5)) assert a.start == 0 assert a.end == 1 assert a.is_valid is None a = floor(interval(-5, 5)) assert a.is_valid is None a = floor(5.4) assert a.start == 5 assert a.end == 5 def test_asinh(): a = asinh(interval(1, 2)) assert a.start == np.arcsinh(1) assert a.end == np.arcsinh(2) a = asinh(0.5) assert a.start == np.arcsinh(0.5) assert a.end == np.arcsinh(0.5) def test_acosh(): a = acosh(interval(3, 5)) assert a.start == np.arccosh(3) assert a.end == np.arccosh(5) a = acosh(interval(0, 3)) assert a.is_valid is None a = acosh(interval(-3, 0.5)) assert a.is_valid is False a = acosh(0.5) assert a.is_valid is False a = acosh(2) assert a.start == np.arccosh(2) assert a.end == np.arccosh(2) def test_atanh(): a = atanh(interval(-0.5, 0.5)) assert a.start == np.arctanh(-0.5) assert a.end == np.arctanh(0.5) a = atanh(interval(0, 3)) assert a.is_valid is None a = atanh(interval(-3, -2)) assert a.is_valid is False a = atanh(0.5) assert a.start == np.arctanh(0.5) assert a.end == np.arctanh(0.5) a = atanh(1.5) assert a.is_valid is False def test_Abs(): assert (Abs(interval(-0.5, 0.5)) == interval(0, 0.5)) == (True, True) assert (Abs(interval(-3, -2)) == interval(2, 3)) == (True, True) assert (Abs(-3) == interval(3, 3)) == (True, True) def test_And(): args = [(True, True), (True, False), (True, None)] assert And(*args) == (True, False) args = [(False, True), (None, None), (True, True)] assert And(*args) == (False, None) def test_Or(): args = [(True, True), (True, False), (False, None)] assert Or(*args) == (True, True) args = [(None, None), (False, None), (False, False)] assert Or(*args) == (None, None) sympy-sympy-1.9/sympy/plotting/intervalmath/tests/test_interval_membership.py000066400000000000000000000101701412543434000302530ustar00rootroot00000000000000from sympy.core.symbol import Symbol from sympy.plotting.intervalmath import interval from sympy.plotting.intervalmath.interval_membership import intervalMembership from sympy.plotting.experimental_lambdify import experimental_lambdify from sympy.testing.pytest import raises def test_creation(): assert intervalMembership(True, True) raises(TypeError, lambda: intervalMembership(True)) raises(TypeError, lambda: intervalMembership(True, True, True)) def test_getitem(): a = intervalMembership(True, False) assert a[0] is True assert a[1] is False raises(IndexError, lambda: a[2]) def test_str(): a = intervalMembership(True, False) assert str(a) == 'intervalMembership(True, False)' assert repr(a) == 'intervalMembership(True, False)' def test_equivalence(): a = intervalMembership(True, True) b = intervalMembership(True, False) assert (a == b) is False assert (a != b) is True a = intervalMembership(True, False) b = intervalMembership(True, False) assert (a == b) is True assert (a != b) is False def test_not(): x = Symbol('x') r1 = x > -1 r2 = x <= -1 i = interval f1 = experimental_lambdify((x,), r1) f2 = experimental_lambdify((x,), r2) tt = i(-0.1, 0.1, is_valid=True) tn = i(-0.1, 0.1, is_valid=None) tf = i(-0.1, 0.1, is_valid=False) assert f1(tt) == ~f2(tt) assert f1(tn) == ~f2(tn) assert f1(tf) == ~f2(tf) nt = i(0.9, 1.1, is_valid=True) nn = i(0.9, 1.1, is_valid=None) nf = i(0.9, 1.1, is_valid=False) assert f1(nt) == ~f2(nt) assert f1(nn) == ~f2(nn) assert f1(nf) == ~f2(nf) ft = i(1.9, 2.1, is_valid=True) fn = i(1.9, 2.1, is_valid=None) ff = i(1.9, 2.1, is_valid=False) assert f1(ft) == ~f2(ft) assert f1(fn) == ~f2(fn) assert f1(ff) == ~f2(ff) def test_boolean(): # There can be 9*9 test cases in full mapping of the cartesian product. # But we only consider 3*3 cases for simplicity. s = [ intervalMembership(False, False), intervalMembership(None, None), intervalMembership(True, True) ] # Reduced tests for 'And' a1 = [ intervalMembership(False, False), intervalMembership(False, False), intervalMembership(False, False), intervalMembership(False, False), intervalMembership(None, None), intervalMembership(None, None), intervalMembership(False, False), intervalMembership(None, None), intervalMembership(True, True) ] a1_iter = iter(a1) for i in range(len(s)): for j in range(len(s)): assert s[i] & s[j] == next(a1_iter) # Reduced tests for 'Or' a1 = [ intervalMembership(False, False), intervalMembership(None, False), intervalMembership(True, False), intervalMembership(None, False), intervalMembership(None, None), intervalMembership(True, None), intervalMembership(True, False), intervalMembership(True, None), intervalMembership(True, True) ] a1_iter = iter(a1) for i in range(len(s)): for j in range(len(s)): assert s[i] | s[j] == next(a1_iter) # Reduced tests for 'Xor' a1 = [ intervalMembership(False, False), intervalMembership(None, False), intervalMembership(True, False), intervalMembership(None, False), intervalMembership(None, None), intervalMembership(None, None), intervalMembership(True, False), intervalMembership(None, None), intervalMembership(False, True) ] a1_iter = iter(a1) for i in range(len(s)): for j in range(len(s)): assert s[i] ^ s[j] == next(a1_iter) # Reduced tests for 'Not' a1 = [ intervalMembership(True, False), intervalMembership(None, None), intervalMembership(False, True) ] a1_iter = iter(a1) for i in range(len(s)): assert ~s[i] == next(a1_iter) def test_boolean_errors(): a = intervalMembership(True, True) raises(ValueError, lambda: a & 1) raises(ValueError, lambda: a | 1) raises(ValueError, lambda: a ^ 1) sympy-sympy-1.9/sympy/plotting/intervalmath/tests/test_intervalmath.py000066400000000000000000000215121412543434000267140ustar00rootroot00000000000000from sympy.plotting.intervalmath import interval from sympy.testing.pytest import raises def test_interval(): assert (interval(1, 1) == interval(1, 1, is_valid=True)) == (True, True) assert (interval(1, 1) == interval(1, 1, is_valid=False)) == (True, False) assert (interval(1, 1) == interval(1, 1, is_valid=None)) == (True, None) assert (interval(1, 1.5) == interval(1, 2)) == (None, True) assert (interval(0, 1) == interval(2, 3)) == (False, True) assert (interval(0, 1) == interval(1, 2)) == (None, True) assert (interval(1, 2) != interval(1, 2)) == (False, True) assert (interval(1, 3) != interval(2, 3)) == (None, True) assert (interval(1, 3) != interval(-5, -3)) == (True, True) assert ( interval(1, 3, is_valid=False) != interval(-5, -3)) == (True, False) assert (interval(1, 3, is_valid=None) != interval(-5, 3)) == (None, None) assert (interval(4, 4) != 4) == (False, True) assert (interval(1, 1) == 1) == (True, True) assert (interval(1, 3, is_valid=False) == interval(1, 3)) == (True, False) assert (interval(1, 3, is_valid=None) == interval(1, 3)) == (True, None) inter = interval(-5, 5) assert (interval(inter) == interval(-5, 5)) == (True, True) assert inter.width == 10 assert 0 in inter assert -5 in inter assert 5 in inter assert interval(0, 3) in inter assert interval(-6, 2) not in inter assert -5.05 not in inter assert 5.3 not in inter interb = interval(-float('inf'), float('inf')) assert 0 in inter assert inter in interb assert interval(0, float('inf')) in interb assert interval(-float('inf'), 5) in interb assert interval(-1e50, 1e50) in interb assert ( -interval(-1, -2, is_valid=False) == interval(1, 2)) == (True, False) raises(ValueError, lambda: interval(1, 2, 3)) def test_interval_add(): assert (interval(1, 2) + interval(2, 3) == interval(3, 5)) == (True, True) assert (1 + interval(1, 2) == interval(2, 3)) == (True, True) assert (interval(1, 2) + 1 == interval(2, 3)) == (True, True) compare = (1 + interval(0, float('inf')) == interval(1, float('inf'))) assert compare == (True, True) a = 1 + interval(2, 5, is_valid=False) assert a.is_valid is False a = 1 + interval(2, 5, is_valid=None) assert a.is_valid is None a = interval(2, 5, is_valid=False) + interval(3, 5, is_valid=None) assert a.is_valid is False a = interval(3, 5) + interval(-1, 1, is_valid=None) assert a.is_valid is None a = interval(2, 5, is_valid=False) + 1 assert a.is_valid is False def test_interval_sub(): assert (interval(1, 2) - interval(1, 5) == interval(-4, 1)) == (True, True) assert (interval(1, 2) - 1 == interval(0, 1)) == (True, True) assert (1 - interval(1, 2) == interval(-1, 0)) == (True, True) a = 1 - interval(1, 2, is_valid=False) assert a.is_valid is False a = interval(1, 4, is_valid=None) - 1 assert a.is_valid is None a = interval(1, 3, is_valid=False) - interval(1, 3) assert a.is_valid is False a = interval(1, 3, is_valid=None) - interval(1, 3) assert a.is_valid is None def test_interval_inequality(): assert (interval(1, 2) < interval(3, 4)) == (True, True) assert (interval(1, 2) < interval(2, 4)) == (None, True) assert (interval(1, 2) < interval(-2, 0)) == (False, True) assert (interval(1, 2) <= interval(2, 4)) == (True, True) assert (interval(1, 2) <= interval(1.5, 6)) == (None, True) assert (interval(2, 3) <= interval(1, 2)) == (None, True) assert (interval(2, 3) <= interval(1, 1.5)) == (False, True) assert ( interval(1, 2, is_valid=False) <= interval(-2, 0)) == (False, False) assert (interval(1, 2, is_valid=None) <= interval(-2, 0)) == (False, None) assert (interval(1, 2) <= 1.5) == (None, True) assert (interval(1, 2) <= 3) == (True, True) assert (interval(1, 2) <= 0) == (False, True) assert (interval(5, 8) > interval(2, 3)) == (True, True) assert (interval(2, 5) > interval(1, 3)) == (None, True) assert (interval(2, 3) > interval(3.1, 5)) == (False, True) assert (interval(-1, 1) == 0) == (None, True) assert (interval(-1, 1) == 2) == (False, True) assert (interval(-1, 1) != 0) == (None, True) assert (interval(-1, 1) != 2) == (True, True) assert (interval(3, 5) > 2) == (True, True) assert (interval(3, 5) < 2) == (False, True) assert (interval(1, 5) < 2) == (None, True) assert (interval(1, 5) > 2) == (None, True) assert (interval(0, 1) > 2) == (False, True) assert (interval(1, 2) >= interval(0, 1)) == (True, True) assert (interval(1, 2) >= interval(0, 1.5)) == (None, True) assert (interval(1, 2) >= interval(3, 4)) == (False, True) assert (interval(1, 2) >= 0) == (True, True) assert (interval(1, 2) >= 1.2) == (None, True) assert (interval(1, 2) >= 3) == (False, True) assert (2 > interval(0, 1)) == (True, True) a = interval(-1, 1, is_valid=False) < interval(2, 5, is_valid=None) assert a == (True, False) a = interval(-1, 1, is_valid=None) < interval(2, 5, is_valid=False) assert a == (True, False) a = interval(-1, 1, is_valid=None) < interval(2, 5, is_valid=None) assert a == (True, None) a = interval(-1, 1, is_valid=False) > interval(-5, -2, is_valid=None) assert a == (True, False) a = interval(-1, 1, is_valid=None) > interval(-5, -2, is_valid=False) assert a == (True, False) a = interval(-1, 1, is_valid=None) > interval(-5, -2, is_valid=None) assert a == (True, None) def test_interval_mul(): assert ( interval(1, 5) * interval(2, 10) == interval(2, 50)) == (True, True) a = interval(-1, 1) * interval(2, 10) == interval(-10, 10) assert a == (True, True) a = interval(-1, 1) * interval(-5, 3) == interval(-5, 5) assert a == (True, True) assert (interval(1, 3) * 2 == interval(2, 6)) == (True, True) assert (3 * interval(-1, 2) == interval(-3, 6)) == (True, True) a = 3 * interval(1, 2, is_valid=False) assert a.is_valid is False a = 3 * interval(1, 2, is_valid=None) assert a.is_valid is None a = interval(1, 5, is_valid=False) * interval(1, 2, is_valid=None) assert a.is_valid is False def test_interval_div(): div = interval(1, 2, is_valid=False) / 3 assert div == interval(-float('inf'), float('inf'), is_valid=False) div = interval(1, 2, is_valid=None) / 3 assert div == interval(-float('inf'), float('inf'), is_valid=None) div = 3 / interval(1, 2, is_valid=None) assert div == interval(-float('inf'), float('inf'), is_valid=None) a = interval(1, 2) / 0 assert a.is_valid is False a = interval(0.5, 1) / interval(-1, 0) assert a.is_valid is None a = interval(0, 1) / interval(0, 1) assert a.is_valid is None a = interval(-1, 1) / interval(-1, 1) assert a.is_valid is None a = interval(-1, 2) / interval(0.5, 1) == interval(-2.0, 4.0) assert a == (True, True) a = interval(0, 1) / interval(0.5, 1) == interval(0.0, 2.0) assert a == (True, True) a = interval(-1, 0) / interval(0.5, 1) == interval(-2.0, 0.0) assert a == (True, True) a = interval(-0.5, -0.25) / interval(0.5, 1) == interval(-1.0, -0.25) assert a == (True, True) a = interval(0.5, 1) / interval(0.5, 1) == interval(0.5, 2.0) assert a == (True, True) a = interval(0.5, 4) / interval(0.5, 1) == interval(0.5, 8.0) assert a == (True, True) a = interval(-1, -0.5) / interval(0.5, 1) == interval(-2.0, -0.5) assert a == (True, True) a = interval(-4, -0.5) / interval(0.5, 1) == interval(-8.0, -0.5) assert a == (True, True) a = interval(-1, 2) / interval(-2, -0.5) == interval(-4.0, 2.0) assert a == (True, True) a = interval(0, 1) / interval(-2, -0.5) == interval(-2.0, 0.0) assert a == (True, True) a = interval(-1, 0) / interval(-2, -0.5) == interval(0.0, 2.0) assert a == (True, True) a = interval(-0.5, -0.25) / interval(-2, -0.5) == interval(0.125, 1.0) assert a == (True, True) a = interval(0.5, 1) / interval(-2, -0.5) == interval(-2.0, -0.25) assert a == (True, True) a = interval(0.5, 4) / interval(-2, -0.5) == interval(-8.0, -0.25) assert a == (True, True) a = interval(-1, -0.5) / interval(-2, -0.5) == interval(0.25, 2.0) assert a == (True, True) a = interval(-4, -0.5) / interval(-2, -0.5) == interval(0.25, 8.0) assert a == (True, True) a = interval(-5, 5, is_valid=False) / 2 assert a.is_valid is False def test_hashable(): ''' test that interval objects are hashable. this is required in order to be able to put them into the cache, which appears to be necessary for plotting in py3k. For details, see: https://github.com/sympy/sympy/pull/2101 https://github.com/sympy/sympy/issues/6533 ''' hash(interval(1, 1)) hash(interval(1, 1, is_valid=True)) hash(interval(-4, -0.5)) hash(interval(-2, -0.5)) hash(interval(0.25, 8.0)) sympy-sympy-1.9/sympy/plotting/plot.py000066400000000000000000002613001412543434000202760ustar00rootroot00000000000000"""Plotting module for Sympy. A plot is represented by the ``Plot`` class that contains a reference to the backend and a list of the data series to be plotted. The data series are instances of classes meant to simplify getting points and meshes from sympy expressions. ``plot_backends`` is a dictionary with all the backends. This module gives only the essential. For all the fancy stuff use directly the backend. You can get the backend wrapper for every plot from the ``_backend`` attribute. Moreover the data series classes have various useful methods like ``get_points``, ``get_meshes``, etc, that may be useful if you wish to use another plotting library. Especially if you need publication ready graphs and this module is not enough for you - just get the ``_backend`` attribute and add whatever you want directly to it. In the case of matplotlib (the common way to graph data in python) just copy ``_backend.fig`` which is the figure and ``_backend.ax`` which is the axis and work on them as you would on any other matplotlib object. Simplicity of code takes much greater importance than performance. Don't use it if you care at all about performance. A new backend instance is initialized every time you call ``show()`` and the old one is left to the garbage collector. """ from collections.abc import Callable from sympy import sympify, Expr, Tuple, Dummy, Symbol from sympy.external import import_module from sympy.core.function import arity from sympy.utilities.iterables import is_sequence from .experimental_lambdify import (vectorized_lambdify, lambdify) from sympy.utilities.exceptions import SymPyDeprecationWarning # N.B. # When changing the minimum module version for matplotlib, please change # the same in the `SymPyDocTestFinder`` in `sympy/testing/runtests.py` # Backend specific imports - textplot from sympy.plotting.textplot import textplot # Global variable # Set to False when running tests / doctests so that the plots don't show. _show = True def unset_show(): """ Disable show(). For use in the tests. """ global _show _show = False ############################################################################## # The public interface ############################################################################## class Plot: """The central class of the plotting module. Explanation =========== For interactive work the function ``plot`` is better suited. This class permits the plotting of sympy expressions using numerous backends (matplotlib, textplot, the old pyglet module for sympy, Google charts api, etc). The figure can contain an arbitrary number of plots of sympy expressions, lists of coordinates of points, etc. Plot has a private attribute _series that contains all data series to be plotted (expressions for lines or surfaces, lists of points, etc (all subclasses of BaseSeries)). Those data series are instances of classes not imported by ``from sympy import *``. The customization of the figure is on two levels. Global options that concern the figure as a whole (eg title, xlabel, scale, etc) and per-data series options (eg name) and aesthetics (eg. color, point shape, line type, etc.). The difference between options and aesthetics is that an aesthetic can be a function of the coordinates (or parameters in a parametric plot). The supported values for an aesthetic are: - None (the backend uses default values) - a constant - a function of one variable (the first coordinate or parameter) - a function of two variables (the first and second coordinate or parameters) - a function of three variables (only in nonparametric 3D plots) Their implementation depends on the backend so they may not work in some backends. If the plot is parametric and the arity of the aesthetic function permits it the aesthetic is calculated over parameters and not over coordinates. If the arity does not permit calculation over parameters the calculation is done over coordinates. Only cartesian coordinates are supported for the moment, but you can use the parametric plots to plot in polar, spherical and cylindrical coordinates. The arguments for the constructor Plot must be subclasses of BaseSeries. Any global option can be specified as a keyword argument. The global options for a figure are: - title : str - xlabel : str - ylabel : str - zlabel : str - legend : bool - xscale : {'linear', 'log'} - yscale : {'linear', 'log'} - axis : bool - axis_center : tuple of two floats or {'center', 'auto'} - xlim : tuple of two floats - ylim : tuple of two floats - aspect_ratio : tuple of two floats or {'auto'} - autoscale : bool - margin : float in [0, 1] - backend : {'default', 'matplotlib', 'text'} or a subclass of BaseBackend - size : optional tuple of two floats, (width, height); default: None The per data series options and aesthetics are: There are none in the base series. See below for options for subclasses. Some data series support additional aesthetics or options: ListSeries, LineOver1DRangeSeries, Parametric2DLineSeries, Parametric3DLineSeries support the following: Aesthetics: - line_color : string, or float, or function, optional Specifies the color for the plot, which depends on the backend being used. For example, if ``MatplotlibBackend`` is being used, then Matplotlib string colors are acceptable ("red", "r", "cyan", "c", ...). Alternatively, we can use a float number `0 < color < 1` wrapped in a string (for example, `line_color="0.5"`) to specify grayscale colors. Alternatively, We can specify a function returning a single float value: this will be used to apply a color-loop (for example, `line_color=lambda x: math.cos(x)`). Note that by setting line_color, it would be applied simultaneously to all the series. options: - label : str - steps : bool - integers_only : bool SurfaceOver2DRangeSeries, ParametricSurfaceSeries support the following: aesthetics: - surface_color : function which returns a float. """ def __init__(self, *args, title=None, xlabel=None, ylabel=None, zlabel=None, aspect_ratio='auto', xlim=None, ylim=None, axis_center='auto', axis=True, xscale='linear', yscale='linear', legend=False, autoscale=True, margin=0, annotations=None, markers=None, rectangles=None, fill=None, backend='default', size=None, **kwargs): super().__init__() # Options for the graph as a whole. # The possible values for each option are described in the docstring of # Plot. They are based purely on convention, no checking is done. self.title = title self.xlabel = xlabel self.ylabel = ylabel self.zlabel = zlabel self.aspect_ratio = aspect_ratio self.axis_center = axis_center self.axis = axis self.xscale = xscale self.yscale = yscale self.legend = legend self.autoscale = autoscale self.margin = margin self.annotations = annotations self.markers = markers self.rectangles = rectangles self.fill = fill # Contains the data objects to be plotted. The backend should be smart # enough to iterate over this list. self._series = [] self._series.extend(args) # The backend type. On every show() a new backend instance is created # in self._backend which is tightly coupled to the Plot instance # (thanks to the parent attribute of the backend). if isinstance(backend, str): self.backend = plot_backends[backend] elif (type(backend) == type) and issubclass(backend, BaseBackend): self.backend = backend else: raise TypeError( "backend must be either a string or a subclass of BaseBackend") is_real = \ lambda lim: all(getattr(i, 'is_real', True) for i in lim) is_finite = \ lambda lim: all(getattr(i, 'is_finite', True) for i in lim) # reduce code repetition def check_and_set(t_name, t): if t: if not is_real(t): raise ValueError( "All numbers from {}={} must be real".format(t_name, t)) if not is_finite(t): raise ValueError( "All numbers from {}={} must be finite".format(t_name, t)) setattr(self, t_name, (float(t[0]), float(t[1]))) self.xlim = None check_and_set("xlim", xlim) self.ylim = None check_and_set("ylim", ylim) self.size = None check_and_set("size", size) def show(self): # TODO move this to the backend (also for save) if hasattr(self, '_backend'): self._backend.close() self._backend = self.backend(self) self._backend.show() def save(self, path): if hasattr(self, '_backend'): self._backend.close() self._backend = self.backend(self) self._backend.save(path) def __str__(self): series_strs = [('[%d]: ' % i) + str(s) for i, s in enumerate(self._series)] return 'Plot object containing:\n' + '\n'.join(series_strs) def __getitem__(self, index): return self._series[index] def __setitem__(self, index, *args): if len(args) == 1 and isinstance(args[0], BaseSeries): self._series[index] = args def __delitem__(self, index): del self._series[index] def append(self, arg): """Adds an element from a plot's series to an existing plot. Examples ======== Consider two ``Plot`` objects, ``p1`` and ``p2``. To add the second plot's first series object to the first, use the ``append`` method, like so: .. plot:: :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.plotting import plot >>> x = symbols('x') >>> p1 = plot(x*x, show=False) >>> p2 = plot(x, show=False) >>> p1.append(p2[0]) >>> p1 Plot object containing: [0]: cartesian line: x**2 for x over (-10.0, 10.0) [1]: cartesian line: x for x over (-10.0, 10.0) >>> p1.show() See Also ======== extend """ if isinstance(arg, BaseSeries): self._series.append(arg) else: raise TypeError('Must specify element of plot to append.') def extend(self, arg): """Adds all series from another plot. Examples ======== Consider two ``Plot`` objects, ``p1`` and ``p2``. To add the second plot to the first, use the ``extend`` method, like so: .. plot:: :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.plotting import plot >>> x = symbols('x') >>> p1 = plot(x**2, show=False) >>> p2 = plot(x, -x, show=False) >>> p1.extend(p2) >>> p1 Plot object containing: [0]: cartesian line: x**2 for x over (-10.0, 10.0) [1]: cartesian line: x for x over (-10.0, 10.0) [2]: cartesian line: -x for x over (-10.0, 10.0) >>> p1.show() """ if isinstance(arg, Plot): self._series.extend(arg._series) elif is_sequence(arg): self._series.extend(arg) else: raise TypeError('Expecting Plot or sequence of BaseSeries') class PlotGrid: """This class helps to plot subplots from already created sympy plots in a single figure. Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.plotting import plot, plot3d, PlotGrid >>> x, y = symbols('x, y') >>> p1 = plot(x, x**2, x**3, (x, -5, 5)) >>> p2 = plot((x**2, (x, -6, 6)), (x, (x, -5, 5))) >>> p3 = plot(x**3, (x, -5, 5)) >>> p4 = plot3d(x*y, (x, -5, 5), (y, -5, 5)) Plotting vertically in a single line: .. plot:: :context: close-figs :format: doctest :include-source: True >>> PlotGrid(2, 1 , p1, p2) PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: x for x over (-5.0, 5.0) [1]: cartesian line: x**2 for x over (-5.0, 5.0) [2]: cartesian line: x**3 for x over (-5.0, 5.0) Plot[1]:Plot object containing: [0]: cartesian line: x**2 for x over (-6.0, 6.0) [1]: cartesian line: x for x over (-5.0, 5.0) Plotting horizontally in a single line: .. plot:: :context: close-figs :format: doctest :include-source: True >>> PlotGrid(1, 3 , p2, p3, p4) PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: x**2 for x over (-6.0, 6.0) [1]: cartesian line: x for x over (-5.0, 5.0) Plot[1]:Plot object containing: [0]: cartesian line: x**3 for x over (-5.0, 5.0) Plot[2]:Plot object containing: [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) Plotting in a grid form: .. plot:: :context: close-figs :format: doctest :include-source: True >>> PlotGrid(2, 2, p1, p2 ,p3, p4) PlotGrid object containing: Plot[0]:Plot object containing: [0]: cartesian line: x for x over (-5.0, 5.0) [1]: cartesian line: x**2 for x over (-5.0, 5.0) [2]: cartesian line: x**3 for x over (-5.0, 5.0) Plot[1]:Plot object containing: [0]: cartesian line: x**2 for x over (-6.0, 6.0) [1]: cartesian line: x for x over (-5.0, 5.0) Plot[2]:Plot object containing: [0]: cartesian line: x**3 for x over (-5.0, 5.0) Plot[3]:Plot object containing: [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) """ def __init__(self, nrows, ncolumns, *args, show=True, size=None, **kwargs): """ Parameters ========== nrows : The number of rows that should be in the grid of the required subplot. ncolumns : The number of columns that should be in the grid of the required subplot. nrows and ncolumns together define the required grid. Arguments ========= A list of predefined plot objects entered in a row-wise sequence i.e. plot objects which are to be in the top row of the required grid are written first, then the second row objects and so on Keyword arguments ================= show : Boolean The default value is set to ``True``. Set show to ``False`` and the function will not display the subplot. The returned instance of the ``PlotGrid`` class can then be used to save or display the plot by calling the ``save()`` and ``show()`` methods respectively. size : (float, float), optional A tuple in the form (width, height) in inches to specify the size of the overall figure. The default value is set to ``None``, meaning the size will be set by the default backend. """ self.nrows = nrows self.ncolumns = ncolumns self._series = [] self.args = args for arg in args: self._series.append(arg._series) self.backend = DefaultBackend self.size = size if show: self.show() def show(self): if hasattr(self, '_backend'): self._backend.close() self._backend = self.backend(self) self._backend.show() def save(self, path): if hasattr(self, '_backend'): self._backend.close() self._backend = self.backend(self) self._backend.save(path) def __str__(self): plot_strs = [('Plot[%d]:' % i) + str(plot) for i, plot in enumerate(self.args)] return 'PlotGrid object containing:\n' + '\n'.join(plot_strs) ############################################################################## # Data Series ############################################################################## #TODO more general way to calculate aesthetics (see get_color_array) ### The base class for all series class BaseSeries: """Base class for the data objects containing stuff to be plotted. Explanation =========== The backend should check if it supports the data series that it's given. (eg TextBackend supports only LineOver1DRange). It's the backend responsibility to know how to use the class of data series that it's given. Some data series classes are grouped (using a class attribute like is_2Dline) according to the api they present (based only on convention). The backend is not obliged to use that api (eg. The LineOver1DRange belongs to the is_2Dline group and presents the get_points method, but the TextBackend does not use the get_points method). """ # Some flags follow. The rationale for using flags instead of checking base # classes is that setting multiple flags is simpler than multiple # inheritance. is_2Dline = False # Some of the backends expect: # - get_points returning 1D np.arrays list_x, list_y # - get_color_array returning 1D np.array (done in Line2DBaseSeries) # with the colors calculated at the points from get_points is_3Dline = False # Some of the backends expect: # - get_points returning 1D np.arrays list_x, list_y, list_y # - get_color_array returning 1D np.array (done in Line2DBaseSeries) # with the colors calculated at the points from get_points is_3Dsurface = False # Some of the backends expect: # - get_meshes returning mesh_x, mesh_y, mesh_z (2D np.arrays) # - get_points an alias for get_meshes is_contour = False # Some of the backends expect: # - get_meshes returning mesh_x, mesh_y, mesh_z (2D np.arrays) # - get_points an alias for get_meshes is_implicit = False # Some of the backends expect: # - get_meshes returning mesh_x (1D array), mesh_y(1D array, # mesh_z (2D np.arrays) # - get_points an alias for get_meshes # Different from is_contour as the colormap in backend will be # different is_parametric = False # The calculation of aesthetics expects: # - get_parameter_points returning one or two np.arrays (1D or 2D) # used for calculation aesthetics def __init__(self): super().__init__() @property def is_3D(self): flags3D = [ self.is_3Dline, self.is_3Dsurface ] return any(flags3D) @property def is_line(self): flagslines = [ self.is_2Dline, self.is_3Dline ] return any(flagslines) ### 2D lines class Line2DBaseSeries(BaseSeries): """A base class for 2D lines. - adding the label, steps and only_integers options - making is_2Dline true - defining get_segments and get_color_array """ is_2Dline = True _dim = 2 def __init__(self): super().__init__() self.label = None self.steps = False self.only_integers = False self.line_color = None def get_data(self): """ Return lists of coordinates for plotting the line. Returns ======= x: list List of x-coordinates y: list List of y-coordinates y: list List of z-coordinates in case of Parametric3DLineSeries """ np = import_module('numpy') points = self.get_points() if self.steps is True: if len(points) == 2: x = np.array((points[0], points[0])).T.flatten()[1:] y = np.array((points[1], points[1])).T.flatten()[:-1] points = (x, y) else: x = np.repeat(points[0], 3)[2:] y = np.repeat(points[1], 3)[:-2] z = np.repeat(points[2], 3)[1:-1] points = (x, y, z) return points def get_segments(self): SymPyDeprecationWarning( feature="get_segments", issue=21329, deprecated_since_version="1.9", useinstead="MatplotlibBackend.get_segments").warn() np = import_module('numpy') points = type(self).get_data(self) points = np.ma.array(points).T.reshape(-1, 1, self._dim) return np.ma.concatenate([points[:-1], points[1:]], axis=1) def get_color_array(self): np = import_module('numpy') c = self.line_color if hasattr(c, '__call__'): f = np.vectorize(c) nargs = arity(c) if nargs == 1 and self.is_parametric: x = self.get_parameter_points() return f(centers_of_segments(x)) else: variables = list(map(centers_of_segments, self.get_points())) if nargs == 1: return f(variables[0]) elif nargs == 2: return f(*variables[:2]) else: # only if the line is 3D (otherwise raises an error) return f(*variables) else: return c*np.ones(self.nb_of_points) class List2DSeries(Line2DBaseSeries): """Representation for a line consisting of list of points.""" def __init__(self, list_x, list_y): np = import_module('numpy') super().__init__() self.list_x = np.array(list_x) self.list_y = np.array(list_y) self.label = 'list' def __str__(self): return 'list plot' def get_points(self): return (self.list_x, self.list_y) class LineOver1DRangeSeries(Line2DBaseSeries): """Representation for a line consisting of a SymPy expression over a range.""" def __init__(self, expr, var_start_end, **kwargs): super().__init__() self.expr = sympify(expr) self.label = kwargs.get('label', None) or str(self.expr) self.var = sympify(var_start_end[0]) self.start = float(var_start_end[1]) self.end = float(var_start_end[2]) self.nb_of_points = kwargs.get('nb_of_points', 300) self.adaptive = kwargs.get('adaptive', True) self.depth = kwargs.get('depth', 12) self.line_color = kwargs.get('line_color', None) self.xscale = kwargs.get('xscale', 'linear') def __str__(self): return 'cartesian line: %s for %s over %s' % ( str(self.expr), str(self.var), str((self.start, self.end))) def get_points(self): """ Return lists of coordinates for plotting. Depending on the `adaptive` option, this function will either use an adaptive algorithm or it will uniformly sample the expression over the provided range. Returns ======= x: list List of x-coordinates y: list List of y-coordinates Explanation =========== The adaptive sampling is done by recursively checking if three points are almost collinear. If they are not collinear, then more points are added between those points. References ========== .. [1] Adaptive polygonal approximation of parametric curves, Luiz Henrique de Figueiredo. """ if self.only_integers or not self.adaptive: return self._uniform_sampling() else: f = lambdify([self.var], self.expr) x_coords = [] y_coords = [] np = import_module('numpy') def sample(p, q, depth): """ Samples recursively if three points are almost collinear. For depth < 6, points are added irrespective of whether they satisfy the collinearity condition or not. The maximum depth allowed is 12. """ # Randomly sample to avoid aliasing. random = 0.45 + np.random.rand() * 0.1 if self.xscale == 'log': xnew = 10**(np.log10(p[0]) + random * (np.log10(q[0]) - np.log10(p[0]))) else: xnew = p[0] + random * (q[0] - p[0]) ynew = f(xnew) new_point = np.array([xnew, ynew]) # Maximum depth if depth > self.depth: x_coords.append(q[0]) y_coords.append(q[1]) # Sample irrespective of whether the line is flat till the # depth of 6. We are not using linspace to avoid aliasing. elif depth < 6: sample(p, new_point, depth + 1) sample(new_point, q, depth + 1) # Sample ten points if complex values are encountered # at both ends. If there is a real value in between, then # sample those points further. elif p[1] is None and q[1] is None: if self.xscale == 'log': xarray = np.logspace(p[0], q[0], 10) else: xarray = np.linspace(p[0], q[0], 10) yarray = list(map(f, xarray)) if any(y is not None for y in yarray): for i in range(len(yarray) - 1): if yarray[i] is not None or yarray[i + 1] is not None: sample([xarray[i], yarray[i]], [xarray[i + 1], yarray[i + 1]], depth + 1) # Sample further if one of the end points in None (i.e. a # complex value) or the three points are not almost collinear. elif (p[1] is None or q[1] is None or new_point[1] is None or not flat(p, new_point, q)): sample(p, new_point, depth + 1) sample(new_point, q, depth + 1) else: x_coords.append(q[0]) y_coords.append(q[1]) f_start = f(self.start) f_end = f(self.end) x_coords.append(self.start) y_coords.append(f_start) sample(np.array([self.start, f_start]), np.array([self.end, f_end]), 0) return (x_coords, y_coords) def _uniform_sampling(self): np = import_module('numpy') if self.only_integers is True: if self.xscale == 'log': list_x = np.logspace(int(self.start), int(self.end), num=int(self.end) - int(self.start) + 1) else: list_x = np.linspace(int(self.start), int(self.end), num=int(self.end) - int(self.start) + 1) else: if self.xscale == 'log': list_x = np.logspace(self.start, self.end, num=self.nb_of_points) else: list_x = np.linspace(self.start, self.end, num=self.nb_of_points) f = vectorized_lambdify([self.var], self.expr) list_y = f(list_x) return (list_x, list_y) class Parametric2DLineSeries(Line2DBaseSeries): """Representation for a line consisting of two parametric sympy expressions over a range.""" is_parametric = True def __init__(self, expr_x, expr_y, var_start_end, **kwargs): super().__init__() self.expr_x = sympify(expr_x) self.expr_y = sympify(expr_y) self.label = kwargs.get('label', None) or \ "(%s, %s)" % (str(self.expr_x), str(self.expr_y)) self.var = sympify(var_start_end[0]) self.start = float(var_start_end[1]) self.end = float(var_start_end[2]) self.nb_of_points = kwargs.get('nb_of_points', 300) self.adaptive = kwargs.get('adaptive', True) self.depth = kwargs.get('depth', 12) self.line_color = kwargs.get('line_color', None) def __str__(self): return 'parametric cartesian line: (%s, %s) for %s over %s' % ( str(self.expr_x), str(self.expr_y), str(self.var), str((self.start, self.end))) def get_parameter_points(self): np = import_module('numpy') return np.linspace(self.start, self.end, num=self.nb_of_points) def _uniform_sampling(self): param = self.get_parameter_points() fx = vectorized_lambdify([self.var], self.expr_x) fy = vectorized_lambdify([self.var], self.expr_y) list_x = fx(param) list_y = fy(param) return (list_x, list_y) def get_points(self): """ Return lists of coordinates for plotting. Depending on the `adaptive` option, this function will either use an adaptive algorithm or it will uniformly sample the expression over the provided range. Returns ======= x: list List of x-coordinates y: list List of y-coordinates Explanation =========== The adaptive sampling is done by recursively checking if three points are almost collinear. If they are not collinear, then more points are added between those points. References ========== .. [1] Adaptive polygonal approximation of parametric curves, Luiz Henrique de Figueiredo. """ if not self.adaptive: return self._uniform_sampling() f_x = lambdify([self.var], self.expr_x) f_y = lambdify([self.var], self.expr_y) x_coords = [] y_coords = [] def sample(param_p, param_q, p, q, depth): """ Samples recursively if three points are almost collinear. For depth < 6, points are added irrespective of whether they satisfy the collinearity condition or not. The maximum depth allowed is 12. """ # Randomly sample to avoid aliasing. np = import_module('numpy') random = 0.45 + np.random.rand() * 0.1 param_new = param_p + random * (param_q - param_p) xnew = f_x(param_new) ynew = f_y(param_new) new_point = np.array([xnew, ynew]) # Maximum depth if depth > self.depth: x_coords.append(q[0]) y_coords.append(q[1]) # Sample irrespective of whether the line is flat till the # depth of 6. We are not using linspace to avoid aliasing. elif depth < 6: sample(param_p, param_new, p, new_point, depth + 1) sample(param_new, param_q, new_point, q, depth + 1) # Sample ten points if complex values are encountered # at both ends. If there is a real value in between, then # sample those points further. elif ((p[0] is None and q[1] is None) or (p[1] is None and q[1] is None)): param_array = np.linspace(param_p, param_q, 10) x_array = list(map(f_x, param_array)) y_array = list(map(f_y, param_array)) if any(x is not None and y is not None for x, y in zip(x_array, y_array)): for i in range(len(y_array) - 1): if ((x_array[i] is not None and y_array[i] is not None) or (x_array[i + 1] is not None and y_array[i + 1] is not None)): point_a = [x_array[i], y_array[i]] point_b = [x_array[i + 1], y_array[i + 1]] sample(param_array[i], param_array[i], point_a, point_b, depth + 1) # Sample further if one of the end points in None (i.e. a complex # value) or the three points are not almost collinear. elif (p[0] is None or p[1] is None or q[1] is None or q[0] is None or not flat(p, new_point, q)): sample(param_p, param_new, p, new_point, depth + 1) sample(param_new, param_q, new_point, q, depth + 1) else: x_coords.append(q[0]) y_coords.append(q[1]) f_start_x = f_x(self.start) f_start_y = f_y(self.start) start = [f_start_x, f_start_y] f_end_x = f_x(self.end) f_end_y = f_y(self.end) end = [f_end_x, f_end_y] x_coords.append(f_start_x) y_coords.append(f_start_y) sample(self.start, self.end, start, end, 0) return x_coords, y_coords ### 3D lines class Line3DBaseSeries(Line2DBaseSeries): """A base class for 3D lines. Most of the stuff is derived from Line2DBaseSeries.""" is_2Dline = False is_3Dline = True _dim = 3 def __init__(self): super().__init__() class Parametric3DLineSeries(Line3DBaseSeries): """Representation for a 3D line consisting of three parametric sympy expressions and a range.""" is_parametric = True def __init__(self, expr_x, expr_y, expr_z, var_start_end, **kwargs): super().__init__() self.expr_x = sympify(expr_x) self.expr_y = sympify(expr_y) self.expr_z = sympify(expr_z) self.label = kwargs.get('label', None) or \ "(%s, %s)" % (str(self.expr_x), str(self.expr_y)) self.var = sympify(var_start_end[0]) self.start = float(var_start_end[1]) self.end = float(var_start_end[2]) self.nb_of_points = kwargs.get('nb_of_points', 300) self.line_color = kwargs.get('line_color', None) def __str__(self): return '3D parametric cartesian line: (%s, %s, %s) for %s over %s' % ( str(self.expr_x), str(self.expr_y), str(self.expr_z), str(self.var), str((self.start, self.end))) def get_parameter_points(self): np = import_module('numpy') return np.linspace(self.start, self.end, num=self.nb_of_points) def get_points(self): np = import_module('numpy') param = self.get_parameter_points() fx = vectorized_lambdify([self.var], self.expr_x) fy = vectorized_lambdify([self.var], self.expr_y) fz = vectorized_lambdify([self.var], self.expr_z) list_x = fx(param) list_y = fy(param) list_z = fz(param) list_x = np.array(list_x, dtype=np.float64) list_y = np.array(list_y, dtype=np.float64) list_z = np.array(list_z, dtype=np.float64) list_x = np.ma.masked_invalid(list_x) list_y = np.ma.masked_invalid(list_y) list_z = np.ma.masked_invalid(list_z) self._xlim = (np.amin(list_x), np.amax(list_x)) self._ylim = (np.amin(list_y), np.amax(list_y)) self._zlim = (np.amin(list_z), np.amax(list_z)) return list_x, list_y, list_z ### Surfaces class SurfaceBaseSeries(BaseSeries): """A base class for 3D surfaces.""" is_3Dsurface = True def __init__(self): super().__init__() self.surface_color = None def get_color_array(self): np = import_module('numpy') c = self.surface_color if isinstance(c, Callable): f = np.vectorize(c) nargs = arity(c) if self.is_parametric: variables = list(map(centers_of_faces, self.get_parameter_meshes())) if nargs == 1: return f(variables[0]) elif nargs == 2: return f(*variables) variables = list(map(centers_of_faces, self.get_meshes())) if nargs == 1: return f(variables[0]) elif nargs == 2: return f(*variables[:2]) else: return f(*variables) else: if isinstance(self, SurfaceOver2DRangeSeries): return c*np.ones(min(self.nb_of_points_x, self.nb_of_points_y)) else: return c*np.ones(min(self.nb_of_points_u, self.nb_of_points_v)) class SurfaceOver2DRangeSeries(SurfaceBaseSeries): """Representation for a 3D surface consisting of a sympy expression and 2D range.""" def __init__(self, expr, var_start_end_x, var_start_end_y, **kwargs): super().__init__() self.expr = sympify(expr) self.var_x = sympify(var_start_end_x[0]) self.start_x = float(var_start_end_x[1]) self.end_x = float(var_start_end_x[2]) self.var_y = sympify(var_start_end_y[0]) self.start_y = float(var_start_end_y[1]) self.end_y = float(var_start_end_y[2]) self.nb_of_points_x = kwargs.get('nb_of_points_x', 50) self.nb_of_points_y = kwargs.get('nb_of_points_y', 50) self.surface_color = kwargs.get('surface_color', None) self._xlim = (self.start_x, self.end_x) self._ylim = (self.start_y, self.end_y) def __str__(self): return ('cartesian surface: %s for' ' %s over %s and %s over %s') % ( str(self.expr), str(self.var_x), str((self.start_x, self.end_x)), str(self.var_y), str((self.start_y, self.end_y))) def get_meshes(self): np = import_module('numpy') mesh_x, mesh_y = np.meshgrid(np.linspace(self.start_x, self.end_x, num=self.nb_of_points_x), np.linspace(self.start_y, self.end_y, num=self.nb_of_points_y)) f = vectorized_lambdify((self.var_x, self.var_y), self.expr) mesh_z = f(mesh_x, mesh_y) mesh_z = np.array(mesh_z, dtype=np.float64) mesh_z = np.ma.masked_invalid(mesh_z) self._zlim = (np.amin(mesh_z), np.amax(mesh_z)) return mesh_x, mesh_y, mesh_z class ParametricSurfaceSeries(SurfaceBaseSeries): """Representation for a 3D surface consisting of three parametric sympy expressions and a range.""" is_parametric = True def __init__( self, expr_x, expr_y, expr_z, var_start_end_u, var_start_end_v, **kwargs): super().__init__() self.expr_x = sympify(expr_x) self.expr_y = sympify(expr_y) self.expr_z = sympify(expr_z) self.var_u = sympify(var_start_end_u[0]) self.start_u = float(var_start_end_u[1]) self.end_u = float(var_start_end_u[2]) self.var_v = sympify(var_start_end_v[0]) self.start_v = float(var_start_end_v[1]) self.end_v = float(var_start_end_v[2]) self.nb_of_points_u = kwargs.get('nb_of_points_u', 50) self.nb_of_points_v = kwargs.get('nb_of_points_v', 50) self.surface_color = kwargs.get('surface_color', None) def __str__(self): return ('parametric cartesian surface: (%s, %s, %s) for' ' %s over %s and %s over %s') % ( str(self.expr_x), str(self.expr_y), str(self.expr_z), str(self.var_u), str((self.start_u, self.end_u)), str(self.var_v), str((self.start_v, self.end_v))) def get_parameter_meshes(self): np = import_module('numpy') return np.meshgrid(np.linspace(self.start_u, self.end_u, num=self.nb_of_points_u), np.linspace(self.start_v, self.end_v, num=self.nb_of_points_v)) def get_meshes(self): np = import_module('numpy') mesh_u, mesh_v = self.get_parameter_meshes() fx = vectorized_lambdify((self.var_u, self.var_v), self.expr_x) fy = vectorized_lambdify((self.var_u, self.var_v), self.expr_y) fz = vectorized_lambdify((self.var_u, self.var_v), self.expr_z) mesh_x = fx(mesh_u, mesh_v) mesh_y = fy(mesh_u, mesh_v) mesh_z = fz(mesh_u, mesh_v) mesh_x = np.array(mesh_x, dtype=np.float64) mesh_y = np.array(mesh_y, dtype=np.float64) mesh_z = np.array(mesh_z, dtype=np.float64) mesh_x = np.ma.masked_invalid(mesh_x) mesh_y = np.ma.masked_invalid(mesh_y) mesh_z = np.ma.masked_invalid(mesh_z) self._xlim = (np.amin(mesh_x), np.amax(mesh_x)) self._ylim = (np.amin(mesh_y), np.amax(mesh_y)) self._zlim = (np.amin(mesh_z), np.amax(mesh_z)) return mesh_x, mesh_y, mesh_z ### Contours class ContourSeries(BaseSeries): """Representation for a contour plot.""" # The code is mostly repetition of SurfaceOver2DRange. # Presently used in contour_plot function is_contour = True def __init__(self, expr, var_start_end_x, var_start_end_y): super().__init__() self.nb_of_points_x = 50 self.nb_of_points_y = 50 self.expr = sympify(expr) self.var_x = sympify(var_start_end_x[0]) self.start_x = float(var_start_end_x[1]) self.end_x = float(var_start_end_x[2]) self.var_y = sympify(var_start_end_y[0]) self.start_y = float(var_start_end_y[1]) self.end_y = float(var_start_end_y[2]) self.get_points = self.get_meshes self._xlim = (self.start_x, self.end_x) self._ylim = (self.start_y, self.end_y) def __str__(self): return ('contour: %s for ' '%s over %s and %s over %s') % ( str(self.expr), str(self.var_x), str((self.start_x, self.end_x)), str(self.var_y), str((self.start_y, self.end_y))) def get_meshes(self): np = import_module('numpy') mesh_x, mesh_y = np.meshgrid(np.linspace(self.start_x, self.end_x, num=self.nb_of_points_x), np.linspace(self.start_y, self.end_y, num=self.nb_of_points_y)) f = vectorized_lambdify((self.var_x, self.var_y), self.expr) return (mesh_x, mesh_y, f(mesh_x, mesh_y)) ############################################################################## # Backends ############################################################################## class BaseBackend: """Base class for all backends. A backend represents the plotting library, which implements the necessary functionalities in order to use SymPy plotting functions. How the plotting module works: 1. Whenever a plotting function is called, the provided expressions are processed and a list of instances of the `BaseSeries` class is created, containing the necessary information to plot the expressions (eg the expression, ranges, series name, ...). Eventually, these objects will generate the numerical data to be plotted. 2. A Plot object is instantiated, which stores the list of series and the main attributes of the plot (eg axis labels, title, ...). 3. When the "show" command is executed, a new backend is instantiated, which loops through each series object to generate and plot the numerical data. The backend is also going to set the axis labels, title, ..., according to the values stored in the Plot instance. The backend should check if it supports the data series that it's given (eg TextBackend supports only LineOver1DRange). It's the backend responsibility to know how to use the class of data series that it's given. Note that the current implementation of the `*Series` classes is "matplotlib-centric": the numerical data returned by the `get_points` and `get_meshes` methods is meant to be used directly by Matplotlib. Therefore, the new backend will have to pre-process the numerical data to make it compatible with the chosen plotting library. Keep in mind that future SymPy versions may improve the `*Series` classes in order to return numerical data "non-matplotlib-centric", hence if you code a new backend you have the responsibility to check if its working on each SymPy release. Please, explore the `MatplotlibBackend` source code to understand how a backend should be coded. Methods ======= In order to be used by SymPy plotting functions, a backend must implement the following methods: * `show(self)`: used to loop over the data series, generate the numerical data, plot it and set the axis labels, title, ... * save(self, path): used to save the current plot to the specified file path. * close(self): used to close the current plot backend (note: some plotting library doesn't support this functionality. In that case, just raise a warning). See also ======== MatplotlibBackend """ def __init__(self, parent): super().__init__() self.parent = parent def show(self): raise NotImplementedError def save(self, path): raise NotImplementedError def close(self): raise NotImplementedError # Don't have to check for the success of importing matplotlib in each case; # we will only be using this backend if we can successfully import matploblib class MatplotlibBackend(BaseBackend): """ This class implements the functionalities to use Matplotlib with SymPy plotting functions. """ def __init__(self, parent): super().__init__(parent) self.matplotlib = import_module('matplotlib', import_kwargs={'fromlist': ['pyplot', 'cm', 'collections']}, min_module_version='1.1.0', catch=(RuntimeError,)) self.plt = self.matplotlib.pyplot self.cm = self.matplotlib.cm self.LineCollection = self.matplotlib.collections.LineCollection aspect = getattr(self.parent, 'aspect_ratio', 'auto') if aspect != 'auto': aspect = float(aspect[1]) / aspect[0] if isinstance(self.parent, Plot): nrows, ncolumns = 1, 1 series_list = [self.parent._series] elif isinstance(self.parent, PlotGrid): nrows, ncolumns = self.parent.nrows, self.parent.ncolumns series_list = self.parent._series self.ax = [] self.fig = self.plt.figure(figsize=parent.size) for i, series in enumerate(series_list): are_3D = [s.is_3D for s in series] if any(are_3D) and not all(are_3D): raise ValueError('The matplotlib backend can not mix 2D and 3D.') elif all(are_3D): # mpl_toolkits.mplot3d is necessary for # projection='3d' mpl_toolkits = import_module('mpl_toolkits', # noqa import_kwargs={'fromlist': ['mplot3d']}) self.ax.append(self.fig.add_subplot(nrows, ncolumns, i + 1, projection='3d', aspect=aspect)) elif not any(are_3D): self.ax.append(self.fig.add_subplot(nrows, ncolumns, i + 1, aspect=aspect)) self.ax[i].spines['left'].set_position('zero') self.ax[i].spines['right'].set_color('none') self.ax[i].spines['bottom'].set_position('zero') self.ax[i].spines['top'].set_color('none') self.ax[i].xaxis.set_ticks_position('bottom') self.ax[i].yaxis.set_ticks_position('left') @staticmethod def get_segments(x, y, z=None): """ Convert two list of coordinates to a list of segments to be used with Matplotlib's LineCollection. Parameters ========== x: list List of x-coordinates y: list List of y-coordinates z: list List of z-coordinates for a 3D line. """ np = import_module('numpy') if z is not None: dim = 3 points = (x, y, z) else: dim = 2 points = (x, y) points = np.ma.array(points).T.reshape(-1, 1, dim) return np.ma.concatenate([points[:-1], points[1:]], axis=1) def _process_series(self, series, ax, parent): np = import_module('numpy') mpl_toolkits = import_module( 'mpl_toolkits', import_kwargs={'fromlist': ['mplot3d']}) # XXX Workaround for matplotlib issue # https://github.com/matplotlib/matplotlib/issues/17130 xlims, ylims, zlims = [], [], [] for s in series: # Create the collections if s.is_2Dline: x, y = s.get_data() if (isinstance(s.line_color, (int, float)) or callable(s.line_color)): segments = self.get_segments(x, y) collection = self.LineCollection(segments) collection.set_array(s.get_color_array()) ax.add_collection(collection) else: line, = ax.plot(x, y, label=s.label, color=s.line_color) elif s.is_contour: ax.contour(*s.get_meshes()) elif s.is_3Dline: x, y, z = s.get_data() if (isinstance(s.line_color, (int, float)) or callable(s.line_color)): art3d = mpl_toolkits.mplot3d.art3d segments = self.get_segments(x, y, z) collection = art3d.Line3DCollection(segments) collection.set_array(s.get_color_array()) ax.add_collection(collection) else: ax.plot(x, y, z, label=s.label, color=s.line_color) xlims.append(s._xlim) ylims.append(s._ylim) zlims.append(s._zlim) elif s.is_3Dsurface: x, y, z = s.get_meshes() collection = ax.plot_surface(x, y, z, cmap=getattr(self.cm, 'viridis', self.cm.jet), rstride=1, cstride=1, linewidth=0.1) if isinstance(s.surface_color, (float, int)) or isinstance(s.surface_color, Callable): color_array = s.get_color_array() color_array = color_array.reshape(color_array.size) collection.set_array(color_array) else: collection.set_color(s.surface_color) xlims.append(s._xlim) ylims.append(s._ylim) zlims.append(s._zlim) elif s.is_implicit: points = s.get_raster() if len(points) == 2: # interval math plotting x, y = _matplotlib_list(points[0]) ax.fill(x, y, facecolor=s.line_color, edgecolor='None') else: # use contourf or contour depending on whether it is # an inequality or equality. # XXX: ``contour`` plots multiple lines. Should be fixed. ListedColormap = self.matplotlib.colors.ListedColormap colormap = ListedColormap(["white", s.line_color]) xarray, yarray, zarray, plot_type = points if plot_type == 'contour': ax.contour(xarray, yarray, zarray, cmap=colormap) else: ax.contourf(xarray, yarray, zarray, cmap=colormap) else: raise NotImplementedError( '{} is not supported in the sympy plotting module ' 'with matplotlib backend. Please report this issue.' .format(ax)) Axes3D = mpl_toolkits.mplot3d.Axes3D if not isinstance(ax, Axes3D): ax.autoscale_view( scalex=ax.get_autoscalex_on(), scaley=ax.get_autoscaley_on()) else: # XXX Workaround for matplotlib issue # https://github.com/matplotlib/matplotlib/issues/17130 if xlims: xlims = np.array(xlims) xlim = (np.amin(xlims[:, 0]), np.amax(xlims[:, 1])) ax.set_xlim(xlim) else: ax.set_xlim([0, 1]) if ylims: ylims = np.array(ylims) ylim = (np.amin(ylims[:, 0]), np.amax(ylims[:, 1])) ax.set_ylim(ylim) else: ax.set_ylim([0, 1]) if zlims: zlims = np.array(zlims) zlim = (np.amin(zlims[:, 0]), np.amax(zlims[:, 1])) ax.set_zlim(zlim) else: ax.set_zlim([0, 1]) # Set global options. # TODO The 3D stuff # XXX The order of those is important. if parent.xscale and not isinstance(ax, Axes3D): ax.set_xscale(parent.xscale) if parent.yscale and not isinstance(ax, Axes3D): ax.set_yscale(parent.yscale) if not isinstance(ax, Axes3D) or self.matplotlib.__version__ >= '1.2.0': # XXX in the distant future remove this check ax.set_autoscale_on(parent.autoscale) if parent.axis_center: val = parent.axis_center if isinstance(ax, Axes3D): pass elif val == 'center': ax.spines['left'].set_position('center') ax.spines['bottom'].set_position('center') elif val == 'auto': xl, xh = ax.get_xlim() yl, yh = ax.get_ylim() pos_left = ('data', 0) if xl*xh <= 0 else 'center' pos_bottom = ('data', 0) if yl*yh <= 0 else 'center' ax.spines['left'].set_position(pos_left) ax.spines['bottom'].set_position(pos_bottom) else: ax.spines['left'].set_position(('data', val[0])) ax.spines['bottom'].set_position(('data', val[1])) if not parent.axis: ax.set_axis_off() if parent.legend: if ax.legend(): ax.legend_.set_visible(parent.legend) if parent.margin: ax.set_xmargin(parent.margin) ax.set_ymargin(parent.margin) if parent.title: ax.set_title(parent.title) if parent.xlabel: ax.set_xlabel(parent.xlabel, position=(1, 0)) if parent.ylabel: ax.set_ylabel(parent.ylabel, position=(0, 1)) if isinstance(ax, Axes3D) and parent.zlabel: ax.set_zlabel(parent.zlabel, position=(0, 1)) if parent.annotations: for a in parent.annotations: ax.annotate(**a) if parent.markers: for marker in parent.markers: # make a copy of the marker dictionary # so that it doesn't get altered m = marker.copy() args = m.pop('args') ax.plot(*args, **m) if parent.rectangles: for r in parent.rectangles: rect = self.matplotlib.patches.Rectangle(**r) ax.add_patch(rect) if parent.fill: ax.fill_between(**parent.fill) # xlim and ylim shoulld always be set at last so that plot limits # doesn't get altered during the process. if parent.xlim: ax.set_xlim(parent.xlim) if parent.ylim: ax.set_ylim(parent.ylim) def process_series(self): """ Iterates over every ``Plot`` object and further calls _process_series() """ parent = self.parent if isinstance(parent, Plot): series_list = [parent._series] else: series_list = parent._series for i, (series, ax) in enumerate(zip(series_list, self.ax)): if isinstance(self.parent, PlotGrid): parent = self.parent.args[i] self._process_series(series, ax, parent) def show(self): self.process_series() #TODO after fixing https://github.com/ipython/ipython/issues/1255 # you can uncomment the next line and remove the pyplot.show() call #self.fig.show() if _show: self.fig.tight_layout() self.plt.show() else: self.close() def save(self, path): self.process_series() self.fig.savefig(path) def close(self): self.plt.close(self.fig) class TextBackend(BaseBackend): def __init__(self, parent): super().__init__(parent) def show(self): if not _show: return if len(self.parent._series) != 1: raise ValueError( 'The TextBackend supports only one graph per Plot.') elif not isinstance(self.parent._series[0], LineOver1DRangeSeries): raise ValueError( 'The TextBackend supports only expressions over a 1D range') else: ser = self.parent._series[0] textplot(ser.expr, ser.start, ser.end) def close(self): pass class DefaultBackend(BaseBackend): def __new__(cls, parent): matplotlib = import_module('matplotlib', min_module_version='1.1.0', catch=(RuntimeError,)) if matplotlib: return MatplotlibBackend(parent) else: return TextBackend(parent) plot_backends = { 'matplotlib': MatplotlibBackend, 'text': TextBackend, 'default': DefaultBackend } ############################################################################## # Finding the centers of line segments or mesh faces ############################################################################## def centers_of_segments(array): np = import_module('numpy') return np.mean(np.vstack((array[:-1], array[1:])), 0) def centers_of_faces(array): np = import_module('numpy') return np.mean(np.dstack((array[:-1, :-1], array[1:, :-1], array[:-1, 1:], array[:-1, :-1], )), 2) def flat(x, y, z, eps=1e-3): """Checks whether three points are almost collinear""" np = import_module('numpy') # Workaround plotting piecewise (#8577): # workaround for `lambdify` in `.experimental_lambdify` fails # to return numerical values in some cases. Lower-level fix # in `lambdify` is possible. vector_a = (x - y).astype(np.float64) vector_b = (z - y).astype(np.float64) dot_product = np.dot(vector_a, vector_b) vector_a_norm = np.linalg.norm(vector_a) vector_b_norm = np.linalg.norm(vector_b) cos_theta = dot_product / (vector_a_norm * vector_b_norm) return abs(cos_theta + 1) < eps def _matplotlib_list(interval_list): """ Returns lists for matplotlib ``fill`` command from a list of bounding rectangular intervals """ xlist = [] ylist = [] if len(interval_list): for intervals in interval_list: intervalx = intervals[0] intervaly = intervals[1] xlist.extend([intervalx.start, intervalx.start, intervalx.end, intervalx.end, None]) ylist.extend([intervaly.start, intervaly.end, intervaly.end, intervaly.start, None]) else: #XXX Ugly hack. Matplotlib does not accept empty lists for ``fill`` xlist.extend([None, None, None, None]) ylist.extend([None, None, None, None]) return xlist, ylist ####New API for plotting module #### # TODO: Add color arrays for plots. # TODO: Add more plotting options for 3d plots. # TODO: Adaptive sampling for 3D plots. def plot(*args, show=True, **kwargs): """Plots a function of a single variable as a curve. Parameters ========== args : The first argument is the expression representing the function of single variable to be plotted. The last argument is a 3-tuple denoting the range of the free variable. e.g. ``(x, 0, 5)`` Typical usage examples are in the followings: - Plotting a single expression with a single range. ``plot(expr, range, **kwargs)`` - Plotting a single expression with the default range (-10, 10). ``plot(expr, **kwargs)`` - Plotting multiple expressions with a single range. ``plot(expr1, expr2, ..., range, **kwargs)`` - Plotting multiple expressions with multiple ranges. ``plot((expr1, range1), (expr2, range2), ..., **kwargs)`` It is best practice to specify range explicitly because default range may change in the future if a more advanced default range detection algorithm is implemented. show : bool, optional The default value is set to ``True``. Set show to ``False`` and the function will not display the plot. The returned instance of the ``Plot`` class can then be used to save or display the plot by calling the ``save()`` and ``show()`` methods respectively. line_color : string, or float, or function, optional Specifies the color for the plot. See ``Plot`` to see how to set color for the plots. Note that by setting ``line_color``, it would be applied simultaneously to all the series. title : str, optional Title of the plot. It is set to the latex representation of the expression, if the plot has only one expression. label : str, optional The label of the expression in the plot. It will be used when called with ``legend``. Default is the name of the expression. e.g. ``sin(x)`` xlabel : str, optional Label for the x-axis. ylabel : str, optional Label for the y-axis. xscale : 'linear' or 'log', optional Sets the scaling of the x-axis. yscale : 'linear' or 'log', optional Sets the scaling of the y-axis. axis_center : (float, float), optional Tuple of two floats denoting the coordinates of the center or {'center', 'auto'} xlim : (float, float), optional Denotes the x-axis limits, ``(min, max)```. ylim : (float, float), optional Denotes the y-axis limits, ``(min, max)```. annotations : list, optional A list of dictionaries specifying the type of annotation required. The keys in the dictionary should be equivalent to the arguments of the matplotlib's annotate() function. markers : list, optional A list of dictionaries specifying the type the markers required. The keys in the dictionary should be equivalent to the arguments of the matplotlib's plot() function along with the marker related keyworded arguments. rectangles : list, optional A list of dictionaries specifying the dimensions of the rectangles to be plotted. The keys in the dictionary should be equivalent to the arguments of the matplotlib's patches.Rectangle class. fill : dict, optional A dictionary specifying the type of color filling required in the plot. The keys in the dictionary should be equivalent to the arguments of the matplotlib's fill_between() function. adaptive : bool, optional The default value is set to ``True``. Set adaptive to ``False`` and specify ``nb_of_points`` if uniform sampling is required. The plotting uses an adaptive algorithm which samples recursively to accurately plot. The adaptive algorithm uses a random point near the midpoint of two points that has to be further sampled. Hence the same plots can appear slightly different. depth : int, optional Recursion depth of the adaptive algorithm. A depth of value ``n`` samples a maximum of `2^{n}` points. If the ``adaptive`` flag is set to ``False``, this will be ignored. nb_of_points : int, optional Used when the ``adaptive`` is set to ``False``. The function is uniformly sampled at ``nb_of_points`` number of points. If the ``adaptive`` flag is set to ``True``, this will be ignored. size : (float, float), optional A tuple in the form (width, height) in inches to specify the size of the overall figure. The default value is set to ``None``, meaning the size will be set by the default backend. Examples ======== .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.plotting import plot >>> x = symbols('x') Single Plot .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot(x**2, (x, -5, 5)) Plot object containing: [0]: cartesian line: x**2 for x over (-5.0, 5.0) Multiple plots with single range. .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot(x, x**2, x**3, (x, -5, 5)) Plot object containing: [0]: cartesian line: x for x over (-5.0, 5.0) [1]: cartesian line: x**2 for x over (-5.0, 5.0) [2]: cartesian line: x**3 for x over (-5.0, 5.0) Multiple plots with different ranges. .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot((x**2, (x, -6, 6)), (x, (x, -5, 5))) Plot object containing: [0]: cartesian line: x**2 for x over (-6.0, 6.0) [1]: cartesian line: x for x over (-5.0, 5.0) No adaptive sampling. .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot(x**2, adaptive=False, nb_of_points=400) Plot object containing: [0]: cartesian line: x**2 for x over (-10.0, 10.0) See Also ======== Plot, LineOver1DRangeSeries """ args = list(map(sympify, args)) free = set() for a in args: if isinstance(a, Expr): free |= a.free_symbols if len(free) > 1: raise ValueError( 'The same variable should be used in all ' 'univariate expressions being plotted.') x = free.pop() if free else Symbol('x') kwargs.setdefault('xlabel', x.name) kwargs.setdefault('ylabel', 'f(%s)' % x.name) series = [] plot_expr = check_arguments(args, 1, 1) series = [LineOver1DRangeSeries(*arg, **kwargs) for arg in plot_expr] plots = Plot(*series, **kwargs) if show: plots.show() return plots def plot_parametric(*args, show=True, **kwargs): """ Plots a 2D parametric curve. Parameters ========== args Common specifications are: - Plotting a single parametric curve with a range ``plot_parametric((expr_x, expr_y), range)`` - Plotting multiple parametric curves with the same range ``plot_parametric((expr_x, expr_y), ..., range)`` - Plotting multiple parametric curves with different ranges ``plot_parametric((expr_x, expr_y, range), ...)`` ``expr_x`` is the expression representing $x$ component of the parametric function. ``expr_y`` is the expression representing $y$ component of the parametric function. ``range`` is a 3-tuple denoting the parameter symbol, start and stop. For example, ``(u, 0, 5)``. If the range is not specified, then a default range of (-10, 10) is used. However, if the arguments are specified as ``(expr_x, expr_y, range), ...``, you must specify the ranges for each expressions manually. Default range may change in the future if a more advanced algorithm is implemented. adaptive : bool, optional Specifies whether to use the adaptive sampling or not. The default value is set to ``True``. Set adaptive to ``False`` and specify ``nb_of_points`` if uniform sampling is required. depth : int, optional The recursion depth of the adaptive algorithm. A depth of value $n$ samples a maximum of $2^n$ points. nb_of_points : int, optional Used when the ``adaptive`` flag is set to ``False``. Specifies the number of the points used for the uniform sampling. line_color : string, or float, or function, optional Specifies the color for the plot. See ``Plot`` to see how to set color for the plots. Note that by setting ``line_color``, it would be applied simultaneously to all the series. label : str, optional The label of the expression in the plot. It will be used when called with ``legend``. Default is the name of the expression. e.g. ``sin(x)`` xlabel : str, optional Label for the x-axis. ylabel : str, optional Label for the y-axis. xscale : 'linear' or 'log', optional Sets the scaling of the x-axis. yscale : 'linear' or 'log', optional Sets the scaling of the y-axis. axis_center : (float, float), optional Tuple of two floats denoting the coordinates of the center or {'center', 'auto'} xlim : (float, float), optional Denotes the x-axis limits, ``(min, max)```. ylim : (float, float), optional Denotes the y-axis limits, ``(min, max)```. size : (float, float), optional A tuple in the form (width, height) in inches to specify the size of the overall figure. The default value is set to ``None``, meaning the size will be set by the default backend. Examples ======== .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import symbols, cos, sin >>> from sympy.plotting import plot_parametric >>> u = symbols('u') A parametric plot with a single expression: .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot_parametric((cos(u), sin(u)), (u, -5, 5)) Plot object containing: [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0) A parametric plot with multiple expressions with the same range: .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot_parametric((cos(u), sin(u)), (u, cos(u)), (u, -10, 10)) Plot object containing: [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-10.0, 10.0) [1]: parametric cartesian line: (u, cos(u)) for u over (-10.0, 10.0) A parametric plot with multiple expressions with different ranges for each curve: .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot_parametric((cos(u), sin(u), (u, -5, 5)), ... (cos(u), u, (u, -5, 5))) Plot object containing: [0]: parametric cartesian line: (cos(u), sin(u)) for u over (-5.0, 5.0) [1]: parametric cartesian line: (cos(u), u) for u over (-5.0, 5.0) Notes ===== The plotting uses an adaptive algorithm which samples recursively to accurately plot the curve. The adaptive algorithm uses a random point near the midpoint of two points that has to be further sampled. Hence, repeating the same plot command can give slightly different results because of the random sampling. If there are multiple plots, then the same optional arguments are applied to all the plots drawn in the same canvas. If you want to set these options separately, you can index the returned ``Plot`` object and set it. For example, when you specify ``line_color`` once, it would be applied simultaneously to both series. .. plot:: :context: close-figs :format: doctest :include-source: True >>> from sympy import pi >>> expr1 = (u, cos(2*pi*u)/2 + 1/2) >>> expr2 = (u, sin(2*pi*u)/2 + 1/2) >>> p = plot_parametric(expr1, expr2, (u, 0, 1), line_color='blue') If you want to specify the line color for the specific series, you should index each item and apply the property manually. .. plot:: :context: close-figs :format: doctest :include-source: True >>> p[0].line_color = 'red' >>> p.show() See Also ======== Plot, Parametric2DLineSeries """ args = list(map(sympify, args)) series = [] plot_expr = check_arguments(args, 2, 1) series = [Parametric2DLineSeries(*arg, **kwargs) for arg in plot_expr] plots = Plot(*series, **kwargs) if show: plots.show() return plots def plot3d_parametric_line(*args, show=True, **kwargs): """ Plots a 3D parametric line plot. Usage ===== Single plot: ``plot3d_parametric_line(expr_x, expr_y, expr_z, range, **kwargs)`` If the range is not specified, then a default range of (-10, 10) is used. Multiple plots. ``plot3d_parametric_line((expr_x, expr_y, expr_z, range), ..., **kwargs)`` Ranges have to be specified for every expression. Default range may change in the future if a more advanced default range detection algorithm is implemented. Arguments ========= ``expr_x`` : Expression representing the function along x. ``expr_y`` : Expression representing the function along y. ``expr_z`` : Expression representing the function along z. ``range``: ``(u, 0, 5)``, A 3-tuple denoting the range of the parameter variable. Keyword Arguments ================= Arguments for ``Parametric3DLineSeries`` class. ``nb_of_points``: The range is uniformly sampled at ``nb_of_points`` number of points. Aesthetics: ``line_color``: string, or float, or function, optional Specifies the color for the plot. See ``Plot`` to see how to set color for the plots. Note that by setting ``line_color``, it would be applied simultaneously to all the series. ``label``: str The label to the plot. It will be used when called with ``legend=True`` to denote the function with the given label in the plot. If there are multiple plots, then the same series arguments are applied to all the plots. If you want to set these options separately, you can index the returned ``Plot`` object and set it. Arguments for ``Plot`` class. ``title`` : str. Title of the plot. ``size`` : (float, float), optional A tuple in the form (width, height) in inches to specify the size of the overall figure. The default value is set to ``None``, meaning the size will be set by the default backend. Examples ======== .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import symbols, cos, sin >>> from sympy.plotting import plot3d_parametric_line >>> u = symbols('u') Single plot. .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot3d_parametric_line(cos(u), sin(u), u, (u, -5, 5)) Plot object containing: [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0) Multiple plots. .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot3d_parametric_line((cos(u), sin(u), u, (u, -5, 5)), ... (sin(u), u**2, u, (u, -5, 5))) Plot object containing: [0]: 3D parametric cartesian line: (cos(u), sin(u), u) for u over (-5.0, 5.0) [1]: 3D parametric cartesian line: (sin(u), u**2, u) for u over (-5.0, 5.0) See Also ======== Plot, Parametric3DLineSeries """ args = list(map(sympify, args)) series = [] plot_expr = check_arguments(args, 3, 1) series = [Parametric3DLineSeries(*arg, **kwargs) for arg in plot_expr] kwargs.setdefault("xlabel", "x") kwargs.setdefault("ylabel", "y") kwargs.setdefault("zlabel", "z") plots = Plot(*series, **kwargs) if show: plots.show() return plots def plot3d(*args, show=True, **kwargs): """ Plots a 3D surface plot. Usage ===== Single plot ``plot3d(expr, range_x, range_y, **kwargs)`` If the ranges are not specified, then a default range of (-10, 10) is used. Multiple plot with the same range. ``plot3d(expr1, expr2, range_x, range_y, **kwargs)`` If the ranges are not specified, then a default range of (-10, 10) is used. Multiple plots with different ranges. ``plot3d((expr1, range_x, range_y), (expr2, range_x, range_y), ..., **kwargs)`` Ranges have to be specified for every expression. Default range may change in the future if a more advanced default range detection algorithm is implemented. Arguments ========= ``expr`` : Expression representing the function along x. ``range_x``: (x, 0, 5), A 3-tuple denoting the range of the x variable. ``range_y``: (y, 0, 5), A 3-tuple denoting the range of the y variable. Keyword Arguments ================= Arguments for ``SurfaceOver2DRangeSeries`` class: ``nb_of_points_x``: int. The x range is sampled uniformly at ``nb_of_points_x`` of points. ``nb_of_points_y``: int. The y range is sampled uniformly at ``nb_of_points_y`` of points. Aesthetics: ``surface_color``: Function which returns a float. Specifies the color for the surface of the plot. See ``sympy.plotting.Plot`` for more details. If there are multiple plots, then the same series arguments are applied to all the plots. If you want to set these options separately, you can index the returned ``Plot`` object and set it. Arguments for ``Plot`` class: ``title`` : str. Title of the plot. ``size`` : (float, float), optional A tuple in the form (width, height) in inches to specify the size of the overall figure. The default value is set to ``None``, meaning the size will be set by the default backend. Examples ======== .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import symbols >>> from sympy.plotting import plot3d >>> x, y = symbols('x y') Single plot .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot3d(x*y, (x, -5, 5), (y, -5, 5)) Plot object containing: [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) Multiple plots with same range .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot3d(x*y, -x*y, (x, -5, 5), (y, -5, 5)) Plot object containing: [0]: cartesian surface: x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) [1]: cartesian surface: -x*y for x over (-5.0, 5.0) and y over (-5.0, 5.0) Multiple plots with different ranges. .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot3d((x**2 + y**2, (x, -5, 5), (y, -5, 5)), ... (x*y, (x, -3, 3), (y, -3, 3))) Plot object containing: [0]: cartesian surface: x**2 + y**2 for x over (-5.0, 5.0) and y over (-5.0, 5.0) [1]: cartesian surface: x*y for x over (-3.0, 3.0) and y over (-3.0, 3.0) See Also ======== Plot, SurfaceOver2DRangeSeries """ args = list(map(sympify, args)) series = [] plot_expr = check_arguments(args, 1, 2) series = [SurfaceOver2DRangeSeries(*arg, **kwargs) for arg in plot_expr] xlabel = series[0].var_x.name ylabel = series[0].var_y.name kwargs.setdefault("xlabel", xlabel) kwargs.setdefault("ylabel", ylabel) kwargs.setdefault("zlabel", "f(%s, %s)" % (xlabel, ylabel)) plots = Plot(*series, **kwargs) if show: plots.show() return plots def plot3d_parametric_surface(*args, show=True, **kwargs): """ Plots a 3D parametric surface plot. Explanation =========== Single plot. ``plot3d_parametric_surface(expr_x, expr_y, expr_z, range_u, range_v, **kwargs)`` If the ranges is not specified, then a default range of (-10, 10) is used. Multiple plots. ``plot3d_parametric_surface((expr_x, expr_y, expr_z, range_u, range_v), ..., **kwargs)`` Ranges have to be specified for every expression. Default range may change in the future if a more advanced default range detection algorithm is implemented. Arguments ========= ``expr_x``: Expression representing the function along ``x``. ``expr_y``: Expression representing the function along ``y``. ``expr_z``: Expression representing the function along ``z``. ``range_u``: ``(u, 0, 5)``, A 3-tuple denoting the range of the ``u`` variable. ``range_v``: ``(v, 0, 5)``, A 3-tuple denoting the range of the v variable. Keyword Arguments ================= Arguments for ``ParametricSurfaceSeries`` class: ``nb_of_points_u``: int. The ``u`` range is sampled uniformly at ``nb_of_points_v`` of points ``nb_of_points_y``: int. The ``v`` range is sampled uniformly at ``nb_of_points_y`` of points Aesthetics: ``surface_color``: Function which returns a float. Specifies the color for the surface of the plot. See ``sympy.plotting.Plot`` for more details. If there are multiple plots, then the same series arguments are applied for all the plots. If you want to set these options separately, you can index the returned ``Plot`` object and set it. Arguments for ``Plot`` class: ``title`` : str. Title of the plot. ``size`` : (float, float), optional A tuple in the form (width, height) in inches to specify the size of the overall figure. The default value is set to ``None``, meaning the size will be set by the default backend. Examples ======== .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import symbols, cos, sin >>> from sympy.plotting import plot3d_parametric_surface >>> u, v = symbols('u v') Single plot. .. plot:: :context: close-figs :format: doctest :include-source: True >>> plot3d_parametric_surface(cos(u + v), sin(u - v), u - v, ... (u, -5, 5), (v, -5, 5)) Plot object containing: [0]: parametric cartesian surface: (cos(u + v), sin(u - v), u - v) for u over (-5.0, 5.0) and v over (-5.0, 5.0) See Also ======== Plot, ParametricSurfaceSeries """ args = list(map(sympify, args)) series = [] plot_expr = check_arguments(args, 3, 2) series = [ParametricSurfaceSeries(*arg, **kwargs) for arg in plot_expr] kwargs.setdefault("xlabel", "x") kwargs.setdefault("ylabel", "y") kwargs.setdefault("zlabel", "z") plots = Plot(*series, **kwargs) if show: plots.show() return plots def plot_contour(*args, show=True, **kwargs): """ Draws contour plot of a function Usage ===== Single plot ``plot_contour(expr, range_x, range_y, **kwargs)`` If the ranges are not specified, then a default range of (-10, 10) is used. Multiple plot with the same range. ``plot_contour(expr1, expr2, range_x, range_y, **kwargs)`` If the ranges are not specified, then a default range of (-10, 10) is used. Multiple plots with different ranges. ``plot_contour((expr1, range_x, range_y), (expr2, range_x, range_y), ..., **kwargs)`` Ranges have to be specified for every expression. Default range may change in the future if a more advanced default range detection algorithm is implemented. Arguments ========= ``expr`` : Expression representing the function along x. ``range_x``: (x, 0, 5), A 3-tuple denoting the range of the x variable. ``range_y``: (y, 0, 5), A 3-tuple denoting the range of the y variable. Keyword Arguments ================= Arguments for ``ContourSeries`` class: ``nb_of_points_x``: int. The x range is sampled uniformly at ``nb_of_points_x`` of points. ``nb_of_points_y``: int. The y range is sampled uniformly at ``nb_of_points_y`` of points. Aesthetics: ``surface_color``: Function which returns a float. Specifies the color for the surface of the plot. See ``sympy.plotting.Plot`` for more details. If there are multiple plots, then the same series arguments are applied to all the plots. If you want to set these options separately, you can index the returned ``Plot`` object and set it. Arguments for ``Plot`` class: ``title`` : str. Title of the plot. ``size`` : (float, float), optional A tuple in the form (width, height) in inches to specify the size of the overall figure. The default value is set to ``None``, meaning the size will be set by the default backend. See Also ======== Plot, ContourSeries """ args = list(map(sympify, args)) plot_expr = check_arguments(args, 1, 2) series = [ContourSeries(*arg) for arg in plot_expr] plot_contours = Plot(*series, **kwargs) if len(plot_expr[0].free_symbols) > 2: raise ValueError('Contour Plot cannot Plot for more than two variables.') if show: plot_contours.show() return plot_contours def check_arguments(args, expr_len, nb_of_free_symbols): """ Checks the arguments and converts into tuples of the form (exprs, ranges). Examples ======== .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import cos, sin, symbols >>> from sympy.plotting.plot import check_arguments >>> x = symbols('x') >>> check_arguments([cos(x), sin(x)], 2, 1) [(cos(x), sin(x), (x, -10, 10))] >>> check_arguments([x, x**2], 1, 1) [(x, (x, -10, 10)), (x**2, (x, -10, 10))] """ if not args: return [] if expr_len > 1 and isinstance(args[0], Expr): # Multiple expressions same range. # The arguments are tuples when the expression length is # greater than 1. if len(args) < expr_len: raise ValueError("len(args) should not be less than expr_len") for i in range(len(args)): if isinstance(args[i], Tuple): break else: i = len(args) + 1 exprs = Tuple(*args[:i]) free_symbols = list(set().union(*[e.free_symbols for e in exprs])) if len(args) == expr_len + nb_of_free_symbols: #Ranges given plots = [exprs + Tuple(*args[expr_len:])] else: default_range = Tuple(-10, 10) ranges = [] for symbol in free_symbols: ranges.append(Tuple(symbol) + default_range) for i in range(len(free_symbols) - nb_of_free_symbols): ranges.append(Tuple(Dummy()) + default_range) plots = [exprs + Tuple(*ranges)] return plots if isinstance(args[0], Expr) or (isinstance(args[0], Tuple) and len(args[0]) == expr_len and expr_len != 3): # Cannot handle expressions with number of expression = 3. It is # not possible to differentiate between expressions and ranges. #Series of plots with same range for i in range(len(args)): if isinstance(args[i], Tuple) and len(args[i]) != expr_len: break if not isinstance(args[i], Tuple): args[i] = Tuple(args[i]) else: i = len(args) + 1 exprs = args[:i] assert all(isinstance(e, Expr) for expr in exprs for e in expr) free_symbols = list(set().union(*[e.free_symbols for expr in exprs for e in expr])) if len(free_symbols) > nb_of_free_symbols: raise ValueError("The number of free_symbols in the expression " "is greater than %d" % nb_of_free_symbols) if len(args) == i + nb_of_free_symbols and isinstance(args[i], Tuple): ranges = Tuple(*[range_expr for range_expr in args[ i:i + nb_of_free_symbols]]) plots = [expr + ranges for expr in exprs] return plots else: # Use default ranges. default_range = Tuple(-10, 10) ranges = [] for symbol in free_symbols: ranges.append(Tuple(symbol) + default_range) for i in range(nb_of_free_symbols - len(free_symbols)): ranges.append(Tuple(Dummy()) + default_range) ranges = Tuple(*ranges) plots = [expr + ranges for expr in exprs] return plots elif isinstance(args[0], Tuple) and len(args[0]) == expr_len + nb_of_free_symbols: # Multiple plots with different ranges. for arg in args: for i in range(expr_len): if not isinstance(arg[i], Expr): raise ValueError("Expected an expression, given %s" % str(arg[i])) for i in range(nb_of_free_symbols): if not len(arg[i + expr_len]) == 3: raise ValueError("The ranges should be a tuple of " "length 3, got %s" % str(arg[i + expr_len])) return args sympy-sympy-1.9/sympy/plotting/plot_implicit.py000066400000000000000000000362761412543434000222040ustar00rootroot00000000000000"""Implicit plotting module for SymPy. Explanation =========== The module implements a data series called ImplicitSeries which is used by ``Plot`` class to plot implicit plots for different backends. The module, by default, implements plotting using interval arithmetic. It switches to a fall back algorithm if the expression cannot be plotted using interval arithmetic. It is also possible to specify to use the fall back algorithm for all plots. Boolean combinations of expressions cannot be plotted by the fall back algorithm. See Also ======== sympy.plotting.plot References ========== .. [1] Jeffrey Allen Tupper. Reliable Two-Dimensional Graphing Methods for Mathematical Formulae with Two Free Variables. .. [2] Jeffrey Allen Tupper. Graphing Equations with Generalized Interval Arithmetic. Master's thesis. University of Toronto, 1996 """ from .plot import BaseSeries, Plot from .experimental_lambdify import experimental_lambdify, vectorized_lambdify from .intervalmath import interval from sympy.core.relational import (Equality, GreaterThan, LessThan, Relational, StrictLessThan, StrictGreaterThan) from sympy import Eq, Tuple, sympify, Symbol, Dummy from sympy.external import import_module from sympy.logic.boolalg import BooleanFunction from sympy.polys.polyutils import _sort_gens from sympy.utilities.decorator import doctest_depends_on from sympy.utilities.iterables import flatten import warnings class ImplicitSeries(BaseSeries): """ Representation for Implicit plot """ is_implicit = True def __init__(self, expr, var_start_end_x, var_start_end_y, has_equality, use_interval_math, depth, nb_of_points, line_color): super().__init__() self.expr = sympify(expr) self.var_x = sympify(var_start_end_x[0]) self.start_x = float(var_start_end_x[1]) self.end_x = float(var_start_end_x[2]) self.var_y = sympify(var_start_end_y[0]) self.start_y = float(var_start_end_y[1]) self.end_y = float(var_start_end_y[2]) self.get_points = self.get_raster self.has_equality = has_equality # If the expression has equality, i.e. #Eq, Greaterthan, LessThan. self.nb_of_points = nb_of_points self.use_interval_math = use_interval_math self.depth = 4 + depth self.line_color = line_color def __str__(self): return ('Implicit equation: %s for ' '%s over %s and %s over %s') % ( str(self.expr), str(self.var_x), str((self.start_x, self.end_x)), str(self.var_y), str((self.start_y, self.end_y))) def get_raster(self): func = experimental_lambdify((self.var_x, self.var_y), self.expr, use_interval=True) xinterval = interval(self.start_x, self.end_x) yinterval = interval(self.start_y, self.end_y) try: func(xinterval, yinterval) except AttributeError: # XXX: AttributeError("'list' object has no attribute 'is_real'") # That needs fixing somehow - we shouldn't be catching # AttributeError here. if self.use_interval_math: warnings.warn("Adaptive meshing could not be applied to the" " expression. Using uniform meshing.") self.use_interval_math = False if self.use_interval_math: return self._get_raster_interval(func) else: return self._get_meshes_grid() def _get_raster_interval(self, func): """ Uses interval math to adaptively mesh and obtain the plot""" k = self.depth interval_list = [] #Create initial 32 divisions np = import_module('numpy') xsample = np.linspace(self.start_x, self.end_x, 33) ysample = np.linspace(self.start_y, self.end_y, 33) #Add a small jitter so that there are no false positives for equality. # Ex: y==x becomes True for x interval(1, 2) and y interval(1, 2) #which will draw a rectangle. jitterx = (np.random.rand( len(xsample)) * 2 - 1) * (self.end_x - self.start_x) / 2**20 jittery = (np.random.rand( len(ysample)) * 2 - 1) * (self.end_y - self.start_y) / 2**20 xsample += jitterx ysample += jittery xinter = [interval(x1, x2) for x1, x2 in zip(xsample[:-1], xsample[1:])] yinter = [interval(y1, y2) for y1, y2 in zip(ysample[:-1], ysample[1:])] interval_list = [[x, y] for x in xinter for y in yinter] plot_list = [] #recursive call refinepixels which subdivides the intervals which are #neither True nor False according to the expression. def refine_pixels(interval_list): """ Evaluates the intervals and subdivides the interval if the expression is partially satisfied.""" temp_interval_list = [] plot_list = [] for intervals in interval_list: #Convert the array indices to x and y values intervalx = intervals[0] intervaly = intervals[1] func_eval = func(intervalx, intervaly) #The expression is valid in the interval. Change the contour #array values to 1. if func_eval[1] is False or func_eval[0] is False: pass elif func_eval == (True, True): plot_list.append([intervalx, intervaly]) elif func_eval[1] is None or func_eval[0] is None: #Subdivide avgx = intervalx.mid avgy = intervaly.mid a = interval(intervalx.start, avgx) b = interval(avgx, intervalx.end) c = interval(intervaly.start, avgy) d = interval(avgy, intervaly.end) temp_interval_list.append([a, c]) temp_interval_list.append([a, d]) temp_interval_list.append([b, c]) temp_interval_list.append([b, d]) return temp_interval_list, plot_list while k >= 0 and len(interval_list): interval_list, plot_list_temp = refine_pixels(interval_list) plot_list.extend(plot_list_temp) k = k - 1 #Check whether the expression represents an equality #If it represents an equality, then none of the intervals #would have satisfied the expression due to floating point #differences. Add all the undecided values to the plot. if self.has_equality: for intervals in interval_list: intervalx = intervals[0] intervaly = intervals[1] func_eval = func(intervalx, intervaly) if func_eval[1] and func_eval[0] is not False: plot_list.append([intervalx, intervaly]) return plot_list, 'fill' def _get_meshes_grid(self): """Generates the mesh for generating a contour. In the case of equality, ``contour`` function of matplotlib can be used. In other cases, matplotlib's ``contourf`` is used. """ equal = False if isinstance(self.expr, Equality): expr = self.expr.lhs - self.expr.rhs equal = True elif isinstance(self.expr, (GreaterThan, StrictGreaterThan)): expr = self.expr.lhs - self.expr.rhs elif isinstance(self.expr, (LessThan, StrictLessThan)): expr = self.expr.rhs - self.expr.lhs else: raise NotImplementedError("The expression is not supported for " "plotting in uniform meshed plot.") np = import_module('numpy') xarray = np.linspace(self.start_x, self.end_x, self.nb_of_points) yarray = np.linspace(self.start_y, self.end_y, self.nb_of_points) x_grid, y_grid = np.meshgrid(xarray, yarray) func = vectorized_lambdify((self.var_x, self.var_y), expr) z_grid = func(x_grid, y_grid) z_grid[np.ma.where(z_grid < 0)] = -1 z_grid[np.ma.where(z_grid > 0)] = 1 if equal: return xarray, yarray, z_grid, 'contour' else: return xarray, yarray, z_grid, 'contourf' @doctest_depends_on(modules=('matplotlib',)) def plot_implicit(expr, x_var=None, y_var=None, adaptive=True, depth=0, points=300, line_color="blue", show=True, **kwargs): """A plot function to plot implicit equations / inequalities. Arguments ========= - ``expr`` : The equation / inequality that is to be plotted. - ``x_var`` (optional) : symbol to plot on x-axis or tuple giving symbol and range as ``(symbol, xmin, xmax)`` - ``y_var`` (optional) : symbol to plot on y-axis or tuple giving symbol and range as ``(symbol, ymin, ymax)`` If neither ``x_var`` nor ``y_var`` are given then the free symbols in the expression will be assigned in the order they are sorted. The following keyword arguments can also be used: - ``adaptive`` Boolean. The default value is set to True. It has to be set to False if you want to use a mesh grid. - ``depth`` integer. The depth of recursion for adaptive mesh grid. Default value is 0. Takes value in the range (0, 4). - ``points`` integer. The number of points if adaptive mesh grid is not used. Default value is 300. - ``show`` Boolean. Default value is True. If set to False, the plot will not be shown. See ``Plot`` for further information. - ``title`` string. The title for the plot. - ``xlabel`` string. The label for the x-axis - ``ylabel`` string. The label for the y-axis Aesthetics options: - ``line_color``: float or string. Specifies the color for the plot. See ``Plot`` to see how to set color for the plots. Default value is "Blue" plot_implicit, by default, uses interval arithmetic to plot functions. If the expression cannot be plotted using interval arithmetic, it defaults to a generating a contour using a mesh grid of fixed number of points. By setting adaptive to False, you can force plot_implicit to use the mesh grid. The mesh grid method can be effective when adaptive plotting using interval arithmetic, fails to plot with small line width. Examples ======== Plot expressions: .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import plot_implicit, symbols, Eq, And >>> x, y = symbols('x y') Without any ranges for the symbols in the expression: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p1 = plot_implicit(Eq(x**2 + y**2, 5)) With the range for the symbols: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p2 = plot_implicit( ... Eq(x**2 + y**2, 3), (x, -3, 3), (y, -3, 3)) With depth of recursion as argument: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p3 = plot_implicit( ... Eq(x**2 + y**2, 5), (x, -4, 4), (y, -4, 4), depth = 2) Using mesh grid and not using adaptive meshing: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p4 = plot_implicit( ... Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2), ... adaptive=False) Using mesh grid without using adaptive meshing with number of points specified: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p5 = plot_implicit( ... Eq(x**2 + y**2, 5), (x, -5, 5), (y, -2, 2), ... adaptive=False, points=400) Plotting regions: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p6 = plot_implicit(y > x**2) Plotting Using boolean conjunctions: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p7 = plot_implicit(And(y > x, y > -x)) When plotting an expression with a single variable (y - 1, for example), specify the x or the y variable explicitly: .. plot:: :context: close-figs :format: doctest :include-source: True >>> p8 = plot_implicit(y - 1, y_var=y) >>> p9 = plot_implicit(x - 1, x_var=x) """ has_equality = False # Represents whether the expression contains an Equality, #GreaterThan or LessThan def arg_expand(bool_expr): """ Recursively expands the arguments of an Boolean Function """ for arg in bool_expr.args: if isinstance(arg, BooleanFunction): arg_expand(arg) elif isinstance(arg, Relational): arg_list.append(arg) arg_list = [] if isinstance(expr, BooleanFunction): arg_expand(expr) #Check whether there is an equality in the expression provided. if any(isinstance(e, (Equality, GreaterThan, LessThan)) for e in arg_list): has_equality = True elif not isinstance(expr, Relational): expr = Eq(expr, 0) has_equality = True elif isinstance(expr, (Equality, GreaterThan, LessThan)): has_equality = True xyvar = [i for i in (x_var, y_var) if i is not None] free_symbols = expr.free_symbols range_symbols = Tuple(*flatten(xyvar)).free_symbols undeclared = free_symbols - range_symbols if len(free_symbols & range_symbols) > 2: raise NotImplementedError("Implicit plotting is not implemented for " "more than 2 variables") #Create default ranges if the range is not provided. default_range = Tuple(-5, 5) def _range_tuple(s): if isinstance(s, Symbol): return Tuple(s) + default_range if len(s) == 3: return Tuple(*s) raise ValueError('symbol or `(symbol, min, max)` expected but got %s' % s) if len(xyvar) == 0: xyvar = list(_sort_gens(free_symbols)) var_start_end_x = _range_tuple(xyvar[0]) x = var_start_end_x[0] if len(xyvar) != 2: if x in undeclared or not undeclared: xyvar.append(Dummy('f(%s)' % x.name)) else: xyvar.append(undeclared.pop()) var_start_end_y = _range_tuple(xyvar[1]) #Check whether the depth is greater than 4 or less than 0. if depth > 4: depth = 4 elif depth < 0: depth = 0 series_argument = ImplicitSeries(expr, var_start_end_x, var_start_end_y, has_equality, adaptive, depth, points, line_color) #set the x and y limits kwargs['xlim'] = tuple(float(x) for x in var_start_end_x[1:]) kwargs['ylim'] = tuple(float(y) for y in var_start_end_y[1:]) # set the x and y labels kwargs.setdefault('xlabel', var_start_end_x[0].name) kwargs.setdefault('ylabel', var_start_end_y[0].name) p = Plot(series_argument, **kwargs) if show: p.show() return p sympy-sympy-1.9/sympy/plotting/pygletplot/000077500000000000000000000000001412543434000211475ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/pygletplot/__init__.py000066400000000000000000000072241412543434000232650ustar00rootroot00000000000000"""Plotting module that can plot 2D and 3D functions """ from sympy.utilities.decorator import doctest_depends_on @doctest_depends_on(modules=('pyglet',)) def PygletPlot(*args, **kwargs): """ Plot Examples ============= See examples/advanced/pyglet_plotting.py for many more examples. >>> from sympy.plotting.pygletplot import PygletPlot as Plot >>> from sympy.abc import x, y, z >>> Plot(x*y**3-y*x**3) [0]: -x**3*y + x*y**3, 'mode=cartesian' >>> p = Plot() >>> p[1] = x*y >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4) >>> p = Plot() >>> p[1] = x**2+y**2 >>> p[2] = -x**2-y**2 Variable Intervals ================== The basic format is [var, min, max, steps], but the syntax is flexible and arguments left out are taken from the defaults for the current coordinate mode: >>> Plot(x**2) # implies [x,-5,5,100] [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [], []) # [x,-1,1,40], [y,-1,1,40] [0]: x**2, 'mode=cartesian' >>> Plot(x**2-y**2, [100], [100]) # [x,-1,1,100], [y,-1,1,100] [0]: x**2 - y**2, 'mode=cartesian' >>> Plot(x**2, [x,-13,13,100]) [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [-13,13]) # [x,-13,13,100] [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [x,-13,13]) # [x,-13,13,100] [0]: x**2, 'mode=cartesian' >>> Plot(1*x, [], [x], mode='cylindrical') ... # [unbound_theta,0,2*Pi,40], [x,-1,1,20] [0]: x, 'mode=cartesian' Coordinate Modes ================ Plot supports several curvilinear coordinate modes, and they independent for each plotted function. You can specify a coordinate mode explicitly with the 'mode' named argument, but it can be automatically determined for Cartesian or parametric plots, and therefore must only be specified for polar, cylindrical, and spherical modes. Specifically, Plot(function arguments) and Plot[n] = (function arguments) will interpret your arguments as a Cartesian plot if you provide one function and a parametric plot if you provide two or three functions. Similarly, the arguments will be interpreted as a curve if one variable is used, and a surface if two are used. Supported mode names by number of variables: 1: parametric, cartesian, polar 2: parametric, cartesian, cylindrical = polar, spherical >>> Plot(1, mode='spherical') Calculator-like Interface ========================= >>> p = Plot(visible=False) >>> f = x**2 >>> p[1] = f >>> p[2] = f.diff(x) >>> p[3] = f.diff(x).diff(x) >>> p [1]: x**2, 'mode=cartesian' [2]: 2*x, 'mode=cartesian' [3]: 2, 'mode=cartesian' >>> p.show() >>> p.clear() >>> p >>> p[1] = x**2+y**2 >>> p[1].style = 'solid' >>> p[2] = -x**2-y**2 >>> p[2].style = 'wireframe' >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4) >>> p[1].style = 'both' >>> p[2].style = 'both' >>> p.close() Plot Window Keyboard Controls ============================= Screen Rotation: X,Y axis Arrow Keys, A,S,D,W, Numpad 4,6,8,2 Z axis Q,E, Numpad 7,9 Model Rotation: Z axis Z,C, Numpad 1,3 Zoom: R,F, PgUp,PgDn, Numpad +,- Reset Camera: X, Numpad 5 Camera Presets: XY F1 XZ F2 YZ F3 Perspective F4 Sensitivity Modifier: SHIFT Axes Toggle: Visible F5 Colors F6 Close Window: ESCAPE ============================= """ from sympy.plotting.pygletplot.plot import PygletPlot return PygletPlot(*args, **kwargs) sympy-sympy-1.9/sympy/plotting/pygletplot/color_scheme.py000066400000000000000000000302501412543434000241630ustar00rootroot00000000000000from sympy import Basic, Symbol, symbols, lambdify from .util import interpolate, rinterpolate, create_bounds, update_bounds from sympy.utilities.iterables import sift class ColorGradient: colors = [0.4, 0.4, 0.4], [0.9, 0.9, 0.9] intervals = 0.0, 1.0 def __init__(self, *args): if len(args) == 2: self.colors = list(args) self.intervals = [0.0, 1.0] elif len(args) > 0: if len(args) % 2 != 0: raise ValueError("len(args) should be even") self.colors = [args[i] for i in range(1, len(args), 2)] self.intervals = [args[i] for i in range(0, len(args), 2)] assert len(self.colors) == len(self.intervals) def copy(self): c = ColorGradient() c.colors = [e[::] for e in self.colors] c.intervals = self.intervals[::] return c def _find_interval(self, v): m = len(self.intervals) i = 0 while i < m - 1 and self.intervals[i] <= v: i += 1 return i def _interpolate_axis(self, axis, v): i = self._find_interval(v) v = rinterpolate(self.intervals[i - 1], self.intervals[i], v) return interpolate(self.colors[i - 1][axis], self.colors[i][axis], v) def __call__(self, r, g, b): c = self._interpolate_axis return c(0, r), c(1, g), c(2, b) default_color_schemes = {} # defined at the bottom of this file class ColorScheme: def __init__(self, *args, **kwargs): self.args = args self.f, self.gradient = None, ColorGradient() if len(args) == 1 and not isinstance(args[0], Basic) and callable(args[0]): self.f = args[0] elif len(args) == 1 and isinstance(args[0], str): if args[0] in default_color_schemes: cs = default_color_schemes[args[0]] self.f, self.gradient = cs.f, cs.gradient.copy() else: self.f = lambdify('x,y,z,u,v', args[0]) else: self.f, self.gradient = self._interpret_args(args) self._test_color_function() if not isinstance(self.gradient, ColorGradient): raise ValueError("Color gradient not properly initialized. " "(Not a ColorGradient instance.)") def _interpret_args(self, args): f, gradient = None, self.gradient atoms, lists = self._sort_args(args) s = self._pop_symbol_list(lists) s = self._fill_in_vars(s) # prepare the error message for lambdification failure f_str = ', '.join(str(fa) for fa in atoms) s_str = (str(sa) for sa in s) s_str = ', '.join(sa for sa in s_str if sa.find('unbound') < 0) f_error = ValueError("Could not interpret arguments " "%s as functions of %s." % (f_str, s_str)) # try to lambdify args if len(atoms) == 1: fv = atoms[0] try: f = lambdify(s, [fv, fv, fv]) except TypeError: raise f_error elif len(atoms) == 3: fr, fg, fb = atoms try: f = lambdify(s, [fr, fg, fb]) except TypeError: raise f_error else: raise ValueError("A ColorScheme must provide 1 or 3 " "functions in x, y, z, u, and/or v.") # try to intrepret any given color information if len(lists) == 0: gargs = [] elif len(lists) == 1: gargs = lists[0] elif len(lists) == 2: try: (r1, g1, b1), (r2, g2, b2) = lists except TypeError: raise ValueError("If two color arguments are given, " "they must be given in the format " "(r1, g1, b1), (r2, g2, b2).") gargs = lists elif len(lists) == 3: try: (r1, r2), (g1, g2), (b1, b2) = lists except Exception: raise ValueError("If three color arguments are given, " "they must be given in the format " "(r1, r2), (g1, g2), (b1, b2). To create " "a multi-step gradient, use the syntax " "[0, colorStart, step1, color1, ..., 1, " "colorEnd].") gargs = [[r1, g1, b1], [r2, g2, b2]] else: raise ValueError("Don't know what to do with collection " "arguments %s." % (', '.join(str(l) for l in lists))) if gargs: try: gradient = ColorGradient(*gargs) except Exception as ex: raise ValueError(("Could not initialize a gradient " "with arguments %s. Inner " "exception: %s") % (gargs, str(ex))) return f, gradient def _pop_symbol_list(self, lists): symbol_lists = [] for l in lists: mark = True for s in l: if s is not None and not isinstance(s, Symbol): mark = False break if mark: lists.remove(l) symbol_lists.append(l) if len(symbol_lists) == 1: return symbol_lists[0] elif len(symbol_lists) == 0: return [] else: raise ValueError("Only one list of Symbols " "can be given for a color scheme.") def _fill_in_vars(self, args): defaults = symbols('x,y,z,u,v') v_error = ValueError("Could not find what to plot.") if len(args) == 0: return defaults if not isinstance(args, (tuple, list)): raise v_error if len(args) == 0: return defaults for s in args: if s is not None and not isinstance(s, Symbol): raise v_error # when vars are given explicitly, any vars # not given are marked 'unbound' as to not # be accidentally used in an expression vars = [Symbol('unbound%i' % (i)) for i in range(1, 6)] # interpret as t if len(args) == 1: vars[3] = args[0] # interpret as u,v elif len(args) == 2: if args[0] is not None: vars[3] = args[0] if args[1] is not None: vars[4] = args[1] # interpret as x,y,z elif len(args) >= 3: # allow some of x,y,z to be # left unbound if not given if args[0] is not None: vars[0] = args[0] if args[1] is not None: vars[1] = args[1] if args[2] is not None: vars[2] = args[2] # interpret the rest as t if len(args) >= 4: vars[3] = args[3] # ...or u,v if len(args) >= 5: vars[4] = args[4] return vars def _sort_args(self, args): lists, atoms = sift(args, lambda a: isinstance(a, (tuple, list)), binary=True) return atoms, lists def _test_color_function(self): if not callable(self.f): raise ValueError("Color function is not callable.") try: result = self.f(0, 0, 0, 0, 0) if len(result) != 3: raise ValueError("length should be equal to 3") except TypeError: raise ValueError("Color function needs to accept x,y,z,u,v, " "as arguments even if it doesn't use all of them.") except AssertionError: raise ValueError("Color function needs to return 3-tuple r,g,b.") except Exception: pass # color function probably not valid at 0,0,0,0,0 def __call__(self, x, y, z, u, v): try: return self.f(x, y, z, u, v) except Exception: return None def apply_to_curve(self, verts, u_set, set_len=None, inc_pos=None): """ Apply this color scheme to a set of vertices over a single independent variable u. """ bounds = create_bounds() cverts = list() if callable(set_len): set_len(len(u_set)*2) # calculate f() = r,g,b for each vert # and find the min and max for r,g,b for _u in range(len(u_set)): if verts[_u] is None: cverts.append(None) else: x, y, z = verts[_u] u, v = u_set[_u], None c = self(x, y, z, u, v) if c is not None: c = list(c) update_bounds(bounds, c) cverts.append(c) if callable(inc_pos): inc_pos() # scale and apply gradient for _u in range(len(u_set)): if cverts[_u] is not None: for _c in range(3): # scale from [f_min, f_max] to [0,1] cverts[_u][_c] = rinterpolate(bounds[_c][0], bounds[_c][1], cverts[_u][_c]) # apply gradient cverts[_u] = self.gradient(*cverts[_u]) if callable(inc_pos): inc_pos() return cverts def apply_to_surface(self, verts, u_set, v_set, set_len=None, inc_pos=None): """ Apply this color scheme to a set of vertices over two independent variables u and v. """ bounds = create_bounds() cverts = list() if callable(set_len): set_len(len(u_set)*len(v_set)*2) # calculate f() = r,g,b for each vert # and find the min and max for r,g,b for _u in range(len(u_set)): column = list() for _v in range(len(v_set)): if verts[_u][_v] is None: column.append(None) else: x, y, z = verts[_u][_v] u, v = u_set[_u], v_set[_v] c = self(x, y, z, u, v) if c is not None: c = list(c) update_bounds(bounds, c) column.append(c) if callable(inc_pos): inc_pos() cverts.append(column) # scale and apply gradient for _u in range(len(u_set)): for _v in range(len(v_set)): if cverts[_u][_v] is not None: # scale from [f_min, f_max] to [0,1] for _c in range(3): cverts[_u][_v][_c] = rinterpolate(bounds[_c][0], bounds[_c][1], cverts[_u][_v][_c]) # apply gradient cverts[_u][_v] = self.gradient(*cverts[_u][_v]) if callable(inc_pos): inc_pos() return cverts def str_base(self): return ", ".join(str(a) for a in self.args) def __repr__(self): return "%s" % (self.str_base()) x, y, z, t, u, v = symbols('x,y,z,t,u,v') default_color_schemes['rainbow'] = ColorScheme(z, y, x) default_color_schemes['zfade'] = ColorScheme(z, (0.4, 0.4, 0.97), (0.97, 0.4, 0.4), (None, None, z)) default_color_schemes['zfade3'] = ColorScheme(z, (None, None, z), [0.00, (0.2, 0.2, 1.0), 0.35, (0.2, 0.8, 0.4), 0.50, (0.3, 0.9, 0.3), 0.65, (0.4, 0.8, 0.2), 1.00, (1.0, 0.2, 0.2)]) default_color_schemes['zfade4'] = ColorScheme(z, (None, None, z), [0.0, (0.3, 0.3, 1.0), 0.30, (0.3, 1.0, 0.3), 0.55, (0.95, 1.0, 0.2), 0.65, (1.0, 0.95, 0.2), 0.85, (1.0, 0.7, 0.2), 1.0, (1.0, 0.3, 0.2)]) sympy-sympy-1.9/sympy/plotting/pygletplot/managed_window.py000066400000000000000000000057701412543434000245150ustar00rootroot00000000000000from pyglet.window import Window from pyglet.clock import Clock from threading import Thread, Lock gl_lock = Lock() class ManagedWindow(Window): """ A pyglet window with an event loop which executes automatically in a separate thread. Behavior is added by creating a subclass which overrides setup, update, and/or draw. """ fps_limit = 30 default_win_args = dict(width=600, height=500, vsync=False, resizable=True) def __init__(self, **win_args): """ It is best not to override this function in the child class, unless you need to take additional arguments. Do any OpenGL initialization calls in setup(). """ # check if this is run from the doctester if win_args.get('runfromdoctester', False): return self.win_args = dict(self.default_win_args, **win_args) self.Thread = Thread(target=self.__event_loop__) self.Thread.start() def __event_loop__(self, **win_args): """ The event loop thread function. Do not override or call directly (it is called by __init__). """ gl_lock.acquire() try: try: super().__init__(**self.win_args) self.switch_to() self.setup() except Exception as e: print("Window initialization failed: %s" % (str(e))) self.has_exit = True finally: gl_lock.release() clock = Clock() clock.fps_limit = self.fps_limit while not self.has_exit: dt = clock.tick() gl_lock.acquire() try: try: self.switch_to() self.dispatch_events() self.clear() self.update(dt) self.draw() self.flip() except Exception as e: print("Uncaught exception in event loop: %s" % str(e)) self.has_exit = True finally: gl_lock.release() super().close() def close(self): """ Closes the window. """ self.has_exit = True def setup(self): """ Called once before the event loop begins. Override this method in a child class. This is the best place to put things like OpenGL initialization calls. """ pass def update(self, dt): """ Called before draw during each iteration of the event loop. dt is the elapsed time in seconds since the last update. OpenGL rendering calls are best put in draw() rather than here. """ pass def draw(self): """ Called after update during each iteration of the event loop. Put OpenGL rendering calls here. """ pass if __name__ == '__main__': ManagedWindow() sympy-sympy-1.9/sympy/plotting/pygletplot/plot.py000066400000000000000000000320141412543434000224770ustar00rootroot00000000000000from threading import RLock # it is sufficient to import "pyglet" here once try: import pyglet.gl as pgl except ImportError: raise ImportError("pyglet is required for plotting.\n " "visit http://www.pyglet.org/") from sympy.core.compatibility import is_sequence, SYMPY_INTS from sympy.core.numbers import Integer from sympy.geometry.entity import GeometryEntity from sympy.plotting.pygletplot.plot_axes import PlotAxes from sympy.plotting.pygletplot.plot_mode import PlotMode from sympy.plotting.pygletplot.plot_object import PlotObject from sympy.plotting.pygletplot.plot_window import PlotWindow from sympy.plotting.pygletplot.util import parse_option_string from sympy.utilities.decorator import doctest_depends_on from time import sleep from os import getcwd, listdir import ctypes @doctest_depends_on(modules=('pyglet',)) class PygletPlot: """ Plot Examples ============= See examples/advanced/pyglet_plotting.py for many more examples. >>> from sympy.plotting.pygletplot import PygletPlot as Plot >>> from sympy.abc import x, y, z >>> Plot(x*y**3-y*x**3) [0]: -x**3*y + x*y**3, 'mode=cartesian' >>> p = Plot() >>> p[1] = x*y >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4) >>> p = Plot() >>> p[1] = x**2+y**2 >>> p[2] = -x**2-y**2 Variable Intervals ================== The basic format is [var, min, max, steps], but the syntax is flexible and arguments left out are taken from the defaults for the current coordinate mode: >>> Plot(x**2) # implies [x,-5,5,100] [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [], []) # [x,-1,1,40], [y,-1,1,40] [0]: x**2, 'mode=cartesian' >>> Plot(x**2-y**2, [100], [100]) # [x,-1,1,100], [y,-1,1,100] [0]: x**2 - y**2, 'mode=cartesian' >>> Plot(x**2, [x,-13,13,100]) [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [-13,13]) # [x,-13,13,100] [0]: x**2, 'mode=cartesian' >>> Plot(x**2, [x,-13,13]) # [x,-13,13,10] [0]: x**2, 'mode=cartesian' >>> Plot(1*x, [], [x], mode='cylindrical') ... # [unbound_theta,0,2*Pi,40], [x,-1,1,20] [0]: x, 'mode=cartesian' Coordinate Modes ================ Plot supports several curvilinear coordinate modes, and they independent for each plotted function. You can specify a coordinate mode explicitly with the 'mode' named argument, but it can be automatically determined for Cartesian or parametric plots, and therefore must only be specified for polar, cylindrical, and spherical modes. Specifically, Plot(function arguments) and Plot[n] = (function arguments) will interpret your arguments as a Cartesian plot if you provide one function and a parametric plot if you provide two or three functions. Similarly, the arguments will be interpreted as a curve if one variable is used, and a surface if two are used. Supported mode names by number of variables: 1: parametric, cartesian, polar 2: parametric, cartesian, cylindrical = polar, spherical >>> Plot(1, mode='spherical') Calculator-like Interface ========================= >>> p = Plot(visible=False) >>> f = x**2 >>> p[1] = f >>> p[2] = f.diff(x) >>> p[3] = f.diff(x).diff(x) >>> p [1]: x**2, 'mode=cartesian' [2]: 2*x, 'mode=cartesian' [3]: 2, 'mode=cartesian' >>> p.show() >>> p.clear() >>> p >>> p[1] = x**2+y**2 >>> p[1].style = 'solid' >>> p[2] = -x**2-y**2 >>> p[2].style = 'wireframe' >>> p[1].color = z, (0.4,0.4,0.9), (0.9,0.4,0.4) >>> p[1].style = 'both' >>> p[2].style = 'both' >>> p.close() Plot Window Keyboard Controls ============================= Screen Rotation: X,Y axis Arrow Keys, A,S,D,W, Numpad 4,6,8,2 Z axis Q,E, Numpad 7,9 Model Rotation: Z axis Z,C, Numpad 1,3 Zoom: R,F, PgUp,PgDn, Numpad +,- Reset Camera: X, Numpad 5 Camera Presets: XY F1 XZ F2 YZ F3 Perspective F4 Sensitivity Modifier: SHIFT Axes Toggle: Visible F5 Colors F6 Close Window: ESCAPE ============================= """ @doctest_depends_on(modules=('pyglet',)) def __init__(self, *fargs, **win_args): """ Positional Arguments ==================== Any given positional arguments are used to initialize a plot function at index 1. In other words... >>> from sympy.plotting.pygletplot import PygletPlot as Plot >>> from sympy.abc import x >>> p = Plot(x**2, visible=False) ...is equivalent to... >>> p = Plot(visible=False) >>> p[1] = x**2 Note that in earlier versions of the plotting module, you were able to specify multiple functions in the initializer. This functionality has been dropped in favor of better automatic plot plot_mode detection. Named Arguments =============== axes An option string of the form "key1=value1; key2 = value2" which can use the following options: style = ordinate none OR frame OR box OR ordinate stride = 0.25 val OR (val_x, val_y, val_z) overlay = True (draw on top of plot) True OR False colored = False (False uses Black, True uses colors R,G,B = X,Y,Z) True OR False label_axes = False (display axis names at endpoints) True OR False visible = True (show immediately True OR False The following named arguments are passed as arguments to window initialization: antialiasing = True True OR False ortho = False True OR False invert_mouse_zoom = False True OR False """ # Register the plot modes from . import plot_modes # noqa self._win_args = win_args self._window = None self._render_lock = RLock() self._functions = {} self._pobjects = [] self._screenshot = ScreenShot(self) axe_options = parse_option_string(win_args.pop('axes', '')) self.axes = PlotAxes(**axe_options) self._pobjects.append(self.axes) self[0] = fargs if win_args.get('visible', True): self.show() ## Window Interfaces def show(self): """ Creates and displays a plot window, or activates it (gives it focus) if it has already been created. """ if self._window and not self._window.has_exit: self._window.activate() else: self._win_args['visible'] = True self.axes.reset_resources() #if hasattr(self, '_doctest_depends_on'): # self._win_args['runfromdoctester'] = True self._window = PlotWindow(self, **self._win_args) def close(self): """ Closes the plot window. """ if self._window: self._window.close() def saveimage(self, outfile=None, format='', size=(600, 500)): """ Saves a screen capture of the plot window to an image file. If outfile is given, it can either be a path or a file object. Otherwise a png image will be saved to the current working directory. If the format is omitted, it is determined from the filename extension. """ self._screenshot.save(outfile, format, size) ## Function List Interfaces def clear(self): """ Clears the function list of this plot. """ self._render_lock.acquire() self._functions = {} self.adjust_all_bounds() self._render_lock.release() def __getitem__(self, i): """ Returns the function at position i in the function list. """ return self._functions[i] def __setitem__(self, i, args): """ Parses and adds a PlotMode to the function list. """ if not (isinstance(i, (SYMPY_INTS, Integer)) and i >= 0): raise ValueError("Function index must " "be an integer >= 0.") if isinstance(args, PlotObject): f = args else: if (not is_sequence(args)) or isinstance(args, GeometryEntity): args = [args] if len(args) == 0: return # no arguments given kwargs = dict(bounds_callback=self.adjust_all_bounds) f = PlotMode(*args, **kwargs) if f: self._render_lock.acquire() self._functions[i] = f self._render_lock.release() else: raise ValueError("Failed to parse '%s'." % ', '.join(str(a) for a in args)) def __delitem__(self, i): """ Removes the function in the function list at position i. """ self._render_lock.acquire() del self._functions[i] self.adjust_all_bounds() self._render_lock.release() def firstavailableindex(self): """ Returns the first unused index in the function list. """ i = 0 self._render_lock.acquire() while i in self._functions: i += 1 self._render_lock.release() return i def append(self, *args): """ Parses and adds a PlotMode to the function list at the first available index. """ self.__setitem__(self.firstavailableindex(), args) def __len__(self): """ Returns the number of functions in the function list. """ return len(self._functions) def __iter__(self): """ Allows iteration of the function list. """ return self._functions.itervalues() def __repr__(self): return str(self) def __str__(self): """ Returns a string containing a new-line separated list of the functions in the function list. """ s = "" if len(self._functions) == 0: s += "" else: self._render_lock.acquire() s += "\n".join(["%s[%i]: %s" % ("", i, str(self._functions[i])) for i in self._functions]) self._render_lock.release() return s def adjust_all_bounds(self): self._render_lock.acquire() self.axes.reset_bounding_box() for f in self._functions: self.axes.adjust_bounds(self._functions[f].bounds) self._render_lock.release() def wait_for_calculations(self): sleep(0) self._render_lock.acquire() for f in self._functions: a = self._functions[f]._get_calculating_verts b = self._functions[f]._get_calculating_cverts while a() or b(): sleep(0) self._render_lock.release() class ScreenShot: def __init__(self, plot): self._plot = plot self.screenshot_requested = False self.outfile = None self.format = '' self.invisibleMode = False self.flag = 0 def __bool__(self): return self.screenshot_requested def _execute_saving(self): if self.flag < 3: self.flag += 1 return size_x, size_y = self._plot._window.get_size() size = size_x*size_y*4*ctypes.sizeof(ctypes.c_ubyte) image = ctypes.create_string_buffer(size) pgl.glReadPixels(0, 0, size_x, size_y, pgl.GL_RGBA, pgl.GL_UNSIGNED_BYTE, image) from PIL import Image im = Image.frombuffer('RGBA', (size_x, size_y), image.raw, 'raw', 'RGBA', 0, 1) im.transpose(Image.FLIP_TOP_BOTTOM).save(self.outfile, self.format) self.flag = 0 self.screenshot_requested = False if self.invisibleMode: self._plot._window.close() def save(self, outfile=None, format='', size=(600, 500)): self.outfile = outfile self.format = format self.size = size self.screenshot_requested = True if not self._plot._window or self._plot._window.has_exit: self._plot._win_args['visible'] = False self._plot._win_args['width'] = size[0] self._plot._win_args['height'] = size[1] self._plot.axes.reset_resources() self._plot._window = PlotWindow(self._plot, **self._plot._win_args) self.invisibleMode = True if self.outfile is None: self.outfile = self._create_unique_path() print(self.outfile) def _create_unique_path(self): cwd = getcwd() l = listdir(cwd) path = '' i = 0 while True: if not 'plot_%s.png' % i in l: path = cwd + '/plot_%s.png' % i break i += 1 return path sympy-sympy-1.9/sympy/plotting/pygletplot/plot_axes.py000066400000000000000000000207171412543434000235260ustar00rootroot00000000000000import pyglet.gl as pgl from pyglet import font from sympy.core import S from sympy.core.compatibility import is_sequence from sympy.plotting.pygletplot.plot_object import PlotObject from sympy.plotting.pygletplot.util import billboard_matrix, dot_product, \ get_direction_vectors, strided_range, vec_mag, vec_sub class PlotAxes(PlotObject): def __init__(self, *args, style='', none=None, frame=None, box=None, ordinate=None, stride=0.25, visible='', overlay='', colored='', label_axes='', label_ticks='', tick_length=0.1, font_face='Arial', font_size=28, **kwargs): # initialize style parameter style = style.lower() # allow alias kwargs to override style kwarg if none is not None: style = 'none' if frame is not None: style = 'frame' if box is not None: style = 'box' if ordinate is not None: style = 'ordinate' if style in ['', 'ordinate']: self._render_object = PlotAxesOrdinate(self) elif style in ['frame', 'box']: self._render_object = PlotAxesFrame(self) elif style in ['none']: self._render_object = None else: raise ValueError(("Unrecognized axes style %s.") % (style)) # initialize stride parameter try: stride = eval(stride) except TypeError: pass if is_sequence(stride): if len(stride) != 3: raise ValueError("length should be equal to 3") self._stride = stride else: self._stride = [stride, stride, stride] self._tick_length = float(tick_length) # setup bounding box and ticks self._origin = [0, 0, 0] self.reset_bounding_box() def flexible_boolean(input, default): if input in [True, False]: return input if input in ['f', 'F', 'false', 'False']: return False if input in ['t', 'T', 'true', 'True']: return True return default # initialize remaining parameters self.visible = flexible_boolean(kwargs, True) self._overlay = flexible_boolean(overlay, True) self._colored = flexible_boolean(colored, False) self._label_axes = flexible_boolean(label_axes, False) self._label_ticks = flexible_boolean(label_ticks, True) # setup label font self.font_face = font_face self.font_size = font_size # this is also used to reinit the # font on window close/reopen self.reset_resources() def reset_resources(self): self.label_font = None def reset_bounding_box(self): self._bounding_box = [[None, None], [None, None], [None, None]] self._axis_ticks = [[], [], []] def draw(self): if self._render_object: pgl.glPushAttrib(pgl.GL_ENABLE_BIT | pgl.GL_POLYGON_BIT | pgl.GL_DEPTH_BUFFER_BIT) if self._overlay: pgl.glDisable(pgl.GL_DEPTH_TEST) self._render_object.draw() pgl.glPopAttrib() def adjust_bounds(self, child_bounds): b = self._bounding_box c = child_bounds for i in [0, 1, 2]: if abs(c[i][0]) is S.Infinity or abs(c[i][1]) is S.Infinity: continue b[i][0] = c[i][0] if b[i][0] is None else min([b[i][0], c[i][0]]) b[i][1] = c[i][1] if b[i][1] is None else max([b[i][1], c[i][1]]) self._bounding_box = b self._recalculate_axis_ticks(i) def _recalculate_axis_ticks(self, axis): b = self._bounding_box if b[axis][0] is None or b[axis][1] is None: self._axis_ticks[axis] = [] else: self._axis_ticks[axis] = strided_range(b[axis][0], b[axis][1], self._stride[axis]) def toggle_visible(self): self.visible = not self.visible def toggle_colors(self): self._colored = not self._colored class PlotAxesBase(PlotObject): def __init__(self, parent_axes): self._p = parent_axes def draw(self): color = [([0.2, 0.1, 0.3], [0.2, 0.1, 0.3], [0.2, 0.1, 0.3]), ([0.9, 0.3, 0.5], [0.5, 1.0, 0.5], [0.3, 0.3, 0.9])][self._p._colored] self.draw_background(color) self.draw_axis(2, color[2]) self.draw_axis(1, color[1]) self.draw_axis(0, color[0]) def draw_background(self, color): pass # optional def draw_axis(self, axis, color): raise NotImplementedError() def draw_text(self, text, position, color, scale=1.0): if len(color) == 3: color = (color[0], color[1], color[2], 1.0) if self._p.label_font is None: self._p.label_font = font.load(self._p.font_face, self._p.font_size, bold=True, italic=False) label = font.Text(self._p.label_font, text, color=color, valign=font.Text.BASELINE, halign=font.Text.CENTER) pgl.glPushMatrix() pgl.glTranslatef(*position) billboard_matrix() scale_factor = 0.005 * scale pgl.glScalef(scale_factor, scale_factor, scale_factor) pgl.glColor4f(0, 0, 0, 0) label.draw() pgl.glPopMatrix() def draw_line(self, v, color): o = self._p._origin pgl.glBegin(pgl.GL_LINES) pgl.glColor3f(*color) pgl.glVertex3f(v[0][0] + o[0], v[0][1] + o[1], v[0][2] + o[2]) pgl.glVertex3f(v[1][0] + o[0], v[1][1] + o[1], v[1][2] + o[2]) pgl.glEnd() class PlotAxesOrdinate(PlotAxesBase): def __init__(self, parent_axes): super().__init__(parent_axes) def draw_axis(self, axis, color): ticks = self._p._axis_ticks[axis] radius = self._p._tick_length / 2.0 if len(ticks) < 2: return # calculate the vector for this axis axis_lines = [[0, 0, 0], [0, 0, 0]] axis_lines[0][axis], axis_lines[1][axis] = ticks[0], ticks[-1] axis_vector = vec_sub(axis_lines[1], axis_lines[0]) # calculate angle to the z direction vector pos_z = get_direction_vectors()[2] d = abs(dot_product(axis_vector, pos_z)) d = d / vec_mag(axis_vector) # don't draw labels if we're looking down the axis labels_visible = abs(d - 1.0) > 0.02 # draw the ticks and labels for tick in ticks: self.draw_tick_line(axis, color, radius, tick, labels_visible) # draw the axis line and labels self.draw_axis_line(axis, color, ticks[0], ticks[-1], labels_visible) def draw_axis_line(self, axis, color, a_min, a_max, labels_visible): axis_line = [[0, 0, 0], [0, 0, 0]] axis_line[0][axis], axis_line[1][axis] = a_min, a_max self.draw_line(axis_line, color) if labels_visible: self.draw_axis_line_labels(axis, color, axis_line) def draw_axis_line_labels(self, axis, color, axis_line): if not self._p._label_axes: return axis_labels = [axis_line[0][::], axis_line[1][::]] axis_labels[0][axis] -= 0.3 axis_labels[1][axis] += 0.3 a_str = ['X', 'Y', 'Z'][axis] self.draw_text("-" + a_str, axis_labels[0], color) self.draw_text("+" + a_str, axis_labels[1], color) def draw_tick_line(self, axis, color, radius, tick, labels_visible): tick_axis = {0: 1, 1: 0, 2: 1}[axis] tick_line = [[0, 0, 0], [0, 0, 0]] tick_line[0][axis] = tick_line[1][axis] = tick tick_line[0][tick_axis], tick_line[1][tick_axis] = -radius, radius self.draw_line(tick_line, color) if labels_visible: self.draw_tick_line_label(axis, color, radius, tick) def draw_tick_line_label(self, axis, color, radius, tick): if not self._p._label_axes: return tick_label_vector = [0, 0, 0] tick_label_vector[axis] = tick tick_label_vector[{0: 1, 1: 0, 2: 1}[axis]] = [-1, 1, 1][ axis] * radius * 3.5 self.draw_text(str(tick), tick_label_vector, color, scale=0.5) class PlotAxesFrame(PlotAxesBase): def __init__(self, parent_axes): super().__init__(parent_axes) def draw_background(self, color): pass def draw_axis(self, axis, color): raise NotImplementedError() sympy-sympy-1.9/sympy/plotting/pygletplot/plot_camera.py000066400000000000000000000076411412543434000240170ustar00rootroot00000000000000import pyglet.gl as pgl from sympy.plotting.pygletplot.plot_rotation import get_spherical_rotatation from sympy.plotting.pygletplot.util import get_model_matrix, model_to_screen, \ screen_to_model, vec_subs class PlotCamera: min_dist = 0.05 max_dist = 500.0 min_ortho_dist = 100.0 max_ortho_dist = 10000.0 _default_dist = 6.0 _default_ortho_dist = 600.0 rot_presets = { 'xy': (0, 0, 0), 'xz': (-90, 0, 0), 'yz': (0, 90, 0), 'perspective': (-45, 0, -45) } def __init__(self, window, ortho=False): self.window = window self.axes = self.window.plot.axes self.ortho = ortho self.reset() def init_rot_matrix(self): pgl.glPushMatrix() pgl.glLoadIdentity() self._rot = get_model_matrix() pgl.glPopMatrix() def set_rot_preset(self, preset_name): self.init_rot_matrix() try: r = self.rot_presets[preset_name] except AttributeError: raise ValueError( "%s is not a valid rotation preset." % preset_name) try: self.euler_rotate(r[0], 1, 0, 0) self.euler_rotate(r[1], 0, 1, 0) self.euler_rotate(r[2], 0, 0, 1) except AttributeError: pass def reset(self): self._dist = 0.0 self._x, self._y = 0.0, 0.0 self._rot = None if self.ortho: self._dist = self._default_ortho_dist else: self._dist = self._default_dist self.init_rot_matrix() def mult_rot_matrix(self, rot): pgl.glPushMatrix() pgl.glLoadMatrixf(rot) pgl.glMultMatrixf(self._rot) self._rot = get_model_matrix() pgl.glPopMatrix() def setup_projection(self): pgl.glMatrixMode(pgl.GL_PROJECTION) pgl.glLoadIdentity() if self.ortho: # yep, this is pseudo ortho (don't tell anyone) pgl.gluPerspective( 0.3, float(self.window.width)/float(self.window.height), self.min_ortho_dist - 0.01, self.max_ortho_dist + 0.01) else: pgl.gluPerspective( 30.0, float(self.window.width)/float(self.window.height), self.min_dist - 0.01, self.max_dist + 0.01) pgl.glMatrixMode(pgl.GL_MODELVIEW) def _get_scale(self): return 1.0, 1.0, 1.0 def apply_transformation(self): pgl.glLoadIdentity() pgl.glTranslatef(self._x, self._y, -self._dist) if self._rot is not None: pgl.glMultMatrixf(self._rot) pgl.glScalef(*self._get_scale()) def spherical_rotate(self, p1, p2, sensitivity=1.0): mat = get_spherical_rotatation(p1, p2, self.window.width, self.window.height, sensitivity) if mat is not None: self.mult_rot_matrix(mat) def euler_rotate(self, angle, x, y, z): pgl.glPushMatrix() pgl.glLoadMatrixf(self._rot) pgl.glRotatef(angle, x, y, z) self._rot = get_model_matrix() pgl.glPopMatrix() def zoom_relative(self, clicks, sensitivity): if self.ortho: dist_d = clicks * sensitivity * 50.0 min_dist = self.min_ortho_dist max_dist = self.max_ortho_dist else: dist_d = clicks * sensitivity min_dist = self.min_dist max_dist = self.max_dist new_dist = (self._dist - dist_d) if (clicks < 0 and new_dist < max_dist) or new_dist > min_dist: self._dist = new_dist def mouse_translate(self, x, y, dx, dy): pgl.glPushMatrix() pgl.glLoadIdentity() pgl.glTranslatef(0, 0, -self._dist) z = model_to_screen(0, 0, 0)[2] d = vec_subs(screen_to_model(x, y, z), screen_to_model(x - dx, y - dy, z)) pgl.glPopMatrix() self._x += d[0] self._y += d[1] sympy-sympy-1.9/sympy/plotting/pygletplot/plot_controller.py000066400000000000000000000154351412543434000247520ustar00rootroot00000000000000from pyglet.window import key from pyglet.window.mouse import LEFT, RIGHT, MIDDLE from sympy.plotting.pygletplot.util import get_direction_vectors, get_basis_vectors class PlotController: normal_mouse_sensitivity = 4.0 modified_mouse_sensitivity = 1.0 normal_key_sensitivity = 160.0 modified_key_sensitivity = 40.0 keymap = { key.LEFT: 'left', key.A: 'left', key.NUM_4: 'left', key.RIGHT: 'right', key.D: 'right', key.NUM_6: 'right', key.UP: 'up', key.W: 'up', key.NUM_8: 'up', key.DOWN: 'down', key.S: 'down', key.NUM_2: 'down', key.Z: 'rotate_z_neg', key.NUM_1: 'rotate_z_neg', key.C: 'rotate_z_pos', key.NUM_3: 'rotate_z_pos', key.Q: 'spin_left', key.NUM_7: 'spin_left', key.E: 'spin_right', key.NUM_9: 'spin_right', key.X: 'reset_camera', key.NUM_5: 'reset_camera', key.NUM_ADD: 'zoom_in', key.PAGEUP: 'zoom_in', key.R: 'zoom_in', key.NUM_SUBTRACT: 'zoom_out', key.PAGEDOWN: 'zoom_out', key.F: 'zoom_out', key.RSHIFT: 'modify_sensitivity', key.LSHIFT: 'modify_sensitivity', key.F1: 'rot_preset_xy', key.F2: 'rot_preset_xz', key.F3: 'rot_preset_yz', key.F4: 'rot_preset_perspective', key.F5: 'toggle_axes', key.F6: 'toggle_axe_colors', key.F8: 'save_image' } def __init__(self, window, *, invert_mouse_zoom=False, **kwargs): self.invert_mouse_zoom = invert_mouse_zoom self.window = window self.camera = window.camera self.action = { # Rotation around the view Y (up) vector 'left': False, 'right': False, # Rotation around the view X vector 'up': False, 'down': False, # Rotation around the view Z vector 'spin_left': False, 'spin_right': False, # Rotation around the model Z vector 'rotate_z_neg': False, 'rotate_z_pos': False, # Reset to the default rotation 'reset_camera': False, # Performs camera z-translation 'zoom_in': False, 'zoom_out': False, # Use alternative sensitivity (speed) 'modify_sensitivity': False, # Rotation presets 'rot_preset_xy': False, 'rot_preset_xz': False, 'rot_preset_yz': False, 'rot_preset_perspective': False, # axes 'toggle_axes': False, 'toggle_axe_colors': False, # screenshot 'save_image': False } def update(self, dt): z = 0 if self.action['zoom_out']: z -= 1 if self.action['zoom_in']: z += 1 if z != 0: self.camera.zoom_relative(z/10.0, self.get_key_sensitivity()/10.0) dx, dy, dz = 0, 0, 0 if self.action['left']: dx -= 1 if self.action['right']: dx += 1 if self.action['up']: dy -= 1 if self.action['down']: dy += 1 if self.action['spin_left']: dz += 1 if self.action['spin_right']: dz -= 1 if not self.is_2D(): if dx != 0: self.camera.euler_rotate(dx*dt*self.get_key_sensitivity(), *(get_direction_vectors()[1])) if dy != 0: self.camera.euler_rotate(dy*dt*self.get_key_sensitivity(), *(get_direction_vectors()[0])) if dz != 0: self.camera.euler_rotate(dz*dt*self.get_key_sensitivity(), *(get_direction_vectors()[2])) else: self.camera.mouse_translate(0, 0, dx*dt*self.get_key_sensitivity(), -dy*dt*self.get_key_sensitivity()) rz = 0 if self.action['rotate_z_neg'] and not self.is_2D(): rz -= 1 if self.action['rotate_z_pos'] and not self.is_2D(): rz += 1 if rz != 0: self.camera.euler_rotate(rz*dt*self.get_key_sensitivity(), *(get_basis_vectors()[2])) if self.action['reset_camera']: self.camera.reset() if self.action['rot_preset_xy']: self.camera.set_rot_preset('xy') if self.action['rot_preset_xz']: self.camera.set_rot_preset('xz') if self.action['rot_preset_yz']: self.camera.set_rot_preset('yz') if self.action['rot_preset_perspective']: self.camera.set_rot_preset('perspective') if self.action['toggle_axes']: self.action['toggle_axes'] = False self.camera.axes.toggle_visible() if self.action['toggle_axe_colors']: self.action['toggle_axe_colors'] = False self.camera.axes.toggle_colors() if self.action['save_image']: self.action['save_image'] = False self.window.plot.saveimage() return True def get_mouse_sensitivity(self): if self.action['modify_sensitivity']: return self.modified_mouse_sensitivity else: return self.normal_mouse_sensitivity def get_key_sensitivity(self): if self.action['modify_sensitivity']: return self.modified_key_sensitivity else: return self.normal_key_sensitivity def on_key_press(self, symbol, modifiers): if symbol in self.keymap: self.action[self.keymap[symbol]] = True def on_key_release(self, symbol, modifiers): if symbol in self.keymap: self.action[self.keymap[symbol]] = False def on_mouse_drag(self, x, y, dx, dy, buttons, modifiers): if buttons & LEFT: if self.is_2D(): self.camera.mouse_translate(x, y, dx, dy) else: self.camera.spherical_rotate((x - dx, y - dy), (x, y), self.get_mouse_sensitivity()) if buttons & MIDDLE: self.camera.zoom_relative([1, -1][self.invert_mouse_zoom]*dy, self.get_mouse_sensitivity()/20.0) if buttons & RIGHT: self.camera.mouse_translate(x, y, dx, dy) def on_mouse_scroll(self, x, y, dx, dy): self.camera.zoom_relative([1, -1][self.invert_mouse_zoom]*dy, self.get_mouse_sensitivity()) def is_2D(self): functions = self.window.plot._functions for i in functions: if len(functions[i].i_vars) > 1 or len(functions[i].d_vars) > 2: return False return True sympy-sympy-1.9/sympy/plotting/pygletplot/plot_curve.py000066400000000000000000000054321412543434000237070ustar00rootroot00000000000000import pyglet.gl as pgl from sympy.core import S from sympy.plotting.pygletplot.plot_mode_base import PlotModeBase class PlotCurve(PlotModeBase): style_override = 'wireframe' def _on_calculate_verts(self): self.t_interval = self.intervals[0] self.t_set = list(self.t_interval.frange()) self.bounds = [[S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0]] evaluate = self._get_evaluator() self._calculating_verts_pos = 0.0 self._calculating_verts_len = float(self.t_interval.v_len) self.verts = list() b = self.bounds for t in self.t_set: try: _e = evaluate(t) # calculate vertex except (NameError, ZeroDivisionError): _e = None if _e is not None: # update bounding box for axis in range(3): b[axis][0] = min([b[axis][0], _e[axis]]) b[axis][1] = max([b[axis][1], _e[axis]]) self.verts.append(_e) self._calculating_verts_pos += 1.0 for axis in range(3): b[axis][2] = b[axis][1] - b[axis][0] if b[axis][2] == 0.0: b[axis][2] = 1.0 self.push_wireframe(self.draw_verts(False)) def _on_calculate_cverts(self): if not self.verts or not self.color: return def set_work_len(n): self._calculating_cverts_len = float(n) def inc_work_pos(): self._calculating_cverts_pos += 1.0 set_work_len(1) self._calculating_cverts_pos = 0 self.cverts = self.color.apply_to_curve(self.verts, self.t_set, set_len=set_work_len, inc_pos=inc_work_pos) self.push_wireframe(self.draw_verts(True)) def calculate_one_cvert(self, t): vert = self.verts[t] return self.color(vert[0], vert[1], vert[2], self.t_set[t], None) def draw_verts(self, use_cverts): def f(): pgl.glBegin(pgl.GL_LINE_STRIP) for t in range(len(self.t_set)): p = self.verts[t] if p is None: pgl.glEnd() pgl.glBegin(pgl.GL_LINE_STRIP) continue if use_cverts: c = self.cverts[t] if c is None: c = (0, 0, 0) pgl.glColor3f(*c) else: pgl.glColor3f(*self.default_wireframe_color) pgl.glVertex3f(*p) pgl.glEnd() return f sympy-sympy-1.9/sympy/plotting/pygletplot/plot_interval.py000066400000000000000000000123621412543434000244070ustar00rootroot00000000000000from sympy import Symbol, sympify from sympy.core.numbers import Integer class PlotInterval: """ """ _v, _v_min, _v_max, _v_steps = None, None, None, None def require_all_args(f): def check(self, *args, **kwargs): for g in [self._v, self._v_min, self._v_max, self._v_steps]: if g is None: raise ValueError("PlotInterval is incomplete.") return f(self, *args, **kwargs) return check def __init__(self, *args): if len(args) == 1: if isinstance(args[0], PlotInterval): self.fill_from(args[0]) return elif isinstance(args[0], str): try: args = eval(args[0]) except TypeError: s_eval_error = "Could not interpret string %s." raise ValueError(s_eval_error % (args[0])) elif isinstance(args[0], (tuple, list)): args = args[0] else: raise ValueError("Not an interval.") if not isinstance(args, (tuple, list)) or len(args) > 4: f_error = "PlotInterval must be a tuple or list of length 4 or less." raise ValueError(f_error) args = list(args) if len(args) > 0 and (args[0] is None or isinstance(args[0], Symbol)): self.v = args.pop(0) if len(args) in [2, 3]: self.v_min = args.pop(0) self.v_max = args.pop(0) if len(args) == 1: self.v_steps = args.pop(0) elif len(args) == 1: self.v_steps = args.pop(0) def get_v(self): return self._v def set_v(self, v): if v is None: self._v = None return if not isinstance(v, Symbol): raise ValueError("v must be a sympy Symbol.") self._v = v def get_v_min(self): return self._v_min def set_v_min(self, v_min): if v_min is None: self._v_min = None return try: self._v_min = sympify(v_min) float(self._v_min.evalf()) except TypeError: raise ValueError("v_min could not be interpreted as a number.") def get_v_max(self): return self._v_max def set_v_max(self, v_max): if v_max is None: self._v_max = None return try: self._v_max = sympify(v_max) float(self._v_max.evalf()) except TypeError: raise ValueError("v_max could not be interpreted as a number.") def get_v_steps(self): return self._v_steps def set_v_steps(self, v_steps): if v_steps is None: self._v_steps = None return if isinstance(v_steps, int): v_steps = Integer(v_steps) elif not isinstance(v_steps, Integer): raise ValueError("v_steps must be an int or sympy Integer.") if v_steps <= Integer(0): raise ValueError("v_steps must be positive.") self._v_steps = v_steps @require_all_args def get_v_len(self): return self.v_steps + 1 v = property(get_v, set_v) v_min = property(get_v_min, set_v_min) v_max = property(get_v_max, set_v_max) v_steps = property(get_v_steps, set_v_steps) v_len = property(get_v_len) def fill_from(self, b): if b.v is not None: self.v = b.v if b.v_min is not None: self.v_min = b.v_min if b.v_max is not None: self.v_max = b.v_max if b.v_steps is not None: self.v_steps = b.v_steps @staticmethod def try_parse(*args): """ Returns a PlotInterval if args can be interpreted as such, otherwise None. """ if len(args) == 1 and isinstance(args[0], PlotInterval): return args[0] try: return PlotInterval(*args) except ValueError: return None def _str_base(self): return ",".join([str(self.v), str(self.v_min), str(self.v_max), str(self.v_steps)]) def __repr__(self): """ A string representing the interval in class constructor form. """ return "PlotInterval(%s)" % (self._str_base()) def __str__(self): """ A string representing the interval in list form. """ return "[%s]" % (self._str_base()) @require_all_args def assert_complete(self): pass @require_all_args def vrange(self): """ Yields v_steps+1 sympy numbers ranging from v_min to v_max. """ d = (self.v_max - self.v_min) / self.v_steps for i in range(self.v_steps + 1): a = self.v_min + (d * Integer(i)) yield a @require_all_args def vrange2(self): """ Yields v_steps pairs of sympy numbers ranging from (v_min, v_min + step) to (v_max - step, v_max). """ d = (self.v_max - self.v_min) / self.v_steps a = self.v_min + (d * Integer(0)) for i in range(self.v_steps): b = self.v_min + (d * Integer(i + 1)) yield a, b a = b def frange(self): for i in self.vrange(): yield float(i.evalf()) sympy-sympy-1.9/sympy/plotting/pygletplot/plot_mode.py000066400000000000000000000334411412543434000235100ustar00rootroot00000000000000from sympy import Symbol, sympify from sympy.core.compatibility import is_sequence from sympy.geometry.entity import GeometryEntity from .plot_interval import PlotInterval from .plot_object import PlotObject from .util import parse_option_string class PlotMode(PlotObject): """ Grandparent class for plotting modes. Serves as interface for registration, lookup, and init of modes. To create a new plot mode, inherit from PlotModeBase or one of its children, such as PlotSurface or PlotCurve. """ ## Class-level attributes ## used to register and lookup ## plot modes. See PlotModeBase ## for descriptions and usage. i_vars, d_vars = '', '' intervals = [] aliases = [] is_default = False ## Draw is the only method here which ## is meant to be overridden in child ## classes, and PlotModeBase provides ## a base implementation. def draw(self): raise NotImplementedError() ## Everything else in this file has to ## do with registration and retrieval ## of plot modes. This is where I've ## hidden much of the ugliness of automatic ## plot mode divination... ## Plot mode registry data structures _mode_alias_list = [] _mode_map = { 1: {1: {}, 2: {}}, 2: {1: {}, 2: {}}, 3: {1: {}, 2: {}}, } # [d][i][alias_str]: class _mode_default_map = { 1: {}, 2: {}, 3: {}, } # [d][i]: class _i_var_max, _d_var_max = 2, 3 def __new__(cls, *args, **kwargs): """ This is the function which interprets arguments given to Plot.__init__ and Plot.__setattr__. Returns an initialized instance of the appropriate child class. """ newargs, newkwargs = PlotMode._extract_options(args, kwargs) mode_arg = newkwargs.get('mode', '') # Interpret the arguments d_vars, intervals = PlotMode._interpret_args(newargs) i_vars = PlotMode._find_i_vars(d_vars, intervals) i, d = max([len(i_vars), len(intervals)]), len(d_vars) # Find the appropriate mode subcls = PlotMode._get_mode(mode_arg, i, d) # Create the object o = object.__new__(subcls) # Do some setup for the mode instance o.d_vars = d_vars o._fill_i_vars(i_vars) o._fill_intervals(intervals) o.options = newkwargs return o @staticmethod def _get_mode(mode_arg, i_var_count, d_var_count): """ Tries to return an appropriate mode class. Intended to be called only by __new__. mode_arg Can be a string or a class. If it is a PlotMode subclass, it is simply returned. If it is a string, it can an alias for a mode or an empty string. In the latter case, we try to find a default mode for the i_var_count and d_var_count. i_var_count The number of independent variables needed to evaluate the d_vars. d_var_count The number of dependent variables; usually the number of functions to be evaluated in plotting. For example, a Cartesian function y = f(x) has one i_var (x) and one d_var (y). A parametric form x,y,z = f(u,v), f(u,v), f(u,v) has two two i_vars (u,v) and three d_vars (x,y,z). """ # if the mode_arg is simply a PlotMode class, # check that the mode supports the numbers # of independent and dependent vars, then # return it try: m = None if issubclass(mode_arg, PlotMode): m = mode_arg except TypeError: pass if m: if not m._was_initialized: raise ValueError(("To use unregistered plot mode %s " "you must first call %s._init_mode().") % (m.__name__, m.__name__)) if d_var_count != m.d_var_count: raise ValueError(("%s can only plot functions " "with %i dependent variables.") % (m.__name__, m.d_var_count)) if i_var_count > m.i_var_count: raise ValueError(("%s cannot plot functions " "with more than %i independent " "variables.") % (m.__name__, m.i_var_count)) return m # If it is a string, there are two possibilities. if isinstance(mode_arg, str): i, d = i_var_count, d_var_count if i > PlotMode._i_var_max: raise ValueError(var_count_error(True, True)) if d > PlotMode._d_var_max: raise ValueError(var_count_error(False, True)) # If the string is '', try to find a suitable # default mode if not mode_arg: return PlotMode._get_default_mode(i, d) # Otherwise, interpret the string as a mode # alias (e.g. 'cartesian', 'parametric', etc) else: return PlotMode._get_aliased_mode(mode_arg, i, d) else: raise ValueError("PlotMode argument must be " "a class or a string") @staticmethod def _get_default_mode(i, d, i_vars=-1): if i_vars == -1: i_vars = i try: return PlotMode._mode_default_map[d][i] except KeyError: # Keep looking for modes in higher i var counts # which support the given d var count until we # reach the max i_var count. if i < PlotMode._i_var_max: return PlotMode._get_default_mode(i + 1, d, i_vars) else: raise ValueError(("Couldn't find a default mode " "for %i independent and %i " "dependent variables.") % (i_vars, d)) @staticmethod def _get_aliased_mode(alias, i, d, i_vars=-1): if i_vars == -1: i_vars = i if alias not in PlotMode._mode_alias_list: raise ValueError(("Couldn't find a mode called" " %s. Known modes: %s.") % (alias, ", ".join(PlotMode._mode_alias_list))) try: return PlotMode._mode_map[d][i][alias] except TypeError: # Keep looking for modes in higher i var counts # which support the given d var count and alias # until we reach the max i_var count. if i < PlotMode._i_var_max: return PlotMode._get_aliased_mode(alias, i + 1, d, i_vars) else: raise ValueError(("Couldn't find a %s mode " "for %i independent and %i " "dependent variables.") % (alias, i_vars, d)) @classmethod def _register(cls): """ Called once for each user-usable plot mode. For Cartesian2D, it is invoked after the class definition: Cartesian2D._register() """ name = cls.__name__ cls._init_mode() try: i, d = cls.i_var_count, cls.d_var_count # Add the mode to _mode_map under all # given aliases for a in cls.aliases: if a not in PlotMode._mode_alias_list: # Also track valid aliases, so # we can quickly know when given # an invalid one in _get_mode. PlotMode._mode_alias_list.append(a) PlotMode._mode_map[d][i][a] = cls if cls.is_default: # If this mode was marked as the # default for this d,i combination, # also set that. PlotMode._mode_default_map[d][i] = cls except Exception as e: raise RuntimeError(("Failed to register " "plot mode %s. Reason: %s") % (name, (str(e)))) @classmethod def _init_mode(cls): """ Initializes the plot mode based on the 'mode-specific parameters' above. Only intended to be called by PlotMode._register(). To use a mode without registering it, you can directly call ModeSubclass._init_mode(). """ def symbols_list(symbol_str): return [Symbol(s) for s in symbol_str] # Convert the vars strs into # lists of symbols. cls.i_vars = symbols_list(cls.i_vars) cls.d_vars = symbols_list(cls.d_vars) # Var count is used often, calculate # it once here cls.i_var_count = len(cls.i_vars) cls.d_var_count = len(cls.d_vars) if cls.i_var_count > PlotMode._i_var_max: raise ValueError(var_count_error(True, False)) if cls.d_var_count > PlotMode._d_var_max: raise ValueError(var_count_error(False, False)) # Try to use first alias as primary_alias if len(cls.aliases) > 0: cls.primary_alias = cls.aliases[0] else: cls.primary_alias = cls.__name__ di = cls.intervals if len(di) != cls.i_var_count: raise ValueError("Plot mode must provide a " "default interval for each i_var.") for i in range(cls.i_var_count): # default intervals must be given [min,max,steps] # (no var, but they must be in the same order as i_vars) if len(di[i]) != 3: raise ValueError("length should be equal to 3") # Initialize an incomplete interval, # to later be filled with a var when # the mode is instantiated. di[i] = PlotInterval(None, *di[i]) # To prevent people from using modes # without these required fields set up. cls._was_initialized = True _was_initialized = False ## Initializer Helper Methods @staticmethod def _find_i_vars(functions, intervals): i_vars = [] # First, collect i_vars in the # order they are given in any # intervals. for i in intervals: if i.v is None: continue elif i.v in i_vars: raise ValueError(("Multiple intervals given " "for %s.") % (str(i.v))) i_vars.append(i.v) # Then, find any remaining # i_vars in given functions # (aka d_vars) for f in functions: for a in f.free_symbols: if a not in i_vars: i_vars.append(a) return i_vars def _fill_i_vars(self, i_vars): # copy default i_vars self.i_vars = [Symbol(str(i)) for i in self.i_vars] # replace with given i_vars for i in range(len(i_vars)): self.i_vars[i] = i_vars[i] def _fill_intervals(self, intervals): # copy default intervals self.intervals = [PlotInterval(i) for i in self.intervals] # track i_vars used so far v_used = [] # fill copy of default # intervals with given info for i in range(len(intervals)): self.intervals[i].fill_from(intervals[i]) if self.intervals[i].v is not None: v_used.append(self.intervals[i].v) # Find any orphan intervals and # assign them i_vars for i in range(len(self.intervals)): if self.intervals[i].v is None: u = [v for v in self.i_vars if v not in v_used] if len(u) == 0: raise ValueError("length should not be equal to 0") self.intervals[i].v = u[0] v_used.append(u[0]) @staticmethod def _interpret_args(args): interval_wrong_order = "PlotInterval %s was given before any function(s)." interpret_error = "Could not interpret %s as a function or interval." functions, intervals = [], [] if isinstance(args[0], GeometryEntity): for coords in list(args[0].arbitrary_point()): functions.append(coords) intervals.append(PlotInterval.try_parse(args[0].plot_interval())) else: for a in args: i = PlotInterval.try_parse(a) if i is not None: if len(functions) == 0: raise ValueError(interval_wrong_order % (str(i))) else: intervals.append(i) else: if is_sequence(a, include=str): raise ValueError(interpret_error % (str(a))) try: f = sympify(a) functions.append(f) except TypeError: raise ValueError(interpret_error % str(a)) return functions, intervals @staticmethod def _extract_options(args, kwargs): newkwargs, newargs = {}, [] for a in args: if isinstance(a, str): newkwargs = dict(newkwargs, **parse_option_string(a)) else: newargs.append(a) newkwargs = dict(newkwargs, **kwargs) return newargs, newkwargs def var_count_error(is_independent, is_plotting): """ Used to format an error message which differs slightly in 4 places. """ if is_plotting: v = "Plotting" else: v = "Registering plot modes" if is_independent: n, s = PlotMode._i_var_max, "independent" else: n, s = PlotMode._d_var_max, "dependent" return ("%s with more than %i %s variables " "is not supported.") % (v, n, s) sympy-sympy-1.9/sympy/plotting/pygletplot/plot_mode_base.py000066400000000000000000000263501412543434000245030ustar00rootroot00000000000000import pyglet.gl as pgl from sympy.core import S from sympy.core.compatibility import is_sequence from sympy.plotting.pygletplot.color_scheme import ColorScheme from sympy.plotting.pygletplot.plot_mode import PlotMode from time import sleep from threading import Thread, Event, RLock import warnings class PlotModeBase(PlotMode): """ Intended parent class for plotting modes. Provides base functionality in conjunction with its parent, PlotMode. """ ## ## Class-Level Attributes ## """ The following attributes are meant to be set at the class level, and serve as parameters to the plot mode registry (in PlotMode). See plot_modes.py for concrete examples. """ """ i_vars 'x' for Cartesian2D 'xy' for Cartesian3D etc. d_vars 'y' for Cartesian2D 'r' for Polar etc. """ i_vars, d_vars = '', '' """ intervals Default intervals for each i_var, and in the same order. Specified [min, max, steps]. No variable can be given (it is bound later). """ intervals = [] """ aliases A list of strings which can be used to access this mode. 'cartesian' for Cartesian2D and Cartesian3D 'polar' for Polar 'cylindrical', 'polar' for Cylindrical Note that _init_mode chooses the first alias in the list as the mode's primary_alias, which will be displayed to the end user in certain contexts. """ aliases = [] """ is_default Whether to set this mode as the default for arguments passed to PlotMode() containing the same number of d_vars as this mode and at most the same number of i_vars. """ is_default = False """ All of the above attributes are defined in PlotMode. The following ones are specific to PlotModeBase. """ """ A list of the render styles. Do not modify. """ styles = {'wireframe': 1, 'solid': 2, 'both': 3} """ style_override Always use this style if not blank. """ style_override = '' """ default_wireframe_color default_solid_color Can be used when color is None or being calculated. Used by PlotCurve and PlotSurface, but not anywhere in PlotModeBase. """ default_wireframe_color = (0.85, 0.85, 0.85) default_solid_color = (0.6, 0.6, 0.9) default_rot_preset = 'xy' ## ## Instance-Level Attributes ## ## 'Abstract' member functions def _get_evaluator(self): if self.use_lambda_eval: try: e = self._get_lambda_evaluator() return e except Exception: warnings.warn("\nWarning: creating lambda evaluator failed. " "Falling back on sympy subs evaluator.") return self._get_sympy_evaluator() def _get_sympy_evaluator(self): raise NotImplementedError() def _get_lambda_evaluator(self): raise NotImplementedError() def _on_calculate_verts(self): raise NotImplementedError() def _on_calculate_cverts(self): raise NotImplementedError() ## Base member functions def __init__(self, *args, bounds_callback=None, **kwargs): self.verts = [] self.cverts = [] self.bounds = [[S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0]] self.cbounds = [[S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0]] self._draw_lock = RLock() self._calculating_verts = Event() self._calculating_cverts = Event() self._calculating_verts_pos = 0.0 self._calculating_verts_len = 0.0 self._calculating_cverts_pos = 0.0 self._calculating_cverts_len = 0.0 self._max_render_stack_size = 3 self._draw_wireframe = [-1] self._draw_solid = [-1] self._style = None self._color = None self.predraw = [] self.postdraw = [] self.use_lambda_eval = self.options.pop('use_sympy_eval', None) is None self.style = self.options.pop('style', '') self.color = self.options.pop('color', 'rainbow') self.bounds_callback = bounds_callback self._on_calculate() def synchronized(f): def w(self, *args, **kwargs): self._draw_lock.acquire() try: r = f(self, *args, **kwargs) return r finally: self._draw_lock.release() return w @synchronized def push_wireframe(self, function): """ Push a function which performs gl commands used to build a display list. (The list is built outside of the function) """ assert callable(function) self._draw_wireframe.append(function) if len(self._draw_wireframe) > self._max_render_stack_size: del self._draw_wireframe[1] # leave marker element @synchronized def push_solid(self, function): """ Push a function which performs gl commands used to build a display list. (The list is built outside of the function) """ assert callable(function) self._draw_solid.append(function) if len(self._draw_solid) > self._max_render_stack_size: del self._draw_solid[1] # leave marker element def _create_display_list(self, function): dl = pgl.glGenLists(1) pgl.glNewList(dl, pgl.GL_COMPILE) function() pgl.glEndList() return dl def _render_stack_top(self, render_stack): top = render_stack[-1] if top == -1: return -1 # nothing to display elif callable(top): dl = self._create_display_list(top) render_stack[-1] = (dl, top) return dl # display newly added list elif len(top) == 2: if pgl.GL_TRUE == pgl.glIsList(top[0]): return top[0] # display stored list dl = self._create_display_list(top[1]) render_stack[-1] = (dl, top[1]) return dl # display regenerated list def _draw_solid_display_list(self, dl): pgl.glPushAttrib(pgl.GL_ENABLE_BIT | pgl.GL_POLYGON_BIT) pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_FILL) pgl.glCallList(dl) pgl.glPopAttrib() def _draw_wireframe_display_list(self, dl): pgl.glPushAttrib(pgl.GL_ENABLE_BIT | pgl.GL_POLYGON_BIT) pgl.glPolygonMode(pgl.GL_FRONT_AND_BACK, pgl.GL_LINE) pgl.glEnable(pgl.GL_POLYGON_OFFSET_LINE) pgl.glPolygonOffset(-0.005, -50.0) pgl.glCallList(dl) pgl.glPopAttrib() @synchronized def draw(self): for f in self.predraw: if callable(f): f() if self.style_override: style = self.styles[self.style_override] else: style = self.styles[self._style] # Draw solid component if style includes solid if style & 2: dl = self._render_stack_top(self._draw_solid) if dl > 0 and pgl.GL_TRUE == pgl.glIsList(dl): self._draw_solid_display_list(dl) # Draw wireframe component if style includes wireframe if style & 1: dl = self._render_stack_top(self._draw_wireframe) if dl > 0 and pgl.GL_TRUE == pgl.glIsList(dl): self._draw_wireframe_display_list(dl) for f in self.postdraw: if callable(f): f() def _on_change_color(self, color): Thread(target=self._calculate_cverts).start() def _on_calculate(self): Thread(target=self._calculate_all).start() def _calculate_all(self): self._calculate_verts() self._calculate_cverts() def _calculate_verts(self): if self._calculating_verts.isSet(): return self._calculating_verts.set() try: self._on_calculate_verts() finally: self._calculating_verts.clear() if callable(self.bounds_callback): self.bounds_callback() def _calculate_cverts(self): if self._calculating_verts.isSet(): return while self._calculating_cverts.isSet(): sleep(0) # wait for previous calculation self._calculating_cverts.set() try: self._on_calculate_cverts() finally: self._calculating_cverts.clear() def _get_calculating_verts(self): return self._calculating_verts.isSet() def _get_calculating_verts_pos(self): return self._calculating_verts_pos def _get_calculating_verts_len(self): return self._calculating_verts_len def _get_calculating_cverts(self): return self._calculating_cverts.isSet() def _get_calculating_cverts_pos(self): return self._calculating_cverts_pos def _get_calculating_cverts_len(self): return self._calculating_cverts_len ## Property handlers def _get_style(self): return self._style @synchronized def _set_style(self, v): if v is None: return if v == '': step_max = 0 for i in self.intervals: if i.v_steps is None: continue step_max = max([step_max, int(i.v_steps)]) v = ['both', 'solid'][step_max > 40] if v not in self.styles: raise ValueError("v should be there in self.styles") if v == self._style: return self._style = v def _get_color(self): return self._color @synchronized def _set_color(self, v): try: if v is not None: if is_sequence(v): v = ColorScheme(*v) else: v = ColorScheme(v) if repr(v) == repr(self._color): return self._on_change_color(v) self._color = v except Exception as e: raise RuntimeError("Color change failed. " "Reason: %s" % (str(e))) style = property(_get_style, _set_style) color = property(_get_color, _set_color) calculating_verts = property(_get_calculating_verts) calculating_verts_pos = property(_get_calculating_verts_pos) calculating_verts_len = property(_get_calculating_verts_len) calculating_cverts = property(_get_calculating_cverts) calculating_cverts_pos = property(_get_calculating_cverts_pos) calculating_cverts_len = property(_get_calculating_cverts_len) ## String representations def __str__(self): f = ", ".join(str(d) for d in self.d_vars) o = "'mode=%s'" % (self.primary_alias) return ", ".join([f, o]) def __repr__(self): f = ", ".join(str(d) for d in self.d_vars) i = ", ".join(str(i) for i in self.intervals) d = [('mode', self.primary_alias), ('color', str(self.color)), ('style', str(self.style))] o = "'%s'" % ("; ".join("%s=%s" % (k, v) for k, v in d if v != 'None')) return ", ".join([f, i, o]) sympy-sympy-1.9/sympy/plotting/pygletplot/plot_modes.py000066400000000000000000000123251412543434000236710ustar00rootroot00000000000000from sympy import lambdify from sympy.core.numbers import pi from sympy.functions import sin, cos from sympy.plotting.pygletplot.plot_curve import PlotCurve from sympy.plotting.pygletplot.plot_surface import PlotSurface from math import sin as p_sin from math import cos as p_cos def float_vec3(f): def inner(*args): v = f(*args) return float(v[0]), float(v[1]), float(v[2]) return inner class Cartesian2D(PlotCurve): i_vars, d_vars = 'x', 'y' intervals = [[-5, 5, 100]] aliases = ['cartesian'] is_default = True def _get_sympy_evaluator(self): fy = self.d_vars[0] x = self.t_interval.v @float_vec3 def e(_x): return (_x, fy.subs(x, _x), 0.0) return e def _get_lambda_evaluator(self): fy = self.d_vars[0] x = self.t_interval.v return lambdify([x], [x, fy, 0.0]) class Cartesian3D(PlotSurface): i_vars, d_vars = 'xy', 'z' intervals = [[-1, 1, 40], [-1, 1, 40]] aliases = ['cartesian', 'monge'] is_default = True def _get_sympy_evaluator(self): fz = self.d_vars[0] x = self.u_interval.v y = self.v_interval.v @float_vec3 def e(_x, _y): return (_x, _y, fz.subs(x, _x).subs(y, _y)) return e def _get_lambda_evaluator(self): fz = self.d_vars[0] x = self.u_interval.v y = self.v_interval.v return lambdify([x, y], [x, y, fz]) class ParametricCurve2D(PlotCurve): i_vars, d_vars = 't', 'xy' intervals = [[0, 2*pi, 100]] aliases = ['parametric'] is_default = True def _get_sympy_evaluator(self): fx, fy = self.d_vars t = self.t_interval.v @float_vec3 def e(_t): return (fx.subs(t, _t), fy.subs(t, _t), 0.0) return e def _get_lambda_evaluator(self): fx, fy = self.d_vars t = self.t_interval.v return lambdify([t], [fx, fy, 0.0]) class ParametricCurve3D(PlotCurve): i_vars, d_vars = 't', 'xyz' intervals = [[0, 2*pi, 100]] aliases = ['parametric'] is_default = True def _get_sympy_evaluator(self): fx, fy, fz = self.d_vars t = self.t_interval.v @float_vec3 def e(_t): return (fx.subs(t, _t), fy.subs(t, _t), fz.subs(t, _t)) return e def _get_lambda_evaluator(self): fx, fy, fz = self.d_vars t = self.t_interval.v return lambdify([t], [fx, fy, fz]) class ParametricSurface(PlotSurface): i_vars, d_vars = 'uv', 'xyz' intervals = [[-1, 1, 40], [-1, 1, 40]] aliases = ['parametric'] is_default = True def _get_sympy_evaluator(self): fx, fy, fz = self.d_vars u = self.u_interval.v v = self.v_interval.v @float_vec3 def e(_u, _v): return (fx.subs(u, _u).subs(v, _v), fy.subs(u, _u).subs(v, _v), fz.subs(u, _u).subs(v, _v)) return e def _get_lambda_evaluator(self): fx, fy, fz = self.d_vars u = self.u_interval.v v = self.v_interval.v return lambdify([u, v], [fx, fy, fz]) class Polar(PlotCurve): i_vars, d_vars = 't', 'r' intervals = [[0, 2*pi, 100]] aliases = ['polar'] is_default = False def _get_sympy_evaluator(self): fr = self.d_vars[0] t = self.t_interval.v def e(_t): _r = float(fr.subs(t, _t)) return (_r*p_cos(_t), _r*p_sin(_t), 0.0) return e def _get_lambda_evaluator(self): fr = self.d_vars[0] t = self.t_interval.v fx, fy = fr*cos(t), fr*sin(t) return lambdify([t], [fx, fy, 0.0]) class Cylindrical(PlotSurface): i_vars, d_vars = 'th', 'r' intervals = [[0, 2*pi, 40], [-1, 1, 20]] aliases = ['cylindrical', 'polar'] is_default = False def _get_sympy_evaluator(self): fr = self.d_vars[0] t = self.u_interval.v h = self.v_interval.v def e(_t, _h): _r = float(fr.subs(t, _t).subs(h, _h)) return (_r*p_cos(_t), _r*p_sin(_t), _h) return e def _get_lambda_evaluator(self): fr = self.d_vars[0] t = self.u_interval.v h = self.v_interval.v fx, fy = fr*cos(t), fr*sin(t) return lambdify([t, h], [fx, fy, h]) class Spherical(PlotSurface): i_vars, d_vars = 'tp', 'r' intervals = [[0, 2*pi, 40], [0, pi, 20]] aliases = ['spherical'] is_default = False def _get_sympy_evaluator(self): fr = self.d_vars[0] t = self.u_interval.v p = self.v_interval.v def e(_t, _p): _r = float(fr.subs(t, _t).subs(p, _p)) return (_r*p_cos(_t)*p_sin(_p), _r*p_sin(_t)*p_sin(_p), _r*p_cos(_p)) return e def _get_lambda_evaluator(self): fr = self.d_vars[0] t = self.u_interval.v p = self.v_interval.v fx = fr * cos(t) * sin(p) fy = fr * sin(t) * sin(p) fz = fr * cos(p) return lambdify([t, p], [fx, fy, fz]) Cartesian2D._register() Cartesian3D._register() ParametricCurve2D._register() ParametricCurve3D._register() ParametricSurface._register() Polar._register() Cylindrical._register() Spherical._register() sympy-sympy-1.9/sympy/plotting/pygletplot/plot_object.py000066400000000000000000000005121412543434000240230ustar00rootroot00000000000000class PlotObject: """ Base class for objects which can be displayed in a Plot. """ visible = True def _draw(self): if self.visible: self.draw() def draw(self): """ OpenGL rendering code for the plot object. Override in base class. """ pass sympy-sympy-1.9/sympy/plotting/pygletplot/plot_rotation.py000066400000000000000000000026471412543434000244270ustar00rootroot00000000000000try: from ctypes import c_float except ImportError: pass import pyglet.gl as pgl from math import sqrt as _sqrt, acos as _acos def cross(a, b): return (a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]) def dot(a, b): return a[0] * b[0] + a[1] * b[1] + a[2] * b[2] def mag(a): return _sqrt(a[0]**2 + a[1]**2 + a[2]**2) def norm(a): m = mag(a) return (a[0] / m, a[1] / m, a[2] / m) def get_sphere_mapping(x, y, width, height): x = min([max([x, 0]), width]) y = min([max([y, 0]), height]) sr = _sqrt((width/2)**2 + (height/2)**2) sx = ((x - width / 2) / sr) sy = ((y - height / 2) / sr) sz = 1.0 - sx**2 - sy**2 if sz > 0.0: sz = _sqrt(sz) return (sx, sy, sz) else: sz = 0 return norm((sx, sy, sz)) rad2deg = 180.0 / 3.141592 def get_spherical_rotatation(p1, p2, width, height, theta_multiplier): v1 = get_sphere_mapping(p1[0], p1[1], width, height) v2 = get_sphere_mapping(p2[0], p2[1], width, height) d = min(max([dot(v1, v2), -1]), 1) if abs(d - 1.0) < 0.000001: return None raxis = norm( cross(v1, v2) ) rtheta = theta_multiplier * rad2deg * _acos(d) pgl.glPushMatrix() pgl.glLoadIdentity() pgl.glRotatef(rtheta, *raxis) mat = (c_float*16)() pgl.glGetFloatv(pgl.GL_MODELVIEW_MATRIX, mat) pgl.glPopMatrix() return mat sympy-sympy-1.9/sympy/plotting/pygletplot/plot_surface.py000066400000000000000000000073431412543434000242160ustar00rootroot00000000000000import pyglet.gl as pgl from sympy.core import S from sympy.plotting.pygletplot.plot_mode_base import PlotModeBase class PlotSurface(PlotModeBase): default_rot_preset = 'perspective' def _on_calculate_verts(self): self.u_interval = self.intervals[0] self.u_set = list(self.u_interval.frange()) self.v_interval = self.intervals[1] self.v_set = list(self.v_interval.frange()) self.bounds = [[S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0]] evaluate = self._get_evaluator() self._calculating_verts_pos = 0.0 self._calculating_verts_len = float( self.u_interval.v_len*self.v_interval.v_len) verts = list() b = self.bounds for u in self.u_set: column = list() for v in self.v_set: try: _e = evaluate(u, v) # calculate vertex except ZeroDivisionError: _e = None if _e is not None: # update bounding box for axis in range(3): b[axis][0] = min([b[axis][0], _e[axis]]) b[axis][1] = max([b[axis][1], _e[axis]]) column.append(_e) self._calculating_verts_pos += 1.0 verts.append(column) for axis in range(3): b[axis][2] = b[axis][1] - b[axis][0] if b[axis][2] == 0.0: b[axis][2] = 1.0 self.verts = verts self.push_wireframe(self.draw_verts(False, False)) self.push_solid(self.draw_verts(False, True)) def _on_calculate_cverts(self): if not self.verts or not self.color: return def set_work_len(n): self._calculating_cverts_len = float(n) def inc_work_pos(): self._calculating_cverts_pos += 1.0 set_work_len(1) self._calculating_cverts_pos = 0 self.cverts = self.color.apply_to_surface(self.verts, self.u_set, self.v_set, set_len=set_work_len, inc_pos=inc_work_pos) self.push_solid(self.draw_verts(True, True)) def calculate_one_cvert(self, u, v): vert = self.verts[u][v] return self.color(vert[0], vert[1], vert[2], self.u_set[u], self.v_set[v]) def draw_verts(self, use_cverts, use_solid_color): def f(): for u in range(1, len(self.u_set)): pgl.glBegin(pgl.GL_QUAD_STRIP) for v in range(len(self.v_set)): pa = self.verts[u - 1][v] pb = self.verts[u][v] if pa is None or pb is None: pgl.glEnd() pgl.glBegin(pgl.GL_QUAD_STRIP) continue if use_cverts: ca = self.cverts[u - 1][v] cb = self.cverts[u][v] if ca is None: ca = (0, 0, 0) if cb is None: cb = (0, 0, 0) else: if use_solid_color: ca = cb = self.default_solid_color else: ca = cb = self.default_wireframe_color pgl.glColor3f(*ca) pgl.glVertex3f(*pa) pgl.glColor3f(*cb) pgl.glVertex3f(*pb) pgl.glEnd() return f sympy-sympy-1.9/sympy/plotting/pygletplot/plot_window.py000066400000000000000000000113461412543434000240730ustar00rootroot00000000000000from sympy.core.compatibility import clock import pyglet.gl as pgl from sympy.plotting.pygletplot.managed_window import ManagedWindow from sympy.plotting.pygletplot.plot_camera import PlotCamera from sympy.plotting.pygletplot.plot_controller import PlotController class PlotWindow(ManagedWindow): def __init__(self, plot, antialiasing=True, ortho=False, invert_mouse_zoom=False, linewidth=1.5, caption="SymPy Plot", **kwargs): """ Named Arguments =============== antialiasing = True True OR False ortho = False True OR False invert_mouse_zoom = False True OR False """ self.plot = plot self.camera = None self._calculating = False self.antialiasing = antialiasing self.ortho = ortho self.invert_mouse_zoom = invert_mouse_zoom self.linewidth = linewidth self.title = caption self.last_caption_update = 0 self.caption_update_interval = 0.2 self.drawing_first_object = True super().__init__(**kwargs) def setup(self): self.camera = PlotCamera(self, ortho=self.ortho) self.controller = PlotController(self, invert_mouse_zoom=self.invert_mouse_zoom) self.push_handlers(self.controller) pgl.glClearColor(1.0, 1.0, 1.0, 0.0) pgl.glClearDepth(1.0) pgl.glDepthFunc(pgl.GL_LESS) pgl.glEnable(pgl.GL_DEPTH_TEST) pgl.glEnable(pgl.GL_LINE_SMOOTH) pgl.glShadeModel(pgl.GL_SMOOTH) pgl.glLineWidth(self.linewidth) pgl.glEnable(pgl.GL_BLEND) pgl.glBlendFunc(pgl.GL_SRC_ALPHA, pgl.GL_ONE_MINUS_SRC_ALPHA) if self.antialiasing: pgl.glHint(pgl.GL_LINE_SMOOTH_HINT, pgl.GL_NICEST) pgl.glHint(pgl.GL_POLYGON_SMOOTH_HINT, pgl.GL_NICEST) self.camera.setup_projection() def on_resize(self, w, h): super().on_resize(w, h) if self.camera is not None: self.camera.setup_projection() def update(self, dt): self.controller.update(dt) def draw(self): self.plot._render_lock.acquire() self.camera.apply_transformation() calc_verts_pos, calc_verts_len = 0, 0 calc_cverts_pos, calc_cverts_len = 0, 0 should_update_caption = (clock() - self.last_caption_update > self.caption_update_interval) if len(self.plot._functions.values()) == 0: self.drawing_first_object = True try: dict.iteritems except AttributeError: # Python 3 iterfunctions = iter(self.plot._functions.values()) else: # Python 2 iterfunctions = self.plot._functions.itervalues() for r in iterfunctions: if self.drawing_first_object: self.camera.set_rot_preset(r.default_rot_preset) self.drawing_first_object = False pgl.glPushMatrix() r._draw() pgl.glPopMatrix() # might as well do this while we are # iterating and have the lock rather # than locking and iterating twice # per frame: if should_update_caption: try: if r.calculating_verts: calc_verts_pos += r.calculating_verts_pos calc_verts_len += r.calculating_verts_len if r.calculating_cverts: calc_cverts_pos += r.calculating_cverts_pos calc_cverts_len += r.calculating_cverts_len except ValueError: pass for r in self.plot._pobjects: pgl.glPushMatrix() r._draw() pgl.glPopMatrix() if should_update_caption: self.update_caption(calc_verts_pos, calc_verts_len, calc_cverts_pos, calc_cverts_len) self.last_caption_update = clock() if self.plot._screenshot: self.plot._screenshot._execute_saving() self.plot._render_lock.release() def update_caption(self, calc_verts_pos, calc_verts_len, calc_cverts_pos, calc_cverts_len): caption = self.title if calc_verts_len or calc_cverts_len: caption += " (calculating" if calc_verts_len > 0: p = (calc_verts_pos / calc_verts_len) * 100 caption += " vertices %i%%" % (p) if calc_cverts_len > 0: p = (calc_cverts_pos / calc_cverts_len) * 100 caption += " colors %i%%" % (p) caption += ")" if self.caption != caption: self.set_caption(caption) sympy-sympy-1.9/sympy/plotting/pygletplot/tests/000077500000000000000000000000001412543434000223115ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/pygletplot/tests/__init__.py000066400000000000000000000000001412543434000244100ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/pygletplot/tests/test_plotting.py000066400000000000000000000050301412543434000255600ustar00rootroot00000000000000from sympy.external.importtools import import_module disabled = False # if pyglet.gl fails to import, e.g. opengl is missing, we disable the tests pyglet_gl = import_module("pyglet.gl", catch=(OSError,)) pyglet_window = import_module("pyglet.window", catch=(OSError,)) if not pyglet_gl or not pyglet_window: disabled = True from sympy import symbols, sin, cos, log x, y, z = symbols('x, y, z') def test_plot_2d(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(x, [x, -5, 5, 4], visible=False) p.wait_for_calculations() def test_plot_2d_discontinuous(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(1/x, [x, -1, 1, 2], visible=False) p.wait_for_calculations() def test_plot_3d(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(x*y, [x, -5, 5, 5], [y, -5, 5, 5], visible=False) p.wait_for_calculations() def test_plot_3d_discontinuous(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(1/x, [x, -3, 3, 6], [y, -1, 1, 1], visible=False) p.wait_for_calculations() def test_plot_2d_polar(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(1/x, [x, -1, 1, 4], 'mode=polar', visible=False) p.wait_for_calculations() def test_plot_3d_cylinder(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot( 1/y, [x, 0, 6.282, 4], [y, -1, 1, 4], 'mode=polar;style=solid', visible=False) p.wait_for_calculations() def test_plot_3d_spherical(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot( 1, [x, 0, 6.282, 4], [y, 0, 3.141, 4], 'mode=spherical;style=wireframe', visible=False) p.wait_for_calculations() def test_plot_2d_parametric(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(sin(x), cos(x), [x, 0, 6.282, 4], visible=False) p.wait_for_calculations() def test_plot_3d_parametric(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(sin(x), cos(x), x/5.0, [x, 0, 6.282, 4], visible=False) p.wait_for_calculations() def _test_plot_log(): from sympy.plotting.pygletplot import PygletPlot p = PygletPlot(log(x), [x, 0, 6.282, 4], 'mode=polar', visible=False) p.wait_for_calculations() def test_plot_integral(): # Make sure it doesn't treat x as an independent variable from sympy.plotting.pygletplot import PygletPlot from sympy import Integral p = PygletPlot(Integral(z*x, (x, 1, z), (z, 1, y)), visible=False) p.wait_for_calculations() sympy-sympy-1.9/sympy/plotting/pygletplot/util.py000066400000000000000000000110261412543434000224760ustar00rootroot00000000000000try: from ctypes import c_float, c_int, c_double except ImportError: pass import pyglet.gl as pgl from sympy.core import S def get_model_matrix(array_type=c_float, glGetMethod=pgl.glGetFloatv): """ Returns the current modelview matrix. """ m = (array_type*16)() glGetMethod(pgl.GL_MODELVIEW_MATRIX, m) return m def get_projection_matrix(array_type=c_float, glGetMethod=pgl.glGetFloatv): """ Returns the current modelview matrix. """ m = (array_type*16)() glGetMethod(pgl.GL_PROJECTION_MATRIX, m) return m def get_viewport(): """ Returns the current viewport. """ m = (c_int*4)() pgl.glGetIntegerv(pgl.GL_VIEWPORT, m) return m def get_direction_vectors(): m = get_model_matrix() return ((m[0], m[4], m[8]), (m[1], m[5], m[9]), (m[2], m[6], m[10])) def get_view_direction_vectors(): m = get_model_matrix() return ((m[0], m[1], m[2]), (m[4], m[5], m[6]), (m[8], m[9], m[10])) def get_basis_vectors(): return ((1, 0, 0), (0, 1, 0), (0, 0, 1)) def screen_to_model(x, y, z): m = get_model_matrix(c_double, pgl.glGetDoublev) p = get_projection_matrix(c_double, pgl.glGetDoublev) w = get_viewport() mx, my, mz = c_double(), c_double(), c_double() pgl.gluUnProject(x, y, z, m, p, w, mx, my, mz) return float(mx.value), float(my.value), float(mz.value) def model_to_screen(x, y, z): m = get_model_matrix(c_double, pgl.glGetDoublev) p = get_projection_matrix(c_double, pgl.glGetDoublev) w = get_viewport() mx, my, mz = c_double(), c_double(), c_double() pgl.gluProject(x, y, z, m, p, w, mx, my, mz) return float(mx.value), float(my.value), float(mz.value) def vec_subs(a, b): return tuple(a[i] - b[i] for i in range(len(a))) def billboard_matrix(): """ Removes rotational components of current matrix so that primitives are always drawn facing the viewer. |1|0|0|x| |0|1|0|x| |0|0|1|x| (x means left unchanged) |x|x|x|x| """ m = get_model_matrix() # XXX: for i in range(11): m[i] = i ? m[0] = 1 m[1] = 0 m[2] = 0 m[4] = 0 m[5] = 1 m[6] = 0 m[8] = 0 m[9] = 0 m[10] = 1 pgl.glLoadMatrixf(m) def create_bounds(): return [[S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0], [S.Infinity, S.NegativeInfinity, 0]] def update_bounds(b, v): if v is None: return for axis in range(3): b[axis][0] = min([b[axis][0], v[axis]]) b[axis][1] = max([b[axis][1], v[axis]]) def interpolate(a_min, a_max, a_ratio): return a_min + a_ratio * (a_max - a_min) def rinterpolate(a_min, a_max, a_value): a_range = a_max - a_min if a_max == a_min: a_range = 1.0 return (a_value - a_min) / float(a_range) def interpolate_color(color1, color2, ratio): return tuple(interpolate(color1[i], color2[i], ratio) for i in range(3)) def scale_value(v, v_min, v_len): return (v - v_min) / v_len def scale_value_list(flist): v_min, v_max = min(flist), max(flist) v_len = v_max - v_min return list(scale_value(f, v_min, v_len) for f in flist) def strided_range(r_min, r_max, stride, max_steps=50): o_min, o_max = r_min, r_max if abs(r_min - r_max) < 0.001: return [] try: range(int(r_min - r_max)) except (TypeError, OverflowError): return [] if r_min > r_max: raise ValueError("r_min can not be greater than r_max") r_min_s = (r_min % stride) r_max_s = stride - (r_max % stride) if abs(r_max_s - stride) < 0.001: r_max_s = 0.0 r_min -= r_min_s r_max += r_max_s r_steps = int((r_max - r_min)/stride) if max_steps and r_steps > max_steps: return strided_range(o_min, o_max, stride*2) return [r_min] + list(r_min + e*stride for e in range(1, r_steps + 1)) + [r_max] def parse_option_string(s): if not isinstance(s, str): return None options = {} for token in s.split(';'): pieces = token.split('=') if len(pieces) == 1: option, value = pieces[0], "" elif len(pieces) == 2: option, value = pieces else: raise ValueError("Plot option string '%s' is malformed." % (s)) options[option.strip()] = value.strip() return options def dot_product(v1, v2): return sum(v1[i]*v2[i] for i in range(3)) def vec_sub(v1, v2): return tuple(v1[i] - v2[i] for i in range(3)) def vec_mag(v): return sum(v[i]**2 for i in range(3))**(0.5) sympy-sympy-1.9/sympy/plotting/tests/000077500000000000000000000000001412543434000201065ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/tests/__init__.py000066400000000000000000000000001412543434000222050ustar00rootroot00000000000000sympy-sympy-1.9/sympy/plotting/tests/test_experimental_lambdify.py000066400000000000000000000060671412543434000260740ustar00rootroot00000000000000from sympy.core.symbol import symbols, Symbol from sympy.functions import Max from sympy.plotting.experimental_lambdify import experimental_lambdify from sympy.plotting.intervalmath.interval_arithmetic import \ interval, intervalMembership # Tests for exception handling in experimental_lambdify def test_experimental_lambify(): x = Symbol('x') f = experimental_lambdify([x], Max(x, 5)) # XXX should f be tested? If f(2) is attempted, an # error is raised because a complex produced during wrapping of the arg # is being compared with an int. assert Max(2, 5) == 5 assert Max(5, 7) == 7 x = Symbol('x-3') f = experimental_lambdify([x], x + 1) assert f(1) == 2 def test_composite_boolean_region(): x, y = symbols('x y') r1 = (x - 1)**2 + y**2 < 2 r2 = (x + 1)**2 + y**2 < 2 f = experimental_lambdify((x, y), r1 & r2) a = (interval(-0.1, 0.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(True, True) a = (interval(-1.1, -0.9), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(0.9, 1.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(-0.1, 0.1), interval(1.9, 2.1)) assert f(*a) == intervalMembership(False, True) f = experimental_lambdify((x, y), r1 | r2) a = (interval(-0.1, 0.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(True, True) a = (interval(-1.1, -0.9), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(True, True) a = (interval(0.9, 1.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(True, True) a = (interval(-0.1, 0.1), interval(1.9, 2.1)) assert f(*a) == intervalMembership(False, True) f = experimental_lambdify((x, y), r1 & ~r2) a = (interval(-0.1, 0.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(-1.1, -0.9), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(0.9, 1.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(True, True) a = (interval(-0.1, 0.1), interval(1.9, 2.1)) assert f(*a) == intervalMembership(False, True) f = experimental_lambdify((x, y), ~r1 & r2) a = (interval(-0.1, 0.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(-1.1, -0.9), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(True, True) a = (interval(0.9, 1.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(-0.1, 0.1), interval(1.9, 2.1)) assert f(*a) == intervalMembership(False, True) f = experimental_lambdify((x, y), ~r1 & ~r2) a = (interval(-0.1, 0.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(-1.1, -0.9), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(0.9, 1.1), interval(-0.1, 0.1)) assert f(*a) == intervalMembership(False, True) a = (interval(-0.1, 0.1), interval(1.9, 2.1)) assert f(*a) == intervalMembership(True, True) sympy-sympy-1.9/sympy/plotting/tests/test_plot.py000066400000000000000000000563531412543434000225110ustar00rootroot00000000000000import os from tempfile import TemporaryDirectory from sympy import ( pi, sin, cos, Symbol, Integral, Sum, sqrt, log, exp, Ne, oo, LambertW, I, meijerg, exp_polar, Piecewise, And, real_root) from sympy.core.singleton import S from sympy.core.sympify import sympify from sympy.external import import_module from sympy.plotting.plot import ( Plot, plot, plot_parametric, plot3d_parametric_line, plot3d, plot3d_parametric_surface) from sympy.plotting.plot import ( unset_show, plot_contour, PlotGrid, DefaultBackend, MatplotlibBackend, TextBackend, BaseBackend) from sympy.testing.pytest import skip, raises, warns from sympy.utilities import lambdify as lambdify_ unset_show() matplotlib = import_module( 'matplotlib', min_module_version='1.1.0', catch=(RuntimeError,)) class DummyBackendNotOk(BaseBackend): """ Used to verify if users can create their own backends. This backend is meant to raise NotImplementedError for methods `show`, `save`, `close`. """ pass class DummyBackendOk(BaseBackend): """ Used to verify if users can create their own backends. This backend is meant to pass all tests. """ def show(self): pass def save(self): pass def close(self): pass def test_plot_and_save_1(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') y = Symbol('y') with TemporaryDirectory(prefix='sympy_') as tmpdir: ### # Examples from the 'introduction' notebook ### p = plot(x, legend=True, label='f1') p = plot(x*sin(x), x*cos(x), label='f2') p.extend(p) p[0].line_color = lambda a: a p[1].line_color = 'b' p.title = 'Big title' p.xlabel = 'the x axis' p[1].label = 'straight line' p.legend = True p.aspect_ratio = (1, 1) p.xlim = (-15, 20) filename = 'test_basic_options_and_colors.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p.extend(plot(x + 1)) p.append(plot(x + 3, x**2)[1]) filename = 'test_plot_extend_append.png' p.save(os.path.join(tmpdir, filename)) p[2] = plot(x**2, (x, -2, 3)) filename = 'test_plot_setitem.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot(sin(x), (x, -2*pi, 4*pi)) filename = 'test_line_explicit.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot(sin(x)) filename = 'test_line_default_range.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot((x**2, (x, -5, 5)), (x**3, (x, -3, 3))) filename = 'test_line_multiple_range.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() raises(ValueError, lambda: plot(x, y)) #Piecewise plots p = plot(Piecewise((1, x > 0), (0, True)), (x, -1, 1)) filename = 'test_plot_piecewise.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot(Piecewise((x, x < 1), (x**2, True)), (x, -3, 3)) filename = 'test_plot_piecewise_2.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # test issue 7471 p1 = plot(x) p2 = plot(3) p1.extend(p2) filename = 'test_horizontal_line.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # test issue 10925 f = Piecewise((-1, x < -1), (x, And(-1 <= x, x < 0)), \ (x**2, And(0 <= x, x < 1)), (x**3, x >= 1)) p = plot(f, (x, -3, 3)) filename = 'test_plot_piecewise_3.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() def test_plot_and_save_2(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') y = Symbol('y') z = Symbol('z') with TemporaryDirectory(prefix='sympy_') as tmpdir: #parametric 2d plots. #Single plot with default range. p = plot_parametric(sin(x), cos(x)) filename = 'test_parametric.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() #Single plot with range. p = plot_parametric( sin(x), cos(x), (x, -5, 5), legend=True, label='parametric_plot') filename = 'test_parametric_range.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() #Multiple plots with same range. p = plot_parametric((sin(x), cos(x)), (x, sin(x))) filename = 'test_parametric_multiple.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() #Multiple plots with different ranges. p = plot_parametric( (sin(x), cos(x), (x, -3, 3)), (x, sin(x), (x, -5, 5))) filename = 'test_parametric_multiple_ranges.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() #depth of recursion specified. p = plot_parametric(x, sin(x), depth=13) filename = 'test_recursion_depth.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() #No adaptive sampling. p = plot_parametric(cos(x), sin(x), adaptive=False, nb_of_points=500) filename = 'test_adaptive.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() #3d parametric plots p = plot3d_parametric_line( sin(x), cos(x), x, legend=True, label='3d_parametric_plot') filename = 'test_3d_line.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot3d_parametric_line( (sin(x), cos(x), x, (x, -5, 5)), (cos(x), sin(x), x, (x, -3, 3))) filename = 'test_3d_line_multiple.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot3d_parametric_line(sin(x), cos(x), x, nb_of_points=30) filename = 'test_3d_line_points.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # 3d surface single plot. p = plot3d(x * y) filename = 'test_surface.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # Multiple 3D plots with same range. p = plot3d(-x * y, x * y, (x, -5, 5)) filename = 'test_surface_multiple.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # Multiple 3D plots with different ranges. p = plot3d( (x * y, (x, -3, 3), (y, -3, 3)), (-x * y, (x, -3, 3), (y, -3, 3))) filename = 'test_surface_multiple_ranges.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # Single Parametric 3D plot p = plot3d_parametric_surface(sin(x + y), cos(x - y), x - y) filename = 'test_parametric_surface.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # Multiple Parametric 3D plots. p = plot3d_parametric_surface( (x*sin(z), x*cos(z), z, (x, -5, 5), (z, -5, 5)), (sin(x + y), cos(x - y), x - y, (x, -5, 5), (y, -5, 5))) filename = 'test_parametric_surface.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # Single Contour plot. p = plot_contour(sin(x)*sin(y), (x, -5, 5), (y, -5, 5)) filename = 'test_contour_plot.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # Multiple Contour plots with same range. p = plot_contour(x**2 + y**2, x**3 + y**3, (x, -5, 5), (y, -5, 5)) filename = 'test_contour_plot.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # Multiple Contour plots with different range. p = plot_contour( (x**2 + y**2, (x, -5, 5), (y, -5, 5)), (x**3 + y**3, (x, -3, 3), (y, -3, 3))) filename = 'test_contour_plot.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() def test_plot_and_save_3(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') y = Symbol('y') z = Symbol('z') with TemporaryDirectory(prefix='sympy_') as tmpdir: ### # Examples from the 'colors' notebook ### p = plot(sin(x)) p[0].line_color = lambda a: a filename = 'test_colors_line_arity1.png' p.save(os.path.join(tmpdir, filename)) p[0].line_color = lambda a, b: b filename = 'test_colors_line_arity2.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot(x*sin(x), x*cos(x), (x, 0, 10)) p[0].line_color = lambda a: a filename = 'test_colors_param_line_arity1.png' p.save(os.path.join(tmpdir, filename)) p[0].line_color = lambda a, b: a filename = 'test_colors_param_line_arity1.png' p.save(os.path.join(tmpdir, filename)) p[0].line_color = lambda a, b: b filename = 'test_colors_param_line_arity2b.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot3d_parametric_line(sin(x) + 0.1*sin(x)*cos(7*x), cos(x) + 0.1*cos(x)*cos(7*x), 0.1*sin(7*x), (x, 0, 2*pi)) p[0].line_color = lambdify_(x, sin(4*x)) filename = 'test_colors_3d_line_arity1.png' p.save(os.path.join(tmpdir, filename)) p[0].line_color = lambda a, b: b filename = 'test_colors_3d_line_arity2.png' p.save(os.path.join(tmpdir, filename)) p[0].line_color = lambda a, b, c: c filename = 'test_colors_3d_line_arity3.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot3d(sin(x)*y, (x, 0, 6*pi), (y, -5, 5)) p[0].surface_color = lambda a: a filename = 'test_colors_surface_arity1.png' p.save(os.path.join(tmpdir, filename)) p[0].surface_color = lambda a, b: b filename = 'test_colors_surface_arity2.png' p.save(os.path.join(tmpdir, filename)) p[0].surface_color = lambda a, b, c: c filename = 'test_colors_surface_arity3a.png' p.save(os.path.join(tmpdir, filename)) p[0].surface_color = lambdify_((x, y, z), sqrt((x - 3*pi)**2 + y**2)) filename = 'test_colors_surface_arity3b.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot3d_parametric_surface(x * cos(4 * y), x * sin(4 * y), y, (x, -1, 1), (y, -1, 1)) p[0].surface_color = lambda a: a filename = 'test_colors_param_surf_arity1.png' p.save(os.path.join(tmpdir, filename)) p[0].surface_color = lambda a, b: a*b filename = 'test_colors_param_surf_arity2.png' p.save(os.path.join(tmpdir, filename)) p[0].surface_color = lambdify_((x, y, z), sqrt(x**2 + y**2 + z**2)) filename = 'test_colors_param_surf_arity3.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() def test_plot_and_save_4(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') y = Symbol('y') ### # Examples from the 'advanced' notebook ### # XXX: This raises the warning "The evaluation of the expression is # problematic. We are trying a failback method that may still work. Please # report this as a bug." It has to use the fallback because using evalf() # is the only way to evaluate the integral. We should perhaps just remove # that warning. with TemporaryDirectory(prefix='sympy_') as tmpdir: with warns( UserWarning, match="The evaluation of the expression is problematic"): i = Integral(log((sin(x)**2 + 1)*sqrt(x**2 + 1)), (x, 0, y)) p = plot(i, (y, 1, 5)) filename = 'test_advanced_integral.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() def test_plot_and_save_5(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') y = Symbol('y') with TemporaryDirectory(prefix='sympy_') as tmpdir: s = Sum(1/x**y, (x, 1, oo)) p = plot(s, (y, 2, 10)) filename = 'test_advanced_inf_sum.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p = plot(Sum(1/x, (x, 1, y)), (y, 2, 10), show=False) p[0].only_integers = True p[0].steps = True filename = 'test_advanced_fin_sum.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() def test_plot_and_save_6(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') with TemporaryDirectory(prefix='sympy_') as tmpdir: filename = 'test.png' ### # Test expressions that can not be translated to np and generate complex # results. ### p = plot(sin(x) + I*cos(x)) p.save(os.path.join(tmpdir, filename)) p = plot(sqrt(sqrt(-x))) p.save(os.path.join(tmpdir, filename)) p = plot(LambertW(x)) p.save(os.path.join(tmpdir, filename)) p = plot(sqrt(LambertW(x))) p.save(os.path.join(tmpdir, filename)) #Characteristic function of a StudentT distribution with nu=10 x1 = 5 * x**2 * exp_polar(-I*pi)/2 m1 = meijerg(((1 / 2,), ()), ((5, 0, 1 / 2), ()), x1) x2 = 5*x**2 * exp_polar(I*pi)/2 m2 = meijerg(((1/2,), ()), ((5, 0, 1/2), ()), x2) expr = (m1 + m2) / (48 * pi) p = plot(expr, (x, 1e-6, 1e-2)) p.save(os.path.join(tmpdir, filename)) def test_plotgrid_and_save(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') y = Symbol('y') with TemporaryDirectory(prefix='sympy_') as tmpdir: p1 = plot(x) p2 = plot_parametric((sin(x), cos(x)), (x, sin(x)), show=False) p3 = plot_parametric( cos(x), sin(x), adaptive=False, nb_of_points=500, show=False) p4 = plot3d_parametric_line(sin(x), cos(x), x, show=False) # symmetric grid p = PlotGrid(2, 2, p1, p2, p3, p4) filename = 'test_grid1.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() # grid size greater than the number of subplots p = PlotGrid(3, 4, p1, p2, p3, p4) filename = 'test_grid2.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() p5 = plot(cos(x),(x, -pi, pi), show=False) p5[0].line_color = lambda a: a p6 = plot(Piecewise((1, x > 0), (0, True)), (x, -1, 1), show=False) p7 = plot_contour( (x**2 + y**2, (x, -5, 5), (y, -5, 5)), (x**3 + y**3, (x, -3, 3), (y, -3, 3)), show=False) # unsymmetric grid (subplots in one line) p = PlotGrid(1, 3, p5, p6, p7) filename = 'test_grid3.png' p.save(os.path.join(tmpdir, filename)) p._backend.close() def test_append_issue_7140(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') p1 = plot(x) p2 = plot(x**2) plot(x + 2) # append a series p2.append(p1[0]) assert len(p2._series) == 2 with raises(TypeError): p1.append(p2) with raises(TypeError): p1.append(p2._series) def test_issue_15265(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') eqn = sin(x) p = plot(eqn, xlim=(-S.Pi, S.Pi), ylim=(-1, 1)) p._backend.close() p = plot(eqn, xlim=(-1, 1), ylim=(-S.Pi, S.Pi)) p._backend.close() p = plot(eqn, xlim=(-1, 1), ylim=(sympify('-3.14'), sympify('3.14'))) p._backend.close() p = plot(eqn, xlim=(sympify('-3.14'), sympify('3.14')), ylim=(-1, 1)) p._backend.close() raises(ValueError, lambda: plot(eqn, xlim=(-S.ImaginaryUnit, 1), ylim=(-1, 1))) raises(ValueError, lambda: plot(eqn, xlim=(-1, 1), ylim=(-1, S.ImaginaryUnit))) raises(ValueError, lambda: plot(eqn, xlim=(S.NegativeInfinity, 1), ylim=(-1, 1))) raises(ValueError, lambda: plot(eqn, xlim=(-1, 1), ylim=(-1, S.Infinity))) def test_empty_Plot(): if not matplotlib: skip("Matplotlib not the default backend") # No exception showing an empty plot plot() p = Plot() p.show() def test_issue_17405(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') f = x**0.3 - 10*x**3 + x**2 p = plot(f, (x, -10, 10), show=False) # Random number of segments, probably more than 100, but we want to see # that there are segments generated, as opposed to when the bug was present assert len(p[0].get_data()[0]) >= 30 def test_logplot_PR_16796(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') p = plot(x, (x, .001, 100), xscale='log', show=False) # Random number of segments, probably more than 100, but we want to see # that there are segments generated, as opposed to when the bug was present assert len(p[0].get_data()[0]) >= 30 assert p[0].end == 100.0 assert p[0].start == .001 def test_issue_16572(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') p = plot(LambertW(x), show=False) # Random number of segments, probably more than 50, but we want to see # that there are segments generated, as opposed to when the bug was present assert len(p[0].get_data()[0]) >= 30 def test_issue_11865(): if not matplotlib: skip("Matplotlib not the default backend") k = Symbol('k', integer=True) f = Piecewise((-I*exp(I*pi*k)/k + I*exp(-I*pi*k)/k, Ne(k, 0)), (2*pi, True)) p = plot(f, show=False) # Random number of segments, probably more than 100, but we want to see # that there are segments generated, as opposed to when the bug was present # and that there are no exceptions. assert len(p[0].get_data()[0]) >= 30 def test_issue_11461(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') p = plot(real_root((log(x/(x-2))), 3), show=False) # Random number of segments, probably more than 100, but we want to see # that there are segments generated, as opposed to when the bug was present # and that there are no exceptions. assert len(p[0].get_data()[0]) >= 30 def test_issue_11764(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') p = plot_parametric(cos(x), sin(x), (x, 0, 2 * pi), aspect_ratio=(1,1), show=False) p.aspect_ratio == (1, 1) # Random number of segments, probably more than 100, but we want to see # that there are segments generated, as opposed to when the bug was present assert len(p[0].get_data()[0]) >= 30 def test_issue_13516(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') pm = plot(sin(x), backend="matplotlib", show=False) assert pm.backend == MatplotlibBackend assert len(pm[0].get_data()[0]) >= 30 pt = plot(sin(x), backend="text", show=False) assert pt.backend == TextBackend assert len(pt[0].get_data()[0]) >= 30 pd = plot(sin(x), backend="default", show=False) assert pd.backend == DefaultBackend assert len(pd[0].get_data()[0]) >= 30 p = plot(sin(x), show=False) assert p.backend == DefaultBackend assert len(p[0].get_data()[0]) >= 30 def test_plot_limits(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') p = plot(x, x**2, (x, -10, 10)) backend = p._backend xmin, xmax = backend.ax[0].get_xlim() assert abs(xmin + 10) < 2 assert abs(xmax - 10) < 2 ymin, ymax = backend.ax[0].get_ylim() assert abs(ymin + 10) < 10 assert abs(ymax - 100) < 10 def test_plot3d_parametric_line_limits(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') v1 = (2*cos(x), 2*sin(x), 2*x, (x, -5, 5)) v2 = (sin(x), cos(x), x, (x, -5, 5)) p = plot3d_parametric_line(v1, v2) backend = p._backend xmin, xmax = backend.ax[0].get_xlim() assert abs(xmin + 2) < 1e-2 assert abs(xmax - 2) < 1e-2 ymin, ymax = backend.ax[0].get_ylim() assert abs(ymin + 2) < 1e-2 assert abs(ymax - 2) < 1e-2 zmin, zmax = backend.ax[0].get_zlim() assert abs(zmin + 10) < 1e-2 assert abs(zmax - 10) < 1e-2 p = plot3d_parametric_line(v2, v1) backend = p._backend xmin, xmax = backend.ax[0].get_xlim() assert abs(xmin + 2) < 1e-2 assert abs(xmax - 2) < 1e-2 ymin, ymax = backend.ax[0].get_ylim() assert abs(ymin + 2) < 1e-2 assert abs(ymax - 2) < 1e-2 zmin, zmax = backend.ax[0].get_zlim() assert abs(zmin + 10) < 1e-2 assert abs(zmax - 10) < 1e-2 def test_plot_size(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') p1 = plot(sin(x), backend="matplotlib", size=(8, 4)) s1 = p1._backend.fig.get_size_inches() assert (s1[0] == 8) and (s1[1] == 4) p2 = plot(sin(x), backend="matplotlib", size=(5, 10)) s2 = p2._backend.fig.get_size_inches() assert (s2[0] == 5) and (s2[1] == 10) p3 = PlotGrid(2, 1, p1, p2, size=(6, 2)) s3 = p3._backend.fig.get_size_inches() assert (s3[0] == 6) and (s3[1] == 2) with raises(ValueError): plot(sin(x), backend="matplotlib", size=(-1, 3)) def test_issue_20113(): if not matplotlib: skip("Matplotlib not the default backend") x = Symbol('x') # verify the capability to use custom backends with raises(TypeError): plot(sin(x), backend=Plot, show=False) p2 = plot(sin(x), backend=MatplotlibBackend, show=False) assert p2.backend == MatplotlibBackend assert len(p2[0].get_data()[0]) >= 30 p3 = plot(sin(x), backend=DummyBackendOk, show=False) assert p3.backend == DummyBackendOk assert len(p3[0].get_data()[0]) >= 30 # test for an improper coded backend p4 = plot(sin(x), backend=DummyBackendNotOk, show=False) assert p4.backend == DummyBackendNotOk assert len(p4[0].get_data()[0]) >= 30 with raises(NotImplementedError): p4.show() with raises(NotImplementedError): p4.save("test/path") with raises(NotImplementedError): p4._backend.close() def test_custom_coloring(): x = Symbol('x') y = Symbol('y') plot(cos(x), line_color=lambda a: a) plot(cos(x), line_color=1) plot(cos(x), line_color="r") plot_parametric(cos(x), sin(x), line_color=lambda a: a) plot_parametric(cos(x), sin(x), line_color=1) plot_parametric(cos(x), sin(x), line_color="r") plot3d_parametric_line(cos(x), sin(x), x, line_color=lambda a: a) plot3d_parametric_line(cos(x), sin(x), x, line_color=1) plot3d_parametric_line(cos(x), sin(x), x, line_color="r") plot3d_parametric_surface(cos(x + y), sin(x - y), x - y, (x, -5, 5), (y, -5, 5), surface_color=lambda a, b: a**2 + b**2) plot3d_parametric_surface(cos(x + y), sin(x - y), x - y, (x, -5, 5), (y, -5, 5), surface_color=1) plot3d_parametric_surface(cos(x + y), sin(x - y), x - y, (x, -5, 5), (y, -5, 5), surface_color="r") plot3d(x*y, (x, -5, 5), (y, -5, 5), surface_color=lambda a, b: a**2 + b**2) plot3d(x*y, (x, -5, 5), (y, -5, 5), surface_color=1) plot3d(x*y, (x, -5, 5), (y, -5, 5), surface_color="r") sympy-sympy-1.9/sympy/plotting/tests/test_plot_implicit.py000066400000000000000000000113601412543434000243700ustar00rootroot00000000000000from sympy import (plot_implicit, cos, Symbol, symbols, Eq, sin, re, And, Or, exp, I, tan, pi) from sympy.plotting.plot import unset_show from tempfile import NamedTemporaryFile, mkdtemp from sympy.testing.pytest import skip, warns from sympy.external import import_module from sympy.testing.tmpfiles import TmpFileManager import os #Set plots not to show unset_show() def tmp_file(dir=None, name=''): return NamedTemporaryFile( suffix='.png', dir=dir, delete=False).name def plot_and_save(expr, *args, name='', dir=None, **kwargs): p = plot_implicit(expr, *args, **kwargs) p.save(tmp_file(dir=dir, name=name)) # Close the plot to avoid a warning from matplotlib p._backend.close() def plot_implicit_tests(name): temp_dir = mkdtemp() TmpFileManager.tmp_folder(temp_dir) x = Symbol('x') y = Symbol('y') #implicit plot tests plot_and_save(Eq(y, cos(x)), (x, -5, 5), (y, -2, 2), name=name, dir=temp_dir) plot_and_save(Eq(y**2, x**3 - x), (x, -5, 5), (y, -4, 4), name=name, dir=temp_dir) plot_and_save(y > 1 / x, (x, -5, 5), (y, -2, 2), name=name, dir=temp_dir) plot_and_save(y < 1 / tan(x), (x, -5, 5), (y, -2, 2), name=name, dir=temp_dir) plot_and_save(y >= 2 * sin(x) * cos(x), (x, -5, 5), (y, -2, 2), name=name, dir=temp_dir) plot_and_save(y <= x**2, (x, -3, 3), (y, -1, 5), name=name, dir=temp_dir) #Test all input args for plot_implicit plot_and_save(Eq(y**2, x**3 - x), dir=temp_dir) plot_and_save(Eq(y**2, x**3 - x), adaptive=False, dir=temp_dir) plot_and_save(Eq(y**2, x**3 - x), adaptive=False, points=500, dir=temp_dir) plot_and_save(y > x, (x, -5, 5), dir=temp_dir) plot_and_save(And(y > exp(x), y > x + 2), dir=temp_dir) plot_and_save(Or(y > x, y > -x), dir=temp_dir) plot_and_save(x**2 - 1, (x, -5, 5), dir=temp_dir) plot_and_save(x**2 - 1, dir=temp_dir) plot_and_save(y > x, depth=-5, dir=temp_dir) plot_and_save(y > x, depth=5, dir=temp_dir) plot_and_save(y > cos(x), adaptive=False, dir=temp_dir) plot_and_save(y < cos(x), adaptive=False, dir=temp_dir) plot_and_save(And(y > cos(x), Or(y > x, Eq(y, x))), dir=temp_dir) plot_and_save(y - cos(pi / x), dir=temp_dir) #Test plots which cannot be rendered using the adaptive algorithm with warns(UserWarning, match="Adaptive meshing could not be applied"): plot_and_save(Eq(y, re(cos(x) + I*sin(x))), name=name, dir=temp_dir) plot_and_save(x**2 - 1, title='An implicit plot', dir=temp_dir) def test_line_color(): x, y = symbols('x, y') p = plot_implicit(x**2 + y**2 - 1, line_color="green", show=False) assert p._series[0].line_color == "green" p = plot_implicit(x**2 + y**2 - 1, line_color='r', show=False) assert p._series[0].line_color == "r" def test_matplotlib(): matplotlib = import_module('matplotlib', min_module_version='1.1.0', catch=(RuntimeError,)) if matplotlib: try: plot_implicit_tests('test') test_line_color() finally: TmpFileManager.cleanup() else: skip("Matplotlib not the default backend") def test_region_and(): matplotlib = import_module('matplotlib', min_module_version='1.1.0', catch=(RuntimeError,)) if not matplotlib: skip("Matplotlib not the default backend") from matplotlib.testing.compare import compare_images test_directory = os.path.dirname(os.path.abspath(__file__)) try: temp_dir = mkdtemp() TmpFileManager.tmp_folder(temp_dir) x, y = symbols('x y') r1 = (x - 1)**2 + y**2 < 2 r2 = (x + 1)**2 + y**2 < 2 test_filename = tmp_file(dir=temp_dir, name="test_region_and") cmp_filename = os.path.join(test_directory, "test_region_and.png") p = plot_implicit(r1 & r2, x, y) p.save(test_filename) compare_images(cmp_filename, test_filename, 0.005) test_filename = tmp_file(dir=temp_dir, name="test_region_or") cmp_filename = os.path.join(test_directory, "test_region_or.png") p = plot_implicit(r1 | r2, x, y) p.save(test_filename) compare_images(cmp_filename, test_filename, 0.005) test_filename = tmp_file(dir=temp_dir, name="test_region_not") cmp_filename = os.path.join(test_directory, "test_region_not.png") p = plot_implicit(~r1, x, y) p.save(test_filename) compare_images(cmp_filename, test_filename, 0.005) test_filename = tmp_file(dir=temp_dir, name="test_region_xor") cmp_filename = os.path.join(test_directory, "test_region_xor.png") p = plot_implicit(r1 ^ r2, x, y) p.save(test_filename) compare_images(cmp_filename, test_filename, 0.005) finally: TmpFileManager.cleanup() sympy-sympy-1.9/sympy/plotting/tests/test_region_and.png000066400000000000000000000153201412543434000237610ustar00rootroot00000000000000PNG  IHDR5sBIT|d pHYsaa?i8tEXtSoftwarematplotlib version3.1.0, http://matplotlib.org/.IDATxu״9E,bKW{*`ݫhZd4) $ȑ ^Pv)]C#MVB5E-$R@F 4@ i tOHii8|Ox$}ד<̴:N'1[P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#ZdI`7U/r-ZO>9_yG(Ov6oޜO}S2s̜uYYvm~6=tnt`ĵ:vУ>o|L2%seOnz= dhh(M0c旿e֭[ueĉ?y;ߙnʰwUVeݺu7o^.\pKY&'K/5<숦z;wcXz̟?,^8o}[&+Zzu;L;Ї`\9FÚ5k#dÆ nGk4YzΦMrW[oɓke˖e```mƌ<%@sZN#;ȹ瞛'ڶcǎZL0!{<{pƌJ0 ~y'vfΜ9?W%ɤI2iҤQ9}}};wێ>mok;@E(5n300@'Y(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1e˖NK___Ns9'?ϛ `\@OZ~}{~,Z(jӣ4t:M0ڶnݚSf9v2441`cahh(Ir1 nd.&x yN'W]uU>dܹ|βe2006cƌ1`x yG>}>3fx I^z_~`%ɤI2iҤ1 9IN'_~ynw}5kV#I7|;?$ȑGtr ГZ>Z*K,Yza>P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b >|MO0z nx 9;6^t:/MK^x!II 0$y䬳m~l۶c/8s%s&?Acޏ}lsw(m~.]:s&_$ɯ~W}~ћ ` @5kŋ'<}|5#?X@9۷'_z3gc `@ ?{X=ֆ ~,$R/OzhCcN PW #;8\@0׿cc#l }z{ÁzmrMn `@Odsu:s} P@_<؝G г` 4=pWVvf̘M6E/,ڵEvI$'{w{I$ydGx /K?FdƯ=Cb赟E@/V?u&'˸Nr1}?쨣?փb8yЃޒǾm$c?8c hM |UO$95ɟ%)ݏ$&MҥK3iҤG)ZɄ=^h|6&+;f„8㇟E&g|sr#uv$CkWJ,9#@8{z;H4=>ld3Z`wˢEꫯ6=Zi?pn;_4c`wߝ*w+>hϟX]Yre6n(ފ {|1 ̂$$YvG"غukNOoz^y啼=W|sbŊ Xd/B.䒬^:G4lhh(sLcII %y`aCCCIA9}Q8D]:N,YK/4zj㰛~:7xc.1;ܼ0{nK#qo~\hw]UW]|;wn㔴f͚<#YW`]w]Z֛6lؐo1v;^{m#Yn˖-93sy/nh_šǶ?#¡ԧ>'G)iӦM+r뭷fMp `۶m˶m93g矟;3ݾtǎ8qb.r-=jߟknٲ% .̂ r7gf_k$Ɂ]2=QInK~ ?$y,>I'%|rr~/wܑ?fjz㎜{8qm;vHʄ 2<mo)кuSO婧+-←S@h]L+=7fʕI38cVʒ%K~ !^zO~*>=y%묳C0jr͛,Z46+rSv%N=+s{o(k/ώp N:)9d4>}z'4 (cp`"ͽc. Pʗ\tQrч~_>c%t= ~06+@I}\˼yc}ɏG Ƀl PW$?>3+@yO?|ݕ;_ۺ ݕիٳ`DXʛ=;y꫓ɓ~|c< puL6-_vm-Yn]5 nMK^x!}+sNx̙3'~sggŊM6 n^y 3ʝwgʔ'F`ޜviyg{؇v> ߟ~~dܹٴiS6lؐyyP1W7=06nܘ-[dΝyg1Vng` ۷}oϟ9sK_RxwqM6 >@=W_}u֮]K.$j/_xBt`4]Yre6nܸ dhh(8سs1o nG{,ƸiO?tn\zoe˖e```mƌc4!aKzۆ g˖-93sy/~_{u۴ihq@రm۶l۶M3sL<9I7.\ o΄ ]5acͱ_ݼys.\SN9%V:u)[lgO<1˗/֭[w=6mڴ'? S֭[z*O=TOcxr >e.(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1P(F#@b @1̟??V+=XY\sMN8ᄦw Г[.˗/ozq爦i/B.q9ꨣk nGk߭j@1=KFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF#jYhQc +Wf̙6mZ{{$ @`D} _=ܓs߲>?]j?VQ]OO=tے|&ɧ IoiuI&'K[,p+~hE7lcY'?ɇk ,Vdem\*$$9$ys1VX&+~{鞖d}'~'i4(6Ym2ɉI= Y&+~` 4&+~PPPPPPPPPPPPPPPPPPPPPPPPPP`A$=@G@ݚI_ C $$dks@NrB=@GٮF5I&Y2ްm?t +@-O$d_ M#3@iZf==uO<$c7yl]3ǤZk85I_Gc0@%=vz-O$ah>4Ф$7{)I@X V # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #Z$dV:@@Cݔ$7'Y$3s(jZuzzSޔ^"Y':Ծ&'}mۛU&$SoJ֭Kz+/O~@=zZV!YOO#?$}IzGM<9a%}vC[)wޙH+~` 4裓+۰QY.y[a$^? )o7(Fرɇ>pC +mMUxb_>S}a8^?Mi#חޑ0s_U= MRz i϶~x'T$`V]n랄MK%'\$ `WĉuO–Sw%;P4 PvH_Lvܱix2W_K&O{^(;Q*W$ ԟYrCΕ@>3랂=;m>c({[Eo;~'""̟͝/#3@q^ @yM2gNS0C{ lh>5{ F)T{[&F3&랂6aBuv{LhNHN:){'^XЙ Xc$dSPW2yֳ: oHL{ %S@@c}uO@'8yϫ{ ,hsΩO}j=t4y%==uOA8C:/":)$'&/zQS@@-vDg';T (S8-;O)3@QfͲ͝[ (^t @Qܳ dӧ'{UP?4Ʃ @핯{cc8 ~h3Ϭ{?dƘ2 ɴiuO@#s2n˲f9xz0h3k6{nwnˋ_YlY}C1&O{K.ɜ9srg9yN.L:5_~yݣͫ{vuZVu$Y6~f͚,Y$sN7>裏΢EFWիx{{KϥuO@I&kGa3~J}}}{Z6Zӄ$S,OR7B׼&+V~헅 {9_|q,] |pŊ9${H3u,_|Mo*Ls~Fhp?4 xink1XollgرYrァ?O&M*vGgTNgv > #i*:%=Kp/~ϧ>|3OӜwyYlY:vd\wozZ N:)?pfŊ>}zկxƀ^?nUm~uiFݸqwע#NiSǎBGϓg?{xkY%%TC2}z_= u*~란n𕯈?@c|uO >lr)?آ ~h~@x2K=O'F]I$7Ʉ$Juݚg[Ǡ]vey$9ꨣxߔA[`A=L4){f͚gmg=LmAέ{HuQ;OOI~I1;+|kk͹瞛??I0|-[6 17tS>|Ypay̜93V{~{Y$H .Ӧf^kI'B&-j 8IdƌI?uס~ƌy ^|^fƌ5kV,X02(>`v}tM9ꨣr0V%yA˒\KkhJ+l$g&2ĚgRok׬YKf̙{|̙7 ю$. `?ΉJtvAhd$zGa3LT_M pɇz(֭˔)S)Sr} t EsGfCzٶ$U`'y{-S=bS&yE1Zvŋ;gc;Zct͝;7?sW}{Jnq65kpswϦے.\tEY|y8|#eGwyWdz_:9ᇇq068&.ӽ`9$]? )D׏F[$yiѢ}{ Lh/O6\CB'眓[W$Й x^6C}֯O.u@ޚ]uOhw /{ l('~S0~o{ |(~|r= #aݺӒI @(u uݓ0In);@8KV 7Xx;vr0H a?|uOEźB}ݓ0T $s v%Yg%k= umS@w@29䷿{bݺB?${$yr-ar76U]zZoܞ'3v[I&O=uWR$t&{YrtA9r饗=بm,\sM%W CwvoSwܑ[o5Ǐ{Q'$yz{?sNq= Iggɒ%y_@p f݌I?;K֭K>WIsw=Lm 8?{2}g$^IrJrfΜ9v.`h$e޼&أo.'yޚIȺu;%/yI&M/u6l_]rdƌ[ߪ{f/$4ɕIz3f̘\yw/j`MV[L; dE/J>ٚgժd޼+ꞄR^?MjN;%|e%6ڳ5ɅV/Ꞇ^?Mp=LN=5y׻'랆^?MjpN;U9Uٺ˚5ɏ~T]'($:{]2aM-֬I-J. ?$׏lj?77.9Xt8f\'_zkr]w=lY#$/75qbxe/;VH~kݼV=l[#$F&7ɴi}ngJ+2eD>հZ:K_J~H~󛺧)~` 4v-gO>˿~|-Z*Y:oٲL~׏lܒv}wO;n?OZ݊mݺ$K3^?M3pkƎ}|frN/~H9J.$:;^?c% # # # # # # # # # # # # # # #+ɜ$&YIޝdM3t`xݙd}J$?JrfUI>X\j=m'<ɯ$%^?V%eYaۨce&9ko6u{lc[kM$'&9cT+47@q ` ۓ' 7KH ߻&+~t]7lqO;8 0&9&ީ.&m:8hböf}>8Mr 4Y@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@V'90IOks@:@${] I&57lP 0$AnAɛlS}2N!.T's<ٶ$GS޽}$}lˇchjZuzzJІ$_JK26)Iy?J`_ tGIBYwo'|I@hI @;nYx4c ch}R FV # # # # # # # # # # # # # # # # # # # # # # # # # # # # # ]tV ߟL%uO0zZ- V+WfҤI{a% @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@'B'.IENDB`sympy-sympy-1.9/sympy/plotting/tests/test_region_or.png000066400000000000000000000211511412543434000236360ustar00rootroot00000000000000PNG  IHDR5sBIT|d pHYsaa?i8tEXtSoftwarematplotlib version3.1.0, http://matplotlib.org/ IDATx}u:07%ެ[Dª嶺ز֖V>4j54ݕJ2fׇSK4SlE,,S6qӲ]53 Rgr@\3|>3^{]纚@1{(((((((((((((((((((((((((((((((((((((((((((((((((((((zդIr-=/"^tva{sgd…uP<oYpa>я[VFwꪫ|{E]]]HWWWݣ.}g?Y.|_͐!Cr1#H{G[KGGGZ[[ޞQV>gΜ93gN /˼u˗(@W-_<^{mfΜ9sdԨQ92q :4I2k֬xyꩧjv +@#۲׼&+WG=z˞3nܸUa:2Yzե^}=MMM9_@CsdԨQuo@a=38qb.luo@aM2%ǏϡZ(ʖuf͚{'sݠwvvs vV`tI2x zںSԧ!zٳsGdРA[bE[s%ݯ=---}6;@_ h8o{_bǎ=9^IܜVh8Cȑ#zlˎ;J@8immu АFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF i;vlw9&Lȃ>XX7ߜ)S; 7ܐ>vX}ٺG]SWWWWCŋgw7ߜ}~GGGZ[[ޞ>lY}=I;ttvv's.`uuuSNA#Gvӧu;v oʔ)w[o5Æ 9ݭ 4$},^{mnW$innNsssNP4|cW_n){G#hHSL_k&Co$Ikkkfc3g̤Iz@![W40ٲǒ3Mp@S;L.l_wiɰa=?5uuuu=,X,_;߹U{zy礵]xaֶ5Hkkk?G_ 9ޞw3ڒ_V[%]{>wi6-&zg[oLܷ?גe˪>>%Jnۓŋg}2?zݒsٗ8eJpaw<|W'o~s_uX<Pyy%gW+L+W=զ[rԨ䬳wL^e'dW=\}bjv„wn@&AuWr5?Irӛ;Kϫ_{BOUW%?կU OtPY}w'_<@ 4ӫݺ!lZv)67jG'ܴYjwԩՇXEBx?LM򕺧?8"y{Kw^=$vr9p;d̘C]v{@6o^ 7=M~P}`aCmJxcrUҽ=u3q I|yr8y' I٦yɫ^oh>t2sfLyoPzUr%n#}Gsg=v1է?d??SF/NJ eÓn{7VPox˯8Jre_T7%Slu@"KK=ѣc/]/]Z=whno|eO}*җ/=裓kiY{0iԩSO%W\QoSNI>'%? ;Wv߽:wd[s8%=YY"9*_8M` ̕W&cV}o޼jW:(+WVر6,+Џ|lh$I]g!1Iq@~dJ3&גQ>f^Z]V͝[m+^Z$0Y}Sy%uOYZZO)aV&ݖtQm;΋ NB .({چ.I`` ا?|Iggݓnv?S= ,VMA\]NB93Ї;{h,wQm[3g= C%?AcuOǪm졇 uնvuO^ɏ~ӾW~IЋfJ8),gQm{+K~st96tOB/xdΜt6uO^'gUPr~@x%zs9I`m.=l#ꞂRp꫓ +Ѓ/|ն !=xruOحV&2o^ruOt+m@!M=НFO~R'ն 0;L<)Y>܈#9Y(ʹxqo=!j {7)yv7,=)^V # #a3<`YvdɟYS;}{ @@d$Z4+I~/#: РdrY$iKr^C [=@ՕK=5z智'{˒M>̱_%%mUvwe{晤ÿ :4MMMuQ  imm{ `O (+ikk˂ 6C%c;vM N=9Ooŋ?+ɬ$t󚗮>k7n3&緋N٧Gު(E+voViiiiO_2޹%ps N2(nsHl?ۡ|zOmC$t|h@[: /y$oq+@:%Ir` R: inn駟G!INW6ϑI~?R72쾁o~ɯv_qlN<0YIyܨv)d@ {̀~@@@@ٙѣG){ok{~OI&'#6IL)e=ֹIoMg)$cS{$}zr'= HҭSO=5}kc@ndԨ~Lr~_&r{2W&99'^`w: }$Sܙ$'9,ɳFU,\Q=}H2_}̙3f=JO23_v]_J:6QdR'ycmb~3}gĉsf{6d-Otttdԩu< |3{ִ$M빽Ev /q=70]'גO:y≺'A|s.F#Gf;wnFUHp #''7ܐISSӔ%C띥dMMնp ⏞#dѢEYre͛W8ϼ W67=MydѢ5ǘ=`}&',[,'N̑G~'{d3{'\|qrV[yf/O34)yZmh{]V1=馛n?A$?~FӧOy¾%aX<ǓsΩ{'_B/^wʼyɩ&f Z)S/yzd5ftӦU_?g]$O>sOuizu܆T?K '^jӒ?}b7ߜyf2h7y[kk{(l˓_ʮu0!O6t_'go2%{H^꺧r @hC2~;S5dHkc~0yWJ6%j~\ziue'Lyf# fc-:`;jWdi;9moK;iРy$+lO|SҘ1==̝[~U7M|]f `ٲWCէw꘾J I=<\bEOV &էɾ_d},O<$[=> t5kK_y֧9wܱDXoι9nsNݟgW_l<{}K{lYZZռUZM4hͪ__|{V-K5Xtt~5_|k&}7  NPz*6/^3v u+Y0'#$?ƿqk*[m|~!M :dz~p]~8֍ݻ޵@ @Eз @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a P}L<9{Gf9ӳlٲG7{dʕ9^{g}63f̨{<~!zYg;/<#iooOKKK/N =;:ٙ;::z{,8hhsgNXOշ> @`@6mZy;wZYhQ?}q:ujW,XЛZ9,Y%K9#FTw!d_-ظu  ;Svi z… s!d̙37:ʢErg1cF/^{kh(s?~8Æ [{x8c # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #ٙѣG){ohXzj^=@#tgΜ91cFݣ;[=@O{'rgvm75\}@tuueҤI92f̘ ~ں֋SK´iԴܹssg#SNݨ:ujW,XK5uuuu=,Y$K,YsF:*]w]V?bŊ 4('N%\A?#iooOKKf@̟?-Zq媫aÆm@P!C$Is ?F@Xڈ#HYVIDAT(((((((((((((((((((((((((((((((LSWWWWC7]]]YtiQ0vFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFS؇7IENDB`sympy-sympy-1.9/sympy/plotting/tests/test_region_xor.png000066400000000000000000000234221412543434000240310ustar00rootroot00000000000000PNG  IHDR5sBIT|d pHYsaa?i8tEXtSoftwarematplotlib version3.1.0, http://matplotlib.org/ IDATx{Wu*̤:y]Dtkfy+ko4X/l9Г%ж./ 'o072?V(3f~Ga˵oPu% # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #5qr-u@Gw}笳O3gf̙0`@>я淿mΫ{OfK[xq:뤣c%+ښ477!`^y{3LFN;M$ ʠAzkDZ @ :4#G\ 70lɛ(s @hooOKKsd @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a АLw1Cͦn8  O@C3iҤu]5kV׿f}͟G]SggggCg}6nin|}{{{ZZZ֖^[-IXWC@I'w=#G\kL_<%@qhx&M 7ܐn-[n _= !`}_[n-/I Ad@Cg?\s5馛6=@!4iҤ|u]C橧Jdׯy:z9hHMMM+|~ڴi8q*20@#hH୹ @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a֭{z쳻 ]vyJv]ɕWv}le}Mu'-{-xW_^Ung\.{<|xNM)Ғ477_{-yeO>zůmkKyhmM~뭗G?~ @(܏|Mf1c#{wuw,\XE?k]M7~_,ښ6  k_K~;H}yVeu"7z~&%OT}O$;\< @h STuCWY7j 5?W_K>h k6KZ.>D=̞~dѵi>P2gN&\Ł '$c&{lYKNz*5i1c kMLN= @Vl}w#җ+u,Z<`ux#^{aȐdÑL򶷭/LVv_W^ޖ\~yuxr?@Џj䬳Ꞥ;SÇlՊ_7/O~{= _HN]x^lQu._s{~zUW=i[o䤓|Iq @ͫ䮻;.hv[[&Lhc=YYY'e*X$e><7.y׻zozW{oكVO= Mz~sNSpɡz=Z7:"O6ܰoa5zj'ɱ=\r)SױV$<~)7o\YWZm2ѓO&V] =yAVmU&ncUW=G'SO߈]uULݺ`睓b㫙w[m@EB7x[X[oU@Bx_)ez*ZF_m@y={7cj6BZz?{ `u6 x"9ZCJN<)ډ'V3RΫY('S/WAն %Mݷ)wjۅ @@~^xaf <8cƌɭ5߮߮f!Cnƌ9rg7M>eϼy2Ռֶz АN#<2GuT.~Z[[sE=@֭{3/rcPW^{dѢ} f>pn[#K/ٶWڵg(СCTh{=---u477=F-Zh=imm';؝KlOҚd~Mj'|2#FȬYN;-}s3gΜ7-{|N~-آf=mq{vE(yCk!6%ߧ7ݧ9p^ߺ΀//{=oy~:[E!C=C! 80cƌɬY{~֬Ymj y&dԨeϝtI93v뮹3o޼s1yլudРA933hРG!39detAyy'3rxzWkK.:]h>kad]瞫{:h\[K>ߝvN3Y@@@!<`ruuO֮/PGGGF{uӧm}ouRMrdmdT\+jmr5ݳ /0{${Gnֵ^5T3SdhMko}fY;SLISSSN8ᄺGa @VSOo^†.Pג|+oIW̘1#'pBN>$ɮ?ͫyݜdRJ$&/qԨjes=3 @'?IfΜs=Q _i{W'999TwW2N#<2GqDNkkk.5^WTU?M21{?61/ɛLxW2a„\r%h YO?>:W\qE6`7>݊%ٸWү͝vp̙3'rᄍ;x^j?l;>VYs&M{= kɝ@X3'N1cG{~cРdzr HrAJse mYz꩚ҙ$'FKlj[eL>=sٳn``&O~͞=;\pAs=r4jT/U4.HuH$Gu o~sԴ7=j&IOrK_su1|ϕW^=9WÇ_r7qر0aB.xdU$+HILkx?k֬|?q5 k3U]TE꺉m5^{X|31bDN;4 @j{Շ96ݴzC<vX2kVsnuOBt7wܑ#F@Ə?z>NN: ?iu>VJ8xps~ ˵UOlAПM4)?ϳ;=ܓ=VЇ|;g$O?]$:ӽUSm9w^ݓkͪ_w;/ȑ#3̞=;F{Z8#1ISSӔ}0#jTm f?#< ^c=V8OI%W],^\\-U=%G|uOB#Ypavi=:#FԩSd6{^'W랤};ߙ|pu\wL<[K/M9Ih4rJw}2dHs :4? @|:$ёwuOx˒]vI[o+E]w%'&կ~w=I2o޼5*SLɱ[KB?hQo|I?Sl;A|Ei?\? \}z7;dī&'R3T&~ۓvγ<ꓼ=* tu˓?yVeР37$9_gO\x669QO|yP>ik[_{ojo__M0`^қzsT{.L>e/^heoeu_%ZZwfVӟы/&?YחNo}^ع&[le>:ӟr=@Y=sE]Gydޞ} -oJ_ё{z,8hhrcYL_4!@@0y455k˽gor樣ZO?-?~O9@s[k'o=;.,ӵu Ȝ Æ ˰aVO4jC Il9hhÇ3]g @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a @a:;;;/Cq(CrIENDB`sympy-sympy-1.9/sympy/plotting/tests/test_textplot.py000066400000000000000000000276371412543434000234210ustar00rootroot00000000000000from sympy import Symbol, log, sqrt, sin, S from sympy.plotting.textplot import textplot_str def test_axes_alignment(): x = Symbol('x') lines = [ ' 1 | ..', ' | ... ', ' | .. ', ' | ... ', ' | ... ', ' | .. ', ' | ... ', ' | ... ', ' | .. ', ' | ... ', ' 0 |--------------------------...--------------------------', ' | ... ', ' | .. ', ' | ... ', ' | ... ', ' | .. ', ' | ... ', ' | ... ', ' | .. ', ' | ... ', ' -1 |_______________________________________________________', ' -1 0 1' ] assert lines == list(textplot_str(x, -1, 1)) lines = [ ' 1 | ..', ' | .... ', ' | ... ', ' | ... ', ' | .... ', ' | ... ', ' | ... ', ' | .... ', ' 0 |--------------------------...--------------------------', ' | .... ', ' | ... ', ' | ... ', ' | .... ', ' | ... ', ' | ... ', ' | .... ', ' -1 |_______________________________________________________', ' -1 0 1' ] assert lines == list(textplot_str(x, -1, 1, H=17)) def test_singularity(): x = Symbol('x') lines = [ ' 54 | . ', ' | ', ' | ', ' | ', ' | ',' | ', ' | ', ' | ', ' | ', ' | ', ' 27.5 |--.----------------------------------------------------', ' | ', ' | ', ' | ', ' | . ', ' | \\ ', ' | \\ ', ' | .. ', ' | ... ', ' | ............. ', ' 1 |_______________________________________________________', ' 0 0.5 1' ] assert lines == list(textplot_str(1/x, 0, 1)) lines = [ ' 0 | ......', ' | ........ ', ' | ........ ', ' | ...... ', ' | ..... ', ' | .... ', ' | ... ', ' | .. ', ' | ... ', ' | / ', ' -2 |-------..----------------------------------------------', ' | / ', ' | / ', ' | / ', ' | . ', ' | ', ' | . ', ' | ', ' | ', ' | ', ' -4 |_______________________________________________________', ' 0 0.5 1' ] assert lines == list(textplot_str(log(x), 0, 1)) def test_sinc(): x = Symbol('x') lines = [ ' 1 | . . ', ' | . . ', ' | ', ' | . . ', ' | ', ' | . . ', ' | ', ' | ', ' | . . ', ' | ', ' 0.4 |-------------------------------------------------------', ' | . . ', ' | ', ' | . . ', ' | ', ' | ..... ..... ', ' | .. \\ . . / .. ', ' | / \\ / \\ ', ' |/ \\ . . / \\', ' | \\ / \\ / ', ' -0.2 |_______________________________________________________', ' -10 0 10' ] assert lines == list(textplot_str(sin(x)/x, -10, 10)) def test_imaginary(): x = Symbol('x') lines = [ ' 1 | ..', ' | .. ', ' | ... ', ' | .. ', ' | .. ', ' | .. ', ' | .. ', ' | .. ', ' | .. ', ' | / ', ' 0.5 |----------------------------------/--------------------', ' | .. ', ' | / ', ' | . ', ' | ', ' | . ', ' | . ', ' | ', ' | ', ' | ', ' 0 |_______________________________________________________', ' -1 0 1' ] assert list(textplot_str(sqrt(x), -1, 1)) == lines lines = [ ' 1 | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' 0 |-------------------------------------------------------', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' | ', ' -1 |_______________________________________________________', ' -1 0 1' ] assert list(textplot_str(S.ImaginaryUnit, -1, 1)) == lines sympy-sympy-1.9/sympy/plotting/textplot.py000066400000000000000000000117051412543434000212050ustar00rootroot00000000000000from sympy.core.numbers import Float from sympy.core.symbol import Dummy from sympy.utilities.lambdify import lambdify import math def is_valid(x): """Check if a floating point number is valid""" if x is None: return False if isinstance(x, complex): return False return not math.isinf(x) and not math.isnan(x) def rescale(y, W, H, mi, ma): """Rescale the given array `y` to fit into the integer values between `0` and `H-1` for the values between ``mi`` and ``ma``. """ y_new = list() norm = ma - mi offset = (ma + mi) / 2 for x in range(W): if is_valid(y[x]): normalized = (y[x] - offset) / norm if not is_valid(normalized): y_new.append(None) else: # XXX There are some test failings because of the # difference between the python 2 and 3 rounding. rescaled = Float((normalized*H + H/2) * (H-1)/H).round() rescaled = int(rescaled) y_new.append(rescaled) else: y_new.append(None) return y_new def linspace(start, stop, num): return [start + (stop - start) * x / (num-1) for x in range(num)] def textplot_str(expr, a, b, W=55, H=21): """Generator for the lines of the plot""" free = expr.free_symbols if len(free) > 1: raise ValueError( "The expression must have a single variable. (Got {})" .format(free)) x = free.pop() if free else Dummy() f = lambdify([x], expr) a = float(a) b = float(b) # Calculate function values x = linspace(a, b, W) y = list() for val in x: try: y.append(f(val)) # Not sure what exceptions to catch here or why... except (ValueError, TypeError, ZeroDivisionError): y.append(None) # Normalize height to screen space y_valid = list(filter(is_valid, y)) if y_valid: ma = max(y_valid) mi = min(y_valid) if ma == mi: if ma: mi, ma = sorted([0, 2*ma]) else: mi, ma = -1, 1 else: mi, ma = -1, 1 y_range = ma - mi precision = math.floor(math.log(y_range, 10)) - 1 precision *= -1 mi = round(mi, precision) ma = round(ma, precision) y = rescale(y, W, H, mi, ma) y_bins = linspace(mi, ma, H) # Draw plot margin = 7 for h in range(H - 1, -1, -1): s = [' '] * W for i in range(W): if y[i] == h: if (i == 0 or y[i - 1] == h - 1) and (i == W - 1 or y[i + 1] == h + 1): s[i] = '/' elif (i == 0 or y[i - 1] == h + 1) and (i == W - 1 or y[i + 1] == h - 1): s[i] = '\\' else: s[i] = '.' if h == 0: for i in range(W): s[i] = '_' # Print y values if h in (0, H//2, H - 1): prefix = ("%g" % y_bins[h]).rjust(margin)[:margin] else: prefix = " "*margin s = "".join(s) if h == H//2: s = s.replace(" ", "-") yield prefix + " |" + s # Print x values bottom = " " * (margin + 2) bottom += ("%g" % x[0]).ljust(W//2) if W % 2 == 1: bottom += ("%g" % x[W//2]).ljust(W//2) else: bottom += ("%g" % x[W//2]).ljust(W//2-1) bottom += "%g" % x[-1] yield bottom def textplot(expr, a, b, W=55, H=21): r""" Print a crude ASCII art plot of the SymPy expression 'expr' (which should contain a single symbol, e.g. x or something else) over the interval [a, b]. Examples ======== >>> from sympy import Symbol, sin >>> from sympy.plotting import textplot >>> t = Symbol('t') >>> textplot(sin(t)*t, 0, 15) 14 | ... | . | . | . | . | ... | / . . | / | / . | . . . 1.5 |----.......-------------------------------------------- |.... \ . . | \ / . | .. / . | \ / . | .... | . | . . | | . . -11 |_______________________________________________________ 0 7.5 15 """ for line in textplot_str(expr, a, b, W, H): print(line) sympy-sympy-1.9/sympy/polys/000077500000000000000000000000001412543434000162525ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/__init__.py000066400000000000000000000120661412543434000203700ustar00rootroot00000000000000"""Polynomial manipulation algorithms and algebraic objects. """ __all__ = [ 'Poly', 'PurePoly', 'poly_from_expr', 'parallel_poly_from_expr', 'degree', 'total_degree', 'degree_list', 'LC', 'LM', 'LT', 'pdiv', 'prem', 'pquo', 'pexquo', 'div', 'rem', 'quo', 'exquo', 'half_gcdex', 'gcdex', 'invert', 'subresultants', 'resultant', 'discriminant', 'cofactors', 'gcd_list', 'gcd', 'lcm_list', 'lcm', 'terms_gcd', 'trunc', 'monic', 'content', 'primitive', 'compose', 'decompose', 'sturm', 'gff_list', 'gff', 'sqf_norm', 'sqf_part', 'sqf_list', 'sqf', 'factor_list', 'factor', 'intervals', 'refine_root', 'count_roots', 'real_roots', 'nroots', 'ground_roots', 'nth_power_roots_poly', 'cancel', 'reduced', 'groebner', 'is_zero_dimensional', 'GroebnerBasis', 'poly', 'symmetrize', 'horner', 'interpolate', 'rational_interpolate', 'viete', 'together', 'BasePolynomialError', 'ExactQuotientFailed', 'PolynomialDivisionFailed', 'OperationNotSupported', 'HeuristicGCDFailed', 'HomomorphismFailed', 'IsomorphismFailed', 'ExtraneousFactors', 'EvaluationFailed', 'RefinementFailed', 'CoercionFailed', 'NotInvertible', 'NotReversible', 'NotAlgebraic', 'DomainError', 'PolynomialError', 'UnificationFailed', 'GeneratorsError', 'GeneratorsNeeded', 'ComputationFailed', 'UnivariatePolynomialError', 'MultivariatePolynomialError', 'PolificationFailed', 'OptionError', 'FlagError', 'minpoly', 'minimal_polynomial', 'primitive_element', 'field_isomorphism', 'to_number_field', 'isolate', 'itermonomials', 'Monomial', 'lex', 'grlex', 'grevlex', 'ilex', 'igrlex', 'igrevlex', 'CRootOf', 'rootof', 'RootOf', 'ComplexRootOf', 'RootSum', 'roots', 'Domain', 'FiniteField', 'IntegerRing', 'RationalField', 'RealField', 'ComplexField', 'PythonFiniteField', 'GMPYFiniteField', 'PythonIntegerRing', 'GMPYIntegerRing', 'PythonRational', 'GMPYRationalField', 'AlgebraicField', 'PolynomialRing', 'FractionField', 'ExpressionDomain', 'FF_python', 'FF_gmpy', 'ZZ_python', 'ZZ_gmpy', 'QQ_python', 'QQ_gmpy', 'GF', 'FF', 'ZZ', 'QQ', 'ZZ_I', 'QQ_I', 'RR', 'CC', 'EX', 'EXRAW', 'construct_domain', 'swinnerton_dyer_poly', 'cyclotomic_poly', 'symmetric_poly', 'random_poly', 'interpolating_poly', 'jacobi_poly', 'chebyshevt_poly', 'chebyshevu_poly', 'hermite_poly', 'legendre_poly', 'laguerre_poly', 'apart', 'apart_list', 'assemble_partfrac_list', 'Options', 'ring', 'xring', 'vring', 'sring', 'field', 'xfield', 'vfield', 'sfield' ] from .polytools import (Poly, PurePoly, poly_from_expr, parallel_poly_from_expr, degree, total_degree, degree_list, LC, LM, LT, pdiv, prem, pquo, pexquo, div, rem, quo, exquo, half_gcdex, gcdex, invert, subresultants, resultant, discriminant, cofactors, gcd_list, gcd, lcm_list, lcm, terms_gcd, trunc, monic, content, primitive, compose, decompose, sturm, gff_list, gff, sqf_norm, sqf_part, sqf_list, sqf, factor_list, factor, intervals, refine_root, count_roots, real_roots, nroots, ground_roots, nth_power_roots_poly, cancel, reduced, groebner, is_zero_dimensional, GroebnerBasis, poly) from .polyfuncs import (symmetrize, horner, interpolate, rational_interpolate, viete) from .rationaltools import together from .polyerrors import (BasePolynomialError, ExactQuotientFailed, PolynomialDivisionFailed, OperationNotSupported, HeuristicGCDFailed, HomomorphismFailed, IsomorphismFailed, ExtraneousFactors, EvaluationFailed, RefinementFailed, CoercionFailed, NotInvertible, NotReversible, NotAlgebraic, DomainError, PolynomialError, UnificationFailed, GeneratorsError, GeneratorsNeeded, ComputationFailed, UnivariatePolynomialError, MultivariatePolynomialError, PolificationFailed, OptionError, FlagError) from .numberfields import (minpoly, minimal_polynomial, primitive_element, field_isomorphism, to_number_field, isolate) from .monomials import itermonomials, Monomial from .orderings import lex, grlex, grevlex, ilex, igrlex, igrevlex from .rootoftools import CRootOf, rootof, RootOf, ComplexRootOf, RootSum from .polyroots import roots from .domains import (Domain, FiniteField, IntegerRing, RationalField, RealField, ComplexField, PythonFiniteField, GMPYFiniteField, PythonIntegerRing, GMPYIntegerRing, PythonRational, GMPYRationalField, AlgebraicField, PolynomialRing, FractionField, ExpressionDomain, FF_python, FF_gmpy, ZZ_python, ZZ_gmpy, QQ_python, QQ_gmpy, GF, FF, ZZ, QQ, ZZ_I, QQ_I, RR, CC, EX, EXRAW) from .constructor import construct_domain from .specialpolys import (swinnerton_dyer_poly, cyclotomic_poly, symmetric_poly, random_poly, interpolating_poly) from .orthopolys import (jacobi_poly, chebyshevt_poly, chebyshevu_poly, hermite_poly, legendre_poly, laguerre_poly) from .partfrac import apart, apart_list, assemble_partfrac_list from .polyoptions import Options from .rings import ring, xring, vring, sring from .fields import field, xfield, vfield, sfield sympy-sympy-1.9/sympy/polys/agca/000077500000000000000000000000001412543434000171455ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/agca/__init__.py000066400000000000000000000002021412543434000212500ustar00rootroot00000000000000"""Module for algebraic geometry and commutative algebra.""" from .homomorphisms import homomorphism __all__ = ['homomorphism'] sympy-sympy-1.9/sympy/polys/agca/extensions.py000066400000000000000000000217201412543434000217200ustar00rootroot00000000000000"""Finite extensions of ring domains.""" from sympy.polys.domains.domain import Domain from sympy.polys.domains.domainelement import DomainElement from sympy.polys.polyerrors import (CoercionFailed, NotInvertible, GeneratorsError) from sympy.polys.polytools import Poly from sympy.printing.defaults import DefaultPrinting class ExtensionElement(DomainElement, DefaultPrinting): """ Element of a finite extension. A class of univariate polynomials modulo the ``modulus`` of the extension ``ext``. It is represented by the unique polynomial ``rep`` of lowest degree. Both ``rep`` and the representation ``mod`` of ``modulus`` are of class DMP. """ __slots__ = ('rep', 'ext') def __init__(self, rep, ext): self.rep = rep self.ext = ext def parent(f): return f.ext def __bool__(f): return bool(f.rep) def __pos__(f): return f def __neg__(f): return ExtElem(-f.rep, f.ext) def _get_rep(f, g): if isinstance(g, ExtElem): if g.ext == f.ext: return g.rep else: return None else: try: g = f.ext.convert(g) return g.rep except CoercionFailed: return None def __add__(f, g): rep = f._get_rep(g) if rep is not None: return ExtElem(f.rep + rep, f.ext) else: return NotImplemented __radd__ = __add__ def __sub__(f, g): rep = f._get_rep(g) if rep is not None: return ExtElem(f.rep - rep, f.ext) else: return NotImplemented def __rsub__(f, g): rep = f._get_rep(g) if rep is not None: return ExtElem(rep - f.rep, f.ext) else: return NotImplemented def __mul__(f, g): rep = f._get_rep(g) if rep is not None: return ExtElem((f.rep * rep) % f.ext.mod, f.ext) else: return NotImplemented __rmul__ = __mul__ def _divcheck(f): """Raise if division is not implemented for this divisor""" if not f: raise NotInvertible('Zero divisor') elif f.ext.is_Field: return True elif f.rep.is_ground and f.ext.domain.is_unit(f.rep.rep[0]): return True else: # Some cases like (2*x + 2)/2 over ZZ will fail here. It is # unclear how to implement division in general if the ground # domain is not a field so for now it was decided to restrict the # implementation to division by invertible constants. msg = (f"Can not invert {f} in {f.ext}. " "Only division by invertible constants is implemented.") raise NotImplementedError(msg) def inverse(f): """Multiplicative inverse. Raises ====== NotInvertible If the element is a zero divisor. """ f._divcheck() if f.ext.is_Field: invrep = f.rep.invert(f.ext.mod) else: R = f.ext.ring invrep = R.exquo(R.one, f.rep) return ExtElem(invrep, f.ext) def __truediv__(f, g): rep = f._get_rep(g) if rep is None: return NotImplemented g = ExtElem(rep, f.ext) try: ginv = g.inverse() except NotInvertible: raise ZeroDivisionError(f"{f} / {g}") return f * ginv __floordiv__ = __truediv__ def __rtruediv__(f, g): try: g = f.ext.convert(g) except CoercionFailed: return NotImplemented return g / f __rfloordiv__ = __rtruediv__ def __mod__(f, g): rep = f._get_rep(g) if rep is None: return NotImplemented g = ExtElem(rep, f.ext) try: g._divcheck() except NotInvertible: raise ZeroDivisionError(f"{f} % {g}") # Division where defined is always exact so there is no remainder return f.ext.zero def __rmod__(f, g): try: g = f.ext.convert(g) except CoercionFailed: return NotImplemented return g % f def __pow__(f, n): if not isinstance(n, int): raise TypeError("exponent of type 'int' expected") if n < 0: try: f, n = f.inverse(), -n except NotImplementedError: raise ValueError("negative powers are not defined") b = f.rep m = f.ext.mod r = f.ext.one.rep while n > 0: if n % 2: r = (r*b) % m b = (b*b) % m n //= 2 return ExtElem(r, f.ext) def __eq__(f, g): if isinstance(g, ExtElem): return f.rep == g.rep and f.ext == g.ext else: return NotImplemented def __ne__(f, g): return not f == g def __hash__(f): return hash((f.rep, f.ext)) def __str__(f): from sympy.printing.str import sstr return sstr(f.rep) __repr__ = __str__ @property def is_ground(f): return f.rep.is_ground def to_ground(f): [c] = f.rep.to_list() return c ExtElem = ExtensionElement class MonogenicFiniteExtension(Domain): r""" Finite extension generated by an integral element. The generator is defined by a monic univariate polynomial derived from the argument ``mod``. A shorter alias is ``FiniteExtension``. Examples ======== Quadratic integer ring $\mathbb{Z}[\sqrt2]$: >>> from sympy import Symbol, Poly >>> from sympy.polys.agca.extensions import FiniteExtension >>> x = Symbol('x') >>> R = FiniteExtension(Poly(x**2 - 2)); R ZZ[x]/(x**2 - 2) >>> R.rank 2 >>> R(1 + x)*(3 - 2*x) x - 1 Finite field $GF(5^3)$ defined by the primitive polynomial $x^3 + x^2 + 2$ (over $\mathbb{Z}_5$). >>> F = FiniteExtension(Poly(x**3 + x**2 + 2, modulus=5)); F GF(5)[x]/(x**3 + x**2 + 2) >>> F.basis (1, x, x**2) >>> F(x + 3)/(x**2 + 2) -2*x**2 + x + 2 Function field of an elliptic curve: >>> t = Symbol('t') >>> FiniteExtension(Poly(t**2 - x**3 - x + 1, t, field=True)) ZZ(x)[t]/(t**2 - x**3 - x + 1) """ is_FiniteExtension = True dtype = ExtensionElement def __init__(self, mod): if not (isinstance(mod, Poly) and mod.is_univariate): raise TypeError("modulus must be a univariate Poly") # Using auto=True (default) potentially changes the ground domain to a # field whereas auto=False raises if division is not exact. We'll let # the caller decide whether or not they want to put the ground domain # over a field. In most uses mod is already monic. mod = mod.monic(auto=False) self.rank = mod.degree() self.modulus = mod self.mod = mod.rep # DMP representation self.domain = dom = mod.domain self.ring = mod.rep.ring or dom.old_poly_ring(*mod.gens) self.zero = self.convert(self.ring.zero) self.one = self.convert(self.ring.one) gen = self.ring.gens[0] self.symbol = self.ring.symbols[0] self.generator = self.convert(gen) self.basis = tuple(self.convert(gen**i) for i in range(self.rank)) # XXX: It might be necessary to check mod.is_irreducible here self.is_Field = self.domain.is_Field def new(self, arg): rep = self.ring.convert(arg) return ExtElem(rep % self.mod, self) def __eq__(self, other): if not isinstance(other, FiniteExtension): return False return self.modulus == other.modulus def __hash__(self): return hash((self.__class__.__name__, self.modulus)) def __str__(self): return "%s/(%s)" % (self.ring, self.modulus.as_expr()) __repr__ = __str__ def convert(self, f, base=None): rep = self.ring.convert(f, base) return ExtElem(rep % self.mod, self) def convert_from(self, f, base): rep = self.ring.convert(f, base) return ExtElem(rep % self.mod, self) def to_sympy(self, f): return self.ring.to_sympy(f.rep) def from_sympy(self, f): return self.convert(f) def set_domain(self, K): mod = self.modulus.set_domain(K) return self.__class__(mod) def drop(self, *symbols): if self.symbol in symbols: raise GeneratorsError('Can not drop generator from FiniteExtension') K = self.domain.drop(*symbols) return self.set_domain(K) def quo(self, f, g): return self.exquo(f, g) def exquo(self, f, g): rep = self.ring.exquo(f.rep, g.rep) return ExtElem(rep % self.mod, self) def is_negative(self, a): return False def is_unit(self, a): if self.is_Field: return bool(a) elif a.is_ground: return self.domain.is_unit(a.to_ground()) FiniteExtension = MonogenicFiniteExtension sympy-sympy-1.9/sympy/polys/agca/homomorphisms.py000066400000000000000000000526611412543434000224350ustar00rootroot00000000000000""" Computations with homomorphisms of modules and rings. This module implements classes for representing homomorphisms of rings and their modules. Instead of instantiating the classes directly, you should use the function ``homomorphism(from, to, matrix)`` to create homomorphism objects. """ from sympy.polys.agca.modules import (Module, FreeModule, QuotientModule, SubModule, SubQuotientModule) from sympy.polys.polyerrors import CoercionFailed # The main computational task for module homomorphisms is kernels. # For this reason, the concrete classes are organised by domain module type. class ModuleHomomorphism: """ Abstract base class for module homomoprhisms. Do not instantiate. Instead, use the ``homomorphism`` function: >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> homomorphism(F, F, [[1, 0], [0, 1]]) Matrix([ [1, 0], : QQ[x]**2 -> QQ[x]**2 [0, 1]]) Attributes: - ring - the ring over which we are considering modules - domain - the domain module - codomain - the codomain module - _ker - cached kernel - _img - cached image Non-implemented methods: - _kernel - _image - _restrict_domain - _restrict_codomain - _quotient_domain - _quotient_codomain - _apply - _mul_scalar - _compose - _add """ def __init__(self, domain, codomain): if not isinstance(domain, Module): raise TypeError('Source must be a module, got %s' % domain) if not isinstance(codomain, Module): raise TypeError('Target must be a module, got %s' % codomain) if domain.ring != codomain.ring: raise ValueError('Source and codomain must be over same ring, ' 'got %s != %s' % (domain, codomain)) self.domain = domain self.codomain = codomain self.ring = domain.ring self._ker = None self._img = None def kernel(self): r""" Compute the kernel of ``self``. That is, if ``self`` is the homomorphism `\phi: M \to N`, then compute `ker(\phi) = \{x \in M | \phi(x) = 0\}`. This is a submodule of `M`. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> homomorphism(F, F, [[1, 0], [x, 0]]).kernel() <[x, -1]> """ if self._ker is None: self._ker = self._kernel() return self._ker def image(self): r""" Compute the image of ``self``. That is, if ``self`` is the homomorphism `\phi: M \to N`, then compute `im(\phi) = \{\phi(x) | x \in M \}`. This is a submodule of `N`. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> homomorphism(F, F, [[1, 0], [x, 0]]).image() == F.submodule([1, 0]) True """ if self._img is None: self._img = self._image() return self._img def _kernel(self): """Compute the kernel of ``self``.""" raise NotImplementedError def _image(self): """Compute the image of ``self``.""" raise NotImplementedError def _restrict_domain(self, sm): """Implementation of domain restriction.""" raise NotImplementedError def _restrict_codomain(self, sm): """Implementation of codomain restriction.""" raise NotImplementedError def _quotient_domain(self, sm): """Implementation of domain quotient.""" raise NotImplementedError def _quotient_codomain(self, sm): """Implementation of codomain quotient.""" raise NotImplementedError def restrict_domain(self, sm): """ Return ``self``, with the domain restricted to ``sm``. Here ``sm`` has to be a submodule of ``self.domain``. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h Matrix([ [1, x], : QQ[x]**2 -> QQ[x]**2 [0, 0]]) >>> h.restrict_domain(F.submodule([1, 0])) Matrix([ [1, x], : <[1, 0]> -> QQ[x]**2 [0, 0]]) This is the same as just composing on the right with the submodule inclusion: >>> h * F.submodule([1, 0]).inclusion_hom() Matrix([ [1, x], : <[1, 0]> -> QQ[x]**2 [0, 0]]) """ if not self.domain.is_submodule(sm): raise ValueError('sm must be a submodule of %s, got %s' % (self.domain, sm)) if sm == self.domain: return self return self._restrict_domain(sm) def restrict_codomain(self, sm): """ Return ``self``, with codomain restricted to to ``sm``. Here ``sm`` has to be a submodule of ``self.codomain`` containing the image. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h Matrix([ [1, x], : QQ[x]**2 -> QQ[x]**2 [0, 0]]) >>> h.restrict_codomain(F.submodule([1, 0])) Matrix([ [1, x], : QQ[x]**2 -> <[1, 0]> [0, 0]]) """ if not sm.is_submodule(self.image()): raise ValueError('the image %s must contain sm, got %s' % (self.image(), sm)) if sm == self.codomain: return self return self._restrict_codomain(sm) def quotient_domain(self, sm): """ Return ``self`` with domain replaced by ``domain/sm``. Here ``sm`` must be a submodule of ``self.kernel()``. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h Matrix([ [1, x], : QQ[x]**2 -> QQ[x]**2 [0, 0]]) >>> h.quotient_domain(F.submodule([-x, 1])) Matrix([ [1, x], : QQ[x]**2/<[-x, 1]> -> QQ[x]**2 [0, 0]]) """ if not self.kernel().is_submodule(sm): raise ValueError('kernel %s must contain sm, got %s' % (self.kernel(), sm)) if sm.is_zero(): return self return self._quotient_domain(sm) def quotient_codomain(self, sm): """ Return ``self`` with codomain replaced by ``codomain/sm``. Here ``sm`` must be a submodule of ``self.codomain``. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h Matrix([ [1, x], : QQ[x]**2 -> QQ[x]**2 [0, 0]]) >>> h.quotient_codomain(F.submodule([1, 1])) Matrix([ [1, x], : QQ[x]**2 -> QQ[x]**2/<[1, 1]> [0, 0]]) This is the same as composing with the quotient map on the left: >>> (F/[(1, 1)]).quotient_hom() * h Matrix([ [1, x], : QQ[x]**2 -> QQ[x]**2/<[1, 1]> [0, 0]]) """ if not self.codomain.is_submodule(sm): raise ValueError('sm must be a submodule of codomain %s, got %s' % (self.codomain, sm)) if sm.is_zero(): return self return self._quotient_codomain(sm) def _apply(self, elem): """Apply ``self`` to ``elem``.""" raise NotImplementedError def __call__(self, elem): return self.codomain.convert(self._apply(self.domain.convert(elem))) def _compose(self, oth): """ Compose ``self`` with ``oth``, that is, return the homomorphism obtained by first applying then ``self``, then ``oth``. (This method is private since in this syntax, it is non-obvious which homomorphism is executed first.) """ raise NotImplementedError def _mul_scalar(self, c): """Scalar multiplication. ``c`` is guaranteed in self.ring.""" raise NotImplementedError def _add(self, oth): """ Homomorphism addition. ``oth`` is guaranteed to be a homomorphism with same domain/codomain. """ raise NotImplementedError def _check_hom(self, oth): """Helper to check that oth is a homomorphism with same domain/codomain.""" if not isinstance(oth, ModuleHomomorphism): return False return oth.domain == self.domain and oth.codomain == self.codomain def __mul__(self, oth): if isinstance(oth, ModuleHomomorphism) and self.domain == oth.codomain: return oth._compose(self) try: return self._mul_scalar(self.ring.convert(oth)) except CoercionFailed: return NotImplemented # NOTE: _compose will never be called from rmul __rmul__ = __mul__ def __truediv__(self, oth): try: return self._mul_scalar(1/self.ring.convert(oth)) except CoercionFailed: return NotImplemented def __add__(self, oth): if self._check_hom(oth): return self._add(oth) return NotImplemented def __sub__(self, oth): if self._check_hom(oth): return self._add(oth._mul_scalar(self.ring.convert(-1))) return NotImplemented def is_injective(self): """ Return True if ``self`` is injective. That is, check if the elements of the domain are mapped to the same codomain element. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h.is_injective() False >>> h.quotient_domain(h.kernel()).is_injective() True """ return self.kernel().is_zero() def is_surjective(self): """ Return True if ``self`` is surjective. That is, check if every element of the codomain has at least one preimage. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h.is_surjective() False >>> h.restrict_codomain(h.image()).is_surjective() True """ return self.image() == self.codomain def is_isomorphism(self): """ Return True if ``self`` is an isomorphism. That is, check if every element of the codomain has precisely one preimage. Equivalently, ``self`` is both injective and surjective. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h = h.restrict_codomain(h.image()) >>> h.is_isomorphism() False >>> h.quotient_domain(h.kernel()).is_isomorphism() True """ return self.is_injective() and self.is_surjective() def is_zero(self): """ Return True if ``self`` is a zero morphism. That is, check if every element of the domain is mapped to zero under self. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> h = homomorphism(F, F, [[1, 0], [x, 0]]) >>> h.is_zero() False >>> h.restrict_domain(F.submodule()).is_zero() True >>> h.quotient_codomain(h.image()).is_zero() True """ return self.image().is_zero() def __eq__(self, oth): try: return (self - oth).is_zero() except TypeError: return False def __ne__(self, oth): return not (self == oth) class MatrixHomomorphism(ModuleHomomorphism): r""" Helper class for all homomoprhisms which are expressed via a matrix. That is, for such homomorphisms ``domain`` is contained in a module generated by finitely many elements `e_1, \ldots, e_n`, so that the homomorphism is determined uniquely by its action on the `e_i`. It can thus be represented as a vector of elements of the codomain module, or potentially a supermodule of the codomain module (and hence conventionally as a matrix, if there is a similar interpretation for elements of the codomain module). Note that this class does *not* assume that the `e_i` freely generate a submodule, nor that ``domain`` is even all of this submodule. It exists only to unify the interface. Do not instantiate. Attributes: - matrix - the list of images determining the homomorphism. NOTE: the elements of matrix belong to either self.codomain or self.codomain.container Still non-implemented methods: - kernel - _apply """ def __init__(self, domain, codomain, matrix): ModuleHomomorphism.__init__(self, domain, codomain) if len(matrix) != domain.rank: raise ValueError('Need to provide %s elements, got %s' % (domain.rank, len(matrix))) converter = self.codomain.convert if isinstance(self.codomain, (SubModule, SubQuotientModule)): converter = self.codomain.container.convert self.matrix = tuple(converter(x) for x in matrix) def _sympy_matrix(self): """Helper function which returns a sympy matrix ``self.matrix``.""" from sympy.matrices import Matrix c = lambda x: x if isinstance(self.codomain, (QuotientModule, SubQuotientModule)): c = lambda x: x.data return Matrix([[self.ring.to_sympy(y) for y in c(x)] for x in self.matrix]).T def __repr__(self): lines = repr(self._sympy_matrix()).split('\n') t = " : %s -> %s" % (self.domain, self.codomain) s = ' '*len(t) n = len(lines) for i in range(n // 2): lines[i] += s lines[n // 2] += t for i in range(n//2 + 1, n): lines[i] += s return '\n'.join(lines) def _restrict_domain(self, sm): """Implementation of domain restriction.""" return SubModuleHomomorphism(sm, self.codomain, self.matrix) def _restrict_codomain(self, sm): """Implementation of codomain restriction.""" return self.__class__(self.domain, sm, self.matrix) def _quotient_domain(self, sm): """Implementation of domain quotient.""" return self.__class__(self.domain/sm, self.codomain, self.matrix) def _quotient_codomain(self, sm): """Implementation of codomain quotient.""" Q = self.codomain/sm converter = Q.convert if isinstance(self.codomain, SubModule): converter = Q.container.convert return self.__class__(self.domain, self.codomain/sm, [converter(x) for x in self.matrix]) def _add(self, oth): return self.__class__(self.domain, self.codomain, [x + y for x, y in zip(self.matrix, oth.matrix)]) def _mul_scalar(self, c): return self.__class__(self.domain, self.codomain, [c*x for x in self.matrix]) def _compose(self, oth): return self.__class__(self.domain, oth.codomain, [oth(x) for x in self.matrix]) class FreeModuleHomomorphism(MatrixHomomorphism): """ Concrete class for homomorphisms with domain a free module or a quotient thereof. Do not instantiate; the constructor does not check that your data is well defined. Use the ``homomorphism`` function instead: >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> F = QQ.old_poly_ring(x).free_module(2) >>> homomorphism(F, F, [[1, 0], [0, 1]]) Matrix([ [1, 0], : QQ[x]**2 -> QQ[x]**2 [0, 1]]) """ def _apply(self, elem): if isinstance(self.domain, QuotientModule): elem = elem.data return sum(x * e for x, e in zip(elem, self.matrix)) def _image(self): return self.codomain.submodule(*self.matrix) def _kernel(self): # The domain is either a free module or a quotient thereof. # It does not matter if it is a quotient, because that won't increase # the kernel. # Our generators {e_i} are sent to the matrix entries {b_i}. # The kernel is essentially the syzygy module of these {b_i}. syz = self.image().syzygy_module() return self.domain.submodule(*syz.gens) class SubModuleHomomorphism(MatrixHomomorphism): """ Concrete class for homomorphism with domain a submodule of a free module or a quotient thereof. Do not instantiate; the constructor does not check that your data is well defined. Use the ``homomorphism`` function instead: >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> M = QQ.old_poly_ring(x).free_module(2)*x >>> homomorphism(M, M, [[1, 0], [0, 1]]) Matrix([ [1, 0], : <[x, 0], [0, x]> -> <[x, 0], [0, x]> [0, 1]]) """ def _apply(self, elem): if isinstance(self.domain, SubQuotientModule): elem = elem.data return sum(x * e for x, e in zip(elem, self.matrix)) def _image(self): return self.codomain.submodule(*[self(x) for x in self.domain.gens]) def _kernel(self): syz = self.image().syzygy_module() return self.domain.submodule( *[sum(xi*gi for xi, gi in zip(s, self.domain.gens)) for s in syz.gens]) def homomorphism(domain, codomain, matrix): r""" Create a homomorphism object. This function tries to build a homomorphism from ``domain`` to ``codomain`` via the matrix ``matrix``. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x >>> from sympy.polys.agca import homomorphism >>> R = QQ.old_poly_ring(x) >>> T = R.free_module(2) If ``domain`` is a free module generated by `e_1, \ldots, e_n`, then ``matrix`` should be an n-element iterable `(b_1, \ldots, b_n)` where the `b_i` are elements of ``codomain``. The constructed homomorphism is the unique homomorphism sending `e_i` to `b_i`. >>> F = R.free_module(2) >>> h = homomorphism(F, T, [[1, x], [x**2, 0]]) >>> h Matrix([ [1, x**2], : QQ[x]**2 -> QQ[x]**2 [x, 0]]) >>> h([1, 0]) [1, x] >>> h([0, 1]) [x**2, 0] >>> h([1, 1]) [x**2 + 1, x] If ``domain`` is a submodule of a free module, them ``matrix`` determines a homomoprhism from the containing free module to ``codomain``, and the homomorphism returned is obtained by restriction to ``domain``. >>> S = F.submodule([1, 0], [0, x]) >>> homomorphism(S, T, [[1, x], [x**2, 0]]) Matrix([ [1, x**2], : <[1, 0], [0, x]> -> QQ[x]**2 [x, 0]]) If ``domain`` is a (sub)quotient `N/K`, then ``matrix`` determines a homomorphism from `N` to ``codomain``. If the kernel contains `K`, this homomorphism descends to ``domain`` and is returned; otherwise an exception is raised. >>> homomorphism(S/[(1, 0)], T, [0, [x**2, 0]]) Matrix([ [0, x**2], : <[1, 0] + <[1, 0]>, [0, x] + <[1, 0]>, [1, 0] + <[1, 0]>> -> QQ[x]**2 [0, 0]]) >>> homomorphism(S/[(0, x)], T, [0, [x**2, 0]]) Traceback (most recent call last): ... ValueError: kernel <[1, 0], [0, 0]> must contain sm, got <[0,x]> """ def freepres(module): """ Return a tuple ``(F, S, Q, c)`` where ``F`` is a free module, ``S`` is a submodule of ``F``, and ``Q`` a submodule of ``S``, such that ``module = S/Q``, and ``c`` is a conversion function. """ if isinstance(module, FreeModule): return module, module, module.submodule(), lambda x: module.convert(x) if isinstance(module, QuotientModule): return (module.base, module.base, module.killed_module, lambda x: module.convert(x).data) if isinstance(module, SubQuotientModule): return (module.base.container, module.base, module.killed_module, lambda x: module.container.convert(x).data) # an ordinary submodule return (module.container, module, module.submodule(), lambda x: module.container.convert(x)) SF, SS, SQ, _ = freepres(domain) TF, TS, TQ, c = freepres(codomain) # NOTE this is probably a bit inefficient (redundant checks) return FreeModuleHomomorphism(SF, TF, [c(x) for x in matrix] ).restrict_domain(SS).restrict_codomain(TS ).quotient_codomain(TQ).quotient_domain(SQ) sympy-sympy-1.9/sympy/polys/agca/ideals.py000066400000000000000000000250441412543434000207650ustar00rootroot00000000000000"""Computations with ideals of polynomial rings.""" from functools import reduce from sympy.polys.polyerrors import CoercionFailed class Ideal: """ Abstract base class for ideals. Do not instantiate - use explicit constructors in the ring class instead: >>> from sympy import QQ >>> from sympy.abc import x >>> QQ.old_poly_ring(x).ideal(x+1) Attributes - ring - the ring this ideal belongs to Non-implemented methods: - _contains_elem - _contains_ideal - _quotient - _intersect - _union - _product - is_whole_ring - is_zero - is_prime, is_maximal, is_primary, is_radical - is_principal - height, depth - radical Methods that likely should be overridden in subclasses: - reduce_element """ def _contains_elem(self, x): """Implementation of element containment.""" raise NotImplementedError def _contains_ideal(self, I): """Implementation of ideal containment.""" raise NotImplementedError def _quotient(self, J): """Implementation of ideal quotient.""" raise NotImplementedError def _intersect(self, J): """Implementation of ideal intersection.""" raise NotImplementedError def is_whole_ring(self): """Return True if ``self`` is the whole ring.""" raise NotImplementedError def is_zero(self): """Return True if ``self`` is the zero ideal.""" raise NotImplementedError def _equals(self, J): """Implementation of ideal equality.""" return self._contains_ideal(J) and J._contains_ideal(self) def is_prime(self): """Return True if ``self`` is a prime ideal.""" raise NotImplementedError def is_maximal(self): """Return True if ``self`` is a maximal ideal.""" raise NotImplementedError def is_radical(self): """Return True if ``self`` is a radical ideal.""" raise NotImplementedError def is_primary(self): """Return True if ``self`` is a primary ideal.""" raise NotImplementedError def is_principal(self): """Return True if ``self`` is a principal ideal.""" raise NotImplementedError def radical(self): """Compute the radical of ``self``.""" raise NotImplementedError def depth(self): """Compute the depth of ``self``.""" raise NotImplementedError def height(self): """Compute the height of ``self``.""" raise NotImplementedError # TODO more # non-implemented methods end here def __init__(self, ring): self.ring = ring def _check_ideal(self, J): """Helper to check ``J`` is an ideal of our ring.""" if not isinstance(J, Ideal) or J.ring != self.ring: raise ValueError( 'J must be an ideal of %s, got %s' % (self.ring, J)) def contains(self, elem): """ Return True if ``elem`` is an element of this ideal. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).ideal(x+1, x-1).contains(3) True >>> QQ.old_poly_ring(x).ideal(x**2, x**3).contains(x) False """ return self._contains_elem(self.ring.convert(elem)) def subset(self, other): """ Returns True if ``other`` is is a subset of ``self``. Here ``other`` may be an ideal. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> I = QQ.old_poly_ring(x).ideal(x+1) >>> I.subset([x**2 - 1, x**2 + 2*x + 1]) True >>> I.subset([x**2 + 1, x + 1]) False >>> I.subset(QQ.old_poly_ring(x).ideal(x**2 - 1)) True """ if isinstance(other, Ideal): return self._contains_ideal(other) return all(self._contains_elem(x) for x in other) def quotient(self, J, **opts): r""" Compute the ideal quotient of ``self`` by ``J``. That is, if ``self`` is the ideal `I`, compute the set `I : J = \{x \in R | xJ \subset I \}`. Examples ======== >>> from sympy.abc import x, y >>> from sympy import QQ >>> R = QQ.old_poly_ring(x, y) >>> R.ideal(x*y).quotient(R.ideal(x)) """ self._check_ideal(J) return self._quotient(J, **opts) def intersect(self, J): """ Compute the intersection of self with ideal J. Examples ======== >>> from sympy.abc import x, y >>> from sympy import QQ >>> R = QQ.old_poly_ring(x, y) >>> R.ideal(x).intersect(R.ideal(y)) """ self._check_ideal(J) return self._intersect(J) def saturate(self, J): r""" Compute the ideal saturation of ``self`` by ``J``. That is, if ``self`` is the ideal `I`, compute the set `I : J^\infty = \{x \in R | xJ^n \subset I \text{ for some } n\}`. """ raise NotImplementedError # Note this can be implemented using repeated quotient def union(self, J): """ Compute the ideal generated by the union of ``self`` and ``J``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).ideal(x**2 - 1).union(QQ.old_poly_ring(x).ideal((x+1)**2)) == QQ.old_poly_ring(x).ideal(x+1) True """ self._check_ideal(J) return self._union(J) def product(self, J): r""" Compute the ideal product of ``self`` and ``J``. That is, compute the ideal generated by products `xy`, for `x` an element of ``self`` and `y \in J`. Examples ======== >>> from sympy.abc import x, y >>> from sympy import QQ >>> QQ.old_poly_ring(x, y).ideal(x).product(QQ.old_poly_ring(x, y).ideal(y)) """ self._check_ideal(J) return self._product(J) def reduce_element(self, x): """ Reduce the element ``x`` of our ring modulo the ideal ``self``. Here "reduce" has no specific meaning: it could return a unique normal form, simplify the expression a bit, or just do nothing. """ return x def __add__(self, e): if not isinstance(e, Ideal): R = self.ring.quotient_ring(self) if isinstance(e, R.dtype): return e if isinstance(e, R.ring.dtype): return R(e) return R.convert(e) self._check_ideal(e) return self.union(e) __radd__ = __add__ def __mul__(self, e): if not isinstance(e, Ideal): try: e = self.ring.ideal(e) except CoercionFailed: return NotImplemented self._check_ideal(e) return self.product(e) __rmul__ = __mul__ def __pow__(self, exp): if exp < 0: raise NotImplementedError # TODO exponentiate by squaring return reduce(lambda x, y: x*y, [self]*exp, self.ring.ideal(1)) def __eq__(self, e): if not isinstance(e, Ideal) or e.ring != self.ring: return False return self._equals(e) def __ne__(self, e): return not (self == e) class ModuleImplementedIdeal(Ideal): """ Ideal implementation relying on the modules code. Attributes: - _module - the underlying module """ def __init__(self, ring, module): Ideal.__init__(self, ring) self._module = module def _contains_elem(self, x): return self._module.contains([x]) def _contains_ideal(self, J): if not isinstance(J, ModuleImplementedIdeal): raise NotImplementedError return self._module.is_submodule(J._module) def _intersect(self, J): if not isinstance(J, ModuleImplementedIdeal): raise NotImplementedError return self.__class__(self.ring, self._module.intersect(J._module)) def _quotient(self, J, **opts): if not isinstance(J, ModuleImplementedIdeal): raise NotImplementedError return self._module.module_quotient(J._module, **opts) def _union(self, J): if not isinstance(J, ModuleImplementedIdeal): raise NotImplementedError return self.__class__(self.ring, self._module.union(J._module)) @property def gens(self): """ Return generators for ``self``. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x, y >>> list(QQ.old_poly_ring(x, y).ideal(x, y, x**2 + y).gens) [x, y, x**2 + y] """ return (x[0] for x in self._module.gens) def is_zero(self): """ Return True if ``self`` is the zero ideal. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).ideal(x).is_zero() False >>> QQ.old_poly_ring(x).ideal().is_zero() True """ return self._module.is_zero() def is_whole_ring(self): """ Return True if ``self`` is the whole ring, i.e. one generator is a unit. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ, ilex >>> QQ.old_poly_ring(x).ideal(x).is_whole_ring() False >>> QQ.old_poly_ring(x).ideal(3).is_whole_ring() True >>> QQ.old_poly_ring(x, order=ilex).ideal(2 + x).is_whole_ring() True """ return self._module.is_full_module() def __repr__(self): from sympy import sstr return '<' + ','.join(sstr(x) for [x] in self._module.gens) + '>' # NOTE this is the only method using the fact that the module is a SubModule def _product(self, J): if not isinstance(J, ModuleImplementedIdeal): raise NotImplementedError return self.__class__(self.ring, self._module.submodule( *[[x*y] for [x] in self._module.gens for [y] in J._module.gens])) def in_terms_of_generators(self, e): """ Express ``e`` in terms of the generators of ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> I = QQ.old_poly_ring(x).ideal(x**2 + 1, x) >>> I.in_terms_of_generators(1) [1, -x] """ return self._module.in_terms_of_generators([e]) def reduce_element(self, x, **options): return self._module.reduce_element([x], **options)[0] sympy-sympy-1.9/sympy/polys/agca/modules.py000066400000000000000000001334411412543434000211750ustar00rootroot00000000000000""" Computations with modules over polynomial rings. This module implements various classes that encapsulate groebner basis computations for modules. Most of them should not be instantiated by hand. Instead, use the constructing routines on objects you already have. For example, to construct a free module over ``QQ[x, y]``, call ``QQ[x, y].free_module(rank)`` instead of the ``FreeModule`` constructor. In fact ``FreeModule`` is an abstract base class that should not be instantiated, the ``free_module`` method instead returns the implementing class ``FreeModulePolyRing``. In general, the abstract base classes implement most functionality in terms of a few non-implemented methods. The concrete base classes supply only these non-implemented methods. They may also supply new implementations of the convenience methods, for example if there are faster algorithms available. """ from copy import copy from functools import reduce from sympy.core.compatibility import iterable from sympy.polys.agca.ideals import Ideal from sympy.polys.domains.field import Field from sympy.polys.orderings import ProductOrder, monomial_key from sympy.polys.polyerrors import CoercionFailed from sympy.core.basic import _aresame # TODO # - module saturation # - module quotient/intersection for quotient rings # - free resoltutions / syzygies # - finding small/minimal generating sets # - ... ########################################################################## ## Abstract base classes ################################################# ########################################################################## class Module: """ Abstract base class for modules. Do not instantiate - use ring explicit constructors instead: >>> from sympy import QQ >>> from sympy.abc import x >>> QQ.old_poly_ring(x).free_module(2) QQ[x]**2 Attributes: - dtype - type of elements - ring - containing ring Non-implemented methods: - submodule - quotient_module - is_zero - is_submodule - multiply_ideal The method convert likely needs to be changed in subclasses. """ def __init__(self, ring): self.ring = ring def convert(self, elem, M=None): """ Convert ``elem`` into internal representation of this module. If ``M`` is not None, it should be a module containing it. """ if not isinstance(elem, self.dtype): raise CoercionFailed return elem def submodule(self, *gens): """Generate a submodule.""" raise NotImplementedError def quotient_module(self, other): """Generate a quotient module.""" raise NotImplementedError def __truediv__(self, e): if not isinstance(e, Module): e = self.submodule(*e) return self.quotient_module(e) def contains(self, elem): """Return True if ``elem`` is an element of this module.""" try: self.convert(elem) return True except CoercionFailed: return False def __contains__(self, elem): return self.contains(elem) def subset(self, other): """ Returns True if ``other`` is is a subset of ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> F.subset([(1, x), (x, 2)]) True >>> F.subset([(1/x, x), (x, 2)]) False """ return all(self.contains(x) for x in other) def __eq__(self, other): return self.is_submodule(other) and other.is_submodule(self) def __ne__(self, other): return not (self == other) def is_zero(self): """Returns True if ``self`` is a zero module.""" raise NotImplementedError def is_submodule(self, other): """Returns True if ``other`` is a submodule of ``self``.""" raise NotImplementedError def multiply_ideal(self, other): """ Multiply ``self`` by the ideal ``other``. """ raise NotImplementedError def __mul__(self, e): if not isinstance(e, Ideal): try: e = self.ring.ideal(e) except (CoercionFailed, NotImplementedError): return NotImplemented return self.multiply_ideal(e) __rmul__ = __mul__ def identity_hom(self): """Return the identity homomorphism on ``self``.""" raise NotImplementedError class ModuleElement: """ Base class for module element wrappers. Use this class to wrap primitive data types as module elements. It stores a reference to the containing module, and implements all the arithmetic operators. Attributes: - module - containing module - data - internal data Methods that likely need change in subclasses: - add - mul - div - eq """ def __init__(self, module, data): self.module = module self.data = data def add(self, d1, d2): """Add data ``d1`` and ``d2``.""" return d1 + d2 def mul(self, m, d): """Multiply module data ``m`` by coefficient d.""" return m * d def div(self, m, d): """Divide module data ``m`` by coefficient d.""" return m / d def eq(self, d1, d2): """Return true if d1 and d2 represent the same element.""" return d1 == d2 def __add__(self, om): if not isinstance(om, self.__class__) or om.module != self.module: try: om = self.module.convert(om) except CoercionFailed: return NotImplemented return self.__class__(self.module, self.add(self.data, om.data)) __radd__ = __add__ def __neg__(self): return self.__class__(self.module, self.mul(self.data, self.module.ring.convert(-1))) def __sub__(self, om): if not isinstance(om, self.__class__) or om.module != self.module: try: om = self.module.convert(om) except CoercionFailed: return NotImplemented return self.__add__(-om) def __rsub__(self, om): return (-self).__add__(om) def __mul__(self, o): if not isinstance(o, self.module.ring.dtype): try: o = self.module.ring.convert(o) except CoercionFailed: return NotImplemented return self.__class__(self.module, self.mul(self.data, o)) __rmul__ = __mul__ def __truediv__(self, o): if not isinstance(o, self.module.ring.dtype): try: o = self.module.ring.convert(o) except CoercionFailed: return NotImplemented return self.__class__(self.module, self.div(self.data, o)) def __eq__(self, om): if not isinstance(om, self.__class__) or om.module != self.module: try: om = self.module.convert(om) except CoercionFailed: return False return self.eq(self.data, om.data) def __ne__(self, om): return not self == om ########################################################################## ## Free Modules ########################################################## ########################################################################## class FreeModuleElement(ModuleElement): """Element of a free module. Data stored as a tuple.""" def add(self, d1, d2): return tuple(x + y for x, y in zip(d1, d2)) def mul(self, d, p): return tuple(x * p for x in d) def div(self, d, p): return tuple(x / p for x in d) def __repr__(self): from sympy import sstr return '[' + ', '.join(sstr(x) for x in self.data) + ']' def __iter__(self): return self.data.__iter__() def __getitem__(self, idx): return self.data[idx] class FreeModule(Module): """ Abstract base class for free modules. Additional attributes: - rank - rank of the free module Non-implemented methods: - submodule """ dtype = FreeModuleElement def __init__(self, ring, rank): Module.__init__(self, ring) self.rank = rank def __repr__(self): return repr(self.ring) + "**" + repr(self.rank) def is_submodule(self, other): """ Returns True if ``other`` is a submodule of ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> M = F.submodule([2, x]) >>> F.is_submodule(F) True >>> F.is_submodule(M) True >>> M.is_submodule(F) False """ if isinstance(other, SubModule): return other.container == self if isinstance(other, FreeModule): return other.ring == self.ring and other.rank == self.rank return False def convert(self, elem, M=None): """ Convert ``elem`` into the internal representation. This method is called implicitly whenever computations involve elements not in the internal representation. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> F.convert([1, 0]) [1, 0] """ if isinstance(elem, FreeModuleElement): if elem.module is self: return elem if elem.module.rank != self.rank: raise CoercionFailed return FreeModuleElement(self, tuple(self.ring.convert(x, elem.module.ring) for x in elem.data)) elif iterable(elem): tpl = tuple(self.ring.convert(x) for x in elem) if len(tpl) != self.rank: raise CoercionFailed return FreeModuleElement(self, tpl) elif _aresame(elem, 0): return FreeModuleElement(self, (self.ring.convert(0),)*self.rank) else: raise CoercionFailed def is_zero(self): """ Returns True if ``self`` is a zero module. (If, as this implementation assumes, the coefficient ring is not the zero ring, then this is equivalent to the rank being zero.) Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(0).is_zero() True >>> QQ.old_poly_ring(x).free_module(1).is_zero() False """ return self.rank == 0 def basis(self): """ Return a set of basis elements. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(3).basis() ([1, 0, 0], [0, 1, 0], [0, 0, 1]) """ from sympy.matrices import eye M = eye(self.rank) return tuple(self.convert(M.row(i)) for i in range(self.rank)) def quotient_module(self, submodule): """ Return a quotient module. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> M = QQ.old_poly_ring(x).free_module(2) >>> M.quotient_module(M.submodule([1, x], [x, 2])) QQ[x]**2/<[1, x], [x, 2]> Or more conicisely, using the overloaded division operator: >>> QQ.old_poly_ring(x).free_module(2) / [[1, x], [x, 2]] QQ[x]**2/<[1, x], [x, 2]> """ return QuotientModule(self.ring, self, submodule) def multiply_ideal(self, other): """ Multiply ``self`` by the ideal ``other``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> I = QQ.old_poly_ring(x).ideal(x) >>> F = QQ.old_poly_ring(x).free_module(2) >>> F.multiply_ideal(I) <[x, 0], [0, x]> """ return self.submodule(*self.basis()).multiply_ideal(other) def identity_hom(self): """ Return the identity homomorphism on ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(2).identity_hom() Matrix([ [1, 0], : QQ[x]**2 -> QQ[x]**2 [0, 1]]) """ from sympy.polys.agca.homomorphisms import homomorphism return homomorphism(self, self, self.basis()) class FreeModulePolyRing(FreeModule): """ Free module over a generalized polynomial ring. Do not instantiate this, use the constructor method of the ring instead: Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(3) >>> F QQ[x]**3 >>> F.contains([x, 1, 0]) True >>> F.contains([1/x, 0, 1]) False """ def __init__(self, ring, rank): from sympy.polys.domains.old_polynomialring import PolynomialRingBase FreeModule.__init__(self, ring, rank) if not isinstance(ring, PolynomialRingBase): raise NotImplementedError('This implementation only works over ' + 'polynomial rings, got %s' % ring) if not isinstance(ring.dom, Field): raise NotImplementedError('Ground domain must be a field, ' + 'got %s' % ring.dom) def submodule(self, *gens, **opts): """ Generate a submodule. Examples ======== >>> from sympy.abc import x, y >>> from sympy import QQ >>> M = QQ.old_poly_ring(x, y).free_module(2).submodule([x, x + y]) >>> M <[x, x + y]> >>> M.contains([2*x, 2*x + 2*y]) True >>> M.contains([x, y]) False """ return SubModulePolyRing(gens, self, **opts) class FreeModuleQuotientRing(FreeModule): """ Free module over a quotient ring. Do not instantiate this, use the constructor method of the ring instead: Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(3) >>> F (QQ[x]/)**3 Attributes - quot - the quotient module `R^n / IR^n`, where `R/I` is our ring """ def __init__(self, ring, rank): from sympy.polys.domains.quotientring import QuotientRing FreeModule.__init__(self, ring, rank) if not isinstance(ring, QuotientRing): raise NotImplementedError('This implementation only works over ' + 'quotient rings, got %s' % ring) F = self.ring.ring.free_module(self.rank) self.quot = F / (self.ring.base_ideal*F) def __repr__(self): return "(" + repr(self.ring) + ")" + "**" + repr(self.rank) def submodule(self, *gens, **opts): """ Generate a submodule. Examples ======== >>> from sympy.abc import x, y >>> from sympy import QQ >>> M = (QQ.old_poly_ring(x, y)/[x**2 - y**2]).free_module(2).submodule([x, x + y]) >>> M <[x + , x + y + ]> >>> M.contains([y**2, x**2 + x*y]) True >>> M.contains([x, y]) False """ return SubModuleQuotientRing(gens, self, **opts) def lift(self, elem): """ Lift the element ``elem`` of self to the module self.quot. Note that self.quot is the same set as self, just as an R-module and not as an R/I-module, so this makes sense. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(2) >>> e = F.convert([1, 0]) >>> e [1 + , 0 + ] >>> L = F.quot >>> l = F.lift(e) >>> l [1, 0] + <[x**2 + 1, 0], [0, x**2 + 1]> >>> L.contains(l) True """ return self.quot.convert([x.data for x in elem]) def unlift(self, elem): """ Push down an element of self.quot to self. This undoes ``lift``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(2) >>> e = F.convert([1, 0]) >>> l = F.lift(e) >>> e == l False >>> e == F.unlift(l) True """ return self.convert(elem.data) ########################################################################## ## Submodules and subquotients ########################################### ########################################################################## class SubModule(Module): """ Base class for submodules. Attributes: - container - containing module - gens - generators (subset of containing module) - rank - rank of containing module Non-implemented methods: - _contains - _syzygies - _in_terms_of_generators - _intersect - _module_quotient Methods that likely need change in subclasses: - reduce_element """ def __init__(self, gens, container): Module.__init__(self, container.ring) self.gens = tuple(container.convert(x) for x in gens) self.container = container self.rank = container.rank self.ring = container.ring self.dtype = container.dtype def __repr__(self): return "<" + ", ".join(repr(x) for x in self.gens) + ">" def _contains(self, other): """Implementation of containment. Other is guaranteed to be FreeModuleElement.""" raise NotImplementedError def _syzygies(self): """Implementation of syzygy computation wrt self generators.""" raise NotImplementedError def _in_terms_of_generators(self, e): """Implementation of expression in terms of generators.""" raise NotImplementedError def convert(self, elem, M=None): """ Convert ``elem`` into the internal represantition. Mostly called implicitly. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> M = QQ.old_poly_ring(x).free_module(2).submodule([1, x]) >>> M.convert([2, 2*x]) [2, 2*x] """ if isinstance(elem, self.container.dtype) and elem.module is self: return elem r = copy(self.container.convert(elem, M)) r.module = self if not self._contains(r): raise CoercionFailed return r def _intersect(self, other): """Implementation of intersection. Other is guaranteed to be a submodule of same free module.""" raise NotImplementedError def _module_quotient(self, other): """Implementation of quotient. Other is guaranteed to be a submodule of same free module.""" raise NotImplementedError def intersect(self, other, **options): """ Returns the intersection of ``self`` with submodule ``other``. Examples ======== >>> from sympy.abc import x, y >>> from sympy import QQ >>> F = QQ.old_poly_ring(x, y).free_module(2) >>> F.submodule([x, x]).intersect(F.submodule([y, y])) <[x*y, x*y]> Some implementation allow further options to be passed. Currently, to only one implemented is ``relations=True``, in which case the function will return a triple ``(res, rela, relb)``, where ``res`` is the intersection module, and ``rela`` and ``relb`` are lists of coefficient vectors, expressing the generators of ``res`` in terms of the generators of ``self`` (``rela``) and ``other`` (``relb``). >>> F.submodule([x, x]).intersect(F.submodule([y, y]), relations=True) (<[x*y, x*y]>, [(y,)], [(x,)]) The above result says: the intersection module is generated by the single element `(-xy, -xy) = -y (x, x) = -x (y, y)`, where `(x, x)` and `(y, y)` respectively are the unique generators of the two modules being intersected. """ if not isinstance(other, SubModule): raise TypeError('%s is not a SubModule' % other) if other.container != self.container: raise ValueError( '%s is contained in a different free module' % other) return self._intersect(other, **options) def module_quotient(self, other, **options): r""" Returns the module quotient of ``self`` by submodule ``other``. That is, if ``self`` is the module `M` and ``other`` is `N`, then return the ideal `\{f \in R | fN \subset M\}`. Examples ======== >>> from sympy import QQ >>> from sympy.abc import x, y >>> F = QQ.old_poly_ring(x, y).free_module(2) >>> S = F.submodule([x*y, x*y]) >>> T = F.submodule([x, x]) >>> S.module_quotient(T) Some implementations allow further options to be passed. Currently, the only one implemented is ``relations=True``, which may only be passed if ``other`` is principal. In this case the function will return a pair ``(res, rel)`` where ``res`` is the ideal, and ``rel`` is a list of coefficient vectors, expressing the generators of the ideal, multiplied by the generator of ``other`` in terms of generators of ``self``. >>> S.module_quotient(T, relations=True) (, [[1]]) This means that the quotient ideal is generated by the single element `y`, and that `y (x, x) = 1 (xy, xy)`, `(x, x)` and `(xy, xy)` being the generators of `T` and `S`, respectively. """ if not isinstance(other, SubModule): raise TypeError('%s is not a SubModule' % other) if other.container != self.container: raise ValueError( '%s is contained in a different free module' % other) return self._module_quotient(other, **options) def union(self, other): """ Returns the module generated by the union of ``self`` and ``other``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(1) >>> M = F.submodule([x**2 + x]) # >>> N = F.submodule([x**2 - 1]) # <(x-1)(x+1)> >>> M.union(N) == F.submodule([x+1]) True """ if not isinstance(other, SubModule): raise TypeError('%s is not a SubModule' % other) if other.container != self.container: raise ValueError( '%s is contained in a different free module' % other) return self.__class__(self.gens + other.gens, self.container) def is_zero(self): """ Return True if ``self`` is a zero module. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> F.submodule([x, 1]).is_zero() False >>> F.submodule([0, 0]).is_zero() True """ return all(x == 0 for x in self.gens) def submodule(self, *gens): """ Generate a submodule. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> M = QQ.old_poly_ring(x).free_module(2).submodule([x, 1]) >>> M.submodule([x**2, x]) <[x**2, x]> """ if not self.subset(gens): raise ValueError('%s not a subset of %s' % (gens, self)) return self.__class__(gens, self.container) def is_full_module(self): """ Return True if ``self`` is the entire free module. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> F.submodule([x, 1]).is_full_module() False >>> F.submodule([1, 1], [1, 2]).is_full_module() True """ return all(self.contains(x) for x in self.container.basis()) def is_submodule(self, other): """ Returns True if ``other`` is a submodule of ``self``. >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> M = F.submodule([2, x]) >>> N = M.submodule([2*x, x**2]) >>> M.is_submodule(M) True >>> M.is_submodule(N) True >>> N.is_submodule(M) False """ if isinstance(other, SubModule): return self.container == other.container and \ all(self.contains(x) for x in other.gens) if isinstance(other, (FreeModule, QuotientModule)): return self.container == other and self.is_full_module() return False def syzygy_module(self, **opts): r""" Compute the syzygy module of the generators of ``self``. Suppose `M` is generated by `f_1, \ldots, f_n` over the ring `R`. Consider the homomorphism `\phi: R^n \to M`, given by sending `(r_1, \ldots, r_n) \to r_1 f_1 + \cdots + r_n f_n`. The syzygy module is defined to be the kernel of `\phi`. Examples ======== The syzygy module is zero iff the generators generate freely a free submodule: >>> from sympy.abc import x, y >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(2).submodule([1, 0], [1, 1]).syzygy_module().is_zero() True A slightly more interesting example: >>> M = QQ.old_poly_ring(x, y).free_module(2).submodule([x, 2*x], [y, 2*y]) >>> S = QQ.old_poly_ring(x, y).free_module(2).submodule([y, -x]) >>> M.syzygy_module() == S True """ F = self.ring.free_module(len(self.gens)) # NOTE we filter out zero syzygies. This is for convenience of the # _syzygies function and not meant to replace any real "generating set # reduction" algorithm return F.submodule(*[x for x in self._syzygies() if F.convert(x) != 0], **opts) def in_terms_of_generators(self, e): """ Express element ``e`` of ``self`` in terms of the generators. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> M = F.submodule([1, 0], [1, 1]) >>> M.in_terms_of_generators([x, x**2]) [-x**2 + x, x**2] """ try: e = self.convert(e) except CoercionFailed: raise ValueError('%s is not an element of %s' % (e, self)) return self._in_terms_of_generators(e) def reduce_element(self, x): """ Reduce the element ``x`` of our ring modulo the ideal ``self``. Here "reduce" has no specific meaning, it could return a unique normal form, simplify the expression a bit, or just do nothing. """ return x def quotient_module(self, other, **opts): """ Return a quotient module. This is the same as taking a submodule of a quotient of the containing module. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> S1 = F.submodule([x, 1]) >>> S2 = F.submodule([x**2, x]) >>> S1.quotient_module(S2) <[x, 1] + <[x**2, x]>> Or more coincisely, using the overloaded division operator: >>> F.submodule([x, 1]) / [(x**2, x)] <[x, 1] + <[x**2, x]>> """ if not self.is_submodule(other): raise ValueError('%s not a submodule of %s' % (other, self)) return SubQuotientModule(self.gens, self.container.quotient_module(other), **opts) def __add__(self, oth): return self.container.quotient_module(self).convert(oth) __radd__ = __add__ def multiply_ideal(self, I): """ Multiply ``self`` by the ideal ``I``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> I = QQ.old_poly_ring(x).ideal(x**2) >>> M = QQ.old_poly_ring(x).free_module(2).submodule([1, 1]) >>> I*M <[x**2, x**2]> """ return self.submodule(*[x*g for [x] in I._module.gens for g in self.gens]) def inclusion_hom(self): """ Return a homomorphism representing the inclusion map of ``self``. That is, the natural map from ``self`` to ``self.container``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(2).submodule([x, x]).inclusion_hom() Matrix([ [1, 0], : <[x, x]> -> QQ[x]**2 [0, 1]]) """ return self.container.identity_hom().restrict_domain(self) def identity_hom(self): """ Return the identity homomorphism on ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(2).submodule([x, x]).identity_hom() Matrix([ [1, 0], : <[x, x]> -> <[x, x]> [0, 1]]) """ return self.container.identity_hom().restrict_domain( self).restrict_codomain(self) class SubQuotientModule(SubModule): """ Submodule of a quotient module. Equivalently, quotient module of a submodule. Do not instantiate this, instead use the submodule or quotient_module constructing methods: >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> S = F.submodule([1, 0], [1, x]) >>> Q = F/[(1, 0)] >>> S/[(1, 0)] == Q.submodule([5, x]) True Attributes: - base - base module we are quotient of - killed_module - submodule used to form the quotient """ def __init__(self, gens, container, **opts): SubModule.__init__(self, gens, container) self.killed_module = self.container.killed_module # XXX it is important for some code below that the generators of base # are in this particular order! self.base = self.container.base.submodule( *[x.data for x in self.gens], **opts).union(self.killed_module) def _contains(self, elem): return self.base.contains(elem.data) def _syzygies(self): # let N = self.killed_module be generated by e_1, ..., e_r # let F = self.base be generated by f_1, ..., f_s and e_1, ..., e_r # Then self = F/N. # Let phi: R**s --> self be the evident surjection. # Similarly psi: R**(s + r) --> F. # We need to find generators for ker(phi). Let chi: R**s --> F be the # evident lift of phi. For X in R**s, phi(X) = 0 iff chi(X) is # contained in N, iff there exists Y in R**r such that # psi(X, Y) = 0. # Hence if alpha: R**(s + r) --> R**s is the projection map, then # ker(phi) = alpha ker(psi). return [X[:len(self.gens)] for X in self.base._syzygies()] def _in_terms_of_generators(self, e): return self.base._in_terms_of_generators(e.data)[:len(self.gens)] def is_full_module(self): """ Return True if ``self`` is the entire free module. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> F.submodule([x, 1]).is_full_module() False >>> F.submodule([1, 1], [1, 2]).is_full_module() True """ return self.base.is_full_module() def quotient_hom(self): """ Return the quotient homomorphism to self. That is, return the natural map from ``self.base`` to ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> M = (QQ.old_poly_ring(x).free_module(2) / [(1, x)]).submodule([1, 0]) >>> M.quotient_hom() Matrix([ [1, 0], : <[1, 0], [1, x]> -> <[1, 0] + <[1, x]>, [1, x] + <[1, x]>> [0, 1]]) """ return self.base.identity_hom().quotient_codomain(self.killed_module) _subs0 = lambda x: x[0] _subs1 = lambda x: x[1:] class ModuleOrder(ProductOrder): """A product monomial order with a zeroth term as module index.""" def __init__(self, o1, o2, TOP): if TOP: ProductOrder.__init__(self, (o2, _subs1), (o1, _subs0)) else: ProductOrder.__init__(self, (o1, _subs0), (o2, _subs1)) class SubModulePolyRing(SubModule): """ Submodule of a free module over a generalized polynomial ring. Do not instantiate this, use the constructor method of FreeModule instead: >>> from sympy.abc import x, y >>> from sympy import QQ >>> F = QQ.old_poly_ring(x, y).free_module(2) >>> F.submodule([x, y], [1, 0]) <[x, y], [1, 0]> Attributes: - order - monomial order used """ #self._gb - cached groebner basis #self._gbe - cached groebner basis relations def __init__(self, gens, container, order="lex", TOP=True): SubModule.__init__(self, gens, container) if not isinstance(container, FreeModulePolyRing): raise NotImplementedError('This implementation is for submodules of ' + 'FreeModulePolyRing, got %s' % container) self.order = ModuleOrder(monomial_key(order), self.ring.order, TOP) self._gb = None self._gbe = None def __eq__(self, other): if isinstance(other, SubModulePolyRing) and self.order != other.order: return False return SubModule.__eq__(self, other) def _groebner(self, extended=False): """Returns a standard basis in sdm form.""" from sympy.polys.distributedmodules import sdm_groebner, sdm_nf_mora if self._gbe is None and extended: gb, gbe = sdm_groebner( [self.ring._vector_to_sdm(x, self.order) for x in self.gens], sdm_nf_mora, self.order, self.ring.dom, extended=True) self._gb, self._gbe = tuple(gb), tuple(gbe) if self._gb is None: self._gb = tuple(sdm_groebner( [self.ring._vector_to_sdm(x, self.order) for x in self.gens], sdm_nf_mora, self.order, self.ring.dom)) if extended: return self._gb, self._gbe else: return self._gb def _groebner_vec(self, extended=False): """Returns a standard basis in element form.""" if not extended: return [self.convert(self.ring._sdm_to_vector(x, self.rank)) for x in self._groebner()] gb, gbe = self._groebner(extended=True) return ([self.convert(self.ring._sdm_to_vector(x, self.rank)) for x in gb], [self.ring._sdm_to_vector(x, len(self.gens)) for x in gbe]) def _contains(self, x): from sympy.polys.distributedmodules import sdm_zero, sdm_nf_mora return sdm_nf_mora(self.ring._vector_to_sdm(x, self.order), self._groebner(), self.order, self.ring.dom) == \ sdm_zero() def _syzygies(self): """Compute syzygies. See [SCA, algorithm 2.5.4].""" # NOTE if self.gens is a standard basis, this can be done more # efficiently using Schreyer's theorem from sympy.matrices import eye # First bullet point k = len(self.gens) r = self.rank im = eye(k) Rkr = self.ring.free_module(r + k) newgens = [] for j, f in enumerate(self.gens): m = [0]*(r + k) for i, v in enumerate(f): m[i] = f[i] for i in range(k): m[r + i] = im[j, i] newgens.append(Rkr.convert(m)) # Note: we need *descending* order on module index, and TOP=False to # get an elimination order F = Rkr.submodule(*newgens, order='ilex', TOP=False) # Second bullet point: standard basis of F G = F._groebner_vec() # Third bullet point: G0 = G intersect the new k components G0 = [x[r:] for x in G if all(y == self.ring.convert(0) for y in x[:r])] # Fourth and fifth bullet points: we are done return G0 def _in_terms_of_generators(self, e): """Expression in terms of generators. See [SCA, 2.8.1].""" # NOTE: if gens is a standard basis, this can be done more efficiently M = self.ring.free_module(self.rank).submodule(*((e,) + self.gens)) S = M.syzygy_module( order="ilex", TOP=False) # We want decreasing order! G = S._groebner_vec() # This list cannot not be empty since e is an element e = [x for x in G if self.ring.is_unit(x[0])][0] return [-x/e[0] for x in e[1:]] def reduce_element(self, x, NF=None): """ Reduce the element ``x`` of our container modulo ``self``. This applies the normal form ``NF`` to ``x``. If ``NF`` is passed as none, the default Mora normal form is used (which is not unique!). """ from sympy.polys.distributedmodules import sdm_nf_mora if NF is None: NF = sdm_nf_mora return self.container.convert(self.ring._sdm_to_vector(NF( self.ring._vector_to_sdm(x, self.order), self._groebner(), self.order, self.ring.dom), self.rank)) def _intersect(self, other, relations=False): # See: [SCA, section 2.8.2] fi = self.gens hi = other.gens r = self.rank ci = [[0]*(2*r) for _ in range(r)] for k in range(r): ci[k][k] = 1 ci[k][r + k] = 1 di = [list(f) + [0]*r for f in fi] ei = [[0]*r + list(h) for h in hi] syz = self.ring.free_module(2*r).submodule(*(ci + di + ei))._syzygies() nonzero = [x for x in syz if any(y != self.ring.zero for y in x[:r])] res = self.container.submodule(*([-y for y in x[:r]] for x in nonzero)) reln1 = [x[r:r + len(fi)] for x in nonzero] reln2 = [x[r + len(fi):] for x in nonzero] if relations: return res, reln1, reln2 return res def _module_quotient(self, other, relations=False): # See: [SCA, section 2.8.4] if relations and len(other.gens) != 1: raise NotImplementedError if len(other.gens) == 0: return self.ring.ideal(1) elif len(other.gens) == 1: # We do some trickery. Let f be the (vector!) generating ``other`` # and f1, .., fn be the (vectors) generating self. # Consider the submodule of R^{r+1} generated by (f, 1) and # {(fi, 0) | i}. Then the intersection with the last module # component yields the quotient. g1 = list(other.gens[0]) + [1] gi = [list(x) + [0] for x in self.gens] # NOTE: We *need* to use an elimination order M = self.ring.free_module(self.rank + 1).submodule(*([g1] + gi), order='ilex', TOP=False) if not relations: return self.ring.ideal(*[x[-1] for x in M._groebner_vec() if all(y == self.ring.zero for y in x[:-1])]) else: G, R = M._groebner_vec(extended=True) indices = [i for i, x in enumerate(G) if all(y == self.ring.zero for y in x[:-1])] return (self.ring.ideal(*[G[i][-1] for i in indices]), [[-x for x in R[i][1:]] for i in indices]) # For more generators, we use I : = intersection of # {I : | i} # TODO this can be done more efficiently return reduce(lambda x, y: x.intersect(y), (self._module_quotient(self.container.submodule(x)) for x in other.gens)) class SubModuleQuotientRing(SubModule): """ Class for submodules of free modules over quotient rings. Do not instantiate this. Instead use the submodule methods. >>> from sympy.abc import x, y >>> from sympy import QQ >>> M = (QQ.old_poly_ring(x, y)/[x**2 - y**2]).free_module(2).submodule([x, x + y]) >>> M <[x + , x + y + ]> >>> M.contains([y**2, x**2 + x*y]) True >>> M.contains([x, y]) False Attributes: - quot - the subquotient of `R^n/IR^n` generated by lifts of our generators """ def __init__(self, gens, container): SubModule.__init__(self, gens, container) self.quot = self.container.quot.submodule( *[self.container.lift(x) for x in self.gens]) def _contains(self, elem): return self.quot._contains(self.container.lift(elem)) def _syzygies(self): return [tuple(self.ring.convert(y, self.quot.ring) for y in x) for x in self.quot._syzygies()] def _in_terms_of_generators(self, elem): return [self.ring.convert(x, self.quot.ring) for x in self.quot._in_terms_of_generators(self.container.lift(elem))] ########################################################################## ## Quotient Modules ###################################################### ########################################################################## class QuotientModuleElement(ModuleElement): """Element of a quotient module.""" def eq(self, d1, d2): """Equality comparison.""" return self.module.killed_module.contains(d1 - d2) def __repr__(self): return repr(self.data) + " + " + repr(self.module.killed_module) class QuotientModule(Module): """ Class for quotient modules. Do not instantiate this directly. For subquotients, see the SubQuotientModule class. Attributes: - base - the base module we are a quotient of - killed_module - the submodule used to form the quotient - rank of the base """ dtype = QuotientModuleElement def __init__(self, ring, base, submodule): Module.__init__(self, ring) if not base.is_submodule(submodule): raise ValueError('%s is not a submodule of %s' % (submodule, base)) self.base = base self.killed_module = submodule self.rank = base.rank def __repr__(self): return repr(self.base) + "/" + repr(self.killed_module) def is_zero(self): """ Return True if ``self`` is a zero module. This happens if and only if the base module is the same as the submodule being killed. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) >>> (F/[(1, 0)]).is_zero() False >>> (F/[(1, 0), (0, 1)]).is_zero() True """ return self.base == self.killed_module def is_submodule(self, other): """ Return True if ``other`` is a submodule of ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> Q = QQ.old_poly_ring(x).free_module(2) / [(x, x)] >>> S = Q.submodule([1, 0]) >>> Q.is_submodule(S) True >>> S.is_submodule(Q) False """ if isinstance(other, QuotientModule): return self.killed_module == other.killed_module and \ self.base.is_submodule(other.base) if isinstance(other, SubQuotientModule): return other.container == self return False def submodule(self, *gens, **opts): """ Generate a submodule. This is the same as taking a quotient of a submodule of the base module. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> Q = QQ.old_poly_ring(x).free_module(2) / [(x, x)] >>> Q.submodule([x, 0]) <[x, 0] + <[x, x]>> """ return SubQuotientModule(gens, self, **opts) def convert(self, elem, M=None): """ Convert ``elem`` into the internal representation. This method is called implicitly whenever computations involve elements not in the internal representation. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> F = QQ.old_poly_ring(x).free_module(2) / [(1, 2), (1, x)] >>> F.convert([1, 0]) [1, 0] + <[1, 2], [1, x]> """ if isinstance(elem, QuotientModuleElement): if elem.module is self: return elem if self.killed_module.is_submodule(elem.module.killed_module): return QuotientModuleElement(self, self.base.convert(elem.data)) raise CoercionFailed return QuotientModuleElement(self, self.base.convert(elem)) def identity_hom(self): """ Return the identity homomorphism on ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> M = QQ.old_poly_ring(x).free_module(2) / [(1, 2), (1, x)] >>> M.identity_hom() Matrix([ [1, 0], : QQ[x]**2/<[1, 2], [1, x]> -> QQ[x]**2/<[1, 2], [1, x]> [0, 1]]) """ return self.base.identity_hom().quotient_codomain( self.killed_module).quotient_domain(self.killed_module) def quotient_hom(self): """ Return the quotient homomorphism to ``self``. That is, return a homomorphism representing the natural map from ``self.base`` to ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> M = QQ.old_poly_ring(x).free_module(2) / [(1, 2), (1, x)] >>> M.quotient_hom() Matrix([ [1, 0], : QQ[x]**2 -> QQ[x]**2/<[1, 2], [1, x]> [0, 1]]) """ return self.base.identity_hom().quotient_codomain( self.killed_module) sympy-sympy-1.9/sympy/polys/agca/tests/000077500000000000000000000000001412543434000203075ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/agca/tests/__init__.py000066400000000000000000000000001412543434000224060ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/agca/tests/test_extensions.py000066400000000000000000000143651412543434000241300ustar00rootroot00000000000000from sympy import symbols, sin, cos from sympy.polys import QQ, ZZ from sympy.polys.polytools import Poly from sympy.polys.polyerrors import NotInvertible from sympy.polys.agca.extensions import FiniteExtension from sympy.polys.domainmatrix import DomainMatrix from sympy.testing.pytest import raises from sympy.abc import x, y, t def test_FiniteExtension(): # Gaussian integers A = FiniteExtension(Poly(x**2 + 1, x)) assert A.rank == 2 assert str(A) == 'ZZ[x]/(x**2 + 1)' i = A.generator assert i.parent() is A assert i*i == A(-1) raises(TypeError, lambda: i*()) assert A.basis == (A.one, i) assert A(1) == A.one assert i**2 == A(-1) assert i**2 != -1 # no coercion assert (2 + i)*(1 - i) == 3 - i assert (1 + i)**8 == A(16) assert A(1).inverse() == A(1) raises(NotImplementedError, lambda: A(2).inverse()) # Finite field of order 27 F = FiniteExtension(Poly(x**3 - x + 1, x, modulus=3)) assert F.rank == 3 a = F.generator # also generates the cyclic group F - {0} assert F.basis == (F(1), a, a**2) assert a**27 == a assert a**26 == F(1) assert a**13 == F(-1) assert a**9 == a + 1 assert a**3 == a - 1 assert a**6 == a**2 + a + 1 assert F(x**2 + x).inverse() == 1 - a assert F(x + 2)**(-1) == F(x + 2).inverse() assert a**19 * a**(-19) == F(1) assert (a - 1) / (2*a**2 - 1) == a**2 + 1 assert (a - 1) // (2*a**2 - 1) == a**2 + 1 assert 2/(a**2 + 1) == a**2 - a + 1 assert (a**2 + 1)/2 == -a**2 - 1 raises(NotInvertible, lambda: F(0).inverse()) # Function field of an elliptic curve K = FiniteExtension(Poly(t**2 - x**3 - x + 1, t, field=True)) assert K.rank == 2 assert str(K) == 'ZZ(x)[t]/(t**2 - x**3 - x + 1)' y = K.generator c = 1/(x**3 - x**2 + x - 1) assert ((y + x)*(y - x)).inverse() == K(c) assert (y + x)*(y - x)*c == K(1) # explicit inverse of y + x def test_FiniteExtension_eq_hash(): # Test eq and hash p1 = Poly(x**2 - 2, x, domain=ZZ) p2 = Poly(x**2 - 2, x, domain=QQ) K1 = FiniteExtension(p1) K2 = FiniteExtension(p2) assert K1 == FiniteExtension(Poly(x**2 - 2)) assert K2 != FiniteExtension(Poly(x**2 - 2)) assert len({K1, K2, FiniteExtension(p1)}) == 2 def test_FiniteExtension_mod(): # Test mod K = FiniteExtension(Poly(x**3 + 1, x, domain=QQ)) xf = K(x) assert (xf**2 - 1) % 1 == K.zero assert 1 % (xf**2 - 1) == K.zero assert (xf**2 - 1) / (xf - 1) == xf + 1 assert (xf**2 - 1) // (xf - 1) == xf + 1 assert (xf**2 - 1) % (xf - 1) == K.zero raises(ZeroDivisionError, lambda: (xf**2 - 1) % 0) raises(TypeError, lambda: xf % []) raises(TypeError, lambda: [] % xf) # Test mod over ring K = FiniteExtension(Poly(x**3 + 1, x, domain=ZZ)) xf = K(x) assert (xf**2 - 1) % 1 == K.zero raises(NotImplementedError, lambda: (xf**2 - 1) % (xf - 1)) def test_FiniteExtension_from_sympy(): # Test to_sympy/from_sympy K = FiniteExtension(Poly(x**3 + 1, x, domain=ZZ)) xf = K(x) assert K.from_sympy(x) == xf assert K.to_sympy(xf) == x def test_FiniteExtension_set_domain(): KZ = FiniteExtension(Poly(x**2 + 1, x, domain='ZZ')) KQ = FiniteExtension(Poly(x**2 + 1, x, domain='QQ')) assert KZ.set_domain(QQ) == KQ def test_FiniteExtension_exquo(): # Test exquo K = FiniteExtension(Poly(x**4 + 1)) xf = K(x) assert K.exquo(xf**2 - 1, xf - 1) == xf + 1 def test_FiniteExtension_convert(): # Test from_MonogenicFiniteExtension K1 = FiniteExtension(Poly(x**2 + 1)) K2 = QQ[x] x1, x2 = K1(x), K2(x) assert K1.convert(x2) == x1 assert K2.convert(x1) == x2 K = FiniteExtension(Poly(x**2 - 1, domain=QQ)) assert K.convert_from(QQ(1, 2), QQ) == K.one/2 def test_FiniteExtension_division_ring(): # Test division in FiniteExtension over a ring KQ = FiniteExtension(Poly(x**2 - 1, x, domain=QQ)) KZ = FiniteExtension(Poly(x**2 - 1, x, domain=ZZ)) KQt = FiniteExtension(Poly(x**2 - 1, x, domain=QQ[t])) KQtf = FiniteExtension(Poly(x**2 - 1, x, domain=QQ.frac_field(t))) assert KQ.is_Field is True assert KZ.is_Field is False assert KQt.is_Field is False assert KQtf.is_Field is True for K in KQ, KZ, KQt, KQtf: xK = K.convert(x) assert xK / K.one == xK assert xK // K.one == xK assert xK % K.one == K.zero raises(ZeroDivisionError, lambda: xK / K.zero) raises(ZeroDivisionError, lambda: xK // K.zero) raises(ZeroDivisionError, lambda: xK % K.zero) if K.is_Field: assert xK / xK == K.one assert xK // xK == K.one assert xK % xK == K.zero else: raises(NotImplementedError, lambda: xK / xK) raises(NotImplementedError, lambda: xK // xK) raises(NotImplementedError, lambda: xK % xK) def test_FiniteExtension_Poly(): K = FiniteExtension(Poly(x**2 - 2)) p = Poly(x, y, domain=K) assert p.domain == K assert p.as_expr() == x assert (p**2).as_expr() == 2 K = FiniteExtension(Poly(x**2 - 2, x, domain=QQ)) K2 = FiniteExtension(Poly(t**2 - 2, t, domain=K)) assert str(K2) == 'QQ[x]/(x**2 - 2)[t]/(t**2 - 2)' eK = K2.convert(x + t) assert K2.to_sympy(eK) == x + t assert K2.to_sympy(eK ** 2) == 4 + 2*x*t p = Poly(x + t, y, domain=K2) assert p**2 == Poly(4 + 2*x*t, y, domain=K2) def test_FiniteExtension_sincos_jacobian(): # Use FiniteExtensino to compute the Jacobian of a matrix involving sin # and cos of different symbols. r, p, t = symbols('rho, phi, theta') elements = [ [sin(p)*cos(t), r*cos(p)*cos(t), -r*sin(p)*sin(t)], [sin(p)*sin(t), r*cos(p)*sin(t), r*sin(p)*cos(t)], [ cos(p), -r*sin(p), 0], ] def make_extension(K): K = FiniteExtension(Poly(sin(p)**2+cos(p)**2-1, sin(p), domain=K[cos(p)])) K = FiniteExtension(Poly(sin(t)**2+cos(t)**2-1, sin(t), domain=K[cos(t)])) return K Ksc1 = make_extension(ZZ[r]) Ksc2 = make_extension(ZZ)[r] for K in [Ksc1, Ksc2]: elements_K = [[K.convert(e) for e in row] for row in elements] J = DomainMatrix(elements_K, (3, 3), K) det = J.charpoly()[-1] * (-K.one)**3 assert det == K.convert(r**2*sin(p)) sympy-sympy-1.9/sympy/polys/agca/tests/test_homomorphisms.py000066400000000000000000000101041412543434000246200ustar00rootroot00000000000000"""Tests for homomorphisms.""" from sympy import QQ, S from sympy.abc import x, y from sympy.polys.agca import homomorphism from sympy.testing.pytest import raises def test_printing(): R = QQ.old_poly_ring(x) assert str(homomorphism(R.free_module(1), R.free_module(1), [0])) == \ 'Matrix([[0]]) : QQ[x]**1 -> QQ[x]**1' assert str(homomorphism(R.free_module(2), R.free_module(2), [0, 0])) == \ 'Matrix([ \n[0, 0], : QQ[x]**2 -> QQ[x]**2\n[0, 0]]) ' assert str(homomorphism(R.free_module(1), R.free_module(1) / [[x]], [0])) == \ 'Matrix([[0]]) : QQ[x]**1 -> QQ[x]**1/<[x]>' assert str(R.free_module(0).identity_hom()) == 'Matrix(0, 0, []) : QQ[x]**0 -> QQ[x]**0' def test_operations(): F = QQ.old_poly_ring(x).free_module(2) G = QQ.old_poly_ring(x).free_module(3) f = F.identity_hom() g = homomorphism(F, F, [0, [1, x]]) h = homomorphism(F, F, [[1, 0], 0]) i = homomorphism(F, G, [[1, 0, 0], [0, 1, 0]]) assert f == f assert f != g assert f != i assert (f != F.identity_hom()) is False assert 2*f == f*2 == homomorphism(F, F, [[2, 0], [0, 2]]) assert f/2 == homomorphism(F, F, [[S.Half, 0], [0, S.Half]]) assert f + g == homomorphism(F, F, [[1, 0], [1, x + 1]]) assert f - g == homomorphism(F, F, [[1, 0], [-1, 1 - x]]) assert f*g == g == g*f assert h*g == homomorphism(F, F, [0, [1, 0]]) assert g*h == homomorphism(F, F, [0, 0]) assert i*f == i assert f([1, 2]) == [1, 2] assert g([1, 2]) == [2, 2*x] assert i.restrict_domain(F.submodule([x, x]))([x, x]) == i([x, x]) h1 = h.quotient_domain(F.submodule([0, 1])) assert h1([1, 0]) == h([1, 0]) assert h1.restrict_domain(h1.domain.submodule([x, 0]))([x, 0]) == h([x, 0]) raises(TypeError, lambda: f/g) raises(TypeError, lambda: f + 1) raises(TypeError, lambda: f + i) raises(TypeError, lambda: f - 1) raises(TypeError, lambda: f*i) def test_creation(): F = QQ.old_poly_ring(x).free_module(3) G = QQ.old_poly_ring(x).free_module(2) SM = F.submodule([1, 1, 1]) Q = F / SM SQ = Q.submodule([1, 0, 0]) matrix = [[1, 0], [0, 1], [-1, -1]] h = homomorphism(F, G, matrix) h2 = homomorphism(Q, G, matrix) assert h.quotient_domain(SM) == h2 raises(ValueError, lambda: h.quotient_domain(F.submodule([1, 0, 0]))) assert h2.restrict_domain(SQ) == homomorphism(SQ, G, matrix) raises(ValueError, lambda: h.restrict_domain(G)) raises(ValueError, lambda: h.restrict_codomain(G.submodule([1, 0]))) raises(ValueError, lambda: h.quotient_codomain(F)) im = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] for M in [F, SM, Q, SQ]: assert M.identity_hom() == homomorphism(M, M, im) assert SM.inclusion_hom() == homomorphism(SM, F, im) assert SQ.inclusion_hom() == homomorphism(SQ, Q, im) assert Q.quotient_hom() == homomorphism(F, Q, im) assert SQ.quotient_hom() == homomorphism(SQ.base, SQ, im) class conv: def convert(x, y=None): return x class dummy: container = conv() def submodule(*args): return None raises(TypeError, lambda: homomorphism(dummy(), G, matrix)) raises(TypeError, lambda: homomorphism(F, dummy(), matrix)) raises( ValueError, lambda: homomorphism(QQ.old_poly_ring(x, y).free_module(3), G, matrix)) raises(ValueError, lambda: homomorphism(F, G, [0, 0])) def test_properties(): R = QQ.old_poly_ring(x, y) F = R.free_module(2) h = homomorphism(F, F, [[x, 0], [y, 0]]) assert h.kernel() == F.submodule([-y, x]) assert h.image() == F.submodule([x, 0], [y, 0]) assert not h.is_injective() assert not h.is_surjective() assert h.restrict_codomain(h.image()).is_surjective() assert h.restrict_domain(F.submodule([1, 0])).is_injective() assert h.quotient_domain( h.kernel()).restrict_codomain(h.image()).is_isomorphism() R2 = QQ.old_poly_ring(x, y, order=(("lex", x), ("ilex", y))) / [x**2 + 1] F = R2.free_module(2) h = homomorphism(F, F, [[x, 0], [y, y + 1]]) assert h.is_isomorphism() sympy-sympy-1.9/sympy/polys/agca/tests/test_ideals.py000066400000000000000000000073141412543434000231660ustar00rootroot00000000000000"""Test ideals.py code.""" from sympy.polys import QQ, ilex from sympy.abc import x, y, z from sympy.testing.pytest import raises def test_ideal_operations(): R = QQ.old_poly_ring(x, y) I = R.ideal(x) J = R.ideal(y) S = R.ideal(x*y) T = R.ideal(x, y) assert not (I == J) assert I == I assert I.union(J) == T assert I + J == T assert I + T == T assert not I.subset(T) assert T.subset(I) assert I.product(J) == S assert I*J == S assert x*J == S assert I*y == S assert R.convert(x)*J == S assert I*R.convert(y) == S assert not I.is_zero() assert not J.is_whole_ring() assert R.ideal(x**2 + 1, x).is_whole_ring() assert R.ideal() == R.ideal(0) assert R.ideal().is_zero() assert T.contains(x*y) assert T.subset([x, y]) assert T.in_terms_of_generators(x) == [R(1), R(0)] assert T**0 == R.ideal(1) assert T**1 == T assert T**2 == R.ideal(x**2, y**2, x*y) assert I**5 == R.ideal(x**5) def test_exceptions(): I = QQ.old_poly_ring(x).ideal(x) J = QQ.old_poly_ring(y).ideal(1) raises(ValueError, lambda: I.union(x)) raises(ValueError, lambda: I + J) raises(ValueError, lambda: I * J) raises(ValueError, lambda: I.union(J)) assert (I == J) is False assert I != J def test_nontriv_global(): R = QQ.old_poly_ring(x, y, z) def contains(I, f): return R.ideal(*I).contains(f) assert contains([x, y], x) assert contains([x, y], x + y) assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**3) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y**2) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4 + y**3 + 2*z*y*x) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y*z) assert contains([x, 1 + x + y, 5 - 7*y], 1) assert contains( [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], x**3) assert not contains( [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], x**2 + y**2) # compare local order assert not contains([x*(1 + x + y), y*(1 + z)], x) assert not contains([x*(1 + x + y), y*(1 + z)], x + y) def test_nontriv_local(): R = QQ.old_poly_ring(x, y, z, order=ilex) def contains(I, f): return R.ideal(*I).contains(f) assert contains([x, y], x) assert contains([x, y], x + y) assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) assert contains([x*(1 + x + y), y*(1 + z)], x) assert contains([x*(1 + x + y), y*(1 + z)], x + y) def test_intersection(): R = QQ.old_poly_ring(x, y, z) # SCA, example 1.8.11 assert R.ideal(x, y).intersect(R.ideal(y**2, z)) == R.ideal(y**2, y*z, x*z) assert R.ideal(x, y).intersect(R.ideal()).is_zero() R = QQ.old_poly_ring(x, y, z, order="ilex") assert R.ideal(x, y).intersect(R.ideal(y**2 + y**2*z, z + z*x**3*y)) == \ R.ideal(y**2, y*z, x*z) def test_quotient(): # SCA, example 1.8.13 R = QQ.old_poly_ring(x, y, z) assert R.ideal(x, y).quotient(R.ideal(y**2, z)) == R.ideal(x, y) def test_reduction(): from sympy.polys.distributedmodules import sdm_nf_buchberger_reduced R = QQ.old_poly_ring(x, y) I = R.ideal(x**5, y) e = R.convert(x**3 + y**2) assert I.reduce_element(e) == e assert I.reduce_element(e, NF=sdm_nf_buchberger_reduced) == R.convert(x**3) sympy-sympy-1.9/sympy/polys/agca/tests/test_modules.py000066400000000000000000000323431412543434000233750ustar00rootroot00000000000000"""Test modules.py code.""" from sympy.polys.agca.modules import FreeModule, ModuleOrder, FreeModulePolyRing from sympy.polys import CoercionFailed, QQ, lex, grlex, ilex, ZZ from sympy.abc import x, y, z from sympy.testing.pytest import raises from sympy import Rational def test_FreeModuleElement(): M = QQ.old_poly_ring(x).free_module(3) e = M.convert([1, x, x**2]) f = [QQ.old_poly_ring(x).convert(1), QQ.old_poly_ring(x).convert(x), QQ.old_poly_ring(x).convert(x**2)] assert list(e) == f assert f[0] == e[0] assert f[1] == e[1] assert f[2] == e[2] raises(IndexError, lambda: e[3]) g = M.convert([x, 0, 0]) assert e + g == M.convert([x + 1, x, x**2]) assert f + g == M.convert([x + 1, x, x**2]) assert -e == M.convert([-1, -x, -x**2]) assert e - g == M.convert([1 - x, x, x**2]) assert e != g assert M.convert([x, x, x]) / QQ.old_poly_ring(x).convert(x) == [1, 1, 1] R = QQ.old_poly_ring(x, order="ilex") assert R.free_module(1).convert([x]) / R.convert(x) == [1] def test_FreeModule(): M1 = FreeModule(QQ.old_poly_ring(x), 2) assert M1 == FreeModule(QQ.old_poly_ring(x), 2) assert M1 != FreeModule(QQ.old_poly_ring(y), 2) assert M1 != FreeModule(QQ.old_poly_ring(x), 3) M2 = FreeModule(QQ.old_poly_ring(x, order="ilex"), 2) assert [x, 1] in M1 assert [x] not in M1 assert [2, y] not in M1 assert [1/(x + 1), 2] not in M1 e = M1.convert([x, x**2 + 1]) X = QQ.old_poly_ring(x).convert(x) assert e == [X, X**2 + 1] assert e == [x, x**2 + 1] assert 2*e == [2*x, 2*x**2 + 2] assert e*2 == [2*x, 2*x**2 + 2] assert e/2 == [x/2, (x**2 + 1)/2] assert x*e == [x**2, x**3 + x] assert e*x == [x**2, x**3 + x] assert X*e == [x**2, x**3 + x] assert e*X == [x**2, x**3 + x] assert [x, 1] in M2 assert [x] not in M2 assert [2, y] not in M2 assert [1/(x + 1), 2] in M2 e = M2.convert([x, x**2 + 1]) X = QQ.old_poly_ring(x, order="ilex").convert(x) assert e == [X, X**2 + 1] assert e == [x, x**2 + 1] assert 2*e == [2*x, 2*x**2 + 2] assert e*2 == [2*x, 2*x**2 + 2] assert e/2 == [x/2, (x**2 + 1)/2] assert x*e == [x**2, x**3 + x] assert e*x == [x**2, x**3 + x] assert e/(1 + x) == [x/(1 + x), (x**2 + 1)/(1 + x)] assert X*e == [x**2, x**3 + x] assert e*X == [x**2, x**3 + x] M3 = FreeModule(QQ.old_poly_ring(x, y), 2) assert M3.convert(e) == M3.convert([x, x**2 + 1]) assert not M3.is_submodule(0) assert not M3.is_zero() raises(NotImplementedError, lambda: ZZ.old_poly_ring(x).free_module(2)) raises(NotImplementedError, lambda: FreeModulePolyRing(ZZ, 2)) raises(CoercionFailed, lambda: M1.convert(QQ.old_poly_ring(x).free_module(3) .convert([1, 2, 3]))) raises(CoercionFailed, lambda: M3.convert(1)) def test_ModuleOrder(): o1 = ModuleOrder(lex, grlex, False) o2 = ModuleOrder(ilex, lex, False) assert o1 == ModuleOrder(lex, grlex, False) assert (o1 != ModuleOrder(lex, grlex, False)) is False assert o1 != o2 assert o1((1, 2, 3)) == (1, (5, (2, 3))) assert o2((1, 2, 3)) == (-1, (2, 3)) def test_SubModulePolyRing_global(): R = QQ.old_poly_ring(x, y) F = R.free_module(3) Fd = F.submodule([1, 0, 0], [1, 2, 0], [1, 2, 3]) M = F.submodule([x**2 + y**2, 1, 0], [x, y, 1]) assert F == Fd assert Fd == F assert F != M assert M != F assert Fd != M assert M != Fd assert Fd == F.submodule(*F.basis()) assert Fd.is_full_module() assert not M.is_full_module() assert not Fd.is_zero() assert not M.is_zero() assert Fd.submodule().is_zero() assert M.contains([x**2 + y**2 + x, 1 + y, 1]) assert not M.contains([x**2 + y**2 + x, 1 + y, 2]) assert M.contains([y**2, 1 - x*y, -x]) assert not F.submodule([1 + x, 0, 0]) == F.submodule([1, 0, 0]) assert F.submodule([1, 0, 0], [0, 1, 0]).union(F.submodule([0, 0, 1])) == F assert not M.is_submodule(0) m = F.convert([x**2 + y**2, 1, 0]) n = M.convert(m) assert m.module is F assert n.module is M raises(ValueError, lambda: M.submodule([1, 0, 0])) raises(TypeError, lambda: M.union(1)) raises(ValueError, lambda: M.union(R.free_module(1).submodule([x]))) assert F.submodule([x, x, x]) != F.submodule([x, x, x], order="ilex") def test_SubModulePolyRing_local(): R = QQ.old_poly_ring(x, y, order=ilex) F = R.free_module(3) Fd = F.submodule([1 + x, 0, 0], [1 + y, 2 + 2*y, 0], [1, 2, 3]) M = F.submodule([x**2 + y**2, 1, 0], [x, y, 1]) assert F == Fd assert Fd == F assert F != M assert M != F assert Fd != M assert M != Fd assert Fd == F.submodule(*F.basis()) assert Fd.is_full_module() assert not M.is_full_module() assert not Fd.is_zero() assert not M.is_zero() assert Fd.submodule().is_zero() assert M.contains([x**2 + y**2 + x, 1 + y, 1]) assert not M.contains([x**2 + y**2 + x, 1 + y, 2]) assert M.contains([y**2, 1 - x*y, -x]) assert F.submodule([1 + x, 0, 0]) == F.submodule([1, 0, 0]) assert F.submodule( [1, 0, 0], [0, 1, 0]).union(F.submodule([0, 0, 1 + x*y])) == F raises(ValueError, lambda: M.submodule([1, 0, 0])) def test_SubModulePolyRing_nontriv_global(): R = QQ.old_poly_ring(x, y, z) F = R.free_module(1) def contains(I, f): return F.submodule(*[[g] for g in I]).contains([f]) assert contains([x, y], x) assert contains([x, y], x + y) assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**3) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y**2) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4 + y**3 + 2*z*y*x) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y*z) assert contains([x, 1 + x + y, 5 - 7*y], 1) assert contains( [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], x**3) assert not contains( [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], x**2 + y**2) # compare local order assert not contains([x*(1 + x + y), y*(1 + z)], x) assert not contains([x*(1 + x + y), y*(1 + z)], x + y) def test_SubModulePolyRing_nontriv_local(): R = QQ.old_poly_ring(x, y, z, order=ilex) F = R.free_module(1) def contains(I, f): return F.submodule(*[[g] for g in I]).contains([f]) assert contains([x, y], x) assert contains([x, y], x + y) assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) assert contains([x*(1 + x + y), y*(1 + z)], x) assert contains([x*(1 + x + y), y*(1 + z)], x + y) def test_syzygy(): R = QQ.old_poly_ring(x, y, z) M = R.free_module(1).submodule([x*y], [y*z], [x*z]) S = R.free_module(3).submodule([0, x, -y], [z, -x, 0]) assert M.syzygy_module() == S M2 = M / ([x*y*z],) S2 = R.free_module(3).submodule([z, 0, 0], [0, x, 0], [0, 0, y]) assert M2.syzygy_module() == S2 F = R.free_module(3) assert F.submodule(*F.basis()).syzygy_module() == F.submodule() R2 = QQ.old_poly_ring(x, y, z) / [x*y*z] M3 = R2.free_module(1).submodule([x*y], [y*z], [x*z]) S3 = R2.free_module(3).submodule([z, 0, 0], [0, x, 0], [0, 0, y]) assert M3.syzygy_module() == S3 def test_in_terms_of_generators(): R = QQ.old_poly_ring(x, order="ilex") M = R.free_module(2).submodule([2*x, 0], [1, 2]) assert M.in_terms_of_generators( [x, x]) == [R.convert(Rational(1, 4)), R.convert(x/2)] raises(ValueError, lambda: M.in_terms_of_generators([1, 0])) M = R.free_module(2) / ([x, 0], [1, 1]) SM = M.submodule([1, x]) assert SM.in_terms_of_generators([2, 0]) == [R.convert(-2/(x - 1))] R = QQ.old_poly_ring(x, y) / [x**2 - y**2] M = R.free_module(2) SM = M.submodule([x, 0], [0, y]) assert SM.in_terms_of_generators( [x**2, x**2]) == [R.convert(x), R.convert(y)] def test_QuotientModuleElement(): R = QQ.old_poly_ring(x) F = R.free_module(3) N = F.submodule([1, x, x**2]) M = F/N e = M.convert([x**2, 2, 0]) assert M.convert([x + 1, x**2 + x, x**3 + x**2]) == 0 assert e == [x**2, 2, 0] + N == F.convert([x**2, 2, 0]) + N == \ M.convert(F.convert([x**2, 2, 0])) assert M.convert([x**2 + 1, 2*x + 2, x**2]) == e + [0, x, 0] == \ e + M.convert([0, x, 0]) == e + F.convert([0, x, 0]) assert M.convert([x**2 + 1, 2, x**2]) == e - [0, x, 0] == \ e - M.convert([0, x, 0]) == e - F.convert([0, x, 0]) assert M.convert([0, 2, 0]) == M.convert([x**2, 4, 0]) - e == \ [x**2, 4, 0] - e == F.convert([x**2, 4, 0]) - e assert M.convert([x**3 + x**2, 2*x + 2, 0]) == (1 + x)*e == \ R.convert(1 + x)*e == e*(1 + x) == e*R.convert(1 + x) assert -e == [-x**2, -2, 0] f = [x, x, 0] + N assert M.convert([1, 1, 0]) == f / x == f / R.convert(x) M2 = F/[(2, 2*x, 2*x**2), (0, 0, 1)] G = R.free_module(2) M3 = G/[[1, x]] M4 = F.submodule([1, x, x**2], [1, 0, 0]) / N raises(CoercionFailed, lambda: M.convert(G.convert([1, x]))) raises(CoercionFailed, lambda: M.convert(M3.convert([1, x]))) raises(CoercionFailed, lambda: M.convert(M2.convert([1, x, x]))) assert M2.convert(M.convert([2, x, x**2])) == [2, x, 0] assert M.convert(M4.convert([2, 0, 0])) == [2, 0, 0] def test_QuotientModule(): R = QQ.old_poly_ring(x) F = R.free_module(3) N = F.submodule([1, x, x**2]) M = F/N assert M != F assert M != N assert M == F / [(1, x, x**2)] assert not M.is_zero() assert (F / F.basis()).is_zero() SQ = F.submodule([1, x, x**2], [2, 0, 0]) / N assert SQ == M.submodule([2, x, x**2]) assert SQ != M.submodule([2, 1, 0]) assert SQ != M assert M.is_submodule(SQ) assert not SQ.is_full_module() raises(ValueError, lambda: N/F) raises(ValueError, lambda: F.submodule([2, 0, 0]) / N) raises(ValueError, lambda: R.free_module(2)/F) raises(CoercionFailed, lambda: F.convert(M.convert([1, x, x**2]))) M1 = F / [[1, 1, 1]] M2 = M1.submodule([1, 0, 0], [0, 1, 0]) assert M1 == M2 def test_ModulesQuotientRing(): R = QQ.old_poly_ring(x, y, order=(("lex", x), ("ilex", y))) / [x**2 + 1] M1 = R.free_module(2) assert M1 == R.free_module(2) assert M1 != QQ.old_poly_ring(x).free_module(2) assert M1 != R.free_module(3) assert [x, 1] in M1 assert [x] not in M1 assert [1/(R.convert(x) + 1), 2] in M1 assert [1, 2/(1 + y)] in M1 assert [1, 2/y] not in M1 assert M1.convert([x**2, y]) == [-1, y] F = R.free_module(3) Fd = F.submodule([x**2, 0, 0], [1, 2, 0], [1, 2, 3]) M = F.submodule([x**2 + y**2, 1, 0], [x, y, 1]) assert F == Fd assert Fd == F assert F != M assert M != F assert Fd != M assert M != Fd assert Fd == F.submodule(*F.basis()) assert Fd.is_full_module() assert not M.is_full_module() assert not Fd.is_zero() assert not M.is_zero() assert Fd.submodule().is_zero() assert M.contains([x**2 + y**2 + x, -x**2 + y, 1]) assert not M.contains([x**2 + y**2 + x, 1 + y, 2]) assert M.contains([y**2, 1 - x*y, -x]) assert F.submodule([x, 0, 0]) == F.submodule([1, 0, 0]) assert not F.submodule([y, 0, 0]) == F.submodule([1, 0, 0]) assert F.submodule([1, 0, 0], [0, 1, 0]).union(F.submodule([0, 0, 1])) == F assert not M.is_submodule(0) def test_module_mul(): R = QQ.old_poly_ring(x) M = R.free_module(2) S1 = M.submodule([x, 0], [0, x]) S2 = M.submodule([x**2, 0], [0, x**2]) I = R.ideal(x) assert I*M == M*I == S1 == x*M == M*x assert I*S1 == S2 == x*S1 def test_intersection(): # SCA, example 2.8.5 F = QQ.old_poly_ring(x, y).free_module(2) M1 = F.submodule([x, y], [y, 1]) M2 = F.submodule([0, y - 1], [x, 1], [y, x]) I = F.submodule([x, y], [y**2 - y, y - 1], [x*y + y, x + 1]) I1, rel1, rel2 = M1.intersect(M2, relations=True) assert I1 == M2.intersect(M1) == I for i, g in enumerate(I1.gens): assert g == sum(c*x for c, x in zip(rel1[i], M1.gens)) \ == sum(d*y for d, y in zip(rel2[i], M2.gens)) assert F.submodule([x, y]).intersect(F.submodule([y, x])).is_zero() def test_quotient(): # SCA, example 2.8.6 R = QQ.old_poly_ring(x, y, z) F = R.free_module(2) assert F.submodule([x*y, x*z], [y*z, x*y]).module_quotient( F.submodule([y, z], [z, y])) == QQ.old_poly_ring(x, y, z).ideal(x**2*y**2 - x*y*z**2) assert F.submodule([x, y]).module_quotient(F.submodule()).is_whole_ring() M = F.submodule([x**2, x**2], [y**2, y**2]) N = F.submodule([x + y, x + y]) q, rel = M.module_quotient(N, relations=True) assert q == R.ideal(y**2, x - y) for i, g in enumerate(q.gens): assert g*N.gens[0] == sum(c*x for c, x in zip(rel[i], M.gens)) def test_groebner_extendend(): M = QQ.old_poly_ring(x, y, z).free_module(3).submodule([x + 1, y, 1], [x*y, z, z**2]) G, R = M._groebner_vec(extended=True) for i, g in enumerate(G): assert g == sum(c*gen for c, gen in zip(R[i], M.gens)) sympy-sympy-1.9/sympy/polys/benchmarks/000077500000000000000000000000001412543434000203675ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/benchmarks/__init__.py000066400000000000000000000000001412543434000224660ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/benchmarks/bench_galoispolys.py000066400000000000000000000026571412543434000244570ustar00rootroot00000000000000"""Benchmarks for polynomials over Galois fields. """ from sympy.polys.galoistools import gf_from_dict, gf_factor_sqf from sympy.polys.domains import ZZ from sympy import pi, nextprime def gathen_poly(n, p, K): return gf_from_dict({n: K.one, 1: K.one, 0: K.one}, p, K) def shoup_poly(n, p, K): f = [K.one] * (n + 1) for i in range(1, n + 1): f[i] = (f[i - 1]**2 + K.one) % p return f def genprime(n, K): return K(nextprime(int((2**n * pi).evalf()))) p_10 = genprime(10, ZZ) f_10 = gathen_poly(10, p_10, ZZ) p_20 = genprime(20, ZZ) f_20 = gathen_poly(20, p_20, ZZ) def timeit_gathen_poly_f10_zassenhaus(): gf_factor_sqf(f_10, p_10, ZZ, method='zassenhaus') def timeit_gathen_poly_f10_shoup(): gf_factor_sqf(f_10, p_10, ZZ, method='shoup') def timeit_gathen_poly_f20_zassenhaus(): gf_factor_sqf(f_20, p_20, ZZ, method='zassenhaus') def timeit_gathen_poly_f20_shoup(): gf_factor_sqf(f_20, p_20, ZZ, method='shoup') P_08 = genprime(8, ZZ) F_10 = shoup_poly(10, P_08, ZZ) P_18 = genprime(18, ZZ) F_20 = shoup_poly(20, P_18, ZZ) def timeit_shoup_poly_F10_zassenhaus(): gf_factor_sqf(F_10, P_08, ZZ, method='zassenhaus') def timeit_shoup_poly_F10_shoup(): gf_factor_sqf(F_10, P_08, ZZ, method='shoup') def timeit_shoup_poly_F20_zassenhaus(): gf_factor_sqf(F_20, P_18, ZZ, method='zassenhaus') def timeit_shoup_poly_F20_shoup(): gf_factor_sqf(F_20, P_18, ZZ, method='shoup') sympy-sympy-1.9/sympy/polys/benchmarks/bench_groebnertools.py000066400000000000000000000014431412543434000247660ustar00rootroot00000000000000"""Benchmark of the Groebner bases algorithms. """ from sympy.polys.rings import ring from sympy.polys.domains import QQ from sympy.polys.groebnertools import groebner R, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12 = ring("x1:13", QQ) V = R.gens E = [(x1, x2), (x2, x3), (x1, x4), (x1, x6), (x1, x12), (x2, x5), (x2, x7), (x3, x8), (x3, x10), (x4, x11), (x4, x9), (x5, x6), (x6, x7), (x7, x8), (x8, x9), (x9, x10), (x10, x11), (x11, x12), (x5, x12), (x5, x9), (x6, x10), (x7, x11), (x8, x12)] F3 = [ x**3 - 1 for x in V ] Fg = [ x**2 + x*y + y**2 for x, y in E ] F_1 = F3 + Fg F_2 = F3 + Fg + [x3**2 + x3*x4 + x4**2] def time_vertex_color_12_vertices_23_edges(): assert groebner(F_1, R) != [1] def time_vertex_color_12_vertices_24_edges(): assert groebner(F_2, R) == [1] sympy-sympy-1.9/sympy/polys/benchmarks/bench_solvers.py000066400000000000000000015505061412543434000236110ustar00rootroot00000000000000from sympy.polys.rings import ring from sympy.polys.fields import field from sympy.polys.domains import ZZ, QQ from sympy.polys.solvers import solve_lin_sys # Expected times on 3.4 GHz i7: # In [1]: %timeit time_solve_lin_sys_189x49() # 1 loops, best of 3: 864 ms per loop # In [2]: %timeit time_solve_lin_sys_165x165() # 1 loops, best of 3: 1.83 s per loop # In [3]: %timeit time_solve_lin_sys_10x8() # 1 loops, best of 3: 2.31 s per loop # Benchmark R_165: shows how fast are arithmetics in QQ. R_165, uk_0, uk_1, uk_2, uk_3, uk_4, uk_5, uk_6, uk_7, uk_8, uk_9, uk_10, uk_11, uk_12, uk_13, uk_14, uk_15, uk_16, uk_17, uk_18, uk_19, uk_20, uk_21, uk_22, uk_23, uk_24, uk_25, uk_26, uk_27, uk_28, uk_29, uk_30, uk_31, uk_32, uk_33, uk_34, uk_35, uk_36, uk_37, uk_38, uk_39, uk_40, uk_41, uk_42, uk_43, uk_44, uk_45, uk_46, uk_47, uk_48, uk_49, uk_50, uk_51, uk_52, uk_53, uk_54, uk_55, uk_56, uk_57, uk_58, uk_59, uk_60, uk_61, uk_62, uk_63, uk_64, uk_65, uk_66, uk_67, uk_68, uk_69, uk_70, uk_71, uk_72, uk_73, uk_74, uk_75, uk_76, uk_77, uk_78, uk_79, uk_80, uk_81, uk_82, uk_83, uk_84, uk_85, uk_86, uk_87, uk_88, uk_89, uk_90, uk_91, uk_92, uk_93, uk_94, uk_95, uk_96, uk_97, uk_98, uk_99, uk_100, uk_101, uk_102, uk_103, uk_104, uk_105, uk_106, uk_107, uk_108, uk_109, uk_110, uk_111, uk_112, uk_113, uk_114, uk_115, uk_116, uk_117, uk_118, uk_119, uk_120, uk_121, uk_122, uk_123, uk_124, uk_125, uk_126, uk_127, uk_128, uk_129, uk_130, uk_131, uk_132, uk_133, uk_134, uk_135, uk_136, uk_137, uk_138, uk_139, uk_140, uk_141, uk_142, uk_143, uk_144, uk_145, uk_146, uk_147, uk_148, uk_149, uk_150, uk_151, uk_152, uk_153, uk_154, uk_155, uk_156, uk_157, uk_158, uk_159, uk_160, uk_161, uk_162, uk_163, uk_164 = ring("uk_:165", QQ) def eqs_165x165(): return [ uk_0 + 50719*uk_1 + 2789545*uk_10 + 411400*uk_100 + 1683000*uk_101 + 166375*uk_103 + 680625*uk_104 + 2784375*uk_106 + 729*uk_109 + 456471*uk_11 + 4131*uk_110 + 11016*uk_111 + 4455*uk_112 + 18225*uk_113 + 23409*uk_115 + 62424*uk_116 + 25245*uk_117 + 103275*uk_118 + 2586669*uk_12 + 166464*uk_120 + 67320*uk_121 + 275400*uk_122 + 27225*uk_124 + 111375*uk_125 + 455625*uk_127 + 6897784*uk_13 + 132651*uk_130 + 353736*uk_131 + 143055*uk_132 + 585225*uk_133 + 943296*uk_135 + 381480*uk_136 + 1560600*uk_137 + 154275*uk_139 + 2789545*uk_14 + 631125*uk_140 + 2581875*uk_142 + 2515456*uk_145 + 1017280*uk_146 + 4161600*uk_147 + 411400*uk_149 + 11411775*uk_15 + 1683000*uk_150 + 6885000*uk_152 + 166375*uk_155 + 680625*uk_156 + 2784375*uk_158 + 11390625*uk_161 + 3025*uk_17 + 495*uk_18 + 2805*uk_19 + 55*uk_2 + 7480*uk_20 + 3025*uk_21 + 12375*uk_22 + 81*uk_24 + 459*uk_25 + 1224*uk_26 + 495*uk_27 + 2025*uk_28 + 9*uk_3 + 2601*uk_30 + 6936*uk_31 + 2805*uk_32 + 11475*uk_33 + 18496*uk_35 + 7480*uk_36 + 30600*uk_37 + 3025*uk_39 + 51*uk_4 + 12375*uk_40 + 50625*uk_42 + 130470415844959*uk_45 + 141482932855*uk_46 + 23151752649*uk_47 + 131193265011*uk_48 + 349848706696*uk_49 + 136*uk_5 + 141482932855*uk_50 + 578793816225*uk_51 + 153424975*uk_53 + 25105905*uk_54 + 142266795*uk_55 + 379378120*uk_56 + 153424975*uk_57 + 627647625*uk_58 + 55*uk_6 + 4108239*uk_60 + 23280021*uk_61 + 62080056*uk_62 + 25105905*uk_63 + 102705975*uk_64 + 131920119*uk_66 + 351786984*uk_67 + 142266795*uk_68 + 582000525*uk_69 + 225*uk_7 + 938098624*uk_71 + 379378120*uk_72 + 1552001400*uk_73 + 153424975*uk_75 + 627647625*uk_76 + 2567649375*uk_78 + 166375*uk_81 + 27225*uk_82 + 154275*uk_83 + 411400*uk_84 + 166375*uk_85 + 680625*uk_86 + 4455*uk_88 + 25245*uk_89 + 2572416961*uk_9 + 67320*uk_90 + 27225*uk_91 + 111375*uk_92 + 143055*uk_94 + 381480*uk_95 + 154275*uk_96 + 631125*uk_97 + 1017280*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 413820*uk_100 + 1633500*uk_101 + 65340*uk_102 + 178695*uk_103 + 705375*uk_104 + 28215*uk_105 + 2784375*uk_106 + 111375*uk_107 + 4455*uk_108 + 97336*uk_109 + 2333074*uk_11 + 19044*uk_110 + 279312*uk_111 + 120612*uk_112 + 476100*uk_113 + 19044*uk_114 + 3726*uk_115 + 54648*uk_116 + 23598*uk_117 + 93150*uk_118 + 3726*uk_119 + 456471*uk_12 + 801504*uk_120 + 346104*uk_121 + 1366200*uk_122 + 54648*uk_123 + 149454*uk_124 + 589950*uk_125 + 23598*uk_126 + 2328750*uk_127 + 93150*uk_128 + 3726*uk_129 + 6694908*uk_13 + 729*uk_130 + 10692*uk_131 + 4617*uk_132 + 18225*uk_133 + 729*uk_134 + 156816*uk_135 + 67716*uk_136 + 267300*uk_137 + 10692*uk_138 + 29241*uk_139 + 2890983*uk_14 + 115425*uk_140 + 4617*uk_141 + 455625*uk_142 + 18225*uk_143 + 729*uk_144 + 2299968*uk_145 + 993168*uk_146 + 3920400*uk_147 + 156816*uk_148 + 428868*uk_149 + 11411775*uk_15 + 1692900*uk_150 + 67716*uk_151 + 6682500*uk_152 + 267300*uk_153 + 10692*uk_154 + 185193*uk_155 + 731025*uk_156 + 29241*uk_157 + 2885625*uk_158 + 115425*uk_159 + 456471*uk_16 + 4617*uk_160 + 11390625*uk_161 + 455625*uk_162 + 18225*uk_163 + 729*uk_164 + 3025*uk_17 + 2530*uk_18 + 495*uk_19 + 55*uk_2 + 7260*uk_20 + 3135*uk_21 + 12375*uk_22 + 495*uk_23 + 2116*uk_24 + 414*uk_25 + 6072*uk_26 + 2622*uk_27 + 10350*uk_28 + 414*uk_29 + 46*uk_3 + 81*uk_30 + 1188*uk_31 + 513*uk_32 + 2025*uk_33 + 81*uk_34 + 17424*uk_35 + 7524*uk_36 + 29700*uk_37 + 1188*uk_38 + 3249*uk_39 + 9*uk_4 + 12825*uk_40 + 513*uk_41 + 50625*uk_42 + 2025*uk_43 + 81*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 118331180206*uk_47 + 23151752649*uk_48 + 339559038852*uk_49 + 132*uk_5 + 146627766777*uk_50 + 578793816225*uk_51 + 23151752649*uk_52 + 153424975*uk_53 + 128319070*uk_54 + 25105905*uk_55 + 368219940*uk_56 + 159004065*uk_57 + 627647625*uk_58 + 25105905*uk_59 + 57*uk_6 + 107321404*uk_60 + 20997666*uk_61 + 307965768*uk_62 + 132985218*uk_63 + 524941650*uk_64 + 20997666*uk_65 + 4108239*uk_66 + 60254172*uk_67 + 26018847*uk_68 + 102705975*uk_69 + 225*uk_7 + 4108239*uk_70 + 883727856*uk_71 + 381609756*uk_72 + 1506354300*uk_73 + 60254172*uk_74 + 164786031*uk_75 + 650471175*uk_76 + 26018847*uk_77 + 2567649375*uk_78 + 102705975*uk_79 + 9*uk_8 + 4108239*uk_80 + 166375*uk_81 + 139150*uk_82 + 27225*uk_83 + 399300*uk_84 + 172425*uk_85 + 680625*uk_86 + 27225*uk_87 + 116380*uk_88 + 22770*uk_89 + 2572416961*uk_9 + 333960*uk_90 + 144210*uk_91 + 569250*uk_92 + 22770*uk_93 + 4455*uk_94 + 65340*uk_95 + 28215*uk_96 + 111375*uk_97 + 4455*uk_98 + 958320*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 402380*uk_100 + 1534500*uk_101 + 313720*uk_102 + 191455*uk_103 + 730125*uk_104 + 149270*uk_105 + 2784375*uk_106 + 569250*uk_107 + 116380*uk_108 + 912673*uk_109 + 4919743*uk_11 + 432814*uk_110 + 1166716*uk_111 + 555131*uk_112 + 2117025*uk_113 + 432814*uk_114 + 205252*uk_115 + 553288*uk_116 + 263258*uk_117 + 1003950*uk_118 + 205252*uk_119 + 2333074*uk_12 + 1491472*uk_120 + 709652*uk_121 + 2706300*uk_122 + 553288*uk_123 + 337657*uk_124 + 1287675*uk_125 + 263258*uk_126 + 4910625*uk_127 + 1003950*uk_128 + 205252*uk_129 + 6289156*uk_13 + 97336*uk_130 + 262384*uk_131 + 124844*uk_132 + 476100*uk_133 + 97336*uk_134 + 707296*uk_135 + 336536*uk_136 + 1283400*uk_137 + 262384*uk_138 + 160126*uk_139 + 2992421*uk_14 + 610650*uk_140 + 124844*uk_141 + 2328750*uk_142 + 476100*uk_143 + 97336*uk_144 + 1906624*uk_145 + 907184*uk_146 + 3459600*uk_147 + 707296*uk_148 + 431644*uk_149 + 11411775*uk_15 + 1646100*uk_150 + 336536*uk_151 + 6277500*uk_152 + 1283400*uk_153 + 262384*uk_154 + 205379*uk_155 + 783225*uk_156 + 160126*uk_157 + 2986875*uk_158 + 610650*uk_159 + 2333074*uk_16 + 124844*uk_160 + 11390625*uk_161 + 2328750*uk_162 + 476100*uk_163 + 97336*uk_164 + 3025*uk_17 + 5335*uk_18 + 2530*uk_19 + 55*uk_2 + 6820*uk_20 + 3245*uk_21 + 12375*uk_22 + 2530*uk_23 + 9409*uk_24 + 4462*uk_25 + 12028*uk_26 + 5723*uk_27 + 21825*uk_28 + 4462*uk_29 + 97*uk_3 + 2116*uk_30 + 5704*uk_31 + 2714*uk_32 + 10350*uk_33 + 2116*uk_34 + 15376*uk_35 + 7316*uk_36 + 27900*uk_37 + 5704*uk_38 + 3481*uk_39 + 46*uk_4 + 13275*uk_40 + 2714*uk_41 + 50625*uk_42 + 10350*uk_43 + 2116*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 249524445217*uk_47 + 118331180206*uk_48 + 318979703164*uk_49 + 124*uk_5 + 151772600699*uk_50 + 578793816225*uk_51 + 118331180206*uk_52 + 153424975*uk_53 + 270585865*uk_54 + 128319070*uk_55 + 345903580*uk_56 + 164583155*uk_57 + 627647625*uk_58 + 128319070*uk_59 + 59*uk_6 + 477215071*uk_60 + 226308178*uk_61 + 610048132*uk_62 + 290264837*uk_63 + 1106942175*uk_64 + 226308178*uk_65 + 107321404*uk_66 + 289301176*uk_67 + 137651366*uk_68 + 524941650*uk_69 + 225*uk_7 + 107321404*uk_70 + 779855344*uk_71 + 371060204*uk_72 + 1415060100*uk_73 + 289301176*uk_74 + 176552839*uk_75 + 673294725*uk_76 + 137651366*uk_77 + 2567649375*uk_78 + 524941650*uk_79 + 46*uk_8 + 107321404*uk_80 + 166375*uk_81 + 293425*uk_82 + 139150*uk_83 + 375100*uk_84 + 178475*uk_85 + 680625*uk_86 + 139150*uk_87 + 517495*uk_88 + 245410*uk_89 + 2572416961*uk_9 + 661540*uk_90 + 314765*uk_91 + 1200375*uk_92 + 245410*uk_93 + 116380*uk_94 + 313720*uk_95 + 149270*uk_96 + 569250*uk_97 + 116380*uk_98 + 845680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 389180*uk_100 + 1435500*uk_101 + 618860*uk_102 + 204655*uk_103 + 754875*uk_104 + 325435*uk_105 + 2784375*uk_106 + 1200375*uk_107 + 517495*uk_108 + 3375000*uk_109 + 7607850*uk_11 + 2182500*uk_110 + 2610000*uk_111 + 1372500*uk_112 + 5062500*uk_113 + 2182500*uk_114 + 1411350*uk_115 + 1687800*uk_116 + 887550*uk_117 + 3273750*uk_118 + 1411350*uk_119 + 4919743*uk_12 + 2018400*uk_120 + 1061400*uk_121 + 3915000*uk_122 + 1687800*uk_123 + 558150*uk_124 + 2058750*uk_125 + 887550*uk_126 + 7593750*uk_127 + 3273750*uk_128 + 1411350*uk_129 + 5883404*uk_13 + 912673*uk_130 + 1091444*uk_131 + 573949*uk_132 + 2117025*uk_133 + 912673*uk_134 + 1305232*uk_135 + 686372*uk_136 + 2531700*uk_137 + 1091444*uk_138 + 360937*uk_139 + 3093859*uk_14 + 1331325*uk_140 + 573949*uk_141 + 4910625*uk_142 + 2117025*uk_143 + 912673*uk_144 + 1560896*uk_145 + 820816*uk_146 + 3027600*uk_147 + 1305232*uk_148 + 431636*uk_149 + 11411775*uk_15 + 1592100*uk_150 + 686372*uk_151 + 5872500*uk_152 + 2531700*uk_153 + 1091444*uk_154 + 226981*uk_155 + 837225*uk_156 + 360937*uk_157 + 3088125*uk_158 + 1331325*uk_159 + 4919743*uk_16 + 573949*uk_160 + 11390625*uk_161 + 4910625*uk_162 + 2117025*uk_163 + 912673*uk_164 + 3025*uk_17 + 8250*uk_18 + 5335*uk_19 + 55*uk_2 + 6380*uk_20 + 3355*uk_21 + 12375*uk_22 + 5335*uk_23 + 22500*uk_24 + 14550*uk_25 + 17400*uk_26 + 9150*uk_27 + 33750*uk_28 + 14550*uk_29 + 150*uk_3 + 9409*uk_30 + 11252*uk_31 + 5917*uk_32 + 21825*uk_33 + 9409*uk_34 + 13456*uk_35 + 7076*uk_36 + 26100*uk_37 + 11252*uk_38 + 3721*uk_39 + 97*uk_4 + 13725*uk_40 + 5917*uk_41 + 50625*uk_42 + 21825*uk_43 + 9409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 385862544150*uk_47 + 249524445217*uk_48 + 298400367476*uk_49 + 116*uk_5 + 156917434621*uk_50 + 578793816225*uk_51 + 249524445217*uk_52 + 153424975*uk_53 + 418431750*uk_54 + 270585865*uk_55 + 323587220*uk_56 + 170162245*uk_57 + 627647625*uk_58 + 270585865*uk_59 + 61*uk_6 + 1141177500*uk_60 + 737961450*uk_61 + 882510600*uk_62 + 464078850*uk_63 + 1711766250*uk_64 + 737961450*uk_65 + 477215071*uk_66 + 570690188*uk_67 + 300104323*uk_68 + 1106942175*uk_69 + 225*uk_7 + 477215071*uk_70 + 682474864*uk_71 + 358887644*uk_72 + 1323765900*uk_73 + 570690188*uk_74 + 188725399*uk_75 + 696118275*uk_76 + 300104323*uk_77 + 2567649375*uk_78 + 1106942175*uk_79 + 97*uk_8 + 477215071*uk_80 + 166375*uk_81 + 453750*uk_82 + 293425*uk_83 + 350900*uk_84 + 184525*uk_85 + 680625*uk_86 + 293425*uk_87 + 1237500*uk_88 + 800250*uk_89 + 2572416961*uk_9 + 957000*uk_90 + 503250*uk_91 + 1856250*uk_92 + 800250*uk_93 + 517495*uk_94 + 618860*uk_95 + 325435*uk_96 + 1200375*uk_97 + 517495*uk_98 + 740080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 374220*uk_100 + 1336500*uk_101 + 891000*uk_102 + 218295*uk_103 + 779625*uk_104 + 519750*uk_105 + 2784375*uk_106 + 1856250*uk_107 + 1237500*uk_108 + 7189057*uk_109 + 9788767*uk_11 + 5587350*uk_110 + 4022892*uk_111 + 2346687*uk_112 + 8381025*uk_113 + 5587350*uk_114 + 4342500*uk_115 + 3126600*uk_116 + 1823850*uk_117 + 6513750*uk_118 + 4342500*uk_119 + 7607850*uk_12 + 2251152*uk_120 + 1313172*uk_121 + 4689900*uk_122 + 3126600*uk_123 + 766017*uk_124 + 2735775*uk_125 + 1823850*uk_126 + 9770625*uk_127 + 6513750*uk_128 + 4342500*uk_129 + 5477652*uk_13 + 3375000*uk_130 + 2430000*uk_131 + 1417500*uk_132 + 5062500*uk_133 + 3375000*uk_134 + 1749600*uk_135 + 1020600*uk_136 + 3645000*uk_137 + 2430000*uk_138 + 595350*uk_139 + 3195297*uk_14 + 2126250*uk_140 + 1417500*uk_141 + 7593750*uk_142 + 5062500*uk_143 + 3375000*uk_144 + 1259712*uk_145 + 734832*uk_146 + 2624400*uk_147 + 1749600*uk_148 + 428652*uk_149 + 11411775*uk_15 + 1530900*uk_150 + 1020600*uk_151 + 5467500*uk_152 + 3645000*uk_153 + 2430000*uk_154 + 250047*uk_155 + 893025*uk_156 + 595350*uk_157 + 3189375*uk_158 + 2126250*uk_159 + 7607850*uk_16 + 1417500*uk_160 + 11390625*uk_161 + 7593750*uk_162 + 5062500*uk_163 + 3375000*uk_164 + 3025*uk_17 + 10615*uk_18 + 8250*uk_19 + 55*uk_2 + 5940*uk_20 + 3465*uk_21 + 12375*uk_22 + 8250*uk_23 + 37249*uk_24 + 28950*uk_25 + 20844*uk_26 + 12159*uk_27 + 43425*uk_28 + 28950*uk_29 + 193*uk_3 + 22500*uk_30 + 16200*uk_31 + 9450*uk_32 + 33750*uk_33 + 22500*uk_34 + 11664*uk_35 + 6804*uk_36 + 24300*uk_37 + 16200*uk_38 + 3969*uk_39 + 150*uk_4 + 14175*uk_40 + 9450*uk_41 + 50625*uk_42 + 33750*uk_43 + 22500*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 496476473473*uk_47 + 385862544150*uk_48 + 277821031788*uk_49 + 108*uk_5 + 162062268543*uk_50 + 578793816225*uk_51 + 385862544150*uk_52 + 153424975*uk_53 + 538382185*uk_54 + 418431750*uk_55 + 301270860*uk_56 + 175741335*uk_57 + 627647625*uk_58 + 418431750*uk_59 + 63*uk_6 + 1889232031*uk_60 + 1468315050*uk_61 + 1057186836*uk_62 + 616692321*uk_63 + 2202472575*uk_64 + 1468315050*uk_65 + 1141177500*uk_66 + 821647800*uk_67 + 479294550*uk_68 + 1711766250*uk_69 + 225*uk_7 + 1141177500*uk_70 + 591586416*uk_71 + 345092076*uk_72 + 1232471700*uk_73 + 821647800*uk_74 + 201303711*uk_75 + 718941825*uk_76 + 479294550*uk_77 + 2567649375*uk_78 + 1711766250*uk_79 + 150*uk_8 + 1141177500*uk_80 + 166375*uk_81 + 583825*uk_82 + 453750*uk_83 + 326700*uk_84 + 190575*uk_85 + 680625*uk_86 + 453750*uk_87 + 2048695*uk_88 + 1592250*uk_89 + 2572416961*uk_9 + 1146420*uk_90 + 668745*uk_91 + 2388375*uk_92 + 1592250*uk_93 + 1237500*uk_94 + 891000*uk_95 + 519750*uk_96 + 1856250*uk_97 + 1237500*uk_98 + 641520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 357500*uk_100 + 1237500*uk_101 + 1061500*uk_102 + 232375*uk_103 + 804375*uk_104 + 689975*uk_105 + 2784375*uk_106 + 2388375*uk_107 + 2048695*uk_108 + 9800344*uk_109 + 10853866*uk_11 + 8838628*uk_110 + 4579600*uk_111 + 2976740*uk_112 + 10304100*uk_113 + 8838628*uk_114 + 7971286*uk_115 + 4130200*uk_116 + 2684630*uk_117 + 9292950*uk_118 + 7971286*uk_119 + 9788767*uk_12 + 2140000*uk_120 + 1391000*uk_121 + 4815000*uk_122 + 4130200*uk_123 + 904150*uk_124 + 3129750*uk_125 + 2684630*uk_126 + 10833750*uk_127 + 9292950*uk_128 + 7971286*uk_129 + 5071900*uk_13 + 7189057*uk_130 + 3724900*uk_131 + 2421185*uk_132 + 8381025*uk_133 + 7189057*uk_134 + 1930000*uk_135 + 1254500*uk_136 + 4342500*uk_137 + 3724900*uk_138 + 815425*uk_139 + 3296735*uk_14 + 2822625*uk_140 + 2421185*uk_141 + 9770625*uk_142 + 8381025*uk_143 + 7189057*uk_144 + 1000000*uk_145 + 650000*uk_146 + 2250000*uk_147 + 1930000*uk_148 + 422500*uk_149 + 11411775*uk_15 + 1462500*uk_150 + 1254500*uk_151 + 5062500*uk_152 + 4342500*uk_153 + 3724900*uk_154 + 274625*uk_155 + 950625*uk_156 + 815425*uk_157 + 3290625*uk_158 + 2822625*uk_159 + 9788767*uk_16 + 2421185*uk_160 + 11390625*uk_161 + 9770625*uk_162 + 8381025*uk_163 + 7189057*uk_164 + 3025*uk_17 + 11770*uk_18 + 10615*uk_19 + 55*uk_2 + 5500*uk_20 + 3575*uk_21 + 12375*uk_22 + 10615*uk_23 + 45796*uk_24 + 41302*uk_25 + 21400*uk_26 + 13910*uk_27 + 48150*uk_28 + 41302*uk_29 + 214*uk_3 + 37249*uk_30 + 19300*uk_31 + 12545*uk_32 + 43425*uk_33 + 37249*uk_34 + 10000*uk_35 + 6500*uk_36 + 22500*uk_37 + 19300*uk_38 + 4225*uk_39 + 193*uk_4 + 14625*uk_40 + 12545*uk_41 + 50625*uk_42 + 43425*uk_43 + 37249*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 550497229654*uk_47 + 496476473473*uk_48 + 257241696100*uk_49 + 100*uk_5 + 167207102465*uk_50 + 578793816225*uk_51 + 496476473473*uk_52 + 153424975*uk_53 + 596962630*uk_54 + 538382185*uk_55 + 278954500*uk_56 + 181320425*uk_57 + 627647625*uk_58 + 538382185*uk_59 + 65*uk_6 + 2322727324*uk_60 + 2094796138*uk_61 + 1085386600*uk_62 + 705501290*uk_63 + 2442119850*uk_64 + 2094796138*uk_65 + 1889232031*uk_66 + 978876700*uk_67 + 636269855*uk_68 + 2202472575*uk_69 + 225*uk_7 + 1889232031*uk_70 + 507190000*uk_71 + 329673500*uk_72 + 1141177500*uk_73 + 978876700*uk_74 + 214287775*uk_75 + 741765375*uk_76 + 636269855*uk_77 + 2567649375*uk_78 + 2202472575*uk_79 + 193*uk_8 + 1889232031*uk_80 + 166375*uk_81 + 647350*uk_82 + 583825*uk_83 + 302500*uk_84 + 196625*uk_85 + 680625*uk_86 + 583825*uk_87 + 2518780*uk_88 + 2271610*uk_89 + 2572416961*uk_9 + 1177000*uk_90 + 765050*uk_91 + 2648250*uk_92 + 2271610*uk_93 + 2048695*uk_94 + 1061500*uk_95 + 689975*uk_96 + 2388375*uk_97 + 2048695*uk_98 + 550000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 339020*uk_100 + 1138500*uk_101 + 1082840*uk_102 + 246895*uk_103 + 829125*uk_104 + 788590*uk_105 + 2784375*uk_106 + 2648250*uk_107 + 2518780*uk_108 + 8120601*uk_109 + 10194519*uk_11 + 8645814*uk_110 + 3716892*uk_111 + 2706867*uk_112 + 9090225*uk_113 + 8645814*uk_114 + 9204996*uk_115 + 3957288*uk_116 + 2881938*uk_117 + 9678150*uk_118 + 9204996*uk_119 + 10853866*uk_12 + 1701264*uk_120 + 1238964*uk_121 + 4160700*uk_122 + 3957288*uk_123 + 902289*uk_124 + 3030075*uk_125 + 2881938*uk_126 + 10175625*uk_127 + 9678150*uk_128 + 9204996*uk_129 + 4666148*uk_13 + 9800344*uk_130 + 4213232*uk_131 + 3068332*uk_132 + 10304100*uk_133 + 9800344*uk_134 + 1811296*uk_135 + 1319096*uk_136 + 4429800*uk_137 + 4213232*uk_138 + 960646*uk_139 + 3398173*uk_14 + 3226050*uk_140 + 3068332*uk_141 + 10833750*uk_142 + 10304100*uk_143 + 9800344*uk_144 + 778688*uk_145 + 567088*uk_146 + 1904400*uk_147 + 1811296*uk_148 + 412988*uk_149 + 11411775*uk_15 + 1386900*uk_150 + 1319096*uk_151 + 4657500*uk_152 + 4429800*uk_153 + 4213232*uk_154 + 300763*uk_155 + 1010025*uk_156 + 960646*uk_157 + 3391875*uk_158 + 3226050*uk_159 + 10853866*uk_16 + 3068332*uk_160 + 11390625*uk_161 + 10833750*uk_162 + 10304100*uk_163 + 9800344*uk_164 + 3025*uk_17 + 11055*uk_18 + 11770*uk_19 + 55*uk_2 + 5060*uk_20 + 3685*uk_21 + 12375*uk_22 + 11770*uk_23 + 40401*uk_24 + 43014*uk_25 + 18492*uk_26 + 13467*uk_27 + 45225*uk_28 + 43014*uk_29 + 201*uk_3 + 45796*uk_30 + 19688*uk_31 + 14338*uk_32 + 48150*uk_33 + 45796*uk_34 + 8464*uk_35 + 6164*uk_36 + 20700*uk_37 + 19688*uk_38 + 4489*uk_39 + 214*uk_4 + 15075*uk_40 + 14338*uk_41 + 50625*uk_42 + 48150*uk_43 + 45796*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 517055809161*uk_47 + 550497229654*uk_48 + 236662360412*uk_49 + 92*uk_5 + 172351936387*uk_50 + 578793816225*uk_51 + 550497229654*uk_52 + 153424975*uk_53 + 560698545*uk_54 + 596962630*uk_55 + 256638140*uk_56 + 186899515*uk_57 + 627647625*uk_58 + 596962630*uk_59 + 67*uk_6 + 2049098319*uk_60 + 2181627066*uk_61 + 937895748*uk_62 + 683032773*uk_63 + 2293766775*uk_64 + 2181627066*uk_65 + 2322727324*uk_66 + 998555672*uk_67 + 727209022*uk_68 + 2442119850*uk_69 + 225*uk_7 + 2322727324*uk_70 + 429285616*uk_71 + 312631916*uk_72 + 1049883300*uk_73 + 998555672*uk_74 + 227677591*uk_75 + 764588925*uk_76 + 727209022*uk_77 + 2567649375*uk_78 + 2442119850*uk_79 + 214*uk_8 + 2322727324*uk_80 + 166375*uk_81 + 608025*uk_82 + 647350*uk_83 + 278300*uk_84 + 202675*uk_85 + 680625*uk_86 + 647350*uk_87 + 2222055*uk_88 + 2365770*uk_89 + 2572416961*uk_9 + 1017060*uk_90 + 740685*uk_91 + 2487375*uk_92 + 2365770*uk_93 + 2518780*uk_94 + 1082840*uk_95 + 788590*uk_96 + 2648250*uk_97 + 2518780*uk_98 + 465520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 318780*uk_100 + 1039500*uk_101 + 928620*uk_102 + 261855*uk_103 + 853875*uk_104 + 762795*uk_105 + 2784375*uk_106 + 2487375*uk_107 + 2222055*uk_108 + 2863288*uk_109 + 7202098*uk_11 + 4052964*uk_110 + 1693776*uk_111 + 1391316*uk_112 + 4536900*uk_113 + 4052964*uk_114 + 5736942*uk_115 + 2397528*uk_116 + 1969398*uk_117 + 6421950*uk_118 + 5736942*uk_119 + 10194519*uk_12 + 1001952*uk_120 + 823032*uk_121 + 2683800*uk_122 + 2397528*uk_123 + 676062*uk_124 + 2204550*uk_125 + 1969398*uk_126 + 7188750*uk_127 + 6421950*uk_128 + 5736942*uk_129 + 4260396*uk_13 + 8120601*uk_130 + 3393684*uk_131 + 2787669*uk_132 + 9090225*uk_133 + 8120601*uk_134 + 1418256*uk_135 + 1164996*uk_136 + 3798900*uk_137 + 3393684*uk_138 + 956961*uk_139 + 3499611*uk_14 + 3120525*uk_140 + 2787669*uk_141 + 10175625*uk_142 + 9090225*uk_143 + 8120601*uk_144 + 592704*uk_145 + 486864*uk_146 + 1587600*uk_147 + 1418256*uk_148 + 399924*uk_149 + 11411775*uk_15 + 1304100*uk_150 + 1164996*uk_151 + 4252500*uk_152 + 3798900*uk_153 + 3393684*uk_154 + 328509*uk_155 + 1071225*uk_156 + 956961*uk_157 + 3493125*uk_158 + 3120525*uk_159 + 10194519*uk_16 + 2787669*uk_160 + 11390625*uk_161 + 10175625*uk_162 + 9090225*uk_163 + 8120601*uk_164 + 3025*uk_17 + 7810*uk_18 + 11055*uk_19 + 55*uk_2 + 4620*uk_20 + 3795*uk_21 + 12375*uk_22 + 11055*uk_23 + 20164*uk_24 + 28542*uk_25 + 11928*uk_26 + 9798*uk_27 + 31950*uk_28 + 28542*uk_29 + 142*uk_3 + 40401*uk_30 + 16884*uk_31 + 13869*uk_32 + 45225*uk_33 + 40401*uk_34 + 7056*uk_35 + 5796*uk_36 + 18900*uk_37 + 16884*uk_38 + 4761*uk_39 + 201*uk_4 + 15525*uk_40 + 13869*uk_41 + 50625*uk_42 + 45225*uk_43 + 40401*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 365283208462*uk_47 + 517055809161*uk_48 + 216083024724*uk_49 + 84*uk_5 + 177496770309*uk_50 + 578793816225*uk_51 + 517055809161*uk_52 + 153424975*uk_53 + 396115390*uk_54 + 560698545*uk_55 + 234321780*uk_56 + 192478605*uk_57 + 627647625*uk_58 + 560698545*uk_59 + 69*uk_6 + 1022697916*uk_60 + 1447621698*uk_61 + 604976232*uk_62 + 496944762*uk_63 + 1620472050*uk_64 + 1447621698*uk_65 + 2049098319*uk_66 + 856339596*uk_67 + 703421811*uk_68 + 2293766775*uk_69 + 225*uk_7 + 2049098319*uk_70 + 357873264*uk_71 + 293967324*uk_72 + 958589100*uk_73 + 856339596*uk_74 + 241473159*uk_75 + 787412475*uk_76 + 703421811*uk_77 + 2567649375*uk_78 + 2293766775*uk_79 + 201*uk_8 + 2049098319*uk_80 + 166375*uk_81 + 429550*uk_82 + 608025*uk_83 + 254100*uk_84 + 208725*uk_85 + 680625*uk_86 + 608025*uk_87 + 1109020*uk_88 + 1569810*uk_89 + 2572416961*uk_9 + 656040*uk_90 + 538890*uk_91 + 1757250*uk_92 + 1569810*uk_93 + 2222055*uk_94 + 928620*uk_95 + 762795*uk_96 + 2487375*uk_97 + 2222055*uk_98 + 388080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 296780*uk_100 + 940500*uk_101 + 593560*uk_102 + 277255*uk_103 + 878625*uk_104 + 554510*uk_105 + 2784375*uk_106 + 1757250*uk_107 + 1109020*uk_108 + 15625*uk_109 + 1267975*uk_11 + 88750*uk_110 + 47500*uk_111 + 44375*uk_112 + 140625*uk_113 + 88750*uk_114 + 504100*uk_115 + 269800*uk_116 + 252050*uk_117 + 798750*uk_118 + 504100*uk_119 + 7202098*uk_12 + 144400*uk_120 + 134900*uk_121 + 427500*uk_122 + 269800*uk_123 + 126025*uk_124 + 399375*uk_125 + 252050*uk_126 + 1265625*uk_127 + 798750*uk_128 + 504100*uk_129 + 3854644*uk_13 + 2863288*uk_130 + 1532464*uk_131 + 1431644*uk_132 + 4536900*uk_133 + 2863288*uk_134 + 820192*uk_135 + 766232*uk_136 + 2428200*uk_137 + 1532464*uk_138 + 715822*uk_139 + 3601049*uk_14 + 2268450*uk_140 + 1431644*uk_141 + 7188750*uk_142 + 4536900*uk_143 + 2863288*uk_144 + 438976*uk_145 + 410096*uk_146 + 1299600*uk_147 + 820192*uk_148 + 383116*uk_149 + 11411775*uk_15 + 1214100*uk_150 + 766232*uk_151 + 3847500*uk_152 + 2428200*uk_153 + 1532464*uk_154 + 357911*uk_155 + 1134225*uk_156 + 715822*uk_157 + 3594375*uk_158 + 2268450*uk_159 + 7202098*uk_16 + 1431644*uk_160 + 11390625*uk_161 + 7188750*uk_162 + 4536900*uk_163 + 2863288*uk_164 + 3025*uk_17 + 1375*uk_18 + 7810*uk_19 + 55*uk_2 + 4180*uk_20 + 3905*uk_21 + 12375*uk_22 + 7810*uk_23 + 625*uk_24 + 3550*uk_25 + 1900*uk_26 + 1775*uk_27 + 5625*uk_28 + 3550*uk_29 + 25*uk_3 + 20164*uk_30 + 10792*uk_31 + 10082*uk_32 + 31950*uk_33 + 20164*uk_34 + 5776*uk_35 + 5396*uk_36 + 17100*uk_37 + 10792*uk_38 + 5041*uk_39 + 142*uk_4 + 15975*uk_40 + 10082*uk_41 + 50625*uk_42 + 31950*uk_43 + 20164*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 64310424025*uk_47 + 365283208462*uk_48 + 195503689036*uk_49 + 76*uk_5 + 182641604231*uk_50 + 578793816225*uk_51 + 365283208462*uk_52 + 153424975*uk_53 + 69738625*uk_54 + 396115390*uk_55 + 212005420*uk_56 + 198057695*uk_57 + 627647625*uk_58 + 396115390*uk_59 + 71*uk_6 + 31699375*uk_60 + 180052450*uk_61 + 96366100*uk_62 + 90026225*uk_63 + 285294375*uk_64 + 180052450*uk_65 + 1022697916*uk_66 + 547359448*uk_67 + 511348958*uk_68 + 1620472050*uk_69 + 225*uk_7 + 1022697916*uk_70 + 292952944*uk_71 + 273679724*uk_72 + 867294900*uk_73 + 547359448*uk_74 + 255674479*uk_75 + 810236025*uk_76 + 511348958*uk_77 + 2567649375*uk_78 + 1620472050*uk_79 + 142*uk_8 + 1022697916*uk_80 + 166375*uk_81 + 75625*uk_82 + 429550*uk_83 + 229900*uk_84 + 214775*uk_85 + 680625*uk_86 + 429550*uk_87 + 34375*uk_88 + 195250*uk_89 + 2572416961*uk_9 + 104500*uk_90 + 97625*uk_91 + 309375*uk_92 + 195250*uk_93 + 1109020*uk_94 + 593560*uk_95 + 554510*uk_96 + 1757250*uk_97 + 1109020*uk_98 + 317680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 321200*uk_100 + 990000*uk_101 + 110000*uk_102 + 293095*uk_103 + 903375*uk_104 + 100375*uk_105 + 2784375*uk_106 + 309375*uk_107 + 34375*uk_108 + 185193*uk_109 + 2890983*uk_11 + 81225*uk_110 + 259920*uk_111 + 237177*uk_112 + 731025*uk_113 + 81225*uk_114 + 35625*uk_115 + 114000*uk_116 + 104025*uk_117 + 320625*uk_118 + 35625*uk_119 + 1267975*uk_12 + 364800*uk_120 + 332880*uk_121 + 1026000*uk_122 + 114000*uk_123 + 303753*uk_124 + 936225*uk_125 + 104025*uk_126 + 2885625*uk_127 + 320625*uk_128 + 35625*uk_129 + 4057520*uk_13 + 15625*uk_130 + 50000*uk_131 + 45625*uk_132 + 140625*uk_133 + 15625*uk_134 + 160000*uk_135 + 146000*uk_136 + 450000*uk_137 + 50000*uk_138 + 133225*uk_139 + 3702487*uk_14 + 410625*uk_140 + 45625*uk_141 + 1265625*uk_142 + 140625*uk_143 + 15625*uk_144 + 512000*uk_145 + 467200*uk_146 + 1440000*uk_147 + 160000*uk_148 + 426320*uk_149 + 11411775*uk_15 + 1314000*uk_150 + 146000*uk_151 + 4050000*uk_152 + 450000*uk_153 + 50000*uk_154 + 389017*uk_155 + 1199025*uk_156 + 133225*uk_157 + 3695625*uk_158 + 410625*uk_159 + 1267975*uk_16 + 45625*uk_160 + 11390625*uk_161 + 1265625*uk_162 + 140625*uk_163 + 15625*uk_164 + 3025*uk_17 + 3135*uk_18 + 1375*uk_19 + 55*uk_2 + 4400*uk_20 + 4015*uk_21 + 12375*uk_22 + 1375*uk_23 + 3249*uk_24 + 1425*uk_25 + 4560*uk_26 + 4161*uk_27 + 12825*uk_28 + 1425*uk_29 + 57*uk_3 + 625*uk_30 + 2000*uk_31 + 1825*uk_32 + 5625*uk_33 + 625*uk_34 + 6400*uk_35 + 5840*uk_36 + 18000*uk_37 + 2000*uk_38 + 5329*uk_39 + 25*uk_4 + 16425*uk_40 + 1825*uk_41 + 50625*uk_42 + 5625*uk_43 + 625*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 146627766777*uk_47 + 64310424025*uk_48 + 205793356880*uk_49 + 80*uk_5 + 187786438153*uk_50 + 578793816225*uk_51 + 64310424025*uk_52 + 153424975*uk_53 + 159004065*uk_54 + 69738625*uk_55 + 223163600*uk_56 + 203636785*uk_57 + 627647625*uk_58 + 69738625*uk_59 + 73*uk_6 + 164786031*uk_60 + 72274575*uk_61 + 231278640*uk_62 + 211041759*uk_63 + 650471175*uk_64 + 72274575*uk_65 + 31699375*uk_66 + 101438000*uk_67 + 92562175*uk_68 + 285294375*uk_69 + 225*uk_7 + 31699375*uk_70 + 324601600*uk_71 + 296198960*uk_72 + 912942000*uk_73 + 101438000*uk_74 + 270281551*uk_75 + 833059575*uk_76 + 92562175*uk_77 + 2567649375*uk_78 + 285294375*uk_79 + 25*uk_8 + 31699375*uk_80 + 166375*uk_81 + 172425*uk_82 + 75625*uk_83 + 242000*uk_84 + 220825*uk_85 + 680625*uk_86 + 75625*uk_87 + 178695*uk_88 + 78375*uk_89 + 2572416961*uk_9 + 250800*uk_90 + 228855*uk_91 + 705375*uk_92 + 78375*uk_93 + 34375*uk_94 + 110000*uk_95 + 100375*uk_96 + 309375*uk_97 + 34375*uk_98 + 352000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 297000*uk_100 + 891000*uk_101 + 225720*uk_102 + 309375*uk_103 + 928125*uk_104 + 235125*uk_105 + 2784375*uk_106 + 705375*uk_107 + 178695*uk_108 + 6859*uk_109 + 963661*uk_11 + 20577*uk_110 + 25992*uk_111 + 27075*uk_112 + 81225*uk_113 + 20577*uk_114 + 61731*uk_115 + 77976*uk_116 + 81225*uk_117 + 243675*uk_118 + 61731*uk_119 + 2890983*uk_12 + 98496*uk_120 + 102600*uk_121 + 307800*uk_122 + 77976*uk_123 + 106875*uk_124 + 320625*uk_125 + 81225*uk_126 + 961875*uk_127 + 243675*uk_128 + 61731*uk_129 + 3651768*uk_13 + 185193*uk_130 + 233928*uk_131 + 243675*uk_132 + 731025*uk_133 + 185193*uk_134 + 295488*uk_135 + 307800*uk_136 + 923400*uk_137 + 233928*uk_138 + 320625*uk_139 + 3803925*uk_14 + 961875*uk_140 + 243675*uk_141 + 2885625*uk_142 + 731025*uk_143 + 185193*uk_144 + 373248*uk_145 + 388800*uk_146 + 1166400*uk_147 + 295488*uk_148 + 405000*uk_149 + 11411775*uk_15 + 1215000*uk_150 + 307800*uk_151 + 3645000*uk_152 + 923400*uk_153 + 233928*uk_154 + 421875*uk_155 + 1265625*uk_156 + 320625*uk_157 + 3796875*uk_158 + 961875*uk_159 + 2890983*uk_16 + 243675*uk_160 + 11390625*uk_161 + 2885625*uk_162 + 731025*uk_163 + 185193*uk_164 + 3025*uk_17 + 1045*uk_18 + 3135*uk_19 + 55*uk_2 + 3960*uk_20 + 4125*uk_21 + 12375*uk_22 + 3135*uk_23 + 361*uk_24 + 1083*uk_25 + 1368*uk_26 + 1425*uk_27 + 4275*uk_28 + 1083*uk_29 + 19*uk_3 + 3249*uk_30 + 4104*uk_31 + 4275*uk_32 + 12825*uk_33 + 3249*uk_34 + 5184*uk_35 + 5400*uk_36 + 16200*uk_37 + 4104*uk_38 + 5625*uk_39 + 57*uk_4 + 16875*uk_40 + 4275*uk_41 + 50625*uk_42 + 12825*uk_43 + 3249*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 48875922259*uk_47 + 146627766777*uk_48 + 185214021192*uk_49 + 72*uk_5 + 192931272075*uk_50 + 578793816225*uk_51 + 146627766777*uk_52 + 153424975*uk_53 + 53001355*uk_54 + 159004065*uk_55 + 200847240*uk_56 + 209215875*uk_57 + 627647625*uk_58 + 159004065*uk_59 + 75*uk_6 + 18309559*uk_60 + 54928677*uk_61 + 69383592*uk_62 + 72274575*uk_63 + 216823725*uk_64 + 54928677*uk_65 + 164786031*uk_66 + 208150776*uk_67 + 216823725*uk_68 + 650471175*uk_69 + 225*uk_7 + 164786031*uk_70 + 262927296*uk_71 + 273882600*uk_72 + 821647800*uk_73 + 208150776*uk_74 + 285294375*uk_75 + 855883125*uk_76 + 216823725*uk_77 + 2567649375*uk_78 + 650471175*uk_79 + 57*uk_8 + 164786031*uk_80 + 166375*uk_81 + 57475*uk_82 + 172425*uk_83 + 217800*uk_84 + 226875*uk_85 + 680625*uk_86 + 172425*uk_87 + 19855*uk_88 + 59565*uk_89 + 2572416961*uk_9 + 75240*uk_90 + 78375*uk_91 + 235125*uk_92 + 59565*uk_93 + 178695*uk_94 + 225720*uk_95 + 235125*uk_96 + 705375*uk_97 + 178695*uk_98 + 285120*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 304920*uk_100 + 891000*uk_101 + 75240*uk_102 + 326095*uk_103 + 952875*uk_104 + 80465*uk_105 + 2784375*uk_106 + 235125*uk_107 + 19855*uk_108 + 148877*uk_109 + 2688107*uk_11 + 53371*uk_110 + 202248*uk_111 + 216293*uk_112 + 632025*uk_113 + 53371*uk_114 + 19133*uk_115 + 72504*uk_116 + 77539*uk_117 + 226575*uk_118 + 19133*uk_119 + 963661*uk_12 + 274752*uk_120 + 293832*uk_121 + 858600*uk_122 + 72504*uk_123 + 314237*uk_124 + 918225*uk_125 + 77539*uk_126 + 2683125*uk_127 + 226575*uk_128 + 19133*uk_129 + 3651768*uk_13 + 6859*uk_130 + 25992*uk_131 + 27797*uk_132 + 81225*uk_133 + 6859*uk_134 + 98496*uk_135 + 105336*uk_136 + 307800*uk_137 + 25992*uk_138 + 112651*uk_139 + 3905363*uk_14 + 329175*uk_140 + 27797*uk_141 + 961875*uk_142 + 81225*uk_143 + 6859*uk_144 + 373248*uk_145 + 399168*uk_146 + 1166400*uk_147 + 98496*uk_148 + 426888*uk_149 + 11411775*uk_15 + 1247400*uk_150 + 105336*uk_151 + 3645000*uk_152 + 307800*uk_153 + 25992*uk_154 + 456533*uk_155 + 1334025*uk_156 + 112651*uk_157 + 3898125*uk_158 + 329175*uk_159 + 963661*uk_16 + 27797*uk_160 + 11390625*uk_161 + 961875*uk_162 + 81225*uk_163 + 6859*uk_164 + 3025*uk_17 + 2915*uk_18 + 1045*uk_19 + 55*uk_2 + 3960*uk_20 + 4235*uk_21 + 12375*uk_22 + 1045*uk_23 + 2809*uk_24 + 1007*uk_25 + 3816*uk_26 + 4081*uk_27 + 11925*uk_28 + 1007*uk_29 + 53*uk_3 + 361*uk_30 + 1368*uk_31 + 1463*uk_32 + 4275*uk_33 + 361*uk_34 + 5184*uk_35 + 5544*uk_36 + 16200*uk_37 + 1368*uk_38 + 5929*uk_39 + 19*uk_4 + 17325*uk_40 + 1463*uk_41 + 50625*uk_42 + 4275*uk_43 + 361*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 136338098933*uk_47 + 48875922259*uk_48 + 185214021192*uk_49 + 72*uk_5 + 198076105997*uk_50 + 578793816225*uk_51 + 48875922259*uk_52 + 153424975*uk_53 + 147845885*uk_54 + 53001355*uk_55 + 200847240*uk_56 + 214794965*uk_57 + 627647625*uk_58 + 53001355*uk_59 + 77*uk_6 + 142469671*uk_60 + 51074033*uk_61 + 193543704*uk_62 + 206984239*uk_63 + 604824075*uk_64 + 51074033*uk_65 + 18309559*uk_66 + 69383592*uk_67 + 74201897*uk_68 + 216823725*uk_69 + 225*uk_7 + 18309559*uk_70 + 262927296*uk_71 + 281186136*uk_72 + 821647800*uk_73 + 69383592*uk_74 + 300712951*uk_75 + 878706675*uk_76 + 74201897*uk_77 + 2567649375*uk_78 + 216823725*uk_79 + 19*uk_8 + 18309559*uk_80 + 166375*uk_81 + 160325*uk_82 + 57475*uk_83 + 217800*uk_84 + 232925*uk_85 + 680625*uk_86 + 57475*uk_87 + 154495*uk_88 + 55385*uk_89 + 2572416961*uk_9 + 209880*uk_90 + 224455*uk_91 + 655875*uk_92 + 55385*uk_93 + 19855*uk_94 + 75240*uk_95 + 80465*uk_96 + 235125*uk_97 + 19855*uk_98 + 285120*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 278080*uk_100 + 792000*uk_101 + 186560*uk_102 + 343255*uk_103 + 977625*uk_104 + 230285*uk_105 + 2784375*uk_106 + 655875*uk_107 + 154495*uk_108 + uk_109 + 50719*uk_11 + 53*uk_110 + 64*uk_111 + 79*uk_112 + 225*uk_113 + 53*uk_114 + 2809*uk_115 + 3392*uk_116 + 4187*uk_117 + 11925*uk_118 + 2809*uk_119 + 2688107*uk_12 + 4096*uk_120 + 5056*uk_121 + 14400*uk_122 + 3392*uk_123 + 6241*uk_124 + 17775*uk_125 + 4187*uk_126 + 50625*uk_127 + 11925*uk_128 + 2809*uk_129 + 3246016*uk_13 + 148877*uk_130 + 179776*uk_131 + 221911*uk_132 + 632025*uk_133 + 148877*uk_134 + 217088*uk_135 + 267968*uk_136 + 763200*uk_137 + 179776*uk_138 + 330773*uk_139 + 4006801*uk_14 + 942075*uk_140 + 221911*uk_141 + 2683125*uk_142 + 632025*uk_143 + 148877*uk_144 + 262144*uk_145 + 323584*uk_146 + 921600*uk_147 + 217088*uk_148 + 399424*uk_149 + 11411775*uk_15 + 1137600*uk_150 + 267968*uk_151 + 3240000*uk_152 + 763200*uk_153 + 179776*uk_154 + 493039*uk_155 + 1404225*uk_156 + 330773*uk_157 + 3999375*uk_158 + 942075*uk_159 + 2688107*uk_16 + 221911*uk_160 + 11390625*uk_161 + 2683125*uk_162 + 632025*uk_163 + 148877*uk_164 + 3025*uk_17 + 55*uk_18 + 2915*uk_19 + 55*uk_2 + 3520*uk_20 + 4345*uk_21 + 12375*uk_22 + 2915*uk_23 + uk_24 + 53*uk_25 + 64*uk_26 + 79*uk_27 + 225*uk_28 + 53*uk_29 + uk_3 + 2809*uk_30 + 3392*uk_31 + 4187*uk_32 + 11925*uk_33 + 2809*uk_34 + 4096*uk_35 + 5056*uk_36 + 14400*uk_37 + 3392*uk_38 + 6241*uk_39 + 53*uk_4 + 17775*uk_40 + 4187*uk_41 + 50625*uk_42 + 11925*uk_43 + 2809*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 2572416961*uk_47 + 136338098933*uk_48 + 164634685504*uk_49 + 64*uk_5 + 203220939919*uk_50 + 578793816225*uk_51 + 136338098933*uk_52 + 153424975*uk_53 + 2789545*uk_54 + 147845885*uk_55 + 178530880*uk_56 + 220374055*uk_57 + 627647625*uk_58 + 147845885*uk_59 + 79*uk_6 + 50719*uk_60 + 2688107*uk_61 + 3246016*uk_62 + 4006801*uk_63 + 11411775*uk_64 + 2688107*uk_65 + 142469671*uk_66 + 172038848*uk_67 + 212360453*uk_68 + 604824075*uk_69 + 225*uk_7 + 142469671*uk_70 + 207745024*uk_71 + 256435264*uk_72 + 730353600*uk_73 + 172038848*uk_74 + 316537279*uk_75 + 901530225*uk_76 + 212360453*uk_77 + 2567649375*uk_78 + 604824075*uk_79 + 53*uk_8 + 142469671*uk_80 + 166375*uk_81 + 3025*uk_82 + 160325*uk_83 + 193600*uk_84 + 238975*uk_85 + 680625*uk_86 + 160325*uk_87 + 55*uk_88 + 2915*uk_89 + 2572416961*uk_9 + 3520*uk_90 + 4345*uk_91 + 12375*uk_92 + 2915*uk_93 + 154495*uk_94 + 186560*uk_95 + 230285*uk_96 + 655875*uk_97 + 154495*uk_98 + 225280*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 285120*uk_100 + 792000*uk_101 + 3520*uk_102 + 360855*uk_103 + 1002375*uk_104 + 4455*uk_105 + 2784375*uk_106 + 12375*uk_107 + 55*uk_108 + 2197*uk_109 + 659347*uk_11 + 169*uk_110 + 10816*uk_111 + 13689*uk_112 + 38025*uk_113 + 169*uk_114 + 13*uk_115 + 832*uk_116 + 1053*uk_117 + 2925*uk_118 + 13*uk_119 + 50719*uk_12 + 53248*uk_120 + 67392*uk_121 + 187200*uk_122 + 832*uk_123 + 85293*uk_124 + 236925*uk_125 + 1053*uk_126 + 658125*uk_127 + 2925*uk_128 + 13*uk_129 + 3246016*uk_13 + uk_130 + 64*uk_131 + 81*uk_132 + 225*uk_133 + uk_134 + 4096*uk_135 + 5184*uk_136 + 14400*uk_137 + 64*uk_138 + 6561*uk_139 + 4108239*uk_14 + 18225*uk_140 + 81*uk_141 + 50625*uk_142 + 225*uk_143 + uk_144 + 262144*uk_145 + 331776*uk_146 + 921600*uk_147 + 4096*uk_148 + 419904*uk_149 + 11411775*uk_15 + 1166400*uk_150 + 5184*uk_151 + 3240000*uk_152 + 14400*uk_153 + 64*uk_154 + 531441*uk_155 + 1476225*uk_156 + 6561*uk_157 + 4100625*uk_158 + 18225*uk_159 + 50719*uk_16 + 81*uk_160 + 11390625*uk_161 + 50625*uk_162 + 225*uk_163 + uk_164 + 3025*uk_17 + 715*uk_18 + 55*uk_19 + 55*uk_2 + 3520*uk_20 + 4455*uk_21 + 12375*uk_22 + 55*uk_23 + 169*uk_24 + 13*uk_25 + 832*uk_26 + 1053*uk_27 + 2925*uk_28 + 13*uk_29 + 13*uk_3 + uk_30 + 64*uk_31 + 81*uk_32 + 225*uk_33 + uk_34 + 4096*uk_35 + 5184*uk_36 + 14400*uk_37 + 64*uk_38 + 6561*uk_39 + uk_4 + 18225*uk_40 + 81*uk_41 + 50625*uk_42 + 225*uk_43 + uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 33441420493*uk_47 + 2572416961*uk_48 + 164634685504*uk_49 + 64*uk_5 + 208365773841*uk_50 + 578793816225*uk_51 + 2572416961*uk_52 + 153424975*uk_53 + 36264085*uk_54 + 2789545*uk_55 + 178530880*uk_56 + 225953145*uk_57 + 627647625*uk_58 + 2789545*uk_59 + 81*uk_6 + 8571511*uk_60 + 659347*uk_61 + 42198208*uk_62 + 53407107*uk_63 + 148353075*uk_64 + 659347*uk_65 + 50719*uk_66 + 3246016*uk_67 + 4108239*uk_68 + 11411775*uk_69 + 225*uk_7 + 50719*uk_70 + 207745024*uk_71 + 262927296*uk_72 + 730353600*uk_73 + 3246016*uk_74 + 332767359*uk_75 + 924353775*uk_76 + 4108239*uk_77 + 2567649375*uk_78 + 11411775*uk_79 + uk_8 + 50719*uk_80 + 166375*uk_81 + 39325*uk_82 + 3025*uk_83 + 193600*uk_84 + 245025*uk_85 + 680625*uk_86 + 3025*uk_87 + 9295*uk_88 + 715*uk_89 + 2572416961*uk_9 + 45760*uk_90 + 57915*uk_91 + 160875*uk_92 + 715*uk_93 + 55*uk_94 + 3520*uk_95 + 4455*uk_96 + 12375*uk_97 + 55*uk_98 + 225280*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 273900*uk_100 + 742500*uk_101 + 42900*uk_102 + 378895*uk_103 + 1027125*uk_104 + 59345*uk_105 + 2784375*uk_106 + 160875*uk_107 + 9295*uk_108 + 216*uk_109 + 304314*uk_11 + 468*uk_110 + 2160*uk_111 + 2988*uk_112 + 8100*uk_113 + 468*uk_114 + 1014*uk_115 + 4680*uk_116 + 6474*uk_117 + 17550*uk_118 + 1014*uk_119 + 659347*uk_12 + 21600*uk_120 + 29880*uk_121 + 81000*uk_122 + 4680*uk_123 + 41334*uk_124 + 112050*uk_125 + 6474*uk_126 + 303750*uk_127 + 17550*uk_128 + 1014*uk_129 + 3043140*uk_13 + 2197*uk_130 + 10140*uk_131 + 14027*uk_132 + 38025*uk_133 + 2197*uk_134 + 46800*uk_135 + 64740*uk_136 + 175500*uk_137 + 10140*uk_138 + 89557*uk_139 + 4209677*uk_14 + 242775*uk_140 + 14027*uk_141 + 658125*uk_142 + 38025*uk_143 + 2197*uk_144 + 216000*uk_145 + 298800*uk_146 + 810000*uk_147 + 46800*uk_148 + 413340*uk_149 + 11411775*uk_15 + 1120500*uk_150 + 64740*uk_151 + 3037500*uk_152 + 175500*uk_153 + 10140*uk_154 + 571787*uk_155 + 1550025*uk_156 + 89557*uk_157 + 4201875*uk_158 + 242775*uk_159 + 659347*uk_16 + 14027*uk_160 + 11390625*uk_161 + 658125*uk_162 + 38025*uk_163 + 2197*uk_164 + 3025*uk_17 + 330*uk_18 + 715*uk_19 + 55*uk_2 + 3300*uk_20 + 4565*uk_21 + 12375*uk_22 + 715*uk_23 + 36*uk_24 + 78*uk_25 + 360*uk_26 + 498*uk_27 + 1350*uk_28 + 78*uk_29 + 6*uk_3 + 169*uk_30 + 780*uk_31 + 1079*uk_32 + 2925*uk_33 + 169*uk_34 + 3600*uk_35 + 4980*uk_36 + 13500*uk_37 + 780*uk_38 + 6889*uk_39 + 13*uk_4 + 18675*uk_40 + 1079*uk_41 + 50625*uk_42 + 2925*uk_43 + 169*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 15434501766*uk_47 + 33441420493*uk_48 + 154345017660*uk_49 + 60*uk_5 + 213510607763*uk_50 + 578793816225*uk_51 + 33441420493*uk_52 + 153424975*uk_53 + 16737270*uk_54 + 36264085*uk_55 + 167372700*uk_56 + 231532235*uk_57 + 627647625*uk_58 + 36264085*uk_59 + 83*uk_6 + 1825884*uk_60 + 3956082*uk_61 + 18258840*uk_62 + 25258062*uk_63 + 68470650*uk_64 + 3956082*uk_65 + 8571511*uk_66 + 39560820*uk_67 + 54725801*uk_68 + 148353075*uk_69 + 225*uk_7 + 8571511*uk_70 + 182588400*uk_71 + 252580620*uk_72 + 684706500*uk_73 + 39560820*uk_74 + 349403191*uk_75 + 947177325*uk_76 + 54725801*uk_77 + 2567649375*uk_78 + 148353075*uk_79 + 13*uk_8 + 8571511*uk_80 + 166375*uk_81 + 18150*uk_82 + 39325*uk_83 + 181500*uk_84 + 251075*uk_85 + 680625*uk_86 + 39325*uk_87 + 1980*uk_88 + 4290*uk_89 + 2572416961*uk_9 + 19800*uk_90 + 27390*uk_91 + 74250*uk_92 + 4290*uk_93 + 9295*uk_94 + 42900*uk_95 + 59345*uk_96 + 160875*uk_97 + 9295*uk_98 + 198000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 280500*uk_100 + 742500*uk_101 + 19800*uk_102 + 397375*uk_103 + 1051875*uk_104 + 28050*uk_105 + 2784375*uk_106 + 74250*uk_107 + 1980*uk_108 + 205379*uk_109 + 2992421*uk_11 + 20886*uk_110 + 208860*uk_111 + 295885*uk_112 + 783225*uk_113 + 20886*uk_114 + 2124*uk_115 + 21240*uk_116 + 30090*uk_117 + 79650*uk_118 + 2124*uk_119 + 304314*uk_12 + 212400*uk_120 + 300900*uk_121 + 796500*uk_122 + 21240*uk_123 + 426275*uk_124 + 1128375*uk_125 + 30090*uk_126 + 2986875*uk_127 + 79650*uk_128 + 2124*uk_129 + 3043140*uk_13 + 216*uk_130 + 2160*uk_131 + 3060*uk_132 + 8100*uk_133 + 216*uk_134 + 21600*uk_135 + 30600*uk_136 + 81000*uk_137 + 2160*uk_138 + 43350*uk_139 + 4311115*uk_14 + 114750*uk_140 + 3060*uk_141 + 303750*uk_142 + 8100*uk_143 + 216*uk_144 + 216000*uk_145 + 306000*uk_146 + 810000*uk_147 + 21600*uk_148 + 433500*uk_149 + 11411775*uk_15 + 1147500*uk_150 + 30600*uk_151 + 3037500*uk_152 + 81000*uk_153 + 2160*uk_154 + 614125*uk_155 + 1625625*uk_156 + 43350*uk_157 + 4303125*uk_158 + 114750*uk_159 + 304314*uk_16 + 3060*uk_160 + 11390625*uk_161 + 303750*uk_162 + 8100*uk_163 + 216*uk_164 + 3025*uk_17 + 3245*uk_18 + 330*uk_19 + 55*uk_2 + 3300*uk_20 + 4675*uk_21 + 12375*uk_22 + 330*uk_23 + 3481*uk_24 + 354*uk_25 + 3540*uk_26 + 5015*uk_27 + 13275*uk_28 + 354*uk_29 + 59*uk_3 + 36*uk_30 + 360*uk_31 + 510*uk_32 + 1350*uk_33 + 36*uk_34 + 3600*uk_35 + 5100*uk_36 + 13500*uk_37 + 360*uk_38 + 7225*uk_39 + 6*uk_4 + 19125*uk_40 + 510*uk_41 + 50625*uk_42 + 1350*uk_43 + 36*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 151772600699*uk_47 + 15434501766*uk_48 + 154345017660*uk_49 + 60*uk_5 + 218655441685*uk_50 + 578793816225*uk_51 + 15434501766*uk_52 + 153424975*uk_53 + 164583155*uk_54 + 16737270*uk_55 + 167372700*uk_56 + 237111325*uk_57 + 627647625*uk_58 + 16737270*uk_59 + 85*uk_6 + 176552839*uk_60 + 17954526*uk_61 + 179545260*uk_62 + 254355785*uk_63 + 673294725*uk_64 + 17954526*uk_65 + 1825884*uk_66 + 18258840*uk_67 + 25866690*uk_68 + 68470650*uk_69 + 225*uk_7 + 1825884*uk_70 + 182588400*uk_71 + 258666900*uk_72 + 684706500*uk_73 + 18258840*uk_74 + 366444775*uk_75 + 970000875*uk_76 + 25866690*uk_77 + 2567649375*uk_78 + 68470650*uk_79 + 6*uk_8 + 1825884*uk_80 + 166375*uk_81 + 178475*uk_82 + 18150*uk_83 + 181500*uk_84 + 257125*uk_85 + 680625*uk_86 + 18150*uk_87 + 191455*uk_88 + 19470*uk_89 + 2572416961*uk_9 + 194700*uk_90 + 275825*uk_91 + 730125*uk_92 + 19470*uk_93 + 1980*uk_94 + 19800*uk_95 + 28050*uk_96 + 74250*uk_97 + 1980*uk_98 + 198000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 267960*uk_100 + 693000*uk_101 + 181720*uk_102 + 416295*uk_103 + 1076625*uk_104 + 282315*uk_105 + 2784375*uk_106 + 730125*uk_107 + 191455*uk_108 + 614125*uk_109 + 4311115*uk_11 + 426275*uk_110 + 404600*uk_111 + 628575*uk_112 + 1625625*uk_113 + 426275*uk_114 + 295885*uk_115 + 280840*uk_116 + 436305*uk_117 + 1128375*uk_118 + 295885*uk_119 + 2992421*uk_12 + 266560*uk_120 + 414120*uk_121 + 1071000*uk_122 + 280840*uk_123 + 643365*uk_124 + 1663875*uk_125 + 436305*uk_126 + 4303125*uk_127 + 1128375*uk_128 + 295885*uk_129 + 2840264*uk_13 + 205379*uk_130 + 194936*uk_131 + 302847*uk_132 + 783225*uk_133 + 205379*uk_134 + 185024*uk_135 + 287448*uk_136 + 743400*uk_137 + 194936*uk_138 + 446571*uk_139 + 4412553*uk_14 + 1154925*uk_140 + 302847*uk_141 + 2986875*uk_142 + 783225*uk_143 + 205379*uk_144 + 175616*uk_145 + 272832*uk_146 + 705600*uk_147 + 185024*uk_148 + 423864*uk_149 + 11411775*uk_15 + 1096200*uk_150 + 287448*uk_151 + 2835000*uk_152 + 743400*uk_153 + 194936*uk_154 + 658503*uk_155 + 1703025*uk_156 + 446571*uk_157 + 4404375*uk_158 + 1154925*uk_159 + 2992421*uk_16 + 302847*uk_160 + 11390625*uk_161 + 2986875*uk_162 + 783225*uk_163 + 205379*uk_164 + 3025*uk_17 + 4675*uk_18 + 3245*uk_19 + 55*uk_2 + 3080*uk_20 + 4785*uk_21 + 12375*uk_22 + 3245*uk_23 + 7225*uk_24 + 5015*uk_25 + 4760*uk_26 + 7395*uk_27 + 19125*uk_28 + 5015*uk_29 + 85*uk_3 + 3481*uk_30 + 3304*uk_31 + 5133*uk_32 + 13275*uk_33 + 3481*uk_34 + 3136*uk_35 + 4872*uk_36 + 12600*uk_37 + 3304*uk_38 + 7569*uk_39 + 59*uk_4 + 19575*uk_40 + 5133*uk_41 + 50625*uk_42 + 13275*uk_43 + 3481*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 218655441685*uk_47 + 151772600699*uk_48 + 144055349816*uk_49 + 56*uk_5 + 223800275607*uk_50 + 578793816225*uk_51 + 151772600699*uk_52 + 153424975*uk_53 + 237111325*uk_54 + 164583155*uk_55 + 156214520*uk_56 + 242690415*uk_57 + 627647625*uk_58 + 164583155*uk_59 + 87*uk_6 + 366444775*uk_60 + 254355785*uk_61 + 241422440*uk_62 + 375067005*uk_63 + 970000875*uk_64 + 254355785*uk_65 + 176552839*uk_66 + 167575576*uk_67 + 260340627*uk_68 + 673294725*uk_69 + 225*uk_7 + 176552839*uk_70 + 159054784*uk_71 + 247102968*uk_72 + 639059400*uk_73 + 167575576*uk_74 + 383892111*uk_75 + 992824425*uk_76 + 260340627*uk_77 + 2567649375*uk_78 + 673294725*uk_79 + 59*uk_8 + 176552839*uk_80 + 166375*uk_81 + 257125*uk_82 + 178475*uk_83 + 169400*uk_84 + 263175*uk_85 + 680625*uk_86 + 178475*uk_87 + 397375*uk_88 + 275825*uk_89 + 2572416961*uk_9 + 261800*uk_90 + 406725*uk_91 + 1051875*uk_92 + 275825*uk_93 + 191455*uk_94 + 181720*uk_95 + 282315*uk_96 + 730125*uk_97 + 191455*uk_98 + 172480*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 254540*uk_100 + 643500*uk_101 + 243100*uk_102 + 435655*uk_103 + 1101375*uk_104 + 416075*uk_105 + 2784375*uk_106 + 1051875*uk_107 + 397375*uk_108 + 474552*uk_109 + 3956082*uk_11 + 517140*uk_110 + 316368*uk_111 + 541476*uk_112 + 1368900*uk_113 + 517140*uk_114 + 563550*uk_115 + 344760*uk_116 + 590070*uk_117 + 1491750*uk_118 + 563550*uk_119 + 4311115*uk_12 + 210912*uk_120 + 360984*uk_121 + 912600*uk_122 + 344760*uk_123 + 617838*uk_124 + 1561950*uk_125 + 590070*uk_126 + 3948750*uk_127 + 1491750*uk_128 + 563550*uk_129 + 2637388*uk_13 + 614125*uk_130 + 375700*uk_131 + 643025*uk_132 + 1625625*uk_133 + 614125*uk_134 + 229840*uk_135 + 393380*uk_136 + 994500*uk_137 + 375700*uk_138 + 673285*uk_139 + 4513991*uk_14 + 1702125*uk_140 + 643025*uk_141 + 4303125*uk_142 + 1625625*uk_143 + 614125*uk_144 + 140608*uk_145 + 240656*uk_146 + 608400*uk_147 + 229840*uk_148 + 411892*uk_149 + 11411775*uk_15 + 1041300*uk_150 + 393380*uk_151 + 2632500*uk_152 + 994500*uk_153 + 375700*uk_154 + 704969*uk_155 + 1782225*uk_156 + 673285*uk_157 + 4505625*uk_158 + 1702125*uk_159 + 4311115*uk_16 + 643025*uk_160 + 11390625*uk_161 + 4303125*uk_162 + 1625625*uk_163 + 614125*uk_164 + 3025*uk_17 + 4290*uk_18 + 4675*uk_19 + 55*uk_2 + 2860*uk_20 + 4895*uk_21 + 12375*uk_22 + 4675*uk_23 + 6084*uk_24 + 6630*uk_25 + 4056*uk_26 + 6942*uk_27 + 17550*uk_28 + 6630*uk_29 + 78*uk_3 + 7225*uk_30 + 4420*uk_31 + 7565*uk_32 + 19125*uk_33 + 7225*uk_34 + 2704*uk_35 + 4628*uk_36 + 11700*uk_37 + 4420*uk_38 + 7921*uk_39 + 85*uk_4 + 20025*uk_40 + 7565*uk_41 + 50625*uk_42 + 19125*uk_43 + 7225*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 200648522958*uk_47 + 218655441685*uk_48 + 133765681972*uk_49 + 52*uk_5 + 228945109529*uk_50 + 578793816225*uk_51 + 218655441685*uk_52 + 153424975*uk_53 + 217584510*uk_54 + 237111325*uk_55 + 145056340*uk_56 + 248269505*uk_57 + 627647625*uk_58 + 237111325*uk_59 + 89*uk_6 + 308574396*uk_60 + 336266970*uk_61 + 205716264*uk_62 + 352091298*uk_63 + 890118450*uk_64 + 336266970*uk_65 + 366444775*uk_66 + 224177980*uk_67 + 383689235*uk_68 + 970000875*uk_69 + 225*uk_7 + 366444775*uk_70 + 137144176*uk_71 + 234727532*uk_72 + 593412300*uk_73 + 224177980*uk_74 + 401745199*uk_75 + 1015647975*uk_76 + 383689235*uk_77 + 2567649375*uk_78 + 970000875*uk_79 + 85*uk_8 + 366444775*uk_80 + 166375*uk_81 + 235950*uk_82 + 257125*uk_83 + 157300*uk_84 + 269225*uk_85 + 680625*uk_86 + 257125*uk_87 + 334620*uk_88 + 364650*uk_89 + 2572416961*uk_9 + 223080*uk_90 + 381810*uk_91 + 965250*uk_92 + 364650*uk_93 + 397375*uk_94 + 243100*uk_95 + 416075*uk_96 + 1051875*uk_97 + 397375*uk_98 + 148720*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 240240*uk_100 + 594000*uk_101 + 205920*uk_102 + 455455*uk_103 + 1126125*uk_104 + 390390*uk_105 + 2784375*uk_106 + 965250*uk_107 + 334620*uk_108 + 32768*uk_109 + 1623008*uk_11 + 79872*uk_110 + 49152*uk_111 + 93184*uk_112 + 230400*uk_113 + 79872*uk_114 + 194688*uk_115 + 119808*uk_116 + 227136*uk_117 + 561600*uk_118 + 194688*uk_119 + 3956082*uk_12 + 73728*uk_120 + 139776*uk_121 + 345600*uk_122 + 119808*uk_123 + 264992*uk_124 + 655200*uk_125 + 227136*uk_126 + 1620000*uk_127 + 561600*uk_128 + 194688*uk_129 + 2434512*uk_13 + 474552*uk_130 + 292032*uk_131 + 553644*uk_132 + 1368900*uk_133 + 474552*uk_134 + 179712*uk_135 + 340704*uk_136 + 842400*uk_137 + 292032*uk_138 + 645918*uk_139 + 4615429*uk_14 + 1597050*uk_140 + 553644*uk_141 + 3948750*uk_142 + 1368900*uk_143 + 474552*uk_144 + 110592*uk_145 + 209664*uk_146 + 518400*uk_147 + 179712*uk_148 + 397488*uk_149 + 11411775*uk_15 + 982800*uk_150 + 340704*uk_151 + 2430000*uk_152 + 842400*uk_153 + 292032*uk_154 + 753571*uk_155 + 1863225*uk_156 + 645918*uk_157 + 4606875*uk_158 + 1597050*uk_159 + 3956082*uk_16 + 553644*uk_160 + 11390625*uk_161 + 3948750*uk_162 + 1368900*uk_163 + 474552*uk_164 + 3025*uk_17 + 1760*uk_18 + 4290*uk_19 + 55*uk_2 + 2640*uk_20 + 5005*uk_21 + 12375*uk_22 + 4290*uk_23 + 1024*uk_24 + 2496*uk_25 + 1536*uk_26 + 2912*uk_27 + 7200*uk_28 + 2496*uk_29 + 32*uk_3 + 6084*uk_30 + 3744*uk_31 + 7098*uk_32 + 17550*uk_33 + 6084*uk_34 + 2304*uk_35 + 4368*uk_36 + 10800*uk_37 + 3744*uk_38 + 8281*uk_39 + 78*uk_4 + 20475*uk_40 + 7098*uk_41 + 50625*uk_42 + 17550*uk_43 + 6084*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 82317342752*uk_47 + 200648522958*uk_48 + 123476014128*uk_49 + 48*uk_5 + 234089943451*uk_50 + 578793816225*uk_51 + 200648522958*uk_52 + 153424975*uk_53 + 89265440*uk_54 + 217584510*uk_55 + 133898160*uk_56 + 253848595*uk_57 + 627647625*uk_58 + 217584510*uk_59 + 91*uk_6 + 51936256*uk_60 + 126594624*uk_61 + 77904384*uk_62 + 147693728*uk_63 + 365176800*uk_64 + 126594624*uk_65 + 308574396*uk_66 + 189891936*uk_67 + 360003462*uk_68 + 890118450*uk_69 + 225*uk_7 + 308574396*uk_70 + 116856576*uk_71 + 221540592*uk_72 + 547765200*uk_73 + 189891936*uk_74 + 420004039*uk_75 + 1038471525*uk_76 + 360003462*uk_77 + 2567649375*uk_78 + 890118450*uk_79 + 78*uk_8 + 308574396*uk_80 + 166375*uk_81 + 96800*uk_82 + 235950*uk_83 + 145200*uk_84 + 275275*uk_85 + 680625*uk_86 + 235950*uk_87 + 56320*uk_88 + 137280*uk_89 + 2572416961*uk_9 + 84480*uk_90 + 160160*uk_91 + 396000*uk_92 + 137280*uk_93 + 334620*uk_94 + 205920*uk_95 + 390390*uk_96 + 965250*uk_97 + 334620*uk_98 + 126720*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 245520*uk_100 + 594000*uk_101 + 84480*uk_102 + 475695*uk_103 + 1150875*uk_104 + 163680*uk_105 + 2784375*uk_106 + 396000*uk_107 + 56320*uk_108 + 39304*uk_109 + 1724446*uk_11 + 36992*uk_110 + 55488*uk_111 + 107508*uk_112 + 260100*uk_113 + 36992*uk_114 + 34816*uk_115 + 52224*uk_116 + 101184*uk_117 + 244800*uk_118 + 34816*uk_119 + 1623008*uk_12 + 78336*uk_120 + 151776*uk_121 + 367200*uk_122 + 52224*uk_123 + 294066*uk_124 + 711450*uk_125 + 101184*uk_126 + 1721250*uk_127 + 244800*uk_128 + 34816*uk_129 + 2434512*uk_13 + 32768*uk_130 + 49152*uk_131 + 95232*uk_132 + 230400*uk_133 + 32768*uk_134 + 73728*uk_135 + 142848*uk_136 + 345600*uk_137 + 49152*uk_138 + 276768*uk_139 + 4716867*uk_14 + 669600*uk_140 + 95232*uk_141 + 1620000*uk_142 + 230400*uk_143 + 32768*uk_144 + 110592*uk_145 + 214272*uk_146 + 518400*uk_147 + 73728*uk_148 + 415152*uk_149 + 11411775*uk_15 + 1004400*uk_150 + 142848*uk_151 + 2430000*uk_152 + 345600*uk_153 + 49152*uk_154 + 804357*uk_155 + 1946025*uk_156 + 276768*uk_157 + 4708125*uk_158 + 669600*uk_159 + 1623008*uk_16 + 95232*uk_160 + 11390625*uk_161 + 1620000*uk_162 + 230400*uk_163 + 32768*uk_164 + 3025*uk_17 + 1870*uk_18 + 1760*uk_19 + 55*uk_2 + 2640*uk_20 + 5115*uk_21 + 12375*uk_22 + 1760*uk_23 + 1156*uk_24 + 1088*uk_25 + 1632*uk_26 + 3162*uk_27 + 7650*uk_28 + 1088*uk_29 + 34*uk_3 + 1024*uk_30 + 1536*uk_31 + 2976*uk_32 + 7200*uk_33 + 1024*uk_34 + 2304*uk_35 + 4464*uk_36 + 10800*uk_37 + 1536*uk_38 + 8649*uk_39 + 32*uk_4 + 20925*uk_40 + 2976*uk_41 + 50625*uk_42 + 7200*uk_43 + 1024*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 87462176674*uk_47 + 82317342752*uk_48 + 123476014128*uk_49 + 48*uk_5 + 239234777373*uk_50 + 578793816225*uk_51 + 82317342752*uk_52 + 153424975*uk_53 + 94844530*uk_54 + 89265440*uk_55 + 133898160*uk_56 + 259427685*uk_57 + 627647625*uk_58 + 89265440*uk_59 + 93*uk_6 + 58631164*uk_60 + 55182272*uk_61 + 82773408*uk_62 + 160373478*uk_63 + 388000350*uk_64 + 55182272*uk_65 + 51936256*uk_66 + 77904384*uk_67 + 150939744*uk_68 + 365176800*uk_69 + 225*uk_7 + 51936256*uk_70 + 116856576*uk_71 + 226409616*uk_72 + 547765200*uk_73 + 77904384*uk_74 + 438668631*uk_75 + 1061295075*uk_76 + 150939744*uk_77 + 2567649375*uk_78 + 365176800*uk_79 + 32*uk_8 + 51936256*uk_80 + 166375*uk_81 + 102850*uk_82 + 96800*uk_83 + 145200*uk_84 + 281325*uk_85 + 680625*uk_86 + 96800*uk_87 + 63580*uk_88 + 59840*uk_89 + 2572416961*uk_9 + 89760*uk_90 + 173910*uk_91 + 420750*uk_92 + 59840*uk_93 + 56320*uk_94 + 84480*uk_95 + 163680*uk_96 + 396000*uk_97 + 56320*uk_98 + 126720*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 250800*uk_100 + 594000*uk_101 + 89760*uk_102 + 496375*uk_103 + 1175625*uk_104 + 177650*uk_105 + 2784375*uk_106 + 420750*uk_107 + 63580*uk_108 + 592704*uk_109 + 4260396*uk_11 + 239904*uk_110 + 338688*uk_111 + 670320*uk_112 + 1587600*uk_113 + 239904*uk_114 + 97104*uk_115 + 137088*uk_116 + 271320*uk_117 + 642600*uk_118 + 97104*uk_119 + 1724446*uk_12 + 193536*uk_120 + 383040*uk_121 + 907200*uk_122 + 137088*uk_123 + 758100*uk_124 + 1795500*uk_125 + 271320*uk_126 + 4252500*uk_127 + 642600*uk_128 + 97104*uk_129 + 2434512*uk_13 + 39304*uk_130 + 55488*uk_131 + 109820*uk_132 + 260100*uk_133 + 39304*uk_134 + 78336*uk_135 + 155040*uk_136 + 367200*uk_137 + 55488*uk_138 + 306850*uk_139 + 4818305*uk_14 + 726750*uk_140 + 109820*uk_141 + 1721250*uk_142 + 260100*uk_143 + 39304*uk_144 + 110592*uk_145 + 218880*uk_146 + 518400*uk_147 + 78336*uk_148 + 433200*uk_149 + 11411775*uk_15 + 1026000*uk_150 + 155040*uk_151 + 2430000*uk_152 + 367200*uk_153 + 55488*uk_154 + 857375*uk_155 + 2030625*uk_156 + 306850*uk_157 + 4809375*uk_158 + 726750*uk_159 + 1724446*uk_16 + 109820*uk_160 + 11390625*uk_161 + 1721250*uk_162 + 260100*uk_163 + 39304*uk_164 + 3025*uk_17 + 4620*uk_18 + 1870*uk_19 + 55*uk_2 + 2640*uk_20 + 5225*uk_21 + 12375*uk_22 + 1870*uk_23 + 7056*uk_24 + 2856*uk_25 + 4032*uk_26 + 7980*uk_27 + 18900*uk_28 + 2856*uk_29 + 84*uk_3 + 1156*uk_30 + 1632*uk_31 + 3230*uk_32 + 7650*uk_33 + 1156*uk_34 + 2304*uk_35 + 4560*uk_36 + 10800*uk_37 + 1632*uk_38 + 9025*uk_39 + 34*uk_4 + 21375*uk_40 + 3230*uk_41 + 50625*uk_42 + 7650*uk_43 + 1156*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 216083024724*uk_47 + 87462176674*uk_48 + 123476014128*uk_49 + 48*uk_5 + 244379611295*uk_50 + 578793816225*uk_51 + 87462176674*uk_52 + 153424975*uk_53 + 234321780*uk_54 + 94844530*uk_55 + 133898160*uk_56 + 265006775*uk_57 + 627647625*uk_58 + 94844530*uk_59 + 95*uk_6 + 357873264*uk_60 + 144853464*uk_61 + 204499008*uk_62 + 404737620*uk_63 + 958589100*uk_64 + 144853464*uk_65 + 58631164*uk_66 + 82773408*uk_67 + 163822370*uk_68 + 388000350*uk_69 + 225*uk_7 + 58631164*uk_70 + 116856576*uk_71 + 231278640*uk_72 + 547765200*uk_73 + 82773408*uk_74 + 457738975*uk_75 + 1084118625*uk_76 + 163822370*uk_77 + 2567649375*uk_78 + 388000350*uk_79 + 34*uk_8 + 58631164*uk_80 + 166375*uk_81 + 254100*uk_82 + 102850*uk_83 + 145200*uk_84 + 287375*uk_85 + 680625*uk_86 + 102850*uk_87 + 388080*uk_88 + 157080*uk_89 + 2572416961*uk_9 + 221760*uk_90 + 438900*uk_91 + 1039500*uk_92 + 157080*uk_93 + 63580*uk_94 + 89760*uk_95 + 177650*uk_96 + 420750*uk_97 + 63580*uk_98 + 126720*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 234740*uk_100 + 544500*uk_101 + 203280*uk_102 + 517495*uk_103 + 1200375*uk_104 + 448140*uk_105 + 2784375*uk_106 + 1039500*uk_107 + 388080*uk_108 + 614125*uk_109 + 4311115*uk_11 + 606900*uk_110 + 317900*uk_111 + 700825*uk_112 + 1625625*uk_113 + 606900*uk_114 + 599760*uk_115 + 314160*uk_116 + 692580*uk_117 + 1606500*uk_118 + 599760*uk_119 + 4260396*uk_12 + 164560*uk_120 + 362780*uk_121 + 841500*uk_122 + 314160*uk_123 + 799765*uk_124 + 1855125*uk_125 + 692580*uk_126 + 4303125*uk_127 + 1606500*uk_128 + 599760*uk_129 + 2231636*uk_13 + 592704*uk_130 + 310464*uk_131 + 684432*uk_132 + 1587600*uk_133 + 592704*uk_134 + 162624*uk_135 + 358512*uk_136 + 831600*uk_137 + 310464*uk_138 + 790356*uk_139 + 4919743*uk_14 + 1833300*uk_140 + 684432*uk_141 + 4252500*uk_142 + 1587600*uk_143 + 592704*uk_144 + 85184*uk_145 + 187792*uk_146 + 435600*uk_147 + 162624*uk_148 + 413996*uk_149 + 11411775*uk_15 + 960300*uk_150 + 358512*uk_151 + 2227500*uk_152 + 831600*uk_153 + 310464*uk_154 + 912673*uk_155 + 2117025*uk_156 + 790356*uk_157 + 4910625*uk_158 + 1833300*uk_159 + 4260396*uk_16 + 684432*uk_160 + 11390625*uk_161 + 4252500*uk_162 + 1587600*uk_163 + 592704*uk_164 + 3025*uk_17 + 4675*uk_18 + 4620*uk_19 + 55*uk_2 + 2420*uk_20 + 5335*uk_21 + 12375*uk_22 + 4620*uk_23 + 7225*uk_24 + 7140*uk_25 + 3740*uk_26 + 8245*uk_27 + 19125*uk_28 + 7140*uk_29 + 85*uk_3 + 7056*uk_30 + 3696*uk_31 + 8148*uk_32 + 18900*uk_33 + 7056*uk_34 + 1936*uk_35 + 4268*uk_36 + 9900*uk_37 + 3696*uk_38 + 9409*uk_39 + 84*uk_4 + 21825*uk_40 + 8148*uk_41 + 50625*uk_42 + 18900*uk_43 + 7056*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 218655441685*uk_47 + 216083024724*uk_48 + 113186346284*uk_49 + 44*uk_5 + 249524445217*uk_50 + 578793816225*uk_51 + 216083024724*uk_52 + 153424975*uk_53 + 237111325*uk_54 + 234321780*uk_55 + 122739980*uk_56 + 270585865*uk_57 + 627647625*uk_58 + 234321780*uk_59 + 97*uk_6 + 366444775*uk_60 + 362133660*uk_61 + 189689060*uk_62 + 418178155*uk_63 + 970000875*uk_64 + 362133660*uk_65 + 357873264*uk_66 + 187457424*uk_67 + 413258412*uk_68 + 958589100*uk_69 + 225*uk_7 + 357873264*uk_70 + 98191984*uk_71 + 216468692*uk_72 + 502118100*uk_73 + 187457424*uk_74 + 477215071*uk_75 + 1106942175*uk_76 + 413258412*uk_77 + 2567649375*uk_78 + 958589100*uk_79 + 84*uk_8 + 357873264*uk_80 + 166375*uk_81 + 257125*uk_82 + 254100*uk_83 + 133100*uk_84 + 293425*uk_85 + 680625*uk_86 + 254100*uk_87 + 397375*uk_88 + 392700*uk_89 + 2572416961*uk_9 + 205700*uk_90 + 453475*uk_91 + 1051875*uk_92 + 392700*uk_93 + 388080*uk_94 + 203280*uk_95 + 448140*uk_96 + 1039500*uk_97 + 388080*uk_98 + 106480*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 217800*uk_100 + 495000*uk_101 + 187000*uk_102 + 539055*uk_103 + 1225125*uk_104 + 462825*uk_105 + 2784375*uk_106 + 1051875*uk_107 + 397375*uk_108 + 29791*uk_109 + 1572289*uk_11 + 81685*uk_110 + 38440*uk_111 + 95139*uk_112 + 216225*uk_113 + 81685*uk_114 + 223975*uk_115 + 105400*uk_116 + 260865*uk_117 + 592875*uk_118 + 223975*uk_119 + 4311115*uk_12 + 49600*uk_120 + 122760*uk_121 + 279000*uk_122 + 105400*uk_123 + 303831*uk_124 + 690525*uk_125 + 260865*uk_126 + 1569375*uk_127 + 592875*uk_128 + 223975*uk_129 + 2028760*uk_13 + 614125*uk_130 + 289000*uk_131 + 715275*uk_132 + 1625625*uk_133 + 614125*uk_134 + 136000*uk_135 + 336600*uk_136 + 765000*uk_137 + 289000*uk_138 + 833085*uk_139 + 5021181*uk_14 + 1893375*uk_140 + 715275*uk_141 + 4303125*uk_142 + 1625625*uk_143 + 614125*uk_144 + 64000*uk_145 + 158400*uk_146 + 360000*uk_147 + 136000*uk_148 + 392040*uk_149 + 11411775*uk_15 + 891000*uk_150 + 336600*uk_151 + 2025000*uk_152 + 765000*uk_153 + 289000*uk_154 + 970299*uk_155 + 2205225*uk_156 + 833085*uk_157 + 5011875*uk_158 + 1893375*uk_159 + 4311115*uk_16 + 715275*uk_160 + 11390625*uk_161 + 4303125*uk_162 + 1625625*uk_163 + 614125*uk_164 + 3025*uk_17 + 1705*uk_18 + 4675*uk_19 + 55*uk_2 + 2200*uk_20 + 5445*uk_21 + 12375*uk_22 + 4675*uk_23 + 961*uk_24 + 2635*uk_25 + 1240*uk_26 + 3069*uk_27 + 6975*uk_28 + 2635*uk_29 + 31*uk_3 + 7225*uk_30 + 3400*uk_31 + 8415*uk_32 + 19125*uk_33 + 7225*uk_34 + 1600*uk_35 + 3960*uk_36 + 9000*uk_37 + 3400*uk_38 + 9801*uk_39 + 85*uk_4 + 22275*uk_40 + 8415*uk_41 + 50625*uk_42 + 19125*uk_43 + 7225*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 79744925791*uk_47 + 218655441685*uk_48 + 102896678440*uk_49 + 40*uk_5 + 254669279139*uk_50 + 578793816225*uk_51 + 218655441685*uk_52 + 153424975*uk_53 + 86475895*uk_54 + 237111325*uk_55 + 111581800*uk_56 + 276164955*uk_57 + 627647625*uk_58 + 237111325*uk_59 + 99*uk_6 + 48740959*uk_60 + 133644565*uk_61 + 62891560*uk_62 + 155656611*uk_63 + 353765025*uk_64 + 133644565*uk_65 + 366444775*uk_66 + 172444600*uk_67 + 426800385*uk_68 + 970000875*uk_69 + 225*uk_7 + 366444775*uk_70 + 81150400*uk_71 + 200847240*uk_72 + 456471000*uk_73 + 172444600*uk_74 + 497096919*uk_75 + 1129765725*uk_76 + 426800385*uk_77 + 2567649375*uk_78 + 970000875*uk_79 + 85*uk_8 + 366444775*uk_80 + 166375*uk_81 + 93775*uk_82 + 257125*uk_83 + 121000*uk_84 + 299475*uk_85 + 680625*uk_86 + 257125*uk_87 + 52855*uk_88 + 144925*uk_89 + 2572416961*uk_9 + 68200*uk_90 + 168795*uk_91 + 383625*uk_92 + 144925*uk_93 + 397375*uk_94 + 187000*uk_95 + 462825*uk_96 + 1051875*uk_97 + 397375*uk_98 + 88000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 222200*uk_100 + 495000*uk_101 + 68200*uk_102 + 561055*uk_103 + 1249875*uk_104 + 172205*uk_105 + 2784375*uk_106 + 383625*uk_107 + 52855*uk_108 + 4913*uk_109 + 862223*uk_11 + 8959*uk_110 + 11560*uk_111 + 29189*uk_112 + 65025*uk_113 + 8959*uk_114 + 16337*uk_115 + 21080*uk_116 + 53227*uk_117 + 118575*uk_118 + 16337*uk_119 + 1572289*uk_12 + 27200*uk_120 + 68680*uk_121 + 153000*uk_122 + 21080*uk_123 + 173417*uk_124 + 386325*uk_125 + 53227*uk_126 + 860625*uk_127 + 118575*uk_128 + 16337*uk_129 + 2028760*uk_13 + 29791*uk_130 + 38440*uk_131 + 97061*uk_132 + 216225*uk_133 + 29791*uk_134 + 49600*uk_135 + 125240*uk_136 + 279000*uk_137 + 38440*uk_138 + 316231*uk_139 + 5122619*uk_14 + 704475*uk_140 + 97061*uk_141 + 1569375*uk_142 + 216225*uk_143 + 29791*uk_144 + 64000*uk_145 + 161600*uk_146 + 360000*uk_147 + 49600*uk_148 + 408040*uk_149 + 11411775*uk_15 + 909000*uk_150 + 125240*uk_151 + 2025000*uk_152 + 279000*uk_153 + 38440*uk_154 + 1030301*uk_155 + 2295225*uk_156 + 316231*uk_157 + 5113125*uk_158 + 704475*uk_159 + 1572289*uk_16 + 97061*uk_160 + 11390625*uk_161 + 1569375*uk_162 + 216225*uk_163 + 29791*uk_164 + 3025*uk_17 + 935*uk_18 + 1705*uk_19 + 55*uk_2 + 2200*uk_20 + 5555*uk_21 + 12375*uk_22 + 1705*uk_23 + 289*uk_24 + 527*uk_25 + 680*uk_26 + 1717*uk_27 + 3825*uk_28 + 527*uk_29 + 17*uk_3 + 961*uk_30 + 1240*uk_31 + 3131*uk_32 + 6975*uk_33 + 961*uk_34 + 1600*uk_35 + 4040*uk_36 + 9000*uk_37 + 1240*uk_38 + 10201*uk_39 + 31*uk_4 + 22725*uk_40 + 3131*uk_41 + 50625*uk_42 + 6975*uk_43 + 961*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 43731088337*uk_47 + 79744925791*uk_48 + 102896678440*uk_49 + 40*uk_5 + 259814113061*uk_50 + 578793816225*uk_51 + 79744925791*uk_52 + 153424975*uk_53 + 47422265*uk_54 + 86475895*uk_55 + 111581800*uk_56 + 281744045*uk_57 + 627647625*uk_58 + 86475895*uk_59 + 101*uk_6 + 14657791*uk_60 + 26728913*uk_61 + 34488920*uk_62 + 87084523*uk_63 + 194000175*uk_64 + 26728913*uk_65 + 48740959*uk_66 + 62891560*uk_67 + 158801189*uk_68 + 353765025*uk_69 + 225*uk_7 + 48740959*uk_70 + 81150400*uk_71 + 204904760*uk_72 + 456471000*uk_73 + 62891560*uk_74 + 517384519*uk_75 + 1152589275*uk_76 + 158801189*uk_77 + 2567649375*uk_78 + 353765025*uk_79 + 31*uk_8 + 48740959*uk_80 + 166375*uk_81 + 51425*uk_82 + 93775*uk_83 + 121000*uk_84 + 305525*uk_85 + 680625*uk_86 + 93775*uk_87 + 15895*uk_88 + 28985*uk_89 + 2572416961*uk_9 + 37400*uk_90 + 94435*uk_91 + 210375*uk_92 + 28985*uk_93 + 52855*uk_94 + 68200*uk_95 + 172205*uk_96 + 383625*uk_97 + 52855*uk_98 + 88000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 226600*uk_100 + 495000*uk_101 + 37400*uk_102 + 583495*uk_103 + 1274625*uk_104 + 96305*uk_105 + 2784375*uk_106 + 210375*uk_107 + 15895*uk_108 + 79507*uk_109 + 2180917*uk_11 + 31433*uk_110 + 73960*uk_111 + 190447*uk_112 + 416025*uk_113 + 31433*uk_114 + 12427*uk_115 + 29240*uk_116 + 75293*uk_117 + 164475*uk_118 + 12427*uk_119 + 862223*uk_12 + 68800*uk_120 + 177160*uk_121 + 387000*uk_122 + 29240*uk_123 + 456187*uk_124 + 996525*uk_125 + 75293*uk_126 + 2176875*uk_127 + 164475*uk_128 + 12427*uk_129 + 2028760*uk_13 + 4913*uk_130 + 11560*uk_131 + 29767*uk_132 + 65025*uk_133 + 4913*uk_134 + 27200*uk_135 + 70040*uk_136 + 153000*uk_137 + 11560*uk_138 + 180353*uk_139 + 5224057*uk_14 + 393975*uk_140 + 29767*uk_141 + 860625*uk_142 + 65025*uk_143 + 4913*uk_144 + 64000*uk_145 + 164800*uk_146 + 360000*uk_147 + 27200*uk_148 + 424360*uk_149 + 11411775*uk_15 + 927000*uk_150 + 70040*uk_151 + 2025000*uk_152 + 153000*uk_153 + 11560*uk_154 + 1092727*uk_155 + 2387025*uk_156 + 180353*uk_157 + 5214375*uk_158 + 393975*uk_159 + 862223*uk_16 + 29767*uk_160 + 11390625*uk_161 + 860625*uk_162 + 65025*uk_163 + 4913*uk_164 + 3025*uk_17 + 2365*uk_18 + 935*uk_19 + 55*uk_2 + 2200*uk_20 + 5665*uk_21 + 12375*uk_22 + 935*uk_23 + 1849*uk_24 + 731*uk_25 + 1720*uk_26 + 4429*uk_27 + 9675*uk_28 + 731*uk_29 + 43*uk_3 + 289*uk_30 + 680*uk_31 + 1751*uk_32 + 3825*uk_33 + 289*uk_34 + 1600*uk_35 + 4120*uk_36 + 9000*uk_37 + 680*uk_38 + 10609*uk_39 + 17*uk_4 + 23175*uk_40 + 1751*uk_41 + 50625*uk_42 + 3825*uk_43 + 289*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 110613929323*uk_47 + 43731088337*uk_48 + 102896678440*uk_49 + 40*uk_5 + 264958946983*uk_50 + 578793816225*uk_51 + 43731088337*uk_52 + 153424975*uk_53 + 119950435*uk_54 + 47422265*uk_55 + 111581800*uk_56 + 287323135*uk_57 + 627647625*uk_58 + 47422265*uk_59 + 103*uk_6 + 93779431*uk_60 + 37075589*uk_61 + 87236680*uk_62 + 224634451*uk_63 + 490706325*uk_64 + 37075589*uk_65 + 14657791*uk_66 + 34488920*uk_67 + 88808969*uk_68 + 194000175*uk_69 + 225*uk_7 + 14657791*uk_70 + 81150400*uk_71 + 208962280*uk_72 + 456471000*uk_73 + 34488920*uk_74 + 538077871*uk_75 + 1175412825*uk_76 + 88808969*uk_77 + 2567649375*uk_78 + 194000175*uk_79 + 17*uk_8 + 14657791*uk_80 + 166375*uk_81 + 130075*uk_82 + 51425*uk_83 + 121000*uk_84 + 311575*uk_85 + 680625*uk_86 + 51425*uk_87 + 101695*uk_88 + 40205*uk_89 + 2572416961*uk_9 + 94600*uk_90 + 243595*uk_91 + 532125*uk_92 + 40205*uk_93 + 15895*uk_94 + 37400*uk_95 + 96305*uk_96 + 210375*uk_97 + 15895*uk_98 + 88000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 207900*uk_100 + 445500*uk_101 + 85140*uk_102 + 606375*uk_103 + 1299375*uk_104 + 248325*uk_105 + 2784375*uk_106 + 532125*uk_107 + 101695*uk_108 + 64*uk_109 + 202876*uk_11 + 688*uk_110 + 576*uk_111 + 1680*uk_112 + 3600*uk_113 + 688*uk_114 + 7396*uk_115 + 6192*uk_116 + 18060*uk_117 + 38700*uk_118 + 7396*uk_119 + 2180917*uk_12 + 5184*uk_120 + 15120*uk_121 + 32400*uk_122 + 6192*uk_123 + 44100*uk_124 + 94500*uk_125 + 18060*uk_126 + 202500*uk_127 + 38700*uk_128 + 7396*uk_129 + 1825884*uk_13 + 79507*uk_130 + 66564*uk_131 + 194145*uk_132 + 416025*uk_133 + 79507*uk_134 + 55728*uk_135 + 162540*uk_136 + 348300*uk_137 + 66564*uk_138 + 474075*uk_139 + 5325495*uk_14 + 1015875*uk_140 + 194145*uk_141 + 2176875*uk_142 + 416025*uk_143 + 79507*uk_144 + 46656*uk_145 + 136080*uk_146 + 291600*uk_147 + 55728*uk_148 + 396900*uk_149 + 11411775*uk_15 + 850500*uk_150 + 162540*uk_151 + 1822500*uk_152 + 348300*uk_153 + 66564*uk_154 + 1157625*uk_155 + 2480625*uk_156 + 474075*uk_157 + 5315625*uk_158 + 1015875*uk_159 + 2180917*uk_16 + 194145*uk_160 + 11390625*uk_161 + 2176875*uk_162 + 416025*uk_163 + 79507*uk_164 + 3025*uk_17 + 220*uk_18 + 2365*uk_19 + 55*uk_2 + 1980*uk_20 + 5775*uk_21 + 12375*uk_22 + 2365*uk_23 + 16*uk_24 + 172*uk_25 + 144*uk_26 + 420*uk_27 + 900*uk_28 + 172*uk_29 + 4*uk_3 + 1849*uk_30 + 1548*uk_31 + 4515*uk_32 + 9675*uk_33 + 1849*uk_34 + 1296*uk_35 + 3780*uk_36 + 8100*uk_37 + 1548*uk_38 + 11025*uk_39 + 43*uk_4 + 23625*uk_40 + 4515*uk_41 + 50625*uk_42 + 9675*uk_43 + 1849*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 110613929323*uk_48 + 92607010596*uk_49 + 36*uk_5 + 270103780905*uk_50 + 578793816225*uk_51 + 110613929323*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 119950435*uk_55 + 100423620*uk_56 + 292902225*uk_57 + 627647625*uk_58 + 119950435*uk_59 + 105*uk_6 + 811504*uk_60 + 8723668*uk_61 + 7303536*uk_62 + 21301980*uk_63 + 45647100*uk_64 + 8723668*uk_65 + 93779431*uk_66 + 78513012*uk_67 + 228996285*uk_68 + 490706325*uk_69 + 225*uk_7 + 93779431*uk_70 + 65731824*uk_71 + 191717820*uk_72 + 410823900*uk_73 + 78513012*uk_74 + 559176975*uk_75 + 1198236375*uk_76 + 228996285*uk_77 + 2567649375*uk_78 + 490706325*uk_79 + 43*uk_8 + 93779431*uk_80 + 166375*uk_81 + 12100*uk_82 + 130075*uk_83 + 108900*uk_84 + 317625*uk_85 + 680625*uk_86 + 130075*uk_87 + 880*uk_88 + 9460*uk_89 + 2572416961*uk_9 + 7920*uk_90 + 23100*uk_91 + 49500*uk_92 + 9460*uk_93 + 101695*uk_94 + 85140*uk_95 + 248325*uk_96 + 532125*uk_97 + 101695*uk_98 + 71280*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 211860*uk_100 + 445500*uk_101 + 7920*uk_102 + 629695*uk_103 + 1324125*uk_104 + 23540*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + uk_109 + 50719*uk_11 + 4*uk_110 + 36*uk_111 + 107*uk_112 + 225*uk_113 + 4*uk_114 + 16*uk_115 + 144*uk_116 + 428*uk_117 + 900*uk_118 + 16*uk_119 + 202876*uk_12 + 1296*uk_120 + 3852*uk_121 + 8100*uk_122 + 144*uk_123 + 11449*uk_124 + 24075*uk_125 + 428*uk_126 + 50625*uk_127 + 900*uk_128 + 16*uk_129 + 1825884*uk_13 + 64*uk_130 + 576*uk_131 + 1712*uk_132 + 3600*uk_133 + 64*uk_134 + 5184*uk_135 + 15408*uk_136 + 32400*uk_137 + 576*uk_138 + 45796*uk_139 + 5426933*uk_14 + 96300*uk_140 + 1712*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 46656*uk_145 + 138672*uk_146 + 291600*uk_147 + 5184*uk_148 + 412164*uk_149 + 11411775*uk_15 + 866700*uk_150 + 15408*uk_151 + 1822500*uk_152 + 32400*uk_153 + 576*uk_154 + 1225043*uk_155 + 2576025*uk_156 + 45796*uk_157 + 5416875*uk_158 + 96300*uk_159 + 202876*uk_16 + 1712*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 55*uk_18 + 220*uk_19 + 55*uk_2 + 1980*uk_20 + 5885*uk_21 + 12375*uk_22 + 220*uk_23 + uk_24 + 4*uk_25 + 36*uk_26 + 107*uk_27 + 225*uk_28 + 4*uk_29 + uk_3 + 16*uk_30 + 144*uk_31 + 428*uk_32 + 900*uk_33 + 16*uk_34 + 1296*uk_35 + 3852*uk_36 + 8100*uk_37 + 144*uk_38 + 11449*uk_39 + 4*uk_4 + 24075*uk_40 + 428*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 2572416961*uk_47 + 10289667844*uk_48 + 92607010596*uk_49 + 36*uk_5 + 275248614827*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 2789545*uk_54 + 11158180*uk_55 + 100423620*uk_56 + 298481315*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 107*uk_6 + 50719*uk_60 + 202876*uk_61 + 1825884*uk_62 + 5426933*uk_63 + 11411775*uk_64 + 202876*uk_65 + 811504*uk_66 + 7303536*uk_67 + 21707732*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 65731824*uk_71 + 195369588*uk_72 + 410823900*uk_73 + 7303536*uk_74 + 580681831*uk_75 + 1221059925*uk_76 + 21707732*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 3025*uk_82 + 12100*uk_83 + 108900*uk_84 + 323675*uk_85 + 680625*uk_86 + 12100*uk_87 + 55*uk_88 + 220*uk_89 + 2572416961*uk_9 + 1980*uk_90 + 5885*uk_91 + 12375*uk_92 + 220*uk_93 + 880*uk_94 + 7920*uk_95 + 23540*uk_96 + 49500*uk_97 + 880*uk_98 + 71280*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 215820*uk_100 + 445500*uk_101 + 1980*uk_102 + 653455*uk_103 + 1348875*uk_104 + 5995*uk_105 + 2784375*uk_106 + 12375*uk_107 + 55*uk_108 + 39304*uk_109 + 1724446*uk_11 + 1156*uk_110 + 41616*uk_111 + 126004*uk_112 + 260100*uk_113 + 1156*uk_114 + 34*uk_115 + 1224*uk_116 + 3706*uk_117 + 7650*uk_118 + 34*uk_119 + 50719*uk_12 + 44064*uk_120 + 133416*uk_121 + 275400*uk_122 + 1224*uk_123 + 403954*uk_124 + 833850*uk_125 + 3706*uk_126 + 1721250*uk_127 + 7650*uk_128 + 34*uk_129 + 1825884*uk_13 + uk_130 + 36*uk_131 + 109*uk_132 + 225*uk_133 + uk_134 + 1296*uk_135 + 3924*uk_136 + 8100*uk_137 + 36*uk_138 + 11881*uk_139 + 5528371*uk_14 + 24525*uk_140 + 109*uk_141 + 50625*uk_142 + 225*uk_143 + uk_144 + 46656*uk_145 + 141264*uk_146 + 291600*uk_147 + 1296*uk_148 + 427716*uk_149 + 11411775*uk_15 + 882900*uk_150 + 3924*uk_151 + 1822500*uk_152 + 8100*uk_153 + 36*uk_154 + 1295029*uk_155 + 2673225*uk_156 + 11881*uk_157 + 5518125*uk_158 + 24525*uk_159 + 50719*uk_16 + 109*uk_160 + 11390625*uk_161 + 50625*uk_162 + 225*uk_163 + uk_164 + 3025*uk_17 + 1870*uk_18 + 55*uk_19 + 55*uk_2 + 1980*uk_20 + 5995*uk_21 + 12375*uk_22 + 55*uk_23 + 1156*uk_24 + 34*uk_25 + 1224*uk_26 + 3706*uk_27 + 7650*uk_28 + 34*uk_29 + 34*uk_3 + uk_30 + 36*uk_31 + 109*uk_32 + 225*uk_33 + uk_34 + 1296*uk_35 + 3924*uk_36 + 8100*uk_37 + 36*uk_38 + 11881*uk_39 + uk_4 + 24525*uk_40 + 109*uk_41 + 50625*uk_42 + 225*uk_43 + uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 87462176674*uk_47 + 2572416961*uk_48 + 92607010596*uk_49 + 36*uk_5 + 280393448749*uk_50 + 578793816225*uk_51 + 2572416961*uk_52 + 153424975*uk_53 + 94844530*uk_54 + 2789545*uk_55 + 100423620*uk_56 + 304060405*uk_57 + 627647625*uk_58 + 2789545*uk_59 + 109*uk_6 + 58631164*uk_60 + 1724446*uk_61 + 62080056*uk_62 + 187964614*uk_63 + 388000350*uk_64 + 1724446*uk_65 + 50719*uk_66 + 1825884*uk_67 + 5528371*uk_68 + 11411775*uk_69 + 225*uk_7 + 50719*uk_70 + 65731824*uk_71 + 199021356*uk_72 + 410823900*uk_73 + 1825884*uk_74 + 602592439*uk_75 + 1243883475*uk_76 + 5528371*uk_77 + 2567649375*uk_78 + 11411775*uk_79 + uk_8 + 50719*uk_80 + 166375*uk_81 + 102850*uk_82 + 3025*uk_83 + 108900*uk_84 + 329725*uk_85 + 680625*uk_86 + 3025*uk_87 + 63580*uk_88 + 1870*uk_89 + 2572416961*uk_9 + 67320*uk_90 + 203830*uk_91 + 420750*uk_92 + 1870*uk_93 + 55*uk_94 + 1980*uk_95 + 5995*uk_96 + 12375*uk_97 + 55*uk_98 + 71280*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 219780*uk_100 + 445500*uk_101 + 67320*uk_102 + 677655*uk_103 + 1373625*uk_104 + 207570*uk_105 + 2784375*uk_106 + 420750*uk_107 + 63580*uk_108 + 1092727*uk_109 + 5224057*uk_11 + 360706*uk_110 + 381924*uk_111 + 1177599*uk_112 + 2387025*uk_113 + 360706*uk_114 + 119068*uk_115 + 126072*uk_116 + 388722*uk_117 + 787950*uk_118 + 119068*uk_119 + 1724446*uk_12 + 133488*uk_120 + 411588*uk_121 + 834300*uk_122 + 126072*uk_123 + 1269063*uk_124 + 2572425*uk_125 + 388722*uk_126 + 5214375*uk_127 + 787950*uk_128 + 119068*uk_129 + 1825884*uk_13 + 39304*uk_130 + 41616*uk_131 + 128316*uk_132 + 260100*uk_133 + 39304*uk_134 + 44064*uk_135 + 135864*uk_136 + 275400*uk_137 + 41616*uk_138 + 418914*uk_139 + 5629809*uk_14 + 849150*uk_140 + 128316*uk_141 + 1721250*uk_142 + 260100*uk_143 + 39304*uk_144 + 46656*uk_145 + 143856*uk_146 + 291600*uk_147 + 44064*uk_148 + 443556*uk_149 + 11411775*uk_15 + 899100*uk_150 + 135864*uk_151 + 1822500*uk_152 + 275400*uk_153 + 41616*uk_154 + 1367631*uk_155 + 2772225*uk_156 + 418914*uk_157 + 5619375*uk_158 + 849150*uk_159 + 1724446*uk_16 + 128316*uk_160 + 11390625*uk_161 + 1721250*uk_162 + 260100*uk_163 + 39304*uk_164 + 3025*uk_17 + 5665*uk_18 + 1870*uk_19 + 55*uk_2 + 1980*uk_20 + 6105*uk_21 + 12375*uk_22 + 1870*uk_23 + 10609*uk_24 + 3502*uk_25 + 3708*uk_26 + 11433*uk_27 + 23175*uk_28 + 3502*uk_29 + 103*uk_3 + 1156*uk_30 + 1224*uk_31 + 3774*uk_32 + 7650*uk_33 + 1156*uk_34 + 1296*uk_35 + 3996*uk_36 + 8100*uk_37 + 1224*uk_38 + 12321*uk_39 + 34*uk_4 + 24975*uk_40 + 3774*uk_41 + 50625*uk_42 + 7650*uk_43 + 1156*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 264958946983*uk_47 + 87462176674*uk_48 + 92607010596*uk_49 + 36*uk_5 + 285538282671*uk_50 + 578793816225*uk_51 + 87462176674*uk_52 + 153424975*uk_53 + 287323135*uk_54 + 94844530*uk_55 + 100423620*uk_56 + 309639495*uk_57 + 627647625*uk_58 + 94844530*uk_59 + 111*uk_6 + 538077871*uk_60 + 177617938*uk_61 + 188066052*uk_62 + 579870327*uk_63 + 1175412825*uk_64 + 177617938*uk_65 + 58631164*uk_66 + 62080056*uk_67 + 191413506*uk_68 + 388000350*uk_69 + 225*uk_7 + 58631164*uk_70 + 65731824*uk_71 + 202673124*uk_72 + 410823900*uk_73 + 62080056*uk_74 + 624908799*uk_75 + 1266707025*uk_76 + 191413506*uk_77 + 2567649375*uk_78 + 388000350*uk_79 + 34*uk_8 + 58631164*uk_80 + 166375*uk_81 + 311575*uk_82 + 102850*uk_83 + 108900*uk_84 + 335775*uk_85 + 680625*uk_86 + 102850*uk_87 + 583495*uk_88 + 192610*uk_89 + 2572416961*uk_9 + 203940*uk_90 + 628815*uk_91 + 1274625*uk_92 + 192610*uk_93 + 63580*uk_94 + 67320*uk_95 + 207570*uk_96 + 420750*uk_97 + 63580*uk_98 + 71280*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 198880*uk_100 + 396000*uk_101 + 181280*uk_102 + 702295*uk_103 + 1398375*uk_104 + 640145*uk_105 + 2784375*uk_106 + 1274625*uk_107 + 583495*uk_108 + 857375*uk_109 + 4818305*uk_11 + 929575*uk_110 + 288800*uk_111 + 1019825*uk_112 + 2030625*uk_113 + 929575*uk_114 + 1007855*uk_115 + 313120*uk_116 + 1105705*uk_117 + 2201625*uk_118 + 1007855*uk_119 + 5224057*uk_12 + 97280*uk_120 + 343520*uk_121 + 684000*uk_122 + 313120*uk_123 + 1213055*uk_124 + 2415375*uk_125 + 1105705*uk_126 + 4809375*uk_127 + 2201625*uk_128 + 1007855*uk_129 + 1623008*uk_13 + 1092727*uk_130 + 339488*uk_131 + 1198817*uk_132 + 2387025*uk_133 + 1092727*uk_134 + 105472*uk_135 + 372448*uk_136 + 741600*uk_137 + 339488*uk_138 + 1315207*uk_139 + 5731247*uk_14 + 2618775*uk_140 + 1198817*uk_141 + 5214375*uk_142 + 2387025*uk_143 + 1092727*uk_144 + 32768*uk_145 + 115712*uk_146 + 230400*uk_147 + 105472*uk_148 + 408608*uk_149 + 11411775*uk_15 + 813600*uk_150 + 372448*uk_151 + 1620000*uk_152 + 741600*uk_153 + 339488*uk_154 + 1442897*uk_155 + 2873025*uk_156 + 1315207*uk_157 + 5720625*uk_158 + 2618775*uk_159 + 5224057*uk_16 + 1198817*uk_160 + 11390625*uk_161 + 5214375*uk_162 + 2387025*uk_163 + 1092727*uk_164 + 3025*uk_17 + 5225*uk_18 + 5665*uk_19 + 55*uk_2 + 1760*uk_20 + 6215*uk_21 + 12375*uk_22 + 5665*uk_23 + 9025*uk_24 + 9785*uk_25 + 3040*uk_26 + 10735*uk_27 + 21375*uk_28 + 9785*uk_29 + 95*uk_3 + 10609*uk_30 + 3296*uk_31 + 11639*uk_32 + 23175*uk_33 + 10609*uk_34 + 1024*uk_35 + 3616*uk_36 + 7200*uk_37 + 3296*uk_38 + 12769*uk_39 + 103*uk_4 + 25425*uk_40 + 11639*uk_41 + 50625*uk_42 + 23175*uk_43 + 10609*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 244379611295*uk_47 + 264958946983*uk_48 + 82317342752*uk_49 + 32*uk_5 + 290683116593*uk_50 + 578793816225*uk_51 + 264958946983*uk_52 + 153424975*uk_53 + 265006775*uk_54 + 287323135*uk_55 + 89265440*uk_56 + 315218585*uk_57 + 627647625*uk_58 + 287323135*uk_59 + 113*uk_6 + 457738975*uk_60 + 496285415*uk_61 + 154185760*uk_62 + 544468465*uk_63 + 1084118625*uk_64 + 496285415*uk_65 + 538077871*uk_66 + 167169824*uk_67 + 590318441*uk_68 + 1175412825*uk_69 + 225*uk_7 + 538077871*uk_70 + 51936256*uk_71 + 183399904*uk_72 + 365176800*uk_73 + 167169824*uk_74 + 647630911*uk_75 + 1289530575*uk_76 + 590318441*uk_77 + 2567649375*uk_78 + 1175412825*uk_79 + 103*uk_8 + 538077871*uk_80 + 166375*uk_81 + 287375*uk_82 + 311575*uk_83 + 96800*uk_84 + 341825*uk_85 + 680625*uk_86 + 311575*uk_87 + 496375*uk_88 + 538175*uk_89 + 2572416961*uk_9 + 167200*uk_90 + 590425*uk_91 + 1175625*uk_92 + 538175*uk_93 + 583495*uk_94 + 181280*uk_95 + 640145*uk_96 + 1274625*uk_97 + 583495*uk_98 + 56320*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 177100*uk_100 + 346500*uk_101 + 146300*uk_102 + 727375*uk_103 + 1423125*uk_104 + 600875*uk_105 + 2784375*uk_106 + 1175625*uk_107 + 496375*uk_108 + 64*uk_109 + 202876*uk_11 + 1520*uk_110 + 448*uk_111 + 1840*uk_112 + 3600*uk_113 + 1520*uk_114 + 36100*uk_115 + 10640*uk_116 + 43700*uk_117 + 85500*uk_118 + 36100*uk_119 + 4818305*uk_12 + 3136*uk_120 + 12880*uk_121 + 25200*uk_122 + 10640*uk_123 + 52900*uk_124 + 103500*uk_125 + 43700*uk_126 + 202500*uk_127 + 85500*uk_128 + 36100*uk_129 + 1420132*uk_13 + 857375*uk_130 + 252700*uk_131 + 1037875*uk_132 + 2030625*uk_133 + 857375*uk_134 + 74480*uk_135 + 305900*uk_136 + 598500*uk_137 + 252700*uk_138 + 1256375*uk_139 + 5832685*uk_14 + 2458125*uk_140 + 1037875*uk_141 + 4809375*uk_142 + 2030625*uk_143 + 857375*uk_144 + 21952*uk_145 + 90160*uk_146 + 176400*uk_147 + 74480*uk_148 + 370300*uk_149 + 11411775*uk_15 + 724500*uk_150 + 305900*uk_151 + 1417500*uk_152 + 598500*uk_153 + 252700*uk_154 + 1520875*uk_155 + 2975625*uk_156 + 1256375*uk_157 + 5821875*uk_158 + 2458125*uk_159 + 4818305*uk_16 + 1037875*uk_160 + 11390625*uk_161 + 4809375*uk_162 + 2030625*uk_163 + 857375*uk_164 + 3025*uk_17 + 220*uk_18 + 5225*uk_19 + 55*uk_2 + 1540*uk_20 + 6325*uk_21 + 12375*uk_22 + 5225*uk_23 + 16*uk_24 + 380*uk_25 + 112*uk_26 + 460*uk_27 + 900*uk_28 + 380*uk_29 + 4*uk_3 + 9025*uk_30 + 2660*uk_31 + 10925*uk_32 + 21375*uk_33 + 9025*uk_34 + 784*uk_35 + 3220*uk_36 + 6300*uk_37 + 2660*uk_38 + 13225*uk_39 + 95*uk_4 + 25875*uk_40 + 10925*uk_41 + 50625*uk_42 + 21375*uk_43 + 9025*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 244379611295*uk_48 + 72027674908*uk_49 + 28*uk_5 + 295827950515*uk_50 + 578793816225*uk_51 + 244379611295*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 265006775*uk_55 + 78107260*uk_56 + 320797675*uk_57 + 627647625*uk_58 + 265006775*uk_59 + 115*uk_6 + 811504*uk_60 + 19273220*uk_61 + 5680528*uk_62 + 23330740*uk_63 + 45647100*uk_64 + 19273220*uk_65 + 457738975*uk_66 + 134912540*uk_67 + 554105075*uk_68 + 1084118625*uk_69 + 225*uk_7 + 457738975*uk_70 + 39763696*uk_71 + 163315180*uk_72 + 319529700*uk_73 + 134912540*uk_74 + 670758775*uk_75 + 1312354125*uk_76 + 554105075*uk_77 + 2567649375*uk_78 + 1084118625*uk_79 + 95*uk_8 + 457738975*uk_80 + 166375*uk_81 + 12100*uk_82 + 287375*uk_83 + 84700*uk_84 + 347875*uk_85 + 680625*uk_86 + 287375*uk_87 + 880*uk_88 + 20900*uk_89 + 2572416961*uk_9 + 6160*uk_90 + 25300*uk_91 + 49500*uk_92 + 20900*uk_93 + 496375*uk_94 + 146300*uk_95 + 600875*uk_96 + 1175625*uk_97 + 496375*uk_98 + 43120*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 205920*uk_100 + 396000*uk_101 + 7040*uk_102 + 752895*uk_103 + 1447875*uk_104 + 25740*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 195112*uk_109 + 2941702*uk_11 + 13456*uk_110 + 107648*uk_111 + 393588*uk_112 + 756900*uk_113 + 13456*uk_114 + 928*uk_115 + 7424*uk_116 + 27144*uk_117 + 52200*uk_118 + 928*uk_119 + 202876*uk_12 + 59392*uk_120 + 217152*uk_121 + 417600*uk_122 + 7424*uk_123 + 793962*uk_124 + 1526850*uk_125 + 27144*uk_126 + 2936250*uk_127 + 52200*uk_128 + 928*uk_129 + 1623008*uk_13 + 64*uk_130 + 512*uk_131 + 1872*uk_132 + 3600*uk_133 + 64*uk_134 + 4096*uk_135 + 14976*uk_136 + 28800*uk_137 + 512*uk_138 + 54756*uk_139 + 5934123*uk_14 + 105300*uk_140 + 1872*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 32768*uk_145 + 119808*uk_146 + 230400*uk_147 + 4096*uk_148 + 438048*uk_149 + 11411775*uk_15 + 842400*uk_150 + 14976*uk_151 + 1620000*uk_152 + 28800*uk_153 + 512*uk_154 + 1601613*uk_155 + 3080025*uk_156 + 54756*uk_157 + 5923125*uk_158 + 105300*uk_159 + 202876*uk_16 + 1872*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 3190*uk_18 + 220*uk_19 + 55*uk_2 + 1760*uk_20 + 6435*uk_21 + 12375*uk_22 + 220*uk_23 + 3364*uk_24 + 232*uk_25 + 1856*uk_26 + 6786*uk_27 + 13050*uk_28 + 232*uk_29 + 58*uk_3 + 16*uk_30 + 128*uk_31 + 468*uk_32 + 900*uk_33 + 16*uk_34 + 1024*uk_35 + 3744*uk_36 + 7200*uk_37 + 128*uk_38 + 13689*uk_39 + 4*uk_4 + 26325*uk_40 + 468*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 149200183738*uk_47 + 10289667844*uk_48 + 82317342752*uk_49 + 32*uk_5 + 300972784437*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 161793610*uk_54 + 11158180*uk_55 + 89265440*uk_56 + 326376765*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 117*uk_6 + 170618716*uk_60 + 11766808*uk_61 + 94134464*uk_62 + 344179134*uk_63 + 661882950*uk_64 + 11766808*uk_65 + 811504*uk_66 + 6492032*uk_67 + 23736492*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 51936256*uk_71 + 189891936*uk_72 + 365176800*uk_73 + 6492032*uk_74 + 694292391*uk_75 + 1335177675*uk_76 + 23736492*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 175450*uk_82 + 12100*uk_83 + 96800*uk_84 + 353925*uk_85 + 680625*uk_86 + 12100*uk_87 + 185020*uk_88 + 12760*uk_89 + 2572416961*uk_9 + 102080*uk_90 + 373230*uk_91 + 717750*uk_92 + 12760*uk_93 + 880*uk_94 + 7040*uk_95 + 25740*uk_96 + 49500*uk_97 + 880*uk_98 + 56320*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 183260*uk_100 + 346500*uk_101 + 89320*uk_102 + 778855*uk_103 + 1472625*uk_104 + 379610*uk_105 + 2784375*uk_106 + 717750*uk_107 + 185020*uk_108 + 15625*uk_109 + 1267975*uk_11 + 36250*uk_110 + 17500*uk_111 + 74375*uk_112 + 140625*uk_113 + 36250*uk_114 + 84100*uk_115 + 40600*uk_116 + 172550*uk_117 + 326250*uk_118 + 84100*uk_119 + 2941702*uk_12 + 19600*uk_120 + 83300*uk_121 + 157500*uk_122 + 40600*uk_123 + 354025*uk_124 + 669375*uk_125 + 172550*uk_126 + 1265625*uk_127 + 326250*uk_128 + 84100*uk_129 + 1420132*uk_13 + 195112*uk_130 + 94192*uk_131 + 400316*uk_132 + 756900*uk_133 + 195112*uk_134 + 45472*uk_135 + 193256*uk_136 + 365400*uk_137 + 94192*uk_138 + 821338*uk_139 + 6035561*uk_14 + 1552950*uk_140 + 400316*uk_141 + 2936250*uk_142 + 756900*uk_143 + 195112*uk_144 + 21952*uk_145 + 93296*uk_146 + 176400*uk_147 + 45472*uk_148 + 396508*uk_149 + 11411775*uk_15 + 749700*uk_150 + 193256*uk_151 + 1417500*uk_152 + 365400*uk_153 + 94192*uk_154 + 1685159*uk_155 + 3186225*uk_156 + 821338*uk_157 + 6024375*uk_158 + 1552950*uk_159 + 2941702*uk_16 + 400316*uk_160 + 11390625*uk_161 + 2936250*uk_162 + 756900*uk_163 + 195112*uk_164 + 3025*uk_17 + 1375*uk_18 + 3190*uk_19 + 55*uk_2 + 1540*uk_20 + 6545*uk_21 + 12375*uk_22 + 3190*uk_23 + 625*uk_24 + 1450*uk_25 + 700*uk_26 + 2975*uk_27 + 5625*uk_28 + 1450*uk_29 + 25*uk_3 + 3364*uk_30 + 1624*uk_31 + 6902*uk_32 + 13050*uk_33 + 3364*uk_34 + 784*uk_35 + 3332*uk_36 + 6300*uk_37 + 1624*uk_38 + 14161*uk_39 + 58*uk_4 + 26775*uk_40 + 6902*uk_41 + 50625*uk_42 + 13050*uk_43 + 3364*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 64310424025*uk_47 + 149200183738*uk_48 + 72027674908*uk_49 + 28*uk_5 + 306117618359*uk_50 + 578793816225*uk_51 + 149200183738*uk_52 + 153424975*uk_53 + 69738625*uk_54 + 161793610*uk_55 + 78107260*uk_56 + 331955855*uk_57 + 627647625*uk_58 + 161793610*uk_59 + 119*uk_6 + 31699375*uk_60 + 73542550*uk_61 + 35503300*uk_62 + 150889025*uk_63 + 285294375*uk_64 + 73542550*uk_65 + 170618716*uk_66 + 82367656*uk_67 + 350062538*uk_68 + 661882950*uk_69 + 225*uk_7 + 170618716*uk_70 + 39763696*uk_71 + 168995708*uk_72 + 319529700*uk_73 + 82367656*uk_74 + 718231759*uk_75 + 1358001225*uk_76 + 350062538*uk_77 + 2567649375*uk_78 + 661882950*uk_79 + 58*uk_8 + 170618716*uk_80 + 166375*uk_81 + 75625*uk_82 + 175450*uk_83 + 84700*uk_84 + 359975*uk_85 + 680625*uk_86 + 175450*uk_87 + 34375*uk_88 + 79750*uk_89 + 2572416961*uk_9 + 38500*uk_90 + 163625*uk_91 + 309375*uk_92 + 79750*uk_93 + 185020*uk_94 + 89320*uk_95 + 379610*uk_96 + 717750*uk_97 + 185020*uk_98 + 43120*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 186340*uk_100 + 346500*uk_101 + 38500*uk_102 + 805255*uk_103 + 1497375*uk_104 + 166375*uk_105 + 2784375*uk_106 + 309375*uk_107 + 34375*uk_108 + 8000*uk_109 + 1014380*uk_11 + 10000*uk_110 + 11200*uk_111 + 48400*uk_112 + 90000*uk_113 + 10000*uk_114 + 12500*uk_115 + 14000*uk_116 + 60500*uk_117 + 112500*uk_118 + 12500*uk_119 + 1267975*uk_12 + 15680*uk_120 + 67760*uk_121 + 126000*uk_122 + 14000*uk_123 + 292820*uk_124 + 544500*uk_125 + 60500*uk_126 + 1012500*uk_127 + 112500*uk_128 + 12500*uk_129 + 1420132*uk_13 + 15625*uk_130 + 17500*uk_131 + 75625*uk_132 + 140625*uk_133 + 15625*uk_134 + 19600*uk_135 + 84700*uk_136 + 157500*uk_137 + 17500*uk_138 + 366025*uk_139 + 6136999*uk_14 + 680625*uk_140 + 75625*uk_141 + 1265625*uk_142 + 140625*uk_143 + 15625*uk_144 + 21952*uk_145 + 94864*uk_146 + 176400*uk_147 + 19600*uk_148 + 409948*uk_149 + 11411775*uk_15 + 762300*uk_150 + 84700*uk_151 + 1417500*uk_152 + 157500*uk_153 + 17500*uk_154 + 1771561*uk_155 + 3294225*uk_156 + 366025*uk_157 + 6125625*uk_158 + 680625*uk_159 + 1267975*uk_16 + 75625*uk_160 + 11390625*uk_161 + 1265625*uk_162 + 140625*uk_163 + 15625*uk_164 + 3025*uk_17 + 1100*uk_18 + 1375*uk_19 + 55*uk_2 + 1540*uk_20 + 6655*uk_21 + 12375*uk_22 + 1375*uk_23 + 400*uk_24 + 500*uk_25 + 560*uk_26 + 2420*uk_27 + 4500*uk_28 + 500*uk_29 + 20*uk_3 + 625*uk_30 + 700*uk_31 + 3025*uk_32 + 5625*uk_33 + 625*uk_34 + 784*uk_35 + 3388*uk_36 + 6300*uk_37 + 700*uk_38 + 14641*uk_39 + 25*uk_4 + 27225*uk_40 + 3025*uk_41 + 50625*uk_42 + 5625*uk_43 + 625*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 51448339220*uk_47 + 64310424025*uk_48 + 72027674908*uk_49 + 28*uk_5 + 311262452281*uk_50 + 578793816225*uk_51 + 64310424025*uk_52 + 153424975*uk_53 + 55790900*uk_54 + 69738625*uk_55 + 78107260*uk_56 + 337534945*uk_57 + 627647625*uk_58 + 69738625*uk_59 + 121*uk_6 + 20287600*uk_60 + 25359500*uk_61 + 28402640*uk_62 + 122739980*uk_63 + 228235500*uk_64 + 25359500*uk_65 + 31699375*uk_66 + 35503300*uk_67 + 153424975*uk_68 + 285294375*uk_69 + 225*uk_7 + 31699375*uk_70 + 39763696*uk_71 + 171835972*uk_72 + 319529700*uk_73 + 35503300*uk_74 + 742576879*uk_75 + 1380824775*uk_76 + 153424975*uk_77 + 2567649375*uk_78 + 285294375*uk_79 + 25*uk_8 + 31699375*uk_80 + 166375*uk_81 + 60500*uk_82 + 75625*uk_83 + 84700*uk_84 + 366025*uk_85 + 680625*uk_86 + 75625*uk_87 + 22000*uk_88 + 27500*uk_89 + 2572416961*uk_9 + 30800*uk_90 + 133100*uk_91 + 247500*uk_92 + 27500*uk_93 + 34375*uk_94 + 38500*uk_95 + 166375*uk_96 + 309375*uk_97 + 34375*uk_98 + 43120*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 189420*uk_100 + 346500*uk_101 + 30800*uk_102 + 832095*uk_103 + 1522125*uk_104 + 135300*uk_105 + 2784375*uk_106 + 247500*uk_107 + 22000*uk_108 + 79507*uk_109 + 2180917*uk_11 + 36980*uk_110 + 51772*uk_111 + 227427*uk_112 + 416025*uk_113 + 36980*uk_114 + 17200*uk_115 + 24080*uk_116 + 105780*uk_117 + 193500*uk_118 + 17200*uk_119 + 1014380*uk_12 + 33712*uk_120 + 148092*uk_121 + 270900*uk_122 + 24080*uk_123 + 650547*uk_124 + 1190025*uk_125 + 105780*uk_126 + 2176875*uk_127 + 193500*uk_128 + 17200*uk_129 + 1420132*uk_13 + 8000*uk_130 + 11200*uk_131 + 49200*uk_132 + 90000*uk_133 + 8000*uk_134 + 15680*uk_135 + 68880*uk_136 + 126000*uk_137 + 11200*uk_138 + 302580*uk_139 + 6238437*uk_14 + 553500*uk_140 + 49200*uk_141 + 1012500*uk_142 + 90000*uk_143 + 8000*uk_144 + 21952*uk_145 + 96432*uk_146 + 176400*uk_147 + 15680*uk_148 + 423612*uk_149 + 11411775*uk_15 + 774900*uk_150 + 68880*uk_151 + 1417500*uk_152 + 126000*uk_153 + 11200*uk_154 + 1860867*uk_155 + 3404025*uk_156 + 302580*uk_157 + 6226875*uk_158 + 553500*uk_159 + 1014380*uk_16 + 49200*uk_160 + 11390625*uk_161 + 1012500*uk_162 + 90000*uk_163 + 8000*uk_164 + 3025*uk_17 + 2365*uk_18 + 1100*uk_19 + 55*uk_2 + 1540*uk_20 + 6765*uk_21 + 12375*uk_22 + 1100*uk_23 + 1849*uk_24 + 860*uk_25 + 1204*uk_26 + 5289*uk_27 + 9675*uk_28 + 860*uk_29 + 43*uk_3 + 400*uk_30 + 560*uk_31 + 2460*uk_32 + 4500*uk_33 + 400*uk_34 + 784*uk_35 + 3444*uk_36 + 6300*uk_37 + 560*uk_38 + 15129*uk_39 + 20*uk_4 + 27675*uk_40 + 2460*uk_41 + 50625*uk_42 + 4500*uk_43 + 400*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 110613929323*uk_47 + 51448339220*uk_48 + 72027674908*uk_49 + 28*uk_5 + 316407286203*uk_50 + 578793816225*uk_51 + 51448339220*uk_52 + 153424975*uk_53 + 119950435*uk_54 + 55790900*uk_55 + 78107260*uk_56 + 343114035*uk_57 + 627647625*uk_58 + 55790900*uk_59 + 123*uk_6 + 93779431*uk_60 + 43618340*uk_61 + 61065676*uk_62 + 268252791*uk_63 + 490706325*uk_64 + 43618340*uk_65 + 20287600*uk_66 + 28402640*uk_67 + 124768740*uk_68 + 228235500*uk_69 + 225*uk_7 + 20287600*uk_70 + 39763696*uk_71 + 174676236*uk_72 + 319529700*uk_73 + 28402640*uk_74 + 767327751*uk_75 + 1403648325*uk_76 + 124768740*uk_77 + 2567649375*uk_78 + 228235500*uk_79 + 20*uk_8 + 20287600*uk_80 + 166375*uk_81 + 130075*uk_82 + 60500*uk_83 + 84700*uk_84 + 372075*uk_85 + 680625*uk_86 + 60500*uk_87 + 101695*uk_88 + 47300*uk_89 + 2572416961*uk_9 + 66220*uk_90 + 290895*uk_91 + 532125*uk_92 + 47300*uk_93 + 22000*uk_94 + 30800*uk_95 + 135300*uk_96 + 247500*uk_97 + 22000*uk_98 + 43120*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 192500*uk_100 + 346500*uk_101 + 66220*uk_102 + 859375*uk_103 + 1546875*uk_104 + 295625*uk_105 + 2784375*uk_106 + 532125*uk_107 + 101695*uk_108 + 830584*uk_109 + 4767586*uk_11 + 379948*uk_110 + 247408*uk_111 + 1104500*uk_112 + 1988100*uk_113 + 379948*uk_114 + 173806*uk_115 + 113176*uk_116 + 505250*uk_117 + 909450*uk_118 + 173806*uk_119 + 2180917*uk_12 + 73696*uk_120 + 329000*uk_121 + 592200*uk_122 + 113176*uk_123 + 1468750*uk_124 + 2643750*uk_125 + 505250*uk_126 + 4758750*uk_127 + 909450*uk_128 + 173806*uk_129 + 1420132*uk_13 + 79507*uk_130 + 51772*uk_131 + 231125*uk_132 + 416025*uk_133 + 79507*uk_134 + 33712*uk_135 + 150500*uk_136 + 270900*uk_137 + 51772*uk_138 + 671875*uk_139 + 6339875*uk_14 + 1209375*uk_140 + 231125*uk_141 + 2176875*uk_142 + 416025*uk_143 + 79507*uk_144 + 21952*uk_145 + 98000*uk_146 + 176400*uk_147 + 33712*uk_148 + 437500*uk_149 + 11411775*uk_15 + 787500*uk_150 + 150500*uk_151 + 1417500*uk_152 + 270900*uk_153 + 51772*uk_154 + 1953125*uk_155 + 3515625*uk_156 + 671875*uk_157 + 6328125*uk_158 + 1209375*uk_159 + 2180917*uk_16 + 231125*uk_160 + 11390625*uk_161 + 2176875*uk_162 + 416025*uk_163 + 79507*uk_164 + 3025*uk_17 + 5170*uk_18 + 2365*uk_19 + 55*uk_2 + 1540*uk_20 + 6875*uk_21 + 12375*uk_22 + 2365*uk_23 + 8836*uk_24 + 4042*uk_25 + 2632*uk_26 + 11750*uk_27 + 21150*uk_28 + 4042*uk_29 + 94*uk_3 + 1849*uk_30 + 1204*uk_31 + 5375*uk_32 + 9675*uk_33 + 1849*uk_34 + 784*uk_35 + 3500*uk_36 + 6300*uk_37 + 1204*uk_38 + 15625*uk_39 + 43*uk_4 + 28125*uk_40 + 5375*uk_41 + 50625*uk_42 + 9675*uk_43 + 1849*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 241807194334*uk_47 + 110613929323*uk_48 + 72027674908*uk_49 + 28*uk_5 + 321552120125*uk_50 + 578793816225*uk_51 + 110613929323*uk_52 + 153424975*uk_53 + 262217230*uk_54 + 119950435*uk_55 + 78107260*uk_56 + 348693125*uk_57 + 627647625*uk_58 + 119950435*uk_59 + 125*uk_6 + 448153084*uk_60 + 205006198*uk_61 + 133492408*uk_62 + 595948250*uk_63 + 1072706850*uk_64 + 205006198*uk_65 + 93779431*uk_66 + 61065676*uk_67 + 272614625*uk_68 + 490706325*uk_69 + 225*uk_7 + 93779431*uk_70 + 39763696*uk_71 + 177516500*uk_72 + 319529700*uk_73 + 61065676*uk_74 + 792484375*uk_75 + 1426471875*uk_76 + 272614625*uk_77 + 2567649375*uk_78 + 490706325*uk_79 + 43*uk_8 + 93779431*uk_80 + 166375*uk_81 + 284350*uk_82 + 130075*uk_83 + 84700*uk_84 + 378125*uk_85 + 680625*uk_86 + 130075*uk_87 + 485980*uk_88 + 222310*uk_89 + 2572416961*uk_9 + 144760*uk_90 + 646250*uk_91 + 1163250*uk_92 + 222310*uk_93 + 101695*uk_94 + 66220*uk_95 + 295625*uk_96 + 532125*uk_97 + 101695*uk_98 + 43120*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 167640*uk_100 + 297000*uk_101 + 124080*uk_102 + 887095*uk_103 + 1571625*uk_104 + 656590*uk_105 + 2784375*uk_106 + 1163250*uk_107 + 485980*uk_108 + 97336*uk_109 + 2333074*uk_11 + 198904*uk_110 + 50784*uk_111 + 268732*uk_112 + 476100*uk_113 + 198904*uk_114 + 406456*uk_115 + 103776*uk_116 + 549148*uk_117 + 972900*uk_118 + 406456*uk_119 + 4767586*uk_12 + 26496*uk_120 + 140208*uk_121 + 248400*uk_122 + 103776*uk_123 + 741934*uk_124 + 1314450*uk_125 + 549148*uk_126 + 2328750*uk_127 + 972900*uk_128 + 406456*uk_129 + 1217256*uk_13 + 830584*uk_130 + 212064*uk_131 + 1122172*uk_132 + 1988100*uk_133 + 830584*uk_134 + 54144*uk_135 + 286512*uk_136 + 507600*uk_137 + 212064*uk_138 + 1516126*uk_139 + 6441313*uk_14 + 2686050*uk_140 + 1122172*uk_141 + 4758750*uk_142 + 1988100*uk_143 + 830584*uk_144 + 13824*uk_145 + 73152*uk_146 + 129600*uk_147 + 54144*uk_148 + 387096*uk_149 + 11411775*uk_15 + 685800*uk_150 + 286512*uk_151 + 1215000*uk_152 + 507600*uk_153 + 212064*uk_154 + 2048383*uk_155 + 3629025*uk_156 + 1516126*uk_157 + 6429375*uk_158 + 2686050*uk_159 + 4767586*uk_16 + 1122172*uk_160 + 11390625*uk_161 + 4758750*uk_162 + 1988100*uk_163 + 830584*uk_164 + 3025*uk_17 + 2530*uk_18 + 5170*uk_19 + 55*uk_2 + 1320*uk_20 + 6985*uk_21 + 12375*uk_22 + 5170*uk_23 + 2116*uk_24 + 4324*uk_25 + 1104*uk_26 + 5842*uk_27 + 10350*uk_28 + 4324*uk_29 + 46*uk_3 + 8836*uk_30 + 2256*uk_31 + 11938*uk_32 + 21150*uk_33 + 8836*uk_34 + 576*uk_35 + 3048*uk_36 + 5400*uk_37 + 2256*uk_38 + 16129*uk_39 + 94*uk_4 + 28575*uk_40 + 11938*uk_41 + 50625*uk_42 + 21150*uk_43 + 8836*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 118331180206*uk_47 + 241807194334*uk_48 + 61738007064*uk_49 + 24*uk_5 + 326696954047*uk_50 + 578793816225*uk_51 + 241807194334*uk_52 + 153424975*uk_53 + 128319070*uk_54 + 262217230*uk_55 + 66949080*uk_56 + 354272215*uk_57 + 627647625*uk_58 + 262217230*uk_59 + 127*uk_6 + 107321404*uk_60 + 219308956*uk_61 + 55993776*uk_62 + 296300398*uk_63 + 524941650*uk_64 + 219308956*uk_65 + 448153084*uk_66 + 114422064*uk_67 + 605483422*uk_68 + 1072706850*uk_69 + 225*uk_7 + 448153084*uk_70 + 29214144*uk_71 + 154591512*uk_72 + 273882600*uk_73 + 114422064*uk_74 + 818046751*uk_75 + 1449295425*uk_76 + 605483422*uk_77 + 2567649375*uk_78 + 1072706850*uk_79 + 94*uk_8 + 448153084*uk_80 + 166375*uk_81 + 139150*uk_82 + 284350*uk_83 + 72600*uk_84 + 384175*uk_85 + 680625*uk_86 + 284350*uk_87 + 116380*uk_88 + 237820*uk_89 + 2572416961*uk_9 + 60720*uk_90 + 321310*uk_91 + 569250*uk_92 + 237820*uk_93 + 485980*uk_94 + 124080*uk_95 + 656590*uk_96 + 1163250*uk_97 + 485980*uk_98 + 31680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 170280*uk_100 + 297000*uk_101 + 60720*uk_102 + 915255*uk_103 + 1596375*uk_104 + 326370*uk_105 + 2784375*uk_106 + 569250*uk_107 + 116380*uk_108 + 10648*uk_109 + 1115818*uk_11 + 22264*uk_110 + 11616*uk_111 + 62436*uk_112 + 108900*uk_113 + 22264*uk_114 + 46552*uk_115 + 24288*uk_116 + 130548*uk_117 + 227700*uk_118 + 46552*uk_119 + 2333074*uk_12 + 12672*uk_120 + 68112*uk_121 + 118800*uk_122 + 24288*uk_123 + 366102*uk_124 + 638550*uk_125 + 130548*uk_126 + 1113750*uk_127 + 227700*uk_128 + 46552*uk_129 + 1217256*uk_13 + 97336*uk_130 + 50784*uk_131 + 272964*uk_132 + 476100*uk_133 + 97336*uk_134 + 26496*uk_135 + 142416*uk_136 + 248400*uk_137 + 50784*uk_138 + 765486*uk_139 + 6542751*uk_14 + 1335150*uk_140 + 272964*uk_141 + 2328750*uk_142 + 476100*uk_143 + 97336*uk_144 + 13824*uk_145 + 74304*uk_146 + 129600*uk_147 + 26496*uk_148 + 399384*uk_149 + 11411775*uk_15 + 696600*uk_150 + 142416*uk_151 + 1215000*uk_152 + 248400*uk_153 + 50784*uk_154 + 2146689*uk_155 + 3744225*uk_156 + 765486*uk_157 + 6530625*uk_158 + 1335150*uk_159 + 2333074*uk_16 + 272964*uk_160 + 11390625*uk_161 + 2328750*uk_162 + 476100*uk_163 + 97336*uk_164 + 3025*uk_17 + 1210*uk_18 + 2530*uk_19 + 55*uk_2 + 1320*uk_20 + 7095*uk_21 + 12375*uk_22 + 2530*uk_23 + 484*uk_24 + 1012*uk_25 + 528*uk_26 + 2838*uk_27 + 4950*uk_28 + 1012*uk_29 + 22*uk_3 + 2116*uk_30 + 1104*uk_31 + 5934*uk_32 + 10350*uk_33 + 2116*uk_34 + 576*uk_35 + 3096*uk_36 + 5400*uk_37 + 1104*uk_38 + 16641*uk_39 + 46*uk_4 + 29025*uk_40 + 5934*uk_41 + 50625*uk_42 + 10350*uk_43 + 2116*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 56593173142*uk_47 + 118331180206*uk_48 + 61738007064*uk_49 + 24*uk_5 + 331841787969*uk_50 + 578793816225*uk_51 + 118331180206*uk_52 + 153424975*uk_53 + 61369990*uk_54 + 128319070*uk_55 + 66949080*uk_56 + 359851305*uk_57 + 627647625*uk_58 + 128319070*uk_59 + 129*uk_6 + 24547996*uk_60 + 51327628*uk_61 + 26779632*uk_62 + 143940522*uk_63 + 251059050*uk_64 + 51327628*uk_65 + 107321404*uk_66 + 55993776*uk_67 + 300966546*uk_68 + 524941650*uk_69 + 225*uk_7 + 107321404*uk_70 + 29214144*uk_71 + 157026024*uk_72 + 273882600*uk_73 + 55993776*uk_74 + 844014879*uk_75 + 1472118975*uk_76 + 300966546*uk_77 + 2567649375*uk_78 + 524941650*uk_79 + 46*uk_8 + 107321404*uk_80 + 166375*uk_81 + 66550*uk_82 + 139150*uk_83 + 72600*uk_84 + 390225*uk_85 + 680625*uk_86 + 139150*uk_87 + 26620*uk_88 + 55660*uk_89 + 2572416961*uk_9 + 29040*uk_90 + 156090*uk_91 + 272250*uk_92 + 55660*uk_93 + 116380*uk_94 + 60720*uk_95 + 326370*uk_96 + 569250*uk_97 + 116380*uk_98 + 31680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 172920*uk_100 + 297000*uk_101 + 29040*uk_102 + 943855*uk_103 + 1621125*uk_104 + 158510*uk_105 + 2784375*uk_106 + 272250*uk_107 + 26620*uk_108 + 10648*uk_109 + 1115818*uk_11 + 10648*uk_110 + 11616*uk_111 + 63404*uk_112 + 108900*uk_113 + 10648*uk_114 + 10648*uk_115 + 11616*uk_116 + 63404*uk_117 + 108900*uk_118 + 10648*uk_119 + 1115818*uk_12 + 12672*uk_120 + 69168*uk_121 + 118800*uk_122 + 11616*uk_123 + 377542*uk_124 + 648450*uk_125 + 63404*uk_126 + 1113750*uk_127 + 108900*uk_128 + 10648*uk_129 + 1217256*uk_13 + 10648*uk_130 + 11616*uk_131 + 63404*uk_132 + 108900*uk_133 + 10648*uk_134 + 12672*uk_135 + 69168*uk_136 + 118800*uk_137 + 11616*uk_138 + 377542*uk_139 + 6644189*uk_14 + 648450*uk_140 + 63404*uk_141 + 1113750*uk_142 + 108900*uk_143 + 10648*uk_144 + 13824*uk_145 + 75456*uk_146 + 129600*uk_147 + 12672*uk_148 + 411864*uk_149 + 11411775*uk_15 + 707400*uk_150 + 69168*uk_151 + 1215000*uk_152 + 118800*uk_153 + 11616*uk_154 + 2248091*uk_155 + 3861225*uk_156 + 377542*uk_157 + 6631875*uk_158 + 648450*uk_159 + 1115818*uk_16 + 63404*uk_160 + 11390625*uk_161 + 1113750*uk_162 + 108900*uk_163 + 10648*uk_164 + 3025*uk_17 + 1210*uk_18 + 1210*uk_19 + 55*uk_2 + 1320*uk_20 + 7205*uk_21 + 12375*uk_22 + 1210*uk_23 + 484*uk_24 + 484*uk_25 + 528*uk_26 + 2882*uk_27 + 4950*uk_28 + 484*uk_29 + 22*uk_3 + 484*uk_30 + 528*uk_31 + 2882*uk_32 + 4950*uk_33 + 484*uk_34 + 576*uk_35 + 3144*uk_36 + 5400*uk_37 + 528*uk_38 + 17161*uk_39 + 22*uk_4 + 29475*uk_40 + 2882*uk_41 + 50625*uk_42 + 4950*uk_43 + 484*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 56593173142*uk_47 + 56593173142*uk_48 + 61738007064*uk_49 + 24*uk_5 + 336986621891*uk_50 + 578793816225*uk_51 + 56593173142*uk_52 + 153424975*uk_53 + 61369990*uk_54 + 61369990*uk_55 + 66949080*uk_56 + 365430395*uk_57 + 627647625*uk_58 + 61369990*uk_59 + 131*uk_6 + 24547996*uk_60 + 24547996*uk_61 + 26779632*uk_62 + 146172158*uk_63 + 251059050*uk_64 + 24547996*uk_65 + 24547996*uk_66 + 26779632*uk_67 + 146172158*uk_68 + 251059050*uk_69 + 225*uk_7 + 24547996*uk_70 + 29214144*uk_71 + 159460536*uk_72 + 273882600*uk_73 + 26779632*uk_74 + 870388759*uk_75 + 1494942525*uk_76 + 146172158*uk_77 + 2567649375*uk_78 + 251059050*uk_79 + 22*uk_8 + 24547996*uk_80 + 166375*uk_81 + 66550*uk_82 + 66550*uk_83 + 72600*uk_84 + 396275*uk_85 + 680625*uk_86 + 66550*uk_87 + 26620*uk_88 + 26620*uk_89 + 2572416961*uk_9 + 29040*uk_90 + 158510*uk_91 + 272250*uk_92 + 26620*uk_93 + 26620*uk_94 + 29040*uk_95 + 158510*uk_96 + 272250*uk_97 + 26620*uk_98 + 31680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 175560*uk_100 + 297000*uk_101 + 29040*uk_102 + 972895*uk_103 + 1645875*uk_104 + 160930*uk_105 + 2784375*uk_106 + 272250*uk_107 + 26620*uk_108 + 97336*uk_109 + 2333074*uk_11 + 46552*uk_110 + 50784*uk_111 + 281428*uk_112 + 476100*uk_113 + 46552*uk_114 + 22264*uk_115 + 24288*uk_116 + 134596*uk_117 + 227700*uk_118 + 22264*uk_119 + 1115818*uk_12 + 26496*uk_120 + 146832*uk_121 + 248400*uk_122 + 24288*uk_123 + 813694*uk_124 + 1376550*uk_125 + 134596*uk_126 + 2328750*uk_127 + 227700*uk_128 + 22264*uk_129 + 1217256*uk_13 + 10648*uk_130 + 11616*uk_131 + 64372*uk_132 + 108900*uk_133 + 10648*uk_134 + 12672*uk_135 + 70224*uk_136 + 118800*uk_137 + 11616*uk_138 + 389158*uk_139 + 6745627*uk_14 + 658350*uk_140 + 64372*uk_141 + 1113750*uk_142 + 108900*uk_143 + 10648*uk_144 + 13824*uk_145 + 76608*uk_146 + 129600*uk_147 + 12672*uk_148 + 424536*uk_149 + 11411775*uk_15 + 718200*uk_150 + 70224*uk_151 + 1215000*uk_152 + 118800*uk_153 + 11616*uk_154 + 2352637*uk_155 + 3980025*uk_156 + 389158*uk_157 + 6733125*uk_158 + 658350*uk_159 + 1115818*uk_16 + 64372*uk_160 + 11390625*uk_161 + 1113750*uk_162 + 108900*uk_163 + 10648*uk_164 + 3025*uk_17 + 2530*uk_18 + 1210*uk_19 + 55*uk_2 + 1320*uk_20 + 7315*uk_21 + 12375*uk_22 + 1210*uk_23 + 2116*uk_24 + 1012*uk_25 + 1104*uk_26 + 6118*uk_27 + 10350*uk_28 + 1012*uk_29 + 46*uk_3 + 484*uk_30 + 528*uk_31 + 2926*uk_32 + 4950*uk_33 + 484*uk_34 + 576*uk_35 + 3192*uk_36 + 5400*uk_37 + 528*uk_38 + 17689*uk_39 + 22*uk_4 + 29925*uk_40 + 2926*uk_41 + 50625*uk_42 + 4950*uk_43 + 484*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 118331180206*uk_47 + 56593173142*uk_48 + 61738007064*uk_49 + 24*uk_5 + 342131455813*uk_50 + 578793816225*uk_51 + 56593173142*uk_52 + 153424975*uk_53 + 128319070*uk_54 + 61369990*uk_55 + 66949080*uk_56 + 371009485*uk_57 + 627647625*uk_58 + 61369990*uk_59 + 133*uk_6 + 107321404*uk_60 + 51327628*uk_61 + 55993776*uk_62 + 310298842*uk_63 + 524941650*uk_64 + 51327628*uk_65 + 24547996*uk_66 + 26779632*uk_67 + 148403794*uk_68 + 251059050*uk_69 + 225*uk_7 + 24547996*uk_70 + 29214144*uk_71 + 161895048*uk_72 + 273882600*uk_73 + 26779632*uk_74 + 897168391*uk_75 + 1517766075*uk_76 + 148403794*uk_77 + 2567649375*uk_78 + 251059050*uk_79 + 22*uk_8 + 24547996*uk_80 + 166375*uk_81 + 139150*uk_82 + 66550*uk_83 + 72600*uk_84 + 402325*uk_85 + 680625*uk_86 + 66550*uk_87 + 116380*uk_88 + 55660*uk_89 + 2572416961*uk_9 + 60720*uk_90 + 336490*uk_91 + 569250*uk_92 + 55660*uk_93 + 26620*uk_94 + 29040*uk_95 + 160930*uk_96 + 272250*uk_97 + 26620*uk_98 + 31680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 178200*uk_100 + 297000*uk_101 + 60720*uk_102 + 1002375*uk_103 + 1670625*uk_104 + 341550*uk_105 + 2784375*uk_106 + 569250*uk_107 + 116380*uk_108 + 830584*uk_109 + 4767586*uk_11 + 406456*uk_110 + 212064*uk_111 + 1192860*uk_112 + 1988100*uk_113 + 406456*uk_114 + 198904*uk_115 + 103776*uk_116 + 583740*uk_117 + 972900*uk_118 + 198904*uk_119 + 2333074*uk_12 + 54144*uk_120 + 304560*uk_121 + 507600*uk_122 + 103776*uk_123 + 1713150*uk_124 + 2855250*uk_125 + 583740*uk_126 + 4758750*uk_127 + 972900*uk_128 + 198904*uk_129 + 1217256*uk_13 + 97336*uk_130 + 50784*uk_131 + 285660*uk_132 + 476100*uk_133 + 97336*uk_134 + 26496*uk_135 + 149040*uk_136 + 248400*uk_137 + 50784*uk_138 + 838350*uk_139 + 6847065*uk_14 + 1397250*uk_140 + 285660*uk_141 + 2328750*uk_142 + 476100*uk_143 + 97336*uk_144 + 13824*uk_145 + 77760*uk_146 + 129600*uk_147 + 26496*uk_148 + 437400*uk_149 + 11411775*uk_15 + 729000*uk_150 + 149040*uk_151 + 1215000*uk_152 + 248400*uk_153 + 50784*uk_154 + 2460375*uk_155 + 4100625*uk_156 + 838350*uk_157 + 6834375*uk_158 + 1397250*uk_159 + 2333074*uk_16 + 285660*uk_160 + 11390625*uk_161 + 2328750*uk_162 + 476100*uk_163 + 97336*uk_164 + 3025*uk_17 + 5170*uk_18 + 2530*uk_19 + 55*uk_2 + 1320*uk_20 + 7425*uk_21 + 12375*uk_22 + 2530*uk_23 + 8836*uk_24 + 4324*uk_25 + 2256*uk_26 + 12690*uk_27 + 21150*uk_28 + 4324*uk_29 + 94*uk_3 + 2116*uk_30 + 1104*uk_31 + 6210*uk_32 + 10350*uk_33 + 2116*uk_34 + 576*uk_35 + 3240*uk_36 + 5400*uk_37 + 1104*uk_38 + 18225*uk_39 + 46*uk_4 + 30375*uk_40 + 6210*uk_41 + 50625*uk_42 + 10350*uk_43 + 2116*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 241807194334*uk_47 + 118331180206*uk_48 + 61738007064*uk_49 + 24*uk_5 + 347276289735*uk_50 + 578793816225*uk_51 + 118331180206*uk_52 + 153424975*uk_53 + 262217230*uk_54 + 128319070*uk_55 + 66949080*uk_56 + 376588575*uk_57 + 627647625*uk_58 + 128319070*uk_59 + 135*uk_6 + 448153084*uk_60 + 219308956*uk_61 + 114422064*uk_62 + 643624110*uk_63 + 1072706850*uk_64 + 219308956*uk_65 + 107321404*uk_66 + 55993776*uk_67 + 314964990*uk_68 + 524941650*uk_69 + 225*uk_7 + 107321404*uk_70 + 29214144*uk_71 + 164329560*uk_72 + 273882600*uk_73 + 55993776*uk_74 + 924353775*uk_75 + 1540589625*uk_76 + 314964990*uk_77 + 2567649375*uk_78 + 524941650*uk_79 + 46*uk_8 + 107321404*uk_80 + 166375*uk_81 + 284350*uk_82 + 139150*uk_83 + 72600*uk_84 + 408375*uk_85 + 680625*uk_86 + 139150*uk_87 + 485980*uk_88 + 237820*uk_89 + 2572416961*uk_9 + 124080*uk_90 + 697950*uk_91 + 1163250*uk_92 + 237820*uk_93 + 116380*uk_94 + 60720*uk_95 + 341550*uk_96 + 569250*uk_97 + 116380*uk_98 + 31680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 150700*uk_100 + 247500*uk_101 + 103400*uk_102 + 1032295*uk_103 + 1695375*uk_104 + 708290*uk_105 + 2784375*uk_106 + 1163250*uk_107 + 485980*uk_108 + 24389*uk_109 + 1470851*uk_11 + 79054*uk_110 + 16820*uk_111 + 115217*uk_112 + 189225*uk_113 + 79054*uk_114 + 256244*uk_115 + 54520*uk_116 + 373462*uk_117 + 613350*uk_118 + 256244*uk_119 + 4767586*uk_12 + 11600*uk_120 + 79460*uk_121 + 130500*uk_122 + 54520*uk_123 + 544301*uk_124 + 893925*uk_125 + 373462*uk_126 + 1468125*uk_127 + 613350*uk_128 + 256244*uk_129 + 1014380*uk_13 + 830584*uk_130 + 176720*uk_131 + 1210532*uk_132 + 1988100*uk_133 + 830584*uk_134 + 37600*uk_135 + 257560*uk_136 + 423000*uk_137 + 176720*uk_138 + 1764286*uk_139 + 6948503*uk_14 + 2897550*uk_140 + 1210532*uk_141 + 4758750*uk_142 + 1988100*uk_143 + 830584*uk_144 + 8000*uk_145 + 54800*uk_146 + 90000*uk_147 + 37600*uk_148 + 375380*uk_149 + 11411775*uk_15 + 616500*uk_150 + 257560*uk_151 + 1012500*uk_152 + 423000*uk_153 + 176720*uk_154 + 2571353*uk_155 + 4223025*uk_156 + 1764286*uk_157 + 6935625*uk_158 + 2897550*uk_159 + 4767586*uk_16 + 1210532*uk_160 + 11390625*uk_161 + 4758750*uk_162 + 1988100*uk_163 + 830584*uk_164 + 3025*uk_17 + 1595*uk_18 + 5170*uk_19 + 55*uk_2 + 1100*uk_20 + 7535*uk_21 + 12375*uk_22 + 5170*uk_23 + 841*uk_24 + 2726*uk_25 + 580*uk_26 + 3973*uk_27 + 6525*uk_28 + 2726*uk_29 + 29*uk_3 + 8836*uk_30 + 1880*uk_31 + 12878*uk_32 + 21150*uk_33 + 8836*uk_34 + 400*uk_35 + 2740*uk_36 + 4500*uk_37 + 1880*uk_38 + 18769*uk_39 + 94*uk_4 + 30825*uk_40 + 12878*uk_41 + 50625*uk_42 + 21150*uk_43 + 8836*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 74600091869*uk_47 + 241807194334*uk_48 + 51448339220*uk_49 + 20*uk_5 + 352421123657*uk_50 + 578793816225*uk_51 + 241807194334*uk_52 + 153424975*uk_53 + 80896805*uk_54 + 262217230*uk_55 + 55790900*uk_56 + 382167665*uk_57 + 627647625*uk_58 + 262217230*uk_59 + 137*uk_6 + 42654679*uk_60 + 138259994*uk_61 + 29417020*uk_62 + 201506587*uk_63 + 330941475*uk_64 + 138259994*uk_65 + 448153084*uk_66 + 95351720*uk_67 + 653159282*uk_68 + 1072706850*uk_69 + 225*uk_7 + 448153084*uk_70 + 20287600*uk_71 + 138970060*uk_72 + 228235500*uk_73 + 95351720*uk_74 + 951944911*uk_75 + 1563413175*uk_76 + 653159282*uk_77 + 2567649375*uk_78 + 1072706850*uk_79 + 94*uk_8 + 448153084*uk_80 + 166375*uk_81 + 87725*uk_82 + 284350*uk_83 + 60500*uk_84 + 414425*uk_85 + 680625*uk_86 + 284350*uk_87 + 46255*uk_88 + 149930*uk_89 + 2572416961*uk_9 + 31900*uk_90 + 218515*uk_91 + 358875*uk_92 + 149930*uk_93 + 485980*uk_94 + 103400*uk_95 + 708290*uk_96 + 1163250*uk_97 + 485980*uk_98 + 22000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 183480*uk_100 + 297000*uk_101 + 38280*uk_102 + 1062655*uk_103 + 1720125*uk_104 + 221705*uk_105 + 2784375*uk_106 + 358875*uk_107 + 46255*uk_108 + 1860867*uk_109 + 6238437*uk_11 + 438741*uk_110 + 363096*uk_111 + 2102931*uk_112 + 3404025*uk_113 + 438741*uk_114 + 103443*uk_115 + 85608*uk_116 + 495813*uk_117 + 802575*uk_118 + 103443*uk_119 + 1470851*uk_12 + 70848*uk_120 + 410328*uk_121 + 664200*uk_122 + 85608*uk_123 + 2376483*uk_124 + 3846825*uk_125 + 495813*uk_126 + 6226875*uk_127 + 802575*uk_128 + 103443*uk_129 + 1217256*uk_13 + 24389*uk_130 + 20184*uk_131 + 116899*uk_132 + 189225*uk_133 + 24389*uk_134 + 16704*uk_135 + 96744*uk_136 + 156600*uk_137 + 20184*uk_138 + 560309*uk_139 + 7049941*uk_14 + 906975*uk_140 + 116899*uk_141 + 1468125*uk_142 + 189225*uk_143 + 24389*uk_144 + 13824*uk_145 + 80064*uk_146 + 129600*uk_147 + 16704*uk_148 + 463704*uk_149 + 11411775*uk_15 + 750600*uk_150 + 96744*uk_151 + 1215000*uk_152 + 156600*uk_153 + 20184*uk_154 + 2685619*uk_155 + 4347225*uk_156 + 560309*uk_157 + 7036875*uk_158 + 906975*uk_159 + 1470851*uk_16 + 116899*uk_160 + 11390625*uk_161 + 1468125*uk_162 + 189225*uk_163 + 24389*uk_164 + 3025*uk_17 + 6765*uk_18 + 1595*uk_19 + 55*uk_2 + 1320*uk_20 + 7645*uk_21 + 12375*uk_22 + 1595*uk_23 + 15129*uk_24 + 3567*uk_25 + 2952*uk_26 + 17097*uk_27 + 27675*uk_28 + 3567*uk_29 + 123*uk_3 + 841*uk_30 + 696*uk_31 + 4031*uk_32 + 6525*uk_33 + 841*uk_34 + 576*uk_35 + 3336*uk_36 + 5400*uk_37 + 696*uk_38 + 19321*uk_39 + 29*uk_4 + 31275*uk_40 + 4031*uk_41 + 50625*uk_42 + 6525*uk_43 + 841*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 316407286203*uk_47 + 74600091869*uk_48 + 61738007064*uk_49 + 24*uk_5 + 357565957579*uk_50 + 578793816225*uk_51 + 74600091869*uk_52 + 153424975*uk_53 + 343114035*uk_54 + 80896805*uk_55 + 66949080*uk_56 + 387746755*uk_57 + 627647625*uk_58 + 80896805*uk_59 + 139*uk_6 + 767327751*uk_60 + 180914673*uk_61 + 149722488*uk_62 + 867142743*uk_63 + 1403648325*uk_64 + 180914673*uk_65 + 42654679*uk_66 + 35300424*uk_67 + 204448289*uk_68 + 330941475*uk_69 + 225*uk_7 + 42654679*uk_70 + 29214144*uk_71 + 169198584*uk_72 + 273882600*uk_73 + 35300424*uk_74 + 979941799*uk_75 + 1586236725*uk_76 + 204448289*uk_77 + 2567649375*uk_78 + 330941475*uk_79 + 29*uk_8 + 42654679*uk_80 + 166375*uk_81 + 372075*uk_82 + 87725*uk_83 + 72600*uk_84 + 420475*uk_85 + 680625*uk_86 + 87725*uk_87 + 832095*uk_88 + 196185*uk_89 + 2572416961*uk_9 + 162360*uk_90 + 940335*uk_91 + 1522125*uk_92 + 196185*uk_93 + 46255*uk_94 + 38280*uk_95 + 221705*uk_96 + 358875*uk_97 + 46255*uk_98 + 31680*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 155100*uk_100 + 247500*uk_101 + 135300*uk_102 + 1093455*uk_103 + 1744875*uk_104 + 953865*uk_105 + 2784375*uk_106 + 1522125*uk_107 + 832095*uk_108 + 1000000*uk_109 + 5071900*uk_11 + 1230000*uk_110 + 200000*uk_111 + 1410000*uk_112 + 2250000*uk_113 + 1230000*uk_114 + 1512900*uk_115 + 246000*uk_116 + 1734300*uk_117 + 2767500*uk_118 + 1512900*uk_119 + 6238437*uk_12 + 40000*uk_120 + 282000*uk_121 + 450000*uk_122 + 246000*uk_123 + 1988100*uk_124 + 3172500*uk_125 + 1734300*uk_126 + 5062500*uk_127 + 2767500*uk_128 + 1512900*uk_129 + 1014380*uk_13 + 1860867*uk_130 + 302580*uk_131 + 2133189*uk_132 + 3404025*uk_133 + 1860867*uk_134 + 49200*uk_135 + 346860*uk_136 + 553500*uk_137 + 302580*uk_138 + 2445363*uk_139 + 7151379*uk_14 + 3902175*uk_140 + 2133189*uk_141 + 6226875*uk_142 + 3404025*uk_143 + 1860867*uk_144 + 8000*uk_145 + 56400*uk_146 + 90000*uk_147 + 49200*uk_148 + 397620*uk_149 + 11411775*uk_15 + 634500*uk_150 + 346860*uk_151 + 1012500*uk_152 + 553500*uk_153 + 302580*uk_154 + 2803221*uk_155 + 4473225*uk_156 + 2445363*uk_157 + 7138125*uk_158 + 3902175*uk_159 + 6238437*uk_16 + 2133189*uk_160 + 11390625*uk_161 + 6226875*uk_162 + 3404025*uk_163 + 1860867*uk_164 + 3025*uk_17 + 5500*uk_18 + 6765*uk_19 + 55*uk_2 + 1100*uk_20 + 7755*uk_21 + 12375*uk_22 + 6765*uk_23 + 10000*uk_24 + 12300*uk_25 + 2000*uk_26 + 14100*uk_27 + 22500*uk_28 + 12300*uk_29 + 100*uk_3 + 15129*uk_30 + 2460*uk_31 + 17343*uk_32 + 27675*uk_33 + 15129*uk_34 + 400*uk_35 + 2820*uk_36 + 4500*uk_37 + 2460*uk_38 + 19881*uk_39 + 123*uk_4 + 31725*uk_40 + 17343*uk_41 + 50625*uk_42 + 27675*uk_43 + 15129*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 257241696100*uk_47 + 316407286203*uk_48 + 51448339220*uk_49 + 20*uk_5 + 362710791501*uk_50 + 578793816225*uk_51 + 316407286203*uk_52 + 153424975*uk_53 + 278954500*uk_54 + 343114035*uk_55 + 55790900*uk_56 + 393325845*uk_57 + 627647625*uk_58 + 343114035*uk_59 + 141*uk_6 + 507190000*uk_60 + 623843700*uk_61 + 101438000*uk_62 + 715137900*uk_63 + 1141177500*uk_64 + 623843700*uk_65 + 767327751*uk_66 + 124768740*uk_67 + 879619617*uk_68 + 1403648325*uk_69 + 225*uk_7 + 767327751*uk_70 + 20287600*uk_71 + 143027580*uk_72 + 228235500*uk_73 + 124768740*uk_74 + 1008344439*uk_75 + 1609060275*uk_76 + 879619617*uk_77 + 2567649375*uk_78 + 1403648325*uk_79 + 123*uk_8 + 767327751*uk_80 + 166375*uk_81 + 302500*uk_82 + 372075*uk_83 + 60500*uk_84 + 426525*uk_85 + 680625*uk_86 + 372075*uk_87 + 550000*uk_88 + 676500*uk_89 + 2572416961*uk_9 + 110000*uk_90 + 775500*uk_91 + 1237500*uk_92 + 676500*uk_93 + 832095*uk_94 + 135300*uk_95 + 953865*uk_96 + 1522125*uk_97 + 832095*uk_98 + 22000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 157300*uk_100 + 247500*uk_101 + 110000*uk_102 + 1124695*uk_103 + 1769625*uk_104 + 786500*uk_105 + 2784375*uk_106 + 1237500*uk_107 + 550000*uk_108 + 912673*uk_109 + 4919743*uk_11 + 940900*uk_110 + 188180*uk_111 + 1345487*uk_112 + 2117025*uk_113 + 940900*uk_114 + 970000*uk_115 + 194000*uk_116 + 1387100*uk_117 + 2182500*uk_118 + 970000*uk_119 + 5071900*uk_12 + 38800*uk_120 + 277420*uk_121 + 436500*uk_122 + 194000*uk_123 + 1983553*uk_124 + 3120975*uk_125 + 1387100*uk_126 + 4910625*uk_127 + 2182500*uk_128 + 970000*uk_129 + 1014380*uk_13 + 1000000*uk_130 + 200000*uk_131 + 1430000*uk_132 + 2250000*uk_133 + 1000000*uk_134 + 40000*uk_135 + 286000*uk_136 + 450000*uk_137 + 200000*uk_138 + 2044900*uk_139 + 7252817*uk_14 + 3217500*uk_140 + 1430000*uk_141 + 5062500*uk_142 + 2250000*uk_143 + 1000000*uk_144 + 8000*uk_145 + 57200*uk_146 + 90000*uk_147 + 40000*uk_148 + 408980*uk_149 + 11411775*uk_15 + 643500*uk_150 + 286000*uk_151 + 1012500*uk_152 + 450000*uk_153 + 200000*uk_154 + 2924207*uk_155 + 4601025*uk_156 + 2044900*uk_157 + 7239375*uk_158 + 3217500*uk_159 + 5071900*uk_16 + 1430000*uk_160 + 11390625*uk_161 + 5062500*uk_162 + 2250000*uk_163 + 1000000*uk_164 + 3025*uk_17 + 5335*uk_18 + 5500*uk_19 + 55*uk_2 + 1100*uk_20 + 7865*uk_21 + 12375*uk_22 + 5500*uk_23 + 9409*uk_24 + 9700*uk_25 + 1940*uk_26 + 13871*uk_27 + 21825*uk_28 + 9700*uk_29 + 97*uk_3 + 10000*uk_30 + 2000*uk_31 + 14300*uk_32 + 22500*uk_33 + 10000*uk_34 + 400*uk_35 + 2860*uk_36 + 4500*uk_37 + 2000*uk_38 + 20449*uk_39 + 100*uk_4 + 32175*uk_40 + 14300*uk_41 + 50625*uk_42 + 22500*uk_43 + 10000*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 249524445217*uk_47 + 257241696100*uk_48 + 51448339220*uk_49 + 20*uk_5 + 367855625423*uk_50 + 578793816225*uk_51 + 257241696100*uk_52 + 153424975*uk_53 + 270585865*uk_54 + 278954500*uk_55 + 55790900*uk_56 + 398904935*uk_57 + 627647625*uk_58 + 278954500*uk_59 + 143*uk_6 + 477215071*uk_60 + 491974300*uk_61 + 98394860*uk_62 + 703523249*uk_63 + 1106942175*uk_64 + 491974300*uk_65 + 507190000*uk_66 + 101438000*uk_67 + 725281700*uk_68 + 1141177500*uk_69 + 225*uk_7 + 507190000*uk_70 + 20287600*uk_71 + 145056340*uk_72 + 228235500*uk_73 + 101438000*uk_74 + 1037152831*uk_75 + 1631883825*uk_76 + 725281700*uk_77 + 2567649375*uk_78 + 1141177500*uk_79 + 100*uk_8 + 507190000*uk_80 + 166375*uk_81 + 293425*uk_82 + 302500*uk_83 + 60500*uk_84 + 432575*uk_85 + 680625*uk_86 + 302500*uk_87 + 517495*uk_88 + 533500*uk_89 + 2572416961*uk_9 + 106700*uk_90 + 762905*uk_91 + 1200375*uk_92 + 533500*uk_93 + 550000*uk_94 + 110000*uk_95 + 786500*uk_96 + 1237500*uk_97 + 550000*uk_98 + 22000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 159500*uk_100 + 247500*uk_101 + 106700*uk_102 + 1156375*uk_103 + 1794375*uk_104 + 773575*uk_105 + 2784375*uk_106 + 1200375*uk_107 + 517495*uk_108 + 1481544*uk_109 + 5781966*uk_11 + 1260612*uk_110 + 259920*uk_111 + 1884420*uk_112 + 2924100*uk_113 + 1260612*uk_114 + 1072626*uk_115 + 221160*uk_116 + 1603410*uk_117 + 2488050*uk_118 + 1072626*uk_119 + 4919743*uk_12 + 45600*uk_120 + 330600*uk_121 + 513000*uk_122 + 221160*uk_123 + 2396850*uk_124 + 3719250*uk_125 + 1603410*uk_126 + 5771250*uk_127 + 2488050*uk_128 + 1072626*uk_129 + 1014380*uk_13 + 912673*uk_130 + 188180*uk_131 + 1364305*uk_132 + 2117025*uk_133 + 912673*uk_134 + 38800*uk_135 + 281300*uk_136 + 436500*uk_137 + 188180*uk_138 + 2039425*uk_139 + 7354255*uk_14 + 3164625*uk_140 + 1364305*uk_141 + 4910625*uk_142 + 2117025*uk_143 + 912673*uk_144 + 8000*uk_145 + 58000*uk_146 + 90000*uk_147 + 38800*uk_148 + 420500*uk_149 + 11411775*uk_15 + 652500*uk_150 + 281300*uk_151 + 1012500*uk_152 + 436500*uk_153 + 188180*uk_154 + 3048625*uk_155 + 4730625*uk_156 + 2039425*uk_157 + 7340625*uk_158 + 3164625*uk_159 + 4919743*uk_16 + 1364305*uk_160 + 11390625*uk_161 + 4910625*uk_162 + 2117025*uk_163 + 912673*uk_164 + 3025*uk_17 + 6270*uk_18 + 5335*uk_19 + 55*uk_2 + 1100*uk_20 + 7975*uk_21 + 12375*uk_22 + 5335*uk_23 + 12996*uk_24 + 11058*uk_25 + 2280*uk_26 + 16530*uk_27 + 25650*uk_28 + 11058*uk_29 + 114*uk_3 + 9409*uk_30 + 1940*uk_31 + 14065*uk_32 + 21825*uk_33 + 9409*uk_34 + 400*uk_35 + 2900*uk_36 + 4500*uk_37 + 1940*uk_38 + 21025*uk_39 + 97*uk_4 + 32625*uk_40 + 14065*uk_41 + 50625*uk_42 + 21825*uk_43 + 9409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 293255533554*uk_47 + 249524445217*uk_48 + 51448339220*uk_49 + 20*uk_5 + 373000459345*uk_50 + 578793816225*uk_51 + 249524445217*uk_52 + 153424975*uk_53 + 318008130*uk_54 + 270585865*uk_55 + 55790900*uk_56 + 404484025*uk_57 + 627647625*uk_58 + 270585865*uk_59 + 145*uk_6 + 659144124*uk_60 + 560850702*uk_61 + 115639320*uk_62 + 838385070*uk_63 + 1300942350*uk_64 + 560850702*uk_65 + 477215071*uk_66 + 98394860*uk_67 + 713362735*uk_68 + 1106942175*uk_69 + 225*uk_7 + 477215071*uk_70 + 20287600*uk_71 + 147085100*uk_72 + 228235500*uk_73 + 98394860*uk_74 + 1066366975*uk_75 + 1654707375*uk_76 + 713362735*uk_77 + 2567649375*uk_78 + 1106942175*uk_79 + 97*uk_8 + 477215071*uk_80 + 166375*uk_81 + 344850*uk_82 + 293425*uk_83 + 60500*uk_84 + 438625*uk_85 + 680625*uk_86 + 293425*uk_87 + 714780*uk_88 + 608190*uk_89 + 2572416961*uk_9 + 125400*uk_90 + 909150*uk_91 + 1410750*uk_92 + 608190*uk_93 + 517495*uk_94 + 106700*uk_95 + 773575*uk_96 + 1200375*uk_97 + 517495*uk_98 + 22000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 129360*uk_100 + 198000*uk_101 + 100320*uk_102 + 1188495*uk_103 + 1819125*uk_104 + 921690*uk_105 + 2784375*uk_106 + 1410750*uk_107 + 714780*uk_108 + 64*uk_109 + 202876*uk_11 + 1824*uk_110 + 256*uk_111 + 2352*uk_112 + 3600*uk_113 + 1824*uk_114 + 51984*uk_115 + 7296*uk_116 + 67032*uk_117 + 102600*uk_118 + 51984*uk_119 + 5781966*uk_12 + 1024*uk_120 + 9408*uk_121 + 14400*uk_122 + 7296*uk_123 + 86436*uk_124 + 132300*uk_125 + 67032*uk_126 + 202500*uk_127 + 102600*uk_128 + 51984*uk_129 + 811504*uk_13 + 1481544*uk_130 + 207936*uk_131 + 1910412*uk_132 + 2924100*uk_133 + 1481544*uk_134 + 29184*uk_135 + 268128*uk_136 + 410400*uk_137 + 207936*uk_138 + 2463426*uk_139 + 7455693*uk_14 + 3770550*uk_140 + 1910412*uk_141 + 5771250*uk_142 + 2924100*uk_143 + 1481544*uk_144 + 4096*uk_145 + 37632*uk_146 + 57600*uk_147 + 29184*uk_148 + 345744*uk_149 + 11411775*uk_15 + 529200*uk_150 + 268128*uk_151 + 810000*uk_152 + 410400*uk_153 + 207936*uk_154 + 3176523*uk_155 + 4862025*uk_156 + 2463426*uk_157 + 7441875*uk_158 + 3770550*uk_159 + 5781966*uk_16 + 1910412*uk_160 + 11390625*uk_161 + 5771250*uk_162 + 2924100*uk_163 + 1481544*uk_164 + 3025*uk_17 + 220*uk_18 + 6270*uk_19 + 55*uk_2 + 880*uk_20 + 8085*uk_21 + 12375*uk_22 + 6270*uk_23 + 16*uk_24 + 456*uk_25 + 64*uk_26 + 588*uk_27 + 900*uk_28 + 456*uk_29 + 4*uk_3 + 12996*uk_30 + 1824*uk_31 + 16758*uk_32 + 25650*uk_33 + 12996*uk_34 + 256*uk_35 + 2352*uk_36 + 3600*uk_37 + 1824*uk_38 + 21609*uk_39 + 114*uk_4 + 33075*uk_40 + 16758*uk_41 + 50625*uk_42 + 25650*uk_43 + 12996*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 293255533554*uk_48 + 41158671376*uk_49 + 16*uk_5 + 378145293267*uk_50 + 578793816225*uk_51 + 293255533554*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 318008130*uk_55 + 44632720*uk_56 + 410063115*uk_57 + 627647625*uk_58 + 318008130*uk_59 + 147*uk_6 + 811504*uk_60 + 23127864*uk_61 + 3246016*uk_62 + 29822772*uk_63 + 45647100*uk_64 + 23127864*uk_65 + 659144124*uk_66 + 92511456*uk_67 + 849949002*uk_68 + 1300942350*uk_69 + 225*uk_7 + 659144124*uk_70 + 12984064*uk_71 + 119291088*uk_72 + 182588400*uk_73 + 92511456*uk_74 + 1095986871*uk_75 + 1677530925*uk_76 + 849949002*uk_77 + 2567649375*uk_78 + 1300942350*uk_79 + 114*uk_8 + 659144124*uk_80 + 166375*uk_81 + 12100*uk_82 + 344850*uk_83 + 48400*uk_84 + 444675*uk_85 + 680625*uk_86 + 344850*uk_87 + 880*uk_88 + 25080*uk_89 + 2572416961*uk_9 + 3520*uk_90 + 32340*uk_91 + 49500*uk_92 + 25080*uk_93 + 714780*uk_94 + 100320*uk_95 + 921690*uk_96 + 1410750*uk_97 + 714780*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 163900*uk_100 + 247500*uk_101 + 4400*uk_102 + 1221055*uk_103 + 1843875*uk_104 + 32780*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 205379*uk_109 + 2992421*uk_11 + 13924*uk_110 + 69620*uk_111 + 518669*uk_112 + 783225*uk_113 + 13924*uk_114 + 944*uk_115 + 4720*uk_116 + 35164*uk_117 + 53100*uk_118 + 944*uk_119 + 202876*uk_12 + 23600*uk_120 + 175820*uk_121 + 265500*uk_122 + 4720*uk_123 + 1309859*uk_124 + 1977975*uk_125 + 35164*uk_126 + 2986875*uk_127 + 53100*uk_128 + 944*uk_129 + 1014380*uk_13 + 64*uk_130 + 320*uk_131 + 2384*uk_132 + 3600*uk_133 + 64*uk_134 + 1600*uk_135 + 11920*uk_136 + 18000*uk_137 + 320*uk_138 + 88804*uk_139 + 7557131*uk_14 + 134100*uk_140 + 2384*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 8000*uk_145 + 59600*uk_146 + 90000*uk_147 + 1600*uk_148 + 444020*uk_149 + 11411775*uk_15 + 670500*uk_150 + 11920*uk_151 + 1012500*uk_152 + 18000*uk_153 + 320*uk_154 + 3307949*uk_155 + 4995225*uk_156 + 88804*uk_157 + 7543125*uk_158 + 134100*uk_159 + 202876*uk_16 + 2384*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 3245*uk_18 + 220*uk_19 + 55*uk_2 + 1100*uk_20 + 8195*uk_21 + 12375*uk_22 + 220*uk_23 + 3481*uk_24 + 236*uk_25 + 1180*uk_26 + 8791*uk_27 + 13275*uk_28 + 236*uk_29 + 59*uk_3 + 16*uk_30 + 80*uk_31 + 596*uk_32 + 900*uk_33 + 16*uk_34 + 400*uk_35 + 2980*uk_36 + 4500*uk_37 + 80*uk_38 + 22201*uk_39 + 4*uk_4 + 33525*uk_40 + 596*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 151772600699*uk_47 + 10289667844*uk_48 + 51448339220*uk_49 + 20*uk_5 + 383290127189*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 164583155*uk_54 + 11158180*uk_55 + 55790900*uk_56 + 415642205*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 149*uk_6 + 176552839*uk_60 + 11969684*uk_61 + 59848420*uk_62 + 445870729*uk_63 + 673294725*uk_64 + 11969684*uk_65 + 811504*uk_66 + 4057520*uk_67 + 30228524*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 20287600*uk_71 + 151142620*uk_72 + 228235500*uk_73 + 4057520*uk_74 + 1126012519*uk_75 + 1700354475*uk_76 + 30228524*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 178475*uk_82 + 12100*uk_83 + 60500*uk_84 + 450725*uk_85 + 680625*uk_86 + 12100*uk_87 + 191455*uk_88 + 12980*uk_89 + 2572416961*uk_9 + 64900*uk_90 + 483505*uk_91 + 730125*uk_92 + 12980*uk_93 + 880*uk_94 + 4400*uk_95 + 32780*uk_96 + 49500*uk_97 + 880*uk_98 + 22000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 166100*uk_100 + 247500*uk_101 + 64900*uk_102 + 1254055*uk_103 + 1868625*uk_104 + 489995*uk_105 + 2784375*uk_106 + 730125*uk_107 + 191455*uk_108 + 2406104*uk_109 + 6796346*uk_11 + 1059404*uk_110 + 359120*uk_111 + 2711356*uk_112 + 4040100*uk_113 + 1059404*uk_114 + 466454*uk_115 + 158120*uk_116 + 1193806*uk_117 + 1778850*uk_118 + 466454*uk_119 + 2992421*uk_12 + 53600*uk_120 + 404680*uk_121 + 603000*uk_122 + 158120*uk_123 + 3055334*uk_124 + 4552650*uk_125 + 1193806*uk_126 + 6783750*uk_127 + 1778850*uk_128 + 466454*uk_129 + 1014380*uk_13 + 205379*uk_130 + 69620*uk_131 + 525631*uk_132 + 783225*uk_133 + 205379*uk_134 + 23600*uk_135 + 178180*uk_136 + 265500*uk_137 + 69620*uk_138 + 1345259*uk_139 + 7658569*uk_14 + 2004525*uk_140 + 525631*uk_141 + 2986875*uk_142 + 783225*uk_143 + 205379*uk_144 + 8000*uk_145 + 60400*uk_146 + 90000*uk_147 + 23600*uk_148 + 456020*uk_149 + 11411775*uk_15 + 679500*uk_150 + 178180*uk_151 + 1012500*uk_152 + 265500*uk_153 + 69620*uk_154 + 3442951*uk_155 + 5130225*uk_156 + 1345259*uk_157 + 7644375*uk_158 + 2004525*uk_159 + 2992421*uk_16 + 525631*uk_160 + 11390625*uk_161 + 2986875*uk_162 + 783225*uk_163 + 205379*uk_164 + 3025*uk_17 + 7370*uk_18 + 3245*uk_19 + 55*uk_2 + 1100*uk_20 + 8305*uk_21 + 12375*uk_22 + 3245*uk_23 + 17956*uk_24 + 7906*uk_25 + 2680*uk_26 + 20234*uk_27 + 30150*uk_28 + 7906*uk_29 + 134*uk_3 + 3481*uk_30 + 1180*uk_31 + 8909*uk_32 + 13275*uk_33 + 3481*uk_34 + 400*uk_35 + 3020*uk_36 + 4500*uk_37 + 1180*uk_38 + 22801*uk_39 + 59*uk_4 + 33975*uk_40 + 8909*uk_41 + 50625*uk_42 + 13275*uk_43 + 3481*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 344703872774*uk_47 + 151772600699*uk_48 + 51448339220*uk_49 + 20*uk_5 + 388434961111*uk_50 + 578793816225*uk_51 + 151772600699*uk_52 + 153424975*uk_53 + 373799030*uk_54 + 164583155*uk_55 + 55790900*uk_56 + 421221295*uk_57 + 627647625*uk_58 + 164583155*uk_59 + 151*uk_6 + 910710364*uk_60 + 400984414*uk_61 + 135926920*uk_62 + 1026248246*uk_63 + 1529177850*uk_64 + 400984414*uk_65 + 176552839*uk_66 + 59848420*uk_67 + 451855571*uk_68 + 673294725*uk_69 + 225*uk_7 + 176552839*uk_70 + 20287600*uk_71 + 153171380*uk_72 + 228235500*uk_73 + 59848420*uk_74 + 1156443919*uk_75 + 1723178025*uk_76 + 451855571*uk_77 + 2567649375*uk_78 + 673294725*uk_79 + 59*uk_8 + 176552839*uk_80 + 166375*uk_81 + 405350*uk_82 + 178475*uk_83 + 60500*uk_84 + 456775*uk_85 + 680625*uk_86 + 178475*uk_87 + 987580*uk_88 + 434830*uk_89 + 2572416961*uk_9 + 147400*uk_90 + 1112870*uk_91 + 1658250*uk_92 + 434830*uk_93 + 191455*uk_94 + 64900*uk_95 + 489995*uk_96 + 730125*uk_97 + 191455*uk_98 + 22000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 134640*uk_100 + 198000*uk_101 + 117920*uk_102 + 1287495*uk_103 + 1893375*uk_104 + 1127610*uk_105 + 2784375*uk_106 + 1658250*uk_107 + 987580*uk_108 + 438976*uk_109 + 3854644*uk_11 + 773984*uk_110 + 92416*uk_111 + 883728*uk_112 + 1299600*uk_113 + 773984*uk_114 + 1364656*uk_115 + 162944*uk_116 + 1558152*uk_117 + 2291400*uk_118 + 1364656*uk_119 + 6796346*uk_12 + 19456*uk_120 + 186048*uk_121 + 273600*uk_122 + 162944*uk_123 + 1779084*uk_124 + 2616300*uk_125 + 1558152*uk_126 + 3847500*uk_127 + 2291400*uk_128 + 1364656*uk_129 + 811504*uk_13 + 2406104*uk_130 + 287296*uk_131 + 2747268*uk_132 + 4040100*uk_133 + 2406104*uk_134 + 34304*uk_135 + 328032*uk_136 + 482400*uk_137 + 287296*uk_138 + 3136806*uk_139 + 7760007*uk_14 + 4612950*uk_140 + 2747268*uk_141 + 6783750*uk_142 + 4040100*uk_143 + 2406104*uk_144 + 4096*uk_145 + 39168*uk_146 + 57600*uk_147 + 34304*uk_148 + 374544*uk_149 + 11411775*uk_15 + 550800*uk_150 + 328032*uk_151 + 810000*uk_152 + 482400*uk_153 + 287296*uk_154 + 3581577*uk_155 + 5267025*uk_156 + 3136806*uk_157 + 7745625*uk_158 + 4612950*uk_159 + 6796346*uk_16 + 2747268*uk_160 + 11390625*uk_161 + 6783750*uk_162 + 4040100*uk_163 + 2406104*uk_164 + 3025*uk_17 + 4180*uk_18 + 7370*uk_19 + 55*uk_2 + 880*uk_20 + 8415*uk_21 + 12375*uk_22 + 7370*uk_23 + 5776*uk_24 + 10184*uk_25 + 1216*uk_26 + 11628*uk_27 + 17100*uk_28 + 10184*uk_29 + 76*uk_3 + 17956*uk_30 + 2144*uk_31 + 20502*uk_32 + 30150*uk_33 + 17956*uk_34 + 256*uk_35 + 2448*uk_36 + 3600*uk_37 + 2144*uk_38 + 23409*uk_39 + 134*uk_4 + 34425*uk_40 + 20502*uk_41 + 50625*uk_42 + 30150*uk_43 + 17956*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 195503689036*uk_47 + 344703872774*uk_48 + 41158671376*uk_49 + 16*uk_5 + 393579795033*uk_50 + 578793816225*uk_51 + 344703872774*uk_52 + 153424975*uk_53 + 212005420*uk_54 + 373799030*uk_55 + 44632720*uk_56 + 426800385*uk_57 + 627647625*uk_58 + 373799030*uk_59 + 153*uk_6 + 292952944*uk_60 + 516522296*uk_61 + 61674304*uk_62 + 589760532*uk_63 + 867294900*uk_64 + 516522296*uk_65 + 910710364*uk_66 + 108741536*uk_67 + 1039840938*uk_68 + 1529177850*uk_69 + 225*uk_7 + 910710364*uk_70 + 12984064*uk_71 + 124160112*uk_72 + 182588400*uk_73 + 108741536*uk_74 + 1187281071*uk_75 + 1746001575*uk_76 + 1039840938*uk_77 + 2567649375*uk_78 + 1529177850*uk_79 + 134*uk_8 + 910710364*uk_80 + 166375*uk_81 + 229900*uk_82 + 405350*uk_83 + 48400*uk_84 + 462825*uk_85 + 680625*uk_86 + 405350*uk_87 + 317680*uk_88 + 560120*uk_89 + 2572416961*uk_9 + 66880*uk_90 + 639540*uk_91 + 940500*uk_92 + 560120*uk_93 + 987580*uk_94 + 117920*uk_95 + 1127610*uk_96 + 1658250*uk_97 + 987580*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 136400*uk_100 + 198000*uk_101 + 66880*uk_102 + 1321375*uk_103 + 1918125*uk_104 + 647900*uk_105 + 2784375*uk_106 + 940500*uk_107 + 317680*uk_108 + 39304*uk_109 + 1724446*uk_11 + 87856*uk_110 + 18496*uk_111 + 179180*uk_112 + 260100*uk_113 + 87856*uk_114 + 196384*uk_115 + 41344*uk_116 + 400520*uk_117 + 581400*uk_118 + 196384*uk_119 + 3854644*uk_12 + 8704*uk_120 + 84320*uk_121 + 122400*uk_122 + 41344*uk_123 + 816850*uk_124 + 1185750*uk_125 + 400520*uk_126 + 1721250*uk_127 + 581400*uk_128 + 196384*uk_129 + 811504*uk_13 + 438976*uk_130 + 92416*uk_131 + 895280*uk_132 + 1299600*uk_133 + 438976*uk_134 + 19456*uk_135 + 188480*uk_136 + 273600*uk_137 + 92416*uk_138 + 1825900*uk_139 + 7861445*uk_14 + 2650500*uk_140 + 895280*uk_141 + 3847500*uk_142 + 1299600*uk_143 + 438976*uk_144 + 4096*uk_145 + 39680*uk_146 + 57600*uk_147 + 19456*uk_148 + 384400*uk_149 + 11411775*uk_15 + 558000*uk_150 + 188480*uk_151 + 810000*uk_152 + 273600*uk_153 + 92416*uk_154 + 3723875*uk_155 + 5405625*uk_156 + 1825900*uk_157 + 7846875*uk_158 + 2650500*uk_159 + 3854644*uk_16 + 895280*uk_160 + 11390625*uk_161 + 3847500*uk_162 + 1299600*uk_163 + 438976*uk_164 + 3025*uk_17 + 1870*uk_18 + 4180*uk_19 + 55*uk_2 + 880*uk_20 + 8525*uk_21 + 12375*uk_22 + 4180*uk_23 + 1156*uk_24 + 2584*uk_25 + 544*uk_26 + 5270*uk_27 + 7650*uk_28 + 2584*uk_29 + 34*uk_3 + 5776*uk_30 + 1216*uk_31 + 11780*uk_32 + 17100*uk_33 + 5776*uk_34 + 256*uk_35 + 2480*uk_36 + 3600*uk_37 + 1216*uk_38 + 24025*uk_39 + 76*uk_4 + 34875*uk_40 + 11780*uk_41 + 50625*uk_42 + 17100*uk_43 + 5776*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 87462176674*uk_47 + 195503689036*uk_48 + 41158671376*uk_49 + 16*uk_5 + 398724628955*uk_50 + 578793816225*uk_51 + 195503689036*uk_52 + 153424975*uk_53 + 94844530*uk_54 + 212005420*uk_55 + 44632720*uk_56 + 432379475*uk_57 + 627647625*uk_58 + 212005420*uk_59 + 155*uk_6 + 58631164*uk_60 + 131057896*uk_61 + 27591136*uk_62 + 267289130*uk_63 + 388000350*uk_64 + 131057896*uk_65 + 292952944*uk_66 + 61674304*uk_67 + 597469820*uk_68 + 867294900*uk_69 + 225*uk_7 + 292952944*uk_70 + 12984064*uk_71 + 125783120*uk_72 + 182588400*uk_73 + 61674304*uk_74 + 1218523975*uk_75 + 1768825125*uk_76 + 597469820*uk_77 + 2567649375*uk_78 + 867294900*uk_79 + 76*uk_8 + 292952944*uk_80 + 166375*uk_81 + 102850*uk_82 + 229900*uk_83 + 48400*uk_84 + 468875*uk_85 + 680625*uk_86 + 229900*uk_87 + 63580*uk_88 + 142120*uk_89 + 2572416961*uk_9 + 29920*uk_90 + 289850*uk_91 + 420750*uk_92 + 142120*uk_93 + 317680*uk_94 + 66880*uk_95 + 647900*uk_96 + 940500*uk_97 + 317680*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 138160*uk_100 + 198000*uk_101 + 29920*uk_102 + 1355695*uk_103 + 1942875*uk_104 + 293590*uk_105 + 2784375*uk_106 + 420750*uk_107 + 63580*uk_108 + 512*uk_109 + 405752*uk_11 + 2176*uk_110 + 1024*uk_111 + 10048*uk_112 + 14400*uk_113 + 2176*uk_114 + 9248*uk_115 + 4352*uk_116 + 42704*uk_117 + 61200*uk_118 + 9248*uk_119 + 1724446*uk_12 + 2048*uk_120 + 20096*uk_121 + 28800*uk_122 + 4352*uk_123 + 197192*uk_124 + 282600*uk_125 + 42704*uk_126 + 405000*uk_127 + 61200*uk_128 + 9248*uk_129 + 811504*uk_13 + 39304*uk_130 + 18496*uk_131 + 181492*uk_132 + 260100*uk_133 + 39304*uk_134 + 8704*uk_135 + 85408*uk_136 + 122400*uk_137 + 18496*uk_138 + 838066*uk_139 + 7962883*uk_14 + 1201050*uk_140 + 181492*uk_141 + 1721250*uk_142 + 260100*uk_143 + 39304*uk_144 + 4096*uk_145 + 40192*uk_146 + 57600*uk_147 + 8704*uk_148 + 394384*uk_149 + 11411775*uk_15 + 565200*uk_150 + 85408*uk_151 + 810000*uk_152 + 122400*uk_153 + 18496*uk_154 + 3869893*uk_155 + 5546025*uk_156 + 838066*uk_157 + 7948125*uk_158 + 1201050*uk_159 + 1724446*uk_16 + 181492*uk_160 + 11390625*uk_161 + 1721250*uk_162 + 260100*uk_163 + 39304*uk_164 + 3025*uk_17 + 440*uk_18 + 1870*uk_19 + 55*uk_2 + 880*uk_20 + 8635*uk_21 + 12375*uk_22 + 1870*uk_23 + 64*uk_24 + 272*uk_25 + 128*uk_26 + 1256*uk_27 + 1800*uk_28 + 272*uk_29 + 8*uk_3 + 1156*uk_30 + 544*uk_31 + 5338*uk_32 + 7650*uk_33 + 1156*uk_34 + 256*uk_35 + 2512*uk_36 + 3600*uk_37 + 544*uk_38 + 24649*uk_39 + 34*uk_4 + 35325*uk_40 + 5338*uk_41 + 50625*uk_42 + 7650*uk_43 + 1156*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 20579335688*uk_47 + 87462176674*uk_48 + 41158671376*uk_49 + 16*uk_5 + 403869462877*uk_50 + 578793816225*uk_51 + 87462176674*uk_52 + 153424975*uk_53 + 22316360*uk_54 + 94844530*uk_55 + 44632720*uk_56 + 437958565*uk_57 + 627647625*uk_58 + 94844530*uk_59 + 157*uk_6 + 3246016*uk_60 + 13795568*uk_61 + 6492032*uk_62 + 63703064*uk_63 + 91294200*uk_64 + 13795568*uk_65 + 58631164*uk_66 + 27591136*uk_67 + 270738022*uk_68 + 388000350*uk_69 + 225*uk_7 + 58631164*uk_70 + 12984064*uk_71 + 127406128*uk_72 + 182588400*uk_73 + 27591136*uk_74 + 1250172631*uk_75 + 1791648675*uk_76 + 270738022*uk_77 + 2567649375*uk_78 + 388000350*uk_79 + 34*uk_8 + 58631164*uk_80 + 166375*uk_81 + 24200*uk_82 + 102850*uk_83 + 48400*uk_84 + 474925*uk_85 + 680625*uk_86 + 102850*uk_87 + 3520*uk_88 + 14960*uk_89 + 2572416961*uk_9 + 7040*uk_90 + 69080*uk_91 + 99000*uk_92 + 14960*uk_93 + 63580*uk_94 + 29920*uk_95 + 293590*uk_96 + 420750*uk_97 + 63580*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 174900*uk_100 + 247500*uk_101 + 8800*uk_102 + 1390455*uk_103 + 1967625*uk_104 + 69960*uk_105 + 2784375*uk_106 + 99000*uk_107 + 3520*uk_108 + 3869893*uk_109 + 7962883*uk_11 + 197192*uk_110 + 492980*uk_111 + 3919191*uk_112 + 5546025*uk_113 + 197192*uk_114 + 10048*uk_115 + 25120*uk_116 + 199704*uk_117 + 282600*uk_118 + 10048*uk_119 + 405752*uk_12 + 62800*uk_120 + 499260*uk_121 + 706500*uk_122 + 25120*uk_123 + 3969117*uk_124 + 5616675*uk_125 + 199704*uk_126 + 7948125*uk_127 + 282600*uk_128 + 10048*uk_129 + 1014380*uk_13 + 512*uk_130 + 1280*uk_131 + 10176*uk_132 + 14400*uk_133 + 512*uk_134 + 3200*uk_135 + 25440*uk_136 + 36000*uk_137 + 1280*uk_138 + 202248*uk_139 + 8064321*uk_14 + 286200*uk_140 + 10176*uk_141 + 405000*uk_142 + 14400*uk_143 + 512*uk_144 + 8000*uk_145 + 63600*uk_146 + 90000*uk_147 + 3200*uk_148 + 505620*uk_149 + 11411775*uk_15 + 715500*uk_150 + 25440*uk_151 + 1012500*uk_152 + 36000*uk_153 + 1280*uk_154 + 4019679*uk_155 + 5688225*uk_156 + 202248*uk_157 + 8049375*uk_158 + 286200*uk_159 + 405752*uk_16 + 10176*uk_160 + 11390625*uk_161 + 405000*uk_162 + 14400*uk_163 + 512*uk_164 + 3025*uk_17 + 8635*uk_18 + 440*uk_19 + 55*uk_2 + 1100*uk_20 + 8745*uk_21 + 12375*uk_22 + 440*uk_23 + 24649*uk_24 + 1256*uk_25 + 3140*uk_26 + 24963*uk_27 + 35325*uk_28 + 1256*uk_29 + 157*uk_3 + 64*uk_30 + 160*uk_31 + 1272*uk_32 + 1800*uk_33 + 64*uk_34 + 400*uk_35 + 3180*uk_36 + 4500*uk_37 + 160*uk_38 + 25281*uk_39 + 8*uk_4 + 35775*uk_40 + 1272*uk_41 + 50625*uk_42 + 1800*uk_43 + 64*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 403869462877*uk_47 + 20579335688*uk_48 + 51448339220*uk_49 + 20*uk_5 + 409014296799*uk_50 + 578793816225*uk_51 + 20579335688*uk_52 + 153424975*uk_53 + 437958565*uk_54 + 22316360*uk_55 + 55790900*uk_56 + 443537655*uk_57 + 627647625*uk_58 + 22316360*uk_59 + 159*uk_6 + 1250172631*uk_60 + 63703064*uk_61 + 159257660*uk_62 + 1266098397*uk_63 + 1791648675*uk_64 + 63703064*uk_65 + 3246016*uk_66 + 8115040*uk_67 + 64514568*uk_68 + 91294200*uk_69 + 225*uk_7 + 3246016*uk_70 + 20287600*uk_71 + 161286420*uk_72 + 228235500*uk_73 + 8115040*uk_74 + 1282227039*uk_75 + 1814472225*uk_76 + 64514568*uk_77 + 2567649375*uk_78 + 91294200*uk_79 + 8*uk_8 + 3246016*uk_80 + 166375*uk_81 + 474925*uk_82 + 24200*uk_83 + 60500*uk_84 + 480975*uk_85 + 680625*uk_86 + 24200*uk_87 + 1355695*uk_88 + 69080*uk_89 + 2572416961*uk_9 + 172700*uk_90 + 1372965*uk_91 + 1942875*uk_92 + 69080*uk_93 + 3520*uk_94 + 8800*uk_95 + 69960*uk_96 + 99000*uk_97 + 3520*uk_98 + 22000*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 106260*uk_100 + 148500*uk_101 + 103620*uk_102 + 1425655*uk_103 + 1992375*uk_104 + 1390235*uk_105 + 2784375*uk_106 + 1942875*uk_107 + 1355695*uk_108 + 64*uk_109 + 202876*uk_11 + 2512*uk_110 + 192*uk_111 + 2576*uk_112 + 3600*uk_113 + 2512*uk_114 + 98596*uk_115 + 7536*uk_116 + 101108*uk_117 + 141300*uk_118 + 98596*uk_119 + 7962883*uk_12 + 576*uk_120 + 7728*uk_121 + 10800*uk_122 + 7536*uk_123 + 103684*uk_124 + 144900*uk_125 + 101108*uk_126 + 202500*uk_127 + 141300*uk_128 + 98596*uk_129 + 608628*uk_13 + 3869893*uk_130 + 295788*uk_131 + 3968489*uk_132 + 5546025*uk_133 + 3869893*uk_134 + 22608*uk_135 + 303324*uk_136 + 423900*uk_137 + 295788*uk_138 + 4069597*uk_139 + 8165759*uk_14 + 5687325*uk_140 + 3968489*uk_141 + 7948125*uk_142 + 5546025*uk_143 + 3869893*uk_144 + 1728*uk_145 + 23184*uk_146 + 32400*uk_147 + 22608*uk_148 + 311052*uk_149 + 11411775*uk_15 + 434700*uk_150 + 303324*uk_151 + 607500*uk_152 + 423900*uk_153 + 295788*uk_154 + 4173281*uk_155 + 5832225*uk_156 + 4069597*uk_157 + 8150625*uk_158 + 5687325*uk_159 + 7962883*uk_16 + 3968489*uk_160 + 11390625*uk_161 + 7948125*uk_162 + 5546025*uk_163 + 3869893*uk_164 + 3025*uk_17 + 220*uk_18 + 8635*uk_19 + 55*uk_2 + 660*uk_20 + 8855*uk_21 + 12375*uk_22 + 8635*uk_23 + 16*uk_24 + 628*uk_25 + 48*uk_26 + 644*uk_27 + 900*uk_28 + 628*uk_29 + 4*uk_3 + 24649*uk_30 + 1884*uk_31 + 25277*uk_32 + 35325*uk_33 + 24649*uk_34 + 144*uk_35 + 1932*uk_36 + 2700*uk_37 + 1884*uk_38 + 25921*uk_39 + 157*uk_4 + 36225*uk_40 + 25277*uk_41 + 50625*uk_42 + 35325*uk_43 + 24649*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 403869462877*uk_48 + 30869003532*uk_49 + 12*uk_5 + 414159130721*uk_50 + 578793816225*uk_51 + 403869462877*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 437958565*uk_55 + 33474540*uk_56 + 449116745*uk_57 + 627647625*uk_58 + 437958565*uk_59 + 161*uk_6 + 811504*uk_60 + 31851532*uk_61 + 2434512*uk_62 + 32663036*uk_63 + 45647100*uk_64 + 31851532*uk_65 + 1250172631*uk_66 + 95554596*uk_67 + 1282024163*uk_68 + 1791648675*uk_69 + 225*uk_7 + 1250172631*uk_70 + 7303536*uk_71 + 97989108*uk_72 + 136941300*uk_73 + 95554596*uk_74 + 1314687199*uk_75 + 1837295775*uk_76 + 1282024163*uk_77 + 2567649375*uk_78 + 1791648675*uk_79 + 157*uk_8 + 1250172631*uk_80 + 166375*uk_81 + 12100*uk_82 + 474925*uk_83 + 36300*uk_84 + 487025*uk_85 + 680625*uk_86 + 474925*uk_87 + 880*uk_88 + 34540*uk_89 + 2572416961*uk_9 + 2640*uk_90 + 35420*uk_91 + 49500*uk_92 + 34540*uk_93 + 1355695*uk_94 + 103620*uk_95 + 1390235*uk_96 + 1942875*uk_97 + 1355695*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 143440*uk_100 + 198000*uk_101 + 3520*uk_102 + 1461295*uk_103 + 2017125*uk_104 + 35860*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 17576*uk_109 + 1318694*uk_11 + 2704*uk_110 + 10816*uk_111 + 110188*uk_112 + 152100*uk_113 + 2704*uk_114 + 416*uk_115 + 1664*uk_116 + 16952*uk_117 + 23400*uk_118 + 416*uk_119 + 202876*uk_12 + 6656*uk_120 + 67808*uk_121 + 93600*uk_122 + 1664*uk_123 + 690794*uk_124 + 953550*uk_125 + 16952*uk_126 + 1316250*uk_127 + 23400*uk_128 + 416*uk_129 + 811504*uk_13 + 64*uk_130 + 256*uk_131 + 2608*uk_132 + 3600*uk_133 + 64*uk_134 + 1024*uk_135 + 10432*uk_136 + 14400*uk_137 + 256*uk_138 + 106276*uk_139 + 8267197*uk_14 + 146700*uk_140 + 2608*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 4096*uk_145 + 41728*uk_146 + 57600*uk_147 + 1024*uk_148 + 425104*uk_149 + 11411775*uk_15 + 586800*uk_150 + 10432*uk_151 + 810000*uk_152 + 14400*uk_153 + 256*uk_154 + 4330747*uk_155 + 5978025*uk_156 + 106276*uk_157 + 8251875*uk_158 + 146700*uk_159 + 202876*uk_16 + 2608*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 1430*uk_18 + 220*uk_19 + 55*uk_2 + 880*uk_20 + 8965*uk_21 + 12375*uk_22 + 220*uk_23 + 676*uk_24 + 104*uk_25 + 416*uk_26 + 4238*uk_27 + 5850*uk_28 + 104*uk_29 + 26*uk_3 + 16*uk_30 + 64*uk_31 + 652*uk_32 + 900*uk_33 + 16*uk_34 + 256*uk_35 + 2608*uk_36 + 3600*uk_37 + 64*uk_38 + 26569*uk_39 + 4*uk_4 + 36675*uk_40 + 652*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 66882840986*uk_47 + 10289667844*uk_48 + 41158671376*uk_49 + 16*uk_5 + 419303964643*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 72528170*uk_54 + 11158180*uk_55 + 44632720*uk_56 + 454695835*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 163*uk_6 + 34286044*uk_60 + 5274776*uk_61 + 21099104*uk_62 + 214947122*uk_63 + 296706150*uk_64 + 5274776*uk_65 + 811504*uk_66 + 3246016*uk_67 + 33068788*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 12984064*uk_71 + 132275152*uk_72 + 182588400*uk_73 + 3246016*uk_74 + 1347553111*uk_75 + 1860119325*uk_76 + 33068788*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 78650*uk_82 + 12100*uk_83 + 48400*uk_84 + 493075*uk_85 + 680625*uk_86 + 12100*uk_87 + 37180*uk_88 + 5720*uk_89 + 2572416961*uk_9 + 22880*uk_90 + 233090*uk_91 + 321750*uk_92 + 5720*uk_93 + 880*uk_94 + 3520*uk_95 + 35860*uk_96 + 49500*uk_97 + 880*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 145200*uk_100 + 198000*uk_101 + 22880*uk_102 + 1497375*uk_103 + 2041875*uk_104 + 235950*uk_105 + 2784375*uk_106 + 321750*uk_107 + 37180*uk_108 + 262144*uk_109 + 3246016*uk_11 + 106496*uk_110 + 65536*uk_111 + 675840*uk_112 + 921600*uk_113 + 106496*uk_114 + 43264*uk_115 + 26624*uk_116 + 274560*uk_117 + 374400*uk_118 + 43264*uk_119 + 1318694*uk_12 + 16384*uk_120 + 168960*uk_121 + 230400*uk_122 + 26624*uk_123 + 1742400*uk_124 + 2376000*uk_125 + 274560*uk_126 + 3240000*uk_127 + 374400*uk_128 + 43264*uk_129 + 811504*uk_13 + 17576*uk_130 + 10816*uk_131 + 111540*uk_132 + 152100*uk_133 + 17576*uk_134 + 6656*uk_135 + 68640*uk_136 + 93600*uk_137 + 10816*uk_138 + 707850*uk_139 + 8368635*uk_14 + 965250*uk_140 + 111540*uk_141 + 1316250*uk_142 + 152100*uk_143 + 17576*uk_144 + 4096*uk_145 + 42240*uk_146 + 57600*uk_147 + 6656*uk_148 + 435600*uk_149 + 11411775*uk_15 + 594000*uk_150 + 68640*uk_151 + 810000*uk_152 + 93600*uk_153 + 10816*uk_154 + 4492125*uk_155 + 6125625*uk_156 + 707850*uk_157 + 8353125*uk_158 + 965250*uk_159 + 1318694*uk_16 + 111540*uk_160 + 11390625*uk_161 + 1316250*uk_162 + 152100*uk_163 + 17576*uk_164 + 3025*uk_17 + 3520*uk_18 + 1430*uk_19 + 55*uk_2 + 880*uk_20 + 9075*uk_21 + 12375*uk_22 + 1430*uk_23 + 4096*uk_24 + 1664*uk_25 + 1024*uk_26 + 10560*uk_27 + 14400*uk_28 + 1664*uk_29 + 64*uk_3 + 676*uk_30 + 416*uk_31 + 4290*uk_32 + 5850*uk_33 + 676*uk_34 + 256*uk_35 + 2640*uk_36 + 3600*uk_37 + 416*uk_38 + 27225*uk_39 + 26*uk_4 + 37125*uk_40 + 4290*uk_41 + 50625*uk_42 + 5850*uk_43 + 676*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 164634685504*uk_47 + 66882840986*uk_48 + 41158671376*uk_49 + 16*uk_5 + 424448798565*uk_50 + 578793816225*uk_51 + 66882840986*uk_52 + 153424975*uk_53 + 178530880*uk_54 + 72528170*uk_55 + 44632720*uk_56 + 460274925*uk_57 + 627647625*uk_58 + 72528170*uk_59 + 165*uk_6 + 207745024*uk_60 + 84396416*uk_61 + 51936256*uk_62 + 535592640*uk_63 + 730353600*uk_64 + 84396416*uk_65 + 34286044*uk_66 + 21099104*uk_67 + 217584510*uk_68 + 296706150*uk_69 + 225*uk_7 + 34286044*uk_70 + 12984064*uk_71 + 133898160*uk_72 + 182588400*uk_73 + 21099104*uk_74 + 1380824775*uk_75 + 1882942875*uk_76 + 217584510*uk_77 + 2567649375*uk_78 + 296706150*uk_79 + 26*uk_8 + 34286044*uk_80 + 166375*uk_81 + 193600*uk_82 + 78650*uk_83 + 48400*uk_84 + 499125*uk_85 + 680625*uk_86 + 78650*uk_87 + 225280*uk_88 + 91520*uk_89 + 2572416961*uk_9 + 56320*uk_90 + 580800*uk_91 + 792000*uk_92 + 91520*uk_93 + 37180*uk_94 + 22880*uk_95 + 235950*uk_96 + 321750*uk_97 + 37180*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 146960*uk_100 + 198000*uk_101 + 56320*uk_102 + 1533895*uk_103 + 2066625*uk_104 + 587840*uk_105 + 2784375*uk_106 + 792000*uk_107 + 225280*uk_108 + 1643032*uk_109 + 5984842*uk_11 + 891136*uk_110 + 222784*uk_111 + 2325308*uk_112 + 3132900*uk_113 + 891136*uk_114 + 483328*uk_115 + 120832*uk_116 + 1261184*uk_117 + 1699200*uk_118 + 483328*uk_119 + 3246016*uk_12 + 30208*uk_120 + 315296*uk_121 + 424800*uk_122 + 120832*uk_123 + 3290902*uk_124 + 4433850*uk_125 + 1261184*uk_126 + 5973750*uk_127 + 1699200*uk_128 + 483328*uk_129 + 811504*uk_13 + 262144*uk_130 + 65536*uk_131 + 684032*uk_132 + 921600*uk_133 + 262144*uk_134 + 16384*uk_135 + 171008*uk_136 + 230400*uk_137 + 65536*uk_138 + 1784896*uk_139 + 8470073*uk_14 + 2404800*uk_140 + 684032*uk_141 + 3240000*uk_142 + 921600*uk_143 + 262144*uk_144 + 4096*uk_145 + 42752*uk_146 + 57600*uk_147 + 16384*uk_148 + 446224*uk_149 + 11411775*uk_15 + 601200*uk_150 + 171008*uk_151 + 810000*uk_152 + 230400*uk_153 + 65536*uk_154 + 4657463*uk_155 + 6275025*uk_156 + 1784896*uk_157 + 8454375*uk_158 + 2404800*uk_159 + 3246016*uk_16 + 684032*uk_160 + 11390625*uk_161 + 3240000*uk_162 + 921600*uk_163 + 262144*uk_164 + 3025*uk_17 + 6490*uk_18 + 3520*uk_19 + 55*uk_2 + 880*uk_20 + 9185*uk_21 + 12375*uk_22 + 3520*uk_23 + 13924*uk_24 + 7552*uk_25 + 1888*uk_26 + 19706*uk_27 + 26550*uk_28 + 7552*uk_29 + 118*uk_3 + 4096*uk_30 + 1024*uk_31 + 10688*uk_32 + 14400*uk_33 + 4096*uk_34 + 256*uk_35 + 2672*uk_36 + 3600*uk_37 + 1024*uk_38 + 27889*uk_39 + 64*uk_4 + 37575*uk_40 + 10688*uk_41 + 50625*uk_42 + 14400*uk_43 + 4096*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 303545201398*uk_47 + 164634685504*uk_48 + 41158671376*uk_49 + 16*uk_5 + 429593632487*uk_50 + 578793816225*uk_51 + 164634685504*uk_52 + 153424975*uk_53 + 329166310*uk_54 + 178530880*uk_55 + 44632720*uk_56 + 465854015*uk_57 + 627647625*uk_58 + 178530880*uk_59 + 167*uk_6 + 706211356*uk_60 + 383029888*uk_61 + 95757472*uk_62 + 999468614*uk_63 + 1346589450*uk_64 + 383029888*uk_65 + 207745024*uk_66 + 51936256*uk_67 + 542084672*uk_68 + 730353600*uk_69 + 225*uk_7 + 207745024*uk_70 + 12984064*uk_71 + 135521168*uk_72 + 182588400*uk_73 + 51936256*uk_74 + 1414502191*uk_75 + 1905766425*uk_76 + 542084672*uk_77 + 2567649375*uk_78 + 730353600*uk_79 + 64*uk_8 + 207745024*uk_80 + 166375*uk_81 + 356950*uk_82 + 193600*uk_83 + 48400*uk_84 + 505175*uk_85 + 680625*uk_86 + 193600*uk_87 + 765820*uk_88 + 415360*uk_89 + 2572416961*uk_9 + 103840*uk_90 + 1083830*uk_91 + 1460250*uk_92 + 415360*uk_93 + 225280*uk_94 + 56320*uk_95 + 587840*uk_96 + 792000*uk_97 + 225280*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 111540*uk_100 + 148500*uk_101 + 77880*uk_102 + 1570855*uk_103 + 2091375*uk_104 + 1096810*uk_105 + 2784375*uk_106 + 1460250*uk_107 + 765820*uk_108 + 6859*uk_109 + 963661*uk_11 + 42598*uk_110 + 4332*uk_111 + 61009*uk_112 + 81225*uk_113 + 42598*uk_114 + 264556*uk_115 + 26904*uk_116 + 378898*uk_117 + 504450*uk_118 + 264556*uk_119 + 5984842*uk_12 + 2736*uk_120 + 38532*uk_121 + 51300*uk_122 + 26904*uk_123 + 542659*uk_124 + 722475*uk_125 + 378898*uk_126 + 961875*uk_127 + 504450*uk_128 + 264556*uk_129 + 608628*uk_13 + 1643032*uk_130 + 167088*uk_131 + 2353156*uk_132 + 3132900*uk_133 + 1643032*uk_134 + 16992*uk_135 + 239304*uk_136 + 318600*uk_137 + 167088*uk_138 + 3370198*uk_139 + 8571511*uk_14 + 4486950*uk_140 + 2353156*uk_141 + 5973750*uk_142 + 3132900*uk_143 + 1643032*uk_144 + 1728*uk_145 + 24336*uk_146 + 32400*uk_147 + 16992*uk_148 + 342732*uk_149 + 11411775*uk_15 + 456300*uk_150 + 239304*uk_151 + 607500*uk_152 + 318600*uk_153 + 167088*uk_154 + 4826809*uk_155 + 6426225*uk_156 + 3370198*uk_157 + 8555625*uk_158 + 4486950*uk_159 + 5984842*uk_16 + 2353156*uk_160 + 11390625*uk_161 + 5973750*uk_162 + 3132900*uk_163 + 1643032*uk_164 + 3025*uk_17 + 1045*uk_18 + 6490*uk_19 + 55*uk_2 + 660*uk_20 + 9295*uk_21 + 12375*uk_22 + 6490*uk_23 + 361*uk_24 + 2242*uk_25 + 228*uk_26 + 3211*uk_27 + 4275*uk_28 + 2242*uk_29 + 19*uk_3 + 13924*uk_30 + 1416*uk_31 + 19942*uk_32 + 26550*uk_33 + 13924*uk_34 + 144*uk_35 + 2028*uk_36 + 2700*uk_37 + 1416*uk_38 + 28561*uk_39 + 118*uk_4 + 38025*uk_40 + 19942*uk_41 + 50625*uk_42 + 26550*uk_43 + 13924*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 48875922259*uk_47 + 303545201398*uk_48 + 30869003532*uk_49 + 12*uk_5 + 434738466409*uk_50 + 578793816225*uk_51 + 303545201398*uk_52 + 153424975*uk_53 + 53001355*uk_54 + 329166310*uk_55 + 33474540*uk_56 + 471433105*uk_57 + 627647625*uk_58 + 329166310*uk_59 + 169*uk_6 + 18309559*uk_60 + 113711998*uk_61 + 11563932*uk_62 + 162858709*uk_63 + 216823725*uk_64 + 113711998*uk_65 + 706211356*uk_66 + 71818104*uk_67 + 1011438298*uk_68 + 1346589450*uk_69 + 225*uk_7 + 706211356*uk_70 + 7303536*uk_71 + 102858132*uk_72 + 136941300*uk_73 + 71818104*uk_74 + 1448585359*uk_75 + 1928589975*uk_76 + 1011438298*uk_77 + 2567649375*uk_78 + 1346589450*uk_79 + 118*uk_8 + 706211356*uk_80 + 166375*uk_81 + 57475*uk_82 + 356950*uk_83 + 36300*uk_84 + 511225*uk_85 + 680625*uk_86 + 356950*uk_87 + 19855*uk_88 + 123310*uk_89 + 2572416961*uk_9 + 12540*uk_90 + 176605*uk_91 + 235125*uk_92 + 123310*uk_93 + 765820*uk_94 + 77880*uk_95 + 1096810*uk_96 + 1460250*uk_97 + 765820*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 150480*uk_100 + 198000*uk_101 + 16720*uk_102 + 1608255*uk_103 + 2116125*uk_104 + 178695*uk_105 + 2784375*uk_106 + 235125*uk_107 + 19855*uk_108 + 1092727*uk_109 + 5224057*uk_11 + 201571*uk_110 + 169744*uk_111 + 1814139*uk_112 + 2387025*uk_113 + 201571*uk_114 + 37183*uk_115 + 31312*uk_116 + 334647*uk_117 + 440325*uk_118 + 37183*uk_119 + 963661*uk_12 + 26368*uk_120 + 281808*uk_121 + 370800*uk_122 + 31312*uk_123 + 3011823*uk_124 + 3962925*uk_125 + 334647*uk_126 + 5214375*uk_127 + 440325*uk_128 + 37183*uk_129 + 811504*uk_13 + 6859*uk_130 + 5776*uk_131 + 61731*uk_132 + 81225*uk_133 + 6859*uk_134 + 4864*uk_135 + 51984*uk_136 + 68400*uk_137 + 5776*uk_138 + 555579*uk_139 + 8672949*uk_14 + 731025*uk_140 + 61731*uk_141 + 961875*uk_142 + 81225*uk_143 + 6859*uk_144 + 4096*uk_145 + 43776*uk_146 + 57600*uk_147 + 4864*uk_148 + 467856*uk_149 + 11411775*uk_15 + 615600*uk_150 + 51984*uk_151 + 810000*uk_152 + 68400*uk_153 + 5776*uk_154 + 5000211*uk_155 + 6579225*uk_156 + 555579*uk_157 + 8656875*uk_158 + 731025*uk_159 + 963661*uk_16 + 61731*uk_160 + 11390625*uk_161 + 961875*uk_162 + 81225*uk_163 + 6859*uk_164 + 3025*uk_17 + 5665*uk_18 + 1045*uk_19 + 55*uk_2 + 880*uk_20 + 9405*uk_21 + 12375*uk_22 + 1045*uk_23 + 10609*uk_24 + 1957*uk_25 + 1648*uk_26 + 17613*uk_27 + 23175*uk_28 + 1957*uk_29 + 103*uk_3 + 361*uk_30 + 304*uk_31 + 3249*uk_32 + 4275*uk_33 + 361*uk_34 + 256*uk_35 + 2736*uk_36 + 3600*uk_37 + 304*uk_38 + 29241*uk_39 + 19*uk_4 + 38475*uk_40 + 3249*uk_41 + 50625*uk_42 + 4275*uk_43 + 361*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 264958946983*uk_47 + 48875922259*uk_48 + 41158671376*uk_49 + 16*uk_5 + 439883300331*uk_50 + 578793816225*uk_51 + 48875922259*uk_52 + 153424975*uk_53 + 287323135*uk_54 + 53001355*uk_55 + 44632720*uk_56 + 477012195*uk_57 + 627647625*uk_58 + 53001355*uk_59 + 171*uk_6 + 538077871*uk_60 + 99257083*uk_61 + 83584912*uk_62 + 893313747*uk_63 + 1175412825*uk_64 + 99257083*uk_65 + 18309559*uk_66 + 15418576*uk_67 + 164786031*uk_68 + 216823725*uk_69 + 225*uk_7 + 18309559*uk_70 + 12984064*uk_71 + 138767184*uk_72 + 182588400*uk_73 + 15418576*uk_74 + 1483074279*uk_75 + 1951413525*uk_76 + 164786031*uk_77 + 2567649375*uk_78 + 216823725*uk_79 + 19*uk_8 + 18309559*uk_80 + 166375*uk_81 + 311575*uk_82 + 57475*uk_83 + 48400*uk_84 + 517275*uk_85 + 680625*uk_86 + 57475*uk_87 + 583495*uk_88 + 107635*uk_89 + 2572416961*uk_9 + 90640*uk_90 + 968715*uk_91 + 1274625*uk_92 + 107635*uk_93 + 19855*uk_94 + 16720*uk_95 + 178695*uk_96 + 235125*uk_97 + 19855*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 114180*uk_100 + 148500*uk_101 + 67980*uk_102 + 1646095*uk_103 + 2140875*uk_104 + 980045*uk_105 + 2784375*uk_106 + 1274625*uk_107 + 583495*uk_108 + 27000*uk_109 + 1521570*uk_11 + 92700*uk_110 + 10800*uk_111 + 155700*uk_112 + 202500*uk_113 + 92700*uk_114 + 318270*uk_115 + 37080*uk_116 + 534570*uk_117 + 695250*uk_118 + 318270*uk_119 + 5224057*uk_12 + 4320*uk_120 + 62280*uk_121 + 81000*uk_122 + 37080*uk_123 + 897870*uk_124 + 1167750*uk_125 + 534570*uk_126 + 1518750*uk_127 + 695250*uk_128 + 318270*uk_129 + 608628*uk_13 + 1092727*uk_130 + 127308*uk_131 + 1835357*uk_132 + 2387025*uk_133 + 1092727*uk_134 + 14832*uk_135 + 213828*uk_136 + 278100*uk_137 + 127308*uk_138 + 3082687*uk_139 + 8774387*uk_14 + 4009275*uk_140 + 1835357*uk_141 + 5214375*uk_142 + 2387025*uk_143 + 1092727*uk_144 + 1728*uk_145 + 24912*uk_146 + 32400*uk_147 + 14832*uk_148 + 359148*uk_149 + 11411775*uk_15 + 467100*uk_150 + 213828*uk_151 + 607500*uk_152 + 278100*uk_153 + 127308*uk_154 + 5177717*uk_155 + 6734025*uk_156 + 3082687*uk_157 + 8758125*uk_158 + 4009275*uk_159 + 5224057*uk_16 + 1835357*uk_160 + 11390625*uk_161 + 5214375*uk_162 + 2387025*uk_163 + 1092727*uk_164 + 3025*uk_17 + 1650*uk_18 + 5665*uk_19 + 55*uk_2 + 660*uk_20 + 9515*uk_21 + 12375*uk_22 + 5665*uk_23 + 900*uk_24 + 3090*uk_25 + 360*uk_26 + 5190*uk_27 + 6750*uk_28 + 3090*uk_29 + 30*uk_3 + 10609*uk_30 + 1236*uk_31 + 17819*uk_32 + 23175*uk_33 + 10609*uk_34 + 144*uk_35 + 2076*uk_36 + 2700*uk_37 + 1236*uk_38 + 29929*uk_39 + 103*uk_4 + 38925*uk_40 + 17819*uk_41 + 50625*uk_42 + 23175*uk_43 + 10609*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 77172508830*uk_47 + 264958946983*uk_48 + 30869003532*uk_49 + 12*uk_5 + 445028134253*uk_50 + 578793816225*uk_51 + 264958946983*uk_52 + 153424975*uk_53 + 83686350*uk_54 + 287323135*uk_55 + 33474540*uk_56 + 482591285*uk_57 + 627647625*uk_58 + 287323135*uk_59 + 173*uk_6 + 45647100*uk_60 + 156721710*uk_61 + 18258840*uk_62 + 263231610*uk_63 + 342353250*uk_64 + 156721710*uk_65 + 538077871*uk_66 + 62688684*uk_67 + 903761861*uk_68 + 1175412825*uk_69 + 225*uk_7 + 538077871*uk_70 + 7303536*uk_71 + 105292644*uk_72 + 136941300*uk_73 + 62688684*uk_74 + 1517968951*uk_75 + 1974237075*uk_76 + 903761861*uk_77 + 2567649375*uk_78 + 1175412825*uk_79 + 103*uk_8 + 538077871*uk_80 + 166375*uk_81 + 90750*uk_82 + 311575*uk_83 + 36300*uk_84 + 523325*uk_85 + 680625*uk_86 + 311575*uk_87 + 49500*uk_88 + 169950*uk_89 + 2572416961*uk_9 + 19800*uk_90 + 285450*uk_91 + 371250*uk_92 + 169950*uk_93 + 583495*uk_94 + 67980*uk_95 + 980045*uk_96 + 1274625*uk_97 + 583495*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 154000*uk_100 + 198000*uk_101 + 26400*uk_102 + 1684375*uk_103 + 2165625*uk_104 + 288750*uk_105 + 2784375*uk_106 + 371250*uk_107 + 49500*uk_108 + 2985984*uk_109 + 7303536*uk_11 + 622080*uk_110 + 331776*uk_111 + 3628800*uk_112 + 4665600*uk_113 + 622080*uk_114 + 129600*uk_115 + 69120*uk_116 + 756000*uk_117 + 972000*uk_118 + 129600*uk_119 + 1521570*uk_12 + 36864*uk_120 + 403200*uk_121 + 518400*uk_122 + 69120*uk_123 + 4410000*uk_124 + 5670000*uk_125 + 756000*uk_126 + 7290000*uk_127 + 972000*uk_128 + 129600*uk_129 + 811504*uk_13 + 27000*uk_130 + 14400*uk_131 + 157500*uk_132 + 202500*uk_133 + 27000*uk_134 + 7680*uk_135 + 84000*uk_136 + 108000*uk_137 + 14400*uk_138 + 918750*uk_139 + 8875825*uk_14 + 1181250*uk_140 + 157500*uk_141 + 1518750*uk_142 + 202500*uk_143 + 27000*uk_144 + 4096*uk_145 + 44800*uk_146 + 57600*uk_147 + 7680*uk_148 + 490000*uk_149 + 11411775*uk_15 + 630000*uk_150 + 84000*uk_151 + 810000*uk_152 + 108000*uk_153 + 14400*uk_154 + 5359375*uk_155 + 6890625*uk_156 + 918750*uk_157 + 8859375*uk_158 + 1181250*uk_159 + 1521570*uk_16 + 157500*uk_160 + 11390625*uk_161 + 1518750*uk_162 + 202500*uk_163 + 27000*uk_164 + 3025*uk_17 + 7920*uk_18 + 1650*uk_19 + 55*uk_2 + 880*uk_20 + 9625*uk_21 + 12375*uk_22 + 1650*uk_23 + 20736*uk_24 + 4320*uk_25 + 2304*uk_26 + 25200*uk_27 + 32400*uk_28 + 4320*uk_29 + 144*uk_3 + 900*uk_30 + 480*uk_31 + 5250*uk_32 + 6750*uk_33 + 900*uk_34 + 256*uk_35 + 2800*uk_36 + 3600*uk_37 + 480*uk_38 + 30625*uk_39 + 30*uk_4 + 39375*uk_40 + 5250*uk_41 + 50625*uk_42 + 6750*uk_43 + 900*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 370428042384*uk_47 + 77172508830*uk_48 + 41158671376*uk_49 + 16*uk_5 + 450172968175*uk_50 + 578793816225*uk_51 + 77172508830*uk_52 + 153424975*uk_53 + 401694480*uk_54 + 83686350*uk_55 + 44632720*uk_56 + 488170375*uk_57 + 627647625*uk_58 + 83686350*uk_59 + 175*uk_6 + 1051709184*uk_60 + 219106080*uk_61 + 116856576*uk_62 + 1278118800*uk_63 + 1643295600*uk_64 + 219106080*uk_65 + 45647100*uk_66 + 24345120*uk_67 + 266274750*uk_68 + 342353250*uk_69 + 225*uk_7 + 45647100*uk_70 + 12984064*uk_71 + 142013200*uk_72 + 182588400*uk_73 + 24345120*uk_74 + 1553269375*uk_75 + 1997060625*uk_76 + 266274750*uk_77 + 2567649375*uk_78 + 342353250*uk_79 + 30*uk_8 + 45647100*uk_80 + 166375*uk_81 + 435600*uk_82 + 90750*uk_83 + 48400*uk_84 + 529375*uk_85 + 680625*uk_86 + 90750*uk_87 + 1140480*uk_88 + 237600*uk_89 + 2572416961*uk_9 + 126720*uk_90 + 1386000*uk_91 + 1782000*uk_92 + 237600*uk_93 + 49500*uk_94 + 26400*uk_95 + 288750*uk_96 + 371250*uk_97 + 49500*uk_98 + 14080*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 116820*uk_100 + 148500*uk_101 + 95040*uk_102 + 1723095*uk_103 + 2190375*uk_104 + 1401840*uk_105 + 2784375*uk_106 + 1782000*uk_107 + 1140480*uk_108 + 912673*uk_109 + 4919743*uk_11 + 1354896*uk_110 + 112908*uk_111 + 1665393*uk_112 + 2117025*uk_113 + 1354896*uk_114 + 2011392*uk_115 + 167616*uk_116 + 2472336*uk_117 + 3142800*uk_118 + 2011392*uk_119 + 7303536*uk_12 + 13968*uk_120 + 206028*uk_121 + 261900*uk_122 + 167616*uk_123 + 3038913*uk_124 + 3863025*uk_125 + 2472336*uk_126 + 4910625*uk_127 + 3142800*uk_128 + 2011392*uk_129 + 608628*uk_13 + 2985984*uk_130 + 248832*uk_131 + 3670272*uk_132 + 4665600*uk_133 + 2985984*uk_134 + 20736*uk_135 + 305856*uk_136 + 388800*uk_137 + 248832*uk_138 + 4511376*uk_139 + 8977263*uk_14 + 5734800*uk_140 + 3670272*uk_141 + 7290000*uk_142 + 4665600*uk_143 + 2985984*uk_144 + 1728*uk_145 + 25488*uk_146 + 32400*uk_147 + 20736*uk_148 + 375948*uk_149 + 11411775*uk_15 + 477900*uk_150 + 305856*uk_151 + 607500*uk_152 + 388800*uk_153 + 248832*uk_154 + 5545233*uk_155 + 7049025*uk_156 + 4511376*uk_157 + 8960625*uk_158 + 5734800*uk_159 + 7303536*uk_16 + 3670272*uk_160 + 11390625*uk_161 + 7290000*uk_162 + 4665600*uk_163 + 2985984*uk_164 + 3025*uk_17 + 5335*uk_18 + 7920*uk_19 + 55*uk_2 + 660*uk_20 + 9735*uk_21 + 12375*uk_22 + 7920*uk_23 + 9409*uk_24 + 13968*uk_25 + 1164*uk_26 + 17169*uk_27 + 21825*uk_28 + 13968*uk_29 + 97*uk_3 + 20736*uk_30 + 1728*uk_31 + 25488*uk_32 + 32400*uk_33 + 20736*uk_34 + 144*uk_35 + 2124*uk_36 + 2700*uk_37 + 1728*uk_38 + 31329*uk_39 + 144*uk_4 + 39825*uk_40 + 25488*uk_41 + 50625*uk_42 + 32400*uk_43 + 20736*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 249524445217*uk_47 + 370428042384*uk_48 + 30869003532*uk_49 + 12*uk_5 + 455317802097*uk_50 + 578793816225*uk_51 + 370428042384*uk_52 + 153424975*uk_53 + 270585865*uk_54 + 401694480*uk_55 + 33474540*uk_56 + 493749465*uk_57 + 627647625*uk_58 + 401694480*uk_59 + 177*uk_6 + 477215071*uk_60 + 708442992*uk_61 + 59036916*uk_62 + 870794511*uk_63 + 1106942175*uk_64 + 708442992*uk_65 + 1051709184*uk_66 + 87642432*uk_67 + 1292725872*uk_68 + 1643295600*uk_69 + 225*uk_7 + 1051709184*uk_70 + 7303536*uk_71 + 107727156*uk_72 + 136941300*uk_73 + 87642432*uk_74 + 1588975551*uk_75 + 2019884175*uk_76 + 1292725872*uk_77 + 2567649375*uk_78 + 1643295600*uk_79 + 144*uk_8 + 1051709184*uk_80 + 166375*uk_81 + 293425*uk_82 + 435600*uk_83 + 36300*uk_84 + 535425*uk_85 + 680625*uk_86 + 435600*uk_87 + 517495*uk_88 + 768240*uk_89 + 2572416961*uk_9 + 64020*uk_90 + 944295*uk_91 + 1200375*uk_92 + 768240*uk_93 + 1140480*uk_94 + 95040*uk_95 + 1401840*uk_96 + 1782000*uk_97 + 1140480*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 118140*uk_100 + 148500*uk_101 + 64020*uk_102 + 1762255*uk_103 + 2215125*uk_104 + 954965*uk_105 + 2784375*uk_106 + 1200375*uk_107 + 517495*uk_108 + 238328*uk_109 + 3144578*uk_11 + 372868*uk_110 + 46128*uk_111 + 688076*uk_112 + 864900*uk_113 + 372868*uk_114 + 583358*uk_115 + 72168*uk_116 + 1076506*uk_117 + 1353150*uk_118 + 583358*uk_119 + 4919743*uk_12 + 8928*uk_120 + 133176*uk_121 + 167400*uk_122 + 72168*uk_123 + 1986542*uk_124 + 2497050*uk_125 + 1076506*uk_126 + 3138750*uk_127 + 1353150*uk_128 + 583358*uk_129 + 608628*uk_13 + 912673*uk_130 + 112908*uk_131 + 1684211*uk_132 + 2117025*uk_133 + 912673*uk_134 + 13968*uk_135 + 208356*uk_136 + 261900*uk_137 + 112908*uk_138 + 3107977*uk_139 + 9078701*uk_14 + 3906675*uk_140 + 1684211*uk_141 + 4910625*uk_142 + 2117025*uk_143 + 912673*uk_144 + 1728*uk_145 + 25776*uk_146 + 32400*uk_147 + 13968*uk_148 + 384492*uk_149 + 11411775*uk_15 + 483300*uk_150 + 208356*uk_151 + 607500*uk_152 + 261900*uk_153 + 112908*uk_154 + 5735339*uk_155 + 7209225*uk_156 + 3107977*uk_157 + 9061875*uk_158 + 3906675*uk_159 + 4919743*uk_16 + 1684211*uk_160 + 11390625*uk_161 + 4910625*uk_162 + 2117025*uk_163 + 912673*uk_164 + 3025*uk_17 + 3410*uk_18 + 5335*uk_19 + 55*uk_2 + 660*uk_20 + 9845*uk_21 + 12375*uk_22 + 5335*uk_23 + 3844*uk_24 + 6014*uk_25 + 744*uk_26 + 11098*uk_27 + 13950*uk_28 + 6014*uk_29 + 62*uk_3 + 9409*uk_30 + 1164*uk_31 + 17363*uk_32 + 21825*uk_33 + 9409*uk_34 + 144*uk_35 + 2148*uk_36 + 2700*uk_37 + 1164*uk_38 + 32041*uk_39 + 97*uk_4 + 40275*uk_40 + 17363*uk_41 + 50625*uk_42 + 21825*uk_43 + 9409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 159489851582*uk_47 + 249524445217*uk_48 + 30869003532*uk_49 + 12*uk_5 + 460462636019*uk_50 + 578793816225*uk_51 + 249524445217*uk_52 + 153424975*uk_53 + 172951790*uk_54 + 270585865*uk_55 + 33474540*uk_56 + 499328555*uk_57 + 627647625*uk_58 + 270585865*uk_59 + 179*uk_6 + 194963836*uk_60 + 305024066*uk_61 + 37734936*uk_62 + 562879462*uk_63 + 707530050*uk_64 + 305024066*uk_65 + 477215071*uk_66 + 59036916*uk_67 + 880633997*uk_68 + 1106942175*uk_69 + 225*uk_7 + 477215071*uk_70 + 7303536*uk_71 + 108944412*uk_72 + 136941300*uk_73 + 59036916*uk_74 + 1625087479*uk_75 + 2042707725*uk_76 + 880633997*uk_77 + 2567649375*uk_78 + 1106942175*uk_79 + 97*uk_8 + 477215071*uk_80 + 166375*uk_81 + 187550*uk_82 + 293425*uk_83 + 36300*uk_84 + 541475*uk_85 + 680625*uk_86 + 293425*uk_87 + 211420*uk_88 + 330770*uk_89 + 2572416961*uk_9 + 40920*uk_90 + 610390*uk_91 + 767250*uk_92 + 330770*uk_93 + 517495*uk_94 + 64020*uk_95 + 954965*uk_96 + 1200375*uk_97 + 517495*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 119460*uk_100 + 148500*uk_101 + 40920*uk_102 + 1801855*uk_103 + 2239875*uk_104 + 617210*uk_105 + 2784375*uk_106 + 767250*uk_107 + 211420*uk_108 + 59319*uk_109 + 1978041*uk_11 + 94302*uk_110 + 18252*uk_111 + 275301*uk_112 + 342225*uk_113 + 94302*uk_114 + 149916*uk_115 + 29016*uk_116 + 437658*uk_117 + 544050*uk_118 + 149916*uk_119 + 3144578*uk_12 + 5616*uk_120 + 84708*uk_121 + 105300*uk_122 + 29016*uk_123 + 1277679*uk_124 + 1588275*uk_125 + 437658*uk_126 + 1974375*uk_127 + 544050*uk_128 + 149916*uk_129 + 608628*uk_13 + 238328*uk_130 + 46128*uk_131 + 695764*uk_132 + 864900*uk_133 + 238328*uk_134 + 8928*uk_135 + 134664*uk_136 + 167400*uk_137 + 46128*uk_138 + 2031182*uk_139 + 9180139*uk_14 + 2524950*uk_140 + 695764*uk_141 + 3138750*uk_142 + 864900*uk_143 + 238328*uk_144 + 1728*uk_145 + 26064*uk_146 + 32400*uk_147 + 8928*uk_148 + 393132*uk_149 + 11411775*uk_15 + 488700*uk_150 + 134664*uk_151 + 607500*uk_152 + 167400*uk_153 + 46128*uk_154 + 5929741*uk_155 + 7371225*uk_156 + 2031182*uk_157 + 9163125*uk_158 + 2524950*uk_159 + 3144578*uk_16 + 695764*uk_160 + 11390625*uk_161 + 3138750*uk_162 + 864900*uk_163 + 238328*uk_164 + 3025*uk_17 + 2145*uk_18 + 3410*uk_19 + 55*uk_2 + 660*uk_20 + 9955*uk_21 + 12375*uk_22 + 3410*uk_23 + 1521*uk_24 + 2418*uk_25 + 468*uk_26 + 7059*uk_27 + 8775*uk_28 + 2418*uk_29 + 39*uk_3 + 3844*uk_30 + 744*uk_31 + 11222*uk_32 + 13950*uk_33 + 3844*uk_34 + 144*uk_35 + 2172*uk_36 + 2700*uk_37 + 744*uk_38 + 32761*uk_39 + 62*uk_4 + 40725*uk_40 + 11222*uk_41 + 50625*uk_42 + 13950*uk_43 + 3844*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 100324261479*uk_47 + 159489851582*uk_48 + 30869003532*uk_49 + 12*uk_5 + 465607469941*uk_50 + 578793816225*uk_51 + 159489851582*uk_52 + 153424975*uk_53 + 108792255*uk_54 + 172951790*uk_55 + 33474540*uk_56 + 504907645*uk_57 + 627647625*uk_58 + 172951790*uk_59 + 181*uk_6 + 77143599*uk_60 + 122638542*uk_61 + 23736492*uk_62 + 358025421*uk_63 + 445059225*uk_64 + 122638542*uk_65 + 194963836*uk_66 + 37734936*uk_67 + 569168618*uk_68 + 707530050*uk_69 + 225*uk_7 + 194963836*uk_70 + 7303536*uk_71 + 110161668*uk_72 + 136941300*uk_73 + 37734936*uk_74 + 1661605159*uk_75 + 2065531275*uk_76 + 569168618*uk_77 + 2567649375*uk_78 + 707530050*uk_79 + 62*uk_8 + 194963836*uk_80 + 166375*uk_81 + 117975*uk_82 + 187550*uk_83 + 36300*uk_84 + 547525*uk_85 + 680625*uk_86 + 187550*uk_87 + 83655*uk_88 + 132990*uk_89 + 2572416961*uk_9 + 25740*uk_90 + 388245*uk_91 + 482625*uk_92 + 132990*uk_93 + 211420*uk_94 + 40920*uk_95 + 617210*uk_96 + 767250*uk_97 + 211420*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 120780*uk_100 + 148500*uk_101 + 25740*uk_102 + 1841895*uk_103 + 2264625*uk_104 + 392535*uk_105 + 2784375*uk_106 + 482625*uk_107 + 83655*uk_108 + 21952*uk_109 + 1420132*uk_11 + 30576*uk_110 + 9408*uk_111 + 143472*uk_112 + 176400*uk_113 + 30576*uk_114 + 42588*uk_115 + 13104*uk_116 + 199836*uk_117 + 245700*uk_118 + 42588*uk_119 + 1978041*uk_12 + 4032*uk_120 + 61488*uk_121 + 75600*uk_122 + 13104*uk_123 + 937692*uk_124 + 1152900*uk_125 + 199836*uk_126 + 1417500*uk_127 + 245700*uk_128 + 42588*uk_129 + 608628*uk_13 + 59319*uk_130 + 18252*uk_131 + 278343*uk_132 + 342225*uk_133 + 59319*uk_134 + 5616*uk_135 + 85644*uk_136 + 105300*uk_137 + 18252*uk_138 + 1306071*uk_139 + 9281577*uk_14 + 1605825*uk_140 + 278343*uk_141 + 1974375*uk_142 + 342225*uk_143 + 59319*uk_144 + 1728*uk_145 + 26352*uk_146 + 32400*uk_147 + 5616*uk_148 + 401868*uk_149 + 11411775*uk_15 + 494100*uk_150 + 85644*uk_151 + 607500*uk_152 + 105300*uk_153 + 18252*uk_154 + 6128487*uk_155 + 7535025*uk_156 + 1306071*uk_157 + 9264375*uk_158 + 1605825*uk_159 + 1978041*uk_16 + 278343*uk_160 + 11390625*uk_161 + 1974375*uk_162 + 342225*uk_163 + 59319*uk_164 + 3025*uk_17 + 1540*uk_18 + 2145*uk_19 + 55*uk_2 + 660*uk_20 + 10065*uk_21 + 12375*uk_22 + 2145*uk_23 + 784*uk_24 + 1092*uk_25 + 336*uk_26 + 5124*uk_27 + 6300*uk_28 + 1092*uk_29 + 28*uk_3 + 1521*uk_30 + 468*uk_31 + 7137*uk_32 + 8775*uk_33 + 1521*uk_34 + 144*uk_35 + 2196*uk_36 + 2700*uk_37 + 468*uk_38 + 33489*uk_39 + 39*uk_4 + 41175*uk_40 + 7137*uk_41 + 50625*uk_42 + 8775*uk_43 + 1521*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 72027674908*uk_47 + 100324261479*uk_48 + 30869003532*uk_49 + 12*uk_5 + 470752303863*uk_50 + 578793816225*uk_51 + 100324261479*uk_52 + 153424975*uk_53 + 78107260*uk_54 + 108792255*uk_55 + 33474540*uk_56 + 510486735*uk_57 + 627647625*uk_58 + 108792255*uk_59 + 183*uk_6 + 39763696*uk_60 + 55385148*uk_61 + 17041584*uk_62 + 259884156*uk_63 + 319529700*uk_64 + 55385148*uk_65 + 77143599*uk_66 + 23736492*uk_67 + 361981503*uk_68 + 445059225*uk_69 + 225*uk_7 + 77143599*uk_70 + 7303536*uk_71 + 111378924*uk_72 + 136941300*uk_73 + 23736492*uk_74 + 1698528591*uk_75 + 2088354825*uk_76 + 361981503*uk_77 + 2567649375*uk_78 + 445059225*uk_79 + 39*uk_8 + 77143599*uk_80 + 166375*uk_81 + 84700*uk_82 + 117975*uk_83 + 36300*uk_84 + 553575*uk_85 + 680625*uk_86 + 117975*uk_87 + 43120*uk_88 + 60060*uk_89 + 2572416961*uk_9 + 18480*uk_90 + 281820*uk_91 + 346500*uk_92 + 60060*uk_93 + 83655*uk_94 + 25740*uk_95 + 392535*uk_96 + 482625*uk_97 + 83655*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 122100*uk_100 + 148500*uk_101 + 18480*uk_102 + 1882375*uk_103 + 2289375*uk_104 + 284900*uk_105 + 2784375*uk_106 + 346500*uk_107 + 43120*uk_108 + 24389*uk_109 + 1470851*uk_11 + 23548*uk_110 + 10092*uk_111 + 155585*uk_112 + 189225*uk_113 + 23548*uk_114 + 22736*uk_115 + 9744*uk_116 + 150220*uk_117 + 182700*uk_118 + 22736*uk_119 + 1420132*uk_12 + 4176*uk_120 + 64380*uk_121 + 78300*uk_122 + 9744*uk_123 + 992525*uk_124 + 1207125*uk_125 + 150220*uk_126 + 1468125*uk_127 + 182700*uk_128 + 22736*uk_129 + 608628*uk_13 + 21952*uk_130 + 9408*uk_131 + 145040*uk_132 + 176400*uk_133 + 21952*uk_134 + 4032*uk_135 + 62160*uk_136 + 75600*uk_137 + 9408*uk_138 + 958300*uk_139 + 9383015*uk_14 + 1165500*uk_140 + 145040*uk_141 + 1417500*uk_142 + 176400*uk_143 + 21952*uk_144 + 1728*uk_145 + 26640*uk_146 + 32400*uk_147 + 4032*uk_148 + 410700*uk_149 + 11411775*uk_15 + 499500*uk_150 + 62160*uk_151 + 607500*uk_152 + 75600*uk_153 + 9408*uk_154 + 6331625*uk_155 + 7700625*uk_156 + 958300*uk_157 + 9365625*uk_158 + 1165500*uk_159 + 1420132*uk_16 + 145040*uk_160 + 11390625*uk_161 + 1417500*uk_162 + 176400*uk_163 + 21952*uk_164 + 3025*uk_17 + 1595*uk_18 + 1540*uk_19 + 55*uk_2 + 660*uk_20 + 10175*uk_21 + 12375*uk_22 + 1540*uk_23 + 841*uk_24 + 812*uk_25 + 348*uk_26 + 5365*uk_27 + 6525*uk_28 + 812*uk_29 + 29*uk_3 + 784*uk_30 + 336*uk_31 + 5180*uk_32 + 6300*uk_33 + 784*uk_34 + 144*uk_35 + 2220*uk_36 + 2700*uk_37 + 336*uk_38 + 34225*uk_39 + 28*uk_4 + 41625*uk_40 + 5180*uk_41 + 50625*uk_42 + 6300*uk_43 + 784*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 74600091869*uk_47 + 72027674908*uk_48 + 30869003532*uk_49 + 12*uk_5 + 475897137785*uk_50 + 578793816225*uk_51 + 72027674908*uk_52 + 153424975*uk_53 + 80896805*uk_54 + 78107260*uk_55 + 33474540*uk_56 + 516065825*uk_57 + 627647625*uk_58 + 78107260*uk_59 + 185*uk_6 + 42654679*uk_60 + 41183828*uk_61 + 17650212*uk_62 + 272107435*uk_63 + 330941475*uk_64 + 41183828*uk_65 + 39763696*uk_66 + 17041584*uk_67 + 262724420*uk_68 + 319529700*uk_69 + 225*uk_7 + 39763696*uk_70 + 7303536*uk_71 + 112596180*uk_72 + 136941300*uk_73 + 17041584*uk_74 + 1735857775*uk_75 + 2111178375*uk_76 + 262724420*uk_77 + 2567649375*uk_78 + 319529700*uk_79 + 28*uk_8 + 39763696*uk_80 + 166375*uk_81 + 87725*uk_82 + 84700*uk_83 + 36300*uk_84 + 559625*uk_85 + 680625*uk_86 + 84700*uk_87 + 46255*uk_88 + 44660*uk_89 + 2572416961*uk_9 + 19140*uk_90 + 295075*uk_91 + 358875*uk_92 + 44660*uk_93 + 43120*uk_94 + 18480*uk_95 + 284900*uk_96 + 346500*uk_97 + 43120*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 123420*uk_100 + 148500*uk_101 + 19140*uk_102 + 1923295*uk_103 + 2314125*uk_104 + 298265*uk_105 + 2784375*uk_106 + 358875*uk_107 + 46255*uk_108 + 74088*uk_109 + 2130198*uk_11 + 51156*uk_110 + 21168*uk_111 + 329868*uk_112 + 396900*uk_113 + 51156*uk_114 + 35322*uk_115 + 14616*uk_116 + 227766*uk_117 + 274050*uk_118 + 35322*uk_119 + 1470851*uk_12 + 6048*uk_120 + 94248*uk_121 + 113400*uk_122 + 14616*uk_123 + 1468698*uk_124 + 1767150*uk_125 + 227766*uk_126 + 2126250*uk_127 + 274050*uk_128 + 35322*uk_129 + 608628*uk_13 + 24389*uk_130 + 10092*uk_131 + 157267*uk_132 + 189225*uk_133 + 24389*uk_134 + 4176*uk_135 + 65076*uk_136 + 78300*uk_137 + 10092*uk_138 + 1014101*uk_139 + 9484453*uk_14 + 1220175*uk_140 + 157267*uk_141 + 1468125*uk_142 + 189225*uk_143 + 24389*uk_144 + 1728*uk_145 + 26928*uk_146 + 32400*uk_147 + 4176*uk_148 + 419628*uk_149 + 11411775*uk_15 + 504900*uk_150 + 65076*uk_151 + 607500*uk_152 + 78300*uk_153 + 10092*uk_154 + 6539203*uk_155 + 7868025*uk_156 + 1014101*uk_157 + 9466875*uk_158 + 1220175*uk_159 + 1470851*uk_16 + 157267*uk_160 + 11390625*uk_161 + 1468125*uk_162 + 189225*uk_163 + 24389*uk_164 + 3025*uk_17 + 2310*uk_18 + 1595*uk_19 + 55*uk_2 + 660*uk_20 + 10285*uk_21 + 12375*uk_22 + 1595*uk_23 + 1764*uk_24 + 1218*uk_25 + 504*uk_26 + 7854*uk_27 + 9450*uk_28 + 1218*uk_29 + 42*uk_3 + 841*uk_30 + 348*uk_31 + 5423*uk_32 + 6525*uk_33 + 841*uk_34 + 144*uk_35 + 2244*uk_36 + 2700*uk_37 + 348*uk_38 + 34969*uk_39 + 29*uk_4 + 42075*uk_40 + 5423*uk_41 + 50625*uk_42 + 6525*uk_43 + 841*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 108041512362*uk_47 + 74600091869*uk_48 + 30869003532*uk_49 + 12*uk_5 + 481041971707*uk_50 + 578793816225*uk_51 + 74600091869*uk_52 + 153424975*uk_53 + 117160890*uk_54 + 80896805*uk_55 + 33474540*uk_56 + 521644915*uk_57 + 627647625*uk_58 + 80896805*uk_59 + 187*uk_6 + 89468316*uk_60 + 61775742*uk_61 + 25562376*uk_62 + 398347026*uk_63 + 479294550*uk_64 + 61775742*uk_65 + 42654679*uk_66 + 17650212*uk_67 + 275049137*uk_68 + 330941475*uk_69 + 225*uk_7 + 42654679*uk_70 + 7303536*uk_71 + 113813436*uk_72 + 136941300*uk_73 + 17650212*uk_74 + 1773592711*uk_75 + 2134001925*uk_76 + 275049137*uk_77 + 2567649375*uk_78 + 330941475*uk_79 + 29*uk_8 + 42654679*uk_80 + 166375*uk_81 + 127050*uk_82 + 87725*uk_83 + 36300*uk_84 + 565675*uk_85 + 680625*uk_86 + 87725*uk_87 + 97020*uk_88 + 66990*uk_89 + 2572416961*uk_9 + 27720*uk_90 + 431970*uk_91 + 519750*uk_92 + 66990*uk_93 + 46255*uk_94 + 19140*uk_95 + 298265*uk_96 + 358875*uk_97 + 46255*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 124740*uk_100 + 148500*uk_101 + 27720*uk_102 + 1964655*uk_103 + 2338875*uk_104 + 436590*uk_105 + 2784375*uk_106 + 519750*uk_107 + 97020*uk_108 + 300763*uk_109 + 3398173*uk_11 + 188538*uk_110 + 53868*uk_111 + 848421*uk_112 + 1010025*uk_113 + 188538*uk_114 + 118188*uk_115 + 33768*uk_116 + 531846*uk_117 + 633150*uk_118 + 118188*uk_119 + 2130198*uk_12 + 9648*uk_120 + 151956*uk_121 + 180900*uk_122 + 33768*uk_123 + 2393307*uk_124 + 2849175*uk_125 + 531846*uk_126 + 3391875*uk_127 + 633150*uk_128 + 118188*uk_129 + 608628*uk_13 + 74088*uk_130 + 21168*uk_131 + 333396*uk_132 + 396900*uk_133 + 74088*uk_134 + 6048*uk_135 + 95256*uk_136 + 113400*uk_137 + 21168*uk_138 + 1500282*uk_139 + 9585891*uk_14 + 1786050*uk_140 + 333396*uk_141 + 2126250*uk_142 + 396900*uk_143 + 74088*uk_144 + 1728*uk_145 + 27216*uk_146 + 32400*uk_147 + 6048*uk_148 + 428652*uk_149 + 11411775*uk_15 + 510300*uk_150 + 95256*uk_151 + 607500*uk_152 + 113400*uk_153 + 21168*uk_154 + 6751269*uk_155 + 8037225*uk_156 + 1500282*uk_157 + 9568125*uk_158 + 1786050*uk_159 + 2130198*uk_16 + 333396*uk_160 + 11390625*uk_161 + 2126250*uk_162 + 396900*uk_163 + 74088*uk_164 + 3025*uk_17 + 3685*uk_18 + 2310*uk_19 + 55*uk_2 + 660*uk_20 + 10395*uk_21 + 12375*uk_22 + 2310*uk_23 + 4489*uk_24 + 2814*uk_25 + 804*uk_26 + 12663*uk_27 + 15075*uk_28 + 2814*uk_29 + 67*uk_3 + 1764*uk_30 + 504*uk_31 + 7938*uk_32 + 9450*uk_33 + 1764*uk_34 + 144*uk_35 + 2268*uk_36 + 2700*uk_37 + 504*uk_38 + 35721*uk_39 + 42*uk_4 + 42525*uk_40 + 7938*uk_41 + 50625*uk_42 + 9450*uk_43 + 1764*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 172351936387*uk_47 + 108041512362*uk_48 + 30869003532*uk_49 + 12*uk_5 + 486186805629*uk_50 + 578793816225*uk_51 + 108041512362*uk_52 + 153424975*uk_53 + 186899515*uk_54 + 117160890*uk_55 + 33474540*uk_56 + 527224005*uk_57 + 627647625*uk_58 + 117160890*uk_59 + 189*uk_6 + 227677591*uk_60 + 142723266*uk_61 + 40778076*uk_62 + 642254697*uk_63 + 764588925*uk_64 + 142723266*uk_65 + 89468316*uk_66 + 25562376*uk_67 + 402607422*uk_68 + 479294550*uk_69 + 225*uk_7 + 89468316*uk_70 + 7303536*uk_71 + 115030692*uk_72 + 136941300*uk_73 + 25562376*uk_74 + 1811733399*uk_75 + 2156825475*uk_76 + 402607422*uk_77 + 2567649375*uk_78 + 479294550*uk_79 + 42*uk_8 + 89468316*uk_80 + 166375*uk_81 + 202675*uk_82 + 127050*uk_83 + 36300*uk_84 + 571725*uk_85 + 680625*uk_86 + 127050*uk_87 + 246895*uk_88 + 154770*uk_89 + 2572416961*uk_9 + 44220*uk_90 + 696465*uk_91 + 829125*uk_92 + 154770*uk_93 + 97020*uk_94 + 27720*uk_95 + 436590*uk_96 + 519750*uk_97 + 97020*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 126060*uk_100 + 148500*uk_101 + 44220*uk_102 + 2006455*uk_103 + 2363625*uk_104 + 703835*uk_105 + 2784375*uk_106 + 829125*uk_107 + 246895*uk_108 + 1124864*uk_109 + 5274776*uk_11 + 724672*uk_110 + 129792*uk_111 + 2065856*uk_112 + 2433600*uk_113 + 724672*uk_114 + 466856*uk_115 + 83616*uk_116 + 1330888*uk_117 + 1567800*uk_118 + 466856*uk_119 + 3398173*uk_12 + 14976*uk_120 + 238368*uk_121 + 280800*uk_122 + 83616*uk_123 + 3794024*uk_124 + 4469400*uk_125 + 1330888*uk_126 + 5265000*uk_127 + 1567800*uk_128 + 466856*uk_129 + 608628*uk_13 + 300763*uk_130 + 53868*uk_131 + 857399*uk_132 + 1010025*uk_133 + 300763*uk_134 + 9648*uk_135 + 153564*uk_136 + 180900*uk_137 + 53868*uk_138 + 2444227*uk_139 + 9687329*uk_14 + 2879325*uk_140 + 857399*uk_141 + 3391875*uk_142 + 1010025*uk_143 + 300763*uk_144 + 1728*uk_145 + 27504*uk_146 + 32400*uk_147 + 9648*uk_148 + 437772*uk_149 + 11411775*uk_15 + 515700*uk_150 + 153564*uk_151 + 607500*uk_152 + 180900*uk_153 + 53868*uk_154 + 6967871*uk_155 + 8208225*uk_156 + 2444227*uk_157 + 9669375*uk_158 + 2879325*uk_159 + 3398173*uk_16 + 857399*uk_160 + 11390625*uk_161 + 3391875*uk_162 + 1010025*uk_163 + 300763*uk_164 + 3025*uk_17 + 5720*uk_18 + 3685*uk_19 + 55*uk_2 + 660*uk_20 + 10505*uk_21 + 12375*uk_22 + 3685*uk_23 + 10816*uk_24 + 6968*uk_25 + 1248*uk_26 + 19864*uk_27 + 23400*uk_28 + 6968*uk_29 + 104*uk_3 + 4489*uk_30 + 804*uk_31 + 12797*uk_32 + 15075*uk_33 + 4489*uk_34 + 144*uk_35 + 2292*uk_36 + 2700*uk_37 + 804*uk_38 + 36481*uk_39 + 67*uk_4 + 42975*uk_40 + 12797*uk_41 + 50625*uk_42 + 15075*uk_43 + 4489*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 267531363944*uk_47 + 172351936387*uk_48 + 30869003532*uk_49 + 12*uk_5 + 491331639551*uk_50 + 578793816225*uk_51 + 172351936387*uk_52 + 153424975*uk_53 + 290112680*uk_54 + 186899515*uk_55 + 33474540*uk_56 + 532803095*uk_57 + 627647625*uk_58 + 186899515*uk_59 + 191*uk_6 + 548576704*uk_60 + 353409992*uk_61 + 63297312*uk_62 + 1007482216*uk_63 + 1186824600*uk_64 + 353409992*uk_65 + 227677591*uk_66 + 40778076*uk_67 + 649051043*uk_68 + 764588925*uk_69 + 225*uk_7 + 227677591*uk_70 + 7303536*uk_71 + 116247948*uk_72 + 136941300*uk_73 + 40778076*uk_74 + 1850279839*uk_75 + 2179649025*uk_76 + 649051043*uk_77 + 2567649375*uk_78 + 764588925*uk_79 + 67*uk_8 + 227677591*uk_80 + 166375*uk_81 + 314600*uk_82 + 202675*uk_83 + 36300*uk_84 + 577775*uk_85 + 680625*uk_86 + 202675*uk_87 + 594880*uk_88 + 383240*uk_89 + 2572416961*uk_9 + 68640*uk_90 + 1092520*uk_91 + 1287000*uk_92 + 383240*uk_93 + 246895*uk_94 + 44220*uk_95 + 703835*uk_96 + 829125*uk_97 + 246895*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 127380*uk_100 + 148500*uk_101 + 68640*uk_102 + 2048695*uk_103 + 2388375*uk_104 + 1103960*uk_105 + 2784375*uk_106 + 1287000*uk_107 + 594880*uk_108 + 3581577*uk_109 + 7760007*uk_11 + 2434536*uk_110 + 280908*uk_111 + 4517937*uk_112 + 5267025*uk_113 + 2434536*uk_114 + 1654848*uk_115 + 190944*uk_116 + 3071016*uk_117 + 3580200*uk_118 + 1654848*uk_119 + 5274776*uk_12 + 22032*uk_120 + 354348*uk_121 + 413100*uk_122 + 190944*uk_123 + 5699097*uk_124 + 6644025*uk_125 + 3071016*uk_126 + 7745625*uk_127 + 3580200*uk_128 + 1654848*uk_129 + 608628*uk_13 + 1124864*uk_130 + 129792*uk_131 + 2087488*uk_132 + 2433600*uk_133 + 1124864*uk_134 + 14976*uk_135 + 240864*uk_136 + 280800*uk_137 + 129792*uk_138 + 3873896*uk_139 + 9788767*uk_14 + 4516200*uk_140 + 2087488*uk_141 + 5265000*uk_142 + 2433600*uk_143 + 1124864*uk_144 + 1728*uk_145 + 27792*uk_146 + 32400*uk_147 + 14976*uk_148 + 446988*uk_149 + 11411775*uk_15 + 521100*uk_150 + 240864*uk_151 + 607500*uk_152 + 280800*uk_153 + 129792*uk_154 + 7189057*uk_155 + 8381025*uk_156 + 3873896*uk_157 + 9770625*uk_158 + 4516200*uk_159 + 5274776*uk_16 + 2087488*uk_160 + 11390625*uk_161 + 5265000*uk_162 + 2433600*uk_163 + 1124864*uk_164 + 3025*uk_17 + 8415*uk_18 + 5720*uk_19 + 55*uk_2 + 660*uk_20 + 10615*uk_21 + 12375*uk_22 + 5720*uk_23 + 23409*uk_24 + 15912*uk_25 + 1836*uk_26 + 29529*uk_27 + 34425*uk_28 + 15912*uk_29 + 153*uk_3 + 10816*uk_30 + 1248*uk_31 + 20072*uk_32 + 23400*uk_33 + 10816*uk_34 + 144*uk_35 + 2316*uk_36 + 2700*uk_37 + 1248*uk_38 + 37249*uk_39 + 104*uk_4 + 43425*uk_40 + 20072*uk_41 + 50625*uk_42 + 23400*uk_43 + 10816*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 393579795033*uk_47 + 267531363944*uk_48 + 30869003532*uk_49 + 12*uk_5 + 496476473473*uk_50 + 578793816225*uk_51 + 267531363944*uk_52 + 153424975*uk_53 + 426800385*uk_54 + 290112680*uk_55 + 33474540*uk_56 + 538382185*uk_57 + 627647625*uk_58 + 290112680*uk_59 + 193*uk_6 + 1187281071*uk_60 + 807040728*uk_61 + 93120084*uk_62 + 1497681351*uk_63 + 1746001575*uk_64 + 807040728*uk_65 + 548576704*uk_66 + 63297312*uk_67 + 1018031768*uk_68 + 1186824600*uk_69 + 225*uk_7 + 548576704*uk_70 + 7303536*uk_71 + 117465204*uk_72 + 136941300*uk_73 + 63297312*uk_74 + 1889232031*uk_75 + 2202472575*uk_76 + 1018031768*uk_77 + 2567649375*uk_78 + 1186824600*uk_79 + 104*uk_8 + 548576704*uk_80 + 166375*uk_81 + 462825*uk_82 + 314600*uk_83 + 36300*uk_84 + 583825*uk_85 + 680625*uk_86 + 314600*uk_87 + 1287495*uk_88 + 875160*uk_89 + 2572416961*uk_9 + 100980*uk_90 + 1624095*uk_91 + 1893375*uk_92 + 875160*uk_93 + 594880*uk_94 + 68640*uk_95 + 1103960*uk_96 + 1287000*uk_97 + 594880*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 85800*uk_100 + 99000*uk_101 + 67320*uk_102 + 2091375*uk_103 + 2413125*uk_104 + 1640925*uk_105 + 2784375*uk_106 + 1893375*uk_107 + 1287495*uk_108 + 6859*uk_109 + 963661*uk_11 + 55233*uk_110 + 2888*uk_111 + 70395*uk_112 + 81225*uk_113 + 55233*uk_114 + 444771*uk_115 + 23256*uk_116 + 566865*uk_117 + 654075*uk_118 + 444771*uk_119 + 7760007*uk_12 + 1216*uk_120 + 29640*uk_121 + 34200*uk_122 + 23256*uk_123 + 722475*uk_124 + 833625*uk_125 + 566865*uk_126 + 961875*uk_127 + 654075*uk_128 + 444771*uk_129 + 405752*uk_13 + 3581577*uk_130 + 187272*uk_131 + 4564755*uk_132 + 5267025*uk_133 + 3581577*uk_134 + 9792*uk_135 + 238680*uk_136 + 275400*uk_137 + 187272*uk_138 + 5817825*uk_139 + 9890205*uk_14 + 6712875*uk_140 + 4564755*uk_141 + 7745625*uk_142 + 5267025*uk_143 + 3581577*uk_144 + 512*uk_145 + 12480*uk_146 + 14400*uk_147 + 9792*uk_148 + 304200*uk_149 + 11411775*uk_15 + 351000*uk_150 + 238680*uk_151 + 405000*uk_152 + 275400*uk_153 + 187272*uk_154 + 7414875*uk_155 + 8555625*uk_156 + 5817825*uk_157 + 9871875*uk_158 + 6712875*uk_159 + 7760007*uk_16 + 4564755*uk_160 + 11390625*uk_161 + 7745625*uk_162 + 5267025*uk_163 + 3581577*uk_164 + 3025*uk_17 + 1045*uk_18 + 8415*uk_19 + 55*uk_2 + 440*uk_20 + 10725*uk_21 + 12375*uk_22 + 8415*uk_23 + 361*uk_24 + 2907*uk_25 + 152*uk_26 + 3705*uk_27 + 4275*uk_28 + 2907*uk_29 + 19*uk_3 + 23409*uk_30 + 1224*uk_31 + 29835*uk_32 + 34425*uk_33 + 23409*uk_34 + 64*uk_35 + 1560*uk_36 + 1800*uk_37 + 1224*uk_38 + 38025*uk_39 + 153*uk_4 + 43875*uk_40 + 29835*uk_41 + 50625*uk_42 + 34425*uk_43 + 23409*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 48875922259*uk_47 + 393579795033*uk_48 + 20579335688*uk_49 + 8*uk_5 + 501621307395*uk_50 + 578793816225*uk_51 + 393579795033*uk_52 + 153424975*uk_53 + 53001355*uk_54 + 426800385*uk_55 + 22316360*uk_56 + 543961275*uk_57 + 627647625*uk_58 + 426800385*uk_59 + 195*uk_6 + 18309559*uk_60 + 147440133*uk_61 + 7709288*uk_62 + 187913895*uk_63 + 216823725*uk_64 + 147440133*uk_65 + 1187281071*uk_66 + 62080056*uk_67 + 1513201365*uk_68 + 1746001575*uk_69 + 225*uk_7 + 1187281071*uk_70 + 3246016*uk_71 + 79121640*uk_72 + 91294200*uk_73 + 62080056*uk_74 + 1928589975*uk_75 + 2225296125*uk_76 + 1513201365*uk_77 + 2567649375*uk_78 + 1746001575*uk_79 + 153*uk_8 + 1187281071*uk_80 + 166375*uk_81 + 57475*uk_82 + 462825*uk_83 + 24200*uk_84 + 589875*uk_85 + 680625*uk_86 + 462825*uk_87 + 19855*uk_88 + 159885*uk_89 + 2572416961*uk_9 + 8360*uk_90 + 203775*uk_91 + 235125*uk_92 + 159885*uk_93 + 1287495*uk_94 + 67320*uk_95 + 1640925*uk_96 + 1893375*uk_97 + 1287495*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 130020*uk_100 + 148500*uk_101 + 12540*uk_102 + 2134495*uk_103 + 2437875*uk_104 + 205865*uk_105 + 2784375*uk_106 + 235125*uk_107 + 19855*uk_108 + 729000*uk_109 + 4564710*uk_11 + 153900*uk_110 + 97200*uk_111 + 1595700*uk_112 + 1822500*uk_113 + 153900*uk_114 + 32490*uk_115 + 20520*uk_116 + 336870*uk_117 + 384750*uk_118 + 32490*uk_119 + 963661*uk_12 + 12960*uk_120 + 212760*uk_121 + 243000*uk_122 + 20520*uk_123 + 3492810*uk_124 + 3989250*uk_125 + 336870*uk_126 + 4556250*uk_127 + 384750*uk_128 + 32490*uk_129 + 608628*uk_13 + 6859*uk_130 + 4332*uk_131 + 71117*uk_132 + 81225*uk_133 + 6859*uk_134 + 2736*uk_135 + 44916*uk_136 + 51300*uk_137 + 4332*uk_138 + 737371*uk_139 + 9991643*uk_14 + 842175*uk_140 + 71117*uk_141 + 961875*uk_142 + 81225*uk_143 + 6859*uk_144 + 1728*uk_145 + 28368*uk_146 + 32400*uk_147 + 2736*uk_148 + 465708*uk_149 + 11411775*uk_15 + 531900*uk_150 + 44916*uk_151 + 607500*uk_152 + 51300*uk_153 + 4332*uk_154 + 7645373*uk_155 + 8732025*uk_156 + 737371*uk_157 + 9973125*uk_158 + 842175*uk_159 + 963661*uk_16 + 71117*uk_160 + 11390625*uk_161 + 961875*uk_162 + 81225*uk_163 + 6859*uk_164 + 3025*uk_17 + 4950*uk_18 + 1045*uk_19 + 55*uk_2 + 660*uk_20 + 10835*uk_21 + 12375*uk_22 + 1045*uk_23 + 8100*uk_24 + 1710*uk_25 + 1080*uk_26 + 17730*uk_27 + 20250*uk_28 + 1710*uk_29 + 90*uk_3 + 361*uk_30 + 228*uk_31 + 3743*uk_32 + 4275*uk_33 + 361*uk_34 + 144*uk_35 + 2364*uk_36 + 2700*uk_37 + 228*uk_38 + 38809*uk_39 + 19*uk_4 + 44325*uk_40 + 3743*uk_41 + 50625*uk_42 + 4275*uk_43 + 361*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 231517526490*uk_47 + 48875922259*uk_48 + 30869003532*uk_49 + 12*uk_5 + 506766141317*uk_50 + 578793816225*uk_51 + 48875922259*uk_52 + 153424975*uk_53 + 251059050*uk_54 + 53001355*uk_55 + 33474540*uk_56 + 549540365*uk_57 + 627647625*uk_58 + 53001355*uk_59 + 197*uk_6 + 410823900*uk_60 + 86729490*uk_61 + 54776520*uk_62 + 899247870*uk_63 + 1027059750*uk_64 + 86729490*uk_65 + 18309559*uk_66 + 11563932*uk_67 + 189841217*uk_68 + 216823725*uk_69 + 225*uk_7 + 18309559*uk_70 + 7303536*uk_71 + 119899716*uk_72 + 136941300*uk_73 + 11563932*uk_74 + 1968353671*uk_75 + 2248119675*uk_76 + 189841217*uk_77 + 2567649375*uk_78 + 216823725*uk_79 + 19*uk_8 + 18309559*uk_80 + 166375*uk_81 + 272250*uk_82 + 57475*uk_83 + 36300*uk_84 + 595925*uk_85 + 680625*uk_86 + 57475*uk_87 + 445500*uk_88 + 94050*uk_89 + 2572416961*uk_9 + 59400*uk_90 + 975150*uk_91 + 1113750*uk_92 + 94050*uk_93 + 19855*uk_94 + 12540*uk_95 + 205865*uk_96 + 235125*uk_97 + 19855*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 131340*uk_100 + 148500*uk_101 + 59400*uk_102 + 2178055*uk_103 + 2462625*uk_104 + 985050*uk_105 + 2784375*uk_106 + 1113750*uk_107 + 445500*uk_108 + 5177717*uk_109 + 8774387*uk_11 + 2693610*uk_110 + 359148*uk_111 + 5955871*uk_112 + 6734025*uk_113 + 2693610*uk_114 + 1401300*uk_115 + 186840*uk_116 + 3098430*uk_117 + 3503250*uk_118 + 1401300*uk_119 + 4564710*uk_12 + 24912*uk_120 + 413124*uk_121 + 467100*uk_122 + 186840*uk_123 + 6850973*uk_124 + 7746075*uk_125 + 3098430*uk_126 + 8758125*uk_127 + 3503250*uk_128 + 1401300*uk_129 + 608628*uk_13 + 729000*uk_130 + 97200*uk_131 + 1611900*uk_132 + 1822500*uk_133 + 729000*uk_134 + 12960*uk_135 + 214920*uk_136 + 243000*uk_137 + 97200*uk_138 + 3564090*uk_139 + 10093081*uk_14 + 4029750*uk_140 + 1611900*uk_141 + 4556250*uk_142 + 1822500*uk_143 + 729000*uk_144 + 1728*uk_145 + 28656*uk_146 + 32400*uk_147 + 12960*uk_148 + 475212*uk_149 + 11411775*uk_15 + 537300*uk_150 + 214920*uk_151 + 607500*uk_152 + 243000*uk_153 + 97200*uk_154 + 7880599*uk_155 + 8910225*uk_156 + 3564090*uk_157 + 10074375*uk_158 + 4029750*uk_159 + 4564710*uk_16 + 1611900*uk_160 + 11390625*uk_161 + 4556250*uk_162 + 1822500*uk_163 + 729000*uk_164 + 3025*uk_17 + 9515*uk_18 + 4950*uk_19 + 55*uk_2 + 660*uk_20 + 10945*uk_21 + 12375*uk_22 + 4950*uk_23 + 29929*uk_24 + 15570*uk_25 + 2076*uk_26 + 34427*uk_27 + 38925*uk_28 + 15570*uk_29 + 173*uk_3 + 8100*uk_30 + 1080*uk_31 + 17910*uk_32 + 20250*uk_33 + 8100*uk_34 + 144*uk_35 + 2388*uk_36 + 2700*uk_37 + 1080*uk_38 + 39601*uk_39 + 90*uk_4 + 44775*uk_40 + 17910*uk_41 + 50625*uk_42 + 20250*uk_43 + 8100*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 445028134253*uk_47 + 231517526490*uk_48 + 30869003532*uk_49 + 12*uk_5 + 511910975239*uk_50 + 578793816225*uk_51 + 231517526490*uk_52 + 153424975*uk_53 + 482591285*uk_54 + 251059050*uk_55 + 33474540*uk_56 + 555119455*uk_57 + 627647625*uk_58 + 251059050*uk_59 + 199*uk_6 + 1517968951*uk_60 + 789694830*uk_61 + 105292644*uk_62 + 1746103013*uk_63 + 1974237075*uk_64 + 789694830*uk_65 + 410823900*uk_66 + 54776520*uk_67 + 908377290*uk_68 + 1027059750*uk_69 + 225*uk_7 + 410823900*uk_70 + 7303536*uk_71 + 121116972*uk_72 + 136941300*uk_73 + 54776520*uk_74 + 2008523119*uk_75 + 2270943225*uk_76 + 908377290*uk_77 + 2567649375*uk_78 + 1027059750*uk_79 + 90*uk_8 + 410823900*uk_80 + 166375*uk_81 + 523325*uk_82 + 272250*uk_83 + 36300*uk_84 + 601975*uk_85 + 680625*uk_86 + 272250*uk_87 + 1646095*uk_88 + 856350*uk_89 + 2572416961*uk_9 + 114180*uk_90 + 1893485*uk_91 + 2140875*uk_92 + 856350*uk_93 + 445500*uk_94 + 59400*uk_95 + 985050*uk_96 + 1113750*uk_97 + 445500*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 88440*uk_100 + 99000*uk_101 + 76120*uk_102 + 2222055*uk_103 + 2487375*uk_104 + 1912515*uk_105 + 2784375*uk_106 + 2140875*uk_107 + 1646095*uk_108 + 300763*uk_109 + 3398173*uk_11 + 776597*uk_110 + 35912*uk_111 + 902289*uk_112 + 1010025*uk_113 + 776597*uk_114 + 2005243*uk_115 + 92728*uk_116 + 2329791*uk_117 + 2607975*uk_118 + 2005243*uk_119 + 8774387*uk_12 + 4288*uk_120 + 107736*uk_121 + 120600*uk_122 + 92728*uk_123 + 2706867*uk_124 + 3030075*uk_125 + 2329791*uk_126 + 3391875*uk_127 + 2607975*uk_128 + 2005243*uk_129 + 405752*uk_13 + 5177717*uk_130 + 239432*uk_131 + 6015729*uk_132 + 6734025*uk_133 + 5177717*uk_134 + 11072*uk_135 + 278184*uk_136 + 311400*uk_137 + 239432*uk_138 + 6989373*uk_139 + 10194519*uk_14 + 7823925*uk_140 + 6015729*uk_141 + 8758125*uk_142 + 6734025*uk_143 + 5177717*uk_144 + 512*uk_145 + 12864*uk_146 + 14400*uk_147 + 11072*uk_148 + 323208*uk_149 + 11411775*uk_15 + 361800*uk_150 + 278184*uk_151 + 405000*uk_152 + 311400*uk_153 + 239432*uk_154 + 8120601*uk_155 + 9090225*uk_156 + 6989373*uk_157 + 10175625*uk_158 + 7823925*uk_159 + 8774387*uk_16 + 6015729*uk_160 + 11390625*uk_161 + 8758125*uk_162 + 6734025*uk_163 + 5177717*uk_164 + 3025*uk_17 + 3685*uk_18 + 9515*uk_19 + 55*uk_2 + 440*uk_20 + 11055*uk_21 + 12375*uk_22 + 9515*uk_23 + 4489*uk_24 + 11591*uk_25 + 536*uk_26 + 13467*uk_27 + 15075*uk_28 + 11591*uk_29 + 67*uk_3 + 29929*uk_30 + 1384*uk_31 + 34773*uk_32 + 38925*uk_33 + 29929*uk_34 + 64*uk_35 + 1608*uk_36 + 1800*uk_37 + 1384*uk_38 + 40401*uk_39 + 173*uk_4 + 45225*uk_40 + 34773*uk_41 + 50625*uk_42 + 38925*uk_43 + 29929*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 172351936387*uk_47 + 445028134253*uk_48 + 20579335688*uk_49 + 8*uk_5 + 517055809161*uk_50 + 578793816225*uk_51 + 445028134253*uk_52 + 153424975*uk_53 + 186899515*uk_54 + 482591285*uk_55 + 22316360*uk_56 + 560698545*uk_57 + 627647625*uk_58 + 482591285*uk_59 + 201*uk_6 + 227677591*uk_60 + 587883929*uk_61 + 27185384*uk_62 + 683032773*uk_63 + 764588925*uk_64 + 587883929*uk_65 + 1517968951*uk_66 + 70195096*uk_67 + 1763651787*uk_68 + 1974237075*uk_69 + 225*uk_7 + 1517968951*uk_70 + 3246016*uk_71 + 81556152*uk_72 + 91294200*uk_73 + 70195096*uk_74 + 2049098319*uk_75 + 2293766775*uk_76 + 1763651787*uk_77 + 2567649375*uk_78 + 1974237075*uk_79 + 173*uk_8 + 1517968951*uk_80 + 166375*uk_81 + 202675*uk_82 + 523325*uk_83 + 24200*uk_84 + 608025*uk_85 + 680625*uk_86 + 523325*uk_87 + 246895*uk_88 + 637505*uk_89 + 2572416961*uk_9 + 29480*uk_90 + 740685*uk_91 + 829125*uk_92 + 637505*uk_93 + 1646095*uk_94 + 76120*uk_95 + 1912515*uk_96 + 2140875*uk_97 + 1646095*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 133980*uk_100 + 148500*uk_101 + 44220*uk_102 + 2266495*uk_103 + 2512125*uk_104 + 748055*uk_105 + 2784375*uk_106 + 829125*uk_107 + 246895*uk_108 + 5088448*uk_109 + 8723668*uk_11 + 1982128*uk_110 + 355008*uk_111 + 6005552*uk_112 + 6656400*uk_113 + 1982128*uk_114 + 772108*uk_115 + 138288*uk_116 + 2339372*uk_117 + 2592900*uk_118 + 772108*uk_119 + 3398173*uk_12 + 24768*uk_120 + 418992*uk_121 + 464400*uk_122 + 138288*uk_123 + 7087948*uk_124 + 7856100*uk_125 + 2339372*uk_126 + 8707500*uk_127 + 2592900*uk_128 + 772108*uk_129 + 608628*uk_13 + 300763*uk_130 + 53868*uk_131 + 911267*uk_132 + 1010025*uk_133 + 300763*uk_134 + 9648*uk_135 + 163212*uk_136 + 180900*uk_137 + 53868*uk_138 + 2761003*uk_139 + 10295957*uk_14 + 3060225*uk_140 + 911267*uk_141 + 3391875*uk_142 + 1010025*uk_143 + 300763*uk_144 + 1728*uk_145 + 29232*uk_146 + 32400*uk_147 + 9648*uk_148 + 494508*uk_149 + 11411775*uk_15 + 548100*uk_150 + 163212*uk_151 + 607500*uk_152 + 180900*uk_153 + 53868*uk_154 + 8365427*uk_155 + 9272025*uk_156 + 2761003*uk_157 + 10276875*uk_158 + 3060225*uk_159 + 3398173*uk_16 + 911267*uk_160 + 11390625*uk_161 + 3391875*uk_162 + 1010025*uk_163 + 300763*uk_164 + 3025*uk_17 + 9460*uk_18 + 3685*uk_19 + 55*uk_2 + 660*uk_20 + 11165*uk_21 + 12375*uk_22 + 3685*uk_23 + 29584*uk_24 + 11524*uk_25 + 2064*uk_26 + 34916*uk_27 + 38700*uk_28 + 11524*uk_29 + 172*uk_3 + 4489*uk_30 + 804*uk_31 + 13601*uk_32 + 15075*uk_33 + 4489*uk_34 + 144*uk_35 + 2436*uk_36 + 2700*uk_37 + 804*uk_38 + 41209*uk_39 + 67*uk_4 + 45675*uk_40 + 13601*uk_41 + 50625*uk_42 + 15075*uk_43 + 4489*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 442455717292*uk_47 + 172351936387*uk_48 + 30869003532*uk_49 + 12*uk_5 + 522200643083*uk_50 + 578793816225*uk_51 + 172351936387*uk_52 + 153424975*uk_53 + 479801740*uk_54 + 186899515*uk_55 + 33474540*uk_56 + 566277635*uk_57 + 627647625*uk_58 + 186899515*uk_59 + 203*uk_6 + 1500470896*uk_60 + 584485756*uk_61 + 104684016*uk_62 + 1770904604*uk_63 + 1962825300*uk_64 + 584485756*uk_65 + 227677591*uk_66 + 40778076*uk_67 + 689829119*uk_68 + 764588925*uk_69 + 225*uk_7 + 227677591*uk_70 + 7303536*uk_71 + 123551484*uk_72 + 136941300*uk_73 + 40778076*uk_74 + 2090079271*uk_75 + 2316590325*uk_76 + 689829119*uk_77 + 2567649375*uk_78 + 764588925*uk_79 + 67*uk_8 + 227677591*uk_80 + 166375*uk_81 + 520300*uk_82 + 202675*uk_83 + 36300*uk_84 + 614075*uk_85 + 680625*uk_86 + 202675*uk_87 + 1627120*uk_88 + 633820*uk_89 + 2572416961*uk_9 + 113520*uk_90 + 1920380*uk_91 + 2128500*uk_92 + 633820*uk_93 + 246895*uk_94 + 44220*uk_95 + 748055*uk_96 + 829125*uk_97 + 246895*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 90200*uk_100 + 99000*uk_101 + 75680*uk_102 + 2311375*uk_103 + 2536875*uk_104 + 1939300*uk_105 + 2784375*uk_106 + 2128500*uk_107 + 1627120*uk_108 + 592704*uk_109 + 4260396*uk_11 + 1213632*uk_110 + 56448*uk_111 + 1446480*uk_112 + 1587600*uk_113 + 1213632*uk_114 + 2485056*uk_115 + 115584*uk_116 + 2961840*uk_117 + 3250800*uk_118 + 2485056*uk_119 + 8723668*uk_12 + 5376*uk_120 + 137760*uk_121 + 151200*uk_122 + 115584*uk_123 + 3530100*uk_124 + 3874500*uk_125 + 2961840*uk_126 + 4252500*uk_127 + 3250800*uk_128 + 2485056*uk_129 + 405752*uk_13 + 5088448*uk_130 + 236672*uk_131 + 6064720*uk_132 + 6656400*uk_133 + 5088448*uk_134 + 11008*uk_135 + 282080*uk_136 + 309600*uk_137 + 236672*uk_138 + 7228300*uk_139 + 10397395*uk_14 + 7933500*uk_140 + 6064720*uk_141 + 8707500*uk_142 + 6656400*uk_143 + 5088448*uk_144 + 512*uk_145 + 13120*uk_146 + 14400*uk_147 + 11008*uk_148 + 336200*uk_149 + 11411775*uk_15 + 369000*uk_150 + 282080*uk_151 + 405000*uk_152 + 309600*uk_153 + 236672*uk_154 + 8615125*uk_155 + 9455625*uk_156 + 7228300*uk_157 + 10378125*uk_158 + 7933500*uk_159 + 8723668*uk_16 + 6064720*uk_160 + 11390625*uk_161 + 8707500*uk_162 + 6656400*uk_163 + 5088448*uk_164 + 3025*uk_17 + 4620*uk_18 + 9460*uk_19 + 55*uk_2 + 440*uk_20 + 11275*uk_21 + 12375*uk_22 + 9460*uk_23 + 7056*uk_24 + 14448*uk_25 + 672*uk_26 + 17220*uk_27 + 18900*uk_28 + 14448*uk_29 + 84*uk_3 + 29584*uk_30 + 1376*uk_31 + 35260*uk_32 + 38700*uk_33 + 29584*uk_34 + 64*uk_35 + 1640*uk_36 + 1800*uk_37 + 1376*uk_38 + 42025*uk_39 + 172*uk_4 + 46125*uk_40 + 35260*uk_41 + 50625*uk_42 + 38700*uk_43 + 29584*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 216083024724*uk_47 + 442455717292*uk_48 + 20579335688*uk_49 + 8*uk_5 + 527345477005*uk_50 + 578793816225*uk_51 + 442455717292*uk_52 + 153424975*uk_53 + 234321780*uk_54 + 479801740*uk_55 + 22316360*uk_56 + 571856725*uk_57 + 627647625*uk_58 + 479801740*uk_59 + 205*uk_6 + 357873264*uk_60 + 732788112*uk_61 + 34083168*uk_62 + 873381180*uk_63 + 958589100*uk_64 + 732788112*uk_65 + 1500470896*uk_66 + 69789344*uk_67 + 1788351940*uk_68 + 1962825300*uk_69 + 225*uk_7 + 1500470896*uk_70 + 3246016*uk_71 + 83179160*uk_72 + 91294200*uk_73 + 69789344*uk_74 + 2131465975*uk_75 + 2339413875*uk_76 + 1788351940*uk_77 + 2567649375*uk_78 + 1962825300*uk_79 + 172*uk_8 + 1500470896*uk_80 + 166375*uk_81 + 254100*uk_82 + 520300*uk_83 + 24200*uk_84 + 620125*uk_85 + 680625*uk_86 + 520300*uk_87 + 388080*uk_88 + 794640*uk_89 + 2572416961*uk_9 + 36960*uk_90 + 947100*uk_91 + 1039500*uk_92 + 794640*uk_93 + 1627120*uk_94 + 75680*uk_95 + 1939300*uk_96 + 2128500*uk_97 + 1627120*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 91080*uk_100 + 99000*uk_101 + 36960*uk_102 + 2356695*uk_103 + 2561625*uk_104 + 956340*uk_105 + 2784375*uk_106 + 1039500*uk_107 + 388080*uk_108 + 64*uk_109 + 202876*uk_11 + 1344*uk_110 + 128*uk_111 + 3312*uk_112 + 3600*uk_113 + 1344*uk_114 + 28224*uk_115 + 2688*uk_116 + 69552*uk_117 + 75600*uk_118 + 28224*uk_119 + 4260396*uk_12 + 256*uk_120 + 6624*uk_121 + 7200*uk_122 + 2688*uk_123 + 171396*uk_124 + 186300*uk_125 + 69552*uk_126 + 202500*uk_127 + 75600*uk_128 + 28224*uk_129 + 405752*uk_13 + 592704*uk_130 + 56448*uk_131 + 1460592*uk_132 + 1587600*uk_133 + 592704*uk_134 + 5376*uk_135 + 139104*uk_136 + 151200*uk_137 + 56448*uk_138 + 3599316*uk_139 + 10498833*uk_14 + 3912300*uk_140 + 1460592*uk_141 + 4252500*uk_142 + 1587600*uk_143 + 592704*uk_144 + 512*uk_145 + 13248*uk_146 + 14400*uk_147 + 5376*uk_148 + 342792*uk_149 + 11411775*uk_15 + 372600*uk_150 + 139104*uk_151 + 405000*uk_152 + 151200*uk_153 + 56448*uk_154 + 8869743*uk_155 + 9641025*uk_156 + 3599316*uk_157 + 10479375*uk_158 + 3912300*uk_159 + 4260396*uk_16 + 1460592*uk_160 + 11390625*uk_161 + 4252500*uk_162 + 1587600*uk_163 + 592704*uk_164 + 3025*uk_17 + 220*uk_18 + 4620*uk_19 + 55*uk_2 + 440*uk_20 + 11385*uk_21 + 12375*uk_22 + 4620*uk_23 + 16*uk_24 + 336*uk_25 + 32*uk_26 + 828*uk_27 + 900*uk_28 + 336*uk_29 + 4*uk_3 + 7056*uk_30 + 672*uk_31 + 17388*uk_32 + 18900*uk_33 + 7056*uk_34 + 64*uk_35 + 1656*uk_36 + 1800*uk_37 + 672*uk_38 + 42849*uk_39 + 84*uk_4 + 46575*uk_40 + 17388*uk_41 + 50625*uk_42 + 18900*uk_43 + 7056*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 10289667844*uk_47 + 216083024724*uk_48 + 20579335688*uk_49 + 8*uk_5 + 532490310927*uk_50 + 578793816225*uk_51 + 216083024724*uk_52 + 153424975*uk_53 + 11158180*uk_54 + 234321780*uk_55 + 22316360*uk_56 + 577435815*uk_57 + 627647625*uk_58 + 234321780*uk_59 + 207*uk_6 + 811504*uk_60 + 17041584*uk_61 + 1623008*uk_62 + 41995332*uk_63 + 45647100*uk_64 + 17041584*uk_65 + 357873264*uk_66 + 34083168*uk_67 + 881901972*uk_68 + 958589100*uk_69 + 225*uk_7 + 357873264*uk_70 + 3246016*uk_71 + 83990664*uk_72 + 91294200*uk_73 + 34083168*uk_74 + 2173258431*uk_75 + 2362237425*uk_76 + 881901972*uk_77 + 2567649375*uk_78 + 958589100*uk_79 + 84*uk_8 + 357873264*uk_80 + 166375*uk_81 + 12100*uk_82 + 254100*uk_83 + 24200*uk_84 + 626175*uk_85 + 680625*uk_86 + 254100*uk_87 + 880*uk_88 + 18480*uk_89 + 2572416961*uk_9 + 1760*uk_90 + 45540*uk_91 + 49500*uk_92 + 18480*uk_93 + 388080*uk_94 + 36960*uk_95 + 956340*uk_96 + 1039500*uk_97 + 388080*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 137940*uk_100 + 148500*uk_101 + 2640*uk_102 + 2402455*uk_103 + 2586375*uk_104 + 45980*uk_105 + 2784375*uk_106 + 49500*uk_107 + 880*uk_108 + 2803221*uk_109 + 7151379*uk_11 + 79524*uk_110 + 238572*uk_111 + 4155129*uk_112 + 4473225*uk_113 + 79524*uk_114 + 2256*uk_115 + 6768*uk_116 + 117876*uk_117 + 126900*uk_118 + 2256*uk_119 + 202876*uk_12 + 20304*uk_120 + 353628*uk_121 + 380700*uk_122 + 6768*uk_123 + 6159021*uk_124 + 6630525*uk_125 + 117876*uk_126 + 7138125*uk_127 + 126900*uk_128 + 2256*uk_129 + 608628*uk_13 + 64*uk_130 + 192*uk_131 + 3344*uk_132 + 3600*uk_133 + 64*uk_134 + 576*uk_135 + 10032*uk_136 + 10800*uk_137 + 192*uk_138 + 174724*uk_139 + 10600271*uk_14 + 188100*uk_140 + 3344*uk_141 + 202500*uk_142 + 3600*uk_143 + 64*uk_144 + 1728*uk_145 + 30096*uk_146 + 32400*uk_147 + 576*uk_148 + 524172*uk_149 + 11411775*uk_15 + 564300*uk_150 + 10032*uk_151 + 607500*uk_152 + 10800*uk_153 + 192*uk_154 + 9129329*uk_155 + 9828225*uk_156 + 174724*uk_157 + 10580625*uk_158 + 188100*uk_159 + 202876*uk_16 + 3344*uk_160 + 11390625*uk_161 + 202500*uk_162 + 3600*uk_163 + 64*uk_164 + 3025*uk_17 + 7755*uk_18 + 220*uk_19 + 55*uk_2 + 660*uk_20 + 11495*uk_21 + 12375*uk_22 + 220*uk_23 + 19881*uk_24 + 564*uk_25 + 1692*uk_26 + 29469*uk_27 + 31725*uk_28 + 564*uk_29 + 141*uk_3 + 16*uk_30 + 48*uk_31 + 836*uk_32 + 900*uk_33 + 16*uk_34 + 144*uk_35 + 2508*uk_36 + 2700*uk_37 + 48*uk_38 + 43681*uk_39 + 4*uk_4 + 47025*uk_40 + 836*uk_41 + 50625*uk_42 + 900*uk_43 + 16*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 362710791501*uk_47 + 10289667844*uk_48 + 30869003532*uk_49 + 12*uk_5 + 537635144849*uk_50 + 578793816225*uk_51 + 10289667844*uk_52 + 153424975*uk_53 + 393325845*uk_54 + 11158180*uk_55 + 33474540*uk_56 + 583014905*uk_57 + 627647625*uk_58 + 11158180*uk_59 + 209*uk_6 + 1008344439*uk_60 + 28605516*uk_61 + 85816548*uk_62 + 1494638211*uk_63 + 1609060275*uk_64 + 28605516*uk_65 + 811504*uk_66 + 2434512*uk_67 + 42401084*uk_68 + 45647100*uk_69 + 225*uk_7 + 811504*uk_70 + 7303536*uk_71 + 127203252*uk_72 + 136941300*uk_73 + 2434512*uk_74 + 2215456639*uk_75 + 2385060975*uk_76 + 42401084*uk_77 + 2567649375*uk_78 + 45647100*uk_79 + 4*uk_8 + 811504*uk_80 + 166375*uk_81 + 426525*uk_82 + 12100*uk_83 + 36300*uk_84 + 632225*uk_85 + 680625*uk_86 + 12100*uk_87 + 1093455*uk_88 + 31020*uk_89 + 2572416961*uk_9 + 93060*uk_90 + 1620795*uk_91 + 1744875*uk_92 + 31020*uk_93 + 880*uk_94 + 2640*uk_95 + 45980*uk_96 + 49500*uk_97 + 880*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 92840*uk_100 + 99000*uk_101 + 62040*uk_102 + 2448655*uk_103 + 2611125*uk_104 + 1636305*uk_105 + 2784375*uk_106 + 1744875*uk_107 + 1093455*uk_108 + 493039*uk_109 + 4006801*uk_11 + 879981*uk_110 + 49928*uk_111 + 1316851*uk_112 + 1404225*uk_113 + 879981*uk_114 + 1570599*uk_115 + 89112*uk_116 + 2350329*uk_117 + 2506275*uk_118 + 1570599*uk_119 + 7151379*uk_12 + 5056*uk_120 + 133352*uk_121 + 142200*uk_122 + 89112*uk_123 + 3517159*uk_124 + 3750525*uk_125 + 2350329*uk_126 + 3999375*uk_127 + 2506275*uk_128 + 1570599*uk_129 + 405752*uk_13 + 2803221*uk_130 + 159048*uk_131 + 4194891*uk_132 + 4473225*uk_133 + 2803221*uk_134 + 9024*uk_135 + 238008*uk_136 + 253800*uk_137 + 159048*uk_138 + 6277461*uk_139 + 10701709*uk_14 + 6693975*uk_140 + 4194891*uk_141 + 7138125*uk_142 + 4473225*uk_143 + 2803221*uk_144 + 512*uk_145 + 13504*uk_146 + 14400*uk_147 + 9024*uk_148 + 356168*uk_149 + 11411775*uk_15 + 379800*uk_150 + 238008*uk_151 + 405000*uk_152 + 253800*uk_153 + 159048*uk_154 + 9393931*uk_155 + 10017225*uk_156 + 6277461*uk_157 + 10681875*uk_158 + 6693975*uk_159 + 7151379*uk_16 + 4194891*uk_160 + 11390625*uk_161 + 7138125*uk_162 + 4473225*uk_163 + 2803221*uk_164 + 3025*uk_17 + 4345*uk_18 + 7755*uk_19 + 55*uk_2 + 440*uk_20 + 11605*uk_21 + 12375*uk_22 + 7755*uk_23 + 6241*uk_24 + 11139*uk_25 + 632*uk_26 + 16669*uk_27 + 17775*uk_28 + 11139*uk_29 + 79*uk_3 + 19881*uk_30 + 1128*uk_31 + 29751*uk_32 + 31725*uk_33 + 19881*uk_34 + 64*uk_35 + 1688*uk_36 + 1800*uk_37 + 1128*uk_38 + 44521*uk_39 + 141*uk_4 + 47475*uk_40 + 29751*uk_41 + 50625*uk_42 + 31725*uk_43 + 19881*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 203220939919*uk_47 + 362710791501*uk_48 + 20579335688*uk_49 + 8*uk_5 + 542779978771*uk_50 + 578793816225*uk_51 + 362710791501*uk_52 + 153424975*uk_53 + 220374055*uk_54 + 393325845*uk_55 + 22316360*uk_56 + 588593995*uk_57 + 627647625*uk_58 + 393325845*uk_59 + 211*uk_6 + 316537279*uk_60 + 564958941*uk_61 + 32054408*uk_62 + 845435011*uk_63 + 901530225*uk_64 + 564958941*uk_65 + 1008344439*uk_66 + 57211032*uk_67 + 1508940969*uk_68 + 1609060275*uk_69 + 225*uk_7 + 1008344439*uk_70 + 3246016*uk_71 + 85613672*uk_72 + 91294200*uk_73 + 57211032*uk_74 + 2258060599*uk_75 + 2407884525*uk_76 + 1508940969*uk_77 + 2567649375*uk_78 + 1609060275*uk_79 + 141*uk_8 + 1008344439*uk_80 + 166375*uk_81 + 238975*uk_82 + 426525*uk_83 + 24200*uk_84 + 638275*uk_85 + 680625*uk_86 + 426525*uk_87 + 343255*uk_88 + 612645*uk_89 + 2572416961*uk_9 + 34760*uk_90 + 916795*uk_91 + 977625*uk_92 + 612645*uk_93 + 1093455*uk_94 + 62040*uk_95 + 1636305*uk_96 + 1744875*uk_97 + 1093455*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 93720*uk_100 + 99000*uk_101 + 34760*uk_102 + 2495295*uk_103 + 2635875*uk_104 + 925485*uk_105 + 2784375*uk_106 + 977625*uk_107 + 343255*uk_108 + 15625*uk_109 + 1267975*uk_11 + 49375*uk_110 + 5000*uk_111 + 133125*uk_112 + 140625*uk_113 + 49375*uk_114 + 156025*uk_115 + 15800*uk_116 + 420675*uk_117 + 444375*uk_118 + 156025*uk_119 + 4006801*uk_12 + 1600*uk_120 + 42600*uk_121 + 45000*uk_122 + 15800*uk_123 + 1134225*uk_124 + 1198125*uk_125 + 420675*uk_126 + 1265625*uk_127 + 444375*uk_128 + 156025*uk_129 + 405752*uk_13 + 493039*uk_130 + 49928*uk_131 + 1329333*uk_132 + 1404225*uk_133 + 493039*uk_134 + 5056*uk_135 + 134616*uk_136 + 142200*uk_137 + 49928*uk_138 + 3584151*uk_139 + 10803147*uk_14 + 3786075*uk_140 + 1329333*uk_141 + 3999375*uk_142 + 1404225*uk_143 + 493039*uk_144 + 512*uk_145 + 13632*uk_146 + 14400*uk_147 + 5056*uk_148 + 362952*uk_149 + 11411775*uk_15 + 383400*uk_150 + 134616*uk_151 + 405000*uk_152 + 142200*uk_153 + 49928*uk_154 + 9663597*uk_155 + 10208025*uk_156 + 3584151*uk_157 + 10783125*uk_158 + 3786075*uk_159 + 4006801*uk_16 + 1329333*uk_160 + 11390625*uk_161 + 3999375*uk_162 + 1404225*uk_163 + 493039*uk_164 + 3025*uk_17 + 1375*uk_18 + 4345*uk_19 + 55*uk_2 + 440*uk_20 + 11715*uk_21 + 12375*uk_22 + 4345*uk_23 + 625*uk_24 + 1975*uk_25 + 200*uk_26 + 5325*uk_27 + 5625*uk_28 + 1975*uk_29 + 25*uk_3 + 6241*uk_30 + 632*uk_31 + 16827*uk_32 + 17775*uk_33 + 6241*uk_34 + 64*uk_35 + 1704*uk_36 + 1800*uk_37 + 632*uk_38 + 45369*uk_39 + 79*uk_4 + 47925*uk_40 + 16827*uk_41 + 50625*uk_42 + 17775*uk_43 + 6241*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 64310424025*uk_47 + 203220939919*uk_48 + 20579335688*uk_49 + 8*uk_5 + 547924812693*uk_50 + 578793816225*uk_51 + 203220939919*uk_52 + 153424975*uk_53 + 69738625*uk_54 + 220374055*uk_55 + 22316360*uk_56 + 594173085*uk_57 + 627647625*uk_58 + 220374055*uk_59 + 213*uk_6 + 31699375*uk_60 + 100170025*uk_61 + 10143800*uk_62 + 270078675*uk_63 + 285294375*uk_64 + 100170025*uk_65 + 316537279*uk_66 + 32054408*uk_67 + 853448613*uk_68 + 901530225*uk_69 + 225*uk_7 + 316537279*uk_70 + 3246016*uk_71 + 86425176*uk_72 + 91294200*uk_73 + 32054408*uk_74 + 2301070311*uk_75 + 2430708075*uk_76 + 853448613*uk_77 + 2567649375*uk_78 + 901530225*uk_79 + 79*uk_8 + 316537279*uk_80 + 166375*uk_81 + 75625*uk_82 + 238975*uk_83 + 24200*uk_84 + 644325*uk_85 + 680625*uk_86 + 238975*uk_87 + 34375*uk_88 + 108625*uk_89 + 2572416961*uk_9 + 11000*uk_90 + 292875*uk_91 + 309375*uk_92 + 108625*uk_93 + 343255*uk_94 + 34760*uk_95 + 925485*uk_96 + 977625*uk_97 + 343255*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 141900*uk_100 + 148500*uk_101 + 16500*uk_102 + 2542375*uk_103 + 2660625*uk_104 + 295625*uk_105 + 2784375*uk_106 + 309375*uk_107 + 34375*uk_108 + 7301384*uk_109 + 9839486*uk_11 + 940900*uk_110 + 451632*uk_111 + 8091740*uk_112 + 8468100*uk_113 + 940900*uk_114 + 121250*uk_115 + 58200*uk_116 + 1042750*uk_117 + 1091250*uk_118 + 121250*uk_119 + 1267975*uk_12 + 27936*uk_120 + 500520*uk_121 + 523800*uk_122 + 58200*uk_123 + 8967650*uk_124 + 9384750*uk_125 + 1042750*uk_126 + 9821250*uk_127 + 1091250*uk_128 + 121250*uk_129 + 608628*uk_13 + 15625*uk_130 + 7500*uk_131 + 134375*uk_132 + 140625*uk_133 + 15625*uk_134 + 3600*uk_135 + 64500*uk_136 + 67500*uk_137 + 7500*uk_138 + 1155625*uk_139 + 10904585*uk_14 + 1209375*uk_140 + 134375*uk_141 + 1265625*uk_142 + 140625*uk_143 + 15625*uk_144 + 1728*uk_145 + 30960*uk_146 + 32400*uk_147 + 3600*uk_148 + 554700*uk_149 + 11411775*uk_15 + 580500*uk_150 + 64500*uk_151 + 607500*uk_152 + 67500*uk_153 + 7500*uk_154 + 9938375*uk_155 + 10400625*uk_156 + 1155625*uk_157 + 10884375*uk_158 + 1209375*uk_159 + 1267975*uk_16 + 134375*uk_160 + 11390625*uk_161 + 1265625*uk_162 + 140625*uk_163 + 15625*uk_164 + 3025*uk_17 + 10670*uk_18 + 1375*uk_19 + 55*uk_2 + 660*uk_20 + 11825*uk_21 + 12375*uk_22 + 1375*uk_23 + 37636*uk_24 + 4850*uk_25 + 2328*uk_26 + 41710*uk_27 + 43650*uk_28 + 4850*uk_29 + 194*uk_3 + 625*uk_30 + 300*uk_31 + 5375*uk_32 + 5625*uk_33 + 625*uk_34 + 144*uk_35 + 2580*uk_36 + 2700*uk_37 + 300*uk_38 + 46225*uk_39 + 25*uk_4 + 48375*uk_40 + 5375*uk_41 + 50625*uk_42 + 5625*uk_43 + 625*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 499048890434*uk_47 + 64310424025*uk_48 + 30869003532*uk_49 + 12*uk_5 + 553069646615*uk_50 + 578793816225*uk_51 + 64310424025*uk_52 + 153424975*uk_53 + 541171730*uk_54 + 69738625*uk_55 + 33474540*uk_56 + 599752175*uk_57 + 627647625*uk_58 + 69738625*uk_59 + 215*uk_6 + 1908860284*uk_60 + 245987150*uk_61 + 118073832*uk_62 + 2115489490*uk_63 + 2213884350*uk_64 + 245987150*uk_65 + 31699375*uk_66 + 15215700*uk_67 + 272614625*uk_68 + 285294375*uk_69 + 225*uk_7 + 31699375*uk_70 + 7303536*uk_71 + 130855020*uk_72 + 136941300*uk_73 + 15215700*uk_74 + 2344485775*uk_75 + 2453531625*uk_76 + 272614625*uk_77 + 2567649375*uk_78 + 285294375*uk_79 + 25*uk_8 + 31699375*uk_80 + 166375*uk_81 + 586850*uk_82 + 75625*uk_83 + 36300*uk_84 + 650375*uk_85 + 680625*uk_86 + 75625*uk_87 + 2069980*uk_88 + 266750*uk_89 + 2572416961*uk_9 + 128040*uk_90 + 2294050*uk_91 + 2400750*uk_92 + 266750*uk_93 + 34375*uk_94 + 16500*uk_95 + 295625*uk_96 + 309375*uk_97 + 34375*uk_98 + 7920*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 95480*uk_100 + 99000*uk_101 + 85360*uk_102 + 2589895*uk_103 + 2685375*uk_104 + 2315390*uk_105 + 2784375*uk_106 + 2400750*uk_107 + 2069980*uk_108 + 3944312*uk_109 + 8013602*uk_11 + 4843016*uk_110 + 199712*uk_111 + 5417188*uk_112 + 5616900*uk_113 + 4843016*uk_114 + 5946488*uk_115 + 245216*uk_116 + 6651484*uk_117 + 6896700*uk_118 + 5946488*uk_119 + 9839486*uk_12 + 10112*uk_120 + 274288*uk_121 + 284400*uk_122 + 245216*uk_123 + 7440062*uk_124 + 7714350*uk_125 + 6651484*uk_126 + 7998750*uk_127 + 6896700*uk_128 + 5946488*uk_129 + 405752*uk_13 + 7301384*uk_130 + 301088*uk_131 + 8167012*uk_132 + 8468100*uk_133 + 7301384*uk_134 + 12416*uk_135 + 336784*uk_136 + 349200*uk_137 + 301088*uk_138 + 9135266*uk_139 + 11006023*uk_14 + 9472050*uk_140 + 8167012*uk_141 + 9821250*uk_142 + 8468100*uk_143 + 7301384*uk_144 + 512*uk_145 + 13888*uk_146 + 14400*uk_147 + 12416*uk_148 + 376712*uk_149 + 11411775*uk_15 + 390600*uk_150 + 336784*uk_151 + 405000*uk_152 + 349200*uk_153 + 301088*uk_154 + 10218313*uk_155 + 10595025*uk_156 + 9135266*uk_157 + 10985625*uk_158 + 9472050*uk_159 + 9839486*uk_16 + 8167012*uk_160 + 11390625*uk_161 + 9821250*uk_162 + 8468100*uk_163 + 7301384*uk_164 + 3025*uk_17 + 8690*uk_18 + 10670*uk_19 + 55*uk_2 + 440*uk_20 + 11935*uk_21 + 12375*uk_22 + 10670*uk_23 + 24964*uk_24 + 30652*uk_25 + 1264*uk_26 + 34286*uk_27 + 35550*uk_28 + 30652*uk_29 + 158*uk_3 + 37636*uk_30 + 1552*uk_31 + 42098*uk_32 + 43650*uk_33 + 37636*uk_34 + 64*uk_35 + 1736*uk_36 + 1800*uk_37 + 1552*uk_38 + 47089*uk_39 + 194*uk_4 + 48825*uk_40 + 42098*uk_41 + 50625*uk_42 + 43650*uk_43 + 37636*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 406441879838*uk_47 + 499048890434*uk_48 + 20579335688*uk_49 + 8*uk_5 + 558214480537*uk_50 + 578793816225*uk_51 + 499048890434*uk_52 + 153424975*uk_53 + 440748110*uk_54 + 541171730*uk_55 + 22316360*uk_56 + 605331265*uk_57 + 627647625*uk_58 + 541171730*uk_59 + 217*uk_6 + 1266149116*uk_60 + 1554638788*uk_61 + 64108816*uk_62 + 1738951634*uk_63 + 1803060450*uk_64 + 1554638788*uk_65 + 1908860284*uk_66 + 78715888*uk_67 + 2135168462*uk_68 + 2213884350*uk_69 + 225*uk_7 + 1908860284*uk_70 + 3246016*uk_71 + 88048184*uk_72 + 91294200*uk_73 + 78715888*uk_74 + 2388306991*uk_75 + 2476355175*uk_76 + 2135168462*uk_77 + 2567649375*uk_78 + 2213884350*uk_79 + 194*uk_8 + 1908860284*uk_80 + 166375*uk_81 + 477950*uk_82 + 586850*uk_83 + 24200*uk_84 + 656425*uk_85 + 680625*uk_86 + 586850*uk_87 + 1373020*uk_88 + 1685860*uk_89 + 2572416961*uk_9 + 69520*uk_90 + 1885730*uk_91 + 1955250*uk_92 + 1685860*uk_93 + 2069980*uk_94 + 85360*uk_95 + 2315390*uk_96 + 2400750*uk_97 + 2069980*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 96360*uk_100 + 99000*uk_101 + 69520*uk_102 + 2637855*uk_103 + 2710125*uk_104 + 1903110*uk_105 + 2784375*uk_106 + 1955250*uk_107 + 1373020*uk_108 + 2197000*uk_109 + 6593470*uk_11 + 2670200*uk_110 + 135200*uk_111 + 3701100*uk_112 + 3802500*uk_113 + 2670200*uk_114 + 3245320*uk_115 + 164320*uk_116 + 4498260*uk_117 + 4621500*uk_118 + 3245320*uk_119 + 8013602*uk_12 + 8320*uk_120 + 227760*uk_121 + 234000*uk_122 + 164320*uk_123 + 6234930*uk_124 + 6405750*uk_125 + 4498260*uk_126 + 6581250*uk_127 + 4621500*uk_128 + 3245320*uk_129 + 405752*uk_13 + 3944312*uk_130 + 199712*uk_131 + 5467116*uk_132 + 5616900*uk_133 + 3944312*uk_134 + 10112*uk_135 + 276816*uk_136 + 284400*uk_137 + 199712*uk_138 + 7577838*uk_139 + 11107461*uk_14 + 7785450*uk_140 + 5467116*uk_141 + 7998750*uk_142 + 5616900*uk_143 + 3944312*uk_144 + 512*uk_145 + 14016*uk_146 + 14400*uk_147 + 10112*uk_148 + 383688*uk_149 + 11411775*uk_15 + 394200*uk_150 + 276816*uk_151 + 405000*uk_152 + 284400*uk_153 + 199712*uk_154 + 10503459*uk_155 + 10791225*uk_156 + 7577838*uk_157 + 11086875*uk_158 + 7785450*uk_159 + 8013602*uk_16 + 5467116*uk_160 + 11390625*uk_161 + 7998750*uk_162 + 5616900*uk_163 + 3944312*uk_164 + 3025*uk_17 + 7150*uk_18 + 8690*uk_19 + 55*uk_2 + 440*uk_20 + 12045*uk_21 + 12375*uk_22 + 8690*uk_23 + 16900*uk_24 + 20540*uk_25 + 1040*uk_26 + 28470*uk_27 + 29250*uk_28 + 20540*uk_29 + 130*uk_3 + 24964*uk_30 + 1264*uk_31 + 34602*uk_32 + 35550*uk_33 + 24964*uk_34 + 64*uk_35 + 1752*uk_36 + 1800*uk_37 + 1264*uk_38 + 47961*uk_39 + 158*uk_4 + 49275*uk_40 + 34602*uk_41 + 50625*uk_42 + 35550*uk_43 + 24964*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 334414204930*uk_47 + 406441879838*uk_48 + 20579335688*uk_49 + 8*uk_5 + 563359314459*uk_50 + 578793816225*uk_51 + 406441879838*uk_52 + 153424975*uk_53 + 362640850*uk_54 + 440748110*uk_55 + 22316360*uk_56 + 610910355*uk_57 + 627647625*uk_58 + 440748110*uk_59 + 219*uk_6 + 857151100*uk_60 + 1041768260*uk_61 + 52747760*uk_62 + 1443969930*uk_63 + 1483530750*uk_64 + 1041768260*uk_65 + 1266149116*uk_66 + 64108816*uk_67 + 1754978838*uk_68 + 1803060450*uk_69 + 225*uk_7 + 1266149116*uk_70 + 3246016*uk_71 + 88859688*uk_72 + 91294200*uk_73 + 64108816*uk_74 + 2432533959*uk_75 + 2499178725*uk_76 + 1754978838*uk_77 + 2567649375*uk_78 + 1803060450*uk_79 + 158*uk_8 + 1266149116*uk_80 + 166375*uk_81 + 393250*uk_82 + 477950*uk_83 + 24200*uk_84 + 662475*uk_85 + 680625*uk_86 + 477950*uk_87 + 929500*uk_88 + 1129700*uk_89 + 2572416961*uk_9 + 57200*uk_90 + 1565850*uk_91 + 1608750*uk_92 + 1129700*uk_93 + 1373020*uk_94 + 69520*uk_95 + 1903110*uk_96 + 1955250*uk_97 + 1373020*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 97240*uk_100 + 99000*uk_101 + 57200*uk_102 + 2686255*uk_103 + 2734875*uk_104 + 1580150*uk_105 + 2784375*uk_106 + 1608750*uk_107 + 929500*uk_108 + 1331000*uk_109 + 5579090*uk_11 + 1573000*uk_110 + 96800*uk_111 + 2674100*uk_112 + 2722500*uk_113 + 1573000*uk_114 + 1859000*uk_115 + 114400*uk_116 + 3160300*uk_117 + 3217500*uk_118 + 1859000*uk_119 + 6593470*uk_12 + 7040*uk_120 + 194480*uk_121 + 198000*uk_122 + 114400*uk_123 + 5372510*uk_124 + 5469750*uk_125 + 3160300*uk_126 + 5568750*uk_127 + 3217500*uk_128 + 1859000*uk_129 + 405752*uk_13 + 2197000*uk_130 + 135200*uk_131 + 3734900*uk_132 + 3802500*uk_133 + 2197000*uk_134 + 8320*uk_135 + 229840*uk_136 + 234000*uk_137 + 135200*uk_138 + 6349330*uk_139 + 11208899*uk_14 + 6464250*uk_140 + 3734900*uk_141 + 6581250*uk_142 + 3802500*uk_143 + 2197000*uk_144 + 512*uk_145 + 14144*uk_146 + 14400*uk_147 + 8320*uk_148 + 390728*uk_149 + 11411775*uk_15 + 397800*uk_150 + 229840*uk_151 + 405000*uk_152 + 234000*uk_153 + 135200*uk_154 + 10793861*uk_155 + 10989225*uk_156 + 6349330*uk_157 + 11188125*uk_158 + 6464250*uk_159 + 6593470*uk_16 + 3734900*uk_160 + 11390625*uk_161 + 6581250*uk_162 + 3802500*uk_163 + 2197000*uk_164 + 3025*uk_17 + 6050*uk_18 + 7150*uk_19 + 55*uk_2 + 440*uk_20 + 12155*uk_21 + 12375*uk_22 + 7150*uk_23 + 12100*uk_24 + 14300*uk_25 + 880*uk_26 + 24310*uk_27 + 24750*uk_28 + 14300*uk_29 + 110*uk_3 + 16900*uk_30 + 1040*uk_31 + 28730*uk_32 + 29250*uk_33 + 16900*uk_34 + 64*uk_35 + 1768*uk_36 + 1800*uk_37 + 1040*uk_38 + 48841*uk_39 + 130*uk_4 + 49725*uk_40 + 28730*uk_41 + 50625*uk_42 + 29250*uk_43 + 16900*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 282965865710*uk_47 + 334414204930*uk_48 + 20579335688*uk_49 + 8*uk_5 + 568504148381*uk_50 + 578793816225*uk_51 + 334414204930*uk_52 + 153424975*uk_53 + 306849950*uk_54 + 362640850*uk_55 + 22316360*uk_56 + 616489445*uk_57 + 627647625*uk_58 + 362640850*uk_59 + 221*uk_6 + 613699900*uk_60 + 725281700*uk_61 + 44632720*uk_62 + 1232978890*uk_63 + 1255295250*uk_64 + 725281700*uk_65 + 857151100*uk_66 + 52747760*uk_67 + 1457156870*uk_68 + 1483530750*uk_69 + 225*uk_7 + 857151100*uk_70 + 3246016*uk_71 + 89671192*uk_72 + 91294200*uk_73 + 52747760*uk_74 + 2477166679*uk_75 + 2522002275*uk_76 + 1457156870*uk_77 + 2567649375*uk_78 + 1483530750*uk_79 + 130*uk_8 + 857151100*uk_80 + 166375*uk_81 + 332750*uk_82 + 393250*uk_83 + 24200*uk_84 + 668525*uk_85 + 680625*uk_86 + 393250*uk_87 + 665500*uk_88 + 786500*uk_89 + 2572416961*uk_9 + 48400*uk_90 + 1337050*uk_91 + 1361250*uk_92 + 786500*uk_93 + 929500*uk_94 + 57200*uk_95 + 1580150*uk_96 + 1608750*uk_97 + 929500*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 98120*uk_100 + 99000*uk_101 + 48400*uk_102 + 2735095*uk_103 + 2759625*uk_104 + 1349150*uk_105 + 2784375*uk_106 + 1361250*uk_107 + 665500*uk_108 + 941192*uk_109 + 4970462*uk_11 + 1056440*uk_110 + 76832*uk_111 + 2141692*uk_112 + 2160900*uk_113 + 1056440*uk_114 + 1185800*uk_115 + 86240*uk_116 + 2403940*uk_117 + 2425500*uk_118 + 1185800*uk_119 + 5579090*uk_12 + 6272*uk_120 + 174832*uk_121 + 176400*uk_122 + 86240*uk_123 + 4873442*uk_124 + 4917150*uk_125 + 2403940*uk_126 + 4961250*uk_127 + 2425500*uk_128 + 1185800*uk_129 + 405752*uk_13 + 1331000*uk_130 + 96800*uk_131 + 2698300*uk_132 + 2722500*uk_133 + 1331000*uk_134 + 7040*uk_135 + 196240*uk_136 + 198000*uk_137 + 96800*uk_138 + 5470190*uk_139 + 11310337*uk_14 + 5519250*uk_140 + 2698300*uk_141 + 5568750*uk_142 + 2722500*uk_143 + 1331000*uk_144 + 512*uk_145 + 14272*uk_146 + 14400*uk_147 + 7040*uk_148 + 397832*uk_149 + 11411775*uk_15 + 401400*uk_150 + 196240*uk_151 + 405000*uk_152 + 198000*uk_153 + 96800*uk_154 + 11089567*uk_155 + 11189025*uk_156 + 5470190*uk_157 + 11289375*uk_158 + 5519250*uk_159 + 5579090*uk_16 + 2698300*uk_160 + 11390625*uk_161 + 5568750*uk_162 + 2722500*uk_163 + 1331000*uk_164 + 3025*uk_17 + 5390*uk_18 + 6050*uk_19 + 55*uk_2 + 440*uk_20 + 12265*uk_21 + 12375*uk_22 + 6050*uk_23 + 9604*uk_24 + 10780*uk_25 + 784*uk_26 + 21854*uk_27 + 22050*uk_28 + 10780*uk_29 + 98*uk_3 + 12100*uk_30 + 880*uk_31 + 24530*uk_32 + 24750*uk_33 + 12100*uk_34 + 64*uk_35 + 1784*uk_36 + 1800*uk_37 + 880*uk_38 + 49729*uk_39 + 110*uk_4 + 50175*uk_40 + 24530*uk_41 + 50625*uk_42 + 24750*uk_43 + 12100*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 252096862178*uk_47 + 282965865710*uk_48 + 20579335688*uk_49 + 8*uk_5 + 573648982303*uk_50 + 578793816225*uk_51 + 282965865710*uk_52 + 153424975*uk_53 + 273375410*uk_54 + 306849950*uk_55 + 22316360*uk_56 + 622068535*uk_57 + 627647625*uk_58 + 306849950*uk_59 + 223*uk_6 + 487105276*uk_60 + 546750820*uk_61 + 39763696*uk_62 + 1108413026*uk_63 + 1118353950*uk_64 + 546750820*uk_65 + 613699900*uk_66 + 44632720*uk_67 + 1244137070*uk_68 + 1255295250*uk_69 + 225*uk_7 + 613699900*uk_70 + 3246016*uk_71 + 90482696*uk_72 + 91294200*uk_73 + 44632720*uk_74 + 2522205151*uk_75 + 2544825825*uk_76 + 1244137070*uk_77 + 2567649375*uk_78 + 1255295250*uk_79 + 110*uk_8 + 613699900*uk_80 + 166375*uk_81 + 296450*uk_82 + 332750*uk_83 + 24200*uk_84 + 674575*uk_85 + 680625*uk_86 + 332750*uk_87 + 528220*uk_88 + 592900*uk_89 + 2572416961*uk_9 + 43120*uk_90 + 1201970*uk_91 + 1212750*uk_92 + 592900*uk_93 + 665500*uk_94 + 48400*uk_95 + 1349150*uk_96 + 1361250*uk_97 + 665500*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 99000*uk_100 + 99000*uk_101 + 43120*uk_102 + 2784375*uk_103 + 2784375*uk_104 + 1212750*uk_105 + 2784375*uk_106 + 1212750*uk_107 + 528220*uk_108 + 830584*uk_109 + 4767586*uk_11 + 865928*uk_110 + 70688*uk_111 + 1988100*uk_112 + 1988100*uk_113 + 865928*uk_114 + 902776*uk_115 + 73696*uk_116 + 2072700*uk_117 + 2072700*uk_118 + 902776*uk_119 + 4970462*uk_12 + 6016*uk_120 + 169200*uk_121 + 169200*uk_122 + 73696*uk_123 + 4758750*uk_124 + 4758750*uk_125 + 2072700*uk_126 + 4758750*uk_127 + 2072700*uk_128 + 902776*uk_129 + 405752*uk_13 + 941192*uk_130 + 76832*uk_131 + 2160900*uk_132 + 2160900*uk_133 + 941192*uk_134 + 6272*uk_135 + 176400*uk_136 + 176400*uk_137 + 76832*uk_138 + 4961250*uk_139 + 11411775*uk_14 + 4961250*uk_140 + 2160900*uk_141 + 4961250*uk_142 + 2160900*uk_143 + 941192*uk_144 + 512*uk_145 + 14400*uk_146 + 14400*uk_147 + 6272*uk_148 + 405000*uk_149 + 11411775*uk_15 + 405000*uk_150 + 176400*uk_151 + 405000*uk_152 + 176400*uk_153 + 76832*uk_154 + 11390625*uk_155 + 11390625*uk_156 + 4961250*uk_157 + 11390625*uk_158 + 4961250*uk_159 + 4970462*uk_16 + 2160900*uk_160 + 11390625*uk_161 + 4961250*uk_162 + 2160900*uk_163 + 941192*uk_164 + 3025*uk_17 + 5170*uk_18 + 5390*uk_19 + 55*uk_2 + 440*uk_20 + 12375*uk_21 + 12375*uk_22 + 5390*uk_23 + 8836*uk_24 + 9212*uk_25 + 752*uk_26 + 21150*uk_27 + 21150*uk_28 + 9212*uk_29 + 94*uk_3 + 9604*uk_30 + 784*uk_31 + 22050*uk_32 + 22050*uk_33 + 9604*uk_34 + 64*uk_35 + 1800*uk_36 + 1800*uk_37 + 784*uk_38 + 50625*uk_39 + 98*uk_4 + 50625*uk_40 + 22050*uk_41 + 50625*uk_42 + 22050*uk_43 + 9604*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 241807194334*uk_47 + 252096862178*uk_48 + 20579335688*uk_49 + 8*uk_5 + 578793816225*uk_50 + 578793816225*uk_51 + 252096862178*uk_52 + 153424975*uk_53 + 262217230*uk_54 + 273375410*uk_55 + 22316360*uk_56 + 627647625*uk_57 + 627647625*uk_58 + 273375410*uk_59 + 225*uk_6 + 448153084*uk_60 + 467223428*uk_61 + 38140688*uk_62 + 1072706850*uk_63 + 1072706850*uk_64 + 467223428*uk_65 + 487105276*uk_66 + 39763696*uk_67 + 1118353950*uk_68 + 1118353950*uk_69 + 225*uk_7 + 487105276*uk_70 + 3246016*uk_71 + 91294200*uk_72 + 91294200*uk_73 + 39763696*uk_74 + 2567649375*uk_75 + 2567649375*uk_76 + 1118353950*uk_77 + 2567649375*uk_78 + 1118353950*uk_79 + 98*uk_8 + 487105276*uk_80 + 166375*uk_81 + 284350*uk_82 + 296450*uk_83 + 24200*uk_84 + 680625*uk_85 + 680625*uk_86 + 296450*uk_87 + 485980*uk_88 + 506660*uk_89 + 2572416961*uk_9 + 41360*uk_90 + 1163250*uk_91 + 1163250*uk_92 + 506660*uk_93 + 528220*uk_94 + 43120*uk_95 + 1212750*uk_96 + 1212750*uk_97 + 528220*uk_98 + 3520*uk_99, uk_0 + 50719*uk_1 + 2789545*uk_10 + 99880*uk_100 + 99000*uk_101 + 41360*uk_102 + 2834095*uk_103 + 2809125*uk_104 + 1173590*uk_105 + 2784375*uk_106 + 1163250*uk_107 + 485980*uk_108 + 941192*uk_109 + 4970462*uk_11 + 902776*uk_110 + 76832*uk_111 + 2180108*uk_112 + 2160900*uk_113 + 902776*uk_114 + 865928*uk_115 + 73696*uk_116 + 2091124*uk_117 + 2072700*uk_118 + 865928*uk_119 + 4767586*uk_12 + 6272*uk_120 + 177968*uk_121 + 176400*uk_122 + 73696*uk_123 + 5049842*uk_124 + 5005350*uk_125 + 2091124*uk_126 + 4961250*uk_127 + 2072700*uk_128 + 865928*uk_129 + 405752*uk_13 + 830584*uk_130 + 70688*uk_131 + 2005772*uk_132 + 1988100*uk_133 + 830584*uk_134 + 6016*uk_135 + 170704*uk_136 + 169200*uk_137 + 70688*uk_138 + 4843726*uk_139 + 11513213*uk_14 + 4801050*uk_140 + 2005772*uk_141 + 4758750*uk_142 + 1988100*uk_143 + 830584*uk_144 + 512*uk_145 + 14528*uk_146 + 14400*uk_147 + 6016*uk_148 + 412232*uk_149 + 11411775*uk_15 + 408600*uk_150 + 170704*uk_151 + 405000*uk_152 + 169200*uk_153 + 70688*uk_154 + 11697083*uk_155 + 11594025*uk_156 + 4843726*uk_157 + 11491875*uk_158 + 4801050*uk_159 + 4767586*uk_16 + 2005772*uk_160 + 11390625*uk_161 + 4758750*uk_162 + 1988100*uk_163 + 830584*uk_164 + 3025*uk_17 + 5390*uk_18 + 5170*uk_19 + 55*uk_2 + 440*uk_20 + 12485*uk_21 + 12375*uk_22 + 5170*uk_23 + 9604*uk_24 + 9212*uk_25 + 784*uk_26 + 22246*uk_27 + 22050*uk_28 + 9212*uk_29 + 98*uk_3 + 8836*uk_30 + 752*uk_31 + 21338*uk_32 + 21150*uk_33 + 8836*uk_34 + 64*uk_35 + 1816*uk_36 + 1800*uk_37 + 752*uk_38 + 51529*uk_39 + 94*uk_4 + 51075*uk_40 + 21338*uk_41 + 50625*uk_42 + 21150*uk_43 + 8836*uk_44 + 130470415844959*uk_45 + 141482932855*uk_46 + 252096862178*uk_47 + 241807194334*uk_48 + 20579335688*uk_49 + 8*uk_5 + 583938650147*uk_50 + 578793816225*uk_51 + 241807194334*uk_52 + 153424975*uk_53 + 273375410*uk_54 + 262217230*uk_55 + 22316360*uk_56 + 633226715*uk_57 + 627647625*uk_58 + 262217230*uk_59 + 227*uk_6 + 487105276*uk_60 + 467223428*uk_61 + 39763696*uk_62 + 1128294874*uk_63 + 1118353950*uk_64 + 467223428*uk_65 + 448153084*uk_66 + 38140688*uk_67 + 1082242022*uk_68 + 1072706850*uk_69 + 225*uk_7 + 448153084*uk_70 + 3246016*uk_71 + 92105704*uk_72 + 91294200*uk_73 + 38140688*uk_74 + 2613499351*uk_75 + 2590472925*uk_76 + 1082242022*uk_77 + 2567649375*uk_78 + 1072706850*uk_79 + 94*uk_8 + 448153084*uk_80 + 166375*uk_81 + 296450*uk_82 + 284350*uk_83 + 24200*uk_84 + 686675*uk_85 + 680625*uk_86 + 284350*uk_87 + 528220*uk_88 + 506660*uk_89 + 2572416961*uk_9 + 43120*uk_90 + 1223530*uk_91 + 1212750*uk_92 + 506660*uk_93 + 485980*uk_94 + 41360*uk_95 + 1173590*uk_96 + 1163250*uk_97 + 485980*uk_98 + 3520*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 396900*uk_100 + 1367100*uk_101 + 250047*uk_103 + 861273*uk_104 + 2966607*uk_106 + 64000*uk_109 + 1894120*uk_11 + 27200*uk_110 + 160000*uk_111 + 100800*uk_112 + 347200*uk_113 + 11560*uk_115 + 68000*uk_116 + 42840*uk_117 + 147560*uk_118 + 805001*uk_12 + 400000*uk_120 + 252000*uk_121 + 868000*uk_122 + 158760*uk_124 + 546840*uk_125 + 1883560*uk_127 + 4735300*uk_13 + 4913*uk_130 + 28900*uk_131 + 18207*uk_132 + 62713*uk_133 + 170000*uk_135 + 107100*uk_136 + 368900*uk_137 + 67473*uk_139 + 2983239*uk_14 + 232407*uk_140 + 800513*uk_142 + 1000000*uk_145 + 630000*uk_146 + 2170000*uk_147 + 396900*uk_149 + 10275601*uk_15 + 1367100*uk_150 + 4708900*uk_152 + 250047*uk_155 + 861273*uk_156 + 2966607*uk_158 + 10218313*uk_161 + 3969*uk_17 + 2520*uk_18 + 1071*uk_19 + 63*uk_2 + 6300*uk_20 + 3969*uk_21 + 13671*uk_22 + 1600*uk_24 + 680*uk_25 + 4000*uk_26 + 2520*uk_27 + 8680*uk_28 + 40*uk_3 + 289*uk_30 + 1700*uk_31 + 1071*uk_32 + 3689*uk_33 + 10000*uk_35 + 6300*uk_36 + 21700*uk_37 + 3969*uk_39 + 17*uk_4 + 13671*uk_40 + 47089*uk_42 + 106179944855977*uk_45 + 141265316367*uk_46 + 89692264360*uk_47 + 38119212353*uk_48 + 224230660900*uk_49 + 100*uk_5 + 141265316367*uk_50 + 486580534153*uk_51 + 187944057*uk_53 + 119329560*uk_54 + 50715063*uk_55 + 298323900*uk_56 + 187944057*uk_57 + 647362863*uk_58 + 63*uk_6 + 75764800*uk_60 + 32200040*uk_61 + 189412000*uk_62 + 119329560*uk_63 + 411024040*uk_64 + 13685017*uk_66 + 80500100*uk_67 + 50715063*uk_68 + 174685217*uk_69 + 217*uk_7 + 473530000*uk_71 + 298323900*uk_72 + 1027560100*uk_73 + 187944057*uk_75 + 647362863*uk_76 + 2229805417*uk_78 + 250047*uk_81 + 158760*uk_82 + 67473*uk_83 + 396900*uk_84 + 250047*uk_85 + 861273*uk_86 + 100800*uk_88 + 42840*uk_89 + 2242306609*uk_9 + 252000*uk_90 + 158760*uk_91 + 546840*uk_92 + 18207*uk_94 + 107100*uk_95 + 67473*uk_96 + 232407*uk_97 + 630000*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 376740*uk_100 + 1257732*uk_101 + 231840*uk_102 + 266175*uk_103 + 888615*uk_104 + 163800*uk_105 + 2966607*uk_106 + 546840*uk_107 + 100800*uk_108 + 35937*uk_109 + 1562649*uk_11 + 43560*uk_110 + 100188*uk_111 + 70785*uk_112 + 236313*uk_113 + 43560*uk_114 + 52800*uk_115 + 121440*uk_116 + 85800*uk_117 + 286440*uk_118 + 52800*uk_119 + 1894120*uk_12 + 279312*uk_120 + 197340*uk_121 + 658812*uk_122 + 121440*uk_123 + 139425*uk_124 + 465465*uk_125 + 85800*uk_126 + 1553937*uk_127 + 286440*uk_128 + 52800*uk_129 + 4356476*uk_13 + 64000*uk_130 + 147200*uk_131 + 104000*uk_132 + 347200*uk_133 + 64000*uk_134 + 338560*uk_135 + 239200*uk_136 + 798560*uk_137 + 147200*uk_138 + 169000*uk_139 + 3077945*uk_14 + 564200*uk_140 + 104000*uk_141 + 1883560*uk_142 + 347200*uk_143 + 64000*uk_144 + 778688*uk_145 + 550160*uk_146 + 1836688*uk_147 + 338560*uk_148 + 388700*uk_149 + 10275601*uk_15 + 1297660*uk_150 + 239200*uk_151 + 4332188*uk_152 + 798560*uk_153 + 147200*uk_154 + 274625*uk_155 + 916825*uk_156 + 169000*uk_157 + 3060785*uk_158 + 564200*uk_159 + 1894120*uk_16 + 104000*uk_160 + 10218313*uk_161 + 1883560*uk_162 + 347200*uk_163 + 64000*uk_164 + 3969*uk_17 + 2079*uk_18 + 2520*uk_19 + 63*uk_2 + 5796*uk_20 + 4095*uk_21 + 13671*uk_22 + 2520*uk_23 + 1089*uk_24 + 1320*uk_25 + 3036*uk_26 + 2145*uk_27 + 7161*uk_28 + 1320*uk_29 + 33*uk_3 + 1600*uk_30 + 3680*uk_31 + 2600*uk_32 + 8680*uk_33 + 1600*uk_34 + 8464*uk_35 + 5980*uk_36 + 19964*uk_37 + 3680*uk_38 + 4225*uk_39 + 40*uk_4 + 14105*uk_40 + 2600*uk_41 + 47089*uk_42 + 8680*uk_43 + 1600*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 73996118097*uk_47 + 89692264360*uk_48 + 206292208028*uk_49 + 92*uk_5 + 145749929585*uk_50 + 486580534153*uk_51 + 89692264360*uk_52 + 187944057*uk_53 + 98446887*uk_54 + 119329560*uk_55 + 274457988*uk_56 + 193910535*uk_57 + 647362863*uk_58 + 119329560*uk_59 + 65*uk_6 + 51567417*uk_60 + 62505960*uk_61 + 143763708*uk_62 + 101572185*uk_63 + 339094833*uk_64 + 62505960*uk_65 + 75764800*uk_66 + 174259040*uk_67 + 123117800*uk_68 + 411024040*uk_69 + 217*uk_7 + 75764800*uk_70 + 400795792*uk_71 + 283170940*uk_72 + 945355292*uk_73 + 174259040*uk_74 + 200066425*uk_75 + 667914065*uk_76 + 123117800*uk_77 + 2229805417*uk_78 + 411024040*uk_79 + 40*uk_8 + 75764800*uk_80 + 250047*uk_81 + 130977*uk_82 + 158760*uk_83 + 365148*uk_84 + 257985*uk_85 + 861273*uk_86 + 158760*uk_87 + 68607*uk_88 + 83160*uk_89 + 2242306609*uk_9 + 191268*uk_90 + 135135*uk_91 + 451143*uk_92 + 83160*uk_93 + 100800*uk_94 + 231840*uk_95 + 163800*uk_96 + 546840*uk_97 + 100800*uk_98 + 533232*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 371448*uk_100 + 1203048*uk_101 + 182952*uk_102 + 282807*uk_103 + 915957*uk_104 + 139293*uk_105 + 2966607*uk_106 + 451143*uk_107 + 68607*uk_108 + 132651*uk_109 + 2415003*uk_11 + 85833*uk_110 + 228888*uk_111 + 174267*uk_112 + 564417*uk_113 + 85833*uk_114 + 55539*uk_115 + 148104*uk_116 + 112761*uk_117 + 365211*uk_118 + 55539*uk_119 + 1562649*uk_12 + 394944*uk_120 + 300696*uk_121 + 973896*uk_122 + 148104*uk_123 + 228939*uk_124 + 741489*uk_125 + 112761*uk_126 + 2401539*uk_127 + 365211*uk_128 + 55539*uk_129 + 4167064*uk_13 + 35937*uk_130 + 95832*uk_131 + 72963*uk_132 + 236313*uk_133 + 35937*uk_134 + 255552*uk_135 + 194568*uk_136 + 630168*uk_137 + 95832*uk_138 + 148137*uk_139 + 3172651*uk_14 + 479787*uk_140 + 72963*uk_141 + 1553937*uk_142 + 236313*uk_143 + 35937*uk_144 + 681472*uk_145 + 518848*uk_146 + 1680448*uk_147 + 255552*uk_148 + 395032*uk_149 + 10275601*uk_15 + 1279432*uk_150 + 194568*uk_151 + 4143832*uk_152 + 630168*uk_153 + 95832*uk_154 + 300763*uk_155 + 974113*uk_156 + 148137*uk_157 + 3154963*uk_158 + 479787*uk_159 + 1562649*uk_16 + 72963*uk_160 + 10218313*uk_161 + 1553937*uk_162 + 236313*uk_163 + 35937*uk_164 + 3969*uk_17 + 3213*uk_18 + 2079*uk_19 + 63*uk_2 + 5544*uk_20 + 4221*uk_21 + 13671*uk_22 + 2079*uk_23 + 2601*uk_24 + 1683*uk_25 + 4488*uk_26 + 3417*uk_27 + 11067*uk_28 + 1683*uk_29 + 51*uk_3 + 1089*uk_30 + 2904*uk_31 + 2211*uk_32 + 7161*uk_33 + 1089*uk_34 + 7744*uk_35 + 5896*uk_36 + 19096*uk_37 + 2904*uk_38 + 4489*uk_39 + 33*uk_4 + 14539*uk_40 + 2211*uk_41 + 47089*uk_42 + 7161*uk_43 + 1089*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 114357637059*uk_47 + 73996118097*uk_48 + 197322981592*uk_49 + 88*uk_5 + 150234542803*uk_50 + 486580534153*uk_51 + 73996118097*uk_52 + 187944057*uk_53 + 152145189*uk_54 + 98446887*uk_55 + 262525032*uk_56 + 199877013*uk_57 + 647362863*uk_58 + 98446887*uk_59 + 67*uk_6 + 123165153*uk_60 + 79695099*uk_61 + 212520264*uk_62 + 161805201*uk_63 + 524055651*uk_64 + 79695099*uk_65 + 51567417*uk_66 + 137513112*uk_67 + 104697483*uk_68 + 339094833*uk_69 + 217*uk_7 + 51567417*uk_70 + 366701632*uk_71 + 279193288*uk_72 + 904252888*uk_73 + 137513112*uk_74 + 212567617*uk_75 + 688465267*uk_76 + 104697483*uk_77 + 2229805417*uk_78 + 339094833*uk_79 + 33*uk_8 + 51567417*uk_80 + 250047*uk_81 + 202419*uk_82 + 130977*uk_83 + 349272*uk_84 + 265923*uk_85 + 861273*uk_86 + 130977*uk_87 + 163863*uk_88 + 106029*uk_89 + 2242306609*uk_9 + 282744*uk_90 + 215271*uk_91 + 697221*uk_92 + 106029*uk_93 + 68607*uk_94 + 182952*uk_95 + 139293*uk_96 + 451143*uk_97 + 68607*uk_98 + 487872*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 347760*uk_100 + 1093680*uk_101 + 257040*uk_102 + 299943*uk_103 + 943299*uk_104 + 221697*uk_105 + 2966607*uk_106 + 697221*uk_107 + 163863*uk_108 + 6859*uk_109 + 899707*uk_11 + 18411*uk_110 + 28880*uk_111 + 24909*uk_112 + 78337*uk_113 + 18411*uk_114 + 49419*uk_115 + 77520*uk_116 + 66861*uk_117 + 210273*uk_118 + 49419*uk_119 + 2415003*uk_12 + 121600*uk_120 + 104880*uk_121 + 329840*uk_122 + 77520*uk_123 + 90459*uk_124 + 284487*uk_125 + 66861*uk_126 + 894691*uk_127 + 210273*uk_128 + 49419*uk_129 + 3788240*uk_13 + 132651*uk_130 + 208080*uk_131 + 179469*uk_132 + 564417*uk_133 + 132651*uk_134 + 326400*uk_135 + 281520*uk_136 + 885360*uk_137 + 208080*uk_138 + 242811*uk_139 + 3267357*uk_14 + 763623*uk_140 + 179469*uk_141 + 2401539*uk_142 + 564417*uk_143 + 132651*uk_144 + 512000*uk_145 + 441600*uk_146 + 1388800*uk_147 + 326400*uk_148 + 380880*uk_149 + 10275601*uk_15 + 1197840*uk_150 + 281520*uk_151 + 3767120*uk_152 + 885360*uk_153 + 208080*uk_154 + 328509*uk_155 + 1033137*uk_156 + 242811*uk_157 + 3249141*uk_158 + 763623*uk_159 + 2415003*uk_16 + 179469*uk_160 + 10218313*uk_161 + 2401539*uk_162 + 564417*uk_163 + 132651*uk_164 + 3969*uk_17 + 1197*uk_18 + 3213*uk_19 + 63*uk_2 + 5040*uk_20 + 4347*uk_21 + 13671*uk_22 + 3213*uk_23 + 361*uk_24 + 969*uk_25 + 1520*uk_26 + 1311*uk_27 + 4123*uk_28 + 969*uk_29 + 19*uk_3 + 2601*uk_30 + 4080*uk_31 + 3519*uk_32 + 11067*uk_33 + 2601*uk_34 + 6400*uk_35 + 5520*uk_36 + 17360*uk_37 + 4080*uk_38 + 4761*uk_39 + 51*uk_4 + 14973*uk_40 + 3519*uk_41 + 47089*uk_42 + 11067*uk_43 + 2601*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 42603825571*uk_47 + 114357637059*uk_48 + 179384528720*uk_49 + 80*uk_5 + 154719156021*uk_50 + 486580534153*uk_51 + 114357637059*uk_52 + 187944057*uk_53 + 56681541*uk_54 + 152145189*uk_55 + 238659120*uk_56 + 205843491*uk_57 + 647362863*uk_58 + 152145189*uk_59 + 69*uk_6 + 17094433*uk_60 + 45885057*uk_61 + 71976560*uk_62 + 62079783*uk_63 + 195236419*uk_64 + 45885057*uk_65 + 123165153*uk_66 + 193200240*uk_67 + 166635207*uk_68 + 524055651*uk_69 + 217*uk_7 + 123165153*uk_70 + 303059200*uk_71 + 261388560*uk_72 + 822048080*uk_73 + 193200240*uk_74 + 225447633*uk_75 + 709016469*uk_76 + 166635207*uk_77 + 2229805417*uk_78 + 524055651*uk_79 + 51*uk_8 + 123165153*uk_80 + 250047*uk_81 + 75411*uk_82 + 202419*uk_83 + 317520*uk_84 + 273861*uk_85 + 861273*uk_86 + 202419*uk_87 + 22743*uk_88 + 61047*uk_89 + 2242306609*uk_9 + 95760*uk_90 + 82593*uk_91 + 259749*uk_92 + 61047*uk_93 + 163863*uk_94 + 257040*uk_95 + 221697*uk_96 + 697221*uk_97 + 163863*uk_98 + 403200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 357840*uk_100 + 1093680*uk_101 + 95760*uk_102 + 317583*uk_103 + 970641*uk_104 + 84987*uk_105 + 2966607*uk_106 + 259749*uk_107 + 22743*uk_108 + 300763*uk_109 + 3172651*uk_11 + 85291*uk_110 + 359120*uk_111 + 318719*uk_112 + 974113*uk_113 + 85291*uk_114 + 24187*uk_115 + 101840*uk_116 + 90383*uk_117 + 276241*uk_118 + 24187*uk_119 + 899707*uk_12 + 428800*uk_120 + 380560*uk_121 + 1163120*uk_122 + 101840*uk_123 + 337747*uk_124 + 1032269*uk_125 + 90383*uk_126 + 3154963*uk_127 + 276241*uk_128 + 24187*uk_129 + 3788240*uk_13 + 6859*uk_130 + 28880*uk_131 + 25631*uk_132 + 78337*uk_133 + 6859*uk_134 + 121600*uk_135 + 107920*uk_136 + 329840*uk_137 + 28880*uk_138 + 95779*uk_139 + 3362063*uk_14 + 292733*uk_140 + 25631*uk_141 + 894691*uk_142 + 78337*uk_143 + 6859*uk_144 + 512000*uk_145 + 454400*uk_146 + 1388800*uk_147 + 121600*uk_148 + 403280*uk_149 + 10275601*uk_15 + 1232560*uk_150 + 107920*uk_151 + 3767120*uk_152 + 329840*uk_153 + 28880*uk_154 + 357911*uk_155 + 1093897*uk_156 + 95779*uk_157 + 3343319*uk_158 + 292733*uk_159 + 899707*uk_16 + 25631*uk_160 + 10218313*uk_161 + 894691*uk_162 + 78337*uk_163 + 6859*uk_164 + 3969*uk_17 + 4221*uk_18 + 1197*uk_19 + 63*uk_2 + 5040*uk_20 + 4473*uk_21 + 13671*uk_22 + 1197*uk_23 + 4489*uk_24 + 1273*uk_25 + 5360*uk_26 + 4757*uk_27 + 14539*uk_28 + 1273*uk_29 + 67*uk_3 + 361*uk_30 + 1520*uk_31 + 1349*uk_32 + 4123*uk_33 + 361*uk_34 + 6400*uk_35 + 5680*uk_36 + 17360*uk_37 + 1520*uk_38 + 5041*uk_39 + 19*uk_4 + 15407*uk_40 + 1349*uk_41 + 47089*uk_42 + 4123*uk_43 + 361*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 150234542803*uk_47 + 42603825571*uk_48 + 179384528720*uk_49 + 80*uk_5 + 159203769239*uk_50 + 486580534153*uk_51 + 42603825571*uk_52 + 187944057*uk_53 + 199877013*uk_54 + 56681541*uk_55 + 238659120*uk_56 + 211809969*uk_57 + 647362863*uk_58 + 56681541*uk_59 + 71*uk_6 + 212567617*uk_60 + 60280369*uk_61 + 253812080*uk_62 + 225258221*uk_63 + 688465267*uk_64 + 60280369*uk_65 + 17094433*uk_66 + 71976560*uk_67 + 63879197*uk_68 + 195236419*uk_69 + 217*uk_7 + 17094433*uk_70 + 303059200*uk_71 + 268965040*uk_72 + 822048080*uk_73 + 71976560*uk_74 + 238706473*uk_75 + 729567671*uk_76 + 63879197*uk_77 + 2229805417*uk_78 + 195236419*uk_79 + 19*uk_8 + 17094433*uk_80 + 250047*uk_81 + 265923*uk_82 + 75411*uk_83 + 317520*uk_84 + 281799*uk_85 + 861273*uk_86 + 75411*uk_87 + 282807*uk_88 + 80199*uk_89 + 2242306609*uk_9 + 337680*uk_90 + 299691*uk_91 + 915957*uk_92 + 80199*uk_93 + 22743*uk_94 + 95760*uk_95 + 84987*uk_96 + 259749*uk_97 + 22743*uk_98 + 403200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 331128*uk_100 + 984312*uk_101 + 303912*uk_102 + 335727*uk_103 + 997983*uk_104 + 308133*uk_105 + 2966607*uk_106 + 915957*uk_107 + 282807*uk_108 + 117649*uk_109 + 2320297*uk_11 + 160867*uk_110 + 172872*uk_111 + 175273*uk_112 + 521017*uk_113 + 160867*uk_114 + 219961*uk_115 + 236376*uk_116 + 239659*uk_117 + 712411*uk_118 + 219961*uk_119 + 3172651*uk_12 + 254016*uk_120 + 257544*uk_121 + 765576*uk_122 + 236376*uk_123 + 261121*uk_124 + 776209*uk_125 + 239659*uk_126 + 2307361*uk_127 + 712411*uk_128 + 219961*uk_129 + 3409416*uk_13 + 300763*uk_130 + 323208*uk_131 + 327697*uk_132 + 974113*uk_133 + 300763*uk_134 + 347328*uk_135 + 352152*uk_136 + 1046808*uk_137 + 323208*uk_138 + 357043*uk_139 + 3456769*uk_14 + 1061347*uk_140 + 327697*uk_141 + 3154963*uk_142 + 974113*uk_143 + 300763*uk_144 + 373248*uk_145 + 378432*uk_146 + 1124928*uk_147 + 347328*uk_148 + 383688*uk_149 + 10275601*uk_15 + 1140552*uk_150 + 352152*uk_151 + 3390408*uk_152 + 1046808*uk_153 + 323208*uk_154 + 389017*uk_155 + 1156393*uk_156 + 357043*uk_157 + 3437497*uk_158 + 1061347*uk_159 + 3172651*uk_16 + 327697*uk_160 + 10218313*uk_161 + 3154963*uk_162 + 974113*uk_163 + 300763*uk_164 + 3969*uk_17 + 3087*uk_18 + 4221*uk_19 + 63*uk_2 + 4536*uk_20 + 4599*uk_21 + 13671*uk_22 + 4221*uk_23 + 2401*uk_24 + 3283*uk_25 + 3528*uk_26 + 3577*uk_27 + 10633*uk_28 + 3283*uk_29 + 49*uk_3 + 4489*uk_30 + 4824*uk_31 + 4891*uk_32 + 14539*uk_33 + 4489*uk_34 + 5184*uk_35 + 5256*uk_36 + 15624*uk_37 + 4824*uk_38 + 5329*uk_39 + 67*uk_4 + 15841*uk_40 + 4891*uk_41 + 47089*uk_42 + 14539*uk_43 + 4489*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 109873023841*uk_47 + 150234542803*uk_48 + 161446075848*uk_49 + 72*uk_5 + 163688382457*uk_50 + 486580534153*uk_51 + 150234542803*uk_52 + 187944057*uk_53 + 146178711*uk_54 + 199877013*uk_55 + 214793208*uk_56 + 217776447*uk_57 + 647362863*uk_58 + 199877013*uk_59 + 73*uk_6 + 113694553*uk_60 + 155459899*uk_61 + 167061384*uk_62 + 169381681*uk_63 + 503504449*uk_64 + 155459899*uk_65 + 212567617*uk_66 + 228430872*uk_67 + 231603523*uk_68 + 688465267*uk_69 + 217*uk_7 + 212567617*uk_70 + 245477952*uk_71 + 248887368*uk_72 + 739843272*uk_73 + 228430872*uk_74 + 252344137*uk_75 + 750118873*uk_76 + 231603523*uk_77 + 2229805417*uk_78 + 688465267*uk_79 + 67*uk_8 + 212567617*uk_80 + 250047*uk_81 + 194481*uk_82 + 265923*uk_83 + 285768*uk_84 + 289737*uk_85 + 861273*uk_86 + 265923*uk_87 + 151263*uk_88 + 206829*uk_89 + 2242306609*uk_9 + 222264*uk_90 + 225351*uk_91 + 669879*uk_92 + 206829*uk_93 + 282807*uk_94 + 303912*uk_95 + 308133*uk_96 + 915957*uk_97 + 282807*uk_98 + 326592*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 321300*uk_100 + 929628*uk_101 + 209916*uk_102 + 354375*uk_103 + 1025325*uk_104 + 231525*uk_105 + 2966607*uk_106 + 669879*uk_107 + 151263*uk_108 + 21952*uk_109 + 1325884*uk_11 + 38416*uk_110 + 53312*uk_111 + 58800*uk_112 + 170128*uk_113 + 38416*uk_114 + 67228*uk_115 + 93296*uk_116 + 102900*uk_117 + 297724*uk_118 + 67228*uk_119 + 2320297*uk_12 + 129472*uk_120 + 142800*uk_121 + 413168*uk_122 + 93296*uk_123 + 157500*uk_124 + 455700*uk_125 + 102900*uk_126 + 1318492*uk_127 + 297724*uk_128 + 67228*uk_129 + 3220004*uk_13 + 117649*uk_130 + 163268*uk_131 + 180075*uk_132 + 521017*uk_133 + 117649*uk_134 + 226576*uk_135 + 249900*uk_136 + 723044*uk_137 + 163268*uk_138 + 275625*uk_139 + 3551475*uk_14 + 797475*uk_140 + 180075*uk_141 + 2307361*uk_142 + 521017*uk_143 + 117649*uk_144 + 314432*uk_145 + 346800*uk_146 + 1003408*uk_147 + 226576*uk_148 + 382500*uk_149 + 10275601*uk_15 + 1106700*uk_150 + 249900*uk_151 + 3202052*uk_152 + 723044*uk_153 + 163268*uk_154 + 421875*uk_155 + 1220625*uk_156 + 275625*uk_157 + 3531675*uk_158 + 797475*uk_159 + 2320297*uk_16 + 180075*uk_160 + 10218313*uk_161 + 2307361*uk_162 + 521017*uk_163 + 117649*uk_164 + 3969*uk_17 + 1764*uk_18 + 3087*uk_19 + 63*uk_2 + 4284*uk_20 + 4725*uk_21 + 13671*uk_22 + 3087*uk_23 + 784*uk_24 + 1372*uk_25 + 1904*uk_26 + 2100*uk_27 + 6076*uk_28 + 1372*uk_29 + 28*uk_3 + 2401*uk_30 + 3332*uk_31 + 3675*uk_32 + 10633*uk_33 + 2401*uk_34 + 4624*uk_35 + 5100*uk_36 + 14756*uk_37 + 3332*uk_38 + 5625*uk_39 + 49*uk_4 + 16275*uk_40 + 3675*uk_41 + 47089*uk_42 + 10633*uk_43 + 2401*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 62784585052*uk_47 + 109873023841*uk_48 + 152476849412*uk_49 + 68*uk_5 + 168172995675*uk_50 + 486580534153*uk_51 + 109873023841*uk_52 + 187944057*uk_53 + 83530692*uk_54 + 146178711*uk_55 + 202860252*uk_56 + 223742925*uk_57 + 647362863*uk_58 + 146178711*uk_59 + 75*uk_6 + 37124752*uk_60 + 64968316*uk_61 + 90160112*uk_62 + 99441300*uk_63 + 287716828*uk_64 + 64968316*uk_65 + 113694553*uk_66 + 157780196*uk_67 + 174022275*uk_68 + 503504449*uk_69 + 217*uk_7 + 113694553*uk_70 + 218960272*uk_71 + 241500300*uk_72 + 698740868*uk_73 + 157780196*uk_74 + 266360625*uk_75 + 770670075*uk_76 + 174022275*uk_77 + 2229805417*uk_78 + 503504449*uk_79 + 49*uk_8 + 113694553*uk_80 + 250047*uk_81 + 111132*uk_82 + 194481*uk_83 + 269892*uk_84 + 297675*uk_85 + 861273*uk_86 + 194481*uk_87 + 49392*uk_88 + 86436*uk_89 + 2242306609*uk_9 + 119952*uk_90 + 132300*uk_91 + 382788*uk_92 + 86436*uk_93 + 151263*uk_94 + 209916*uk_95 + 231525*uk_96 + 669879*uk_97 + 151263*uk_98 + 291312*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 329868*uk_100 + 929628*uk_101 + 119952*uk_102 + 373527*uk_103 + 1052667*uk_104 + 135828*uk_105 + 2966607*uk_106 + 382788*uk_107 + 49392*uk_108 + 421875*uk_109 + 3551475*uk_11 + 157500*uk_110 + 382500*uk_111 + 433125*uk_112 + 1220625*uk_113 + 157500*uk_114 + 58800*uk_115 + 142800*uk_116 + 161700*uk_117 + 455700*uk_118 + 58800*uk_119 + 1325884*uk_12 + 346800*uk_120 + 392700*uk_121 + 1106700*uk_122 + 142800*uk_123 + 444675*uk_124 + 1253175*uk_125 + 161700*uk_126 + 3531675*uk_127 + 455700*uk_128 + 58800*uk_129 + 3220004*uk_13 + 21952*uk_130 + 53312*uk_131 + 60368*uk_132 + 170128*uk_133 + 21952*uk_134 + 129472*uk_135 + 146608*uk_136 + 413168*uk_137 + 53312*uk_138 + 166012*uk_139 + 3646181*uk_14 + 467852*uk_140 + 60368*uk_141 + 1318492*uk_142 + 170128*uk_143 + 21952*uk_144 + 314432*uk_145 + 356048*uk_146 + 1003408*uk_147 + 129472*uk_148 + 403172*uk_149 + 10275601*uk_15 + 1136212*uk_150 + 146608*uk_151 + 3202052*uk_152 + 413168*uk_153 + 53312*uk_154 + 456533*uk_155 + 1286593*uk_156 + 166012*uk_157 + 3625853*uk_158 + 467852*uk_159 + 1325884*uk_16 + 60368*uk_160 + 10218313*uk_161 + 1318492*uk_162 + 170128*uk_163 + 21952*uk_164 + 3969*uk_17 + 4725*uk_18 + 1764*uk_19 + 63*uk_2 + 4284*uk_20 + 4851*uk_21 + 13671*uk_22 + 1764*uk_23 + 5625*uk_24 + 2100*uk_25 + 5100*uk_26 + 5775*uk_27 + 16275*uk_28 + 2100*uk_29 + 75*uk_3 + 784*uk_30 + 1904*uk_31 + 2156*uk_32 + 6076*uk_33 + 784*uk_34 + 4624*uk_35 + 5236*uk_36 + 14756*uk_37 + 1904*uk_38 + 5929*uk_39 + 28*uk_4 + 16709*uk_40 + 2156*uk_41 + 47089*uk_42 + 6076*uk_43 + 784*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 168172995675*uk_47 + 62784585052*uk_48 + 152476849412*uk_49 + 68*uk_5 + 172657608893*uk_50 + 486580534153*uk_51 + 62784585052*uk_52 + 187944057*uk_53 + 223742925*uk_54 + 83530692*uk_55 + 202860252*uk_56 + 229709403*uk_57 + 647362863*uk_58 + 83530692*uk_59 + 77*uk_6 + 266360625*uk_60 + 99441300*uk_61 + 241500300*uk_62 + 273463575*uk_63 + 770670075*uk_64 + 99441300*uk_65 + 37124752*uk_66 + 90160112*uk_67 + 102093068*uk_68 + 287716828*uk_69 + 217*uk_7 + 37124752*uk_70 + 218960272*uk_71 + 247940308*uk_72 + 698740868*uk_73 + 90160112*uk_74 + 280755937*uk_75 + 791221277*uk_76 + 102093068*uk_77 + 2229805417*uk_78 + 287716828*uk_79 + 28*uk_8 + 37124752*uk_80 + 250047*uk_81 + 297675*uk_82 + 111132*uk_83 + 269892*uk_84 + 305613*uk_85 + 861273*uk_86 + 111132*uk_87 + 354375*uk_88 + 132300*uk_89 + 2242306609*uk_9 + 321300*uk_90 + 363825*uk_91 + 1025325*uk_92 + 132300*uk_93 + 49392*uk_94 + 119952*uk_95 + 135828*uk_96 + 382788*uk_97 + 49392*uk_98 + 291312*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 298620*uk_100 + 820260*uk_101 + 283500*uk_102 + 393183*uk_103 + 1080009*uk_104 + 373275*uk_105 + 2966607*uk_106 + 1025325*uk_107 + 354375*uk_108 + 32768*uk_109 + 1515296*uk_11 + 76800*uk_110 + 61440*uk_111 + 80896*uk_112 + 222208*uk_113 + 76800*uk_114 + 180000*uk_115 + 144000*uk_116 + 189600*uk_117 + 520800*uk_118 + 180000*uk_119 + 3551475*uk_12 + 115200*uk_120 + 151680*uk_121 + 416640*uk_122 + 144000*uk_123 + 199712*uk_124 + 548576*uk_125 + 189600*uk_126 + 1506848*uk_127 + 520800*uk_128 + 180000*uk_129 + 2841180*uk_13 + 421875*uk_130 + 337500*uk_131 + 444375*uk_132 + 1220625*uk_133 + 421875*uk_134 + 270000*uk_135 + 355500*uk_136 + 976500*uk_137 + 337500*uk_138 + 468075*uk_139 + 3740887*uk_14 + 1285725*uk_140 + 444375*uk_141 + 3531675*uk_142 + 1220625*uk_143 + 421875*uk_144 + 216000*uk_145 + 284400*uk_146 + 781200*uk_147 + 270000*uk_148 + 374460*uk_149 + 10275601*uk_15 + 1028580*uk_150 + 355500*uk_151 + 2825340*uk_152 + 976500*uk_153 + 337500*uk_154 + 493039*uk_155 + 1354297*uk_156 + 468075*uk_157 + 3720031*uk_158 + 1285725*uk_159 + 3551475*uk_16 + 444375*uk_160 + 10218313*uk_161 + 3531675*uk_162 + 1220625*uk_163 + 421875*uk_164 + 3969*uk_17 + 2016*uk_18 + 4725*uk_19 + 63*uk_2 + 3780*uk_20 + 4977*uk_21 + 13671*uk_22 + 4725*uk_23 + 1024*uk_24 + 2400*uk_25 + 1920*uk_26 + 2528*uk_27 + 6944*uk_28 + 2400*uk_29 + 32*uk_3 + 5625*uk_30 + 4500*uk_31 + 5925*uk_32 + 16275*uk_33 + 5625*uk_34 + 3600*uk_35 + 4740*uk_36 + 13020*uk_37 + 4500*uk_38 + 6241*uk_39 + 75*uk_4 + 17143*uk_40 + 5925*uk_41 + 47089*uk_42 + 16275*uk_43 + 5625*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 71753811488*uk_47 + 168172995675*uk_48 + 134538396540*uk_49 + 60*uk_5 + 177142222111*uk_50 + 486580534153*uk_51 + 168172995675*uk_52 + 187944057*uk_53 + 95463648*uk_54 + 223742925*uk_55 + 178994340*uk_56 + 235675881*uk_57 + 647362863*uk_58 + 223742925*uk_59 + 79*uk_6 + 48489472*uk_60 + 113647200*uk_61 + 90917760*uk_62 + 119708384*uk_63 + 328819232*uk_64 + 113647200*uk_65 + 266360625*uk_66 + 213088500*uk_67 + 280566525*uk_68 + 770670075*uk_69 + 217*uk_7 + 266360625*uk_70 + 170470800*uk_71 + 224453220*uk_72 + 616536060*uk_73 + 213088500*uk_74 + 295530073*uk_75 + 811772479*uk_76 + 280566525*uk_77 + 2229805417*uk_78 + 770670075*uk_79 + 75*uk_8 + 266360625*uk_80 + 250047*uk_81 + 127008*uk_82 + 297675*uk_83 + 238140*uk_84 + 313551*uk_85 + 861273*uk_86 + 297675*uk_87 + 64512*uk_88 + 151200*uk_89 + 2242306609*uk_9 + 120960*uk_90 + 159264*uk_91 + 437472*uk_92 + 151200*uk_93 + 354375*uk_94 + 283500*uk_95 + 373275*uk_96 + 1025325*uk_97 + 354375*uk_98 + 226800*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 306180*uk_100 + 820260*uk_101 + 120960*uk_102 + 413343*uk_103 + 1107351*uk_104 + 163296*uk_105 + 2966607*uk_106 + 437472*uk_107 + 64512*uk_108 + 117649*uk_109 + 2320297*uk_11 + 76832*uk_110 + 144060*uk_111 + 194481*uk_112 + 521017*uk_113 + 76832*uk_114 + 50176*uk_115 + 94080*uk_116 + 127008*uk_117 + 340256*uk_118 + 50176*uk_119 + 1515296*uk_12 + 176400*uk_120 + 238140*uk_121 + 637980*uk_122 + 94080*uk_123 + 321489*uk_124 + 861273*uk_125 + 127008*uk_126 + 2307361*uk_127 + 340256*uk_128 + 50176*uk_129 + 2841180*uk_13 + 32768*uk_130 + 61440*uk_131 + 82944*uk_132 + 222208*uk_133 + 32768*uk_134 + 115200*uk_135 + 155520*uk_136 + 416640*uk_137 + 61440*uk_138 + 209952*uk_139 + 3835593*uk_14 + 562464*uk_140 + 82944*uk_141 + 1506848*uk_142 + 222208*uk_143 + 32768*uk_144 + 216000*uk_145 + 291600*uk_146 + 781200*uk_147 + 115200*uk_148 + 393660*uk_149 + 10275601*uk_15 + 1054620*uk_150 + 155520*uk_151 + 2825340*uk_152 + 416640*uk_153 + 61440*uk_154 + 531441*uk_155 + 1423737*uk_156 + 209952*uk_157 + 3814209*uk_158 + 562464*uk_159 + 1515296*uk_16 + 82944*uk_160 + 10218313*uk_161 + 1506848*uk_162 + 222208*uk_163 + 32768*uk_164 + 3969*uk_17 + 3087*uk_18 + 2016*uk_19 + 63*uk_2 + 3780*uk_20 + 5103*uk_21 + 13671*uk_22 + 2016*uk_23 + 2401*uk_24 + 1568*uk_25 + 2940*uk_26 + 3969*uk_27 + 10633*uk_28 + 1568*uk_29 + 49*uk_3 + 1024*uk_30 + 1920*uk_31 + 2592*uk_32 + 6944*uk_33 + 1024*uk_34 + 3600*uk_35 + 4860*uk_36 + 13020*uk_37 + 1920*uk_38 + 6561*uk_39 + 32*uk_4 + 17577*uk_40 + 2592*uk_41 + 47089*uk_42 + 6944*uk_43 + 1024*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 109873023841*uk_47 + 71753811488*uk_48 + 134538396540*uk_49 + 60*uk_5 + 181626835329*uk_50 + 486580534153*uk_51 + 71753811488*uk_52 + 187944057*uk_53 + 146178711*uk_54 + 95463648*uk_55 + 178994340*uk_56 + 241642359*uk_57 + 647362863*uk_58 + 95463648*uk_59 + 81*uk_6 + 113694553*uk_60 + 74249504*uk_61 + 139217820*uk_62 + 187944057*uk_63 + 503504449*uk_64 + 74249504*uk_65 + 48489472*uk_66 + 90917760*uk_67 + 122738976*uk_68 + 328819232*uk_69 + 217*uk_7 + 48489472*uk_70 + 170470800*uk_71 + 230135580*uk_72 + 616536060*uk_73 + 90917760*uk_74 + 310683033*uk_75 + 832323681*uk_76 + 122738976*uk_77 + 2229805417*uk_78 + 328819232*uk_79 + 32*uk_8 + 48489472*uk_80 + 250047*uk_81 + 194481*uk_82 + 127008*uk_83 + 238140*uk_84 + 321489*uk_85 + 861273*uk_86 + 127008*uk_87 + 151263*uk_88 + 98784*uk_89 + 2242306609*uk_9 + 185220*uk_90 + 250047*uk_91 + 669879*uk_92 + 98784*uk_93 + 64512*uk_94 + 120960*uk_95 + 163296*uk_96 + 437472*uk_97 + 64512*uk_98 + 226800*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 292824*uk_100 + 765576*uk_101 + 172872*uk_102 + 434007*uk_103 + 1134693*uk_104 + 256221*uk_105 + 2966607*uk_106 + 669879*uk_107 + 151263*uk_108 + 79507*uk_109 + 2036179*uk_11 + 90601*uk_110 + 103544*uk_111 + 153467*uk_112 + 401233*uk_113 + 90601*uk_114 + 103243*uk_115 + 117992*uk_116 + 174881*uk_117 + 457219*uk_118 + 103243*uk_119 + 2320297*uk_12 + 134848*uk_120 + 199864*uk_121 + 522536*uk_122 + 117992*uk_123 + 296227*uk_124 + 774473*uk_125 + 174881*uk_126 + 2024827*uk_127 + 457219*uk_128 + 103243*uk_129 + 2651768*uk_13 + 117649*uk_130 + 134456*uk_131 + 199283*uk_132 + 521017*uk_133 + 117649*uk_134 + 153664*uk_135 + 227752*uk_136 + 595448*uk_137 + 134456*uk_138 + 337561*uk_139 + 3930299*uk_14 + 882539*uk_140 + 199283*uk_141 + 2307361*uk_142 + 521017*uk_143 + 117649*uk_144 + 175616*uk_145 + 260288*uk_146 + 680512*uk_147 + 153664*uk_148 + 385784*uk_149 + 10275601*uk_15 + 1008616*uk_150 + 227752*uk_151 + 2636984*uk_152 + 595448*uk_153 + 134456*uk_154 + 571787*uk_155 + 1494913*uk_156 + 337561*uk_157 + 3908387*uk_158 + 882539*uk_159 + 2320297*uk_16 + 199283*uk_160 + 10218313*uk_161 + 2307361*uk_162 + 521017*uk_163 + 117649*uk_164 + 3969*uk_17 + 2709*uk_18 + 3087*uk_19 + 63*uk_2 + 3528*uk_20 + 5229*uk_21 + 13671*uk_22 + 3087*uk_23 + 1849*uk_24 + 2107*uk_25 + 2408*uk_26 + 3569*uk_27 + 9331*uk_28 + 2107*uk_29 + 43*uk_3 + 2401*uk_30 + 2744*uk_31 + 4067*uk_32 + 10633*uk_33 + 2401*uk_34 + 3136*uk_35 + 4648*uk_36 + 12152*uk_37 + 2744*uk_38 + 6889*uk_39 + 49*uk_4 + 18011*uk_40 + 4067*uk_41 + 47089*uk_42 + 10633*uk_43 + 2401*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 96419184187*uk_47 + 109873023841*uk_48 + 125569170104*uk_49 + 56*uk_5 + 186111448547*uk_50 + 486580534153*uk_51 + 109873023841*uk_52 + 187944057*uk_53 + 128279277*uk_54 + 146178711*uk_55 + 167061384*uk_56 + 247608837*uk_57 + 647362863*uk_58 + 146178711*uk_59 + 83*uk_6 + 87555697*uk_60 + 99772771*uk_61 + 114026024*uk_62 + 169002857*uk_63 + 441850843*uk_64 + 99772771*uk_65 + 113694553*uk_66 + 129936632*uk_67 + 192584651*uk_68 + 503504449*uk_69 + 217*uk_7 + 113694553*uk_70 + 148499008*uk_71 + 220096744*uk_72 + 575433656*uk_73 + 129936632*uk_74 + 326214817*uk_75 + 852874883*uk_76 + 192584651*uk_77 + 2229805417*uk_78 + 503504449*uk_79 + 49*uk_8 + 113694553*uk_80 + 250047*uk_81 + 170667*uk_82 + 194481*uk_83 + 222264*uk_84 + 329427*uk_85 + 861273*uk_86 + 194481*uk_87 + 116487*uk_88 + 132741*uk_89 + 2242306609*uk_9 + 151704*uk_90 + 224847*uk_91 + 587853*uk_92 + 132741*uk_93 + 151263*uk_94 + 172872*uk_95 + 256221*uk_96 + 669879*uk_97 + 151263*uk_98 + 197568*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 278460*uk_100 + 710892*uk_101 + 140868*uk_102 + 455175*uk_103 + 1162035*uk_104 + 230265*uk_105 + 2966607*uk_106 + 587853*uk_107 + 116487*uk_108 + 512*uk_109 + 378824*uk_11 + 2752*uk_110 + 3328*uk_111 + 5440*uk_112 + 13888*uk_113 + 2752*uk_114 + 14792*uk_115 + 17888*uk_116 + 29240*uk_117 + 74648*uk_118 + 14792*uk_119 + 2036179*uk_12 + 21632*uk_120 + 35360*uk_121 + 90272*uk_122 + 17888*uk_123 + 57800*uk_124 + 147560*uk_125 + 29240*uk_126 + 376712*uk_127 + 74648*uk_128 + 14792*uk_129 + 2462356*uk_13 + 79507*uk_130 + 96148*uk_131 + 157165*uk_132 + 401233*uk_133 + 79507*uk_134 + 116272*uk_135 + 190060*uk_136 + 485212*uk_137 + 96148*uk_138 + 310675*uk_139 + 4025005*uk_14 + 793135*uk_140 + 157165*uk_141 + 2024827*uk_142 + 401233*uk_143 + 79507*uk_144 + 140608*uk_145 + 229840*uk_146 + 586768*uk_147 + 116272*uk_148 + 375700*uk_149 + 10275601*uk_15 + 959140*uk_150 + 190060*uk_151 + 2448628*uk_152 + 485212*uk_153 + 96148*uk_154 + 614125*uk_155 + 1567825*uk_156 + 310675*uk_157 + 4002565*uk_158 + 793135*uk_159 + 2036179*uk_16 + 157165*uk_160 + 10218313*uk_161 + 2024827*uk_162 + 401233*uk_163 + 79507*uk_164 + 3969*uk_17 + 504*uk_18 + 2709*uk_19 + 63*uk_2 + 3276*uk_20 + 5355*uk_21 + 13671*uk_22 + 2709*uk_23 + 64*uk_24 + 344*uk_25 + 416*uk_26 + 680*uk_27 + 1736*uk_28 + 344*uk_29 + 8*uk_3 + 1849*uk_30 + 2236*uk_31 + 3655*uk_32 + 9331*uk_33 + 1849*uk_34 + 2704*uk_35 + 4420*uk_36 + 11284*uk_37 + 2236*uk_38 + 7225*uk_39 + 43*uk_4 + 18445*uk_40 + 3655*uk_41 + 47089*uk_42 + 9331*uk_43 + 1849*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 17938452872*uk_47 + 96419184187*uk_48 + 116599943668*uk_49 + 52*uk_5 + 190596061765*uk_50 + 486580534153*uk_51 + 96419184187*uk_52 + 187944057*uk_53 + 23865912*uk_54 + 128279277*uk_55 + 155128428*uk_56 + 253575315*uk_57 + 647362863*uk_58 + 128279277*uk_59 + 85*uk_6 + 3030592*uk_60 + 16289432*uk_61 + 19698848*uk_62 + 32200040*uk_63 + 82204808*uk_64 + 16289432*uk_65 + 87555697*uk_66 + 105881308*uk_67 + 173075215*uk_68 + 441850843*uk_69 + 217*uk_7 + 87555697*uk_70 + 128042512*uk_71 + 209300260*uk_72 + 534331252*uk_73 + 105881308*uk_74 + 342125425*uk_75 + 873426085*uk_76 + 173075215*uk_77 + 2229805417*uk_78 + 441850843*uk_79 + 43*uk_8 + 87555697*uk_80 + 250047*uk_81 + 31752*uk_82 + 170667*uk_83 + 206388*uk_84 + 337365*uk_85 + 861273*uk_86 + 170667*uk_87 + 4032*uk_88 + 21672*uk_89 + 2242306609*uk_9 + 26208*uk_90 + 42840*uk_91 + 109368*uk_92 + 21672*uk_93 + 116487*uk_94 + 140868*uk_95 + 230265*uk_96 + 587853*uk_97 + 116487*uk_98 + 170352*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 285012*uk_100 + 710892*uk_101 + 26208*uk_102 + 476847*uk_103 + 1189377*uk_104 + 43848*uk_105 + 2966607*uk_106 + 109368*uk_107 + 4032*uk_108 + 15625*uk_109 + 1183825*uk_11 + 5000*uk_110 + 32500*uk_111 + 54375*uk_112 + 135625*uk_113 + 5000*uk_114 + 1600*uk_115 + 10400*uk_116 + 17400*uk_117 + 43400*uk_118 + 1600*uk_119 + 378824*uk_12 + 67600*uk_120 + 113100*uk_121 + 282100*uk_122 + 10400*uk_123 + 189225*uk_124 + 471975*uk_125 + 17400*uk_126 + 1177225*uk_127 + 43400*uk_128 + 1600*uk_129 + 2462356*uk_13 + 512*uk_130 + 3328*uk_131 + 5568*uk_132 + 13888*uk_133 + 512*uk_134 + 21632*uk_135 + 36192*uk_136 + 90272*uk_137 + 3328*uk_138 + 60552*uk_139 + 4119711*uk_14 + 151032*uk_140 + 5568*uk_141 + 376712*uk_142 + 13888*uk_143 + 512*uk_144 + 140608*uk_145 + 235248*uk_146 + 586768*uk_147 + 21632*uk_148 + 393588*uk_149 + 10275601*uk_15 + 981708*uk_150 + 36192*uk_151 + 2448628*uk_152 + 90272*uk_153 + 3328*uk_154 + 658503*uk_155 + 1642473*uk_156 + 60552*uk_157 + 4096743*uk_158 + 151032*uk_159 + 378824*uk_16 + 5568*uk_160 + 10218313*uk_161 + 376712*uk_162 + 13888*uk_163 + 512*uk_164 + 3969*uk_17 + 1575*uk_18 + 504*uk_19 + 63*uk_2 + 3276*uk_20 + 5481*uk_21 + 13671*uk_22 + 504*uk_23 + 625*uk_24 + 200*uk_25 + 1300*uk_26 + 2175*uk_27 + 5425*uk_28 + 200*uk_29 + 25*uk_3 + 64*uk_30 + 416*uk_31 + 696*uk_32 + 1736*uk_33 + 64*uk_34 + 2704*uk_35 + 4524*uk_36 + 11284*uk_37 + 416*uk_38 + 7569*uk_39 + 8*uk_4 + 18879*uk_40 + 696*uk_41 + 47089*uk_42 + 1736*uk_43 + 64*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 56057665225*uk_47 + 17938452872*uk_48 + 116599943668*uk_49 + 52*uk_5 + 195080674983*uk_50 + 486580534153*uk_51 + 17938452872*uk_52 + 187944057*uk_53 + 74580975*uk_54 + 23865912*uk_55 + 155128428*uk_56 + 259541793*uk_57 + 647362863*uk_58 + 23865912*uk_59 + 87*uk_6 + 29595625*uk_60 + 9470600*uk_61 + 61558900*uk_62 + 102992775*uk_63 + 256890025*uk_64 + 9470600*uk_65 + 3030592*uk_66 + 19698848*uk_67 + 32957688*uk_68 + 82204808*uk_69 + 217*uk_7 + 3030592*uk_70 + 128042512*uk_71 + 214224972*uk_72 + 534331252*uk_73 + 19698848*uk_74 + 358414857*uk_75 + 893977287*uk_76 + 32957688*uk_77 + 2229805417*uk_78 + 82204808*uk_79 + 8*uk_8 + 3030592*uk_80 + 250047*uk_81 + 99225*uk_82 + 31752*uk_83 + 206388*uk_84 + 345303*uk_85 + 861273*uk_86 + 31752*uk_87 + 39375*uk_88 + 12600*uk_89 + 2242306609*uk_9 + 81900*uk_90 + 137025*uk_91 + 341775*uk_92 + 12600*uk_93 + 4032*uk_94 + 26208*uk_95 + 43848*uk_96 + 109368*uk_97 + 4032*uk_98 + 170352*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 269136*uk_100 + 656208*uk_101 + 75600*uk_102 + 499023*uk_103 + 1216719*uk_104 + 140175*uk_105 + 2966607*uk_106 + 341775*uk_107 + 39375*uk_108 + 125*uk_109 + 236765*uk_11 + 625*uk_110 + 1200*uk_111 + 2225*uk_112 + 5425*uk_113 + 625*uk_114 + 3125*uk_115 + 6000*uk_116 + 11125*uk_117 + 27125*uk_118 + 3125*uk_119 + 1183825*uk_12 + 11520*uk_120 + 21360*uk_121 + 52080*uk_122 + 6000*uk_123 + 39605*uk_124 + 96565*uk_125 + 11125*uk_126 + 235445*uk_127 + 27125*uk_128 + 3125*uk_129 + 2272944*uk_13 + 15625*uk_130 + 30000*uk_131 + 55625*uk_132 + 135625*uk_133 + 15625*uk_134 + 57600*uk_135 + 106800*uk_136 + 260400*uk_137 + 30000*uk_138 + 198025*uk_139 + 4214417*uk_14 + 482825*uk_140 + 55625*uk_141 + 1177225*uk_142 + 135625*uk_143 + 15625*uk_144 + 110592*uk_145 + 205056*uk_146 + 499968*uk_147 + 57600*uk_148 + 380208*uk_149 + 10275601*uk_15 + 927024*uk_150 + 106800*uk_151 + 2260272*uk_152 + 260400*uk_153 + 30000*uk_154 + 704969*uk_155 + 1718857*uk_156 + 198025*uk_157 + 4190921*uk_158 + 482825*uk_159 + 1183825*uk_16 + 55625*uk_160 + 10218313*uk_161 + 1177225*uk_162 + 135625*uk_163 + 15625*uk_164 + 3969*uk_17 + 315*uk_18 + 1575*uk_19 + 63*uk_2 + 3024*uk_20 + 5607*uk_21 + 13671*uk_22 + 1575*uk_23 + 25*uk_24 + 125*uk_25 + 240*uk_26 + 445*uk_27 + 1085*uk_28 + 125*uk_29 + 5*uk_3 + 625*uk_30 + 1200*uk_31 + 2225*uk_32 + 5425*uk_33 + 625*uk_34 + 2304*uk_35 + 4272*uk_36 + 10416*uk_37 + 1200*uk_38 + 7921*uk_39 + 25*uk_4 + 19313*uk_40 + 2225*uk_41 + 47089*uk_42 + 5425*uk_43 + 625*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 11211533045*uk_47 + 56057665225*uk_48 + 107630717232*uk_49 + 48*uk_5 + 199565288201*uk_50 + 486580534153*uk_51 + 56057665225*uk_52 + 187944057*uk_53 + 14916195*uk_54 + 74580975*uk_55 + 143195472*uk_56 + 265508271*uk_57 + 647362863*uk_58 + 74580975*uk_59 + 89*uk_6 + 1183825*uk_60 + 5919125*uk_61 + 11364720*uk_62 + 21072085*uk_63 + 51378005*uk_64 + 5919125*uk_65 + 29595625*uk_66 + 56823600*uk_67 + 105360425*uk_68 + 256890025*uk_69 + 217*uk_7 + 29595625*uk_70 + 109101312*uk_71 + 202292016*uk_72 + 493228848*uk_73 + 56823600*uk_74 + 375083113*uk_75 + 914528489*uk_76 + 105360425*uk_77 + 2229805417*uk_78 + 256890025*uk_79 + 25*uk_8 + 29595625*uk_80 + 250047*uk_81 + 19845*uk_82 + 99225*uk_83 + 190512*uk_84 + 353241*uk_85 + 861273*uk_86 + 99225*uk_87 + 1575*uk_88 + 7875*uk_89 + 2242306609*uk_9 + 15120*uk_90 + 28035*uk_91 + 68355*uk_92 + 7875*uk_93 + 39375*uk_94 + 75600*uk_95 + 140175*uk_96 + 341775*uk_97 + 39375*uk_98 + 145152*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 275184*uk_100 + 656208*uk_101 + 15120*uk_102 + 521703*uk_103 + 1244061*uk_104 + 28665*uk_105 + 2966607*uk_106 + 68355*uk_107 + 1575*uk_108 + 35937*uk_109 + 1562649*uk_11 + 5445*uk_110 + 52272*uk_111 + 99099*uk_112 + 236313*uk_113 + 5445*uk_114 + 825*uk_115 + 7920*uk_116 + 15015*uk_117 + 35805*uk_118 + 825*uk_119 + 236765*uk_12 + 76032*uk_120 + 144144*uk_121 + 343728*uk_122 + 7920*uk_123 + 273273*uk_124 + 651651*uk_125 + 15015*uk_126 + 1553937*uk_127 + 35805*uk_128 + 825*uk_129 + 2272944*uk_13 + 125*uk_130 + 1200*uk_131 + 2275*uk_132 + 5425*uk_133 + 125*uk_134 + 11520*uk_135 + 21840*uk_136 + 52080*uk_137 + 1200*uk_138 + 41405*uk_139 + 4309123*uk_14 + 98735*uk_140 + 2275*uk_141 + 235445*uk_142 + 5425*uk_143 + 125*uk_144 + 110592*uk_145 + 209664*uk_146 + 499968*uk_147 + 11520*uk_148 + 397488*uk_149 + 10275601*uk_15 + 947856*uk_150 + 21840*uk_151 + 2260272*uk_152 + 52080*uk_153 + 1200*uk_154 + 753571*uk_155 + 1796977*uk_156 + 41405*uk_157 + 4285099*uk_158 + 98735*uk_159 + 236765*uk_16 + 2275*uk_160 + 10218313*uk_161 + 235445*uk_162 + 5425*uk_163 + 125*uk_164 + 3969*uk_17 + 2079*uk_18 + 315*uk_19 + 63*uk_2 + 3024*uk_20 + 5733*uk_21 + 13671*uk_22 + 315*uk_23 + 1089*uk_24 + 165*uk_25 + 1584*uk_26 + 3003*uk_27 + 7161*uk_28 + 165*uk_29 + 33*uk_3 + 25*uk_30 + 240*uk_31 + 455*uk_32 + 1085*uk_33 + 25*uk_34 + 2304*uk_35 + 4368*uk_36 + 10416*uk_37 + 240*uk_38 + 8281*uk_39 + 5*uk_4 + 19747*uk_40 + 455*uk_41 + 47089*uk_42 + 1085*uk_43 + 25*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 73996118097*uk_47 + 11211533045*uk_48 + 107630717232*uk_49 + 48*uk_5 + 204049901419*uk_50 + 486580534153*uk_51 + 11211533045*uk_52 + 187944057*uk_53 + 98446887*uk_54 + 14916195*uk_55 + 143195472*uk_56 + 271474749*uk_57 + 647362863*uk_58 + 14916195*uk_59 + 91*uk_6 + 51567417*uk_60 + 7813245*uk_61 + 75007152*uk_62 + 142201059*uk_63 + 339094833*uk_64 + 7813245*uk_65 + 1183825*uk_66 + 11364720*uk_67 + 21545615*uk_68 + 51378005*uk_69 + 217*uk_7 + 1183825*uk_70 + 109101312*uk_71 + 206837904*uk_72 + 493228848*uk_73 + 11364720*uk_74 + 392130193*uk_75 + 935079691*uk_76 + 21545615*uk_77 + 2229805417*uk_78 + 51378005*uk_79 + 5*uk_8 + 1183825*uk_80 + 250047*uk_81 + 130977*uk_82 + 19845*uk_83 + 190512*uk_84 + 361179*uk_85 + 861273*uk_86 + 19845*uk_87 + 68607*uk_88 + 10395*uk_89 + 2242306609*uk_9 + 99792*uk_90 + 189189*uk_91 + 451143*uk_92 + 10395*uk_93 + 1575*uk_94 + 15120*uk_95 + 28665*uk_96 + 68355*uk_97 + 1575*uk_98 + 145152*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 257796*uk_100 + 601524*uk_101 + 91476*uk_102 + 544887*uk_103 + 1271403*uk_104 + 193347*uk_105 + 2966607*uk_106 + 451143*uk_107 + 68607*uk_108 + 4096*uk_109 + 757648*uk_11 + 8448*uk_110 + 11264*uk_111 + 23808*uk_112 + 55552*uk_113 + 8448*uk_114 + 17424*uk_115 + 23232*uk_116 + 49104*uk_117 + 114576*uk_118 + 17424*uk_119 + 1562649*uk_12 + 30976*uk_120 + 65472*uk_121 + 152768*uk_122 + 23232*uk_123 + 138384*uk_124 + 322896*uk_125 + 49104*uk_126 + 753424*uk_127 + 114576*uk_128 + 17424*uk_129 + 2083532*uk_13 + 35937*uk_130 + 47916*uk_131 + 101277*uk_132 + 236313*uk_133 + 35937*uk_134 + 63888*uk_135 + 135036*uk_136 + 315084*uk_137 + 47916*uk_138 + 285417*uk_139 + 4403829*uk_14 + 665973*uk_140 + 101277*uk_141 + 1553937*uk_142 + 236313*uk_143 + 35937*uk_144 + 85184*uk_145 + 180048*uk_146 + 420112*uk_147 + 63888*uk_148 + 380556*uk_149 + 10275601*uk_15 + 887964*uk_150 + 135036*uk_151 + 2071916*uk_152 + 315084*uk_153 + 47916*uk_154 + 804357*uk_155 + 1876833*uk_156 + 285417*uk_157 + 4379277*uk_158 + 665973*uk_159 + 1562649*uk_16 + 101277*uk_160 + 10218313*uk_161 + 1553937*uk_162 + 236313*uk_163 + 35937*uk_164 + 3969*uk_17 + 1008*uk_18 + 2079*uk_19 + 63*uk_2 + 2772*uk_20 + 5859*uk_21 + 13671*uk_22 + 2079*uk_23 + 256*uk_24 + 528*uk_25 + 704*uk_26 + 1488*uk_27 + 3472*uk_28 + 528*uk_29 + 16*uk_3 + 1089*uk_30 + 1452*uk_31 + 3069*uk_32 + 7161*uk_33 + 1089*uk_34 + 1936*uk_35 + 4092*uk_36 + 9548*uk_37 + 1452*uk_38 + 8649*uk_39 + 33*uk_4 + 20181*uk_40 + 3069*uk_41 + 47089*uk_42 + 7161*uk_43 + 1089*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 35876905744*uk_47 + 73996118097*uk_48 + 98661490796*uk_49 + 44*uk_5 + 208534514637*uk_50 + 486580534153*uk_51 + 73996118097*uk_52 + 187944057*uk_53 + 47731824*uk_54 + 98446887*uk_55 + 131262516*uk_56 + 277441227*uk_57 + 647362863*uk_58 + 98446887*uk_59 + 93*uk_6 + 12122368*uk_60 + 25002384*uk_61 + 33336512*uk_62 + 70461264*uk_63 + 164409616*uk_64 + 25002384*uk_65 + 51567417*uk_66 + 68756556*uk_67 + 145326357*uk_68 + 339094833*uk_69 + 217*uk_7 + 51567417*uk_70 + 91675408*uk_71 + 193768476*uk_72 + 452126444*uk_73 + 68756556*uk_74 + 409556097*uk_75 + 955630893*uk_76 + 145326357*uk_77 + 2229805417*uk_78 + 339094833*uk_79 + 33*uk_8 + 51567417*uk_80 + 250047*uk_81 + 63504*uk_82 + 130977*uk_83 + 174636*uk_84 + 369117*uk_85 + 861273*uk_86 + 130977*uk_87 + 16128*uk_88 + 33264*uk_89 + 2242306609*uk_9 + 44352*uk_90 + 93744*uk_91 + 218736*uk_92 + 33264*uk_93 + 68607*uk_94 + 91476*uk_95 + 193347*uk_96 + 451143*uk_97 + 68607*uk_98 + 121968*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 263340*uk_100 + 601524*uk_101 + 44352*uk_102 + 568575*uk_103 + 1298745*uk_104 + 95760*uk_105 + 2966607*uk_106 + 218736*uk_107 + 16128*uk_108 + 79507*uk_109 + 2036179*uk_11 + 29584*uk_110 + 81356*uk_111 + 175655*uk_112 + 401233*uk_113 + 29584*uk_114 + 11008*uk_115 + 30272*uk_116 + 65360*uk_117 + 149296*uk_118 + 11008*uk_119 + 757648*uk_12 + 83248*uk_120 + 179740*uk_121 + 410564*uk_122 + 30272*uk_123 + 388075*uk_124 + 886445*uk_125 + 65360*uk_126 + 2024827*uk_127 + 149296*uk_128 + 11008*uk_129 + 2083532*uk_13 + 4096*uk_130 + 11264*uk_131 + 24320*uk_132 + 55552*uk_133 + 4096*uk_134 + 30976*uk_135 + 66880*uk_136 + 152768*uk_137 + 11264*uk_138 + 144400*uk_139 + 4498535*uk_14 + 329840*uk_140 + 24320*uk_141 + 753424*uk_142 + 55552*uk_143 + 4096*uk_144 + 85184*uk_145 + 183920*uk_146 + 420112*uk_147 + 30976*uk_148 + 397100*uk_149 + 10275601*uk_15 + 907060*uk_150 + 66880*uk_151 + 2071916*uk_152 + 152768*uk_153 + 11264*uk_154 + 857375*uk_155 + 1958425*uk_156 + 144400*uk_157 + 4473455*uk_158 + 329840*uk_159 + 757648*uk_16 + 24320*uk_160 + 10218313*uk_161 + 753424*uk_162 + 55552*uk_163 + 4096*uk_164 + 3969*uk_17 + 2709*uk_18 + 1008*uk_19 + 63*uk_2 + 2772*uk_20 + 5985*uk_21 + 13671*uk_22 + 1008*uk_23 + 1849*uk_24 + 688*uk_25 + 1892*uk_26 + 4085*uk_27 + 9331*uk_28 + 688*uk_29 + 43*uk_3 + 256*uk_30 + 704*uk_31 + 1520*uk_32 + 3472*uk_33 + 256*uk_34 + 1936*uk_35 + 4180*uk_36 + 9548*uk_37 + 704*uk_38 + 9025*uk_39 + 16*uk_4 + 20615*uk_40 + 1520*uk_41 + 47089*uk_42 + 3472*uk_43 + 256*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 96419184187*uk_47 + 35876905744*uk_48 + 98661490796*uk_49 + 44*uk_5 + 213019127855*uk_50 + 486580534153*uk_51 + 35876905744*uk_52 + 187944057*uk_53 + 128279277*uk_54 + 47731824*uk_55 + 131262516*uk_56 + 283407705*uk_57 + 647362863*uk_58 + 47731824*uk_59 + 95*uk_6 + 87555697*uk_60 + 32578864*uk_61 + 89591876*uk_62 + 193437005*uk_63 + 441850843*uk_64 + 32578864*uk_65 + 12122368*uk_66 + 33336512*uk_67 + 71976560*uk_68 + 164409616*uk_69 + 217*uk_7 + 12122368*uk_70 + 91675408*uk_71 + 197935540*uk_72 + 452126444*uk_73 + 33336512*uk_74 + 427360825*uk_75 + 976182095*uk_76 + 71976560*uk_77 + 2229805417*uk_78 + 164409616*uk_79 + 16*uk_8 + 12122368*uk_80 + 250047*uk_81 + 170667*uk_82 + 63504*uk_83 + 174636*uk_84 + 377055*uk_85 + 861273*uk_86 + 63504*uk_87 + 116487*uk_88 + 43344*uk_89 + 2242306609*uk_9 + 119196*uk_90 + 257355*uk_91 + 587853*uk_92 + 43344*uk_93 + 16128*uk_94 + 44352*uk_95 + 95760*uk_96 + 218736*uk_97 + 16128*uk_98 + 121968*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 244440*uk_100 + 546840*uk_101 + 108360*uk_102 + 592767*uk_103 + 1326087*uk_104 + 262773*uk_105 + 2966607*uk_106 + 587853*uk_107 + 116487*uk_108 + 4913*uk_109 + 805001*uk_11 + 12427*uk_110 + 11560*uk_111 + 28033*uk_112 + 62713*uk_113 + 12427*uk_114 + 31433*uk_115 + 29240*uk_116 + 70907*uk_117 + 158627*uk_118 + 31433*uk_119 + 2036179*uk_12 + 27200*uk_120 + 65960*uk_121 + 147560*uk_122 + 29240*uk_123 + 159953*uk_124 + 357833*uk_125 + 70907*uk_126 + 800513*uk_127 + 158627*uk_128 + 31433*uk_129 + 1894120*uk_13 + 79507*uk_130 + 73960*uk_131 + 179353*uk_132 + 401233*uk_133 + 79507*uk_134 + 68800*uk_135 + 166840*uk_136 + 373240*uk_137 + 73960*uk_138 + 404587*uk_139 + 4593241*uk_14 + 905107*uk_140 + 179353*uk_141 + 2024827*uk_142 + 401233*uk_143 + 79507*uk_144 + 64000*uk_145 + 155200*uk_146 + 347200*uk_147 + 68800*uk_148 + 376360*uk_149 + 10275601*uk_15 + 841960*uk_150 + 166840*uk_151 + 1883560*uk_152 + 373240*uk_153 + 73960*uk_154 + 912673*uk_155 + 2041753*uk_156 + 404587*uk_157 + 4567633*uk_158 + 905107*uk_159 + 2036179*uk_16 + 179353*uk_160 + 10218313*uk_161 + 2024827*uk_162 + 401233*uk_163 + 79507*uk_164 + 3969*uk_17 + 1071*uk_18 + 2709*uk_19 + 63*uk_2 + 2520*uk_20 + 6111*uk_21 + 13671*uk_22 + 2709*uk_23 + 289*uk_24 + 731*uk_25 + 680*uk_26 + 1649*uk_27 + 3689*uk_28 + 731*uk_29 + 17*uk_3 + 1849*uk_30 + 1720*uk_31 + 4171*uk_32 + 9331*uk_33 + 1849*uk_34 + 1600*uk_35 + 3880*uk_36 + 8680*uk_37 + 1720*uk_38 + 9409*uk_39 + 43*uk_4 + 21049*uk_40 + 4171*uk_41 + 47089*uk_42 + 9331*uk_43 + 1849*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 38119212353*uk_47 + 96419184187*uk_48 + 89692264360*uk_49 + 40*uk_5 + 217503741073*uk_50 + 486580534153*uk_51 + 96419184187*uk_52 + 187944057*uk_53 + 50715063*uk_54 + 128279277*uk_55 + 119329560*uk_56 + 289374183*uk_57 + 647362863*uk_58 + 128279277*uk_59 + 97*uk_6 + 13685017*uk_60 + 34615043*uk_61 + 32200040*uk_62 + 78085097*uk_63 + 174685217*uk_64 + 34615043*uk_65 + 87555697*uk_66 + 81447160*uk_67 + 197509363*uk_68 + 441850843*uk_69 + 217*uk_7 + 87555697*uk_70 + 75764800*uk_71 + 183729640*uk_72 + 411024040*uk_73 + 81447160*uk_74 + 445544377*uk_75 + 996733297*uk_76 + 197509363*uk_77 + 2229805417*uk_78 + 441850843*uk_79 + 43*uk_8 + 87555697*uk_80 + 250047*uk_81 + 67473*uk_82 + 170667*uk_83 + 158760*uk_84 + 384993*uk_85 + 861273*uk_86 + 170667*uk_87 + 18207*uk_88 + 46053*uk_89 + 2242306609*uk_9 + 42840*uk_90 + 103887*uk_91 + 232407*uk_92 + 46053*uk_93 + 116487*uk_94 + 108360*uk_95 + 262773*uk_96 + 587853*uk_97 + 116487*uk_98 + 100800*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 249480*uk_100 + 546840*uk_101 + 42840*uk_102 + 617463*uk_103 + 1353429*uk_104 + 106029*uk_105 + 2966607*uk_106 + 232407*uk_107 + 18207*uk_108 + 29791*uk_109 + 1467943*uk_11 + 16337*uk_110 + 38440*uk_111 + 95139*uk_112 + 208537*uk_113 + 16337*uk_114 + 8959*uk_115 + 21080*uk_116 + 52173*uk_117 + 114359*uk_118 + 8959*uk_119 + 805001*uk_12 + 49600*uk_120 + 122760*uk_121 + 269080*uk_122 + 21080*uk_123 + 303831*uk_124 + 665973*uk_125 + 52173*uk_126 + 1459759*uk_127 + 114359*uk_128 + 8959*uk_129 + 1894120*uk_13 + 4913*uk_130 + 11560*uk_131 + 28611*uk_132 + 62713*uk_133 + 4913*uk_134 + 27200*uk_135 + 67320*uk_136 + 147560*uk_137 + 11560*uk_138 + 166617*uk_139 + 4687947*uk_14 + 365211*uk_140 + 28611*uk_141 + 800513*uk_142 + 62713*uk_143 + 4913*uk_144 + 64000*uk_145 + 158400*uk_146 + 347200*uk_147 + 27200*uk_148 + 392040*uk_149 + 10275601*uk_15 + 859320*uk_150 + 67320*uk_151 + 1883560*uk_152 + 147560*uk_153 + 11560*uk_154 + 970299*uk_155 + 2126817*uk_156 + 166617*uk_157 + 4661811*uk_158 + 365211*uk_159 + 805001*uk_16 + 28611*uk_160 + 10218313*uk_161 + 800513*uk_162 + 62713*uk_163 + 4913*uk_164 + 3969*uk_17 + 1953*uk_18 + 1071*uk_19 + 63*uk_2 + 2520*uk_20 + 6237*uk_21 + 13671*uk_22 + 1071*uk_23 + 961*uk_24 + 527*uk_25 + 1240*uk_26 + 3069*uk_27 + 6727*uk_28 + 527*uk_29 + 31*uk_3 + 289*uk_30 + 680*uk_31 + 1683*uk_32 + 3689*uk_33 + 289*uk_34 + 1600*uk_35 + 3960*uk_36 + 8680*uk_37 + 680*uk_38 + 9801*uk_39 + 17*uk_4 + 21483*uk_40 + 1683*uk_41 + 47089*uk_42 + 3689*uk_43 + 289*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 69511504879*uk_47 + 38119212353*uk_48 + 89692264360*uk_49 + 40*uk_5 + 221988354291*uk_50 + 486580534153*uk_51 + 38119212353*uk_52 + 187944057*uk_53 + 92480409*uk_54 + 50715063*uk_55 + 119329560*uk_56 + 295340661*uk_57 + 647362863*uk_58 + 50715063*uk_59 + 99*uk_6 + 45506233*uk_60 + 24955031*uk_61 + 58717720*uk_62 + 145326357*uk_63 + 318543631*uk_64 + 24955031*uk_65 + 13685017*uk_66 + 32200040*uk_67 + 79695099*uk_68 + 174685217*uk_69 + 217*uk_7 + 13685017*uk_70 + 75764800*uk_71 + 187517880*uk_72 + 411024040*uk_73 + 32200040*uk_74 + 464106753*uk_75 + 1017284499*uk_76 + 79695099*uk_77 + 2229805417*uk_78 + 174685217*uk_79 + 17*uk_8 + 13685017*uk_80 + 250047*uk_81 + 123039*uk_82 + 67473*uk_83 + 158760*uk_84 + 392931*uk_85 + 861273*uk_86 + 67473*uk_87 + 60543*uk_88 + 33201*uk_89 + 2242306609*uk_9 + 78120*uk_90 + 193347*uk_91 + 423801*uk_92 + 33201*uk_93 + 18207*uk_94 + 42840*uk_95 + 106029*uk_96 + 232407*uk_97 + 18207*uk_98 + 100800*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 254520*uk_100 + 546840*uk_101 + 78120*uk_102 + 642663*uk_103 + 1380771*uk_104 + 197253*uk_105 + 2966607*uk_106 + 423801*uk_107 + 60543*uk_108 + 614125*uk_109 + 4025005*uk_11 + 223975*uk_110 + 289000*uk_111 + 729725*uk_112 + 1567825*uk_113 + 223975*uk_114 + 81685*uk_115 + 105400*uk_116 + 266135*uk_117 + 571795*uk_118 + 81685*uk_119 + 1467943*uk_12 + 136000*uk_120 + 343400*uk_121 + 737800*uk_122 + 105400*uk_123 + 867085*uk_124 + 1862945*uk_125 + 266135*uk_126 + 4002565*uk_127 + 571795*uk_128 + 81685*uk_129 + 1894120*uk_13 + 29791*uk_130 + 38440*uk_131 + 97061*uk_132 + 208537*uk_133 + 29791*uk_134 + 49600*uk_135 + 125240*uk_136 + 269080*uk_137 + 38440*uk_138 + 316231*uk_139 + 4782653*uk_14 + 679427*uk_140 + 97061*uk_141 + 1459759*uk_142 + 208537*uk_143 + 29791*uk_144 + 64000*uk_145 + 161600*uk_146 + 347200*uk_147 + 49600*uk_148 + 408040*uk_149 + 10275601*uk_15 + 876680*uk_150 + 125240*uk_151 + 1883560*uk_152 + 269080*uk_153 + 38440*uk_154 + 1030301*uk_155 + 2213617*uk_156 + 316231*uk_157 + 4755989*uk_158 + 679427*uk_159 + 1467943*uk_16 + 97061*uk_160 + 10218313*uk_161 + 1459759*uk_162 + 208537*uk_163 + 29791*uk_164 + 3969*uk_17 + 5355*uk_18 + 1953*uk_19 + 63*uk_2 + 2520*uk_20 + 6363*uk_21 + 13671*uk_22 + 1953*uk_23 + 7225*uk_24 + 2635*uk_25 + 3400*uk_26 + 8585*uk_27 + 18445*uk_28 + 2635*uk_29 + 85*uk_3 + 961*uk_30 + 1240*uk_31 + 3131*uk_32 + 6727*uk_33 + 961*uk_34 + 1600*uk_35 + 4040*uk_36 + 8680*uk_37 + 1240*uk_38 + 10201*uk_39 + 31*uk_4 + 21917*uk_40 + 3131*uk_41 + 47089*uk_42 + 6727*uk_43 + 961*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 190596061765*uk_47 + 69511504879*uk_48 + 89692264360*uk_49 + 40*uk_5 + 226472967509*uk_50 + 486580534153*uk_51 + 69511504879*uk_52 + 187944057*uk_53 + 253575315*uk_54 + 92480409*uk_55 + 119329560*uk_56 + 301307139*uk_57 + 647362863*uk_58 + 92480409*uk_59 + 101*uk_6 + 342125425*uk_60 + 124775155*uk_61 + 161000200*uk_62 + 406525505*uk_63 + 873426085*uk_64 + 124775155*uk_65 + 45506233*uk_66 + 58717720*uk_67 + 148262243*uk_68 + 318543631*uk_69 + 217*uk_7 + 45506233*uk_70 + 75764800*uk_71 + 191306120*uk_72 + 411024040*uk_73 + 58717720*uk_74 + 483047953*uk_75 + 1037835701*uk_76 + 148262243*uk_77 + 2229805417*uk_78 + 318543631*uk_79 + 31*uk_8 + 45506233*uk_80 + 250047*uk_81 + 337365*uk_82 + 123039*uk_83 + 158760*uk_84 + 400869*uk_85 + 861273*uk_86 + 123039*uk_87 + 455175*uk_88 + 166005*uk_89 + 2242306609*uk_9 + 214200*uk_90 + 540855*uk_91 + 1162035*uk_92 + 166005*uk_93 + 60543*uk_94 + 78120*uk_95 + 197253*uk_96 + 423801*uk_97 + 60543*uk_98 + 100800*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 233604*uk_100 + 492156*uk_101 + 192780*uk_102 + 668367*uk_103 + 1408113*uk_104 + 551565*uk_105 + 2966607*uk_106 + 1162035*uk_107 + 455175*uk_108 + 438976*uk_109 + 3598828*uk_11 + 490960*uk_110 + 207936*uk_111 + 594928*uk_112 + 1253392*uk_113 + 490960*uk_114 + 549100*uk_115 + 232560*uk_116 + 665380*uk_117 + 1401820*uk_118 + 549100*uk_119 + 4025005*uk_12 + 98496*uk_120 + 281808*uk_121 + 593712*uk_122 + 232560*uk_123 + 806284*uk_124 + 1698676*uk_125 + 665380*uk_126 + 3578764*uk_127 + 1401820*uk_128 + 549100*uk_129 + 1704708*uk_13 + 614125*uk_130 + 260100*uk_131 + 744175*uk_132 + 1567825*uk_133 + 614125*uk_134 + 110160*uk_135 + 315180*uk_136 + 664020*uk_137 + 260100*uk_138 + 901765*uk_139 + 4877359*uk_14 + 1899835*uk_140 + 744175*uk_141 + 4002565*uk_142 + 1567825*uk_143 + 614125*uk_144 + 46656*uk_145 + 133488*uk_146 + 281232*uk_147 + 110160*uk_148 + 381924*uk_149 + 10275601*uk_15 + 804636*uk_150 + 315180*uk_151 + 1695204*uk_152 + 664020*uk_153 + 260100*uk_154 + 1092727*uk_155 + 2302153*uk_156 + 901765*uk_157 + 4850167*uk_158 + 1899835*uk_159 + 4025005*uk_16 + 744175*uk_160 + 10218313*uk_161 + 4002565*uk_162 + 1567825*uk_163 + 614125*uk_164 + 3969*uk_17 + 4788*uk_18 + 5355*uk_19 + 63*uk_2 + 2268*uk_20 + 6489*uk_21 + 13671*uk_22 + 5355*uk_23 + 5776*uk_24 + 6460*uk_25 + 2736*uk_26 + 7828*uk_27 + 16492*uk_28 + 6460*uk_29 + 76*uk_3 + 7225*uk_30 + 3060*uk_31 + 8755*uk_32 + 18445*uk_33 + 7225*uk_34 + 1296*uk_35 + 3708*uk_36 + 7812*uk_37 + 3060*uk_38 + 10609*uk_39 + 85*uk_4 + 22351*uk_40 + 8755*uk_41 + 47089*uk_42 + 18445*uk_43 + 7225*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 170415302284*uk_47 + 190596061765*uk_48 + 80723037924*uk_49 + 36*uk_5 + 230957580727*uk_50 + 486580534153*uk_51 + 190596061765*uk_52 + 187944057*uk_53 + 226726164*uk_54 + 253575315*uk_55 + 107396604*uk_56 + 307273617*uk_57 + 647362863*uk_58 + 253575315*uk_59 + 103*uk_6 + 273510928*uk_60 + 305900380*uk_61 + 129557808*uk_62 + 370679284*uk_63 + 780945676*uk_64 + 305900380*uk_65 + 342125425*uk_66 + 144900180*uk_67 + 414575515*uk_68 + 873426085*uk_69 + 217*uk_7 + 342125425*uk_70 + 61369488*uk_71 + 175584924*uk_72 + 369921636*uk_73 + 144900180*uk_74 + 502367977*uk_75 + 1058386903*uk_76 + 414575515*uk_77 + 2229805417*uk_78 + 873426085*uk_79 + 85*uk_8 + 342125425*uk_80 + 250047*uk_81 + 301644*uk_82 + 337365*uk_83 + 142884*uk_84 + 408807*uk_85 + 861273*uk_86 + 337365*uk_87 + 363888*uk_88 + 406980*uk_89 + 2242306609*uk_9 + 172368*uk_90 + 493164*uk_91 + 1038996*uk_92 + 406980*uk_93 + 455175*uk_94 + 192780*uk_95 + 551565*uk_96 + 1162035*uk_97 + 455175*uk_98 + 81648*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 238140*uk_100 + 492156*uk_101 + 172368*uk_102 + 694575*uk_103 + 1435455*uk_104 + 502740*uk_105 + 2966607*uk_106 + 1038996*uk_107 + 363888*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 806284*uk_110 + 381924*uk_111 + 1113945*uk_112 + 2302153*uk_113 + 806284*uk_114 + 594928*uk_115 + 281808*uk_116 + 821940*uk_117 + 1698676*uk_118 + 594928*uk_119 + 3598828*uk_12 + 133488*uk_120 + 389340*uk_121 + 804636*uk_122 + 281808*uk_123 + 1135575*uk_124 + 2346855*uk_125 + 821940*uk_126 + 4850167*uk_127 + 1698676*uk_128 + 594928*uk_129 + 1704708*uk_13 + 438976*uk_130 + 207936*uk_131 + 606480*uk_132 + 1253392*uk_133 + 438976*uk_134 + 98496*uk_135 + 287280*uk_136 + 593712*uk_137 + 207936*uk_138 + 837900*uk_139 + 4972065*uk_14 + 1731660*uk_140 + 606480*uk_141 + 3578764*uk_142 + 1253392*uk_143 + 438976*uk_144 + 46656*uk_145 + 136080*uk_146 + 281232*uk_147 + 98496*uk_148 + 396900*uk_149 + 10275601*uk_15 + 820260*uk_150 + 287280*uk_151 + 1695204*uk_152 + 593712*uk_153 + 207936*uk_154 + 1157625*uk_155 + 2392425*uk_156 + 837900*uk_157 + 4944345*uk_158 + 1731660*uk_159 + 3598828*uk_16 + 606480*uk_160 + 10218313*uk_161 + 3578764*uk_162 + 1253392*uk_163 + 438976*uk_164 + 3969*uk_17 + 6489*uk_18 + 4788*uk_19 + 63*uk_2 + 2268*uk_20 + 6615*uk_21 + 13671*uk_22 + 4788*uk_23 + 10609*uk_24 + 7828*uk_25 + 3708*uk_26 + 10815*uk_27 + 22351*uk_28 + 7828*uk_29 + 103*uk_3 + 5776*uk_30 + 2736*uk_31 + 7980*uk_32 + 16492*uk_33 + 5776*uk_34 + 1296*uk_35 + 3780*uk_36 + 7812*uk_37 + 2736*uk_38 + 11025*uk_39 + 76*uk_4 + 22785*uk_40 + 7980*uk_41 + 47089*uk_42 + 16492*uk_43 + 5776*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 170415302284*uk_48 + 80723037924*uk_49 + 36*uk_5 + 235442193945*uk_50 + 486580534153*uk_51 + 170415302284*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 226726164*uk_55 + 107396604*uk_56 + 313240095*uk_57 + 647362863*uk_58 + 226726164*uk_59 + 105*uk_6 + 502367977*uk_60 + 370679284*uk_61 + 175584924*uk_62 + 512122695*uk_63 + 1058386903*uk_64 + 370679284*uk_65 + 273510928*uk_66 + 129557808*uk_67 + 377876940*uk_68 + 780945676*uk_69 + 217*uk_7 + 273510928*uk_70 + 61369488*uk_71 + 178994340*uk_72 + 369921636*uk_73 + 129557808*uk_74 + 522066825*uk_75 + 1078938105*uk_76 + 377876940*uk_77 + 2229805417*uk_78 + 780945676*uk_79 + 76*uk_8 + 273510928*uk_80 + 250047*uk_81 + 408807*uk_82 + 301644*uk_83 + 142884*uk_84 + 416745*uk_85 + 861273*uk_86 + 301644*uk_87 + 668367*uk_88 + 493164*uk_89 + 2242306609*uk_9 + 233604*uk_90 + 681345*uk_91 + 1408113*uk_92 + 493164*uk_93 + 363888*uk_94 + 172368*uk_95 + 502740*uk_96 + 1038996*uk_97 + 363888*uk_98 + 81648*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 215712*uk_100 + 437472*uk_101 + 207648*uk_102 + 721287*uk_103 + 1462797*uk_104 + 694323*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 205379*uk_109 + 2793827*uk_11 + 358543*uk_110 + 111392*uk_111 + 372467*uk_112 + 755377*uk_113 + 358543*uk_114 + 625931*uk_115 + 194464*uk_116 + 650239*uk_117 + 1318709*uk_118 + 625931*uk_119 + 4877359*uk_12 + 60416*uk_120 + 202016*uk_121 + 409696*uk_122 + 194464*uk_123 + 675491*uk_124 + 1369921*uk_125 + 650239*uk_126 + 2778251*uk_127 + 1318709*uk_128 + 625931*uk_129 + 1515296*uk_13 + 1092727*uk_130 + 339488*uk_131 + 1135163*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 105472*uk_135 + 352672*uk_136 + 715232*uk_137 + 339488*uk_138 + 1179247*uk_139 + 5066771*uk_14 + 2391557*uk_140 + 1135163*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 32768*uk_145 + 109568*uk_146 + 222208*uk_147 + 105472*uk_148 + 366368*uk_149 + 10275601*uk_15 + 743008*uk_150 + 352672*uk_151 + 1506848*uk_152 + 715232*uk_153 + 339488*uk_154 + 1225043*uk_155 + 2484433*uk_156 + 1179247*uk_157 + 5038523*uk_158 + 2391557*uk_159 + 4877359*uk_16 + 1135163*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 3717*uk_18 + 6489*uk_19 + 63*uk_2 + 2016*uk_20 + 6741*uk_21 + 13671*uk_22 + 6489*uk_23 + 3481*uk_24 + 6077*uk_25 + 1888*uk_26 + 6313*uk_27 + 12803*uk_28 + 6077*uk_29 + 59*uk_3 + 10609*uk_30 + 3296*uk_31 + 11021*uk_32 + 22351*uk_33 + 10609*uk_34 + 1024*uk_35 + 3424*uk_36 + 6944*uk_37 + 3296*uk_38 + 11449*uk_39 + 103*uk_4 + 23219*uk_40 + 11021*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 132296089931*uk_47 + 230957580727*uk_48 + 71753811488*uk_49 + 32*uk_5 + 239926807163*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 176011101*uk_54 + 307273617*uk_55 + 95463648*uk_56 + 319206573*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 107*uk_6 + 164835793*uk_60 + 287764181*uk_61 + 89402464*uk_62 + 298939489*uk_63 + 606260459*uk_64 + 287764181*uk_65 + 502367977*uk_66 + 156075488*uk_67 + 521877413*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 48489472*uk_71 + 162136672*uk_72 + 328819232*uk_73 + 156075488*uk_74 + 542144497*uk_75 + 1099489307*uk_76 + 521877413*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 234171*uk_82 + 408807*uk_83 + 127008*uk_84 + 424683*uk_85 + 861273*uk_86 + 408807*uk_87 + 219303*uk_88 + 382851*uk_89 + 2242306609*uk_9 + 118944*uk_90 + 397719*uk_91 + 806589*uk_92 + 382851*uk_93 + 668367*uk_94 + 207648*uk_95 + 694323*uk_96 + 1408113*uk_97 + 668367*uk_98 + 64512*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 219744*uk_100 + 437472*uk_101 + 118944*uk_102 + 748503*uk_103 + 1490139*uk_104 + 405153*uk_105 + 2966607*uk_106 + 806589*uk_107 + 219303*uk_108 + 103823*uk_109 + 2225591*uk_11 + 130331*uk_110 + 70688*uk_111 + 240781*uk_112 + 479353*uk_113 + 130331*uk_114 + 163607*uk_115 + 88736*uk_116 + 302257*uk_117 + 601741*uk_118 + 163607*uk_119 + 2793827*uk_12 + 48128*uk_120 + 163936*uk_121 + 326368*uk_122 + 88736*uk_123 + 558407*uk_124 + 1111691*uk_125 + 302257*uk_126 + 2213183*uk_127 + 601741*uk_128 + 163607*uk_129 + 1515296*uk_13 + 205379*uk_130 + 111392*uk_131 + 379429*uk_132 + 755377*uk_133 + 205379*uk_134 + 60416*uk_135 + 205792*uk_136 + 409696*uk_137 + 111392*uk_138 + 700979*uk_139 + 5161477*uk_14 + 1395527*uk_140 + 379429*uk_141 + 2778251*uk_142 + 755377*uk_143 + 205379*uk_144 + 32768*uk_145 + 111616*uk_146 + 222208*uk_147 + 60416*uk_148 + 380192*uk_149 + 10275601*uk_15 + 756896*uk_150 + 205792*uk_151 + 1506848*uk_152 + 409696*uk_153 + 111392*uk_154 + 1295029*uk_155 + 2578177*uk_156 + 700979*uk_157 + 5132701*uk_158 + 1395527*uk_159 + 2793827*uk_16 + 379429*uk_160 + 10218313*uk_161 + 2778251*uk_162 + 755377*uk_163 + 205379*uk_164 + 3969*uk_17 + 2961*uk_18 + 3717*uk_19 + 63*uk_2 + 2016*uk_20 + 6867*uk_21 + 13671*uk_22 + 3717*uk_23 + 2209*uk_24 + 2773*uk_25 + 1504*uk_26 + 5123*uk_27 + 10199*uk_28 + 2773*uk_29 + 47*uk_3 + 3481*uk_30 + 1888*uk_31 + 6431*uk_32 + 12803*uk_33 + 3481*uk_34 + 1024*uk_35 + 3488*uk_36 + 6944*uk_37 + 1888*uk_38 + 11881*uk_39 + 59*uk_4 + 23653*uk_40 + 6431*uk_41 + 47089*uk_42 + 12803*uk_43 + 3481*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 105388410623*uk_47 + 132296089931*uk_48 + 71753811488*uk_49 + 32*uk_5 + 244411420381*uk_50 + 486580534153*uk_51 + 132296089931*uk_52 + 187944057*uk_53 + 140212233*uk_54 + 176011101*uk_55 + 95463648*uk_56 + 325173051*uk_57 + 647362863*uk_58 + 176011101*uk_59 + 109*uk_6 + 104602777*uk_60 + 131309869*uk_61 + 71218912*uk_62 + 242589419*uk_63 + 482953247*uk_64 + 131309869*uk_65 + 164835793*uk_66 + 89402464*uk_67 + 304527143*uk_68 + 606260459*uk_69 + 217*uk_7 + 164835793*uk_70 + 48489472*uk_71 + 165167264*uk_72 + 328819232*uk_73 + 89402464*uk_74 + 562600993*uk_75 + 1120040509*uk_76 + 304527143*uk_77 + 2229805417*uk_78 + 606260459*uk_79 + 59*uk_8 + 164835793*uk_80 + 250047*uk_81 + 186543*uk_82 + 234171*uk_83 + 127008*uk_84 + 432621*uk_85 + 861273*uk_86 + 234171*uk_87 + 139167*uk_88 + 174699*uk_89 + 2242306609*uk_9 + 94752*uk_90 + 322749*uk_91 + 642537*uk_92 + 174699*uk_93 + 219303*uk_94 + 118944*uk_95 + 405153*uk_96 + 806589*uk_97 + 219303*uk_98 + 64512*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 223776*uk_100 + 437472*uk_101 + 94752*uk_102 + 776223*uk_103 + 1517481*uk_104 + 328671*uk_105 + 2966607*uk_106 + 642537*uk_107 + 139167*uk_108 + 300763*uk_109 + 3172651*uk_11 + 210983*uk_110 + 143648*uk_111 + 498279*uk_112 + 974113*uk_113 + 210983*uk_114 + 148003*uk_115 + 100768*uk_116 + 349539*uk_117 + 683333*uk_118 + 148003*uk_119 + 2225591*uk_12 + 68608*uk_120 + 237984*uk_121 + 465248*uk_122 + 100768*uk_123 + 825507*uk_124 + 1613829*uk_125 + 349539*uk_126 + 3154963*uk_127 + 683333*uk_128 + 148003*uk_129 + 1515296*uk_13 + 103823*uk_130 + 70688*uk_131 + 245199*uk_132 + 479353*uk_133 + 103823*uk_134 + 48128*uk_135 + 166944*uk_136 + 326368*uk_137 + 70688*uk_138 + 579087*uk_139 + 5256183*uk_14 + 1132089*uk_140 + 245199*uk_141 + 2213183*uk_142 + 479353*uk_143 + 103823*uk_144 + 32768*uk_145 + 113664*uk_146 + 222208*uk_147 + 48128*uk_148 + 394272*uk_149 + 10275601*uk_15 + 770784*uk_150 + 166944*uk_151 + 1506848*uk_152 + 326368*uk_153 + 70688*uk_154 + 1367631*uk_155 + 2673657*uk_156 + 579087*uk_157 + 5226879*uk_158 + 1132089*uk_159 + 2225591*uk_16 + 245199*uk_160 + 10218313*uk_161 + 2213183*uk_162 + 479353*uk_163 + 103823*uk_164 + 3969*uk_17 + 4221*uk_18 + 2961*uk_19 + 63*uk_2 + 2016*uk_20 + 6993*uk_21 + 13671*uk_22 + 2961*uk_23 + 4489*uk_24 + 3149*uk_25 + 2144*uk_26 + 7437*uk_27 + 14539*uk_28 + 3149*uk_29 + 67*uk_3 + 2209*uk_30 + 1504*uk_31 + 5217*uk_32 + 10199*uk_33 + 2209*uk_34 + 1024*uk_35 + 3552*uk_36 + 6944*uk_37 + 1504*uk_38 + 12321*uk_39 + 47*uk_4 + 24087*uk_40 + 5217*uk_41 + 47089*uk_42 + 10199*uk_43 + 2209*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 150234542803*uk_47 + 105388410623*uk_48 + 71753811488*uk_49 + 32*uk_5 + 248896033599*uk_50 + 486580534153*uk_51 + 105388410623*uk_52 + 187944057*uk_53 + 199877013*uk_54 + 140212233*uk_55 + 95463648*uk_56 + 331139529*uk_57 + 647362863*uk_58 + 140212233*uk_59 + 111*uk_6 + 212567617*uk_60 + 149114597*uk_61 + 101524832*uk_62 + 352164261*uk_63 + 688465267*uk_64 + 149114597*uk_65 + 104602777*uk_66 + 71218912*uk_67 + 247040601*uk_68 + 482953247*uk_69 + 217*uk_7 + 104602777*uk_70 + 48489472*uk_71 + 168197856*uk_72 + 328819232*uk_73 + 71218912*uk_74 + 583436313*uk_75 + 1140591711*uk_76 + 247040601*uk_77 + 2229805417*uk_78 + 482953247*uk_79 + 47*uk_8 + 104602777*uk_80 + 250047*uk_81 + 265923*uk_82 + 186543*uk_83 + 127008*uk_84 + 440559*uk_85 + 861273*uk_86 + 186543*uk_87 + 282807*uk_88 + 198387*uk_89 + 2242306609*uk_9 + 135072*uk_90 + 468531*uk_91 + 915957*uk_92 + 198387*uk_93 + 139167*uk_94 + 94752*uk_95 + 328671*uk_96 + 642537*uk_97 + 139167*uk_98 + 64512*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 199332*uk_100 + 382788*uk_101 + 118188*uk_102 + 804447*uk_103 + 1544823*uk_104 + 476973*uk_105 + 2966607*uk_106 + 915957*uk_107 + 282807*uk_108 + 216*uk_109 + 284118*uk_11 + 2412*uk_110 + 1008*uk_111 + 4068*uk_112 + 7812*uk_113 + 2412*uk_114 + 26934*uk_115 + 11256*uk_116 + 45426*uk_117 + 87234*uk_118 + 26934*uk_119 + 3172651*uk_12 + 4704*uk_120 + 18984*uk_121 + 36456*uk_122 + 11256*uk_123 + 76614*uk_124 + 147126*uk_125 + 45426*uk_126 + 282534*uk_127 + 87234*uk_128 + 26934*uk_129 + 1325884*uk_13 + 300763*uk_130 + 125692*uk_131 + 507257*uk_132 + 974113*uk_133 + 300763*uk_134 + 52528*uk_135 + 211988*uk_136 + 407092*uk_137 + 125692*uk_138 + 855523*uk_139 + 5350889*uk_14 + 1642907*uk_140 + 507257*uk_141 + 3154963*uk_142 + 974113*uk_143 + 300763*uk_144 + 21952*uk_145 + 88592*uk_146 + 170128*uk_147 + 52528*uk_148 + 357532*uk_149 + 10275601*uk_15 + 686588*uk_150 + 211988*uk_151 + 1318492*uk_152 + 407092*uk_153 + 125692*uk_154 + 1442897*uk_155 + 2770873*uk_156 + 855523*uk_157 + 5321057*uk_158 + 1642907*uk_159 + 3172651*uk_16 + 507257*uk_160 + 10218313*uk_161 + 3154963*uk_162 + 974113*uk_163 + 300763*uk_164 + 3969*uk_17 + 378*uk_18 + 4221*uk_19 + 63*uk_2 + 1764*uk_20 + 7119*uk_21 + 13671*uk_22 + 4221*uk_23 + 36*uk_24 + 402*uk_25 + 168*uk_26 + 678*uk_27 + 1302*uk_28 + 402*uk_29 + 6*uk_3 + 4489*uk_30 + 1876*uk_31 + 7571*uk_32 + 14539*uk_33 + 4489*uk_34 + 784*uk_35 + 3164*uk_36 + 6076*uk_37 + 1876*uk_38 + 12769*uk_39 + 67*uk_4 + 24521*uk_40 + 7571*uk_41 + 47089*uk_42 + 14539*uk_43 + 4489*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 13453839654*uk_47 + 150234542803*uk_48 + 62784585052*uk_49 + 28*uk_5 + 253380646817*uk_50 + 486580534153*uk_51 + 150234542803*uk_52 + 187944057*uk_53 + 17899434*uk_54 + 199877013*uk_55 + 83530692*uk_56 + 337106007*uk_57 + 647362863*uk_58 + 199877013*uk_59 + 113*uk_6 + 1704708*uk_60 + 19035906*uk_61 + 7955304*uk_62 + 32105334*uk_63 + 61653606*uk_64 + 19035906*uk_65 + 212567617*uk_66 + 88834228*uk_67 + 358509563*uk_68 + 688465267*uk_69 + 217*uk_7 + 212567617*uk_70 + 37124752*uk_71 + 149824892*uk_72 + 287716828*uk_73 + 88834228*uk_74 + 604650457*uk_75 + 1161142913*uk_76 + 358509563*uk_77 + 2229805417*uk_78 + 688465267*uk_79 + 67*uk_8 + 212567617*uk_80 + 250047*uk_81 + 23814*uk_82 + 265923*uk_83 + 111132*uk_84 + 448497*uk_85 + 861273*uk_86 + 265923*uk_87 + 2268*uk_88 + 25326*uk_89 + 2242306609*uk_9 + 10584*uk_90 + 42714*uk_91 + 82026*uk_92 + 25326*uk_93 + 282807*uk_94 + 118188*uk_95 + 476973*uk_96 + 915957*uk_97 + 282807*uk_98 + 49392*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 231840*uk_100 + 437472*uk_101 + 12096*uk_102 + 833175*uk_103 + 1572165*uk_104 + 43470*uk_105 + 2966607*uk_106 + 82026*uk_107 + 2268*uk_108 + 681472*uk_109 + 4167064*uk_11 + 46464*uk_110 + 247808*uk_111 + 890560*uk_112 + 1680448*uk_113 + 46464*uk_114 + 3168*uk_115 + 16896*uk_116 + 60720*uk_117 + 114576*uk_118 + 3168*uk_119 + 284118*uk_12 + 90112*uk_120 + 323840*uk_121 + 611072*uk_122 + 16896*uk_123 + 1163800*uk_124 + 2196040*uk_125 + 60720*uk_126 + 4143832*uk_127 + 114576*uk_128 + 3168*uk_129 + 1515296*uk_13 + 216*uk_130 + 1152*uk_131 + 4140*uk_132 + 7812*uk_133 + 216*uk_134 + 6144*uk_135 + 22080*uk_136 + 41664*uk_137 + 1152*uk_138 + 79350*uk_139 + 5445595*uk_14 + 149730*uk_140 + 4140*uk_141 + 282534*uk_142 + 7812*uk_143 + 216*uk_144 + 32768*uk_145 + 117760*uk_146 + 222208*uk_147 + 6144*uk_148 + 423200*uk_149 + 10275601*uk_15 + 798560*uk_150 + 22080*uk_151 + 1506848*uk_152 + 41664*uk_153 + 1152*uk_154 + 1520875*uk_155 + 2869825*uk_156 + 79350*uk_157 + 5415235*uk_158 + 149730*uk_159 + 284118*uk_16 + 4140*uk_160 + 10218313*uk_161 + 282534*uk_162 + 7812*uk_163 + 216*uk_164 + 3969*uk_17 + 5544*uk_18 + 378*uk_19 + 63*uk_2 + 2016*uk_20 + 7245*uk_21 + 13671*uk_22 + 378*uk_23 + 7744*uk_24 + 528*uk_25 + 2816*uk_26 + 10120*uk_27 + 19096*uk_28 + 528*uk_29 + 88*uk_3 + 36*uk_30 + 192*uk_31 + 690*uk_32 + 1302*uk_33 + 36*uk_34 + 1024*uk_35 + 3680*uk_36 + 6944*uk_37 + 192*uk_38 + 13225*uk_39 + 6*uk_4 + 24955*uk_40 + 690*uk_41 + 47089*uk_42 + 1302*uk_43 + 36*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 197322981592*uk_47 + 13453839654*uk_48 + 71753811488*uk_49 + 32*uk_5 + 257865260035*uk_50 + 486580534153*uk_51 + 13453839654*uk_52 + 187944057*uk_53 + 262525032*uk_54 + 17899434*uk_55 + 95463648*uk_56 + 343072485*uk_57 + 647362863*uk_58 + 17899434*uk_59 + 115*uk_6 + 366701632*uk_60 + 25002384*uk_61 + 133346048*uk_62 + 479212360*uk_63 + 904252888*uk_64 + 25002384*uk_65 + 1704708*uk_66 + 9091776*uk_67 + 32673570*uk_68 + 61653606*uk_69 + 217*uk_7 + 1704708*uk_70 + 48489472*uk_71 + 174259040*uk_72 + 328819232*uk_73 + 9091776*uk_74 + 626243425*uk_75 + 1181694115*uk_76 + 32673570*uk_77 + 2229805417*uk_78 + 61653606*uk_79 + 6*uk_8 + 1704708*uk_80 + 250047*uk_81 + 349272*uk_82 + 23814*uk_83 + 127008*uk_84 + 456435*uk_85 + 861273*uk_86 + 23814*uk_87 + 487872*uk_88 + 33264*uk_89 + 2242306609*uk_9 + 177408*uk_90 + 637560*uk_91 + 1203048*uk_92 + 33264*uk_93 + 2268*uk_94 + 12096*uk_95 + 43470*uk_96 + 82026*uk_97 + 2268*uk_98 + 64512*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 206388*uk_100 + 382788*uk_101 + 155232*uk_102 + 862407*uk_103 + 1599507*uk_104 + 648648*uk_105 + 2966607*uk_106 + 1203048*uk_107 + 487872*uk_108 + 614125*uk_109 + 4025005*uk_11 + 635800*uk_110 + 202300*uk_111 + 845325*uk_112 + 1567825*uk_113 + 635800*uk_114 + 658240*uk_115 + 209440*uk_116 + 875160*uk_117 + 1623160*uk_118 + 658240*uk_119 + 4167064*uk_12 + 66640*uk_120 + 278460*uk_121 + 516460*uk_122 + 209440*uk_123 + 1163565*uk_124 + 2158065*uk_125 + 875160*uk_126 + 4002565*uk_127 + 1623160*uk_128 + 658240*uk_129 + 1325884*uk_13 + 681472*uk_130 + 216832*uk_131 + 906048*uk_132 + 1680448*uk_133 + 681472*uk_134 + 68992*uk_135 + 288288*uk_136 + 534688*uk_137 + 216832*uk_138 + 1204632*uk_139 + 5540301*uk_14 + 2234232*uk_140 + 906048*uk_141 + 4143832*uk_142 + 1680448*uk_143 + 681472*uk_144 + 21952*uk_145 + 91728*uk_146 + 170128*uk_147 + 68992*uk_148 + 383292*uk_149 + 10275601*uk_15 + 710892*uk_150 + 288288*uk_151 + 1318492*uk_152 + 534688*uk_153 + 216832*uk_154 + 1601613*uk_155 + 2970513*uk_156 + 1204632*uk_157 + 5509413*uk_158 + 2234232*uk_159 + 4167064*uk_16 + 906048*uk_160 + 10218313*uk_161 + 4143832*uk_162 + 1680448*uk_163 + 681472*uk_164 + 3969*uk_17 + 5355*uk_18 + 5544*uk_19 + 63*uk_2 + 1764*uk_20 + 7371*uk_21 + 13671*uk_22 + 5544*uk_23 + 7225*uk_24 + 7480*uk_25 + 2380*uk_26 + 9945*uk_27 + 18445*uk_28 + 7480*uk_29 + 85*uk_3 + 7744*uk_30 + 2464*uk_31 + 10296*uk_32 + 19096*uk_33 + 7744*uk_34 + 784*uk_35 + 3276*uk_36 + 6076*uk_37 + 2464*uk_38 + 13689*uk_39 + 88*uk_4 + 25389*uk_40 + 10296*uk_41 + 47089*uk_42 + 19096*uk_43 + 7744*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 190596061765*uk_47 + 197322981592*uk_48 + 62784585052*uk_49 + 28*uk_5 + 262349873253*uk_50 + 486580534153*uk_51 + 197322981592*uk_52 + 187944057*uk_53 + 253575315*uk_54 + 262525032*uk_55 + 83530692*uk_56 + 349038963*uk_57 + 647362863*uk_58 + 262525032*uk_59 + 117*uk_6 + 342125425*uk_60 + 354200440*uk_61 + 112700140*uk_62 + 470925585*uk_63 + 873426085*uk_64 + 354200440*uk_65 + 366701632*uk_66 + 116677792*uk_67 + 487546488*uk_68 + 904252888*uk_69 + 217*uk_7 + 366701632*uk_70 + 37124752*uk_71 + 155128428*uk_72 + 287716828*uk_73 + 116677792*uk_74 + 648215217*uk_75 + 1202245317*uk_76 + 487546488*uk_77 + 2229805417*uk_78 + 904252888*uk_79 + 88*uk_8 + 366701632*uk_80 + 250047*uk_81 + 337365*uk_82 + 349272*uk_83 + 111132*uk_84 + 464373*uk_85 + 861273*uk_86 + 349272*uk_87 + 455175*uk_88 + 471240*uk_89 + 2242306609*uk_9 + 149940*uk_90 + 626535*uk_91 + 1162035*uk_92 + 471240*uk_93 + 487872*uk_94 + 155232*uk_95 + 648648*uk_96 + 1203048*uk_97 + 487872*uk_98 + 49392*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 209916*uk_100 + 382788*uk_101 + 149940*uk_102 + 892143*uk_103 + 1626849*uk_104 + 637245*uk_105 + 2966607*uk_106 + 1162035*uk_107 + 455175*uk_108 + 1331000*uk_109 + 5208830*uk_11 + 1028500*uk_110 + 338800*uk_111 + 1439900*uk_112 + 2625700*uk_113 + 1028500*uk_114 + 794750*uk_115 + 261800*uk_116 + 1112650*uk_117 + 2028950*uk_118 + 794750*uk_119 + 4025005*uk_12 + 86240*uk_120 + 366520*uk_121 + 668360*uk_122 + 261800*uk_123 + 1557710*uk_124 + 2840530*uk_125 + 1112650*uk_126 + 5179790*uk_127 + 2028950*uk_128 + 794750*uk_129 + 1325884*uk_13 + 614125*uk_130 + 202300*uk_131 + 859775*uk_132 + 1567825*uk_133 + 614125*uk_134 + 66640*uk_135 + 283220*uk_136 + 516460*uk_137 + 202300*uk_138 + 1203685*uk_139 + 5635007*uk_14 + 2194955*uk_140 + 859775*uk_141 + 4002565*uk_142 + 1567825*uk_143 + 614125*uk_144 + 21952*uk_145 + 93296*uk_146 + 170128*uk_147 + 66640*uk_148 + 396508*uk_149 + 10275601*uk_15 + 723044*uk_150 + 283220*uk_151 + 1318492*uk_152 + 516460*uk_153 + 202300*uk_154 + 1685159*uk_155 + 3072937*uk_156 + 1203685*uk_157 + 5603591*uk_158 + 2194955*uk_159 + 4025005*uk_16 + 859775*uk_160 + 10218313*uk_161 + 4002565*uk_162 + 1567825*uk_163 + 614125*uk_164 + 3969*uk_17 + 6930*uk_18 + 5355*uk_19 + 63*uk_2 + 1764*uk_20 + 7497*uk_21 + 13671*uk_22 + 5355*uk_23 + 12100*uk_24 + 9350*uk_25 + 3080*uk_26 + 13090*uk_27 + 23870*uk_28 + 9350*uk_29 + 110*uk_3 + 7225*uk_30 + 2380*uk_31 + 10115*uk_32 + 18445*uk_33 + 7225*uk_34 + 784*uk_35 + 3332*uk_36 + 6076*uk_37 + 2380*uk_38 + 14161*uk_39 + 85*uk_4 + 25823*uk_40 + 10115*uk_41 + 47089*uk_42 + 18445*uk_43 + 7225*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 246653726990*uk_47 + 190596061765*uk_48 + 62784585052*uk_49 + 28*uk_5 + 266834486471*uk_50 + 486580534153*uk_51 + 190596061765*uk_52 + 187944057*uk_53 + 328156290*uk_54 + 253575315*uk_55 + 83530692*uk_56 + 355005441*uk_57 + 647362863*uk_58 + 253575315*uk_59 + 119*uk_6 + 572971300*uk_60 + 442750550*uk_61 + 145847240*uk_62 + 619850770*uk_63 + 1130316110*uk_64 + 442750550*uk_65 + 342125425*uk_66 + 112700140*uk_67 + 478975595*uk_68 + 873426085*uk_69 + 217*uk_7 + 342125425*uk_70 + 37124752*uk_71 + 157780196*uk_72 + 287716828*uk_73 + 112700140*uk_74 + 670565833*uk_75 + 1222796519*uk_76 + 478975595*uk_77 + 2229805417*uk_78 + 873426085*uk_79 + 85*uk_8 + 342125425*uk_80 + 250047*uk_81 + 436590*uk_82 + 337365*uk_83 + 111132*uk_84 + 472311*uk_85 + 861273*uk_86 + 337365*uk_87 + 762300*uk_88 + 589050*uk_89 + 2242306609*uk_9 + 194040*uk_90 + 824670*uk_91 + 1503810*uk_92 + 589050*uk_93 + 455175*uk_94 + 149940*uk_95 + 637245*uk_96 + 1162035*uk_97 + 455175*uk_98 + 49392*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 182952*uk_100 + 328104*uk_101 + 166320*uk_102 + 922383*uk_103 + 1654191*uk_104 + 838530*uk_105 + 2966607*uk_106 + 1503810*uk_107 + 762300*uk_108 + 74088*uk_109 + 1988826*uk_11 + 194040*uk_110 + 42336*uk_111 + 213444*uk_112 + 382788*uk_113 + 194040*uk_114 + 508200*uk_115 + 110880*uk_116 + 559020*uk_117 + 1002540*uk_118 + 508200*uk_119 + 5208830*uk_12 + 24192*uk_120 + 121968*uk_121 + 218736*uk_122 + 110880*uk_123 + 614922*uk_124 + 1102794*uk_125 + 559020*uk_126 + 1977738*uk_127 + 1002540*uk_128 + 508200*uk_129 + 1136472*uk_13 + 1331000*uk_130 + 290400*uk_131 + 1464100*uk_132 + 2625700*uk_133 + 1331000*uk_134 + 63360*uk_135 + 319440*uk_136 + 572880*uk_137 + 290400*uk_138 + 1610510*uk_139 + 5729713*uk_14 + 2888270*uk_140 + 1464100*uk_141 + 5179790*uk_142 + 2625700*uk_143 + 1331000*uk_144 + 13824*uk_145 + 69696*uk_146 + 124992*uk_147 + 63360*uk_148 + 351384*uk_149 + 10275601*uk_15 + 630168*uk_150 + 319440*uk_151 + 1130136*uk_152 + 572880*uk_153 + 290400*uk_154 + 1771561*uk_155 + 3177097*uk_156 + 1610510*uk_157 + 5697769*uk_158 + 2888270*uk_159 + 5208830*uk_16 + 1464100*uk_160 + 10218313*uk_161 + 5179790*uk_162 + 2625700*uk_163 + 1331000*uk_164 + 3969*uk_17 + 2646*uk_18 + 6930*uk_19 + 63*uk_2 + 1512*uk_20 + 7623*uk_21 + 13671*uk_22 + 6930*uk_23 + 1764*uk_24 + 4620*uk_25 + 1008*uk_26 + 5082*uk_27 + 9114*uk_28 + 4620*uk_29 + 42*uk_3 + 12100*uk_30 + 2640*uk_31 + 13310*uk_32 + 23870*uk_33 + 12100*uk_34 + 576*uk_35 + 2904*uk_36 + 5208*uk_37 + 2640*uk_38 + 14641*uk_39 + 110*uk_4 + 26257*uk_40 + 13310*uk_41 + 47089*uk_42 + 23870*uk_43 + 12100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 94176877578*uk_47 + 246653726990*uk_48 + 53815358616*uk_49 + 24*uk_5 + 271319099689*uk_50 + 486580534153*uk_51 + 246653726990*uk_52 + 187944057*uk_53 + 125296038*uk_54 + 328156290*uk_55 + 71597736*uk_56 + 360971919*uk_57 + 647362863*uk_58 + 328156290*uk_59 + 121*uk_6 + 83530692*uk_60 + 218770860*uk_61 + 47731824*uk_62 + 240647946*uk_63 + 431575242*uk_64 + 218770860*uk_65 + 572971300*uk_66 + 125011920*uk_67 + 630268430*uk_68 + 1130316110*uk_69 + 217*uk_7 + 572971300*uk_70 + 27275328*uk_71 + 137513112*uk_72 + 246614424*uk_73 + 125011920*uk_74 + 693295273*uk_75 + 1243347721*uk_76 + 630268430*uk_77 + 2229805417*uk_78 + 1130316110*uk_79 + 110*uk_8 + 572971300*uk_80 + 250047*uk_81 + 166698*uk_82 + 436590*uk_83 + 95256*uk_84 + 480249*uk_85 + 861273*uk_86 + 436590*uk_87 + 111132*uk_88 + 291060*uk_89 + 2242306609*uk_9 + 63504*uk_90 + 320166*uk_91 + 574182*uk_92 + 291060*uk_93 + 762300*uk_94 + 166320*uk_95 + 838530*uk_96 + 1503810*uk_97 + 762300*uk_98 + 36288*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 216972*uk_100 + 382788*uk_101 + 74088*uk_102 + 953127*uk_103 + 1681533*uk_104 + 325458*uk_105 + 2966607*uk_106 + 574182*uk_107 + 111132*uk_108 + 1771561*uk_109 + 5729713*uk_11 + 614922*uk_110 + 409948*uk_111 + 1800843*uk_112 + 3177097*uk_113 + 614922*uk_114 + 213444*uk_115 + 142296*uk_116 + 625086*uk_117 + 1102794*uk_118 + 213444*uk_119 + 1988826*uk_12 + 94864*uk_120 + 416724*uk_121 + 735196*uk_122 + 142296*uk_123 + 1830609*uk_124 + 3229611*uk_125 + 625086*uk_126 + 5697769*uk_127 + 1102794*uk_128 + 213444*uk_129 + 1325884*uk_13 + 74088*uk_130 + 49392*uk_131 + 216972*uk_132 + 382788*uk_133 + 74088*uk_134 + 32928*uk_135 + 144648*uk_136 + 255192*uk_137 + 49392*uk_138 + 635418*uk_139 + 5824419*uk_14 + 1121022*uk_140 + 216972*uk_141 + 1977738*uk_142 + 382788*uk_143 + 74088*uk_144 + 21952*uk_145 + 96432*uk_146 + 170128*uk_147 + 32928*uk_148 + 423612*uk_149 + 10275601*uk_15 + 747348*uk_150 + 144648*uk_151 + 1318492*uk_152 + 255192*uk_153 + 49392*uk_154 + 1860867*uk_155 + 3282993*uk_156 + 635418*uk_157 + 5791947*uk_158 + 1121022*uk_159 + 1988826*uk_16 + 216972*uk_160 + 10218313*uk_161 + 1977738*uk_162 + 382788*uk_163 + 74088*uk_164 + 3969*uk_17 + 7623*uk_18 + 2646*uk_19 + 63*uk_2 + 1764*uk_20 + 7749*uk_21 + 13671*uk_22 + 2646*uk_23 + 14641*uk_24 + 5082*uk_25 + 3388*uk_26 + 14883*uk_27 + 26257*uk_28 + 5082*uk_29 + 121*uk_3 + 1764*uk_30 + 1176*uk_31 + 5166*uk_32 + 9114*uk_33 + 1764*uk_34 + 784*uk_35 + 3444*uk_36 + 6076*uk_37 + 1176*uk_38 + 15129*uk_39 + 42*uk_4 + 26691*uk_40 + 5166*uk_41 + 47089*uk_42 + 9114*uk_43 + 1764*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 271319099689*uk_47 + 94176877578*uk_48 + 62784585052*uk_49 + 28*uk_5 + 275803712907*uk_50 + 486580534153*uk_51 + 94176877578*uk_52 + 187944057*uk_53 + 360971919*uk_54 + 125296038*uk_55 + 83530692*uk_56 + 366938397*uk_57 + 647362863*uk_58 + 125296038*uk_59 + 123*uk_6 + 693295273*uk_60 + 240647946*uk_61 + 160431964*uk_62 + 704754699*uk_63 + 1243347721*uk_64 + 240647946*uk_65 + 83530692*uk_66 + 55687128*uk_67 + 244625598*uk_68 + 431575242*uk_69 + 217*uk_7 + 83530692*uk_70 + 37124752*uk_71 + 163083732*uk_72 + 287716828*uk_73 + 55687128*uk_74 + 716403537*uk_75 + 1263898923*uk_76 + 244625598*uk_77 + 2229805417*uk_78 + 431575242*uk_79 + 42*uk_8 + 83530692*uk_80 + 250047*uk_81 + 480249*uk_82 + 166698*uk_83 + 111132*uk_84 + 488187*uk_85 + 861273*uk_86 + 166698*uk_87 + 922383*uk_88 + 320166*uk_89 + 2242306609*uk_9 + 213444*uk_90 + 937629*uk_91 + 1654191*uk_92 + 320166*uk_93 + 111132*uk_94 + 74088*uk_95 + 325458*uk_96 + 574182*uk_97 + 111132*uk_98 + 49392*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 189000*uk_100 + 328104*uk_101 + 182952*uk_102 + 984375*uk_103 + 1708875*uk_104 + 952875*uk_105 + 2966607*uk_106 + 1654191*uk_107 + 922383*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 1283689*uk_110 + 254616*uk_111 + 1326125*uk_112 + 2302153*uk_113 + 1283689*uk_114 + 1508023*uk_115 + 299112*uk_116 + 1557875*uk_117 + 2704471*uk_118 + 1508023*uk_119 + 5729713*uk_12 + 59328*uk_120 + 309000*uk_121 + 536424*uk_122 + 299112*uk_123 + 1609375*uk_124 + 2793875*uk_125 + 1557875*uk_126 + 4850167*uk_127 + 2704471*uk_128 + 1508023*uk_129 + 1136472*uk_13 + 1771561*uk_130 + 351384*uk_131 + 1830125*uk_132 + 3177097*uk_133 + 1771561*uk_134 + 69696*uk_135 + 363000*uk_136 + 630168*uk_137 + 351384*uk_138 + 1890625*uk_139 + 5919125*uk_14 + 3282125*uk_140 + 1830125*uk_141 + 5697769*uk_142 + 3177097*uk_143 + 1771561*uk_144 + 13824*uk_145 + 72000*uk_146 + 124992*uk_147 + 69696*uk_148 + 375000*uk_149 + 10275601*uk_15 + 651000*uk_150 + 363000*uk_151 + 1130136*uk_152 + 630168*uk_153 + 351384*uk_154 + 1953125*uk_155 + 3390625*uk_156 + 1890625*uk_157 + 5886125*uk_158 + 3282125*uk_159 + 5729713*uk_16 + 1830125*uk_160 + 10218313*uk_161 + 5697769*uk_162 + 3177097*uk_163 + 1771561*uk_164 + 3969*uk_17 + 6489*uk_18 + 7623*uk_19 + 63*uk_2 + 1512*uk_20 + 7875*uk_21 + 13671*uk_22 + 7623*uk_23 + 10609*uk_24 + 12463*uk_25 + 2472*uk_26 + 12875*uk_27 + 22351*uk_28 + 12463*uk_29 + 103*uk_3 + 14641*uk_30 + 2904*uk_31 + 15125*uk_32 + 26257*uk_33 + 14641*uk_34 + 576*uk_35 + 3000*uk_36 + 5208*uk_37 + 2904*uk_38 + 15625*uk_39 + 121*uk_4 + 27125*uk_40 + 15125*uk_41 + 47089*uk_42 + 26257*uk_43 + 14641*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 271319099689*uk_48 + 53815358616*uk_49 + 24*uk_5 + 280288326125*uk_50 + 486580534153*uk_51 + 271319099689*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 360971919*uk_55 + 71597736*uk_56 + 372904875*uk_57 + 647362863*uk_58 + 360971919*uk_59 + 125*uk_6 + 502367977*uk_60 + 590160439*uk_61 + 117056616*uk_62 + 609669875*uk_63 + 1058386903*uk_64 + 590160439*uk_65 + 693295273*uk_66 + 137513112*uk_67 + 716214125*uk_68 + 1243347721*uk_69 + 217*uk_7 + 693295273*uk_70 + 27275328*uk_71 + 142059000*uk_72 + 246614424*uk_73 + 137513112*uk_74 + 739890625*uk_75 + 1284450125*uk_76 + 716214125*uk_77 + 2229805417*uk_78 + 1243347721*uk_79 + 121*uk_8 + 693295273*uk_80 + 250047*uk_81 + 408807*uk_82 + 480249*uk_83 + 95256*uk_84 + 496125*uk_85 + 861273*uk_86 + 480249*uk_87 + 668367*uk_88 + 785169*uk_89 + 2242306609*uk_9 + 155736*uk_90 + 811125*uk_91 + 1408113*uk_92 + 785169*uk_93 + 922383*uk_94 + 182952*uk_95 + 952875*uk_96 + 1654191*uk_97 + 922383*uk_98 + 36288*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 192024*uk_100 + 328104*uk_101 + 155736*uk_102 + 1016127*uk_103 + 1736217*uk_104 + 824103*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 1295029*uk_109 + 5161477*uk_11 + 1223743*uk_110 + 285144*uk_111 + 1508887*uk_112 + 2578177*uk_113 + 1223743*uk_114 + 1156381*uk_115 + 269448*uk_116 + 1425829*uk_117 + 2436259*uk_118 + 1156381*uk_119 + 4877359*uk_12 + 62784*uk_120 + 332232*uk_121 + 567672*uk_122 + 269448*uk_123 + 1758061*uk_124 + 3003931*uk_125 + 1425829*uk_126 + 5132701*uk_127 + 2436259*uk_128 + 1156381*uk_129 + 1136472*uk_13 + 1092727*uk_130 + 254616*uk_131 + 1347343*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 59328*uk_135 + 313944*uk_136 + 536424*uk_137 + 254616*uk_138 + 1661287*uk_139 + 6013831*uk_14 + 2838577*uk_140 + 1347343*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 13824*uk_145 + 73152*uk_146 + 124992*uk_147 + 59328*uk_148 + 387096*uk_149 + 10275601*uk_15 + 661416*uk_150 + 313944*uk_151 + 1130136*uk_152 + 536424*uk_153 + 254616*uk_154 + 2048383*uk_155 + 3499993*uk_156 + 1661287*uk_157 + 5980303*uk_158 + 2838577*uk_159 + 4877359*uk_16 + 1347343*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 6867*uk_18 + 6489*uk_19 + 63*uk_2 + 1512*uk_20 + 8001*uk_21 + 13671*uk_22 + 6489*uk_23 + 11881*uk_24 + 11227*uk_25 + 2616*uk_26 + 13843*uk_27 + 23653*uk_28 + 11227*uk_29 + 109*uk_3 + 10609*uk_30 + 2472*uk_31 + 13081*uk_32 + 22351*uk_33 + 10609*uk_34 + 576*uk_35 + 3048*uk_36 + 5208*uk_37 + 2472*uk_38 + 16129*uk_39 + 103*uk_4 + 27559*uk_40 + 13081*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 244411420381*uk_47 + 230957580727*uk_48 + 53815358616*uk_49 + 24*uk_5 + 284772939343*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 325173051*uk_54 + 307273617*uk_55 + 71597736*uk_56 + 378871353*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 127*uk_6 + 562600993*uk_60 + 531632131*uk_61 + 123875448*uk_62 + 655507579*uk_63 + 1120040509*uk_64 + 531632131*uk_65 + 502367977*uk_66 + 117056616*uk_67 + 619424593*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 27275328*uk_71 + 144331944*uk_72 + 246614424*uk_73 + 117056616*uk_74 + 763756537*uk_75 + 1305001327*uk_76 + 619424593*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 432621*uk_82 + 408807*uk_83 + 95256*uk_84 + 504063*uk_85 + 861273*uk_86 + 408807*uk_87 + 748503*uk_88 + 707301*uk_89 + 2242306609*uk_9 + 164808*uk_90 + 872109*uk_91 + 1490139*uk_92 + 707301*uk_93 + 668367*uk_94 + 155736*uk_95 + 824103*uk_96 + 1408113*uk_97 + 668367*uk_98 + 36288*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 162540*uk_100 + 273420*uk_101 + 137340*uk_102 + 1048383*uk_103 + 1763559*uk_104 + 885843*uk_105 + 2966607*uk_106 + 1490139*uk_107 + 748503*uk_108 + 1000*uk_109 + 473530*uk_11 + 10900*uk_110 + 2000*uk_111 + 12900*uk_112 + 21700*uk_113 + 10900*uk_114 + 118810*uk_115 + 21800*uk_116 + 140610*uk_117 + 236530*uk_118 + 118810*uk_119 + 5161477*uk_12 + 4000*uk_120 + 25800*uk_121 + 43400*uk_122 + 21800*uk_123 + 166410*uk_124 + 279930*uk_125 + 140610*uk_126 + 470890*uk_127 + 236530*uk_128 + 118810*uk_129 + 947060*uk_13 + 1295029*uk_130 + 237620*uk_131 + 1532649*uk_132 + 2578177*uk_133 + 1295029*uk_134 + 43600*uk_135 + 281220*uk_136 + 473060*uk_137 + 237620*uk_138 + 1813869*uk_139 + 6108537*uk_14 + 3051237*uk_140 + 1532649*uk_141 + 5132701*uk_142 + 2578177*uk_143 + 1295029*uk_144 + 8000*uk_145 + 51600*uk_146 + 86800*uk_147 + 43600*uk_148 + 332820*uk_149 + 10275601*uk_15 + 559860*uk_150 + 281220*uk_151 + 941780*uk_152 + 473060*uk_153 + 237620*uk_154 + 2146689*uk_155 + 3611097*uk_156 + 1813869*uk_157 + 6074481*uk_158 + 3051237*uk_159 + 5161477*uk_16 + 1532649*uk_160 + 10218313*uk_161 + 5132701*uk_162 + 2578177*uk_163 + 1295029*uk_164 + 3969*uk_17 + 630*uk_18 + 6867*uk_19 + 63*uk_2 + 1260*uk_20 + 8127*uk_21 + 13671*uk_22 + 6867*uk_23 + 100*uk_24 + 1090*uk_25 + 200*uk_26 + 1290*uk_27 + 2170*uk_28 + 1090*uk_29 + 10*uk_3 + 11881*uk_30 + 2180*uk_31 + 14061*uk_32 + 23653*uk_33 + 11881*uk_34 + 400*uk_35 + 2580*uk_36 + 4340*uk_37 + 2180*uk_38 + 16641*uk_39 + 109*uk_4 + 27993*uk_40 + 14061*uk_41 + 47089*uk_42 + 23653*uk_43 + 11881*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 22423066090*uk_47 + 244411420381*uk_48 + 44846132180*uk_49 + 20*uk_5 + 289257552561*uk_50 + 486580534153*uk_51 + 244411420381*uk_52 + 187944057*uk_53 + 29832390*uk_54 + 325173051*uk_55 + 59664780*uk_56 + 384837831*uk_57 + 647362863*uk_58 + 325173051*uk_59 + 129*uk_6 + 4735300*uk_60 + 51614770*uk_61 + 9470600*uk_62 + 61085370*uk_63 + 102756010*uk_64 + 51614770*uk_65 + 562600993*uk_66 + 103229540*uk_67 + 665830533*uk_68 + 1120040509*uk_69 + 217*uk_7 + 562600993*uk_70 + 18941200*uk_71 + 122170740*uk_72 + 205512020*uk_73 + 103229540*uk_74 + 788001273*uk_75 + 1325552529*uk_76 + 665830533*uk_77 + 2229805417*uk_78 + 1120040509*uk_79 + 109*uk_8 + 562600993*uk_80 + 250047*uk_81 + 39690*uk_82 + 432621*uk_83 + 79380*uk_84 + 512001*uk_85 + 861273*uk_86 + 432621*uk_87 + 6300*uk_88 + 68670*uk_89 + 2242306609*uk_9 + 12600*uk_90 + 81270*uk_91 + 136710*uk_92 + 68670*uk_93 + 748503*uk_94 + 137340*uk_95 + 885843*uk_96 + 1490139*uk_97 + 748503*uk_98 + 25200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 198072*uk_100 + 328104*uk_101 + 15120*uk_102 + 1081143*uk_103 + 1790901*uk_104 + 82530*uk_105 + 2966607*uk_106 + 136710*uk_107 + 6300*uk_108 + 238328*uk_109 + 2935886*uk_11 + 38440*uk_110 + 92256*uk_111 + 503564*uk_112 + 834148*uk_113 + 38440*uk_114 + 6200*uk_115 + 14880*uk_116 + 81220*uk_117 + 134540*uk_118 + 6200*uk_119 + 473530*uk_12 + 35712*uk_120 + 194928*uk_121 + 322896*uk_122 + 14880*uk_123 + 1063982*uk_124 + 1762474*uk_125 + 81220*uk_126 + 2919518*uk_127 + 134540*uk_128 + 6200*uk_129 + 1136472*uk_13 + 1000*uk_130 + 2400*uk_131 + 13100*uk_132 + 21700*uk_133 + 1000*uk_134 + 5760*uk_135 + 31440*uk_136 + 52080*uk_137 + 2400*uk_138 + 171610*uk_139 + 6203243*uk_14 + 284270*uk_140 + 13100*uk_141 + 470890*uk_142 + 21700*uk_143 + 1000*uk_144 + 13824*uk_145 + 75456*uk_146 + 124992*uk_147 + 5760*uk_148 + 411864*uk_149 + 10275601*uk_15 + 682248*uk_150 + 31440*uk_151 + 1130136*uk_152 + 52080*uk_153 + 2400*uk_154 + 2248091*uk_155 + 3723937*uk_156 + 171610*uk_157 + 6168659*uk_158 + 284270*uk_159 + 473530*uk_16 + 13100*uk_160 + 10218313*uk_161 + 470890*uk_162 + 21700*uk_163 + 1000*uk_164 + 3969*uk_17 + 3906*uk_18 + 630*uk_19 + 63*uk_2 + 1512*uk_20 + 8253*uk_21 + 13671*uk_22 + 630*uk_23 + 3844*uk_24 + 620*uk_25 + 1488*uk_26 + 8122*uk_27 + 13454*uk_28 + 620*uk_29 + 62*uk_3 + 100*uk_30 + 240*uk_31 + 1310*uk_32 + 2170*uk_33 + 100*uk_34 + 576*uk_35 + 3144*uk_36 + 5208*uk_37 + 240*uk_38 + 17161*uk_39 + 10*uk_4 + 28427*uk_40 + 1310*uk_41 + 47089*uk_42 + 2170*uk_43 + 100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 139023009758*uk_47 + 22423066090*uk_48 + 53815358616*uk_49 + 24*uk_5 + 293742165779*uk_50 + 486580534153*uk_51 + 22423066090*uk_52 + 187944057*uk_53 + 184960818*uk_54 + 29832390*uk_55 + 71597736*uk_56 + 390804309*uk_57 + 647362863*uk_58 + 29832390*uk_59 + 131*uk_6 + 182024932*uk_60 + 29358860*uk_61 + 70461264*uk_62 + 384601066*uk_63 + 637087262*uk_64 + 29358860*uk_65 + 4735300*uk_66 + 11364720*uk_67 + 62032430*uk_68 + 102756010*uk_69 + 217*uk_7 + 4735300*uk_70 + 27275328*uk_71 + 148877832*uk_72 + 246614424*uk_73 + 11364720*uk_74 + 812624833*uk_75 + 1346103731*uk_76 + 62032430*uk_77 + 2229805417*uk_78 + 102756010*uk_79 + 10*uk_8 + 4735300*uk_80 + 250047*uk_81 + 246078*uk_82 + 39690*uk_83 + 95256*uk_84 + 519939*uk_85 + 861273*uk_86 + 39690*uk_87 + 242172*uk_88 + 39060*uk_89 + 2242306609*uk_9 + 93744*uk_90 + 511686*uk_91 + 847602*uk_92 + 39060*uk_93 + 6300*uk_94 + 15120*uk_95 + 82530*uk_96 + 136710*uk_97 + 6300*uk_98 + 36288*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 167580*uk_100 + 273420*uk_101 + 78120*uk_102 + 1114407*uk_103 + 1818243*uk_104 + 519498*uk_105 + 2966607*uk_106 + 847602*uk_107 + 242172*uk_108 + 125*uk_109 + 236765*uk_11 + 1550*uk_110 + 500*uk_111 + 3325*uk_112 + 5425*uk_113 + 1550*uk_114 + 19220*uk_115 + 6200*uk_116 + 41230*uk_117 + 67270*uk_118 + 19220*uk_119 + 2935886*uk_12 + 2000*uk_120 + 13300*uk_121 + 21700*uk_122 + 6200*uk_123 + 88445*uk_124 + 144305*uk_125 + 41230*uk_126 + 235445*uk_127 + 67270*uk_128 + 19220*uk_129 + 947060*uk_13 + 238328*uk_130 + 76880*uk_131 + 511252*uk_132 + 834148*uk_133 + 238328*uk_134 + 24800*uk_135 + 164920*uk_136 + 269080*uk_137 + 76880*uk_138 + 1096718*uk_139 + 6297949*uk_14 + 1789382*uk_140 + 511252*uk_141 + 2919518*uk_142 + 834148*uk_143 + 238328*uk_144 + 8000*uk_145 + 53200*uk_146 + 86800*uk_147 + 24800*uk_148 + 353780*uk_149 + 10275601*uk_15 + 577220*uk_150 + 164920*uk_151 + 941780*uk_152 + 269080*uk_153 + 76880*uk_154 + 2352637*uk_155 + 3838513*uk_156 + 1096718*uk_157 + 6262837*uk_158 + 1789382*uk_159 + 2935886*uk_16 + 511252*uk_160 + 10218313*uk_161 + 2919518*uk_162 + 834148*uk_163 + 238328*uk_164 + 3969*uk_17 + 315*uk_18 + 3906*uk_19 + 63*uk_2 + 1260*uk_20 + 8379*uk_21 + 13671*uk_22 + 3906*uk_23 + 25*uk_24 + 310*uk_25 + 100*uk_26 + 665*uk_27 + 1085*uk_28 + 310*uk_29 + 5*uk_3 + 3844*uk_30 + 1240*uk_31 + 8246*uk_32 + 13454*uk_33 + 3844*uk_34 + 400*uk_35 + 2660*uk_36 + 4340*uk_37 + 1240*uk_38 + 17689*uk_39 + 62*uk_4 + 28861*uk_40 + 8246*uk_41 + 47089*uk_42 + 13454*uk_43 + 3844*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 11211533045*uk_47 + 139023009758*uk_48 + 44846132180*uk_49 + 20*uk_5 + 298226778997*uk_50 + 486580534153*uk_51 + 139023009758*uk_52 + 187944057*uk_53 + 14916195*uk_54 + 184960818*uk_55 + 59664780*uk_56 + 396770787*uk_57 + 647362863*uk_58 + 184960818*uk_59 + 133*uk_6 + 1183825*uk_60 + 14679430*uk_61 + 4735300*uk_62 + 31489745*uk_63 + 51378005*uk_64 + 14679430*uk_65 + 182024932*uk_66 + 58717720*uk_67 + 390472838*uk_68 + 637087262*uk_69 + 217*uk_7 + 182024932*uk_70 + 18941200*uk_71 + 125958980*uk_72 + 205512020*uk_73 + 58717720*uk_74 + 837627217*uk_75 + 1366654933*uk_76 + 390472838*uk_77 + 2229805417*uk_78 + 637087262*uk_79 + 62*uk_8 + 182024932*uk_80 + 250047*uk_81 + 19845*uk_82 + 246078*uk_83 + 79380*uk_84 + 527877*uk_85 + 861273*uk_86 + 246078*uk_87 + 1575*uk_88 + 19530*uk_89 + 2242306609*uk_9 + 6300*uk_90 + 41895*uk_91 + 68355*uk_92 + 19530*uk_93 + 242172*uk_94 + 78120*uk_95 + 519498*uk_96 + 847602*uk_97 + 242172*uk_98 + 25200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 204120*uk_100 + 328104*uk_101 + 7560*uk_102 + 1148175*uk_103 + 1845585*uk_104 + 42525*uk_105 + 2966607*uk_106 + 68355*uk_107 + 1575*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 53045*uk_110 + 254616*uk_111 + 1432215*uk_112 + 2302153*uk_113 + 53045*uk_114 + 2575*uk_115 + 12360*uk_116 + 69525*uk_117 + 111755*uk_118 + 2575*uk_119 + 236765*uk_12 + 59328*uk_120 + 333720*uk_121 + 536424*uk_122 + 12360*uk_123 + 1877175*uk_124 + 3017385*uk_125 + 69525*uk_126 + 4850167*uk_127 + 111755*uk_128 + 2575*uk_129 + 1136472*uk_13 + 125*uk_130 + 600*uk_131 + 3375*uk_132 + 5425*uk_133 + 125*uk_134 + 2880*uk_135 + 16200*uk_136 + 26040*uk_137 + 600*uk_138 + 91125*uk_139 + 6392655*uk_14 + 146475*uk_140 + 3375*uk_141 + 235445*uk_142 + 5425*uk_143 + 125*uk_144 + 13824*uk_145 + 77760*uk_146 + 124992*uk_147 + 2880*uk_148 + 437400*uk_149 + 10275601*uk_15 + 703080*uk_150 + 16200*uk_151 + 1130136*uk_152 + 26040*uk_153 + 600*uk_154 + 2460375*uk_155 + 3954825*uk_156 + 91125*uk_157 + 6357015*uk_158 + 146475*uk_159 + 236765*uk_16 + 3375*uk_160 + 10218313*uk_161 + 235445*uk_162 + 5425*uk_163 + 125*uk_164 + 3969*uk_17 + 6489*uk_18 + 315*uk_19 + 63*uk_2 + 1512*uk_20 + 8505*uk_21 + 13671*uk_22 + 315*uk_23 + 10609*uk_24 + 515*uk_25 + 2472*uk_26 + 13905*uk_27 + 22351*uk_28 + 515*uk_29 + 103*uk_3 + 25*uk_30 + 120*uk_31 + 675*uk_32 + 1085*uk_33 + 25*uk_34 + 576*uk_35 + 3240*uk_36 + 5208*uk_37 + 120*uk_38 + 18225*uk_39 + 5*uk_4 + 29295*uk_40 + 675*uk_41 + 47089*uk_42 + 1085*uk_43 + 25*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 11211533045*uk_48 + 53815358616*uk_49 + 24*uk_5 + 302711392215*uk_50 + 486580534153*uk_51 + 11211533045*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 14916195*uk_55 + 71597736*uk_56 + 402737265*uk_57 + 647362863*uk_58 + 14916195*uk_59 + 135*uk_6 + 502367977*uk_60 + 24386795*uk_61 + 117056616*uk_62 + 658443465*uk_63 + 1058386903*uk_64 + 24386795*uk_65 + 1183825*uk_66 + 5682360*uk_67 + 31963275*uk_68 + 51378005*uk_69 + 217*uk_7 + 1183825*uk_70 + 27275328*uk_71 + 153423720*uk_72 + 246614424*uk_73 + 5682360*uk_74 + 863008425*uk_75 + 1387206135*uk_76 + 31963275*uk_77 + 2229805417*uk_78 + 51378005*uk_79 + 5*uk_8 + 1183825*uk_80 + 250047*uk_81 + 408807*uk_82 + 19845*uk_83 + 95256*uk_84 + 535815*uk_85 + 861273*uk_86 + 19845*uk_87 + 668367*uk_88 + 32445*uk_89 + 2242306609*uk_9 + 155736*uk_90 + 876015*uk_91 + 1408113*uk_92 + 32445*uk_93 + 1575*uk_94 + 7560*uk_95 + 42525*uk_96 + 68355*uk_97 + 1575*uk_98 + 36288*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 172620*uk_100 + 273420*uk_101 + 129780*uk_102 + 1182447*uk_103 + 1872927*uk_104 + 888993*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 681472*uk_109 + 4167064*uk_11 + 797632*uk_110 + 154880*uk_111 + 1060928*uk_112 + 1680448*uk_113 + 797632*uk_114 + 933592*uk_115 + 181280*uk_116 + 1241768*uk_117 + 1966888*uk_118 + 933592*uk_119 + 4877359*uk_12 + 35200*uk_120 + 241120*uk_121 + 381920*uk_122 + 181280*uk_123 + 1651672*uk_124 + 2616152*uk_125 + 1241768*uk_126 + 4143832*uk_127 + 1966888*uk_128 + 933592*uk_129 + 947060*uk_13 + 1092727*uk_130 + 212180*uk_131 + 1453433*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 41200*uk_135 + 282220*uk_136 + 447020*uk_137 + 212180*uk_138 + 1933207*uk_139 + 6487361*uk_14 + 3062087*uk_140 + 1453433*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 8000*uk_145 + 54800*uk_146 + 86800*uk_147 + 41200*uk_148 + 375380*uk_149 + 10275601*uk_15 + 594580*uk_150 + 282220*uk_151 + 941780*uk_152 + 447020*uk_153 + 212180*uk_154 + 2571353*uk_155 + 4072873*uk_156 + 1933207*uk_157 + 6451193*uk_158 + 3062087*uk_159 + 4877359*uk_16 + 1453433*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 5544*uk_18 + 6489*uk_19 + 63*uk_2 + 1260*uk_20 + 8631*uk_21 + 13671*uk_22 + 6489*uk_23 + 7744*uk_24 + 9064*uk_25 + 1760*uk_26 + 12056*uk_27 + 19096*uk_28 + 9064*uk_29 + 88*uk_3 + 10609*uk_30 + 2060*uk_31 + 14111*uk_32 + 22351*uk_33 + 10609*uk_34 + 400*uk_35 + 2740*uk_36 + 4340*uk_37 + 2060*uk_38 + 18769*uk_39 + 103*uk_4 + 29729*uk_40 + 14111*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 197322981592*uk_47 + 230957580727*uk_48 + 44846132180*uk_49 + 20*uk_5 + 307196005433*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 262525032*uk_54 + 307273617*uk_55 + 59664780*uk_56 + 408703743*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 137*uk_6 + 366701632*uk_60 + 429207592*uk_61 + 83341280*uk_62 + 570887768*uk_63 + 904252888*uk_64 + 429207592*uk_65 + 502367977*uk_66 + 97547180*uk_67 + 668198183*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 18941200*uk_71 + 129747220*uk_72 + 205512020*uk_73 + 97547180*uk_74 + 888768457*uk_75 + 1407757337*uk_76 + 668198183*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 349272*uk_82 + 408807*uk_83 + 79380*uk_84 + 543753*uk_85 + 861273*uk_86 + 408807*uk_87 + 487872*uk_88 + 571032*uk_89 + 2242306609*uk_9 + 110880*uk_90 + 759528*uk_91 + 1203048*uk_92 + 571032*uk_93 + 668367*uk_94 + 129780*uk_95 + 888993*uk_96 + 1408113*uk_97 + 668367*uk_98 + 25200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 175140*uk_100 + 273420*uk_101 + 110880*uk_102 + 1217223*uk_103 + 1900269*uk_104 + 770616*uk_105 + 2966607*uk_106 + 1203048*uk_107 + 487872*uk_108 + 804357*uk_109 + 4403829*uk_11 + 761112*uk_110 + 172980*uk_111 + 1202211*uk_112 + 1876833*uk_113 + 761112*uk_114 + 720192*uk_115 + 163680*uk_116 + 1137576*uk_117 + 1775928*uk_118 + 720192*uk_119 + 4167064*uk_12 + 37200*uk_120 + 258540*uk_121 + 403620*uk_122 + 163680*uk_123 + 1796853*uk_124 + 2805159*uk_125 + 1137576*uk_126 + 4379277*uk_127 + 1775928*uk_128 + 720192*uk_129 + 947060*uk_13 + 681472*uk_130 + 154880*uk_131 + 1076416*uk_132 + 1680448*uk_133 + 681472*uk_134 + 35200*uk_135 + 244640*uk_136 + 381920*uk_137 + 154880*uk_138 + 1700248*uk_139 + 6582067*uk_14 + 2654344*uk_140 + 1076416*uk_141 + 4143832*uk_142 + 1680448*uk_143 + 681472*uk_144 + 8000*uk_145 + 55600*uk_146 + 86800*uk_147 + 35200*uk_148 + 386420*uk_149 + 10275601*uk_15 + 603260*uk_150 + 244640*uk_151 + 941780*uk_152 + 381920*uk_153 + 154880*uk_154 + 2685619*uk_155 + 4192657*uk_156 + 1700248*uk_157 + 6545371*uk_158 + 2654344*uk_159 + 4167064*uk_16 + 1076416*uk_160 + 10218313*uk_161 + 4143832*uk_162 + 1680448*uk_163 + 681472*uk_164 + 3969*uk_17 + 5859*uk_18 + 5544*uk_19 + 63*uk_2 + 1260*uk_20 + 8757*uk_21 + 13671*uk_22 + 5544*uk_23 + 8649*uk_24 + 8184*uk_25 + 1860*uk_26 + 12927*uk_27 + 20181*uk_28 + 8184*uk_29 + 93*uk_3 + 7744*uk_30 + 1760*uk_31 + 12232*uk_32 + 19096*uk_33 + 7744*uk_34 + 400*uk_35 + 2780*uk_36 + 4340*uk_37 + 1760*uk_38 + 19321*uk_39 + 88*uk_4 + 30163*uk_40 + 12232*uk_41 + 47089*uk_42 + 19096*uk_43 + 7744*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 208534514637*uk_47 + 197322981592*uk_48 + 44846132180*uk_49 + 20*uk_5 + 311680618651*uk_50 + 486580534153*uk_51 + 197322981592*uk_52 + 187944057*uk_53 + 277441227*uk_54 + 262525032*uk_55 + 59664780*uk_56 + 414670221*uk_57 + 647362863*uk_58 + 262525032*uk_59 + 139*uk_6 + 409556097*uk_60 + 387536952*uk_61 + 88076580*uk_62 + 612132231*uk_63 + 955630893*uk_64 + 387536952*uk_65 + 366701632*uk_66 + 83341280*uk_67 + 579221896*uk_68 + 904252888*uk_69 + 217*uk_7 + 366701632*uk_70 + 18941200*uk_71 + 131641340*uk_72 + 205512020*uk_73 + 83341280*uk_74 + 914907313*uk_75 + 1428308539*uk_76 + 579221896*uk_77 + 2229805417*uk_78 + 904252888*uk_79 + 88*uk_8 + 366701632*uk_80 + 250047*uk_81 + 369117*uk_82 + 349272*uk_83 + 79380*uk_84 + 551691*uk_85 + 861273*uk_86 + 349272*uk_87 + 544887*uk_88 + 515592*uk_89 + 2242306609*uk_9 + 117180*uk_90 + 814401*uk_91 + 1271403*uk_92 + 515592*uk_93 + 487872*uk_94 + 110880*uk_95 + 770616*uk_96 + 1203048*uk_97 + 487872*uk_98 + 25200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 177660*uk_100 + 273420*uk_101 + 117180*uk_102 + 1252503*uk_103 + 1927611*uk_104 + 826119*uk_105 + 2966607*uk_106 + 1271403*uk_107 + 544887*uk_108 + 1643032*uk_109 + 5587654*uk_11 + 1294932*uk_110 + 278480*uk_111 + 1963284*uk_112 + 3021508*uk_113 + 1294932*uk_114 + 1020582*uk_115 + 219480*uk_116 + 1547334*uk_117 + 2381358*uk_118 + 1020582*uk_119 + 4403829*uk_12 + 47200*uk_120 + 332760*uk_121 + 512120*uk_122 + 219480*uk_123 + 2345958*uk_124 + 3610446*uk_125 + 1547334*uk_126 + 5556502*uk_127 + 2381358*uk_128 + 1020582*uk_129 + 947060*uk_13 + 804357*uk_130 + 172980*uk_131 + 1219509*uk_132 + 1876833*uk_133 + 804357*uk_134 + 37200*uk_135 + 262260*uk_136 + 403620*uk_137 + 172980*uk_138 + 1848933*uk_139 + 6676773*uk_14 + 2845521*uk_140 + 1219509*uk_141 + 4379277*uk_142 + 1876833*uk_143 + 804357*uk_144 + 8000*uk_145 + 56400*uk_146 + 86800*uk_147 + 37200*uk_148 + 397620*uk_149 + 10275601*uk_15 + 611940*uk_150 + 262260*uk_151 + 941780*uk_152 + 403620*uk_153 + 172980*uk_154 + 2803221*uk_155 + 4314177*uk_156 + 1848933*uk_157 + 6639549*uk_158 + 2845521*uk_159 + 4403829*uk_16 + 1219509*uk_160 + 10218313*uk_161 + 4379277*uk_162 + 1876833*uk_163 + 804357*uk_164 + 3969*uk_17 + 7434*uk_18 + 5859*uk_19 + 63*uk_2 + 1260*uk_20 + 8883*uk_21 + 13671*uk_22 + 5859*uk_23 + 13924*uk_24 + 10974*uk_25 + 2360*uk_26 + 16638*uk_27 + 25606*uk_28 + 10974*uk_29 + 118*uk_3 + 8649*uk_30 + 1860*uk_31 + 13113*uk_32 + 20181*uk_33 + 8649*uk_34 + 400*uk_35 + 2820*uk_36 + 4340*uk_37 + 1860*uk_38 + 19881*uk_39 + 93*uk_4 + 30597*uk_40 + 13113*uk_41 + 47089*uk_42 + 20181*uk_43 + 8649*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 264592179862*uk_47 + 208534514637*uk_48 + 44846132180*uk_49 + 20*uk_5 + 316165231869*uk_50 + 486580534153*uk_51 + 208534514637*uk_52 + 187944057*uk_53 + 352022202*uk_54 + 277441227*uk_55 + 59664780*uk_56 + 420636699*uk_57 + 647362863*uk_58 + 277441227*uk_59 + 141*uk_6 + 659343172*uk_60 + 519651822*uk_61 + 111753080*uk_62 + 787859214*uk_63 + 1212520918*uk_64 + 519651822*uk_65 + 409556097*uk_66 + 88076580*uk_67 + 620939889*uk_68 + 955630893*uk_69 + 217*uk_7 + 409556097*uk_70 + 18941200*uk_71 + 133535460*uk_72 + 205512020*uk_73 + 88076580*uk_74 + 941424993*uk_75 + 1448859741*uk_76 + 620939889*uk_77 + 2229805417*uk_78 + 955630893*uk_79 + 93*uk_8 + 409556097*uk_80 + 250047*uk_81 + 468342*uk_82 + 369117*uk_83 + 79380*uk_84 + 559629*uk_85 + 861273*uk_86 + 369117*uk_87 + 877212*uk_88 + 691362*uk_89 + 2242306609*uk_9 + 148680*uk_90 + 1048194*uk_91 + 1613178*uk_92 + 691362*uk_93 + 544887*uk_94 + 117180*uk_95 + 826119*uk_96 + 1271403*uk_97 + 544887*uk_98 + 25200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 144144*uk_100 + 218736*uk_101 + 118944*uk_102 + 1288287*uk_103 + 1954953*uk_104 + 1063062*uk_105 + 2966607*uk_106 + 1613178*uk_107 + 877212*uk_108 + 8000*uk_109 + 947060*uk_11 + 47200*uk_110 + 6400*uk_111 + 57200*uk_112 + 86800*uk_113 + 47200*uk_114 + 278480*uk_115 + 37760*uk_116 + 337480*uk_117 + 512120*uk_118 + 278480*uk_119 + 5587654*uk_12 + 5120*uk_120 + 45760*uk_121 + 69440*uk_122 + 37760*uk_123 + 408980*uk_124 + 620620*uk_125 + 337480*uk_126 + 941780*uk_127 + 512120*uk_128 + 278480*uk_129 + 757648*uk_13 + 1643032*uk_130 + 222784*uk_131 + 1991132*uk_132 + 3021508*uk_133 + 1643032*uk_134 + 30208*uk_135 + 269984*uk_136 + 409696*uk_137 + 222784*uk_138 + 2412982*uk_139 + 6771479*uk_14 + 3661658*uk_140 + 1991132*uk_141 + 5556502*uk_142 + 3021508*uk_143 + 1643032*uk_144 + 4096*uk_145 + 36608*uk_146 + 55552*uk_147 + 30208*uk_148 + 327184*uk_149 + 10275601*uk_15 + 496496*uk_150 + 269984*uk_151 + 753424*uk_152 + 409696*uk_153 + 222784*uk_154 + 2924207*uk_155 + 4437433*uk_156 + 2412982*uk_157 + 6733727*uk_158 + 3661658*uk_159 + 5587654*uk_16 + 1991132*uk_160 + 10218313*uk_161 + 5556502*uk_162 + 3021508*uk_163 + 1643032*uk_164 + 3969*uk_17 + 1260*uk_18 + 7434*uk_19 + 63*uk_2 + 1008*uk_20 + 9009*uk_21 + 13671*uk_22 + 7434*uk_23 + 400*uk_24 + 2360*uk_25 + 320*uk_26 + 2860*uk_27 + 4340*uk_28 + 2360*uk_29 + 20*uk_3 + 13924*uk_30 + 1888*uk_31 + 16874*uk_32 + 25606*uk_33 + 13924*uk_34 + 256*uk_35 + 2288*uk_36 + 3472*uk_37 + 1888*uk_38 + 20449*uk_39 + 118*uk_4 + 31031*uk_40 + 16874*uk_41 + 47089*uk_42 + 25606*uk_43 + 13924*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 44846132180*uk_47 + 264592179862*uk_48 + 35876905744*uk_49 + 16*uk_5 + 320649845087*uk_50 + 486580534153*uk_51 + 264592179862*uk_52 + 187944057*uk_53 + 59664780*uk_54 + 352022202*uk_55 + 47731824*uk_56 + 426603177*uk_57 + 647362863*uk_58 + 352022202*uk_59 + 143*uk_6 + 18941200*uk_60 + 111753080*uk_61 + 15152960*uk_62 + 135429580*uk_63 + 205512020*uk_64 + 111753080*uk_65 + 659343172*uk_66 + 89402464*uk_67 + 799034522*uk_68 + 1212520918*uk_69 + 217*uk_7 + 659343172*uk_70 + 12122368*uk_71 + 108343664*uk_72 + 164409616*uk_73 + 89402464*uk_74 + 968321497*uk_75 + 1469410943*uk_76 + 799034522*uk_77 + 2229805417*uk_78 + 1212520918*uk_79 + 118*uk_8 + 659343172*uk_80 + 250047*uk_81 + 79380*uk_82 + 468342*uk_83 + 63504*uk_84 + 567567*uk_85 + 861273*uk_86 + 468342*uk_87 + 25200*uk_88 + 148680*uk_89 + 2242306609*uk_9 + 20160*uk_90 + 180180*uk_91 + 273420*uk_92 + 148680*uk_93 + 877212*uk_94 + 118944*uk_95 + 1063062*uk_96 + 1613178*uk_97 + 877212*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 182700*uk_100 + 273420*uk_101 + 25200*uk_102 + 1324575*uk_103 + 1982295*uk_104 + 182700*uk_105 + 2966607*uk_106 + 273420*uk_107 + 25200*uk_108 + 571787*uk_109 + 3930299*uk_11 + 137780*uk_110 + 137780*uk_111 + 998905*uk_112 + 1494913*uk_113 + 137780*uk_114 + 33200*uk_115 + 33200*uk_116 + 240700*uk_117 + 360220*uk_118 + 33200*uk_119 + 947060*uk_12 + 33200*uk_120 + 240700*uk_121 + 360220*uk_122 + 33200*uk_123 + 1745075*uk_124 + 2611595*uk_125 + 240700*uk_126 + 3908387*uk_127 + 360220*uk_128 + 33200*uk_129 + 947060*uk_13 + 8000*uk_130 + 8000*uk_131 + 58000*uk_132 + 86800*uk_133 + 8000*uk_134 + 8000*uk_135 + 58000*uk_136 + 86800*uk_137 + 8000*uk_138 + 420500*uk_139 + 6866185*uk_14 + 629300*uk_140 + 58000*uk_141 + 941780*uk_142 + 86800*uk_143 + 8000*uk_144 + 8000*uk_145 + 58000*uk_146 + 86800*uk_147 + 8000*uk_148 + 420500*uk_149 + 10275601*uk_15 + 629300*uk_150 + 58000*uk_151 + 941780*uk_152 + 86800*uk_153 + 8000*uk_154 + 3048625*uk_155 + 4562425*uk_156 + 420500*uk_157 + 6827905*uk_158 + 629300*uk_159 + 947060*uk_16 + 58000*uk_160 + 10218313*uk_161 + 941780*uk_162 + 86800*uk_163 + 8000*uk_164 + 3969*uk_17 + 5229*uk_18 + 1260*uk_19 + 63*uk_2 + 1260*uk_20 + 9135*uk_21 + 13671*uk_22 + 1260*uk_23 + 6889*uk_24 + 1660*uk_25 + 1660*uk_26 + 12035*uk_27 + 18011*uk_28 + 1660*uk_29 + 83*uk_3 + 400*uk_30 + 400*uk_31 + 2900*uk_32 + 4340*uk_33 + 400*uk_34 + 400*uk_35 + 2900*uk_36 + 4340*uk_37 + 400*uk_38 + 21025*uk_39 + 20*uk_4 + 31465*uk_40 + 2900*uk_41 + 47089*uk_42 + 4340*uk_43 + 400*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 186111448547*uk_47 + 44846132180*uk_48 + 44846132180*uk_49 + 20*uk_5 + 325134458305*uk_50 + 486580534153*uk_51 + 44846132180*uk_52 + 187944057*uk_53 + 247608837*uk_54 + 59664780*uk_55 + 59664780*uk_56 + 432569655*uk_57 + 647362863*uk_58 + 59664780*uk_59 + 145*uk_6 + 326214817*uk_60 + 78605980*uk_61 + 78605980*uk_62 + 569893355*uk_63 + 852874883*uk_64 + 78605980*uk_65 + 18941200*uk_66 + 18941200*uk_67 + 137323700*uk_68 + 205512020*uk_69 + 217*uk_7 + 18941200*uk_70 + 18941200*uk_71 + 137323700*uk_72 + 205512020*uk_73 + 18941200*uk_74 + 995596825*uk_75 + 1489962145*uk_76 + 137323700*uk_77 + 2229805417*uk_78 + 205512020*uk_79 + 20*uk_8 + 18941200*uk_80 + 250047*uk_81 + 329427*uk_82 + 79380*uk_83 + 79380*uk_84 + 575505*uk_85 + 861273*uk_86 + 79380*uk_87 + 434007*uk_88 + 104580*uk_89 + 2242306609*uk_9 + 104580*uk_90 + 758205*uk_91 + 1134693*uk_92 + 104580*uk_93 + 25200*uk_94 + 25200*uk_95 + 182700*uk_96 + 273420*uk_97 + 25200*uk_98 + 25200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 148176*uk_100 + 218736*uk_101 + 83664*uk_102 + 1361367*uk_103 + 2009637*uk_104 + 768663*uk_105 + 2966607*uk_106 + 1134693*uk_107 + 434007*uk_108 + 6859*uk_109 + 899707*uk_11 + 29963*uk_110 + 5776*uk_111 + 53067*uk_112 + 78337*uk_113 + 29963*uk_114 + 130891*uk_115 + 25232*uk_116 + 231819*uk_117 + 342209*uk_118 + 130891*uk_119 + 3930299*uk_12 + 4864*uk_120 + 44688*uk_121 + 65968*uk_122 + 25232*uk_123 + 410571*uk_124 + 606081*uk_125 + 231819*uk_126 + 894691*uk_127 + 342209*uk_128 + 130891*uk_129 + 757648*uk_13 + 571787*uk_130 + 110224*uk_131 + 1012683*uk_132 + 1494913*uk_133 + 571787*uk_134 + 21248*uk_135 + 195216*uk_136 + 288176*uk_137 + 110224*uk_138 + 1793547*uk_139 + 6960891*uk_14 + 2647617*uk_140 + 1012683*uk_141 + 3908387*uk_142 + 1494913*uk_143 + 571787*uk_144 + 4096*uk_145 + 37632*uk_146 + 55552*uk_147 + 21248*uk_148 + 345744*uk_149 + 10275601*uk_15 + 510384*uk_150 + 195216*uk_151 + 753424*uk_152 + 288176*uk_153 + 110224*uk_154 + 3176523*uk_155 + 4689153*uk_156 + 1793547*uk_157 + 6922083*uk_158 + 2647617*uk_159 + 3930299*uk_16 + 1012683*uk_160 + 10218313*uk_161 + 3908387*uk_162 + 1494913*uk_163 + 571787*uk_164 + 3969*uk_17 + 1197*uk_18 + 5229*uk_19 + 63*uk_2 + 1008*uk_20 + 9261*uk_21 + 13671*uk_22 + 5229*uk_23 + 361*uk_24 + 1577*uk_25 + 304*uk_26 + 2793*uk_27 + 4123*uk_28 + 1577*uk_29 + 19*uk_3 + 6889*uk_30 + 1328*uk_31 + 12201*uk_32 + 18011*uk_33 + 6889*uk_34 + 256*uk_35 + 2352*uk_36 + 3472*uk_37 + 1328*uk_38 + 21609*uk_39 + 83*uk_4 + 31899*uk_40 + 12201*uk_41 + 47089*uk_42 + 18011*uk_43 + 6889*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 42603825571*uk_47 + 186111448547*uk_48 + 35876905744*uk_49 + 16*uk_5 + 329619071523*uk_50 + 486580534153*uk_51 + 186111448547*uk_52 + 187944057*uk_53 + 56681541*uk_54 + 247608837*uk_55 + 47731824*uk_56 + 438536133*uk_57 + 647362863*uk_58 + 247608837*uk_59 + 147*uk_6 + 17094433*uk_60 + 74675681*uk_61 + 14395312*uk_62 + 132256929*uk_63 + 195236419*uk_64 + 74675681*uk_65 + 326214817*uk_66 + 62884784*uk_67 + 577753953*uk_68 + 852874883*uk_69 + 217*uk_7 + 326214817*uk_70 + 12122368*uk_71 + 111374256*uk_72 + 164409616*uk_73 + 62884784*uk_74 + 1023250977*uk_75 + 1510513347*uk_76 + 577753953*uk_77 + 2229805417*uk_78 + 852874883*uk_79 + 83*uk_8 + 326214817*uk_80 + 250047*uk_81 + 75411*uk_82 + 329427*uk_83 + 63504*uk_84 + 583443*uk_85 + 861273*uk_86 + 329427*uk_87 + 22743*uk_88 + 99351*uk_89 + 2242306609*uk_9 + 19152*uk_90 + 175959*uk_91 + 259749*uk_92 + 99351*uk_93 + 434007*uk_94 + 83664*uk_95 + 768663*uk_96 + 1134693*uk_97 + 434007*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 187740*uk_100 + 273420*uk_101 + 23940*uk_102 + 1398663*uk_103 + 2036979*uk_104 + 178353*uk_105 + 2966607*uk_106 + 259749*uk_107 + 22743*uk_108 + 1728000*uk_109 + 5682360*uk_11 + 273600*uk_110 + 288000*uk_111 + 2145600*uk_112 + 3124800*uk_113 + 273600*uk_114 + 43320*uk_115 + 45600*uk_116 + 339720*uk_117 + 494760*uk_118 + 43320*uk_119 + 899707*uk_12 + 48000*uk_120 + 357600*uk_121 + 520800*uk_122 + 45600*uk_123 + 2664120*uk_124 + 3879960*uk_125 + 339720*uk_126 + 5650680*uk_127 + 494760*uk_128 + 43320*uk_129 + 947060*uk_13 + 6859*uk_130 + 7220*uk_131 + 53789*uk_132 + 78337*uk_133 + 6859*uk_134 + 7600*uk_135 + 56620*uk_136 + 82460*uk_137 + 7220*uk_138 + 421819*uk_139 + 7055597*uk_14 + 614327*uk_140 + 53789*uk_141 + 894691*uk_142 + 78337*uk_143 + 6859*uk_144 + 8000*uk_145 + 59600*uk_146 + 86800*uk_147 + 7600*uk_148 + 444020*uk_149 + 10275601*uk_15 + 646660*uk_150 + 56620*uk_151 + 941780*uk_152 + 82460*uk_153 + 7220*uk_154 + 3307949*uk_155 + 4817617*uk_156 + 421819*uk_157 + 7016261*uk_158 + 614327*uk_159 + 899707*uk_16 + 53789*uk_160 + 10218313*uk_161 + 894691*uk_162 + 78337*uk_163 + 6859*uk_164 + 3969*uk_17 + 7560*uk_18 + 1197*uk_19 + 63*uk_2 + 1260*uk_20 + 9387*uk_21 + 13671*uk_22 + 1197*uk_23 + 14400*uk_24 + 2280*uk_25 + 2400*uk_26 + 17880*uk_27 + 26040*uk_28 + 2280*uk_29 + 120*uk_3 + 361*uk_30 + 380*uk_31 + 2831*uk_32 + 4123*uk_33 + 361*uk_34 + 400*uk_35 + 2980*uk_36 + 4340*uk_37 + 380*uk_38 + 22201*uk_39 + 19*uk_4 + 32333*uk_40 + 2831*uk_41 + 47089*uk_42 + 4123*uk_43 + 361*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 269076793080*uk_47 + 42603825571*uk_48 + 44846132180*uk_49 + 20*uk_5 + 334103684741*uk_50 + 486580534153*uk_51 + 42603825571*uk_52 + 187944057*uk_53 + 357988680*uk_54 + 56681541*uk_55 + 59664780*uk_56 + 444502611*uk_57 + 647362863*uk_58 + 56681541*uk_59 + 149*uk_6 + 681883200*uk_60 + 107964840*uk_61 + 113647200*uk_62 + 846671640*uk_63 + 1233072120*uk_64 + 107964840*uk_65 + 17094433*uk_66 + 17994140*uk_67 + 134056343*uk_68 + 195236419*uk_69 + 217*uk_7 + 17094433*uk_70 + 18941200*uk_71 + 141111940*uk_72 + 205512020*uk_73 + 17994140*uk_74 + 1051283953*uk_75 + 1531064549*uk_76 + 134056343*uk_77 + 2229805417*uk_78 + 195236419*uk_79 + 19*uk_8 + 17094433*uk_80 + 250047*uk_81 + 476280*uk_82 + 75411*uk_83 + 79380*uk_84 + 591381*uk_85 + 861273*uk_86 + 75411*uk_87 + 907200*uk_88 + 143640*uk_89 + 2242306609*uk_9 + 151200*uk_90 + 1126440*uk_91 + 1640520*uk_92 + 143640*uk_93 + 22743*uk_94 + 23940*uk_95 + 178353*uk_96 + 259749*uk_97 + 22743*uk_98 + 25200*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 152208*uk_100 + 218736*uk_101 + 120960*uk_102 + 1436463*uk_103 + 2064321*uk_104 + 1141560*uk_105 + 2966607*uk_106 + 1640520*uk_107 + 907200*uk_108 + 729000*uk_109 + 4261770*uk_11 + 972000*uk_110 + 129600*uk_111 + 1223100*uk_112 + 1757700*uk_113 + 972000*uk_114 + 1296000*uk_115 + 172800*uk_116 + 1630800*uk_117 + 2343600*uk_118 + 1296000*uk_119 + 5682360*uk_12 + 23040*uk_120 + 217440*uk_121 + 312480*uk_122 + 172800*uk_123 + 2052090*uk_124 + 2949030*uk_125 + 1630800*uk_126 + 4238010*uk_127 + 2343600*uk_128 + 1296000*uk_129 + 757648*uk_13 + 1728000*uk_130 + 230400*uk_131 + 2174400*uk_132 + 3124800*uk_133 + 1728000*uk_134 + 30720*uk_135 + 289920*uk_136 + 416640*uk_137 + 230400*uk_138 + 2736120*uk_139 + 7150303*uk_14 + 3932040*uk_140 + 2174400*uk_141 + 5650680*uk_142 + 3124800*uk_143 + 1728000*uk_144 + 4096*uk_145 + 38656*uk_146 + 55552*uk_147 + 30720*uk_148 + 364816*uk_149 + 10275601*uk_15 + 524272*uk_150 + 289920*uk_151 + 753424*uk_152 + 416640*uk_153 + 230400*uk_154 + 3442951*uk_155 + 4947817*uk_156 + 2736120*uk_157 + 7110439*uk_158 + 3932040*uk_159 + 5682360*uk_16 + 2174400*uk_160 + 10218313*uk_161 + 5650680*uk_162 + 3124800*uk_163 + 1728000*uk_164 + 3969*uk_17 + 5670*uk_18 + 7560*uk_19 + 63*uk_2 + 1008*uk_20 + 9513*uk_21 + 13671*uk_22 + 7560*uk_23 + 8100*uk_24 + 10800*uk_25 + 1440*uk_26 + 13590*uk_27 + 19530*uk_28 + 10800*uk_29 + 90*uk_3 + 14400*uk_30 + 1920*uk_31 + 18120*uk_32 + 26040*uk_33 + 14400*uk_34 + 256*uk_35 + 2416*uk_36 + 3472*uk_37 + 1920*uk_38 + 22801*uk_39 + 120*uk_4 + 32767*uk_40 + 18120*uk_41 + 47089*uk_42 + 26040*uk_43 + 14400*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 201807594810*uk_47 + 269076793080*uk_48 + 35876905744*uk_49 + 16*uk_5 + 338588297959*uk_50 + 486580534153*uk_51 + 269076793080*uk_52 + 187944057*uk_53 + 268491510*uk_54 + 357988680*uk_55 + 47731824*uk_56 + 450469089*uk_57 + 647362863*uk_58 + 357988680*uk_59 + 151*uk_6 + 383559300*uk_60 + 511412400*uk_61 + 68188320*uk_62 + 643527270*uk_63 + 924804090*uk_64 + 511412400*uk_65 + 681883200*uk_66 + 90917760*uk_67 + 858036360*uk_68 + 1233072120*uk_69 + 217*uk_7 + 681883200*uk_70 + 12122368*uk_71 + 114404848*uk_72 + 164409616*uk_73 + 90917760*uk_74 + 1079695753*uk_75 + 1551615751*uk_76 + 858036360*uk_77 + 2229805417*uk_78 + 1233072120*uk_79 + 120*uk_8 + 681883200*uk_80 + 250047*uk_81 + 357210*uk_82 + 476280*uk_83 + 63504*uk_84 + 599319*uk_85 + 861273*uk_86 + 476280*uk_87 + 510300*uk_88 + 680400*uk_89 + 2242306609*uk_9 + 90720*uk_90 + 856170*uk_91 + 1230390*uk_92 + 680400*uk_93 + 907200*uk_94 + 120960*uk_95 + 1141560*uk_96 + 1640520*uk_97 + 907200*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 154224*uk_100 + 218736*uk_101 + 90720*uk_102 + 1474767*uk_103 + 2091663*uk_104 + 867510*uk_105 + 2966607*uk_106 + 1230390*uk_107 + 510300*uk_108 + 438976*uk_109 + 3598828*uk_11 + 519840*uk_110 + 92416*uk_111 + 883728*uk_112 + 1253392*uk_113 + 519840*uk_114 + 615600*uk_115 + 109440*uk_116 + 1046520*uk_117 + 1484280*uk_118 + 615600*uk_119 + 4261770*uk_12 + 19456*uk_120 + 186048*uk_121 + 263872*uk_122 + 109440*uk_123 + 1779084*uk_124 + 2523276*uk_125 + 1046520*uk_126 + 3578764*uk_127 + 1484280*uk_128 + 615600*uk_129 + 757648*uk_13 + 729000*uk_130 + 129600*uk_131 + 1239300*uk_132 + 1757700*uk_133 + 729000*uk_134 + 23040*uk_135 + 220320*uk_136 + 312480*uk_137 + 129600*uk_138 + 2106810*uk_139 + 7245009*uk_14 + 2988090*uk_140 + 1239300*uk_141 + 4238010*uk_142 + 1757700*uk_143 + 729000*uk_144 + 4096*uk_145 + 39168*uk_146 + 55552*uk_147 + 23040*uk_148 + 374544*uk_149 + 10275601*uk_15 + 531216*uk_150 + 220320*uk_151 + 753424*uk_152 + 312480*uk_153 + 129600*uk_154 + 3581577*uk_155 + 5079753*uk_156 + 2106810*uk_157 + 7204617*uk_158 + 2988090*uk_159 + 4261770*uk_16 + 1239300*uk_160 + 10218313*uk_161 + 4238010*uk_162 + 1757700*uk_163 + 729000*uk_164 + 3969*uk_17 + 4788*uk_18 + 5670*uk_19 + 63*uk_2 + 1008*uk_20 + 9639*uk_21 + 13671*uk_22 + 5670*uk_23 + 5776*uk_24 + 6840*uk_25 + 1216*uk_26 + 11628*uk_27 + 16492*uk_28 + 6840*uk_29 + 76*uk_3 + 8100*uk_30 + 1440*uk_31 + 13770*uk_32 + 19530*uk_33 + 8100*uk_34 + 256*uk_35 + 2448*uk_36 + 3472*uk_37 + 1440*uk_38 + 23409*uk_39 + 90*uk_4 + 33201*uk_40 + 13770*uk_41 + 47089*uk_42 + 19530*uk_43 + 8100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 170415302284*uk_47 + 201807594810*uk_48 + 35876905744*uk_49 + 16*uk_5 + 343072911177*uk_50 + 486580534153*uk_51 + 201807594810*uk_52 + 187944057*uk_53 + 226726164*uk_54 + 268491510*uk_55 + 47731824*uk_56 + 456435567*uk_57 + 647362863*uk_58 + 268491510*uk_59 + 153*uk_6 + 273510928*uk_60 + 323894520*uk_61 + 57581248*uk_62 + 550620684*uk_63 + 780945676*uk_64 + 323894520*uk_65 + 383559300*uk_66 + 68188320*uk_67 + 652050810*uk_68 + 924804090*uk_69 + 217*uk_7 + 383559300*uk_70 + 12122368*uk_71 + 115920144*uk_72 + 164409616*uk_73 + 68188320*uk_74 + 1108486377*uk_75 + 1572166953*uk_76 + 652050810*uk_77 + 2229805417*uk_78 + 924804090*uk_79 + 90*uk_8 + 383559300*uk_80 + 250047*uk_81 + 301644*uk_82 + 357210*uk_83 + 63504*uk_84 + 607257*uk_85 + 861273*uk_86 + 357210*uk_87 + 363888*uk_88 + 430920*uk_89 + 2242306609*uk_9 + 76608*uk_90 + 732564*uk_91 + 1038996*uk_92 + 430920*uk_93 + 510300*uk_94 + 90720*uk_95 + 867510*uk_96 + 1230390*uk_97 + 510300*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 156240*uk_100 + 218736*uk_101 + 76608*uk_102 + 1513575*uk_103 + 2119005*uk_104 + 742140*uk_105 + 2966607*uk_106 + 1038996*uk_107 + 363888*uk_108 + 474552*uk_109 + 3693534*uk_11 + 462384*uk_110 + 97344*uk_111 + 943020*uk_112 + 1320228*uk_113 + 462384*uk_114 + 450528*uk_115 + 94848*uk_116 + 918840*uk_117 + 1286376*uk_118 + 450528*uk_119 + 3598828*uk_12 + 19968*uk_120 + 193440*uk_121 + 270816*uk_122 + 94848*uk_123 + 1873950*uk_124 + 2623530*uk_125 + 918840*uk_126 + 3672942*uk_127 + 1286376*uk_128 + 450528*uk_129 + 757648*uk_13 + 438976*uk_130 + 92416*uk_131 + 895280*uk_132 + 1253392*uk_133 + 438976*uk_134 + 19456*uk_135 + 188480*uk_136 + 263872*uk_137 + 92416*uk_138 + 1825900*uk_139 + 7339715*uk_14 + 2556260*uk_140 + 895280*uk_141 + 3578764*uk_142 + 1253392*uk_143 + 438976*uk_144 + 4096*uk_145 + 39680*uk_146 + 55552*uk_147 + 19456*uk_148 + 384400*uk_149 + 10275601*uk_15 + 538160*uk_150 + 188480*uk_151 + 753424*uk_152 + 263872*uk_153 + 92416*uk_154 + 3723875*uk_155 + 5213425*uk_156 + 1825900*uk_157 + 7298795*uk_158 + 2556260*uk_159 + 3598828*uk_16 + 895280*uk_160 + 10218313*uk_161 + 3578764*uk_162 + 1253392*uk_163 + 438976*uk_164 + 3969*uk_17 + 4914*uk_18 + 4788*uk_19 + 63*uk_2 + 1008*uk_20 + 9765*uk_21 + 13671*uk_22 + 4788*uk_23 + 6084*uk_24 + 5928*uk_25 + 1248*uk_26 + 12090*uk_27 + 16926*uk_28 + 5928*uk_29 + 78*uk_3 + 5776*uk_30 + 1216*uk_31 + 11780*uk_32 + 16492*uk_33 + 5776*uk_34 + 256*uk_35 + 2480*uk_36 + 3472*uk_37 + 1216*uk_38 + 24025*uk_39 + 76*uk_4 + 33635*uk_40 + 11780*uk_41 + 47089*uk_42 + 16492*uk_43 + 5776*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 174899915502*uk_47 + 170415302284*uk_48 + 35876905744*uk_49 + 16*uk_5 + 347557524395*uk_50 + 486580534153*uk_51 + 170415302284*uk_52 + 187944057*uk_53 + 232692642*uk_54 + 226726164*uk_55 + 47731824*uk_56 + 462402045*uk_57 + 647362863*uk_58 + 226726164*uk_59 + 155*uk_6 + 288095652*uk_60 + 280708584*uk_61 + 59096544*uk_62 + 572497770*uk_63 + 801496878*uk_64 + 280708584*uk_65 + 273510928*uk_66 + 57581248*uk_67 + 557818340*uk_68 + 780945676*uk_69 + 217*uk_7 + 273510928*uk_70 + 12122368*uk_71 + 117435440*uk_72 + 164409616*uk_73 + 57581248*uk_74 + 1137655825*uk_75 + 1592718155*uk_76 + 557818340*uk_77 + 2229805417*uk_78 + 780945676*uk_79 + 76*uk_8 + 273510928*uk_80 + 250047*uk_81 + 309582*uk_82 + 301644*uk_83 + 63504*uk_84 + 615195*uk_85 + 861273*uk_86 + 301644*uk_87 + 383292*uk_88 + 373464*uk_89 + 2242306609*uk_9 + 78624*uk_90 + 761670*uk_91 + 1066338*uk_92 + 373464*uk_93 + 363888*uk_94 + 76608*uk_95 + 742140*uk_96 + 1038996*uk_97 + 363888*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 158256*uk_100 + 218736*uk_101 + 78624*uk_102 + 1552887*uk_103 + 2146347*uk_104 + 771498*uk_105 + 2966607*uk_106 + 1066338*uk_107 + 383292*uk_108 + 884736*uk_109 + 4545888*uk_11 + 718848*uk_110 + 147456*uk_111 + 1446912*uk_112 + 1999872*uk_113 + 718848*uk_114 + 584064*uk_115 + 119808*uk_116 + 1175616*uk_117 + 1624896*uk_118 + 584064*uk_119 + 3693534*uk_12 + 24576*uk_120 + 241152*uk_121 + 333312*uk_122 + 119808*uk_123 + 2366304*uk_124 + 3270624*uk_125 + 1175616*uk_126 + 4520544*uk_127 + 1624896*uk_128 + 584064*uk_129 + 757648*uk_13 + 474552*uk_130 + 97344*uk_131 + 955188*uk_132 + 1320228*uk_133 + 474552*uk_134 + 19968*uk_135 + 195936*uk_136 + 270816*uk_137 + 97344*uk_138 + 1922622*uk_139 + 7434421*uk_14 + 2657382*uk_140 + 955188*uk_141 + 3672942*uk_142 + 1320228*uk_143 + 474552*uk_144 + 4096*uk_145 + 40192*uk_146 + 55552*uk_147 + 19968*uk_148 + 394384*uk_149 + 10275601*uk_15 + 545104*uk_150 + 195936*uk_151 + 753424*uk_152 + 270816*uk_153 + 97344*uk_154 + 3869893*uk_155 + 5348833*uk_156 + 1922622*uk_157 + 7392973*uk_158 + 2657382*uk_159 + 3693534*uk_16 + 955188*uk_160 + 10218313*uk_161 + 3672942*uk_162 + 1320228*uk_163 + 474552*uk_164 + 3969*uk_17 + 6048*uk_18 + 4914*uk_19 + 63*uk_2 + 1008*uk_20 + 9891*uk_21 + 13671*uk_22 + 4914*uk_23 + 9216*uk_24 + 7488*uk_25 + 1536*uk_26 + 15072*uk_27 + 20832*uk_28 + 7488*uk_29 + 96*uk_3 + 6084*uk_30 + 1248*uk_31 + 12246*uk_32 + 16926*uk_33 + 6084*uk_34 + 256*uk_35 + 2512*uk_36 + 3472*uk_37 + 1248*uk_38 + 24649*uk_39 + 78*uk_4 + 34069*uk_40 + 12246*uk_41 + 47089*uk_42 + 16926*uk_43 + 6084*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 215261434464*uk_47 + 174899915502*uk_48 + 35876905744*uk_49 + 16*uk_5 + 352042137613*uk_50 + 486580534153*uk_51 + 174899915502*uk_52 + 187944057*uk_53 + 286390944*uk_54 + 232692642*uk_55 + 47731824*uk_56 + 468368523*uk_57 + 647362863*uk_58 + 232692642*uk_59 + 157*uk_6 + 436405248*uk_60 + 354579264*uk_61 + 72734208*uk_62 + 713704416*uk_63 + 986457696*uk_64 + 354579264*uk_65 + 288095652*uk_66 + 59096544*uk_67 + 579884838*uk_68 + 801496878*uk_69 + 217*uk_7 + 288095652*uk_70 + 12122368*uk_71 + 118950736*uk_72 + 164409616*uk_73 + 59096544*uk_74 + 1167204097*uk_75 + 1613269357*uk_76 + 579884838*uk_77 + 2229805417*uk_78 + 801496878*uk_79 + 78*uk_8 + 288095652*uk_80 + 250047*uk_81 + 381024*uk_82 + 309582*uk_83 + 63504*uk_84 + 623133*uk_85 + 861273*uk_86 + 309582*uk_87 + 580608*uk_88 + 471744*uk_89 + 2242306609*uk_9 + 96768*uk_90 + 949536*uk_91 + 1312416*uk_92 + 471744*uk_93 + 383292*uk_94 + 78624*uk_95 + 771498*uk_96 + 1066338*uk_97 + 383292*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 160272*uk_100 + 218736*uk_101 + 96768*uk_102 + 1592703*uk_103 + 2173689*uk_104 + 961632*uk_105 + 2966607*uk_106 + 1312416*uk_107 + 580608*uk_108 + 2197000*uk_109 + 6155890*uk_11 + 1622400*uk_110 + 270400*uk_111 + 2687100*uk_112 + 3667300*uk_113 + 1622400*uk_114 + 1198080*uk_115 + 199680*uk_116 + 1984320*uk_117 + 2708160*uk_118 + 1198080*uk_119 + 4545888*uk_12 + 33280*uk_120 + 330720*uk_121 + 451360*uk_122 + 199680*uk_123 + 3286530*uk_124 + 4485390*uk_125 + 1984320*uk_126 + 6121570*uk_127 + 2708160*uk_128 + 1198080*uk_129 + 757648*uk_13 + 884736*uk_130 + 147456*uk_131 + 1465344*uk_132 + 1999872*uk_133 + 884736*uk_134 + 24576*uk_135 + 244224*uk_136 + 333312*uk_137 + 147456*uk_138 + 2426976*uk_139 + 7529127*uk_14 + 3312288*uk_140 + 1465344*uk_141 + 4520544*uk_142 + 1999872*uk_143 + 884736*uk_144 + 4096*uk_145 + 40704*uk_146 + 55552*uk_147 + 24576*uk_148 + 404496*uk_149 + 10275601*uk_15 + 552048*uk_150 + 244224*uk_151 + 753424*uk_152 + 333312*uk_153 + 147456*uk_154 + 4019679*uk_155 + 5485977*uk_156 + 2426976*uk_157 + 7487151*uk_158 + 3312288*uk_159 + 4545888*uk_16 + 1465344*uk_160 + 10218313*uk_161 + 4520544*uk_162 + 1999872*uk_163 + 884736*uk_164 + 3969*uk_17 + 8190*uk_18 + 6048*uk_19 + 63*uk_2 + 1008*uk_20 + 10017*uk_21 + 13671*uk_22 + 6048*uk_23 + 16900*uk_24 + 12480*uk_25 + 2080*uk_26 + 20670*uk_27 + 28210*uk_28 + 12480*uk_29 + 130*uk_3 + 9216*uk_30 + 1536*uk_31 + 15264*uk_32 + 20832*uk_33 + 9216*uk_34 + 256*uk_35 + 2544*uk_36 + 3472*uk_37 + 1536*uk_38 + 25281*uk_39 + 96*uk_4 + 34503*uk_40 + 15264*uk_41 + 47089*uk_42 + 20832*uk_43 + 9216*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 291499859170*uk_47 + 215261434464*uk_48 + 35876905744*uk_49 + 16*uk_5 + 356526750831*uk_50 + 486580534153*uk_51 + 215261434464*uk_52 + 187944057*uk_53 + 387821070*uk_54 + 286390944*uk_55 + 47731824*uk_56 + 474335001*uk_57 + 647362863*uk_58 + 286390944*uk_59 + 159*uk_6 + 800265700*uk_60 + 590965440*uk_61 + 98494240*uk_62 + 978786510*uk_63 + 1335828130*uk_64 + 590965440*uk_65 + 436405248*uk_66 + 72734208*uk_67 + 722796192*uk_68 + 986457696*uk_69 + 217*uk_7 + 436405248*uk_70 + 12122368*uk_71 + 120466032*uk_72 + 164409616*uk_73 + 72734208*uk_74 + 1197131193*uk_75 + 1633820559*uk_76 + 722796192*uk_77 + 2229805417*uk_78 + 986457696*uk_79 + 96*uk_8 + 436405248*uk_80 + 250047*uk_81 + 515970*uk_82 + 381024*uk_83 + 63504*uk_84 + 631071*uk_85 + 861273*uk_86 + 381024*uk_87 + 1064700*uk_88 + 786240*uk_89 + 2242306609*uk_9 + 131040*uk_90 + 1302210*uk_91 + 1777230*uk_92 + 786240*uk_93 + 580608*uk_94 + 96768*uk_95 + 961632*uk_96 + 1312416*uk_97 + 580608*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 121716*uk_100 + 164052*uk_101 + 98280*uk_102 + 1633023*uk_103 + 2201031*uk_104 + 1318590*uk_105 + 2966607*uk_106 + 1777230*uk_107 + 1064700*uk_108 + 6859*uk_109 + 899707*uk_11 + 46930*uk_110 + 4332*uk_111 + 58121*uk_112 + 78337*uk_113 + 46930*uk_114 + 321100*uk_115 + 29640*uk_116 + 397670*uk_117 + 535990*uk_118 + 321100*uk_119 + 6155890*uk_12 + 2736*uk_120 + 36708*uk_121 + 49476*uk_122 + 29640*uk_123 + 492499*uk_124 + 663803*uk_125 + 397670*uk_126 + 894691*uk_127 + 535990*uk_128 + 321100*uk_129 + 568236*uk_13 + 2197000*uk_130 + 202800*uk_131 + 2720900*uk_132 + 3667300*uk_133 + 2197000*uk_134 + 18720*uk_135 + 251160*uk_136 + 338520*uk_137 + 202800*uk_138 + 3369730*uk_139 + 7623833*uk_14 + 4541810*uk_140 + 2720900*uk_141 + 6121570*uk_142 + 3667300*uk_143 + 2197000*uk_144 + 1728*uk_145 + 23184*uk_146 + 31248*uk_147 + 18720*uk_148 + 311052*uk_149 + 10275601*uk_15 + 419244*uk_150 + 251160*uk_151 + 565068*uk_152 + 338520*uk_153 + 202800*uk_154 + 4173281*uk_155 + 5624857*uk_156 + 3369730*uk_157 + 7581329*uk_158 + 4541810*uk_159 + 6155890*uk_16 + 2720900*uk_160 + 10218313*uk_161 + 6121570*uk_162 + 3667300*uk_163 + 2197000*uk_164 + 3969*uk_17 + 1197*uk_18 + 8190*uk_19 + 63*uk_2 + 756*uk_20 + 10143*uk_21 + 13671*uk_22 + 8190*uk_23 + 361*uk_24 + 2470*uk_25 + 228*uk_26 + 3059*uk_27 + 4123*uk_28 + 2470*uk_29 + 19*uk_3 + 16900*uk_30 + 1560*uk_31 + 20930*uk_32 + 28210*uk_33 + 16900*uk_34 + 144*uk_35 + 1932*uk_36 + 2604*uk_37 + 1560*uk_38 + 25921*uk_39 + 130*uk_4 + 34937*uk_40 + 20930*uk_41 + 47089*uk_42 + 28210*uk_43 + 16900*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 42603825571*uk_47 + 291499859170*uk_48 + 26907679308*uk_49 + 12*uk_5 + 361011364049*uk_50 + 486580534153*uk_51 + 291499859170*uk_52 + 187944057*uk_53 + 56681541*uk_54 + 387821070*uk_55 + 35798868*uk_56 + 480301479*uk_57 + 647362863*uk_58 + 387821070*uk_59 + 161*uk_6 + 17094433*uk_60 + 116961910*uk_61 + 10796484*uk_62 + 144852827*uk_63 + 195236419*uk_64 + 116961910*uk_65 + 800265700*uk_66 + 73870680*uk_67 + 991098290*uk_68 + 1335828130*uk_69 + 217*uk_7 + 800265700*uk_70 + 6818832*uk_71 + 91485996*uk_72 + 123307212*uk_73 + 73870680*uk_74 + 1227437113*uk_75 + 1654371761*uk_76 + 991098290*uk_77 + 2229805417*uk_78 + 1335828130*uk_79 + 130*uk_8 + 800265700*uk_80 + 250047*uk_81 + 75411*uk_82 + 515970*uk_83 + 47628*uk_84 + 639009*uk_85 + 861273*uk_86 + 515970*uk_87 + 22743*uk_88 + 155610*uk_89 + 2242306609*uk_9 + 14364*uk_90 + 192717*uk_91 + 259749*uk_92 + 155610*uk_93 + 1064700*uk_94 + 98280*uk_95 + 1318590*uk_96 + 1777230*uk_97 + 1064700*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 164304*uk_100 + 218736*uk_101 + 19152*uk_102 + 1673847*uk_103 + 2228373*uk_104 + 195111*uk_105 + 2966607*uk_106 + 259749*uk_107 + 22743*uk_108 + 571787*uk_109 + 3930299*uk_11 + 130891*uk_110 + 110224*uk_111 + 1122907*uk_112 + 1494913*uk_113 + 130891*uk_114 + 29963*uk_115 + 25232*uk_116 + 257051*uk_117 + 342209*uk_118 + 29963*uk_119 + 899707*uk_12 + 21248*uk_120 + 216464*uk_121 + 288176*uk_122 + 25232*uk_123 + 2205227*uk_124 + 2935793*uk_125 + 257051*uk_126 + 3908387*uk_127 + 342209*uk_128 + 29963*uk_129 + 757648*uk_13 + 6859*uk_130 + 5776*uk_131 + 58843*uk_132 + 78337*uk_133 + 6859*uk_134 + 4864*uk_135 + 49552*uk_136 + 65968*uk_137 + 5776*uk_138 + 504811*uk_139 + 7718539*uk_14 + 672049*uk_140 + 58843*uk_141 + 894691*uk_142 + 78337*uk_143 + 6859*uk_144 + 4096*uk_145 + 41728*uk_146 + 55552*uk_147 + 4864*uk_148 + 425104*uk_149 + 10275601*uk_15 + 565936*uk_150 + 49552*uk_151 + 753424*uk_152 + 65968*uk_153 + 5776*uk_154 + 4330747*uk_155 + 5765473*uk_156 + 504811*uk_157 + 7675507*uk_158 + 672049*uk_159 + 899707*uk_16 + 58843*uk_160 + 10218313*uk_161 + 894691*uk_162 + 78337*uk_163 + 6859*uk_164 + 3969*uk_17 + 5229*uk_18 + 1197*uk_19 + 63*uk_2 + 1008*uk_20 + 10269*uk_21 + 13671*uk_22 + 1197*uk_23 + 6889*uk_24 + 1577*uk_25 + 1328*uk_26 + 13529*uk_27 + 18011*uk_28 + 1577*uk_29 + 83*uk_3 + 361*uk_30 + 304*uk_31 + 3097*uk_32 + 4123*uk_33 + 361*uk_34 + 256*uk_35 + 2608*uk_36 + 3472*uk_37 + 304*uk_38 + 26569*uk_39 + 19*uk_4 + 35371*uk_40 + 3097*uk_41 + 47089*uk_42 + 4123*uk_43 + 361*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 186111448547*uk_47 + 42603825571*uk_48 + 35876905744*uk_49 + 16*uk_5 + 365495977267*uk_50 + 486580534153*uk_51 + 42603825571*uk_52 + 187944057*uk_53 + 247608837*uk_54 + 56681541*uk_55 + 47731824*uk_56 + 486267957*uk_57 + 647362863*uk_58 + 56681541*uk_59 + 163*uk_6 + 326214817*uk_60 + 74675681*uk_61 + 62884784*uk_62 + 640638737*uk_63 + 852874883*uk_64 + 74675681*uk_65 + 17094433*uk_66 + 14395312*uk_67 + 146652241*uk_68 + 195236419*uk_69 + 217*uk_7 + 17094433*uk_70 + 12122368*uk_71 + 123496624*uk_72 + 164409616*uk_73 + 14395312*uk_74 + 1258121857*uk_75 + 1674922963*uk_76 + 146652241*uk_77 + 2229805417*uk_78 + 195236419*uk_79 + 19*uk_8 + 17094433*uk_80 + 250047*uk_81 + 329427*uk_82 + 75411*uk_83 + 63504*uk_84 + 646947*uk_85 + 861273*uk_86 + 75411*uk_87 + 434007*uk_88 + 99351*uk_89 + 2242306609*uk_9 + 83664*uk_90 + 852327*uk_91 + 1134693*uk_92 + 99351*uk_93 + 22743*uk_94 + 19152*uk_95 + 195111*uk_96 + 259749*uk_97 + 22743*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 166320*uk_100 + 218736*uk_101 + 83664*uk_102 + 1715175*uk_103 + 2255715*uk_104 + 862785*uk_105 + 2966607*uk_106 + 1134693*uk_107 + 434007*uk_108 + 4330747*uk_109 + 7718539*uk_11 + 2205227*uk_110 + 425104*uk_111 + 4383885*uk_112 + 5765473*uk_113 + 2205227*uk_114 + 1122907*uk_115 + 216464*uk_116 + 2232285*uk_117 + 2935793*uk_118 + 1122907*uk_119 + 3930299*uk_12 + 41728*uk_120 + 430320*uk_121 + 565936*uk_122 + 216464*uk_123 + 4437675*uk_124 + 5836215*uk_125 + 2232285*uk_126 + 7675507*uk_127 + 2935793*uk_128 + 1122907*uk_129 + 757648*uk_13 + 571787*uk_130 + 110224*uk_131 + 1136685*uk_132 + 1494913*uk_133 + 571787*uk_134 + 21248*uk_135 + 219120*uk_136 + 288176*uk_137 + 110224*uk_138 + 2259675*uk_139 + 7813245*uk_14 + 2971815*uk_140 + 1136685*uk_141 + 3908387*uk_142 + 1494913*uk_143 + 571787*uk_144 + 4096*uk_145 + 42240*uk_146 + 55552*uk_147 + 21248*uk_148 + 435600*uk_149 + 10275601*uk_15 + 572880*uk_150 + 219120*uk_151 + 753424*uk_152 + 288176*uk_153 + 110224*uk_154 + 4492125*uk_155 + 5907825*uk_156 + 2259675*uk_157 + 7769685*uk_158 + 2971815*uk_159 + 3930299*uk_16 + 1136685*uk_160 + 10218313*uk_161 + 3908387*uk_162 + 1494913*uk_163 + 571787*uk_164 + 3969*uk_17 + 10269*uk_18 + 5229*uk_19 + 63*uk_2 + 1008*uk_20 + 10395*uk_21 + 13671*uk_22 + 5229*uk_23 + 26569*uk_24 + 13529*uk_25 + 2608*uk_26 + 26895*uk_27 + 35371*uk_28 + 13529*uk_29 + 163*uk_3 + 6889*uk_30 + 1328*uk_31 + 13695*uk_32 + 18011*uk_33 + 6889*uk_34 + 256*uk_35 + 2640*uk_36 + 3472*uk_37 + 1328*uk_38 + 27225*uk_39 + 83*uk_4 + 35805*uk_40 + 13695*uk_41 + 47089*uk_42 + 18011*uk_43 + 6889*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 365495977267*uk_47 + 186111448547*uk_48 + 35876905744*uk_49 + 16*uk_5 + 369980590485*uk_50 + 486580534153*uk_51 + 186111448547*uk_52 + 187944057*uk_53 + 486267957*uk_54 + 247608837*uk_55 + 47731824*uk_56 + 492234435*uk_57 + 647362863*uk_58 + 247608837*uk_59 + 165*uk_6 + 1258121857*uk_60 + 640638737*uk_61 + 123496624*uk_62 + 1273558935*uk_63 + 1674922963*uk_64 + 640638737*uk_65 + 326214817*uk_66 + 62884784*uk_67 + 648499335*uk_68 + 852874883*uk_69 + 217*uk_7 + 326214817*uk_70 + 12122368*uk_71 + 125011920*uk_72 + 164409616*uk_73 + 62884784*uk_74 + 1289185425*uk_75 + 1695474165*uk_76 + 648499335*uk_77 + 2229805417*uk_78 + 852874883*uk_79 + 83*uk_8 + 326214817*uk_80 + 250047*uk_81 + 646947*uk_82 + 329427*uk_83 + 63504*uk_84 + 654885*uk_85 + 861273*uk_86 + 329427*uk_87 + 1673847*uk_88 + 852327*uk_89 + 2242306609*uk_9 + 164304*uk_90 + 1694385*uk_91 + 2228373*uk_92 + 852327*uk_93 + 434007*uk_94 + 83664*uk_95 + 862785*uk_96 + 1134693*uk_97 + 434007*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 126252*uk_100 + 164052*uk_101 + 123228*uk_102 + 1757007*uk_103 + 2283057*uk_104 + 1714923*uk_105 + 2966607*uk_106 + 2228373*uk_107 + 1673847*uk_108 + 778688*uk_109 + 4356476*uk_11 + 1379632*uk_110 + 101568*uk_111 + 1413488*uk_112 + 1836688*uk_113 + 1379632*uk_114 + 2444348*uk_115 + 179952*uk_116 + 2504332*uk_117 + 3254132*uk_118 + 2444348*uk_119 + 7718539*uk_12 + 13248*uk_120 + 184368*uk_121 + 239568*uk_122 + 179952*uk_123 + 2565788*uk_124 + 3333988*uk_125 + 2504332*uk_126 + 4332188*uk_127 + 3254132*uk_128 + 2444348*uk_129 + 568236*uk_13 + 4330747*uk_130 + 318828*uk_131 + 4437023*uk_132 + 5765473*uk_133 + 4330747*uk_134 + 23472*uk_135 + 326652*uk_136 + 424452*uk_137 + 318828*uk_138 + 4545907*uk_139 + 7907951*uk_14 + 5906957*uk_140 + 4437023*uk_141 + 7675507*uk_142 + 5765473*uk_143 + 4330747*uk_144 + 1728*uk_145 + 24048*uk_146 + 31248*uk_147 + 23472*uk_148 + 334668*uk_149 + 10275601*uk_15 + 434868*uk_150 + 326652*uk_151 + 565068*uk_152 + 424452*uk_153 + 318828*uk_154 + 4657463*uk_155 + 6051913*uk_156 + 4545907*uk_157 + 7863863*uk_158 + 5906957*uk_159 + 7718539*uk_16 + 4437023*uk_160 + 10218313*uk_161 + 7675507*uk_162 + 5765473*uk_163 + 4330747*uk_164 + 3969*uk_17 + 5796*uk_18 + 10269*uk_19 + 63*uk_2 + 756*uk_20 + 10521*uk_21 + 13671*uk_22 + 10269*uk_23 + 8464*uk_24 + 14996*uk_25 + 1104*uk_26 + 15364*uk_27 + 19964*uk_28 + 14996*uk_29 + 92*uk_3 + 26569*uk_30 + 1956*uk_31 + 27221*uk_32 + 35371*uk_33 + 26569*uk_34 + 144*uk_35 + 2004*uk_36 + 2604*uk_37 + 1956*uk_38 + 27889*uk_39 + 163*uk_4 + 36239*uk_40 + 27221*uk_41 + 47089*uk_42 + 35371*uk_43 + 26569*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 206292208028*uk_47 + 365495977267*uk_48 + 26907679308*uk_49 + 12*uk_5 + 374465203703*uk_50 + 486580534153*uk_51 + 365495977267*uk_52 + 187944057*uk_53 + 274457988*uk_54 + 486267957*uk_55 + 35798868*uk_56 + 498200913*uk_57 + 647362863*uk_58 + 486267957*uk_59 + 167*uk_6 + 400795792*uk_60 + 710105588*uk_61 + 52277712*uk_62 + 727531492*uk_63 + 945355292*uk_64 + 710105588*uk_65 + 1258121857*uk_66 + 92622468*uk_67 + 1288996013*uk_68 + 1674922963*uk_69 + 217*uk_7 + 1258121857*uk_70 + 6818832*uk_71 + 94895412*uk_72 + 123307212*uk_73 + 92622468*uk_74 + 1320627817*uk_75 + 1716025367*uk_76 + 1288996013*uk_77 + 2229805417*uk_78 + 1674922963*uk_79 + 163*uk_8 + 1258121857*uk_80 + 250047*uk_81 + 365148*uk_82 + 646947*uk_83 + 47628*uk_84 + 662823*uk_85 + 861273*uk_86 + 646947*uk_87 + 533232*uk_88 + 944748*uk_89 + 2242306609*uk_9 + 69552*uk_90 + 967932*uk_91 + 1257732*uk_92 + 944748*uk_93 + 1673847*uk_94 + 123228*uk_95 + 1714923*uk_96 + 2228373*uk_97 + 1673847*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 127764*uk_100 + 164052*uk_101 + 69552*uk_102 + 1799343*uk_103 + 2310399*uk_104 + 979524*uk_105 + 2966607*uk_106 + 1257732*uk_107 + 533232*uk_108 + 35937*uk_109 + 1562649*uk_11 + 100188*uk_110 + 13068*uk_111 + 184041*uk_112 + 236313*uk_113 + 100188*uk_114 + 279312*uk_115 + 36432*uk_116 + 513084*uk_117 + 658812*uk_118 + 279312*uk_119 + 4356476*uk_12 + 4752*uk_120 + 66924*uk_121 + 85932*uk_122 + 36432*uk_123 + 942513*uk_124 + 1210209*uk_125 + 513084*uk_126 + 1553937*uk_127 + 658812*uk_128 + 279312*uk_129 + 568236*uk_13 + 778688*uk_130 + 101568*uk_131 + 1430416*uk_132 + 1836688*uk_133 + 778688*uk_134 + 13248*uk_135 + 186576*uk_136 + 239568*uk_137 + 101568*uk_138 + 2627612*uk_139 + 8002657*uk_14 + 3373916*uk_140 + 1430416*uk_141 + 4332188*uk_142 + 1836688*uk_143 + 778688*uk_144 + 1728*uk_145 + 24336*uk_146 + 31248*uk_147 + 13248*uk_148 + 342732*uk_149 + 10275601*uk_15 + 440076*uk_150 + 186576*uk_151 + 565068*uk_152 + 239568*uk_153 + 101568*uk_154 + 4826809*uk_155 + 6197737*uk_156 + 2627612*uk_157 + 7958041*uk_158 + 3373916*uk_159 + 4356476*uk_16 + 1430416*uk_160 + 10218313*uk_161 + 4332188*uk_162 + 1836688*uk_163 + 778688*uk_164 + 3969*uk_17 + 2079*uk_18 + 5796*uk_19 + 63*uk_2 + 756*uk_20 + 10647*uk_21 + 13671*uk_22 + 5796*uk_23 + 1089*uk_24 + 3036*uk_25 + 396*uk_26 + 5577*uk_27 + 7161*uk_28 + 3036*uk_29 + 33*uk_3 + 8464*uk_30 + 1104*uk_31 + 15548*uk_32 + 19964*uk_33 + 8464*uk_34 + 144*uk_35 + 2028*uk_36 + 2604*uk_37 + 1104*uk_38 + 28561*uk_39 + 92*uk_4 + 36673*uk_40 + 15548*uk_41 + 47089*uk_42 + 19964*uk_43 + 8464*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 73996118097*uk_47 + 206292208028*uk_48 + 26907679308*uk_49 + 12*uk_5 + 378949816921*uk_50 + 486580534153*uk_51 + 206292208028*uk_52 + 187944057*uk_53 + 98446887*uk_54 + 274457988*uk_55 + 35798868*uk_56 + 504167391*uk_57 + 647362863*uk_58 + 274457988*uk_59 + 169*uk_6 + 51567417*uk_60 + 143763708*uk_61 + 18751788*uk_62 + 264087681*uk_63 + 339094833*uk_64 + 143763708*uk_65 + 400795792*uk_66 + 52277712*uk_67 + 736244444*uk_68 + 945355292*uk_69 + 217*uk_7 + 400795792*uk_70 + 6818832*uk_71 + 96031884*uk_72 + 123307212*uk_73 + 52277712*uk_74 + 1352449033*uk_75 + 1736576569*uk_76 + 736244444*uk_77 + 2229805417*uk_78 + 945355292*uk_79 + 92*uk_8 + 400795792*uk_80 + 250047*uk_81 + 130977*uk_82 + 365148*uk_83 + 47628*uk_84 + 670761*uk_85 + 861273*uk_86 + 365148*uk_87 + 68607*uk_88 + 191268*uk_89 + 2242306609*uk_9 + 24948*uk_90 + 351351*uk_91 + 451143*uk_92 + 191268*uk_93 + 533232*uk_94 + 69552*uk_95 + 979524*uk_96 + 1257732*uk_97 + 533232*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 172368*uk_100 + 218736*uk_101 + 33264*uk_102 + 1842183*uk_103 + 2337741*uk_104 + 355509*uk_105 + 2966607*uk_106 + 451143*uk_107 + 68607*uk_108 + 3869893*uk_109 + 7434421*uk_11 + 813417*uk_110 + 394384*uk_111 + 4214979*uk_112 + 5348833*uk_113 + 813417*uk_114 + 170973*uk_115 + 82896*uk_116 + 885951*uk_117 + 1124277*uk_118 + 170973*uk_119 + 1562649*uk_12 + 40192*uk_120 + 429552*uk_121 + 545104*uk_122 + 82896*uk_123 + 4590837*uk_124 + 5825799*uk_125 + 885951*uk_126 + 7392973*uk_127 + 1124277*uk_128 + 170973*uk_129 + 757648*uk_13 + 35937*uk_130 + 17424*uk_131 + 186219*uk_132 + 236313*uk_133 + 35937*uk_134 + 8448*uk_135 + 90288*uk_136 + 114576*uk_137 + 17424*uk_138 + 964953*uk_139 + 8097363*uk_14 + 1224531*uk_140 + 186219*uk_141 + 1553937*uk_142 + 236313*uk_143 + 35937*uk_144 + 4096*uk_145 + 43776*uk_146 + 55552*uk_147 + 8448*uk_148 + 467856*uk_149 + 10275601*uk_15 + 593712*uk_150 + 90288*uk_151 + 753424*uk_152 + 114576*uk_153 + 17424*uk_154 + 5000211*uk_155 + 6345297*uk_156 + 964953*uk_157 + 8052219*uk_158 + 1224531*uk_159 + 1562649*uk_16 + 186219*uk_160 + 10218313*uk_161 + 1553937*uk_162 + 236313*uk_163 + 35937*uk_164 + 3969*uk_17 + 9891*uk_18 + 2079*uk_19 + 63*uk_2 + 1008*uk_20 + 10773*uk_21 + 13671*uk_22 + 2079*uk_23 + 24649*uk_24 + 5181*uk_25 + 2512*uk_26 + 26847*uk_27 + 34069*uk_28 + 5181*uk_29 + 157*uk_3 + 1089*uk_30 + 528*uk_31 + 5643*uk_32 + 7161*uk_33 + 1089*uk_34 + 256*uk_35 + 2736*uk_36 + 3472*uk_37 + 528*uk_38 + 29241*uk_39 + 33*uk_4 + 37107*uk_40 + 5643*uk_41 + 47089*uk_42 + 7161*uk_43 + 1089*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 352042137613*uk_47 + 73996118097*uk_48 + 35876905744*uk_49 + 16*uk_5 + 383434430139*uk_50 + 486580534153*uk_51 + 73996118097*uk_52 + 187944057*uk_53 + 468368523*uk_54 + 98446887*uk_55 + 47731824*uk_56 + 510133869*uk_57 + 647362863*uk_58 + 98446887*uk_59 + 171*uk_6 + 1167204097*uk_60 + 245335893*uk_61 + 118950736*uk_62 + 1271285991*uk_63 + 1613269357*uk_64 + 245335893*uk_65 + 51567417*uk_66 + 25002384*uk_67 + 267212979*uk_68 + 339094833*uk_69 + 217*uk_7 + 51567417*uk_70 + 12122368*uk_71 + 129557808*uk_72 + 164409616*uk_73 + 25002384*uk_74 + 1384649073*uk_75 + 1757127771*uk_76 + 267212979*uk_77 + 2229805417*uk_78 + 339094833*uk_79 + 33*uk_8 + 51567417*uk_80 + 250047*uk_81 + 623133*uk_82 + 130977*uk_83 + 63504*uk_84 + 678699*uk_85 + 861273*uk_86 + 130977*uk_87 + 1552887*uk_88 + 326403*uk_89 + 2242306609*uk_9 + 158256*uk_90 + 1691361*uk_91 + 2146347*uk_92 + 326403*uk_93 + 68607*uk_94 + 33264*uk_95 + 355509*uk_96 + 451143*uk_97 + 68607*uk_98 + 16128*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 130788*uk_100 + 164052*uk_101 + 118692*uk_102 + 1885527*uk_103 + 2365083*uk_104 + 1711143*uk_105 + 2966607*uk_106 + 2146347*uk_107 + 1552887*uk_108 + 1906624*uk_109 + 5871772*uk_11 + 2414032*uk_110 + 184512*uk_111 + 2660048*uk_112 + 3336592*uk_113 + 2414032*uk_114 + 3056476*uk_115 + 233616*uk_116 + 3367964*uk_117 + 4224556*uk_118 + 3056476*uk_119 + 7434421*uk_12 + 17856*uk_120 + 257424*uk_121 + 322896*uk_122 + 233616*uk_123 + 3711196*uk_124 + 4655084*uk_125 + 3367964*uk_126 + 5839036*uk_127 + 4224556*uk_128 + 3056476*uk_129 + 568236*uk_13 + 3869893*uk_130 + 295788*uk_131 + 4264277*uk_132 + 5348833*uk_133 + 3869893*uk_134 + 22608*uk_135 + 325932*uk_136 + 408828*uk_137 + 295788*uk_138 + 4698853*uk_139 + 8192069*uk_14 + 5893937*uk_140 + 4264277*uk_141 + 7392973*uk_142 + 5348833*uk_143 + 3869893*uk_144 + 1728*uk_145 + 24912*uk_146 + 31248*uk_147 + 22608*uk_148 + 359148*uk_149 + 10275601*uk_15 + 450492*uk_150 + 325932*uk_151 + 565068*uk_152 + 408828*uk_153 + 295788*uk_154 + 5177717*uk_155 + 6494593*uk_156 + 4698853*uk_157 + 8146397*uk_158 + 5893937*uk_159 + 7434421*uk_16 + 4264277*uk_160 + 10218313*uk_161 + 7392973*uk_162 + 5348833*uk_163 + 3869893*uk_164 + 3969*uk_17 + 7812*uk_18 + 9891*uk_19 + 63*uk_2 + 756*uk_20 + 10899*uk_21 + 13671*uk_22 + 9891*uk_23 + 15376*uk_24 + 19468*uk_25 + 1488*uk_26 + 21452*uk_27 + 26908*uk_28 + 19468*uk_29 + 124*uk_3 + 24649*uk_30 + 1884*uk_31 + 27161*uk_32 + 34069*uk_33 + 24649*uk_34 + 144*uk_35 + 2076*uk_36 + 2604*uk_37 + 1884*uk_38 + 29929*uk_39 + 157*uk_4 + 37541*uk_40 + 27161*uk_41 + 47089*uk_42 + 34069*uk_43 + 24649*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 278046019516*uk_47 + 352042137613*uk_48 + 26907679308*uk_49 + 12*uk_5 + 387919043357*uk_50 + 486580534153*uk_51 + 352042137613*uk_52 + 187944057*uk_53 + 369921636*uk_54 + 468368523*uk_55 + 35798868*uk_56 + 516100347*uk_57 + 647362863*uk_58 + 468368523*uk_59 + 173*uk_6 + 728099728*uk_60 + 921868204*uk_61 + 70461264*uk_62 + 1015816556*uk_63 + 1274174524*uk_64 + 921868204*uk_65 + 1167204097*uk_66 + 89213052*uk_67 + 1286154833*uk_68 + 1613269357*uk_69 + 217*uk_7 + 1167204097*uk_70 + 6818832*uk_71 + 98304828*uk_72 + 123307212*uk_73 + 89213052*uk_74 + 1417227937*uk_75 + 1777678973*uk_76 + 1286154833*uk_77 + 2229805417*uk_78 + 1613269357*uk_79 + 157*uk_8 + 1167204097*uk_80 + 250047*uk_81 + 492156*uk_82 + 623133*uk_83 + 47628*uk_84 + 686637*uk_85 + 861273*uk_86 + 623133*uk_87 + 968688*uk_88 + 1226484*uk_89 + 2242306609*uk_9 + 93744*uk_90 + 1351476*uk_91 + 1695204*uk_92 + 1226484*uk_93 + 1552887*uk_94 + 118692*uk_95 + 1711143*uk_96 + 2146347*uk_97 + 1552887*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 132300*uk_100 + 164052*uk_101 + 93744*uk_102 + 1929375*uk_103 + 2392425*uk_104 + 1367100*uk_105 + 2966607*uk_106 + 1695204*uk_107 + 968688*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 1315516*uk_110 + 127308*uk_111 + 1856575*uk_112 + 2302153*uk_113 + 1315516*uk_114 + 1583728*uk_115 + 153264*uk_116 + 2235100*uk_117 + 2771524*uk_118 + 1583728*uk_119 + 5871772*uk_12 + 14832*uk_120 + 216300*uk_121 + 268212*uk_122 + 153264*uk_123 + 3154375*uk_124 + 3911425*uk_125 + 2235100*uk_126 + 4850167*uk_127 + 2771524*uk_128 + 1583728*uk_129 + 568236*uk_13 + 1906624*uk_130 + 184512*uk_131 + 2690800*uk_132 + 3336592*uk_133 + 1906624*uk_134 + 17856*uk_135 + 260400*uk_136 + 322896*uk_137 + 184512*uk_138 + 3797500*uk_139 + 8286775*uk_14 + 4708900*uk_140 + 2690800*uk_141 + 5839036*uk_142 + 3336592*uk_143 + 1906624*uk_144 + 1728*uk_145 + 25200*uk_146 + 31248*uk_147 + 17856*uk_148 + 367500*uk_149 + 10275601*uk_15 + 455700*uk_150 + 260400*uk_151 + 565068*uk_152 + 322896*uk_153 + 184512*uk_154 + 5359375*uk_155 + 6645625*uk_156 + 3797500*uk_157 + 8240575*uk_158 + 4708900*uk_159 + 5871772*uk_16 + 2690800*uk_160 + 10218313*uk_161 + 5839036*uk_162 + 3336592*uk_163 + 1906624*uk_164 + 3969*uk_17 + 6489*uk_18 + 7812*uk_19 + 63*uk_2 + 756*uk_20 + 11025*uk_21 + 13671*uk_22 + 7812*uk_23 + 10609*uk_24 + 12772*uk_25 + 1236*uk_26 + 18025*uk_27 + 22351*uk_28 + 12772*uk_29 + 103*uk_3 + 15376*uk_30 + 1488*uk_31 + 21700*uk_32 + 26908*uk_33 + 15376*uk_34 + 144*uk_35 + 2100*uk_36 + 2604*uk_37 + 1488*uk_38 + 30625*uk_39 + 124*uk_4 + 37975*uk_40 + 21700*uk_41 + 47089*uk_42 + 26908*uk_43 + 15376*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 278046019516*uk_48 + 26907679308*uk_49 + 12*uk_5 + 392403656575*uk_50 + 486580534153*uk_51 + 278046019516*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 369921636*uk_55 + 35798868*uk_56 + 522066825*uk_57 + 647362863*uk_58 + 369921636*uk_59 + 175*uk_6 + 502367977*uk_60 + 604792516*uk_61 + 58528308*uk_62 + 853537825*uk_63 + 1058386903*uk_64 + 604792516*uk_65 + 728099728*uk_66 + 70461264*uk_67 + 1027560100*uk_68 + 1274174524*uk_69 + 217*uk_7 + 728099728*uk_70 + 6818832*uk_71 + 99441300*uk_72 + 123307212*uk_73 + 70461264*uk_74 + 1450185625*uk_75 + 1798230175*uk_76 + 1027560100*uk_77 + 2229805417*uk_78 + 1274174524*uk_79 + 124*uk_8 + 728099728*uk_80 + 250047*uk_81 + 408807*uk_82 + 492156*uk_83 + 47628*uk_84 + 694575*uk_85 + 861273*uk_86 + 492156*uk_87 + 668367*uk_88 + 804636*uk_89 + 2242306609*uk_9 + 77868*uk_90 + 1135575*uk_91 + 1408113*uk_92 + 804636*uk_93 + 968688*uk_94 + 93744*uk_95 + 1367100*uk_96 + 1695204*uk_97 + 968688*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 133812*uk_100 + 164052*uk_101 + 77868*uk_102 + 1973727*uk_103 + 2419767*uk_104 + 1148553*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 830584*uk_109 + 4451182*uk_11 + 910108*uk_110 + 106032*uk_111 + 1563972*uk_112 + 1917412*uk_113 + 910108*uk_114 + 997246*uk_115 + 116184*uk_116 + 1713714*uk_117 + 2100994*uk_118 + 997246*uk_119 + 4877359*uk_12 + 13536*uk_120 + 199656*uk_121 + 244776*uk_122 + 116184*uk_123 + 2944926*uk_124 + 3610446*uk_125 + 1713714*uk_126 + 4426366*uk_127 + 2100994*uk_128 + 997246*uk_129 + 568236*uk_13 + 1092727*uk_130 + 127308*uk_131 + 1877793*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 14832*uk_135 + 218772*uk_136 + 268212*uk_137 + 127308*uk_138 + 3226887*uk_139 + 8381481*uk_14 + 3956127*uk_140 + 1877793*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 1728*uk_145 + 25488*uk_146 + 31248*uk_147 + 14832*uk_148 + 375948*uk_149 + 10275601*uk_15 + 460908*uk_150 + 218772*uk_151 + 565068*uk_152 + 268212*uk_153 + 127308*uk_154 + 5545233*uk_155 + 6798393*uk_156 + 3226887*uk_157 + 8334753*uk_158 + 3956127*uk_159 + 4877359*uk_16 + 1877793*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 5922*uk_18 + 6489*uk_19 + 63*uk_2 + 756*uk_20 + 11151*uk_21 + 13671*uk_22 + 6489*uk_23 + 8836*uk_24 + 9682*uk_25 + 1128*uk_26 + 16638*uk_27 + 20398*uk_28 + 9682*uk_29 + 94*uk_3 + 10609*uk_30 + 1236*uk_31 + 18231*uk_32 + 22351*uk_33 + 10609*uk_34 + 144*uk_35 + 2124*uk_36 + 2604*uk_37 + 1236*uk_38 + 31329*uk_39 + 103*uk_4 + 38409*uk_40 + 18231*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 210776821246*uk_47 + 230957580727*uk_48 + 26907679308*uk_49 + 12*uk_5 + 396888269793*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 280424466*uk_54 + 307273617*uk_55 + 35798868*uk_56 + 528033303*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 177*uk_6 + 418411108*uk_60 + 458471746*uk_61 + 53414184*uk_62 + 787859214*uk_63 + 965906494*uk_64 + 458471746*uk_65 + 502367977*uk_66 + 58528308*uk_67 + 863292543*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 6818832*uk_71 + 100577772*uk_72 + 123307212*uk_73 + 58528308*uk_74 + 1483522137*uk_75 + 1818781377*uk_76 + 863292543*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 373086*uk_82 + 408807*uk_83 + 47628*uk_84 + 702513*uk_85 + 861273*uk_86 + 408807*uk_87 + 556668*uk_88 + 609966*uk_89 + 2242306609*uk_9 + 71064*uk_90 + 1048194*uk_91 + 1285074*uk_92 + 609966*uk_93 + 668367*uk_94 + 77868*uk_95 + 1148553*uk_96 + 1408113*uk_97 + 668367*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 135324*uk_100 + 164052*uk_101 + 71064*uk_102 + 2018583*uk_103 + 2447109*uk_104 + 1060038*uk_105 + 2966607*uk_106 + 1285074*uk_107 + 556668*uk_108 + 912673*uk_109 + 4593241*uk_11 + 884446*uk_110 + 112908*uk_111 + 1684211*uk_112 + 2041753*uk_113 + 884446*uk_114 + 857092*uk_115 + 109416*uk_116 + 1632122*uk_117 + 1978606*uk_118 + 857092*uk_119 + 4451182*uk_12 + 13968*uk_120 + 208356*uk_121 + 252588*uk_122 + 109416*uk_123 + 3107977*uk_124 + 3767771*uk_125 + 1632122*uk_126 + 4567633*uk_127 + 1978606*uk_128 + 857092*uk_129 + 568236*uk_13 + 830584*uk_130 + 106032*uk_131 + 1581644*uk_132 + 1917412*uk_133 + 830584*uk_134 + 13536*uk_135 + 201912*uk_136 + 244776*uk_137 + 106032*uk_138 + 3011854*uk_139 + 8476187*uk_14 + 3651242*uk_140 + 1581644*uk_141 + 4426366*uk_142 + 1917412*uk_143 + 830584*uk_144 + 1728*uk_145 + 25776*uk_146 + 31248*uk_147 + 13536*uk_148 + 384492*uk_149 + 10275601*uk_15 + 466116*uk_150 + 201912*uk_151 + 565068*uk_152 + 244776*uk_153 + 106032*uk_154 + 5735339*uk_155 + 6952897*uk_156 + 3011854*uk_157 + 8428931*uk_158 + 3651242*uk_159 + 4451182*uk_16 + 1581644*uk_160 + 10218313*uk_161 + 4426366*uk_162 + 1917412*uk_163 + 830584*uk_164 + 3969*uk_17 + 6111*uk_18 + 5922*uk_19 + 63*uk_2 + 756*uk_20 + 11277*uk_21 + 13671*uk_22 + 5922*uk_23 + 9409*uk_24 + 9118*uk_25 + 1164*uk_26 + 17363*uk_27 + 21049*uk_28 + 9118*uk_29 + 97*uk_3 + 8836*uk_30 + 1128*uk_31 + 16826*uk_32 + 20398*uk_33 + 8836*uk_34 + 144*uk_35 + 2148*uk_36 + 2604*uk_37 + 1128*uk_38 + 32041*uk_39 + 94*uk_4 + 38843*uk_40 + 16826*uk_41 + 47089*uk_42 + 20398*uk_43 + 8836*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 217503741073*uk_47 + 210776821246*uk_48 + 26907679308*uk_49 + 12*uk_5 + 401372883011*uk_50 + 486580534153*uk_51 + 210776821246*uk_52 + 187944057*uk_53 + 289374183*uk_54 + 280424466*uk_55 + 35798868*uk_56 + 533999781*uk_57 + 647362863*uk_58 + 280424466*uk_59 + 179*uk_6 + 445544377*uk_60 + 431764654*uk_61 + 55118892*uk_62 + 822190139*uk_63 + 996733297*uk_64 + 431764654*uk_65 + 418411108*uk_66 + 53414184*uk_67 + 796761578*uk_68 + 965906494*uk_69 + 217*uk_7 + 418411108*uk_70 + 6818832*uk_71 + 101714244*uk_72 + 123307212*uk_73 + 53414184*uk_74 + 1517237473*uk_75 + 1839332579*uk_76 + 796761578*uk_77 + 2229805417*uk_78 + 965906494*uk_79 + 94*uk_8 + 418411108*uk_80 + 250047*uk_81 + 384993*uk_82 + 373086*uk_83 + 47628*uk_84 + 710451*uk_85 + 861273*uk_86 + 373086*uk_87 + 592767*uk_88 + 574434*uk_89 + 2242306609*uk_9 + 73332*uk_90 + 1093869*uk_91 + 1326087*uk_92 + 574434*uk_93 + 556668*uk_94 + 71064*uk_95 + 1060038*uk_96 + 1285074*uk_97 + 556668*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 136836*uk_100 + 164052*uk_101 + 73332*uk_102 + 2063943*uk_103 + 2474451*uk_104 + 1106091*uk_105 + 2966607*uk_106 + 1326087*uk_107 + 592767*uk_108 + 1404928*uk_109 + 5303536*uk_11 + 1216768*uk_110 + 150528*uk_111 + 2270464*uk_112 + 2722048*uk_113 + 1216768*uk_114 + 1053808*uk_115 + 130368*uk_116 + 1966384*uk_117 + 2357488*uk_118 + 1053808*uk_119 + 4593241*uk_12 + 16128*uk_120 + 243264*uk_121 + 291648*uk_122 + 130368*uk_123 + 3669232*uk_124 + 4399024*uk_125 + 1966384*uk_126 + 5273968*uk_127 + 2357488*uk_128 + 1053808*uk_129 + 568236*uk_13 + 912673*uk_130 + 112908*uk_131 + 1703029*uk_132 + 2041753*uk_133 + 912673*uk_134 + 13968*uk_135 + 210684*uk_136 + 252588*uk_137 + 112908*uk_138 + 3177817*uk_139 + 8570893*uk_14 + 3809869*uk_140 + 1703029*uk_141 + 4567633*uk_142 + 2041753*uk_143 + 912673*uk_144 + 1728*uk_145 + 26064*uk_146 + 31248*uk_147 + 13968*uk_148 + 393132*uk_149 + 10275601*uk_15 + 471324*uk_150 + 210684*uk_151 + 565068*uk_152 + 252588*uk_153 + 112908*uk_154 + 5929741*uk_155 + 7109137*uk_156 + 3177817*uk_157 + 8523109*uk_158 + 3809869*uk_159 + 4593241*uk_16 + 1703029*uk_160 + 10218313*uk_161 + 4567633*uk_162 + 2041753*uk_163 + 912673*uk_164 + 3969*uk_17 + 7056*uk_18 + 6111*uk_19 + 63*uk_2 + 756*uk_20 + 11403*uk_21 + 13671*uk_22 + 6111*uk_23 + 12544*uk_24 + 10864*uk_25 + 1344*uk_26 + 20272*uk_27 + 24304*uk_28 + 10864*uk_29 + 112*uk_3 + 9409*uk_30 + 1164*uk_31 + 17557*uk_32 + 21049*uk_33 + 9409*uk_34 + 144*uk_35 + 2172*uk_36 + 2604*uk_37 + 1164*uk_38 + 32761*uk_39 + 97*uk_4 + 39277*uk_40 + 17557*uk_41 + 47089*uk_42 + 21049*uk_43 + 9409*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 251138340208*uk_47 + 217503741073*uk_48 + 26907679308*uk_49 + 12*uk_5 + 405857496229*uk_50 + 486580534153*uk_51 + 217503741073*uk_52 + 187944057*uk_53 + 334122768*uk_54 + 289374183*uk_55 + 35798868*uk_56 + 539966259*uk_57 + 647362863*uk_58 + 289374183*uk_59 + 181*uk_6 + 593996032*uk_60 + 514442992*uk_61 + 63642432*uk_62 + 959940016*uk_63 + 1150867312*uk_64 + 514442992*uk_65 + 445544377*uk_66 + 55118892*uk_67 + 831376621*uk_68 + 996733297*uk_69 + 217*uk_7 + 445544377*uk_70 + 6818832*uk_71 + 102850716*uk_72 + 123307212*uk_73 + 55118892*uk_74 + 1551331633*uk_75 + 1859883781*uk_76 + 831376621*uk_77 + 2229805417*uk_78 + 996733297*uk_79 + 97*uk_8 + 445544377*uk_80 + 250047*uk_81 + 444528*uk_82 + 384993*uk_83 + 47628*uk_84 + 718389*uk_85 + 861273*uk_86 + 384993*uk_87 + 790272*uk_88 + 684432*uk_89 + 2242306609*uk_9 + 84672*uk_90 + 1277136*uk_91 + 1531152*uk_92 + 684432*uk_93 + 592767*uk_94 + 73332*uk_95 + 1106091*uk_96 + 1326087*uk_97 + 592767*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 138348*uk_100 + 164052*uk_101 + 84672*uk_102 + 2109807*uk_103 + 2501793*uk_104 + 1291248*uk_105 + 2966607*uk_106 + 1531152*uk_107 + 790272*uk_108 + 2685619*uk_109 + 6582067*uk_11 + 2163952*uk_110 + 231852*uk_111 + 3535743*uk_112 + 4192657*uk_113 + 2163952*uk_114 + 1743616*uk_115 + 186816*uk_116 + 2848944*uk_117 + 3378256*uk_118 + 1743616*uk_119 + 5303536*uk_12 + 20016*uk_120 + 305244*uk_121 + 361956*uk_122 + 186816*uk_123 + 4654971*uk_124 + 5519829*uk_125 + 2848944*uk_126 + 6545371*uk_127 + 3378256*uk_128 + 1743616*uk_129 + 568236*uk_13 + 1404928*uk_130 + 150528*uk_131 + 2295552*uk_132 + 2722048*uk_133 + 1404928*uk_134 + 16128*uk_135 + 245952*uk_136 + 291648*uk_137 + 150528*uk_138 + 3750768*uk_139 + 8665599*uk_14 + 4447632*uk_140 + 2295552*uk_141 + 5273968*uk_142 + 2722048*uk_143 + 1404928*uk_144 + 1728*uk_145 + 26352*uk_146 + 31248*uk_147 + 16128*uk_148 + 401868*uk_149 + 10275601*uk_15 + 476532*uk_150 + 245952*uk_151 + 565068*uk_152 + 291648*uk_153 + 150528*uk_154 + 6128487*uk_155 + 7267113*uk_156 + 3750768*uk_157 + 8617287*uk_158 + 4447632*uk_159 + 5303536*uk_16 + 2295552*uk_160 + 10218313*uk_161 + 5273968*uk_162 + 2722048*uk_163 + 1404928*uk_164 + 3969*uk_17 + 8757*uk_18 + 7056*uk_19 + 63*uk_2 + 756*uk_20 + 11529*uk_21 + 13671*uk_22 + 7056*uk_23 + 19321*uk_24 + 15568*uk_25 + 1668*uk_26 + 25437*uk_27 + 30163*uk_28 + 15568*uk_29 + 139*uk_3 + 12544*uk_30 + 1344*uk_31 + 20496*uk_32 + 24304*uk_33 + 12544*uk_34 + 144*uk_35 + 2196*uk_36 + 2604*uk_37 + 1344*uk_38 + 33489*uk_39 + 112*uk_4 + 39711*uk_40 + 20496*uk_41 + 47089*uk_42 + 24304*uk_43 + 12544*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 311680618651*uk_47 + 251138340208*uk_48 + 26907679308*uk_49 + 12*uk_5 + 410342109447*uk_50 + 486580534153*uk_51 + 251138340208*uk_52 + 187944057*uk_53 + 414670221*uk_54 + 334122768*uk_55 + 35798868*uk_56 + 545932737*uk_57 + 647362863*uk_58 + 334122768*uk_59 + 183*uk_6 + 914907313*uk_60 + 737191504*uk_61 + 78984804*uk_62 + 1204518261*uk_63 + 1428308539*uk_64 + 737191504*uk_65 + 593996032*uk_66 + 63642432*uk_67 + 970547088*uk_68 + 1150867312*uk_69 + 217*uk_7 + 593996032*uk_70 + 6818832*uk_71 + 103987188*uk_72 + 123307212*uk_73 + 63642432*uk_74 + 1585804617*uk_75 + 1880434983*uk_76 + 970547088*uk_77 + 2229805417*uk_78 + 1150867312*uk_79 + 112*uk_8 + 593996032*uk_80 + 250047*uk_81 + 551691*uk_82 + 444528*uk_83 + 47628*uk_84 + 726327*uk_85 + 861273*uk_86 + 444528*uk_87 + 1217223*uk_88 + 980784*uk_89 + 2242306609*uk_9 + 105084*uk_90 + 1602531*uk_91 + 1900269*uk_92 + 980784*uk_93 + 790272*uk_94 + 84672*uk_95 + 1291248*uk_96 + 1531152*uk_97 + 790272*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 139860*uk_100 + 164052*uk_101 + 105084*uk_102 + 2156175*uk_103 + 2529135*uk_104 + 1620045*uk_105 + 2966607*uk_106 + 1900269*uk_107 + 1217223*uk_108 + 5639752*uk_109 + 8428834*uk_11 + 4404076*uk_110 + 380208*uk_111 + 5861540*uk_112 + 6875428*uk_113 + 4404076*uk_114 + 3439138*uk_115 + 296904*uk_116 + 4577270*uk_117 + 5369014*uk_118 + 3439138*uk_119 + 6582067*uk_12 + 25632*uk_120 + 395160*uk_121 + 463512*uk_122 + 296904*uk_123 + 6092050*uk_124 + 7145810*uk_125 + 4577270*uk_126 + 8381842*uk_127 + 5369014*uk_128 + 3439138*uk_129 + 568236*uk_13 + 2685619*uk_130 + 231852*uk_131 + 3574385*uk_132 + 4192657*uk_133 + 2685619*uk_134 + 20016*uk_135 + 308580*uk_136 + 361956*uk_137 + 231852*uk_138 + 4757275*uk_139 + 8760305*uk_14 + 5580155*uk_140 + 3574385*uk_141 + 6545371*uk_142 + 4192657*uk_143 + 2685619*uk_144 + 1728*uk_145 + 26640*uk_146 + 31248*uk_147 + 20016*uk_148 + 410700*uk_149 + 10275601*uk_15 + 481740*uk_150 + 308580*uk_151 + 565068*uk_152 + 361956*uk_153 + 231852*uk_154 + 6331625*uk_155 + 7426825*uk_156 + 4757275*uk_157 + 8711465*uk_158 + 5580155*uk_159 + 6582067*uk_16 + 3574385*uk_160 + 10218313*uk_161 + 6545371*uk_162 + 4192657*uk_163 + 2685619*uk_164 + 3969*uk_17 + 11214*uk_18 + 8757*uk_19 + 63*uk_2 + 756*uk_20 + 11655*uk_21 + 13671*uk_22 + 8757*uk_23 + 31684*uk_24 + 24742*uk_25 + 2136*uk_26 + 32930*uk_27 + 38626*uk_28 + 24742*uk_29 + 178*uk_3 + 19321*uk_30 + 1668*uk_31 + 25715*uk_32 + 30163*uk_33 + 19321*uk_34 + 144*uk_35 + 2220*uk_36 + 2604*uk_37 + 1668*uk_38 + 34225*uk_39 + 139*uk_4 + 40145*uk_40 + 25715*uk_41 + 47089*uk_42 + 30163*uk_43 + 19321*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 399130576402*uk_47 + 311680618651*uk_48 + 26907679308*uk_49 + 12*uk_5 + 414826722665*uk_50 + 486580534153*uk_51 + 311680618651*uk_52 + 187944057*uk_53 + 531016542*uk_54 + 414670221*uk_55 + 35798868*uk_56 + 551899215*uk_57 + 647362863*uk_58 + 414670221*uk_59 + 185*uk_6 + 1500332452*uk_60 + 1171607926*uk_61 + 101146008*uk_62 + 1559334290*uk_63 + 1829056978*uk_64 + 1171607926*uk_65 + 914907313*uk_66 + 78984804*uk_67 + 1217682395*uk_68 + 1428308539*uk_69 + 217*uk_7 + 914907313*uk_70 + 6818832*uk_71 + 105123660*uk_72 + 123307212*uk_73 + 78984804*uk_74 + 1620656425*uk_75 + 1900986185*uk_76 + 1217682395*uk_77 + 2229805417*uk_78 + 1428308539*uk_79 + 139*uk_8 + 914907313*uk_80 + 250047*uk_81 + 706482*uk_82 + 551691*uk_83 + 47628*uk_84 + 734265*uk_85 + 861273*uk_86 + 551691*uk_87 + 1996092*uk_88 + 1558746*uk_89 + 2242306609*uk_9 + 134568*uk_90 + 2074590*uk_91 + 2433438*uk_92 + 1558746*uk_93 + 1217223*uk_94 + 105084*uk_95 + 1620045*uk_96 + 1900269*uk_97 + 1217223*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 94248*uk_100 + 109368*uk_101 + 89712*uk_102 + 2203047*uk_103 + 2556477*uk_104 + 2097018*uk_105 + 2966607*uk_106 + 2433438*uk_107 + 1996092*uk_108 + 74088*uk_109 + 1988826*uk_11 + 313992*uk_110 + 14112*uk_111 + 329868*uk_112 + 382788*uk_113 + 313992*uk_114 + 1330728*uk_115 + 59808*uk_116 + 1398012*uk_117 + 1622292*uk_118 + 1330728*uk_119 + 8428834*uk_12 + 2688*uk_120 + 62832*uk_121 + 72912*uk_122 + 59808*uk_123 + 1468698*uk_124 + 1704318*uk_125 + 1398012*uk_126 + 1977738*uk_127 + 1622292*uk_128 + 1330728*uk_129 + 378824*uk_13 + 5639752*uk_130 + 253472*uk_131 + 5924908*uk_132 + 6875428*uk_133 + 5639752*uk_134 + 11392*uk_135 + 266288*uk_136 + 309008*uk_137 + 253472*uk_138 + 6224482*uk_139 + 8855011*uk_14 + 7223062*uk_140 + 5924908*uk_141 + 8381842*uk_142 + 6875428*uk_143 + 5639752*uk_144 + 512*uk_145 + 11968*uk_146 + 13888*uk_147 + 11392*uk_148 + 279752*uk_149 + 10275601*uk_15 + 324632*uk_150 + 266288*uk_151 + 376712*uk_152 + 309008*uk_153 + 253472*uk_154 + 6539203*uk_155 + 7588273*uk_156 + 6224482*uk_157 + 8805643*uk_158 + 7223062*uk_159 + 8428834*uk_16 + 5924908*uk_160 + 10218313*uk_161 + 8381842*uk_162 + 6875428*uk_163 + 5639752*uk_164 + 3969*uk_17 + 2646*uk_18 + 11214*uk_19 + 63*uk_2 + 504*uk_20 + 11781*uk_21 + 13671*uk_22 + 11214*uk_23 + 1764*uk_24 + 7476*uk_25 + 336*uk_26 + 7854*uk_27 + 9114*uk_28 + 7476*uk_29 + 42*uk_3 + 31684*uk_30 + 1424*uk_31 + 33286*uk_32 + 38626*uk_33 + 31684*uk_34 + 64*uk_35 + 1496*uk_36 + 1736*uk_37 + 1424*uk_38 + 34969*uk_39 + 178*uk_4 + 40579*uk_40 + 33286*uk_41 + 47089*uk_42 + 38626*uk_43 + 31684*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 94176877578*uk_47 + 399130576402*uk_48 + 17938452872*uk_49 + 8*uk_5 + 419311335883*uk_50 + 486580534153*uk_51 + 399130576402*uk_52 + 187944057*uk_53 + 125296038*uk_54 + 531016542*uk_55 + 23865912*uk_56 + 557865693*uk_57 + 647362863*uk_58 + 531016542*uk_59 + 187*uk_6 + 83530692*uk_60 + 354011028*uk_61 + 15910608*uk_62 + 371910462*uk_63 + 431575242*uk_64 + 354011028*uk_65 + 1500332452*uk_66 + 67430672*uk_67 + 1576191958*uk_68 + 1829056978*uk_69 + 217*uk_7 + 1500332452*uk_70 + 3030592*uk_71 + 70840088*uk_72 + 82204808*uk_73 + 67430672*uk_74 + 1655887057*uk_75 + 1921537387*uk_76 + 1576191958*uk_77 + 2229805417*uk_78 + 1829056978*uk_79 + 178*uk_8 + 1500332452*uk_80 + 250047*uk_81 + 166698*uk_82 + 706482*uk_83 + 31752*uk_84 + 742203*uk_85 + 861273*uk_86 + 706482*uk_87 + 111132*uk_88 + 470988*uk_89 + 2242306609*uk_9 + 21168*uk_90 + 494802*uk_91 + 574182*uk_92 + 470988*uk_93 + 1996092*uk_94 + 89712*uk_95 + 2097018*uk_96 + 2433438*uk_97 + 1996092*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 142884*uk_100 + 164052*uk_101 + 31752*uk_102 + 2250423*uk_103 + 2583819*uk_104 + 500094*uk_105 + 2966607*uk_106 + 574182*uk_107 + 111132*uk_108 + 1092727*uk_109 + 4877359*uk_11 + 445578*uk_110 + 127308*uk_111 + 2005101*uk_112 + 2302153*uk_113 + 445578*uk_114 + 181692*uk_115 + 51912*uk_116 + 817614*uk_117 + 938742*uk_118 + 181692*uk_119 + 1988826*uk_12 + 14832*uk_120 + 233604*uk_121 + 268212*uk_122 + 51912*uk_123 + 3679263*uk_124 + 4224339*uk_125 + 817614*uk_126 + 4850167*uk_127 + 938742*uk_128 + 181692*uk_129 + 568236*uk_13 + 74088*uk_130 + 21168*uk_131 + 333396*uk_132 + 382788*uk_133 + 74088*uk_134 + 6048*uk_135 + 95256*uk_136 + 109368*uk_137 + 21168*uk_138 + 1500282*uk_139 + 8949717*uk_14 + 1722546*uk_140 + 333396*uk_141 + 1977738*uk_142 + 382788*uk_143 + 74088*uk_144 + 1728*uk_145 + 27216*uk_146 + 31248*uk_147 + 6048*uk_148 + 428652*uk_149 + 10275601*uk_15 + 492156*uk_150 + 95256*uk_151 + 565068*uk_152 + 109368*uk_153 + 21168*uk_154 + 6751269*uk_155 + 7751457*uk_156 + 1500282*uk_157 + 8899821*uk_158 + 1722546*uk_159 + 1988826*uk_16 + 333396*uk_160 + 10218313*uk_161 + 1977738*uk_162 + 382788*uk_163 + 74088*uk_164 + 3969*uk_17 + 6489*uk_18 + 2646*uk_19 + 63*uk_2 + 756*uk_20 + 11907*uk_21 + 13671*uk_22 + 2646*uk_23 + 10609*uk_24 + 4326*uk_25 + 1236*uk_26 + 19467*uk_27 + 22351*uk_28 + 4326*uk_29 + 103*uk_3 + 1764*uk_30 + 504*uk_31 + 7938*uk_32 + 9114*uk_33 + 1764*uk_34 + 144*uk_35 + 2268*uk_36 + 2604*uk_37 + 504*uk_38 + 35721*uk_39 + 42*uk_4 + 41013*uk_40 + 7938*uk_41 + 47089*uk_42 + 9114*uk_43 + 1764*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 230957580727*uk_47 + 94176877578*uk_48 + 26907679308*uk_49 + 12*uk_5 + 423795949101*uk_50 + 486580534153*uk_51 + 94176877578*uk_52 + 187944057*uk_53 + 307273617*uk_54 + 125296038*uk_55 + 35798868*uk_56 + 563832171*uk_57 + 647362863*uk_58 + 125296038*uk_59 + 189*uk_6 + 502367977*uk_60 + 204849078*uk_61 + 58528308*uk_62 + 921820851*uk_63 + 1058386903*uk_64 + 204849078*uk_65 + 83530692*uk_66 + 23865912*uk_67 + 375888114*uk_68 + 431575242*uk_69 + 217*uk_7 + 83530692*uk_70 + 6818832*uk_71 + 107396604*uk_72 + 123307212*uk_73 + 23865912*uk_74 + 1691496513*uk_75 + 1942088589*uk_76 + 375888114*uk_77 + 2229805417*uk_78 + 431575242*uk_79 + 42*uk_8 + 83530692*uk_80 + 250047*uk_81 + 408807*uk_82 + 166698*uk_83 + 47628*uk_84 + 750141*uk_85 + 861273*uk_86 + 166698*uk_87 + 668367*uk_88 + 272538*uk_89 + 2242306609*uk_9 + 77868*uk_90 + 1226421*uk_91 + 1408113*uk_92 + 272538*uk_93 + 111132*uk_94 + 31752*uk_95 + 500094*uk_96 + 574182*uk_97 + 111132*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 144396*uk_100 + 164052*uk_101 + 77868*uk_102 + 2298303*uk_103 + 2611161*uk_104 + 1239399*uk_105 + 2966607*uk_106 + 1408113*uk_107 + 668367*uk_108 + 5451776*uk_109 + 8334128*uk_11 + 3190528*uk_110 + 371712*uk_111 + 5916416*uk_112 + 6721792*uk_113 + 3190528*uk_114 + 1867184*uk_115 + 217536*uk_116 + 3462448*uk_117 + 3933776*uk_118 + 1867184*uk_119 + 4877359*uk_12 + 25344*uk_120 + 403392*uk_121 + 458304*uk_122 + 217536*uk_123 + 6420656*uk_124 + 7294672*uk_125 + 3462448*uk_126 + 8287664*uk_127 + 3933776*uk_128 + 1867184*uk_129 + 568236*uk_13 + 1092727*uk_130 + 127308*uk_131 + 2026319*uk_132 + 2302153*uk_133 + 1092727*uk_134 + 14832*uk_135 + 236076*uk_136 + 268212*uk_137 + 127308*uk_138 + 3757543*uk_139 + 9044423*uk_14 + 4269041*uk_140 + 2026319*uk_141 + 4850167*uk_142 + 2302153*uk_143 + 1092727*uk_144 + 1728*uk_145 + 27504*uk_146 + 31248*uk_147 + 14832*uk_148 + 437772*uk_149 + 10275601*uk_15 + 497364*uk_150 + 236076*uk_151 + 565068*uk_152 + 268212*uk_153 + 127308*uk_154 + 6967871*uk_155 + 7916377*uk_156 + 3757543*uk_157 + 8993999*uk_158 + 4269041*uk_159 + 4877359*uk_16 + 2026319*uk_160 + 10218313*uk_161 + 4850167*uk_162 + 2302153*uk_163 + 1092727*uk_164 + 3969*uk_17 + 11088*uk_18 + 6489*uk_19 + 63*uk_2 + 756*uk_20 + 12033*uk_21 + 13671*uk_22 + 6489*uk_23 + 30976*uk_24 + 18128*uk_25 + 2112*uk_26 + 33616*uk_27 + 38192*uk_28 + 18128*uk_29 + 176*uk_3 + 10609*uk_30 + 1236*uk_31 + 19673*uk_32 + 22351*uk_33 + 10609*uk_34 + 144*uk_35 + 2292*uk_36 + 2604*uk_37 + 1236*uk_38 + 36481*uk_39 + 103*uk_4 + 41447*uk_40 + 19673*uk_41 + 47089*uk_42 + 22351*uk_43 + 10609*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 394645963184*uk_47 + 230957580727*uk_48 + 26907679308*uk_49 + 12*uk_5 + 428280562319*uk_50 + 486580534153*uk_51 + 230957580727*uk_52 + 187944057*uk_53 + 525050064*uk_54 + 307273617*uk_55 + 35798868*uk_56 + 569798649*uk_57 + 647362863*uk_58 + 307273617*uk_59 + 191*uk_6 + 1466806528*uk_60 + 858415184*uk_61 + 100009536*uk_62 + 1591818448*uk_63 + 1808505776*uk_64 + 858415184*uk_65 + 502367977*uk_66 + 58528308*uk_67 + 931575569*uk_68 + 1058386903*uk_69 + 217*uk_7 + 502367977*uk_70 + 6818832*uk_71 + 108533076*uk_72 + 123307212*uk_73 + 58528308*uk_74 + 1727484793*uk_75 + 1962639791*uk_76 + 931575569*uk_77 + 2229805417*uk_78 + 1058386903*uk_79 + 103*uk_8 + 502367977*uk_80 + 250047*uk_81 + 698544*uk_82 + 408807*uk_83 + 47628*uk_84 + 758079*uk_85 + 861273*uk_86 + 408807*uk_87 + 1951488*uk_88 + 1142064*uk_89 + 2242306609*uk_9 + 133056*uk_90 + 2117808*uk_91 + 2406096*uk_92 + 1142064*uk_93 + 668367*uk_94 + 77868*uk_95 + 1239399*uk_96 + 1408113*uk_97 + 668367*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 97272*uk_100 + 109368*uk_101 + 88704*uk_102 + 2346687*uk_103 + 2638503*uk_104 + 2139984*uk_105 + 2966607*uk_106 + 2406096*uk_107 + 1951488*uk_108 + 314432*uk_109 + 3220004*uk_11 + 813824*uk_110 + 36992*uk_111 + 892432*uk_112 + 1003408*uk_113 + 813824*uk_114 + 2106368*uk_115 + 95744*uk_116 + 2309824*uk_117 + 2597056*uk_118 + 2106368*uk_119 + 8334128*uk_12 + 4352*uk_120 + 104992*uk_121 + 118048*uk_122 + 95744*uk_123 + 2532932*uk_124 + 2847908*uk_125 + 2309824*uk_126 + 3202052*uk_127 + 2597056*uk_128 + 2106368*uk_129 + 378824*uk_13 + 5451776*uk_130 + 247808*uk_131 + 5978368*uk_132 + 6721792*uk_133 + 5451776*uk_134 + 11264*uk_135 + 271744*uk_136 + 305536*uk_137 + 247808*uk_138 + 6555824*uk_139 + 9139129*uk_14 + 7371056*uk_140 + 5978368*uk_141 + 8287664*uk_142 + 6721792*uk_143 + 5451776*uk_144 + 512*uk_145 + 12352*uk_146 + 13888*uk_147 + 11264*uk_148 + 297992*uk_149 + 10275601*uk_15 + 335048*uk_150 + 271744*uk_151 + 376712*uk_152 + 305536*uk_153 + 247808*uk_154 + 7189057*uk_155 + 8083033*uk_156 + 6555824*uk_157 + 9088177*uk_158 + 7371056*uk_159 + 8334128*uk_16 + 5978368*uk_160 + 10218313*uk_161 + 8287664*uk_162 + 6721792*uk_163 + 5451776*uk_164 + 3969*uk_17 + 4284*uk_18 + 11088*uk_19 + 63*uk_2 + 504*uk_20 + 12159*uk_21 + 13671*uk_22 + 11088*uk_23 + 4624*uk_24 + 11968*uk_25 + 544*uk_26 + 13124*uk_27 + 14756*uk_28 + 11968*uk_29 + 68*uk_3 + 30976*uk_30 + 1408*uk_31 + 33968*uk_32 + 38192*uk_33 + 30976*uk_34 + 64*uk_35 + 1544*uk_36 + 1736*uk_37 + 1408*uk_38 + 37249*uk_39 + 176*uk_4 + 41881*uk_40 + 33968*uk_41 + 47089*uk_42 + 38192*uk_43 + 30976*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 152476849412*uk_47 + 394645963184*uk_48 + 17938452872*uk_49 + 8*uk_5 + 432765175537*uk_50 + 486580534153*uk_51 + 394645963184*uk_52 + 187944057*uk_53 + 202860252*uk_54 + 525050064*uk_55 + 23865912*uk_56 + 575765127*uk_57 + 647362863*uk_58 + 525050064*uk_59 + 193*uk_6 + 218960272*uk_60 + 566720704*uk_61 + 25760032*uk_62 + 621460772*uk_63 + 698740868*uk_64 + 566720704*uk_65 + 1466806528*uk_66 + 66673024*uk_67 + 1608486704*uk_68 + 1808505776*uk_69 + 217*uk_7 + 1466806528*uk_70 + 3030592*uk_71 + 73113032*uk_72 + 82204808*uk_73 + 66673024*uk_74 + 1763851897*uk_75 + 1983190993*uk_76 + 1608486704*uk_77 + 2229805417*uk_78 + 1808505776*uk_79 + 176*uk_8 + 1466806528*uk_80 + 250047*uk_81 + 269892*uk_82 + 698544*uk_83 + 31752*uk_84 + 766017*uk_85 + 861273*uk_86 + 698544*uk_87 + 291312*uk_88 + 753984*uk_89 + 2242306609*uk_9 + 34272*uk_90 + 826812*uk_91 + 929628*uk_92 + 753984*uk_93 + 1951488*uk_94 + 88704*uk_95 + 2139984*uk_96 + 2406096*uk_97 + 1951488*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 147420*uk_100 + 164052*uk_101 + 51408*uk_102 + 2395575*uk_103 + 2665845*uk_104 + 835380*uk_105 + 2966607*uk_106 + 929628*uk_107 + 291312*uk_108 + 4330747*uk_109 + 7718539*uk_11 + 1806692*uk_110 + 318828*uk_111 + 5180955*uk_112 + 5765473*uk_113 + 1806692*uk_114 + 753712*uk_115 + 133008*uk_116 + 2161380*uk_117 + 2405228*uk_118 + 753712*uk_119 + 3220004*uk_12 + 23472*uk_120 + 381420*uk_121 + 424452*uk_122 + 133008*uk_123 + 6198075*uk_124 + 6897345*uk_125 + 2161380*uk_126 + 7675507*uk_127 + 2405228*uk_128 + 753712*uk_129 + 568236*uk_13 + 314432*uk_130 + 55488*uk_131 + 901680*uk_132 + 1003408*uk_133 + 314432*uk_134 + 9792*uk_135 + 159120*uk_136 + 177072*uk_137 + 55488*uk_138 + 2585700*uk_139 + 9233835*uk_14 + 2877420*uk_140 + 901680*uk_141 + 3202052*uk_142 + 1003408*uk_143 + 314432*uk_144 + 1728*uk_145 + 28080*uk_146 + 31248*uk_147 + 9792*uk_148 + 456300*uk_149 + 10275601*uk_15 + 507780*uk_150 + 159120*uk_151 + 565068*uk_152 + 177072*uk_153 + 55488*uk_154 + 7414875*uk_155 + 8251425*uk_156 + 2585700*uk_157 + 9182355*uk_158 + 2877420*uk_159 + 3220004*uk_16 + 901680*uk_160 + 10218313*uk_161 + 3202052*uk_162 + 1003408*uk_163 + 314432*uk_164 + 3969*uk_17 + 10269*uk_18 + 4284*uk_19 + 63*uk_2 + 756*uk_20 + 12285*uk_21 + 13671*uk_22 + 4284*uk_23 + 26569*uk_24 + 11084*uk_25 + 1956*uk_26 + 31785*uk_27 + 35371*uk_28 + 11084*uk_29 + 163*uk_3 + 4624*uk_30 + 816*uk_31 + 13260*uk_32 + 14756*uk_33 + 4624*uk_34 + 144*uk_35 + 2340*uk_36 + 2604*uk_37 + 816*uk_38 + 38025*uk_39 + 68*uk_4 + 42315*uk_40 + 13260*uk_41 + 47089*uk_42 + 14756*uk_43 + 4624*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 365495977267*uk_47 + 152476849412*uk_48 + 26907679308*uk_49 + 12*uk_5 + 437249788755*uk_50 + 486580534153*uk_51 + 152476849412*uk_52 + 187944057*uk_53 + 486267957*uk_54 + 202860252*uk_55 + 35798868*uk_56 + 581731605*uk_57 + 647362863*uk_58 + 202860252*uk_59 + 195*uk_6 + 1258121857*uk_60 + 524860652*uk_61 + 92622468*uk_62 + 1505115105*uk_63 + 1674922963*uk_64 + 524860652*uk_65 + 218960272*uk_66 + 38640048*uk_67 + 627900780*uk_68 + 698740868*uk_69 + 217*uk_7 + 218960272*uk_70 + 6818832*uk_71 + 110806020*uk_72 + 123307212*uk_73 + 38640048*uk_74 + 1800597825*uk_75 + 2003742195*uk_76 + 627900780*uk_77 + 2229805417*uk_78 + 698740868*uk_79 + 68*uk_8 + 218960272*uk_80 + 250047*uk_81 + 646947*uk_82 + 269892*uk_83 + 47628*uk_84 + 773955*uk_85 + 861273*uk_86 + 269892*uk_87 + 1673847*uk_88 + 698292*uk_89 + 2242306609*uk_9 + 123228*uk_90 + 2002455*uk_91 + 2228373*uk_92 + 698292*uk_93 + 291312*uk_94 + 51408*uk_95 + 835380*uk_96 + 929628*uk_97 + 291312*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 99288*uk_100 + 109368*uk_101 + 82152*uk_102 + 2444967*uk_103 + 2693187*uk_104 + 2022993*uk_105 + 2966607*uk_106 + 2228373*uk_107 + 1673847*uk_108 + 389017*uk_109 + 3456769*uk_11 + 868627*uk_110 + 42632*uk_111 + 1049813*uk_112 + 1156393*uk_113 + 868627*uk_114 + 1939537*uk_115 + 95192*uk_116 + 2344103*uk_117 + 2582083*uk_118 + 1939537*uk_119 + 7718539*uk_12 + 4672*uk_120 + 115048*uk_121 + 126728*uk_122 + 95192*uk_123 + 2833057*uk_124 + 3120677*uk_125 + 2344103*uk_126 + 3437497*uk_127 + 2582083*uk_128 + 1939537*uk_129 + 378824*uk_13 + 4330747*uk_130 + 212552*uk_131 + 5234093*uk_132 + 5765473*uk_133 + 4330747*uk_134 + 10432*uk_135 + 256888*uk_136 + 282968*uk_137 + 212552*uk_138 + 6325867*uk_139 + 9328541*uk_14 + 6968087*uk_140 + 5234093*uk_141 + 7675507*uk_142 + 5765473*uk_143 + 4330747*uk_144 + 512*uk_145 + 12608*uk_146 + 13888*uk_147 + 10432*uk_148 + 310472*uk_149 + 10275601*uk_15 + 341992*uk_150 + 256888*uk_151 + 376712*uk_152 + 282968*uk_153 + 212552*uk_154 + 7645373*uk_155 + 8421553*uk_156 + 6325867*uk_157 + 9276533*uk_158 + 6968087*uk_159 + 7718539*uk_16 + 5234093*uk_160 + 10218313*uk_161 + 7675507*uk_162 + 5765473*uk_163 + 4330747*uk_164 + 3969*uk_17 + 4599*uk_18 + 10269*uk_19 + 63*uk_2 + 504*uk_20 + 12411*uk_21 + 13671*uk_22 + 10269*uk_23 + 5329*uk_24 + 11899*uk_25 + 584*uk_26 + 14381*uk_27 + 15841*uk_28 + 11899*uk_29 + 73*uk_3 + 26569*uk_30 + 1304*uk_31 + 32111*uk_32 + 35371*uk_33 + 26569*uk_34 + 64*uk_35 + 1576*uk_36 + 1736*uk_37 + 1304*uk_38 + 38809*uk_39 + 163*uk_4 + 42749*uk_40 + 32111*uk_41 + 47089*uk_42 + 35371*uk_43 + 26569*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 163688382457*uk_47 + 365495977267*uk_48 + 17938452872*uk_49 + 8*uk_5 + 441734401973*uk_50 + 486580534153*uk_51 + 365495977267*uk_52 + 187944057*uk_53 + 217776447*uk_54 + 486267957*uk_55 + 23865912*uk_56 + 587698083*uk_57 + 647362863*uk_58 + 486267957*uk_59 + 197*uk_6 + 252344137*uk_60 + 563453347*uk_61 + 27654152*uk_62 + 680983493*uk_63 + 750118873*uk_64 + 563453347*uk_65 + 1258121857*uk_66 + 61748312*uk_67 + 1520552183*uk_68 + 1674922963*uk_69 + 217*uk_7 + 1258121857*uk_70 + 3030592*uk_71 + 74628328*uk_72 + 82204808*uk_73 + 61748312*uk_74 + 1837722577*uk_75 + 2024293397*uk_76 + 1520552183*uk_77 + 2229805417*uk_78 + 1674922963*uk_79 + 163*uk_8 + 1258121857*uk_80 + 250047*uk_81 + 289737*uk_82 + 646947*uk_83 + 31752*uk_84 + 781893*uk_85 + 861273*uk_86 + 646947*uk_87 + 335727*uk_88 + 749637*uk_89 + 2242306609*uk_9 + 36792*uk_90 + 906003*uk_91 + 997983*uk_92 + 749637*uk_93 + 1673847*uk_94 + 82152*uk_95 + 2022993*uk_96 + 2228373*uk_97 + 1673847*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 150444*uk_100 + 164052*uk_101 + 55188*uk_102 + 2494863*uk_103 + 2720529*uk_104 + 915201*uk_105 + 2966607*uk_106 + 997983*uk_107 + 335727*uk_108 + 6859000*uk_109 + 8997070*uk_11 + 2635300*uk_110 + 433200*uk_111 + 7183900*uk_112 + 7833700*uk_113 + 2635300*uk_114 + 1012510*uk_115 + 166440*uk_116 + 2760130*uk_117 + 3009790*uk_118 + 1012510*uk_119 + 3456769*uk_12 + 27360*uk_120 + 453720*uk_121 + 494760*uk_122 + 166440*uk_123 + 7524190*uk_124 + 8204770*uk_125 + 2760130*uk_126 + 8946910*uk_127 + 3009790*uk_128 + 1012510*uk_129 + 568236*uk_13 + 389017*uk_130 + 63948*uk_131 + 1060471*uk_132 + 1156393*uk_133 + 389017*uk_134 + 10512*uk_135 + 174324*uk_136 + 190092*uk_137 + 63948*uk_138 + 2890873*uk_139 + 9423247*uk_14 + 3152359*uk_140 + 1060471*uk_141 + 3437497*uk_142 + 1156393*uk_143 + 389017*uk_144 + 1728*uk_145 + 28656*uk_146 + 31248*uk_147 + 10512*uk_148 + 475212*uk_149 + 10275601*uk_15 + 518196*uk_150 + 174324*uk_151 + 565068*uk_152 + 190092*uk_153 + 63948*uk_154 + 7880599*uk_155 + 8593417*uk_156 + 2890873*uk_157 + 9370711*uk_158 + 3152359*uk_159 + 3456769*uk_16 + 1060471*uk_160 + 10218313*uk_161 + 3437497*uk_162 + 1156393*uk_163 + 389017*uk_164 + 3969*uk_17 + 11970*uk_18 + 4599*uk_19 + 63*uk_2 + 756*uk_20 + 12537*uk_21 + 13671*uk_22 + 4599*uk_23 + 36100*uk_24 + 13870*uk_25 + 2280*uk_26 + 37810*uk_27 + 41230*uk_28 + 13870*uk_29 + 190*uk_3 + 5329*uk_30 + 876*uk_31 + 14527*uk_32 + 15841*uk_33 + 5329*uk_34 + 144*uk_35 + 2388*uk_36 + 2604*uk_37 + 876*uk_38 + 39601*uk_39 + 73*uk_4 + 43183*uk_40 + 14527*uk_41 + 47089*uk_42 + 15841*uk_43 + 5329*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 426038255710*uk_47 + 163688382457*uk_48 + 26907679308*uk_49 + 12*uk_5 + 446219015191*uk_50 + 486580534153*uk_51 + 163688382457*uk_52 + 187944057*uk_53 + 566815410*uk_54 + 217776447*uk_55 + 35798868*uk_56 + 593664561*uk_57 + 647362863*uk_58 + 217776447*uk_59 + 199*uk_6 + 1709443300*uk_60 + 656786110*uk_61 + 107964840*uk_62 + 1790416930*uk_63 + 1952364190*uk_64 + 656786110*uk_65 + 252344137*uk_66 + 41481228*uk_67 + 687897031*uk_68 + 750118873*uk_69 + 217*uk_7 + 252344137*uk_70 + 6818832*uk_71 + 113078964*uk_72 + 123307212*uk_73 + 41481228*uk_74 + 1875226153*uk_75 + 2044844599*uk_76 + 687897031*uk_77 + 2229805417*uk_78 + 750118873*uk_79 + 73*uk_8 + 252344137*uk_80 + 250047*uk_81 + 754110*uk_82 + 289737*uk_83 + 47628*uk_84 + 789831*uk_85 + 861273*uk_86 + 289737*uk_87 + 2274300*uk_88 + 873810*uk_89 + 2242306609*uk_9 + 143640*uk_90 + 2382030*uk_91 + 2597490*uk_92 + 873810*uk_93 + 335727*uk_94 + 55188*uk_95 + 915201*uk_96 + 997983*uk_97 + 335727*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 101304*uk_100 + 109368*uk_101 + 95760*uk_102 + 2545263*uk_103 + 2747871*uk_104 + 2405970*uk_105 + 2966607*uk_106 + 2597490*uk_107 + 2274300*uk_108 + 1643032*uk_109 + 5587654*uk_11 + 2645560*uk_110 + 111392*uk_111 + 2798724*uk_112 + 3021508*uk_113 + 2645560*uk_114 + 4259800*uk_115 + 179360*uk_116 + 4506420*uk_117 + 4865140*uk_118 + 4259800*uk_119 + 8997070*uk_12 + 7552*uk_120 + 189744*uk_121 + 204848*uk_122 + 179360*uk_123 + 4767318*uk_124 + 5146806*uk_125 + 4506420*uk_126 + 5556502*uk_127 + 4865140*uk_128 + 4259800*uk_129 + 378824*uk_13 + 6859000*uk_130 + 288800*uk_131 + 7256100*uk_132 + 7833700*uk_133 + 6859000*uk_134 + 12160*uk_135 + 305520*uk_136 + 329840*uk_137 + 288800*uk_138 + 7676190*uk_139 + 9517953*uk_14 + 8287230*uk_140 + 7256100*uk_141 + 8946910*uk_142 + 7833700*uk_143 + 6859000*uk_144 + 512*uk_145 + 12864*uk_146 + 13888*uk_147 + 12160*uk_148 + 323208*uk_149 + 10275601*uk_15 + 348936*uk_150 + 305520*uk_151 + 376712*uk_152 + 329840*uk_153 + 288800*uk_154 + 8120601*uk_155 + 8767017*uk_156 + 7676190*uk_157 + 9464889*uk_158 + 8287230*uk_159 + 8997070*uk_16 + 7256100*uk_160 + 10218313*uk_161 + 8946910*uk_162 + 7833700*uk_163 + 6859000*uk_164 + 3969*uk_17 + 7434*uk_18 + 11970*uk_19 + 63*uk_2 + 504*uk_20 + 12663*uk_21 + 13671*uk_22 + 11970*uk_23 + 13924*uk_24 + 22420*uk_25 + 944*uk_26 + 23718*uk_27 + 25606*uk_28 + 22420*uk_29 + 118*uk_3 + 36100*uk_30 + 1520*uk_31 + 38190*uk_32 + 41230*uk_33 + 36100*uk_34 + 64*uk_35 + 1608*uk_36 + 1736*uk_37 + 1520*uk_38 + 40401*uk_39 + 190*uk_4 + 43617*uk_40 + 38190*uk_41 + 47089*uk_42 + 41230*uk_43 + 36100*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 264592179862*uk_47 + 426038255710*uk_48 + 17938452872*uk_49 + 8*uk_5 + 450703628409*uk_50 + 486580534153*uk_51 + 426038255710*uk_52 + 187944057*uk_53 + 352022202*uk_54 + 566815410*uk_55 + 23865912*uk_56 + 599631039*uk_57 + 647362863*uk_58 + 566815410*uk_59 + 201*uk_6 + 659343172*uk_60 + 1061654260*uk_61 + 44701232*uk_62 + 1123118454*uk_63 + 1212520918*uk_64 + 1061654260*uk_65 + 1709443300*uk_66 + 71976560*uk_67 + 1808411070*uk_68 + 1952364190*uk_69 + 217*uk_7 + 1709443300*uk_70 + 3030592*uk_71 + 76143624*uk_72 + 82204808*uk_73 + 71976560*uk_74 + 1913108553*uk_75 + 2065395801*uk_76 + 1808411070*uk_77 + 2229805417*uk_78 + 1952364190*uk_79 + 190*uk_8 + 1709443300*uk_80 + 250047*uk_81 + 468342*uk_82 + 754110*uk_83 + 31752*uk_84 + 797769*uk_85 + 861273*uk_86 + 754110*uk_87 + 877212*uk_88 + 1412460*uk_89 + 2242306609*uk_9 + 59472*uk_90 + 1494234*uk_91 + 1613178*uk_92 + 1412460*uk_93 + 2274300*uk_94 + 95760*uk_95 + 2405970*uk_96 + 2597490*uk_97 + 2274300*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 102312*uk_100 + 109368*uk_101 + 59472*uk_102 + 2596167*uk_103 + 2775213*uk_104 + 1509102*uk_105 + 2966607*uk_106 + 1613178*uk_107 + 877212*uk_108 + 157464*uk_109 + 2557062*uk_11 + 344088*uk_110 + 23328*uk_111 + 591948*uk_112 + 632772*uk_113 + 344088*uk_114 + 751896*uk_115 + 50976*uk_116 + 1293516*uk_117 + 1382724*uk_118 + 751896*uk_119 + 5587654*uk_12 + 3456*uk_120 + 87696*uk_121 + 93744*uk_122 + 50976*uk_123 + 2225286*uk_124 + 2378754*uk_125 + 1293516*uk_126 + 2542806*uk_127 + 1382724*uk_128 + 751896*uk_129 + 378824*uk_13 + 1643032*uk_130 + 111392*uk_131 + 2826572*uk_132 + 3021508*uk_133 + 1643032*uk_134 + 7552*uk_135 + 191632*uk_136 + 204848*uk_137 + 111392*uk_138 + 4862662*uk_139 + 9612659*uk_14 + 5198018*uk_140 + 2826572*uk_141 + 5556502*uk_142 + 3021508*uk_143 + 1643032*uk_144 + 512*uk_145 + 12992*uk_146 + 13888*uk_147 + 7552*uk_148 + 329672*uk_149 + 10275601*uk_15 + 352408*uk_150 + 191632*uk_151 + 376712*uk_152 + 204848*uk_153 + 111392*uk_154 + 8365427*uk_155 + 8942353*uk_156 + 4862662*uk_157 + 9559067*uk_158 + 5198018*uk_159 + 5587654*uk_16 + 2826572*uk_160 + 10218313*uk_161 + 5556502*uk_162 + 3021508*uk_163 + 1643032*uk_164 + 3969*uk_17 + 3402*uk_18 + 7434*uk_19 + 63*uk_2 + 504*uk_20 + 12789*uk_21 + 13671*uk_22 + 7434*uk_23 + 2916*uk_24 + 6372*uk_25 + 432*uk_26 + 10962*uk_27 + 11718*uk_28 + 6372*uk_29 + 54*uk_3 + 13924*uk_30 + 944*uk_31 + 23954*uk_32 + 25606*uk_33 + 13924*uk_34 + 64*uk_35 + 1624*uk_36 + 1736*uk_37 + 944*uk_38 + 41209*uk_39 + 118*uk_4 + 44051*uk_40 + 23954*uk_41 + 47089*uk_42 + 25606*uk_43 + 13924*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 121084556886*uk_47 + 264592179862*uk_48 + 17938452872*uk_49 + 8*uk_5 + 455188241627*uk_50 + 486580534153*uk_51 + 264592179862*uk_52 + 187944057*uk_53 + 161094906*uk_54 + 352022202*uk_55 + 23865912*uk_56 + 605597517*uk_57 + 647362863*uk_58 + 352022202*uk_59 + 203*uk_6 + 138081348*uk_60 + 301733316*uk_61 + 20456496*uk_62 + 519083586*uk_63 + 554882454*uk_64 + 301733316*uk_65 + 659343172*uk_66 + 44701232*uk_67 + 1134293762*uk_68 + 1212520918*uk_69 + 217*uk_7 + 659343172*uk_70 + 3030592*uk_71 + 76901272*uk_72 + 82204808*uk_73 + 44701232*uk_74 + 1951369777*uk_75 + 2085947003*uk_76 + 1134293762*uk_77 + 2229805417*uk_78 + 1212520918*uk_79 + 118*uk_8 + 659343172*uk_80 + 250047*uk_81 + 214326*uk_82 + 468342*uk_83 + 31752*uk_84 + 805707*uk_85 + 861273*uk_86 + 468342*uk_87 + 183708*uk_88 + 401436*uk_89 + 2242306609*uk_9 + 27216*uk_90 + 690606*uk_91 + 738234*uk_92 + 401436*uk_93 + 877212*uk_94 + 59472*uk_95 + 1509102*uk_96 + 1613178*uk_97 + 877212*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 154980*uk_100 + 164052*uk_101 + 40824*uk_102 + 2647575*uk_103 + 2802555*uk_104 + 697410*uk_105 + 2966607*uk_106 + 738234*uk_107 + 183708*uk_108 + 8365427*uk_109 + 9612659*uk_11 + 2225286*uk_110 + 494508*uk_111 + 8447845*uk_112 + 8942353*uk_113 + 2225286*uk_114 + 591948*uk_115 + 131544*uk_116 + 2247210*uk_117 + 2378754*uk_118 + 591948*uk_119 + 2557062*uk_12 + 29232*uk_120 + 499380*uk_121 + 528612*uk_122 + 131544*uk_123 + 8531075*uk_124 + 9030455*uk_125 + 2247210*uk_126 + 9559067*uk_127 + 2378754*uk_128 + 591948*uk_129 + 568236*uk_13 + 157464*uk_130 + 34992*uk_131 + 597780*uk_132 + 632772*uk_133 + 157464*uk_134 + 7776*uk_135 + 132840*uk_136 + 140616*uk_137 + 34992*uk_138 + 2269350*uk_139 + 9707365*uk_14 + 2402190*uk_140 + 597780*uk_141 + 2542806*uk_142 + 632772*uk_143 + 157464*uk_144 + 1728*uk_145 + 29520*uk_146 + 31248*uk_147 + 7776*uk_148 + 504300*uk_149 + 10275601*uk_15 + 533820*uk_150 + 132840*uk_151 + 565068*uk_152 + 140616*uk_153 + 34992*uk_154 + 8615125*uk_155 + 9119425*uk_156 + 2269350*uk_157 + 9653245*uk_158 + 2402190*uk_159 + 2557062*uk_16 + 597780*uk_160 + 10218313*uk_161 + 2542806*uk_162 + 632772*uk_163 + 157464*uk_164 + 3969*uk_17 + 12789*uk_18 + 3402*uk_19 + 63*uk_2 + 756*uk_20 + 12915*uk_21 + 13671*uk_22 + 3402*uk_23 + 41209*uk_24 + 10962*uk_25 + 2436*uk_26 + 41615*uk_27 + 44051*uk_28 + 10962*uk_29 + 203*uk_3 + 2916*uk_30 + 648*uk_31 + 11070*uk_32 + 11718*uk_33 + 2916*uk_34 + 144*uk_35 + 2460*uk_36 + 2604*uk_37 + 648*uk_38 + 42025*uk_39 + 54*uk_4 + 44485*uk_40 + 11070*uk_41 + 47089*uk_42 + 11718*uk_43 + 2916*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 455188241627*uk_47 + 121084556886*uk_48 + 26907679308*uk_49 + 12*uk_5 + 459672854845*uk_50 + 486580534153*uk_51 + 121084556886*uk_52 + 187944057*uk_53 + 605597517*uk_54 + 161094906*uk_55 + 35798868*uk_56 + 611563995*uk_57 + 647362863*uk_58 + 161094906*uk_59 + 205*uk_6 + 1951369777*uk_60 + 519083586*uk_61 + 115351908*uk_62 + 1970595095*uk_63 + 2085947003*uk_64 + 519083586*uk_65 + 138081348*uk_66 + 30684744*uk_67 + 524197710*uk_68 + 554882454*uk_69 + 217*uk_7 + 138081348*uk_70 + 6818832*uk_71 + 116488380*uk_72 + 123307212*uk_73 + 30684744*uk_74 + 1990009825*uk_75 + 2106498205*uk_76 + 524197710*uk_77 + 2229805417*uk_78 + 554882454*uk_79 + 54*uk_8 + 138081348*uk_80 + 250047*uk_81 + 805707*uk_82 + 214326*uk_83 + 47628*uk_84 + 813645*uk_85 + 861273*uk_86 + 214326*uk_87 + 2596167*uk_88 + 690606*uk_89 + 2242306609*uk_9 + 153468*uk_90 + 2621745*uk_91 + 2775213*uk_92 + 690606*uk_93 + 183708*uk_94 + 40824*uk_95 + 697410*uk_96 + 738234*uk_97 + 183708*uk_98 + 9072*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 104328*uk_100 + 109368*uk_101 + 102312*uk_102 + 2699487*uk_103 + 2829897*uk_104 + 2647323*uk_105 + 2966607*uk_106 + 2775213*uk_107 + 2596167*uk_108 + 3869893*uk_109 + 7434421*uk_11 + 5003747*uk_110 + 197192*uk_111 + 5102343*uk_112 + 5348833*uk_113 + 5003747*uk_114 + 6469813*uk_115 + 254968*uk_116 + 6597297*uk_117 + 6916007*uk_118 + 6469813*uk_119 + 9612659*uk_12 + 10048*uk_120 + 259992*uk_121 + 272552*uk_122 + 254968*uk_123 + 6727293*uk_124 + 7052283*uk_125 + 6597297*uk_126 + 7392973*uk_127 + 6916007*uk_128 + 6469813*uk_129 + 378824*uk_13 + 8365427*uk_130 + 329672*uk_131 + 8530263*uk_132 + 8942353*uk_133 + 8365427*uk_134 + 12992*uk_135 + 336168*uk_136 + 352408*uk_137 + 329672*uk_138 + 8698347*uk_139 + 9802071*uk_14 + 9118557*uk_140 + 8530263*uk_141 + 9559067*uk_142 + 8942353*uk_143 + 8365427*uk_144 + 512*uk_145 + 13248*uk_146 + 13888*uk_147 + 12992*uk_148 + 342792*uk_149 + 10275601*uk_15 + 359352*uk_150 + 336168*uk_151 + 376712*uk_152 + 352408*uk_153 + 329672*uk_154 + 8869743*uk_155 + 9298233*uk_156 + 8698347*uk_157 + 9747423*uk_158 + 9118557*uk_159 + 9612659*uk_16 + 8530263*uk_160 + 10218313*uk_161 + 9559067*uk_162 + 8942353*uk_163 + 8365427*uk_164 + 3969*uk_17 + 9891*uk_18 + 12789*uk_19 + 63*uk_2 + 504*uk_20 + 13041*uk_21 + 13671*uk_22 + 12789*uk_23 + 24649*uk_24 + 31871*uk_25 + 1256*uk_26 + 32499*uk_27 + 34069*uk_28 + 31871*uk_29 + 157*uk_3 + 41209*uk_30 + 1624*uk_31 + 42021*uk_32 + 44051*uk_33 + 41209*uk_34 + 64*uk_35 + 1656*uk_36 + 1736*uk_37 + 1624*uk_38 + 42849*uk_39 + 203*uk_4 + 44919*uk_40 + 42021*uk_41 + 47089*uk_42 + 44051*uk_43 + 41209*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 352042137613*uk_47 + 455188241627*uk_48 + 17938452872*uk_49 + 8*uk_5 + 464157468063*uk_50 + 486580534153*uk_51 + 455188241627*uk_52 + 187944057*uk_53 + 468368523*uk_54 + 605597517*uk_55 + 23865912*uk_56 + 617530473*uk_57 + 647362863*uk_58 + 605597517*uk_59 + 207*uk_6 + 1167204097*uk_60 + 1509187463*uk_61 + 59475368*uk_62 + 1538925147*uk_63 + 1613269357*uk_64 + 1509187463*uk_65 + 1951369777*uk_66 + 76901272*uk_67 + 1989820413*uk_68 + 2085947003*uk_69 + 217*uk_7 + 1951369777*uk_70 + 3030592*uk_71 + 78416568*uk_72 + 82204808*uk_73 + 76901272*uk_74 + 2029028697*uk_75 + 2127049407*uk_76 + 1989820413*uk_77 + 2229805417*uk_78 + 2085947003*uk_79 + 203*uk_8 + 1951369777*uk_80 + 250047*uk_81 + 623133*uk_82 + 805707*uk_83 + 31752*uk_84 + 821583*uk_85 + 861273*uk_86 + 805707*uk_87 + 1552887*uk_88 + 2007873*uk_89 + 2242306609*uk_9 + 79128*uk_90 + 2047437*uk_91 + 2146347*uk_92 + 2007873*uk_93 + 2596167*uk_94 + 102312*uk_95 + 2647323*uk_96 + 2775213*uk_97 + 2596167*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 105336*uk_100 + 109368*uk_101 + 79128*uk_102 + 2751903*uk_103 + 2857239*uk_104 + 2067219*uk_105 + 2966607*uk_106 + 2146347*uk_107 + 1552887*uk_108 + 1685159*uk_109 + 5635007*uk_11 + 2223277*uk_110 + 113288*uk_111 + 2959649*uk_112 + 3072937*uk_113 + 2223277*uk_114 + 2933231*uk_115 + 149464*uk_116 + 3904747*uk_117 + 4054211*uk_118 + 2933231*uk_119 + 7434421*uk_12 + 7616*uk_120 + 198968*uk_121 + 206584*uk_122 + 149464*uk_123 + 5198039*uk_124 + 5397007*uk_125 + 3904747*uk_126 + 5603591*uk_127 + 4054211*uk_128 + 2933231*uk_129 + 378824*uk_13 + 3869893*uk_130 + 197192*uk_131 + 5151641*uk_132 + 5348833*uk_133 + 3869893*uk_134 + 10048*uk_135 + 262504*uk_136 + 272552*uk_137 + 197192*uk_138 + 6857917*uk_139 + 9896777*uk_14 + 7120421*uk_140 + 5151641*uk_141 + 7392973*uk_142 + 5348833*uk_143 + 3869893*uk_144 + 512*uk_145 + 13376*uk_146 + 13888*uk_147 + 10048*uk_148 + 349448*uk_149 + 10275601*uk_15 + 362824*uk_150 + 262504*uk_151 + 376712*uk_152 + 272552*uk_153 + 197192*uk_154 + 9129329*uk_155 + 9478777*uk_156 + 6857917*uk_157 + 9841601*uk_158 + 7120421*uk_159 + 7434421*uk_16 + 5151641*uk_160 + 10218313*uk_161 + 7392973*uk_162 + 5348833*uk_163 + 3869893*uk_164 + 3969*uk_17 + 7497*uk_18 + 9891*uk_19 + 63*uk_2 + 504*uk_20 + 13167*uk_21 + 13671*uk_22 + 9891*uk_23 + 14161*uk_24 + 18683*uk_25 + 952*uk_26 + 24871*uk_27 + 25823*uk_28 + 18683*uk_29 + 119*uk_3 + 24649*uk_30 + 1256*uk_31 + 32813*uk_32 + 34069*uk_33 + 24649*uk_34 + 64*uk_35 + 1672*uk_36 + 1736*uk_37 + 1256*uk_38 + 43681*uk_39 + 157*uk_4 + 45353*uk_40 + 32813*uk_41 + 47089*uk_42 + 34069*uk_43 + 24649*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 266834486471*uk_47 + 352042137613*uk_48 + 17938452872*uk_49 + 8*uk_5 + 468642081281*uk_50 + 486580534153*uk_51 + 352042137613*uk_52 + 187944057*uk_53 + 355005441*uk_54 + 468368523*uk_55 + 23865912*uk_56 + 623496951*uk_57 + 647362863*uk_58 + 468368523*uk_59 + 209*uk_6 + 670565833*uk_60 + 884696099*uk_61 + 45080056*uk_62 + 1177716463*uk_63 + 1222796519*uk_64 + 884696099*uk_65 + 1167204097*uk_66 + 59475368*uk_67 + 1553793989*uk_68 + 1613269357*uk_69 + 217*uk_7 + 1167204097*uk_70 + 3030592*uk_71 + 79174216*uk_72 + 82204808*uk_73 + 59475368*uk_74 + 2068426393*uk_75 + 2147600609*uk_76 + 1553793989*uk_77 + 2229805417*uk_78 + 1613269357*uk_79 + 157*uk_8 + 1167204097*uk_80 + 250047*uk_81 + 472311*uk_82 + 623133*uk_83 + 31752*uk_84 + 829521*uk_85 + 861273*uk_86 + 623133*uk_87 + 892143*uk_88 + 1177029*uk_89 + 2242306609*uk_9 + 59976*uk_90 + 1566873*uk_91 + 1626849*uk_92 + 1177029*uk_93 + 1552887*uk_94 + 79128*uk_95 + 2067219*uk_96 + 2146347*uk_97 + 1552887*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 106344*uk_100 + 109368*uk_101 + 59976*uk_102 + 2804823*uk_103 + 2884581*uk_104 + 1581867*uk_105 + 2966607*uk_106 + 1626849*uk_107 + 892143*uk_108 + 704969*uk_109 + 4214417*uk_11 + 942599*uk_110 + 63368*uk_111 + 1671331*uk_112 + 1718857*uk_113 + 942599*uk_114 + 1260329*uk_115 + 84728*uk_116 + 2234701*uk_117 + 2298247*uk_118 + 1260329*uk_119 + 5635007*uk_12 + 5696*uk_120 + 150232*uk_121 + 154504*uk_122 + 84728*uk_123 + 3962369*uk_124 + 4075043*uk_125 + 2234701*uk_126 + 4190921*uk_127 + 2298247*uk_128 + 1260329*uk_129 + 378824*uk_13 + 1685159*uk_130 + 113288*uk_131 + 2987971*uk_132 + 3072937*uk_133 + 1685159*uk_134 + 7616*uk_135 + 200872*uk_136 + 206584*uk_137 + 113288*uk_138 + 5297999*uk_139 + 9991483*uk_14 + 5448653*uk_140 + 2987971*uk_141 + 5603591*uk_142 + 3072937*uk_143 + 1685159*uk_144 + 512*uk_145 + 13504*uk_146 + 13888*uk_147 + 7616*uk_148 + 356168*uk_149 + 10275601*uk_15 + 366296*uk_150 + 200872*uk_151 + 376712*uk_152 + 206584*uk_153 + 113288*uk_154 + 9393931*uk_155 + 9661057*uk_156 + 5297999*uk_157 + 9935779*uk_158 + 5448653*uk_159 + 5635007*uk_16 + 2987971*uk_160 + 10218313*uk_161 + 5603591*uk_162 + 3072937*uk_163 + 1685159*uk_164 + 3969*uk_17 + 5607*uk_18 + 7497*uk_19 + 63*uk_2 + 504*uk_20 + 13293*uk_21 + 13671*uk_22 + 7497*uk_23 + 7921*uk_24 + 10591*uk_25 + 712*uk_26 + 18779*uk_27 + 19313*uk_28 + 10591*uk_29 + 89*uk_3 + 14161*uk_30 + 952*uk_31 + 25109*uk_32 + 25823*uk_33 + 14161*uk_34 + 64*uk_35 + 1688*uk_36 + 1736*uk_37 + 952*uk_38 + 44521*uk_39 + 119*uk_4 + 45787*uk_40 + 25109*uk_41 + 47089*uk_42 + 25823*uk_43 + 14161*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 199565288201*uk_47 + 266834486471*uk_48 + 17938452872*uk_49 + 8*uk_5 + 473126694499*uk_50 + 486580534153*uk_51 + 266834486471*uk_52 + 187944057*uk_53 + 265508271*uk_54 + 355005441*uk_55 + 23865912*uk_56 + 629463429*uk_57 + 647362863*uk_58 + 355005441*uk_59 + 211*uk_6 + 375083113*uk_60 + 501515623*uk_61 + 33715336*uk_62 + 889241987*uk_63 + 914528489*uk_64 + 501515623*uk_65 + 670565833*uk_66 + 45080056*uk_67 + 1188986477*uk_68 + 1222796519*uk_69 + 217*uk_7 + 670565833*uk_70 + 3030592*uk_71 + 79931864*uk_72 + 82204808*uk_73 + 45080056*uk_74 + 2108202913*uk_75 + 2168151811*uk_76 + 1188986477*uk_77 + 2229805417*uk_78 + 1222796519*uk_79 + 119*uk_8 + 670565833*uk_80 + 250047*uk_81 + 353241*uk_82 + 472311*uk_83 + 31752*uk_84 + 837459*uk_85 + 861273*uk_86 + 472311*uk_87 + 499023*uk_88 + 667233*uk_89 + 2242306609*uk_9 + 44856*uk_90 + 1183077*uk_91 + 1216719*uk_92 + 667233*uk_93 + 892143*uk_94 + 59976*uk_95 + 1581867*uk_96 + 1626849*uk_97 + 892143*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 107352*uk_100 + 109368*uk_101 + 44856*uk_102 + 2858247*uk_103 + 2911923*uk_104 + 1194291*uk_105 + 2966607*uk_106 + 1216719*uk_107 + 499023*uk_108 + 300763*uk_109 + 3172651*uk_11 + 399521*uk_110 + 35912*uk_111 + 956157*uk_112 + 974113*uk_113 + 399521*uk_114 + 530707*uk_115 + 47704*uk_116 + 1270119*uk_117 + 1293971*uk_118 + 530707*uk_119 + 4214417*uk_12 + 4288*uk_120 + 114168*uk_121 + 116312*uk_122 + 47704*uk_123 + 3039723*uk_124 + 3096807*uk_125 + 1270119*uk_126 + 3154963*uk_127 + 1293971*uk_128 + 530707*uk_129 + 378824*uk_13 + 704969*uk_130 + 63368*uk_131 + 1687173*uk_132 + 1718857*uk_133 + 704969*uk_134 + 5696*uk_135 + 151656*uk_136 + 154504*uk_137 + 63368*uk_138 + 4037841*uk_139 + 10086189*uk_14 + 4113669*uk_140 + 1687173*uk_141 + 4190921*uk_142 + 1718857*uk_143 + 704969*uk_144 + 512*uk_145 + 13632*uk_146 + 13888*uk_147 + 5696*uk_148 + 362952*uk_149 + 10275601*uk_15 + 369768*uk_150 + 151656*uk_151 + 376712*uk_152 + 154504*uk_153 + 63368*uk_154 + 9663597*uk_155 + 9845073*uk_156 + 4037841*uk_157 + 10029957*uk_158 + 4113669*uk_159 + 4214417*uk_16 + 1687173*uk_160 + 10218313*uk_161 + 4190921*uk_162 + 1718857*uk_163 + 704969*uk_164 + 3969*uk_17 + 4221*uk_18 + 5607*uk_19 + 63*uk_2 + 504*uk_20 + 13419*uk_21 + 13671*uk_22 + 5607*uk_23 + 4489*uk_24 + 5963*uk_25 + 536*uk_26 + 14271*uk_27 + 14539*uk_28 + 5963*uk_29 + 67*uk_3 + 7921*uk_30 + 712*uk_31 + 18957*uk_32 + 19313*uk_33 + 7921*uk_34 + 64*uk_35 + 1704*uk_36 + 1736*uk_37 + 712*uk_38 + 45369*uk_39 + 89*uk_4 + 46221*uk_40 + 18957*uk_41 + 47089*uk_42 + 19313*uk_43 + 7921*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 150234542803*uk_47 + 199565288201*uk_48 + 17938452872*uk_49 + 8*uk_5 + 477611307717*uk_50 + 486580534153*uk_51 + 199565288201*uk_52 + 187944057*uk_53 + 199877013*uk_54 + 265508271*uk_55 + 23865912*uk_56 + 635429907*uk_57 + 647362863*uk_58 + 265508271*uk_59 + 213*uk_6 + 212567617*uk_60 + 282365939*uk_61 + 25381208*uk_62 + 675774663*uk_63 + 688465267*uk_64 + 282365939*uk_65 + 375083113*uk_66 + 33715336*uk_67 + 897670821*uk_68 + 914528489*uk_69 + 217*uk_7 + 375083113*uk_70 + 3030592*uk_71 + 80689512*uk_72 + 82204808*uk_73 + 33715336*uk_74 + 2148358257*uk_75 + 2188703013*uk_76 + 897670821*uk_77 + 2229805417*uk_78 + 914528489*uk_79 + 89*uk_8 + 375083113*uk_80 + 250047*uk_81 + 265923*uk_82 + 353241*uk_83 + 31752*uk_84 + 845397*uk_85 + 861273*uk_86 + 353241*uk_87 + 282807*uk_88 + 375669*uk_89 + 2242306609*uk_9 + 33768*uk_90 + 899073*uk_91 + 915957*uk_92 + 375669*uk_93 + 499023*uk_94 + 44856*uk_95 + 1194291*uk_96 + 1216719*uk_97 + 499023*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 108360*uk_100 + 109368*uk_101 + 33768*uk_102 + 2912175*uk_103 + 2939265*uk_104 + 907515*uk_105 + 2966607*uk_106 + 915957*uk_107 + 282807*uk_108 + 148877*uk_109 + 2509709*uk_11 + 188203*uk_110 + 22472*uk_111 + 603935*uk_112 + 609553*uk_113 + 188203*uk_114 + 237917*uk_115 + 28408*uk_116 + 763465*uk_117 + 770567*uk_118 + 237917*uk_119 + 3172651*uk_12 + 3392*uk_120 + 91160*uk_121 + 92008*uk_122 + 28408*uk_123 + 2449925*uk_124 + 2472715*uk_125 + 763465*uk_126 + 2495717*uk_127 + 770567*uk_128 + 237917*uk_129 + 378824*uk_13 + 300763*uk_130 + 35912*uk_131 + 965135*uk_132 + 974113*uk_133 + 300763*uk_134 + 4288*uk_135 + 115240*uk_136 + 116312*uk_137 + 35912*uk_138 + 3097075*uk_139 + 10180895*uk_14 + 3125885*uk_140 + 965135*uk_141 + 3154963*uk_142 + 974113*uk_143 + 300763*uk_144 + 512*uk_145 + 13760*uk_146 + 13888*uk_147 + 4288*uk_148 + 369800*uk_149 + 10275601*uk_15 + 373240*uk_150 + 115240*uk_151 + 376712*uk_152 + 116312*uk_153 + 35912*uk_154 + 9938375*uk_155 + 10030825*uk_156 + 3097075*uk_157 + 10124135*uk_158 + 3125885*uk_159 + 3172651*uk_16 + 965135*uk_160 + 10218313*uk_161 + 3154963*uk_162 + 974113*uk_163 + 300763*uk_164 + 3969*uk_17 + 3339*uk_18 + 4221*uk_19 + 63*uk_2 + 504*uk_20 + 13545*uk_21 + 13671*uk_22 + 4221*uk_23 + 2809*uk_24 + 3551*uk_25 + 424*uk_26 + 11395*uk_27 + 11501*uk_28 + 3551*uk_29 + 53*uk_3 + 4489*uk_30 + 536*uk_31 + 14405*uk_32 + 14539*uk_33 + 4489*uk_34 + 64*uk_35 + 1720*uk_36 + 1736*uk_37 + 536*uk_38 + 46225*uk_39 + 67*uk_4 + 46655*uk_40 + 14405*uk_41 + 47089*uk_42 + 14539*uk_43 + 4489*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 118842250277*uk_47 + 150234542803*uk_48 + 17938452872*uk_49 + 8*uk_5 + 482095920935*uk_50 + 486580534153*uk_51 + 150234542803*uk_52 + 187944057*uk_53 + 158111667*uk_54 + 199877013*uk_55 + 23865912*uk_56 + 641396385*uk_57 + 647362863*uk_58 + 199877013*uk_59 + 215*uk_6 + 133014577*uk_60 + 168150503*uk_61 + 20077672*uk_62 + 539587435*uk_63 + 544606853*uk_64 + 168150503*uk_65 + 212567617*uk_66 + 25381208*uk_67 + 682119965*uk_68 + 688465267*uk_69 + 217*uk_7 + 212567617*uk_70 + 3030592*uk_71 + 81447160*uk_72 + 82204808*uk_73 + 25381208*uk_74 + 2188892425*uk_75 + 2209254215*uk_76 + 682119965*uk_77 + 2229805417*uk_78 + 688465267*uk_79 + 67*uk_8 + 212567617*uk_80 + 250047*uk_81 + 210357*uk_82 + 265923*uk_83 + 31752*uk_84 + 853335*uk_85 + 861273*uk_86 + 265923*uk_87 + 176967*uk_88 + 223713*uk_89 + 2242306609*uk_9 + 26712*uk_90 + 717885*uk_91 + 724563*uk_92 + 223713*uk_93 + 282807*uk_94 + 33768*uk_95 + 907515*uk_96 + 915957*uk_97 + 282807*uk_98 + 4032*uk_99, uk_0 + 47353*uk_1 + 2983239*uk_10 + 109368*uk_100 + 109368*uk_101 + 26712*uk_102 + 2966607*uk_103 + 2966607*uk_104 + 724563*uk_105 + 2966607*uk_106 + 724563*uk_107 + 176967*uk_108 + 103823*uk_109 + 2225591*uk_11 + 117077*uk_110 + 17672*uk_111 + 479353*uk_112 + 479353*uk_113 + 117077*uk_114 + 132023*uk_115 + 19928*uk_116 + 540547*uk_117 + 540547*uk_118 + 132023*uk_119 + 2509709*uk_12 + 3008*uk_120 + 81592*uk_121 + 81592*uk_122 + 19928*uk_123 + 2213183*uk_124 + 2213183*uk_125 + 540547*uk_126 + 2213183*uk_127 + 540547*uk_128 + 132023*uk_129 + 378824*uk_13 + 148877*uk_130 + 22472*uk_131 + 609553*uk_132 + 609553*uk_133 + 148877*uk_134 + 3392*uk_135 + 92008*uk_136 + 92008*uk_137 + 22472*uk_138 + 2495717*uk_139 + 10275601*uk_14 + 2495717*uk_140 + 609553*uk_141 + 2495717*uk_142 + 609553*uk_143 + 148877*uk_144 + 512*uk_145 + 13888*uk_146 + 13888*uk_147 + 3392*uk_148 + 376712*uk_149 + 10275601*uk_15 + 376712*uk_150 + 92008*uk_151 + 376712*uk_152 + 92008*uk_153 + 22472*uk_154 + 10218313*uk_155 + 10218313*uk_156 + 2495717*uk_157 + 10218313*uk_158 + 2495717*uk_159 + 2509709*uk_16 + 609553*uk_160 + 10218313*uk_161 + 2495717*uk_162 + 609553*uk_163 + 148877*uk_164 + 3969*uk_17 + 2961*uk_18 + 3339*uk_19 + 63*uk_2 + 504*uk_20 + 13671*uk_21 + 13671*uk_22 + 3339*uk_23 + 2209*uk_24 + 2491*uk_25 + 376*uk_26 + 10199*uk_27 + 10199*uk_28 + 2491*uk_29 + 47*uk_3 + 2809*uk_30 + 424*uk_31 + 11501*uk_32 + 11501*uk_33 + 2809*uk_34 + 64*uk_35 + 1736*uk_36 + 1736*uk_37 + 424*uk_38 + 47089*uk_39 + 53*uk_4 + 47089*uk_40 + 11501*uk_41 + 47089*uk_42 + 11501*uk_43 + 2809*uk_44 + 106179944855977*uk_45 + 141265316367*uk_46 + 105388410623*uk_47 + 118842250277*uk_48 + 17938452872*uk_49 + 8*uk_5 + 486580534153*uk_50 + 486580534153*uk_51 + 118842250277*uk_52 + 187944057*uk_53 + 140212233*uk_54 + 158111667*uk_55 + 23865912*uk_56 + 647362863*uk_57 + 647362863*uk_58 + 158111667*uk_59 + 217*uk_6 + 104602777*uk_60 + 117956323*uk_61 + 17804728*uk_62 + 482953247*uk_63 + 482953247*uk_64 + 117956323*uk_65 + 133014577*uk_66 + 20077672*uk_67 + 544606853*uk_68 + 544606853*uk_69 + 217*uk_7 + 133014577*uk_70 + 3030592*uk_71 + 82204808*uk_72 + 82204808*uk_73 + 20077672*uk_74 + 2229805417*uk_75 + 2229805417*uk_76 + 544606853*uk_77 + 2229805417*uk_78 + 544606853*uk_79 + 53*uk_8 + 133014577*uk_80 + 250047*uk_81 + 186543*uk_82 + 210357*uk_83 + 31752*uk_84 + 861273*uk_85 + 861273*uk_86 + 210357*uk_87 + 139167*uk_88 + 156933*uk_89 + 2242306609*uk_9 + 23688*uk_90 + 642537*uk_91 + 642537*uk_92 + 156933*uk_93 + 176967*uk_94 + 26712*uk_95 + 724563*uk_96 + 724563*uk_97 + 176967*uk_98 + 4032*uk_99, ] def sol_165x165(): return { uk_0: -QQ(295441,1683)*uk_2 - QQ(175799,1683)*uk_7 + QQ(2401696807,1)*uk_9 - QQ(9606787228,1683)*uk_10 + QQ(9606787228,1683)*uk_15 - QQ(29030443,1683)*uk_17 - QQ(5965893,187)*uk_22 + QQ(262901,99)*uk_42 + QQ(235539209256104,1)*uk_45 - QQ(232597130667529,1683)*uk_46 + QQ(1364372733998209,1683)*uk_51 - QQ(1133600892904,1683)*uk_53 - QQ(172922170104,187)*uk_58 + QQ(249776467928,99)*uk_78 - QQ(2401889209,1683)*uk_81 - QQ(636292759,187)*uk_86 - QQ(1034157281,187)*uk_106 + QQ(10558824289,1683)*uk_161, uk_1: QQ(4,1683)*uk_2 - QQ(4,1683)*uk_7 - QQ(98072,1)*uk_9 + QQ(96847,1683)*uk_10 - QQ(568087,1683)*uk_15 + QQ(472,1683)*uk_17 + QQ(72,187)*uk_22 - QQ(104,99)*uk_42 - QQ(7216420377,1)*uk_45 - QQ(108808244,1683)*uk_46 - QQ(46106641036,1683)*uk_51 + QQ(17259541,1683)*uk_53 + QQ(1095291,187)*uk_58 - QQ(9936587,99)*uk_78 + QQ(41836,1683)*uk_81 + QQ(10036,187)*uk_86 + QQ(10124,187)*uk_106 - QQ(8,1)*uk_149 - QQ(586156,1683)*uk_161, uk_3: -QQ(295441,1683)*uk_18 - QQ(175799,1683)*uk_28 + QQ(2401696807,1)*uk_47 - QQ(9606787228,1683)*uk_54 + QQ(9606787228,1683)*uk_64 - QQ(29030443,1683)*uk_82 - QQ(5965893,187)*uk_92 + QQ(262901,99)*uk_127 + QQ(8,1)*uk_149, uk_4: -QQ(295441,1683)*uk_19 + QQ(1602583,3366)*uk_29 - QQ(175799,1683)*uk_33 - QQ(45670,99)*uk_34 - QQ(76006,187)*uk_38 + QQ(295441,1683)*uk_41 - QQ(45670,99)*uk_44 + QQ(2401696807,1)*uk_48 - QQ(9606787228,1683)*uk_55 + QQ(74452601017,3366)*uk_65 + QQ(9606787228,1683)*uk_69 - QQ(2401696807,99)*uk_70 - QQ(4803393614,187)*uk_74 + QQ(9606787228,1683)*uk_77 - QQ(2401696807,99)*uk_80 - QQ(29030443,1683)*uk_83 + QQ(11596905,374)*uk_93 - QQ(5965893,187)*uk_97 - QQ(769658,33)*uk_98 - QQ(17335370,1683)*uk_102 + QQ(29030443,1683)*uk_105 - QQ(769658,33)*uk_108 + QQ(77314807,3366)*uk_114 + QQ(750229,198)*uk_119 + QQ(72457964,1683)*uk_123 + QQ(11596905,374)*uk_126 + QQ(31304645,306)*uk_128 + QQ(750229,198)*uk_129 - QQ(3191393,99)*uk_134 - QQ(647642,9)*uk_138 - QQ(769658,33)*uk_141 + QQ(262901,99)*uk_142 - QQ(10478626,99)*uk_143 - QQ(3191393,99)*uk_144 - QQ(20480616,187)*uk_148 - QQ(17335370,1683)*uk_151 - QQ(174199750,1683)*uk_153 - QQ(647642,9)*uk_154 + QQ(29030443,1683)*uk_157 + QQ(5965893,187)*uk_159 - QQ(769658,33)*uk_160 - QQ(10478626,99)*uk_163 - QQ(3191393,99)*uk_164, uk_5: -QQ(295441,1683)*uk_20 - QQ(175799,1683)*uk_37 + QQ(2401696807,1)*uk_49 - QQ(9606787228,1683)*uk_56 + QQ(9606787228,1683)*uk_73 - QQ(29030443,1683)*uk_84 - QQ(5965893,187)*uk_101 + QQ(262901,99)*uk_152, uk_6: -QQ(295441,1683)*uk_21 - QQ(175799,1683)*uk_40 + QQ(2401696807,1)*uk_50 - QQ(9606787228,1683)*uk_57 + QQ(9606787228,1683)*uk_76 - QQ(29030443,1683)*uk_85 - QQ(5965893,187)*uk_104 + QQ(262901,99)*uk_158, uk_8: -QQ(295441,1683)*uk_23 - QQ(1602583,3366)*uk_29 + QQ(45670,99)*uk_34 + QQ(76006,187)*uk_38 - QQ(295441,1683)*uk_41 - QQ(175799,1683)*uk_43 + QQ(45670,99)*uk_44 + QQ(2401696807,1)*uk_52 - QQ(9606787228,1683)*uk_59 - QQ(74452601017,3366)*uk_65 + QQ(2401696807,99)*uk_70 + QQ(4803393614,187)*uk_74 - QQ(9606787228,1683)*uk_77 + QQ(9606787228,1683)*uk_79 + QQ(2401696807,99)*uk_80 - QQ(29030443,1683)*uk_87 - QQ(11596905,374)*uk_93 + QQ(769658,33)*uk_98 + QQ(17335370,1683)*uk_102 - QQ(29030443,1683)*uk_105 - QQ(5965893,187)*uk_107 + QQ(769658,33)*uk_108 - QQ(77314807,3366)*uk_114 - QQ(750229,198)*uk_119 - QQ(72457964,1683)*uk_123 - QQ(11596905,374)*uk_126 - QQ(31304645,306)*uk_128 - QQ(750229,198)*uk_129 + QQ(3191393,99)*uk_134 + QQ(647642,9)*uk_138 + QQ(769658,33)*uk_141 + QQ(10478626,99)*uk_143 + QQ(3191393,99)*uk_144 + QQ(20480616,187)*uk_148 + QQ(17335370,1683)*uk_151 + QQ(174199750,1683)*uk_153 + QQ(647642,9)*uk_154 - QQ(29030443,1683)*uk_157 - QQ(5965893,187)*uk_159 + QQ(769658,33)*uk_160 + QQ(262901,99)*uk_162 + QQ(10478626,99)*uk_163 + QQ(3191393,99)*uk_164, uk_11: QQ(4,1683)*uk_18 - QQ(4,1683)*uk_28 - QQ(98072,1)*uk_47 + QQ(96847,1683)*uk_54 - QQ(568087,1683)*uk_64 + QQ(472,1683)*uk_82 + QQ(72,187)*uk_92 - QQ(104,99)*uk_127, uk_12: QQ(4,1683)*uk_19 - QQ(31,3366)*uk_29 - QQ(4,1683)*uk_33 + QQ(1,99)*uk_34 + QQ(2,187)*uk_38 - QQ(4,1683)*uk_41 + QQ(1,99)*uk_44 - QQ(98072,1)*uk_48 + QQ(96847,1683)*uk_55 - QQ(1437649,3366)*uk_65 - QQ(568087,1683)*uk_69 + QQ(52402,99)*uk_70 + QQ(120138,187)*uk_74 - QQ(96847,1683)*uk_77 + QQ(52402,99)*uk_80 + QQ(472,1683)*uk_83 - QQ(225,374)*uk_93 + QQ(72,187)*uk_97 + QQ(17,33)*uk_98 + QQ(590,1683)*uk_102 - QQ(472,1683)*uk_105 + QQ(17,33)*uk_108 - QQ(1519,3366)*uk_114 - QQ(13,198)*uk_119 - QQ(1388,1683)*uk_123 - QQ(225,374)*uk_126 - QQ(605,306)*uk_128 - QQ(13,198)*uk_129 + QQ(68,99)*uk_134 + QQ(14,9)*uk_138 + QQ(17,33)*uk_141 - QQ(104,99)*uk_142 + QQ(229,99)*uk_143 + QQ(68,99)*uk_144 + QQ(472,187)*uk_148 + QQ(590,1683)*uk_151 + QQ(4450,1683)*uk_153 + QQ(14,9)*uk_154 - QQ(472,1683)*uk_157 - QQ(72,187)*uk_159 + QQ(17,33)*uk_160 + QQ(229,99)*uk_163 + QQ(68,99)*uk_164, uk_13: QQ(4,1683)*uk_20 - QQ(4,1683)*uk_37 - QQ(98072,1)*uk_49 + QQ(96847,1683)*uk_56 - QQ(568087,1683)*uk_73 + QQ(472,1683)*uk_84 + QQ(72,187)*uk_101 - QQ(104,99)*uk_152, uk_14: QQ(4,1683)*uk_21 - QQ(4,1683)*uk_40 - QQ(98072,1)*uk_50 + QQ(96847,1683)*uk_57 - QQ(568087,1683)*uk_76 + QQ(472,1683)*uk_85 + QQ(72,187)*uk_104 - QQ(104,99)*uk_158, uk_16: QQ(4,1683)*uk_23 + QQ(31,3366)*uk_29 - QQ(1,99)*uk_34 - QQ(2,187)*uk_38 + QQ(4,1683)*uk_41 - QQ(4,1683)*uk_43 - QQ(1,99)*uk_44 - QQ(98072,1)*uk_52 + QQ(96847,1683)*uk_59 + QQ(1437649,3366)*uk_65 - QQ(52402,99)*uk_70 - QQ(120138,187)*uk_74 + QQ(96847,1683)*uk_77 - QQ(568087,1683)*uk_79 - QQ(52402,99)*uk_80 + QQ(472,1683)*uk_87 + QQ(225,374)*uk_93 - QQ(17,33)*uk_98 - QQ(590,1683)*uk_102 + QQ(472,1683)*uk_105 + QQ(72,187)*uk_107 - QQ(17,33)*uk_108 + QQ(1519,3366)*uk_114 + QQ(13,198)*uk_119 + QQ(1388,1683)*uk_123 + QQ(225,374)*uk_126 + QQ(605,306)*uk_128 + QQ(13,198)*uk_129 - QQ(68,99)*uk_134 - QQ(14,9)*uk_138 - QQ(17,33)*uk_141 - QQ(229,99)*uk_143 - QQ(68,99)*uk_144 - QQ(472,187)*uk_148 - QQ(590,1683)*uk_151 - QQ(4450,1683)*uk_153 - QQ(14,9)*uk_154 + QQ(472,1683)*uk_157 + QQ(72,187)*uk_159 - QQ(17,33)*uk_160 - QQ(104,99)*uk_162 - QQ(229,99)*uk_163 - QQ(68,99)*uk_164, uk_24: -QQ(295441,1683)*uk_88 - QQ(175799,1683)*uk_113, uk_26: -QQ(295441,1683)*uk_90 - QQ(175799,1683)*uk_122, uk_25: -uk_29 - QQ(295441,1683)*uk_89 - QQ(295441,1683)*uk_93 - QQ(175799,1683)*uk_118 - QQ(175799,1683)*uk_128, uk_27: -QQ(295441,1683)*uk_91 - QQ(175799,1683)*uk_125 - QQ(4,1)*uk_149, uk_30: -uk_34 - uk_44 - QQ(295441,1683)*uk_94 - QQ(295441,1683)*uk_98 - QQ(295441,1683)*uk_108 - QQ(175799,1683)*uk_133 - QQ(175799,1683)*uk_143 - QQ(175799,1683)*uk_163, uk_31: -uk_38 - QQ(295441,1683)*uk_95 - QQ(295441,1683)*uk_102 - QQ(175799,1683)*uk_137 - QQ(175799,1683)*uk_153, uk_32: -uk_41 - QQ(295441,1683)*uk_96 - QQ(295441,1683)*uk_105 - QQ(175799,1683)*uk_140 + QQ(4,1)*uk_149 - QQ(175799,1683)*uk_159, uk_35: -QQ(295441,1683)*uk_99 - QQ(175799,1683)*uk_147, uk_36: -QQ(295441,1683)*uk_100 - QQ(2,1)*uk_149 - QQ(175799,1683)*uk_150, uk_39: -QQ(295441,1683)*uk_103 - QQ(175799,1683)*uk_156, uk_60: QQ(4,1683)*uk_88 - QQ(4,1683)*uk_113, uk_61: -uk_65 + QQ(4,1683)*uk_89 + QQ(4,1683)*uk_93 - QQ(4,1683)*uk_118 - QQ(4,1683)*uk_128, uk_62: QQ(4,1683)*uk_90 - QQ(4,1683)*uk_122, uk_63: QQ(4,1683)*uk_91 - QQ(4,1683)*uk_125, uk_66: -uk_70 - uk_80 + QQ(4,1683)*uk_94 + QQ(4,1683)*uk_98 + QQ(4,1683)*uk_108 - QQ(4,1683)*uk_133 - QQ(4,1683)*uk_143 - QQ(4,1683)*uk_163, uk_67: -uk_74 + QQ(4,1683)*uk_95 + QQ(4,1683)*uk_102 - QQ(4,1683)*uk_137 - QQ(4,1683)*uk_153, uk_68: -uk_77 + QQ(4,1683)*uk_96 + QQ(4,1683)*uk_105 - QQ(4,1683)*uk_140 - QQ(4,1683)*uk_159, uk_71: QQ(4,1683)*uk_99 - QQ(4,1683)*uk_147, uk_72: QQ(4,1683)*uk_100 - QQ(4,1683)*uk_150, uk_75: QQ(4,1683)*uk_103 - QQ(4,1683)*uk_156, uk_109: 0, uk_110: -uk_114, uk_111: 0, uk_112: 0, uk_115: -uk_119 - uk_129, uk_116: -uk_123, uk_117: -uk_126, uk_120: 0, uk_121: 0, uk_124: 0, uk_130: -uk_134 - uk_144 - uk_164, uk_131: -uk_138 - uk_154, uk_132: -uk_141 - uk_160, uk_135: -uk_148, uk_136: -uk_151, uk_139: -uk_157, uk_145: 0, uk_146: 0, uk_155: 0, } def time_eqs_165x165(): if len(eqs_165x165()) != 165: raise ValueError("length should be 165") def time_solve_lin_sys_165x165(): eqs = eqs_165x165() sol = solve_lin_sys(eqs, R_165) if sol != sol_165x165(): raise ValueError("Value should be equal") def time_verify_sol_165x165(): eqs = eqs_165x165() sol = sol_165x165() zeros = [ eq.compose(sol) for eq in eqs ] if not all([ zero == 0 for zero in zeros ]): raise ValueError("All should be 0") def time_to_expr_eqs_165x165(): eqs = eqs_165x165() assert [ R_165.from_expr(eq.as_expr()) for eq in eqs ] == eqs # Benchmark R_49: shows how fast are arithmetics in rational function fields. F_abc, a, b, c = field("a,b,c", ZZ) R_49, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49 = ring("k1:50", F_abc) def eqs_189x49(): return [ -b*k8/a+c*k8/a, -b*k11/a+c*k11/a, -b*k10/a+c*k10/a+k2, -k3-b*k9/a+c*k9/a, -b*k14/a+c*k14/a, -b*k15/a+c*k15/a, -b*k18/a+c*k18/a-k2, -b*k17/a+c*k17/a, -b*k16/a+c*k16/a+k4, -b*k13/a+c*k13/a-b*k21/a+c*k21/a+b*k5/a-c*k5/a, b*k44/a-c*k44/a, -b*k45/a+c*k45/a, -b*k20/a+c*k20/a, -b*k44/a+c*k44/a, b*k46/a-c*k46/a, b**2*k47/a**2-2*b*c*k47/a**2+c**2*k47/a**2, k3, -k4, -b*k12/a+c*k12/a-a*k6/b+c*k6/b, -b*k19/a+c*k19/a+a*k7/c-b*k7/c, b*k45/a-c*k45/a, -b*k46/a+c*k46/a, -k48+c*k48/a+c*k48/b-c**2*k48/(a*b), -k49+b*k49/a+b*k49/c-b**2*k49/(a*c), a*k1/b-c*k1/b, a*k4/b-c*k4/b, a*k3/b-c*k3/b+k9, -k10+a*k2/b-c*k2/b, a*k7/b-c*k7/b, -k9, k11, b*k12/a-c*k12/a+a*k6/b-c*k6/b, a*k15/b-c*k15/b, k10+a*k18/b-c*k18/b, -k11+a*k17/b-c*k17/b, a*k16/b-c*k16/b, -a*k13/b+c*k13/b+a*k21/b-c*k21/b+a*k5/b-c*k5/b, -a*k44/b+c*k44/b, a*k45/b-c*k45/b, a*k14/c-b*k14/c+a*k20/b-c*k20/b, a*k44/b-c*k44/b, -a*k46/b+c*k46/b, -k47+c*k47/a+c*k47/b-c**2*k47/(a*b), a*k19/b-c*k19/b, -a*k45/b+c*k45/b, a*k46/b-c*k46/b, a**2*k48/b**2-2*a*c*k48/b**2+c**2*k48/b**2, -k49+a*k49/b+a*k49/c-a**2*k49/(b*c), k16, -k17, -a*k1/c+b*k1/c, -k16-a*k4/c+b*k4/c, -a*k3/c+b*k3/c, k18-a*k2/c+b*k2/c, b*k19/a-c*k19/a-a*k7/c+b*k7/c, -a*k6/c+b*k6/c, -a*k8/c+b*k8/c, -a*k11/c+b*k11/c+k17, -a*k10/c+b*k10/c-k18, -a*k9/c+b*k9/c, -a*k14/c+b*k14/c-a*k20/b+c*k20/b, -a*k13/c+b*k13/c+a*k21/c-b*k21/c-a*k5/c+b*k5/c, a*k44/c-b*k44/c, -a*k45/c+b*k45/c, -a*k44/c+b*k44/c, a*k46/c-b*k46/c, -k47+b*k47/a+b*k47/c-b**2*k47/(a*c), -a*k12/c+b*k12/c, a*k45/c-b*k45/c, -a*k46/c+b*k46/c, -k48+a*k48/b+a*k48/c-a**2*k48/(b*c), a**2*k49/c**2-2*a*b*k49/c**2+b**2*k49/c**2, k8, k11, -k15, k10-k18, -k17, k9, -k16, -k29, k14-k32, -k21+k23-k31, -k24-k30, -k35, k44, -k45, k36, k13-k23+k39, -k20+k38, k25+k37, b*k26/a-c*k26/a-k34+k42, -2*k44, k45, k46, b*k47/a-c*k47/a, k41, k44, -k46, -b*k47/a+c*k47/a, k12+k24, -k19-k25, -a*k27/b+c*k27/b-k33, k45, -k46, -a*k48/b+c*k48/b, a*k28/c-b*k28/c+k40, -k45, k46, a*k48/b-c*k48/b, a*k49/c-b*k49/c, -a*k49/c+b*k49/c, -k1, -k4, -k3, k15, k18-k2, k17, k16, k22, k25-k7, k24+k30, k21+k23-k31, k28, -k44, k45, -k30-k6, k20+k32, k27+b*k33/a-c*k33/a, k44, -k46, -b*k47/a+c*k47/a, -k36, k31-k39-k5, -k32-k38, k19-k37, k26-a*k34/b+c*k34/b-k42, k44, -2*k45, k46, a*k48/b-c*k48/b, a*k35/c-b*k35/c-k41, -k44, k46, b*k47/a-c*k47/a, -a*k49/c+b*k49/c, -k40, k45, -k46, -a*k48/b+c*k48/b, a*k49/c-b*k49/c, k1, k4, k3, -k8, -k11, -k10+k2, -k9, k37+k7, -k14-k38, -k22, -k25-k37, -k24+k6, -k13-k23+k39, -k28+b*k40/a-c*k40/a, k44, -k45, -k27, -k44, k46, b*k47/a-c*k47/a, k29, k32+k38, k31-k39+k5, -k12+k30, k35-a*k41/b+c*k41/b, -k44, k45, -k26+k34+a*k42/c-b*k42/c, k44, k45, -2*k46, -b*k47/a+c*k47/a, -a*k48/b+c*k48/b, a*k49/c-b*k49/c, k33, -k45, k46, a*k48/b-c*k48/b, -a*k49/c+b*k49/c, ] def sol_189x49(): return { k49: 0, k48: 0, k47: 0, k46: 0, k45: 0, k44: 0, k41: 0, k40: 0, k38: 0, k37: 0, k36: 0, k35: 0, k33: 0, k32: 0, k30: 0, k29: 0, k28: 0, k27: 0, k25: 0, k24: 0, k22: 0, k21: 0, k20: 0, k19: 0, k18: 0, k17: 0, k16: 0, k15: 0, k14: 0, k13: 0, k12: 0, k11: 0, k10: 0, k9: 0, k8: 0, k7: 0, k6: 0, k5: 0, k4: 0, k3: 0, k2: 0, k1: 0, k34: b/c*k42, k31: k39, k26: a/c*k42, k23: k39, } def time_eqs_189x49(): if len(eqs_189x49()) != 189: raise ValueError("Length should be equal to 189") def time_solve_lin_sys_189x49(): eqs = eqs_189x49() sol = solve_lin_sys(eqs, R_49) if sol != sol_189x49(): raise ValueError("Values should be equal") def time_verify_sol_189x49(): eqs = eqs_189x49() sol = sol_189x49() zeros = [ eq.compose(sol) for eq in eqs ] assert all([ zero == 0 for zero in zeros ]) def time_to_expr_eqs_189x49(): eqs = eqs_189x49() assert [ R_49.from_expr(eq.as_expr()) for eq in eqs ] == eqs # Benchmark R_8: shows how fast polynomial GCDs are computed. F_a5_5, a_11, a_12, a_13, a_14, a_21, a_22, a_23, a_24, a_31, a_32, a_33, a_34, a_41, a_42, a_43, a_44 = field("a_(1:5)(1:5)", ZZ) R_8, x0, x1, x2, x3, x4, x5, x6, x7 = ring("x:8", F_a5_5) def eqs_10x8(): return [ (a_33*a_34 + a_33*a_44 + a_43*a_44)*x3 + (a_33*a_34 + a_33*a_44 + a_43*a_44)*x4 + (a_12*a_34 + a_12*a_44 + a_22*a_34 + a_22*a_44)*x5 + (a_12*a_44 + a_22*a_44)*x6 + (a_12*a_33 + a_22*a_33)*x7 - a_12*a_33 - a_12*a_43 - a_22*a_33 - a_22*a_43, (a_33 + a_34 + a_43 + a_44)*x3 + (a_33 + a_34 + a_43 + a_44)*x4 + (a_12 + a_22 + a_34 + a_44)*x5 + (a_12 + a_22 + a_44)*x6 + (a_12 + a_22 + a_33)*x7 - a_12 - a_22 - a_33 - a_43, x3 + x4 + x5 + x6 + x7 - 1, (a_12*a_33*a_34 + a_12*a_33*a_44 + a_12*a_43*a_44 + a_22*a_33*a_34 + a_22*a_33*a_44 + a_22*a_43*a_44)*x0 + (a_22*a_33*a_34 + a_22*a_33*a_44 + a_22*a_43*a_44)*x1 + (a_12*a_33*a_34 + a_12*a_33*a_44 + a_12*a_43*a_44 + a_22*a_33*a_34 + a_22*a_33*a_44 + a_22*a_43*a_44)*x2 + (a_11*a_33*a_34 + a_11*a_33*a_44 + a_11*a_43*a_44 + a_31*a_33*a_34 + a_31*a_33*a_44 + a_31*a_43*a_44)*x3 + (a_11*a_33*a_34 + a_11*a_33*a_44 + a_11*a_43*a_44 + a_21*a_33*a_34 + a_21*a_33*a_44 + a_21*a_43*a_44 + a_31*a_33*a_34 + a_31*a_33*a_44 + a_31*a_43*a_44)*x4 + (a_11*a_12*a_34 + a_11*a_12*a_44 + a_11*a_22*a_34 + a_11*a_22*a_44 + a_12*a_31*a_34 + a_12*a_31*a_44 + a_21*a_22*a_34 + a_21*a_22*a_44 + a_22*a_31*a_34 + a_22*a_31*a_44)*x5 + (a_11*a_12*a_44 + a_11*a_22*a_44 + a_12*a_31*a_44 + a_21*a_22*a_44 + a_22*a_31*a_44)*x6 + (a_11*a_12*a_33 + a_11*a_22*a_33 + a_12*a_31*a_33 + a_21*a_22*a_33 + a_22*a_31*a_33)*x7 - a_11*a_12*a_33 - a_11*a_12*a_43 - a_11*a_22*a_33 - a_11*a_22*a_43 - a_12*a_31*a_33 - a_12*a_31*a_43 - a_21*a_22*a_33 - a_21*a_22*a_43 - a_22*a_31*a_33 - a_22*a_31*a_43, (a_12*a_33 + a_12*a_34 + a_12*a_43 + a_12*a_44 + a_22*a_33 + a_22*a_34 + a_22*a_43 + a_22*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x0 + (a_22*a_33 + a_22*a_34 + a_22*a_43 + a_22*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x1 + (a_12*a_33 + a_12*a_34 + a_12*a_43 + a_12*a_44 + a_22*a_33 + a_22*a_34 + a_22*a_43 + a_22*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x2 + (a_11*a_33 + a_11*a_34 + a_11*a_43 + a_11*a_44 + a_31*a_33 + a_31*a_34 + a_31*a_43 + a_31*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x3 + (a_11*a_33 + a_11*a_34 + a_11*a_43 + a_11*a_44 + a_21*a_33 + a_21*a_34 + a_21*a_43 + a_21*a_44 + a_31*a_33 + a_31*a_34 + a_31*a_43 + a_31*a_44 + a_33*a_34 + a_33*a_44 + a_43*a_44)*x4 + (a_11*a_12 + a_11*a_22 + a_11*a_34 + a_11*a_44 + a_12*a_31 + a_12*a_34 + a_12*a_44 + a_21*a_22 + a_21*a_34 + a_21*a_44 + a_22*a_31 + a_22*a_34 + a_22*a_44 + a_31*a_34 + a_31*a_44)*x5 + (a_11*a_12 + a_11*a_22 + a_11*a_44 + a_12*a_31 + a_12*a_44 + a_21*a_22 + a_21*a_44 + a_22*a_31 + a_22*a_44 + a_31*a_44)*x6 + (a_11*a_12 + a_11*a_22 + a_11*a_33 + a_12*a_31 + a_12*a_33 + a_21*a_22 + a_21*a_33 + a_22*a_31 + a_22*a_33 + a_31*a_33)*x7 - a_11*a_12 - a_11*a_22 - a_11*a_33 - a_11*a_43 - a_12*a_31 - a_12*a_33 - a_12*a_43 - a_21*a_22 - a_21*a_33 - a_21*a_43 - a_22*a_31 - a_22*a_33 - a_22*a_43 - a_31*a_33 - a_31*a_43, (a_12 + a_22 + a_33 + a_34 + a_43 + a_44)*x0 + (a_22 + a_33 + a_34 + a_43 + a_44)*x1 + (a_12 + a_22 + a_33 + a_34 + a_43 + a_44)*x2 + (a_11 + a_31 + a_33 + a_34 + a_43 + a_44)*x3 + (a_11 + a_21 + a_31 + a_33 + a_34 + a_43 + a_44)*x4 + (a_11 + a_12 + a_21 + a_22 + a_31 + a_34 + a_44)*x5 + (a_11 + a_12 + a_21 + a_22 + a_31 + a_44)*x6 + (a_11 + a_12 + a_21 + a_22 + a_31 + a_33)*x7 - a_11 - a_12 - a_21 - a_22 - a_31 - a_33 - a_43, x0 + x1 + x2 + x3 + x4 + x5 + x6 + x7 - 1, (a_12*a_34 + a_12*a_44 + a_22*a_34 + a_22*a_44)*x2 + (a_31*a_34 + a_31*a_44)*x3 + (a_31*a_34 + a_31*a_44)*x4 + (a_12*a_31 + a_22*a_31)*x7 - a_12*a_31 - a_22*a_31, (a_12 + a_22 + a_34 + a_44)*x2 + a_31*x3 + a_31*x4 + a_31*x7 - a_31, x2, ] def sol_10x8(): return { x0: -a_21/a_12*x4, x1: a_21/a_12*x4, x2: 0, x3: -x4, x5: a_43/a_34, x6: -a_43/a_34, x7: 1, } def time_eqs_10x8(): if len(eqs_10x8()) != 10: raise ValueError("Value should be equal to 10") def time_solve_lin_sys_10x8(): eqs = eqs_10x8() sol = solve_lin_sys(eqs, R_8) if sol != sol_10x8(): raise ValueError("Values should be equal") def time_verify_sol_10x8(): eqs = eqs_10x8() sol = sol_10x8() zeros = [ eq.compose(sol) for eq in eqs ] if not all([ zero == 0 for zero in zeros ]): raise ValueError("All values in zero should be 0") def time_to_expr_eqs_10x8(): eqs = eqs_10x8() assert [ R_8.from_expr(eq.as_expr()) for eq in eqs ] == eqs sympy-sympy-1.9/sympy/polys/compatibility.py000066400000000000000000001601021412543434000214750ustar00rootroot00000000000000"""Compatibility interface between dense and sparse polys. """ from sympy.polys.densearith import dup_add_term from sympy.polys.densearith import dmp_add_term from sympy.polys.densearith import dup_sub_term from sympy.polys.densearith import dmp_sub_term from sympy.polys.densearith import dup_mul_term from sympy.polys.densearith import dmp_mul_term from sympy.polys.densearith import dup_add_ground from sympy.polys.densearith import dmp_add_ground from sympy.polys.densearith import dup_sub_ground from sympy.polys.densearith import dmp_sub_ground from sympy.polys.densearith import dup_mul_ground from sympy.polys.densearith import dmp_mul_ground from sympy.polys.densearith import dup_quo_ground from sympy.polys.densearith import dmp_quo_ground from sympy.polys.densearith import dup_exquo_ground from sympy.polys.densearith import dmp_exquo_ground from sympy.polys.densearith import dup_lshift from sympy.polys.densearith import dup_rshift from sympy.polys.densearith import dup_abs from sympy.polys.densearith import dmp_abs from sympy.polys.densearith import dup_neg from sympy.polys.densearith import dmp_neg from sympy.polys.densearith import dup_add from sympy.polys.densearith import dmp_add from sympy.polys.densearith import dup_sub from sympy.polys.densearith import dmp_sub from sympy.polys.densearith import dup_add_mul from sympy.polys.densearith import dmp_add_mul from sympy.polys.densearith import dup_sub_mul from sympy.polys.densearith import dmp_sub_mul from sympy.polys.densearith import dup_mul from sympy.polys.densearith import dmp_mul from sympy.polys.densearith import dup_sqr from sympy.polys.densearith import dmp_sqr from sympy.polys.densearith import dup_pow from sympy.polys.densearith import dmp_pow from sympy.polys.densearith import dup_pdiv from sympy.polys.densearith import dup_prem from sympy.polys.densearith import dup_pquo from sympy.polys.densearith import dup_pexquo from sympy.polys.densearith import dmp_pdiv from sympy.polys.densearith import dmp_prem from sympy.polys.densearith import dmp_pquo from sympy.polys.densearith import dmp_pexquo from sympy.polys.densearith import dup_rr_div from sympy.polys.densearith import dmp_rr_div from sympy.polys.densearith import dup_ff_div from sympy.polys.densearith import dmp_ff_div from sympy.polys.densearith import dup_div from sympy.polys.densearith import dup_rem from sympy.polys.densearith import dup_quo from sympy.polys.densearith import dup_exquo from sympy.polys.densearith import dmp_div from sympy.polys.densearith import dmp_rem from sympy.polys.densearith import dmp_quo from sympy.polys.densearith import dmp_exquo from sympy.polys.densearith import dup_max_norm from sympy.polys.densearith import dmp_max_norm from sympy.polys.densearith import dup_l1_norm from sympy.polys.densearith import dmp_l1_norm from sympy.polys.densearith import dup_expand from sympy.polys.densearith import dmp_expand from sympy.polys.densebasic import dup_LC from sympy.polys.densebasic import dmp_LC from sympy.polys.densebasic import dup_TC from sympy.polys.densebasic import dmp_TC from sympy.polys.densebasic import dmp_ground_LC from sympy.polys.densebasic import dmp_ground_TC from sympy.polys.densebasic import dup_degree from sympy.polys.densebasic import dmp_degree from sympy.polys.densebasic import dmp_degree_in from sympy.polys.densebasic import dmp_to_dict from sympy.polys.densetools import dup_integrate from sympy.polys.densetools import dmp_integrate from sympy.polys.densetools import dmp_integrate_in from sympy.polys.densetools import dup_diff from sympy.polys.densetools import dmp_diff from sympy.polys.densetools import dmp_diff_in from sympy.polys.densetools import dup_eval from sympy.polys.densetools import dmp_eval from sympy.polys.densetools import dmp_eval_in from sympy.polys.densetools import dmp_eval_tail from sympy.polys.densetools import dmp_diff_eval_in from sympy.polys.densetools import dup_trunc from sympy.polys.densetools import dmp_trunc from sympy.polys.densetools import dmp_ground_trunc from sympy.polys.densetools import dup_monic from sympy.polys.densetools import dmp_ground_monic from sympy.polys.densetools import dup_content from sympy.polys.densetools import dmp_ground_content from sympy.polys.densetools import dup_primitive from sympy.polys.densetools import dmp_ground_primitive from sympy.polys.densetools import dup_extract from sympy.polys.densetools import dmp_ground_extract from sympy.polys.densetools import dup_real_imag from sympy.polys.densetools import dup_mirror from sympy.polys.densetools import dup_scale from sympy.polys.densetools import dup_shift from sympy.polys.densetools import dup_transform from sympy.polys.densetools import dup_compose from sympy.polys.densetools import dmp_compose from sympy.polys.densetools import dup_decompose from sympy.polys.densetools import dmp_lift from sympy.polys.densetools import dup_sign_variations from sympy.polys.densetools import dup_clear_denoms from sympy.polys.densetools import dmp_clear_denoms from sympy.polys.densetools import dup_revert from sympy.polys.euclidtools import dup_half_gcdex from sympy.polys.euclidtools import dmp_half_gcdex from sympy.polys.euclidtools import dup_gcdex from sympy.polys.euclidtools import dmp_gcdex from sympy.polys.euclidtools import dup_invert from sympy.polys.euclidtools import dmp_invert from sympy.polys.euclidtools import dup_euclidean_prs from sympy.polys.euclidtools import dmp_euclidean_prs from sympy.polys.euclidtools import dup_primitive_prs from sympy.polys.euclidtools import dmp_primitive_prs from sympy.polys.euclidtools import dup_inner_subresultants from sympy.polys.euclidtools import dup_subresultants from sympy.polys.euclidtools import dup_prs_resultant from sympy.polys.euclidtools import dup_resultant from sympy.polys.euclidtools import dmp_inner_subresultants from sympy.polys.euclidtools import dmp_subresultants from sympy.polys.euclidtools import dmp_prs_resultant from sympy.polys.euclidtools import dmp_zz_modular_resultant from sympy.polys.euclidtools import dmp_zz_collins_resultant from sympy.polys.euclidtools import dmp_qq_collins_resultant from sympy.polys.euclidtools import dmp_resultant from sympy.polys.euclidtools import dup_discriminant from sympy.polys.euclidtools import dmp_discriminant from sympy.polys.euclidtools import dup_rr_prs_gcd from sympy.polys.euclidtools import dup_ff_prs_gcd from sympy.polys.euclidtools import dmp_rr_prs_gcd from sympy.polys.euclidtools import dmp_ff_prs_gcd from sympy.polys.euclidtools import dup_zz_heu_gcd from sympy.polys.euclidtools import dmp_zz_heu_gcd from sympy.polys.euclidtools import dup_qq_heu_gcd from sympy.polys.euclidtools import dmp_qq_heu_gcd from sympy.polys.euclidtools import dup_inner_gcd from sympy.polys.euclidtools import dmp_inner_gcd from sympy.polys.euclidtools import dup_gcd from sympy.polys.euclidtools import dmp_gcd from sympy.polys.euclidtools import dup_rr_lcm from sympy.polys.euclidtools import dup_ff_lcm from sympy.polys.euclidtools import dup_lcm from sympy.polys.euclidtools import dmp_rr_lcm from sympy.polys.euclidtools import dmp_ff_lcm from sympy.polys.euclidtools import dmp_lcm from sympy.polys.euclidtools import dmp_content from sympy.polys.euclidtools import dmp_primitive from sympy.polys.euclidtools import dup_cancel from sympy.polys.euclidtools import dmp_cancel from sympy.polys.factortools import dup_trial_division from sympy.polys.factortools import dmp_trial_division from sympy.polys.factortools import dup_zz_mignotte_bound from sympy.polys.factortools import dmp_zz_mignotte_bound from sympy.polys.factortools import dup_zz_hensel_step from sympy.polys.factortools import dup_zz_hensel_lift from sympy.polys.factortools import dup_zz_zassenhaus from sympy.polys.factortools import dup_zz_irreducible_p from sympy.polys.factortools import dup_cyclotomic_p from sympy.polys.factortools import dup_zz_cyclotomic_poly from sympy.polys.factortools import dup_zz_cyclotomic_factor from sympy.polys.factortools import dup_zz_factor_sqf from sympy.polys.factortools import dup_zz_factor from sympy.polys.factortools import dmp_zz_wang_non_divisors from sympy.polys.factortools import dmp_zz_wang_lead_coeffs from sympy.polys.factortools import dup_zz_diophantine from sympy.polys.factortools import dmp_zz_diophantine from sympy.polys.factortools import dmp_zz_wang_hensel_lifting from sympy.polys.factortools import dmp_zz_wang from sympy.polys.factortools import dmp_zz_factor from sympy.polys.factortools import dup_qq_i_factor from sympy.polys.factortools import dup_zz_i_factor from sympy.polys.factortools import dmp_qq_i_factor from sympy.polys.factortools import dmp_zz_i_factor from sympy.polys.factortools import dup_ext_factor from sympy.polys.factortools import dmp_ext_factor from sympy.polys.factortools import dup_gf_factor from sympy.polys.factortools import dmp_gf_factor from sympy.polys.factortools import dup_factor_list from sympy.polys.factortools import dup_factor_list_include from sympy.polys.factortools import dmp_factor_list from sympy.polys.factortools import dmp_factor_list_include from sympy.polys.factortools import dup_irreducible_p from sympy.polys.factortools import dmp_irreducible_p from sympy.polys.rootisolation import dup_sturm from sympy.polys.rootisolation import dup_root_upper_bound from sympy.polys.rootisolation import dup_root_lower_bound from sympy.polys.rootisolation import dup_step_refine_real_root from sympy.polys.rootisolation import dup_inner_refine_real_root from sympy.polys.rootisolation import dup_outer_refine_real_root from sympy.polys.rootisolation import dup_refine_real_root from sympy.polys.rootisolation import dup_inner_isolate_real_roots from sympy.polys.rootisolation import dup_inner_isolate_positive_roots from sympy.polys.rootisolation import dup_inner_isolate_negative_roots from sympy.polys.rootisolation import dup_isolate_real_roots_sqf from sympy.polys.rootisolation import dup_isolate_real_roots from sympy.polys.rootisolation import dup_isolate_real_roots_list from sympy.polys.rootisolation import dup_count_real_roots from sympy.polys.rootisolation import dup_count_complex_roots from sympy.polys.rootisolation import dup_isolate_complex_roots_sqf from sympy.polys.rootisolation import dup_isolate_all_roots_sqf from sympy.polys.rootisolation import dup_isolate_all_roots from sympy.polys.sqfreetools import ( dup_sqf_p, dmp_sqf_p, dup_sqf_norm, dmp_sqf_norm, dup_gf_sqf_part, dmp_gf_sqf_part, dup_sqf_part, dmp_sqf_part, dup_gf_sqf_list, dmp_gf_sqf_list, dup_sqf_list, dup_sqf_list_include, dmp_sqf_list, dmp_sqf_list_include, dup_gff_list, dmp_gff_list) from sympy.polys.galoistools import ( gf_degree, gf_LC, gf_TC, gf_strip, gf_from_dict, gf_to_dict, gf_from_int_poly, gf_to_int_poly, gf_neg, gf_add_ground, gf_sub_ground, gf_mul_ground, gf_quo_ground, gf_add, gf_sub, gf_mul, gf_sqr, gf_add_mul, gf_sub_mul, gf_expand, gf_div, gf_rem, gf_quo, gf_exquo, gf_lshift, gf_rshift, gf_pow, gf_pow_mod, gf_gcd, gf_lcm, gf_cofactors, gf_gcdex, gf_monic, gf_diff, gf_eval, gf_multi_eval, gf_compose, gf_compose_mod, gf_trace_map, gf_random, gf_irreducible, gf_irred_p_ben_or, gf_irred_p_rabin, gf_irreducible_p, gf_sqf_p, gf_sqf_part, gf_Qmatrix, gf_berlekamp, gf_ddf_zassenhaus, gf_edf_zassenhaus, gf_ddf_shoup, gf_edf_shoup, gf_zassenhaus, gf_shoup, gf_factor_sqf, gf_factor) from sympy.utilities import public @public class IPolys: symbols = None ngens = None domain = None order = None gens = None def drop(self, gen): pass def clone(self, symbols=None, domain=None, order=None): pass def to_ground(self): pass def ground_new(self, element): pass def domain_new(self, element): pass def from_dict(self, d): pass def wrap(self, element): from sympy.polys.rings import PolyElement if isinstance(element, PolyElement): if element.ring == self: return element else: raise NotImplementedError("domain conversions") else: return self.ground_new(element) def to_dense(self, element): return self.wrap(element).to_dense() def from_dense(self, element): return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain)) def dup_add_term(self, f, c, i): return self.from_dense(dup_add_term(self.to_dense(f), c, i, self.domain)) def dmp_add_term(self, f, c, i): return self.from_dense(dmp_add_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) def dup_sub_term(self, f, c, i): return self.from_dense(dup_sub_term(self.to_dense(f), c, i, self.domain)) def dmp_sub_term(self, f, c, i): return self.from_dense(dmp_sub_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) def dup_mul_term(self, f, c, i): return self.from_dense(dup_mul_term(self.to_dense(f), c, i, self.domain)) def dmp_mul_term(self, f, c, i): return self.from_dense(dmp_mul_term(self.to_dense(f), self.wrap(c).drop(0).to_dense(), i, self.ngens-1, self.domain)) def dup_add_ground(self, f, c): return self.from_dense(dup_add_ground(self.to_dense(f), c, self.domain)) def dmp_add_ground(self, f, c): return self.from_dense(dmp_add_ground(self.to_dense(f), c, self.ngens-1, self.domain)) def dup_sub_ground(self, f, c): return self.from_dense(dup_sub_ground(self.to_dense(f), c, self.domain)) def dmp_sub_ground(self, f, c): return self.from_dense(dmp_sub_ground(self.to_dense(f), c, self.ngens-1, self.domain)) def dup_mul_ground(self, f, c): return self.from_dense(dup_mul_ground(self.to_dense(f), c, self.domain)) def dmp_mul_ground(self, f, c): return self.from_dense(dmp_mul_ground(self.to_dense(f), c, self.ngens-1, self.domain)) def dup_quo_ground(self, f, c): return self.from_dense(dup_quo_ground(self.to_dense(f), c, self.domain)) def dmp_quo_ground(self, f, c): return self.from_dense(dmp_quo_ground(self.to_dense(f), c, self.ngens-1, self.domain)) def dup_exquo_ground(self, f, c): return self.from_dense(dup_exquo_ground(self.to_dense(f), c, self.domain)) def dmp_exquo_ground(self, f, c): return self.from_dense(dmp_exquo_ground(self.to_dense(f), c, self.ngens-1, self.domain)) def dup_lshift(self, f, n): return self.from_dense(dup_lshift(self.to_dense(f), n, self.domain)) def dup_rshift(self, f, n): return self.from_dense(dup_rshift(self.to_dense(f), n, self.domain)) def dup_abs(self, f): return self.from_dense(dup_abs(self.to_dense(f), self.domain)) def dmp_abs(self, f): return self.from_dense(dmp_abs(self.to_dense(f), self.ngens-1, self.domain)) def dup_neg(self, f): return self.from_dense(dup_neg(self.to_dense(f), self.domain)) def dmp_neg(self, f): return self.from_dense(dmp_neg(self.to_dense(f), self.ngens-1, self.domain)) def dup_add(self, f, g): return self.from_dense(dup_add(self.to_dense(f), self.to_dense(g), self.domain)) def dmp_add(self, f, g): return self.from_dense(dmp_add(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dup_sub(self, f, g): return self.from_dense(dup_sub(self.to_dense(f), self.to_dense(g), self.domain)) def dmp_sub(self, f, g): return self.from_dense(dmp_sub(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dup_add_mul(self, f, g, h): return self.from_dense(dup_add_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.domain)) def dmp_add_mul(self, f, g, h): return self.from_dense(dmp_add_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.ngens-1, self.domain)) def dup_sub_mul(self, f, g, h): return self.from_dense(dup_sub_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.domain)) def dmp_sub_mul(self, f, g, h): return self.from_dense(dmp_sub_mul(self.to_dense(f), self.to_dense(g), self.to_dense(h), self.ngens-1, self.domain)) def dup_mul(self, f, g): return self.from_dense(dup_mul(self.to_dense(f), self.to_dense(g), self.domain)) def dmp_mul(self, f, g): return self.from_dense(dmp_mul(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dup_sqr(self, f): return self.from_dense(dup_sqr(self.to_dense(f), self.domain)) def dmp_sqr(self, f): return self.from_dense(dmp_sqr(self.to_dense(f), self.ngens-1, self.domain)) def dup_pow(self, f, n): return self.from_dense(dup_pow(self.to_dense(f), n, self.domain)) def dmp_pow(self, f, n): return self.from_dense(dmp_pow(self.to_dense(f), n, self.ngens-1, self.domain)) def dup_pdiv(self, f, g): q, r = dup_pdiv(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(q), self.from_dense(r)) def dup_prem(self, f, g): return self.from_dense(dup_prem(self.to_dense(f), self.to_dense(g), self.domain)) def dup_pquo(self, f, g): return self.from_dense(dup_pquo(self.to_dense(f), self.to_dense(g), self.domain)) def dup_pexquo(self, f, g): return self.from_dense(dup_pexquo(self.to_dense(f), self.to_dense(g), self.domain)) def dmp_pdiv(self, f, g): q, r = dmp_pdiv(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(q), self.from_dense(r)) def dmp_prem(self, f, g): return self.from_dense(dmp_prem(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dmp_pquo(self, f, g): return self.from_dense(dmp_pquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dmp_pexquo(self, f, g): return self.from_dense(dmp_pexquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dup_rr_div(self, f, g): q, r = dup_rr_div(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(q), self.from_dense(r)) def dmp_rr_div(self, f, g): q, r = dmp_rr_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(q), self.from_dense(r)) def dup_ff_div(self, f, g): q, r = dup_ff_div(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(q), self.from_dense(r)) def dmp_ff_div(self, f, g): q, r = dmp_ff_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(q), self.from_dense(r)) def dup_div(self, f, g): q, r = dup_div(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(q), self.from_dense(r)) def dup_rem(self, f, g): return self.from_dense(dup_rem(self.to_dense(f), self.to_dense(g), self.domain)) def dup_quo(self, f, g): return self.from_dense(dup_quo(self.to_dense(f), self.to_dense(g), self.domain)) def dup_exquo(self, f, g): return self.from_dense(dup_exquo(self.to_dense(f), self.to_dense(g), self.domain)) def dmp_div(self, f, g): q, r = dmp_div(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(q), self.from_dense(r)) def dmp_rem(self, f, g): return self.from_dense(dmp_rem(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dmp_quo(self, f, g): return self.from_dense(dmp_quo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dmp_exquo(self, f, g): return self.from_dense(dmp_exquo(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dup_max_norm(self, f): return dup_max_norm(self.to_dense(f), self.domain) def dmp_max_norm(self, f): return dmp_max_norm(self.to_dense(f), self.ngens-1, self.domain) def dup_l1_norm(self, f): return dup_l1_norm(self.to_dense(f), self.domain) def dmp_l1_norm(self, f): return dmp_l1_norm(self.to_dense(f), self.ngens-1, self.domain) def dup_expand(self, polys): return self.from_dense(dup_expand(list(map(self.to_dense, polys)), self.domain)) def dmp_expand(self, polys): return self.from_dense(dmp_expand(list(map(self.to_dense, polys)), self.ngens-1, self.domain)) def dup_LC(self, f): return dup_LC(self.to_dense(f), self.domain) def dmp_LC(self, f): LC = dmp_LC(self.to_dense(f), self.domain) if isinstance(LC, list): return self[1:].from_dense(LC) else: return LC def dup_TC(self, f): return dup_TC(self.to_dense(f), self.domain) def dmp_TC(self, f): TC = dmp_TC(self.to_dense(f), self.domain) if isinstance(TC, list): return self[1:].from_dense(TC) else: return TC def dmp_ground_LC(self, f): return dmp_ground_LC(self.to_dense(f), self.ngens-1, self.domain) def dmp_ground_TC(self, f): return dmp_ground_TC(self.to_dense(f), self.ngens-1, self.domain) def dup_degree(self, f): return dup_degree(self.to_dense(f)) def dmp_degree(self, f): return dmp_degree(self.to_dense(f), self.ngens-1) def dmp_degree_in(self, f, j): return dmp_degree_in(self.to_dense(f), j, self.ngens-1) def dup_integrate(self, f, m): return self.from_dense(dup_integrate(self.to_dense(f), m, self.domain)) def dmp_integrate(self, f, m): return self.from_dense(dmp_integrate(self.to_dense(f), m, self.ngens-1, self.domain)) def dup_diff(self, f, m): return self.from_dense(dup_diff(self.to_dense(f), m, self.domain)) def dmp_diff(self, f, m): return self.from_dense(dmp_diff(self.to_dense(f), m, self.ngens-1, self.domain)) def dmp_diff_in(self, f, m, j): return self.from_dense(dmp_diff_in(self.to_dense(f), m, j, self.ngens-1, self.domain)) def dmp_integrate_in(self, f, m, j): return self.from_dense(dmp_integrate_in(self.to_dense(f), m, j, self.ngens-1, self.domain)) def dup_eval(self, f, a): return dup_eval(self.to_dense(f), a, self.domain) def dmp_eval(self, f, a): result = dmp_eval(self.to_dense(f), a, self.ngens-1, self.domain) return self[1:].from_dense(result) def dmp_eval_in(self, f, a, j): result = dmp_eval_in(self.to_dense(f), a, j, self.ngens-1, self.domain) return self.drop(j).from_dense(result) def dmp_diff_eval_in(self, f, m, a, j): result = dmp_diff_eval_in(self.to_dense(f), m, a, j, self.ngens-1, self.domain) return self.drop(j).from_dense(result) def dmp_eval_tail(self, f, A): result = dmp_eval_tail(self.to_dense(f), A, self.ngens-1, self.domain) if isinstance(result, list): return self[:-len(A)].from_dense(result) else: return result def dup_trunc(self, f, p): return self.from_dense(dup_trunc(self.to_dense(f), p, self.domain)) def dmp_trunc(self, f, g): return self.from_dense(dmp_trunc(self.to_dense(f), self[1:].to_dense(g), self.ngens-1, self.domain)) def dmp_ground_trunc(self, f, p): return self.from_dense(dmp_ground_trunc(self.to_dense(f), p, self.ngens-1, self.domain)) def dup_monic(self, f): return self.from_dense(dup_monic(self.to_dense(f), self.domain)) def dmp_ground_monic(self, f): return self.from_dense(dmp_ground_monic(self.to_dense(f), self.ngens-1, self.domain)) def dup_extract(self, f, g): c, F, G = dup_extract(self.to_dense(f), self.to_dense(g), self.domain) return (c, self.from_dense(F), self.from_dense(G)) def dmp_ground_extract(self, f, g): c, F, G = dmp_ground_extract(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (c, self.from_dense(F), self.from_dense(G)) def dup_real_imag(self, f): p, q = dup_real_imag(self.wrap(f).drop(1).to_dense(), self.domain) return (self.from_dense(p), self.from_dense(q)) def dup_mirror(self, f): return self.from_dense(dup_mirror(self.to_dense(f), self.domain)) def dup_scale(self, f, a): return self.from_dense(dup_scale(self.to_dense(f), a, self.domain)) def dup_shift(self, f, a): return self.from_dense(dup_shift(self.to_dense(f), a, self.domain)) def dup_transform(self, f, p, q): return self.from_dense(dup_transform(self.to_dense(f), self.to_dense(p), self.to_dense(q), self.domain)) def dup_compose(self, f, g): return self.from_dense(dup_compose(self.to_dense(f), self.to_dense(g), self.domain)) def dmp_compose(self, f, g): return self.from_dense(dmp_compose(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dup_decompose(self, f): components = dup_decompose(self.to_dense(f), self.domain) return list(map(self.from_dense, components)) def dmp_lift(self, f): result = dmp_lift(self.to_dense(f), self.ngens-1, self.domain) return self.to_ground().from_dense(result) def dup_sign_variations(self, f): return dup_sign_variations(self.to_dense(f), self.domain) def dup_clear_denoms(self, f, convert=False): c, F = dup_clear_denoms(self.to_dense(f), self.domain, convert=convert) if convert: ring = self.clone(domain=self.domain.get_ring()) else: ring = self return (c, ring.from_dense(F)) def dmp_clear_denoms(self, f, convert=False): c, F = dmp_clear_denoms(self.to_dense(f), self.ngens-1, self.domain, convert=convert) if convert: ring = self.clone(domain=self.domain.get_ring()) else: ring = self return (c, ring.from_dense(F)) def dup_revert(self, f, n): return self.from_dense(dup_revert(self.to_dense(f), n, self.domain)) def dup_half_gcdex(self, f, g): s, h = dup_half_gcdex(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(s), self.from_dense(h)) def dmp_half_gcdex(self, f, g): s, h = dmp_half_gcdex(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(s), self.from_dense(h)) def dup_gcdex(self, f, g): s, t, h = dup_gcdex(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(s), self.from_dense(t), self.from_dense(h)) def dmp_gcdex(self, f, g): s, t, h = dmp_gcdex(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(s), self.from_dense(t), self.from_dense(h)) def dup_invert(self, f, g): return self.from_dense(dup_invert(self.to_dense(f), self.to_dense(g), self.domain)) def dmp_invert(self, f, g): return self.from_dense(dmp_invert(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain)) def dup_euclidean_prs(self, f, g): prs = dup_euclidean_prs(self.to_dense(f), self.to_dense(g), self.domain) return list(map(self.from_dense, prs)) def dmp_euclidean_prs(self, f, g): prs = dmp_euclidean_prs(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return list(map(self.from_dense, prs)) def dup_primitive_prs(self, f, g): prs = dup_primitive_prs(self.to_dense(f), self.to_dense(g), self.domain) return list(map(self.from_dense, prs)) def dmp_primitive_prs(self, f, g): prs = dmp_primitive_prs(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return list(map(self.from_dense, prs)) def dup_inner_subresultants(self, f, g): prs, sres = dup_inner_subresultants(self.to_dense(f), self.to_dense(g), self.domain) return (list(map(self.from_dense, prs)), sres) def dmp_inner_subresultants(self, f, g): prs, sres = dmp_inner_subresultants(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (list(map(self.from_dense, prs)), sres) def dup_subresultants(self, f, g): prs = dup_subresultants(self.to_dense(f), self.to_dense(g), self.domain) return list(map(self.from_dense, prs)) def dmp_subresultants(self, f, g): prs = dmp_subresultants(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return list(map(self.from_dense, prs)) def dup_prs_resultant(self, f, g): res, prs = dup_prs_resultant(self.to_dense(f), self.to_dense(g), self.domain) return (res, list(map(self.from_dense, prs))) def dmp_prs_resultant(self, f, g): res, prs = dmp_prs_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self[1:].from_dense(res), list(map(self.from_dense, prs))) def dmp_zz_modular_resultant(self, f, g, p): res = dmp_zz_modular_resultant(self.to_dense(f), self.to_dense(g), self.domain_new(p), self.ngens-1, self.domain) return self[1:].from_dense(res) def dmp_zz_collins_resultant(self, f, g): res = dmp_zz_collins_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return self[1:].from_dense(res) def dmp_qq_collins_resultant(self, f, g): res = dmp_qq_collins_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return self[1:].from_dense(res) def dup_resultant(self, f, g): #, includePRS=False): return dup_resultant(self.to_dense(f), self.to_dense(g), self.domain) #, includePRS=includePRS) def dmp_resultant(self, f, g): #, includePRS=False): res = dmp_resultant(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) #, includePRS=includePRS) if isinstance(res, list): return self[1:].from_dense(res) else: return res def dup_discriminant(self, f): return dup_discriminant(self.to_dense(f), self.domain) def dmp_discriminant(self, f): disc = dmp_discriminant(self.to_dense(f), self.ngens-1, self.domain) if isinstance(disc, list): return self[1:].from_dense(disc) else: return disc def dup_rr_prs_gcd(self, f, g): H, F, G = dup_rr_prs_gcd(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dup_ff_prs_gcd(self, f, g): H, F, G = dup_ff_prs_gcd(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dmp_rr_prs_gcd(self, f, g): H, F, G = dmp_rr_prs_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dmp_ff_prs_gcd(self, f, g): H, F, G = dmp_ff_prs_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dup_zz_heu_gcd(self, f, g): H, F, G = dup_zz_heu_gcd(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dmp_zz_heu_gcd(self, f, g): H, F, G = dmp_zz_heu_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dup_qq_heu_gcd(self, f, g): H, F, G = dup_qq_heu_gcd(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dmp_qq_heu_gcd(self, f, g): H, F, G = dmp_qq_heu_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dup_inner_gcd(self, f, g): H, F, G = dup_inner_gcd(self.to_dense(f), self.to_dense(g), self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dmp_inner_gcd(self, f, g): H, F, G = dmp_inner_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return (self.from_dense(H), self.from_dense(F), self.from_dense(G)) def dup_gcd(self, f, g): H = dup_gcd(self.to_dense(f), self.to_dense(g), self.domain) return self.from_dense(H) def dmp_gcd(self, f, g): H = dmp_gcd(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return self.from_dense(H) def dup_rr_lcm(self, f, g): H = dup_rr_lcm(self.to_dense(f), self.to_dense(g), self.domain) return self.from_dense(H) def dup_ff_lcm(self, f, g): H = dup_ff_lcm(self.to_dense(f), self.to_dense(g), self.domain) return self.from_dense(H) def dup_lcm(self, f, g): H = dup_lcm(self.to_dense(f), self.to_dense(g), self.domain) return self.from_dense(H) def dmp_rr_lcm(self, f, g): H = dmp_rr_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return self.from_dense(H) def dmp_ff_lcm(self, f, g): H = dmp_ff_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return self.from_dense(H) def dmp_lcm(self, f, g): H = dmp_lcm(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain) return self.from_dense(H) def dup_content(self, f): cont = dup_content(self.to_dense(f), self.domain) return cont def dup_primitive(self, f): cont, prim = dup_primitive(self.to_dense(f), self.domain) return cont, self.from_dense(prim) def dmp_content(self, f): cont = dmp_content(self.to_dense(f), self.ngens-1, self.domain) if isinstance(cont, list): return self[1:].from_dense(cont) else: return cont def dmp_primitive(self, f): cont, prim = dmp_primitive(self.to_dense(f), self.ngens-1, self.domain) if isinstance(cont, list): return (self[1:].from_dense(cont), self.from_dense(prim)) else: return (cont, self.from_dense(prim)) def dmp_ground_content(self, f): cont = dmp_ground_content(self.to_dense(f), self.ngens-1, self.domain) return cont def dmp_ground_primitive(self, f): cont, prim = dmp_ground_primitive(self.to_dense(f), self.ngens-1, self.domain) return (cont, self.from_dense(prim)) def dup_cancel(self, f, g, include=True): result = dup_cancel(self.to_dense(f), self.to_dense(g), self.domain, include=include) if not include: cf, cg, F, G = result return (cf, cg, self.from_dense(F), self.from_dense(G)) else: F, G = result return (self.from_dense(F), self.from_dense(G)) def dmp_cancel(self, f, g, include=True): result = dmp_cancel(self.to_dense(f), self.to_dense(g), self.ngens-1, self.domain, include=include) if not include: cf, cg, F, G = result return (cf, cg, self.from_dense(F), self.from_dense(G)) else: F, G = result return (self.from_dense(F), self.from_dense(G)) def dup_trial_division(self, f, factors): factors = dup_trial_division(self.to_dense(f), list(map(self.to_dense, factors)), self.domain) return [ (self.from_dense(g), k) for g, k in factors ] def dmp_trial_division(self, f, factors): factors = dmp_trial_division(self.to_dense(f), list(map(self.to_dense, factors)), self.ngens-1, self.domain) return [ (self.from_dense(g), k) for g, k in factors ] def dup_zz_mignotte_bound(self, f): return dup_zz_mignotte_bound(self.to_dense(f), self.domain) def dmp_zz_mignotte_bound(self, f): return dmp_zz_mignotte_bound(self.to_dense(f), self.ngens-1, self.domain) def dup_zz_hensel_step(self, m, f, g, h, s, t): D = self.to_dense G, H, S, T = dup_zz_hensel_step(m, D(f), D(g), D(h), D(s), D(t), self.domain) return (self.from_dense(G), self.from_dense(H), self.from_dense(S), self.from_dense(T)) def dup_zz_hensel_lift(self, p, f, f_list, l): D = self.to_dense polys = dup_zz_hensel_lift(p, D(f), list(map(D, f_list)), l, self.domain) return list(map(self.from_dense, polys)) def dup_zz_zassenhaus(self, f): factors = dup_zz_zassenhaus(self.to_dense(f), self.domain) return [ (self.from_dense(g), k) for g, k in factors ] def dup_zz_irreducible_p(self, f): return dup_zz_irreducible_p(self.to_dense(f), self.domain) def dup_cyclotomic_p(self, f, irreducible=False): return dup_cyclotomic_p(self.to_dense(f), self.domain, irreducible=irreducible) def dup_zz_cyclotomic_poly(self, n): F = dup_zz_cyclotomic_poly(n, self.domain) return self.from_dense(F) def dup_zz_cyclotomic_factor(self, f): result = dup_zz_cyclotomic_factor(self.to_dense(f), self.domain) if result is None: return result else: return list(map(self.from_dense, result)) # E: List[ZZ], cs: ZZ, ct: ZZ def dmp_zz_wang_non_divisors(self, E, cs, ct): return dmp_zz_wang_non_divisors(E, cs, ct, self.domain) # f: Poly, T: List[(Poly, int)], ct: ZZ, A: List[ZZ] #def dmp_zz_wang_test_points(f, T, ct, A): # dmp_zz_wang_test_points(self.to_dense(f), T, ct, A, self.ngens-1, self.domain) # f: Poly, T: List[(Poly, int)], cs: ZZ, E: List[ZZ], H: List[Poly], A: List[ZZ] def dmp_zz_wang_lead_coeffs(self, f, T, cs, E, H, A): mv = self[1:] T = [ (mv.to_dense(t), k) for t, k in T ] uv = self[:1] H = list(map(uv.to_dense, H)) f, HH, CC = dmp_zz_wang_lead_coeffs(self.to_dense(f), T, cs, E, H, A, self.ngens-1, self.domain) return self.from_dense(f), list(map(uv.from_dense, HH)), list(map(mv.from_dense, CC)) # f: List[Poly], m: int, p: ZZ def dup_zz_diophantine(self, F, m, p): result = dup_zz_diophantine(list(map(self.to_dense, F)), m, p, self.domain) return list(map(self.from_dense, result)) # f: List[Poly], c: List[Poly], A: List[ZZ], d: int, p: ZZ def dmp_zz_diophantine(self, F, c, A, d, p): result = dmp_zz_diophantine(list(map(self.to_dense, F)), self.to_dense(c), A, d, p, self.ngens-1, self.domain) return list(map(self.from_dense, result)) # f: Poly, H: List[Poly], LC: List[Poly], A: List[ZZ], p: ZZ def dmp_zz_wang_hensel_lifting(self, f, H, LC, A, p): uv = self[:1] mv = self[1:] H = list(map(uv.to_dense, H)) LC = list(map(mv.to_dense, LC)) result = dmp_zz_wang_hensel_lifting(self.to_dense(f), H, LC, A, p, self.ngens-1, self.domain) return list(map(self.from_dense, result)) def dmp_zz_wang(self, f, mod=None, seed=None): factors = dmp_zz_wang(self.to_dense(f), self.ngens-1, self.domain, mod=mod, seed=seed) return [ self.from_dense(g) for g in factors ] def dup_zz_factor_sqf(self, f): coeff, factors = dup_zz_factor_sqf(self.to_dense(f), self.domain) return (coeff, [ self.from_dense(g) for g in factors ]) def dup_zz_factor(self, f): coeff, factors = dup_zz_factor(self.to_dense(f), self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_zz_factor(self, f): coeff, factors = dmp_zz_factor(self.to_dense(f), self.ngens-1, self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_qq_i_factor(self, f): coeff, factors = dup_qq_i_factor(self.to_dense(f), self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_qq_i_factor(self, f): coeff, factors = dmp_qq_i_factor(self.to_dense(f), self.ngens-1, self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_zz_i_factor(self, f): coeff, factors = dup_zz_i_factor(self.to_dense(f), self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_zz_i_factor(self, f): coeff, factors = dmp_zz_i_factor(self.to_dense(f), self.ngens-1, self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_ext_factor(self, f): coeff, factors = dup_ext_factor(self.to_dense(f), self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_ext_factor(self, f): coeff, factors = dmp_ext_factor(self.to_dense(f), self.ngens-1, self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_gf_factor(self, f): coeff, factors = dup_gf_factor(self.to_dense(f), self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_gf_factor(self, f): coeff, factors = dmp_gf_factor(self.to_dense(f), self.ngens-1, self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_factor_list(self, f): coeff, factors = dup_factor_list(self.to_dense(f), self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_factor_list_include(self, f): factors = dup_factor_list_include(self.to_dense(f), self.domain) return [ (self.from_dense(g), k) for g, k in factors ] def dmp_factor_list(self, f): coeff, factors = dmp_factor_list(self.to_dense(f), self.ngens-1, self.domain) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_factor_list_include(self, f): factors = dmp_factor_list_include(self.to_dense(f), self.ngens-1, self.domain) return [ (self.from_dense(g), k) for g, k in factors ] def dup_irreducible_p(self, f): return dup_irreducible_p(self.to_dense(f), self.domain) def dmp_irreducible_p(self, f): return dmp_irreducible_p(self.to_dense(f), self.ngens-1, self.domain) def dup_sturm(self, f): seq = dup_sturm(self.to_dense(f), self.domain) return list(map(self.from_dense, seq)) def dup_sqf_p(self, f): return dup_sqf_p(self.to_dense(f), self.domain) def dmp_sqf_p(self, f): return dmp_sqf_p(self.to_dense(f), self.ngens-1, self.domain) def dup_sqf_norm(self, f): s, F, R = dup_sqf_norm(self.to_dense(f), self.domain) return (s, self.from_dense(F), self.to_ground().from_dense(R)) def dmp_sqf_norm(self, f): s, F, R = dmp_sqf_norm(self.to_dense(f), self.ngens-1, self.domain) return (s, self.from_dense(F), self.to_ground().from_dense(R)) def dup_gf_sqf_part(self, f): return self.from_dense(dup_gf_sqf_part(self.to_dense(f), self.domain)) def dmp_gf_sqf_part(self, f): return self.from_dense(dmp_gf_sqf_part(self.to_dense(f), self.domain)) def dup_sqf_part(self, f): return self.from_dense(dup_sqf_part(self.to_dense(f), self.domain)) def dmp_sqf_part(self, f): return self.from_dense(dmp_sqf_part(self.to_dense(f), self.ngens-1, self.domain)) def dup_gf_sqf_list(self, f, all=False): coeff, factors = dup_gf_sqf_list(self.to_dense(f), self.domain, all=all) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_gf_sqf_list(self, f, all=False): coeff, factors = dmp_gf_sqf_list(self.to_dense(f), self.ngens-1, self.domain, all=all) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_sqf_list(self, f, all=False): coeff, factors = dup_sqf_list(self.to_dense(f), self.domain, all=all) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dup_sqf_list_include(self, f, all=False): factors = dup_sqf_list_include(self.to_dense(f), self.domain, all=all) return [ (self.from_dense(g), k) for g, k in factors ] def dmp_sqf_list(self, f, all=False): coeff, factors = dmp_sqf_list(self.to_dense(f), self.ngens-1, self.domain, all=all) return (coeff, [ (self.from_dense(g), k) for g, k in factors ]) def dmp_sqf_list_include(self, f, all=False): factors = dmp_sqf_list_include(self.to_dense(f), self.ngens-1, self.domain, all=all) return [ (self.from_dense(g), k) for g, k in factors ] def dup_gff_list(self, f): factors = dup_gff_list(self.to_dense(f), self.domain) return [ (self.from_dense(g), k) for g, k in factors ] def dmp_gff_list(self, f): factors = dmp_gff_list(self.to_dense(f), self.ngens-1, self.domain) return [ (self.from_dense(g), k) for g, k in factors ] def dup_root_upper_bound(self, f): return dup_root_upper_bound(self.to_dense(f), self.domain) def dup_root_lower_bound(self, f): return dup_root_lower_bound(self.to_dense(f), self.domain) def dup_step_refine_real_root(self, f, M, fast=False): return dup_step_refine_real_root(self.to_dense(f), M, self.domain, fast=fast) def dup_inner_refine_real_root(self, f, M, eps=None, steps=None, disjoint=None, fast=False, mobius=False): return dup_inner_refine_real_root(self.to_dense(f), M, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast, mobius=mobius) def dup_outer_refine_real_root(self, f, s, t, eps=None, steps=None, disjoint=None, fast=False): return dup_outer_refine_real_root(self.to_dense(f), s, t, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast) def dup_refine_real_root(self, f, s, t, eps=None, steps=None, disjoint=None, fast=False): return dup_refine_real_root(self.to_dense(f), s, t, self.domain, eps=eps, steps=steps, disjoint=disjoint, fast=fast) def dup_inner_isolate_real_roots(self, f, eps=None, fast=False): return dup_inner_isolate_real_roots(self.to_dense(f), self.domain, eps=eps, fast=fast) def dup_inner_isolate_positive_roots(self, f, eps=None, inf=None, sup=None, fast=False, mobius=False): return dup_inner_isolate_positive_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, mobius=mobius) def dup_inner_isolate_negative_roots(self, f, inf=None, sup=None, eps=None, fast=False, mobius=False): return dup_inner_isolate_negative_roots(self.to_dense(f), self.domain, inf=inf, sup=sup, eps=eps, fast=fast, mobius=mobius) def dup_isolate_real_roots_sqf(self, f, eps=None, inf=None, sup=None, fast=False, blackbox=False): return dup_isolate_real_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox) def dup_isolate_real_roots(self, f, eps=None, inf=None, sup=None, basis=False, fast=False): return dup_isolate_real_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, basis=basis, fast=fast) def dup_isolate_real_roots_list(self, polys, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): return dup_isolate_real_roots_list(list(map(self.to_dense, polys)), self.domain, eps=eps, inf=inf, sup=sup, strict=strict, basis=basis, fast=fast) def dup_count_real_roots(self, f, inf=None, sup=None): return dup_count_real_roots(self.to_dense(f), self.domain, inf=inf, sup=sup) def dup_count_complex_roots(self, f, inf=None, sup=None, exclude=None): return dup_count_complex_roots(self.to_dense(f), self.domain, inf=inf, sup=sup, exclude=exclude) def dup_isolate_complex_roots_sqf(self, f, eps=None, inf=None, sup=None, blackbox=False): return dup_isolate_complex_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, blackbox=blackbox) def dup_isolate_all_roots_sqf(self, f, eps=None, inf=None, sup=None, fast=False, blackbox=False): return dup_isolate_all_roots_sqf(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox) def dup_isolate_all_roots(self, f, eps=None, inf=None, sup=None, fast=False): return dup_isolate_all_roots(self.to_dense(f), self.domain, eps=eps, inf=inf, sup=sup, fast=fast) def fateman_poly_F_1(self): from sympy.polys.specialpolys import dmp_fateman_poly_F_1 return tuple(map(self.from_dense, dmp_fateman_poly_F_1(self.ngens-1, self.domain))) def fateman_poly_F_2(self): from sympy.polys.specialpolys import dmp_fateman_poly_F_2 return tuple(map(self.from_dense, dmp_fateman_poly_F_2(self.ngens-1, self.domain))) def fateman_poly_F_3(self): from sympy.polys.specialpolys import dmp_fateman_poly_F_3 return tuple(map(self.from_dense, dmp_fateman_poly_F_3(self.ngens-1, self.domain))) def to_gf_dense(self, element): return gf_strip([ self.domain.dom.convert(c, self.domain) for c in self.wrap(element).to_dense() ]) def from_gf_dense(self, element): return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain.dom)) def gf_degree(self, f): return gf_degree(self.to_gf_dense(f)) def gf_LC(self, f): return gf_LC(self.to_gf_dense(f), self.domain.dom) def gf_TC(self, f): return gf_TC(self.to_gf_dense(f), self.domain.dom) def gf_strip(self, f): return self.from_gf_dense(gf_strip(self.to_gf_dense(f))) def gf_trunc(self, f): return self.from_gf_dense(gf_strip(self.to_gf_dense(f), self.domain.mod)) def gf_normal(self, f): return self.from_gf_dense(gf_strip(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) def gf_from_dict(self, f): return self.from_gf_dense(gf_from_dict(f, self.domain.mod, self.domain.dom)) def gf_to_dict(self, f, symmetric=True): return gf_to_dict(self.to_gf_dense(f), self.domain.mod, symmetric=symmetric) def gf_from_int_poly(self, f): return self.from_gf_dense(gf_from_int_poly(f, self.domain.mod)) def gf_to_int_poly(self, f, symmetric=True): return gf_to_int_poly(self.to_gf_dense(f), self.domain.mod, symmetric=symmetric) def gf_neg(self, f): return self.from_gf_dense(gf_neg(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) def gf_add_ground(self, f, a): return self.from_gf_dense(gf_add_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) def gf_sub_ground(self, f, a): return self.from_gf_dense(gf_sub_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) def gf_mul_ground(self, f, a): return self.from_gf_dense(gf_mul_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) def gf_quo_ground(self, f, a): return self.from_gf_dense(gf_quo_ground(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom)) def gf_add(self, f, g): return self.from_gf_dense(gf_add(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_sub(self, f, g): return self.from_gf_dense(gf_sub(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_mul(self, f, g): return self.from_gf_dense(gf_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_sqr(self, f): return self.from_gf_dense(gf_sqr(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) def gf_add_mul(self, f, g, h): return self.from_gf_dense(gf_add_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.to_gf_dense(h), self.domain.mod, self.domain.dom)) def gf_sub_mul(self, f, g, h): return self.from_gf_dense(gf_sub_mul(self.to_gf_dense(f), self.to_gf_dense(g), self.to_gf_dense(h), self.domain.mod, self.domain.dom)) def gf_expand(self, F): return self.from_gf_dense(gf_expand(list(map(self.to_gf_dense, F)), self.domain.mod, self.domain.dom)) def gf_div(self, f, g): q, r = gf_div(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom) return self.from_gf_dense(q), self.from_gf_dense(r) def gf_rem(self, f, g): return self.from_gf_dense(gf_rem(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_quo(self, f, g): return self.from_gf_dense(gf_quo(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_exquo(self, f, g): return self.from_gf_dense(gf_exquo(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_lshift(self, f, n): return self.from_gf_dense(gf_lshift(self.to_gf_dense(f), n, self.domain.dom)) def gf_rshift(self, f, n): return self.from_gf_dense(gf_rshift(self.to_gf_dense(f), n, self.domain.dom)) def gf_pow(self, f, n): return self.from_gf_dense(gf_pow(self.to_gf_dense(f), n, self.domain.mod, self.domain.dom)) def gf_pow_mod(self, f, n, g): return self.from_gf_dense(gf_pow_mod(self.to_gf_dense(f), n, self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_cofactors(self, f, g): h, cff, cfg = gf_cofactors(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom) return self.from_gf_dense(h), self.from_gf_dense(cff), self.from_gf_dense(cfg) def gf_gcd(self, f, g): return self.from_gf_dense(gf_gcd(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_lcm(self, f, g): return self.from_gf_dense(gf_lcm(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_gcdex(self, f, g): return self.from_gf_dense(gf_gcdex(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_monic(self, f): return self.from_gf_dense(gf_monic(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) def gf_diff(self, f): return self.from_gf_dense(gf_diff(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) def gf_eval(self, f, a): return gf_eval(self.to_gf_dense(f), a, self.domain.mod, self.domain.dom) def gf_multi_eval(self, f, A): return gf_multi_eval(self.to_gf_dense(f), A, self.domain.mod, self.domain.dom) def gf_compose(self, f, g): return self.from_gf_dense(gf_compose(self.to_gf_dense(f), self.to_gf_dense(g), self.domain.mod, self.domain.dom)) def gf_compose_mod(self, g, h, f): return self.from_gf_dense(gf_compose_mod(self.to_gf_dense(g), self.to_gf_dense(h), self.to_gf_dense(f), self.domain.mod, self.domain.dom)) def gf_trace_map(self, a, b, c, n, f): a = self.to_gf_dense(a) b = self.to_gf_dense(b) c = self.to_gf_dense(c) f = self.to_gf_dense(f) U, V = gf_trace_map(a, b, c, n, f, self.domain.mod, self.domain.dom) return self.from_gf_dense(U), self.from_gf_dense(V) def gf_random(self, n): return self.from_gf_dense(gf_random(n, self.domain.mod, self.domain.dom)) def gf_irreducible(self, n): return self.from_gf_dense(gf_irreducible(n, self.domain.mod, self.domain.dom)) def gf_irred_p_ben_or(self, f): return gf_irred_p_ben_or(self.to_gf_dense(f), self.domain.mod, self.domain.dom) def gf_irred_p_rabin(self, f): return gf_irred_p_rabin(self.to_gf_dense(f), self.domain.mod, self.domain.dom) def gf_irreducible_p(self, f): return gf_irreducible_p(self.to_gf_dense(f), self.domain.mod, self.domain.dom) def gf_sqf_p(self, f): return gf_sqf_p(self.to_gf_dense(f), self.domain.mod, self.domain.dom) def gf_sqf_part(self, f): return self.from_gf_dense(gf_sqf_part(self.to_gf_dense(f), self.domain.mod, self.domain.dom)) def gf_sqf_list(self, f, all=False): coeff, factors = gf_sqf_part(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return coeff, [ (self.from_gf_dense(g), k) for g, k in factors ] def gf_Qmatrix(self, f): return gf_Qmatrix(self.to_gf_dense(f), self.domain.mod, self.domain.dom) def gf_berlekamp(self, f): factors = gf_berlekamp(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return [ self.from_gf_dense(g) for g in factors ] def gf_ddf_zassenhaus(self, f): factors = gf_ddf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return [ (self.from_gf_dense(g), k) for g, k in factors ] def gf_edf_zassenhaus(self, f, n): factors = gf_edf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return [ self.from_gf_dense(g) for g in factors ] def gf_ddf_shoup(self, f): factors = gf_ddf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return [ (self.from_gf_dense(g), k) for g, k in factors ] def gf_edf_shoup(self, f, n): factors = gf_edf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return [ self.from_gf_dense(g) for g in factors ] def gf_zassenhaus(self, f): factors = gf_zassenhaus(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return [ self.from_gf_dense(g) for g in factors ] def gf_shoup(self, f): factors = gf_shoup(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return [ self.from_gf_dense(g) for g in factors ] def gf_factor_sqf(self, f, method=None): coeff, factors = gf_factor_sqf(self.to_gf_dense(f), self.domain.mod, self.domain.dom, method=method) return coeff, [ self.from_gf_dense(g) for g in factors ] def gf_factor(self, f): coeff, factors = gf_factor(self.to_gf_dense(f), self.domain.mod, self.domain.dom) return coeff, [ (self.from_gf_dense(g), k) for g, k in factors ] sympy-sympy-1.9/sympy/polys/constructor.py000066400000000000000000000263301412543434000212150ustar00rootroot00000000000000"""Tools for constructing domains for expressions. """ from sympy.core import sympify from sympy.core.compatibility import ordered from sympy.core.evalf import pure_complex from sympy.polys.domains import ZZ, QQ, ZZ_I, QQ_I, EX from sympy.polys.domains.complexfield import ComplexField from sympy.polys.domains.realfield import RealField from sympy.polys.polyoptions import build_options from sympy.polys.polyutils import parallel_dict_from_basic from sympy.utilities import public def _construct_simple(coeffs, opt): """Handle simple domains, e.g.: ZZ, QQ, RR and algebraic domains. """ rationals = floats = complexes = algebraics = False float_numbers = [] if opt.extension is True: is_algebraic = lambda coeff: coeff.is_number and coeff.is_algebraic else: is_algebraic = lambda coeff: False for coeff in coeffs: if coeff.is_Rational: if not coeff.is_Integer: rationals = True elif coeff.is_Float: if algebraics: # there are both reals and algebraics -> EX return False else: floats = True float_numbers.append(coeff) else: is_complex = pure_complex(coeff) if is_complex: complexes = True x, y = is_complex if x.is_Rational and y.is_Rational: if not (x.is_Integer and y.is_Integer): rationals = True continue else: floats = True if x.is_Float: float_numbers.append(x) if y.is_Float: float_numbers.append(y) elif is_algebraic(coeff): if floats: # there are both algebraics and reals -> EX return False algebraics = True else: # this is a composite domain, e.g. ZZ[X], EX return None # Use the maximum precision of all coefficients for the RR or CC # precision max_prec = max(c._prec for c in float_numbers) if float_numbers else 53 if algebraics: domain, result = _construct_algebraic(coeffs, opt) else: if floats and complexes: domain = ComplexField(prec=max_prec) elif floats: domain = RealField(prec=max_prec) elif rationals or opt.field: domain = QQ_I if complexes else QQ else: domain = ZZ_I if complexes else ZZ result = [domain.from_sympy(coeff) for coeff in coeffs] return domain, result def _construct_algebraic(coeffs, opt): """We know that coefficients are algebraic so construct the extension. """ from sympy.polys.numberfields import primitive_element exts = set() def build_trees(args): trees = [] for a in args: if a.is_Rational: tree = ('Q', QQ.from_sympy(a)) elif a.is_Add: tree = ('+', build_trees(a.args)) elif a.is_Mul: tree = ('*', build_trees(a.args)) else: tree = ('e', a) exts.add(a) trees.append(tree) return trees trees = build_trees(coeffs) exts = list(ordered(exts)) g, span, H = primitive_element(exts, ex=True, polys=True) root = sum([ s*ext for s, ext in zip(span, exts) ]) domain, g = QQ.algebraic_field((g, root)), g.rep.rep exts_dom = [domain.dtype.from_list(h, g, QQ) for h in H] exts_map = dict(zip(exts, exts_dom)) def convert_tree(tree): op, args = tree if op == 'Q': return domain.dtype.from_list([args], g, QQ) elif op == '+': return sum((convert_tree(a) for a in args), domain.zero) elif op == '*': # return prod(convert(a) for a in args) t = convert_tree(args[0]) for a in args[1:]: t *= convert_tree(a) return t elif op == 'e': return exts_map[args] else: raise RuntimeError result = [convert_tree(tree) for tree in trees] return domain, result def _construct_composite(coeffs, opt): """Handle composite domains, e.g.: ZZ[X], QQ[X], ZZ(X), QQ(X). """ numers, denoms = [], [] for coeff in coeffs: numer, denom = coeff.as_numer_denom() numers.append(numer) denoms.append(denom) polys, gens = parallel_dict_from_basic(numers + denoms) # XXX: sorting if not gens: return None if opt.composite is None: if any(gen.is_number and gen.is_algebraic for gen in gens): return None # generators are number-like so lets better use EX all_symbols = set() for gen in gens: symbols = gen.free_symbols if all_symbols & symbols: return None # there could be algebraic relations between generators else: all_symbols |= symbols n = len(gens) k = len(polys)//2 numers = polys[:k] denoms = polys[k:] if opt.field: fractions = True else: fractions, zeros = False, (0,)*n for denom in denoms: if len(denom) > 1 or zeros not in denom: fractions = True break coeffs = set() if not fractions: for numer, denom in zip(numers, denoms): denom = denom[zeros] for monom, coeff in numer.items(): coeff /= denom coeffs.add(coeff) numer[monom] = coeff else: for numer, denom in zip(numers, denoms): coeffs.update(list(numer.values())) coeffs.update(list(denom.values())) rationals = floats = complexes = False float_numbers = [] for coeff in coeffs: if coeff.is_Rational: if not coeff.is_Integer: rationals = True elif coeff.is_Float: floats = True float_numbers.append(coeff) else: is_complex = pure_complex(coeff) if is_complex is not None: complexes = True x, y = is_complex if x.is_Rational and y.is_Rational: if not (x.is_Integer and y.is_Integer): rationals = True else: floats = True if x.is_Float: float_numbers.append(x) if y.is_Float: float_numbers.append(y) max_prec = max(c._prec for c in float_numbers) if float_numbers else 53 if floats and complexes: ground = ComplexField(prec=max_prec) elif floats: ground = RealField(prec=max_prec) elif complexes: if rationals: ground = QQ_I else: ground = ZZ_I elif rationals: ground = QQ else: ground = ZZ result = [] if not fractions: domain = ground.poly_ring(*gens) for numer in numers: for monom, coeff in numer.items(): numer[monom] = ground.from_sympy(coeff) result.append(domain(numer)) else: domain = ground.frac_field(*gens) for numer, denom in zip(numers, denoms): for monom, coeff in numer.items(): numer[monom] = ground.from_sympy(coeff) for monom, coeff in denom.items(): denom[monom] = ground.from_sympy(coeff) result.append(domain((numer, denom))) return domain, result def _construct_expression(coeffs, opt): """The last resort case, i.e. use the expression domain. """ domain, result = EX, [] for coeff in coeffs: result.append(domain.from_sympy(coeff)) return domain, result @public def construct_domain(obj, **args): """Construct a minimal domain for a list of expressions. Explanation =========== Given a list of normal SymPy expressions (of type :py:class:`~.Expr`) ``construct_domain`` will find a minimal :py:class:`~.Domain` that can represent those expressions. The expressions will be converted to elements of the domain and both the domain and the domain elements are returned. Parameters ========== obj: list or dict The expressions to build a domain for. **args: keyword arguments Options that affect the choice of domain. Returns ======= (K, elements): Domain and list of domain elements The domain K that can represent the expressions and the list or dict of domain elements representing the same expressions as elements of K. Examples ======== Given a list of :py:class:`~.Integer` ``construct_domain`` will return the domain :ref:`ZZ` and a list of integers as elements of :ref:`ZZ`. >>> from sympy import construct_domain, S >>> expressions = [S(2), S(3), S(4)] >>> K, elements = construct_domain(expressions) >>> K ZZ >>> elements [2, 3, 4] >>> type(elements[0]) # doctest: +SKIP >>> type(expressions[0]) If there are any :py:class:`~.Rational` then :ref:`QQ` is returned instead. >>> construct_domain([S(1)/2, S(3)/4]) (QQ, [1/2, 3/4]) If there are symbols then a polynomial ring :ref:`K[x]` is returned. >>> from sympy import symbols >>> x, y = symbols('x, y') >>> construct_domain([2*x + 1, S(3)/4]) (QQ[x], [2*x + 1, 3/4]) >>> construct_domain([2*x + 1, y]) (ZZ[x,y], [2*x + 1, y]) If any symbols appear with negative powers then a rational function field :ref:`K(x)` will be returned. >>> construct_domain([y/x, x/(1 - y)]) (ZZ(x,y), [y/x, -x/(y - 1)]) Irrational algebraic numbers will result in the :ref:`EX` domain by default. The keyword argument ``extension=True`` leads to the construction of an algebraic number field :ref:`QQ(a)`. >>> from sympy import sqrt >>> construct_domain([sqrt(2)]) (EX, [EX(sqrt(2))]) >>> construct_domain([sqrt(2)], extension=True) # doctest: +SKIP (QQ, [ANP([1, 0], [1, 0, -2], QQ)]) See also ======== Domain Expr """ opt = build_options(args) if hasattr(obj, '__iter__'): if isinstance(obj, dict): if not obj: monoms, coeffs = [], [] else: monoms, coeffs = list(zip(*list(obj.items()))) else: coeffs = obj else: coeffs = [obj] coeffs = list(map(sympify, coeffs)) result = _construct_simple(coeffs, opt) if result is not None: if result is not False: domain, coeffs = result else: domain, coeffs = _construct_expression(coeffs, opt) else: if opt.composite is False: result = None else: result = _construct_composite(coeffs, opt) if result is not None: domain, coeffs = result else: domain, coeffs = _construct_expression(coeffs, opt) if hasattr(obj, '__iter__'): if isinstance(obj, dict): return domain, dict(list(zip(monoms, coeffs))) else: return domain, coeffs else: return domain, coeffs[0] sympy-sympy-1.9/sympy/polys/densearith.py000066400000000000000000001011641412543434000207550ustar00rootroot00000000000000"""Arithmetics for dense recursive polynomials in ``K[x]`` or ``K[X]``. """ from sympy.polys.densebasic import ( dup_slice, dup_LC, dmp_LC, dup_degree, dmp_degree, dup_strip, dmp_strip, dmp_zero_p, dmp_zero, dmp_one_p, dmp_one, dmp_ground, dmp_zeros) from sympy.polys.polyerrors import (ExactQuotientFailed, PolynomialDivisionFailed) def dup_add_term(f, c, i, K): """ Add ``c*x**i`` to ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_add_term(x**2 - 1, ZZ(2), 4) 2*x**4 + x**2 - 1 """ if not c: return f n = len(f) m = n - i - 1 if i == n - 1: return dup_strip([f[0] + c] + f[1:]) else: if i >= n: return [c] + [K.zero]*(i - n) + f else: return f[:m] + [f[m] + c] + f[m + 1:] def dmp_add_term(f, c, i, u, K): """ Add ``c(x_2..x_u)*x_0**i`` to ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_add_term(x*y + 1, 2, 2) 2*x**2 + x*y + 1 """ if not u: return dup_add_term(f, c, i, K) v = u - 1 if dmp_zero_p(c, v): return f n = len(f) m = n - i - 1 if i == n - 1: return dmp_strip([dmp_add(f[0], c, v, K)] + f[1:], u) else: if i >= n: return [c] + dmp_zeros(i - n, v, K) + f else: return f[:m] + [dmp_add(f[m], c, v, K)] + f[m + 1:] def dup_sub_term(f, c, i, K): """ Subtract ``c*x**i`` from ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sub_term(2*x**4 + x**2 - 1, ZZ(2), 4) x**2 - 1 """ if not c: return f n = len(f) m = n - i - 1 if i == n - 1: return dup_strip([f[0] - c] + f[1:]) else: if i >= n: return [-c] + [K.zero]*(i - n) + f else: return f[:m] + [f[m] - c] + f[m + 1:] def dmp_sub_term(f, c, i, u, K): """ Subtract ``c(x_2..x_u)*x_0**i`` from ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_sub_term(2*x**2 + x*y + 1, 2, 2) x*y + 1 """ if not u: return dup_add_term(f, -c, i, K) v = u - 1 if dmp_zero_p(c, v): return f n = len(f) m = n - i - 1 if i == n - 1: return dmp_strip([dmp_sub(f[0], c, v, K)] + f[1:], u) else: if i >= n: return [dmp_neg(c, v, K)] + dmp_zeros(i - n, v, K) + f else: return f[:m] + [dmp_sub(f[m], c, v, K)] + f[m + 1:] def dup_mul_term(f, c, i, K): """ Multiply ``f`` by ``c*x**i`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_mul_term(x**2 - 1, ZZ(3), 2) 3*x**4 - 3*x**2 """ if not c or not f: return [] else: return [ cf * c for cf in f ] + [K.zero]*i def dmp_mul_term(f, c, i, u, K): """ Multiply ``f`` by ``c(x_2..x_u)*x_0**i`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_mul_term(x**2*y + x, 3*y, 2) 3*x**4*y**2 + 3*x**3*y """ if not u: return dup_mul_term(f, c, i, K) v = u - 1 if dmp_zero_p(f, u): return f if dmp_zero_p(c, v): return dmp_zero(u) else: return [ dmp_mul(cf, c, v, K) for cf in f ] + dmp_zeros(i, v, K) def dup_add_ground(f, c, K): """ Add an element of the ground domain to ``f``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_add_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) x**3 + 2*x**2 + 3*x + 8 """ return dup_add_term(f, c, 0, K) def dmp_add_ground(f, c, u, K): """ Add an element of the ground domain to ``f``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_add_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) x**3 + 2*x**2 + 3*x + 8 """ return dmp_add_term(f, dmp_ground(c, u - 1), 0, u, K) def dup_sub_ground(f, c, K): """ Subtract an element of the ground domain from ``f``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sub_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) x**3 + 2*x**2 + 3*x """ return dup_sub_term(f, c, 0, K) def dmp_sub_ground(f, c, u, K): """ Subtract an element of the ground domain from ``f``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_sub_ground(x**3 + 2*x**2 + 3*x + 4, ZZ(4)) x**3 + 2*x**2 + 3*x """ return dmp_sub_term(f, dmp_ground(c, u - 1), 0, u, K) def dup_mul_ground(f, c, K): """ Multiply ``f`` by a constant value in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_mul_ground(x**2 + 2*x - 1, ZZ(3)) 3*x**2 + 6*x - 3 """ if not c or not f: return [] else: return [ cf * c for cf in f ] def dmp_mul_ground(f, c, u, K): """ Multiply ``f`` by a constant value in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_mul_ground(2*x + 2*y, ZZ(3)) 6*x + 6*y """ if not u: return dup_mul_ground(f, c, K) v = u - 1 return [ dmp_mul_ground(cf, c, v, K) for cf in f ] def dup_quo_ground(f, c, K): """ Quotient by a constant in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x = ring("x", ZZ) >>> R.dup_quo_ground(3*x**2 + 2, ZZ(2)) x**2 + 1 >>> R, x = ring("x", QQ) >>> R.dup_quo_ground(3*x**2 + 2, QQ(2)) 3/2*x**2 + 1 """ if not c: raise ZeroDivisionError('polynomial division') if not f: return f if K.is_Field: return [ K.quo(cf, c) for cf in f ] else: return [ cf // c for cf in f ] def dmp_quo_ground(f, c, u, K): """ Quotient by a constant in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_quo_ground(2*x**2*y + 3*x, ZZ(2)) x**2*y + x >>> R, x,y = ring("x,y", QQ) >>> R.dmp_quo_ground(2*x**2*y + 3*x, QQ(2)) x**2*y + 3/2*x """ if not u: return dup_quo_ground(f, c, K) v = u - 1 return [ dmp_quo_ground(cf, c, v, K) for cf in f ] def dup_exquo_ground(f, c, K): """ Exact quotient by a constant in ``K[x]``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> R.dup_exquo_ground(x**2 + 2, QQ(2)) 1/2*x**2 + 1 """ if not c: raise ZeroDivisionError('polynomial division') if not f: return f return [ K.exquo(cf, c) for cf in f ] def dmp_exquo_ground(f, c, u, K): """ Exact quotient by a constant in ``K[X]``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y = ring("x,y", QQ) >>> R.dmp_exquo_ground(x**2*y + 2*x, QQ(2)) 1/2*x**2*y + x """ if not u: return dup_exquo_ground(f, c, K) v = u - 1 return [ dmp_exquo_ground(cf, c, v, K) for cf in f ] def dup_lshift(f, n, K): """ Efficiently multiply ``f`` by ``x**n`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_lshift(x**2 + 1, 2) x**4 + x**2 """ if not f: return f else: return f + [K.zero]*n def dup_rshift(f, n, K): """ Efficiently divide ``f`` by ``x**n`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_rshift(x**4 + x**2, 2) x**2 + 1 >>> R.dup_rshift(x**4 + x**2 + 2, 2) x**2 + 1 """ return f[:-n] def dup_abs(f, K): """ Make all coefficients positive in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_abs(x**2 - 1) x**2 + 1 """ return [ K.abs(coeff) for coeff in f ] def dmp_abs(f, u, K): """ Make all coefficients positive in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_abs(x**2*y - x) x**2*y + x """ if not u: return dup_abs(f, K) v = u - 1 return [ dmp_abs(cf, v, K) for cf in f ] def dup_neg(f, K): """ Negate a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_neg(x**2 - 1) -x**2 + 1 """ return [ -coeff for coeff in f ] def dmp_neg(f, u, K): """ Negate a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_neg(x**2*y - x) -x**2*y + x """ if not u: return dup_neg(f, K) v = u - 1 return [ dmp_neg(cf, v, K) for cf in f ] def dup_add(f, g, K): """ Add dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_add(x**2 - 1, x - 2) x**2 + x - 3 """ if not f: return g if not g: return f df = dup_degree(f) dg = dup_degree(g) if df == dg: return dup_strip([ a + b for a, b in zip(f, g) ]) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = g[:k], g[k:] return h + [ a + b for a, b in zip(f, g) ] def dmp_add(f, g, u, K): """ Add dense polynomials in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_add(x**2 + y, x**2*y + x) x**2*y + x**2 + x + y """ if not u: return dup_add(f, g, K) df = dmp_degree(f, u) if df < 0: return g dg = dmp_degree(g, u) if dg < 0: return f v = u - 1 if df == dg: return dmp_strip([ dmp_add(a, b, v, K) for a, b in zip(f, g) ], u) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = g[:k], g[k:] return h + [ dmp_add(a, b, v, K) for a, b in zip(f, g) ] def dup_sub(f, g, K): """ Subtract dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sub(x**2 - 1, x - 2) x**2 - x + 1 """ if not f: return dup_neg(g, K) if not g: return f df = dup_degree(f) dg = dup_degree(g) if df == dg: return dup_strip([ a - b for a, b in zip(f, g) ]) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = dup_neg(g[:k], K), g[k:] return h + [ a - b for a, b in zip(f, g) ] def dmp_sub(f, g, u, K): """ Subtract dense polynomials in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_sub(x**2 + y, x**2*y + x) -x**2*y + x**2 - x + y """ if not u: return dup_sub(f, g, K) df = dmp_degree(f, u) if df < 0: return dmp_neg(g, u, K) dg = dmp_degree(g, u) if dg < 0: return f v = u - 1 if df == dg: return dmp_strip([ dmp_sub(a, b, v, K) for a, b in zip(f, g) ], u) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = dmp_neg(g[:k], u, K), g[k:] return h + [ dmp_sub(a, b, v, K) for a, b in zip(f, g) ] def dup_add_mul(f, g, h, K): """ Returns ``f + g*h`` where ``f, g, h`` are in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_add_mul(x**2 - 1, x - 2, x + 2) 2*x**2 - 5 """ return dup_add(f, dup_mul(g, h, K), K) def dmp_add_mul(f, g, h, u, K): """ Returns ``f + g*h`` where ``f, g, h`` are in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_add_mul(x**2 + y, x, x + 2) 2*x**2 + 2*x + y """ return dmp_add(f, dmp_mul(g, h, u, K), u, K) def dup_sub_mul(f, g, h, K): """ Returns ``f - g*h`` where ``f, g, h`` are in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sub_mul(x**2 - 1, x - 2, x + 2) 3 """ return dup_sub(f, dup_mul(g, h, K), K) def dmp_sub_mul(f, g, h, u, K): """ Returns ``f - g*h`` where ``f, g, h`` are in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_sub_mul(x**2 + y, x, x + 2) -2*x + y """ return dmp_sub(f, dmp_mul(g, h, u, K), u, K) def dup_mul(f, g, K): """ Multiply dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_mul(x - 2, x + 2) x**2 - 4 """ if f == g: return dup_sqr(f, K) if not (f and g): return [] df = dup_degree(f) dg = dup_degree(g) n = max(df, dg) + 1 if n < 100: h = [] for i in range(0, df + dg + 1): coeff = K.zero for j in range(max(0, i - dg), min(df, i) + 1): coeff += f[j]*g[i - j] h.append(coeff) return dup_strip(h) else: # Use Karatsuba's algorithm (divide and conquer), see e.g.: # Joris van der Hoeven, Relax But Don't Be Too Lazy, # J. Symbolic Computation, 11 (2002), section 3.1.1. n2 = n//2 fl, gl = dup_slice(f, 0, n2, K), dup_slice(g, 0, n2, K) fh = dup_rshift(dup_slice(f, n2, n, K), n2, K) gh = dup_rshift(dup_slice(g, n2, n, K), n2, K) lo, hi = dup_mul(fl, gl, K), dup_mul(fh, gh, K) mid = dup_mul(dup_add(fl, fh, K), dup_add(gl, gh, K), K) mid = dup_sub(mid, dup_add(lo, hi, K), K) return dup_add(dup_add(lo, dup_lshift(mid, n2, K), K), dup_lshift(hi, 2*n2, K), K) def dmp_mul(f, g, u, K): """ Multiply dense polynomials in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_mul(x*y + 1, x) x**2*y + x """ if not u: return dup_mul(f, g, K) if f == g: return dmp_sqr(f, u, K) df = dmp_degree(f, u) if df < 0: return f dg = dmp_degree(g, u) if dg < 0: return g h, v = [], u - 1 for i in range(0, df + dg + 1): coeff = dmp_zero(v) for j in range(max(0, i - dg), min(df, i) + 1): coeff = dmp_add(coeff, dmp_mul(f[j], g[i - j], v, K), v, K) h.append(coeff) return dmp_strip(h, u) def dup_sqr(f, K): """ Square dense polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sqr(x**2 + 1) x**4 + 2*x**2 + 1 """ df, h = len(f) - 1, [] for i in range(0, 2*df + 1): c = K.zero jmin = max(0, i - df) jmax = min(i, df) n = jmax - jmin + 1 jmax = jmin + n // 2 - 1 for j in range(jmin, jmax + 1): c += f[j]*f[i - j] c += c if n & 1: elem = f[jmax + 1] c += elem**2 h.append(c) return dup_strip(h) def dmp_sqr(f, u, K): """ Square dense polynomials in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_sqr(x**2 + x*y + y**2) x**4 + 2*x**3*y + 3*x**2*y**2 + 2*x*y**3 + y**4 """ if not u: return dup_sqr(f, K) df = dmp_degree(f, u) if df < 0: return f h, v = [], u - 1 for i in range(0, 2*df + 1): c = dmp_zero(v) jmin = max(0, i - df) jmax = min(i, df) n = jmax - jmin + 1 jmax = jmin + n // 2 - 1 for j in range(jmin, jmax + 1): c = dmp_add(c, dmp_mul(f[j], f[i - j], v, K), v, K) c = dmp_mul_ground(c, K(2), v, K) if n & 1: elem = dmp_sqr(f[jmax + 1], v, K) c = dmp_add(c, elem, v, K) h.append(c) return dmp_strip(h, u) def dup_pow(f, n, K): """ Raise ``f`` to the ``n``-th power in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_pow(x - 2, 3) x**3 - 6*x**2 + 12*x - 8 """ if not n: return [K.one] if n < 0: raise ValueError("can't raise polynomial to a negative power") if n == 1 or not f or f == [K.one]: return f g = [K.one] while True: n, m = n//2, n if m % 2: g = dup_mul(g, f, K) if not n: break f = dup_sqr(f, K) return g def dmp_pow(f, n, u, K): """ Raise ``f`` to the ``n``-th power in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_pow(x*y + 1, 3) x**3*y**3 + 3*x**2*y**2 + 3*x*y + 1 """ if not u: return dup_pow(f, n, K) if not n: return dmp_one(u, K) if n < 0: raise ValueError("can't raise polynomial to a negative power") if n == 1 or dmp_zero_p(f, u) or dmp_one_p(f, u, K): return f g = dmp_one(u, K) while True: n, m = n//2, n if m & 1: g = dmp_mul(g, f, u, K) if not n: break f = dmp_sqr(f, u, K) return g def dup_pdiv(f, g, K): """ Polynomial pseudo-division in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_pdiv(x**2 + 1, 2*x - 4) (2*x + 4, 20) """ df = dup_degree(f) dg = dup_degree(g) q, r, dr = [], f, df if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r N = df - dg + 1 lc_g = dup_LC(g, K) while True: lc_r = dup_LC(r, K) j, N = dr - dg, N - 1 Q = dup_mul_ground(q, lc_g, K) q = dup_add_term(Q, lc_r, j, K) R = dup_mul_ground(r, lc_g, K) G = dup_mul_term(g, lc_r, j, K) r = dup_sub(R, G, K) _dr, dr = dr, dup_degree(r) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) c = lc_g**N q = dup_mul_ground(q, c, K) r = dup_mul_ground(r, c, K) return q, r def dup_prem(f, g, K): """ Polynomial pseudo-remainder in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_prem(x**2 + 1, 2*x - 4) 20 """ df = dup_degree(f) dg = dup_degree(g) r, dr = f, df if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return r N = df - dg + 1 lc_g = dup_LC(g, K) while True: lc_r = dup_LC(r, K) j, N = dr - dg, N - 1 R = dup_mul_ground(r, lc_g, K) G = dup_mul_term(g, lc_r, j, K) r = dup_sub(R, G, K) _dr, dr = dr, dup_degree(r) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) return dup_mul_ground(r, lc_g**N, K) def dup_pquo(f, g, K): """ Polynomial exact pseudo-quotient in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_pquo(x**2 - 1, 2*x - 2) 2*x + 2 >>> R.dup_pquo(x**2 + 1, 2*x - 4) 2*x + 4 """ return dup_pdiv(f, g, K)[0] def dup_pexquo(f, g, K): """ Polynomial pseudo-quotient in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_pexquo(x**2 - 1, 2*x - 2) 2*x + 2 >>> R.dup_pexquo(x**2 + 1, 2*x - 4) Traceback (most recent call last): ... ExactQuotientFailed: [2, -4] does not divide [1, 0, 1] """ q, r = dup_pdiv(f, g, K) if not r: return q else: raise ExactQuotientFailed(f, g) def dmp_pdiv(f, g, u, K): """ Polynomial pseudo-division in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_pdiv(x**2 + x*y, 2*x + 2) (2*x + 2*y - 2, -4*y + 4) """ if not u: return dup_pdiv(f, g, K) df = dmp_degree(f, u) dg = dmp_degree(g, u) if dg < 0: raise ZeroDivisionError("polynomial division") q, r, dr = dmp_zero(u), f, df if df < dg: return q, r N = df - dg + 1 lc_g = dmp_LC(g, K) while True: lc_r = dmp_LC(r, K) j, N = dr - dg, N - 1 Q = dmp_mul_term(q, lc_g, 0, u, K) q = dmp_add_term(Q, lc_r, j, u, K) R = dmp_mul_term(r, lc_g, 0, u, K) G = dmp_mul_term(g, lc_r, j, u, K) r = dmp_sub(R, G, u, K) _dr, dr = dr, dmp_degree(r, u) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) c = dmp_pow(lc_g, N, u - 1, K) q = dmp_mul_term(q, c, 0, u, K) r = dmp_mul_term(r, c, 0, u, K) return q, r def dmp_prem(f, g, u, K): """ Polynomial pseudo-remainder in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_prem(x**2 + x*y, 2*x + 2) -4*y + 4 """ if not u: return dup_prem(f, g, K) df = dmp_degree(f, u) dg = dmp_degree(g, u) if dg < 0: raise ZeroDivisionError("polynomial division") r, dr = f, df if df < dg: return r N = df - dg + 1 lc_g = dmp_LC(g, K) while True: lc_r = dmp_LC(r, K) j, N = dr - dg, N - 1 R = dmp_mul_term(r, lc_g, 0, u, K) G = dmp_mul_term(g, lc_r, j, u, K) r = dmp_sub(R, G, u, K) _dr, dr = dr, dmp_degree(r, u) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) c = dmp_pow(lc_g, N, u - 1, K) return dmp_mul_term(r, c, 0, u, K) def dmp_pquo(f, g, u, K): """ Polynomial exact pseudo-quotient in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x**2 + x*y >>> g = 2*x + 2*y >>> h = 2*x + 2 >>> R.dmp_pquo(f, g) 2*x >>> R.dmp_pquo(f, h) 2*x + 2*y - 2 """ return dmp_pdiv(f, g, u, K)[0] def dmp_pexquo(f, g, u, K): """ Polynomial pseudo-quotient in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x**2 + x*y >>> g = 2*x + 2*y >>> h = 2*x + 2 >>> R.dmp_pexquo(f, g) 2*x >>> R.dmp_pexquo(f, h) Traceback (most recent call last): ... ExactQuotientFailed: [[2], [2]] does not divide [[1], [1, 0], []] """ q, r = dmp_pdiv(f, g, u, K) if dmp_zero_p(r, u): return q else: raise ExactQuotientFailed(f, g) def dup_rr_div(f, g, K): """ Univariate division with remainder over a ring. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_rr_div(x**2 + 1, 2*x - 4) (0, x**2 + 1) """ df = dup_degree(f) dg = dup_degree(g) q, r, dr = [], f, df if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: lc_r = dup_LC(r, K) if lc_r % lc_g: break c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) _dr, dr = dr, dup_degree(r) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) return q, r def dmp_rr_div(f, g, u, K): """ Multivariate division with remainder over a ring. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_rr_div(x**2 + x*y, 2*x + 2) (0, x**2 + x*y) """ if not u: return dup_rr_div(f, g, K) df = dmp_degree(f, u) dg = dmp_degree(g, u) if dg < 0: raise ZeroDivisionError("polynomial division") q, r, dr = dmp_zero(u), f, df if df < dg: return q, r lc_g, v = dmp_LC(g, K), u - 1 while True: lc_r = dmp_LC(r, K) c, R = dmp_rr_div(lc_r, lc_g, v, K) if not dmp_zero_p(R, v): break j = dr - dg q = dmp_add_term(q, c, j, u, K) h = dmp_mul_term(g, c, j, u, K) r = dmp_sub(r, h, u, K) _dr, dr = dr, dmp_degree(r, u) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) return q, r def dup_ff_div(f, g, K): """ Polynomial division with remainder over a field. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> R.dup_ff_div(x**2 + 1, 2*x - 4) (1/2*x + 1, 5) """ df = dup_degree(f) dg = dup_degree(g) q, r, dr = [], f, df if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return q, r lc_g = dup_LC(g, K) while True: lc_r = dup_LC(r, K) c = K.exquo(lc_r, lc_g) j = dr - dg q = dup_add_term(q, c, j, K) h = dup_mul_term(g, c, j, K) r = dup_sub(r, h, K) _dr, dr = dr, dup_degree(r) if dr < dg: break elif dr == _dr and not K.is_Exact: # remove leading term created by rounding error r = dup_strip(r[1:]) dr = dup_degree(r) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) return q, r def dmp_ff_div(f, g, u, K): """ Polynomial division with remainder over a field. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y = ring("x,y", QQ) >>> R.dmp_ff_div(x**2 + x*y, 2*x + 2) (1/2*x + 1/2*y - 1/2, -y + 1) """ if not u: return dup_ff_div(f, g, K) df = dmp_degree(f, u) dg = dmp_degree(g, u) if dg < 0: raise ZeroDivisionError("polynomial division") q, r, dr = dmp_zero(u), f, df if df < dg: return q, r lc_g, v = dmp_LC(g, K), u - 1 while True: lc_r = dmp_LC(r, K) c, R = dmp_ff_div(lc_r, lc_g, v, K) if not dmp_zero_p(R, v): break j = dr - dg q = dmp_add_term(q, c, j, u, K) h = dmp_mul_term(g, c, j, u, K) r = dmp_sub(r, h, u, K) _dr, dr = dr, dmp_degree(r, u) if dr < dg: break elif not (dr < _dr): raise PolynomialDivisionFailed(f, g, K) return q, r def dup_div(f, g, K): """ Polynomial division with remainder in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x = ring("x", ZZ) >>> R.dup_div(x**2 + 1, 2*x - 4) (0, x**2 + 1) >>> R, x = ring("x", QQ) >>> R.dup_div(x**2 + 1, 2*x - 4) (1/2*x + 1, 5) """ if K.is_Field: return dup_ff_div(f, g, K) else: return dup_rr_div(f, g, K) def dup_rem(f, g, K): """ Returns polynomial remainder in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x = ring("x", ZZ) >>> R.dup_rem(x**2 + 1, 2*x - 4) x**2 + 1 >>> R, x = ring("x", QQ) >>> R.dup_rem(x**2 + 1, 2*x - 4) 5 """ return dup_div(f, g, K)[1] def dup_quo(f, g, K): """ Returns exact polynomial quotient in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x = ring("x", ZZ) >>> R.dup_quo(x**2 + 1, 2*x - 4) 0 >>> R, x = ring("x", QQ) >>> R.dup_quo(x**2 + 1, 2*x - 4) 1/2*x + 1 """ return dup_div(f, g, K)[0] def dup_exquo(f, g, K): """ Returns polynomial quotient in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_exquo(x**2 - 1, x - 1) x + 1 >>> R.dup_exquo(x**2 + 1, 2*x - 4) Traceback (most recent call last): ... ExactQuotientFailed: [2, -4] does not divide [1, 0, 1] """ q, r = dup_div(f, g, K) if not r: return q else: raise ExactQuotientFailed(f, g) def dmp_div(f, g, u, K): """ Polynomial division with remainder in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_div(x**2 + x*y, 2*x + 2) (0, x**2 + x*y) >>> R, x,y = ring("x,y", QQ) >>> R.dmp_div(x**2 + x*y, 2*x + 2) (1/2*x + 1/2*y - 1/2, -y + 1) """ if K.is_Field: return dmp_ff_div(f, g, u, K) else: return dmp_rr_div(f, g, u, K) def dmp_rem(f, g, u, K): """ Returns polynomial remainder in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_rem(x**2 + x*y, 2*x + 2) x**2 + x*y >>> R, x,y = ring("x,y", QQ) >>> R.dmp_rem(x**2 + x*y, 2*x + 2) -y + 1 """ return dmp_div(f, g, u, K)[1] def dmp_quo(f, g, u, K): """ Returns exact polynomial quotient in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_quo(x**2 + x*y, 2*x + 2) 0 >>> R, x,y = ring("x,y", QQ) >>> R.dmp_quo(x**2 + x*y, 2*x + 2) 1/2*x + 1/2*y - 1/2 """ return dmp_div(f, g, u, K)[0] def dmp_exquo(f, g, u, K): """ Returns polynomial quotient in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x**2 + x*y >>> g = x + y >>> h = 2*x + 2 >>> R.dmp_exquo(f, g) x >>> R.dmp_exquo(f, h) Traceback (most recent call last): ... ExactQuotientFailed: [[2], [2]] does not divide [[1], [1, 0], []] """ q, r = dmp_div(f, g, u, K) if dmp_zero_p(r, u): return q else: raise ExactQuotientFailed(f, g) def dup_max_norm(f, K): """ Returns maximum norm of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_max_norm(-x**2 + 2*x - 3) 3 """ if not f: return K.zero else: return max(dup_abs(f, K)) def dmp_max_norm(f, u, K): """ Returns maximum norm of a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_max_norm(2*x*y - x - 3) 3 """ if not u: return dup_max_norm(f, K) v = u - 1 return max([ dmp_max_norm(c, v, K) for c in f ]) def dup_l1_norm(f, K): """ Returns l1 norm of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_l1_norm(2*x**3 - 3*x**2 + 1) 6 """ if not f: return K.zero else: return sum(dup_abs(f, K)) def dmp_l1_norm(f, u, K): """ Returns l1 norm of a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_l1_norm(2*x*y - x - 3) 6 """ if not u: return dup_l1_norm(f, K) v = u - 1 return sum([ dmp_l1_norm(c, v, K) for c in f ]) def dup_expand(polys, K): """ Multiply together several polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_expand([x**2 - 1, x, 2]) 2*x**3 - 2*x """ if not polys: return [K.one] f = polys[0] for g in polys[1:]: f = dup_mul(f, g, K) return f def dmp_expand(polys, u, K): """ Multiply together several polynomials in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_expand([x**2 + y**2, x + 1]) x**3 + x**2 + x*y**2 + y**2 """ if not polys: return dmp_one(u, K) f = polys[0] for g in polys[1:]: f = dmp_mul(f, g, u, K) return f sympy-sympy-1.9/sympy/polys/densebasic.py000066400000000000000000001060751412543434000207350ustar00rootroot00000000000000"""Basic tools for dense recursive polynomials in ``K[x]`` or ``K[X]``. """ from sympy import oo from sympy.core import igcd from sympy.polys.monomials import monomial_min, monomial_div from sympy.polys.orderings import monomial_key import random def poly_LC(f, K): """ Return leading coefficient of ``f``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import poly_LC >>> poly_LC([], ZZ) 0 >>> poly_LC([ZZ(1), ZZ(2), ZZ(3)], ZZ) 1 """ if not f: return K.zero else: return f[0] def poly_TC(f, K): """ Return trailing coefficient of ``f``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import poly_TC >>> poly_TC([], ZZ) 0 >>> poly_TC([ZZ(1), ZZ(2), ZZ(3)], ZZ) 3 """ if not f: return K.zero else: return f[-1] dup_LC = dmp_LC = poly_LC dup_TC = dmp_TC = poly_TC def dmp_ground_LC(f, u, K): """ Return the ground leading coefficient. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_ground_LC >>> f = ZZ.map([[[1], [2, 3]]]) >>> dmp_ground_LC(f, 2, ZZ) 1 """ while u: f = dmp_LC(f, K) u -= 1 return dup_LC(f, K) def dmp_ground_TC(f, u, K): """ Return the ground trailing coefficient. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_ground_TC >>> f = ZZ.map([[[1], [2, 3]]]) >>> dmp_ground_TC(f, 2, ZZ) 3 """ while u: f = dmp_TC(f, K) u -= 1 return dup_TC(f, K) def dmp_true_LT(f, u, K): """ Return the leading term ``c * x_1**n_1 ... x_k**n_k``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_true_LT >>> f = ZZ.map([[4], [2, 0], [3, 0, 0]]) >>> dmp_true_LT(f, 1, ZZ) ((2, 0), 4) """ monom = [] while u: monom.append(len(f) - 1) f, u = f[0], u - 1 if not f: monom.append(0) else: monom.append(len(f) - 1) return tuple(monom), dup_LC(f, K) def dup_degree(f): """ Return the leading degree of ``f`` in ``K[x]``. Note that the degree of 0 is negative infinity (the SymPy object -oo). Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_degree >>> f = ZZ.map([1, 2, 0, 3]) >>> dup_degree(f) 3 """ if not f: return -oo return len(f) - 1 def dmp_degree(f, u): """ Return the leading degree of ``f`` in ``x_0`` in ``K[X]``. Note that the degree of 0 is negative infinity (the SymPy object -oo). Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_degree >>> dmp_degree([[[]]], 2) -oo >>> f = ZZ.map([[2], [1, 2, 3]]) >>> dmp_degree(f, 1) 1 """ if dmp_zero_p(f, u): return -oo else: return len(f) - 1 def _rec_degree_in(g, v, i, j): """Recursive helper function for :func:`dmp_degree_in`.""" if i == j: return dmp_degree(g, v) v, i = v - 1, i + 1 return max([ _rec_degree_in(c, v, i, j) for c in g ]) def dmp_degree_in(f, j, u): """ Return the leading degree of ``f`` in ``x_j`` in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_degree_in >>> f = ZZ.map([[2], [1, 2, 3]]) >>> dmp_degree_in(f, 0, 1) 1 >>> dmp_degree_in(f, 1, 1) 2 """ if not j: return dmp_degree(f, u) if j < 0 or j > u: raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) return _rec_degree_in(f, u, 0, j) def _rec_degree_list(g, v, i, degs): """Recursive helper for :func:`dmp_degree_list`.""" degs[i] = max(degs[i], dmp_degree(g, v)) if v > 0: v, i = v - 1, i + 1 for c in g: _rec_degree_list(c, v, i, degs) def dmp_degree_list(f, u): """ Return a list of degrees of ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_degree_list >>> f = ZZ.map([[1], [1, 2, 3]]) >>> dmp_degree_list(f, 1) (1, 2) """ degs = [-oo]*(u + 1) _rec_degree_list(f, u, 0, degs) return tuple(degs) def dup_strip(f): """ Remove leading zeros from ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys.densebasic import dup_strip >>> dup_strip([0, 0, 1, 2, 3, 0]) [1, 2, 3, 0] """ if not f or f[0]: return f i = 0 for cf in f: if cf: break else: i += 1 return f[i:] def dmp_strip(f, u): """ Remove leading zeros from ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys.densebasic import dmp_strip >>> dmp_strip([[], [0, 1, 2], [1]], 1) [[0, 1, 2], [1]] """ if not u: return dup_strip(f) if dmp_zero_p(f, u): return f i, v = 0, u - 1 for c in f: if not dmp_zero_p(c, v): break else: i += 1 if i == len(f): return dmp_zero(u) else: return f[i:] def _rec_validate(f, g, i, K): """Recursive helper for :func:`dmp_validate`.""" if type(g) is not list: if K is not None and not K.of_type(g): raise TypeError("%s in %s in not of type %s" % (g, f, K.dtype)) return {i - 1} elif not g: return {i} else: levels = set() for c in g: levels |= _rec_validate(f, c, i + 1, K) return levels def _rec_strip(g, v): """Recursive helper for :func:`_rec_strip`.""" if not v: return dup_strip(g) w = v - 1 return dmp_strip([ _rec_strip(c, w) for c in g ], v) def dmp_validate(f, K=None): """ Return the number of levels in ``f`` and recursively strip it. Examples ======== >>> from sympy.polys.densebasic import dmp_validate >>> dmp_validate([[], [0, 1, 2], [1]]) ([[1, 2], [1]], 1) >>> dmp_validate([[1], 1]) Traceback (most recent call last): ... ValueError: invalid data structure for a multivariate polynomial """ levels = _rec_validate(f, f, 0, K) u = levels.pop() if not levels: return _rec_strip(f, u), u else: raise ValueError( "invalid data structure for a multivariate polynomial") def dup_reverse(f): """ Compute ``x**n * f(1/x)``, i.e.: reverse ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_reverse >>> f = ZZ.map([1, 2, 3, 0]) >>> dup_reverse(f) [3, 2, 1] """ return dup_strip(list(reversed(f))) def dup_copy(f): """ Create a new copy of a polynomial ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_copy >>> f = ZZ.map([1, 2, 3, 0]) >>> dup_copy([1, 2, 3, 0]) [1, 2, 3, 0] """ return list(f) def dmp_copy(f, u): """ Create a new copy of a polynomial ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_copy >>> f = ZZ.map([[1], [1, 2]]) >>> dmp_copy(f, 1) [[1], [1, 2]] """ if not u: return list(f) v = u - 1 return [ dmp_copy(c, v) for c in f ] def dup_to_tuple(f): """ Convert `f` into a tuple. This is needed for hashing. This is similar to dup_copy(). Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_copy >>> f = ZZ.map([1, 2, 3, 0]) >>> dup_copy([1, 2, 3, 0]) [1, 2, 3, 0] """ return tuple(f) def dmp_to_tuple(f, u): """ Convert `f` into a nested tuple of tuples. This is needed for hashing. This is similar to dmp_copy(). Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_to_tuple >>> f = ZZ.map([[1], [1, 2]]) >>> dmp_to_tuple(f, 1) ((1,), (1, 2)) """ if not u: return tuple(f) v = u - 1 return tuple(dmp_to_tuple(c, v) for c in f) def dup_normal(f, K): """ Normalize univariate polynomial in the given domain. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_normal >>> dup_normal([0, 1.5, 2, 3], ZZ) [1, 2, 3] """ return dup_strip([ K.normal(c) for c in f ]) def dmp_normal(f, u, K): """ Normalize a multivariate polynomial in the given domain. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_normal >>> dmp_normal([[], [0, 1.5, 2]], 1, ZZ) [[1, 2]] """ if not u: return dup_normal(f, K) v = u - 1 return dmp_strip([ dmp_normal(c, v, K) for c in f ], u) def dup_convert(f, K0, K1): """ Convert the ground domain of ``f`` from ``K0`` to ``K1``. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_convert >>> R, x = ring("x", ZZ) >>> dup_convert([R(1), R(2)], R.to_domain(), ZZ) [1, 2] >>> dup_convert([ZZ(1), ZZ(2)], ZZ, R.to_domain()) [1, 2] """ if K0 is not None and K0 == K1: return f else: return dup_strip([ K1.convert(c, K0) for c in f ]) def dmp_convert(f, u, K0, K1): """ Convert the ground domain of ``f`` from ``K0`` to ``K1``. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_convert >>> R, x = ring("x", ZZ) >>> dmp_convert([[R(1)], [R(2)]], 1, R.to_domain(), ZZ) [[1], [2]] >>> dmp_convert([[ZZ(1)], [ZZ(2)]], 1, ZZ, R.to_domain()) [[1], [2]] """ if not u: return dup_convert(f, K0, K1) if K0 is not None and K0 == K1: return f v = u - 1 return dmp_strip([ dmp_convert(c, v, K0, K1) for c in f ], u) def dup_from_sympy(f, K): """ Convert the ground domain of ``f`` from SymPy to ``K``. Examples ======== >>> from sympy import S >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_from_sympy >>> dup_from_sympy([S(1), S(2)], ZZ) == [ZZ(1), ZZ(2)] True """ return dup_strip([ K.from_sympy(c) for c in f ]) def dmp_from_sympy(f, u, K): """ Convert the ground domain of ``f`` from SymPy to ``K``. Examples ======== >>> from sympy import S >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_from_sympy >>> dmp_from_sympy([[S(1)], [S(2)]], 1, ZZ) == [[ZZ(1)], [ZZ(2)]] True """ if not u: return dup_from_sympy(f, K) v = u - 1 return dmp_strip([ dmp_from_sympy(c, v, K) for c in f ], u) def dup_nth(f, n, K): """ Return the ``n``-th coefficient of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_nth >>> f = ZZ.map([1, 2, 3]) >>> dup_nth(f, 0, ZZ) 3 >>> dup_nth(f, 4, ZZ) 0 """ if n < 0: raise IndexError("'n' must be non-negative, got %i" % n) elif n >= len(f): return K.zero else: return f[dup_degree(f) - n] def dmp_nth(f, n, u, K): """ Return the ``n``-th coefficient of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_nth >>> f = ZZ.map([[1], [2], [3]]) >>> dmp_nth(f, 0, 1, ZZ) [3] >>> dmp_nth(f, 4, 1, ZZ) [] """ if n < 0: raise IndexError("'n' must be non-negative, got %i" % n) elif n >= len(f): return dmp_zero(u - 1) else: return f[dmp_degree(f, u) - n] def dmp_ground_nth(f, N, u, K): """ Return the ground ``n``-th coefficient of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_ground_nth >>> f = ZZ.map([[1], [2, 3]]) >>> dmp_ground_nth(f, (0, 1), 1, ZZ) 2 """ v = u for n in N: if n < 0: raise IndexError("`n` must be non-negative, got %i" % n) elif n >= len(f): return K.zero else: d = dmp_degree(f, v) if d == -oo: d = -1 f, v = f[d - n], v - 1 return f def dmp_zero_p(f, u): """ Return ``True`` if ``f`` is zero in ``K[X]``. Examples ======== >>> from sympy.polys.densebasic import dmp_zero_p >>> dmp_zero_p([[[[[]]]]], 4) True >>> dmp_zero_p([[[[[1]]]]], 4) False """ while u: if len(f) != 1: return False f = f[0] u -= 1 return not f def dmp_zero(u): """ Return a multivariate zero. Examples ======== >>> from sympy.polys.densebasic import dmp_zero >>> dmp_zero(4) [[[[[]]]]] """ r = [] for i in range(u): r = [r] return r def dmp_one_p(f, u, K): """ Return ``True`` if ``f`` is one in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_one_p >>> dmp_one_p([[[ZZ(1)]]], 2, ZZ) True """ return dmp_ground_p(f, K.one, u) def dmp_one(u, K): """ Return a multivariate one over ``K``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_one >>> dmp_one(2, ZZ) [[[1]]] """ return dmp_ground(K.one, u) def dmp_ground_p(f, c, u): """ Return True if ``f`` is constant in ``K[X]``. Examples ======== >>> from sympy.polys.densebasic import dmp_ground_p >>> dmp_ground_p([[[3]]], 3, 2) True >>> dmp_ground_p([[[4]]], None, 2) True """ if c is not None and not c: return dmp_zero_p(f, u) while u: if len(f) != 1: return False f = f[0] u -= 1 if c is None: return len(f) <= 1 else: return f == [c] def dmp_ground(c, u): """ Return a multivariate constant. Examples ======== >>> from sympy.polys.densebasic import dmp_ground >>> dmp_ground(3, 5) [[[[[[3]]]]]] >>> dmp_ground(1, -1) 1 """ if not c: return dmp_zero(u) for i in range(u + 1): c = [c] return c def dmp_zeros(n, u, K): """ Return a list of multivariate zeros. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_zeros >>> dmp_zeros(3, 2, ZZ) [[[[]]], [[[]]], [[[]]]] >>> dmp_zeros(3, -1, ZZ) [0, 0, 0] """ if not n: return [] if u < 0: return [K.zero]*n else: return [ dmp_zero(u) for i in range(n) ] def dmp_grounds(c, n, u): """ Return a list of multivariate constants. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_grounds >>> dmp_grounds(ZZ(4), 3, 2) [[[[4]]], [[[4]]], [[[4]]]] >>> dmp_grounds(ZZ(4), 3, -1) [4, 4, 4] """ if not n: return [] if u < 0: return [c]*n else: return [ dmp_ground(c, u) for i in range(n) ] def dmp_negative_p(f, u, K): """ Return ``True`` if ``LC(f)`` is negative. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_negative_p >>> dmp_negative_p([[ZZ(1)], [-ZZ(1)]], 1, ZZ) False >>> dmp_negative_p([[-ZZ(1)], [ZZ(1)]], 1, ZZ) True """ return K.is_negative(dmp_ground_LC(f, u, K)) def dmp_positive_p(f, u, K): """ Return ``True`` if ``LC(f)`` is positive. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_positive_p >>> dmp_positive_p([[ZZ(1)], [-ZZ(1)]], 1, ZZ) True >>> dmp_positive_p([[-ZZ(1)], [ZZ(1)]], 1, ZZ) False """ return K.is_positive(dmp_ground_LC(f, u, K)) def dup_from_dict(f, K): """ Create a ``K[x]`` polynomial from a ``dict``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_from_dict >>> dup_from_dict({(0,): ZZ(7), (2,): ZZ(5), (4,): ZZ(1)}, ZZ) [1, 0, 5, 0, 7] >>> dup_from_dict({}, ZZ) [] """ if not f: return [] n, h = max(f.keys()), [] if type(n) is int: for k in range(n, -1, -1): h.append(f.get(k, K.zero)) else: (n,) = n for k in range(n, -1, -1): h.append(f.get((k,), K.zero)) return dup_strip(h) def dup_from_raw_dict(f, K): """ Create a ``K[x]`` polynomial from a raw ``dict``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_from_raw_dict >>> dup_from_raw_dict({0: ZZ(7), 2: ZZ(5), 4: ZZ(1)}, ZZ) [1, 0, 5, 0, 7] """ if not f: return [] n, h = max(f.keys()), [] for k in range(n, -1, -1): h.append(f.get(k, K.zero)) return dup_strip(h) def dmp_from_dict(f, u, K): """ Create a ``K[X]`` polynomial from a ``dict``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_from_dict >>> dmp_from_dict({(0, 0): ZZ(3), (0, 1): ZZ(2), (2, 1): ZZ(1)}, 1, ZZ) [[1, 0], [], [2, 3]] >>> dmp_from_dict({}, 0, ZZ) [] """ if not u: return dup_from_dict(f, K) if not f: return dmp_zero(u) coeffs = {} for monom, coeff in f.items(): head, tail = monom[0], monom[1:] if head in coeffs: coeffs[head][tail] = coeff else: coeffs[head] = { tail: coeff } n, v, h = max(coeffs.keys()), u - 1, [] for k in range(n, -1, -1): coeff = coeffs.get(k) if coeff is not None: h.append(dmp_from_dict(coeff, v, K)) else: h.append(dmp_zero(v)) return dmp_strip(h, u) def dup_to_dict(f, K=None, zero=False): """ Convert ``K[x]`` polynomial to a ``dict``. Examples ======== >>> from sympy.polys.densebasic import dup_to_dict >>> dup_to_dict([1, 0, 5, 0, 7]) {(0,): 7, (2,): 5, (4,): 1} >>> dup_to_dict([]) {} """ if not f and zero: return {(0,): K.zero} n, result = len(f) - 1, {} for k in range(0, n + 1): if f[n - k]: result[(k,)] = f[n - k] return result def dup_to_raw_dict(f, K=None, zero=False): """ Convert a ``K[x]`` polynomial to a raw ``dict``. Examples ======== >>> from sympy.polys.densebasic import dup_to_raw_dict >>> dup_to_raw_dict([1, 0, 5, 0, 7]) {0: 7, 2: 5, 4: 1} """ if not f and zero: return {0: K.zero} n, result = len(f) - 1, {} for k in range(0, n + 1): if f[n - k]: result[k] = f[n - k] return result def dmp_to_dict(f, u, K=None, zero=False): """ Convert a ``K[X]`` polynomial to a ``dict````. Examples ======== >>> from sympy.polys.densebasic import dmp_to_dict >>> dmp_to_dict([[1, 0], [], [2, 3]], 1) {(0, 0): 3, (0, 1): 2, (2, 1): 1} >>> dmp_to_dict([], 0) {} """ if not u: return dup_to_dict(f, K, zero=zero) if dmp_zero_p(f, u) and zero: return {(0,)*(u + 1): K.zero} n, v, result = dmp_degree(f, u), u - 1, {} if n == -oo: n = -1 for k in range(0, n + 1): h = dmp_to_dict(f[n - k], v) for exp, coeff in h.items(): result[(k,) + exp] = coeff return result def dmp_swap(f, i, j, u, K): """ Transform ``K[..x_i..x_j..]`` to ``K[..x_j..x_i..]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_swap >>> f = ZZ.map([[[2], [1, 0]], []]) >>> dmp_swap(f, 0, 1, 2, ZZ) [[[2], []], [[1, 0], []]] >>> dmp_swap(f, 1, 2, 2, ZZ) [[[1], [2, 0]], [[]]] >>> dmp_swap(f, 0, 2, 2, ZZ) [[[1, 0]], [[2, 0], []]] """ if i < 0 or j < 0 or i > u or j > u: raise IndexError("0 <= i < j <= %s expected" % u) elif i == j: return f F, H = dmp_to_dict(f, u), {} for exp, coeff in F.items(): H[exp[:i] + (exp[j],) + exp[i + 1:j] + (exp[i],) + exp[j + 1:]] = coeff return dmp_from_dict(H, u, K) def dmp_permute(f, P, u, K): """ Return a polynomial in ``K[x_{P(1)},..,x_{P(n)}]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_permute >>> f = ZZ.map([[[2], [1, 0]], []]) >>> dmp_permute(f, [1, 0, 2], 2, ZZ) [[[2], []], [[1, 0], []]] >>> dmp_permute(f, [1, 2, 0], 2, ZZ) [[[1], []], [[2, 0], []]] """ F, H = dmp_to_dict(f, u), {} for exp, coeff in F.items(): new_exp = [0]*len(exp) for e, p in zip(exp, P): new_exp[p] = e H[tuple(new_exp)] = coeff return dmp_from_dict(H, u, K) def dmp_nest(f, l, K): """ Return a multivariate value nested ``l``-levels. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_nest >>> dmp_nest([[ZZ(1)]], 2, ZZ) [[[[1]]]] """ if not isinstance(f, list): return dmp_ground(f, l) for i in range(l): f = [f] return f def dmp_raise(f, l, u, K): """ Return a multivariate polynomial raised ``l``-levels. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_raise >>> f = ZZ.map([[], [1, 2]]) >>> dmp_raise(f, 2, 1, ZZ) [[[[]]], [[[1]], [[2]]]] """ if not l: return f if not u: if not f: return dmp_zero(l) k = l - 1 return [ dmp_ground(c, k) for c in f ] v = u - 1 return [ dmp_raise(c, l, v, K) for c in f ] def dup_deflate(f, K): """ Map ``x**m`` to ``y`` in a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_deflate >>> f = ZZ.map([1, 0, 0, 1, 0, 0, 1]) >>> dup_deflate(f, ZZ) (3, [1, 1, 1]) """ if dup_degree(f) <= 0: return 1, f g = 0 for i in range(len(f)): if not f[-i - 1]: continue g = igcd(g, i) if g == 1: return 1, f return g, f[::g] def dmp_deflate(f, u, K): """ Map ``x_i**m_i`` to ``y_i`` in a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_deflate >>> f = ZZ.map([[1, 0, 0, 2], [], [3, 0, 0, 4]]) >>> dmp_deflate(f, 1, ZZ) ((2, 3), [[1, 2], [3, 4]]) """ if dmp_zero_p(f, u): return (1,)*(u + 1), f F = dmp_to_dict(f, u) B = [0]*(u + 1) for M in F.keys(): for i, m in enumerate(M): B[i] = igcd(B[i], m) for i, b in enumerate(B): if not b: B[i] = 1 B = tuple(B) if all(b == 1 for b in B): return B, f H = {} for A, coeff in F.items(): N = [ a // b for a, b in zip(A, B) ] H[tuple(N)] = coeff return B, dmp_from_dict(H, u, K) def dup_multi_deflate(polys, K): """ Map ``x**m`` to ``y`` in a set of polynomials in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_multi_deflate >>> f = ZZ.map([1, 0, 2, 0, 3]) >>> g = ZZ.map([4, 0, 0]) >>> dup_multi_deflate((f, g), ZZ) (2, ([1, 2, 3], [4, 0])) """ G = 0 for p in polys: if dup_degree(p) <= 0: return 1, polys g = 0 for i in range(len(p)): if not p[-i - 1]: continue g = igcd(g, i) if g == 1: return 1, polys G = igcd(G, g) return G, tuple([ p[::G] for p in polys ]) def dmp_multi_deflate(polys, u, K): """ Map ``x_i**m_i`` to ``y_i`` in a set of polynomials in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_multi_deflate >>> f = ZZ.map([[1, 0, 0, 2], [], [3, 0, 0, 4]]) >>> g = ZZ.map([[1, 0, 2], [], [3, 0, 4]]) >>> dmp_multi_deflate((f, g), 1, ZZ) ((2, 1), ([[1, 0, 0, 2], [3, 0, 0, 4]], [[1, 0, 2], [3, 0, 4]])) """ if not u: M, H = dup_multi_deflate(polys, K) return (M,), H F, B = [], [0]*(u + 1) for p in polys: f = dmp_to_dict(p, u) if not dmp_zero_p(p, u): for M in f.keys(): for i, m in enumerate(M): B[i] = igcd(B[i], m) F.append(f) for i, b in enumerate(B): if not b: B[i] = 1 B = tuple(B) if all(b == 1 for b in B): return B, polys H = [] for f in F: h = {} for A, coeff in f.items(): N = [ a // b for a, b in zip(A, B) ] h[tuple(N)] = coeff H.append(dmp_from_dict(h, u, K)) return B, tuple(H) def dup_inflate(f, m, K): """ Map ``y`` to ``x**m`` in a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_inflate >>> f = ZZ.map([1, 1, 1]) >>> dup_inflate(f, 3, ZZ) [1, 0, 0, 1, 0, 0, 1] """ if m <= 0: raise IndexError("'m' must be positive, got %s" % m) if m == 1 or not f: return f result = [f[0]] for coeff in f[1:]: result.extend([K.zero]*(m - 1)) result.append(coeff) return result def _rec_inflate(g, M, v, i, K): """Recursive helper for :func:`dmp_inflate`.""" if not v: return dup_inflate(g, M[i], K) if M[i] <= 0: raise IndexError("all M[i] must be positive, got %s" % M[i]) w, j = v - 1, i + 1 g = [ _rec_inflate(c, M, w, j, K) for c in g ] result = [g[0]] for coeff in g[1:]: for _ in range(1, M[i]): result.append(dmp_zero(w)) result.append(coeff) return result def dmp_inflate(f, M, u, K): """ Map ``y_i`` to ``x_i**k_i`` in a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_inflate >>> f = ZZ.map([[1, 2], [3, 4]]) >>> dmp_inflate(f, (2, 3), 1, ZZ) [[1, 0, 0, 2], [], [3, 0, 0, 4]] """ if not u: return dup_inflate(f, M[0], K) if all(m == 1 for m in M): return f else: return _rec_inflate(f, M, u, 0, K) def dmp_exclude(f, u, K): """ Exclude useless levels from ``f``. Return the levels excluded, the new excluded ``f``, and the new ``u``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_exclude >>> f = ZZ.map([[[1]], [[1], [2]]]) >>> dmp_exclude(f, 2, ZZ) ([2], [[1], [1, 2]], 1) """ if not u or dmp_ground_p(f, None, u): return [], f, u J, F = [], dmp_to_dict(f, u) for j in range(0, u + 1): for monom in F.keys(): if monom[j]: break else: J.append(j) if not J: return [], f, u f = {} for monom, coeff in F.items(): monom = list(monom) for j in reversed(J): del monom[j] f[tuple(monom)] = coeff u -= len(J) return J, dmp_from_dict(f, u, K), u def dmp_include(f, J, u, K): """ Include useless levels in ``f``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_include >>> f = ZZ.map([[1], [1, 2]]) >>> dmp_include(f, [2], 1, ZZ) [[[1]], [[1], [2]]] """ if not J: return f F, f = dmp_to_dict(f, u), {} for monom, coeff in F.items(): monom = list(monom) for j in J: monom.insert(j, 0) f[tuple(monom)] = coeff u += len(J) return dmp_from_dict(f, u, K) def dmp_inject(f, u, K, front=False): """ Convert ``f`` from ``K[X][Y]`` to ``K[X,Y]``. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_inject >>> R, x,y = ring("x,y", ZZ) >>> dmp_inject([R(1), x + 2], 0, R.to_domain()) ([[[1]], [[1], [2]]], 2) >>> dmp_inject([R(1), x + 2], 0, R.to_domain(), front=True) ([[[1]], [[1, 2]]], 2) """ f, h = dmp_to_dict(f, u), {} v = K.ngens - 1 for f_monom, g in f.items(): g = g.to_dict() for g_monom, c in g.items(): if front: h[g_monom + f_monom] = c else: h[f_monom + g_monom] = c w = u + v + 1 return dmp_from_dict(h, w, K.dom), w def dmp_eject(f, u, K, front=False): """ Convert ``f`` from ``K[X,Y]`` to ``K[X][Y]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_eject >>> dmp_eject([[[1]], [[1], [2]]], 2, ZZ['x', 'y']) [1, x + 2] """ f, h = dmp_to_dict(f, u), {} n = K.ngens v = u - K.ngens + 1 for monom, c in f.items(): if front: g_monom, f_monom = monom[:n], monom[n:] else: g_monom, f_monom = monom[-n:], monom[:-n] if f_monom in h: h[f_monom][g_monom] = c else: h[f_monom] = {g_monom: c} for monom, c in h.items(): h[monom] = K(c) return dmp_from_dict(h, v - 1, K) def dup_terms_gcd(f, K): """ Remove GCD of terms from ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_terms_gcd >>> f = ZZ.map([1, 0, 1, 0, 0]) >>> dup_terms_gcd(f, ZZ) (2, [1, 0, 1]) """ if dup_TC(f, K) or not f: return 0, f i = 0 for c in reversed(f): if not c: i += 1 else: break return i, f[:-i] def dmp_terms_gcd(f, u, K): """ Remove GCD of terms from ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_terms_gcd >>> f = ZZ.map([[1, 0], [1, 0, 0], [], []]) >>> dmp_terms_gcd(f, 1, ZZ) ((2, 1), [[1], [1, 0]]) """ if dmp_ground_TC(f, u, K) or dmp_zero_p(f, u): return (0,)*(u + 1), f F = dmp_to_dict(f, u) G = monomial_min(*list(F.keys())) if all(g == 0 for g in G): return G, f f = {} for monom, coeff in F.items(): f[monomial_div(monom, G)] = coeff return G, dmp_from_dict(f, u, K) def _rec_list_terms(g, v, monom): """Recursive helper for :func:`dmp_list_terms`.""" d, terms = dmp_degree(g, v), [] if not v: for i, c in enumerate(g): if not c: continue terms.append((monom + (d - i,), c)) else: w = v - 1 for i, c in enumerate(g): terms.extend(_rec_list_terms(c, w, monom + (d - i,))) return terms def dmp_list_terms(f, u, K, order=None): """ List all non-zero terms from ``f`` in the given order ``order``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_list_terms >>> f = ZZ.map([[1, 1], [2, 3]]) >>> dmp_list_terms(f, 1, ZZ) [((1, 1), 1), ((1, 0), 1), ((0, 1), 2), ((0, 0), 3)] >>> dmp_list_terms(f, 1, ZZ, order='grevlex') [((1, 1), 1), ((1, 0), 1), ((0, 1), 2), ((0, 0), 3)] """ def sort(terms, O): return sorted(terms, key=lambda term: O(term[0]), reverse=True) terms = _rec_list_terms(f, u, ()) if not terms: return [((0,)*(u + 1), K.zero)] if order is None: return terms else: return sort(terms, monomial_key(order)) def dup_apply_pairs(f, g, h, args, K): """ Apply ``h`` to pairs of coefficients of ``f`` and ``g``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_apply_pairs >>> h = lambda x, y, z: 2*x + y - z >>> dup_apply_pairs([1, 2, 3], [3, 2, 1], h, (1,), ZZ) [4, 5, 6] """ n, m = len(f), len(g) if n != m: if n > m: g = [K.zero]*(n - m) + g else: f = [K.zero]*(m - n) + f result = [] for a, b in zip(f, g): result.append(h(a, b, *args)) return dup_strip(result) def dmp_apply_pairs(f, g, h, args, u, K): """ Apply ``h`` to pairs of coefficients of ``f`` and ``g``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dmp_apply_pairs >>> h = lambda x, y, z: 2*x + y - z >>> dmp_apply_pairs([[1], [2, 3]], [[3], [2, 1]], h, (1,), 1, ZZ) [[4], [5, 6]] """ if not u: return dup_apply_pairs(f, g, h, args, K) n, m, v = len(f), len(g), u - 1 if n != m: if n > m: g = dmp_zeros(n - m, v, K) + g else: f = dmp_zeros(m - n, v, K) + f result = [] for a, b in zip(f, g): result.append(dmp_apply_pairs(a, b, h, args, v, K)) return dmp_strip(result, u) def dup_slice(f, m, n, K): """Take a continuous subsequence of terms of ``f`` in ``K[x]``. """ k = len(f) if k >= m: M = k - m else: M = 0 if k >= n: N = k - n else: N = 0 f = f[N:M] if not f: return [] else: return f + [K.zero]*m def dmp_slice(f, m, n, u, K): """Take a continuous subsequence of terms of ``f`` in ``K[X]``. """ return dmp_slice_in(f, m, n, 0, u, K) def dmp_slice_in(f, m, n, j, u, K): """Take a continuous subsequence of terms of ``f`` in ``x_j`` in ``K[X]``. """ if j < 0 or j > u: raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) if not u: return dup_slice(f, m, n, K) f, g = dmp_to_dict(f, u), {} for monom, coeff in f.items(): k = monom[j] if k < m or k >= n: monom = monom[:j] + (0,) + monom[j + 1:] if monom in g: g[monom] += coeff else: g[monom] = coeff return dmp_from_dict(g, u, K) def dup_random(n, a, b, K): """ Return a polynomial of degree ``n`` with coefficients in ``[a, b]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.densebasic import dup_random >>> dup_random(3, -10, 10, ZZ) #doctest: +SKIP [-2, -8, 9, -4] """ f = [ K.convert(random.randint(a, b)) for _ in range(0, n + 1) ] while not f[0]: f[0] = K.convert(random.randint(a, b)) return f sympy-sympy-1.9/sympy/polys/densetools.py000066400000000000000000000624431412543434000210140ustar00rootroot00000000000000"""Advanced tools for dense recursive polynomials in ``K[x]`` or ``K[X]``. """ from sympy.polys.densearith import ( dup_add_term, dmp_add_term, dup_lshift, dup_add, dmp_add, dup_sub, dmp_sub, dup_mul, dmp_mul, dup_sqr, dup_div, dup_rem, dmp_rem, dmp_expand, dup_mul_ground, dmp_mul_ground, dup_quo_ground, dmp_quo_ground, dup_exquo_ground, dmp_exquo_ground, ) from sympy.polys.densebasic import ( dup_strip, dmp_strip, dup_convert, dmp_convert, dup_degree, dmp_degree, dmp_to_dict, dmp_from_dict, dup_LC, dmp_LC, dmp_ground_LC, dup_TC, dmp_TC, dmp_zero, dmp_ground, dmp_zero_p, dup_to_raw_dict, dup_from_raw_dict, dmp_zeros ) from sympy.polys.polyerrors import ( MultivariatePolynomialError, DomainError ) from sympy.utilities import variations from math import ceil as _ceil, log as _log def dup_integrate(f, m, K): """ Computes the indefinite integral of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> R.dup_integrate(x**2 + 2*x, 1) 1/3*x**3 + x**2 >>> R.dup_integrate(x**2 + 2*x, 2) 1/12*x**4 + 1/3*x**3 """ if m <= 0 or not f: return f g = [K.zero]*m for i, c in enumerate(reversed(f)): n = i + 1 for j in range(1, m): n *= i + j + 1 g.insert(0, K.exquo(c, K(n))) return g def dmp_integrate(f, m, u, K): """ Computes the indefinite integral of ``f`` in ``x_0`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y = ring("x,y", QQ) >>> R.dmp_integrate(x + 2*y, 1) 1/2*x**2 + 2*x*y >>> R.dmp_integrate(x + 2*y, 2) 1/6*x**3 + x**2*y """ if not u: return dup_integrate(f, m, K) if m <= 0 or dmp_zero_p(f, u): return f g, v = dmp_zeros(m, u - 1, K), u - 1 for i, c in enumerate(reversed(f)): n = i + 1 for j in range(1, m): n *= i + j + 1 g.insert(0, dmp_quo_ground(c, K(n), v, K)) return g def _rec_integrate_in(g, m, v, i, j, K): """Recursive helper for :func:`dmp_integrate_in`.""" if i == j: return dmp_integrate(g, m, v, K) w, i = v - 1, i + 1 return dmp_strip([ _rec_integrate_in(c, m, w, i, j, K) for c in g ], v) def dmp_integrate_in(f, m, j, u, K): """ Computes the indefinite integral of ``f`` in ``x_j`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y = ring("x,y", QQ) >>> R.dmp_integrate_in(x + 2*y, 1, 0) 1/2*x**2 + 2*x*y >>> R.dmp_integrate_in(x + 2*y, 1, 1) x*y + y**2 """ if j < 0 or j > u: raise IndexError("0 <= j <= u expected, got u = %d, j = %d" % (u, j)) return _rec_integrate_in(f, m, u, 0, j, K) def dup_diff(f, m, K): """ ``m``-th order derivative of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_diff(x**3 + 2*x**2 + 3*x + 4, 1) 3*x**2 + 4*x + 3 >>> R.dup_diff(x**3 + 2*x**2 + 3*x + 4, 2) 6*x + 4 """ if m <= 0: return f n = dup_degree(f) if n < m: return [] deriv = [] if m == 1: for coeff in f[:-m]: deriv.append(K(n)*coeff) n -= 1 else: for coeff in f[:-m]: k = n for i in range(n - 1, n - m, -1): k *= i deriv.append(K(k)*coeff) n -= 1 return dup_strip(deriv) def dmp_diff(f, m, u, K): """ ``m``-th order derivative in ``x_0`` of a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 >>> R.dmp_diff(f, 1) y**2 + 2*y + 3 >>> R.dmp_diff(f, 2) 0 """ if not u: return dup_diff(f, m, K) if m <= 0: return f n = dmp_degree(f, u) if n < m: return dmp_zero(u) deriv, v = [], u - 1 if m == 1: for coeff in f[:-m]: deriv.append(dmp_mul_ground(coeff, K(n), v, K)) n -= 1 else: for coeff in f[:-m]: k = n for i in range(n - 1, n - m, -1): k *= i deriv.append(dmp_mul_ground(coeff, K(k), v, K)) n -= 1 return dmp_strip(deriv, u) def _rec_diff_in(g, m, v, i, j, K): """Recursive helper for :func:`dmp_diff_in`.""" if i == j: return dmp_diff(g, m, v, K) w, i = v - 1, i + 1 return dmp_strip([ _rec_diff_in(c, m, w, i, j, K) for c in g ], v) def dmp_diff_in(f, m, j, u, K): """ ``m``-th order derivative in ``x_j`` of a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 >>> R.dmp_diff_in(f, 1, 0) y**2 + 2*y + 3 >>> R.dmp_diff_in(f, 1, 1) 2*x*y + 2*x + 4*y + 3 """ if j < 0 or j > u: raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) return _rec_diff_in(f, m, u, 0, j, K) def dup_eval(f, a, K): """ Evaluate a polynomial at ``x = a`` in ``K[x]`` using Horner scheme. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_eval(x**2 + 2*x + 3, 2) 11 """ if not a: return dup_TC(f, K) result = K.zero for c in f: result *= a result += c return result def dmp_eval(f, a, u, K): """ Evaluate a polynomial at ``x_0 = a`` in ``K[X]`` using the Horner scheme. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_eval(2*x*y + 3*x + y + 2, 2) 5*y + 8 """ if not u: return dup_eval(f, a, K) if not a: return dmp_TC(f, K) result, v = dmp_LC(f, K), u - 1 for coeff in f[1:]: result = dmp_mul_ground(result, a, v, K) result = dmp_add(result, coeff, v, K) return result def _rec_eval_in(g, a, v, i, j, K): """Recursive helper for :func:`dmp_eval_in`.""" if i == j: return dmp_eval(g, a, v, K) v, i = v - 1, i + 1 return dmp_strip([ _rec_eval_in(c, a, v, i, j, K) for c in g ], v) def dmp_eval_in(f, a, j, u, K): """ Evaluate a polynomial at ``x_j = a`` in ``K[X]`` using the Horner scheme. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 2*x*y + 3*x + y + 2 >>> R.dmp_eval_in(f, 2, 0) 5*y + 8 >>> R.dmp_eval_in(f, 2, 1) 7*x + 4 """ if j < 0 or j > u: raise IndexError("0 <= j <= %s expected, got %s" % (u, j)) return _rec_eval_in(f, a, u, 0, j, K) def _rec_eval_tail(g, i, A, u, K): """Recursive helper for :func:`dmp_eval_tail`.""" if i == u: return dup_eval(g, A[-1], K) else: h = [ _rec_eval_tail(c, i + 1, A, u, K) for c in g ] if i < u - len(A) + 1: return h else: return dup_eval(h, A[-u + i - 1], K) def dmp_eval_tail(f, A, u, K): """ Evaluate a polynomial at ``x_j = a_j, ...`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 2*x*y + 3*x + y + 2 >>> R.dmp_eval_tail(f, [2]) 7*x + 4 >>> R.dmp_eval_tail(f, [2, 2]) 18 """ if not A: return f if dmp_zero_p(f, u): return dmp_zero(u - len(A)) e = _rec_eval_tail(f, 0, A, u, K) if u == len(A) - 1: return e else: return dmp_strip(e, u - len(A)) def _rec_diff_eval(g, m, a, v, i, j, K): """Recursive helper for :func:`dmp_diff_eval`.""" if i == j: return dmp_eval(dmp_diff(g, m, v, K), a, v, K) v, i = v - 1, i + 1 return dmp_strip([ _rec_diff_eval(c, m, a, v, i, j, K) for c in g ], v) def dmp_diff_eval_in(f, m, a, j, u, K): """ Differentiate and evaluate a polynomial in ``x_j`` at ``a`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x*y**2 + 2*x*y + 3*x + 2*y**2 + 3*y + 1 >>> R.dmp_diff_eval_in(f, 1, 2, 0) y**2 + 2*y + 3 >>> R.dmp_diff_eval_in(f, 1, 2, 1) 6*x + 11 """ if j > u: raise IndexError("-%s <= j < %s expected, got %s" % (u, u, j)) if not j: return dmp_eval(dmp_diff(f, m, u, K), a, u, K) return _rec_diff_eval(f, m, a, u, 0, j, K) def dup_trunc(f, p, K): """ Reduce a ``K[x]`` polynomial modulo a constant ``p`` in ``K``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_trunc(2*x**3 + 3*x**2 + 5*x + 7, ZZ(3)) -x**3 - x + 1 """ if K.is_ZZ: g = [] for c in f: c = c % p if c > p // 2: g.append(c - p) else: g.append(c) else: g = [ c % p for c in f ] return dup_strip(g) def dmp_trunc(f, p, u, K): """ Reduce a ``K[X]`` polynomial modulo a polynomial ``p`` in ``K[Y]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 >>> g = (y - 1).drop(x) >>> R.dmp_trunc(f, g) 11*x**2 + 11*x + 5 """ return dmp_strip([ dmp_rem(c, p, u - 1, K) for c in f ], u) def dmp_ground_trunc(f, p, u, K): """ Reduce a ``K[X]`` polynomial modulo a constant ``p`` in ``K``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 >>> R.dmp_ground_trunc(f, ZZ(3)) -x**2 - x*y - y """ if not u: return dup_trunc(f, p, K) v = u - 1 return dmp_strip([ dmp_ground_trunc(c, p, v, K) for c in f ], u) def dup_monic(f, K): """ Divide all coefficients by ``LC(f)`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x = ring("x", ZZ) >>> R.dup_monic(3*x**2 + 6*x + 9) x**2 + 2*x + 3 >>> R, x = ring("x", QQ) >>> R.dup_monic(3*x**2 + 4*x + 2) x**2 + 4/3*x + 2/3 """ if not f: return f lc = dup_LC(f, K) if K.is_one(lc): return f else: return dup_exquo_ground(f, lc, K) def dmp_ground_monic(f, u, K): """ Divide all coefficients by ``LC(f)`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x,y = ring("x,y", ZZ) >>> f = 3*x**2*y + 6*x**2 + 3*x*y + 9*y + 3 >>> R.dmp_ground_monic(f) x**2*y + 2*x**2 + x*y + 3*y + 1 >>> R, x,y = ring("x,y", QQ) >>> f = 3*x**2*y + 8*x**2 + 5*x*y + 6*x + 2*y + 3 >>> R.dmp_ground_monic(f) x**2*y + 8/3*x**2 + 5/3*x*y + 2*x + 2/3*y + 1 """ if not u: return dup_monic(f, K) if dmp_zero_p(f, u): return f lc = dmp_ground_LC(f, u, K) if K.is_one(lc): return f else: return dmp_exquo_ground(f, lc, u, K) def dup_content(f, K): """ Compute the GCD of coefficients of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x = ring("x", ZZ) >>> f = 6*x**2 + 8*x + 12 >>> R.dup_content(f) 2 >>> R, x = ring("x", QQ) >>> f = 6*x**2 + 8*x + 12 >>> R.dup_content(f) 2 """ from sympy.polys.domains import QQ if not f: return K.zero cont = K.zero if K == QQ: for c in f: cont = K.gcd(cont, c) else: for c in f: cont = K.gcd(cont, c) if K.is_one(cont): break return cont def dmp_ground_content(f, u, K): """ Compute the GCD of coefficients of ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x,y = ring("x,y", ZZ) >>> f = 2*x*y + 6*x + 4*y + 12 >>> R.dmp_ground_content(f) 2 >>> R, x,y = ring("x,y", QQ) >>> f = 2*x*y + 6*x + 4*y + 12 >>> R.dmp_ground_content(f) 2 """ from sympy.polys.domains import QQ if not u: return dup_content(f, K) if dmp_zero_p(f, u): return K.zero cont, v = K.zero, u - 1 if K == QQ: for c in f: cont = K.gcd(cont, dmp_ground_content(c, v, K)) else: for c in f: cont = K.gcd(cont, dmp_ground_content(c, v, K)) if K.is_one(cont): break return cont def dup_primitive(f, K): """ Compute content and the primitive form of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x = ring("x", ZZ) >>> f = 6*x**2 + 8*x + 12 >>> R.dup_primitive(f) (2, 3*x**2 + 4*x + 6) >>> R, x = ring("x", QQ) >>> f = 6*x**2 + 8*x + 12 >>> R.dup_primitive(f) (2, 3*x**2 + 4*x + 6) """ if not f: return K.zero, f cont = dup_content(f, K) if K.is_one(cont): return cont, f else: return cont, dup_quo_ground(f, cont, K) def dmp_ground_primitive(f, u, K): """ Compute content and the primitive form of ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ, QQ >>> R, x,y = ring("x,y", ZZ) >>> f = 2*x*y + 6*x + 4*y + 12 >>> R.dmp_ground_primitive(f) (2, x*y + 3*x + 2*y + 6) >>> R, x,y = ring("x,y", QQ) >>> f = 2*x*y + 6*x + 4*y + 12 >>> R.dmp_ground_primitive(f) (2, x*y + 3*x + 2*y + 6) """ if not u: return dup_primitive(f, K) if dmp_zero_p(f, u): return K.zero, f cont = dmp_ground_content(f, u, K) if K.is_one(cont): return cont, f else: return cont, dmp_quo_ground(f, cont, u, K) def dup_extract(f, g, K): """ Extract common content from a pair of polynomials in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_extract(6*x**2 + 12*x + 18, 4*x**2 + 8*x + 12) (2, 3*x**2 + 6*x + 9, 2*x**2 + 4*x + 6) """ fc = dup_content(f, K) gc = dup_content(g, K) gcd = K.gcd(fc, gc) if not K.is_one(gcd): f = dup_quo_ground(f, gcd, K) g = dup_quo_ground(g, gcd, K) return gcd, f, g def dmp_ground_extract(f, g, u, K): """ Extract common content from a pair of polynomials in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_ground_extract(6*x*y + 12*x + 18, 4*x*y + 8*x + 12) (2, 3*x*y + 6*x + 9, 2*x*y + 4*x + 6) """ fc = dmp_ground_content(f, u, K) gc = dmp_ground_content(g, u, K) gcd = K.gcd(fc, gc) if not K.is_one(gcd): f = dmp_quo_ground(f, gcd, u, K) g = dmp_quo_ground(g, gcd, u, K) return gcd, f, g def dup_real_imag(f, K): """ Return bivariate polynomials ``f1`` and ``f2``, such that ``f = f1 + f2*I``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dup_real_imag(x**3 + x**2 + x + 1) (x**3 + x**2 - 3*x*y**2 + x - y**2 + 1, 3*x**2*y + 2*x*y - y**3 + y) """ if not K.is_ZZ and not K.is_QQ: raise DomainError("computing real and imaginary parts is not supported over %s" % K) f1 = dmp_zero(1) f2 = dmp_zero(1) if not f: return f1, f2 g = [[[K.one, K.zero]], [[K.one], []]] h = dmp_ground(f[0], 2) for c in f[1:]: h = dmp_mul(h, g, 2, K) h = dmp_add_term(h, dmp_ground(c, 1), 0, 2, K) H = dup_to_raw_dict(h) for k, h in H.items(): m = k % 4 if not m: f1 = dmp_add(f1, h, 1, K) elif m == 1: f2 = dmp_add(f2, h, 1, K) elif m == 2: f1 = dmp_sub(f1, h, 1, K) else: f2 = dmp_sub(f2, h, 1, K) return f1, f2 def dup_mirror(f, K): """ Evaluate efficiently the composition ``f(-x)`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_mirror(x**3 + 2*x**2 - 4*x + 2) -x**3 + 2*x**2 + 4*x + 2 """ f = list(f) for i in range(len(f) - 2, -1, -2): f[i] = -f[i] return f def dup_scale(f, a, K): """ Evaluate efficiently composition ``f(a*x)`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_scale(x**2 - 2*x + 1, ZZ(2)) 4*x**2 - 4*x + 1 """ f, n, b = list(f), len(f) - 1, a for i in range(n - 1, -1, -1): f[i], b = b*f[i], b*a return f def dup_shift(f, a, K): """ Evaluate efficiently Taylor shift ``f(x + a)`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_shift(x**2 - 2*x + 1, ZZ(2)) x**2 + 2*x + 1 """ f, n = list(f), len(f) - 1 for i in range(n, 0, -1): for j in range(0, i): f[j + 1] += a*f[j] return f def dup_transform(f, p, q, K): """ Evaluate functional transformation ``q**n * f(p/q)`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_transform(x**2 - 2*x + 1, x**2 + 1, x - 1) x**4 - 2*x**3 + 5*x**2 - 4*x + 4 """ if not f: return [] n = len(f) - 1 h, Q = [f[0]], [[K.one]] for i in range(0, n): Q.append(dup_mul(Q[-1], q, K)) for c, q in zip(f[1:], Q[1:]): h = dup_mul(h, p, K) q = dup_mul_ground(q, c, K) h = dup_add(h, q, K) return h def dup_compose(f, g, K): """ Evaluate functional composition ``f(g)`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_compose(x**2 + x, x - 1) x**2 - x """ if len(g) <= 1: return dup_strip([dup_eval(f, dup_LC(g, K), K)]) if not f: return [] h = [f[0]] for c in f[1:]: h = dup_mul(h, g, K) h = dup_add_term(h, c, 0, K) return h def dmp_compose(f, g, u, K): """ Evaluate functional composition ``f(g)`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_compose(x*y + 2*x + y, y) y**2 + 3*y """ if not u: return dup_compose(f, g, K) if dmp_zero_p(f, u): return f h = [f[0]] for c in f[1:]: h = dmp_mul(h, g, u, K) h = dmp_add_term(h, c, 0, u, K) return h def _dup_right_decompose(f, s, K): """Helper function for :func:`_dup_decompose`.""" n = len(f) - 1 lc = dup_LC(f, K) f = dup_to_raw_dict(f) g = { s: K.one } r = n // s for i in range(1, s): coeff = K.zero for j in range(0, i): if not n + j - i in f: continue if not s - j in g: continue fc, gc = f[n + j - i], g[s - j] coeff += (i - r*j)*fc*gc g[s - i] = K.quo(coeff, i*r*lc) return dup_from_raw_dict(g, K) def _dup_left_decompose(f, h, K): """Helper function for :func:`_dup_decompose`.""" g, i = {}, 0 while f: q, r = dup_div(f, h, K) if dup_degree(r) > 0: return None else: g[i] = dup_LC(r, K) f, i = q, i + 1 return dup_from_raw_dict(g, K) def _dup_decompose(f, K): """Helper function for :func:`dup_decompose`.""" df = len(f) - 1 for s in range(2, df): if df % s != 0: continue h = _dup_right_decompose(f, s, K) if h is not None: g = _dup_left_decompose(f, h, K) if g is not None: return g, h return None def dup_decompose(f, K): """ Computes functional decomposition of ``f`` in ``K[x]``. Given a univariate polynomial ``f`` with coefficients in a field of characteristic zero, returns list ``[f_1, f_2, ..., f_n]``, where:: f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) and ``f_2, ..., f_n`` are monic and homogeneous polynomials of at least second degree. Unlike factorization, complete functional decompositions of polynomials are not unique, consider examples: 1. ``f o g = f(x + b) o (g - b)`` 2. ``x**n o x**m = x**m o x**n`` 3. ``T_n o T_m = T_m o T_n`` where ``T_n`` and ``T_m`` are Chebyshev polynomials. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_decompose(x**4 - 2*x**3 + x**2) [x**2, x**2 - x] References ========== .. [1] [Kozen89]_ """ F = [] while True: result = _dup_decompose(f, K) if result is not None: f, h = result F = [h] + F else: break return [f] + F def dmp_lift(f, u, K): """ Convert algebraic coefficients to integers in ``K[X]``. Examples ======== >>> from sympy.polys import ring, QQ >>> from sympy import I >>> K = QQ.algebraic_field(I) >>> R, x = ring("x", K) >>> f = x**2 + K([QQ(1), QQ(0)])*x + K([QQ(2), QQ(0)]) >>> R.dmp_lift(f) x**8 + 2*x**6 + 9*x**4 - 8*x**2 + 16 """ if K.is_GaussianField: K1 = K.as_AlgebraicField() f = dmp_convert(f, u, K, K1) K = K1 if not K.is_Algebraic: raise DomainError( 'computation can be done only in an algebraic domain') F, monoms, polys = dmp_to_dict(f, u), [], [] for monom, coeff in F.items(): if not coeff.is_ground: monoms.append(monom) perms = variations([-1, 1], len(monoms), repetition=True) for perm in perms: G = dict(F) for sign, monom in zip(perm, monoms): if sign == -1: G[monom] = -G[monom] polys.append(dmp_from_dict(G, u, K)) return dmp_convert(dmp_expand(polys, u, K), u, K, K.dom) def dup_sign_variations(f, K): """ Compute the number of sign variations of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sign_variations(x**4 - x**2 - x + 1) 2 """ prev, k = K.zero, 0 for coeff in f: if K.is_negative(coeff*prev): k += 1 if coeff: prev = coeff return k def dup_clear_denoms(f, K0, K1=None, convert=False): """ Clear denominators, i.e. transform ``K_0`` to ``K_1``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = QQ(1,2)*x + QQ(1,3) >>> R.dup_clear_denoms(f, convert=False) (6, 3*x + 2) >>> R.dup_clear_denoms(f, convert=True) (6, 3*x + 2) """ if K1 is None: if K0.has_assoc_Ring: K1 = K0.get_ring() else: K1 = K0 common = K1.one for c in f: common = K1.lcm(common, K0.denom(c)) if not K1.is_one(common): f = dup_mul_ground(f, common, K0) if not convert: return common, f else: return common, dup_convert(f, K0, K1) def _rec_clear_denoms(g, v, K0, K1): """Recursive helper for :func:`dmp_clear_denoms`.""" common = K1.one if not v: for c in g: common = K1.lcm(common, K0.denom(c)) else: w = v - 1 for c in g: common = K1.lcm(common, _rec_clear_denoms(c, w, K0, K1)) return common def dmp_clear_denoms(f, u, K0, K1=None, convert=False): """ Clear denominators, i.e. transform ``K_0`` to ``K_1``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y = ring("x,y", QQ) >>> f = QQ(1,2)*x + QQ(1,3)*y + 1 >>> R.dmp_clear_denoms(f, convert=False) (6, 3*x + 2*y + 6) >>> R.dmp_clear_denoms(f, convert=True) (6, 3*x + 2*y + 6) """ if not u: return dup_clear_denoms(f, K0, K1, convert=convert) if K1 is None: if K0.has_assoc_Ring: K1 = K0.get_ring() else: K1 = K0 common = _rec_clear_denoms(f, u, K0, K1) if not K1.is_one(common): f = dmp_mul_ground(f, common, u, K0) if not convert: return common, f else: return common, dmp_convert(f, u, K0, K1) def dup_revert(f, n, K): """ Compute ``f**(-1)`` mod ``x**n`` using Newton iteration. This function computes first ``2**n`` terms of a polynomial that is a result of inversion of a polynomial modulo ``x**n``. This is useful to efficiently compute series expansion of ``1/f``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = -QQ(1,720)*x**6 + QQ(1,24)*x**4 - QQ(1,2)*x**2 + 1 >>> R.dup_revert(f, 8) 61/720*x**6 + 5/24*x**4 + 1/2*x**2 + 1 """ g = [K.revert(dup_TC(f, K))] h = [K.one, K.zero, K.zero] N = int(_ceil(_log(n, 2))) for i in range(1, N + 1): a = dup_mul_ground(g, K(2), K) b = dup_mul(f, dup_sqr(g, K), K) g = dup_rem(dup_sub(a, b, K), h, K) h = dup_lshift(h, dup_degree(h), K) return g def dmp_revert(f, g, u, K): """ Compute ``f**(-1)`` mod ``x**n`` using Newton iteration. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y = ring("x,y", QQ) """ if not u: return dup_revert(f, g, K) else: raise MultivariatePolynomialError(f, g) sympy-sympy-1.9/sympy/polys/dispersion.py000066400000000000000000000131541412543434000210070ustar00rootroot00000000000000from sympy.core import S from sympy.polys import Poly def dispersionset(p, q=None, *gens, **args): r"""Compute the *dispersion set* of two polynomials. For two polynomials `f(x)` and `g(x)` with `\deg f > 0` and `\deg g > 0` the dispersion set `\operatorname{J}(f, g)` is defined as: .. math:: \operatorname{J}(f, g) & := \{a \in \mathbb{N}_0 | \gcd(f(x), g(x+a)) \neq 1\} \\ & = \{a \in \mathbb{N}_0 | \deg \gcd(f(x), g(x+a)) \geq 1\} For a single polynomial one defines `\operatorname{J}(f) := \operatorname{J}(f, f)`. Examples ======== >>> from sympy import poly >>> from sympy.polys.dispersion import dispersion, dispersionset >>> from sympy.abc import x Dispersion set and dispersion of a simple polynomial: >>> fp = poly((x - 3)*(x + 3), x) >>> sorted(dispersionset(fp)) [0, 6] >>> dispersion(fp) 6 Note that the definition of the dispersion is not symmetric: >>> fp = poly(x**4 - 3*x**2 + 1, x) >>> gp = fp.shift(-3) >>> sorted(dispersionset(fp, gp)) [2, 3, 4] >>> dispersion(fp, gp) 4 >>> sorted(dispersionset(gp, fp)) [] >>> dispersion(gp, fp) -oo Computing the dispersion also works over field extensions: >>> from sympy import sqrt >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') >>> sorted(dispersionset(fp, gp)) [2] >>> sorted(dispersionset(gp, fp)) [1, 4] We can even perform the computations for polynomials having symbolic coefficients: >>> from sympy.abc import a >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) >>> sorted(dispersionset(fp)) [0, 1] See Also ======== dispersion References ========== .. [1] [ManWright94]_ .. [2] [Koepf98]_ .. [3] [Abramov71]_ .. [4] [Man93]_ """ # Check for valid input same = False if q is not None else True if same: q = p p = Poly(p, *gens, **args) q = Poly(q, *gens, **args) if not p.is_univariate or not q.is_univariate: raise ValueError("Polynomials need to be univariate") # The generator if not p.gen == q.gen: raise ValueError("Polynomials must have the same generator") gen = p.gen # We define the dispersion of constant polynomials to be zero if p.degree() < 1 or q.degree() < 1: return {0} # Factor p and q over the rationals fp = p.factor_list() fq = q.factor_list() if not same else fp # Iterate over all pairs of factors J = set() for s, unused in fp[1]: for t, unused in fq[1]: m = s.degree() n = t.degree() if n != m: continue an = s.LC() bn = t.LC() if not (an - bn).is_zero: continue # Note that the roles of `s` and `t` below are switched # w.r.t. the original paper. This is for consistency # with the description in the book of W. Koepf. anm1 = s.coeff_monomial(gen**(m-1)) bnm1 = t.coeff_monomial(gen**(n-1)) alpha = (anm1 - bnm1) / S(n*bn) if not alpha.is_integer: continue if alpha < 0 or alpha in J: continue if n > 1 and not (s - t.shift(alpha)).is_zero: continue J.add(alpha) return J def dispersion(p, q=None, *gens, **args): r"""Compute the *dispersion* of polynomials. For two polynomials `f(x)` and `g(x)` with `\deg f > 0` and `\deg g > 0` the dispersion `\operatorname{dis}(f, g)` is defined as: .. math:: \operatorname{dis}(f, g) & := \max\{ J(f,g) \cup \{0\} \} \\ & = \max\{ \{a \in \mathbb{N} | \gcd(f(x), g(x+a)) \neq 1\} \cup \{0\} \} and for a single polynomial `\operatorname{dis}(f) := \operatorname{dis}(f, f)`. Note that we make the definition `\max\{\} := -\infty`. Examples ======== >>> from sympy import poly >>> from sympy.polys.dispersion import dispersion, dispersionset >>> from sympy.abc import x Dispersion set and dispersion of a simple polynomial: >>> fp = poly((x - 3)*(x + 3), x) >>> sorted(dispersionset(fp)) [0, 6] >>> dispersion(fp) 6 Note that the definition of the dispersion is not symmetric: >>> fp = poly(x**4 - 3*x**2 + 1, x) >>> gp = fp.shift(-3) >>> sorted(dispersionset(fp, gp)) [2, 3, 4] >>> dispersion(fp, gp) 4 >>> sorted(dispersionset(gp, fp)) [] >>> dispersion(gp, fp) -oo The maximum of an empty set is defined to be `-\infty` as seen in this example. Computing the dispersion also works over field extensions: >>> from sympy import sqrt >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') >>> sorted(dispersionset(fp, gp)) [2] >>> sorted(dispersionset(gp, fp)) [1, 4] We can even perform the computations for polynomials having symbolic coefficients: >>> from sympy.abc import a >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) >>> sorted(dispersionset(fp)) [0, 1] See Also ======== dispersionset References ========== .. [1] [ManWright94]_ .. [2] [Koepf98]_ .. [3] [Abramov71]_ .. [4] [Man93]_ """ J = dispersionset(p, q, *gens, **args) if not J: # Definition for maximum of empty set j = S.NegativeInfinity else: j = max(J) return j sympy-sympy-1.9/sympy/polys/distributedmodules.py000066400000000000000000000524251412543434000225470ustar00rootroot00000000000000r""" Sparse distributed elements of free modules over multivariate (generalized) polynomial rings. This code and its data structures are very much like the distributed polynomials, except that the first "exponent" of the monomial is a module generator index. That is, the multi-exponent ``(i, e_1, ..., e_n)`` represents the "monomial" `x_1^{e_1} \cdots x_n^{e_n} f_i` of the free module `F` generated by `f_1, \ldots, f_r` over (a localization of) the ring `K[x_1, \ldots, x_n]`. A module element is simply stored as a list of terms ordered by the monomial order. Here a term is a pair of a multi-exponent and a coefficient. In general, this coefficient should never be zero (since it can then be omitted). The zero module element is stored as an empty list. The main routines are ``sdm_nf_mora`` and ``sdm_groebner`` which can be used to compute, respectively, weak normal forms and standard bases. They work with arbitrary (not necessarily global) monomial orders. In general, product orders have to be used to construct valid monomial orders for modules. However, ``lex`` can be used as-is. Note that the "level" (number of variables, i.e. parameter u+1 in distributedpolys.py) is never needed in this code. The main reference for this file is [SCA], "A Singular Introduction to Commutative Algebra". """ from itertools import permutations from sympy.polys.monomials import ( monomial_mul, monomial_lcm, monomial_div, monomial_deg ) from sympy.polys.polytools import Poly from sympy.polys.polyutils import parallel_dict_from_expr from sympy import S, sympify # Additional monomial tools. def sdm_monomial_mul(M, X): """ Multiply tuple ``X`` representing a monomial of `K[X]` into the tuple ``M`` representing a monomial of `F`. Examples ======== Multiplying `xy^3` into `x f_1` yields `x^2 y^3 f_1`: >>> from sympy.polys.distributedmodules import sdm_monomial_mul >>> sdm_monomial_mul((1, 1, 0), (1, 3)) (1, 2, 3) """ return (M[0],) + monomial_mul(X, M[1:]) def sdm_monomial_deg(M): """ Return the total degree of ``M``. Examples ======== For example, the total degree of `x^2 y f_5` is 3: >>> from sympy.polys.distributedmodules import sdm_monomial_deg >>> sdm_monomial_deg((5, 2, 1)) 3 """ return monomial_deg(M[1:]) def sdm_monomial_lcm(A, B): r""" Return the "least common multiple" of ``A`` and ``B``. IF `A = M e_j` and `B = N e_j`, where `M` and `N` are polynomial monomials, this returns `\lcm(M, N) e_j`. Note that ``A`` and ``B`` involve distinct monomials. Otherwise the result is undefined. Examples ======== >>> from sympy.polys.distributedmodules import sdm_monomial_lcm >>> sdm_monomial_lcm((1, 2, 3), (1, 0, 5)) (1, 2, 5) """ return (A[0],) + monomial_lcm(A[1:], B[1:]) def sdm_monomial_divides(A, B): """ Does there exist a (polynomial) monomial X such that XA = B? Examples ======== Positive examples: In the following examples, the monomial is given in terms of x, y and the generator(s), f_1, f_2 etc. The tuple form of that monomial is used in the call to sdm_monomial_divides. Note: the generator appears last in the expression but first in the tuple and other factors appear in the same order that they appear in the monomial expression. `A = f_1` divides `B = f_1` >>> from sympy.polys.distributedmodules import sdm_monomial_divides >>> sdm_monomial_divides((1, 0, 0), (1, 0, 0)) True `A = f_1` divides `B = x^2 y f_1` >>> sdm_monomial_divides((1, 0, 0), (1, 2, 1)) True `A = xy f_5` divides `B = x^2 y f_5` >>> sdm_monomial_divides((5, 1, 1), (5, 2, 1)) True Negative examples: `A = f_1` does not divide `B = f_2` >>> sdm_monomial_divides((1, 0, 0), (2, 0, 0)) False `A = x f_1` does not divide `B = f_1` >>> sdm_monomial_divides((1, 1, 0), (1, 0, 0)) False `A = xy^2 f_5` does not divide `B = y f_5` >>> sdm_monomial_divides((5, 1, 2), (5, 0, 1)) False """ return A[0] == B[0] and all(a <= b for a, b in zip(A[1:], B[1:])) # The actual distributed modules code. def sdm_LC(f, K): """Returns the leading coeffcient of ``f``. """ if not f: return K.zero else: return f[0][1] def sdm_to_dict(f): """Make a dictionary from a distributed polynomial. """ return dict(f) def sdm_from_dict(d, O): """ Create an sdm from a dictionary. Here ``O`` is the monomial order to use. Examples ======== >>> from sympy.polys.distributedmodules import sdm_from_dict >>> from sympy.polys import QQ, lex >>> dic = {(1, 1, 0): QQ(1), (1, 0, 0): QQ(2), (0, 1, 0): QQ(0)} >>> sdm_from_dict(dic, lex) [((1, 1, 0), 1), ((1, 0, 0), 2)] """ return sdm_strip(sdm_sort(list(d.items()), O)) def sdm_sort(f, O): """Sort terms in ``f`` using the given monomial order ``O``. """ return sorted(f, key=lambda term: O(term[0]), reverse=True) def sdm_strip(f): """Remove terms with zero coefficients from ``f`` in ``K[X]``. """ return [ (monom, coeff) for monom, coeff in f if coeff ] def sdm_add(f, g, O, K): """ Add two module elements ``f``, ``g``. Addition is done over the ground field ``K``, monomials are ordered according to ``O``. Examples ======== All examples use lexicographic order. `(xy f_1) + (f_2) = f_2 + xy f_1` >>> from sympy.polys.distributedmodules import sdm_add >>> from sympy.polys import lex, QQ >>> sdm_add([((1, 1, 1), QQ(1))], [((2, 0, 0), QQ(1))], lex, QQ) [((2, 0, 0), 1), ((1, 1, 1), 1)] `(xy f_1) + (-xy f_1)` = 0` >>> sdm_add([((1, 1, 1), QQ(1))], [((1, 1, 1), QQ(-1))], lex, QQ) [] `(f_1) + (2f_1) = 3f_1` >>> sdm_add([((1, 0, 0), QQ(1))], [((1, 0, 0), QQ(2))], lex, QQ) [((1, 0, 0), 3)] `(yf_1) + (xf_1) = xf_1 + yf_1` >>> sdm_add([((1, 0, 1), QQ(1))], [((1, 1, 0), QQ(1))], lex, QQ) [((1, 1, 0), 1), ((1, 0, 1), 1)] """ h = dict(f) for monom, c in g: if monom in h: coeff = h[monom] + c if not coeff: del h[monom] else: h[monom] = coeff else: h[monom] = c return sdm_from_dict(h, O) def sdm_LM(f): r""" Returns the leading monomial of ``f``. Only valid if `f \ne 0`. Examples ======== >>> from sympy.polys.distributedmodules import sdm_LM, sdm_from_dict >>> from sympy.polys import QQ, lex >>> dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(1), (4, 0, 1): QQ(1)} >>> sdm_LM(sdm_from_dict(dic, lex)) (4, 0, 1) """ return f[0][0] def sdm_LT(f): r""" Returns the leading term of ``f``. Only valid if `f \ne 0`. Examples ======== >>> from sympy.polys.distributedmodules import sdm_LT, sdm_from_dict >>> from sympy.polys import QQ, lex >>> dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(2), (4, 0, 1): QQ(3)} >>> sdm_LT(sdm_from_dict(dic, lex)) ((4, 0, 1), 3) """ return f[0] def sdm_mul_term(f, term, O, K): """ Multiply a distributed module element ``f`` by a (polynomial) term ``term``. Multiplication of coefficients is done over the ground field ``K``, and monomials are ordered according to ``O``. Examples ======== `0 f_1 = 0` >>> from sympy.polys.distributedmodules import sdm_mul_term >>> from sympy.polys import lex, QQ >>> sdm_mul_term([((1, 0, 0), QQ(1))], ((0, 0), QQ(0)), lex, QQ) [] `x 0 = 0` >>> sdm_mul_term([], ((1, 0), QQ(1)), lex, QQ) [] `(x) (f_1) = xf_1` >>> sdm_mul_term([((1, 0, 0), QQ(1))], ((1, 0), QQ(1)), lex, QQ) [((1, 1, 0), 1)] `(2xy) (3x f_1 + 4y f_2) = 8xy^2 f_2 + 6x^2y f_1` >>> f = [((2, 0, 1), QQ(4)), ((1, 1, 0), QQ(3))] >>> sdm_mul_term(f, ((1, 1), QQ(2)), lex, QQ) [((2, 1, 2), 8), ((1, 2, 1), 6)] """ X, c = term if not f or not c: return [] else: if K.is_one(c): return [ (sdm_monomial_mul(f_M, X), f_c) for f_M, f_c in f ] else: return [ (sdm_monomial_mul(f_M, X), f_c * c) for f_M, f_c in f ] def sdm_zero(): """Return the zero module element.""" return [] def sdm_deg(f): """ Degree of ``f``. This is the maximum of the degrees of all its monomials. Invalid if ``f`` is zero. Examples ======== >>> from sympy.polys.distributedmodules import sdm_deg >>> sdm_deg([((1, 2, 3), 1), ((10, 0, 1), 1), ((2, 3, 4), 4)]) 7 """ return max(sdm_monomial_deg(M[0]) for M in f) # Conversion def sdm_from_vector(vec, O, K, **opts): """ Create an sdm from an iterable of expressions. Coefficients are created in the ground field ``K``, and terms are ordered according to monomial order ``O``. Named arguments are passed on to the polys conversion code and can be used to specify for example generators. Examples ======== >>> from sympy.polys.distributedmodules import sdm_from_vector >>> from sympy.abc import x, y, z >>> from sympy.polys import QQ, lex >>> sdm_from_vector([x**2+y**2, 2*z], lex, QQ) [((1, 0, 0, 1), 2), ((0, 2, 0, 0), 1), ((0, 0, 2, 0), 1)] """ dics, gens = parallel_dict_from_expr(sympify(vec), **opts) dic = {} for i, d in enumerate(dics): for k, v in d.items(): dic[(i,) + k] = K.convert(v) return sdm_from_dict(dic, O) def sdm_to_vector(f, gens, K, n=None): """ Convert sdm ``f`` into a list of polynomial expressions. The generators for the polynomial ring are specified via ``gens``. The rank of the module is guessed, or passed via ``n``. The ground field is assumed to be ``K``. Examples ======== >>> from sympy.polys.distributedmodules import sdm_to_vector >>> from sympy.abc import x, y, z >>> from sympy.polys import QQ >>> f = [((1, 0, 0, 1), QQ(2)), ((0, 2, 0, 0), QQ(1)), ((0, 0, 2, 0), QQ(1))] >>> sdm_to_vector(f, [x, y, z], QQ) [x**2 + y**2, 2*z] """ dic = sdm_to_dict(f) dics = {} for k, v in dic.items(): dics.setdefault(k[0], []).append((k[1:], v)) n = n or len(dics) res = [] for k in range(n): if k in dics: res.append(Poly(dict(dics[k]), gens=gens, domain=K).as_expr()) else: res.append(S.Zero) return res # Algorithms. def sdm_spoly(f, g, O, K, phantom=None): """ Compute the generalized s-polynomial of ``f`` and ``g``. The ground field is assumed to be ``K``, and monomials ordered according to ``O``. This is invalid if either of ``f`` or ``g`` is zero. If the leading terms of `f` and `g` involve different basis elements of `F`, their s-poly is defined to be zero. Otherwise it is a certain linear combination of `f` and `g` in which the leading terms cancel. See [SCA, defn 2.3.6] for details. If ``phantom`` is not ``None``, it should be a pair of module elements on which to perform the same operation(s) as on ``f`` and ``g``. The in this case both results are returned. Examples ======== >>> from sympy.polys.distributedmodules import sdm_spoly >>> from sympy.polys import QQ, lex >>> f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))] >>> g = [((2, 3, 0), QQ(1))] >>> h = [((1, 2, 3), QQ(1))] >>> sdm_spoly(f, h, lex, QQ) [] >>> sdm_spoly(f, g, lex, QQ) [((1, 2, 1), 1)] """ if not f or not g: return sdm_zero() LM1 = sdm_LM(f) LM2 = sdm_LM(g) if LM1[0] != LM2[0]: return sdm_zero() LM1 = LM1[1:] LM2 = LM2[1:] lcm = monomial_lcm(LM1, LM2) m1 = monomial_div(lcm, LM1) m2 = monomial_div(lcm, LM2) c = K.quo(-sdm_LC(f, K), sdm_LC(g, K)) r1 = sdm_add(sdm_mul_term(f, (m1, K.one), O, K), sdm_mul_term(g, (m2, c), O, K), O, K) if phantom is None: return r1 r2 = sdm_add(sdm_mul_term(phantom[0], (m1, K.one), O, K), sdm_mul_term(phantom[1], (m2, c), O, K), O, K) return r1, r2 def sdm_ecart(f): """ Compute the ecart of ``f``. This is defined to be the difference of the total degree of `f` and the total degree of the leading monomial of `f` [SCA, defn 2.3.7]. Invalid if f is zero. Examples ======== >>> from sympy.polys.distributedmodules import sdm_ecart >>> sdm_ecart([((1, 2, 3), 1), ((1, 0, 1), 1)]) 0 >>> sdm_ecart([((2, 2, 1), 1), ((1, 5, 1), 1)]) 3 """ return sdm_deg(f) - sdm_monomial_deg(sdm_LM(f)) def sdm_nf_mora(f, G, O, K, phantom=None): r""" Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. The ground field is assumed to be ``K``, and monomials ordered according to ``O``. Weak normal forms are defined in [SCA, defn 2.3.3]. They are not unique. This function deterministically computes a weak normal form, depending on the order of `G`. The most important property of a weak normal form is the following: if `R` is the ring associated with the monomial ordering (if the ordering is global, we just have `R = K[x_1, \ldots, x_n]`, otherwise it is a certain localization thereof), `I` any ideal of `R` and `G` a standard basis for `I`, then for any `f \in R`, we have `f \in I` if and only if `NF(f | G) = 0`. This is the generalized Mora algorithm for computing weak normal forms with respect to arbitrary monomial orders [SCA, algorithm 2.3.9]. If ``phantom`` is not ``None``, it should be a pair of "phantom" arguments on which to perform the same computations as on ``f``, ``G``, both results are then returned. """ from itertools import repeat h = f T = list(G) if phantom is not None: # "phantom" variables with suffix p hp = phantom[0] Tp = list(phantom[1]) phantom = True else: Tp = repeat([]) phantom = False while h: # TODO better data structure!!! Th = [(g, sdm_ecart(g), gp) for g, gp in zip(T, Tp) if sdm_monomial_divides(sdm_LM(g), sdm_LM(h))] if not Th: break g, _, gp = min(Th, key=lambda x: x[1]) if sdm_ecart(g) > sdm_ecart(h): T.append(h) if phantom: Tp.append(hp) if phantom: h, hp = sdm_spoly(h, g, O, K, phantom=(hp, gp)) else: h = sdm_spoly(h, g, O, K) if phantom: return h, hp return h def sdm_nf_buchberger(f, G, O, K, phantom=None): r""" Compute a weak normal form of ``f`` with respect to ``G`` and order ``O``. The ground field is assumed to be ``K``, and monomials ordered according to ``O``. This is the standard Buchberger algorithm for computing weak normal forms with respect to *global* monomial orders [SCA, algorithm 1.6.10]. If ``phantom`` is not ``None``, it should be a pair of "phantom" arguments on which to perform the same computations as on ``f``, ``G``, both results are then returned. """ from itertools import repeat h = f T = list(G) if phantom is not None: # "phantom" variables with suffix p hp = phantom[0] Tp = list(phantom[1]) phantom = True else: Tp = repeat([]) phantom = False while h: try: g, gp = next((g, gp) for g, gp in zip(T, Tp) if sdm_monomial_divides(sdm_LM(g), sdm_LM(h))) except StopIteration: break if phantom: h, hp = sdm_spoly(h, g, O, K, phantom=(hp, gp)) else: h = sdm_spoly(h, g, O, K) if phantom: return h, hp return h def sdm_nf_buchberger_reduced(f, G, O, K): r""" Compute a reduced normal form of ``f`` with respect to ``G`` and order ``O``. The ground field is assumed to be ``K``, and monomials ordered according to ``O``. In contrast to weak normal forms, reduced normal forms *are* unique, but their computation is more expensive. This is the standard Buchberger algorithm for computing reduced normal forms with respect to *global* monomial orders [SCA, algorithm 1.6.11]. The ``pantom`` option is not supported, so this normal form cannot be used as a normal form for the "extended" groebner algorithm. """ h = sdm_zero() g = f while g: g = sdm_nf_buchberger(g, G, O, K) if g: h = sdm_add(h, [sdm_LT(g)], O, K) g = g[1:] return h def sdm_groebner(G, NF, O, K, extended=False): """ Compute a minimal standard basis of ``G`` with respect to order ``O``. The algorithm uses a normal form ``NF``, for example ``sdm_nf_mora``. The ground field is assumed to be ``K``, and monomials ordered according to ``O``. Let `N` denote the submodule generated by elements of `G`. A standard basis for `N` is a subset `S` of `N`, such that `in(S) = in(N)`, where for any subset `X` of `F`, `in(X)` denotes the submodule generated by the initial forms of elements of `X`. [SCA, defn 2.3.2] A standard basis is called minimal if no subset of it is a standard basis. One may show that standard bases are always generating sets. Minimal standard bases are not unique. This algorithm computes a deterministic result, depending on the particular order of `G`. If ``extended=True``, also compute the transition matrix from the initial generators to the groebner basis. That is, return a list of coefficient vectors, expressing the elements of the groebner basis in terms of the elements of ``G``. This functions implements the "sugar" strategy, see Giovini et al: "One sugar cube, please" OR Selection strategies in Buchberger algorithm. """ # The critical pair set. # A critical pair is stored as (i, j, s, t) where (i, j) defines the pair # (by indexing S), s is the sugar of the pair, and t is the lcm of their # leading monomials. P = [] # The eventual standard basis. S = [] Sugars = [] def Ssugar(i, j): """Compute the sugar of the S-poly corresponding to (i, j).""" LMi = sdm_LM(S[i]) LMj = sdm_LM(S[j]) return max(Sugars[i] - sdm_monomial_deg(LMi), Sugars[j] - sdm_monomial_deg(LMj)) \ + sdm_monomial_deg(sdm_monomial_lcm(LMi, LMj)) ourkey = lambda p: (p[2], O(p[3]), p[1]) def update(f, sugar, P): """Add f with sugar ``sugar`` to S, update P.""" if not f: return P k = len(S) S.append(f) Sugars.append(sugar) LMf = sdm_LM(f) def removethis(pair): i, j, s, t = pair if LMf[0] != t[0]: return False tik = sdm_monomial_lcm(LMf, sdm_LM(S[i])) tjk = sdm_monomial_lcm(LMf, sdm_LM(S[j])) return tik != t and tjk != t and sdm_monomial_divides(tik, t) and \ sdm_monomial_divides(tjk, t) # apply the chain criterion P = [p for p in P if not removethis(p)] # new-pair set N = [(i, k, Ssugar(i, k), sdm_monomial_lcm(LMf, sdm_LM(S[i]))) for i in range(k) if LMf[0] == sdm_LM(S[i])[0]] # TODO apply the product criterion? N.sort(key=ourkey) remove = set() for i, p in enumerate(N): for j in range(i + 1, len(N)): if sdm_monomial_divides(p[3], N[j][3]): remove.add(j) # TODO mergesort? P.extend(reversed([p for i, p in enumerate(N) if not i in remove])) P.sort(key=ourkey, reverse=True) # NOTE reverse-sort, because we want to pop from the end return P # Figure out the number of generators in the ground ring. try: # NOTE: we look for the first non-zero vector, take its first monomial # the number of generators in the ring is one less than the length # (since the zeroth entry is for the module generators) numgens = len(next(x[0] for x in G if x)[0]) - 1 except StopIteration: # No non-zero elements in G ... if extended: return [], [] return [] # This list will store expressions of the elements of S in terms of the # initial generators coefficients = [] # First add all the elements of G to S for i, f in enumerate(G): P = update(f, sdm_deg(f), P) if extended and f: coefficients.append(sdm_from_dict({(i,) + (0,)*numgens: K(1)}, O)) # Now carry out the buchberger algorithm. while P: i, j, s, t = P.pop() f, g = S[i], S[j] if extended: sp, coeff = sdm_spoly(f, g, O, K, phantom=(coefficients[i], coefficients[j])) h, hcoeff = NF(sp, S, O, K, phantom=(coeff, coefficients)) if h: coefficients.append(hcoeff) else: h = NF(sdm_spoly(f, g, O, K), S, O, K) P = update(h, Ssugar(i, j), P) # Finally interreduce the standard basis. # (TODO again, better data structures) S = {(tuple(f), i) for i, f in enumerate(S)} for (a, ai), (b, bi) in permutations(S, 2): A = sdm_LM(a) B = sdm_LM(b) if sdm_monomial_divides(A, B) and (b, bi) in S and (a, ai) in S: S.remove((b, bi)) L = sorted(((list(f), i) for f, i in S), key=lambda p: O(sdm_LM(p[0])), reverse=True) res = [x[0] for x in L] if extended: return res, [coefficients[i] for _, i in L] return res sympy-sympy-1.9/sympy/polys/domainmatrix.py000066400000000000000000000004661412543434000213260ustar00rootroot00000000000000""" Stub module to expose DomainMatrix which has now moved to sympy.polys.matrices package. It should now be imported as: >>> from sympy.polys.matrices import DomainMatrix This module might be removed in future. """ from sympy.polys.matrices.domainmatrix import DomainMatrix __all__ = ['DomainMatrix'] sympy-sympy-1.9/sympy/polys/domains/000077500000000000000000000000001412543434000177045ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/domains/__init__.py000066400000000000000000000035211412543434000220160ustar00rootroot00000000000000"""Implementation of mathematical domains. """ __all__ = [ 'Domain', 'FiniteField', 'IntegerRing', 'RationalField', 'RealField', 'ComplexField', 'AlgebraicField', 'PolynomialRing', 'FractionField', 'ExpressionDomain', 'PythonRational', 'GF', 'FF', 'ZZ', 'QQ', 'ZZ_I', 'QQ_I', 'RR', 'CC', 'EX', 'EXRAW', ] from .domain import Domain from .finitefield import FiniteField, FF, GF from .integerring import IntegerRing, ZZ from .rationalfield import RationalField, QQ from .algebraicfield import AlgebraicField from .gaussiandomains import ZZ_I, QQ_I from .realfield import RealField, RR from .complexfield import ComplexField, CC from .polynomialring import PolynomialRing from .fractionfield import FractionField from .expressiondomain import ExpressionDomain, EX from .expressionrawdomain import EXRAW from .pythonrational import PythonRational # This is imported purely for backwards compatibility because some parts of # the codebase used to import this from here and it's possible that downstream # does as well: from sympy.external.gmpy import GROUND_TYPES # noqa: F401 # # The rest of these are obsolete and provided only for backwards # compatibility: # from .pythonfinitefield import PythonFiniteField from .gmpyfinitefield import GMPYFiniteField from .pythonintegerring import PythonIntegerRing from .gmpyintegerring import GMPYIntegerRing from .pythonrationalfield import PythonRationalField from .gmpyrationalfield import GMPYRationalField FF_python = PythonFiniteField FF_gmpy = GMPYFiniteField ZZ_python = PythonIntegerRing ZZ_gmpy = GMPYIntegerRing QQ_python = PythonRationalField QQ_gmpy = GMPYRationalField __all__.extend([ 'PythonFiniteField', 'GMPYFiniteField', 'PythonIntegerRing', 'GMPYIntegerRing', 'PythonRational', 'GMPYRationalField', 'FF_python', 'FF_gmpy', 'ZZ_python', 'ZZ_gmpy', 'QQ_python', 'QQ_gmpy', ]) sympy-sympy-1.9/sympy/polys/domains/algebraicfield.py000066400000000000000000000345731412543434000232070ustar00rootroot00000000000000"""Implementation of :class:`AlgebraicField` class. """ from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.field import Field from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.polyclasses import ANP from sympy.polys.polyerrors import CoercionFailed, DomainError, NotAlgebraic, IsomorphismFailed from sympy.utilities import public @public class AlgebraicField(Field, CharacteristicZero, SimpleDomain): r"""Algebraic number field :ref:`QQ(a)` A :ref:`QQ(a)` domain represents an `algebraic number field`_ `\mathbb{Q}(a)` as a :py:class:`~.Domain` in the domain system (see :ref:`polys-domainsintro`). A :py:class:`~.Poly` created from an expression involving `algebraic numbers`_ will treat the algebraic numbers as generators if the generators argument is not specified. >>> from sympy import Poly, Symbol, sqrt >>> x = Symbol('x') >>> Poly(x**2 + sqrt(2)) Poly(x**2 + (sqrt(2)), x, sqrt(2), domain='ZZ') That is a multivariate polynomial with ``sqrt(2)`` treated as one of the generators (variables). If the generators are explicitly specified then ``sqrt(2)`` will be considered to be a coefficient but by default the :ref:`EX` domain is used. To make a :py:class:`~.Poly` with a :ref:`QQ(a)` domain the argument ``extension=True`` can be given. >>> Poly(x**2 + sqrt(2), x) Poly(x**2 + sqrt(2), x, domain='EX') >>> Poly(x**2 + sqrt(2), x, extension=True) Poly(x**2 + sqrt(2), x, domain='QQ') A generator of the algebraic field extension can also be specified explicitly which is particularly useful if the coefficients are all rational but an extension field is needed (e.g. to factor the polynomial). >>> Poly(x**2 + 1) Poly(x**2 + 1, x, domain='ZZ') >>> Poly(x**2 + 1, extension=sqrt(2)) Poly(x**2 + 1, x, domain='QQ') It is possible to factorise a polynomial over a :ref:`QQ(a)` domain using the ``extension`` argument to :py:func:`~.factor` or by specifying the domain explicitly. >>> from sympy import factor, QQ >>> factor(x**2 - 2) x**2 - 2 >>> factor(x**2 - 2, extension=sqrt(2)) (x - sqrt(2))*(x + sqrt(2)) >>> factor(x**2 - 2, domain='QQ') (x - sqrt(2))*(x + sqrt(2)) >>> factor(x**2 - 2, domain=QQ.algebraic_field(sqrt(2))) (x - sqrt(2))*(x + sqrt(2)) The ``extension=True`` argument can be used but will only create an extension that contains the coefficients which is usually not enough to factorise the polynomial. >>> p = x**3 + sqrt(2)*x**2 - 2*x - 2*sqrt(2) >>> factor(p) # treats sqrt(2) as a symbol (x + sqrt(2))*(x**2 - 2) >>> factor(p, extension=True) (x - sqrt(2))*(x + sqrt(2))**2 >>> factor(x**2 - 2, extension=True) # all rational coefficients x**2 - 2 It is also possible to use :ref:`QQ(a)` with the :py:func:`~.cancel` and :py:func:`~.gcd` functions. >>> from sympy import cancel, gcd >>> cancel((x**2 - 2)/(x - sqrt(2))) (x**2 - 2)/(x - sqrt(2)) >>> cancel((x**2 - 2)/(x - sqrt(2)), extension=sqrt(2)) x + sqrt(2) >>> gcd(x**2 - 2, x - sqrt(2)) 1 >>> gcd(x**2 - 2, x - sqrt(2), extension=sqrt(2)) x - sqrt(2) When using the domain directly :ref:`QQ(a)` can be used as a constructor to create instances which then support the operations ``+,-,*,**,/``. The :py:meth:`~.Domain.algebraic_field` method is used to construct a particular :ref:`QQ(a)` domain. The :py:meth:`~.Domain.from_sympy` method can be used to create domain elements from normal sympy expressions. >>> K = QQ.algebraic_field(sqrt(2)) >>> K QQ >>> xk = K.from_sympy(3 + 4*sqrt(2)) >>> xk # doctest: +SKIP ANP([4, 3], [1, 0, -2], QQ) Elements of :ref:`QQ(a)` are instances of :py:class:`~.ANP` which have limited printing support. The raw display shows the internal representation of the element as the list ``[4, 3]`` representing the coefficients of ``1`` and ``sqrt(2)`` for this element in the form ``a * sqrt(2) + b * 1`` where ``a`` and ``b`` are elements of :ref:`QQ`. The minimal polynomial for the generator ``(x**2 - 2)`` is also shown in the :ref:`dup-representation` as the list ``[1, 0, -2]``. We can use :py:meth:`~.Domain.to_sympy` to get a better printed form for the elements and to see the results of operations. >>> xk = K.from_sympy(3 + 4*sqrt(2)) >>> yk = K.from_sympy(2 + 3*sqrt(2)) >>> xk * yk # doctest: +SKIP ANP([17, 30], [1, 0, -2], QQ) >>> K.to_sympy(xk * yk) 17*sqrt(2) + 30 >>> K.to_sympy(xk + yk) 5 + 7*sqrt(2) >>> K.to_sympy(xk ** 2) 24*sqrt(2) + 41 >>> K.to_sympy(xk / yk) sqrt(2)/14 + 9/7 Any expression representing an algebraic number can be used to generate a :ref:`QQ(a)` domain provided its `minimal polynomial`_ can be computed. The function :py:func:`~.minpoly` function is used for this. >>> from sympy import exp, I, pi, minpoly >>> g = exp(2*I*pi/3) >>> g exp(2*I*pi/3) >>> g.is_algebraic True >>> minpoly(g, x) x**2 + x + 1 >>> factor(x**3 - 1, extension=g) (x - 1)*(x - exp(2*I*pi/3))*(x + 1 + exp(2*I*pi/3)) It is also possible to make an algebraic field from multiple extension elements. >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) >>> K QQ >>> p = x**4 - 5*x**2 + 6 >>> factor(p) (x**2 - 3)*(x**2 - 2) >>> factor(p, domain=K) (x - sqrt(2))*(x + sqrt(2))*(x - sqrt(3))*(x + sqrt(3)) >>> factor(p, extension=[sqrt(2), sqrt(3)]) (x - sqrt(2))*(x + sqrt(2))*(x - sqrt(3))*(x + sqrt(3)) Multiple extension elements are always combined together to make a single `primitive element`_. In the case of ``[sqrt(2), sqrt(3)]`` the primitive element chosen is ``sqrt(2) + sqrt(3)`` which is why the domain displays as ``QQ``. The minimal polynomial for the primitive element is computed using the :py:func:`~.primitive_element` function. >>> from sympy import primitive_element >>> primitive_element([sqrt(2), sqrt(3)], x) (x**4 - 10*x**2 + 1, [1, 1]) >>> minpoly(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 The extension elements that generate the domain can be accessed from the domain using the :py:attr:`~.ext` and :py:attr:`~.orig_ext` attributes as instances of :py:class:`~.AlgebraicNumber`. The minimal polynomial for the primitive element as a :py:class:`~.DMP` instance is available as :py:attr:`~.mod`. >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) >>> K QQ >>> K.ext sqrt(2) + sqrt(3) >>> K.orig_ext (sqrt(2), sqrt(3)) >>> K.mod DMP([1, 0, -10, 0, 1], QQ, None) Notes ===== It is not currently possible to generate an algebraic extension over any domain other than :ref:`QQ`. Ideally it would be possible to generate extensions like ``QQ(x)(sqrt(x**2 - 2))``. This is equivalent to the quotient ring ``QQ(x)[y]/(y**2 - x**2 + 2)`` and there are two implementations of this kind of quotient ring/extension in the :py:class:`~.QuotientRing` and :py:class:`~.MonogenicFiniteExtension` classes. Each of those implementations needs some work to make them fully usable though. .. _algebraic number field: https://en.wikipedia.org/wiki/Algebraic_number_field .. _algebraic numbers: https://en.wikipedia.org/wiki/Algebraic_number .. _minimal polynomial: https://en.wikipedia.org/wiki/Minimal_polynomial_(field_theory) .. _primitive element: https://en.wikipedia.org/wiki/Primitive_element_theorem """ dtype = ANP is_AlgebraicField = is_Algebraic = True is_Numerical = True has_assoc_Ring = False has_assoc_Field = True def __init__(self, dom, *ext): if not dom.is_QQ: raise DomainError("ground domain must be a rational field") from sympy.polys.numberfields import to_number_field if len(ext) == 1 and isinstance(ext[0], tuple): orig_ext = ext[0][1:] else: orig_ext = ext self.orig_ext = orig_ext """ Original elements given to generate the extension. >>> from sympy import QQ, sqrt >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) >>> K.orig_ext (sqrt(2), sqrt(3)) """ self.ext = to_number_field(ext) """ Primitive element used for the extension. >>> from sympy import QQ, sqrt >>> K = QQ.algebraic_field(sqrt(2), sqrt(3)) >>> K.ext sqrt(2) + sqrt(3) """ self.mod = self.ext.minpoly.rep """ Minimal polynomial for the primitive element of the extension. >>> from sympy import QQ, sqrt >>> K = QQ.algebraic_field(sqrt(2)) >>> K.mod DMP([1, 0, -2], QQ, None) """ self.domain = self.dom = dom self.ngens = 1 self.symbols = self.gens = (self.ext,) self.unit = self([dom(1), dom(0)]) self.zero = self.dtype.zero(self.mod.rep, dom) self.one = self.dtype.one(self.mod.rep, dom) def new(self, element): return self.dtype(element, self.mod.rep, self.dom) def __str__(self): return str(self.dom) + '<' + str(self.ext) + '>' def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.dom, self.ext)) def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ return isinstance(other, AlgebraicField) and \ self.dtype == other.dtype and self.ext == other.ext def algebraic_field(self, *extension): r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`. """ return AlgebraicField(self.dom, *((self.ext,) + extension)) def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ # Precompute a converter to be reused: if not hasattr(self, '_converter'): self._converter = _make_converter(self) return self._converter(a) def from_sympy(self, a): """Convert SymPy's expression to ``dtype``. """ try: return self([self.dom.from_sympy(a)]) except CoercionFailed: pass from sympy.polys.numberfields import to_number_field try: return self(to_number_field(a, self.ext).native_coeffs()) except (NotAlgebraic, IsomorphismFailed): raise CoercionFailed( "%s is not a valid algebraic number in %s" % (a, self)) def from_ZZ(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_RealField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def get_ring(self): """Returns a ring associated with ``self``. """ raise DomainError('there is no ring associated with %s' % self) def is_positive(self, a): """Returns True if ``a`` is positive. """ return self.dom.is_positive(a.LC()) def is_negative(self, a): """Returns True if ``a`` is negative. """ return self.dom.is_negative(a.LC()) def is_nonpositive(self, a): """Returns True if ``a`` is non-positive. """ return self.dom.is_nonpositive(a.LC()) def is_nonnegative(self, a): """Returns True if ``a`` is non-negative. """ return self.dom.is_nonnegative(a.LC()) def numer(self, a): """Returns numerator of ``a``. """ return a def denom(self, a): """Returns denominator of ``a``. """ return self.one def from_AlgebraicField(K1, a, K0): """Convert AlgebraicField element 'a' to another AlgebraicField """ return K1.from_sympy(K0.to_sympy(a)) def from_GaussianIntegerRing(K1, a, K0): """Convert a GaussianInteger element 'a' to ``dtype``. """ return K1.from_sympy(K0.to_sympy(a)) def from_GaussianRationalField(K1, a, K0): """Convert a GaussianRational element 'a' to ``dtype``. """ return K1.from_sympy(K0.to_sympy(a)) def _make_converter(K): """Construct the converter to convert back to Expr""" # Precompute the effect of converting to sympy and expanding expressions # like (sqrt(2) + sqrt(3))**2. Asking Expr to do the expansion on every # conversion from K to Expr is slow. Here we compute the expansions for # each power of the generator and collect together the resulting algebraic # terms and the rational coefficients into a matrix. from sympy import Add, S gen = K.ext.as_expr() todom = K.dom.from_sympy # We'll let Expr compute the expansions. We won't make any presumptions # about what this results in except that it is QQ-linear in some terms # that we will call algebraics. The final result will be expressed in # terms of those. powers = [S.One, gen] for n in range(2, K.mod.degree()): powers.append((gen * powers[-1]).expand()) # Collect the rational coefficients and algebraic Expr that can # map the ANP coefficients into an expanded sympy expression terms = [dict(t.as_coeff_Mul()[::-1] for t in Add.make_args(p)) for p in powers] algebraics = set().union(*terms) matrix = [[todom(t.get(a, S.Zero)) for t in terms] for a in algebraics] # Create a function to do the conversion efficiently: def converter(a): """Convert a to Expr using converter""" from sympy import Add, Mul ai = a.rep[::-1] tosympy = K.dom.to_sympy coeffs_dom = [sum(mij*aj for mij, aj in zip(mi, ai)) for mi in matrix] coeffs_sympy = [tosympy(c) for c in coeffs_dom] res = Add(*(Mul(c, a) for c, a in zip(coeffs_sympy, algebraics))) return res return converter sympy-sympy-1.9/sympy/polys/domains/characteristiczero.py000066400000000000000000000005761412543434000241560ustar00rootroot00000000000000"""Implementation of :class:`CharacteristicZero` class. """ from sympy.polys.domains.domain import Domain from sympy.utilities import public @public class CharacteristicZero(Domain): """Domain that has infinite number of elements. """ has_CharacteristicZero = True def characteristic(self): """Return the characteristic of this domain. """ return 0 sympy-sympy-1.9/sympy/polys/domains/complexfield.py000066400000000000000000000110141412543434000227260ustar00rootroot00000000000000"""Implementation of :class:`ComplexField` class. """ from sympy.core.numbers import Float, I from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.field import Field from sympy.polys.domains.mpelements import MPContext from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.polyerrors import DomainError, CoercionFailed from sympy.utilities import public @public class ComplexField(Field, CharacteristicZero, SimpleDomain): """Complex numbers up to the given precision. """ rep = 'CC' is_ComplexField = is_CC = True is_Exact = False is_Numerical = True has_assoc_Ring = False has_assoc_Field = True _default_precision = 53 @property def has_default_precision(self): return self.precision == self._default_precision @property def precision(self): return self._context.prec @property def dps(self): return self._context.dps @property def tolerance(self): return self._context.tolerance def __init__(self, prec=_default_precision, dps=None, tol=None): context = MPContext(prec, dps, tol, False) context._parent = self self._context = context self.dtype = context.mpc self.zero = self.dtype(0) self.one = self.dtype(1) def __eq__(self, other): return (isinstance(other, ComplexField) and self.precision == other.precision and self.tolerance == other.tolerance) def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.precision, self.tolerance)) def to_sympy(self, element): """Convert ``element`` to SymPy number. """ return Float(element.real, self.dps) + I*Float(element.imag, self.dps) def from_sympy(self, expr): """Convert SymPy's number to ``dtype``. """ number = expr.evalf(n=self.dps) real, imag = number.as_real_imag() if real.is_Number and imag.is_Number: return self.dtype(real, imag) else: raise CoercionFailed("expected complex number, got %s" % expr) def from_ZZ(self, element, base): return self.dtype(element) def from_QQ(self, element, base): return self.dtype(int(element.numerator)) / int(element.denominator) def from_ZZ_python(self, element, base): return self.dtype(element) def from_QQ_python(self, element, base): return self.dtype(element.numerator) / element.denominator def from_ZZ_gmpy(self, element, base): return self.dtype(int(element)) def from_QQ_gmpy(self, element, base): return self.dtype(int(element.numerator)) / int(element.denominator) def from_GaussianIntegerRing(self, element, base): return self.dtype(int(element.x), int(element.y)) def from_GaussianRationalField(self, element, base): x = element.x y = element.y return (self.dtype(int(x.numerator)) / int(x.denominator) + self.dtype(0, int(y.numerator)) / int(y.denominator)) def from_AlgebraicField(self, element, base): return self.from_sympy(base.to_sympy(element).evalf(self.dps)) def from_RealField(self, element, base): return self.dtype(element) def from_ComplexField(self, element, base): if self == base: return element else: return self.dtype(element) def get_ring(self): """Returns a ring associated with ``self``. """ raise DomainError("there is no ring associated with %s" % self) def get_exact(self): """Returns an exact domain associated with ``self``. """ raise DomainError("there is no exact domain associated with %s" % self) def is_negative(self, element): """Returns ``False`` for any ``ComplexElement``. """ return False def is_positive(self, element): """Returns ``False`` for any ``ComplexElement``. """ return False def is_nonnegative(self, element): """Returns ``False`` for any ``ComplexElement``. """ return False def is_nonpositive(self, element): """Returns ``False`` for any ``ComplexElement``. """ return False def gcd(self, a, b): """Returns GCD of ``a`` and ``b``. """ return self.one def lcm(self, a, b): """Returns LCM of ``a`` and ``b``. """ return a*b def almosteq(self, a, b, tolerance=None): """Check if ``a`` and ``b`` are almost equal. """ return self._context.almosteq(a, b, tolerance) CC = ComplexField() sympy-sympy-1.9/sympy/polys/domains/compositedomain.py000066400000000000000000000020221412543434000234440ustar00rootroot00000000000000"""Implementation of :class:`CompositeDomain` class. """ from sympy.polys.domains.domain import Domain from sympy.polys.polyerrors import GeneratorsError from sympy.utilities import public @public class CompositeDomain(Domain): """Base class for composite domains, e.g. ZZ[x], ZZ(X). """ is_Composite = True gens, ngens, symbols, domain = [None]*4 def inject(self, *symbols): """Inject generators into this domain. """ if not (set(self.symbols) & set(symbols)): return self.__class__(self.domain, self.symbols + symbols, self.order) else: raise GeneratorsError("common generators in %s and %s" % (self.symbols, symbols)) def drop(self, *symbols): """Drop generators from this domain. """ symset = set(symbols) newsyms = tuple(s for s in self.symbols if s not in symset) domain = self.domain.drop(*symbols) if not newsyms: return domain else: return self.__class__(domain, newsyms, self.order) sympy-sympy-1.9/sympy/polys/domains/domain.py000066400000000000000000001045041412543434000215310ustar00rootroot00000000000000"""Implementation of :class:`Domain` class. """ from typing import Any, Optional, Type from sympy.core import Basic, sympify from sympy.core.compatibility import HAS_GMPY, is_sequence, ordered from sympy.core.decorators import deprecated from sympy.polys.domains.domainelement import DomainElement from sympy.polys.orderings import lex from sympy.polys.polyerrors import UnificationFailed, CoercionFailed, DomainError from sympy.polys.polyutils import _unify_gens, _not_a_coeff from sympy.utilities import default_sort_key, public @public class Domain: """Superclass for all domains in the polys domains system. See :ref:`polys-domainsintro` for an introductory explanation of the domains system. The :py:class:`~.Domain` class is an abstract base class for all of the concrete domain types. There are many different :py:class:`~.Domain` subclasses each of which has an associated ``dtype`` which is a class representing the elements of the domain. The coefficients of a :py:class:`~.Poly` are elements of a domain which must be a subclass of :py:class:`~.Domain`. Examples ======== The most common example domains are the integers :ref:`ZZ` and the rationals :ref:`QQ`. >>> from sympy import Poly, symbols, Domain >>> x, y = symbols('x, y') >>> p = Poly(x**2 + y) >>> p Poly(x**2 + y, x, y, domain='ZZ') >>> p.domain ZZ >>> isinstance(p.domain, Domain) True >>> Poly(x**2 + y/2) Poly(x**2 + 1/2*y, x, y, domain='QQ') The domains can be used directly in which case the domain object e.g. (:ref:`ZZ` or :ref:`QQ`) can be used as a constructor for elements of ``dtype``. >>> from sympy import ZZ, QQ >>> ZZ(2) 2 >>> ZZ.dtype # doctest: +SKIP >>> type(ZZ(2)) # doctest: +SKIP >>> QQ(1, 2) 1/2 >>> type(QQ(1, 2)) # doctest: +SKIP The corresponding domain elements can be used with the arithmetic operations ``+,-,*,**`` and depending on the domain some combination of ``/,//,%`` might be usable. For example in :ref:`ZZ` both ``//`` (floor division) and ``%`` (modulo division) can be used but ``/`` (true division) can not. Since :ref:`QQ` is a :py:class:`~.Field` its elements can be used with ``/`` but ``//`` and ``%`` should not be used. Some domains have a :py:meth:`~.Domain.gcd` method. >>> ZZ(2) + ZZ(3) 5 >>> ZZ(5) // ZZ(2) 2 >>> ZZ(5) % ZZ(2) 1 >>> QQ(1, 2) / QQ(2, 3) 3/4 >>> ZZ.gcd(ZZ(4), ZZ(2)) 2 >>> QQ.gcd(QQ(2,7), QQ(5,3)) 1/21 >>> ZZ.is_Field False >>> QQ.is_Field True There are also many other domains including: 1. :ref:`GF(p)` for finite fields of prime order. 2. :ref:`RR` for real (floating point) numbers. 3. :ref:`CC` for complex (floating point) numbers. 4. :ref:`QQ(a)` for algebraic number fields. 5. :ref:`K[x]` for polynomial rings. 6. :ref:`K(x)` for rational function fields. 7. :ref:`EX` for arbitrary expressions. Each domain is represented by a domain object and also an implementation class (``dtype``) for the elements of the domain. For example the :ref:`K[x]` domains are represented by a domain object which is an instance of :py:class:`~.PolynomialRing` and the elements are always instances of :py:class:`~.PolyElement`. The implementation class represents particular types of mathematical expressions in a way that is more efficient than a normal SymPy expression which is of type :py:class:`~.Expr`. The domain methods :py:meth:`~.Domain.from_sympy` and :py:meth:`~.Domain.to_sympy` are used to convert from :py:class:`~.Expr` to a domain element and vice versa. >>> from sympy import Symbol, ZZ, Expr >>> x = Symbol('x') >>> K = ZZ[x] # polynomial ring domain >>> K ZZ[x] >>> type(K) # class of the domain >>> K.dtype # class of the elements >>> p_expr = x**2 + 1 # Expr >>> p_expr x**2 + 1 >>> type(p_expr) >>> isinstance(p_expr, Expr) True >>> p_domain = K.from_sympy(p_expr) >>> p_domain # domain element x**2 + 1 >>> type(p_domain) >>> K.to_sympy(p_domain) == p_expr True The :py:meth:`~.Domain.convert_from` method is used to convert domain elements from one domain to another. >>> from sympy import ZZ, QQ >>> ez = ZZ(2) >>> eq = QQ.convert_from(ez, ZZ) >>> type(ez) # doctest: +SKIP >>> type(eq) # doctest: +SKIP Elements from different domains should not be mixed in arithmetic or other operations: they should be converted to a common domain first. The domain method :py:meth:`~.Domain.unify` is used to find a domain that can represent all the elements of two given domains. >>> from sympy import ZZ, QQ, symbols >>> x, y = symbols('x, y') >>> ZZ.unify(QQ) QQ >>> ZZ[x].unify(QQ) QQ[x] >>> ZZ[x].unify(QQ[y]) QQ[x,y] If a domain is a :py:class:`~.Ring` then is might have an associated :py:class:`~.Field` and vice versa. The :py:meth:`~.Domain.get_field` and :py:meth:`~.Domain.get_ring` methods will find or create the associated domain. >>> from sympy import ZZ, QQ, Symbol >>> x = Symbol('x') >>> ZZ.has_assoc_Field True >>> ZZ.get_field() QQ >>> QQ.has_assoc_Ring True >>> QQ.get_ring() ZZ >>> K = QQ[x] >>> K QQ[x] >>> K.get_field() QQ(x) See also ======== DomainElement: abstract base class for domain elements construct_domain: construct a minimal domain for some expressions """ dtype = None # type: Optional[Type] """The type (class) of the elements of this :py:class:`~.Domain`: >>> from sympy import ZZ, QQ, Symbol >>> ZZ.dtype >>> z = ZZ(2) >>> z 2 >>> type(z) >>> type(z) == ZZ.dtype True Every domain has an associated **dtype** ("datatype") which is the class of the associated domain elements. See also ======== of_type """ zero = None # type: Optional[Any] """The zero element of the :py:class:`~.Domain`: >>> from sympy import QQ >>> QQ.zero 0 >>> QQ.of_type(QQ.zero) True See also ======== of_type one """ one = None # type: Optional[Any] """The one element of the :py:class:`~.Domain`: >>> from sympy import QQ >>> QQ.one 1 >>> QQ.of_type(QQ.one) True See also ======== of_type zero """ is_Ring = False """Boolean flag indicating if the domain is a :py:class:`~.Ring`. >>> from sympy import ZZ >>> ZZ.is_Ring True Basically every :py:class:`~.Domain` represents a ring so this flag is not that useful. See also ======== is_PID is_Field get_ring has_assoc_Ring """ is_Field = False """Boolean flag indicating if the domain is a :py:class:`~.Field`. >>> from sympy import ZZ, QQ >>> ZZ.is_Field False >>> QQ.is_Field True See also ======== is_PID is_Ring get_field has_assoc_Field """ has_assoc_Ring = False """Boolean flag indicating if the domain has an associated :py:class:`~.Ring`. >>> from sympy import QQ >>> QQ.has_assoc_Ring True >>> QQ.get_ring() ZZ See also ======== is_Field get_ring """ has_assoc_Field = False """Boolean flag indicating if the domain has an associated :py:class:`~.Field`. >>> from sympy import ZZ >>> ZZ.has_assoc_Field True >>> ZZ.get_field() QQ See also ======== is_Field get_field """ is_FiniteField = is_FF = False is_IntegerRing = is_ZZ = False is_RationalField = is_QQ = False is_GaussianRing = is_ZZ_I = False is_GaussianField = is_QQ_I = False is_RealField = is_RR = False is_ComplexField = is_CC = False is_AlgebraicField = is_Algebraic = False is_PolynomialRing = is_Poly = False is_FractionField = is_Frac = False is_SymbolicDomain = is_EX = False is_SymbolicRawDomain = is_EXRAW = False is_FiniteExtension = False is_Exact = True is_Numerical = False is_Simple = False is_Composite = False is_PID = False """Boolean flag indicating if the domain is a `principal ideal domain`_. >>> from sympy import ZZ >>> ZZ.has_assoc_Field True >>> ZZ.get_field() QQ .. _principal ideal domain: https://en.wikipedia.org/wiki/Principal_ideal_domain See also ======== is_Field get_field """ has_CharacteristicZero = False rep = None # type: Optional[str] alias = None # type: Optional[str] @property # type: ignore @deprecated(useinstead="is_Field", issue=12723, deprecated_since_version="1.1") def has_Field(self): return self.is_Field @property # type: ignore @deprecated(useinstead="is_Ring", issue=12723, deprecated_since_version="1.1") def has_Ring(self): return self.is_Ring def __init__(self): raise NotImplementedError def __str__(self): return self.rep def __repr__(self): return str(self) def __hash__(self): return hash((self.__class__.__name__, self.dtype)) def new(self, *args): return self.dtype(*args) @property def tp(self): """Alias for :py:attr:`~.Domain.dtype`""" return self.dtype def __call__(self, *args): """Construct an element of ``self`` domain from ``args``. """ return self.new(*args) def normal(self, *args): return self.dtype(*args) def convert_from(self, element, base): """Convert ``element`` to ``self.dtype`` given the base domain. """ if base.alias is not None: method = "from_" + base.alias else: method = "from_" + base.__class__.__name__ _convert = getattr(self, method) if _convert is not None: result = _convert(element, base) if result is not None: return result raise CoercionFailed("can't convert %s of type %s from %s to %s" % (element, type(element), base, self)) def convert(self, element, base=None): """Convert ``element`` to ``self.dtype``. """ if _not_a_coeff(element): raise CoercionFailed('%s is not in any domain' % element) if base is not None: return self.convert_from(element, base) if self.of_type(element): return element from sympy.polys.domains import ZZ, QQ, RealField, ComplexField if ZZ.of_type(element): return self.convert_from(element, ZZ) if isinstance(element, int): return self.convert_from(ZZ(element), ZZ) if HAS_GMPY: integers = ZZ if isinstance(element, integers.tp): return self.convert_from(element, integers) rationals = QQ if isinstance(element, rationals.tp): return self.convert_from(element, rationals) if isinstance(element, float): parent = RealField(tol=False) return self.convert_from(parent(element), parent) if isinstance(element, complex): parent = ComplexField(tol=False) return self.convert_from(parent(element), parent) if isinstance(element, DomainElement): return self.convert_from(element, element.parent()) # TODO: implement this in from_ methods if self.is_Numerical and getattr(element, 'is_ground', False): return self.convert(element.LC()) if isinstance(element, Basic): try: return self.from_sympy(element) except (TypeError, ValueError): pass else: # TODO: remove this branch if not is_sequence(element): try: element = sympify(element, strict=True) if isinstance(element, Basic): return self.from_sympy(element) except (TypeError, ValueError): pass raise CoercionFailed("can't convert %s of type %s to %s" % (element, type(element), self)) def of_type(self, element): """Check if ``a`` is of type ``dtype``. """ return isinstance(element, self.tp) # XXX: this isn't correct, e.g. PolyElement def __contains__(self, a): """Check if ``a`` belongs to this domain. """ try: if _not_a_coeff(a): raise CoercionFailed self.convert(a) # this might raise, too except CoercionFailed: return False return True def to_sympy(self, a): """Convert domain element *a* to a SymPy expression (Expr). Explanation =========== Convert a :py:class:`~.Domain` element *a* to :py:class:`~.Expr`. Most public SymPy functions work with objects of type :py:class:`~.Expr`. The elements of a :py:class:`~.Domain` have a different internal representation. It is not possible to mix domain elements with :py:class:`~.Expr` so each domain has :py:meth:`~.Domain.to_sympy` and :py:meth:`~.Domain.from_sympy` methods to convert its domain elements to and from :py:class:`~.Expr`. Parameters ========== a: domain element An element of this :py:class:`~.Domain`. Returns ======= expr: Expr A normal sympy expression of type :py:class:`~.Expr`. Examples ======== Construct an element of the :ref:`QQ` domain and then convert it to :py:class:`~.Expr`. >>> from sympy import QQ, Expr >>> q_domain = QQ(2) >>> q_domain 2 >>> q_expr = QQ.to_sympy(q_domain) >>> q_expr 2 Although the printed forms look similar these objects are not of the same type. >>> isinstance(q_domain, Expr) False >>> isinstance(q_expr, Expr) True Construct an element of :ref:`K[x]` and convert to :py:class:`~.Expr`. >>> from sympy import Symbol >>> x = Symbol('x') >>> K = QQ[x] >>> x_domain = K.gens[0] # generator x as a domain element >>> p_domain = x_domain**2/3 + 1 >>> p_domain 1/3*x**2 + 1 >>> p_expr = K.to_sympy(p_domain) >>> p_expr x**2/3 + 1 The :py:meth:`~.Domain.from_sympy` method is used for the opposite conversion from a normal SymPy expression to a domain element. >>> p_domain == p_expr False >>> K.from_sympy(p_expr) == p_domain True >>> K.to_sympy(p_domain) == p_expr True >>> K.from_sympy(K.to_sympy(p_domain)) == p_domain True >>> K.to_sympy(K.from_sympy(p_expr)) == p_expr True The :py:meth:`~.Domain.from_sympy` method makes it easier to construct domain elements interactively. >>> from sympy import Symbol >>> x = Symbol('x') >>> K = QQ[x] >>> K.from_sympy(x**2/3 + 1) 1/3*x**2 + 1 See also ======== from_sympy convert_from """ raise NotImplementedError def from_sympy(self, a): """Convert a SymPy expression to an element of this domain. Explanation =========== See :py:meth:`~.Domain.to_sympy` for explanation and examples. Parameters ========== expr: Expr A normal sympy expression of type :py:class:`~.Expr`. Returns ======= a: domain element An element of this :py:class:`~.Domain`. See also ======== to_sympy convert_from """ raise NotImplementedError def sum(self, args): return sum(args) def from_FF(K1, a, K0): """Convert ``ModularInteger(int)`` to ``dtype``. """ return None def from_FF_python(K1, a, K0): """Convert ``ModularInteger(int)`` to ``dtype``. """ return None def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return None def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return None def from_FF_gmpy(K1, a, K0): """Convert ``ModularInteger(mpz)`` to ``dtype``. """ return None def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return None def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return None def from_RealField(K1, a, K0): """Convert a real element object to ``dtype``. """ return None def from_ComplexField(K1, a, K0): """Convert a complex element to ``dtype``. """ return None def from_AlgebraicField(K1, a, K0): """Convert an algebraic number to ``dtype``. """ return None def from_PolynomialRing(K1, a, K0): """Convert a polynomial to ``dtype``. """ if a.is_ground: return K1.convert(a.LC, K0.dom) def from_FractionField(K1, a, K0): """Convert a rational function to ``dtype``. """ return None def from_MonogenicFiniteExtension(K1, a, K0): """Convert an ``ExtensionElement`` to ``dtype``. """ return K1.convert_from(a.rep, K0.ring) def from_ExpressionDomain(K1, a, K0): """Convert a ``EX`` object to ``dtype``. """ return K1.from_sympy(a.ex) def from_ExpressionRawDomain(K1, a, K0): """Convert a ``EX`` object to ``dtype``. """ return K1.from_sympy(a) def from_GlobalPolynomialRing(K1, a, K0): """Convert a polynomial to ``dtype``. """ if a.degree() <= 0: return K1.convert(a.LC(), K0.dom) def from_GeneralizedPolynomialRing(K1, a, K0): return K1.from_FractionField(a, K0) def unify_with_symbols(K0, K1, symbols): if (K0.is_Composite and (set(K0.symbols) & set(symbols))) or (K1.is_Composite and (set(K1.symbols) & set(symbols))): raise UnificationFailed("can't unify %s with %s, given %s generators" % (K0, K1, tuple(symbols))) return K0.unify(K1) def unify(K0, K1, symbols=None): """ Construct a minimal domain that contains elements of ``K0`` and ``K1``. Known domains (from smallest to largest): - ``GF(p)`` - ``ZZ`` - ``QQ`` - ``RR(prec, tol)`` - ``CC(prec, tol)`` - ``ALG(a, b, c)`` - ``K[x, y, z]`` - ``K(x, y, z)`` - ``EX`` """ if symbols is not None: return K0.unify_with_symbols(K1, symbols) if K0 == K1: return K0 if K0.is_EXRAW: return K0 if K1.is_EXRAW: return K1 if K0.is_EX: return K0 if K1.is_EX: return K1 if K0.is_FiniteExtension or K1.is_FiniteExtension: if K1.is_FiniteExtension: K0, K1 = K1, K0 if K1.is_FiniteExtension: # Unifying two extensions. # Try to ensure that K0.unify(K1) == K1.unify(K0) if list(ordered([K0.modulus, K1.modulus]))[1] == K0.modulus: K0, K1 = K1, K0 return K1.set_domain(K0) else: # Drop the generator from other and unify with the base domain K1 = K1.drop(K0.symbol) K1 = K0.domain.unify(K1) return K0.set_domain(K1) if K0.is_Composite or K1.is_Composite: K0_ground = K0.dom if K0.is_Composite else K0 K1_ground = K1.dom if K1.is_Composite else K1 K0_symbols = K0.symbols if K0.is_Composite else () K1_symbols = K1.symbols if K1.is_Composite else () domain = K0_ground.unify(K1_ground) symbols = _unify_gens(K0_symbols, K1_symbols) order = K0.order if K0.is_Composite else K1.order if ((K0.is_FractionField and K1.is_PolynomialRing or K1.is_FractionField and K0.is_PolynomialRing) and (not K0_ground.is_Field or not K1_ground.is_Field) and domain.is_Field and domain.has_assoc_Ring): domain = domain.get_ring() if K0.is_Composite and (not K1.is_Composite or K0.is_FractionField or K1.is_PolynomialRing): cls = K0.__class__ else: cls = K1.__class__ from sympy.polys.domains.old_polynomialring import GlobalPolynomialRing if cls == GlobalPolynomialRing: return cls(domain, symbols) return cls(domain, symbols, order) def mkinexact(cls, K0, K1): prec = max(K0.precision, K1.precision) tol = max(K0.tolerance, K1.tolerance) return cls(prec=prec, tol=tol) if K1.is_ComplexField: K0, K1 = K1, K0 if K0.is_ComplexField: if K1.is_ComplexField or K1.is_RealField: return mkinexact(K0.__class__, K0, K1) else: return K0 if K1.is_RealField: K0, K1 = K1, K0 if K0.is_RealField: if K1.is_RealField: return mkinexact(K0.__class__, K0, K1) elif K1.is_GaussianRing or K1.is_GaussianField: from sympy.polys.domains.complexfield import ComplexField return ComplexField(prec=K0.precision, tol=K0.tolerance) else: return K0 if K1.is_AlgebraicField: K0, K1 = K1, K0 if K0.is_AlgebraicField: if K1.is_GaussianRing: K1 = K1.get_field() if K1.is_GaussianField: K1 = K1.as_AlgebraicField() if K1.is_AlgebraicField: return K0.__class__(K0.dom.unify(K1.dom), *_unify_gens(K0.orig_ext, K1.orig_ext)) else: return K0 if K0.is_GaussianField: return K0 if K1.is_GaussianField: return K1 if K0.is_GaussianRing: if K1.is_RationalField: K0 = K0.get_field() return K0 if K1.is_GaussianRing: if K0.is_RationalField: K1 = K1.get_field() return K1 if K0.is_RationalField: return K0 if K1.is_RationalField: return K1 if K0.is_IntegerRing: return K0 if K1.is_IntegerRing: return K1 if K0.is_FiniteField and K1.is_FiniteField: return K0.__class__(max(K0.mod, K1.mod, key=default_sort_key)) from sympy.polys.domains import EX return EX def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ return isinstance(other, Domain) and self.dtype == other.dtype def __ne__(self, other): """Returns ``False`` if two domains are equivalent. """ return not self == other def map(self, seq): """Rersively apply ``self`` to all elements of ``seq``. """ result = [] for elt in seq: if isinstance(elt, list): result.append(self.map(elt)) else: result.append(self(elt)) return result def get_ring(self): """Returns a ring associated with ``self``. """ raise DomainError('there is no ring associated with %s' % self) def get_field(self): """Returns a field associated with ``self``. """ raise DomainError('there is no field associated with %s' % self) def get_exact(self): """Returns an exact domain associated with ``self``. """ return self def __getitem__(self, symbols): """The mathematical way to make a polynomial ring. """ if hasattr(symbols, '__iter__'): return self.poly_ring(*symbols) else: return self.poly_ring(symbols) def poly_ring(self, *symbols, order=lex): """Returns a polynomial ring, i.e. `K[X]`. """ from sympy.polys.domains.polynomialring import PolynomialRing return PolynomialRing(self, symbols, order) def frac_field(self, *symbols, order=lex): """Returns a fraction field, i.e. `K(X)`. """ from sympy.polys.domains.fractionfield import FractionField return FractionField(self, symbols, order) def old_poly_ring(self, *symbols, **kwargs): """Returns a polynomial ring, i.e. `K[X]`. """ from sympy.polys.domains.old_polynomialring import PolynomialRing return PolynomialRing(self, *symbols, **kwargs) def old_frac_field(self, *symbols, **kwargs): """Returns a fraction field, i.e. `K(X)`. """ from sympy.polys.domains.old_fractionfield import FractionField return FractionField(self, *symbols, **kwargs) def algebraic_field(self, *extension): r"""Returns an algebraic field, i.e. `K(\alpha, \ldots)`. """ raise DomainError("can't create algebraic field over %s" % self) def inject(self, *symbols): """Inject generators into this domain. """ raise NotImplementedError def drop(self, *symbols): """Drop generators from this domain. """ if self.is_Simple: return self raise NotImplementedError # pragma: no cover def is_zero(self, a): """Returns True if ``a`` is zero. """ return not a def is_one(self, a): """Returns True if ``a`` is one. """ return a == self.one def is_positive(self, a): """Returns True if ``a`` is positive. """ return a > 0 def is_negative(self, a): """Returns True if ``a`` is negative. """ return a < 0 def is_nonpositive(self, a): """Returns True if ``a`` is non-positive. """ return a <= 0 def is_nonnegative(self, a): """Returns True if ``a`` is non-negative. """ return a >= 0 def canonical_unit(self, a): if self.is_negative(a): return -self.one else: return self.one def abs(self, a): """Absolute value of ``a``, implies ``__abs__``. """ return abs(a) def neg(self, a): """Returns ``a`` negated, implies ``__neg__``. """ return -a def pos(self, a): """Returns ``a`` positive, implies ``__pos__``. """ return +a def add(self, a, b): """Sum of ``a`` and ``b``, implies ``__add__``. """ return a + b def sub(self, a, b): """Difference of ``a`` and ``b``, implies ``__sub__``. """ return a - b def mul(self, a, b): """Product of ``a`` and ``b``, implies ``__mul__``. """ return a * b def pow(self, a, b): """Raise ``a`` to power ``b``, implies ``__pow__``. """ return a ** b def exquo(self, a, b): """Exact quotient of *a* and *b*. Analogue of ``a / b``. Explanation =========== This is essentially the same as ``a / b`` except that an error will be raised if the division is inexact (if there is any remainder) and the result will always be a domain element. When working in a :py:class:`~.Domain` that is not a :py:class:`~.Field` (e.g. :ref:`ZZ` or :ref:`K[x]`) ``exquo`` should be used instead of ``/``. The key invariant is that if ``q = K.exquo(a, b)`` (and ``exquo`` does not raise an exception) then ``a == b*q``. Examples ======== We can use ``K.exquo`` instead of ``/`` for exact division. >>> from sympy import ZZ >>> ZZ.exquo(ZZ(4), ZZ(2)) 2 >>> ZZ.exquo(ZZ(5), ZZ(2)) Traceback (most recent call last): ... ExactQuotientFailed: 2 does not divide 5 in ZZ Over a :py:class:`~.Field` such as :ref:`QQ`, division (with nonzero divisor) is always exact so in that case ``/`` can be used instead of :py:meth:`~.Domain.exquo`. >>> from sympy import QQ >>> QQ.exquo(QQ(5), QQ(2)) 5/2 >>> QQ(5) / QQ(2) 5/2 Parameters ========== a: domain element The dividend b: domain element The divisor Returns ======= q: domain element The exact quotient Raises ====== ExactQuotientFailed: if exact division is not possible. ZeroDivisionError: when the divisor is zero. See also ======== quo: Analogue of ``a // b`` rem: Analogue of ``a % b`` div: Analogue of ``divmod(a, b)`` Notes ===== Since the default :py:attr:`~.Domain.dtype` for :ref:`ZZ` is ``int`` (or ``mpz``) division as ``a / b`` should not be used as it would give a ``float``. >>> ZZ(4) / ZZ(2) 2.0 >>> ZZ(5) / ZZ(2) 2.5 Using ``/`` with :ref:`ZZ` will lead to incorrect results so :py:meth:`~.Domain.exquo` should be used instead. """ raise NotImplementedError def quo(self, a, b): """Quotient of *a* and *b*. Analogue of ``a // b``. ``K.quo(a, b)`` is equivalent to ``K.div(a, b)[0]``. See :py:meth:`~.Domain.div` for more explanation. See also ======== rem: Analogue of ``a % b`` div: Analogue of ``divmod(a, b)`` exquo: Analogue of ``a / b`` """ raise NotImplementedError def rem(self, a, b): """Modulo division of *a* and *b*. Analogue of ``a % b``. ``K.rem(a, b)`` is equivalent to ``K.div(a, b)[1]``. See :py:meth:`~.Domain.div` for more explanation. See also ======== quo: Analogue of ``a // b`` div: Analogue of ``divmod(a, b)`` exquo: Analogue of ``a / b`` """ raise NotImplementedError def div(self, a, b): """Quotient and remainder for *a* and *b*. Analogue of ``divmod(a, b)`` Explanation =========== This is essentially the same as ``divmod(a, b)`` except that is more consistent when working over some :py:class:`~.Field` domains such as :ref:`QQ`. When working over an arbitrary :py:class:`~.Domain` the :py:meth:`~.Domain.div` method should be used instead of ``divmod``. The key invariant is that if ``q, r = K.div(a, b)`` then ``a == b*q + r``. The result of ``K.div(a, b)`` is the same as the tuple ``(K.quo(a, b), K.rem(a, b))`` except that if both quotient and remainder are needed then it is more efficient to use :py:meth:`~.Domain.div`. Examples ======== We can use ``K.div`` instead of ``divmod`` for floor division and remainder. >>> from sympy import ZZ, QQ >>> ZZ.div(ZZ(5), ZZ(2)) (2, 1) If ``K`` is a :py:class:`~.Field` then the division is always exact with a remainder of :py:attr:`~.Domain.zero`. >>> QQ.div(QQ(5), QQ(2)) (5/2, 0) Parameters ========== a: domain element The dividend b: domain element The divisor Returns ======= (q, r): tuple of domain elements The quotient and remainder Raises ====== ZeroDivisionError: when the divisor is zero. See also ======== quo: Analogue of ``a // b`` rem: Analogue of ``a % b`` exquo: Analogue of ``a / b`` Notes ===== If ``gmpy`` is installed then the ``gmpy.mpq`` type will be used as the :py:attr:`~.Domain.dtype` for :ref:`QQ`. The ``gmpy.mpq`` type defines ``divmod`` in a way that is undesirable so :py:meth:`~.Domain.div` should be used instead of ``divmod``. >>> a = QQ(1) >>> b = QQ(3, 2) >>> a # doctest: +SKIP mpq(1,1) >>> b # doctest: +SKIP mpq(3,2) >>> divmod(a, b) # doctest: +SKIP (mpz(0), mpq(1,1)) >>> QQ.div(a, b) # doctest: +SKIP (mpq(2,3), mpq(0,1)) Using ``//`` or ``%`` with :ref:`QQ` will lead to incorrect results so :py:meth:`~.Domain.div` should be used instead. """ raise NotImplementedError def invert(self, a, b): """Returns inversion of ``a mod b``, implies something. """ raise NotImplementedError def revert(self, a): """Returns ``a**(-1)`` if possible. """ raise NotImplementedError def numer(self, a): """Returns numerator of ``a``. """ raise NotImplementedError def denom(self, a): """Returns denominator of ``a``. """ raise NotImplementedError def half_gcdex(self, a, b): """Half extended GCD of ``a`` and ``b``. """ s, t, h = self.gcdex(a, b) return s, h def gcdex(self, a, b): """Extended GCD of ``a`` and ``b``. """ raise NotImplementedError def cofactors(self, a, b): """Returns GCD and cofactors of ``a`` and ``b``. """ gcd = self.gcd(a, b) cfa = self.quo(a, gcd) cfb = self.quo(b, gcd) return gcd, cfa, cfb def gcd(self, a, b): """Returns GCD of ``a`` and ``b``. """ raise NotImplementedError def lcm(self, a, b): """Returns LCM of ``a`` and ``b``. """ raise NotImplementedError def log(self, a, b): """Returns b-base logarithm of ``a``. """ raise NotImplementedError def sqrt(self, a): """Returns square root of ``a``. """ raise NotImplementedError def evalf(self, a, prec=None, **options): """Returns numerical approximation of ``a``. """ return self.to_sympy(a).evalf(prec, **options) n = evalf def real(self, a): return a def imag(self, a): return self.zero def almosteq(self, a, b, tolerance=None): """Check if ``a`` and ``b`` are almost equal. """ return a == b def characteristic(self): """Return the characteristic of this domain. """ raise NotImplementedError('characteristic()') __all__ = ['Domain'] sympy-sympy-1.9/sympy/polys/domains/domainelement.py000066400000000000000000000015101412543434000230740ustar00rootroot00000000000000"""Trait for implementing domain elements. """ from sympy.utilities import public @public class DomainElement: """ Represents an element of a domain. Mix in this trait into a class whose instances should be recognized as elements of a domain. Method ``parent()`` gives that domain. """ def parent(self): """Get the domain associated with ``self`` Examples ======== >>> from sympy import ZZ, symbols >>> x, y = symbols('x, y') >>> K = ZZ[x,y] >>> p = K(x)**2 + K(y)**2 >>> p x**2 + y**2 >>> p.parent() ZZ[x,y] Notes ===== This is used by :py:meth:`~.Domain.convert` to identify the domain associated with a domain element. """ raise NotImplementedError("abstract method") sympy-sympy-1.9/sympy/polys/domains/expressiondomain.py000066400000000000000000000153731412543434000236560ustar00rootroot00000000000000"""Implementation of :class:`ExpressionDomain` class. """ from sympy.core import sympify, SympifyError from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.field import Field from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.polyutils import PicklableWithSlots from sympy.utilities import public eflags = dict(deep=False, mul=True, power_exp=False, power_base=False, basic=False, multinomial=False, log=False) @public class ExpressionDomain(Field, CharacteristicZero, SimpleDomain): """A class for arbitrary expressions. """ is_SymbolicDomain = is_EX = True class Expression(PicklableWithSlots): """An arbitrary expression. """ __slots__ = ('ex',) def __init__(self, ex): if not isinstance(ex, self.__class__): self.ex = sympify(ex) else: self.ex = ex.ex def __repr__(f): return 'EX(%s)' % repr(f.ex) def __str__(f): return 'EX(%s)' % str(f.ex) def __hash__(self): return hash((self.__class__.__name__, self.ex)) def as_expr(f): return f.ex def numer(f): return f.__class__(f.ex.as_numer_denom()[0]) def denom(f): return f.__class__(f.ex.as_numer_denom()[1]) def simplify(f, ex): return f.__class__(ex.cancel().expand(**eflags)) def __abs__(f): return f.__class__(abs(f.ex)) def __neg__(f): return f.__class__(-f.ex) def _to_ex(f, g): try: return f.__class__(g) except SympifyError: return None def __add__(f, g): g = f._to_ex(g) if g is None: return NotImplemented elif g == EX.zero: return f elif f == EX.zero: return g else: return f.simplify(f.ex + g.ex) def __radd__(f, g): return f.simplify(f.__class__(g).ex + f.ex) def __sub__(f, g): g = f._to_ex(g) if g is None: return NotImplemented elif g == EX.zero: return f elif f == EX.zero: return -g else: return f.simplify(f.ex - g.ex) def __rsub__(f, g): return f.simplify(f.__class__(g).ex - f.ex) def __mul__(f, g): g = f._to_ex(g) if g is None: return NotImplemented if EX.zero in (f, g): return EX.zero elif f.ex.is_Number and g.ex.is_Number: return f.__class__(f.ex*g.ex) return f.simplify(f.ex*g.ex) def __rmul__(f, g): return f.simplify(f.__class__(g).ex*f.ex) def __pow__(f, n): n = f._to_ex(n) if n is not None: return f.simplify(f.ex**n.ex) else: return NotImplemented def __truediv__(f, g): g = f._to_ex(g) if g is not None: return f.simplify(f.ex/g.ex) else: return NotImplemented def __rtruediv__(f, g): return f.simplify(f.__class__(g).ex/f.ex) def __eq__(f, g): return f.ex == f.__class__(g).ex def __ne__(f, g): return not f == g def __bool__(f): return not f.ex.is_zero def gcd(f, g): from sympy.polys import gcd return f.__class__(gcd(f.ex, f.__class__(g).ex)) def lcm(f, g): from sympy.polys import lcm return f.__class__(lcm(f.ex, f.__class__(g).ex)) dtype = Expression zero = Expression(0) one = Expression(1) rep = 'EX' has_assoc_Ring = False has_assoc_Field = True def __init__(self): pass def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return a.as_expr() def from_sympy(self, a): """Convert SymPy's expression to ``dtype``. """ return self.dtype(a) def from_ZZ(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_QQ(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_GaussianIntegerRing(K1, a, K0): """Convert a ``GaussianRational`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_GaussianRationalField(K1, a, K0): """Convert a ``GaussianRational`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_RealField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_PolynomialRing(K1, a, K0): """Convert a ``DMP`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_FractionField(K1, a, K0): """Convert a ``DMF`` object to ``dtype``. """ return K1(K0.to_sympy(a)) def from_ExpressionDomain(K1, a, K0): """Convert a ``EX`` object to ``dtype``. """ return a def get_ring(self): """Returns a ring associated with ``self``. """ return self # XXX: EX is not a ring but we don't have much choice here. def get_field(self): """Returns a field associated with ``self``. """ return self def is_positive(self, a): """Returns True if ``a`` is positive. """ return a.ex.as_coeff_mul()[0].is_positive def is_negative(self, a): """Returns True if ``a`` is negative. """ return a.ex.could_extract_minus_sign() def is_nonpositive(self, a): """Returns True if ``a`` is non-positive. """ return a.ex.as_coeff_mul()[0].is_nonpositive def is_nonnegative(self, a): """Returns True if ``a`` is non-negative. """ return a.ex.as_coeff_mul()[0].is_nonnegative def numer(self, a): """Returns numerator of ``a``. """ return a.numer() def denom(self, a): """Returns denominator of ``a``. """ return a.denom() def gcd(self, a, b): return self(1) def lcm(self, a, b): return a.lcm(b) EX = ExpressionDomain() sympy-sympy-1.9/sympy/polys/domains/expressionrawdomain.py000066400000000000000000000026501412543434000243620ustar00rootroot00000000000000"""Implementation of :class:`ExpressionRawDomain` class. """ from sympy.core import Expr, S, sympify, Add from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.field import Field from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public @public class ExpressionRawDomain(Field, CharacteristicZero, SimpleDomain): """A class for arbitrary expressions but without automatic simplification. """ is_SymbolicRawDomain = is_EXRAW = True dtype = Expr zero = S.Zero one = S.One rep = 'EXRAW' has_assoc_Ring = False has_assoc_Field = True def __init__(self): pass @classmethod def new(self, a): return sympify(a) def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return a def from_sympy(self, a): """Convert SymPy's expression to ``dtype``. """ if not isinstance(a, Expr): raise CoercionFailed(f"Expecting an Expr instance but found: {type(a).__name__}") return a def convert_from(self, a, K): """Convert a domain element from another domain to EXRAW""" return K.to_sympy(a) def get_field(self): """Returns a field associated with ``self``. """ return self def sum(self, items): return Add(*items) EXRAW = ExpressionRawDomain() sympy-sympy-1.9/sympy/polys/domains/field.py000066400000000000000000000050371412543434000213460ustar00rootroot00000000000000"""Implementation of :class:`Field` class. """ from sympy.polys.domains.ring import Ring from sympy.polys.polyerrors import NotReversible, DomainError from sympy.utilities import public @public class Field(Ring): """Represents a field domain. """ is_Field = True is_PID = True def get_ring(self): """Returns a ring associated with ``self``. """ raise DomainError('there is no ring associated with %s' % self) def get_field(self): """Returns a field associated with ``self``. """ return self def exquo(self, a, b): """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """ return a / b def quo(self, a, b): """Quotient of ``a`` and ``b``, implies ``__truediv__``. """ return a / b def rem(self, a, b): """Remainder of ``a`` and ``b``, implies nothing. """ return self.zero def div(self, a, b): """Division of ``a`` and ``b``, implies ``__truediv__``. """ return a / b, self.zero def gcd(self, a, b): """ Returns GCD of ``a`` and ``b``. This definition of GCD over fields allows to clear denominators in `primitive()`. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy import S, gcd, primitive >>> from sympy.abc import x >>> QQ.gcd(QQ(2, 3), QQ(4, 9)) 2/9 >>> gcd(S(2)/3, S(4)/9) 2/9 >>> primitive(2*x/3 + S(4)/9) (2/9, 3*x + 2) """ try: ring = self.get_ring() except DomainError: return self.one p = ring.gcd(self.numer(a), self.numer(b)) q = ring.lcm(self.denom(a), self.denom(b)) return self.convert(p, ring)/q def lcm(self, a, b): """ Returns LCM of ``a`` and ``b``. >>> from sympy.polys.domains import QQ >>> from sympy import S, lcm >>> QQ.lcm(QQ(2, 3), QQ(4, 9)) 4/3 >>> lcm(S(2)/3, S(4)/9) 4/3 """ try: ring = self.get_ring() except DomainError: return a*b p = ring.lcm(self.numer(a), self.numer(b)) q = ring.gcd(self.denom(a), self.denom(b)) return self.convert(p, ring)/q def revert(self, a): """Returns ``a**(-1)`` if possible. """ if a: return 1/a else: raise NotReversible('zero is not reversible') def is_unit(self, a): """Return true if ``a`` is a invertible""" return bool(a) sympy-sympy-1.9/sympy/polys/domains/finitefield.py000066400000000000000000000136061412543434000225460ustar00rootroot00000000000000"""Implementation of :class:`FiniteField` class. """ from sympy.polys.domains.field import Field from sympy.polys.domains.modularinteger import ModularIntegerFactory from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public from sympy.polys.domains.groundtypes import SymPyInteger @public class FiniteField(Field, SimpleDomain): r"""Finite field of prime order :ref:`GF(p)` A :ref:`GF(p)` domain represents a `finite field`_ `\mathbb{F}_p` of prime order as :py:class:`~.Domain` in the domain system (see :ref:`polys-domainsintro`). A :py:class:`~.Poly` created from an expression with integer coefficients will have the domain :ref:`ZZ`. Howeer if the ``modulus=p`` option is given the the domain will be a finite field instead. >>> from sympy import Poly, Symbol >>> x = Symbol('x') >>> p = Poly(x**2 + 1) >>> p Poly(x**2 + 1, x, domain='ZZ') >>> p.domain ZZ >>> p2 = Poly(x**2 + 1, modulus=2) >>> p2 Poly(x**2 + 1, x, modulus=2) >>> p2.domain GF(2) It is possible to factorise a polynomial over :ref:`GF(p)` using the modulus argument to :py:func:`~.factor` or by specifying the domain explicitly. The domain can also be given as a string. >>> from sympy import factor, GF >>> factor(x**2 + 1) x**2 + 1 >>> factor(x**2 + 1, modulus=2) (x + 1)**2 >>> factor(x**2 + 1, domain=GF(2)) (x + 1)**2 >>> factor(x**2 + 1, domain='GF(2)') (x + 1)**2 It is also possible to use :ref:`GF(p)` with the :py:func:`~.cancel` and :py:func:`~.gcd` functions. >>> from sympy import cancel, gcd >>> cancel((x**2 + 1)/(x + 1)) (x**2 + 1)/(x + 1) >>> cancel((x**2 + 1)/(x + 1), domain=GF(2)) x + 1 >>> gcd(x**2 + 1, x + 1) 1 >>> gcd(x**2 + 1, x + 1, domain=GF(2)) x + 1 When using the domain directly :ref:`GF(p)` can be used as a constructor to create instances which then support the operations ``+,-,*,**,/`` >>> from sympy import GF >>> K = GF(5) >>> K GF(5) >>> x = K(3) >>> y = K(2) >>> x 3 mod 5 >>> y 2 mod 5 >>> x * y 1 mod 5 >>> x / y 4 mod 5 Notes ===== It is also possible to create a :ref:`GF(p)` domain of **non-prime** order but the resulting ring is **not** a field: it is just the ring of the integers modulo ``n``. >>> K = GF(9) >>> z = K(3) >>> z 3 mod 9 >>> z**2 0 mod 9 It would be good to have a proper implementation of prime power fields (``GF(p**n)``) but these are not yet implemented in SymPY. .. _finite field: https://en.wikipedia.org/wiki/Finite_field """ rep = 'FF' alias = 'FF' is_FiniteField = is_FF = True is_Numerical = True has_assoc_Ring = False has_assoc_Field = True dom = None mod = None def __init__(self, mod, symmetric=True): from sympy.polys.domains import ZZ dom = ZZ if mod <= 0: raise ValueError('modulus must be a positive integer, got %s' % mod) self.dtype = ModularIntegerFactory(mod, dom, symmetric, self) self.zero = self.dtype(0) self.one = self.dtype(1) self.dom = dom self.mod = mod def __str__(self): return 'GF(%s)' % self.mod def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.mod, self.dom)) def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ return isinstance(other, FiniteField) and \ self.mod == other.mod and self.dom == other.dom def characteristic(self): """Return the characteristic of this domain. """ return self.mod def get_field(self): """Returns a field associated with ``self``. """ return self def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return SymPyInteger(int(a)) def from_sympy(self, a): """Convert SymPy's Integer to SymPy's ``Integer``. """ if a.is_Integer: return self.dtype(self.dom.dtype(int(a))) elif a.is_Float and int(a) == a: return self.dtype(self.dom.dtype(int(a))) else: raise CoercionFailed("expected an integer, got %s" % a) def from_FF(K1, a, K0=None): """Convert ``ModularInteger(int)`` to ``dtype``. """ return K1.dtype(K1.dom.from_ZZ(a.val, K0.dom)) def from_FF_python(K1, a, K0=None): """Convert ``ModularInteger(int)`` to ``dtype``. """ return K1.dtype(K1.dom.from_ZZ_python(a.val, K0.dom)) def from_ZZ(K1, a, K0=None): """Convert Python's ``int`` to ``dtype``. """ return K1.dtype(K1.dom.from_ZZ_python(a, K0)) def from_ZZ_python(K1, a, K0=None): """Convert Python's ``int`` to ``dtype``. """ return K1.dtype(K1.dom.from_ZZ_python(a, K0)) def from_QQ(K1, a, K0=None): """Convert Python's ``Fraction`` to ``dtype``. """ if a.denominator == 1: return K1.from_ZZ_python(a.numerator) def from_QQ_python(K1, a, K0=None): """Convert Python's ``Fraction`` to ``dtype``. """ if a.denominator == 1: return K1.from_ZZ_python(a.numerator) def from_FF_gmpy(K1, a, K0=None): """Convert ``ModularInteger(mpz)`` to ``dtype``. """ return K1.dtype(K1.dom.from_ZZ_gmpy(a.val, K0.dom)) def from_ZZ_gmpy(K1, a, K0=None): """Convert GMPY's ``mpz`` to ``dtype``. """ return K1.dtype(K1.dom.from_ZZ_gmpy(a, K0)) def from_QQ_gmpy(K1, a, K0=None): """Convert GMPY's ``mpq`` to ``dtype``. """ if a.denominator == 1: return K1.from_ZZ_gmpy(a.numerator) def from_RealField(K1, a, K0): """Convert mpmath's ``mpf`` to ``dtype``. """ p, q = K0.to_rational(a) if q == 1: return K1.dtype(K1.dom.dtype(p)) FF = GF = FiniteField sympy-sympy-1.9/sympy/polys/domains/fractionfield.py000066400000000000000000000134711412543434000230750ustar00rootroot00000000000000"""Implementation of :class:`FractionField` class. """ from sympy.polys.domains.compositedomain import CompositeDomain from sympy.polys.domains.field import Field from sympy.polys.polyerrors import CoercionFailed, GeneratorsError from sympy.utilities import public @public class FractionField(Field, CompositeDomain): """A class for representing multivariate rational function fields. """ is_FractionField = is_Frac = True has_assoc_Ring = True has_assoc_Field = True def __init__(self, domain_or_field, symbols=None, order=None): from sympy.polys.fields import FracField if isinstance(domain_or_field, FracField) and symbols is None and order is None: field = domain_or_field else: field = FracField(symbols, domain_or_field, order) self.field = field self.dtype = field.dtype self.gens = field.gens self.ngens = field.ngens self.symbols = field.symbols self.domain = field.domain # TODO: remove this self.dom = self.domain def new(self, element): return self.field.field_new(element) @property def zero(self): return self.field.zero @property def one(self): return self.field.one @property def order(self): return self.field.order @property def is_Exact(self): return self.domain.is_Exact def get_exact(self): return FractionField(self.domain.get_exact(), self.symbols) def __str__(self): return str(self.domain) + '(' + ','.join(map(str, self.symbols)) + ')' def __hash__(self): return hash((self.__class__.__name__, self.dtype.field, self.domain, self.symbols)) def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ return isinstance(other, FractionField) and \ (self.dtype.field, self.domain, self.symbols) ==\ (other.dtype.field, other.domain, other.symbols) def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return a.as_expr() def from_sympy(self, a): """Convert SymPy's expression to ``dtype``. """ return self.field.from_expr(a) def from_ZZ(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_QQ(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ dom = K1.domain conv = dom.convert_from if dom.is_ZZ: return K1(conv(K0.numer(a), K0)) / K1(conv(K0.denom(a), K0)) else: return K1(conv(a, K0)) def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_GaussianRationalField(K1, a, K0): """Convert a ``GaussianRational`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_GaussianIntegerRing(K1, a, K0): """Convert a ``GaussianInteger`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_RealField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_ComplexField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K1.domain.convert(a, K0)) def from_AlgebraicField(K1, a, K0): """Convert an algebraic number to ``dtype``. """ if K1.domain != K0: a = K1.domain.convert_from(a, K0) if a is not None: return K1.new(a) def from_PolynomialRing(K1, a, K0): """Convert a polynomial to ``dtype``. """ if a.is_ground: return K1.convert_from(a.coeff(1), K0.domain) try: return K1.new(a.set_ring(K1.field.ring)) except (CoercionFailed, GeneratorsError): # XXX: We get here if K1=ZZ(x,y) and K0=QQ[x,y] # and the poly a in K0 has non-integer coefficients. # It seems that K1.new can handle this but K1.new doesn't work # when K0.domain is an algebraic field... try: return K1.new(a) except (CoercionFailed, GeneratorsError): return None def from_FractionField(K1, a, K0): """Convert a rational function to ``dtype``. """ try: return a.set_field(K1.field) except (CoercionFailed, GeneratorsError): return None def get_ring(self): """Returns a field associated with ``self``. """ return self.field.to_ring().to_domain() def is_positive(self, a): """Returns True if ``LC(a)`` is positive. """ return self.domain.is_positive(a.numer.LC) def is_negative(self, a): """Returns True if ``LC(a)`` is negative. """ return self.domain.is_negative(a.numer.LC) def is_nonpositive(self, a): """Returns True if ``LC(a)`` is non-positive. """ return self.domain.is_nonpositive(a.numer.LC) def is_nonnegative(self, a): """Returns True if ``LC(a)`` is non-negative. """ return self.domain.is_nonnegative(a.numer.LC) def numer(self, a): """Returns numerator of ``a``. """ return a.numer def denom(self, a): """Returns denominator of ``a``. """ return a.denom def factorial(self, a): """Returns factorial of ``a``. """ return self.dtype(self.domain.factorial(a)) sympy-sympy-1.9/sympy/polys/domains/gaussiandomains.py000066400000000000000000000431251412543434000234500ustar00rootroot00000000000000"""Domains of Gaussian type.""" from sympy.core.numbers import I from sympy.polys.polyerrors import CoercionFailed from sympy.polys.domains.integerring import ZZ from sympy.polys.domains.rationalfield import QQ from sympy.polys.domains.algebraicfield import AlgebraicField from sympy.polys.domains.domain import Domain from sympy.polys.domains.domainelement import DomainElement from sympy.polys.domains.field import Field from sympy.polys.domains.ring import Ring class GaussianElement(DomainElement): """Base class for elements of Gaussian type domains.""" base = None # type: Domain _parent = None # type: Domain __slots__ = ('x', 'y') def __new__(cls, x, y=0): conv = cls.base.convert return cls.new(conv(x), conv(y)) @classmethod def new(cls, x, y): """Create a new GaussianElement of the same domain.""" obj = super().__new__(cls) obj.x = x obj.y = y return obj def parent(self): """The domain that this is an element of (ZZ_I or QQ_I)""" return self._parent def __hash__(self): return hash((self.x, self.y)) def __eq__(self, other): if isinstance(other, self.__class__): return self.x == other.x and self.y == other.y else: return NotImplemented def __lt__(self, other): if not isinstance(other, GaussianElement): return NotImplemented return [self.y, self.x] < [other.y, other.x] def __pos__(self): return self def __neg__(self): return self.new(-self.x, -self.y) def __repr__(self): return "%s(%s, %s)" % (self._parent.rep, self.x, self.y) def __str__(self): return str(self._parent.to_sympy(self)) @classmethod def _get_xy(cls, other): if not isinstance(other, cls): try: other = cls._parent.convert(other) except CoercionFailed: return None, None return other.x, other.y def __add__(self, other): x, y = self._get_xy(other) if x is not None: return self.new(self.x + x, self.y + y) else: return NotImplemented __radd__ = __add__ def __sub__(self, other): x, y = self._get_xy(other) if x is not None: return self.new(self.x - x, self.y - y) else: return NotImplemented def __rsub__(self, other): x, y = self._get_xy(other) if x is not None: return self.new(x - self.x, y - self.y) else: return NotImplemented def __mul__(self, other): x, y = self._get_xy(other) if x is not None: return self.new(self.x*x - self.y*y, self.x*y + self.y*x) else: return NotImplemented __rmul__ = __mul__ def __pow__(self, exp): if exp == 0: return self.new(1, 0) if exp < 0: self, exp = 1/self, -exp if exp == 1: return self pow2 = self prod = self if exp % 2 else self._parent.one exp //= 2 while exp: pow2 *= pow2 if exp % 2: prod *= pow2 exp //= 2 return prod def __bool__(self): return bool(self.x) or bool(self.y) def quadrant(self): """Return quadrant index 0-3. 0 is included in quadrant 0. """ if self.y > 0: return 0 if self.x > 0 else 1 elif self.y < 0: return 2 if self.x < 0 else 3 else: return 0 if self.x >= 0 else 2 def __rdivmod__(self, other): try: other = self._parent.convert(other) except CoercionFailed: return NotImplemented else: return other.__divmod__(self) def __rtruediv__(self, other): try: other = QQ_I.convert(other) except CoercionFailed: return NotImplemented else: return other.__truediv__(self) def __floordiv__(self, other): qr = self.__divmod__(other) return qr if qr is NotImplemented else qr[0] def __rfloordiv__(self, other): qr = self.__rdivmod__(other) return qr if qr is NotImplemented else qr[0] def __mod__(self, other): qr = self.__divmod__(other) return qr if qr is NotImplemented else qr[1] def __rmod__(self, other): qr = self.__rdivmod__(other) return qr if qr is NotImplemented else qr[1] class GaussianInteger(GaussianElement): """Gaussian integer: domain element for :ref:`ZZ_I` >>> from sympy import ZZ_I >>> z = ZZ_I(2, 3) >>> z (2 + 3*I) >>> type(z) """ base = ZZ def __truediv__(self, other): """Return a Gaussian rational.""" return QQ_I.convert(self)/other def __divmod__(self, other): if not other: raise ZeroDivisionError('divmod({}, 0)'.format(self)) x, y = self._get_xy(other) if x is None: return NotImplemented # multiply self and other by x - I*y # self/other == (a + I*b)/c a, b = self.x*x + self.y*y, -self.x*y + self.y*x c = x*x + y*y # find integers qx and qy such that # |a - qx*c| <= c/2 and |b - qy*c| <= c/2 qx = (2*a + c) // (2*c) # -c <= 2*a - qx*2*c < c qy = (2*b + c) // (2*c) q = GaussianInteger(qx, qy) # |self/other - q| < 1 since # |a/c - qx|**2 + |b/c - qy|**2 <= 1/4 + 1/4 < 1 return q, self - q*other # |r| < |other| class GaussianRational(GaussianElement): """Gaussian rational: domain element for :ref:`QQ_I` >>> from sympy import QQ_I, QQ >>> z = QQ_I(QQ(2, 3), QQ(4, 5)) >>> z (2/3 + 4/5*I) >>> type(z) """ base = QQ def __truediv__(self, other): """Return a Gaussian rational.""" if not other: raise ZeroDivisionError('{} / 0'.format(self)) x, y = self._get_xy(other) if x is None: return NotImplemented c = x*x + y*y return GaussianRational((self.x*x + self.y*y)/c, (-self.x*y + self.y*x)/c) def __divmod__(self, other): try: other = self._parent.convert(other) except CoercionFailed: return NotImplemented if not other: raise ZeroDivisionError('{} % 0'.format(self)) else: return self/other, QQ_I.zero class GaussianDomain(): """Base class for Gaussian domains.""" dom = None # type: Domain is_Numerical = True is_Exact = True has_assoc_Ring = True has_assoc_Field = True def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ conv = self.dom.to_sympy return conv(a.x) + I*conv(a.y) def from_sympy(self, a): """Convert a SymPy object to ``self.dtype``.""" r, b = a.as_coeff_Add() x = self.dom.from_sympy(r) # may raise CoercionFailed if not b: return self.new(x, 0) r, b = b.as_coeff_Mul() y = self.dom.from_sympy(r) if b is I: return self.new(x, y) else: raise CoercionFailed("{} is not Gaussian".format(a)) def inject(self, *gens): """Inject generators into this domain. """ return self.poly_ring(*gens) def canonical_unit(self, d): unit = self.units[-d.quadrant()] # - for inverse power return unit def is_negative(self, element): """Returns ``False`` for any ``GaussianElement``. """ return False def is_positive(self, element): """Returns ``False`` for any ``GaussianElement``. """ return False def is_nonnegative(self, element): """Returns ``False`` for any ``GaussianElement``. """ return False def is_nonpositive(self, element): """Returns ``False`` for any ``GaussianElement``. """ return False def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY mpz to ``self.dtype``.""" return K1(a) def from_ZZ(K1, a, K0): """Convert a ZZ_python element to ``self.dtype``.""" return K1(a) def from_ZZ_python(K1, a, K0): """Convert a ZZ_python element to ``self.dtype``.""" return K1(a) def from_QQ(K1, a, K0): """Convert a GMPY mpq to ``self.dtype``.""" return K1(a) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY mpq to ``self.dtype``.""" return K1(a) def from_QQ_python(K1, a, K0): """Convert a QQ_python element to ``self.dtype``.""" return K1(a) def from_AlgebraicField(K1, a, K0): """Convert an element from ZZ or QQ to ``self.dtype``.""" if K0.ext.args[0] == I: return K1.from_sympy(K0.to_sympy(a)) class GaussianIntegerRing(GaussianDomain, Ring): r"""Ring of Gaussian integers ``ZZ_I`` The :ref:`ZZ_I` domain represents the `Gaussian integers`_ `\mathbb{Z}[i]` as a :py:class:`~.Domain` in the domain system (see :ref:`polys-domainsintro`). By default a :py:class:`~.Poly` created from an expression with coefficients that are combinations of integers and ``I`` (`\sqrt{-1}`) will have the domain :ref:`ZZ_I`. >>> from sympy import Poly, Symbol, I >>> x = Symbol('x') >>> p = Poly(x**2 + I) >>> p Poly(x**2 + I, x, domain='ZZ_I') >>> p.domain ZZ_I The :ref:`ZZ_I` domain can be used to factorise polynomials that are reducible over the Gaussian integers. >>> from sympy import factor >>> factor(x**2 + 1) x**2 + 1 >>> factor(x**2 + 1, domain='ZZ_I') (x - I)*(x + I) The corresponding `field of fractions`_ is the domain of the Gaussian rationals :ref:`QQ_I`. Conversely :ref:`ZZ_I` is the `ring of integers`_ of :ref:`QQ_I`. >>> from sympy import ZZ_I, QQ_I >>> ZZ_I.get_field() QQ_I >>> QQ_I.get_ring() ZZ_I When using the domain directly :ref:`ZZ_I` can be used as a constructor. >>> ZZ_I(3, 4) (3 + 4*I) >>> ZZ_I(5) (5 + 0*I) The domain elements of :ref:`ZZ_I` are instances of :py:class:`~.GaussianInteger` which support the rings operations ``+,-,*,**``. >>> z1 = ZZ_I(5, 1) >>> z2 = ZZ_I(2, 3) >>> z1 (5 + 1*I) >>> z2 (2 + 3*I) >>> z1 + z2 (7 + 4*I) >>> z1 * z2 (7 + 17*I) >>> z1 ** 2 (24 + 10*I) Both floor (``//``) and modulo (``%``) division work with :py:class:`~.GaussianInteger` (see the :py:meth:`~.Domain.div` method). >>> z3, z4 = ZZ_I(5), ZZ_I(1, 3) >>> z3 // z4 # floor division (1 + -1*I) >>> z3 % z4 # modulo division (remainder) (1 + -2*I) >>> (z3//z4)*z4 + z3%z4 == z3 True True division (``/``) in :ref:`ZZ_I` gives an element of :ref:`QQ_I`. The :py:meth:`~.Domain.exquo` method can be used to divide in :ref:`ZZ_I` when exact division is possible. >>> z1 / z2 (1 + -1*I) >>> ZZ_I.exquo(z1, z2) (1 + -1*I) >>> z3 / z4 (1/2 + -3/2*I) >>> ZZ_I.exquo(z3, z4) Traceback (most recent call last): ... ExactQuotientFailed: (1 + 3*I) does not divide (5 + 0*I) in ZZ_I The :py:meth:`~.Domain.gcd` method can be used to compute the `gcd`_ of any two elements. >>> ZZ_I.gcd(ZZ_I(10), ZZ_I(2)) (2 + 0*I) >>> ZZ_I.gcd(ZZ_I(5), ZZ_I(2, 1)) (2 + 1*I) .. _Gaussian integers: https://en.wikipedia.org/wiki/Gaussian_integer .. _gcd: https://en.wikipedia.org/wiki/Greatest_common_divisor """ dom = ZZ dtype = GaussianInteger zero = dtype(ZZ(0), ZZ(0)) one = dtype(ZZ(1), ZZ(0)) imag_unit = dtype(ZZ(0), ZZ(1)) units = (one, imag_unit, -one, -imag_unit) # powers of i rep = 'ZZ_I' is_GaussianRing = True is_ZZ_I = True def __init__(self): # override Domain.__init__ """For constructing ZZ_I.""" def get_ring(self): """Returns a ring associated with ``self``. """ return self def get_field(self): """Returns a field associated with ``self``. """ return QQ_I def normalize(self, d, *args): """Return first quadrant element associated with ``d``. Also multiply the other arguments by the same power of i. """ unit = self.canonical_unit(d) d *= unit args = tuple(a*unit for a in args) return (d,) + args if args else d def gcd(self, a, b): """Greatest common divisor of a and b over ZZ_I.""" while b: a, b = b, a % b return self.normalize(a) def lcm(self, a, b): """Least common multiple of a and b over ZZ_I.""" return (a * b) // self.gcd(a, b) def from_GaussianIntegerRing(K1, a, K0): """Convert a ZZ_I element to ZZ_I.""" return a def from_GaussianRationalField(K1, a, K0): """Convert a QQ_I element to ZZ_I.""" return K1.new(ZZ.convert(a.x), ZZ.convert(a.y)) ZZ_I = GaussianInteger._parent = GaussianIntegerRing() class GaussianRationalField(GaussianDomain, Field): r"""Field of Gaussian rationals ``QQ_I`` The :ref:`QQ_I` domain represents the `Gaussian rationals`_ `\mathbb{Q}(i)` as a :py:class:`~.Domain` in the domain system (see :ref:`polys-domainsintro`). By default a :py:class:`~.Poly` created from an expression with coefficients that are combinations of rationals and ``I`` (`\sqrt{-1}`) will have the domain :ref:`QQ_I`. >>> from sympy import Poly, Symbol, I >>> x = Symbol('x') >>> p = Poly(x**2 + I/2) >>> p Poly(x**2 + I/2, x, domain='QQ_I') >>> p.domain QQ_I The polys option ``gaussian=True`` can be used to specify that the domain should be :ref:`QQ_I` even if the coefficients do not contain ``I`` or are all integers. >>> Poly(x**2) Poly(x**2, x, domain='ZZ') >>> Poly(x**2 + I) Poly(x**2 + I, x, domain='ZZ_I') >>> Poly(x**2/2) Poly(1/2*x**2, x, domain='QQ') >>> Poly(x**2, gaussian=True) Poly(x**2, x, domain='QQ_I') >>> Poly(x**2 + I, gaussian=True) Poly(x**2 + I, x, domain='QQ_I') >>> Poly(x**2/2, gaussian=True) Poly(1/2*x**2, x, domain='QQ_I') The :ref:`QQ_I` domain can be used to factorise polynomials that are reducible over the Gaussian rationals. >>> from sympy import factor, QQ_I >>> factor(x**2/4 + 1) (x**2 + 4)/4 >>> factor(x**2/4 + 1, domain='QQ_I') (x - 2*I)*(x + 2*I)/4 >>> factor(x**2/4 + 1, domain=QQ_I) (x - 2*I)*(x + 2*I)/4 It is also possible to specify the :ref:`QQ_I` domain explicitly with polys functions like :py:func:`~.apart`. >>> from sympy import apart >>> apart(1/(1 + x**2)) 1/(x**2 + 1) >>> apart(1/(1 + x**2), domain=QQ_I) I/(2*(x + I)) - I/(2*(x - I)) The corresponding `ring of integers`_ is the domain of the Gaussian integers :ref:`ZZ_I`. Conversely :ref:`QQ_I` is the `field of fractions`_ of :ref:`ZZ_I`. >>> from sympy import ZZ_I, QQ_I, QQ >>> ZZ_I.get_field() QQ_I >>> QQ_I.get_ring() ZZ_I When using the domain directly :ref:`QQ_I` can be used as a constructor. >>> QQ_I(3, 4) (3 + 4*I) >>> QQ_I(5) (5 + 0*I) >>> QQ_I(QQ(2, 3), QQ(4, 5)) (2/3 + 4/5*I) The domain elements of :ref:`QQ_I` are instances of :py:class:`~.GaussianRational` which support the field operations ``+,-,*,**,/``. >>> z1 = QQ_I(5, 1) >>> z2 = QQ_I(2, QQ(1, 2)) >>> z1 (5 + 1*I) >>> z2 (2 + 1/2*I) >>> z1 + z2 (7 + 3/2*I) >>> z1 * z2 (19/2 + 9/2*I) >>> z2 ** 2 (15/4 + 2*I) True division (``/``) in :ref:`QQ_I` gives an element of :ref:`QQ_I` and is always exact. >>> z1 / z2 (42/17 + -2/17*I) >>> QQ_I.exquo(z1, z2) (42/17 + -2/17*I) >>> z1 == (z1/z2)*z2 True Both floor (``//``) and modulo (``%``) division can be used with :py:class:`~.GaussianRational` (see :py:meth:`~.Domain.div`) but division is always exact so there is no remainder. >>> z1 // z2 (42/17 + -2/17*I) >>> z1 % z2 (0 + 0*I) >>> QQ_I.div(z1, z2) ((42/17 + -2/17*I), (0 + 0*I)) >>> (z1//z2)*z2 + z1%z2 == z1 True .. _Gaussian rationals: https://en.wikipedia.org/wiki/Gaussian_rational """ dom = QQ dtype = GaussianRational zero = dtype(QQ(0), QQ(0)) one = dtype(QQ(1), QQ(0)) imag_unit = dtype(QQ(0), QQ(1)) units = (one, imag_unit, -one, -imag_unit) # powers of i rep = 'QQ_I' is_GaussianField = True is_QQ_I = True def __init__(self): # override Domain.__init__ """For constructing QQ_I.""" def get_ring(self): """Returns a ring associated with ``self``. """ return ZZ_I def get_field(self): """Returns a field associated with ``self``. """ return self def as_AlgebraicField(self): """Get equivalent domain as an ``AlgebraicField``. """ return AlgebraicField(self.dom, I) def numer(self, a): """Get the numerator of ``a``.""" ZZ_I = self.get_ring() return ZZ_I.convert(a * self.denom(a)) def denom(self, a): """Get the denominator of ``a``.""" ZZ = self.dom.get_ring() QQ = self.dom ZZ_I = self.get_ring() denom_ZZ = ZZ.lcm(QQ.denom(a.x), QQ.denom(a.y)) return ZZ_I(denom_ZZ, ZZ.zero) def from_GaussianIntegerRing(K1, a, K0): """Convert a ZZ_I element to QQ_I.""" return K1.new(a.x, a.y) def from_GaussianRationalField(K1, a, K0): """Convert a QQ_I element to QQ_I.""" return a QQ_I = GaussianRational._parent = GaussianRationalField() sympy-sympy-1.9/sympy/polys/domains/gmpyfinitefield.py000066400000000000000000000006741412543434000234440ustar00rootroot00000000000000"""Implementation of :class:`GMPYFiniteField` class. """ from sympy.polys.domains.finitefield import FiniteField from sympy.polys.domains.gmpyintegerring import GMPYIntegerRing from sympy.utilities import public @public class GMPYFiniteField(FiniteField): """Finite field based on GMPY integers. """ alias = 'FF_gmpy' def __init__(self, mod, symmetric=True): return super().__init__(mod, GMPYIntegerRing(), symmetric) sympy-sympy-1.9/sympy/polys/domains/gmpyintegerring.py000066400000000000000000000057111412543434000234740ustar00rootroot00000000000000"""Implementation of :class:`GMPYIntegerRing` class. """ from sympy.polys.domains.groundtypes import ( GMPYInteger, SymPyInteger, factorial as gmpy_factorial, gmpy_gcdex, gmpy_gcd, gmpy_lcm, sqrt as gmpy_sqrt, ) from sympy.polys.domains.integerring import IntegerRing from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public @public class GMPYIntegerRing(IntegerRing): """Integer ring based on GMPY's ``mpz`` type. This will be the implementation of :ref:`ZZ` if ``gmpy`` or ``gmpy2`` is installed. Elements will be of type ``gmpy.mpz``. """ dtype = GMPYInteger zero = dtype(0) one = dtype(1) tp = type(one) alias = 'ZZ_gmpy' def __init__(self): """Allow instantiation of this domain. """ def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return SymPyInteger(int(a)) def from_sympy(self, a): """Convert SymPy's Integer to ``dtype``. """ if a.is_Integer: return GMPYInteger(a.p) elif a.is_Float and int(a) == a: return GMPYInteger(int(a)) else: raise CoercionFailed("expected an integer, got %s" % a) def from_FF_python(K1, a, K0): """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """ return GMPYInteger(a.to_int()) def from_ZZ_python(K1, a, K0): """Convert Python's ``int`` to GMPY's ``mpz``. """ return GMPYInteger(a) def from_QQ(K1, a, K0): """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ if a.denominator == 1: return GMPYInteger(a.numerator) def from_QQ_python(K1, a, K0): """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ if a.denominator == 1: return GMPYInteger(a.numerator) def from_FF_gmpy(K1, a, K0): """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """ return a.to_int() def from_ZZ_gmpy(K1, a, K0): """Convert GMPY's ``mpz`` to GMPY's ``mpz``. """ return a def from_QQ_gmpy(K1, a, K0): """Convert GMPY ``mpq`` to GMPY's ``mpz``. """ if a.denominator == 1: return a.numerator def from_RealField(K1, a, K0): """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """ p, q = K0.to_rational(a) if q == 1: return GMPYInteger(p) def from_GaussianIntegerRing(K1, a, K0): if a.y == 0: return a.x def gcdex(self, a, b): """Compute extended GCD of ``a`` and ``b``. """ h, s, t = gmpy_gcdex(a, b) return s, t, h def gcd(self, a, b): """Compute GCD of ``a`` and ``b``. """ return gmpy_gcd(a, b) def lcm(self, a, b): """Compute LCM of ``a`` and ``b``. """ return gmpy_lcm(a, b) def sqrt(self, a): """Compute square root of ``a``. """ return gmpy_sqrt(a) def factorial(self, a): """Compute factorial of ``a``. """ return gmpy_factorial(a) sympy-sympy-1.9/sympy/polys/domains/gmpyrationalfield.py000066400000000000000000000061521412543434000237740ustar00rootroot00000000000000"""Implementation of :class:`GMPYRationalField` class. """ from sympy.polys.domains.groundtypes import ( GMPYRational, SymPyRational, gmpy_numer, gmpy_denom, factorial as gmpy_factorial, ) from sympy.polys.domains.rationalfield import RationalField from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public @public class GMPYRationalField(RationalField): """Rational field based on GMPY's ``mpq`` type. This will be the implementation of :ref:`QQ` if ``gmpy`` or ``gmpy2`` is installed. Elements will be of type ``gmpy.mpq``. """ dtype = GMPYRational zero = dtype(0) one = dtype(1) tp = type(one) alias = 'QQ_gmpy' def __init__(self): pass def get_ring(self): """Returns ring associated with ``self``. """ from sympy.polys.domains import GMPYIntegerRing return GMPYIntegerRing() def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return SymPyRational(int(gmpy_numer(a)), int(gmpy_denom(a))) def from_sympy(self, a): """Convert SymPy's Integer to ``dtype``. """ if a.is_Rational: return GMPYRational(a.p, a.q) elif a.is_Float: from sympy.polys.domains import RR return GMPYRational(*map(int, RR.to_rational(a))) else: raise CoercionFailed("expected ``Rational`` object, got %s" % a) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return GMPYRational(a) def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return GMPYRational(a.numerator, a.denominator) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return GMPYRational(a) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return a def from_GaussianRationalField(K1, a, K0): """Convert a ``GaussianElement`` object to ``dtype``. """ if a.y == 0: return GMPYRational(a.x) def from_RealField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return GMPYRational(*map(int, K0.to_rational(a))) def exquo(self, a, b): """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """ return GMPYRational(a) / GMPYRational(b) def quo(self, a, b): """Quotient of ``a`` and ``b``, implies ``__truediv__``. """ return GMPYRational(a) / GMPYRational(b) def rem(self, a, b): """Remainder of ``a`` and ``b``, implies nothing. """ return self.zero def div(self, a, b): """Division of ``a`` and ``b``, implies ``__truediv__``. """ return GMPYRational(a) / GMPYRational(b), self.zero def numer(self, a): """Returns numerator of ``a``. """ return a.numerator def denom(self, a): """Returns denominator of ``a``. """ return a.denominator def factorial(self, a): """Returns factorial of ``a``. """ return GMPYRational(gmpy_factorial(int(a))) sympy-sympy-1.9/sympy/polys/domains/groundtypes.py000066400000000000000000000031201412543434000226350ustar00rootroot00000000000000"""Ground types for various mathematical domains in SymPy. """ import builtins from sympy.external.gmpy import HAS_GMPY, factorial, sqrt PythonInteger = builtins.int PythonReal = builtins.float PythonComplex = builtins.complex from .pythonrational import PythonRational from sympy.core.numbers import ( igcdex as python_gcdex, igcd2 as python_gcd, ilcm as python_lcm, ) from sympy import ( Float as SymPyReal, Integer as SymPyInteger, Rational as SymPyRational, ) if HAS_GMPY == 2: from gmpy2 import ( mpz as GMPYInteger, mpq as GMPYRational, numer as gmpy_numer, denom as gmpy_denom, gcdext as gmpy_gcdex, gcd as gmpy_gcd, lcm as gmpy_lcm, qdiv as gmpy_qdiv, ) gcdex = gmpy_gcdex gcd = gmpy_gcd lcm = gmpy_lcm else: class _GMPYInteger: def __init__(self, obj): pass class _GMPYRational: def __init__(self, obj): pass GMPYInteger = _GMPYInteger GMPYRational = _GMPYRational gmpy_numer = None gmpy_denom = None gmpy_gcdex = None gmpy_gcd = None gmpy_lcm = None gmpy_qdiv = None gcdex = python_gcdex gcd = python_gcd lcm = python_lcm __all__ = [ 'PythonInteger', 'PythonReal', 'PythonComplex', 'PythonRational', 'python_gcdex', 'python_gcd', 'python_lcm', 'SymPyReal', 'SymPyInteger', 'SymPyRational', 'GMPYInteger', 'GMPYRational', 'gmpy_numer', 'gmpy_denom', 'gmpy_gcdex', 'gmpy_gcd', 'gmpy_lcm', 'gmpy_qdiv', 'factorial', 'sqrt', 'GMPYInteger', 'GMPYRational', ] sympy-sympy-1.9/sympy/polys/domains/integerring.py000066400000000000000000000132771412543434000226050ustar00rootroot00000000000000"""Implementation of :class:`IntegerRing` class. """ from sympy.external.gmpy import MPZ, HAS_GMPY from sympy.polys.domains.groundtypes import ( SymPyInteger, factorial, gcdex, gcd, lcm, sqrt, ) from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.ring import Ring from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public import math @public class IntegerRing(Ring, CharacteristicZero, SimpleDomain): r"""The domain ``ZZ`` representing the integers `\mathbb{Z}`. The :py:class:`IntegerRing` class represents the ring of integers as a :py:class:`~.Domain` in the domain system. :py:class:`IntegerRing` is a super class of :py:class:`PythonIntegerRing` and :py:class:`GMPYIntegerRing` one of which will be the implementation for :ref:`ZZ` depending on whether or not ``gmpy`` or ``gmpy2`` is installed. See also ======== Domain """ rep = 'ZZ' alias = 'ZZ' dtype = MPZ zero = dtype(0) one = dtype(1) tp = type(one) is_IntegerRing = is_ZZ = True is_Numerical = True is_PID = True has_assoc_Ring = True has_assoc_Field = True def __init__(self): """Allow instantiation of this domain. """ def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return SymPyInteger(int(a)) def from_sympy(self, a): """Convert SymPy's Integer to ``dtype``. """ if a.is_Integer: return MPZ(a.p) elif a.is_Float and int(a) == a: return MPZ(int(a)) else: raise CoercionFailed("expected an integer, got %s" % a) def get_field(self): r"""Return the associated field of fractions :ref:`QQ` Returns ======= :ref:`QQ`: The associated field of fractions :ref:`QQ`, a :py:class:`~.Domain` representing the rational numbers `\mathbb{Q}`. Examples ======== >>> from sympy import ZZ >>> ZZ.get_field() QQ """ from sympy.polys.domains import QQ return QQ def algebraic_field(self, *extension): r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`. Parameters ========== *extension: One or more Expr. Generators of the extension. These should be expressions that are algebraic over `\mathbb{Q}`. Returns ======= :py:class:`~.AlgebraicField` A :py:class:`~.Domain` representing the algebraic field extension. Examples ======== >>> from sympy import ZZ, sqrt >>> ZZ.algebraic_field(sqrt(2)) QQ """ return self.get_field().algebraic_field(*extension) def from_AlgebraicField(K1, a, K0): """Convert a :py:class:`~.ANP` object to :ref:`ZZ`. See :py:meth:`~.Domain.convert`. """ if a.is_ground: return K1.convert(a.LC(), K0.dom) def log(self, a, b): r"""logarithm of *a* to the base *b* Parameters ========== a: number b: number Returns ======= $\\lfloor\log(a, b)\\rfloor$: Floor of the logarithm of *a* to the base *b* Examples ======== >>> from sympy import ZZ >>> ZZ.log(ZZ(8), ZZ(2)) 3 >>> ZZ.log(ZZ(9), ZZ(2)) 3 Notes ===== This function uses ``math.log`` which is based on ``float`` so it will fail for large integer arguments. """ return self.dtype(math.log(int(a), b)) def from_FF(K1, a, K0): """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """ return MPZ(a.to_int()) def from_FF_python(K1, a, K0): """Convert ``ModularInteger(int)`` to GMPY's ``mpz``. """ return MPZ(a.to_int()) def from_ZZ(K1, a, K0): """Convert Python's ``int`` to GMPY's ``mpz``. """ return MPZ(a) def from_ZZ_python(K1, a, K0): """Convert Python's ``int`` to GMPY's ``mpz``. """ return MPZ(a) def from_QQ(K1, a, K0): """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ if a.denominator == 1: return MPZ(a.numerator) def from_QQ_python(K1, a, K0): """Convert Python's ``Fraction`` to GMPY's ``mpz``. """ if a.denominator == 1: return MPZ(a.numerator) def from_FF_gmpy(K1, a, K0): """Convert ``ModularInteger(mpz)`` to GMPY's ``mpz``. """ return a.to_int() def from_ZZ_gmpy(K1, a, K0): """Convert GMPY's ``mpz`` to GMPY's ``mpz``. """ return a def from_QQ_gmpy(K1, a, K0): """Convert GMPY ``mpq`` to GMPY's ``mpz``. """ if a.denominator == 1: return a.numerator def from_RealField(K1, a, K0): """Convert mpmath's ``mpf`` to GMPY's ``mpz``. """ p, q = K0.to_rational(a) if q == 1: return MPZ(p) def from_GaussianIntegerRing(K1, a, K0): if a.y == 0: return a.x def gcdex(self, a, b): """Compute extended GCD of ``a`` and ``b``. """ h, s, t = gcdex(a, b) if HAS_GMPY: return s, t, h else: return h, s, t def gcd(self, a, b): """Compute GCD of ``a`` and ``b``. """ return gcd(a, b) def lcm(self, a, b): """Compute LCM of ``a`` and ``b``. """ return lcm(a, b) def sqrt(self, a): """Compute square root of ``a``. """ return sqrt(a) def factorial(self, a): """Compute factorial of ``a``. """ return factorial(a) ZZ = IntegerRing() sympy-sympy-1.9/sympy/polys/domains/modularinteger.py000066400000000000000000000117371412543434000233100ustar00rootroot00000000000000"""Implementation of :class:`ModularInteger` class. """ from typing import Any, Dict, Tuple, Type import operator from sympy.polys.polyutils import PicklableWithSlots from sympy.polys.polyerrors import CoercionFailed from sympy.polys.domains.domainelement import DomainElement from sympy.utilities import public @public class ModularInteger(PicklableWithSlots, DomainElement): """A class representing a modular integer. """ mod, dom, sym, _parent = None, None, None, None __slots__ = ('val',) def parent(self): return self._parent def __init__(self, val): if isinstance(val, self.__class__): self.val = val.val % self.mod else: self.val = self.dom.convert(val) % self.mod def __hash__(self): return hash((self.val, self.mod)) def __repr__(self): return "%s(%s)" % (self.__class__.__name__, self.val) def __str__(self): return "%s mod %s" % (self.val, self.mod) def __int__(self): return int(self.to_int()) def to_int(self): if self.sym: if self.val <= self.mod // 2: return self.val else: return self.val - self.mod else: return self.val def __pos__(self): return self def __neg__(self): return self.__class__(-self.val) @classmethod def _get_val(cls, other): if isinstance(other, cls): return other.val else: try: return cls.dom.convert(other) except CoercionFailed: return None def __add__(self, other): val = self._get_val(other) if val is not None: return self.__class__(self.val + val) else: return NotImplemented def __radd__(self, other): return self.__add__(other) def __sub__(self, other): val = self._get_val(other) if val is not None: return self.__class__(self.val - val) else: return NotImplemented def __rsub__(self, other): return (-self).__add__(other) def __mul__(self, other): val = self._get_val(other) if val is not None: return self.__class__(self.val * val) else: return NotImplemented def __rmul__(self, other): return self.__mul__(other) def __truediv__(self, other): val = self._get_val(other) if val is not None: return self.__class__(self.val * self._invert(val)) else: return NotImplemented def __rtruediv__(self, other): return self.invert().__mul__(other) def __mod__(self, other): val = self._get_val(other) if val is not None: return self.__class__(self.val % val) else: return NotImplemented def __rmod__(self, other): val = self._get_val(other) if val is not None: return self.__class__(val % self.val) else: return NotImplemented def __pow__(self, exp): if not exp: return self.__class__(self.dom.one) if exp < 0: val, exp = self.invert().val, -exp else: val = self.val return self.__class__(pow(val, int(exp), self.mod)) def _compare(self, other, op): val = self._get_val(other) if val is not None: return op(self.val, val % self.mod) else: return NotImplemented def __eq__(self, other): return self._compare(other, operator.eq) def __ne__(self, other): return self._compare(other, operator.ne) def __lt__(self, other): return self._compare(other, operator.lt) def __le__(self, other): return self._compare(other, operator.le) def __gt__(self, other): return self._compare(other, operator.gt) def __ge__(self, other): return self._compare(other, operator.ge) def __bool__(self): return bool(self.val) @classmethod def _invert(cls, value): return cls.dom.invert(value, cls.mod) def invert(self): return self.__class__(self._invert(self.val)) _modular_integer_cache = {} # type: Dict[Tuple[Any, Any, Any], Type[ModularInteger]] def ModularIntegerFactory(_mod, _dom, _sym, parent): """Create custom class for specific integer modulus.""" try: _mod = _dom.convert(_mod) except CoercionFailed: ok = False else: ok = True if not ok or _mod < 1: raise ValueError("modulus must be a positive integer, got %s" % _mod) key = _mod, _dom, _sym try: cls = _modular_integer_cache[key] except KeyError: class cls(ModularInteger): mod, dom, sym = _mod, _dom, _sym _parent = parent if _sym: cls.__name__ = "SymmetricModularIntegerMod%s" % _mod else: cls.__name__ = "ModularIntegerMod%s" % _mod _modular_integer_cache[key] = cls return cls sympy-sympy-1.9/sympy/polys/domains/mpelements.py000066400000000000000000000110101412543434000224200ustar00rootroot00000000000000"""Real and complex elements. """ from sympy.polys.domains.domainelement import DomainElement from sympy.utilities import public from mpmath.ctx_mp_python import PythonMPContext, _mpf, _mpc, _constant from mpmath.libmp import (MPZ_ONE, fzero, fone, finf, fninf, fnan, round_nearest, mpf_mul, repr_dps, int_types, from_int, from_float, from_str, to_rational) from mpmath.rational import mpq @public class RealElement(_mpf, DomainElement): """An element of a real domain. """ __slots__ = ('__mpf__',) def _set_mpf(self, val): self.__mpf__ = val _mpf_ = property(lambda self: self.__mpf__, _set_mpf) def parent(self): return self.context._parent @public class ComplexElement(_mpc, DomainElement): """An element of a complex domain. """ __slots__ = ('__mpc__',) def _set_mpc(self, val): self.__mpc__ = val _mpc_ = property(lambda self: self.__mpc__, _set_mpc) def parent(self): return self.context._parent new = object.__new__ @public class MPContext(PythonMPContext): def __init__(ctx, prec=53, dps=None, tol=None, real=False): ctx._prec_rounding = [prec, round_nearest] if dps is None: ctx._set_prec(prec) else: ctx._set_dps(dps) ctx.mpf = RealElement ctx.mpc = ComplexElement ctx.mpf._ctxdata = [ctx.mpf, new, ctx._prec_rounding] ctx.mpc._ctxdata = [ctx.mpc, new, ctx._prec_rounding] if real: ctx.mpf.context = ctx else: ctx.mpc.context = ctx ctx.constant = _constant ctx.constant._ctxdata = [ctx.mpf, new, ctx._prec_rounding] ctx.constant.context = ctx ctx.types = [ctx.mpf, ctx.mpc, ctx.constant] ctx.trap_complex = True ctx.pretty = True if tol is None: ctx.tol = ctx._make_tol() elif tol is False: ctx.tol = fzero else: ctx.tol = ctx._convert_tol(tol) ctx.tolerance = ctx.make_mpf(ctx.tol) if not ctx.tolerance: ctx.max_denom = 1000000 else: ctx.max_denom = int(1/ctx.tolerance) ctx.zero = ctx.make_mpf(fzero) ctx.one = ctx.make_mpf(fone) ctx.j = ctx.make_mpc((fzero, fone)) ctx.inf = ctx.make_mpf(finf) ctx.ninf = ctx.make_mpf(fninf) ctx.nan = ctx.make_mpf(fnan) def _make_tol(ctx): hundred = (0, 25, 2, 5) eps = (0, MPZ_ONE, 1-ctx.prec, 1) return mpf_mul(hundred, eps) def make_tol(ctx): return ctx.make_mpf(ctx._make_tol()) def _convert_tol(ctx, tol): if isinstance(tol, int_types): return from_int(tol) if isinstance(tol, float): return from_float(tol) if hasattr(tol, "_mpf_"): return tol._mpf_ prec, rounding = ctx._prec_rounding if isinstance(tol, str): return from_str(tol, prec, rounding) raise ValueError("expected a real number, got %s" % tol) def _convert_fallback(ctx, x, strings): raise TypeError("cannot create mpf from " + repr(x)) @property def _repr_digits(ctx): return repr_dps(ctx._prec) @property def _str_digits(ctx): return ctx._dps def to_rational(ctx, s, limit=True): p, q = to_rational(s._mpf_) if not limit or q <= ctx.max_denom: return p, q p0, q0, p1, q1 = 0, 1, 1, 0 n, d = p, q while True: a = n//d q2 = q0 + a*q1 if q2 > ctx.max_denom: break p0, q0, p1, q1 = p1, q1, p0 + a*p1, q2 n, d = d, n - a*d k = (ctx.max_denom - q0)//q1 number = mpq(p, q) bound1 = mpq(p0 + k*p1, q0 + k*q1) bound2 = mpq(p1, q1) if not bound2 or not bound1: return p, q elif abs(bound2 - number) <= abs(bound1 - number): return bound2._mpq_ else: return bound1._mpq_ def almosteq(ctx, s, t, rel_eps=None, abs_eps=None): t = ctx.convert(t) if abs_eps is None and rel_eps is None: rel_eps = abs_eps = ctx.tolerance or ctx.make_tol() if abs_eps is None: abs_eps = ctx.convert(rel_eps) elif rel_eps is None: rel_eps = ctx.convert(abs_eps) diff = abs(s-t) if diff <= abs_eps: return True abss = abs(s) abst = abs(t) if abss < abst: err = diff/abst else: err = diff/abss return err <= rel_eps sympy-sympy-1.9/sympy/polys/domains/old_fractionfield.py000066400000000000000000000140421412543434000237260ustar00rootroot00000000000000"""Implementation of :class:`FractionField` class. """ from sympy.polys.domains.field import Field from sympy.polys.domains.compositedomain import CompositeDomain from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.polyclasses import DMF from sympy.polys.polyerrors import GeneratorsNeeded from sympy.polys.polyutils import dict_from_basic, basic_from_dict, _dict_reorder from sympy.utilities import public @public class FractionField(Field, CharacteristicZero, CompositeDomain): """A class for representing rational function fields. """ dtype = DMF is_FractionField = is_Frac = True has_assoc_Ring = True has_assoc_Field = True def __init__(self, dom, *gens): if not gens: raise GeneratorsNeeded("generators not specified") lev = len(gens) - 1 self.ngens = len(gens) self.zero = self.dtype.zero(lev, dom, ring=self) self.one = self.dtype.one(lev, dom, ring=self) self.domain = self.dom = dom self.symbols = self.gens = gens def new(self, element): return self.dtype(element, self.dom, len(self.gens) - 1, ring=self) def __str__(self): return str(self.dom) + '(' + ','.join(map(str, self.gens)) + ')' def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.dom, self.gens)) def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ return isinstance(other, FractionField) and \ self.dtype == other.dtype and self.dom == other.dom and self.gens == other.gens def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return (basic_from_dict(a.numer().to_sympy_dict(), *self.gens) / basic_from_dict(a.denom().to_sympy_dict(), *self.gens)) def from_sympy(self, a): """Convert SymPy's expression to ``dtype``. """ p, q = a.as_numer_denom() num, _ = dict_from_basic(p, gens=self.gens) den, _ = dict_from_basic(q, gens=self.gens) for k, v in num.items(): num[k] = self.dom.from_sympy(v) for k, v in den.items(): den[k] = self.dom.from_sympy(v) return self((num, den)).cancel() def from_ZZ(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_RealField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_GlobalPolynomialRing(K1, a, K0): """Convert a ``DMF`` object to ``dtype``. """ if K1.gens == K0.gens: if K1.dom == K0.dom: return K1(a.rep) else: return K1(a.convert(K1.dom).rep) else: monoms, coeffs = _dict_reorder(a.to_dict(), K0.gens, K1.gens) if K1.dom != K0.dom: coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] return K1(dict(zip(monoms, coeffs))) def from_FractionField(K1, a, K0): """ Convert a fraction field element to another fraction field. Examples ======== >>> from sympy.polys.polyclasses import DMF >>> from sympy.polys.domains import ZZ, QQ >>> from sympy.abc import x >>> f = DMF(([ZZ(1), ZZ(2)], [ZZ(1), ZZ(1)]), ZZ) >>> QQx = QQ.old_frac_field(x) >>> ZZx = ZZ.old_frac_field(x) >>> QQx.from_FractionField(f, ZZx) (x + 2)/(x + 1) """ if K1.gens == K0.gens: if K1.dom == K0.dom: return a else: return K1((a.numer().convert(K1.dom).rep, a.denom().convert(K1.dom).rep)) elif set(K0.gens).issubset(K1.gens): nmonoms, ncoeffs = _dict_reorder( a.numer().to_dict(), K0.gens, K1.gens) dmonoms, dcoeffs = _dict_reorder( a.denom().to_dict(), K0.gens, K1.gens) if K1.dom != K0.dom: ncoeffs = [ K1.dom.convert(c, K0.dom) for c in ncoeffs ] dcoeffs = [ K1.dom.convert(c, K0.dom) for c in dcoeffs ] return K1((dict(zip(nmonoms, ncoeffs)), dict(zip(dmonoms, dcoeffs)))) def get_ring(self): """Returns a ring associated with ``self``. """ from sympy.polys.domains import PolynomialRing return PolynomialRing(self.dom, *self.gens) def poly_ring(self, *gens): """Returns a polynomial ring, i.e. `K[X]`. """ raise NotImplementedError('nested domains not allowed') def frac_field(self, *gens): """Returns a fraction field, i.e. `K(X)`. """ raise NotImplementedError('nested domains not allowed') def is_positive(self, a): """Returns True if ``a`` is positive. """ return self.dom.is_positive(a.numer().LC()) def is_negative(self, a): """Returns True if ``a`` is negative. """ return self.dom.is_negative(a.numer().LC()) def is_nonpositive(self, a): """Returns True if ``a`` is non-positive. """ return self.dom.is_nonpositive(a.numer().LC()) def is_nonnegative(self, a): """Returns True if ``a`` is non-negative. """ return self.dom.is_nonnegative(a.numer().LC()) def numer(self, a): """Returns numerator of ``a``. """ return a.numer() def denom(self, a): """Returns denominator of ``a``. """ return a.denom() def factorial(self, a): """Returns factorial of ``a``. """ return self.dtype(self.dom.factorial(a)) sympy-sympy-1.9/sympy/polys/domains/old_polynomialring.py000066400000000000000000000351001412543434000241560ustar00rootroot00000000000000"""Implementation of :class:`PolynomialRing` class. """ from sympy.core.compatibility import iterable from sympy.polys.agca.modules import FreeModulePolyRing from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.compositedomain import CompositeDomain from sympy.polys.domains.old_fractionfield import FractionField from sympy.polys.domains.ring import Ring from sympy.polys.orderings import monomial_key, build_product_order from sympy.polys.polyclasses import DMP, DMF from sympy.polys.polyerrors import (GeneratorsNeeded, PolynomialError, CoercionFailed, ExactQuotientFailed, NotReversible) from sympy.polys.polyutils import dict_from_basic, basic_from_dict, _dict_reorder from sympy.utilities import public # XXX why does this derive from CharacteristicZero??? @public class PolynomialRingBase(Ring, CharacteristicZero, CompositeDomain): """ Base class for generalized polynomial rings. This base class should be used for uniform access to generalized polynomial rings. Subclasses only supply information about the element storage etc. Do not instantiate. """ has_assoc_Ring = True has_assoc_Field = True default_order = "grevlex" def __init__(self, dom, *gens, **opts): if not gens: raise GeneratorsNeeded("generators not specified") lev = len(gens) - 1 self.ngens = len(gens) self.zero = self.dtype.zero(lev, dom, ring=self) self.one = self.dtype.one(lev, dom, ring=self) self.domain = self.dom = dom self.symbols = self.gens = gens # NOTE 'order' may not be set if inject was called through CompositeDomain self.order = opts.get('order', monomial_key(self.default_order)) def new(self, element): return self.dtype(element, self.dom, len(self.gens) - 1, ring=self) def __str__(self): s_order = str(self.order) orderstr = ( " order=" + s_order) if s_order != self.default_order else "" return str(self.dom) + '[' + ','.join(map(str, self.gens)) + orderstr + ']' def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.dom, self.gens, self.order)) def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ return isinstance(other, PolynomialRingBase) and \ self.dtype == other.dtype and self.dom == other.dom and \ self.gens == other.gens and self.order == other.order def from_ZZ(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_RealField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return K1(K1.dom.convert(a, K0)) def from_AlgebraicField(K1, a, K0): """Convert a ``ANP`` object to ``dtype``. """ if K1.dom == K0: return K1(a) def from_PolynomialRing(K1, a, K0): """Convert a ``PolyElement`` object to ``dtype``. """ if K1.gens == K0.symbols: if K1.dom == K0.dom: return K1(dict(a)) # set the correct ring else: convert_dom = lambda c: K1.dom.convert_from(c, K0.dom) return K1({m: convert_dom(c) for m, c in a.items()}) else: monoms, coeffs = _dict_reorder(a.to_dict(), K0.symbols, K1.gens) if K1.dom != K0.dom: coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] return K1(dict(zip(monoms, coeffs))) def from_GlobalPolynomialRing(K1, a, K0): """Convert a ``DMP`` object to ``dtype``. """ if K1.gens == K0.gens: if K1.dom == K0.dom: return K1(a.rep) # set the correct ring else: return K1(a.convert(K1.dom).rep) else: monoms, coeffs = _dict_reorder(a.to_dict(), K0.gens, K1.gens) if K1.dom != K0.dom: coeffs = [ K1.dom.convert(c, K0.dom) for c in coeffs ] return K1(dict(zip(monoms, coeffs))) def get_field(self): """Returns a field associated with ``self``. """ return FractionField(self.dom, *self.gens) def poly_ring(self, *gens): """Returns a polynomial ring, i.e. ``K[X]``. """ raise NotImplementedError('nested domains not allowed') def frac_field(self, *gens): """Returns a fraction field, i.e. ``K(X)``. """ raise NotImplementedError('nested domains not allowed') def revert(self, a): try: return 1/a except (ExactQuotientFailed, ZeroDivisionError): raise NotReversible('%s is not a unit' % a) def gcdex(self, a, b): """Extended GCD of ``a`` and ``b``. """ return a.gcdex(b) def gcd(self, a, b): """Returns GCD of ``a`` and ``b``. """ return a.gcd(b) def lcm(self, a, b): """Returns LCM of ``a`` and ``b``. """ return a.lcm(b) def factorial(self, a): """Returns factorial of ``a``. """ return self.dtype(self.dom.factorial(a)) def _vector_to_sdm(self, v, order): """ For internal use by the modules class. Convert an iterable of elements of this ring into a sparse distributed module element. """ raise NotImplementedError def _sdm_to_dics(self, s, n): """Helper for _sdm_to_vector.""" from sympy.polys.distributedmodules import sdm_to_dict dic = sdm_to_dict(s) res = [{} for _ in range(n)] for k, v in dic.items(): res[k[0]][k[1:]] = v return res def _sdm_to_vector(self, s, n): """ For internal use by the modules class. Convert a sparse distributed module into a list of length ``n``. Examples ======== >>> from sympy import QQ, ilex >>> from sympy.abc import x, y >>> R = QQ.old_poly_ring(x, y, order=ilex) >>> L = [((1, 1, 1), QQ(1)), ((0, 1, 0), QQ(1)), ((0, 0, 1), QQ(2))] >>> R._sdm_to_vector(L, 2) [x + 2*y, x*y] """ dics = self._sdm_to_dics(s, n) # NOTE this works for global and local rings! return [self(x) for x in dics] def free_module(self, rank): """ Generate a free module of rank ``rank`` over ``self``. Examples ======== >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(2) QQ[x]**2 """ return FreeModulePolyRing(self, rank) def _vector_to_sdm_helper(v, order): """Helper method for common code in Global and Local poly rings.""" from sympy.polys.distributedmodules import sdm_from_dict d = {} for i, e in enumerate(v): for key, value in e.to_dict().items(): d[(i,) + key] = value return sdm_from_dict(d, order) @public class GlobalPolynomialRing(PolynomialRingBase): """A true polynomial ring, with objects DMP. """ is_PolynomialRing = is_Poly = True dtype = DMP def from_FractionField(K1, a, K0): """ Convert a ``DMF`` object to ``DMP``. Examples ======== >>> from sympy.polys.polyclasses import DMP, DMF >>> from sympy.polys.domains import ZZ >>> from sympy.abc import x >>> f = DMF(([ZZ(1), ZZ(1)], [ZZ(1)]), ZZ) >>> K = ZZ.old_frac_field(x) >>> F = ZZ.old_poly_ring(x).from_FractionField(f, K) >>> F == DMP([ZZ(1), ZZ(1)], ZZ) True >>> type(F) """ if a.denom().is_one: return K1.from_GlobalPolynomialRing(a.numer(), K0) def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return basic_from_dict(a.to_sympy_dict(), *self.gens) def from_sympy(self, a): """Convert SymPy's expression to ``dtype``. """ try: rep, _ = dict_from_basic(a, gens=self.gens) except PolynomialError: raise CoercionFailed("can't convert %s to type %s" % (a, self)) for k, v in rep.items(): rep[k] = self.dom.from_sympy(v) return self(rep) def is_positive(self, a): """Returns True if ``LC(a)`` is positive. """ return self.dom.is_positive(a.LC()) def is_negative(self, a): """Returns True if ``LC(a)`` is negative. """ return self.dom.is_negative(a.LC()) def is_nonpositive(self, a): """Returns True if ``LC(a)`` is non-positive. """ return self.dom.is_nonpositive(a.LC()) def is_nonnegative(self, a): """Returns True if ``LC(a)`` is non-negative. """ return self.dom.is_nonnegative(a.LC()) def _vector_to_sdm(self, v, order): """ Examples ======== >>> from sympy import lex, QQ >>> from sympy.abc import x, y >>> R = QQ.old_poly_ring(x, y) >>> f = R.convert(x + 2*y) >>> g = R.convert(x * y) >>> R._vector_to_sdm([f, g], lex) [((1, 1, 1), 1), ((0, 1, 0), 1), ((0, 0, 1), 2)] """ return _vector_to_sdm_helper(v, order) class GeneralizedPolynomialRing(PolynomialRingBase): """A generalized polynomial ring, with objects DMF. """ dtype = DMF def new(self, a): """Construct an element of ``self`` domain from ``a``. """ res = self.dtype(a, self.dom, len(self.gens) - 1, ring=self) # make sure res is actually in our ring if res.denom().terms(order=self.order)[0][0] != (0,)*len(self.gens): from sympy.printing.str import sstr raise CoercionFailed("denominator %s not allowed in %s" % (sstr(res), self)) return res def __contains__(self, a): try: a = self.convert(a) except CoercionFailed: return False return a.denom().terms(order=self.order)[0][0] == (0,)*len(self.gens) def from_FractionField(K1, a, K0): dmf = K1.get_field().from_FractionField(a, K0) return K1((dmf.num, dmf.den)) def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return (basic_from_dict(a.numer().to_sympy_dict(), *self.gens) / basic_from_dict(a.denom().to_sympy_dict(), *self.gens)) def from_sympy(self, a): """Convert SymPy's expression to ``dtype``. """ p, q = a.as_numer_denom() num, _ = dict_from_basic(p, gens=self.gens) den, _ = dict_from_basic(q, gens=self.gens) for k, v in num.items(): num[k] = self.dom.from_sympy(v) for k, v in den.items(): den[k] = self.dom.from_sympy(v) return self((num, den)).cancel() def _vector_to_sdm(self, v, order): """ Turn an iterable into a sparse distributed module. Note that the vector is multiplied by a unit first to make all entries polynomials. Examples ======== >>> from sympy import ilex, QQ >>> from sympy.abc import x, y >>> R = QQ.old_poly_ring(x, y, order=ilex) >>> f = R.convert((x + 2*y) / (1 + x)) >>> g = R.convert(x * y) >>> R._vector_to_sdm([f, g], ilex) [((0, 0, 1), 2), ((0, 1, 0), 1), ((1, 1, 1), 1), ((1, 2, 1), 1)] """ # NOTE this is quite inefficient... u = self.one.numer() for x in v: u *= x.denom() return _vector_to_sdm_helper([x.numer()*u/x.denom() for x in v], order) @public def PolynomialRing(dom, *gens, **opts): r""" Create a generalized multivariate polynomial ring. A generalized polynomial ring is defined by a ground field `K`, a set of generators (typically `x_1, \ldots, x_n`) and a monomial order `<`. The monomial order can be global, local or mixed. In any case it induces a total ordering on the monomials, and there exists for every (non-zero) polynomial `f \in K[x_1, \ldots, x_n]` a well-defined "leading monomial" `LM(f) = LM(f, >)`. One can then define a multiplicative subset `S = S_> = \{f \in K[x_1, \ldots, x_n] | LM(f) = 1\}`. The generalized polynomial ring corresponding to the monomial order is `R = S^{-1}K[x_1, \ldots, x_n]`. If `>` is a so-called global order, that is `1` is the smallest monomial, then we just have `S = K` and `R = K[x_1, \ldots, x_n]`. Examples ======== A few examples may make this clearer. >>> from sympy.abc import x, y >>> from sympy import QQ Our first ring uses global lexicographic order. >>> R1 = QQ.old_poly_ring(x, y, order=(("lex", x, y),)) The second ring uses local lexicographic order. Note that when using a single (non-product) order, you can just specify the name and omit the variables: >>> R2 = QQ.old_poly_ring(x, y, order="ilex") The third and fourth rings use a mixed orders: >>> o1 = (("ilex", x), ("lex", y)) >>> o2 = (("lex", x), ("ilex", y)) >>> R3 = QQ.old_poly_ring(x, y, order=o1) >>> R4 = QQ.old_poly_ring(x, y, order=o2) We will investigate what elements of `K(x, y)` are contained in the various rings. >>> L = [x, 1/x, y/(1 + x), 1/(1 + y), 1/(1 + x*y)] >>> test = lambda R: [f in R for f in L] The first ring is just `K[x, y]`: >>> test(R1) [True, False, False, False, False] The second ring is R1 localised at the maximal ideal (x, y): >>> test(R2) [True, False, True, True, True] The third ring is R1 localised at the prime ideal (x): >>> test(R3) [True, False, True, False, True] Finally the fourth ring is R1 localised at `S = K[x, y] \setminus yK[y]`: >>> test(R4) [True, False, False, True, False] """ order = opts.get("order", GeneralizedPolynomialRing.default_order) if iterable(order): order = build_product_order(order, gens) order = monomial_key(order) opts['order'] = order if order.is_global: return GlobalPolynomialRing(dom, *gens, **opts) else: return GeneralizedPolynomialRing(dom, *gens, **opts) sympy-sympy-1.9/sympy/polys/domains/polynomialring.py000066400000000000000000000140111412543434000233160ustar00rootroot00000000000000"""Implementation of :class:`PolynomialRing` class. """ from sympy.polys.domains.ring import Ring from sympy.polys.domains.compositedomain import CompositeDomain from sympy.polys.polyerrors import CoercionFailed, GeneratorsError from sympy.utilities import public @public class PolynomialRing(Ring, CompositeDomain): """A class for representing multivariate polynomial rings. """ is_PolynomialRing = is_Poly = True has_assoc_Ring = True has_assoc_Field = True def __init__(self, domain_or_ring, symbols=None, order=None): from sympy.polys.rings import PolyRing if isinstance(domain_or_ring, PolyRing) and symbols is None and order is None: ring = domain_or_ring else: ring = PolyRing(symbols, domain_or_ring, order) self.ring = ring self.dtype = ring.dtype self.gens = ring.gens self.ngens = ring.ngens self.symbols = ring.symbols self.domain = ring.domain if symbols: if ring.domain.is_Field and ring.domain.is_Exact and len(symbols)==1: self.is_PID = True # TODO: remove this self.dom = self.domain def new(self, element): return self.ring.ring_new(element) @property def zero(self): return self.ring.zero @property def one(self): return self.ring.one @property def order(self): return self.ring.order def __str__(self): return str(self.domain) + '[' + ','.join(map(str, self.symbols)) + ']' def __hash__(self): return hash((self.__class__.__name__, self.dtype.ring, self.domain, self.symbols)) def __eq__(self, other): """Returns `True` if two domains are equivalent. """ return isinstance(other, PolynomialRing) and \ (self.dtype.ring, self.domain, self.symbols) == \ (other.dtype.ring, other.domain, other.symbols) def is_unit(self, a): """Returns ``True`` if ``a`` is a unit of ``self``""" if not a.is_ground: return False K = self.domain return K.is_unit(K.convert_from(a, self)) def canonical_unit(self, a): u = self.domain.canonical_unit(a.LC) return self.ring.ground_new(u) def to_sympy(self, a): """Convert `a` to a SymPy object. """ return a.as_expr() def from_sympy(self, a): """Convert SymPy's expression to `dtype`. """ return self.ring.from_expr(a) def from_ZZ(K1, a, K0): """Convert a Python `int` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_ZZ_python(K1, a, K0): """Convert a Python `int` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_QQ(K1, a, K0): """Convert a Python `Fraction` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_QQ_python(K1, a, K0): """Convert a Python `Fraction` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY `mpz` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY `mpq` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_GaussianIntegerRing(K1, a, K0): """Convert a `GaussianInteger` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_GaussianRationalField(K1, a, K0): """Convert a `GaussianRational` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_RealField(K1, a, K0): """Convert a mpmath `mpf` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_ComplexField(K1, a, K0): """Convert a mpmath `mpf` object to `dtype`. """ return K1(K1.domain.convert(a, K0)) def from_AlgebraicField(K1, a, K0): """Convert an algebraic number to ``dtype``. """ if K1.domain != K0: a = K1.domain.convert_from(a, K0) if a is not None: return K1.new(a) def from_PolynomialRing(K1, a, K0): """Convert a polynomial to ``dtype``. """ try: return a.set_ring(K1.ring) except (CoercionFailed, GeneratorsError): return None def from_FractionField(K1, a, K0): """Convert a rational function to ``dtype``. """ if K1.domain == K0: return K1.ring.from_list([a]) q, r = K0.numer(a).div(K0.denom(a)) if r.is_zero: return K1.from_PolynomialRing(q, K0.field.ring.to_domain()) else: return None def from_GlobalPolynomialRing(K1, a, K0): """Convert from old poly ring to ``dtype``. """ if K1.symbols == K0.gens: ad = a.to_dict() if K1.domain != K0.domain: ad = {m: K1.domain.convert(c) for m, c in ad.items()} return K1(ad) elif a.is_ground and K0.domain == K1: return K1.convert_from(a.to_list()[0], K0.domain) def get_field(self): """Returns a field associated with `self`. """ return self.ring.to_field().to_domain() def is_positive(self, a): """Returns True if `LC(a)` is positive. """ return self.domain.is_positive(a.LC) def is_negative(self, a): """Returns True if `LC(a)` is negative. """ return self.domain.is_negative(a.LC) def is_nonpositive(self, a): """Returns True if `LC(a)` is non-positive. """ return self.domain.is_nonpositive(a.LC) def is_nonnegative(self, a): """Returns True if `LC(a)` is non-negative. """ return self.domain.is_nonnegative(a.LC) def gcdex(self, a, b): """Extended GCD of `a` and `b`. """ return a.gcdex(b) def gcd(self, a, b): """Returns GCD of `a` and `b`. """ return a.gcd(b) def lcm(self, a, b): """Returns LCM of `a` and `b`. """ return a.lcm(b) def factorial(self, a): """Returns factorial of `a`. """ return self.dtype(self.domain.factorial(a)) sympy-sympy-1.9/sympy/polys/domains/pythonfinitefield.py000066400000000000000000000007141412543434000240040ustar00rootroot00000000000000"""Implementation of :class:`PythonFiniteField` class. """ from sympy.polys.domains.finitefield import FiniteField from sympy.polys.domains.pythonintegerring import PythonIntegerRing from sympy.utilities import public @public class PythonFiniteField(FiniteField): """Finite field based on Python's integers. """ alias = 'FF_python' def __init__(self, mod, symmetric=True): return super().__init__(mod, PythonIntegerRing(), symmetric) sympy-sympy-1.9/sympy/polys/domains/pythonintegerring.py000066400000000000000000000055611412543434000240440ustar00rootroot00000000000000"""Implementation of :class:`PythonIntegerRing` class. """ from sympy.polys.domains.groundtypes import ( PythonInteger, SymPyInteger, sqrt as python_sqrt, factorial as python_factorial, python_gcdex, python_gcd, python_lcm, ) from sympy.polys.domains.integerring import IntegerRing from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public @public class PythonIntegerRing(IntegerRing): """Integer ring based on Python's ``int`` type. This will be used as :ref:`ZZ` if ``gmpy`` and ``gmpy2`` are not installed. Elements are instances of the standard Python ``int`` type. """ dtype = PythonInteger zero = dtype(0) one = dtype(1) alias = 'ZZ_python' def __init__(self): """Allow instantiation of this domain. """ def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return SymPyInteger(a) def from_sympy(self, a): """Convert SymPy's Integer to ``dtype``. """ if a.is_Integer: return PythonInteger(a.p) elif a.is_Float and int(a) == a: return PythonInteger(int(a)) else: raise CoercionFailed("expected an integer, got %s" % a) def from_FF_python(K1, a, K0): """Convert ``ModularInteger(int)`` to Python's ``int``. """ return a.to_int() def from_ZZ_python(K1, a, K0): """Convert Python's ``int`` to Python's ``int``. """ return a def from_QQ(K1, a, K0): """Convert Python's ``Fraction`` to Python's ``int``. """ if a.denominator == 1: return a.numerator def from_QQ_python(K1, a, K0): """Convert Python's ``Fraction`` to Python's ``int``. """ if a.denominator == 1: return a.numerator def from_FF_gmpy(K1, a, K0): """Convert ``ModularInteger(mpz)`` to Python's ``int``. """ return PythonInteger(a.to_int()) def from_ZZ_gmpy(K1, a, K0): """Convert GMPY's ``mpz`` to Python's ``int``. """ return PythonInteger(a) def from_QQ_gmpy(K1, a, K0): """Convert GMPY's ``mpq`` to Python's ``int``. """ if a.denom() == 1: return PythonInteger(a.numer()) def from_RealField(K1, a, K0): """Convert mpmath's ``mpf`` to Python's ``int``. """ p, q = K0.to_rational(a) if q == 1: return PythonInteger(p) def gcdex(self, a, b): """Compute extended GCD of ``a`` and ``b``. """ return python_gcdex(a, b) def gcd(self, a, b): """Compute GCD of ``a`` and ``b``. """ return python_gcd(a, b) def lcm(self, a, b): """Compute LCM of ``a`` and ``b``. """ return python_lcm(a, b) def sqrt(self, a): """Compute square root of ``a``. """ return python_sqrt(a) def factorial(self, a): """Compute factorial of ``a``. """ return python_factorial(a) sympy-sympy-1.9/sympy/polys/domains/pythonrational.py000066400000000000000000000010261412543434000233300ustar00rootroot00000000000000""" Rational number type based on Python integers. The PythonRational class from here has been moved to sympy.external.pythonmpq This module is just left here for backwards compatibility. """ from sympy.core.numbers import Rational from sympy.core.sympify import converter from sympy.utilities import public from sympy.external.pythonmpq import PythonMPQ PythonRational = public(PythonMPQ) def sympify_pythonrational(arg): return Rational(arg.numerator, arg.denominator) converter[PythonRational] = sympify_pythonrational sympy-sympy-1.9/sympy/polys/domains/pythonrationalfield.py000066400000000000000000000043671412543434000243470ustar00rootroot00000000000000"""Implementation of :class:`PythonRationalField` class. """ from sympy.polys.domains.groundtypes import PythonInteger, PythonRational, SymPyRational from sympy.polys.domains.rationalfield import RationalField from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public @public class PythonRationalField(RationalField): """Rational field based on :ref:`MPQ`. This will be used as :ref:`QQ` if ``gmpy`` and ``gmpy2`` are not installed. Elements are instances of :ref:`MPQ`. """ dtype = PythonRational zero = dtype(0) one = dtype(1) alias = 'QQ_python' def __init__(self): pass def get_ring(self): """Returns ring associated with ``self``. """ from sympy.polys.domains import PythonIntegerRing return PythonIntegerRing() def to_sympy(self, a): """Convert `a` to a SymPy object. """ return SymPyRational(a.numerator, a.denominator) def from_sympy(self, a): """Convert SymPy's Rational to `dtype`. """ if a.is_Rational: return PythonRational(a.p, a.q) elif a.is_Float: from sympy.polys.domains import RR p, q = RR.to_rational(a) return PythonRational(int(p), int(q)) else: raise CoercionFailed("expected `Rational` object, got %s" % a) def from_ZZ_python(K1, a, K0): """Convert a Python `int` object to `dtype`. """ return PythonRational(a) def from_QQ_python(K1, a, K0): """Convert a Python `Fraction` object to `dtype`. """ return a def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY `mpz` object to `dtype`. """ return PythonRational(PythonInteger(a)) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY `mpq` object to `dtype`. """ return PythonRational(PythonInteger(a.numer()), PythonInteger(a.denom())) def from_RealField(K1, a, K0): """Convert a mpmath `mpf` object to `dtype`. """ p, q = K0.to_rational(a) return PythonRational(int(p), int(q)) def numer(self, a): """Returns numerator of `a`. """ return a.numerator def denom(self, a): """Returns denominator of `a`. """ return a.denominator sympy-sympy-1.9/sympy/polys/domains/quotientring.py000066400000000000000000000133351412543434000230130ustar00rootroot00000000000000"""Implementation of :class:`QuotientRing` class.""" from sympy.polys.agca.modules import FreeModuleQuotientRing from sympy.polys.domains.ring import Ring from sympy.polys.polyerrors import NotReversible, CoercionFailed from sympy.utilities import public # TODO # - successive quotients (when quotient ideals are implemented) # - poly rings over quotients? # - division by non-units in integral domains? @public class QuotientRingElement: """ Class representing elements of (commutative) quotient rings. Attributes: - ring - containing ring - data - element of ring.ring (i.e. base ring) representing self """ def __init__(self, ring, data): self.ring = ring self.data = data def __str__(self): from sympy import sstr return sstr(self.data) + " + " + str(self.ring.base_ideal) __repr__ = __str__ def __bool__(self): return not self.ring.is_zero(self) def __add__(self, om): if not isinstance(om, self.__class__) or om.ring != self.ring: try: om = self.ring.convert(om) except (NotImplementedError, CoercionFailed): return NotImplemented return self.ring(self.data + om.data) __radd__ = __add__ def __neg__(self): return self.ring(self.data*self.ring.ring.convert(-1)) def __sub__(self, om): return self.__add__(-om) def __rsub__(self, om): return (-self).__add__(om) def __mul__(self, o): if not isinstance(o, self.__class__): try: o = self.ring.convert(o) except (NotImplementedError, CoercionFailed): return NotImplemented return self.ring(self.data*o.data) __rmul__ = __mul__ def __rtruediv__(self, o): return self.ring.revert(self)*o def __truediv__(self, o): if not isinstance(o, self.__class__): try: o = self.ring.convert(o) except (NotImplementedError, CoercionFailed): return NotImplemented return self.ring.revert(o)*self def __pow__(self, oth): if oth < 0: return self.ring.revert(self) ** -oth return self.ring(self.data ** oth) def __eq__(self, om): if not isinstance(om, self.__class__) or om.ring != self.ring: return False return self.ring.is_zero(self - om) def __ne__(self, om): return not self == om class QuotientRing(Ring): """ Class representing (commutative) quotient rings. You should not usually instantiate this by hand, instead use the constructor from the base ring in the construction. >>> from sympy.abc import x >>> from sympy import QQ >>> I = QQ.old_poly_ring(x).ideal(x**3 + 1) >>> QQ.old_poly_ring(x).quotient_ring(I) QQ[x]/ Shorter versions are possible: >>> QQ.old_poly_ring(x)/I QQ[x]/ >>> QQ.old_poly_ring(x)/[x**3 + 1] QQ[x]/ Attributes: - ring - the base ring - base_ideal - the ideal used to form the quotient """ has_assoc_Ring = True has_assoc_Field = False dtype = QuotientRingElement def __init__(self, ring, ideal): if not ideal.ring == ring: raise ValueError('Ideal must belong to %s, got %s' % (ring, ideal)) self.ring = ring self.base_ideal = ideal self.zero = self(self.ring.zero) self.one = self(self.ring.one) def __str__(self): return str(self.ring) + "/" + str(self.base_ideal) def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.ring, self.base_ideal)) def new(self, a): """Construct an element of ``self`` domain from ``a``. """ if not isinstance(a, self.ring.dtype): a = self.ring(a) # TODO optionally disable reduction? return self.dtype(self, self.base_ideal.reduce_element(a)) def __eq__(self, other): """Returns ``True`` if two domains are equivalent. """ return isinstance(other, QuotientRing) and \ self.ring == other.ring and self.base_ideal == other.base_ideal def from_ZZ(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return K1(K1.ring.convert(a, K0)) from_ZZ_python = from_ZZ from_QQ_python = from_ZZ_python from_ZZ_gmpy = from_ZZ_python from_QQ_gmpy = from_ZZ_python from_RealField = from_ZZ_python from_GlobalPolynomialRing = from_ZZ_python from_FractionField = from_ZZ_python def from_sympy(self, a): return self(self.ring.from_sympy(a)) def to_sympy(self, a): return self.ring.to_sympy(a.data) def from_QuotientRing(self, a, K0): if K0 == self: return a def poly_ring(self, *gens): """Returns a polynomial ring, i.e. ``K[X]``. """ raise NotImplementedError('nested domains not allowed') def frac_field(self, *gens): """Returns a fraction field, i.e. ``K(X)``. """ raise NotImplementedError('nested domains not allowed') def revert(self, a): """ Compute a**(-1), if possible. """ I = self.ring.ideal(a.data) + self.base_ideal try: return self(I.in_terms_of_generators(1)[0]) except ValueError: # 1 not in I raise NotReversible('%s not a unit in %r' % (a, self)) def is_zero(self, a): return self.base_ideal.contains(a.data) def free_module(self, rank): """ Generate a free module of rank ``rank`` over ``self``. >>> from sympy.abc import x >>> from sympy import QQ >>> (QQ.old_poly_ring(x)/[x**2 + 1]).free_module(2) (QQ[x]/)**2 """ return FreeModuleQuotientRing(self, rank) sympy-sympy-1.9/sympy/polys/domains/rationalfield.py000066400000000000000000000110001412543434000230630ustar00rootroot00000000000000"""Implementation of :class:`RationalField` class. """ from sympy.external.gmpy import MPQ from sympy.polys.domains.groundtypes import SymPyRational from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.field import Field from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public @public class RationalField(Field, CharacteristicZero, SimpleDomain): r"""Abstract base class for the domain :ref:`QQ`. The :py:class:`RationalField` class represents the field of rational numbers $\mathbb{Q}$ as a :py:class:`~.Domain` in the domain system. :py:class:`RationalField` is a superclass of :py:class:`PythonRationalField` and :py:class:`GMPYRationalField` one of which will be the implementation for :ref:`QQ` depending on whether either of ``gmpy`` or ``gmpy2`` is installed or not. See also ======== Domain """ rep = 'QQ' alias = 'QQ' is_RationalField = is_QQ = True is_Numerical = True has_assoc_Ring = True has_assoc_Field = True dtype = MPQ zero = dtype(0) one = dtype(1) tp = type(one) def __init__(self): pass def get_ring(self): """Returns ring associated with ``self``. """ from sympy.polys.domains import ZZ return ZZ def to_sympy(self, a): """Convert ``a`` to a SymPy object. """ return SymPyRational(int(a.numerator), int(a.denominator)) def from_sympy(self, a): """Convert SymPy's Integer to ``dtype``. """ if a.is_Rational: return MPQ(a.p, a.q) elif a.is_Float: from sympy.polys.domains import RR return MPQ(*map(int, RR.to_rational(a))) else: raise CoercionFailed("expected `Rational` object, got %s" % a) def algebraic_field(self, *extension): r"""Returns an algebraic field, i.e. `\mathbb{Q}(\alpha, \ldots)`. Parameters ========== *extension: One or more Expr Generators of the extension. These should be expressions that are algebraic over `\mathbb{Q}`. Returns ======= :py:class:`~.AlgebraicField` A :py:class:`~.Domain` representing the algebraic field extension. Examples ======== >>> from sympy import QQ, sqrt >>> QQ.algebraic_field(sqrt(2)) QQ """ from sympy.polys.domains import AlgebraicField return AlgebraicField(self, *extension) def from_AlgebraicField(K1, a, K0): """Convert a :py:class:`~.ANP` object to :ref:`QQ`. See :py:meth:`~.Domain.convert` """ if a.is_ground: return K1.convert(a.LC(), K0.dom) def from_ZZ(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return MPQ(a) def from_ZZ_python(K1, a, K0): """Convert a Python ``int`` object to ``dtype``. """ return MPQ(a) def from_QQ(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return MPQ(a.numerator, a.denominator) def from_QQ_python(K1, a, K0): """Convert a Python ``Fraction`` object to ``dtype``. """ return MPQ(a.numerator, a.denominator) def from_ZZ_gmpy(K1, a, K0): """Convert a GMPY ``mpz`` object to ``dtype``. """ return MPQ(a) def from_QQ_gmpy(K1, a, K0): """Convert a GMPY ``mpq`` object to ``dtype``. """ return a def from_GaussianRationalField(K1, a, K0): """Convert a ``GaussianElement`` object to ``dtype``. """ if a.y == 0: return MPQ(a.x) def from_RealField(K1, a, K0): """Convert a mpmath ``mpf`` object to ``dtype``. """ return MPQ(*map(int, K0.to_rational(a))) def exquo(self, a, b): """Exact quotient of ``a`` and ``b``, implies ``__truediv__``. """ return MPQ(a) / MPQ(b) def quo(self, a, b): """Quotient of ``a`` and ``b``, implies ``__truediv__``. """ return MPQ(a) / MPQ(b) def rem(self, a, b): """Remainder of ``a`` and ``b``, implies nothing. """ return self.zero def div(self, a, b): """Division of ``a`` and ``b``, implies ``__truediv__``. """ return MPQ(a) / MPQ(b), self.zero def numer(self, a): """Returns numerator of ``a``. """ return a.numerator def denom(self, a): """Returns denominator of ``a``. """ return a.denominator QQ = RationalField() sympy-sympy-1.9/sympy/polys/domains/realfield.py000066400000000000000000000073061412543434000222130ustar00rootroot00000000000000"""Implementation of :class:`RealField` class. """ from sympy.core.numbers import Float from sympy.polys.domains.field import Field from sympy.polys.domains.simpledomain import SimpleDomain from sympy.polys.domains.characteristiczero import CharacteristicZero from sympy.polys.domains.mpelements import MPContext from sympy.polys.polyerrors import CoercionFailed from sympy.utilities import public @public class RealField(Field, CharacteristicZero, SimpleDomain): """Real numbers up to the given precision. """ rep = 'RR' is_RealField = is_RR = True is_Exact = False is_Numerical = True is_PID = False has_assoc_Ring = False has_assoc_Field = True _default_precision = 53 @property def has_default_precision(self): return self.precision == self._default_precision @property def precision(self): return self._context.prec @property def dps(self): return self._context.dps @property def tolerance(self): return self._context.tolerance def __init__(self, prec=_default_precision, dps=None, tol=None): context = MPContext(prec, dps, tol, True) context._parent = self self._context = context self.dtype = context.mpf self.zero = self.dtype(0) self.one = self.dtype(1) def __eq__(self, other): return (isinstance(other, RealField) and self.precision == other.precision and self.tolerance == other.tolerance) def __hash__(self): return hash((self.__class__.__name__, self.dtype, self.precision, self.tolerance)) def to_sympy(self, element): """Convert ``element`` to SymPy number. """ return Float(element, self.dps) def from_sympy(self, expr): """Convert SymPy's number to ``dtype``. """ number = expr.evalf(n=self.dps) if number.is_Number: return self.dtype(number) else: raise CoercionFailed("expected real number, got %s" % expr) def from_ZZ(self, element, base): return self.dtype(element) def from_ZZ_python(self, element, base): return self.dtype(element) def from_QQ(self, element, base): return self.dtype(element.numerator) / element.denominator def from_QQ_python(self, element, base): return self.dtype(element.numerator) / element.denominator def from_ZZ_gmpy(self, element, base): return self.dtype(int(element)) def from_QQ_gmpy(self, element, base): return self.dtype(int(element.numerator)) / int(element.denominator) def from_AlgebraicField(self, element, base): return self.from_sympy(base.to_sympy(element).evalf(self.dps)) def from_RealField(self, element, base): if self == base: return element else: return self.dtype(element) def from_ComplexField(self, element, base): if not element.imag: return self.dtype(element.real) def to_rational(self, element, limit=True): """Convert a real number to rational number. """ return self._context.to_rational(element, limit) def get_ring(self): """Returns a ring associated with ``self``. """ return self def get_exact(self): """Returns an exact domain associated with ``self``. """ from sympy.polys.domains import QQ return QQ def gcd(self, a, b): """Returns GCD of ``a`` and ``b``. """ return self.one def lcm(self, a, b): """Returns LCM of ``a`` and ``b``. """ return a*b def almosteq(self, a, b, tolerance=None): """Check if ``a`` and ``b`` are almost equal. """ return self._context.almosteq(a, b, tolerance) RR = RealField() sympy-sympy-1.9/sympy/polys/domains/ring.py000066400000000000000000000062441412543434000212230ustar00rootroot00000000000000"""Implementation of :class:`Ring` class. """ from sympy.polys.domains.domain import Domain from sympy.polys.polyerrors import ExactQuotientFailed, NotInvertible, NotReversible from sympy.utilities import public @public class Ring(Domain): """Represents a ring domain. """ is_Ring = True def get_ring(self): """Returns a ring associated with ``self``. """ return self def exquo(self, a, b): """Exact quotient of ``a`` and ``b``, implies ``__floordiv__``. """ if a % b: raise ExactQuotientFailed(a, b, self) else: return a // b def quo(self, a, b): """Quotient of ``a`` and ``b``, implies ``__floordiv__``. """ return a // b def rem(self, a, b): """Remainder of ``a`` and ``b``, implies ``__mod__``. """ return a % b def div(self, a, b): """Division of ``a`` and ``b``, implies ``__divmod__``. """ return divmod(a, b) def invert(self, a, b): """Returns inversion of ``a mod b``. """ s, t, h = self.gcdex(a, b) if self.is_one(h): return s % b else: raise NotInvertible("zero divisor") def revert(self, a): """Returns ``a**(-1)`` if possible. """ if self.is_one(a) or self.is_one(-a): return a else: raise NotReversible('only units are reversible in a ring') def is_unit(self, a): try: self.revert(a) return True except NotReversible: return False def numer(self, a): """Returns numerator of ``a``. """ return a def denom(self, a): """Returns denominator of `a`. """ return self.one def free_module(self, rank): """ Generate a free module of rank ``rank`` over self. >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).free_module(2) QQ[x]**2 """ raise NotImplementedError def ideal(self, *gens): """ Generate an ideal of ``self``. >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).ideal(x**2) """ from sympy.polys.agca.ideals import ModuleImplementedIdeal return ModuleImplementedIdeal(self, self.free_module(1).submodule( *[[x] for x in gens])) def quotient_ring(self, e): """ Form a quotient ring of ``self``. Here ``e`` can be an ideal or an iterable. >>> from sympy.abc import x >>> from sympy import QQ >>> QQ.old_poly_ring(x).quotient_ring(QQ.old_poly_ring(x).ideal(x**2)) QQ[x]/ >>> QQ.old_poly_ring(x).quotient_ring([x**2]) QQ[x]/ The division operator has been overloaded for this: >>> QQ.old_poly_ring(x)/[x**2] QQ[x]/ """ from sympy.polys.agca.ideals import Ideal from sympy.polys.domains.quotientring import QuotientRing if not isinstance(e, Ideal): e = self.ideal(*e) return QuotientRing(self, e) def __truediv__(self, e): return self.quotient_ring(e) sympy-sympy-1.9/sympy/polys/domains/simpledomain.py000066400000000000000000000005611412543434000227410ustar00rootroot00000000000000"""Implementation of :class:`SimpleDomain` class. """ from sympy.polys.domains.domain import Domain from sympy.utilities import public @public class SimpleDomain(Domain): """Base class for simple domains, e.g. ZZ, QQ. """ is_Simple = True def inject(self, *gens): """Inject generators into this domain. """ return self.poly_ring(*gens) sympy-sympy-1.9/sympy/polys/domains/tests/000077500000000000000000000000001412543434000210465ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/domains/tests/__init__.py000066400000000000000000000000001412543434000231450ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/domains/tests/test_domains.py000066400000000000000000001206541412543434000241210ustar00rootroot00000000000000"""Tests for classes defining properties of ground domains, e.g. ZZ, QQ, ZZ[x] ... """ from sympy import I, S, sqrt, sin, oo, Poly, Float, Integer, Rational, pi, exp, E from sympy.abc import x, y, z from sympy.utilities.iterables import cartes from sympy.core.compatibility import HAS_GMPY from sympy.polys.domains import (ZZ, QQ, RR, CC, FF, GF, EX, EXRAW, ZZ_gmpy, ZZ_python, QQ_gmpy, QQ_python) from sympy.polys.domains.algebraicfield import AlgebraicField from sympy.polys.domains.gaussiandomains import ZZ_I, QQ_I from sympy.polys.domains.polynomialring import PolynomialRing from sympy.polys.domains.realfield import RealField from sympy.polys.rings import ring from sympy.polys.fields import field from sympy.polys.agca.extensions import FiniteExtension from sympy.polys.polyerrors import ( UnificationFailed, GeneratorsError, CoercionFailed, NotInvertible, DomainError) from sympy.polys.polyutils import illegal from sympy.testing.pytest import raises ALG = QQ.algebraic_field(sqrt(2), sqrt(3)) def unify(K0, K1): return K0.unify(K1) def test_Domain_unify(): F3 = GF(3) assert unify(F3, F3) == F3 assert unify(F3, ZZ) == ZZ assert unify(F3, QQ) == QQ assert unify(F3, ALG) == ALG assert unify(F3, RR) == RR assert unify(F3, CC) == CC assert unify(F3, ZZ[x]) == ZZ[x] assert unify(F3, ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(F3, EX) == EX assert unify(ZZ, F3) == ZZ assert unify(ZZ, ZZ) == ZZ assert unify(ZZ, QQ) == QQ assert unify(ZZ, ALG) == ALG assert unify(ZZ, RR) == RR assert unify(ZZ, CC) == CC assert unify(ZZ, ZZ[x]) == ZZ[x] assert unify(ZZ, ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(ZZ, EX) == EX assert unify(QQ, F3) == QQ assert unify(QQ, ZZ) == QQ assert unify(QQ, QQ) == QQ assert unify(QQ, ALG) == ALG assert unify(QQ, RR) == RR assert unify(QQ, CC) == CC assert unify(QQ, ZZ[x]) == QQ[x] assert unify(QQ, ZZ.frac_field(x)) == QQ.frac_field(x) assert unify(QQ, EX) == EX assert unify(ZZ_I, F3) == ZZ_I assert unify(ZZ_I, ZZ) == ZZ_I assert unify(ZZ_I, ZZ_I) == ZZ_I assert unify(ZZ_I, QQ) == QQ_I assert unify(ZZ_I, ALG) == QQ.algebraic_field(I, sqrt(2), sqrt(3)) assert unify(ZZ_I, RR) == CC assert unify(ZZ_I, CC) == CC assert unify(ZZ_I, ZZ[x]) == ZZ_I[x] assert unify(ZZ_I, ZZ_I[x]) == ZZ_I[x] assert unify(ZZ_I, ZZ.frac_field(x)) == ZZ_I.frac_field(x) assert unify(ZZ_I, ZZ_I.frac_field(x)) == ZZ_I.frac_field(x) assert unify(ZZ_I, EX) == EX assert unify(QQ_I, F3) == QQ_I assert unify(QQ_I, ZZ) == QQ_I assert unify(QQ_I, ZZ_I) == QQ_I assert unify(QQ_I, QQ) == QQ_I assert unify(QQ_I, ALG) == QQ.algebraic_field(I, sqrt(2), sqrt(3)) assert unify(QQ_I, RR) == CC assert unify(QQ_I, CC) == CC assert unify(QQ_I, ZZ[x]) == QQ_I[x] assert unify(QQ_I, ZZ_I[x]) == QQ_I[x] assert unify(QQ_I, QQ[x]) == QQ_I[x] assert unify(QQ_I, QQ_I[x]) == QQ_I[x] assert unify(QQ_I, ZZ.frac_field(x)) == QQ_I.frac_field(x) assert unify(QQ_I, ZZ_I.frac_field(x)) == QQ_I.frac_field(x) assert unify(QQ_I, QQ.frac_field(x)) == QQ_I.frac_field(x) assert unify(QQ_I, QQ_I.frac_field(x)) == QQ_I.frac_field(x) assert unify(QQ_I, EX) == EX assert unify(RR, F3) == RR assert unify(RR, ZZ) == RR assert unify(RR, QQ) == RR assert unify(RR, ALG) == RR assert unify(RR, RR) == RR assert unify(RR, CC) == CC assert unify(RR, ZZ[x]) == RR[x] assert unify(RR, ZZ.frac_field(x)) == RR.frac_field(x) assert unify(RR, EX) == EX assert RR[x].unify(ZZ.frac_field(y)) == RR.frac_field(x, y) assert unify(CC, F3) == CC assert unify(CC, ZZ) == CC assert unify(CC, QQ) == CC assert unify(CC, ALG) == CC assert unify(CC, RR) == CC assert unify(CC, CC) == CC assert unify(CC, ZZ[x]) == CC[x] assert unify(CC, ZZ.frac_field(x)) == CC.frac_field(x) assert unify(CC, EX) == EX assert unify(ZZ[x], F3) == ZZ[x] assert unify(ZZ[x], ZZ) == ZZ[x] assert unify(ZZ[x], QQ) == QQ[x] assert unify(ZZ[x], ALG) == ALG[x] assert unify(ZZ[x], RR) == RR[x] assert unify(ZZ[x], CC) == CC[x] assert unify(ZZ[x], ZZ[x]) == ZZ[x] assert unify(ZZ[x], ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(ZZ[x], EX) == EX assert unify(ZZ.frac_field(x), F3) == ZZ.frac_field(x) assert unify(ZZ.frac_field(x), ZZ) == ZZ.frac_field(x) assert unify(ZZ.frac_field(x), QQ) == QQ.frac_field(x) assert unify(ZZ.frac_field(x), ALG) == ALG.frac_field(x) assert unify(ZZ.frac_field(x), RR) == RR.frac_field(x) assert unify(ZZ.frac_field(x), CC) == CC.frac_field(x) assert unify(ZZ.frac_field(x), ZZ[x]) == ZZ.frac_field(x) assert unify(ZZ.frac_field(x), ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(ZZ.frac_field(x), EX) == EX assert unify(EX, F3) == EX assert unify(EX, ZZ) == EX assert unify(EX, QQ) == EX assert unify(EX, ALG) == EX assert unify(EX, RR) == EX assert unify(EX, CC) == EX assert unify(EX, ZZ[x]) == EX assert unify(EX, ZZ.frac_field(x)) == EX assert unify(EX, EX) == EX def test_Domain_unify_composite(): assert unify(ZZ.poly_ring(x), ZZ) == ZZ.poly_ring(x) assert unify(ZZ.poly_ring(x), QQ) == QQ.poly_ring(x) assert unify(QQ.poly_ring(x), ZZ) == QQ.poly_ring(x) assert unify(QQ.poly_ring(x), QQ) == QQ.poly_ring(x) assert unify(ZZ, ZZ.poly_ring(x)) == ZZ.poly_ring(x) assert unify(QQ, ZZ.poly_ring(x)) == QQ.poly_ring(x) assert unify(ZZ, QQ.poly_ring(x)) == QQ.poly_ring(x) assert unify(QQ, QQ.poly_ring(x)) == QQ.poly_ring(x) assert unify(ZZ.poly_ring(x, y), ZZ) == ZZ.poly_ring(x, y) assert unify(ZZ.poly_ring(x, y), QQ) == QQ.poly_ring(x, y) assert unify(QQ.poly_ring(x, y), ZZ) == QQ.poly_ring(x, y) assert unify(QQ.poly_ring(x, y), QQ) == QQ.poly_ring(x, y) assert unify(ZZ, ZZ.poly_ring(x, y)) == ZZ.poly_ring(x, y) assert unify(QQ, ZZ.poly_ring(x, y)) == QQ.poly_ring(x, y) assert unify(ZZ, QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) assert unify(QQ, QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) assert unify(ZZ.frac_field(x), ZZ) == ZZ.frac_field(x) assert unify(ZZ.frac_field(x), QQ) == QQ.frac_field(x) assert unify(QQ.frac_field(x), ZZ) == QQ.frac_field(x) assert unify(QQ.frac_field(x), QQ) == QQ.frac_field(x) assert unify(ZZ, ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(QQ, ZZ.frac_field(x)) == QQ.frac_field(x) assert unify(ZZ, QQ.frac_field(x)) == QQ.frac_field(x) assert unify(QQ, QQ.frac_field(x)) == QQ.frac_field(x) assert unify(ZZ.frac_field(x, y), ZZ) == ZZ.frac_field(x, y) assert unify(ZZ.frac_field(x, y), QQ) == QQ.frac_field(x, y) assert unify(QQ.frac_field(x, y), ZZ) == QQ.frac_field(x, y) assert unify(QQ.frac_field(x, y), QQ) == QQ.frac_field(x, y) assert unify(ZZ, ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) assert unify(QQ, ZZ.frac_field(x, y)) == QQ.frac_field(x, y) assert unify(ZZ, QQ.frac_field(x, y)) == QQ.frac_field(x, y) assert unify(QQ, QQ.frac_field(x, y)) == QQ.frac_field(x, y) assert unify(ZZ.poly_ring(x), ZZ.poly_ring(x)) == ZZ.poly_ring(x) assert unify(ZZ.poly_ring(x), QQ.poly_ring(x)) == QQ.poly_ring(x) assert unify(QQ.poly_ring(x), ZZ.poly_ring(x)) == QQ.poly_ring(x) assert unify(QQ.poly_ring(x), QQ.poly_ring(x)) == QQ.poly_ring(x) assert unify(ZZ.poly_ring(x, y), ZZ.poly_ring(x)) == ZZ.poly_ring(x, y) assert unify(ZZ.poly_ring(x, y), QQ.poly_ring(x)) == QQ.poly_ring(x, y) assert unify(QQ.poly_ring(x, y), ZZ.poly_ring(x)) == QQ.poly_ring(x, y) assert unify(QQ.poly_ring(x, y), QQ.poly_ring(x)) == QQ.poly_ring(x, y) assert unify(ZZ.poly_ring(x), ZZ.poly_ring(x, y)) == ZZ.poly_ring(x, y) assert unify(ZZ.poly_ring(x), QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) assert unify(QQ.poly_ring(x), ZZ.poly_ring(x, y)) == QQ.poly_ring(x, y) assert unify(QQ.poly_ring(x), QQ.poly_ring(x, y)) == QQ.poly_ring(x, y) assert unify(ZZ.poly_ring(x, y), ZZ.poly_ring(x, z)) == ZZ.poly_ring(x, y, z) assert unify(ZZ.poly_ring(x, y), QQ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) assert unify(QQ.poly_ring(x, y), ZZ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) assert unify(QQ.poly_ring(x, y), QQ.poly_ring(x, z)) == QQ.poly_ring(x, y, z) assert unify(ZZ.frac_field(x), ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(ZZ.frac_field(x), QQ.frac_field(x)) == QQ.frac_field(x) assert unify(QQ.frac_field(x), ZZ.frac_field(x)) == QQ.frac_field(x) assert unify(QQ.frac_field(x), QQ.frac_field(x)) == QQ.frac_field(x) assert unify(ZZ.frac_field(x, y), ZZ.frac_field(x)) == ZZ.frac_field(x, y) assert unify(ZZ.frac_field(x, y), QQ.frac_field(x)) == QQ.frac_field(x, y) assert unify(QQ.frac_field(x, y), ZZ.frac_field(x)) == QQ.frac_field(x, y) assert unify(QQ.frac_field(x, y), QQ.frac_field(x)) == QQ.frac_field(x, y) assert unify(ZZ.frac_field(x), ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) assert unify(ZZ.frac_field(x), QQ.frac_field(x, y)) == QQ.frac_field(x, y) assert unify(QQ.frac_field(x), ZZ.frac_field(x, y)) == QQ.frac_field(x, y) assert unify(QQ.frac_field(x), QQ.frac_field(x, y)) == QQ.frac_field(x, y) assert unify(ZZ.frac_field(x, y), ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) assert unify(ZZ.frac_field(x, y), QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) assert unify(QQ.frac_field(x, y), ZZ.frac_field(x, z)) == QQ.frac_field(x, y, z) assert unify(QQ.frac_field(x, y), QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) assert unify(ZZ.poly_ring(x), ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(ZZ.poly_ring(x), QQ.frac_field(x)) == ZZ.frac_field(x) assert unify(QQ.poly_ring(x), ZZ.frac_field(x)) == ZZ.frac_field(x) assert unify(QQ.poly_ring(x), QQ.frac_field(x)) == QQ.frac_field(x) assert unify(ZZ.poly_ring(x, y), ZZ.frac_field(x)) == ZZ.frac_field(x, y) assert unify(ZZ.poly_ring(x, y), QQ.frac_field(x)) == ZZ.frac_field(x, y) assert unify(QQ.poly_ring(x, y), ZZ.frac_field(x)) == ZZ.frac_field(x, y) assert unify(QQ.poly_ring(x, y), QQ.frac_field(x)) == QQ.frac_field(x, y) assert unify(ZZ.poly_ring(x), ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) assert unify(ZZ.poly_ring(x), QQ.frac_field(x, y)) == ZZ.frac_field(x, y) assert unify(QQ.poly_ring(x), ZZ.frac_field(x, y)) == ZZ.frac_field(x, y) assert unify(QQ.poly_ring(x), QQ.frac_field(x, y)) == QQ.frac_field(x, y) assert unify(ZZ.poly_ring(x, y), ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) assert unify(ZZ.poly_ring(x, y), QQ.frac_field(x, z)) == ZZ.frac_field(x, y, z) assert unify(QQ.poly_ring(x, y), ZZ.frac_field(x, z)) == ZZ.frac_field(x, y, z) assert unify(QQ.poly_ring(x, y), QQ.frac_field(x, z)) == QQ.frac_field(x, y, z) assert unify(ZZ.frac_field(x), ZZ.poly_ring(x)) == ZZ.frac_field(x) assert unify(ZZ.frac_field(x), QQ.poly_ring(x)) == ZZ.frac_field(x) assert unify(QQ.frac_field(x), ZZ.poly_ring(x)) == ZZ.frac_field(x) assert unify(QQ.frac_field(x), QQ.poly_ring(x)) == QQ.frac_field(x) assert unify(ZZ.frac_field(x, y), ZZ.poly_ring(x)) == ZZ.frac_field(x, y) assert unify(ZZ.frac_field(x, y), QQ.poly_ring(x)) == ZZ.frac_field(x, y) assert unify(QQ.frac_field(x, y), ZZ.poly_ring(x)) == ZZ.frac_field(x, y) assert unify(QQ.frac_field(x, y), QQ.poly_ring(x)) == QQ.frac_field(x, y) assert unify(ZZ.frac_field(x), ZZ.poly_ring(x, y)) == ZZ.frac_field(x, y) assert unify(ZZ.frac_field(x), QQ.poly_ring(x, y)) == ZZ.frac_field(x, y) assert unify(QQ.frac_field(x), ZZ.poly_ring(x, y)) == ZZ.frac_field(x, y) assert unify(QQ.frac_field(x), QQ.poly_ring(x, y)) == QQ.frac_field(x, y) assert unify(ZZ.frac_field(x, y), ZZ.poly_ring(x, z)) == ZZ.frac_field(x, y, z) assert unify(ZZ.frac_field(x, y), QQ.poly_ring(x, z)) == ZZ.frac_field(x, y, z) assert unify(QQ.frac_field(x, y), ZZ.poly_ring(x, z)) == ZZ.frac_field(x, y, z) assert unify(QQ.frac_field(x, y), QQ.poly_ring(x, z)) == QQ.frac_field(x, y, z) def test_Domain_unify_algebraic(): sqrt5 = QQ.algebraic_field(sqrt(5)) sqrt7 = QQ.algebraic_field(sqrt(7)) sqrt57 = QQ.algebraic_field(sqrt(5), sqrt(7)) assert sqrt5.unify(sqrt7) == sqrt57 assert sqrt5.unify(sqrt5[x, y]) == sqrt5[x, y] assert sqrt5[x, y].unify(sqrt5) == sqrt5[x, y] assert sqrt5.unify(sqrt5.frac_field(x, y)) == sqrt5.frac_field(x, y) assert sqrt5.frac_field(x, y).unify(sqrt5) == sqrt5.frac_field(x, y) assert sqrt5.unify(sqrt7[x, y]) == sqrt57[x, y] assert sqrt5[x, y].unify(sqrt7) == sqrt57[x, y] assert sqrt5.unify(sqrt7.frac_field(x, y)) == sqrt57.frac_field(x, y) assert sqrt5.frac_field(x, y).unify(sqrt7) == sqrt57.frac_field(x, y) def test_Domain_unify_FiniteExtension(): KxZZ = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ)) KxQQ = FiniteExtension(Poly(x**2 - 2, x, domain=QQ)) KxZZy = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ[y])) KxQQy = FiniteExtension(Poly(x**2 - 2, x, domain=QQ[y])) assert KxZZ.unify(KxZZ) == KxZZ assert KxQQ.unify(KxQQ) == KxQQ assert KxZZy.unify(KxZZy) == KxZZy assert KxQQy.unify(KxQQy) == KxQQy assert KxZZ.unify(ZZ) == KxZZ assert KxZZ.unify(QQ) == KxQQ assert KxQQ.unify(ZZ) == KxQQ assert KxQQ.unify(QQ) == KxQQ assert KxZZ.unify(ZZ[y]) == KxZZy assert KxZZ.unify(QQ[y]) == KxQQy assert KxQQ.unify(ZZ[y]) == KxQQy assert KxQQ.unify(QQ[y]) == KxQQy assert KxZZy.unify(ZZ) == KxZZy assert KxZZy.unify(QQ) == KxQQy assert KxQQy.unify(ZZ) == KxQQy assert KxQQy.unify(QQ) == KxQQy assert KxZZy.unify(ZZ[y]) == KxZZy assert KxZZy.unify(QQ[y]) == KxQQy assert KxQQy.unify(ZZ[y]) == KxQQy assert KxQQy.unify(QQ[y]) == KxQQy K = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ[y])) assert K.unify(ZZ) == K assert K.unify(ZZ[x]) == K assert K.unify(ZZ[y]) == K assert K.unify(ZZ[x, y]) == K Kz = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ[y, z])) assert K.unify(ZZ[z]) == Kz assert K.unify(ZZ[x, z]) == Kz assert K.unify(ZZ[y, z]) == Kz assert K.unify(ZZ[x, y, z]) == Kz Kx = FiniteExtension(Poly(x**2 - 2, x, domain=ZZ)) Ky = FiniteExtension(Poly(y**2 - 2, y, domain=ZZ)) Kxy = FiniteExtension(Poly(y**2 - 2, y, domain=Kx)) assert Kx.unify(Kx) == Kx assert Ky.unify(Ky) == Ky assert Kx.unify(Ky) == Kxy assert Ky.unify(Kx) == Kxy def test_Domain_unify_with_symbols(): raises(UnificationFailed, lambda: ZZ[x, y].unify_with_symbols(ZZ, (y, z))) raises(UnificationFailed, lambda: ZZ.unify_with_symbols(ZZ[x, y], (y, z))) def test_Domain__contains__(): assert (0 in EX) is True assert (0 in ZZ) is True assert (0 in QQ) is True assert (0 in RR) is True assert (0 in CC) is True assert (0 in ALG) is True assert (0 in ZZ[x, y]) is True assert (0 in QQ[x, y]) is True assert (0 in RR[x, y]) is True assert (-7 in EX) is True assert (-7 in ZZ) is True assert (-7 in QQ) is True assert (-7 in RR) is True assert (-7 in CC) is True assert (-7 in ALG) is True assert (-7 in ZZ[x, y]) is True assert (-7 in QQ[x, y]) is True assert (-7 in RR[x, y]) is True assert (17 in EX) is True assert (17 in ZZ) is True assert (17 in QQ) is True assert (17 in RR) is True assert (17 in CC) is True assert (17 in ALG) is True assert (17 in ZZ[x, y]) is True assert (17 in QQ[x, y]) is True assert (17 in RR[x, y]) is True assert (Rational(-1, 7) in EX) is True assert (Rational(-1, 7) in ZZ) is False assert (Rational(-1, 7) in QQ) is True assert (Rational(-1, 7) in RR) is True assert (Rational(-1, 7) in CC) is True assert (Rational(-1, 7) in ALG) is True assert (Rational(-1, 7) in ZZ[x, y]) is False assert (Rational(-1, 7) in QQ[x, y]) is True assert (Rational(-1, 7) in RR[x, y]) is True assert (Rational(3, 5) in EX) is True assert (Rational(3, 5) in ZZ) is False assert (Rational(3, 5) in QQ) is True assert (Rational(3, 5) in RR) is True assert (Rational(3, 5) in CC) is True assert (Rational(3, 5) in ALG) is True assert (Rational(3, 5) in ZZ[x, y]) is False assert (Rational(3, 5) in QQ[x, y]) is True assert (Rational(3, 5) in RR[x, y]) is True assert (3.0 in EX) is True assert (3.0 in ZZ) is True assert (3.0 in QQ) is True assert (3.0 in RR) is True assert (3.0 in CC) is True assert (3.0 in ALG) is True assert (3.0 in ZZ[x, y]) is True assert (3.0 in QQ[x, y]) is True assert (3.0 in RR[x, y]) is True assert (3.14 in EX) is True assert (3.14 in ZZ) is False assert (3.14 in QQ) is True assert (3.14 in RR) is True assert (3.14 in CC) is True assert (3.14 in ALG) is True assert (3.14 in ZZ[x, y]) is False assert (3.14 in QQ[x, y]) is True assert (3.14 in RR[x, y]) is True assert (oo in ALG) is False assert (oo in ZZ[x, y]) is False assert (oo in QQ[x, y]) is False assert (-oo in ZZ) is False assert (-oo in QQ) is False assert (-oo in ALG) is False assert (-oo in ZZ[x, y]) is False assert (-oo in QQ[x, y]) is False assert (sqrt(7) in EX) is True assert (sqrt(7) in ZZ) is False assert (sqrt(7) in QQ) is False assert (sqrt(7) in RR) is True assert (sqrt(7) in CC) is True assert (sqrt(7) in ALG) is False assert (sqrt(7) in ZZ[x, y]) is False assert (sqrt(7) in QQ[x, y]) is False assert (sqrt(7) in RR[x, y]) is True assert (2*sqrt(3) + 1 in EX) is True assert (2*sqrt(3) + 1 in ZZ) is False assert (2*sqrt(3) + 1 in QQ) is False assert (2*sqrt(3) + 1 in RR) is True assert (2*sqrt(3) + 1 in CC) is True assert (2*sqrt(3) + 1 in ALG) is True assert (2*sqrt(3) + 1 in ZZ[x, y]) is False assert (2*sqrt(3) + 1 in QQ[x, y]) is False assert (2*sqrt(3) + 1 in RR[x, y]) is True assert (sin(1) in EX) is True assert (sin(1) in ZZ) is False assert (sin(1) in QQ) is False assert (sin(1) in RR) is True assert (sin(1) in CC) is True assert (sin(1) in ALG) is False assert (sin(1) in ZZ[x, y]) is False assert (sin(1) in QQ[x, y]) is False assert (sin(1) in RR[x, y]) is True assert (x**2 + 1 in EX) is True assert (x**2 + 1 in ZZ) is False assert (x**2 + 1 in QQ) is False assert (x**2 + 1 in RR) is False assert (x**2 + 1 in CC) is False assert (x**2 + 1 in ALG) is False assert (x**2 + 1 in ZZ[x]) is True assert (x**2 + 1 in QQ[x]) is True assert (x**2 + 1 in RR[x]) is True assert (x**2 + 1 in ZZ[x, y]) is True assert (x**2 + 1 in QQ[x, y]) is True assert (x**2 + 1 in RR[x, y]) is True assert (x**2 + y**2 in EX) is True assert (x**2 + y**2 in ZZ) is False assert (x**2 + y**2 in QQ) is False assert (x**2 + y**2 in RR) is False assert (x**2 + y**2 in CC) is False assert (x**2 + y**2 in ALG) is False assert (x**2 + y**2 in ZZ[x]) is False assert (x**2 + y**2 in QQ[x]) is False assert (x**2 + y**2 in RR[x]) is False assert (x**2 + y**2 in ZZ[x, y]) is True assert (x**2 + y**2 in QQ[x, y]) is True assert (x**2 + y**2 in RR[x, y]) is True assert (Rational(3, 2)*x/(y + 1) - z in QQ[x, y, z]) is False def test_Domain_get_ring(): assert ZZ.has_assoc_Ring is True assert QQ.has_assoc_Ring is True assert ZZ[x].has_assoc_Ring is True assert QQ[x].has_assoc_Ring is True assert ZZ[x, y].has_assoc_Ring is True assert QQ[x, y].has_assoc_Ring is True assert ZZ.frac_field(x).has_assoc_Ring is True assert QQ.frac_field(x).has_assoc_Ring is True assert ZZ.frac_field(x, y).has_assoc_Ring is True assert QQ.frac_field(x, y).has_assoc_Ring is True assert EX.has_assoc_Ring is False assert RR.has_assoc_Ring is False assert ALG.has_assoc_Ring is False assert ZZ.get_ring() == ZZ assert QQ.get_ring() == ZZ assert ZZ[x].get_ring() == ZZ[x] assert QQ[x].get_ring() == QQ[x] assert ZZ[x, y].get_ring() == ZZ[x, y] assert QQ[x, y].get_ring() == QQ[x, y] assert ZZ.frac_field(x).get_ring() == ZZ[x] assert QQ.frac_field(x).get_ring() == QQ[x] assert ZZ.frac_field(x, y).get_ring() == ZZ[x, y] assert QQ.frac_field(x, y).get_ring() == QQ[x, y] assert EX.get_ring() == EX assert RR.get_ring() == RR # XXX: This should also be like RR raises(DomainError, lambda: ALG.get_ring()) def test_Domain_get_field(): assert EX.has_assoc_Field is True assert ZZ.has_assoc_Field is True assert QQ.has_assoc_Field is True assert RR.has_assoc_Field is True assert ALG.has_assoc_Field is True assert ZZ[x].has_assoc_Field is True assert QQ[x].has_assoc_Field is True assert ZZ[x, y].has_assoc_Field is True assert QQ[x, y].has_assoc_Field is True assert EX.get_field() == EX assert ZZ.get_field() == QQ assert QQ.get_field() == QQ assert RR.get_field() == RR assert ALG.get_field() == ALG assert ZZ[x].get_field() == ZZ.frac_field(x) assert QQ[x].get_field() == QQ.frac_field(x) assert ZZ[x, y].get_field() == ZZ.frac_field(x, y) assert QQ[x, y].get_field() == QQ.frac_field(x, y) def test_Domain_get_exact(): assert EX.get_exact() == EX assert ZZ.get_exact() == ZZ assert QQ.get_exact() == QQ assert RR.get_exact() == QQ assert ALG.get_exact() == ALG assert ZZ[x].get_exact() == ZZ[x] assert QQ[x].get_exact() == QQ[x] assert ZZ[x, y].get_exact() == ZZ[x, y] assert QQ[x, y].get_exact() == QQ[x, y] assert ZZ.frac_field(x).get_exact() == ZZ.frac_field(x) assert QQ.frac_field(x).get_exact() == QQ.frac_field(x) assert ZZ.frac_field(x, y).get_exact() == ZZ.frac_field(x, y) assert QQ.frac_field(x, y).get_exact() == QQ.frac_field(x, y) def test_Domain_is_unit(): nums = [-2, -1, 0, 1, 2] invring = [False, True, False, True, False] invfield = [True, True, False, True, True] ZZx, QQx, QQxf = ZZ[x], QQ[x], QQ.frac_field(x) assert [ZZ.is_unit(ZZ(n)) for n in nums] == invring assert [QQ.is_unit(QQ(n)) for n in nums] == invfield assert [ZZx.is_unit(ZZx(n)) for n in nums] == invring assert [QQx.is_unit(QQx(n)) for n in nums] == invfield assert [QQxf.is_unit(QQxf(n)) for n in nums] == invfield assert ZZx.is_unit(ZZx(x)) is False assert QQx.is_unit(QQx(x)) is False assert QQxf.is_unit(QQxf(x)) is True def test_Domain_convert(): def check_element(e1, e2, K1, K2, K3): assert type(e1) is type(e2), '%s, %s: %s %s -> %s' % (e1, e2, K1, K2, K3) assert e1 == e2, '%s, %s: %s %s -> %s' % (e1, e2, K1, K2, K3) def check_domains(K1, K2): K3 = K1.unify(K2) check_element(K3.convert_from(K1.one, K1), K3.one , K1, K2, K3) check_element(K3.convert_from(K2.one, K2), K3.one , K1, K2, K3) check_element(K3.convert_from(K1.zero, K1), K3.zero, K1, K2, K3) check_element(K3.convert_from(K2.zero, K2), K3.zero, K1, K2, K3) def composite_domains(K): domains = [ K, K[y], K[z], K[y, z], K.frac_field(y), K.frac_field(z), K.frac_field(y, z), # XXX: These should be tested and made to work... # K.old_poly_ring(y), K.old_frac_field(y), ] return domains QQ2 = QQ.algebraic_field(sqrt(2)) QQ3 = QQ.algebraic_field(sqrt(3)) doms = [ZZ, QQ, QQ2, QQ3, QQ_I, ZZ_I, RR, CC] for i, K1 in enumerate(doms): for K2 in doms[i:]: for K3 in composite_domains(K1): for K4 in composite_domains(K2): check_domains(K3, K4) assert QQ.convert(10e-52) == QQ(1684996666696915, 1684996666696914987166688442938726917102321526408785780068975640576) R, xr = ring("x", ZZ) assert ZZ.convert(xr - xr) == 0 assert ZZ.convert(xr - xr, R.to_domain()) == 0 assert CC.convert(ZZ_I(1, 2)) == CC(1, 2) assert CC.convert(QQ_I(1, 2)) == CC(1, 2) K1 = QQ.frac_field(x) K2 = ZZ.frac_field(x) K3 = QQ[x] K4 = ZZ[x] Ks = [K1, K2, K3, K4] for Ka, Kb in cartes(Ks, Ks): assert Ka.convert_from(Kb.from_sympy(x), Kb) == Ka.from_sympy(x) assert K2.convert_from(QQ(1, 2), QQ) == K2(QQ(1, 2)) def test_GlobalPolynomialRing_convert(): K1 = QQ.old_poly_ring(x) K2 = QQ[x] assert K1.convert(x) == K1.convert(K2.convert(x), K2) assert K2.convert(x) == K2.convert(K1.convert(x), K1) K1 = QQ.old_poly_ring(x, y) K2 = QQ[x] assert K1.convert(x) == K1.convert(K2.convert(x), K2) #assert K2.convert(x) == K2.convert(K1.convert(x), K1) K1 = ZZ.old_poly_ring(x, y) K2 = QQ[x] assert K1.convert(x) == K1.convert(K2.convert(x), K2) #assert K2.convert(x) == K2.convert(K1.convert(x), K1) def test_PolynomialRing__init(): R, = ring("", ZZ) assert ZZ.poly_ring() == R.to_domain() def test_FractionField__init(): F, = field("", ZZ) assert ZZ.frac_field() == F.to_domain() def test_FractionField_convert(): K = QQ.frac_field(x) assert K.convert(QQ(2, 3), QQ) == K.from_sympy(Rational(2, 3)) K = QQ.frac_field(x) assert K.convert(ZZ(2), ZZ) == K.from_sympy(Integer(2)) def test_inject(): assert ZZ.inject(x, y, z) == ZZ[x, y, z] assert ZZ[x].inject(y, z) == ZZ[x, y, z] assert ZZ.frac_field(x).inject(y, z) == ZZ.frac_field(x, y, z) raises(GeneratorsError, lambda: ZZ[x].inject(x)) def test_drop(): assert ZZ.drop(x) == ZZ assert ZZ[x].drop(x) == ZZ assert ZZ[x, y].drop(x) == ZZ[y] assert ZZ.frac_field(x).drop(x) == ZZ assert ZZ.frac_field(x, y).drop(x) == ZZ.frac_field(y) assert ZZ[x][y].drop(y) == ZZ[x] assert ZZ[x][y].drop(x) == ZZ[y] assert ZZ.frac_field(x)[y].drop(x) == ZZ[y] assert ZZ.frac_field(x)[y].drop(y) == ZZ.frac_field(x) Ky = FiniteExtension(Poly(x**2-1, x, domain=ZZ[y])) K = FiniteExtension(Poly(x**2-1, x, domain=ZZ)) assert Ky.drop(y) == K raises(GeneratorsError, lambda: Ky.drop(x)) def test_Domain_map(): seq = ZZ.map([1, 2, 3, 4]) assert all(ZZ.of_type(elt) for elt in seq) seq = ZZ.map([[1, 2, 3, 4]]) assert all(ZZ.of_type(elt) for elt in seq[0]) and len(seq) == 1 def test_Domain___eq__(): assert (ZZ[x, y] == ZZ[x, y]) is True assert (QQ[x, y] == QQ[x, y]) is True assert (ZZ[x, y] == QQ[x, y]) is False assert (QQ[x, y] == ZZ[x, y]) is False assert (ZZ.frac_field(x, y) == ZZ.frac_field(x, y)) is True assert (QQ.frac_field(x, y) == QQ.frac_field(x, y)) is True assert (ZZ.frac_field(x, y) == QQ.frac_field(x, y)) is False assert (QQ.frac_field(x, y) == ZZ.frac_field(x, y)) is False assert RealField()[x] == RR[x] def test_Domain__algebraic_field(): alg = ZZ.algebraic_field(sqrt(2)) assert alg.ext.minpoly == Poly(x**2 - 2) assert alg.dom == QQ alg = QQ.algebraic_field(sqrt(2)) assert alg.ext.minpoly == Poly(x**2 - 2) assert alg.dom == QQ alg = alg.algebraic_field(sqrt(3)) assert alg.ext.minpoly == Poly(x**4 - 10*x**2 + 1) assert alg.dom == QQ def test_PolynomialRing_from_FractionField(): F, x,y = field("x,y", ZZ) R, X,Y = ring("x,y", ZZ) f = (x**2 + y**2)/(x + 1) g = (x**2 + y**2)/4 h = x**2 + y**2 assert R.to_domain().from_FractionField(f, F.to_domain()) is None assert R.to_domain().from_FractionField(g, F.to_domain()) == X**2/4 + Y**2/4 assert R.to_domain().from_FractionField(h, F.to_domain()) == X**2 + Y**2 F, x,y = field("x,y", QQ) R, X,Y = ring("x,y", QQ) f = (x**2 + y**2)/(x + 1) g = (x**2 + y**2)/4 h = x**2 + y**2 assert R.to_domain().from_FractionField(f, F.to_domain()) is None assert R.to_domain().from_FractionField(g, F.to_domain()) == X**2/4 + Y**2/4 assert R.to_domain().from_FractionField(h, F.to_domain()) == X**2 + Y**2 def test_FractionField_from_PolynomialRing(): R, x,y = ring("x,y", QQ) F, X,Y = field("x,y", ZZ) f = 3*x**2 + 5*y**2 g = x**2/3 + y**2/5 assert F.to_domain().from_PolynomialRing(f, R.to_domain()) == 3*X**2 + 5*Y**2 assert F.to_domain().from_PolynomialRing(g, R.to_domain()) == (5*X**2 + 3*Y**2)/15 def test_FF_of_type(): assert FF(3).of_type(FF(3)(1)) is True assert FF(5).of_type(FF(5)(3)) is True assert FF(5).of_type(FF(7)(3)) is False def test___eq__(): assert not QQ[x] == ZZ[x] assert not QQ.frac_field(x) == ZZ.frac_field(x) def test_RealField_from_sympy(): assert RR.convert(S.Zero) == RR.dtype(0) assert RR.convert(S(0.0)) == RR.dtype(0.0) assert RR.convert(S.One) == RR.dtype(1) assert RR.convert(S(1.0)) == RR.dtype(1.0) assert RR.convert(sin(1)) == RR.dtype(sin(1).evalf()) def test_not_in_any_domain(): check = illegal + [x] + [ float(i) for i in illegal if i != S.ComplexInfinity] for dom in (ZZ, QQ, RR, CC, EX): for i in check: if i == x and dom == EX: continue assert i not in dom, (i, dom) raises(CoercionFailed, lambda: dom.convert(i)) def test_ModularInteger(): F3 = FF(3) a = F3(0) assert isinstance(a, F3.dtype) and a == 0 a = F3(1) assert isinstance(a, F3.dtype) and a == 1 a = F3(2) assert isinstance(a, F3.dtype) and a == 2 a = F3(3) assert isinstance(a, F3.dtype) and a == 0 a = F3(4) assert isinstance(a, F3.dtype) and a == 1 a = F3(F3(0)) assert isinstance(a, F3.dtype) and a == 0 a = F3(F3(1)) assert isinstance(a, F3.dtype) and a == 1 a = F3(F3(2)) assert isinstance(a, F3.dtype) and a == 2 a = F3(F3(3)) assert isinstance(a, F3.dtype) and a == 0 a = F3(F3(4)) assert isinstance(a, F3.dtype) and a == 1 a = -F3(1) assert isinstance(a, F3.dtype) and a == 2 a = -F3(2) assert isinstance(a, F3.dtype) and a == 1 a = 2 + F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(2) + 2 assert isinstance(a, F3.dtype) and a == 1 a = F3(2) + F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(2) + F3(2) assert isinstance(a, F3.dtype) and a == 1 a = 3 - F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(3) - 2 assert isinstance(a, F3.dtype) and a == 1 a = F3(3) - F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(3) - F3(2) assert isinstance(a, F3.dtype) and a == 1 a = 2*F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(2)*2 assert isinstance(a, F3.dtype) and a == 1 a = F3(2)*F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(2)*F3(2) assert isinstance(a, F3.dtype) and a == 1 a = 2/F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(2)/2 assert isinstance(a, F3.dtype) and a == 1 a = F3(2)/F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(2)/F3(2) assert isinstance(a, F3.dtype) and a == 1 a = 1 % F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(1) % 2 assert isinstance(a, F3.dtype) and a == 1 a = F3(1) % F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(1) % F3(2) assert isinstance(a, F3.dtype) and a == 1 a = F3(2)**0 assert isinstance(a, F3.dtype) and a == 1 a = F3(2)**1 assert isinstance(a, F3.dtype) and a == 2 a = F3(2)**2 assert isinstance(a, F3.dtype) and a == 1 F7 = FF(7) a = F7(3)**100000000000 assert isinstance(a, F7.dtype) and a == 4 a = F7(3)**-100000000000 assert isinstance(a, F7.dtype) and a == 2 a = F7(3)**S(2) assert isinstance(a, F7.dtype) and a == 2 assert bool(F3(3)) is False assert bool(F3(4)) is True F5 = FF(5) a = F5(1)**(-1) assert isinstance(a, F5.dtype) and a == 1 a = F5(2)**(-1) assert isinstance(a, F5.dtype) and a == 3 a = F5(3)**(-1) assert isinstance(a, F5.dtype) and a == 2 a = F5(4)**(-1) assert isinstance(a, F5.dtype) and a == 4 assert (F5(1) < F5(2)) is True assert (F5(1) <= F5(2)) is True assert (F5(1) > F5(2)) is False assert (F5(1) >= F5(2)) is False assert (F5(3) < F5(2)) is False assert (F5(3) <= F5(2)) is False assert (F5(3) > F5(2)) is True assert (F5(3) >= F5(2)) is True assert (F5(1) < F5(7)) is True assert (F5(1) <= F5(7)) is True assert (F5(1) > F5(7)) is False assert (F5(1) >= F5(7)) is False assert (F5(3) < F5(7)) is False assert (F5(3) <= F5(7)) is False assert (F5(3) > F5(7)) is True assert (F5(3) >= F5(7)) is True assert (F5(1) < 2) is True assert (F5(1) <= 2) is True assert (F5(1) > 2) is False assert (F5(1) >= 2) is False assert (F5(3) < 2) is False assert (F5(3) <= 2) is False assert (F5(3) > 2) is True assert (F5(3) >= 2) is True assert (F5(1) < 7) is True assert (F5(1) <= 7) is True assert (F5(1) > 7) is False assert (F5(1) >= 7) is False assert (F5(3) < 7) is False assert (F5(3) <= 7) is False assert (F5(3) > 7) is True assert (F5(3) >= 7) is True raises(NotInvertible, lambda: F5(0)**(-1)) raises(NotInvertible, lambda: F5(5)**(-1)) raises(ValueError, lambda: FF(0)) raises(ValueError, lambda: FF(2.1)) def test_QQ_int(): assert int(QQ(2**2000, 3**1250)) == 455431 assert int(QQ(2**100, 3)) == 422550200076076467165567735125 def test_RR_double(): assert RR(3.14) > 1e-50 assert RR(1e-13) > 1e-50 assert RR(1e-14) > 1e-50 assert RR(1e-15) > 1e-50 assert RR(1e-20) > 1e-50 assert RR(1e-40) > 1e-50 def test_RR_Float(): f1 = Float("1.01") f2 = Float("1.0000000000000000000001") assert f1._prec == 53 assert f2._prec == 80 assert RR(f1)-1 > 1e-50 assert RR(f2)-1 < 1e-50 # RR's precision is lower than f2's RR2 = RealField(prec=f2._prec) assert RR2(f1)-1 > 1e-50 assert RR2(f2)-1 > 1e-50 # RR's precision is equal to f2's def test_CC_double(): assert CC(3.14).real > 1e-50 assert CC(1e-13).real > 1e-50 assert CC(1e-14).real > 1e-50 assert CC(1e-15).real > 1e-50 assert CC(1e-20).real > 1e-50 assert CC(1e-40).real > 1e-50 assert CC(3.14j).imag > 1e-50 assert CC(1e-13j).imag > 1e-50 assert CC(1e-14j).imag > 1e-50 assert CC(1e-15j).imag > 1e-50 assert CC(1e-20j).imag > 1e-50 assert CC(1e-40j).imag > 1e-50 def test_gaussian_domains(): I = S.ImaginaryUnit a, b, c, d = [ZZ_I.convert(x) for x in (5, 2 + I, 3 - I, 5 - 5)] ZZ_I.gcd(a, b) == b ZZ_I.gcd(a, c) == b ZZ_I.lcm(a, b) == a ZZ_I.lcm(a, c) == d assert ZZ_I(3, 4) != QQ_I(3, 4) # XXX is this right or should QQ->ZZ if possible? assert ZZ_I(3, 0) != 3 # and should this go to Integer? assert QQ_I(S(3)/4, 0) != S(3)/4 # and this to Rational? assert ZZ_I(0, 0).quadrant() == 0 assert ZZ_I(-1, 0).quadrant() == 2 assert QQ_I.convert(QQ(3, 2)) == QQ_I(QQ(3, 2), QQ(0)) assert QQ_I.convert(QQ(3, 2), QQ) == QQ_I(QQ(3, 2), QQ(0)) for G in (QQ_I, ZZ_I): q = G(3, 4) assert str(q) == '3 + 4*I' assert q.parent() == G assert q._get_xy(pi) == (None, None) assert q._get_xy(2) == (2, 0) assert q._get_xy(2*I) == (0, 2) assert hash(q) == hash((3, 4)) assert G(1, 2) == G(1, 2) assert G(1, 2) != G(1, 3) assert G(3, 0) == G(3) assert q + q == G(6, 8) assert q - q == G(0, 0) assert 3 - q == -q + 3 == G(0, -4) assert 3 + q == q + 3 == G(6, 4) assert q * q == G(-7, 24) assert 3 * q == q * 3 == G(9, 12) assert q ** 0 == G(1, 0) assert q ** 1 == q assert q ** 2 == q * q == G(-7, 24) assert q ** 3 == q * q * q == G(-117, 44) assert 1 / q == q ** -1 == QQ_I(S(3)/25, - S(4)/25) assert q / 1 == QQ_I(3, 4) assert q / 2 == QQ_I(S(3)/2, 2) assert q/3 == QQ_I(1, S(4)/3) assert 3/q == QQ_I(S(9)/25, -S(12)/25) i, r = divmod(q, 2) assert 2*i + r == q i, r = divmod(2, q) assert q*i + r == G(2, 0) raises(ZeroDivisionError, lambda: q % 0) raises(ZeroDivisionError, lambda: q / 0) raises(ZeroDivisionError, lambda: q // 0) raises(ZeroDivisionError, lambda: divmod(q, 0)) raises(ZeroDivisionError, lambda: divmod(q, 0)) raises(TypeError, lambda: q + x) raises(TypeError, lambda: q - x) raises(TypeError, lambda: x + q) raises(TypeError, lambda: x - q) raises(TypeError, lambda: q * x) raises(TypeError, lambda: x * q) raises(TypeError, lambda: q / x) raises(TypeError, lambda: x / q) raises(TypeError, lambda: q // x) raises(TypeError, lambda: x // q) assert G.from_sympy(S(2)) == G(2, 0) assert G.to_sympy(G(2, 0)) == S(2) raises(CoercionFailed, lambda: G.from_sympy(pi)) PR = G.inject(x) assert isinstance(PR, PolynomialRing) assert PR.domain == G assert len(PR.gens) == 1 and PR.gens[0].as_expr() == x if G is QQ_I: AF = G.as_AlgebraicField() assert isinstance(AF, AlgebraicField) assert AF.domain == QQ assert AF.ext.args[0] == I for qi in [G(-1, 0), G(1, 0), G(0, -1), G(0, 1)]: assert G.is_negative(qi) is False assert G.is_positive(qi) is False assert G.is_nonnegative(qi) is False assert G.is_nonpositive(qi) is False domains = [ZZ_python(), QQ_python(), AlgebraicField(QQ, I)] if HAS_GMPY: domains += [ZZ_gmpy(), QQ_gmpy()] for K in domains: assert G.convert(K(2)) == G(2, 0) assert G.convert(K(2), K) == G(2, 0) for K in ZZ_I, QQ_I: assert G.convert(K(1, 1)) == G(1, 1) assert G.convert(K(1, 1), K) == G(1, 1) if G == ZZ_I: assert repr(q) == 'ZZ_I(3, 4)' assert q//3 == G(1, 1) assert 12//q == G(1, -2) assert 12 % q == G(1, 2) assert q % 2 == G(-1, 0) assert i == G(0, 0) assert r == G(2, 0) assert G.get_ring() == G assert G.get_field() == QQ_I else: assert repr(q) == 'QQ_I(3, 4)' assert G.get_ring() == ZZ_I assert G.get_field() == G assert q//3 == G(1, S(4)/3) assert 12//q == G(S(36)/25, -S(48)/25) assert 12 % q == G(0, 0) assert q % 2 == G(0, 0) assert i == G(S(6)/25, -S(8)/25), (G,i) assert r == G(0, 0) q2 = G(S(3)/2, S(5)/3) assert G.numer(q2) == ZZ_I(9, 10) assert G.denom(q2) == ZZ_I(6) def test_EX_EXRAW(): assert EXRAW.zero is S.Zero assert EXRAW.one is S.One assert EX(1) == EX.Expression(1) assert EX(1).ex is S.One assert EXRAW(1) is S.One # EX has cancelling but EXRAW does not assert 2*EX((x + y*x)/x) == EX(2 + 2*y) != 2*((x + y*x)/x) assert 2*EXRAW((x + y*x)/x) == 2*((x + y*x)/x) != (1 + y) assert EXRAW.convert_from(EX(1), EX) is EXRAW.one assert EX.convert_from(EXRAW(1), EXRAW) == EX.one assert EXRAW.from_sympy(S.One) is S.One assert EXRAW.to_sympy(EXRAW.one) is S.One raises(CoercionFailed, lambda: EXRAW.from_sympy([])) assert EXRAW.get_field() == EXRAW assert EXRAW.unify(EX) == EXRAW assert EX.unify(EXRAW) == EXRAW def test_canonical_unit(): for K in [ZZ, QQ, RR]: # CC? assert K.canonical_unit(K(2)) == K(1) assert K.canonical_unit(K(-2)) == K(-1) for K in [ZZ_I, QQ_I]: i = K.from_sympy(I) assert K.canonical_unit(K(2)) == K(1) assert K.canonical_unit(K(2)*i) == -i assert K.canonical_unit(-K(2)) == K(-1) assert K.canonical_unit(-K(2)*i) == i K = ZZ[x] assert K.canonical_unit(K(x + 1)) == K(1) assert K.canonical_unit(K(-x + 1)) == K(-1) K = ZZ_I[x] assert K.canonical_unit(K.from_sympy(I*x)) == ZZ_I(0, -1) K = ZZ_I.frac_field(x, y) i = K.from_sympy(I) assert i / i == K.one assert (K.one + i)/(i - K.one) == -i def test_issue_18278(): assert str(RR(2).parent()) == 'RR' assert str(CC(2).parent()) == 'CC' def test_Domain_is_negative(): I = S.ImaginaryUnit a, b = [CC.convert(x) for x in (2 + I, 5)] assert CC.is_negative(a) == False assert CC.is_negative(b) == False def test_Domain_is_positive(): I = S.ImaginaryUnit a, b = [CC.convert(x) for x in (2 + I, 5)] assert CC.is_positive(a) == False assert CC.is_positive(b) == False def test_Domain_is_nonnegative(): I = S.ImaginaryUnit a, b = [CC.convert(x) for x in (2 + I, 5)] assert CC.is_nonnegative(a) == False assert CC.is_nonnegative(b) == False def test_Domain_is_nonpositive(): I = S.ImaginaryUnit a, b = [CC.convert(x) for x in (2 + I, 5)] assert CC.is_nonpositive(a) == False assert CC.is_nonpositive(b) == False def test_exponential_domain(): K = ZZ[E] eK = K.from_sympy(E) assert K.from_sympy(exp(3)) == eK ** 3 assert K.convert(exp(3)) == eK ** 3 sympy-sympy-1.9/sympy/polys/domains/tests/test_polynomialring.py000066400000000000000000000063601412543434000255270ustar00rootroot00000000000000"""Tests for the PolynomialRing classes. """ from sympy.polys.domains import QQ, ZZ from sympy.polys.polyerrors import ExactQuotientFailed, CoercionFailed, NotReversible from sympy.abc import x, y from sympy.testing.pytest import raises def test_build_order(): R = QQ.old_poly_ring(x, y, order=(("lex", x), ("ilex", y))) assert R.order((1, 5)) == ((1,), (-5,)) def test_globalring(): Qxy = QQ.old_frac_field(x, y) R = QQ.old_poly_ring(x, y) X = R.convert(x) Y = R.convert(y) assert x in R assert 1/x not in R assert 1/(1 + x) not in R assert Y in R assert X.ring == R assert X * (Y**2 + 1) == R.convert(x * (y**2 + 1)) assert X * y == X * Y == R.convert(x * y) == x * Y assert X + y == X + Y == R.convert(x + y) == x + Y assert X - y == X - Y == R.convert(x - y) == x - Y assert X + 1 == R.convert(x + 1) raises(ExactQuotientFailed, lambda: X/Y) raises(ExactQuotientFailed, lambda: x/Y) raises(ExactQuotientFailed, lambda: X/y) assert X**2 / X == X assert R.from_GlobalPolynomialRing(ZZ.old_poly_ring(x, y).convert(x), ZZ.old_poly_ring(x, y)) == X assert R.from_FractionField(Qxy.convert(x), Qxy) == X assert R.from_FractionField(Qxy.convert(x)/y, Qxy) is None assert R._sdm_to_vector(R._vector_to_sdm([X, Y], R.order), 2) == [X, Y] def test_localring(): Qxy = QQ.old_frac_field(x, y) R = QQ.old_poly_ring(x, y, order="ilex") X = R.convert(x) Y = R.convert(y) assert x in R assert 1/x not in R assert 1/(1 + x) in R assert Y in R assert X.ring == R assert X*(Y**2 + 1)/(1 + X) == R.convert(x*(y**2 + 1)/(1 + x)) assert X*y == X*Y raises(ExactQuotientFailed, lambda: X/Y) raises(ExactQuotientFailed, lambda: x/Y) raises(ExactQuotientFailed, lambda: X/y) assert X + y == X + Y == R.convert(x + y) == x + Y assert X - y == X - Y == R.convert(x - y) == x - Y assert X + 1 == R.convert(x + 1) assert X**2 / X == X assert R.from_GlobalPolynomialRing(ZZ.old_poly_ring(x, y).convert(x), ZZ.old_poly_ring(x, y)) == X assert R.from_FractionField(Qxy.convert(x), Qxy) == X raises(CoercionFailed, lambda: R.from_FractionField(Qxy.convert(x)/y, Qxy)) raises(ExactQuotientFailed, lambda: X/Y) raises(NotReversible, lambda: X.invert()) assert R._sdm_to_vector( R._vector_to_sdm([X/(X + 1), Y/(1 + X*Y)], R.order), 2) == \ [X*(1 + X*Y), Y*(1 + X)] def test_conversion(): L = QQ.old_poly_ring(x, y, order="ilex") G = QQ.old_poly_ring(x, y) assert L.convert(x) == L.convert(G.convert(x), G) assert G.convert(x) == G.convert(L.convert(x), L) raises(CoercionFailed, lambda: G.convert(L.convert(1/(1 + x)), L)) def test_units(): R = QQ.old_poly_ring(x) assert R.is_unit(R.convert(1)) assert R.is_unit(R.convert(2)) assert not R.is_unit(R.convert(x)) assert not R.is_unit(R.convert(1 + x)) R = QQ.old_poly_ring(x, order='ilex') assert R.is_unit(R.convert(1)) assert R.is_unit(R.convert(2)) assert not R.is_unit(R.convert(x)) assert R.is_unit(R.convert(1 + x)) R = ZZ.old_poly_ring(x) assert R.is_unit(R.convert(1)) assert not R.is_unit(R.convert(2)) assert not R.is_unit(R.convert(x)) assert not R.is_unit(R.convert(1 + x)) sympy-sympy-1.9/sympy/polys/domains/tests/test_quotientring.py000066400000000000000000000025541412543434000252150ustar00rootroot00000000000000"""Tests for quotient rings.""" from sympy import QQ, ZZ from sympy.abc import x, y from sympy.polys.polyerrors import NotReversible from sympy.testing.pytest import raises def test_QuotientRingElement(): R = QQ.old_poly_ring(x)/[x**10] X = R.convert(x) assert X*(X + 1) == R.convert(x**2 + x) assert X*x == R.convert(x**2) assert x*X == R.convert(x**2) assert X + x == R.convert(2*x) assert x + X == 2*X assert X**2 == R.convert(x**2) assert 1/(1 - X) == R.convert(sum(x**i for i in range(10))) assert X**10 == R.zero assert X != x raises(NotReversible, lambda: 1/X) def test_QuotientRing(): I = QQ.old_poly_ring(x).ideal(x**2 + 1) R = QQ.old_poly_ring(x)/I assert R == QQ.old_poly_ring(x)/[x**2 + 1] assert R == QQ.old_poly_ring(x)/QQ.old_poly_ring(x).ideal(x**2 + 1) assert R != QQ.old_poly_ring(x) assert R.convert(1)/x == -x + I assert -1 + I == x**2 + I assert R.convert(ZZ(1), ZZ) == 1 + I assert R.convert(R.convert(x), R) == R.convert(x) X = R.convert(x) Y = QQ.old_poly_ring(x).convert(x) assert -1 + I == X**2 + I assert -1 + I == Y**2 + I assert R.to_sympy(X) == x raises(ValueError, lambda: QQ.old_poly_ring(x)/QQ.old_poly_ring(x, y).ideal(x)) R = QQ.old_poly_ring(x, order="ilex") I = R.ideal(x) assert R.convert(1) + I == (R/I).convert(1) sympy-sympy-1.9/sympy/polys/euclidtools.py000066400000000000000000001203771412543434000211640ustar00rootroot00000000000000"""Euclidean algorithms, GCDs, LCMs and polynomial remainder sequences. """ from sympy.ntheory import nextprime from sympy.polys.densearith import ( dup_sub_mul, dup_neg, dmp_neg, dmp_add, dmp_sub, dup_mul, dmp_mul, dmp_pow, dup_div, dmp_div, dup_rem, dup_quo, dmp_quo, dup_prem, dmp_prem, dup_mul_ground, dmp_mul_ground, dmp_mul_term, dup_quo_ground, dmp_quo_ground, dup_max_norm, dmp_max_norm) from sympy.polys.densebasic import ( dup_strip, dmp_raise, dmp_zero, dmp_one, dmp_ground, dmp_one_p, dmp_zero_p, dmp_zeros, dup_degree, dmp_degree, dmp_degree_in, dup_LC, dmp_LC, dmp_ground_LC, dmp_multi_deflate, dmp_inflate, dup_convert, dmp_convert, dmp_apply_pairs) from sympy.polys.densetools import ( dup_clear_denoms, dmp_clear_denoms, dup_diff, dmp_diff, dup_eval, dmp_eval, dmp_eval_in, dup_trunc, dmp_ground_trunc, dup_monic, dmp_ground_monic, dup_primitive, dmp_ground_primitive, dup_extract, dmp_ground_extract) from sympy.polys.galoistools import ( gf_int, gf_crt) from sympy.polys.polyconfig import query from sympy.polys.polyerrors import ( MultivariatePolynomialError, HeuristicGCDFailed, HomomorphismFailed, NotInvertible, DomainError) def dup_half_gcdex(f, g, K): """ Half extended Euclidean algorithm in `F[x]`. Returns ``(s, h)`` such that ``h = gcd(f, g)`` and ``s*f = h (mod g)``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 >>> g = x**3 + x**2 - 4*x - 4 >>> R.dup_half_gcdex(f, g) (-1/5*x + 3/5, x + 1) """ if not K.is_Field: raise DomainError("can't compute half extended GCD over %s" % K) a, b = [K.one], [] while g: q, r = dup_div(f, g, K) f, g = g, r a, b = b, dup_sub_mul(a, q, b, K) a = dup_quo_ground(a, dup_LC(f, K), K) f = dup_monic(f, K) return a, f def dmp_half_gcdex(f, g, u, K): """ Half extended Euclidean algorithm in `F[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) """ if not u: return dup_half_gcdex(f, g, K) else: raise MultivariatePolynomialError(f, g) def dup_gcdex(f, g, K): """ Extended Euclidean algorithm in `F[x]`. Returns ``(s, t, h)`` such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 >>> g = x**3 + x**2 - 4*x - 4 >>> R.dup_gcdex(f, g) (-1/5*x + 3/5, 1/5*x**2 - 6/5*x + 2, x + 1) """ s, h = dup_half_gcdex(f, g, K) F = dup_sub_mul(h, s, f, K) t = dup_quo(F, g, K) return s, t, h def dmp_gcdex(f, g, u, K): """ Extended Euclidean algorithm in `F[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) """ if not u: return dup_gcdex(f, g, K) else: raise MultivariatePolynomialError(f, g) def dup_invert(f, g, K): """ Compute multiplicative inverse of `f` modulo `g` in `F[x]`. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = x**2 - 1 >>> g = 2*x - 1 >>> h = x - 1 >>> R.dup_invert(f, g) -4/3 >>> R.dup_invert(f, h) Traceback (most recent call last): ... NotInvertible: zero divisor """ s, h = dup_half_gcdex(f, g, K) if h == [K.one]: return dup_rem(s, g, K) else: raise NotInvertible("zero divisor") def dmp_invert(f, g, u, K): """ Compute multiplicative inverse of `f` modulo `g` in `F[X]`. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) """ if not u: return dup_invert(f, g, K) else: raise MultivariatePolynomialError(f, g) def dup_euclidean_prs(f, g, K): """ Euclidean polynomial remainder sequence (PRS) in `K[x]`. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 >>> prs = R.dup_euclidean_prs(f, g) >>> prs[0] x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 >>> prs[1] 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 >>> prs[2] -5/9*x**4 + 1/9*x**2 - 1/3 >>> prs[3] -117/25*x**2 - 9*x + 441/25 >>> prs[4] 233150/19773*x - 102500/6591 >>> prs[5] -1288744821/543589225 """ prs = [f, g] h = dup_rem(f, g, K) while h: prs.append(h) f, g = g, h h = dup_rem(f, g, K) return prs def dmp_euclidean_prs(f, g, u, K): """ Euclidean polynomial remainder sequence (PRS) in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) """ if not u: return dup_euclidean_prs(f, g, K) else: raise MultivariatePolynomialError(f, g) def dup_primitive_prs(f, g, K): """ Primitive polynomial remainder sequence (PRS) in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 >>> g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 >>> prs = R.dup_primitive_prs(f, g) >>> prs[0] x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 >>> prs[1] 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 >>> prs[2] -5*x**4 + x**2 - 3 >>> prs[3] 13*x**2 + 25*x - 49 >>> prs[4] 4663*x - 6150 >>> prs[5] 1 """ prs = [f, g] _, h = dup_primitive(dup_prem(f, g, K), K) while h: prs.append(h) f, g = g, h _, h = dup_primitive(dup_prem(f, g, K), K) return prs def dmp_primitive_prs(f, g, u, K): """ Primitive polynomial remainder sequence (PRS) in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) """ if not u: return dup_primitive_prs(f, g, K) else: raise MultivariatePolynomialError(f, g) def dup_inner_subresultants(f, g, K): """ Subresultant PRS algorithm in `K[x]`. Computes the subresultant polynomial remainder sequence (PRS) and the non-zero scalar subresultants of `f` and `g`. By [1] Thm. 3, these are the constants '-c' (- to optimize computation of sign). The first subdeterminant is set to 1 by convention to match the polynomial and the scalar subdeterminants. If 'deg(f) < deg(g)', the subresultants of '(g,f)' are computed. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_inner_subresultants(x**2 + 1, x**2 - 1) ([x**2 + 1, x**2 - 1, -2], [1, 1, 4]) References ========== .. [1] W.S. Brown, The Subresultant PRS Algorithm. ACM Transaction of Mathematical Software 4 (1978) 237-249 """ n = dup_degree(f) m = dup_degree(g) if n < m: f, g = g, f n, m = m, n if not f: return [], [] if not g: return [f], [K.one] R = [f, g] d = n - m b = (-K.one)**(d + 1) h = dup_prem(f, g, K) h = dup_mul_ground(h, b, K) lc = dup_LC(g, K) c = lc**d # Conventional first scalar subdeterminant is 1 S = [K.one, c] c = -c while h: k = dup_degree(h) R.append(h) f, g, m, d = g, h, k, m - k b = -lc * c**d h = dup_prem(f, g, K) h = dup_quo_ground(h, b, K) lc = dup_LC(g, K) if d > 1: # abnormal case q = c**(d - 1) c = K.quo((-lc)**d, q) else: c = -lc S.append(-c) return R, S def dup_subresultants(f, g, K): """ Computes subresultant PRS of two polynomials in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_subresultants(x**2 + 1, x**2 - 1) [x**2 + 1, x**2 - 1, -2] """ return dup_inner_subresultants(f, g, K)[0] def dup_prs_resultant(f, g, K): """ Resultant algorithm in `K[x]` using subresultant PRS. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_prs_resultant(x**2 + 1, x**2 - 1) (4, [x**2 + 1, x**2 - 1, -2]) """ if not f or not g: return (K.zero, []) R, S = dup_inner_subresultants(f, g, K) if dup_degree(R[-1]) > 0: return (K.zero, R) return S[-1], R def dup_resultant(f, g, K, includePRS=False): """ Computes resultant of two polynomials in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_resultant(x**2 + 1, x**2 - 1) 4 """ if includePRS: return dup_prs_resultant(f, g, K) return dup_prs_resultant(f, g, K)[0] def dmp_inner_subresultants(f, g, u, K): """ Subresultant PRS algorithm in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 3*x**2*y - y**3 - 4 >>> g = x**2 + x*y**3 - 9 >>> a = 3*x*y**4 + y**3 - 27*y + 4 >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 >>> prs = [f, g, a, b] >>> sres = [[1], [1], [3, 0, 0, 0, 0], [-3, 0, 0, -12, 1, 0, -54, 8, 729, -216, 16]] >>> R.dmp_inner_subresultants(f, g) == (prs, sres) True """ if not u: return dup_inner_subresultants(f, g, K) n = dmp_degree(f, u) m = dmp_degree(g, u) if n < m: f, g = g, f n, m = m, n if dmp_zero_p(f, u): return [], [] v = u - 1 if dmp_zero_p(g, u): return [f], [dmp_ground(K.one, v)] R = [f, g] d = n - m b = dmp_pow(dmp_ground(-K.one, v), d + 1, v, K) h = dmp_prem(f, g, u, K) h = dmp_mul_term(h, b, 0, u, K) lc = dmp_LC(g, K) c = dmp_pow(lc, d, v, K) S = [dmp_ground(K.one, v), c] c = dmp_neg(c, v, K) while not dmp_zero_p(h, u): k = dmp_degree(h, u) R.append(h) f, g, m, d = g, h, k, m - k b = dmp_mul(dmp_neg(lc, v, K), dmp_pow(c, d, v, K), v, K) h = dmp_prem(f, g, u, K) h = [ dmp_quo(ch, b, v, K) for ch in h ] lc = dmp_LC(g, K) if d > 1: p = dmp_pow(dmp_neg(lc, v, K), d, v, K) q = dmp_pow(c, d - 1, v, K) c = dmp_quo(p, q, v, K) else: c = dmp_neg(lc, v, K) S.append(dmp_neg(c, v, K)) return R, S def dmp_subresultants(f, g, u, K): """ Computes subresultant PRS of two polynomials in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 3*x**2*y - y**3 - 4 >>> g = x**2 + x*y**3 - 9 >>> a = 3*x*y**4 + y**3 - 27*y + 4 >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 >>> R.dmp_subresultants(f, g) == [f, g, a, b] True """ return dmp_inner_subresultants(f, g, u, K)[0] def dmp_prs_resultant(f, g, u, K): """ Resultant algorithm in `K[X]` using subresultant PRS. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 3*x**2*y - y**3 - 4 >>> g = x**2 + x*y**3 - 9 >>> a = 3*x*y**4 + y**3 - 27*y + 4 >>> b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 >>> res, prs = R.dmp_prs_resultant(f, g) >>> res == b # resultant has n-1 variables False >>> res == b.drop(x) True >>> prs == [f, g, a, b] True """ if not u: return dup_prs_resultant(f, g, K) if dmp_zero_p(f, u) or dmp_zero_p(g, u): return (dmp_zero(u - 1), []) R, S = dmp_inner_subresultants(f, g, u, K) if dmp_degree(R[-1], u) > 0: return (dmp_zero(u - 1), R) return S[-1], R def dmp_zz_modular_resultant(f, g, p, u, K): """ Compute resultant of `f` and `g` modulo a prime `p`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x + y + 2 >>> g = 2*x*y + x + 3 >>> R.dmp_zz_modular_resultant(f, g, 5) -2*y**2 + 1 """ if not u: return gf_int(dup_prs_resultant(f, g, K)[0] % p, p) v = u - 1 n = dmp_degree(f, u) m = dmp_degree(g, u) N = dmp_degree_in(f, 1, u) M = dmp_degree_in(g, 1, u) B = n*M + m*N D, a = [K.one], -K.one r = dmp_zero(v) while dup_degree(D) <= B: while True: a += K.one if a == p: raise HomomorphismFailed('no luck') F = dmp_eval_in(f, gf_int(a, p), 1, u, K) if dmp_degree(F, v) == n: G = dmp_eval_in(g, gf_int(a, p), 1, u, K) if dmp_degree(G, v) == m: break R = dmp_zz_modular_resultant(F, G, p, v, K) e = dmp_eval(r, a, v, K) if not v: R = dup_strip([R]) e = dup_strip([e]) else: R = [R] e = [e] d = K.invert(dup_eval(D, a, K), p) d = dup_mul_ground(D, d, K) d = dmp_raise(d, v, 0, K) c = dmp_mul(d, dmp_sub(R, e, v, K), v, K) r = dmp_add(r, c, v, K) r = dmp_ground_trunc(r, p, v, K) D = dup_mul(D, [K.one, -a], K) D = dup_trunc(D, p, K) return r def _collins_crt(r, R, P, p, K): """Wrapper of CRT for Collins's resultant algorithm. """ return gf_int(gf_crt([r, R], [P, p], K), P*p) def dmp_zz_collins_resultant(f, g, u, K): """ Collins's modular resultant algorithm in `Z[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x + y + 2 >>> g = 2*x*y + x + 3 >>> R.dmp_zz_collins_resultant(f, g) -2*y**2 - 5*y + 1 """ n = dmp_degree(f, u) m = dmp_degree(g, u) if n < 0 or m < 0: return dmp_zero(u - 1) A = dmp_max_norm(f, u, K) B = dmp_max_norm(g, u, K) a = dmp_ground_LC(f, u, K) b = dmp_ground_LC(g, u, K) v = u - 1 B = K(2)*K.factorial(K(n + m))*A**m*B**n r, p, P = dmp_zero(v), K.one, K.one while P <= B: p = K(nextprime(p)) while not (a % p) or not (b % p): p = K(nextprime(p)) F = dmp_ground_trunc(f, p, u, K) G = dmp_ground_trunc(g, p, u, K) try: R = dmp_zz_modular_resultant(F, G, p, u, K) except HomomorphismFailed: continue if K.is_one(P): r = R else: r = dmp_apply_pairs(r, R, _collins_crt, (P, p, K), v, K) P *= p return r def dmp_qq_collins_resultant(f, g, u, K0): """ Collins's modular resultant algorithm in `Q[X]`. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y = ring("x,y", QQ) >>> f = QQ(1,2)*x + y + QQ(2,3) >>> g = 2*x*y + x + 3 >>> R.dmp_qq_collins_resultant(f, g) -2*y**2 - 7/3*y + 5/6 """ n = dmp_degree(f, u) m = dmp_degree(g, u) if n < 0 or m < 0: return dmp_zero(u - 1) K1 = K0.get_ring() cf, f = dmp_clear_denoms(f, u, K0, K1) cg, g = dmp_clear_denoms(g, u, K0, K1) f = dmp_convert(f, u, K0, K1) g = dmp_convert(g, u, K0, K1) r = dmp_zz_collins_resultant(f, g, u, K1) r = dmp_convert(r, u - 1, K1, K0) c = K0.convert(cf**m * cg**n, K1) return dmp_quo_ground(r, c, u - 1, K0) def dmp_resultant(f, g, u, K, includePRS=False): """ Computes resultant of two polynomials in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = 3*x**2*y - y**3 - 4 >>> g = x**2 + x*y**3 - 9 >>> R.dmp_resultant(f, g) -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 """ if not u: return dup_resultant(f, g, K, includePRS=includePRS) if includePRS: return dmp_prs_resultant(f, g, u, K) if K.is_Field: if K.is_QQ and query('USE_COLLINS_RESULTANT'): return dmp_qq_collins_resultant(f, g, u, K) else: if K.is_ZZ and query('USE_COLLINS_RESULTANT'): return dmp_zz_collins_resultant(f, g, u, K) return dmp_prs_resultant(f, g, u, K)[0] def dup_discriminant(f, K): """ Computes discriminant of a polynomial in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_discriminant(x**2 + 2*x + 3) -8 """ d = dup_degree(f) if d <= 0: return K.zero else: s = (-1)**((d*(d - 1)) // 2) c = dup_LC(f, K) r = dup_resultant(f, dup_diff(f, 1, K), K) return K.quo(r, c*K(s)) def dmp_discriminant(f, u, K): """ Computes discriminant of a polynomial in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y,z,t = ring("x,y,z,t", ZZ) >>> R.dmp_discriminant(x**2*y + x*z + t) -4*y*t + z**2 """ if not u: return dup_discriminant(f, K) d, v = dmp_degree(f, u), u - 1 if d <= 0: return dmp_zero(v) else: s = (-1)**((d*(d - 1)) // 2) c = dmp_LC(f, K) r = dmp_resultant(f, dmp_diff(f, 1, u, K), u, K) c = dmp_mul_ground(c, K(s), v, K) return dmp_quo(r, c, v, K) def _dup_rr_trivial_gcd(f, g, K): """Handle trivial cases in GCD algorithm over a ring. """ if not (f or g): return [], [], [] elif not f: if K.is_nonnegative(dup_LC(g, K)): return g, [], [K.one] else: return dup_neg(g, K), [], [-K.one] elif not g: if K.is_nonnegative(dup_LC(f, K)): return f, [K.one], [] else: return dup_neg(f, K), [-K.one], [] return None def _dup_ff_trivial_gcd(f, g, K): """Handle trivial cases in GCD algorithm over a field. """ if not (f or g): return [], [], [] elif not f: return dup_monic(g, K), [], [dup_LC(g, K)] elif not g: return dup_monic(f, K), [dup_LC(f, K)], [] else: return None def _dmp_rr_trivial_gcd(f, g, u, K): """Handle trivial cases in GCD algorithm over a ring. """ zero_f = dmp_zero_p(f, u) zero_g = dmp_zero_p(g, u) if_contain_one = dmp_one_p(f, u, K) or dmp_one_p(g, u, K) if zero_f and zero_g: return tuple(dmp_zeros(3, u, K)) elif zero_f: if K.is_nonnegative(dmp_ground_LC(g, u, K)): return g, dmp_zero(u), dmp_one(u, K) else: return dmp_neg(g, u, K), dmp_zero(u), dmp_ground(-K.one, u) elif zero_g: if K.is_nonnegative(dmp_ground_LC(f, u, K)): return f, dmp_one(u, K), dmp_zero(u) else: return dmp_neg(f, u, K), dmp_ground(-K.one, u), dmp_zero(u) elif if_contain_one: return dmp_one(u, K), f, g elif query('USE_SIMPLIFY_GCD'): return _dmp_simplify_gcd(f, g, u, K) else: return None def _dmp_ff_trivial_gcd(f, g, u, K): """Handle trivial cases in GCD algorithm over a field. """ zero_f = dmp_zero_p(f, u) zero_g = dmp_zero_p(g, u) if zero_f and zero_g: return tuple(dmp_zeros(3, u, K)) elif zero_f: return (dmp_ground_monic(g, u, K), dmp_zero(u), dmp_ground(dmp_ground_LC(g, u, K), u)) elif zero_g: return (dmp_ground_monic(f, u, K), dmp_ground(dmp_ground_LC(f, u, K), u), dmp_zero(u)) elif query('USE_SIMPLIFY_GCD'): return _dmp_simplify_gcd(f, g, u, K) else: return None def _dmp_simplify_gcd(f, g, u, K): """Try to eliminate `x_0` from GCD computation in `K[X]`. """ df = dmp_degree(f, u) dg = dmp_degree(g, u) if df > 0 and dg > 0: return None if not (df or dg): F = dmp_LC(f, K) G = dmp_LC(g, K) else: if not df: F = dmp_LC(f, K) G = dmp_content(g, u, K) else: F = dmp_content(f, u, K) G = dmp_LC(g, K) v = u - 1 h = dmp_gcd(F, G, v, K) cff = [ dmp_quo(cf, h, v, K) for cf in f ] cfg = [ dmp_quo(cg, h, v, K) for cg in g ] return [h], cff, cfg def dup_rr_prs_gcd(f, g, K): """ Computes polynomial GCD using subresultants over a ring. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_rr_prs_gcd(x**2 - 1, x**2 - 3*x + 2) (x - 1, x + 1, x - 2) """ result = _dup_rr_trivial_gcd(f, g, K) if result is not None: return result fc, F = dup_primitive(f, K) gc, G = dup_primitive(g, K) c = K.gcd(fc, gc) h = dup_subresultants(F, G, K)[-1] _, h = dup_primitive(h, K) c *= K.canonical_unit(dup_LC(h, K)) h = dup_mul_ground(h, c, K) cff = dup_quo(f, h, K) cfg = dup_quo(g, h, K) return h, cff, cfg def dup_ff_prs_gcd(f, g, K): """ Computes polynomial GCD using subresultants over a field. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> R.dup_ff_prs_gcd(x**2 - 1, x**2 - 3*x + 2) (x - 1, x + 1, x - 2) """ result = _dup_ff_trivial_gcd(f, g, K) if result is not None: return result h = dup_subresultants(f, g, K)[-1] h = dup_monic(h, K) cff = dup_quo(f, h, K) cfg = dup_quo(g, h, K) return h, cff, cfg def dmp_rr_prs_gcd(f, g, u, K): """ Computes polynomial GCD using subresultants over a ring. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> f = x**2 + 2*x*y + y**2 >>> g = x**2 + x*y >>> R.dmp_rr_prs_gcd(f, g) (x + y, x + y, x) """ if not u: return dup_rr_prs_gcd(f, g, K) result = _dmp_rr_trivial_gcd(f, g, u, K) if result is not None: return result fc, F = dmp_primitive(f, u, K) gc, G = dmp_primitive(g, u, K) h = dmp_subresultants(F, G, u, K)[-1] c, _, _ = dmp_rr_prs_gcd(fc, gc, u - 1, K) if K.is_negative(dmp_ground_LC(h, u, K)): h = dmp_neg(h, u, K) _, h = dmp_primitive(h, u, K) h = dmp_mul_term(h, c, 0, u, K) cff = dmp_quo(f, h, u, K) cfg = dmp_quo(g, h, u, K) return h, cff, cfg def dmp_ff_prs_gcd(f, g, u, K): """ Computes polynomial GCD using subresultants over a field. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y, = ring("x,y", QQ) >>> f = QQ(1,2)*x**2 + x*y + QQ(1,2)*y**2 >>> g = x**2 + x*y >>> R.dmp_ff_prs_gcd(f, g) (x + y, 1/2*x + 1/2*y, x) """ if not u: return dup_ff_prs_gcd(f, g, K) result = _dmp_ff_trivial_gcd(f, g, u, K) if result is not None: return result fc, F = dmp_primitive(f, u, K) gc, G = dmp_primitive(g, u, K) h = dmp_subresultants(F, G, u, K)[-1] c, _, _ = dmp_ff_prs_gcd(fc, gc, u - 1, K) _, h = dmp_primitive(h, u, K) h = dmp_mul_term(h, c, 0, u, K) h = dmp_ground_monic(h, u, K) cff = dmp_quo(f, h, u, K) cfg = dmp_quo(g, h, u, K) return h, cff, cfg HEU_GCD_MAX = 6 def _dup_zz_gcd_interpolate(h, x, K): """Interpolate polynomial GCD from integer GCD. """ f = [] while h: g = h % x if g > x // 2: g -= x f.insert(0, g) h = (h - g) // x return f def dup_zz_heu_gcd(f, g, K): """ Heuristic polynomial GCD in `Z[x]`. Given univariate polynomials `f` and `g` in `Z[x]`, returns their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` such that:: h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) The algorithm is purely heuristic which means it may fail to compute the GCD. This will be signaled by raising an exception. In this case you will need to switch to another GCD method. The algorithm computes the polynomial GCD by evaluating polynomials f and g at certain points and computing (fast) integer GCD of those evaluations. The polynomial GCD is recovered from the integer image by interpolation. The final step is to verify if the result is the correct GCD. This gives cofactors as a side effect. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_zz_heu_gcd(x**2 - 1, x**2 - 3*x + 2) (x - 1, x + 1, x - 2) References ========== .. [1] [Liao95]_ """ result = _dup_rr_trivial_gcd(f, g, K) if result is not None: return result df = dup_degree(f) dg = dup_degree(g) gcd, f, g = dup_extract(f, g, K) if df == 0 or dg == 0: return [gcd], f, g f_norm = dup_max_norm(f, K) g_norm = dup_max_norm(g, K) B = K(2*min(f_norm, g_norm) + 29) x = max(min(B, 99*K.sqrt(B)), 2*min(f_norm // abs(dup_LC(f, K)), g_norm // abs(dup_LC(g, K))) + 2) for i in range(0, HEU_GCD_MAX): ff = dup_eval(f, x, K) gg = dup_eval(g, x, K) if ff and gg: h = K.gcd(ff, gg) cff = ff // h cfg = gg // h h = _dup_zz_gcd_interpolate(h, x, K) h = dup_primitive(h, K)[1] cff_, r = dup_div(f, h, K) if not r: cfg_, r = dup_div(g, h, K) if not r: h = dup_mul_ground(h, gcd, K) return h, cff_, cfg_ cff = _dup_zz_gcd_interpolate(cff, x, K) h, r = dup_div(f, cff, K) if not r: cfg_, r = dup_div(g, h, K) if not r: h = dup_mul_ground(h, gcd, K) return h, cff, cfg_ cfg = _dup_zz_gcd_interpolate(cfg, x, K) h, r = dup_div(g, cfg, K) if not r: cff_, r = dup_div(f, h, K) if not r: h = dup_mul_ground(h, gcd, K) return h, cff_, cfg x = 73794*x * K.sqrt(K.sqrt(x)) // 27011 raise HeuristicGCDFailed('no luck') def _dmp_zz_gcd_interpolate(h, x, v, K): """Interpolate polynomial GCD from integer GCD. """ f = [] while not dmp_zero_p(h, v): g = dmp_ground_trunc(h, x, v, K) f.insert(0, g) h = dmp_sub(h, g, v, K) h = dmp_quo_ground(h, x, v, K) if K.is_negative(dmp_ground_LC(f, v + 1, K)): return dmp_neg(f, v + 1, K) else: return f def dmp_zz_heu_gcd(f, g, u, K): """ Heuristic polynomial GCD in `Z[X]`. Given univariate polynomials `f` and `g` in `Z[X]`, returns their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` such that:: h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) The algorithm is purely heuristic which means it may fail to compute the GCD. This will be signaled by raising an exception. In this case you will need to switch to another GCD method. The algorithm computes the polynomial GCD by evaluating polynomials f and g at certain points and computing (fast) integer GCD of those evaluations. The polynomial GCD is recovered from the integer image by interpolation. The evaluation process reduces f and g variable by variable into a large integer. The final step is to verify if the interpolated polynomial is the correct GCD. This gives cofactors of the input polynomials as a side effect. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> f = x**2 + 2*x*y + y**2 >>> g = x**2 + x*y >>> R.dmp_zz_heu_gcd(f, g) (x + y, x + y, x) References ========== .. [1] [Liao95]_ """ if not u: return dup_zz_heu_gcd(f, g, K) result = _dmp_rr_trivial_gcd(f, g, u, K) if result is not None: return result gcd, f, g = dmp_ground_extract(f, g, u, K) f_norm = dmp_max_norm(f, u, K) g_norm = dmp_max_norm(g, u, K) B = K(2*min(f_norm, g_norm) + 29) x = max(min(B, 99*K.sqrt(B)), 2*min(f_norm // abs(dmp_ground_LC(f, u, K)), g_norm // abs(dmp_ground_LC(g, u, K))) + 2) for i in range(0, HEU_GCD_MAX): ff = dmp_eval(f, x, u, K) gg = dmp_eval(g, x, u, K) v = u - 1 if not (dmp_zero_p(ff, v) or dmp_zero_p(gg, v)): h, cff, cfg = dmp_zz_heu_gcd(ff, gg, v, K) h = _dmp_zz_gcd_interpolate(h, x, v, K) h = dmp_ground_primitive(h, u, K)[1] cff_, r = dmp_div(f, h, u, K) if dmp_zero_p(r, u): cfg_, r = dmp_div(g, h, u, K) if dmp_zero_p(r, u): h = dmp_mul_ground(h, gcd, u, K) return h, cff_, cfg_ cff = _dmp_zz_gcd_interpolate(cff, x, v, K) h, r = dmp_div(f, cff, u, K) if dmp_zero_p(r, u): cfg_, r = dmp_div(g, h, u, K) if dmp_zero_p(r, u): h = dmp_mul_ground(h, gcd, u, K) return h, cff, cfg_ cfg = _dmp_zz_gcd_interpolate(cfg, x, v, K) h, r = dmp_div(g, cfg, u, K) if dmp_zero_p(r, u): cff_, r = dmp_div(f, h, u, K) if dmp_zero_p(r, u): h = dmp_mul_ground(h, gcd, u, K) return h, cff_, cfg x = 73794*x * K.sqrt(K.sqrt(x)) // 27011 raise HeuristicGCDFailed('no luck') def dup_qq_heu_gcd(f, g, K0): """ Heuristic polynomial GCD in `Q[x]`. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2) >>> g = QQ(1,2)*x**2 + x >>> R.dup_qq_heu_gcd(f, g) (x + 2, 1/2*x + 3/4, 1/2*x) """ result = _dup_ff_trivial_gcd(f, g, K0) if result is not None: return result K1 = K0.get_ring() cf, f = dup_clear_denoms(f, K0, K1) cg, g = dup_clear_denoms(g, K0, K1) f = dup_convert(f, K0, K1) g = dup_convert(g, K0, K1) h, cff, cfg = dup_zz_heu_gcd(f, g, K1) h = dup_convert(h, K1, K0) c = dup_LC(h, K0) h = dup_monic(h, K0) cff = dup_convert(cff, K1, K0) cfg = dup_convert(cfg, K1, K0) cff = dup_mul_ground(cff, K0.quo(c, cf), K0) cfg = dup_mul_ground(cfg, K0.quo(c, cg), K0) return h, cff, cfg def dmp_qq_heu_gcd(f, g, u, K0): """ Heuristic polynomial GCD in `Q[X]`. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y, = ring("x,y", QQ) >>> f = QQ(1,4)*x**2 + x*y + y**2 >>> g = QQ(1,2)*x**2 + x*y >>> R.dmp_qq_heu_gcd(f, g) (x + 2*y, 1/4*x + 1/2*y, 1/2*x) """ result = _dmp_ff_trivial_gcd(f, g, u, K0) if result is not None: return result K1 = K0.get_ring() cf, f = dmp_clear_denoms(f, u, K0, K1) cg, g = dmp_clear_denoms(g, u, K0, K1) f = dmp_convert(f, u, K0, K1) g = dmp_convert(g, u, K0, K1) h, cff, cfg = dmp_zz_heu_gcd(f, g, u, K1) h = dmp_convert(h, u, K1, K0) c = dmp_ground_LC(h, u, K0) h = dmp_ground_monic(h, u, K0) cff = dmp_convert(cff, u, K1, K0) cfg = dmp_convert(cfg, u, K1, K0) cff = dmp_mul_ground(cff, K0.quo(c, cf), u, K0) cfg = dmp_mul_ground(cfg, K0.quo(c, cg), u, K0) return h, cff, cfg def dup_inner_gcd(f, g, K): """ Computes polynomial GCD and cofactors of `f` and `g` in `K[x]`. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_inner_gcd(x**2 - 1, x**2 - 3*x + 2) (x - 1, x + 1, x - 2) """ if not K.is_Exact: try: exact = K.get_exact() except DomainError: return [K.one], f, g f = dup_convert(f, K, exact) g = dup_convert(g, K, exact) h, cff, cfg = dup_inner_gcd(f, g, exact) h = dup_convert(h, exact, K) cff = dup_convert(cff, exact, K) cfg = dup_convert(cfg, exact, K) return h, cff, cfg elif K.is_Field: if K.is_QQ and query('USE_HEU_GCD'): try: return dup_qq_heu_gcd(f, g, K) except HeuristicGCDFailed: pass return dup_ff_prs_gcd(f, g, K) else: if K.is_ZZ and query('USE_HEU_GCD'): try: return dup_zz_heu_gcd(f, g, K) except HeuristicGCDFailed: pass return dup_rr_prs_gcd(f, g, K) def _dmp_inner_gcd(f, g, u, K): """Helper function for `dmp_inner_gcd()`. """ if not K.is_Exact: try: exact = K.get_exact() except DomainError: return dmp_one(u, K), f, g f = dmp_convert(f, u, K, exact) g = dmp_convert(g, u, K, exact) h, cff, cfg = _dmp_inner_gcd(f, g, u, exact) h = dmp_convert(h, u, exact, K) cff = dmp_convert(cff, u, exact, K) cfg = dmp_convert(cfg, u, exact, K) return h, cff, cfg elif K.is_Field: if K.is_QQ and query('USE_HEU_GCD'): try: return dmp_qq_heu_gcd(f, g, u, K) except HeuristicGCDFailed: pass return dmp_ff_prs_gcd(f, g, u, K) else: if K.is_ZZ and query('USE_HEU_GCD'): try: return dmp_zz_heu_gcd(f, g, u, K) except HeuristicGCDFailed: pass return dmp_rr_prs_gcd(f, g, u, K) def dmp_inner_gcd(f, g, u, K): """ Computes polynomial GCD and cofactors of `f` and `g` in `K[X]`. Returns ``(h, cff, cfg)`` such that ``a = gcd(f, g)``, ``cff = quo(f, h)``, and ``cfg = quo(g, h)``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> f = x**2 + 2*x*y + y**2 >>> g = x**2 + x*y >>> R.dmp_inner_gcd(f, g) (x + y, x + y, x) """ if not u: return dup_inner_gcd(f, g, K) J, (f, g) = dmp_multi_deflate((f, g), u, K) h, cff, cfg = _dmp_inner_gcd(f, g, u, K) return (dmp_inflate(h, J, u, K), dmp_inflate(cff, J, u, K), dmp_inflate(cfg, J, u, K)) def dup_gcd(f, g, K): """ Computes polynomial GCD of `f` and `g` in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_gcd(x**2 - 1, x**2 - 3*x + 2) x - 1 """ return dup_inner_gcd(f, g, K)[0] def dmp_gcd(f, g, u, K): """ Computes polynomial GCD of `f` and `g` in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> f = x**2 + 2*x*y + y**2 >>> g = x**2 + x*y >>> R.dmp_gcd(f, g) x + y """ return dmp_inner_gcd(f, g, u, K)[0] def dup_rr_lcm(f, g, K): """ Computes polynomial LCM over a ring in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_rr_lcm(x**2 - 1, x**2 - 3*x + 2) x**3 - 2*x**2 - x + 2 """ fc, f = dup_primitive(f, K) gc, g = dup_primitive(g, K) c = K.lcm(fc, gc) h = dup_quo(dup_mul(f, g, K), dup_gcd(f, g, K), K) return dup_mul_ground(h, c, K) def dup_ff_lcm(f, g, K): """ Computes polynomial LCM over a field in `K[x]`. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> f = QQ(1,2)*x**2 + QQ(7,4)*x + QQ(3,2) >>> g = QQ(1,2)*x**2 + x >>> R.dup_ff_lcm(f, g) x**3 + 7/2*x**2 + 3*x """ h = dup_quo(dup_mul(f, g, K), dup_gcd(f, g, K), K) return dup_monic(h, K) def dup_lcm(f, g, K): """ Computes polynomial LCM of `f` and `g` in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_lcm(x**2 - 1, x**2 - 3*x + 2) x**3 - 2*x**2 - x + 2 """ if K.is_Field: return dup_ff_lcm(f, g, K) else: return dup_rr_lcm(f, g, K) def dmp_rr_lcm(f, g, u, K): """ Computes polynomial LCM over a ring in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> f = x**2 + 2*x*y + y**2 >>> g = x**2 + x*y >>> R.dmp_rr_lcm(f, g) x**3 + 2*x**2*y + x*y**2 """ fc, f = dmp_ground_primitive(f, u, K) gc, g = dmp_ground_primitive(g, u, K) c = K.lcm(fc, gc) h = dmp_quo(dmp_mul(f, g, u, K), dmp_gcd(f, g, u, K), u, K) return dmp_mul_ground(h, c, u, K) def dmp_ff_lcm(f, g, u, K): """ Computes polynomial LCM over a field in `K[X]`. Examples ======== >>> from sympy.polys import ring, QQ >>> R, x,y, = ring("x,y", QQ) >>> f = QQ(1,4)*x**2 + x*y + y**2 >>> g = QQ(1,2)*x**2 + x*y >>> R.dmp_ff_lcm(f, g) x**3 + 4*x**2*y + 4*x*y**2 """ h = dmp_quo(dmp_mul(f, g, u, K), dmp_gcd(f, g, u, K), u, K) return dmp_ground_monic(h, u, K) def dmp_lcm(f, g, u, K): """ Computes polynomial LCM of `f` and `g` in `K[X]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> f = x**2 + 2*x*y + y**2 >>> g = x**2 + x*y >>> R.dmp_lcm(f, g) x**3 + 2*x**2*y + x*y**2 """ if not u: return dup_lcm(f, g, K) if K.is_Field: return dmp_ff_lcm(f, g, u, K) else: return dmp_rr_lcm(f, g, u, K) def dmp_content(f, u, K): """ Returns GCD of multivariate coefficients. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> R.dmp_content(2*x*y + 6*x + 4*y + 12) 2*y + 6 """ cont, v = dmp_LC(f, K), u - 1 if dmp_zero_p(f, u): return cont for c in f[1:]: cont = dmp_gcd(cont, c, v, K) if dmp_one_p(cont, v, K): break if K.is_negative(dmp_ground_LC(cont, v, K)): return dmp_neg(cont, v, K) else: return cont def dmp_primitive(f, u, K): """ Returns multivariate content and a primitive polynomial. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> R.dmp_primitive(2*x*y + 6*x + 4*y + 12) (2*y + 6, x + 2) """ cont, v = dmp_content(f, u, K), u - 1 if dmp_zero_p(f, u) or dmp_one_p(cont, v, K): return cont, f else: return cont, [ dmp_quo(c, cont, v, K) for c in f ] def dup_cancel(f, g, K, include=True): """ Cancel common factors in a rational function `f/g`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_cancel(2*x**2 - 2, x**2 - 2*x + 1) (2*x + 2, x - 1) """ return dmp_cancel(f, g, 0, K, include=include) def dmp_cancel(f, g, u, K, include=True): """ Cancel common factors in a rational function `f/g`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_cancel(2*x**2 - 2, x**2 - 2*x + 1) (2*x + 2, x - 1) """ K0 = None if K.is_Field and K.has_assoc_Ring: K0, K = K, K.get_ring() cq, f = dmp_clear_denoms(f, u, K0, K, convert=True) cp, g = dmp_clear_denoms(g, u, K0, K, convert=True) else: cp, cq = K.one, K.one _, p, q = dmp_inner_gcd(f, g, u, K) if K0 is not None: _, cp, cq = K.cofactors(cp, cq) p = dmp_convert(p, u, K, K0) q = dmp_convert(q, u, K, K0) K = K0 p_neg = K.is_negative(dmp_ground_LC(p, u, K)) q_neg = K.is_negative(dmp_ground_LC(q, u, K)) if p_neg and q_neg: p, q = dmp_neg(p, u, K), dmp_neg(q, u, K) elif p_neg: cp, p = -cp, dmp_neg(p, u, K) elif q_neg: cp, q = -cp, dmp_neg(q, u, K) if not include: return cp, cq, p, q p = dmp_mul_ground(p, cp, u, K) q = dmp_mul_ground(q, cq, u, K) return p, q sympy-sympy-1.9/sympy/polys/factortools.py000066400000000000000000001122241412543434000211650ustar00rootroot00000000000000"""Polynomial factorization routines in characteristic zero. """ from sympy.polys.galoistools import ( gf_from_int_poly, gf_to_int_poly, gf_lshift, gf_add_mul, gf_mul, gf_div, gf_rem, gf_gcdex, gf_sqf_p, gf_factor_sqf, gf_factor) from sympy.polys.densebasic import ( dup_LC, dmp_LC, dmp_ground_LC, dup_TC, dup_convert, dmp_convert, dup_degree, dmp_degree, dmp_degree_in, dmp_degree_list, dmp_from_dict, dmp_zero_p, dmp_one, dmp_nest, dmp_raise, dup_strip, dmp_ground, dup_inflate, dmp_exclude, dmp_include, dmp_inject, dmp_eject, dup_terms_gcd, dmp_terms_gcd) from sympy.polys.densearith import ( dup_neg, dmp_neg, dup_add, dmp_add, dup_sub, dmp_sub, dup_mul, dmp_mul, dup_sqr, dmp_pow, dup_div, dmp_div, dup_quo, dmp_quo, dmp_expand, dmp_add_mul, dup_sub_mul, dmp_sub_mul, dup_lshift, dup_max_norm, dmp_max_norm, dup_l1_norm, dup_mul_ground, dmp_mul_ground, dup_quo_ground, dmp_quo_ground) from sympy.polys.densetools import ( dup_clear_denoms, dmp_clear_denoms, dup_trunc, dmp_ground_trunc, dup_content, dup_monic, dmp_ground_monic, dup_primitive, dmp_ground_primitive, dmp_eval_tail, dmp_eval_in, dmp_diff_eval_in, dmp_compose, dup_shift, dup_mirror) from sympy.polys.euclidtools import ( dmp_primitive, dup_inner_gcd, dmp_inner_gcd) from sympy.polys.sqfreetools import ( dup_sqf_p, dup_sqf_norm, dmp_sqf_norm, dup_sqf_part, dmp_sqf_part) from sympy.polys.polyutils import _sort_factors from sympy.polys.polyconfig import query from sympy.polys.polyerrors import ( ExtraneousFactors, DomainError, CoercionFailed, EvaluationFailed) from sympy.ntheory import nextprime, isprime, factorint from sympy.utilities import subsets from math import ceil as _ceil, log as _log def dup_trial_division(f, factors, K): """ Determine multiplicities of factors for a univariate polynomial using trial division. """ result = [] for factor in factors: k = 0 while True: q, r = dup_div(f, factor, K) if not r: f, k = q, k + 1 else: break result.append((factor, k)) return _sort_factors(result) def dmp_trial_division(f, factors, u, K): """ Determine multiplicities of factors for a multivariate polynomial using trial division. """ result = [] for factor in factors: k = 0 while True: q, r = dmp_div(f, factor, u, K) if dmp_zero_p(r, u): f, k = q, k + 1 else: break result.append((factor, k)) return _sort_factors(result) def dup_zz_mignotte_bound(f, K): """ The Knuth-Cohen variant of Mignotte bound for univariate polynomials in `K[x]`. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = x**3 + 14*x**2 + 56*x + 64 >>> R.dup_zz_mignotte_bound(f) 152 By checking `factor(f)` we can see that max coeff is 8 Also consider a case that `f` is irreducible for example `f = 2*x**2 + 3*x + 4` To avoid a bug for these cases, we return the bound plus the max coefficient of `f` >>> f = 2*x**2 + 3*x + 4 >>> R.dup_zz_mignotte_bound(f) 6 Lastly,To see the difference between the new and the old Mignotte bound consider the irreducible polynomial:: >>> f = 87*x**7 + 4*x**6 + 80*x**5 + 17*x**4 + 9*x**3 + 12*x**2 + 49*x + 26 >>> R.dup_zz_mignotte_bound(f) 744 The new Mignotte bound is 744 whereas the old one (SymPy 1.5.1) is 1937664. References ========== ..[1] [Abbott2013]_ """ from sympy import binomial d = dup_degree(f) delta = _ceil(d / 2) delta2 = _ceil(delta / 2) # euclidean-norm eucl_norm = K.sqrt( sum( [cf**2 for cf in f] ) ) # biggest values of binomial coefficients (p. 538 of reference) t1 = binomial(delta - 1, delta2) t2 = binomial(delta - 1, delta2 - 1) lc = K.abs(dup_LC(f, K)) # leading coefficient bound = t1 * eucl_norm + t2 * lc # (p. 538 of reference) bound += dup_max_norm(f, K) # add max coeff for irreducible polys bound = _ceil(bound / 2) * 2 # round up to even integer return bound def dmp_zz_mignotte_bound(f, u, K): """Mignotte bound for multivariate polynomials in `K[X]`. """ a = dmp_max_norm(f, u, K) b = abs(dmp_ground_LC(f, u, K)) n = sum(dmp_degree_list(f, u)) return K.sqrt(K(n + 1))*2**n*a*b def dup_zz_hensel_step(m, f, g, h, s, t, K): """ One step in Hensel lifting in `Z[x]`. Given positive integer `m` and `Z[x]` polynomials `f`, `g`, `h`, `s` and `t` such that:: f = g*h (mod m) s*g + t*h = 1 (mod m) lc(f) is not a zero divisor (mod m) lc(h) = 1 deg(f) = deg(g) + deg(h) deg(s) < deg(h) deg(t) < deg(g) returns polynomials `G`, `H`, `S` and `T`, such that:: f = G*H (mod m**2) S*G + T*H = 1 (mod m**2) References ========== .. [1] [Gathen99]_ """ M = m**2 e = dup_sub_mul(f, g, h, K) e = dup_trunc(e, M, K) q, r = dup_div(dup_mul(s, e, K), h, K) q = dup_trunc(q, M, K) r = dup_trunc(r, M, K) u = dup_add(dup_mul(t, e, K), dup_mul(q, g, K), K) G = dup_trunc(dup_add(g, u, K), M, K) H = dup_trunc(dup_add(h, r, K), M, K) u = dup_add(dup_mul(s, G, K), dup_mul(t, H, K), K) b = dup_trunc(dup_sub(u, [K.one], K), M, K) c, d = dup_div(dup_mul(s, b, K), H, K) c = dup_trunc(c, M, K) d = dup_trunc(d, M, K) u = dup_add(dup_mul(t, b, K), dup_mul(c, G, K), K) S = dup_trunc(dup_sub(s, d, K), M, K) T = dup_trunc(dup_sub(t, u, K), M, K) return G, H, S, T def dup_zz_hensel_lift(p, f, f_list, l, K): """ Multifactor Hensel lifting in `Z[x]`. Given a prime `p`, polynomial `f` over `Z[x]` such that `lc(f)` is a unit modulo `p`, monic pair-wise coprime polynomials `f_i` over `Z[x]` satisfying:: f = lc(f) f_1 ... f_r (mod p) and a positive integer `l`, returns a list of monic polynomials `F_1`, `F_2`, ..., `F_r` satisfying:: f = lc(f) F_1 ... F_r (mod p**l) F_i = f_i (mod p), i = 1..r References ========== .. [1] [Gathen99]_ """ r = len(f_list) lc = dup_LC(f, K) if r == 1: F = dup_mul_ground(f, K.gcdex(lc, p**l)[0], K) return [ dup_trunc(F, p**l, K) ] m = p k = r // 2 d = int(_ceil(_log(l, 2))) g = gf_from_int_poly([lc], p) for f_i in f_list[:k]: g = gf_mul(g, gf_from_int_poly(f_i, p), p, K) h = gf_from_int_poly(f_list[k], p) for f_i in f_list[k + 1:]: h = gf_mul(h, gf_from_int_poly(f_i, p), p, K) s, t, _ = gf_gcdex(g, h, p, K) g = gf_to_int_poly(g, p) h = gf_to_int_poly(h, p) s = gf_to_int_poly(s, p) t = gf_to_int_poly(t, p) for _ in range(1, d + 1): (g, h, s, t), m = dup_zz_hensel_step(m, f, g, h, s, t, K), m**2 return dup_zz_hensel_lift(p, g, f_list[:k], l, K) \ + dup_zz_hensel_lift(p, h, f_list[k:], l, K) def _test_pl(fc, q, pl): if q > pl // 2: q = q - pl if not q: return True return fc % q == 0 def dup_zz_zassenhaus(f, K): """Factor primitive square-free polynomials in `Z[x]`. """ n = dup_degree(f) if n == 1: return [f] fc = f[-1] A = dup_max_norm(f, K) b = dup_LC(f, K) B = int(abs(K.sqrt(K(n + 1))*2**n*A*b)) C = int((n + 1)**(2*n)*A**(2*n - 1)) gamma = int(_ceil(2*_log(C, 2))) bound = int(2*gamma*_log(gamma)) a = [] # choose a prime number `p` such that `f` be square free in Z_p # if there are many factors in Z_p, choose among a few different `p` # the one with fewer factors for px in range(3, bound + 1): if not isprime(px) or b % px == 0: continue px = K.convert(px) F = gf_from_int_poly(f, px) if not gf_sqf_p(F, px, K): continue fsqfx = gf_factor_sqf(F, px, K)[1] a.append((px, fsqfx)) if len(fsqfx) < 15 or len(a) > 4: break p, fsqf = min(a, key=lambda x: len(x[1])) l = int(_ceil(_log(2*B + 1, p))) modular = [gf_to_int_poly(ff, p) for ff in fsqf] g = dup_zz_hensel_lift(p, f, modular, l, K) sorted_T = range(len(g)) T = set(sorted_T) factors, s = [], 1 pl = p**l while 2*s <= len(T): for S in subsets(sorted_T, s): # lift the constant coefficient of the product `G` of the factors # in the subset `S`; if it is does not divide `fc`, `G` does # not divide the input polynomial if b == 1: q = 1 for i in S: q = q*g[i][-1] q = q % pl if not _test_pl(fc, q, pl): continue else: G = [b] for i in S: G = dup_mul(G, g[i], K) G = dup_trunc(G, pl, K) G = dup_primitive(G, K)[1] q = G[-1] if q and fc % q != 0: continue H = [b] S = set(S) T_S = T - S if b == 1: G = [b] for i in S: G = dup_mul(G, g[i], K) G = dup_trunc(G, pl, K) for i in T_S: H = dup_mul(H, g[i], K) H = dup_trunc(H, pl, K) G_norm = dup_l1_norm(G, K) H_norm = dup_l1_norm(H, K) if G_norm*H_norm <= B: T = T_S sorted_T = [i for i in sorted_T if i not in S] G = dup_primitive(G, K)[1] f = dup_primitive(H, K)[1] factors.append(G) b = dup_LC(f, K) break else: s += 1 return factors + [f] def dup_zz_irreducible_p(f, K): """Test irreducibility using Eisenstein's criterion. """ lc = dup_LC(f, K) tc = dup_TC(f, K) e_fc = dup_content(f[1:], K) if e_fc: e_ff = factorint(int(e_fc)) for p in e_ff.keys(): if (lc % p) and (tc % p**2): return True def dup_cyclotomic_p(f, K, irreducible=False): """ Efficiently test if ``f`` is a cyclotomic polynomial. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 >>> R.dup_cyclotomic_p(f) False >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 >>> R.dup_cyclotomic_p(g) True """ if K.is_QQ: try: K0, K = K, K.get_ring() f = dup_convert(f, K0, K) except CoercionFailed: return False elif not K.is_ZZ: return False lc = dup_LC(f, K) tc = dup_TC(f, K) if lc != 1 or (tc != -1 and tc != 1): return False if not irreducible: coeff, factors = dup_factor_list(f, K) if coeff != K.one or factors != [(f, 1)]: return False n = dup_degree(f) g, h = [], [] for i in range(n, -1, -2): g.insert(0, f[i]) for i in range(n - 1, -1, -2): h.insert(0, f[i]) g = dup_sqr(dup_strip(g), K) h = dup_sqr(dup_strip(h), K) F = dup_sub(g, dup_lshift(h, 1, K), K) if K.is_negative(dup_LC(F, K)): F = dup_neg(F, K) if F == f: return True g = dup_mirror(f, K) if K.is_negative(dup_LC(g, K)): g = dup_neg(g, K) if F == g and dup_cyclotomic_p(g, K): return True G = dup_sqf_part(F, K) if dup_sqr(G, K) == F and dup_cyclotomic_p(G, K): return True return False def dup_zz_cyclotomic_poly(n, K): """Efficiently generate n-th cyclotomic polynomial. """ h = [K.one, -K.one] for p, k in factorint(n).items(): h = dup_quo(dup_inflate(h, p, K), h, K) h = dup_inflate(h, p**(k - 1), K) return h def _dup_cyclotomic_decompose(n, K): H = [[K.one, -K.one]] for p, k in factorint(n).items(): Q = [ dup_quo(dup_inflate(h, p, K), h, K) for h in H ] H.extend(Q) for i in range(1, k): Q = [ dup_inflate(q, p, K) for q in Q ] H.extend(Q) return H def dup_zz_cyclotomic_factor(f, K): """ Efficiently factor polynomials `x**n - 1` and `x**n + 1` in `Z[x]`. Given a univariate polynomial `f` in `Z[x]` returns a list of factors of `f`, provided that `f` is in the form `x**n - 1` or `x**n + 1` for `n >= 1`. Otherwise returns None. Factorization is performed using cyclotomic decomposition of `f`, which makes this method much faster that any other direct factorization approach (e.g. Zassenhaus's). References ========== .. [1] [Weisstein09]_ """ lc_f, tc_f = dup_LC(f, K), dup_TC(f, K) if dup_degree(f) <= 0: return None if lc_f != 1 or tc_f not in [-1, 1]: return None if any(bool(cf) for cf in f[1:-1]): return None n = dup_degree(f) F = _dup_cyclotomic_decompose(n, K) if not K.is_one(tc_f): return F else: H = [] for h in _dup_cyclotomic_decompose(2*n, K): if h not in F: H.append(h) return H def dup_zz_factor_sqf(f, K): """Factor square-free (non-primitive) polynomials in `Z[x]`. """ cont, g = dup_primitive(f, K) n = dup_degree(g) if dup_LC(g, K) < 0: cont, g = -cont, dup_neg(g, K) if n <= 0: return cont, [] elif n == 1: return cont, [g] if query('USE_IRREDUCIBLE_IN_FACTOR'): if dup_zz_irreducible_p(g, K): return cont, [g] factors = None if query('USE_CYCLOTOMIC_FACTOR'): factors = dup_zz_cyclotomic_factor(g, K) if factors is None: factors = dup_zz_zassenhaus(g, K) return cont, _sort_factors(factors, multiple=False) def dup_zz_factor(f, K): """ Factor (non square-free) polynomials in `Z[x]`. Given a univariate polynomial `f` in `Z[x]` computes its complete factorization `f_1, ..., f_n` into irreducibles over integers:: f = content(f) f_1**k_1 ... f_n**k_n The factorization is computed by reducing the input polynomial into a primitive square-free polynomial and factoring it using Zassenhaus algorithm. Trial division is used to recover the multiplicities of factors. The result is returned as a tuple consisting of:: (content(f), [(f_1, k_1), ..., (f_n, k_n)) Examples ======== Consider the polynomial `f = 2*x**4 - 2`:: >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_zz_factor(2*x**4 - 2) (2, [(x - 1, 1), (x + 1, 1), (x**2 + 1, 1)]) In result we got the following factorization:: f = 2 (x - 1) (x + 1) (x**2 + 1) Note that this is a complete factorization over integers, however over Gaussian integers we can factor the last term. By default, polynomials `x**n - 1` and `x**n + 1` are factored using cyclotomic decomposition to speedup computations. To disable this behaviour set cyclotomic=False. References ========== .. [1] [Gathen99]_ """ cont, g = dup_primitive(f, K) n = dup_degree(g) if dup_LC(g, K) < 0: cont, g = -cont, dup_neg(g, K) if n <= 0: return cont, [] elif n == 1: return cont, [(g, 1)] if query('USE_IRREDUCIBLE_IN_FACTOR'): if dup_zz_irreducible_p(g, K): return cont, [(g, 1)] g = dup_sqf_part(g, K) H = None if query('USE_CYCLOTOMIC_FACTOR'): H = dup_zz_cyclotomic_factor(g, K) if H is None: H = dup_zz_zassenhaus(g, K) factors = dup_trial_division(f, H, K) return cont, factors def dmp_zz_wang_non_divisors(E, cs, ct, K): """Wang/EEZ: Compute a set of valid divisors. """ result = [ cs*ct ] for q in E: q = abs(q) for r in reversed(result): while r != 1: r = K.gcd(r, q) q = q // r if K.is_one(q): return None result.append(q) return result[1:] def dmp_zz_wang_test_points(f, T, ct, A, u, K): """Wang/EEZ: Test evaluation points for suitability. """ if not dmp_eval_tail(dmp_LC(f, K), A, u - 1, K): raise EvaluationFailed('no luck') g = dmp_eval_tail(f, A, u, K) if not dup_sqf_p(g, K): raise EvaluationFailed('no luck') c, h = dup_primitive(g, K) if K.is_negative(dup_LC(h, K)): c, h = -c, dup_neg(h, K) v = u - 1 E = [ dmp_eval_tail(t, A, v, K) for t, _ in T ] D = dmp_zz_wang_non_divisors(E, c, ct, K) if D is not None: return c, h, E else: raise EvaluationFailed('no luck') def dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K): """Wang/EEZ: Compute correct leading coefficients. """ C, J, v = [], [0]*len(E), u - 1 for h in H: c = dmp_one(v, K) d = dup_LC(h, K)*cs for i in reversed(range(len(E))): k, e, (t, _) = 0, E[i], T[i] while not (d % e): d, k = d//e, k + 1 if k != 0: c, J[i] = dmp_mul(c, dmp_pow(t, k, v, K), v, K), 1 C.append(c) if any(not j for j in J): raise ExtraneousFactors # pragma: no cover CC, HH = [], [] for c, h in zip(C, H): d = dmp_eval_tail(c, A, v, K) lc = dup_LC(h, K) if K.is_one(cs): cc = lc//d else: g = K.gcd(lc, d) d, cc = d//g, lc//g h, cs = dup_mul_ground(h, d, K), cs//d c = dmp_mul_ground(c, cc, v, K) CC.append(c) HH.append(h) if K.is_one(cs): return f, HH, CC CCC, HHH = [], [] for c, h in zip(CC, HH): CCC.append(dmp_mul_ground(c, cs, v, K)) HHH.append(dmp_mul_ground(h, cs, 0, K)) f = dmp_mul_ground(f, cs**(len(H) - 1), u, K) return f, HHH, CCC def dup_zz_diophantine(F, m, p, K): """Wang/EEZ: Solve univariate Diophantine equations. """ if len(F) == 2: a, b = F f = gf_from_int_poly(a, p) g = gf_from_int_poly(b, p) s, t, G = gf_gcdex(g, f, p, K) s = gf_lshift(s, m, K) t = gf_lshift(t, m, K) q, s = gf_div(s, f, p, K) t = gf_add_mul(t, q, g, p, K) s = gf_to_int_poly(s, p) t = gf_to_int_poly(t, p) result = [s, t] else: G = [F[-1]] for f in reversed(F[1:-1]): G.insert(0, dup_mul(f, G[0], K)) S, T = [], [[1]] for f, g in zip(F, G): t, s = dmp_zz_diophantine([g, f], T[-1], [], 0, p, 1, K) T.append(t) S.append(s) result, S = [], S + [T[-1]] for s, f in zip(S, F): s = gf_from_int_poly(s, p) f = gf_from_int_poly(f, p) r = gf_rem(gf_lshift(s, m, K), f, p, K) s = gf_to_int_poly(r, p) result.append(s) return result def dmp_zz_diophantine(F, c, A, d, p, u, K): """Wang/EEZ: Solve multivariate Diophantine equations. """ if not A: S = [ [] for _ in F ] n = dup_degree(c) for i, coeff in enumerate(c): if not coeff: continue T = dup_zz_diophantine(F, n - i, p, K) for j, (s, t) in enumerate(zip(S, T)): t = dup_mul_ground(t, coeff, K) S[j] = dup_trunc(dup_add(s, t, K), p, K) else: n = len(A) e = dmp_expand(F, u, K) a, A = A[-1], A[:-1] B, G = [], [] for f in F: B.append(dmp_quo(e, f, u, K)) G.append(dmp_eval_in(f, a, n, u, K)) C = dmp_eval_in(c, a, n, u, K) v = u - 1 S = dmp_zz_diophantine(G, C, A, d, p, v, K) S = [ dmp_raise(s, 1, v, K) for s in S ] for s, b in zip(S, B): c = dmp_sub_mul(c, s, b, u, K) c = dmp_ground_trunc(c, p, u, K) m = dmp_nest([K.one, -a], n, K) M = dmp_one(n, K) for k in K.map(range(0, d)): if dmp_zero_p(c, u): break M = dmp_mul(M, m, u, K) C = dmp_diff_eval_in(c, k + 1, a, n, u, K) if not dmp_zero_p(C, v): C = dmp_quo_ground(C, K.factorial(k + 1), v, K) T = dmp_zz_diophantine(G, C, A, d, p, v, K) for i, t in enumerate(T): T[i] = dmp_mul(dmp_raise(t, 1, v, K), M, u, K) for i, (s, t) in enumerate(zip(S, T)): S[i] = dmp_add(s, t, u, K) for t, b in zip(T, B): c = dmp_sub_mul(c, t, b, u, K) c = dmp_ground_trunc(c, p, u, K) S = [ dmp_ground_trunc(s, p, u, K) for s in S ] return S def dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K): """Wang/EEZ: Parallel Hensel lifting algorithm. """ S, n, v = [f], len(A), u - 1 H = list(H) for i, a in enumerate(reversed(A[1:])): s = dmp_eval_in(S[0], a, n - i, u - i, K) S.insert(0, dmp_ground_trunc(s, p, v - i, K)) d = max(dmp_degree_list(f, u)[1:]) for j, s, a in zip(range(2, n + 2), S, A): G, w = list(H), j - 1 I, J = A[:j - 2], A[j - 1:] for i, (h, lc) in enumerate(zip(H, LC)): lc = dmp_ground_trunc(dmp_eval_tail(lc, J, v, K), p, w - 1, K) H[i] = [lc] + dmp_raise(h[1:], 1, w - 1, K) m = dmp_nest([K.one, -a], w, K) M = dmp_one(w, K) c = dmp_sub(s, dmp_expand(H, w, K), w, K) dj = dmp_degree_in(s, w, w) for k in K.map(range(0, dj)): if dmp_zero_p(c, w): break M = dmp_mul(M, m, w, K) C = dmp_diff_eval_in(c, k + 1, a, w, w, K) if not dmp_zero_p(C, w - 1): C = dmp_quo_ground(C, K.factorial(k + 1), w - 1, K) T = dmp_zz_diophantine(G, C, I, d, p, w - 1, K) for i, (h, t) in enumerate(zip(H, T)): h = dmp_add_mul(h, dmp_raise(t, 1, w - 1, K), M, w, K) H[i] = dmp_ground_trunc(h, p, w, K) h = dmp_sub(s, dmp_expand(H, w, K), w, K) c = dmp_ground_trunc(h, p, w, K) if dmp_expand(H, u, K) != f: raise ExtraneousFactors # pragma: no cover else: return H def dmp_zz_wang(f, u, K, mod=None, seed=None): """ Factor primitive square-free polynomials in `Z[X]`. Given a multivariate polynomial `f` in `Z[x_1,...,x_n]`, which is primitive and square-free in `x_1`, computes factorization of `f` into irreducibles over integers. The procedure is based on Wang's Enhanced Extended Zassenhaus algorithm. The algorithm works by viewing `f` as a univariate polynomial in `Z[x_2,...,x_n][x_1]`, for which an evaluation mapping is computed:: x_2 -> a_2, ..., x_n -> a_n where `a_i`, for `i = 2, ..., n`, are carefully chosen integers. The mapping is used to transform `f` into a univariate polynomial in `Z[x_1]`, which can be factored efficiently using Zassenhaus algorithm. The last step is to lift univariate factors to obtain true multivariate factors. For this purpose a parallel Hensel lifting procedure is used. The parameter ``seed`` is passed to _randint and can be used to seed randint (when an integer) or (for testing purposes) can be a sequence of numbers. References ========== .. [1] [Wang78]_ .. [2] [Geddes92]_ """ from sympy.testing.randtest import _randint randint = _randint(seed) ct, T = dmp_zz_factor(dmp_LC(f, K), u - 1, K) b = dmp_zz_mignotte_bound(f, u, K) p = K(nextprime(b)) if mod is None: if u == 1: mod = 2 else: mod = 1 history, configs, A, r = set(), [], [K.zero]*u, None try: cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) _, H = dup_zz_factor_sqf(s, K) r = len(H) if r == 1: return [f] configs = [(s, cs, E, H, A)] except EvaluationFailed: pass eez_num_configs = query('EEZ_NUMBER_OF_CONFIGS') eez_num_tries = query('EEZ_NUMBER_OF_TRIES') eez_mod_step = query('EEZ_MODULUS_STEP') while len(configs) < eez_num_configs: for _ in range(eez_num_tries): A = [ K(randint(-mod, mod)) for _ in range(u) ] if tuple(A) not in history: history.add(tuple(A)) else: continue try: cs, s, E = dmp_zz_wang_test_points(f, T, ct, A, u, K) except EvaluationFailed: continue _, H = dup_zz_factor_sqf(s, K) rr = len(H) if r is not None: if rr != r: # pragma: no cover if rr < r: configs, r = [], rr else: continue else: r = rr if r == 1: return [f] configs.append((s, cs, E, H, A)) if len(configs) == eez_num_configs: break else: mod += eez_mod_step s_norm, s_arg, i = None, 0, 0 for s, _, _, _, _ in configs: _s_norm = dup_max_norm(s, K) if s_norm is not None: if _s_norm < s_norm: s_norm = _s_norm s_arg = i else: s_norm = _s_norm i += 1 _, cs, E, H, A = configs[s_arg] orig_f = f try: f, H, LC = dmp_zz_wang_lead_coeffs(f, T, cs, E, H, A, u, K) factors = dmp_zz_wang_hensel_lifting(f, H, LC, A, p, u, K) except ExtraneousFactors: # pragma: no cover if query('EEZ_RESTART_IF_NEEDED'): return dmp_zz_wang(orig_f, u, K, mod + 1) else: raise ExtraneousFactors( "we need to restart algorithm with better parameters") result = [] for f in factors: _, f = dmp_ground_primitive(f, u, K) if K.is_negative(dmp_ground_LC(f, u, K)): f = dmp_neg(f, u, K) result.append(f) return result def dmp_zz_factor(f, u, K): """ Factor (non square-free) polynomials in `Z[X]`. Given a multivariate polynomial `f` in `Z[x]` computes its complete factorization `f_1, ..., f_n` into irreducibles over integers:: f = content(f) f_1**k_1 ... f_n**k_n The factorization is computed by reducing the input polynomial into a primitive square-free polynomial and factoring it using Enhanced Extended Zassenhaus (EEZ) algorithm. Trial division is used to recover the multiplicities of factors. The result is returned as a tuple consisting of:: (content(f), [(f_1, k_1), ..., (f_n, k_n)) Consider polynomial `f = 2*(x**2 - y**2)`:: >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_zz_factor(2*x**2 - 2*y**2) (2, [(x - y, 1), (x + y, 1)]) In result we got the following factorization:: f = 2 (x - y) (x + y) References ========== .. [1] [Gathen99]_ """ if not u: return dup_zz_factor(f, K) if dmp_zero_p(f, u): return K.zero, [] cont, g = dmp_ground_primitive(f, u, K) if dmp_ground_LC(g, u, K) < 0: cont, g = -cont, dmp_neg(g, u, K) if all(d <= 0 for d in dmp_degree_list(g, u)): return cont, [] G, g = dmp_primitive(g, u, K) factors = [] if dmp_degree(g, u) > 0: g = dmp_sqf_part(g, u, K) H = dmp_zz_wang(g, u, K) factors = dmp_trial_division(f, H, u, K) for g, k in dmp_zz_factor(G, u - 1, K)[1]: factors.insert(0, ([g], k)) return cont, _sort_factors(factors) def dup_qq_i_factor(f, K0): """Factor univariate polynomials into irreducibles in `QQ_I[x]`. """ # Factor in QQ K1 = K0.as_AlgebraicField() f = dup_convert(f, K0, K1) coeff, factors = dup_factor_list(f, K1) factors = [(dup_convert(fac, K1, K0), i) for fac, i in factors] coeff = K0.convert(coeff, K1) return coeff, factors def dup_zz_i_factor(f, K0): """Factor univariate polynomials into irreducibles in `ZZ_I[x]`. """ # First factor in QQ_I K1 = K0.get_field() f = dup_convert(f, K0, K1) coeff, factors = dup_qq_i_factor(f, K1) new_factors = [] for fac, i in factors: # Extract content fac_denom, fac_num = dup_clear_denoms(fac, K1) fac_num_ZZ_I = dup_convert(fac_num, K1, K0) content, fac_prim = dmp_ground_primitive(fac_num_ZZ_I, 0, K1) coeff = (coeff * content ** i) // fac_denom ** i new_factors.append((fac_prim, i)) factors = new_factors coeff = K0.convert(coeff, K1) return coeff, factors def dmp_qq_i_factor(f, u, K0): """Factor multivariate polynomials into irreducibles in `QQ_I[X]`. """ # Factor in QQ K1 = K0.as_AlgebraicField() f = dmp_convert(f, u, K0, K1) coeff, factors = dmp_factor_list(f, u, K1) factors = [(dmp_convert(fac, u, K1, K0), i) for fac, i in factors] coeff = K0.convert(coeff, K1) return coeff, factors def dmp_zz_i_factor(f, u, K0): """Factor multivariate polynomials into irreducibles in `ZZ_I[X]`. """ # First factor in QQ_I K1 = K0.get_field() f = dmp_convert(f, u, K0, K1) coeff, factors = dmp_qq_i_factor(f, u, K1) new_factors = [] for fac, i in factors: # Extract content fac_denom, fac_num = dmp_clear_denoms(fac, u, K1) fac_num_ZZ_I = dmp_convert(fac_num, u, K1, K0) content, fac_prim = dmp_ground_primitive(fac_num_ZZ_I, u, K1) coeff = (coeff * content ** i) // fac_denom ** i new_factors.append((fac_prim, i)) factors = new_factors coeff = K0.convert(coeff, K1) return coeff, factors def dup_ext_factor(f, K): """Factor univariate polynomials over algebraic number fields. """ n, lc = dup_degree(f), dup_LC(f, K) f = dup_monic(f, K) if n <= 0: return lc, [] if n == 1: return lc, [(f, 1)] f, F = dup_sqf_part(f, K), f s, g, r = dup_sqf_norm(f, K) factors = dup_factor_list_include(r, K.dom) if len(factors) == 1: return lc, [(f, n//dup_degree(f))] H = s*K.unit for i, (factor, _) in enumerate(factors): h = dup_convert(factor, K.dom, K) h, _, g = dup_inner_gcd(h, g, K) h = dup_shift(h, H, K) factors[i] = h factors = dup_trial_division(F, factors, K) return lc, factors def dmp_ext_factor(f, u, K): """Factor multivariate polynomials over algebraic number fields. """ if not u: return dup_ext_factor(f, K) lc = dmp_ground_LC(f, u, K) f = dmp_ground_monic(f, u, K) if all(d <= 0 for d in dmp_degree_list(f, u)): return lc, [] f, F = dmp_sqf_part(f, u, K), f s, g, r = dmp_sqf_norm(f, u, K) factors = dmp_factor_list_include(r, u, K.dom) if len(factors) == 1: factors = [f] else: H = dmp_raise([K.one, s*K.unit], u, 0, K) for i, (factor, _) in enumerate(factors): h = dmp_convert(factor, u, K.dom, K) h, _, g = dmp_inner_gcd(h, g, u, K) h = dmp_compose(h, H, u, K) factors[i] = h return lc, dmp_trial_division(F, factors, u, K) def dup_gf_factor(f, K): """Factor univariate polynomials over finite fields. """ f = dup_convert(f, K, K.dom) coeff, factors = gf_factor(f, K.mod, K.dom) for i, (f, k) in enumerate(factors): factors[i] = (dup_convert(f, K.dom, K), k) return K.convert(coeff, K.dom), factors def dmp_gf_factor(f, u, K): """Factor multivariate polynomials over finite fields. """ raise NotImplementedError('multivariate polynomials over finite fields') def dup_factor_list(f, K0): """Factor univariate polynomials into irreducibles in `K[x]`. """ j, f = dup_terms_gcd(f, K0) cont, f = dup_primitive(f, K0) if K0.is_FiniteField: coeff, factors = dup_gf_factor(f, K0) elif K0.is_Algebraic: coeff, factors = dup_ext_factor(f, K0) elif K0.is_GaussianRing: coeff, factors = dup_zz_i_factor(f, K0) elif K0.is_GaussianField: coeff, factors = dup_qq_i_factor(f, K0) else: if not K0.is_Exact: K0_inexact, K0 = K0, K0.get_exact() f = dup_convert(f, K0_inexact, K0) else: K0_inexact = None if K0.is_Field: K = K0.get_ring() denom, f = dup_clear_denoms(f, K0, K) f = dup_convert(f, K0, K) else: K = K0 if K.is_ZZ: coeff, factors = dup_zz_factor(f, K) elif K.is_Poly: f, u = dmp_inject(f, 0, K) coeff, factors = dmp_factor_list(f, u, K.dom) for i, (f, k) in enumerate(factors): factors[i] = (dmp_eject(f, u, K), k) coeff = K.convert(coeff, K.dom) else: # pragma: no cover raise DomainError('factorization not supported over %s' % K0) if K0.is_Field: for i, (f, k) in enumerate(factors): factors[i] = (dup_convert(f, K, K0), k) coeff = K0.convert(coeff, K) coeff = K0.quo(coeff, denom) if K0_inexact: for i, (f, k) in enumerate(factors): max_norm = dup_max_norm(f, K0) f = dup_quo_ground(f, max_norm, K0) f = dup_convert(f, K0, K0_inexact) factors[i] = (f, k) coeff = K0.mul(coeff, K0.pow(max_norm, k)) coeff = K0_inexact.convert(coeff, K0) K0 = K0_inexact if j: factors.insert(0, ([K0.one, K0.zero], j)) return coeff*cont, _sort_factors(factors) def dup_factor_list_include(f, K): """Factor univariate polynomials into irreducibles in `K[x]`. """ coeff, factors = dup_factor_list(f, K) if not factors: return [(dup_strip([coeff]), 1)] else: g = dup_mul_ground(factors[0][0], coeff, K) return [(g, factors[0][1])] + factors[1:] def dmp_factor_list(f, u, K0): """Factor multivariate polynomials into irreducibles in `K[X]`. """ if not u: return dup_factor_list(f, K0) J, f = dmp_terms_gcd(f, u, K0) cont, f = dmp_ground_primitive(f, u, K0) if K0.is_FiniteField: # pragma: no cover coeff, factors = dmp_gf_factor(f, u, K0) elif K0.is_Algebraic: coeff, factors = dmp_ext_factor(f, u, K0) elif K0.is_GaussianRing: coeff, factors = dmp_zz_i_factor(f, u, K0) elif K0.is_GaussianField: coeff, factors = dmp_qq_i_factor(f, u, K0) else: if not K0.is_Exact: K0_inexact, K0 = K0, K0.get_exact() f = dmp_convert(f, u, K0_inexact, K0) else: K0_inexact = None if K0.is_Field: K = K0.get_ring() denom, f = dmp_clear_denoms(f, u, K0, K) f = dmp_convert(f, u, K0, K) else: K = K0 if K.is_ZZ: levels, f, v = dmp_exclude(f, u, K) coeff, factors = dmp_zz_factor(f, v, K) for i, (f, k) in enumerate(factors): factors[i] = (dmp_include(f, levels, v, K), k) elif K.is_Poly: f, v = dmp_inject(f, u, K) coeff, factors = dmp_factor_list(f, v, K.dom) for i, (f, k) in enumerate(factors): factors[i] = (dmp_eject(f, v, K), k) coeff = K.convert(coeff, K.dom) else: # pragma: no cover raise DomainError('factorization not supported over %s' % K0) if K0.is_Field: for i, (f, k) in enumerate(factors): factors[i] = (dmp_convert(f, u, K, K0), k) coeff = K0.convert(coeff, K) coeff = K0.quo(coeff, denom) if K0_inexact: for i, (f, k) in enumerate(factors): max_norm = dmp_max_norm(f, u, K0) f = dmp_quo_ground(f, max_norm, u, K0) f = dmp_convert(f, u, K0, K0_inexact) factors[i] = (f, k) coeff = K0.mul(coeff, K0.pow(max_norm, k)) coeff = K0_inexact.convert(coeff, K0) K0 = K0_inexact for i, j in enumerate(reversed(J)): if not j: continue term = {(0,)*(u - i) + (1,) + (0,)*i: K0.one} factors.insert(0, (dmp_from_dict(term, u, K0), j)) return coeff*cont, _sort_factors(factors) def dmp_factor_list_include(f, u, K): """Factor multivariate polynomials into irreducibles in `K[X]`. """ if not u: return dup_factor_list_include(f, K) coeff, factors = dmp_factor_list(f, u, K) if not factors: return [(dmp_ground(coeff, u), 1)] else: g = dmp_mul_ground(factors[0][0], coeff, u, K) return [(g, factors[0][1])] + factors[1:] def dup_irreducible_p(f, K): """ Returns ``True`` if a univariate polynomial ``f`` has no factors over its domain. """ return dmp_irreducible_p(f, 0, K) def dmp_irreducible_p(f, u, K): """ Returns ``True`` if a multivariate polynomial ``f`` has no factors over its domain. """ _, factors = dmp_factor_list(f, u, K) if not factors: return True elif len(factors) > 1: return False else: _, k = factors[0] return k == 1 sympy-sympy-1.9/sympy/polys/fglmtools.py000066400000000000000000000103501412543434000206310ustar00rootroot00000000000000"""Implementation of matrix FGLM Groebner basis conversion algorithm. """ from sympy.polys.monomials import monomial_mul, monomial_div def matrix_fglm(F, ring, O_to): """ Converts the reduced Groebner basis ``F`` of a zero-dimensional ideal w.r.t. ``O_from`` to a reduced Groebner basis w.r.t. ``O_to``. References ========== .. [1] J.C. Faugere, P. Gianni, D. Lazard, T. Mora (1994). Efficient Computation of Zero-dimensional Groebner Bases by Change of Ordering """ domain = ring.domain ngens = ring.ngens ring_to = ring.clone(order=O_to) old_basis = _basis(F, ring) M = _representing_matrices(old_basis, F, ring) # V contains the normalforms (wrt O_from) of S S = [ring.zero_monom] V = [[domain.one] + [domain.zero] * (len(old_basis) - 1)] G = [] L = [(i, 0) for i in range(ngens)] # (i, j) corresponds to x_i * S[j] L.sort(key=lambda k_l: O_to(_incr_k(S[k_l[1]], k_l[0])), reverse=True) t = L.pop() P = _identity_matrix(len(old_basis), domain) while True: s = len(S) v = _matrix_mul(M[t[0]], V[t[1]]) _lambda = _matrix_mul(P, v) if all(_lambda[i] == domain.zero for i in range(s, len(old_basis))): # there is a linear combination of v by V lt = ring.term_new(_incr_k(S[t[1]], t[0]), domain.one) rest = ring.from_dict({S[i]: _lambda[i] for i in range(s)}) g = (lt - rest).set_ring(ring_to) if g: G.append(g) else: # v is linearly independent from V P = _update(s, _lambda, P) S.append(_incr_k(S[t[1]], t[0])) V.append(v) L.extend([(i, s) for i in range(ngens)]) L = list(set(L)) L.sort(key=lambda k_l: O_to(_incr_k(S[k_l[1]], k_l[0])), reverse=True) L = [(k, l) for (k, l) in L if all(monomial_div(_incr_k(S[l], k), g.LM) is None for g in G)] if not L: G = [ g.monic() for g in G ] return sorted(G, key=lambda g: O_to(g.LM), reverse=True) t = L.pop() def _incr_k(m, k): return tuple(list(m[:k]) + [m[k] + 1] + list(m[k + 1:])) def _identity_matrix(n, domain): M = [[domain.zero]*n for _ in range(n)] for i in range(n): M[i][i] = domain.one return M def _matrix_mul(M, v): return [sum([row[i] * v[i] for i in range(len(v))]) for row in M] def _update(s, _lambda, P): """ Update ``P`` such that for the updated `P'` `P' v = e_{s}`. """ k = min([j for j in range(s, len(_lambda)) if _lambda[j] != 0]) for r in range(len(_lambda)): if r != k: P[r] = [P[r][j] - (P[k][j] * _lambda[r]) / _lambda[k] for j in range(len(P[r]))] P[k] = [P[k][j] / _lambda[k] for j in range(len(P[k]))] P[k], P[s] = P[s], P[k] return P def _representing_matrices(basis, G, ring): r""" Compute the matrices corresponding to the linear maps `m \mapsto x_i m` for all variables `x_i`. """ domain = ring.domain u = ring.ngens-1 def var(i): return tuple([0] * i + [1] + [0] * (u - i)) def representing_matrix(m): M = [[domain.zero] * len(basis) for _ in range(len(basis))] for i, v in enumerate(basis): r = ring.term_new(monomial_mul(m, v), domain.one).rem(G) for monom, coeff in r.terms(): j = basis.index(monom) M[j][i] = coeff return M return [representing_matrix(var(i)) for i in range(u + 1)] def _basis(G, ring): r""" Computes a list of monomials which are not divisible by the leading monomials wrt to ``O`` of ``G``. These monomials are a basis of `K[X_1, \ldots, X_n]/(G)`. """ order = ring.order leading_monomials = [g.LM for g in G] candidates = [ring.zero_monom] basis = [] while candidates: t = candidates.pop() basis.append(t) new_candidates = [_incr_k(t, k) for k in range(ring.ngens) if all(monomial_div(_incr_k(t, k), lmg) is None for lmg in leading_monomials)] candidates.extend(new_candidates) candidates.sort(key=lambda m: order(m), reverse=True) basis = list(set(basis)) return sorted(basis, key=lambda m: order(m)) sympy-sympy-1.9/sympy/polys/fields.py000066400000000000000000000513251412543434000201000ustar00rootroot00000000000000"""Sparse rational function fields. """ from typing import Any, Dict from functools import reduce from operator import add, mul, lt, le, gt, ge from sympy.core.compatibility import is_sequence from sympy.core.expr import Expr from sympy.core.mod import Mod from sympy.core.numbers import Exp1 from sympy.core.singleton import S from sympy.core.symbol import Symbol from sympy.core.sympify import CantSympify, sympify from sympy.functions.elementary.exponential import ExpBase from sympy.polys.domains.domainelement import DomainElement from sympy.polys.domains.fractionfield import FractionField from sympy.polys.domains.polynomialring import PolynomialRing from sympy.polys.constructor import construct_domain from sympy.polys.orderings import lex from sympy.polys.polyerrors import CoercionFailed from sympy.polys.polyoptions import build_options from sympy.polys.polyutils import _parallel_dict_from_expr from sympy.polys.rings import PolyElement from sympy.printing.defaults import DefaultPrinting from sympy.utilities import public from sympy.utilities.magic import pollute @public def field(symbols, domain, order=lex): """Construct new rational function field returning (field, x1, ..., xn). """ _field = FracField(symbols, domain, order) return (_field,) + _field.gens @public def xfield(symbols, domain, order=lex): """Construct new rational function field returning (field, (x1, ..., xn)). """ _field = FracField(symbols, domain, order) return (_field, _field.gens) @public def vfield(symbols, domain, order=lex): """Construct new rational function field and inject generators into global namespace. """ _field = FracField(symbols, domain, order) pollute([ sym.name for sym in _field.symbols ], _field.gens) return _field @public def sfield(exprs, *symbols, **options): """Construct a field deriving generators and domain from options and input expressions. Parameters ========== exprs : py:class:`~.Expr` or sequence of :py:class:`~.Expr` (sympifiable) symbols : sequence of :py:class:`~.Symbol`/:py:class:`~.Expr` options : keyword arguments understood by :py:class:`~.Options` Examples ======== >>> from sympy.core import symbols >>> from sympy.functions import exp, log >>> from sympy.polys.fields import sfield >>> x = symbols("x") >>> K, f = sfield((x*log(x) + 4*x**2)*exp(1/x + log(x)/3)/x**2) >>> K Rational function field in x, exp(1/x), log(x), x**(1/3) over ZZ with lex order >>> f (4*x**2*(exp(1/x)) + x*(exp(1/x))*(log(x)))/((x**(1/3))**5) """ single = False if not is_sequence(exprs): exprs, single = [exprs], True exprs = list(map(sympify, exprs)) opt = build_options(symbols, options) numdens = [] for expr in exprs: numdens.extend(expr.as_numer_denom()) reps, opt = _parallel_dict_from_expr(numdens, opt) if opt.domain is None: # NOTE: this is inefficient because construct_domain() automatically # performs conversion to the target domain. It shouldn't do this. coeffs = sum([list(rep.values()) for rep in reps], []) opt.domain, _ = construct_domain(coeffs, opt=opt) _field = FracField(opt.gens, opt.domain, opt.order) fracs = [] for i in range(0, len(reps), 2): fracs.append(_field(tuple(reps[i:i+2]))) if single: return (_field, fracs[0]) else: return (_field, fracs) _field_cache = {} # type: Dict[Any, Any] class FracField(DefaultPrinting): """Multivariate distributed rational function field. """ def __new__(cls, symbols, domain, order=lex): from sympy.polys.rings import PolyRing ring = PolyRing(symbols, domain, order) symbols = ring.symbols ngens = ring.ngens domain = ring.domain order = ring.order _hash_tuple = (cls.__name__, symbols, ngens, domain, order) obj = _field_cache.get(_hash_tuple) if obj is None: obj = object.__new__(cls) obj._hash_tuple = _hash_tuple obj._hash = hash(_hash_tuple) obj.ring = ring obj.dtype = type("FracElement", (FracElement,), {"field": obj}) obj.symbols = symbols obj.ngens = ngens obj.domain = domain obj.order = order obj.zero = obj.dtype(ring.zero) obj.one = obj.dtype(ring.one) obj.gens = obj._gens() for symbol, generator in zip(obj.symbols, obj.gens): if isinstance(symbol, Symbol): name = symbol.name if not hasattr(obj, name): setattr(obj, name, generator) _field_cache[_hash_tuple] = obj return obj def _gens(self): """Return a list of polynomial generators. """ return tuple([ self.dtype(gen) for gen in self.ring.gens ]) def __getnewargs__(self): return (self.symbols, self.domain, self.order) def __hash__(self): return self._hash def index(self, gen): if isinstance(gen, self.dtype): return self.ring.index(gen.to_poly()) else: raise ValueError("expected a %s, got %s instead" % (self.dtype,gen)) def __eq__(self, other): return isinstance(other, FracField) and \ (self.symbols, self.ngens, self.domain, self.order) == \ (other.symbols, other.ngens, other.domain, other.order) def __ne__(self, other): return not self == other def raw_new(self, numer, denom=None): return self.dtype(numer, denom) def new(self, numer, denom=None): if denom is None: denom = self.ring.one numer, denom = numer.cancel(denom) return self.raw_new(numer, denom) def domain_new(self, element): return self.domain.convert(element) def ground_new(self, element): try: return self.new(self.ring.ground_new(element)) except CoercionFailed: domain = self.domain if not domain.is_Field and domain.has_assoc_Field: ring = self.ring ground_field = domain.get_field() element = ground_field.convert(element) numer = ring.ground_new(ground_field.numer(element)) denom = ring.ground_new(ground_field.denom(element)) return self.raw_new(numer, denom) else: raise def field_new(self, element): if isinstance(element, FracElement): if self == element.field: return element if isinstance(self.domain, FractionField) and \ self.domain.field == element.field: return self.ground_new(element) elif isinstance(self.domain, PolynomialRing) and \ self.domain.ring.to_field() == element.field: return self.ground_new(element) else: raise NotImplementedError("conversion") elif isinstance(element, PolyElement): denom, numer = element.clear_denoms() if isinstance(self.domain, PolynomialRing) and \ numer.ring == self.domain.ring: numer = self.ring.ground_new(numer) elif isinstance(self.domain, FractionField) and \ numer.ring == self.domain.field.to_ring(): numer = self.ring.ground_new(numer) else: numer = numer.set_ring(self.ring) denom = self.ring.ground_new(denom) return self.raw_new(numer, denom) elif isinstance(element, tuple) and len(element) == 2: numer, denom = list(map(self.ring.ring_new, element)) return self.new(numer, denom) elif isinstance(element, str): raise NotImplementedError("parsing") elif isinstance(element, Expr): return self.from_expr(element) else: return self.ground_new(element) __call__ = field_new def _rebuild_expr(self, expr, mapping): domain = self.domain powers = tuple((gen, gen.as_base_exp()) for gen in mapping.keys() if gen.is_Pow or isinstance(gen, ExpBase)) def _rebuild(expr): generator = mapping.get(expr) if generator is not None: return generator elif expr.is_Add: return reduce(add, list(map(_rebuild, expr.args))) elif expr.is_Mul: return reduce(mul, list(map(_rebuild, expr.args))) elif expr.is_Pow or isinstance(expr, (ExpBase, Exp1)): b, e = expr.as_base_exp() # look for bg**eg whose integer power may be b**e for gen, (bg, eg) in powers: if bg == b and Mod(e, eg) == 0: return mapping.get(gen)**int(e/eg) if e.is_Integer and e is not S.One: return _rebuild(b)**int(e) try: return domain.convert(expr) except CoercionFailed: if not domain.is_Field and domain.has_assoc_Field: return domain.get_field().convert(expr) else: raise return _rebuild(sympify(expr)) def from_expr(self, expr): mapping = dict(list(zip(self.symbols, self.gens))) try: frac = self._rebuild_expr(expr, mapping) except CoercionFailed: raise ValueError("expected an expression convertible to a rational function in %s, got %s" % (self, expr)) else: return self.field_new(frac) def to_domain(self): return FractionField(self) def to_ring(self): from sympy.polys.rings import PolyRing return PolyRing(self.symbols, self.domain, self.order) class FracElement(DomainElement, DefaultPrinting, CantSympify): """Element of multivariate distributed rational function field. """ def __init__(self, numer, denom=None): if denom is None: denom = self.field.ring.one elif not denom: raise ZeroDivisionError("zero denominator") self.numer = numer self.denom = denom def raw_new(f, numer, denom): return f.__class__(numer, denom) def new(f, numer, denom): return f.raw_new(*numer.cancel(denom)) def to_poly(f): if f.denom != 1: raise ValueError("f.denom should be 1") return f.numer def parent(self): return self.field.to_domain() def __getnewargs__(self): return (self.field, self.numer, self.denom) _hash = None def __hash__(self): _hash = self._hash if _hash is None: self._hash = _hash = hash((self.field, self.numer, self.denom)) return _hash def copy(self): return self.raw_new(self.numer.copy(), self.denom.copy()) def set_field(self, new_field): if self.field == new_field: return self else: new_ring = new_field.ring numer = self.numer.set_ring(new_ring) denom = self.denom.set_ring(new_ring) return new_field.new(numer, denom) def as_expr(self, *symbols): return self.numer.as_expr(*symbols)/self.denom.as_expr(*symbols) def __eq__(f, g): if isinstance(g, FracElement) and f.field == g.field: return f.numer == g.numer and f.denom == g.denom else: return f.numer == g and f.denom == f.field.ring.one def __ne__(f, g): return not f == g def __bool__(f): return bool(f.numer) def sort_key(self): return (self.denom.sort_key(), self.numer.sort_key()) def _cmp(f1, f2, op): if isinstance(f2, f1.field.dtype): return op(f1.sort_key(), f2.sort_key()) else: return NotImplemented def __lt__(f1, f2): return f1._cmp(f2, lt) def __le__(f1, f2): return f1._cmp(f2, le) def __gt__(f1, f2): return f1._cmp(f2, gt) def __ge__(f1, f2): return f1._cmp(f2, ge) def __pos__(f): """Negate all coefficients in ``f``. """ return f.raw_new(f.numer, f.denom) def __neg__(f): """Negate all coefficients in ``f``. """ return f.raw_new(-f.numer, f.denom) def _extract_ground(self, element): domain = self.field.domain try: element = domain.convert(element) except CoercionFailed: if not domain.is_Field and domain.has_assoc_Field: ground_field = domain.get_field() try: element = ground_field.convert(element) except CoercionFailed: pass else: return -1, ground_field.numer(element), ground_field.denom(element) return 0, None, None else: return 1, element, None def __add__(f, g): """Add rational functions ``f`` and ``g``. """ field = f.field if not g: return f elif not f: return g elif isinstance(g, field.dtype): if f.denom == g.denom: return f.new(f.numer + g.numer, f.denom) else: return f.new(f.numer*g.denom + f.denom*g.numer, f.denom*g.denom) elif isinstance(g, field.ring.dtype): return f.new(f.numer + f.denom*g, f.denom) else: if isinstance(g, FracElement): if isinstance(field.domain, FractionField) and field.domain.field == g.field: pass elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: return g.__radd__(f) else: return NotImplemented elif isinstance(g, PolyElement): if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: pass else: return g.__radd__(f) return f.__radd__(g) def __radd__(f, c): if isinstance(c, f.field.ring.dtype): return f.new(f.numer + f.denom*c, f.denom) op, g_numer, g_denom = f._extract_ground(c) if op == 1: return f.new(f.numer + f.denom*g_numer, f.denom) elif not op: return NotImplemented else: return f.new(f.numer*g_denom + f.denom*g_numer, f.denom*g_denom) def __sub__(f, g): """Subtract rational functions ``f`` and ``g``. """ field = f.field if not g: return f elif not f: return -g elif isinstance(g, field.dtype): if f.denom == g.denom: return f.new(f.numer - g.numer, f.denom) else: return f.new(f.numer*g.denom - f.denom*g.numer, f.denom*g.denom) elif isinstance(g, field.ring.dtype): return f.new(f.numer - f.denom*g, f.denom) else: if isinstance(g, FracElement): if isinstance(field.domain, FractionField) and field.domain.field == g.field: pass elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: return g.__rsub__(f) else: return NotImplemented elif isinstance(g, PolyElement): if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: pass else: return g.__rsub__(f) op, g_numer, g_denom = f._extract_ground(g) if op == 1: return f.new(f.numer - f.denom*g_numer, f.denom) elif not op: return NotImplemented else: return f.new(f.numer*g_denom - f.denom*g_numer, f.denom*g_denom) def __rsub__(f, c): if isinstance(c, f.field.ring.dtype): return f.new(-f.numer + f.denom*c, f.denom) op, g_numer, g_denom = f._extract_ground(c) if op == 1: return f.new(-f.numer + f.denom*g_numer, f.denom) elif not op: return NotImplemented else: return f.new(-f.numer*g_denom + f.denom*g_numer, f.denom*g_denom) def __mul__(f, g): """Multiply rational functions ``f`` and ``g``. """ field = f.field if not f or not g: return field.zero elif isinstance(g, field.dtype): return f.new(f.numer*g.numer, f.denom*g.denom) elif isinstance(g, field.ring.dtype): return f.new(f.numer*g, f.denom) else: if isinstance(g, FracElement): if isinstance(field.domain, FractionField) and field.domain.field == g.field: pass elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: return g.__rmul__(f) else: return NotImplemented elif isinstance(g, PolyElement): if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: pass else: return g.__rmul__(f) return f.__rmul__(g) def __rmul__(f, c): if isinstance(c, f.field.ring.dtype): return f.new(f.numer*c, f.denom) op, g_numer, g_denom = f._extract_ground(c) if op == 1: return f.new(f.numer*g_numer, f.denom) elif not op: return NotImplemented else: return f.new(f.numer*g_numer, f.denom*g_denom) def __truediv__(f, g): """Computes quotient of fractions ``f`` and ``g``. """ field = f.field if not g: raise ZeroDivisionError elif isinstance(g, field.dtype): return f.new(f.numer*g.denom, f.denom*g.numer) elif isinstance(g, field.ring.dtype): return f.new(f.numer, f.denom*g) else: if isinstance(g, FracElement): if isinstance(field.domain, FractionField) and field.domain.field == g.field: pass elif isinstance(g.field.domain, FractionField) and g.field.domain.field == field: return g.__rtruediv__(f) else: return NotImplemented elif isinstance(g, PolyElement): if isinstance(field.domain, PolynomialRing) and field.domain.ring == g.ring: pass else: return g.__rtruediv__(f) op, g_numer, g_denom = f._extract_ground(g) if op == 1: return f.new(f.numer, f.denom*g_numer) elif not op: return NotImplemented else: return f.new(f.numer*g_denom, f.denom*g_numer) def __rtruediv__(f, c): if not f: raise ZeroDivisionError elif isinstance(c, f.field.ring.dtype): return f.new(f.denom*c, f.numer) op, g_numer, g_denom = f._extract_ground(c) if op == 1: return f.new(f.denom*g_numer, f.numer) elif not op: return NotImplemented else: return f.new(f.denom*g_numer, f.numer*g_denom) def __pow__(f, n): """Raise ``f`` to a non-negative power ``n``. """ if n >= 0: return f.raw_new(f.numer**n, f.denom**n) elif not f: raise ZeroDivisionError else: return f.raw_new(f.denom**-n, f.numer**-n) def diff(f, x): """Computes partial derivative in ``x``. Examples ======== >>> from sympy.polys.fields import field >>> from sympy.polys.domains import ZZ >>> _, x, y, z = field("x,y,z", ZZ) >>> ((x**2 + y)/(z + 1)).diff(x) 2*x/(z + 1) """ x = x.to_poly() return f.new(f.numer.diff(x)*f.denom - f.numer*f.denom.diff(x), f.denom**2) def __call__(f, *values): if 0 < len(values) <= f.field.ngens: return f.evaluate(list(zip(f.field.gens, values))) else: raise ValueError("expected at least 1 and at most %s values, got %s" % (f.field.ngens, len(values))) def evaluate(f, x, a=None): if isinstance(x, list) and a is None: x = [ (X.to_poly(), a) for X, a in x ] numer, denom = f.numer.evaluate(x), f.denom.evaluate(x) else: x = x.to_poly() numer, denom = f.numer.evaluate(x, a), f.denom.evaluate(x, a) field = numer.ring.to_field() return field.new(numer, denom) def subs(f, x, a=None): if isinstance(x, list) and a is None: x = [ (X.to_poly(), a) for X, a in x ] numer, denom = f.numer.subs(x), f.denom.subs(x) else: x = x.to_poly() numer, denom = f.numer.subs(x, a), f.denom.subs(x, a) return f.new(numer, denom) def compose(f, x, a=None): raise NotImplementedError sympy-sympy-1.9/sympy/polys/galoistools.py000066400000000000000000001451721412543434000211750ustar00rootroot00000000000000"""Dense univariate polynomials with coefficients in Galois fields. """ from random import uniform from math import ceil as _ceil, sqrt as _sqrt from sympy.core.compatibility import SYMPY_INTS from sympy.core.mul import prod from sympy.ntheory import factorint from sympy.polys.polyconfig import query from sympy.polys.polyerrors import ExactQuotientFailed from sympy.polys.polyutils import _sort_factors def gf_crt(U, M, K=None): """ Chinese Remainder Theorem. Given a set of integer residues ``u_0,...,u_n`` and a set of co-prime integer moduli ``m_0,...,m_n``, returns an integer ``u``, such that ``u = u_i mod m_i`` for ``i = ``0,...,n``. Examples ======== Consider a set of residues ``U = [49, 76, 65]`` and a set of moduli ``M = [99, 97, 95]``. Then we have:: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_crt >>> gf_crt([49, 76, 65], [99, 97, 95], ZZ) 639985 This is the correct result because:: >>> [639985 % m for m in [99, 97, 95]] [49, 76, 65] Note: this is a low-level routine with no error checking. See Also ======== sympy.ntheory.modular.crt : a higher level crt routine sympy.ntheory.modular.solve_congruence """ p = prod(M, start=K.one) v = K.zero for u, m in zip(U, M): e = p // m s, _, _ = K.gcdex(e, m) v += e*(u*s % m) return v % p def gf_crt1(M, K): """ First part of the Chinese Remainder Theorem. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_crt1 >>> gf_crt1([99, 97, 95], ZZ) (912285, [9215, 9405, 9603], [62, 24, 12]) """ E, S = [], [] p = prod(M, start=K.one) for m in M: E.append(p // m) S.append(K.gcdex(E[-1], m)[0] % m) return p, E, S def gf_crt2(U, M, p, E, S, K): """ Second part of the Chinese Remainder Theorem. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_crt2 >>> U = [49, 76, 65] >>> M = [99, 97, 95] >>> p = 912285 >>> E = [9215, 9405, 9603] >>> S = [62, 24, 12] >>> gf_crt2(U, M, p, E, S, ZZ) 639985 """ v = K.zero for u, m, e, s in zip(U, M, E, S): v += e*(u*s % m) return v % p def gf_int(a, p): """ Coerce ``a mod p`` to an integer in the range ``[-p/2, p/2]``. Examples ======== >>> from sympy.polys.galoistools import gf_int >>> gf_int(2, 7) 2 >>> gf_int(5, 7) -2 """ if a <= p // 2: return a else: return a - p def gf_degree(f): """ Return the leading degree of ``f``. Examples ======== >>> from sympy.polys.galoistools import gf_degree >>> gf_degree([1, 1, 2, 0]) 3 >>> gf_degree([]) -1 """ return len(f) - 1 def gf_LC(f, K): """ Return the leading coefficient of ``f``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_LC >>> gf_LC([3, 0, 1], ZZ) 3 """ if not f: return K.zero else: return f[0] def gf_TC(f, K): """ Return the trailing coefficient of ``f``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_TC >>> gf_TC([3, 0, 1], ZZ) 1 """ if not f: return K.zero else: return f[-1] def gf_strip(f): """ Remove leading zeros from ``f``. Examples ======== >>> from sympy.polys.galoistools import gf_strip >>> gf_strip([0, 0, 0, 3, 0, 1]) [3, 0, 1] """ if not f or f[0]: return f k = 0 for coeff in f: if coeff: break else: k += 1 return f[k:] def gf_trunc(f, p): """ Reduce all coefficients modulo ``p``. Examples ======== >>> from sympy.polys.galoistools import gf_trunc >>> gf_trunc([7, -2, 3], 5) [2, 3, 3] """ return gf_strip([ a % p for a in f ]) def gf_normal(f, p, K): """ Normalize all coefficients in ``K``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_normal >>> gf_normal([5, 10, 21, -3], 5, ZZ) [1, 2] """ return gf_trunc(list(map(K, f)), p) def gf_from_dict(f, p, K): """ Create a ``GF(p)[x]`` polynomial from a dict. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_from_dict >>> gf_from_dict({10: ZZ(4), 4: ZZ(33), 0: ZZ(-1)}, 5, ZZ) [4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4] """ n, h = max(f.keys()), [] if isinstance(n, SYMPY_INTS): for k in range(n, -1, -1): h.append(f.get(k, K.zero) % p) else: (n,) = n for k in range(n, -1, -1): h.append(f.get((k,), K.zero) % p) return gf_trunc(h, p) def gf_to_dict(f, p, symmetric=True): """ Convert a ``GF(p)[x]`` polynomial to a dict. Examples ======== >>> from sympy.polys.galoistools import gf_to_dict >>> gf_to_dict([4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4], 5) {0: -1, 4: -2, 10: -1} >>> gf_to_dict([4, 0, 0, 0, 0, 0, 3, 0, 0, 0, 4], 5, symmetric=False) {0: 4, 4: 3, 10: 4} """ n, result = gf_degree(f), {} for k in range(0, n + 1): if symmetric: a = gf_int(f[n - k], p) else: a = f[n - k] if a: result[k] = a return result def gf_from_int_poly(f, p): """ Create a ``GF(p)[x]`` polynomial from ``Z[x]``. Examples ======== >>> from sympy.polys.galoistools import gf_from_int_poly >>> gf_from_int_poly([7, -2, 3], 5) [2, 3, 3] """ return gf_trunc(f, p) def gf_to_int_poly(f, p, symmetric=True): """ Convert a ``GF(p)[x]`` polynomial to ``Z[x]``. Examples ======== >>> from sympy.polys.galoistools import gf_to_int_poly >>> gf_to_int_poly([2, 3, 3], 5) [2, -2, -2] >>> gf_to_int_poly([2, 3, 3], 5, symmetric=False) [2, 3, 3] """ if symmetric: return [ gf_int(c, p) for c in f ] else: return f def gf_neg(f, p, K): """ Negate a polynomial in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_neg >>> gf_neg([3, 2, 1, 0], 5, ZZ) [2, 3, 4, 0] """ return [ -coeff % p for coeff in f ] def gf_add_ground(f, a, p, K): """ Compute ``f + a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_add_ground >>> gf_add_ground([3, 2, 4], 2, 5, ZZ) [3, 2, 1] """ if not f: a = a % p else: a = (f[-1] + a) % p if len(f) > 1: return f[:-1] + [a] if not a: return [] else: return [a] def gf_sub_ground(f, a, p, K): """ Compute ``f - a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sub_ground >>> gf_sub_ground([3, 2, 4], 2, 5, ZZ) [3, 2, 2] """ if not f: a = -a % p else: a = (f[-1] - a) % p if len(f) > 1: return f[:-1] + [a] if not a: return [] else: return [a] def gf_mul_ground(f, a, p, K): """ Compute ``f * a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_mul_ground >>> gf_mul_ground([3, 2, 4], 2, 5, ZZ) [1, 4, 3] """ if not a: return [] else: return [ (a*b) % p for b in f ] def gf_quo_ground(f, a, p, K): """ Compute ``f/a`` where ``f`` in ``GF(p)[x]`` and ``a`` in ``GF(p)``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_quo_ground >>> gf_quo_ground(ZZ.map([3, 2, 4]), ZZ(2), 5, ZZ) [4, 1, 2] """ return gf_mul_ground(f, K.invert(a, p), p, K) def gf_add(f, g, p, K): """ Add polynomials in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_add >>> gf_add([3, 2, 4], [2, 2, 2], 5, ZZ) [4, 1] """ if not f: return g if not g: return f df = gf_degree(f) dg = gf_degree(g) if df == dg: return gf_strip([ (a + b) % p for a, b in zip(f, g) ]) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = g[:k], g[k:] return h + [ (a + b) % p for a, b in zip(f, g) ] def gf_sub(f, g, p, K): """ Subtract polynomials in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sub >>> gf_sub([3, 2, 4], [2, 2, 2], 5, ZZ) [1, 0, 2] """ if not g: return f if not f: return gf_neg(g, p, K) df = gf_degree(f) dg = gf_degree(g) if df == dg: return gf_strip([ (a - b) % p for a, b in zip(f, g) ]) else: k = abs(df - dg) if df > dg: h, f = f[:k], f[k:] else: h, g = gf_neg(g[:k], p, K), g[k:] return h + [ (a - b) % p for a, b in zip(f, g) ] def gf_mul(f, g, p, K): """ Multiply polynomials in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_mul >>> gf_mul([3, 2, 4], [2, 2, 2], 5, ZZ) [1, 0, 3, 2, 3] """ df = gf_degree(f) dg = gf_degree(g) dh = df + dg h = [0]*(dh + 1) for i in range(0, dh + 1): coeff = K.zero for j in range(max(0, i - dg), min(i, df) + 1): coeff += f[j]*g[i - j] h[i] = coeff % p return gf_strip(h) def gf_sqr(f, p, K): """ Square polynomials in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sqr >>> gf_sqr([3, 2, 4], 5, ZZ) [4, 2, 3, 1, 1] """ df = gf_degree(f) dh = 2*df h = [0]*(dh + 1) for i in range(0, dh + 1): coeff = K.zero jmin = max(0, i - df) jmax = min(i, df) n = jmax - jmin + 1 jmax = jmin + n // 2 - 1 for j in range(jmin, jmax + 1): coeff += f[j]*f[i - j] coeff += coeff if n & 1: elem = f[jmax + 1] coeff += elem**2 h[i] = coeff % p return gf_strip(h) def gf_add_mul(f, g, h, p, K): """ Returns ``f + g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_add_mul >>> gf_add_mul([3, 2, 4], [2, 2, 2], [1, 4], 5, ZZ) [2, 3, 2, 2] """ return gf_add(f, gf_mul(g, h, p, K), p, K) def gf_sub_mul(f, g, h, p, K): """ Compute ``f - g*h`` where ``f``, ``g``, ``h`` in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sub_mul >>> gf_sub_mul([3, 2, 4], [2, 2, 2], [1, 4], 5, ZZ) [3, 3, 2, 1] """ return gf_sub(f, gf_mul(g, h, p, K), p, K) def gf_expand(F, p, K): """ Expand results of :func:`~.factor` in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_expand >>> gf_expand([([3, 2, 4], 1), ([2, 2], 2), ([3, 1], 3)], 5, ZZ) [4, 3, 0, 3, 0, 1, 4, 1] """ if type(F) is tuple: lc, F = F else: lc = K.one g = [lc] for f, k in F: f = gf_pow(f, k, p, K) g = gf_mul(g, f, p, K) return g def gf_div(f, g, p, K): """ Division with remainder in ``GF(p)[x]``. Given univariate polynomials ``f`` and ``g`` with coefficients in a finite field with ``p`` elements, returns polynomials ``q`` and ``r`` (quotient and remainder) such that ``f = q*g + r``. Consider polynomials ``x**3 + x + 1`` and ``x**2 + x`` in GF(2):: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_div, gf_add_mul >>> gf_div(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) ([1, 1], [1]) As result we obtained quotient ``x + 1`` and remainder ``1``, thus:: >>> gf_add_mul(ZZ.map([1]), ZZ.map([1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) [1, 0, 1, 1] References ========== .. [1] [Monagan93]_ .. [2] [Gathen99]_ """ df = gf_degree(f) dg = gf_degree(g) if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return [], f inv = K.invert(g[0], p) h, dq, dr = list(f), df - dg, dg - 1 for i in range(0, df + 1): coeff = h[i] for j in range(max(0, dg - i), min(df - i, dr) + 1): coeff -= h[i + j - dg] * g[dg - j] if i <= dq: coeff *= inv h[i] = coeff % p return h[:dq + 1], gf_strip(h[dq + 1:]) def gf_rem(f, g, p, K): """ Compute polynomial remainder in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_rem >>> gf_rem(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) [1] """ return gf_div(f, g, p, K)[1] def gf_quo(f, g, p, K): """ Compute exact quotient in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_quo >>> gf_quo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) [1, 1] >>> gf_quo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ) [3, 2, 4] """ df = gf_degree(f) dg = gf_degree(g) if not g: raise ZeroDivisionError("polynomial division") elif df < dg: return [] inv = K.invert(g[0], p) h, dq, dr = f[:], df - dg, dg - 1 for i in range(0, dq + 1): coeff = h[i] for j in range(max(0, dg - i), min(df - i, dr) + 1): coeff -= h[i + j - dg] * g[dg - j] h[i] = (coeff * inv) % p return h[:dq + 1] def gf_exquo(f, g, p, K): """ Compute polynomial quotient in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_exquo >>> gf_exquo(ZZ.map([1, 0, 3, 2, 3]), ZZ.map([2, 2, 2]), 5, ZZ) [3, 2, 4] >>> gf_exquo(ZZ.map([1, 0, 1, 1]), ZZ.map([1, 1, 0]), 2, ZZ) Traceback (most recent call last): ... ExactQuotientFailed: [1, 1, 0] does not divide [1, 0, 1, 1] """ q, r = gf_div(f, g, p, K) if not r: return q else: raise ExactQuotientFailed(f, g) def gf_lshift(f, n, K): """ Efficiently multiply ``f`` by ``x**n``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_lshift >>> gf_lshift([3, 2, 4], 4, ZZ) [3, 2, 4, 0, 0, 0, 0] """ if not f: return f else: return f + [K.zero]*n def gf_rshift(f, n, K): """ Efficiently divide ``f`` by ``x**n``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_rshift >>> gf_rshift([1, 2, 3, 4, 0], 3, ZZ) ([1, 2], [3, 4, 0]) """ if not n: return f, [] else: return f[:-n], f[-n:] def gf_pow(f, n, p, K): """ Compute ``f**n`` in ``GF(p)[x]`` using repeated squaring. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_pow >>> gf_pow([3, 2, 4], 3, 5, ZZ) [2, 4, 4, 2, 2, 1, 4] """ if not n: return [K.one] elif n == 1: return f elif n == 2: return gf_sqr(f, p, K) h = [K.one] while True: if n & 1: h = gf_mul(h, f, p, K) n -= 1 n >>= 1 if not n: break f = gf_sqr(f, p, K) return h def gf_frobenius_monomial_base(g, p, K): """ return the list of ``x**(i*p) mod g in Z_p`` for ``i = 0, .., n - 1`` where ``n = gf_degree(g)`` Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_frobenius_monomial_base >>> g = ZZ.map([1, 0, 2, 1]) >>> gf_frobenius_monomial_base(g, 5, ZZ) [[1], [4, 4, 2], [1, 2]] """ n = gf_degree(g) if n == 0: return [] b = [0]*n b[0] = [1] if p < n: for i in range(1, n): mon = gf_lshift(b[i - 1], p, K) b[i] = gf_rem(mon, g, p, K) elif n > 1: b[1] = gf_pow_mod([K.one, K.zero], p, g, p, K) for i in range(2, n): b[i] = gf_mul(b[i - 1], b[1], p, K) b[i] = gf_rem(b[i], g, p, K) return b def gf_frobenius_map(f, g, b, p, K): """ compute gf_pow_mod(f, p, g, p, K) using the Frobenius map Parameters ========== f, g : polynomials in ``GF(p)[x]`` b : frobenius monomial base p : prime number K : domain Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_frobenius_monomial_base, gf_frobenius_map >>> f = ZZ.map([2, 1 , 0, 1]) >>> g = ZZ.map([1, 0, 2, 1]) >>> p = 5 >>> b = gf_frobenius_monomial_base(g, p, ZZ) >>> r = gf_frobenius_map(f, g, b, p, ZZ) >>> gf_frobenius_map(f, g, b, p, ZZ) [4, 0, 3] """ m = gf_degree(g) if gf_degree(f) >= m: f = gf_rem(f, g, p, K) if not f: return [] n = gf_degree(f) sf = [f[-1]] for i in range(1, n + 1): v = gf_mul_ground(b[i], f[n - i], p, K) sf = gf_add(sf, v, p, K) return sf def _gf_pow_pnm1d2(f, n, g, b, p, K): """ utility function for ``gf_edf_zassenhaus`` Compute ``f**((p**n - 1) // 2)`` in ``GF(p)[x]/(g)`` ``f**((p**n - 1) // 2) = (f*f**p*...*f**(p**n - 1))**((p - 1) // 2)`` """ f = gf_rem(f, g, p, K) h = f r = f for i in range(1, n): h = gf_frobenius_map(h, g, b, p, K) r = gf_mul(r, h, p, K) r = gf_rem(r, g, p, K) res = gf_pow_mod(r, (p - 1)//2, g, p, K) return res def gf_pow_mod(f, n, g, p, K): """ Compute ``f**n`` in ``GF(p)[x]/(g)`` using repeated squaring. Given polynomials ``f`` and ``g`` in ``GF(p)[x]`` and a non-negative integer ``n``, efficiently computes ``f**n (mod g)`` i.e. the remainder of ``f**n`` from division by ``g``, using the repeated squaring algorithm. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_pow_mod >>> gf_pow_mod(ZZ.map([3, 2, 4]), 3, ZZ.map([1, 1]), 5, ZZ) [] References ========== .. [1] [Gathen99]_ """ if not n: return [K.one] elif n == 1: return gf_rem(f, g, p, K) elif n == 2: return gf_rem(gf_sqr(f, p, K), g, p, K) h = [K.one] while True: if n & 1: h = gf_mul(h, f, p, K) h = gf_rem(h, g, p, K) n -= 1 n >>= 1 if not n: break f = gf_sqr(f, p, K) f = gf_rem(f, g, p, K) return h def gf_gcd(f, g, p, K): """ Euclidean Algorithm in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_gcd >>> gf_gcd(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) [1, 3] """ while g: f, g = g, gf_rem(f, g, p, K) return gf_monic(f, p, K)[1] def gf_lcm(f, g, p, K): """ Compute polynomial LCM in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_lcm >>> gf_lcm(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) [1, 2, 0, 4] """ if not f or not g: return [] h = gf_quo(gf_mul(f, g, p, K), gf_gcd(f, g, p, K), p, K) return gf_monic(h, p, K)[1] def gf_cofactors(f, g, p, K): """ Compute polynomial GCD and cofactors in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_cofactors >>> gf_cofactors(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 3]), 5, ZZ) ([1, 3], [3, 3], [2, 1]) """ if not f and not g: return ([], [], []) h = gf_gcd(f, g, p, K) return (h, gf_quo(f, h, p, K), gf_quo(g, h, p, K)) def gf_gcdex(f, g, p, K): """ Extended Euclidean Algorithm in ``GF(p)[x]``. Given polynomials ``f`` and ``g`` in ``GF(p)[x]``, computes polynomials ``s``, ``t`` and ``h``, such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. The typical application of EEA is solving polynomial diophantine equations. Consider polynomials ``f = (x + 7) (x + 1)``, ``g = (x + 7) (x**2 + 1)`` in ``GF(11)[x]``. Application of Extended Euclidean Algorithm gives:: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_gcdex, gf_mul, gf_add >>> s, t, g = gf_gcdex(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) >>> s, t, g ([5, 6], [6], [1, 7]) As result we obtained polynomials ``s = 5*x + 6`` and ``t = 6``, and additionally ``gcd(f, g) = x + 7``. This is correct because:: >>> S = gf_mul(s, ZZ.map([1, 8, 7]), 11, ZZ) >>> T = gf_mul(t, ZZ.map([1, 7, 1, 7]), 11, ZZ) >>> gf_add(S, T, 11, ZZ) == [1, 7] True References ========== .. [1] [Gathen99]_ """ if not (f or g): return [K.one], [], [] p0, r0 = gf_monic(f, p, K) p1, r1 = gf_monic(g, p, K) if not f: return [], [K.invert(p1, p)], r1 if not g: return [K.invert(p0, p)], [], r0 s0, s1 = [K.invert(p0, p)], [] t0, t1 = [], [K.invert(p1, p)] while True: Q, R = gf_div(r0, r1, p, K) if not R: break (lc, r1), r0 = gf_monic(R, p, K), r1 inv = K.invert(lc, p) s = gf_sub_mul(s0, s1, Q, p, K) t = gf_sub_mul(t0, t1, Q, p, K) s1, s0 = gf_mul_ground(s, inv, p, K), s1 t1, t0 = gf_mul_ground(t, inv, p, K), t1 return s1, t1, r1 def gf_monic(f, p, K): """ Compute LC and a monic polynomial in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_monic >>> gf_monic(ZZ.map([3, 2, 4]), 5, ZZ) (3, [1, 4, 3]) """ if not f: return K.zero, [] else: lc = f[0] if K.is_one(lc): return lc, list(f) else: return lc, gf_quo_ground(f, lc, p, K) def gf_diff(f, p, K): """ Differentiate polynomial in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_diff >>> gf_diff([3, 2, 4], 5, ZZ) [1, 2] """ df = gf_degree(f) h, n = [K.zero]*df, df for coeff in f[:-1]: coeff *= K(n) coeff %= p if coeff: h[df - n] = coeff n -= 1 return gf_strip(h) def gf_eval(f, a, p, K): """ Evaluate ``f(a)`` in ``GF(p)`` using Horner scheme. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_eval >>> gf_eval([3, 2, 4], 2, 5, ZZ) 0 """ result = K.zero for c in f: result *= a result += c result %= p return result def gf_multi_eval(f, A, p, K): """ Evaluate ``f(a)`` for ``a`` in ``[a_1, ..., a_n]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_multi_eval >>> gf_multi_eval([3, 2, 4], [0, 1, 2, 3, 4], 5, ZZ) [4, 4, 0, 2, 0] """ return [ gf_eval(f, a, p, K) for a in A ] def gf_compose(f, g, p, K): """ Compute polynomial composition ``f(g)`` in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_compose >>> gf_compose([3, 2, 4], [2, 2, 2], 5, ZZ) [2, 4, 0, 3, 0] """ if len(g) <= 1: return gf_strip([gf_eval(f, gf_LC(g, K), p, K)]) if not f: return [] h = [f[0]] for c in f[1:]: h = gf_mul(h, g, p, K) h = gf_add_ground(h, c, p, K) return h def gf_compose_mod(g, h, f, p, K): """ Compute polynomial composition ``g(h)`` in ``GF(p)[x]/(f)``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_compose_mod >>> gf_compose_mod(ZZ.map([3, 2, 4]), ZZ.map([2, 2, 2]), ZZ.map([4, 3]), 5, ZZ) [4] """ if not g: return [] comp = [g[0]] for a in g[1:]: comp = gf_mul(comp, h, p, K) comp = gf_add_ground(comp, a, p, K) comp = gf_rem(comp, f, p, K) return comp def gf_trace_map(a, b, c, n, f, p, K): """ Compute polynomial trace map in ``GF(p)[x]/(f)``. Given a polynomial ``f`` in ``GF(p)[x]``, polynomials ``a``, ``b``, ``c`` in the quotient ring ``GF(p)[x]/(f)`` such that ``b = c**t (mod f)`` for some positive power ``t`` of ``p``, and a positive integer ``n``, returns a mapping:: a -> a**t**n, a + a**t + a**t**2 + ... + a**t**n (mod f) In factorization context, ``b = x**p mod f`` and ``c = x mod f``. This way we can efficiently compute trace polynomials in equal degree factorization routine, much faster than with other methods, like iterated Frobenius algorithm, for large degrees. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_trace_map >>> gf_trace_map([1, 2], [4, 4], [1, 1], 4, [3, 2, 4], 5, ZZ) ([1, 3], [1, 3]) References ========== .. [1] [Gathen92]_ """ u = gf_compose_mod(a, b, f, p, K) v = b if n & 1: U = gf_add(a, u, p, K) V = b else: U = a V = c n >>= 1 while n: u = gf_add(u, gf_compose_mod(u, v, f, p, K), p, K) v = gf_compose_mod(v, v, f, p, K) if n & 1: U = gf_add(U, gf_compose_mod(u, V, f, p, K), p, K) V = gf_compose_mod(v, V, f, p, K) n >>= 1 return gf_compose_mod(a, V, f, p, K), U def _gf_trace_map(f, n, g, b, p, K): """ utility for ``gf_edf_shoup`` """ f = gf_rem(f, g, p, K) h = f r = f for i in range(1, n): h = gf_frobenius_map(h, g, b, p, K) r = gf_add(r, h, p, K) r = gf_rem(r, g, p, K) return r def gf_random(n, p, K): """ Generate a random polynomial in ``GF(p)[x]`` of degree ``n``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_random >>> gf_random(10, 5, ZZ) #doctest: +SKIP [1, 2, 3, 2, 1, 1, 1, 2, 0, 4, 2] """ return [K.one] + [ K(int(uniform(0, p))) for i in range(0, n) ] def gf_irreducible(n, p, K): """ Generate random irreducible polynomial of degree ``n`` in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_irreducible >>> gf_irreducible(10, 5, ZZ) #doctest: +SKIP [1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4] """ while True: f = gf_random(n, p, K) if gf_irreducible_p(f, p, K): return f def gf_irred_p_ben_or(f, p, K): """ Ben-Or's polynomial irreducibility test over finite fields. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_irred_p_ben_or >>> gf_irred_p_ben_or(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) True >>> gf_irred_p_ben_or(ZZ.map([3, 2, 4]), 5, ZZ) False """ n = gf_degree(f) if n <= 1: return True _, f = gf_monic(f, p, K) if n < 5: H = h = gf_pow_mod([K.one, K.zero], p, f, p, K) for i in range(0, n//2): g = gf_sub(h, [K.one, K.zero], p, K) if gf_gcd(f, g, p, K) == [K.one]: h = gf_compose_mod(h, H, f, p, K) else: return False else: b = gf_frobenius_monomial_base(f, p, K) H = h = gf_frobenius_map([K.one, K.zero], f, b, p, K) for i in range(0, n//2): g = gf_sub(h, [K.one, K.zero], p, K) if gf_gcd(f, g, p, K) == [K.one]: h = gf_frobenius_map(h, f, b, p, K) else: return False return True def gf_irred_p_rabin(f, p, K): """ Rabin's polynomial irreducibility test over finite fields. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_irred_p_rabin >>> gf_irred_p_rabin(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) True >>> gf_irred_p_rabin(ZZ.map([3, 2, 4]), 5, ZZ) False """ n = gf_degree(f) if n <= 1: return True _, f = gf_monic(f, p, K) x = [K.one, K.zero] indices = { n//d for d in factorint(n) } b = gf_frobenius_monomial_base(f, p, K) h = b[1] for i in range(1, n): if i in indices: g = gf_sub(h, x, p, K) if gf_gcd(f, g, p, K) != [K.one]: return False h = gf_frobenius_map(h, f, b, p, K) return h == x _irred_methods = { 'ben-or': gf_irred_p_ben_or, 'rabin': gf_irred_p_rabin, } def gf_irreducible_p(f, p, K): """ Test irreducibility of a polynomial ``f`` in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_irreducible_p >>> gf_irreducible_p(ZZ.map([1, 4, 2, 2, 3, 2, 4, 1, 4, 0, 4]), 5, ZZ) True >>> gf_irreducible_p(ZZ.map([3, 2, 4]), 5, ZZ) False """ method = query('GF_IRRED_METHOD') if method is not None: irred = _irred_methods[method](f, p, K) else: irred = gf_irred_p_rabin(f, p, K) return irred def gf_sqf_p(f, p, K): """ Return ``True`` if ``f`` is square-free in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sqf_p >>> gf_sqf_p(ZZ.map([3, 2, 4]), 5, ZZ) True >>> gf_sqf_p(ZZ.map([2, 4, 4, 2, 2, 1, 4]), 5, ZZ) False """ _, f = gf_monic(f, p, K) if not f: return True else: return gf_gcd(f, gf_diff(f, p, K), p, K) == [K.one] def gf_sqf_part(f, p, K): """ Return square-free part of a ``GF(p)[x]`` polynomial. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_sqf_part >>> gf_sqf_part(ZZ.map([1, 1, 3, 0, 1, 0, 2, 2, 1]), 5, ZZ) [1, 4, 3] """ _, sqf = gf_sqf_list(f, p, K) g = [K.one] for f, _ in sqf: g = gf_mul(g, f, p, K) return g def gf_sqf_list(f, p, K, all=False): """ Return the square-free decomposition of a ``GF(p)[x]`` polynomial. Given a polynomial ``f`` in ``GF(p)[x]``, returns the leading coefficient of ``f`` and a square-free decomposition ``f_1**e_1 f_2**e_2 ... f_k**e_k`` such that all ``f_i`` are monic polynomials and ``(f_i, f_j)`` for ``i != j`` are co-prime and ``e_1 ... e_k`` are given in increasing order. All trivial terms (i.e. ``f_i = 1``) aren't included in the output. Consider polynomial ``f = x**11 + 1`` over ``GF(11)[x]``:: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import ( ... gf_from_dict, gf_diff, gf_sqf_list, gf_pow, ... ) ... # doctest: +NORMALIZE_WHITESPACE >>> f = gf_from_dict({11: ZZ(1), 0: ZZ(1)}, 11, ZZ) Note that ``f'(x) = 0``:: >>> gf_diff(f, 11, ZZ) [] This phenomenon doesn't happen in characteristic zero. However we can still compute square-free decomposition of ``f`` using ``gf_sqf()``:: >>> gf_sqf_list(f, 11, ZZ) (1, [([1, 1], 11)]) We obtained factorization ``f = (x + 1)**11``. This is correct because:: >>> gf_pow([1, 1], 11, 11, ZZ) == f True References ========== .. [1] [Geddes92]_ """ n, sqf, factors, r = 1, False, [], int(p) lc, f = gf_monic(f, p, K) if gf_degree(f) < 1: return lc, [] while True: F = gf_diff(f, p, K) if F != []: g = gf_gcd(f, F, p, K) h = gf_quo(f, g, p, K) i = 1 while h != [K.one]: G = gf_gcd(g, h, p, K) H = gf_quo(h, G, p, K) if gf_degree(H) > 0: factors.append((H, i*n)) g, h, i = gf_quo(g, G, p, K), G, i + 1 if g == [K.one]: sqf = True else: f = g if not sqf: d = gf_degree(f) // r for i in range(0, d + 1): f[i] = f[i*r] f, n = f[:d + 1], n*r else: break if all: raise ValueError("'all=True' is not supported yet") return lc, factors def gf_Qmatrix(f, p, K): """ Calculate Berlekamp's ``Q`` matrix. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_Qmatrix >>> gf_Qmatrix([3, 2, 4], 5, ZZ) [[1, 0], [3, 4]] >>> gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ) [[1, 0, 0, 0], [0, 4, 0, 0], [0, 0, 1, 0], [0, 0, 0, 4]] """ n, r = gf_degree(f), int(p) q = [K.one] + [K.zero]*(n - 1) Q = [list(q)] + [[]]*(n - 1) for i in range(1, (n - 1)*r + 1): qq, c = [(-q[-1]*f[-1]) % p], q[-1] for j in range(1, n): qq.append((q[j - 1] - c*f[-j - 1]) % p) if not (i % r): Q[i//r] = list(qq) q = qq return Q def gf_Qbasis(Q, p, K): """ Compute a basis of the kernel of ``Q``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_Qmatrix, gf_Qbasis >>> gf_Qbasis(gf_Qmatrix([1, 0, 0, 0, 1], 5, ZZ), 5, ZZ) [[1, 0, 0, 0], [0, 0, 1, 0]] >>> gf_Qbasis(gf_Qmatrix([3, 2, 4], 5, ZZ), 5, ZZ) [[1, 0]] """ Q, n = [ list(q) for q in Q ], len(Q) for k in range(0, n): Q[k][k] = (Q[k][k] - K.one) % p for k in range(0, n): for i in range(k, n): if Q[k][i]: break else: continue inv = K.invert(Q[k][i], p) for j in range(0, n): Q[j][i] = (Q[j][i]*inv) % p for j in range(0, n): t = Q[j][k] Q[j][k] = Q[j][i] Q[j][i] = t for i in range(0, n): if i != k: q = Q[k][i] for j in range(0, n): Q[j][i] = (Q[j][i] - Q[j][k]*q) % p for i in range(0, n): for j in range(0, n): if i == j: Q[i][j] = (K.one - Q[i][j]) % p else: Q[i][j] = (-Q[i][j]) % p basis = [] for q in Q: if any(q): basis.append(q) return basis def gf_berlekamp(f, p, K): """ Factor a square-free ``f`` in ``GF(p)[x]`` for small ``p``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_berlekamp >>> gf_berlekamp([1, 0, 0, 0, 1], 5, ZZ) [[1, 0, 2], [1, 0, 3]] """ Q = gf_Qmatrix(f, p, K) V = gf_Qbasis(Q, p, K) for i, v in enumerate(V): V[i] = gf_strip(list(reversed(v))) factors = [f] for k in range(1, len(V)): for f in list(factors): s = K.zero while s < p: g = gf_sub_ground(V[k], s, p, K) h = gf_gcd(f, g, p, K) if h != [K.one] and h != f: factors.remove(f) f = gf_quo(f, h, p, K) factors.extend([f, h]) if len(factors) == len(V): return _sort_factors(factors, multiple=False) s += K.one return _sort_factors(factors, multiple=False) def gf_ddf_zassenhaus(f, p, K): """ Cantor-Zassenhaus: Deterministic Distinct Degree Factorization Given a monic square-free polynomial ``f`` in ``GF(p)[x]``, computes partial distinct degree factorization ``f_1 ... f_d`` of ``f`` where ``deg(f_i) != deg(f_j)`` for ``i != j``. The result is returned as a list of pairs ``(f_i, e_i)`` where ``deg(f_i) > 0`` and ``e_i > 0`` is an argument to the equal degree factorization routine. Consider the polynomial ``x**15 - 1`` in ``GF(11)[x]``:: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_from_dict >>> f = gf_from_dict({15: ZZ(1), 0: ZZ(-1)}, 11, ZZ) Distinct degree factorization gives:: >>> from sympy.polys.galoistools import gf_ddf_zassenhaus >>> gf_ddf_zassenhaus(f, 11, ZZ) [([1, 0, 0, 0, 0, 10], 1), ([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2)] which means ``x**15 - 1 = (x**5 - 1) (x**10 + x**5 + 1)``. To obtain factorization into irreducibles, use equal degree factorization procedure (EDF) with each of the factors. References ========== .. [1] [Gathen99]_ .. [2] [Geddes92]_ """ i, g, factors = 1, [K.one, K.zero], [] b = gf_frobenius_monomial_base(f, p, K) while 2*i <= gf_degree(f): g = gf_frobenius_map(g, f, b, p, K) h = gf_gcd(f, gf_sub(g, [K.one, K.zero], p, K), p, K) if h != [K.one]: factors.append((h, i)) f = gf_quo(f, h, p, K) g = gf_rem(g, f, p, K) b = gf_frobenius_monomial_base(f, p, K) i += 1 if f != [K.one]: return factors + [(f, gf_degree(f))] else: return factors def gf_edf_zassenhaus(f, n, p, K): """ Cantor-Zassenhaus: Probabilistic Equal Degree Factorization Given a monic square-free polynomial ``f`` in ``GF(p)[x]`` and an integer ``n``, such that ``n`` divides ``deg(f)``, returns all irreducible factors ``f_1,...,f_d`` of ``f``, each of degree ``n``. EDF procedure gives complete factorization over Galois fields. Consider the square-free polynomial ``f = x**3 + x**2 + x + 1`` in ``GF(5)[x]``. Let's compute its irreducible factors of degree one:: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_edf_zassenhaus >>> gf_edf_zassenhaus([1,1,1,1], 1, 5, ZZ) [[1, 1], [1, 2], [1, 3]] References ========== .. [1] [Gathen99]_ .. [2] [Geddes92]_ """ factors = [f] if gf_degree(f) <= n: return factors N = gf_degree(f) // n if p != 2: b = gf_frobenius_monomial_base(f, p, K) while len(factors) < N: r = gf_random(2*n - 1, p, K) if p == 2: h = r for i in range(0, 2**(n*N - 1)): r = gf_pow_mod(r, 2, f, p, K) h = gf_add(h, r, p, K) g = gf_gcd(f, h, p, K) else: h = _gf_pow_pnm1d2(r, n, f, b, p, K) g = gf_gcd(f, gf_sub_ground(h, K.one, p, K), p, K) if g != [K.one] and g != f: factors = gf_edf_zassenhaus(g, n, p, K) \ + gf_edf_zassenhaus(gf_quo(f, g, p, K), n, p, K) return _sort_factors(factors, multiple=False) def gf_ddf_shoup(f, p, K): """ Kaltofen-Shoup: Deterministic Distinct Degree Factorization Given a monic square-free polynomial ``f`` in ``GF(p)[x]``, computes partial distinct degree factorization ``f_1,...,f_d`` of ``f`` where ``deg(f_i) != deg(f_j)`` for ``i != j``. The result is returned as a list of pairs ``(f_i, e_i)`` where ``deg(f_i) > 0`` and ``e_i > 0`` is an argument to the equal degree factorization routine. This algorithm is an improved version of Zassenhaus algorithm for large ``deg(f)`` and modulus ``p`` (especially for ``deg(f) ~ lg(p)``). Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_ddf_shoup, gf_from_dict >>> f = gf_from_dict({6: ZZ(1), 5: ZZ(-1), 4: ZZ(1), 3: ZZ(1), 1: ZZ(-1)}, 3, ZZ) >>> gf_ddf_shoup(f, 3, ZZ) [([1, 1, 0], 1), ([1, 1, 0, 1, 2], 2)] References ========== .. [1] [Kaltofen98]_ .. [2] [Shoup95]_ .. [3] [Gathen92]_ """ n = gf_degree(f) k = int(_ceil(_sqrt(n//2))) b = gf_frobenius_monomial_base(f, p, K) h = gf_frobenius_map([K.one, K.zero], f, b, p, K) # U[i] = x**(p**i) U = [[K.one, K.zero], h] + [K.zero]*(k - 1) for i in range(2, k + 1): U[i] = gf_frobenius_map(U[i-1], f, b, p, K) h, U = U[k], U[:k] # V[i] = x**(p**(k*(i+1))) V = [h] + [K.zero]*(k - 1) for i in range(1, k): V[i] = gf_compose_mod(V[i - 1], h, f, p, K) factors = [] for i, v in enumerate(V): h, j = [K.one], k - 1 for u in U: g = gf_sub(v, u, p, K) h = gf_mul(h, g, p, K) h = gf_rem(h, f, p, K) g = gf_gcd(f, h, p, K) f = gf_quo(f, g, p, K) for u in reversed(U): h = gf_sub(v, u, p, K) F = gf_gcd(g, h, p, K) if F != [K.one]: factors.append((F, k*(i + 1) - j)) g, j = gf_quo(g, F, p, K), j - 1 if f != [K.one]: factors.append((f, gf_degree(f))) return factors def gf_edf_shoup(f, n, p, K): """ Gathen-Shoup: Probabilistic Equal Degree Factorization Given a monic square-free polynomial ``f`` in ``GF(p)[x]`` and integer ``n`` such that ``n`` divides ``deg(f)``, returns all irreducible factors ``f_1,...,f_d`` of ``f``, each of degree ``n``. This is a complete factorization over Galois fields. This algorithm is an improved version of Zassenhaus algorithm for large ``deg(f)`` and modulus ``p`` (especially for ``deg(f) ~ lg(p)``). Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_edf_shoup >>> gf_edf_shoup(ZZ.map([1, 2837, 2277]), 1, 2917, ZZ) [[1, 852], [1, 1985]] References ========== .. [1] [Shoup91]_ .. [2] [Gathen92]_ """ N, q = gf_degree(f), int(p) if not N: return [] if N <= n: return [f] factors, x = [f], [K.one, K.zero] r = gf_random(N - 1, p, K) if p == 2: h = gf_pow_mod(x, q, f, p, K) H = gf_trace_map(r, h, x, n - 1, f, p, K)[1] h1 = gf_gcd(f, H, p, K) h2 = gf_quo(f, h1, p, K) factors = gf_edf_shoup(h1, n, p, K) \ + gf_edf_shoup(h2, n, p, K) else: b = gf_frobenius_monomial_base(f, p, K) H = _gf_trace_map(r, n, f, b, p, K) h = gf_pow_mod(H, (q - 1)//2, f, p, K) h1 = gf_gcd(f, h, p, K) h2 = gf_gcd(f, gf_sub_ground(h, K.one, p, K), p, K) h3 = gf_quo(f, gf_mul(h1, h2, p, K), p, K) factors = gf_edf_shoup(h1, n, p, K) \ + gf_edf_shoup(h2, n, p, K) \ + gf_edf_shoup(h3, n, p, K) return _sort_factors(factors, multiple=False) def gf_zassenhaus(f, p, K): """ Factor a square-free ``f`` in ``GF(p)[x]`` for medium ``p``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_zassenhaus >>> gf_zassenhaus(ZZ.map([1, 4, 3]), 5, ZZ) [[1, 1], [1, 3]] """ factors = [] for factor, n in gf_ddf_zassenhaus(f, p, K): factors += gf_edf_zassenhaus(factor, n, p, K) return _sort_factors(factors, multiple=False) def gf_shoup(f, p, K): """ Factor a square-free ``f`` in ``GF(p)[x]`` for large ``p``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_shoup >>> gf_shoup(ZZ.map([1, 4, 3]), 5, ZZ) [[1, 1], [1, 3]] """ factors = [] for factor, n in gf_ddf_shoup(f, p, K): factors += gf_edf_shoup(factor, n, p, K) return _sort_factors(factors, multiple=False) _factor_methods = { 'berlekamp': gf_berlekamp, # ``p`` : small 'zassenhaus': gf_zassenhaus, # ``p`` : medium 'shoup': gf_shoup, # ``p`` : large } def gf_factor_sqf(f, p, K, method=None): """ Factor a square-free polynomial ``f`` in ``GF(p)[x]``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_factor_sqf >>> gf_factor_sqf(ZZ.map([3, 2, 4]), 5, ZZ) (3, [[1, 1], [1, 3]]) """ lc, f = gf_monic(f, p, K) if gf_degree(f) < 1: return lc, [] method = method or query('GF_FACTOR_METHOD') if method is not None: factors = _factor_methods[method](f, p, K) else: factors = gf_zassenhaus(f, p, K) return lc, factors def gf_factor(f, p, K): """ Factor (non square-free) polynomials in ``GF(p)[x]``. Given a possibly non square-free polynomial ``f`` in ``GF(p)[x]``, returns its complete factorization into irreducibles:: f_1(x)**e_1 f_2(x)**e_2 ... f_d(x)**e_d where each ``f_i`` is a monic polynomial and ``gcd(f_i, f_j) == 1``, for ``i != j``. The result is given as a tuple consisting of the leading coefficient of ``f`` and a list of factors of ``f`` with their multiplicities. The algorithm proceeds by first computing square-free decomposition of ``f`` and then iteratively factoring each of square-free factors. Consider a non square-free polynomial ``f = (7*x + 1) (x + 2)**2`` in ``GF(11)[x]``. We obtain its factorization into irreducibles as follows:: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.galoistools import gf_factor >>> gf_factor(ZZ.map([5, 2, 7, 2]), 11, ZZ) (5, [([1, 2], 1), ([1, 8], 2)]) We arrived with factorization ``f = 5 (x + 2) (x + 8)**2``. We didn't recover the exact form of the input polynomial because we requested to get monic factors of ``f`` and its leading coefficient separately. Square-free factors of ``f`` can be factored into irreducibles over ``GF(p)`` using three very different methods: Berlekamp efficient for very small values of ``p`` (usually ``p < 25``) Cantor-Zassenhaus efficient on average input and with "typical" ``p`` Shoup-Kaltofen-Gathen efficient with very large inputs and modulus If you want to use a specific factorization method, instead of the default one, set ``GF_FACTOR_METHOD`` with one of ``berlekamp``, ``zassenhaus`` or ``shoup`` values. References ========== .. [1] [Gathen99]_ """ lc, f = gf_monic(f, p, K) if gf_degree(f) < 1: return lc, [] factors = [] for g, n in gf_sqf_list(f, p, K)[1]: for h in gf_factor_sqf(g, p, K)[1]: factors.append((h, n)) return lc, _sort_factors(factors) def gf_value(f, a): """ Value of polynomial 'f' at 'a' in field R. Examples ======== >>> from sympy.polys.galoistools import gf_value >>> gf_value([1, 7, 2, 4], 11) 2204 """ result = 0 for c in f: result *= a result += c return result def linear_congruence(a, b, m): """ Returns the values of x satisfying a*x congruent b mod(m) Here m is positive integer and a, b are natural numbers. This function returns only those values of x which are distinct mod(m). Examples ======== >>> from sympy.polys.galoistools import linear_congruence >>> linear_congruence(3, 12, 15) [4, 9, 14] There are 3 solutions distinct mod(15) since gcd(a, m) = gcd(3, 15) = 3. References ========== .. [1] https://en.wikipedia.org/wiki/Linear_congruence_theorem """ from sympy.polys.polytools import gcdex if a % m == 0: if b % m == 0: return list(range(m)) else: return [] r, _, g = gcdex(a, m) if b % g != 0: return [] return [(r * b // g + t * m // g) % m for t in range(g)] def _raise_mod_power(x, s, p, f): """ Used in gf_csolve to generate solutions of f(x) cong 0 mod(p**(s + 1)) from the solutions of f(x) cong 0 mod(p**s). Examples ======== >>> from sympy.polys.galoistools import _raise_mod_power >>> from sympy.polys.galoistools import csolve_prime These is the solutions of f(x) = x**2 + x + 7 cong 0 mod(3) >>> f = [1, 1, 7] >>> csolve_prime(f, 3) [1] >>> [ i for i in range(3) if not (i**2 + i + 7) % 3] [1] The solutions of f(x) cong 0 mod(9) are constructed from the values returned from _raise_mod_power: >>> x, s, p = 1, 1, 3 >>> V = _raise_mod_power(x, s, p, f) >>> [x + v * p**s for v in V] [1, 4, 7] And these are confirmed with the following: >>> [ i for i in range(3**2) if not (i**2 + i + 7) % 3**2] [1, 4, 7] """ from sympy.polys.domains import ZZ f_f = gf_diff(f, p, ZZ) alpha = gf_value(f_f, x) beta = - gf_value(f, x) // p**s return linear_congruence(alpha, beta, p) def csolve_prime(f, p, e=1): """ Solutions of f(x) congruent 0 mod(p**e). Examples ======== >>> from sympy.polys.galoistools import csolve_prime >>> csolve_prime([1, 1, 7], 3, 1) [1] >>> csolve_prime([1, 1, 7], 3, 2) [1, 4, 7] Solutions [7, 4, 1] (mod 3**2) are generated by ``_raise_mod_power()`` from solution [1] (mod 3). """ from sympy.polys.domains import ZZ X1 = [i for i in range(p) if gf_eval(f, i, p, ZZ) == 0] if e == 1: return X1 X = [] S = list(zip(X1, [1]*len(X1))) while S: x, s = S.pop() if s == e: X.append(x) else: s1 = s + 1 ps = p**s S.extend([(x + v*ps, s1) for v in _raise_mod_power(x, s, p, f)]) return sorted(X) def gf_csolve(f, n): """ To solve f(x) congruent 0 mod(n). n is divided into canonical factors and f(x) cong 0 mod(p**e) will be solved for each factor. Applying the Chinese Remainder Theorem to the results returns the final answers. Examples ======== Solve [1, 1, 7] congruent 0 mod(189): >>> from sympy.polys.galoistools import gf_csolve >>> gf_csolve([1, 1, 7], 189) [13, 49, 76, 112, 139, 175] References ========== .. [1] 'An introduction to the Theory of Numbers' 5th Edition by Ivan Niven, Zuckerman and Montgomery. """ from sympy.polys.domains import ZZ P = factorint(n) X = [csolve_prime(f, p, e) for p, e in P.items()] pools = list(map(tuple, X)) perms = [[]] for pool in pools: perms = [x + [y] for x in perms for y in pool] dist_factors = [pow(p, e) for p, e in P.items()] return sorted([gf_crt(per, dist_factors, ZZ) for per in perms]) sympy-sympy-1.9/sympy/polys/groebnertools.py000066400000000000000000000554531412543434000215240ustar00rootroot00000000000000"""Groebner bases algorithms. """ from sympy.core.symbol import Dummy from sympy.polys.monomials import monomial_mul, monomial_lcm, monomial_divides, term_div from sympy.polys.orderings import lex from sympy.polys.polyerrors import DomainError from sympy.polys.polyconfig import query def groebner(seq, ring, method=None): """ Computes Groebner basis for a set of polynomials in `K[X]`. Wrapper around the (default) improved Buchberger and the other algorithms for computing Groebner bases. The choice of algorithm can be changed via ``method`` argument or :func:`sympy.polys.polyconfig.setup`, where ``method`` can be either ``buchberger`` or ``f5b``. """ if method is None: method = query('groebner') _groebner_methods = { 'buchberger': _buchberger, 'f5b': _f5b, } try: _groebner = _groebner_methods[method] except KeyError: raise ValueError("'%s' is not a valid Groebner bases algorithm (valid are 'buchberger' and 'f5b')" % method) domain, orig = ring.domain, None if not domain.is_Field or not domain.has_assoc_Field: try: orig, ring = ring, ring.clone(domain=domain.get_field()) except DomainError: raise DomainError("can't compute a Groebner basis over %s" % domain) else: seq = [ s.set_ring(ring) for s in seq ] G = _groebner(seq, ring) if orig is not None: G = [ g.clear_denoms()[1].set_ring(orig) for g in G ] return G def _buchberger(f, ring): """ Computes Groebner basis for a set of polynomials in `K[X]`. Given a set of multivariate polynomials `F`, finds another set `G`, such that Ideal `F = Ideal G` and `G` is a reduced Groebner basis. The resulting basis is unique and has monic generators if the ground domains is a field. Otherwise the result is non-unique but Groebner bases over e.g. integers can be computed (if the input polynomials are monic). Groebner bases can be used to choose specific generators for a polynomial ideal. Because these bases are unique you can check for ideal equality by comparing the Groebner bases. To see if one polynomial lies in an ideal, divide by the elements in the base and see if the remainder vanishes. They can also be used to solve systems of polynomial equations as, by choosing lexicographic ordering, you can eliminate one variable at a time, provided that the ideal is zero-dimensional (finite number of solutions). Notes ===== Algorithm used: an improved version of Buchberger's algorithm as presented in T. Becker, V. Weispfenning, Groebner Bases: A Computational Approach to Commutative Algebra, Springer, 1993, page 232. References ========== .. [1] [Bose03]_ .. [2] [Giovini91]_ .. [3] [Ajwa95]_ .. [4] [Cox97]_ """ order = ring.order monomial_mul = ring.monomial_mul monomial_div = ring.monomial_div monomial_lcm = ring.monomial_lcm def select(P): # normal selection strategy # select the pair with minimum LCM(LM(f), LM(g)) pr = min(P, key=lambda pair: order(monomial_lcm(f[pair[0]].LM, f[pair[1]].LM))) return pr def normal(g, J): h = g.rem([ f[j] for j in J ]) if not h: return None else: h = h.monic() if not h in I: I[h] = len(f) f.append(h) return h.LM, I[h] def update(G, B, ih): # update G using the set of critical pairs B and h # [BW] page 230 h = f[ih] mh = h.LM # filter new pairs (h, g), g in G C = G.copy() D = set() while C: # select a pair (h, g) by popping an element from C ig = C.pop() g = f[ig] mg = g.LM LCMhg = monomial_lcm(mh, mg) def lcm_divides(ip): # LCM(LM(h), LM(p)) divides LCM(LM(h), LM(g)) m = monomial_lcm(mh, f[ip].LM) return monomial_div(LCMhg, m) # HT(h) and HT(g) disjoint: mh*mg == LCMhg if monomial_mul(mh, mg) == LCMhg or ( not any(lcm_divides(ipx) for ipx in C) and not any(lcm_divides(pr[1]) for pr in D)): D.add((ih, ig)) E = set() while D: # select h, g from D (h the same as above) ih, ig = D.pop() mg = f[ig].LM LCMhg = monomial_lcm(mh, mg) if not monomial_mul(mh, mg) == LCMhg: E.add((ih, ig)) # filter old pairs B_new = set() while B: # select g1, g2 from B (-> CP) ig1, ig2 = B.pop() mg1 = f[ig1].LM mg2 = f[ig2].LM LCM12 = monomial_lcm(mg1, mg2) # if HT(h) does not divide lcm(HT(g1), HT(g2)) if not monomial_div(LCM12, mh) or \ monomial_lcm(mg1, mh) == LCM12 or \ monomial_lcm(mg2, mh) == LCM12: B_new.add((ig1, ig2)) B_new |= E # filter polynomials G_new = set() while G: ig = G.pop() mg = f[ig].LM if not monomial_div(mg, mh): G_new.add(ig) G_new.add(ih) return G_new, B_new # end of update ################################ if not f: return [] # replace f with a reduced list of initial polynomials; see [BW] page 203 f1 = f[:] while True: f = f1[:] f1 = [] for i in range(len(f)): p = f[i] r = p.rem(f[:i]) if r: f1.append(r.monic()) if f == f1: break I = {} # ip = I[p]; p = f[ip] F = set() # set of indices of polynomials G = set() # set of indices of intermediate would-be Groebner basis CP = set() # set of pairs of indices of critical pairs for i, h in enumerate(f): I[h] = i F.add(i) ##################################### # algorithm GROEBNERNEWS2 in [BW] page 232 while F: # select p with minimum monomial according to the monomial ordering h = min([f[x] for x in F], key=lambda f: order(f.LM)) ih = I[h] F.remove(ih) G, CP = update(G, CP, ih) # count the number of critical pairs which reduce to zero reductions_to_zero = 0 while CP: ig1, ig2 = select(CP) CP.remove((ig1, ig2)) h = spoly(f[ig1], f[ig2], ring) # ordering divisors is on average more efficient [Cox] page 111 G1 = sorted(G, key=lambda g: order(f[g].LM)) ht = normal(h, G1) if ht: G, CP = update(G, CP, ht[1]) else: reductions_to_zero += 1 ###################################### # now G is a Groebner basis; reduce it Gr = set() for ig in G: ht = normal(f[ig], G - {ig}) if ht: Gr.add(ht[1]) Gr = [f[ig] for ig in Gr] # order according to the monomial ordering Gr = sorted(Gr, key=lambda f: order(f.LM), reverse=True) return Gr def spoly(p1, p2, ring): """ Compute LCM(LM(p1), LM(p2))/LM(p1)*p1 - LCM(LM(p1), LM(p2))/LM(p2)*p2 This is the S-poly provided p1 and p2 are monic """ LM1 = p1.LM LM2 = p2.LM LCM12 = ring.monomial_lcm(LM1, LM2) m1 = ring.monomial_div(LCM12, LM1) m2 = ring.monomial_div(LCM12, LM2) s1 = p1.mul_monom(m1) s2 = p2.mul_monom(m2) s = s1 - s2 return s # F5B # convenience functions def Sign(f): return f[0] def Polyn(f): return f[1] def Num(f): return f[2] def sig(monomial, index): return (monomial, index) def lbp(signature, polynomial, number): return (signature, polynomial, number) # signature functions def sig_cmp(u, v, order): """ Compare two signatures by extending the term order to K[X]^n. u < v iff - the index of v is greater than the index of u or - the index of v is equal to the index of u and u[0] < v[0] w.r.t. order u > v otherwise """ if u[1] > v[1]: return -1 if u[1] == v[1]: #if u[0] == v[0]: # return 0 if order(u[0]) < order(v[0]): return -1 return 1 def sig_key(s, order): """ Key for comparing two signatures. s = (m, k), t = (n, l) s < t iff [k > l] or [k == l and m < n] s > t otherwise """ return (-s[1], order(s[0])) def sig_mult(s, m): """ Multiply a signature by a monomial. The product of a signature (m, i) and a monomial n is defined as (m * t, i). """ return sig(monomial_mul(s[0], m), s[1]) # labeled polynomial functions def lbp_sub(f, g): """ Subtract labeled polynomial g from f. The signature and number of the difference of f and g are signature and number of the maximum of f and g, w.r.t. lbp_cmp. """ if sig_cmp(Sign(f), Sign(g), Polyn(f).ring.order) < 0: max_poly = g else: max_poly = f ret = Polyn(f) - Polyn(g) return lbp(Sign(max_poly), ret, Num(max_poly)) def lbp_mul_term(f, cx): """ Multiply a labeled polynomial with a term. The product of a labeled polynomial (s, p, k) by a monomial is defined as (m * s, m * p, k). """ return lbp(sig_mult(Sign(f), cx[0]), Polyn(f).mul_term(cx), Num(f)) def lbp_cmp(f, g): """ Compare two labeled polynomials. f < g iff - Sign(f) < Sign(g) or - Sign(f) == Sign(g) and Num(f) > Num(g) f > g otherwise """ if sig_cmp(Sign(f), Sign(g), Polyn(f).ring.order) == -1: return -1 if Sign(f) == Sign(g): if Num(f) > Num(g): return -1 #if Num(f) == Num(g): # return 0 return 1 def lbp_key(f): """ Key for comparing two labeled polynomials. """ return (sig_key(Sign(f), Polyn(f).ring.order), -Num(f)) # algorithm and helper functions def critical_pair(f, g, ring): """ Compute the critical pair corresponding to two labeled polynomials. A critical pair is a tuple (um, f, vm, g), where um and vm are terms such that um * f - vm * g is the S-polynomial of f and g (so, wlog assume um * f > vm * g). For performance sake, a critical pair is represented as a tuple (Sign(um * f), um, f, Sign(vm * g), vm, g), since um * f creates a new, relatively expensive object in memory, whereas Sign(um * f) and um are lightweight and f (in the tuple) is a reference to an already existing object in memory. """ domain = ring.domain ltf = Polyn(f).LT ltg = Polyn(g).LT lt = (monomial_lcm(ltf[0], ltg[0]), domain.one) um = term_div(lt, ltf, domain) vm = term_div(lt, ltg, domain) # The full information is not needed (now), so only the product # with the leading term is considered: fr = lbp_mul_term(lbp(Sign(f), Polyn(f).leading_term(), Num(f)), um) gr = lbp_mul_term(lbp(Sign(g), Polyn(g).leading_term(), Num(g)), vm) # return in proper order, such that the S-polynomial is just # u_first * f_first - u_second * f_second: if lbp_cmp(fr, gr) == -1: return (Sign(gr), vm, g, Sign(fr), um, f) else: return (Sign(fr), um, f, Sign(gr), vm, g) def cp_cmp(c, d): """ Compare two critical pairs c and d. c < d iff - lbp(c[0], _, Num(c[2]) < lbp(d[0], _, Num(d[2])) (this corresponds to um_c * f_c and um_d * f_d) or - lbp(c[0], _, Num(c[2]) >< lbp(d[0], _, Num(d[2])) and lbp(c[3], _, Num(c[5])) < lbp(d[3], _, Num(d[5])) (this corresponds to vm_c * g_c and vm_d * g_d) c > d otherwise """ zero = Polyn(c[2]).ring.zero c0 = lbp(c[0], zero, Num(c[2])) d0 = lbp(d[0], zero, Num(d[2])) r = lbp_cmp(c0, d0) if r == -1: return -1 if r == 0: c1 = lbp(c[3], zero, Num(c[5])) d1 = lbp(d[3], zero, Num(d[5])) r = lbp_cmp(c1, d1) if r == -1: return -1 #if r == 0: # return 0 return 1 def cp_key(c, ring): """ Key for comparing critical pairs. """ return (lbp_key(lbp(c[0], ring.zero, Num(c[2]))), lbp_key(lbp(c[3], ring.zero, Num(c[5])))) def s_poly(cp): """ Compute the S-polynomial of a critical pair. The S-polynomial of a critical pair cp is cp[1] * cp[2] - cp[4] * cp[5]. """ return lbp_sub(lbp_mul_term(cp[2], cp[1]), lbp_mul_term(cp[5], cp[4])) def is_rewritable_or_comparable(sign, num, B): """ Check if a labeled polynomial is redundant by checking if its signature and number imply rewritability or comparability. (sign, num) is comparable if there exists a labeled polynomial h in B, such that sign[1] (the index) is less than Sign(h)[1] and sign[0] is divisible by the leading monomial of h. (sign, num) is rewritable if there exists a labeled polynomial h in B, such thatsign[1] is equal to Sign(h)[1], num < Num(h) and sign[0] is divisible by Sign(h)[0]. """ for h in B: # comparable if sign[1] < Sign(h)[1]: if monomial_divides(Polyn(h).LM, sign[0]): return True # rewritable if sign[1] == Sign(h)[1]: if num < Num(h): if monomial_divides(Sign(h)[0], sign[0]): return True return False def f5_reduce(f, B): """ F5-reduce a labeled polynomial f by B. Continuously searches for non-zero labeled polynomial h in B, such that the leading term lt_h of h divides the leading term lt_f of f and Sign(lt_h * h) < Sign(f). If such a labeled polynomial h is found, f gets replaced by f - lt_f / lt_h * h. If no such h can be found or f is 0, f is no further F5-reducible and f gets returned. A polynomial that is reducible in the usual sense need not be F5-reducible, e.g.: >>> from sympy.polys.groebnertools import lbp, sig, f5_reduce, Polyn >>> from sympy.polys import ring, QQ, lex >>> R, x,y,z = ring("x,y,z", QQ, lex) >>> f = lbp(sig((1, 1, 1), 4), x, 3) >>> g = lbp(sig((0, 0, 0), 2), x, 2) >>> Polyn(f).rem([Polyn(g)]) 0 >>> f5_reduce(f, [g]) (((1, 1, 1), 4), x, 3) """ order = Polyn(f).ring.order domain = Polyn(f).ring.domain if not Polyn(f): return f while True: g = f for h in B: if Polyn(h): if monomial_divides(Polyn(h).LM, Polyn(f).LM): t = term_div(Polyn(f).LT, Polyn(h).LT, domain) if sig_cmp(sig_mult(Sign(h), t[0]), Sign(f), order) < 0: # The following check need not be done and is in general slower than without. #if not is_rewritable_or_comparable(Sign(gp), Num(gp), B): hp = lbp_mul_term(h, t) f = lbp_sub(f, hp) break if g == f or not Polyn(f): return f def _f5b(F, ring): """ Computes a reduced Groebner basis for the ideal generated by F. f5b is an implementation of the F5B algorithm by Yao Sun and Dingkang Wang. Similarly to Buchberger's algorithm, the algorithm proceeds by computing critical pairs, computing the S-polynomial, reducing it and adjoining the reduced S-polynomial if it is not 0. Unlike Buchberger's algorithm, each polynomial contains additional information, namely a signature and a number. The signature specifies the path of computation (i.e. from which polynomial in the original basis was it derived and how), the number says when the polynomial was added to the basis. With this information it is (often) possible to decide if an S-polynomial will reduce to 0 and can be discarded. Optimizations include: Reducing the generators before computing a Groebner basis, removing redundant critical pairs when a new polynomial enters the basis and sorting the critical pairs and the current basis. Once a Groebner basis has been found, it gets reduced. References ========== .. [1] Yao Sun, Dingkang Wang: "A New Proof for the Correctness of F5 (F5-Like) Algorithm", http://arxiv.org/abs/1004.0084 (specifically v4) .. [2] Thomas Becker, Volker Weispfenning, Groebner bases: A computational approach to commutative algebra, 1993, p. 203, 216 """ order = ring.order # reduce polynomials (like in Mario Pernici's implementation) (Becker, Weispfenning, p. 203) B = F while True: F = B B = [] for i in range(len(F)): p = F[i] r = p.rem(F[:i]) if r: B.append(r) if F == B: break # basis B = [lbp(sig(ring.zero_monom, i + 1), F[i], i + 1) for i in range(len(F))] B.sort(key=lambda f: order(Polyn(f).LM), reverse=True) # critical pairs CP = [critical_pair(B[i], B[j], ring) for i in range(len(B)) for j in range(i + 1, len(B))] CP.sort(key=lambda cp: cp_key(cp, ring), reverse=True) k = len(B) reductions_to_zero = 0 while len(CP): cp = CP.pop() # discard redundant critical pairs: if is_rewritable_or_comparable(cp[0], Num(cp[2]), B): continue if is_rewritable_or_comparable(cp[3], Num(cp[5]), B): continue s = s_poly(cp) p = f5_reduce(s, B) p = lbp(Sign(p), Polyn(p).monic(), k + 1) if Polyn(p): # remove old critical pairs, that become redundant when adding p: indices = [] for i, cp in enumerate(CP): if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p]): indices.append(i) elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p]): indices.append(i) for i in reversed(indices): del CP[i] # only add new critical pairs that are not made redundant by p: for g in B: if Polyn(g): cp = critical_pair(p, g, ring) if is_rewritable_or_comparable(cp[0], Num(cp[2]), [p]): continue elif is_rewritable_or_comparable(cp[3], Num(cp[5]), [p]): continue CP.append(cp) # sort (other sorting methods/selection strategies were not as successful) CP.sort(key=lambda cp: cp_key(cp, ring), reverse=True) # insert p into B: m = Polyn(p).LM if order(m) <= order(Polyn(B[-1]).LM): B.append(p) else: for i, q in enumerate(B): if order(m) > order(Polyn(q).LM): B.insert(i, p) break k += 1 #print(len(B), len(CP), "%d critical pairs removed" % len(indices)) else: reductions_to_zero += 1 # reduce Groebner basis: H = [Polyn(g).monic() for g in B] H = red_groebner(H, ring) return sorted(H, key=lambda f: order(f.LM), reverse=True) def red_groebner(G, ring): """ Compute reduced Groebner basis, from BeckerWeispfenning93, p. 216 Selects a subset of generators, that already generate the ideal and computes a reduced Groebner basis for them. """ def reduction(P): """ The actual reduction algorithm. """ Q = [] for i, p in enumerate(P): h = p.rem(P[:i] + P[i + 1:]) if h: Q.append(h) return [p.monic() for p in Q] F = G H = [] while F: f0 = F.pop() if not any(monomial_divides(f.LM, f0.LM) for f in F + H): H.append(f0) # Becker, Weispfenning, p. 217: H is Groebner basis of the ideal generated by G. return reduction(H) def is_groebner(G, ring): """ Check if G is a Groebner basis. """ for i in range(len(G)): for j in range(i + 1, len(G)): s = spoly(G[i], G[j], ring) s = s.rem(G) if s: return False return True def is_minimal(G, ring): """ Checks if G is a minimal Groebner basis. """ order = ring.order domain = ring.domain G.sort(key=lambda g: order(g.LM)) for i, g in enumerate(G): if g.LC != domain.one: return False for h in G[:i] + G[i + 1:]: if monomial_divides(h.LM, g.LM): return False return True def is_reduced(G, ring): """ Checks if G is a reduced Groebner basis. """ order = ring.order domain = ring.domain G.sort(key=lambda g: order(g.LM)) for i, g in enumerate(G): if g.LC != domain.one: return False for term in g.terms(): for h in G[:i] + G[i + 1:]: if monomial_divides(h.LM, term[0]): return False return True def groebner_lcm(f, g): """ Computes LCM of two polynomials using Groebner bases. The LCM is computed as the unique generator of the intersection of the two ideals generated by `f` and `g`. The approach is to compute a Groebner basis with respect to lexicographic ordering of `t*f` and `(1 - t)*g`, where `t` is an unrelated variable and then filtering out the solution that doesn't contain `t`. References ========== .. [1] [Cox97]_ """ if f.ring != g.ring: raise ValueError("Values should be equal") ring = f.ring domain = ring.domain if not f or not g: return ring.zero if len(f) <= 1 and len(g) <= 1: monom = monomial_lcm(f.LM, g.LM) coeff = domain.lcm(f.LC, g.LC) return ring.term_new(monom, coeff) fc, f = f.primitive() gc, g = g.primitive() lcm = domain.lcm(fc, gc) f_terms = [ ((1,) + monom, coeff) for monom, coeff in f.terms() ] g_terms = [ ((0,) + monom, coeff) for monom, coeff in g.terms() ] \ + [ ((1,) + monom,-coeff) for monom, coeff in g.terms() ] t = Dummy("t") t_ring = ring.clone(symbols=(t,) + ring.symbols, order=lex) F = t_ring.from_terms(f_terms) G = t_ring.from_terms(g_terms) basis = groebner([F, G], t_ring) def is_independent(h, j): return all(not monom[j] for monom in h.monoms()) H = [ h for h in basis if is_independent(h, 0) ] h_terms = [ (monom[1:], coeff*lcm) for monom, coeff in H[0].terms() ] h = ring.from_terms(h_terms) return h def groebner_gcd(f, g): """Computes GCD of two polynomials using Groebner bases. """ if f.ring != g.ring: raise ValueError("Values should be equal") domain = f.ring.domain if not domain.is_Field: fc, f = f.primitive() gc, g = g.primitive() gcd = domain.gcd(fc, gc) H = (f*g).quo([groebner_lcm(f, g)]) if len(H) != 1: raise ValueError("Length should be 1") h = H[0] if not domain.is_Field: return gcd*h else: return h.monic() sympy-sympy-1.9/sympy/polys/heuristicgcd.py000066400000000000000000000072241412543434000213060ustar00rootroot00000000000000"""Heuristic polynomial GCD algorithm (HEUGCD). """ from .polyerrors import HeuristicGCDFailed HEU_GCD_MAX = 6 def heugcd(f, g): """ Heuristic polynomial GCD in ``Z[X]``. Given univariate polynomials ``f`` and ``g`` in ``Z[X]``, returns their GCD and cofactors, i.e. polynomials ``h``, ``cff`` and ``cfg`` such that:: h = gcd(f, g), cff = quo(f, h) and cfg = quo(g, h) The algorithm is purely heuristic which means it may fail to compute the GCD. This will be signaled by raising an exception. In this case you will need to switch to another GCD method. The algorithm computes the polynomial GCD by evaluating polynomials ``f`` and ``g`` at certain points and computing (fast) integer GCD of those evaluations. The polynomial GCD is recovered from the integer image by interpolation. The evaluation process reduces f and g variable by variable into a large integer. The final step is to verify if the interpolated polynomial is the correct GCD. This gives cofactors of the input polynomials as a side effect. Examples ======== >>> from sympy.polys.heuristicgcd import heugcd >>> from sympy.polys import ring, ZZ >>> R, x,y, = ring("x,y", ZZ) >>> f = x**2 + 2*x*y + y**2 >>> g = x**2 + x*y >>> h, cff, cfg = heugcd(f, g) >>> h, cff, cfg (x + y, x + y, x) >>> cff*h == f True >>> cfg*h == g True References ========== .. [1] [Liao95]_ """ assert f.ring == g.ring and f.ring.domain.is_ZZ ring = f.ring x0 = ring.gens[0] domain = ring.domain gcd, f, g = f.extract_ground(g) f_norm = f.max_norm() g_norm = g.max_norm() B = domain(2*min(f_norm, g_norm) + 29) x = max(min(B, 99*domain.sqrt(B)), 2*min(f_norm // abs(f.LC), g_norm // abs(g.LC)) + 4) for i in range(0, HEU_GCD_MAX): ff = f.evaluate(x0, x) gg = g.evaluate(x0, x) if ff and gg: if ring.ngens == 1: h, cff, cfg = domain.cofactors(ff, gg) else: h, cff, cfg = heugcd(ff, gg) h = _gcd_interpolate(h, x, ring) h = h.primitive()[1] cff_, r = f.div(h) if not r: cfg_, r = g.div(h) if not r: h = h.mul_ground(gcd) return h, cff_, cfg_ cff = _gcd_interpolate(cff, x, ring) h, r = f.div(cff) if not r: cfg_, r = g.div(h) if not r: h = h.mul_ground(gcd) return h, cff, cfg_ cfg = _gcd_interpolate(cfg, x, ring) h, r = g.div(cfg) if not r: cff_, r = f.div(h) if not r: h = h.mul_ground(gcd) return h, cff_, cfg x = 73794*x * domain.sqrt(domain.sqrt(x)) // 27011 raise HeuristicGCDFailed('no luck') def _gcd_interpolate(h, x, ring): """Interpolate polynomial GCD from integer GCD. """ f, i = ring.zero, 0 # TODO: don't expose poly repr implementation details if ring.ngens == 1: while h: g = h % x if g > x // 2: g -= x h = (h - g) // x # f += X**i*g if g: f[(i,)] = g i += 1 else: while h: g = h.trunc_ground(x) h = (h - g).quo_ground(x) # f += X**i*g if g: for monom, coeff in g.iterterms(): f[(i,) + monom] = coeff i += 1 if f.LC < 0: return -f else: return f sympy-sympy-1.9/sympy/polys/matrices/000077500000000000000000000000001412543434000200615ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/matrices/__init__.py000066400000000000000000000006031412543434000221710ustar00rootroot00000000000000""" sympy.polys.matrices package. The main export from this package is the DomainMatrix class which is a lower-level implementation of matrices based on the polys Domains. This implementation is typically a lot faster than sympy's standard Matrix class but is a work in progress and is still experimental. """ from .domainmatrix import DomainMatrix __all__ = [ 'DomainMatrix', ] sympy-sympy-1.9/sympy/polys/matrices/ddm.py000066400000000000000000000300371412543434000212020ustar00rootroot00000000000000""" Module for the DDM class. The DDM class is an internal representation used by DomainMatrix. The letters DDM stand for Dense Domain Matrix. A DDM instance represents a matrix using elements from a polynomial Domain (e.g. ZZ, QQ, ...) in a dense-matrix representation. Basic usage: >>> from sympy import ZZ, QQ >>> from sympy.polys.matrices.ddm import DDM >>> A = DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ) >>> A.shape (2, 2) >>> A [[0, 1], [-1, 0]] >>> type(A) >>> A @ A [[-1, 0], [0, -1]] The ddm_* functions are designed to operate on DDM as well as on an ordinary list of lists: >>> from sympy.polys.matrices.dense import ddm_idet >>> ddm_idet(A, QQ) 1 >>> ddm_idet([[0, 1], [-1, 0]], QQ) 1 >>> A [[-1, 0], [0, -1]] Note that ddm_idet modifies the input matrix in-place. It is recommended to use the DDM.det method as a friendlier interface to this instead which takes care of copying the matrix: >>> B = DDM([[ZZ(0), ZZ(1)], [ZZ(-1), ZZ(0)]], (2, 2), ZZ) >>> B.det() 1 Normally DDM would not be used directly and is just part of the internal representation of DomainMatrix which adds further functionality including e.g. unifying domains. The dense format used by DDM is a list of lists of elements e.g. the 2x2 identity matrix is like [[1, 0], [0, 1]]. The DDM class itself is a subclass of list and its list items are plain lists. Elements are accessed as e.g. ddm[i][j] where ddm[i] gives the ith row and ddm[i][j] gets the element in the jth column of that row. Subclassing list makes e.g. iteration and indexing very efficient. We do not override __getitem__ because it would lose that benefit. The core routines are implemented by the ddm_* functions defined in dense.py. Those functions are intended to be able to operate on a raw list-of-lists representation of matrices with most functions operating in-place. The DDM class takes care of copying etc and also stores a Domain object associated with its elements. This makes it possible to implement things like A + B with domain checking and also shape checking so that the list of lists representation is friendlier. """ from .exceptions import DDMBadInputError, DDMShapeError, DDMDomainError from .dense import ( ddm_transpose, ddm_iadd, ddm_isub, ddm_ineg, ddm_imul, ddm_irmul, ddm_imatmul, ddm_irref, ddm_idet, ddm_iinv, ddm_ilu_split, ddm_ilu_solve, ddm_berk, ) class DDM(list): """Dense matrix based on polys domain elements This is a list subclass and is a wrapper for a list of lists that supports basic matrix arithmetic +, -, *, **. """ fmt = 'dense' def __init__(self, rowslist, shape, domain): super().__init__(rowslist) self.shape = self.rows, self.cols = m, n = shape self.domain = domain if not (len(self) == m and all(len(row) == n for row in self)): raise DDMBadInputError("Inconsistent row-list/shape") def getitem(self, i, j): return self[i][j] def extract_slice(self, slice1, slice2): ddm = [row[slice2] for row in self[slice1]] rows = len(ddm) cols = len(ddm[0]) if ddm else len(range(self.shape[1])[slice2]) return DDM(ddm, (rows, cols), self.domain) def extract(self, rows, cols): ddm = [] for i in rows: rowi = self[i] ddm.append([rowi[j] for j in cols]) return DDM(ddm, (len(rows), len(cols)), self.domain) def to_list(self): return list(self) def to_list_flat(self): flat = [] for row in self: flat.extend(row) return flat def to_dok(self): return {(i, j): e for i, row in enumerate(self) for j, e in enumerate(row)} def to_ddm(self): return self def to_sdm(self): return SDM.from_list(self, self.shape, self.domain) def convert_to(self, K): Kold = self.domain if K == Kold: return self.copy() rows = ([K.convert_from(e, Kold) for e in row] for row in self) return DDM(rows, self.shape, K) def __str__(self): rowsstr = ['[%s]' % ', '.join(map(str, row)) for row in self] return '[%s]' % ', '.join(rowsstr) def __repr__(self): cls = type(self).__name__ rows = list.__repr__(self) return '%s(%s, %s, %s)' % (cls, rows, self.shape, self.domain) def __eq__(self, other): if not isinstance(other, DDM): return False return (super().__eq__(other) and self.domain == other.domain) def __ne__(self, other): return not self.__eq__(other) @classmethod def zeros(cls, shape, domain): z = domain.zero m, n = shape rowslist = ([z] * n for _ in range(m)) return DDM(rowslist, shape, domain) @classmethod def ones(cls, shape, domain): one = domain.one m, n = shape rowlist = ([one] * n for _ in range(m)) return DDM(rowlist, shape, domain) @classmethod def eye(cls, size, domain): one = domain.one ddm = cls.zeros((size, size), domain) for i in range(size): ddm[i][i] = one return ddm def copy(self): copyrows = (row[:] for row in self) return DDM(copyrows, self.shape, self.domain) def transpose(self): rows, cols = self.shape if rows: ddmT = ddm_transpose(self) else: ddmT = [[]] * cols return DDM(ddmT, (cols, rows), self.domain) def __add__(a, b): if not isinstance(b, DDM): return NotImplemented return a.add(b) def __sub__(a, b): if not isinstance(b, DDM): return NotImplemented return a.sub(b) def __neg__(a): return a.neg() def __mul__(a, b): if b in a.domain: return a.mul(b) else: return NotImplemented def __rmul__(a, b): if b in a.domain: return a.mul(b) else: return NotImplemented def __matmul__(a, b): if isinstance(b, DDM): return a.matmul(b) else: return NotImplemented @classmethod def _check(cls, a, op, b, ashape, bshape): if a.domain != b.domain: msg = "Domain mismatch: %s %s %s" % (a.domain, op, b.domain) raise DDMDomainError(msg) if ashape != bshape: msg = "Shape mismatch: %s %s %s" % (a.shape, op, b.shape) raise DDMShapeError(msg) def add(a, b): """a + b""" a._check(a, '+', b, a.shape, b.shape) c = a.copy() ddm_iadd(c, b) return c def sub(a, b): """a - b""" a._check(a, '-', b, a.shape, b.shape) c = a.copy() ddm_isub(c, b) return c def neg(a): """-a""" b = a.copy() ddm_ineg(b) return b def mul(a, b): c = a.copy() ddm_imul(c, b) return c def rmul(a, b): c = a.copy() ddm_irmul(c, b) return c def matmul(a, b): """a @ b (matrix product)""" m, o = a.shape o2, n = b.shape a._check(a, '*', b, o, o2) c = a.zeros((m, n), a.domain) ddm_imatmul(c, a, b) return c def mul_elementwise(a, b): assert a.shape == b.shape assert a.domain == b.domain c = [[aij * bij for aij, bij in zip(ai, bi)] for ai, bi in zip(a, b)] return DDM(c, a.shape, a.domain) def hstack(A, *B): """Horizontally stacks :py:class:`~.DDM` matrices. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import DDM >>> A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DDM([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) >>> A.hstack(B) [[1, 2, 5, 6], [3, 4, 7, 8]] >>> C = DDM([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) >>> A.hstack(B, C) [[1, 2, 5, 6, 9, 10], [3, 4, 7, 8, 11, 12]] """ Anew = list(A.copy()) rows, cols = A.shape domain = A.domain for Bk in B: Bkrows, Bkcols = Bk.shape assert Bkrows == rows assert Bk.domain == domain cols += Bkcols for i, Bki in enumerate(Bk): Anew[i].extend(Bki) return DDM(Anew, (rows, cols), A.domain) def vstack(A, *B): """Vertically stacks :py:class:`~.DDM` matrices. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import DDM >>> A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DDM([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) >>> A.vstack(B) [[1, 2], [3, 4], [5, 6], [7, 8]] >>> C = DDM([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) >>> A.vstack(B, C) [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]] """ Anew = list(A.copy()) rows, cols = A.shape domain = A.domain for Bk in B: Bkrows, Bkcols = Bk.shape assert Bkcols == cols assert Bk.domain == domain rows += Bkrows Anew.extend(Bk.copy()) return DDM(Anew, (rows, cols), A.domain) def applyfunc(self, func, domain): elements = (list(map(func, row)) for row in self) return DDM(elements, self.shape, domain) def scc(a): """Strongly connected components of a square matrix *a*. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import DDM >>> A = DDM([[ZZ(1), ZZ(0)], [ZZ(0), ZZ(1)]], (2, 2), ZZ) >>> A.scc() [[0], [1]] See also ======== sympy.polys.matrices.domainmatrix.DomainMatrix.scc """ return a.to_sdm().scc() def rref(a): """Reduced-row echelon form of a and list of pivots""" b = a.copy() K = a.domain partial_pivot = K.is_RealField or K.is_ComplexField pivots = ddm_irref(b, _partial_pivot=partial_pivot) return b, pivots def nullspace(a): rref, pivots = a.rref() rows, cols = a.shape domain = a.domain basis = [] nonpivots = [] for i in range(cols): if i in pivots: continue nonpivots.append(i) vec = [domain.one if i == j else domain.zero for j in range(cols)] for ii, jj in enumerate(pivots): vec[jj] -= rref[ii][i] basis.append(vec) return DDM(basis, (len(basis), cols), domain), nonpivots def particular(a): return a.to_sdm().particular().to_ddm() def det(a): """Determinant of a""" m, n = a.shape if m != n: raise DDMShapeError("Determinant of non-square matrix") b = a.copy() K = b.domain deta = ddm_idet(b, K) return deta def inv(a): """Inverse of a""" m, n = a.shape if m != n: raise DDMShapeError("Determinant of non-square matrix") ainv = a.copy() K = a.domain ddm_iinv(ainv, a, K) return ainv def lu(a): """L, U decomposition of a""" m, n = a.shape K = a.domain U = a.copy() L = a.eye(m, K) swaps = ddm_ilu_split(L, U, K) return L, U, swaps def lu_solve(a, b): """x where a*x = b""" m, n = a.shape m2, o = b.shape a._check(a, 'lu_solve', b, m, m2) L, U, swaps = a.lu() x = a.zeros((n, o), a.domain) ddm_ilu_solve(x, L, U, swaps, b) return x def charpoly(a): """Coefficients of characteristic polynomial of a""" K = a.domain m, n = a.shape if m != n: raise DDMShapeError("Charpoly of non-square matrix") vec = ddm_berk(a, K) coeffs = [vec[i][0] for i in range(n+1)] return coeffs from .sdm import SDM sympy-sympy-1.9/sympy/polys/matrices/dense.py000066400000000000000000000200771412543434000215370ustar00rootroot00000000000000""" Module for the ddm_* routines for operating on a matrix in list of lists matrix representation. These routines are used internally by the DDM class which also provides a friendlier interface for them. The idea here is to implement core matrix routines in a way that can be applied to any simple list representation without the need to use any particular matrix class. For example we can compute the RREF of a matrix like: >>> from sympy.polys.matrices.dense import ddm_irref >>> M = [[1, 2, 3], [4, 5, 6]] >>> pivots = ddm_irref(M) >>> M [[1.0, 0.0, -1.0], [0, 1.0, 2.0]] These are lower-level routines that work mostly in place.The routines at this level should not need to know what the domain of the elements is but should ideally document what operations they will use and what functions they need to be provided with. The next-level up is the DDM class which uses these routines but wraps them up with an interface that handles copying etc and keeps track of the Domain of the elements of the matrix: >>> from sympy.polys.domains import QQ >>> from sympy.polys.matrices.ddm import DDM >>> M = DDM([[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]], (2, 3), QQ) >>> M [[1, 2, 3], [4, 5, 6]] >>> Mrref, pivots = M.rref() >>> Mrref [[1, 0, -1], [0, 1, 2]] """ from operator import mul from .exceptions import ( DDMShapeError, NonInvertibleMatrixError, NonSquareMatrixError, ) def ddm_transpose(a): """matrix transpose""" aT = list(map(list, zip(*a))) return aT def ddm_iadd(a, b): """a += b""" for ai, bi in zip(a, b): for j, bij in enumerate(bi): ai[j] += bij def ddm_isub(a, b): """a -= b""" for ai, bi in zip(a, b): for j, bij in enumerate(bi): ai[j] -= bij def ddm_ineg(a): """a <-- -a""" for ai in a: for j, aij in enumerate(ai): ai[j] = -aij def ddm_imul(a, b): for ai in a: for j, aij in enumerate(ai): ai[j] = aij * b def ddm_irmul(a, b): for ai in a: for j, aij in enumerate(ai): ai[j] = b * aij def ddm_imatmul(a, b, c): """a += b @ c""" cT = list(zip(*c)) for bi, ai in zip(b, a): for j, cTj in enumerate(cT): ai[j] = sum(map(mul, bi, cTj), ai[j]) def ddm_irref(a, _partial_pivot=False): """a <-- rref(a)""" # a is (m x n) m = len(a) if not m: return [] n = len(a[0]) i = 0 pivots = [] for j in range(n): # Proper pivoting should be used for all domains for performance # reasons but it is only strictly needed for RR and CC (and possibly # other domains like RR(x)). This path is used by DDM.rref() if the # domain is RR or CC. It uses partial (row) pivoting based on the # absolute value of the pivot candidates. if _partial_pivot: ip = max(range(i, m), key=lambda ip: abs(a[ip][j])) a[i], a[ip] = a[ip], a[i] # pivot aij = a[i][j] # zero-pivot if not aij: for ip in range(i+1, m): aij = a[ip][j] # row-swap if aij: a[i], a[ip] = a[ip], a[i] break else: # next column continue # normalise row ai = a[i] aijinv = aij**-1 for l in range(j, n): ai[l] *= aijinv # ai[j] = one # eliminate above and below to the right for k, ak in enumerate(a): if k == i or not ak[j]: continue akj = ak[j] ak[j] -= akj # ak[j] = zero for l in range(j+1, n): ak[l] -= akj * ai[l] # next row pivots.append(j) i += 1 # no more rows? if i >= m: break return pivots def ddm_idet(a, K): """a <-- echelon(a); return det""" # Bareiss algorithm # https://www.math.usm.edu/perry/Research/Thesis_DRL.pdf # a is (m x n) m = len(a) if not m: return K.one n = len(a[0]) exquo = K.exquo # uf keeps track of the sign change from row swaps uf = K.one for k in range(n-1): if not a[k][k]: for i in range(k+1, n): if a[i][k]: a[k], a[i] = a[i], a[k] uf = -uf break else: return K.zero akkm1 = a[k-1][k-1] if k else K.one for i in range(k+1, n): for j in range(k+1, n): a[i][j] = exquo(a[i][j]*a[k][k] - a[i][k]*a[k][j], akkm1) return uf * a[-1][-1] def ddm_iinv(ainv, a, K): if not K.is_Field: raise ValueError('Not a field') # a is (m x n) m = len(a) if not m: return n = len(a[0]) if m != n: raise NonSquareMatrixError eye = [[K.one if i==j else K.zero for j in range(n)] for i in range(n)] Aaug = [row + eyerow for row, eyerow in zip(a, eye)] pivots = ddm_irref(Aaug) if pivots != list(range(n)): raise NonInvertibleMatrixError('Matrix det == 0; not invertible.') ainv[:] = [row[n:] for row in Aaug] def ddm_ilu_split(L, U, K): """L, U <-- LU(U)""" m = len(U) if not m: return [] n = len(U[0]) swaps = ddm_ilu(U) zeros = [K.zero] * min(m, n) for i in range(1, m): j = min(i, n) L[i][:j] = U[i][:j] U[i][:j] = zeros[:j] return swaps def ddm_ilu(a): """a <-- LU(a)""" m = len(a) if not m: return [] n = len(a[0]) swaps = [] for i in range(min(m, n)): if not a[i][i]: for ip in range(i+1, m): if a[ip][i]: swaps.append((i, ip)) a[i], a[ip] = a[ip], a[i] break else: # M = Matrix([[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 2]]) continue for j in range(i+1, m): l_ji = a[j][i] / a[i][i] a[j][i] = l_ji for k in range(i+1, n): a[j][k] -= l_ji * a[i][k] return swaps def ddm_ilu_solve(x, L, U, swaps, b): """x <-- solve(L*U*x = swaps(b))""" m = len(U) if not m: return n = len(U[0]) m2 = len(b) if not m2: raise DDMShapeError("Shape mismtch") o = len(b[0]) if m != m2: raise DDMShapeError("Shape mismtch") if m < n: raise NotImplementedError("Underdetermined") if swaps: b = [row[:] for row in b] for i1, i2 in swaps: b[i1], b[i2] = b[i2], b[i1] # solve Ly = b y = [[None] * o for _ in range(m)] for k in range(o): for i in range(m): rhs = b[i][k] for j in range(i): rhs -= L[i][j] * y[j][k] y[i][k] = rhs if m > n: for i in range(n, m): for j in range(o): if y[i][j]: raise NonInvertibleMatrixError # Solve Ux = y for k in range(o): for i in reversed(range(n)): if not U[i][i]: raise NonInvertibleMatrixError rhs = y[i][k] for j in range(i+1, n): rhs -= U[i][j] * x[j][k] x[i][k] = rhs / U[i][i] def ddm_berk(M, K): m = len(M) if not m: return [[K.one]] n = len(M[0]) if m != n: raise DDMShapeError("Not square") if n == 1: return [[K.one], [-M[0][0]]] a = M[0][0] R = [M[0][1:]] C = [[row[0]] for row in M[1:]] A = [row[1:] for row in M[1:]] q = ddm_berk(A, K) T = [[K.zero] * n for _ in range(n+1)] for i in range(n): T[i][i] = K.one T[i+1][i] = -a for i in range(2, n+1): if i == 2: AnC = C else: C = AnC AnC = [[K.zero] for row in C] ddm_imatmul(AnC, A, C) RAnC = [[K.zero]] ddm_imatmul(RAnC, R, AnC) for j in range(0, n+1-i): T[i+j][j] = -RAnC[0][0] qout = [[K.zero] for _ in range(n+1)] ddm_imatmul(qout, T, q) return qout sympy-sympy-1.9/sympy/polys/matrices/domainmatrix.py000066400000000000000000001167161412543434000231430ustar00rootroot00000000000000""" Module for the DomainMatrix class. A DomainMatrix represents a matrix with elements that are in a particular Domain. Each DomainMatrix internally wraps a DDM which is used for the lower-level operations. The idea is that the DomainMatrix class provides the convenience routines for converting between Expr and the poly domains as well as unifying matrices with different domains. """ from functools import reduce from sympy.core.sympify import _sympify from ..constructor import construct_domain from .exceptions import (NonSquareMatrixError, ShapeError, DDMShapeError, DDMDomainError, DDMFormatError, DDMBadInputError) from .ddm import DDM from .sdm import SDM from .domainscalar import DomainScalar from sympy.polys.domains import ZZ, EXRAW class DomainMatrix: r""" Associate Matrix with :py:class:`~.Domain` Explanation =========== DomainMatrix uses :py:class:`~.Domain` for its internal representation which makes it more faster for many common operations than current sympy Matrix class, but this advantage makes it not entirely compatible with Matrix. DomainMatrix could be found analogous to numpy arrays with "dtype". In the DomainMatrix, each matrix has a domain such as :ref:`ZZ` or :ref:`QQ(a)`. Examples ======== Creating a DomainMatrix from the existing Matrix class: >>> from sympy import Matrix >>> from sympy.polys.matrices import DomainMatrix >>> Matrix1 = Matrix([ ... [1, 2], ... [3, 4]]) >>> A = DomainMatrix.from_Matrix(Matrix1) >>> A DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ) Driectly forming a DomainMatrix: >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> A DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) See Also ======== DDM SDM Domain Poly """ def __new__(cls, rows, shape, domain, *, fmt=None): """ Creates a :py:class:`~.DomainMatrix`. Parameters ========== rows : Represents elements of DomainMatrix as list of lists shape : Represents dimension of DomainMatrix domain : Represents :py:class:`~.Domain` of DomainMatrix Raises ====== TypeError If any of rows, shape and domain are not provided """ if isinstance(rows, (DDM, SDM)): raise TypeError("Use from_rep to initialise from SDM/DDM") elif isinstance(rows, list): rep = DDM(rows, shape, domain) elif isinstance(rows, dict): rep = SDM(rows, shape, domain) else: msg = "Input should be list-of-lists or dict-of-dicts" raise TypeError(msg) if fmt is not None: if fmt == 'sparse': rep = rep.to_sdm() elif fmt == 'dense': rep = rep.to_ddm() else: raise ValueError("fmt should be 'sparse' or 'dense'") return cls.from_rep(rep) def __getnewargs__(self): rep = self.rep if isinstance(rep, DDM): arg = list(rep) elif isinstance(rep, SDM): arg = dict(rep) else: raise RuntimeError # pragma: no cover return arg, self.shape, self.domain def __getitem__(self, key): i, j = key m, n = self.shape if not (isinstance(i, slice) or isinstance(j, slice)): return DomainScalar(self.rep.getitem(i, j), self.domain) if not isinstance(i, slice): if not -m <= i < m: raise IndexError("Row index out of range") i = i % m i = slice(i, i+1) if not isinstance(j, slice): if not -n <= j < n: raise IndexError("Column index out of range") j = j % n j = slice(j, j+1) return self.from_rep(self.rep.extract_slice(i, j)) def getitem_sympy(self, i, j): return self.domain.to_sympy(self.rep.getitem(i, j)) def extract(self, rowslist, colslist): return self.from_rep(self.rep.extract(rowslist, colslist)) def __setitem__(self, key, value): i, j = key if not self.domain.of_type(value): raise TypeError if isinstance(i, int) and isinstance(j, int): self.rep.setitem(i, j, value) else: raise NotImplementedError @classmethod def from_rep(cls, rep): """Create a new DomainMatrix efficiently from DDM/SDM. Examples ======== Create a :py:class:`~.DomainMatrix` with an dense internal representation as :py:class:`~.DDM`: >>> from sympy.polys.domains import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> from sympy.polys.matrices.ddm import DDM >>> drep = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> dM = DomainMatrix.from_rep(drep) >>> dM DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ) Create a :py:class:`~.DomainMatrix` with a sparse internal representation as :py:class:`~.SDM`: >>> from sympy.polys.matrices import DomainMatrix >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import ZZ >>> drep = SDM({0:{1:ZZ(1)},1:{0:ZZ(2)}}, (2, 2), ZZ) >>> dM = DomainMatrix.from_rep(drep) >>> dM DomainMatrix({0: {1: 1}, 1: {0: 2}}, (2, 2), ZZ) Parameters ========== rep: SDM or DDM The internal sparse or dense representation of the matrix. Returns ======= DomainMatrix A :py:class:`~.DomainMatrix` wrapping *rep*. Notes ===== This takes ownership of rep as its internal representation. If rep is being mutated elsewhere then a copy should be provided to ``from_rep``. Only minimal verification or checking is done on *rep* as this is supposed to be an efficient internal routine. """ if not isinstance(rep, (DDM, SDM)): raise TypeError("rep should be of type DDM or SDM") self = super().__new__(cls) self.rep = rep self.shape = rep.shape self.domain = rep.domain return self @classmethod def from_list_sympy(cls, nrows, ncols, rows, **kwargs): r""" Convert a list of lists of Expr into a DomainMatrix using construct_domain Parameters ========== nrows: number of rows ncols: number of columns rows: list of lists Returns ======= DomainMatrix containing elements of rows Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy.abc import x, y, z >>> A = DomainMatrix.from_list_sympy(1, 3, [[x, y, z]]) >>> A DomainMatrix([[x, y, z]], (1, 3), ZZ[x,y,z]) See Also ======== sympy.polys.constructor.construct_domain, from_dict_sympy """ assert len(rows) == nrows assert all(len(row) == ncols for row in rows) items_sympy = [_sympify(item) for row in rows for item in row] domain, items_domain = cls.get_domain(items_sympy, **kwargs) domain_rows = [[items_domain[ncols*r + c] for c in range(ncols)] for r in range(nrows)] return DomainMatrix(domain_rows, (nrows, ncols), domain) @classmethod def from_dict_sympy(cls, nrows, ncols, elemsdict, **kwargs): """ Parameters ========== nrows: number of rows ncols: number of cols elemsdict: dict of dicts containing non-zero elements of the DomainMatrix Returns ======= DomainMatrix containing elements of elemsdict Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy.abc import x,y,z >>> elemsdict = {0: {0:x}, 1:{1: y}, 2: {2: z}} >>> A = DomainMatrix.from_dict_sympy(3, 3, elemsdict) >>> A DomainMatrix({0: {0: x}, 1: {1: y}, 2: {2: z}}, (3, 3), ZZ[x,y,z]) See Also ======== from_list_sympy """ if not all(0 <= r < nrows for r in elemsdict): raise DDMBadInputError("Row out of range") if not all(0 <= c < ncols for row in elemsdict.values() for c in row): raise DDMBadInputError("Column out of range") items_sympy = [_sympify(item) for row in elemsdict.values() for item in row.values()] domain, items_domain = cls.get_domain(items_sympy, **kwargs) idx = 0 items_dict = {} for i, row in elemsdict.items(): items_dict[i] = {} for j in row: items_dict[i][j] = items_domain[idx] idx += 1 return DomainMatrix(items_dict, (nrows, ncols), domain) @classmethod def from_Matrix(cls, M, fmt='sparse',**kwargs): r""" Convert Matrix to DomainMatrix Parameters ========== M: Matrix Returns ======= Returns DomainMatrix with identical elements as M Examples ======== >>> from sympy import Matrix >>> from sympy.polys.matrices import DomainMatrix >>> M = Matrix([ ... [1.0, 3.4], ... [2.4, 1]]) >>> A = DomainMatrix.from_Matrix(M) >>> A DomainMatrix({0: {0: 1.0, 1: 3.4}, 1: {0: 2.4, 1: 1.0}}, (2, 2), RR) We can keep internal representation as ddm using fmt='dense' >>> from sympy import Matrix, QQ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix.from_Matrix(Matrix([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]]), fmt='dense') >>> A.rep [[1/2, 3/4], [0, 0]] See Also ======== Matrix """ if fmt == 'dense': return cls.from_list_sympy(*M.shape, M.tolist(), **kwargs) return cls.from_dict_sympy(*M.shape, M.todod(), **kwargs) @classmethod def get_domain(cls, items_sympy, **kwargs): K, items_K = construct_domain(items_sympy, **kwargs) return K, items_K def copy(self): return self.from_rep(self.rep.copy()) def convert_to(self, K): r""" Change the domain of DomainMatrix to desired domain or field Parameters ========== K : Represents the desired domain or field Returns ======= DomainMatrix DomainMatrix with the desired domain or field Examples ======== >>> from sympy import ZZ, ZZ_I >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> A.convert_to(ZZ_I) DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ_I) """ return self.from_rep(self.rep.convert_to(K)) def to_sympy(self): return self.convert_to(EXRAW) def to_field(self): r""" Returns a DomainMatrix with the appropriate field Returns ======= DomainMatrix DomainMatrix with the appropriate field Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> A.to_field() DomainMatrix([[1, 2], [3, 4]], (2, 2), QQ) """ K = self.domain.get_field() return self.convert_to(K) def to_sparse(self): """ Return a sparse DomainMatrix representation of *self*. Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy import QQ >>> A = DomainMatrix([[1, 0],[0, 2]], (2, 2), QQ) >>> A.rep [[1, 0], [0, 2]] >>> B = A.to_sparse() >>> B.rep {0: {0: 1}, 1: {1: 2}} """ if self.rep.fmt == 'sparse': return self return self.from_rep(SDM.from_ddm(self.rep)) def to_dense(self): """ Return a dense DomainMatrix representation of *self*. Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy import QQ >>> A = DomainMatrix({0: {0: 1}, 1: {1: 2}}, (2, 2), QQ) >>> A.rep {0: {0: 1}, 1: {1: 2}} >>> B = A.to_dense() >>> B.rep [[1, 0], [0, 2]] """ if self.rep.fmt == 'dense': return self return self.from_rep(SDM.to_ddm(self.rep)) @classmethod def _unify_domain(cls, *matrices): """Convert matrices to a common domain""" domains = {matrix.domain for matrix in matrices} if len(domains) == 1: return matrices domain = reduce(lambda x, y: x.unify(y), domains) return tuple(matrix.convert_to(domain) for matrix in matrices) @classmethod def _unify_fmt(cls, *matrices, fmt=None): """Convert matrices to the same format. If all matrices have the same format, then return unmodified. Otherwise convert both to the preferred format given as *fmt* which should be 'dense' or 'sparse'. """ formats = {matrix.rep.fmt for matrix in matrices} if len(formats) == 1: return matrices if fmt == 'sparse': return tuple(matrix.to_sparse() for matrix in matrices) elif fmt == 'dense': return tuple(matrix.to_dense() for matrix in matrices) else: raise ValueError("fmt should be 'sparse' or 'dense'") def unify(self, *others, fmt=None): """ Unifies the domains and the format of self and other matrices. Parameters ========== others : DomainMatrix fmt: string 'dense', 'sparse' or `None` (default) The preferred format to convert to if self and other are not already in the same format. If `None` or not specified then no conversion if performed. Returns ======= Tuple[DomainMatrix] Matrices with unified domain and format Examples ======== Unify the domain of DomainMatrix that have different domains: >>> from sympy import ZZ, QQ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ) >>> B = DomainMatrix([[QQ(1, 2), QQ(2)]], (1, 2), QQ) >>> Aq, Bq = A.unify(B) >>> Aq DomainMatrix([[1, 2]], (1, 2), QQ) >>> Bq DomainMatrix([[1/2, 2]], (1, 2), QQ) Unify the format (dense or sparse): >>> A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ) >>> B = DomainMatrix({0:{0: ZZ(1)}}, (2, 2), ZZ) >>> B.rep {0: {0: 1}} >>> A2, B2 = A.unify(B, fmt='dense') >>> B2.rep [[1, 0], [0, 0]] See Also ======== convert_to, to_dense, to_sparse """ matrices = (self,) + others matrices = DomainMatrix._unify_domain(*matrices) if fmt is not None: matrices = DomainMatrix._unify_fmt(*matrices, fmt=fmt) return matrices def to_Matrix(self): r""" Convert DomainMatrix to Matrix Returns ======= Matrix MutableDenseMatrix for the DomainMatrix Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> A.to_Matrix() Matrix([ [1, 2], [3, 4]]) See Also ======== from_Matrix """ from sympy.matrices.dense import MutableDenseMatrix elemlist = self.rep.to_list() elements_sympy = [self.domain.to_sympy(e) for row in elemlist for e in row] return MutableDenseMatrix(*self.shape, elements_sympy) def to_list(self): return self.rep.to_list() def to_list_flat(self): return self.rep.to_list_flat() def to_dok(self): return self.rep.to_dok() def __repr__(self): return 'DomainMatrix(%s, %r, %r)' % (str(self.rep), self.shape, self.domain) def transpose(self): """Matrix transpose of ``self``""" return self.from_rep(self.rep.transpose()) def flat(self): rows, cols = self.shape return [self[i,j].element for i in range(rows) for j in range(cols)] @property def is_zero_matrix(self): return all(self[i, j].element == self.domain.zero for i in range(self.shape[0]) for j in range(self.shape[1])) def hstack(A, *B): r"""Horizontally stack the given matrices. Parameters ========== B: DomainMatrix Matrices to stack horizontally. Returns ======= DomainMatrix DomainMatrix by stacking horizontally. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) >>> A.hstack(B) DomainMatrix([[1, 2, 5, 6], [3, 4, 7, 8]], (2, 4), ZZ) >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) >>> A.hstack(B, C) DomainMatrix([[1, 2, 5, 6, 9, 10], [3, 4, 7, 8, 11, 12]], (2, 6), ZZ) See Also ======== unify """ A, *B = A.unify(*B, fmt='dense') return DomainMatrix.from_rep(A.rep.hstack(*(Bk.rep for Bk in B))) def vstack(A, *B): r"""Vertically stack the given matrices. Parameters ========== B: DomainMatrix Matrices to stack vertically. Returns ======= DomainMatrix DomainMatrix by stacking vertically. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) >>> A.vstack(B) DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8]], (4, 2), ZZ) >>> C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) >>> A.vstack(B, C) DomainMatrix([[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]], (6, 2), ZZ) See Also ======== unify """ A, *B = A.unify(*B, fmt='dense') return DomainMatrix.from_rep(A.rep.vstack(*(Bk.rep for Bk in B))) def applyfunc(self, func, domain=None): if domain is None: domain = self.domain return self.from_rep(self.rep.applyfunc(func, domain)) def __add__(A, B): if not isinstance(B, DomainMatrix): return NotImplemented A, B = A.unify(B, fmt='dense') return A.add(B) def __sub__(A, B): if not isinstance(B, DomainMatrix): return NotImplemented A, B = A.unify(B, fmt='dense') return A.sub(B) def __neg__(A): return A.neg() def __mul__(A, B): """A * B""" if isinstance(B, DomainMatrix): A, B = A.unify(B, fmt='dense') return A.matmul(B) elif B in A.domain: return A.scalarmul(B) elif isinstance(B, DomainScalar): A, B = A.unify(B) return A.scalarmul(B.element) else: return NotImplemented def __rmul__(A, B): if B in A.domain: return A.rscalarmul(B) elif isinstance(B, DomainScalar): A, B = A.unify(B) return A.rscalarmul(B.element) else: return NotImplemented def __pow__(A, n): """A ** n""" if not isinstance(n, int): return NotImplemented return A.pow(n) def _check(a, op, b, ashape, bshape): if a.domain != b.domain: msg = "Domain mismatch: %s %s %s" % (a.domain, op, b.domain) raise DDMDomainError(msg) if ashape != bshape: msg = "Shape mismatch: %s %s %s" % (a.shape, op, b.shape) raise DDMShapeError(msg) if a.rep.fmt != b.rep.fmt: msg = "Format mismatch: %s %s %s" % (a.rep.fmt, op, b.rep.fmt) raise DDMFormatError(msg) def add(A, B): r""" Adds two DomainMatrix matrices of the same Domain Parameters ========== A, B: DomainMatrix matrices to add Returns ======= DomainMatrix DomainMatrix after Addition Raises ====== ShapeError If the dimensions of the two DomainMatrix are not equal ValueError If the domain of the two DomainMatrix are not same Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DomainMatrix([ ... [ZZ(4), ZZ(3)], ... [ZZ(2), ZZ(1)]], (2, 2), ZZ) >>> A.add(B) DomainMatrix([[5, 5], [5, 5]], (2, 2), ZZ) See Also ======== sub, matmul """ A._check('+', B, A.shape, B.shape) return A.from_rep(A.rep.add(B.rep)) def sub(A, B): r""" Subtracts two DomainMatrix matrices of the same Domain Parameters ========== A, B: DomainMatrix matrices to substract Returns ======= DomainMatrix DomainMatrix after Substraction Raises ====== ShapeError If the dimensions of the two DomainMatrix are not equal ValueError If the domain of the two DomainMatrix are not same Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DomainMatrix([ ... [ZZ(4), ZZ(3)], ... [ZZ(2), ZZ(1)]], (2, 2), ZZ) >>> A.sub(B) DomainMatrix([[-3, -1], [1, 3]], (2, 2), ZZ) See Also ======== add, matmul """ A._check('-', B, A.shape, B.shape) return A.from_rep(A.rep.sub(B.rep)) def neg(A): r""" Returns the negative of DomainMatrix Parameters ========== A : Represents a DomainMatrix Returns ======= DomainMatrix DomainMatrix after Negation Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> A.neg() DomainMatrix([[-1, -2], [-3, -4]], (2, 2), ZZ) """ return A.from_rep(A.rep.neg()) def mul(A, b): r""" Performs term by term multiplication for the second DomainMatrix w.r.t first DomainMatrix. Returns a DomainMatrix whose rows are list of DomainMatrix matrices created after term by term multiplication. Parameters ========== A, B: DomainMatrix matrices to multiply term-wise Returns ======= DomainMatrix DomainMatrix after term by term multiplication Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DomainMatrix([ ... [ZZ(1), ZZ(1)], ... [ZZ(0), ZZ(1)]], (2, 2), ZZ) >>> A.mul(B) DomainMatrix([[DomainMatrix([[1, 1], [0, 1]], (2, 2), ZZ), DomainMatrix([[2, 2], [0, 2]], (2, 2), ZZ)], [DomainMatrix([[3, 3], [0, 3]], (2, 2), ZZ), DomainMatrix([[4, 4], [0, 4]], (2, 2), ZZ)]], (2, 2), ZZ) See Also ======== matmul """ return A.from_rep(A.rep.mul(b)) def rmul(A, b): return A.from_rep(A.rep.rmul(b)) def matmul(A, B): r""" Performs matrix multiplication of two DomainMatrix matrices Parameters ========== A, B: DomainMatrix to multiply Returns ======= DomainMatrix DomainMatrix after multiplication Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DomainMatrix([ ... [ZZ(1), ZZ(1)], ... [ZZ(0), ZZ(1)]], (2, 2), ZZ) >>> A.matmul(B) DomainMatrix([[1, 3], [3, 7]], (2, 2), ZZ) See Also ======== mul, pow, add, sub """ A._check('*', B, A.shape[1], B.shape[0]) return A.from_rep(A.rep.matmul(B.rep)) def _scalarmul(A, lamda, reverse): if lamda == A.domain.zero: return DomainMatrix.zeros(A.shape, A.domain) elif lamda == A.domain.one: return A.copy() elif reverse: return A.rmul(lamda) else: return A.mul(lamda) def scalarmul(A, lamda): return A._scalarmul(lamda, reverse=False) def rscalarmul(A, lamda): return A._scalarmul(lamda, reverse=True) def mul_elementwise(A, B): assert A.domain == B.domain return A.from_rep(A.rep.mul_elementwise(B.rep)) def __truediv__(A, lamda): """ Method for Scalar Divison""" if isinstance(lamda, int): lamda = DomainScalar(ZZ(lamda), ZZ) if not isinstance(lamda, DomainScalar): return NotImplemented A, lamda = A.to_field().unify(lamda) if lamda.element == lamda.domain.zero: raise ZeroDivisionError if lamda.element == lamda.domain.one: return A.to_field() return A.mul(1 / lamda.element) def pow(A, n): r""" Computes A**n Parameters ========== A : DomainMatrix n : exponent for A Returns ======= DomainMatrix DomainMatrix on computing A**n Raises ====== NotImplementedError if n is negative. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(1)], ... [ZZ(0), ZZ(1)]], (2, 2), ZZ) >>> A.pow(2) DomainMatrix([[1, 2], [0, 1]], (2, 2), ZZ) See Also ======== matmul """ nrows, ncols = A.shape if nrows != ncols: raise NonSquareMatrixError('Power of a nonsquare matrix') if n < 0: raise NotImplementedError('Negative powers') elif n == 0: return A.eye(nrows, A.domain) elif n == 1: return A elif n % 2 == 1: return A * A**(n - 1) else: sqrtAn = A ** (n // 2) return sqrtAn * sqrtAn def scc(self): """Compute the strongly connected components of a DomainMatrix Explanation =========== A square matrix can be considered as the adjacency matrix for a directed graph where the row and column indices are the vertices. In this graph if there is an edge from vertex ``i`` to vertex ``j`` if ``M[i, j]`` is nonzero. This routine computes the strongly connected components of that graph which are subsets of the rows and columns that are connected by some nonzero element of the matrix. The strongly connected components are useful because many operations such as the determinant can be computed by working with the submatrices corresponding to each component. Examples ======== Find the strongly connected components of a matrix: >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> M = DomainMatrix([[ZZ(1), ZZ(0), ZZ(2)], ... [ZZ(0), ZZ(3), ZZ(0)], ... [ZZ(4), ZZ(6), ZZ(5)]], (3, 3), ZZ) >>> M.scc() [[1], [0, 2]] Compute the determinant from the components: >>> MM = M.to_Matrix() >>> MM Matrix([ [1, 0, 2], [0, 3, 0], [4, 6, 5]]) >>> MM[[1], [1]] Matrix([[3]]) >>> MM[[0, 2], [0, 2]] Matrix([ [1, 2], [4, 5]]) >>> MM.det() -9 >>> MM[[1], [1]].det() * MM[[0, 2], [0, 2]].det() -9 The components are given in reverse topological order and represent a permutation of the rows and columns that will bring the matrix into block lower-triangular form: >>> MM[[1, 0, 2], [1, 0, 2]] Matrix([ [3, 0, 0], [0, 1, 2], [6, 4, 5]]) Returns ======= List of lists of integers Each list represents a strongly connected component. See also ======== sympy.matrices.matrices.MatrixBase.strongly_connected_components sympy.utilities.iterables.strongly_connected_components """ rows, cols = self.shape assert rows == cols return self.rep.scc() def rref(self): r""" Returns reduced-row echelon form and list of pivots for the DomainMatrix Returns ======= (DomainMatrix, list) reduced-row echelon form and list of pivots for the DomainMatrix Raises ====== ValueError If the domain of DomainMatrix not a Field Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [QQ(2), QQ(-1), QQ(0)], ... [QQ(-1), QQ(2), QQ(-1)], ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ) >>> rref_matrix, rref_pivots = A.rref() >>> rref_matrix DomainMatrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], (3, 3), QQ) >>> rref_pivots (0, 1, 2) See Also ======== convert_to, lu """ if not self.domain.is_Field: raise ValueError('Not a field') rref_ddm, pivots = self.rep.rref() return self.from_rep(rref_ddm), tuple(pivots) def nullspace(self): r""" Returns the Null Space for the DomainMatrix Returns ======= DomainMatrix Null Space of the DomainMatrix Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [QQ(1), QQ(-1)], ... [QQ(2), QQ(-2)]], (2, 2), QQ) >>> A.nullspace() DomainMatrix([[1, 1]], (1, 2), QQ) """ if not self.domain.is_Field: raise ValueError('Not a field') return self.from_rep(self.rep.nullspace()[0]) def inv(self): r""" Finds the inverse of the DomainMatrix if exists Returns ======= DomainMatrix DomainMatrix after inverse Raises ====== ValueError If the domain of DomainMatrix not a Field NonSquareMatrixError If the DomainMatrix is not a not Square DomainMatrix Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [QQ(2), QQ(-1), QQ(0)], ... [QQ(-1), QQ(2), QQ(-1)], ... [QQ(0), QQ(0), QQ(2)]], (3, 3), QQ) >>> A.inv() DomainMatrix([[2/3, 1/3, 1/6], [1/3, 2/3, 1/3], [0, 0, 1/2]], (3, 3), QQ) See Also ======== neg """ if not self.domain.is_Field: raise ValueError('Not a field') m, n = self.shape if m != n: raise NonSquareMatrixError inv = self.rep.inv() return self.from_rep(inv) def det(self): r""" Returns the determinant of a Square DomainMatrix Returns ======= S.Complexes determinant of Square DomainMatrix Raises ====== ValueError If the domain of DomainMatrix not a Field Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> A.det() -2 """ m, n = self.shape if m != n: raise NonSquareMatrixError return self.rep.det() def lu(self): r""" Returns Lower and Upper decomposition of the DomainMatrix Returns ======= (L, U, exchange) L, U are Lower and Upper decomposition of the DomainMatrix, exchange is the list of indices of rows exchanged in the decomposition. Raises ====== ValueError If the domain of DomainMatrix not a Field Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [QQ(1), QQ(-1)], ... [QQ(2), QQ(-2)]], (2, 2), QQ) >>> A.lu() (DomainMatrix([[1, 0], [2, 1]], (2, 2), QQ), DomainMatrix([[1, -1], [0, 0]], (2, 2), QQ), []) See Also ======== lu_solve """ if not self.domain.is_Field: raise ValueError('Not a field') L, U, swaps = self.rep.lu() return self.from_rep(L), self.from_rep(U), swaps def lu_solve(self, rhs): r""" Solver for DomainMatrix x in the A*x = B Parameters ========== rhs : DomainMatrix B Returns ======= DomainMatrix x in A*x = B Raises ====== ShapeError If the DomainMatrix A and rhs have different number of rows ValueError If the domain of DomainMatrix A not a Field Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [QQ(1), QQ(2)], ... [QQ(3), QQ(4)]], (2, 2), QQ) >>> B = DomainMatrix([ ... [QQ(1), QQ(1)], ... [QQ(0), QQ(1)]], (2, 2), QQ) >>> A.lu_solve(B) DomainMatrix([[-2, -1], [3/2, 1]], (2, 2), QQ) See Also ======== lu """ if self.shape[0] != rhs.shape[0]: raise ShapeError("Shape") if not self.domain.is_Field: raise ValueError('Not a field') sol = self.rep.lu_solve(rhs.rep) return self.from_rep(sol) def _solve(A, b): # XXX: Not sure about this method or its signature. It is just created # because it is needed by the holonomic module. if A.shape[0] != b.shape[0]: raise ShapeError("Shape") if A.domain != b.domain or not A.domain.is_Field: raise ValueError('Not a field') Aaug = A.hstack(b) Arref, pivots = Aaug.rref() particular = Arref.from_rep(Arref.rep.particular()) nullspace_rep, nonpivots = Arref[:,:-1].rep.nullspace() nullspace = Arref.from_rep(nullspace_rep) return particular, nullspace def charpoly(self): r""" Returns the coefficients of the characteristic polynomial of the DomainMatrix. These elements will be domain elements. The domain of the elements will be same as domain of the DomainMatrix. Returns ======= list coefficients of the characteristic polynomial Raises ====== NonSquareMatrixError If the DomainMatrix is not a not Square DomainMatrix Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> A.charpoly() [1, -5, -2] """ m, n = self.shape if m != n: raise NonSquareMatrixError("not square") return self.rep.charpoly() @classmethod def eye(cls, shape, domain): r""" Return identity matrix of size n Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy import QQ >>> DomainMatrix.eye(3, QQ) DomainMatrix({0: {0: 1}, 1: {1: 1}, 2: {2: 1}}, (3, 3), QQ) """ if isinstance(shape, int): shape = (shape, shape) return cls.from_rep(SDM.eye(shape, domain)) @classmethod def diag(cls, diagonal, domain, shape=None): r""" Return diagonal matrix with entries from ``diagonal``. Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy import ZZ >>> DomainMatrix.diag([ZZ(5), ZZ(6)], ZZ) DomainMatrix({0: {0: 5}, 1: {1: 6}}, (2, 2), ZZ) """ if shape is None: N = len(diagonal) shape = (N, N) return cls.from_rep(SDM.diag(diagonal, domain, shape)) @classmethod def zeros(cls, shape, domain, *, fmt='sparse'): """Returns a zero DomainMatrix of size shape, belonging to the specified domain Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy import QQ >>> DomainMatrix.zeros((2, 3), QQ) DomainMatrix({}, (2, 3), QQ) """ return cls.from_rep(SDM.zeros(shape, domain)) @classmethod def ones(cls, shape, domain): """Returns a zero DomainMatrix of size shape, belonging to the specified domain Examples ======== >>> from sympy.polys.matrices import DomainMatrix >>> from sympy import QQ >>> DomainMatrix.ones((2,3), QQ) DomainMatrix([[1, 1, 1], [1, 1, 1]], (2, 3), QQ) """ return cls.from_rep(DDM.ones(shape, domain)) def __eq__(A, B): r""" Checks for two DomainMatrix matrices to be equal or not Parameters ========== A, B: DomainMatrix to check equality Returns ======= Boolean True for equal, else False Raises ====== NotImplementedError If B is not a DomainMatrix Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> A = DomainMatrix([ ... [ZZ(1), ZZ(2)], ... [ZZ(3), ZZ(4)]], (2, 2), ZZ) >>> B = DomainMatrix([ ... [ZZ(1), ZZ(1)], ... [ZZ(0), ZZ(1)]], (2, 2), ZZ) >>> A.__eq__(A) True >>> A.__eq__(B) False """ if not isinstance(A, type(B)): return NotImplemented return A.domain == B.domain and A.rep == B.rep def unify_eq(A, B): if A.shape != B.shape: return False if A.domain != B.domain: A, B = A.unify(B) return A == B sympy-sympy-1.9/sympy/polys/matrices/domainscalar.py000066400000000000000000000070731412543434000230770ustar00rootroot00000000000000""" Module for the DomainScalar class. A DomainScalar represents an element which is in a particular Domain. The idea is that the DomainScalar class provides the convenience routines for unifying elements with different domains. It assists in Scalar Multiplication and getitem for DomainMatrix. """ from ..constructor import construct_domain from sympy.polys.domains import Domain, ZZ class DomainScalar: r""" docstring """ def __new__(cls, element, domain): if not isinstance(domain, Domain): raise TypeError("domain should be of type Domain") if not domain.of_type(element): raise TypeError("element %s should be in domain %s" % (element, domain)) return cls.new(element, domain) @classmethod def new(cls, element, domain): obj = super().__new__(cls) obj.element = element obj.domain = domain return obj def __repr__(self): return repr(self.element) @classmethod def from_sympy(cls, expr): [domain, [element]] = construct_domain([expr]) return cls.new(element, domain) def to_sympy(self): return self.domain.to_sympy(self.element) def to_domain(self, domain): element = domain.convert_from(self.element, self.domain) return self.new(element, domain) def convert_to(self, domain): return self.to_domain(domain) def unify(self, other): domain = self.domain.unify(other.domain) return self.to_domain(domain), other.to_domain(domain) def __add__(self, other): if not isinstance(other, DomainScalar): return NotImplemented self, other = self.unify(other) return self.new(self.element + other.element, self.domain) def __sub__(self, other): if not isinstance(other, DomainScalar): return NotImplemented self, other = self.unify(other) return self.new(self.element - other.element, self.domain) def __mul__(self, other): if not isinstance(other, DomainScalar): if isinstance(other, int): other = DomainScalar(ZZ(other), ZZ) else: return NotImplemented self, other = self.unify(other) return self.new(self.element * other.element, self.domain) def __floordiv__(self, other): if not isinstance(other, DomainScalar): return NotImplemented self, other = self.unify(other) return self.new(self.domain.quo(self.element, other.element), self.domain) def __mod__(self, other): if not isinstance(other, DomainScalar): return NotImplemented self, other = self.unify(other) return self.new(self.domain.rem(self.element, other.element), self.domain) def __divmod__(self, other): if not isinstance(other, DomainScalar): return NotImplemented self, other = self.unify(other) q, r = self.domain.div(self.element, other.element) return (self.new(q, self.domain), self.new(r, self.domain)) def __pow__(self, n): if not isinstance(n, int): return NotImplemented return self.new(self.element**n, self.domain) def __pos__(self): return self.new(+self.element, self.domain) def __eq__(self, other): if not isinstance(other, DomainScalar): return NotImplemented return self.element == other.element and self.domain == other.domain def is_zero(self): return self.element == self.domain.zero def is_one(self): return self.element == self.domain.one sympy-sympy-1.9/sympy/polys/matrices/eigen.py000066400000000000000000000056471412543434000215360ustar00rootroot00000000000000""" Routines for computing eigenvectors with DomainMatrix. """ from sympy.core.symbol import Dummy from ..agca.extensions import FiniteExtension from ..factortools import dup_factor_list from ..polyroots import roots from ..polytools import Poly from ..rootoftools import CRootOf from .domainmatrix import DomainMatrix def dom_eigenvects(A, l=Dummy('lambda')): charpoly = A.charpoly() rows, cols = A.shape domain = A.domain _, factors = dup_factor_list(charpoly, domain) rational_eigenvects = [] algebraic_eigenvects = [] for base, exp in factors: if len(base) == 2: field = domain eigenval = -base[1] / base[0] EE_items = [ [eigenval if i == j else field.zero for j in range(cols)] for i in range(rows)] EE = DomainMatrix(EE_items, (rows, cols), field) basis = (A - EE).nullspace() rational_eigenvects.append((field, eigenval, exp, basis)) else: minpoly = Poly.from_list(base, l, domain=domain) field = FiniteExtension(minpoly) eigenval = field(l) AA_items = [ [Poly.from_list([item], l, domain=domain).rep for item in row] for row in A.rep.to_ddm()] AA_items = [[field(item) for item in row] for row in AA_items] AA = DomainMatrix(AA_items, (rows, cols), field) EE_items = [ [eigenval if i == j else field.zero for j in range(cols)] for i in range(rows)] EE = DomainMatrix(EE_items, (rows, cols), field) basis = (AA - EE).nullspace() algebraic_eigenvects.append((field, minpoly, exp, basis)) return rational_eigenvects, algebraic_eigenvects def dom_eigenvects_to_sympy( rational_eigenvects, algebraic_eigenvects, Matrix, **kwargs ): result = [] for field, eigenvalue, multiplicity, eigenvects in rational_eigenvects: eigenvects = eigenvects.rep.to_ddm() eigenvalue = field.to_sympy(eigenvalue) new_eigenvects = [ Matrix([field.to_sympy(x) for x in vect]) for vect in eigenvects] result.append((eigenvalue, multiplicity, new_eigenvects)) for field, minpoly, multiplicity, eigenvects in algebraic_eigenvects: eigenvects = eigenvects.rep.to_ddm() l = minpoly.gens[0] eigenvects = [[field.to_sympy(x) for x in vect] for vect in eigenvects] degree = minpoly.degree() minpoly = minpoly.as_expr() eigenvals = roots(minpoly, l, **kwargs) if len(eigenvals) != degree: eigenvals = [CRootOf(minpoly, l, idx) for idx in range(degree)] for eigenvalue in eigenvals: new_eigenvects = [ Matrix([x.subs(l, eigenvalue) for x in vect]) for vect in eigenvects] result.append((eigenvalue, multiplicity, new_eigenvects)) return result sympy-sympy-1.9/sympy/polys/matrices/exceptions.py000066400000000000000000000017201412543434000226140ustar00rootroot00000000000000""" Module to define exceptions to be used in sympy.polys.matrices modules and classes. Ideally all exceptions raised in these modules would be defined and documented here and not e.g. imported from matrices. Also ideally generic exceptions like ValueError/TypeError would not be raised anywhere. """ from sympy.matrices.common import (NonInvertibleMatrixError, NonSquareMatrixError, ShapeError) class DDMError(Exception): """Base class for errors raised by DDM""" pass class DDMBadInputError(DDMError): """list of lists is inconsistent with shape""" pass class DDMDomainError(DDMError): """domains do not match""" pass class DDMShapeError(DDMError): """shapes are inconsistent""" pass class DDMFormatError(DDMError): """mixed dense/sparse not supported""" pass __all__ = [ 'DDMError', 'DDMShapeError', 'DDMDomainError', 'DDMFormatError', 'NonSquareMatrixError', 'NonInvertibleMatrixError', 'ShapeError', ] sympy-sympy-1.9/sympy/polys/matrices/linsolve.py000066400000000000000000000151351412543434000222730ustar00rootroot00000000000000# # sympy.polys.matrices.linsolve module # # This module defines the _linsolve function which is the internal workhorse # used by linsolve. This computes the solution of a system of linear equations # using the SDM sparse matrix implementation in sympy.polys.matrices.sdm. This # is a replacement for solve_lin_sys in sympy.polys.solvers which is # inefficient for large sparse systems due to the use of a PolyRing with many # generators: # # https://github.com/sympy/sympy/issues/20857 # # The implementation of _linsolve here handles: # # - Extracting the coefficients from the Expr/Eq input equations. # - Constructing a domain and converting the coefficients to # that domain. # - Using the SDM.rref, SDM.nullspace etc methods to generate the full # solution working with arithmetic only in the domain of the coefficients. # # The routines here are particularly designed to be efficient for large sparse # systems of linear equations although as well as dense systems. It is # possible that for some small dense systems solve_lin_sys which uses the # dense matrix implementation DDM will be more efficient. With smaller systems # though the bulk of the time is spent just preprocessing the inputs and the # relative time spent in rref is too small to be noticeable. # from collections import defaultdict from sympy.core.add import Add from sympy.core.mul import Mul from sympy.core.singleton import S from sympy.polys.constructor import construct_domain from sympy.polys.solvers import PolyNonlinearError from .sdm import ( SDM, sdm_irref, sdm_particular_from_rref, sdm_nullspace_from_rref ) def _linsolve(eqs, syms): """Solve a linear system of equations. Examples ======== Solve a linear system with a unique solution: >>> from sympy import symbols, Eq >>> from sympy.polys.matrices.linsolve import _linsolve >>> x, y = symbols('x, y') >>> eqs = [Eq(x + y, 1), Eq(x - y, 2)] >>> _linsolve(eqs, [x, y]) {x: 3/2, y: -1/2} In the case of underdetermined systems the solution will be expressed in terms of the unknown symbols that are unconstrained: >>> _linsolve([Eq(x + y, 0)], [x, y]) {x: -y, y: y} """ # Number of unknowns (columns in the non-augmented matrix) nsyms = len(syms) # Convert to sparse augmented matrix (len(eqs) x (nsyms+1)) eqsdict, rhs = _linear_eq_to_dict(eqs, syms) Aaug = sympy_dict_to_dm(eqsdict, rhs, syms) K = Aaug.domain # sdm_irref has issues with float matrices. This uses the ddm_rref() # function. When sdm_rref() can handle float matrices reasonably this # should be removed... if K.is_RealField or K.is_ComplexField: Aaug = Aaug.to_ddm().rref()[0].to_sdm() # Compute reduced-row echelon form (RREF) Arref, pivots, nzcols = sdm_irref(Aaug) # No solution: if pivots and pivots[-1] == nsyms: return None # Particular solution for non-homogeneous system: P = sdm_particular_from_rref(Arref, nsyms+1, pivots) # Nullspace - general solution to homogeneous system # Note: using nsyms not nsyms+1 to ignore last column V, nonpivots = sdm_nullspace_from_rref(Arref, K.one, nsyms, pivots, nzcols) # Collect together terms from particular and nullspace: sol = defaultdict(list) for i, v in P.items(): sol[syms[i]].append(K.to_sympy(v)) for npi, Vi in zip(nonpivots, V): sym = syms[npi] for i, v in Vi.items(): sol[syms[i]].append(sym * K.to_sympy(v)) # Use a single call to Add for each term: sol = {s: Add(*terms) for s, terms in sol.items()} # Fill in the zeros: zero = S.Zero for s in set(syms) - set(sol): sol[s] = zero # All done! return sol def sympy_dict_to_dm(eqs_coeffs, eqs_rhs, syms): """Convert a system of dict equations to a sparse augmented matrix""" elems = set(eqs_rhs).union(*(e.values() for e in eqs_coeffs)) K, elems_K = construct_domain(elems, field=True, extension=True) elem_map = dict(zip(elems, elems_K)) neqs = len(eqs_coeffs) nsyms = len(syms) sym2index = dict(zip(syms, range(nsyms))) eqsdict = [] for eq, rhs in zip(eqs_coeffs, eqs_rhs): eqdict = {sym2index[s]: elem_map[c] for s, c in eq.items()} if rhs: eqdict[nsyms] = - elem_map[rhs] if eqdict: eqsdict.append(eqdict) sdm_aug = SDM(enumerate(eqsdict), (neqs, nsyms+1), K) return sdm_aug def _expand_eqs_deprecated(eqs): """Use expand to cancel nonlinear terms. This approach matches previous behaviour of linsolve but should be deprecated. """ def expand_eq(eq): if eq.is_Equality: eq = eq.lhs - eq.rhs return eq.expand() return [expand_eq(eq) for eq in eqs] def _linear_eq_to_dict(eqs, syms): """Convert a system Expr/Eq equations into dict form""" try: return _linear_eq_to_dict_inner(eqs, syms) except PolyNonlinearError: # XXX: This should be deprecated: eqs = _expand_eqs_deprecated(eqs) return _linear_eq_to_dict_inner(eqs, syms) def _linear_eq_to_dict_inner(eqs, syms): """Convert a system Expr/Eq equations into dict form""" syms = set(syms) eqsdict, eqs_rhs = [], [] for eq in eqs: rhs, eqdict = _lin_eq2dict(eq, syms) eqsdict.append(eqdict) eqs_rhs.append(rhs) return eqsdict, eqs_rhs def _lin_eq2dict(a, symset): """Efficiently convert a linear equation to a dict of coefficients""" if a in symset: return S.Zero, {a: S.One} elif a.is_Add: terms_list = defaultdict(list) coeff_list = [] for ai in a.args: ci, ti = _lin_eq2dict(ai, symset) coeff_list.append(ci) for mij, cij in ti.items(): terms_list[mij].append(cij) coeff = Add(*coeff_list) terms = {sym: Add(*coeffs) for sym, coeffs in terms_list.items()} return coeff, terms elif a.is_Mul: terms = terms_coeff = None coeff_list = [] for ai in a.args: ci, ti = _lin_eq2dict(ai, symset) if not ti: coeff_list.append(ci) elif terms is None: terms = ti terms_coeff = ci else: raise PolyNonlinearError coeff = Mul(*coeff_list) if terms is None: return coeff, {} else: terms = {sym: coeff * c for sym, c in terms.items()} return coeff * terms_coeff, terms elif a.is_Equality: return _lin_eq2dict(a.lhs - a.rhs, symset) elif not a.free_symbols & symset: return a, {} else: raise PolyNonlinearError sympy-sympy-1.9/sympy/polys/matrices/normalforms.py000066400000000000000000000106161412543434000227760ustar00rootroot00000000000000'''Functions returning normal forms of matrices''' from .domainmatrix import DomainMatrix def smith_normal_form(m): ''' Return the Smith Normal Form of a matrix `m` over the ring `domain`. This will only work if the ring is a principal ideal domain. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices import DomainMatrix >>> from sympy.polys.matrices.normalforms import smith_normal_form >>> m = DomainMatrix([[ZZ(12), ZZ(6), ZZ(4)], ... [ZZ(3), ZZ(9), ZZ(6)], ... [ZZ(2), ZZ(16), ZZ(14)]], (3, 3), ZZ) >>> print(smith_normal_form(m).to_Matrix()) Matrix([[1, 0, 0], [0, 10, 0], [0, 0, -30]]) ''' invs = invariant_factors(m) smf = DomainMatrix.diag(invs, m.domain, m.shape) return smf def invariant_factors(m): ''' Return the tuple of abelian invariants for a matrix `m` (as in the Smith-Normal form) References ========== [1] https://en.wikipedia.org/wiki/Smith_normal_form#Algorithm [2] http://sierra.nmsu.edu/morandi/notes/SmithNormalForm.pdf ''' domain = m.domain if not domain.is_PID: msg = "The matrix entries must be over a principal ideal domain" raise ValueError(msg) if 0 in m.shape: return () rows, cols = shape = m.shape m = list(m.to_dense().rep) def add_rows(m, i, j, a, b, c, d): # replace m[i, :] by a*m[i, :] + b*m[j, :] # and m[j, :] by c*m[i, :] + d*m[j, :] for k in range(cols): e = m[i][k] m[i][k] = a*e + b*m[j][k] m[j][k] = c*e + d*m[j][k] def add_columns(m, i, j, a, b, c, d): # replace m[:, i] by a*m[:, i] + b*m[:, j] # and m[:, j] by c*m[:, i] + d*m[:, j] for k in range(rows): e = m[k][i] m[k][i] = a*e + b*m[k][j] m[k][j] = c*e + d*m[k][j] def clear_column(m): # make m[1:, 0] zero by row and column operations if m[0][0] == 0: return m # pragma: nocover pivot = m[0][0] for j in range(1, rows): if m[j][0] == 0: continue d, r = domain.div(m[j][0], pivot) if r == 0: add_rows(m, 0, j, 1, 0, -d, 1) else: a, b, g = domain.gcdex(pivot, m[j][0]) d_0 = domain.div(m[j][0], g)[0] d_j = domain.div(pivot, g)[0] add_rows(m, 0, j, a, b, d_0, -d_j) pivot = g return m def clear_row(m): # make m[0, 1:] zero by row and column operations if m[0][0] == 0: return m # pragma: nocover pivot = m[0][0] for j in range(1, cols): if m[0][j] == 0: continue d, r = domain.div(m[0][j], pivot) if r == 0: add_columns(m, 0, j, 1, 0, -d, 1) else: a, b, g = domain.gcdex(pivot, m[0][j]) d_0 = domain.div(m[0][j], g)[0] d_j = domain.div(pivot, g)[0] add_columns(m, 0, j, a, b, d_0, -d_j) pivot = g return m # permute the rows and columns until m[0,0] is non-zero if possible ind = [i for i in range(rows) if m[i][0] != 0] if ind and ind[0] != 0: m[0], m[ind[0]] = m[ind[0]], m[0] else: ind = [j for j in range(cols) if m[0][j] != 0] if ind and ind[0] != 0: for row in m: row[0], row[ind[0]] = row[ind[0]], row[0] # make the first row and column except m[0,0] zero while (any([m[0][i] != 0 for i in range(1,cols)]) or any([m[i][0] != 0 for i in range(1,rows)])): m = clear_column(m) m = clear_row(m) if 1 in shape: invs = () else: lower_right = DomainMatrix([r[1:] for r in m[1:]], (rows-1, cols-1), domain) invs = invariant_factors(lower_right) if m[0][0]: result = [m[0][0]] result.extend(invs) # in case m[0] doesn't divide the invariants of the rest of the matrix for i in range(len(result)-1): if result[i] and domain.div(result[i+1], result[i])[1] != 0: g = domain.gcd(result[i+1], result[i]) result[i+1] = domain.div(result[i], g)[0]*result[i+1] result[i] = g else: break else: result = invs + (m[0][0],) return tuple(result) sympy-sympy-1.9/sympy/polys/matrices/sdm.py000066400000000000000000001035171412543434000212250ustar00rootroot00000000000000""" Module for the SDM class. """ from operator import add, neg, pos, sub, mul from collections import defaultdict from sympy.utilities.iterables import _strongly_connected_components from .exceptions import DDMBadInputError, DDMDomainError, DDMShapeError from .ddm import DDM class SDM(dict): r"""Sparse matrix based on polys domain elements This is a dict subclass and is a wrapper for a dict of dicts that supports basic matrix arithmetic +, -, *, **. In order to create a new :py:class:`~.SDM`, a dict of dicts mapping non-zero elements to their corresponding row and column in the matrix is needed. We also need to specify the shape and :py:class:`~.Domain` of our :py:class:`~.SDM` object. We declare a 2x2 :py:class:`~.SDM` matrix belonging to QQ domain as shown below. The 2x2 Matrix in the example is .. math:: A = \left[\begin{array}{ccc} 0 & \frac{1}{2} \\ 0 & 0 \end{array} \right] >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> elemsdict = {0:{1:QQ(1, 2)}} >>> A = SDM(elemsdict, (2, 2), QQ) >>> A {0: {1: 1/2}} We can manipulate :py:class:`~.SDM` the same way as a Matrix class >>> from sympy import ZZ >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) >>> B = SDM({0:{0: ZZ(3)}, 1:{1:ZZ(4)}}, (2, 2), ZZ) >>> A + B {0: {0: 3, 1: 2}, 1: {0: 1, 1: 4}} Multiplication >>> A*B {0: {1: 8}, 1: {0: 3}} >>> A*ZZ(2) {0: {1: 4}, 1: {0: 2}} """ fmt = 'sparse' def __init__(self, elemsdict, shape, domain): super().__init__(elemsdict) self.shape = self.rows, self.cols = m, n = shape self.domain = domain if not all(0 <= r < m for r in self): raise DDMBadInputError("Row out of range") if not all(0 <= c < n for row in self.values() for c in row): raise DDMBadInputError("Column out of range") def getitem(self, i, j): try: return self[i][j] except KeyError: m, n = self.shape if -m <= i < m and -n <= j < n: try: return self[i % m][j % n] except KeyError: return self.domain.zero else: raise IndexError("index out of range") def setitem(self, i, j, value): m, n = self.shape if not (-m <= i < m and -n <= j < n): raise IndexError("index out of range") i, j = i % m, j % n if value: try: self[i][j] = value except KeyError: self[i] = {j: value} else: rowi = self.get(i, None) if rowi is not None: try: del rowi[j] except KeyError: pass else: if not rowi: del self[i] def extract_slice(self, slice1, slice2): m, n = self.shape ri = range(m)[slice1] ci = range(n)[slice2] sdm = {} for i, row in self.items(): if i in ri: row = {ci.index(j): e for j, e in row.items() if j in ci} if row: sdm[ri.index(i)] = row return self.new(sdm, (len(ri), len(ci)), self.domain) def extract(self, rows, cols): if not (self and rows and cols): return self.zeros((len(rows), len(cols)), self.domain) m, n = self.shape if not (-m <= min(rows) <= max(rows) < m): raise IndexError('Row index out of range') if not (-n <= min(cols) <= max(cols) < n): raise IndexError('Column index out of range') # rows and cols can contain duplicates e.g. M[[1, 2, 2], [0, 1]] # Build a map from row/col in self to list of rows/cols in output rowmap = defaultdict(list) colmap = defaultdict(list) for i2, i1 in enumerate(rows): rowmap[i1 % m].append(i2) for j2, j1 in enumerate(cols): colmap[j1 % n].append(j2) # Used to efficiently skip zero rows/cols rowset = set(rowmap) colset = set(colmap) sdm1 = self sdm2 = {} for i1 in rowset & set(sdm1): row1 = sdm1[i1] row2 = {} for j1 in colset & set(row1): row1_j1 = row1[j1] for j2 in colmap[j1]: row2[j2] = row1_j1 if row2: for i2 in rowmap[i1]: sdm2[i2] = row2.copy() return self.new(sdm2, (len(rows), len(cols)), self.domain) def __str__(self): rowsstr = [] for i, row in self.items(): elemsstr = ', '.join('%s: %s' % (j, elem) for j, elem in row.items()) rowsstr.append('%s: {%s}' % (i, elemsstr)) return '{%s}' % ', '.join(rowsstr) def __repr__(self): cls = type(self).__name__ rows = dict.__repr__(self) return '%s(%s, %s, %s)' % (cls, rows, self.shape, self.domain) @classmethod def new(cls, sdm, shape, domain): """ Parameters ========== sdm: A dict of dicts for non-zero elements in SDM shape: tuple representing dimension of SDM domain: Represents :py:class:`~.Domain` of SDM Returns ======= An :py:class:`~.SDM` object Examples ======== >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> elemsdict = {0:{1: QQ(2)}} >>> A = SDM.new(elemsdict, (2, 2), QQ) >>> A {0: {1: 2}} """ return cls(sdm, shape, domain) def copy(A): """ Returns the copy of a :py:class:`~.SDM` object Examples ======== >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> elemsdict = {0:{1:QQ(2)}, 1:{}} >>> A = SDM(elemsdict, (2, 2), QQ) >>> B = A.copy() >>> B {0: {1: 2}, 1: {}} """ Ac = {i: Ai.copy() for i, Ai in A.items()} return A.new(Ac, A.shape, A.domain) @classmethod def from_list(cls, ddm, shape, domain): """ Parameters ========== ddm: list of lists containing domain elements shape: Dimensions of :py:class:`~.SDM` matrix domain: Represents :py:class:`~.Domain` of :py:class:`~.SDM` object Returns ======= :py:class:`~.SDM` containing elements of ddm Examples ======== >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> ddm = [[QQ(1, 2), QQ(0)], [QQ(0), QQ(3, 4)]] >>> A = SDM.from_list(ddm, (2, 2), QQ) >>> A {0: {0: 1/2}, 1: {1: 3/4}} """ m, n = shape if not (len(ddm) == m and all(len(row) == n for row in ddm)): raise DDMBadInputError("Inconsistent row-list/shape") getrow = lambda i: {j:ddm[i][j] for j in range(n) if ddm[i][j]} irows = ((i, getrow(i)) for i in range(m)) sdm = {i: row for i, row in irows if row} return cls(sdm, shape, domain) @classmethod def from_ddm(cls, ddm): """ converts object of :py:class:`~.DDM` to :py:class:`~.SDM` Examples ======== >>> from sympy.polys.matrices.ddm import DDM >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> ddm = DDM( [[QQ(1, 2), 0], [0, QQ(3, 4)]], (2, 2), QQ) >>> A = SDM.from_ddm(ddm) >>> A {0: {0: 1/2}, 1: {1: 3/4}} """ return cls.from_list(ddm, ddm.shape, ddm.domain) def to_list(M): """ Converts a :py:class:`~.SDM` object to a list Examples ======== >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> elemsdict = {0:{1:QQ(2)}, 1:{}} >>> A = SDM(elemsdict, (2, 2), QQ) >>> A.to_list() [[0, 2], [0, 0]] """ m, n = M.shape zero = M.domain.zero ddm = [[zero] * n for _ in range(m)] for i, row in M.items(): for j, e in row.items(): ddm[i][j] = e return ddm def to_list_flat(M): m, n = M.shape zero = M.domain.zero flat = [zero] * (m * n) for i, row in M.items(): for j, e in row.items(): flat[i*n + j] = e return flat def to_dok(M): return {(i, j): e for i, row in M.items() for j, e in row.items()} def to_ddm(M): """ Convert a :py:class:`~.SDM` object to a :py:class:`~.DDM` object Examples ======== >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> A = SDM({0:{1:QQ(2)}, 1:{}}, (2, 2), QQ) >>> A.to_ddm() [[0, 2], [0, 0]] """ return DDM(M.to_list(), M.shape, M.domain) def to_sdm(M): return M @classmethod def zeros(cls, shape, domain): r""" Returns a :py:class:`~.SDM` of size shape, belonging to the specified domain In the example below we declare a matrix A where, .. math:: A := \left[\begin{array}{ccc} 0 & 0 & 0 \\ 0 & 0 & 0 \end{array} \right] >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> A = SDM.zeros((2, 3), QQ) >>> A {} """ return cls({}, shape, domain) @classmethod def ones(cls, shape, domain): one = domain.one m, n = shape row = dict(zip(range(n), [one]*n)) sdm = {i: row.copy() for i in range(m)} return cls(sdm, shape, domain) @classmethod def eye(cls, shape, domain): """ Returns a identity :py:class:`~.SDM` matrix of dimensions size x size, belonging to the specified domain Examples ======== >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> I = SDM.eye((2, 2), QQ) >>> I {0: {0: 1}, 1: {1: 1}} """ rows, cols = shape one = domain.one sdm = {i: {i: one} for i in range(min(rows, cols))} return cls(sdm, shape, domain) @classmethod def diag(cls, diagonal, domain, shape): sdm = {i: {i: v} for i, v in enumerate(diagonal) if v} return cls(sdm, shape, domain) def transpose(M): """ Returns the transpose of a :py:class:`~.SDM` matrix Examples ======== >>> from sympy.polys.matrices.sdm import SDM >>> from sympy import QQ >>> A = SDM({0:{1:QQ(2)}, 1:{}}, (2, 2), QQ) >>> A.transpose() {1: {0: 2}} """ MT = sdm_transpose(M) return M.new(MT, M.shape[::-1], M.domain) def __add__(A, B): if not isinstance(B, SDM): return NotImplemented return A.add(B) def __sub__(A, B): if not isinstance(B, SDM): return NotImplemented return A.sub(B) def __neg__(A): return A.neg() def __mul__(A, B): """A * B""" if isinstance(B, SDM): return A.matmul(B) elif B in A.domain: return A.mul(B) else: return NotImplemented def __rmul__(a, b): if b in a.domain: return a.rmul(b) else: return NotImplemented def matmul(A, B): """ Performs matrix multiplication of two SDM matrices Parameters ========== A, B: SDM to multiply Returns ======= SDM SDM after multiplication Raises ====== DomainError If domain of A does not match with that of B Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) >>> B = SDM({0:{0:ZZ(2), 1:ZZ(3)}, 1:{0:ZZ(4)}}, (2, 2), ZZ) >>> A.matmul(B) {0: {0: 8}, 1: {0: 2, 1: 3}} """ if A.domain != B.domain: raise DDMDomainError m, n = A.shape n2, o = B.shape if n != n2: raise DDMShapeError C = sdm_matmul(A, B, A.domain, m, o) return A.new(C, (m, o), A.domain) def mul(A, b): """ Multiplies each element of A with a scalar b Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) >>> A.mul(ZZ(3)) {0: {1: 6}, 1: {0: 3}} """ Csdm = unop_dict(A, lambda aij: aij*b) return A.new(Csdm, A.shape, A.domain) def rmul(A, b): Csdm = unop_dict(A, lambda aij: b*aij) return A.new(Csdm, A.shape, A.domain) def mul_elementwise(A, B): if A.domain != B.domain: raise DDMDomainError if A.shape != B.shape: raise DDMShapeError zero = A.domain.zero fzero = lambda e: zero Csdm = binop_dict(A, B, mul, fzero, fzero) return A.new(Csdm, A.shape, A.domain) def add(A, B): """ Adds two :py:class:`~.SDM` matrices Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) >>> B = SDM({0:{0: ZZ(3)}, 1:{1:ZZ(4)}}, (2, 2), ZZ) >>> A.add(B) {0: {0: 3, 1: 2}, 1: {0: 1, 1: 4}} """ Csdm = binop_dict(A, B, add, pos, pos) return A.new(Csdm, A.shape, A.domain) def sub(A, B): """ Subtracts two :py:class:`~.SDM` matrices Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) >>> B = SDM({0:{0: ZZ(3)}, 1:{1:ZZ(4)}}, (2, 2), ZZ) >>> A.sub(B) {0: {0: -3, 1: 2}, 1: {0: 1, 1: -4}} """ Csdm = binop_dict(A, B, sub, pos, neg) return A.new(Csdm, A.shape, A.domain) def neg(A): """ Returns the negative of a :py:class:`~.SDM` matrix Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) >>> A.neg() {0: {1: -2}, 1: {0: -1}} """ Csdm = unop_dict(A, neg) return A.new(Csdm, A.shape, A.domain) def convert_to(A, K): """ Converts the :py:class:`~.Domain` of a :py:class:`~.SDM` matrix to K Examples ======== >>> from sympy import ZZ, QQ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{1: ZZ(2)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) >>> A.convert_to(QQ) {0: {1: 2}, 1: {0: 1}} """ Kold = A.domain if K == Kold: return A.copy() Ak = unop_dict(A, lambda e: K.convert_from(e, Kold)) return A.new(Ak, A.shape, K) def scc(A): """Strongly connected components of a square matrix *A*. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{0: ZZ(2)}, 1:{1:ZZ(1)}}, (2, 2), ZZ) >>> A.scc() [[0], [1]] See also ======== sympy.polys.matrices.domainmatrix.DomainMatrix.scc """ rows, cols = A.shape assert rows == cols V = range(rows) Emap = {v: list(A.get(v, [])) for v in V} return _strongly_connected_components(V, Emap) def rref(A): """ Returns reduced-row echelon form and list of pivots for the :py:class:`~.SDM` Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(2), 1:QQ(4)}}, (2, 2), QQ) >>> A.rref() ({0: {0: 1, 1: 2}}, [0]) """ B, pivots, _ = sdm_irref(A) return A.new(B, A.shape, A.domain), pivots def inv(A): """ Returns inverse of a matrix A Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) >>> A.inv() {0: {0: -2, 1: 1}, 1: {0: 3/2, 1: -1/2}} """ return A.from_ddm(A.to_ddm().inv()) def det(A): """ Returns determinant of A Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) >>> A.det() -2 """ return A.to_ddm().det() def lu(A): """ Returns LU decomposition for a matrix A Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) >>> A.lu() ({0: {0: 1}, 1: {0: 3, 1: 1}}, {0: {0: 1, 1: 2}, 1: {1: -2}}, []) """ L, U, swaps = A.to_ddm().lu() return A.from_ddm(L), A.from_ddm(U), swaps def lu_solve(A, b): """ Uses LU decomposition to solve Ax = b, Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) >>> b = SDM({0:{0:QQ(1)}, 1:{0:QQ(2)}}, (2, 1), QQ) >>> A.lu_solve(b) {1: {0: 1/2}} """ return A.from_ddm(A.to_ddm().lu_solve(b.to_ddm())) def nullspace(A): """ Returns nullspace for a :py:class:`~.SDM` matrix A Examples ======== >>> from sympy import QQ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0: QQ(2), 1: QQ(4)}}, (2, 2), QQ) >>> A.nullspace() ({0: {0: -2, 1: 1}}, [1]) """ ncols = A.shape[1] one = A.domain.one B, pivots, nzcols = sdm_irref(A) K, nonpivots = sdm_nullspace_from_rref(B, one, ncols, pivots, nzcols) K = dict(enumerate(K)) shape = (len(K), ncols) return A.new(K, shape, A.domain), nonpivots def particular(A): ncols = A.shape[1] B, pivots, nzcols = sdm_irref(A) P = sdm_particular_from_rref(B, ncols, pivots) rep = {0:P} if P else {} return A.new(rep, (1, ncols-1), A.domain) def hstack(A, *B): """Horizontally stacks :py:class:`~.SDM` matrices. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0: {0: ZZ(1), 1: ZZ(2)}, 1: {0: ZZ(3), 1: ZZ(4)}}, (2, 2), ZZ) >>> B = SDM({0: {0: ZZ(5), 1: ZZ(6)}, 1: {0: ZZ(7), 1: ZZ(8)}}, (2, 2), ZZ) >>> A.hstack(B) {0: {0: 1, 1: 2, 2: 5, 3: 6}, 1: {0: 3, 1: 4, 2: 7, 3: 8}} >>> C = SDM({0: {0: ZZ(9), 1: ZZ(10)}, 1: {0: ZZ(11), 1: ZZ(12)}}, (2, 2), ZZ) >>> A.hstack(B, C) {0: {0: 1, 1: 2, 2: 5, 3: 6, 4: 9, 5: 10}, 1: {0: 3, 1: 4, 2: 7, 3: 8, 4: 11, 5: 12}} """ Anew = dict(A.copy()) rows, cols = A.shape domain = A.domain for Bk in B: Bkrows, Bkcols = Bk.shape assert Bkrows == rows assert Bk.domain == domain for i, Bki in Bk.items(): Ai = Anew.get(i, None) if Ai is None: Anew[i] = Ai = {} for j, Bkij in Bki.items(): Ai[j + cols] = Bkij cols += Bkcols return A.new(Anew, (rows, cols), A.domain) def vstack(A, *B): """Vertically stacks :py:class:`~.SDM` matrices. Examples ======== >>> from sympy import ZZ >>> from sympy.polys.matrices.sdm import SDM >>> A = SDM({0: {0: ZZ(1), 1: ZZ(2)}, 1: {0: ZZ(3), 1: ZZ(4)}}, (2, 2), ZZ) >>> B = SDM({0: {0: ZZ(5), 1: ZZ(6)}, 1: {0: ZZ(7), 1: ZZ(8)}}, (2, 2), ZZ) >>> A.vstack(B) {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}, 2: {0: 5, 1: 6}, 3: {0: 7, 1: 8}} >>> C = SDM({0: {0: ZZ(9), 1: ZZ(10)}, 1: {0: ZZ(11), 1: ZZ(12)}}, (2, 2), ZZ) >>> A.vstack(B, C) {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}, 2: {0: 5, 1: 6}, 3: {0: 7, 1: 8}, 4: {0: 9, 1: 10}, 5: {0: 11, 1: 12}} """ Anew = dict(A.copy()) rows, cols = A.shape domain = A.domain for Bk in B: Bkrows, Bkcols = Bk.shape assert Bkcols == cols assert Bk.domain == domain for i, Bki in Bk.items(): Anew[i + rows] = Bki rows += Bkrows return A.new(Anew, (rows, cols), A.domain) def applyfunc(self, func, domain): sdm = {i: {j: func(e) for j, e in row.items()} for i, row in self.items()} return self.new(sdm, self.shape, domain) def charpoly(A): """ Returns the coefficients of the characteristic polynomial of the :py:class:`~.SDM` matrix. These elements will be domain elements. The domain of the elements will be same as domain of the :py:class:`~.SDM`. Examples ======== >>> from sympy import QQ, Symbol >>> from sympy.polys.matrices.sdm import SDM >>> from sympy.polys import Poly >>> A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) >>> A.charpoly() [1, -5, -2] We can create a polynomial using the coefficients using :py:class:`~.Poly` >>> x = Symbol('x') >>> p = Poly(A.charpoly(), x, domain=A.domain) >>> p Poly(x**2 - 5*x - 2, x, domain='QQ') """ return A.to_ddm().charpoly() def binop_dict(A, B, fab, fa, fb): Anz, Bnz = set(A), set(B) C = {} for i in Anz & Bnz: Ai, Bi = A[i], B[i] Ci = {} Anzi, Bnzi = set(Ai), set(Bi) for j in Anzi & Bnzi: Cij = fab(Ai[j], Bi[j]) if Cij: Ci[j] = Cij for j in Anzi - Bnzi: Cij = fa(Ai[j]) if Cij: Ci[j] = Cij for j in Bnzi - Anzi: Cij = fb(Bi[j]) if Cij: Ci[j] = Cij if Ci: C[i] = Ci for i in Anz - Bnz: Ai = A[i] Ci = {} for j, Aij in Ai.items(): Cij = fa(Aij) if Cij: Ci[j] = Cij if Ci: C[i] = Ci for i in Bnz - Anz: Bi = B[i] Ci = {} for j, Bij in Bi.items(): Cij = fb(Bij) if Cij: Ci[j] = Cij if Ci: C[i] = Ci return C def unop_dict(A, f): B = {} for i, Ai in A.items(): Bi = {} for j, Aij in Ai.items(): Bij = f(Aij) if Bij: Bi[j] = Bij if Bi: B[i] = Bi return B def sdm_transpose(M): MT = {} for i, Mi in M.items(): for j, Mij in Mi.items(): try: MT[j][i] = Mij except KeyError: MT[j] = {i: Mij} return MT def sdm_matmul(A, B, K, m, o): # # Should be fast if A and B are very sparse. # Consider e.g. A = B = eye(1000). # # The idea here is that we compute C = A*B in terms of the rows of C and # B since the dict of dicts representation naturally stores the matrix as # rows. The ith row of C (Ci) is equal to the sum of Aik * Bk where Bk is # the kth row of B. The algorithm below loops over each nonzero element # Aik of A and if the corresponding row Bj is nonzero then we do # Ci += Aik * Bk. # To make this more efficient we don't need to loop over all elements Aik. # Instead for each row Ai we compute the intersection of the nonzero # columns in Ai with the nonzero rows in B. That gives the k such that # Aik and Bk are both nonzero. In Python the intersection of two sets # of int can be computed very efficiently. # if K.is_EXRAW: return sdm_matmul_exraw(A, B, K, m, o) C = {} B_knz = set(B) for i, Ai in A.items(): Ci = {} Ai_knz = set(Ai) for k in Ai_knz & B_knz: Aik = Ai[k] for j, Bkj in B[k].items(): Cij = Ci.get(j, None) if Cij is not None: Cij = Cij + Aik * Bkj if Cij: Ci[j] = Cij else: Ci.pop(j) else: Cij = Aik * Bkj if Cij: Ci[j] = Cij if Ci: C[i] = Ci return C def sdm_matmul_exraw(A, B, K, m, o): # # Like sdm_matmul above except that: # # - Handles cases like 0*oo -> nan (sdm_matmul skips multipication by zero) # - Uses K.sum (Add(*items)) for efficient addition of Expr # zero = K.zero C = {} B_knz = set(B) for i, Ai in A.items(): Ci_list = defaultdict(list) Ai_knz = set(Ai) # Nonzero row/column pair for k in Ai_knz & B_knz: Aik = Ai[k] if zero * Aik == zero: # This is the main inner loop: for j, Bkj in B[k].items(): Ci_list[j].append(Aik * Bkj) else: for j in range(o): Ci_list[j].append(Aik * B[k].get(j, zero)) # Zero row in B, check for infinities in A for k in Ai_knz - B_knz: zAik = zero * Ai[k] if zAik != zero: for j in range(o): Ci_list[j].append(zAik) # Add terms using K.sum (Add(*terms)) for efficiency Ci = {} for j, Cij_list in Ci_list.items(): Cij = K.sum(Cij_list) if Cij: Ci[j] = Cij if Ci: C[i] = Ci # Find all infinities in B for k, Bk in B.items(): for j, Bkj in Bk.items(): if zero * Bkj != zero: for i in range(m): Aik = A.get(i, {}).get(k, zero) # If Aik is not zero then this was handled above if Aik == zero: Ci = C.get(i, {}) Cij = Ci.get(j, zero) + Aik * Bkj if Cij != zero: Ci[j] = Cij else: # pragma: no cover # Not sure how we could get here but let's raise an # exception just in case. raise RuntimeError C[i] = Ci return C def sdm_irref(A): """RREF and pivots of a sparse matrix *A*. Compute the reduced row echelon form (RREF) of the matrix *A* and return a list of the pivot columns. This routine does not work in place and leaves the original matrix *A* unmodified. Examples ======== This routine works with a dict of dicts sparse representation of a matrix: >>> from sympy import QQ >>> from sympy.polys.matrices.sdm import sdm_irref >>> A = {0: {0: QQ(1), 1: QQ(2)}, 1: {0: QQ(3), 1: QQ(4)}} >>> Arref, pivots, _ = sdm_irref(A) >>> Arref {0: {0: 1}, 1: {1: 1}} >>> pivots [0, 1] The analogous calculation with :py:class:`~.Matrix` would be >>> from sympy import Matrix >>> M = Matrix([[1, 2], [3, 4]]) >>> Mrref, pivots = M.rref() >>> Mrref Matrix([ [1, 0], [0, 1]]) >>> pivots (0, 1) Notes ===== The cost of this algorithm is determined purely by the nonzero elements of the matrix. No part of the cost of any step in this algorithm depends on the number of rows or columns in the matrix. No step depends even on the number of nonzero rows apart from the primary loop over those rows. The implementation is much faster than ddm_rref for sparse matrices. In fact at the time of writing it is also (slightly) faster than the dense implementation even if the input is a fully dense matrix so it seems to be faster in all cases. The elements of the matrix should support exact division with ``/``. For example elements of any domain that is a field (e.g. ``QQ``) should be fine. No attempt is made to handle inexact arithmetic. """ # # Any zeros in the matrix are not stored at all so an element is zero if # its row dict has no index at that key. A row is entirely zero if its # row index is not in the outer dict. Since rref reorders the rows and # removes zero rows we can completely discard the row indices. The first # step then copies the row dicts into a list sorted by the index of the # first nonzero column in each row. # # The algorithm then processes each row Ai one at a time. Previously seen # rows are used to cancel their pivot columns from Ai. Then a pivot from # Ai is chosen and is cancelled from all previously seen rows. At this # point Ai joins the previously seen rows. Once all rows are seen all # elimination has occurred and the rows are sorted by pivot column index. # # The previously seen rows are stored in two separate groups. The reduced # group consists of all rows that have been reduced to a single nonzero # element (the pivot). There is no need to attempt any further reduction # with these. Rows that still have other nonzeros need to be considered # when Ai is cancelled from the previously seen rows. # # A dict nonzerocolumns is used to map from a column index to a set of # previously seen rows that still have a nonzero element in that column. # This means that we can cancel the pivot from Ai into the previously seen # rows without needing to loop over each row that might have a zero in # that column. # # Row dicts sorted by index of first nonzero column # (Maybe sorting is not needed/useful.) Arows = sorted((Ai.copy() for Ai in A.values()), key=min) # Each processed row has an associated pivot column. # pivot_row_map maps from the pivot column index to the row dict. # This means that we can represent a set of rows purely as a set of their # pivot indices. pivot_row_map = {} # Set of pivot indices for rows that are fully reduced to a single nonzero. reduced_pivots = set() # Set of pivot indices for rows not fully reduced nonreduced_pivots = set() # Map from column index to a set of pivot indices representing the rows # that have a nonzero at that column. nonzero_columns = defaultdict(set) while Arows: # Select pivot element and row Ai = Arows.pop() # Nonzero columns from fully reduced pivot rows can be removed Ai = {j: Aij for j, Aij in Ai.items() if j not in reduced_pivots} # Others require full row cancellation for j in nonreduced_pivots & set(Ai): Aj = pivot_row_map[j] Aij = Ai[j] Ainz = set(Ai) Ajnz = set(Aj) for k in Ajnz - Ainz: Ai[k] = - Aij * Aj[k] Ai.pop(j) Ainz.remove(j) for k in Ajnz & Ainz: Aik = Ai[k] - Aij * Aj[k] if Aik: Ai[k] = Aik else: Ai.pop(k) # We have now cancelled previously seen pivots from Ai. # If it is zero then discard it. if not Ai: continue # Choose a pivot from Ai: j = min(Ai) Aij = Ai[j] pivot_row_map[j] = Ai Ainz = set(Ai) # Normalise the pivot row to make the pivot 1. # # This approach is slow for some domains. Cross cancellation might be # better for e.g. QQ(x) with division delayed to the final steps. Aijinv = Aij**-1 for l in Ai: Ai[l] *= Aijinv # Use Aij to cancel column j from all previously seen rows for k in nonzero_columns.pop(j, ()): Ak = pivot_row_map[k] Akj = Ak[j] Aknz = set(Ak) for l in Ainz - Aknz: Ak[l] = - Akj * Ai[l] nonzero_columns[l].add(k) Ak.pop(j) Aknz.remove(j) for l in Ainz & Aknz: Akl = Ak[l] - Akj * Ai[l] if Akl: Ak[l] = Akl else: # Drop nonzero elements Ak.pop(l) if l != j: nonzero_columns[l].remove(k) if len(Ak) == 1: reduced_pivots.add(k) nonreduced_pivots.remove(k) if len(Ai) == 1: reduced_pivots.add(j) else: nonreduced_pivots.add(j) for l in Ai: if l != j: nonzero_columns[l].add(j) # All done! pivots = sorted(reduced_pivots | nonreduced_pivots) pivot2row = {p: n for n, p in enumerate(pivots)} nonzero_columns = {c: set(pivot2row[p] for p in s) for c, s in nonzero_columns.items()} rows = [pivot_row_map[i] for i in pivots] rref = dict(enumerate(rows)) return rref, pivots, nonzero_columns def sdm_nullspace_from_rref(A, one, ncols, pivots, nonzero_cols): """Get nullspace from A which is in RREF""" nonpivots = sorted(set(range(ncols)) - set(pivots)) K = [] for j in nonpivots: Kj = {j:one} for i in nonzero_cols.get(j, ()): Kj[pivots[i]] = -A[i][j] K.append(Kj) return K, nonpivots def sdm_particular_from_rref(A, ncols, pivots): """Get a particular solution from A which is in RREF""" P = {} for i, j in enumerate(pivots): Ain = A[i].get(ncols-1, None) if Ain is not None: P[j] = Ain / A[i][j] return P sympy-sympy-1.9/sympy/polys/matrices/tests/000077500000000000000000000000001412543434000212235ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/matrices/tests/__init__.py000066400000000000000000000000001412543434000233220ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/matrices/tests/test_ddm.py000066400000000000000000000341501412543434000234030ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy.core.compatibility import HAS_GMPY from sympy.polys import ZZ, QQ from sympy.polys.matrices.ddm import DDM from sympy.polys.matrices.exceptions import ( DDMShapeError, NonInvertibleMatrixError, DDMDomainError, DDMBadInputError) def test_DDM_init(): items = [[ZZ(0), ZZ(1), ZZ(2)], [ZZ(3), ZZ(4), ZZ(5)]] shape = (2, 3) ddm = DDM(items, shape, ZZ) assert ddm.shape == shape assert ddm.rows == 2 assert ddm.cols == 3 assert ddm.domain == ZZ raises(DDMBadInputError, lambda: DDM([[ZZ(2), ZZ(3)]], (2, 2), ZZ)) raises(DDMBadInputError, lambda: DDM([[ZZ(1)], [ZZ(2), ZZ(3)]], (2, 2), ZZ)) def test_DDM_getsetitem(): ddm = DDM([[ZZ(2), ZZ(3)], [ZZ(4), ZZ(5)]], (2, 2), ZZ) assert ddm[0][0] == ZZ(2) assert ddm[0][1] == ZZ(3) assert ddm[1][0] == ZZ(4) assert ddm[1][1] == ZZ(5) raises(IndexError, lambda: ddm[2][0]) raises(IndexError, lambda: ddm[0][2]) ddm[0][0] = ZZ(-1) assert ddm[0][0] == ZZ(-1) def test_DDM_str(): ddm = DDM([[ZZ(0), ZZ(1)], [ZZ(2), ZZ(3)]], (2, 2), ZZ) if HAS_GMPY: # pragma: no cover assert str(ddm) == '[[0, 1], [2, 3]]' assert repr(ddm) == 'DDM([[mpz(0), mpz(1)], [mpz(2), mpz(3)]], (2, 2), ZZ)' else: # pragma: no cover assert repr(ddm) == 'DDM([[0, 1], [2, 3]], (2, 2), ZZ)' assert str(ddm) == '[[0, 1], [2, 3]]' def test_DDM_eq(): items = [[ZZ(0), ZZ(1)], [ZZ(2), ZZ(3)]] ddm1 = DDM(items, (2, 2), ZZ) ddm2 = DDM(items, (2, 2), ZZ) assert (ddm1 == ddm1) is True assert (ddm1 == items) is False assert (items == ddm1) is False assert (ddm1 == ddm2) is True assert (ddm2 == ddm1) is True assert (ddm1 != ddm1) is False assert (ddm1 != items) is True assert (items != ddm1) is True assert (ddm1 != ddm2) is False assert (ddm2 != ddm1) is False ddm3 = DDM([[ZZ(0), ZZ(1)], [ZZ(3), ZZ(3)]], (2, 2), ZZ) ddm3 = DDM(items, (2, 2), QQ) assert (ddm1 == ddm3) is False assert (ddm3 == ddm1) is False assert (ddm1 != ddm3) is True assert (ddm3 != ddm1) is True def test_DDM_convert_to(): ddm = DDM([[ZZ(1), ZZ(2)]], (1, 2), ZZ) assert ddm.convert_to(ZZ) == ddm ddmq = ddm.convert_to(QQ) assert ddmq.domain == QQ def test_DDM_zeros(): ddmz = DDM.zeros((3, 4), QQ) assert list(ddmz) == [[QQ(0)] * 4] * 3 assert ddmz.shape == (3, 4) assert ddmz.domain == QQ def test_DDM_ones(): ddmone = DDM.ones((2, 3), QQ) assert list(ddmone) == [[QQ(1)] * 3] * 2 assert ddmone.shape == (2, 3) assert ddmone.domain == QQ def test_DDM_eye(): ddmz = DDM.eye(3, QQ) f = lambda i, j: QQ(1) if i == j else QQ(0) assert list(ddmz) == [[f(i, j) for i in range(3)] for j in range(3)] assert ddmz.shape == (3, 3) assert ddmz.domain == QQ def test_DDM_copy(): ddm1 = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) ddm2 = ddm1.copy() assert (ddm1 == ddm2) is True ddm1[0][0] = QQ(-1) assert (ddm1 == ddm2) is False ddm2[0][0] = QQ(-1) assert (ddm1 == ddm2) is True def test_DDM_transpose(): ddm = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) ddmT = DDM([[QQ(1), QQ(2)]], (1, 2), QQ) assert ddm.transpose() == ddmT ddm02 = DDM([], (0, 2), QQ) ddm02T = DDM([[], []], (2, 0), QQ) assert ddm02.transpose() == ddm02T assert ddm02T.transpose() == ddm02 ddm0 = DDM([], (0, 0), QQ) assert ddm0.transpose() == ddm0 def test_DDM_add(): A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ) B = DDM([[ZZ(3)], [ZZ(4)]], (2, 1), ZZ) C = DDM([[ZZ(4)], [ZZ(6)]], (2, 1), ZZ) AQ = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) assert A + B == A.add(B) == C raises(DDMShapeError, lambda: A + DDM([[ZZ(5)]], (1, 1), ZZ)) raises(TypeError, lambda: A + ZZ(1)) raises(TypeError, lambda: ZZ(1) + A) raises(DDMDomainError, lambda: A + AQ) raises(DDMDomainError, lambda: AQ + A) def test_DDM_sub(): A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ) B = DDM([[ZZ(3)], [ZZ(4)]], (2, 1), ZZ) C = DDM([[ZZ(-2)], [ZZ(-2)]], (2, 1), ZZ) AQ = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) D = DDM([[ZZ(5)]], (1, 1), ZZ) assert A - B == A.sub(B) == C raises(TypeError, lambda: A - ZZ(1)) raises(TypeError, lambda: ZZ(1) - A) raises(DDMShapeError, lambda: A - D) raises(DDMShapeError, lambda: D - A) raises(DDMShapeError, lambda: A.sub(D)) raises(DDMShapeError, lambda: D.sub(A)) raises(DDMDomainError, lambda: A - AQ) raises(DDMDomainError, lambda: AQ - A) raises(DDMDomainError, lambda: A.sub(AQ)) raises(DDMDomainError, lambda: AQ.sub(A)) def test_DDM_neg(): A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ) An = DDM([[ZZ(-1)], [ZZ(-2)]], (2, 1), ZZ) assert -A == A.neg() == An assert -An == An.neg() == A def test_DDM_mul(): A = DDM([[ZZ(1)]], (1, 1), ZZ) A2 = DDM([[ZZ(2)]], (1, 1), ZZ) assert A * ZZ(2) == A2 assert ZZ(2) * A == A2 raises(TypeError, lambda: [[1]] * A) raises(TypeError, lambda: A * [[1]]) def test_DDM_matmul(): A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ) B = DDM([[ZZ(3), ZZ(4)]], (1, 2), ZZ) AB = DDM([[ZZ(3), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ) BA = DDM([[ZZ(11)]], (1, 1), ZZ) assert A @ B == A.matmul(B) == AB assert B @ A == B.matmul(A) == BA raises(TypeError, lambda: A @ 1) raises(TypeError, lambda: A @ [[3, 4]]) Bq = DDM([[QQ(3), QQ(4)]], (1, 2), QQ) raises(DDMDomainError, lambda: A @ Bq) raises(DDMDomainError, lambda: Bq @ A) C = DDM([[ZZ(1)]], (1, 1), ZZ) assert A @ C == A.matmul(C) == A raises(DDMShapeError, lambda: C @ A) raises(DDMShapeError, lambda: C.matmul(A)) Z04 = DDM([], (0, 4), ZZ) Z40 = DDM([[]]*4, (4, 0), ZZ) Z50 = DDM([[]]*5, (5, 0), ZZ) Z05 = DDM([], (0, 5), ZZ) Z45 = DDM([[0] * 5] * 4, (4, 5), ZZ) Z54 = DDM([[0] * 4] * 5, (5, 4), ZZ) Z00 = DDM([], (0, 0), ZZ) assert Z04 @ Z45 == Z04.matmul(Z45) == Z05 assert Z45 @ Z50 == Z45.matmul(Z50) == Z40 assert Z00 @ Z04 == Z00.matmul(Z04) == Z04 assert Z50 @ Z00 == Z50.matmul(Z00) == Z50 assert Z00 @ Z00 == Z00.matmul(Z00) == Z00 assert Z50 @ Z04 == Z50.matmul(Z04) == Z54 raises(DDMShapeError, lambda: Z05 @ Z40) raises(DDMShapeError, lambda: Z05.matmul(Z40)) def test_DDM_hstack(): A = DDM([[ZZ(1), ZZ(2), ZZ(3)]], (1, 3), ZZ) B = DDM([[ZZ(4), ZZ(5)]], (1, 2), ZZ) C = DDM([[ZZ(6)]], (1, 1), ZZ) Ah = A.hstack(B) assert Ah.shape == (1, 5) assert Ah.domain == ZZ assert Ah == DDM([[ZZ(1), ZZ(2), ZZ(3), ZZ(4), ZZ(5)]], (1, 5), ZZ) Ah = A.hstack(B, C) assert Ah.shape == (1, 6) assert Ah.domain == ZZ assert Ah == DDM([[ZZ(1), ZZ(2), ZZ(3), ZZ(4), ZZ(5), ZZ(6)]], (1, 6), ZZ) def test_DDM_vstack(): A = DDM([[ZZ(1)], [ZZ(2)], [ZZ(3)]], (3, 1), ZZ) B = DDM([[ZZ(4)], [ZZ(5)]], (2, 1), ZZ) C = DDM([[ZZ(6)]], (1, 1), ZZ) Ah = A.vstack(B) assert Ah.shape == (5, 1) assert Ah.domain == ZZ assert Ah == DDM([[ZZ(1)], [ZZ(2)], [ZZ(3)], [ZZ(4)], [ZZ(5)]], (5, 1), ZZ) Ah = A.vstack(B, C) assert Ah.shape == (6, 1) assert Ah.domain == ZZ assert Ah == DDM([[ZZ(1)], [ZZ(2)], [ZZ(3)], [ZZ(4)], [ZZ(5)], [ZZ(6)]], (6, 1), ZZ) def test_DDM_applyfunc(): A = DDM([[ZZ(1), ZZ(2), ZZ(3)]], (1, 3), ZZ) B = DDM([[ZZ(2), ZZ(4), ZZ(6)]], (1, 3), ZZ) assert A.applyfunc(lambda x: 2*x, ZZ) == B def test_DDM_rref(): A = DDM([], (0, 4), QQ) assert A.rref() == (A, []) A = DDM([[QQ(0), QQ(1)], [QQ(1), QQ(1)]], (2, 2), QQ) Ar = DDM([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ) pivots = [0, 1] assert A.rref() == (Ar, pivots) A = DDM([[QQ(1), QQ(2), QQ(1)], [QQ(3), QQ(4), QQ(1)]], (2, 3), QQ) Ar = DDM([[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]], (2, 3), QQ) pivots = [0, 1] assert A.rref() == (Ar, pivots) A = DDM([[QQ(3), QQ(4), QQ(1)], [QQ(1), QQ(2), QQ(1)]], (2, 3), QQ) Ar = DDM([[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]], (2, 3), QQ) pivots = [0, 1] assert A.rref() == (Ar, pivots) A = DDM([[QQ(1), QQ(0)], [QQ(1), QQ(3)], [QQ(0), QQ(1)]], (3, 2), QQ) Ar = DDM([[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]], (3, 2), QQ) pivots = [0, 1] assert A.rref() == (Ar, pivots) A = DDM([[QQ(1), QQ(0), QQ(1)], [QQ(3), QQ(0), QQ(1)]], (2, 3), QQ) Ar = DDM([[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(0), QQ(1)]], (2, 3), QQ) pivots = [0, 2] assert A.rref() == (Ar, pivots) def test_DDM_nullspace(): A = DDM([[QQ(1), QQ(1)], [QQ(1), QQ(1)]], (2, 2), QQ) Anull = DDM([[QQ(-1), QQ(1)]], (1, 2), QQ) nonpivots = [1] assert A.nullspace() == (Anull, nonpivots) def test_DDM_particular(): A = DDM([[QQ(1), QQ(0)]], (1, 2), QQ) assert A.particular() == DDM.zeros((1, 1), QQ) def test_DDM_det(): # 0x0 case A = DDM([], (0, 0), ZZ) assert A.det() == ZZ(1) # 1x1 case A = DDM([[ZZ(2)]], (1, 1), ZZ) assert A.det() == ZZ(2) # 2x2 case A = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.det() == ZZ(-2) # 3x3 with swap A = DDM([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(2), ZZ(5)]], (3, 3), ZZ) assert A.det() == ZZ(0) # 2x2 QQ case A = DDM([[QQ(1, 2), QQ(1, 2)], [QQ(1, 3), QQ(1, 4)]], (2, 2), QQ) assert A.det() == QQ(-1, 24) # Nonsquare error A = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ) raises(DDMShapeError, lambda: A.det()) # Nonsquare error with empty matrix A = DDM([], (0, 1), ZZ) raises(DDMShapeError, lambda: A.det()) def test_DDM_inv(): A = DDM([[QQ(1, 1), QQ(2, 1)], [QQ(3, 1), QQ(4, 1)]], (2, 2), QQ) Ainv = DDM([[QQ(-2, 1), QQ(1, 1)], [QQ(3, 2), QQ(-1, 2)]], (2, 2), QQ) assert A.inv() == Ainv A = DDM([[QQ(1), QQ(2)]], (1, 2), QQ) raises(DDMShapeError, lambda: A.inv()) A = DDM([[ZZ(2)]], (1, 1), ZZ) raises(ValueError, lambda: A.inv()) A = DDM([], (0, 0), QQ) assert A.inv() == A A = DDM([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ) raises(NonInvertibleMatrixError, lambda: A.inv()) def test_DDM_lu(): A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) L, U, swaps = A.lu() assert L == DDM([[QQ(1), QQ(0)], [QQ(3), QQ(1)]], (2, 2), QQ) assert U == DDM([[QQ(1), QQ(2)], [QQ(0), QQ(-2)]], (2, 2), QQ) assert swaps == [] A = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 2]] Lexp = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 1, 1]] Uexp = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]] to_dom = lambda rows, dom: [[dom(e) for e in row] for row in rows] A = DDM(to_dom(A, QQ), (4, 4), QQ) Lexp = DDM(to_dom(Lexp, QQ), (4, 4), QQ) Uexp = DDM(to_dom(Uexp, QQ), (4, 4), QQ) L, U, swaps = A.lu() assert L == Lexp assert U == Uexp assert swaps == [] def test_DDM_lu_solve(): # Basic example A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) x = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ) assert A.lu_solve(b) == x # Example with swaps A = DDM([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) assert A.lu_solve(b) == x # Overdetermined, consistent A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ) b = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ) assert A.lu_solve(b) == x # Overdetermined, inconsistent b = DDM([[QQ(1)], [QQ(2)], [QQ(4)]], (3, 1), QQ) raises(NonInvertibleMatrixError, lambda: A.lu_solve(b)) # Square, noninvertible A = DDM([[QQ(1), QQ(2)], [QQ(1), QQ(2)]], (2, 2), QQ) b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) raises(NonInvertibleMatrixError, lambda: A.lu_solve(b)) # Underdetermined A = DDM([[QQ(1), QQ(2)]], (1, 2), QQ) b = DDM([[QQ(3)]], (1, 1), QQ) raises(NotImplementedError, lambda: A.lu_solve(b)) # Domain mismatch bz = DDM([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ) raises(DDMDomainError, lambda: A.lu_solve(bz)) # Shape mismatch b3 = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ) raises(DDMShapeError, lambda: A.lu_solve(b3)) def test_DDM_charpoly(): A = DDM([], (0, 0), ZZ) assert A.charpoly() == [ZZ(1)] A = DDM([ [ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ) Avec = [ZZ(1), ZZ(-15), ZZ(-18), ZZ(0)] assert A.charpoly() == Avec A = DDM([[ZZ(1), ZZ(2)]], (1, 2), ZZ) raises(DDMShapeError, lambda: A.charpoly()) def test_DDM_getitem(): dm = DDM([ [ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ) assert dm.getitem(1, 1) == ZZ(5) assert dm.getitem(1, -2) == ZZ(5) assert dm.getitem(-1, -3) == ZZ(7) raises(IndexError, lambda: dm.getitem(3, 3)) def test_DDM_extract_slice(): dm = DDM([ [ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ) assert dm.extract_slice(slice(0, 3), slice(0, 3)) == dm assert dm.extract_slice(slice(1, 3), slice(-2)) == DDM([[4], [7]], (2, 1), ZZ) assert dm.extract_slice(slice(1, 3), slice(-2)) == DDM([[4], [7]], (2, 1), ZZ) assert dm.extract_slice(slice(2, 3), slice(-2)) == DDM([[ZZ(7)]], (1, 1), ZZ) assert dm.extract_slice(slice(0, 2), slice(-2)) == DDM([[1], [4]], (2, 1), ZZ) assert dm.extract_slice(slice(-1), slice(-1)) == DDM([[1, 2], [4, 5]], (2, 2), ZZ) assert dm.extract_slice(slice(2), slice(3, 4)) == DDM([[], []], (2, 0), ZZ) assert dm.extract_slice(slice(3, 4), slice(2)) == DDM([], (0, 2), ZZ) assert dm.extract_slice(slice(3, 4), slice(3, 4)) == DDM([], (0, 0), ZZ) def test_DDM_extract(): dm1 = DDM([ [ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ) dm2 = DDM([ [ZZ(6), ZZ(4)], [ZZ(3), ZZ(1)]], (2, 2), ZZ) assert dm1.extract([1, 0], [2, 0]) == dm2 assert dm1.extract([-2, 0], [-1, 0]) == dm2 assert dm1.extract([], []) == DDM.zeros((0, 0), ZZ) assert dm1.extract([1], []) == DDM.zeros((1, 0), ZZ) assert dm1.extract([], [1]) == DDM.zeros((0, 1), ZZ) raises(IndexError, lambda: dm2.extract([2], [0])) raises(IndexError, lambda: dm2.extract([0], [2])) raises(IndexError, lambda: dm2.extract([-3], [0])) raises(IndexError, lambda: dm2.extract([0], [-3])) sympy-sympy-1.9/sympy/polys/matrices/tests/test_dense.py000066400000000000000000000224071412543434000237370ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy.polys import ZZ, QQ from sympy.polys.matrices.ddm import DDM from sympy.polys.matrices.dense import ( ddm_transpose, ddm_iadd, ddm_isub, ddm_ineg, ddm_imatmul, ddm_imul, ddm_irref, ddm_idet, ddm_iinv, ddm_ilu, ddm_ilu_split, ddm_ilu_solve, ddm_berk) from sympy.polys.matrices.exceptions import ( DDMShapeError, NonInvertibleMatrixError, NonSquareMatrixError) def test_ddm_transpose(): a = [[1, 2], [3, 4]] assert ddm_transpose(a) == [[1, 3], [2, 4]] def test_ddm_iadd(): a = [[1, 2], [3, 4]] b = [[5, 6], [7, 8]] ddm_iadd(a, b) assert a == [[6, 8], [10, 12]] def test_ddm_isub(): a = [[1, 2], [3, 4]] b = [[5, 6], [7, 8]] ddm_isub(a, b) assert a == [[-4, -4], [-4, -4]] def test_ddm_ineg(): a = [[1, 2], [3, 4]] ddm_ineg(a) assert a == [[-1, -2], [-3, -4]] def test_ddm_matmul(): a = [[1, 2], [3, 4]] ddm_imul(a, 2) assert a == [[2, 4], [6, 8]] a = [[1, 2], [3, 4]] ddm_imul(a, 0) assert a == [[0, 0], [0, 0]] def test_ddm_imatmul(): a = [[1, 2, 3], [4, 5, 6]] b = [[1, 2], [3, 4], [5, 6]] c1 = [[0, 0], [0, 0]] ddm_imatmul(c1, a, b) assert c1 == [[22, 28], [49, 64]] c2 = [[0, 0, 0], [0, 0, 0], [0, 0, 0]] ddm_imatmul(c2, b, a) assert c2 == [[9, 12, 15], [19, 26, 33], [29, 40, 51]] b3 = [[1], [2], [3]] c3 = [[0], [0]] ddm_imatmul(c3, a, b3) assert c3 == [[14], [32]] def test_ddm_irref(): # Empty matrix A = [] Ar = [] pivots = [] assert ddm_irref(A) == pivots assert A == Ar # Standard square case A = [[QQ(0), QQ(1)], [QQ(1), QQ(1)]] Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]] pivots = [0, 1] assert ddm_irref(A) == pivots assert A == Ar # m < n case A = [[QQ(1), QQ(2), QQ(1)], [QQ(3), QQ(4), QQ(1)]] Ar = [[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]] pivots = [0, 1] assert ddm_irref(A) == pivots assert A == Ar # same m < n but reversed A = [[QQ(3), QQ(4), QQ(1)], [QQ(1), QQ(2), QQ(1)]] Ar = [[QQ(1), QQ(0), QQ(-1)], [QQ(0), QQ(1), QQ(1)]] pivots = [0, 1] assert ddm_irref(A) == pivots assert A == Ar # m > n case A = [[QQ(1), QQ(0)], [QQ(1), QQ(3)], [QQ(0), QQ(1)]] Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]] pivots = [0, 1] assert ddm_irref(A) == pivots assert A == Ar # Example with missing pivot A = [[QQ(1), QQ(0), QQ(1)], [QQ(3), QQ(0), QQ(1)]] Ar = [[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(0), QQ(1)]] pivots = [0, 2] assert ddm_irref(A) == pivots assert A == Ar # Example with missing pivot and no replacement A = [[QQ(0), QQ(1)], [QQ(0), QQ(2)], [QQ(1), QQ(0)]] Ar = [[QQ(1), QQ(0)], [QQ(0), QQ(1)], [QQ(0), QQ(0)]] pivots = [0, 1] assert ddm_irref(A) == pivots assert A == Ar def test_ddm_idet(): A = [] assert ddm_idet(A, ZZ) == ZZ(1) A = [[ZZ(2)]] assert ddm_idet(A, ZZ) == ZZ(2) A = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]] assert ddm_idet(A, ZZ) == ZZ(-2) A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(3), ZZ(5)]] assert ddm_idet(A, ZZ) == ZZ(-1) A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(2), ZZ(5)]] assert ddm_idet(A, ZZ) == ZZ(0) A = [[QQ(1, 2), QQ(1, 2)], [QQ(1, 3), QQ(1, 4)]] assert ddm_idet(A, QQ) == QQ(-1, 24) def test_ddm_inv(): A = [] Ainv = [] ddm_iinv(Ainv, A, QQ) assert Ainv == A A = [] Ainv = [] raises(ValueError, lambda: ddm_iinv(Ainv, A, ZZ)) A = [[QQ(1), QQ(2)]] Ainv = [[QQ(0), QQ(0)]] raises(NonSquareMatrixError, lambda: ddm_iinv(Ainv, A, QQ)) A = [[QQ(1, 1), QQ(2, 1)], [QQ(3, 1), QQ(4, 1)]] Ainv = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]] Ainv_expected = [[QQ(-2, 1), QQ(1, 1)], [QQ(3, 2), QQ(-1, 2)]] ddm_iinv(Ainv, A, QQ) assert Ainv == Ainv_expected A = [[QQ(1, 1), QQ(2, 1)], [QQ(2, 1), QQ(4, 1)]] Ainv = [[QQ(0), QQ(0)], [QQ(0), QQ(0)]] raises(NonInvertibleMatrixError, lambda: ddm_iinv(Ainv, A, QQ)) def test_ddm_ilu(): A = [] Alu = [] swaps = ddm_ilu(A) assert A == Alu assert swaps == [] A = [[]] Alu = [[]] swaps = ddm_ilu(A) assert A == Alu assert swaps == [] A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]] Alu = [[QQ(1), QQ(2)], [QQ(3), QQ(-2)]] swaps = ddm_ilu(A) assert A == Alu assert swaps == [] A = [[QQ(0), QQ(2)], [QQ(3), QQ(4)]] Alu = [[QQ(3), QQ(4)], [QQ(0), QQ(2)]] swaps = ddm_ilu(A) assert A == Alu assert swaps == [(0, 1)] A = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)], [QQ(7), QQ(8), QQ(9)]] Alu = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(-3), QQ(-6)], [QQ(7), QQ(2), QQ(0)]] swaps = ddm_ilu(A) assert A == Alu assert swaps == [] A = [[QQ(0), QQ(1), QQ(2)], [QQ(0), QQ(1), QQ(3)], [QQ(1), QQ(1), QQ(2)]] Alu = [[QQ(1), QQ(1), QQ(2)], [QQ(0), QQ(1), QQ(3)], [QQ(0), QQ(1), QQ(-1)]] swaps = ddm_ilu(A) assert A == Alu assert swaps == [(0, 2)] A = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]] Alu = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(-3), QQ(-6)]] swaps = ddm_ilu(A) assert A == Alu assert swaps == [] A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]] Alu = [[QQ(1), QQ(2)], [QQ(3), QQ(-2)], [QQ(5), QQ(2)]] swaps = ddm_ilu(A) assert A == Alu assert swaps == [] def test_ddm_ilu_split(): U = [] L = [] Uexp = [] Lexp = [] swaps = ddm_ilu_split(L, U, QQ) assert U == Uexp assert L == Lexp assert swaps == [] U = [[]] L = [[QQ(1)]] Uexp = [[]] Lexp = [[QQ(1)]] swaps = ddm_ilu_split(L, U, QQ) assert U == Uexp assert L == Lexp assert swaps == [] U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]] L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]] Uexp = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)]] Lexp = [[QQ(1), QQ(0)], [QQ(3), QQ(1)]] swaps = ddm_ilu_split(L, U, QQ) assert U == Uexp assert L == Lexp assert swaps == [] U = [[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]] L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]] Uexp = [[QQ(1), QQ(2), QQ(3)], [QQ(0), QQ(-3), QQ(-6)]] Lexp = [[QQ(1), QQ(0)], [QQ(4), QQ(1)]] swaps = ddm_ilu_split(L, U, QQ) assert U == Uexp assert L == Lexp assert swaps == [] U = [[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]] L = [[QQ(1), QQ(0), QQ(0)], [QQ(0), QQ(1), QQ(0)], [QQ(0), QQ(0), QQ(1)]] Uexp = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]] Lexp = [[QQ(1), QQ(0), QQ(0)], [QQ(3), QQ(1), QQ(0)], [QQ(5), QQ(2), QQ(1)]] swaps = ddm_ilu_split(L, U, QQ) assert U == Uexp assert L == Lexp assert swaps == [] def test_ddm_ilu_solve(): # Basic example # A = [[QQ(1), QQ(2)], [QQ(3), QQ(4)]] U = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)]] L = [[QQ(1), QQ(0)], [QQ(3), QQ(1)]] swaps = [] b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ) xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ) ddm_ilu_solve(x, L, U, swaps, b) assert x == xexp # Example with swaps # A = [[QQ(0), QQ(2)], [QQ(3), QQ(4)]] U = [[QQ(3), QQ(4)], [QQ(0), QQ(2)]] L = [[QQ(1), QQ(0)], [QQ(0), QQ(1)]] swaps = [(0, 1)] b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ) xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ) ddm_ilu_solve(x, L, U, swaps, b) assert x == xexp # Overdetermined, consistent # A = DDM([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ) U = [[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]] L = [[QQ(1), QQ(0), QQ(0)], [QQ(3), QQ(1), QQ(0)], [QQ(5), QQ(2), QQ(1)]] swaps = [] b = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ) x = DDM([[QQ(0)], [QQ(0)]], (2, 1), QQ) xexp = DDM([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ) ddm_ilu_solve(x, L, U, swaps, b) assert x == xexp # Overdetermined, inconsistent b = DDM([[QQ(1)], [QQ(2)], [QQ(4)]], (3, 1), QQ) raises(NonInvertibleMatrixError, lambda: ddm_ilu_solve(x, L, U, swaps, b)) # Square, noninvertible # A = DDM([[QQ(1), QQ(2)], [QQ(1), QQ(2)]], (2, 2), QQ) U = [[QQ(1), QQ(2)], [QQ(0), QQ(0)]] L = [[QQ(1), QQ(0)], [QQ(1), QQ(1)]] swaps = [] b = DDM([[QQ(1)], [QQ(2)]], (2, 1), QQ) raises(NonInvertibleMatrixError, lambda: ddm_ilu_solve(x, L, U, swaps, b)) # Underdetermined # A = DDM([[QQ(1), QQ(2)]], (1, 2), QQ) U = [[QQ(1), QQ(2)]] L = [[QQ(1)]] swaps = [] b = DDM([[QQ(3)]], (1, 1), QQ) raises(NotImplementedError, lambda: ddm_ilu_solve(x, L, U, swaps, b)) # Shape mismatch b3 = DDM([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ) raises(DDMShapeError, lambda: ddm_ilu_solve(x, L, U, swaps, b3)) # Empty shape mismatch U = [[QQ(1)]] L = [[QQ(1)]] swaps = [] x = [[QQ(1)]] b = [] raises(DDMShapeError, lambda: ddm_ilu_solve(x, L, U, swaps, b)) # Empty system U = [] L = [] swaps = [] b = [] x = [] ddm_ilu_solve(x, L, U, swaps, b) assert x == [] def test_ddm_charpoly(): A = [] assert ddm_berk(A, ZZ) == [[ZZ(1)]] A = [[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]] Avec = [[ZZ(1)], [ZZ(-15)], [ZZ(-18)], [ZZ(0)]] assert ddm_berk(A, ZZ) == Avec A = DDM([[ZZ(1), ZZ(2)]], (1, 2), ZZ) raises(DDMShapeError, lambda: ddm_berk(A, ZZ)) sympy-sympy-1.9/sympy/polys/matrices/tests/test_domainmatrix.py000066400000000000000000000716631412543434000253450ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy.core.numbers import Integer, Rational from sympy.core.singleton import S from sympy.functions import sqrt from sympy.matrices.common import (NonInvertibleMatrixError, NonSquareMatrixError, ShapeError) from sympy.matrices.dense import Matrix from sympy.polys.domains import ZZ, QQ, EXRAW from sympy.polys.matrices.domainmatrix import DomainMatrix, DomainScalar from sympy.polys.matrices.exceptions import (DDMBadInputError, DDMDomainError, DDMShapeError, DDMFormatError) from sympy.polys.matrices.ddm import DDM from sympy.polys.matrices.sdm import SDM def test_DomainMatrix_init(): lol = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]] dod = {0: {0: ZZ(1), 1:ZZ(2)}, 1: {0:ZZ(3), 1:ZZ(4)}} ddm = DDM(lol, (2, 2), ZZ) sdm = SDM(dod, (2, 2), ZZ) A = DomainMatrix(lol, (2, 2), ZZ) assert A.rep == ddm assert A.shape == (2, 2) assert A.domain == ZZ A = DomainMatrix(dod, (2, 2), ZZ) assert A.rep == sdm assert A.shape == (2, 2) assert A.domain == ZZ raises(TypeError, lambda: DomainMatrix(ddm, (2, 2), ZZ)) raises(TypeError, lambda: DomainMatrix(sdm, (2, 2), ZZ)) raises(TypeError, lambda: DomainMatrix(Matrix([[1]]), (1, 1), ZZ)) for fmt, rep in [('sparse', sdm), ('dense', ddm)]: A = DomainMatrix(lol, (2, 2), ZZ, fmt=fmt) assert A.rep == rep A = DomainMatrix(dod, (2, 2), ZZ, fmt=fmt) assert A.rep == rep raises(ValueError, lambda: DomainMatrix(lol, (2, 2), ZZ, fmt='invalid')) raises(DDMBadInputError, lambda: DomainMatrix([[ZZ(1), ZZ(2)]], (2, 2), ZZ)) def test_DomainMatrix_from_rep(): ddm = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) A = DomainMatrix.from_rep(ddm) assert A.rep == ddm assert A.shape == (2, 2) assert A.domain == ZZ sdm = SDM({0: {0: ZZ(1), 1:ZZ(2)}, 1: {0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ) A = DomainMatrix.from_rep(sdm) assert A.rep == sdm assert A.shape == (2, 2) assert A.domain == ZZ A = DomainMatrix([[ZZ(1)]], (1, 1), ZZ) raises(TypeError, lambda: DomainMatrix.from_rep(A)) def test_DomainMatrix_from_list_sympy(): ddm = DDM([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) A = DomainMatrix.from_list_sympy(2, 2, [[1, 2], [3, 4]]) assert A.rep == ddm assert A.shape == (2, 2) assert A.domain == ZZ K = QQ.algebraic_field(sqrt(2)) ddm = DDM( [[K.convert(1 + sqrt(2)), K.convert(2 + sqrt(2))], [K.convert(3 + sqrt(2)), K.convert(4 + sqrt(2))]], (2, 2), K ) A = DomainMatrix.from_list_sympy( 2, 2, [[1 + sqrt(2), 2 + sqrt(2)], [3 + sqrt(2), 4 + sqrt(2)]], extension=True) assert A.rep == ddm assert A.shape == (2, 2) assert A.domain == K def test_DomainMatrix_from_dict_sympy(): sdm = SDM({0: {0: QQ(1, 2)}, 1: {1: QQ(2, 3)}}, (2, 2), QQ) sympy_dict = {0: {0: Rational(1, 2)}, 1: {1: Rational(2, 3)}} A = DomainMatrix.from_dict_sympy(2, 2, sympy_dict) assert A.rep == sdm assert A.shape == (2, 2) assert A.domain == QQ fds = DomainMatrix.from_dict_sympy raises(DDMBadInputError, lambda: fds(2, 2, {3: {0: Rational(1, 2)}})) raises(DDMBadInputError, lambda: fds(2, 2, {0: {3: Rational(1, 2)}})) def test_DomainMatrix_from_Matrix(): sdm = SDM({0: {0: ZZ(1), 1: ZZ(2)}, 1: {0: ZZ(3), 1: ZZ(4)}}, (2, 2), ZZ) A = DomainMatrix.from_Matrix(Matrix([[1, 2], [3, 4]])) assert A.rep == sdm assert A.shape == (2, 2) assert A.domain == ZZ K = QQ.algebraic_field(sqrt(2)) sdm = SDM( {0: {0: K.convert(1 + sqrt(2)), 1: K.convert(2 + sqrt(2))}, 1: {0: K.convert(3 + sqrt(2)), 1: K.convert(4 + sqrt(2))}}, (2, 2), K ) A = DomainMatrix.from_Matrix( Matrix([[1 + sqrt(2), 2 + sqrt(2)], [3 + sqrt(2), 4 + sqrt(2)]]), extension=True) assert A.rep == sdm assert A.shape == (2, 2) assert A.domain == K A = DomainMatrix.from_Matrix(Matrix([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]]), fmt='dense') ddm = DDM([[QQ(1, 2), QQ(3, 4)], [QQ(0, 1), QQ(0, 1)]], (2, 2), QQ) assert A.rep == ddm assert A.shape == (2, 2) assert A.domain == QQ def test_DomainMatrix_eq(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A == A B = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(1)]], (2, 2), ZZ) assert A != B C = [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]] assert A != C def test_DomainMatrix_unify_eq(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) B1 = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) B2 = DomainMatrix([[QQ(1), QQ(3)], [QQ(3), QQ(4)]], (2, 2), QQ) B3 = DomainMatrix([[ZZ(1)]], (1, 1), ZZ) assert A.unify_eq(B1) is True assert A.unify_eq(B2) is False assert A.unify_eq(B3) is False def test_DomainMatrix_get_domain(): K, items = DomainMatrix.get_domain([1, 2, 3, 4]) assert items == [ZZ(1), ZZ(2), ZZ(3), ZZ(4)] assert K == ZZ K, items = DomainMatrix.get_domain([1, 2, 3, Rational(1, 2)]) assert items == [QQ(1), QQ(2), QQ(3), QQ(1, 2)] assert K == QQ def test_DomainMatrix_convert_to(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Aq = A.convert_to(QQ) assert Aq == DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) def test_DomainMatrix_to_sympy(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.to_sympy() == A.convert_to(EXRAW) def test_DomainMatrix_to_field(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Aq = A.to_field() assert Aq == DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) def test_DomainMatrix_to_sparse(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) A_sparse = A.to_sparse() assert A_sparse.rep == {0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}} def test_DomainMatrix_to_dense(): A = DomainMatrix({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ) A_dense = A.to_dense() assert A_dense.rep == DDM([[1, 2], [3, 4]], (2, 2), ZZ) def test_DomainMatrix_unify(): Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) assert Az.unify(Az) == (Az, Az) assert Az.unify(Aq) == (Aq, Aq) assert Aq.unify(Az) == (Aq, Aq) assert Aq.unify(Aq) == (Aq, Aq) As = DomainMatrix({0: {1: ZZ(1)}, 1:{0:ZZ(2)}}, (2, 2), ZZ) Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert As.unify(As) == (As, As) assert Ad.unify(Ad) == (Ad, Ad) Bs, Bd = As.unify(Ad, fmt='dense') assert Bs.rep == DDM([[0, 1], [2, 0]], (2, 2), ZZ) assert Bd.rep == DDM([[1, 2],[3, 4]], (2, 2), ZZ) Bs, Bd = As.unify(Ad, fmt='sparse') assert Bs.rep == SDM({0: {1: 1}, 1: {0: 2}}, (2, 2), ZZ) assert Bd.rep == SDM({0: {0: 1, 1: 2}, 1: {0: 3, 1: 4}}, (2, 2), ZZ) raises(ValueError, lambda: As.unify(Ad, fmt='invalid')) def test_DomainMatrix_to_Matrix(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.to_Matrix() == Matrix([[1, 2], [3, 4]]) def test_DomainMatrix_to_list(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.to_list() == [[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]] def test_DomainMatrix_to_list_flat(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.to_list_flat() == [ZZ(1), ZZ(2), ZZ(3), ZZ(4)] def test_DomainMatrix_to_dok(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.to_dok() == {(0, 0):ZZ(1), (0, 1):ZZ(2), (1, 0):ZZ(3), (1, 1):ZZ(4)} def test_DomainMatrix_repr(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert repr(A) == 'DomainMatrix([[1, 2], [3, 4]], (2, 2), ZZ)' def test_DomainMatrix_transpose(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) AT = DomainMatrix([[ZZ(1), ZZ(3)], [ZZ(2), ZZ(4)]], (2, 2), ZZ) assert A.transpose() == AT def test_DomainMatrix_flat(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.flat() == [ZZ(1), ZZ(2), ZZ(3), ZZ(4)] def test_DomainMatrix_is_zero_matrix(): A = DomainMatrix([[ZZ(1)]], (1, 1), ZZ) B = DomainMatrix([[ZZ(0)]], (1, 1), ZZ) assert A.is_zero_matrix is False assert B.is_zero_matrix is True def test_DomainMatrix_add(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) B = DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ) assert A + A == A.add(A) == B A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) L = [[2, 3], [3, 4]] raises(TypeError, lambda: A + L) raises(TypeError, lambda: L + A) A1 = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) A2 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ) raises(DDMShapeError, lambda: A1 + A2) raises(DDMShapeError, lambda: A2 + A1) raises(DDMShapeError, lambda: A1.add(A2)) raises(DDMShapeError, lambda: A2.add(A1)) Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) Asum = DomainMatrix([[QQ(2), QQ(4)], [QQ(6), QQ(8)]], (2, 2), QQ) assert Az + Aq == Asum assert Aq + Az == Asum raises(DDMDomainError, lambda: Az.add(Aq)) raises(DDMDomainError, lambda: Aq.add(Az)) As = DomainMatrix({0: {1: ZZ(1)}, 1: {0: ZZ(2)}}, (2, 2), ZZ) Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Asd = As + Ad Ads = Ad + As assert Asd == DomainMatrix([[1, 3], [5, 4]], (2, 2), ZZ) assert Asd.rep == DDM([[1, 3], [5, 4]], (2, 2), ZZ) assert Ads == DomainMatrix([[1, 3], [5, 4]], (2, 2), ZZ) assert Ads.rep == DDM([[1, 3], [5, 4]], (2, 2), ZZ) raises(DDMFormatError, lambda: As.add(Ad)) def test_DomainMatrix_sub(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) B = DomainMatrix([[ZZ(0), ZZ(0)], [ZZ(0), ZZ(0)]], (2, 2), ZZ) assert A - A == A.sub(A) == B A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) L = [[2, 3], [3, 4]] raises(TypeError, lambda: A - L) raises(TypeError, lambda: L - A) A1 = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) A2 = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ) raises(DDMShapeError, lambda: A1 - A2) raises(DDMShapeError, lambda: A2 - A1) raises(DDMShapeError, lambda: A1.sub(A2)) raises(DDMShapeError, lambda: A2.sub(A1)) Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) Adiff = DomainMatrix([[QQ(0), QQ(0)], [QQ(0), QQ(0)]], (2, 2), QQ) assert Az - Aq == Adiff assert Aq - Az == Adiff raises(DDMDomainError, lambda: Az.sub(Aq)) raises(DDMDomainError, lambda: Aq.sub(Az)) As = DomainMatrix({0: {1: ZZ(1)}, 1: {0: ZZ(2)}}, (2, 2), ZZ) Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Asd = As - Ad Ads = Ad - As assert Asd == DomainMatrix([[-1, -1], [-1, -4]], (2, 2), ZZ) assert Asd.rep == DDM([[-1, -1], [-1, -4]], (2, 2), ZZ) assert Asd == -Ads assert Asd.rep == -Ads.rep def test_DomainMatrix_neg(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Aneg = DomainMatrix([[ZZ(-1), ZZ(-2)], [ZZ(-3), ZZ(-4)]], (2, 2), ZZ) assert -A == A.neg() == Aneg def test_DomainMatrix_mul(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) A2 = DomainMatrix([[ZZ(7), ZZ(10)], [ZZ(15), ZZ(22)]], (2, 2), ZZ) assert A*A == A.matmul(A) == A2 A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) L = [[1, 2], [3, 4]] raises(TypeError, lambda: A * L) raises(TypeError, lambda: L * A) Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Aq = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) Aprod = DomainMatrix([[QQ(7), QQ(10)], [QQ(15), QQ(22)]], (2, 2), QQ) assert Az * Aq == Aprod assert Aq * Az == Aprod raises(DDMDomainError, lambda: Az.matmul(Aq)) raises(DDMDomainError, lambda: Aq.matmul(Az)) A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) AA = DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ) x = ZZ(2) assert A * x == x * A == A.mul(x) == AA A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) AA = DomainMatrix.zeros((2, 2), ZZ) x = ZZ(0) assert A * x == x * A == A.mul(x).to_sparse() == AA As = DomainMatrix({0: {1: ZZ(1)}, 1: {0: ZZ(2)}}, (2, 2), ZZ) Ad = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) Asd = As * Ad Ads = Ad * As assert Asd == DomainMatrix([[3, 4], [2, 4]], (2, 2), ZZ) assert Asd.rep == DDM([[3, 4], [2, 4]], (2, 2), ZZ) assert Ads == DomainMatrix([[4, 1], [8, 3]], (2, 2), ZZ) assert Ads.rep == DDM([[4, 1], [8, 3]], (2, 2), ZZ) def test_DomainMatrix_mul_elementwise(): A = DomainMatrix([[ZZ(2), ZZ(2)], [ZZ(0), ZZ(0)]], (2, 2), ZZ) B = DomainMatrix([[ZZ(4), ZZ(0)], [ZZ(3), ZZ(0)]], (2, 2), ZZ) C = DomainMatrix([[ZZ(8), ZZ(0)], [ZZ(0), ZZ(0)]], (2, 2), ZZ) assert A.mul_elementwise(B) == C assert B.mul_elementwise(A) == C def test_DomainMatrix_pow(): eye = DomainMatrix.eye(2, ZZ) A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) A2 = DomainMatrix([[ZZ(7), ZZ(10)], [ZZ(15), ZZ(22)]], (2, 2), ZZ) A3 = DomainMatrix([[ZZ(37), ZZ(54)], [ZZ(81), ZZ(118)]], (2, 2), ZZ) assert A**0 == A.pow(0) == eye assert A**1 == A.pow(1) == A assert A**2 == A.pow(2) == A2 assert A**3 == A.pow(3) == A3 raises(TypeError, lambda: A ** Rational(1, 2)) raises(NotImplementedError, lambda: A ** -1) raises(NotImplementedError, lambda: A.pow(-1)) A = DomainMatrix.zeros((2, 1), ZZ) raises(NonSquareMatrixError, lambda: A ** 1) def test_DomainMatrix_scc(): Ad = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(0), ZZ(1), ZZ(0)], [ZZ(2), ZZ(0), ZZ(4)]], (3, 3), ZZ) As = Ad.to_sparse() Addm = Ad.rep Asdm = As.rep for A in [Ad, As, Addm, Asdm]: assert Ad.scc() == [[1], [0, 2]] def test_DomainMatrix_rref(): A = DomainMatrix([], (0, 1), QQ) assert A.rref() == (A, ()) A = DomainMatrix([[QQ(1)]], (1, 1), QQ) assert A.rref() == (A, (0,)) A = DomainMatrix([[QQ(0)]], (1, 1), QQ) assert A.rref() == (A, ()) A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) Ar, pivots = A.rref() assert Ar == DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ) assert pivots == (0, 1) A = DomainMatrix([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) Ar, pivots = A.rref() assert Ar == DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ) assert pivots == (0, 1) A = DomainMatrix([[QQ(0), QQ(2)], [QQ(0), QQ(4)]], (2, 2), QQ) Ar, pivots = A.rref() assert Ar == DomainMatrix([[QQ(0), QQ(1)], [QQ(0), QQ(0)]], (2, 2), QQ) assert pivots == (1,) Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) raises(ValueError, lambda: Az.rref()) def test_DomainMatrix_nullspace(): A = DomainMatrix([[QQ(1), QQ(1)], [QQ(1), QQ(1)]], (2, 2), QQ) Anull = DomainMatrix([[QQ(-1), QQ(1)]], (1, 2), QQ) assert A.nullspace() == Anull Az = DomainMatrix([[ZZ(1), ZZ(1)], [ZZ(1), ZZ(1)]], (2, 2), ZZ) raises(ValueError, lambda: Az.nullspace()) def test_DomainMatrix_solve(): # XXX: Maybe the _solve method should be changed... A = DomainMatrix([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ) b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ) particular = DomainMatrix([[1, 0]], (1, 2), QQ) nullspace = DomainMatrix([[-2, 1]], (1, 2), QQ) assert A._solve(b) == (particular, nullspace) b3 = DomainMatrix([[QQ(1)], [QQ(1)], [QQ(1)]], (3, 1), QQ) raises(ShapeError, lambda: A._solve(b3)) bz = DomainMatrix([[ZZ(1)], [ZZ(1)]], (2, 1), ZZ) raises(ValueError, lambda: A._solve(bz)) def test_DomainMatrix_inv(): A = DomainMatrix([], (0, 0), QQ) assert A.inv() == A A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) Ainv = DomainMatrix([[QQ(-2), QQ(1)], [QQ(3, 2), QQ(-1, 2)]], (2, 2), QQ) assert A.inv() == Ainv Az = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) raises(ValueError, lambda: Az.inv()) Ans = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ) raises(NonSquareMatrixError, lambda: Ans.inv()) Aninv = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(6)]], (2, 2), QQ) raises(NonInvertibleMatrixError, lambda: Aninv.inv()) def test_DomainMatrix_det(): A = DomainMatrix([], (0, 0), ZZ) assert A.det() == 1 A = DomainMatrix([[1]], (1, 1), ZZ) assert A.det() == 1 A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.det() == ZZ(-2) A = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(3), ZZ(5)]], (3, 3), ZZ) assert A.det() == ZZ(-1) A = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(1), ZZ(2), ZZ(4)], [ZZ(1), ZZ(2), ZZ(5)]], (3, 3), ZZ) assert A.det() == ZZ(0) Ans = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ) raises(NonSquareMatrixError, lambda: Ans.det()) A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) assert A.det() == QQ(-2) def test_DomainMatrix_lu(): A = DomainMatrix([], (0, 0), QQ) assert A.lu() == (A, A, []) A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) L = DomainMatrix([[QQ(1), QQ(0)], [QQ(3), QQ(1)]], (2, 2), QQ) U = DomainMatrix([[QQ(1), QQ(2)], [QQ(0), QQ(-2)]], (2, 2), QQ) swaps = [] assert A.lu() == (L, U, swaps) A = DomainMatrix([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) L = DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ) U = DomainMatrix([[QQ(3), QQ(4)], [QQ(0), QQ(2)]], (2, 2), QQ) swaps = [(0, 1)] assert A.lu() == (L, U, swaps) A = DomainMatrix([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ) L = DomainMatrix([[QQ(1), QQ(0)], [QQ(2), QQ(1)]], (2, 2), QQ) U = DomainMatrix([[QQ(1), QQ(2)], [QQ(0), QQ(0)]], (2, 2), QQ) swaps = [] assert A.lu() == (L, U, swaps) A = DomainMatrix([[QQ(0), QQ(2)], [QQ(0), QQ(4)]], (2, 2), QQ) L = DomainMatrix([[QQ(1), QQ(0)], [QQ(0), QQ(1)]], (2, 2), QQ) U = DomainMatrix([[QQ(0), QQ(2)], [QQ(0), QQ(4)]], (2, 2), QQ) swaps = [] assert A.lu() == (L, U, swaps) A = DomainMatrix([[QQ(1), QQ(2), QQ(3)], [QQ(4), QQ(5), QQ(6)]], (2, 3), QQ) L = DomainMatrix([[QQ(1), QQ(0)], [QQ(4), QQ(1)]], (2, 2), QQ) U = DomainMatrix([[QQ(1), QQ(2), QQ(3)], [QQ(0), QQ(-3), QQ(-6)]], (2, 3), QQ) swaps = [] assert A.lu() == (L, U, swaps) A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ) L = DomainMatrix([ [QQ(1), QQ(0), QQ(0)], [QQ(3), QQ(1), QQ(0)], [QQ(5), QQ(2), QQ(1)]], (3, 3), QQ) U = DomainMatrix([[QQ(1), QQ(2)], [QQ(0), QQ(-2)], [QQ(0), QQ(0)]], (3, 2), QQ) swaps = [] assert A.lu() == (L, U, swaps) A = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 1, 2]] L = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 1, 1]] U = [[1, 0, 0, 0], [0, 0, 0, 0], [0, 0, 1, 1], [0, 0, 0, 1]] to_dom = lambda rows, dom: [[dom(e) for e in row] for row in rows] A = DomainMatrix(to_dom(A, QQ), (4, 4), QQ) L = DomainMatrix(to_dom(L, QQ), (4, 4), QQ) U = DomainMatrix(to_dom(U, QQ), (4, 4), QQ) assert A.lu() == (L, U, []) A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) raises(ValueError, lambda: A.lu()) def test_DomainMatrix_lu_solve(): # Base case A = b = x = DomainMatrix([], (0, 0), QQ) assert A.lu_solve(b) == x # Basic example A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ) x = DomainMatrix([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ) assert A.lu_solve(b) == x # Example with swaps A = DomainMatrix([[QQ(0), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ) x = DomainMatrix([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ) assert A.lu_solve(b) == x # Non-invertible A = DomainMatrix([[QQ(1), QQ(2)], [QQ(2), QQ(4)]], (2, 2), QQ) b = DomainMatrix([[QQ(1)], [QQ(2)]], (2, 1), QQ) raises(NonInvertibleMatrixError, lambda: A.lu_solve(b)) # Overdetermined, consistent A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ) b = DomainMatrix([[QQ(1)], [QQ(2)], [QQ(3)]], (3, 1), QQ) x = DomainMatrix([[QQ(0)], [QQ(1, 2)]], (2, 1), QQ) assert A.lu_solve(b) == x # Overdetermined, inconsistent A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)], [QQ(5), QQ(6)]], (3, 2), QQ) b = DomainMatrix([[QQ(1)], [QQ(2)], [QQ(4)]], (3, 1), QQ) raises(NonInvertibleMatrixError, lambda: A.lu_solve(b)) # Underdetermined A = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ) b = DomainMatrix([[QQ(1)]], (1, 1), QQ) raises(NotImplementedError, lambda: A.lu_solve(b)) # Non-field A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) b = DomainMatrix([[ZZ(1)], [ZZ(2)]], (2, 1), ZZ) raises(ValueError, lambda: A.lu_solve(b)) # Shape mismatch A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) b = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ) raises(ShapeError, lambda: A.lu_solve(b)) def test_DomainMatrix_charpoly(): A = DomainMatrix([], (0, 0), ZZ) assert A.charpoly() == [ZZ(1)] A = DomainMatrix([[1]], (1, 1), ZZ) assert A.charpoly() == [ZZ(1), ZZ(-1)] A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A.charpoly() == [ZZ(1), ZZ(-5), ZZ(-2)] A = DomainMatrix([[ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ) assert A.charpoly() == [ZZ(1), ZZ(-15), ZZ(-18), ZZ(0)] Ans = DomainMatrix([[QQ(1), QQ(2)]], (1, 2), QQ) raises(NonSquareMatrixError, lambda: Ans.charpoly()) def test_DomainMatrix_eye(): A = DomainMatrix.eye(3, QQ) assert A.rep == SDM.eye((3, 3), QQ) assert A.shape == (3, 3) assert A.domain == QQ def test_DomainMatrix_zeros(): A = DomainMatrix.zeros((1, 2), QQ) assert A.rep == SDM.zeros((1, 2), QQ) assert A.shape == (1, 2) assert A.domain == QQ def test_DomainMatrix_ones(): A = DomainMatrix.ones((2, 3), QQ) assert A.rep == DDM.ones((2, 3), QQ) assert A.shape == (2, 3) assert A.domain == QQ def test_DomainMatrix_diag(): A = DomainMatrix({0:{0:ZZ(2)}, 1:{1:ZZ(3)}}, (2, 2), ZZ) assert DomainMatrix.diag([ZZ(2), ZZ(3)], ZZ) == A A = DomainMatrix({0:{0:ZZ(2)}, 1:{1:ZZ(3)}}, (3, 4), ZZ) assert DomainMatrix.diag([ZZ(2), ZZ(3)], ZZ, (3, 4)) == A def test_DomainMatrix_hstack(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) AB = DomainMatrix([ [ZZ(1), ZZ(2), ZZ(5), ZZ(6)], [ZZ(3), ZZ(4), ZZ(7), ZZ(8)]], (2, 4), ZZ) ABC = DomainMatrix([ [ZZ(1), ZZ(2), ZZ(5), ZZ(6), ZZ(9), ZZ(10)], [ZZ(3), ZZ(4), ZZ(7), ZZ(8), ZZ(11), ZZ(12)]], (2, 6), ZZ) assert A.hstack(B) == AB assert A.hstack(B, C) == ABC def test_DomainMatrix_vstack(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) B = DomainMatrix([[ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (2, 2), ZZ) C = DomainMatrix([[ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (2, 2), ZZ) AB = DomainMatrix([ [ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)], [ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)]], (4, 2), ZZ) ABC = DomainMatrix([ [ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)], [ZZ(5), ZZ(6)], [ZZ(7), ZZ(8)], [ZZ(9), ZZ(10)], [ZZ(11), ZZ(12)]], (6, 2), ZZ) assert A.vstack(B) == AB assert A.vstack(B, C) == ABC def test_DomainMatrix_applyfunc(): A = DomainMatrix([[ZZ(1), ZZ(2)]], (1, 2), ZZ) B = DomainMatrix([[ZZ(2), ZZ(4)]], (1, 2), ZZ) assert A.applyfunc(lambda x: 2*x) == B def test_DomainMatrix_scalarmul(): A = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) lamda = DomainScalar(QQ(3)/QQ(2), QQ) assert A * lamda == DomainMatrix([[QQ(3, 2), QQ(3)], [QQ(9, 2), QQ(6)]], (2, 2), QQ) assert A * 2 == DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ) assert 2 * A == DomainMatrix([[ZZ(2), ZZ(4)], [ZZ(6), ZZ(8)]], (2, 2), ZZ) assert A * DomainScalar(ZZ(0), ZZ) == DomainMatrix({}, (2, 2), ZZ) assert A * DomainScalar(ZZ(1), ZZ) == A raises(TypeError, lambda: A * 1.5) def test_DomainMatrix_truediv(): A = DomainMatrix.from_Matrix(Matrix([[1, 2], [3, 4]])) lamda = DomainScalar(QQ(3)/QQ(2), QQ) assert A / lamda == DomainMatrix({0: {0: QQ(2, 3), 1: QQ(4, 3)}, 1: {0: QQ(2), 1: QQ(8, 3)}}, (2, 2), QQ) b = DomainScalar(ZZ(1), ZZ) assert A / b == DomainMatrix({0: {0: QQ(1), 1: QQ(2)}, 1: {0: QQ(3), 1: QQ(4)}}, (2, 2), QQ) assert A / 1 == DomainMatrix({0: {0: QQ(1), 1: QQ(2)}, 1: {0: QQ(3), 1: QQ(4)}}, (2, 2), QQ) assert A / 2 == DomainMatrix({0: {0: QQ(1, 2), 1: QQ(1)}, 1: {0: QQ(3, 2), 1: QQ(2)}}, (2, 2), QQ) raises(ZeroDivisionError, lambda: A / 0) raises(TypeError, lambda: A / 1.5) raises(ZeroDivisionError, lambda: A / DomainScalar(ZZ(0), ZZ)) def test_DomainMatrix_getitem(): dM = DomainMatrix([ [ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ) assert dM[1:,:-2] == DomainMatrix([[ZZ(4)], [ZZ(7)]], (2, 1), ZZ) assert dM[2,:-2] == DomainMatrix([[ZZ(7)]], (1, 1), ZZ) assert dM[:-2,:-2] == DomainMatrix([[ZZ(1)]], (1, 1), ZZ) assert dM[:-1,0:2] == DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(4), ZZ(5)]], (2, 2), ZZ) assert dM[:, -1] == DomainMatrix([[ZZ(3)], [ZZ(6)], [ZZ(9)]], (3, 1), ZZ) assert dM[-1, :] == DomainMatrix([[ZZ(7), ZZ(8), ZZ(9)]], (1, 3), ZZ) assert dM[::-1, :] == DomainMatrix([ [ZZ(7), ZZ(8), ZZ(9)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(1), ZZ(2), ZZ(3)]], (3, 3), ZZ) raises(IndexError, lambda: dM[4, :-2]) raises(IndexError, lambda: dM[:-2, 4]) assert dM[1, 2] == DomainScalar(ZZ(6), ZZ) assert dM[-2, 2] == DomainScalar(ZZ(6), ZZ) assert dM[1, -2] == DomainScalar(ZZ(5), ZZ) assert dM[-1, -3] == DomainScalar(ZZ(7), ZZ) raises(IndexError, lambda: dM[3, 3]) raises(IndexError, lambda: dM[1, 4]) raises(IndexError, lambda: dM[-1, -4]) dM = DomainMatrix({0: {0: ZZ(1)}}, (10, 10), ZZ) assert dM[5, 5] == DomainScalar(ZZ(0), ZZ) assert dM[0, 0] == DomainScalar(ZZ(1), ZZ) dM = DomainMatrix({1: {0: 1}}, (2,1), ZZ) assert dM[0:, 0] == DomainMatrix({1: {0: 1}}, (2, 1), ZZ) raises(IndexError, lambda: dM[3, 0]) dM = DomainMatrix({2: {2: ZZ(1)}, 4: {4: ZZ(1)}}, (5, 5), ZZ) assert dM[:2,:2] == DomainMatrix({}, (2, 2), ZZ) assert dM[2:,2:] == DomainMatrix({0: {0: 1}, 2: {2: 1}}, (3, 3), ZZ) assert dM[3:,3:] == DomainMatrix({1: {1: 1}}, (2, 2), ZZ) assert dM[2:, 6:] == DomainMatrix({}, (3, 0), ZZ) def test_DomainMatrix_getitem_sympy(): dM = DomainMatrix({2: {2: ZZ(2)}, 4: {4: ZZ(1)}}, (5, 5), ZZ) val1 = dM.getitem_sympy(0, 0) assert val1 is S.Zero val2 = dM.getitem_sympy(2, 2) assert val2 == 2 and isinstance(val2, Integer) def test_DomainMatrix_extract(): dM1 = DomainMatrix([ [ZZ(1), ZZ(2), ZZ(3)], [ZZ(4), ZZ(5), ZZ(6)], [ZZ(7), ZZ(8), ZZ(9)]], (3, 3), ZZ) dM2 = DomainMatrix([ [ZZ(1), ZZ(3)], [ZZ(7), ZZ(9)]], (2, 2), ZZ) assert dM1.extract([0, 2], [0, 2]) == dM2 assert dM1.to_sparse().extract([0, 2], [0, 2]) == dM2.to_sparse() assert dM1.extract([0, -1], [0, -1]) == dM2 assert dM1.to_sparse().extract([0, -1], [0, -1]) == dM2.to_sparse() dM3 = DomainMatrix([ [ZZ(1), ZZ(2), ZZ(2)], [ZZ(4), ZZ(5), ZZ(5)], [ZZ(4), ZZ(5), ZZ(5)]], (3, 3), ZZ) assert dM1.extract([0, 1, 1], [0, 1, 1]) == dM3 assert dM1.to_sparse().extract([0, 1, 1], [0, 1, 1]) == dM3.to_sparse() empty = [ ([], [], (0, 0)), ([1], [], (1, 0)), ([], [1], (0, 1)), ] for rows, cols, size in empty: assert dM1.extract(rows, cols) == DomainMatrix.zeros(size, ZZ).to_dense() assert dM1.to_sparse().extract(rows, cols) == DomainMatrix.zeros(size, ZZ) dM = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) bad_indices = [([2], [0]), ([0], [2]), ([-3], [0]), ([0], [-3])] for rows, cols in bad_indices: raises(IndexError, lambda: dM.extract(rows, cols)) raises(IndexError, lambda: dM.to_sparse().extract(rows, cols)) def test_DomainMatrix_setitem(): dM = DomainMatrix({2: {2: ZZ(1)}, 4: {4: ZZ(1)}}, (5, 5), ZZ) dM[2, 2] = ZZ(2) assert dM == DomainMatrix({2: {2: ZZ(2)}, 4: {4: ZZ(1)}}, (5, 5), ZZ) def setitem(i, j, val): dM[i, j] = val raises(TypeError, lambda: setitem(2, 2, QQ(1, 2))) raises(NotImplementedError, lambda: setitem(slice(1, 2), 2, ZZ(1))) def test_DomainMatrix_pickling(): import pickle dM = DomainMatrix({2: {2: ZZ(1)}, 4: {4: ZZ(1)}}, (5, 5), ZZ) assert pickle.loads(pickle.dumps(dM)) == dM dM = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert pickle.loads(pickle.dumps(dM)) == dM sympy-sympy-1.9/sympy/polys/matrices/tests/test_domainscalar.py000066400000000000000000000070501412543434000252730ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy.core.symbol import S from sympy.polys import ZZ, QQ from sympy.polys.matrices.domainscalar import DomainScalar from sympy.polys.matrices.domainmatrix import DomainMatrix def test_DomainScalar___new__(): raises(TypeError, lambda: DomainScalar(ZZ(1), QQ)) raises(TypeError, lambda: DomainScalar(ZZ(1), 1)) def test_DomainScalar_new(): A = DomainScalar(ZZ(1), ZZ) B = A.new(ZZ(4), ZZ) assert B == DomainScalar(ZZ(4), ZZ) def test_DomainScalar_repr(): A = DomainScalar(ZZ(1), ZZ) assert repr(A) in {'1', 'mpz(1)'} def test_DomainScalar_from_sympy(): expr = S(1) B = DomainScalar.from_sympy(expr) assert B == DomainScalar(ZZ(1), ZZ) def test_DomainScalar_to_sympy(): B = DomainScalar(ZZ(1), ZZ) expr = B.to_sympy() assert expr.is_Integer and expr == 1 def test_DomainScalar_to_domain(): A = DomainScalar(ZZ(1), ZZ) B = A.to_domain(QQ) assert B == DomainScalar(QQ(1), QQ) def test_DomainScalar_convert_to(): A = DomainScalar(ZZ(1), ZZ) B = A.convert_to(QQ) assert B == DomainScalar(QQ(1), QQ) def test_DomainScalar_unify(): A = DomainScalar(ZZ(1), ZZ) B = DomainScalar(QQ(2), QQ) A, B = A.unify(B) assert A.domain == B.domain == QQ def test_DomainScalar_add(): A = DomainScalar(ZZ(1), ZZ) B = DomainScalar(QQ(2), QQ) assert A + B == DomainScalar(QQ(3), QQ) raises(TypeError, lambda: A + 1.5) def test_DomainScalar_sub(): A = DomainScalar(ZZ(1), ZZ) B = DomainScalar(QQ(2), QQ) assert A - B == DomainScalar(QQ(-1), QQ) raises(TypeError, lambda: A - 1.5) def test_DomainScalar_mul(): A = DomainScalar(ZZ(1), ZZ) B = DomainScalar(QQ(2), QQ) dm = DomainMatrix([[ZZ(1), ZZ(2)], [ZZ(3), ZZ(4)]], (2, 2), ZZ) assert A * B == DomainScalar(QQ(2), QQ) assert A * dm == dm assert B * 2 == DomainScalar(QQ(4), QQ) raises(TypeError, lambda: A * 1.5) def test_DomainScalar_floordiv(): A = DomainScalar(ZZ(-5), ZZ) B = DomainScalar(QQ(2), QQ) assert A // B == DomainScalar(QQ(-5, 2), QQ) C = DomainScalar(ZZ(2), ZZ) assert A // C == DomainScalar(ZZ(-3), ZZ) raises(TypeError, lambda: A // 1.5) def test_DomainScalar_mod(): A = DomainScalar(ZZ(5), ZZ) B = DomainScalar(QQ(2), QQ) assert A % B == DomainScalar(QQ(0), QQ) C = DomainScalar(ZZ(2), ZZ) assert A % C == DomainScalar(ZZ(1), ZZ) raises(TypeError, lambda: A % 1.5) def test_DomainScalar_divmod(): A = DomainScalar(ZZ(5), ZZ) B = DomainScalar(QQ(2), QQ) assert divmod(A, B) == (DomainScalar(QQ(5, 2), QQ), DomainScalar(QQ(0), QQ)) C = DomainScalar(ZZ(2), ZZ) assert divmod(A, C) == (DomainScalar(ZZ(2), ZZ), DomainScalar(ZZ(1), ZZ)) raises(TypeError, lambda: divmod(A, 1.5)) def test_DomainScalar_pow(): A = DomainScalar(ZZ(-5), ZZ) B = A**(2) assert B == DomainScalar(ZZ(25), ZZ) raises(TypeError, lambda: A**(1.5)) def test_DomainScalar_pos(): A = DomainScalar(QQ(2), QQ) B = DomainScalar(QQ(2), QQ) assert +A == B def test_DomainScalar_eq(): A = DomainScalar(QQ(2), QQ) assert A == A B = DomainScalar(ZZ(-5), ZZ) assert A != B C = DomainScalar(ZZ(2), ZZ) assert A != C D = [1] assert A != D def test_DomainScalar_isZero(): A = DomainScalar(ZZ(0), ZZ) assert A.is_zero() == True B = DomainScalar(ZZ(1), ZZ) assert B.is_zero() == False def test_DomainScalar_isOne(): A = DomainScalar(ZZ(1), ZZ) assert A.is_one() == True B = DomainScalar(ZZ(0), ZZ) assert B.is_one() == False sympy-sympy-1.9/sympy/polys/matrices/tests/test_eigen.py000066400000000000000000000060351412543434000237270ustar00rootroot00000000000000""" Tests for the sympy.polys.matrices.eigen module """ from sympy import S, Matrix, sqrt from sympy.polys.agca.extensions import FiniteExtension from sympy.polys.domains import QQ from sympy.polys.polytools import Poly from sympy.polys.rootoftools import CRootOf from sympy.polys.matrices.domainmatrix import DomainMatrix from sympy.polys.matrices.eigen import dom_eigenvects, dom_eigenvects_to_sympy def test_dom_eigenvects_rational(): # Rational eigenvalues A = DomainMatrix([[QQ(1), QQ(2)], [QQ(1), QQ(2)]], (2, 2), QQ) rational_eigenvects = [ (QQ, QQ(3), 1, DomainMatrix([[QQ(1), QQ(1)]], (1, 2), QQ)), (QQ, QQ(0), 1, DomainMatrix([[QQ(-2), QQ(1)]], (1, 2), QQ)), ] assert dom_eigenvects(A) == (rational_eigenvects, []) # Test converting to Expr: sympy_eigenvects = [ (S(3), 1, [Matrix([1, 1])]), (S(0), 1, [Matrix([-2, 1])]), ] assert dom_eigenvects_to_sympy(rational_eigenvects, [], Matrix) == sympy_eigenvects def test_dom_eigenvects_algebraic(): # Algebraic eigenvalues A = DomainMatrix([[QQ(1), QQ(2)], [QQ(3), QQ(4)]], (2, 2), QQ) Avects = dom_eigenvects(A) # Extract the dummy to build the expected result: lamda = Avects[1][0][1].gens[0] irreducible = Poly(lamda**2 - 5*lamda - 2, lamda, domain=QQ) K = FiniteExtension(irreducible) KK = K.from_sympy algebraic_eigenvects = [ (K, irreducible, 1, DomainMatrix([[KK((lamda-4)/3), KK(1)]], (1, 2), K)), ] assert Avects == ([], algebraic_eigenvects) # Test converting to Expr: sympy_eigenvects = [ (S(5)/2 - sqrt(33)/2, 1, [Matrix([[-sqrt(33)/6 - S(1)/2], [1]])]), (S(5)/2 + sqrt(33)/2, 1, [Matrix([[-S(1)/2 + sqrt(33)/6], [1]])]), ] assert dom_eigenvects_to_sympy([], algebraic_eigenvects, Matrix) == sympy_eigenvects def test_dom_eigenvects_rootof(): # Algebraic eigenvalues A = DomainMatrix([ [0, 0, 0, 0, -1], [1, 0, 0, 0, 1], [0, 1, 0, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 0]], (5, 5), QQ) Avects = dom_eigenvects(A) # Extract the dummy to build the expected result: lamda = Avects[1][0][1].gens[0] irreducible = Poly(lamda**5 - lamda + 1, lamda, domain=QQ) K = FiniteExtension(irreducible) KK = K.from_sympy algebraic_eigenvects = [ (K, irreducible, 1, DomainMatrix([ [KK(lamda**4-1), KK(lamda**3), KK(lamda**2), KK(lamda), KK(1)] ], (1, 5), K)), ] assert Avects == ([], algebraic_eigenvects) # Test converting to Expr (slow): l0, l1, l2, l3, l4 = [CRootOf(lamda**5 - lamda + 1, i) for i in range(5)] sympy_eigenvects = [ (l0, 1, [Matrix([-1 + l0**4, l0**3, l0**2, l0, 1])]), (l1, 1, [Matrix([-1 + l1**4, l1**3, l1**2, l1, 1])]), (l2, 1, [Matrix([-1 + l2**4, l2**3, l2**2, l2, 1])]), (l3, 1, [Matrix([-1 + l3**4, l3**3, l3**2, l3, 1])]), (l4, 1, [Matrix([-1 + l4**4, l4**3, l4**2, l4, 1])]), ] assert dom_eigenvects_to_sympy([], algebraic_eigenvects, Matrix) == sympy_eigenvects sympy-sympy-1.9/sympy/polys/matrices/tests/test_linsolve.py000066400000000000000000000061541412543434000244750ustar00rootroot00000000000000# # test_linsolve.py # # Test the internal implementation of linsolve. # from sympy.testing.pytest import raises from sympy import S, Eq, I from sympy.abc import x, y, z from sympy.polys.matrices.linsolve import _linsolve from sympy.polys.solvers import PolyNonlinearError def test__linsolve(): assert _linsolve([], [x]) == {x:x} assert _linsolve([S.Zero], [x]) == {x:x} assert _linsolve([x-1,x-2], [x]) is None assert _linsolve([x-1], [x]) == {x:1} assert _linsolve([x-1, y], [x, y]) == {x:1, y:S.Zero} assert _linsolve([2*I], [x]) is None raises(PolyNonlinearError, lambda: _linsolve([x*(1 + x)], [x])) def test__linsolve_float(): # This should give the exact answer: eqs = [ y - x, y - 0.0216 * x ] sol = {x:0.0, y:0.0} assert _linsolve(eqs, (x, y)) == sol # Other cases should be close to eps def all_close(sol1, sol2, eps=1e-15): close = lambda a, b: abs(a - b) < eps assert sol1.keys() == sol2.keys() return all(close(sol1[s], sol2[s]) for s in sol1) eqs = [ 0.8*x + 0.8*z + 0.2, 0.9*x + 0.7*y + 0.2*z + 0.9, 0.7*x + 0.2*y + 0.2*z + 0.5 ] sol_exact = {x:-29/42, y:-11/21, z:37/84} sol_linsolve = _linsolve(eqs, [x,y,z]) assert all_close(sol_exact, sol_linsolve) eqs = [ 0.9*x + 0.3*y + 0.4*z + 0.6, 0.6*x + 0.9*y + 0.1*z + 0.7, 0.4*x + 0.6*y + 0.9*z + 0.5 ] sol_exact = {x:-88/175, y:-46/105, z:-1/25} sol_linsolve = _linsolve(eqs, [x,y,z]) assert all_close(sol_exact, sol_linsolve) eqs = [ 0.4*x + 0.3*y + 0.6*z + 0.7, 0.4*x + 0.3*y + 0.9*z + 0.9, 0.7*x + 0.9*y, ] sol_exact = {x:-9/5, y:7/5, z:-2/3} sol_linsolve = _linsolve(eqs, [x,y,z]) assert all_close(sol_exact, sol_linsolve) eqs = [ x*(0.7 + 0.6*I) + y*(0.4 + 0.7*I) + z*(0.9 + 0.1*I) + 0.5, 0.2*I*x + 0.2*I*y + z*(0.9 + 0.2*I) + 0.1, x*(0.9 + 0.7*I) + y*(0.9 + 0.7*I) + z*(0.9 + 0.4*I) + 0.4, ] sol_exact = { x:-6157/7995 - 411/5330*I, y:8519/15990 + 1784/7995*I, z:-34/533 + 107/1599*I, } sol_linsolve = _linsolve(eqs, [x,y,z]) assert all_close(sol_exact, sol_linsolve) # XXX: This system for x and y over RR(z) is problematic. # # eqs = [ # x*(0.2*z + 0.9) + y*(0.5*z + 0.8) + 0.6, # 0.1*x*z + y*(0.1*z + 0.6) + 0.9, # ] # # linsolve(eqs, [x, y]) # The solution for x comes out as # # -3.9e-5*z**2 - 3.6e-5*z - 8.67361737988404e-20 # x = ---------------------------------------------- # 3.0e-6*z**3 - 1.3e-5*z**2 - 5.4e-5*z # # The 8e-20 in the numerator should be zero which would allow z to cancel # from top and bottom. It should be possible to avoid this somehow because # the inverse of the matrix only has a quadratic factor (the determinant) # in the denominator. def test__linsolve_deprecated(): assert _linsolve([Eq(x**2, x**2+y)], [x, y]) == {x:x, y:S.Zero} assert _linsolve([(x+y)**2-x**2], [x]) == {x:-y/2} assert _linsolve([Eq((x+y)**2, x**2)], [x]) == {x:-y/2} sympy-sympy-1.9/sympy/polys/matrices/tests/test_normalforms.py000066400000000000000000000030171412543434000251740ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy import Symbol, sympify from sympy.polys.matrices.normalforms import invariant_factors, smith_normal_form from sympy.polys.domains import ZZ, QQ from sympy.polys.matrices import DomainMatrix def test_smith_normal(): def DM(elems, domain): conv = lambda e: domain.from_sympy(sympify(e)) elems = [[conv(e) for e in row] for row in elems] return DomainMatrix(elems, (len(elems), len(elems[0])), domain) m = DM([[12, 6, 4, 8], [3, 9, 6, 12], [2, 16, 14, 28], [20, 10, 10, 20]], ZZ) smf = DM([[1, 0, 0, 0], [0, 10, 0, 0], [0, 0, -30, 0], [0, 0, 0, 0]], ZZ) assert smith_normal_form(m).to_dense() == smf x = Symbol('x') m = DM([[x-1, 1, -1], [ 0, x, -1], [ 0, -1, x]], QQ[x]) dx = m.domain.gens[0] assert invariant_factors(m) == (1, dx-1, dx**2-1) zr = DomainMatrix([], (0, 2), ZZ) zc = DomainMatrix([[], []], (2, 0), ZZ) assert smith_normal_form(zr).to_dense() == zr assert smith_normal_form(zc).to_dense() == zc assert smith_normal_form(DM([[2, 4]], ZZ)).to_dense() == DM([[2, 0]], ZZ) assert smith_normal_form(DM([[0, -2]], ZZ)).to_dense() == DM([[-2, 0]], ZZ) assert smith_normal_form(DM([[0], [-2]], ZZ)).to_dense() == DM([[-2], [0]], ZZ) m = DM([[3, 0, 0, 0], [0, 0, 0, 0], [0, 0, 2, 0]], ZZ) snf = DM([[1, 0, 0, 0], [0, 6, 0, 0], [0, 0, 0, 0]], ZZ) assert smith_normal_form(m).to_dense() == snf raises(ValueError, lambda: smith_normal_form(DM([[1]], ZZ[x]))) sympy-sympy-1.9/sympy/polys/matrices/tests/test_sdm.py000066400000000000000000000307721412543434000234300ustar00rootroot00000000000000""" Tests for the basic functionality of the SDM class. """ from itertools import product from sympy import S from sympy.core.compatibility import HAS_GMPY from sympy.testing.pytest import raises from sympy.polys.domains import QQ, ZZ, EXRAW from sympy.polys.matrices.sdm import SDM from sympy.polys.matrices.ddm import DDM from sympy.polys.matrices.exceptions import (DDMBadInputError, DDMDomainError, DDMShapeError) def test_SDM(): A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ) assert A.domain == ZZ assert A.shape == (2, 2) assert dict(A) == {0:{0:ZZ(1)}} raises(DDMBadInputError, lambda: SDM({5:{1:ZZ(0)}}, (2, 2), ZZ)) raises(DDMBadInputError, lambda: SDM({0:{5:ZZ(0)}}, (2, 2), ZZ)) def test_DDM_str(): sdm = SDM({0:{0:ZZ(1)}, 1:{1:ZZ(1)}}, (2, 2), ZZ) assert str(sdm) == '{0: {0: 1}, 1: {1: 1}}' if HAS_GMPY: # pragma: no cover assert repr(sdm) == 'SDM({0: {0: mpz(1)}, 1: {1: mpz(1)}}, (2, 2), ZZ)' else: # pragma: no cover assert repr(sdm) == 'SDM({0: {0: 1}, 1: {1: 1}}, (2, 2), ZZ)' def test_SDM_new(): A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ) B = A.new({}, (2, 2), ZZ) assert B == SDM({}, (2, 2), ZZ) def test_SDM_copy(): A = SDM({0:{0:ZZ(1)}}, (2, 2), ZZ) B = A.copy() assert A == B A[0][0] = ZZ(2) assert A != B def test_SDM_from_list(): A = SDM.from_list([[ZZ(0), ZZ(1)], [ZZ(1), ZZ(0)]], (2, 2), ZZ) assert A == SDM({0:{1:ZZ(1)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) raises(DDMBadInputError, lambda: SDM.from_list([[ZZ(0)], [ZZ(0), ZZ(1)]], (2, 2), ZZ)) raises(DDMBadInputError, lambda: SDM.from_list([[ZZ(0), ZZ(1)]], (2, 2), ZZ)) def test_SDM_to_list(): A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ) assert A.to_list() == [[ZZ(0), ZZ(1)], [ZZ(0), ZZ(0)]] A = SDM({}, (0, 2), ZZ) assert A.to_list() == [] A = SDM({}, (2, 0), ZZ) assert A.to_list() == [[], []] def test_SDM_to_list_flat(): A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ) assert A.to_list_flat() == [ZZ(0), ZZ(1), ZZ(0), ZZ(0)] def test_SDM_to_dok(): A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ) assert A.to_dok() == {(0, 1): ZZ(1)} def test_SDM_from_ddm(): A = DDM([[ZZ(1), ZZ(0)], [ZZ(1), ZZ(0)]], (2, 2), ZZ) B = SDM.from_ddm(A) assert B.domain == ZZ assert B.shape == (2, 2) assert dict(B) == {0:{0:ZZ(1)}, 1:{0:ZZ(1)}} def test_SDM_to_ddm(): A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ) B = DDM([[ZZ(0), ZZ(1)], [ZZ(0), ZZ(0)]], (2, 2), ZZ) assert A.to_ddm() == B def test_SDM_to_sdm(): A = SDM({0:{1: ZZ(1)}}, (2, 2), ZZ) assert A.to_sdm() == A def test_SDM_getitem(): A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) assert A.getitem(0, 0) == ZZ.zero assert A.getitem(0, 1) == ZZ.one assert A.getitem(1, 0) == ZZ.zero assert A.getitem(-2, -2) == ZZ.zero assert A.getitem(-2, -1) == ZZ.one assert A.getitem(-1, -2) == ZZ.zero raises(IndexError, lambda: A.getitem(2, 0)) raises(IndexError, lambda: A.getitem(0, 2)) def test_SDM_setitem(): A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) A.setitem(0, 0, ZZ(1)) assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ) A.setitem(1, 0, ZZ(1)) assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{0:ZZ(1)}}, (2, 2), ZZ) A.setitem(1, 0, ZZ(0)) assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ) # Repeat the above test so that this time the row is empty A.setitem(1, 0, ZZ(0)) assert A == SDM({0:{0:ZZ(1), 1:ZZ(1)}}, (2, 2), ZZ) A.setitem(0, 0, ZZ(0)) assert A == SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) # This time the row is there but column is empty A.setitem(0, 0, ZZ(0)) assert A == SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) raises(IndexError, lambda: A.setitem(2, 0, ZZ(1))) raises(IndexError, lambda: A.setitem(0, 2, ZZ(1))) def test_SDM_extract_slice(): A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ) B = A.extract_slice(slice(1, 2), slice(1, 2)) assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ) def test_SDM_extract(): A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ) B = A.extract([1], [1]) assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ) B = A.extract([1, 0], [1, 0]) assert B == SDM({0:{0:ZZ(4), 1:ZZ(3)}, 1:{0:ZZ(2), 1:ZZ(1)}}, (2, 2), ZZ) B = A.extract([1, 1], [1, 1]) assert B == SDM({0:{0:ZZ(4), 1:ZZ(4)}, 1:{0:ZZ(4), 1:ZZ(4)}}, (2, 2), ZZ) B = A.extract([-1], [-1]) assert B == SDM({0:{0:ZZ(4)}}, (1, 1), ZZ) A = SDM({}, (2, 2), ZZ) B = A.extract([0, 1, 0], [0, 0]) assert B == SDM({}, (3, 2), ZZ) A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ) assert A.extract([], []) == SDM.zeros((0, 0), ZZ) assert A.extract([1], []) == SDM.zeros((1, 0), ZZ) assert A.extract([], [1]) == SDM.zeros((0, 1), ZZ) raises(IndexError, lambda: A.extract([2], [0])) raises(IndexError, lambda: A.extract([0], [2])) raises(IndexError, lambda: A.extract([-3], [0])) raises(IndexError, lambda: A.extract([0], [-3])) def test_SDM_zeros(): A = SDM.zeros((2, 2), ZZ) assert A.domain == ZZ assert A.shape == (2, 2) assert dict(A) == {} def test_SDM_ones(): A = SDM.ones((1, 2), QQ) assert A.domain == QQ assert A.shape == (1, 2) assert dict(A) == {0:{0:QQ(1), 1:QQ(1)}} def test_SDM_eye(): A = SDM.eye((2, 2), ZZ) assert A.domain == ZZ assert A.shape == (2, 2) assert dict(A) == {0:{0:ZZ(1)}, 1:{1:ZZ(1)}} def test_SDM_diag(): A = SDM.diag([ZZ(1), ZZ(2)], ZZ, (2, 3)) assert A == SDM({0:{0:ZZ(1)}, 1:{1:ZZ(2)}}, (2, 3), ZZ) def test_SDM_transpose(): A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(1), 1:ZZ(3)}, 1:{0:ZZ(2), 1:ZZ(4)}}, (2, 2), ZZ) assert A.transpose() == B A = SDM({0:{1:ZZ(2)}}, (2, 2), ZZ) B = SDM({1:{0:ZZ(2)}}, (2, 2), ZZ) assert A.transpose() == B A = SDM({0:{1:ZZ(2)}}, (1, 2), ZZ) B = SDM({1:{0:ZZ(2)}}, (2, 1), ZZ) assert A.transpose() == B def test_SDM_mul(): A = SDM({0:{0:ZZ(2)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ) assert A*ZZ(2) == B assert ZZ(2)*A == B raises(TypeError, lambda: A*QQ(1, 2)) raises(TypeError, lambda: QQ(1, 2)*A) def test_SDM_mul_elementwise(): A = SDM({0:{0:ZZ(2), 1:ZZ(2)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(4)}, 1:{0:ZZ(3)}}, (2, 2), ZZ) C = SDM({0:{0:ZZ(8)}}, (2, 2), ZZ) assert A.mul_elementwise(B) == C assert B.mul_elementwise(A) == C Aq = A.convert_to(QQ) A1 = SDM({0:{0:ZZ(1)}}, (1, 1), ZZ) raises(DDMDomainError, lambda: Aq.mul_elementwise(B)) raises(DDMShapeError, lambda: A1.mul_elementwise(B)) def test_SDM_matmul(): A = SDM({0:{0:ZZ(2)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ) assert A.matmul(A) == A*A == B C = SDM({0:{0:ZZ(2)}}, (2, 2), QQ) raises(DDMDomainError, lambda: A.matmul(C)) A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(7), 1:ZZ(10)}, 1:{0:ZZ(15), 1:ZZ(22)}}, (2, 2), ZZ) assert A.matmul(A) == A*A == B A22 = SDM({0:{0:ZZ(4)}}, (2, 2), ZZ) A32 = SDM({0:{0:ZZ(2)}}, (3, 2), ZZ) A23 = SDM({0:{0:ZZ(4)}}, (2, 3), ZZ) A33 = SDM({0:{0:ZZ(8)}}, (3, 3), ZZ) A22 = SDM({0:{0:ZZ(8)}}, (2, 2), ZZ) assert A32.matmul(A23) == A33 assert A23.matmul(A32) == A22 # XXX: @ not supported by SDM... #assert A32.matmul(A23) == A32 @ A23 == A33 #assert A23.matmul(A32) == A23 @ A32 == A22 #raises(DDMShapeError, lambda: A23 @ A22) raises(DDMShapeError, lambda: A23.matmul(A22)) A = SDM({0: {0: ZZ(-1), 1: ZZ(1)}}, (1, 2), ZZ) B = SDM({0: {0: ZZ(-1)}, 1: {0: ZZ(-1)}}, (2, 1), ZZ) assert A.matmul(B) == A*B == SDM({}, (1, 1), ZZ) def test_matmul_exraw(): def dm(d): result = {} for i, row in d.items(): row = {j:val for j, val in row.items() if val} if row: result[i] = row return SDM(result, (2, 2), EXRAW) values = [S.NegativeInfinity, S.NegativeOne, S.Zero, S.One, S.Infinity] for a, b, c, d in product(*[values]*4): Ad = dm({0: {0:a, 1:b}, 1: {0:c, 1:d}}) Ad2 = dm({0: {0:a*a + b*c, 1:a*b + b*d}, 1:{0:c*a + d*c, 1: c*b + d*d}}) assert Ad * Ad == Ad2 def test_SDM_add(): A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ) C = SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{1:ZZ(6)}}, (2, 2), ZZ) assert A.add(B) == B.add(A) == A + B == B + A == C A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ) C = SDM({0:{0:ZZ(1), 1:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ) assert A.add(B) == B.add(A) == A + B == B + A == C raises(TypeError, lambda: A + []) def test_SDM_sub(): A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ) B = SDM({0:{0:ZZ(1)}, 1:{0:ZZ(-2), 1:ZZ(3)}}, (2, 2), ZZ) C = SDM({0:{0:ZZ(-1), 1:ZZ(1)}, 1:{0:ZZ(4)}}, (2, 2), ZZ) assert A.sub(B) == A - B == C raises(TypeError, lambda: A - []) def test_SDM_neg(): A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ) B = SDM({0:{1:ZZ(-1)}, 1:{0:ZZ(-2), 1:ZZ(-3)}}, (2, 2), ZZ) assert A.neg() == -A == B def test_SDM_convert_to(): A = SDM({0:{1:ZZ(1)}, 1:{0:ZZ(2), 1:ZZ(3)}}, (2, 2), ZZ) B = SDM({0:{1:QQ(1)}, 1:{0:QQ(2), 1:QQ(3)}}, (2, 2), QQ) C = A.convert_to(QQ) assert C == B assert C.domain == QQ D = A.convert_to(ZZ) assert D == A assert D.domain == ZZ def test_SDM_hstack(): A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) B = SDM({1:{1:ZZ(1)}}, (2, 2), ZZ) AA = SDM({0:{1:ZZ(1), 3:ZZ(1)}}, (2, 4), ZZ) AB = SDM({0:{1:ZZ(1)}, 1:{3:ZZ(1)}}, (2, 4), ZZ) assert SDM.hstack(A) == A assert SDM.hstack(A, A) == AA assert SDM.hstack(A, B) == AB def test_SDM_vstack(): A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) B = SDM({1:{1:ZZ(1)}}, (2, 2), ZZ) AA = SDM({0:{1:ZZ(1)}, 2:{1:ZZ(1)}}, (4, 2), ZZ) AB = SDM({0:{1:ZZ(1)}, 3:{1:ZZ(1)}}, (4, 2), ZZ) assert SDM.vstack(A) == A assert SDM.vstack(A, A) == AA assert SDM.vstack(A, B) == AB def test_SDM_applyfunc(): A = SDM({0:{1:ZZ(1)}}, (2, 2), ZZ) B = SDM({0:{1:ZZ(2)}}, (2, 2), ZZ) assert A.applyfunc(lambda x: 2*x, ZZ) == B def test_SDM_inv(): A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) B = SDM({0:{0:QQ(-2), 1:QQ(1)}, 1:{0:QQ(3, 2), 1:QQ(-1, 2)}}, (2, 2), QQ) assert A.inv() == B def test_SDM_det(): A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) assert A.det() == QQ(-2) def test_SDM_lu(): A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) L = SDM({0:{0:QQ(1)}, 1:{0:QQ(3), 1:QQ(1)}}, (2, 2), QQ) #U = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(-2)}}, (2, 2), QQ) #swaps = [] # This doesn't quite work. U has some nonzero elements in the lower part. #assert A.lu() == (L, U, swaps) assert A.lu()[0] == L def test_SDM_lu_solve(): A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) b = SDM({0:{0:QQ(1)}, 1:{0:QQ(2)}}, (2, 1), QQ) x = SDM({1:{0:QQ(1, 2)}}, (2, 1), QQ) assert A.matmul(x) == b assert A.lu_solve(b) == x def test_SDM_charpoly(): A = SDM({0:{0:ZZ(1), 1:ZZ(2)}, 1:{0:ZZ(3), 1:ZZ(4)}}, (2, 2), ZZ) assert A.charpoly() == [ZZ(1), ZZ(-5), ZZ(-2)] def test_SDM_nullspace(): A = SDM({0:{0:QQ(1), 1:QQ(1)}}, (2, 2), QQ) assert A.nullspace()[0] == SDM({0:{0:QQ(-1), 1:QQ(1)}}, (1, 2), QQ) def test_SDM_rref(): eye2 = SDM({0:{0:QQ(1)}, 1:{1:QQ(1)}}, (2, 2), QQ) A = SDM({0:{0:QQ(1), 1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) assert A.rref() == (eye2, [0, 1]) A = SDM({0:{0:QQ(1)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) assert A.rref() == (eye2, [0, 1]) A = SDM({0:{1:QQ(2)}, 1:{0:QQ(3), 1:QQ(4)}}, (2, 2), QQ) assert A.rref() == (eye2, [0, 1]) A = SDM({0:{0:QQ(1), 1:QQ(2), 2:QQ(3)}, 1:{0:QQ(4), 1:QQ(5), 2:QQ(6)}, 2:{0:QQ(7), 1:QQ(8), 2:QQ(9)} }, (3, 3), QQ) Arref = SDM({0:{0:QQ(1), 2:QQ(-1)}, 1:{1:QQ(1), 2:QQ(2)}}, (3, 3), QQ) assert A.rref() == (Arref, [0, 1]) A = SDM({0:{0:QQ(1), 1:QQ(2), 3:QQ(1)}, 1:{0:QQ(1), 1:QQ(1), 2:QQ(9)}}, (2, 4), QQ) Arref = SDM({0:{0:QQ(1), 2:QQ(18), 3:QQ(-1)}, 1:{1:QQ(1), 2:QQ(-9), 3:QQ(1)}}, (2, 4), QQ) assert A.rref() == (Arref, [0, 1]) A = SDM({0:{0:QQ(1), 1:QQ(1), 2:QQ(1)}, 1:{0:QQ(1), 1:QQ(2), 2:QQ(2)}}, (2, 3), QQ) Arref = SDM( {0: {0: QQ(1,1)}, 1: {1: QQ(1,1), 2: QQ(1,1)}}, (2, 3), QQ) assert A.rref() == (Arref, [0, 1]) def test_SDM_particular(): A = SDM({0:{0:QQ(1)}}, (2, 2), QQ) Apart = SDM.zeros((1, 2), QQ) assert A.particular() == Apart sympy-sympy-1.9/sympy/polys/modulargcd.py000066400000000000000000001624341412543434000207570ustar00rootroot00000000000000from sympy import Dummy from sympy.ntheory import nextprime from sympy.ntheory.modular import crt from sympy.polys.domains import PolynomialRing from sympy.polys.galoistools import ( gf_gcd, gf_from_dict, gf_gcdex, gf_div, gf_lcm) from sympy.polys.polyerrors import ModularGCDFailed from mpmath import sqrt import random def _trivial_gcd(f, g): """ Compute the GCD of two polynomials in trivial cases, i.e. when one or both polynomials are zero. """ ring = f.ring if not (f or g): return ring.zero, ring.zero, ring.zero elif not f: if g.LC < ring.domain.zero: return -g, ring.zero, -ring.one else: return g, ring.zero, ring.one elif not g: if f.LC < ring.domain.zero: return -f, -ring.one, ring.zero else: return f, ring.one, ring.zero return None def _gf_gcd(fp, gp, p): r""" Compute the GCD of two univariate polynomials in `\mathbb{Z}_p[x]`. """ dom = fp.ring.domain while gp: rem = fp deg = gp.degree() lcinv = dom.invert(gp.LC, p) while True: degrem = rem.degree() if degrem < deg: break rem = (rem - gp.mul_monom((degrem - deg,)).mul_ground(lcinv * rem.LC)).trunc_ground(p) fp = gp gp = rem return fp.mul_ground(dom.invert(fp.LC, p)).trunc_ground(p) def _degree_bound_univariate(f, g): r""" Compute an upper bound for the degree of the GCD of two univariate integer polynomials `f` and `g`. The function chooses a suitable prime `p` and computes the GCD of `f` and `g` in `\mathbb{Z}_p[x]`. The choice of `p` guarantees that the degree in `\mathbb{Z}_p[x]` is greater than or equal to the degree in `\mathbb{Z}[x]`. Parameters ========== f : PolyElement univariate integer polynomial g : PolyElement univariate integer polynomial """ gamma = f.ring.domain.gcd(f.LC, g.LC) p = 1 p = nextprime(p) while gamma % p == 0: p = nextprime(p) fp = f.trunc_ground(p) gp = g.trunc_ground(p) hp = _gf_gcd(fp, gp, p) deghp = hp.degree() return deghp def _chinese_remainder_reconstruction_univariate(hp, hq, p, q): r""" Construct a polynomial `h_{pq}` in `\mathbb{Z}_{p q}[x]` such that .. math :: h_{pq} = h_p \; \mathrm{mod} \, p h_{pq} = h_q \; \mathrm{mod} \, q for relatively prime integers `p` and `q` and polynomials `h_p` and `h_q` in `\mathbb{Z}_p[x]` and `\mathbb{Z}_q[x]` respectively. The coefficients of the polynomial `h_{pq}` are computed with the Chinese Remainder Theorem. The symmetric representation in `\mathbb{Z}_p[x]`, `\mathbb{Z}_q[x]` and `\mathbb{Z}_{p q}[x]` is used. It is assumed that `h_p` and `h_q` have the same degree. Parameters ========== hp : PolyElement univariate integer polynomial with coefficients in `\mathbb{Z}_p` hq : PolyElement univariate integer polynomial with coefficients in `\mathbb{Z}_q` p : Integer modulus of `h_p`, relatively prime to `q` q : Integer modulus of `h_q`, relatively prime to `p` Examples ======== >>> from sympy.polys.modulargcd import _chinese_remainder_reconstruction_univariate >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> p = 3 >>> q = 5 >>> hp = -x**3 - 1 >>> hq = 2*x**3 - 2*x**2 + x >>> hpq = _chinese_remainder_reconstruction_univariate(hp, hq, p, q) >>> hpq 2*x**3 + 3*x**2 + 6*x + 5 >>> hpq.trunc_ground(p) == hp True >>> hpq.trunc_ground(q) == hq True """ n = hp.degree() x = hp.ring.gens[0] hpq = hp.ring.zero for i in range(n+1): hpq[(i,)] = crt([p, q], [hp.coeff(x**i), hq.coeff(x**i)], symmetric=True)[0] hpq.strip_zero() return hpq def modgcd_univariate(f, g): r""" Computes the GCD of two polynomials in `\mathbb{Z}[x]` using a modular algorithm. The algorithm computes the GCD of two univariate integer polynomials `f` and `g` by computing the GCD in `\mathbb{Z}_p[x]` for suitable primes `p` and then reconstructing the coefficients with the Chinese Remainder Theorem. Trial division is only made for candidates which are very likely the desired GCD. Parameters ========== f : PolyElement univariate integer polynomial g : PolyElement univariate integer polynomial Returns ======= h : PolyElement GCD of the polynomials `f` and `g` cff : PolyElement cofactor of `f`, i.e. `\frac{f}{h}` cfg : PolyElement cofactor of `g`, i.e. `\frac{g}{h}` Examples ======== >>> from sympy.polys.modulargcd import modgcd_univariate >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = x**5 - 1 >>> g = x - 1 >>> h, cff, cfg = modgcd_univariate(f, g) >>> h, cff, cfg (x - 1, x**4 + x**3 + x**2 + x + 1, 1) >>> cff * h == f True >>> cfg * h == g True >>> f = 6*x**2 - 6 >>> g = 2*x**2 + 4*x + 2 >>> h, cff, cfg = modgcd_univariate(f, g) >>> h, cff, cfg (2*x + 2, 3*x - 3, x + 1) >>> cff * h == f True >>> cfg * h == g True References ========== 1. [Monagan00]_ """ assert f.ring == g.ring and f.ring.domain.is_ZZ result = _trivial_gcd(f, g) if result is not None: return result ring = f.ring cf, f = f.primitive() cg, g = g.primitive() ch = ring.domain.gcd(cf, cg) bound = _degree_bound_univariate(f, g) if bound == 0: return ring(ch), f.mul_ground(cf // ch), g.mul_ground(cg // ch) gamma = ring.domain.gcd(f.LC, g.LC) m = 1 p = 1 while True: p = nextprime(p) while gamma % p == 0: p = nextprime(p) fp = f.trunc_ground(p) gp = g.trunc_ground(p) hp = _gf_gcd(fp, gp, p) deghp = hp.degree() if deghp > bound: continue elif deghp < bound: m = 1 bound = deghp continue hp = hp.mul_ground(gamma).trunc_ground(p) if m == 1: m = p hlastm = hp continue hm = _chinese_remainder_reconstruction_univariate(hp, hlastm, p, m) m *= p if not hm == hlastm: hlastm = hm continue h = hm.quo_ground(hm.content()) fquo, frem = f.div(h) gquo, grem = g.div(h) if not frem and not grem: if h.LC < 0: ch = -ch h = h.mul_ground(ch) cff = fquo.mul_ground(cf // ch) cfg = gquo.mul_ground(cg // ch) return h, cff, cfg def _primitive(f, p): r""" Compute the content and the primitive part of a polynomial in `\mathbb{Z}_p[x_0, \ldots, x_{k-2}, y] \cong \mathbb{Z}_p[y][x_0, \ldots, x_{k-2}]`. Parameters ========== f : PolyElement integer polynomial in `\mathbb{Z}_p[x0, \ldots, x{k-2}, y]` p : Integer modulus of `f` Returns ======= contf : PolyElement integer polynomial in `\mathbb{Z}_p[y]`, content of `f` ppf : PolyElement primitive part of `f`, i.e. `\frac{f}{contf}` Examples ======== >>> from sympy.polys.modulargcd import _primitive >>> from sympy.polys import ring, ZZ >>> R, x, y = ring("x, y", ZZ) >>> p = 3 >>> f = x**2*y**2 + x**2*y - y**2 - y >>> _primitive(f, p) (y**2 + y, x**2 - 1) >>> R, x, y, z = ring("x, y, z", ZZ) >>> f = x*y*z - y**2*z**2 >>> _primitive(f, p) (z, x*y - y**2*z) """ ring = f.ring dom = ring.domain k = ring.ngens coeffs = {} for monom, coeff in f.iterterms(): if monom[:-1] not in coeffs: coeffs[monom[:-1]] = {} coeffs[monom[:-1]][monom[-1]] = coeff cont = [] for coeff in iter(coeffs.values()): cont = gf_gcd(cont, gf_from_dict(coeff, p, dom), p, dom) yring = ring.clone(symbols=ring.symbols[k-1]) contf = yring.from_dense(cont).trunc_ground(p) return contf, f.quo(contf.set_ring(ring)) def _deg(f): r""" Compute the degree of a multivariate polynomial `f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`. Parameters ========== f : PolyElement polynomial in `K[x_0, \ldots, x_{k-2}, y]` Returns ======= degf : Integer tuple degree of `f` in `x_0, \ldots, x_{k-2}` Examples ======== >>> from sympy.polys.modulargcd import _deg >>> from sympy.polys import ring, ZZ >>> R, x, y = ring("x, y", ZZ) >>> f = x**2*y**2 + x**2*y - 1 >>> _deg(f) (2,) >>> R, x, y, z = ring("x, y, z", ZZ) >>> f = x**2*y**2 + x**2*y - 1 >>> _deg(f) (2, 2) >>> f = x*y*z - y**2*z**2 >>> _deg(f) (1, 1) """ k = f.ring.ngens degf = (0,) * (k-1) for monom in f.itermonoms(): if monom[:-1] > degf: degf = monom[:-1] return degf def _LC(f): r""" Compute the leading coefficient of a multivariate polynomial `f \in K[x_0, \ldots, x_{k-2}, y] \cong K[y][x_0, \ldots, x_{k-2}]`. Parameters ========== f : PolyElement polynomial in `K[x_0, \ldots, x_{k-2}, y]` Returns ======= lcf : PolyElement polynomial in `K[y]`, leading coefficient of `f` Examples ======== >>> from sympy.polys.modulargcd import _LC >>> from sympy.polys import ring, ZZ >>> R, x, y = ring("x, y", ZZ) >>> f = x**2*y**2 + x**2*y - 1 >>> _LC(f) y**2 + y >>> R, x, y, z = ring("x, y, z", ZZ) >>> f = x**2*y**2 + x**2*y - 1 >>> _LC(f) 1 >>> f = x*y*z - y**2*z**2 >>> _LC(f) z """ ring = f.ring k = ring.ngens yring = ring.clone(symbols=ring.symbols[k-1]) y = yring.gens[0] degf = _deg(f) lcf = yring.zero for monom, coeff in f.iterterms(): if monom[:-1] == degf: lcf += coeff*y**monom[-1] return lcf def _swap(f, i): """ Make the variable `x_i` the leading one in a multivariate polynomial `f`. """ ring = f.ring fswap = ring.zero for monom, coeff in f.iterterms(): monomswap = (monom[i],) + monom[:i] + monom[i+1:] fswap[monomswap] = coeff return fswap def _degree_bound_bivariate(f, g): r""" Compute upper degree bounds for the GCD of two bivariate integer polynomials `f` and `g`. The GCD is viewed as a polynomial in `\mathbb{Z}[y][x]` and the function returns an upper bound for its degree and one for the degree of its content. This is done by choosing a suitable prime `p` and computing the GCD of the contents of `f \; \mathrm{mod} \, p` and `g \; \mathrm{mod} \, p`. The choice of `p` guarantees that the degree of the content in `\mathbb{Z}_p[y]` is greater than or equal to the degree in `\mathbb{Z}[y]`. To obtain the degree bound in the variable `x`, the polynomials are evaluated at `y = a` for a suitable `a \in \mathbb{Z}_p` and then their GCD in `\mathbb{Z}_p[x]` is computed. If no such `a` exists, i.e. the degree in `\mathbb{Z}_p[x]` is always smaller than the one in `\mathbb{Z}[y][x]`, then the bound is set to the minimum of the degrees of `f` and `g` in `x`. Parameters ========== f : PolyElement bivariate integer polynomial g : PolyElement bivariate integer polynomial Returns ======= xbound : Integer upper bound for the degree of the GCD of the polynomials `f` and `g` in the variable `x` ycontbound : Integer upper bound for the degree of the content of the GCD of the polynomials `f` and `g` in the variable `y` References ========== 1. [Monagan00]_ """ ring = f.ring gamma1 = ring.domain.gcd(f.LC, g.LC) gamma2 = ring.domain.gcd(_swap(f, 1).LC, _swap(g, 1).LC) badprimes = gamma1 * gamma2 p = 1 p = nextprime(p) while badprimes % p == 0: p = nextprime(p) fp = f.trunc_ground(p) gp = g.trunc_ground(p) contfp, fp = _primitive(fp, p) contgp, gp = _primitive(gp, p) conthp = _gf_gcd(contfp, contgp, p) # polynomial in Z_p[y] ycontbound = conthp.degree() # polynomial in Z_p[y] delta = _gf_gcd(_LC(fp), _LC(gp), p) for a in range(p): if not delta.evaluate(0, a) % p: continue fpa = fp.evaluate(1, a).trunc_ground(p) gpa = gp.evaluate(1, a).trunc_ground(p) hpa = _gf_gcd(fpa, gpa, p) xbound = hpa.degree() return xbound, ycontbound return min(fp.degree(), gp.degree()), ycontbound def _chinese_remainder_reconstruction_multivariate(hp, hq, p, q): r""" Construct a polynomial `h_{pq}` in `\mathbb{Z}_{p q}[x_0, \ldots, x_{k-1}]` such that .. math :: h_{pq} = h_p \; \mathrm{mod} \, p h_{pq} = h_q \; \mathrm{mod} \, q for relatively prime integers `p` and `q` and polynomials `h_p` and `h_q` in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` and `\mathbb{Z}_q[x_0, \ldots, x_{k-1}]` respectively. The coefficients of the polynomial `h_{pq}` are computed with the Chinese Remainder Theorem. The symmetric representation in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`, `\mathbb{Z}_q[x_0, \ldots, x_{k-1}]` and `\mathbb{Z}_{p q}[x_0, \ldots, x_{k-1}]` is used. Parameters ========== hp : PolyElement multivariate integer polynomial with coefficients in `\mathbb{Z}_p` hq : PolyElement multivariate integer polynomial with coefficients in `\mathbb{Z}_q` p : Integer modulus of `h_p`, relatively prime to `q` q : Integer modulus of `h_q`, relatively prime to `p` Examples ======== >>> from sympy.polys.modulargcd import _chinese_remainder_reconstruction_multivariate >>> from sympy.polys import ring, ZZ >>> R, x, y = ring("x, y", ZZ) >>> p = 3 >>> q = 5 >>> hp = x**3*y - x**2 - 1 >>> hq = -x**3*y - 2*x*y**2 + 2 >>> hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) >>> hpq 4*x**3*y + 5*x**2 + 3*x*y**2 + 2 >>> hpq.trunc_ground(p) == hp True >>> hpq.trunc_ground(q) == hq True >>> R, x, y, z = ring("x, y, z", ZZ) >>> p = 6 >>> q = 5 >>> hp = 3*x**4 - y**3*z + z >>> hq = -2*x**4 + z >>> hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) >>> hpq 3*x**4 + 5*y**3*z + z >>> hpq.trunc_ground(p) == hp True >>> hpq.trunc_ground(q) == hq True """ hpmonoms = set(hp.monoms()) hqmonoms = set(hq.monoms()) monoms = hpmonoms.intersection(hqmonoms) hpmonoms.difference_update(monoms) hqmonoms.difference_update(monoms) zero = hp.ring.domain.zero hpq = hp.ring.zero if isinstance(hp.ring.domain, PolynomialRing): crt_ = _chinese_remainder_reconstruction_multivariate else: def crt_(cp, cq, p, q): return crt([p, q], [cp, cq], symmetric=True)[0] for monom in monoms: hpq[monom] = crt_(hp[monom], hq[monom], p, q) for monom in hpmonoms: hpq[monom] = crt_(hp[monom], zero, p, q) for monom in hqmonoms: hpq[monom] = crt_(zero, hq[monom], p, q) return hpq def _interpolate_multivariate(evalpoints, hpeval, ring, i, p, ground=False): r""" Reconstruct a polynomial `h_p` in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` from a list of evaluation points in `\mathbb{Z}_p` and a list of polynomials in `\mathbb{Z}_p[x_0, \ldots, x_{i-1}, x_{i+1}, \ldots, x_{k-1}]`, which are the images of `h_p` evaluated in the variable `x_i`. It is also possible to reconstruct a parameter of the ground domain, i.e. if `h_p` is a polynomial over `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`. In this case, one has to set ``ground=True``. Parameters ========== evalpoints : list of Integer objects list of evaluation points in `\mathbb{Z}_p` hpeval : list of PolyElement objects list of polynomials in (resp. over) `\mathbb{Z}_p[x_0, \ldots, x_{i-1}, x_{i+1}, \ldots, x_{k-1}]`, images of `h_p` evaluated in the variable `x_i` ring : PolyRing `h_p` will be an element of this ring i : Integer index of the variable which has to be reconstructed p : Integer prime number, modulus of `h_p` ground : Boolean indicates whether `x_i` is in the ground domain, default is ``False`` Returns ======= hp : PolyElement interpolated polynomial in (resp. over) `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` """ hp = ring.zero if ground: domain = ring.domain.domain y = ring.domain.gens[i] else: domain = ring.domain y = ring.gens[i] for a, hpa in zip(evalpoints, hpeval): numer = ring.one denom = domain.one for b in evalpoints: if b == a: continue numer *= y - b denom *= a - b denom = domain.invert(denom, p) coeff = numer.mul_ground(denom) hp += hpa.set_ring(ring) * coeff return hp.trunc_ground(p) def modgcd_bivariate(f, g): r""" Computes the GCD of two polynomials in `\mathbb{Z}[x, y]` using a modular algorithm. The algorithm computes the GCD of two bivariate integer polynomials `f` and `g` by calculating the GCD in `\mathbb{Z}_p[x, y]` for suitable primes `p` and then reconstructing the coefficients with the Chinese Remainder Theorem. To compute the bivariate GCD over `\mathbb{Z}_p`, the polynomials `f \; \mathrm{mod} \, p` and `g \; \mathrm{mod} \, p` are evaluated at `y = a` for certain `a \in \mathbb{Z}_p` and then their univariate GCD in `\mathbb{Z}_p[x]` is computed. Interpolating those yields the bivariate GCD in `\mathbb{Z}_p[x, y]`. To verify the result in `\mathbb{Z}[x, y]`, trial division is done, but only for candidates which are very likely the desired GCD. Parameters ========== f : PolyElement bivariate integer polynomial g : PolyElement bivariate integer polynomial Returns ======= h : PolyElement GCD of the polynomials `f` and `g` cff : PolyElement cofactor of `f`, i.e. `\frac{f}{h}` cfg : PolyElement cofactor of `g`, i.e. `\frac{g}{h}` Examples ======== >>> from sympy.polys.modulargcd import modgcd_bivariate >>> from sympy.polys import ring, ZZ >>> R, x, y = ring("x, y", ZZ) >>> f = x**2 - y**2 >>> g = x**2 + 2*x*y + y**2 >>> h, cff, cfg = modgcd_bivariate(f, g) >>> h, cff, cfg (x + y, x - y, x + y) >>> cff * h == f True >>> cfg * h == g True >>> f = x**2*y - x**2 - 4*y + 4 >>> g = x + 2 >>> h, cff, cfg = modgcd_bivariate(f, g) >>> h, cff, cfg (x + 2, x*y - x - 2*y + 2, 1) >>> cff * h == f True >>> cfg * h == g True References ========== 1. [Monagan00]_ """ assert f.ring == g.ring and f.ring.domain.is_ZZ result = _trivial_gcd(f, g) if result is not None: return result ring = f.ring cf, f = f.primitive() cg, g = g.primitive() ch = ring.domain.gcd(cf, cg) xbound, ycontbound = _degree_bound_bivariate(f, g) if xbound == ycontbound == 0: return ring(ch), f.mul_ground(cf // ch), g.mul_ground(cg // ch) fswap = _swap(f, 1) gswap = _swap(g, 1) degyf = fswap.degree() degyg = gswap.degree() ybound, xcontbound = _degree_bound_bivariate(fswap, gswap) if ybound == xcontbound == 0: return ring(ch), f.mul_ground(cf // ch), g.mul_ground(cg // ch) # TODO: to improve performance, choose the main variable here gamma1 = ring.domain.gcd(f.LC, g.LC) gamma2 = ring.domain.gcd(fswap.LC, gswap.LC) badprimes = gamma1 * gamma2 m = 1 p = 1 while True: p = nextprime(p) while badprimes % p == 0: p = nextprime(p) fp = f.trunc_ground(p) gp = g.trunc_ground(p) contfp, fp = _primitive(fp, p) contgp, gp = _primitive(gp, p) conthp = _gf_gcd(contfp, contgp, p) # monic polynomial in Z_p[y] degconthp = conthp.degree() if degconthp > ycontbound: continue elif degconthp < ycontbound: m = 1 ycontbound = degconthp continue # polynomial in Z_p[y] delta = _gf_gcd(_LC(fp), _LC(gp), p) degcontfp = contfp.degree() degcontgp = contgp.degree() degdelta = delta.degree() N = min(degyf - degcontfp, degyg - degcontgp, ybound - ycontbound + degdelta) + 1 if p < N: continue n = 0 evalpoints = [] hpeval = [] unlucky = False for a in range(p): deltaa = delta.evaluate(0, a) if not deltaa % p: continue fpa = fp.evaluate(1, a).trunc_ground(p) gpa = gp.evaluate(1, a).trunc_ground(p) hpa = _gf_gcd(fpa, gpa, p) # monic polynomial in Z_p[x] deghpa = hpa.degree() if deghpa > xbound: continue elif deghpa < xbound: m = 1 xbound = deghpa unlucky = True break hpa = hpa.mul_ground(deltaa).trunc_ground(p) evalpoints.append(a) hpeval.append(hpa) n += 1 if n == N: break if unlucky: continue if n < N: continue hp = _interpolate_multivariate(evalpoints, hpeval, ring, 1, p) hp = _primitive(hp, p)[1] hp = hp * conthp.set_ring(ring) degyhp = hp.degree(1) if degyhp > ybound: continue if degyhp < ybound: m = 1 ybound = degyhp continue hp = hp.mul_ground(gamma1).trunc_ground(p) if m == 1: m = p hlastm = hp continue hm = _chinese_remainder_reconstruction_multivariate(hp, hlastm, p, m) m *= p if not hm == hlastm: hlastm = hm continue h = hm.quo_ground(hm.content()) fquo, frem = f.div(h) gquo, grem = g.div(h) if not frem and not grem: if h.LC < 0: ch = -ch h = h.mul_ground(ch) cff = fquo.mul_ground(cf // ch) cfg = gquo.mul_ground(cg // ch) return h, cff, cfg def _modgcd_multivariate_p(f, g, p, degbound, contbound): r""" Compute the GCD of two polynomials in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]`. The algorithm reduces the problem step by step by evaluating the polynomials `f` and `g` at `x_{k-1} = a` for suitable `a \in \mathbb{Z}_p` and then calls itself recursively to compute the GCD in `\mathbb{Z}_p[x_0, \ldots, x_{k-2}]`. If these recursive calls are successful for enough evaluation points, the GCD in `k` variables is interpolated, otherwise the algorithm returns ``None``. Every time a GCD or a content is computed, their degrees are compared with the bounds. If a degree greater then the bound is encountered, then the current call returns ``None`` and a new evaluation point has to be chosen. If at some point the degree is smaller, the correspondent bound is updated and the algorithm fails. Parameters ========== f : PolyElement multivariate integer polynomial with coefficients in `\mathbb{Z}_p` g : PolyElement multivariate integer polynomial with coefficients in `\mathbb{Z}_p` p : Integer prime number, modulus of `f` and `g` degbound : list of Integer objects ``degbound[i]`` is an upper bound for the degree of the GCD of `f` and `g` in the variable `x_i` contbound : list of Integer objects ``contbound[i]`` is an upper bound for the degree of the content of the GCD in `\mathbb{Z}_p[x_i][x_0, \ldots, x_{i-1}]`, ``contbound[0]`` is not used can therefore be chosen arbitrarily. Returns ======= h : PolyElement GCD of the polynomials `f` and `g` or ``None`` References ========== 1. [Monagan00]_ 2. [Brown71]_ """ ring = f.ring k = ring.ngens if k == 1: h = _gf_gcd(f, g, p).trunc_ground(p) degh = h.degree() if degh > degbound[0]: return None if degh < degbound[0]: degbound[0] = degh raise ModularGCDFailed return h degyf = f.degree(k-1) degyg = g.degree(k-1) contf, f = _primitive(f, p) contg, g = _primitive(g, p) conth = _gf_gcd(contf, contg, p) # polynomial in Z_p[y] degcontf = contf.degree() degcontg = contg.degree() degconth = conth.degree() if degconth > contbound[k-1]: return None if degconth < contbound[k-1]: contbound[k-1] = degconth raise ModularGCDFailed lcf = _LC(f) lcg = _LC(g) delta = _gf_gcd(lcf, lcg, p) # polynomial in Z_p[y] evaltest = delta for i in range(k-1): evaltest *= _gf_gcd(_LC(_swap(f, i)), _LC(_swap(g, i)), p) degdelta = delta.degree() N = min(degyf - degcontf, degyg - degcontg, degbound[k-1] - contbound[k-1] + degdelta) + 1 if p < N: return None n = 0 d = 0 evalpoints = [] heval = [] points = list(range(p)) while points: a = random.sample(points, 1)[0] points.remove(a) if not evaltest.evaluate(0, a) % p: continue deltaa = delta.evaluate(0, a) % p fa = f.evaluate(k-1, a).trunc_ground(p) ga = g.evaluate(k-1, a).trunc_ground(p) # polynomials in Z_p[x_0, ..., x_{k-2}] ha = _modgcd_multivariate_p(fa, ga, p, degbound, contbound) if ha is None: d += 1 if d > n: return None continue if ha.is_ground: h = conth.set_ring(ring).trunc_ground(p) return h ha = ha.mul_ground(deltaa).trunc_ground(p) evalpoints.append(a) heval.append(ha) n += 1 if n == N: h = _interpolate_multivariate(evalpoints, heval, ring, k-1, p) h = _primitive(h, p)[1] * conth.set_ring(ring) degyh = h.degree(k-1) if degyh > degbound[k-1]: return None if degyh < degbound[k-1]: degbound[k-1] = degyh raise ModularGCDFailed return h return None def modgcd_multivariate(f, g): r""" Compute the GCD of two polynomials in `\mathbb{Z}[x_0, \ldots, x_{k-1}]` using a modular algorithm. The algorithm computes the GCD of two multivariate integer polynomials `f` and `g` by calculating the GCD in `\mathbb{Z}_p[x_0, \ldots, x_{k-1}]` for suitable primes `p` and then reconstructing the coefficients with the Chinese Remainder Theorem. To compute the multivariate GCD over `\mathbb{Z}_p` the recursive subroutine :func:`_modgcd_multivariate_p` is used. To verify the result in `\mathbb{Z}[x_0, \ldots, x_{k-1}]`, trial division is done, but only for candidates which are very likely the desired GCD. Parameters ========== f : PolyElement multivariate integer polynomial g : PolyElement multivariate integer polynomial Returns ======= h : PolyElement GCD of the polynomials `f` and `g` cff : PolyElement cofactor of `f`, i.e. `\frac{f}{h}` cfg : PolyElement cofactor of `g`, i.e. `\frac{g}{h}` Examples ======== >>> from sympy.polys.modulargcd import modgcd_multivariate >>> from sympy.polys import ring, ZZ >>> R, x, y = ring("x, y", ZZ) >>> f = x**2 - y**2 >>> g = x**2 + 2*x*y + y**2 >>> h, cff, cfg = modgcd_multivariate(f, g) >>> h, cff, cfg (x + y, x - y, x + y) >>> cff * h == f True >>> cfg * h == g True >>> R, x, y, z = ring("x, y, z", ZZ) >>> f = x*z**2 - y*z**2 >>> g = x**2*z + z >>> h, cff, cfg = modgcd_multivariate(f, g) >>> h, cff, cfg (z, x*z - y*z, x**2 + 1) >>> cff * h == f True >>> cfg * h == g True References ========== 1. [Monagan00]_ 2. [Brown71]_ See also ======== _modgcd_multivariate_p """ assert f.ring == g.ring and f.ring.domain.is_ZZ result = _trivial_gcd(f, g) if result is not None: return result ring = f.ring k = ring.ngens # divide out integer content cf, f = f.primitive() cg, g = g.primitive() ch = ring.domain.gcd(cf, cg) gamma = ring.domain.gcd(f.LC, g.LC) badprimes = ring.domain.one for i in range(k): badprimes *= ring.domain.gcd(_swap(f, i).LC, _swap(g, i).LC) degbound = [min(fdeg, gdeg) for fdeg, gdeg in zip(f.degrees(), g.degrees())] contbound = list(degbound) m = 1 p = 1 while True: p = nextprime(p) while badprimes % p == 0: p = nextprime(p) fp = f.trunc_ground(p) gp = g.trunc_ground(p) try: # monic GCD of fp, gp in Z_p[x_0, ..., x_{k-2}, y] hp = _modgcd_multivariate_p(fp, gp, p, degbound, contbound) except ModularGCDFailed: m = 1 continue if hp is None: continue hp = hp.mul_ground(gamma).trunc_ground(p) if m == 1: m = p hlastm = hp continue hm = _chinese_remainder_reconstruction_multivariate(hp, hlastm, p, m) m *= p if not hm == hlastm: hlastm = hm continue h = hm.primitive()[1] fquo, frem = f.div(h) gquo, grem = g.div(h) if not frem and not grem: if h.LC < 0: ch = -ch h = h.mul_ground(ch) cff = fquo.mul_ground(cf // ch) cfg = gquo.mul_ground(cg // ch) return h, cff, cfg def _gf_div(f, g, p): r""" Compute `\frac f g` modulo `p` for two univariate polynomials over `\mathbb Z_p`. """ ring = f.ring densequo, denserem = gf_div(f.to_dense(), g.to_dense(), p, ring.domain) return ring.from_dense(densequo), ring.from_dense(denserem) def _rational_function_reconstruction(c, p, m): r""" Reconstruct a rational function `\frac a b` in `\mathbb Z_p(t)` from .. math:: c = \frac a b \; \mathrm{mod} \, m, where `c` and `m` are polynomials in `\mathbb Z_p[t]` and `m` has positive degree. The algorithm is based on the Euclidean Algorithm. In general, `m` is not irreducible, so it is possible that `b` is not invertible modulo `m`. In that case ``None`` is returned. Parameters ========== c : PolyElement univariate polynomial in `\mathbb Z[t]` p : Integer prime number m : PolyElement modulus, not necessarily irreducible Returns ======= frac : FracElement either `\frac a b` in `\mathbb Z(t)` or ``None`` References ========== 1. [Hoeij04]_ """ ring = c.ring domain = ring.domain M = m.degree() N = M // 2 D = M - N - 1 r0, s0 = m, ring.zero r1, s1 = c, ring.one while r1.degree() > N: quo = _gf_div(r0, r1, p)[0] r0, r1 = r1, (r0 - quo*r1).trunc_ground(p) s0, s1 = s1, (s0 - quo*s1).trunc_ground(p) a, b = r1, s1 if b.degree() > D or _gf_gcd(b, m, p) != 1: return None lc = b.LC if lc != 1: lcinv = domain.invert(lc, p) a = a.mul_ground(lcinv).trunc_ground(p) b = b.mul_ground(lcinv).trunc_ground(p) field = ring.to_field() return field(a) / field(b) def _rational_reconstruction_func_coeffs(hm, p, m, ring, k): r""" Reconstruct every coefficient `c_h` of a polynomial `h` in `\mathbb Z_p(t_k)[t_1, \ldots, t_{k-1}][x, z]` from the corresponding coefficient `c_{h_m}` of a polynomial `h_m` in `\mathbb Z_p[t_1, \ldots, t_k][x, z] \cong \mathbb Z_p[t_k][t_1, \ldots, t_{k-1}][x, z]` such that .. math:: c_{h_m} = c_h \; \mathrm{mod} \, m, where `m \in \mathbb Z_p[t]`. The reconstruction is based on the Euclidean Algorithm. In general, `m` is not irreducible, so it is possible that this fails for some coefficient. In that case ``None`` is returned. Parameters ========== hm : PolyElement polynomial in `\mathbb Z[t_1, \ldots, t_k][x, z]` p : Integer prime number, modulus of `\mathbb Z_p` m : PolyElement modulus, polynomial in `\mathbb Z[t]`, not necessarily irreducible ring : PolyRing `\mathbb Z(t_k)[t_1, \ldots, t_{k-1}][x, z]`, `h` will be an element of this ring k : Integer index of the parameter `t_k` which will be reconstructed Returns ======= h : PolyElement reconstructed polynomial in `\mathbb Z(t_k)[t_1, \ldots, t_{k-1}][x, z]` or ``None`` See also ======== _rational_function_reconstruction """ h = ring.zero for monom, coeff in hm.iterterms(): if k == 0: coeffh = _rational_function_reconstruction(coeff, p, m) if not coeffh: return None else: coeffh = ring.domain.zero for mon, c in coeff.drop_to_ground(k).iterterms(): ch = _rational_function_reconstruction(c, p, m) if not ch: return None coeffh[mon] = ch h[monom] = coeffh return h def _gf_gcdex(f, g, p): r""" Extended Euclidean Algorithm for two univariate polynomials over `\mathbb Z_p`. Returns polynomials `s, t` and `h`, such that `h` is the GCD of `f` and `g` and `sf + tg = h \; \mathrm{mod} \, p`. """ ring = f.ring s, t, h = gf_gcdex(f.to_dense(), g.to_dense(), p, ring.domain) return ring.from_dense(s), ring.from_dense(t), ring.from_dense(h) def _trunc(f, minpoly, p): r""" Compute the reduced representation of a polynomial `f` in `\mathbb Z_p[z] / (\check m_{\alpha}(z))[x]` Parameters ========== f : PolyElement polynomial in `\mathbb Z[x, z]` minpoly : PolyElement polynomial `\check m_{\alpha} \in \mathbb Z[z]`, not necessarily irreducible p : Integer prime number, modulus of `\mathbb Z_p` Returns ======= ftrunc : PolyElement polynomial in `\mathbb Z[x, z]`, reduced modulo `\check m_{\alpha}(z)` and `p` """ ring = f.ring minpoly = minpoly.set_ring(ring) p_ = ring.ground_new(p) return f.trunc_ground(p).rem([minpoly, p_]).trunc_ground(p) def _euclidean_algorithm(f, g, minpoly, p): r""" Compute the monic GCD of two univariate polynomials in `\mathbb{Z}_p[z]/(\check m_{\alpha}(z))[x]` with the Euclidean Algorithm. In general, `\check m_{\alpha}(z)` is not irreducible, so it is possible that some leading coefficient is not invertible modulo `\check m_{\alpha}(z)`. In that case ``None`` is returned. Parameters ========== f, g : PolyElement polynomials in `\mathbb Z[x, z]` minpoly : PolyElement polynomial in `\mathbb Z[z]`, not necessarily irreducible p : Integer prime number, modulus of `\mathbb Z_p` Returns ======= h : PolyElement GCD of `f` and `g` in `\mathbb Z[z, x]` or ``None``, coefficients are in `\left[ -\frac{p-1} 2, \frac{p-1} 2 \right]` """ ring = f.ring f = _trunc(f, minpoly, p) g = _trunc(g, minpoly, p) while g: rem = f deg = g.degree(0) # degree in x lcinv, _, gcd = _gf_gcdex(ring.dmp_LC(g), minpoly, p) if not gcd == 1: return None while True: degrem = rem.degree(0) # degree in x if degrem < deg: break quo = (lcinv * ring.dmp_LC(rem)).set_ring(ring) rem = _trunc(rem - g.mul_monom((degrem - deg, 0))*quo, minpoly, p) f = g g = rem lcfinv = _gf_gcdex(ring.dmp_LC(f), minpoly, p)[0].set_ring(ring) return _trunc(f * lcfinv, minpoly, p) def _trial_division(f, h, minpoly, p=None): r""" Check if `h` divides `f` in `\mathbb K[t_1, \ldots, t_k][z]/(m_{\alpha}(z))`, where `\mathbb K` is either `\mathbb Q` or `\mathbb Z_p`. This algorithm is based on pseudo division and does not use any fractions. By default `\mathbb K` is `\mathbb Q`, if a prime number `p` is given, `\mathbb Z_p` is chosen instead. Parameters ========== f, h : PolyElement polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]` minpoly : PolyElement polynomial `m_{\alpha}(z)` in `\mathbb Z[t_1, \ldots, t_k][z]` p : Integer or None if `p` is given, `\mathbb K` is set to `\mathbb Z_p` instead of `\mathbb Q`, default is ``None`` Returns ======= rem : PolyElement remainder of `\frac f h` References ========== .. [1] [Hoeij02]_ """ ring = f.ring zxring = ring.clone(symbols=(ring.symbols[1], ring.symbols[0])) minpoly = minpoly.set_ring(ring) rem = f degrem = rem.degree() degh = h.degree() degm = minpoly.degree(1) lch = _LC(h).set_ring(ring) lcm = minpoly.LC while rem and degrem >= degh: # polynomial in Z[t_1, ..., t_k][z] lcrem = _LC(rem).set_ring(ring) rem = rem*lch - h.mul_monom((degrem - degh, 0))*lcrem if p: rem = rem.trunc_ground(p) degrem = rem.degree(1) while rem and degrem >= degm: # polynomial in Z[t_1, ..., t_k][x] lcrem = _LC(rem.set_ring(zxring)).set_ring(ring) rem = rem.mul_ground(lcm) - minpoly.mul_monom((0, degrem - degm))*lcrem if p: rem = rem.trunc_ground(p) degrem = rem.degree(1) degrem = rem.degree() return rem def _evaluate_ground(f, i, a): r""" Evaluate a polynomial `f` at `a` in the `i`-th variable of the ground domain. """ ring = f.ring.clone(domain=f.ring.domain.ring.drop(i)) fa = ring.zero for monom, coeff in f.iterterms(): fa[monom] = coeff.evaluate(i, a) return fa def _func_field_modgcd_p(f, g, minpoly, p): r""" Compute the GCD of two polynomials `f` and `g` in `\mathbb Z_p(t_1, \ldots, t_k)[z]/(\check m_\alpha(z))[x]`. The algorithm reduces the problem step by step by evaluating the polynomials `f` and `g` at `t_k = a` for suitable `a \in \mathbb Z_p` and then calls itself recursively to compute the GCD in `\mathbb Z_p(t_1, \ldots, t_{k-1})[z]/(\check m_\alpha(z))[x]`. If these recursive calls are successful, the GCD over `k` variables is interpolated, otherwise the algorithm returns ``None``. After interpolation, Rational Function Reconstruction is used to obtain the correct coefficients. If this fails, a new evaluation point has to be chosen, otherwise the desired polynomial is obtained by clearing denominators. The result is verified with a fraction free trial division. Parameters ========== f, g : PolyElement polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]` minpoly : PolyElement polynomial in `\mathbb Z[t_1, \ldots, t_k][z]`, not necessarily irreducible p : Integer prime number, modulus of `\mathbb Z_p` Returns ======= h : PolyElement primitive associate in `\mathbb Z[t_1, \ldots, t_k][x, z]` of the GCD of the polynomials `f` and `g` or ``None``, coefficients are in `\left[ -\frac{p-1} 2, \frac{p-1} 2 \right]` References ========== 1. [Hoeij04]_ """ ring = f.ring domain = ring.domain # Z[t_1, ..., t_k] if isinstance(domain, PolynomialRing): k = domain.ngens else: return _euclidean_algorithm(f, g, minpoly, p) if k == 1: qdomain = domain.ring.to_field() else: qdomain = domain.ring.drop_to_ground(k - 1) qdomain = qdomain.clone(domain=qdomain.domain.ring.to_field()) qring = ring.clone(domain=qdomain) # = Z(t_k)[t_1, ..., t_{k-1}][x, z] n = 1 d = 1 # polynomial in Z_p[t_1, ..., t_k][z] gamma = ring.dmp_LC(f) * ring.dmp_LC(g) # polynomial in Z_p[t_1, ..., t_k] delta = minpoly.LC evalpoints = [] heval = [] LMlist = [] points = list(range(p)) while points: a = random.sample(points, 1)[0] points.remove(a) if k == 1: test = delta.evaluate(k-1, a) % p == 0 else: test = delta.evaluate(k-1, a).trunc_ground(p) == 0 if test: continue gammaa = _evaluate_ground(gamma, k-1, a) minpolya = _evaluate_ground(minpoly, k-1, a) if gammaa.rem([minpolya, gammaa.ring(p)]) == 0: continue fa = _evaluate_ground(f, k-1, a) ga = _evaluate_ground(g, k-1, a) # polynomial in Z_p[x, t_1, ..., t_{k-1}, z]/(minpoly) ha = _func_field_modgcd_p(fa, ga, minpolya, p) if ha is None: d += 1 if d > n: return None continue if ha == 1: return ha LM = [ha.degree()] + [0]*(k-1) if k > 1: for monom, coeff in ha.iterterms(): if monom[0] == LM[0] and coeff.LM > tuple(LM[1:]): LM[1:] = coeff.LM evalpoints_a = [a] heval_a = [ha] if k == 1: m = qring.domain.get_ring().one else: m = qring.domain.domain.get_ring().one t = m.ring.gens[0] for b, hb, LMhb in zip(evalpoints, heval, LMlist): if LMhb == LM: evalpoints_a.append(b) heval_a.append(hb) m *= (t - b) m = m.trunc_ground(p) evalpoints.append(a) heval.append(ha) LMlist.append(LM) n += 1 # polynomial in Z_p[t_1, ..., t_k][x, z] h = _interpolate_multivariate(evalpoints_a, heval_a, ring, k-1, p, ground=True) # polynomial in Z_p(t_k)[t_1, ..., t_{k-1}][x, z] h = _rational_reconstruction_func_coeffs(h, p, m, qring, k-1) if h is None: continue if k == 1: dom = qring.domain.field den = dom.ring.one for coeff in h.itercoeffs(): den = dom.ring.from_dense(gf_lcm(den.to_dense(), coeff.denom.to_dense(), p, dom.domain)) else: dom = qring.domain.domain.field den = dom.ring.one for coeff in h.itercoeffs(): for c in coeff.itercoeffs(): den = dom.ring.from_dense(gf_lcm(den.to_dense(), c.denom.to_dense(), p, dom.domain)) den = qring.domain_new(den.trunc_ground(p)) h = ring(h.mul_ground(den).as_expr()).trunc_ground(p) if not _trial_division(f, h, minpoly, p) and not _trial_division(g, h, minpoly, p): return h return None def _integer_rational_reconstruction(c, m, domain): r""" Reconstruct a rational number `\frac a b` from .. math:: c = \frac a b \; \mathrm{mod} \, m, where `c` and `m` are integers. The algorithm is based on the Euclidean Algorithm. In general, `m` is not a prime number, so it is possible that `b` is not invertible modulo `m`. In that case ``None`` is returned. Parameters ========== c : Integer `c = \frac a b \; \mathrm{mod} \, m` m : Integer modulus, not necessarily prime domain : IntegerRing `a, b, c` are elements of ``domain`` Returns ======= frac : Rational either `\frac a b` in `\mathbb Q` or ``None`` References ========== 1. [Wang81]_ """ if c < 0: c += m r0, s0 = m, domain.zero r1, s1 = c, domain.one bound = sqrt(m / 2) # still correct if replaced by ZZ.sqrt(m // 2) ? while r1 >= bound: quo = r0 // r1 r0, r1 = r1, r0 - quo*r1 s0, s1 = s1, s0 - quo*s1 if abs(s1) >= bound: return None if s1 < 0: a, b = -r1, -s1 elif s1 > 0: a, b = r1, s1 else: return None field = domain.get_field() return field(a) / field(b) def _rational_reconstruction_int_coeffs(hm, m, ring): r""" Reconstruct every rational coefficient `c_h` of a polynomial `h` in `\mathbb Q[t_1, \ldots, t_k][x, z]` from the corresponding integer coefficient `c_{h_m}` of a polynomial `h_m` in `\mathbb Z[t_1, \ldots, t_k][x, z]` such that .. math:: c_{h_m} = c_h \; \mathrm{mod} \, m, where `m \in \mathbb Z`. The reconstruction is based on the Euclidean Algorithm. In general, `m` is not a prime number, so it is possible that this fails for some coefficient. In that case ``None`` is returned. Parameters ========== hm : PolyElement polynomial in `\mathbb Z[t_1, \ldots, t_k][x, z]` m : Integer modulus, not necessarily prime ring : PolyRing `\mathbb Q[t_1, \ldots, t_k][x, z]`, `h` will be an element of this ring Returns ======= h : PolyElement reconstructed polynomial in `\mathbb Q[t_1, \ldots, t_k][x, z]` or ``None`` See also ======== _integer_rational_reconstruction """ h = ring.zero if isinstance(ring.domain, PolynomialRing): reconstruction = _rational_reconstruction_int_coeffs domain = ring.domain.ring else: reconstruction = _integer_rational_reconstruction domain = hm.ring.domain for monom, coeff in hm.iterterms(): coeffh = reconstruction(coeff, m, domain) if not coeffh: return None h[monom] = coeffh return h def _func_field_modgcd_m(f, g, minpoly): r""" Compute the GCD of two polynomials in `\mathbb Q(t_1, \ldots, t_k)[z]/(m_{\alpha}(z))[x]` using a modular algorithm. The algorithm computes the GCD of two polynomials `f` and `g` by calculating the GCD in `\mathbb Z_p(t_1, \ldots, t_k)[z] / (\check m_{\alpha}(z))[x]` for suitable primes `p` and the primitive associate `\check m_{\alpha}(z)` of `m_{\alpha}(z)`. Then the coefficients are reconstructed with the Chinese Remainder Theorem and Rational Reconstruction. To compute the GCD over `\mathbb Z_p(t_1, \ldots, t_k)[z] / (\check m_{\alpha})[x]`, the recursive subroutine ``_func_field_modgcd_p`` is used. To verify the result in `\mathbb Q(t_1, \ldots, t_k)[z] / (m_{\alpha}(z))[x]`, a fraction free trial division is used. Parameters ========== f, g : PolyElement polynomials in `\mathbb Z[t_1, \ldots, t_k][x, z]` minpoly : PolyElement irreducible polynomial in `\mathbb Z[t_1, \ldots, t_k][z]` Returns ======= h : PolyElement the primitive associate in `\mathbb Z[t_1, \ldots, t_k][x, z]` of the GCD of `f` and `g` Examples ======== >>> from sympy.polys.modulargcd import _func_field_modgcd_m >>> from sympy.polys import ring, ZZ >>> R, x, z = ring('x, z', ZZ) >>> minpoly = (z**2 - 2).drop(0) >>> f = x**2 + 2*x*z + 2 >>> g = x + z >>> _func_field_modgcd_m(f, g, minpoly) x + z >>> D, t = ring('t', ZZ) >>> R, x, z = ring('x, z', D) >>> minpoly = (z**2-3).drop(0) >>> f = x**2 + (t + 1)*x*z + 3*t >>> g = x*z + 3*t >>> _func_field_modgcd_m(f, g, minpoly) x + t*z References ========== 1. [Hoeij04]_ See also ======== _func_field_modgcd_p """ ring = f.ring domain = ring.domain if isinstance(domain, PolynomialRing): k = domain.ngens QQdomain = domain.ring.clone(domain=domain.domain.get_field()) QQring = ring.clone(domain=QQdomain) else: k = 0 QQring = ring.clone(domain=ring.domain.get_field()) cf, f = f.primitive() cg, g = g.primitive() # polynomial in Z[t_1, ..., t_k][z] gamma = ring.dmp_LC(f) * ring.dmp_LC(g) # polynomial in Z[t_1, ..., t_k] delta = minpoly.LC p = 1 primes = [] hplist = [] LMlist = [] while True: p = nextprime(p) if gamma.trunc_ground(p) == 0: continue if k == 0: test = (delta % p == 0) else: test = (delta.trunc_ground(p) == 0) if test: continue fp = f.trunc_ground(p) gp = g.trunc_ground(p) minpolyp = minpoly.trunc_ground(p) hp = _func_field_modgcd_p(fp, gp, minpolyp, p) if hp is None: continue if hp == 1: return ring.one LM = [hp.degree()] + [0]*k if k > 0: for monom, coeff in hp.iterterms(): if monom[0] == LM[0] and coeff.LM > tuple(LM[1:]): LM[1:] = coeff.LM hm = hp m = p for q, hq, LMhq in zip(primes, hplist, LMlist): if LMhq == LM: hm = _chinese_remainder_reconstruction_multivariate(hq, hm, q, m) m *= q primes.append(p) hplist.append(hp) LMlist.append(LM) hm = _rational_reconstruction_int_coeffs(hm, m, QQring) if hm is None: continue if k == 0: h = hm.clear_denoms()[1] else: den = domain.domain.one for coeff in hm.itercoeffs(): den = domain.domain.lcm(den, coeff.clear_denoms()[0]) h = hm.mul_ground(den) # convert back to Z[t_1, ..., t_k][x, z] from Q[t_1, ..., t_k][x, z] h = h.set_ring(ring) h = h.primitive()[1] if not (_trial_division(f.mul_ground(cf), h, minpoly) or _trial_division(g.mul_ground(cg), h, minpoly)): return h def _to_ZZ_poly(f, ring): r""" Compute an associate of a polynomial `f \in \mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` in `\mathbb Z[x_1, \ldots, x_{n-1}][z] / (\check m_{\alpha}(z))[x_0]`, where `\check m_{\alpha}(z) \in \mathbb Z[z]` is the primitive associate of the minimal polynomial `m_{\alpha}(z)` of `\alpha` over `\mathbb Q`. Parameters ========== f : PolyElement polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` ring : PolyRing `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]` Returns ======= f_ : PolyElement associate of `f` in `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]` """ f_ = ring.zero if isinstance(ring.domain, PolynomialRing): domain = ring.domain.domain else: domain = ring.domain den = domain.one for coeff in f.itercoeffs(): for c in coeff.rep: if c: den = domain.lcm(den, c.denominator) for monom, coeff in f.iterterms(): coeff = coeff.rep m = ring.domain.one if isinstance(ring.domain, PolynomialRing): m = m.mul_monom(monom[1:]) n = len(coeff) for i in range(n): if coeff[i]: c = domain(coeff[i] * den) * m if (monom[0], n-i-1) not in f_: f_[(monom[0], n-i-1)] = c else: f_[(monom[0], n-i-1)] += c return f_ def _to_ANP_poly(f, ring): r""" Convert a polynomial `f \in \mathbb Z[x_1, \ldots, x_{n-1}][z]/(\check m_{\alpha}(z))[x_0]` to a polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]`, where `\check m_{\alpha}(z) \in \mathbb Z[z]` is the primitive associate of the minimal polynomial `m_{\alpha}(z)` of `\alpha` over `\mathbb Q`. Parameters ========== f : PolyElement polynomial in `\mathbb Z[x_1, \ldots, x_{n-1}][x_0, z]` ring : PolyRing `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` Returns ======= f_ : PolyElement polynomial in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` """ domain = ring.domain f_ = ring.zero if isinstance(f.ring.domain, PolynomialRing): for monom, coeff in f.iterterms(): for mon, coef in coeff.iterterms(): m = (monom[0],) + mon c = domain([domain.domain(coef)] + [0]*monom[1]) if m not in f_: f_[m] = c else: f_[m] += c else: for monom, coeff in f.iterterms(): m = (monom[0],) c = domain([domain.domain(coeff)] + [0]*monom[1]) if m not in f_: f_[m] = c else: f_[m] += c return f_ def _minpoly_from_dense(minpoly, ring): r""" Change representation of the minimal polynomial from ``DMP`` to ``PolyElement`` for a given ring. """ minpoly_ = ring.zero for monom, coeff in minpoly.terms(): minpoly_[monom] = ring.domain(coeff) return minpoly_ def _primitive_in_x0(f): r""" Compute the content in `x_0` and the primitive part of a polynomial `f` in `\mathbb Q(\alpha)[x_0, x_1, \ldots, x_{n-1}] \cong \mathbb Q(\alpha)[x_1, \ldots, x_{n-1}][x_0]`. """ fring = f.ring ring = fring.drop_to_ground(*range(1, fring.ngens)) dom = ring.domain.ring f_ = ring(f.as_expr()) cont = dom.zero for coeff in f_.itercoeffs(): cont = func_field_modgcd(cont, coeff)[0] if cont == dom.one: return cont, f return cont, f.quo(cont.set_ring(fring)) # TODO: add support for algebraic function fields def func_field_modgcd(f, g): r""" Compute the GCD of two polynomials `f` and `g` in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` using a modular algorithm. The algorithm first computes the primitive associate `\check m_{\alpha}(z)` of the minimal polynomial `m_{\alpha}` in `\mathbb{Z}[z]` and the primitive associates of `f` and `g` in `\mathbb{Z}[x_1, \ldots, x_{n-1}][z]/(\check m_{\alpha})[x_0]`. Then it computes the GCD in `\mathbb Q(x_1, \ldots, x_{n-1})[z]/(m_{\alpha}(z))[x_0]`. This is done by calculating the GCD in `\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]` for suitable primes `p` and then reconstructing the coefficients with the Chinese Remainder Theorem and Rational Reconstuction. The GCD over `\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]` is computed with a recursive subroutine, which evaluates the polynomials at `x_{n-1} = a` for suitable evaluation points `a \in \mathbb Z_p` and then calls itself recursively until the ground domain does no longer contain any parameters. For `\mathbb{Z}_p[z]/(\check m_{\alpha}(z))[x_0]` the Euclidean Algorithm is used. The results of those recursive calls are then interpolated and Rational Function Reconstruction is used to obtain the correct coefficients. The results, both in `\mathbb Q(x_1, \ldots, x_{n-1})[z]/(m_{\alpha}(z))[x_0]` and `\mathbb{Z}_p(x_1, \ldots, x_{n-1})[z]/(\check m_{\alpha}(z))[x_0]`, are verified by a fraction free trial division. Apart from the above GCD computation some GCDs in `\mathbb Q(\alpha)[x_1, \ldots, x_{n-1}]` have to be calculated, because treating the polynomials as univariate ones can result in a spurious content of the GCD. For this ``func_field_modgcd`` is called recursively. Parameters ========== f, g : PolyElement polynomials in `\mathbb Q(\alpha)[x_0, \ldots, x_{n-1}]` Returns ======= h : PolyElement monic GCD of the polynomials `f` and `g` cff : PolyElement cofactor of `f`, i.e. `\frac f h` cfg : PolyElement cofactor of `g`, i.e. `\frac g h` Examples ======== >>> from sympy.polys.modulargcd import func_field_modgcd >>> from sympy.polys import AlgebraicField, QQ, ring >>> from sympy import sqrt >>> A = AlgebraicField(QQ, sqrt(2)) >>> R, x = ring('x', A) >>> f = x**2 - 2 >>> g = x + sqrt(2) >>> h, cff, cfg = func_field_modgcd(f, g) >>> h == x + sqrt(2) True >>> cff * h == f True >>> cfg * h == g True >>> R, x, y = ring('x, y', A) >>> f = x**2 + 2*sqrt(2)*x*y + 2*y**2 >>> g = x + sqrt(2)*y >>> h, cff, cfg = func_field_modgcd(f, g) >>> h == x + sqrt(2)*y True >>> cff * h == f True >>> cfg * h == g True >>> f = x + sqrt(2)*y >>> g = x + y >>> h, cff, cfg = func_field_modgcd(f, g) >>> h == R.one True >>> cff * h == f True >>> cfg * h == g True References ========== 1. [Hoeij04]_ """ ring = f.ring domain = ring.domain n = ring.ngens assert ring == g.ring and domain.is_Algebraic result = _trivial_gcd(f, g) if result is not None: return result z = Dummy('z') ZZring = ring.clone(symbols=ring.symbols + (z,), domain=domain.domain.get_ring()) if n == 1: f_ = _to_ZZ_poly(f, ZZring) g_ = _to_ZZ_poly(g, ZZring) minpoly = ZZring.drop(0).from_dense(domain.mod.rep) h = _func_field_modgcd_m(f_, g_, minpoly) h = _to_ANP_poly(h, ring) else: # contx0f in Q(a)[x_1, ..., x_{n-1}], f in Q(a)[x_0, ..., x_{n-1}] contx0f, f = _primitive_in_x0(f) contx0g, g = _primitive_in_x0(g) contx0h = func_field_modgcd(contx0f, contx0g)[0] ZZring_ = ZZring.drop_to_ground(*range(1, n)) f_ = _to_ZZ_poly(f, ZZring_) g_ = _to_ZZ_poly(g, ZZring_) minpoly = _minpoly_from_dense(domain.mod, ZZring_.drop(0)) h = _func_field_modgcd_m(f_, g_, minpoly) h = _to_ANP_poly(h, ring) contx0h_, h = _primitive_in_x0(h) h *= contx0h.set_ring(ring) f *= contx0f.set_ring(ring) g *= contx0g.set_ring(ring) h = h.quo_ground(h.LC) return h, f.quo(h), g.quo(h) sympy-sympy-1.9/sympy/polys/monomials.py000066400000000000000000000450301412543434000206240ustar00rootroot00000000000000"""Tools and arithmetics for monomials of distributed polynomials. """ from itertools import combinations_with_replacement, product from textwrap import dedent from sympy.core import Mul, S, Tuple, sympify from sympy.core.compatibility import iterable from sympy.polys.polyerrors import ExactQuotientFailed from sympy.polys.polyutils import PicklableWithSlots, dict_from_expr from sympy.utilities import public from sympy.core.compatibility import is_sequence @public def itermonomials(variables, max_degrees, min_degrees=None): r""" ``max_degrees`` and ``min_degrees`` are either both integers or both lists. Unless otherwise specified, ``min_degrees`` is either ``0`` or ``[0, ..., 0]``. A generator of all monomials ``monom`` is returned, such that either ``min_degree <= total_degree(monom) <= max_degree``, or ``min_degrees[i] <= degree_list(monom)[i] <= max_degrees[i]``, for all ``i``. Case I. ``max_degrees`` and ``min_degrees`` are both integers ============================================================= Given a set of variables $V$ and a min_degree $N$ and a max_degree $M$ generate a set of monomials of degree less than or equal to $N$ and greater than or equal to $M$. The total number of monomials in commutative variables is huge and is given by the following formula if $M = 0$: .. math:: \frac{(\#V + N)!}{\#V! N!} For example if we would like to generate a dense polynomial of a total degree $N = 50$ and $M = 0$, which is the worst case, in 5 variables, assuming that exponents and all of coefficients are 32-bit long and stored in an array we would need almost 80 GiB of memory! Fortunately most polynomials, that we will encounter, are sparse. Consider monomials in commutative variables $x$ and $y$ and non-commutative variables $a$ and $b$:: >>> from sympy import symbols >>> from sympy.polys.monomials import itermonomials >>> from sympy.polys.orderings import monomial_key >>> from sympy.abc import x, y >>> sorted(itermonomials([x, y], 2), key=monomial_key('grlex', [y, x])) [1, x, y, x**2, x*y, y**2] >>> sorted(itermonomials([x, y], 3), key=monomial_key('grlex', [y, x])) [1, x, y, x**2, x*y, y**2, x**3, x**2*y, x*y**2, y**3] >>> a, b = symbols('a, b', commutative=False) >>> set(itermonomials([a, b, x], 2)) {1, a, a**2, b, b**2, x, x**2, a*b, b*a, x*a, x*b} >>> sorted(itermonomials([x, y], 2, 1), key=monomial_key('grlex', [y, x])) [x, y, x**2, x*y, y**2] Case II. ``max_degrees`` and ``min_degrees`` are both lists =========================================================== If ``max_degrees = [d_1, ..., d_n]`` and ``min_degrees = [e_1, ..., e_n]``, the number of monomials generated is: .. math:: (d_1 - e_1 + 1) (d_2 - e_2 + 1) \cdots (d_n - e_n + 1) Let us generate all monomials ``monom`` in variables $x$ and $y$ such that ``[1, 2][i] <= degree_list(monom)[i] <= [2, 4][i]``, ``i = 0, 1`` :: >>> from sympy import symbols >>> from sympy.polys.monomials import itermonomials >>> from sympy.polys.orderings import monomial_key >>> from sympy.abc import x, y >>> sorted(itermonomials([x, y], [2, 4], [1, 2]), reverse=True, key=monomial_key('lex', [x, y])) [x**2*y**4, x**2*y**3, x**2*y**2, x*y**4, x*y**3, x*y**2] """ n = len(variables) if is_sequence(max_degrees): if len(max_degrees) != n: raise ValueError('Argument sizes do not match') if min_degrees is None: min_degrees = [0]*n elif not is_sequence(min_degrees): raise ValueError('min_degrees is not a list') else: if len(min_degrees) != n: raise ValueError('Argument sizes do not match') if any(i < 0 for i in min_degrees): raise ValueError("min_degrees can't contain negative numbers") total_degree = False else: max_degree = max_degrees if max_degree < 0: raise ValueError("max_degrees can't be negative") if min_degrees is None: min_degree = 0 else: if min_degrees < 0: raise ValueError("min_degrees can't be negative") min_degree = min_degrees total_degree = True if total_degree: if min_degree > max_degree: return if not variables or max_degree == 0: yield S.One return # Force to list in case of passed tuple or other incompatible collection variables = list(variables) + [S.One] if all(variable.is_commutative for variable in variables): monomials_list_comm = [] for item in combinations_with_replacement(variables, max_degree): powers = dict() for variable in variables: powers[variable] = 0 for variable in item: if variable != 1: powers[variable] += 1 if sum(powers.values()) >= min_degree: monomials_list_comm.append(Mul(*item)) yield from set(monomials_list_comm) else: monomials_list_non_comm = [] for item in product(variables, repeat=max_degree): powers = dict() for variable in variables: powers[variable] = 0 for variable in item: if variable != 1: powers[variable] += 1 if sum(powers.values()) >= min_degree: monomials_list_non_comm.append(Mul(*item)) yield from set(monomials_list_non_comm) else: if any(min_degrees[i] > max_degrees[i] for i in range(n)): raise ValueError('min_degrees[i] must be <= max_degrees[i] for all i') power_lists = [] for var, min_d, max_d in zip(variables, min_degrees, max_degrees): power_lists.append([var**i for i in range(min_d, max_d + 1)]) for powers in product(*power_lists): yield Mul(*powers) def monomial_count(V, N): r""" Computes the number of monomials. The number of monomials is given by the following formula: .. math:: \frac{(\#V + N)!}{\#V! N!} where `N` is a total degree and `V` is a set of variables. Examples ======== >>> from sympy.polys.monomials import itermonomials, monomial_count >>> from sympy.polys.orderings import monomial_key >>> from sympy.abc import x, y >>> monomial_count(2, 2) 6 >>> M = list(itermonomials([x, y], 2)) >>> sorted(M, key=monomial_key('grlex', [y, x])) [1, x, y, x**2, x*y, y**2] >>> len(M) 6 """ from sympy import factorial return factorial(V + N) / factorial(V) / factorial(N) def monomial_mul(A, B): """ Multiplication of tuples representing monomials. Examples ======== Lets multiply `x**3*y**4*z` with `x*y**2`:: >>> from sympy.polys.monomials import monomial_mul >>> monomial_mul((3, 4, 1), (1, 2, 0)) (4, 6, 1) which gives `x**4*y**5*z`. """ return tuple([ a + b for a, b in zip(A, B) ]) def monomial_div(A, B): """ Division of tuples representing monomials. Examples ======== Lets divide `x**3*y**4*z` by `x*y**2`:: >>> from sympy.polys.monomials import monomial_div >>> monomial_div((3, 4, 1), (1, 2, 0)) (2, 2, 1) which gives `x**2*y**2*z`. However:: >>> monomial_div((3, 4, 1), (1, 2, 2)) is None True `x*y**2*z**2` does not divide `x**3*y**4*z`. """ C = monomial_ldiv(A, B) if all(c >= 0 for c in C): return tuple(C) else: return None def monomial_ldiv(A, B): """ Division of tuples representing monomials. Examples ======== Lets divide `x**3*y**4*z` by `x*y**2`:: >>> from sympy.polys.monomials import monomial_ldiv >>> monomial_ldiv((3, 4, 1), (1, 2, 0)) (2, 2, 1) which gives `x**2*y**2*z`. >>> monomial_ldiv((3, 4, 1), (1, 2, 2)) (2, 2, -1) which gives `x**2*y**2*z**-1`. """ return tuple([ a - b for a, b in zip(A, B) ]) def monomial_pow(A, n): """Return the n-th pow of the monomial. """ return tuple([ a*n for a in A ]) def monomial_gcd(A, B): """ Greatest common divisor of tuples representing monomials. Examples ======== Lets compute GCD of `x*y**4*z` and `x**3*y**2`:: >>> from sympy.polys.monomials import monomial_gcd >>> monomial_gcd((1, 4, 1), (3, 2, 0)) (1, 2, 0) which gives `x*y**2`. """ return tuple([ min(a, b) for a, b in zip(A, B) ]) def monomial_lcm(A, B): """ Least common multiple of tuples representing monomials. Examples ======== Lets compute LCM of `x*y**4*z` and `x**3*y**2`:: >>> from sympy.polys.monomials import monomial_lcm >>> monomial_lcm((1, 4, 1), (3, 2, 0)) (3, 4, 1) which gives `x**3*y**4*z`. """ return tuple([ max(a, b) for a, b in zip(A, B) ]) def monomial_divides(A, B): """ Does there exist a monomial X such that XA == B? Examples ======== >>> from sympy.polys.monomials import monomial_divides >>> monomial_divides((1, 2), (3, 4)) True >>> monomial_divides((1, 2), (0, 2)) False """ return all(a <= b for a, b in zip(A, B)) def monomial_max(*monoms): """ Returns maximal degree for each variable in a set of monomials. Examples ======== Consider monomials `x**3*y**4*z**5`, `y**5*z` and `x**6*y**3*z**9`. We wish to find out what is the maximal degree for each of `x`, `y` and `z` variables:: >>> from sympy.polys.monomials import monomial_max >>> monomial_max((3,4,5), (0,5,1), (6,3,9)) (6, 5, 9) """ M = list(monoms[0]) for N in monoms[1:]: for i, n in enumerate(N): M[i] = max(M[i], n) return tuple(M) def monomial_min(*monoms): """ Returns minimal degree for each variable in a set of monomials. Examples ======== Consider monomials `x**3*y**4*z**5`, `y**5*z` and `x**6*y**3*z**9`. We wish to find out what is the minimal degree for each of `x`, `y` and `z` variables:: >>> from sympy.polys.monomials import monomial_min >>> monomial_min((3,4,5), (0,5,1), (6,3,9)) (0, 3, 1) """ M = list(monoms[0]) for N in monoms[1:]: for i, n in enumerate(N): M[i] = min(M[i], n) return tuple(M) def monomial_deg(M): """ Returns the total degree of a monomial. Examples ======== The total degree of `xy^2` is 3: >>> from sympy.polys.monomials import monomial_deg >>> monomial_deg((1, 2)) 3 """ return sum(M) def term_div(a, b, domain): """Division of two terms in over a ring/field. """ a_lm, a_lc = a b_lm, b_lc = b monom = monomial_div(a_lm, b_lm) if domain.is_Field: if monom is not None: return monom, domain.quo(a_lc, b_lc) else: return None else: if not (monom is None or a_lc % b_lc): return monom, domain.quo(a_lc, b_lc) else: return None class MonomialOps: """Code generator of fast monomial arithmetic functions. """ def __init__(self, ngens): self.ngens = ngens def _build(self, code, name): ns = {} exec(code, ns) return ns[name] def _vars(self, name): return [ "%s%s" % (name, i) for i in range(self.ngens) ] def mul(self): name = "monomial_mul" template = dedent("""\ def %(name)s(A, B): (%(A)s,) = A (%(B)s,) = B return (%(AB)s,) """) A = self._vars("a") B = self._vars("b") AB = [ "%s + %s" % (a, b) for a, b in zip(A, B) ] code = template % dict(name=name, A=", ".join(A), B=", ".join(B), AB=", ".join(AB)) return self._build(code, name) def pow(self): name = "monomial_pow" template = dedent("""\ def %(name)s(A, k): (%(A)s,) = A return (%(Ak)s,) """) A = self._vars("a") Ak = [ "%s*k" % a for a in A ] code = template % dict(name=name, A=", ".join(A), Ak=", ".join(Ak)) return self._build(code, name) def mulpow(self): name = "monomial_mulpow" template = dedent("""\ def %(name)s(A, B, k): (%(A)s,) = A (%(B)s,) = B return (%(ABk)s,) """) A = self._vars("a") B = self._vars("b") ABk = [ "%s + %s*k" % (a, b) for a, b in zip(A, B) ] code = template % dict(name=name, A=", ".join(A), B=", ".join(B), ABk=", ".join(ABk)) return self._build(code, name) def ldiv(self): name = "monomial_ldiv" template = dedent("""\ def %(name)s(A, B): (%(A)s,) = A (%(B)s,) = B return (%(AB)s,) """) A = self._vars("a") B = self._vars("b") AB = [ "%s - %s" % (a, b) for a, b in zip(A, B) ] code = template % dict(name=name, A=", ".join(A), B=", ".join(B), AB=", ".join(AB)) return self._build(code, name) def div(self): name = "monomial_div" template = dedent("""\ def %(name)s(A, B): (%(A)s,) = A (%(B)s,) = B %(RAB)s return (%(R)s,) """) A = self._vars("a") B = self._vars("b") RAB = [ "r%(i)s = a%(i)s - b%(i)s\n if r%(i)s < 0: return None" % dict(i=i) for i in range(self.ngens) ] R = self._vars("r") code = template % dict(name=name, A=", ".join(A), B=", ".join(B), RAB="\n ".join(RAB), R=", ".join(R)) return self._build(code, name) def lcm(self): name = "monomial_lcm" template = dedent("""\ def %(name)s(A, B): (%(A)s,) = A (%(B)s,) = B return (%(AB)s,) """) A = self._vars("a") B = self._vars("b") AB = [ "%s if %s >= %s else %s" % (a, a, b, b) for a, b in zip(A, B) ] code = template % dict(name=name, A=", ".join(A), B=", ".join(B), AB=", ".join(AB)) return self._build(code, name) def gcd(self): name = "monomial_gcd" template = dedent("""\ def %(name)s(A, B): (%(A)s,) = A (%(B)s,) = B return (%(AB)s,) """) A = self._vars("a") B = self._vars("b") AB = [ "%s if %s <= %s else %s" % (a, a, b, b) for a, b in zip(A, B) ] code = template % dict(name=name, A=", ".join(A), B=", ".join(B), AB=", ".join(AB)) return self._build(code, name) @public class Monomial(PicklableWithSlots): """Class representing a monomial, i.e. a product of powers. """ __slots__ = ('exponents', 'gens') def __init__(self, monom, gens=None): if not iterable(monom): rep, gens = dict_from_expr(sympify(monom), gens=gens) if len(rep) == 1 and list(rep.values())[0] == 1: monom = list(rep.keys())[0] else: raise ValueError("Expected a monomial got {}".format(monom)) self.exponents = tuple(map(int, monom)) self.gens = gens def rebuild(self, exponents, gens=None): return self.__class__(exponents, gens or self.gens) def __len__(self): return len(self.exponents) def __iter__(self): return iter(self.exponents) def __getitem__(self, item): return self.exponents[item] def __hash__(self): return hash((self.__class__.__name__, self.exponents, self.gens)) def __str__(self): if self.gens: return "*".join([ "%s**%s" % (gen, exp) for gen, exp in zip(self.gens, self.exponents) ]) else: return "%s(%s)" % (self.__class__.__name__, self.exponents) def as_expr(self, *gens): """Convert a monomial instance to a SymPy expression. """ gens = gens or self.gens if not gens: raise ValueError( "can't convert %s to an expression without generators" % self) return Mul(*[ gen**exp for gen, exp in zip(gens, self.exponents) ]) def __eq__(self, other): if isinstance(other, Monomial): exponents = other.exponents elif isinstance(other, (tuple, Tuple)): exponents = other else: return False return self.exponents == exponents def __ne__(self, other): return not self == other def __mul__(self, other): if isinstance(other, Monomial): exponents = other.exponents elif isinstance(other, (tuple, Tuple)): exponents = other else: raise NotImplementedError return self.rebuild(monomial_mul(self.exponents, exponents)) def __truediv__(self, other): if isinstance(other, Monomial): exponents = other.exponents elif isinstance(other, (tuple, Tuple)): exponents = other else: raise NotImplementedError result = monomial_div(self.exponents, exponents) if result is not None: return self.rebuild(result) else: raise ExactQuotientFailed(self, Monomial(other)) __floordiv__ = __truediv__ def __pow__(self, other): n = int(other) if not n: return self.rebuild([0]*len(self)) elif n > 0: exponents = self.exponents for i in range(1, n): exponents = monomial_mul(exponents, self.exponents) return self.rebuild(exponents) else: raise ValueError("a non-negative integer expected, got %s" % other) def gcd(self, other): """Greatest common divisor of monomials. """ if isinstance(other, Monomial): exponents = other.exponents elif isinstance(other, (tuple, Tuple)): exponents = other else: raise TypeError( "an instance of Monomial class expected, got %s" % other) return self.rebuild(monomial_gcd(self.exponents, exponents)) def lcm(self, other): """Least common multiple of monomials. """ if isinstance(other, Monomial): exponents = other.exponents elif isinstance(other, (tuple, Tuple)): exponents = other else: raise TypeError( "an instance of Monomial class expected, got %s" % other) return self.rebuild(monomial_lcm(self.exponents, exponents)) sympy-sympy-1.9/sympy/polys/multivariate_resultants.py000066400000000000000000000351031412543434000236200ustar00rootroot00000000000000""" This module contains functions for two multivariate resultants. These are: - Dixon's resultant. - Macaulay's resultant. Multivariate resultants are used to identify whether a multivariate system has common roots. That is when the resultant is equal to zero. """ from sympy import IndexedBase, Matrix, Mul, Poly from sympy import rem, prod, degree_list, diag, simplify from sympy.polys.monomials import itermonomials, monomial_deg from sympy.polys.orderings import monomial_key from sympy.polys.polytools import poly_from_expr, total_degree from sympy.functions.combinatorial.factorials import binomial from itertools import combinations_with_replacement from sympy.utilities.exceptions import SymPyDeprecationWarning class DixonResultant(): """ A class for retrieving the Dixon's resultant of a multivariate system. Examples ======== >>> from sympy.core import symbols >>> from sympy.polys.multivariate_resultants import DixonResultant >>> x, y = symbols('x, y') >>> p = x + y >>> q = x ** 2 + y ** 3 >>> h = x ** 2 + y >>> dixon = DixonResultant(variables=[x, y], polynomials=[p, q, h]) >>> poly = dixon.get_dixon_polynomial() >>> matrix = dixon.get_dixon_matrix(polynomial=poly) >>> matrix Matrix([ [ 0, 0, -1, 0, -1], [ 0, -1, 0, -1, 0], [-1, 0, 1, 0, 0], [ 0, -1, 0, 0, 1], [-1, 0, 0, 1, 0]]) >>> matrix.det() 0 See Also ======== Notebook in examples: sympy/example/notebooks. References ========== .. [1] [Kapur1994]_ .. [2] [Palancz08]_ """ def __init__(self, polynomials, variables): """ A class that takes two lists, a list of polynomials and list of variables. Returns the Dixon matrix of the multivariate system. Parameters ---------- polynomials : list of polynomials A list of m n-degree polynomials variables: list A list of all n variables """ self.polynomials = polynomials self.variables = variables self.n = len(self.variables) self.m = len(self.polynomials) a = IndexedBase("alpha") # A list of n alpha variables (the replacing variables) self.dummy_variables = [a[i] for i in range(self.n)] # A list of the d_max of each variable. self._max_degrees = [max(degree_list(poly)[i] for poly in self.polynomials) for i in range(self.n)] @property def max_degrees(self): SymPyDeprecationWarning(feature="max_degrees", issue=17763, deprecated_since_version="1.5").warn() return self._max_degrees def get_dixon_polynomial(self): r""" Returns ======= dixon_polynomial: polynomial Dixon's polynomial is calculated as: delta = Delta(A) / ((x_1 - a_1) ... (x_n - a_n)) where, A = |p_1(x_1,... x_n), ..., p_n(x_1,... x_n)| |p_1(a_1,... x_n), ..., p_n(a_1,... x_n)| |... , ..., ...| |p_1(a_1,... a_n), ..., p_n(a_1,... a_n)| """ if self.m != (self.n + 1): raise ValueError('Method invalid for given combination.') # First row rows = [self.polynomials] temp = list(self.variables) for idx in range(self.n): temp[idx] = self.dummy_variables[idx] substitution = {var: t for var, t in zip(self.variables, temp)} rows.append([f.subs(substitution) for f in self.polynomials]) A = Matrix(rows) terms = zip(self.variables, self.dummy_variables) product_of_differences = Mul(*[a - b for a, b in terms]) dixon_polynomial = (A.det() / product_of_differences).factor() return poly_from_expr(dixon_polynomial, self.dummy_variables)[0] def get_upper_degree(self): SymPyDeprecationWarning(feature="get_upper_degree", useinstead="get_max_degrees", issue=17763, deprecated_since_version="1.5").warn() list_of_products = [self.variables[i] ** self._max_degrees[i] for i in range(self.n)] product = prod(list_of_products) product = Poly(product).monoms() return monomial_deg(*product) def get_max_degrees(self, polynomial): r""" Returns a list of the maximum degree of each variable appearing in the coefficients of the Dixon polynomial. The coefficients are viewed as polys in x_1, ... , x_n. """ deg_lists = [degree_list(Poly(poly, self.variables)) for poly in polynomial.coeffs()] max_degrees = [max(degs) for degs in zip(*deg_lists)] return max_degrees def get_dixon_matrix(self, polynomial): r""" Construct the Dixon matrix from the coefficients of polynomial \alpha. Each coefficient is viewed as a polynomial of x_1, ..., x_n. """ max_degrees = self.get_max_degrees(polynomial) # list of column headers of the Dixon matrix. monomials = itermonomials(self.variables, max_degrees) monomials = sorted(monomials, reverse=True, key=monomial_key('lex', self.variables)) dixon_matrix = Matrix([[Poly(c, *self.variables).coeff_monomial(m) for m in monomials] for c in polynomial.coeffs()]) # remove columns if needed if dixon_matrix.shape[0] != dixon_matrix.shape[1]: keep = [column for column in range(dixon_matrix.shape[-1]) if any([element != 0 for element in dixon_matrix[:, column]])] dixon_matrix = dixon_matrix[:, keep] return dixon_matrix def KSY_precondition(self, matrix): """ Test for the validity of the Kapur-Saxena-Yang precondition. The precondition requires that the column corresponding to the monomial 1 = x_1 ^ 0 * x_2 ^ 0 * ... * x_n ^ 0 is not a linear combination of the remaining ones. In sympy notation this is the last column. For the precondition to hold the last non-zero row of the rref matrix should be of the form [0, 0, ..., 1]. """ if matrix.is_zero_matrix: return False m, n = matrix.shape # simplify the matrix and keep only its non-zero rows matrix = simplify(matrix.rref()[0]) rows = [i for i in range(m) if any(matrix[i, j] != 0 for j in range(n))] matrix = matrix[rows,:] condition = Matrix([[0]*(n-1) + [1]]) if matrix[-1,:] == condition: return True else: return False def delete_zero_rows_and_columns(self, matrix): """Remove the zero rows and columns of the matrix.""" rows = [ i for i in range(matrix.rows) if not matrix.row(i).is_zero_matrix] cols = [ j for j in range(matrix.cols) if not matrix.col(j).is_zero_matrix] return matrix[rows, cols] def product_leading_entries(self, matrix): """Calculate the product of the leading entries of the matrix.""" res = 1 for row in range(matrix.rows): for el in matrix.row(row): if el != 0: res = res * el break return res def get_KSY_Dixon_resultant(self, matrix): """Calculate the Kapur-Saxena-Yang approach to the Dixon Resultant.""" matrix = self.delete_zero_rows_and_columns(matrix) _, U, _ = matrix.LUdecomposition() matrix = self.delete_zero_rows_and_columns(simplify(U)) return self.product_leading_entries(matrix) class MacaulayResultant(): """ A class for calculating the Macaulay resultant. Note that the polynomials must be homogenized and their coefficients must be given as symbols. Examples ======== >>> from sympy.core import symbols >>> from sympy.polys.multivariate_resultants import MacaulayResultant >>> x, y, z = symbols('x, y, z') >>> a_0, a_1, a_2 = symbols('a_0, a_1, a_2') >>> b_0, b_1, b_2 = symbols('b_0, b_1, b_2') >>> c_0, c_1, c_2,c_3, c_4 = symbols('c_0, c_1, c_2, c_3, c_4') >>> f = a_0 * y - a_1 * x + a_2 * z >>> g = b_1 * x ** 2 + b_0 * y ** 2 - b_2 * z ** 2 >>> h = c_0 * y * z ** 2 - c_1 * x ** 3 + c_2 * x ** 2 * z - c_3 * x * z ** 2 + c_4 * z ** 3 >>> mac = MacaulayResultant(polynomials=[f, g, h], variables=[x, y, z]) >>> mac.monomial_set [x**4, x**3*y, x**3*z, x**2*y**2, x**2*y*z, x**2*z**2, x*y**3, x*y**2*z, x*y*z**2, x*z**3, y**4, y**3*z, y**2*z**2, y*z**3, z**4] >>> matrix = mac.get_matrix() >>> submatrix = mac.get_submatrix(matrix) >>> submatrix Matrix([ [-a_1, a_0, a_2, 0], [ 0, -a_1, 0, 0], [ 0, 0, -a_1, 0], [ 0, 0, 0, -a_1]]) See Also ======== Notebook in examples: sympy/example/notebooks. References ========== .. [1] [Bruce97]_ .. [2] [Stiller96]_ """ def __init__(self, polynomials, variables): """ Parameters ========== variables: list A list of all n variables polynomials : list of sympy polynomials A list of m n-degree polynomials """ self.polynomials = polynomials self.variables = variables self.n = len(variables) # A list of the d_max of each polynomial. self.degrees = [total_degree(poly, *self.variables) for poly in self.polynomials] self.degree_m = self._get_degree_m() self.monomials_size = self.get_size() # The set T of all possible monomials of degree degree_m self.monomial_set = self.get_monomials_of_certain_degree(self.degree_m) def _get_degree_m(self): r""" Returns ======= degree_m: int The degree_m is calculated as 1 + \sum_1 ^ n (d_i - 1), where d_i is the degree of the i polynomial """ return 1 + sum(d - 1 for d in self.degrees) def get_size(self): r""" Returns ======= size: int The size of set T. Set T is the set of all possible monomials of the n variables for degree equal to the degree_m """ return binomial(self.degree_m + self.n - 1, self.n - 1) def get_monomials_of_certain_degree(self, degree): """ Returns ======= monomials: list A list of monomials of a certain degree. """ monomials = [Mul(*monomial) for monomial in combinations_with_replacement(self.variables, degree)] return sorted(monomials, reverse=True, key=monomial_key('lex', self.variables)) def get_row_coefficients(self): """ Returns ======= row_coefficients: list The row coefficients of Macaulay's matrix """ row_coefficients = [] divisible = [] for i in range(self.n): if i == 0: degree = self.degree_m - self.degrees[i] monomial = self.get_monomials_of_certain_degree(degree) row_coefficients.append(monomial) else: divisible.append(self.variables[i - 1] ** self.degrees[i - 1]) degree = self.degree_m - self.degrees[i] poss_rows = self.get_monomials_of_certain_degree(degree) for div in divisible: for p in poss_rows: if rem(p, div) == 0: poss_rows = [item for item in poss_rows if item != p] row_coefficients.append(poss_rows) return row_coefficients def get_matrix(self): """ Returns ======= macaulay_matrix: Matrix The Macaulay numerator matrix """ rows = [] row_coefficients = self.get_row_coefficients() for i in range(self.n): for multiplier in row_coefficients[i]: coefficients = [] poly = Poly(self.polynomials[i] * multiplier, *self.variables) for mono in self.monomial_set: coefficients.append(poly.coeff_monomial(mono)) rows.append(coefficients) macaulay_matrix = Matrix(rows) return macaulay_matrix def get_reduced_nonreduced(self): r""" Returns ======= reduced: list A list of the reduced monomials non_reduced: list A list of the monomials that are not reduced Definition ========== A polynomial is said to be reduced in x_i, if its degree (the maximum degree of its monomials) in x_i is less than d_i. A polynomial that is reduced in all variables but one is said simply to be reduced. """ divisible = [] for m in self.monomial_set: temp = [] for i, v in enumerate(self.variables): temp.append(bool(total_degree(m, v) >= self.degrees[i])) divisible.append(temp) reduced = [i for i, r in enumerate(divisible) if sum(r) < self.n - 1] non_reduced = [i for i, r in enumerate(divisible) if sum(r) >= self.n -1] return reduced, non_reduced def get_submatrix(self, matrix): r""" Returns ======= macaulay_submatrix: Matrix The Macaulay denominator matrix. Columns that are non reduced are kept. The row which contains one of the a_{i}s is dropped. a_{i}s are the coefficients of x_i ^ {d_i}. """ reduced, non_reduced = self.get_reduced_nonreduced() # if reduced == [], then det(matrix) should be 1 if reduced == []: return diag([1]) # reduced != [] reduction_set = [v ** self.degrees[i] for i, v in enumerate(self.variables)] ais = list([self.polynomials[i].coeff(reduction_set[i]) for i in range(self.n)]) reduced_matrix = matrix[:, reduced] keep = [] for row in range(reduced_matrix.rows): check = [ai in reduced_matrix[row, :] for ai in ais] if True not in check: keep.append(row) return matrix[keep, non_reduced] sympy-sympy-1.9/sympy/polys/numberfields.py000066400000000000000000001025241412543434000213070ustar00rootroot00000000000000"""Computational algebraic field theory. """ from functools import reduce from sympy import ( S, Rational, AlgebraicNumber, GoldenRatio, TribonacciConstant, Add, Mul, sympify, Dummy, expand_mul, I, pi ) from sympy.functions import sqrt, cbrt from sympy.core.exprtools import Factors from sympy.core.function import _mexpand from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.trigonometric import cos, sin, tan from sympy.ntheory import sieve from sympy.ntheory.factor_ import divisors from sympy.utilities.iterables import subsets from sympy.polys.densetools import dup_eval from sympy.polys.domains import ZZ, QQ from sympy.polys.orthopolys import dup_chebyshevt from sympy.polys.polyerrors import ( IsomorphismFailed, NotAlgebraic, GeneratorsError, ) from sympy.polys.polytools import ( Poly, PurePoly, invert, factor_list, groebner, resultant, degree, poly_from_expr, parallel_poly_from_expr, lcm ) from sympy.polys.polyutils import dict_from_expr, expr_from_dict from sympy.polys.ring_series import rs_compose_add from sympy.polys.rings import ring from sympy.polys.rootoftools import CRootOf from sympy.polys.specialpolys import cyclotomic_poly from sympy.printing.lambdarepr import LambdaPrinter from sympy.printing.pycode import PythonCodePrinter, MpmathPrinter from sympy.simplify.radsimp import _split_gcd from sympy.simplify.simplify import _is_sum_surds from sympy.utilities import ( numbered_symbols, lambdify, public, sift ) from mpmath import pslq, mp def _choose_factor(factors, x, v, dom=QQ, prec=200, bound=5): """ Return a factor having root ``v`` It is assumed that one of the factors has root ``v``. """ from sympy.polys.polyutils import illegal if isinstance(factors[0], tuple): factors = [f[0] for f in factors] if len(factors) == 1: return factors[0] prec1 = 10 points = {} symbols = dom.symbols if hasattr(dom, 'symbols') else [] while prec1 <= prec: # when dealing with non-Rational numbers we usually evaluate # with `subs` argument but we only need a ballpark evaluation xv = {x:v if not v.is_number else v.n(prec1)} fe = [f.as_expr().xreplace(xv) for f in factors] # assign integers [0, n) to symbols (if any) for n in subsets(range(bound), k=len(symbols), repetition=True): for s, i in zip(symbols, n): points[s] = i # evaluate the expression at these points candidates = [(abs(f.subs(points).n(prec1)), i) for i,f in enumerate(fe)] # if we get invalid numbers (e.g. from division by zero) # we try again if any(i in illegal for i, _ in candidates): continue # find the smallest two -- if they differ significantly # then we assume we have found the factor that becomes # 0 when v is substituted into it can = sorted(candidates) (a, ix), (b, _) = can[:2] if b > a * 10**6: # XXX what to use? return factors[ix] prec1 *= 2 raise NotImplementedError("multiple candidates for the minimal polynomial of %s" % v) def _separate_sq(p): """ helper function for ``_minimal_polynomial_sq`` It selects a rational ``g`` such that the polynomial ``p`` consists of a sum of terms whose surds squared have gcd equal to ``g`` and a sum of terms with surds squared prime with ``g``; then it takes the field norm to eliminate ``sqrt(g)`` See simplify.simplify.split_surds and polytools.sqf_norm. Examples ======== >>> from sympy import sqrt >>> from sympy.abc import x >>> from sympy.polys.numberfields import _separate_sq >>> p= -x + sqrt(2) + sqrt(3) + sqrt(7) >>> p = _separate_sq(p); p -x**2 + 2*sqrt(3)*x + 2*sqrt(7)*x - 2*sqrt(21) - 8 >>> p = _separate_sq(p); p -x**4 + 4*sqrt(7)*x**3 - 32*x**2 + 8*sqrt(7)*x + 20 >>> p = _separate_sq(p); p -x**8 + 48*x**6 - 536*x**4 + 1728*x**2 - 400 """ from sympy.utilities.iterables import sift def is_sqrt(expr): return expr.is_Pow and expr.exp is S.Half # p = c1*sqrt(q1) + ... + cn*sqrt(qn) -> a = [(c1, q1), .., (cn, qn)] a = [] for y in p.args: if not y.is_Mul: if is_sqrt(y): a.append((S.One, y**2)) elif y.is_Atom: a.append((y, S.One)) elif y.is_Pow and y.exp.is_integer: a.append((y, S.One)) else: raise NotImplementedError continue T, F = sift(y.args, is_sqrt, binary=True) a.append((Mul(*F), Mul(*T)**2)) a.sort(key=lambda z: z[1]) if a[-1][1] is S.One: # there are no surds return p surds = [z for y, z in a] for i in range(len(surds)): if surds[i] != 1: break g, b1, b2 = _split_gcd(*surds[i:]) a1 = [] a2 = [] for y, z in a: if z in b1: a1.append(y*z**S.Half) else: a2.append(y*z**S.Half) p1 = Add(*a1) p2 = Add(*a2) p = _mexpand(p1**2) - _mexpand(p2**2) return p def _minimal_polynomial_sq(p, n, x): """ Returns the minimal polynomial for the ``nth-root`` of a sum of surds or ``None`` if it fails. Parameters ========== p : sum of surds n : positive integer x : variable of the returned polynomial Examples ======== >>> from sympy.polys.numberfields import _minimal_polynomial_sq >>> from sympy import sqrt >>> from sympy.abc import x >>> q = 1 + sqrt(2) + sqrt(3) >>> _minimal_polynomial_sq(q, 3, x) x**12 - 4*x**9 - 4*x**6 + 16*x**3 - 8 """ from sympy.simplify.simplify import _is_sum_surds p = sympify(p) n = sympify(n) if not n.is_Integer or not n > 0 or not _is_sum_surds(p): return None pn = p**Rational(1, n) # eliminate the square roots p -= x while 1: p1 = _separate_sq(p) if p1 is p: p = p1.subs({x:x**n}) break else: p = p1 # _separate_sq eliminates field extensions in a minimal way, so that # if n = 1 then `p = constant*(minimal_polynomial(p))` # if n > 1 it contains the minimal polynomial as a factor. if n == 1: p1 = Poly(p) if p.coeff(x**p1.degree(x)) < 0: p = -p p = p.primitive()[1] return p # by construction `p` has root `pn` # the minimal polynomial is the factor vanishing in x = pn factors = factor_list(p)[1] result = _choose_factor(factors, x, pn) return result def _minpoly_op_algebraic_element(op, ex1, ex2, x, dom, mp1=None, mp2=None): """ return the minimal polynomial for ``op(ex1, ex2)`` Parameters ========== op : operation ``Add`` or ``Mul`` ex1, ex2 : expressions for the algebraic elements x : indeterminate of the polynomials dom: ground domain mp1, mp2 : minimal polynomials for ``ex1`` and ``ex2`` or None Examples ======== >>> from sympy import sqrt, Add, Mul, QQ >>> from sympy.polys.numberfields import _minpoly_op_algebraic_element >>> from sympy.abc import x, y >>> p1 = sqrt(sqrt(2) + 1) >>> p2 = sqrt(sqrt(2) - 1) >>> _minpoly_op_algebraic_element(Mul, p1, p2, x, QQ) x - 1 >>> q1 = sqrt(y) >>> q2 = 1 / y >>> _minpoly_op_algebraic_element(Add, q1, q2, x, QQ.frac_field(y)) x**2*y**2 - 2*x*y - y**3 + 1 References ========== .. [1] https://en.wikipedia.org/wiki/Resultant .. [2] I.M. Isaacs, Proc. Amer. Math. Soc. 25 (1970), 638 "Degrees of sums in a separable field extension". """ y = Dummy(str(x)) if mp1 is None: mp1 = _minpoly_compose(ex1, x, dom) if mp2 is None: mp2 = _minpoly_compose(ex2, y, dom) else: mp2 = mp2.subs({x: y}) if op is Add: # mp1a = mp1.subs({x: x - y}) if dom == QQ: R, X = ring('X', QQ) p1 = R(dict_from_expr(mp1)[0]) p2 = R(dict_from_expr(mp2)[0]) else: (p1, p2), _ = parallel_poly_from_expr((mp1, x - y), x, y) r = p1.compose(p2) mp1a = r.as_expr() elif op is Mul: mp1a = _muly(mp1, x, y) else: raise NotImplementedError('option not available') if op is Mul or dom != QQ: r = resultant(mp1a, mp2, gens=[y, x]) else: r = rs_compose_add(p1, p2) r = expr_from_dict(r.as_expr_dict(), x) deg1 = degree(mp1, x) deg2 = degree(mp2, y) if op is Mul and deg1 == 1 or deg2 == 1: # if deg1 = 1, then mp1 = x - a; mp1a = x - y - a; # r = mp2(x - a), so that `r` is irreducible return r r = Poly(r, x, domain=dom) _, factors = r.factor_list() res = _choose_factor(factors, x, op(ex1, ex2), dom) return res.as_expr() def _invertx(p, x): """ Returns ``expand_mul(x**degree(p, x)*p.subs(x, 1/x))`` """ p1 = poly_from_expr(p, x)[0] n = degree(p1) a = [c * x**(n - i) for (i,), c in p1.terms()] return Add(*a) def _muly(p, x, y): """ Returns ``_mexpand(y**deg*p.subs({x:x / y}))`` """ p1 = poly_from_expr(p, x)[0] n = degree(p1) a = [c * x**i * y**(n - i) for (i,), c in p1.terms()] return Add(*a) def _minpoly_pow(ex, pw, x, dom, mp=None): """ Returns ``minpoly(ex**pw, x)`` Parameters ========== ex : algebraic element pw : rational number x : indeterminate of the polynomial dom: ground domain mp : minimal polynomial of ``p`` Examples ======== >>> from sympy import sqrt, QQ, Rational >>> from sympy.polys.numberfields import _minpoly_pow, minpoly >>> from sympy.abc import x, y >>> p = sqrt(1 + sqrt(2)) >>> _minpoly_pow(p, 2, x, QQ) x**2 - 2*x - 1 >>> minpoly(p**2, x) x**2 - 2*x - 1 >>> _minpoly_pow(y, Rational(1, 3), x, QQ.frac_field(y)) x**3 - y >>> minpoly(y**Rational(1, 3), x) x**3 - y """ pw = sympify(pw) if not mp: mp = _minpoly_compose(ex, x, dom) if not pw.is_rational: raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) if pw < 0: if mp == x: raise ZeroDivisionError('%s is zero' % ex) mp = _invertx(mp, x) if pw == -1: return mp pw = -pw ex = 1/ex y = Dummy(str(x)) mp = mp.subs({x: y}) n, d = pw.as_numer_denom() res = Poly(resultant(mp, x**d - y**n, gens=[y]), x, domain=dom) _, factors = res.factor_list() res = _choose_factor(factors, x, ex**pw, dom) return res.as_expr() def _minpoly_add(x, dom, *a): """ returns ``minpoly(Add(*a), dom, x)`` """ mp = _minpoly_op_algebraic_element(Add, a[0], a[1], x, dom) p = a[0] + a[1] for px in a[2:]: mp = _minpoly_op_algebraic_element(Add, p, px, x, dom, mp1=mp) p = p + px return mp def _minpoly_mul(x, dom, *a): """ returns ``minpoly(Mul(*a), dom, x)`` """ mp = _minpoly_op_algebraic_element(Mul, a[0], a[1], x, dom) p = a[0] * a[1] for px in a[2:]: mp = _minpoly_op_algebraic_element(Mul, p, px, x, dom, mp1=mp) p = p * px return mp def _minpoly_sin(ex, x): """ Returns the minimal polynomial of ``sin(ex)`` see http://mathworld.wolfram.com/TrigonometryAngles.html """ c, a = ex.args[0].as_coeff_Mul() if a is pi: if c.is_rational: n = c.q q = sympify(n) if q.is_prime: # for a = pi*p/q with q odd prime, using chebyshevt # write sin(q*a) = mp(sin(a))*sin(a); # the roots of mp(x) are sin(pi*p/q) for p = 1,..., q - 1 a = dup_chebyshevt(n, ZZ) return Add(*[x**(n - i - 1)*a[i] for i in range(n)]) if c.p == 1: if q == 9: return 64*x**6 - 96*x**4 + 36*x**2 - 3 if n % 2 == 1: # for a = pi*p/q with q odd, use # sin(q*a) = 0 to see that the minimal polynomial must be # a factor of dup_chebyshevt(n, ZZ) a = dup_chebyshevt(n, ZZ) a = [x**(n - i)*a[i] for i in range(n + 1)] r = Add(*a) _, factors = factor_list(r) res = _choose_factor(factors, x, ex) return res expr = ((1 - cos(2*c*pi))/2)**S.Half res = _minpoly_compose(expr, x, QQ) return res raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) def _minpoly_cos(ex, x): """ Returns the minimal polynomial of ``cos(ex)`` see http://mathworld.wolfram.com/TrigonometryAngles.html """ from sympy import sqrt c, a = ex.args[0].as_coeff_Mul() if a is pi: if c.is_rational: if c.p == 1: if c.q == 7: return 8*x**3 - 4*x**2 - 4*x + 1 if c.q == 9: return 8*x**3 - 6*x + 1 elif c.p == 2: q = sympify(c.q) if q.is_prime: s = _minpoly_sin(ex, x) return _mexpand(s.subs({x:sqrt((1 - x)/2)})) # for a = pi*p/q, cos(q*a) =T_q(cos(a)) = (-1)**p n = int(c.q) a = dup_chebyshevt(n, ZZ) a = [x**(n - i)*a[i] for i in range(n + 1)] r = Add(*a) - (-1)**c.p _, factors = factor_list(r) res = _choose_factor(factors, x, ex) return res raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) def _minpoly_tan(ex, x): """ Returns the minimal polynomial of ``tan(ex)`` see https://github.com/sympy/sympy/issues/21430 """ c, a = ex.args[0].as_coeff_Mul() if a is pi: if c.is_rational: c = c * 2 n = int(c.q) a = n if c.p % 2 == 0 else 1 terms = [] for k in range((c.p+1)%2, n+1, 2): terms.append(a*x**k) a = -(a*(n-k-1)*(n-k)) // ((k+1)*(k+2)) r = Add(*terms) _, factors = factor_list(r) res = _choose_factor(factors, x, ex) return res raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) def _minpoly_exp(ex, x): """ Returns the minimal polynomial of ``exp(ex)`` """ c, a = ex.args[0].as_coeff_Mul() q = sympify(c.q) if a == I*pi: if c.is_rational: if c.p == 1 or c.p == -1: if q == 3: return x**2 - x + 1 if q == 4: return x**4 + 1 if q == 6: return x**4 - x**2 + 1 if q == 8: return x**8 + 1 if q == 9: return x**6 - x**3 + 1 if q == 10: return x**8 - x**6 + x**4 - x**2 + 1 if q.is_prime: s = 0 for i in range(q): s += (-x)**i return s # x**(2*q) = product(factors) factors = [cyclotomic_poly(i, x) for i in divisors(2*q)] mp = _choose_factor(factors, x, ex) return mp else: raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) def _minpoly_rootof(ex, x): """ Returns the minimal polynomial of a ``CRootOf`` object. """ p = ex.expr p = p.subs({ex.poly.gens[0]:x}) _, factors = factor_list(p, x) result = _choose_factor(factors, x, ex) return result def _minpoly_compose(ex, x, dom): """ Computes the minimal polynomial of an algebraic element using operations on minimal polynomials Examples ======== >>> from sympy import minimal_polynomial, sqrt, Rational >>> from sympy.abc import x, y >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=True) x**2 - 2*x - 1 >>> minimal_polynomial(sqrt(y) + 1/y, x, compose=True) x**2*y**2 - 2*x*y - y**3 + 1 """ if ex.is_Rational: return ex.q*x - ex.p if ex is I: _, factors = factor_list(x**2 + 1, x, domain=dom) return x**2 + 1 if len(factors) == 1 else x - I if ex is GoldenRatio: _, factors = factor_list(x**2 - x - 1, x, domain=dom) if len(factors) == 1: return x**2 - x - 1 else: return _choose_factor(factors, x, (1 + sqrt(5))/2, dom=dom) if ex is TribonacciConstant: _, factors = factor_list(x**3 - x**2 - x - 1, x, domain=dom) if len(factors) == 1: return x**3 - x**2 - x - 1 else: fac = (1 + cbrt(19 - 3*sqrt(33)) + cbrt(19 + 3*sqrt(33))) / 3 return _choose_factor(factors, x, fac, dom=dom) if hasattr(dom, 'symbols') and ex in dom.symbols: return x - ex if dom.is_QQ and _is_sum_surds(ex): # eliminate the square roots ex -= x while 1: ex1 = _separate_sq(ex) if ex1 is ex: return ex else: ex = ex1 if ex.is_Add: res = _minpoly_add(x, dom, *ex.args) elif ex.is_Mul: f = Factors(ex).factors r = sift(f.items(), lambda itx: itx[0].is_Rational and itx[1].is_Rational) if r[True] and dom == QQ: ex1 = Mul(*[bx**ex for bx, ex in r[False] + r[None]]) r1 = dict(r[True]) dens = [y.q for y in r1.values()] lcmdens = reduce(lcm, dens, 1) neg1 = S.NegativeOne expn1 = r1.pop(neg1, S.Zero) nums = [base**(y.p*lcmdens // y.q) for base, y in r1.items()] ex2 = Mul(*nums) mp1 = minimal_polynomial(ex1, x) # use the fact that in SymPy canonicalization products of integers # raised to rational powers are organized in relatively prime # bases, and that in ``base**(n/d)`` a perfect power is # simplified with the root # Powers of -1 have to be treated separately to preserve sign. mp2 = ex2.q*x**lcmdens - ex2.p*neg1**(expn1*lcmdens) ex2 = neg1**expn1 * ex2**Rational(1, lcmdens) res = _minpoly_op_algebraic_element(Mul, ex1, ex2, x, dom, mp1=mp1, mp2=mp2) else: res = _minpoly_mul(x, dom, *ex.args) elif ex.is_Pow: res = _minpoly_pow(ex.base, ex.exp, x, dom) elif ex.__class__ is sin: res = _minpoly_sin(ex, x) elif ex.__class__ is cos: res = _minpoly_cos(ex, x) elif ex.__class__ is tan: res = _minpoly_tan(ex, x) elif ex.__class__ is exp: res = _minpoly_exp(ex, x) elif ex.__class__ is CRootOf: res = _minpoly_rootof(ex, x) else: raise NotAlgebraic("%s doesn't seem to be an algebraic element" % ex) return res @public def minimal_polynomial(ex, x=None, compose=True, polys=False, domain=None): """ Computes the minimal polynomial of an algebraic element. Parameters ========== ex : Expr Element or expression whose minimal polynomial is to be calculated. x : Symbol, optional Independent variable of the minimal polynomial compose : boolean, optional (default=True) Method to use for computing minimal polynomial. If ``compose=True`` (default) then ``_minpoly_compose`` is used, if ``compose=False`` then groebner bases are used. polys : boolean, optional (default=False) If ``True`` returns a ``Poly`` object else an ``Expr`` object. domain : Domain, optional Ground domain Notes ===== By default ``compose=True``, the minimal polynomial of the subexpressions of ``ex`` are computed, then the arithmetic operations on them are performed using the resultant and factorization. If ``compose=False``, a bottom-up algorithm is used with ``groebner``. The default algorithm stalls less frequently. If no ground domain is given, it will be generated automatically from the expression. Examples ======== >>> from sympy import minimal_polynomial, sqrt, solve, QQ >>> from sympy.abc import x, y >>> minimal_polynomial(sqrt(2), x) x**2 - 2 >>> minimal_polynomial(sqrt(2), x, domain=QQ.algebraic_field(sqrt(2))) x - sqrt(2) >>> minimal_polynomial(sqrt(2) + sqrt(3), x) x**4 - 10*x**2 + 1 >>> minimal_polynomial(solve(x**3 + x + 3)[0], x) x**3 + x + 3 >>> minimal_polynomial(sqrt(y), x) x**2 - y """ from sympy.polys.polytools import degree from sympy.polys.domains import FractionField from sympy.core.basic import preorder_traversal ex = sympify(ex) if ex.is_number: # not sure if it's always needed but try it for numbers (issue 8354) ex = _mexpand(ex, recursive=True) for expr in preorder_traversal(ex): if expr.is_AlgebraicNumber: compose = False break if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly if not domain: if ex.free_symbols: domain = FractionField(QQ, list(ex.free_symbols)) else: domain = QQ if hasattr(domain, 'symbols') and x in domain.symbols: raise GeneratorsError("the variable %s is an element of the ground " "domain %s" % (x, domain)) if compose: result = _minpoly_compose(ex, x, domain) result = result.primitive()[1] c = result.coeff(x**degree(result, x)) if c.is_negative: result = expand_mul(-result) return cls(result, x, field=True) if polys else result.collect(x) if not domain.is_QQ: raise NotImplementedError("groebner method only works for QQ") result = _minpoly_groebner(ex, x, cls) return cls(result, x, field=True) if polys else result.collect(x) def _minpoly_groebner(ex, x, cls): """ Computes the minimal polynomial of an algebraic number using Groebner bases Examples ======== >>> from sympy import minimal_polynomial, sqrt, Rational >>> from sympy.abc import x >>> minimal_polynomial(sqrt(2) + 3*Rational(1, 3), x, compose=False) x**2 - 2*x - 1 """ from sympy.polys.polytools import degree from sympy.core.function import expand_multinomial generator = numbered_symbols('a', cls=Dummy) mapping, symbols = {}, {} def update_mapping(ex, exp, base=None): a = next(generator) symbols[ex] = a if base is not None: mapping[ex] = a**exp + base else: mapping[ex] = exp.as_expr(a) return a def bottom_up_scan(ex): if ex.is_Atom: if ex is S.ImaginaryUnit: if ex not in mapping: return update_mapping(ex, 2, 1) else: return symbols[ex] elif ex.is_Rational: return ex elif ex.is_Add: return Add(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Mul: return Mul(*[ bottom_up_scan(g) for g in ex.args ]) elif ex.is_Pow: if ex.exp.is_Rational: if ex.exp < 0: minpoly_base = _minpoly_groebner(ex.base, x, cls) inverse = invert(x, minpoly_base).as_expr() base_inv = inverse.subs(x, ex.base).expand() if ex.exp == -1: return bottom_up_scan(base_inv) else: ex = base_inv**(-ex.exp) if not ex.exp.is_Integer: base, exp = ( ex.base**ex.exp.p).expand(), Rational(1, ex.exp.q) else: base, exp = ex.base, ex.exp base = bottom_up_scan(base) expr = base**exp if expr not in mapping: return update_mapping(expr, 1/exp, -base) else: return symbols[expr] elif ex.is_AlgebraicNumber: if ex.root not in mapping: return update_mapping(ex.root, ex.minpoly) else: return symbols[ex.root] raise NotAlgebraic("%s doesn't seem to be an algebraic number" % ex) def simpler_inverse(ex): """ Returns True if it is more likely that the minimal polynomial algorithm works better with the inverse """ if ex.is_Pow: if (1/ex.exp).is_integer and ex.exp < 0: if ex.base.is_Add: return True if ex.is_Mul: hit = True for p in ex.args: if p.is_Add: return False if p.is_Pow: if p.base.is_Add and p.exp > 0: return False if hit: return True return False inverted = False ex = expand_multinomial(ex) if ex.is_AlgebraicNumber: return ex.minpoly.as_expr(x) elif ex.is_Rational: result = ex.q*x - ex.p else: inverted = simpler_inverse(ex) if inverted: ex = ex**-1 res = None if ex.is_Pow and (1/ex.exp).is_Integer: n = 1/ex.exp res = _minimal_polynomial_sq(ex.base, n, x) elif _is_sum_surds(ex): res = _minimal_polynomial_sq(ex, S.One, x) if res is not None: result = res if res is None: bus = bottom_up_scan(ex) F = [x - bus] + list(mapping.values()) G = groebner(F, list(symbols.values()) + [x], order='lex') _, factors = factor_list(G[-1]) # by construction G[-1] has root `ex` result = _choose_factor(factors, x, ex) if inverted: result = _invertx(result, x) if result.coeff(x**degree(result, x)) < 0: result = expand_mul(-result) return result minpoly = minimal_polynomial def _switch_domain(g, K): # An algebraic relation f(a, b) = 0 over Q can also be written # g(b) = 0 where g is in Q(a)[x] and h(a) = 0 where h is in Q(b)[x]. # This function transforms g into h where Q(b) = K. frep = g.rep.inject() hrep = frep.eject(K, front=True) return g.new(hrep, g.gens[0]) def _linsolve(p): # Compute root of linear polynomial. c, d = p.rep.rep return -d/c @public def primitive_element(extension, x=None, *, ex=False, polys=False): """Construct a common number field for all extensions. """ if not extension: raise ValueError("can't compute primitive element for empty extension") if x is not None: x, cls = sympify(x), Poly else: x, cls = Dummy('x'), PurePoly if not ex: gen, coeffs = extension[0], [1] g = minimal_polynomial(gen, x, polys=True) for ext in extension[1:]: _, factors = factor_list(g, extension=ext) g = _choose_factor(factors, x, gen) s, _, g = g.sqf_norm() gen += s*ext coeffs.append(s) if not polys: return g.as_expr(), coeffs else: return cls(g), coeffs gen, coeffs = extension[0], [1] f = minimal_polynomial(gen, x, polys=True) K = QQ.algebraic_field((f, gen)) # incrementally constructed field reps = [K.unit] # representations of extension elements in K for ext in extension[1:]: p = minimal_polynomial(ext, x, polys=True) L = QQ.algebraic_field((p, ext)) _, factors = factor_list(f, domain=L) f = _choose_factor(factors, x, gen) s, g, f = f.sqf_norm() gen += s*ext coeffs.append(s) K = QQ.algebraic_field((f, gen)) h = _switch_domain(g, K) erep = _linsolve(h.gcd(p)) # ext as element of K ogen = K.unit - s*erep # old gen as element of K reps = [dup_eval(_.rep, ogen, K) for _ in reps] + [erep] H = [_.rep for _ in reps] if not polys: return f.as_expr(), coeffs, H else: return f, coeffs, H def is_isomorphism_possible(a, b): """Returns `True` if there is a chance for isomorphism. """ n = a.minpoly.degree() m = b.minpoly.degree() if m % n != 0: return False if n == m: return True da = a.minpoly.discriminant() db = b.minpoly.discriminant() i, k, half = 1, m//n, db//2 while True: p = sieve[i] P = p**k if P > half: break if ((da % p) % 2) and not (db % P): return False i += 1 return True def field_isomorphism_pslq(a, b): """Construct field isomorphism using PSLQ algorithm. """ if not a.root.is_real or not b.root.is_real: raise NotImplementedError("PSLQ doesn't support complex coefficients") f = a.minpoly g = b.minpoly.replace(f.gen) n, m, prev = 100, b.minpoly.degree(), None for i in range(1, 5): A = a.root.evalf(n) B = b.root.evalf(n) basis = [1, B] + [ B**i for i in range(2, m) ] + [A] dps, mp.dps = mp.dps, n coeffs = pslq(basis, maxcoeff=int(1e10), maxsteps=1000) mp.dps = dps if coeffs is None: break if coeffs != prev: prev = coeffs else: break coeffs = [S(c)/coeffs[-1] for c in coeffs[:-1]] while not coeffs[-1]: coeffs.pop() coeffs = list(reversed(coeffs)) h = Poly(coeffs, f.gen, domain='QQ') if f.compose(h).rem(g).is_zero: d, approx = len(coeffs) - 1, 0 for i, coeff in enumerate(coeffs): approx += coeff*B**(d - i) if A*approx < 0: return [ -c for c in coeffs ] else: return coeffs elif f.compose(-h).rem(g).is_zero: return [ -c for c in coeffs ] else: n *= 2 return None def field_isomorphism_factor(a, b): """Construct field isomorphism via factorization. """ _, factors = factor_list(a.minpoly, extension=b) for f, _ in factors: if f.degree() == 1: coeffs = f.rep.TC().to_sympy_list() d, terms = len(coeffs) - 1, [] for i, coeff in enumerate(coeffs): terms.append(coeff*b.root**(d - i)) root = Add(*terms) if (a.root - root).evalf(chop=True) == 0: return coeffs if (a.root + root).evalf(chop=True) == 0: return [-c for c in coeffs] return None @public def field_isomorphism(a, b, *, fast=True): """Construct an isomorphism between two number fields. """ a, b = sympify(a), sympify(b) if not a.is_AlgebraicNumber: a = AlgebraicNumber(a) if not b.is_AlgebraicNumber: b = AlgebraicNumber(b) if a == b: return a.coeffs() n = a.minpoly.degree() m = b.minpoly.degree() if n == 1: return [a.root] if m % n != 0: return None if fast: try: result = field_isomorphism_pslq(a, b) if result is not None: return result except NotImplementedError: pass return field_isomorphism_factor(a, b) @public def to_number_field(extension, theta=None, *, gen=None): """Express `extension` in the field generated by `theta`. """ if hasattr(extension, '__iter__'): extension = list(extension) else: extension = [extension] if len(extension) == 1 and type(extension[0]) is tuple: return AlgebraicNumber(extension[0]) minpoly, coeffs = primitive_element(extension, gen, polys=True) root = sum([ coeff*ext for coeff, ext in zip(coeffs, extension) ]) if theta is None: return AlgebraicNumber((minpoly, root)) else: theta = sympify(theta) if not theta.is_AlgebraicNumber: theta = AlgebraicNumber(theta, gen=gen) coeffs = field_isomorphism(root, theta) if coeffs is not None: return AlgebraicNumber(theta, coeffs) else: raise IsomorphismFailed( "%s is not in a subfield of %s" % (root, theta.root)) class IntervalPrinter(MpmathPrinter, LambdaPrinter): """Use ``lambda`` printer but print numbers as ``mpi`` intervals. """ def _print_Integer(self, expr): return "mpi('%s')" % super(PythonCodePrinter, self)._print_Integer(expr) def _print_Rational(self, expr): return "mpi('%s')" % super(PythonCodePrinter, self)._print_Rational(expr) def _print_Half(self, expr): return "mpi('%s')" % super(PythonCodePrinter, self)._print_Rational(expr) def _print_Pow(self, expr): return super(MpmathPrinter, self)._print_Pow(expr, rational=True) @public def isolate(alg, eps=None, fast=False): """Give a rational isolating interval for an algebraic number. """ alg = sympify(alg) if alg.is_Rational: return (alg, alg) elif not alg.is_real: raise NotImplementedError( "complex algebraic numbers are not supported") func = lambdify((), alg, modules="mpmath", printer=IntervalPrinter()) poly = minpoly(alg, polys=True) intervals = poly.intervals(sqf=True) dps, done = mp.dps, False try: while not done: alg = func() for a, b in intervals: if a <= alg.a and alg.b <= b: done = True break else: mp.dps *= 2 finally: mp.dps = dps if eps is not None: a, b = poly.refine_root(a, b, eps=eps, fast=fast) return (a, b) sympy-sympy-1.9/sympy/polys/orderings.py000066400000000000000000000205031412543434000206200ustar00rootroot00000000000000"""Definitions of monomial orderings. """ from typing import Optional __all__ = ["lex", "grlex", "grevlex", "ilex", "igrlex", "igrevlex"] from sympy.core import Symbol from sympy.core.compatibility import iterable class MonomialOrder: """Base class for monomial orderings. """ alias = None # type: Optional[str] is_global = None # type: Optional[bool] is_default = False def __repr__(self): return self.__class__.__name__ + "()" def __str__(self): return self.alias def __call__(self, monomial): raise NotImplementedError def __eq__(self, other): return self.__class__ == other.__class__ def __hash__(self): return hash(self.__class__) def __ne__(self, other): return not (self == other) class LexOrder(MonomialOrder): """Lexicographic order of monomials. """ alias = 'lex' is_global = True is_default = True def __call__(self, monomial): return monomial class GradedLexOrder(MonomialOrder): """Graded lexicographic order of monomials. """ alias = 'grlex' is_global = True def __call__(self, monomial): return (sum(monomial), monomial) class ReversedGradedLexOrder(MonomialOrder): """Reversed graded lexicographic order of monomials. """ alias = 'grevlex' is_global = True def __call__(self, monomial): return (sum(monomial), tuple(reversed([-m for m in monomial]))) class ProductOrder(MonomialOrder): """ A product order built from other monomial orders. Given (not necessarily total) orders O1, O2, ..., On, their product order P is defined as M1 > M2 iff there exists i such that O1(M1) = O2(M2), ..., Oi(M1) = Oi(M2), O{i+1}(M1) > O{i+1}(M2). Product orders are typically built from monomial orders on different sets of variables. ProductOrder is constructed by passing a list of pairs [(O1, L1), (O2, L2), ...] where Oi are MonomialOrders and Li are callables. Upon comparison, the Li are passed the total monomial, and should filter out the part of the monomial to pass to Oi. Examples ======== We can use a lexicographic order on x_1, x_2 and also on y_1, y_2, y_3, and their product on {x_i, y_i} as follows: >>> from sympy.polys.orderings import lex, grlex, ProductOrder >>> P = ProductOrder( ... (lex, lambda m: m[:2]), # lex order on x_1 and x_2 of monomial ... (grlex, lambda m: m[2:]) # grlex on y_1, y_2, y_3 ... ) >>> P((2, 1, 1, 0, 0)) > P((1, 10, 0, 2, 0)) True Here the exponent `2` of `x_1` in the first monomial (`x_1^2 x_2 y_1`) is bigger than the exponent `1` of `x_1` in the second monomial (`x_1 x_2^10 y_2^2`), so the first monomial is greater in the product ordering. >>> P((2, 1, 1, 0, 0)) < P((2, 1, 0, 2, 0)) True Here the exponents of `x_1` and `x_2` agree, so the grlex order on `y_1, y_2, y_3` is used to decide the ordering. In this case the monomial `y_2^2` is ordered larger than `y_1`, since for the grlex order the degree of the monomial is most important. """ def __init__(self, *args): self.args = args def __call__(self, monomial): return tuple(O(lamda(monomial)) for (O, lamda) in self.args) def __repr__(self): contents = [repr(x[0]) for x in self.args] return self.__class__.__name__ + '(' + ", ".join(contents) + ')' def __str__(self): contents = [str(x[0]) for x in self.args] return self.__class__.__name__ + '(' + ", ".join(contents) + ')' def __eq__(self, other): if not isinstance(other, ProductOrder): return False return self.args == other.args def __hash__(self): return hash((self.__class__, self.args)) @property def is_global(self): if all(o.is_global is True for o, _ in self.args): return True if all(o.is_global is False for o, _ in self.args): return False return None class InverseOrder(MonomialOrder): """ The "inverse" of another monomial order. If O is any monomial order, we can construct another monomial order iO such that `A >_{iO} B` if and only if `B >_O A`. This is useful for constructing local orders. Note that many algorithms only work with *global* orders. For example, in the inverse lexicographic order on a single variable `x`, high powers of `x` count as small: >>> from sympy.polys.orderings import lex, InverseOrder >>> ilex = InverseOrder(lex) >>> ilex((5,)) < ilex((0,)) True """ def __init__(self, O): self.O = O def __str__(self): return "i" + str(self.O) def __call__(self, monomial): def inv(l): if iterable(l): return tuple(inv(x) for x in l) return -l return inv(self.O(monomial)) @property def is_global(self): if self.O.is_global is True: return False if self.O.is_global is False: return True return None def __eq__(self, other): return isinstance(other, InverseOrder) and other.O == self.O def __hash__(self): return hash((self.__class__, self.O)) lex = LexOrder() grlex = GradedLexOrder() grevlex = ReversedGradedLexOrder() ilex = InverseOrder(lex) igrlex = InverseOrder(grlex) igrevlex = InverseOrder(grevlex) _monomial_key = { 'lex': lex, 'grlex': grlex, 'grevlex': grevlex, 'ilex': ilex, 'igrlex': igrlex, 'igrevlex': igrevlex } def monomial_key(order=None, gens=None): """ Return a function defining admissible order on monomials. The result of a call to :func:`monomial_key` is a function which should be used as a key to :func:`sorted` built-in function, to provide order in a set of monomials of the same length. Currently supported monomial orderings are: 1. lex - lexicographic order (default) 2. grlex - graded lexicographic order 3. grevlex - reversed graded lexicographic order 4. ilex, igrlex, igrevlex - the corresponding inverse orders If the ``order`` input argument is not a string but has ``__call__`` attribute, then it will pass through with an assumption that the callable object defines an admissible order on monomials. If the ``gens`` input argument contains a list of generators, the resulting key function can be used to sort SymPy ``Expr`` objects. """ if order is None: order = lex if isinstance(order, Symbol): order = str(order) if isinstance(order, str): try: order = _monomial_key[order] except KeyError: raise ValueError("supported monomial orderings are 'lex', 'grlex' and 'grevlex', got %r" % order) if hasattr(order, '__call__'): if gens is not None: def _order(expr): return order(expr.as_poly(*gens).degree_list()) return _order return order else: raise ValueError("monomial ordering specification must be a string or a callable, got %s" % order) class _ItemGetter: """Helper class to return a subsequence of values.""" def __init__(self, seq): self.seq = tuple(seq) def __call__(self, m): return tuple(m[idx] for idx in self.seq) def __eq__(self, other): if not isinstance(other, _ItemGetter): return False return self.seq == other.seq def build_product_order(arg, gens): """ Build a monomial order on ``gens``. ``arg`` should be a tuple of iterables. The first element of each iterable should be a string or monomial order (will be passed to monomial_key), the others should be subsets of the generators. This function will build the corresponding product order. For example, build a product of two grlex orders: >>> from sympy.polys.orderings import build_product_order >>> from sympy.abc import x, y, z, t >>> O = build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) >>> O((1, 2, 3, 4)) ((3, (1, 2)), (7, (3, 4))) """ gens2idx = {} for i, g in enumerate(gens): gens2idx[g] = i order = [] for expr in arg: name = expr[0] var = expr[1:] def makelambda(var): return _ItemGetter(gens2idx[g] for g in var) order.append((monomial_key(name), makelambda(var))) return ProductOrder(*order) sympy-sympy-1.9/sympy/polys/orthopolys.py000066400000000000000000000235601412543434000210540ustar00rootroot00000000000000"""Efficient functions for generating orthogonal polynomials. """ from sympy import Dummy from sympy.polys.constructor import construct_domain from sympy.polys.densearith import ( dup_mul, dup_mul_ground, dup_lshift, dup_sub, dup_add ) from sympy.polys.domains import ZZ, QQ from sympy.polys.polyclasses import DMP from sympy.polys.polytools import Poly, PurePoly from sympy.utilities import public def dup_jacobi(n, a, b, K): """Low-level implementation of Jacobi polynomials. """ seq = [[K.one], [(a + b + K(2))/K(2), (a - b)/K(2)]] for i in range(2, n + 1): den = K(i)*(a + b + i)*(a + b + K(2)*i - K(2)) f0 = (a + b + K(2)*i - K.one) * (a*a - b*b) / (K(2)*den) f1 = (a + b + K(2)*i - K.one) * (a + b + K(2)*i - K(2)) * (a + b + K(2)*i) / (K(2)*den) f2 = (a + i - K.one)*(b + i - K.one)*(a + b + K(2)*i) / den p0 = dup_mul_ground(seq[-1], f0, K) p1 = dup_mul_ground(dup_lshift(seq[-1], 1, K), f1, K) p2 = dup_mul_ground(seq[-2], f2, K) seq.append(dup_sub(dup_add(p0, p1, K), p2, K)) return seq[n] @public def jacobi_poly(n, a, b, x=None, polys=False): """Generates Jacobi polynomial of degree `n` in `x`. Parameters ========== n : int `n` decides the degree of polynomial a Lower limit of minimal domain for the list of coefficients. b Upper limit of minimal domain for the list of coefficients. x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n < 0: raise ValueError("can't generate Jacobi polynomial of degree %s" % n) K, v = construct_domain([a, b], field=True) poly = DMP(dup_jacobi(int(n), v[0], v[1], K), K) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() def dup_gegenbauer(n, a, K): """Low-level implementation of Gegenbauer polynomials. """ seq = [[K.one], [K(2)*a, K.zero]] for i in range(2, n + 1): f1 = K(2) * (i + a - K.one) / i f2 = (i + K(2)*a - K(2)) / i p1 = dup_mul_ground(dup_lshift(seq[-1], 1, K), f1, K) p2 = dup_mul_ground(seq[-2], f2, K) seq.append(dup_sub(p1, p2, K)) return seq[n] def gegenbauer_poly(n, a, x=None, polys=False): """Generates Gegenbauer polynomial of degree `n` in `x`. Parameters ========== n : int `n` decides the degree of polynomial x : optional a Decides minimal domain for the list of coefficients. polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n < 0: raise ValueError( "can't generate Gegenbauer polynomial of degree %s" % n) K, a = construct_domain(a, field=True) poly = DMP(dup_gegenbauer(int(n), a, K), K) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() def dup_chebyshevt(n, K): """Low-level implementation of Chebyshev polynomials of the 1st kind. """ seq = [[K.one], [K.one, K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n] @public def chebyshevt_poly(n, x=None, polys=False): """Generates Chebyshev polynomial of the first kind of degree `n` in `x`. Parameters ========== n : int `n` decides the degree of polynomial x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n < 0: raise ValueError( "can't generate 1st kind Chebyshev polynomial of degree %s" % n) poly = DMP(dup_chebyshevt(int(n), ZZ), ZZ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() def dup_chebyshevu(n, K): """Low-level implementation of Chebyshev polynomials of the 2nd kind. """ seq = [[K.one], [K(2), K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n] @public def chebyshevu_poly(n, x=None, polys=False): """Generates Chebyshev polynomial of the second kind of degree `n` in `x`. Parameters ========== n : int `n` decides the degree of polynomial x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n < 0: raise ValueError( "can't generate 2nd kind Chebyshev polynomial of degree %s" % n) poly = DMP(dup_chebyshevu(int(n), ZZ), ZZ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() def dup_hermite(n, K): """Low-level implementation of Hermite polynomials. """ seq = [[K.one], [K(2), K.zero]] for i in range(2, n + 1): a = dup_lshift(seq[-1], 1, K) b = dup_mul_ground(seq[-2], K(i - 1), K) c = dup_mul_ground(dup_sub(a, b, K), K(2), K) seq.append(c) return seq[n] @public def hermite_poly(n, x=None, polys=False): """Generates Hermite polynomial of degree `n` in `x`. Parameters ========== n : int `n` decides the degree of polynomial x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n < 0: raise ValueError("can't generate Hermite polynomial of degree %s" % n) poly = DMP(dup_hermite(int(n), ZZ), ZZ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() def dup_legendre(n, K): """Low-level implementation of Legendre polynomials. """ seq = [[K.one], [K.one, K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2*i - 1, i), K) b = dup_mul_ground(seq[-2], K(i - 1, i), K) seq.append(dup_sub(a, b, K)) return seq[n] @public def legendre_poly(n, x=None, polys=False): """Generates Legendre polynomial of degree `n` in `x`. Parameters ========== n : int `n` decides the degree of polynomial x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n < 0: raise ValueError("can't generate Legendre polynomial of degree %s" % n) poly = DMP(dup_legendre(int(n), QQ), QQ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() def dup_laguerre(n, alpha, K): """Low-level implementation of Laguerre polynomials. """ seq = [[K.zero], [K.one]] for i in range(1, n + 1): a = dup_mul(seq[-1], [-K.one/i, alpha/i + K(2*i - 1)/i], K) b = dup_mul_ground(seq[-2], alpha/i + K(i - 1)/i, K) seq.append(dup_sub(a, b, K)) return seq[-1] @public def laguerre_poly(n, x=None, alpha=None, polys=False): """Generates Laguerre polynomial of degree `n` in `x`. Parameters ========== n : int `n` decides the degree of polynomial x : optional alpha Decides minimal domain for the list of coefficients. polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n < 0: raise ValueError("can't generate Laguerre polynomial of degree %s" % n) if alpha is not None: K, alpha = construct_domain( alpha, field=True) # XXX: ground_field=True else: K, alpha = QQ, QQ(0) poly = DMP(dup_laguerre(int(n), alpha, K), K) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() def dup_spherical_bessel_fn(n, K): """ Low-level implementation of fn(n, x) """ seq = [[K.one], [K.one, K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(2*i - 1), K) seq.append(dup_sub(a, seq[-2], K)) return dup_lshift(seq[n], 1, K) def dup_spherical_bessel_fn_minus(n, K): """ Low-level implementation of fn(-n, x) """ seq = [[K.one, K.zero], [K.zero]] for i in range(2, n + 1): a = dup_mul_ground(dup_lshift(seq[-1], 1, K), K(3 - 2*i), K) seq.append(dup_sub(a, seq[-2], K)) return seq[n] def spherical_bessel_fn(n, x=None, polys=False): """ Coefficients for the spherical Bessel functions. Those are only needed in the jn() function. The coefficients are calculated from: fn(0, z) = 1/z fn(1, z) = 1/z**2 fn(n-1, z) + fn(n+1, z) == (2*n+1)/z * fn(n, z) Parameters ========== n : int `n` decides the degree of polynomial x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. Examples ======== >>> from sympy.polys.orthopolys import spherical_bessel_fn as fn >>> from sympy import Symbol >>> z = Symbol("z") >>> fn(1, z) z**(-2) >>> fn(2, z) -1/z + 3/z**3 >>> fn(3, z) -6/z**2 + 15/z**4 >>> fn(4, z) 1/z - 45/z**3 + 105/z**5 """ if n < 0: dup = dup_spherical_bessel_fn_minus(-int(n), ZZ) else: dup = dup_spherical_bessel_fn(int(n), ZZ) poly = DMP(dup, ZZ) if x is not None: poly = Poly.new(poly, 1/x) else: poly = PurePoly.new(poly, 1/Dummy('x')) return poly if polys else poly.as_expr() sympy-sympy-1.9/sympy/polys/partfrac.py000066400000000000000000000345051412543434000204350ustar00rootroot00000000000000"""Algorithms for partial fraction decomposition of rational functions. """ from sympy.core import S, Add, sympify, Function, Lambda, Dummy from sympy.core.basic import preorder_traversal from sympy.polys import Poly, RootSum, cancel, factor from sympy.polys.polyerrors import PolynomialError from sympy.polys.polyoptions import allowed_flags, set_defaults from sympy.polys.polytools import parallel_poly_from_expr from sympy.utilities import numbered_symbols, take, xthreaded, public @xthreaded @public def apart(f, x=None, full=False, **options): """ Compute partial fraction decomposition of a rational function. Given a rational function ``f``, computes the partial fraction decomposition of ``f``. Two algorithms are available: One is based on the undertermined coefficients method, the other is Bronstein's full partial fraction decomposition algorithm. The undetermined coefficients method (selected by ``full=False``) uses polynomial factorization (and therefore accepts the same options as factor) for the denominator. Per default it works over the rational numbers, therefore decomposition of denominators with non-rational roots (e.g. irrational, complex roots) is not supported by default (see options of factor). Bronstein's algorithm can be selected by using ``full=True`` and allows a decomposition of denominators with non-rational roots. A human-readable result can be obtained via ``doit()`` (see examples below). Examples ======== >>> from sympy.polys.partfrac import apart >>> from sympy.abc import x, y By default, using the undetermined coefficients method: >>> apart(y/(x + 2)/(x + 1), x) -y/(x + 2) + y/(x + 1) The undetermined coefficients method does not provide a result when the denominators roots are not rational: >>> apart(y/(x**2 + x + 1), x) y/(x**2 + x + 1) You can choose Bronstein's algorithm by setting ``full=True``: >>> apart(y/(x**2 + x + 1), x, full=True) RootSum(_w**2 + _w + 1, Lambda(_a, (-2*_a*y/3 - y/3)/(-_a + x))) Calling ``doit()`` yields a human-readable result: >>> apart(y/(x**2 + x + 1), x, full=True).doit() (-y/3 - 2*y*(-1/2 - sqrt(3)*I/2)/3)/(x + 1/2 + sqrt(3)*I/2) + (-y/3 - 2*y*(-1/2 + sqrt(3)*I/2)/3)/(x + 1/2 - sqrt(3)*I/2) See Also ======== apart_list, assemble_partfrac_list """ allowed_flags(options, []) f = sympify(f) if f.is_Atom: return f else: P, Q = f.as_numer_denom() _options = options.copy() options = set_defaults(options, extension=True) try: (P, Q), opt = parallel_poly_from_expr((P, Q), x, **options) except PolynomialError as msg: if f.is_commutative: raise PolynomialError(msg) # non-commutative if f.is_Mul: c, nc = f.args_cnc(split_1=False) nc = f.func(*nc) if c: c = apart(f.func._from_args(c), x=x, full=full, **_options) return c*nc else: return nc elif f.is_Add: c = [] nc = [] for i in f.args: if i.is_commutative: c.append(i) else: try: nc.append(apart(i, x=x, full=full, **_options)) except NotImplementedError: nc.append(i) return apart(f.func(*c), x=x, full=full, **_options) + f.func(*nc) else: reps = [] pot = preorder_traversal(f) next(pot) for e in pot: try: reps.append((e, apart(e, x=x, full=full, **_options))) pot.skip() # this was handled successfully except NotImplementedError: pass return f.xreplace(dict(reps)) if P.is_multivariate: fc = f.cancel() if fc != f: return apart(fc, x=x, full=full, **_options) raise NotImplementedError( "multivariate partial fraction decomposition") common, P, Q = P.cancel(Q) poly, P = P.div(Q, auto=True) P, Q = P.rat_clear_denoms(Q) if Q.degree() <= 1: partial = P/Q else: if not full: partial = apart_undetermined_coeffs(P, Q) else: partial = apart_full_decomposition(P, Q) terms = S.Zero for term in Add.make_args(partial): if term.has(RootSum): terms += term else: terms += factor(term) return common*(poly.as_expr() + terms) def apart_undetermined_coeffs(P, Q): """Partial fractions via method of undetermined coefficients. """ X = numbered_symbols(cls=Dummy) partial, symbols = [], [] _, factors = Q.factor_list() for f, k in factors: n, q = f.degree(), Q for i in range(1, k + 1): coeffs, q = take(X, n), q.quo(f) partial.append((coeffs, q, f, i)) symbols.extend(coeffs) dom = Q.get_domain().inject(*symbols) F = Poly(0, Q.gen, domain=dom) for i, (coeffs, q, f, k) in enumerate(partial): h = Poly(coeffs, Q.gen, domain=dom) partial[i] = (h, f, k) q = q.set_domain(dom) F += h*q system, result = [], S.Zero for (k,), coeff in F.terms(): system.append(coeff - P.nth(k)) from sympy.solvers import solve solution = solve(system, symbols) for h, f, k in partial: h = h.as_expr().subs(solution) result += h/f.as_expr()**k return result def apart_full_decomposition(P, Q): """ Bronstein's full partial fraction decomposition algorithm. Given a univariate rational function ``f``, performing only GCD operations over the algebraic closure of the initial ground domain of definition, compute full partial fraction decomposition with fractions having linear denominators. Note that no factorization of the initial denominator of ``f`` is performed. The final decomposition is formed in terms of a sum of :class:`RootSum` instances. References ========== .. [1] [Bronstein93]_ """ return assemble_partfrac_list(apart_list(P/Q, P.gens[0])) @public def apart_list(f, x=None, dummies=None, **options): """ Compute partial fraction decomposition of a rational function and return the result in structured form. Given a rational function ``f`` compute the partial fraction decomposition of ``f``. Only Bronstein's full partial fraction decomposition algorithm is supported by this method. The return value is highly structured and perfectly suited for further algorithmic treatment rather than being human-readable. The function returns a tuple holding three elements: * The first item is the common coefficient, free of the variable `x` used for decomposition. (It is an element of the base field `K`.) * The second item is the polynomial part of the decomposition. This can be the zero polynomial. (It is an element of `K[x]`.) * The third part itself is a list of quadruples. Each quadruple has the following elements in this order: - The (not necessarily irreducible) polynomial `D` whose roots `w_i` appear in the linear denominator of a bunch of related fraction terms. (This item can also be a list of explicit roots. However, at the moment ``apart_list`` never returns a result this way, but the related ``assemble_partfrac_list`` function accepts this format as input.) - The numerator of the fraction, written as a function of the root `w` - The linear denominator of the fraction *excluding its power exponent*, written as a function of the root `w`. - The power to which the denominator has to be raised. On can always rebuild a plain expression by using the function ``assemble_partfrac_list``. Examples ======== A first example: >>> from sympy.polys.partfrac import apart_list, assemble_partfrac_list >>> from sympy.abc import x, t >>> f = (2*x**3 - 2*x) / (x**2 - 2*x + 1) >>> pfd = apart_list(f) >>> pfd (1, Poly(2*x + 4, x, domain='ZZ'), [(Poly(_w - 1, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1)]) >>> assemble_partfrac_list(pfd) 2*x + 4 + 4/(x - 1) Second example: >>> f = (-2*x - 2*x**2) / (3*x**2 - 6*x) >>> pfd = apart_list(f) >>> pfd (-1, Poly(2/3, x, domain='QQ'), [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 2), Lambda(_a, -_a + x), 1)]) >>> assemble_partfrac_list(pfd) -2/3 - 2/(x - 2) Another example, showing symbolic parameters: >>> pfd = apart_list(t/(x**2 + x + t), x) >>> pfd (1, Poly(0, x, domain='ZZ[t]'), [(Poly(_w**2 + _w + t, _w, domain='ZZ[t]'), Lambda(_a, -2*_a*t/(4*t - 1) - t/(4*t - 1)), Lambda(_a, -_a + x), 1)]) >>> assemble_partfrac_list(pfd) RootSum(_w**2 + _w + t, Lambda(_a, (-2*_a*t/(4*t - 1) - t/(4*t - 1))/(-_a + x))) This example is taken from Bronstein's original paper: >>> f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) >>> pfd = apart_list(f) >>> pfd (1, Poly(0, x, domain='ZZ'), [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), (Poly(_w**2 - 1, _w, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), (Poly(_w + 1, _w, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) >>> assemble_partfrac_list(pfd) -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) See also ======== apart, assemble_partfrac_list References ========== .. [1] [Bronstein93]_ """ allowed_flags(options, []) f = sympify(f) if f.is_Atom: return f else: P, Q = f.as_numer_denom() options = set_defaults(options, extension=True) (P, Q), opt = parallel_poly_from_expr((P, Q), x, **options) if P.is_multivariate: raise NotImplementedError( "multivariate partial fraction decomposition") common, P, Q = P.cancel(Q) poly, P = P.div(Q, auto=True) P, Q = P.rat_clear_denoms(Q) polypart = poly if dummies is None: def dummies(name): d = Dummy(name) while True: yield d dummies = dummies("w") rationalpart = apart_list_full_decomposition(P, Q, dummies) return (common, polypart, rationalpart) def apart_list_full_decomposition(P, Q, dummygen): """ Bronstein's full partial fraction decomposition algorithm. Given a univariate rational function ``f``, performing only GCD operations over the algebraic closure of the initial ground domain of definition, compute full partial fraction decomposition with fractions having linear denominators. Note that no factorization of the initial denominator of ``f`` is performed. The final decomposition is formed in terms of a sum of :class:`RootSum` instances. References ========== .. [1] [Bronstein93]_ """ f, x, U = P/Q, P.gen, [] u = Function('u')(x) a = Dummy('a') partial = [] for d, n in Q.sqf_list_include(all=True): b = d.as_expr() U += [ u.diff(x, n - 1) ] h = cancel(f*b**n) / u**n H, subs = [h], [] for j in range(1, n): H += [ H[-1].diff(x) / j ] for j in range(1, n + 1): subs += [ (U[j - 1], b.diff(x, j) / j) ] for j in range(0, n): P, Q = cancel(H[j]).as_numer_denom() for i in range(0, j + 1): P = P.subs(*subs[j - i]) Q = Q.subs(*subs[0]) P = Poly(P, x) Q = Poly(Q, x) G = P.gcd(d) D = d.quo(G) B, g = Q.half_gcdex(D) b = (P * B.quo(g)).rem(D) Dw = D.subs(x, next(dummygen)) numer = Lambda(a, b.as_expr().subs(x, a)) denom = Lambda(a, (x - a)) exponent = n-j partial.append((Dw, numer, denom, exponent)) return partial @public def assemble_partfrac_list(partial_list): r"""Reassemble a full partial fraction decomposition from a structured result obtained by the function ``apart_list``. Examples ======== This example is taken from Bronstein's original paper: >>> from sympy.polys.partfrac import apart_list, assemble_partfrac_list >>> from sympy.abc import x >>> f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) >>> pfd = apart_list(f) >>> pfd (1, Poly(0, x, domain='ZZ'), [(Poly(_w - 2, _w, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), (Poly(_w**2 - 1, _w, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), (Poly(_w + 1, _w, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) >>> assemble_partfrac_list(pfd) -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) If we happen to know some roots we can provide them easily inside the structure: >>> pfd = apart_list(2/(x**2-2)) >>> pfd (1, Poly(0, x, domain='ZZ'), [(Poly(_w**2 - 2, _w, domain='ZZ'), Lambda(_a, _a/2), Lambda(_a, -_a + x), 1)]) >>> pfda = assemble_partfrac_list(pfd) >>> pfda RootSum(_w**2 - 2, Lambda(_a, _a/(-_a + x)))/2 >>> pfda.doit() -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2))) >>> from sympy import Dummy, Poly, Lambda, sqrt >>> a = Dummy("a") >>> pfd = (1, Poly(0, x, domain='ZZ'), [([sqrt(2),-sqrt(2)], Lambda(a, a/2), Lambda(a, -a + x), 1)]) >>> assemble_partfrac_list(pfd) -sqrt(2)/(2*(x + sqrt(2))) + sqrt(2)/(2*(x - sqrt(2))) See Also ======== apart, apart_list """ # Common factor common = partial_list[0] # Polynomial part polypart = partial_list[1] pfd = polypart.as_expr() # Rational parts for r, nf, df, ex in partial_list[2]: if isinstance(r, Poly): # Assemble in case the roots are given implicitly by a polynomials an, nu = nf.variables, nf.expr ad, de = df.variables, df.expr # Hack to make dummies equal because Lambda created new Dummies de = de.subs(ad[0], an[0]) func = Lambda(tuple(an), nu/de**ex) pfd += RootSum(r, func, auto=False, quadratic=False) else: # Assemble in case the roots are given explicitly by a list of algebraic numbers for root in r: pfd += nf(root)/df(root)**ex return common*pfd sympy-sympy-1.9/sympy/polys/polyclasses.py000066400000000000000000001500641412543434000211730ustar00rootroot00000000000000"""OO layer for several polynomial representations. """ from sympy import oo from sympy.core.sympify import CantSympify from sympy.polys.polyerrors import CoercionFailed, NotReversible, NotInvertible from sympy.polys.polyutils import PicklableWithSlots class GenericPoly(PicklableWithSlots): """Base class for low-level polynomial representations. """ def ground_to_ring(f): """Make the ground domain a ring. """ return f.set_domain(f.dom.get_ring()) def ground_to_field(f): """Make the ground domain a field. """ return f.set_domain(f.dom.get_field()) def ground_to_exact(f): """Make the ground domain exact. """ return f.set_domain(f.dom.get_exact()) @classmethod def _perify_factors(per, result, include): if include: coeff, factors = result factors = [ (per(g), k) for g, k in factors ] if include: return coeff, factors else: return factors from sympy.polys.densebasic import ( dmp_validate, dup_normal, dmp_normal, dup_convert, dmp_convert, dmp_from_sympy, dup_strip, dup_degree, dmp_degree_in, dmp_degree_list, dmp_negative_p, dup_LC, dmp_ground_LC, dup_TC, dmp_ground_TC, dmp_ground_nth, dmp_one, dmp_ground, dmp_zero_p, dmp_one_p, dmp_ground_p, dup_from_dict, dmp_from_dict, dmp_to_dict, dmp_deflate, dmp_inject, dmp_eject, dmp_terms_gcd, dmp_list_terms, dmp_exclude, dmp_slice_in, dmp_permute, dmp_to_tuple,) from sympy.polys.densearith import ( dmp_add_ground, dmp_sub_ground, dmp_mul_ground, dmp_quo_ground, dmp_exquo_ground, dmp_abs, dup_neg, dmp_neg, dup_add, dmp_add, dup_sub, dmp_sub, dup_mul, dmp_mul, dmp_sqr, dup_pow, dmp_pow, dmp_pdiv, dmp_prem, dmp_pquo, dmp_pexquo, dmp_div, dup_rem, dmp_rem, dmp_quo, dmp_exquo, dmp_add_mul, dmp_sub_mul, dmp_max_norm, dmp_l1_norm) from sympy.polys.densetools import ( dmp_clear_denoms, dmp_integrate_in, dmp_diff_in, dmp_eval_in, dup_revert, dmp_ground_trunc, dmp_ground_content, dmp_ground_primitive, dmp_ground_monic, dmp_compose, dup_decompose, dup_shift, dup_transform, dmp_lift) from sympy.polys.euclidtools import ( dup_half_gcdex, dup_gcdex, dup_invert, dmp_subresultants, dmp_resultant, dmp_discriminant, dmp_inner_gcd, dmp_gcd, dmp_lcm, dmp_cancel) from sympy.polys.sqfreetools import ( dup_gff_list, dmp_norm, dmp_sqf_p, dmp_sqf_norm, dmp_sqf_part, dmp_sqf_list, dmp_sqf_list_include) from sympy.polys.factortools import ( dup_cyclotomic_p, dmp_irreducible_p, dmp_factor_list, dmp_factor_list_include) from sympy.polys.rootisolation import ( dup_isolate_real_roots_sqf, dup_isolate_real_roots, dup_isolate_all_roots_sqf, dup_isolate_all_roots, dup_refine_real_root, dup_count_real_roots, dup_count_complex_roots, dup_sturm) from sympy.polys.polyerrors import ( UnificationFailed, PolynomialError) def init_normal_DMP(rep, lev, dom): return DMP(dmp_normal(rep, lev, dom), dom, lev) class DMP(PicklableWithSlots, CantSympify): """Dense Multivariate Polynomials over `K`. """ __slots__ = ('rep', 'lev', 'dom', 'ring') def __init__(self, rep, dom, lev=None, ring=None): if lev is not None: if type(rep) is dict: rep = dmp_from_dict(rep, lev, dom) elif type(rep) is not list: rep = dmp_ground(dom.convert(rep), lev) else: rep, lev = dmp_validate(rep) self.rep = rep self.lev = lev self.dom = dom self.ring = ring def __repr__(f): return "%s(%s, %s, %s)" % (f.__class__.__name__, f.rep, f.dom, f.ring) def __hash__(f): return hash((f.__class__.__name__, f.to_tuple(), f.lev, f.dom, f.ring)) def unify(f, g): """Unify representations of two multivariate polynomials. """ if not isinstance(g, DMP) or f.lev != g.lev: raise UnificationFailed("can't unify %s with %s" % (f, g)) if f.dom == g.dom and f.ring == g.ring: return f.lev, f.dom, f.per, f.rep, g.rep else: lev, dom = f.lev, f.dom.unify(g.dom) ring = f.ring if g.ring is not None: if ring is not None: ring = ring.unify(g.ring) else: ring = g.ring F = dmp_convert(f.rep, lev, f.dom, dom) G = dmp_convert(g.rep, lev, g.dom, dom) def per(rep, dom=dom, lev=lev, kill=False): if kill: if not lev: return rep else: lev -= 1 return DMP(rep, dom, lev, ring) return lev, dom, per, F, G def per(f, rep, dom=None, kill=False, ring=None): """Create a DMP out of the given representation. """ lev = f.lev if kill: if not lev: return rep else: lev -= 1 if dom is None: dom = f.dom if ring is None: ring = f.ring return DMP(rep, dom, lev, ring) @classmethod def zero(cls, lev, dom, ring=None): return DMP(0, dom, lev, ring) @classmethod def one(cls, lev, dom, ring=None): return DMP(1, dom, lev, ring) @classmethod def from_list(cls, rep, lev, dom): """Create an instance of ``cls`` given a list of native coefficients. """ return cls(dmp_convert(rep, lev, None, dom), dom, lev) @classmethod def from_sympy_list(cls, rep, lev, dom): """Create an instance of ``cls`` given a list of SymPy coefficients. """ return cls(dmp_from_sympy(rep, lev, dom), dom, lev) def to_dict(f, zero=False): """Convert ``f`` to a dict representation with native coefficients. """ return dmp_to_dict(f.rep, f.lev, f.dom, zero=zero) def to_sympy_dict(f, zero=False): """Convert ``f`` to a dict representation with SymPy coefficients. """ rep = dmp_to_dict(f.rep, f.lev, f.dom, zero=zero) for k, v in rep.items(): rep[k] = f.dom.to_sympy(v) return rep def to_list(f): """Convert ``f`` to a list representation with native coefficients. """ return f.rep def to_sympy_list(f): """Convert ``f`` to a list representation with SymPy coefficients. """ def sympify_nested_list(rep): out = [] for val in rep: if isinstance(val, list): out.append(sympify_nested_list(val)) else: out.append(f.dom.to_sympy(val)) return out return sympify_nested_list(f.rep) def to_tuple(f): """ Convert ``f`` to a tuple representation with native coefficients. This is needed for hashing. """ return dmp_to_tuple(f.rep, f.lev) @classmethod def from_dict(cls, rep, lev, dom): """Construct and instance of ``cls`` from a ``dict`` representation. """ return cls(dmp_from_dict(rep, lev, dom), dom, lev) @classmethod def from_monoms_coeffs(cls, monoms, coeffs, lev, dom, ring=None): return DMP(dict(list(zip(monoms, coeffs))), dom, lev, ring) def to_ring(f): """Make the ground domain a ring. """ return f.convert(f.dom.get_ring()) def to_field(f): """Make the ground domain a field. """ return f.convert(f.dom.get_field()) def to_exact(f): """Make the ground domain exact. """ return f.convert(f.dom.get_exact()) def convert(f, dom): """Convert the ground domain of ``f``. """ if f.dom == dom: return f else: return DMP(dmp_convert(f.rep, f.lev, f.dom, dom), dom, f.lev) def slice(f, m, n, j=0): """Take a continuous subsequence of terms of ``f``. """ return f.per(dmp_slice_in(f.rep, m, n, j, f.lev, f.dom)) def coeffs(f, order=None): """Returns all non-zero coefficients from ``f`` in lex order. """ return [ c for _, c in dmp_list_terms(f.rep, f.lev, f.dom, order=order) ] def monoms(f, order=None): """Returns all non-zero monomials from ``f`` in lex order. """ return [ m for m, _ in dmp_list_terms(f.rep, f.lev, f.dom, order=order) ] def terms(f, order=None): """Returns all non-zero terms from ``f`` in lex order. """ return dmp_list_terms(f.rep, f.lev, f.dom, order=order) def all_coeffs(f): """Returns all coefficients from ``f``. """ if not f.lev: if not f: return [f.dom.zero] else: return [ c for c in f.rep ] else: raise PolynomialError('multivariate polynomials not supported') def all_monoms(f): """Returns all monomials from ``f``. """ if not f.lev: n = dup_degree(f.rep) if n < 0: return [(0,)] else: return [ (n - i,) for i, c in enumerate(f.rep) ] else: raise PolynomialError('multivariate polynomials not supported') def all_terms(f): """Returns all terms from a ``f``. """ if not f.lev: n = dup_degree(f.rep) if n < 0: return [((0,), f.dom.zero)] else: return [ ((n - i,), c) for i, c in enumerate(f.rep) ] else: raise PolynomialError('multivariate polynomials not supported') def lift(f): """Convert algebraic coefficients to rationals. """ return f.per(dmp_lift(f.rep, f.lev, f.dom), dom=f.dom.dom) def deflate(f): """Reduce degree of `f` by mapping `x_i^m` to `y_i`. """ J, F = dmp_deflate(f.rep, f.lev, f.dom) return J, f.per(F) def inject(f, front=False): """Inject ground domain generators into ``f``. """ F, lev = dmp_inject(f.rep, f.lev, f.dom, front=front) return f.__class__(F, f.dom.dom, lev) def eject(f, dom, front=False): """Eject selected generators into the ground domain. """ F = dmp_eject(f.rep, f.lev, dom, front=front) return f.__class__(F, dom, f.lev - len(dom.symbols)) def exclude(f): r""" Remove useless generators from ``f``. Returns the removed generators and the new excluded ``f``. Examples ======== >>> from sympy.polys.polyclasses import DMP >>> from sympy.polys.domains import ZZ >>> DMP([[[ZZ(1)]], [[ZZ(1)], [ZZ(2)]]], ZZ).exclude() ([2], DMP([[1], [1, 2]], ZZ, None)) """ J, F, u = dmp_exclude(f.rep, f.lev, f.dom) return J, f.__class__(F, f.dom, u) def permute(f, P): r""" Returns a polynomial in `K[x_{P(1)}, ..., x_{P(n)}]`. Examples ======== >>> from sympy.polys.polyclasses import DMP >>> from sympy.polys.domains import ZZ >>> DMP([[[ZZ(2)], [ZZ(1), ZZ(0)]], [[]]], ZZ).permute([1, 0, 2]) DMP([[[2], []], [[1, 0], []]], ZZ, None) >>> DMP([[[ZZ(2)], [ZZ(1), ZZ(0)]], [[]]], ZZ).permute([1, 2, 0]) DMP([[[1], []], [[2, 0], []]], ZZ, None) """ return f.per(dmp_permute(f.rep, P, f.lev, f.dom)) def terms_gcd(f): """Remove GCD of terms from the polynomial ``f``. """ J, F = dmp_terms_gcd(f.rep, f.lev, f.dom) return J, f.per(F) def add_ground(f, c): """Add an element of the ground domain to ``f``. """ return f.per(dmp_add_ground(f.rep, f.dom.convert(c), f.lev, f.dom)) def sub_ground(f, c): """Subtract an element of the ground domain from ``f``. """ return f.per(dmp_sub_ground(f.rep, f.dom.convert(c), f.lev, f.dom)) def mul_ground(f, c): """Multiply ``f`` by a an element of the ground domain. """ return f.per(dmp_mul_ground(f.rep, f.dom.convert(c), f.lev, f.dom)) def quo_ground(f, c): """Quotient of ``f`` by a an element of the ground domain. """ return f.per(dmp_quo_ground(f.rep, f.dom.convert(c), f.lev, f.dom)) def exquo_ground(f, c): """Exact quotient of ``f`` by a an element of the ground domain. """ return f.per(dmp_exquo_ground(f.rep, f.dom.convert(c), f.lev, f.dom)) def abs(f): """Make all coefficients in ``f`` positive. """ return f.per(dmp_abs(f.rep, f.lev, f.dom)) def neg(f): """Negate all coefficients in ``f``. """ return f.per(dmp_neg(f.rep, f.lev, f.dom)) def add(f, g): """Add two multivariate polynomials ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_add(F, G, lev, dom)) def sub(f, g): """Subtract two multivariate polynomials ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_sub(F, G, lev, dom)) def mul(f, g): """Multiply two multivariate polynomials ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_mul(F, G, lev, dom)) def sqr(f): """Square a multivariate polynomial ``f``. """ return f.per(dmp_sqr(f.rep, f.lev, f.dom)) def pow(f, n): """Raise ``f`` to a non-negative power ``n``. """ if isinstance(n, int): return f.per(dmp_pow(f.rep, n, f.lev, f.dom)) else: raise TypeError("``int`` expected, got %s" % type(n)) def pdiv(f, g): """Polynomial pseudo-division of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) q, r = dmp_pdiv(F, G, lev, dom) return per(q), per(r) def prem(f, g): """Polynomial pseudo-remainder of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_prem(F, G, lev, dom)) def pquo(f, g): """Polynomial pseudo-quotient of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_pquo(F, G, lev, dom)) def pexquo(f, g): """Polynomial exact pseudo-quotient of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_pexquo(F, G, lev, dom)) def div(f, g): """Polynomial division with remainder of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) q, r = dmp_div(F, G, lev, dom) return per(q), per(r) def rem(f, g): """Computes polynomial remainder of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_rem(F, G, lev, dom)) def quo(f, g): """Computes polynomial quotient of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_quo(F, G, lev, dom)) def exquo(f, g): """Computes polynomial exact quotient of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) res = per(dmp_exquo(F, G, lev, dom)) if f.ring and res not in f.ring: from sympy.polys.polyerrors import ExactQuotientFailed raise ExactQuotientFailed(f, g, f.ring) return res def degree(f, j=0): """Returns the leading degree of ``f`` in ``x_j``. """ if isinstance(j, int): return dmp_degree_in(f.rep, j, f.lev) else: raise TypeError("``int`` expected, got %s" % type(j)) def degree_list(f): """Returns a list of degrees of ``f``. """ return dmp_degree_list(f.rep, f.lev) def total_degree(f): """Returns the total degree of ``f``. """ return max(sum(m) for m in f.monoms()) def homogenize(f, s): """Return homogeneous polynomial of ``f``""" td = f.total_degree() result = {} new_symbol = (s == len(f.terms()[0][0])) for term in f.terms(): d = sum(term[0]) if d < td: i = td - d else: i = 0 if new_symbol: result[term[0] + (i,)] = term[1] else: l = list(term[0]) l[s] += i result[tuple(l)] = term[1] return DMP(result, f.dom, f.lev + int(new_symbol), f.ring) def homogeneous_order(f): """Returns the homogeneous order of ``f``. """ if f.is_zero: return -oo monoms = f.monoms() tdeg = sum(monoms[0]) for monom in monoms: _tdeg = sum(monom) if _tdeg != tdeg: return None return tdeg def LC(f): """Returns the leading coefficient of ``f``. """ return dmp_ground_LC(f.rep, f.lev, f.dom) def TC(f): """Returns the trailing coefficient of ``f``. """ return dmp_ground_TC(f.rep, f.lev, f.dom) def nth(f, *N): """Returns the ``n``-th coefficient of ``f``. """ if all(isinstance(n, int) for n in N): return dmp_ground_nth(f.rep, N, f.lev, f.dom) else: raise TypeError("a sequence of integers expected") def max_norm(f): """Returns maximum norm of ``f``. """ return dmp_max_norm(f.rep, f.lev, f.dom) def l1_norm(f): """Returns l1 norm of ``f``. """ return dmp_l1_norm(f.rep, f.lev, f.dom) def clear_denoms(f): """Clear denominators, but keep the ground domain. """ coeff, F = dmp_clear_denoms(f.rep, f.lev, f.dom) return coeff, f.per(F) def integrate(f, m=1, j=0): """Computes the ``m``-th order indefinite integral of ``f`` in ``x_j``. """ if not isinstance(m, int): raise TypeError("``int`` expected, got %s" % type(m)) if not isinstance(j, int): raise TypeError("``int`` expected, got %s" % type(j)) return f.per(dmp_integrate_in(f.rep, m, j, f.lev, f.dom)) def diff(f, m=1, j=0): """Computes the ``m``-th order derivative of ``f`` in ``x_j``. """ if not isinstance(m, int): raise TypeError("``int`` expected, got %s" % type(m)) if not isinstance(j, int): raise TypeError("``int`` expected, got %s" % type(j)) return f.per(dmp_diff_in(f.rep, m, j, f.lev, f.dom)) def eval(f, a, j=0): """Evaluates ``f`` at the given point ``a`` in ``x_j``. """ if not isinstance(j, int): raise TypeError("``int`` expected, got %s" % type(j)) return f.per(dmp_eval_in(f.rep, f.dom.convert(a), j, f.lev, f.dom), kill=True) def half_gcdex(f, g): """Half extended Euclidean algorithm, if univariate. """ lev, dom, per, F, G = f.unify(g) if not lev: s, h = dup_half_gcdex(F, G, dom) return per(s), per(h) else: raise ValueError('univariate polynomial expected') def gcdex(f, g): """Extended Euclidean algorithm, if univariate. """ lev, dom, per, F, G = f.unify(g) if not lev: s, t, h = dup_gcdex(F, G, dom) return per(s), per(t), per(h) else: raise ValueError('univariate polynomial expected') def invert(f, g): """Invert ``f`` modulo ``g``, if possible. """ lev, dom, per, F, G = f.unify(g) if not lev: return per(dup_invert(F, G, dom)) else: raise ValueError('univariate polynomial expected') def revert(f, n): """Compute ``f**(-1)`` mod ``x**n``. """ if not f.lev: return f.per(dup_revert(f.rep, n, f.dom)) else: raise ValueError('univariate polynomial expected') def subresultants(f, g): """Computes subresultant PRS sequence of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) R = dmp_subresultants(F, G, lev, dom) return list(map(per, R)) def resultant(f, g, includePRS=False): """Computes resultant of ``f`` and ``g`` via PRS. """ lev, dom, per, F, G = f.unify(g) if includePRS: res, R = dmp_resultant(F, G, lev, dom, includePRS=includePRS) return per(res, kill=True), list(map(per, R)) return per(dmp_resultant(F, G, lev, dom), kill=True) def discriminant(f): """Computes discriminant of ``f``. """ return f.per(dmp_discriminant(f.rep, f.lev, f.dom), kill=True) def cofactors(f, g): """Returns GCD of ``f`` and ``g`` and their cofactors. """ lev, dom, per, F, G = f.unify(g) h, cff, cfg = dmp_inner_gcd(F, G, lev, dom) return per(h), per(cff), per(cfg) def gcd(f, g): """Returns polynomial GCD of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_gcd(F, G, lev, dom)) def lcm(f, g): """Returns polynomial LCM of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_lcm(F, G, lev, dom)) def cancel(f, g, include=True): """Cancel common factors in a rational function ``f/g``. """ lev, dom, per, F, G = f.unify(g) if include: F, G = dmp_cancel(F, G, lev, dom, include=True) else: cF, cG, F, G = dmp_cancel(F, G, lev, dom, include=False) F, G = per(F), per(G) if include: return F, G else: return cF, cG, F, G def trunc(f, p): """Reduce ``f`` modulo a constant ``p``. """ return f.per(dmp_ground_trunc(f.rep, f.dom.convert(p), f.lev, f.dom)) def monic(f): """Divides all coefficients by ``LC(f)``. """ return f.per(dmp_ground_monic(f.rep, f.lev, f.dom)) def content(f): """Returns GCD of polynomial coefficients. """ return dmp_ground_content(f.rep, f.lev, f.dom) def primitive(f): """Returns content and a primitive form of ``f``. """ cont, F = dmp_ground_primitive(f.rep, f.lev, f.dom) return cont, f.per(F) def compose(f, g): """Computes functional composition of ``f`` and ``g``. """ lev, dom, per, F, G = f.unify(g) return per(dmp_compose(F, G, lev, dom)) def decompose(f): """Computes functional decomposition of ``f``. """ if not f.lev: return list(map(f.per, dup_decompose(f.rep, f.dom))) else: raise ValueError('univariate polynomial expected') def shift(f, a): """Efficiently compute Taylor shift ``f(x + a)``. """ if not f.lev: return f.per(dup_shift(f.rep, f.dom.convert(a), f.dom)) else: raise ValueError('univariate polynomial expected') def transform(f, p, q): """Evaluate functional transformation ``q**n * f(p/q)``.""" if f.lev: raise ValueError('univariate polynomial expected') lev, dom, per, P, Q = p.unify(q) lev, dom, per, F, P = f.unify(per(P, dom, lev)) lev, dom, per, F, Q = per(F, dom, lev).unify(per(Q, dom, lev)) if not lev: return per(dup_transform(F, P, Q, dom)) else: raise ValueError('univariate polynomial expected') def sturm(f): """Computes the Sturm sequence of ``f``. """ if not f.lev: return list(map(f.per, dup_sturm(f.rep, f.dom))) else: raise ValueError('univariate polynomial expected') def gff_list(f): """Computes greatest factorial factorization of ``f``. """ if not f.lev: return [ (f.per(g), k) for g, k in dup_gff_list(f.rep, f.dom) ] else: raise ValueError('univariate polynomial expected') def norm(f): """Computes ``Norm(f)``.""" r = dmp_norm(f.rep, f.lev, f.dom) return f.per(r, dom=f.dom.dom) def sqf_norm(f): """Computes square-free norm of ``f``. """ s, g, r = dmp_sqf_norm(f.rep, f.lev, f.dom) return s, f.per(g), f.per(r, dom=f.dom.dom) def sqf_part(f): """Computes square-free part of ``f``. """ return f.per(dmp_sqf_part(f.rep, f.lev, f.dom)) def sqf_list(f, all=False): """Returns a list of square-free factors of ``f``. """ coeff, factors = dmp_sqf_list(f.rep, f.lev, f.dom, all) return coeff, [ (f.per(g), k) for g, k in factors ] def sqf_list_include(f, all=False): """Returns a list of square-free factors of ``f``. """ factors = dmp_sqf_list_include(f.rep, f.lev, f.dom, all) return [ (f.per(g), k) for g, k in factors ] def factor_list(f): """Returns a list of irreducible factors of ``f``. """ coeff, factors = dmp_factor_list(f.rep, f.lev, f.dom) return coeff, [ (f.per(g), k) for g, k in factors ] def factor_list_include(f): """Returns a list of irreducible factors of ``f``. """ factors = dmp_factor_list_include(f.rep, f.lev, f.dom) return [ (f.per(g), k) for g, k in factors ] def intervals(f, all=False, eps=None, inf=None, sup=None, fast=False, sqf=False): """Compute isolating intervals for roots of ``f``. """ if not f.lev: if not all: if not sqf: return dup_isolate_real_roots(f.rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) else: return dup_isolate_real_roots_sqf(f.rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) else: if not sqf: return dup_isolate_all_roots(f.rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) else: return dup_isolate_all_roots_sqf(f.rep, f.dom, eps=eps, inf=inf, sup=sup, fast=fast) else: raise PolynomialError( "can't isolate roots of a multivariate polynomial") def refine_root(f, s, t, eps=None, steps=None, fast=False): """ Refine an isolating interval to the given precision. ``eps`` should be a rational number. """ if not f.lev: return dup_refine_real_root(f.rep, s, t, f.dom, eps=eps, steps=steps, fast=fast) else: raise PolynomialError( "can't refine a root of a multivariate polynomial") def count_real_roots(f, inf=None, sup=None): """Return the number of real roots of ``f`` in ``[inf, sup]``. """ return dup_count_real_roots(f.rep, f.dom, inf=inf, sup=sup) def count_complex_roots(f, inf=None, sup=None): """Return the number of complex roots of ``f`` in ``[inf, sup]``. """ return dup_count_complex_roots(f.rep, f.dom, inf=inf, sup=sup) @property def is_zero(f): """Returns ``True`` if ``f`` is a zero polynomial. """ return dmp_zero_p(f.rep, f.lev) @property def is_one(f): """Returns ``True`` if ``f`` is a unit polynomial. """ return dmp_one_p(f.rep, f.lev, f.dom) @property def is_ground(f): """Returns ``True`` if ``f`` is an element of the ground domain. """ return dmp_ground_p(f.rep, None, f.lev) @property def is_sqf(f): """Returns ``True`` if ``f`` is a square-free polynomial. """ return dmp_sqf_p(f.rep, f.lev, f.dom) @property def is_monic(f): """Returns ``True`` if the leading coefficient of ``f`` is one. """ return f.dom.is_one(dmp_ground_LC(f.rep, f.lev, f.dom)) @property def is_primitive(f): """Returns ``True`` if the GCD of the coefficients of ``f`` is one. """ return f.dom.is_one(dmp_ground_content(f.rep, f.lev, f.dom)) @property def is_linear(f): """Returns ``True`` if ``f`` is linear in all its variables. """ return all(sum(monom) <= 1 for monom in dmp_to_dict(f.rep, f.lev, f.dom).keys()) @property def is_quadratic(f): """Returns ``True`` if ``f`` is quadratic in all its variables. """ return all(sum(monom) <= 2 for monom in dmp_to_dict(f.rep, f.lev, f.dom).keys()) @property def is_monomial(f): """Returns ``True`` if ``f`` is zero or has only one term. """ return len(f.to_dict()) <= 1 @property def is_homogeneous(f): """Returns ``True`` if ``f`` is a homogeneous polynomial. """ return f.homogeneous_order() is not None @property def is_irreducible(f): """Returns ``True`` if ``f`` has no factors over its domain. """ return dmp_irreducible_p(f.rep, f.lev, f.dom) @property def is_cyclotomic(f): """Returns ``True`` if ``f`` is a cyclotomic polynomial. """ if not f.lev: return dup_cyclotomic_p(f.rep, f.dom) else: return False def __abs__(f): return f.abs() def __neg__(f): return f.neg() def __add__(f, g): if not isinstance(g, DMP): try: g = f.per(dmp_ground(f.dom.convert(g), f.lev)) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: g = f.ring.convert(g) except (CoercionFailed, NotImplementedError): return NotImplemented return f.add(g) def __radd__(f, g): return f.__add__(g) def __sub__(f, g): if not isinstance(g, DMP): try: g = f.per(dmp_ground(f.dom.convert(g), f.lev)) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: g = f.ring.convert(g) except (CoercionFailed, NotImplementedError): return NotImplemented return f.sub(g) def __rsub__(f, g): return (-f).__add__(g) def __mul__(f, g): if isinstance(g, DMP): return f.mul(g) else: try: return f.mul_ground(g) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: return f.mul(f.ring.convert(g)) except (CoercionFailed, NotImplementedError): pass return NotImplemented def __truediv__(f, g): if isinstance(g, DMP): return f.exquo(g) else: try: return f.mul_ground(g) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: return f.exquo(f.ring.convert(g)) except (CoercionFailed, NotImplementedError): pass return NotImplemented def __rtruediv__(f, g): if isinstance(g, DMP): return g.exquo(f) elif f.ring is not None: try: return f.ring.convert(g).exquo(f) except (CoercionFailed, NotImplementedError): pass return NotImplemented def __rmul__(f, g): return f.__mul__(g) def __pow__(f, n): return f.pow(n) def __divmod__(f, g): return f.div(g) def __mod__(f, g): return f.rem(g) def __floordiv__(f, g): if isinstance(g, DMP): return f.quo(g) else: try: return f.quo_ground(g) except TypeError: return NotImplemented def __eq__(f, g): try: _, _, _, F, G = f.unify(g) if f.lev == g.lev: return F == G except UnificationFailed: pass return False def __ne__(f, g): return not f == g def eq(f, g, strict=False): if not strict: return f == g else: return f._strict_eq(g) def ne(f, g, strict=False): return not f.eq(g, strict=strict) def _strict_eq(f, g): return isinstance(g, f.__class__) and f.lev == g.lev \ and f.dom == g.dom \ and f.rep == g.rep def __lt__(f, g): _, _, _, F, G = f.unify(g) return F < G def __le__(f, g): _, _, _, F, G = f.unify(g) return F <= G def __gt__(f, g): _, _, _, F, G = f.unify(g) return F > G def __ge__(f, g): _, _, _, F, G = f.unify(g) return F >= G def __bool__(f): return not dmp_zero_p(f.rep, f.lev) def init_normal_DMF(num, den, lev, dom): return DMF(dmp_normal(num, lev, dom), dmp_normal(den, lev, dom), dom, lev) class DMF(PicklableWithSlots, CantSympify): """Dense Multivariate Fractions over `K`. """ __slots__ = ('num', 'den', 'lev', 'dom', 'ring') def __init__(self, rep, dom, lev=None, ring=None): num, den, lev = self._parse(rep, dom, lev) num, den = dmp_cancel(num, den, lev, dom) self.num = num self.den = den self.lev = lev self.dom = dom self.ring = ring @classmethod def new(cls, rep, dom, lev=None, ring=None): num, den, lev = cls._parse(rep, dom, lev) obj = object.__new__(cls) obj.num = num obj.den = den obj.lev = lev obj.dom = dom obj.ring = ring return obj @classmethod def _parse(cls, rep, dom, lev=None): if type(rep) is tuple: num, den = rep if lev is not None: if type(num) is dict: num = dmp_from_dict(num, lev, dom) if type(den) is dict: den = dmp_from_dict(den, lev, dom) else: num, num_lev = dmp_validate(num) den, den_lev = dmp_validate(den) if num_lev == den_lev: lev = num_lev else: raise ValueError('inconsistent number of levels') if dmp_zero_p(den, lev): raise ZeroDivisionError('fraction denominator') if dmp_zero_p(num, lev): den = dmp_one(lev, dom) else: if dmp_negative_p(den, lev, dom): num = dmp_neg(num, lev, dom) den = dmp_neg(den, lev, dom) else: num = rep if lev is not None: if type(num) is dict: num = dmp_from_dict(num, lev, dom) elif type(num) is not list: num = dmp_ground(dom.convert(num), lev) else: num, lev = dmp_validate(num) den = dmp_one(lev, dom) return num, den, lev def __repr__(f): return "%s((%s, %s), %s, %s)" % (f.__class__.__name__, f.num, f.den, f.dom, f.ring) def __hash__(f): return hash((f.__class__.__name__, dmp_to_tuple(f.num, f.lev), dmp_to_tuple(f.den, f.lev), f.lev, f.dom, f.ring)) def poly_unify(f, g): """Unify a multivariate fraction and a polynomial. """ if not isinstance(g, DMP) or f.lev != g.lev: raise UnificationFailed("can't unify %s with %s" % (f, g)) if f.dom == g.dom and f.ring == g.ring: return (f.lev, f.dom, f.per, (f.num, f.den), g.rep) else: lev, dom = f.lev, f.dom.unify(g.dom) ring = f.ring if g.ring is not None: if ring is not None: ring = ring.unify(g.ring) else: ring = g.ring F = (dmp_convert(f.num, lev, f.dom, dom), dmp_convert(f.den, lev, f.dom, dom)) G = dmp_convert(g.rep, lev, g.dom, dom) def per(num, den, cancel=True, kill=False, lev=lev): if kill: if not lev: return num/den else: lev = lev - 1 if cancel: num, den = dmp_cancel(num, den, lev, dom) return f.__class__.new((num, den), dom, lev, ring=ring) return lev, dom, per, F, G def frac_unify(f, g): """Unify representations of two multivariate fractions. """ if not isinstance(g, DMF) or f.lev != g.lev: raise UnificationFailed("can't unify %s with %s" % (f, g)) if f.dom == g.dom and f.ring == g.ring: return (f.lev, f.dom, f.per, (f.num, f.den), (g.num, g.den)) else: lev, dom = f.lev, f.dom.unify(g.dom) ring = f.ring if g.ring is not None: if ring is not None: ring = ring.unify(g.ring) else: ring = g.ring F = (dmp_convert(f.num, lev, f.dom, dom), dmp_convert(f.den, lev, f.dom, dom)) G = (dmp_convert(g.num, lev, g.dom, dom), dmp_convert(g.den, lev, g.dom, dom)) def per(num, den, cancel=True, kill=False, lev=lev): if kill: if not lev: return num/den else: lev = lev - 1 if cancel: num, den = dmp_cancel(num, den, lev, dom) return f.__class__.new((num, den), dom, lev, ring=ring) return lev, dom, per, F, G def per(f, num, den, cancel=True, kill=False, ring=None): """Create a DMF out of the given representation. """ lev, dom = f.lev, f.dom if kill: if not lev: return num/den else: lev -= 1 if cancel: num, den = dmp_cancel(num, den, lev, dom) if ring is None: ring = f.ring return f.__class__.new((num, den), dom, lev, ring=ring) def half_per(f, rep, kill=False): """Create a DMP out of the given representation. """ lev = f.lev if kill: if not lev: return rep else: lev -= 1 return DMP(rep, f.dom, lev) @classmethod def zero(cls, lev, dom, ring=None): return cls.new(0, dom, lev, ring=ring) @classmethod def one(cls, lev, dom, ring=None): return cls.new(1, dom, lev, ring=ring) def numer(f): """Returns the numerator of ``f``. """ return f.half_per(f.num) def denom(f): """Returns the denominator of ``f``. """ return f.half_per(f.den) def cancel(f): """Remove common factors from ``f.num`` and ``f.den``. """ return f.per(f.num, f.den) def neg(f): """Negate all coefficients in ``f``. """ return f.per(dmp_neg(f.num, f.lev, f.dom), f.den, cancel=False) def add(f, g): """Add two multivariate fractions ``f`` and ``g``. """ if isinstance(g, DMP): lev, dom, per, (F_num, F_den), G = f.poly_unify(g) num, den = dmp_add_mul(F_num, F_den, G, lev, dom), F_den else: lev, dom, per, F, G = f.frac_unify(g) (F_num, F_den), (G_num, G_den) = F, G num = dmp_add(dmp_mul(F_num, G_den, lev, dom), dmp_mul(F_den, G_num, lev, dom), lev, dom) den = dmp_mul(F_den, G_den, lev, dom) return per(num, den) def sub(f, g): """Subtract two multivariate fractions ``f`` and ``g``. """ if isinstance(g, DMP): lev, dom, per, (F_num, F_den), G = f.poly_unify(g) num, den = dmp_sub_mul(F_num, F_den, G, lev, dom), F_den else: lev, dom, per, F, G = f.frac_unify(g) (F_num, F_den), (G_num, G_den) = F, G num = dmp_sub(dmp_mul(F_num, G_den, lev, dom), dmp_mul(F_den, G_num, lev, dom), lev, dom) den = dmp_mul(F_den, G_den, lev, dom) return per(num, den) def mul(f, g): """Multiply two multivariate fractions ``f`` and ``g``. """ if isinstance(g, DMP): lev, dom, per, (F_num, F_den), G = f.poly_unify(g) num, den = dmp_mul(F_num, G, lev, dom), F_den else: lev, dom, per, F, G = f.frac_unify(g) (F_num, F_den), (G_num, G_den) = F, G num = dmp_mul(F_num, G_num, lev, dom) den = dmp_mul(F_den, G_den, lev, dom) return per(num, den) def pow(f, n): """Raise ``f`` to a non-negative power ``n``. """ if isinstance(n, int): num, den = f.num, f.den if n < 0: num, den, n = den, num, -n return f.per(dmp_pow(num, n, f.lev, f.dom), dmp_pow(den, n, f.lev, f.dom), cancel=False) else: raise TypeError("``int`` expected, got %s" % type(n)) def quo(f, g): """Computes quotient of fractions ``f`` and ``g``. """ if isinstance(g, DMP): lev, dom, per, (F_num, F_den), G = f.poly_unify(g) num, den = F_num, dmp_mul(F_den, G, lev, dom) else: lev, dom, per, F, G = f.frac_unify(g) (F_num, F_den), (G_num, G_den) = F, G num = dmp_mul(F_num, G_den, lev, dom) den = dmp_mul(F_den, G_num, lev, dom) res = per(num, den) if f.ring is not None and res not in f.ring: from sympy.polys.polyerrors import ExactQuotientFailed raise ExactQuotientFailed(f, g, f.ring) return res exquo = quo def invert(f, check=True): """Computes inverse of a fraction ``f``. """ if check and f.ring is not None and not f.ring.is_unit(f): raise NotReversible(f, f.ring) res = f.per(f.den, f.num, cancel=False) return res @property def is_zero(f): """Returns ``True`` if ``f`` is a zero fraction. """ return dmp_zero_p(f.num, f.lev) @property def is_one(f): """Returns ``True`` if ``f`` is a unit fraction. """ return dmp_one_p(f.num, f.lev, f.dom) and \ dmp_one_p(f.den, f.lev, f.dom) def __neg__(f): return f.neg() def __add__(f, g): if isinstance(g, (DMP, DMF)): return f.add(g) try: return f.add(f.half_per(g)) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: return f.add(f.ring.convert(g)) except (CoercionFailed, NotImplementedError): pass return NotImplemented def __radd__(f, g): return f.__add__(g) def __sub__(f, g): if isinstance(g, (DMP, DMF)): return f.sub(g) try: return f.sub(f.half_per(g)) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: return f.sub(f.ring.convert(g)) except (CoercionFailed, NotImplementedError): pass return NotImplemented def __rsub__(f, g): return (-f).__add__(g) def __mul__(f, g): if isinstance(g, (DMP, DMF)): return f.mul(g) try: return f.mul(f.half_per(g)) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: return f.mul(f.ring.convert(g)) except (CoercionFailed, NotImplementedError): pass return NotImplemented def __rmul__(f, g): return f.__mul__(g) def __pow__(f, n): return f.pow(n) def __truediv__(f, g): if isinstance(g, (DMP, DMF)): return f.quo(g) try: return f.quo(f.half_per(g)) except TypeError: return NotImplemented except (CoercionFailed, NotImplementedError): if f.ring is not None: try: return f.quo(f.ring.convert(g)) except (CoercionFailed, NotImplementedError): pass return NotImplemented def __rtruediv__(self, g): r = self.invert(check=False)*g if self.ring and r not in self.ring: from sympy.polys.polyerrors import ExactQuotientFailed raise ExactQuotientFailed(g, self, self.ring) return r def __eq__(f, g): try: if isinstance(g, DMP): _, _, _, (F_num, F_den), G = f.poly_unify(g) if f.lev == g.lev: return dmp_one_p(F_den, f.lev, f.dom) and F_num == G else: _, _, _, F, G = f.frac_unify(g) if f.lev == g.lev: return F == G except UnificationFailed: pass return False def __ne__(f, g): try: if isinstance(g, DMP): _, _, _, (F_num, F_den), G = f.poly_unify(g) if f.lev == g.lev: return not (dmp_one_p(F_den, f.lev, f.dom) and F_num == G) else: _, _, _, F, G = f.frac_unify(g) if f.lev == g.lev: return F != G except UnificationFailed: pass return True def __lt__(f, g): _, _, _, F, G = f.frac_unify(g) return F < G def __le__(f, g): _, _, _, F, G = f.frac_unify(g) return F <= G def __gt__(f, g): _, _, _, F, G = f.frac_unify(g) return F > G def __ge__(f, g): _, _, _, F, G = f.frac_unify(g) return F >= G def __bool__(f): return not dmp_zero_p(f.num, f.lev) def init_normal_ANP(rep, mod, dom): return ANP(dup_normal(rep, dom), dup_normal(mod, dom), dom) class ANP(PicklableWithSlots, CantSympify): """Dense Algebraic Number Polynomials over a field. """ __slots__ = ('rep', 'mod', 'dom') def __init__(self, rep, mod, dom): if type(rep) is dict: self.rep = dup_from_dict(rep, dom) else: if type(rep) is not list: rep = [dom.convert(rep)] self.rep = dup_strip(rep) if isinstance(mod, DMP): self.mod = mod.rep else: if type(mod) is dict: self.mod = dup_from_dict(mod, dom) else: self.mod = dup_strip(mod) self.dom = dom def __repr__(f): return "%s(%s, %s, %s)" % (f.__class__.__name__, f.rep, f.mod, f.dom) def __hash__(f): return hash((f.__class__.__name__, f.to_tuple(), dmp_to_tuple(f.mod, 0), f.dom)) def unify(f, g): """Unify representations of two algebraic numbers. """ if not isinstance(g, ANP) or f.mod != g.mod: raise UnificationFailed("can't unify %s with %s" % (f, g)) if f.dom == g.dom: return f.dom, f.per, f.rep, g.rep, f.mod else: dom = f.dom.unify(g.dom) F = dup_convert(f.rep, f.dom, dom) G = dup_convert(g.rep, g.dom, dom) if dom != f.dom and dom != g.dom: mod = dup_convert(f.mod, f.dom, dom) else: if dom == f.dom: mod = f.mod else: mod = g.mod per = lambda rep: ANP(rep, mod, dom) return dom, per, F, G, mod def per(f, rep, mod=None, dom=None): return ANP(rep, mod or f.mod, dom or f.dom) @classmethod def zero(cls, mod, dom): return ANP(0, mod, dom) @classmethod def one(cls, mod, dom): return ANP(1, mod, dom) def to_dict(f): """Convert ``f`` to a dict representation with native coefficients. """ return dmp_to_dict(f.rep, 0, f.dom) def to_sympy_dict(f): """Convert ``f`` to a dict representation with SymPy coefficients. """ rep = dmp_to_dict(f.rep, 0, f.dom) for k, v in rep.items(): rep[k] = f.dom.to_sympy(v) return rep def to_list(f): """Convert ``f`` to a list representation with native coefficients. """ return f.rep def to_sympy_list(f): """Convert ``f`` to a list representation with SymPy coefficients. """ return [ f.dom.to_sympy(c) for c in f.rep ] def to_tuple(f): """ Convert ``f`` to a tuple representation with native coefficients. This is needed for hashing. """ return dmp_to_tuple(f.rep, 0) @classmethod def from_list(cls, rep, mod, dom): return ANP(dup_strip(list(map(dom.convert, rep))), mod, dom) def neg(f): return f.per(dup_neg(f.rep, f.dom)) def add(f, g): dom, per, F, G, mod = f.unify(g) return per(dup_add(F, G, dom)) def sub(f, g): dom, per, F, G, mod = f.unify(g) return per(dup_sub(F, G, dom)) def mul(f, g): dom, per, F, G, mod = f.unify(g) return per(dup_rem(dup_mul(F, G, dom), mod, dom)) def pow(f, n): """Raise ``f`` to a non-negative power ``n``. """ if isinstance(n, int): if n < 0: F, n = dup_invert(f.rep, f.mod, f.dom), -n else: F = f.rep return f.per(dup_rem(dup_pow(F, n, f.dom), f.mod, f.dom)) else: raise TypeError("``int`` expected, got %s" % type(n)) def div(f, g): dom, per, F, G, mod = f.unify(g) return (per(dup_rem(dup_mul(F, dup_invert(G, mod, dom), dom), mod, dom)), f.zero(mod, dom)) def rem(f, g): dom, _, _, G, mod = f.unify(g) s, h = dup_half_gcdex(G, mod, dom) if h == [dom.one]: return f.zero(mod, dom) else: raise NotInvertible("zero divisor") def quo(f, g): dom, per, F, G, mod = f.unify(g) return per(dup_rem(dup_mul(F, dup_invert(G, mod, dom), dom), mod, dom)) exquo = quo def LC(f): """Returns the leading coefficient of ``f``. """ return dup_LC(f.rep, f.dom) def TC(f): """Returns the trailing coefficient of ``f``. """ return dup_TC(f.rep, f.dom) @property def is_zero(f): """Returns ``True`` if ``f`` is a zero algebraic number. """ return not f @property def is_one(f): """Returns ``True`` if ``f`` is a unit algebraic number. """ return f.rep == [f.dom.one] @property def is_ground(f): """Returns ``True`` if ``f`` is an element of the ground domain. """ return not f.rep or len(f.rep) == 1 def __pos__(f): return f def __neg__(f): return f.neg() def __add__(f, g): if isinstance(g, ANP): return f.add(g) else: try: return f.add(f.per(g)) except (CoercionFailed, TypeError): return NotImplemented def __radd__(f, g): return f.__add__(g) def __sub__(f, g): if isinstance(g, ANP): return f.sub(g) else: try: return f.sub(f.per(g)) except (CoercionFailed, TypeError): return NotImplemented def __rsub__(f, g): return (-f).__add__(g) def __mul__(f, g): if isinstance(g, ANP): return f.mul(g) else: try: return f.mul(f.per(g)) except (CoercionFailed, TypeError): return NotImplemented def __rmul__(f, g): return f.__mul__(g) def __pow__(f, n): return f.pow(n) def __divmod__(f, g): return f.div(g) def __mod__(f, g): return f.rem(g) def __truediv__(f, g): if isinstance(g, ANP): return f.quo(g) else: try: return f.quo(f.per(g)) except (CoercionFailed, TypeError): return NotImplemented def __eq__(f, g): try: _, _, F, G, _ = f.unify(g) return F == G except UnificationFailed: return False def __ne__(f, g): try: _, _, F, G, _ = f.unify(g) return F != G except UnificationFailed: return True def __lt__(f, g): _, _, F, G, _ = f.unify(g) return F < G def __le__(f, g): _, _, F, G, _ = f.unify(g) return F <= G def __gt__(f, g): _, _, F, G, _ = f.unify(g) return F > G def __ge__(f, g): _, _, F, G, _ = f.unify(g) return F >= G def __bool__(f): return bool(f.rep) sympy-sympy-1.9/sympy/polys/polyconfig.py000066400000000000000000000030761412543434000210030ustar00rootroot00000000000000"""Configuration utilities for polynomial manipulation algorithms. """ from contextlib import contextmanager _default_config = { 'USE_COLLINS_RESULTANT': False, 'USE_SIMPLIFY_GCD': True, 'USE_HEU_GCD': True, 'USE_IRREDUCIBLE_IN_FACTOR': False, 'USE_CYCLOTOMIC_FACTOR': True, 'EEZ_RESTART_IF_NEEDED': True, 'EEZ_NUMBER_OF_CONFIGS': 3, 'EEZ_NUMBER_OF_TRIES': 5, 'EEZ_MODULUS_STEP': 2, 'GF_IRRED_METHOD': 'rabin', 'GF_FACTOR_METHOD': 'zassenhaus', 'GROEBNER': 'buchberger', } _current_config = {} @contextmanager def using(**kwargs): for k, v in kwargs.items(): setup(k, v) yield for k in kwargs.keys(): setup(k) def setup(key, value=None): """Assign a value to (or reset) a configuration item. """ key = key.upper() if value is not None: _current_config[key] = value else: _current_config[key] = _default_config[key] def query(key): """Ask for a value of the given configuration item. """ return _current_config.get(key.upper(), None) def configure(): """Initialized configuration of polys module. """ from os import getenv for key, default in _default_config.items(): value = getenv('SYMPY_' + key) if value is not None: try: _current_config[key] = eval(value) except NameError: _current_config[key] = value else: _current_config[key] = default configure() sympy-sympy-1.9/sympy/polys/polyerrors.py000066400000000000000000000106471412543434000210540ustar00rootroot00000000000000"""Definitions of common exceptions for `polys` module. """ from sympy.utilities import public @public class BasePolynomialError(Exception): """Base class for polynomial related exceptions. """ def new(self, *args): raise NotImplementedError("abstract base class") @public class ExactQuotientFailed(BasePolynomialError): def __init__(self, f, g, dom=None): self.f, self.g, self.dom = f, g, dom def __str__(self): # pragma: no cover from sympy.printing.str import sstr if self.dom is None: return "%s does not divide %s" % (sstr(self.g), sstr(self.f)) else: return "%s does not divide %s in %s" % (sstr(self.g), sstr(self.f), sstr(self.dom)) def new(self, f, g): return self.__class__(f, g, self.dom) @public class PolynomialDivisionFailed(BasePolynomialError): def __init__(self, f, g, domain): self.f = f self.g = g self.domain = domain def __str__(self): if self.domain.is_EX: msg = "You may want to use a different simplification algorithm. Note " \ "that in general it's not possible to guarantee to detect zero " \ "in this domain." elif not self.domain.is_Exact: msg = "Your working precision or tolerance of computations may be set " \ "improperly. Adjust those parameters of the coefficient domain " \ "and try again." else: msg = "Zero detection is guaranteed in this coefficient domain. This " \ "may indicate a bug in SymPy or the domain is user defined and " \ "doesn't implement zero detection properly." return "couldn't reduce degree in a polynomial division algorithm when " \ "dividing %s by %s. This can happen when it's not possible to " \ "detect zero in the coefficient domain. The domain of computation " \ "is %s. %s" % (self.f, self.g, self.domain, msg) @public class OperationNotSupported(BasePolynomialError): def __init__(self, poly, func): self.poly = poly self.func = func def __str__(self): # pragma: no cover return "`%s` operation not supported by %s representation" % (self.func, self.poly.rep.__class__.__name__) @public class HeuristicGCDFailed(BasePolynomialError): pass class ModularGCDFailed(BasePolynomialError): pass @public class HomomorphismFailed(BasePolynomialError): pass @public class IsomorphismFailed(BasePolynomialError): pass @public class ExtraneousFactors(BasePolynomialError): pass @public class EvaluationFailed(BasePolynomialError): pass @public class RefinementFailed(BasePolynomialError): pass @public class CoercionFailed(BasePolynomialError): pass @public class NotInvertible(BasePolynomialError): pass @public class NotReversible(BasePolynomialError): pass @public class NotAlgebraic(BasePolynomialError): pass @public class DomainError(BasePolynomialError): pass @public class PolynomialError(BasePolynomialError): pass @public class UnificationFailed(BasePolynomialError): pass @public class GeneratorsError(BasePolynomialError): pass @public class GeneratorsNeeded(GeneratorsError): pass @public class ComputationFailed(BasePolynomialError): def __init__(self, func, nargs, exc): self.func = func self.nargs = nargs self.exc = exc def __str__(self): return "%s(%s) failed without generators" % (self.func, ', '.join(map(str, self.exc.exprs[:self.nargs]))) @public class UnivariatePolynomialError(PolynomialError): pass @public class MultivariatePolynomialError(PolynomialError): pass @public class PolificationFailed(PolynomialError): def __init__(self, opt, origs, exprs, seq=False): if not seq: self.orig = origs self.expr = exprs self.origs = [origs] self.exprs = [exprs] else: self.origs = origs self.exprs = exprs self.opt = opt self.seq = seq def __str__(self): # pragma: no cover if not self.seq: return "can't construct a polynomial from %s" % str(self.orig) else: return "can't construct polynomials from %s" % ', '.join(map(str, self.origs)) @public class OptionError(BasePolynomialError): pass @public class FlagError(OptionError): pass sympy-sympy-1.9/sympy/polys/polyfuncs.py000066400000000000000000000240221412543434000206460ustar00rootroot00000000000000"""High-level polynomials manipulation functions. """ from sympy.core import S, Basic, Add, Mul, symbols, Dummy from sympy.polys.polyerrors import ( PolificationFailed, ComputationFailed, MultivariatePolynomialError, OptionError) from sympy.polys.polyoptions import allowed_flags from sympy.polys.polytools import ( poly_from_expr, parallel_poly_from_expr, Poly) from sympy.polys.specialpolys import ( symmetric_poly, interpolating_poly) from sympy.utilities import numbered_symbols, take, public @public def symmetrize(F, *gens, **args): """ Rewrite a polynomial in terms of elementary symmetric polynomials. A symmetric polynomial is a multivariate polynomial that remains invariant under any variable permutation, i.e., if ``f = f(x_1, x_2, ..., x_n)``, then ``f = f(x_{i_1}, x_{i_2}, ..., x_{i_n})``, where ``(i_1, i_2, ..., i_n)`` is a permutation of ``(1, 2, ..., n)`` (an element of the group ``S_n``). Returns a tuple of symmetric polynomials ``(f1, f2, ..., fn)`` such that ``f = f1 + f2 + ... + fn``. Examples ======== >>> from sympy.polys.polyfuncs import symmetrize >>> from sympy.abc import x, y >>> symmetrize(x**2 + y**2) (-2*x*y + (x + y)**2, 0) >>> symmetrize(x**2 + y**2, formal=True) (s1**2 - 2*s2, 0, [(s1, x + y), (s2, x*y)]) >>> symmetrize(x**2 - y**2) (-2*x*y + (x + y)**2, -2*y**2) >>> symmetrize(x**2 - y**2, formal=True) (s1**2 - 2*s2, -2*y**2, [(s1, x + y), (s2, x*y)]) """ allowed_flags(args, ['formal', 'symbols']) iterable = True if not hasattr(F, '__iter__'): iterable = False F = [F] try: F, opt = parallel_poly_from_expr(F, *gens, **args) except PolificationFailed as exc: result = [] for expr in exc.exprs: if expr.is_Number: result.append((expr, S.Zero)) else: raise ComputationFailed('symmetrize', len(F), exc) if not iterable: result, = result if not exc.opt.formal: return result else: if iterable: return result, [] else: return result + ([],) polys, symbols = [], opt.symbols gens, dom = opt.gens, opt.domain for i in range(len(gens)): poly = symmetric_poly(i + 1, gens, polys=True) polys.append((next(symbols), poly.set_domain(dom))) indices = list(range(len(gens) - 1)) weights = list(range(len(gens), 0, -1)) result = [] for f in F: symmetric = [] if not f.is_homogeneous: symmetric.append(f.TC()) f -= f.TC().as_poly(f.gens) while f: _height, _monom, _coeff = -1, None, None for i, (monom, coeff) in enumerate(f.terms()): if all(monom[i] >= monom[i + 1] for i in indices): height = max([n*m for n, m in zip(weights, monom)]) if height > _height: _height, _monom, _coeff = height, monom, coeff if _height != -1: monom, coeff = _monom, _coeff else: break exponents = [] for m1, m2 in zip(monom, monom[1:] + (0,)): exponents.append(m1 - m2) term = [s**n for (s, _), n in zip(polys, exponents)] poly = [p**n for (_, p), n in zip(polys, exponents)] symmetric.append(Mul(coeff, *term)) product = poly[0].mul(coeff) for p in poly[1:]: product = product.mul(p) f -= product result.append((Add(*symmetric), f.as_expr())) polys = [(s, p.as_expr()) for s, p in polys] if not opt.formal: for i, (sym, non_sym) in enumerate(result): result[i] = (sym.subs(polys), non_sym) if not iterable: result, = result if not opt.formal: return result else: if iterable: return result, polys else: return result + (polys,) @public def horner(f, *gens, **args): """ Rewrite a polynomial in Horner form. Among other applications, evaluation of a polynomial at a point is optimal when it is applied using the Horner scheme ([1]). Examples ======== >>> from sympy.polys.polyfuncs import horner >>> from sympy.abc import x, y, a, b, c, d, e >>> horner(9*x**4 + 8*x**3 + 7*x**2 + 6*x + 5) x*(x*(x*(9*x + 8) + 7) + 6) + 5 >>> horner(a*x**4 + b*x**3 + c*x**2 + d*x + e) e + x*(d + x*(c + x*(a*x + b))) >>> f = 4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y >>> horner(f, wrt=x) x*(x*y*(4*y + 2) + y*(2*y + 1)) >>> horner(f, wrt=y) y*(x*y*(4*x + 2) + x*(2*x + 1)) References ========== [1] - https://en.wikipedia.org/wiki/Horner_scheme """ allowed_flags(args, []) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: return exc.expr form, gen = S.Zero, F.gen if F.is_univariate: for coeff in F.all_coeffs(): form = form*gen + coeff else: F, gens = Poly(F, gen), gens[1:] for coeff in F.all_coeffs(): form = form*gen + horner(coeff, *gens, **args) return form @public def interpolate(data, x): """ Construct an interpolating polynomial for the data points evaluated at point x (which can be symbolic or numeric). Examples ======== >>> from sympy.polys.polyfuncs import interpolate >>> from sympy.abc import a, b, x A list is interpreted as though it were paired with a range starting from 1: >>> interpolate([1, 4, 9, 16], x) x**2 This can be made explicit by giving a list of coordinates: >>> interpolate([(1, 1), (2, 4), (3, 9)], x) x**2 The (x, y) coordinates can also be given as keys and values of a dictionary (and the points need not be equispaced): >>> interpolate([(-1, 2), (1, 2), (2, 5)], x) x**2 + 1 >>> interpolate({-1: 2, 1: 2, 2: 5}, x) x**2 + 1 If the interpolation is going to be used only once then the value of interest can be passed instead of passing a symbol: >>> interpolate([1, 4, 9], 5) 25 Symbolic coordinates are also supported: >>> [(i,interpolate((a, b), i)) for i in range(1, 4)] [(1, a), (2, b), (3, -a + 2*b)] """ n = len(data) if isinstance(data, dict): if x in data: return S(data[x]) X, Y = list(zip(*data.items())) else: if isinstance(data[0], tuple): X, Y = list(zip(*data)) if x in X: return S(Y[X.index(x)]) else: if x in range(1, n + 1): return S(data[x - 1]) Y = list(data) X = list(range(1, n + 1)) try: return interpolating_poly(n, x, X, Y).expand() except ValueError: d = Dummy() return interpolating_poly(n, d, X, Y).expand().subs(d, x) @public def rational_interpolate(data, degnum, X=symbols('x')): """ Returns a rational interpolation, where the data points are element of any integral domain. The first argument contains the data (as a list of coordinates). The ``degnum`` argument is the degree in the numerator of the rational function. Setting it too high will decrease the maximal degree in the denominator for the same amount of data. Examples ======== >>> from sympy.polys.polyfuncs import rational_interpolate >>> data = [(1, -210), (2, -35), (3, 105), (4, 231), (5, 350), (6, 465)] >>> rational_interpolate(data, 2) (105*x**2 - 525)/(x + 1) Values do not need to be integers: >>> from sympy import sympify >>> x = [1, 2, 3, 4, 5, 6] >>> y = sympify("[-1, 0, 2, 22/5, 7, 68/7]") >>> rational_interpolate(zip(x, y), 2) (3*x**2 - 7*x + 2)/(x + 1) The symbol for the variable can be changed if needed: >>> from sympy import symbols >>> z = symbols('z') >>> rational_interpolate(data, 2, X=z) (105*z**2 - 525)/(z + 1) References ========== .. [1] Algorithm is adapted from: http://axiom-wiki.newsynthesis.org/RationalInterpolation """ from sympy.matrices.dense import ones xdata, ydata = list(zip(*data)) k = len(xdata) - degnum - 1 if k < 0: raise OptionError("Too few values for the required degree.") c = ones(degnum + k + 1, degnum + k + 2) for j in range(max(degnum, k)): for i in range(degnum + k + 1): c[i, j + 1] = c[i, j]*xdata[i] for j in range(k + 1): for i in range(degnum + k + 1): c[i, degnum + k + 1 - j] = -c[i, k - j]*ydata[i] r = c.nullspace()[0] return (sum(r[i] * X**i for i in range(degnum + 1)) / sum(r[i + degnum + 1] * X**i for i in range(k + 1))) @public def viete(f, roots=None, *gens, **args): """ Generate Viete's formulas for ``f``. Examples ======== >>> from sympy.polys.polyfuncs import viete >>> from sympy import symbols >>> x, a, b, c, r1, r2 = symbols('x,a:c,r1:3') >>> viete(a*x**2 + b*x + c, [r1, r2], x) [(r1 + r2, -b/a), (r1*r2, c/a)] """ allowed_flags(args, []) if isinstance(roots, Basic): gens, roots = (roots,) + gens, None try: f, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('viete', 1, exc) if f.is_multivariate: raise MultivariatePolynomialError( "multivariate polynomials are not allowed") n = f.degree() if n < 1: raise ValueError( "can't derive Viete's formulas for a constant polynomial") if roots is None: roots = numbered_symbols('r', start=1) roots = take(roots, n) if n != len(roots): raise ValueError("required %s roots, got %s" % (n, len(roots))) lc, coeffs = f.LC(), f.all_coeffs() result, sign = [], -1 for i, coeff in enumerate(coeffs[1:]): poly = symmetric_poly(i + 1, roots) coeff = sign*(coeff/lc) result.append((poly, coeff)) sign = -sign return result sympy-sympy-1.9/sympy/polys/polymatrix.py000066400000000000000000000230251412543434000210360ustar00rootroot00000000000000from sympy.core.expr import Expr from sympy.core.symbol import Dummy from sympy.core.sympify import _sympify from sympy.polys.polyerrors import CoercionFailed from sympy.polys.polytools import Poly, parallel_poly_from_expr from sympy.polys.domains import QQ from sympy.polys.matrices import DomainMatrix from sympy.polys.matrices.domainscalar import DomainScalar class MutablePolyDenseMatrix: """ A mutable matrix of objects from poly module or to operate with them. Examples ======== >>> from sympy.polys.polymatrix import PolyMatrix >>> from sympy import Symbol, Poly >>> x = Symbol('x') >>> pm1 = PolyMatrix([[Poly(x**2, x), Poly(-x, x)], [Poly(x**3, x), Poly(-1 + x, x)]]) >>> v1 = PolyMatrix([[1, 0], [-1, 0]], x) >>> pm1*v1 PolyMatrix([ [ x**2 + x, 0], [x**3 - x + 1, 0]], ring=QQ[x]) >>> pm1.ring ZZ[x] >>> v1*pm1 PolyMatrix([ [ x**2, -x], [-x**2, x]], ring=QQ[x]) >>> pm2 = PolyMatrix([[Poly(x**2, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(1, x, domain='QQ'), \ Poly(x**3, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(-x**3, x, domain='QQ')]]) >>> v2 = PolyMatrix([1, 0, 0, 0, 0, 0], x) >>> v2.ring QQ[x] >>> pm2*v2 PolyMatrix([[x**2]], ring=QQ[x]) """ def __new__(cls, *args, ring=None): if not args: # PolyMatrix(ring=QQ[x]) if ring is None: raise TypeError("The ring needs to be specified for an empty PolyMatrix") rows, cols, items, gens = 0, 0, [], () elif isinstance(args[0], list): elements, gens = args[0], args[1:] if not elements: # PolyMatrix([]) rows, cols, items = 0, 0, [] elif isinstance(elements[0], (list, tuple)): # PolyMatrix([[1, 2]], x) rows, cols = len(elements), len(elements[0]) items = [e for row in elements for e in row] else: # PolyMatrix([1, 2], x) rows, cols = len(elements), 1 items = elements elif [type(a) for a in args[:3]] == [int, int, list]: # PolyMatrix(2, 2, [1, 2, 3, 4], x) rows, cols, items, gens = args[0], args[1], args[2], args[3:] elif [type(a) for a in args[:3]] == [int, int, type(lambda: 0)]: # PolyMatrix(2, 2, lambda i, j: i+j, x) rows, cols, func, gens = args[0], args[1], args[2], args[3:] items = [func(i, j) for i in range(rows) for j in range(cols)] else: raise TypeError("Invalid arguments") # PolyMatrix([[1]], x, y) vs PolyMatrix([[1]], (x, y)) if len(gens) == 1 and isinstance(gens[0], tuple): gens = gens[0] # gens is now a tuple (x, y) return cls.from_list(rows, cols, items, gens, ring) @classmethod def from_list(cls, rows, cols, items, gens, ring): # items can be Expr, Poly, or a mix of Expr and Poly items = [_sympify(item) for item in items] if items and all(isinstance(item, Poly) for item in items): polys = True else: polys = False # Identify the ring for the polys if ring is not None: # Parse a domain string like 'QQ[x]' if isinstance(ring, str): ring = Poly(0, Dummy(), domain=ring).domain elif polys: p = items[0] for p2 in items[1:]: p, _ = p.unify(p2) ring = p.domain[p.gens] else: items, info = parallel_poly_from_expr(items, gens, field=True) ring = info['domain'][info['gens']] polys = True # Efficiently convert when all elements are Poly if polys: p_ring = Poly(0, ring.symbols, domain=ring.domain) to_ring = ring.ring.from_list convert_poly = lambda p: to_ring(p.unify(p_ring)[0].rep.rep) elements = [convert_poly(p) for p in items] else: convert_expr = ring.from_sympy elements = [convert_expr(e.as_expr()) for e in items] # Convert to domain elements and construct DomainMatrix elements_lol = [[elements[i*cols + j] for j in range(cols)] for i in range(rows)] dm = DomainMatrix(elements_lol, (rows, cols), ring) return cls.from_dm(dm) @classmethod def from_dm(cls, dm): obj = super().__new__(cls) dm = dm.to_sparse() R = dm.domain obj._dm = dm obj.ring = R obj.domain = R.domain obj.gens = R.symbols return obj def to_Matrix(self): return self._dm.to_Matrix() @classmethod def from_Matrix(cls, other, *gens, ring=None): return cls(*other.shape, other.flat(), *gens, ring=ring) def set_gens(self, gens): return self.from_Matrix(self.to_Matrix(), gens) def __repr__(self): if self.rows * self.cols: return 'Poly' + repr(self.to_Matrix())[:-1] + f', ring={self.ring})' else: return f'PolyMatrix({self.rows}, {self.cols}, [], ring={self.ring})' @property def shape(self): return self._dm.shape @property def rows(self): return self.shape[0] @property def cols(self): return self.shape[1] def __len__(self): return self.rows * self.cols def __getitem__(self, key): def to_poly(v): ground = self._dm.domain.domain gens = self._dm.domain.symbols return Poly(v.to_dict(), gens, domain=ground) dm = self._dm if isinstance(key, slice): items = dm.flat()[key] return [to_poly(item) for item in items] elif isinstance(key, int): i, j = divmod(key, self.cols) e = dm[i,j] return to_poly(e.element) i, j = key if isinstance(i, int) and isinstance(j, int): return to_poly(dm[i, j].element) else: return self.from_dm(dm[i, j]) def __eq__(self, other): if not isinstance(self, type(other)): return NotImplemented return self._dm == other._dm def __add__(self, other): if isinstance(other, type(self)): return self.from_dm(self._dm + other._dm) return NotImplemented def __sub__(self, other): if isinstance(other, type(self)): return self.from_dm(self._dm - other._dm) return NotImplemented def __mul__(self, other): if isinstance(other, type(self)): return self.from_dm(self._dm * other._dm) elif isinstance(other, int): other = _sympify(other) if isinstance(other, Expr): Kx = self.ring try: other_ds = DomainScalar(Kx.from_sympy(other), Kx) except (CoercionFailed, ValueError): other_ds = DomainScalar.from_sympy(other) return self.from_dm(self._dm * other_ds) return NotImplemented def __rmul__(self, other): if isinstance(other, int): other = _sympify(other) if isinstance(other, Expr): other_ds = DomainScalar.from_sympy(other) return self.from_dm(other_ds * self._dm) return NotImplemented def __truediv__(self, other): if isinstance(other, Poly): other = other.as_expr() elif isinstance(other, int): other = _sympify(other) if not isinstance(other, Expr): return NotImplemented other = self.domain.from_sympy(other) inverse = self.ring.convert_from(1/other, self.domain) inverse = DomainScalar(inverse, self.ring) dm = self._dm * inverse return self.from_dm(dm) def __neg__(self): return self.from_dm(-self._dm) def transpose(self): return self.from_dm(self._dm.transpose()) def row_join(self, other): dm = DomainMatrix.hstack(self._dm, other._dm) return self.from_dm(dm) def col_join(self, other): dm = DomainMatrix.vstack(self._dm, other._dm) return self.from_dm(dm) def applyfunc(self, func): M = self.to_Matrix().applyfunc(func) return self.from_Matrix(M, self.gens) @classmethod def eye(cls, n, gens): return cls.from_dm(DomainMatrix.eye(n, QQ[gens])) @classmethod def zeros(cls, m, n, gens): return cls.from_dm(DomainMatrix.zeros((m, n), QQ[gens])) def rref(self, simplify='ignore', normalize_last='ignore'): # If this is K[x] then computes RREF in ground field K. if not (self.domain.is_Field and all(p.is_ground for p in self)): raise ValueError("PolyMatrix rref is only for ground field elements") dm = self._dm dm_ground = dm.convert_to(dm.domain.domain) dm_rref, pivots = dm_ground.rref() dm_rref = dm_rref.convert_to(dm.domain) return self.from_dm(dm_rref), pivots def nullspace(self): # If this is K[x] then computes nullspace in ground field K. if not (self.domain.is_Field and all(p.is_ground for p in self)): raise ValueError("PolyMatrix nullspace is only for ground field elements") dm = self._dm K, Kx = self.domain, self.ring dm_null_rows = dm.convert_to(K).nullspace().convert_to(Kx) dm_null = dm_null_rows.transpose() dm_basis = [dm_null[:,i] for i in range(dm_null.shape[1])] return [self.from_dm(dmvec) for dmvec in dm_basis] def rank(self): return self.cols - len(self.nullspace()) MutablePolyMatrix = PolyMatrix = MutablePolyDenseMatrix sympy-sympy-1.9/sympy/polys/polyoptions.py000066400000000000000000000527531412543434000212370ustar00rootroot00000000000000"""Options manager for :class:`~.Poly` and public API functions. """ __all__ = ["Options"] from typing import Dict, Type from typing import List, Optional from sympy.core import Basic, sympify from sympy.polys.polyerrors import GeneratorsError, OptionError, FlagError from sympy.utilities import numbered_symbols, topological_sort, public from sympy.utilities.iterables import has_dups from sympy.core.compatibility import is_sequence import sympy.polys import re class Option: """Base class for all kinds of options. """ option = None # type: Optional[str] is_Flag = False requires = [] # type: List[str] excludes = [] # type: List[str] after = [] # type: List[str] before = [] # type: List[str] @classmethod def default(cls): return None @classmethod def preprocess(cls, option): return None @classmethod def postprocess(cls, options): pass class Flag(Option): """Base class for all kinds of flags. """ is_Flag = True class BooleanOption(Option): """An option that must have a boolean value or equivalent assigned. """ @classmethod def preprocess(cls, value): if value in [True, False]: return bool(value) else: raise OptionError("'%s' must have a boolean value assigned, got %s" % (cls.option, value)) class OptionType(type): """Base type for all options that does registers options. """ def __init__(cls, *args, **kwargs): @property def getter(self): try: return self[cls.option] except KeyError: return cls.default() setattr(Options, cls.option, getter) Options.__options__[cls.option] = cls @public class Options(dict): """ Options manager for polynomial manipulation module. Examples ======== >>> from sympy.polys.polyoptions import Options >>> from sympy.polys.polyoptions import build_options >>> from sympy.abc import x, y, z >>> Options((x, y, z), {'domain': 'ZZ'}) {'auto': False, 'domain': ZZ, 'gens': (x, y, z)} >>> build_options((x, y, z), {'domain': 'ZZ'}) {'auto': False, 'domain': ZZ, 'gens': (x, y, z)} **Options** * Expand --- boolean option * Gens --- option * Wrt --- option * Sort --- option * Order --- option * Field --- boolean option * Greedy --- boolean option * Domain --- option * Split --- boolean option * Gaussian --- boolean option * Extension --- option * Modulus --- option * Symmetric --- boolean option * Strict --- boolean option **Flags** * Auto --- boolean flag * Frac --- boolean flag * Formal --- boolean flag * Polys --- boolean flag * Include --- boolean flag * All --- boolean flag * Gen --- flag * Series --- boolean flag """ __order__ = None __options__ = {} # type: Dict[str, Type[Option]] def __init__(self, gens, args, flags=None, strict=False): dict.__init__(self) if gens and args.get('gens', ()): raise OptionError( "both '*gens' and keyword argument 'gens' supplied") elif gens: args = dict(args) args['gens'] = gens defaults = args.pop('defaults', {}) def preprocess_options(args): for option, value in args.items(): try: cls = self.__options__[option] except KeyError: raise OptionError("'%s' is not a valid option" % option) if issubclass(cls, Flag): if flags is None or option not in flags: if strict: raise OptionError("'%s' flag is not allowed in this context" % option) if value is not None: self[option] = cls.preprocess(value) preprocess_options(args) for key, value in dict(defaults).items(): if key in self: del defaults[key] else: for option in self.keys(): cls = self.__options__[option] if key in cls.excludes: del defaults[key] break preprocess_options(defaults) for option in self.keys(): cls = self.__options__[option] for require_option in cls.requires: if self.get(require_option) is None: raise OptionError("'%s' option is only allowed together with '%s'" % (option, require_option)) for exclude_option in cls.excludes: if self.get(exclude_option) is not None: raise OptionError("'%s' option is not allowed together with '%s'" % (option, exclude_option)) for option in self.__order__: self.__options__[option].postprocess(self) @classmethod def _init_dependencies_order(cls): """Resolve the order of options' processing. """ if cls.__order__ is None: vertices, edges = [], set() for name, option in cls.__options__.items(): vertices.append(name) for _name in option.after: edges.add((_name, name)) for _name in option.before: edges.add((name, _name)) try: cls.__order__ = topological_sort((vertices, list(edges))) except ValueError: raise RuntimeError( "cycle detected in sympy.polys options framework") def clone(self, updates={}): """Clone ``self`` and update specified options. """ obj = dict.__new__(self.__class__) for option, value in self.items(): obj[option] = value for option, value in updates.items(): obj[option] = value return obj def __setattr__(self, attr, value): if attr in self.__options__: self[attr] = value else: super().__setattr__(attr, value) @property def args(self): args = {} for option, value in self.items(): if value is not None and option != 'gens': cls = self.__options__[option] if not issubclass(cls, Flag): args[option] = value return args @property def options(self): options = {} for option, cls in self.__options__.items(): if not issubclass(cls, Flag): options[option] = getattr(self, option) return options @property def flags(self): flags = {} for option, cls in self.__options__.items(): if issubclass(cls, Flag): flags[option] = getattr(self, option) return flags class Expand(BooleanOption, metaclass=OptionType): """``expand`` option to polynomial manipulation functions. """ option = 'expand' requires = [] # type: List[str] excludes = [] # type: List[str] @classmethod def default(cls): return True class Gens(Option, metaclass=OptionType): """``gens`` option to polynomial manipulation functions. """ option = 'gens' requires = [] # type: List[str] excludes = [] # type: List[str] @classmethod def default(cls): return () @classmethod def preprocess(cls, gens): if isinstance(gens, Basic): gens = (gens,) elif len(gens) == 1 and is_sequence(gens[0]): gens = gens[0] if gens == (None,): gens = () elif has_dups(gens): raise GeneratorsError("duplicated generators: %s" % str(gens)) elif any(gen.is_commutative is False for gen in gens): raise GeneratorsError("non-commutative generators: %s" % str(gens)) return tuple(gens) class Wrt(Option, metaclass=OptionType): """``wrt`` option to polynomial manipulation functions. """ option = 'wrt' requires = [] # type: List[str] excludes = [] # type: List[str] _re_split = re.compile(r"\s*,\s*|\s+") @classmethod def preprocess(cls, wrt): if isinstance(wrt, Basic): return [str(wrt)] elif isinstance(wrt, str): wrt = wrt.strip() if wrt.endswith(','): raise OptionError('Bad input: missing parameter.') if not wrt: return [] return [ gen for gen in cls._re_split.split(wrt) ] elif hasattr(wrt, '__getitem__'): return list(map(str, wrt)) else: raise OptionError("invalid argument for 'wrt' option") class Sort(Option, metaclass=OptionType): """``sort`` option to polynomial manipulation functions. """ option = 'sort' requires = [] # type: List[str] excludes = [] # type: List[str] @classmethod def default(cls): return [] @classmethod def preprocess(cls, sort): if isinstance(sort, str): return [ gen.strip() for gen in sort.split('>') ] elif hasattr(sort, '__getitem__'): return list(map(str, sort)) else: raise OptionError("invalid argument for 'sort' option") class Order(Option, metaclass=OptionType): """``order`` option to polynomial manipulation functions. """ option = 'order' requires = [] # type: List[str] excludes = [] # type: List[str] @classmethod def default(cls): return sympy.polys.orderings.lex @classmethod def preprocess(cls, order): return sympy.polys.orderings.monomial_key(order) class Field(BooleanOption, metaclass=OptionType): """``field`` option to polynomial manipulation functions. """ option = 'field' requires = [] # type: List[str] excludes = ['domain', 'split', 'gaussian'] class Greedy(BooleanOption, metaclass=OptionType): """``greedy`` option to polynomial manipulation functions. """ option = 'greedy' requires = [] # type: List[str] excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] class Composite(BooleanOption, metaclass=OptionType): """``composite`` option to polynomial manipulation functions. """ option = 'composite' @classmethod def default(cls): return None requires = [] # type: List[str] excludes = ['domain', 'split', 'gaussian', 'extension', 'modulus', 'symmetric'] class Domain(Option, metaclass=OptionType): """``domain`` option to polynomial manipulation functions. """ option = 'domain' requires = [] # type: List[str] excludes = ['field', 'greedy', 'split', 'gaussian', 'extension'] after = ['gens'] _re_realfield = re.compile(r"^(R|RR)(_(\d+))?$") _re_complexfield = re.compile(r"^(C|CC)(_(\d+))?$") _re_finitefield = re.compile(r"^(FF|GF)\((\d+)\)$") _re_polynomial = re.compile(r"^(Z|ZZ|Q|QQ|ZZ_I|QQ_I|R|RR|C|CC)\[(.+)\]$") _re_fraction = re.compile(r"^(Z|ZZ|Q|QQ)\((.+)\)$") _re_algebraic = re.compile(r"^(Q|QQ)\<(.+)\>$") @classmethod def preprocess(cls, domain): if isinstance(domain, sympy.polys.domains.Domain): return domain elif hasattr(domain, 'to_domain'): return domain.to_domain() elif isinstance(domain, str): if domain in ['Z', 'ZZ']: return sympy.polys.domains.ZZ if domain in ['Q', 'QQ']: return sympy.polys.domains.QQ if domain == 'ZZ_I': return sympy.polys.domains.ZZ_I if domain == 'QQ_I': return sympy.polys.domains.QQ_I if domain == 'EX': return sympy.polys.domains.EX r = cls._re_realfield.match(domain) if r is not None: _, _, prec = r.groups() if prec is None: return sympy.polys.domains.RR else: return sympy.polys.domains.RealField(int(prec)) r = cls._re_complexfield.match(domain) if r is not None: _, _, prec = r.groups() if prec is None: return sympy.polys.domains.CC else: return sympy.polys.domains.ComplexField(int(prec)) r = cls._re_finitefield.match(domain) if r is not None: return sympy.polys.domains.FF(int(r.groups()[1])) r = cls._re_polynomial.match(domain) if r is not None: ground, gens = r.groups() gens = list(map(sympify, gens.split(','))) if ground in ['Z', 'ZZ']: return sympy.polys.domains.ZZ.poly_ring(*gens) elif ground in ['Q', 'QQ']: return sympy.polys.domains.QQ.poly_ring(*gens) elif ground in ['R', 'RR']: return sympy.polys.domains.RR.poly_ring(*gens) elif ground == 'ZZ_I': return sympy.polys.domains.ZZ_I.poly_ring(*gens) elif ground == 'QQ_I': return sympy.polys.domains.QQ_I.poly_ring(*gens) else: return sympy.polys.domains.CC.poly_ring(*gens) r = cls._re_fraction.match(domain) if r is not None: ground, gens = r.groups() gens = list(map(sympify, gens.split(','))) if ground in ['Z', 'ZZ']: return sympy.polys.domains.ZZ.frac_field(*gens) else: return sympy.polys.domains.QQ.frac_field(*gens) r = cls._re_algebraic.match(domain) if r is not None: gens = list(map(sympify, r.groups()[1].split(','))) return sympy.polys.domains.QQ.algebraic_field(*gens) raise OptionError('expected a valid domain specification, got %s' % domain) @classmethod def postprocess(cls, options): if 'gens' in options and 'domain' in options and options['domain'].is_Composite and \ (set(options['domain'].symbols) & set(options['gens'])): raise GeneratorsError( "ground domain and generators interfere together") elif ('gens' not in options or not options['gens']) and \ 'domain' in options and options['domain'] == sympy.polys.domains.EX: raise GeneratorsError("you have to provide generators because EX domain was requested") class Split(BooleanOption, metaclass=OptionType): """``split`` option to polynomial manipulation functions. """ option = 'split' requires = [] # type: List[str] excludes = ['field', 'greedy', 'domain', 'gaussian', 'extension', 'modulus', 'symmetric'] @classmethod def postprocess(cls, options): if 'split' in options: raise NotImplementedError("'split' option is not implemented yet") class Gaussian(BooleanOption, metaclass=OptionType): """``gaussian`` option to polynomial manipulation functions. """ option = 'gaussian' requires = [] # type: List[str] excludes = ['field', 'greedy', 'domain', 'split', 'extension', 'modulus', 'symmetric'] @classmethod def postprocess(cls, options): if 'gaussian' in options and options['gaussian'] is True: options['domain'] = sympy.polys.domains.QQ_I Extension.postprocess(options) class Extension(Option, metaclass=OptionType): """``extension`` option to polynomial manipulation functions. """ option = 'extension' requires = [] # type: List[str] excludes = ['greedy', 'domain', 'split', 'gaussian', 'modulus', 'symmetric'] @classmethod def preprocess(cls, extension): if extension == 1: return bool(extension) elif extension == 0: raise OptionError("'False' is an invalid argument for 'extension'") else: if not hasattr(extension, '__iter__'): extension = {extension} else: if not extension: extension = None else: extension = set(extension) return extension @classmethod def postprocess(cls, options): if 'extension' in options and options['extension'] is not True: options['domain'] = sympy.polys.domains.QQ.algebraic_field( *options['extension']) class Modulus(Option, metaclass=OptionType): """``modulus`` option to polynomial manipulation functions. """ option = 'modulus' requires = [] # type: List[str] excludes = ['greedy', 'split', 'domain', 'gaussian', 'extension'] @classmethod def preprocess(cls, modulus): modulus = sympify(modulus) if modulus.is_Integer and modulus > 0: return int(modulus) else: raise OptionError( "'modulus' must a positive integer, got %s" % modulus) @classmethod def postprocess(cls, options): if 'modulus' in options: modulus = options['modulus'] symmetric = options.get('symmetric', True) options['domain'] = sympy.polys.domains.FF(modulus, symmetric) class Symmetric(BooleanOption, metaclass=OptionType): """``symmetric`` option to polynomial manipulation functions. """ option = 'symmetric' requires = ['modulus'] excludes = ['greedy', 'domain', 'split', 'gaussian', 'extension'] class Strict(BooleanOption, metaclass=OptionType): """``strict`` option to polynomial manipulation functions. """ option = 'strict' @classmethod def default(cls): return True class Auto(BooleanOption, Flag, metaclass=OptionType): """``auto`` flag to polynomial manipulation functions. """ option = 'auto' after = ['field', 'domain', 'extension', 'gaussian'] @classmethod def default(cls): return True @classmethod def postprocess(cls, options): if ('domain' in options or 'field' in options) and 'auto' not in options: options['auto'] = False class Frac(BooleanOption, Flag, metaclass=OptionType): """``auto`` option to polynomial manipulation functions. """ option = 'frac' @classmethod def default(cls): return False class Formal(BooleanOption, Flag, metaclass=OptionType): """``formal`` flag to polynomial manipulation functions. """ option = 'formal' @classmethod def default(cls): return False class Polys(BooleanOption, Flag, metaclass=OptionType): """``polys`` flag to polynomial manipulation functions. """ option = 'polys' class Include(BooleanOption, Flag, metaclass=OptionType): """``include`` flag to polynomial manipulation functions. """ option = 'include' @classmethod def default(cls): return False class All(BooleanOption, Flag, metaclass=OptionType): """``all`` flag to polynomial manipulation functions. """ option = 'all' @classmethod def default(cls): return False class Gen(Flag, metaclass=OptionType): """``gen`` flag to polynomial manipulation functions. """ option = 'gen' @classmethod def default(cls): return 0 @classmethod def preprocess(cls, gen): if isinstance(gen, (Basic, int)): return gen else: raise OptionError("invalid argument for 'gen' option") class Series(BooleanOption, Flag, metaclass=OptionType): """``series`` flag to polynomial manipulation functions. """ option = 'series' @classmethod def default(cls): return False class Symbols(Flag, metaclass=OptionType): """``symbols`` flag to polynomial manipulation functions. """ option = 'symbols' @classmethod def default(cls): return numbered_symbols('s', start=1) @classmethod def preprocess(cls, symbols): if hasattr(symbols, '__iter__'): return iter(symbols) else: raise OptionError("expected an iterator or iterable container, got %s" % symbols) class Method(Flag, metaclass=OptionType): """``method`` flag to polynomial manipulation functions. """ option = 'method' @classmethod def preprocess(cls, method): if isinstance(method, str): return method.lower() else: raise OptionError("expected a string, got %s" % method) def build_options(gens, args=None): """Construct options from keyword arguments or ... options. """ if args is None: gens, args = (), gens if len(args) != 1 or 'opt' not in args or gens: return Options(gens, args) else: return args['opt'] def allowed_flags(args, flags): """ Allow specified flags to be used in the given context. Examples ======== >>> from sympy.polys.polyoptions import allowed_flags >>> from sympy.polys.domains import ZZ >>> allowed_flags({'domain': ZZ}, []) >>> allowed_flags({'domain': ZZ, 'frac': True}, []) Traceback (most recent call last): ... FlagError: 'frac' flag is not allowed in this context >>> allowed_flags({'domain': ZZ, 'frac': True}, ['frac']) """ flags = set(flags) for arg in args.keys(): try: if Options.__options__[arg].is_Flag and not arg in flags: raise FlagError( "'%s' flag is not allowed in this context" % arg) except KeyError: raise OptionError("'%s' is not a valid option" % arg) def set_defaults(options, **defaults): """Update options with default values. """ if 'defaults' not in options: options = dict(options) options['defaults'] = defaults return options Options._init_dependencies_order() sympy-sympy-1.9/sympy/polys/polyquinticconst.py000066400000000000000000002734421412543434000222670ustar00rootroot00000000000000""" Solving solvable quintics - An implementation of DS Dummit's paper Paper : http://www.ams.org/journals/mcom/1991-57-195/S0025-5718-1991-1079014-X/S0025-5718-1991-1079014-X.pdf Mathematica notebook: http://www.emba.uvm.edu/~ddummit/quintics/quintics.nb """ from sympy.core import Symbol from sympy.core.evalf import N from sympy.core.numbers import I, Rational from sympy.functions import sqrt from sympy.polys.polytools import Poly from sympy.utilities import public x = Symbol('x') @public class PolyQuintic: """Special functions for solvable quintics""" def __init__(self, poly): _, _, self.p, self.q, self.r, self.s = poly.all_coeffs() self.zeta1 = Rational(-1, 4) + (sqrt(5)/4) + I*sqrt((sqrt(5)/8) + Rational(5, 8)) self.zeta2 = (-sqrt(5)/4) - Rational(1, 4) + I*sqrt((-sqrt(5)/8) + Rational(5, 8)) self.zeta3 = (-sqrt(5)/4) - Rational(1, 4) - I*sqrt((-sqrt(5)/8) + Rational(5, 8)) self.zeta4 = Rational(-1, 4) + (sqrt(5)/4) - I*sqrt((sqrt(5)/8) + Rational(5, 8)) @property def f20(self): p, q, r, s = self.p, self.q, self.r, self.s f20 = q**8 - 13*p*q**6*r + p**5*q**2*r**2 + 65*p**2*q**4*r**2 - 4*p**6*r**3 - 128*p**3*q**2*r**3 + 17*q**4*r**3 + 48*p**4*r**4 - 16*p*q**2*r**4 - 192*p**2*r**5 + 256*r**6 - 4*p**5*q**3*s - 12*p**2*q**5*s + 18*p**6*q*r*s + 12*p**3*q**3*r*s - 124*q**5*r*s + 196*p**4*q*r**2*s + 590*p*q**3*r**2*s - 160*p**2*q*r**3*s - 1600*q*r**4*s - 27*p**7*s**2 - 150*p**4*q**2*s**2 - 125*p*q**4*s**2 - 99*p**5*r*s**2 - 725*p**2*q**2*r*s**2 + 1200*p**3*r**2*s**2 + 3250*q**2*r**2*s**2 - 2000*p*r**3*s**2 - 1250*p*q*r*s**3 + 3125*p**2*s**4 - 9375*r*s**4-(2*p*q**6 - 19*p**2*q**4*r + 51*p**3*q**2*r**2 - 3*q**4*r**2 - 32*p**4*r**3 - 76*p*q**2*r**3 + 256*p**2*r**4 - 512*r**5 + 31*p**3*q**3*s + 58*q**5*s - 117*p**4*q*r*s - 105*p*q**3*r*s - 260*p**2*q*r**2*s + 2400*q*r**3*s + 108*p**5*s**2 + 325*p**2*q**2*s**2 - 525*p**3*r*s**2 - 2750*q**2*r*s**2 + 500*p*r**2*s**2 - 625*p*q*s**3 + 3125*s**4)*x+(p**2*q**4 - 6*p**3*q**2*r - 8*q**4*r + 9*p**4*r**2 + 76*p*q**2*r**2 - 136*p**2*r**3 + 400*r**4 - 50*p*q**3*s + 90*p**2*q*r*s - 1400*q*r**2*s + 625*q**2*s**2 + 500*p*r*s**2)*x**2-(2*q**4 - 21*p*q**2*r + 40*p**2*r**2 - 160*r**3 + 15*p**2*q*s + 400*q*r*s - 125*p*s**2)*x**3+(2*p*q**2 - 6*p**2*r + 40*r**2 - 50*q*s)*x**4 + 8*r*x**5 + x**6 return Poly(f20, x) @property def b(self): p, q, r, s = self.p, self.q, self.r, self.s b = ( [], [0,0,0,0,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0], [0,0,0,0,0,0],) b[1][5] = 100*p**7*q**7 + 2175*p**4*q**9 + 10500*p*q**11 - 1100*p**8*q**5*r - 27975*p**5*q**7*r - 152950*p**2*q**9*r + 4125*p**9*q**3*r**2 + 128875*p**6*q**5*r**2 + 830525*p**3*q**7*r**2 - 59450*q**9*r**2 - 5400*p**10*q*r**3 - 243800*p**7*q**3*r**3 - 2082650*p**4*q**5*r**3 + 333925*p*q**7*r**3 + 139200*p**8*q*r**4 + 2406000*p**5*q**3*r**4 + 122600*p**2*q**5*r**4 - 1254400*p**6*q*r**5 - 3776000*p**3*q**3*r**5 - 1832000*q**5*r**5 + 4736000*p**4*q*r**6 + 6720000*p*q**3*r**6 - 6400000*p**2*q*r**7 + 900*p**9*q**4*s + 37400*p**6*q**6*s + 281625*p**3*q**8*s + 435000*q**10*s - 6750*p**10*q**2*r*s - 322300*p**7*q**4*r*s - 2718575*p**4*q**6*r*s - 4214250*p*q**8*r*s + 16200*p**11*r**2*s + 859275*p**8*q**2*r**2*s + 8925475*p**5*q**4*r**2*s + 14427875*p**2*q**6*r**2*s - 453600*p**9*r**3*s - 10038400*p**6*q**2*r**3*s - 17397500*p**3*q**4*r**3*s + 11333125*q**6*r**3*s + 4451200*p**7*r**4*s + 15850000*p**4*q**2*r**4*s - 34000000*p*q**4*r**4*s - 17984000*p**5*r**5*s + 10000000*p**2*q**2*r**5*s + 25600000*p**3*r**6*s + 8000000*q**2*r**6*s - 6075*p**11*q*s**2 + 83250*p**8*q**3*s**2 + 1282500*p**5*q**5*s**2 + 2862500*p**2*q**7*s**2 - 724275*p**9*q*r*s**2 - 9807250*p**6*q**3*r*s**2 - 28374375*p**3*q**5*r*s**2 - 22212500*q**7*r*s**2 + 8982000*p**7*q*r**2*s**2 + 39600000*p**4*q**3*r**2*s**2 + 61746875*p*q**5*r**2*s**2 + 1010000*p**5*q*r**3*s**2 + 1000000*p**2*q**3*r**3*s**2 - 78000000*p**3*q*r**4*s**2 - 30000000*q**3*r**4*s**2 - 80000000*p*q*r**5*s**2 + 759375*p**10*s**3 + 9787500*p**7*q**2*s**3 + 39062500*p**4*q**4*s**3 + 52343750*p*q**6*s**3 - 12301875*p**8*r*s**3 - 98175000*p**5*q**2*r*s**3 - 225078125*p**2*q**4*r*s**3 + 54900000*p**6*r**2*s**3 + 310000000*p**3*q**2*r**2*s**3 + 7890625*q**4*r**2*s**3 - 51250000*p**4*r**3*s**3 + 420000000*p*q**2*r**3*s**3 - 110000000*p**2*r**4*s**3 + 200000000*r**5*s**3 - 2109375*p**6*q*s**4 + 21093750*p**3*q**3*s**4 + 89843750*q**5*s**4 - 182343750*p**4*q*r*s**4 - 733203125*p*q**3*r*s**4 + 196875000*p**2*q*r**2*s**4 - 1125000000*q*r**3*s**4 + 158203125*p**5*s**5 + 566406250*p**2*q**2*s**5 - 101562500*p**3*r*s**5 + 1669921875*q**2*r*s**5 - 1250000000*p*r**2*s**5 + 1220703125*p*q*s**6 - 6103515625*s**7 b[1][4] = -1000*p**5*q**7 - 7250*p**2*q**9 + 10800*p**6*q**5*r + 96900*p**3*q**7*r + 52500*q**9*r - 37400*p**7*q**3*r**2 - 470850*p**4*q**5*r**2 - 640600*p*q**7*r**2 + 39600*p**8*q*r**3 + 983600*p**5*q**3*r**3 + 2848100*p**2*q**5*r**3 - 814400*p**6*q*r**4 - 6076000*p**3*q**3*r**4 - 2308000*q**5*r**4 + 5024000*p**4*q*r**5 + 9680000*p*q**3*r**5 - 9600000*p**2*q*r**6 - 13800*p**7*q**4*s - 94650*p**4*q**6*s + 26500*p*q**8*s + 86400*p**8*q**2*r*s + 816500*p**5*q**4*r*s + 257500*p**2*q**6*r*s - 91800*p**9*r**2*s - 1853700*p**6*q**2*r**2*s - 630000*p**3*q**4*r**2*s + 8971250*q**6*r**2*s + 2071200*p**7*r**3*s + 7240000*p**4*q**2*r**3*s - 29375000*p*q**4*r**3*s - 14416000*p**5*r**4*s + 5200000*p**2*q**2*r**4*s + 30400000*p**3*r**5*s + 12000000*q**2*r**5*s - 64800*p**9*q*s**2 - 567000*p**6*q**3*s**2 - 1655000*p**3*q**5*s**2 - 6987500*q**7*s**2 - 337500*p**7*q*r*s**2 - 8462500*p**4*q**3*r*s**2 + 5812500*p*q**5*r*s**2 + 24930000*p**5*q*r**2*s**2 + 69125000*p**2*q**3*r**2*s**2 - 103500000*p**3*q*r**3*s**2 - 30000000*q**3*r**3*s**2 - 90000000*p*q*r**4*s**2 + 708750*p**8*s**3 + 5400000*p**5*q**2*s**3 - 8906250*p**2*q**4*s**3 - 18562500*p**6*r*s**3 + 625000*p**3*q**2*r*s**3 - 29687500*q**4*r*s**3 + 75000000*p**4*r**2*s**3 + 416250000*p*q**2*r**2*s**3 - 60000000*p**2*r**3*s**3 + 300000000*r**4*s**3 - 71718750*p**4*q*s**4 - 189062500*p*q**3*s**4 - 210937500*p**2*q*r*s**4 - 1187500000*q*r**2*s**4 + 187500000*p**3*s**5 + 800781250*q**2*s**5 + 390625000*p*r*s**5 b[1][3] = 500*p**6*q**5 + 6350*p**3*q**7 + 19800*q**9 - 3750*p**7*q**3*r - 65100*p**4*q**5*r - 264950*p*q**7*r + 6750*p**8*q*r**2 + 209050*p**5*q**3*r**2 + 1217250*p**2*q**5*r**2 - 219000*p**6*q*r**3 - 2510000*p**3*q**3*r**3 - 1098500*q**5*r**3 + 2068000*p**4*q*r**4 + 5060000*p*q**3*r**4 - 5200000*p**2*q*r**5 + 6750*p**8*q**2*s + 96350*p**5*q**4*s + 346000*p**2*q**6*s - 20250*p**9*r*s - 459900*p**6*q**2*r*s - 1828750*p**3*q**4*r*s + 2930000*q**6*r*s + 594000*p**7*r**2*s + 4301250*p**4*q**2*r**2*s - 10906250*p*q**4*r**2*s - 5252000*p**5*r**3*s + 1450000*p**2*q**2*r**3*s + 12800000*p**3*r**4*s + 6500000*q**2*r**4*s - 74250*p**7*q*s**2 - 1418750*p**4*q**3*s**2 - 5956250*p*q**5*s**2 + 4297500*p**5*q*r*s**2 + 29906250*p**2*q**3*r*s**2 - 31500000*p**3*q*r**2*s**2 - 12500000*q**3*r**2*s**2 - 35000000*p*q*r**3*s**2 - 1350000*p**6*s**3 - 6093750*p**3*q**2*s**3 - 17500000*q**4*s**3 + 7031250*p**4*r*s**3 + 127812500*p*q**2*r*s**3 - 18750000*p**2*r**2*s**3 + 162500000*r**3*s**3 - 107812500*p**2*q*s**4 - 460937500*q*r*s**4 + 214843750*p*s**5 b[1][2] = -1950*p**4*q**5 - 14100*p*q**7 + 14350*p**5*q**3*r + 125600*p**2*q**5*r - 27900*p**6*q*r**2 - 402250*p**3*q**3*r**2 - 288250*q**5*r**2 + 436000*p**4*q*r**3 + 1345000*p*q**3*r**3 - 1400000*p**2*q*r**4 - 9450*p**6*q**2*s + 1250*p**3*q**4*s + 465000*q**6*s + 49950*p**7*r*s + 302500*p**4*q**2*r*s - 1718750*p*q**4*r*s - 834000*p**5*r**2*s - 437500*p**2*q**2*r**2*s + 3100000*p**3*r**3*s + 1750000*q**2*r**3*s + 292500*p**5*q*s**2 + 1937500*p**2*q**3*s**2 - 3343750*p**3*q*r*s**2 - 1875000*q**3*r*s**2 - 8125000*p*q*r**2*s**2 + 1406250*p**4*s**3 + 12343750*p*q**2*s**3 - 5312500*p**2*r*s**3 + 43750000*r**2*s**3 - 74218750*q*s**4 b[1][1] = 300*p**5*q**3 + 2150*p**2*q**5 - 1350*p**6*q*r - 21500*p**3*q**3*r - 61500*q**5*r + 42000*p**4*q*r**2 + 290000*p*q**3*r**2 - 300000*p**2*q*r**3 + 4050*p**7*s + 45000*p**4*q**2*s + 125000*p*q**4*s - 108000*p**5*r*s - 643750*p**2*q**2*r*s + 700000*p**3*r**2*s + 375000*q**2*r**2*s + 93750*p**3*q*s**2 + 312500*q**3*s**2 - 1875000*p*q*r*s**2 + 1406250*p**2*s**3 + 9375000*r*s**3 b[1][0] = -1250*p**3*q**3 - 9000*q**5 + 4500*p**4*q*r + 46250*p*q**3*r - 50000*p**2*q*r**2 - 6750*p**5*s - 43750*p**2*q**2*s + 75000*p**3*r*s + 62500*q**2*r*s - 156250*p*q*s**2 + 1562500*s**3 b[2][5] = 200*p**6*q**11 - 250*p**3*q**13 - 10800*q**15 - 3900*p**7*q**9*r - 3325*p**4*q**11*r + 181800*p*q**13*r + 26950*p**8*q**7*r**2 + 69625*p**5*q**9*r**2 - 1214450*p**2*q**11*r**2 - 78725*p**9*q**5*r**3 - 368675*p**6*q**7*r**3 + 4166325*p**3*q**9*r**3 + 1131100*q**11*r**3 + 73400*p**10*q**3*r**4 + 661950*p**7*q**5*r**4 - 9151950*p**4*q**7*r**4 - 16633075*p*q**9*r**4 + 36000*p**11*q*r**5 + 135600*p**8*q**3*r**5 + 17321400*p**5*q**5*r**5 + 85338300*p**2*q**7*r**5 - 832000*p**9*q*r**6 - 21379200*p**6*q**3*r**6 - 176044000*p**3*q**5*r**6 - 1410000*q**7*r**6 + 6528000*p**7*q*r**7 + 129664000*p**4*q**3*r**7 + 47344000*p*q**5*r**7 - 21504000*p**5*q*r**8 - 115200000*p**2*q**3*r**8 + 25600000*p**3*q*r**9 + 64000000*q**3*r**9 + 15700*p**8*q**8*s + 120525*p**5*q**10*s + 113250*p**2*q**12*s - 196900*p**9*q**6*r*s - 1776925*p**6*q**8*r*s - 3062475*p**3*q**10*r*s - 4153500*q**12*r*s + 857925*p**10*q**4*r**2*s + 10562775*p**7*q**6*r**2*s + 34866250*p**4*q**8*r**2*s + 73486750*p*q**10*r**2*s - 1333800*p**11*q**2*r**3*s - 29212625*p**8*q**4*r**3*s - 168729675*p**5*q**6*r**3*s - 427230750*p**2*q**8*r**3*s + 108000*p**12*r**4*s + 30384200*p**9*q**2*r**4*s + 324535100*p**6*q**4*r**4*s + 952666750*p**3*q**6*r**4*s - 38076875*q**8*r**4*s - 4296000*p**10*r**5*s - 213606400*p**7*q**2*r**5*s - 842060000*p**4*q**4*r**5*s - 95285000*p*q**6*r**5*s + 61184000*p**8*r**6*s + 567520000*p**5*q**2*r**6*s + 547000000*p**2*q**4*r**6*s - 390912000*p**6*r**7*s - 812800000*p**3*q**2*r**7*s - 924000000*q**4*r**7*s + 1152000000*p**4*r**8*s + 800000000*p*q**2*r**8*s - 1280000000*p**2*r**9*s + 141750*p**10*q**5*s**2 - 31500*p**7*q**7*s**2 - 11325000*p**4*q**9*s**2 - 31687500*p*q**11*s**2 - 1293975*p**11*q**3*r*s**2 - 4803800*p**8*q**5*r*s**2 + 71398250*p**5*q**7*r*s**2 + 227625000*p**2*q**9*r*s**2 + 3256200*p**12*q*r**2*s**2 + 43870125*p**9*q**3*r**2*s**2 + 64581500*p**6*q**5*r**2*s**2 + 56090625*p**3*q**7*r**2*s**2 + 260218750*q**9*r**2*s**2 - 74610000*p**10*q*r**3*s**2 - 662186500*p**7*q**3*r**3*s**2 - 1987747500*p**4*q**5*r**3*s**2 - 811928125*p*q**7*r**3*s**2 + 471286000*p**8*q*r**4*s**2 + 2106040000*p**5*q**3*r**4*s**2 + 792687500*p**2*q**5*r**4*s**2 - 135120000*p**6*q*r**5*s**2 + 2479000000*p**3*q**3*r**5*s**2 + 5242250000*q**5*r**5*s**2 - 6400000000*p**4*q*r**6*s**2 - 8620000000*p*q**3*r**6*s**2 + 13280000000*p**2*q*r**7*s**2 + 1600000000*q*r**8*s**2 + 273375*p**12*q**2*s**3 - 13612500*p**9*q**4*s**3 - 177250000*p**6*q**6*s**3 - 511015625*p**3*q**8*s**3 - 320937500*q**10*s**3 - 2770200*p**13*r*s**3 + 12595500*p**10*q**2*r*s**3 + 543950000*p**7*q**4*r*s**3 + 1612281250*p**4*q**6*r*s**3 + 968125000*p*q**8*r*s**3 + 77031000*p**11*r**2*s**3 + 373218750*p**8*q**2*r**2*s**3 + 1839765625*p**5*q**4*r**2*s**3 + 1818515625*p**2*q**6*r**2*s**3 - 776745000*p**9*r**3*s**3 - 6861075000*p**6*q**2*r**3*s**3 - 20014531250*p**3*q**4*r**3*s**3 - 13747812500*q**6*r**3*s**3 + 3768000000*p**7*r**4*s**3 + 35365000000*p**4*q**2*r**4*s**3 + 34441875000*p*q**4*r**4*s**3 - 9628000000*p**5*r**5*s**3 - 63230000000*p**2*q**2*r**5*s**3 + 13600000000*p**3*r**6*s**3 - 15000000000*q**2*r**6*s**3 - 10400000000*p*r**7*s**3 - 45562500*p**11*q*s**4 - 525937500*p**8*q**3*s**4 - 1364218750*p**5*q**5*s**4 - 1382812500*p**2*q**7*s**4 + 572062500*p**9*q*r*s**4 + 2473515625*p**6*q**3*r*s**4 + 13192187500*p**3*q**5*r*s**4 + 12703125000*q**7*r*s**4 - 451406250*p**7*q*r**2*s**4 - 18153906250*p**4*q**3*r**2*s**4 - 36908203125*p*q**5*r**2*s**4 - 9069375000*p**5*q*r**3*s**4 + 79957812500*p**2*q**3*r**3*s**4 + 5512500000*p**3*q*r**4*s**4 + 50656250000*q**3*r**4*s**4 + 74750000000*p*q*r**5*s**4 + 56953125*p**10*s**5 + 1381640625*p**7*q**2*s**5 - 781250000*p**4*q**4*s**5 + 878906250*p*q**6*s**5 - 2655703125*p**8*r*s**5 - 3223046875*p**5*q**2*r*s**5 - 35117187500*p**2*q**4*r*s**5 + 26573437500*p**6*r**2*s**5 + 14785156250*p**3*q**2*r**2*s**5 - 52050781250*q**4*r**2*s**5 - 103062500000*p**4*r**3*s**5 - 281796875000*p*q**2*r**3*s**5 + 146875000000*p**2*r**4*s**5 - 37500000000*r**5*s**5 - 8789062500*p**6*q*s**6 - 3906250000*p**3*q**3*s**6 + 1464843750*q**5*s**6 + 102929687500*p**4*q*r*s**6 + 297119140625*p*q**3*r*s**6 - 217773437500*p**2*q*r**2*s**6 + 167968750000*q*r**3*s**6 + 10986328125*p**5*s**7 + 98876953125*p**2*q**2*s**7 - 188964843750*p**3*r*s**7 - 278320312500*q**2*r*s**7 + 517578125000*p*r**2*s**7 - 610351562500*p*q*s**8 + 762939453125*s**9 b[2][4] = -200*p**7*q**9 + 1850*p**4*q**11 + 21600*p*q**13 + 3200*p**8*q**7*r - 19200*p**5*q**9*r - 316350*p**2*q**11*r - 19050*p**9*q**5*r**2 + 37400*p**6*q**7*r**2 + 1759250*p**3*q**9*r**2 + 440100*q**11*r**2 + 48750*p**10*q**3*r**3 + 190200*p**7*q**5*r**3 - 4604200*p**4*q**7*r**3 - 6072800*p*q**9*r**3 - 43200*p**11*q*r**4 - 834500*p**8*q**3*r**4 + 4916000*p**5*q**5*r**4 + 27926850*p**2*q**7*r**4 + 969600*p**9*q*r**5 + 2467200*p**6*q**3*r**5 - 45393200*p**3*q**5*r**5 - 5399500*q**7*r**5 - 7283200*p**7*q*r**6 + 10536000*p**4*q**3*r**6 + 41656000*p*q**5*r**6 + 22784000*p**5*q*r**7 - 35200000*p**2*q**3*r**7 - 25600000*p**3*q*r**8 + 96000000*q**3*r**8 - 3000*p**9*q**6*s + 40400*p**6*q**8*s + 136550*p**3*q**10*s - 1647000*q**12*s + 40500*p**10*q**4*r*s - 173600*p**7*q**6*r*s - 126500*p**4*q**8*r*s + 23969250*p*q**10*r*s - 153900*p**11*q**2*r**2*s - 486150*p**8*q**4*r**2*s - 4115800*p**5*q**6*r**2*s - 112653250*p**2*q**8*r**2*s + 129600*p**12*r**3*s + 2683350*p**9*q**2*r**3*s + 10906650*p**6*q**4*r**3*s + 187289500*p**3*q**6*r**3*s + 44098750*q**8*r**3*s - 4384800*p**10*r**4*s - 35660800*p**7*q**2*r**4*s - 175420000*p**4*q**4*r**4*s - 426538750*p*q**6*r**4*s + 60857600*p**8*r**5*s + 349436000*p**5*q**2*r**5*s + 900600000*p**2*q**4*r**5*s - 429568000*p**6*r**6*s - 1511200000*p**3*q**2*r**6*s - 1286000000*q**4*r**6*s + 1472000000*p**4*r**7*s + 1440000000*p*q**2*r**7*s - 1920000000*p**2*r**8*s - 36450*p**11*q**3*s**2 - 188100*p**8*q**5*s**2 - 5504750*p**5*q**7*s**2 - 37968750*p**2*q**9*s**2 + 255150*p**12*q*r*s**2 + 2754000*p**9*q**3*r*s**2 + 49196500*p**6*q**5*r*s**2 + 323587500*p**3*q**7*r*s**2 - 83250000*q**9*r*s**2 - 465750*p**10*q*r**2*s**2 - 31881500*p**7*q**3*r**2*s**2 - 415585000*p**4*q**5*r**2*s**2 + 1054775000*p*q**7*r**2*s**2 - 96823500*p**8*q*r**3*s**2 - 701490000*p**5*q**3*r**3*s**2 - 2953531250*p**2*q**5*r**3*s**2 + 1454560000*p**6*q*r**4*s**2 + 7670500000*p**3*q**3*r**4*s**2 + 5661062500*q**5*r**4*s**2 - 7785000000*p**4*q*r**5*s**2 - 9450000000*p*q**3*r**5*s**2 + 14000000000*p**2*q*r**6*s**2 + 2400000000*q*r**7*s**2 - 437400*p**13*s**3 - 10145250*p**10*q**2*s**3 - 121912500*p**7*q**4*s**3 - 576531250*p**4*q**6*s**3 - 528593750*p*q**8*s**3 + 12939750*p**11*r*s**3 + 313368750*p**8*q**2*r*s**3 + 2171812500*p**5*q**4*r*s**3 + 2381718750*p**2*q**6*r*s**3 - 124638750*p**9*r**2*s**3 - 3001575000*p**6*q**2*r**2*s**3 - 12259375000*p**3*q**4*r**2*s**3 - 9985312500*q**6*r**2*s**3 + 384000000*p**7*r**3*s**3 + 13997500000*p**4*q**2*r**3*s**3 + 20749531250*p*q**4*r**3*s**3 - 553500000*p**5*r**4*s**3 - 41835000000*p**2*q**2*r**4*s**3 + 5420000000*p**3*r**5*s**3 - 16300000000*q**2*r**5*s**3 - 17600000000*p*r**6*s**3 - 7593750*p**9*q*s**4 + 289218750*p**6*q**3*s**4 + 3591406250*p**3*q**5*s**4 + 5992187500*q**7*s**4 + 658125000*p**7*q*r*s**4 - 269531250*p**4*q**3*r*s**4 - 15882812500*p*q**5*r*s**4 - 4785000000*p**5*q*r**2*s**4 + 54375781250*p**2*q**3*r**2*s**4 - 5668750000*p**3*q*r**3*s**4 + 35867187500*q**3*r**3*s**4 + 113875000000*p*q*r**4*s**4 - 544218750*p**8*s**5 - 5407031250*p**5*q**2*s**5 - 14277343750*p**2*q**4*s**5 + 5421093750*p**6*r*s**5 - 24941406250*p**3*q**2*r*s**5 - 25488281250*q**4*r*s**5 - 11500000000*p**4*r**2*s**5 - 231894531250*p*q**2*r**2*s**5 - 6250000000*p**2*r**3*s**5 - 43750000000*r**4*s**5 + 35449218750*p**4*q*s**6 + 137695312500*p*q**3*s**6 + 34667968750*p**2*q*r*s**6 + 202148437500*q*r**2*s**6 - 33691406250*p**3*s**7 - 214843750000*q**2*s**7 - 31738281250*p*r*s**7 b[2][3] = -800*p**5*q**9 - 5400*p**2*q**11 + 5800*p**6*q**7*r + 48750*p**3*q**9*r + 16200*q**11*r - 3000*p**7*q**5*r**2 - 108350*p**4*q**7*r**2 - 263250*p*q**9*r**2 - 60700*p**8*q**3*r**3 - 386250*p**5*q**5*r**3 + 253100*p**2*q**7*r**3 + 127800*p**9*q*r**4 + 2326700*p**6*q**3*r**4 + 6565550*p**3*q**5*r**4 - 705750*q**7*r**4 - 2903200*p**7*q*r**5 - 21218000*p**4*q**3*r**5 + 1057000*p*q**5*r**5 + 20368000*p**5*q*r**6 + 33000000*p**2*q**3*r**6 - 43200000*p**3*q*r**7 + 52000000*q**3*r**7 + 6200*p**7*q**6*s + 188250*p**4*q**8*s + 931500*p*q**10*s - 73800*p**8*q**4*r*s - 1466850*p**5*q**6*r*s - 6894000*p**2*q**8*r*s + 315900*p**9*q**2*r**2*s + 4547000*p**6*q**4*r**2*s + 20362500*p**3*q**6*r**2*s + 15018750*q**8*r**2*s - 653400*p**10*r**3*s - 13897550*p**7*q**2*r**3*s - 76757500*p**4*q**4*r**3*s - 124207500*p*q**6*r**3*s + 18567600*p**8*r**4*s + 175911000*p**5*q**2*r**4*s + 253787500*p**2*q**4*r**4*s - 183816000*p**6*r**5*s - 706900000*p**3*q**2*r**5*s - 665750000*q**4*r**5*s + 740000000*p**4*r**6*s + 890000000*p*q**2*r**6*s - 1040000000*p**2*r**7*s - 763000*p**6*q**5*s**2 - 12375000*p**3*q**7*s**2 - 40500000*q**9*s**2 + 364500*p**10*q*r*s**2 + 15537000*p**7*q**3*r*s**2 + 154392500*p**4*q**5*r*s**2 + 372206250*p*q**7*r*s**2 - 25481250*p**8*q*r**2*s**2 - 386300000*p**5*q**3*r**2*s**2 - 996343750*p**2*q**5*r**2*s**2 + 459872500*p**6*q*r**3*s**2 + 2943937500*p**3*q**3*r**3*s**2 + 2437781250*q**5*r**3*s**2 - 2883750000*p**4*q*r**4*s**2 - 4343750000*p*q**3*r**4*s**2 + 5495000000*p**2*q*r**5*s**2 + 1300000000*q*r**6*s**2 - 364500*p**11*s**3 - 13668750*p**8*q**2*s**3 - 113406250*p**5*q**4*s**3 - 159062500*p**2*q**6*s**3 + 13972500*p**9*r*s**3 + 61537500*p**6*q**2*r*s**3 - 1622656250*p**3*q**4*r*s**3 - 2720625000*q**6*r*s**3 - 201656250*p**7*r**2*s**3 + 1949687500*p**4*q**2*r**2*s**3 + 4979687500*p*q**4*r**2*s**3 + 497125000*p**5*r**3*s**3 - 11150625000*p**2*q**2*r**3*s**3 + 2982500000*p**3*r**4*s**3 - 6612500000*q**2*r**4*s**3 - 10450000000*p*r**5*s**3 + 126562500*p**7*q*s**4 + 1443750000*p**4*q**3*s**4 + 281250000*p*q**5*s**4 - 1648125000*p**5*q*r*s**4 + 11271093750*p**2*q**3*r*s**4 - 4785156250*p**3*q*r**2*s**4 + 8808593750*q**3*r**2*s**4 + 52390625000*p*q*r**3*s**4 - 611718750*p**6*s**5 - 13027343750*p**3*q**2*s**5 - 1464843750*q**4*s**5 + 6492187500*p**4*r*s**5 - 65351562500*p*q**2*r*s**5 - 13476562500*p**2*r**2*s**5 - 24218750000*r**3*s**5 + 41992187500*p**2*q*s**6 + 69824218750*q*r*s**6 - 34179687500*p*s**7 b[2][2] = -1000*p**6*q**7 - 5150*p**3*q**9 + 10800*q**11 + 11000*p**7*q**5*r + 66450*p**4*q**7*r - 127800*p*q**9*r - 41250*p**8*q**3*r**2 - 368400*p**5*q**5*r**2 + 204200*p**2*q**7*r**2 + 54000*p**9*q*r**3 + 1040950*p**6*q**3*r**3 + 2096500*p**3*q**5*r**3 + 200000*q**7*r**3 - 1140000*p**7*q*r**4 - 7691000*p**4*q**3*r**4 - 2281000*p*q**5*r**4 + 7296000*p**5*q*r**5 + 13300000*p**2*q**3*r**5 - 14400000*p**3*q*r**6 + 14000000*q**3*r**6 - 9000*p**8*q**4*s + 52100*p**5*q**6*s + 710250*p**2*q**8*s + 67500*p**9*q**2*r*s - 256100*p**6*q**4*r*s - 5753000*p**3*q**6*r*s + 292500*q**8*r*s - 162000*p**10*r**2*s - 1432350*p**7*q**2*r**2*s + 5410000*p**4*q**4*r**2*s - 7408750*p*q**6*r**2*s + 4401000*p**8*r**3*s + 24185000*p**5*q**2*r**3*s + 20781250*p**2*q**4*r**3*s - 43012000*p**6*r**4*s - 146300000*p**3*q**2*r**4*s - 165875000*q**4*r**4*s + 182000000*p**4*r**5*s + 250000000*p*q**2*r**5*s - 280000000*p**2*r**6*s + 60750*p**10*q*s**2 + 2414250*p**7*q**3*s**2 + 15770000*p**4*q**5*s**2 + 15825000*p*q**7*s**2 - 6021000*p**8*q*r*s**2 - 62252500*p**5*q**3*r*s**2 - 74718750*p**2*q**5*r*s**2 + 90888750*p**6*q*r**2*s**2 + 471312500*p**3*q**3*r**2*s**2 + 525875000*q**5*r**2*s**2 - 539375000*p**4*q*r**3*s**2 - 1030000000*p*q**3*r**3*s**2 + 1142500000*p**2*q*r**4*s**2 + 350000000*q*r**5*s**2 - 303750*p**9*s**3 - 35943750*p**6*q**2*s**3 - 331875000*p**3*q**4*s**3 - 505937500*q**6*s**3 + 8437500*p**7*r*s**3 + 530781250*p**4*q**2*r*s**3 + 1150312500*p*q**4*r*s**3 - 154500000*p**5*r**2*s**3 - 2059062500*p**2*q**2*r**2*s**3 + 1150000000*p**3*r**3*s**3 - 1343750000*q**2*r**3*s**3 - 2900000000*p*r**4*s**3 + 30937500*p**5*q*s**4 + 1166406250*p**2*q**3*s**4 - 1496875000*p**3*q*r*s**4 + 1296875000*q**3*r*s**4 + 10640625000*p*q*r**2*s**4 - 281250000*p**4*s**5 - 9746093750*p*q**2*s**5 + 1269531250*p**2*r*s**5 - 7421875000*r**2*s**5 + 15625000000*q*s**6 b[2][1] = -1600*p**4*q**7 - 10800*p*q**9 + 9800*p**5*q**5*r + 80550*p**2*q**7*r - 4600*p**6*q**3*r**2 - 112700*p**3*q**5*r**2 + 40500*q**7*r**2 - 34200*p**7*q*r**3 - 279500*p**4*q**3*r**3 - 665750*p*q**5*r**3 + 632000*p**5*q*r**4 + 3200000*p**2*q**3*r**4 - 2800000*p**3*q*r**5 + 3000000*q**3*r**5 - 18600*p**6*q**4*s - 51750*p**3*q**6*s + 405000*q**8*s + 21600*p**7*q**2*r*s - 122500*p**4*q**4*r*s - 2891250*p*q**6*r*s + 156600*p**8*r**2*s + 1569750*p**5*q**2*r**2*s + 6943750*p**2*q**4*r**2*s - 3774000*p**6*r**3*s - 27100000*p**3*q**2*r**3*s - 30187500*q**4*r**3*s + 28000000*p**4*r**4*s + 52500000*p*q**2*r**4*s - 60000000*p**2*r**5*s - 81000*p**8*q*s**2 - 240000*p**5*q**3*s**2 + 937500*p**2*q**5*s**2 + 3273750*p**6*q*r*s**2 + 30406250*p**3*q**3*r*s**2 + 55687500*q**5*r*s**2 - 42187500*p**4*q*r**2*s**2 - 112812500*p*q**3*r**2*s**2 + 152500000*p**2*q*r**3*s**2 + 75000000*q*r**4*s**2 - 4218750*p**4*q**2*s**3 + 15156250*p*q**4*s**3 + 5906250*p**5*r*s**3 - 206562500*p**2*q**2*r*s**3 + 107500000*p**3*r**2*s**3 - 159375000*q**2*r**2*s**3 - 612500000*p*r**3*s**3 + 135937500*p**3*q*s**4 + 46875000*q**3*s**4 + 1175781250*p*q*r*s**4 - 292968750*p**2*s**5 - 1367187500*r*s**5 b[2][0] = -800*p**5*q**5 - 5400*p**2*q**7 + 6000*p**6*q**3*r + 51700*p**3*q**5*r + 27000*q**7*r - 10800*p**7*q*r**2 - 163250*p**4*q**3*r**2 - 285750*p*q**5*r**2 + 192000*p**5*q*r**3 + 1000000*p**2*q**3*r**3 - 800000*p**3*q*r**4 + 500000*q**3*r**4 - 10800*p**7*q**2*s - 57500*p**4*q**4*s + 67500*p*q**6*s + 32400*p**8*r*s + 279000*p**5*q**2*r*s - 131250*p**2*q**4*r*s - 729000*p**6*r**2*s - 4100000*p**3*q**2*r**2*s - 5343750*q**4*r**2*s + 5000000*p**4*r**3*s + 10000000*p*q**2*r**3*s - 10000000*p**2*r**4*s + 641250*p**6*q*s**2 + 5812500*p**3*q**3*s**2 + 10125000*q**5*s**2 - 7031250*p**4*q*r*s**2 - 20625000*p*q**3*r*s**2 + 17500000*p**2*q*r**2*s**2 + 12500000*q*r**3*s**2 - 843750*p**5*s**3 - 19375000*p**2*q**2*s**3 + 30000000*p**3*r*s**3 - 20312500*q**2*r*s**3 - 112500000*p*r**2*s**3 + 183593750*p*q*s**4 - 292968750*s**5 b[3][5] = 500*p**11*q**6 + 9875*p**8*q**8 + 42625*p**5*q**10 - 35000*p**2*q**12 - 4500*p**12*q**4*r - 108375*p**9*q**6*r - 516750*p**6*q**8*r + 1110500*p**3*q**10*r + 2730000*q**12*r + 10125*p**13*q**2*r**2 + 358250*p**10*q**4*r**2 + 1908625*p**7*q**6*r**2 - 11744250*p**4*q**8*r**2 - 43383250*p*q**10*r**2 - 313875*p**11*q**2*r**3 - 2074875*p**8*q**4*r**3 + 52094750*p**5*q**6*r**3 + 264567500*p**2*q**8*r**3 + 796125*p**9*q**2*r**4 - 92486250*p**6*q**4*r**4 - 757957500*p**3*q**6*r**4 - 29354375*q**8*r**4 + 60970000*p**7*q**2*r**5 + 1112462500*p**4*q**4*r**5 + 571094375*p*q**6*r**5 - 685290000*p**5*q**2*r**6 - 2037800000*p**2*q**4*r**6 + 2279600000*p**3*q**2*r**7 + 849000000*q**4*r**7 - 1480000000*p*q**2*r**8 + 13500*p**13*q**3*s + 363000*p**10*q**5*s + 2861250*p**7*q**7*s + 8493750*p**4*q**9*s + 17031250*p*q**11*s - 60750*p**14*q*r*s - 2319750*p**11*q**3*r*s - 22674250*p**8*q**5*r*s - 74368750*p**5*q**7*r*s - 170578125*p**2*q**9*r*s + 2760750*p**12*q*r**2*s + 46719000*p**9*q**3*r**2*s + 163356375*p**6*q**5*r**2*s + 360295625*p**3*q**7*r**2*s - 195990625*q**9*r**2*s - 37341750*p**10*q*r**3*s - 194739375*p**7*q**3*r**3*s - 105463125*p**4*q**5*r**3*s - 415825000*p*q**7*r**3*s + 90180000*p**8*q*r**4*s - 990552500*p**5*q**3*r**4*s + 3519212500*p**2*q**5*r**4*s + 1112220000*p**6*q*r**5*s - 4508750000*p**3*q**3*r**5*s - 8159500000*q**5*r**5*s - 4356000000*p**4*q*r**6*s + 14615000000*p*q**3*r**6*s - 2160000000*p**2*q*r**7*s + 91125*p**15*s**2 + 3290625*p**12*q**2*s**2 + 35100000*p**9*q**4*s**2 + 175406250*p**6*q**6*s**2 + 629062500*p**3*q**8*s**2 + 910937500*q**10*s**2 - 5710500*p**13*r*s**2 - 100423125*p**10*q**2*r*s**2 - 604743750*p**7*q**4*r*s**2 - 2954843750*p**4*q**6*r*s**2 - 4587578125*p*q**8*r*s**2 + 116194500*p**11*r**2*s**2 + 1280716250*p**8*q**2*r**2*s**2 + 7401190625*p**5*q**4*r**2*s**2 + 11619937500*p**2*q**6*r**2*s**2 - 952173125*p**9*r**3*s**2 - 6519712500*p**6*q**2*r**3*s**2 - 10238593750*p**3*q**4*r**3*s**2 + 29984609375*q**6*r**3*s**2 + 2558300000*p**7*r**4*s**2 + 16225000000*p**4*q**2*r**4*s**2 - 64994140625*p*q**4*r**4*s**2 + 4202250000*p**5*r**5*s**2 + 46925000000*p**2*q**2*r**5*s**2 - 28950000000*p**3*r**6*s**2 - 1000000000*q**2*r**6*s**2 + 37000000000*p*r**7*s**2 - 48093750*p**11*q*s**3 - 673359375*p**8*q**3*s**3 - 2170312500*p**5*q**5*s**3 - 2466796875*p**2*q**7*s**3 + 647578125*p**9*q*r*s**3 + 597031250*p**6*q**3*r*s**3 - 7542578125*p**3*q**5*r*s**3 - 41125000000*q**7*r*s**3 - 2175828125*p**7*q*r**2*s**3 - 7101562500*p**4*q**3*r**2*s**3 + 100596875000*p*q**5*r**2*s**3 - 8984687500*p**5*q*r**3*s**3 - 120070312500*p**2*q**3*r**3*s**3 + 57343750000*p**3*q*r**4*s**3 + 9500000000*q**3*r**4*s**3 - 342875000000*p*q*r**5*s**3 + 400781250*p**10*s**4 + 8531250000*p**7*q**2*s**4 + 34033203125*p**4*q**4*s**4 + 42724609375*p*q**6*s**4 - 6289453125*p**8*r*s**4 - 24037109375*p**5*q**2*r*s**4 - 62626953125*p**2*q**4*r*s**4 + 17299218750*p**6*r**2*s**4 + 108357421875*p**3*q**2*r**2*s**4 - 55380859375*q**4*r**2*s**4 + 105648437500*p**4*r**3*s**4 + 1204228515625*p*q**2*r**3*s**4 - 365000000000*p**2*r**4*s**4 + 184375000000*r**5*s**4 - 32080078125*p**6*q*s**5 - 98144531250*p**3*q**3*s**5 + 93994140625*q**5*s**5 - 178955078125*p**4*q*r*s**5 - 1299804687500*p*q**3*r*s**5 + 332421875000*p**2*q*r**2*s**5 - 1195312500000*q*r**3*s**5 + 72021484375*p**5*s**6 + 323486328125*p**2*q**2*s**6 + 682373046875*p**3*r*s**6 + 2447509765625*q**2*r*s**6 - 3011474609375*p*r**2*s**6 + 3051757812500*p*q*s**7 - 7629394531250*s**8 b[3][4] = 1500*p**9*q**6 + 69625*p**6*q**8 + 590375*p**3*q**10 + 1035000*q**12 - 13500*p**10*q**4*r - 760625*p**7*q**6*r - 7904500*p**4*q**8*r - 18169250*p*q**10*r + 30375*p**11*q**2*r**2 + 2628625*p**8*q**4*r**2 + 37879000*p**5*q**6*r**2 + 121367500*p**2*q**8*r**2 - 2699250*p**9*q**2*r**3 - 76776875*p**6*q**4*r**3 - 403583125*p**3*q**6*r**3 - 78865625*q**8*r**3 + 60907500*p**7*q**2*r**4 + 735291250*p**4*q**4*r**4 + 781142500*p*q**6*r**4 - 558270000*p**5*q**2*r**5 - 2150725000*p**2*q**4*r**5 + 2015400000*p**3*q**2*r**6 + 1181000000*q**4*r**6 - 2220000000*p*q**2*r**7 + 40500*p**11*q**3*s + 1376500*p**8*q**5*s + 9953125*p**5*q**7*s + 9765625*p**2*q**9*s - 182250*p**12*q*r*s - 8859000*p**9*q**3*r*s - 82854500*p**6*q**5*r*s - 71511250*p**3*q**7*r*s + 273631250*q**9*r*s + 10233000*p**10*q*r**2*s + 179627500*p**7*q**3*r**2*s + 25164375*p**4*q**5*r**2*s - 2927290625*p*q**7*r**2*s - 171305000*p**8*q*r**3*s - 544768750*p**5*q**3*r**3*s + 7583437500*p**2*q**5*r**3*s + 1139860000*p**6*q*r**4*s - 6489375000*p**3*q**3*r**4*s - 9625375000*q**5*r**4*s - 1838000000*p**4*q*r**5*s + 19835000000*p*q**3*r**5*s - 3240000000*p**2*q*r**6*s + 273375*p**13*s**2 + 9753750*p**10*q**2*s**2 + 82575000*p**7*q**4*s**2 + 202265625*p**4*q**6*s**2 + 556093750*p*q**8*s**2 - 11552625*p**11*r*s**2 - 115813125*p**8*q**2*r*s**2 + 630590625*p**5*q**4*r*s**2 + 1347015625*p**2*q**6*r*s**2 + 157578750*p**9*r**2*s**2 - 689206250*p**6*q**2*r**2*s**2 - 4299609375*p**3*q**4*r**2*s**2 + 23896171875*q**6*r**2*s**2 - 1022437500*p**7*r**3*s**2 + 6648125000*p**4*q**2*r**3*s**2 - 52895312500*p*q**4*r**3*s**2 + 4401750000*p**5*r**4*s**2 + 26500000000*p**2*q**2*r**4*s**2 - 22125000000*p**3*r**5*s**2 - 1500000000*q**2*r**5*s**2 + 55500000000*p*r**6*s**2 - 137109375*p**9*q*s**3 - 1955937500*p**6*q**3*s**3 - 6790234375*p**3*q**5*s**3 - 16996093750*q**7*s**3 + 2146218750*p**7*q*r*s**3 + 6570312500*p**4*q**3*r*s**3 + 39918750000*p*q**5*r*s**3 - 7673281250*p**5*q*r**2*s**3 - 52000000000*p**2*q**3*r**2*s**3 + 50796875000*p**3*q*r**3*s**3 + 18750000000*q**3*r**3*s**3 - 399875000000*p*q*r**4*s**3 + 780468750*p**8*s**4 + 14455078125*p**5*q**2*s**4 + 10048828125*p**2*q**4*s**4 - 15113671875*p**6*r*s**4 + 39298828125*p**3*q**2*r*s**4 - 52138671875*q**4*r*s**4 + 45964843750*p**4*r**2*s**4 + 914414062500*p*q**2*r**2*s**4 + 1953125000*p**2*r**3*s**4 + 334375000000*r**4*s**4 - 149169921875*p**4*q*s**5 - 459716796875*p*q**3*s**5 - 325585937500*p**2*q*r*s**5 - 1462890625000*q*r**2*s**5 + 296630859375*p**3*s**6 + 1324462890625*q**2*s**6 + 307617187500*p*r*s**6 b[3][3] = -20750*p**7*q**6 - 290125*p**4*q**8 - 993000*p*q**10 + 146125*p**8*q**4*r + 2721500*p**5*q**6*r + 11833750*p**2*q**8*r - 237375*p**9*q**2*r**2 - 8167500*p**6*q**4*r**2 - 54605625*p**3*q**6*r**2 - 23802500*q**8*r**2 + 8927500*p**7*q**2*r**3 + 131184375*p**4*q**4*r**3 + 254695000*p*q**6*r**3 - 121561250*p**5*q**2*r**4 - 728003125*p**2*q**4*r**4 + 702550000*p**3*q**2*r**5 + 597312500*q**4*r**5 - 1202500000*p*q**2*r**6 - 194625*p**9*q**3*s - 1568875*p**6*q**5*s + 9685625*p**3*q**7*s + 74662500*q**9*s + 327375*p**10*q*r*s + 1280000*p**7*q**3*r*s - 123703750*p**4*q**5*r*s - 850121875*p*q**7*r*s - 7436250*p**8*q*r**2*s + 164820000*p**5*q**3*r**2*s + 2336659375*p**2*q**5*r**2*s + 32202500*p**6*q*r**3*s - 2429765625*p**3*q**3*r**3*s - 4318609375*q**5*r**3*s + 148000000*p**4*q*r**4*s + 9902812500*p*q**3*r**4*s - 1755000000*p**2*q*r**5*s + 1154250*p**11*s**2 + 36821250*p**8*q**2*s**2 + 372825000*p**5*q**4*s**2 + 1170921875*p**2*q**6*s**2 - 38913750*p**9*r*s**2 - 797071875*p**6*q**2*r*s**2 - 2848984375*p**3*q**4*r*s**2 + 7651406250*q**6*r*s**2 + 415068750*p**7*r**2*s**2 + 3151328125*p**4*q**2*r**2*s**2 - 17696875000*p*q**4*r**2*s**2 - 725968750*p**5*r**3*s**2 + 5295312500*p**2*q**2*r**3*s**2 - 8581250000*p**3*r**4*s**2 - 812500000*q**2*r**4*s**2 + 30062500000*p*r**5*s**2 - 110109375*p**7*q*s**3 - 1976562500*p**4*q**3*s**3 - 6329296875*p*q**5*s**3 + 2256328125*p**5*q*r*s**3 + 8554687500*p**2*q**3*r*s**3 + 12947265625*p**3*q*r**2*s**3 + 7984375000*q**3*r**2*s**3 - 167039062500*p*q*r**3*s**3 + 1181250000*p**6*s**4 + 17873046875*p**3*q**2*s**4 - 20449218750*q**4*s**4 - 16265625000*p**4*r*s**4 + 260869140625*p*q**2*r*s**4 + 21025390625*p**2*r**2*s**4 + 207617187500*r**3*s**4 - 207177734375*p**2*q*s**5 - 615478515625*q*r*s**5 + 301513671875*p*s**6 b[3][2] = 53125*p**5*q**6 + 425000*p**2*q**8 - 394375*p**6*q**4*r - 4301875*p**3*q**6*r - 3225000*q**8*r + 851250*p**7*q**2*r**2 + 16910625*p**4*q**4*r**2 + 44210000*p*q**6*r**2 - 20474375*p**5*q**2*r**3 - 147190625*p**2*q**4*r**3 + 163975000*p**3*q**2*r**4 + 156812500*q**4*r**4 - 323750000*p*q**2*r**5 - 99375*p**7*q**3*s - 6395000*p**4*q**5*s - 49243750*p*q**7*s - 1164375*p**8*q*r*s + 4465625*p**5*q**3*r*s + 205546875*p**2*q**5*r*s + 12163750*p**6*q*r**2*s - 315546875*p**3*q**3*r**2*s - 946453125*q**5*r**2*s - 23500000*p**4*q*r**3*s + 2313437500*p*q**3*r**3*s - 472500000*p**2*q*r**4*s + 1316250*p**9*s**2 + 22715625*p**6*q**2*s**2 + 206953125*p**3*q**4*s**2 + 1220000000*q**6*s**2 - 20953125*p**7*r*s**2 - 277656250*p**4*q**2*r*s**2 - 3317187500*p*q**4*r*s**2 + 293734375*p**5*r**2*s**2 + 1351562500*p**2*q**2*r**2*s**2 - 2278125000*p**3*r**3*s**2 - 218750000*q**2*r**3*s**2 + 8093750000*p*r**4*s**2 - 9609375*p**5*q*s**3 + 240234375*p**2*q**3*s**3 + 2310546875*p**3*q*r*s**3 + 1171875000*q**3*r*s**3 - 33460937500*p*q*r**2*s**3 + 2185546875*p**4*s**4 + 32578125000*p*q**2*s**4 - 8544921875*p**2*r*s**4 + 58398437500*r**2*s**4 - 114013671875*q*s**5 b[3][1] = -16250*p**6*q**4 - 191875*p**3*q**6 - 495000*q**8 + 73125*p**7*q**2*r + 1437500*p**4*q**4*r + 5866250*p*q**6*r - 2043125*p**5*q**2*r**2 - 17218750*p**2*q**4*r**2 + 19106250*p**3*q**2*r**3 + 34015625*q**4*r**3 - 69375000*p*q**2*r**4 - 219375*p**8*q*s - 2846250*p**5*q**3*s - 8021875*p**2*q**5*s + 3420000*p**6*q*r*s - 1640625*p**3*q**3*r*s - 152468750*q**5*r*s + 3062500*p**4*q*r**2*s + 381171875*p*q**3*r**2*s - 101250000*p**2*q*r**3*s + 2784375*p**7*s**2 + 43515625*p**4*q**2*s**2 + 115625000*p*q**4*s**2 - 48140625*p**5*r*s**2 - 307421875*p**2*q**2*r*s**2 - 25781250*p**3*r**2*s**2 - 46875000*q**2*r**2*s**2 + 1734375000*p*r**3*s**2 - 128906250*p**3*q*s**3 + 339843750*q**3*s**3 - 4583984375*p*q*r*s**3 + 2236328125*p**2*s**4 + 12255859375*r*s**4 b[3][0] = 31875*p**4*q**4 + 255000*p*q**6 - 82500*p**5*q**2*r - 1106250*p**2*q**4*r + 1653125*p**3*q**2*r**2 + 5187500*q**4*r**2 - 11562500*p*q**2*r**3 - 118125*p**6*q*s - 3593750*p**3*q**3*s - 23812500*q**5*s + 4656250*p**4*q*r*s + 67109375*p*q**3*r*s - 16875000*p**2*q*r**2*s - 984375*p**5*s**2 - 19531250*p**2*q**2*s**2 - 37890625*p**3*r*s**2 - 7812500*q**2*r*s**2 + 289062500*p*r**2*s**2 - 529296875*p*q*s**3 + 2343750000*s**4 b[4][5] = 600*p**10*q**10 + 13850*p**7*q**12 + 106150*p**4*q**14 + 270000*p*q**16 - 9300*p**11*q**8*r - 234075*p**8*q**10*r - 1942825*p**5*q**12*r - 5319900*p**2*q**14*r + 52050*p**12*q**6*r**2 + 1481025*p**9*q**8*r**2 + 13594450*p**6*q**10*r**2 + 40062750*p**3*q**12*r**2 - 3569400*q**14*r**2 - 122175*p**13*q**4*r**3 - 4260350*p**10*q**6*r**3 - 45052375*p**7*q**8*r**3 - 142634900*p**4*q**10*r**3 + 54186350*p*q**12*r**3 + 97200*p**14*q**2*r**4 + 5284225*p**11*q**4*r**4 + 70389525*p**8*q**6*r**4 + 232732850*p**5*q**8*r**4 - 318849400*p**2*q**10*r**4 - 2046000*p**12*q**2*r**5 - 43874125*p**9*q**4*r**5 - 107411850*p**6*q**6*r**5 + 948310700*p**3*q**8*r**5 - 34763575*q**10*r**5 + 5915600*p**10*q**2*r**6 - 115887800*p**7*q**4*r**6 - 1649542400*p**4*q**6*r**6 + 224468875*p*q**8*r**6 + 120252800*p**8*q**2*r**7 + 1779902000*p**5*q**4*r**7 - 288250000*p**2*q**6*r**7 - 915200000*p**6*q**2*r**8 - 1164000000*p**3*q**4*r**8 - 444200000*q**6*r**8 + 2502400000*p**4*q**2*r**9 + 1984000000*p*q**4*r**9 - 2880000000*p**2*q**2*r**10 + 20700*p**12*q**7*s + 551475*p**9*q**9*s + 5194875*p**6*q**11*s + 18985000*p**3*q**13*s + 16875000*q**15*s - 218700*p**13*q**5*r*s - 6606475*p**10*q**7*r*s - 69770850*p**7*q**9*r*s - 285325500*p**4*q**11*r*s - 292005000*p*q**13*r*s + 694575*p**14*q**3*r**2*s + 26187750*p**11*q**5*r**2*s + 328992825*p**8*q**7*r**2*s + 1573292400*p**5*q**9*r**2*s + 1930043875*p**2*q**11*r**2*s - 583200*p**15*q*r**3*s - 37263225*p**12*q**3*r**3*s - 638579425*p**9*q**5*r**3*s - 3920212225*p**6*q**7*r**3*s - 6327336875*p**3*q**9*r**3*s + 440969375*q**11*r**3*s + 13446000*p**13*q*r**4*s + 462330325*p**10*q**3*r**4*s + 4509088275*p**7*q**5*r**4*s + 11709795625*p**4*q**7*r**4*s - 3579565625*p*q**9*r**4*s - 85033600*p**11*q*r**5*s - 2136801600*p**8*q**3*r**5*s - 12221575800*p**5*q**5*r**5*s + 9431044375*p**2*q**7*r**5*s + 10643200*p**9*q*r**6*s + 4565594000*p**6*q**3*r**6*s - 1778590000*p**3*q**5*r**6*s + 4842175000*q**7*r**6*s + 712320000*p**7*q*r**7*s - 16182000000*p**4*q**3*r**7*s - 21918000000*p*q**5*r**7*s - 742400000*p**5*q*r**8*s + 31040000000*p**2*q**3*r**8*s + 1280000000*p**3*q*r**9*s + 4800000000*q**3*r**9*s + 230850*p**14*q**4*s**2 + 7373250*p**11*q**6*s**2 + 85045625*p**8*q**8*s**2 + 399140625*p**5*q**10*s**2 + 565031250*p**2*q**12*s**2 - 1257525*p**15*q**2*r*s**2 - 52728975*p**12*q**4*r*s**2 - 743466375*p**9*q**6*r*s**2 - 4144915000*p**6*q**8*r*s**2 - 7102690625*p**3*q**10*r*s**2 - 1389937500*q**12*r*s**2 + 874800*p**16*r**2*s**2 + 89851275*p**13*q**2*r**2*s**2 + 1897236775*p**10*q**4*r**2*s**2 + 14144163000*p**7*q**6*r**2*s**2 + 31942921875*p**4*q**8*r**2*s**2 + 13305118750*p*q**10*r**2*s**2 - 23004000*p**14*r**3*s**2 - 1450715475*p**11*q**2*r**3*s**2 - 19427105000*p**8*q**4*r**3*s**2 - 70634028750*p**5*q**6*r**3*s**2 - 47854218750*p**2*q**8*r**3*s**2 + 204710400*p**12*r**4*s**2 + 10875135000*p**9*q**2*r**4*s**2 + 83618806250*p**6*q**4*r**4*s**2 + 62744500000*p**3*q**6*r**4*s**2 - 19806718750*q**8*r**4*s**2 - 757094800*p**10*r**5*s**2 - 37718030000*p**7*q**2*r**5*s**2 - 22479500000*p**4*q**4*r**5*s**2 + 91556093750*p*q**6*r**5*s**2 + 2306320000*p**8*r**6*s**2 + 55539600000*p**5*q**2*r**6*s**2 - 112851250000*p**2*q**4*r**6*s**2 - 10720000000*p**6*r**7*s**2 - 64720000000*p**3*q**2*r**7*s**2 - 59925000000*q**4*r**7*s**2 + 28000000000*p**4*r**8*s**2 + 28000000000*p*q**2*r**8*s**2 - 24000000000*p**2*r**9*s**2 + 820125*p**16*q*s**3 + 36804375*p**13*q**3*s**3 + 552225000*p**10*q**5*s**3 + 3357593750*p**7*q**7*s**3 + 7146562500*p**4*q**9*s**3 + 3851562500*p*q**11*s**3 - 92400750*p**14*q*r*s**3 - 2350175625*p**11*q**3*r*s**3 - 19470640625*p**8*q**5*r*s**3 - 52820593750*p**5*q**7*r*s**3 - 45447734375*p**2*q**9*r*s**3 + 1824363000*p**12*q*r**2*s**3 + 31435234375*p**9*q**3*r**2*s**3 + 141717537500*p**6*q**5*r**2*s**3 + 228370781250*p**3*q**7*r**2*s**3 + 34610078125*q**9*r**2*s**3 - 17591825625*p**10*q*r**3*s**3 - 188927187500*p**7*q**3*r**3*s**3 - 502088984375*p**4*q**5*r**3*s**3 - 187849296875*p*q**7*r**3*s**3 + 75577750000*p**8*q*r**4*s**3 + 342800000000*p**5*q**3*r**4*s**3 + 295384296875*p**2*q**5*r**4*s**3 - 107681250000*p**6*q*r**5*s**3 + 53330000000*p**3*q**3*r**5*s**3 + 271586875000*q**5*r**5*s**3 - 26410000000*p**4*q*r**6*s**3 - 188200000000*p*q**3*r**6*s**3 + 92000000000*p**2*q*r**7*s**3 + 120000000000*q*r**8*s**3 + 47840625*p**15*s**4 + 1150453125*p**12*q**2*s**4 + 9229453125*p**9*q**4*s**4 + 24954687500*p**6*q**6*s**4 + 22978515625*p**3*q**8*s**4 + 1367187500*q**10*s**4 - 1193737500*p**13*r*s**4 - 20817843750*p**10*q**2*r*s**4 - 98640000000*p**7*q**4*r*s**4 - 225767187500*p**4*q**6*r*s**4 - 74707031250*p*q**8*r*s**4 + 13431318750*p**11*r**2*s**4 + 188709843750*p**8*q**2*r**2*s**4 + 875157656250*p**5*q**4*r**2*s**4 + 593812890625*p**2*q**6*r**2*s**4 - 69869296875*p**9*r**3*s**4 - 854811093750*p**6*q**2*r**3*s**4 - 1730658203125*p**3*q**4*r**3*s**4 - 570867187500*q**6*r**3*s**4 + 162075625000*p**7*r**4*s**4 + 1536375000000*p**4*q**2*r**4*s**4 + 765156250000*p*q**4*r**4*s**4 - 165988750000*p**5*r**5*s**4 - 728968750000*p**2*q**2*r**5*s**4 + 121500000000*p**3*r**6*s**4 - 1039375000000*q**2*r**6*s**4 - 100000000000*p*r**7*s**4 - 379687500*p**11*q*s**5 - 11607421875*p**8*q**3*s**5 - 20830078125*p**5*q**5*s**5 - 33691406250*p**2*q**7*s**5 - 41491406250*p**9*q*r*s**5 - 419054687500*p**6*q**3*r*s**5 - 129511718750*p**3*q**5*r*s**5 + 311767578125*q**7*r*s**5 + 620116015625*p**7*q*r**2*s**5 + 1154687500000*p**4*q**3*r**2*s**5 + 36455078125*p*q**5*r**2*s**5 - 2265953125000*p**5*q*r**3*s**5 - 1509521484375*p**2*q**3*r**3*s**5 + 2530468750000*p**3*q*r**4*s**5 + 3259765625000*q**3*r**4*s**5 + 93750000000*p*q*r**5*s**5 + 23730468750*p**10*s**6 + 243603515625*p**7*q**2*s**6 + 341552734375*p**4*q**4*s**6 - 12207031250*p*q**6*s**6 - 357099609375*p**8*r*s**6 - 298193359375*p**5*q**2*r*s**6 + 406738281250*p**2*q**4*r*s**6 + 1615683593750*p**6*r**2*s**6 + 558593750000*p**3*q**2*r**2*s**6 - 2811035156250*q**4*r**2*s**6 - 2960937500000*p**4*r**3*s**6 - 3802246093750*p*q**2*r**3*s**6 + 2347656250000*p**2*r**4*s**6 - 671875000000*r**5*s**6 - 651855468750*p**6*q*s**7 - 1458740234375*p**3*q**3*s**7 - 152587890625*q**5*s**7 + 1628417968750*p**4*q*r*s**7 + 3948974609375*p*q**3*r*s**7 - 916748046875*p**2*q*r**2*s**7 + 1611328125000*q*r**3*s**7 + 640869140625*p**5*s**8 + 1068115234375*p**2*q**2*s**8 - 2044677734375*p**3*r*s**8 - 3204345703125*q**2*r*s**8 + 1739501953125*p*r**2*s**8 b[4][4] = -600*p**11*q**8 - 14050*p**8*q**10 - 109100*p**5*q**12 - 280800*p**2*q**14 + 7200*p**12*q**6*r + 188700*p**9*q**8*r + 1621725*p**6*q**10*r + 4577075*p**3*q**12*r + 5400*q**14*r - 28350*p**13*q**4*r**2 - 910600*p**10*q**6*r**2 - 9237975*p**7*q**8*r**2 - 30718900*p**4*q**10*r**2 - 5575950*p*q**12*r**2 + 36450*p**14*q**2*r**3 + 1848125*p**11*q**4*r**3 + 25137775*p**8*q**6*r**3 + 109591450*p**5*q**8*r**3 + 70627650*p**2*q**10*r**3 - 1317150*p**12*q**2*r**4 - 32857100*p**9*q**4*r**4 - 219125575*p**6*q**6*r**4 - 327565875*p**3*q**8*r**4 - 13011875*q**10*r**4 + 16484150*p**10*q**2*r**5 + 222242250*p**7*q**4*r**5 + 642173750*p**4*q**6*r**5 + 101263750*p*q**8*r**5 - 79345000*p**8*q**2*r**6 - 433180000*p**5*q**4*r**6 - 93731250*p**2*q**6*r**6 - 74300000*p**6*q**2*r**7 - 1057900000*p**3*q**4*r**7 - 591175000*q**6*r**7 + 1891600000*p**4*q**2*r**8 + 2796000000*p*q**4*r**8 - 4320000000*p**2*q**2*r**9 - 16200*p**13*q**5*s - 359500*p**10*q**7*s - 2603825*p**7*q**9*s - 4590375*p**4*q**11*s + 12352500*p*q**13*s + 121500*p**14*q**3*r*s + 3227400*p**11*q**5*r*s + 27301725*p**8*q**7*r*s + 59480975*p**5*q**9*r*s - 137308875*p**2*q**11*r*s - 218700*p**15*q*r**2*s - 8903925*p**12*q**3*r**2*s - 100918225*p**9*q**5*r**2*s - 325291300*p**6*q**7*r**2*s + 365705000*p**3*q**9*r**2*s + 94342500*q**11*r**2*s + 7632900*p**13*q*r**3*s + 162995400*p**10*q**3*r**3*s + 974558975*p**7*q**5*r**3*s + 930991250*p**4*q**7*r**3*s - 495368750*p*q**9*r**3*s - 97344900*p**11*q*r**4*s - 1406739250*p**8*q**3*r**4*s - 5572526250*p**5*q**5*r**4*s - 1903987500*p**2*q**7*r**4*s + 678550000*p**9*q*r**5*s + 8176215000*p**6*q**3*r**5*s + 18082050000*p**3*q**5*r**5*s + 5435843750*q**7*r**5*s - 2979800000*p**7*q*r**6*s - 29163500000*p**4*q**3*r**6*s - 27417500000*p*q**5*r**6*s + 6282400000*p**5*q*r**7*s + 48690000000*p**2*q**3*r**7*s - 2880000000*p**3*q*r**8*s + 7200000000*q**3*r**8*s - 109350*p**15*q**2*s**2 - 2405700*p**12*q**4*s**2 - 16125250*p**9*q**6*s**2 - 4930000*p**6*q**8*s**2 + 201150000*p**3*q**10*s**2 - 243000000*q**12*s**2 + 328050*p**16*r*s**2 + 10552275*p**13*q**2*r*s**2 + 88019100*p**10*q**4*r*s**2 - 4208625*p**7*q**6*r*s**2 - 1920390625*p**4*q**8*r*s**2 + 1759537500*p*q**10*r*s**2 - 11955600*p**14*r**2*s**2 - 196375050*p**11*q**2*r**2*s**2 - 555196250*p**8*q**4*r**2*s**2 + 4213270000*p**5*q**6*r**2*s**2 - 157468750*p**2*q**8*r**2*s**2 + 162656100*p**12*r**3*s**2 + 1880870000*p**9*q**2*r**3*s**2 + 753684375*p**6*q**4*r**3*s**2 - 25423062500*p**3*q**6*r**3*s**2 - 14142031250*q**8*r**3*s**2 - 1251948750*p**10*r**4*s**2 - 12524475000*p**7*q**2*r**4*s**2 + 18067656250*p**4*q**4*r**4*s**2 + 60531875000*p*q**6*r**4*s**2 + 6827725000*p**8*r**5*s**2 + 57157000000*p**5*q**2*r**5*s**2 - 75844531250*p**2*q**4*r**5*s**2 - 24452500000*p**6*r**6*s**2 - 144950000000*p**3*q**2*r**6*s**2 - 82109375000*q**4*r**6*s**2 + 46950000000*p**4*r**7*s**2 + 60000000000*p*q**2*r**7*s**2 - 36000000000*p**2*r**8*s**2 + 1549125*p**14*q*s**3 + 51873750*p**11*q**3*s**3 + 599781250*p**8*q**5*s**3 + 2421156250*p**5*q**7*s**3 - 1693515625*p**2*q**9*s**3 - 104884875*p**12*q*r*s**3 - 1937437500*p**9*q**3*r*s**3 - 11461053125*p**6*q**5*r*s**3 + 10299375000*p**3*q**7*r*s**3 + 10551250000*q**9*r*s**3 + 1336263750*p**10*q*r**2*s**3 + 23737250000*p**7*q**3*r**2*s**3 + 57136718750*p**4*q**5*r**2*s**3 - 8288906250*p*q**7*r**2*s**3 - 10907218750*p**8*q*r**3*s**3 - 160615000000*p**5*q**3*r**3*s**3 - 111134687500*p**2*q**5*r**3*s**3 + 46743125000*p**6*q*r**4*s**3 + 570509375000*p**3*q**3*r**4*s**3 + 274839843750*q**5*r**4*s**3 - 73312500000*p**4*q*r**5*s**3 - 145437500000*p*q**3*r**5*s**3 + 8750000000*p**2*q*r**6*s**3 + 180000000000*q*r**7*s**3 + 15946875*p**13*s**4 + 1265625*p**10*q**2*s**4 - 3282343750*p**7*q**4*s**4 - 38241406250*p**4*q**6*s**4 - 40136718750*p*q**8*s**4 - 113146875*p**11*r*s**4 - 2302734375*p**8*q**2*r*s**4 + 68450156250*p**5*q**4*r*s**4 + 177376562500*p**2*q**6*r*s**4 + 3164062500*p**9*r**2*s**4 + 14392890625*p**6*q**2*r**2*s**4 - 543781250000*p**3*q**4*r**2*s**4 - 319769531250*q**6*r**2*s**4 - 21048281250*p**7*r**3*s**4 - 240687500000*p**4*q**2*r**3*s**4 - 228164062500*p*q**4*r**3*s**4 + 23062500000*p**5*r**4*s**4 + 300410156250*p**2*q**2*r**4*s**4 + 93437500000*p**3*r**5*s**4 - 1141015625000*q**2*r**5*s**4 - 187500000000*p*r**6*s**4 + 1761328125*p**9*q*s**5 - 3177734375*p**6*q**3*s**5 + 60019531250*p**3*q**5*s**5 + 108398437500*q**7*s**5 + 24106640625*p**7*q*r*s**5 + 429589843750*p**4*q**3*r*s**5 + 410371093750*p*q**5*r*s**5 - 23582031250*p**5*q*r**2*s**5 + 202441406250*p**2*q**3*r**2*s**5 - 383203125000*p**3*q*r**3*s**5 + 2232910156250*q**3*r**3*s**5 + 1500000000000*p*q*r**4*s**5 - 13710937500*p**8*s**6 - 202832031250*p**5*q**2*s**6 - 531738281250*p**2*q**4*s**6 + 73330078125*p**6*r*s**6 - 3906250000*p**3*q**2*r*s**6 - 1275878906250*q**4*r*s**6 - 121093750000*p**4*r**2*s**6 - 3308593750000*p*q**2*r**2*s**6 + 18066406250*p**2*r**3*s**6 - 244140625000*r**4*s**6 + 327148437500*p**4*q*s**7 + 1672363281250*p*q**3*s**7 + 446777343750*p**2*q*r*s**7 + 1232910156250*q*r**2*s**7 - 274658203125*p**3*s**8 - 1068115234375*q**2*s**8 - 61035156250*p*r*s**8 b[4][3] = 200*p**9*q**8 + 7550*p**6*q**10 + 78650*p**3*q**12 + 248400*q**14 - 4800*p**10*q**6*r - 164300*p**7*q**8*r - 1709575*p**4*q**10*r - 5566500*p*q**12*r + 31050*p**11*q**4*r**2 + 1116175*p**8*q**6*r**2 + 12674650*p**5*q**8*r**2 + 45333850*p**2*q**10*r**2 - 60750*p**12*q**2*r**3 - 2872725*p**9*q**4*r**3 - 40403050*p**6*q**6*r**3 - 173564375*p**3*q**8*r**3 - 11242250*q**10*r**3 + 2174100*p**10*q**2*r**4 + 54010000*p**7*q**4*r**4 + 331074875*p**4*q**6*r**4 + 114173750*p*q**8*r**4 - 24858500*p**8*q**2*r**5 - 300875000*p**5*q**4*r**5 - 319430625*p**2*q**6*r**5 + 69810000*p**6*q**2*r**6 - 23900000*p**3*q**4*r**6 - 294662500*q**6*r**6 + 524200000*p**4*q**2*r**7 + 1432000000*p*q**4*r**7 - 2340000000*p**2*q**2*r**8 + 5400*p**11*q**5*s + 310400*p**8*q**7*s + 3591725*p**5*q**9*s + 11556750*p**2*q**11*s - 105300*p**12*q**3*r*s - 4234650*p**9*q**5*r*s - 49928875*p**6*q**7*r*s - 174078125*p**3*q**9*r*s + 18000000*q**11*r*s + 364500*p**13*q*r**2*s + 15763050*p**10*q**3*r**2*s + 220187400*p**7*q**5*r**2*s + 929609375*p**4*q**7*r**2*s - 43653125*p*q**9*r**2*s - 13427100*p**11*q*r**3*s - 346066250*p**8*q**3*r**3*s - 2287673375*p**5*q**5*r**3*s - 1403903125*p**2*q**7*r**3*s + 184586000*p**9*q*r**4*s + 2983460000*p**6*q**3*r**4*s + 8725818750*p**3*q**5*r**4*s + 2527734375*q**7*r**4*s - 1284480000*p**7*q*r**5*s - 13138250000*p**4*q**3*r**5*s - 14001625000*p*q**5*r**5*s + 4224800000*p**5*q*r**6*s + 27460000000*p**2*q**3*r**6*s - 3760000000*p**3*q*r**7*s + 3900000000*q**3*r**7*s + 36450*p**13*q**2*s**2 + 2765475*p**10*q**4*s**2 + 34027625*p**7*q**6*s**2 + 97375000*p**4*q**8*s**2 - 88275000*p*q**10*s**2 - 546750*p**14*r*s**2 - 21961125*p**11*q**2*r*s**2 - 273059375*p**8*q**4*r*s**2 - 761562500*p**5*q**6*r*s**2 + 1869656250*p**2*q**8*r*s**2 + 20545650*p**12*r**2*s**2 + 473934375*p**9*q**2*r**2*s**2 + 1758053125*p**6*q**4*r**2*s**2 - 8743359375*p**3*q**6*r**2*s**2 - 4154375000*q**8*r**2*s**2 - 296559000*p**10*r**3*s**2 - 4065056250*p**7*q**2*r**3*s**2 - 186328125*p**4*q**4*r**3*s**2 + 19419453125*p*q**6*r**3*s**2 + 2326262500*p**8*r**4*s**2 + 21189375000*p**5*q**2*r**4*s**2 - 26301953125*p**2*q**4*r**4*s**2 - 10513250000*p**6*r**5*s**2 - 69937500000*p**3*q**2*r**5*s**2 - 42257812500*q**4*r**5*s**2 + 23375000000*p**4*r**6*s**2 + 40750000000*p*q**2*r**6*s**2 - 19500000000*p**2*r**7*s**2 + 4009500*p**12*q*s**3 + 36140625*p**9*q**3*s**3 - 335459375*p**6*q**5*s**3 - 2695312500*p**3*q**7*s**3 - 1486250000*q**9*s**3 + 102515625*p**10*q*r*s**3 + 4006812500*p**7*q**3*r*s**3 + 27589609375*p**4*q**5*r*s**3 + 20195312500*p*q**7*r*s**3 - 2792812500*p**8*q*r**2*s**3 - 44115156250*p**5*q**3*r**2*s**3 - 72609453125*p**2*q**5*r**2*s**3 + 18752500000*p**6*q*r**3*s**3 + 218140625000*p**3*q**3*r**3*s**3 + 109940234375*q**5*r**3*s**3 - 21893750000*p**4*q*r**4*s**3 - 65187500000*p*q**3*r**4*s**3 - 31000000000*p**2*q*r**5*s**3 + 97500000000*q*r**6*s**3 - 86568750*p**11*s**4 - 1955390625*p**8*q**2*s**4 - 8960781250*p**5*q**4*s**4 - 1357812500*p**2*q**6*s**4 + 1657968750*p**9*r*s**4 + 10467187500*p**6*q**2*r*s**4 - 55292968750*p**3*q**4*r*s**4 - 60683593750*q**6*r*s**4 - 11473593750*p**7*r**2*s**4 - 123281250000*p**4*q**2*r**2*s**4 - 164912109375*p*q**4*r**2*s**4 + 13150000000*p**5*r**3*s**4 + 190751953125*p**2*q**2*r**3*s**4 + 61875000000*p**3*r**4*s**4 - 467773437500*q**2*r**4*s**4 - 118750000000*p*r**5*s**4 + 7583203125*p**7*q*s**5 + 54638671875*p**4*q**3*s**5 + 39423828125*p*q**5*s**5 + 32392578125*p**5*q*r*s**5 + 278515625000*p**2*q**3*r*s**5 - 298339843750*p**3*q*r**2*s**5 + 560791015625*q**3*r**2*s**5 + 720703125000*p*q*r**3*s**5 - 19687500000*p**6*s**6 - 159667968750*p**3*q**2*s**6 - 72265625000*q**4*s**6 + 116699218750*p**4*r*s**6 - 924072265625*p*q**2*r*s**6 - 156005859375*p**2*r**2*s**6 - 112304687500*r**3*s**6 + 349121093750*p**2*q*s**7 + 396728515625*q*r*s**7 - 213623046875*p*s**8 b[4][2] = -600*p**10*q**6 - 18450*p**7*q**8 - 174000*p**4*q**10 - 518400*p*q**12 + 5400*p**11*q**4*r + 197550*p**8*q**6*r + 2147775*p**5*q**8*r + 7219800*p**2*q**10*r - 12150*p**12*q**2*r**2 - 662200*p**9*q**4*r**2 - 9274775*p**6*q**6*r**2 - 38330625*p**3*q**8*r**2 - 5508000*q**10*r**2 + 656550*p**10*q**2*r**3 + 16233750*p**7*q**4*r**3 + 97335875*p**4*q**6*r**3 + 58271250*p*q**8*r**3 - 9845500*p**8*q**2*r**4 - 119464375*p**5*q**4*r**4 - 194431875*p**2*q**6*r**4 + 49465000*p**6*q**2*r**5 + 166000000*p**3*q**4*r**5 - 80793750*q**6*r**5 + 54400000*p**4*q**2*r**6 + 377750000*p*q**4*r**6 - 630000000*p**2*q**2*r**7 - 16200*p**12*q**3*s - 459300*p**9*q**5*s - 4207225*p**6*q**7*s - 10827500*p**3*q**9*s + 13635000*q**11*s + 72900*p**13*q*r*s + 2877300*p**10*q**3*r*s + 33239700*p**7*q**5*r*s + 107080625*p**4*q**7*r*s - 114975000*p*q**9*r*s - 3601800*p**11*q*r**2*s - 75214375*p**8*q**3*r**2*s - 387073250*p**5*q**5*r**2*s + 55540625*p**2*q**7*r**2*s + 53793000*p**9*q*r**3*s + 687176875*p**6*q**3*r**3*s + 1670018750*p**3*q**5*r**3*s + 665234375*q**7*r**3*s - 391570000*p**7*q*r**4*s - 3420125000*p**4*q**3*r**4*s - 3609625000*p*q**5*r**4*s + 1365600000*p**5*q*r**5*s + 7236250000*p**2*q**3*r**5*s - 1220000000*p**3*q*r**6*s + 1050000000*q**3*r**6*s - 109350*p**14*s**2 - 3065850*p**11*q**2*s**2 - 26908125*p**8*q**4*s**2 - 44606875*p**5*q**6*s**2 + 269812500*p**2*q**8*s**2 + 5200200*p**12*r*s**2 + 81826875*p**9*q**2*r*s**2 + 155378125*p**6*q**4*r*s**2 - 1936203125*p**3*q**6*r*s**2 - 998437500*q**8*r*s**2 - 77145750*p**10*r**2*s**2 - 745528125*p**7*q**2*r**2*s**2 + 683437500*p**4*q**4*r**2*s**2 + 4083359375*p*q**6*r**2*s**2 + 593287500*p**8*r**3*s**2 + 4799375000*p**5*q**2*r**3*s**2 - 4167578125*p**2*q**4*r**3*s**2 - 2731125000*p**6*r**4*s**2 - 18668750000*p**3*q**2*r**4*s**2 - 10480468750*q**4*r**4*s**2 + 6200000000*p**4*r**5*s**2 + 11750000000*p*q**2*r**5*s**2 - 5250000000*p**2*r**6*s**2 + 26527500*p**10*q*s**3 + 526031250*p**7*q**3*s**3 + 3160703125*p**4*q**5*s**3 + 2650312500*p*q**7*s**3 - 448031250*p**8*q*r*s**3 - 6682968750*p**5*q**3*r*s**3 - 11642812500*p**2*q**5*r*s**3 + 2553203125*p**6*q*r**2*s**3 + 37234375000*p**3*q**3*r**2*s**3 + 21871484375*q**5*r**2*s**3 + 2803125000*p**4*q*r**3*s**3 - 10796875000*p*q**3*r**3*s**3 - 16656250000*p**2*q*r**4*s**3 + 26250000000*q*r**5*s**3 - 75937500*p**9*s**4 - 704062500*p**6*q**2*s**4 - 8363281250*p**3*q**4*s**4 - 10398437500*q**6*s**4 + 197578125*p**7*r*s**4 - 16441406250*p**4*q**2*r*s**4 - 24277343750*p*q**4*r*s**4 - 5716015625*p**5*r**2*s**4 + 31728515625*p**2*q**2*r**2*s**4 + 27031250000*p**3*r**3*s**4 - 92285156250*q**2*r**3*s**4 - 33593750000*p*r**4*s**4 + 10394531250*p**5*q*s**5 + 38037109375*p**2*q**3*s**5 - 48144531250*p**3*q*r*s**5 + 74462890625*q**3*r*s**5 + 121093750000*p*q*r**2*s**5 - 2197265625*p**4*s**6 - 92529296875*p*q**2*s**6 + 15380859375*p**2*r*s**6 - 31738281250*r**2*s**6 + 54931640625*q*s**7 b[4][1] = 200*p**8*q**6 + 2950*p**5*q**8 + 10800*p**2*q**10 - 1800*p**9*q**4*r - 49650*p**6*q**6*r - 403375*p**3*q**8*r - 999000*q**10*r + 4050*p**10*q**2*r**2 + 236625*p**7*q**4*r**2 + 3109500*p**4*q**6*r**2 + 11463750*p*q**8*r**2 - 331500*p**8*q**2*r**3 - 7818125*p**5*q**4*r**3 - 41411250*p**2*q**6*r**3 + 4782500*p**6*q**2*r**4 + 47475000*p**3*q**4*r**4 - 16728125*q**6*r**4 - 8700000*p**4*q**2*r**5 + 81750000*p*q**4*r**5 - 135000000*p**2*q**2*r**6 + 5400*p**10*q**3*s + 144200*p**7*q**5*s + 939375*p**4*q**7*s + 1012500*p*q**9*s - 24300*p**11*q*r*s - 1169250*p**8*q**3*r*s - 14027250*p**5*q**5*r*s - 44446875*p**2*q**7*r*s + 2011500*p**9*q*r**2*s + 49330625*p**6*q**3*r**2*s + 272009375*p**3*q**5*r**2*s + 104062500*q**7*r**2*s - 34660000*p**7*q*r**3*s - 455062500*p**4*q**3*r**3*s - 625906250*p*q**5*r**3*s + 210200000*p**5*q*r**4*s + 1298750000*p**2*q**3*r**4*s - 240000000*p**3*q*r**5*s + 225000000*q**3*r**5*s + 36450*p**12*s**2 + 1231875*p**9*q**2*s**2 + 10712500*p**6*q**4*s**2 + 21718750*p**3*q**6*s**2 + 16875000*q**8*s**2 - 2814750*p**10*r*s**2 - 67612500*p**7*q**2*r*s**2 - 345156250*p**4*q**4*r*s**2 - 283125000*p*q**6*r*s**2 + 51300000*p**8*r**2*s**2 + 734531250*p**5*q**2*r**2*s**2 + 1267187500*p**2*q**4*r**2*s**2 - 384312500*p**6*r**3*s**2 - 3912500000*p**3*q**2*r**3*s**2 - 1822265625*q**4*r**3*s**2 + 1112500000*p**4*r**4*s**2 + 2437500000*p*q**2*r**4*s**2 - 1125000000*p**2*r**5*s**2 - 72578125*p**5*q**3*s**3 - 189296875*p**2*q**5*s**3 + 127265625*p**6*q*r*s**3 + 1415625000*p**3*q**3*r*s**3 + 1229687500*q**5*r*s**3 + 1448437500*p**4*q*r**2*s**3 + 2218750000*p*q**3*r**2*s**3 - 4031250000*p**2*q*r**3*s**3 + 5625000000*q*r**4*s**3 - 132890625*p**7*s**4 - 529296875*p**4*q**2*s**4 - 175781250*p*q**4*s**4 - 401953125*p**5*r*s**4 - 4482421875*p**2*q**2*r*s**4 + 4140625000*p**3*r**2*s**4 - 10498046875*q**2*r**2*s**4 - 7031250000*p*r**3*s**4 + 1220703125*p**3*q*s**5 + 1953125000*q**3*s**5 + 14160156250*p*q*r*s**5 - 1708984375*p**2*s**6 - 3662109375*r*s**6 b[4][0] = -4600*p**6*q**6 - 67850*p**3*q**8 - 248400*q**10 + 38900*p**7*q**4*r + 679575*p**4*q**6*r + 2866500*p*q**8*r - 81900*p**8*q**2*r**2 - 2009750*p**5*q**4*r**2 - 10783750*p**2*q**6*r**2 + 1478750*p**6*q**2*r**3 + 14165625*p**3*q**4*r**3 - 2743750*q**6*r**3 - 5450000*p**4*q**2*r**4 + 12687500*p*q**4*r**4 - 22500000*p**2*q**2*r**5 - 101700*p**8*q**3*s - 1700975*p**5*q**5*s - 7061250*p**2*q**7*s + 423900*p**9*q*r*s + 9292375*p**6*q**3*r*s + 50438750*p**3*q**5*r*s + 20475000*q**7*r*s - 7852500*p**7*q*r**2*s - 87765625*p**4*q**3*r**2*s - 121609375*p*q**5*r**2*s + 47700000*p**5*q*r**3*s + 264687500*p**2*q**3*r**3*s - 65000000*p**3*q*r**4*s + 37500000*q**3*r**4*s - 534600*p**10*s**2 - 10344375*p**7*q**2*s**2 - 54859375*p**4*q**4*s**2 - 40312500*p*q**6*s**2 + 10158750*p**8*r*s**2 + 117778125*p**5*q**2*r*s**2 + 192421875*p**2*q**4*r*s**2 - 70593750*p**6*r**2*s**2 - 685312500*p**3*q**2*r**2*s**2 - 334375000*q**4*r**2*s**2 + 193750000*p**4*r**3*s**2 + 500000000*p*q**2*r**3*s**2 - 187500000*p**2*r**4*s**2 + 8437500*p**6*q*s**3 + 159218750*p**3*q**3*s**3 + 220625000*q**5*s**3 + 353828125*p**4*q*r*s**3 + 412500000*p*q**3*r*s**3 - 1023437500*p**2*q*r**2*s**3 + 937500000*q*r**3*s**3 - 206015625*p**5*s**4 - 701171875*p**2*q**2*s**4 + 998046875*p**3*r*s**4 - 1308593750*q**2*r*s**4 - 1367187500*p*r**2*s**4 + 1708984375*p*q*s**5 - 976562500*s**6 return b @property def o(self): p, q, r, s = self.p, self.q, self.r, self.s o = [0]*6 o[5] = -1600*p**10*q**10 - 23600*p**7*q**12 - 86400*p**4*q**14 + 24800*p**11*q**8*r + 419200*p**8*q**10*r + 1850450*p**5*q**12*r + 896400*p**2*q**14*r - 138800*p**12*q**6*r**2 - 2921900*p**9*q**8*r**2 - 17295200*p**6*q**10*r**2 - 27127750*p**3*q**12*r**2 - 26076600*q**14*r**2 + 325800*p**13*q**4*r**3 + 9993850*p**10*q**6*r**3 + 88010500*p**7*q**8*r**3 + 274047650*p**4*q**10*r**3 + 410171400*p*q**12*r**3 - 259200*p**14*q**2*r**4 - 17147100*p**11*q**4*r**4 - 254289150*p**8*q**6*r**4 - 1318548225*p**5*q**8*r**4 - 2633598475*p**2*q**10*r**4 + 12636000*p**12*q**2*r**5 + 388911000*p**9*q**4*r**5 + 3269704725*p**6*q**6*r**5 + 8791192300*p**3*q**8*r**5 + 93560575*q**10*r**5 - 228361600*p**10*q**2*r**6 - 3951199200*p**7*q**4*r**6 - 16276981100*p**4*q**6*r**6 - 1597227000*p*q**8*r**6 + 1947899200*p**8*q**2*r**7 + 17037648000*p**5*q**4*r**7 + 8919740000*p**2*q**6*r**7 - 7672160000*p**6*q**2*r**8 - 15496000000*p**3*q**4*r**8 + 4224000000*q**6*r**8 + 9968000000*p**4*q**2*r**9 - 8640000000*p*q**4*r**9 + 4800000000*p**2*q**2*r**10 - 55200*p**12*q**7*s - 685600*p**9*q**9*s + 1028250*p**6*q**11*s + 37650000*p**3*q**13*s + 111375000*q**15*s + 583200*p**13*q**5*r*s + 9075600*p**10*q**7*r*s - 883150*p**7*q**9*r*s - 506830750*p**4*q**11*r*s - 1793137500*p*q**13*r*s - 1852200*p**14*q**3*r**2*s - 41435250*p**11*q**5*r**2*s - 80566700*p**8*q**7*r**2*s + 2485673600*p**5*q**9*r**2*s + 11442286125*p**2*q**11*r**2*s + 1555200*p**15*q*r**3*s + 80846100*p**12*q**3*r**3*s + 564906800*p**9*q**5*r**3*s - 4493012400*p**6*q**7*r**3*s - 35492391250*p**3*q**9*r**3*s - 789931875*q**11*r**3*s - 71766000*p**13*q*r**4*s - 1551149200*p**10*q**3*r**4*s - 1773437900*p**7*q**5*r**4*s + 51957593125*p**4*q**7*r**4*s + 14964765625*p*q**9*r**4*s + 1231569600*p**11*q*r**5*s + 12042977600*p**8*q**3*r**5*s - 27151011200*p**5*q**5*r**5*s - 88080610000*p**2*q**7*r**5*s - 9912995200*p**9*q*r**6*s - 29448104000*p**6*q**3*r**6*s + 144954840000*p**3*q**5*r**6*s - 44601300000*q**7*r**6*s + 35453760000*p**7*q*r**7*s - 63264000000*p**4*q**3*r**7*s + 60544000000*p*q**5*r**7*s - 30048000000*p**5*q*r**8*s + 37040000000*p**2*q**3*r**8*s - 60800000000*p**3*q*r**9*s - 48000000000*q**3*r**9*s - 615600*p**14*q**4*s**2 - 10524500*p**11*q**6*s**2 - 33831250*p**8*q**8*s**2 + 222806250*p**5*q**10*s**2 + 1099687500*p**2*q**12*s**2 + 3353400*p**15*q**2*r*s**2 + 74269350*p**12*q**4*r*s**2 + 276445750*p**9*q**6*r*s**2 - 2618600000*p**6*q**8*r*s**2 - 14473243750*p**3*q**10*r*s**2 + 1383750000*q**12*r*s**2 - 2332800*p**16*r**2*s**2 - 132750900*p**13*q**2*r**2*s**2 - 900775150*p**10*q**4*r**2*s**2 + 8249244500*p**7*q**6*r**2*s**2 + 59525796875*p**4*q**8*r**2*s**2 - 40292868750*p*q**10*r**2*s**2 + 128304000*p**14*r**3*s**2 + 3160232100*p**11*q**2*r**3*s**2 + 8329580000*p**8*q**4*r**3*s**2 - 45558458750*p**5*q**6*r**3*s**2 + 297252890625*p**2*q**8*r**3*s**2 - 2769854400*p**12*r**4*s**2 - 37065970000*p**9*q**2*r**4*s**2 - 90812546875*p**6*q**4*r**4*s**2 - 627902000000*p**3*q**6*r**4*s**2 + 181347421875*q**8*r**4*s**2 + 30946932800*p**10*r**5*s**2 + 249954680000*p**7*q**2*r**5*s**2 + 802954812500*p**4*q**4*r**5*s**2 - 80900000000*p*q**6*r**5*s**2 - 192137320000*p**8*r**6*s**2 - 932641600000*p**5*q**2*r**6*s**2 - 943242500000*p**2*q**4*r**6*s**2 + 658412000000*p**6*r**7*s**2 + 1930720000000*p**3*q**2*r**7*s**2 + 593800000000*q**4*r**7*s**2 - 1162800000000*p**4*r**8*s**2 - 280000000000*p*q**2*r**8*s**2 + 840000000000*p**2*r**9*s**2 - 2187000*p**16*q*s**3 - 47418750*p**13*q**3*s**3 - 180618750*p**10*q**5*s**3 + 2231250000*p**7*q**7*s**3 + 17857734375*p**4*q**9*s**3 + 29882812500*p*q**11*s**3 + 24664500*p**14*q*r*s**3 - 853368750*p**11*q**3*r*s**3 - 25939693750*p**8*q**5*r*s**3 - 177541562500*p**5*q**7*r*s**3 - 297978828125*p**2*q**9*r*s**3 - 153468000*p**12*q*r**2*s**3 + 30188125000*p**9*q**3*r**2*s**3 + 344049821875*p**6*q**5*r**2*s**3 + 534026875000*p**3*q**7*r**2*s**3 - 340726484375*q**9*r**2*s**3 - 9056190000*p**10*q*r**3*s**3 - 322314687500*p**7*q**3*r**3*s**3 - 769632109375*p**4*q**5*r**3*s**3 - 83276875000*p*q**7*r**3*s**3 + 164061000000*p**8*q*r**4*s**3 + 1381358750000*p**5*q**3*r**4*s**3 + 3088020000000*p**2*q**5*r**4*s**3 - 1267655000000*p**6*q*r**5*s**3 - 7642630000000*p**3*q**3*r**5*s**3 - 2759877500000*q**5*r**5*s**3 + 4597760000000*p**4*q*r**6*s**3 + 1846200000000*p*q**3*r**6*s**3 - 7006000000000*p**2*q*r**7*s**3 - 1200000000000*q*r**8*s**3 + 18225000*p**15*s**4 + 1328906250*p**12*q**2*s**4 + 24729140625*p**9*q**4*s**4 + 169467187500*p**6*q**6*s**4 + 413281250000*p**3*q**8*s**4 + 223828125000*q**10*s**4 + 710775000*p**13*r*s**4 - 18611015625*p**10*q**2*r*s**4 - 314344375000*p**7*q**4*r*s**4 - 828439843750*p**4*q**6*r*s**4 + 460937500000*p*q**8*r*s**4 - 25674975000*p**11*r**2*s**4 - 52223515625*p**8*q**2*r**2*s**4 - 387160000000*p**5*q**4*r**2*s**4 - 4733680078125*p**2*q**6*r**2*s**4 + 343911875000*p**9*r**3*s**4 + 3328658359375*p**6*q**2*r**3*s**4 + 16532406250000*p**3*q**4*r**3*s**4 + 5980613281250*q**6*r**3*s**4 - 2295497500000*p**7*r**4*s**4 - 14809820312500*p**4*q**2*r**4*s**4 - 6491406250000*p*q**4*r**4*s**4 + 7768470000000*p**5*r**5*s**4 + 34192562500000*p**2*q**2*r**5*s**4 - 11859000000000*p**3*r**6*s**4 + 10530000000000*q**2*r**6*s**4 + 6000000000000*p*r**7*s**4 + 11453906250*p**11*q*s**5 + 149765625000*p**8*q**3*s**5 + 545537109375*p**5*q**5*s**5 + 527343750000*p**2*q**7*s**5 - 371313281250*p**9*q*r*s**5 - 3461455078125*p**6*q**3*r*s**5 - 7920878906250*p**3*q**5*r*s**5 - 4747314453125*q**7*r*s**5 + 2417815625000*p**7*q*r**2*s**5 + 5465576171875*p**4*q**3*r**2*s**5 + 5937128906250*p*q**5*r**2*s**5 - 10661156250000*p**5*q*r**3*s**5 - 63574218750000*p**2*q**3*r**3*s**5 + 24059375000000*p**3*q*r**4*s**5 - 33023437500000*q**3*r**4*s**5 - 43125000000000*p*q*r**5*s**5 + 94394531250*p**10*s**6 + 1097167968750*p**7*q**2*s**6 + 2829833984375*p**4*q**4*s**6 - 1525878906250*p*q**6*s**6 + 2724609375*p**8*r*s**6 + 13998535156250*p**5*q**2*r*s**6 + 57094482421875*p**2*q**4*r*s**6 - 8512509765625*p**6*r**2*s**6 - 37941406250000*p**3*q**2*r**2*s**6 + 33191894531250*q**4*r**2*s**6 + 50534179687500*p**4*r**3*s**6 + 156656250000000*p*q**2*r**3*s**6 - 85023437500000*p**2*r**4*s**6 + 10125000000000*r**5*s**6 - 2717285156250*p**6*q*s**7 - 11352539062500*p**3*q**3*s**7 - 2593994140625*q**5*s**7 - 47154541015625*p**4*q*r*s**7 - 160644531250000*p*q**3*r*s**7 + 142500000000000*p**2*q*r**2*s**7 - 26757812500000*q*r**3*s**7 - 4364013671875*p**5*s**8 - 94604492187500*p**2*q**2*s**8 + 114379882812500*p**3*r*s**8 + 51116943359375*q**2*r*s**8 - 346435546875000*p*r**2*s**8 + 476837158203125*p*q*s**9 - 476837158203125*s**10 o[4] = 1600*p**11*q**8 + 20800*p**8*q**10 + 45100*p**5*q**12 - 151200*p**2*q**14 - 19200*p**12*q**6*r - 293200*p**9*q**8*r - 794600*p**6*q**10*r + 2634675*p**3*q**12*r + 2640600*q**14*r + 75600*p**13*q**4*r**2 + 1529100*p**10*q**6*r**2 + 6233350*p**7*q**8*r**2 - 12013350*p**4*q**10*r**2 - 29069550*p*q**12*r**2 - 97200*p**14*q**2*r**3 - 3562500*p**11*q**4*r**3 - 26984900*p**8*q**6*r**3 - 15900325*p**5*q**8*r**3 + 76267100*p**2*q**10*r**3 + 3272400*p**12*q**2*r**4 + 59486850*p**9*q**4*r**4 + 221270075*p**6*q**6*r**4 + 74065250*p**3*q**8*r**4 - 300564375*q**10*r**4 - 45569400*p**10*q**2*r**5 - 438666000*p**7*q**4*r**5 - 444821250*p**4*q**6*r**5 + 2448256250*p*q**8*r**5 + 290640000*p**8*q**2*r**6 + 855850000*p**5*q**4*r**6 - 5741875000*p**2*q**6*r**6 - 644000000*p**6*q**2*r**7 + 5574000000*p**3*q**4*r**7 + 4643000000*q**6*r**7 - 1696000000*p**4*q**2*r**8 - 12660000000*p*q**4*r**8 + 7200000000*p**2*q**2*r**9 + 43200*p**13*q**5*s + 572000*p**10*q**7*s - 59800*p**7*q**9*s - 24174625*p**4*q**11*s - 74587500*p*q**13*s - 324000*p**14*q**3*r*s - 5531400*p**11*q**5*r*s - 3712100*p**8*q**7*r*s + 293009275*p**5*q**9*r*s + 1115548875*p**2*q**11*r*s + 583200*p**15*q*r**2*s + 18343800*p**12*q**3*r**2*s + 77911100*p**9*q**5*r**2*s - 957488825*p**6*q**7*r**2*s - 5449661250*p**3*q**9*r**2*s + 960120000*q**11*r**2*s - 23684400*p**13*q*r**3*s - 373761900*p**10*q**3*r**3*s - 27944975*p**7*q**5*r**3*s + 10375740625*p**4*q**7*r**3*s - 4649093750*p*q**9*r**3*s + 395816400*p**11*q*r**4*s + 2910968000*p**8*q**3*r**4*s - 9126162500*p**5*q**5*r**4*s - 11696118750*p**2*q**7*r**4*s - 3028640000*p**9*q*r**5*s - 3251550000*p**6*q**3*r**5*s + 47914250000*p**3*q**5*r**5*s - 30255625000*q**7*r**5*s + 9304000000*p**7*q*r**6*s - 42970000000*p**4*q**3*r**6*s + 31475000000*p*q**5*r**6*s + 2176000000*p**5*q*r**7*s + 62100000000*p**2*q**3*r**7*s - 43200000000*p**3*q*r**8*s - 72000000000*q**3*r**8*s + 291600*p**15*q**2*s**2 + 2702700*p**12*q**4*s**2 - 38692250*p**9*q**6*s**2 - 538903125*p**6*q**8*s**2 - 1613112500*p**3*q**10*s**2 + 320625000*q**12*s**2 - 874800*p**16*r*s**2 - 14166900*p**13*q**2*r*s**2 + 193284900*p**10*q**4*r*s**2 + 3688520500*p**7*q**6*r*s**2 + 11613390625*p**4*q**8*r*s**2 - 15609881250*p*q**10*r*s**2 + 44031600*p**14*r**2*s**2 + 482345550*p**11*q**2*r**2*s**2 - 2020881875*p**8*q**4*r**2*s**2 - 7407026250*p**5*q**6*r**2*s**2 + 136175750000*p**2*q**8*r**2*s**2 - 1000884600*p**12*r**3*s**2 - 8888950000*p**9*q**2*r**3*s**2 - 30101703125*p**6*q**4*r**3*s**2 - 319761000000*p**3*q**6*r**3*s**2 + 51519218750*q**8*r**3*s**2 + 12622395000*p**10*r**4*s**2 + 97032450000*p**7*q**2*r**4*s**2 + 469929218750*p**4*q**4*r**4*s**2 + 291342187500*p*q**6*r**4*s**2 - 96382000000*p**8*r**5*s**2 - 598070000000*p**5*q**2*r**5*s**2 - 1165021875000*p**2*q**4*r**5*s**2 + 446500000000*p**6*r**6*s**2 + 1651500000000*p**3*q**2*r**6*s**2 + 789375000000*q**4*r**6*s**2 - 1152000000000*p**4*r**7*s**2 - 600000000000*p*q**2*r**7*s**2 + 1260000000000*p**2*r**8*s**2 - 24786000*p**14*q*s**3 - 660487500*p**11*q**3*s**3 - 5886356250*p**8*q**5*s**3 - 18137187500*p**5*q**7*s**3 - 5120546875*p**2*q**9*s**3 + 827658000*p**12*q*r*s**3 + 13343062500*p**9*q**3*r*s**3 + 39782068750*p**6*q**5*r*s**3 - 111288437500*p**3*q**7*r*s**3 - 15438750000*q**9*r*s**3 - 14540782500*p**10*q*r**2*s**3 - 135889750000*p**7*q**3*r**2*s**3 - 176892578125*p**4*q**5*r**2*s**3 - 934462656250*p*q**7*r**2*s**3 + 171669250000*p**8*q*r**3*s**3 + 1164538125000*p**5*q**3*r**3*s**3 + 3192346406250*p**2*q**5*r**3*s**3 - 1295476250000*p**6*q*r**4*s**3 - 6540712500000*p**3*q**3*r**4*s**3 - 2957828125000*q**5*r**4*s**3 + 5366750000000*p**4*q*r**5*s**3 + 3165000000000*p*q**3*r**5*s**3 - 8862500000000*p**2*q*r**6*s**3 - 1800000000000*q*r**7*s**3 + 236925000*p**13*s**4 + 8895234375*p**10*q**2*s**4 + 106180781250*p**7*q**4*s**4 + 474221875000*p**4*q**6*s**4 + 616210937500*p*q**8*s**4 - 6995868750*p**11*r*s**4 - 184190625000*p**8*q**2*r*s**4 - 1299254453125*p**5*q**4*r*s**4 - 2475458593750*p**2*q**6*r*s**4 + 63049218750*p**9*r**2*s**4 + 1646791484375*p**6*q**2*r**2*s**4 + 9086886718750*p**3*q**4*r**2*s**4 + 4673421875000*q**6*r**2*s**4 - 215665000000*p**7*r**3*s**4 - 7864589843750*p**4*q**2*r**3*s**4 - 5987890625000*p*q**4*r**3*s**4 + 594843750000*p**5*r**4*s**4 + 27791171875000*p**2*q**2*r**4*s**4 - 3881250000000*p**3*r**5*s**4 + 12203125000000*q**2*r**5*s**4 + 10312500000000*p*r**6*s**4 - 34720312500*p**9*q*s**5 - 545126953125*p**6*q**3*s**5 - 2176425781250*p**3*q**5*s**5 - 2792968750000*q**7*s**5 - 1395703125*p**7*q*r*s**5 - 1957568359375*p**4*q**3*r*s**5 + 5122636718750*p*q**5*r*s**5 + 858210937500*p**5*q*r**2*s**5 - 42050097656250*p**2*q**3*r**2*s**5 + 7088281250000*p**3*q*r**3*s**5 - 25974609375000*q**3*r**3*s**5 - 69296875000000*p*q*r**4*s**5 + 384697265625*p**8*s**6 + 6403320312500*p**5*q**2*s**6 + 16742675781250*p**2*q**4*s**6 - 3467080078125*p**6*r*s**6 + 11009765625000*p**3*q**2*r*s**6 + 16451660156250*q**4*r*s**6 + 6979003906250*p**4*r**2*s**6 + 145403320312500*p*q**2*r**2*s**6 + 4076171875000*p**2*r**3*s**6 + 22265625000000*r**4*s**6 - 21915283203125*p**4*q*s**7 - 86608886718750*p*q**3*s**7 - 22785644531250*p**2*q*r*s**7 - 103466796875000*q*r**2*s**7 + 18798828125000*p**3*s**8 + 106048583984375*q**2*s**8 + 17761230468750*p*r*s**8 o[3] = 2800*p**9*q**8 + 55700*p**6*q**10 + 363600*p**3*q**12 + 777600*q**14 - 27200*p**10*q**6*r - 700200*p**7*q**8*r - 5726550*p**4*q**10*r - 15066000*p*q**12*r + 74700*p**11*q**4*r**2 + 2859575*p**8*q**6*r**2 + 31175725*p**5*q**8*r**2 + 103147650*p**2*q**10*r**2 - 40500*p**12*q**2*r**3 - 4274400*p**9*q**4*r**3 - 76065825*p**6*q**6*r**3 - 365623750*p**3*q**8*r**3 - 132264000*q**10*r**3 + 2192400*p**10*q**2*r**4 + 92562500*p**7*q**4*r**4 + 799193875*p**4*q**6*r**4 + 1188193125*p*q**8*r**4 - 41231500*p**8*q**2*r**5 - 914210000*p**5*q**4*r**5 - 3318853125*p**2*q**6*r**5 + 398850000*p**6*q**2*r**6 + 3944000000*p**3*q**4*r**6 + 2211312500*q**6*r**6 - 1817000000*p**4*q**2*r**7 - 6720000000*p*q**4*r**7 + 3900000000*p**2*q**2*r**8 + 75600*p**11*q**5*s + 1823100*p**8*q**7*s + 14534150*p**5*q**9*s + 38265750*p**2*q**11*s - 394200*p**12*q**3*r*s - 11453850*p**9*q**5*r*s - 101213000*p**6*q**7*r*s - 223565625*p**3*q**9*r*s + 415125000*q**11*r*s + 243000*p**13*q*r**2*s + 13654575*p**10*q**3*r**2*s + 163811725*p**7*q**5*r**2*s + 173461250*p**4*q**7*r**2*s - 3008671875*p*q**9*r**2*s - 2016900*p**11*q*r**3*s - 86576250*p**8*q**3*r**3*s - 324146625*p**5*q**5*r**3*s + 3378506250*p**2*q**7*r**3*s - 89211000*p**9*q*r**4*s - 55207500*p**6*q**3*r**4*s + 1493950000*p**3*q**5*r**4*s - 12573609375*q**7*r**4*s + 1140100000*p**7*q*r**5*s + 42500000*p**4*q**3*r**5*s + 21511250000*p*q**5*r**5*s - 4058000000*p**5*q*r**6*s + 6725000000*p**2*q**3*r**6*s - 1400000000*p**3*q*r**7*s - 39000000000*q**3*r**7*s + 510300*p**13*q**2*s**2 + 4814775*p**10*q**4*s**2 - 70265125*p**7*q**6*s**2 - 1016484375*p**4*q**8*s**2 - 3221100000*p*q**10*s**2 - 364500*p**14*r*s**2 + 30314250*p**11*q**2*r*s**2 + 1106765625*p**8*q**4*r*s**2 + 10984203125*p**5*q**6*r*s**2 + 33905812500*p**2*q**8*r*s**2 - 37980900*p**12*r**2*s**2 - 2142905625*p**9*q**2*r**2*s**2 - 26896125000*p**6*q**4*r**2*s**2 - 95551328125*p**3*q**6*r**2*s**2 + 11320312500*q**8*r**2*s**2 + 1743781500*p**10*r**3*s**2 + 35432262500*p**7*q**2*r**3*s**2 + 177855859375*p**4*q**4*r**3*s**2 + 121260546875*p*q**6*r**3*s**2 - 25943162500*p**8*r**4*s**2 - 249165500000*p**5*q**2*r**4*s**2 - 461739453125*p**2*q**4*r**4*s**2 + 177823750000*p**6*r**5*s**2 + 726225000000*p**3*q**2*r**5*s**2 + 404195312500*q**4*r**5*s**2 - 565875000000*p**4*r**6*s**2 - 407500000000*p*q**2*r**6*s**2 + 682500000000*p**2*r**7*s**2 - 59140125*p**12*q*s**3 - 1290515625*p**9*q**3*s**3 - 8785071875*p**6*q**5*s**3 - 15588281250*p**3*q**7*s**3 + 17505000000*q**9*s**3 + 896062500*p**10*q*r*s**3 + 2589750000*p**7*q**3*r*s**3 - 82700156250*p**4*q**5*r*s**3 - 347683593750*p*q**7*r*s**3 + 17022656250*p**8*q*r**2*s**3 + 320923593750*p**5*q**3*r**2*s**3 + 1042116875000*p**2*q**5*r**2*s**3 - 353262812500*p**6*q*r**3*s**3 - 2212664062500*p**3*q**3*r**3*s**3 - 1252408984375*q**5*r**3*s**3 + 1967362500000*p**4*q*r**4*s**3 + 1583343750000*p*q**3*r**4*s**3 - 3560625000000*p**2*q*r**5*s**3 - 975000000000*q*r**6*s**3 + 462459375*p**11*s**4 + 14210859375*p**8*q**2*s**4 + 99521718750*p**5*q**4*s**4 + 114955468750*p**2*q**6*s**4 - 17720859375*p**9*r*s**4 - 100320703125*p**6*q**2*r*s**4 + 1021943359375*p**3*q**4*r*s**4 + 1193203125000*q**6*r*s**4 + 171371250000*p**7*r**2*s**4 - 1113390625000*p**4*q**2*r**2*s**4 - 1211474609375*p*q**4*r**2*s**4 - 274056250000*p**5*r**3*s**4 + 8285166015625*p**2*q**2*r**3*s**4 - 2079375000000*p**3*r**4*s**4 + 5137304687500*q**2*r**4*s**4 + 6187500000000*p*r**5*s**4 - 135675000000*p**7*q*s**5 - 1275244140625*p**4*q**3*s**5 - 28388671875*p*q**5*s**5 + 1015166015625*p**5*q*r*s**5 - 10584423828125*p**2*q**3*r*s**5 + 3559570312500*p**3*q*r**2*s**5 - 6929931640625*q**3*r**2*s**5 - 32304687500000*p*q*r**3*s**5 + 430576171875*p**6*s**6 + 9397949218750*p**3*q**2*s**6 + 575195312500*q**4*s**6 - 4086425781250*p**4*r*s**6 + 42183837890625*p*q**2*r*s**6 + 8156494140625*p**2*r**2*s**6 + 12612304687500*r**3*s**6 - 25513916015625*p**2*q*s**7 - 37017822265625*q*r*s**7 + 18981933593750*p*s**8 o[2] = 1600*p**10*q**6 + 9200*p**7*q**8 - 126000*p**4*q**10 - 777600*p*q**12 - 14400*p**11*q**4*r - 119300*p**8*q**6*r + 1203225*p**5*q**8*r + 9412200*p**2*q**10*r + 32400*p**12*q**2*r**2 + 417950*p**9*q**4*r**2 - 4543725*p**6*q**6*r**2 - 49008125*p**3*q**8*r**2 - 24192000*q**10*r**2 - 292050*p**10*q**2*r**3 + 8760000*p**7*q**4*r**3 + 137506625*p**4*q**6*r**3 + 225438750*p*q**8*r**3 - 4213250*p**8*q**2*r**4 - 173595625*p**5*q**4*r**4 - 653003125*p**2*q**6*r**4 + 82575000*p**6*q**2*r**5 + 838125000*p**3*q**4*r**5 + 578562500*q**6*r**5 - 421500000*p**4*q**2*r**6 - 1796250000*p*q**4*r**6 + 1050000000*p**2*q**2*r**7 + 43200*p**12*q**3*s + 807300*p**9*q**5*s + 5328225*p**6*q**7*s + 16946250*p**3*q**9*s + 29565000*q**11*s - 194400*p**13*q*r*s - 5505300*p**10*q**3*r*s - 49886700*p**7*q**5*r*s - 178821875*p**4*q**7*r*s - 222750000*p*q**9*r*s + 6814800*p**11*q*r**2*s + 120525625*p**8*q**3*r**2*s + 526694500*p**5*q**5*r**2*s + 84065625*p**2*q**7*r**2*s - 123670500*p**9*q*r**3*s - 1106731875*p**6*q**3*r**3*s - 669556250*p**3*q**5*r**3*s - 2869265625*q**7*r**3*s + 1004350000*p**7*q*r**4*s + 3384375000*p**4*q**3*r**4*s + 5665625000*p*q**5*r**4*s - 3411000000*p**5*q*r**5*s - 418750000*p**2*q**3*r**5*s + 1700000000*p**3*q*r**6*s - 10500000000*q**3*r**6*s + 291600*p**14*s**2 + 9829350*p**11*q**2*s**2 + 114151875*p**8*q**4*s**2 + 522169375*p**5*q**6*s**2 + 716906250*p**2*q**8*s**2 - 18625950*p**12*r*s**2 - 387703125*p**9*q**2*r*s**2 - 2056109375*p**6*q**4*r*s**2 - 760203125*p**3*q**6*r*s**2 + 3071250000*q**8*r*s**2 + 512419500*p**10*r**2*s**2 + 5859053125*p**7*q**2*r**2*s**2 + 12154062500*p**4*q**4*r**2*s**2 + 15931640625*p*q**6*r**2*s**2 - 6598393750*p**8*r**3*s**2 - 43549625000*p**5*q**2*r**3*s**2 - 82011328125*p**2*q**4*r**3*s**2 + 43538125000*p**6*r**4*s**2 + 160831250000*p**3*q**2*r**4*s**2 + 99070312500*q**4*r**4*s**2 - 141812500000*p**4*r**5*s**2 - 117500000000*p*q**2*r**5*s**2 + 183750000000*p**2*r**6*s**2 - 154608750*p**10*q*s**3 - 3309468750*p**7*q**3*s**3 - 20834140625*p**4*q**5*s**3 - 34731562500*p*q**7*s**3 + 5970375000*p**8*q*r*s**3 + 68533281250*p**5*q**3*r*s**3 + 142698281250*p**2*q**5*r*s**3 - 74509140625*p**6*q*r**2*s**3 - 389148437500*p**3*q**3*r**2*s**3 - 270937890625*q**5*r**2*s**3 + 366696875000*p**4*q*r**3*s**3 + 400031250000*p*q**3*r**3*s**3 - 735156250000*p**2*q*r**4*s**3 - 262500000000*q*r**5*s**3 + 371250000*p**9*s**4 + 21315000000*p**6*q**2*s**4 + 179515625000*p**3*q**4*s**4 + 238406250000*q**6*s**4 - 9071015625*p**7*r*s**4 - 268945312500*p**4*q**2*r*s**4 - 379785156250*p*q**4*r*s**4 + 140262890625*p**5*r**2*s**4 + 1486259765625*p**2*q**2*r**2*s**4 - 806484375000*p**3*r**3*s**4 + 1066210937500*q**2*r**3*s**4 + 1722656250000*p*r**4*s**4 - 125648437500*p**5*q*s**5 - 1236279296875*p**2*q**3*s**5 + 1267871093750*p**3*q*r*s**5 - 1044677734375*q**3*r*s**5 - 6630859375000*p*q*r**2*s**5 + 160888671875*p**4*s**6 + 6352294921875*p*q**2*s**6 - 708740234375*p**2*r*s**6 + 3901367187500*r**2*s**6 - 8050537109375*q*s**7 o[1] = 2800*p**8*q**6 + 41300*p**5*q**8 + 151200*p**2*q**10 - 25200*p**9*q**4*r - 542600*p**6*q**6*r - 3397875*p**3*q**8*r - 5751000*q**10*r + 56700*p**10*q**2*r**2 + 1972125*p**7*q**4*r**2 + 18624250*p**4*q**6*r**2 + 50253750*p*q**8*r**2 - 1701000*p**8*q**2*r**3 - 32630625*p**5*q**4*r**3 - 139868750*p**2*q**6*r**3 + 18162500*p**6*q**2*r**4 + 177125000*p**3*q**4*r**4 + 121734375*q**6*r**4 - 100500000*p**4*q**2*r**5 - 386250000*p*q**4*r**5 + 225000000*p**2*q**2*r**6 + 75600*p**10*q**3*s + 1708800*p**7*q**5*s + 12836875*p**4*q**7*s + 32062500*p*q**9*s - 340200*p**11*q*r*s - 10185750*p**8*q**3*r*s - 97502750*p**5*q**5*r*s - 301640625*p**2*q**7*r*s + 7168500*p**9*q*r**2*s + 135960625*p**6*q**3*r**2*s + 587471875*p**3*q**5*r**2*s - 384750000*q**7*r**2*s - 29325000*p**7*q*r**3*s - 320625000*p**4*q**3*r**3*s + 523437500*p*q**5*r**3*s - 42000000*p**5*q*r**4*s + 343750000*p**2*q**3*r**4*s + 150000000*p**3*q*r**5*s - 2250000000*q**3*r**5*s + 510300*p**12*s**2 + 12808125*p**9*q**2*s**2 + 107062500*p**6*q**4*s**2 + 270312500*p**3*q**6*s**2 - 168750000*q**8*s**2 - 2551500*p**10*r*s**2 - 5062500*p**7*q**2*r*s**2 + 712343750*p**4*q**4*r*s**2 + 4788281250*p*q**6*r*s**2 - 256837500*p**8*r**2*s**2 - 3574812500*p**5*q**2*r**2*s**2 - 14967968750*p**2*q**4*r**2*s**2 + 4040937500*p**6*r**3*s**2 + 26400000000*p**3*q**2*r**3*s**2 + 17083984375*q**4*r**3*s**2 - 21812500000*p**4*r**4*s**2 - 24375000000*p*q**2*r**4*s**2 + 39375000000*p**2*r**5*s**2 - 127265625*p**5*q**3*s**3 - 680234375*p**2*q**5*s**3 - 2048203125*p**6*q*r*s**3 - 18794531250*p**3*q**3*r*s**3 - 25050000000*q**5*r*s**3 + 26621875000*p**4*q*r**2*s**3 + 37007812500*p*q**3*r**2*s**3 - 105468750000*p**2*q*r**3*s**3 - 56250000000*q*r**4*s**3 + 1124296875*p**7*s**4 + 9251953125*p**4*q**2*s**4 - 8007812500*p*q**4*s**4 - 4004296875*p**5*r*s**4 + 179931640625*p**2*q**2*r*s**4 - 75703125000*p**3*r**2*s**4 + 133447265625*q**2*r**2*s**4 + 363281250000*p*r**3*s**4 - 91552734375*p**3*q*s**5 - 19531250000*q**3*s**5 - 751953125000*p*q*r*s**5 + 157958984375*p**2*s**6 + 748291015625*r*s**6 o[0] = -14400*p**6*q**6 - 212400*p**3*q**8 - 777600*q**10 + 92100*p**7*q**4*r + 1689675*p**4*q**6*r + 7371000*p*q**8*r - 122850*p**8*q**2*r**2 - 3735250*p**5*q**4*r**2 - 22432500*p**2*q**6*r**2 + 2298750*p**6*q**2*r**3 + 29390625*p**3*q**4*r**3 + 18000000*q**6*r**3 - 17750000*p**4*q**2*r**4 - 62812500*p*q**4*r**4 + 37500000*p**2*q**2*r**5 - 51300*p**8*q**3*s - 768025*p**5*q**5*s - 2801250*p**2*q**7*s - 275400*p**9*q*r*s - 5479875*p**6*q**3*r*s - 35538750*p**3*q**5*r*s - 68850000*q**7*r*s + 12757500*p**7*q*r**2*s + 133640625*p**4*q**3*r**2*s + 222609375*p*q**5*r**2*s - 108500000*p**5*q*r**3*s - 290312500*p**2*q**3*r**3*s + 275000000*p**3*q*r**4*s - 375000000*q**3*r**4*s + 1931850*p**10*s**2 + 40213125*p**7*q**2*s**2 + 253921875*p**4*q**4*s**2 + 464062500*p*q**6*s**2 - 71077500*p**8*r*s**2 - 818746875*p**5*q**2*r*s**2 - 1882265625*p**2*q**4*r*s**2 + 826031250*p**6*r**2*s**2 + 4369687500*p**3*q**2*r**2*s**2 + 3107812500*q**4*r**2*s**2 - 3943750000*p**4*r**3*s**2 - 5000000000*p*q**2*r**3*s**2 + 6562500000*p**2*r**4*s**2 - 295312500*p**6*q*s**3 - 2938906250*p**3*q**3*s**3 - 4848750000*q**5*s**3 + 3791484375*p**4*q*r*s**3 + 7556250000*p*q**3*r*s**3 - 11960937500*p**2*q*r**2*s**3 - 9375000000*q*r**3*s**3 + 1668515625*p**5*s**4 + 20447265625*p**2*q**2*s**4 - 21955078125*p**3*r*s**4 + 18984375000*q**2*r*s**4 + 67382812500*p*r**2*s**4 - 120849609375*p*q*s**5 + 157226562500*s**6 return o @property def a(self): p, q, r, s = self.p, self.q, self.r, self.s a = [0]*6 a[5] = -100*p**7*q**7 - 2175*p**4*q**9 - 10500*p*q**11 + 1100*p**8*q**5*r + 27975*p**5*q**7*r + 152950*p**2*q**9*r - 4125*p**9*q**3*r**2 - 128875*p**6*q**5*r**2 - 830525*p**3*q**7*r**2 + 59450*q**9*r**2 + 5400*p**10*q*r**3 + 243800*p**7*q**3*r**3 + 2082650*p**4*q**5*r**3 - 333925*p*q**7*r**3 - 139200*p**8*q*r**4 - 2406000*p**5*q**3*r**4 - 122600*p**2*q**5*r**4 + 1254400*p**6*q*r**5 + 3776000*p**3*q**3*r**5 + 1832000*q**5*r**5 - 4736000*p**4*q*r**6 - 6720000*p*q**3*r**6 + 6400000*p**2*q*r**7 - 900*p**9*q**4*s - 37400*p**6*q**6*s - 281625*p**3*q**8*s - 435000*q**10*s + 6750*p**10*q**2*r*s + 322300*p**7*q**4*r*s + 2718575*p**4*q**6*r*s + 4214250*p*q**8*r*s - 16200*p**11*r**2*s - 859275*p**8*q**2*r**2*s - 8925475*p**5*q**4*r**2*s - 14427875*p**2*q**6*r**2*s + 453600*p**9*r**3*s + 10038400*p**6*q**2*r**3*s + 17397500*p**3*q**4*r**3*s - 11333125*q**6*r**3*s - 4451200*p**7*r**4*s - 15850000*p**4*q**2*r**4*s + 34000000*p*q**4*r**4*s + 17984000*p**5*r**5*s - 10000000*p**2*q**2*r**5*s - 25600000*p**3*r**6*s - 8000000*q**2*r**6*s + 6075*p**11*q*s**2 - 83250*p**8*q**3*s**2 - 1282500*p**5*q**5*s**2 - 2862500*p**2*q**7*s**2 + 724275*p**9*q*r*s**2 + 9807250*p**6*q**3*r*s**2 + 28374375*p**3*q**5*r*s**2 + 22212500*q**7*r*s**2 - 8982000*p**7*q*r**2*s**2 - 39600000*p**4*q**3*r**2*s**2 - 61746875*p*q**5*r**2*s**2 - 1010000*p**5*q*r**3*s**2 - 1000000*p**2*q**3*r**3*s**2 + 78000000*p**3*q*r**4*s**2 + 30000000*q**3*r**4*s**2 + 80000000*p*q*r**5*s**2 - 759375*p**10*s**3 - 9787500*p**7*q**2*s**3 - 39062500*p**4*q**4*s**3 - 52343750*p*q**6*s**3 + 12301875*p**8*r*s**3 + 98175000*p**5*q**2*r*s**3 + 225078125*p**2*q**4*r*s**3 - 54900000*p**6*r**2*s**3 - 310000000*p**3*q**2*r**2*s**3 - 7890625*q**4*r**2*s**3 + 51250000*p**4*r**3*s**3 - 420000000*p*q**2*r**3*s**3 + 110000000*p**2*r**4*s**3 - 200000000*r**5*s**3 + 2109375*p**6*q*s**4 - 21093750*p**3*q**3*s**4 - 89843750*q**5*s**4 + 182343750*p**4*q*r*s**4 + 733203125*p*q**3*r*s**4 - 196875000*p**2*q*r**2*s**4 + 1125000000*q*r**3*s**4 - 158203125*p**5*s**5 - 566406250*p**2*q**2*s**5 + 101562500*p**3*r*s**5 - 1669921875*q**2*r*s**5 + 1250000000*p*r**2*s**5 - 1220703125*p*q*s**6 + 6103515625*s**7 a[4] = 1000*p**5*q**7 + 7250*p**2*q**9 - 10800*p**6*q**5*r - 96900*p**3*q**7*r - 52500*q**9*r + 37400*p**7*q**3*r**2 + 470850*p**4*q**5*r**2 + 640600*p*q**7*r**2 - 39600*p**8*q*r**3 - 983600*p**5*q**3*r**3 - 2848100*p**2*q**5*r**3 + 814400*p**6*q*r**4 + 6076000*p**3*q**3*r**4 + 2308000*q**5*r**4 - 5024000*p**4*q*r**5 - 9680000*p*q**3*r**5 + 9600000*p**2*q*r**6 + 13800*p**7*q**4*s + 94650*p**4*q**6*s - 26500*p*q**8*s - 86400*p**8*q**2*r*s - 816500*p**5*q**4*r*s - 257500*p**2*q**6*r*s + 91800*p**9*r**2*s + 1853700*p**6*q**2*r**2*s + 630000*p**3*q**4*r**2*s - 8971250*q**6*r**2*s - 2071200*p**7*r**3*s - 7240000*p**4*q**2*r**3*s + 29375000*p*q**4*r**3*s + 14416000*p**5*r**4*s - 5200000*p**2*q**2*r**4*s - 30400000*p**3*r**5*s - 12000000*q**2*r**5*s + 64800*p**9*q*s**2 + 567000*p**6*q**3*s**2 + 1655000*p**3*q**5*s**2 + 6987500*q**7*s**2 + 337500*p**7*q*r*s**2 + 8462500*p**4*q**3*r*s**2 - 5812500*p*q**5*r*s**2 - 24930000*p**5*q*r**2*s**2 - 69125000*p**2*q**3*r**2*s**2 + 103500000*p**3*q*r**3*s**2 + 30000000*q**3*r**3*s**2 + 90000000*p*q*r**4*s**2 - 708750*p**8*s**3 - 5400000*p**5*q**2*s**3 + 8906250*p**2*q**4*s**3 + 18562500*p**6*r*s**3 - 625000*p**3*q**2*r*s**3 + 29687500*q**4*r*s**3 - 75000000*p**4*r**2*s**3 - 416250000*p*q**2*r**2*s**3 + 60000000*p**2*r**3*s**3 - 300000000*r**4*s**3 + 71718750*p**4*q*s**4 + 189062500*p*q**3*s**4 + 210937500*p**2*q*r*s**4 + 1187500000*q*r**2*s**4 - 187500000*p**3*s**5 - 800781250*q**2*s**5 - 390625000*p*r*s**5 a[3] = -500*p**6*q**5 - 6350*p**3*q**7 - 19800*q**9 + 3750*p**7*q**3*r + 65100*p**4*q**5*r + 264950*p*q**7*r - 6750*p**8*q*r**2 - 209050*p**5*q**3*r**2 - 1217250*p**2*q**5*r**2 + 219000*p**6*q*r**3 + 2510000*p**3*q**3*r**3 + 1098500*q**5*r**3 - 2068000*p**4*q*r**4 - 5060000*p*q**3*r**4 + 5200000*p**2*q*r**5 - 6750*p**8*q**2*s - 96350*p**5*q**4*s - 346000*p**2*q**6*s + 20250*p**9*r*s + 459900*p**6*q**2*r*s + 1828750*p**3*q**4*r*s - 2930000*q**6*r*s - 594000*p**7*r**2*s - 4301250*p**4*q**2*r**2*s + 10906250*p*q**4*r**2*s + 5252000*p**5*r**3*s - 1450000*p**2*q**2*r**3*s - 12800000*p**3*r**4*s - 6500000*q**2*r**4*s + 74250*p**7*q*s**2 + 1418750*p**4*q**3*s**2 + 5956250*p*q**5*s**2 - 4297500*p**5*q*r*s**2 - 29906250*p**2*q**3*r*s**2 + 31500000*p**3*q*r**2*s**2 + 12500000*q**3*r**2*s**2 + 35000000*p*q*r**3*s**2 + 1350000*p**6*s**3 + 6093750*p**3*q**2*s**3 + 17500000*q**4*s**3 - 7031250*p**4*r*s**3 - 127812500*p*q**2*r*s**3 + 18750000*p**2*r**2*s**3 - 162500000*r**3*s**3 + 107812500*p**2*q*s**4 + 460937500*q*r*s**4 - 214843750*p*s**5 a[2] = 1950*p**4*q**5 + 14100*p*q**7 - 14350*p**5*q**3*r - 125600*p**2*q**5*r + 27900*p**6*q*r**2 + 402250*p**3*q**3*r**2 + 288250*q**5*r**2 - 436000*p**4*q*r**3 - 1345000*p*q**3*r**3 + 1400000*p**2*q*r**4 + 9450*p**6*q**2*s - 1250*p**3*q**4*s - 465000*q**6*s - 49950*p**7*r*s - 302500*p**4*q**2*r*s + 1718750*p*q**4*r*s + 834000*p**5*r**2*s + 437500*p**2*q**2*r**2*s - 3100000*p**3*r**3*s - 1750000*q**2*r**3*s - 292500*p**5*q*s**2 - 1937500*p**2*q**3*s**2 + 3343750*p**3*q*r*s**2 + 1875000*q**3*r*s**2 + 8125000*p*q*r**2*s**2 - 1406250*p**4*s**3 - 12343750*p*q**2*s**3 + 5312500*p**2*r*s**3 - 43750000*r**2*s**3 + 74218750*q*s**4 a[1] = -300*p**5*q**3 - 2150*p**2*q**5 + 1350*p**6*q*r + 21500*p**3*q**3*r + 61500*q**5*r - 42000*p**4*q*r**2 - 290000*p*q**3*r**2 + 300000*p**2*q*r**3 - 4050*p**7*s - 45000*p**4*q**2*s - 125000*p*q**4*s + 108000*p**5*r*s + 643750*p**2*q**2*r*s - 700000*p**3*r**2*s - 375000*q**2*r**2*s - 93750*p**3*q*s**2 - 312500*q**3*s**2 + 1875000*p*q*r*s**2 - 1406250*p**2*s**3 - 9375000*r*s**3 a[0] = 1250*p**3*q**3 + 9000*q**5 - 4500*p**4*q*r - 46250*p*q**3*r + 50000*p**2*q*r**2 + 6750*p**5*s + 43750*p**2*q**2*s - 75000*p**3*r*s - 62500*q**2*r*s + 156250*p*q*s**2 - 1562500*s**3 return a @property def c(self): p, q, r, s = self.p, self.q, self.r, self.s c = [0]*6 c[5] = -40*p**5*q**11 - 270*p**2*q**13 + 700*p**6*q**9*r + 5165*p**3*q**11*r + 540*q**13*r - 4230*p**7*q**7*r**2 - 31845*p**4*q**9*r**2 + 20880*p*q**11*r**2 + 9645*p**8*q**5*r**3 + 57615*p**5*q**7*r**3 - 358255*p**2*q**9*r**3 - 1880*p**9*q**3*r**4 + 114020*p**6*q**5*r**4 + 2012190*p**3*q**7*r**4 - 26855*q**9*r**4 - 14400*p**10*q*r**5 - 470400*p**7*q**3*r**5 - 5088640*p**4*q**5*r**5 + 920*p*q**7*r**5 + 332800*p**8*q*r**6 + 5797120*p**5*q**3*r**6 + 1608000*p**2*q**5*r**6 - 2611200*p**6*q*r**7 - 7424000*p**3*q**3*r**7 - 2323200*q**5*r**7 + 8601600*p**4*q*r**8 + 9472000*p*q**3*r**8 - 10240000*p**2*q*r**9 - 3060*p**7*q**8*s - 39085*p**4*q**10*s - 132300*p*q**12*s + 36580*p**8*q**6*r*s + 520185*p**5*q**8*r*s + 1969860*p**2*q**10*r*s - 144045*p**9*q**4*r**2*s - 2438425*p**6*q**6*r**2*s - 10809475*p**3*q**8*r**2*s + 518850*q**10*r**2*s + 182520*p**10*q**2*r**3*s + 4533930*p**7*q**4*r**3*s + 26196770*p**4*q**6*r**3*s - 4542325*p*q**8*r**3*s + 21600*p**11*r**4*s - 2208080*p**8*q**2*r**4*s - 24787960*p**5*q**4*r**4*s + 10813900*p**2*q**6*r**4*s - 499200*p**9*r**5*s + 3827840*p**6*q**2*r**5*s + 9596000*p**3*q**4*r**5*s + 22662000*q**6*r**5*s + 3916800*p**7*r**6*s - 29952000*p**4*q**2*r**6*s - 90800000*p*q**4*r**6*s - 12902400*p**5*r**7*s + 87040000*p**2*q**2*r**7*s + 15360000*p**3*r**8*s + 12800000*q**2*r**8*s - 38070*p**9*q**5*s**2 - 566700*p**6*q**7*s**2 - 2574375*p**3*q**9*s**2 - 1822500*q**11*s**2 + 292815*p**10*q**3*r*s**2 + 5170280*p**7*q**5*r*s**2 + 27918125*p**4*q**7*r*s**2 + 21997500*p*q**9*r*s**2 - 573480*p**11*q*r**2*s**2 - 14566350*p**8*q**3*r**2*s**2 - 104851575*p**5*q**5*r**2*s**2 - 96448750*p**2*q**7*r**2*s**2 + 11001240*p**9*q*r**3*s**2 + 147798600*p**6*q**3*r**3*s**2 + 158632750*p**3*q**5*r**3*s**2 - 78222500*q**7*r**3*s**2 - 62819200*p**7*q*r**4*s**2 - 136160000*p**4*q**3*r**4*s**2 + 317555000*p*q**5*r**4*s**2 + 160224000*p**5*q*r**5*s**2 - 267600000*p**2*q**3*r**5*s**2 - 153600000*p**3*q*r**6*s**2 - 120000000*q**3*r**6*s**2 - 32000000*p*q*r**7*s**2 - 127575*p**11*q**2*s**3 - 2148750*p**8*q**4*s**3 - 13652500*p**5*q**6*s**3 - 19531250*p**2*q**8*s**3 + 495720*p**12*r*s**3 + 11856375*p**9*q**2*r*s**3 + 107807500*p**6*q**4*r*s**3 + 222334375*p**3*q**6*r*s**3 + 105062500*q**8*r*s**3 - 11566800*p**10*r**2*s**3 - 216787500*p**7*q**2*r**2*s**3 - 633437500*p**4*q**4*r**2*s**3 - 504484375*p*q**6*r**2*s**3 + 90918000*p**8*r**3*s**3 + 567080000*p**5*q**2*r**3*s**3 + 692937500*p**2*q**4*r**3*s**3 - 326640000*p**6*r**4*s**3 - 339000000*p**3*q**2*r**4*s**3 + 369250000*q**4*r**4*s**3 + 560000000*p**4*r**5*s**3 + 508000000*p*q**2*r**5*s**3 - 480000000*p**2*r**6*s**3 + 320000000*r**7*s**3 - 455625*p**10*q*s**4 - 27562500*p**7*q**3*s**4 - 120593750*p**4*q**5*s**4 - 60312500*p*q**7*s**4 + 110615625*p**8*q*r*s**4 + 662984375*p**5*q**3*r*s**4 + 528515625*p**2*q**5*r*s**4 - 541687500*p**6*q*r**2*s**4 - 1262343750*p**3*q**3*r**2*s**4 - 466406250*q**5*r**2*s**4 + 633000000*p**4*q*r**3*s**4 - 1264375000*p*q**3*r**3*s**4 + 1085000000*p**2*q*r**4*s**4 - 2700000000*q*r**5*s**4 - 68343750*p**9*s**5 - 478828125*p**6*q**2*s**5 - 355468750*p**3*q**4*s**5 - 11718750*q**6*s**5 + 718031250*p**7*r*s**5 + 1658593750*p**4*q**2*r*s**5 + 2212890625*p*q**4*r*s**5 - 2855625000*p**5*r**2*s**5 - 4273437500*p**2*q**2*r**2*s**5 + 4537500000*p**3*r**3*s**5 + 8031250000*q**2*r**3*s**5 - 1750000000*p*r**4*s**5 + 1353515625*p**5*q*s**6 + 1562500000*p**2*q**3*s**6 - 3964843750*p**3*q*r*s**6 - 7226562500*q**3*r*s**6 + 1953125000*p*q*r**2*s**6 - 1757812500*p**4*s**7 - 3173828125*p*q**2*s**7 + 6445312500*p**2*r*s**7 - 3906250000*r**2*s**7 + 6103515625*q*s**8 c[4] = 40*p**6*q**9 + 110*p**3*q**11 - 1080*q**13 - 560*p**7*q**7*r - 1780*p**4*q**9*r + 17370*p*q**11*r + 2850*p**8*q**5*r**2 + 10520*p**5*q**7*r**2 - 115910*p**2*q**9*r**2 - 6090*p**9*q**3*r**3 - 25330*p**6*q**5*r**3 + 448740*p**3*q**7*r**3 + 128230*q**9*r**3 + 4320*p**10*q*r**4 + 16960*p**7*q**3*r**4 - 1143600*p**4*q**5*r**4 - 1410310*p*q**7*r**4 + 3840*p**8*q*r**5 + 1744480*p**5*q**3*r**5 + 5619520*p**2*q**5*r**5 - 1198080*p**6*q*r**6 - 10579200*p**3*q**3*r**6 - 2940800*q**5*r**6 + 8294400*p**4*q*r**7 + 13568000*p*q**3*r**7 - 15360000*p**2*q*r**8 + 840*p**8*q**6*s + 7580*p**5*q**8*s + 24420*p**2*q**10*s - 8100*p**9*q**4*r*s - 94100*p**6*q**6*r*s - 473000*p**3*q**8*r*s - 473400*q**10*r*s + 22680*p**10*q**2*r**2*s + 374370*p**7*q**4*r**2*s + 2888020*p**4*q**6*r**2*s + 5561050*p*q**8*r**2*s - 12960*p**11*r**3*s - 485820*p**8*q**2*r**3*s - 6723440*p**5*q**4*r**3*s - 23561400*p**2*q**6*r**3*s + 190080*p**9*r**4*s + 5894880*p**6*q**2*r**4*s + 50882000*p**3*q**4*r**4*s + 22411500*q**6*r**4*s - 258560*p**7*r**5*s - 46248000*p**4*q**2*r**5*s - 103800000*p*q**4*r**5*s - 3737600*p**5*r**6*s + 119680000*p**2*q**2*r**6*s + 10240000*p**3*r**7*s + 19200000*q**2*r**7*s + 7290*p**10*q**3*s**2 + 117360*p**7*q**5*s**2 + 691250*p**4*q**7*s**2 - 198750*p*q**9*s**2 - 36450*p**11*q*r*s**2 - 854550*p**8*q**3*r*s**2 - 7340700*p**5*q**5*r*s**2 - 2028750*p**2*q**7*r*s**2 + 995490*p**9*q*r**2*s**2 + 18896600*p**6*q**3*r**2*s**2 + 5026500*p**3*q**5*r**2*s**2 - 52272500*q**7*r**2*s**2 - 16636800*p**7*q*r**3*s**2 - 43200000*p**4*q**3*r**3*s**2 + 223426250*p*q**5*r**3*s**2 + 112068000*p**5*q*r**4*s**2 - 177000000*p**2*q**3*r**4*s**2 - 244000000*p**3*q*r**5*s**2 - 156000000*q**3*r**5*s**2 + 43740*p**12*s**3 + 1032750*p**9*q**2*s**3 + 8602500*p**6*q**4*s**3 + 15606250*p**3*q**6*s**3 + 39625000*q**8*s**3 - 1603800*p**10*r*s**3 - 26932500*p**7*q**2*r*s**3 - 19562500*p**4*q**4*r*s**3 - 152000000*p*q**6*r*s**3 + 25555500*p**8*r**2*s**3 + 16230000*p**5*q**2*r**2*s**3 + 42187500*p**2*q**4*r**2*s**3 - 165660000*p**6*r**3*s**3 + 373500000*p**3*q**2*r**3*s**3 + 332937500*q**4*r**3*s**3 + 465000000*p**4*r**4*s**3 + 586000000*p*q**2*r**4*s**3 - 592000000*p**2*r**5*s**3 + 480000000*r**6*s**3 - 1518750*p**8*q*s**4 - 62531250*p**5*q**3*s**4 + 7656250*p**2*q**5*s**4 + 184781250*p**6*q*r*s**4 - 15781250*p**3*q**3*r*s**4 - 135156250*q**5*r*s**4 - 1148250000*p**4*q*r**2*s**4 - 2121406250*p*q**3*r**2*s**4 + 1990000000*p**2*q*r**3*s**4 - 3150000000*q*r**4*s**4 - 2531250*p**7*s**5 + 660937500*p**4*q**2*s**5 + 1339843750*p*q**4*s**5 - 33750000*p**5*r*s**5 - 679687500*p**2*q**2*r*s**5 + 6250000*p**3*r**2*s**5 + 6195312500*q**2*r**2*s**5 + 1125000000*p*r**3*s**5 - 996093750*p**3*q*s**6 - 3125000000*q**3*s**6 - 3222656250*p*q*r*s**6 + 1171875000*p**2*s**7 + 976562500*r*s**7 c[3] = 80*p**4*q**9 + 540*p*q**11 - 600*p**5*q**7*r - 4770*p**2*q**9*r + 1230*p**6*q**5*r**2 + 20900*p**3*q**7*r**2 + 47250*q**9*r**2 - 710*p**7*q**3*r**3 - 84950*p**4*q**5*r**3 - 526310*p*q**7*r**3 + 720*p**8*q*r**4 + 216280*p**5*q**3*r**4 + 2068020*p**2*q**5*r**4 - 198080*p**6*q*r**5 - 3703200*p**3*q**3*r**5 - 1423600*q**5*r**5 + 2860800*p**4*q*r**6 + 7056000*p*q**3*r**6 - 8320000*p**2*q*r**7 - 2720*p**6*q**6*s - 46350*p**3*q**8*s - 178200*q**10*s + 25740*p**7*q**4*r*s + 489490*p**4*q**6*r*s + 2152350*p*q**8*r*s - 61560*p**8*q**2*r**2*s - 1568150*p**5*q**4*r**2*s - 9060500*p**2*q**6*r**2*s + 24840*p**9*r**3*s + 1692380*p**6*q**2*r**3*s + 18098250*p**3*q**4*r**3*s + 9387750*q**6*r**3*s - 382560*p**7*r**4*s - 16818000*p**4*q**2*r**4*s - 49325000*p*q**4*r**4*s + 1212800*p**5*r**5*s + 64840000*p**2*q**2*r**5*s - 320000*p**3*r**6*s + 10400000*q**2*r**6*s - 36450*p**8*q**3*s**2 - 588350*p**5*q**5*s**2 - 2156250*p**2*q**7*s**2 + 123930*p**9*q*r*s**2 + 2879700*p**6*q**3*r*s**2 + 12548000*p**3*q**5*r*s**2 - 14445000*q**7*r*s**2 - 3233250*p**7*q*r**2*s**2 - 28485000*p**4*q**3*r**2*s**2 + 72231250*p*q**5*r**2*s**2 + 32093000*p**5*q*r**3*s**2 - 61275000*p**2*q**3*r**3*s**2 - 107500000*p**3*q*r**4*s**2 - 78500000*q**3*r**4*s**2 + 22000000*p*q*r**5*s**2 - 72900*p**10*s**3 - 1215000*p**7*q**2*s**3 - 2937500*p**4*q**4*s**3 + 9156250*p*q**6*s**3 + 2612250*p**8*r*s**3 + 16560000*p**5*q**2*r*s**3 - 75468750*p**2*q**4*r*s**3 - 32737500*p**6*r**2*s**3 + 169062500*p**3*q**2*r**2*s**3 + 121718750*q**4*r**2*s**3 + 160250000*p**4*r**3*s**3 + 219750000*p*q**2*r**3*s**3 - 317000000*p**2*r**4*s**3 + 260000000*r**5*s**3 + 2531250*p**6*q*s**4 + 22500000*p**3*q**3*s**4 + 39843750*q**5*s**4 - 266343750*p**4*q*r*s**4 - 776406250*p*q**3*r*s**4 + 789062500*p**2*q*r**2*s**4 - 1368750000*q*r**3*s**4 + 67500000*p**5*s**5 + 441406250*p**2*q**2*s**5 - 311718750*p**3*r*s**5 + 1785156250*q**2*r*s**5 + 546875000*p*r**2*s**5 - 1269531250*p*q*s**6 + 488281250*s**7 c[2] = 120*p**5*q**7 + 810*p**2*q**9 - 1280*p**6*q**5*r - 9160*p**3*q**7*r + 3780*q**9*r + 4530*p**7*q**3*r**2 + 36640*p**4*q**5*r**2 - 45270*p*q**7*r**2 - 5400*p**8*q*r**3 - 60920*p**5*q**3*r**3 + 200050*p**2*q**5*r**3 + 31200*p**6*q*r**4 - 476000*p**3*q**3*r**4 - 378200*q**5*r**4 + 521600*p**4*q*r**5 + 1872000*p*q**3*r**5 - 2240000*p**2*q*r**6 + 1440*p**7*q**4*s + 15310*p**4*q**6*s + 59400*p*q**8*s - 9180*p**8*q**2*r*s - 115240*p**5*q**4*r*s - 589650*p**2*q**6*r*s + 16200*p**9*r**2*s + 316710*p**6*q**2*r**2*s + 2547750*p**3*q**4*r**2*s + 2178000*q**6*r**2*s - 259200*p**7*r**3*s - 4123000*p**4*q**2*r**3*s - 11700000*p*q**4*r**3*s + 937600*p**5*r**4*s + 16340000*p**2*q**2*r**4*s - 640000*p**3*r**5*s + 2800000*q**2*r**5*s - 2430*p**9*q*s**2 - 54450*p**6*q**3*s**2 - 285500*p**3*q**5*s**2 - 2767500*q**7*s**2 + 43200*p**7*q*r*s**2 - 916250*p**4*q**3*r*s**2 + 14482500*p*q**5*r*s**2 + 4806000*p**5*q*r**2*s**2 - 13212500*p**2*q**3*r**2*s**2 - 25400000*p**3*q*r**3*s**2 - 18750000*q**3*r**3*s**2 + 8000000*p*q*r**4*s**2 + 121500*p**8*s**3 + 2058750*p**5*q**2*s**3 - 6656250*p**2*q**4*s**3 - 6716250*p**6*r*s**3 + 24125000*p**3*q**2*r*s**3 + 23875000*q**4*r*s**3 + 43125000*p**4*r**2*s**3 + 45750000*p*q**2*r**2*s**3 - 87500000*p**2*r**3*s**3 + 70000000*r**4*s**3 - 44437500*p**4*q*s**4 - 107968750*p*q**3*s**4 + 159531250*p**2*q*r*s**4 - 284375000*q*r**2*s**4 + 7031250*p**3*s**5 + 265625000*q**2*s**5 + 31250000*p*r*s**5 c[1] = 160*p**3*q**7 + 1080*q**9 - 1080*p**4*q**5*r - 8730*p*q**7*r + 1510*p**5*q**3*r**2 + 20420*p**2*q**5*r**2 + 720*p**6*q*r**3 - 23200*p**3*q**3*r**3 - 79900*q**5*r**3 + 35200*p**4*q*r**4 + 404000*p*q**3*r**4 - 480000*p**2*q*r**5 + 960*p**5*q**4*s + 2850*p**2*q**6*s + 540*p**6*q**2*r*s + 63500*p**3*q**4*r*s + 319500*q**6*r*s - 7560*p**7*r**2*s - 253500*p**4*q**2*r**2*s - 1806250*p*q**4*r**2*s + 91200*p**5*r**3*s + 2600000*p**2*q**2*r**3*s - 80000*p**3*r**4*s + 600000*q**2*r**4*s - 4050*p**7*q*s**2 - 120000*p**4*q**3*s**2 - 273750*p*q**5*s**2 + 425250*p**5*q*r*s**2 + 2325000*p**2*q**3*r*s**2 - 5400000*p**3*q*r**2*s**2 - 2875000*q**3*r**2*s**2 + 1500000*p*q*r**3*s**2 - 303750*p**6*s**3 - 843750*p**3*q**2*s**3 - 812500*q**4*s**3 + 5062500*p**4*r*s**3 + 13312500*p*q**2*r*s**3 - 14500000*p**2*r**2*s**3 + 15000000*r**3*s**3 - 3750000*p**2*q*s**4 - 35937500*q*r*s**4 + 11718750*p*s**5 c[0] = 80*p**4*q**5 + 540*p*q**7 - 600*p**5*q**3*r - 4770*p**2*q**5*r + 1080*p**6*q*r**2 + 11200*p**3*q**3*r**2 - 12150*q**5*r**2 - 4800*p**4*q*r**3 + 64000*p*q**3*r**3 - 80000*p**2*q*r**4 + 1080*p**6*q**2*s + 13250*p**3*q**4*s + 54000*q**6*s - 3240*p**7*r*s - 56250*p**4*q**2*r*s - 337500*p*q**4*r*s + 43200*p**5*r**2*s + 560000*p**2*q**2*r**2*s - 80000*p**3*r**3*s + 100000*q**2*r**3*s + 6750*p**5*q*s**2 + 225000*p**2*q**3*s**2 - 900000*p**3*q*r*s**2 - 562500*q**3*r*s**2 + 500000*p*q*r**2*s**2 + 843750*p**4*s**3 + 1937500*p*q**2*s**3 - 3000000*p**2*r*s**3 + 2500000*r**2*s**3 - 5468750*q*s**4 return c @property def F(self): p, q, r, s = self.p, self.q, self.r, self.s F = 4*p**6*q**6 + 59*p**3*q**8 + 216*q**10 - 36*p**7*q**4*r - 623*p**4*q**6*r - 2610*p*q**8*r + 81*p**8*q**2*r**2 + 2015*p**5*q**4*r**2 + 10825*p**2*q**6*r**2 - 1800*p**6*q**2*r**3 - 17500*p**3*q**4*r**3 + 625*q**6*r**3 + 10000*p**4*q**2*r**4 + 108*p**8*q**3*s + 1584*p**5*q**5*s + 5700*p**2*q**7*s - 486*p**9*q*r*s - 9720*p**6*q**3*r*s - 45050*p**3*q**5*r*s - 9000*q**7*r*s + 10800*p**7*q*r**2*s + 92500*p**4*q**3*r**2*s + 32500*p*q**5*r**2*s - 60000*p**5*q*r**3*s - 50000*p**2*q**3*r**3*s + 729*p**10*s**2 + 12150*p**7*q**2*s**2 + 60000*p**4*q**4*s**2 + 93750*p*q**6*s**2 - 18225*p**8*r*s**2 - 175500*p**5*q**2*r*s**2 - 478125*p**2*q**4*r*s**2 + 135000*p**6*r**2*s**2 + 850000*p**3*q**2*r**2*s**2 + 15625*q**4*r**2*s**2 - 250000*p**4*r**3*s**2 + 225000*p**3*q**3*s**3 + 175000*q**5*s**3 - 1012500*p**4*q*r*s**3 - 1187500*p*q**3*r*s**3 + 1250000*p**2*q*r**2*s**3 + 928125*p**5*s**4 + 1875000*p**2*q**2*s**4 - 2812500*p**3*r*s**4 - 390625*q**2*r*s**4 - 9765625*s**6 return F def l0(self, theta): F = self.F a = self.a l0 = Poly(a, x).eval(theta)/F return l0 def T(self, theta, d): F = self.F T = [0]*5 b = self.b # Note that the order of sublists of the b's has been reversed compared to the paper T[1] = -Poly(b[1], x).eval(theta)/(2*F) T[2] = Poly(b[2], x).eval(theta)/(2*d*F) T[3] = Poly(b[3], x).eval(theta)/(2*F) T[4] = Poly(b[4], x).eval(theta)/(2*d*F) return T def order(self, theta, d): F = self.F o = self.o order = Poly(o, x).eval(theta)/(d*F) return N(order) def uv(self, theta, d): c = self.c u = self.q*Rational(-25, 2) v = Poly(c, x).eval(theta)/(2*d*self.F) return N(u), N(v) @property def zeta(self): return [self.zeta1, self.zeta2, self.zeta3, self.zeta4] sympy-sympy-1.9/sympy/polys/polyroots.py000066400000000000000000001015031412543434000206760ustar00rootroot00000000000000"""Algorithms for computing symbolic roots of polynomials. """ import math from functools import reduce from sympy.core import S, I, pi from sympy.core.compatibility import ordered from sympy.core.exprtools import factor_terms from sympy.core.function import _mexpand from sympy.core.logic import fuzzy_not from sympy.core.mul import expand_2arg, Mul from sympy.core.numbers import Rational, igcd, comp from sympy.core.power import Pow from sympy.core.relational import Eq from sympy.core.symbol import Dummy, Symbol, symbols from sympy.core.sympify import sympify from sympy.functions import exp, sqrt, im, cos, acos, Piecewise from sympy.functions.elementary.miscellaneous import root from sympy.ntheory import divisors, isprime, nextprime from sympy.polys.domains import EX from sympy.polys.polyerrors import (PolynomialError, GeneratorsNeeded, DomainError) from sympy.polys.polyquinticconst import PolyQuintic from sympy.polys.polytools import Poly, cancel, factor, gcd_list, discriminant from sympy.polys.rationaltools import together from sympy.polys.specialpolys import cyclotomic_poly from sympy.simplify import simplify, powsimp from sympy.utilities import public def roots_linear(f): """Returns a list of roots of a linear polynomial.""" r = -f.nth(0)/f.nth(1) dom = f.get_domain() if not dom.is_Numerical: if dom.is_Composite: r = factor(r) else: r = simplify(r) return [r] def roots_quadratic(f): """Returns a list of roots of a quadratic polynomial. If the domain is ZZ then the roots will be sorted with negatives coming before positives. The ordering will be the same for any numerical coefficients as long as the assumptions tested are correct, otherwise the ordering will not be sorted (but will be canonical). """ a, b, c = f.all_coeffs() dom = f.get_domain() def _sqrt(d): # remove squares from square root since both will be represented # in the results; a similar thing is happening in roots() but # must be duplicated here because not all quadratics are binomials co = [] other = [] for di in Mul.make_args(d): if di.is_Pow and di.exp.is_Integer and di.exp % 2 == 0: co.append(Pow(di.base, di.exp//2)) else: other.append(di) if co: d = Mul(*other) co = Mul(*co) return co*sqrt(d) return sqrt(d) def _simplify(expr): if dom.is_Composite: return factor(expr) else: return simplify(expr) if c is S.Zero: r0, r1 = S.Zero, -b/a if not dom.is_Numerical: r1 = _simplify(r1) elif r1.is_negative: r0, r1 = r1, r0 elif b is S.Zero: r = -c/a if not dom.is_Numerical: r = _simplify(r) R = _sqrt(r) r0 = -R r1 = R else: d = b**2 - 4*a*c A = 2*a B = -b/A if not dom.is_Numerical: d = _simplify(d) B = _simplify(B) D = factor_terms(_sqrt(d)/A) r0 = B - D r1 = B + D if a.is_negative: r0, r1 = r1, r0 elif not dom.is_Numerical: r0, r1 = [expand_2arg(i) for i in (r0, r1)] return [r0, r1] def roots_cubic(f, trig=False): """Returns a list of roots of a cubic polynomial. References ========== [1] https://en.wikipedia.org/wiki/Cubic_function, General formula for roots, (accessed November 17, 2014). """ if trig: a, b, c, d = f.all_coeffs() p = (3*a*c - b**2)/3/a**2 q = (2*b**3 - 9*a*b*c + 27*a**2*d)/(27*a**3) D = 18*a*b*c*d - 4*b**3*d + b**2*c**2 - 4*a*c**3 - 27*a**2*d**2 if (D > 0) == True: rv = [] for k in range(3): rv.append(2*sqrt(-p/3)*cos(acos(q/p*sqrt(-3/p)*Rational(3, 2))/3 - k*pi*Rational(2, 3))) return [i - b/3/a for i in rv] # a*x**3 + b*x**2 + c*x + d -> x**3 + a*x**2 + b*x + c _, a, b, c = f.monic().all_coeffs() if c is S.Zero: x1, x2 = roots([1, a, b], multiple=True) return [x1, S.Zero, x2] # x**3 + a*x**2 + b*x + c -> u**3 + p*u + q p = b - a**2/3 q = c - a*b/3 + 2*a**3/27 pon3 = p/3 aon3 = a/3 u1 = None if p is S.Zero: if q is S.Zero: return [-aon3]*3 u1 = -root(q, 3) if q.is_positive else root(-q, 3) elif q is S.Zero: y1, y2 = roots([1, 0, p], multiple=True) return [tmp - aon3 for tmp in [y1, S.Zero, y2]] elif q.is_real and q.is_negative: u1 = -root(-q/2 + sqrt(q**2/4 + pon3**3), 3) coeff = I*sqrt(3)/2 if u1 is None: u1 = S.One u2 = Rational(-1, 2) + coeff u3 = Rational(-1, 2) - coeff a, b, c, d = S(1), a, b, c D0 = b**2 - 3*a*c D1 = 2*b**3 - 9*a*b*c + 27*a**2*d C = root((D1 + sqrt(D1**2 - 4*D0**3))/2, 3) return [-(b + uk*C + D0/C/uk)/3/a for uk in [u1, u2, u3]] u2 = u1*(Rational(-1, 2) + coeff) u3 = u1*(Rational(-1, 2) - coeff) if p is S.Zero: return [u1 - aon3, u2 - aon3, u3 - aon3] soln = [ -u1 + pon3/u1 - aon3, -u2 + pon3/u2 - aon3, -u3 + pon3/u3 - aon3 ] return soln def _roots_quartic_euler(p, q, r, a): """ Descartes-Euler solution of the quartic equation Parameters ========== p, q, r: coefficients of ``x**4 + p*x**2 + q*x + r`` a: shift of the roots Notes ===== This is a helper function for ``roots_quartic``. Look for solutions of the form :: ``x1 = sqrt(R) - sqrt(A + B*sqrt(R))`` ``x2 = -sqrt(R) - sqrt(A - B*sqrt(R))`` ``x3 = -sqrt(R) + sqrt(A - B*sqrt(R))`` ``x4 = sqrt(R) + sqrt(A + B*sqrt(R))`` To satisfy the quartic equation one must have ``p = -2*(R + A); q = -4*B*R; r = (R - A)**2 - B**2*R`` so that ``R`` must satisfy the Descartes-Euler resolvent equation ``64*R**3 + 32*p*R**2 + (4*p**2 - 16*r)*R - q**2 = 0`` If the resolvent does not have a rational solution, return None; in that case it is likely that the Ferrari method gives a simpler solution. Examples ======== >>> from sympy import S >>> from sympy.polys.polyroots import _roots_quartic_euler >>> p, q, r = -S(64)/5, -S(512)/125, -S(1024)/3125 >>> _roots_quartic_euler(p, q, r, S(0))[0] -sqrt(32*sqrt(5)/125 + 16/5) + 4*sqrt(5)/5 """ # solve the resolvent equation x = Dummy('x') eq = 64*x**3 + 32*p*x**2 + (4*p**2 - 16*r)*x - q**2 xsols = list(roots(Poly(eq, x), cubics=False).keys()) xsols = [sol for sol in xsols if sol.is_rational and sol.is_nonzero] if not xsols: return None R = max(xsols) c1 = sqrt(R) B = -q*c1/(4*R) A = -R - p/2 c2 = sqrt(A + B) c3 = sqrt(A - B) return [c1 - c2 - a, -c1 - c3 - a, -c1 + c3 - a, c1 + c2 - a] def roots_quartic(f): r""" Returns a list of roots of a quartic polynomial. There are many references for solving quartic expressions available [1-5]. This reviewer has found that many of them require one to select from among 2 or more possible sets of solutions and that some solutions work when one is searching for real roots but don't work when searching for complex roots (though this is not always stated clearly). The following routine has been tested and found to be correct for 0, 2 or 4 complex roots. The quasisymmetric case solution [6] looks for quartics that have the form `x**4 + A*x**3 + B*x**2 + C*x + D = 0` where `(C/A)**2 = D`. Although no general solution that is always applicable for all coefficients is known to this reviewer, certain conditions are tested to determine the simplest 4 expressions that can be returned: 1) `f = c + a*(a**2/8 - b/2) == 0` 2) `g = d - a*(a*(3*a**2/256 - b/16) + c/4) = 0` 3) if `f != 0` and `g != 0` and `p = -d + a*c/4 - b**2/12` then a) `p == 0` b) `p != 0` Examples ======== >>> from sympy import Poly >>> from sympy.polys.polyroots import roots_quartic >>> r = roots_quartic(Poly('x**4-6*x**3+17*x**2-26*x+20')) >>> # 4 complex roots: 1+-I*sqrt(3), 2+-I >>> sorted(str(tmp.evalf(n=2)) for tmp in r) ['1.0 + 1.7*I', '1.0 - 1.7*I', '2.0 + 1.0*I', '2.0 - 1.0*I'] References ========== 1. http://mathforum.org/dr.math/faq/faq.cubic.equations.html 2. https://en.wikipedia.org/wiki/Quartic_function#Summary_of_Ferrari.27s_method 3. http://planetmath.org/encyclopedia/GaloisTheoreticDerivationOfTheQuarticFormula.html 4. http://staff.bath.ac.uk/masjhd/JHD-CA.pdf 5. http://www.albmath.org/files/Math_5713.pdf 6. http://www.statemaster.com/encyclopedia/Quartic-equation 7. eqworld.ipmnet.ru/en/solutions/ae/ae0108.pdf """ _, a, b, c, d = f.monic().all_coeffs() if not d: return [S.Zero] + roots([1, a, b, c], multiple=True) elif (c/a)**2 == d: x, m = f.gen, c/a g = Poly(x**2 + a*x + b - 2*m, x) z1, z2 = roots_quadratic(g) h1 = Poly(x**2 - z1*x + m, x) h2 = Poly(x**2 - z2*x + m, x) r1 = roots_quadratic(h1) r2 = roots_quadratic(h2) return r1 + r2 else: a2 = a**2 e = b - 3*a2/8 f = _mexpand(c + a*(a2/8 - b/2)) g = _mexpand(d - a*(a*(3*a2/256 - b/16) + c/4)) aon4 = a/4 if f is S.Zero: y1, y2 = [sqrt(tmp) for tmp in roots([1, e, g], multiple=True)] return [tmp - aon4 for tmp in [-y1, -y2, y1, y2]] if g is S.Zero: y = [S.Zero] + roots([1, 0, e, f], multiple=True) return [tmp - aon4 for tmp in y] else: # Descartes-Euler method, see [7] sols = _roots_quartic_euler(e, f, g, aon4) if sols: return sols # Ferrari method, see [1, 2] a2 = a**2 e = b - 3*a2/8 f = c + a*(a2/8 - b/2) g = d - a*(a*(3*a2/256 - b/16) + c/4) p = -e**2/12 - g q = -e**3/108 + e*g/3 - f**2/8 TH = Rational(1, 3) def _ans(y): w = sqrt(e + 2*y) arg1 = 3*e + 2*y arg2 = 2*f/w ans = [] for s in [-1, 1]: root = sqrt(-(arg1 + s*arg2)) for t in [-1, 1]: ans.append((s*w - t*root)/2 - aon4) return ans # whether a Piecewise is returned or not # depends on knowing p, so try to put # in a simple form p = _mexpand(p) # p == 0 case y1 = e*Rational(-5, 6) - q**TH if p.is_zero: return _ans(y1) # if p != 0 then u below is not 0 root = sqrt(q**2/4 + p**3/27) r = -q/2 + root # or -q/2 - root u = r**TH # primary root of solve(x**3 - r, x) y2 = e*Rational(-5, 6) + u - p/u/3 if fuzzy_not(p.is_zero): return _ans(y2) # sort it out once they know the values of the coefficients return [Piecewise((a1, Eq(p, 0)), (a2, True)) for a1, a2 in zip(_ans(y1), _ans(y2))] def roots_binomial(f): """Returns a list of roots of a binomial polynomial. If the domain is ZZ then the roots will be sorted with negatives coming before positives. The ordering will be the same for any numerical coefficients as long as the assumptions tested are correct, otherwise the ordering will not be sorted (but will be canonical). """ n = f.degree() a, b = f.nth(n), f.nth(0) base = -cancel(b/a) alpha = root(base, n) if alpha.is_number: alpha = alpha.expand(complex=True) # define some parameters that will allow us to order the roots. # If the domain is ZZ this is guaranteed to return roots sorted # with reals before non-real roots and non-real sorted according # to real part and imaginary part, e.g. -1, 1, -1 + I, 2 - I neg = base.is_negative even = n % 2 == 0 if neg: if even == True and (base + 1).is_positive: big = True else: big = False # get the indices in the right order so the computed # roots will be sorted when the domain is ZZ ks = [] imax = n//2 if even: ks.append(imax) imax -= 1 if not neg: ks.append(0) for i in range(imax, 0, -1): if neg: ks.extend([i, -i]) else: ks.extend([-i, i]) if neg: ks.append(0) if big: for i in range(0, len(ks), 2): pair = ks[i: i + 2] pair = list(reversed(pair)) # compute the roots roots, d = [], 2*I*pi/n for k in ks: zeta = exp(k*d).expand(complex=True) roots.append((alpha*zeta).expand(power_base=False)) return roots def _inv_totient_estimate(m): """ Find ``(L, U)`` such that ``L <= phi^-1(m) <= U``. Examples ======== >>> from sympy.polys.polyroots import _inv_totient_estimate >>> _inv_totient_estimate(192) (192, 840) >>> _inv_totient_estimate(400) (400, 1750) """ primes = [ d + 1 for d in divisors(m) if isprime(d + 1) ] a, b = 1, 1 for p in primes: a *= p b *= p - 1 L = m U = int(math.ceil(m*(float(a)/b))) P = p = 2 primes = [] while P <= U: p = nextprime(p) primes.append(p) P *= p P //= p b = 1 for p in primes[:-1]: b *= p - 1 U = int(math.ceil(m*(float(P)/b))) return L, U def roots_cyclotomic(f, factor=False): """Compute roots of cyclotomic polynomials. """ L, U = _inv_totient_estimate(f.degree()) for n in range(L, U + 1): g = cyclotomic_poly(n, f.gen, polys=True) if f.expr == g.expr: break else: # pragma: no cover raise RuntimeError("failed to find index of a cyclotomic polynomial") roots = [] if not factor: # get the indices in the right order so the computed # roots will be sorted h = n//2 ks = [i for i in range(1, n + 1) if igcd(i, n) == 1] ks.sort(key=lambda x: (x, -1) if x <= h else (abs(x - n), 1)) d = 2*I*pi/n for k in reversed(ks): roots.append(exp(k*d).expand(complex=True)) else: g = Poly(f, extension=root(-1, n)) for h, _ in ordered(g.factor_list()[1]): roots.append(-h.TC()) return roots def roots_quintic(f): """ Calculate exact roots of a solvable quintic """ result = [] coeff_5, coeff_4, p, q, r, s = f.all_coeffs() # Eqn must be of the form x^5 + px^3 + qx^2 + rx + s if coeff_4: return result if coeff_5 != 1: l = [p/coeff_5, q/coeff_5, r/coeff_5, s/coeff_5] if not all(coeff.is_Rational for coeff in l): return result f = Poly(f/coeff_5) elif not all(coeff.is_Rational for coeff in (p, q, r, s)): return result quintic = PolyQuintic(f) # Eqn standardized. Algo for solving starts here if not f.is_irreducible: return result f20 = quintic.f20 # Check if f20 has linear factors over domain Z if f20.is_irreducible: return result # Now, we know that f is solvable for _factor in f20.factor_list()[1]: if _factor[0].is_linear: theta = _factor[0].root(0) break d = discriminant(f) delta = sqrt(d) # zeta = a fifth root of unity zeta1, zeta2, zeta3, zeta4 = quintic.zeta T = quintic.T(theta, d) tol = S(1e-10) alpha = T[1] + T[2]*delta alpha_bar = T[1] - T[2]*delta beta = T[3] + T[4]*delta beta_bar = T[3] - T[4]*delta disc = alpha**2 - 4*beta disc_bar = alpha_bar**2 - 4*beta_bar l0 = quintic.l0(theta) l1 = _quintic_simplify((-alpha + sqrt(disc)) / S(2)) l4 = _quintic_simplify((-alpha - sqrt(disc)) / S(2)) l2 = _quintic_simplify((-alpha_bar + sqrt(disc_bar)) / S(2)) l3 = _quintic_simplify((-alpha_bar - sqrt(disc_bar)) / S(2)) order = quintic.order(theta, d) test = (order*delta.n()) - ( (l1.n() - l4.n())*(l2.n() - l3.n()) ) # Comparing floats if not comp(test, 0, tol): l2, l3 = l3, l2 # Now we have correct order of l's R1 = l0 + l1*zeta1 + l2*zeta2 + l3*zeta3 + l4*zeta4 R2 = l0 + l3*zeta1 + l1*zeta2 + l4*zeta3 + l2*zeta4 R3 = l0 + l2*zeta1 + l4*zeta2 + l1*zeta3 + l3*zeta4 R4 = l0 + l4*zeta1 + l3*zeta2 + l2*zeta3 + l1*zeta4 Res = [None, [None]*5, [None]*5, [None]*5, [None]*5] Res_n = [None, [None]*5, [None]*5, [None]*5, [None]*5] sol = Symbol('sol') # Simplifying improves performance a lot for exact expressions R1 = _quintic_simplify(R1) R2 = _quintic_simplify(R2) R3 = _quintic_simplify(R3) R4 = _quintic_simplify(R4) # Solve imported here. Causing problems if imported as 'solve' # and hence the changed name from sympy.solvers.solvers import solve as _solve a, b = symbols('a b', cls=Dummy) _sol = _solve( sol**5 - a - I*b, sol) for i in range(5): _sol[i] = factor(_sol[i]) R1 = R1.as_real_imag() R2 = R2.as_real_imag() R3 = R3.as_real_imag() R4 = R4.as_real_imag() for i, currentroot in enumerate(_sol): Res[1][i] = _quintic_simplify(currentroot.subs({ a: R1[0], b: R1[1] })) Res[2][i] = _quintic_simplify(currentroot.subs({ a: R2[0], b: R2[1] })) Res[3][i] = _quintic_simplify(currentroot.subs({ a: R3[0], b: R3[1] })) Res[4][i] = _quintic_simplify(currentroot.subs({ a: R4[0], b: R4[1] })) for i in range(1, 5): for j in range(5): Res_n[i][j] = Res[i][j].n() Res[i][j] = _quintic_simplify(Res[i][j]) r1 = Res[1][0] r1_n = Res_n[1][0] for i in range(5): if comp(im(r1_n*Res_n[4][i]), 0, tol): r4 = Res[4][i] break # Now we have various Res values. Each will be a list of five # values. We have to pick one r value from those five for each Res u, v = quintic.uv(theta, d) testplus = (u + v*delta*sqrt(5)).n() testminus = (u - v*delta*sqrt(5)).n() # Evaluated numbers suffixed with _n # We will use evaluated numbers for calculation. Much faster. r4_n = r4.n() r2 = r3 = None for i in range(5): r2temp_n = Res_n[2][i] for j in range(5): # Again storing away the exact number and using # evaluated numbers in computations r3temp_n = Res_n[3][j] if (comp((r1_n*r2temp_n**2 + r4_n*r3temp_n**2 - testplus).n(), 0, tol) and comp((r3temp_n*r1_n**2 + r2temp_n*r4_n**2 - testminus).n(), 0, tol)): r2 = Res[2][i] r3 = Res[3][j] break if r2: break else: return [] # fall back to normal solve # Now, we have r's so we can get roots x1 = (r1 + r2 + r3 + r4)/5 x2 = (r1*zeta4 + r2*zeta3 + r3*zeta2 + r4*zeta1)/5 x3 = (r1*zeta3 + r2*zeta1 + r3*zeta4 + r4*zeta2)/5 x4 = (r1*zeta2 + r2*zeta4 + r3*zeta1 + r4*zeta3)/5 x5 = (r1*zeta1 + r2*zeta2 + r3*zeta3 + r4*zeta4)/5 result = [x1, x2, x3, x4, x5] # Now check if solutions are distinct saw = set() for r in result: r = r.n(2) if r in saw: # Roots were identical. Abort, return [] # and fall back to usual solve return [] saw.add(r) return result def _quintic_simplify(expr): expr = powsimp(expr) expr = cancel(expr) return together(expr) def _integer_basis(poly): """Compute coefficient basis for a polynomial over integers. Returns the integer ``div`` such that substituting ``x = div*y`` ``p(x) = m*q(y)`` where the coefficients of ``q`` are smaller than those of ``p``. For example ``x**5 + 512*x + 1024 = 0`` with ``div = 4`` becomes ``y**5 + 2*y + 1 = 0`` Returns the integer ``div`` or ``None`` if there is no possible scaling. Examples ======== >>> from sympy.polys import Poly >>> from sympy.abc import x >>> from sympy.polys.polyroots import _integer_basis >>> p = Poly(x**5 + 512*x + 1024, x, domain='ZZ') >>> _integer_basis(p) 4 """ monoms, coeffs = list(zip(*poly.terms())) monoms, = list(zip(*monoms)) coeffs = list(map(abs, coeffs)) if coeffs[0] < coeffs[-1]: coeffs = list(reversed(coeffs)) n = monoms[0] monoms = [n - i for i in reversed(monoms)] else: return None monoms = monoms[:-1] coeffs = coeffs[:-1] divs = reversed(divisors(gcd_list(coeffs))[1:]) try: div = next(divs) except StopIteration: return None while True: for monom, coeff in zip(monoms, coeffs): if coeff % div**monom != 0: try: div = next(divs) except StopIteration: return None else: break else: return div def preprocess_roots(poly): """Try to get rid of symbolic coefficients from ``poly``. """ coeff = S.One poly_func = poly.func try: _, poly = poly.clear_denoms(convert=True) except DomainError: return coeff, poly poly = poly.primitive()[1] poly = poly.retract() # TODO: This is fragile. Figure out how to make this independent of construct_domain(). if poly.get_domain().is_Poly and all(c.is_term for c in poly.rep.coeffs()): poly = poly.inject() strips = list(zip(*poly.monoms())) gens = list(poly.gens[1:]) base, strips = strips[0], strips[1:] for gen, strip in zip(list(gens), strips): reverse = False if strip[0] < strip[-1]: strip = reversed(strip) reverse = True ratio = None for a, b in zip(base, strip): if not a and not b: continue elif not a or not b: break elif b % a != 0: break else: _ratio = b // a if ratio is None: ratio = _ratio elif ratio != _ratio: break else: if reverse: ratio = -ratio poly = poly.eval(gen, 1) coeff *= gen**(-ratio) gens.remove(gen) if gens: poly = poly.eject(*gens) if poly.is_univariate and poly.get_domain().is_ZZ: basis = _integer_basis(poly) if basis is not None: n = poly.degree() def func(k, coeff): return coeff//basis**(n - k[0]) poly = poly.termwise(func) coeff *= basis if not isinstance(poly, poly_func): poly = poly_func(poly) return coeff, poly @public def roots(f, *gens, auto=True, cubics=True, trig=False, quartics=True, quintics=False, multiple=False, filter=None, predicate=None, **flags): """ Computes symbolic roots of a univariate polynomial. Given a univariate polynomial f with symbolic coefficients (or a list of the polynomial's coefficients), returns a dictionary with its roots and their multiplicities. Only roots expressible via radicals will be returned. To get a complete set of roots use RootOf class or numerical methods instead. By default cubic and quartic formulas are used in the algorithm. To disable them because of unreadable output set ``cubics=False`` or ``quartics=False`` respectively. If cubic roots are real but are expressed in terms of complex numbers (casus irreducibilis [1]) the ``trig`` flag can be set to True to have the solutions returned in terms of cosine and inverse cosine functions. To get roots from a specific domain set the ``filter`` flag with one of the following specifiers: Z, Q, R, I, C. By default all roots are returned (this is equivalent to setting ``filter='C'``). By default a dictionary is returned giving a compact result in case of multiple roots. However to get a list containing all those roots set the ``multiple`` flag to True; the list will have identical roots appearing next to each other in the result. (For a given Poly, the all_roots method will give the roots in sorted numerical order.) Examples ======== >>> from sympy import Poly, roots >>> from sympy.abc import x, y >>> roots(x**2 - 1, x) {-1: 1, 1: 1} >>> p = Poly(x**2-1, x) >>> roots(p) {-1: 1, 1: 1} >>> p = Poly(x**2-y, x, y) >>> roots(Poly(p, x)) {-sqrt(y): 1, sqrt(y): 1} >>> roots(x**2 - y, x) {-sqrt(y): 1, sqrt(y): 1} >>> roots([1, 0, -1]) {-1: 1, 1: 1} References ========== .. [1] https://en.wikipedia.org/wiki/Cubic_function#Trigonometric_.28and_hyperbolic.29_method """ from sympy.polys.polytools import to_rational_coeffs flags = dict(flags) if isinstance(f, list): if gens: raise ValueError('redundant generators given') x = Dummy('x') poly, i = {}, len(f) - 1 for coeff in f: poly[i], i = sympify(coeff), i - 1 f = Poly(poly, x, field=True) else: try: F = Poly(f, *gens, **flags) if not isinstance(f, Poly) and not F.gen.is_Symbol: raise PolynomialError("generator must be a Symbol") else: f = F if f.length == 2 and f.degree() != 1: # check for foo**n factors in the constant n = f.degree() npow_bases = [] others = [] expr = f.as_expr() con = expr.as_independent(*gens)[0] for p in Mul.make_args(con): if p.is_Pow and not p.exp % n: npow_bases.append(p.base**(p.exp/n)) else: others.append(p) if npow_bases: b = Mul(*npow_bases) B = Dummy() d = roots(Poly(expr - con + B**n*Mul(*others), *gens, **flags), *gens, **flags) rv = {} for k, v in d.items(): rv[k.subs(B, b)] = v return rv except GeneratorsNeeded: if multiple: return [] else: return {} if f.is_multivariate: raise PolynomialError('multivariate polynomials are not supported') def _update_dict(result, currentroot, k): if currentroot in result: result[currentroot] += k else: result[currentroot] = k def _try_decompose(f): """Find roots using functional decomposition. """ factors, roots = f.decompose(), [] for currentroot in _try_heuristics(factors[0]): roots.append(currentroot) for currentfactor in factors[1:]: previous, roots = list(roots), [] for currentroot in previous: g = currentfactor - Poly(currentroot, f.gen) for currentroot in _try_heuristics(g): roots.append(currentroot) return roots def _try_heuristics(f): """Find roots using formulas and some tricks. """ if f.is_ground: return [] if f.is_monomial: return [S.Zero]*f.degree() if f.length() == 2: if f.degree() == 1: return list(map(cancel, roots_linear(f))) else: return roots_binomial(f) result = [] for i in [-1, 1]: if not f.eval(i): f = f.quo(Poly(f.gen - i, f.gen)) result.append(i) break n = f.degree() if n == 1: result += list(map(cancel, roots_linear(f))) elif n == 2: result += list(map(cancel, roots_quadratic(f))) elif f.is_cyclotomic: result += roots_cyclotomic(f) elif n == 3 and cubics: result += roots_cubic(f, trig=trig) elif n == 4 and quartics: result += roots_quartic(f) elif n == 5 and quintics: result += roots_quintic(f) return result # Convert the generators to symbols dumgens = symbols('x:%d' % len(f.gens), cls=Dummy) f = f.per(f.rep, dumgens) (k,), f = f.terms_gcd() if not k: zeros = {} else: zeros = {S.Zero: k} coeff, f = preprocess_roots(f) if auto and f.get_domain().is_Ring: f = f.to_field() # Use EX instead of ZZ_I or QQ_I if f.get_domain().is_QQ_I: f = f.per(f.rep.convert(EX)) rescale_x = None translate_x = None result = {} if not f.is_ground: dom = f.get_domain() if not dom.is_Exact and dom.is_Numerical: for r in f.nroots(): _update_dict(result, r, 1) elif f.degree() == 1: result[roots_linear(f)[0]] = 1 elif f.length() == 2: roots_fun = roots_quadratic if f.degree() == 2 else roots_binomial for r in roots_fun(f): _update_dict(result, r, 1) else: _, factors = Poly(f.as_expr()).factor_list() if len(factors) == 1 and f.degree() == 2: for r in roots_quadratic(f): _update_dict(result, r, 1) else: if len(factors) == 1 and factors[0][1] == 1: if f.get_domain().is_EX: res = to_rational_coeffs(f) if res: if res[0] is None: translate_x, f = res[2:] else: rescale_x, f = res[1], res[-1] result = roots(f) if not result: for currentroot in _try_decompose(f): _update_dict(result, currentroot, 1) else: for r in _try_heuristics(f): _update_dict(result, r, 1) else: for currentroot in _try_decompose(f): _update_dict(result, currentroot, 1) else: for currentfactor, k in factors: for r in _try_heuristics(Poly(currentfactor, f.gen, field=True)): _update_dict(result, r, k) if coeff is not S.One: _result, result, = result, {} for currentroot, k in _result.items(): result[coeff*currentroot] = k if filter not in [None, 'C']: handlers = { 'Z': lambda r: r.is_Integer, 'Q': lambda r: r.is_Rational, 'R': lambda r: all(a.is_real for a in r.as_numer_denom()), 'I': lambda r: r.is_imaginary, } try: query = handlers[filter] except KeyError: raise ValueError("Invalid filter: %s" % filter) for zero in dict(result).keys(): if not query(zero): del result[zero] if predicate is not None: for zero in dict(result).keys(): if not predicate(zero): del result[zero] if rescale_x: result1 = {} for k, v in result.items(): result1[k*rescale_x] = v result = result1 if translate_x: result1 = {} for k, v in result.items(): result1[k + translate_x] = v result = result1 # adding zero roots after non-trivial roots have been translated result.update(zeros) if not multiple: return result else: zeros = [] for zero in ordered(result): zeros.extend([zero]*result[zero]) return zeros def root_factors(f, *gens, filter=None, **args): """ Returns all factors of a univariate polynomial. Examples ======== >>> from sympy.abc import x, y >>> from sympy.polys.polyroots import root_factors >>> root_factors(x**2 - y, x) [x - sqrt(y), x + sqrt(y)] """ args = dict(args) F = Poly(f, *gens, **args) if not F.is_Poly: return [f] if F.is_multivariate: raise ValueError('multivariate polynomials are not supported') x = F.gens[0] zeros = roots(F, filter=filter) if not zeros: factors = [F] else: factors, N = [], 0 for r, n in ordered(zeros.items()): factors, N = factors + [Poly(x - r, x)]*n, N + n if N < F.degree(): G = reduce(lambda p, q: p*q, factors) factors.append(F.quo(G)) if not isinstance(f, Poly): factors = [ f.as_expr() for f in factors ] return factors sympy-sympy-1.9/sympy/polys/polytools.py000066400000000000000000005550571412543434000207110ustar00rootroot00000000000000"""User-friendly public interface to polynomial functions. """ from functools import wraps, reduce from operator import mul from sympy.core import ( S, Basic, Expr, I, Integer, Add, Mul, Dummy, Tuple ) from sympy.core.basic import preorder_traversal from sympy.core.compatibility import iterable, ordered from sympy.core.decorators import _sympifyit from sympy.core.evalf import pure_complex from sympy.core.function import Derivative from sympy.core.mul import _keep_coeff from sympy.core.relational import Relational from sympy.core.symbol import Symbol from sympy.core.sympify import sympify, _sympify from sympy.logic.boolalg import BooleanAtom from sympy.polys import polyoptions as options from sympy.polys.constructor import construct_domain from sympy.polys.domains import FF, QQ, ZZ from sympy.polys.domains.domainelement import DomainElement from sympy.polys.fglmtools import matrix_fglm from sympy.polys.groebnertools import groebner as _groebner from sympy.polys.monomials import Monomial from sympy.polys.orderings import monomial_key from sympy.polys.polyclasses import DMP, DMF, ANP from sympy.polys.polyerrors import ( OperationNotSupported, DomainError, CoercionFailed, UnificationFailed, GeneratorsNeeded, PolynomialError, MultivariatePolynomialError, ExactQuotientFailed, PolificationFailed, ComputationFailed, GeneratorsError, ) from sympy.polys.polyutils import ( basic_from_dict, _sort_gens, _unify_gens, _dict_reorder, _dict_from_expr, _parallel_dict_from_expr, ) from sympy.polys.rationaltools import together from sympy.polys.rootisolation import dup_isolate_real_roots_list from sympy.utilities import group, sift, public, filldedent from sympy.utilities.exceptions import SymPyDeprecationWarning # Required to avoid errors import sympy.polys import mpmath from mpmath.libmp.libhyper import NoConvergence def _polifyit(func): @wraps(func) def wrapper(f, g): g = _sympify(g) if isinstance(g, Poly): return func(f, g) elif isinstance(g, Expr): try: g = f.from_expr(g, *f.gens) except PolynomialError: if g.is_Matrix: return NotImplemented expr_method = getattr(f.as_expr(), func.__name__) result = expr_method(g) if result is not NotImplemented: SymPyDeprecationWarning( feature="Mixing Poly with non-polynomial expressions in binary operations", issue=18613, deprecated_since_version="1.6", useinstead="the as_expr or as_poly method to convert types").warn() return result else: return func(f, g) else: return NotImplemented return wrapper @public class Poly(Basic): """ Generic class for representing and operating on polynomial expressions. See :ref:`polys-docs` for general documentation. Poly is a subclass of Basic rather than Expr but instances can be converted to Expr with the :py:meth:`~.Poly.as_expr` method. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y Create a univariate polynomial: >>> Poly(x*(x**2 + x - 1)**2) Poly(x**5 + 2*x**4 - x**3 - 2*x**2 + x, x, domain='ZZ') Create a univariate polynomial with specific domain: >>> from sympy import sqrt >>> Poly(x**2 + 2*x + sqrt(3), domain='R') Poly(1.0*x**2 + 2.0*x + 1.73205080756888, x, domain='RR') Create a multivariate polynomial: >>> Poly(y*x**2 + x*y + 1) Poly(x**2*y + x*y + 1, x, y, domain='ZZ') Create a univariate polynomial, where y is a constant: >>> Poly(y*x**2 + x*y + 1,x) Poly(y*x**2 + y*x + 1, x, domain='ZZ[y]') You can evaluate the above polynomial as a function of y: >>> Poly(y*x**2 + x*y + 1,x).eval(2) 6*y + 1 See Also ======== sympy.core.expr.Expr """ __slots__ = ('rep', 'gens') is_commutative = True is_Poly = True _op_priority = 10.001 def __new__(cls, rep, *gens, **args): """Create a new polynomial instance out of something useful. """ opt = options.build_options(gens, args) if 'order' in opt: raise NotImplementedError("'order' keyword is not implemented yet") if isinstance(rep, (DMP, DMF, ANP, DomainElement)): return cls._from_domain_element(rep, opt) elif iterable(rep, exclude=str): if isinstance(rep, dict): return cls._from_dict(rep, opt) else: return cls._from_list(list(rep), opt) else: rep = sympify(rep) if rep.is_Poly: return cls._from_poly(rep, opt) else: return cls._from_expr(rep, opt) # Poly does not pass its args to Basic.__new__ to be stored in _args so we # have to emulate them here with an args property that derives from rep # and gens which are instance attributes. This also means we need to # define _hashable_content. The _hashable_content is rep and gens but args # uses expr instead of rep (expr is the Basic version of rep). Passing # expr in args means that Basic methods like subs should work. Using rep # otherwise means that Poly can remain more efficient than Basic by # avoiding creating a Basic instance just to be hashable. @classmethod def new(cls, rep, *gens): """Construct :class:`Poly` instance from raw representation. """ if not isinstance(rep, DMP): raise PolynomialError( "invalid polynomial representation: %s" % rep) elif rep.lev != len(gens) - 1: raise PolynomialError("invalid arguments: %s, %s" % (rep, gens)) obj = Basic.__new__(cls) obj.rep = rep obj.gens = gens return obj @property def expr(self): return basic_from_dict(self.rep.to_sympy_dict(), *self.gens) @property def args(self): return (self.expr,) + self.gens def _hashable_content(self): return (self.rep,) + self.gens @classmethod def from_dict(cls, rep, *gens, **args): """Construct a polynomial from a ``dict``. """ opt = options.build_options(gens, args) return cls._from_dict(rep, opt) @classmethod def from_list(cls, rep, *gens, **args): """Construct a polynomial from a ``list``. """ opt = options.build_options(gens, args) return cls._from_list(rep, opt) @classmethod def from_poly(cls, rep, *gens, **args): """Construct a polynomial from a polynomial. """ opt = options.build_options(gens, args) return cls._from_poly(rep, opt) @classmethod def from_expr(cls, rep, *gens, **args): """Construct a polynomial from an expression. """ opt = options.build_options(gens, args) return cls._from_expr(rep, opt) @classmethod def _from_dict(cls, rep, opt): """Construct a polynomial from a ``dict``. """ gens = opt.gens if not gens: raise GeneratorsNeeded( "can't initialize from 'dict' without generators") level = len(gens) - 1 domain = opt.domain if domain is None: domain, rep = construct_domain(rep, opt=opt) else: for monom, coeff in rep.items(): rep[monom] = domain.convert(coeff) return cls.new(DMP.from_dict(rep, level, domain), *gens) @classmethod def _from_list(cls, rep, opt): """Construct a polynomial from a ``list``. """ gens = opt.gens if not gens: raise GeneratorsNeeded( "can't initialize from 'list' without generators") elif len(gens) != 1: raise MultivariatePolynomialError( "'list' representation not supported") level = len(gens) - 1 domain = opt.domain if domain is None: domain, rep = construct_domain(rep, opt=opt) else: rep = list(map(domain.convert, rep)) return cls.new(DMP.from_list(rep, level, domain), *gens) @classmethod def _from_poly(cls, rep, opt): """Construct a polynomial from a polynomial. """ if cls != rep.__class__: rep = cls.new(rep.rep, *rep.gens) gens = opt.gens field = opt.field domain = opt.domain if gens and rep.gens != gens: if set(rep.gens) != set(gens): return cls._from_expr(rep.as_expr(), opt) else: rep = rep.reorder(*gens) if 'domain' in opt and domain: rep = rep.set_domain(domain) elif field is True: rep = rep.to_field() return rep @classmethod def _from_expr(cls, rep, opt): """Construct a polynomial from an expression. """ rep, opt = _dict_from_expr(rep, opt) return cls._from_dict(rep, opt) @classmethod def _from_domain_element(cls, rep, opt): gens = opt.gens domain = opt.domain level = len(gens) - 1 rep = [domain.convert(rep)] return cls.new(DMP.from_list(rep, level, domain), *gens) def __hash__(self): return super().__hash__() @property def free_symbols(self): """ Free symbols of a polynomial expression. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y, z >>> Poly(x**2 + 1).free_symbols {x} >>> Poly(x**2 + y).free_symbols {x, y} >>> Poly(x**2 + y, x).free_symbols {x, y} >>> Poly(x**2 + y, x, z).free_symbols {x, y} """ symbols = set() gens = self.gens for i in range(len(gens)): for monom in self.monoms(): if monom[i]: symbols |= gens[i].free_symbols break return symbols | self.free_symbols_in_domain @property def free_symbols_in_domain(self): """ Free symbols of the domain of ``self``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + 1).free_symbols_in_domain set() >>> Poly(x**2 + y).free_symbols_in_domain set() >>> Poly(x**2 + y, x).free_symbols_in_domain {y} """ domain, symbols = self.rep.dom, set() if domain.is_Composite: for gen in domain.symbols: symbols |= gen.free_symbols elif domain.is_EX: for coeff in self.coeffs(): symbols |= coeff.free_symbols return symbols @property def gen(self): """ Return the principal generator. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).gen x """ return self.gens[0] @property def domain(self): """Get the ground domain of a :py:class:`~.Poly` Returns ======= :py:class:`~.Domain`: Ground domain of the :py:class:`~.Poly`. Examples ======== >>> from sympy import Poly, Symbol >>> x = Symbol('x') >>> p = Poly(x**2 + x) >>> p Poly(x**2 + x, x, domain='ZZ') >>> p.domain ZZ """ return self.get_domain() @property def zero(self): """Return zero polynomial with ``self``'s properties. """ return self.new(self.rep.zero(self.rep.lev, self.rep.dom), *self.gens) @property def one(self): """Return one polynomial with ``self``'s properties. """ return self.new(self.rep.one(self.rep.lev, self.rep.dom), *self.gens) @property def unit(self): """Return unit polynomial with ``self``'s properties. """ return self.new(self.rep.unit(self.rep.lev, self.rep.dom), *self.gens) def unify(f, g): """ Make ``f`` and ``g`` belong to the same domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f, g = Poly(x/2 + 1), Poly(2*x + 1) >>> f Poly(1/2*x + 1, x, domain='QQ') >>> g Poly(2*x + 1, x, domain='ZZ') >>> F, G = f.unify(g) >>> F Poly(1/2*x + 1, x, domain='QQ') >>> G Poly(2*x + 1, x, domain='QQ') """ _, per, F, G = f._unify(g) return per(F), per(G) def _unify(f, g): g = sympify(g) if not g.is_Poly: try: return f.rep.dom, f.per, f.rep, f.rep.per(f.rep.dom.from_sympy(g)) except CoercionFailed: raise UnificationFailed("can't unify %s with %s" % (f, g)) if isinstance(f.rep, DMP) and isinstance(g.rep, DMP): gens = _unify_gens(f.gens, g.gens) dom, lev = f.rep.dom.unify(g.rep.dom, gens), len(gens) - 1 if f.gens != gens: f_monoms, f_coeffs = _dict_reorder( f.rep.to_dict(), f.gens, gens) if f.rep.dom != dom: f_coeffs = [dom.convert(c, f.rep.dom) for c in f_coeffs] F = DMP(dict(list(zip(f_monoms, f_coeffs))), dom, lev) else: F = f.rep.convert(dom) if g.gens != gens: g_monoms, g_coeffs = _dict_reorder( g.rep.to_dict(), g.gens, gens) if g.rep.dom != dom: g_coeffs = [dom.convert(c, g.rep.dom) for c in g_coeffs] G = DMP(dict(list(zip(g_monoms, g_coeffs))), dom, lev) else: G = g.rep.convert(dom) else: raise UnificationFailed("can't unify %s with %s" % (f, g)) cls = f.__class__ def per(rep, dom=dom, gens=gens, remove=None): if remove is not None: gens = gens[:remove] + gens[remove + 1:] if not gens: return dom.to_sympy(rep) return cls.new(rep, *gens) return dom, per, F, G def per(f, rep, gens=None, remove=None): """ Create a Poly out of the given representation. Examples ======== >>> from sympy import Poly, ZZ >>> from sympy.abc import x, y >>> from sympy.polys.polyclasses import DMP >>> a = Poly(x**2 + 1) >>> a.per(DMP([ZZ(1), ZZ(1)], ZZ), gens=[y]) Poly(y + 1, y, domain='ZZ') """ if gens is None: gens = f.gens if remove is not None: gens = gens[:remove] + gens[remove + 1:] if not gens: return f.rep.dom.to_sympy(rep) return f.__class__.new(rep, *gens) def set_domain(f, domain): """Set the ground domain of ``f``. """ opt = options.build_options(f.gens, {'domain': domain}) return f.per(f.rep.convert(opt.domain)) def get_domain(f): """Get the ground domain of ``f``. """ return f.rep.dom def set_modulus(f, modulus): """ Set the modulus of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(5*x**2 + 2*x - 1, x).set_modulus(2) Poly(x**2 + 1, x, modulus=2) """ modulus = options.Modulus.preprocess(modulus) return f.set_domain(FF(modulus)) def get_modulus(f): """ Get the modulus of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, modulus=2).get_modulus() 2 """ domain = f.get_domain() if domain.is_FiniteField: return Integer(domain.characteristic()) else: raise PolynomialError("not a polynomial over a Galois field") def _eval_subs(f, old, new): """Internal implementation of :func:`subs`. """ if old in f.gens: if new.is_number: return f.eval(old, new) else: try: return f.replace(old, new) except PolynomialError: pass return f.as_expr().subs(old, new) def exclude(f): """ Remove unnecessary generators from ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import a, b, c, d, x >>> Poly(a + x, a, b, c, d, x).exclude() Poly(a + x, a, x, domain='ZZ') """ J, new = f.rep.exclude() gens = [] for j in range(len(f.gens)): if j not in J: gens.append(f.gens[j]) return f.per(new, gens=gens) def replace(f, x, y=None, **_ignore): # XXX this does not match Basic's signature """ Replace ``x`` with ``y`` in generators list. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + 1, x).replace(x, y) Poly(y**2 + 1, y, domain='ZZ') """ if y is None: if f.is_univariate: x, y = f.gen, x else: raise PolynomialError( "syntax supported only in univariate case") if x == y or x not in f.gens: return f if x in f.gens and y not in f.gens: dom = f.get_domain() if not dom.is_Composite or y not in dom.symbols: gens = list(f.gens) gens[gens.index(x)] = y return f.per(f.rep, gens=gens) raise PolynomialError("can't replace %s with %s in %s" % (x, y, f)) def match(f, *args, **kwargs): """Match expression from Poly. See Basic.match()""" return f.as_expr().match(*args, **kwargs) def reorder(f, *gens, **args): """ Efficiently apply new order of generators. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + x*y**2, x, y).reorder(y, x) Poly(y**2*x + x**2, y, x, domain='ZZ') """ opt = options.Options((), args) if not gens: gens = _sort_gens(f.gens, opt=opt) elif set(f.gens) != set(gens): raise PolynomialError( "generators list can differ only up to order of elements") rep = dict(list(zip(*_dict_reorder(f.rep.to_dict(), f.gens, gens)))) return f.per(DMP(rep, f.rep.dom, len(gens) - 1), gens=gens) def ltrim(f, gen): """ Remove dummy generators from ``f`` that are to the left of specified ``gen`` in the generators as ordered. When ``gen`` is an integer, it refers to the generator located at that position within the tuple of generators of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y, z >>> Poly(y**2 + y*z**2, x, y, z).ltrim(y) Poly(y**2 + y*z**2, y, z, domain='ZZ') >>> Poly(z, x, y, z).ltrim(-1) Poly(z, z, domain='ZZ') """ rep = f.as_dict(native=True) j = f._gen_to_level(gen) terms = {} for monom, coeff in rep.items(): if any(monom[:j]): # some generator is used in the portion to be trimmed raise PolynomialError("can't left trim %s" % f) terms[monom[j:]] = coeff gens = f.gens[j:] return f.new(DMP.from_dict(terms, len(gens) - 1, f.rep.dom), *gens) def has_only_gens(f, *gens): """ Return ``True`` if ``Poly(f, *gens)`` retains ground domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y, z >>> Poly(x*y + 1, x, y, z).has_only_gens(x, y) True >>> Poly(x*y + z, x, y, z).has_only_gens(x, y) False """ indices = set() for gen in gens: try: index = f.gens.index(gen) except ValueError: raise GeneratorsError( "%s doesn't have %s as generator" % (f, gen)) else: indices.add(index) for monom in f.monoms(): for i, elt in enumerate(monom): if i not in indices and elt: return False return True def to_ring(f): """ Make the ground domain a ring. Examples ======== >>> from sympy import Poly, QQ >>> from sympy.abc import x >>> Poly(x**2 + 1, domain=QQ).to_ring() Poly(x**2 + 1, x, domain='ZZ') """ if hasattr(f.rep, 'to_ring'): result = f.rep.to_ring() else: # pragma: no cover raise OperationNotSupported(f, 'to_ring') return f.per(result) def to_field(f): """ Make the ground domain a field. Examples ======== >>> from sympy import Poly, ZZ >>> from sympy.abc import x >>> Poly(x**2 + 1, x, domain=ZZ).to_field() Poly(x**2 + 1, x, domain='QQ') """ if hasattr(f.rep, 'to_field'): result = f.rep.to_field() else: # pragma: no cover raise OperationNotSupported(f, 'to_field') return f.per(result) def to_exact(f): """ Make the ground domain exact. Examples ======== >>> from sympy import Poly, RR >>> from sympy.abc import x >>> Poly(x**2 + 1.0, x, domain=RR).to_exact() Poly(x**2 + 1, x, domain='QQ') """ if hasattr(f.rep, 'to_exact'): result = f.rep.to_exact() else: # pragma: no cover raise OperationNotSupported(f, 'to_exact') return f.per(result) def retract(f, field=None): """ Recalculate the ground domain of a polynomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = Poly(x**2 + 1, x, domain='QQ[y]') >>> f Poly(x**2 + 1, x, domain='QQ[y]') >>> f.retract() Poly(x**2 + 1, x, domain='ZZ') >>> f.retract(field=True) Poly(x**2 + 1, x, domain='QQ') """ dom, rep = construct_domain(f.as_dict(zero=True), field=field, composite=f.domain.is_Composite or None) return f.from_dict(rep, f.gens, domain=dom) def slice(f, x, m, n=None): """Take a continuous subsequence of terms of ``f``. """ if n is None: j, m, n = 0, x, m else: j = f._gen_to_level(x) m, n = int(m), int(n) if hasattr(f.rep, 'slice'): result = f.rep.slice(m, n, j) else: # pragma: no cover raise OperationNotSupported(f, 'slice') return f.per(result) def coeffs(f, order=None): """ Returns all non-zero coefficients from ``f`` in lex order. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 + 2*x + 3, x).coeffs() [1, 2, 3] See Also ======== all_coeffs coeff_monomial nth """ return [f.rep.dom.to_sympy(c) for c in f.rep.coeffs(order=order)] def monoms(f, order=None): """ Returns all non-zero monomials from ``f`` in lex order. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + 2*x*y**2 + x*y + 3*y, x, y).monoms() [(2, 0), (1, 2), (1, 1), (0, 1)] See Also ======== all_monoms """ return f.rep.monoms(order=order) def terms(f, order=None): """ Returns all non-zero terms from ``f`` in lex order. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + 2*x*y**2 + x*y + 3*y, x, y).terms() [((2, 0), 1), ((1, 2), 2), ((1, 1), 1), ((0, 1), 3)] See Also ======== all_terms """ return [(m, f.rep.dom.to_sympy(c)) for m, c in f.rep.terms(order=order)] def all_coeffs(f): """ Returns all coefficients from a univariate polynomial ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 + 2*x - 1, x).all_coeffs() [1, 0, 2, -1] """ return [f.rep.dom.to_sympy(c) for c in f.rep.all_coeffs()] def all_monoms(f): """ Returns all monomials from a univariate polynomial ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 + 2*x - 1, x).all_monoms() [(3,), (2,), (1,), (0,)] See Also ======== all_terms """ return f.rep.all_monoms() def all_terms(f): """ Returns all terms from a univariate polynomial ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 + 2*x - 1, x).all_terms() [((3,), 1), ((2,), 0), ((1,), 2), ((0,), -1)] """ return [(m, f.rep.dom.to_sympy(c)) for m, c in f.rep.all_terms()] def termwise(f, func, *gens, **args): """ Apply a function to all terms of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> def func(k, coeff): ... k = k[0] ... return coeff//10**(2-k) >>> Poly(x**2 + 20*x + 400).termwise(func) Poly(x**2 + 2*x + 4, x, domain='ZZ') """ terms = {} for monom, coeff in f.terms(): result = func(monom, coeff) if isinstance(result, tuple): monom, coeff = result else: coeff = result if coeff: if monom not in terms: terms[monom] = coeff else: raise PolynomialError( "%s monomial was generated twice" % monom) return f.from_dict(terms, *(gens or f.gens), **args) def length(f): """ Returns the number of non-zero terms in ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 2*x - 1).length() 3 """ return len(f.as_dict()) def as_dict(f, native=False, zero=False): """ Switch to a ``dict`` representation. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + 2*x*y**2 - y, x, y).as_dict() {(0, 1): -1, (1, 2): 2, (2, 0): 1} """ if native: return f.rep.to_dict(zero=zero) else: return f.rep.to_sympy_dict(zero=zero) def as_list(f, native=False): """Switch to a ``list`` representation. """ if native: return f.rep.to_list() else: return f.rep.to_sympy_list() def as_expr(f, *gens): """ Convert a Poly instance to an Expr instance. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> f = Poly(x**2 + 2*x*y**2 - y, x, y) >>> f.as_expr() x**2 + 2*x*y**2 - y >>> f.as_expr({x: 5}) 10*y**2 - y + 25 >>> f.as_expr(5, 6) 379 """ if not gens: return f.expr if len(gens) == 1 and isinstance(gens[0], dict): mapping = gens[0] gens = list(f.gens) for gen, value in mapping.items(): try: index = gens.index(gen) except ValueError: raise GeneratorsError( "%s doesn't have %s as generator" % (f, gen)) else: gens[index] = value return basic_from_dict(f.rep.to_sympy_dict(), *gens) def as_poly(self, *gens, **args): """Converts ``self`` to a polynomial or returns ``None``. >>> from sympy import sin >>> from sympy.abc import x, y >>> print((x**2 + x*y).as_poly()) Poly(x**2 + x*y, x, y, domain='ZZ') >>> print((x**2 + x*y).as_poly(x, y)) Poly(x**2 + x*y, x, y, domain='ZZ') >>> print((x**2 + sin(y)).as_poly(x, y)) None """ try: poly = Poly(self, *gens, **args) if not poly.is_Poly: return None else: return poly except PolynomialError: return None def lift(f): """ Convert algebraic coefficients to rationals. Examples ======== >>> from sympy import Poly, I >>> from sympy.abc import x >>> Poly(x**2 + I*x + 1, x, extension=I).lift() Poly(x**4 + 3*x**2 + 1, x, domain='QQ') """ if hasattr(f.rep, 'lift'): result = f.rep.lift() else: # pragma: no cover raise OperationNotSupported(f, 'lift') return f.per(result) def deflate(f): """ Reduce degree of ``f`` by mapping ``x_i**m`` to ``y_i``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**6*y**2 + x**3 + 1, x, y).deflate() ((3, 2), Poly(x**2*y + x + 1, x, y, domain='ZZ')) """ if hasattr(f.rep, 'deflate'): J, result = f.rep.deflate() else: # pragma: no cover raise OperationNotSupported(f, 'deflate') return J, f.per(result) def inject(f, front=False): """ Inject ground domain generators into ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> f = Poly(x**2*y + x*y**3 + x*y + 1, x) >>> f.inject() Poly(x**2*y + x*y**3 + x*y + 1, x, y, domain='ZZ') >>> f.inject(front=True) Poly(y**3*x + y*x**2 + y*x + 1, y, x, domain='ZZ') """ dom = f.rep.dom if dom.is_Numerical: return f elif not dom.is_Poly: raise DomainError("can't inject generators over %s" % dom) if hasattr(f.rep, 'inject'): result = f.rep.inject(front=front) else: # pragma: no cover raise OperationNotSupported(f, 'inject') if front: gens = dom.symbols + f.gens else: gens = f.gens + dom.symbols return f.new(result, *gens) def eject(f, *gens): """ Eject selected generators into the ground domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> f = Poly(x**2*y + x*y**3 + x*y + 1, x, y) >>> f.eject(x) Poly(x*y**3 + (x**2 + x)*y + 1, y, domain='ZZ[x]') >>> f.eject(y) Poly(y*x**2 + (y**3 + y)*x + 1, x, domain='ZZ[y]') """ dom = f.rep.dom if not dom.is_Numerical: raise DomainError("can't eject generators over %s" % dom) k = len(gens) if f.gens[:k] == gens: _gens, front = f.gens[k:], True elif f.gens[-k:] == gens: _gens, front = f.gens[:-k], False else: raise NotImplementedError( "can only eject front or back generators") dom = dom.inject(*gens) if hasattr(f.rep, 'eject'): result = f.rep.eject(dom, front=front) else: # pragma: no cover raise OperationNotSupported(f, 'eject') return f.new(result, *_gens) def terms_gcd(f): """ Remove GCD of terms from the polynomial ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**6*y**2 + x**3*y, x, y).terms_gcd() ((3, 1), Poly(x**3*y + 1, x, y, domain='ZZ')) """ if hasattr(f.rep, 'terms_gcd'): J, result = f.rep.terms_gcd() else: # pragma: no cover raise OperationNotSupported(f, 'terms_gcd') return J, f.per(result) def add_ground(f, coeff): """ Add an element of the ground domain to ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x + 1).add_ground(2) Poly(x + 3, x, domain='ZZ') """ if hasattr(f.rep, 'add_ground'): result = f.rep.add_ground(coeff) else: # pragma: no cover raise OperationNotSupported(f, 'add_ground') return f.per(result) def sub_ground(f, coeff): """ Subtract an element of the ground domain from ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x + 1).sub_ground(2) Poly(x - 1, x, domain='ZZ') """ if hasattr(f.rep, 'sub_ground'): result = f.rep.sub_ground(coeff) else: # pragma: no cover raise OperationNotSupported(f, 'sub_ground') return f.per(result) def mul_ground(f, coeff): """ Multiply ``f`` by a an element of the ground domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x + 1).mul_ground(2) Poly(2*x + 2, x, domain='ZZ') """ if hasattr(f.rep, 'mul_ground'): result = f.rep.mul_ground(coeff) else: # pragma: no cover raise OperationNotSupported(f, 'mul_ground') return f.per(result) def quo_ground(f, coeff): """ Quotient of ``f`` by a an element of the ground domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x + 4).quo_ground(2) Poly(x + 2, x, domain='ZZ') >>> Poly(2*x + 3).quo_ground(2) Poly(x + 1, x, domain='ZZ') """ if hasattr(f.rep, 'quo_ground'): result = f.rep.quo_ground(coeff) else: # pragma: no cover raise OperationNotSupported(f, 'quo_ground') return f.per(result) def exquo_ground(f, coeff): """ Exact quotient of ``f`` by a an element of the ground domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x + 4).exquo_ground(2) Poly(x + 2, x, domain='ZZ') >>> Poly(2*x + 3).exquo_ground(2) Traceback (most recent call last): ... ExactQuotientFailed: 2 does not divide 3 in ZZ """ if hasattr(f.rep, 'exquo_ground'): result = f.rep.exquo_ground(coeff) else: # pragma: no cover raise OperationNotSupported(f, 'exquo_ground') return f.per(result) def abs(f): """ Make all coefficients in ``f`` positive. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).abs() Poly(x**2 + 1, x, domain='ZZ') """ if hasattr(f.rep, 'abs'): result = f.rep.abs() else: # pragma: no cover raise OperationNotSupported(f, 'abs') return f.per(result) def neg(f): """ Negate all coefficients in ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).neg() Poly(-x**2 + 1, x, domain='ZZ') >>> -Poly(x**2 - 1, x) Poly(-x**2 + 1, x, domain='ZZ') """ if hasattr(f.rep, 'neg'): result = f.rep.neg() else: # pragma: no cover raise OperationNotSupported(f, 'neg') return f.per(result) def add(f, g): """ Add two polynomials ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).add(Poly(x - 2, x)) Poly(x**2 + x - 1, x, domain='ZZ') >>> Poly(x**2 + 1, x) + Poly(x - 2, x) Poly(x**2 + x - 1, x, domain='ZZ') """ g = sympify(g) if not g.is_Poly: return f.add_ground(g) _, per, F, G = f._unify(g) if hasattr(f.rep, 'add'): result = F.add(G) else: # pragma: no cover raise OperationNotSupported(f, 'add') return per(result) def sub(f, g): """ Subtract two polynomials ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).sub(Poly(x - 2, x)) Poly(x**2 - x + 3, x, domain='ZZ') >>> Poly(x**2 + 1, x) - Poly(x - 2, x) Poly(x**2 - x + 3, x, domain='ZZ') """ g = sympify(g) if not g.is_Poly: return f.sub_ground(g) _, per, F, G = f._unify(g) if hasattr(f.rep, 'sub'): result = F.sub(G) else: # pragma: no cover raise OperationNotSupported(f, 'sub') return per(result) def mul(f, g): """ Multiply two polynomials ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).mul(Poly(x - 2, x)) Poly(x**3 - 2*x**2 + x - 2, x, domain='ZZ') >>> Poly(x**2 + 1, x)*Poly(x - 2, x) Poly(x**3 - 2*x**2 + x - 2, x, domain='ZZ') """ g = sympify(g) if not g.is_Poly: return f.mul_ground(g) _, per, F, G = f._unify(g) if hasattr(f.rep, 'mul'): result = F.mul(G) else: # pragma: no cover raise OperationNotSupported(f, 'mul') return per(result) def sqr(f): """ Square a polynomial ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x - 2, x).sqr() Poly(x**2 - 4*x + 4, x, domain='ZZ') >>> Poly(x - 2, x)**2 Poly(x**2 - 4*x + 4, x, domain='ZZ') """ if hasattr(f.rep, 'sqr'): result = f.rep.sqr() else: # pragma: no cover raise OperationNotSupported(f, 'sqr') return f.per(result) def pow(f, n): """ Raise ``f`` to a non-negative power ``n``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x - 2, x).pow(3) Poly(x**3 - 6*x**2 + 12*x - 8, x, domain='ZZ') >>> Poly(x - 2, x)**3 Poly(x**3 - 6*x**2 + 12*x - 8, x, domain='ZZ') """ n = int(n) if hasattr(f.rep, 'pow'): result = f.rep.pow(n) else: # pragma: no cover raise OperationNotSupported(f, 'pow') return f.per(result) def pdiv(f, g): """ Polynomial pseudo-division of ``f`` by ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).pdiv(Poly(2*x - 4, x)) (Poly(2*x + 4, x, domain='ZZ'), Poly(20, x, domain='ZZ')) """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'pdiv'): q, r = F.pdiv(G) else: # pragma: no cover raise OperationNotSupported(f, 'pdiv') return per(q), per(r) def prem(f, g): """ Polynomial pseudo-remainder of ``f`` by ``g``. Caveat: The function prem(f, g, x) can be safely used to compute in Z[x] _only_ subresultant polynomial remainder sequences (prs's). To safely compute Euclidean and Sturmian prs's in Z[x] employ anyone of the corresponding functions found in the module sympy.polys.subresultants_qq_zz. The functions in the module with suffix _pg compute prs's in Z[x] employing rem(f, g, x), whereas the functions with suffix _amv compute prs's in Z[x] employing rem_z(f, g, x). The function rem_z(f, g, x) differs from prem(f, g, x) in that to compute the remainder polynomials in Z[x] it premultiplies the divident times the absolute value of the leading coefficient of the divisor raised to the power degree(f, x) - degree(g, x) + 1. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).prem(Poly(2*x - 4, x)) Poly(20, x, domain='ZZ') """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'prem'): result = F.prem(G) else: # pragma: no cover raise OperationNotSupported(f, 'prem') return per(result) def pquo(f, g): """ Polynomial pseudo-quotient of ``f`` by ``g``. See the Caveat note in the function prem(f, g). Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).pquo(Poly(2*x - 4, x)) Poly(2*x + 4, x, domain='ZZ') >>> Poly(x**2 - 1, x).pquo(Poly(2*x - 2, x)) Poly(2*x + 2, x, domain='ZZ') """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'pquo'): result = F.pquo(G) else: # pragma: no cover raise OperationNotSupported(f, 'pquo') return per(result) def pexquo(f, g): """ Polynomial exact pseudo-quotient of ``f`` by ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).pexquo(Poly(2*x - 2, x)) Poly(2*x + 2, x, domain='ZZ') >>> Poly(x**2 + 1, x).pexquo(Poly(2*x - 4, x)) Traceback (most recent call last): ... ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'pexquo'): try: result = F.pexquo(G) except ExactQuotientFailed as exc: raise exc.new(f.as_expr(), g.as_expr()) else: # pragma: no cover raise OperationNotSupported(f, 'pexquo') return per(result) def div(f, g, auto=True): """ Polynomial division with remainder of ``f`` by ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).div(Poly(2*x - 4, x)) (Poly(1/2*x + 1, x, domain='QQ'), Poly(5, x, domain='QQ')) >>> Poly(x**2 + 1, x).div(Poly(2*x - 4, x), auto=False) (Poly(0, x, domain='ZZ'), Poly(x**2 + 1, x, domain='ZZ')) """ dom, per, F, G = f._unify(g) retract = False if auto and dom.is_Ring and not dom.is_Field: F, G = F.to_field(), G.to_field() retract = True if hasattr(f.rep, 'div'): q, r = F.div(G) else: # pragma: no cover raise OperationNotSupported(f, 'div') if retract: try: Q, R = q.to_ring(), r.to_ring() except CoercionFailed: pass else: q, r = Q, R return per(q), per(r) def rem(f, g, auto=True): """ Computes the polynomial remainder of ``f`` by ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).rem(Poly(2*x - 4, x)) Poly(5, x, domain='ZZ') >>> Poly(x**2 + 1, x).rem(Poly(2*x - 4, x), auto=False) Poly(x**2 + 1, x, domain='ZZ') """ dom, per, F, G = f._unify(g) retract = False if auto and dom.is_Ring and not dom.is_Field: F, G = F.to_field(), G.to_field() retract = True if hasattr(f.rep, 'rem'): r = F.rem(G) else: # pragma: no cover raise OperationNotSupported(f, 'rem') if retract: try: r = r.to_ring() except CoercionFailed: pass return per(r) def quo(f, g, auto=True): """ Computes polynomial quotient of ``f`` by ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).quo(Poly(2*x - 4, x)) Poly(1/2*x + 1, x, domain='QQ') >>> Poly(x**2 - 1, x).quo(Poly(x - 1, x)) Poly(x + 1, x, domain='ZZ') """ dom, per, F, G = f._unify(g) retract = False if auto and dom.is_Ring and not dom.is_Field: F, G = F.to_field(), G.to_field() retract = True if hasattr(f.rep, 'quo'): q = F.quo(G) else: # pragma: no cover raise OperationNotSupported(f, 'quo') if retract: try: q = q.to_ring() except CoercionFailed: pass return per(q) def exquo(f, g, auto=True): """ Computes polynomial exact quotient of ``f`` by ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).exquo(Poly(x - 1, x)) Poly(x + 1, x, domain='ZZ') >>> Poly(x**2 + 1, x).exquo(Poly(2*x - 4, x)) Traceback (most recent call last): ... ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 """ dom, per, F, G = f._unify(g) retract = False if auto and dom.is_Ring and not dom.is_Field: F, G = F.to_field(), G.to_field() retract = True if hasattr(f.rep, 'exquo'): try: q = F.exquo(G) except ExactQuotientFailed as exc: raise exc.new(f.as_expr(), g.as_expr()) else: # pragma: no cover raise OperationNotSupported(f, 'exquo') if retract: try: q = q.to_ring() except CoercionFailed: pass return per(q) def _gen_to_level(f, gen): """Returns level associated with the given generator. """ if isinstance(gen, int): length = len(f.gens) if -length <= gen < length: if gen < 0: return length + gen else: return gen else: raise PolynomialError("-%s <= gen < %s expected, got %s" % (length, length, gen)) else: try: return f.gens.index(sympify(gen)) except ValueError: raise PolynomialError( "a valid generator expected, got %s" % gen) def degree(f, gen=0): """ Returns degree of ``f`` in ``x_j``. The degree of 0 is negative infinity. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + y*x + 1, x, y).degree() 2 >>> Poly(x**2 + y*x + y, x, y).degree(y) 1 >>> Poly(0, x).degree() -oo """ j = f._gen_to_level(gen) if hasattr(f.rep, 'degree'): return f.rep.degree(j) else: # pragma: no cover raise OperationNotSupported(f, 'degree') def degree_list(f): """ Returns a list of degrees of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + y*x + 1, x, y).degree_list() (2, 1) """ if hasattr(f.rep, 'degree_list'): return f.rep.degree_list() else: # pragma: no cover raise OperationNotSupported(f, 'degree_list') def total_degree(f): """ Returns the total degree of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + y*x + 1, x, y).total_degree() 2 >>> Poly(x + y**5, x, y).total_degree() 5 """ if hasattr(f.rep, 'total_degree'): return f.rep.total_degree() else: # pragma: no cover raise OperationNotSupported(f, 'total_degree') def homogenize(f, s): """ Returns the homogeneous polynomial of ``f``. A homogeneous polynomial is a polynomial whose all monomials with non-zero coefficients have the same total degree. If you only want to check if a polynomial is homogeneous, then use :func:`Poly.is_homogeneous`. If you want not only to check if a polynomial is homogeneous but also compute its homogeneous order, then use :func:`Poly.homogeneous_order`. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y, z >>> f = Poly(x**5 + 2*x**2*y**2 + 9*x*y**3) >>> f.homogenize(z) Poly(x**5 + 2*x**2*y**2*z + 9*x*y**3*z, x, y, z, domain='ZZ') """ if not isinstance(s, Symbol): raise TypeError("``Symbol`` expected, got %s" % type(s)) if s in f.gens: i = f.gens.index(s) gens = f.gens else: i = len(f.gens) gens = f.gens + (s,) if hasattr(f.rep, 'homogenize'): return f.per(f.rep.homogenize(i), gens=gens) raise OperationNotSupported(f, 'homogeneous_order') def homogeneous_order(f): """ Returns the homogeneous order of ``f``. A homogeneous polynomial is a polynomial whose all monomials with non-zero coefficients have the same total degree. This degree is the homogeneous order of ``f``. If you only want to check if a polynomial is homogeneous, then use :func:`Poly.is_homogeneous`. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> f = Poly(x**5 + 2*x**3*y**2 + 9*x*y**4) >>> f.homogeneous_order() 5 """ if hasattr(f.rep, 'homogeneous_order'): return f.rep.homogeneous_order() else: # pragma: no cover raise OperationNotSupported(f, 'homogeneous_order') def LC(f, order=None): """ Returns the leading coefficient of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(4*x**3 + 2*x**2 + 3*x, x).LC() 4 """ if order is not None: return f.coeffs(order)[0] if hasattr(f.rep, 'LC'): result = f.rep.LC() else: # pragma: no cover raise OperationNotSupported(f, 'LC') return f.rep.dom.to_sympy(result) def TC(f): """ Returns the trailing coefficient of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 + 2*x**2 + 3*x, x).TC() 0 """ if hasattr(f.rep, 'TC'): result = f.rep.TC() else: # pragma: no cover raise OperationNotSupported(f, 'TC') return f.rep.dom.to_sympy(result) def EC(f, order=None): """ Returns the last non-zero coefficient of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 + 2*x**2 + 3*x, x).EC() 3 """ if hasattr(f.rep, 'coeffs'): return f.coeffs(order)[-1] else: # pragma: no cover raise OperationNotSupported(f, 'EC') def coeff_monomial(f, monom): """ Returns the coefficient of ``monom`` in ``f`` if there, else None. Examples ======== >>> from sympy import Poly, exp >>> from sympy.abc import x, y >>> p = Poly(24*x*y*exp(8) + 23*x, x, y) >>> p.coeff_monomial(x) 23 >>> p.coeff_monomial(y) 0 >>> p.coeff_monomial(x*y) 24*exp(8) Note that ``Expr.coeff()`` behaves differently, collecting terms if possible; the Poly must be converted to an Expr to use that method, however: >>> p.as_expr().coeff(x) 24*y*exp(8) + 23 >>> p.as_expr().coeff(y) 24*x*exp(8) >>> p.as_expr().coeff(x*y) 24*exp(8) See Also ======== nth: more efficient query using exponents of the monomial's generators """ return f.nth(*Monomial(monom, f.gens).exponents) def nth(f, *N): """ Returns the ``n``-th coefficient of ``f`` where ``N`` are the exponents of the generators in the term of interest. Examples ======== >>> from sympy import Poly, sqrt >>> from sympy.abc import x, y >>> Poly(x**3 + 2*x**2 + 3*x, x).nth(2) 2 >>> Poly(x**3 + 2*x*y**2 + y**2, x, y).nth(1, 2) 2 >>> Poly(4*sqrt(x)*y) Poly(4*y*(sqrt(x)), y, sqrt(x), domain='ZZ') >>> _.nth(1, 1) 4 See Also ======== coeff_monomial """ if hasattr(f.rep, 'nth'): if len(N) != len(f.gens): raise ValueError('exponent of each generator must be specified') result = f.rep.nth(*list(map(int, N))) else: # pragma: no cover raise OperationNotSupported(f, 'nth') return f.rep.dom.to_sympy(result) def coeff(f, x, n=1, right=False): # the semantics of coeff_monomial and Expr.coeff are different; # if someone is working with a Poly, they should be aware of the # differences and chose the method best suited for the query. # Alternatively, a pure-polys method could be written here but # at this time the ``right`` keyword would be ignored because Poly # doesn't work with non-commutatives. raise NotImplementedError( 'Either convert to Expr with `as_expr` method ' 'to use Expr\'s coeff method or else use the ' '`coeff_monomial` method of Polys.') def LM(f, order=None): """ Returns the leading monomial of ``f``. The Leading monomial signifies the monomial having the highest power of the principal generator in the expression f. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).LM() x**2*y**0 """ return Monomial(f.monoms(order)[0], f.gens) def EM(f, order=None): """ Returns the last non-zero monomial of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).EM() x**0*y**1 """ return Monomial(f.monoms(order)[-1], f.gens) def LT(f, order=None): """ Returns the leading term of ``f``. The Leading term signifies the term having the highest power of the principal generator in the expression f along with its coefficient. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).LT() (x**2*y**0, 4) """ monom, coeff = f.terms(order)[0] return Monomial(monom, f.gens), coeff def ET(f, order=None): """ Returns the last non-zero term of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(4*x**2 + 2*x*y**2 + x*y + 3*y, x, y).ET() (x**0*y**1, 3) """ monom, coeff = f.terms(order)[-1] return Monomial(monom, f.gens), coeff def max_norm(f): """ Returns maximum norm of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(-x**2 + 2*x - 3, x).max_norm() 3 """ if hasattr(f.rep, 'max_norm'): result = f.rep.max_norm() else: # pragma: no cover raise OperationNotSupported(f, 'max_norm') return f.rep.dom.to_sympy(result) def l1_norm(f): """ Returns l1 norm of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(-x**2 + 2*x - 3, x).l1_norm() 6 """ if hasattr(f.rep, 'l1_norm'): result = f.rep.l1_norm() else: # pragma: no cover raise OperationNotSupported(f, 'l1_norm') return f.rep.dom.to_sympy(result) def clear_denoms(self, convert=False): """ Clear denominators, but keep the ground domain. Examples ======== >>> from sympy import Poly, S, QQ >>> from sympy.abc import x >>> f = Poly(x/2 + S(1)/3, x, domain=QQ) >>> f.clear_denoms() (6, Poly(3*x + 2, x, domain='QQ')) >>> f.clear_denoms(convert=True) (6, Poly(3*x + 2, x, domain='ZZ')) """ f = self if not f.rep.dom.is_Field: return S.One, f dom = f.get_domain() if dom.has_assoc_Ring: dom = f.rep.dom.get_ring() if hasattr(f.rep, 'clear_denoms'): coeff, result = f.rep.clear_denoms() else: # pragma: no cover raise OperationNotSupported(f, 'clear_denoms') coeff, f = dom.to_sympy(coeff), f.per(result) if not convert or not dom.has_assoc_Ring: return coeff, f else: return coeff, f.to_ring() def rat_clear_denoms(self, g): """ Clear denominators in a rational function ``f/g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> f = Poly(x**2/y + 1, x) >>> g = Poly(x**3 + y, x) >>> p, q = f.rat_clear_denoms(g) >>> p Poly(x**2 + y, x, domain='ZZ[y]') >>> q Poly(y*x**3 + y**2, x, domain='ZZ[y]') """ f = self dom, per, f, g = f._unify(g) f = per(f) g = per(g) if not (dom.is_Field and dom.has_assoc_Ring): return f, g a, f = f.clear_denoms(convert=True) b, g = g.clear_denoms(convert=True) f = f.mul_ground(b) g = g.mul_ground(a) return f, g def integrate(self, *specs, **args): """ Computes indefinite integral of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + 2*x + 1, x).integrate() Poly(1/3*x**3 + x**2 + x, x, domain='QQ') >>> Poly(x*y**2 + x, x, y).integrate((0, 1), (1, 0)) Poly(1/2*x**2*y**2 + 1/2*x**2, x, y, domain='QQ') """ f = self if args.get('auto', True) and f.rep.dom.is_Ring: f = f.to_field() if hasattr(f.rep, 'integrate'): if not specs: return f.per(f.rep.integrate(m=1)) rep = f.rep for spec in specs: if type(spec) is tuple: gen, m = spec else: gen, m = spec, 1 rep = rep.integrate(int(m), f._gen_to_level(gen)) return f.per(rep) else: # pragma: no cover raise OperationNotSupported(f, 'integrate') def diff(f, *specs, **kwargs): """ Computes partial derivative of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + 2*x + 1, x).diff() Poly(2*x + 2, x, domain='ZZ') >>> Poly(x*y**2 + x, x, y).diff((0, 0), (1, 1)) Poly(2*x*y, x, y, domain='ZZ') """ if not kwargs.get('evaluate', True): return Derivative(f, *specs, **kwargs) if hasattr(f.rep, 'diff'): if not specs: return f.per(f.rep.diff(m=1)) rep = f.rep for spec in specs: if type(spec) is tuple: gen, m = spec else: gen, m = spec, 1 rep = rep.diff(int(m), f._gen_to_level(gen)) return f.per(rep) else: # pragma: no cover raise OperationNotSupported(f, 'diff') _eval_derivative = diff def eval(self, x, a=None, auto=True): """ Evaluate ``f`` at ``a`` in the given variable. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y, z >>> Poly(x**2 + 2*x + 3, x).eval(2) 11 >>> Poly(2*x*y + 3*x + y + 2, x, y).eval(x, 2) Poly(5*y + 8, y, domain='ZZ') >>> f = Poly(2*x*y + 3*x + y + 2*z, x, y, z) >>> f.eval({x: 2}) Poly(5*y + 2*z + 6, y, z, domain='ZZ') >>> f.eval({x: 2, y: 5}) Poly(2*z + 31, z, domain='ZZ') >>> f.eval({x: 2, y: 5, z: 7}) 45 >>> f.eval((2, 5)) Poly(2*z + 31, z, domain='ZZ') >>> f(2, 5) Poly(2*z + 31, z, domain='ZZ') """ f = self if a is None: if isinstance(x, dict): mapping = x for gen, value in mapping.items(): f = f.eval(gen, value) return f elif isinstance(x, (tuple, list)): values = x if len(values) > len(f.gens): raise ValueError("too many values provided") for gen, value in zip(f.gens, values): f = f.eval(gen, value) return f else: j, a = 0, x else: j = f._gen_to_level(x) if not hasattr(f.rep, 'eval'): # pragma: no cover raise OperationNotSupported(f, 'eval') try: result = f.rep.eval(a, j) except CoercionFailed: if not auto: raise DomainError("can't evaluate at %s in %s" % (a, f.rep.dom)) else: a_domain, [a] = construct_domain([a]) new_domain = f.get_domain().unify_with_symbols(a_domain, f.gens) f = f.set_domain(new_domain) a = new_domain.convert(a, a_domain) result = f.rep.eval(a, j) return f.per(result, remove=j) def __call__(f, *values): """ Evaluate ``f`` at the give values. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y, z >>> f = Poly(2*x*y + 3*x + y + 2*z, x, y, z) >>> f(2) Poly(5*y + 2*z + 6, y, z, domain='ZZ') >>> f(2, 5) Poly(2*z + 31, z, domain='ZZ') >>> f(2, 5, 7) 45 """ return f.eval(values) def half_gcdex(f, g, auto=True): """ Half extended Euclidean algorithm of ``f`` and ``g``. Returns ``(s, h)`` such that ``h = gcd(f, g)`` and ``s*f = h (mod g)``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 >>> g = x**3 + x**2 - 4*x - 4 >>> Poly(f).half_gcdex(Poly(g)) (Poly(-1/5*x + 3/5, x, domain='QQ'), Poly(x + 1, x, domain='QQ')) """ dom, per, F, G = f._unify(g) if auto and dom.is_Ring: F, G = F.to_field(), G.to_field() if hasattr(f.rep, 'half_gcdex'): s, h = F.half_gcdex(G) else: # pragma: no cover raise OperationNotSupported(f, 'half_gcdex') return per(s), per(h) def gcdex(f, g, auto=True): """ Extended Euclidean algorithm of ``f`` and ``g``. Returns ``(s, t, h)`` such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 >>> g = x**3 + x**2 - 4*x - 4 >>> Poly(f).gcdex(Poly(g)) (Poly(-1/5*x + 3/5, x, domain='QQ'), Poly(1/5*x**2 - 6/5*x + 2, x, domain='QQ'), Poly(x + 1, x, domain='QQ')) """ dom, per, F, G = f._unify(g) if auto and dom.is_Ring: F, G = F.to_field(), G.to_field() if hasattr(f.rep, 'gcdex'): s, t, h = F.gcdex(G) else: # pragma: no cover raise OperationNotSupported(f, 'gcdex') return per(s), per(t), per(h) def invert(f, g, auto=True): """ Invert ``f`` modulo ``g`` when possible. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).invert(Poly(2*x - 1, x)) Poly(-4/3, x, domain='QQ') >>> Poly(x**2 - 1, x).invert(Poly(x - 1, x)) Traceback (most recent call last): ... NotInvertible: zero divisor """ dom, per, F, G = f._unify(g) if auto and dom.is_Ring: F, G = F.to_field(), G.to_field() if hasattr(f.rep, 'invert'): result = F.invert(G) else: # pragma: no cover raise OperationNotSupported(f, 'invert') return per(result) def revert(f, n): """ Compute ``f**(-1)`` mod ``x**n``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(1, x).revert(2) Poly(1, x, domain='ZZ') >>> Poly(1 + x, x).revert(1) Poly(1, x, domain='ZZ') >>> Poly(x**2 - 2, x).revert(2) Traceback (most recent call last): ... NotReversible: only units are reversible in a ring >>> Poly(1/x, x).revert(1) Traceback (most recent call last): ... PolynomialError: 1/x contains an element of the generators set """ if hasattr(f.rep, 'revert'): result = f.rep.revert(int(n)) else: # pragma: no cover raise OperationNotSupported(f, 'revert') return f.per(result) def subresultants(f, g): """ Computes the subresultant PRS of ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 1, x).subresultants(Poly(x**2 - 1, x)) [Poly(x**2 + 1, x, domain='ZZ'), Poly(x**2 - 1, x, domain='ZZ'), Poly(-2, x, domain='ZZ')] """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'subresultants'): result = F.subresultants(G) else: # pragma: no cover raise OperationNotSupported(f, 'subresultants') return list(map(per, result)) def resultant(f, g, includePRS=False): """ Computes the resultant of ``f`` and ``g`` via PRS. If includePRS=True, it includes the subresultant PRS in the result. Because the PRS is used to calculate the resultant, this is more efficient than calling :func:`subresultants` separately. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = Poly(x**2 + 1, x) >>> f.resultant(Poly(x**2 - 1, x)) 4 >>> f.resultant(Poly(x**2 - 1, x), includePRS=True) (4, [Poly(x**2 + 1, x, domain='ZZ'), Poly(x**2 - 1, x, domain='ZZ'), Poly(-2, x, domain='ZZ')]) """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'resultant'): if includePRS: result, R = F.resultant(G, includePRS=includePRS) else: result = F.resultant(G) else: # pragma: no cover raise OperationNotSupported(f, 'resultant') if includePRS: return (per(result, remove=0), list(map(per, R))) return per(result, remove=0) def discriminant(f): """ Computes the discriminant of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + 2*x + 3, x).discriminant() -8 """ if hasattr(f.rep, 'discriminant'): result = f.rep.discriminant() else: # pragma: no cover raise OperationNotSupported(f, 'discriminant') return f.per(result, remove=0) def dispersionset(f, g=None): r"""Compute the *dispersion set* of two polynomials. For two polynomials `f(x)` and `g(x)` with `\deg f > 0` and `\deg g > 0` the dispersion set `\operatorname{J}(f, g)` is defined as: .. math:: \operatorname{J}(f, g) & := \{a \in \mathbb{N}_0 | \gcd(f(x), g(x+a)) \neq 1\} \\ & = \{a \in \mathbb{N}_0 | \deg \gcd(f(x), g(x+a)) \geq 1\} For a single polynomial one defines `\operatorname{J}(f) := \operatorname{J}(f, f)`. Examples ======== >>> from sympy import poly >>> from sympy.polys.dispersion import dispersion, dispersionset >>> from sympy.abc import x Dispersion set and dispersion of a simple polynomial: >>> fp = poly((x - 3)*(x + 3), x) >>> sorted(dispersionset(fp)) [0, 6] >>> dispersion(fp) 6 Note that the definition of the dispersion is not symmetric: >>> fp = poly(x**4 - 3*x**2 + 1, x) >>> gp = fp.shift(-3) >>> sorted(dispersionset(fp, gp)) [2, 3, 4] >>> dispersion(fp, gp) 4 >>> sorted(dispersionset(gp, fp)) [] >>> dispersion(gp, fp) -oo Computing the dispersion also works over field extensions: >>> from sympy import sqrt >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') >>> sorted(dispersionset(fp, gp)) [2] >>> sorted(dispersionset(gp, fp)) [1, 4] We can even perform the computations for polynomials having symbolic coefficients: >>> from sympy.abc import a >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) >>> sorted(dispersionset(fp)) [0, 1] See Also ======== dispersion References ========== 1. [ManWright94]_ 2. [Koepf98]_ 3. [Abramov71]_ 4. [Man93]_ """ from sympy.polys.dispersion import dispersionset return dispersionset(f, g) def dispersion(f, g=None): r"""Compute the *dispersion* of polynomials. For two polynomials `f(x)` and `g(x)` with `\deg f > 0` and `\deg g > 0` the dispersion `\operatorname{dis}(f, g)` is defined as: .. math:: \operatorname{dis}(f, g) & := \max\{ J(f,g) \cup \{0\} \} \\ & = \max\{ \{a \in \mathbb{N} | \gcd(f(x), g(x+a)) \neq 1\} \cup \{0\} \} and for a single polynomial `\operatorname{dis}(f) := \operatorname{dis}(f, f)`. Examples ======== >>> from sympy import poly >>> from sympy.polys.dispersion import dispersion, dispersionset >>> from sympy.abc import x Dispersion set and dispersion of a simple polynomial: >>> fp = poly((x - 3)*(x + 3), x) >>> sorted(dispersionset(fp)) [0, 6] >>> dispersion(fp) 6 Note that the definition of the dispersion is not symmetric: >>> fp = poly(x**4 - 3*x**2 + 1, x) >>> gp = fp.shift(-3) >>> sorted(dispersionset(fp, gp)) [2, 3, 4] >>> dispersion(fp, gp) 4 >>> sorted(dispersionset(gp, fp)) [] >>> dispersion(gp, fp) -oo Computing the dispersion also works over field extensions: >>> from sympy import sqrt >>> fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') >>> gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') >>> sorted(dispersionset(fp, gp)) [2] >>> sorted(dispersionset(gp, fp)) [1, 4] We can even perform the computations for polynomials having symbolic coefficients: >>> from sympy.abc import a >>> fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) >>> sorted(dispersionset(fp)) [0, 1] See Also ======== dispersionset References ========== 1. [ManWright94]_ 2. [Koepf98]_ 3. [Abramov71]_ 4. [Man93]_ """ from sympy.polys.dispersion import dispersion return dispersion(f, g) def cofactors(f, g): """ Returns the GCD of ``f`` and ``g`` and their cofactors. Returns polynomials ``(h, cff, cfg)`` such that ``h = gcd(f, g)``, and ``cff = quo(f, h)`` and ``cfg = quo(g, h)`` are, so called, cofactors of ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).cofactors(Poly(x**2 - 3*x + 2, x)) (Poly(x - 1, x, domain='ZZ'), Poly(x + 1, x, domain='ZZ'), Poly(x - 2, x, domain='ZZ')) """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'cofactors'): h, cff, cfg = F.cofactors(G) else: # pragma: no cover raise OperationNotSupported(f, 'cofactors') return per(h), per(cff), per(cfg) def gcd(f, g): """ Returns the polynomial GCD of ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).gcd(Poly(x**2 - 3*x + 2, x)) Poly(x - 1, x, domain='ZZ') """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'gcd'): result = F.gcd(G) else: # pragma: no cover raise OperationNotSupported(f, 'gcd') return per(result) def lcm(f, g): """ Returns polynomial LCM of ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 1, x).lcm(Poly(x**2 - 3*x + 2, x)) Poly(x**3 - 2*x**2 - x + 2, x, domain='ZZ') """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'lcm'): result = F.lcm(G) else: # pragma: no cover raise OperationNotSupported(f, 'lcm') return per(result) def trunc(f, p): """ Reduce ``f`` modulo a constant ``p``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x**3 + 3*x**2 + 5*x + 7, x).trunc(3) Poly(-x**3 - x + 1, x, domain='ZZ') """ p = f.rep.dom.convert(p) if hasattr(f.rep, 'trunc'): result = f.rep.trunc(p) else: # pragma: no cover raise OperationNotSupported(f, 'trunc') return f.per(result) def monic(self, auto=True): """ Divides all coefficients by ``LC(f)``. Examples ======== >>> from sympy import Poly, ZZ >>> from sympy.abc import x >>> Poly(3*x**2 + 6*x + 9, x, domain=ZZ).monic() Poly(x**2 + 2*x + 3, x, domain='QQ') >>> Poly(3*x**2 + 4*x + 2, x, domain=ZZ).monic() Poly(x**2 + 4/3*x + 2/3, x, domain='QQ') """ f = self if auto and f.rep.dom.is_Ring: f = f.to_field() if hasattr(f.rep, 'monic'): result = f.rep.monic() else: # pragma: no cover raise OperationNotSupported(f, 'monic') return f.per(result) def content(f): """ Returns the GCD of polynomial coefficients. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(6*x**2 + 8*x + 12, x).content() 2 """ if hasattr(f.rep, 'content'): result = f.rep.content() else: # pragma: no cover raise OperationNotSupported(f, 'content') return f.rep.dom.to_sympy(result) def primitive(f): """ Returns the content and a primitive form of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x**2 + 8*x + 12, x).primitive() (2, Poly(x**2 + 4*x + 6, x, domain='ZZ')) """ if hasattr(f.rep, 'primitive'): cont, result = f.rep.primitive() else: # pragma: no cover raise OperationNotSupported(f, 'primitive') return f.rep.dom.to_sympy(cont), f.per(result) def compose(f, g): """ Computes the functional composition of ``f`` and ``g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + x, x).compose(Poly(x - 1, x)) Poly(x**2 - x, x, domain='ZZ') """ _, per, F, G = f._unify(g) if hasattr(f.rep, 'compose'): result = F.compose(G) else: # pragma: no cover raise OperationNotSupported(f, 'compose') return per(result) def decompose(f): """ Computes a functional decomposition of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**4 + 2*x**3 - x - 1, x, domain='ZZ').decompose() [Poly(x**2 - x - 1, x, domain='ZZ'), Poly(x**2 + x, x, domain='ZZ')] """ if hasattr(f.rep, 'decompose'): result = f.rep.decompose() else: # pragma: no cover raise OperationNotSupported(f, 'decompose') return list(map(f.per, result)) def shift(f, a): """ Efficiently compute Taylor shift ``f(x + a)``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 2*x + 1, x).shift(2) Poly(x**2 + 2*x + 1, x, domain='ZZ') """ if hasattr(f.rep, 'shift'): result = f.rep.shift(a) else: # pragma: no cover raise OperationNotSupported(f, 'shift') return f.per(result) def transform(f, p, q): """ Efficiently evaluate the functional transformation ``q**n * f(p/q)``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1, x), Poly(x - 1, x)) Poly(4, x, domain='ZZ') """ P, Q = p.unify(q) F, P = f.unify(P) F, Q = F.unify(Q) if hasattr(F.rep, 'transform'): result = F.rep.transform(P.rep, Q.rep) else: # pragma: no cover raise OperationNotSupported(F, 'transform') return F.per(result) def sturm(self, auto=True): """ Computes the Sturm sequence of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 - 2*x**2 + x - 3, x).sturm() [Poly(x**3 - 2*x**2 + x - 3, x, domain='QQ'), Poly(3*x**2 - 4*x + 1, x, domain='QQ'), Poly(2/9*x + 25/9, x, domain='QQ'), Poly(-2079/4, x, domain='QQ')] """ f = self if auto and f.rep.dom.is_Ring: f = f.to_field() if hasattr(f.rep, 'sturm'): result = f.rep.sturm() else: # pragma: no cover raise OperationNotSupported(f, 'sturm') return list(map(f.per, result)) def gff_list(f): """ Computes greatest factorial factorization of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = x**5 + 2*x**4 - x**3 - 2*x**2 >>> Poly(f).gff_list() [(Poly(x, x, domain='ZZ'), 1), (Poly(x + 2, x, domain='ZZ'), 4)] """ if hasattr(f.rep, 'gff_list'): result = f.rep.gff_list() else: # pragma: no cover raise OperationNotSupported(f, 'gff_list') return [(f.per(g), k) for g, k in result] def norm(f): """ Computes the product, ``Norm(f)``, of the conjugates of a polynomial ``f`` defined over a number field ``K``. Examples ======== >>> from sympy import Poly, sqrt >>> from sympy.abc import x >>> a, b = sqrt(2), sqrt(3) A polynomial over a quadratic extension. Two conjugates x - a and x + a. >>> f = Poly(x - a, x, extension=a) >>> f.norm() Poly(x**2 - 2, x, domain='QQ') A polynomial over a quartic extension. Four conjugates x - a, x - a, x + a and x + a. >>> f = Poly(x - a, x, extension=(a, b)) >>> f.norm() Poly(x**4 - 4*x**2 + 4, x, domain='QQ') """ if hasattr(f.rep, 'norm'): r = f.rep.norm() else: # pragma: no cover raise OperationNotSupported(f, 'norm') return f.per(r) def sqf_norm(f): """ Computes square-free norm of ``f``. Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))`` is a square-free polynomial over ``K``, where ``a`` is the algebraic extension of the ground domain. Examples ======== >>> from sympy import Poly, sqrt >>> from sympy.abc import x >>> s, f, r = Poly(x**2 + 1, x, extension=[sqrt(3)]).sqf_norm() >>> s 1 >>> f Poly(x**2 - 2*sqrt(3)*x + 4, x, domain='QQ') >>> r Poly(x**4 - 4*x**2 + 16, x, domain='QQ') """ if hasattr(f.rep, 'sqf_norm'): s, g, r = f.rep.sqf_norm() else: # pragma: no cover raise OperationNotSupported(f, 'sqf_norm') return s, f.per(g), f.per(r) def sqf_part(f): """ Computes square-free part of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**3 - 3*x - 2, x).sqf_part() Poly(x**2 - x - 2, x, domain='ZZ') """ if hasattr(f.rep, 'sqf_part'): result = f.rep.sqf_part() else: # pragma: no cover raise OperationNotSupported(f, 'sqf_part') return f.per(result) def sqf_list(f, all=False): """ Returns a list of square-free factors of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 >>> Poly(f).sqf_list() (2, [(Poly(x + 1, x, domain='ZZ'), 2), (Poly(x + 2, x, domain='ZZ'), 3)]) >>> Poly(f).sqf_list(all=True) (2, [(Poly(1, x, domain='ZZ'), 1), (Poly(x + 1, x, domain='ZZ'), 2), (Poly(x + 2, x, domain='ZZ'), 3)]) """ if hasattr(f.rep, 'sqf_list'): coeff, factors = f.rep.sqf_list(all) else: # pragma: no cover raise OperationNotSupported(f, 'sqf_list') return f.rep.dom.to_sympy(coeff), [(f.per(g), k) for g, k in factors] def sqf_list_include(f, all=False): """ Returns a list of square-free factors of ``f``. Examples ======== >>> from sympy import Poly, expand >>> from sympy.abc import x >>> f = expand(2*(x + 1)**3*x**4) >>> f 2*x**7 + 6*x**6 + 6*x**5 + 2*x**4 >>> Poly(f).sqf_list_include() [(Poly(2, x, domain='ZZ'), 1), (Poly(x + 1, x, domain='ZZ'), 3), (Poly(x, x, domain='ZZ'), 4)] >>> Poly(f).sqf_list_include(all=True) [(Poly(2, x, domain='ZZ'), 1), (Poly(1, x, domain='ZZ'), 2), (Poly(x + 1, x, domain='ZZ'), 3), (Poly(x, x, domain='ZZ'), 4)] """ if hasattr(f.rep, 'sqf_list_include'): factors = f.rep.sqf_list_include(all) else: # pragma: no cover raise OperationNotSupported(f, 'sqf_list_include') return [(f.per(g), k) for g, k in factors] def factor_list(f): """ Returns a list of irreducible factors of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> f = 2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y >>> Poly(f).factor_list() (2, [(Poly(x + y, x, y, domain='ZZ'), 1), (Poly(x**2 + 1, x, y, domain='ZZ'), 2)]) """ if hasattr(f.rep, 'factor_list'): try: coeff, factors = f.rep.factor_list() except DomainError: return S.One, [(f, 1)] else: # pragma: no cover raise OperationNotSupported(f, 'factor_list') return f.rep.dom.to_sympy(coeff), [(f.per(g), k) for g, k in factors] def factor_list_include(f): """ Returns a list of irreducible factors of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> f = 2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y >>> Poly(f).factor_list_include() [(Poly(2*x + 2*y, x, y, domain='ZZ'), 1), (Poly(x**2 + 1, x, y, domain='ZZ'), 2)] """ if hasattr(f.rep, 'factor_list_include'): try: factors = f.rep.factor_list_include() except DomainError: return [(f, 1)] else: # pragma: no cover raise OperationNotSupported(f, 'factor_list_include') return [(f.per(g), k) for g, k in factors] def intervals(f, all=False, eps=None, inf=None, sup=None, fast=False, sqf=False): """ Compute isolating intervals for roots of ``f``. For real roots the Vincent-Akritas-Strzebonski (VAS) continued fractions method is used. References ========== .. [#] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative Study of Two Real Root Isolation Methods . Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. .. [#] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. Vigklas: Improving the Performance of the Continued Fractions Method Using new Bounds of Positive Roots. Nonlinear Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 3, x).intervals() [((-2, -1), 1), ((1, 2), 1)] >>> Poly(x**2 - 3, x).intervals(eps=1e-2) [((-26/15, -19/11), 1), ((19/11, 26/15), 1)] """ if eps is not None: eps = QQ.convert(eps) if eps <= 0: raise ValueError("'eps' must be a positive rational") if inf is not None: inf = QQ.convert(inf) if sup is not None: sup = QQ.convert(sup) if hasattr(f.rep, 'intervals'): result = f.rep.intervals( all=all, eps=eps, inf=inf, sup=sup, fast=fast, sqf=sqf) else: # pragma: no cover raise OperationNotSupported(f, 'intervals') if sqf: def _real(interval): s, t = interval return (QQ.to_sympy(s), QQ.to_sympy(t)) if not all: return list(map(_real, result)) def _complex(rectangle): (u, v), (s, t) = rectangle return (QQ.to_sympy(u) + I*QQ.to_sympy(v), QQ.to_sympy(s) + I*QQ.to_sympy(t)) real_part, complex_part = result return list(map(_real, real_part)), list(map(_complex, complex_part)) else: def _real(interval): (s, t), k = interval return ((QQ.to_sympy(s), QQ.to_sympy(t)), k) if not all: return list(map(_real, result)) def _complex(rectangle): ((u, v), (s, t)), k = rectangle return ((QQ.to_sympy(u) + I*QQ.to_sympy(v), QQ.to_sympy(s) + I*QQ.to_sympy(t)), k) real_part, complex_part = result return list(map(_real, real_part)), list(map(_complex, complex_part)) def refine_root(f, s, t, eps=None, steps=None, fast=False, check_sqf=False): """ Refine an isolating interval of a root to the given precision. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 3, x).refine_root(1, 2, eps=1e-2) (19/11, 26/15) """ if check_sqf and not f.is_sqf: raise PolynomialError("only square-free polynomials supported") s, t = QQ.convert(s), QQ.convert(t) if eps is not None: eps = QQ.convert(eps) if eps <= 0: raise ValueError("'eps' must be a positive rational") if steps is not None: steps = int(steps) elif eps is None: steps = 1 if hasattr(f.rep, 'refine_root'): S, T = f.rep.refine_root(s, t, eps=eps, steps=steps, fast=fast) else: # pragma: no cover raise OperationNotSupported(f, 'refine_root') return QQ.to_sympy(S), QQ.to_sympy(T) def count_roots(f, inf=None, sup=None): """ Return the number of roots of ``f`` in ``[inf, sup]`` interval. Examples ======== >>> from sympy import Poly, I >>> from sympy.abc import x >>> Poly(x**4 - 4, x).count_roots(-3, 3) 2 >>> Poly(x**4 - 4, x).count_roots(0, 1 + 3*I) 1 """ inf_real, sup_real = True, True if inf is not None: inf = sympify(inf) if inf is S.NegativeInfinity: inf = None else: re, im = inf.as_real_imag() if not im: inf = QQ.convert(inf) else: inf, inf_real = list(map(QQ.convert, (re, im))), False if sup is not None: sup = sympify(sup) if sup is S.Infinity: sup = None else: re, im = sup.as_real_imag() if not im: sup = QQ.convert(sup) else: sup, sup_real = list(map(QQ.convert, (re, im))), False if inf_real and sup_real: if hasattr(f.rep, 'count_real_roots'): count = f.rep.count_real_roots(inf=inf, sup=sup) else: # pragma: no cover raise OperationNotSupported(f, 'count_real_roots') else: if inf_real and inf is not None: inf = (inf, QQ.zero) if sup_real and sup is not None: sup = (sup, QQ.zero) if hasattr(f.rep, 'count_complex_roots'): count = f.rep.count_complex_roots(inf=inf, sup=sup) else: # pragma: no cover raise OperationNotSupported(f, 'count_complex_roots') return Integer(count) def root(f, index, radicals=True): """ Get an indexed root of a polynomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = Poly(2*x**3 - 7*x**2 + 4*x + 4) >>> f.root(0) -1/2 >>> f.root(1) 2 >>> f.root(2) 2 >>> f.root(3) Traceback (most recent call last): ... IndexError: root index out of [-3, 2] range, got 3 >>> Poly(x**5 + x + 1).root(0) CRootOf(x**3 - x**2 + 1, 0) """ return sympy.polys.rootoftools.rootof(f, index, radicals=radicals) def real_roots(f, multiple=True, radicals=True): """ Return a list of real roots with multiplicities. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x**3 - 7*x**2 + 4*x + 4).real_roots() [-1/2, 2, 2] >>> Poly(x**3 + x + 1).real_roots() [CRootOf(x**3 + x + 1, 0)] """ reals = sympy.polys.rootoftools.CRootOf.real_roots(f, radicals=radicals) if multiple: return reals else: return group(reals, multiple=False) def all_roots(f, multiple=True, radicals=True): """ Return a list of real and complex roots with multiplicities. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x**3 - 7*x**2 + 4*x + 4).all_roots() [-1/2, 2, 2] >>> Poly(x**3 + x + 1).all_roots() [CRootOf(x**3 + x + 1, 0), CRootOf(x**3 + x + 1, 1), CRootOf(x**3 + x + 1, 2)] """ roots = sympy.polys.rootoftools.CRootOf.all_roots(f, radicals=radicals) if multiple: return roots else: return group(roots, multiple=False) def nroots(f, n=15, maxsteps=50, cleanup=True): """ Compute numerical approximations of roots of ``f``. Parameters ========== n ... the number of digits to calculate maxsteps ... the maximum number of iterations to do If the accuracy `n` cannot be reached in `maxsteps`, it will raise an exception. You need to rerun with higher maxsteps. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 3).nroots(n=15) [-1.73205080756888, 1.73205080756888] >>> Poly(x**2 - 3).nroots(n=30) [-1.73205080756887729352744634151, 1.73205080756887729352744634151] """ from sympy.functions.elementary.complexes import sign if f.is_multivariate: raise MultivariatePolynomialError( "can't compute numerical roots of %s" % f) if f.degree() <= 0: return [] # For integer and rational coefficients, convert them to integers only # (for accuracy). Otherwise just try to convert the coefficients to # mpmath.mpc and raise an exception if the conversion fails. if f.rep.dom is ZZ: coeffs = [int(coeff) for coeff in f.all_coeffs()] elif f.rep.dom is QQ: denoms = [coeff.q for coeff in f.all_coeffs()] from sympy.core.numbers import ilcm fac = ilcm(*denoms) coeffs = [int(coeff*fac) for coeff in f.all_coeffs()] else: coeffs = [coeff.evalf(n=n).as_real_imag() for coeff in f.all_coeffs()] try: coeffs = [mpmath.mpc(*coeff) for coeff in coeffs] except TypeError: raise DomainError("Numerical domain expected, got %s" % \ f.rep.dom) dps = mpmath.mp.dps mpmath.mp.dps = n try: # We need to add extra precision to guard against losing accuracy. # 10 times the degree of the polynomial seems to work well. roots = mpmath.polyroots(coeffs, maxsteps=maxsteps, cleanup=cleanup, error=False, extraprec=f.degree()*10) # Mpmath puts real roots first, then complex ones (as does all_roots) # so we make sure this convention holds here, too. roots = list(map(sympify, sorted(roots, key=lambda r: (1 if r.imag else 0, r.real, abs(r.imag), sign(r.imag))))) except NoConvergence: raise NoConvergence( 'convergence to root failed; try n < %s or maxsteps > %s' % ( n, maxsteps)) finally: mpmath.mp.dps = dps return roots def ground_roots(f): """ Compute roots of ``f`` by factorization in the ground domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**6 - 4*x**4 + 4*x**3 - x**2).ground_roots() {0: 2, 1: 2} """ if f.is_multivariate: raise MultivariatePolynomialError( "can't compute ground roots of %s" % f) roots = {} for factor, k in f.factor_list()[1]: if factor.is_linear: a, b = factor.all_coeffs() roots[-b/a] = k return roots def nth_power_roots_poly(f, n): """ Construct a polynomial with n-th powers of roots of ``f``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = Poly(x**4 - x**2 + 1) >>> f.nth_power_roots_poly(2) Poly(x**4 - 2*x**3 + 3*x**2 - 2*x + 1, x, domain='ZZ') >>> f.nth_power_roots_poly(3) Poly(x**4 + 2*x**2 + 1, x, domain='ZZ') >>> f.nth_power_roots_poly(4) Poly(x**4 + 2*x**3 + 3*x**2 + 2*x + 1, x, domain='ZZ') >>> f.nth_power_roots_poly(12) Poly(x**4 - 4*x**3 + 6*x**2 - 4*x + 1, x, domain='ZZ') """ if f.is_multivariate: raise MultivariatePolynomialError( "must be a univariate polynomial") N = sympify(n) if N.is_Integer and N >= 1: n = int(N) else: raise ValueError("'n' must an integer and n >= 1, got %s" % n) x = f.gen t = Dummy('t') r = f.resultant(f.__class__.from_expr(x**n - t, x, t)) return r.replace(t, x) def cancel(f, g, include=False): """ Cancel common factors in a rational function ``f/g``. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x**2 - 2, x).cancel(Poly(x**2 - 2*x + 1, x)) (1, Poly(2*x + 2, x, domain='ZZ'), Poly(x - 1, x, domain='ZZ')) >>> Poly(2*x**2 - 2, x).cancel(Poly(x**2 - 2*x + 1, x), include=True) (Poly(2*x + 2, x, domain='ZZ'), Poly(x - 1, x, domain='ZZ')) """ dom, per, F, G = f._unify(g) if hasattr(F, 'cancel'): result = F.cancel(G, include=include) else: # pragma: no cover raise OperationNotSupported(f, 'cancel') if not include: if dom.has_assoc_Ring: dom = dom.get_ring() cp, cq, p, q = result cp = dom.to_sympy(cp) cq = dom.to_sympy(cq) return cp/cq, per(p), per(q) else: return tuple(map(per, result)) @property def is_zero(f): """ Returns ``True`` if ``f`` is a zero polynomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(0, x).is_zero True >>> Poly(1, x).is_zero False """ return f.rep.is_zero @property def is_one(f): """ Returns ``True`` if ``f`` is a unit polynomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(0, x).is_one False >>> Poly(1, x).is_one True """ return f.rep.is_one @property def is_sqf(f): """ Returns ``True`` if ``f`` is a square-free polynomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 - 2*x + 1, x).is_sqf False >>> Poly(x**2 - 1, x).is_sqf True """ return f.rep.is_sqf @property def is_monic(f): """ Returns ``True`` if the leading coefficient of ``f`` is one. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x + 2, x).is_monic True >>> Poly(2*x + 2, x).is_monic False """ return f.rep.is_monic @property def is_primitive(f): """ Returns ``True`` if GCD of the coefficients of ``f`` is one. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(2*x**2 + 6*x + 12, x).is_primitive False >>> Poly(x**2 + 3*x + 6, x).is_primitive True """ return f.rep.is_primitive @property def is_ground(f): """ Returns ``True`` if ``f`` is an element of the ground domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x, x).is_ground False >>> Poly(2, x).is_ground True >>> Poly(y, x).is_ground True """ return f.rep.is_ground @property def is_linear(f): """ Returns ``True`` if ``f`` is linear in all its variables. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x + y + 2, x, y).is_linear True >>> Poly(x*y + 2, x, y).is_linear False """ return f.rep.is_linear @property def is_quadratic(f): """ Returns ``True`` if ``f`` is quadratic in all its variables. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x*y + 2, x, y).is_quadratic True >>> Poly(x*y**2 + 2, x, y).is_quadratic False """ return f.rep.is_quadratic @property def is_monomial(f): """ Returns ``True`` if ``f`` is zero or has only one term. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(3*x**2, x).is_monomial True >>> Poly(3*x**2 + 1, x).is_monomial False """ return f.rep.is_monomial @property def is_homogeneous(f): """ Returns ``True`` if ``f`` is a homogeneous polynomial. A homogeneous polynomial is a polynomial whose all monomials with non-zero coefficients have the same total degree. If you want not only to check if a polynomial is homogeneous but also compute its homogeneous order, then use :func:`Poly.homogeneous_order`. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + x*y, x, y).is_homogeneous True >>> Poly(x**3 + x*y, x, y).is_homogeneous False """ return f.rep.is_homogeneous @property def is_irreducible(f): """ Returns ``True`` if ``f`` has no factors over its domain. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> Poly(x**2 + x + 1, x, modulus=2).is_irreducible True >>> Poly(x**2 + 1, x, modulus=2).is_irreducible False """ return f.rep.is_irreducible @property def is_univariate(f): """ Returns ``True`` if ``f`` is a univariate polynomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + x + 1, x).is_univariate True >>> Poly(x*y**2 + x*y + 1, x, y).is_univariate False >>> Poly(x*y**2 + x*y + 1, x).is_univariate True >>> Poly(x**2 + x + 1, x, y).is_univariate False """ return len(f.gens) == 1 @property def is_multivariate(f): """ Returns ``True`` if ``f`` is a multivariate polynomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x, y >>> Poly(x**2 + x + 1, x).is_multivariate False >>> Poly(x*y**2 + x*y + 1, x, y).is_multivariate True >>> Poly(x*y**2 + x*y + 1, x).is_multivariate False >>> Poly(x**2 + x + 1, x, y).is_multivariate True """ return len(f.gens) != 1 @property def is_cyclotomic(f): """ Returns ``True`` if ``f`` is a cyclotomic polnomial. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 >>> Poly(f).is_cyclotomic False >>> g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 >>> Poly(g).is_cyclotomic True """ return f.rep.is_cyclotomic def __abs__(f): return f.abs() def __neg__(f): return f.neg() @_polifyit def __add__(f, g): return f.add(g) @_polifyit def __radd__(f, g): return g.add(f) @_polifyit def __sub__(f, g): return f.sub(g) @_polifyit def __rsub__(f, g): return g.sub(f) @_polifyit def __mul__(f, g): return f.mul(g) @_polifyit def __rmul__(f, g): return g.mul(f) @_sympifyit('n', NotImplemented) def __pow__(f, n): if n.is_Integer and n >= 0: return f.pow(n) else: return NotImplemented @_polifyit def __divmod__(f, g): return f.div(g) @_polifyit def __rdivmod__(f, g): return g.div(f) @_polifyit def __mod__(f, g): return f.rem(g) @_polifyit def __rmod__(f, g): return g.rem(f) @_polifyit def __floordiv__(f, g): return f.quo(g) @_polifyit def __rfloordiv__(f, g): return g.quo(f) @_sympifyit('g', NotImplemented) def __truediv__(f, g): return f.as_expr()/g.as_expr() @_sympifyit('g', NotImplemented) def __rtruediv__(f, g): return g.as_expr()/f.as_expr() @_sympifyit('other', NotImplemented) def __eq__(self, other): f, g = self, other if not g.is_Poly: try: g = f.__class__(g, f.gens, domain=f.get_domain()) except (PolynomialError, DomainError, CoercionFailed): return False if f.gens != g.gens: return False if f.rep.dom != g.rep.dom: return False return f.rep == g.rep @_sympifyit('g', NotImplemented) def __ne__(f, g): return not f == g def __bool__(f): return not f.is_zero def eq(f, g, strict=False): if not strict: return f == g else: return f._strict_eq(sympify(g)) def ne(f, g, strict=False): return not f.eq(g, strict=strict) def _strict_eq(f, g): return isinstance(g, f.__class__) and f.gens == g.gens and f.rep.eq(g.rep, strict=True) @public class PurePoly(Poly): """Class for representing pure polynomials. """ def _hashable_content(self): """Allow SymPy to hash Poly instances. """ return (self.rep,) def __hash__(self): return super().__hash__() @property def free_symbols(self): """ Free symbols of a polynomial. Examples ======== >>> from sympy import PurePoly >>> from sympy.abc import x, y >>> PurePoly(x**2 + 1).free_symbols set() >>> PurePoly(x**2 + y).free_symbols set() >>> PurePoly(x**2 + y, x).free_symbols {y} """ return self.free_symbols_in_domain @_sympifyit('other', NotImplemented) def __eq__(self, other): f, g = self, other if not g.is_Poly: try: g = f.__class__(g, f.gens, domain=f.get_domain()) except (PolynomialError, DomainError, CoercionFailed): return False if len(f.gens) != len(g.gens): return False if f.rep.dom != g.rep.dom: try: dom = f.rep.dom.unify(g.rep.dom, f.gens) except UnificationFailed: return False f = f.set_domain(dom) g = g.set_domain(dom) return f.rep == g.rep def _strict_eq(f, g): return isinstance(g, f.__class__) and f.rep.eq(g.rep, strict=True) def _unify(f, g): g = sympify(g) if not g.is_Poly: try: return f.rep.dom, f.per, f.rep, f.rep.per(f.rep.dom.from_sympy(g)) except CoercionFailed: raise UnificationFailed("can't unify %s with %s" % (f, g)) if len(f.gens) != len(g.gens): raise UnificationFailed("can't unify %s with %s" % (f, g)) if not (isinstance(f.rep, DMP) and isinstance(g.rep, DMP)): raise UnificationFailed("can't unify %s with %s" % (f, g)) cls = f.__class__ gens = f.gens dom = f.rep.dom.unify(g.rep.dom, gens) F = f.rep.convert(dom) G = g.rep.convert(dom) def per(rep, dom=dom, gens=gens, remove=None): if remove is not None: gens = gens[:remove] + gens[remove + 1:] if not gens: return dom.to_sympy(rep) return cls.new(rep, *gens) return dom, per, F, G @public def poly_from_expr(expr, *gens, **args): """Construct a polynomial from an expression. """ opt = options.build_options(gens, args) return _poly_from_expr(expr, opt) def _poly_from_expr(expr, opt): """Construct a polynomial from an expression. """ orig, expr = expr, sympify(expr) if not isinstance(expr, Basic): raise PolificationFailed(opt, orig, expr) elif expr.is_Poly: poly = expr.__class__._from_poly(expr, opt) opt.gens = poly.gens opt.domain = poly.domain if opt.polys is None: opt.polys = True return poly, opt elif opt.expand: expr = expr.expand() rep, opt = _dict_from_expr(expr, opt) if not opt.gens: raise PolificationFailed(opt, orig, expr) monoms, coeffs = list(zip(*list(rep.items()))) domain = opt.domain if domain is None: opt.domain, coeffs = construct_domain(coeffs, opt=opt) else: coeffs = list(map(domain.from_sympy, coeffs)) rep = dict(list(zip(monoms, coeffs))) poly = Poly._from_dict(rep, opt) if opt.polys is None: opt.polys = False return poly, opt @public def parallel_poly_from_expr(exprs, *gens, **args): """Construct polynomials from expressions. """ opt = options.build_options(gens, args) return _parallel_poly_from_expr(exprs, opt) def _parallel_poly_from_expr(exprs, opt): """Construct polynomials from expressions. """ from sympy.functions.elementary.piecewise import Piecewise if len(exprs) == 2: f, g = exprs if isinstance(f, Poly) and isinstance(g, Poly): f = f.__class__._from_poly(f, opt) g = g.__class__._from_poly(g, opt) f, g = f.unify(g) opt.gens = f.gens opt.domain = f.domain if opt.polys is None: opt.polys = True return [f, g], opt origs, exprs = list(exprs), [] _exprs, _polys = [], [] failed = False for i, expr in enumerate(origs): expr = sympify(expr) if isinstance(expr, Basic): if expr.is_Poly: _polys.append(i) else: _exprs.append(i) if opt.expand: expr = expr.expand() else: failed = True exprs.append(expr) if failed: raise PolificationFailed(opt, origs, exprs, True) if _polys: # XXX: this is a temporary solution for i in _polys: exprs[i] = exprs[i].as_expr() reps, opt = _parallel_dict_from_expr(exprs, opt) if not opt.gens: raise PolificationFailed(opt, origs, exprs, True) for k in opt.gens: if isinstance(k, Piecewise): raise PolynomialError("Piecewise generators do not make sense") coeffs_list, lengths = [], [] all_monoms = [] all_coeffs = [] for rep in reps: monoms, coeffs = list(zip(*list(rep.items()))) coeffs_list.extend(coeffs) all_monoms.append(monoms) lengths.append(len(coeffs)) domain = opt.domain if domain is None: opt.domain, coeffs_list = construct_domain(coeffs_list, opt=opt) else: coeffs_list = list(map(domain.from_sympy, coeffs_list)) for k in lengths: all_coeffs.append(coeffs_list[:k]) coeffs_list = coeffs_list[k:] polys = [] for monoms, coeffs in zip(all_monoms, all_coeffs): rep = dict(list(zip(monoms, coeffs))) poly = Poly._from_dict(rep, opt) polys.append(poly) if opt.polys is None: opt.polys = bool(_polys) return polys, opt def _update_args(args, key, value): """Add a new ``(key, value)`` pair to arguments ``dict``. """ args = dict(args) if key not in args: args[key] = value return args @public def degree(f, gen=0): """ Return the degree of ``f`` in the given variable. The degree of 0 is negative infinity. Examples ======== >>> from sympy import degree >>> from sympy.abc import x, y >>> degree(x**2 + y*x + 1, gen=x) 2 >>> degree(x**2 + y*x + 1, gen=y) 1 >>> degree(0, x) -oo See also ======== sympy.polys.polytools.Poly.total_degree degree_list """ f = sympify(f, strict=True) gen_is_Num = sympify(gen, strict=True).is_Number if f.is_Poly: p = f isNum = p.as_expr().is_Number else: isNum = f.is_Number if not isNum: if gen_is_Num: p, _ = poly_from_expr(f) else: p, _ = poly_from_expr(f, gen) if isNum: return S.Zero if f else S.NegativeInfinity if not gen_is_Num: if f.is_Poly and gen not in p.gens: # try recast without explicit gens p, _ = poly_from_expr(f.as_expr()) if gen not in p.gens: return S.Zero elif not f.is_Poly and len(f.free_symbols) > 1: raise TypeError(filldedent(''' A symbolic generator of interest is required for a multivariate expression like func = %s, e.g. degree(func, gen = %s) instead of degree(func, gen = %s). ''' % (f, next(ordered(f.free_symbols)), gen))) result = p.degree(gen) return Integer(result) if isinstance(result, int) else S.NegativeInfinity @public def total_degree(f, *gens): """ Return the total_degree of ``f`` in the given variables. Examples ======== >>> from sympy import total_degree, Poly >>> from sympy.abc import x, y >>> total_degree(1) 0 >>> total_degree(x + x*y) 2 >>> total_degree(x + x*y, x) 1 If the expression is a Poly and no variables are given then the generators of the Poly will be used: >>> p = Poly(x + x*y, y) >>> total_degree(p) 1 To deal with the underlying expression of the Poly, convert it to an Expr: >>> total_degree(p.as_expr()) 2 This is done automatically if any variables are given: >>> total_degree(p, x) 1 See also ======== degree """ p = sympify(f) if p.is_Poly: p = p.as_expr() if p.is_Number: rv = 0 else: if f.is_Poly: gens = gens or f.gens rv = Poly(p, gens).total_degree() return Integer(rv) @public def degree_list(f, *gens, **args): """ Return a list of degrees of ``f`` in all variables. Examples ======== >>> from sympy import degree_list >>> from sympy.abc import x, y >>> degree_list(x**2 + y*x + 1) (2, 1) """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('degree_list', 1, exc) degrees = F.degree_list() return tuple(map(Integer, degrees)) @public def LC(f, *gens, **args): """ Return the leading coefficient of ``f``. Examples ======== >>> from sympy import LC >>> from sympy.abc import x, y >>> LC(4*x**2 + 2*x*y**2 + x*y + 3*y) 4 """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('LC', 1, exc) return F.LC(order=opt.order) @public def LM(f, *gens, **args): """ Return the leading monomial of ``f``. Examples ======== >>> from sympy import LM >>> from sympy.abc import x, y >>> LM(4*x**2 + 2*x*y**2 + x*y + 3*y) x**2 """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('LM', 1, exc) monom = F.LM(order=opt.order) return monom.as_expr() @public def LT(f, *gens, **args): """ Return the leading term of ``f``. Examples ======== >>> from sympy import LT >>> from sympy.abc import x, y >>> LT(4*x**2 + 2*x*y**2 + x*y + 3*y) 4*x**2 """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('LT', 1, exc) monom, coeff = F.LT(order=opt.order) return coeff*monom.as_expr() @public def pdiv(f, g, *gens, **args): """ Compute polynomial pseudo-division of ``f`` and ``g``. Examples ======== >>> from sympy import pdiv >>> from sympy.abc import x >>> pdiv(x**2 + 1, 2*x - 4) (2*x + 4, 20) """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('pdiv', 2, exc) q, r = F.pdiv(G) if not opt.polys: return q.as_expr(), r.as_expr() else: return q, r @public def prem(f, g, *gens, **args): """ Compute polynomial pseudo-remainder of ``f`` and ``g``. Examples ======== >>> from sympy import prem >>> from sympy.abc import x >>> prem(x**2 + 1, 2*x - 4) 20 """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('prem', 2, exc) r = F.prem(G) if not opt.polys: return r.as_expr() else: return r @public def pquo(f, g, *gens, **args): """ Compute polynomial pseudo-quotient of ``f`` and ``g``. Examples ======== >>> from sympy import pquo >>> from sympy.abc import x >>> pquo(x**2 + 1, 2*x - 4) 2*x + 4 >>> pquo(x**2 - 1, 2*x - 1) 2*x + 1 """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('pquo', 2, exc) try: q = F.pquo(G) except ExactQuotientFailed: raise ExactQuotientFailed(f, g) if not opt.polys: return q.as_expr() else: return q @public def pexquo(f, g, *gens, **args): """ Compute polynomial exact pseudo-quotient of ``f`` and ``g``. Examples ======== >>> from sympy import pexquo >>> from sympy.abc import x >>> pexquo(x**2 - 1, 2*x - 2) 2*x + 2 >>> pexquo(x**2 + 1, 2*x - 4) Traceback (most recent call last): ... ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('pexquo', 2, exc) q = F.pexquo(G) if not opt.polys: return q.as_expr() else: return q @public def div(f, g, *gens, **args): """ Compute polynomial division of ``f`` and ``g``. Examples ======== >>> from sympy import div, ZZ, QQ >>> from sympy.abc import x >>> div(x**2 + 1, 2*x - 4, domain=ZZ) (0, x**2 + 1) >>> div(x**2 + 1, 2*x - 4, domain=QQ) (x/2 + 1, 5) """ options.allowed_flags(args, ['auto', 'polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('div', 2, exc) q, r = F.div(G, auto=opt.auto) if not opt.polys: return q.as_expr(), r.as_expr() else: return q, r @public def rem(f, g, *gens, **args): """ Compute polynomial remainder of ``f`` and ``g``. Examples ======== >>> from sympy import rem, ZZ, QQ >>> from sympy.abc import x >>> rem(x**2 + 1, 2*x - 4, domain=ZZ) x**2 + 1 >>> rem(x**2 + 1, 2*x - 4, domain=QQ) 5 """ options.allowed_flags(args, ['auto', 'polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('rem', 2, exc) r = F.rem(G, auto=opt.auto) if not opt.polys: return r.as_expr() else: return r @public def quo(f, g, *gens, **args): """ Compute polynomial quotient of ``f`` and ``g``. Examples ======== >>> from sympy import quo >>> from sympy.abc import x >>> quo(x**2 + 1, 2*x - 4) x/2 + 1 >>> quo(x**2 - 1, x - 1) x + 1 """ options.allowed_flags(args, ['auto', 'polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('quo', 2, exc) q = F.quo(G, auto=opt.auto) if not opt.polys: return q.as_expr() else: return q @public def exquo(f, g, *gens, **args): """ Compute polynomial exact quotient of ``f`` and ``g``. Examples ======== >>> from sympy import exquo >>> from sympy.abc import x >>> exquo(x**2 - 1, x - 1) x + 1 >>> exquo(x**2 + 1, 2*x - 4) Traceback (most recent call last): ... ExactQuotientFailed: 2*x - 4 does not divide x**2 + 1 """ options.allowed_flags(args, ['auto', 'polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('exquo', 2, exc) q = F.exquo(G, auto=opt.auto) if not opt.polys: return q.as_expr() else: return q @public def half_gcdex(f, g, *gens, **args): """ Half extended Euclidean algorithm of ``f`` and ``g``. Returns ``(s, h)`` such that ``h = gcd(f, g)`` and ``s*f = h (mod g)``. Examples ======== >>> from sympy import half_gcdex >>> from sympy.abc import x >>> half_gcdex(x**4 - 2*x**3 - 6*x**2 + 12*x + 15, x**3 + x**2 - 4*x - 4) (3/5 - x/5, x + 1) """ options.allowed_flags(args, ['auto', 'polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: domain, (a, b) = construct_domain(exc.exprs) try: s, h = domain.half_gcdex(a, b) except NotImplementedError: raise ComputationFailed('half_gcdex', 2, exc) else: return domain.to_sympy(s), domain.to_sympy(h) s, h = F.half_gcdex(G, auto=opt.auto) if not opt.polys: return s.as_expr(), h.as_expr() else: return s, h @public def gcdex(f, g, *gens, **args): """ Extended Euclidean algorithm of ``f`` and ``g``. Returns ``(s, t, h)`` such that ``h = gcd(f, g)`` and ``s*f + t*g = h``. Examples ======== >>> from sympy import gcdex >>> from sympy.abc import x >>> gcdex(x**4 - 2*x**3 - 6*x**2 + 12*x + 15, x**3 + x**2 - 4*x - 4) (3/5 - x/5, x**2/5 - 6*x/5 + 2, x + 1) """ options.allowed_flags(args, ['auto', 'polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: domain, (a, b) = construct_domain(exc.exprs) try: s, t, h = domain.gcdex(a, b) except NotImplementedError: raise ComputationFailed('gcdex', 2, exc) else: return domain.to_sympy(s), domain.to_sympy(t), domain.to_sympy(h) s, t, h = F.gcdex(G, auto=opt.auto) if not opt.polys: return s.as_expr(), t.as_expr(), h.as_expr() else: return s, t, h @public def invert(f, g, *gens, **args): """ Invert ``f`` modulo ``g`` when possible. Examples ======== >>> from sympy import invert, S >>> from sympy.core.numbers import mod_inverse >>> from sympy.abc import x >>> invert(x**2 - 1, 2*x - 1) -4/3 >>> invert(x**2 - 1, x - 1) Traceback (most recent call last): ... NotInvertible: zero divisor For more efficient inversion of Rationals, use the :obj:`~.mod_inverse` function: >>> mod_inverse(3, 5) 2 >>> (S(2)/5).invert(S(7)/3) 5/2 See Also ======== sympy.core.numbers.mod_inverse """ options.allowed_flags(args, ['auto', 'polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: domain, (a, b) = construct_domain(exc.exprs) try: return domain.to_sympy(domain.invert(a, b)) except NotImplementedError: raise ComputationFailed('invert', 2, exc) h = F.invert(G, auto=opt.auto) if not opt.polys: return h.as_expr() else: return h @public def subresultants(f, g, *gens, **args): """ Compute subresultant PRS of ``f`` and ``g``. Examples ======== >>> from sympy import subresultants >>> from sympy.abc import x >>> subresultants(x**2 + 1, x**2 - 1) [x**2 + 1, x**2 - 1, -2] """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('subresultants', 2, exc) result = F.subresultants(G) if not opt.polys: return [r.as_expr() for r in result] else: return result @public def resultant(f, g, *gens, includePRS=False, **args): """ Compute resultant of ``f`` and ``g``. Examples ======== >>> from sympy import resultant >>> from sympy.abc import x >>> resultant(x**2 + 1, x**2 - 1) 4 """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('resultant', 2, exc) if includePRS: result, R = F.resultant(G, includePRS=includePRS) else: result = F.resultant(G) if not opt.polys: if includePRS: return result.as_expr(), [r.as_expr() for r in R] return result.as_expr() else: if includePRS: return result, R return result @public def discriminant(f, *gens, **args): """ Compute discriminant of ``f``. Examples ======== >>> from sympy import discriminant >>> from sympy.abc import x >>> discriminant(x**2 + 2*x + 3) -8 """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('discriminant', 1, exc) result = F.discriminant() if not opt.polys: return result.as_expr() else: return result @public def cofactors(f, g, *gens, **args): """ Compute GCD and cofactors of ``f`` and ``g``. Returns polynomials ``(h, cff, cfg)`` such that ``h = gcd(f, g)``, and ``cff = quo(f, h)`` and ``cfg = quo(g, h)`` are, so called, cofactors of ``f`` and ``g``. Examples ======== >>> from sympy import cofactors >>> from sympy.abc import x >>> cofactors(x**2 - 1, x**2 - 3*x + 2) (x - 1, x + 1, x - 2) """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: domain, (a, b) = construct_domain(exc.exprs) try: h, cff, cfg = domain.cofactors(a, b) except NotImplementedError: raise ComputationFailed('cofactors', 2, exc) else: return domain.to_sympy(h), domain.to_sympy(cff), domain.to_sympy(cfg) h, cff, cfg = F.cofactors(G) if not opt.polys: return h.as_expr(), cff.as_expr(), cfg.as_expr() else: return h, cff, cfg @public def gcd_list(seq, *gens, **args): """ Compute GCD of a list of polynomials. Examples ======== >>> from sympy import gcd_list >>> from sympy.abc import x >>> gcd_list([x**3 - 1, x**2 - 1, x**2 - 3*x + 2]) x - 1 """ seq = sympify(seq) def try_non_polynomial_gcd(seq): if not gens and not args: domain, numbers = construct_domain(seq) if not numbers: return domain.zero elif domain.is_Numerical: result, numbers = numbers[0], numbers[1:] for number in numbers: result = domain.gcd(result, number) if domain.is_one(result): break return domain.to_sympy(result) return None result = try_non_polynomial_gcd(seq) if result is not None: return result options.allowed_flags(args, ['polys']) try: polys, opt = parallel_poly_from_expr(seq, *gens, **args) # gcd for domain Q[irrational] (purely algebraic irrational) if len(seq) > 1 and all(elt.is_algebraic and elt.is_irrational for elt in seq): a = seq[-1] lst = [ (a/elt).ratsimp() for elt in seq[:-1] ] if all(frc.is_rational for frc in lst): lc = 1 for frc in lst: lc = lcm(lc, frc.as_numer_denom()[0]) # abs ensures that the gcd is always non-negative return abs(a/lc) except PolificationFailed as exc: result = try_non_polynomial_gcd(exc.exprs) if result is not None: return result else: raise ComputationFailed('gcd_list', len(seq), exc) if not polys: if not opt.polys: return S.Zero else: return Poly(0, opt=opt) result, polys = polys[0], polys[1:] for poly in polys: result = result.gcd(poly) if result.is_one: break if not opt.polys: return result.as_expr() else: return result @public def gcd(f, g=None, *gens, **args): """ Compute GCD of ``f`` and ``g``. Examples ======== >>> from sympy import gcd >>> from sympy.abc import x >>> gcd(x**2 - 1, x**2 - 3*x + 2) x - 1 """ if hasattr(f, '__iter__'): if g is not None: gens = (g,) + gens return gcd_list(f, *gens, **args) elif g is None: raise TypeError("gcd() takes 2 arguments or a sequence of arguments") options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) # gcd for domain Q[irrational] (purely algebraic irrational) a, b = map(sympify, (f, g)) if a.is_algebraic and a.is_irrational and b.is_algebraic and b.is_irrational: frc = (a/b).ratsimp() if frc.is_rational: # abs ensures that the returned gcd is always non-negative return abs(a/frc.as_numer_denom()[0]) except PolificationFailed as exc: domain, (a, b) = construct_domain(exc.exprs) try: return domain.to_sympy(domain.gcd(a, b)) except NotImplementedError: raise ComputationFailed('gcd', 2, exc) result = F.gcd(G) if not opt.polys: return result.as_expr() else: return result @public def lcm_list(seq, *gens, **args): """ Compute LCM of a list of polynomials. Examples ======== >>> from sympy import lcm_list >>> from sympy.abc import x >>> lcm_list([x**3 - 1, x**2 - 1, x**2 - 3*x + 2]) x**5 - x**4 - 2*x**3 - x**2 + x + 2 """ seq = sympify(seq) def try_non_polynomial_lcm(seq): if not gens and not args: domain, numbers = construct_domain(seq) if not numbers: return domain.one elif domain.is_Numerical: result, numbers = numbers[0], numbers[1:] for number in numbers: result = domain.lcm(result, number) return domain.to_sympy(result) return None result = try_non_polynomial_lcm(seq) if result is not None: return result options.allowed_flags(args, ['polys']) try: polys, opt = parallel_poly_from_expr(seq, *gens, **args) # lcm for domain Q[irrational] (purely algebraic irrational) if len(seq) > 1 and all(elt.is_algebraic and elt.is_irrational for elt in seq): a = seq[-1] lst = [ (a/elt).ratsimp() for elt in seq[:-1] ] if all(frc.is_rational for frc in lst): lc = 1 for frc in lst: lc = lcm(lc, frc.as_numer_denom()[1]) return a*lc except PolificationFailed as exc: result = try_non_polynomial_lcm(exc.exprs) if result is not None: return result else: raise ComputationFailed('lcm_list', len(seq), exc) if not polys: if not opt.polys: return S.One else: return Poly(1, opt=opt) result, polys = polys[0], polys[1:] for poly in polys: result = result.lcm(poly) if not opt.polys: return result.as_expr() else: return result @public def lcm(f, g=None, *gens, **args): """ Compute LCM of ``f`` and ``g``. Examples ======== >>> from sympy import lcm >>> from sympy.abc import x >>> lcm(x**2 - 1, x**2 - 3*x + 2) x**3 - 2*x**2 - x + 2 """ if hasattr(f, '__iter__'): if g is not None: gens = (g,) + gens return lcm_list(f, *gens, **args) elif g is None: raise TypeError("lcm() takes 2 arguments or a sequence of arguments") options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) # lcm for domain Q[irrational] (purely algebraic irrational) a, b = map(sympify, (f, g)) if a.is_algebraic and a.is_irrational and b.is_algebraic and b.is_irrational: frc = (a/b).ratsimp() if frc.is_rational: return a*frc.as_numer_denom()[1] except PolificationFailed as exc: domain, (a, b) = construct_domain(exc.exprs) try: return domain.to_sympy(domain.lcm(a, b)) except NotImplementedError: raise ComputationFailed('lcm', 2, exc) result = F.lcm(G) if not opt.polys: return result.as_expr() else: return result @public def terms_gcd(f, *gens, **args): """ Remove GCD of terms from ``f``. If the ``deep`` flag is True, then the arguments of ``f`` will have terms_gcd applied to them. If a fraction is factored out of ``f`` and ``f`` is an Add, then an unevaluated Mul will be returned so that automatic simplification does not redistribute it. The hint ``clear``, when set to False, can be used to prevent such factoring when all coefficients are not fractions. Examples ======== >>> from sympy import terms_gcd, cos >>> from sympy.abc import x, y >>> terms_gcd(x**6*y**2 + x**3*y, x, y) x**3*y*(x**3*y + 1) The default action of polys routines is to expand the expression given to them. terms_gcd follows this behavior: >>> terms_gcd((3+3*x)*(x+x*y)) 3*x*(x*y + x + y + 1) If this is not desired then the hint ``expand`` can be set to False. In this case the expression will be treated as though it were comprised of one or more terms: >>> terms_gcd((3+3*x)*(x+x*y), expand=False) (3*x + 3)*(x*y + x) In order to traverse factors of a Mul or the arguments of other functions, the ``deep`` hint can be used: >>> terms_gcd((3 + 3*x)*(x + x*y), expand=False, deep=True) 3*x*(x + 1)*(y + 1) >>> terms_gcd(cos(x + x*y), deep=True) cos(x*(y + 1)) Rationals are factored out by default: >>> terms_gcd(x + y/2) (2*x + y)/2 Only the y-term had a coefficient that was a fraction; if one does not want to factor out the 1/2 in cases like this, the flag ``clear`` can be set to False: >>> terms_gcd(x + y/2, clear=False) x + y/2 >>> terms_gcd(x*y/2 + y**2, clear=False) y*(x/2 + y) The ``clear`` flag is ignored if all coefficients are fractions: >>> terms_gcd(x/3 + y/2, clear=False) (2*x + 3*y)/6 See Also ======== sympy.core.exprtools.gcd_terms, sympy.core.exprtools.factor_terms """ from sympy.core.relational import Equality orig = sympify(f) if isinstance(f, Equality): return Equality(*(terms_gcd(s, *gens, **args) for s in [f.lhs, f.rhs])) elif isinstance(f, Relational): raise TypeError("Inequalities can not be used with terms_gcd. Found: %s" %(f,)) if not isinstance(f, Expr) or f.is_Atom: return orig if args.get('deep', False): new = f.func(*[terms_gcd(a, *gens, **args) for a in f.args]) args.pop('deep') args['expand'] = False return terms_gcd(new, *gens, **args) clear = args.pop('clear', True) options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: return exc.expr J, f = F.terms_gcd() if opt.domain.is_Ring: if opt.domain.is_Field: denom, f = f.clear_denoms(convert=True) coeff, f = f.primitive() if opt.domain.is_Field: coeff /= denom else: coeff = S.One term = Mul(*[x**j for x, j in zip(f.gens, J)]) if coeff == 1: coeff = S.One if term == 1: return orig if clear: return _keep_coeff(coeff, term*f.as_expr()) # base the clearing on the form of the original expression, not # the (perhaps) Mul that we have now coeff, f = _keep_coeff(coeff, f.as_expr(), clear=False).as_coeff_Mul() return _keep_coeff(coeff, term*f, clear=False) @public def trunc(f, p, *gens, **args): """ Reduce ``f`` modulo a constant ``p``. Examples ======== >>> from sympy import trunc >>> from sympy.abc import x >>> trunc(2*x**3 + 3*x**2 + 5*x + 7, 3) -x**3 - x + 1 """ options.allowed_flags(args, ['auto', 'polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('trunc', 1, exc) result = F.trunc(sympify(p)) if not opt.polys: return result.as_expr() else: return result @public def monic(f, *gens, **args): """ Divide all coefficients of ``f`` by ``LC(f)``. Examples ======== >>> from sympy import monic >>> from sympy.abc import x >>> monic(3*x**2 + 4*x + 2) x**2 + 4*x/3 + 2/3 """ options.allowed_flags(args, ['auto', 'polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('monic', 1, exc) result = F.monic(auto=opt.auto) if not opt.polys: return result.as_expr() else: return result @public def content(f, *gens, **args): """ Compute GCD of coefficients of ``f``. Examples ======== >>> from sympy import content >>> from sympy.abc import x >>> content(6*x**2 + 8*x + 12) 2 """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('content', 1, exc) return F.content() @public def primitive(f, *gens, **args): """ Compute content and the primitive form of ``f``. Examples ======== >>> from sympy.polys.polytools import primitive >>> from sympy.abc import x >>> primitive(6*x**2 + 8*x + 12) (2, 3*x**2 + 4*x + 6) >>> eq = (2 + 2*x)*x + 2 Expansion is performed by default: >>> primitive(eq) (2, x**2 + x + 1) Set ``expand`` to False to shut this off. Note that the extraction will not be recursive; use the as_content_primitive method for recursive, non-destructive Rational extraction. >>> primitive(eq, expand=False) (1, x*(2*x + 2) + 2) >>> eq.as_content_primitive() (2, x*(x + 1) + 1) """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('primitive', 1, exc) cont, result = F.primitive() if not opt.polys: return cont, result.as_expr() else: return cont, result @public def compose(f, g, *gens, **args): """ Compute functional composition ``f(g)``. Examples ======== >>> from sympy import compose >>> from sympy.abc import x >>> compose(x**2 + x, x - 1) x**2 - x """ options.allowed_flags(args, ['polys']) try: (F, G), opt = parallel_poly_from_expr((f, g), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('compose', 2, exc) result = F.compose(G) if not opt.polys: return result.as_expr() else: return result @public def decompose(f, *gens, **args): """ Compute functional decomposition of ``f``. Examples ======== >>> from sympy import decompose >>> from sympy.abc import x >>> decompose(x**4 + 2*x**3 - x - 1) [x**2 - x - 1, x**2 + x] """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('decompose', 1, exc) result = F.decompose() if not opt.polys: return [r.as_expr() for r in result] else: return result @public def sturm(f, *gens, **args): """ Compute Sturm sequence of ``f``. Examples ======== >>> from sympy import sturm >>> from sympy.abc import x >>> sturm(x**3 - 2*x**2 + x - 3) [x**3 - 2*x**2 + x - 3, 3*x**2 - 4*x + 1, 2*x/9 + 25/9, -2079/4] """ options.allowed_flags(args, ['auto', 'polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('sturm', 1, exc) result = F.sturm(auto=opt.auto) if not opt.polys: return [r.as_expr() for r in result] else: return result @public def gff_list(f, *gens, **args): """ Compute a list of greatest factorial factors of ``f``. Note that the input to ff() and rf() should be Poly instances to use the definitions here. Examples ======== >>> from sympy import gff_list, ff, Poly >>> from sympy.abc import x >>> f = Poly(x**5 + 2*x**4 - x**3 - 2*x**2, x) >>> gff_list(f) [(Poly(x, x, domain='ZZ'), 1), (Poly(x + 2, x, domain='ZZ'), 4)] >>> (ff(Poly(x), 1)*ff(Poly(x + 2), 4)) == f True >>> f = Poly(x**12 + 6*x**11 - 11*x**10 - 56*x**9 + 220*x**8 + 208*x**7 - \ 1401*x**6 + 1090*x**5 + 2715*x**4 - 6720*x**3 - 1092*x**2 + 5040*x, x) >>> gff_list(f) [(Poly(x**3 + 7, x, domain='ZZ'), 2), (Poly(x**2 + 5*x, x, domain='ZZ'), 3)] >>> ff(Poly(x**3 + 7, x), 2)*ff(Poly(x**2 + 5*x, x), 3) == f True """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('gff_list', 1, exc) factors = F.gff_list() if not opt.polys: return [(g.as_expr(), k) for g, k in factors] else: return factors @public def gff(f, *gens, **args): """Compute greatest factorial factorization of ``f``. """ raise NotImplementedError('symbolic falling factorial') @public def sqf_norm(f, *gens, **args): """ Compute square-free norm of ``f``. Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))`` is a square-free polynomial over ``K``, where ``a`` is the algebraic extension of the ground domain. Examples ======== >>> from sympy import sqf_norm, sqrt >>> from sympy.abc import x >>> sqf_norm(x**2 + 1, extension=[sqrt(3)]) (1, x**2 - 2*sqrt(3)*x + 4, x**4 - 4*x**2 + 16) """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('sqf_norm', 1, exc) s, g, r = F.sqf_norm() if not opt.polys: return Integer(s), g.as_expr(), r.as_expr() else: return Integer(s), g, r @public def sqf_part(f, *gens, **args): """ Compute square-free part of ``f``. Examples ======== >>> from sympy import sqf_part >>> from sympy.abc import x >>> sqf_part(x**3 - 3*x - 2) x**2 - x - 2 """ options.allowed_flags(args, ['polys']) try: F, opt = poly_from_expr(f, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('sqf_part', 1, exc) result = F.sqf_part() if not opt.polys: return result.as_expr() else: return result def _sorted_factors(factors, method): """Sort a list of ``(expr, exp)`` pairs. """ if method == 'sqf': def key(obj): poly, exp = obj rep = poly.rep.rep return (exp, len(rep), len(poly.gens), rep) else: def key(obj): poly, exp = obj rep = poly.rep.rep return (len(rep), len(poly.gens), exp, rep) return sorted(factors, key=key) def _factors_product(factors): """Multiply a list of ``(expr, exp)`` pairs. """ return Mul(*[f.as_expr()**k for f, k in factors]) def _symbolic_factor_list(expr, opt, method): """Helper function for :func:`_symbolic_factor`. """ coeff, factors = S.One, [] args = [i._eval_factor() if hasattr(i, '_eval_factor') else i for i in Mul.make_args(expr)] for arg in args: if arg.is_Number or (isinstance(arg, Expr) and pure_complex(arg)): coeff *= arg continue elif arg.is_Pow and arg.base != S.Exp1: base, exp = arg.args if base.is_Number and exp.is_Number: coeff *= arg continue if base.is_Number: factors.append((base, exp)) continue else: base, exp = arg, S.One try: poly, _ = _poly_from_expr(base, opt) except PolificationFailed as exc: factors.append((exc.expr, exp)) else: func = getattr(poly, method + '_list') _coeff, _factors = func() if _coeff is not S.One: if exp.is_Integer: coeff *= _coeff**exp elif _coeff.is_positive: factors.append((_coeff, exp)) else: _factors.append((_coeff, S.One)) if exp is S.One: factors.extend(_factors) elif exp.is_integer: factors.extend([(f, k*exp) for f, k in _factors]) else: other = [] for f, k in _factors: if f.as_expr().is_positive: factors.append((f, k*exp)) else: other.append((f, k)) factors.append((_factors_product(other), exp)) if method == 'sqf': factors = [(reduce(mul, (f for f, _ in factors if _ == k)), k) for k in {i for _, i in factors}] return coeff, factors def _symbolic_factor(expr, opt, method): """Helper function for :func:`_factor`. """ if isinstance(expr, Expr): if hasattr(expr,'_eval_factor'): return expr._eval_factor() coeff, factors = _symbolic_factor_list(together(expr, fraction=opt['fraction']), opt, method) return _keep_coeff(coeff, _factors_product(factors)) elif hasattr(expr, 'args'): return expr.func(*[_symbolic_factor(arg, opt, method) for arg in expr.args]) elif hasattr(expr, '__iter__'): return expr.__class__([_symbolic_factor(arg, opt, method) for arg in expr]) else: return expr def _generic_factor_list(expr, gens, args, method): """Helper function for :func:`sqf_list` and :func:`factor_list`. """ options.allowed_flags(args, ['frac', 'polys']) opt = options.build_options(gens, args) expr = sympify(expr) if isinstance(expr, (Expr, Poly)): if isinstance(expr, Poly): numer, denom = expr, 1 else: numer, denom = together(expr).as_numer_denom() cp, fp = _symbolic_factor_list(numer, opt, method) cq, fq = _symbolic_factor_list(denom, opt, method) if fq and not opt.frac: raise PolynomialError("a polynomial expected, got %s" % expr) _opt = opt.clone(dict(expand=True)) for factors in (fp, fq): for i, (f, k) in enumerate(factors): if not f.is_Poly: f, _ = _poly_from_expr(f, _opt) factors[i] = (f, k) fp = _sorted_factors(fp, method) fq = _sorted_factors(fq, method) if not opt.polys: fp = [(f.as_expr(), k) for f, k in fp] fq = [(f.as_expr(), k) for f, k in fq] coeff = cp/cq if not opt.frac: return coeff, fp else: return coeff, fp, fq else: raise PolynomialError("a polynomial expected, got %s" % expr) def _generic_factor(expr, gens, args, method): """Helper function for :func:`sqf` and :func:`factor`. """ fraction = args.pop('fraction', True) options.allowed_flags(args, []) opt = options.build_options(gens, args) opt['fraction'] = fraction return _symbolic_factor(sympify(expr), opt, method) def to_rational_coeffs(f): """ try to transform a polynomial to have rational coefficients try to find a transformation ``x = alpha*y`` ``f(x) = lc*alpha**n * g(y)`` where ``g`` is a polynomial with rational coefficients, ``lc`` the leading coefficient. If this fails, try ``x = y + beta`` ``f(x) = g(y)`` Returns ``None`` if ``g`` not found; ``(lc, alpha, None, g)`` in case of rescaling ``(None, None, beta, g)`` in case of translation Notes ===== Currently it transforms only polynomials without roots larger than 2. Examples ======== >>> from sympy import sqrt, Poly, simplify >>> from sympy.polys.polytools import to_rational_coeffs >>> from sympy.abc import x >>> p = Poly(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))}), x, domain='EX') >>> lc, r, _, g = to_rational_coeffs(p) >>> lc, r (7 + 5*sqrt(2), 2 - 2*sqrt(2)) >>> g Poly(x**3 + x**2 - 1/4*x - 1/4, x, domain='QQ') >>> r1 = simplify(1/r) >>> Poly(lc*r**3*(g.as_expr()).subs({x:x*r1}), x, domain='EX') == p True """ from sympy.simplify.simplify import simplify def _try_rescale(f, f1=None): """ try rescaling ``x -> alpha*x`` to convert f to a polynomial with rational coefficients. Returns ``alpha, f``; if the rescaling is successful, ``alpha`` is the rescaling factor, and ``f`` is the rescaled polynomial; else ``alpha`` is ``None``. """ from sympy.core.add import Add if not len(f.gens) == 1 or not (f.gens[0]).is_Atom: return None, f n = f.degree() lc = f.LC() f1 = f1 or f1.monic() coeffs = f1.all_coeffs()[1:] coeffs = [simplify(coeffx) for coeffx in coeffs] if len(coeffs) > 1 and coeffs[-2]: rescale1_x = simplify(coeffs[-2]/coeffs[-1]) coeffs1 = [] for i in range(len(coeffs)): coeffx = simplify(coeffs[i]*rescale1_x**(i + 1)) if not coeffx.is_rational: break coeffs1.append(coeffx) else: rescale_x = simplify(1/rescale1_x) x = f.gens[0] v = [x**n] for i in range(1, n + 1): v.append(coeffs1[i - 1]*x**(n - i)) f = Add(*v) f = Poly(f) return lc, rescale_x, f return None def _try_translate(f, f1=None): """ try translating ``x -> x + alpha`` to convert f to a polynomial with rational coefficients. Returns ``alpha, f``; if the translating is successful, ``alpha`` is the translating factor, and ``f`` is the shifted polynomial; else ``alpha`` is ``None``. """ if not len(f.gens) == 1 or not (f.gens[0]).is_Atom: return None, f n = f.degree() f1 = f1 or f1.monic() coeffs = f1.all_coeffs()[1:] c = simplify(coeffs[0]) if c.is_Add and not c.is_rational: rat, nonrat = sift(c.args, lambda z: z.is_rational is True, binary=True) alpha = -c.func(*nonrat)/n f2 = f1.shift(alpha) return alpha, f2 return None def _has_square_roots(p): """ Return True if ``f`` is a sum with square roots but no other root """ from sympy.core.exprtools import Factors coeffs = p.coeffs() has_sq = False for y in coeffs: for x in Add.make_args(y): f = Factors(x).factors r = [wx.q for b, wx in f.items() if b.is_number and wx.is_Rational and wx.q >= 2] if not r: continue if min(r) == 2: has_sq = True if max(r) > 2: return False return has_sq if f.get_domain().is_EX and _has_square_roots(f): f1 = f.monic() r = _try_rescale(f, f1) if r: return r[0], r[1], None, r[2] else: r = _try_translate(f, f1) if r: return None, None, r[0], r[1] return None def _torational_factor_list(p, x): """ helper function to factor polynomial using to_rational_coeffs Examples ======== >>> from sympy.polys.polytools import _torational_factor_list >>> from sympy.abc import x >>> from sympy import sqrt, expand, Mul >>> p = expand(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))})) >>> factors = _torational_factor_list(p, x); factors (-2, [(-x*(1 + sqrt(2))/2 + 1, 1), (-x*(1 + sqrt(2)) - 1, 1), (-x*(1 + sqrt(2)) + 1, 1)]) >>> expand(factors[0]*Mul(*[z[0] for z in factors[1]])) == p True >>> p = expand(((x**2-1)*(x-2)).subs({x:x + sqrt(2)})) >>> factors = _torational_factor_list(p, x); factors (1, [(x - 2 + sqrt(2), 1), (x - 1 + sqrt(2), 1), (x + 1 + sqrt(2), 1)]) >>> expand(factors[0]*Mul(*[z[0] for z in factors[1]])) == p True """ from sympy.simplify.simplify import simplify p1 = Poly(p, x, domain='EX') n = p1.degree() res = to_rational_coeffs(p1) if not res: return None lc, r, t, g = res factors = factor_list(g.as_expr()) if lc: c = simplify(factors[0]*lc*r**n) r1 = simplify(1/r) a = [] for z in factors[1:][0]: a.append((simplify(z[0].subs({x: x*r1})), z[1])) else: c = factors[0] a = [] for z in factors[1:][0]: a.append((z[0].subs({x: x - t}), z[1])) return (c, a) @public def sqf_list(f, *gens, **args): """ Compute a list of square-free factors of ``f``. Examples ======== >>> from sympy import sqf_list >>> from sympy.abc import x >>> sqf_list(2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16) (2, [(x + 1, 2), (x + 2, 3)]) """ return _generic_factor_list(f, gens, args, method='sqf') @public def sqf(f, *gens, **args): """ Compute square-free factorization of ``f``. Examples ======== >>> from sympy import sqf >>> from sympy.abc import x >>> sqf(2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16) 2*(x + 1)**2*(x + 2)**3 """ return _generic_factor(f, gens, args, method='sqf') @public def factor_list(f, *gens, **args): """ Compute a list of irreducible factors of ``f``. Examples ======== >>> from sympy import factor_list >>> from sympy.abc import x, y >>> factor_list(2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y) (2, [(x + y, 1), (x**2 + 1, 2)]) """ return _generic_factor_list(f, gens, args, method='factor') @public def factor(f, *gens, deep=False, **args): """ Compute the factorization of expression, ``f``, into irreducibles. (To factor an integer into primes, use ``factorint``.) There two modes implemented: symbolic and formal. If ``f`` is not an instance of :class:`Poly` and generators are not specified, then the former mode is used. Otherwise, the formal mode is used. In symbolic mode, :func:`factor` will traverse the expression tree and factor its components without any prior expansion, unless an instance of :class:`~.Add` is encountered (in this case formal factorization is used). This way :func:`factor` can handle large or symbolic exponents. By default, the factorization is computed over the rationals. To factor over other domain, e.g. an algebraic or finite field, use appropriate options: ``extension``, ``modulus`` or ``domain``. Examples ======== >>> from sympy import factor, sqrt, exp >>> from sympy.abc import x, y >>> factor(2*x**5 + 2*x**4*y + 4*x**3 + 4*x**2*y + 2*x + 2*y) 2*(x + y)*(x**2 + 1)**2 >>> factor(x**2 + 1) x**2 + 1 >>> factor(x**2 + 1, modulus=2) (x + 1)**2 >>> factor(x**2 + 1, gaussian=True) (x - I)*(x + I) >>> factor(x**2 - 2, extension=sqrt(2)) (x - sqrt(2))*(x + sqrt(2)) >>> factor((x**2 - 1)/(x**2 + 4*x + 4)) (x - 1)*(x + 1)/(x + 2)**2 >>> factor((x**2 + 4*x + 4)**10000000*(x**2 + 1)) (x + 2)**20000000*(x**2 + 1) By default, factor deals with an expression as a whole: >>> eq = 2**(x**2 + 2*x + 1) >>> factor(eq) 2**(x**2 + 2*x + 1) If the ``deep`` flag is True then subexpressions will be factored: >>> factor(eq, deep=True) 2**((x + 1)**2) If the ``fraction`` flag is False then rational expressions won't be combined. By default it is True. >>> factor(5*x + 3*exp(2 - 7*x), deep=True) (5*x*exp(7*x) + 3*exp(2))*exp(-7*x) >>> factor(5*x + 3*exp(2 - 7*x), deep=True, fraction=False) 5*x + 3*exp(2)*exp(-7*x) See Also ======== sympy.ntheory.factor_.factorint """ f = sympify(f) if deep: from sympy.simplify.simplify import bottom_up def _try_factor(expr): """ Factor, but avoid changing the expression when unable to. """ fac = factor(expr, *gens, **args) if fac.is_Mul or fac.is_Pow: return fac return expr f = bottom_up(f, _try_factor) # clean up any subexpressions that may have been expanded # while factoring out a larger expression partials = {} muladd = f.atoms(Mul, Add) for p in muladd: fac = factor(p, *gens, **args) if (fac.is_Mul or fac.is_Pow) and fac != p: partials[p] = fac return f.xreplace(partials) try: return _generic_factor(f, gens, args, method='factor') except PolynomialError as msg: if not f.is_commutative: from sympy.core.exprtools import factor_nc return factor_nc(f) else: raise PolynomialError(msg) @public def intervals(F, all=False, eps=None, inf=None, sup=None, strict=False, fast=False, sqf=False): """ Compute isolating intervals for roots of ``f``. Examples ======== >>> from sympy import intervals >>> from sympy.abc import x >>> intervals(x**2 - 3) [((-2, -1), 1), ((1, 2), 1)] >>> intervals(x**2 - 3, eps=1e-2) [((-26/15, -19/11), 1), ((19/11, 26/15), 1)] """ if not hasattr(F, '__iter__'): try: F = Poly(F) except GeneratorsNeeded: return [] return F.intervals(all=all, eps=eps, inf=inf, sup=sup, fast=fast, sqf=sqf) else: polys, opt = parallel_poly_from_expr(F, domain='QQ') if len(opt.gens) > 1: raise MultivariatePolynomialError for i, poly in enumerate(polys): polys[i] = poly.rep.rep if eps is not None: eps = opt.domain.convert(eps) if eps <= 0: raise ValueError("'eps' must be a positive rational") if inf is not None: inf = opt.domain.convert(inf) if sup is not None: sup = opt.domain.convert(sup) intervals = dup_isolate_real_roots_list(polys, opt.domain, eps=eps, inf=inf, sup=sup, strict=strict, fast=fast) result = [] for (s, t), indices in intervals: s, t = opt.domain.to_sympy(s), opt.domain.to_sympy(t) result.append(((s, t), indices)) return result @public def refine_root(f, s, t, eps=None, steps=None, fast=False, check_sqf=False): """ Refine an isolating interval of a root to the given precision. Examples ======== >>> from sympy import refine_root >>> from sympy.abc import x >>> refine_root(x**2 - 3, 1, 2, eps=1e-2) (19/11, 26/15) """ try: F = Poly(f) if not isinstance(f, Poly) and not F.gen.is_Symbol: # root of sin(x) + 1 is -1 but when someone # passes an Expr instead of Poly they may not expect # that the generator will be sin(x), not x raise PolynomialError("generator must be a Symbol") except GeneratorsNeeded: raise PolynomialError( "can't refine a root of %s, not a polynomial" % f) return F.refine_root(s, t, eps=eps, steps=steps, fast=fast, check_sqf=check_sqf) @public def count_roots(f, inf=None, sup=None): """ Return the number of roots of ``f`` in ``[inf, sup]`` interval. If one of ``inf`` or ``sup`` is complex, it will return the number of roots in the complex rectangle with corners at ``inf`` and ``sup``. Examples ======== >>> from sympy import count_roots, I >>> from sympy.abc import x >>> count_roots(x**4 - 4, -3, 3) 2 >>> count_roots(x**4 - 4, 0, 1 + 3*I) 1 """ try: F = Poly(f, greedy=False) if not isinstance(f, Poly) and not F.gen.is_Symbol: # root of sin(x) + 1 is -1 but when someone # passes an Expr instead of Poly they may not expect # that the generator will be sin(x), not x raise PolynomialError("generator must be a Symbol") except GeneratorsNeeded: raise PolynomialError("can't count roots of %s, not a polynomial" % f) return F.count_roots(inf=inf, sup=sup) @public def real_roots(f, multiple=True): """ Return a list of real roots with multiplicities of ``f``. Examples ======== >>> from sympy import real_roots >>> from sympy.abc import x >>> real_roots(2*x**3 - 7*x**2 + 4*x + 4) [-1/2, 2, 2] """ try: F = Poly(f, greedy=False) if not isinstance(f, Poly) and not F.gen.is_Symbol: # root of sin(x) + 1 is -1 but when someone # passes an Expr instead of Poly they may not expect # that the generator will be sin(x), not x raise PolynomialError("generator must be a Symbol") except GeneratorsNeeded: raise PolynomialError( "can't compute real roots of %s, not a polynomial" % f) return F.real_roots(multiple=multiple) @public def nroots(f, n=15, maxsteps=50, cleanup=True): """ Compute numerical approximations of roots of ``f``. Examples ======== >>> from sympy import nroots >>> from sympy.abc import x >>> nroots(x**2 - 3, n=15) [-1.73205080756888, 1.73205080756888] >>> nroots(x**2 - 3, n=30) [-1.73205080756887729352744634151, 1.73205080756887729352744634151] """ try: F = Poly(f, greedy=False) if not isinstance(f, Poly) and not F.gen.is_Symbol: # root of sin(x) + 1 is -1 but when someone # passes an Expr instead of Poly they may not expect # that the generator will be sin(x), not x raise PolynomialError("generator must be a Symbol") except GeneratorsNeeded: raise PolynomialError( "can't compute numerical roots of %s, not a polynomial" % f) return F.nroots(n=n, maxsteps=maxsteps, cleanup=cleanup) @public def ground_roots(f, *gens, **args): """ Compute roots of ``f`` by factorization in the ground domain. Examples ======== >>> from sympy import ground_roots >>> from sympy.abc import x >>> ground_roots(x**6 - 4*x**4 + 4*x**3 - x**2) {0: 2, 1: 2} """ options.allowed_flags(args, []) try: F, opt = poly_from_expr(f, *gens, **args) if not isinstance(f, Poly) and not F.gen.is_Symbol: # root of sin(x) + 1 is -1 but when someone # passes an Expr instead of Poly they may not expect # that the generator will be sin(x), not x raise PolynomialError("generator must be a Symbol") except PolificationFailed as exc: raise ComputationFailed('ground_roots', 1, exc) return F.ground_roots() @public def nth_power_roots_poly(f, n, *gens, **args): """ Construct a polynomial with n-th powers of roots of ``f``. Examples ======== >>> from sympy import nth_power_roots_poly, factor, roots >>> from sympy.abc import x >>> f = x**4 - x**2 + 1 >>> g = factor(nth_power_roots_poly(f, 2)) >>> g (x**2 - x + 1)**2 >>> R_f = [ (r**2).expand() for r in roots(f) ] >>> R_g = roots(g).keys() >>> set(R_f) == set(R_g) True """ options.allowed_flags(args, []) try: F, opt = poly_from_expr(f, *gens, **args) if not isinstance(f, Poly) and not F.gen.is_Symbol: # root of sin(x) + 1 is -1 but when someone # passes an Expr instead of Poly they may not expect # that the generator will be sin(x), not x raise PolynomialError("generator must be a Symbol") except PolificationFailed as exc: raise ComputationFailed('nth_power_roots_poly', 1, exc) result = F.nth_power_roots_poly(n) if not opt.polys: return result.as_expr() else: return result @public def cancel(f, *gens, **args): """ Cancel common factors in a rational function ``f``. Examples ======== >>> from sympy import cancel, sqrt, Symbol, together >>> from sympy.abc import x >>> A = Symbol('A', commutative=False) >>> cancel((2*x**2 - 2)/(x**2 - 2*x + 1)) (2*x + 2)/(x - 1) >>> cancel((sqrt(3) + sqrt(15)*A)/(sqrt(2) + sqrt(10)*A)) sqrt(6)/2 Note: due to automatic distribution of Rationals, a sum divided by an integer will appear as a sum. To recover a rational form use `together` on the result: >>> cancel(x/2 + 1) x/2 + 1 >>> together(_) (x + 2)/2 """ from sympy.core.exprtools import factor_terms from sympy.functions.elementary.piecewise import Piecewise from sympy.polys.rings import sring options.allowed_flags(args, ['polys']) f = sympify(f) opt = {} if 'polys' in args: opt['polys'] = args['polys'] if not isinstance(f, (tuple, Tuple)): if f.is_Number or isinstance(f, Relational) or not isinstance(f, Expr): return f f = factor_terms(f, radical=True) p, q = f.as_numer_denom() elif len(f) == 2: p, q = f if isinstance(p, Poly) and isinstance(q, Poly): opt['gens'] = p.gens opt['domain'] = p.domain opt['polys'] = opt.get('polys', True) p, q = p.as_expr(), q.as_expr() elif isinstance(f, Tuple): return factor_terms(f) else: raise ValueError('unexpected argument: %s' % f) try: if f.has(Piecewise): raise PolynomialError() R, (F, G) = sring((p, q), *gens, **args) if not R.ngens: if not isinstance(f, (tuple, Tuple)): return f.expand() else: return S.One, p, q except PolynomialError as msg: if f.is_commutative and not f.has(Piecewise): raise PolynomialError(msg) # Handling of noncommutative and/or piecewise expressions if f.is_Add or f.is_Mul: c, nc = sift(f.args, lambda x: x.is_commutative is True and not x.has(Piecewise), binary=True) nc = [cancel(i) for i in nc] return f.func(cancel(f.func(*c)), *nc) else: reps = [] pot = preorder_traversal(f) next(pot) for e in pot: # XXX: This should really skip anything that's not Expr. if isinstance(e, (tuple, Tuple, BooleanAtom)): continue try: reps.append((e, cancel(e))) pot.skip() # this was handled successfully except NotImplementedError: pass return f.xreplace(dict(reps)) c, (P, Q) = 1, F.cancel(G) if opt.get('polys', False) and not 'gens' in opt: opt['gens'] = R.symbols if not isinstance(f, (tuple, Tuple)): return c*(P.as_expr()/Q.as_expr()) else: P, Q = P.as_expr(), Q.as_expr() if not opt.get('polys', False): return c, P, Q else: return c, Poly(P, *gens, **opt), Poly(Q, *gens, **opt) @public def reduced(f, G, *gens, **args): """ Reduces a polynomial ``f`` modulo a set of polynomials ``G``. Given a polynomial ``f`` and a set of polynomials ``G = (g_1, ..., g_n)``, computes a set of quotients ``q = (q_1, ..., q_n)`` and the remainder ``r`` such that ``f = q_1*g_1 + ... + q_n*g_n + r``, where ``r`` vanishes or ``r`` is a completely reduced polynomial with respect to ``G``. Examples ======== >>> from sympy import reduced >>> from sympy.abc import x, y >>> reduced(2*x**4 + y**2 - x**2 + y**3, [x**3 - x, y**3 - y]) ([2*x, 1], x**2 + y**2 + y) """ options.allowed_flags(args, ['polys', 'auto']) try: polys, opt = parallel_poly_from_expr([f] + list(G), *gens, **args) except PolificationFailed as exc: raise ComputationFailed('reduced', 0, exc) domain = opt.domain retract = False if opt.auto and domain.is_Ring and not domain.is_Field: opt = opt.clone(dict(domain=domain.get_field())) retract = True from sympy.polys.rings import xring _ring, _ = xring(opt.gens, opt.domain, opt.order) for i, poly in enumerate(polys): poly = poly.set_domain(opt.domain).rep.to_dict() polys[i] = _ring.from_dict(poly) Q, r = polys[0].div(polys[1:]) Q = [Poly._from_dict(dict(q), opt) for q in Q] r = Poly._from_dict(dict(r), opt) if retract: try: _Q, _r = [q.to_ring() for q in Q], r.to_ring() except CoercionFailed: pass else: Q, r = _Q, _r if not opt.polys: return [q.as_expr() for q in Q], r.as_expr() else: return Q, r @public def groebner(F, *gens, **args): """ Computes the reduced Groebner basis for a set of polynomials. Use the ``order`` argument to set the monomial ordering that will be used to compute the basis. Allowed orders are ``lex``, ``grlex`` and ``grevlex``. If no order is specified, it defaults to ``lex``. For more information on Groebner bases, see the references and the docstring of :func:`~.solve_poly_system`. Examples ======== Example taken from [1]. >>> from sympy import groebner >>> from sympy.abc import x, y >>> F = [x*y - 2*y, 2*y**2 - x**2] >>> groebner(F, x, y, order='lex') GroebnerBasis([x**2 - 2*y**2, x*y - 2*y, y**3 - 2*y], x, y, domain='ZZ', order='lex') >>> groebner(F, x, y, order='grlex') GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, domain='ZZ', order='grlex') >>> groebner(F, x, y, order='grevlex') GroebnerBasis([y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y], x, y, domain='ZZ', order='grevlex') By default, an improved implementation of the Buchberger algorithm is used. Optionally, an implementation of the F5B algorithm can be used. The algorithm can be set using the ``method`` flag or with the :func:`sympy.polys.polyconfig.setup` function. >>> F = [x**2 - x - 1, (2*x - 1) * y - (x**10 - (1 - x)**10)] >>> groebner(F, x, y, method='buchberger') GroebnerBasis([x**2 - x - 1, y - 55], x, y, domain='ZZ', order='lex') >>> groebner(F, x, y, method='f5b') GroebnerBasis([x**2 - x - 1, y - 55], x, y, domain='ZZ', order='lex') References ========== 1. [Buchberger01]_ 2. [Cox97]_ """ return GroebnerBasis(F, *gens, **args) @public def is_zero_dimensional(F, *gens, **args): """ Checks if the ideal generated by a Groebner basis is zero-dimensional. The algorithm checks if the set of monomials not divisible by the leading monomial of any element of ``F`` is bounded. References ========== David A. Cox, John B. Little, Donal O'Shea. Ideals, Varieties and Algorithms, 3rd edition, p. 230 """ return GroebnerBasis(F, *gens, **args).is_zero_dimensional @public class GroebnerBasis(Basic): """Represents a reduced Groebner basis. """ def __new__(cls, F, *gens, **args): """Compute a reduced Groebner basis for a system of polynomials. """ options.allowed_flags(args, ['polys', 'method']) try: polys, opt = parallel_poly_from_expr(F, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('groebner', len(F), exc) from sympy.polys.rings import PolyRing ring = PolyRing(opt.gens, opt.domain, opt.order) polys = [ring.from_dict(poly.rep.to_dict()) for poly in polys if poly] G = _groebner(polys, ring, method=opt.method) G = [Poly._from_dict(g, opt) for g in G] return cls._new(G, opt) @classmethod def _new(cls, basis, options): obj = Basic.__new__(cls) obj._basis = tuple(basis) obj._options = options return obj @property def args(self): basis = (p.as_expr() for p in self._basis) return (Tuple(*basis), Tuple(*self._options.gens)) @property def exprs(self): return [poly.as_expr() for poly in self._basis] @property def polys(self): return list(self._basis) @property def gens(self): return self._options.gens @property def domain(self): return self._options.domain @property def order(self): return self._options.order def __len__(self): return len(self._basis) def __iter__(self): if self._options.polys: return iter(self.polys) else: return iter(self.exprs) def __getitem__(self, item): if self._options.polys: basis = self.polys else: basis = self.exprs return basis[item] def __hash__(self): return hash((self._basis, tuple(self._options.items()))) def __eq__(self, other): if isinstance(other, self.__class__): return self._basis == other._basis and self._options == other._options elif iterable(other): return self.polys == list(other) or self.exprs == list(other) else: return False def __ne__(self, other): return not self == other @property def is_zero_dimensional(self): """ Checks if the ideal generated by a Groebner basis is zero-dimensional. The algorithm checks if the set of monomials not divisible by the leading monomial of any element of ``F`` is bounded. References ========== David A. Cox, John B. Little, Donal O'Shea. Ideals, Varieties and Algorithms, 3rd edition, p. 230 """ def single_var(monomial): return sum(map(bool, monomial)) == 1 exponents = Monomial([0]*len(self.gens)) order = self._options.order for poly in self.polys: monomial = poly.LM(order=order) if single_var(monomial): exponents *= monomial # If any element of the exponents vector is zero, then there's # a variable for which there's no degree bound and the ideal # generated by this Groebner basis isn't zero-dimensional. return all(exponents) def fglm(self, order): """ Convert a Groebner basis from one ordering to another. The FGLM algorithm converts reduced Groebner bases of zero-dimensional ideals from one ordering to another. This method is often used when it is infeasible to compute a Groebner basis with respect to a particular ordering directly. Examples ======== >>> from sympy.abc import x, y >>> from sympy import groebner >>> F = [x**2 - 3*y - x + 1, y**2 - 2*x + y - 1] >>> G = groebner(F, x, y, order='grlex') >>> list(G.fglm('lex')) [2*x - y**2 - y + 1, y**4 + 2*y**3 - 3*y**2 - 16*y + 7] >>> list(groebner(F, x, y, order='lex')) [2*x - y**2 - y + 1, y**4 + 2*y**3 - 3*y**2 - 16*y + 7] References ========== .. [1] J.C. Faugere, P. Gianni, D. Lazard, T. Mora (1994). Efficient Computation of Zero-dimensional Groebner Bases by Change of Ordering """ opt = self._options src_order = opt.order dst_order = monomial_key(order) if src_order == dst_order: return self if not self.is_zero_dimensional: raise NotImplementedError("can't convert Groebner bases of ideals with positive dimension") polys = list(self._basis) domain = opt.domain opt = opt.clone(dict( domain=domain.get_field(), order=dst_order, )) from sympy.polys.rings import xring _ring, _ = xring(opt.gens, opt.domain, src_order) for i, poly in enumerate(polys): poly = poly.set_domain(opt.domain).rep.to_dict() polys[i] = _ring.from_dict(poly) G = matrix_fglm(polys, _ring, dst_order) G = [Poly._from_dict(dict(g), opt) for g in G] if not domain.is_Field: G = [g.clear_denoms(convert=True)[1] for g in G] opt.domain = domain return self._new(G, opt) def reduce(self, expr, auto=True): """ Reduces a polynomial modulo a Groebner basis. Given a polynomial ``f`` and a set of polynomials ``G = (g_1, ..., g_n)``, computes a set of quotients ``q = (q_1, ..., q_n)`` and the remainder ``r`` such that ``f = q_1*f_1 + ... + q_n*f_n + r``, where ``r`` vanishes or ``r`` is a completely reduced polynomial with respect to ``G``. Examples ======== >>> from sympy import groebner, expand >>> from sympy.abc import x, y >>> f = 2*x**4 - x**2 + y**3 + y**2 >>> G = groebner([x**3 - x, y**3 - y]) >>> G.reduce(f) ([2*x, 1], x**2 + y**2 + y) >>> Q, r = _ >>> expand(sum(q*g for q, g in zip(Q, G)) + r) 2*x**4 - x**2 + y**3 + y**2 >>> _ == f True """ poly = Poly._from_expr(expr, self._options) polys = [poly] + list(self._basis) opt = self._options domain = opt.domain retract = False if auto and domain.is_Ring and not domain.is_Field: opt = opt.clone(dict(domain=domain.get_field())) retract = True from sympy.polys.rings import xring _ring, _ = xring(opt.gens, opt.domain, opt.order) for i, poly in enumerate(polys): poly = poly.set_domain(opt.domain).rep.to_dict() polys[i] = _ring.from_dict(poly) Q, r = polys[0].div(polys[1:]) Q = [Poly._from_dict(dict(q), opt) for q in Q] r = Poly._from_dict(dict(r), opt) if retract: try: _Q, _r = [q.to_ring() for q in Q], r.to_ring() except CoercionFailed: pass else: Q, r = _Q, _r if not opt.polys: return [q.as_expr() for q in Q], r.as_expr() else: return Q, r def contains(self, poly): """ Check if ``poly`` belongs the ideal generated by ``self``. Examples ======== >>> from sympy import groebner >>> from sympy.abc import x, y >>> f = 2*x**3 + y**3 + 3*y >>> G = groebner([x**2 + y**2 - 1, x*y - 2]) >>> G.contains(f) True >>> G.contains(f + 1) False """ return self.reduce(poly)[1] == 0 @public def poly(expr, *gens, **args): """ Efficiently transform an expression into a polynomial. Examples ======== >>> from sympy import poly >>> from sympy.abc import x >>> poly(x*(x**2 + x - 1)**2) Poly(x**5 + 2*x**4 - x**3 - 2*x**2 + x, x, domain='ZZ') """ options.allowed_flags(args, []) def _poly(expr, opt): terms, poly_terms = [], [] for term in Add.make_args(expr): factors, poly_factors = [], [] for factor in Mul.make_args(term): if factor.is_Add: poly_factors.append(_poly(factor, opt)) elif factor.is_Pow and factor.base.is_Add and \ factor.exp.is_Integer and factor.exp >= 0: poly_factors.append( _poly(factor.base, opt).pow(factor.exp)) else: factors.append(factor) if not poly_factors: terms.append(term) else: product = poly_factors[0] for factor in poly_factors[1:]: product = product.mul(factor) if factors: factor = Mul(*factors) if factor.is_Number: product = product.mul(factor) else: product = product.mul(Poly._from_expr(factor, opt)) poly_terms.append(product) if not poly_terms: result = Poly._from_expr(expr, opt) else: result = poly_terms[0] for term in poly_terms[1:]: result = result.add(term) if terms: term = Add(*terms) if term.is_Number: result = result.add(term) else: result = result.add(Poly._from_expr(term, opt)) return result.reorder(*opt.get('gens', ()), **args) expr = sympify(expr) if expr.is_Poly: return Poly(expr, *gens, **args) if 'expand' not in args: args['expand'] = False opt = options.build_options(gens, args) return _poly(expr, opt) sympy-sympy-1.9/sympy/polys/polyutils.py000066400000000000000000000334411412543434000206750ustar00rootroot00000000000000"""Useful utilities for higher level polynomial classes. """ from sympy.core import (S, Add, Mul, Pow, Eq, Expr, expand_mul, expand_multinomial) from sympy.core.exprtools import decompose_power, decompose_power_rat from sympy.polys.polyerrors import PolynomialError, GeneratorsError from sympy.polys.polyoptions import build_options import re _gens_order = { 'a': 301, 'b': 302, 'c': 303, 'd': 304, 'e': 305, 'f': 306, 'g': 307, 'h': 308, 'i': 309, 'j': 310, 'k': 311, 'l': 312, 'm': 313, 'n': 314, 'o': 315, 'p': 216, 'q': 217, 'r': 218, 's': 219, 't': 220, 'u': 221, 'v': 222, 'w': 223, 'x': 124, 'y': 125, 'z': 126, } _max_order = 1000 _re_gen = re.compile(r"^(.*?)(\d*)$", re.MULTILINE) def _nsort(roots, separated=False): """Sort the numerical roots putting the real roots first, then sorting according to real and imaginary parts. If ``separated`` is True, then the real and imaginary roots will be returned in two lists, respectively. This routine tries to avoid issue 6137 by separating the roots into real and imaginary parts before evaluation. In addition, the sorting will raise an error if any computation cannot be done with precision. """ if not all(r.is_number for r in roots): raise NotImplementedError # see issue 6137: # get the real part of the evaluated real and imaginary parts of each root key = [[i.n(2).as_real_imag()[0] for i in r.as_real_imag()] for r in roots] # make sure the parts were computed with precision if len(roots) > 1 and any(i._prec == 1 for k in key for i in k): raise NotImplementedError("could not compute root with precision") # insert a key to indicate if the root has an imaginary part key = [(1 if i else 0, r, i) for r, i in key] key = sorted(zip(key, roots)) # return the real and imaginary roots separately if desired if separated: r = [] i = [] for (im, _, _), v in key: if im: i.append(v) else: r.append(v) return r, i _, roots = zip(*key) return list(roots) def _sort_gens(gens, **args): """Sort generators in a reasonably intelligent way. """ opt = build_options(args) gens_order, wrt = {}, None if opt is not None: gens_order, wrt = {}, opt.wrt for i, gen in enumerate(opt.sort): gens_order[gen] = i + 1 def order_key(gen): gen = str(gen) if wrt is not None: try: return (-len(wrt) + wrt.index(gen), gen, 0) except ValueError: pass name, index = _re_gen.match(gen).groups() if index: index = int(index) else: index = 0 try: return ( gens_order[name], name, index) except KeyError: pass try: return (_gens_order[name], name, index) except KeyError: pass return (_max_order, name, index) try: gens = sorted(gens, key=order_key) except TypeError: # pragma: no cover pass return tuple(gens) def _unify_gens(f_gens, g_gens): """Unify generators in a reasonably intelligent way. """ f_gens = list(f_gens) g_gens = list(g_gens) if f_gens == g_gens: return tuple(f_gens) gens, common, k = [], [], 0 for gen in f_gens: if gen in g_gens: common.append(gen) for i, gen in enumerate(g_gens): if gen in common: g_gens[i], k = common[k], k + 1 for gen in common: i = f_gens.index(gen) gens.extend(f_gens[:i]) f_gens = f_gens[i + 1:] i = g_gens.index(gen) gens.extend(g_gens[:i]) g_gens = g_gens[i + 1:] gens.append(gen) gens.extend(f_gens) gens.extend(g_gens) return tuple(gens) def _analyze_gens(gens): """Support for passing generators as `*gens` and `[gens]`. """ if len(gens) == 1 and hasattr(gens[0], '__iter__'): return tuple(gens[0]) else: return tuple(gens) def _sort_factors(factors, **args): """Sort low-level factors in increasing 'complexity' order. """ def order_if_multiple_key(factor): (f, n) = factor return (len(f), n, f) def order_no_multiple_key(f): return (len(f), f) if args.get('multiple', True): return sorted(factors, key=order_if_multiple_key) else: return sorted(factors, key=order_no_multiple_key) illegal = [S.NaN, S.Infinity, S.NegativeInfinity, S.ComplexInfinity] illegal_types = [type(obj) for obj in illegal] finf = [float(i) for i in illegal[1:3]] def _not_a_coeff(expr): """Do not treat NaN and infinities as valid polynomial coefficients. """ if type(expr) in illegal_types or expr in finf: return True if type(expr) is float and float(expr) != expr: return True # nan return # could be def _parallel_dict_from_expr_if_gens(exprs, opt): """Transform expressions into a multinomial form given generators. """ k, indices = len(opt.gens), {} for i, g in enumerate(opt.gens): indices[g] = i polys = [] for expr in exprs: poly = {} if expr.is_Equality: expr = expr.lhs - expr.rhs for term in Add.make_args(expr): coeff, monom = [], [0]*k for factor in Mul.make_args(term): if not _not_a_coeff(factor) and factor.is_Number: coeff.append(factor) else: try: if opt.series is False: base, exp = decompose_power(factor) if exp < 0: exp, base = -exp, Pow(base, -S.One) else: base, exp = decompose_power_rat(factor) monom[indices[base]] = exp except KeyError: if not factor.free_symbols.intersection(opt.gens): coeff.append(factor) else: raise PolynomialError("%s contains an element of " "the set of generators." % factor) monom = tuple(monom) if monom in poly: poly[monom] += Mul(*coeff) else: poly[monom] = Mul(*coeff) polys.append(poly) return polys, opt.gens def _parallel_dict_from_expr_no_gens(exprs, opt): """Transform expressions into a multinomial form and figure out generators. """ if opt.domain is not None: def _is_coeff(factor): return factor in opt.domain elif opt.extension is True: def _is_coeff(factor): return factor.is_algebraic elif opt.greedy is not False: def _is_coeff(factor): return factor is S.ImaginaryUnit else: def _is_coeff(factor): return factor.is_number gens, reprs = set(), [] for expr in exprs: terms = [] if expr.is_Equality: expr = expr.lhs - expr.rhs for term in Add.make_args(expr): coeff, elements = [], {} for factor in Mul.make_args(term): if not _not_a_coeff(factor) and (factor.is_Number or _is_coeff(factor)): coeff.append(factor) else: if opt.series is False: base, exp = decompose_power(factor) if exp < 0: exp, base = -exp, Pow(base, -S.One) else: base, exp = decompose_power_rat(factor) elements[base] = elements.setdefault(base, 0) + exp gens.add(base) terms.append((coeff, elements)) reprs.append(terms) gens = _sort_gens(gens, opt=opt) k, indices = len(gens), {} for i, g in enumerate(gens): indices[g] = i polys = [] for terms in reprs: poly = {} for coeff, term in terms: monom = [0]*k for base, exp in term.items(): monom[indices[base]] = exp monom = tuple(monom) if monom in poly: poly[monom] += Mul(*coeff) else: poly[monom] = Mul(*coeff) polys.append(poly) return polys, tuple(gens) def _dict_from_expr_if_gens(expr, opt): """Transform an expression into a multinomial form given generators. """ (poly,), gens = _parallel_dict_from_expr_if_gens((expr,), opt) return poly, gens def _dict_from_expr_no_gens(expr, opt): """Transform an expression into a multinomial form and figure out generators. """ (poly,), gens = _parallel_dict_from_expr_no_gens((expr,), opt) return poly, gens def parallel_dict_from_expr(exprs, **args): """Transform expressions into a multinomial form. """ reps, opt = _parallel_dict_from_expr(exprs, build_options(args)) return reps, opt.gens def _parallel_dict_from_expr(exprs, opt): """Transform expressions into a multinomial form. """ if opt.expand is not False: exprs = [ expr.expand() for expr in exprs ] if any(expr.is_commutative is False for expr in exprs): raise PolynomialError('non-commutative expressions are not supported') if opt.gens: reps, gens = _parallel_dict_from_expr_if_gens(exprs, opt) else: reps, gens = _parallel_dict_from_expr_no_gens(exprs, opt) return reps, opt.clone({'gens': gens}) def dict_from_expr(expr, **args): """Transform an expression into a multinomial form. """ rep, opt = _dict_from_expr(expr, build_options(args)) return rep, opt.gens def _dict_from_expr(expr, opt): """Transform an expression into a multinomial form. """ if expr.is_commutative is False: raise PolynomialError('non-commutative expressions are not supported') def _is_expandable_pow(expr): return (expr.is_Pow and expr.exp.is_positive and expr.exp.is_Integer and expr.base.is_Add) if opt.expand is not False: if not isinstance(expr, (Expr, Eq)): raise PolynomialError('expression must be of type Expr') expr = expr.expand() # TODO: Integrate this into expand() itself while any(_is_expandable_pow(i) or i.is_Mul and any(_is_expandable_pow(j) for j in i.args) for i in Add.make_args(expr)): expr = expand_multinomial(expr) while any(i.is_Mul and any(j.is_Add for j in i.args) for i in Add.make_args(expr)): expr = expand_mul(expr) if opt.gens: rep, gens = _dict_from_expr_if_gens(expr, opt) else: rep, gens = _dict_from_expr_no_gens(expr, opt) return rep, opt.clone({'gens': gens}) def expr_from_dict(rep, *gens): """Convert a multinomial form into an expression. """ result = [] for monom, coeff in rep.items(): term = [coeff] for g, m in zip(gens, monom): if m: term.append(Pow(g, m)) result.append(Mul(*term)) return Add(*result) parallel_dict_from_basic = parallel_dict_from_expr dict_from_basic = dict_from_expr basic_from_dict = expr_from_dict def _dict_reorder(rep, gens, new_gens): """Reorder levels using dict representation. """ gens = list(gens) monoms = rep.keys() coeffs = rep.values() new_monoms = [ [] for _ in range(len(rep)) ] used_indices = set() for gen in new_gens: try: j = gens.index(gen) used_indices.add(j) for M, new_M in zip(monoms, new_monoms): new_M.append(M[j]) except ValueError: for new_M in new_monoms: new_M.append(0) for i, _ in enumerate(gens): if i not in used_indices: for monom in monoms: if monom[i]: raise GeneratorsError("unable to drop generators") return map(tuple, new_monoms), coeffs class PicklableWithSlots: """ Mixin class that allows to pickle objects with ``__slots__``. Examples ======== First define a class that mixes :class:`PicklableWithSlots` in:: >>> from sympy.polys.polyutils import PicklableWithSlots >>> class Some(PicklableWithSlots): ... __slots__ = ('foo', 'bar') ... ... def __init__(self, foo, bar): ... self.foo = foo ... self.bar = bar To make :mod:`pickle` happy in doctest we have to use these hacks:: >>> import builtins >>> builtins.Some = Some >>> from sympy.polys import polyutils >>> polyutils.Some = Some Next lets see if we can create an instance, pickle it and unpickle:: >>> some = Some('abc', 10) >>> some.foo, some.bar ('abc', 10) >>> from pickle import dumps, loads >>> some2 = loads(dumps(some)) >>> some2.foo, some2.bar ('abc', 10) """ __slots__ = () def __getstate__(self, cls=None): if cls is None: # This is the case for the instance that gets pickled cls = self.__class__ d = {} # Get all data that should be stored from super classes for c in cls.__bases__: if hasattr(c, "__getstate__"): d.update(c.__getstate__(self, c)) # Get all information that should be stored from cls and return the dict for name in cls.__slots__: if hasattr(self, name): d[name] = getattr(self, name) return d def __setstate__(self, d): # All values that were pickled are now assigned to a fresh instance for name, value in d.items(): try: setattr(self, name, value) except AttributeError: # This is needed in cases like Rational :> Half pass sympy-sympy-1.9/sympy/polys/rationaltools.py000066400000000000000000000054361412543434000215260ustar00rootroot00000000000000"""Tools for manipulation of rational expressions. """ from sympy.core import Basic, Add, sympify from sympy.core.compatibility import iterable from sympy.core.exprtools import gcd_terms from sympy.utilities import public @public def together(expr, deep=False, fraction=True): """ Denest and combine rational expressions using symbolic methods. This function takes an expression or a container of expressions and puts it (them) together by denesting and combining rational subexpressions. No heroic measures are taken to minimize degree of the resulting numerator and denominator. To obtain completely reduced expression use :func:`~.cancel`. However, :func:`~.together` can preserve as much as possible of the structure of the input expression in the output (no expansion is performed). A wide variety of objects can be put together including lists, tuples, sets, relational objects, integrals and others. It is also possible to transform interior of function applications, by setting ``deep`` flag to ``True``. By definition, :func:`~.together` is a complement to :func:`~.apart`, so ``apart(together(expr))`` should return expr unchanged. Note however, that :func:`~.together` uses only symbolic methods, so it might be necessary to use :func:`~.cancel` to perform algebraic simplification and minimize degree of the numerator and denominator. Examples ======== >>> from sympy import together, exp >>> from sympy.abc import x, y, z >>> together(1/x + 1/y) (x + y)/(x*y) >>> together(1/x + 1/y + 1/z) (x*y + x*z + y*z)/(x*y*z) >>> together(1/(x*y) + 1/y**2) (x + y)/(x*y**2) >>> together(1/(1 + 1/x) + 1/(1 + 1/y)) (x*(y + 1) + y*(x + 1))/((x + 1)*(y + 1)) >>> together(exp(1/x + 1/y)) exp(1/y + 1/x) >>> together(exp(1/x + 1/y), deep=True) exp((x + y)/(x*y)) >>> together(1/exp(x) + 1/(x*exp(x))) (x + 1)*exp(-x)/x >>> together(1/exp(2*x) + 1/(x*exp(3*x))) (x*exp(x) + 1)*exp(-3*x)/x """ def _together(expr): if isinstance(expr, Basic): if expr.is_Atom or (expr.is_Function and not deep): return expr elif expr.is_Add: return gcd_terms(list(map(_together, Add.make_args(expr))), fraction=fraction) elif expr.is_Pow: base = _together(expr.base) if deep: exp = _together(expr.exp) else: exp = expr.exp return expr.__class__(base, exp) else: return expr.__class__(*[ _together(arg) for arg in expr.args ]) elif iterable(expr): return expr.__class__([ _together(ex) for ex in expr ]) return expr return _together(sympify(expr)) sympy-sympy-1.9/sympy/polys/ring_series.py000066400000000000000000001607661412543434000211550ustar00rootroot00000000000000"""Power series evaluation and manipulation using sparse Polynomials Implementing a new function --------------------------- There are a few things to be kept in mind when adding a new function here:: - The implementation should work on all possible input domains/rings. Special cases include the ``EX`` ring and a constant term in the series to be expanded. There can be two types of constant terms in the series: + A constant value or symbol. + A term of a multivariate series not involving the generator, with respect to which the series is to expanded. Strictly speaking, a generator of a ring should not be considered a constant. However, for series expansion both the cases need similar treatment (as the user doesn't care about inner details), i.e, use an addition formula to separate the constant part and the variable part (see rs_sin for reference). - All the algorithms used here are primarily designed to work for Taylor series (number of iterations in the algo equals the required order). Hence, it becomes tricky to get the series of the right order if a Puiseux series is input. Use rs_puiseux? in your function if your algorithm is not designed to handle fractional powers. Extending rs_series ------------------- To make a function work with rs_series you need to do two things:: - Many sure it works with a constant term (as explained above). - If the series contains constant terms, you might need to extend its ring. You do so by adding the new terms to the rings as generators. ``PolyRing.compose`` and ``PolyRing.add_gens`` are two functions that do so and need to be called every time you expand a series containing a constant term. Look at rs_sin and rs_series for further reference. """ from sympy.polys.domains import QQ, EX from sympy.polys.rings import PolyElement, ring, sring from sympy.polys.polyerrors import DomainError from sympy.polys.monomials import (monomial_min, monomial_mul, monomial_div, monomial_ldiv) from mpmath.libmp.libintmath import ifac from sympy.core import PoleError, Function, Expr from sympy.core.numbers import Rational, igcd from sympy.core.compatibility import as_int from sympy.functions import sin, cos, tan, atan, exp, atanh, tanh, log, ceiling from mpmath.libmp.libintmath import giant_steps import math def _invert_monoms(p1): """ Compute ``x**n * p1(1/x)`` for a univariate polynomial ``p1`` in ``x``. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import _invert_monoms >>> R, x = ring('x', ZZ) >>> p = x**2 + 2*x + 3 >>> _invert_monoms(p) 3*x**2 + 2*x + 1 See Also ======== sympy.polys.densebasic.dup_reverse """ terms = list(p1.items()) terms.sort() deg = p1.degree() R = p1.ring p = R.zero cv = p1.listcoeffs() mv = p1.listmonoms() for i in range(len(mv)): p[(deg - mv[i][0],)] = cv[i] return p def _giant_steps(target): """Return a list of precision steps for the Newton's method""" res = giant_steps(2, target) if res[0] != 2: res = [2] + res return res def rs_trunc(p1, x, prec): """ Truncate the series in the ``x`` variable with precision ``prec``, that is, modulo ``O(x**prec)`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_trunc >>> R, x = ring('x', QQ) >>> p = x**10 + x**5 + x + 1 >>> rs_trunc(p, x, 12) x**10 + x**5 + x + 1 >>> rs_trunc(p, x, 10) x**5 + x + 1 """ R = p1.ring p = R.zero i = R.gens.index(x) for exp1 in p1: if exp1[i] >= prec: continue p[exp1] = p1[exp1] return p def rs_is_puiseux(p, x): """ Test if ``p`` is Puiseux series in ``x``. Raise an exception if it has a negative power in ``x``. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_is_puiseux >>> R, x = ring('x', QQ) >>> p = x**QQ(2,5) + x**QQ(2,3) + x >>> rs_is_puiseux(p, x) True """ index = p.ring.gens.index(x) for k in p: if k[index] != int(k[index]): return True if k[index] < 0: raise ValueError('The series is not regular in %s' % x) return False def rs_puiseux(f, p, x, prec): """ Return the puiseux series for `f(p, x, prec)`. To be used when function ``f`` is implemented only for regular series. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_puiseux, rs_exp >>> R, x = ring('x', QQ) >>> p = x**QQ(2,5) + x**QQ(2,3) + x >>> rs_puiseux(rs_exp,p, x, 1) 1/2*x**(4/5) + x**(2/3) + x**(2/5) + 1 """ index = p.ring.gens.index(x) n = 1 for k in p: power = k[index] if isinstance(power, Rational): num, den = power.as_numer_denom() n = int(n*den // igcd(n, den)) elif power != int(power): den = power.denominator n = int(n*den // igcd(n, den)) if n != 1: p1 = pow_xin(p, index, n) r = f(p1, x, prec*n) n1 = QQ(1, n) if isinstance(r, tuple): r = tuple([pow_xin(rx, index, n1) for rx in r]) else: r = pow_xin(r, index, n1) else: r = f(p, x, prec) return r def rs_puiseux2(f, p, q, x, prec): """ Return the puiseux series for `f(p, q, x, prec)`. To be used when function ``f`` is implemented only for regular series. """ index = p.ring.gens.index(x) n = 1 for k in p: power = k[index] if isinstance(power, Rational): num, den = power.as_numer_denom() n = n*den // igcd(n, den) elif power != int(power): den = power.denominator n = n*den // igcd(n, den) if n != 1: p1 = pow_xin(p, index, n) r = f(p1, q, x, prec*n) n1 = QQ(1, n) r = pow_xin(r, index, n1) else: r = f(p, q, x, prec) return r def rs_mul(p1, p2, x, prec): """ Return the product of the given two series, modulo ``O(x**prec)``. ``x`` is the series variable or its position in the generators. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_mul >>> R, x = ring('x', QQ) >>> p1 = x**2 + 2*x + 1 >>> p2 = x + 1 >>> rs_mul(p1, p2, x, 3) 3*x**2 + 3*x + 1 """ R = p1.ring p = R.zero if R.__class__ != p2.ring.__class__ or R != p2.ring: raise ValueError('p1 and p2 must have the same ring') iv = R.gens.index(x) if not isinstance(p2, PolyElement): raise ValueError('p1 and p2 must have the same ring') if R == p2.ring: get = p.get items2 = list(p2.items()) items2.sort(key=lambda e: e[0][iv]) if R.ngens == 1: for exp1, v1 in p1.items(): for exp2, v2 in items2: exp = exp1[0] + exp2[0] if exp < prec: exp = (exp, ) p[exp] = get(exp, 0) + v1*v2 else: break else: monomial_mul = R.monomial_mul for exp1, v1 in p1.items(): for exp2, v2 in items2: if exp1[iv] + exp2[iv] < prec: exp = monomial_mul(exp1, exp2) p[exp] = get(exp, 0) + v1*v2 else: break p.strip_zero() return p def rs_square(p1, x, prec): """ Square the series modulo ``O(x**prec)`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_square >>> R, x = ring('x', QQ) >>> p = x**2 + 2*x + 1 >>> rs_square(p, x, 3) 6*x**2 + 4*x + 1 """ R = p1.ring p = R.zero iv = R.gens.index(x) get = p.get items = list(p1.items()) items.sort(key=lambda e: e[0][iv]) monomial_mul = R.monomial_mul for i in range(len(items)): exp1, v1 = items[i] for j in range(i): exp2, v2 = items[j] if exp1[iv] + exp2[iv] < prec: exp = monomial_mul(exp1, exp2) p[exp] = get(exp, 0) + v1*v2 else: break p = p.imul_num(2) get = p.get for expv, v in p1.items(): if 2*expv[iv] < prec: e2 = monomial_mul(expv, expv) p[e2] = get(e2, 0) + v**2 p.strip_zero() return p def rs_pow(p1, n, x, prec): """ Return ``p1**n`` modulo ``O(x**prec)`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_pow >>> R, x = ring('x', QQ) >>> p = x + 1 >>> rs_pow(p, 4, x, 3) 6*x**2 + 4*x + 1 """ R = p1.ring if isinstance(n, Rational): np = int(n.p) nq = int(n.q) if nq != 1: res = rs_nth_root(p1, nq, x, prec) if np != 1: res = rs_pow(res, np, x, prec) else: res = rs_pow(p1, np, x, prec) return res n = as_int(n) if n == 0: if p1: return R(1) else: raise ValueError('0**0 is undefined') if n < 0: p1 = rs_pow(p1, -n, x, prec) return rs_series_inversion(p1, x, prec) if n == 1: return rs_trunc(p1, x, prec) if n == 2: return rs_square(p1, x, prec) if n == 3: p2 = rs_square(p1, x, prec) return rs_mul(p1, p2, x, prec) p = R(1) while 1: if n & 1: p = rs_mul(p1, p, x, prec) n -= 1 if not n: break p1 = rs_square(p1, x, prec) n = n // 2 return p def rs_subs(p, rules, x, prec): """ Substitution with truncation according to the mapping in ``rules``. Return a series with precision ``prec`` in the generator ``x`` Note that substitutions are not done one after the other >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_subs >>> R, x, y = ring('x, y', QQ) >>> p = x**2 + y**2 >>> rs_subs(p, {x: x+ y, y: x+ 2*y}, x, 3) 2*x**2 + 6*x*y + 5*y**2 >>> (x + y)**2 + (x + 2*y)**2 2*x**2 + 6*x*y + 5*y**2 which differs from >>> rs_subs(rs_subs(p, {x: x+ y}, x, 3), {y: x+ 2*y}, x, 3) 5*x**2 + 12*x*y + 8*y**2 Parameters ---------- p : :class:`~.PolyElement` Input series. rules : ``dict`` with substitution mappings. x : :class:`~.PolyElement` in which the series truncation is to be done. prec : :class:`~.Integer` order of the series after truncation. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_subs >>> R, x, y = ring('x, y', QQ) >>> rs_subs(x**2+y**2, {y: (x+y)**2}, x, 3) 6*x**2*y**2 + x**2 + 4*x*y**3 + y**4 """ R = p.ring ngens = R.ngens d = R(0) for i in range(ngens): d[(i, 1)] = R.gens[i] for var in rules: d[(R.index(var), 1)] = rules[var] p1 = R(0) p_keys = sorted(p.keys()) for expv in p_keys: p2 = R(1) for i in range(ngens): power = expv[i] if power == 0: continue if (i, power) not in d: q, r = divmod(power, 2) if r == 0 and (i, q) in d: d[(i, power)] = rs_square(d[(i, q)], x, prec) elif (i, power - 1) in d: d[(i, power)] = rs_mul(d[(i, power - 1)], d[(i, 1)], x, prec) else: d[(i, power)] = rs_pow(d[(i, 1)], power, x, prec) p2 = rs_mul(p2, d[(i, power)], x, prec) p1 += p2*p[expv] return p1 def _has_constant_term(p, x): """ Check if ``p`` has a constant term in ``x`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import _has_constant_term >>> R, x = ring('x', QQ) >>> p = x**2 + x + 1 >>> _has_constant_term(p, x) True """ R = p.ring iv = R.gens.index(x) zm = R.zero_monom a = [0]*R.ngens a[iv] = 1 miv = tuple(a) for expv in p: if monomial_min(expv, miv) == zm: return True return False def _get_constant_term(p, x): """Return constant term in p with respect to x Note that it is not simply `p[R.zero_monom]` as there might be multiple generators in the ring R. We want the `x`-free term which can contain other generators. """ R = p.ring i = R.gens.index(x) zm = R.zero_monom a = [0]*R.ngens a[i] = 1 miv = tuple(a) c = 0 for expv in p: if monomial_min(expv, miv) == zm: c += R({expv: p[expv]}) return c def _check_series_var(p, x, name): index = p.ring.gens.index(x) m = min(p, key=lambda k: k[index])[index] if m < 0: raise PoleError("Asymptotic expansion of %s around [oo] not " "implemented." % name) return index, m def _series_inversion1(p, x, prec): """ Univariate series inversion ``1/p`` modulo ``O(x**prec)``. The Newton method is used. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import _series_inversion1 >>> R, x = ring('x', QQ) >>> p = x + 1 >>> _series_inversion1(p, x, 4) -x**3 + x**2 - x + 1 """ if rs_is_puiseux(p, x): return rs_puiseux(_series_inversion1, p, x, prec) R = p.ring zm = R.zero_monom c = p[zm] # giant_steps does not seem to work with PythonRational numbers with 1 as # denominator. This makes sure such a number is converted to integer. if prec == int(prec): prec = int(prec) if zm not in p: raise ValueError("No constant term in series") if _has_constant_term(p - c, x): raise ValueError("p cannot contain a constant term depending on " "parameters") one = R(1) if R.domain is EX: one = 1 if c != one: # TODO add check that it is a unit p1 = R(1)/c else: p1 = R(1) for precx in _giant_steps(prec): t = 1 - rs_mul(p1, p, x, precx) p1 = p1 + rs_mul(p1, t, x, precx) return p1 def rs_series_inversion(p, x, prec): """ Multivariate series inversion ``1/p`` modulo ``O(x**prec)``. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_series_inversion >>> R, x, y = ring('x, y', QQ) >>> rs_series_inversion(1 + x*y**2, x, 4) -x**3*y**6 + x**2*y**4 - x*y**2 + 1 >>> rs_series_inversion(1 + x*y**2, y, 4) -x*y**2 + 1 >>> rs_series_inversion(x + x**2, x, 4) x**3 - x**2 + x - 1 + x**(-1) """ R = p.ring if p == R.zero: raise ZeroDivisionError zm = R.zero_monom index = R.gens.index(x) m = min(p, key=lambda k: k[index])[index] if m: p = mul_xin(p, index, -m) prec = prec + m if zm not in p: raise NotImplementedError("No constant term in series") if _has_constant_term(p - p[zm], x): raise NotImplementedError("p - p[0] must not have a constant term in " "the series variables") r = _series_inversion1(p, x, prec) if m != 0: r = mul_xin(r, index, -m) return r def _coefficient_t(p, t): r"""Coefficient of `x_i**j` in p, where ``t`` = (i, j)""" i, j = t R = p.ring expv1 = [0]*R.ngens expv1[i] = j expv1 = tuple(expv1) p1 = R(0) for expv in p: if expv[i] == j: p1[monomial_div(expv, expv1)] = p[expv] return p1 def rs_series_reversion(p, x, n, y): r""" Reversion of a series. ``p`` is a series with ``O(x**n)`` of the form $p = ax + f(x)$ where $a$ is a number different from 0. $f(x) = \sum_{k=2}^{n-1} a_kx_k$ Parameters ========== a_k : Can depend polynomially on other variables, not indicated. x : Variable with name x. y : Variable with name y. Returns ======= Solve $p = y$, that is, given $ax + f(x) - y = 0$, find the solution $x = r(y)$ up to $O(y^n)$. Algorithm ========= If $r_i$ is the solution at order $i$, then: $ar_i + f(r_i) - y = O\left(y^{i + 1}\right)$ and if $r_{i + 1}$ is the solution at order $i + 1$, then: $ar_{i + 1} + f(r_{i + 1}) - y = O\left(y^{i + 2}\right)$ We have, $r_{i + 1} = r_i + e$, such that, $ae + f(r_i) = O\left(y^{i + 2}\right)$ or $e = -f(r_i)/a$ So we use the recursion relation: $r_{i + 1} = r_i - f(r_i)/a$ with the boundary condition: $r_1 = y$ Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_series_reversion, rs_trunc >>> R, x, y, a, b = ring('x, y, a, b', QQ) >>> p = x - x**2 - 2*b*x**2 + 2*a*b*x**2 >>> p1 = rs_series_reversion(p, x, 3, y); p1 -2*y**2*a*b + 2*y**2*b + y**2 + y >>> rs_trunc(p.compose(x, p1), y, 3) y """ if rs_is_puiseux(p, x): raise NotImplementedError R = p.ring nx = R.gens.index(x) y = R(y) ny = R.gens.index(y) if _has_constant_term(p, x): raise ValueError("p must not contain a constant term in the series " "variable") a = _coefficient_t(p, (nx, 1)) zm = R.zero_monom assert zm in a and len(a) == 1 a = a[zm] r = y/a for i in range(2, n): sp = rs_subs(p, {x: r}, y, i + 1) sp = _coefficient_t(sp, (ny, i))*y**i r -= sp/a return r def rs_series_from_list(p, c, x, prec, concur=1): """ Return a series `sum c[n]*p**n` modulo `O(x**prec)`. It reduces the number of multiplications by summing concurrently. `ax = [1, p, p**2, .., p**(J - 1)]` `s = sum(c[i]*ax[i]` for i in `range(r, (r + 1)*J))*p**((K - 1)*J)` with `K >= (n + 1)/J` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_series_from_list, rs_trunc >>> R, x = ring('x', QQ) >>> p = x**2 + x + 1 >>> c = [1, 2, 3] >>> rs_series_from_list(p, c, x, 4) 6*x**3 + 11*x**2 + 8*x + 6 >>> rs_trunc(1 + 2*p + 3*p**2, x, 4) 6*x**3 + 11*x**2 + 8*x + 6 >>> pc = R.from_list(list(reversed(c))) >>> rs_trunc(pc.compose(x, p), x, 4) 6*x**3 + 11*x**2 + 8*x + 6 """ # TODO: Add this when it is documented in Sphinx """ See Also ======== sympy.polys.rings.PolyRing.compose """ R = p.ring n = len(c) if not concur: q = R(1) s = c[0]*q for i in range(1, n): q = rs_mul(q, p, x, prec) s += c[i]*q return s J = int(math.sqrt(n) + 1) K, r = divmod(n, J) if r: K += 1 ax = [R(1)] q = R(1) if len(p) < 20: for i in range(1, J): q = rs_mul(q, p, x, prec) ax.append(q) else: for i in range(1, J): if i % 2 == 0: q = rs_square(ax[i//2], x, prec) else: q = rs_mul(q, p, x, prec) ax.append(q) # optimize using rs_square pj = rs_mul(ax[-1], p, x, prec) b = R(1) s = R(0) for k in range(K - 1): r = J*k s1 = c[r] for j in range(1, J): s1 += c[r + j]*ax[j] s1 = rs_mul(s1, b, x, prec) s += s1 b = rs_mul(b, pj, x, prec) if not b: break k = K - 1 r = J*k if r < n: s1 = c[r]*R(1) for j in range(1, J): if r + j >= n: break s1 += c[r + j]*ax[j] s1 = rs_mul(s1, b, x, prec) s += s1 return s def rs_diff(p, x): """ Return partial derivative of ``p`` with respect to ``x``. Parameters ========== x : :class:`~.PolyElement` with respect to which ``p`` is differentiated. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_diff >>> R, x, y = ring('x, y', QQ) >>> p = x + x**2*y**3 >>> rs_diff(p, x) 2*x*y**3 + 1 """ R = p.ring n = R.gens.index(x) p1 = R.zero mn = [0]*R.ngens mn[n] = 1 mn = tuple(mn) for expv in p: if expv[n]: e = monomial_ldiv(expv, mn) p1[e] = R.domain_new(p[expv]*expv[n]) return p1 def rs_integrate(p, x): """ Integrate ``p`` with respect to ``x``. Parameters ========== x : :class:`~.PolyElement` with respect to which ``p`` is integrated. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_integrate >>> R, x, y = ring('x, y', QQ) >>> p = x + x**2*y**3 >>> rs_integrate(p, x) 1/3*x**3*y**3 + 1/2*x**2 """ R = p.ring p1 = R.zero n = R.gens.index(x) mn = [0]*R.ngens mn[n] = 1 mn = tuple(mn) for expv in p: e = monomial_mul(expv, mn) p1[e] = R.domain_new(p[expv]/(expv[n] + 1)) return p1 def rs_fun(p, f, *args): r""" Function of a multivariate series computed by substitution. The case with f method name is used to compute `rs\_tan` and `rs\_nth\_root` of a multivariate series: `rs\_fun(p, tan, iv, prec)` tan series is first computed for a dummy variable _x, i.e, `rs\_tan(\_x, iv, prec)`. Then we substitute _x with p to get the desired series Parameters ========== p : :class:`~.PolyElement` The multivariate series to be expanded. f : `ring\_series` function to be applied on `p`. args[-2] : :class:`~.PolyElement` with respect to which, the series is to be expanded. args[-1] : Required order of the expanded series. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_fun, _tan1 >>> R, x, y = ring('x, y', QQ) >>> p = x + x*y + x**2*y + x**3*y**2 >>> rs_fun(p, _tan1, x, 4) 1/3*x**3*y**3 + 2*x**3*y**2 + x**3*y + 1/3*x**3 + x**2*y + x*y + x """ _R = p.ring R1, _x = ring('_x', _R.domain) h = int(args[-1]) args1 = args[:-2] + (_x, h) zm = _R.zero_monom # separate the constant term of the series # compute the univariate series f(_x, .., 'x', sum(nv)) if zm in p: x1 = _x + p[zm] p1 = p - p[zm] else: x1 = _x p1 = p if isinstance(f, str): q = getattr(x1, f)(*args1) else: q = f(x1, *args1) a = sorted(q.items()) c = [0]*h for x in a: c[x[0][0]] = x[1] p1 = rs_series_from_list(p1, c, args[-2], args[-1]) return p1 def mul_xin(p, i, n): r""" Return `p*x_i**n`. `x\_i` is the ith variable in ``p``. """ R = p.ring q = R(0) for k, v in p.items(): k1 = list(k) k1[i] += n q[tuple(k1)] = v return q def pow_xin(p, i, n): """ >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import pow_xin >>> R, x, y = ring('x, y', QQ) >>> p = x**QQ(2,5) + x + x**QQ(2,3) >>> index = p.ring.gens.index(x) >>> pow_xin(p, index, 15) x**15 + x**10 + x**6 """ R = p.ring q = R(0) for k, v in p.items(): k1 = list(k) k1[i] *= n q[tuple(k1)] = v return q def _nth_root1(p, n, x, prec): """ Univariate series expansion of the nth root of ``p``. The Newton method is used. """ if rs_is_puiseux(p, x): return rs_puiseux2(_nth_root1, p, n, x, prec) R = p.ring zm = R.zero_monom if zm not in p: raise NotImplementedError('No constant term in series') n = as_int(n) assert p[zm] == 1 p1 = R(1) if p == 1: return p if n == 0: return R(1) if n == 1: return p if n < 0: n = -n sign = 1 else: sign = 0 for precx in _giant_steps(prec): tmp = rs_pow(p1, n + 1, x, precx) tmp = rs_mul(tmp, p, x, precx) p1 += p1/n - tmp/n if sign: return p1 else: return _series_inversion1(p1, x, prec) def rs_nth_root(p, n, x, prec): """ Multivariate series expansion of the nth root of ``p``. Parameters ========== p : Expr The polynomial to computer the root of. n : integer The order of the root to be computed. x : :class:`~.PolyElement` prec : integer Order of the expanded series. Notes ===== The result of this function is dependent on the ring over which the polynomial has been defined. If the answer involves a root of a constant, make sure that the polynomial is over a real field. It can not yet handle roots of symbols. Examples ======== >>> from sympy.polys.domains import QQ, RR >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_nth_root >>> R, x, y = ring('x, y', QQ) >>> rs_nth_root(1 + x + x*y, -3, x, 3) 2/9*x**2*y**2 + 4/9*x**2*y + 2/9*x**2 - 1/3*x*y - 1/3*x + 1 >>> R, x, y = ring('x, y', RR) >>> rs_nth_root(3 + x + x*y, 3, x, 2) 0.160249952256379*x*y + 0.160249952256379*x + 1.44224957030741 """ if n == 0: if p == 0: raise ValueError('0**0 expression') else: return p.ring(1) if n == 1: return rs_trunc(p, x, prec) R = p.ring index = R.gens.index(x) m = min(p, key=lambda k: k[index])[index] p = mul_xin(p, index, -m) prec -= m if _has_constant_term(p - 1, x): zm = R.zero_monom c = p[zm] if R.domain is EX: c_expr = c.as_expr() const = c_expr**QQ(1, n) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() const = R(c_expr**(QQ(1, n))) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") else: try: # RealElement doesn't support const = R(c**Rational(1, n)) # exponentiation with mpq object except ValueError: # as exponent raise DomainError("The given series can't be expanded in " "this domain.") res = rs_nth_root(p/c, n, x, prec)*const else: res = _nth_root1(p, n, x, prec) if m: m = QQ(m, n) res = mul_xin(res, index, m) return res def rs_log(p, x, prec): """ The Logarithm of ``p`` modulo ``O(x**prec)``. Notes ===== Truncation of ``integral dx p**-1*d p/dx`` is used. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_log >>> R, x = ring('x', QQ) >>> rs_log(1 + x, x, 8) 1/7*x**7 - 1/6*x**6 + 1/5*x**5 - 1/4*x**4 + 1/3*x**3 - 1/2*x**2 + x >>> rs_log(x**QQ(3, 2) + 1, x, 5) 1/3*x**(9/2) - 1/2*x**3 + x**(3/2) """ if rs_is_puiseux(p, x): return rs_puiseux(rs_log, p, x, prec) R = p.ring if p == 1: return R.zero c = _get_constant_term(p, x) if c: const = 0 if c == 1: pass else: c_expr = c.as_expr() if R.domain is EX: const = log(c_expr) elif isinstance(c, PolyElement): try: const = R(log(c_expr)) except ValueError: R = R.add_gens([log(c_expr)]) p = p.set_ring(R) x = x.set_ring(R) c = c.set_ring(R) const = R(log(c_expr)) else: try: const = R(log(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") dlog = p.diff(x) dlog = rs_mul(dlog, _series_inversion1(p, x, prec), x, prec - 1) return rs_integrate(dlog, x) + const else: raise NotImplementedError def rs_LambertW(p, x, prec): """ Calculate the series expansion of the principal branch of the Lambert W function. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_LambertW >>> R, x, y = ring('x, y', QQ) >>> rs_LambertW(x + x*y, x, 3) -x**2*y**2 - 2*x**2*y - x**2 + x*y + x See Also ======== LambertW """ if rs_is_puiseux(p, x): return rs_puiseux(rs_LambertW, p, x, prec) R = p.ring p1 = R(0) if _has_constant_term(p, x): raise NotImplementedError("Polynomial must not have constant term in " "the series variables") if x in R.gens: for precx in _giant_steps(prec): e = rs_exp(p1, x, precx) p2 = rs_mul(e, p1, x, precx) - p p3 = rs_mul(e, p1 + 1, x, precx) p3 = rs_series_inversion(p3, x, precx) tmp = rs_mul(p2, p3, x, precx) p1 -= tmp return p1 else: raise NotImplementedError def _exp1(p, x, prec): r"""Helper function for `rs\_exp`. """ R = p.ring p1 = R(1) for precx in _giant_steps(prec): pt = p - rs_log(p1, x, precx) tmp = rs_mul(pt, p1, x, precx) p1 += tmp return p1 def rs_exp(p, x, prec): """ Exponentiation of a series modulo ``O(x**prec)`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_exp >>> R, x = ring('x', QQ) >>> rs_exp(x**2, x, 7) 1/6*x**6 + 1/2*x**4 + x**2 + 1 """ if rs_is_puiseux(p, x): return rs_puiseux(rs_exp, p, x, prec) R = p.ring c = _get_constant_term(p, x) if c: if R.domain is EX: c_expr = c.as_expr() const = exp(c_expr) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() const = R(exp(c_expr)) except ValueError: R = R.add_gens([exp(c_expr)]) p = p.set_ring(R) x = x.set_ring(R) c = c.set_ring(R) const = R(exp(c_expr)) else: try: const = R(exp(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") p1 = p - c # Makes use of sympy functions to evaluate the values of the cos/sin # of the constant term. return const*rs_exp(p1, x, prec) if len(p) > 20: return _exp1(p, x, prec) one = R(1) n = 1 c = [] for k in range(prec): c.append(one/n) k += 1 n *= k r = rs_series_from_list(p, c, x, prec) return r def _atan(p, iv, prec): """ Expansion using formula. Faster on very small and univariate series. """ R = p.ring mo = R(-1) c = [-mo] p2 = rs_square(p, iv, prec) for k in range(1, prec): c.append(mo**k/(2*k + 1)) s = rs_series_from_list(p2, c, iv, prec) s = rs_mul(s, p, iv, prec) return s def rs_atan(p, x, prec): """ The arctangent of a series Return the series expansion of the atan of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_atan >>> R, x, y = ring('x, y', QQ) >>> rs_atan(x + x*y, x, 4) -1/3*x**3*y**3 - x**3*y**2 - x**3*y - 1/3*x**3 + x*y + x See Also ======== atan """ if rs_is_puiseux(p, x): return rs_puiseux(rs_atan, p, x, prec) R = p.ring const = 0 if _has_constant_term(p, x): zm = R.zero_monom c = p[zm] if R.domain is EX: c_expr = c.as_expr() const = atan(c_expr) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() const = R(atan(c_expr)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") else: try: const = R(atan(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") # Instead of using a closed form formula, we differentiate atan(p) to get # `1/(1+p**2) * dp`, whose series expansion is much easier to calculate. # Finally we integrate to get back atan dp = p.diff(x) p1 = rs_square(p, x, prec) + R(1) p1 = rs_series_inversion(p1, x, prec - 1) p1 = rs_mul(dp, p1, x, prec - 1) return rs_integrate(p1, x) + const def rs_asin(p, x, prec): """ Arcsine of a series Return the series expansion of the asin of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_asin >>> R, x, y = ring('x, y', QQ) >>> rs_asin(x, x, 8) 5/112*x**7 + 3/40*x**5 + 1/6*x**3 + x See Also ======== asin """ if rs_is_puiseux(p, x): return rs_puiseux(rs_asin, p, x, prec) if _has_constant_term(p, x): raise NotImplementedError("Polynomial must not have constant term in " "series variables") R = p.ring if x in R.gens: # get a good value if len(p) > 20: dp = rs_diff(p, x) p1 = 1 - rs_square(p, x, prec - 1) p1 = rs_nth_root(p1, -2, x, prec - 1) p1 = rs_mul(dp, p1, x, prec - 1) return rs_integrate(p1, x) one = R(1) c = [0, one, 0] for k in range(3, prec, 2): c.append((k - 2)**2*c[-2]/(k*(k - 1))) c.append(0) return rs_series_from_list(p, c, x, prec) else: raise NotImplementedError def _tan1(p, x, prec): r""" Helper function of :func:`rs_tan`. Return the series expansion of tan of a univariate series using Newton's method. It takes advantage of the fact that series expansion of atan is easier than that of tan. Consider `f(x) = y - \arctan(x)` Let r be a root of f(x) found using Newton's method. Then `f(r) = 0` Or `y = \arctan(x)` where `x = \tan(y)` as required. """ R = p.ring p1 = R(0) for precx in _giant_steps(prec): tmp = p - rs_atan(p1, x, precx) tmp = rs_mul(tmp, 1 + rs_square(p1, x, precx), x, precx) p1 += tmp return p1 def rs_tan(p, x, prec): """ Tangent of a series. Return the series expansion of the tan of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_tan >>> R, x, y = ring('x, y', QQ) >>> rs_tan(x + x*y, x, 4) 1/3*x**3*y**3 + x**3*y**2 + x**3*y + 1/3*x**3 + x*y + x See Also ======== _tan1, tan """ if rs_is_puiseux(p, x): r = rs_puiseux(rs_tan, p, x, prec) return r R = p.ring const = 0 c = _get_constant_term(p, x) if c: if R.domain is EX: c_expr = c.as_expr() const = tan(c_expr) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() const = R(tan(c_expr)) except ValueError: R = R.add_gens([tan(c_expr, )]) p = p.set_ring(R) x = x.set_ring(R) c = c.set_ring(R) const = R(tan(c_expr)) else: try: const = R(tan(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") p1 = p - c # Makes use of sympy functions to evaluate the values of the cos/sin # of the constant term. t2 = rs_tan(p1, x, prec) t = rs_series_inversion(1 - const*t2, x, prec) return rs_mul(const + t2, t, x, prec) if R.ngens == 1: return _tan1(p, x, prec) else: return rs_fun(p, rs_tan, x, prec) def rs_cot(p, x, prec): """ Cotangent of a series Return the series expansion of the cot of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_cot >>> R, x, y = ring('x, y', QQ) >>> rs_cot(x, x, 6) -2/945*x**5 - 1/45*x**3 - 1/3*x + x**(-1) See Also ======== cot """ # It can not handle series like `p = x + x*y` where the coefficient of the # linear term in the series variable is symbolic. if rs_is_puiseux(p, x): r = rs_puiseux(rs_cot, p, x, prec) return r i, m = _check_series_var(p, x, 'cot') prec1 = prec + 2*m c, s = rs_cos_sin(p, x, prec1) s = mul_xin(s, i, -m) s = rs_series_inversion(s, x, prec1) res = rs_mul(c, s, x, prec1) res = mul_xin(res, i, -m) res = rs_trunc(res, x, prec) return res def rs_sin(p, x, prec): """ Sine of a series Return the series expansion of the sin of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_sin >>> R, x, y = ring('x, y', QQ) >>> rs_sin(x + x*y, x, 4) -1/6*x**3*y**3 - 1/2*x**3*y**2 - 1/2*x**3*y - 1/6*x**3 + x*y + x >>> rs_sin(x**QQ(3, 2) + x*y**QQ(7, 5), x, 4) -1/2*x**(7/2)*y**(14/5) - 1/6*x**3*y**(21/5) + x**(3/2) + x*y**(7/5) See Also ======== sin """ if rs_is_puiseux(p, x): return rs_puiseux(rs_sin, p, x, prec) R = x.ring if not p: return R(0) c = _get_constant_term(p, x) if c: if R.domain is EX: c_expr = c.as_expr() t1, t2 = sin(c_expr), cos(c_expr) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() t1, t2 = R(sin(c_expr)), R(cos(c_expr)) except ValueError: R = R.add_gens([sin(c_expr), cos(c_expr)]) p = p.set_ring(R) x = x.set_ring(R) c = c.set_ring(R) t1, t2 = R(sin(c_expr)), R(cos(c_expr)) else: try: t1, t2 = R(sin(c)), R(cos(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") p1 = p - c # Makes use of sympy cos, sin functions to evaluate the values of the # cos/sin of the constant term. return rs_sin(p1, x, prec)*t2 + rs_cos(p1, x, prec)*t1 # Series is calculated in terms of tan as its evaluation is fast. if len(p) > 20 and R.ngens == 1: t = rs_tan(p/2, x, prec) t2 = rs_square(t, x, prec) p1 = rs_series_inversion(1 + t2, x, prec) return rs_mul(p1, 2*t, x, prec) one = R(1) n = 1 c = [0] for k in range(2, prec + 2, 2): c.append(one/n) c.append(0) n *= -k*(k + 1) return rs_series_from_list(p, c, x, prec) def rs_cos(p, x, prec): """ Cosine of a series Return the series expansion of the cos of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_cos >>> R, x, y = ring('x, y', QQ) >>> rs_cos(x + x*y, x, 4) -1/2*x**2*y**2 - x**2*y - 1/2*x**2 + 1 >>> rs_cos(x + x*y, x, 4)/x**QQ(7, 5) -1/2*x**(3/5)*y**2 - x**(3/5)*y - 1/2*x**(3/5) + x**(-7/5) See Also ======== cos """ if rs_is_puiseux(p, x): return rs_puiseux(rs_cos, p, x, prec) R = p.ring c = _get_constant_term(p, x) if c: if R.domain is EX: c_expr = c.as_expr() _, _ = sin(c_expr), cos(c_expr) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() _, _ = R(sin(c_expr)), R(cos(c_expr)) except ValueError: R = R.add_gens([sin(c_expr), cos(c_expr)]) p = p.set_ring(R) x = x.set_ring(R) c = c.set_ring(R) else: try: _, _ = R(sin(c)), R(cos(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") p1 = p - c # Makes use of sympy cos, sin functions to evaluate the values of the # cos/sin of the constant term. p_cos = rs_cos(p1, x, prec) p_sin = rs_sin(p1, x, prec) R = R.compose(p_cos.ring).compose(p_sin.ring) p_cos.set_ring(R) p_sin.set_ring(R) t1, t2 = R(sin(c_expr)), R(cos(c_expr)) return p_cos*t2 - p_sin*t1 # Series is calculated in terms of tan as its evaluation is fast. if len(p) > 20 and R.ngens == 1: t = rs_tan(p/2, x, prec) t2 = rs_square(t, x, prec) p1 = rs_series_inversion(1+t2, x, prec) return rs_mul(p1, 1 - t2, x, prec) one = R(1) n = 1 c = [] for k in range(2, prec + 2, 2): c.append(one/n) c.append(0) n *= -k*(k - 1) return rs_series_from_list(p, c, x, prec) def rs_cos_sin(p, x, prec): r""" Return the tuple ``(rs_cos(p, x, prec)`, `rs_sin(p, x, prec))``. Is faster than calling rs_cos and rs_sin separately """ if rs_is_puiseux(p, x): return rs_puiseux(rs_cos_sin, p, x, prec) t = rs_tan(p/2, x, prec) t2 = rs_square(t, x, prec) p1 = rs_series_inversion(1 + t2, x, prec) return (rs_mul(p1, 1 - t2, x, prec), rs_mul(p1, 2*t, x, prec)) def _atanh(p, x, prec): """ Expansion using formula Faster for very small and univariate series """ R = p.ring one = R(1) c = [one] p2 = rs_square(p, x, prec) for k in range(1, prec): c.append(one/(2*k + 1)) s = rs_series_from_list(p2, c, x, prec) s = rs_mul(s, p, x, prec) return s def rs_atanh(p, x, prec): """ Hyperbolic arctangent of a series Return the series expansion of the atanh of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_atanh >>> R, x, y = ring('x, y', QQ) >>> rs_atanh(x + x*y, x, 4) 1/3*x**3*y**3 + x**3*y**2 + x**3*y + 1/3*x**3 + x*y + x See Also ======== atanh """ if rs_is_puiseux(p, x): return rs_puiseux(rs_atanh, p, x, prec) R = p.ring const = 0 if _has_constant_term(p, x): zm = R.zero_monom c = p[zm] if R.domain is EX: c_expr = c.as_expr() const = atanh(c_expr) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() const = R(atanh(c_expr)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") else: try: const = R(atanh(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") # Instead of using a closed form formula, we differentiate atanh(p) to get # `1/(1-p**2) * dp`, whose series expansion is much easier to calculate. # Finally we integrate to get back atanh dp = rs_diff(p, x) p1 = - rs_square(p, x, prec) + 1 p1 = rs_series_inversion(p1, x, prec - 1) p1 = rs_mul(dp, p1, x, prec - 1) return rs_integrate(p1, x) + const def rs_sinh(p, x, prec): """ Hyperbolic sine of a series Return the series expansion of the sinh of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_sinh >>> R, x, y = ring('x, y', QQ) >>> rs_sinh(x + x*y, x, 4) 1/6*x**3*y**3 + 1/2*x**3*y**2 + 1/2*x**3*y + 1/6*x**3 + x*y + x See Also ======== sinh """ if rs_is_puiseux(p, x): return rs_puiseux(rs_sinh, p, x, prec) t = rs_exp(p, x, prec) t1 = rs_series_inversion(t, x, prec) return (t - t1)/2 def rs_cosh(p, x, prec): """ Hyperbolic cosine of a series Return the series expansion of the cosh of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_cosh >>> R, x, y = ring('x, y', QQ) >>> rs_cosh(x + x*y, x, 4) 1/2*x**2*y**2 + x**2*y + 1/2*x**2 + 1 See Also ======== cosh """ if rs_is_puiseux(p, x): return rs_puiseux(rs_cosh, p, x, prec) t = rs_exp(p, x, prec) t1 = rs_series_inversion(t, x, prec) return (t + t1)/2 def _tanh(p, x, prec): r""" Helper function of :func:`rs_tanh` Return the series expansion of tanh of a univariate series using Newton's method. It takes advantage of the fact that series expansion of atanh is easier than that of tanh. See Also ======== _tanh """ R = p.ring p1 = R(0) for precx in _giant_steps(prec): tmp = p - rs_atanh(p1, x, precx) tmp = rs_mul(tmp, 1 - rs_square(p1, x, prec), x, precx) p1 += tmp return p1 def rs_tanh(p, x, prec): """ Hyperbolic tangent of a series Return the series expansion of the tanh of ``p``, about 0. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_tanh >>> R, x, y = ring('x, y', QQ) >>> rs_tanh(x + x*y, x, 4) -1/3*x**3*y**3 - x**3*y**2 - x**3*y - 1/3*x**3 + x*y + x See Also ======== tanh """ if rs_is_puiseux(p, x): return rs_puiseux(rs_tanh, p, x, prec) R = p.ring const = 0 if _has_constant_term(p, x): zm = R.zero_monom c = p[zm] if R.domain is EX: c_expr = c.as_expr() const = tanh(c_expr) elif isinstance(c, PolyElement): try: c_expr = c.as_expr() const = R(tanh(c_expr)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") else: try: const = R(tanh(c)) except ValueError: raise DomainError("The given series can't be expanded in " "this domain.") p1 = p - c t1 = rs_tanh(p1, x, prec) t = rs_series_inversion(1 + const*t1, x, prec) return rs_mul(const + t1, t, x, prec) if R.ngens == 1: return _tanh(p, x, prec) else: return rs_fun(p, _tanh, x, prec) def rs_newton(p, x, prec): """ Compute the truncated Newton sum of the polynomial ``p`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_newton >>> R, x = ring('x', QQ) >>> p = x**2 - 2 >>> rs_newton(p, x, 5) 8*x**4 + 4*x**2 + 2 """ deg = p.degree() p1 = _invert_monoms(p) p2 = rs_series_inversion(p1, x, prec) p3 = rs_mul(p1.diff(x), p2, x, prec) res = deg - p3*x return res def rs_hadamard_exp(p1, inverse=False): """ Return ``sum f_i/i!*x**i`` from ``sum f_i*x**i``, where ``x`` is the first variable. If ``invers=True`` return ``sum f_i*i!*x**i`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_hadamard_exp >>> R, x = ring('x', QQ) >>> p = 1 + x + x**2 + x**3 >>> rs_hadamard_exp(p) 1/6*x**3 + 1/2*x**2 + x + 1 """ R = p1.ring if R.domain != QQ: raise NotImplementedError p = R.zero if not inverse: for exp1, v1 in p1.items(): p[exp1] = v1/int(ifac(exp1[0])) else: for exp1, v1 in p1.items(): p[exp1] = v1*int(ifac(exp1[0])) return p def rs_compose_add(p1, p2): """ compute the composed sum ``prod(p2(x - beta) for beta root of p1)`` Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> from sympy.polys.ring_series import rs_compose_add >>> R, x = ring('x', QQ) >>> f = x**2 - 2 >>> g = x**2 - 3 >>> rs_compose_add(f, g) x**4 - 10*x**2 + 1 References ========== .. [1] A. Bostan, P. Flajolet, B. Salvy and E. Schost "Fast Computation with Two Algebraic Numbers", (2002) Research Report 4579, Institut National de Recherche en Informatique et en Automatique """ R = p1.ring x = R.gens[0] prec = p1.degree()*p2.degree() + 1 np1 = rs_newton(p1, x, prec) np1e = rs_hadamard_exp(np1) np2 = rs_newton(p2, x, prec) np2e = rs_hadamard_exp(np2) np3e = rs_mul(np1e, np2e, x, prec) np3 = rs_hadamard_exp(np3e, True) np3a = (np3[(0,)] - np3)/x q = rs_integrate(np3a, x) q = rs_exp(q, x, prec) q = _invert_monoms(q) q = q.primitive()[1] dp = p1.degree()*p2.degree() - q.degree() # `dp` is the multiplicity of the zeroes of the resultant; # these zeroes are missed in this computation so they are put here. # if p1 and p2 are monic irreducible polynomials, # there are zeroes in the resultant # if and only if p1 = p2 ; in fact in that case p1 and p2 have a # root in common, so gcd(p1, p2) != 1; being p1 and p2 irreducible # this means p1 = p2 if dp: q = q*x**dp return q _convert_func = { 'sin': 'rs_sin', 'cos': 'rs_cos', 'exp': 'rs_exp', 'tan': 'rs_tan', 'log': 'rs_log' } def rs_min_pow(expr, series_rs, a): """Find the minimum power of `a` in the series expansion of expr""" series = 0 n = 2 while series == 0: series = _rs_series(expr, series_rs, a, n) n *= 2 R = series.ring a = R(a) i = R.gens.index(a) return min(series, key=lambda t: t[i])[i] def _rs_series(expr, series_rs, a, prec): # TODO Use _parallel_dict_from_expr instead of sring as sring is # inefficient. For details, read the todo in sring. args = expr.args R = series_rs.ring # expr does not contain any function to be expanded if not any(arg.has(Function) for arg in args) and not expr.is_Function: return series_rs if not expr.has(a): return series_rs elif expr.is_Function: arg = args[0] if len(args) > 1: raise NotImplementedError R1, series = sring(arg, domain=QQ, expand=False, series=True) series_inner = _rs_series(arg, series, a, prec) # Why do we need to compose these three rings? # # We want to use a simple domain (like ``QQ`` or ``RR``) but they don't # support symbolic coefficients. We need a ring that for example lets # us have `sin(1)` and `cos(1)` as coefficients if we are expanding # `sin(x + 1)`. The ``EX`` domain allows all symbolic coefficients, but # that makes it very complex and hence slow. # # To solve this problem, we add only those symbolic elements as # generators to our ring, that we need. Here, series_inner might # involve terms like `sin(4)`, `exp(a)`, etc, which are not there in # R1 or R. Hence, we compose these three rings to create one that has # the generators of all three. R = R.compose(R1).compose(series_inner.ring) series_inner = series_inner.set_ring(R) series = eval(_convert_func[str(expr.func)])(series_inner, R(a), prec) return series elif expr.is_Mul: n = len(args) for arg in args: # XXX Looks redundant if not arg.is_Number: R1, _ = sring(arg, expand=False, series=True) R = R.compose(R1) min_pows = list(map(rs_min_pow, args, [R(arg) for arg in args], [a]*len(args))) sum_pows = sum(min_pows) series = R(1) for i in range(n): _series = _rs_series(args[i], R(args[i]), a, prec - sum_pows + min_pows[i]) R = R.compose(_series.ring) _series = _series.set_ring(R) series = series.set_ring(R) series *= _series series = rs_trunc(series, R(a), prec) return series elif expr.is_Add: n = len(args) series = R(0) for i in range(n): _series = _rs_series(args[i], R(args[i]), a, prec) R = R.compose(_series.ring) _series = _series.set_ring(R) series = series.set_ring(R) series += _series return series elif expr.is_Pow: R1, _ = sring(expr.base, domain=QQ, expand=False, series=True) R = R.compose(R1) series_inner = _rs_series(expr.base, R(expr.base), a, prec) return rs_pow(series_inner, expr.exp, series_inner.ring(a), prec) # The `is_constant` method is buggy hence we check it at the end. # See issue #9786 for details. elif isinstance(expr, Expr) and expr.is_constant(): return sring(expr, domain=QQ, expand=False, series=True)[1] else: raise NotImplementedError def rs_series(expr, a, prec): """Return the series expansion of an expression about 0. Parameters ========== expr : :class:`Expr` a : :class:`Symbol` with respect to which expr is to be expanded prec : order of the series expansion Currently supports multivariate Taylor series expansion. This is much faster that Sympy's series method as it uses sparse polynomial operations. It automatically creates the simplest ring required to represent the series expansion through repeated calls to sring. Examples ======== >>> from sympy.polys.ring_series import rs_series >>> from sympy.functions import sin, cos, exp, tan >>> from sympy.core import symbols >>> from sympy.polys.domains import QQ >>> a, b, c = symbols('a, b, c') >>> rs_series(sin(a) + exp(a), a, 5) 1/24*a**4 + 1/2*a**2 + 2*a + 1 >>> series = rs_series(tan(a + b)*cos(a + c), a, 2) >>> series.as_expr() -a*sin(c)*tan(b) + a*cos(c)*tan(b)**2 + a*cos(c) + cos(c)*tan(b) >>> series = rs_series(exp(a**QQ(1,3) + a**QQ(2, 5)), a, 1) >>> series.as_expr() a**(11/15) + a**(4/5)/2 + a**(2/5) + a**(2/3)/2 + a**(1/3) + 1 """ R, series = sring(expr, domain=QQ, expand=False, series=True) if a not in R.symbols: R = R.add_gens([a, ]) series = series.set_ring(R) series = _rs_series(expr, series, a, prec) R = series.ring gen = R(a) prec_got = series.degree(gen) + 1 if prec_got >= prec: return rs_trunc(series, gen, prec) else: # increase the requested number of terms to get the desired # number keep increasing (up to 9) until the received order # is different than the original order and then predict how # many additional terms are needed for more in range(1, 9): p1 = _rs_series(expr, series, a, prec=prec + more) gen = gen.set_ring(p1.ring) new_prec = p1.degree(gen) + 1 if new_prec != prec_got: prec_do = ceiling(prec + (prec - prec_got)*more/(new_prec - prec_got)) p1 = _rs_series(expr, series, a, prec=prec_do) while p1.degree(gen) + 1 < prec: p1 = _rs_series(expr, series, a, prec=prec_do) gen = gen.set_ring(p1.ring) prec_do *= 2 break else: break else: raise ValueError('Could not calculate %s terms for %s' % (str(prec), expr)) return rs_trunc(p1, gen, prec) sympy-sympy-1.9/sympy/polys/rings.py000066400000000000000000002066351412543434000177620ustar00rootroot00000000000000"""Sparse polynomial rings. """ from typing import Any, Dict from operator import add, mul, lt, le, gt, ge from functools import reduce from types import GeneratorType from sympy.core.compatibility import is_sequence from sympy.core.expr import Expr from sympy.core.numbers import igcd, oo from sympy.core.symbol import Symbol, symbols as _symbols from sympy.core.sympify import CantSympify, sympify from sympy.ntheory.multinomial import multinomial_coefficients from sympy.polys.compatibility import IPolys from sympy.polys.constructor import construct_domain from sympy.polys.densebasic import dmp_to_dict, dmp_from_dict from sympy.polys.domains.domainelement import DomainElement from sympy.polys.domains.polynomialring import PolynomialRing from sympy.polys.heuristicgcd import heugcd from sympy.polys.monomials import MonomialOps from sympy.polys.orderings import lex from sympy.polys.polyerrors import ( CoercionFailed, GeneratorsError, ExactQuotientFailed, MultivariatePolynomialError) from sympy.polys.polyoptions import (Domain as DomainOpt, Order as OrderOpt, build_options) from sympy.polys.polyutils import (expr_from_dict, _dict_reorder, _parallel_dict_from_expr) from sympy.printing.defaults import DefaultPrinting from sympy.utilities import public from sympy.utilities.magic import pollute @public def ring(symbols, domain, order=lex): """Construct a polynomial ring returning ``(ring, x_1, ..., x_n)``. Parameters ========== symbols : str Symbol/Expr or sequence of str, Symbol/Expr (non-empty) domain : :class:`~.Domain` or coercible order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex`` Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.orderings import lex >>> R, x, y, z = ring("x,y,z", ZZ, lex) >>> R Polynomial ring in x, y, z over ZZ with lex order >>> x + y + z x + y + z >>> type(_) """ _ring = PolyRing(symbols, domain, order) return (_ring,) + _ring.gens @public def xring(symbols, domain, order=lex): """Construct a polynomial ring returning ``(ring, (x_1, ..., x_n))``. Parameters ========== symbols : str Symbol/Expr or sequence of str, Symbol/Expr (non-empty) domain : :class:`~.Domain` or coercible order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex`` Examples ======== >>> from sympy.polys.rings import xring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.orderings import lex >>> R, (x, y, z) = xring("x,y,z", ZZ, lex) >>> R Polynomial ring in x, y, z over ZZ with lex order >>> x + y + z x + y + z >>> type(_) """ _ring = PolyRing(symbols, domain, order) return (_ring, _ring.gens) @public def vring(symbols, domain, order=lex): """Construct a polynomial ring and inject ``x_1, ..., x_n`` into the global namespace. Parameters ========== symbols : str Symbol/Expr or sequence of str, Symbol/Expr (non-empty) domain : :class:`~.Domain` or coercible order : :class:`~.MonomialOrder` or coercible, optional, defaults to ``lex`` Examples ======== >>> from sympy.polys.rings import vring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.orderings import lex >>> vring("x,y,z", ZZ, lex) Polynomial ring in x, y, z over ZZ with lex order >>> x + y + z # noqa: x + y + z >>> type(_) """ _ring = PolyRing(symbols, domain, order) pollute([ sym.name for sym in _ring.symbols ], _ring.gens) return _ring @public def sring(exprs, *symbols, **options): """Construct a ring deriving generators and domain from options and input expressions. Parameters ========== exprs : :class:`~.Expr` or sequence of :class:`~.Expr` (sympifiable) symbols : sequence of :class:`~.Symbol`/:class:`~.Expr` options : keyword arguments understood by :class:`~.Options` Examples ======== >>> from sympy.core import symbols >>> from sympy.polys.rings import sring >>> x, y, z = symbols("x,y,z") >>> R, f = sring(x + 2*y + 3*z) >>> R Polynomial ring in x, y, z over ZZ with lex order >>> f x + 2*y + 3*z >>> type(_) """ single = False if not is_sequence(exprs): exprs, single = [exprs], True exprs = list(map(sympify, exprs)) opt = build_options(symbols, options) # TODO: rewrite this so that it doesn't use expand() (see poly()). reps, opt = _parallel_dict_from_expr(exprs, opt) if opt.domain is None: coeffs = sum([ list(rep.values()) for rep in reps ], []) opt.domain, coeffs_dom = construct_domain(coeffs, opt=opt) coeff_map = dict(zip(coeffs, coeffs_dom)) reps = [{m: coeff_map[c] for m, c in rep.items()} for rep in reps] _ring = PolyRing(opt.gens, opt.domain, opt.order) polys = list(map(_ring.from_dict, reps)) if single: return (_ring, polys[0]) else: return (_ring, polys) def _parse_symbols(symbols): if isinstance(symbols, str): return _symbols(symbols, seq=True) if symbols else () elif isinstance(symbols, Expr): return (symbols,) elif is_sequence(symbols): if all(isinstance(s, str) for s in symbols): return _symbols(symbols) elif all(isinstance(s, Expr) for s in symbols): return symbols raise GeneratorsError("expected a string, Symbol or expression or a non-empty sequence of strings, Symbols or expressions") _ring_cache = {} # type: Dict[Any, Any] class PolyRing(DefaultPrinting, IPolys): """Multivariate distributed polynomial ring. """ def __new__(cls, symbols, domain, order=lex): symbols = tuple(_parse_symbols(symbols)) ngens = len(symbols) domain = DomainOpt.preprocess(domain) order = OrderOpt.preprocess(order) _hash_tuple = (cls.__name__, symbols, ngens, domain, order) obj = _ring_cache.get(_hash_tuple) if obj is None: if domain.is_Composite and set(symbols) & set(domain.symbols): raise GeneratorsError("polynomial ring and it's ground domain share generators") obj = object.__new__(cls) obj._hash_tuple = _hash_tuple obj._hash = hash(_hash_tuple) obj.dtype = type("PolyElement", (PolyElement,), {"ring": obj}) obj.symbols = symbols obj.ngens = ngens obj.domain = domain obj.order = order obj.zero_monom = (0,)*ngens obj.gens = obj._gens() obj._gens_set = set(obj.gens) obj._one = [(obj.zero_monom, domain.one)] if ngens: # These expect monomials in at least one variable codegen = MonomialOps(ngens) obj.monomial_mul = codegen.mul() obj.monomial_pow = codegen.pow() obj.monomial_mulpow = codegen.mulpow() obj.monomial_ldiv = codegen.ldiv() obj.monomial_div = codegen.div() obj.monomial_lcm = codegen.lcm() obj.monomial_gcd = codegen.gcd() else: monunit = lambda a, b: () obj.monomial_mul = monunit obj.monomial_pow = monunit obj.monomial_mulpow = lambda a, b, c: () obj.monomial_ldiv = monunit obj.monomial_div = monunit obj.monomial_lcm = monunit obj.monomial_gcd = monunit if order is lex: obj.leading_expv = lambda f: max(f) else: obj.leading_expv = lambda f: max(f, key=order) for symbol, generator in zip(obj.symbols, obj.gens): if isinstance(symbol, Symbol): name = symbol.name if not hasattr(obj, name): setattr(obj, name, generator) _ring_cache[_hash_tuple] = obj return obj def _gens(self): """Return a list of polynomial generators. """ one = self.domain.one _gens = [] for i in range(self.ngens): expv = self.monomial_basis(i) poly = self.zero poly[expv] = one _gens.append(poly) return tuple(_gens) def __getnewargs__(self): return (self.symbols, self.domain, self.order) def __getstate__(self): state = self.__dict__.copy() del state["leading_expv"] for key, value in state.items(): if key.startswith("monomial_"): del state[key] return state def __hash__(self): return self._hash def __eq__(self, other): return isinstance(other, PolyRing) and \ (self.symbols, self.domain, self.ngens, self.order) == \ (other.symbols, other.domain, other.ngens, other.order) def __ne__(self, other): return not self == other def clone(self, symbols=None, domain=None, order=None): return self.__class__(symbols or self.symbols, domain or self.domain, order or self.order) def monomial_basis(self, i): """Return the ith-basis element. """ basis = [0]*self.ngens basis[i] = 1 return tuple(basis) @property def zero(self): return self.dtype() @property def one(self): return self.dtype(self._one) def domain_new(self, element, orig_domain=None): return self.domain.convert(element, orig_domain) def ground_new(self, coeff): return self.term_new(self.zero_monom, coeff) def term_new(self, monom, coeff): coeff = self.domain_new(coeff) poly = self.zero if coeff: poly[monom] = coeff return poly def ring_new(self, element): if isinstance(element, PolyElement): if self == element.ring: return element elif isinstance(self.domain, PolynomialRing) and self.domain.ring == element.ring: return self.ground_new(element) else: raise NotImplementedError("conversion") elif isinstance(element, str): raise NotImplementedError("parsing") elif isinstance(element, dict): return self.from_dict(element) elif isinstance(element, list): try: return self.from_terms(element) except ValueError: return self.from_list(element) elif isinstance(element, Expr): return self.from_expr(element) else: return self.ground_new(element) __call__ = ring_new def from_dict(self, element, orig_domain=None): domain_new = self.domain_new poly = self.zero for monom, coeff in element.items(): coeff = domain_new(coeff, orig_domain) if coeff: poly[monom] = coeff return poly def from_terms(self, element, orig_domain=None): return self.from_dict(dict(element), orig_domain) def from_list(self, element): return self.from_dict(dmp_to_dict(element, self.ngens-1, self.domain)) def _rebuild_expr(self, expr, mapping): domain = self.domain def _rebuild(expr): generator = mapping.get(expr) if generator is not None: return generator elif expr.is_Add: return reduce(add, list(map(_rebuild, expr.args))) elif expr.is_Mul: return reduce(mul, list(map(_rebuild, expr.args))) else: # XXX: Use as_base_exp() to handle Pow(x, n) and also exp(n) # XXX: E can be a generator e.g. sring([exp(2)]) -> ZZ[E] base, exp = expr.as_base_exp() if exp.is_Integer and exp > 1: return _rebuild(base)**int(exp) else: return self.ground_new(domain.convert(expr)) return _rebuild(sympify(expr)) def from_expr(self, expr): mapping = dict(list(zip(self.symbols, self.gens))) try: poly = self._rebuild_expr(expr, mapping) except CoercionFailed: raise ValueError("expected an expression convertible to a polynomial in %s, got %s" % (self, expr)) else: return self.ring_new(poly) def index(self, gen): """Compute index of ``gen`` in ``self.gens``. """ if gen is None: if self.ngens: i = 0 else: i = -1 # indicate impossible choice elif isinstance(gen, int): i = gen if 0 <= i and i < self.ngens: pass elif -self.ngens <= i and i <= -1: i = -i - 1 else: raise ValueError("invalid generator index: %s" % gen) elif isinstance(gen, self.dtype): try: i = self.gens.index(gen) except ValueError: raise ValueError("invalid generator: %s" % gen) elif isinstance(gen, str): try: i = self.symbols.index(gen) except ValueError: raise ValueError("invalid generator: %s" % gen) else: raise ValueError("expected a polynomial generator, an integer, a string or None, got %s" % gen) return i def drop(self, *gens): """Remove specified generators from this ring. """ indices = set(map(self.index, gens)) symbols = [ s for i, s in enumerate(self.symbols) if i not in indices ] if not symbols: return self.domain else: return self.clone(symbols=symbols) def __getitem__(self, key): symbols = self.symbols[key] if not symbols: return self.domain else: return self.clone(symbols=symbols) def to_ground(self): # TODO: should AlgebraicField be a Composite domain? if self.domain.is_Composite or hasattr(self.domain, 'domain'): return self.clone(domain=self.domain.domain) else: raise ValueError("%s is not a composite domain" % self.domain) def to_domain(self): return PolynomialRing(self) def to_field(self): from sympy.polys.fields import FracField return FracField(self.symbols, self.domain, self.order) @property def is_univariate(self): return len(self.gens) == 1 @property def is_multivariate(self): return len(self.gens) > 1 def add(self, *objs): """ Add a sequence of polynomials or containers of polynomials. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> R, x = ring("x", ZZ) >>> R.add([ x**2 + 2*i + 3 for i in range(4) ]) 4*x**2 + 24 >>> _.factor_list() (4, [(x**2 + 6, 1)]) """ p = self.zero for obj in objs: if is_sequence(obj, include=GeneratorType): p += self.add(*obj) else: p += obj return p def mul(self, *objs): """ Multiply a sequence of polynomials or containers of polynomials. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> R, x = ring("x", ZZ) >>> R.mul([ x**2 + 2*i + 3 for i in range(4) ]) x**8 + 24*x**6 + 206*x**4 + 744*x**2 + 945 >>> _.factor_list() (1, [(x**2 + 3, 1), (x**2 + 5, 1), (x**2 + 7, 1), (x**2 + 9, 1)]) """ p = self.one for obj in objs: if is_sequence(obj, include=GeneratorType): p *= self.mul(*obj) else: p *= obj return p def drop_to_ground(self, *gens): r""" Remove specified generators from the ring and inject them into its domain. """ indices = set(map(self.index, gens)) symbols = [s for i, s in enumerate(self.symbols) if i not in indices] gens = [gen for i, gen in enumerate(self.gens) if i not in indices] if not symbols: return self else: return self.clone(symbols=symbols, domain=self.drop(*gens)) def compose(self, other): """Add the generators of ``other`` to ``self``""" if self != other: syms = set(self.symbols).union(set(other.symbols)) return self.clone(symbols=list(syms)) else: return self def add_gens(self, symbols): """Add the elements of ``symbols`` as generators to ``self``""" syms = set(self.symbols).union(set(symbols)) return self.clone(symbols=list(syms)) class PolyElement(DomainElement, DefaultPrinting, CantSympify, dict): """Element of multivariate distributed polynomial ring. """ def new(self, init): return self.__class__(init) def parent(self): return self.ring.to_domain() def __getnewargs__(self): return (self.ring, list(self.iterterms())) _hash = None def __hash__(self): # XXX: This computes a hash of a dictionary, but currently we don't # protect dictionary from being changed so any use site modifications # will make hashing go wrong. Use this feature with caution until we # figure out how to make a safe API without compromising speed of this # low-level class. _hash = self._hash if _hash is None: self._hash = _hash = hash((self.ring, frozenset(self.items()))) return _hash def copy(self): """Return a copy of polynomial self. Polynomials are mutable; if one is interested in preserving a polynomial, and one plans to use inplace operations, one can copy the polynomial. This method makes a shallow copy. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> R, x, y = ring('x, y', ZZ) >>> p = (x + y)**2 >>> p1 = p.copy() >>> p2 = p >>> p[R.zero_monom] = 3 >>> p x**2 + 2*x*y + y**2 + 3 >>> p1 x**2 + 2*x*y + y**2 >>> p2 x**2 + 2*x*y + y**2 + 3 """ return self.new(self) def set_ring(self, new_ring): if self.ring == new_ring: return self elif self.ring.symbols != new_ring.symbols: terms = list(zip(*_dict_reorder(self, self.ring.symbols, new_ring.symbols))) return new_ring.from_terms(terms, self.ring.domain) else: return new_ring.from_dict(self, self.ring.domain) def as_expr(self, *symbols): if symbols and len(symbols) != self.ring.ngens: raise ValueError("not enough symbols, expected %s got %s" % (self.ring.ngens, len(symbols))) else: symbols = self.ring.symbols return expr_from_dict(self.as_expr_dict(), *symbols) def as_expr_dict(self): to_sympy = self.ring.domain.to_sympy return {monom: to_sympy(coeff) for monom, coeff in self.iterterms()} def clear_denoms(self): domain = self.ring.domain if not domain.is_Field or not domain.has_assoc_Ring: return domain.one, self ground_ring = domain.get_ring() common = ground_ring.one lcm = ground_ring.lcm denom = domain.denom for coeff in self.values(): common = lcm(common, denom(coeff)) poly = self.new([ (k, v*common) for k, v in self.items() ]) return common, poly def strip_zero(self): """Eliminate monomials with zero coefficient. """ for k, v in list(self.items()): if not v: del self[k] def __eq__(p1, p2): """Equality test for polynomials. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> _, x, y = ring('x, y', ZZ) >>> p1 = (x + y)**2 + (x - y)**2 >>> p1 == 4*x*y False >>> p1 == 2*(x**2 + y**2) True """ if not p2: return not p1 elif isinstance(p2, PolyElement) and p2.ring == p1.ring: return dict.__eq__(p1, p2) elif len(p1) > 1: return False else: return p1.get(p1.ring.zero_monom) == p2 def __ne__(p1, p2): return not p1 == p2 def almosteq(p1, p2, tolerance=None): """Approximate equality test for polynomials. """ ring = p1.ring if isinstance(p2, ring.dtype): if set(p1.keys()) != set(p2.keys()): return False almosteq = ring.domain.almosteq for k in p1.keys(): if not almosteq(p1[k], p2[k], tolerance): return False return True elif len(p1) > 1: return False else: try: p2 = ring.domain.convert(p2) except CoercionFailed: return False else: return ring.domain.almosteq(p1.const(), p2, tolerance) def sort_key(self): return (len(self), self.terms()) def _cmp(p1, p2, op): if isinstance(p2, p1.ring.dtype): return op(p1.sort_key(), p2.sort_key()) else: return NotImplemented def __lt__(p1, p2): return p1._cmp(p2, lt) def __le__(p1, p2): return p1._cmp(p2, le) def __gt__(p1, p2): return p1._cmp(p2, gt) def __ge__(p1, p2): return p1._cmp(p2, ge) def _drop(self, gen): ring = self.ring i = ring.index(gen) if ring.ngens == 1: return i, ring.domain else: symbols = list(ring.symbols) del symbols[i] return i, ring.clone(symbols=symbols) def drop(self, gen): i, ring = self._drop(gen) if self.ring.ngens == 1: if self.is_ground: return self.coeff(1) else: raise ValueError("can't drop %s" % gen) else: poly = ring.zero for k, v in self.items(): if k[i] == 0: K = list(k) del K[i] poly[tuple(K)] = v else: raise ValueError("can't drop %s" % gen) return poly def _drop_to_ground(self, gen): ring = self.ring i = ring.index(gen) symbols = list(ring.symbols) del symbols[i] return i, ring.clone(symbols=symbols, domain=ring[i]) def drop_to_ground(self, gen): if self.ring.ngens == 1: raise ValueError("can't drop only generator to ground") i, ring = self._drop_to_ground(gen) poly = ring.zero gen = ring.domain.gens[0] for monom, coeff in self.iterterms(): mon = monom[:i] + monom[i+1:] if not mon in poly: poly[mon] = (gen**monom[i]).mul_ground(coeff) else: poly[mon] += (gen**monom[i]).mul_ground(coeff) return poly def to_dense(self): return dmp_from_dict(self, self.ring.ngens-1, self.ring.domain) def to_dict(self): return dict(self) def str(self, printer, precedence, exp_pattern, mul_symbol): if not self: return printer._print(self.ring.domain.zero) prec_mul = precedence["Mul"] prec_atom = precedence["Atom"] ring = self.ring symbols = ring.symbols ngens = ring.ngens zm = ring.zero_monom sexpvs = [] for expv, coeff in self.terms(): negative = ring.domain.is_negative(coeff) sign = " - " if negative else " + " sexpvs.append(sign) if expv == zm: scoeff = printer._print(coeff) if negative and scoeff.startswith("-"): scoeff = scoeff[1:] else: if negative: coeff = -coeff if coeff != self.ring.one: scoeff = printer.parenthesize(coeff, prec_mul, strict=True) else: scoeff = '' sexpv = [] for i in range(ngens): exp = expv[i] if not exp: continue symbol = printer.parenthesize(symbols[i], prec_atom, strict=True) if exp != 1: if exp != int(exp) or exp < 0: sexp = printer.parenthesize(exp, prec_atom, strict=False) else: sexp = exp sexpv.append(exp_pattern % (symbol, sexp)) else: sexpv.append('%s' % symbol) if scoeff: sexpv = [scoeff] + sexpv sexpvs.append(mul_symbol.join(sexpv)) if sexpvs[0] in [" + ", " - "]: head = sexpvs.pop(0) if head == " - ": sexpvs.insert(0, "-") return "".join(sexpvs) @property def is_generator(self): return self in self.ring._gens_set @property def is_ground(self): return not self or (len(self) == 1 and self.ring.zero_monom in self) @property def is_monomial(self): return not self or (len(self) == 1 and self.LC == 1) @property def is_term(self): return len(self) <= 1 @property def is_negative(self): return self.ring.domain.is_negative(self.LC) @property def is_positive(self): return self.ring.domain.is_positive(self.LC) @property def is_nonnegative(self): return self.ring.domain.is_nonnegative(self.LC) @property def is_nonpositive(self): return self.ring.domain.is_nonpositive(self.LC) @property def is_zero(f): return not f @property def is_one(f): return f == f.ring.one @property def is_monic(f): return f.ring.domain.is_one(f.LC) @property def is_primitive(f): return f.ring.domain.is_one(f.content()) @property def is_linear(f): return all(sum(monom) <= 1 for monom in f.itermonoms()) @property def is_quadratic(f): return all(sum(monom) <= 2 for monom in f.itermonoms()) @property def is_squarefree(f): if not f.ring.ngens: return True return f.ring.dmp_sqf_p(f) @property def is_irreducible(f): if not f.ring.ngens: return True return f.ring.dmp_irreducible_p(f) @property def is_cyclotomic(f): if f.ring.is_univariate: return f.ring.dup_cyclotomic_p(f) else: raise MultivariatePolynomialError("cyclotomic polynomial") def __neg__(self): return self.new([ (monom, -coeff) for monom, coeff in self.iterterms() ]) def __pos__(self): return self def __add__(p1, p2): """Add two polynomials. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> _, x, y = ring('x, y', ZZ) >>> (x + y)**2 + (x - y)**2 2*x**2 + 2*y**2 """ if not p2: return p1.copy() ring = p1.ring if isinstance(p2, ring.dtype): p = p1.copy() get = p.get zero = ring.domain.zero for k, v in p2.items(): v = get(k, zero) + v if v: p[k] = v else: del p[k] return p elif isinstance(p2, PolyElement): if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: pass elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: return p2.__radd__(p1) else: return NotImplemented try: cp2 = ring.domain_new(p2) except CoercionFailed: return NotImplemented else: p = p1.copy() if not cp2: return p zm = ring.zero_monom if zm not in p1.keys(): p[zm] = cp2 else: if p2 == -p[zm]: del p[zm] else: p[zm] += cp2 return p def __radd__(p1, n): p = p1.copy() if not n: return p ring = p1.ring try: n = ring.domain_new(n) except CoercionFailed: return NotImplemented else: zm = ring.zero_monom if zm not in p1.keys(): p[zm] = n else: if n == -p[zm]: del p[zm] else: p[zm] += n return p def __sub__(p1, p2): """Subtract polynomial p2 from p1. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> _, x, y = ring('x, y', ZZ) >>> p1 = x + y**2 >>> p2 = x*y + y**2 >>> p1 - p2 -x*y + x """ if not p2: return p1.copy() ring = p1.ring if isinstance(p2, ring.dtype): p = p1.copy() get = p.get zero = ring.domain.zero for k, v in p2.items(): v = get(k, zero) - v if v: p[k] = v else: del p[k] return p elif isinstance(p2, PolyElement): if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: pass elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: return p2.__rsub__(p1) else: return NotImplemented try: p2 = ring.domain_new(p2) except CoercionFailed: return NotImplemented else: p = p1.copy() zm = ring.zero_monom if zm not in p1.keys(): p[zm] = -p2 else: if p2 == p[zm]: del p[zm] else: p[zm] -= p2 return p def __rsub__(p1, n): """n - p1 with n convertible to the coefficient domain. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> _, x, y = ring('x, y', ZZ) >>> p = x + y >>> 4 - p -x - y + 4 """ ring = p1.ring try: n = ring.domain_new(n) except CoercionFailed: return NotImplemented else: p = ring.zero for expv in p1: p[expv] = -p1[expv] p += n return p def __mul__(p1, p2): """Multiply two polynomials. Examples ======== >>> from sympy.polys.domains import QQ >>> from sympy.polys.rings import ring >>> _, x, y = ring('x, y', QQ) >>> p1 = x + y >>> p2 = x - y >>> p1*p2 x**2 - y**2 """ ring = p1.ring p = ring.zero if not p1 or not p2: return p elif isinstance(p2, ring.dtype): get = p.get zero = ring.domain.zero monomial_mul = ring.monomial_mul p2it = list(p2.items()) for exp1, v1 in p1.items(): for exp2, v2 in p2it: exp = monomial_mul(exp1, exp2) p[exp] = get(exp, zero) + v1*v2 p.strip_zero() return p elif isinstance(p2, PolyElement): if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: pass elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: return p2.__rmul__(p1) else: return NotImplemented try: p2 = ring.domain_new(p2) except CoercionFailed: return NotImplemented else: for exp1, v1 in p1.items(): v = v1*p2 if v: p[exp1] = v return p def __rmul__(p1, p2): """p2 * p1 with p2 in the coefficient domain of p1. Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> _, x, y = ring('x, y', ZZ) >>> p = x + y >>> 4 * p 4*x + 4*y """ p = p1.ring.zero if not p2: return p try: p2 = p.ring.domain_new(p2) except CoercionFailed: return NotImplemented else: for exp1, v1 in p1.items(): v = p2*v1 if v: p[exp1] = v return p def __pow__(self, n): """raise polynomial to power `n` Examples ======== >>> from sympy.polys.domains import ZZ >>> from sympy.polys.rings import ring >>> _, x, y = ring('x, y', ZZ) >>> p = x + y**2 >>> p**3 x**3 + 3*x**2*y**2 + 3*x*y**4 + y**6 """ ring = self.ring if not n: if self: return ring.one else: raise ValueError("0**0") elif len(self) == 1: monom, coeff = list(self.items())[0] p = ring.zero if coeff == 1: p[ring.monomial_pow(monom, n)] = coeff else: p[ring.monomial_pow(monom, n)] = coeff**n return p # For ring series, we need negative and rational exponent support only # with monomials. n = int(n) if n < 0: raise ValueError("Negative exponent") elif n == 1: return self.copy() elif n == 2: return self.square() elif n == 3: return self*self.square() elif len(self) <= 5: # TODO: use an actual density measure return self._pow_multinomial(n) else: return self._pow_generic(n) def _pow_generic(self, n): p = self.ring.one c = self while True: if n & 1: p = p*c n -= 1 if not n: break c = c.square() n = n // 2 return p def _pow_multinomial(self, n): multinomials = multinomial_coefficients(len(self), n).items() monomial_mulpow = self.ring.monomial_mulpow zero_monom = self.ring.zero_monom terms = self.items() zero = self.ring.domain.zero poly = self.ring.zero for multinomial, multinomial_coeff in multinomials: product_monom = zero_monom product_coeff = multinomial_coeff for exp, (monom, coeff) in zip(multinomial, terms): if exp: product_monom = monomial_mulpow(product_monom, monom, exp) product_coeff *= coeff**exp monom = tuple(product_monom) coeff = product_coeff coeff = poly.get(monom, zero) + coeff if coeff: poly[monom] = coeff elif monom in poly: del poly[monom] return poly def square(self): """square of a polynomial Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y = ring('x, y', ZZ) >>> p = x + y**2 >>> p.square() x**2 + 2*x*y**2 + y**4 """ ring = self.ring p = ring.zero get = p.get keys = list(self.keys()) zero = ring.domain.zero monomial_mul = ring.monomial_mul for i in range(len(keys)): k1 = keys[i] pk = self[k1] for j in range(i): k2 = keys[j] exp = monomial_mul(k1, k2) p[exp] = get(exp, zero) + pk*self[k2] p = p.imul_num(2) get = p.get for k, v in self.items(): k2 = monomial_mul(k, k) p[k2] = get(k2, zero) + v**2 p.strip_zero() return p def __divmod__(p1, p2): ring = p1.ring if not p2: raise ZeroDivisionError("polynomial division") elif isinstance(p2, ring.dtype): return p1.div(p2) elif isinstance(p2, PolyElement): if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: pass elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: return p2.__rdivmod__(p1) else: return NotImplemented try: p2 = ring.domain_new(p2) except CoercionFailed: return NotImplemented else: return (p1.quo_ground(p2), p1.rem_ground(p2)) def __rdivmod__(p1, p2): return NotImplemented def __mod__(p1, p2): ring = p1.ring if not p2: raise ZeroDivisionError("polynomial division") elif isinstance(p2, ring.dtype): return p1.rem(p2) elif isinstance(p2, PolyElement): if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: pass elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: return p2.__rmod__(p1) else: return NotImplemented try: p2 = ring.domain_new(p2) except CoercionFailed: return NotImplemented else: return p1.rem_ground(p2) def __rmod__(p1, p2): return NotImplemented def __truediv__(p1, p2): ring = p1.ring if not p2: raise ZeroDivisionError("polynomial division") elif isinstance(p2, ring.dtype): if p2.is_monomial: return p1*(p2**(-1)) else: return p1.quo(p2) elif isinstance(p2, PolyElement): if isinstance(ring.domain, PolynomialRing) and ring.domain.ring == p2.ring: pass elif isinstance(p2.ring.domain, PolynomialRing) and p2.ring.domain.ring == ring: return p2.__rtruediv__(p1) else: return NotImplemented try: p2 = ring.domain_new(p2) except CoercionFailed: return NotImplemented else: return p1.quo_ground(p2) def __rtruediv__(p1, p2): return NotImplemented __floordiv__ = __truediv__ __rfloordiv__ = __rtruediv__ # TODO: use // (__floordiv__) for exquo()? def _term_div(self): zm = self.ring.zero_monom domain = self.ring.domain domain_quo = domain.quo monomial_div = self.ring.monomial_div if domain.is_Field: def term_div(a_lm_a_lc, b_lm_b_lc): a_lm, a_lc = a_lm_a_lc b_lm, b_lc = b_lm_b_lc if b_lm == zm: # apparently this is a very common case monom = a_lm else: monom = monomial_div(a_lm, b_lm) if monom is not None: return monom, domain_quo(a_lc, b_lc) else: return None else: def term_div(a_lm_a_lc, b_lm_b_lc): a_lm, a_lc = a_lm_a_lc b_lm, b_lc = b_lm_b_lc if b_lm == zm: # apparently this is a very common case monom = a_lm else: monom = monomial_div(a_lm, b_lm) if not (monom is None or a_lc % b_lc): return monom, domain_quo(a_lc, b_lc) else: return None return term_div def div(self, fv): """Division algorithm, see [CLO] p64. fv array of polynomials return qv, r such that self = sum(fv[i]*qv[i]) + r All polynomials are required not to be Laurent polynomials. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y = ring('x, y', ZZ) >>> f = x**3 >>> f0 = x - y**2 >>> f1 = x - y >>> qv, r = f.div((f0, f1)) >>> qv[0] x**2 + x*y**2 + y**4 >>> qv[1] 0 >>> r y**6 """ ring = self.ring ret_single = False if isinstance(fv, PolyElement): ret_single = True fv = [fv] if any(not f for f in fv): raise ZeroDivisionError("polynomial division") if not self: if ret_single: return ring.zero, ring.zero else: return [], ring.zero for f in fv: if f.ring != ring: raise ValueError('self and f must have the same ring') s = len(fv) qv = [ring.zero for i in range(s)] p = self.copy() r = ring.zero term_div = self._term_div() expvs = [fx.leading_expv() for fx in fv] while p: i = 0 divoccurred = 0 while i < s and divoccurred == 0: expv = p.leading_expv() term = term_div((expv, p[expv]), (expvs[i], fv[i][expvs[i]])) if term is not None: expv1, c = term qv[i] = qv[i]._iadd_monom((expv1, c)) p = p._iadd_poly_monom(fv[i], (expv1, -c)) divoccurred = 1 else: i += 1 if not divoccurred: expv = p.leading_expv() r = r._iadd_monom((expv, p[expv])) del p[expv] if expv == ring.zero_monom: r += p if ret_single: if not qv: return ring.zero, r else: return qv[0], r else: return qv, r def rem(self, G): f = self if isinstance(G, PolyElement): G = [G] if any(not g for g in G): raise ZeroDivisionError("polynomial division") ring = f.ring domain = ring.domain zero = domain.zero monomial_mul = ring.monomial_mul r = ring.zero term_div = f._term_div() ltf = f.LT f = f.copy() get = f.get while f: for g in G: tq = term_div(ltf, g.LT) if tq is not None: m, c = tq for mg, cg in g.iterterms(): m1 = monomial_mul(mg, m) c1 = get(m1, zero) - c*cg if not c1: del f[m1] else: f[m1] = c1 ltm = f.leading_expv() if ltm is not None: ltf = ltm, f[ltm] break else: ltm, ltc = ltf if ltm in r: r[ltm] += ltc else: r[ltm] = ltc del f[ltm] ltm = f.leading_expv() if ltm is not None: ltf = ltm, f[ltm] return r def quo(f, G): return f.div(G)[0] def exquo(f, G): q, r = f.div(G) if not r: return q else: raise ExactQuotientFailed(f, G) def _iadd_monom(self, mc): """add to self the monomial coeff*x0**i0*x1**i1*... unless self is a generator -- then just return the sum of the two. mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...) Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y = ring('x, y', ZZ) >>> p = x**4 + 2*y >>> m = (1, 2) >>> p1 = p._iadd_monom((m, 5)) >>> p1 x**4 + 5*x*y**2 + 2*y >>> p1 is p True >>> p = x >>> p1 = p._iadd_monom((m, 5)) >>> p1 5*x*y**2 + x >>> p1 is p False """ if self in self.ring._gens_set: cpself = self.copy() else: cpself = self expv, coeff = mc c = cpself.get(expv) if c is None: cpself[expv] = coeff else: c += coeff if c: cpself[expv] = c else: del cpself[expv] return cpself def _iadd_poly_monom(self, p2, mc): """add to self the product of (p)*(coeff*x0**i0*x1**i1*...) unless self is a generator -- then just return the sum of the two. mc is a tuple, (monom, coeff), where monomial is (i0, i1, ...) Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y, z = ring('x, y, z', ZZ) >>> p1 = x**4 + 2*y >>> p2 = y + z >>> m = (1, 2, 3) >>> p1 = p1._iadd_poly_monom(p2, (m, 3)) >>> p1 x**4 + 3*x*y**3*z**3 + 3*x*y**2*z**4 + 2*y """ p1 = self if p1 in p1.ring._gens_set: p1 = p1.copy() (m, c) = mc get = p1.get zero = p1.ring.domain.zero monomial_mul = p1.ring.monomial_mul for k, v in p2.items(): ka = monomial_mul(k, m) coeff = get(ka, zero) + v*c if coeff: p1[ka] = coeff else: del p1[ka] return p1 def degree(f, x=None): """ The leading degree in ``x`` or the main variable. Note that the degree of 0 is negative infinity (the SymPy object -oo). """ i = f.ring.index(x) if not f: return -oo elif i < 0: return 0 else: return max([ monom[i] for monom in f.itermonoms() ]) def degrees(f): """ A tuple containing leading degrees in all variables. Note that the degree of 0 is negative infinity (the SymPy object -oo) """ if not f: return (-oo,)*f.ring.ngens else: return tuple(map(max, list(zip(*f.itermonoms())))) def tail_degree(f, x=None): """ The tail degree in ``x`` or the main variable. Note that the degree of 0 is negative infinity (the SymPy object -oo) """ i = f.ring.index(x) if not f: return -oo elif i < 0: return 0 else: return min([ monom[i] for monom in f.itermonoms() ]) def tail_degrees(f): """ A tuple containing tail degrees in all variables. Note that the degree of 0 is negative infinity (the SymPy object -oo) """ if not f: return (-oo,)*f.ring.ngens else: return tuple(map(min, list(zip(*f.itermonoms())))) def leading_expv(self): """Leading monomial tuple according to the monomial ordering. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y, z = ring('x, y, z', ZZ) >>> p = x**4 + x**3*y + x**2*z**2 + z**7 >>> p.leading_expv() (4, 0, 0) """ if self: return self.ring.leading_expv(self) else: return None def _get_coeff(self, expv): return self.get(expv, self.ring.domain.zero) def coeff(self, element): """ Returns the coefficient that stands next to the given monomial. Parameters ========== element : PolyElement (with ``is_monomial = True``) or 1 Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y, z = ring("x,y,z", ZZ) >>> f = 3*x**2*y - x*y*z + 7*z**3 + 23 >>> f.coeff(x**2*y) 3 >>> f.coeff(x*y) 0 >>> f.coeff(1) 23 """ if element == 1: return self._get_coeff(self.ring.zero_monom) elif isinstance(element, self.ring.dtype): terms = list(element.iterterms()) if len(terms) == 1: monom, coeff = terms[0] if coeff == self.ring.domain.one: return self._get_coeff(monom) raise ValueError("expected a monomial, got %s" % element) def const(self): """Returns the constant coeffcient. """ return self._get_coeff(self.ring.zero_monom) @property def LC(self): return self._get_coeff(self.leading_expv()) @property def LM(self): expv = self.leading_expv() if expv is None: return self.ring.zero_monom else: return expv def leading_monom(self): """ Leading monomial as a polynomial element. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y = ring('x, y', ZZ) >>> (3*x*y + y**2).leading_monom() x*y """ p = self.ring.zero expv = self.leading_expv() if expv: p[expv] = self.ring.domain.one return p @property def LT(self): expv = self.leading_expv() if expv is None: return (self.ring.zero_monom, self.ring.domain.zero) else: return (expv, self._get_coeff(expv)) def leading_term(self): """Leading term as a polynomial element. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y = ring('x, y', ZZ) >>> (3*x*y + y**2).leading_term() 3*x*y """ p = self.ring.zero expv = self.leading_expv() if expv is not None: p[expv] = self[expv] return p def _sorted(self, seq, order): if order is None: order = self.ring.order else: order = OrderOpt.preprocess(order) if order is lex: return sorted(seq, key=lambda monom: monom[0], reverse=True) else: return sorted(seq, key=lambda monom: order(monom[0]), reverse=True) def coeffs(self, order=None): """Ordered list of polynomial coefficients. Parameters ========== order : :class:`~.MonomialOrder` or coercible, optional Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.orderings import lex, grlex >>> _, x, y = ring("x, y", ZZ, lex) >>> f = x*y**7 + 2*x**2*y**3 >>> f.coeffs() [2, 1] >>> f.coeffs(grlex) [1, 2] """ return [ coeff for _, coeff in self.terms(order) ] def monoms(self, order=None): """Ordered list of polynomial monomials. Parameters ========== order : :class:`~.MonomialOrder` or coercible, optional Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.orderings import lex, grlex >>> _, x, y = ring("x, y", ZZ, lex) >>> f = x*y**7 + 2*x**2*y**3 >>> f.monoms() [(2, 3), (1, 7)] >>> f.monoms(grlex) [(1, 7), (2, 3)] """ return [ monom for monom, _ in self.terms(order) ] def terms(self, order=None): """Ordered list of polynomial terms. Parameters ========== order : :class:`~.MonomialOrder` or coercible, optional Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> from sympy.polys.orderings import lex, grlex >>> _, x, y = ring("x, y", ZZ, lex) >>> f = x*y**7 + 2*x**2*y**3 >>> f.terms() [((2, 3), 2), ((1, 7), 1)] >>> f.terms(grlex) [((1, 7), 1), ((2, 3), 2)] """ return self._sorted(list(self.items()), order) def itercoeffs(self): """Iterator over coefficients of a polynomial. """ return iter(self.values()) def itermonoms(self): """Iterator over monomials of a polynomial. """ return iter(self.keys()) def iterterms(self): """Iterator over terms of a polynomial. """ return iter(self.items()) def listcoeffs(self): """Unordered list of polynomial coefficients. """ return list(self.values()) def listmonoms(self): """Unordered list of polynomial monomials. """ return list(self.keys()) def listterms(self): """Unordered list of polynomial terms. """ return list(self.items()) def imul_num(p, c): """multiply inplace the polynomial p by an element in the coefficient ring, provided p is not one of the generators; else multiply not inplace Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y = ring('x, y', ZZ) >>> p = x + y**2 >>> p1 = p.imul_num(3) >>> p1 3*x + 3*y**2 >>> p1 is p True >>> p = x >>> p1 = p.imul_num(3) >>> p1 3*x >>> p1 is p False """ if p in p.ring._gens_set: return p*c if not c: p.clear() return for exp in p: p[exp] *= c return p def content(f): """Returns GCD of polynomial's coefficients. """ domain = f.ring.domain cont = domain.zero gcd = domain.gcd for coeff in f.itercoeffs(): cont = gcd(cont, coeff) return cont def primitive(f): """Returns content and a primitive polynomial. """ cont = f.content() return cont, f.quo_ground(cont) def monic(f): """Divides all coefficients by the leading coefficient. """ if not f: return f else: return f.quo_ground(f.LC) def mul_ground(f, x): if not x: return f.ring.zero terms = [ (monom, coeff*x) for monom, coeff in f.iterterms() ] return f.new(terms) def mul_monom(f, monom): monomial_mul = f.ring.monomial_mul terms = [ (monomial_mul(f_monom, monom), f_coeff) for f_monom, f_coeff in f.items() ] return f.new(terms) def mul_term(f, term): monom, coeff = term if not f or not coeff: return f.ring.zero elif monom == f.ring.zero_monom: return f.mul_ground(coeff) monomial_mul = f.ring.monomial_mul terms = [ (monomial_mul(f_monom, monom), f_coeff*coeff) for f_monom, f_coeff in f.items() ] return f.new(terms) def quo_ground(f, x): domain = f.ring.domain if not x: raise ZeroDivisionError('polynomial division') if not f or x == domain.one: return f if domain.is_Field: quo = domain.quo terms = [ (monom, quo(coeff, x)) for monom, coeff in f.iterterms() ] else: terms = [ (monom, coeff // x) for monom, coeff in f.iterterms() if not (coeff % x) ] return f.new(terms) def quo_term(f, term): monom, coeff = term if not coeff: raise ZeroDivisionError("polynomial division") elif not f: return f.ring.zero elif monom == f.ring.zero_monom: return f.quo_ground(coeff) term_div = f._term_div() terms = [ term_div(t, term) for t in f.iterterms() ] return f.new([ t for t in terms if t is not None ]) def trunc_ground(f, p): if f.ring.domain.is_ZZ: terms = [] for monom, coeff in f.iterterms(): coeff = coeff % p if coeff > p // 2: coeff = coeff - p terms.append((monom, coeff)) else: terms = [ (monom, coeff % p) for monom, coeff in f.iterterms() ] poly = f.new(terms) poly.strip_zero() return poly rem_ground = trunc_ground def extract_ground(self, g): f = self fc = f.content() gc = g.content() gcd = f.ring.domain.gcd(fc, gc) f = f.quo_ground(gcd) g = g.quo_ground(gcd) return gcd, f, g def _norm(f, norm_func): if not f: return f.ring.domain.zero else: ground_abs = f.ring.domain.abs return norm_func([ ground_abs(coeff) for coeff in f.itercoeffs() ]) def max_norm(f): return f._norm(max) def l1_norm(f): return f._norm(sum) def deflate(f, *G): ring = f.ring polys = [f] + list(G) J = [0]*ring.ngens for p in polys: for monom in p.itermonoms(): for i, m in enumerate(monom): J[i] = igcd(J[i], m) for i, b in enumerate(J): if not b: J[i] = 1 J = tuple(J) if all(b == 1 for b in J): return J, polys H = [] for p in polys: h = ring.zero for I, coeff in p.iterterms(): N = [ i // j for i, j in zip(I, J) ] h[tuple(N)] = coeff H.append(h) return J, H def inflate(f, J): poly = f.ring.zero for I, coeff in f.iterterms(): N = [ i*j for i, j in zip(I, J) ] poly[tuple(N)] = coeff return poly def lcm(self, g): f = self domain = f.ring.domain if not domain.is_Field: fc, f = f.primitive() gc, g = g.primitive() c = domain.lcm(fc, gc) h = (f*g).quo(f.gcd(g)) if not domain.is_Field: return h.mul_ground(c) else: return h.monic() def gcd(f, g): return f.cofactors(g)[0] def cofactors(f, g): if not f and not g: zero = f.ring.zero return zero, zero, zero elif not f: h, cff, cfg = f._gcd_zero(g) return h, cff, cfg elif not g: h, cfg, cff = g._gcd_zero(f) return h, cff, cfg elif len(f) == 1: h, cff, cfg = f._gcd_monom(g) return h, cff, cfg elif len(g) == 1: h, cfg, cff = g._gcd_monom(f) return h, cff, cfg J, (f, g) = f.deflate(g) h, cff, cfg = f._gcd(g) return (h.inflate(J), cff.inflate(J), cfg.inflate(J)) def _gcd_zero(f, g): one, zero = f.ring.one, f.ring.zero if g.is_nonnegative: return g, zero, one else: return -g, zero, -one def _gcd_monom(f, g): ring = f.ring ground_gcd = ring.domain.gcd ground_quo = ring.domain.quo monomial_gcd = ring.monomial_gcd monomial_ldiv = ring.monomial_ldiv mf, cf = list(f.iterterms())[0] _mgcd, _cgcd = mf, cf for mg, cg in g.iterterms(): _mgcd = monomial_gcd(_mgcd, mg) _cgcd = ground_gcd(_cgcd, cg) h = f.new([(_mgcd, _cgcd)]) cff = f.new([(monomial_ldiv(mf, _mgcd), ground_quo(cf, _cgcd))]) cfg = f.new([(monomial_ldiv(mg, _mgcd), ground_quo(cg, _cgcd)) for mg, cg in g.iterterms()]) return h, cff, cfg def _gcd(f, g): ring = f.ring if ring.domain.is_QQ: return f._gcd_QQ(g) elif ring.domain.is_ZZ: return f._gcd_ZZ(g) else: # TODO: don't use dense representation (port PRS algorithms) return ring.dmp_inner_gcd(f, g) def _gcd_ZZ(f, g): return heugcd(f, g) def _gcd_QQ(self, g): f = self ring = f.ring new_ring = ring.clone(domain=ring.domain.get_ring()) cf, f = f.clear_denoms() cg, g = g.clear_denoms() f = f.set_ring(new_ring) g = g.set_ring(new_ring) h, cff, cfg = f._gcd_ZZ(g) h = h.set_ring(ring) c, h = h.LC, h.monic() cff = cff.set_ring(ring).mul_ground(ring.domain.quo(c, cf)) cfg = cfg.set_ring(ring).mul_ground(ring.domain.quo(c, cg)) return h, cff, cfg def cancel(self, g): """ Cancel common factors in a rational function ``f/g``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> (2*x**2 - 2).cancel(x**2 - 2*x + 1) (2*x + 2, x - 1) """ f = self ring = f.ring if not f: return f, ring.one domain = ring.domain if not (domain.is_Field and domain.has_assoc_Ring): _, p, q = f.cofactors(g) else: new_ring = ring.clone(domain=domain.get_ring()) cq, f = f.clear_denoms() cp, g = g.clear_denoms() f = f.set_ring(new_ring) g = g.set_ring(new_ring) _, p, q = f.cofactors(g) _, cp, cq = new_ring.domain.cofactors(cp, cq) p = p.set_ring(ring) q = q.set_ring(ring) p = p.mul_ground(cp) q = q.mul_ground(cq) # Make canonical with respect to sign or quadrant in the case of ZZ_I # or QQ_I. This ensures that the LC of the denominator is canonical by # multiplying top and bottom by a unit of the ring. u = q.canonical_unit() if u == domain.one: p, q = p, q elif u == -domain.one: p, q = -p, -q else: p = p.mul_ground(u) q = q.mul_ground(u) return p, q def canonical_unit(f): domain = f.ring.domain return domain.canonical_unit(f.LC) def diff(f, x): """Computes partial derivative in ``x``. Examples ======== >>> from sympy.polys.rings import ring >>> from sympy.polys.domains import ZZ >>> _, x, y = ring("x,y", ZZ) >>> p = x + x**2*y**3 >>> p.diff(x) 2*x*y**3 + 1 """ ring = f.ring i = ring.index(x) m = ring.monomial_basis(i) g = ring.zero for expv, coeff in f.iterterms(): if expv[i]: e = ring.monomial_ldiv(expv, m) g[e] = ring.domain_new(coeff*expv[i]) return g def __call__(f, *values): if 0 < len(values) <= f.ring.ngens: return f.evaluate(list(zip(f.ring.gens, values))) else: raise ValueError("expected at least 1 and at most %s values, got %s" % (f.ring.ngens, len(values))) def evaluate(self, x, a=None): f = self if isinstance(x, list) and a is None: (X, a), x = x[0], x[1:] f = f.evaluate(X, a) if not x: return f else: x = [ (Y.drop(X), a) for (Y, a) in x ] return f.evaluate(x) ring = f.ring i = ring.index(x) a = ring.domain.convert(a) if ring.ngens == 1: result = ring.domain.zero for (n,), coeff in f.iterterms(): result += coeff*a**n return result else: poly = ring.drop(x).zero for monom, coeff in f.iterterms(): n, monom = monom[i], monom[:i] + monom[i+1:] coeff = coeff*a**n if monom in poly: coeff = coeff + poly[monom] if coeff: poly[monom] = coeff else: del poly[monom] else: if coeff: poly[monom] = coeff return poly def subs(self, x, a=None): f = self if isinstance(x, list) and a is None: for X, a in x: f = f.subs(X, a) return f ring = f.ring i = ring.index(x) a = ring.domain.convert(a) if ring.ngens == 1: result = ring.domain.zero for (n,), coeff in f.iterterms(): result += coeff*a**n return ring.ground_new(result) else: poly = ring.zero for monom, coeff in f.iterterms(): n, monom = monom[i], monom[:i] + (0,) + monom[i+1:] coeff = coeff*a**n if monom in poly: coeff = coeff + poly[monom] if coeff: poly[monom] = coeff else: del poly[monom] else: if coeff: poly[monom] = coeff return poly def compose(f, x, a=None): ring = f.ring poly = ring.zero gens_map = dict(list(zip(ring.gens, list(range(ring.ngens))))) if a is not None: replacements = [(x, a)] else: if isinstance(x, list): replacements = list(x) elif isinstance(x, dict): replacements = sorted(list(x.items()), key=lambda k: gens_map[k[0]]) else: raise ValueError("expected a generator, value pair a sequence of such pairs") for k, (x, g) in enumerate(replacements): replacements[k] = (gens_map[x], ring.ring_new(g)) for monom, coeff in f.iterterms(): monom = list(monom) subpoly = ring.one for i, g in replacements: n, monom[i] = monom[i], 0 if n: subpoly *= g**n subpoly = subpoly.mul_term((tuple(monom), coeff)) poly += subpoly return poly # TODO: following methods should point to polynomial # representation independent algorithm implementations. def pdiv(f, g): return f.ring.dmp_pdiv(f, g) def prem(f, g): return f.ring.dmp_prem(f, g) def pquo(f, g): return f.ring.dmp_quo(f, g) def pexquo(f, g): return f.ring.dmp_exquo(f, g) def half_gcdex(f, g): return f.ring.dmp_half_gcdex(f, g) def gcdex(f, g): return f.ring.dmp_gcdex(f, g) def subresultants(f, g): return f.ring.dmp_subresultants(f, g) def resultant(f, g): return f.ring.dmp_resultant(f, g) def discriminant(f): return f.ring.dmp_discriminant(f) def decompose(f): if f.ring.is_univariate: return f.ring.dup_decompose(f) else: raise MultivariatePolynomialError("polynomial decomposition") def shift(f, a): if f.ring.is_univariate: return f.ring.dup_shift(f, a) else: raise MultivariatePolynomialError("polynomial shift") def sturm(f): if f.ring.is_univariate: return f.ring.dup_sturm(f) else: raise MultivariatePolynomialError("sturm sequence") def gff_list(f): return f.ring.dmp_gff_list(f) def sqf_norm(f): return f.ring.dmp_sqf_norm(f) def sqf_part(f): return f.ring.dmp_sqf_part(f) def sqf_list(f, all=False): return f.ring.dmp_sqf_list(f, all=all) def factor_list(f): return f.ring.dmp_factor_list(f) sympy-sympy-1.9/sympy/polys/rootisolation.py000066400000000000000000001663521412543434000215460ustar00rootroot00000000000000"""Real and complex root isolation and refinement algorithms. """ from sympy.polys.densearith import ( dup_neg, dup_rshift, dup_rem) from sympy.polys.densebasic import ( dup_LC, dup_TC, dup_degree, dup_strip, dup_reverse, dup_convert, dup_terms_gcd) from sympy.polys.densetools import ( dup_clear_denoms, dup_mirror, dup_scale, dup_shift, dup_transform, dup_diff, dup_eval, dmp_eval_in, dup_sign_variations, dup_real_imag) from sympy.polys.factortools import ( dup_factor_list) from sympy.polys.polyerrors import ( RefinementFailed, DomainError) from sympy.polys.sqfreetools import ( dup_sqf_part, dup_sqf_list) def dup_sturm(f, K): """ Computes the Sturm sequence of ``f`` in ``F[x]``. Given a univariate, square-free polynomial ``f(x)`` returns the associated Sturm sequence ``f_0(x), ..., f_n(x)`` defined by:: f_0(x), f_1(x) = f(x), f'(x) f_n = -rem(f_{n-2}(x), f_{n-1}(x)) Examples ======== >>> from sympy.polys import ring, QQ >>> R, x = ring("x", QQ) >>> R.dup_sturm(x**3 - 2*x**2 + x - 3) [x**3 - 2*x**2 + x - 3, 3*x**2 - 4*x + 1, 2/9*x + 25/9, -2079/4] References ========== .. [1] [Davenport88]_ """ if not K.is_Field: raise DomainError("can't compute Sturm sequence over %s" % K) f = dup_sqf_part(f, K) sturm = [f, dup_diff(f, 1, K)] while sturm[-1]: s = dup_rem(sturm[-2], sturm[-1], K) sturm.append(dup_neg(s, K)) return sturm[:-1] def dup_root_upper_bound(f, K): """Compute the LMQ upper bound for the positive roots of `f`; LMQ (Local Max Quadratic) was developed by Akritas-Strzebonski-Vigklas. References ========== .. [1] Alkiviadis G. Akritas: "Linear and Quadratic Complexity Bounds on the Values of the Positive Roots of Polynomials" Journal of Universal Computer Science, Vol. 15, No. 3, 523-537, 2009. """ n, P = len(f), [] t = n * [K.one] if dup_LC(f, K) < 0: f = dup_neg(f, K) f = list(reversed(f)) for i in range(0, n): if f[i] >= 0: continue a, QL = K.log(-f[i], 2), [] for j in range(i + 1, n): if f[j] <= 0: continue q = t[j] + a - K.log(f[j], 2) QL.append([q // (j - i) , j]) if not QL: continue q = min(QL) t[q[1]] = t[q[1]] + 1 P.append(q[0]) if not P: return None else: return K.get_field()(2)**(max(P) + 1) def dup_root_lower_bound(f, K): """Compute the LMQ lower bound for the positive roots of `f`; LMQ (Local Max Quadratic) was developed by Akritas-Strzebonski-Vigklas. References ========== .. [1] Alkiviadis G. Akritas: "Linear and Quadratic Complexity Bounds on the Values of the Positive Roots of Polynomials" Journal of Universal Computer Science, Vol. 15, No. 3, 523-537, 2009. """ bound = dup_root_upper_bound(dup_reverse(f), K) if bound is not None: return 1/bound else: return None def _mobius_from_interval(I, field): """Convert an open interval to a Mobius transform. """ s, t = I a, c = field.numer(s), field.denom(s) b, d = field.numer(t), field.denom(t) return a, b, c, d def _mobius_to_interval(M, field): """Convert a Mobius transform to an open interval. """ a, b, c, d = M s, t = field(a, c), field(b, d) if s <= t: return (s, t) else: return (t, s) def dup_step_refine_real_root(f, M, K, fast=False): """One step of positive real root refinement algorithm. """ a, b, c, d = M if a == b and c == d: return f, (a, b, c, d) A = dup_root_lower_bound(f, K) if A is not None: A = K(int(A)) else: A = K.zero if fast and A > 16: f = dup_scale(f, A, K) a, c, A = A*a, A*c, K.one if A >= K.one: f = dup_shift(f, A, K) b, d = A*a + b, A*c + d if not dup_eval(f, K.zero, K): return f, (b, b, d, d) f, g = dup_shift(f, K.one, K), f a1, b1, c1, d1 = a, a + b, c, c + d if not dup_eval(f, K.zero, K): return f, (b1, b1, d1, d1) k = dup_sign_variations(f, K) if k == 1: a, b, c, d = a1, b1, c1, d1 else: f = dup_shift(dup_reverse(g), K.one, K) if not dup_eval(f, K.zero, K): f = dup_rshift(f, 1, K) a, b, c, d = b, a + b, d, c + d return f, (a, b, c, d) def dup_inner_refine_real_root(f, M, K, eps=None, steps=None, disjoint=None, fast=False, mobius=False): """Refine a positive root of `f` given a Mobius transform or an interval. """ F = K.get_field() if len(M) == 2: a, b, c, d = _mobius_from_interval(M, F) else: a, b, c, d = M while not c: f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) if eps is not None and steps is not None: for i in range(0, steps): if abs(F(a, c) - F(b, d)) >= eps: f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) else: break else: if eps is not None: while abs(F(a, c) - F(b, d)) >= eps: f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) if steps is not None: for i in range(0, steps): f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) if disjoint is not None: while True: u, v = _mobius_to_interval((a, b, c, d), F) if v <= disjoint or disjoint <= u: break else: f, (a, b, c, d) = dup_step_refine_real_root(f, (a, b, c, d), K, fast=fast) if not mobius: return _mobius_to_interval((a, b, c, d), F) else: return f, (a, b, c, d) def dup_outer_refine_real_root(f, s, t, K, eps=None, steps=None, disjoint=None, fast=False): """Refine a positive root of `f` given an interval `(s, t)`. """ a, b, c, d = _mobius_from_interval((s, t), K.get_field()) f = dup_transform(f, dup_strip([a, b]), dup_strip([c, d]), K) if dup_sign_variations(f, K) != 1: raise RefinementFailed("there should be exactly one root in (%s, %s) interval" % (s, t)) return dup_inner_refine_real_root(f, (a, b, c, d), K, eps=eps, steps=steps, disjoint=disjoint, fast=fast) def dup_refine_real_root(f, s, t, K, eps=None, steps=None, disjoint=None, fast=False): """Refine real root's approximating interval to the given precision. """ if K.is_QQ: (_, f), K = dup_clear_denoms(f, K, convert=True), K.get_ring() elif not K.is_ZZ: raise DomainError("real root refinement not supported over %s" % K) if s == t: return (s, t) if s > t: s, t = t, s negative = False if s < 0: if t <= 0: f, s, t, negative = dup_mirror(f, K), -t, -s, True else: raise ValueError("can't refine a real root in (%s, %s)" % (s, t)) if negative and disjoint is not None: if disjoint < 0: disjoint = -disjoint else: disjoint = None s, t = dup_outer_refine_real_root( f, s, t, K, eps=eps, steps=steps, disjoint=disjoint, fast=fast) if negative: return (-t, -s) else: return ( s, t) def dup_inner_isolate_real_roots(f, K, eps=None, fast=False): """Internal function for isolation positive roots up to given precision. References ========== 1. Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative Study of Two Real Root Isolation Methods . Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. 2. Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. Vigklas: Improving the Performance of the Continued Fractions Method Using new Bounds of Positive Roots. Nonlinear Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. """ a, b, c, d = K.one, K.zero, K.zero, K.one k = dup_sign_variations(f, K) if k == 0: return [] if k == 1: roots = [dup_inner_refine_real_root( f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)] else: roots, stack = [], [(a, b, c, d, f, k)] while stack: a, b, c, d, f, k = stack.pop() A = dup_root_lower_bound(f, K) if A is not None: A = K(int(A)) else: A = K.zero if fast and A > 16: f = dup_scale(f, A, K) a, c, A = A*a, A*c, K.one if A >= K.one: f = dup_shift(f, A, K) b, d = A*a + b, A*c + d if not dup_TC(f, K): roots.append((f, (b, b, d, d))) f = dup_rshift(f, 1, K) k = dup_sign_variations(f, K) if k == 0: continue if k == 1: roots.append(dup_inner_refine_real_root( f, (a, b, c, d), K, eps=eps, fast=fast, mobius=True)) continue f1 = dup_shift(f, K.one, K) a1, b1, c1, d1, r = a, a + b, c, c + d, 0 if not dup_TC(f1, K): roots.append((f1, (b1, b1, d1, d1))) f1, r = dup_rshift(f1, 1, K), 1 k1 = dup_sign_variations(f1, K) k2 = k - k1 - r a2, b2, c2, d2 = b, a + b, d, c + d if k2 > 1: f2 = dup_shift(dup_reverse(f), K.one, K) if not dup_TC(f2, K): f2 = dup_rshift(f2, 1, K) k2 = dup_sign_variations(f2, K) else: f2 = None if k1 < k2: a1, a2, b1, b2 = a2, a1, b2, b1 c1, c2, d1, d2 = c2, c1, d2, d1 f1, f2, k1, k2 = f2, f1, k2, k1 if not k1: continue if f1 is None: f1 = dup_shift(dup_reverse(f), K.one, K) if not dup_TC(f1, K): f1 = dup_rshift(f1, 1, K) if k1 == 1: roots.append(dup_inner_refine_real_root( f1, (a1, b1, c1, d1), K, eps=eps, fast=fast, mobius=True)) else: stack.append((a1, b1, c1, d1, f1, k1)) if not k2: continue if f2 is None: f2 = dup_shift(dup_reverse(f), K.one, K) if not dup_TC(f2, K): f2 = dup_rshift(f2, 1, K) if k2 == 1: roots.append(dup_inner_refine_real_root( f2, (a2, b2, c2, d2), K, eps=eps, fast=fast, mobius=True)) else: stack.append((a2, b2, c2, d2, f2, k2)) return roots def _discard_if_outside_interval(f, M, inf, sup, K, negative, fast, mobius): """Discard an isolating interval if outside ``(inf, sup)``. """ F = K.get_field() while True: u, v = _mobius_to_interval(M, F) if negative: u, v = -v, -u if (inf is None or u >= inf) and (sup is None or v <= sup): if not mobius: return u, v else: return f, M elif (sup is not None and u > sup) or (inf is not None and v < inf): return None else: f, M = dup_step_refine_real_root(f, M, K, fast=fast) def dup_inner_isolate_positive_roots(f, K, eps=None, inf=None, sup=None, fast=False, mobius=False): """Iteratively compute disjoint positive root isolation intervals. """ if sup is not None and sup < 0: return [] roots = dup_inner_isolate_real_roots(f, K, eps=eps, fast=fast) F, results = K.get_field(), [] if inf is not None or sup is not None: for f, M in roots: result = _discard_if_outside_interval(f, M, inf, sup, K, False, fast, mobius) if result is not None: results.append(result) elif not mobius: for f, M in roots: u, v = _mobius_to_interval(M, F) results.append((u, v)) else: results = roots return results def dup_inner_isolate_negative_roots(f, K, inf=None, sup=None, eps=None, fast=False, mobius=False): """Iteratively compute disjoint negative root isolation intervals. """ if inf is not None and inf >= 0: return [] roots = dup_inner_isolate_real_roots(dup_mirror(f, K), K, eps=eps, fast=fast) F, results = K.get_field(), [] if inf is not None or sup is not None: for f, M in roots: result = _discard_if_outside_interval(f, M, inf, sup, K, True, fast, mobius) if result is not None: results.append(result) elif not mobius: for f, M in roots: u, v = _mobius_to_interval(M, F) results.append((-v, -u)) else: results = roots return results def _isolate_zero(f, K, inf, sup, basis=False, sqf=False): """Handle special case of CF algorithm when ``f`` is homogeneous. """ j, f = dup_terms_gcd(f, K) if j > 0: F = K.get_field() if (inf is None or inf <= 0) and (sup is None or 0 <= sup): if not sqf: if not basis: return [((F.zero, F.zero), j)], f else: return [((F.zero, F.zero), j, [K.one, K.zero])], f else: return [(F.zero, F.zero)], f return [], f def dup_isolate_real_roots_sqf(f, K, eps=None, inf=None, sup=None, fast=False, blackbox=False): """Isolate real roots of a square-free polynomial using the Vincent-Akritas-Strzebonski (VAS) CF approach. References ========== .. [1] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative Study of Two Real Root Isolation Methods. Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. .. [2] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. Vigklas: Improving the Performance of the Continued Fractions Method Using New Bounds of Positive Roots. Nonlinear Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. """ if K.is_QQ: (_, f), K = dup_clear_denoms(f, K, convert=True), K.get_ring() elif not K.is_ZZ: raise DomainError("isolation of real roots not supported over %s" % K) if dup_degree(f) <= 0: return [] I_zero, f = _isolate_zero(f, K, inf, sup, basis=False, sqf=True) I_neg = dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) I_pos = dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) roots = sorted(I_neg + I_zero + I_pos) if not blackbox: return roots else: return [ RealInterval((a, b), f, K) for (a, b) in roots ] def dup_isolate_real_roots(f, K, eps=None, inf=None, sup=None, basis=False, fast=False): """Isolate real roots using Vincent-Akritas-Strzebonski (VAS) continued fractions approach. References ========== .. [1] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative Study of Two Real Root Isolation Methods. Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. .. [2] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. Vigklas: Improving the Performance of the Continued Fractions Method Using New Bounds of Positive Roots. Nonlinear Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. """ if K.is_QQ: (_, f), K = dup_clear_denoms(f, K, convert=True), K.get_ring() elif not K.is_ZZ: raise DomainError("isolation of real roots not supported over %s" % K) if dup_degree(f) <= 0: return [] I_zero, f = _isolate_zero(f, K, inf, sup, basis=basis, sqf=False) _, factors = dup_sqf_list(f, K) if len(factors) == 1: ((f, k),) = factors I_neg = dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) I_pos = dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast) I_neg = [ ((u, v), k) for u, v in I_neg ] I_pos = [ ((u, v), k) for u, v in I_pos ] else: I_neg, I_pos = _real_isolate_and_disjoin(factors, K, eps=eps, inf=inf, sup=sup, basis=basis, fast=fast) return sorted(I_neg + I_zero + I_pos) def dup_isolate_real_roots_list(polys, K, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): """Isolate real roots of a list of square-free polynomial using Vincent-Akritas-Strzebonski (VAS) CF approach. References ========== .. [1] Alkiviadis G. Akritas and Adam W. Strzebonski: A Comparative Study of Two Real Root Isolation Methods. Nonlinear Analysis: Modelling and Control, Vol. 10, No. 4, 297-304, 2005. .. [2] Alkiviadis G. Akritas, Adam W. Strzebonski and Panagiotis S. Vigklas: Improving the Performance of the Continued Fractions Method Using New Bounds of Positive Roots. Nonlinear Analysis: Modelling and Control, Vol. 13, No. 3, 265-279, 2008. """ if K.is_QQ: K, F, polys = K.get_ring(), K, polys[:] for i, p in enumerate(polys): polys[i] = dup_clear_denoms(p, F, K, convert=True)[1] elif not K.is_ZZ: raise DomainError("isolation of real roots not supported over %s" % K) zeros, factors_dict = False, {} if (inf is None or inf <= 0) and (sup is None or 0 <= sup): zeros, zero_indices = True, {} for i, p in enumerate(polys): j, p = dup_terms_gcd(p, K) if zeros and j > 0: zero_indices[i] = j for f, k in dup_factor_list(p, K)[1]: f = tuple(f) if f not in factors_dict: factors_dict[f] = {i: k} else: factors_dict[f][i] = k factors_list = [] for f, indices in factors_dict.items(): factors_list.append((list(f), indices)) I_neg, I_pos = _real_isolate_and_disjoin(factors_list, K, eps=eps, inf=inf, sup=sup, strict=strict, basis=basis, fast=fast) F = K.get_field() if not zeros or not zero_indices: I_zero = [] else: if not basis: I_zero = [((F.zero, F.zero), zero_indices)] else: I_zero = [((F.zero, F.zero), zero_indices, [K.one, K.zero])] return sorted(I_neg + I_zero + I_pos) def _disjoint_p(M, N, strict=False): """Check if Mobius transforms define disjoint intervals. """ a1, b1, c1, d1 = M a2, b2, c2, d2 = N a1d1, b1c1 = a1*d1, b1*c1 a2d2, b2c2 = a2*d2, b2*c2 if a1d1 == b1c1 and a2d2 == b2c2: return True if a1d1 > b1c1: a1, c1, b1, d1 = b1, d1, a1, c1 if a2d2 > b2c2: a2, c2, b2, d2 = b2, d2, a2, c2 if not strict: return a2*d1 >= c2*b1 or b2*c1 <= d2*a1 else: return a2*d1 > c2*b1 or b2*c1 < d2*a1 def _real_isolate_and_disjoin(factors, K, eps=None, inf=None, sup=None, strict=False, basis=False, fast=False): """Isolate real roots of a list of polynomials and disjoin intervals. """ I_pos, I_neg = [], [] for i, (f, k) in enumerate(factors): for F, M in dup_inner_isolate_positive_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast, mobius=True): I_pos.append((F, M, k, f)) for G, N in dup_inner_isolate_negative_roots(f, K, eps=eps, inf=inf, sup=sup, fast=fast, mobius=True): I_neg.append((G, N, k, f)) for i, (f, M, k, F) in enumerate(I_pos): for j, (g, N, m, G) in enumerate(I_pos[i + 1:]): while not _disjoint_p(M, N, strict=strict): f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) I_pos[i + j + 1] = (g, N, m, G) I_pos[i] = (f, M, k, F) for i, (f, M, k, F) in enumerate(I_neg): for j, (g, N, m, G) in enumerate(I_neg[i + 1:]): while not _disjoint_p(M, N, strict=strict): f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) I_neg[i + j + 1] = (g, N, m, G) I_neg[i] = (f, M, k, F) if strict: for i, (f, M, k, F) in enumerate(I_neg): if not M[0]: while not M[0]: f, M = dup_inner_refine_real_root(f, M, K, steps=1, fast=fast, mobius=True) I_neg[i] = (f, M, k, F) break for j, (g, N, m, G) in enumerate(I_pos): if not N[0]: while not N[0]: g, N = dup_inner_refine_real_root(g, N, K, steps=1, fast=fast, mobius=True) I_pos[j] = (g, N, m, G) break field = K.get_field() I_neg = [ (_mobius_to_interval(M, field), k, f) for (_, M, k, f) in I_neg ] I_pos = [ (_mobius_to_interval(M, field), k, f) for (_, M, k, f) in I_pos ] if not basis: I_neg = [ ((-v, -u), k) for ((u, v), k, _) in I_neg ] I_pos = [ (( u, v), k) for ((u, v), k, _) in I_pos ] else: I_neg = [ ((-v, -u), k, f) for ((u, v), k, f) in I_neg ] I_pos = [ (( u, v), k, f) for ((u, v), k, f) in I_pos ] return I_neg, I_pos def dup_count_real_roots(f, K, inf=None, sup=None): """Returns the number of distinct real roots of ``f`` in ``[inf, sup]``. """ if dup_degree(f) <= 0: return 0 if not K.is_Field: R, K = K, K.get_field() f = dup_convert(f, R, K) sturm = dup_sturm(f, K) if inf is None: signs_inf = dup_sign_variations([ dup_LC(s, K)*(-1)**dup_degree(s) for s in sturm ], K) else: signs_inf = dup_sign_variations([ dup_eval(s, inf, K) for s in sturm ], K) if sup is None: signs_sup = dup_sign_variations([ dup_LC(s, K) for s in sturm ], K) else: signs_sup = dup_sign_variations([ dup_eval(s, sup, K) for s in sturm ], K) count = abs(signs_inf - signs_sup) if inf is not None and not dup_eval(f, inf, K): count += 1 return count OO = 'OO' # Origin of (re, im) coordinate system Q1 = 'Q1' # Quadrant #1 (++): re > 0 and im > 0 Q2 = 'Q2' # Quadrant #2 (-+): re < 0 and im > 0 Q3 = 'Q3' # Quadrant #3 (--): re < 0 and im < 0 Q4 = 'Q4' # Quadrant #4 (+-): re > 0 and im < 0 A1 = 'A1' # Axis #1 (+0): re > 0 and im = 0 A2 = 'A2' # Axis #2 (0+): re = 0 and im > 0 A3 = 'A3' # Axis #3 (-0): re < 0 and im = 0 A4 = 'A4' # Axis #4 (0-): re = 0 and im < 0 _rules_simple = { # Q --> Q (same) => no change (Q1, Q1): 0, (Q2, Q2): 0, (Q3, Q3): 0, (Q4, Q4): 0, # A -- CCW --> Q => +1/4 (CCW) (A1, Q1): 1, (A2, Q2): 1, (A3, Q3): 1, (A4, Q4): 1, # A -- CW --> Q => -1/4 (CCW) (A1, Q4): 2, (A2, Q1): 2, (A3, Q2): 2, (A4, Q3): 2, # Q -- CCW --> A => +1/4 (CCW) (Q1, A2): 3, (Q2, A3): 3, (Q3, A4): 3, (Q4, A1): 3, # Q -- CW --> A => -1/4 (CCW) (Q1, A1): 4, (Q2, A2): 4, (Q3, A3): 4, (Q4, A4): 4, # Q -- CCW --> Q => +1/2 (CCW) (Q1, Q2): +5, (Q2, Q3): +5, (Q3, Q4): +5, (Q4, Q1): +5, # Q -- CW --> Q => -1/2 (CW) (Q1, Q4): -5, (Q2, Q1): -5, (Q3, Q2): -5, (Q4, Q3): -5, } _rules_ambiguous = { # A -- CCW --> Q => { +1/4 (CCW), -9/4 (CW) } (A1, OO, Q1): -1, (A2, OO, Q2): -1, (A3, OO, Q3): -1, (A4, OO, Q4): -1, # A -- CW --> Q => { -1/4 (CCW), +7/4 (CW) } (A1, OO, Q4): -2, (A2, OO, Q1): -2, (A3, OO, Q2): -2, (A4, OO, Q3): -2, # Q -- CCW --> A => { +1/4 (CCW), -9/4 (CW) } (Q1, OO, A2): -3, (Q2, OO, A3): -3, (Q3, OO, A4): -3, (Q4, OO, A1): -3, # Q -- CW --> A => { -1/4 (CCW), +7/4 (CW) } (Q1, OO, A1): -4, (Q2, OO, A2): -4, (Q3, OO, A3): -4, (Q4, OO, A4): -4, # A -- OO --> A => { +1 (CCW), -1 (CW) } (A1, A3): 7, (A2, A4): 7, (A3, A1): 7, (A4, A2): 7, (A1, OO, A3): 7, (A2, OO, A4): 7, (A3, OO, A1): 7, (A4, OO, A2): 7, # Q -- DIA --> Q => { +1 (CCW), -1 (CW) } (Q1, Q3): 8, (Q2, Q4): 8, (Q3, Q1): 8, (Q4, Q2): 8, (Q1, OO, Q3): 8, (Q2, OO, Q4): 8, (Q3, OO, Q1): 8, (Q4, OO, Q2): 8, # A --- R ---> A => { +1/2 (CCW), -3/2 (CW) } (A1, A2): 9, (A2, A3): 9, (A3, A4): 9, (A4, A1): 9, (A1, OO, A2): 9, (A2, OO, A3): 9, (A3, OO, A4): 9, (A4, OO, A1): 9, # A --- L ---> A => { +3/2 (CCW), -1/2 (CW) } (A1, A4): 10, (A2, A1): 10, (A3, A2): 10, (A4, A3): 10, (A1, OO, A4): 10, (A2, OO, A1): 10, (A3, OO, A2): 10, (A4, OO, A3): 10, # Q --- 1 ---> A => { +3/4 (CCW), -5/4 (CW) } (Q1, A3): 11, (Q2, A4): 11, (Q3, A1): 11, (Q4, A2): 11, (Q1, OO, A3): 11, (Q2, OO, A4): 11, (Q3, OO, A1): 11, (Q4, OO, A2): 11, # Q --- 2 ---> A => { +5/4 (CCW), -3/4 (CW) } (Q1, A4): 12, (Q2, A1): 12, (Q3, A2): 12, (Q4, A3): 12, (Q1, OO, A4): 12, (Q2, OO, A1): 12, (Q3, OO, A2): 12, (Q4, OO, A3): 12, # A --- 1 ---> Q => { +5/4 (CCW), -3/4 (CW) } (A1, Q3): 13, (A2, Q4): 13, (A3, Q1): 13, (A4, Q2): 13, (A1, OO, Q3): 13, (A2, OO, Q4): 13, (A3, OO, Q1): 13, (A4, OO, Q2): 13, # A --- 2 ---> Q => { +3/4 (CCW), -5/4 (CW) } (A1, Q2): 14, (A2, Q3): 14, (A3, Q4): 14, (A4, Q1): 14, (A1, OO, Q2): 14, (A2, OO, Q3): 14, (A3, OO, Q4): 14, (A4, OO, Q1): 14, # Q --> OO --> Q => { +1/2 (CCW), -3/2 (CW) } (Q1, OO, Q2): 15, (Q2, OO, Q3): 15, (Q3, OO, Q4): 15, (Q4, OO, Q1): 15, # Q --> OO --> Q => { +3/2 (CCW), -1/2 (CW) } (Q1, OO, Q4): 16, (Q2, OO, Q1): 16, (Q3, OO, Q2): 16, (Q4, OO, Q3): 16, # A --> OO --> A => { +2 (CCW), 0 (CW) } (A1, OO, A1): 17, (A2, OO, A2): 17, (A3, OO, A3): 17, (A4, OO, A4): 17, # Q --> OO --> Q => { +2 (CCW), 0 (CW) } (Q1, OO, Q1): 18, (Q2, OO, Q2): 18, (Q3, OO, Q3): 18, (Q4, OO, Q4): 18, } _values = { 0: [( 0, 1)], 1: [(+1, 4)], 2: [(-1, 4)], 3: [(+1, 4)], 4: [(-1, 4)], -1: [(+9, 4), (+1, 4)], -2: [(+7, 4), (-1, 4)], -3: [(+9, 4), (+1, 4)], -4: [(+7, 4), (-1, 4)], +5: [(+1, 2)], -5: [(-1, 2)], 7: [(+1, 1), (-1, 1)], 8: [(+1, 1), (-1, 1)], 9: [(+1, 2), (-3, 2)], 10: [(+3, 2), (-1, 2)], 11: [(+3, 4), (-5, 4)], 12: [(+5, 4), (-3, 4)], 13: [(+5, 4), (-3, 4)], 14: [(+3, 4), (-5, 4)], 15: [(+1, 2), (-3, 2)], 16: [(+3, 2), (-1, 2)], 17: [(+2, 1), ( 0, 1)], 18: [(+2, 1), ( 0, 1)], } def _classify_point(re, im): """Return the half-axis (or origin) on which (re, im) point is located. """ if not re and not im: return OO if not re: if im > 0: return A2 else: return A4 elif not im: if re > 0: return A1 else: return A3 def _intervals_to_quadrants(intervals, f1, f2, s, t, F): """Generate a sequence of extended quadrants from a list of critical points. """ if not intervals: return [] Q = [] if not f1: (a, b), _, _ = intervals[0] if a == b == s: if len(intervals) == 1: if dup_eval(f2, t, F) > 0: return [OO, A2] else: return [OO, A4] else: (a, _), _, _ = intervals[1] if dup_eval(f2, (s + a)/2, F) > 0: Q.extend([OO, A2]) f2_sgn = +1 else: Q.extend([OO, A4]) f2_sgn = -1 intervals = intervals[1:] else: if dup_eval(f2, s, F) > 0: Q.append(A2) f2_sgn = +1 else: Q.append(A4) f2_sgn = -1 for (a, _), indices, _ in intervals: Q.append(OO) if indices[1] % 2 == 1: f2_sgn = -f2_sgn if a != t: if f2_sgn > 0: Q.append(A2) else: Q.append(A4) return Q if not f2: (a, b), _, _ = intervals[0] if a == b == s: if len(intervals) == 1: if dup_eval(f1, t, F) > 0: return [OO, A1] else: return [OO, A3] else: (a, _), _, _ = intervals[1] if dup_eval(f1, (s + a)/2, F) > 0: Q.extend([OO, A1]) f1_sgn = +1 else: Q.extend([OO, A3]) f1_sgn = -1 intervals = intervals[1:] else: if dup_eval(f1, s, F) > 0: Q.append(A1) f1_sgn = +1 else: Q.append(A3) f1_sgn = -1 for (a, _), indices, _ in intervals: Q.append(OO) if indices[0] % 2 == 1: f1_sgn = -f1_sgn if a != t: if f1_sgn > 0: Q.append(A1) else: Q.append(A3) return Q re = dup_eval(f1, s, F) im = dup_eval(f2, s, F) if not re or not im: Q.append(_classify_point(re, im)) if len(intervals) == 1: re = dup_eval(f1, t, F) im = dup_eval(f2, t, F) else: (a, _), _, _ = intervals[1] re = dup_eval(f1, (s + a)/2, F) im = dup_eval(f2, (s + a)/2, F) intervals = intervals[1:] if re > 0: f1_sgn = +1 else: f1_sgn = -1 if im > 0: f2_sgn = +1 else: f2_sgn = -1 sgn = { (+1, +1): Q1, (-1, +1): Q2, (-1, -1): Q3, (+1, -1): Q4, } Q.append(sgn[(f1_sgn, f2_sgn)]) for (a, b), indices, _ in intervals: if a == b: re = dup_eval(f1, a, F) im = dup_eval(f2, a, F) cls = _classify_point(re, im) if cls is not None: Q.append(cls) if 0 in indices: if indices[0] % 2 == 1: f1_sgn = -f1_sgn if 1 in indices: if indices[1] % 2 == 1: f2_sgn = -f2_sgn if not (a == b and b == t): Q.append(sgn[(f1_sgn, f2_sgn)]) return Q def _traverse_quadrants(Q_L1, Q_L2, Q_L3, Q_L4, exclude=None): """Transform sequences of quadrants to a sequence of rules. """ if exclude is True: edges = [1, 1, 0, 0] corners = { (0, 1): 1, (1, 2): 1, (2, 3): 0, (3, 0): 1, } else: edges = [0, 0, 0, 0] corners = { (0, 1): 0, (1, 2): 0, (2, 3): 0, (3, 0): 0, } if exclude is not None and exclude is not True: exclude = set(exclude) for i, edge in enumerate(['S', 'E', 'N', 'W']): if edge in exclude: edges[i] = 1 for i, corner in enumerate(['SW', 'SE', 'NE', 'NW']): if corner in exclude: corners[((i - 1) % 4, i)] = 1 QQ, rules = [Q_L1, Q_L2, Q_L3, Q_L4], [] for i, Q in enumerate(QQ): if not Q: continue if Q[-1] == OO: Q = Q[:-1] if Q[0] == OO: j, Q = (i - 1) % 4, Q[1:] qq = (QQ[j][-2], OO, Q[0]) if qq in _rules_ambiguous: rules.append((_rules_ambiguous[qq], corners[(j, i)])) else: raise NotImplementedError("3 element rule (corner): " + str(qq)) q1, k = Q[0], 1 while k < len(Q): q2, k = Q[k], k + 1 if q2 != OO: qq = (q1, q2) if qq in _rules_simple: rules.append((_rules_simple[qq], 0)) elif qq in _rules_ambiguous: rules.append((_rules_ambiguous[qq], edges[i])) else: raise NotImplementedError("2 element rule (inside): " + str(qq)) else: qq, k = (q1, q2, Q[k]), k + 1 if qq in _rules_ambiguous: rules.append((_rules_ambiguous[qq], edges[i])) else: raise NotImplementedError("3 element rule (edge): " + str(qq)) q1 = qq[-1] return rules def _reverse_intervals(intervals): """Reverse intervals for traversal from right to left and from top to bottom. """ return [ ((b, a), indices, f) for (a, b), indices, f in reversed(intervals) ] def _winding_number(T, field): """Compute the winding number of the input polynomial, i.e. the number of roots. """ return int(sum([ field(*_values[t][i]) for t, i in T ]) / field(2)) def dup_count_complex_roots(f, K, inf=None, sup=None, exclude=None): """Count all roots in [u + v*I, s + t*I] rectangle using Collins-Krandick algorithm. """ if not K.is_ZZ and not K.is_QQ: raise DomainError("complex root counting is not supported over %s" % K) if K.is_ZZ: R, F = K, K.get_field() else: R, F = K.get_ring(), K f = dup_convert(f, K, F) if inf is None or sup is None: _, lc = dup_degree(f), abs(dup_LC(f, F)) B = 2*max([ F.quo(abs(c), lc) for c in f ]) if inf is None: (u, v) = (-B, -B) else: (u, v) = inf if sup is None: (s, t) = (+B, +B) else: (s, t) = sup f1, f2 = dup_real_imag(f, F) f1L1F = dmp_eval_in(f1, v, 1, 1, F) f2L1F = dmp_eval_in(f2, v, 1, 1, F) _, f1L1R = dup_clear_denoms(f1L1F, F, R, convert=True) _, f2L1R = dup_clear_denoms(f2L1F, F, R, convert=True) f1L2F = dmp_eval_in(f1, s, 0, 1, F) f2L2F = dmp_eval_in(f2, s, 0, 1, F) _, f1L2R = dup_clear_denoms(f1L2F, F, R, convert=True) _, f2L2R = dup_clear_denoms(f2L2F, F, R, convert=True) f1L3F = dmp_eval_in(f1, t, 1, 1, F) f2L3F = dmp_eval_in(f2, t, 1, 1, F) _, f1L3R = dup_clear_denoms(f1L3F, F, R, convert=True) _, f2L3R = dup_clear_denoms(f2L3F, F, R, convert=True) f1L4F = dmp_eval_in(f1, u, 0, 1, F) f2L4F = dmp_eval_in(f2, u, 0, 1, F) _, f1L4R = dup_clear_denoms(f1L4F, F, R, convert=True) _, f2L4R = dup_clear_denoms(f2L4F, F, R, convert=True) S_L1 = [f1L1R, f2L1R] S_L2 = [f1L2R, f2L2R] S_L3 = [f1L3R, f2L3R] S_L4 = [f1L4R, f2L4R] I_L1 = dup_isolate_real_roots_list(S_L1, R, inf=u, sup=s, fast=True, basis=True, strict=True) I_L2 = dup_isolate_real_roots_list(S_L2, R, inf=v, sup=t, fast=True, basis=True, strict=True) I_L3 = dup_isolate_real_roots_list(S_L3, R, inf=u, sup=s, fast=True, basis=True, strict=True) I_L4 = dup_isolate_real_roots_list(S_L4, R, inf=v, sup=t, fast=True, basis=True, strict=True) I_L3 = _reverse_intervals(I_L3) I_L4 = _reverse_intervals(I_L4) Q_L1 = _intervals_to_quadrants(I_L1, f1L1F, f2L1F, u, s, F) Q_L2 = _intervals_to_quadrants(I_L2, f1L2F, f2L2F, v, t, F) Q_L3 = _intervals_to_quadrants(I_L3, f1L3F, f2L3F, s, u, F) Q_L4 = _intervals_to_quadrants(I_L4, f1L4F, f2L4F, t, v, F) T = _traverse_quadrants(Q_L1, Q_L2, Q_L3, Q_L4, exclude=exclude) return _winding_number(T, F) def _vertical_bisection(N, a, b, I, Q, F1, F2, f1, f2, F): """Vertical bisection step in Collins-Krandick root isolation algorithm. """ (u, v), (s, t) = a, b I_L1, I_L2, I_L3, I_L4 = I Q_L1, Q_L2, Q_L3, Q_L4 = Q f1L1F, f1L2F, f1L3F, f1L4F = F1 f2L1F, f2L2F, f2L3F, f2L4F = F2 x = (u + s) / 2 f1V = dmp_eval_in(f1, x, 0, 1, F) f2V = dmp_eval_in(f2, x, 0, 1, F) I_V = dup_isolate_real_roots_list([f1V, f2V], F, inf=v, sup=t, fast=True, strict=True, basis=True) I_L1_L, I_L1_R = [], [] I_L2_L, I_L2_R = I_V, I_L2 I_L3_L, I_L3_R = [], [] I_L4_L, I_L4_R = I_L4, _reverse_intervals(I_V) for I in I_L1: (a, b), indices, h = I if a == b: if a == x: I_L1_L.append(I) I_L1_R.append(I) elif a < x: I_L1_L.append(I) else: I_L1_R.append(I) else: if b <= x: I_L1_L.append(I) elif a >= x: I_L1_R.append(I) else: a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=x, fast=True) if b <= x: I_L1_L.append(((a, b), indices, h)) if a >= x: I_L1_R.append(((a, b), indices, h)) for I in I_L3: (b, a), indices, h = I if a == b: if a == x: I_L3_L.append(I) I_L3_R.append(I) elif a < x: I_L3_L.append(I) else: I_L3_R.append(I) else: if b <= x: I_L3_L.append(I) elif a >= x: I_L3_R.append(I) else: a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=x, fast=True) if b <= x: I_L3_L.append(((b, a), indices, h)) if a >= x: I_L3_R.append(((b, a), indices, h)) Q_L1_L = _intervals_to_quadrants(I_L1_L, f1L1F, f2L1F, u, x, F) Q_L2_L = _intervals_to_quadrants(I_L2_L, f1V, f2V, v, t, F) Q_L3_L = _intervals_to_quadrants(I_L3_L, f1L3F, f2L3F, x, u, F) Q_L4_L = Q_L4 Q_L1_R = _intervals_to_quadrants(I_L1_R, f1L1F, f2L1F, x, s, F) Q_L2_R = Q_L2 Q_L3_R = _intervals_to_quadrants(I_L3_R, f1L3F, f2L3F, s, x, F) Q_L4_R = _intervals_to_quadrants(I_L4_R, f1V, f2V, t, v, F) T_L = _traverse_quadrants(Q_L1_L, Q_L2_L, Q_L3_L, Q_L4_L, exclude=True) T_R = _traverse_quadrants(Q_L1_R, Q_L2_R, Q_L3_R, Q_L4_R, exclude=True) N_L = _winding_number(T_L, F) N_R = _winding_number(T_R, F) I_L = (I_L1_L, I_L2_L, I_L3_L, I_L4_L) Q_L = (Q_L1_L, Q_L2_L, Q_L3_L, Q_L4_L) I_R = (I_L1_R, I_L2_R, I_L3_R, I_L4_R) Q_R = (Q_L1_R, Q_L2_R, Q_L3_R, Q_L4_R) F1_L = (f1L1F, f1V, f1L3F, f1L4F) F2_L = (f2L1F, f2V, f2L3F, f2L4F) F1_R = (f1L1F, f1L2F, f1L3F, f1V) F2_R = (f2L1F, f2L2F, f2L3F, f2V) a, b = (u, v), (x, t) c, d = (x, v), (s, t) D_L = (N_L, a, b, I_L, Q_L, F1_L, F2_L) D_R = (N_R, c, d, I_R, Q_R, F1_R, F2_R) return D_L, D_R def _horizontal_bisection(N, a, b, I, Q, F1, F2, f1, f2, F): """Horizontal bisection step in Collins-Krandick root isolation algorithm. """ (u, v), (s, t) = a, b I_L1, I_L2, I_L3, I_L4 = I Q_L1, Q_L2, Q_L3, Q_L4 = Q f1L1F, f1L2F, f1L3F, f1L4F = F1 f2L1F, f2L2F, f2L3F, f2L4F = F2 y = (v + t) / 2 f1H = dmp_eval_in(f1, y, 1, 1, F) f2H = dmp_eval_in(f2, y, 1, 1, F) I_H = dup_isolate_real_roots_list([f1H, f2H], F, inf=u, sup=s, fast=True, strict=True, basis=True) I_L1_B, I_L1_U = I_L1, I_H I_L2_B, I_L2_U = [], [] I_L3_B, I_L3_U = _reverse_intervals(I_H), I_L3 I_L4_B, I_L4_U = [], [] for I in I_L2: (a, b), indices, h = I if a == b: if a == y: I_L2_B.append(I) I_L2_U.append(I) elif a < y: I_L2_B.append(I) else: I_L2_U.append(I) else: if b <= y: I_L2_B.append(I) elif a >= y: I_L2_U.append(I) else: a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=y, fast=True) if b <= y: I_L2_B.append(((a, b), indices, h)) if a >= y: I_L2_U.append(((a, b), indices, h)) for I in I_L4: (b, a), indices, h = I if a == b: if a == y: I_L4_B.append(I) I_L4_U.append(I) elif a < y: I_L4_B.append(I) else: I_L4_U.append(I) else: if b <= y: I_L4_B.append(I) elif a >= y: I_L4_U.append(I) else: a, b = dup_refine_real_root(h, a, b, F.get_ring(), disjoint=y, fast=True) if b <= y: I_L4_B.append(((b, a), indices, h)) if a >= y: I_L4_U.append(((b, a), indices, h)) Q_L1_B = Q_L1 Q_L2_B = _intervals_to_quadrants(I_L2_B, f1L2F, f2L2F, v, y, F) Q_L3_B = _intervals_to_quadrants(I_L3_B, f1H, f2H, s, u, F) Q_L4_B = _intervals_to_quadrants(I_L4_B, f1L4F, f2L4F, y, v, F) Q_L1_U = _intervals_to_quadrants(I_L1_U, f1H, f2H, u, s, F) Q_L2_U = _intervals_to_quadrants(I_L2_U, f1L2F, f2L2F, y, t, F) Q_L3_U = Q_L3 Q_L4_U = _intervals_to_quadrants(I_L4_U, f1L4F, f2L4F, t, y, F) T_B = _traverse_quadrants(Q_L1_B, Q_L2_B, Q_L3_B, Q_L4_B, exclude=True) T_U = _traverse_quadrants(Q_L1_U, Q_L2_U, Q_L3_U, Q_L4_U, exclude=True) N_B = _winding_number(T_B, F) N_U = _winding_number(T_U, F) I_B = (I_L1_B, I_L2_B, I_L3_B, I_L4_B) Q_B = (Q_L1_B, Q_L2_B, Q_L3_B, Q_L4_B) I_U = (I_L1_U, I_L2_U, I_L3_U, I_L4_U) Q_U = (Q_L1_U, Q_L2_U, Q_L3_U, Q_L4_U) F1_B = (f1L1F, f1L2F, f1H, f1L4F) F2_B = (f2L1F, f2L2F, f2H, f2L4F) F1_U = (f1H, f1L2F, f1L3F, f1L4F) F2_U = (f2H, f2L2F, f2L3F, f2L4F) a, b = (u, v), (s, y) c, d = (u, y), (s, t) D_B = (N_B, a, b, I_B, Q_B, F1_B, F2_B) D_U = (N_U, c, d, I_U, Q_U, F1_U, F2_U) return D_B, D_U def _depth_first_select(rectangles): """Find a rectangle of minimum area for bisection. """ min_area, j = None, None for i, (_, (u, v), (s, t), _, _, _, _) in enumerate(rectangles): area = (s - u)*(t - v) if min_area is None or area < min_area: min_area, j = area, i return rectangles.pop(j) def _rectangle_small_p(a, b, eps): """Return ``True`` if the given rectangle is small enough. """ (u, v), (s, t) = a, b if eps is not None: return s - u < eps and t - v < eps else: return True def dup_isolate_complex_roots_sqf(f, K, eps=None, inf=None, sup=None, blackbox=False): """Isolate complex roots of a square-free polynomial using Collins-Krandick algorithm. """ if not K.is_ZZ and not K.is_QQ: raise DomainError("isolation of complex roots is not supported over %s" % K) if dup_degree(f) <= 0: return [] if K.is_ZZ: F = K.get_field() else: F = K f = dup_convert(f, K, F) lc = abs(dup_LC(f, F)) B = 2*max([ F.quo(abs(c), lc) for c in f ]) (u, v), (s, t) = (-B, F.zero), (B, B) if inf is not None: u = inf if sup is not None: s = sup if v < 0 or t <= v or s <= u: raise ValueError("not a valid complex isolation rectangle") f1, f2 = dup_real_imag(f, F) f1L1 = dmp_eval_in(f1, v, 1, 1, F) f2L1 = dmp_eval_in(f2, v, 1, 1, F) f1L2 = dmp_eval_in(f1, s, 0, 1, F) f2L2 = dmp_eval_in(f2, s, 0, 1, F) f1L3 = dmp_eval_in(f1, t, 1, 1, F) f2L3 = dmp_eval_in(f2, t, 1, 1, F) f1L4 = dmp_eval_in(f1, u, 0, 1, F) f2L4 = dmp_eval_in(f2, u, 0, 1, F) S_L1 = [f1L1, f2L1] S_L2 = [f1L2, f2L2] S_L3 = [f1L3, f2L3] S_L4 = [f1L4, f2L4] I_L1 = dup_isolate_real_roots_list(S_L1, F, inf=u, sup=s, fast=True, strict=True, basis=True) I_L2 = dup_isolate_real_roots_list(S_L2, F, inf=v, sup=t, fast=True, strict=True, basis=True) I_L3 = dup_isolate_real_roots_list(S_L3, F, inf=u, sup=s, fast=True, strict=True, basis=True) I_L4 = dup_isolate_real_roots_list(S_L4, F, inf=v, sup=t, fast=True, strict=True, basis=True) I_L3 = _reverse_intervals(I_L3) I_L4 = _reverse_intervals(I_L4) Q_L1 = _intervals_to_quadrants(I_L1, f1L1, f2L1, u, s, F) Q_L2 = _intervals_to_quadrants(I_L2, f1L2, f2L2, v, t, F) Q_L3 = _intervals_to_quadrants(I_L3, f1L3, f2L3, s, u, F) Q_L4 = _intervals_to_quadrants(I_L4, f1L4, f2L4, t, v, F) T = _traverse_quadrants(Q_L1, Q_L2, Q_L3, Q_L4) N = _winding_number(T, F) if not N: return [] I = (I_L1, I_L2, I_L3, I_L4) Q = (Q_L1, Q_L2, Q_L3, Q_L4) F1 = (f1L1, f1L2, f1L3, f1L4) F2 = (f2L1, f2L2, f2L3, f2L4) rectangles, roots = [(N, (u, v), (s, t), I, Q, F1, F2)], [] while rectangles: N, (u, v), (s, t), I, Q, F1, F2 = _depth_first_select(rectangles) if s - u > t - v: D_L, D_R = _vertical_bisection(N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) N_L, a, b, I_L, Q_L, F1_L, F2_L = D_L N_R, c, d, I_R, Q_R, F1_R, F2_R = D_R if N_L >= 1: if N_L == 1 and _rectangle_small_p(a, b, eps): roots.append(ComplexInterval(a, b, I_L, Q_L, F1_L, F2_L, f1, f2, F)) else: rectangles.append(D_L) if N_R >= 1: if N_R == 1 and _rectangle_small_p(c, d, eps): roots.append(ComplexInterval(c, d, I_R, Q_R, F1_R, F2_R, f1, f2, F)) else: rectangles.append(D_R) else: D_B, D_U = _horizontal_bisection(N, (u, v), (s, t), I, Q, F1, F2, f1, f2, F) N_B, a, b, I_B, Q_B, F1_B, F2_B = D_B N_U, c, d, I_U, Q_U, F1_U, F2_U = D_U if N_B >= 1: if N_B == 1 and _rectangle_small_p(a, b, eps): roots.append(ComplexInterval( a, b, I_B, Q_B, F1_B, F2_B, f1, f2, F)) else: rectangles.append(D_B) if N_U >= 1: if N_U == 1 and _rectangle_small_p(c, d, eps): roots.append(ComplexInterval( c, d, I_U, Q_U, F1_U, F2_U, f1, f2, F)) else: rectangles.append(D_U) _roots, roots = sorted(roots, key=lambda r: (r.ax, r.ay)), [] for root in _roots: roots.extend([root.conjugate(), root]) if blackbox: return roots else: return [ r.as_tuple() for r in roots ] def dup_isolate_all_roots_sqf(f, K, eps=None, inf=None, sup=None, fast=False, blackbox=False): """Isolate real and complex roots of a square-free polynomial ``f``. """ return ( dup_isolate_real_roots_sqf( f, K, eps=eps, inf=inf, sup=sup, fast=fast, blackbox=blackbox), dup_isolate_complex_roots_sqf(f, K, eps=eps, inf=inf, sup=sup, blackbox=blackbox)) def dup_isolate_all_roots(f, K, eps=None, inf=None, sup=None, fast=False): """Isolate real and complex roots of a non-square-free polynomial ``f``. """ if not K.is_ZZ and not K.is_QQ: raise DomainError("isolation of real and complex roots is not supported over %s" % K) _, factors = dup_sqf_list(f, K) if len(factors) == 1: ((f, k),) = factors real_part, complex_part = dup_isolate_all_roots_sqf( f, K, eps=eps, inf=inf, sup=sup, fast=fast) real_part = [ ((a, b), k) for (a, b) in real_part ] complex_part = [ ((a, b), k) for (a, b) in complex_part ] return real_part, complex_part else: raise NotImplementedError( "only trivial square-free polynomials are supported") class RealInterval: """A fully qualified representation of a real isolation interval. """ def __init__(self, data, f, dom): """Initialize new real interval with complete information. """ if len(data) == 2: s, t = data self.neg = False if s < 0: if t <= 0: f, s, t, self.neg = dup_mirror(f, dom), -t, -s, True else: raise ValueError("can't refine a real root in (%s, %s)" % (s, t)) a, b, c, d = _mobius_from_interval((s, t), dom.get_field()) f = dup_transform(f, dup_strip([a, b]), dup_strip([c, d]), dom) self.mobius = a, b, c, d else: self.mobius = data[:-1] self.neg = data[-1] self.f, self.dom = f, dom @property def func(self): return RealInterval @property def args(self): i = self return (i.mobius + (i.neg,), i.f, i.dom) def __eq__(self, other): if type(other) != type(self): return False return self.args == other.args @property def a(self): """Return the position of the left end. """ field = self.dom.get_field() a, b, c, d = self.mobius if not self.neg: if a*d < b*c: return field(a, c) return field(b, d) else: if a*d > b*c: return -field(a, c) return -field(b, d) @property def b(self): """Return the position of the right end. """ was = self.neg self.neg = not was rv = -self.a self.neg = was return rv @property def dx(self): """Return width of the real isolating interval. """ return self.b - self.a @property def center(self): """Return the center of the real isolating interval. """ return (self.a + self.b)/2 def as_tuple(self): """Return tuple representation of real isolating interval. """ return (self.a, self.b) def __repr__(self): return "(%s, %s)" % (self.a, self.b) def is_disjoint(self, other): """Return ``True`` if two isolation intervals are disjoint. """ if isinstance(other, RealInterval): return (self.b < other.a or other.b < self.a) assert isinstance(other, ComplexInterval) return (self.b < other.ax or other.bx < self.a or other.ay*other.by > 0) def _inner_refine(self): """Internal one step real root refinement procedure. """ if self.mobius is None: return self f, mobius = dup_inner_refine_real_root( self.f, self.mobius, self.dom, steps=1, mobius=True) return RealInterval(mobius + (self.neg,), f, self.dom) def refine_disjoint(self, other): """Refine an isolating interval until it is disjoint with another one. """ expr = self while not expr.is_disjoint(other): expr, other = expr._inner_refine(), other._inner_refine() return expr, other def refine_size(self, dx): """Refine an isolating interval until it is of sufficiently small size. """ expr = self while not (expr.dx < dx): expr = expr._inner_refine() return expr def refine_step(self, steps=1): """Perform several steps of real root refinement algorithm. """ expr = self for _ in range(steps): expr = expr._inner_refine() return expr def refine(self): """Perform one step of real root refinement algorithm. """ return self._inner_refine() class ComplexInterval: """A fully qualified representation of a complex isolation interval. The printed form is shown as (ax, bx) x (ay, by) where (ax, ay) and (bx, by) are the coordinates of the southwest and northeast corners of the interval's rectangle, respectively. Examples ======== >>> from sympy import CRootOf, S >>> from sympy.abc import x >>> CRootOf.clear_cache() # for doctest reproducibility >>> root = CRootOf(x**10 - 2*x + 3, 9) >>> i = root._get_interval(); i (3/64, 3/32) x (9/8, 75/64) The real part of the root lies within the range [0, 3/4] while the imaginary part lies within the range [9/8, 3/2]: >>> root.n(3) 0.0766 + 1.14*I The width of the ranges in the x and y directions on the complex plane are: >>> i.dx, i.dy (3/64, 3/64) The center of the range is >>> i.center (9/128, 147/128) The northeast coordinate of the rectangle bounding the root in the complex plane is given by attribute b and the x and y components are accessed by bx and by: >>> i.b, i.bx, i.by ((3/32, 75/64), 3/32, 75/64) The southwest coordinate is similarly given by i.a >>> i.a, i.ax, i.ay ((3/64, 9/8), 3/64, 9/8) Although the interval prints to show only the real and imaginary range of the root, all the information of the underlying root is contained as properties of the interval. For example, an interval with a nonpositive imaginary range is considered to be the conjugate. Since the y values of y are in the range [0, 1/4] it is not the conjugate: >>> i.conj False The conjugate's interval is >>> ic = i.conjugate(); ic (3/64, 3/32) x (-75/64, -9/8) NOTE: the values printed still represent the x and y range in which the root -- conjugate, in this case -- is located, but the underlying a and b values of a root and its conjugate are the same: >>> assert i.a == ic.a and i.b == ic.b What changes are the reported coordinates of the bounding rectangle: >>> (i.ax, i.ay), (i.bx, i.by) ((3/64, 9/8), (3/32, 75/64)) >>> (ic.ax, ic.ay), (ic.bx, ic.by) ((3/64, -75/64), (3/32, -9/8)) The interval can be refined once: >>> i # for reference, this is the current interval (3/64, 3/32) x (9/8, 75/64) >>> i.refine() (3/64, 3/32) x (9/8, 147/128) Several refinement steps can be taken: >>> i.refine_step(2) # 2 steps (9/128, 3/32) x (9/8, 147/128) It is also possible to refine to a given tolerance: >>> tol = min(i.dx, i.dy)/2 >>> i.refine_size(tol) (9/128, 21/256) x (9/8, 291/256) A disjoint interval is one whose bounding rectangle does not overlap with another. An interval, necessarily, is not disjoint with itself, but any interval is disjoint with a conjugate since the conjugate rectangle will always be in the lower half of the complex plane and the non-conjugate in the upper half: >>> i.is_disjoint(i), i.is_disjoint(i.conjugate()) (False, True) The following interval j is not disjoint from i: >>> close = CRootOf(x**10 - 2*x + 300/S(101), 9) >>> j = close._get_interval(); j (75/1616, 75/808) x (225/202, 1875/1616) >>> i.is_disjoint(j) False The two can be made disjoint, however: >>> newi, newj = i.refine_disjoint(j) >>> newi (39/512, 159/2048) x (2325/2048, 4653/4096) >>> newj (3975/51712, 2025/25856) x (29325/25856, 117375/103424) Even though the real ranges overlap, the imaginary do not, so the roots have been resolved as distinct. Intervals are disjoint when either the real or imaginary component of the intervals is distinct. In the case above, the real components have not been resolved (so we don't know, yet, which root has the smaller real part) but the imaginary part of ``close`` is larger than ``root``: >>> close.n(3) 0.0771 + 1.13*I >>> root.n(3) 0.0766 + 1.14*I """ def __init__(self, a, b, I, Q, F1, F2, f1, f2, dom, conj=False): """Initialize new complex interval with complete information. """ # a and b are the SW and NE corner of the bounding interval, # (ax, ay) and (bx, by), respectively, for the NON-CONJUGATE # root (the one with the positive imaginary part); when working # with the conjugate, the a and b value are still non-negative # but the ay, by are reversed and have oppositite sign self.a, self.b = a, b self.I, self.Q = I, Q self.f1, self.F1 = f1, F1 self.f2, self.F2 = f2, F2 self.dom = dom self.conj = conj @property def func(self): return ComplexInterval @property def args(self): i = self return (i.a, i.b, i.I, i.Q, i.F1, i.F2, i.f1, i.f2, i.dom, i.conj) def __eq__(self, other): if type(other) != type(self): return False return self.args == other.args @property def ax(self): """Return ``x`` coordinate of south-western corner. """ return self.a[0] @property def ay(self): """Return ``y`` coordinate of south-western corner. """ if not self.conj: return self.a[1] else: return -self.b[1] @property def bx(self): """Return ``x`` coordinate of north-eastern corner. """ return self.b[0] @property def by(self): """Return ``y`` coordinate of north-eastern corner. """ if not self.conj: return self.b[1] else: return -self.a[1] @property def dx(self): """Return width of the complex isolating interval. """ return self.b[0] - self.a[0] @property def dy(self): """Return height of the complex isolating interval. """ return self.b[1] - self.a[1] @property def center(self): """Return the center of the complex isolating interval. """ return ((self.ax + self.bx)/2, (self.ay + self.by)/2) def as_tuple(self): """Return tuple representation of the complex isolating interval's SW and NE corners, respectively. """ return ((self.ax, self.ay), (self.bx, self.by)) def __repr__(self): return "(%s, %s) x (%s, %s)" % (self.ax, self.bx, self.ay, self.by) def conjugate(self): """This complex interval really is located in lower half-plane. """ return ComplexInterval(self.a, self.b, self.I, self.Q, self.F1, self.F2, self.f1, self.f2, self.dom, conj=True) def is_disjoint(self, other): """Return ``True`` if two isolation intervals are disjoint. """ if isinstance(other, RealInterval): return other.is_disjoint(self) if self.conj != other.conj: # above and below real axis return True re_distinct = (self.bx < other.ax or other.bx < self.ax) if re_distinct: return True im_distinct = (self.by < other.ay or other.by < self.ay) return im_distinct def _inner_refine(self): """Internal one step complex root refinement procedure. """ (u, v), (s, t) = self.a, self.b I, Q = self.I, self.Q f1, F1 = self.f1, self.F1 f2, F2 = self.f2, self.F2 dom = self.dom if s - u > t - v: D_L, D_R = _vertical_bisection(1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) if D_L[0] == 1: _, a, b, I, Q, F1, F2 = D_L else: _, a, b, I, Q, F1, F2 = D_R else: D_B, D_U = _horizontal_bisection(1, (u, v), (s, t), I, Q, F1, F2, f1, f2, dom) if D_B[0] == 1: _, a, b, I, Q, F1, F2 = D_B else: _, a, b, I, Q, F1, F2 = D_U return ComplexInterval(a, b, I, Q, F1, F2, f1, f2, dom, self.conj) def refine_disjoint(self, other): """Refine an isolating interval until it is disjoint with another one. """ expr = self while not expr.is_disjoint(other): expr, other = expr._inner_refine(), other._inner_refine() return expr, other def refine_size(self, dx, dy=None): """Refine an isolating interval until it is of sufficiently small size. """ if dy is None: dy = dx expr = self while not (expr.dx < dx and expr.dy < dy): expr = expr._inner_refine() return expr def refine_step(self, steps=1): """Perform several steps of complex root refinement algorithm. """ expr = self for _ in range(steps): expr = expr._inner_refine() return expr def refine(self): """Perform one step of complex root refinement algorithm. """ return self._inner_refine() sympy-sympy-1.9/sympy/polys/rootoftools.py000066400000000000000000001155701412543434000212260ustar00rootroot00000000000000"""Implementation of RootOf class and related tools. """ from sympy import Basic from sympy.core import (S, Expr, Integer, Float, I, oo, Add, Lambda, symbols, sympify, Rational, Dummy) from sympy.core.cache import cacheit from sympy.core.compatibility import ordered from sympy.core.relational import is_le from sympy.polys.domains import QQ from sympy.polys.polyerrors import ( MultivariatePolynomialError, GeneratorsNeeded, PolynomialError, DomainError) from sympy.polys.polyfuncs import symmetrize, viete from sympy.polys.polyroots import ( roots_linear, roots_quadratic, roots_binomial, preprocess_roots, roots) from sympy.polys.polytools import Poly, PurePoly, factor from sympy.polys.rationaltools import together from sympy.polys.rootisolation import ( dup_isolate_complex_roots_sqf, dup_isolate_real_roots_sqf) from sympy.utilities import lambdify, public, sift, numbered_symbols from mpmath import mpf, mpc, findroot, workprec from mpmath.libmp.libmpf import dps_to_prec, prec_to_dps from sympy.multipledispatch import dispatch from itertools import chain __all__ = ['CRootOf'] class _pure_key_dict: """A minimal dictionary that makes sure that the key is a univariate PurePoly instance. Examples ======== Only the following actions are guaranteed: >>> from sympy.polys.rootoftools import _pure_key_dict >>> from sympy import PurePoly >>> from sympy.abc import x, y 1) creation >>> P = _pure_key_dict() 2) assignment for a PurePoly or univariate polynomial >>> P[x] = 1 >>> P[PurePoly(x - y, x)] = 2 3) retrieval based on PurePoly key comparison (use this instead of the get method) >>> P[y] 1 4) KeyError when trying to retrieve a nonexisting key >>> P[y + 1] Traceback (most recent call last): ... KeyError: PurePoly(y + 1, y, domain='ZZ') 5) ability to query with ``in`` >>> x + 1 in P False NOTE: this is a *not* a dictionary. It is a very basic object for internal use that makes sure to always address its cache via PurePoly instances. It does not, for example, implement ``get`` or ``setdefault``. """ def __init__(self): self._dict = {} def __getitem__(self, k): if not isinstance(k, PurePoly): if not (isinstance(k, Expr) and len(k.free_symbols) == 1): raise KeyError k = PurePoly(k, expand=False) return self._dict[k] def __setitem__(self, k, v): if not isinstance(k, PurePoly): if not (isinstance(k, Expr) and len(k.free_symbols) == 1): raise ValueError('expecting univariate expression') k = PurePoly(k, expand=False) self._dict[k] = v def __contains__(self, k): try: self[k] return True except KeyError: return False _reals_cache = _pure_key_dict() _complexes_cache = _pure_key_dict() def _pure_factors(poly): _, factors = poly.factor_list() return [(PurePoly(f, expand=False), m) for f, m in factors] def _imag_count_of_factor(f): """Return the number of imaginary roots for irreducible univariate polynomial ``f``. """ terms = [(i, j) for (i,), j in f.terms()] if any(i % 2 for i, j in terms): return 0 # update signs even = [(i, I**i*j) for i, j in terms] even = Poly.from_dict(dict(even), Dummy('x')) return int(even.count_roots(-oo, oo)) @public def rootof(f, x, index=None, radicals=True, expand=True): """An indexed root of a univariate polynomial. Returns either a :obj:`ComplexRootOf` object or an explicit expression involving radicals. Parameters ========== f : Expr Univariate polynomial. x : Symbol, optional Generator for ``f``. index : int or Integer radicals : bool Return a radical expression if possible. expand : bool Expand ``f``. """ return CRootOf(f, x, index=index, radicals=radicals, expand=expand) @public class RootOf(Expr): """Represents a root of a univariate polynomial. Base class for roots of different kinds of polynomials. Only complex roots are currently supported. """ __slots__ = ('poly',) def __new__(cls, f, x, index=None, radicals=True, expand=True): """Construct a new ``CRootOf`` object for ``k``-th root of ``f``.""" return rootof(f, x, index=index, radicals=radicals, expand=expand) @public class ComplexRootOf(RootOf): """Represents an indexed complex root of a polynomial. Roots of a univariate polynomial separated into disjoint real or complex intervals and indexed in a fixed order. Currently only rational coefficients are allowed. Can be imported as ``CRootOf``. To avoid confusion, the generator must be a Symbol. Examples ======== >>> from sympy import CRootOf, rootof >>> from sympy.abc import x CRootOf is a way to reference a particular root of a polynomial. If there is a rational root, it will be returned: >>> CRootOf.clear_cache() # for doctest reproducibility >>> CRootOf(x**2 - 4, 0) -2 Whether roots involving radicals are returned or not depends on whether the ``radicals`` flag is true (which is set to True with rootof): >>> CRootOf(x**2 - 3, 0) CRootOf(x**2 - 3, 0) >>> CRootOf(x**2 - 3, 0, radicals=True) -sqrt(3) >>> rootof(x**2 - 3, 0) -sqrt(3) The following cannot be expressed in terms of radicals: >>> r = rootof(4*x**5 + 16*x**3 + 12*x**2 + 7, 0); r CRootOf(4*x**5 + 16*x**3 + 12*x**2 + 7, 0) The root bounds can be seen, however, and they are used by the evaluation methods to get numerical approximations for the root. >>> interval = r._get_interval(); interval (-1, 0) >>> r.evalf(2) -0.98 The evalf method refines the width of the root bounds until it guarantees that any decimal approximation within those bounds will satisfy the desired precision. It then stores the refined interval so subsequent requests at or below the requested precision will not have to recompute the root bounds and will return very quickly. Before evaluation above, the interval was >>> interval (-1, 0) After evaluation it is now >>> r._get_interval() # doctest: +SKIP (-165/169, -206/211) To reset all intervals for a given polynomial, the :meth:`_reset` method can be called from any CRootOf instance of the polynomial: >>> r._reset() >>> r._get_interval() (-1, 0) The :meth:`eval_approx` method will also find the root to a given precision but the interval is not modified unless the search for the root fails to converge within the root bounds. And the secant method is used to find the root. (The ``evalf`` method uses bisection and will always update the interval.) >>> r.eval_approx(2) -0.98 The interval needed to be slightly updated to find that root: >>> r._get_interval() (-1, -1/2) The ``evalf_rational`` will compute a rational approximation of the root to the desired accuracy or precision. >>> r.eval_rational(n=2) -69629/71318 >>> t = CRootOf(x**3 + 10*x + 1, 1) >>> t.eval_rational(1e-1) 15/256 - 805*I/256 >>> t.eval_rational(1e-1, 1e-4) 3275/65536 - 414645*I/131072 >>> t.eval_rational(1e-4, 1e-4) 6545/131072 - 414645*I/131072 >>> t.eval_rational(n=2) 104755/2097152 - 6634255*I/2097152 Notes ===== Although a PurePoly can be constructed from a non-symbol generator RootOf instances of non-symbols are disallowed to avoid confusion over what root is being represented. >>> from sympy import exp, PurePoly >>> PurePoly(x) == PurePoly(exp(x)) True >>> CRootOf(x - 1, 0) 1 >>> CRootOf(exp(x) - 1, 0) # would correspond to x == 0 Traceback (most recent call last): ... sympy.polys.polyerrors.PolynomialError: generator must be a Symbol See Also ======== eval_approx eval_rational """ __slots__ = ('index',) is_complex = True is_number = True is_finite = True def __new__(cls, f, x, index=None, radicals=False, expand=True): """ Construct an indexed complex root of a polynomial. See ``rootof`` for the parameters. The default value of ``radicals`` is ``False`` to satisfy ``eval(srepr(expr) == expr``. """ x = sympify(x) if index is None and x.is_Integer: x, index = None, x else: index = sympify(index) if index is not None and index.is_Integer: index = int(index) else: raise ValueError("expected an integer root index, got %s" % index) poly = PurePoly(f, x, greedy=False, expand=expand) if not poly.is_univariate: raise PolynomialError("only univariate polynomials are allowed") if not poly.gen.is_Symbol: # PurePoly(sin(x) + 1) == PurePoly(x + 1) but the roots of # x for each are not the same: issue 8617 raise PolynomialError("generator must be a Symbol") degree = poly.degree() if degree <= 0: raise PolynomialError("can't construct CRootOf object for %s" % f) if index < -degree or index >= degree: raise IndexError("root index out of [%d, %d] range, got %d" % (-degree, degree - 1, index)) elif index < 0: index += degree dom = poly.get_domain() if not dom.is_Exact: poly = poly.to_exact() roots = cls._roots_trivial(poly, radicals) if roots is not None: return roots[index] coeff, poly = preprocess_roots(poly) dom = poly.get_domain() if not dom.is_ZZ: raise NotImplementedError("CRootOf is not supported over %s" % dom) root = cls._indexed_root(poly, index) return coeff * cls._postprocess_root(root, radicals) @classmethod def _new(cls, poly, index): """Construct new ``CRootOf`` object from raw data. """ obj = Expr.__new__(cls) obj.poly = PurePoly(poly) obj.index = index try: _reals_cache[obj.poly] = _reals_cache[poly] _complexes_cache[obj.poly] = _complexes_cache[poly] except KeyError: pass return obj def _hashable_content(self): return (self.poly, self.index) @property def expr(self): return self.poly.as_expr() @property def args(self): return (self.expr, Integer(self.index)) @property def free_symbols(self): # CRootOf currently only works with univariate expressions # whose poly attribute should be a PurePoly with no free # symbols return set() def _eval_is_real(self): """Return ``True`` if the root is real. """ return self.index < len(_reals_cache[self.poly]) def _eval_is_imaginary(self): """Return ``True`` if the root is imaginary. """ if self.index >= len(_reals_cache[self.poly]): ivl = self._get_interval() return ivl.ax*ivl.bx <= 0 # all others are on one side or the other return False # XXX is this necessary? @classmethod def real_roots(cls, poly, radicals=True): """Get real roots of a polynomial. """ return cls._get_roots("_real_roots", poly, radicals) @classmethod def all_roots(cls, poly, radicals=True): """Get real and complex roots of a polynomial. """ return cls._get_roots("_all_roots", poly, radicals) @classmethod def _get_reals_sqf(cls, currentfactor, use_cache=True): """Get real root isolating intervals for a square-free factor.""" if use_cache and currentfactor in _reals_cache: real_part = _reals_cache[currentfactor] else: _reals_cache[currentfactor] = real_part = \ dup_isolate_real_roots_sqf( currentfactor.rep.rep, currentfactor.rep.dom, blackbox=True) return real_part @classmethod def _get_complexes_sqf(cls, currentfactor, use_cache=True): """Get complex root isolating intervals for a square-free factor.""" if use_cache and currentfactor in _complexes_cache: complex_part = _complexes_cache[currentfactor] else: _complexes_cache[currentfactor] = complex_part = \ dup_isolate_complex_roots_sqf( currentfactor.rep.rep, currentfactor.rep.dom, blackbox=True) return complex_part @classmethod def _get_reals(cls, factors, use_cache=True): """Compute real root isolating intervals for a list of factors. """ reals = [] for currentfactor, k in factors: try: if not use_cache: raise KeyError r = _reals_cache[currentfactor] reals.extend([(i, currentfactor, k) for i in r]) except KeyError: real_part = cls._get_reals_sqf(currentfactor, use_cache) new = [(root, currentfactor, k) for root in real_part] reals.extend(new) reals = cls._reals_sorted(reals) return reals @classmethod def _get_complexes(cls, factors, use_cache=True): """Compute complex root isolating intervals for a list of factors. """ complexes = [] for currentfactor, k in ordered(factors): try: if not use_cache: raise KeyError c = _complexes_cache[currentfactor] complexes.extend([(i, currentfactor, k) for i in c]) except KeyError: complex_part = cls._get_complexes_sqf(currentfactor, use_cache) new = [(root, currentfactor, k) for root in complex_part] complexes.extend(new) complexes = cls._complexes_sorted(complexes) return complexes @classmethod def _reals_sorted(cls, reals): """Make real isolating intervals disjoint and sort roots. """ cache = {} for i, (u, f, k) in enumerate(reals): for j, (v, g, m) in enumerate(reals[i + 1:]): u, v = u.refine_disjoint(v) reals[i + j + 1] = (v, g, m) reals[i] = (u, f, k) reals = sorted(reals, key=lambda r: r[0].a) for root, currentfactor, _ in reals: if currentfactor in cache: cache[currentfactor].append(root) else: cache[currentfactor] = [root] for currentfactor, root in cache.items(): _reals_cache[currentfactor] = root return reals @classmethod def _refine_imaginary(cls, complexes): sifted = sift(complexes, lambda c: c[1]) complexes = [] for f in ordered(sifted): nimag = _imag_count_of_factor(f) if nimag == 0: # refine until xbounds are neg or pos for u, f, k in sifted[f]: while u.ax*u.bx <= 0: u = u._inner_refine() complexes.append((u, f, k)) else: # refine until all but nimag xbounds are neg or pos potential_imag = list(range(len(sifted[f]))) while True: assert len(potential_imag) > 1 for i in list(potential_imag): u, f, k = sifted[f][i] if u.ax*u.bx > 0: potential_imag.remove(i) elif u.ax != u.bx: u = u._inner_refine() sifted[f][i] = u, f, k if len(potential_imag) == nimag: break complexes.extend(sifted[f]) return complexes @classmethod def _refine_complexes(cls, complexes): """return complexes such that no bounding rectangles of non-conjugate roots would intersect. In addition, assure that neither ay nor by is 0 to guarantee that non-real roots are distinct from real roots in terms of the y-bounds. """ # get the intervals pairwise-disjoint. # If rectangles were drawn around the coordinates of the bounding # rectangles, no rectangles would intersect after this procedure. for i, (u, f, k) in enumerate(complexes): for j, (v, g, m) in enumerate(complexes[i + 1:]): u, v = u.refine_disjoint(v) complexes[i + j + 1] = (v, g, m) complexes[i] = (u, f, k) # refine until the x-bounds are unambiguously positive or negative # for non-imaginary roots complexes = cls._refine_imaginary(complexes) # make sure that all y bounds are off the real axis # and on the same side of the axis for i, (u, f, k) in enumerate(complexes): while u.ay*u.by <= 0: u = u.refine() complexes[i] = u, f, k return complexes @classmethod def _complexes_sorted(cls, complexes): """Make complex isolating intervals disjoint and sort roots. """ complexes = cls._refine_complexes(complexes) # XXX don't sort until you are sure that it is compatible # with the indexing method but assert that the desired state # is not broken C, F = 0, 1 # location of ComplexInterval and factor fs = {i[F] for i in complexes} for i in range(1, len(complexes)): if complexes[i][F] != complexes[i - 1][F]: # if this fails the factors of a root were not # contiguous because a discontinuity should only # happen once fs.remove(complexes[i - 1][F]) for i in range(len(complexes)): # negative im part (conj=True) comes before # positive im part (conj=False) assert complexes[i][C].conj is (i % 2 == 0) # update cache cache = {} # -- collate for root, currentfactor, _ in complexes: cache.setdefault(currentfactor, []).append(root) # -- store for currentfactor, root in cache.items(): _complexes_cache[currentfactor] = root return complexes @classmethod def _reals_index(cls, reals, index): """ Map initial real root index to an index in a factor where the root belongs. """ i = 0 for j, (_, currentfactor, k) in enumerate(reals): if index < i + k: poly, index = currentfactor, 0 for _, currentfactor, _ in reals[:j]: if currentfactor == poly: index += 1 return poly, index else: i += k @classmethod def _complexes_index(cls, complexes, index): """ Map initial complex root index to an index in a factor where the root belongs. """ i = 0 for j, (_, currentfactor, k) in enumerate(complexes): if index < i + k: poly, index = currentfactor, 0 for _, currentfactor, _ in complexes[:j]: if currentfactor == poly: index += 1 index += len(_reals_cache[poly]) return poly, index else: i += k @classmethod def _count_roots(cls, roots): """Count the number of real or complex roots with multiplicities.""" return sum([k for _, _, k in roots]) @classmethod def _indexed_root(cls, poly, index): """Get a root of a composite polynomial by index. """ factors = _pure_factors(poly) reals = cls._get_reals(factors) reals_count = cls._count_roots(reals) if index < reals_count: return cls._reals_index(reals, index) else: complexes = cls._get_complexes(factors) return cls._complexes_index(complexes, index - reals_count) @classmethod def _real_roots(cls, poly): """Get real roots of a composite polynomial. """ factors = _pure_factors(poly) reals = cls._get_reals(factors) reals_count = cls._count_roots(reals) roots = [] for index in range(0, reals_count): roots.append(cls._reals_index(reals, index)) return roots def _reset(self): """ Reset all intervals """ self._all_roots(self.poly, use_cache=False) @classmethod def _all_roots(cls, poly, use_cache=True): """Get real and complex roots of a composite polynomial. """ factors = _pure_factors(poly) reals = cls._get_reals(factors, use_cache=use_cache) reals_count = cls._count_roots(reals) roots = [] for index in range(0, reals_count): roots.append(cls._reals_index(reals, index)) complexes = cls._get_complexes(factors, use_cache=use_cache) complexes_count = cls._count_roots(complexes) for index in range(0, complexes_count): roots.append(cls._complexes_index(complexes, index)) return roots @classmethod @cacheit def _roots_trivial(cls, poly, radicals): """Compute roots in linear, quadratic and binomial cases. """ if poly.degree() == 1: return roots_linear(poly) if not radicals: return None if poly.degree() == 2: return roots_quadratic(poly) elif poly.length() == 2 and poly.TC(): return roots_binomial(poly) else: return None @classmethod def _preprocess_roots(cls, poly): """Take heroic measures to make ``poly`` compatible with ``CRootOf``.""" dom = poly.get_domain() if not dom.is_Exact: poly = poly.to_exact() coeff, poly = preprocess_roots(poly) dom = poly.get_domain() if not dom.is_ZZ: raise NotImplementedError( "sorted roots not supported over %s" % dom) return coeff, poly @classmethod def _postprocess_root(cls, root, radicals): """Return the root if it is trivial or a ``CRootOf`` object. """ poly, index = root roots = cls._roots_trivial(poly, radicals) if roots is not None: return roots[index] else: return cls._new(poly, index) @classmethod def _get_roots(cls, method, poly, radicals): """Return postprocessed roots of specified kind. """ if not poly.is_univariate: raise PolynomialError("only univariate polynomials are allowed") # get rid of gen and it's free symbol d = Dummy() poly = poly.subs(poly.gen, d) x = symbols('x') # see what others are left and select x or a numbered x # that doesn't clash free_names = {str(i) for i in poly.free_symbols} for x in chain((symbols('x'),), numbered_symbols('x')): if x.name not in free_names: poly = poly.xreplace({d: x}) break coeff, poly = cls._preprocess_roots(poly) roots = [] for root in getattr(cls, method)(poly): roots.append(coeff*cls._postprocess_root(root, radicals)) return roots @classmethod def clear_cache(cls): """Reset cache for reals and complexes. The intervals used to approximate a root instance are updated as needed. When a request is made to see the intervals, the most current values are shown. `clear_cache` will reset all CRootOf instances back to their original state. See Also ======== _reset """ global _reals_cache, _complexes_cache _reals_cache = _pure_key_dict() _complexes_cache = _pure_key_dict() def _get_interval(self): """Internal function for retrieving isolation interval from cache. """ if self.is_real: return _reals_cache[self.poly][self.index] else: reals_count = len(_reals_cache[self.poly]) return _complexes_cache[self.poly][self.index - reals_count] def _set_interval(self, interval): """Internal function for updating isolation interval in cache. """ if self.is_real: _reals_cache[self.poly][self.index] = interval else: reals_count = len(_reals_cache[self.poly]) _complexes_cache[self.poly][self.index - reals_count] = interval def _eval_subs(self, old, new): # don't allow subs to change anything return self def _eval_conjugate(self): if self.is_real: return self expr, i = self.args return self.func(expr, i + (1 if self._get_interval().conj else -1)) def eval_approx(self, n): """Evaluate this complex root to the given precision. This uses secant method and root bounds are used to both generate an initial guess and to check that the root returned is valid. If ever the method converges outside the root bounds, the bounds will be made smaller and updated. """ prec = dps_to_prec(n) with workprec(prec): g = self.poly.gen if not g.is_Symbol: d = Dummy('x') if self.is_imaginary: d *= I func = lambdify(d, self.expr.subs(g, d)) else: expr = self.expr if self.is_imaginary: expr = self.expr.subs(g, I*g) func = lambdify(g, expr) interval = self._get_interval() while True: if self.is_real: a = mpf(str(interval.a)) b = mpf(str(interval.b)) if a == b: root = a break x0 = mpf(str(interval.center)) x1 = x0 + mpf(str(interval.dx))/4 elif self.is_imaginary: a = mpf(str(interval.ay)) b = mpf(str(interval.by)) if a == b: root = mpc(mpf('0'), a) break x0 = mpf(str(interval.center[1])) x1 = x0 + mpf(str(interval.dy))/4 else: ax = mpf(str(interval.ax)) bx = mpf(str(interval.bx)) ay = mpf(str(interval.ay)) by = mpf(str(interval.by)) if ax == bx and ay == by: root = mpc(ax, ay) break x0 = mpc(*map(str, interval.center)) x1 = x0 + mpc(*map(str, (interval.dx, interval.dy)))/4 try: # without a tolerance, this will return when (to within # the given precision) x_i == x_{i-1} root = findroot(func, (x0, x1)) # If the (real or complex) root is not in the 'interval', # then keep refining the interval. This happens if findroot # accidentally finds a different root outside of this # interval because our initial estimate 'x0' was not close # enough. It is also possible that the secant method will # get trapped by a max/min in the interval; the root # verification by findroot will raise a ValueError in this # case and the interval will then be tightened -- and # eventually the root will be found. # # It is also possible that findroot will not have any # successful iterations to process (in which case it # will fail to initialize a variable that is tested # after the iterations and raise an UnboundLocalError). if self.is_real or self.is_imaginary: if not bool(root.imag) == self.is_real and ( a <= root <= b): if self.is_imaginary: root = mpc(mpf('0'), root.real) break elif (ax <= root.real <= bx and ay <= root.imag <= by): break except (UnboundLocalError, ValueError): pass interval = interval.refine() # update the interval so we at least (for this precision or # less) don't have much work to do to recompute the root self._set_interval(interval) return (Float._new(root.real._mpf_, prec) + I*Float._new(root.imag._mpf_, prec)) def _eval_evalf(self, prec, **kwargs): """Evaluate this complex root to the given precision.""" # all kwargs are ignored return self.eval_rational(n=prec_to_dps(prec))._evalf(prec) def eval_rational(self, dx=None, dy=None, n=15): """ Return a Rational approximation of ``self`` that has real and imaginary component approximations that are within ``dx`` and ``dy`` of the true values, respectively. Alternatively, ``n`` digits of precision can be specified. The interval is refined with bisection and is sure to converge. The root bounds are updated when the refinement is complete so recalculation at the same or lesser precision will not have to repeat the refinement and should be much faster. The following example first obtains Rational approximation to 1e-8 accuracy for all roots of the 4-th order Legendre polynomial. Since the roots are all less than 1, this will ensure the decimal representation of the approximation will be correct (including rounding) to 6 digits: >>> from sympy import legendre_poly, Symbol >>> x = Symbol("x") >>> p = legendre_poly(4, x, polys=True) >>> r = p.real_roots()[-1] >>> r.eval_rational(10**-8).n(6) 0.861136 It is not necessary to a two-step calculation, however: the decimal representation can be computed directly: >>> r.evalf(17) 0.86113631159405258 """ dy = dy or dx if dx: rtol = None dx = dx if isinstance(dx, Rational) else Rational(str(dx)) dy = dy if isinstance(dy, Rational) else Rational(str(dy)) else: # 5 binary (or 2 decimal) digits are needed to ensure that # a given digit is correctly rounded # prec_to_dps(dps_to_prec(n) + 5) - n <= 2 (tested for # n in range(1000000) rtol = S(10)**-(n + 2) # +2 for guard digits interval = self._get_interval() while True: if self.is_real: if rtol: dx = abs(interval.center*rtol) interval = interval.refine_size(dx=dx) c = interval.center real = Rational(c) imag = S.Zero if not rtol or interval.dx < abs(c*rtol): break elif self.is_imaginary: if rtol: dy = abs(interval.center[1]*rtol) dx = 1 interval = interval.refine_size(dx=dx, dy=dy) c = interval.center[1] imag = Rational(c) real = S.Zero if not rtol or interval.dy < abs(c*rtol): break else: if rtol: dx = abs(interval.center[0]*rtol) dy = abs(interval.center[1]*rtol) interval = interval.refine_size(dx, dy) c = interval.center real, imag = map(Rational, c) if not rtol or ( interval.dx < abs(c[0]*rtol) and interval.dy < abs(c[1]*rtol)): break # update the interval so we at least (for this precision or # less) don't have much work to do to recompute the root self._set_interval(interval) return real + I*imag CRootOf = ComplexRootOf @dispatch(ComplexRootOf, ComplexRootOf) def _eval_is_eq(lhs, rhs): # noqa:F811 # if we use is_eq to check here, we get infinite recurion return lhs == rhs @dispatch(ComplexRootOf, Basic) # type:ignore def _eval_is_eq(lhs, rhs): # noqa:F811 # CRootOf represents a Root, so if rhs is that root, it should set # the expression to zero *and* it should be in the interval of the # CRootOf instance. It must also be a number that agrees with the # is_real value of the CRootOf instance. if not rhs.is_number: return None if not rhs.is_finite: return False z = lhs.expr.subs(lhs.expr.free_symbols.pop(), rhs).is_zero if z is False: # all roots will make z True but we don't know # whether this is the right root if z is True return False o = rhs.is_real, rhs.is_imaginary s = lhs.is_real, lhs.is_imaginary assert None not in s # this is part of initial refinement if o != s and None not in o: return False re, im = rhs.as_real_imag() if lhs.is_real: if im: return False i = lhs._get_interval() a, b = [Rational(str(_)) for _ in (i.a, i.b)] return sympify(a <= rhs and rhs <= b) i = lhs._get_interval() r1, r2, i1, i2 = [Rational(str(j)) for j in ( i.ax, i.bx, i.ay, i.by)] return is_le(r1, re) and is_le(re,r2) and is_le(i1,im) and is_le(im,i2) @public class RootSum(Expr): """Represents a sum of all roots of a univariate polynomial. """ __slots__ = ('poly', 'fun', 'auto') def __new__(cls, expr, func=None, x=None, auto=True, quadratic=False): """Construct a new ``RootSum`` instance of roots of a polynomial.""" coeff, poly = cls._transform(expr, x) if not poly.is_univariate: raise MultivariatePolynomialError( "only univariate polynomials are allowed") if func is None: func = Lambda(poly.gen, poly.gen) else: is_func = getattr(func, 'is_Function', False) if is_func and 1 in func.nargs: if not isinstance(func, Lambda): func = Lambda(poly.gen, func(poly.gen)) else: raise ValueError( "expected a univariate function, got %s" % func) var, expr = func.variables[0], func.expr if coeff is not S.One: expr = expr.subs(var, coeff*var) deg = poly.degree() if not expr.has(var): return deg*expr if expr.is_Add: add_const, expr = expr.as_independent(var) else: add_const = S.Zero if expr.is_Mul: mul_const, expr = expr.as_independent(var) else: mul_const = S.One func = Lambda(var, expr) rational = cls._is_func_rational(poly, func) factors, terms = _pure_factors(poly), [] for poly, k in factors: if poly.is_linear: term = func(roots_linear(poly)[0]) elif quadratic and poly.is_quadratic: term = sum(map(func, roots_quadratic(poly))) else: if not rational or not auto: term = cls._new(poly, func, auto) else: term = cls._rational_case(poly, func) terms.append(k*term) return mul_const*Add(*terms) + deg*add_const @classmethod def _new(cls, poly, func, auto=True): """Construct new raw ``RootSum`` instance. """ obj = Expr.__new__(cls) obj.poly = poly obj.fun = func obj.auto = auto return obj @classmethod def new(cls, poly, func, auto=True): """Construct new ``RootSum`` instance. """ if not func.expr.has(*func.variables): return func.expr rational = cls._is_func_rational(poly, func) if not rational or not auto: return cls._new(poly, func, auto) else: return cls._rational_case(poly, func) @classmethod def _transform(cls, expr, x): """Transform an expression to a polynomial. """ poly = PurePoly(expr, x, greedy=False) return preprocess_roots(poly) @classmethod def _is_func_rational(cls, poly, func): """Check if a lambda is a rational function. """ var, expr = func.variables[0], func.expr return expr.is_rational_function(var) @classmethod def _rational_case(cls, poly, func): """Handle the rational function case. """ roots = symbols('r:%d' % poly.degree()) var, expr = func.variables[0], func.expr f = sum(expr.subs(var, r) for r in roots) p, q = together(f).as_numer_denom() domain = QQ[roots] p = p.expand() q = q.expand() try: p = Poly(p, domain=domain, expand=False) except GeneratorsNeeded: p, p_coeff = None, (p,) else: p_monom, p_coeff = zip(*p.terms()) try: q = Poly(q, domain=domain, expand=False) except GeneratorsNeeded: q, q_coeff = None, (q,) else: q_monom, q_coeff = zip(*q.terms()) coeffs, mapping = symmetrize(p_coeff + q_coeff, formal=True) formulas, values = viete(poly, roots), [] for (sym, _), (_, val) in zip(mapping, formulas): values.append((sym, val)) for i, (coeff, _) in enumerate(coeffs): coeffs[i] = coeff.subs(values) n = len(p_coeff) p_coeff = coeffs[:n] q_coeff = coeffs[n:] if p is not None: p = Poly(dict(zip(p_monom, p_coeff)), *p.gens).as_expr() else: (p,) = p_coeff if q is not None: q = Poly(dict(zip(q_monom, q_coeff)), *q.gens).as_expr() else: (q,) = q_coeff return factor(p/q) def _hashable_content(self): return (self.poly, self.fun) @property def expr(self): return self.poly.as_expr() @property def args(self): return (self.expr, self.fun, self.poly.gen) @property def free_symbols(self): return self.poly.free_symbols | self.fun.free_symbols @property def is_commutative(self): return True def doit(self, **hints): if not hints.get('roots', True): return self _roots = roots(self.poly, multiple=True) if len(_roots) < self.poly.degree(): return self else: return Add(*[self.fun(r) for r in _roots]) def _eval_evalf(self, prec): try: _roots = self.poly.nroots(n=prec_to_dps(prec)) except (DomainError, PolynomialError): return self else: return Add(*[self.fun(r) for r in _roots]) def _eval_derivative(self, x): var, expr = self.fun.args func = Lambda(var, expr.diff(x)) return self.new(self.poly, func, self.auto) sympy-sympy-1.9/sympy/polys/solvers.py000066400000000000000000000320421412543434000203220ustar00rootroot00000000000000"""Low-level linear systems solver. """ from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.iterables import connected_components from sympy.core.sympify import sympify from sympy.core.numbers import Integer, Rational from sympy.matrices.dense import MutableDenseMatrix from sympy.polys.domains import ZZ, QQ from sympy.polys.domains import EX from sympy.polys.rings import sring from sympy.polys.polyerrors import NotInvertible from sympy.polys.domainmatrix import DomainMatrix class PolyNonlinearError(Exception): """Raised by solve_lin_sys for nonlinear equations""" pass class RawMatrix(MutableDenseMatrix): """ XXX: This class is broken by design. Use DomainMatrix if you want a matrix over the polys domains or Matrix for a matrix with Expr elements. The RawMatrix class will be removed/broken in future in order to reestablish the invariant that the elements of a Matrix should be of type Expr. """ _sympify = staticmethod(lambda x: x) def __init__(self, *args, **kwargs): SymPyDeprecationWarning( feature="RawMatrix class", useinstead="DomainMatrix or Matrix", issue=21405, deprecated_since_version="1.9" ).warn() domain = ZZ for i in range(self.rows): for j in range(self.cols): val = self[i,j] if getattr(val, 'is_Poly', False): K = val.domain[val.gens] val_sympy = val.as_expr() elif hasattr(val, 'parent'): K = val.parent() val_sympy = K.to_sympy(val) elif isinstance(val, (int, Integer)): K = ZZ val_sympy = sympify(val) elif isinstance(val, Rational): K = QQ val_sympy = val else: for K in ZZ, QQ: if K.of_type(val): val_sympy = K.to_sympy(val) break else: raise TypeError domain = domain.unify(K) self[i,j] = val_sympy self.ring = domain def eqs_to_matrix(eqs_coeffs, eqs_rhs, gens, domain): """Get matrix from linear equations in dict format. Explanation =========== Get the matrix representation of a system of linear equations represented as dicts with low-level DomainElement coefficients. This is an *internal* function that is used by solve_lin_sys. Parameters ========== eqs_coeffs: list[dict[Symbol, DomainElement]] The left hand sides of the equations as dicts mapping from symbols to coefficients where the coefficients are instances of DomainElement. eqs_rhs: list[DomainElements] The right hand sides of the equations as instances of DomainElement. gens: list[Symbol] The unknowns in the system of equations. domain: Domain The domain for coefficients of both lhs and rhs. Returns ======= The augmented matrix representation of the system as a DomainMatrix. Examples ======== >>> from sympy import symbols, ZZ >>> from sympy.polys.solvers import eqs_to_matrix >>> x, y = symbols('x, y') >>> eqs_coeff = [{x:ZZ(1), y:ZZ(1)}, {x:ZZ(1), y:ZZ(-1)}] >>> eqs_rhs = [ZZ(0), ZZ(-1)] >>> eqs_to_matrix(eqs_coeff, eqs_rhs, [x, y], ZZ) DomainMatrix([[1, 1, 0], [1, -1, 1]], (2, 3), ZZ) See also ======== solve_lin_sys: Uses :func:`~eqs_to_matrix` internally """ sym2index = {x: n for n, x in enumerate(gens)} nrows = len(eqs_coeffs) ncols = len(gens) + 1 rows = [[domain.zero] * ncols for _ in range(nrows)] for row, eq_coeff, eq_rhs in zip(rows, eqs_coeffs, eqs_rhs): for sym, coeff in eq_coeff.items(): row[sym2index[sym]] = domain.convert(coeff) row[-1] = -domain.convert(eq_rhs) return DomainMatrix(rows, (nrows, ncols), domain) def sympy_eqs_to_ring(eqs, symbols): """Convert a system of equations from Expr to a PolyRing Explanation =========== High-level functions like ``solve`` expect Expr as inputs but can use ``solve_lin_sys`` internally. This function converts equations from ``Expr`` to the low-level poly types used by the ``solve_lin_sys`` function. Parameters ========== eqs: List of Expr A list of equations as Expr instances symbols: List of Symbol A list of the symbols that are the unknowns in the system of equations. Returns ======= Tuple[List[PolyElement], Ring]: The equations as PolyElement instances and the ring of polynomials within which each equation is represented. Examples ======== >>> from sympy import symbols >>> from sympy.polys.solvers import sympy_eqs_to_ring >>> a, x, y = symbols('a, x, y') >>> eqs = [x-y, x+a*y] >>> eqs_ring, ring = sympy_eqs_to_ring(eqs, [x, y]) >>> eqs_ring [x - y, x + a*y] >>> type(eqs_ring[0]) >>> ring ZZ(a)[x,y] With the equations in this form they can be passed to ``solve_lin_sys``: >>> from sympy.polys.solvers import solve_lin_sys >>> solve_lin_sys(eqs_ring, ring) {y: 0, x: 0} """ try: K, eqs_K = sring(eqs, symbols, field=True, extension=True) except NotInvertible: # https://github.com/sympy/sympy/issues/18874 K, eqs_K = sring(eqs, symbols, domain=EX) return eqs_K, K.to_domain() def solve_lin_sys(eqs, ring, _raw=True): """Solve a system of linear equations from a PolynomialRing Explanation =========== Solves a system of linear equations given as PolyElement instances of a PolynomialRing. The basic arithmetic is carried out using instance of DomainElement which is more efficient than :class:`~sympy.core.expr.Expr` for the most common inputs. While this is a public function it is intended primarily for internal use so its interface is not necessarily convenient. Users are suggested to use the :func:`sympy.solvers.solveset.linsolve` function (which uses this function internally) instead. Parameters ========== eqs: list[PolyElement] The linear equations to be solved as elements of a PolynomialRing (assumed equal to zero). ring: PolynomialRing The polynomial ring from which eqs are drawn. The generators of this ring are the unkowns to be solved for and the domain of the ring is the domain of the coefficients of the system of equations. _raw: bool If *_raw* is False, the keys and values in the returned dictionary will be of type Expr (and the unit of the field will be removed from the keys) otherwise the low-level polys types will be returned, e.g. PolyElement: PythonRational. Returns ======= ``None`` if the system has no solution. dict[Symbol, Expr] if _raw=False dict[Symbol, DomainElement] if _raw=True. Examples ======== >>> from sympy import symbols >>> from sympy.polys.solvers import solve_lin_sys, sympy_eqs_to_ring >>> x, y = symbols('x, y') >>> eqs = [x - y, x + y - 2] >>> eqs_ring, ring = sympy_eqs_to_ring(eqs, [x, y]) >>> solve_lin_sys(eqs_ring, ring) {y: 1, x: 1} Passing ``_raw=False`` returns the same result except that the keys are ``Expr`` rather than low-level poly types. >>> solve_lin_sys(eqs_ring, ring, _raw=False) {x: 1, y: 1} See also ======== sympy_eqs_to_ring: prepares the inputs to ``solve_lin_sys``. linsolve: ``linsolve`` uses ``solve_lin_sys`` internally. sympy.solvers.solvers.solve: ``solve`` uses ``solve_lin_sys`` internally. """ as_expr = not _raw assert ring.domain.is_Field eqs_dict = [dict(eq) for eq in eqs] one_monom = ring.one.monoms()[0] zero = ring.domain.zero eqs_rhs = [] eqs_coeffs = [] for eq_dict in eqs_dict: eq_rhs = eq_dict.pop(one_monom, zero) eq_coeffs = {} for monom, coeff in eq_dict.items(): if sum(monom) != 1: msg = "Nonlinear term encountered in solve_lin_sys" raise PolyNonlinearError(msg) eq_coeffs[ring.gens[monom.index(1)]] = coeff if not eq_coeffs: if not eq_rhs: continue else: return None eqs_rhs.append(eq_rhs) eqs_coeffs.append(eq_coeffs) result = _solve_lin_sys(eqs_coeffs, eqs_rhs, ring) if result is not None and as_expr: def to_sympy(x): as_expr = getattr(x, 'as_expr', None) if as_expr: return as_expr() else: return ring.domain.to_sympy(x) tresult = {to_sympy(sym): to_sympy(val) for sym, val in result.items()} # Remove 1.0x result = {} for k, v in tresult.items(): if k.is_Mul: c, s = k.as_coeff_Mul() result[s] = v/c else: result[k] = v return result def _solve_lin_sys(eqs_coeffs, eqs_rhs, ring): """Solve a linear system from dict of PolynomialRing coefficients Explanation =========== This is an **internal** function used by :func:`solve_lin_sys` after the equations have been preprocessed. The role of this function is to split the system into connected components and pass those to :func:`_solve_lin_sys_component`. Examples ======== Setup a system for $x-y=0$ and $x+y=2$ and solve: >>> from sympy import symbols, sring >>> from sympy.polys.solvers import _solve_lin_sys >>> x, y = symbols('x, y') >>> R, (xr, yr) = sring([x, y], [x, y]) >>> eqs = [{xr:R.one, yr:-R.one}, {xr:R.one, yr:R.one}] >>> eqs_rhs = [R.zero, -2*R.one] >>> _solve_lin_sys(eqs, eqs_rhs, R) {y: 1, x: 1} See also ======== solve_lin_sys: This function is used internally by :func:`solve_lin_sys`. """ V = ring.gens E = [] for eq_coeffs in eqs_coeffs: syms = list(eq_coeffs) E.extend(zip(syms[:-1], syms[1:])) G = V, E components = connected_components(G) sym2comp = {} for n, component in enumerate(components): for sym in component: sym2comp[sym] = n subsystems = [([], []) for _ in range(len(components))] for eq_coeff, eq_rhs in zip(eqs_coeffs, eqs_rhs): sym = next(iter(eq_coeff), None) sub_coeff, sub_rhs = subsystems[sym2comp[sym]] sub_coeff.append(eq_coeff) sub_rhs.append(eq_rhs) sol = {} for subsystem in subsystems: subsol = _solve_lin_sys_component(subsystem[0], subsystem[1], ring) if subsol is None: return None sol.update(subsol) return sol def _solve_lin_sys_component(eqs_coeffs, eqs_rhs, ring): """Solve a linear system from dict of PolynomialRing coefficients Explanation =========== This is an **internal** function used by :func:`solve_lin_sys` after the equations have been preprocessed. After :func:`_solve_lin_sys` splits the system into connected components this function is called for each component. The system of equations is solved using Gauss-Jordan elimination with division followed by back-substitution. Examples ======== Setup a system for $x-y=0$ and $x+y=2$ and solve: >>> from sympy import symbols, sring >>> from sympy.polys.solvers import _solve_lin_sys_component >>> x, y = symbols('x, y') >>> R, (xr, yr) = sring([x, y], [x, y]) >>> eqs = [{xr:R.one, yr:-R.one}, {xr:R.one, yr:R.one}] >>> eqs_rhs = [R.zero, -2*R.one] >>> _solve_lin_sys_component(eqs, eqs_rhs, R) {y: 1, x: 1} See also ======== solve_lin_sys: This function is used internally by :func:`solve_lin_sys`. """ # transform from equations to matrix form matrix = eqs_to_matrix(eqs_coeffs, eqs_rhs, ring.gens, ring.domain) # convert to a field for rref if not matrix.domain.is_Field: matrix = matrix.to_field() # solve by row-reduction echelon, pivots = matrix.rref() # construct the returnable form of the solutions keys = ring.gens if pivots and pivots[-1] == len(keys): return None if len(pivots) == len(keys): sol = [] for s in [row[-1] for row in echelon.rep.to_ddm()]: a = s sol.append(a) sols = dict(zip(keys, sol)) else: sols = {} g = ring.gens # Extract ground domain coefficients and convert to the ring: if hasattr(ring, 'ring'): convert = ring.ring.ground_new else: convert = ring.ground_new echelon = echelon.rep.to_ddm() vals_set = {v for row in echelon for v in row} vals_map = {v: convert(v) for v in vals_set} echelon = [[vals_map[eij] for eij in ei] for ei in echelon] for i, p in enumerate(pivots): v = echelon[i][-1] - sum(echelon[i][j]*g[j] for j in range(p+1, len(g)) if echelon[i][j]) sols[keys[p]] = v return sols sympy-sympy-1.9/sympy/polys/specialpolys.py000066400000000000000000000255171412543434000213450ustar00rootroot00000000000000"""Functions for generating interesting polynomials, e.g. for benchmarking. """ from sympy.core import Add, Mul, Symbol, sympify, Dummy, symbols from sympy.core.containers import Tuple from sympy.core.singleton import S from sympy.functions.elementary.miscellaneous import sqrt from sympy.ntheory import nextprime from sympy.polys.densearith import ( dmp_add_term, dmp_neg, dmp_mul, dmp_sqr ) from sympy.polys.densebasic import ( dmp_zero, dmp_one, dmp_ground, dup_from_raw_dict, dmp_raise, dup_random ) from sympy.polys.domains import ZZ from sympy.polys.factortools import dup_zz_cyclotomic_poly from sympy.polys.polyclasses import DMP from sympy.polys.polytools import Poly, PurePoly from sympy.polys.polyutils import _analyze_gens from sympy.utilities import subsets, public, filldedent @public def swinnerton_dyer_poly(n, x=None, polys=False): """Generates n-th Swinnerton-Dyer polynomial in `x`. Parameters ---------- n : int `n` decides the order of polynomial x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ from .numberfields import minimal_polynomial if n <= 0: raise ValueError( "can't generate Swinnerton-Dyer polynomial of order %s" % n) if x is not None: sympify(x) else: x = Dummy('x') if n > 3: p = 2 a = [sqrt(2)] for i in range(2, n + 1): p = nextprime(p) a.append(sqrt(p)) return minimal_polynomial(Add(*a), x, polys=polys) if n == 1: ex = x**2 - 2 elif n == 2: ex = x**4 - 10*x**2 + 1 elif n == 3: ex = x**8 - 40*x**6 + 352*x**4 - 960*x**2 + 576 return PurePoly(ex, x) if polys else ex @public def cyclotomic_poly(n, x=None, polys=False): """Generates cyclotomic polynomial of order `n` in `x`. Parameters ---------- n : int `n` decides the order of polynomial x : optional polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ if n <= 0: raise ValueError( "can't generate cyclotomic polynomial of order %s" % n) poly = DMP(dup_zz_cyclotomic_poly(int(n), ZZ), ZZ) if x is not None: poly = Poly.new(poly, x) else: poly = PurePoly.new(poly, Dummy('x')) return poly if polys else poly.as_expr() @public def symmetric_poly(n, *gens, **args): """Generates symmetric polynomial of order `n`. Returns a Poly object when ``polys=True``, otherwise (default) returns an expression. """ # TODO: use an explicit keyword argument when Python 2 support is dropped gens = _analyze_gens(gens) if n < 0 or n > len(gens) or not gens: raise ValueError("can't generate symmetric polynomial of order %s for %s" % (n, gens)) elif not n: poly = S.One else: poly = Add(*[Mul(*s) for s in subsets(gens, int(n))]) if not args.get('polys', False): return poly else: return Poly(poly, *gens) @public def random_poly(x, n, inf, sup, domain=ZZ, polys=False): """Generates a polynomial of degree ``n`` with coefficients in ``[inf, sup]``. Parameters ---------- x `x` is the independent term of polynomial n : int `n` decides the order of polynomial inf Lower limit of range in which coefficients lie sup Upper limit of range in which coefficients lie domain : optional Decides what ring the coefficients are supposed to belong. Default is set to Integers. polys : bool, optional ``polys=True`` returns an expression, otherwise (default) returns an expression. """ poly = Poly(dup_random(n, inf, sup, domain), x, domain=domain) return poly if polys else poly.as_expr() @public def interpolating_poly(n, x, X='x', Y='y'): """Construct Lagrange interpolating polynomial for ``n`` data points. If a sequence of values are given for ``X`` and ``Y`` then the first ``n`` values will be used. """ ok = getattr(x, 'free_symbols', None) if isinstance(X, str): X = symbols("%s:%s" % (X, n)) elif ok and ok & Tuple(*X).free_symbols: ok = False if isinstance(Y, str): Y = symbols("%s:%s" % (Y, n)) elif ok and ok & Tuple(*Y).free_symbols: ok = False if not ok: raise ValueError(filldedent(''' Expecting symbol for x that does not appear in X or Y. Use `interpolate(list(zip(X, Y)), x)` instead.''')) coeffs = [] numert = Mul(*[x - X[i] for i in range(n)]) for i in range(n): numer = numert/(x - X[i]) denom = Mul(*[(X[i] - X[j]) for j in range(n) if i != j]) coeffs.append(numer/denom) return Add(*[coeff*y for coeff, y in zip(coeffs, Y)]) def fateman_poly_F_1(n): """Fateman's GCD benchmark: trivial GCD """ Y = [Symbol('y_' + str(i)) for i in range(n + 1)] y_0, y_1 = Y[0], Y[1] u = y_0 + Add(*[y for y in Y[1:]]) v = y_0**2 + Add(*[y**2 for y in Y[1:]]) F = ((u + 1)*(u + 2)).as_poly(*Y) G = ((v + 1)*(-3*y_1*y_0**2 + y_1**2 - 1)).as_poly(*Y) H = Poly(1, *Y) return F, G, H def dmp_fateman_poly_F_1(n, K): """Fateman's GCD benchmark: trivial GCD """ u = [K(1), K(0)] for i in range(n): u = [dmp_one(i, K), u] v = [K(1), K(0), K(0)] for i in range(0, n): v = [dmp_one(i, K), dmp_zero(i), v] m = n - 1 U = dmp_add_term(u, dmp_ground(K(1), m), 0, n, K) V = dmp_add_term(u, dmp_ground(K(2), m), 0, n, K) f = [[-K(3), K(0)], [], [K(1), K(0), -K(1)]] W = dmp_add_term(v, dmp_ground(K(1), m), 0, n, K) Y = dmp_raise(f, m, 1, K) F = dmp_mul(U, V, n, K) G = dmp_mul(W, Y, n, K) H = dmp_one(n, K) return F, G, H def fateman_poly_F_2(n): """Fateman's GCD benchmark: linearly dense quartic inputs """ Y = [Symbol('y_' + str(i)) for i in range(n + 1)] y_0 = Y[0] u = Add(*[y for y in Y[1:]]) H = Poly((y_0 + u + 1)**2, *Y) F = Poly((y_0 - u - 2)**2, *Y) G = Poly((y_0 + u + 2)**2, *Y) return H*F, H*G, H def dmp_fateman_poly_F_2(n, K): """Fateman's GCD benchmark: linearly dense quartic inputs """ u = [K(1), K(0)] for i in range(n - 1): u = [dmp_one(i, K), u] m = n - 1 v = dmp_add_term(u, dmp_ground(K(2), m - 1), 0, n, K) f = dmp_sqr([dmp_one(m, K), dmp_neg(v, m, K)], n, K) g = dmp_sqr([dmp_one(m, K), v], n, K) v = dmp_add_term(u, dmp_one(m - 1, K), 0, n, K) h = dmp_sqr([dmp_one(m, K), v], n, K) return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h def fateman_poly_F_3(n): """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ Y = [Symbol('y_' + str(i)) for i in range(n + 1)] y_0 = Y[0] u = Add(*[y**(n + 1) for y in Y[1:]]) H = Poly((y_0**(n + 1) + u + 1)**2, *Y) F = Poly((y_0**(n + 1) - u - 2)**2, *Y) G = Poly((y_0**(n + 1) + u + 2)**2, *Y) return H*F, H*G, H def dmp_fateman_poly_F_3(n, K): """Fateman's GCD benchmark: sparse inputs (deg f ~ vars f) """ u = dup_from_raw_dict({n + 1: K.one}, K) for i in range(0, n - 1): u = dmp_add_term([u], dmp_one(i, K), n + 1, i + 1, K) v = dmp_add_term(u, dmp_ground(K(2), n - 2), 0, n, K) f = dmp_sqr( dmp_add_term([dmp_neg(v, n - 1, K)], dmp_one(n - 1, K), n + 1, n, K), n, K) g = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K) v = dmp_add_term(u, dmp_one(n - 2, K), 0, n - 1, K) h = dmp_sqr(dmp_add_term([v], dmp_one(n - 1, K), n + 1, n, K), n, K) return dmp_mul(f, h, n, K), dmp_mul(g, h, n, K), h # A few useful polynomials from Wang's paper ('78). from sympy.polys.rings import ring def _f_0(): R, x, y, z = ring("x,y,z", ZZ) return x**2*y*z**2 + 2*x**2*y*z + 3*x**2*y + 2*x**2 + 3*x + 4*y**2*z**2 + 5*y**2*z + 6*y**2 + y*z**2 + 2*y*z + y + 1 def _f_1(): R, x, y, z = ring("x,y,z", ZZ) return x**3*y*z + x**2*y**2*z**2 + x**2*y**2 + 20*x**2*y*z + 30*x**2*y + x**2*z**2 + 10*x**2*z + x*y**3*z + 30*x*y**2*z + 20*x*y**2 + x*y*z**3 + 10*x*y*z**2 + x*y*z + 610*x*y + 20*x*z**2 + 230*x*z + 300*x + y**2*z**2 + 10*y**2*z + 30*y*z**2 + 320*y*z + 200*y + 600*z + 6000 def _f_2(): R, x, y, z = ring("x,y,z", ZZ) return x**5*y**3 + x**5*y**2*z + x**5*y*z**2 + x**5*z**3 + x**3*y**2 + x**3*y*z + 90*x**3*y + 90*x**3*z + x**2*y**2*z - 11*x**2*y**2 + x**2*z**3 - 11*x**2*z**2 + y*z - 11*y + 90*z - 990 def _f_3(): R, x, y, z = ring("x,y,z", ZZ) return x**5*y**2 + x**4*z**4 + x**4 + x**3*y**3*z + x**3*z + x**2*y**4 + x**2*y**3*z**3 + x**2*y*z**5 + x**2*y*z + x*y**2*z**4 + x*y**2 + x*y*z**7 + x*y*z**3 + x*y*z**2 + y**2*z + y*z**4 def _f_4(): R, x, y, z = ring("x,y,z", ZZ) return -x**9*y**8*z - x**8*y**5*z**3 - x**7*y**12*z**2 - 5*x**7*y**8 - x**6*y**9*z**4 + x**6*y**7*z**3 + 3*x**6*y**7*z - 5*x**6*y**5*z**2 - x**6*y**4*z**3 + x**5*y**4*z**5 + 3*x**5*y**4*z**3 - x**5*y*z**5 + x**4*y**11*z**4 + 3*x**4*y**11*z**2 - x**4*y**8*z**4 + 5*x**4*y**7*z**2 + 15*x**4*y**7 - 5*x**4*y**4*z**2 + x**3*y**8*z**6 + 3*x**3*y**8*z**4 - x**3*y**5*z**6 + 5*x**3*y**4*z**4 + 15*x**3*y**4*z**2 + x**3*y**3*z**5 + 3*x**3*y**3*z**3 - 5*x**3*y*z**4 + x**2*z**7 + 3*x**2*z**5 + x*y**7*z**6 + 3*x*y**7*z**4 + 5*x*y**3*z**4 + 15*x*y**3*z**2 + y**4*z**8 + 3*y**4*z**6 + 5*z**6 + 15*z**4 def _f_5(): R, x, y, z = ring("x,y,z", ZZ) return -x**3 - 3*x**2*y + 3*x**2*z - 3*x*y**2 + 6*x*y*z - 3*x*z**2 - y**3 + 3*y**2*z - 3*y*z**2 + z**3 def _f_6(): R, x, y, z, t = ring("x,y,z,t", ZZ) return 2115*x**4*y + 45*x**3*z**3*t**2 - 45*x**3*t**2 - 423*x*y**4 - 47*x*y**3 + 141*x*y*z**3 + 94*x*y*z*t - 9*y**3*z**3*t**2 + 9*y**3*t**2 - y**2*z**3*t**2 + y**2*t**2 + 3*z**6*t**2 + 2*z**4*t**3 - 3*z**3*t**2 - 2*z*t**3 def _w_1(): R, x, y, z = ring("x,y,z", ZZ) return 4*x**6*y**4*z**2 + 4*x**6*y**3*z**3 - 4*x**6*y**2*z**4 - 4*x**6*y*z**5 + x**5*y**4*z**3 + 12*x**5*y**3*z - x**5*y**2*z**5 + 12*x**5*y**2*z**2 - 12*x**5*y*z**3 - 12*x**5*z**4 + 8*x**4*y**4 + 6*x**4*y**3*z**2 + 8*x**4*y**3*z - 4*x**4*y**2*z**4 + 4*x**4*y**2*z**3 - 8*x**4*y**2*z**2 - 4*x**4*y*z**5 - 2*x**4*y*z**4 - 8*x**4*y*z**3 + 2*x**3*y**4*z + x**3*y**3*z**3 - x**3*y**2*z**5 - 2*x**3*y**2*z**3 + 9*x**3*y**2*z - 12*x**3*y*z**3 + 12*x**3*y*z**2 - 12*x**3*z**4 + 3*x**3*z**3 + 6*x**2*y**3 - 6*x**2*y**2*z**2 + 8*x**2*y**2*z - 2*x**2*y*z**4 - 8*x**2*y*z**3 + 2*x**2*y*z**2 + 2*x*y**3*z - 2*x*y**2*z**3 - 3*x*y*z + 3*x*z**3 - 2*y**2 + 2*y*z**2 def _w_2(): R, x, y = ring("x,y", ZZ) return 24*x**8*y**3 + 48*x**8*y**2 + 24*x**7*y**5 - 72*x**7*y**2 + 25*x**6*y**4 + 2*x**6*y**3 + 4*x**6*y + 8*x**6 + x**5*y**6 + x**5*y**3 - 12*x**5 + x**4*y**5 - x**4*y**4 - 2*x**4*y**3 + 292*x**4*y**2 - x**3*y**6 + 3*x**3*y**3 - x**2*y**5 + 12*x**2*y**3 + 48*x**2 - 12*y**3 def f_polys(): return _f_0(), _f_1(), _f_2(), _f_3(), _f_4(), _f_5(), _f_6() def w_polys(): return _w_1(), _w_2() sympy-sympy-1.9/sympy/polys/sqfreetools.py000066400000000000000000000263101412543434000211740ustar00rootroot00000000000000"""Square-free decomposition algorithms and related tools. """ from sympy.polys.densearith import ( dup_neg, dmp_neg, dup_sub, dmp_sub, dup_mul, dup_quo, dmp_quo, dup_mul_ground, dmp_mul_ground) from sympy.polys.densebasic import ( dup_strip, dup_LC, dmp_ground_LC, dmp_zero_p, dmp_ground, dup_degree, dmp_degree, dmp_raise, dmp_inject, dup_convert) from sympy.polys.densetools import ( dup_diff, dmp_diff, dmp_diff_in, dup_shift, dmp_compose, dup_monic, dmp_ground_monic, dup_primitive, dmp_ground_primitive) from sympy.polys.euclidtools import ( dup_inner_gcd, dmp_inner_gcd, dup_gcd, dmp_gcd, dmp_resultant) from sympy.polys.galoistools import ( gf_sqf_list, gf_sqf_part) from sympy.polys.polyerrors import ( MultivariatePolynomialError, DomainError) def dup_sqf_p(f, K): """ Return ``True`` if ``f`` is a square-free polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sqf_p(x**2 - 2*x + 1) False >>> R.dup_sqf_p(x**2 - 1) True """ if not f: return True else: return not dup_degree(dup_gcd(f, dup_diff(f, 1, K), K)) def dmp_sqf_p(f, u, K): """ Return ``True`` if ``f`` is a square-free polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_sqf_p(x**2 + 2*x*y + y**2) False >>> R.dmp_sqf_p(x**2 + y**2) True """ if dmp_zero_p(f, u): return True else: return not dmp_degree(dmp_gcd(f, dmp_diff(f, 1, u, K), u, K), u) def dup_sqf_norm(f, K): """ Square-free norm of ``f`` in ``K[x]``, useful over algebraic domains. Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))`` is a square-free polynomial over K, where ``a`` is the algebraic extension of ``K``. Examples ======== >>> from sympy.polys import ring, QQ >>> from sympy import sqrt >>> K = QQ.algebraic_field(sqrt(3)) >>> R, x = ring("x", K) >>> _, X = ring("x", QQ) >>> s, f, r = R.dup_sqf_norm(x**2 - 2) >>> s == 1 True >>> f == x**2 + K([QQ(-2), QQ(0)])*x + 1 True >>> r == X**4 - 10*X**2 + 1 True """ if not K.is_Algebraic: raise DomainError("ground domain must be algebraic") s, g = 0, dmp_raise(K.mod.rep, 1, 0, K.dom) while True: h, _ = dmp_inject(f, 0, K, front=True) r = dmp_resultant(g, h, 1, K.dom) if dup_sqf_p(r, K.dom): break else: f, s = dup_shift(f, -K.unit, K), s + 1 return s, f, r def dmp_sqf_norm(f, u, K): """ Square-free norm of ``f`` in ``K[X]``, useful over algebraic domains. Returns ``s``, ``f``, ``r``, such that ``g(x) = f(x-sa)`` and ``r(x) = Norm(g(x))`` is a square-free polynomial over K, where ``a`` is the algebraic extension of ``K``. Examples ======== >>> from sympy.polys import ring, QQ >>> from sympy import I >>> K = QQ.algebraic_field(I) >>> R, x, y = ring("x,y", K) >>> _, X, Y = ring("x,y", QQ) >>> s, f, r = R.dmp_sqf_norm(x*y + y**2) >>> s == 1 True >>> f == x*y + y**2 + K([QQ(-1), QQ(0)])*y True >>> r == X**2*Y**2 + 2*X*Y**3 + Y**4 + Y**2 True """ if not u: return dup_sqf_norm(f, K) if not K.is_Algebraic: raise DomainError("ground domain must be algebraic") g = dmp_raise(K.mod.rep, u + 1, 0, K.dom) F = dmp_raise([K.one, -K.unit], u, 0, K) s = 0 while True: h, _ = dmp_inject(f, u, K, front=True) r = dmp_resultant(g, h, u + 1, K.dom) if dmp_sqf_p(r, u, K.dom): break else: f, s = dmp_compose(f, F, u, K), s + 1 return s, f, r def dmp_norm(f, u, K): """ Norm of ``f`` in ``K[X1, ..., Xn]``, often not square-free. """ if not K.is_Algebraic: raise DomainError("ground domain must be algebraic") g = dmp_raise(K.mod.rep, u + 1, 0, K.dom) h, _ = dmp_inject(f, u, K, front=True) return dmp_resultant(g, h, u + 1, K.dom) def dup_gf_sqf_part(f, K): """Compute square-free part of ``f`` in ``GF(p)[x]``. """ f = dup_convert(f, K, K.dom) g = gf_sqf_part(f, K.mod, K.dom) return dup_convert(g, K.dom, K) def dmp_gf_sqf_part(f, u, K): """Compute square-free part of ``f`` in ``GF(p)[X]``. """ raise NotImplementedError('multivariate polynomials over finite fields') def dup_sqf_part(f, K): """ Returns square-free part of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_sqf_part(x**3 - 3*x - 2) x**2 - x - 2 """ if K.is_FiniteField: return dup_gf_sqf_part(f, K) if not f: return f if K.is_negative(dup_LC(f, K)): f = dup_neg(f, K) gcd = dup_gcd(f, dup_diff(f, 1, K), K) sqf = dup_quo(f, gcd, K) if K.is_Field: return dup_monic(sqf, K) else: return dup_primitive(sqf, K)[1] def dmp_sqf_part(f, u, K): """ Returns square-free part of a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> R.dmp_sqf_part(x**3 + 2*x**2*y + x*y**2) x**2 + x*y """ if not u: return dup_sqf_part(f, K) if K.is_FiniteField: return dmp_gf_sqf_part(f, u, K) if dmp_zero_p(f, u): return f if K.is_negative(dmp_ground_LC(f, u, K)): f = dmp_neg(f, u, K) gcd = f for i in range(u+1): gcd = dmp_gcd(gcd, dmp_diff_in(f, 1, i, u, K), u, K) sqf = dmp_quo(f, gcd, u, K) if K.is_Field: return dmp_ground_monic(sqf, u, K) else: return dmp_ground_primitive(sqf, u, K)[1] def dup_gf_sqf_list(f, K, all=False): """Compute square-free decomposition of ``f`` in ``GF(p)[x]``. """ f = dup_convert(f, K, K.dom) coeff, factors = gf_sqf_list(f, K.mod, K.dom, all=all) for i, (f, k) in enumerate(factors): factors[i] = (dup_convert(f, K.dom, K), k) return K.convert(coeff, K.dom), factors def dmp_gf_sqf_list(f, u, K, all=False): """Compute square-free decomposition of ``f`` in ``GF(p)[X]``. """ raise NotImplementedError('multivariate polynomials over finite fields') def dup_sqf_list(f, K, all=False): """ Return square-free decomposition of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 >>> R.dup_sqf_list(f) (2, [(x + 1, 2), (x + 2, 3)]) >>> R.dup_sqf_list(f, all=True) (2, [(1, 1), (x + 1, 2), (x + 2, 3)]) """ if K.is_FiniteField: return dup_gf_sqf_list(f, K, all=all) if K.is_Field: coeff = dup_LC(f, K) f = dup_monic(f, K) else: coeff, f = dup_primitive(f, K) if K.is_negative(dup_LC(f, K)): f = dup_neg(f, K) coeff = -coeff if dup_degree(f) <= 0: return coeff, [] result, i = [], 1 h = dup_diff(f, 1, K) g, p, q = dup_inner_gcd(f, h, K) while True: d = dup_diff(p, 1, K) h = dup_sub(q, d, K) if not h: result.append((p, i)) break g, p, q = dup_inner_gcd(p, h, K) if all or dup_degree(g) > 0: result.append((g, i)) i += 1 return coeff, result def dup_sqf_list_include(f, K, all=False): """ Return square-free decomposition of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> f = 2*x**5 + 16*x**4 + 50*x**3 + 76*x**2 + 56*x + 16 >>> R.dup_sqf_list_include(f) [(2, 1), (x + 1, 2), (x + 2, 3)] >>> R.dup_sqf_list_include(f, all=True) [(2, 1), (x + 1, 2), (x + 2, 3)] """ coeff, factors = dup_sqf_list(f, K, all=all) if factors and factors[0][1] == 1: g = dup_mul_ground(factors[0][0], coeff, K) return [(g, 1)] + factors[1:] else: g = dup_strip([coeff]) return [(g, 1)] + factors def dmp_sqf_list(f, u, K, all=False): """ Return square-free decomposition of a polynomial in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x**5 + 2*x**4*y + x**3*y**2 >>> R.dmp_sqf_list(f) (1, [(x + y, 2), (x, 3)]) >>> R.dmp_sqf_list(f, all=True) (1, [(1, 1), (x + y, 2), (x, 3)]) """ if not u: return dup_sqf_list(f, K, all=all) if K.is_FiniteField: return dmp_gf_sqf_list(f, u, K, all=all) if K.is_Field: coeff = dmp_ground_LC(f, u, K) f = dmp_ground_monic(f, u, K) else: coeff, f = dmp_ground_primitive(f, u, K) if K.is_negative(dmp_ground_LC(f, u, K)): f = dmp_neg(f, u, K) coeff = -coeff if dmp_degree(f, u) <= 0: return coeff, [] result, i = [], 1 h = dmp_diff(f, 1, u, K) g, p, q = dmp_inner_gcd(f, h, u, K) while True: d = dmp_diff(p, 1, u, K) h = dmp_sub(q, d, u, K) if dmp_zero_p(h, u): result.append((p, i)) break g, p, q = dmp_inner_gcd(p, h, u, K) if all or dmp_degree(g, u) > 0: result.append((g, i)) i += 1 return coeff, result def dmp_sqf_list_include(f, u, K, all=False): """ Return square-free decomposition of a polynomial in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) >>> f = x**5 + 2*x**4*y + x**3*y**2 >>> R.dmp_sqf_list_include(f) [(1, 1), (x + y, 2), (x, 3)] >>> R.dmp_sqf_list_include(f, all=True) [(1, 1), (x + y, 2), (x, 3)] """ if not u: return dup_sqf_list_include(f, K, all=all) coeff, factors = dmp_sqf_list(f, u, K, all=all) if factors and factors[0][1] == 1: g = dmp_mul_ground(factors[0][0], coeff, u, K) return [(g, 1)] + factors[1:] else: g = dmp_ground(coeff, u) return [(g, 1)] + factors def dup_gff_list(f, K): """ Compute greatest factorial factorization of ``f`` in ``K[x]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x = ring("x", ZZ) >>> R.dup_gff_list(x**5 + 2*x**4 - x**3 - 2*x**2) [(x, 1), (x + 2, 4)] """ if not f: raise ValueError("greatest factorial factorization doesn't exist for a zero polynomial") f = dup_monic(f, K) if not dup_degree(f): return [] else: g = dup_gcd(f, dup_shift(f, K.one, K), K) H = dup_gff_list(g, K) for i, (h, k) in enumerate(H): g = dup_mul(g, dup_shift(h, -K(k), K), K) H[i] = (h, k + 1) f = dup_quo(f, g, K) if not dup_degree(f): return H else: return [(f, 1)] + H def dmp_gff_list(f, u, K): """ Compute greatest factorial factorization of ``f`` in ``K[X]``. Examples ======== >>> from sympy.polys import ring, ZZ >>> R, x,y = ring("x,y", ZZ) """ if not u: return dup_gff_list(f, K) else: raise MultivariatePolynomialError(f) sympy-sympy-1.9/sympy/polys/subresultants_qq_zz.py000066400000000000000000002535341412543434000230020ustar00rootroot00000000000000""" This module contains functions for the computation of Euclidean, (generalized) Sturmian, (modified) subresultant polynomial remainder sequences (prs's) of two polynomials; included are also three functions for the computation of the resultant of two polynomials. Except for the function res_z(), which computes the resultant of two polynomials, the pseudo-remainder function prem() of sympy is _not_ used by any of the functions in the module. Instead of prem() we use the function rem_z(). Included is also the function quo_z(). An explanation of why we avoid prem() can be found in the references stated in the docstring of rem_z(). 1. Theoretical background: ========================== Consider the polynomials f, g in Z[x] of degrees deg(f) = n and deg(g) = m with n >= m. Definition 1: ============= The sign sequence of a polynomial remainder sequence (prs) is the sequence of signs of the leading coefficients of its polynomials. Sign sequences can be computed with the function: sign_seq(poly_seq, x) Definition 2: ============= A polynomial remainder sequence (prs) is called complete if the degree difference between any two consecutive polynomials is 1; otherwise, it called incomplete. It is understood that f, g belong to the sequences mentioned in the two definitions above. 1A. Euclidean and subresultant prs's: ===================================== The subresultant prs of f, g is a sequence of polynomials in Z[x] analogous to the Euclidean prs, the sequence obtained by applying on f, g Euclid's algorithm for polynomial greatest common divisors (gcd) in Q[x]. The subresultant prs differs from the Euclidean prs in that the coefficients of each polynomial in the former sequence are determinants --- also referred to as subresultants --- of appropriately selected sub-matrices of sylvester1(f, g, x), Sylvester's matrix of 1840 of dimensions (n + m) * (n + m). Recall that the determinant of sylvester1(f, g, x) itself is called the resultant of f, g and serves as a criterion of whether the two polynomials have common roots or not. In sympy the resultant is computed with the function resultant(f, g, x). This function does _not_ evaluate the determinant of sylvester(f, g, x, 1); instead, it returns the last member of the subresultant prs of f, g, multiplied (if needed) by an appropriate power of -1; see the caveat below. In this module we use three functions to compute the resultant of f, g: a) res(f, g, x) computes the resultant by evaluating the determinant of sylvester(f, g, x, 1); b) res_q(f, g, x) computes the resultant recursively, by performing polynomial divisions in Q[x] with the function rem(); c) res_z(f, g, x) computes the resultant recursively, by performing polynomial divisions in Z[x] with the function prem(). Caveat: If Df = degree(f, x) and Dg = degree(g, x), then: resultant(f, g, x) = (-1)**(Df*Dg) * resultant(g, f, x). For complete prs's the sign sequence of the Euclidean prs of f, g is identical to the sign sequence of the subresultant prs of f, g and the coefficients of one sequence are easily computed from the coefficients of the other. For incomplete prs's the polynomials in the subresultant prs, generally differ in sign from those of the Euclidean prs, and --- unlike the case of complete prs's --- it is not at all obvious how to compute the coefficients of one sequence from the coefficients of the other. 1B. Sturmian and modified subresultant prs's: ============================================= For the same polynomials f, g in Z[x] mentioned above, their ``modified'' subresultant prs is a sequence of polynomials similar to the Sturmian prs, the sequence obtained by applying in Q[x] Sturm's algorithm on f, g. The two sequences differ in that the coefficients of each polynomial in the modified subresultant prs are the determinants --- also referred to as modified subresultants --- of appropriately selected sub-matrices of sylvester2(f, g, x), Sylvester's matrix of 1853 of dimensions 2n x 2n. The determinant of sylvester2 itself is called the modified resultant of f, g and it also can serve as a criterion of whether the two polynomials have common roots or not. For complete prs's the sign sequence of the Sturmian prs of f, g is identical to the sign sequence of the modified subresultant prs of f, g and the coefficients of one sequence are easily computed from the coefficients of the other. For incomplete prs's the polynomials in the modified subresultant prs, generally differ in sign from those of the Sturmian prs, and --- unlike the case of complete prs's --- it is not at all obvious how to compute the coefficients of one sequence from the coefficients of the other. As Sylvester pointed out, the coefficients of the polynomial remainders obtained as (modified) subresultants are the smallest possible without introducing rationals and without computing (integer) greatest common divisors. 1C. On terminology: =================== Whence the terminology? Well generalized Sturmian prs's are ``modifications'' of Euclidean prs's; the hint came from the title of the Pell-Gordon paper of 1917. In the literature one also encounters the name ``non signed'' and ``signed'' prs for Euclidean and Sturmian prs respectively. Likewise ``non signed'' and ``signed'' subresultant prs for subresultant and modified subresultant prs respectively. 2. Functions in the module: =========================== No function utilizes sympy's function prem(). 2A. Matrices: ============= The functions sylvester(f, g, x, method=1) and sylvester(f, g, x, method=2) compute either Sylvester matrix. They can be used to compute (modified) subresultant prs's by direct determinant evaluation. The function bezout(f, g, x, method='prs') provides a matrix of smaller dimensions than either Sylvester matrix. It is the function of choice for computing (modified) subresultant prs's by direct determinant evaluation. sylvester(f, g, x, method=1) sylvester(f, g, x, method=2) bezout(f, g, x, method='prs') The following identity holds: bezout(f, g, x, method='prs') = backward_eye(deg(f))*bezout(f, g, x, method='bz')*backward_eye(deg(f)) 2B. Subresultant and modified subresultant prs's by =================================================== determinant evaluations: ======================= We use the Sylvester matrices of 1840 and 1853 to compute, respectively, subresultant and modified subresultant polynomial remainder sequences. However, for large matrices this approach takes a lot of time. Instead of utilizing the Sylvester matrices, we can employ the Bezout matrix which is of smaller dimensions. subresultants_sylv(f, g, x) modified_subresultants_sylv(f, g, x) subresultants_bezout(f, g, x) modified_subresultants_bezout(f, g, x) 2C. Subresultant prs's by ONE determinant evaluation: ===================================================== All three functions in this section evaluate one determinant per remainder polynomial; this is the determinant of an appropriately selected sub-matrix of sylvester1(f, g, x), Sylvester's matrix of 1840. To compute the remainder polynomials the function subresultants_rem(f, g, x) employs rem(f, g, x). By contrast, the other two functions implement Van Vleck's ideas of 1900 and compute the remainder polynomials by trinagularizing sylvester2(f, g, x), Sylvester's matrix of 1853. subresultants_rem(f, g, x) subresultants_vv(f, g, x) subresultants_vv_2(f, g, x). 2E. Euclidean, Sturmian prs's in Q[x]: ====================================== euclid_q(f, g, x) sturm_q(f, g, x) 2F. Euclidean, Sturmian and (modified) subresultant prs's P-G: ============================================================== All functions in this section are based on the Pell-Gordon (P-G) theorem of 1917. Computations are done in Q[x], employing the function rem(f, g, x) for the computation of the remainder polynomials. euclid_pg(f, g, x) sturm pg(f, g, x) subresultants_pg(f, g, x) modified_subresultants_pg(f, g, x) 2G. Euclidean, Sturmian and (modified) subresultant prs's A-M-V: ================================================================ All functions in this section are based on the Akritas-Malaschonok- Vigklas (A-M-V) theorem of 2015. Computations are done in Z[x], employing the function rem_z(f, g, x) for the computation of the remainder polynomials. euclid_amv(f, g, x) sturm_amv(f, g, x) subresultants_amv(f, g, x) modified_subresultants_amv(f, g, x) 2Ga. Exception: =============== subresultants_amv_q(f, g, x) This function employs rem(f, g, x) for the computation of the remainder polynomials, despite the fact that it implements the A-M-V Theorem. It is included in our module in order to show that theorems P-G and A-M-V can be implemented utilizing either the function rem(f, g, x) or the function rem_z(f, g, x). For clearly historical reasons --- since the Collins-Brown-Traub coefficients-reduction factor beta_i was not available in 1917 --- we have implemented the Pell-Gordon theorem with the function rem(f, g, x) and the A-M-V Theorem with the function rem_z(f, g, x). 2H. Resultants: =============== res(f, g, x) res_q(f, g, x) res_z(f, g, x) """ from sympy import (Abs, degree, expand, eye, floor, LC, Matrix, nan, Poly, pprint) from sympy import (QQ, pquo, quo, prem, rem, S, sign, simplify, summation, var, zeros) from sympy.polys.polyerrors import PolynomialError def sylvester(f, g, x, method = 1): ''' The input polynomials f, g are in Z[x] or in Q[x]. Let m = degree(f, x), n = degree(g, x) and mx = max( m , n ). a. If method = 1 (default), computes sylvester1, Sylvester's matrix of 1840 of dimension (m + n) x (m + n). The determinants of properly chosen submatrices of this matrix (a.k.a. subresultants) can be used to compute the coefficients of the Euclidean PRS of f, g. b. If method = 2, computes sylvester2, Sylvester's matrix of 1853 of dimension (2*mx) x (2*mx). The determinants of properly chosen submatrices of this matrix (a.k.a. ``modified'' subresultants) can be used to compute the coefficients of the Sturmian PRS of f, g. Applications of these Matrices can be found in the references below. Especially, for applications of sylvester2, see the first reference!! References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem by Van Vleck Regarding Sturm Sequences. Serdica Journal of Computing, Vol. 7, No 4, 101-134, 2013. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences.'' Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. ''' # obtain degrees of polys m, n = degree( Poly(f, x), x), degree( Poly(g, x), x) # Special cases: # A:: case m = n < 0 (i.e. both polys are 0) if m == n and n < 0: return Matrix([]) # B:: case m = n = 0 (i.e. both polys are constants) if m == n and n == 0: return Matrix([]) # C:: m == 0 and n < 0 or m < 0 and n == 0 # (i.e. one poly is constant and the other is 0) if m == 0 and n < 0: return Matrix([]) elif m < 0 and n == 0: return Matrix([]) # D:: m >= 1 and n < 0 or m < 0 and n >=1 # (i.e. one poly is of degree >=1 and the other is 0) if m >= 1 and n < 0: return Matrix([0]) elif m < 0 and n >= 1: return Matrix([0]) fp = Poly(f, x).all_coeffs() gp = Poly(g, x).all_coeffs() # Sylvester's matrix of 1840 (default; a.k.a. sylvester1) if method <= 1: M = zeros(m + n) k = 0 for i in range(n): j = k for coeff in fp: M[i, j] = coeff j = j + 1 k = k + 1 k = 0 for i in range(n, m + n): j = k for coeff in gp: M[i, j] = coeff j = j + 1 k = k + 1 return M # Sylvester's matrix of 1853 (a.k.a sylvester2) if method >= 2: if len(fp) < len(gp): h = [] for i in range(len(gp) - len(fp)): h.append(0) fp[ : 0] = h else: h = [] for i in range(len(fp) - len(gp)): h.append(0) gp[ : 0] = h mx = max(m, n) dim = 2*mx M = zeros( dim ) k = 0 for i in range( mx ): j = k for coeff in fp: M[2*i, j] = coeff j = j + 1 j = k for coeff in gp: M[2*i + 1, j] = coeff j = j + 1 k = k + 1 return M def process_matrix_output(poly_seq, x): """ poly_seq is a polynomial remainder sequence computed either by (modified_)subresultants_bezout or by (modified_)subresultants_sylv. This function removes from poly_seq all zero polynomials as well as all those whose degree is equal to the degree of a preceding polynomial in poly_seq, as we scan it from left to right. """ L = poly_seq[:] # get a copy of the input sequence d = degree(L[1], x) i = 2 while i < len(L): d_i = degree(L[i], x) if d_i < 0: # zero poly L.remove(L[i]) i = i - 1 if d == d_i: # poly degree equals degree of previous poly L.remove(L[i]) i = i - 1 if d_i >= 0: d = d_i i = i + 1 return L def subresultants_sylv(f, g, x): """ The input polynomials f, g are in Z[x] or in Q[x]. It is assumed that deg(f) >= deg(g). Computes the subresultant polynomial remainder sequence (prs) of f, g by evaluating determinants of appropriately selected submatrices of sylvester(f, g, x, 1). The dimensions of the latter are (deg(f) + deg(g)) x (deg(f) + deg(g)). Each coefficient is computed by evaluating the determinant of the corresponding submatrix of sylvester(f, g, x, 1). If the subresultant prs is complete, then the output coincides with the Euclidean sequence of the polynomials f, g. References: =========== 1. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants and Their Applications. Appl. Algebra in Engin., Communic. and Comp., Vol. 15, 233-266, 2004. """ # make sure neither f nor g is 0 if f == 0 or g == 0: return [f, g] n = degF = degree(f, x) m = degG = degree(g, x) # make sure proper degrees if n == 0 and m == 0: return [f, g] if n < m: n, m, degF, degG, f, g = m, n, degG, degF, g, f if n > 0 and m == 0: return [f, g] SR_L = [f, g] # subresultant list # form matrix sylvester(f, g, x, 1) S = sylvester(f, g, x, 1) # pick appropriate submatrices of S # and form subresultant polys j = m - 1 while j > 0: Sp = S[:, :] # copy of S # delete last j rows of coeffs of g for ind in range(m + n - j, m + n): Sp.row_del(m + n - j) # delete last j rows of coeffs of f for ind in range(m - j, m): Sp.row_del(m - j) # evaluate determinants and form coefficients list coeff_L, k, l = [], Sp.rows, 0 while l <= j: coeff_L.append(Sp[ : , 0 : k].det()) Sp.col_swap(k - 1, k + l) l += 1 # form poly and append to SP_L SR_L.append(Poly(coeff_L, x).as_expr()) j -= 1 # j = 0 SR_L.append(S.det()) return process_matrix_output(SR_L, x) def modified_subresultants_sylv(f, g, x): """ The input polynomials f, g are in Z[x] or in Q[x]. It is assumed that deg(f) >= deg(g). Computes the modified subresultant polynomial remainder sequence (prs) of f, g by evaluating determinants of appropriately selected submatrices of sylvester(f, g, x, 2). The dimensions of the latter are (2*deg(f)) x (2*deg(f)). Each coefficient is computed by evaluating the determinant of the corresponding submatrix of sylvester(f, g, x, 2). If the modified subresultant prs is complete, then the output coincides with the Sturmian sequence of the polynomials f, g. References: =========== 1. A. G. Akritas,G.I. Malaschonok and P.S. Vigklas: Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences. Serdica Journal of Computing, Vol. 8, No 1, 29--46, 2014. """ # make sure neither f nor g is 0 if f == 0 or g == 0: return [f, g] n = degF = degree(f, x) m = degG = degree(g, x) # make sure proper degrees if n == 0 and m == 0: return [f, g] if n < m: n, m, degF, degG, f, g = m, n, degG, degF, g, f if n > 0 and m == 0: return [f, g] SR_L = [f, g] # modified subresultant list # form matrix sylvester(f, g, x, 2) S = sylvester(f, g, x, 2) # pick appropriate submatrices of S # and form modified subresultant polys j = m - 1 while j > 0: # delete last 2*j rows of pairs of coeffs of f, g Sp = S[0:2*n - 2*j, :] # copy of first 2*n - 2*j rows of S # evaluate determinants and form coefficients list coeff_L, k, l = [], Sp.rows, 0 while l <= j: coeff_L.append(Sp[ : , 0 : k].det()) Sp.col_swap(k - 1, k + l) l += 1 # form poly and append to SP_L SR_L.append(Poly(coeff_L, x).as_expr()) j -= 1 # j = 0 SR_L.append(S.det()) return process_matrix_output(SR_L, x) def res(f, g, x): """ The input polynomials f, g are in Z[x] or in Q[x]. The output is the resultant of f, g computed by evaluating the determinant of the matrix sylvester(f, g, x, 1). References: =========== 1. J. S. Cohen: Computer Algebra and Symbolic Computation - Mathematical Methods. A. K. Peters, 2003. """ if f == 0 or g == 0: raise PolynomialError("The resultant of %s and %s is not defined" % (f, g)) else: return sylvester(f, g, x, 1).det() def res_q(f, g, x): """ The input polynomials f, g are in Z[x] or in Q[x]. The output is the resultant of f, g computed recursively by polynomial divisions in Q[x], using the function rem. See Cohen's book p. 281. References: =========== 1. J. S. Cohen: Computer Algebra and Symbolic Computation - Mathematical Methods. A. K. Peters, 2003. """ m = degree(f, x) n = degree(g, x) if m < n: return (-1)**(m*n) * res_q(g, f, x) elif n == 0: # g is a constant return g**m else: r = rem(f, g, x) if r == 0: return 0 else: s = degree(r, x) l = LC(g, x) return (-1)**(m*n) * l**(m-s)*res_q(g, r, x) def res_z(f, g, x): """ The input polynomials f, g are in Z[x] or in Q[x]. The output is the resultant of f, g computed recursively by polynomial divisions in Z[x], using the function prem(). See Cohen's book p. 283. References: =========== 1. J. S. Cohen: Computer Algebra and Symbolic Computation - Mathematical Methods. A. K. Peters, 2003. """ m = degree(f, x) n = degree(g, x) if m < n: return (-1)**(m*n) * res_z(g, f, x) elif n == 0: # g is a constant return g**m else: r = prem(f, g, x) if r == 0: return 0 else: delta = m - n + 1 w = (-1)**(m*n) * res_z(g, r, x) s = degree(r, x) l = LC(g, x) k = delta * n - m + s return quo(w, l**k, x) def sign_seq(poly_seq, x): """ Given a sequence of polynomials poly_seq, it returns the sequence of signs of the leading coefficients of the polynomials in poly_seq. """ return [sign(LC(poly_seq[i], x)) for i in range(len(poly_seq))] def bezout(p, q, x, method='bz'): """ The input polynomials p, q are in Z[x] or in Q[x]. Let mx = max( degree(p, x) , degree(q, x) ). The default option bezout(p, q, x, method='bz') returns Bezout's symmetric matrix of p and q, of dimensions (mx) x (mx). The determinant of this matrix is equal to the determinant of sylvester2, Sylvester's matrix of 1853, whose dimensions are (2*mx) x (2*mx); however the subresultants of these two matrices may differ. The other option, bezout(p, q, x, 'prs'), is of interest to us in this module because it returns a matrix equivalent to sylvester2. In this case all subresultants of the two matrices are identical. Both the subresultant polynomial remainder sequence (prs) and the modified subresultant prs of p and q can be computed by evaluating determinants of appropriately selected submatrices of bezout(p, q, x, 'prs') --- one determinant per coefficient of the remainder polynomials. The matrices bezout(p, q, x, 'bz') and bezout(p, q, x, 'prs') are related by the formula bezout(p, q, x, 'prs') = backward_eye(deg(p)) * bezout(p, q, x, 'bz') * backward_eye(deg(p)), where backward_eye() is the backward identity function. References ========== 1. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants and Their Applications. Appl. Algebra in Engin., Communic. and Comp., Vol. 15, 233-266, 2004. """ # obtain degrees of polys m, n = degree( Poly(p, x), x), degree( Poly(q, x), x) # Special cases: # A:: case m = n < 0 (i.e. both polys are 0) if m == n and n < 0: return Matrix([]) # B:: case m = n = 0 (i.e. both polys are constants) if m == n and n == 0: return Matrix([]) # C:: m == 0 and n < 0 or m < 0 and n == 0 # (i.e. one poly is constant and the other is 0) if m == 0 and n < 0: return Matrix([]) elif m < 0 and n == 0: return Matrix([]) # D:: m >= 1 and n < 0 or m < 0 and n >=1 # (i.e. one poly is of degree >=1 and the other is 0) if m >= 1 and n < 0: return Matrix([0]) elif m < 0 and n >= 1: return Matrix([0]) y = var('y') # expr is 0 when x = y expr = p * q.subs({x:y}) - p.subs({x:y}) * q # hence expr is exactly divisible by x - y poly = Poly( quo(expr, x-y), x, y) # form Bezout matrix and store them in B as indicated to get # the LC coefficient of each poly either in the first position # of each row (method='prs') or in the last (method='bz'). mx = max(m, n) B = zeros(mx) for i in range(mx): for j in range(mx): if method == 'prs': B[mx - 1 - i, mx - 1 - j] = poly.nth(i, j) else: B[i, j] = poly.nth(i, j) return B def backward_eye(n): ''' Returns the backward identity matrix of dimensions n x n. Needed to "turn" the Bezout matrices so that the leading coefficients are first. See docstring of the function bezout(p, q, x, method='bz'). ''' M = eye(n) # identity matrix of order n for i in range(int(M.rows / 2)): M.row_swap(0 + i, M.rows - 1 - i) return M def subresultants_bezout(p, q, x): """ The input polynomials p, q are in Z[x] or in Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the subresultant polynomial remainder sequence of p, q by evaluating determinants of appropriately selected submatrices of bezout(p, q, x, 'prs'). The dimensions of the latter are deg(p) x deg(p). Each coefficient is computed by evaluating the determinant of the corresponding submatrix of bezout(p, q, x, 'prs'). bezout(p, q, x, 'prs) is used instead of sylvester(p, q, x, 1), Sylvester's matrix of 1840, because the dimensions of the latter are (deg(p) + deg(q)) x (deg(p) + deg(q)). If the subresultant prs is complete, then the output coincides with the Euclidean sequence of the polynomials p, q. References ========== 1. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants and Their Applications. Appl. Algebra in Engin., Communic. and Comp., Vol. 15, 233-266, 2004. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] f, g = p, q n = degF = degree(f, x) m = degG = degree(g, x) # make sure proper degrees if n == 0 and m == 0: return [f, g] if n < m: n, m, degF, degG, f, g = m, n, degG, degF, g, f if n > 0 and m == 0: return [f, g] SR_L = [f, g] # subresultant list F = LC(f, x)**(degF - degG) # form the bezout matrix B = bezout(f, g, x, 'prs') # pick appropriate submatrices of B # and form subresultant polys if degF > degG: j = 2 if degF == degG: j = 1 while j <= degF: M = B[0:j, :] k, coeff_L = j - 1, [] while k <= degF - 1: coeff_L.append(M[: ,0 : j].det()) if k < degF - 1: M.col_swap(j - 1, k + 1) k = k + 1 # apply Theorem 2.1 in the paper by Toca & Vega 2004 # to get correct signs SR_L.append(int((-1)**(j*(j-1)/2)) * (Poly(coeff_L, x) / F).as_expr()) j = j + 1 return process_matrix_output(SR_L, x) def modified_subresultants_bezout(p, q, x): """ The input polynomials p, q are in Z[x] or in Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the modified subresultant polynomial remainder sequence of p, q by evaluating determinants of appropriately selected submatrices of bezout(p, q, x, 'prs'). The dimensions of the latter are deg(p) x deg(p). Each coefficient is computed by evaluating the determinant of the corresponding submatrix of bezout(p, q, x, 'prs'). bezout(p, q, x, 'prs') is used instead of sylvester(p, q, x, 2), Sylvester's matrix of 1853, because the dimensions of the latter are 2*deg(p) x 2*deg(p). If the modified subresultant prs is complete, and LC( p ) > 0, the output coincides with the (generalized) Sturm's sequence of the polynomials p, q. References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences.'' Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. 2. G.M.Diaz-Toca,L.Gonzalez-Vega: Various New Expressions for Subresultants and Their Applications. Appl. Algebra in Engin., Communic. and Comp., Vol. 15, 233-266, 2004. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] f, g = p, q n = degF = degree(f, x) m = degG = degree(g, x) # make sure proper degrees if n == 0 and m == 0: return [f, g] if n < m: n, m, degF, degG, f, g = m, n, degG, degF, g, f if n > 0 and m == 0: return [f, g] SR_L = [f, g] # subresultant list # form the bezout matrix B = bezout(f, g, x, 'prs') # pick appropriate submatrices of B # and form subresultant polys if degF > degG: j = 2 if degF == degG: j = 1 while j <= degF: M = B[0:j, :] k, coeff_L = j - 1, [] while k <= degF - 1: coeff_L.append(M[: ,0 : j].det()) if k < degF - 1: M.col_swap(j - 1, k + 1) k = k + 1 ## Theorem 2.1 in the paper by Toca & Vega 2004 is _not needed_ ## in this case since ## the bezout matrix is equivalent to sylvester2 SR_L.append(( Poly(coeff_L, x)).as_expr()) j = j + 1 return process_matrix_output(SR_L, x) def sturm_pg(p, q, x, method=0): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the (generalized) Sturm sequence of p and q in Z[x] or Q[x]. If q = diff(p, x, 1) it is the usual Sturm sequence. A. If method == 0, default, the remainder coefficients of the sequence are (in absolute value) ``modified'' subresultants, which for non-monic polynomials are greater than the coefficients of the corresponding subresultants by the factor Abs(LC(p)**( deg(p)- deg(q))). B. If method == 1, the remainder coefficients of the sequence are (in absolute value) subresultants, which for non-monic polynomials are smaller than the coefficients of the corresponding ``modified'' subresultants by the factor Abs(LC(p)**( deg(p)- deg(q))). If the Sturm sequence is complete, method=0 and LC( p ) > 0, the coefficients of the polynomials in the sequence are ``modified'' subresultants. That is, they are determinants of appropriately selected submatrices of sylvester2, Sylvester's matrix of 1853. In this case the Sturm sequence coincides with the ``modified'' subresultant prs, of the polynomials p, q. If the Sturm sequence is incomplete and method=0 then the signs of the coefficients of the polynomials in the sequence may differ from the signs of the coefficients of the corresponding polynomials in the ``modified'' subresultant prs; however, the absolute values are the same. To compute the coefficients, no determinant evaluation takes place. Instead, polynomial divisions in Q[x] are performed, using the function rem(p, q, x); the coefficients of the remainders computed this way become (``modified'') subresultants with the help of the Pell-Gordon Theorem of 1917. See also the function euclid_pg(p, q, x). References ========== 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding the Highest Common Factor of Two Polynomials. Annals of MatheMatics, Second Series, 18 (1917), No. 4, 188-193. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences.'' Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees d0 = degree(p, x) d1 = degree(q, x) if d0 == 0 and d1 == 0: return [p, q] if d1 > d0: d0, d1 = d1, d0 p, q = q, p if d0 > 0 and d1 == 0: return [p,q] # make sure LC(p) > 0 flag = 0 if LC(p,x) < 0: flag = 1 p = -p q = -q # initialize lcf = LC(p, x)**(d0 - d1) # lcf * subr = modified subr a0, a1 = p, q # the input polys sturm_seq = [a0, a1] # the output list del0 = d0 - d1 # degree difference rho1 = LC(a1, x) # leading coeff of a1 exp_deg = d1 - 1 # expected degree of a2 a2 = - rem(a0, a1, domain=QQ) # first remainder rho2 = LC(a2,x) # leading coeff of a2 d2 = degree(a2, x) # actual degree of a2 deg_diff_new = exp_deg - d2 # expected - actual degree del1 = d1 - d2 # degree difference # mul_fac is the factor by which a2 is multiplied to # get integer coefficients mul_fac_old = rho1**(del0 + del1 - deg_diff_new) # append accordingly if method == 0: sturm_seq.append( simplify(lcf * a2 * Abs(mul_fac_old))) else: sturm_seq.append( simplify( a2 * Abs(mul_fac_old))) # main loop deg_diff_old = deg_diff_new while d2 > 0: a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees del0 = del1 # update degree difference exp_deg = d1 - 1 # new expected degree a2 = - rem(a0, a1, domain=QQ) # new remainder rho3 = LC(a2, x) # leading coeff of a2 d2 = degree(a2, x) # actual degree of a2 deg_diff_new = exp_deg - d2 # expected - actual degree del1 = d1 - d2 # degree difference # take into consideration the power # rho1**deg_diff_old that was "left out" expo_old = deg_diff_old # rho1 raised to this power expo_new = del0 + del1 - deg_diff_new # rho2 raised to this power # update variables and append mul_fac_new = rho2**(expo_new) * rho1**(expo_old) * mul_fac_old deg_diff_old, mul_fac_old = deg_diff_new, mul_fac_new rho1, rho2 = rho2, rho3 if method == 0: sturm_seq.append( simplify(lcf * a2 * Abs(mul_fac_old))) else: sturm_seq.append( simplify( a2 * Abs(mul_fac_old))) if flag: # change the sign of the sequence sturm_seq = [-i for i in sturm_seq] # gcd is of degree > 0 ? m = len(sturm_seq) if sturm_seq[m - 1] == nan or sturm_seq[m - 1] == 0: sturm_seq.pop(m - 1) return sturm_seq def sturm_q(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the (generalized) Sturm sequence of p and q in Q[x]. Polynomial divisions in Q[x] are performed, using the function rem(p, q, x). The coefficients of the polynomials in the Sturm sequence can be uniquely determined from the corresponding coefficients of the polynomials found either in: (a) the ``modified'' subresultant prs, (references 1, 2) or in (b) the subresultant prs (reference 3). References ========== 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding the Highest Common Factor of Two Polynomials. Annals of MatheMatics, Second Series, 18 (1917), No. 4, 188-193. 2 Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences.'' Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees d0 = degree(p, x) d1 = degree(q, x) if d0 == 0 and d1 == 0: return [p, q] if d1 > d0: d0, d1 = d1, d0 p, q = q, p if d0 > 0 and d1 == 0: return [p,q] # make sure LC(p) > 0 flag = 0 if LC(p,x) < 0: flag = 1 p = -p q = -q # initialize a0, a1 = p, q # the input polys sturm_seq = [a0, a1] # the output list a2 = -rem(a0, a1, domain=QQ) # first remainder d2 = degree(a2, x) # degree of a2 sturm_seq.append( a2 ) # main loop while d2 > 0: a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees a2 = -rem(a0, a1, domain=QQ) # new remainder d2 = degree(a2, x) # actual degree of a2 sturm_seq.append( a2 ) if flag: # change the sign of the sequence sturm_seq = [-i for i in sturm_seq] # gcd is of degree > 0 ? m = len(sturm_seq) if sturm_seq[m - 1] == nan or sturm_seq[m - 1] == 0: sturm_seq.pop(m - 1) return sturm_seq def sturm_amv(p, q, x, method=0): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the (generalized) Sturm sequence of p and q in Z[x] or Q[x]. If q = diff(p, x, 1) it is the usual Sturm sequence. A. If method == 0, default, the remainder coefficients of the sequence are (in absolute value) ``modified'' subresultants, which for non-monic polynomials are greater than the coefficients of the corresponding subresultants by the factor Abs(LC(p)**( deg(p)- deg(q))). B. If method == 1, the remainder coefficients of the sequence are (in absolute value) subresultants, which for non-monic polynomials are smaller than the coefficients of the corresponding ``modified'' subresultants by the factor Abs( LC(p)**( deg(p)- deg(q)) ). If the Sturm sequence is complete, method=0 and LC( p ) > 0, then the coefficients of the polynomials in the sequence are ``modified'' subresultants. That is, they are determinants of appropriately selected submatrices of sylvester2, Sylvester's matrix of 1853. In this case the Sturm sequence coincides with the ``modified'' subresultant prs, of the polynomials p, q. If the Sturm sequence is incomplete and method=0 then the signs of the coefficients of the polynomials in the sequence may differ from the signs of the coefficients of the corresponding polynomials in the ``modified'' subresultant prs; however, the absolute values are the same. To compute the coefficients, no determinant evaluation takes place. Instead, we first compute the euclidean sequence of p and q using euclid_amv(p, q, x) and then: (a) change the signs of the remainders in the Euclidean sequence according to the pattern "-, -, +, +, -, -, +, +,..." (see Lemma 1 in the 1st reference or Theorem 3 in the 2nd reference) and (b) if method=0, assuming deg(p) > deg(q), we multiply the remainder coefficients of the Euclidean sequence times the factor Abs( LC(p)**( deg(p)- deg(q)) ) to make them modified subresultants. See also the function sturm_pg(p, q, x). References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On the Remainders Obtained in Finding the Greatest Common Divisor of Two Polynomials.'' Serdica Journal of Computing 9(2) (2015), 123-138. 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial Remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' Serdica Journal of Computing 10 (2016), No.3-4, 197-217. """ # compute the euclidean sequence prs = euclid_amv(p, q, x) # defensive if prs == [] or len(prs) == 2: return prs # the coefficients in prs are subresultants and hence are smaller # than the corresponding subresultants by the factor # Abs( LC(prs[0])**( deg(prs[0]) - deg(prs[1])) ); Theorem 2, 2nd reference. lcf = Abs( LC(prs[0])**( degree(prs[0], x) - degree(prs[1], x) ) ) # the signs of the first two polys in the sequence stay the same sturm_seq = [prs[0], prs[1]] # change the signs according to "-, -, +, +, -, -, +, +,..." # and multiply times lcf if needed flag = 0 m = len(prs) i = 2 while i <= m-1: if flag == 0: sturm_seq.append( - prs[i] ) i = i + 1 if i == m: break sturm_seq.append( - prs[i] ) i = i + 1 flag = 1 elif flag == 1: sturm_seq.append( prs[i] ) i = i + 1 if i == m: break sturm_seq.append( prs[i] ) i = i + 1 flag = 0 # subresultants or modified subresultants? if method == 0 and lcf > 1: aux_seq = [sturm_seq[0], sturm_seq[1]] for i in range(2, m): aux_seq.append(simplify(sturm_seq[i] * lcf )) sturm_seq = aux_seq return sturm_seq def euclid_pg(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the Euclidean sequence of p and q in Z[x] or Q[x]. If the Euclidean sequence is complete the coefficients of the polynomials in the sequence are subresultants. That is, they are determinants of appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. In this case the Euclidean sequence coincides with the subresultant prs of the polynomials p, q. If the Euclidean sequence is incomplete the signs of the coefficients of the polynomials in the sequence may differ from the signs of the coefficients of the corresponding polynomials in the subresultant prs; however, the absolute values are the same. To compute the Euclidean sequence, no determinant evaluation takes place. We first compute the (generalized) Sturm sequence of p and q using sturm_pg(p, q, x, 1), in which case the coefficients are (in absolute value) equal to subresultants. Then we change the signs of the remainders in the Sturm sequence according to the pattern "-, -, +, +, -, -, +, +,..." ; see Lemma 1 in the 1st reference or Theorem 3 in the 2nd reference as well as the function sturm_pg(p, q, x). References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On the Remainders Obtained in Finding the Greatest Common Divisor of Two Polynomials.'' Serdica Journal of Computing 9(2) (2015), 123-138. 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial Remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' Serdica Journal of Computing 10 (2016), No.3-4, 197-217. """ # compute the sturmian sequence using the Pell-Gordon (or AMV) theorem # with the coefficients in the prs being (in absolute value) subresultants prs = sturm_pg(p, q, x, 1) ## any other method would do # defensive if prs == [] or len(prs) == 2: return prs # the signs of the first two polys in the sequence stay the same euclid_seq = [prs[0], prs[1]] # change the signs according to "-, -, +, +, -, -, +, +,..." flag = 0 m = len(prs) i = 2 while i <= m-1: if flag == 0: euclid_seq.append(- prs[i] ) i = i + 1 if i == m: break euclid_seq.append(- prs[i] ) i = i + 1 flag = 1 elif flag == 1: euclid_seq.append(prs[i] ) i = i + 1 if i == m: break euclid_seq.append(prs[i] ) i = i + 1 flag = 0 return euclid_seq def euclid_q(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the Euclidean sequence of p and q in Q[x]. Polynomial divisions in Q[x] are performed, using the function rem(p, q, x). The coefficients of the polynomials in the Euclidean sequence can be uniquely determined from the corresponding coefficients of the polynomials found either in: (a) the ``modified'' subresultant polynomial remainder sequence, (references 1, 2) or in (b) the subresultant polynomial remainder sequence (references 3). References ========== 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding the Highest Common Factor of Two Polynomials. Annals of MatheMatics, Second Series, 18 (1917), No. 4, 188-193. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences.'' Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees d0 = degree(p, x) d1 = degree(q, x) if d0 == 0 and d1 == 0: return [p, q] if d1 > d0: d0, d1 = d1, d0 p, q = q, p if d0 > 0 and d1 == 0: return [p,q] # make sure LC(p) > 0 flag = 0 if LC(p,x) < 0: flag = 1 p = -p q = -q # initialize a0, a1 = p, q # the input polys euclid_seq = [a0, a1] # the output list a2 = rem(a0, a1, domain=QQ) # first remainder d2 = degree(a2, x) # degree of a2 euclid_seq.append( a2 ) # main loop while d2 > 0: a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees a2 = rem(a0, a1, domain=QQ) # new remainder d2 = degree(a2, x) # actual degree of a2 euclid_seq.append( a2 ) if flag: # change the sign of the sequence euclid_seq = [-i for i in euclid_seq] # gcd is of degree > 0 ? m = len(euclid_seq) if euclid_seq[m - 1] == nan or euclid_seq[m - 1] == 0: euclid_seq.pop(m - 1) return euclid_seq def euclid_amv(f, g, x): """ f, g are polynomials in Z[x] or Q[x]. It is assumed that degree(f, x) >= degree(g, x). Computes the Euclidean sequence of p and q in Z[x] or Q[x]. If the Euclidean sequence is complete the coefficients of the polynomials in the sequence are subresultants. That is, they are determinants of appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. In this case the Euclidean sequence coincides with the subresultant prs, of the polynomials p, q. If the Euclidean sequence is incomplete the signs of the coefficients of the polynomials in the sequence may differ from the signs of the coefficients of the corresponding polynomials in the subresultant prs; however, the absolute values are the same. To compute the coefficients, no determinant evaluation takes place. Instead, polynomial divisions in Z[x] or Q[x] are performed, using the function rem_z(f, g, x); the coefficients of the remainders computed this way become subresultants with the help of the Collins-Brown-Traub formula for coefficient reduction. References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' Serdica Journal of Computing 10 (2016), No.3-4, 197-217. """ # make sure neither f nor g is 0 if f == 0 or g == 0: return [f, g] # make sure proper degrees d0 = degree(f, x) d1 = degree(g, x) if d0 == 0 and d1 == 0: return [f, g] if d1 > d0: d0, d1 = d1, d0 f, g = g, f if d0 > 0 and d1 == 0: return [f, g] # initialize a0 = f a1 = g euclid_seq = [a0, a1] deg_dif_p1, c = degree(a0, x) - degree(a1, x) + 1, -1 # compute the first polynomial of the prs i = 1 a2 = rem_z(a0, a1, x) / Abs( (-1)**deg_dif_p1 ) # first remainder euclid_seq.append( a2 ) d2 = degree(a2, x) # actual degree of a2 # main loop while d2 >= 1: a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees i += 1 sigma0 = -LC(a0) c = (sigma0**(deg_dif_p1 - 1)) / (c**(deg_dif_p1 - 2)) deg_dif_p1 = degree(a0, x) - d2 + 1 a2 = rem_z(a0, a1, x) / Abs( (c**(deg_dif_p1 - 1)) * sigma0 ) euclid_seq.append( a2 ) d2 = degree(a2, x) # actual degree of a2 # gcd is of degree > 0 ? m = len(euclid_seq) if euclid_seq[m - 1] == nan or euclid_seq[m - 1] == 0: euclid_seq.pop(m - 1) return euclid_seq def modified_subresultants_pg(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the ``modified'' subresultant prs of p and q in Z[x] or Q[x]; the coefficients of the polynomials in the sequence are ``modified'' subresultants. That is, they are determinants of appropriately selected submatrices of sylvester2, Sylvester's matrix of 1853. To compute the coefficients, no determinant evaluation takes place. Instead, polynomial divisions in Q[x] are performed, using the function rem(p, q, x); the coefficients of the remainders computed this way become ``modified'' subresultants with the help of the Pell-Gordon Theorem of 1917. If the ``modified'' subresultant prs is complete, and LC( p ) > 0, it coincides with the (generalized) Sturm sequence of the polynomials p, q. References ========== 1. Pell A. J., R. L. Gordon. The Modified Remainders Obtained in Finding the Highest Common Factor of Two Polynomials. Annals of MatheMatics, Second Series, 18 (1917), No. 4, 188-193. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences.'' Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees d0 = degree(p,x) d1 = degree(q,x) if d0 == 0 and d1 == 0: return [p, q] if d1 > d0: d0, d1 = d1, d0 p, q = q, p if d0 > 0 and d1 == 0: return [p,q] # initialize k = var('k') # index in summation formula u_list = [] # of elements (-1)**u_i subres_l = [p, q] # mod. subr. prs output list a0, a1 = p, q # the input polys del0 = d0 - d1 # degree difference degdif = del0 # save it rho_1 = LC(a0) # lead. coeff (a0) # Initialize Pell-Gordon variables rho_list_minus_1 = sign( LC(a0, x)) # sign of LC(a0) rho1 = LC(a1, x) # leading coeff of a1 rho_list = [ sign(rho1)] # of signs p_list = [del0] # of degree differences u = summation(k, (k, 1, p_list[0])) # value of u u_list.append(u) # of u values v = sum(p_list) # v value # first remainder exp_deg = d1 - 1 # expected degree of a2 a2 = - rem(a0, a1, domain=QQ) # first remainder rho2 = LC(a2, x) # leading coeff of a2 d2 = degree(a2, x) # actual degree of a2 deg_diff_new = exp_deg - d2 # expected - actual degree del1 = d1 - d2 # degree difference # mul_fac is the factor by which a2 is multiplied to # get integer coefficients mul_fac_old = rho1**(del0 + del1 - deg_diff_new) # update Pell-Gordon variables p_list.append(1 + deg_diff_new) # deg_diff_new is 0 for complete seq # apply Pell-Gordon formula (7) in second reference num = 1 # numerator of fraction for k in range(len(u_list)): num *= (-1)**u_list[k] num = num * (-1)**v # denominator depends on complete / incomplete seq if deg_diff_new == 0: # complete seq den = 1 for k in range(len(rho_list)): den *= rho_list[k]**(p_list[k] + p_list[k + 1]) den = den * rho_list_minus_1 else: # incomplete seq den = 1 for k in range(len(rho_list)-1): den *= rho_list[k]**(p_list[k] + p_list[k + 1]) den = den * rho_list_minus_1 expo = (p_list[len(rho_list) - 1] + p_list[len(rho_list)] - deg_diff_new) den = den * rho_list[len(rho_list) - 1]**expo # the sign of the determinant depends on sg(num / den) if sign(num / den) > 0: subres_l.append( simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) else: subres_l.append(- simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) # update Pell-Gordon variables k = var('k') rho_list.append( sign(rho2)) u = summation(k, (k, 1, p_list[len(p_list) - 1])) u_list.append(u) v = sum(p_list) deg_diff_old=deg_diff_new # main loop while d2 > 0: a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees del0 = del1 # update degree difference exp_deg = d1 - 1 # new expected degree a2 = - rem(a0, a1, domain=QQ) # new remainder rho3 = LC(a2, x) # leading coeff of a2 d2 = degree(a2, x) # actual degree of a2 deg_diff_new = exp_deg - d2 # expected - actual degree del1 = d1 - d2 # degree difference # take into consideration the power # rho1**deg_diff_old that was "left out" expo_old = deg_diff_old # rho1 raised to this power expo_new = del0 + del1 - deg_diff_new # rho2 raised to this power mul_fac_new = rho2**(expo_new) * rho1**(expo_old) * mul_fac_old # update variables deg_diff_old, mul_fac_old = deg_diff_new, mul_fac_new rho1, rho2 = rho2, rho3 # update Pell-Gordon variables p_list.append(1 + deg_diff_new) # deg_diff_new is 0 for complete seq # apply Pell-Gordon formula (7) in second reference num = 1 # numerator for k in range(len(u_list)): num *= (-1)**u_list[k] num = num * (-1)**v # denominator depends on complete / incomplete seq if deg_diff_new == 0: # complete seq den = 1 for k in range(len(rho_list)): den *= rho_list[k]**(p_list[k] + p_list[k + 1]) den = den * rho_list_minus_1 else: # incomplete seq den = 1 for k in range(len(rho_list)-1): den *= rho_list[k]**(p_list[k] + p_list[k + 1]) den = den * rho_list_minus_1 expo = (p_list[len(rho_list) - 1] + p_list[len(rho_list)] - deg_diff_new) den = den * rho_list[len(rho_list) - 1]**expo # the sign of the determinant depends on sg(num / den) if sign(num / den) > 0: subres_l.append( simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) else: subres_l.append(- simplify(rho_1**degdif*a2* Abs(mul_fac_old) ) ) # update Pell-Gordon variables k = var('k') rho_list.append( sign(rho2)) u = summation(k, (k, 1, p_list[len(p_list) - 1])) u_list.append(u) v = sum(p_list) # gcd is of degree > 0 ? m = len(subres_l) if subres_l[m - 1] == nan or subres_l[m - 1] == 0: subres_l.pop(m - 1) # LC( p ) < 0 m = len(subres_l) # list may be shorter now due to deg(gcd ) > 0 if LC( p ) < 0: aux_seq = [subres_l[0], subres_l[1]] for i in range(2, m): aux_seq.append(simplify(subres_l[i] * (-1) )) subres_l = aux_seq return subres_l def subresultants_pg(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the subresultant prs of p and q in Z[x] or Q[x], from the modified subresultant prs of p and q. The coefficients of the polynomials in these two sequences differ only in sign and the factor LC(p)**( deg(p)- deg(q)) as stated in Theorem 2 of the reference. The coefficients of the polynomials in the output sequence are subresultants. That is, they are determinants of appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. If the subresultant prs is complete, then it coincides with the Euclidean sequence of the polynomials p, q. References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: "On the Remainders Obtained in Finding the Greatest Common Divisor of Two Polynomials." Serdica Journal of Computing 9(2) (2015), 123-138. """ # compute the modified subresultant prs lst = modified_subresultants_pg(p,q,x) ## any other method would do # defensive if lst == [] or len(lst) == 2: return lst # the coefficients in lst are modified subresultants and, hence, are # greater than those of the corresponding subresultants by the factor # LC(lst[0])**( deg(lst[0]) - deg(lst[1])); see Theorem 2 in reference. lcf = LC(lst[0])**( degree(lst[0], x) - degree(lst[1], x) ) # Initialize the subresultant prs list subr_seq = [lst[0], lst[1]] # compute the degree sequences m_i and j_i of Theorem 2 in reference. deg_seq = [degree(Poly(poly, x), x) for poly in lst] deg = deg_seq[0] deg_seq_s = deg_seq[1:-1] m_seq = [m-1 for m in deg_seq_s] j_seq = [deg - m for m in m_seq] # compute the AMV factors of Theorem 2 in reference. fact = [(-1)**( j*(j-1)/S(2) ) for j in j_seq] # shortened list without the first two polys lst_s = lst[2:] # poly lst_s[k] is multiplied times fact[k], divided by lcf # and appended to the subresultant prs list m = len(fact) for k in range(m): if sign(fact[k]) == -1: subr_seq.append(-lst_s[k] / lcf) else: subr_seq.append(lst_s[k] / lcf) return subr_seq def subresultants_amv_q(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the subresultant prs of p and q in Q[x]; the coefficients of the polynomials in the sequence are subresultants. That is, they are determinants of appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. To compute the coefficients, no determinant evaluation takes place. Instead, polynomial divisions in Q[x] are performed, using the function rem(p, q, x); the coefficients of the remainders computed this way become subresultants with the help of the Akritas-Malaschonok-Vigklas Theorem of 2015. If the subresultant prs is complete, then it coincides with the Euclidean sequence of the polynomials p, q. References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' Serdica Journal of Computing 10 (2016), No.3-4, 197-217. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees d0 = degree(p, x) d1 = degree(q, x) if d0 == 0 and d1 == 0: return [p, q] if d1 > d0: d0, d1 = d1, d0 p, q = q, p if d0 > 0 and d1 == 0: return [p, q] # initialize i, s = 0, 0 # counters for remainders & odd elements p_odd_index_sum = 0 # contains the sum of p_1, p_3, etc subres_l = [p, q] # subresultant prs output list a0, a1 = p, q # the input polys sigma1 = LC(a1, x) # leading coeff of a1 p0 = d0 - d1 # degree difference if p0 % 2 == 1: s += 1 phi = floor( (s + 1) / 2 ) mul_fac = 1 d2 = d1 # main loop while d2 > 0: i += 1 a2 = rem(a0, a1, domain= QQ) # new remainder if i == 1: sigma2 = LC(a2, x) else: sigma3 = LC(a2, x) sigma1, sigma2 = sigma2, sigma3 d2 = degree(a2, x) p1 = d1 - d2 psi = i + phi + p_odd_index_sum # new mul_fac mul_fac = sigma1**(p0 + 1) * mul_fac ## compute the sign of the first fraction in formula (9) of the paper # numerator num = (-1)**psi # denominator den = sign(mul_fac) # the sign of the determinant depends on sign( num / den ) != 0 if sign(num / den) > 0: subres_l.append( simplify(expand(a2* Abs(mul_fac)))) else: subres_l.append(- simplify(expand(a2* Abs(mul_fac)))) ## bring into mul_fac the missing power of sigma if there was a degree gap if p1 - 1 > 0: mul_fac = mul_fac * sigma1**(p1 - 1) # update AMV variables a0, a1, d0, d1 = a1, a2, d1, d2 p0 = p1 if p0 % 2 ==1: s += 1 phi = floor( (s + 1) / 2 ) if i%2 == 1: p_odd_index_sum += p0 # p_i has odd index # gcd is of degree > 0 ? m = len(subres_l) if subres_l[m - 1] == nan or subres_l[m - 1] == 0: subres_l.pop(m - 1) return subres_l def compute_sign(base, expo): ''' base != 0 and expo >= 0 are integers; returns the sign of base**expo without evaluating the power itself! ''' sb = sign(base) if sb == 1: return 1 pe = expo % 2 if pe == 0: return -sb else: return sb def rem_z(p, q, x): ''' Intended mainly for p, q polynomials in Z[x] so that, on dividing p by q, the remainder will also be in Z[x]. (However, it also works fine for polynomials in Q[x].) It is assumed that degree(p, x) >= degree(q, x). It premultiplies p by the _absolute_ value of the leading coefficient of q, raised to the power deg(p) - deg(q) + 1 and then performs polynomial division in Q[x], using the function rem(p, q, x). By contrast the function prem(p, q, x) does _not_ use the absolute value of the leading coefficient of q. This results not only in ``messing up the signs'' of the Euclidean and Sturmian prs's as mentioned in the second reference, but also in violation of the main results of the first and third references --- Theorem 4 and Theorem 1 respectively. Theorems 4 and 1 establish a one-to-one correspondence between the Euclidean and the Sturmian prs of p, q, on one hand, and the subresultant prs of p, q, on the other. References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On the Remainders Obtained in Finding the Greatest Common Divisor of Two Polynomials.'' Serdica Journal of Computing, 9(2) (2015), 123-138. 2. http://planetMath.org/sturmstheorem 3. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. ''' if (p.as_poly().is_univariate and q.as_poly().is_univariate and p.as_poly().gens == q.as_poly().gens): delta = (degree(p, x) - degree(q, x) + 1) return rem(Abs(LC(q, x))**delta * p, q, x) else: return prem(p, q, x) def quo_z(p, q, x): """ Intended mainly for p, q polynomials in Z[x] so that, on dividing p by q, the quotient will also be in Z[x]. (However, it also works fine for polynomials in Q[x].) It is assumed that degree(p, x) >= degree(q, x). It premultiplies p by the _absolute_ value of the leading coefficient of q, raised to the power deg(p) - deg(q) + 1 and then performs polynomial division in Q[x], using the function quo(p, q, x). By contrast the function pquo(p, q, x) does _not_ use the absolute value of the leading coefficient of q. See also function rem_z(p, q, x) for additional comments and references. """ if (p.as_poly().is_univariate and q.as_poly().is_univariate and p.as_poly().gens == q.as_poly().gens): delta = (degree(p, x) - degree(q, x) + 1) return quo(Abs(LC(q, x))**delta * p, q, x) else: return pquo(p, q, x) def subresultants_amv(f, g, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(f, x) >= degree(g, x). Computes the subresultant prs of p and q in Z[x] or Q[x]; the coefficients of the polynomials in the sequence are subresultants. That is, they are determinants of appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. To compute the coefficients, no determinant evaluation takes place. Instead, polynomial divisions in Z[x] or Q[x] are performed, using the function rem_z(p, q, x); the coefficients of the remainders computed this way become subresultants with the help of the Akritas-Malaschonok-Vigklas Theorem of 2015 and the Collins-Brown- Traub formula for coefficient reduction. If the subresultant prs is complete, then it coincides with the Euclidean sequence of the polynomials p, q. References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``A Basic Result on the Theory of Subresultants.'' Serdica Journal of Computing 10 (2016), No.1, 31-48. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Subresultant Polynomial remainder Sequences Obtained by Polynomial Divisions in Q[x] or in Z[x].'' Serdica Journal of Computing 10 (2016), No.3-4, 197-217. """ # make sure neither f nor g is 0 if f == 0 or g == 0: return [f, g] # make sure proper degrees d0 = degree(f, x) d1 = degree(g, x) if d0 == 0 and d1 == 0: return [f, g] if d1 > d0: d0, d1 = d1, d0 f, g = g, f if d0 > 0 and d1 == 0: return [f, g] # initialize a0 = f a1 = g subres_l = [a0, a1] deg_dif_p1, c = degree(a0, x) - degree(a1, x) + 1, -1 # initialize AMV variables sigma1 = LC(a1, x) # leading coeff of a1 i, s = 0, 0 # counters for remainders & odd elements p_odd_index_sum = 0 # contains the sum of p_1, p_3, etc p0 = deg_dif_p1 - 1 if p0 % 2 == 1: s += 1 phi = floor( (s + 1) / 2 ) # compute the first polynomial of the prs i += 1 a2 = rem_z(a0, a1, x) / Abs( (-1)**deg_dif_p1 ) # first remainder sigma2 = LC(a2, x) # leading coeff of a2 d2 = degree(a2, x) # actual degree of a2 p1 = d1 - d2 # degree difference # sgn_den is the factor, the denominator 1st fraction of (9), # by which a2 is multiplied to get integer coefficients sgn_den = compute_sign( sigma1, p0 + 1 ) ## compute sign of the 1st fraction in formula (9) of the paper # numerator psi = i + phi + p_odd_index_sum num = (-1)**psi # denominator den = sgn_den # the sign of the determinant depends on sign(num / den) != 0 if sign(num / den) > 0: subres_l.append( a2 ) else: subres_l.append( -a2 ) # update AMV variable if p1 % 2 == 1: s += 1 # bring in the missing power of sigma if there was gap if p1 - 1 > 0: sgn_den = sgn_den * compute_sign( sigma1, p1 - 1 ) # main loop while d2 >= 1: phi = floor( (s + 1) / 2 ) if i%2 == 1: p_odd_index_sum += p1 # p_i has odd index a0, a1, d0, d1 = a1, a2, d1, d2 # update polys and degrees p0 = p1 # update degree difference i += 1 sigma0 = -LC(a0) c = (sigma0**(deg_dif_p1 - 1)) / (c**(deg_dif_p1 - 2)) deg_dif_p1 = degree(a0, x) - d2 + 1 a2 = rem_z(a0, a1, x) / Abs( (c**(deg_dif_p1 - 1)) * sigma0 ) sigma3 = LC(a2, x) # leading coeff of a2 d2 = degree(a2, x) # actual degree of a2 p1 = d1 - d2 # degree difference psi = i + phi + p_odd_index_sum # update variables sigma1, sigma2 = sigma2, sigma3 # new sgn_den sgn_den = compute_sign( sigma1, p0 + 1 ) * sgn_den # compute the sign of the first fraction in formula (9) of the paper # numerator num = (-1)**psi # denominator den = sgn_den # the sign of the determinant depends on sign( num / den ) != 0 if sign(num / den) > 0: subres_l.append( a2 ) else: subres_l.append( -a2 ) # update AMV variable if p1 % 2 ==1: s += 1 # bring in the missing power of sigma if there was gap if p1 - 1 > 0: sgn_den = sgn_den * compute_sign( sigma1, p1 - 1 ) # gcd is of degree > 0 ? m = len(subres_l) if subres_l[m - 1] == nan or subres_l[m - 1] == 0: subres_l.pop(m - 1) return subres_l def modified_subresultants_amv(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the modified subresultant prs of p and q in Z[x] or Q[x], from the subresultant prs of p and q. The coefficients of the polynomials in the two sequences differ only in sign and the factor LC(p)**( deg(p)- deg(q)) as stated in Theorem 2 of the reference. The coefficients of the polynomials in the output sequence are modified subresultants. That is, they are determinants of appropriately selected submatrices of sylvester2, Sylvester's matrix of 1853. If the modified subresultant prs is complete, and LC( p ) > 0, it coincides with the (generalized) Sturm's sequence of the polynomials p, q. References ========== 1. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: "On the Remainders Obtained in Finding the Greatest Common Divisor of Two Polynomials." Serdica Journal of Computing, Serdica Journal of Computing, 9(2) (2015), 123-138. """ # compute the subresultant prs lst = subresultants_amv(p,q,x) ## any other method would do # defensive if lst == [] or len(lst) == 2: return lst # the coefficients in lst are subresultants and, hence, smaller than those # of the corresponding modified subresultants by the factor # LC(lst[0])**( deg(lst[0]) - deg(lst[1])); see Theorem 2. lcf = LC(lst[0])**( degree(lst[0], x) - degree(lst[1], x) ) # Initialize the modified subresultant prs list subr_seq = [lst[0], lst[1]] # compute the degree sequences m_i and j_i of Theorem 2 deg_seq = [degree(Poly(poly, x), x) for poly in lst] deg = deg_seq[0] deg_seq_s = deg_seq[1:-1] m_seq = [m-1 for m in deg_seq_s] j_seq = [deg - m for m in m_seq] # compute the AMV factors of Theorem 2 fact = [(-1)**( j*(j-1)/S(2) ) for j in j_seq] # shortened list without the first two polys lst_s = lst[2:] # poly lst_s[k] is multiplied times fact[k] and times lcf # and appended to the subresultant prs list m = len(fact) for k in range(m): if sign(fact[k]) == -1: subr_seq.append( simplify(-lst_s[k] * lcf) ) else: subr_seq.append( simplify(lst_s[k] * lcf) ) return subr_seq def correct_sign(deg_f, deg_g, s1, rdel, cdel): """ Used in various subresultant prs algorithms. Evaluates the determinant, (a.k.a. subresultant) of a properly selected submatrix of s1, Sylvester's matrix of 1840, to get the correct sign and value of the leading coefficient of a given polynomial remainder. deg_f, deg_g are the degrees of the original polynomials p, q for which the matrix s1 = sylvester(p, q, x, 1) was constructed. rdel denotes the expected degree of the remainder; it is the number of rows to be deleted from each group of rows in s1 as described in the reference below. cdel denotes the expected degree minus the actual degree of the remainder; it is the number of columns to be deleted --- starting with the last column forming the square matrix --- from the matrix resulting after the row deletions. References ========== Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``Sturm Sequences and Modified Subresultant Polynomial Remainder Sequences.'' Serdica Journal of Computing, Vol. 8, No 1, 29-46, 2014. """ M = s1[:, :] # copy of matrix s1 # eliminate rdel rows from the first deg_g rows for i in range(M.rows - deg_f - 1, M.rows - deg_f - rdel - 1, -1): M.row_del(i) # eliminate rdel rows from the last deg_f rows for i in range(M.rows - 1, M.rows - rdel - 1, -1): M.row_del(i) # eliminate cdel columns for i in range(cdel): M.col_del(M.rows - 1) # define submatrix Md = M[:, 0: M.rows] return Md.det() def subresultants_rem(p, q, x): """ p, q are polynomials in Z[x] or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the subresultant prs of p and q in Z[x] or Q[x]; the coefficients of the polynomials in the sequence are subresultants. That is, they are determinants of appropriately selected submatrices of sylvester1, Sylvester's matrix of 1840. To compute the coefficients polynomial divisions in Q[x] are performed, using the function rem(p, q, x). The coefficients of the remainders computed this way become subresultants by evaluating one subresultant per remainder --- that of the leading coefficient. This way we obtain the correct sign and value of the leading coefficient of the remainder and we easily ``force'' the rest of the coefficients to become subresultants. If the subresultant prs is complete, then it coincides with the Euclidean sequence of the polynomials p, q. References ========== 1. Akritas, A. G.:``Three New Methods for Computing Subresultant Polynomial Remainder Sequences (PRS's).'' Serdica Journal of Computing 9(1) (2015), 1-26. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees f, g = p, q n = deg_f = degree(f, x) m = deg_g = degree(g, x) if n == 0 and m == 0: return [f, g] if n < m: n, m, deg_f, deg_g, f, g = m, n, deg_g, deg_f, g, f if n > 0 and m == 0: return [f, g] # initialize s1 = sylvester(f, g, x, 1) sr_list = [f, g] # subresultant list # main loop while deg_g > 0: r = rem(p, q, x) d = degree(r, x) if d < 0: return sr_list # make coefficients subresultants evaluating ONE determinant exp_deg = deg_g - 1 # expected degree sign_value = correct_sign(n, m, s1, exp_deg, exp_deg - d) r = simplify((r / LC(r, x)) * sign_value) # append poly with subresultant coeffs sr_list.append(r) # update degrees and polys deg_f, deg_g = deg_g, d p, q = q, r # gcd is of degree > 0 ? m = len(sr_list) if sr_list[m - 1] == nan or sr_list[m - 1] == 0: sr_list.pop(m - 1) return sr_list def pivot(M, i, j): ''' M is a matrix, and M[i, j] specifies the pivot element. All elements below M[i, j], in the j-th column, will be zeroed, if they are not already 0, according to Dodgson-Bareiss' integer preserving transformations. References ========== 1. Akritas, A. G.: ``A new method for computing polynomial greatest common divisors and polynomial remainder sequences.'' Numerische MatheMatik 52, 119-127, 1988. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem by Van Vleck Regarding Sturm Sequences.'' Serdica Journal of Computing, 7, No 4, 101-134, 2013. ''' ma = M[:, :] # copy of matrix M rs = ma.rows # No. of rows cs = ma.cols # No. of cols for r in range(i+1, rs): if ma[r, j] != 0: for c in range(j + 1, cs): ma[r, c] = ma[i, j] * ma[r, c] - ma[i, c] * ma[r, j] ma[r, j] = 0 return ma def rotate_r(L, k): ''' Rotates right by k. L is a row of a matrix or a list. ''' ll = list(L) if ll == []: return [] for i in range(k): el = ll.pop(len(ll) - 1) ll.insert(0, el) return ll if type(L) is list else Matrix([ll]) def rotate_l(L, k): ''' Rotates left by k. L is a row of a matrix or a list. ''' ll = list(L) if ll == []: return [] for i in range(k): el = ll.pop(0) ll.insert(len(ll) - 1, el) return ll if type(L) is list else Matrix([ll]) def row2poly(row, deg, x): ''' Converts the row of a matrix to a poly of degree deg and variable x. Some entries at the beginning and/or at the end of the row may be zero. ''' k = 0 poly = [] leng = len(row) # find the beginning of the poly ; i.e. the first # non-zero element of the row while row[k] == 0: k = k + 1 # append the next deg + 1 elements to poly for j in range( deg + 1): if k + j <= leng: poly.append(row[k + j]) return Poly(poly, x) def create_ma(deg_f, deg_g, row1, row2, col_num): ''' Creates a ``small'' matrix M to be triangularized. deg_f, deg_g are the degrees of the divident and of the divisor polynomials respectively, deg_g > deg_f. The coefficients of the divident poly are the elements in row2 and those of the divisor poly are the elements in row1. col_num defines the number of columns of the matrix M. ''' if deg_g - deg_f >= 1: print('Reverse degrees') return m = zeros(deg_f - deg_g + 2, col_num) for i in range(deg_f - deg_g + 1): m[i, :] = rotate_r(row1, i) m[deg_f - deg_g + 1, :] = row2 return m def find_degree(M, deg_f): ''' Finds the degree of the poly corresponding (after triangularization) to the _last_ row of the ``small'' matrix M, created by create_ma(). deg_f is the degree of the divident poly. If _last_ row is all 0's returns None. ''' j = deg_f for i in range(0, M.cols): if M[M.rows - 1, i] == 0: j = j - 1 else: return j if j >= 0 else 0 def final_touches(s2, r, deg_g): """ s2 is sylvester2, r is the row pointer in s2, deg_g is the degree of the poly last inserted in s2. After a gcd of degree > 0 has been found with Van Vleck's method, and was inserted into s2, if its last term is not in the last column of s2, then it is inserted as many times as needed, rotated right by one each time, until the condition is met. """ R = s2.row(r-1) # find the first non zero term for i in range(s2.cols): if R[0,i] == 0: continue else: break # missing rows until last term is in last column mr = s2.cols - (i + deg_g + 1) # insert them by replacing the existing entries in the row i = 0 while mr != 0 and r + i < s2.rows : s2[r + i, : ] = rotate_r(R, i + 1) i += 1 mr -= 1 return s2 def subresultants_vv(p, q, x, method = 0): """ p, q are polynomials in Z[x] (intended) or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the subresultant prs of p, q by triangularizing, in Z[x] or in Q[x], all the smaller matrices encountered in the process of triangularizing sylvester2, Sylvester's matrix of 1853; see references 1 and 2 for Van Vleck's method. With each remainder, sylvester2 gets updated and is prepared to be printed if requested. If sylvester2 has small dimensions and you want to see the final, triangularized matrix use this version with method=1; otherwise, use either this version with method=0 (default) or the faster version, subresultants_vv_2(p, q, x), where sylvester2 is used implicitly. Sylvester's matrix sylvester1 is also used to compute one subresultant per remainder; namely, that of the leading coefficient, in order to obtain the correct sign and to force the remainder coefficients to become subresultants. If the subresultant prs is complete, then it coincides with the Euclidean sequence of the polynomials p, q. If the final, triangularized matrix s2 is printed, then: (a) if deg(p) - deg(q) > 1 or deg( gcd(p, q) ) > 0, several of the last rows in s2 will remain unprocessed; (b) if deg(p) - deg(q) == 0, p will not appear in the final matrix. References ========== 1. Akritas, A. G.: ``A new method for computing polynomial greatest common divisors and polynomial remainder sequences.'' Numerische MatheMatik 52, 119-127, 1988. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem by Van Vleck Regarding Sturm Sequences.'' Serdica Journal of Computing, 7, No 4, 101-134, 2013. 3. Akritas, A. G.:``Three New Methods for Computing Subresultant Polynomial Remainder Sequences (PRS's).'' Serdica Journal of Computing 9(1) (2015), 1-26. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees f, g = p, q n = deg_f = degree(f, x) m = deg_g = degree(g, x) if n == 0 and m == 0: return [f, g] if n < m: n, m, deg_f, deg_g, f, g = m, n, deg_g, deg_f, g, f if n > 0 and m == 0: return [f, g] # initialize s1 = sylvester(f, g, x, 1) s2 = sylvester(f, g, x, 2) sr_list = [f, g] col_num = 2 * n # columns in s2 # make two rows (row0, row1) of poly coefficients row0 = Poly(f, x, domain = QQ).all_coeffs() leng0 = len(row0) for i in range(col_num - leng0): row0.append(0) row0 = Matrix([row0]) row1 = Poly(g,x, domain = QQ).all_coeffs() leng1 = len(row1) for i in range(col_num - leng1): row1.append(0) row1 = Matrix([row1]) # row pointer for deg_f - deg_g == 1; may be reset below r = 2 # modify first rows of s2 matrix depending on poly degrees if deg_f - deg_g > 1: r = 1 # replacing the existing entries in the rows of s2, # insert row0 (deg_f - deg_g - 1) times, rotated each time for i in range(deg_f - deg_g - 1): s2[r + i, : ] = rotate_r(row0, i + 1) r = r + deg_f - deg_g - 1 # insert row1 (deg_f - deg_g) times, rotated each time for i in range(deg_f - deg_g): s2[r + i, : ] = rotate_r(row1, r + i) r = r + deg_f - deg_g if deg_f - deg_g == 0: r = 0 # main loop while deg_g > 0: # create a small matrix M, and triangularize it; M = create_ma(deg_f, deg_g, row1, row0, col_num) # will need only the first and last rows of M for i in range(deg_f - deg_g + 1): M1 = pivot(M, i, i) M = M1[:, :] # treat last row of M as poly; find its degree d = find_degree(M, deg_f) if d is None: break exp_deg = deg_g - 1 # evaluate one determinant & make coefficients subresultants sign_value = correct_sign(n, m, s1, exp_deg, exp_deg - d) poly = row2poly(M[M.rows - 1, :], d, x) temp2 = LC(poly, x) poly = simplify((poly / temp2) * sign_value) # update s2 by inserting first row of M as needed row0 = M[0, :] for i in range(deg_g - d): s2[r + i, :] = rotate_r(row0, r + i) r = r + deg_g - d # update s2 by inserting last row of M as needed row1 = rotate_l(M[M.rows - 1, :], deg_f - d) row1 = (row1 / temp2) * sign_value for i in range(deg_g - d): s2[r + i, :] = rotate_r(row1, r + i) r = r + deg_g - d # update degrees deg_f, deg_g = deg_g, d # append poly with subresultant coeffs sr_list.append(poly) # final touches to print the s2 matrix if method != 0 and s2.rows > 2: s2 = final_touches(s2, r, deg_g) pprint(s2) elif method != 0 and s2.rows == 2: s2[1, :] = rotate_r(s2.row(1), 1) pprint(s2) return sr_list def subresultants_vv_2(p, q, x): """ p, q are polynomials in Z[x] (intended) or Q[x]. It is assumed that degree(p, x) >= degree(q, x). Computes the subresultant prs of p, q by triangularizing, in Z[x] or in Q[x], all the smaller matrices encountered in the process of triangularizing sylvester2, Sylvester's matrix of 1853; see references 1 and 2 for Van Vleck's method. If the sylvester2 matrix has big dimensions use this version, where sylvester2 is used implicitly. If you want to see the final, triangularized matrix sylvester2, then use the first version, subresultants_vv(p, q, x, 1). sylvester1, Sylvester's matrix of 1840, is also used to compute one subresultant per remainder; namely, that of the leading coefficient, in order to obtain the correct sign and to ``force'' the remainder coefficients to become subresultants. If the subresultant prs is complete, then it coincides with the Euclidean sequence of the polynomials p, q. References ========== 1. Akritas, A. G.: ``A new method for computing polynomial greatest common divisors and polynomial remainder sequences.'' Numerische MatheMatik 52, 119-127, 1988. 2. Akritas, A. G., G.I. Malaschonok and P.S. Vigklas: ``On a Theorem by Van Vleck Regarding Sturm Sequences.'' Serdica Journal of Computing, 7, No 4, 101-134, 2013. 3. Akritas, A. G.:``Three New Methods for Computing Subresultant Polynomial Remainder Sequences (PRS's).'' Serdica Journal of Computing 9(1) (2015), 1-26. """ # make sure neither p nor q is 0 if p == 0 or q == 0: return [p, q] # make sure proper degrees f, g = p, q n = deg_f = degree(f, x) m = deg_g = degree(g, x) if n == 0 and m == 0: return [f, g] if n < m: n, m, deg_f, deg_g, f, g = m, n, deg_g, deg_f, g, f if n > 0 and m == 0: return [f, g] # initialize s1 = sylvester(f, g, x, 1) sr_list = [f, g] # subresultant list col_num = 2 * n # columns in sylvester2 # make two rows (row0, row1) of poly coefficients row0 = Poly(f, x, domain = QQ).all_coeffs() leng0 = len(row0) for i in range(col_num - leng0): row0.append(0) row0 = Matrix([row0]) row1 = Poly(g,x, domain = QQ).all_coeffs() leng1 = len(row1) for i in range(col_num - leng1): row1.append(0) row1 = Matrix([row1]) # main loop while deg_g > 0: # create a small matrix M, and triangularize it M = create_ma(deg_f, deg_g, row1, row0, col_num) for i in range(deg_f - deg_g + 1): M1 = pivot(M, i, i) M = M1[:, :] # treat last row of M as poly; find its degree d = find_degree(M, deg_f) if d is None: return sr_list exp_deg = deg_g - 1 # evaluate one determinant & make coefficients subresultants sign_value = correct_sign(n, m, s1, exp_deg, exp_deg - d) poly = row2poly(M[M.rows - 1, :], d, x) poly = simplify((poly / LC(poly, x)) * sign_value) # append poly with subresultant coeffs sr_list.append(poly) # update degrees and rows deg_f, deg_g = deg_g, d row0 = row1 row1 = Poly(poly, x, domain = QQ).all_coeffs() leng1 = len(row1) for i in range(col_num - leng1): row1.append(0) row1 = Matrix([row1]) return sr_list sympy-sympy-1.9/sympy/polys/tests/000077500000000000000000000000001412543434000174145ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/tests/__init__.py000066400000000000000000000000001412543434000215130ustar00rootroot00000000000000sympy-sympy-1.9/sympy/polys/tests/test_constructor.py000066400000000000000000000140201412543434000234070ustar00rootroot00000000000000"""Tests for tools for constructing domains for expressions. """ from sympy.polys.constructor import construct_domain from sympy.polys.domains import ZZ, QQ, ZZ_I, QQ_I, RR, CC, EX from sympy.polys.domains.realfield import RealField from sympy.polys.domains.complexfield import ComplexField from sympy import ( S, sqrt, sin, exp, Float, E, I, GoldenRatio, pi, Catalan, Rational) from sympy.abc import x, y def test_construct_domain(): assert construct_domain([1, 2, 3]) == (ZZ, [ZZ(1), ZZ(2), ZZ(3)]) assert construct_domain([1, 2, 3], field=True) == (QQ, [QQ(1), QQ(2), QQ(3)]) assert construct_domain([S.One, S(2), S(3)]) == (ZZ, [ZZ(1), ZZ(2), ZZ(3)]) assert construct_domain([S.One, S(2), S(3)], field=True) == (QQ, [QQ(1), QQ(2), QQ(3)]) assert construct_domain([S.Half, S(2)]) == (QQ, [QQ(1, 2), QQ(2)]) result = construct_domain([3.14, 1, S.Half]) assert isinstance(result[0], RealField) assert result[1] == [RR(3.14), RR(1.0), RR(0.5)] result = construct_domain([3.14, I, S.Half]) assert isinstance(result[0], ComplexField) assert result[1] == [CC(3.14), CC(1.0j), CC(0.5)] assert construct_domain([1.0+I]) == (CC, [CC(1.0, 1.0)]) assert construct_domain([2.0+3.0*I]) == (CC, [CC(2.0, 3.0)]) assert construct_domain([1, I]) == (ZZ_I, [ZZ_I(1, 0), ZZ_I(0, 1)]) assert construct_domain([1, I/2]) == (QQ_I, [QQ_I(1, 0), QQ_I(0, S.Half)]) assert construct_domain([3.14, sqrt(2)], extension=None) == (EX, [EX(3.14), EX(sqrt(2))]) assert construct_domain([3.14, sqrt(2)], extension=True) == (EX, [EX(3.14), EX(sqrt(2))]) assert construct_domain([1, sqrt(2)], extension=None) == (EX, [EX(1), EX(sqrt(2))]) assert construct_domain([x, sqrt(x)]) == (EX, [EX(x), EX(sqrt(x))]) assert construct_domain([x, sqrt(x), sqrt(y)]) == (EX, [EX(x), EX(sqrt(x)), EX(sqrt(y))]) alg = QQ.algebraic_field(sqrt(2)) assert construct_domain([7, S.Half, sqrt(2)], extension=True) == \ (alg, [alg.convert(7), alg.convert(S.Half), alg.convert(sqrt(2))]) alg = QQ.algebraic_field(sqrt(2) + sqrt(3)) assert construct_domain([7, sqrt(2), sqrt(3)], extension=True) == \ (alg, [alg.convert(7), alg.convert(sqrt(2)), alg.convert(sqrt(3))]) dom = ZZ[x] assert construct_domain([2*x, 3]) == \ (dom, [dom.convert(2*x), dom.convert(3)]) dom = ZZ[x, y] assert construct_domain([2*x, 3*y]) == \ (dom, [dom.convert(2*x), dom.convert(3*y)]) dom = QQ[x] assert construct_domain([x/2, 3]) == \ (dom, [dom.convert(x/2), dom.convert(3)]) dom = QQ[x, y] assert construct_domain([x/2, 3*y]) == \ (dom, [dom.convert(x/2), dom.convert(3*y)]) dom = ZZ_I[x] assert construct_domain([2*x, I]) == \ (dom, [dom.convert(2*x), dom.convert(I)]) dom = ZZ_I[x, y] assert construct_domain([2*x, I*y]) == \ (dom, [dom.convert(2*x), dom.convert(I*y)]) dom = QQ_I[x] assert construct_domain([x/2, I]) == \ (dom, [dom.convert(x/2), dom.convert(I)]) dom = QQ_I[x, y] assert construct_domain([x/2, I*y]) == \ (dom, [dom.convert(x/2), dom.convert(I*y)]) dom = RR[x] assert construct_domain([x/2, 3.5]) == \ (dom, [dom.convert(x/2), dom.convert(3.5)]) dom = RR[x, y] assert construct_domain([x/2, 3.5*y]) == \ (dom, [dom.convert(x/2), dom.convert(3.5*y)]) dom = CC[x] assert construct_domain([I*x/2, 3.5]) == \ (dom, [dom.convert(I*x/2), dom.convert(3.5)]) dom = CC[x, y] assert construct_domain([I*x/2, 3.5*y]) == \ (dom, [dom.convert(I*x/2), dom.convert(3.5*y)]) dom = CC[x] assert construct_domain([x/2, I*3.5]) == \ (dom, [dom.convert(x/2), dom.convert(I*3.5)]) dom = CC[x, y] assert construct_domain([x/2, I*3.5*y]) == \ (dom, [dom.convert(x/2), dom.convert(I*3.5*y)]) dom = ZZ.frac_field(x) assert construct_domain([2/x, 3]) == \ (dom, [dom.convert(2/x), dom.convert(3)]) dom = ZZ.frac_field(x, y) assert construct_domain([2/x, 3*y]) == \ (dom, [dom.convert(2/x), dom.convert(3*y)]) dom = RR.frac_field(x) assert construct_domain([2/x, 3.5]) == \ (dom, [dom.convert(2/x), dom.convert(3.5)]) dom = RR.frac_field(x, y) assert construct_domain([2/x, 3.5*y]) == \ (dom, [dom.convert(2/x), dom.convert(3.5*y)]) dom = RealField(prec=336)[x] assert construct_domain([pi.evalf(100)*x]) == \ (dom, [dom.convert(pi.evalf(100)*x)]) assert construct_domain(2) == (ZZ, ZZ(2)) assert construct_domain(S(2)/3) == (QQ, QQ(2, 3)) assert construct_domain(Rational(2, 3)) == (QQ, QQ(2, 3)) assert construct_domain({}) == (ZZ, {}) def test_complex_exponential(): w = exp(-I*2*pi/3, evaluate=False) alg = QQ.algebraic_field(w) assert construct_domain([w**2, w, 1], extension=True) == ( alg, [alg.convert(w**2), alg.convert(w), alg.convert(1)] ) def test_composite_option(): assert construct_domain({(1,): sin(y)}, composite=False) == \ (EX, {(1,): EX(sin(y))}) assert construct_domain({(1,): y}, composite=False) == \ (EX, {(1,): EX(y)}) assert construct_domain({(1, 1): 1}, composite=False) == \ (ZZ, {(1, 1): 1}) assert construct_domain({(1, 0): y}, composite=False) == \ (EX, {(1, 0): EX(y)}) def test_precision(): f1 = Float("1.01") f2 = Float("1.0000000000000000000001") for u in [1, 1e-2, 1e-6, 1e-13, 1e-14, 1e-16, 1e-20, 1e-100, 1e-300, f1, f2]: result = construct_domain([u]) v = float(result[1][0]) assert abs(u - v) / u < 1e-14 # Test relative accuracy result = construct_domain([f1]) y = result[1][0] assert y-1 > 1e-50 result = construct_domain([f2]) y = result[1][0] assert y-1 > 1e-50 def test_issue_11538(): for n in [E, pi, Catalan]: assert construct_domain(n)[0] == ZZ[n] assert construct_domain(x + n)[0] == ZZ[x, n] assert construct_domain(GoldenRatio)[0] == EX assert construct_domain(x + GoldenRatio)[0] == EX sympy-sympy-1.9/sympy/polys/tests/test_densearith.py000066400000000000000000001161211412543434000231550ustar00rootroot00000000000000"""Tests for dense recursive polynomials' arithmetics. """ from sympy.polys.densebasic import ( dup_normal, dmp_normal, ) from sympy.polys.densearith import ( dup_add_term, dmp_add_term, dup_sub_term, dmp_sub_term, dup_mul_term, dmp_mul_term, dup_add_ground, dmp_add_ground, dup_sub_ground, dmp_sub_ground, dup_mul_ground, dmp_mul_ground, dup_quo_ground, dmp_quo_ground, dup_exquo_ground, dmp_exquo_ground, dup_lshift, dup_rshift, dup_abs, dmp_abs, dup_neg, dmp_neg, dup_add, dmp_add, dup_sub, dmp_sub, dup_mul, dmp_mul, dup_sqr, dmp_sqr, dup_pow, dmp_pow, dup_add_mul, dmp_add_mul, dup_sub_mul, dmp_sub_mul, dup_pdiv, dup_prem, dup_pquo, dup_pexquo, dmp_pdiv, dmp_prem, dmp_pquo, dmp_pexquo, dup_rr_div, dmp_rr_div, dup_ff_div, dmp_ff_div, dup_div, dup_rem, dup_quo, dup_exquo, dmp_div, dmp_rem, dmp_quo, dmp_exquo, dup_max_norm, dmp_max_norm, dup_l1_norm, dmp_l1_norm, dup_expand, dmp_expand, ) from sympy.polys.polyerrors import ( ExactQuotientFailed, ) from sympy.polys.specialpolys import f_polys from sympy.polys.domains import FF, ZZ, QQ from sympy.testing.pytest import raises f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] F_0 = dmp_mul_ground(dmp_normal(f_0, 2, QQ), QQ(1, 7), 2, QQ) def test_dup_add_term(): f = dup_normal([], ZZ) assert dup_add_term(f, ZZ(0), 0, ZZ) == dup_normal([], ZZ) assert dup_add_term(f, ZZ(1), 0, ZZ) == dup_normal([1], ZZ) assert dup_add_term(f, ZZ(1), 1, ZZ) == dup_normal([1, 0], ZZ) assert dup_add_term(f, ZZ(1), 2, ZZ) == dup_normal([1, 0, 0], ZZ) f = dup_normal([1, 1, 1], ZZ) assert dup_add_term(f, ZZ(1), 0, ZZ) == dup_normal([1, 1, 2], ZZ) assert dup_add_term(f, ZZ(1), 1, ZZ) == dup_normal([1, 2, 1], ZZ) assert dup_add_term(f, ZZ(1), 2, ZZ) == dup_normal([2, 1, 1], ZZ) assert dup_add_term(f, ZZ(1), 3, ZZ) == dup_normal([1, 1, 1, 1], ZZ) assert dup_add_term(f, ZZ(1), 4, ZZ) == dup_normal([1, 0, 1, 1, 1], ZZ) assert dup_add_term(f, ZZ(1), 5, ZZ) == dup_normal([1, 0, 0, 1, 1, 1], ZZ) assert dup_add_term( f, ZZ(1), 6, ZZ) == dup_normal([1, 0, 0, 0, 1, 1, 1], ZZ) assert dup_add_term(f, ZZ(-1), 2, ZZ) == dup_normal([1, 1], ZZ) def test_dmp_add_term(): assert dmp_add_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, 0, ZZ) == \ dup_add_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, ZZ) assert dmp_add_term(f_0, [[]], 3, 2, ZZ) == f_0 assert dmp_add_term(F_0, [[]], 3, 2, QQ) == F_0 def test_dup_sub_term(): f = dup_normal([], ZZ) assert dup_sub_term(f, ZZ(0), 0, ZZ) == dup_normal([], ZZ) assert dup_sub_term(f, ZZ(1), 0, ZZ) == dup_normal([-1], ZZ) assert dup_sub_term(f, ZZ(1), 1, ZZ) == dup_normal([-1, 0], ZZ) assert dup_sub_term(f, ZZ(1), 2, ZZ) == dup_normal([-1, 0, 0], ZZ) f = dup_normal([1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(2), 0, ZZ) == dup_normal([ 1, 1, -1], ZZ) assert dup_sub_term(f, ZZ(2), 1, ZZ) == dup_normal([ 1, -1, 1], ZZ) assert dup_sub_term(f, ZZ(2), 2, ZZ) == dup_normal([-1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 3, ZZ) == dup_normal([-1, 1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 4, ZZ) == dup_normal([-1, 0, 1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 5, ZZ) == dup_normal([-1, 0, 0, 1, 1, 1], ZZ) assert dup_sub_term( f, ZZ(1), 6, ZZ) == dup_normal([-1, 0, 0, 0, 1, 1, 1], ZZ) assert dup_sub_term(f, ZZ(1), 2, ZZ) == dup_normal([1, 1], ZZ) def test_dmp_sub_term(): assert dmp_sub_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, 0, ZZ) == \ dup_sub_term([ZZ(1), ZZ(1), ZZ(1)], ZZ(1), 2, ZZ) assert dmp_sub_term(f_0, [[]], 3, 2, ZZ) == f_0 assert dmp_sub_term(F_0, [[]], 3, 2, QQ) == F_0 def test_dup_mul_term(): f = dup_normal([], ZZ) assert dup_mul_term(f, ZZ(2), 3, ZZ) == dup_normal([], ZZ) f = dup_normal([1, 1], ZZ) assert dup_mul_term(f, ZZ(0), 3, ZZ) == dup_normal([], ZZ) f = dup_normal([1, 2, 3], ZZ) assert dup_mul_term(f, ZZ(2), 0, ZZ) == dup_normal([2, 4, 6], ZZ) assert dup_mul_term(f, ZZ(2), 1, ZZ) == dup_normal([2, 4, 6, 0], ZZ) assert dup_mul_term(f, ZZ(2), 2, ZZ) == dup_normal([2, 4, 6, 0, 0], ZZ) assert dup_mul_term(f, ZZ(2), 3, ZZ) == dup_normal([2, 4, 6, 0, 0, 0], ZZ) def test_dmp_mul_term(): assert dmp_mul_term([ZZ(1), ZZ(2), ZZ(3)], ZZ(2), 1, 0, ZZ) == \ dup_mul_term([ZZ(1), ZZ(2), ZZ(3)], ZZ(2), 1, ZZ) assert dmp_mul_term([[]], [ZZ(2)], 3, 1, ZZ) == [[]] assert dmp_mul_term([[ZZ(1)]], [], 3, 1, ZZ) == [[]] assert dmp_mul_term([[ZZ(1), ZZ(2)], [ZZ(3)]], [ZZ(2)], 2, 1, ZZ) == \ [[ZZ(2), ZZ(4)], [ZZ(6)], [], []] assert dmp_mul_term([[]], [QQ(2, 3)], 3, 1, QQ) == [[]] assert dmp_mul_term([[QQ(1, 2)]], [], 3, 1, QQ) == [[]] assert dmp_mul_term([[QQ(1, 5), QQ(2, 5)], [QQ(3, 5)]], [QQ(2, 3)], 2, 1, QQ) == \ [[QQ(2, 15), QQ(4, 15)], [QQ(6, 15)], [], []] def test_dup_add_ground(): f = ZZ.map([1, 2, 3, 4]) g = ZZ.map([1, 2, 3, 8]) assert dup_add_ground(f, ZZ(4), ZZ) == g def test_dmp_add_ground(): f = ZZ.map([[1], [2], [3], [4]]) g = ZZ.map([[1], [2], [3], [8]]) assert dmp_add_ground(f, ZZ(4), 1, ZZ) == g def test_dup_sub_ground(): f = ZZ.map([1, 2, 3, 4]) g = ZZ.map([1, 2, 3, 0]) assert dup_sub_ground(f, ZZ(4), ZZ) == g def test_dmp_sub_ground(): f = ZZ.map([[1], [2], [3], [4]]) g = ZZ.map([[1], [2], [3], []]) assert dmp_sub_ground(f, ZZ(4), 1, ZZ) == g def test_dup_mul_ground(): f = dup_normal([], ZZ) assert dup_mul_ground(f, ZZ(2), ZZ) == dup_normal([], ZZ) f = dup_normal([1, 2, 3], ZZ) assert dup_mul_ground(f, ZZ(0), ZZ) == dup_normal([], ZZ) assert dup_mul_ground(f, ZZ(2), ZZ) == dup_normal([2, 4, 6], ZZ) def test_dmp_mul_ground(): assert dmp_mul_ground(f_0, ZZ(2), 2, ZZ) == [ [[ZZ(2), ZZ(4), ZZ(6)], [ZZ(4)]], [[ZZ(6)]], [[ZZ(8), ZZ(10), ZZ(12)], [ZZ(2), ZZ(4), ZZ(2)], [ZZ(2)]] ] assert dmp_mul_ground(F_0, QQ(1, 2), 2, QQ) == [ [[QQ(1, 14), QQ(2, 14), QQ(3, 14)], [QQ(2, 14)]], [[QQ(3, 14)]], [[QQ(4, 14), QQ(5, 14), QQ(6, 14)], [QQ(1, 14), QQ(2, 14), QQ(1, 14)], [QQ(1, 14)]] ] def test_dup_quo_ground(): raises(ZeroDivisionError, lambda: dup_quo_ground(dup_normal([1, 2, 3], ZZ), ZZ(0), ZZ)) f = dup_normal([], ZZ) assert dup_quo_ground(f, ZZ(3), ZZ) == dup_normal([], ZZ) f = dup_normal([6, 2, 8], ZZ) assert dup_quo_ground(f, ZZ(1), ZZ) == f assert dup_quo_ground(f, ZZ(2), ZZ) == dup_normal([3, 1, 4], ZZ) assert dup_quo_ground(f, ZZ(3), ZZ) == dup_normal([2, 0, 2], ZZ) f = dup_normal([6, 2, 8], QQ) assert dup_quo_ground(f, QQ(1), QQ) == f assert dup_quo_ground(f, QQ(2), QQ) == [QQ(3), QQ(1), QQ(4)] assert dup_quo_ground(f, QQ(7), QQ) == [QQ(6, 7), QQ(2, 7), QQ(8, 7)] def test_dup_exquo_ground(): raises(ZeroDivisionError, lambda: dup_exquo_ground(dup_normal([1, 2, 3], ZZ), ZZ(0), ZZ)) raises(ExactQuotientFailed, lambda: dup_exquo_ground(dup_normal([1, 2, 3], ZZ), ZZ(3), ZZ)) f = dup_normal([], ZZ) assert dup_exquo_ground(f, ZZ(3), ZZ) == dup_normal([], ZZ) f = dup_normal([6, 2, 8], ZZ) assert dup_exquo_ground(f, ZZ(1), ZZ) == f assert dup_exquo_ground(f, ZZ(2), ZZ) == dup_normal([3, 1, 4], ZZ) f = dup_normal([6, 2, 8], QQ) assert dup_exquo_ground(f, QQ(1), QQ) == f assert dup_exquo_ground(f, QQ(2), QQ) == [QQ(3), QQ(1), QQ(4)] assert dup_exquo_ground(f, QQ(7), QQ) == [QQ(6, 7), QQ(2, 7), QQ(8, 7)] def test_dmp_quo_ground(): f = dmp_normal([[6], [2], [8]], 1, ZZ) assert dmp_quo_ground(f, ZZ(1), 1, ZZ) == f assert dmp_quo_ground( f, ZZ(2), 1, ZZ) == dmp_normal([[3], [1], [4]], 1, ZZ) assert dmp_normal(dmp_quo_ground( f, ZZ(3), 1, ZZ), 1, ZZ) == dmp_normal([[2], [], [2]], 1, ZZ) def test_dmp_exquo_ground(): f = dmp_normal([[6], [2], [8]], 1, ZZ) assert dmp_exquo_ground(f, ZZ(1), 1, ZZ) == f assert dmp_exquo_ground( f, ZZ(2), 1, ZZ) == dmp_normal([[3], [1], [4]], 1, ZZ) def test_dup_lshift(): assert dup_lshift([], 3, ZZ) == [] assert dup_lshift([1], 3, ZZ) == [1, 0, 0, 0] def test_dup_rshift(): assert dup_rshift([], 3, ZZ) == [] assert dup_rshift([1, 0, 0, 0], 3, ZZ) == [1] def test_dup_abs(): assert dup_abs([], ZZ) == [] assert dup_abs([ZZ( 1)], ZZ) == [ZZ(1)] assert dup_abs([ZZ(-7)], ZZ) == [ZZ(7)] assert dup_abs([ZZ(-1), ZZ(2), ZZ(3)], ZZ) == [ZZ(1), ZZ(2), ZZ(3)] assert dup_abs([], QQ) == [] assert dup_abs([QQ( 1, 2)], QQ) == [QQ(1, 2)] assert dup_abs([QQ(-7, 3)], QQ) == [QQ(7, 3)] assert dup_abs( [QQ(-1, 7), QQ(2, 7), QQ(3, 7)], QQ) == [QQ(1, 7), QQ(2, 7), QQ(3, 7)] def test_dmp_abs(): assert dmp_abs([ZZ(-1)], 0, ZZ) == [ZZ(1)] assert dmp_abs([QQ(-1, 2)], 0, QQ) == [QQ(1, 2)] assert dmp_abs([[[]]], 2, ZZ) == [[[]]] assert dmp_abs([[[ZZ(1)]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_abs([[[ZZ(-7)]]], 2, ZZ) == [[[ZZ(7)]]] assert dmp_abs([[[]]], 2, QQ) == [[[]]] assert dmp_abs([[[QQ(1, 2)]]], 2, QQ) == [[[QQ(1, 2)]]] assert dmp_abs([[[QQ(-7, 9)]]], 2, QQ) == [[[QQ(7, 9)]]] def test_dup_neg(): assert dup_neg([], ZZ) == [] assert dup_neg([ZZ(1)], ZZ) == [ZZ(-1)] assert dup_neg([ZZ(-7)], ZZ) == [ZZ(7)] assert dup_neg([ZZ(-1), ZZ(2), ZZ(3)], ZZ) == [ZZ(1), ZZ(-2), ZZ(-3)] assert dup_neg([], QQ) == [] assert dup_neg([QQ(1, 2)], QQ) == [QQ(-1, 2)] assert dup_neg([QQ(-7, 9)], QQ) == [QQ(7, 9)] assert dup_neg([QQ( -1, 7), QQ(2, 7), QQ(3, 7)], QQ) == [QQ(1, 7), QQ(-2, 7), QQ(-3, 7)] def test_dmp_neg(): assert dmp_neg([ZZ(-1)], 0, ZZ) == [ZZ(1)] assert dmp_neg([QQ(-1, 2)], 0, QQ) == [QQ(1, 2)] assert dmp_neg([[[]]], 2, ZZ) == [[[]]] assert dmp_neg([[[ZZ(1)]]], 2, ZZ) == [[[ZZ(-1)]]] assert dmp_neg([[[ZZ(-7)]]], 2, ZZ) == [[[ZZ(7)]]] assert dmp_neg([[[]]], 2, QQ) == [[[]]] assert dmp_neg([[[QQ(1, 9)]]], 2, QQ) == [[[QQ(-1, 9)]]] assert dmp_neg([[[QQ(-7, 9)]]], 2, QQ) == [[[QQ(7, 9)]]] def test_dup_add(): assert dup_add([], [], ZZ) == [] assert dup_add([ZZ(1)], [], ZZ) == [ZZ(1)] assert dup_add([], [ZZ(1)], ZZ) == [ZZ(1)] assert dup_add([ZZ(1)], [ZZ(1)], ZZ) == [ZZ(2)] assert dup_add([ZZ(1)], [ZZ(2)], ZZ) == [ZZ(3)] assert dup_add([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) == [ZZ(1), ZZ(3)] assert dup_add([ZZ(1)], [ZZ(1), ZZ(2)], ZZ) == [ZZ(1), ZZ(3)] assert dup_add([ZZ(1), ZZ( 2), ZZ(3)], [ZZ(8), ZZ(9), ZZ(10)], ZZ) == [ZZ(9), ZZ(11), ZZ(13)] assert dup_add([], [], QQ) == [] assert dup_add([QQ(1, 2)], [], QQ) == [QQ(1, 2)] assert dup_add([], [QQ(1, 2)], QQ) == [QQ(1, 2)] assert dup_add([QQ(1, 4)], [QQ(1, 4)], QQ) == [QQ(1, 2)] assert dup_add([QQ(1, 4)], [QQ(1, 2)], QQ) == [QQ(3, 4)] assert dup_add([QQ(1, 2), QQ(2, 3)], [QQ(1)], QQ) == [QQ(1, 2), QQ(5, 3)] assert dup_add([QQ(1)], [QQ(1, 2), QQ(2, 3)], QQ) == [QQ(1, 2), QQ(5, 3)] assert dup_add([QQ(1, 7), QQ(2, 7), QQ(3, 7)], [QQ( 8, 7), QQ(9, 7), QQ(10, 7)], QQ) == [QQ(9, 7), QQ(11, 7), QQ(13, 7)] def test_dmp_add(): assert dmp_add([ZZ(1), ZZ(2)], [ZZ(1)], 0, ZZ) == \ dup_add([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) assert dmp_add([QQ(1, 2), QQ(2, 3)], [QQ(1)], 0, QQ) == \ dup_add([QQ(1, 2), QQ(2, 3)], [QQ(1)], QQ) assert dmp_add([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_add([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_add([[[]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_add([[[ZZ(2)]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(3)]]] assert dmp_add([[[ZZ(1)]]], [[[ZZ(2)]]], 2, ZZ) == [[[ZZ(3)]]] assert dmp_add([[[]]], [[[]]], 2, QQ) == [[[]]] assert dmp_add([[[QQ(1, 2)]]], [[[]]], 2, QQ) == [[[QQ(1, 2)]]] assert dmp_add([[[]]], [[[QQ(1, 2)]]], 2, QQ) == [[[QQ(1, 2)]]] assert dmp_add([[[QQ(2, 7)]]], [[[QQ(1, 7)]]], 2, QQ) == [[[QQ(3, 7)]]] assert dmp_add([[[QQ(1, 7)]]], [[[QQ(2, 7)]]], 2, QQ) == [[[QQ(3, 7)]]] def test_dup_sub(): assert dup_sub([], [], ZZ) == [] assert dup_sub([ZZ(1)], [], ZZ) == [ZZ(1)] assert dup_sub([], [ZZ(1)], ZZ) == [ZZ(-1)] assert dup_sub([ZZ(1)], [ZZ(1)], ZZ) == [] assert dup_sub([ZZ(1)], [ZZ(2)], ZZ) == [ZZ(-1)] assert dup_sub([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) == [ZZ(1), ZZ(1)] assert dup_sub([ZZ(1)], [ZZ(1), ZZ(2)], ZZ) == [ZZ(-1), ZZ(-1)] assert dup_sub([ZZ(3), ZZ( 2), ZZ(1)], [ZZ(8), ZZ(9), ZZ(10)], ZZ) == [ZZ(-5), ZZ(-7), ZZ(-9)] assert dup_sub([], [], QQ) == [] assert dup_sub([QQ(1, 2)], [], QQ) == [QQ(1, 2)] assert dup_sub([], [QQ(1, 2)], QQ) == [QQ(-1, 2)] assert dup_sub([QQ(1, 3)], [QQ(1, 3)], QQ) == [] assert dup_sub([QQ(1, 3)], [QQ(2, 3)], QQ) == [QQ(-1, 3)] assert dup_sub([QQ(1, 7), QQ(2, 7)], [QQ(1)], QQ) == [QQ(1, 7), QQ(-5, 7)] assert dup_sub([QQ(1)], [QQ(1, 7), QQ(2, 7)], QQ) == [QQ(-1, 7), QQ(5, 7)] assert dup_sub([QQ(3, 7), QQ(2, 7), QQ(1, 7)], [QQ( 8, 7), QQ(9, 7), QQ(10, 7)], QQ) == [QQ(-5, 7), QQ(-7, 7), QQ(-9, 7)] def test_dmp_sub(): assert dmp_sub([ZZ(1), ZZ(2)], [ZZ(1)], 0, ZZ) == \ dup_sub([ZZ(1), ZZ(2)], [ZZ(1)], ZZ) assert dmp_sub([QQ(1, 2), QQ(2, 3)], [QQ(1)], 0, QQ) == \ dup_sub([QQ(1, 2), QQ(2, 3)], [QQ(1)], QQ) assert dmp_sub([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_sub([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_sub([[[]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(-1)]]] assert dmp_sub([[[ZZ(2)]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(1)]]] assert dmp_sub([[[ZZ(1)]]], [[[ZZ(2)]]], 2, ZZ) == [[[ZZ(-1)]]] assert dmp_sub([[[]]], [[[]]], 2, QQ) == [[[]]] assert dmp_sub([[[QQ(1, 2)]]], [[[]]], 2, QQ) == [[[QQ(1, 2)]]] assert dmp_sub([[[]]], [[[QQ(1, 2)]]], 2, QQ) == [[[QQ(-1, 2)]]] assert dmp_sub([[[QQ(2, 7)]]], [[[QQ(1, 7)]]], 2, QQ) == [[[QQ(1, 7)]]] assert dmp_sub([[[QQ(1, 7)]]], [[[QQ(2, 7)]]], 2, QQ) == [[[QQ(-1, 7)]]] def test_dup_add_mul(): assert dup_add_mul([ZZ(1), ZZ(2), ZZ(3)], [ZZ(3), ZZ(2), ZZ(1)], [ZZ(1), ZZ(2)], ZZ) == [ZZ(3), ZZ(9), ZZ(7), ZZ(5)] assert dmp_add_mul([[ZZ(1), ZZ(2)], [ZZ(3)]], [[ZZ(3)], [ZZ(2), ZZ(1)]], [[ZZ(1)], [ZZ(2)]], 1, ZZ) == [[ZZ(3)], [ZZ(3), ZZ(9)], [ZZ(4), ZZ(5)]] def test_dup_sub_mul(): assert dup_sub_mul([ZZ(1), ZZ(2), ZZ(3)], [ZZ(3), ZZ(2), ZZ(1)], [ZZ(1), ZZ(2)], ZZ) == [ZZ(-3), ZZ(-7), ZZ(-3), ZZ(1)] assert dmp_sub_mul([[ZZ(1), ZZ(2)], [ZZ(3)]], [[ZZ(3)], [ZZ(2), ZZ(1)]], [[ZZ(1)], [ZZ(2)]], 1, ZZ) == [[ZZ(-3)], [ZZ(-1), ZZ(-5)], [ZZ(-4), ZZ(1)]] def test_dup_mul(): assert dup_mul([], [], ZZ) == [] assert dup_mul([], [ZZ(1)], ZZ) == [] assert dup_mul([ZZ(1)], [], ZZ) == [] assert dup_mul([ZZ(1)], [ZZ(1)], ZZ) == [ZZ(1)] assert dup_mul([ZZ(5)], [ZZ(7)], ZZ) == [ZZ(35)] assert dup_mul([], [], QQ) == [] assert dup_mul([], [QQ(1, 2)], QQ) == [] assert dup_mul([QQ(1, 2)], [], QQ) == [] assert dup_mul([QQ(1, 2)], [QQ(4, 7)], QQ) == [QQ(2, 7)] assert dup_mul([QQ(5, 7)], [QQ(3, 7)], QQ) == [QQ(15, 49)] f = dup_normal([3, 0, 0, 6, 1, 2], ZZ) g = dup_normal([4, 0, 1, 0], ZZ) h = dup_normal([12, 0, 3, 24, 4, 14, 1, 2, 0], ZZ) assert dup_mul(f, g, ZZ) == h assert dup_mul(g, f, ZZ) == h f = dup_normal([2, 0, 0, 1, 7], ZZ) h = dup_normal([4, 0, 0, 4, 28, 0, 1, 14, 49], ZZ) assert dup_mul(f, f, ZZ) == h K = FF(6) assert dup_mul([K(2), K(1)], [K(3), K(4)], K) == [K(5), K(4)] p1 = dup_normal([79, -1, 78, -94, -10, 11, 32, -19, 78, 2, -89, 30, 73, 42, 85, 77, 83, -30, -34, -2, 95, -81, 37, -49, -46, -58, -16, 37, 35, -11, -57, -15, -31, 67, -20, 27, 76, 2, 70, 67, -65, 65, -26, -93, -44, -12, -92, 57, -90, -57, -11, -67, -98, -69, 97, -41, 89, 33, 89, -50, 81, -31, 60, -27, 43, 29, -77, 44, 21, -91, 32, -57, 33, 3, 53, -51, -38, -99, -84, 23, -50, 66, -100, 1, -75, -25, 27, -60, 98, -51, -87, 6, 8, 78, -28, -95, -88, 12, -35, 26, -9, 16, -92, 55, -7, -86, 68, -39, -46, 84, 94, 45, 60, 92, 68, -75, -74, -19, 8, 75, 78, 91, 57, 34, 14, -3, -49, 65, 78, -18, 6, -29, -80, -98, 17, 13, 58, 21, 20, 9, 37, 7, -30, -53, -20, 34, 67, -42, 89, -22, 73, 43, -6, 5, 51, -8, -15, -52, -22, -58, -72, -3, 43, -92, 82, 83, -2, -13, -23, -60, 16, -94, -8, -28, -95, -72, 63, -90, 76, 6, -43, -100, -59, 76, 3, 3, 46, -85, 75, 62, -71, -76, 88, 97, -72, -1, 30, -64, 72, -48, 14, -78, 58, 63, -91, 24, -87, -27, -80, -100, -44, 98, 70, 100, -29, -38, 11, 77, 100, 52, 86, 65, -5, -42, -81, -38, -42, 43, -2, -70, -63, -52], ZZ) p2 = dup_normal([65, -19, -47, 1, 90, 81, -15, -34, 25, -75, 9, -83, 50, -5, -44, 31, 1, 70, -7, 78, 74, 80, 85, 65, 21, 41, 66, 19, -40, 63, -21, -27, 32, 69, 83, 34, -35, 14, 81, 57, -75, 32, -67, -89, -100, -61, 46, 84, -78, -29, -50, -94, -24, -32, -68, -16, 100, -7, -72, -89, 35, 82, 58, 81, -92, 62, 5, -47, -39, -58, -72, -13, 84, 44, 55, -25, 48, -54, -31, -56, -11, -50, -84, 10, 67, 17, 13, -14, 61, 76, -64, -44, -40, -96, 11, -11, -94, 2, 6, 27, -6, 68, -54, 66, -74, -14, -1, -24, -73, 96, 89, -11, -89, 56, -53, 72, -43, 96, 25, 63, -31, 29, 68, 83, 91, -93, -19, -38, -40, 40, -12, -19, -79, 44, 100, -66, -29, -77, 62, 39, -8, 11, -97, 14, 87, 64, 21, -18, 13, 15, -59, -75, -99, -88, 57, 54, 56, -67, 6, -63, -59, -14, 28, 87, -20, -39, 84, -91, -2, 49, -75, 11, -24, -95, 36, 66, 5, 25, -72, -40, 86, 90, 37, -33, 57, -35, 29, -18, 4, -79, 64, -17, -27, 21, 29, -5, -44, -87, -24, 52, 78, 11, -23, -53, 36, 42, 21, -68, 94, -91, -51, -21, 51, -76, 72, 31, 24, -48, -80, -9, 37, -47, -6, -8, -63, -91, 79, -79, -100, 38, -20, 38, 100, 83, -90, 87, 63, -36, 82, -19, 18, -98, -38, 26, 98, -70, 79, 92, 12, 12, 70, 74, 36, 48, -13, 31, 31, -47, -71, -12, -64, 36, -42, 32, -86, 60, 83, 70, 55, 0, 1, 29, -35, 8, -82, 8, -73, -46, -50, 43, 48, -5, -86, -72, 44, -90, 19, 19, 5, -20, 97, -13, -66, -5, 5, -69, 64, -30, 41, 51, 36, 13, -99, -61, 94, -12, 74, 98, 68, 24, 46, -97, -87, -6, -27, 82, 62, -11, -77, 86, 66, -47, -49, -50, 13, 18, 89, -89, 46, -80, 13, 98, -35, -36, -25, 12, 20, 26, -52, 79, 27, 79, 100, 8, 62, -58, -28, 37], ZZ) res = dup_normal([5135, -1566, 1376, -7466, 4579, 11710, 8001, -7183, -3737, -7439, 345, -10084, 24522, -1201, 1070, -10245, 9582, 9264, 1903, 23312, 18953, 10037, -15268, -5450, 6442, -6243, -3777, 5110, 10936, -16649, -6022, 16255, 31300, 24818, 31922, 32760, 7854, 27080, 15766, 29596, 7139, 31945, -19810, 465, -38026, -3971, 9641, 465, -19375, 5524, -30112, -11960, -12813, 13535, 30670, 5925, -43725, -14089, 11503, -22782, 6371, 43881, 37465, -33529, -33590, -39798, -37854, -18466, -7908, -35825, -26020, -36923, -11332, -5699, 25166, -3147, 19885, 12962, -20659, -1642, 27723, -56331, -24580, -11010, -20206, 20087, -23772, -16038, 38580, 20901, -50731, 32037, -4299, 26508, 18038, -28357, 31846, -7405, -20172, -15894, 2096, 25110, -45786, 45918, -55333, -31928, -49428, -29824, -58796, -24609, -15408, 69, -35415, -18439, 10123, -20360, -65949, 33356, -20333, 26476, -32073, 33621, 930, 28803, -42791, 44716, 38164, 12302, -1739, 11421, 73385, -7613, 14297, 38155, -414, 77587, 24338, -21415, 29367, 42639, 13901, -288, 51027, -11827, 91260, 43407, 88521, -15186, 70572, -12049, 5090, -12208, -56374, 15520, -623, -7742, 50825, 11199, -14894, 40892, 59591, -31356, -28696, -57842, -87751, -33744, -28436, -28945, -40287, 37957, -35638, 33401, -61534, 14870, 40292, 70366, -10803, 102290, -71719, -85251, 7902, -22409, 75009, 99927, 35298, -1175, -762, -34744, -10587, -47574, -62629, -19581, -43659, -54369, -32250, -39545, 15225, -24454, 11241, -67308, -30148, 39929, 37639, 14383, -73475, -77636, -81048, -35992, 41601, -90143, 76937, -8112, 56588, 9124, -40094, -32340, 13253, 10898, -51639, 36390, 12086, -1885, 100714, -28561, -23784, -18735, 18916, 16286, 10742, -87360, -13697, 10689, -19477, -29770, 5060, 20189, -8297, 112407, 47071, 47743, 45519, -4109, 17468, -68831, 78325, -6481, -21641, -19459, 30919, 96115, 8607, 53341, 32105, -16211, 23538, 57259, -76272, -40583, 62093, 38511, -34255, -40665, -40604, -37606, -15274, 33156, -13885, 103636, 118678, -14101, -92682, -100791, 2634, 63791, 98266, 19286, -34590, -21067, -71130, 25380, -40839, -27614, -26060, 52358, -15537, 27138, -6749, 36269, -33306, 13207, -91084, -5540, -57116, 69548, 44169, -57742, -41234, -103327, -62904, -8566, 41149, -12866, 71188, 23980, 1838, 58230, 73950, 5594, 43113, -8159, -15925, 6911, 85598, -75016, -16214, -62726, -39016, 8618, -63882, -4299, 23182, 49959, 49342, -3238, -24913, -37138, 78361, 32451, 6337, -11438, -36241, -37737, 8169, -3077, -24829, 57953, 53016, -31511, -91168, 12599, -41849, 41576, 55275, -62539, 47814, -62319, 12300, -32076, -55137, -84881, -27546, 4312, -3433, -54382, 113288, -30157, 74469, 18219, 79880, -2124, 98911, 17655, -33499, -32861, 47242, -37393, 99765, 14831, -44483, 10800, -31617, -52710, 37406, 22105, 29704, -20050, 13778, 43683, 36628, 8494, 60964, -22644, 31550, -17693, 33805, -124879, -12302, 19343, 20400, -30937, -21574, -34037, -33380, 56539, -24993, -75513, -1527, 53563, 65407, -101, 53577, 37991, 18717, -23795, -8090, -47987, -94717, 41967, 5170, -14815, -94311, 17896, -17734, -57718, -774, -38410, 24830, 29682, 76480, 58802, -46416, -20348, -61353, -68225, -68306, 23822, -31598, 42972, 36327, 28968, -65638, -21638, 24354, -8356, 26777, 52982, -11783, -44051, -26467, -44721, -28435, -53265, -25574, -2669, 44155, 22946, -18454, -30718, -11252, 58420, 8711, 67447, 4425, 41749, 67543, 43162, 11793, -41907, 20477, -13080, 6559, -6104, -13244, 42853, 42935, 29793, 36730, -28087, 28657, 17946, 7503, 7204, 21491, -27450, -24241, -98156, -18082, -42613, -24928, 10775, -14842, -44127, 55910, 14777, 31151, -2194, 39206, -2100, -4211, 11827, -8918, -19471, 72567, 36447, -65590, -34861, -17147, -45303, 9025, -7333, -35473, 11101, 11638, 3441, 6626, -41800, 9416, 13679, 33508, 40502, -60542, 16358, 8392, -43242, -35864, -34127, -48721, 35878, 30598, 28630, 20279, -19983, -14638, -24455, -1851, -11344, 45150, 42051, 26034, -28889, -32382, -3527, -14532, 22564, -22346, 477, 11706, 28338, -25972, -9185, -22867, -12522, 32120, -4424, 11339, -33913, -7184, 5101, -23552, -17115, -31401, -6104, 21906, 25708, 8406, 6317, -7525, 5014, 20750, 20179, 22724, 11692, 13297, 2493, -253, -16841, -17339, -6753, -4808, 2976, -10881, -10228, -13816, -12686, 1385, 2316, 2190, -875, -1924], ZZ) assert dup_mul(p1, p2, ZZ) == res p1 = dup_normal([83, -61, -86, -24, 12, 43, -88, -9, 42, 55, -66, 74, 95, -25, -12, 68, -99, 4, 45, 6, -15, -19, 78, 65, -55, 47, -13, 17, 86, 81, -58, -27, 50, -40, -24, 39, -41, -92, 75, 90, -1, 40, -15, -27, -35, 68, 70, -64, -40, 78, -88, -58, -39, 69, 46, 12, 28, -94, -37, -50, -80, -96, -61, 25, 1, 71, 4, 12, 48, 4, 34, -47, -75, 5, 48, 82, 88, 23, 98, 35, 17, -10, 48, -61, -95, 47, 65, -19, -66, -57, -6, -51, -42, -89, 66, -13, 18, 37, 90, -23, 72, 96, -53, 0, 40, -73, -52, -68, 32, -25, -53, 79, -52, 18, 44, 73, -81, 31, -90, 70, 3, 36, 48, 76, -24, -44, 23, 98, -4, 73, 69, 88, -70, 14, -68, 94, -78, -15, -64, -97, -70, -35, 65, 88, 49, -53, -7, 12, -45, -7, 59, -94, 99, -2, 67, -60, -71, 29, -62, -77, 1, 51, 17, 80, -20, -47, -19, 24, -9, 39, -23, 21, -84, 10, 84, 56, -17, -21, -66, 85, 70, 46, -51, -22, -95, 78, -60, -96, -97, -45, 72, 35, 30, -61, -92, -93, -60, -61, 4, -4, -81, -73, 46, 53, -11, 26, 94, 45, 14, -78, 55, 84, -68, 98, 60, 23, 100, -63, 68, 96, -16, 3, 56, 21, -58, 62, -67, 66, 85, 41, -79, -22, 97, -67, 82, 82, -96, -20, -7, 48, -67, 48, -9, -39, 78], ZZ) p2 = dup_normal([52, 88, 76, 66, 9, -64, 46, -20, -28, 69, 60, 96, -36, -92, -30, -11, -35, 35, 55, 63, -92, -7, 25, -58, 74, 55, -6, 4, 47, -92, -65, 67, -45, 74, -76, 59, -6, 69, 39, 24, -71, -7, 39, -45, 60, -68, 98, 97, -79, 17, 4, 94, -64, 68, -100, -96, -2, 3, 22, 96, 54, -77, -86, 67, 6, 57, 37, 40, 89, -78, 64, -94, -45, -92, 57, 87, -26, 36, 19, 97, 25, 77, -87, 24, 43, -5, 35, 57, 83, 71, 35, 63, 61, 96, -22, 8, -1, 96, 43, 45, 94, -93, 36, 71, -41, -99, 85, -48, 59, 52, -17, 5, 87, -16, -68, -54, 76, -18, 100, 91, -42, -70, -66, -88, -12, 1, 95, -82, 52, 43, -29, 3, 12, 72, -99, -43, -32, -93, -51, 16, -20, -12, -11, 5, 33, -38, 93, -5, -74, 25, 74, -58, 93, 59, -63, -86, 63, -20, -4, -74, -73, -95, 29, -28, 93, -91, -2, -38, -62, 77, -58, -85, -28, 95, 38, 19, -69, 86, 94, 25, -2, -4, 47, 34, -59, 35, -48, 29, -63, -53, 34, 29, 66, 73, 6, 92, -84, 89, 15, 81, 93, 97, 51, -72, -78, 25, 60, 90, -45, 39, 67, -84, -62, 57, 26, -32, -56, -14, -83, 76, 5, -2, 99, -100, 28, 46, 94, -7, 53, -25, 16, -23, -36, 89, -78, -63, 31, 1, 84, -99, -52, 76, 48, 90, -76, 44, -19, 54, -36, -9, -73, -100, -69, 31, 42, 25, -39, 76, -26, -8, -14, 51, 3, 37, 45, 2, -54, 13, -34, -92, 17, -25, -65, 53, -63, 30, 4, -70, -67, 90, 52, 51, 18, -3, 31, -45, -9, 59, 63, -87, 22, -32, 29, -38, 21, 36, -82, 27, -11], ZZ) res = dup_normal([4316, 4132, -3532, -7974, -11303, -10069, 5484, -3330, -5874, 7734, 4673, 11327, -9884, -8031, 17343, 21035, -10570, -9285, 15893, 3780, -14083, 8819, 17592, 10159, 7174, -11587, 8598, -16479, 3602, 25596, 9781, 12163, 150, 18749, -21782, -12307, 27578, -2757, -12573, 12565, 6345, -18956, 19503, -15617, 1443, -16778, 36851, 23588, -28474, 5749, 40695, -7521, -53669, -2497, -18530, 6770, 57038, 3926, -6927, -15399, 1848, -64649, -27728, 3644, 49608, 15187, -8902, -9480, -7398, -40425, 4824, 23767, -7594, -6905, 33089, 18786, 12192, 24670, 31114, 35334, -4501, -14676, 7107, -59018, -21352, 20777, 19661, 20653, 33754, -885, -43758, 6269, 51897, -28719, -97488, -9527, 13746, 11644, 17644, -21720, 23782, -10481, 47867, 20752, 33810, -1875, 39918, -7710, -40840, 19808, -47075, 23066, 46616, 25201, 9287, 35436, -1602, 9645, -11978, 13273, 15544, 33465, 20063, 44539, 11687, 27314, -6538, -37467, 14031, 32970, -27086, 41323, 29551, 65910, -39027, -37800, -22232, 8212, 46316, -28981, -55282, 50417, -44929, -44062, 73879, 37573, -2596, -10877, -21893, -133218, -33707, -25753, -9531, 17530, 61126, 2748, -56235, 43874, -10872, -90459, -30387, 115267, -7264, -44452, 122626, 14839, -599, 10337, 57166, -67467, -54957, 63669, 1202, 18488, 52594, 7205, -97822, 612, 78069, -5403, -63562, 47236, 36873, -154827, -26188, 82427, -39521, 5628, 7416, 5276, -53095, 47050, 26121, -42207, 79021, -13035, 2499, -66943, 29040, -72355, -23480, 23416, -12885, -44225, -42688, -4224, 19858, 55299, 15735, 11465, 101876, -39169, 51786, 14723, 43280, -68697, 16410, 92295, 56767, 7183, 111850, 4550, 115451, -38443, -19642, -35058, 10230, 93829, 8925, 63047, 3146, 29250, 8530, 5255, -98117, -115517, -76817, -8724, 41044, 1312, -35974, 79333, -28567, 7547, -10580, -24559, -16238, 10794, -3867, 24848, 57770, -51536, -35040, 71033, 29853, 62029, -7125, -125585, -32169, -47907, 156811, -65176, -58006, -15757, -57861, 11963, 30225, -41901, -41681, 31310, 27982, 18613, 61760, 60746, -59096, 33499, 30097, -17997, 24032, 56442, -83042, 23747, -20931, -21978, -158752, -9883, -73598, -7987, -7333, -125403, -116329, 30585, 53281, 51018, -29193, 88575, 8264, -40147, -16289, 113088, 12810, -6508, 101552, -13037, 34440, -41840, 101643, 24263, 80532, 61748, 65574, 6423, -20672, 6591, -10834, -71716, 86919, -92626, 39161, 28490, 81319, 46676, 106720, 43530, 26998, 57456, -8862, 60989, 13982, 3119, -2224, 14743, 55415, -49093, -29303, 28999, 1789, 55953, -84043, -7780, -65013, 57129, -47251, 61484, 61994, -78361, -82778, 22487, -26894, 9756, -74637, -15519, -4360, 30115, 42433, 35475, 15286, 69768, 21509, -20214, 78675, -21163, 13596, 11443, -10698, -53621, -53867, -24155, 64500, -42784, -33077, -16500, 873, -52788, 14546, -38011, 36974, -39849, -34029, -94311, 83068, -50437, -26169, -46746, 59185, 42259, -101379, -12943, 30089, -59086, 36271, 22723, -30253, -52472, -70826, -23289, 3331, -31687, 14183, -857, -28627, 35246, -51284, 5636, -6933, 66539, 36654, 50927, 24783, 3457, 33276, 45281, 45650, -4938, -9968, -22590, 47995, 69229, 5214, -58365, -17907, -14651, 18668, 18009, 12649, -11851, -13387, 20339, 52472, -1087, -21458, -68647, 52295, 15849, 40608, 15323, 25164, -29368, 10352, -7055, 7159, 21695, -5373, -54849, 101103, -24963, -10511, 33227, 7659, 41042, -69588, 26718, -20515, 6441, 38135, -63, 24088, -35364, -12785, -18709, 47843, 48533, -48575, 17251, -19394, 32878, -9010, -9050, 504, -12407, 28076, -3429, 25324, -4210, -26119, 752, -29203, 28251, -11324, -32140, -3366, -25135, 18702, -31588, -7047, -24267, 49987, -14975, -33169, 37744, -7720, -9035, 16964, -2807, -421, 14114, -17097, -13662, 40628, -12139, -9427, 5369, 17551, -13232, -16211, 9804, -7422, 2677, 28635, -8280, -4906, 2908, -22558, 5604, 12459, 8756, -3980, -4745, -18525, 7913, 5970, -16457, 20230, -6247, -13812, 2505, 11899, 1409, -15094, 22540, -18863, 137, 11123, -4516, 2290, -8594, 12150, -10380, 3005, 5235, -7350, 2535, -858], ZZ) assert dup_mul(p1, p2, ZZ) == res def test_dmp_mul(): assert dmp_mul([ZZ(5)], [ZZ(7)], 0, ZZ) == \ dup_mul([ZZ(5)], [ZZ(7)], ZZ) assert dmp_mul([QQ(5, 7)], [QQ(3, 7)], 0, QQ) == \ dup_mul([QQ(5, 7)], [QQ(3, 7)], QQ) assert dmp_mul([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_mul([[[ZZ(1)]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_mul([[[]]], [[[ZZ(1)]]], 2, ZZ) == [[[]]] assert dmp_mul([[[ZZ(2)]]], [[[ZZ(1)]]], 2, ZZ) == [[[ZZ(2)]]] assert dmp_mul([[[ZZ(1)]]], [[[ZZ(2)]]], 2, ZZ) == [[[ZZ(2)]]] assert dmp_mul([[[]]], [[[]]], 2, QQ) == [[[]]] assert dmp_mul([[[QQ(1, 2)]]], [[[]]], 2, QQ) == [[[]]] assert dmp_mul([[[]]], [[[QQ(1, 2)]]], 2, QQ) == [[[]]] assert dmp_mul([[[QQ(2, 7)]]], [[[QQ(1, 3)]]], 2, QQ) == [[[QQ(2, 21)]]] assert dmp_mul([[[QQ(1, 7)]]], [[[QQ(2, 3)]]], 2, QQ) == [[[QQ(2, 21)]]] K = FF(6) assert dmp_mul( [[K(2)], [K(1)]], [[K(3)], [K(4)]], 1, K) == [[K(5)], [K(4)]] def test_dup_sqr(): assert dup_sqr([], ZZ) == [] assert dup_sqr([ZZ(2)], ZZ) == [ZZ(4)] assert dup_sqr([ZZ(1), ZZ(2)], ZZ) == [ZZ(1), ZZ(4), ZZ(4)] assert dup_sqr([], QQ) == [] assert dup_sqr([QQ(2, 3)], QQ) == [QQ(4, 9)] assert dup_sqr([QQ(1, 3), QQ(2, 3)], QQ) == [QQ(1, 9), QQ(4, 9), QQ(4, 9)] f = dup_normal([2, 0, 0, 1, 7], ZZ) assert dup_sqr(f, ZZ) == dup_normal([4, 0, 0, 4, 28, 0, 1, 14, 49], ZZ) K = FF(9) assert dup_sqr([K(3), K(4)], K) == [K(6), K(7)] def test_dmp_sqr(): assert dmp_sqr([ZZ(1), ZZ(2)], 0, ZZ) == \ dup_sqr([ZZ(1), ZZ(2)], ZZ) assert dmp_sqr([[[]]], 2, ZZ) == [[[]]] assert dmp_sqr([[[ZZ(2)]]], 2, ZZ) == [[[ZZ(4)]]] assert dmp_sqr([[[]]], 2, QQ) == [[[]]] assert dmp_sqr([[[QQ(2, 3)]]], 2, QQ) == [[[QQ(4, 9)]]] K = FF(9) assert dmp_sqr([[K(3)], [K(4)]], 1, K) == [[K(6)], [K(7)]] def test_dup_pow(): assert dup_pow([], 0, ZZ) == [ZZ(1)] assert dup_pow([], 0, QQ) == [QQ(1)] assert dup_pow([], 1, ZZ) == [] assert dup_pow([], 7, ZZ) == [] assert dup_pow([ZZ(1)], 0, ZZ) == [ZZ(1)] assert dup_pow([ZZ(1)], 1, ZZ) == [ZZ(1)] assert dup_pow([ZZ(1)], 7, ZZ) == [ZZ(1)] assert dup_pow([ZZ(3)], 0, ZZ) == [ZZ(1)] assert dup_pow([ZZ(3)], 1, ZZ) == [ZZ(3)] assert dup_pow([ZZ(3)], 7, ZZ) == [ZZ(2187)] assert dup_pow([QQ(1, 1)], 0, QQ) == [QQ(1, 1)] assert dup_pow([QQ(1, 1)], 1, QQ) == [QQ(1, 1)] assert dup_pow([QQ(1, 1)], 7, QQ) == [QQ(1, 1)] assert dup_pow([QQ(3, 7)], 0, QQ) == [QQ(1, 1)] assert dup_pow([QQ(3, 7)], 1, QQ) == [QQ(3, 7)] assert dup_pow([QQ(3, 7)], 7, QQ) == [QQ(2187, 823543)] f = dup_normal([2, 0, 0, 1, 7], ZZ) assert dup_pow(f, 0, ZZ) == dup_normal([1], ZZ) assert dup_pow(f, 1, ZZ) == dup_normal([2, 0, 0, 1, 7], ZZ) assert dup_pow(f, 2, ZZ) == dup_normal([4, 0, 0, 4, 28, 0, 1, 14, 49], ZZ) assert dup_pow(f, 3, ZZ) == dup_normal( [8, 0, 0, 12, 84, 0, 6, 84, 294, 1, 21, 147, 343], ZZ) def test_dmp_pow(): assert dmp_pow([[]], 0, 1, ZZ) == [[ZZ(1)]] assert dmp_pow([[]], 0, 1, QQ) == [[QQ(1)]] assert dmp_pow([[]], 1, 1, ZZ) == [[]] assert dmp_pow([[]], 7, 1, ZZ) == [[]] assert dmp_pow([[ZZ(1)]], 0, 1, ZZ) == [[ZZ(1)]] assert dmp_pow([[ZZ(1)]], 1, 1, ZZ) == [[ZZ(1)]] assert dmp_pow([[ZZ(1)]], 7, 1, ZZ) == [[ZZ(1)]] assert dmp_pow([[QQ(3, 7)]], 0, 1, QQ) == [[QQ(1, 1)]] assert dmp_pow([[QQ(3, 7)]], 1, 1, QQ) == [[QQ(3, 7)]] assert dmp_pow([[QQ(3, 7)]], 7, 1, QQ) == [[QQ(2187, 823543)]] f = dup_normal([2, 0, 0, 1, 7], ZZ) assert dmp_pow(f, 2, 0, ZZ) == dup_pow(f, 2, ZZ) def test_dup_pdiv(): f = dup_normal([3, 1, 1, 5], ZZ) g = dup_normal([5, -3, 1], ZZ) q = dup_normal([15, 14], ZZ) r = dup_normal([52, 111], ZZ) assert dup_pdiv(f, g, ZZ) == (q, r) assert dup_pquo(f, g, ZZ) == q assert dup_prem(f, g, ZZ) == r raises(ExactQuotientFailed, lambda: dup_pexquo(f, g, ZZ)) f = dup_normal([3, 1, 1, 5], QQ) g = dup_normal([5, -3, 1], QQ) q = dup_normal([15, 14], QQ) r = dup_normal([52, 111], QQ) assert dup_pdiv(f, g, QQ) == (q, r) assert dup_pquo(f, g, QQ) == q assert dup_prem(f, g, QQ) == r raises(ExactQuotientFailed, lambda: dup_pexquo(f, g, QQ)) def test_dmp_pdiv(): f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) g = dmp_normal([[1], [-1, 0]], 1, ZZ) q = dmp_normal([[1], [1, 0]], 1, ZZ) r = dmp_normal([[2, 0, 0]], 1, ZZ) assert dmp_pdiv(f, g, 1, ZZ) == (q, r) assert dmp_pquo(f, g, 1, ZZ) == q assert dmp_prem(f, g, 1, ZZ) == r raises(ExactQuotientFailed, lambda: dmp_pexquo(f, g, 1, ZZ)) f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) g = dmp_normal([[2], [-2, 0]], 1, ZZ) q = dmp_normal([[2], [2, 0]], 1, ZZ) r = dmp_normal([[8, 0, 0]], 1, ZZ) assert dmp_pdiv(f, g, 1, ZZ) == (q, r) assert dmp_pquo(f, g, 1, ZZ) == q assert dmp_prem(f, g, 1, ZZ) == r raises(ExactQuotientFailed, lambda: dmp_pexquo(f, g, 1, ZZ)) def test_dup_rr_div(): raises(ZeroDivisionError, lambda: dup_rr_div([1, 2, 3], [], ZZ)) f = dup_normal([3, 1, 1, 5], ZZ) g = dup_normal([5, -3, 1], ZZ) q, r = [], f assert dup_rr_div(f, g, ZZ) == (q, r) def test_dmp_rr_div(): raises(ZeroDivisionError, lambda: dmp_rr_div([[1, 2], [3]], [[]], 1, ZZ)) f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) g = dmp_normal([[1], [-1, 0]], 1, ZZ) q = dmp_normal([[1], [1, 0]], 1, ZZ) r = dmp_normal([[2, 0, 0]], 1, ZZ) assert dmp_rr_div(f, g, 1, ZZ) == (q, r) f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) g = dmp_normal([[-1], [1, 0]], 1, ZZ) q = dmp_normal([[-1], [-1, 0]], 1, ZZ) r = dmp_normal([[2, 0, 0]], 1, ZZ) assert dmp_rr_div(f, g, 1, ZZ) == (q, r) f = dmp_normal([[1], [], [1, 0, 0]], 1, ZZ) g = dmp_normal([[2], [-2, 0]], 1, ZZ) q, r = [[]], f assert dmp_rr_div(f, g, 1, ZZ) == (q, r) def test_dup_ff_div(): raises(ZeroDivisionError, lambda: dup_ff_div([1, 2, 3], [], QQ)) f = dup_normal([3, 1, 1, 5], QQ) g = dup_normal([5, -3, 1], QQ) q = [QQ(3, 5), QQ(14, 25)] r = [QQ(52, 25), QQ(111, 25)] assert dup_ff_div(f, g, QQ) == (q, r) def test_dup_ff_div_gmpy2(): try: from gmpy2 import mpq except ImportError: return from sympy.polys.domains import GMPYRationalField K = GMPYRationalField() f = [mpq(1,3), mpq(3,2)] g = [mpq(2,1)] assert dmp_ff_div(f, g, 0, K) == ([mpq(1,6), mpq(3,4)], []) f = [mpq(1,2), mpq(1,3), mpq(1,4), mpq(1,5)] g = [mpq(-1,1), mpq(1,1), mpq(-1,1)] assert dmp_ff_div(f, g, 0, K) == ([mpq(-1,2), mpq(-5,6)], [mpq(7,12), mpq(-19,30)]) def test_dmp_ff_div(): raises(ZeroDivisionError, lambda: dmp_ff_div([[1, 2], [3]], [[]], 1, QQ)) f = dmp_normal([[1], [], [1, 0, 0]], 1, QQ) g = dmp_normal([[1], [-1, 0]], 1, QQ) q = [[QQ(1, 1)], [QQ(1, 1), QQ(0, 1)]] r = [[QQ(2, 1), QQ(0, 1), QQ(0, 1)]] assert dmp_ff_div(f, g, 1, QQ) == (q, r) f = dmp_normal([[1], [], [1, 0, 0]], 1, QQ) g = dmp_normal([[-1], [1, 0]], 1, QQ) q = [[QQ(-1, 1)], [QQ(-1, 1), QQ(0, 1)]] r = [[QQ(2, 1), QQ(0, 1), QQ(0, 1)]] assert dmp_ff_div(f, g, 1, QQ) == (q, r) f = dmp_normal([[1], [], [1, 0, 0]], 1, QQ) g = dmp_normal([[2], [-2, 0]], 1, QQ) q = [[QQ(1, 2)], [QQ(1, 2), QQ(0, 1)]] r = [[QQ(2, 1), QQ(0, 1), QQ(0, 1)]] assert dmp_ff_div(f, g, 1, QQ) == (q, r) def test_dup_div(): f, g, q, r = [5, 4, 3, 2, 1], [1, 2, 3], [5, -6, 0], [20, 1] assert dup_div(f, g, ZZ) == (q, r) assert dup_quo(f, g, ZZ) == q assert dup_rem(f, g, ZZ) == r raises(ExactQuotientFailed, lambda: dup_exquo(f, g, ZZ)) f, g, q, r = [5, 4, 3, 2, 1, 0], [1, 2, 0, 0, 9], [5, -6], [15, 2, -44, 54] assert dup_div(f, g, ZZ) == (q, r) assert dup_quo(f, g, ZZ) == q assert dup_rem(f, g, ZZ) == r raises(ExactQuotientFailed, lambda: dup_exquo(f, g, ZZ)) def test_dmp_div(): f, g, q, r = [5, 4, 3, 2, 1], [1, 2, 3], [5, -6, 0], [20, 1] assert dmp_div(f, g, 0, ZZ) == (q, r) assert dmp_quo(f, g, 0, ZZ) == q assert dmp_rem(f, g, 0, ZZ) == r raises(ExactQuotientFailed, lambda: dmp_exquo(f, g, 0, ZZ)) f, g, q, r = [[[1]]], [[[2]], [1]], [[[]]], [[[1]]] assert dmp_div(f, g, 2, ZZ) == (q, r) assert dmp_quo(f, g, 2, ZZ) == q assert dmp_rem(f, g, 2, ZZ) == r raises(ExactQuotientFailed, lambda: dmp_exquo(f, g, 2, ZZ)) def test_dup_max_norm(): assert dup_max_norm([], ZZ) == 0 assert dup_max_norm([1], ZZ) == 1 assert dup_max_norm([1, 4, 2, 3], ZZ) == 4 def test_dmp_max_norm(): assert dmp_max_norm([[[]]], 2, ZZ) == 0 assert dmp_max_norm([[[1]]], 2, ZZ) == 1 assert dmp_max_norm(f_0, 2, ZZ) == 6 def test_dup_l1_norm(): assert dup_l1_norm([], ZZ) == 0 assert dup_l1_norm([1], ZZ) == 1 assert dup_l1_norm([1, 4, 2, 3], ZZ) == 10 def test_dmp_l1_norm(): assert dmp_l1_norm([[[]]], 2, ZZ) == 0 assert dmp_l1_norm([[[1]]], 2, ZZ) == 1 assert dmp_l1_norm(f_0, 2, ZZ) == 31 def test_dup_expand(): assert dup_expand((), ZZ) == [1] assert dup_expand(([1, 2, 3], [1, 2], [7, 5, 4, 3]), ZZ) == \ dup_mul([1, 2, 3], dup_mul([1, 2], [7, 5, 4, 3], ZZ), ZZ) def test_dmp_expand(): assert dmp_expand((), 1, ZZ) == [[1]] assert dmp_expand(([[1], [2], [3]], [[1], [2]], [[7], [5], [4], [3]]), 1, ZZ) == \ dmp_mul([[1], [2], [3]], dmp_mul([[1], [2]], [[7], [5], [ 4], [3]], 1, ZZ), 1, ZZ) sympy-sympy-1.9/sympy/polys/tests/test_densebasic.py000066400000000000000000000517301412543434000231330ustar00rootroot00000000000000"""Tests for dense recursive polynomials' basic tools. """ from sympy.polys.densebasic import ( dup_LC, dmp_LC, dup_TC, dmp_TC, dmp_ground_LC, dmp_ground_TC, dmp_true_LT, dup_degree, dmp_degree, dmp_degree_in, dmp_degree_list, dup_strip, dmp_strip, dmp_validate, dup_reverse, dup_copy, dmp_copy, dup_normal, dmp_normal, dup_convert, dmp_convert, dup_from_sympy, dmp_from_sympy, dup_nth, dmp_nth, dmp_ground_nth, dmp_zero_p, dmp_zero, dmp_one_p, dmp_one, dmp_ground_p, dmp_ground, dmp_negative_p, dmp_positive_p, dmp_zeros, dmp_grounds, dup_from_dict, dup_from_raw_dict, dup_to_dict, dup_to_raw_dict, dmp_from_dict, dmp_to_dict, dmp_swap, dmp_permute, dmp_nest, dmp_raise, dup_deflate, dmp_deflate, dup_multi_deflate, dmp_multi_deflate, dup_inflate, dmp_inflate, dmp_exclude, dmp_include, dmp_inject, dmp_eject, dup_terms_gcd, dmp_terms_gcd, dmp_list_terms, dmp_apply_pairs, dup_slice, dup_random, ) from sympy.polys.specialpolys import f_polys from sympy.polys.domains import ZZ, QQ from sympy.polys.rings import ring from sympy.core.singleton import S from sympy.testing.pytest import raises from sympy import oo f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] def test_dup_LC(): assert dup_LC([], ZZ) == 0 assert dup_LC([2, 3, 4, 5], ZZ) == 2 def test_dup_TC(): assert dup_TC([], ZZ) == 0 assert dup_TC([2, 3, 4, 5], ZZ) == 5 def test_dmp_LC(): assert dmp_LC([[]], ZZ) == [] assert dmp_LC([[2, 3, 4], [5]], ZZ) == [2, 3, 4] assert dmp_LC([[[]]], ZZ) == [[]] assert dmp_LC([[[2], [3, 4]], [[5]]], ZZ) == [[2], [3, 4]] def test_dmp_TC(): assert dmp_TC([[]], ZZ) == [] assert dmp_TC([[2, 3, 4], [5]], ZZ) == [5] assert dmp_TC([[[]]], ZZ) == [[]] assert dmp_TC([[[2], [3, 4]], [[5]]], ZZ) == [[5]] def test_dmp_ground_LC(): assert dmp_ground_LC([[]], 1, ZZ) == 0 assert dmp_ground_LC([[2, 3, 4], [5]], 1, ZZ) == 2 assert dmp_ground_LC([[[]]], 2, ZZ) == 0 assert dmp_ground_LC([[[2], [3, 4]], [[5]]], 2, ZZ) == 2 def test_dmp_ground_TC(): assert dmp_ground_TC([[]], 1, ZZ) == 0 assert dmp_ground_TC([[2, 3, 4], [5]], 1, ZZ) == 5 assert dmp_ground_TC([[[]]], 2, ZZ) == 0 assert dmp_ground_TC([[[2], [3, 4]], [[5]]], 2, ZZ) == 5 def test_dmp_true_LT(): assert dmp_true_LT([[]], 1, ZZ) == ((0, 0), 0) assert dmp_true_LT([[7]], 1, ZZ) == ((0, 0), 7) assert dmp_true_LT([[1, 0]], 1, ZZ) == ((0, 1), 1) assert dmp_true_LT([[1], []], 1, ZZ) == ((1, 0), 1) assert dmp_true_LT([[1, 0], []], 1, ZZ) == ((1, 1), 1) def test_dup_degree(): assert dup_degree([]) is -oo assert dup_degree([1]) == 0 assert dup_degree([1, 0]) == 1 assert dup_degree([1, 0, 0, 0, 1]) == 4 def test_dmp_degree(): assert dmp_degree([[]], 1) is -oo assert dmp_degree([[[]]], 2) is -oo assert dmp_degree([[1]], 1) == 0 assert dmp_degree([[2], [1]], 1) == 1 def test_dmp_degree_in(): assert dmp_degree_in([[[]]], 0, 2) is -oo assert dmp_degree_in([[[]]], 1, 2) is -oo assert dmp_degree_in([[[]]], 2, 2) is -oo assert dmp_degree_in([[[1]]], 0, 2) == 0 assert dmp_degree_in([[[1]]], 1, 2) == 0 assert dmp_degree_in([[[1]]], 2, 2) == 0 assert dmp_degree_in(f_4, 0, 2) == 9 assert dmp_degree_in(f_4, 1, 2) == 12 assert dmp_degree_in(f_4, 2, 2) == 8 assert dmp_degree_in(f_6, 0, 2) == 4 assert dmp_degree_in(f_6, 1, 2) == 4 assert dmp_degree_in(f_6, 2, 2) == 6 assert dmp_degree_in(f_6, 3, 3) == 3 raises(IndexError, lambda: dmp_degree_in([[1]], -5, 1)) def test_dmp_degree_list(): assert dmp_degree_list([[[[ ]]]], 3) == (-oo, -oo, -oo, -oo) assert dmp_degree_list([[[[1]]]], 3) == ( 0, 0, 0, 0) assert dmp_degree_list(f_0, 2) == (2, 2, 2) assert dmp_degree_list(f_1, 2) == (3, 3, 3) assert dmp_degree_list(f_2, 2) == (5, 3, 3) assert dmp_degree_list(f_3, 2) == (5, 4, 7) assert dmp_degree_list(f_4, 2) == (9, 12, 8) assert dmp_degree_list(f_5, 2) == (3, 3, 3) assert dmp_degree_list(f_6, 3) == (4, 4, 6, 3) def test_dup_strip(): assert dup_strip([]) == [] assert dup_strip([0]) == [] assert dup_strip([0, 0, 0]) == [] assert dup_strip([1]) == [1] assert dup_strip([0, 1]) == [1] assert dup_strip([0, 0, 0, 1]) == [1] assert dup_strip([1, 2, 0]) == [1, 2, 0] assert dup_strip([0, 1, 2, 0]) == [1, 2, 0] assert dup_strip([0, 0, 0, 1, 2, 0]) == [1, 2, 0] def test_dmp_strip(): assert dmp_strip([0, 1, 0], 0) == [1, 0] assert dmp_strip([[]], 1) == [[]] assert dmp_strip([[], []], 1) == [[]] assert dmp_strip([[], [], []], 1) == [[]] assert dmp_strip([[[]]], 2) == [[[]]] assert dmp_strip([[[]], [[]]], 2) == [[[]]] assert dmp_strip([[[]], [[]], [[]]], 2) == [[[]]] assert dmp_strip([[[1]]], 2) == [[[1]]] assert dmp_strip([[[]], [[1]]], 2) == [[[1]]] assert dmp_strip([[[]], [[1]], [[]]], 2) == [[[1]], [[]]] def test_dmp_validate(): assert dmp_validate([]) == ([], 0) assert dmp_validate([0, 0, 0, 1, 0]) == ([1, 0], 0) assert dmp_validate([[[]]]) == ([[[]]], 2) assert dmp_validate([[0], [], [0], [1], [0]]) == ([[1], []], 1) raises(ValueError, lambda: dmp_validate([[0], 0, [0], [1], [0]])) def test_dup_reverse(): assert dup_reverse([1, 2, 0, 3]) == [3, 0, 2, 1] assert dup_reverse([1, 2, 3, 0]) == [3, 2, 1] def test_dup_copy(): f = [ZZ(1), ZZ(0), ZZ(2)] g = dup_copy(f) g[0], g[2] = ZZ(7), ZZ(0) assert f != g def test_dmp_copy(): f = [[ZZ(1)], [ZZ(2), ZZ(0)]] g = dmp_copy(f, 1) g[0][0], g[1][1] = ZZ(7), ZZ(1) assert f != g def test_dup_normal(): assert dup_normal([0, 0, 2, 1, 0, 11, 0], ZZ) == \ [ZZ(2), ZZ(1), ZZ(0), ZZ(11), ZZ(0)] def test_dmp_normal(): assert dmp_normal([[0], [], [0, 2, 1], [0], [11], []], 1, ZZ) == \ [[ZZ(2), ZZ(1)], [], [ZZ(11)], []] def test_dup_convert(): K0, K1 = ZZ['x'], ZZ f = [K0(1), K0(2), K0(0), K0(3)] assert dup_convert(f, K0, K1) == \ [ZZ(1), ZZ(2), ZZ(0), ZZ(3)] def test_dmp_convert(): K0, K1 = ZZ['x'], ZZ f = [[K0(1)], [K0(2)], [], [K0(3)]] assert dmp_convert(f, 1, K0, K1) == \ [[ZZ(1)], [ZZ(2)], [], [ZZ(3)]] def test_dup_from_sympy(): assert dup_from_sympy([S.One, S(2)], ZZ) == \ [ZZ(1), ZZ(2)] assert dup_from_sympy([S.Half, S(3)], QQ) == \ [QQ(1, 2), QQ(3, 1)] def test_dmp_from_sympy(): assert dmp_from_sympy([[S.One, S(2)], [S.Zero]], 1, ZZ) == \ [[ZZ(1), ZZ(2)], []] assert dmp_from_sympy([[S.Half, S(2)]], 1, QQ) == \ [[QQ(1, 2), QQ(2, 1)]] def test_dup_nth(): assert dup_nth([1, 2, 3], 0, ZZ) == 3 assert dup_nth([1, 2, 3], 1, ZZ) == 2 assert dup_nth([1, 2, 3], 2, ZZ) == 1 assert dup_nth([1, 2, 3], 9, ZZ) == 0 raises(IndexError, lambda: dup_nth([3, 4, 5], -1, ZZ)) def test_dmp_nth(): assert dmp_nth([[1], [2], [3]], 0, 1, ZZ) == [3] assert dmp_nth([[1], [2], [3]], 1, 1, ZZ) == [2] assert dmp_nth([[1], [2], [3]], 2, 1, ZZ) == [1] assert dmp_nth([[1], [2], [3]], 9, 1, ZZ) == [] raises(IndexError, lambda: dmp_nth([[3], [4], [5]], -1, 1, ZZ)) def test_dmp_ground_nth(): assert dmp_ground_nth([[]], (0, 0), 1, ZZ) == 0 assert dmp_ground_nth([[1], [2], [3]], (0, 0), 1, ZZ) == 3 assert dmp_ground_nth([[1], [2], [3]], (1, 0), 1, ZZ) == 2 assert dmp_ground_nth([[1], [2], [3]], (2, 0), 1, ZZ) == 1 assert dmp_ground_nth([[1], [2], [3]], (2, 1), 1, ZZ) == 0 assert dmp_ground_nth([[1], [2], [3]], (3, 0), 1, ZZ) == 0 raises(IndexError, lambda: dmp_ground_nth([[3], [4], [5]], (2, -1), 1, ZZ)) def test_dmp_zero_p(): assert dmp_zero_p([], 0) is True assert dmp_zero_p([[]], 1) is True assert dmp_zero_p([[[]]], 2) is True assert dmp_zero_p([[[1]]], 2) is False def test_dmp_zero(): assert dmp_zero(0) == [] assert dmp_zero(2) == [[[]]] def test_dmp_one_p(): assert dmp_one_p([1], 0, ZZ) is True assert dmp_one_p([[1]], 1, ZZ) is True assert dmp_one_p([[[1]]], 2, ZZ) is True assert dmp_one_p([[[12]]], 2, ZZ) is False def test_dmp_one(): assert dmp_one(0, ZZ) == [ZZ(1)] assert dmp_one(2, ZZ) == [[[ZZ(1)]]] def test_dmp_ground_p(): assert dmp_ground_p([], 0, 0) is True assert dmp_ground_p([[]], 0, 1) is True assert dmp_ground_p([[]], 1, 1) is False assert dmp_ground_p([[ZZ(1)]], 1, 1) is True assert dmp_ground_p([[[ZZ(2)]]], 2, 2) is True assert dmp_ground_p([[[ZZ(2)]]], 3, 2) is False assert dmp_ground_p([[[ZZ(3)], []]], 3, 2) is False assert dmp_ground_p([], None, 0) is True assert dmp_ground_p([[]], None, 1) is True assert dmp_ground_p([ZZ(1)], None, 0) is True assert dmp_ground_p([[[ZZ(1)]]], None, 2) is True assert dmp_ground_p([[[ZZ(3)], []]], None, 2) is False def test_dmp_ground(): assert dmp_ground(ZZ(0), 2) == [[[]]] assert dmp_ground(ZZ(7), -1) == ZZ(7) assert dmp_ground(ZZ(7), 0) == [ZZ(7)] assert dmp_ground(ZZ(7), 2) == [[[ZZ(7)]]] def test_dmp_zeros(): assert dmp_zeros(4, 0, ZZ) == [[], [], [], []] assert dmp_zeros(0, 2, ZZ) == [] assert dmp_zeros(1, 2, ZZ) == [[[[]]]] assert dmp_zeros(2, 2, ZZ) == [[[[]]], [[[]]]] assert dmp_zeros(3, 2, ZZ) == [[[[]]], [[[]]], [[[]]]] assert dmp_zeros(3, -1, ZZ) == [0, 0, 0] def test_dmp_grounds(): assert dmp_grounds(ZZ(7), 0, 2) == [] assert dmp_grounds(ZZ(7), 1, 2) == [[[[7]]]] assert dmp_grounds(ZZ(7), 2, 2) == [[[[7]]], [[[7]]]] assert dmp_grounds(ZZ(7), 3, 2) == [[[[7]]], [[[7]]], [[[7]]]] assert dmp_grounds(ZZ(7), 3, -1) == [7, 7, 7] def test_dmp_negative_p(): assert dmp_negative_p([[[]]], 2, ZZ) is False assert dmp_negative_p([[[1], [2]]], 2, ZZ) is False assert dmp_negative_p([[[-1], [2]]], 2, ZZ) is True def test_dmp_positive_p(): assert dmp_positive_p([[[]]], 2, ZZ) is False assert dmp_positive_p([[[1], [2]]], 2, ZZ) is True assert dmp_positive_p([[[-1], [2]]], 2, ZZ) is False def test_dup_from_to_dict(): assert dup_from_raw_dict({}, ZZ) == [] assert dup_from_dict({}, ZZ) == [] assert dup_to_raw_dict([]) == {} assert dup_to_dict([]) == {} assert dup_to_raw_dict([], ZZ, zero=True) == {0: ZZ(0)} assert dup_to_dict([], ZZ, zero=True) == {(0,): ZZ(0)} f = [3, 0, 0, 2, 0, 0, 0, 0, 8] g = {8: 3, 5: 2, 0: 8} h = {(8,): 3, (5,): 2, (0,): 8} assert dup_from_raw_dict(g, ZZ) == f assert dup_from_dict(h, ZZ) == f assert dup_to_raw_dict(f) == g assert dup_to_dict(f) == h R, x,y = ring("x,y", ZZ) K = R.to_domain() f = [R(3), R(0), R(2), R(0), R(0), R(8)] g = {5: R(3), 3: R(2), 0: R(8)} h = {(5,): R(3), (3,): R(2), (0,): R(8)} assert dup_from_raw_dict(g, K) == f assert dup_from_dict(h, K) == f assert dup_to_raw_dict(f) == g assert dup_to_dict(f) == h def test_dmp_from_to_dict(): assert dmp_from_dict({}, 1, ZZ) == [[]] assert dmp_to_dict([[]], 1) == {} assert dmp_to_dict([], 0, ZZ, zero=True) == {(0,): ZZ(0)} assert dmp_to_dict([[]], 1, ZZ, zero=True) == {(0, 0): ZZ(0)} f = [[3], [], [], [2], [], [], [], [], [8]] g = {(8, 0): 3, (5, 0): 2, (0, 0): 8} assert dmp_from_dict(g, 1, ZZ) == f assert dmp_to_dict(f, 1) == g def test_dmp_swap(): f = dmp_normal([[1, 0, 0], [], [1, 0], [], [1]], 1, ZZ) g = dmp_normal([[1, 0, 0, 0, 0], [1, 0, 0], [1]], 1, ZZ) assert dmp_swap(f, 1, 1, 1, ZZ) == f assert dmp_swap(f, 0, 1, 1, ZZ) == g assert dmp_swap(g, 0, 1, 1, ZZ) == f raises(IndexError, lambda: dmp_swap(f, -1, -7, 1, ZZ)) def test_dmp_permute(): f = dmp_normal([[1, 0, 0], [], [1, 0], [], [1]], 1, ZZ) g = dmp_normal([[1, 0, 0, 0, 0], [1, 0, 0], [1]], 1, ZZ) assert dmp_permute(f, [0, 1], 1, ZZ) == f assert dmp_permute(g, [0, 1], 1, ZZ) == g assert dmp_permute(f, [1, 0], 1, ZZ) == g assert dmp_permute(g, [1, 0], 1, ZZ) == f def test_dmp_nest(): assert dmp_nest(ZZ(1), 2, ZZ) == [[[1]]] assert dmp_nest([[1]], 0, ZZ) == [[1]] assert dmp_nest([[1]], 1, ZZ) == [[[1]]] assert dmp_nest([[1]], 2, ZZ) == [[[[1]]]] def test_dmp_raise(): assert dmp_raise([], 2, 0, ZZ) == [[[]]] assert dmp_raise([[1]], 0, 1, ZZ) == [[1]] assert dmp_raise([[1, 2, 3], [], [2, 3]], 2, 1, ZZ) == \ [[[[1]], [[2]], [[3]]], [[[]]], [[[2]], [[3]]]] def test_dup_deflate(): assert dup_deflate([], ZZ) == (1, []) assert dup_deflate([2], ZZ) == (1, [2]) assert dup_deflate([1, 2, 3], ZZ) == (1, [1, 2, 3]) assert dup_deflate([1, 0, 2, 0, 3], ZZ) == (2, [1, 2, 3]) assert dup_deflate(dup_from_raw_dict({7: 1, 1: 1}, ZZ), ZZ) == \ (1, [1, 0, 0, 0, 0, 0, 1, 0]) assert dup_deflate(dup_from_raw_dict({7: 1, 0: 1}, ZZ), ZZ) == \ (7, [1, 1]) assert dup_deflate(dup_from_raw_dict({7: 1, 3: 1}, ZZ), ZZ) == \ (1, [1, 0, 0, 0, 1, 0, 0, 0]) assert dup_deflate(dup_from_raw_dict({7: 1, 4: 1}, ZZ), ZZ) == \ (1, [1, 0, 0, 1, 0, 0, 0, 0]) assert dup_deflate(dup_from_raw_dict({8: 1, 4: 1}, ZZ), ZZ) == \ (4, [1, 1, 0]) assert dup_deflate(dup_from_raw_dict({8: 1}, ZZ), ZZ) == \ (8, [1, 0]) assert dup_deflate(dup_from_raw_dict({7: 1}, ZZ), ZZ) == \ (7, [1, 0]) assert dup_deflate(dup_from_raw_dict({1: 1}, ZZ), ZZ) == \ (1, [1, 0]) def test_dmp_deflate(): assert dmp_deflate([[]], 1, ZZ) == ((1, 1), [[]]) assert dmp_deflate([[2]], 1, ZZ) == ((1, 1), [[2]]) f = [[1, 0, 0], [], [1, 0], [], [1]] assert dmp_deflate(f, 1, ZZ) == ((2, 1), [[1, 0, 0], [1, 0], [1]]) def test_dup_multi_deflate(): assert dup_multi_deflate(([2],), ZZ) == (1, ([2],)) assert dup_multi_deflate(([], []), ZZ) == (1, ([], [])) assert dup_multi_deflate(([1, 2, 3],), ZZ) == (1, ([1, 2, 3],)) assert dup_multi_deflate(([1, 0, 2, 0, 3],), ZZ) == (2, ([1, 2, 3],)) assert dup_multi_deflate(([1, 0, 2, 0, 3], [2, 0, 0]), ZZ) == \ (2, ([1, 2, 3], [2, 0])) assert dup_multi_deflate(([1, 0, 2, 0, 3], [2, 1, 0]), ZZ) == \ (1, ([1, 0, 2, 0, 3], [2, 1, 0])) def test_dmp_multi_deflate(): assert dmp_multi_deflate(([[]],), 1, ZZ) == \ ((1, 1), ([[]],)) assert dmp_multi_deflate(([[]], [[]]), 1, ZZ) == \ ((1, 1), ([[]], [[]])) assert dmp_multi_deflate(([[1]], [[]]), 1, ZZ) == \ ((1, 1), ([[1]], [[]])) assert dmp_multi_deflate(([[1]], [[2]]), 1, ZZ) == \ ((1, 1), ([[1]], [[2]])) assert dmp_multi_deflate(([[1]], [[2, 0]]), 1, ZZ) == \ ((1, 1), ([[1]], [[2, 0]])) assert dmp_multi_deflate(([[2, 0]], [[2, 0]]), 1, ZZ) == \ ((1, 1), ([[2, 0]], [[2, 0]])) assert dmp_multi_deflate( ([[2]], [[2, 0, 0]]), 1, ZZ) == ((1, 2), ([[2]], [[2, 0]])) assert dmp_multi_deflate( ([[2, 0, 0]], [[2, 0, 0]]), 1, ZZ) == ((1, 2), ([[2, 0]], [[2, 0]])) assert dmp_multi_deflate(([2, 0, 0], [1, 0, 4, 0, 1]), 0, ZZ) == \ ((2,), ([2, 0], [1, 4, 1])) f = [[1, 0, 0], [], [1, 0], [], [1]] g = [[1, 0, 1, 0], [], [1]] assert dmp_multi_deflate((f,), 1, ZZ) == \ ((2, 1), ([[1, 0, 0], [1, 0], [1]],)) assert dmp_multi_deflate((f, g), 1, ZZ) == \ ((2, 1), ([[1, 0, 0], [1, 0], [1]], [[1, 0, 1, 0], [1]])) def test_dup_inflate(): assert dup_inflate([], 17, ZZ) == [] assert dup_inflate([1, 2, 3], 1, ZZ) == [1, 2, 3] assert dup_inflate([1, 2, 3], 2, ZZ) == [1, 0, 2, 0, 3] assert dup_inflate([1, 2, 3], 3, ZZ) == [1, 0, 0, 2, 0, 0, 3] assert dup_inflate([1, 2, 3], 4, ZZ) == [1, 0, 0, 0, 2, 0, 0, 0, 3] raises(IndexError, lambda: dup_inflate([1, 2, 3], 0, ZZ)) def test_dmp_inflate(): assert dmp_inflate([1], (3,), 0, ZZ) == [1] assert dmp_inflate([[]], (3, 7), 1, ZZ) == [[]] assert dmp_inflate([[2]], (1, 2), 1, ZZ) == [[2]] assert dmp_inflate([[2, 0]], (1, 1), 1, ZZ) == [[2, 0]] assert dmp_inflate([[2, 0]], (1, 2), 1, ZZ) == [[2, 0, 0]] assert dmp_inflate([[2, 0]], (1, 3), 1, ZZ) == [[2, 0, 0, 0]] assert dmp_inflate([[1, 0, 0], [1], [1, 0]], (2, 1), 1, ZZ) == \ [[1, 0, 0], [], [1], [], [1, 0]] raises(IndexError, lambda: dmp_inflate([[]], (-3, 7), 1, ZZ)) def test_dmp_exclude(): assert dmp_exclude([[[]]], 2, ZZ) == ([], [[[]]], 2) assert dmp_exclude([[[7]]], 2, ZZ) == ([], [[[7]]], 2) assert dmp_exclude([1, 2, 3], 0, ZZ) == ([], [1, 2, 3], 0) assert dmp_exclude([[1], [2, 3]], 1, ZZ) == ([], [[1], [2, 3]], 1) assert dmp_exclude([[1, 2, 3]], 1, ZZ) == ([0], [1, 2, 3], 0) assert dmp_exclude([[1], [2], [3]], 1, ZZ) == ([1], [1, 2, 3], 0) assert dmp_exclude([[[1, 2, 3]]], 2, ZZ) == ([0, 1], [1, 2, 3], 0) assert dmp_exclude([[[1]], [[2]], [[3]]], 2, ZZ) == ([1, 2], [1, 2, 3], 0) def test_dmp_include(): assert dmp_include([1, 2, 3], [], 0, ZZ) == [1, 2, 3] assert dmp_include([1, 2, 3], [0], 0, ZZ) == [[1, 2, 3]] assert dmp_include([1, 2, 3], [1], 0, ZZ) == [[1], [2], [3]] assert dmp_include([1, 2, 3], [0, 1], 0, ZZ) == [[[1, 2, 3]]] assert dmp_include([1, 2, 3], [1, 2], 0, ZZ) == [[[1]], [[2]], [[3]]] def test_dmp_inject(): R, x,y = ring("x,y", ZZ) K = R.to_domain() assert dmp_inject([], 0, K) == ([[[]]], 2) assert dmp_inject([[]], 1, K) == ([[[[]]]], 3) assert dmp_inject([R(1)], 0, K) == ([[[1]]], 2) assert dmp_inject([[R(1)]], 1, K) == ([[[[1]]]], 3) assert dmp_inject([R(1), 2*x + 3*y + 4], 0, K) == ([[[1]], [[2], [3, 4]]], 2) f = [3*x**2 + 7*x*y + 5*y**2, 2*x, R(0), x*y**2 + 11] g = [[[3], [7, 0], [5, 0, 0]], [[2], []], [[]], [[1, 0, 0], [11]]] assert dmp_inject(f, 0, K) == (g, 2) def test_dmp_eject(): R, x,y = ring("x,y", ZZ) K = R.to_domain() assert dmp_eject([[[]]], 2, K) == [] assert dmp_eject([[[[]]]], 3, K) == [[]] assert dmp_eject([[[1]]], 2, K) == [R(1)] assert dmp_eject([[[[1]]]], 3, K) == [[R(1)]] assert dmp_eject([[[1]], [[2], [3, 4]]], 2, K) == [R(1), 2*x + 3*y + 4] f = [3*x**2 + 7*x*y + 5*y**2, 2*x, R(0), x*y**2 + 11] g = [[[3], [7, 0], [5, 0, 0]], [[2], []], [[]], [[1, 0, 0], [11]]] assert dmp_eject(g, 2, K) == f def test_dup_terms_gcd(): assert dup_terms_gcd([], ZZ) == (0, []) assert dup_terms_gcd([1, 0, 1], ZZ) == (0, [1, 0, 1]) assert dup_terms_gcd([1, 0, 1, 0], ZZ) == (1, [1, 0, 1]) def test_dmp_terms_gcd(): assert dmp_terms_gcd([[]], 1, ZZ) == ((0, 0), [[]]) assert dmp_terms_gcd([1, 0, 1, 0], 0, ZZ) == ((1,), [1, 0, 1]) assert dmp_terms_gcd([[1], [], [1], []], 1, ZZ) == ((1, 0), [[1], [], [1]]) assert dmp_terms_gcd( [[1, 0], [], [1]], 1, ZZ) == ((0, 0), [[1, 0], [], [1]]) assert dmp_terms_gcd( [[1, 0], [1, 0, 0], [], []], 1, ZZ) == ((2, 1), [[1], [1, 0]]) def test_dmp_list_terms(): assert dmp_list_terms([[[]]], 2, ZZ) == [((0, 0, 0), 0)] assert dmp_list_terms([[[1]]], 2, ZZ) == [((0, 0, 0), 1)] assert dmp_list_terms([1, 2, 4, 3, 5], 0, ZZ) == \ [((4,), 1), ((3,), 2), ((2,), 4), ((1,), 3), ((0,), 5)] assert dmp_list_terms([[1], [2, 4], [3, 5, 0]], 1, ZZ) == \ [((2, 0), 1), ((1, 1), 2), ((1, 0), 4), ((0, 2), 3), ((0, 1), 5)] f = [[2, 0, 0, 0], [1, 0, 0], []] assert dmp_list_terms(f, 1, ZZ, order='lex') == [((2, 3), 2), ((1, 2), 1)] assert dmp_list_terms( f, 1, ZZ, order='grlex') == [((2, 3), 2), ((1, 2), 1)] f = [[2, 0, 0, 0], [1, 0, 0, 0, 0, 0], []] assert dmp_list_terms(f, 1, ZZ, order='lex') == [((2, 3), 2), ((1, 5), 1)] assert dmp_list_terms( f, 1, ZZ, order='grlex') == [((1, 5), 1), ((2, 3), 2)] def test_dmp_apply_pairs(): h = lambda a, b: a*b assert dmp_apply_pairs([1, 2, 3], [4, 5, 6], h, [], 0, ZZ) == [4, 10, 18] assert dmp_apply_pairs([2, 3], [4, 5, 6], h, [], 0, ZZ) == [10, 18] assert dmp_apply_pairs([1, 2, 3], [5, 6], h, [], 0, ZZ) == [10, 18] assert dmp_apply_pairs( [[1, 2], [3]], [[4, 5], [6]], h, [], 1, ZZ) == [[4, 10], [18]] assert dmp_apply_pairs( [[1, 2], [3]], [[4], [5, 6]], h, [], 1, ZZ) == [[8], [18]] assert dmp_apply_pairs( [[1], [2, 3]], [[4, 5], [6]], h, [], 1, ZZ) == [[5], [18]] def test_dup_slice(): f = [1, 2, 3, 4] assert dup_slice(f, 0, 0, ZZ) == [] assert dup_slice(f, 0, 1, ZZ) == [4] assert dup_slice(f, 0, 2, ZZ) == [3, 4] assert dup_slice(f, 0, 3, ZZ) == [2, 3, 4] assert dup_slice(f, 0, 4, ZZ) == [1, 2, 3, 4] assert dup_slice(f, 0, 4, ZZ) == f assert dup_slice(f, 0, 9, ZZ) == f assert dup_slice(f, 1, 0, ZZ) == [] assert dup_slice(f, 1, 1, ZZ) == [] assert dup_slice(f, 1, 2, ZZ) == [3, 0] assert dup_slice(f, 1, 3, ZZ) == [2, 3, 0] assert dup_slice(f, 1, 4, ZZ) == [1, 2, 3, 0] assert dup_slice([1, 2], 0, 3, ZZ) == [1, 2] def test_dup_random(): f = dup_random(0, -10, 10, ZZ) assert dup_degree(f) == 0 assert all(-10 <= c <= 10 for c in f) f = dup_random(1, -20, 20, ZZ) assert dup_degree(f) == 1 assert all(-20 <= c <= 20 for c in f) f = dup_random(2, -30, 30, ZZ) assert dup_degree(f) == 2 assert all(-30 <= c <= 30 for c in f) f = dup_random(3, -40, 40, ZZ) assert dup_degree(f) == 3 assert all(-40 <= c <= 40 for c in f) sympy-sympy-1.9/sympy/polys/tests/test_densetools.py000066400000000000000000000576331412543434000232220ustar00rootroot00000000000000"""Tests for dense recursive polynomials' tools. """ from sympy.polys.densebasic import ( dup_normal, dmp_normal, dup_from_raw_dict, dmp_convert, dmp_swap, ) from sympy.polys.densearith import dmp_mul_ground from sympy.polys.densetools import ( dup_clear_denoms, dmp_clear_denoms, dup_integrate, dmp_integrate, dmp_integrate_in, dup_diff, dmp_diff, dmp_diff_in, dup_eval, dmp_eval, dmp_eval_in, dmp_eval_tail, dmp_diff_eval_in, dup_trunc, dmp_trunc, dmp_ground_trunc, dup_monic, dmp_ground_monic, dup_content, dmp_ground_content, dup_primitive, dmp_ground_primitive, dup_extract, dmp_ground_extract, dup_real_imag, dup_mirror, dup_scale, dup_shift, dup_transform, dup_compose, dmp_compose, dup_decompose, dmp_lift, dup_sign_variations, dup_revert, dmp_revert, ) from sympy.polys.polyclasses import ANP from sympy.polys.polyerrors import ( MultivariatePolynomialError, ExactQuotientFailed, NotReversible, DomainError, ) from sympy.polys.specialpolys import f_polys from sympy.polys.domains import FF, ZZ, QQ, EX from sympy.polys.rings import ring from sympy import S, I, sin from sympy.abc import x from sympy.testing.pytest import raises f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] def test_dup_integrate(): assert dup_integrate([], 1, QQ) == [] assert dup_integrate([], 2, QQ) == [] assert dup_integrate([QQ(1)], 1, QQ) == [QQ(1), QQ(0)] assert dup_integrate([QQ(1)], 2, QQ) == [QQ(1, 2), QQ(0), QQ(0)] assert dup_integrate([QQ(1), QQ(2), QQ(3)], 0, QQ) == \ [QQ(1), QQ(2), QQ(3)] assert dup_integrate([QQ(1), QQ(2), QQ(3)], 1, QQ) == \ [QQ(1, 3), QQ(1), QQ(3), QQ(0)] assert dup_integrate([QQ(1), QQ(2), QQ(3)], 2, QQ) == \ [QQ(1, 12), QQ(1, 3), QQ(3, 2), QQ(0), QQ(0)] assert dup_integrate([QQ(1), QQ(2), QQ(3)], 3, QQ) == \ [QQ(1, 60), QQ(1, 12), QQ(1, 2), QQ(0), QQ(0), QQ(0)] assert dup_integrate(dup_from_raw_dict({29: QQ(17)}, QQ), 3, QQ) == \ dup_from_raw_dict({32: QQ(17, 29760)}, QQ) assert dup_integrate(dup_from_raw_dict({29: QQ(17), 5: QQ(1, 2)}, QQ), 3, QQ) == \ dup_from_raw_dict({32: QQ(17, 29760), 8: QQ(1, 672)}, QQ) def test_dmp_integrate(): assert dmp_integrate([[[]]], 1, 2, QQ) == [[[]]] assert dmp_integrate([[[]]], 2, 2, QQ) == [[[]]] assert dmp_integrate([[[QQ(1)]]], 1, 2, QQ) == [[[QQ(1)]], [[]]] assert dmp_integrate([[[QQ(1)]]], 2, 2, QQ) == [[[QQ(1, 2)]], [[]], [[]]] assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 0, 1, QQ) == \ [[QQ(1)], [QQ(2)], [QQ(3)]] assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 1, 1, QQ) == \ [[QQ(1, 3)], [QQ(1)], [QQ(3)], []] assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 2, 1, QQ) == \ [[QQ(1, 12)], [QQ(1, 3)], [QQ(3, 2)], [], []] assert dmp_integrate([[QQ(1)], [QQ(2)], [QQ(3)]], 3, 1, QQ) == \ [[QQ(1, 60)], [QQ(1, 12)], [QQ(1, 2)], [], [], []] def test_dmp_integrate_in(): f = dmp_convert(f_6, 3, ZZ, QQ) assert dmp_integrate_in(f, 2, 1, 3, QQ) == \ dmp_swap( dmp_integrate(dmp_swap(f, 0, 1, 3, QQ), 2, 3, QQ), 0, 1, 3, QQ) assert dmp_integrate_in(f, 3, 1, 3, QQ) == \ dmp_swap( dmp_integrate(dmp_swap(f, 0, 1, 3, QQ), 3, 3, QQ), 0, 1, 3, QQ) assert dmp_integrate_in(f, 2, 2, 3, QQ) == \ dmp_swap( dmp_integrate(dmp_swap(f, 0, 2, 3, QQ), 2, 3, QQ), 0, 2, 3, QQ) assert dmp_integrate_in(f, 3, 2, 3, QQ) == \ dmp_swap( dmp_integrate(dmp_swap(f, 0, 2, 3, QQ), 3, 3, QQ), 0, 2, 3, QQ) def test_dup_diff(): assert dup_diff([], 1, ZZ) == [] assert dup_diff([7], 1, ZZ) == [] assert dup_diff([2, 7], 1, ZZ) == [2] assert dup_diff([1, 2, 1], 1, ZZ) == [2, 2] assert dup_diff([1, 2, 3, 4], 1, ZZ) == [3, 4, 3] assert dup_diff([1, -1, 0, 0, 2], 1, ZZ) == [4, -3, 0, 0] f = dup_normal([17, 34, 56, -345, 23, 76, 0, 0, 12, 3, 7], ZZ) assert dup_diff(f, 0, ZZ) == f assert dup_diff(f, 1, ZZ) == [170, 306, 448, -2415, 138, 380, 0, 0, 24, 3] assert dup_diff(f, 2, ZZ) == dup_diff(dup_diff(f, 1, ZZ), 1, ZZ) assert dup_diff( f, 3, ZZ) == dup_diff(dup_diff(dup_diff(f, 1, ZZ), 1, ZZ), 1, ZZ) K = FF(3) f = dup_normal([17, 34, 56, -345, 23, 76, 0, 0, 12, 3, 7], K) assert dup_diff(f, 1, K) == dup_normal([2, 0, 1, 0, 0, 2, 0, 0, 0, 0], K) assert dup_diff(f, 2, K) == dup_normal([1, 0, 0, 2, 0, 0, 0], K) assert dup_diff(f, 3, K) == dup_normal([], K) assert dup_diff(f, 0, K) == f assert dup_diff(f, 2, K) == dup_diff(dup_diff(f, 1, K), 1, K) assert dup_diff( f, 3, K) == dup_diff(dup_diff(dup_diff(f, 1, K), 1, K), 1, K) def test_dmp_diff(): assert dmp_diff([], 1, 0, ZZ) == [] assert dmp_diff([[]], 1, 1, ZZ) == [[]] assert dmp_diff([[[]]], 1, 2, ZZ) == [[[]]] assert dmp_diff([[[1], [2]]], 1, 2, ZZ) == [[[]]] assert dmp_diff([[[1]], [[]]], 1, 2, ZZ) == [[[1]]] assert dmp_diff([[[3]], [[1]], [[]]], 1, 2, ZZ) == [[[6]], [[1]]] assert dmp_diff([1, -1, 0, 0, 2], 1, 0, ZZ) == \ dup_diff([1, -1, 0, 0, 2], 1, ZZ) assert dmp_diff(f_6, 0, 3, ZZ) == f_6 assert dmp_diff(f_6, 1, 3, ZZ) == [[[[8460]], [[]]], [[[135, 0, 0], [], [], [-135, 0, 0]]], [[[]]], [[[-423]], [[-47]], [[]], [[141], [], [94, 0], []], [[]]]] assert dmp_diff( f_6, 2, 3, ZZ) == dmp_diff(dmp_diff(f_6, 1, 3, ZZ), 1, 3, ZZ) assert dmp_diff(f_6, 3, 3, ZZ) == dmp_diff( dmp_diff(dmp_diff(f_6, 1, 3, ZZ), 1, 3, ZZ), 1, 3, ZZ) K = FF(23) F_6 = dmp_normal(f_6, 3, K) assert dmp_diff(F_6, 0, 3, K) == F_6 assert dmp_diff(F_6, 1, 3, K) == dmp_diff(F_6, 1, 3, K) assert dmp_diff(F_6, 2, 3, K) == dmp_diff(dmp_diff(F_6, 1, 3, K), 1, 3, K) assert dmp_diff(F_6, 3, 3, K) == dmp_diff( dmp_diff(dmp_diff(F_6, 1, 3, K), 1, 3, K), 1, 3, K) def test_dmp_diff_in(): assert dmp_diff_in(f_6, 2, 1, 3, ZZ) == \ dmp_swap(dmp_diff(dmp_swap(f_6, 0, 1, 3, ZZ), 2, 3, ZZ), 0, 1, 3, ZZ) assert dmp_diff_in(f_6, 3, 1, 3, ZZ) == \ dmp_swap(dmp_diff(dmp_swap(f_6, 0, 1, 3, ZZ), 3, 3, ZZ), 0, 1, 3, ZZ) assert dmp_diff_in(f_6, 2, 2, 3, ZZ) == \ dmp_swap(dmp_diff(dmp_swap(f_6, 0, 2, 3, ZZ), 2, 3, ZZ), 0, 2, 3, ZZ) assert dmp_diff_in(f_6, 3, 2, 3, ZZ) == \ dmp_swap(dmp_diff(dmp_swap(f_6, 0, 2, 3, ZZ), 3, 3, ZZ), 0, 2, 3, ZZ) def test_dup_eval(): assert dup_eval([], 7, ZZ) == 0 assert dup_eval([1, 2], 0, ZZ) == 2 assert dup_eval([1, 2, 3], 7, ZZ) == 66 def test_dmp_eval(): assert dmp_eval([], 3, 0, ZZ) == 0 assert dmp_eval([[]], 3, 1, ZZ) == [] assert dmp_eval([[[]]], 3, 2, ZZ) == [[]] assert dmp_eval([[1, 2]], 0, 1, ZZ) == [1, 2] assert dmp_eval([[[1]]], 3, 2, ZZ) == [[1]] assert dmp_eval([[[1, 2]]], 3, 2, ZZ) == [[1, 2]] assert dmp_eval([[3, 2], [1, 2]], 3, 1, ZZ) == [10, 8] assert dmp_eval([[[3, 2]], [[1, 2]]], 3, 2, ZZ) == [[10, 8]] def test_dmp_eval_in(): assert dmp_eval_in( f_6, -2, 1, 3, ZZ) == dmp_eval(dmp_swap(f_6, 0, 1, 3, ZZ), -2, 3, ZZ) assert dmp_eval_in( f_6, 7, 1, 3, ZZ) == dmp_eval(dmp_swap(f_6, 0, 1, 3, ZZ), 7, 3, ZZ) assert dmp_eval_in(f_6, -2, 2, 3, ZZ) == dmp_swap( dmp_eval(dmp_swap(f_6, 0, 2, 3, ZZ), -2, 3, ZZ), 0, 1, 2, ZZ) assert dmp_eval_in(f_6, 7, 2, 3, ZZ) == dmp_swap( dmp_eval(dmp_swap(f_6, 0, 2, 3, ZZ), 7, 3, ZZ), 0, 1, 2, ZZ) f = [[[int(45)]], [[]], [[]], [[int(-9)], [-1], [], [int(3), int(0), int(10), int(0)]]] assert dmp_eval_in(f, -2, 2, 2, ZZ) == \ [[45], [], [], [-9, -1, 0, -44]] def test_dmp_eval_tail(): assert dmp_eval_tail([[]], [1], 1, ZZ) == [] assert dmp_eval_tail([[[]]], [1], 2, ZZ) == [[]] assert dmp_eval_tail([[[]]], [1, 2], 2, ZZ) == [] assert dmp_eval_tail(f_0, [], 2, ZZ) == f_0 assert dmp_eval_tail(f_0, [1, -17, 8], 2, ZZ) == 84496 assert dmp_eval_tail(f_0, [-17, 8], 2, ZZ) == [-1409, 3, 85902] assert dmp_eval_tail(f_0, [8], 2, ZZ) == [[83, 2], [3], [302, 81, 1]] assert dmp_eval_tail(f_1, [-17, 8], 2, ZZ) == [-136, 15699, 9166, -27144] assert dmp_eval_tail( f_2, [-12, 3], 2, ZZ) == [-1377, 0, -702, -1224, 0, -624] assert dmp_eval_tail( f_3, [-12, 3], 2, ZZ) == [144, 82, -5181, -28872, -14868, -540] assert dmp_eval_tail( f_4, [25, -1], 2, ZZ) == [152587890625, 9765625, -59605407714843750, -3839159765625, -1562475, 9536712644531250, 610349546750, -4, 24414375000, 1562520] assert dmp_eval_tail(f_5, [25, -1], 2, ZZ) == [-1, -78, -2028, -17576] assert dmp_eval_tail(f_6, [0, 2, 4], 3, ZZ) == [5040, 0, 0, 4480] def test_dmp_diff_eval_in(): assert dmp_diff_eval_in(f_6, 2, 7, 1, 3, ZZ) == \ dmp_eval(dmp_diff(dmp_swap(f_6, 0, 1, 3, ZZ), 2, 3, ZZ), 7, 3, ZZ) def test_dup_revert(): f = [-QQ(1, 720), QQ(0), QQ(1, 24), QQ(0), -QQ(1, 2), QQ(0), QQ(1)] g = [QQ(61, 720), QQ(0), QQ(5, 24), QQ(0), QQ(1, 2), QQ(0), QQ(1)] assert dup_revert(f, 8, QQ) == g raises(NotReversible, lambda: dup_revert([QQ(1), QQ(0)], 3, QQ)) def test_dmp_revert(): f = [-QQ(1, 720), QQ(0), QQ(1, 24), QQ(0), -QQ(1, 2), QQ(0), QQ(1)] g = [QQ(61, 720), QQ(0), QQ(5, 24), QQ(0), QQ(1, 2), QQ(0), QQ(1)] assert dmp_revert(f, 8, 0, QQ) == g raises(MultivariatePolynomialError, lambda: dmp_revert([[1]], 2, 1, QQ)) def test_dup_trunc(): assert dup_trunc([1, 2, 3, 4, 5, 6], ZZ(3), ZZ) == [1, -1, 0, 1, -1, 0] assert dup_trunc([6, 5, 4, 3, 2, 1], ZZ(3), ZZ) == [-1, 1, 0, -1, 1] def test_dmp_trunc(): assert dmp_trunc([[]], [1, 2], 2, ZZ) == [[]] assert dmp_trunc([[1, 2], [1, 4, 1], [1]], [1, 2], 1, ZZ) == [[-3], [1]] def test_dmp_ground_trunc(): assert dmp_ground_trunc(f_0, ZZ(3), 2, ZZ) == \ dmp_normal( [[[1, -1, 0], [-1]], [[]], [[1, -1, 0], [1, -1, 1], [1]]], 2, ZZ) def test_dup_monic(): assert dup_monic([3, 6, 9], ZZ) == [1, 2, 3] raises(ExactQuotientFailed, lambda: dup_monic([3, 4, 5], ZZ)) assert dup_monic([], QQ) == [] assert dup_monic([QQ(1)], QQ) == [QQ(1)] assert dup_monic([QQ(7), QQ(1), QQ(21)], QQ) == [QQ(1), QQ(1, 7), QQ(3)] def test_dmp_ground_monic(): assert dmp_ground_monic([[3], [6], [9]], 1, ZZ) == [[1], [2], [3]] raises( ExactQuotientFailed, lambda: dmp_ground_monic([[3], [4], [5]], 1, ZZ)) assert dmp_ground_monic([[]], 1, QQ) == [[]] assert dmp_ground_monic([[QQ(1)]], 1, QQ) == [[QQ(1)]] assert dmp_ground_monic( [[QQ(7)], [QQ(1)], [QQ(21)]], 1, QQ) == [[QQ(1)], [QQ(1, 7)], [QQ(3)]] def test_dup_content(): assert dup_content([], ZZ) == ZZ(0) assert dup_content([1], ZZ) == ZZ(1) assert dup_content([-1], ZZ) == ZZ(1) assert dup_content([1, 1], ZZ) == ZZ(1) assert dup_content([2, 2], ZZ) == ZZ(2) assert dup_content([1, 2, 1], ZZ) == ZZ(1) assert dup_content([2, 4, 2], ZZ) == ZZ(2) assert dup_content([QQ(2, 3), QQ(4, 9)], QQ) == QQ(2, 9) assert dup_content([QQ(2, 3), QQ(4, 5)], QQ) == QQ(2, 15) def test_dmp_ground_content(): assert dmp_ground_content([[]], 1, ZZ) == ZZ(0) assert dmp_ground_content([[]], 1, QQ) == QQ(0) assert dmp_ground_content([[1]], 1, ZZ) == ZZ(1) assert dmp_ground_content([[-1]], 1, ZZ) == ZZ(1) assert dmp_ground_content([[1], [1]], 1, ZZ) == ZZ(1) assert dmp_ground_content([[2], [2]], 1, ZZ) == ZZ(2) assert dmp_ground_content([[1], [2], [1]], 1, ZZ) == ZZ(1) assert dmp_ground_content([[2], [4], [2]], 1, ZZ) == ZZ(2) assert dmp_ground_content([[QQ(2, 3)], [QQ(4, 9)]], 1, QQ) == QQ(2, 9) assert dmp_ground_content([[QQ(2, 3)], [QQ(4, 5)]], 1, QQ) == QQ(2, 15) assert dmp_ground_content(f_0, 2, ZZ) == ZZ(1) assert dmp_ground_content( dmp_mul_ground(f_0, ZZ(2), 2, ZZ), 2, ZZ) == ZZ(2) assert dmp_ground_content(f_1, 2, ZZ) == ZZ(1) assert dmp_ground_content( dmp_mul_ground(f_1, ZZ(3), 2, ZZ), 2, ZZ) == ZZ(3) assert dmp_ground_content(f_2, 2, ZZ) == ZZ(1) assert dmp_ground_content( dmp_mul_ground(f_2, ZZ(4), 2, ZZ), 2, ZZ) == ZZ(4) assert dmp_ground_content(f_3, 2, ZZ) == ZZ(1) assert dmp_ground_content( dmp_mul_ground(f_3, ZZ(5), 2, ZZ), 2, ZZ) == ZZ(5) assert dmp_ground_content(f_4, 2, ZZ) == ZZ(1) assert dmp_ground_content( dmp_mul_ground(f_4, ZZ(6), 2, ZZ), 2, ZZ) == ZZ(6) assert dmp_ground_content(f_5, 2, ZZ) == ZZ(1) assert dmp_ground_content( dmp_mul_ground(f_5, ZZ(7), 2, ZZ), 2, ZZ) == ZZ(7) assert dmp_ground_content(f_6, 3, ZZ) == ZZ(1) assert dmp_ground_content( dmp_mul_ground(f_6, ZZ(8), 3, ZZ), 3, ZZ) == ZZ(8) def test_dup_primitive(): assert dup_primitive([], ZZ) == (ZZ(0), []) assert dup_primitive([ZZ(1)], ZZ) == (ZZ(1), [ZZ(1)]) assert dup_primitive([ZZ(1), ZZ(1)], ZZ) == (ZZ(1), [ZZ(1), ZZ(1)]) assert dup_primitive([ZZ(2), ZZ(2)], ZZ) == (ZZ(2), [ZZ(1), ZZ(1)]) assert dup_primitive( [ZZ(1), ZZ(2), ZZ(1)], ZZ) == (ZZ(1), [ZZ(1), ZZ(2), ZZ(1)]) assert dup_primitive( [ZZ(2), ZZ(4), ZZ(2)], ZZ) == (ZZ(2), [ZZ(1), ZZ(2), ZZ(1)]) assert dup_primitive([], QQ) == (QQ(0), []) assert dup_primitive([QQ(1)], QQ) == (QQ(1), [QQ(1)]) assert dup_primitive([QQ(1), QQ(1)], QQ) == (QQ(1), [QQ(1), QQ(1)]) assert dup_primitive([QQ(2), QQ(2)], QQ) == (QQ(2), [QQ(1), QQ(1)]) assert dup_primitive( [QQ(1), QQ(2), QQ(1)], QQ) == (QQ(1), [QQ(1), QQ(2), QQ(1)]) assert dup_primitive( [QQ(2), QQ(4), QQ(2)], QQ) == (QQ(2), [QQ(1), QQ(2), QQ(1)]) assert dup_primitive( [QQ(2, 3), QQ(4, 9)], QQ) == (QQ(2, 9), [QQ(3), QQ(2)]) assert dup_primitive( [QQ(2, 3), QQ(4, 5)], QQ) == (QQ(2, 15), [QQ(5), QQ(6)]) def test_dmp_ground_primitive(): assert dmp_ground_primitive([[]], 1, ZZ) == (ZZ(0), [[]]) assert dmp_ground_primitive(f_0, 2, ZZ) == (ZZ(1), f_0) assert dmp_ground_primitive( dmp_mul_ground(f_0, ZZ(2), 2, ZZ), 2, ZZ) == (ZZ(2), f_0) assert dmp_ground_primitive(f_1, 2, ZZ) == (ZZ(1), f_1) assert dmp_ground_primitive( dmp_mul_ground(f_1, ZZ(3), 2, ZZ), 2, ZZ) == (ZZ(3), f_1) assert dmp_ground_primitive(f_2, 2, ZZ) == (ZZ(1), f_2) assert dmp_ground_primitive( dmp_mul_ground(f_2, ZZ(4), 2, ZZ), 2, ZZ) == (ZZ(4), f_2) assert dmp_ground_primitive(f_3, 2, ZZ) == (ZZ(1), f_3) assert dmp_ground_primitive( dmp_mul_ground(f_3, ZZ(5), 2, ZZ), 2, ZZ) == (ZZ(5), f_3) assert dmp_ground_primitive(f_4, 2, ZZ) == (ZZ(1), f_4) assert dmp_ground_primitive( dmp_mul_ground(f_4, ZZ(6), 2, ZZ), 2, ZZ) == (ZZ(6), f_4) assert dmp_ground_primitive(f_5, 2, ZZ) == (ZZ(1), f_5) assert dmp_ground_primitive( dmp_mul_ground(f_5, ZZ(7), 2, ZZ), 2, ZZ) == (ZZ(7), f_5) assert dmp_ground_primitive(f_6, 3, ZZ) == (ZZ(1), f_6) assert dmp_ground_primitive( dmp_mul_ground(f_6, ZZ(8), 3, ZZ), 3, ZZ) == (ZZ(8), f_6) assert dmp_ground_primitive([[ZZ(2)]], 1, ZZ) == (ZZ(2), [[ZZ(1)]]) assert dmp_ground_primitive([[QQ(2)]], 1, QQ) == (QQ(2), [[QQ(1)]]) assert dmp_ground_primitive( [[QQ(2, 3)], [QQ(4, 9)]], 1, QQ) == (QQ(2, 9), [[QQ(3)], [QQ(2)]]) assert dmp_ground_primitive( [[QQ(2, 3)], [QQ(4, 5)]], 1, QQ) == (QQ(2, 15), [[QQ(5)], [QQ(6)]]) def test_dup_extract(): f = dup_normal([2930944, 0, 2198208, 0, 549552, 0, 45796], ZZ) g = dup_normal([17585664, 0, 8792832, 0, 1099104, 0], ZZ) F = dup_normal([64, 0, 48, 0, 12, 0, 1], ZZ) G = dup_normal([384, 0, 192, 0, 24, 0], ZZ) assert dup_extract(f, g, ZZ) == (45796, F, G) def test_dmp_ground_extract(): f = dmp_normal( [[2930944], [], [2198208], [], [549552], [], [45796]], 1, ZZ) g = dmp_normal([[17585664], [], [8792832], [], [1099104], []], 1, ZZ) F = dmp_normal([[64], [], [48], [], [12], [], [1]], 1, ZZ) G = dmp_normal([[384], [], [192], [], [24], []], 1, ZZ) assert dmp_ground_extract(f, g, 1, ZZ) == (45796, F, G) def test_dup_real_imag(): assert dup_real_imag([], ZZ) == ([[]], [[]]) assert dup_real_imag([1], ZZ) == ([[1]], [[]]) assert dup_real_imag([1, 1], ZZ) == ([[1], [1]], [[1, 0]]) assert dup_real_imag([1, 2], ZZ) == ([[1], [2]], [[1, 0]]) assert dup_real_imag( [1, 2, 3], ZZ) == ([[1], [2], [-1, 0, 3]], [[2, 0], [2, 0]]) raises(DomainError, lambda: dup_real_imag([EX(1), EX(2)], EX)) def test_dup_mirror(): assert dup_mirror([], ZZ) == [] assert dup_mirror([1], ZZ) == [1] assert dup_mirror([1, 2, 3, 4, 5], ZZ) == [1, -2, 3, -4, 5] assert dup_mirror([1, 2, 3, 4, 5, 6], ZZ) == [-1, 2, -3, 4, -5, 6] def test_dup_scale(): assert dup_scale([], -1, ZZ) == [] assert dup_scale([1], -1, ZZ) == [1] assert dup_scale([1, 2, 3, 4, 5], -1, ZZ) == [1, -2, 3, -4, 5] assert dup_scale([1, 2, 3, 4, 5], -7, ZZ) == [2401, -686, 147, -28, 5] def test_dup_shift(): assert dup_shift([], 1, ZZ) == [] assert dup_shift([1], 1, ZZ) == [1] assert dup_shift([1, 2, 3, 4, 5], 1, ZZ) == [1, 6, 15, 20, 15] assert dup_shift([1, 2, 3, 4, 5], 7, ZZ) == [1, 30, 339, 1712, 3267] def test_dup_transform(): assert dup_transform([], [], [1, 1], ZZ) == [] assert dup_transform([], [1], [1, 1], ZZ) == [] assert dup_transform([], [1, 2], [1, 1], ZZ) == [] assert dup_transform([6, -5, 4, -3, 17], [1, -3, 4], [2, -3], ZZ) == \ [6, -82, 541, -2205, 6277, -12723, 17191, -13603, 4773] def test_dup_compose(): assert dup_compose([], [], ZZ) == [] assert dup_compose([], [1], ZZ) == [] assert dup_compose([], [1, 2], ZZ) == [] assert dup_compose([1], [], ZZ) == [1] assert dup_compose([1, 2, 0], [], ZZ) == [] assert dup_compose([1, 2, 1], [], ZZ) == [1] assert dup_compose([1, 2, 1], [1], ZZ) == [4] assert dup_compose([1, 2, 1], [7], ZZ) == [64] assert dup_compose([1, 2, 1], [1, -1], ZZ) == [1, 0, 0] assert dup_compose([1, 2, 1], [1, 1], ZZ) == [1, 4, 4] assert dup_compose([1, 2, 1], [1, 2, 1], ZZ) == [1, 4, 8, 8, 4] def test_dmp_compose(): assert dmp_compose([1, 2, 1], [1, 2, 1], 0, ZZ) == [1, 4, 8, 8, 4] assert dmp_compose([[[]]], [[[]]], 2, ZZ) == [[[]]] assert dmp_compose([[[]]], [[[1]]], 2, ZZ) == [[[]]] assert dmp_compose([[[]]], [[[1]], [[2]]], 2, ZZ) == [[[]]] assert dmp_compose([[[1]]], [], 2, ZZ) == [[[1]]] assert dmp_compose([[1], [2], [ ]], [[]], 1, ZZ) == [[]] assert dmp_compose([[1], [2], [1]], [[]], 1, ZZ) == [[1]] assert dmp_compose([[1], [2], [1]], [[1]], 1, ZZ) == [[4]] assert dmp_compose([[1], [2], [1]], [[7]], 1, ZZ) == [[64]] assert dmp_compose([[1], [2], [1]], [[1], [-1]], 1, ZZ) == [[1], [ ], [ ]] assert dmp_compose([[1], [2], [1]], [[1], [ 1]], 1, ZZ) == [[1], [4], [4]] assert dmp_compose( [[1], [2], [1]], [[1], [2], [1]], 1, ZZ) == [[1], [4], [8], [8], [4]] def test_dup_decompose(): assert dup_decompose([1], ZZ) == [[1]] assert dup_decompose([1, 0], ZZ) == [[1, 0]] assert dup_decompose([1, 0, 0, 0], ZZ) == [[1, 0, 0, 0]] assert dup_decompose([1, 0, 0, 0, 0], ZZ) == [[1, 0, 0], [1, 0, 0]] assert dup_decompose( [1, 0, 0, 0, 0, 0, 0], ZZ) == [[1, 0, 0, 0], [1, 0, 0]] assert dup_decompose([7, 0, 0, 0, 1], ZZ) == [[7, 0, 1], [1, 0, 0]] assert dup_decompose([4, 0, 3, 0, 2], ZZ) == [[4, 3, 2], [1, 0, 0]] f = [1, 0, 20, 0, 150, 0, 500, 0, 625, -2, 0, -10, 9] assert dup_decompose(f, ZZ) == [[1, 0, 0, -2, 9], [1, 0, 5, 0]] f = [2, 0, 40, 0, 300, 0, 1000, 0, 1250, -4, 0, -20, 18] assert dup_decompose(f, ZZ) == [[2, 0, 0, -4, 18], [1, 0, 5, 0]] f = [1, 0, 20, -8, 150, -120, 524, -600, 865, -1034, 600, -170, 29] assert dup_decompose(f, ZZ) == [[1, -8, 24, -34, 29], [1, 0, 5, 0]] R, t = ring("t", ZZ) f = [6*t**2 - 42, 48*t**2 + 96, 144*t**2 + 648*t + 288, 624*t**2 + 864*t + 384, 108*t**3 + 312*t**2 + 432*t + 192] assert dup_decompose(f, R.to_domain()) == [f] def test_dmp_lift(): q = [QQ(1, 1), QQ(0, 1), QQ(1, 1)] f = [ANP([QQ(1, 1)], q, QQ), ANP([], q, QQ), ANP([], q, QQ), ANP([QQ(1, 1), QQ(0, 1)], q, QQ), ANP([QQ(17, 1), QQ(0, 1)], q, QQ)] assert dmp_lift(f, 0, QQ.algebraic_field(I)) == \ [QQ(1), QQ(0), QQ(0), QQ(0), QQ(0), QQ(0), QQ(2), QQ(0), QQ(578), QQ(0), QQ(0), QQ(0), QQ(1), QQ(0), QQ(-578), QQ(0), QQ(83521)] raises(DomainError, lambda: dmp_lift([EX(1), EX(2)], 0, EX)) def test_dup_sign_variations(): assert dup_sign_variations([], ZZ) == 0 assert dup_sign_variations([1, 0], ZZ) == 0 assert dup_sign_variations([1, 0, 2], ZZ) == 0 assert dup_sign_variations([1, 0, 3, 0], ZZ) == 0 assert dup_sign_variations([1, 0, 4, 0, 5], ZZ) == 0 assert dup_sign_variations([-1, 0, 2], ZZ) == 1 assert dup_sign_variations([-1, 0, 3, 0], ZZ) == 1 assert dup_sign_variations([-1, 0, 4, 0, 5], ZZ) == 1 assert dup_sign_variations([-1, -4, -5], ZZ) == 0 assert dup_sign_variations([ 1, -4, -5], ZZ) == 1 assert dup_sign_variations([ 1, 4, -5], ZZ) == 1 assert dup_sign_variations([ 1, -4, 5], ZZ) == 2 assert dup_sign_variations([-1, 4, -5], ZZ) == 2 assert dup_sign_variations([-1, 4, 5], ZZ) == 1 assert dup_sign_variations([-1, -4, 5], ZZ) == 1 assert dup_sign_variations([ 1, 4, 5], ZZ) == 0 assert dup_sign_variations([-1, 0, -4, 0, -5], ZZ) == 0 assert dup_sign_variations([ 1, 0, -4, 0, -5], ZZ) == 1 assert dup_sign_variations([ 1, 0, 4, 0, -5], ZZ) == 1 assert dup_sign_variations([ 1, 0, -4, 0, 5], ZZ) == 2 assert dup_sign_variations([-1, 0, 4, 0, -5], ZZ) == 2 assert dup_sign_variations([-1, 0, 4, 0, 5], ZZ) == 1 assert dup_sign_variations([-1, 0, -4, 0, 5], ZZ) == 1 assert dup_sign_variations([ 1, 0, 4, 0, 5], ZZ) == 0 def test_dup_clear_denoms(): assert dup_clear_denoms([], QQ, ZZ) == (ZZ(1), []) assert dup_clear_denoms([QQ(1)], QQ, ZZ) == (ZZ(1), [QQ(1)]) assert dup_clear_denoms([QQ(7)], QQ, ZZ) == (ZZ(1), [QQ(7)]) assert dup_clear_denoms([QQ(7, 3)], QQ) == (ZZ(3), [QQ(7)]) assert dup_clear_denoms([QQ(7, 3)], QQ, ZZ) == (ZZ(3), [QQ(7)]) assert dup_clear_denoms( [QQ(3), QQ(1), QQ(0)], QQ, ZZ) == (ZZ(1), [QQ(3), QQ(1), QQ(0)]) assert dup_clear_denoms( [QQ(1), QQ(1, 2), QQ(0)], QQ, ZZ) == (ZZ(2), [QQ(2), QQ(1), QQ(0)]) assert dup_clear_denoms([QQ(3), QQ( 1), QQ(0)], QQ, ZZ, convert=True) == (ZZ(1), [ZZ(3), ZZ(1), ZZ(0)]) assert dup_clear_denoms([QQ(1), QQ( 1, 2), QQ(0)], QQ, ZZ, convert=True) == (ZZ(2), [ZZ(2), ZZ(1), ZZ(0)]) assert dup_clear_denoms( [EX(S(3)/2), EX(S(9)/4)], EX) == (EX(4), [EX(6), EX(9)]) assert dup_clear_denoms([EX(7)], EX) == (EX(1), [EX(7)]) assert dup_clear_denoms([EX(sin(x)/x), EX(0)], EX) == (EX(x), [EX(sin(x)), EX(0)]) def test_dmp_clear_denoms(): assert dmp_clear_denoms([[]], 1, QQ, ZZ) == (ZZ(1), [[]]) assert dmp_clear_denoms([[QQ(1)]], 1, QQ, ZZ) == (ZZ(1), [[QQ(1)]]) assert dmp_clear_denoms([[QQ(7)]], 1, QQ, ZZ) == (ZZ(1), [[QQ(7)]]) assert dmp_clear_denoms([[QQ(7, 3)]], 1, QQ) == (ZZ(3), [[QQ(7)]]) assert dmp_clear_denoms([[QQ(7, 3)]], 1, QQ, ZZ) == (ZZ(3), [[QQ(7)]]) assert dmp_clear_denoms( [[QQ(3)], [QQ(1)], []], 1, QQ, ZZ) == (ZZ(1), [[QQ(3)], [QQ(1)], []]) assert dmp_clear_denoms([[QQ( 1)], [QQ(1, 2)], []], 1, QQ, ZZ) == (ZZ(2), [[QQ(2)], [QQ(1)], []]) assert dmp_clear_denoms([QQ(3), QQ( 1), QQ(0)], 0, QQ, ZZ, convert=True) == (ZZ(1), [ZZ(3), ZZ(1), ZZ(0)]) assert dmp_clear_denoms([QQ(1), QQ(1, 2), QQ( 0)], 0, QQ, ZZ, convert=True) == (ZZ(2), [ZZ(2), ZZ(1), ZZ(0)]) assert dmp_clear_denoms([[QQ(3)], [QQ( 1)], []], 1, QQ, ZZ, convert=True) == (ZZ(1), [[QQ(3)], [QQ(1)], []]) assert dmp_clear_denoms([[QQ(1)], [QQ(1, 2)], []], 1, QQ, ZZ, convert=True) == (ZZ(2), [[QQ(2)], [QQ(1)], []]) assert dmp_clear_denoms( [[EX(S(3)/2)], [EX(S(9)/4)]], 1, EX) == (EX(4), [[EX(6)], [EX(9)]]) assert dmp_clear_denoms([[EX(7)]], 1, EX) == (EX(1), [[EX(7)]]) assert dmp_clear_denoms([[EX(sin(x)/x), EX(0)]], 1, EX) == (EX(x), [[EX(sin(x)), EX(0)]]) sympy-sympy-1.9/sympy/polys/tests/test_dispersion.py000066400000000000000000000061571412543434000232150ustar00rootroot00000000000000from sympy.core import Symbol, S, oo from sympy.functions.elementary.miscellaneous import sqrt from sympy.polys import poly from sympy.polys.dispersion import dispersion, dispersionset def test_dispersion(): x = Symbol("x") a = Symbol("a") fp = poly(S.Zero, x) assert sorted(dispersionset(fp)) == [0] fp = poly(S(2), x) assert sorted(dispersionset(fp)) == [0] fp = poly(x + 1, x) assert sorted(dispersionset(fp)) == [0] assert dispersion(fp) == 0 fp = poly((x + 1)*(x + 2), x) assert sorted(dispersionset(fp)) == [0, 1] assert dispersion(fp) == 1 fp = poly(x*(x + 3), x) assert sorted(dispersionset(fp)) == [0, 3] assert dispersion(fp) == 3 fp = poly((x - 3)*(x + 3), x) assert sorted(dispersionset(fp)) == [0, 6] assert dispersion(fp) == 6 fp = poly(x**4 - 3*x**2 + 1, x) gp = fp.shift(-3) assert sorted(dispersionset(fp, gp)) == [2, 3, 4] assert dispersion(fp, gp) == 4 assert sorted(dispersionset(gp, fp)) == [] assert dispersion(gp, fp) is -oo fp = poly(x*(3*x**2+a)*(x-2536)*(x**3+a), x) gp = fp.as_expr().subs(x, x-345).as_poly(x) assert sorted(dispersionset(fp, gp)) == [345, 2881] assert sorted(dispersionset(gp, fp)) == [2191] gp = poly((x-2)**2*(x-3)**3*(x-5)**3, x) assert sorted(dispersionset(gp)) == [0, 1, 2, 3] assert sorted(dispersionset(gp, (gp+4)**2)) == [1, 2] fp = poly(x*(x+2)*(x-1), x) assert sorted(dispersionset(fp)) == [0, 1, 2, 3] fp = poly(x**2 + sqrt(5)*x - 1, x, domain='QQ') gp = poly(x**2 + (2 + sqrt(5))*x + sqrt(5), x, domain='QQ') assert sorted(dispersionset(fp, gp)) == [2] assert sorted(dispersionset(gp, fp)) == [1, 4] # There are some difficulties if we compute over Z[a] # and alpha happenes to lie in Z[a] instead of simply Z. # Hence we can not decide if alpha is indeed integral # in general. fp = poly(4*x**4 + (4*a + 8)*x**3 + (a**2 + 6*a + 4)*x**2 + (a**2 + 2*a)*x, x) assert sorted(dispersionset(fp)) == [0, 1] # For any specific value of a, the dispersion is 3*a # but the algorithm can not find this in general. # This is the point where the resultant based Ansatz # is superior to the current one. fp = poly(a**2*x**3 + (a**3 + a**2 + a + 1)*x, x) gp = fp.as_expr().subs(x, x - 3*a).as_poly(x) assert sorted(dispersionset(fp, gp)) == [] fpa = fp.as_expr().subs(a, 2).as_poly(x) gpa = gp.as_expr().subs(a, 2).as_poly(x) assert sorted(dispersionset(fpa, gpa)) == [6] # Work with Expr instead of Poly f = (x + 1)*(x + 2) assert sorted(dispersionset(f)) == [0, 1] assert dispersion(f) == 1 f = x**4 - 3*x**2 + 1 g = x**4 - 12*x**3 + 51*x**2 - 90*x + 55 assert sorted(dispersionset(f, g)) == [2, 3, 4] assert dispersion(f, g) == 4 # Work with Expr and specify a generator f = (x + 1)*(x + 2) assert sorted(dispersionset(f, None, x)) == [0, 1] assert dispersion(f, None, x) == 1 f = x**4 - 3*x**2 + 1 g = x**4 - 12*x**3 + 51*x**2 - 90*x + 55 assert sorted(dispersionset(f, g, x)) == [2, 3, 4] assert dispersion(f, g, x) == 4 sympy-sympy-1.9/sympy/polys/tests/test_distributedmodules.py000066400000000000000000000167271412543434000247550ustar00rootroot00000000000000"""Tests for sparse distributed modules. """ from sympy.polys.distributedmodules import ( sdm_monomial_mul, sdm_monomial_deg, sdm_monomial_divides, sdm_add, sdm_LM, sdm_LT, sdm_mul_term, sdm_zero, sdm_deg, sdm_LC, sdm_from_dict, sdm_spoly, sdm_ecart, sdm_nf_mora, sdm_groebner, sdm_from_vector, sdm_to_vector, sdm_monomial_lcm ) from sympy.polys.orderings import lex, grlex, InverseOrder from sympy.polys.domains import QQ from sympy.abc import x, y, z def test_sdm_monomial_mul(): assert sdm_monomial_mul((1, 1, 0), (1, 3)) == (1, 2, 3) def test_sdm_monomial_deg(): assert sdm_monomial_deg((5, 2, 1)) == 3 def test_sdm_monomial_lcm(): assert sdm_monomial_lcm((1, 2, 3), (1, 5, 0)) == (1, 5, 3) def test_sdm_monomial_divides(): assert sdm_monomial_divides((1, 0, 0), (1, 0, 0)) is True assert sdm_monomial_divides((1, 0, 0), (1, 2, 1)) is True assert sdm_monomial_divides((5, 1, 1), (5, 2, 1)) is True assert sdm_monomial_divides((1, 0, 0), (2, 0, 0)) is False assert sdm_monomial_divides((1, 1, 0), (1, 0, 0)) is False assert sdm_monomial_divides((5, 1, 2), (5, 0, 1)) is False def test_sdm_LC(): assert sdm_LC([((1, 2, 3), QQ(5))], QQ) == QQ(5) def test_sdm_from_dict(): dic = {(1, 2, 1, 1): QQ(1), (1, 1, 2, 1): QQ(1), (1, 0, 2, 1): QQ(1), (1, 0, 0, 3): QQ(1), (1, 1, 1, 0): QQ(1)} assert sdm_from_dict(dic, grlex) == \ [((1, 2, 1, 1), QQ(1)), ((1, 1, 2, 1), QQ(1)), ((1, 0, 2, 1), QQ(1)), ((1, 0, 0, 3), QQ(1)), ((1, 1, 1, 0), QQ(1))] # TODO test to_dict? def test_sdm_add(): assert sdm_add([((1, 1, 1), QQ(1))], [((2, 0, 0), QQ(1))], lex, QQ) == \ [((2, 0, 0), QQ(1)), ((1, 1, 1), QQ(1))] assert sdm_add([((1, 1, 1), QQ(1))], [((1, 1, 1), QQ(-1))], lex, QQ) == [] assert sdm_add([((1, 0, 0), QQ(1))], [((1, 0, 0), QQ(2))], lex, QQ) == \ [((1, 0, 0), QQ(3))] assert sdm_add([((1, 0, 1), QQ(1))], [((1, 1, 0), QQ(1))], lex, QQ) == \ [((1, 1, 0), QQ(1)), ((1, 0, 1), QQ(1))] def test_sdm_LM(): dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(1), (4, 0, 1): QQ(1)} assert sdm_LM(sdm_from_dict(dic, lex)) == (4, 0, 1) def test_sdm_LT(): dic = {(1, 2, 3): QQ(1), (4, 0, 0): QQ(2), (4, 0, 1): QQ(3)} assert sdm_LT(sdm_from_dict(dic, lex)) == ((4, 0, 1), QQ(3)) def test_sdm_mul_term(): assert sdm_mul_term([((1, 0, 0), QQ(1))], ((0, 0), QQ(0)), lex, QQ) == [] assert sdm_mul_term([], ((1, 0), QQ(1)), lex, QQ) == [] assert sdm_mul_term([((1, 0, 0), QQ(1))], ((1, 0), QQ(1)), lex, QQ) == \ [((1, 1, 0), QQ(1))] f = [((2, 0, 1), QQ(4)), ((1, 1, 0), QQ(3))] assert sdm_mul_term(f, ((1, 1), QQ(2)), lex, QQ) == \ [((2, 1, 2), QQ(8)), ((1, 2, 1), QQ(6))] def test_sdm_zero(): assert sdm_zero() == [] def test_sdm_deg(): assert sdm_deg([((1, 2, 3), 1), ((10, 0, 1), 1), ((2, 3, 4), 4)]) == 7 def test_sdm_spoly(): f = [((2, 1, 1), QQ(1)), ((1, 0, 1), QQ(1))] g = [((2, 3, 0), QQ(1))] h = [((1, 2, 3), QQ(1))] assert sdm_spoly(f, h, lex, QQ) == [] assert sdm_spoly(f, g, lex, QQ) == [((1, 2, 1), QQ(1))] def test_sdm_ecart(): assert sdm_ecart([((1, 2, 3), 1), ((1, 0, 1), 1)]) == 0 assert sdm_ecart([((2, 2, 1), 1), ((1, 5, 1), 1)]) == 3 def test_sdm_nf_mora(): f = sdm_from_dict({(1, 2, 1, 1): QQ(1), (1, 1, 2, 1): QQ(1), (1, 0, 2, 1): QQ(1), (1, 0, 0, 3): QQ(1), (1, 1, 1, 0): QQ(1)}, grlex) f1 = sdm_from_dict({(1, 1, 1, 0): QQ(1), (1, 0, 2, 0): QQ(1), (1, 0, 0, 0): QQ(-1)}, grlex) f2 = sdm_from_dict({(1, 1, 1, 0): QQ(1)}, grlex) (id0, id1, id2) = [sdm_from_dict({(i, 0, 0, 0): QQ(1)}, grlex) for i in range(3)] assert sdm_nf_mora(f, [f1, f2], grlex, QQ, phantom=(id0, [id1, id2])) == \ ([((1, 0, 2, 1), QQ(1)), ((1, 0, 0, 3), QQ(1)), ((1, 1, 1, 0), QQ(1)), ((1, 1, 0, 1), QQ(1))], [((1, 1, 0, 1), QQ(-1)), ((0, 0, 0, 0), QQ(1))]) assert sdm_nf_mora(f, [f2, f1], grlex, QQ, phantom=(id0, [id2, id1])) == \ ([((1, 0, 2, 1), QQ(1)), ((1, 0, 0, 3), QQ(1)), ((1, 1, 1, 0), QQ(1))], [((2, 1, 0, 1), QQ(-1)), ((2, 0, 1, 1), QQ(-1)), ((0, 0, 0, 0), QQ(1))]) f = sdm_from_vector([x*z, y**2 + y*z - z, y], lex, QQ, gens=[x, y, z]) f1 = sdm_from_vector([x, y, 1], lex, QQ, gens=[x, y, z]) f2 = sdm_from_vector([x*y, z, z**2], lex, QQ, gens=[x, y, z]) assert sdm_nf_mora(f, [f1, f2], lex, QQ) == \ sdm_nf_mora(f, [f2, f1], lex, QQ) == \ [((1, 0, 1, 1), QQ(1)), ((1, 0, 0, 1), QQ(-1)), ((0, 1, 1, 0), QQ(-1)), ((0, 1, 0, 1), QQ(1))] def test_conversion(): f = [x**2 + y**2, 2*z] g = [((1, 0, 0, 1), QQ(2)), ((0, 2, 0, 0), QQ(1)), ((0, 0, 2, 0), QQ(1))] assert sdm_to_vector(g, [x, y, z], QQ) == f assert sdm_from_vector(f, lex, QQ) == g assert sdm_from_vector( [x, 1], lex, QQ) == [((1, 0), QQ(1)), ((0, 1), QQ(1))] assert sdm_to_vector([((1, 1, 0, 0), 1)], [x, y, z], QQ, n=3) == [0, x, 0] assert sdm_from_vector([0, 0], lex, QQ, gens=[x, y]) == sdm_zero() def test_nontrivial(): gens = [x, y, z] def contains(I, f): S = [sdm_from_vector([g], lex, QQ, gens=gens) for g in I] G = sdm_groebner(S, sdm_nf_mora, lex, QQ) return sdm_nf_mora(sdm_from_vector([f], lex, QQ, gens=gens), G, lex, QQ) == sdm_zero() assert contains([x, y], x) assert contains([x, y], x + y) assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**3) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y**2) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x**4 + y**3 + 2*z*y*x) assert contains([x + y + z, x*y + x*z + y*z, x*y*z], x*y*z) assert contains([x, 1 + x + y, 5 - 7*y], 1) assert contains( [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], x**3) assert not contains( [x**3 + y**3, y**3 + z**3, z**3 + x**3, x**2*y + x**2*z + y**2*z], x**2 + y**2) # compare local order assert not contains([x*(1 + x + y), y*(1 + z)], x) assert not contains([x*(1 + x + y), y*(1 + z)], x + y) def test_local(): igrlex = InverseOrder(grlex) gens = [x, y, z] def contains(I, f): S = [sdm_from_vector([g], igrlex, QQ, gens=gens) for g in I] G = sdm_groebner(S, sdm_nf_mora, igrlex, QQ) return sdm_nf_mora(sdm_from_vector([f], lex, QQ, gens=gens), G, lex, QQ) == sdm_zero() assert contains([x, y], x) assert contains([x, y], x + y) assert not contains([x, y], 1) assert not contains([x, y], z) assert contains([x**2 + y, x**2 + x], x - y) assert not contains([x + y + z, x*y + x*z + y*z, x*y*z], x**2) assert contains([x*(1 + x + y), y*(1 + z)], x) assert contains([x*(1 + x + y), y*(1 + z)], x + y) def test_uncovered_line(): gens = [x, y] f1 = sdm_zero() f2 = sdm_from_vector([x, 0], lex, QQ, gens=gens) f3 = sdm_from_vector([0, y], lex, QQ, gens=gens) assert sdm_spoly(f1, f2, lex, QQ) == sdm_zero() assert sdm_spoly(f3, f2, lex, QQ) == sdm_zero() def test_chain_criterion(): gens = [x] f1 = sdm_from_vector([1, x], grlex, QQ, gens=gens) f2 = sdm_from_vector([0, x - 2], grlex, QQ, gens=gens) assert len(sdm_groebner([f1, f2], sdm_nf_mora, grlex, QQ)) == 2 sympy-sympy-1.9/sympy/polys/tests/test_euclidtools.py000066400000000000000000000460321412543434000233600ustar00rootroot00000000000000"""Tests for Euclidean algorithms, GCDs, LCMs and polynomial remainder sequences. """ from sympy.polys.rings import ring from sympy.polys.domains import ZZ, QQ, RR from sympy.polys.specialpolys import ( f_polys, dmp_fateman_poly_F_1, dmp_fateman_poly_F_2, dmp_fateman_poly_F_3) f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() def test_dup_gcdex(): R, x = ring("x", QQ) f = x**4 - 2*x**3 - 6*x**2 + 12*x + 15 g = x**3 + x**2 - 4*x - 4 s = -QQ(1,5)*x + QQ(3,5) t = QQ(1,5)*x**2 - QQ(6,5)*x + 2 h = x + 1 assert R.dup_half_gcdex(f, g) == (s, h) assert R.dup_gcdex(f, g) == (s, t, h) f = x**4 + 4*x**3 - x + 1 g = x**3 - x + 1 s, t, h = R.dup_gcdex(f, g) S, T, H = R.dup_gcdex(g, f) assert R.dup_add(R.dup_mul(s, f), R.dup_mul(t, g)) == h assert R.dup_add(R.dup_mul(S, g), R.dup_mul(T, f)) == H f = 2*x g = x**2 - 16 s = QQ(1,32)*x t = -QQ(1,16) h = 1 assert R.dup_half_gcdex(f, g) == (s, h) assert R.dup_gcdex(f, g) == (s, t, h) def test_dup_invert(): R, x = ring("x", QQ) assert R.dup_invert(2*x, x**2 - 16) == QQ(1,32)*x def test_dup_euclidean_prs(): R, x = ring("x", QQ) f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert R.dup_euclidean_prs(f, g) == [ f, g, -QQ(5,9)*x**4 + QQ(1,9)*x**2 - QQ(1,3), -QQ(117,25)*x**2 - 9*x + QQ(441,25), QQ(233150,19773)*x - QQ(102500,6591), -QQ(1288744821,543589225)] def test_dup_primitive_prs(): R, x = ring("x", ZZ) f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert R.dup_primitive_prs(f, g) == [ f, g, -5*x**4 + x**2 - 3, 13*x**2 + 25*x - 49, 4663*x - 6150, 1] def test_dup_subresultants(): R, x = ring("x", ZZ) assert R.dup_resultant(0, 0) == 0 assert R.dup_resultant(1, 0) == 0 assert R.dup_resultant(0, 1) == 0 f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 a = 15*x**4 - 3*x**2 + 9 b = 65*x**2 + 125*x - 245 c = 9326*x - 12300 d = 260708 assert R.dup_subresultants(f, g) == [f, g, a, b, c, d] assert R.dup_resultant(f, g) == R.dup_LC(d) f = x**2 - 2*x + 1 g = x**2 - 1 a = 2*x - 2 assert R.dup_subresultants(f, g) == [f, g, a] assert R.dup_resultant(f, g) == 0 f = x**2 + 1 g = x**2 - 1 a = -2 assert R.dup_subresultants(f, g) == [f, g, a] assert R.dup_resultant(f, g) == 4 f = x**2 - 1 g = x**3 - x**2 + 2 assert R.dup_resultant(f, g) == 0 f = 3*x**3 - x g = 5*x**2 + 1 assert R.dup_resultant(f, g) == 64 f = x**2 - 2*x + 7 g = x**3 - x + 5 assert R.dup_resultant(f, g) == 265 f = x**3 - 6*x**2 + 11*x - 6 g = x**3 - 15*x**2 + 74*x - 120 assert R.dup_resultant(f, g) == -8640 f = x**3 - 6*x**2 + 11*x - 6 g = x**3 - 10*x**2 + 29*x - 20 assert R.dup_resultant(f, g) == 0 f = x**3 - 1 g = x**3 + 2*x**2 + 2*x - 1 assert R.dup_resultant(f, g) == 16 f = x**8 - 2 g = x - 1 assert R.dup_resultant(f, g) == -1 def test_dmp_subresultants(): R, x, y = ring("x,y", ZZ) assert R.dmp_resultant(0, 0) == 0 assert R.dmp_prs_resultant(0, 0)[0] == 0 assert R.dmp_zz_collins_resultant(0, 0) == 0 assert R.dmp_qq_collins_resultant(0, 0) == 0 assert R.dmp_resultant(1, 0) == 0 assert R.dmp_resultant(1, 0) == 0 assert R.dmp_resultant(1, 0) == 0 assert R.dmp_resultant(0, 1) == 0 assert R.dmp_prs_resultant(0, 1)[0] == 0 assert R.dmp_zz_collins_resultant(0, 1) == 0 assert R.dmp_qq_collins_resultant(0, 1) == 0 f = 3*x**2*y - y**3 - 4 g = x**2 + x*y**3 - 9 a = 3*x*y**4 + y**3 - 27*y + 4 b = -3*y**10 - 12*y**7 + y**6 - 54*y**4 + 8*y**3 + 729*y**2 - 216*y + 16 r = R.dmp_LC(b) assert R.dmp_subresultants(f, g) == [f, g, a, b] assert R.dmp_resultant(f, g) == r assert R.dmp_prs_resultant(f, g)[0] == r assert R.dmp_zz_collins_resultant(f, g) == r assert R.dmp_qq_collins_resultant(f, g) == r f = -x**3 + 5 g = 3*x**2*y + x**2 a = 45*y**2 + 30*y + 5 b = 675*y**3 + 675*y**2 + 225*y + 25 r = R.dmp_LC(b) assert R.dmp_subresultants(f, g) == [f, g, a] assert R.dmp_resultant(f, g) == r assert R.dmp_prs_resultant(f, g)[0] == r assert R.dmp_zz_collins_resultant(f, g) == r assert R.dmp_qq_collins_resultant(f, g) == r R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) f = 6*x**2 - 3*x*y - 2*x*z + y*z g = x**2 - x*u - x*v + u*v r = y**2*z**2 - 3*y**2*z*u - 3*y**2*z*v + 9*y**2*u*v - 2*y*z**2*u \ - 2*y*z**2*v + 6*y*z*u**2 + 12*y*z*u*v + 6*y*z*v**2 - 18*y*u**2*v \ - 18*y*u*v**2 + 4*z**2*u*v - 12*z*u**2*v - 12*z*u*v**2 + 36*u**2*v**2 assert R.dmp_zz_collins_resultant(f, g) == r.drop(x) R, x, y, z, u, v = ring("x,y,z,u,v", QQ) f = x**2 - QQ(1,2)*x*y - QQ(1,3)*x*z + QQ(1,6)*y*z g = x**2 - x*u - x*v + u*v r = QQ(1,36)*y**2*z**2 - QQ(1,12)*y**2*z*u - QQ(1,12)*y**2*z*v + QQ(1,4)*y**2*u*v \ - QQ(1,18)*y*z**2*u - QQ(1,18)*y*z**2*v + QQ(1,6)*y*z*u**2 + QQ(1,3)*y*z*u*v \ + QQ(1,6)*y*z*v**2 - QQ(1,2)*y*u**2*v - QQ(1,2)*y*u*v**2 + QQ(1,9)*z**2*u*v \ - QQ(1,3)*z*u**2*v - QQ(1,3)*z*u*v**2 + u**2*v**2 assert R.dmp_qq_collins_resultant(f, g) == r.drop(x) Rt, t = ring("t", ZZ) Rx, x = ring("x", Rt) f = x**6 - 5*x**4 + 5*x**2 + 4 g = -6*t*x**5 + x**4 + 20*t*x**3 - 3*x**2 - 10*t*x + 6 assert Rx.dup_resultant(f, g) == 2930944*t**6 + 2198208*t**4 + 549552*t**2 + 45796 def test_dup_discriminant(): R, x = ring("x", ZZ) assert R.dup_discriminant(0) == 0 assert R.dup_discriminant(x) == 1 assert R.dup_discriminant(x**3 + 3*x**2 + 9*x - 13) == -11664 assert R.dup_discriminant(5*x**5 + x**3 + 2) == 31252160 assert R.dup_discriminant(x**4 + 2*x**3 + 6*x**2 - 22*x + 13) == 0 assert R.dup_discriminant(12*x**7 + 15*x**4 + 30*x**3 + x**2 + 1) == -220289699947514112 def test_dmp_discriminant(): R, x = ring("x", ZZ) assert R.dmp_discriminant(0) == 0 R, x, y = ring("x,y", ZZ) assert R.dmp_discriminant(0) == 0 assert R.dmp_discriminant(y) == 0 assert R.dmp_discriminant(x**3 + 3*x**2 + 9*x - 13) == -11664 assert R.dmp_discriminant(5*x**5 + x**3 + 2) == 31252160 assert R.dmp_discriminant(x**4 + 2*x**3 + 6*x**2 - 22*x + 13) == 0 assert R.dmp_discriminant(12*x**7 + 15*x**4 + 30*x**3 + x**2 + 1) == -220289699947514112 assert R.dmp_discriminant(x**2*y + 2*y) == (-8*y**2).drop(x) assert R.dmp_discriminant(x*y**2 + 2*x) == 1 R, x, y, z = ring("x,y,z", ZZ) assert R.dmp_discriminant(x*y + z) == 1 R, x, y, z, u = ring("x,y,z,u", ZZ) assert R.dmp_discriminant(x**2*y + x*z + u) == (-4*y*u + z**2).drop(x) R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) assert R.dmp_discriminant(x**3*y + x**2*z + x*u + v) == \ (-27*y**2*v**2 + 18*y*z*u*v - 4*y*u**3 - 4*z**3*v + z**2*u**2).drop(x) def test_dup_gcd(): R, x = ring("x", ZZ) f, g = 0, 0 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (0, 0, 0) f, g = 2, 0 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, 0) f, g = -2, 0 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, -1, 0) f, g = 0, -2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 0, -1) f, g = 0, 2*x + 4 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2*x + 4, 0, 1) f, g = 2*x + 4, 0 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2*x + 4, 1, 0) f, g = 2, 2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, 1) f, g = -2, 2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, -1, 1) f, g = 2, -2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, -1) f, g = -2, -2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, -1, -1) f, g = x**2 + 2*x + 1, 1 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 1) f, g = x**2 + 2*x + 1, 2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 2) f, g = 2*x**2 + 4*x + 2, 2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, x**2 + 2*x + 1, 1) f, g = 2, 2*x**2 + 4*x + 2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (2, 1, x**2 + 2*x + 1) f, g = 2*x**2 + 4*x + 2, x + 1 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (x + 1, 2*x + 2, 1) f, g = x + 1, 2*x**2 + 4*x + 2 assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (x + 1, 1, 2*x + 2) f, g = x - 31, x assert R.dup_zz_heu_gcd(f, g) == R.dup_rr_prs_gcd(f, g) == (1, f, g) f = x**4 + 8*x**3 + 21*x**2 + 22*x + 8 g = x**3 + 6*x**2 + 11*x + 6 h = x**2 + 3*x + 2 cff = x**2 + 5*x + 4 cfg = x + 3 assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) assert R.dup_rr_prs_gcd(f, g) == (h, cff, cfg) f = x**4 - 4 g = x**4 + 4*x**2 + 4 h = x**2 + 2 cff = x**2 - 2 cfg = x**2 + 2 assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) assert R.dup_rr_prs_gcd(f, g) == (h, cff, cfg) f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 h = 1 cff = f cfg = g assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) assert R.dup_rr_prs_gcd(f, g) == (h, cff, cfg) R, x = ring("x", QQ) f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 h = 1 cff = f cfg = g assert R.dup_qq_heu_gcd(f, g) == (h, cff, cfg) assert R.dup_ff_prs_gcd(f, g) == (h, cff, cfg) R, x = ring("x", ZZ) f = - 352518131239247345597970242177235495263669787845475025293906825864749649589178600387510272*x**49 \ + 46818041807522713962450042363465092040687472354933295397472942006618953623327997952*x**42 \ + 378182690892293941192071663536490788434899030680411695933646320291525827756032*x**35 \ + 112806468807371824947796775491032386836656074179286744191026149539708928*x**28 \ - 12278371209708240950316872681744825481125965781519138077173235712*x**21 \ + 289127344604779611146960547954288113529690984687482920704*x**14 \ + 19007977035740498977629742919480623972236450681*x**7 \ + 311973482284542371301330321821976049 g = 365431878023781158602430064717380211405897160759702125019136*x**21 \ + 197599133478719444145775798221171663643171734081650688*x**14 \ - 9504116979659010018253915765478924103928886144*x**7 \ - 311973482284542371301330321821976049 assert R.dup_zz_heu_gcd(f, R.dup_diff(f, 1))[0] == g assert R.dup_rr_prs_gcd(f, R.dup_diff(f, 1))[0] == g R, x = ring("x", QQ) f = QQ(1,2)*x**2 + x + QQ(1,2) g = QQ(1,2)*x + QQ(1,2) h = x + 1 assert R.dup_qq_heu_gcd(f, g) == (h, g, QQ(1,2)) assert R.dup_ff_prs_gcd(f, g) == (h, g, QQ(1,2)) R, x = ring("x", ZZ) f = 1317378933230047068160*x + 2945748836994210856960 g = 120352542776360960*x + 269116466014453760 h = 120352542776360960*x + 269116466014453760 cff = 10946 cfg = 1 assert R.dup_zz_heu_gcd(f, g) == (h, cff, cfg) def test_dmp_gcd(): R, x, y = ring("x,y", ZZ) f, g = 0, 0 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (0, 0, 0) f, g = 2, 0 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, 0) f, g = -2, 0 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, -1, 0) f, g = 0, -2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 0, -1) f, g = 0, 2*x + 4 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2*x + 4, 0, 1) f, g = 2*x + 4, 0 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2*x + 4, 1, 0) f, g = 2, 2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, 1) f, g = -2, 2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, -1, 1) f, g = 2, -2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, -1) f, g = -2, -2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, -1, -1) f, g = x**2 + 2*x + 1, 1 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 1) f, g = x**2 + 2*x + 1, 2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (1, x**2 + 2*x + 1, 2) f, g = 2*x**2 + 4*x + 2, 2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, x**2 + 2*x + 1, 1) f, g = 2, 2*x**2 + 4*x + 2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (2, 1, x**2 + 2*x + 1) f, g = 2*x**2 + 4*x + 2, x + 1 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (x + 1, 2*x + 2, 1) f, g = x + 1, 2*x**2 + 4*x + 2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (x + 1, 1, 2*x + 2) R, x, y, z, u = ring("x,y,z,u", ZZ) f, g = u**2 + 2*u + 1, 2*u + 2 assert R.dmp_zz_heu_gcd(f, g) == R.dmp_rr_prs_gcd(f, g) == (u + 1, u + 1, 2) f, g = z**2*u**2 + 2*z**2*u + z**2 + z*u + z, u**2 + 2*u + 1 h, cff, cfg = u + 1, z**2*u + z**2 + z, u + 1 assert R.dmp_zz_heu_gcd(f, g) == (h, cff, cfg) assert R.dmp_rr_prs_gcd(f, g) == (h, cff, cfg) assert R.dmp_zz_heu_gcd(g, f) == (h, cfg, cff) assert R.dmp_rr_prs_gcd(g, f) == (h, cfg, cff) R, x, y, z = ring("x,y,z", ZZ) f, g, h = map(R.from_dense, dmp_fateman_poly_F_1(2, ZZ)) H, cff, cfg = R.dmp_zz_heu_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g H, cff, cfg = R.dmp_rr_prs_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) f, g, h = map(R.from_dense, dmp_fateman_poly_F_1(4, ZZ)) H, cff, cfg = R.dmp_zz_heu_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g R, x, y, z, u, v, a, b = ring("x,y,z,u,v,a,b", ZZ) f, g, h = map(R.from_dense, dmp_fateman_poly_F_1(6, ZZ)) H, cff, cfg = R.dmp_zz_heu_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g R, x, y, z, u, v, a, b, c, d = ring("x,y,z,u,v,a,b,c,d", ZZ) f, g, h = map(R.from_dense, dmp_fateman_poly_F_1(8, ZZ)) H, cff, cfg = R.dmp_zz_heu_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g R, x, y, z = ring("x,y,z", ZZ) f, g, h = map(R.from_dense, dmp_fateman_poly_F_2(2, ZZ)) H, cff, cfg = R.dmp_zz_heu_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g H, cff, cfg = R.dmp_rr_prs_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g f, g, h = map(R.from_dense, dmp_fateman_poly_F_3(2, ZZ)) H, cff, cfg = R.dmp_zz_heu_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g H, cff, cfg = R.dmp_rr_prs_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) f, g, h = map(R.from_dense, dmp_fateman_poly_F_3(4, ZZ)) H, cff, cfg = R.dmp_inner_gcd(f, g) assert H == h and R.dmp_mul(H, cff) == f \ and R.dmp_mul(H, cfg) == g R, x, y = ring("x,y", QQ) f = QQ(1,2)*x**2 + x + QQ(1,2) g = QQ(1,2)*x + QQ(1,2) h = x + 1 assert R.dmp_qq_heu_gcd(f, g) == (h, g, QQ(1,2)) assert R.dmp_ff_prs_gcd(f, g) == (h, g, QQ(1,2)) R, x, y = ring("x,y", RR) f = 2.1*x*y**2 - 2.2*x*y + 2.1*x g = 1.0*x**3 assert R.dmp_ff_prs_gcd(f, g) == \ (1.0*x, 2.1*y**2 - 2.2*y + 2.1, 1.0*x**2) def test_dup_lcm(): R, x = ring("x", ZZ) assert R.dup_lcm(2, 6) == 6 assert R.dup_lcm(2*x**3, 6*x) == 6*x**3 assert R.dup_lcm(2*x**3, 3*x) == 6*x**3 assert R.dup_lcm(x**2 + x, x) == x**2 + x assert R.dup_lcm(x**2 + x, 2*x) == 2*x**2 + 2*x assert R.dup_lcm(x**2 + 2*x, x) == x**2 + 2*x assert R.dup_lcm(2*x**2 + x, x) == 2*x**2 + x assert R.dup_lcm(2*x**2 + x, 2*x) == 4*x**2 + 2*x def test_dmp_lcm(): R, x, y = ring("x,y", ZZ) assert R.dmp_lcm(2, 6) == 6 assert R.dmp_lcm(x, y) == x*y assert R.dmp_lcm(2*x**3, 6*x*y**2) == 6*x**3*y**2 assert R.dmp_lcm(2*x**3, 3*x*y**2) == 6*x**3*y**2 assert R.dmp_lcm(x**2*y, x*y**2) == x**2*y**2 f = 2*x*y**5 - 3*x*y**4 - 2*x*y**3 + 3*x*y**2 g = y**5 - 2*y**3 + y h = 2*x*y**7 - 3*x*y**6 - 4*x*y**5 + 6*x*y**4 + 2*x*y**3 - 3*x*y**2 assert R.dmp_lcm(f, g) == h f = x**3 - 3*x**2*y - 9*x*y**2 - 5*y**3 g = x**4 + 6*x**3*y + 12*x**2*y**2 + 10*x*y**3 + 3*y**4 h = x**5 + x**4*y - 18*x**3*y**2 - 50*x**2*y**3 - 47*x*y**4 - 15*y**5 assert R.dmp_lcm(f, g) == h def test_dmp_content(): R, x,y = ring("x,y", ZZ) assert R.dmp_content(-2) == 2 f, g, F = 3*y**2 + 2*y + 1, 1, 0 for i in range(0, 5): g *= f F += x**i*g assert R.dmp_content(F) == f.drop(x) R, x,y,z = ring("x,y,z", ZZ) assert R.dmp_content(f_4) == 1 assert R.dmp_content(f_5) == 1 R, x,y,z,t = ring("x,y,z,t", ZZ) assert R.dmp_content(f_6) == 1 def test_dmp_primitive(): R, x,y = ring("x,y", ZZ) assert R.dmp_primitive(0) == (0, 0) assert R.dmp_primitive(1) == (1, 1) f, g, F = 3*y**2 + 2*y + 1, 1, 0 for i in range(0, 5): g *= f F += x**i*g assert R.dmp_primitive(F) == (f.drop(x), F / f) R, x,y,z = ring("x,y,z", ZZ) cont, f = R.dmp_primitive(f_4) assert cont == 1 and f == f_4 cont, f = R.dmp_primitive(f_5) assert cont == 1 and f == f_5 R, x,y,z,t = ring("x,y,z,t", ZZ) cont, f = R.dmp_primitive(f_6) assert cont == 1 and f == f_6 def test_dup_cancel(): R, x = ring("x", ZZ) f = 2*x**2 - 2 g = x**2 - 2*x + 1 p = 2*x + 2 q = x - 1 assert R.dup_cancel(f, g) == (p, q) assert R.dup_cancel(f, g, include=False) == (1, 1, p, q) f = -x - 2 g = 3*x - 4 F = x + 2 G = -3*x + 4 assert R.dup_cancel(f, g) == (f, g) assert R.dup_cancel(F, G) == (f, g) assert R.dup_cancel(0, 0) == (0, 0) assert R.dup_cancel(0, 0, include=False) == (1, 1, 0, 0) assert R.dup_cancel(x, 0) == (1, 0) assert R.dup_cancel(x, 0, include=False) == (1, 1, 1, 0) assert R.dup_cancel(0, x) == (0, 1) assert R.dup_cancel(0, x, include=False) == (1, 1, 0, 1) f = 0 g = x one = 1 assert R.dup_cancel(f, g, include=True) == (f, one) def test_dmp_cancel(): R, x, y = ring("x,y", ZZ) f = 2*x**2 - 2 g = x**2 - 2*x + 1 p = 2*x + 2 q = x - 1 assert R.dmp_cancel(f, g) == (p, q) assert R.dmp_cancel(f, g, include=False) == (1, 1, p, q) assert R.dmp_cancel(0, 0) == (0, 0) assert R.dmp_cancel(0, 0, include=False) == (1, 1, 0, 0) assert R.dmp_cancel(y, 0) == (1, 0) assert R.dmp_cancel(y, 0, include=False) == (1, 1, 1, 0) assert R.dmp_cancel(0, y) == (0, 1) assert R.dmp_cancel(0, y, include=False) == (1, 1, 0, 1) sympy-sympy-1.9/sympy/polys/tests/test_factortools.py000066400000000000000000000575311412543434000233770ustar00rootroot00000000000000"""Tools for polynomial factorization routines in characteristic zero. """ from sympy.polys.rings import ring, xring from sympy.polys.domains import FF, ZZ, QQ, ZZ_I, QQ_I, RR, EX from sympy.polys import polyconfig as config from sympy.polys.polyerrors import DomainError from sympy.polys.polyclasses import ANP from sympy.polys.specialpolys import f_polys, w_polys from sympy import nextprime, sin, sqrt, I from sympy.testing.pytest import raises, XFAIL f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() w_1, w_2 = w_polys() def test_dup_trial_division(): R, x = ring("x", ZZ) assert R.dup_trial_division(x**5 + 8*x**4 + 25*x**3 + 38*x**2 + 28*x + 8, (x + 1, x + 2)) == [(x + 1, 2), (x + 2, 3)] def test_dmp_trial_division(): R, x, y = ring("x,y", ZZ) assert R.dmp_trial_division(x**5 + 8*x**4 + 25*x**3 + 38*x**2 + 28*x + 8, (x + 1, x + 2)) == [(x + 1, 2), (x + 2, 3)] def test_dup_zz_mignotte_bound(): R, x = ring("x", ZZ) assert R.dup_zz_mignotte_bound(2*x**2 + 3*x + 4) == 6 assert R.dup_zz_mignotte_bound(x**3 + 14*x**2 + 56*x + 64) == 152 def test_dmp_zz_mignotte_bound(): R, x, y = ring("x,y", ZZ) assert R.dmp_zz_mignotte_bound(2*x**2 + 3*x + 4) == 32 def test_dup_zz_hensel_step(): R, x = ring("x", ZZ) f = x**4 - 1 g = x**3 + 2*x**2 - x - 2 h = x - 2 s = -2 t = 2*x**2 - 2*x - 1 G, H, S, T = R.dup_zz_hensel_step(5, f, g, h, s, t) assert G == x**3 + 7*x**2 - x - 7 assert H == x - 7 assert S == 8 assert T == -8*x**2 - 12*x - 1 def test_dup_zz_hensel_lift(): R, x = ring("x", ZZ) f = x**4 - 1 F = [x - 1, x - 2, x + 2, x + 1] assert R.dup_zz_hensel_lift(ZZ(5), f, F, 4) == \ [x - 1, x - 182, x + 182, x + 1] def test_dup_zz_irreducible_p(): R, x = ring("x", ZZ) assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 7) is None assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 4) is None assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 10) is True assert R.dup_zz_irreducible_p(3*x**4 + 2*x**3 + 6*x**2 + 8*x + 14) is True def test_dup_cyclotomic_p(): R, x = ring("x", ZZ) assert R.dup_cyclotomic_p(x - 1) is True assert R.dup_cyclotomic_p(x + 1) is True assert R.dup_cyclotomic_p(x**2 + x + 1) is True assert R.dup_cyclotomic_p(x**2 + 1) is True assert R.dup_cyclotomic_p(x**4 + x**3 + x**2 + x + 1) is True assert R.dup_cyclotomic_p(x**2 - x + 1) is True assert R.dup_cyclotomic_p(x**6 + x**5 + x**4 + x**3 + x**2 + x + 1) is True assert R.dup_cyclotomic_p(x**4 + 1) is True assert R.dup_cyclotomic_p(x**6 + x**3 + 1) is True assert R.dup_cyclotomic_p(0) is False assert R.dup_cyclotomic_p(1) is False assert R.dup_cyclotomic_p(x) is False assert R.dup_cyclotomic_p(x + 2) is False assert R.dup_cyclotomic_p(3*x + 1) is False assert R.dup_cyclotomic_p(x**2 - 1) is False f = x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1 assert R.dup_cyclotomic_p(f) is False g = x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1 assert R.dup_cyclotomic_p(g) is True R, x = ring("x", QQ) assert R.dup_cyclotomic_p(x**2 + x + 1) is True assert R.dup_cyclotomic_p(QQ(1,2)*x**2 + x + 1) is False R, x = ring("x", ZZ["y"]) assert R.dup_cyclotomic_p(x**2 + x + 1) is False def test_dup_zz_cyclotomic_poly(): R, x = ring("x", ZZ) assert R.dup_zz_cyclotomic_poly(1) == x - 1 assert R.dup_zz_cyclotomic_poly(2) == x + 1 assert R.dup_zz_cyclotomic_poly(3) == x**2 + x + 1 assert R.dup_zz_cyclotomic_poly(4) == x**2 + 1 assert R.dup_zz_cyclotomic_poly(5) == x**4 + x**3 + x**2 + x + 1 assert R.dup_zz_cyclotomic_poly(6) == x**2 - x + 1 assert R.dup_zz_cyclotomic_poly(7) == x**6 + x**5 + x**4 + x**3 + x**2 + x + 1 assert R.dup_zz_cyclotomic_poly(8) == x**4 + 1 assert R.dup_zz_cyclotomic_poly(9) == x**6 + x**3 + 1 def test_dup_zz_cyclotomic_factor(): R, x = ring("x", ZZ) assert R.dup_zz_cyclotomic_factor(0) is None assert R.dup_zz_cyclotomic_factor(1) is None assert R.dup_zz_cyclotomic_factor(2*x**10 - 1) is None assert R.dup_zz_cyclotomic_factor(x**10 - 3) is None assert R.dup_zz_cyclotomic_factor(x**10 + x**5 - 1) is None assert R.dup_zz_cyclotomic_factor(x + 1) == [x + 1] assert R.dup_zz_cyclotomic_factor(x - 1) == [x - 1] assert R.dup_zz_cyclotomic_factor(x**2 + 1) == [x**2 + 1] assert R.dup_zz_cyclotomic_factor(x**2 - 1) == [x - 1, x + 1] assert R.dup_zz_cyclotomic_factor(x**27 + 1) == \ [x + 1, x**2 - x + 1, x**6 - x**3 + 1, x**18 - x**9 + 1] assert R.dup_zz_cyclotomic_factor(x**27 - 1) == \ [x - 1, x**2 + x + 1, x**6 + x**3 + 1, x**18 + x**9 + 1] def test_dup_zz_factor(): R, x = ring("x", ZZ) assert R.dup_zz_factor(0) == (0, []) assert R.dup_zz_factor(7) == (7, []) assert R.dup_zz_factor(-7) == (-7, []) assert R.dup_zz_factor_sqf(0) == (0, []) assert R.dup_zz_factor_sqf(7) == (7, []) assert R.dup_zz_factor_sqf(-7) == (-7, []) assert R.dup_zz_factor(2*x + 4) == (2, [(x + 2, 1)]) assert R.dup_zz_factor_sqf(2*x + 4) == (2, [x + 2]) f = x**4 + x + 1 for i in range(0, 20): assert R.dup_zz_factor(f) == (1, [(f, 1)]) assert R.dup_zz_factor(x**2 + 2*x + 2) == \ (1, [(x**2 + 2*x + 2, 1)]) assert R.dup_zz_factor(18*x**2 + 12*x + 2) == \ (2, [(3*x + 1, 2)]) assert R.dup_zz_factor(-9*x**2 + 1) == \ (-1, [(3*x - 1, 1), (3*x + 1, 1)]) assert R.dup_zz_factor_sqf(-9*x**2 + 1) == \ (-1, [3*x - 1, 3*x + 1]) assert R.dup_zz_factor(x**3 - 6*x**2 + 11*x - 6) == \ (1, [(x - 3, 1), (x - 2, 1), (x - 1, 1)]) assert R.dup_zz_factor_sqf(x**3 - 6*x**2 + 11*x - 6) == \ (1, [x - 3, x - 2, x - 1]) assert R.dup_zz_factor(3*x**3 + 10*x**2 + 13*x + 10) == \ (1, [(x + 2, 1), (3*x**2 + 4*x + 5, 1)]) assert R.dup_zz_factor_sqf(3*x**3 + 10*x**2 + 13*x + 10) == \ (1, [x + 2, 3*x**2 + 4*x + 5]) assert R.dup_zz_factor(-x**6 + x**2) == \ (-1, [(x - 1, 1), (x + 1, 1), (x, 2), (x**2 + 1, 1)]) f = 1080*x**8 + 5184*x**7 + 2099*x**6 + 744*x**5 + 2736*x**4 - 648*x**3 + 129*x**2 - 324 assert R.dup_zz_factor(f) == \ (1, [(5*x**4 + 24*x**3 + 9*x**2 + 12, 1), (216*x**4 + 31*x**2 - 27, 1)]) f = -29802322387695312500000000000000000000*x**25 \ + 2980232238769531250000000000000000*x**20 \ + 1743435859680175781250000000000*x**15 \ + 114142894744873046875000000*x**10 \ - 210106372833251953125*x**5 \ + 95367431640625 assert R.dup_zz_factor(f) == \ (-95367431640625, [(5*x - 1, 1), (100*x**2 + 10*x - 1, 2), (625*x**4 + 125*x**3 + 25*x**2 + 5*x + 1, 1), (10000*x**4 - 3000*x**3 + 400*x**2 - 20*x + 1, 2), (10000*x**4 + 2000*x**3 + 400*x**2 + 30*x + 1, 2)]) f = x**10 - 1 config.setup('USE_CYCLOTOMIC_FACTOR', True) F_0 = R.dup_zz_factor(f) config.setup('USE_CYCLOTOMIC_FACTOR', False) F_1 = R.dup_zz_factor(f) assert F_0 == F_1 == \ (1, [(x - 1, 1), (x + 1, 1), (x**4 - x**3 + x**2 - x + 1, 1), (x**4 + x**3 + x**2 + x + 1, 1)]) config.setup('USE_CYCLOTOMIC_FACTOR') f = x**10 + 1 config.setup('USE_CYCLOTOMIC_FACTOR', True) F_0 = R.dup_zz_factor(f) config.setup('USE_CYCLOTOMIC_FACTOR', False) F_1 = R.dup_zz_factor(f) assert F_0 == F_1 == \ (1, [(x**2 + 1, 1), (x**8 - x**6 + x**4 - x**2 + 1, 1)]) config.setup('USE_CYCLOTOMIC_FACTOR') def test_dmp_zz_wang(): R, x,y,z = ring("x,y,z", ZZ) UV, _x = ring("x", ZZ) p = ZZ(nextprime(R.dmp_zz_mignotte_bound(w_1))) assert p == 6291469 t_1, k_1, e_1 = y, 1, ZZ(-14) t_2, k_2, e_2 = z, 2, ZZ(3) t_3, k_3, e_3 = y + z, 2, ZZ(-11) t_4, k_4, e_4 = y - z, 1, ZZ(-17) T = [t_1, t_2, t_3, t_4] K = [k_1, k_2, k_3, k_4] E = [e_1, e_2, e_3, e_4] T = zip([ t.drop(x) for t in T ], K) A = [ZZ(-14), ZZ(3)] S = R.dmp_eval_tail(w_1, A) cs, s = UV.dup_primitive(S) assert cs == 1 and s == S == \ 1036728*_x**6 + 915552*_x**5 + 55748*_x**4 + 105621*_x**3 - 17304*_x**2 - 26841*_x - 644 assert R.dmp_zz_wang_non_divisors(E, cs, ZZ(4)) == [7, 3, 11, 17] assert UV.dup_sqf_p(s) and UV.dup_degree(s) == R.dmp_degree(w_1) _, H = UV.dup_zz_factor_sqf(s) h_1 = 44*_x**2 + 42*_x + 1 h_2 = 126*_x**2 - 9*_x + 28 h_3 = 187*_x**2 - 23 assert H == [h_1, h_2, h_3] LC = [ lc.drop(x) for lc in [-4*y - 4*z, -y*z**2, y**2 - z**2] ] assert R.dmp_zz_wang_lead_coeffs(w_1, T, cs, E, H, A) == (w_1, H, LC) factors = R.dmp_zz_wang_hensel_lifting(w_1, H, LC, A, p) assert R.dmp_expand(factors) == w_1 @XFAIL def test_dmp_zz_wang_fail(): R, x,y,z = ring("x,y,z", ZZ) UV, _x = ring("x", ZZ) p = ZZ(nextprime(R.dmp_zz_mignotte_bound(w_1))) assert p == 6291469 H_1 = [44*x**2 + 42*x + 1, 126*x**2 - 9*x + 28, 187*x**2 - 23] H_2 = [-4*x**2*y - 12*x**2 - 3*x*y + 1, -9*x**2*y - 9*x - 2*y, x**2*y**2 - 9*x**2 + y - 9] H_3 = [-4*x**2*y - 12*x**2 - 3*x*y + 1, -9*x**2*y - 9*x - 2*y, x**2*y**2 - 9*x**2 + y - 9] c_1 = -70686*x**5 - 5863*x**4 - 17826*x**3 + 2009*x**2 + 5031*x + 74 c_2 = 9*x**5*y**4 + 12*x**5*y**3 - 45*x**5*y**2 - 108*x**5*y - 324*x**5 + 18*x**4*y**3 - 216*x**4*y**2 - 810*x**4*y + 2*x**3*y**4 + 9*x**3*y**3 - 252*x**3*y**2 - 288*x**3*y - 945*x**3 - 30*x**2*y**2 - 414*x**2*y + 2*x*y**3 - 54*x*y**2 - 3*x*y + 81*x + 12*y c_3 = -36*x**4*y**2 - 108*x**4*y - 27*x**3*y**2 - 36*x**3*y - 108*x**3 - 8*x**2*y**2 - 42*x**2*y - 6*x*y**2 + 9*x + 2*y assert R.dmp_zz_diophantine(H_1, c_1, [], 5, p) == [-3*x, -2, 1] assert R.dmp_zz_diophantine(H_2, c_2, [ZZ(-14)], 5, p) == [-x*y, -3*x, -6] assert R.dmp_zz_diophantine(H_3, c_3, [ZZ(-14)], 5, p) == [0, 0, -1] def test_issue_6355(): # This tests a bug in the Wang algorithm that occurred only with a very # specific set of random numbers. random_sequence = [-1, -1, 0, 0, 0, 0, -1, -1, 0, -1, 3, -1, 3, 3, 3, 3, -1, 3] R, x, y, z = ring("x,y,z", ZZ) f = 2*x**2 + y*z - y - z**2 + z assert R.dmp_zz_wang(f, seed=random_sequence) == [f] def test_dmp_zz_factor(): R, x = ring("x", ZZ) assert R.dmp_zz_factor(0) == (0, []) assert R.dmp_zz_factor(7) == (7, []) assert R.dmp_zz_factor(-7) == (-7, []) assert R.dmp_zz_factor(x**2 - 9) == (1, [(x - 3, 1), (x + 3, 1)]) R, x, y = ring("x,y", ZZ) assert R.dmp_zz_factor(0) == (0, []) assert R.dmp_zz_factor(7) == (7, []) assert R.dmp_zz_factor(-7) == (-7, []) assert R.dmp_zz_factor(x) == (1, [(x, 1)]) assert R.dmp_zz_factor(4*x) == (4, [(x, 1)]) assert R.dmp_zz_factor(4*x + 2) == (2, [(2*x + 1, 1)]) assert R.dmp_zz_factor(x*y + 1) == (1, [(x*y + 1, 1)]) assert R.dmp_zz_factor(y**2 + 1) == (1, [(y**2 + 1, 1)]) assert R.dmp_zz_factor(y**2 - 1) == (1, [(y - 1, 1), (y + 1, 1)]) assert R.dmp_zz_factor(x**2*y**2 + 6*x**2*y + 9*x**2 - 1) == (1, [(x*y + 3*x - 1, 1), (x*y + 3*x + 1, 1)]) assert R.dmp_zz_factor(x**2*y**2 - 9) == (1, [(x*y - 3, 1), (x*y + 3, 1)]) R, x, y, z = ring("x,y,z", ZZ) assert R.dmp_zz_factor(x**2*y**2*z**2 - 9) == \ (1, [(x*y*z - 3, 1), (x*y*z + 3, 1)]) R, x, y, z, u = ring("x,y,z,u", ZZ) assert R.dmp_zz_factor(x**2*y**2*z**2*u**2 - 9) == \ (1, [(x*y*z*u - 3, 1), (x*y*z*u + 3, 1)]) R, x, y, z = ring("x,y,z", ZZ) assert R.dmp_zz_factor(f_1) == \ (1, [(x + y*z + 20, 1), (x*y + z + 10, 1), (x*z + y + 30, 1)]) assert R.dmp_zz_factor(f_2) == \ (1, [(x**2*y**2 + x**2*z**2 + y + 90, 1), (x**3*y + x**3*z + z - 11, 1)]) assert R.dmp_zz_factor(f_3) == \ (1, [(x**2*y**2 + x*z**4 + x + z, 1), (x**3 + x*y*z + y**2 + y*z**3, 1)]) assert R.dmp_zz_factor(f_4) == \ (-1, [(x*y**3 + z**2, 1), (x**2*z + y**4*z**2 + 5, 1), (x**3*y - z**2 - 3, 1), (x**3*y**4 + z**2, 1)]) assert R.dmp_zz_factor(f_5) == \ (-1, [(x + y - z, 3)]) R, x, y, z, t = ring("x,y,z,t", ZZ) assert R.dmp_zz_factor(f_6) == \ (1, [(47*x*y + z**3*t**2 - t**2, 1), (45*x**3 - 9*y**3 - y**2 + 3*z**3 + 2*z*t, 1)]) R, x, y, z = ring("x,y,z", ZZ) assert R.dmp_zz_factor(w_1) == \ (1, [(x**2*y**2 - x**2*z**2 + y - z**2, 1), (x**2*y*z**2 + 3*x*z + 2*y, 1), (4*x**2*y + 4*x**2*z + x*y*z - 1, 1)]) R, x, y = ring("x,y", ZZ) f = -12*x**16*y + 240*x**12*y**3 - 768*x**10*y**4 + 1080*x**8*y**5 - 768*x**6*y**6 + 240*x**4*y**7 - 12*y**9 assert R.dmp_zz_factor(f) == \ (-12, [(y, 1), (x**2 - y, 6), (x**4 + 6*x**2*y + y**2, 1)]) def test_dup_qq_i_factor(): R, x = ring("x", QQ_I) i = QQ_I(0, 1) assert R.dup_qq_i_factor(x**2 - 2) == (QQ_I(1, 0), [(x**2 - 2, 1)]) assert R.dup_qq_i_factor(x**2 - 1) == (QQ_I(1, 0), [(x - 1, 1), (x + 1, 1)]) assert R.dup_qq_i_factor(x**2 + 1) == (QQ_I(1, 0), [(x - i, 1), (x + i, 1)]) assert R.dup_qq_i_factor(x**2/4 + 1) == \ (QQ_I(QQ(1, 4), 0), [(x - 2*i, 1), (x + 2*i, 1)]) assert R.dup_qq_i_factor(x**2 + 4) == \ (QQ_I(1, 0), [(x - 2*i, 1), (x + 2*i, 1)]) assert R.dup_qq_i_factor(x**2 + 2*x + 1) == \ (QQ_I(1, 0), [(x + 1, 2)]) assert R.dup_qq_i_factor(x**2 + 2*i*x - 1) == \ (QQ_I(1, 0), [(x + i, 2)]) f = 8192*x**2 + x*(22656 + 175232*i) - 921416 + 242313*i assert R.dup_qq_i_factor(f) == \ (QQ_I(8192, 0), [(x + QQ_I(QQ(177, 128), QQ(1369, 128)), 2)]) def test_dmp_qq_i_factor(): R, x, y = ring("x, y", QQ_I) i = QQ_I(0, 1) assert R.dmp_qq_i_factor(x**2 + 2*y**2) == \ (QQ_I(1, 0), [(x**2 + 2*y**2, 1)]) assert R.dmp_qq_i_factor(x**2 + y**2) == \ (QQ_I(1, 0), [(x - i*y, 1), (x + i*y, 1)]) assert R.dmp_qq_i_factor(x**2 + y**2/4) == \ (QQ_I(1, 0), [(x - i*y/2, 1), (x + i*y/2, 1)]) assert R.dmp_qq_i_factor(4*x**2 + y**2) == \ (QQ_I(4, 0), [(x - i*y/2, 1), (x + i*y/2, 1)]) def test_dup_zz_i_factor(): R, x = ring("x", ZZ_I) i = ZZ_I(0, 1) assert R.dup_zz_i_factor(x**2 - 2) == (ZZ_I(1, 0), [(x**2 - 2, 1)]) assert R.dup_zz_i_factor(x**2 - 1) == (ZZ_I(1, 0), [(x - 1, 1), (x + 1, 1)]) assert R.dup_zz_i_factor(x**2 + 1) == (ZZ_I(1, 0), [(x - i, 1), (x + i, 1)]) assert R.dup_zz_i_factor(x**2 + 4) == \ (ZZ_I(1, 0), [(x - 2*i, 1), (x + 2*i, 1)]) assert R.dup_zz_i_factor(x**2 + 2*x + 1) == \ (ZZ_I(1, 0), [(x + 1, 2)]) assert R.dup_zz_i_factor(x**2 + 2*i*x - 1) == \ (ZZ_I(1, 0), [(x + i, 2)]) f = 8192*x**2 + x*(22656 + 175232*i) - 921416 + 242313*i assert R.dup_zz_i_factor(f) == \ (ZZ_I(0, 1), [((64 - 64*i)*x + (773 + 596*i), 2)]) def test_dmp_zz_i_factor(): R, x, y = ring("x, y", ZZ_I) i = ZZ_I(0, 1) assert R.dmp_zz_i_factor(x**2 + 2*y**2) == \ (ZZ_I(1, 0), [(x**2 + 2*y**2, 1)]) assert R.dmp_zz_i_factor(x**2 + y**2) == \ (ZZ_I(1, 0), [(x - i*y, 1), (x + i*y, 1)]) assert R.dmp_zz_i_factor(4*x**2 + y**2) == \ (ZZ_I(1, 0), [(2*x - i*y, 1), (2*x + i*y, 1)]) def test_dup_ext_factor(): R, x = ring("x", QQ.algebraic_field(I)) def anp(element): return ANP(element, [QQ(1), QQ(0), QQ(1)], QQ) assert R.dup_ext_factor(0) == (anp([]), []) f = anp([QQ(1)])*x + anp([QQ(1)]) assert R.dup_ext_factor(f) == (anp([QQ(1)]), [(f, 1)]) g = anp([QQ(2)])*x + anp([QQ(2)]) assert R.dup_ext_factor(g) == (anp([QQ(2)]), [(f, 1)]) f = anp([QQ(7)])*x**4 + anp([QQ(1, 1)]) g = anp([QQ(1)])*x**4 + anp([QQ(1, 7)]) assert R.dup_ext_factor(f) == (anp([QQ(7)]), [(g, 1)]) f = anp([QQ(1)])*x**4 + anp([QQ(1)]) assert R.dup_ext_factor(f) == \ (anp([QQ(1, 1)]), [(anp([QQ(1)])*x**2 + anp([QQ(-1), QQ(0)]), 1), (anp([QQ(1)])*x**2 + anp([QQ( 1), QQ(0)]), 1)]) f = anp([QQ(4, 1)])*x**2 + anp([QQ(9, 1)]) assert R.dup_ext_factor(f) == \ (anp([QQ(4, 1)]), [(anp([QQ(1, 1)])*x + anp([-QQ(3, 2), QQ(0, 1)]), 1), (anp([QQ(1, 1)])*x + anp([ QQ(3, 2), QQ(0, 1)]), 1)]) f = anp([QQ(4, 1)])*x**4 + anp([QQ(8, 1)])*x**3 + anp([QQ(77, 1)])*x**2 + anp([QQ(18, 1)])*x + anp([QQ(153, 1)]) assert R.dup_ext_factor(f) == \ (anp([QQ(4, 1)]), [(anp([QQ(1, 1)])*x + anp([-QQ(4, 1), QQ(1, 1)]), 1), (anp([QQ(1, 1)])*x + anp([-QQ(3, 2), QQ(0, 1)]), 1), (anp([QQ(1, 1)])*x + anp([ QQ(3, 2), QQ(0, 1)]), 1), (anp([QQ(1, 1)])*x + anp([ QQ(4, 1), QQ(1, 1)]), 1)]) R, x = ring("x", QQ.algebraic_field(sqrt(2))) def anp(element): return ANP(element, [QQ(1), QQ(0), QQ(-2)], QQ) f = anp([QQ(1)])*x**4 + anp([QQ(1, 1)]) assert R.dup_ext_factor(f) == \ (anp([QQ(1)]), [(anp([QQ(1)])*x**2 + anp([QQ(-1), QQ(0)])*x + anp([QQ(1)]), 1), (anp([QQ(1)])*x**2 + anp([QQ( 1), QQ(0)])*x + anp([QQ(1)]), 1)]) f = anp([QQ(1, 1)])*x**2 + anp([QQ(2), QQ(0)])*x + anp([QQ(2, 1)]) assert R.dup_ext_factor(f) == \ (anp([QQ(1, 1)]), [(anp([1])*x + anp([1, 0]), 2)]) assert R.dup_ext_factor(f**3) == \ (anp([QQ(1, 1)]), [(anp([1])*x + anp([1, 0]), 6)]) f *= anp([QQ(2, 1)]) assert R.dup_ext_factor(f) == \ (anp([QQ(2, 1)]), [(anp([1])*x + anp([1, 0]), 2)]) assert R.dup_ext_factor(f**3) == \ (anp([QQ(8, 1)]), [(anp([1])*x + anp([1, 0]), 6)]) def test_dmp_ext_factor(): R, x,y = ring("x,y", QQ.algebraic_field(sqrt(2))) def anp(x): return ANP(x, [QQ(1), QQ(0), QQ(-2)], QQ) assert R.dmp_ext_factor(0) == (anp([]), []) f = anp([QQ(1)])*x + anp([QQ(1)]) assert R.dmp_ext_factor(f) == (anp([QQ(1)]), [(f, 1)]) g = anp([QQ(2)])*x + anp([QQ(2)]) assert R.dmp_ext_factor(g) == (anp([QQ(2)]), [(f, 1)]) f = anp([QQ(1)])*x**2 + anp([QQ(-2)])*y**2 assert R.dmp_ext_factor(f) == \ (anp([QQ(1)]), [(anp([QQ(1)])*x + anp([QQ(-1), QQ(0)])*y, 1), (anp([QQ(1)])*x + anp([QQ( 1), QQ(0)])*y, 1)]) f = anp([QQ(2)])*x**2 + anp([QQ(-4)])*y**2 assert R.dmp_ext_factor(f) == \ (anp([QQ(2)]), [(anp([QQ(1)])*x + anp([QQ(-1), QQ(0)])*y, 1), (anp([QQ(1)])*x + anp([QQ( 1), QQ(0)])*y, 1)]) def test_dup_factor_list(): R, x = ring("x", ZZ) assert R.dup_factor_list(0) == (0, []) assert R.dup_factor_list(7) == (7, []) R, x = ring("x", QQ) assert R.dup_factor_list(0) == (0, []) assert R.dup_factor_list(QQ(1, 7)) == (QQ(1, 7), []) R, x = ring("x", ZZ['t']) assert R.dup_factor_list(0) == (0, []) assert R.dup_factor_list(7) == (7, []) R, x = ring("x", QQ['t']) assert R.dup_factor_list(0) == (0, []) assert R.dup_factor_list(QQ(1, 7)) == (QQ(1, 7), []) R, x = ring("x", ZZ) assert R.dup_factor_list_include(0) == [(0, 1)] assert R.dup_factor_list_include(7) == [(7, 1)] assert R.dup_factor_list(x**2 + 2*x + 1) == (1, [(x + 1, 2)]) assert R.dup_factor_list_include(x**2 + 2*x + 1) == [(x + 1, 2)] # issue 8037 assert R.dup_factor_list(6*x**2 - 5*x - 6) == (1, [(2*x - 3, 1), (3*x + 2, 1)]) R, x = ring("x", QQ) assert R.dup_factor_list(QQ(1,2)*x**2 + x + QQ(1,2)) == (QQ(1, 2), [(x + 1, 2)]) R, x = ring("x", FF(2)) assert R.dup_factor_list(x**2 + 1) == (1, [(x + 1, 2)]) R, x = ring("x", RR) assert R.dup_factor_list(1.0*x**2 + 2.0*x + 1.0) == (1.0, [(1.0*x + 1.0, 2)]) assert R.dup_factor_list(2.0*x**2 + 4.0*x + 2.0) == (2.0, [(1.0*x + 1.0, 2)]) f = 6.7225336055071*x**2 - 10.6463972754741*x - 0.33469524022264 coeff, factors = R.dup_factor_list(f) assert coeff == RR(10.6463972754741) assert len(factors) == 1 assert factors[0][0].max_norm() == RR(1.0) assert factors[0][1] == 1 Rt, t = ring("t", ZZ) R, x = ring("x", Rt) f = 4*t*x**2 + 4*t**2*x assert R.dup_factor_list(f) == \ (4*t, [(x, 1), (x + t, 1)]) Rt, t = ring("t", QQ) R, x = ring("x", Rt) f = QQ(1, 2)*t*x**2 + QQ(1, 2)*t**2*x assert R.dup_factor_list(f) == \ (QQ(1, 2)*t, [(x, 1), (x + t, 1)]) R, x = ring("x", QQ.algebraic_field(I)) def anp(element): return ANP(element, [QQ(1), QQ(0), QQ(1)], QQ) f = anp([QQ(1, 1)])*x**4 + anp([QQ(2, 1)])*x**2 assert R.dup_factor_list(f) == \ (anp([QQ(1, 1)]), [(anp([QQ(1, 1)])*x, 2), (anp([QQ(1, 1)])*x**2 + anp([])*x + anp([QQ(2, 1)]), 1)]) R, x = ring("x", EX) raises(DomainError, lambda: R.dup_factor_list(EX(sin(1)))) def test_dmp_factor_list(): R, x, y = ring("x,y", ZZ) assert R.dmp_factor_list(0) == (ZZ(0), []) assert R.dmp_factor_list(7) == (7, []) R, x, y = ring("x,y", QQ) assert R.dmp_factor_list(0) == (QQ(0), []) assert R.dmp_factor_list(QQ(1, 7)) == (QQ(1, 7), []) Rt, t = ring("t", ZZ) R, x, y = ring("x,y", Rt) assert R.dmp_factor_list(0) == (0, []) assert R.dmp_factor_list(7) == (ZZ(7), []) Rt, t = ring("t", QQ) R, x, y = ring("x,y", Rt) assert R.dmp_factor_list(0) == (0, []) assert R.dmp_factor_list(QQ(1, 7)) == (QQ(1, 7), []) R, x, y = ring("x,y", ZZ) assert R.dmp_factor_list_include(0) == [(0, 1)] assert R.dmp_factor_list_include(7) == [(7, 1)] R, X = xring("x:200", ZZ) f, g = X[0]**2 + 2*X[0] + 1, X[0] + 1 assert R.dmp_factor_list(f) == (1, [(g, 2)]) f, g = X[-1]**2 + 2*X[-1] + 1, X[-1] + 1 assert R.dmp_factor_list(f) == (1, [(g, 2)]) R, x = ring("x", ZZ) assert R.dmp_factor_list(x**2 + 2*x + 1) == (1, [(x + 1, 2)]) R, x = ring("x", QQ) assert R.dmp_factor_list(QQ(1,2)*x**2 + x + QQ(1,2)) == (QQ(1,2), [(x + 1, 2)]) R, x, y = ring("x,y", ZZ) assert R.dmp_factor_list(x**2 + 2*x + 1) == (1, [(x + 1, 2)]) R, x, y = ring("x,y", QQ) assert R.dmp_factor_list(QQ(1,2)*x**2 + x + QQ(1,2)) == (QQ(1,2), [(x + 1, 2)]) R, x, y = ring("x,y", ZZ) f = 4*x**2*y + 4*x*y**2 assert R.dmp_factor_list(f) == \ (4, [(y, 1), (x, 1), (x + y, 1)]) assert R.dmp_factor_list_include(f) == \ [(4*y, 1), (x, 1), (x + y, 1)] R, x, y = ring("x,y", QQ) f = QQ(1,2)*x**2*y + QQ(1,2)*x*y**2 assert R.dmp_factor_list(f) == \ (QQ(1,2), [(y, 1), (x, 1), (x + y, 1)]) R, x, y = ring("x,y", RR) f = 2.0*x**2 - 8.0*y**2 assert R.dmp_factor_list(f) == \ (RR(8.0), [(0.5*x - y, 1), (0.5*x + y, 1)]) f = 6.7225336055071*x**2*y**2 - 10.6463972754741*x*y - 0.33469524022264 coeff, factors = R.dmp_factor_list(f) assert coeff == RR(10.6463972754741) assert len(factors) == 1 assert factors[0][0].max_norm() == RR(1.0) assert factors[0][1] == 1 Rt, t = ring("t", ZZ) R, x, y = ring("x,y", Rt) f = 4*t*x**2 + 4*t**2*x assert R.dmp_factor_list(f) == \ (4*t, [(x, 1), (x + t, 1)]) Rt, t = ring("t", QQ) R, x, y = ring("x,y", Rt) f = QQ(1, 2)*t*x**2 + QQ(1, 2)*t**2*x assert R.dmp_factor_list(f) == \ (QQ(1, 2)*t, [(x, 1), (x + t, 1)]) R, x, y = ring("x,y", FF(2)) raises(NotImplementedError, lambda: R.dmp_factor_list(x**2 + y**2)) R, x, y = ring("x,y", EX) raises(DomainError, lambda: R.dmp_factor_list(EX(sin(1)))) def test_dup_irreducible_p(): R, x = ring("x", ZZ) assert R.dup_irreducible_p(x**2 + x + 1) is True assert R.dup_irreducible_p(x**2 + 2*x + 1) is False def test_dmp_irreducible_p(): R, x, y = ring("x,y", ZZ) assert R.dmp_irreducible_p(x**2 + x + 1) is True assert R.dmp_irreducible_p(x**2 + 2*x + 1) is False sympy-sympy-1.9/sympy/polys/tests/test_fields.py000066400000000000000000000236201412543434000222760ustar00rootroot00000000000000"""Test sparse rational functions. """ from sympy.polys.fields import field, sfield, FracField, FracElement from sympy.polys.rings import ring from sympy.polys.domains import ZZ, QQ from sympy.polys.orderings import lex from sympy.testing.pytest import raises, XFAIL from sympy.core import symbols, E from sympy import sqrt, Rational, exp, log def test_FracField___init__(): F1 = FracField("x,y", ZZ, lex) F2 = FracField("x,y", ZZ, lex) F3 = FracField("x,y,z", ZZ, lex) assert F1.x == F1.gens[0] assert F1.y == F1.gens[1] assert F1.x == F2.x assert F1.y == F2.y assert F1.x != F3.x assert F1.y != F3.y def test_FracField___hash__(): F, x, y, z = field("x,y,z", QQ) assert hash(F) def test_FracField___eq__(): assert field("x,y,z", QQ)[0] == field("x,y,z", QQ)[0] assert field("x,y,z", QQ)[0] is field("x,y,z", QQ)[0] assert field("x,y,z", QQ)[0] != field("x,y,z", ZZ)[0] assert field("x,y,z", QQ)[0] is not field("x,y,z", ZZ)[0] assert field("x,y,z", ZZ)[0] != field("x,y,z", QQ)[0] assert field("x,y,z", ZZ)[0] is not field("x,y,z", QQ)[0] assert field("x,y,z", QQ)[0] != field("x,y", QQ)[0] assert field("x,y,z", QQ)[0] is not field("x,y", QQ)[0] assert field("x,y", QQ)[0] != field("x,y,z", QQ)[0] assert field("x,y", QQ)[0] is not field("x,y,z", QQ)[0] def test_sfield(): x = symbols("x") F = FracField((E, exp(exp(x)), exp(x)), ZZ, lex) e, exex, ex = F.gens assert sfield(exp(x)*exp(exp(x) + 1 + log(exp(x) + 3)/2)**2/(exp(x) + 3)) \ == (F, e**2*exex**2*ex) F = FracField((x, exp(1/x), log(x), x**QQ(1, 3)), ZZ, lex) _, ex, lg, x3 = F.gens assert sfield(((x-3)*log(x)+4*x**2)*exp(1/x+log(x)/3)/x**2) == \ (F, (4*F.x**2*ex + F.x*ex*lg - 3*ex*lg)/x3**5) F = FracField((x, log(x), sqrt(x + log(x))), ZZ, lex) _, lg, srt = F.gens assert sfield((x + 1) / (x * (x + log(x))**QQ(3, 2)) - 1/(x * log(x)**2)) \ == (F, (F.x*lg**2 - F.x*srt + lg**2 - lg*srt)/ (F.x**2*lg**2*srt + F.x*lg**3*srt)) def test_FracElement___hash__(): F, x, y, z = field("x,y,z", QQ) assert hash(x*y/z) def test_FracElement_copy(): F, x, y, z = field("x,y,z", ZZ) f = x*y/3*z g = f.copy() assert f == g g.numer[(1, 1, 1)] = 7 assert f != g def test_FracElement_as_expr(): F, x, y, z = field("x,y,z", ZZ) f = (3*x**2*y - x*y*z)/(7*z**3 + 1) X, Y, Z = F.symbols g = (3*X**2*Y - X*Y*Z)/(7*Z**3 + 1) assert f != g assert f.as_expr() == g X, Y, Z = symbols("x,y,z") g = (3*X**2*Y - X*Y*Z)/(7*Z**3 + 1) assert f != g assert f.as_expr(X, Y, Z) == g raises(ValueError, lambda: f.as_expr(X)) def test_FracElement_from_expr(): x, y, z = symbols("x,y,z") F, X, Y, Z = field((x, y, z), ZZ) f = F.from_expr(1) assert f == 1 and isinstance(f, F.dtype) f = F.from_expr(Rational(3, 7)) assert f == F(3)/7 and isinstance(f, F.dtype) f = F.from_expr(x) assert f == X and isinstance(f, F.dtype) f = F.from_expr(Rational(3,7)*x) assert f == X*Rational(3, 7) and isinstance(f, F.dtype) f = F.from_expr(1/x) assert f == 1/X and isinstance(f, F.dtype) f = F.from_expr(x*y*z) assert f == X*Y*Z and isinstance(f, F.dtype) f = F.from_expr(x*y/z) assert f == X*Y/Z and isinstance(f, F.dtype) f = F.from_expr(x*y*z + x*y + x) assert f == X*Y*Z + X*Y + X and isinstance(f, F.dtype) f = F.from_expr((x*y*z + x*y + x)/(x*y + 7)) assert f == (X*Y*Z + X*Y + X)/(X*Y + 7) and isinstance(f, F.dtype) f = F.from_expr(x**3*y*z + x**2*y**7 + 1) assert f == X**3*Y*Z + X**2*Y**7 + 1 and isinstance(f, F.dtype) raises(ValueError, lambda: F.from_expr(2**x)) raises(ValueError, lambda: F.from_expr(7*x + sqrt(2))) assert isinstance(ZZ[2**x].get_field().convert(2**(-x)), FracElement) assert isinstance(ZZ[x**2].get_field().convert(x**(-6)), FracElement) assert isinstance(ZZ[exp(Rational(1, 3))].get_field().convert(E), FracElement) def test_FracField_nested(): a, b, x = symbols('a b x') F1 = ZZ.frac_field(a, b) F2 = F1.frac_field(x) frac = F2(a + b) assert frac.numer == F1.poly_ring(x)(a + b) assert frac.numer.coeffs() == [F1(a + b)] assert frac.denom == F1.poly_ring(x)(1) F3 = ZZ.poly_ring(a, b) F4 = F3.frac_field(x) frac = F4(a + b) assert frac.numer == F3.poly_ring(x)(a + b) assert frac.numer.coeffs() == [F3(a + b)] assert frac.denom == F3.poly_ring(x)(1) frac = F2(F3(a + b)) assert frac.numer == F1.poly_ring(x)(a + b) assert frac.numer.coeffs() == [F1(a + b)] assert frac.denom == F1.poly_ring(x)(1) frac = F4(F1(a + b)) assert frac.numer == F3.poly_ring(x)(a + b) assert frac.numer.coeffs() == [F3(a + b)] assert frac.denom == F3.poly_ring(x)(1) def test_FracElement__lt_le_gt_ge__(): F, x, y = field("x,y", ZZ) assert F(1) < 1/x < 1/x**2 < 1/x**3 assert F(1) <= 1/x <= 1/x**2 <= 1/x**3 assert -7/x < 1/x < 3/x < y/x < 1/x**2 assert -7/x <= 1/x <= 3/x <= y/x <= 1/x**2 assert 1/x**3 > 1/x**2 > 1/x > F(1) assert 1/x**3 >= 1/x**2 >= 1/x >= F(1) assert 1/x**2 > y/x > 3/x > 1/x > -7/x assert 1/x**2 >= y/x >= 3/x >= 1/x >= -7/x def test_FracElement___neg__(): F, x,y = field("x,y", QQ) f = (7*x - 9)/y g = (-7*x + 9)/y assert -f == g assert -g == f def test_FracElement___add__(): F, x,y = field("x,y", QQ) f, g = 1/x, 1/y assert f + g == g + f == (x + y)/(x*y) assert x + F.ring.gens[0] == F.ring.gens[0] + x == 2*x F, x,y = field("x,y", ZZ) assert x + 3 == 3 + x assert x + QQ(3,7) == QQ(3,7) + x == (7*x + 3)/7 Fuv, u,v = field("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) f = (u*v + x)/(y + u*v) assert dict(f.numer) == {(1, 0, 0, 0): 1, (0, 0, 0, 0): u*v} assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0): u*v} Ruv, u,v = ring("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) f = (u*v + x)/(y + u*v) assert dict(f.numer) == {(1, 0, 0, 0): 1, (0, 0, 0, 0): u*v} assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0): u*v} def test_FracElement___sub__(): F, x,y = field("x,y", QQ) f, g = 1/x, 1/y assert f - g == (-x + y)/(x*y) assert x - F.ring.gens[0] == F.ring.gens[0] - x == 0 F, x,y = field("x,y", ZZ) assert x - 3 == -(3 - x) assert x - QQ(3,7) == -(QQ(3,7) - x) == (7*x - 3)/7 Fuv, u,v = field("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) f = (u*v - x)/(y - u*v) assert dict(f.numer) == {(1, 0, 0, 0):-1, (0, 0, 0, 0): u*v} assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0):-u*v} Ruv, u,v = ring("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) f = (u*v - x)/(y - u*v) assert dict(f.numer) == {(1, 0, 0, 0):-1, (0, 0, 0, 0): u*v} assert dict(f.denom) == {(0, 1, 0, 0): 1, (0, 0, 0, 0):-u*v} def test_FracElement___mul__(): F, x,y = field("x,y", QQ) f, g = 1/x, 1/y assert f*g == g*f == 1/(x*y) assert x*F.ring.gens[0] == F.ring.gens[0]*x == x**2 F, x,y = field("x,y", ZZ) assert x*3 == 3*x assert x*QQ(3,7) == QQ(3,7)*x == x*Rational(3, 7) Fuv, u,v = field("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) f = ((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1) assert dict(f.numer) == {(1, 1, 0, 0): u + 1, (0, 0, 0, 0): 1} assert dict(f.denom) == {(0, 0, 1, 0): v - 1, (0, 0, 0, 1): -u*v, (0, 0, 0, 0): -1} Ruv, u,v = ring("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) f = ((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1) assert dict(f.numer) == {(1, 1, 0, 0): u + 1, (0, 0, 0, 0): 1} assert dict(f.denom) == {(0, 0, 1, 0): v - 1, (0, 0, 0, 1): -u*v, (0, 0, 0, 0): -1} def test_FracElement___truediv__(): F, x,y = field("x,y", QQ) f, g = 1/x, 1/y assert f/g == y/x assert x/F.ring.gens[0] == F.ring.gens[0]/x == 1 F, x,y = field("x,y", ZZ) assert x*3 == 3*x assert x/QQ(3,7) == (QQ(3,7)/x)**-1 == x*Rational(7, 3) raises(ZeroDivisionError, lambda: x/0) raises(ZeroDivisionError, lambda: 1/(x - x)) raises(ZeroDivisionError, lambda: x/(x - x)) Fuv, u,v = field("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) f = (u*v)/(x*y) assert dict(f.numer) == {(0, 0, 0, 0): u*v} assert dict(f.denom) == {(1, 1, 0, 0): 1} g = (x*y)/(u*v) assert dict(g.numer) == {(1, 1, 0, 0): 1} assert dict(g.denom) == {(0, 0, 0, 0): u*v} Ruv, u,v = ring("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Ruv) f = (u*v)/(x*y) assert dict(f.numer) == {(0, 0, 0, 0): u*v} assert dict(f.denom) == {(1, 1, 0, 0): 1} g = (x*y)/(u*v) assert dict(g.numer) == {(1, 1, 0, 0): 1} assert dict(g.denom) == {(0, 0, 0, 0): u*v} def test_FracElement___pow__(): F, x,y = field("x,y", QQ) f, g = 1/x, 1/y assert f**3 == 1/x**3 assert g**3 == 1/y**3 assert (f*g)**3 == 1/(x**3*y**3) assert (f*g)**-3 == (x*y)**3 raises(ZeroDivisionError, lambda: (x - x)**-3) def test_FracElement_diff(): F, x,y,z = field("x,y,z", ZZ) assert ((x**2 + y)/(z + 1)).diff(x) == 2*x/(z + 1) @XFAIL def test_FracElement___call__(): F, x,y,z = field("x,y,z", ZZ) f = (x**2 + 3*y)/z r = f(1, 1, 1) assert r == 4 and not isinstance(r, FracElement) raises(ZeroDivisionError, lambda: f(1, 1, 0)) def test_FracElement_evaluate(): F, x,y,z = field("x,y,z", ZZ) Fyz = field("y,z", ZZ)[0] f = (x**2 + 3*y)/z assert f.evaluate(x, 0) == 3*Fyz.y/Fyz.z raises(ZeroDivisionError, lambda: f.evaluate(z, 0)) def test_FracElement_subs(): F, x,y,z = field("x,y,z", ZZ) f = (x**2 + 3*y)/z assert f.subs(x, 0) == 3*y/z raises(ZeroDivisionError, lambda: f.subs(z, 0)) def test_FracElement_compose(): pass def test_FracField_index(): a = symbols("a") F, x, y, z = field('x y z', QQ) assert F.index(x) == 0 assert F.index(y) == 1 raises(ValueError, lambda: F.index(1)) raises(ValueError, lambda: F.index(a)) pass sympy-sympy-1.9/sympy/polys/tests/test_galoistools.py000066400000000000000000000663321412543434000233760ustar00rootroot00000000000000from sympy.polys.galoistools import ( gf_crt, gf_crt1, gf_crt2, gf_int, gf_degree, gf_strip, gf_trunc, gf_normal, gf_from_dict, gf_to_dict, gf_from_int_poly, gf_to_int_poly, gf_neg, gf_add_ground, gf_sub_ground, gf_mul_ground, gf_add, gf_sub, gf_add_mul, gf_sub_mul, gf_mul, gf_sqr, gf_div, gf_rem, gf_quo, gf_exquo, gf_lshift, gf_rshift, gf_expand, gf_pow, gf_pow_mod, gf_gcdex, gf_gcd, gf_lcm, gf_cofactors, gf_LC, gf_TC, gf_monic, gf_eval, gf_multi_eval, gf_compose, gf_compose_mod, gf_trace_map, gf_diff, gf_irreducible, gf_irreducible_p, gf_irred_p_ben_or, gf_irred_p_rabin, gf_sqf_list, gf_sqf_part, gf_sqf_p, gf_Qmatrix, gf_Qbasis, gf_ddf_zassenhaus, gf_ddf_shoup, gf_edf_zassenhaus, gf_edf_shoup, gf_berlekamp, gf_factor_sqf, gf_factor, gf_value, linear_congruence, csolve_prime, gf_csolve, gf_frobenius_map, gf_frobenius_monomial_base ) from sympy.polys.polyerrors import ( ExactQuotientFailed, ) from sympy.polys import polyconfig as config from sympy.polys.domains import ZZ from sympy import pi, nextprime from sympy.testing.pytest import raises def test_gf_crt(): U = [49, 76, 65] M = [99, 97, 95] p = 912285 u = 639985 assert gf_crt(U, M, ZZ) == u E = [9215, 9405, 9603] S = [62, 24, 12] assert gf_crt1(M, ZZ) == (p, E, S) assert gf_crt2(U, M, p, E, S, ZZ) == u def test_gf_int(): assert gf_int(0, 5) == 0 assert gf_int(1, 5) == 1 assert gf_int(2, 5) == 2 assert gf_int(3, 5) == -2 assert gf_int(4, 5) == -1 assert gf_int(5, 5) == 0 def test_gf_degree(): assert gf_degree([]) == -1 assert gf_degree([1]) == 0 assert gf_degree([1, 0]) == 1 assert gf_degree([1, 0, 0, 0, 1]) == 4 def test_gf_strip(): assert gf_strip([]) == [] assert gf_strip([0]) == [] assert gf_strip([0, 0, 0]) == [] assert gf_strip([1]) == [1] assert gf_strip([0, 1]) == [1] assert gf_strip([0, 0, 0, 1]) == [1] assert gf_strip([1, 2, 0]) == [1, 2, 0] assert gf_strip([0, 1, 2, 0]) == [1, 2, 0] assert gf_strip([0, 0, 0, 1, 2, 0]) == [1, 2, 0] def test_gf_trunc(): assert gf_trunc([], 11) == [] assert gf_trunc([1], 11) == [1] assert gf_trunc([22], 11) == [] assert gf_trunc([12], 11) == [1] assert gf_trunc([11, 22, 17, 1, 0], 11) == [6, 1, 0] assert gf_trunc([12, 23, 17, 1, 0], 11) == [1, 1, 6, 1, 0] def test_gf_normal(): assert gf_normal([11, 22, 17, 1, 0], 11, ZZ) == [6, 1, 0] def test_gf_from_to_dict(): f = {11: 12, 6: 2, 0: 25} F = {11: 1, 6: 2, 0: 3} g = [1, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 3] assert gf_from_dict(f, 11, ZZ) == g assert gf_to_dict(g, 11) == F f = {11: -5, 4: 0, 3: 1, 0: 12} F = {11: -5, 3: 1, 0: 1} g = [6, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1] assert gf_from_dict(f, 11, ZZ) == g assert gf_to_dict(g, 11) == F assert gf_to_dict([10], 11, symmetric=True) == {0: -1} assert gf_to_dict([10], 11, symmetric=False) == {0: 10} def test_gf_from_to_int_poly(): assert gf_from_int_poly([1, 0, 7, 2, 20], 5) == [1, 0, 2, 2, 0] assert gf_to_int_poly([1, 0, 4, 2, 3], 5) == [1, 0, -1, 2, -2] assert gf_to_int_poly([10], 11, symmetric=True) == [-1] assert gf_to_int_poly([10], 11, symmetric=False) == [10] def test_gf_LC(): assert gf_LC([], ZZ) == 0 assert gf_LC([1], ZZ) == 1 assert gf_LC([1, 2], ZZ) == 1 def test_gf_TC(): assert gf_TC([], ZZ) == 0 assert gf_TC([1], ZZ) == 1 assert gf_TC([1, 2], ZZ) == 2 def test_gf_monic(): assert gf_monic(ZZ.map([]), 11, ZZ) == (0, []) assert gf_monic(ZZ.map([1]), 11, ZZ) == (1, [1]) assert gf_monic(ZZ.map([2]), 11, ZZ) == (2, [1]) assert gf_monic(ZZ.map([1, 2, 3, 4]), 11, ZZ) == (1, [1, 2, 3, 4]) assert gf_monic(ZZ.map([2, 3, 4, 5]), 11, ZZ) == (2, [1, 7, 2, 8]) def test_gf_arith(): assert gf_neg([], 11, ZZ) == [] assert gf_neg([1], 11, ZZ) == [10] assert gf_neg([1, 2, 3], 11, ZZ) == [10, 9, 8] assert gf_add_ground([], 0, 11, ZZ) == [] assert gf_sub_ground([], 0, 11, ZZ) == [] assert gf_add_ground([], 3, 11, ZZ) == [3] assert gf_sub_ground([], 3, 11, ZZ) == [8] assert gf_add_ground([1], 3, 11, ZZ) == [4] assert gf_sub_ground([1], 3, 11, ZZ) == [9] assert gf_add_ground([8], 3, 11, ZZ) == [] assert gf_sub_ground([3], 3, 11, ZZ) == [] assert gf_add_ground([1, 2, 3], 3, 11, ZZ) == [1, 2, 6] assert gf_sub_ground([1, 2, 3], 3, 11, ZZ) == [1, 2, 0] assert gf_mul_ground([], 0, 11, ZZ) == [] assert gf_mul_ground([], 1, 11, ZZ) == [] assert gf_mul_ground([1], 0, 11, ZZ) == [] assert gf_mul_ground([1], 1, 11, ZZ) == [1] assert gf_mul_ground([1, 2, 3], 0, 11, ZZ) == [] assert gf_mul_ground([1, 2, 3], 1, 11, ZZ) == [1, 2, 3] assert gf_mul_ground([1, 2, 3], 7, 11, ZZ) == [7, 3, 10] assert gf_add([], [], 11, ZZ) == [] assert gf_add([1], [], 11, ZZ) == [1] assert gf_add([], [1], 11, ZZ) == [1] assert gf_add([1], [1], 11, ZZ) == [2] assert gf_add([1], [2], 11, ZZ) == [3] assert gf_add([1, 2], [1], 11, ZZ) == [1, 3] assert gf_add([1], [1, 2], 11, ZZ) == [1, 3] assert gf_add([1, 2, 3], [8, 9, 10], 11, ZZ) == [9, 0, 2] assert gf_sub([], [], 11, ZZ) == [] assert gf_sub([1], [], 11, ZZ) == [1] assert gf_sub([], [1], 11, ZZ) == [10] assert gf_sub([1], [1], 11, ZZ) == [] assert gf_sub([1], [2], 11, ZZ) == [10] assert gf_sub([1, 2], [1], 11, ZZ) == [1, 1] assert gf_sub([1], [1, 2], 11, ZZ) == [10, 10] assert gf_sub([3, 2, 1], [8, 9, 10], 11, ZZ) == [6, 4, 2] assert gf_add_mul( [1, 5, 6], [7, 3], [8, 0, 6, 1], 11, ZZ) == [1, 2, 10, 8, 9] assert gf_sub_mul( [1, 5, 6], [7, 3], [8, 0, 6, 1], 11, ZZ) == [10, 9, 3, 2, 3] assert gf_mul([], [], 11, ZZ) == [] assert gf_mul([], [1], 11, ZZ) == [] assert gf_mul([1], [], 11, ZZ) == [] assert gf_mul([1], [1], 11, ZZ) == [1] assert gf_mul([5], [7], 11, ZZ) == [2] assert gf_mul([3, 0, 0, 6, 1, 2], [4, 0, 1, 0], 11, ZZ) == [1, 0, 3, 2, 4, 3, 1, 2, 0] assert gf_mul([4, 0, 1, 0], [3, 0, 0, 6, 1, 2], 11, ZZ) == [1, 0, 3, 2, 4, 3, 1, 2, 0] assert gf_mul([2, 0, 0, 1, 7], [2, 0, 0, 1, 7], 11, ZZ) == [4, 0, 0, 4, 6, 0, 1, 3, 5] assert gf_sqr([], 11, ZZ) == [] assert gf_sqr([2], 11, ZZ) == [4] assert gf_sqr([1, 2], 11, ZZ) == [1, 4, 4] assert gf_sqr([2, 0, 0, 1, 7], 11, ZZ) == [4, 0, 0, 4, 6, 0, 1, 3, 5] def test_gf_division(): raises(ZeroDivisionError, lambda: gf_div([1, 2, 3], [], 11, ZZ)) raises(ZeroDivisionError, lambda: gf_rem([1, 2, 3], [], 11, ZZ)) raises(ZeroDivisionError, lambda: gf_quo([1, 2, 3], [], 11, ZZ)) raises(ZeroDivisionError, lambda: gf_quo([1, 2, 3], [], 11, ZZ)) assert gf_div([1], [1, 2, 3], 7, ZZ) == ([], [1]) assert gf_rem([1], [1, 2, 3], 7, ZZ) == [1] assert gf_quo([1], [1, 2, 3], 7, ZZ) == [] f = ZZ.map([5, 4, 3, 2, 1, 0]) g = ZZ.map([1, 2, 3]) q = [5, 1, 0, 6] r = [3, 3] assert gf_div(f, g, 7, ZZ) == (q, r) assert gf_rem(f, g, 7, ZZ) == r assert gf_quo(f, g, 7, ZZ) == q raises(ExactQuotientFailed, lambda: gf_exquo(f, g, 7, ZZ)) f = ZZ.map([5, 4, 3, 2, 1, 0]) g = ZZ.map([1, 2, 3, 0]) q = [5, 1, 0] r = [6, 1, 0] assert gf_div(f, g, 7, ZZ) == (q, r) assert gf_rem(f, g, 7, ZZ) == r assert gf_quo(f, g, 7, ZZ) == q raises(ExactQuotientFailed, lambda: gf_exquo(f, g, 7, ZZ)) assert gf_quo(ZZ.map([1, 2, 1]), ZZ.map([1, 1]), 11, ZZ) == [1, 1] def test_gf_shift(): f = [1, 2, 3, 4, 5] assert gf_lshift([], 5, ZZ) == [] assert gf_rshift([], 5, ZZ) == ([], []) assert gf_lshift(f, 1, ZZ) == [1, 2, 3, 4, 5, 0] assert gf_lshift(f, 2, ZZ) == [1, 2, 3, 4, 5, 0, 0] assert gf_rshift(f, 0, ZZ) == (f, []) assert gf_rshift(f, 1, ZZ) == ([1, 2, 3, 4], [5]) assert gf_rshift(f, 3, ZZ) == ([1, 2], [3, 4, 5]) assert gf_rshift(f, 5, ZZ) == ([], f) def test_gf_expand(): F = [([1, 1], 2), ([1, 2], 3)] assert gf_expand(F, 11, ZZ) == [1, 8, 3, 5, 6, 8] assert gf_expand((4, F), 11, ZZ) == [4, 10, 1, 9, 2, 10] def test_gf_powering(): assert gf_pow([1, 0, 0, 1, 8], 0, 11, ZZ) == [1] assert gf_pow([1, 0, 0, 1, 8], 1, 11, ZZ) == [1, 0, 0, 1, 8] assert gf_pow([1, 0, 0, 1, 8], 2, 11, ZZ) == [1, 0, 0, 2, 5, 0, 1, 5, 9] assert gf_pow([1, 0, 0, 1, 8], 5, 11, ZZ) == \ [1, 0, 0, 5, 7, 0, 10, 6, 2, 10, 9, 6, 10, 6, 6, 0, 5, 2, 5, 9, 10] assert gf_pow([1, 0, 0, 1, 8], 8, 11, ZZ) == \ [1, 0, 0, 8, 9, 0, 6, 8, 10, 1, 2, 5, 10, 7, 7, 9, 1, 2, 0, 0, 6, 2, 5, 2, 5, 7, 7, 9, 10, 10, 7, 5, 5] assert gf_pow([1, 0, 0, 1, 8], 45, 11, ZZ) == \ [ 1, 0, 0, 1, 8, 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, 4, 0, 0, 4, 10, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 6, 4, 0, 0, 0, 0, 0, 0, 8, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 10, 0, 0, 0, 0, 0, 0, 8, 0, 0, 8, 9, 0, 0, 0, 0, 0, 0, 9, 0, 0, 9, 6, 0, 0, 0, 0, 0, 0, 3, 0, 0, 3, 2, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 10, 0, 0, 10, 3, 0, 0, 0, 0, 0, 0, 2, 0, 0, 2, 5, 0, 0, 0, 0, 0, 0, 4, 0, 0, 4, 10] assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 0, ZZ.map([2, 0, 7]), 11, ZZ) == [1] assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 1, ZZ.map([2, 0, 7]), 11, ZZ) == [1, 1] assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 2, ZZ.map([2, 0, 7]), 11, ZZ) == [2, 3] assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 5, ZZ.map([2, 0, 7]), 11, ZZ) == [7, 8] assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 8, ZZ.map([2, 0, 7]), 11, ZZ) == [1, 5] assert gf_pow_mod(ZZ.map([1, 0, 0, 1, 8]), 45, ZZ.map([2, 0, 7]), 11, ZZ) == [5, 4] def test_gf_gcdex(): assert gf_gcdex(ZZ.map([]), ZZ.map([]), 11, ZZ) == ([1], [], []) assert gf_gcdex(ZZ.map([2]), ZZ.map([]), 11, ZZ) == ([6], [], [1]) assert gf_gcdex(ZZ.map([]), ZZ.map([2]), 11, ZZ) == ([], [6], [1]) assert gf_gcdex(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == ([], [6], [1]) assert gf_gcdex(ZZ.map([]), ZZ.map([3, 0]), 11, ZZ) == ([], [4], [1, 0]) assert gf_gcdex(ZZ.map([3, 0]), ZZ.map([]), 11, ZZ) == ([4], [], [1, 0]) assert gf_gcdex(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == ([], [4], [1, 0]) assert gf_gcdex(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == ([5, 6], [6], [1, 7]) def test_gf_gcd(): assert gf_gcd(ZZ.map([]), ZZ.map([]), 11, ZZ) == [] assert gf_gcd(ZZ.map([2]), ZZ.map([]), 11, ZZ) == [1] assert gf_gcd(ZZ.map([]), ZZ.map([2]), 11, ZZ) == [1] assert gf_gcd(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == [1] assert gf_gcd(ZZ.map([]), ZZ.map([1, 0]), 11, ZZ) == [1, 0] assert gf_gcd(ZZ.map([1, 0]), ZZ.map([]), 11, ZZ) == [1, 0] assert gf_gcd(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == [1, 0] assert gf_gcd(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == [1, 7] def test_gf_lcm(): assert gf_lcm(ZZ.map([]), ZZ.map([]), 11, ZZ) == [] assert gf_lcm(ZZ.map([2]), ZZ.map([]), 11, ZZ) == [] assert gf_lcm(ZZ.map([]), ZZ.map([2]), 11, ZZ) == [] assert gf_lcm(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == [1] assert gf_lcm(ZZ.map([]), ZZ.map([1, 0]), 11, ZZ) == [] assert gf_lcm(ZZ.map([1, 0]), ZZ.map([]), 11, ZZ) == [] assert gf_lcm(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == [1, 0] assert gf_lcm(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == [1, 8, 8, 8, 7] def test_gf_cofactors(): assert gf_cofactors(ZZ.map([]), ZZ.map([]), 11, ZZ) == ([], [], []) assert gf_cofactors(ZZ.map([2]), ZZ.map([]), 11, ZZ) == ([1], [2], []) assert gf_cofactors(ZZ.map([]), ZZ.map([2]), 11, ZZ) == ([1], [], [2]) assert gf_cofactors(ZZ.map([2]), ZZ.map([2]), 11, ZZ) == ([1], [2], [2]) assert gf_cofactors(ZZ.map([]), ZZ.map([1, 0]), 11, ZZ) == ([1, 0], [], [1]) assert gf_cofactors(ZZ.map([1, 0]), ZZ.map([]), 11, ZZ) == ([1, 0], [1], []) assert gf_cofactors(ZZ.map([3, 0]), ZZ.map([3, 0]), 11, ZZ) == ( [1, 0], [3], [3]) assert gf_cofactors(ZZ.map([1, 8, 7]), ZZ.map([1, 7, 1, 7]), 11, ZZ) == ( ([1, 7], [1, 1], [1, 0, 1])) def test_gf_diff(): assert gf_diff([], 11, ZZ) == [] assert gf_diff([7], 11, ZZ) == [] assert gf_diff([7, 3], 11, ZZ) == [7] assert gf_diff([7, 3, 1], 11, ZZ) == [3, 3] assert gf_diff([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], 11, ZZ) == [] def test_gf_eval(): assert gf_eval([], 4, 11, ZZ) == 0 assert gf_eval([], 27, 11, ZZ) == 0 assert gf_eval([7], 4, 11, ZZ) == 7 assert gf_eval([7], 27, 11, ZZ) == 7 assert gf_eval([1, 0, 3, 2, 4, 3, 1, 2, 0], 0, 11, ZZ) == 0 assert gf_eval([1, 0, 3, 2, 4, 3, 1, 2, 0], 4, 11, ZZ) == 9 assert gf_eval([1, 0, 3, 2, 4, 3, 1, 2, 0], 27, 11, ZZ) == 5 assert gf_eval([4, 0, 0, 4, 6, 0, 1, 3, 5], 0, 11, ZZ) == 5 assert gf_eval([4, 0, 0, 4, 6, 0, 1, 3, 5], 4, 11, ZZ) == 3 assert gf_eval([4, 0, 0, 4, 6, 0, 1, 3, 5], 27, 11, ZZ) == 9 assert gf_multi_eval([3, 2, 1], [0, 1, 2, 3], 11, ZZ) == [1, 6, 6, 1] def test_gf_compose(): assert gf_compose([], [1, 0], 11, ZZ) == [] assert gf_compose_mod([], [1, 0], [1, 0], 11, ZZ) == [] assert gf_compose([1], [], 11, ZZ) == [1] assert gf_compose([1, 0], [], 11, ZZ) == [] assert gf_compose([1, 0], [1, 0], 11, ZZ) == [1, 0] f = ZZ.map([1, 1, 4, 9, 1]) g = ZZ.map([1, 1, 1]) h = ZZ.map([1, 0, 0, 2]) assert gf_compose(g, h, 11, ZZ) == [1, 0, 0, 5, 0, 0, 7] assert gf_compose_mod(g, h, f, 11, ZZ) == [3, 9, 6, 10] def test_gf_trace_map(): f = ZZ.map([1, 1, 4, 9, 1]) a = [1, 1, 1] c = ZZ.map([1, 0]) b = gf_pow_mod(c, 11, f, 11, ZZ) assert gf_trace_map(a, b, c, 0, f, 11, ZZ) == \ ([1, 1, 1], [1, 1, 1]) assert gf_trace_map(a, b, c, 1, f, 11, ZZ) == \ ([5, 2, 10, 3], [5, 3, 0, 4]) assert gf_trace_map(a, b, c, 2, f, 11, ZZ) == \ ([5, 9, 5, 3], [10, 1, 5, 7]) assert gf_trace_map(a, b, c, 3, f, 11, ZZ) == \ ([1, 10, 6, 0], [7]) assert gf_trace_map(a, b, c, 4, f, 11, ZZ) == \ ([1, 1, 1], [1, 1, 8]) assert gf_trace_map(a, b, c, 5, f, 11, ZZ) == \ ([5, 2, 10, 3], [5, 3, 0, 0]) assert gf_trace_map(a, b, c, 11, f, 11, ZZ) == \ ([1, 10, 6, 0], [10]) def test_gf_irreducible(): assert gf_irreducible_p(gf_irreducible(1, 11, ZZ), 11, ZZ) is True assert gf_irreducible_p(gf_irreducible(2, 11, ZZ), 11, ZZ) is True assert gf_irreducible_p(gf_irreducible(3, 11, ZZ), 11, ZZ) is True assert gf_irreducible_p(gf_irreducible(4, 11, ZZ), 11, ZZ) is True assert gf_irreducible_p(gf_irreducible(5, 11, ZZ), 11, ZZ) is True assert gf_irreducible_p(gf_irreducible(6, 11, ZZ), 11, ZZ) is True assert gf_irreducible_p(gf_irreducible(7, 11, ZZ), 11, ZZ) is True def test_gf_irreducible_p(): assert gf_irred_p_ben_or(ZZ.map([7]), 11, ZZ) is True assert gf_irred_p_ben_or(ZZ.map([7, 3]), 11, ZZ) is True assert gf_irred_p_ben_or(ZZ.map([7, 3, 1]), 11, ZZ) is False assert gf_irred_p_rabin(ZZ.map([7]), 11, ZZ) is True assert gf_irred_p_rabin(ZZ.map([7, 3]), 11, ZZ) is True assert gf_irred_p_rabin(ZZ.map([7, 3, 1]), 11, ZZ) is False config.setup('GF_IRRED_METHOD', 'ben-or') assert gf_irreducible_p(ZZ.map([7]), 11, ZZ) is True assert gf_irreducible_p(ZZ.map([7, 3]), 11, ZZ) is True assert gf_irreducible_p(ZZ.map([7, 3, 1]), 11, ZZ) is False config.setup('GF_IRRED_METHOD', 'rabin') assert gf_irreducible_p(ZZ.map([7]), 11, ZZ) is True assert gf_irreducible_p(ZZ.map([7, 3]), 11, ZZ) is True assert gf_irreducible_p(ZZ.map([7, 3, 1]), 11, ZZ) is False config.setup('GF_IRRED_METHOD', 'other') raises(KeyError, lambda: gf_irreducible_p([7], 11, ZZ)) config.setup('GF_IRRED_METHOD') f = ZZ.map([1, 9, 9, 13, 16, 15, 6, 7, 7, 7, 10]) g = ZZ.map([1, 7, 16, 7, 15, 13, 13, 11, 16, 10, 9]) h = gf_mul(f, g, 17, ZZ) assert gf_irred_p_ben_or(f, 17, ZZ) is True assert gf_irred_p_ben_or(g, 17, ZZ) is True assert gf_irred_p_ben_or(h, 17, ZZ) is False assert gf_irred_p_rabin(f, 17, ZZ) is True assert gf_irred_p_rabin(g, 17, ZZ) is True assert gf_irred_p_rabin(h, 17, ZZ) is False def test_gf_squarefree(): assert gf_sqf_list([], 11, ZZ) == (0, []) assert gf_sqf_list([1], 11, ZZ) == (1, []) assert gf_sqf_list([1, 1], 11, ZZ) == (1, [([1, 1], 1)]) assert gf_sqf_p([], 11, ZZ) is True assert gf_sqf_p([1], 11, ZZ) is True assert gf_sqf_p([1, 1], 11, ZZ) is True f = gf_from_dict({11: 1, 0: 1}, 11, ZZ) assert gf_sqf_p(f, 11, ZZ) is False assert gf_sqf_list(f, 11, ZZ) == \ (1, [([1, 1], 11)]) f = [1, 5, 8, 4] assert gf_sqf_p(f, 11, ZZ) is False assert gf_sqf_list(f, 11, ZZ) == \ (1, [([1, 1], 1), ([1, 2], 2)]) assert gf_sqf_part(f, 11, ZZ) == [1, 3, 2] f = [1, 0, 0, 2, 0, 0, 2, 0, 0, 1, 0] assert gf_sqf_list(f, 3, ZZ) == \ (1, [([1, 0], 1), ([1, 1], 3), ([1, 2], 6)]) def test_gf_frobenius_map(): f = ZZ.map([2, 0, 1, 0, 2, 2, 0, 2, 2, 2]) g = ZZ.map([1,1,0,2,0,1,0,2,0,1]) p = 3 b = gf_frobenius_monomial_base(g, p, ZZ) h = gf_frobenius_map(f, g, b, p, ZZ) h1 = gf_pow_mod(f, p, g, p, ZZ) assert h == h1 def test_gf_berlekamp(): f = gf_from_int_poly([1, -3, 1, -3, -1, -3, 1], 11) Q = [[1, 0, 0, 0, 0, 0], [3, 5, 8, 8, 6, 5], [3, 6, 6, 1, 10, 0], [9, 4, 10, 3, 7, 9], [7, 8, 10, 0, 0, 8], [8, 10, 7, 8, 10, 8]] V = [[1, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 0], [0, 0, 7, 9, 0, 1]] assert gf_Qmatrix(f, 11, ZZ) == Q assert gf_Qbasis(Q, 11, ZZ) == V assert gf_berlekamp(f, 11, ZZ) == \ [[1, 1], [1, 5, 3], [1, 2, 3, 4]] f = ZZ.map([1, 0, 1, 0, 10, 10, 8, 2, 8]) Q = ZZ.map([[1, 0, 0, 0, 0, 0, 0, 0], [2, 1, 7, 11, 10, 12, 5, 11], [3, 6, 4, 3, 0, 4, 7, 2], [4, 3, 6, 5, 1, 6, 2, 3], [2, 11, 8, 8, 3, 1, 3, 11], [6, 11, 8, 6, 2, 7, 10, 9], [5, 11, 7, 10, 0, 11, 7, 12], [3, 3, 12, 5, 0, 11, 9, 12]]) V = [[1, 0, 0, 0, 0, 0, 0, 0], [0, 5, 5, 0, 9, 5, 1, 0], [0, 9, 11, 9, 10, 12, 0, 1]] assert gf_Qmatrix(f, 13, ZZ) == Q assert gf_Qbasis(Q, 13, ZZ) == V assert gf_berlekamp(f, 13, ZZ) == \ [[1, 3], [1, 8, 4, 12], [1, 2, 3, 4, 6]] def test_gf_ddf(): f = gf_from_dict({15: ZZ(1), 0: ZZ(-1)}, 11, ZZ) g = [([1, 0, 0, 0, 0, 10], 1), ([1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1], 2)] assert gf_ddf_zassenhaus(f, 11, ZZ) == g assert gf_ddf_shoup(f, 11, ZZ) == g f = gf_from_dict({63: ZZ(1), 0: ZZ(1)}, 2, ZZ) g = [([1, 1], 1), ([1, 1, 1], 2), ([1, 1, 1, 1, 1, 1, 1], 3), ([1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1], 6)] assert gf_ddf_zassenhaus(f, 2, ZZ) == g assert gf_ddf_shoup(f, 2, ZZ) == g f = gf_from_dict({6: ZZ(1), 5: ZZ(-1), 4: ZZ(1), 3: ZZ(1), 1: ZZ(-1)}, 3, ZZ) g = [([1, 1, 0], 1), ([1, 1, 0, 1, 2], 2)] assert gf_ddf_zassenhaus(f, 3, ZZ) == g assert gf_ddf_shoup(f, 3, ZZ) == g f = ZZ.map([1, 2, 5, 26, 677, 436, 791, 325, 456, 24, 577]) g = [([1, 701], 1), ([1, 110, 559, 532, 694, 151, 110, 70, 735, 122], 9)] assert gf_ddf_zassenhaus(f, 809, ZZ) == g assert gf_ddf_shoup(f, 809, ZZ) == g p = ZZ(nextprime(int((2**15 * pi).evalf()))) f = gf_from_dict({15: 1, 1: 1, 0: 1}, p, ZZ) g = [([1, 22730, 68144], 2), ([1, 64876, 83977, 10787, 12561, 68608, 52650, 88001, 84356], 4), ([1, 15347, 95022, 84569, 94508, 92335], 5)] assert gf_ddf_zassenhaus(f, p, ZZ) == g assert gf_ddf_shoup(f, p, ZZ) == g def test_gf_edf(): f = ZZ.map([1, 1, 0, 1, 2]) g = ZZ.map([[1, 0, 1], [1, 1, 2]]) assert gf_edf_zassenhaus(f, 2, 3, ZZ) == g assert gf_edf_shoup(f, 2, 3, ZZ) == g def test_gf_factor(): assert gf_factor([], 11, ZZ) == (0, []) assert gf_factor([1], 11, ZZ) == (1, []) assert gf_factor([1, 1], 11, ZZ) == (1, [([1, 1], 1)]) assert gf_factor_sqf([], 11, ZZ) == (0, []) assert gf_factor_sqf([1], 11, ZZ) == (1, []) assert gf_factor_sqf([1, 1], 11, ZZ) == (1, [[1, 1]]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor_sqf([], 11, ZZ) == (0, []) assert gf_factor_sqf([1], 11, ZZ) == (1, []) assert gf_factor_sqf([1, 1], 11, ZZ) == (1, [[1, 1]]) config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor_sqf([], 11, ZZ) == (0, []) assert gf_factor_sqf([1], 11, ZZ) == (1, []) assert gf_factor_sqf([1, 1], 11, ZZ) == (1, [[1, 1]]) config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor_sqf(ZZ.map([]), 11, ZZ) == (0, []) assert gf_factor_sqf(ZZ.map([1]), 11, ZZ) == (1, []) assert gf_factor_sqf(ZZ.map([1, 1]), 11, ZZ) == (1, [[1, 1]]) f, p = ZZ.map([1, 0, 0, 1, 0]), 2 g = (1, [([1, 0], 1), ([1, 1], 1), ([1, 1, 1], 1)]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g g = (1, [[1, 0], [1, 1], [1, 1, 1]]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor_sqf(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor_sqf(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor_sqf(f, p, ZZ) == g f, p = gf_from_int_poly([1, -3, 1, -3, -1, -3, 1], 11), 11 g = (1, [([1, 1], 1), ([1, 5, 3], 1), ([1, 2, 3, 4], 1)]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g f, p = [1, 5, 8, 4], 11 g = (1, [([1, 1], 1), ([1, 2], 2)]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g f, p = [1, 1, 10, 1, 0, 10, 10, 10, 0, 0], 11 g = (1, [([1, 0], 2), ([1, 9, 5], 1), ([1, 3, 0, 8, 5, 2], 1)]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g f, p = gf_from_dict({32: 1, 0: 1}, 11, ZZ), 11 g = (1, [([1, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0, 10], 1), ([1, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 10], 1)]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g f, p = gf_from_dict({32: ZZ(8), 0: ZZ(5)}, 11, ZZ), 11 g = (8, [([1, 3], 1), ([1, 8], 1), ([1, 0, 9], 1), ([1, 2, 2], 1), ([1, 9, 2], 1), ([1, 0, 5, 0, 7], 1), ([1, 0, 6, 0, 7], 1), ([1, 0, 0, 0, 1, 0, 0, 0, 6], 1), ([1, 0, 0, 0, 10, 0, 0, 0, 6], 1)]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g f, p = gf_from_dict({63: ZZ(8), 0: ZZ(5)}, 11, ZZ), 11 g = (8, [([1, 7], 1), ([1, 4, 5], 1), ([1, 6, 8, 2], 1), ([1, 9, 9, 2], 1), ([1, 0, 0, 9, 0, 0, 4], 1), ([1, 2, 0, 8, 4, 6, 4], 1), ([1, 2, 3, 8, 0, 6, 4], 1), ([1, 2, 6, 0, 8, 4, 4], 1), ([1, 3, 3, 1, 6, 8, 4], 1), ([1, 5, 6, 0, 8, 6, 4], 1), ([1, 6, 2, 7, 9, 8, 4], 1), ([1, 10, 4, 7, 10, 7, 4], 1), ([1, 10, 10, 1, 4, 9, 4], 1)]) config.setup('GF_FACTOR_METHOD', 'berlekamp') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g # Gathen polynomials: x**n + x + 1 (mod p > 2**n * pi) p = ZZ(nextprime(int((2**15 * pi).evalf()))) f = gf_from_dict({15: 1, 1: 1, 0: 1}, p, ZZ) assert gf_sqf_p(f, p, ZZ) is True g = (1, [([1, 22730, 68144], 1), ([1, 81553, 77449, 86810, 4724], 1), ([1, 86276, 56779, 14859, 31575], 1), ([1, 15347, 95022, 84569, 94508, 92335], 1)]) config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g g = (1, [[1, 22730, 68144], [1, 81553, 77449, 86810, 4724], [1, 86276, 56779, 14859, 31575], [1, 15347, 95022, 84569, 94508, 92335]]) config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor_sqf(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor_sqf(f, p, ZZ) == g # Shoup polynomials: f = a_0 x**n + a_1 x**(n-1) + ... + a_n # (mod p > 2**(n-2) * pi), where a_n = a_{n-1}**2 + 1, a_0 = 1 p = ZZ(nextprime(int((2**4 * pi).evalf()))) f = ZZ.map([1, 2, 5, 26, 41, 39, 38]) assert gf_sqf_p(f, p, ZZ) is True g = (1, [([1, 44, 26], 1), ([1, 11, 25, 18, 30], 1)]) config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor(f, p, ZZ) == g g = (1, [[1, 44, 26], [1, 11, 25, 18, 30]]) config.setup('GF_FACTOR_METHOD', 'zassenhaus') assert gf_factor_sqf(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'shoup') assert gf_factor_sqf(f, p, ZZ) == g config.setup('GF_FACTOR_METHOD', 'other') raises(KeyError, lambda: gf_factor([1, 1], 11, ZZ)) config.setup('GF_FACTOR_METHOD') def test_gf_csolve(): assert gf_value([1, 7, 2, 4], 11) == 2204 assert linear_congruence(4, 3, 5) == [2] assert linear_congruence(0, 3, 5) == [] assert linear_congruence(6, 1, 4) == [] assert linear_congruence(0, 5, 5) == [0, 1, 2, 3, 4] assert linear_congruence(3, 12, 15) == [4, 9, 14] assert linear_congruence(6, 0, 18) == [0, 3, 6, 9, 12, 15] # with power = 1 assert csolve_prime([1, 3, 2, 17], 7) == [3] assert csolve_prime([1, 3, 1, 5], 5) == [0, 1] assert csolve_prime([3, 6, 9, 3], 3) == [0, 1, 2] # with power > 1 assert csolve_prime( [1, 1, 223], 3, 4) == [4, 13, 22, 31, 40, 49, 58, 67, 76] assert csolve_prime([3, 5, 2, 25], 5, 3) == [16, 50, 99] assert csolve_prime([3, 2, 2, 49], 7, 3) == [147, 190, 234] assert gf_csolve([1, 1, 7], 189) == [13, 49, 76, 112, 139, 175] assert gf_csolve([1, 3, 4, 1, 30], 60) == [10, 30] assert gf_csolve([1, 1, 7], 15) == [] sympy-sympy-1.9/sympy/polys/tests/test_groebnertools.py000066400000000000000000000442301412543434000237140ustar00rootroot00000000000000"""Tests for Groebner bases. """ from sympy.polys.groebnertools import ( groebner, sig, sig_key, lbp, lbp_key, critical_pair, cp_key, is_rewritable_or_comparable, Sign, Polyn, Num, s_poly, f5_reduce, groebner_lcm, groebner_gcd, is_groebner, is_reduced ) from sympy.polys.fglmtools import _representing_matrices from sympy.polys.orderings import lex, grlex from sympy.polys.rings import ring, xring from sympy.polys.domains import ZZ, QQ from sympy.testing.pytest import slow from sympy.polys import polyconfig as config def _do_test_groebner(): R, x,y = ring("x,y", QQ, lex) f = x**2 + 2*x*y**2 g = x*y + 2*y**3 - 1 assert groebner([f, g], R) == [x, y**3 - QQ(1,2)] R, y,x = ring("y,x", QQ, lex) f = 2*x**2*y + y**2 g = 2*x**3 + x*y - 1 assert groebner([f, g], R) == [y, x**3 - QQ(1,2)] R, x,y,z = ring("x,y,z", QQ, lex) f = x - z**2 g = y - z**3 assert groebner([f, g], R) == [f, g] R, x,y = ring("x,y", QQ, grlex) f = x**3 - 2*x*y g = x**2*y + x - 2*y**2 assert groebner([f, g], R) == [x**2, x*y, -QQ(1,2)*x + y**2] R, x,y,z = ring("x,y,z", QQ, lex) f = -x**2 + y g = -x**3 + z assert groebner([f, g], R) == [x**2 - y, x*y - z, x*z - y**2, y**3 - z**2] R, x,y,z = ring("x,y,z", QQ, grlex) f = -x**2 + y g = -x**3 + z assert groebner([f, g], R) == [y**3 - z**2, x**2 - y, x*y - z, x*z - y**2] R, x,y,z = ring("x,y,z", QQ, lex) f = -x**2 + z g = -x**3 + y assert groebner([f, g], R) == [x**2 - z, x*y - z**2, x*z - y, y**2 - z**3] R, x,y,z = ring("x,y,z", QQ, grlex) f = -x**2 + z g = -x**3 + y assert groebner([f, g], R) == [-y**2 + z**3, x**2 - z, x*y - z**2, x*z - y] R, x,y,z = ring("x,y,z", QQ, lex) f = x - y**2 g = -y**3 + z assert groebner([f, g], R) == [x - y**2, y**3 - z] R, x,y,z = ring("x,y,z", QQ, grlex) f = x - y**2 g = -y**3 + z assert groebner([f, g], R) == [x**2 - y*z, x*y - z, -x + y**2] R, x,y,z = ring("x,y,z", QQ, lex) f = x - z**2 g = y - z**3 assert groebner([f, g], R) == [x - z**2, y - z**3] R, x,y,z = ring("x,y,z", QQ, grlex) f = x - z**2 g = y - z**3 assert groebner([f, g], R) == [x**2 - y*z, x*z - y, -x + z**2] R, x,y,z = ring("x,y,z", QQ, lex) f = -y**2 + z g = x - y**3 assert groebner([f, g], R) == [x - y*z, y**2 - z] R, x,y,z = ring("x,y,z", QQ, grlex) f = -y**2 + z g = x - y**3 assert groebner([f, g], R) == [-x**2 + z**3, x*y - z**2, y**2 - z, -x + y*z] R, x,y,z = ring("x,y,z", QQ, lex) f = y - z**2 g = x - z**3 assert groebner([f, g], R) == [x - z**3, y - z**2] R, x,y,z = ring("x,y,z", QQ, grlex) f = y - z**2 g = x - z**3 assert groebner([f, g], R) == [-x**2 + y**3, x*z - y**2, -x + y*z, -y + z**2] R, x,y,z = ring("x,y,z", QQ, lex) f = 4*x**2*y**2 + 4*x*y + 1 g = x**2 + y**2 - 1 assert groebner([f, g], R) == [ x - 4*y**7 + 8*y**5 - 7*y**3 + 3*y, y**8 - 2*y**6 + QQ(3,2)*y**4 - QQ(1,2)*y**2 + QQ(1,16), ] def test_groebner_buchberger(): with config.using(groebner='buchberger'): _do_test_groebner() def test_groebner_f5b(): with config.using(groebner='f5b'): _do_test_groebner() def _do_test_benchmark_minpoly(): R, x,y,z = ring("x,y,z", QQ, lex) F = [x**3 + x + 1, y**2 + y + 1, (x + y) * z - (x**2 + y)] G = [x + QQ(155,2067)*z**5 - QQ(355,689)*z**4 + QQ(6062,2067)*z**3 - QQ(3687,689)*z**2 + QQ(6878,2067)*z - QQ(25,53), y + QQ(4,53)*z**5 - QQ(91,159)*z**4 + QQ(523,159)*z**3 - QQ(387,53)*z**2 + QQ(1043,159)*z - QQ(308,159), z**6 - 7*z**5 + 41*z**4 - 82*z**3 + 89*z**2 - 46*z + 13] assert groebner(F, R) == G def test_benchmark_minpoly_buchberger(): with config.using(groebner='buchberger'): _do_test_benchmark_minpoly() def test_benchmark_minpoly_f5b(): with config.using(groebner='f5b'): _do_test_benchmark_minpoly() def test_benchmark_coloring(): V = range(1, 12 + 1) E = [(1, 2), (2, 3), (1, 4), (1, 6), (1, 12), (2, 5), (2, 7), (3, 8), (3, 10), (4, 11), (4, 9), (5, 6), (6, 7), (7, 8), (8, 9), (9, 10), (10, 11), (11, 12), (5, 12), (5, 9), (6, 10), (7, 11), (8, 12), (3, 4)] R, V = xring([ "x%d" % v for v in V ], QQ, lex) E = [(V[i - 1], V[j - 1]) for i, j in E] x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12 = V I3 = [x**3 - 1 for x in V] Ig = [x**2 + x*y + y**2 for x, y in E] I = I3 + Ig assert groebner(I[:-1], R) == [ x1 + x11 + x12, x2 - x11, x3 - x12, x4 - x12, x5 + x11 + x12, x6 - x11, x7 - x12, x8 + x11 + x12, x9 - x11, x10 + x11 + x12, x11**2 + x11*x12 + x12**2, x12**3 - 1, ] assert groebner(I, R) == [1] def _do_test_benchmark_katsura_3(): R, x0,x1,x2 = ring("x:3", ZZ, lex) I = [x0 + 2*x1 + 2*x2 - 1, x0**2 + 2*x1**2 + 2*x2**2 - x0, 2*x0*x1 + 2*x1*x2 - x1] assert groebner(I, R) == [ -7 + 7*x0 + 8*x2 + 158*x2**2 - 420*x2**3, 7*x1 + 3*x2 - 79*x2**2 + 210*x2**3, x2 + x2**2 - 40*x2**3 + 84*x2**4, ] R, x0,x1,x2 = ring("x:3", ZZ, grlex) I = [ i.set_ring(R) for i in I ] assert groebner(I, R) == [ 7*x1 + 3*x2 - 79*x2**2 + 210*x2**3, -x1 + x2 - 3*x2**2 + 5*x1**2, -x1 - 4*x2 + 10*x1*x2 + 12*x2**2, -1 + x0 + 2*x1 + 2*x2, ] def test_benchmark_katsura3_buchberger(): with config.using(groebner='buchberger'): _do_test_benchmark_katsura_3() def test_benchmark_katsura3_f5b(): with config.using(groebner='f5b'): _do_test_benchmark_katsura_3() def _do_test_benchmark_katsura_4(): R, x0,x1,x2,x3 = ring("x:4", ZZ, lex) I = [x0 + 2*x1 + 2*x2 + 2*x3 - 1, x0**2 + 2*x1**2 + 2*x2**2 + 2*x3**2 - x0, 2*x0*x1 + 2*x1*x2 + 2*x2*x3 - x1, x1**2 + 2*x0*x2 + 2*x1*x3 - x2] assert groebner(I, R) == [ 5913075*x0 - 159690237696*x3**7 + 31246269696*x3**6 + 27439610544*x3**5 - 6475723368*x3**4 - 838935856*x3**3 + 275119624*x3**2 + 4884038*x3 - 5913075, 1971025*x1 - 97197721632*x3**7 + 73975630752*x3**6 - 12121915032*x3**5 - 2760941496*x3**4 + 814792828*x3**3 - 1678512*x3**2 - 9158924*x3, 5913075*x2 + 371438283744*x3**7 - 237550027104*x3**6 + 22645939824*x3**5 + 11520686172*x3**4 - 2024910556*x3**3 - 132524276*x3**2 + 30947828*x3, 128304*x3**8 - 93312*x3**7 + 15552*x3**6 + 3144*x3**5 - 1120*x3**4 + 36*x3**3 + 15*x3**2 - x3, ] R, x0,x1,x2,x3 = ring("x:4", ZZ, grlex) I = [ i.set_ring(R) for i in I ] assert groebner(I, R) == [ 393*x1 - 4662*x2**2 + 4462*x2*x3 - 59*x2 + 224532*x3**4 - 91224*x3**3 - 678*x3**2 + 2046*x3, -x1 + 196*x2**3 - 21*x2**2 + 60*x2*x3 - 18*x2 - 168*x3**3 + 83*x3**2 - 9*x3, -6*x1 + 1134*x2**2*x3 - 189*x2**2 - 466*x2*x3 + 32*x2 - 630*x3**3 + 57*x3**2 + 51*x3, 33*x1 + 63*x2**2 + 2268*x2*x3**2 - 188*x2*x3 + 34*x2 + 2520*x3**3 - 849*x3**2 + 3*x3, 7*x1**2 - x1 - 7*x2**2 - 24*x2*x3 + 3*x2 - 15*x3**2 + 5*x3, 14*x1*x2 - x1 + 14*x2**2 + 18*x2*x3 - 4*x2 + 6*x3**2 - 2*x3, 14*x1*x3 - x1 + 7*x2**2 + 32*x2*x3 - 4*x2 + 27*x3**2 - 9*x3, x0 + 2*x1 + 2*x2 + 2*x3 - 1, ] def test_benchmark_kastura_4_buchberger(): with config.using(groebner='buchberger'): _do_test_benchmark_katsura_4() def test_benchmark_kastura_4_f5b(): with config.using(groebner='f5b'): _do_test_benchmark_katsura_4() def _do_test_benchmark_czichowski(): R, x,t = ring("x,t", ZZ, lex) I = [9*x**8 + 36*x**7 - 32*x**6 - 252*x**5 - 78*x**4 + 468*x**3 + 288*x**2 - 108*x + 9, (-72 - 72*t)*x**7 + (-256 - 252*t)*x**6 + (192 + 192*t)*x**5 + (1280 + 1260*t)*x**4 + (312 + 312*t)*x**3 + (-404*t)*x**2 + (-576 - 576*t)*x + 96 + 108*t] assert groebner(I, R) == [ 3725588592068034903797967297424801242396746870413359539263038139343329273586196480000*x - 160420835591776763325581422211936558925462474417709511019228211783493866564923546661604487873*t**7 - 1406108495478033395547109582678806497509499966197028487131115097902188374051595011248311352864*t**6 - 5241326875850889518164640374668786338033653548841427557880599579174438246266263602956254030352*t**5 - 10758917262823299139373269714910672770004760114329943852726887632013485035262879510837043892416*t**4 - 13119383576444715672578819534846747735372132018341964647712009275306635391456880068261130581248*t**3 - 9491412317016197146080450036267011389660653495578680036574753839055748080962214787557853941760*t**2 - 3767520915562795326943800040277726397326609797172964377014046018280260848046603967211258368000*t - 632314652371226552085897259159210286886724229880266931574701654721512325555116066073245696000, 610733380717522355121*t**8 + 6243748742141230639968*t**7 + 27761407182086143225024*t**6 + 70066148869420956398592*t**5 + 109701225644313784229376*t**4 + 109009005495588442152960*t**3 + 67072101084384786432000*t**2 + 23339979742629593088000*t + 3513592776846090240000, ] R, x,t = ring("x,t", ZZ, grlex) I = [ i.set_ring(R) for i in I ] assert groebner(I, R) == [ 16996618586000601590732959134095643086442*t**3*x - 32936701459297092865176560282688198064839*t**3 + 78592411049800639484139414821529525782364*t**2*x - 120753953358671750165454009478961405619916*t**2 + 120988399875140799712152158915653654637280*t*x - 144576390266626470824138354942076045758736*t + 60017634054270480831259316163620768960*x**2 + 61976058033571109604821862786675242894400*x - 56266268491293858791834120380427754600960, 576689018321912327136790519059646508441672750656050290242749*t**4 + 2326673103677477425562248201573604572527893938459296513327336*t**3 + 110743790416688497407826310048520299245819959064297990236000*t**2*x + 3308669114229100853338245486174247752683277925010505284338016*t**2 + 323150205645687941261103426627818874426097912639158572428800*t*x + 1914335199925152083917206349978534224695445819017286960055680*t + 861662882561803377986838989464278045397192862768588480000*x**2 + 235296483281783440197069672204341465480107019878814196672000*x + 361850798943225141738895123621685122544503614946436727532800, -117584925286448670474763406733005510014188341867*t**3 + 68566565876066068463853874568722190223721653044*t**2*x - 435970731348366266878180788833437896139920683940*t**2 + 196297602447033751918195568051376792491869233408*t*x - 525011527660010557871349062870980202067479780112*t + 517905853447200553360289634770487684447317120*x**3 + 569119014870778921949288951688799397569321920*x**2 + 138877356748142786670127389526667463202210102080*x - 205109210539096046121625447192779783475018619520, -3725142681462373002731339445216700112264527*t**3 + 583711207282060457652784180668273817487940*t**2*x - 12381382393074485225164741437227437062814908*t**2 + 151081054097783125250959636747516827435040*t*x**2 + 1814103857455163948531448580501928933873280*t*x - 13353115629395094645843682074271212731433648*t + 236415091385250007660606958022544983766080*x**2 + 1390443278862804663728298060085399578417600*x - 4716885828494075789338754454248931750698880, ] # NOTE: This is very slow (> 2 minutes on 3.4 GHz) without GMPY @slow def test_benchmark_czichowski_buchberger(): with config.using(groebner='buchberger'): _do_test_benchmark_czichowski() def test_benchmark_czichowski_f5b(): with config.using(groebner='f5b'): _do_test_benchmark_czichowski() def _do_test_benchmark_cyclic_4(): R, a,b,c,d = ring("a,b,c,d", ZZ, lex) I = [a + b + c + d, a*b + a*d + b*c + b*d, a*b*c + a*b*d + a*c*d + b*c*d, a*b*c*d - 1] assert groebner(I, R) == [ 4*a + 3*d**9 - 4*d**5 - 3*d, 4*b + 4*c - 3*d**9 + 4*d**5 + 7*d, 4*c**2 + 3*d**10 - 4*d**6 - 3*d**2, 4*c*d**4 + 4*c - d**9 + 4*d**5 + 5*d, d**12 - d**8 - d**4 + 1 ] R, a,b,c,d = ring("a,b,c,d", ZZ, grlex) I = [ i.set_ring(R) for i in I ] assert groebner(I, R) == [ 3*b*c - c**2 + d**6 - 3*d**2, -b + 3*c**2*d**3 - c - d**5 - 4*d, -b + 3*c*d**4 + 2*c + 2*d**5 + 2*d, c**4 + 2*c**2*d**2 - d**4 - 2, c**3*d + c*d**3 + d**4 + 1, b*c**2 - c**3 - c**2*d - 2*c*d**2 - d**3, b**2 - c**2, b*d + c**2 + c*d + d**2, a + b + c + d ] def test_benchmark_cyclic_4_buchberger(): with config.using(groebner='buchberger'): _do_test_benchmark_cyclic_4() def test_benchmark_cyclic_4_f5b(): with config.using(groebner='f5b'): _do_test_benchmark_cyclic_4() def test_sig_key(): s1 = sig((0,) * 3, 2) s2 = sig((1,) * 3, 4) s3 = sig((2,) * 3, 2) assert sig_key(s1, lex) > sig_key(s2, lex) assert sig_key(s2, lex) < sig_key(s3, lex) def test_lbp_key(): R, x,y,z,t = ring("x,y,z,t", ZZ, lex) p1 = lbp(sig((0,) * 4, 3), R.zero, 12) p2 = lbp(sig((0,) * 4, 4), R.zero, 13) p3 = lbp(sig((0,) * 4, 4), R.zero, 12) assert lbp_key(p1) > lbp_key(p2) assert lbp_key(p2) < lbp_key(p3) def test_critical_pair(): # from cyclic4 with grlex R, x,y,z,t = ring("x,y,z,t", QQ, grlex) p1 = (((0, 0, 0, 0), 4), y*z*t**2 + z**2*t**2 - t**4 - 1, 4) q1 = (((0, 0, 0, 0), 2), -y**2 - y*t - z*t - t**2, 2) p2 = (((0, 0, 0, 2), 3), z**3*t**2 + z**2*t**3 - z - t, 5) q2 = (((0, 0, 2, 2), 2), y*z + z*t**5 + z*t + t**6, 13) assert critical_pair(p1, q1, R) == ( ((0, 0, 1, 2), 2), ((0, 0, 1, 2), QQ(-1, 1)), (((0, 0, 0, 0), 2), -y**2 - y*t - z*t - t**2, 2), ((0, 1, 0, 0), 4), ((0, 1, 0, 0), QQ(1, 1)), (((0, 0, 0, 0), 4), y*z*t**2 + z**2*t**2 - t**4 - 1, 4) ) assert critical_pair(p2, q2, R) == ( ((0, 0, 4, 2), 2), ((0, 0, 2, 0), QQ(1, 1)), (((0, 0, 2, 2), 2), y*z + z*t**5 + z*t + t**6, 13), ((0, 0, 0, 5), 3), ((0, 0, 0, 3), QQ(1, 1)), (((0, 0, 0, 2), 3), z**3*t**2 + z**2*t**3 - z - t, 5) ) def test_cp_key(): # from cyclic4 with grlex R, x,y,z,t = ring("x,y,z,t", QQ, grlex) p1 = (((0, 0, 0, 0), 4), y*z*t**2 + z**2*t**2 - t**4 - 1, 4) q1 = (((0, 0, 0, 0), 2), -y**2 - y*t - z*t - t**2, 2) p2 = (((0, 0, 0, 2), 3), z**3*t**2 + z**2*t**3 - z - t, 5) q2 = (((0, 0, 2, 2), 2), y*z + z*t**5 + z*t + t**6, 13) cp1 = critical_pair(p1, q1, R) cp2 = critical_pair(p2, q2, R) assert cp_key(cp1, R) < cp_key(cp2, R) cp1 = critical_pair(p1, p2, R) cp2 = critical_pair(q1, q2, R) assert cp_key(cp1, R) < cp_key(cp2, R) def test_is_rewritable_or_comparable(): # from katsura4 with grlex R, x,y,z,t = ring("x,y,z,t", QQ, grlex) p = lbp(sig((0, 0, 2, 1), 2), R.zero, 2) B = [lbp(sig((0, 0, 0, 1), 2), QQ(2,45)*y**2 + QQ(1,5)*y*z + QQ(5,63)*y*t + z**2*t + QQ(4,45)*z**2 + QQ(76,35)*z*t**2 - QQ(32,105)*z*t + QQ(13,7)*t**3 - QQ(13,21)*t**2, 6)] # rewritable: assert is_rewritable_or_comparable(Sign(p), Num(p), B) is True p = lbp(sig((0, 1, 1, 0), 2), R.zero, 7) B = [lbp(sig((0, 0, 0, 0), 3), QQ(10,3)*y*z + QQ(4,3)*y*t - QQ(1,3)*y + 4*z**2 + QQ(22,3)*z*t - QQ(4,3)*z + 4*t**2 - QQ(4,3)*t, 3)] # comparable: assert is_rewritable_or_comparable(Sign(p), Num(p), B) is True def test_f5_reduce(): # katsura3 with lex R, x,y,z = ring("x,y,z", QQ, lex) F = [(((0, 0, 0), 1), x + 2*y + 2*z - 1, 1), (((0, 0, 0), 2), 6*y**2 + 8*y*z - 2*y + 6*z**2 - 2*z, 2), (((0, 0, 0), 3), QQ(10,3)*y*z - QQ(1,3)*y + 4*z**2 - QQ(4,3)*z, 3), (((0, 0, 1), 2), y + 30*z**3 - QQ(79,7)*z**2 + QQ(3,7)*z, 4), (((0, 0, 2), 2), z**4 - QQ(10,21)*z**3 + QQ(1,84)*z**2 + QQ(1,84)*z, 5)] cp = critical_pair(F[0], F[1], R) s = s_poly(cp) assert f5_reduce(s, F) == (((0, 2, 0), 1), R.zero, 1) s = lbp(sig(Sign(s)[0], 100), Polyn(s), Num(s)) assert f5_reduce(s, F) == s def test_representing_matrices(): R, x,y = ring("x,y", QQ, grlex) basis = [(0, 0), (0, 1), (1, 0), (1, 1)] F = [x**2 - x - 3*y + 1, -2*x + y**2 + y - 1] assert _representing_matrices(basis, F, R) == [ [[QQ(0, 1), QQ(0, 1),-QQ(1, 1), QQ(3, 1)], [QQ(0, 1), QQ(0, 1), QQ(3, 1),-QQ(4, 1)], [QQ(1, 1), QQ(0, 1), QQ(1, 1), QQ(6, 1)], [QQ(0, 1), QQ(1, 1), QQ(0, 1), QQ(1, 1)]], [[QQ(0, 1), QQ(1, 1), QQ(0, 1),-QQ(2, 1)], [QQ(1, 1),-QQ(1, 1), QQ(0, 1), QQ(6, 1)], [QQ(0, 1), QQ(2, 1), QQ(0, 1), QQ(3, 1)], [QQ(0, 1), QQ(0, 1), QQ(1, 1),-QQ(1, 1)]]] def test_groebner_lcm(): R, x,y,z = ring("x,y,z", ZZ) assert groebner_lcm(x**2 - y**2, x - y) == x**2 - y**2 assert groebner_lcm(2*x**2 - 2*y**2, 2*x - 2*y) == 2*x**2 - 2*y**2 R, x,y,z = ring("x,y,z", QQ) assert groebner_lcm(x**2 - y**2, x - y) == x**2 - y**2 assert groebner_lcm(2*x**2 - 2*y**2, 2*x - 2*y) == 2*x**2 - 2*y**2 R, x,y = ring("x,y", ZZ) assert groebner_lcm(x**2*y, x*y**2) == x**2*y**2 f = 2*x*y**5 - 3*x*y**4 - 2*x*y**3 + 3*x*y**2 g = y**5 - 2*y**3 + y h = 2*x*y**7 - 3*x*y**6 - 4*x*y**5 + 6*x*y**4 + 2*x*y**3 - 3*x*y**2 assert groebner_lcm(f, g) == h f = x**3 - 3*x**2*y - 9*x*y**2 - 5*y**3 g = x**4 + 6*x**3*y + 12*x**2*y**2 + 10*x*y**3 + 3*y**4 h = x**5 + x**4*y - 18*x**3*y**2 - 50*x**2*y**3 - 47*x*y**4 - 15*y**5 assert groebner_lcm(f, g) == h def test_groebner_gcd(): R, x,y,z = ring("x,y,z", ZZ) assert groebner_gcd(x**2 - y**2, x - y) == x - y assert groebner_gcd(2*x**2 - 2*y**2, 2*x - 2*y) == 2*x - 2*y R, x,y,z = ring("x,y,z", QQ) assert groebner_gcd(x**2 - y**2, x - y) == x - y assert groebner_gcd(2*x**2 - 2*y**2, 2*x - 2*y) == x - y def test_is_groebner(): R, x,y = ring("x,y", QQ, grlex) valid_groebner = [x**2, x*y, -QQ(1,2)*x + y**2] invalid_groebner = [x**3, x*y, -QQ(1,2)*x + y**2] assert is_groebner(valid_groebner, R) is True assert is_groebner(invalid_groebner, R) is False def test_is_reduced(): R, x, y = ring("x,y", QQ, lex) f = x**2 + 2*x*y**2 g = x*y + 2*y**3 - 1 assert is_reduced([f, g], R) == False G = groebner([f, g], R) assert is_reduced(G, R) == True sympy-sympy-1.9/sympy/polys/tests/test_heuristicgcd.py000066400000000000000000000076771412543434000235230ustar00rootroot00000000000000from sympy.polys.rings import ring from sympy.polys.domains import ZZ from sympy.polys.heuristicgcd import heugcd def test_heugcd_univariate_integers(): R, x = ring("x", ZZ) f = x**4 + 8*x**3 + 21*x**2 + 22*x + 8 g = x**3 + 6*x**2 + 11*x + 6 h = x**2 + 3*x + 2 cff = x**2 + 5*x + 4 cfg = x + 3 assert heugcd(f, g) == (h, cff, cfg) f = x**4 - 4 g = x**4 + 4*x**2 + 4 h = x**2 + 2 cff = x**2 - 2 cfg = x**2 + 2 assert heugcd(f, g) == (h, cff, cfg) f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 h = 1 cff = f cfg = g assert heugcd(f, g) == (h, cff, cfg) f = - 352518131239247345597970242177235495263669787845475025293906825864749649589178600387510272*x**49 \ + 46818041807522713962450042363465092040687472354933295397472942006618953623327997952*x**42 \ + 378182690892293941192071663536490788434899030680411695933646320291525827756032*x**35 \ + 112806468807371824947796775491032386836656074179286744191026149539708928*x**28 \ - 12278371209708240950316872681744825481125965781519138077173235712*x**21 \ + 289127344604779611146960547954288113529690984687482920704*x**14 \ + 19007977035740498977629742919480623972236450681*x**7 \ + 311973482284542371301330321821976049 g = 365431878023781158602430064717380211405897160759702125019136*x**21 \ + 197599133478719444145775798221171663643171734081650688*x**14 \ - 9504116979659010018253915765478924103928886144*x**7 \ - 311973482284542371301330321821976049 # TODO: assert heugcd(f, f.diff(x))[0] == g f = 1317378933230047068160*x + 2945748836994210856960 g = 120352542776360960*x + 269116466014453760 h = 120352542776360960*x + 269116466014453760 cff = 10946 cfg = 1 assert heugcd(f, g) == (h, cff, cfg) def test_heugcd_multivariate_integers(): R, x, y = ring("x,y", ZZ) f, g = 2*x**2 + 4*x + 2, x + 1 assert heugcd(f, g) == (x + 1, 2*x + 2, 1) f, g = x + 1, 2*x**2 + 4*x + 2 assert heugcd(f, g) == (x + 1, 1, 2*x + 2) R, x, y, z, u = ring("x,y,z,u", ZZ) f, g = u**2 + 2*u + 1, 2*u + 2 assert heugcd(f, g) == (u + 1, u + 1, 2) f, g = z**2*u**2 + 2*z**2*u + z**2 + z*u + z, u**2 + 2*u + 1 h, cff, cfg = u + 1, z**2*u + z**2 + z, u + 1 assert heugcd(f, g) == (h, cff, cfg) assert heugcd(g, f) == (h, cfg, cff) R, x, y, z = ring("x,y,z", ZZ) f, g, h = R.fateman_poly_F_1() H, cff, cfg = heugcd(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) f, g, h = R.fateman_poly_F_1() H, cff, cfg = heugcd(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, u, v, a, b = ring("x,y,z,u,v,a,b", ZZ) f, g, h = R.fateman_poly_F_1() H, cff, cfg = heugcd(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, u, v, a, b, c, d = ring("x,y,z,u,v,a,b,c,d", ZZ) f, g, h = R.fateman_poly_F_1() H, cff, cfg = heugcd(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z = ring("x,y,z", ZZ) f, g, h = R.fateman_poly_F_2() H, cff, cfg = heugcd(f, g) assert H == h and H*cff == f and H*cfg == g f, g, h = R.fateman_poly_F_3() H, cff, cfg = heugcd(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, t = ring("x,y,z,t", ZZ) f, g, h = R.fateman_poly_F_3() H, cff, cfg = heugcd(f, g) assert H == h and H*cff == f and H*cfg == g def test_issue_10996(): R, x, y, z = ring("x,y,z", ZZ) f = 12*x**6*y**7*z**3 - 3*x**4*y**9*z**3 + 12*x**3*y**5*z**4 g = -48*x**7*y**8*z**3 + 12*x**5*y**10*z**3 - 48*x**5*y**7*z**2 + \ 36*x**4*y**7*z - 48*x**4*y**6*z**4 + 12*x**3*y**9*z**2 - 48*x**3*y**4 \ - 9*x**2*y**9*z - 48*x**2*y**5*z**3 + 12*x*y**6 + 36*x*y**5*z**2 - 48*y**2*z H, cff, cfg = heugcd(f, g) assert H == 12*x**3*y**4 - 3*x*y**6 + 12*y**2*z assert H*cff == f and H*cfg == g sympy-sympy-1.9/sympy/polys/tests/test_injections.py000066400000000000000000000024061412543434000231740ustar00rootroot00000000000000"""Tests for functions that inject symbols into the global namespace. """ from sympy.polys.rings import vring from sympy.polys.fields import vfield from sympy.polys.domains import QQ def test_vring(): ns = {'vring':vring, 'QQ':QQ} exec('R = vring("r", QQ)', ns) exec('assert r == R.gens[0]', ns) exec('R = vring("rb rbb rcc rzz _rx", QQ)', ns) exec('assert rb == R.gens[0]', ns) exec('assert rbb == R.gens[1]', ns) exec('assert rcc == R.gens[2]', ns) exec('assert rzz == R.gens[3]', ns) exec('assert _rx == R.gens[4]', ns) exec('R = vring(["rd", "re", "rfg"], QQ)', ns) exec('assert rd == R.gens[0]', ns) exec('assert re == R.gens[1]', ns) exec('assert rfg == R.gens[2]', ns) def test_vfield(): ns = {'vfield':vfield, 'QQ':QQ} exec('F = vfield("f", QQ)', ns) exec('assert f == F.gens[0]', ns) exec('F = vfield("fb fbb fcc fzz _fx", QQ)', ns) exec('assert fb == F.gens[0]', ns) exec('assert fbb == F.gens[1]', ns) exec('assert fcc == F.gens[2]', ns) exec('assert fzz == F.gens[3]', ns) exec('assert _fx == F.gens[4]', ns) exec('F = vfield(["fd", "fe", "ffg"], QQ)', ns) exec('assert fd == F.gens[0]', ns) exec('assert fe == F.gens[1]', ns) exec('assert ffg == F.gens[2]', ns) sympy-sympy-1.9/sympy/polys/tests/test_modulargcd.py000066400000000000000000000214571412543434000231570ustar00rootroot00000000000000from sympy.polys.rings import ring from sympy.polys.domains import ZZ, QQ, AlgebraicField from sympy.polys.modulargcd import ( modgcd_univariate, modgcd_bivariate, _chinese_remainder_reconstruction_multivariate, modgcd_multivariate, _to_ZZ_poly, _to_ANP_poly, func_field_modgcd, _func_field_modgcd_m) from sympy import sqrt def test_modgcd_univariate_integers(): R, x = ring("x", ZZ) f, g = R.zero, R.zero assert modgcd_univariate(f, g) == (0, 0, 0) f, g = R.zero, x assert modgcd_univariate(f, g) == (x, 0, 1) assert modgcd_univariate(g, f) == (x, 1, 0) f, g = R.zero, -x assert modgcd_univariate(f, g) == (x, 0, -1) assert modgcd_univariate(g, f) == (x, -1, 0) f, g = 2*x, R(2) assert modgcd_univariate(f, g) == (2, x, 1) f, g = 2*x + 2, 6*x**2 - 6 assert modgcd_univariate(f, g) == (2*x + 2, 1, 3*x - 3) f = x**4 + 8*x**3 + 21*x**2 + 22*x + 8 g = x**3 + 6*x**2 + 11*x + 6 h = x**2 + 3*x + 2 cff = x**2 + 5*x + 4 cfg = x + 3 assert modgcd_univariate(f, g) == (h, cff, cfg) f = x**4 - 4 g = x**4 + 4*x**2 + 4 h = x**2 + 2 cff = x**2 - 2 cfg = x**2 + 2 assert modgcd_univariate(f, g) == (h, cff, cfg) f = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 g = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 h = 1 cff = f cfg = g assert modgcd_univariate(f, g) == (h, cff, cfg) f = - 352518131239247345597970242177235495263669787845475025293906825864749649589178600387510272*x**49 \ + 46818041807522713962450042363465092040687472354933295397472942006618953623327997952*x**42 \ + 378182690892293941192071663536490788434899030680411695933646320291525827756032*x**35 \ + 112806468807371824947796775491032386836656074179286744191026149539708928*x**28 \ - 12278371209708240950316872681744825481125965781519138077173235712*x**21 \ + 289127344604779611146960547954288113529690984687482920704*x**14 \ + 19007977035740498977629742919480623972236450681*x**7 \ + 311973482284542371301330321821976049 g = 365431878023781158602430064717380211405897160759702125019136*x**21 \ + 197599133478719444145775798221171663643171734081650688*x**14 \ - 9504116979659010018253915765478924103928886144*x**7 \ - 311973482284542371301330321821976049 assert modgcd_univariate(f, f.diff(x))[0] == g f = 1317378933230047068160*x + 2945748836994210856960 g = 120352542776360960*x + 269116466014453760 h = 120352542776360960*x + 269116466014453760 cff = 10946 cfg = 1 assert modgcd_univariate(f, g) == (h, cff, cfg) def test_modgcd_bivariate_integers(): R, x, y = ring("x,y", ZZ) f, g = R.zero, R.zero assert modgcd_bivariate(f, g) == (0, 0, 0) f, g = 2*x, R(2) assert modgcd_bivariate(f, g) == (2, x, 1) f, g = x + 2*y, x + y assert modgcd_bivariate(f, g) == (1, f, g) f, g = x**2 + 2*x*y + y**2, x**3 + y**3 assert modgcd_bivariate(f, g) == (x + y, x + y, x**2 - x*y + y**2) f, g = x*y**2 + 2*x*y + x, x*y**3 + x assert modgcd_bivariate(f, g) == (x*y + x, y + 1, y**2 - y + 1) f, g = x**2*y**2 + x**2*y + 1, x*y**2 + x*y + 1 assert modgcd_bivariate(f, g) == (1, f, g) f = 2*x*y**2 + 4*x*y + 2*x + y**2 + 2*y + 1 g = 2*x*y**3 + 2*x + y**3 + 1 assert modgcd_bivariate(f, g) == (2*x*y + 2*x + y + 1, y + 1, y**2 - y + 1) f, g = 2*x**2 + 4*x + 2, x + 1 assert modgcd_bivariate(f, g) == (x + 1, 2*x + 2, 1) f, g = x + 1, 2*x**2 + 4*x + 2 assert modgcd_bivariate(f, g) == (x + 1, 1, 2*x + 2) f = 2*x**2 + 4*x*y - 2*x - 4*y g = x**2 + x - 2 assert modgcd_bivariate(f, g) == (x - 1, 2*x + 4*y, x + 2) f = 2*x**2 + 2*x*y - 3*x - 3*y g = 4*x*y - 2*x + 4*y**2 - 2*y assert modgcd_bivariate(f, g) == (x + y, 2*x - 3, 4*y - 2) def test_chinese_remainder(): R, x, y = ring("x, y", ZZ) p, q = 3, 5 hp = x**3*y - x**2 - 1 hq = -x**3*y - 2*x*y**2 + 2 hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) assert hpq.trunc_ground(p) == hp assert hpq.trunc_ground(q) == hq T, z = ring("z", R) p, q = 3, 7 hp = (x*y + 1)*z**2 + x hq = (x**2 - 3*y)*z + 2 hpq = _chinese_remainder_reconstruction_multivariate(hp, hq, p, q) assert hpq.trunc_ground(p) == hp assert hpq.trunc_ground(q) == hq def test_modgcd_multivariate_integers(): R, x, y = ring("x,y", ZZ) f, g = R.zero, R.zero assert modgcd_multivariate(f, g) == (0, 0, 0) f, g = 2*x**2 + 4*x + 2, x + 1 assert modgcd_multivariate(f, g) == (x + 1, 2*x + 2, 1) f, g = x + 1, 2*x**2 + 4*x + 2 assert modgcd_multivariate(f, g) == (x + 1, 1, 2*x + 2) f = 2*x**2 + 2*x*y - 3*x - 3*y g = 4*x*y - 2*x + 4*y**2 - 2*y assert modgcd_multivariate(f, g) == (x + y, 2*x - 3, 4*y - 2) f, g = x*y**2 + 2*x*y + x, x*y**3 + x assert modgcd_multivariate(f, g) == (x*y + x, y + 1, y**2 - y + 1) f, g = x**2*y**2 + x**2*y + 1, x*y**2 + x*y + 1 assert modgcd_multivariate(f, g) == (1, f, g) f = x**4 + 8*x**3 + 21*x**2 + 22*x + 8 g = x**3 + 6*x**2 + 11*x + 6 h = x**2 + 3*x + 2 cff = x**2 + 5*x + 4 cfg = x + 3 assert modgcd_multivariate(f, g) == (h, cff, cfg) R, x, y, z, u = ring("x,y,z,u", ZZ) f, g = x + y + z, -x - y - z - u assert modgcd_multivariate(f, g) == (1, f, g) f, g = u**2 + 2*u + 1, 2*u + 2 assert modgcd_multivariate(f, g) == (u + 1, u + 1, 2) f, g = z**2*u**2 + 2*z**2*u + z**2 + z*u + z, u**2 + 2*u + 1 h, cff, cfg = u + 1, z**2*u + z**2 + z, u + 1 assert modgcd_multivariate(f, g) == (h, cff, cfg) assert modgcd_multivariate(g, f) == (h, cfg, cff) R, x, y, z = ring("x,y,z", ZZ) f, g = x - y*z, x - y*z assert modgcd_multivariate(f, g) == (x - y*z, 1, 1) f, g, h = R.fateman_poly_F_1() H, cff, cfg = modgcd_multivariate(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, u, v = ring("x,y,z,u,v", ZZ) f, g, h = R.fateman_poly_F_1() H, cff, cfg = modgcd_multivariate(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, u, v, a, b = ring("x,y,z,u,v,a,b", ZZ) f, g, h = R.fateman_poly_F_1() H, cff, cfg = modgcd_multivariate(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, u, v, a, b, c, d = ring("x,y,z,u,v,a,b,c,d", ZZ) f, g, h = R.fateman_poly_F_1() H, cff, cfg = modgcd_multivariate(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z = ring("x,y,z", ZZ) f, g, h = R.fateman_poly_F_2() H, cff, cfg = modgcd_multivariate(f, g) assert H == h and H*cff == f and H*cfg == g f, g, h = R.fateman_poly_F_3() H, cff, cfg = modgcd_multivariate(f, g) assert H == h and H*cff == f and H*cfg == g R, x, y, z, t = ring("x,y,z,t", ZZ) f, g, h = R.fateman_poly_F_3() H, cff, cfg = modgcd_multivariate(f, g) assert H == h and H*cff == f and H*cfg == g def test_to_ZZ_ANP_poly(): A = AlgebraicField(QQ, sqrt(2)) R, x = ring("x", A) f = x*(sqrt(2) + 1) T, x_, z_ = ring("x_, z_", ZZ) f_ = x_*z_ + x_ assert _to_ZZ_poly(f, T) == f_ assert _to_ANP_poly(f_, R) == f R, x, t, s = ring("x, t, s", A) f = x*t**2 + x*s + sqrt(2) D, t_, s_ = ring("t_, s_", ZZ) T, x_, z_ = ring("x_, z_", D) f_ = (t_**2 + s_)*x_ + z_ assert _to_ZZ_poly(f, T) == f_ assert _to_ANP_poly(f_, R) == f def test_modgcd_algebraic_field(): A = AlgebraicField(QQ, sqrt(2)) R, x = ring("x", A) one = A.one f, g = 2*x, R(2) assert func_field_modgcd(f, g) == (one, f, g) f, g = 2*x, R(sqrt(2)) assert func_field_modgcd(f, g) == (one, f, g) f, g = 2*x + 2, 6*x**2 - 6 assert func_field_modgcd(f, g) == (x + 1, R(2), 6*x - 6) R, x, y = ring("x, y", A) f, g = x + sqrt(2)*y, x + y assert func_field_modgcd(f, g) == (one, f, g) f, g = x*y + sqrt(2)*y**2, R(sqrt(2))*y assert func_field_modgcd(f, g) == (y, x + sqrt(2)*y, R(sqrt(2))) f, g = x**2 + 2*sqrt(2)*x*y + 2*y**2, x + sqrt(2)*y assert func_field_modgcd(f, g) == (g, g, one) A = AlgebraicField(QQ, sqrt(2), sqrt(3)) R, x, y, z = ring("x, y, z", A) h = x**2*y**7 + sqrt(6)/21*z f, g = h*(27*y**3 + 1), h*(y + x) assert func_field_modgcd(f, g) == (h, 27*y**3+1, y+x) h = x**13*y**3 + 1/2*x**10 + 1/sqrt(2) f, g = h*(x + 1), h*sqrt(2)/sqrt(3) assert func_field_modgcd(f, g) == (h, x + 1, R(sqrt(2)/sqrt(3))) A = AlgebraicField(QQ, sqrt(2)**(-1)*sqrt(3)) R, x = ring("x", A) f, g = x + 1, x - 1 assert func_field_modgcd(f, g) == (A.one, f, g) # when func_field_modgcd suppors function fields, this test can be changed def test_modgcd_func_field(): D, t = ring("t", ZZ) R, x, z = ring("x, z", D) minpoly = (z**2*t**2 + z**2*t - 1).drop(0) f, g = x + 1, x - 1 assert _func_field_modgcd_m(f, g, minpoly) == R.one sympy-sympy-1.9/sympy/polys/tests/test_monomials.py000066400000000000000000000253541412543434000230340ustar00rootroot00000000000000"""Tests for tools and arithmetics for monomials of distributed polynomials. """ from sympy.polys.monomials import ( itermonomials, monomial_count, monomial_mul, monomial_div, monomial_gcd, monomial_lcm, monomial_max, monomial_min, monomial_divides, monomial_pow, Monomial, ) from sympy.polys.polyerrors import ExactQuotientFailed from sympy.abc import a, b, c, x, y, z from sympy.core import S, symbols from sympy.testing.pytest import raises def test_monomials(): # total_degree tests assert set(itermonomials([], 0)) == {S.One} assert set(itermonomials([], 1)) == {S.One} assert set(itermonomials([], 2)) == {S.One} assert set(itermonomials([], 0, 0)) == {S.One} assert set(itermonomials([], 1, 0)) == {S.One} assert set(itermonomials([], 2, 0)) == {S.One} raises(StopIteration, lambda: next(itermonomials([], 0, 1))) raises(StopIteration, lambda: next(itermonomials([], 0, 2))) raises(StopIteration, lambda: next(itermonomials([], 0, 3))) assert set(itermonomials([], 0, 1)) == set() assert set(itermonomials([], 0, 2)) == set() assert set(itermonomials([], 0, 3)) == set() raises(ValueError, lambda: set(itermonomials([], -1))) raises(ValueError, lambda: set(itermonomials([x], -1))) raises(ValueError, lambda: set(itermonomials([x, y], -1))) assert set(itermonomials([x], 0)) == {S.One} assert set(itermonomials([x], 1)) == {S.One, x} assert set(itermonomials([x], 2)) == {S.One, x, x**2} assert set(itermonomials([x], 3)) == {S.One, x, x**2, x**3} assert set(itermonomials([x, y], 0)) == {S.One} assert set(itermonomials([x, y], 1)) == {S.One, x, y} assert set(itermonomials([x, y], 2)) == {S.One, x, y, x**2, y**2, x*y} assert set(itermonomials([x, y], 3)) == \ {S.One, x, y, x**2, x**3, y**2, y**3, x*y, x*y**2, y*x**2} i, j, k = symbols('i j k', commutative=False) assert set(itermonomials([i, j, k], 0)) == {S.One} assert set(itermonomials([i, j, k], 1)) == {S.One, i, j, k} assert set(itermonomials([i, j, k], 2)) == \ {S.One, i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j} assert set(itermonomials([i, j, k], 3)) == \ {S.One, i, j, k, i**2, j**2, k**2, i*j, i*k, j*i, j*k, k*i, k*j, i**3, j**3, k**3, i**2 * j, i**2 * k, j * i**2, k * i**2, j**2 * i, j**2 * k, i * j**2, k * j**2, k**2 * i, k**2 * j, i * k**2, j * k**2, i*j*i, i*k*i, j*i*j, j*k*j, k*i*k, k*j*k, i*j*k, i*k*j, j*i*k, j*k*i, k*i*j, k*j*i, } assert set(itermonomials([x, i, j], 0)) == {S.One} assert set(itermonomials([x, i, j], 1)) == {S.One, x, i, j} assert set(itermonomials([x, i, j], 2)) == {S.One, x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2} assert set(itermonomials([x, i, j], 3)) == \ {S.One, x, i, j, x*i, x*j, i*j, j*i, x**2, i**2, j**2, x**3, i**3, j**3, x**2 * i, x**2 * j, x * i**2, j * i**2, i**2 * j, i*j*i, x * j**2, i * j**2, j**2 * i, j*i*j, x * i * j, x * j * i } # degree_list tests assert set(itermonomials([], [])) == {S.One} raises(ValueError, lambda: set(itermonomials([], [0]))) raises(ValueError, lambda: set(itermonomials([], [1]))) raises(ValueError, lambda: set(itermonomials([], [2]))) raises(ValueError, lambda: set(itermonomials([x], [1], []))) raises(ValueError, lambda: set(itermonomials([x], [1, 2], []))) raises(ValueError, lambda: set(itermonomials([x], [1, 2, 3], []))) raises(ValueError, lambda: set(itermonomials([x], [], [1]))) raises(ValueError, lambda: set(itermonomials([x], [], [1, 2]))) raises(ValueError, lambda: set(itermonomials([x], [], [1, 2, 3]))) raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, 2, 3]))) raises(ValueError, lambda: set(itermonomials([x, y, z], [1, 2, 3], [0, 1]))) raises(ValueError, lambda: set(itermonomials([x], [1], [-1]))) raises(ValueError, lambda: set(itermonomials([x, y], [1, 2], [1, -1]))) raises(ValueError, lambda: set(itermonomials([], [], 1))) raises(ValueError, lambda: set(itermonomials([], [], 2))) raises(ValueError, lambda: set(itermonomials([], [], 3))) raises(ValueError, lambda: set(itermonomials([x, y], [0, 1], [1, 2]))) raises(ValueError, lambda: set(itermonomials([x, y, z], [0, 0, 3], [0, 1, 2]))) assert set(itermonomials([x], [0])) == {S.One} assert set(itermonomials([x], [1])) == {S.One, x} assert set(itermonomials([x], [2])) == {S.One, x, x**2} assert set(itermonomials([x], [3])) == {S.One, x, x**2, x**3} assert set(itermonomials([x], [3], [1])) == {x, x**3, x**2} assert set(itermonomials([x], [3], [2])) == {x**3, x**2} assert set(itermonomials([x, y], 3, 3)) == {x**3, x**2*y, x*y**2, y**3} assert set(itermonomials([x, y], 3, 2)) == {x**2, x*y, y**2, x**3, x**2*y, x*y**2, y**3} assert set(itermonomials([x, y], [0, 0])) == {S.One} assert set(itermonomials([x, y], [0, 1])) == {S.One, y} assert set(itermonomials([x, y], [0, 2])) == {S.One, y, y**2} assert set(itermonomials([x, y], [0, 2], [0, 1])) == {y, y**2} assert set(itermonomials([x, y], [0, 2], [0, 2])) == {y**2} assert set(itermonomials([x, y], [1, 0])) == {S.One, x} assert set(itermonomials([x, y], [1, 1])) == {S.One, x, y, x*y} assert set(itermonomials([x, y], [1, 2])) == {S.One, x, y, x*y, y**2, x*y**2} assert set(itermonomials([x, y], [1, 2], [1, 1])) == {x*y, x*y**2} assert set(itermonomials([x, y], [1, 2], [1, 2])) == {x*y**2} assert set(itermonomials([x, y], [2, 0])) == {S.One, x, x**2} assert set(itermonomials([x, y], [2, 1])) == {S.One, x, y, x*y, x**2, x**2*y} assert set(itermonomials([x, y], [2, 2])) == \ {S.One, y**2, x*y**2, x, x*y, x**2, x**2*y**2, y, x**2*y} i, j, k = symbols('i j k', commutative=False) assert set(itermonomials([i, j, k], 2, 2)) == \ {k*i, i**2, i*j, j*k, j*i, k**2, j**2, k*j, i*k} assert set(itermonomials([i, j, k], 3, 2)) == \ {j*k**2, i*k**2, k*i*j, k*i**2, k**2, j*k*j, k*j**2, i*k*i, i*j, j**2*k, i**2*j, j*i*k, j**3, i**3, k*j*i, j*k*i, j*i, k**2*j, j*i**2, k*j, k*j*k, i*j*i, j*i*j, i*j**2, j**2, k*i*k, i**2, j*k, i*k, i*k*j, k**3, i**2*k, j**2*i, k**2*i, i*j*k, k*i } assert set(itermonomials([i, j, k], [0, 0, 0])) == {S.One} assert set(itermonomials([i, j, k], [0, 0, 1])) == {1, k} assert set(itermonomials([i, j, k], [0, 1, 0])) == {1, j} assert set(itermonomials([i, j, k], [1, 0, 0])) == {i, 1} assert set(itermonomials([i, j, k], [0, 0, 2])) == {k**2, 1, k} assert set(itermonomials([i, j, k], [0, 2, 0])) == {1, j, j**2} assert set(itermonomials([i, j, k], [2, 0, 0])) == {i, 1, i**2} assert set(itermonomials([i, j, k], [1, 1, 1])) == {1, k, j, j*k, i*k, i, i*j, i*j*k} assert set(itermonomials([i, j, k], [2, 2, 2])) == \ {1, k, i**2*k**2, j*k, j**2, i, i*k, j*k**2, i*j**2*k**2, i**2*j, i**2*j**2, k**2, j**2*k, i*j**2*k, j**2*k**2, i*j, i**2*k, i**2*j**2*k, j, i**2*j*k, i*j**2, i*k**2, i*j*k, i**2*j**2*k**2, i*j*k**2, i**2, i**2*j*k**2 } assert set(itermonomials([x, j, k], [0, 0, 0])) == {S.One} assert set(itermonomials([x, j, k], [0, 0, 1])) == {1, k} assert set(itermonomials([x, j, k], [0, 1, 0])) == {1, j} assert set(itermonomials([x, j, k], [1, 0, 0])) == {x, 1} assert set(itermonomials([x, j, k], [0, 0, 2])) == {k**2, 1, k} assert set(itermonomials([x, j, k], [0, 2, 0])) == {1, j, j**2} assert set(itermonomials([x, j, k], [2, 0, 0])) == {x, 1, x**2} assert set(itermonomials([x, j, k], [1, 1, 1])) == {1, k, j, j*k, x*k, x, x*j, x*j*k} assert set(itermonomials([x, j, k], [2, 2, 2])) == \ {1, k, x**2*k**2, j*k, j**2, x, x*k, j*k**2, x*j**2*k**2, x**2*j, x**2*j**2, k**2, j**2*k, x*j**2*k, j**2*k**2, x*j, x**2*k, x**2*j**2*k, j, x**2*j*k, x*j**2, x*k**2, x*j*k, x**2*j**2*k**2, x*j*k**2, x**2, x**2*j*k**2 } def test_monomial_count(): assert monomial_count(2, 2) == 6 assert monomial_count(2, 3) == 10 def test_monomial_mul(): assert monomial_mul((3, 4, 1), (1, 2, 0)) == (4, 6, 1) def test_monomial_div(): assert monomial_div((3, 4, 1), (1, 2, 0)) == (2, 2, 1) def test_monomial_gcd(): assert monomial_gcd((3, 4, 1), (1, 2, 0)) == (1, 2, 0) def test_monomial_lcm(): assert monomial_lcm((3, 4, 1), (1, 2, 0)) == (3, 4, 1) def test_monomial_max(): assert monomial_max((3, 4, 5), (0, 5, 1), (6, 3, 9)) == (6, 5, 9) def test_monomial_pow(): assert monomial_pow((1, 2, 3), 3) == (3, 6, 9) def test_monomial_min(): assert monomial_min((3, 4, 5), (0, 5, 1), (6, 3, 9)) == (0, 3, 1) def test_monomial_divides(): assert monomial_divides((1, 2, 3), (4, 5, 6)) is True assert monomial_divides((1, 2, 3), (0, 5, 6)) is False def test_Monomial(): m = Monomial((3, 4, 1), (x, y, z)) n = Monomial((1, 2, 0), (x, y, z)) assert m.as_expr() == x**3*y**4*z assert n.as_expr() == x**1*y**2 assert m.as_expr(a, b, c) == a**3*b**4*c assert n.as_expr(a, b, c) == a**1*b**2 assert m.exponents == (3, 4, 1) assert m.gens == (x, y, z) assert n.exponents == (1, 2, 0) assert n.gens == (x, y, z) assert m == (3, 4, 1) assert n != (3, 4, 1) assert m != (1, 2, 0) assert n == (1, 2, 0) assert (m == 1) is False assert m[0] == m[-3] == 3 assert m[1] == m[-2] == 4 assert m[2] == m[-1] == 1 assert n[0] == n[-3] == 1 assert n[1] == n[-2] == 2 assert n[2] == n[-1] == 0 assert m[:2] == (3, 4) assert n[:2] == (1, 2) assert m*n == Monomial((4, 6, 1)) assert m/n == Monomial((2, 2, 1)) assert m*(1, 2, 0) == Monomial((4, 6, 1)) assert m/(1, 2, 0) == Monomial((2, 2, 1)) assert m.gcd(n) == Monomial((1, 2, 0)) assert m.lcm(n) == Monomial((3, 4, 1)) assert m.gcd((1, 2, 0)) == Monomial((1, 2, 0)) assert m.lcm((1, 2, 0)) == Monomial((3, 4, 1)) assert m**0 == Monomial((0, 0, 0)) assert m**1 == m assert m**2 == Monomial((6, 8, 2)) assert m**3 == Monomial((9, 12, 3)) raises(ExactQuotientFailed, lambda: m/Monomial((5, 2, 0))) mm = Monomial((1, 2, 3)) raises(ValueError, lambda: mm.as_expr()) assert str(mm) == 'Monomial((1, 2, 3))' assert str(m) == 'x**3*y**4*z**1' raises(NotImplementedError, lambda: m*1) raises(NotImplementedError, lambda: m/1) raises(ValueError, lambda: m**-1) raises(TypeError, lambda: m.gcd(3)) raises(TypeError, lambda: m.lcm(3)) sympy-sympy-1.9/sympy/polys/tests/test_multivariate_resultants.py000066400000000000000000000223551412543434000260260ustar00rootroot00000000000000"""Tests for Dixon's and Macaulay's classes. """ from sympy import Matrix, factor from sympy.core import symbols from sympy.tensor.indexed import IndexedBase from sympy.polys.multivariate_resultants import (DixonResultant, MacaulayResultant) c, d = symbols("a, b") x, y = symbols("x, y") p = c * x + y q = x + d * y dixon = DixonResultant(polynomials=[p, q], variables=[x, y]) macaulay = MacaulayResultant(polynomials=[p, q], variables=[x, y]) def test_dixon_resultant_init(): """Test init method of DixonResultant.""" a = IndexedBase("alpha") assert dixon.polynomials == [p, q] assert dixon.variables == [x, y] assert dixon.n == 2 assert dixon.m == 2 assert dixon.dummy_variables == [a[0], a[1]] def test_get_dixon_polynomial_numerical(): """Test Dixon's polynomial for a numerical example.""" a = IndexedBase("alpha") p = x + y q = x ** 2 + y **3 h = x ** 2 + y dixon = DixonResultant([p, q, h], [x, y]) polynomial = -x * y ** 2 * a[0] - x * y ** 2 * a[1] - x * y * a[0] \ * a[1] - x * y * a[1] ** 2 - x * a[0] * a[1] ** 2 + x * a[0] - \ y ** 2 * a[0] * a[1] + y ** 2 * a[1] - y * a[0] * a[1] ** 2 + y * \ a[1] ** 2 assert dixon.get_dixon_polynomial().as_expr().expand() == polynomial def test_get_max_degrees(): """Tests max degrees function.""" p = x + y q = x ** 2 + y **3 h = x ** 2 + y dixon = DixonResultant(polynomials=[p, q, h], variables=[x, y]) dixon_polynomial = dixon.get_dixon_polynomial() assert dixon.get_max_degrees(dixon_polynomial) == [1, 2] def test_get_dixon_matrix(): """Test Dixon's resultant for a numerical example.""" x, y = symbols('x, y') p = x + y q = x ** 2 + y ** 3 h = x ** 2 + y dixon = DixonResultant([p, q, h], [x, y]) polynomial = dixon.get_dixon_polynomial() assert dixon.get_dixon_matrix(polynomial).det() == 0 def test_get_dixon_matrix_example_two(): """Test Dixon's matrix for example from [Palancz08]_.""" x, y, z = symbols('x, y, z') f = x ** 2 + y ** 2 - 1 + z * 0 g = x ** 2 + z ** 2 - 1 + y * 0 h = y ** 2 + z ** 2 - 1 example_two = DixonResultant([f, g, h], [y, z]) poly = example_two.get_dixon_polynomial() matrix = example_two.get_dixon_matrix(poly) expr = 1 - 8 * x ** 2 + 24 * x ** 4 - 32 * x ** 6 + 16 * x ** 8 assert (matrix.det() - expr).expand() == 0 def test_KSY_precondition(): """Tests precondition for KSY Resultant.""" A, B, C = symbols('A, B, C') m1 = Matrix([[1, 2, 3], [4, 5, 12], [6, 7, 18]]) m2 = Matrix([[0, C**2], [-2 * C, -C ** 2]]) m3 = Matrix([[1, 0], [0, 1]]) m4 = Matrix([[A**2, 0, 1], [A, 1, 1 / A]]) m5 = Matrix([[5, 1], [2, B], [0, 1], [0, 0]]) assert dixon.KSY_precondition(m1) == False assert dixon.KSY_precondition(m2) == True assert dixon.KSY_precondition(m3) == True assert dixon.KSY_precondition(m4) == False assert dixon.KSY_precondition(m5) == True def test_delete_zero_rows_and_columns(): """Tests method for deleting rows and columns containing only zeros.""" A, B, C = symbols('A, B, C') m1 = Matrix([[0, 0], [0, 0], [1, 2]]) m2 = Matrix([[0, 1, 2], [0, 3, 4], [0, 5, 6]]) m3 = Matrix([[0, 0, 0, 0], [0, 1, 2, 0], [0, 3, 4, 0], [0, 0, 0, 0]]) m4 = Matrix([[1, 0, 2], [0, 0, 0], [3, 0, 4]]) m5 = Matrix([[0, 0, 0, 1], [0, 0, 0, 2], [0, 0, 0, 3], [0, 0, 0, 4]]) m6 = Matrix([[0, 0, A], [B, 0, 0], [0, 0, C]]) assert dixon.delete_zero_rows_and_columns(m1) == Matrix([[1, 2]]) assert dixon.delete_zero_rows_and_columns(m2) == Matrix([[1, 2], [3, 4], [5, 6]]) assert dixon.delete_zero_rows_and_columns(m3) == Matrix([[1, 2], [3, 4]]) assert dixon.delete_zero_rows_and_columns(m4) == Matrix([[1, 2], [3, 4]]) assert dixon.delete_zero_rows_and_columns(m5) == Matrix([[1], [2], [3], [4]]) assert dixon.delete_zero_rows_and_columns(m6) == Matrix([[0, A], [B, 0], [0, C]]) def test_product_leading_entries(): """Tests product of leading entries method.""" A, B = symbols('A, B') m1 = Matrix([[1, 2, 3], [0, 4, 5], [0, 0, 6]]) m2 = Matrix([[0, 0, 1], [2, 0, 3]]) m3 = Matrix([[0, 0, 0], [1, 2, 3], [0, 0, 0]]) m4 = Matrix([[0, 0, A], [1, 2, 3], [B, 0, 0]]) assert dixon.product_leading_entries(m1) == 24 assert dixon.product_leading_entries(m2) == 2 assert dixon.product_leading_entries(m3) == 1 assert dixon.product_leading_entries(m4) == A * B def test_get_KSY_Dixon_resultant_example_one(): """Tests the KSY Dixon resultant for example one""" x, y, z = symbols('x, y, z') p = x * y * z q = x**2 - z**2 h = x + y + z dixon = DixonResultant([p, q, h], [x, y]) dixon_poly = dixon.get_dixon_polynomial() dixon_matrix = dixon.get_dixon_matrix(dixon_poly) D = dixon.get_KSY_Dixon_resultant(dixon_matrix) assert D == -z**3 def test_get_KSY_Dixon_resultant_example_two(): """Tests the KSY Dixon resultant for example two""" x, y, A = symbols('x, y, A') p = x * y + x * A + x - A**2 - A + y**2 + y q = x**2 + x * A - x + x * y + y * A - y h = x**2 + x * y + 2 * x - x * A - y * A - 2 * A dixon = DixonResultant([p, q, h], [x, y]) dixon_poly = dixon.get_dixon_polynomial() dixon_matrix = dixon.get_dixon_matrix(dixon_poly) D = factor(dixon.get_KSY_Dixon_resultant(dixon_matrix)) assert D == -8*A*(A - 1)*(A + 2)*(2*A - 1)**2 def test_macaulay_resultant_init(): """Test init method of MacaulayResultant.""" assert macaulay.polynomials == [p, q] assert macaulay.variables == [x, y] assert macaulay.n == 2 assert macaulay.degrees == [1, 1] assert macaulay.degree_m == 1 assert macaulay.monomials_size == 2 def test_get_degree_m(): assert macaulay._get_degree_m() == 1 def test_get_size(): assert macaulay.get_size() == 2 def test_macaulay_example_one(): """Tests the Macaulay for example from [Bruce97]_""" x, y, z = symbols('x, y, z') a_1_1, a_1_2, a_1_3 = symbols('a_1_1, a_1_2, a_1_3') a_2_2, a_2_3, a_3_3 = symbols('a_2_2, a_2_3, a_3_3') b_1_1, b_1_2, b_1_3 = symbols('b_1_1, b_1_2, b_1_3') b_2_2, b_2_3, b_3_3 = symbols('b_2_2, b_2_3, b_3_3') c_1, c_2, c_3 = symbols('c_1, c_2, c_3') f_1 = a_1_1 * x ** 2 + a_1_2 * x * y + a_1_3 * x * z + \ a_2_2 * y ** 2 + a_2_3 * y * z + a_3_3 * z ** 2 f_2 = b_1_1 * x ** 2 + b_1_2 * x * y + b_1_3 * x * z + \ b_2_2 * y ** 2 + b_2_3 * y * z + b_3_3 * z ** 2 f_3 = c_1 * x + c_2 * y + c_3 * z mac = MacaulayResultant([f_1, f_2, f_3], [x, y, z]) assert mac.degrees == [2, 2, 1] assert mac.degree_m == 3 assert mac.monomial_set == [x ** 3, x ** 2 * y, x ** 2 * z, x * y ** 2, x * y * z, x * z ** 2, y ** 3, y ** 2 *z, y * z ** 2, z ** 3] assert mac.monomials_size == 10 assert mac.get_row_coefficients() == [[x, y, z], [x, y, z], [x * y, x * z, y * z, z ** 2]] matrix = mac.get_matrix() assert matrix.shape == (mac.monomials_size, mac.monomials_size) assert mac.get_submatrix(matrix) == Matrix([[a_1_1, a_2_2], [b_1_1, b_2_2]]) def test_macaulay_example_two(): """Tests the Macaulay formulation for example from [Stiller96]_.""" x, y, z = symbols('x, y, z') a_0, a_1, a_2 = symbols('a_0, a_1, a_2') b_0, b_1, b_2 = symbols('b_0, b_1, b_2') c_0, c_1, c_2, c_3, c_4 = symbols('c_0, c_1, c_2, c_3, c_4') f = a_0 * y - a_1 * x + a_2 * z g = b_1 * x ** 2 + b_0 * y ** 2 - b_2 * z ** 2 h = c_0 * y - c_1 * x ** 3 + c_2 * x ** 2 * z - c_3 * x * z ** 2 + \ c_4 * z ** 3 mac = MacaulayResultant([f, g, h], [x, y, z]) assert mac.degrees == [1, 2, 3] assert mac.degree_m == 4 assert mac.monomials_size == 15 assert len(mac.get_row_coefficients()) == mac.n matrix = mac.get_matrix() assert matrix.shape == (mac.monomials_size, mac.monomials_size) assert mac.get_submatrix(matrix) == Matrix([[-a_1, a_0, a_2, 0], [0, -a_1, 0, 0], [0, 0, -a_1, 0], [0, 0, 0, -a_1]]) sympy-sympy-1.9/sympy/polys/tests/test_numberfields.py000066400000000000000000001051321412543434000235060ustar00rootroot00000000000000"""Tests for computational algebraic number field theory. """ from sympy import (S, Rational, Symbol, Poly, sqrt, I, oo, Tuple, expand, pi, cos, sin, tan, exp, GoldenRatio, TribonacciConstant, cbrt) from sympy.solvers.solveset import nonlinsolve from sympy.geometry import Circle, intersection from sympy.testing.pytest import raises, slow from sympy.sets.sets import FiniteSet from sympy import Point2D from sympy.polys.numberfields import ( minimal_polynomial, primitive_element, is_isomorphism_possible, field_isomorphism_pslq, field_isomorphism, to_number_field, AlgebraicNumber, isolate, IntervalPrinter, _choose_factor, ) from sympy.polys.partfrac import apart from sympy.polys.polyerrors import ( IsomorphismFailed, NotAlgebraic, GeneratorsError, ) from sympy.polys.polyclasses import DMP from sympy.polys.domains import QQ from sympy.polys.rootoftools import rootof from sympy.polys.polytools import degree from sympy.abc import x, y, z Q = Rational def test_minimal_polynomial(): assert minimal_polynomial(-7, x) == x + 7 assert minimal_polynomial(-1, x) == x + 1 assert minimal_polynomial( 0, x) == x assert minimal_polynomial( 1, x) == x - 1 assert minimal_polynomial( 7, x) == x - 7 assert minimal_polynomial(sqrt(2), x) == x**2 - 2 assert minimal_polynomial(sqrt(5), x) == x**2 - 5 assert minimal_polynomial(sqrt(6), x) == x**2 - 6 assert minimal_polynomial(2*sqrt(2), x) == x**2 - 8 assert minimal_polynomial(3*sqrt(5), x) == x**2 - 45 assert minimal_polynomial(4*sqrt(6), x) == x**2 - 96 assert minimal_polynomial(2*sqrt(2) + 3, x) == x**2 - 6*x + 1 assert minimal_polynomial(3*sqrt(5) + 6, x) == x**2 - 12*x - 9 assert minimal_polynomial(4*sqrt(6) + 7, x) == x**2 - 14*x - 47 assert minimal_polynomial(2*sqrt(2) - 3, x) == x**2 + 6*x + 1 assert minimal_polynomial(3*sqrt(5) - 6, x) == x**2 + 12*x - 9 assert minimal_polynomial(4*sqrt(6) - 7, x) == x**2 + 14*x - 47 assert minimal_polynomial(sqrt(1 + sqrt(6)), x) == x**4 - 2*x**2 - 5 assert minimal_polynomial(sqrt(I + sqrt(6)), x) == x**8 - 10*x**4 + 49 assert minimal_polynomial(2*I + sqrt(2 + I), x) == x**4 + 4*x**2 + 8*x + 37 assert minimal_polynomial(sqrt(2) + sqrt(3), x) == x**4 - 10*x**2 + 1 assert minimal_polynomial( sqrt(2) + sqrt(3) + sqrt(6), x) == x**4 - 22*x**2 - 48*x - 23 a = 1 - 9*sqrt(2) + 7*sqrt(3) assert minimal_polynomial( 1/a, x) == 392*x**4 - 1232*x**3 + 612*x**2 + 4*x - 1 assert minimal_polynomial( 1/sqrt(a), x) == 392*x**8 - 1232*x**6 + 612*x**4 + 4*x**2 - 1 raises(NotAlgebraic, lambda: minimal_polynomial(oo, x)) raises(NotAlgebraic, lambda: minimal_polynomial(2**y, x)) raises(NotAlgebraic, lambda: minimal_polynomial(sin(1), x)) assert minimal_polynomial(sqrt(2)).dummy_eq(x**2 - 2) assert minimal_polynomial(sqrt(2), x) == x**2 - 2 assert minimal_polynomial(sqrt(2), polys=True) == Poly(x**2 - 2) assert minimal_polynomial(sqrt(2), x, polys=True) == Poly(x**2 - 2, domain='QQ') assert minimal_polynomial(sqrt(2), x, polys=True, compose=False) == Poly(x**2 - 2, domain='QQ') a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(3)) assert minimal_polynomial(a, x) == x**2 - 2 assert minimal_polynomial(b, x) == x**2 - 3 assert minimal_polynomial(a, x, polys=True) == Poly(x**2 - 2, domain='QQ') assert minimal_polynomial(b, x, polys=True) == Poly(x**2 - 3, domain='QQ') assert minimal_polynomial(sqrt(a/2 + 17), x) == 2*x**4 - 68*x**2 + 577 assert minimal_polynomial(sqrt(b/2 + 17), x) == 4*x**4 - 136*x**2 + 1153 a, b = sqrt(2)/3 + 7, AlgebraicNumber(sqrt(2)/3 + 7) f = 81*x**8 - 2268*x**6 - 4536*x**5 + 22644*x**4 + 63216*x**3 - \ 31608*x**2 - 189648*x + 141358 assert minimal_polynomial(sqrt(a) + sqrt(sqrt(a)), x) == f assert minimal_polynomial(sqrt(b) + sqrt(sqrt(b)), x) == f assert minimal_polynomial( a**Q(3, 2), x) == 729*x**4 - 506898*x**2 + 84604519 # issue 5994 eq = S(''' -1/(800*sqrt(-1/240 + 1/(18000*(-1/17280000 + sqrt(15)*I/28800000)**(1/3)) + 2*(-1/17280000 + sqrt(15)*I/28800000)**(1/3)))''') assert minimal_polynomial(eq, x) == 8000*x**2 - 1 ex = (sqrt(5)*sqrt(I)/(5*sqrt(1 + 125*I)) + 25*sqrt(5)/(I**Q(5,2)*(1 + 125*I)**Q(3,2)) + 3125*sqrt(5)/(I**Q(11,2)*(1 + 125*I)**Q(3,2)) + 5*I*sqrt(1 - I/125)) mp = minimal_polynomial(ex, x) assert mp == 25*x**4 + 5000*x**2 + 250016 ex = 1 + sqrt(2) + sqrt(3) mp = minimal_polynomial(ex, x) assert mp == x**4 - 4*x**3 - 4*x**2 + 16*x - 8 ex = 1/(1 + sqrt(2) + sqrt(3)) mp = minimal_polynomial(ex, x) assert mp == 8*x**4 - 16*x**3 + 4*x**2 + 4*x - 1 p = (expand((1 + sqrt(2) - 2*sqrt(3) + sqrt(7))**3))**Rational(1, 3) mp = minimal_polynomial(p, x) assert mp == x**8 - 8*x**7 - 56*x**6 + 448*x**5 + 480*x**4 - 5056*x**3 + 1984*x**2 + 7424*x - 3008 p = expand((1 + sqrt(2) - 2*sqrt(3) + sqrt(7))**3) mp = minimal_polynomial(p, x) assert mp == x**8 - 512*x**7 - 118208*x**6 + 31131136*x**5 + 647362560*x**4 - 56026611712*x**3 + 116994310144*x**2 + 404854931456*x - 27216576512 assert minimal_polynomial(S("-sqrt(5)/2 - 1/2 + (-sqrt(5)/2 - 1/2)**2"), x) == x - 1 a = 1 + sqrt(2) assert minimal_polynomial((a*sqrt(2) + a)**3, x) == x**2 - 198*x + 1 p = 1/(1 + sqrt(2) + sqrt(3)) assert minimal_polynomial(p, x, compose=False) == 8*x**4 - 16*x**3 + 4*x**2 + 4*x - 1 p = 2/(1 + sqrt(2) + sqrt(3)) assert minimal_polynomial(p, x, compose=False) == x**4 - 4*x**3 + 2*x**2 + 4*x - 2 assert minimal_polynomial(1 + sqrt(2)*I, x, compose=False) == x**2 - 2*x + 3 assert minimal_polynomial(1/(1 + sqrt(2)) + 1, x, compose=False) == x**2 - 2 assert minimal_polynomial(sqrt(2)*I + I*(1 + sqrt(2)), x, compose=False) == x**4 + 18*x**2 + 49 # minimal polynomial of I assert minimal_polynomial(I, x, domain=QQ.algebraic_field(I)) == x - I K = QQ.algebraic_field(I*(sqrt(2) + 1)) assert minimal_polynomial(I, x, domain=K) == x - I assert minimal_polynomial(I, x, domain=QQ) == x**2 + 1 assert minimal_polynomial(I, x, domain='QQ(y)') == x**2 + 1 #issue 11553 assert minimal_polynomial(GoldenRatio, x) == x**2 - x - 1 assert minimal_polynomial(TribonacciConstant + 3, x) == x**3 - 10*x**2 + 32*x - 34 assert minimal_polynomial(GoldenRatio, x, domain=QQ.algebraic_field(sqrt(5))) == \ 2*x - sqrt(5) - 1 assert minimal_polynomial(TribonacciConstant, x, domain=QQ.algebraic_field(cbrt(19 - 3*sqrt(33)))) == \ 48*x - 19*(19 - 3*sqrt(33))**Rational(2, 3) - 3*sqrt(33)*(19 - 3*sqrt(33))**Rational(2, 3) \ - 16*(19 - 3*sqrt(33))**Rational(1, 3) - 16 # AlgebraicNumber with an alias. # Wester H24 phi = AlgebraicNumber(S.GoldenRatio.expand(func=True), alias='phi') minimal_polynomial(phi, x) == x**2 - x - 1 def test_minimal_polynomial_issue_19732(): # https://github.com/sympy/sympy/issues/19732 expr = (-280898097948878450887044002323982963174671632174995451265117559518123750720061943079105185551006003416773064305074191140286225850817291393988597615/(-488144716373031204149459129212782509078221364279079444636386844223983756114492222145074506571622290776245390771587888364089507840000000*sqrt(238368341569)*sqrt(S(11918417078450)/63568729 - 24411360*sqrt(238368341569)/63568729) + 238326799225996604451373809274348704114327860564921529846705817404208077866956345381951726531296652901169111729944612727047670549086208000000*sqrt(S(11918417078450)/63568729 - 24411360*sqrt(238368341569)/63568729)) - 180561807339168676696180573852937120123827201075968945871075967679148461189459480842956689723484024031016208588658753107/(-59358007109636562851035004992802812513575019937126272896569856090962677491318275291141463850327474176000000*sqrt(238368341569)*sqrt(S(11918417078450)/63568729 - 24411360*sqrt(238368341569)/63568729) + 28980348180319251787320809875930301310576055074938369007463004788921613896002936637780993064387310446267596800000*sqrt(S(11918417078450)/63568729 - 24411360*sqrt(238368341569)/63568729))) poly = (2151288870990266634727173620565483054187142169311153766675688628985237817262915166497766867289157986631135400926544697981091151416655364879773546003475813114962656742744975460025956167152918469472166170500512008351638710934022160294849059721218824490226159355197136265032810944357335461128949781377875451881300105989490353140886315677977149440000000000000000000000*x**4 - 5773274155644072033773937864114266313663195672820501581692669271302387257492905909558846459600429795784309388968498783843631580008547382703258503404023153694528041873101120067477617592651525155101107144042679962433039557235772239171616433004024998230222455940044709064078962397144550855715640331680262171410099614469231080995436488414164502751395405398078353242072696360734131090111239998110773292915337556205692674790561090109440000000000000*x**2 + 211295968822207088328287206509522887719741955693091053353263782924470627623790749534705683380138972642560898936171035770539616881000369889020398551821767092685775598633794696371561234818461806577723412581353857653829324364446419444210520602157621008010129702779407422072249192199762604318993590841636967747488049176548615614290254356975376588506729604345612047361483789518445332415765213187893207704958013682516462853001964919444736320672860140355089) assert minimal_polynomial(expr, x) == poly def test_minimal_polynomial_hi_prec(): p = 1/sqrt(1 - 9*sqrt(2) + 7*sqrt(3) + Rational(1, 10)**30) mp = minimal_polynomial(p, x) # checked with Wolfram Alpha assert mp.coeff(x**6) == -1232000000000000000000000000001223999999999999999999999999999987999999999999999999999999999996000000000000000000000000000000 def test_minimal_polynomial_sq(): from sympy import Add, expand_multinomial p = expand_multinomial((1 + 5*sqrt(2) + 2*sqrt(3))**3) mp = minimal_polynomial(p**Rational(1, 3), x) assert mp == x**4 - 4*x**3 - 118*x**2 + 244*x + 1321 p = expand_multinomial((1 + sqrt(2) - 2*sqrt(3) + sqrt(7))**3) mp = minimal_polynomial(p**Rational(1, 3), x) assert mp == x**8 - 8*x**7 - 56*x**6 + 448*x**5 + 480*x**4 - 5056*x**3 + 1984*x**2 + 7424*x - 3008 p = Add(*[sqrt(i) for i in range(1, 12)]) mp = minimal_polynomial(p, x) assert mp.subs({x: 0}) == -71965773323122507776 def test_minpoly_compose(): # issue 6868 eq = S(''' -1/(800*sqrt(-1/240 + 1/(18000*(-1/17280000 + sqrt(15)*I/28800000)**(1/3)) + 2*(-1/17280000 + sqrt(15)*I/28800000)**(1/3)))''') mp = minimal_polynomial(eq + 3, x) assert mp == 8000*x**2 - 48000*x + 71999 # issue 5888 assert minimal_polynomial(exp(I*pi/8), x) == x**8 + 1 mp = minimal_polynomial(sin(pi/7) + sqrt(2), x) assert mp == 4096*x**12 - 63488*x**10 + 351488*x**8 - 826496*x**6 + \ 770912*x**4 - 268432*x**2 + 28561 mp = minimal_polynomial(cos(pi/7) + sqrt(2), x) assert mp == 64*x**6 - 64*x**5 - 432*x**4 + 304*x**3 + 712*x**2 - \ 232*x - 239 mp = minimal_polynomial(exp(I*pi/7) + sqrt(2), x) assert mp == x**12 - 2*x**11 - 9*x**10 + 16*x**9 + 43*x**8 - 70*x**7 - 97*x**6 + 126*x**5 + 211*x**4 - 212*x**3 - 37*x**2 + 142*x + 127 mp = minimal_polynomial(sin(pi/7) + sqrt(2), x) assert mp == 4096*x**12 - 63488*x**10 + 351488*x**8 - 826496*x**6 + \ 770912*x**4 - 268432*x**2 + 28561 mp = minimal_polynomial(cos(pi/7) + sqrt(2), x) assert mp == 64*x**6 - 64*x**5 - 432*x**4 + 304*x**3 + 712*x**2 - \ 232*x - 239 mp = minimal_polynomial(exp(I*pi/7) + sqrt(2), x) assert mp == x**12 - 2*x**11 - 9*x**10 + 16*x**9 + 43*x**8 - 70*x**7 - 97*x**6 + 126*x**5 + 211*x**4 - 212*x**3 - 37*x**2 + 142*x + 127 mp = minimal_polynomial(exp(I*pi*Rational(2, 7)), x) assert mp == x**6 + x**5 + x**4 + x**3 + x**2 + x + 1 mp = minimal_polynomial(exp(I*pi*Rational(2, 15)), x) assert mp == x**8 - x**7 + x**5 - x**4 + x**3 - x + 1 mp = minimal_polynomial(cos(pi*Rational(2, 7)), x) assert mp == 8*x**3 + 4*x**2 - 4*x - 1 mp = minimal_polynomial(sin(pi*Rational(2, 7)), x) ex = (5*cos(pi*Rational(2, 7)) - 7)/(9*cos(pi/7) - 5*cos(pi*Rational(3, 7))) mp = minimal_polynomial(ex, x) assert mp == x**3 + 2*x**2 - x - 1 assert minimal_polynomial(-1/(2*cos(pi/7)), x) == x**3 + 2*x**2 - x - 1 assert minimal_polynomial(sin(pi*Rational(2, 15)), x) == \ 256*x**8 - 448*x**6 + 224*x**4 - 32*x**2 + 1 assert minimal_polynomial(sin(pi*Rational(5, 14)), x) == 8*x**3 - 4*x**2 - 4*x + 1 assert minimal_polynomial(cos(pi/15), x) == 16*x**4 + 8*x**3 - 16*x**2 - 8*x + 1 ex = rootof(x**3 +x*4 + 1, 0) mp = minimal_polynomial(ex, x) assert mp == x**3 + 4*x + 1 mp = minimal_polynomial(ex + 1, x) assert mp == x**3 - 3*x**2 + 7*x - 4 assert minimal_polynomial(exp(I*pi/3), x) == x**2 - x + 1 assert minimal_polynomial(exp(I*pi/4), x) == x**4 + 1 assert minimal_polynomial(exp(I*pi/6), x) == x**4 - x**2 + 1 assert minimal_polynomial(exp(I*pi/9), x) == x**6 - x**3 + 1 assert minimal_polynomial(exp(I*pi/10), x) == x**8 - x**6 + x**4 - x**2 + 1 assert minimal_polynomial(sin(pi/9), x) == 64*x**6 - 96*x**4 + 36*x**2 - 3 assert minimal_polynomial(sin(pi/11), x) == 1024*x**10 - 2816*x**8 + \ 2816*x**6 - 1232*x**4 + 220*x**2 - 11 ex = 2**Rational(1, 3)*exp(Rational(2, 3)*I*pi) assert minimal_polynomial(ex, x) == x**3 - 2 raises(NotAlgebraic, lambda: minimal_polynomial(cos(pi*sqrt(2)), x)) raises(NotAlgebraic, lambda: minimal_polynomial(sin(pi*sqrt(2)), x)) raises(NotAlgebraic, lambda: minimal_polynomial(exp(I*pi*sqrt(2)), x)) # issue 5934 ex = 1/(-36000 - 7200*sqrt(5) + (12*sqrt(10)*sqrt(sqrt(5) + 5) + 24*sqrt(10)*sqrt(-sqrt(5) + 5))**2) + 1 raises(ZeroDivisionError, lambda: minimal_polynomial(ex, x)) ex = sqrt(1 + 2**Rational(1,3)) + sqrt(1 + 2**Rational(1,4)) + sqrt(2) mp = minimal_polynomial(ex, x) assert degree(mp) == 48 and mp.subs({x:0}) == -16630256576 ex = tan(pi/5, evaluate=False) mp = minimal_polynomial(ex, x) assert mp == x**4 - 10*x**2 + 5 assert mp.subs(x, tan(pi/5)).is_zero ex = tan(pi/6, evaluate=False) mp = minimal_polynomial(ex, x) assert mp == 3*x**2 - 1 assert mp.subs(x, tan(pi/6)).is_zero ex = tan(pi/10, evaluate=False) mp = minimal_polynomial(ex, x) assert mp == 5*x**4 - 10*x**2 + 1 assert mp.subs(x, tan(pi/10)).is_zero raises(NotAlgebraic, lambda: minimal_polynomial(tan(pi*sqrt(2)), x)) def test_minpoly_issue_7113(): # see discussion in https://github.com/sympy/sympy/pull/2234 from sympy.simplify.simplify import nsimplify r = nsimplify(pi, tolerance=0.000000001) mp = minimal_polynomial(r, x) assert mp == 1768292677839237920489538677417507171630859375*x**109 - \ 2734577732179183863586489182929671773182898498218854181690460140337930774573792597743853652058046464 def test_minpoly_issue_7574(): ex = -(-1)**Rational(1, 3) + (-1)**Rational(2,3) assert minimal_polynomial(ex, x) == x + 1 def test_choose_factor(): # Test that this does not enter an infinite loop: bad_factors = [Poly(x-2, x), Poly(x+2, x)] raises(NotImplementedError, lambda: _choose_factor(bad_factors, x, sqrt(3))) def test_primitive_element(): assert primitive_element([sqrt(2)], x) == (x**2 - 2, [1]) assert primitive_element( [sqrt(2), sqrt(3)], x) == (x**4 - 10*x**2 + 1, [1, 1]) assert primitive_element([sqrt(2)], x, polys=True) == (Poly(x**2 - 2, domain='QQ'), [1]) assert primitive_element([sqrt( 2), sqrt(3)], x, polys=True) == (Poly(x**4 - 10*x**2 + 1, domain='QQ'), [1, 1]) assert primitive_element( [sqrt(2)], x, ex=True) == (x**2 - 2, [1], [[1, 0]]) assert primitive_element([sqrt(2), sqrt(3)], x, ex=True) == \ (x**4 - 10*x**2 + 1, [1, 1], [[Q(1, 2), 0, -Q(9, 2), 0], [- Q(1, 2), 0, Q(11, 2), 0]]) assert primitive_element( [sqrt(2)], x, ex=True, polys=True) == (Poly(x**2 - 2, domain='QQ'), [1], [[1, 0]]) assert primitive_element([sqrt(2), sqrt(3)], x, ex=True, polys=True) == \ (Poly(x**4 - 10*x**2 + 1, domain='QQ'), [1, 1], [[Q(1, 2), 0, -Q(9, 2), 0], [-Q(1, 2), 0, Q(11, 2), 0]]) assert primitive_element([sqrt(2)], polys=True) == (Poly(x**2 - 2), [1]) raises(ValueError, lambda: primitive_element([], x, ex=False)) raises(ValueError, lambda: primitive_element([], x, ex=True)) # Issue 14117 a, b = I*sqrt(2*sqrt(2) + 3), I*sqrt(-2*sqrt(2) + 3) assert primitive_element([a, b, I], x) == (x**4 + 6*x**2 + 1, [1, 0, 0]) def test_field_isomorphism_pslq(): a = AlgebraicNumber(I) b = AlgebraicNumber(I*sqrt(3)) raises(NotImplementedError, lambda: field_isomorphism_pslq(a, b)) a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(3)) c = AlgebraicNumber(sqrt(7)) d = AlgebraicNumber(sqrt(2) + sqrt(3)) e = AlgebraicNumber(sqrt(2) + sqrt(3) + sqrt(7)) assert field_isomorphism_pslq(a, a) == [1, 0] assert field_isomorphism_pslq(a, b) is None assert field_isomorphism_pslq(a, c) is None assert field_isomorphism_pslq(a, d) == [Q(1, 2), 0, -Q(9, 2), 0] assert field_isomorphism_pslq( a, e) == [Q(1, 80), 0, -Q(1, 2), 0, Q(59, 20), 0] assert field_isomorphism_pslq(b, a) is None assert field_isomorphism_pslq(b, b) == [1, 0] assert field_isomorphism_pslq(b, c) is None assert field_isomorphism_pslq(b, d) == [-Q(1, 2), 0, Q(11, 2), 0] assert field_isomorphism_pslq(b, e) == [-Q( 3, 640), 0, Q(67, 320), 0, -Q(297, 160), 0, Q(313, 80), 0] assert field_isomorphism_pslq(c, a) is None assert field_isomorphism_pslq(c, b) is None assert field_isomorphism_pslq(c, c) == [1, 0] assert field_isomorphism_pslq(c, d) is None assert field_isomorphism_pslq(c, e) == [Q( 3, 640), 0, -Q(71, 320), 0, Q(377, 160), 0, -Q(469, 80), 0] assert field_isomorphism_pslq(d, a) is None assert field_isomorphism_pslq(d, b) is None assert field_isomorphism_pslq(d, c) is None assert field_isomorphism_pslq(d, d) == [1, 0] assert field_isomorphism_pslq(d, e) == [-Q( 3, 640), 0, Q(71, 320), 0, -Q(377, 160), 0, Q(549, 80), 0] assert field_isomorphism_pslq(e, a) is None assert field_isomorphism_pslq(e, b) is None assert field_isomorphism_pslq(e, c) is None assert field_isomorphism_pslq(e, d) is None assert field_isomorphism_pslq(e, e) == [1, 0] f = AlgebraicNumber(3*sqrt(2) + 8*sqrt(7) - 5) assert field_isomorphism_pslq( f, e) == [Q(3, 80), 0, -Q(139, 80), 0, Q(347, 20), 0, -Q(761, 20), -5] def test_field_isomorphism(): assert field_isomorphism(3, sqrt(2)) == [3] assert field_isomorphism( I*sqrt(3), I*sqrt(3)/2) == [ 2, 0] assert field_isomorphism(-I*sqrt(3), I*sqrt(3)/2) == [-2, 0] assert field_isomorphism( I*sqrt(3), -I*sqrt(3)/2) == [-2, 0] assert field_isomorphism(-I*sqrt(3), -I*sqrt(3)/2) == [ 2, 0] assert field_isomorphism( 2*I*sqrt(3)/7, 5*I*sqrt(3)/3) == [ Rational(6, 35), 0] assert field_isomorphism(-2*I*sqrt(3)/7, 5*I*sqrt(3)/3) == [Rational(-6, 35), 0] assert field_isomorphism( 2*I*sqrt(3)/7, -5*I*sqrt(3)/3) == [Rational(-6, 35), 0] assert field_isomorphism(-2*I*sqrt(3)/7, -5*I*sqrt(3)/3) == [ Rational(6, 35), 0] assert field_isomorphism( 2*I*sqrt(3)/7 + 27, 5*I*sqrt(3)/3) == [ Rational(6, 35), 27] assert field_isomorphism( -2*I*sqrt(3)/7 + 27, 5*I*sqrt(3)/3) == [Rational(-6, 35), 27] assert field_isomorphism( 2*I*sqrt(3)/7 + 27, -5*I*sqrt(3)/3) == [Rational(-6, 35), 27] assert field_isomorphism( -2*I*sqrt(3)/7 + 27, -5*I*sqrt(3)/3) == [ Rational(6, 35), 27] p = AlgebraicNumber( sqrt(2) + sqrt(3)) q = AlgebraicNumber(-sqrt(2) + sqrt(3)) r = AlgebraicNumber( sqrt(2) - sqrt(3)) s = AlgebraicNumber(-sqrt(2) - sqrt(3)) pos_coeffs = [ S.Half, S.Zero, Rational(-9, 2), S.Zero] neg_coeffs = [Rational(-1, 2), S.Zero, Rational(9, 2), S.Zero] a = AlgebraicNumber(sqrt(2)) assert is_isomorphism_possible(a, p) is True assert is_isomorphism_possible(a, q) is True assert is_isomorphism_possible(a, r) is True assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == pos_coeffs assert field_isomorphism(a, q, fast=True) == neg_coeffs assert field_isomorphism(a, r, fast=True) == pos_coeffs assert field_isomorphism(a, s, fast=True) == neg_coeffs assert field_isomorphism(a, p, fast=False) == pos_coeffs assert field_isomorphism(a, q, fast=False) == neg_coeffs assert field_isomorphism(a, r, fast=False) == pos_coeffs assert field_isomorphism(a, s, fast=False) == neg_coeffs a = AlgebraicNumber(-sqrt(2)) assert is_isomorphism_possible(a, p) is True assert is_isomorphism_possible(a, q) is True assert is_isomorphism_possible(a, r) is True assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == neg_coeffs assert field_isomorphism(a, q, fast=True) == pos_coeffs assert field_isomorphism(a, r, fast=True) == neg_coeffs assert field_isomorphism(a, s, fast=True) == pos_coeffs assert field_isomorphism(a, p, fast=False) == neg_coeffs assert field_isomorphism(a, q, fast=False) == pos_coeffs assert field_isomorphism(a, r, fast=False) == neg_coeffs assert field_isomorphism(a, s, fast=False) == pos_coeffs pos_coeffs = [ S.Half, S.Zero, Rational(-11, 2), S.Zero] neg_coeffs = [Rational(-1, 2), S.Zero, Rational(11, 2), S.Zero] a = AlgebraicNumber(sqrt(3)) assert is_isomorphism_possible(a, p) is True assert is_isomorphism_possible(a, q) is True assert is_isomorphism_possible(a, r) is True assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == neg_coeffs assert field_isomorphism(a, q, fast=True) == neg_coeffs assert field_isomorphism(a, r, fast=True) == pos_coeffs assert field_isomorphism(a, s, fast=True) == pos_coeffs assert field_isomorphism(a, p, fast=False) == neg_coeffs assert field_isomorphism(a, q, fast=False) == neg_coeffs assert field_isomorphism(a, r, fast=False) == pos_coeffs assert field_isomorphism(a, s, fast=False) == pos_coeffs a = AlgebraicNumber(-sqrt(3)) assert is_isomorphism_possible(a, p) is True assert is_isomorphism_possible(a, q) is True assert is_isomorphism_possible(a, r) is True assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == pos_coeffs assert field_isomorphism(a, q, fast=True) == pos_coeffs assert field_isomorphism(a, r, fast=True) == neg_coeffs assert field_isomorphism(a, s, fast=True) == neg_coeffs assert field_isomorphism(a, p, fast=False) == pos_coeffs assert field_isomorphism(a, q, fast=False) == pos_coeffs assert field_isomorphism(a, r, fast=False) == neg_coeffs assert field_isomorphism(a, s, fast=False) == neg_coeffs pos_coeffs = [ Rational(3, 2), S.Zero, Rational(-33, 2), -S(8)] neg_coeffs = [Rational(-3, 2), S.Zero, Rational(33, 2), -S(8)] a = AlgebraicNumber(3*sqrt(3) - 8) assert is_isomorphism_possible(a, p) is True assert is_isomorphism_possible(a, q) is True assert is_isomorphism_possible(a, r) is True assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == neg_coeffs assert field_isomorphism(a, q, fast=True) == neg_coeffs assert field_isomorphism(a, r, fast=True) == pos_coeffs assert field_isomorphism(a, s, fast=True) == pos_coeffs assert field_isomorphism(a, p, fast=False) == neg_coeffs assert field_isomorphism(a, q, fast=False) == neg_coeffs assert field_isomorphism(a, r, fast=False) == pos_coeffs assert field_isomorphism(a, s, fast=False) == pos_coeffs a = AlgebraicNumber(3*sqrt(2) + 2*sqrt(3) + 1) pos_1_coeffs = [ S.Half, S.Zero, Rational(-5, 2), S.One] neg_5_coeffs = [Rational(-5, 2), S.Zero, Rational(49, 2), S.One] pos_5_coeffs = [ Rational(5, 2), S.Zero, Rational(-49, 2), S.One] neg_1_coeffs = [Rational(-1, 2), S.Zero, Rational(5, 2), S.One] assert is_isomorphism_possible(a, p) is True assert is_isomorphism_possible(a, q) is True assert is_isomorphism_possible(a, r) is True assert is_isomorphism_possible(a, s) is True assert field_isomorphism(a, p, fast=True) == pos_1_coeffs assert field_isomorphism(a, q, fast=True) == neg_5_coeffs assert field_isomorphism(a, r, fast=True) == pos_5_coeffs assert field_isomorphism(a, s, fast=True) == neg_1_coeffs assert field_isomorphism(a, p, fast=False) == pos_1_coeffs assert field_isomorphism(a, q, fast=False) == neg_5_coeffs assert field_isomorphism(a, r, fast=False) == pos_5_coeffs assert field_isomorphism(a, s, fast=False) == neg_1_coeffs a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(3)) c = AlgebraicNumber(sqrt(7)) assert is_isomorphism_possible(a, b) is True assert is_isomorphism_possible(b, a) is True assert is_isomorphism_possible(c, p) is False assert field_isomorphism(sqrt(2), sqrt(3), fast=True) is None assert field_isomorphism(sqrt(3), sqrt(2), fast=True) is None assert field_isomorphism(sqrt(2), sqrt(3), fast=False) is None assert field_isomorphism(sqrt(3), sqrt(2), fast=False) is None def test_to_number_field(): assert to_number_field(sqrt(2)) == AlgebraicNumber(sqrt(2)) assert to_number_field( [sqrt(2), sqrt(3)]) == AlgebraicNumber(sqrt(2) + sqrt(3)) a = AlgebraicNumber(sqrt(2) + sqrt(3), [S.Half, S.Zero, Rational(-9, 2), S.Zero]) assert to_number_field(sqrt(2), sqrt(2) + sqrt(3)) == a assert to_number_field(sqrt(2), AlgebraicNumber(sqrt(2) + sqrt(3))) == a raises(IsomorphismFailed, lambda: to_number_field(sqrt(2), sqrt(3))) def test_AlgebraicNumber(): minpoly, root = x**2 - 2, sqrt(2) a = AlgebraicNumber(root, gen=x) assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False assert a.coeffs() == [S.One, S.Zero] assert a.native_coeffs() == [QQ(1), QQ(0)] a = AlgebraicNumber(root, gen=x, alias='y') assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias == Symbol('y') assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is True a = AlgebraicNumber(root, gen=x, alias=Symbol('y')) assert a.rep == DMP([QQ(1), QQ(0)], QQ) assert a.root == root assert a.alias == Symbol('y') assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is True assert AlgebraicNumber(sqrt(2), []).rep == DMP([], QQ) assert AlgebraicNumber(sqrt(2), ()).rep == DMP([], QQ) assert AlgebraicNumber(sqrt(2), (0, 0)).rep == DMP([], QQ) assert AlgebraicNumber(sqrt(2), [8]).rep == DMP([QQ(8)], QQ) assert AlgebraicNumber(sqrt(2), [Rational(8, 3)]).rep == DMP([QQ(8, 3)], QQ) assert AlgebraicNumber(sqrt(2), [7, 3]).rep == DMP([QQ(7), QQ(3)], QQ) assert AlgebraicNumber( sqrt(2), [Rational(7, 9), Rational(3, 2)]).rep == DMP([QQ(7, 9), QQ(3, 2)], QQ) assert AlgebraicNumber(sqrt(2), [1, 2, 3]).rep == DMP([QQ(2), QQ(5)], QQ) a = AlgebraicNumber(AlgebraicNumber(root, gen=x), [1, 2]) assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False assert a.coeffs() == [S.One, S(2)] assert a.native_coeffs() == [QQ(1), QQ(2)] a = AlgebraicNumber((minpoly, root), [1, 2]) assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False a = AlgebraicNumber((Poly(minpoly), root), [1, 2]) assert a.rep == DMP([QQ(1), QQ(2)], QQ) assert a.root == root assert a.alias is None assert a.minpoly == minpoly assert a.is_number assert a.is_aliased is False assert AlgebraicNumber( sqrt(3)).rep == DMP([ QQ(1), QQ(0)], QQ) assert AlgebraicNumber(-sqrt(3)).rep == DMP([ QQ(1), QQ(0)], QQ) a = AlgebraicNumber(sqrt(2)) b = AlgebraicNumber(sqrt(2)) assert a == b c = AlgebraicNumber(sqrt(2), gen=x) assert a == b assert a == c a = AlgebraicNumber(sqrt(2), [1, 2]) b = AlgebraicNumber(sqrt(2), [1, 3]) assert a != b and a != sqrt(2) + 3 assert (a == x) is False and (a != x) is True a = AlgebraicNumber(sqrt(2), [1, 0]) b = AlgebraicNumber(sqrt(2), [1, 0], alias=y) assert a.as_poly(x) == Poly(x, domain='QQ') assert b.as_poly() == Poly(y, domain='QQ') assert a.as_expr() == sqrt(2) assert a.as_expr(x) == x assert b.as_expr() == sqrt(2) assert b.as_expr(x) == x a = AlgebraicNumber(sqrt(2), [2, 3]) b = AlgebraicNumber(sqrt(2), [2, 3], alias=y) p = a.as_poly() assert p == Poly(2*p.gen + 3) assert a.as_poly(x) == Poly(2*x + 3, domain='QQ') assert b.as_poly() == Poly(2*y + 3, domain='QQ') assert a.as_expr() == 2*sqrt(2) + 3 assert a.as_expr(x) == 2*x + 3 assert b.as_expr() == 2*sqrt(2) + 3 assert b.as_expr(x) == 2*x + 3 a = AlgebraicNumber(sqrt(2)) b = to_number_field(sqrt(2)) assert a.args == b.args == (sqrt(2), Tuple(1, 0)) b = AlgebraicNumber(sqrt(2), alias='alpha') assert b.args == (sqrt(2), Tuple(1, 0), Symbol('alpha')) a = AlgebraicNumber(sqrt(2), [1, 2, 3]) assert a.args == (sqrt(2), Tuple(1, 2, 3)) def test_to_algebraic_integer(): a = AlgebraicNumber(sqrt(3), gen=x).to_algebraic_integer() assert a.minpoly == x**2 - 3 assert a.root == sqrt(3) assert a.rep == DMP([QQ(1), QQ(0)], QQ) a = AlgebraicNumber(2*sqrt(3), gen=x).to_algebraic_integer() assert a.minpoly == x**2 - 12 assert a.root == 2*sqrt(3) assert a.rep == DMP([QQ(1), QQ(0)], QQ) a = AlgebraicNumber(sqrt(3)/2, gen=x).to_algebraic_integer() assert a.minpoly == x**2 - 12 assert a.root == 2*sqrt(3) assert a.rep == DMP([QQ(1), QQ(0)], QQ) a = AlgebraicNumber(sqrt(3)/2, [Rational(7, 19), 3], gen=x).to_algebraic_integer() assert a.minpoly == x**2 - 12 assert a.root == 2*sqrt(3) assert a.rep == DMP([QQ(7, 19), QQ(3)], QQ) def test_IntervalPrinter(): ip = IntervalPrinter() assert ip.doprint(x**Q(1, 3)) == "x**(mpi('1/3'))" assert ip.doprint(sqrt(x)) == "x**(mpi('1/2'))" def test_isolate(): assert isolate(1) == (1, 1) assert isolate(S.Half) == (S.Half, S.Half) assert isolate(sqrt(2)) == (1, 2) assert isolate(-sqrt(2)) == (-2, -1) assert isolate(sqrt(2), eps=Rational(1, 100)) == (Rational(24, 17), Rational(17, 12)) assert isolate(-sqrt(2), eps=Rational(1, 100)) == (Rational(-17, 12), Rational(-24, 17)) raises(NotImplementedError, lambda: isolate(I)) def test_minpoly_fraction_field(): assert minimal_polynomial(1/x, y) == -x*y + 1 assert minimal_polynomial(1 / (x + 1), y) == (x + 1)*y - 1 assert minimal_polynomial(sqrt(x), y) == y**2 - x assert minimal_polynomial(sqrt(x + 1), y) == y**2 - x - 1 assert minimal_polynomial(sqrt(x) / x, y) == x*y**2 - 1 assert minimal_polynomial(sqrt(2) * sqrt(x), y) == y**2 - 2 * x assert minimal_polynomial(sqrt(2) + sqrt(x), y) == \ y**4 + (-2*x - 4)*y**2 + x**2 - 4*x + 4 assert minimal_polynomial(x**Rational(1,3), y) == y**3 - x assert minimal_polynomial(x**Rational(1,3) + sqrt(x), y) == \ y**6 - 3*x*y**4 - 2*x*y**3 + 3*x**2*y**2 - 6*x**2*y - x**3 + x**2 assert minimal_polynomial(sqrt(x) / z, y) == z**2*y**2 - x assert minimal_polynomial(sqrt(x) / (z + 1), y) == (z**2 + 2*z + 1)*y**2 - x assert minimal_polynomial(1/x, y, polys=True) == Poly(-x*y + 1, y, domain='ZZ(x)') assert minimal_polynomial(1 / (x + 1), y, polys=True) == \ Poly((x + 1)*y - 1, y, domain='ZZ(x)') assert minimal_polynomial(sqrt(x), y, polys=True) == Poly(y**2 - x, y, domain='ZZ(x)') assert minimal_polynomial(sqrt(x) / z, y, polys=True) == \ Poly(z**2*y**2 - x, y, domain='ZZ(x, z)') # this is (sqrt(1 + x**3)/x).integrate(x).diff(x) - sqrt(1 + x**3)/x a = sqrt(x)/sqrt(1 + x**(-3)) - sqrt(x**3 + 1)/x + 1/(x**Rational(5, 2)* \ (1 + x**(-3))**Rational(3, 2)) + 1/(x**Rational(11, 2)*(1 + x**(-3))**Rational(3, 2)) assert minimal_polynomial(a, y) == y raises(NotAlgebraic, lambda: minimal_polynomial(exp(x), y)) raises(GeneratorsError, lambda: minimal_polynomial(sqrt(x), x)) raises(GeneratorsError, lambda: minimal_polynomial(sqrt(x) - y, x)) raises(NotImplementedError, lambda: minimal_polynomial(sqrt(x), y, compose=False)) @slow def test_minpoly_fraction_field_slow(): assert minimal_polynomial(minimal_polynomial(sqrt(x**Rational(1,5) - 1), y).subs(y, sqrt(x**Rational(1,5) - 1)), z) == z def test_minpoly_domain(): assert minimal_polynomial(sqrt(2), x, domain=QQ.algebraic_field(sqrt(2))) == \ x - sqrt(2) assert minimal_polynomial(sqrt(8), x, domain=QQ.algebraic_field(sqrt(2))) == \ x - 2*sqrt(2) assert minimal_polynomial(sqrt(Rational(3,2)), x, domain=QQ.algebraic_field(sqrt(2))) == 2*x**2 - 3 raises(NotAlgebraic, lambda: minimal_polynomial(y, x, domain=QQ)) def test_issue_14831(): a = -2*sqrt(2)*sqrt(12*sqrt(2) + 17) assert minimal_polynomial(a, x) == x**2 + 16*x - 8 e = (-3*sqrt(12*sqrt(2) + 17) + 12*sqrt(2) + 17 - 2*sqrt(2)*sqrt(12*sqrt(2) + 17)) assert minimal_polynomial(e, x) == x def test_issue_18248(): assert nonlinsolve([x*y**3-sqrt(2)/3, x*y**6-4/(9*(sqrt(3)))],x,y) == \ FiniteSet((sqrt(3)/2, sqrt(6)/3), (sqrt(3)/2, -sqrt(6)/6 - sqrt(2)*I/2), (sqrt(3)/2, -sqrt(6)/6 + sqrt(2)*I/2)) def test_issue_13230(): c1 = Circle(Point2D(3, sqrt(5)), 5) c2 = Circle(Point2D(4, sqrt(7)), 6) assert intersection(c1, c2) == [Point2D(-1 + (-sqrt(7) + sqrt(5))*(-2*sqrt(7)/29 + 9*sqrt(5)/29 + sqrt(196*sqrt(35) + 1941)/29), -2*sqrt(7)/29 + 9*sqrt(5)/29 + sqrt(196*sqrt(35) + 1941)/29), Point2D(-1 + (-sqrt(7) + sqrt(5))*(-sqrt(196*sqrt(35) + 1941)/29 - 2*sqrt(7)/29 + 9*sqrt(5)/29), -sqrt(196*sqrt(35) + 1941)/29 - 2*sqrt(7)/29 + 9*sqrt(5)/29)] def test_issue_19760(): e = 1/(sqrt(1 + sqrt(2)) - sqrt(2)*sqrt(1 + sqrt(2))) + 1 mp_expected = x**4 - 4*x**3 + 4*x**2 - 2 for comp in (True, False): mp = Poly(minimal_polynomial(e, compose=comp)) assert mp(x) == mp_expected, "minimal_polynomial(e, compose=%s) = %s; %s expected" % (comp, mp(x), mp_expected) def test_issue_20163(): assert apart(1/(x**6+1), extension=[sqrt(3), I]) == \ (sqrt(3) + I)/(2*x + sqrt(3) + I)/6 + \ (sqrt(3) - I)/(2*x + sqrt(3) - I)/6 - \ (sqrt(3) - I)/(2*x - sqrt(3) + I)/6 - \ (sqrt(3) + I)/(2*x - sqrt(3) - I)/6 + \ I/(x + I)/6 - I/(x - I)/6 sympy-sympy-1.9/sympy/polys/tests/test_orderings.py000066400000000000000000000102361412543434000230230ustar00rootroot00000000000000"""Tests of monomial orderings. """ from sympy.polys.orderings import ( monomial_key, lex, grlex, grevlex, ilex, igrlex, LexOrder, InverseOrder, ProductOrder, build_product_order, ) from sympy.abc import x, y, z, t from sympy.core import S from sympy.testing.pytest import raises def test_lex_order(): assert lex((1, 2, 3)) == (1, 2, 3) assert str(lex) == 'lex' assert lex((1, 2, 3)) == lex((1, 2, 3)) assert lex((2, 2, 3)) > lex((1, 2, 3)) assert lex((1, 3, 3)) > lex((1, 2, 3)) assert lex((1, 2, 4)) > lex((1, 2, 3)) assert lex((0, 2, 3)) < lex((1, 2, 3)) assert lex((1, 1, 3)) < lex((1, 2, 3)) assert lex((1, 2, 2)) < lex((1, 2, 3)) assert lex.is_global is True assert lex == LexOrder() assert lex != grlex def test_grlex_order(): assert grlex((1, 2, 3)) == (6, (1, 2, 3)) assert str(grlex) == 'grlex' assert grlex((1, 2, 3)) == grlex((1, 2, 3)) assert grlex((2, 2, 3)) > grlex((1, 2, 3)) assert grlex((1, 3, 3)) > grlex((1, 2, 3)) assert grlex((1, 2, 4)) > grlex((1, 2, 3)) assert grlex((0, 2, 3)) < grlex((1, 2, 3)) assert grlex((1, 1, 3)) < grlex((1, 2, 3)) assert grlex((1, 2, 2)) < grlex((1, 2, 3)) assert grlex((2, 2, 3)) > grlex((1, 2, 4)) assert grlex((1, 3, 3)) > grlex((1, 2, 4)) assert grlex((0, 2, 3)) < grlex((1, 2, 2)) assert grlex((1, 1, 3)) < grlex((1, 2, 2)) assert grlex((0, 1, 1)) > grlex((0, 0, 2)) assert grlex((0, 3, 1)) < grlex((2, 2, 1)) assert grlex.is_global is True def test_grevlex_order(): assert grevlex((1, 2, 3)) == (6, (-3, -2, -1)) assert str(grevlex) == 'grevlex' assert grevlex((1, 2, 3)) == grevlex((1, 2, 3)) assert grevlex((2, 2, 3)) > grevlex((1, 2, 3)) assert grevlex((1, 3, 3)) > grevlex((1, 2, 3)) assert grevlex((1, 2, 4)) > grevlex((1, 2, 3)) assert grevlex((0, 2, 3)) < grevlex((1, 2, 3)) assert grevlex((1, 1, 3)) < grevlex((1, 2, 3)) assert grevlex((1, 2, 2)) < grevlex((1, 2, 3)) assert grevlex((2, 2, 3)) > grevlex((1, 2, 4)) assert grevlex((1, 3, 3)) > grevlex((1, 2, 4)) assert grevlex((0, 2, 3)) < grevlex((1, 2, 2)) assert grevlex((1, 1, 3)) < grevlex((1, 2, 2)) assert grevlex((0, 1, 1)) > grevlex((0, 0, 2)) assert grevlex((0, 3, 1)) < grevlex((2, 2, 1)) assert grevlex.is_global is True def test_InverseOrder(): ilex = InverseOrder(lex) igrlex = InverseOrder(grlex) assert ilex((1, 2, 3)) > ilex((2, 0, 3)) assert igrlex((1, 2, 3)) < igrlex((0, 2, 3)) assert str(ilex) == "ilex" assert str(igrlex) == "igrlex" assert ilex.is_global is False assert igrlex.is_global is False assert ilex != igrlex assert ilex == InverseOrder(LexOrder()) def test_ProductOrder(): P = ProductOrder((grlex, lambda m: m[:2]), (grlex, lambda m: m[2:])) assert P((1, 3, 3, 4, 5)) > P((2, 1, 5, 5, 5)) assert str(P) == "ProductOrder(grlex, grlex)" assert P.is_global is True assert ProductOrder((grlex, None), (ilex, None)).is_global is None assert ProductOrder((igrlex, None), (ilex, None)).is_global is False def test_monomial_key(): assert monomial_key() == lex assert monomial_key('lex') == lex assert monomial_key('grlex') == grlex assert monomial_key('grevlex') == grevlex raises(ValueError, lambda: monomial_key('foo')) raises(ValueError, lambda: monomial_key(1)) M = [x, x**2*z**2, x*y, x**2, S.One, y**2, x**3, y, z, x*y**2*z, x**2*y**2] assert sorted(M, key=monomial_key('lex', [z, y, x])) == \ [S.One, x, x**2, x**3, y, x*y, y**2, x**2*y**2, z, x*y**2*z, x**2*z**2] assert sorted(M, key=monomial_key('grlex', [z, y, x])) == \ [S.One, x, y, z, x**2, x*y, y**2, x**3, x**2*y**2, x*y**2*z, x**2*z**2] assert sorted(M, key=monomial_key('grevlex', [z, y, x])) == \ [S.One, x, y, z, x**2, x*y, y**2, x**3, x**2*y**2, x**2*z**2, x*y**2*z] def test_build_product_order(): assert build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t])((4, 5, 6, 7)) == \ ((9, (4, 5)), (13, (6, 7))) assert build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) == \ build_product_order((("grlex", x, y), ("grlex", z, t)), [x, y, z, t]) sympy-sympy-1.9/sympy/polys/tests/test_orthopolys.py000066400000000000000000000123121412543434000232460ustar00rootroot00000000000000"""Tests for efficient functions for generating orthogonal polynomials. """ from sympy import Poly, S, Rational as Q from sympy.testing.pytest import raises from sympy.polys.orthopolys import ( jacobi_poly, gegenbauer_poly, chebyshevt_poly, chebyshevu_poly, hermite_poly, legendre_poly, laguerre_poly, ) from sympy.abc import x, a, b def test_jacobi_poly(): raises(ValueError, lambda: jacobi_poly(-1, a, b, x)) assert jacobi_poly(1, a, b, x, polys=True) == Poly( (a/2 + b/2 + 1)*x + a/2 - b/2, x, domain='ZZ(a,b)') assert jacobi_poly(0, a, b, x) == 1 assert jacobi_poly(1, a, b, x) == a/2 - b/2 + x*(a/2 + b/2 + 1) assert jacobi_poly(2, a, b, x) == (a**2/8 - a*b/4 - a/8 + b**2/8 - b/8 + x**2*(a**2/8 + a*b/4 + a*Q(7, 8) + b**2/8 + b*Q(7, 8) + Q(3, 2)) + x*(a**2/4 + a*Q(3, 4) - b**2/4 - b*Q(3, 4)) - S.Half) assert jacobi_poly(1, a, b, polys=True) == Poly( (a/2 + b/2 + 1)*x + a/2 - b/2, x, domain='ZZ(a,b)') def test_gegenbauer_poly(): raises(ValueError, lambda: gegenbauer_poly(-1, a, x)) assert gegenbauer_poly( 1, a, x, polys=True) == Poly(2*a*x, x, domain='ZZ(a)') assert gegenbauer_poly(0, a, x) == 1 assert gegenbauer_poly(1, a, x) == 2*a*x assert gegenbauer_poly(2, a, x) == -a + x**2*(2*a**2 + 2*a) assert gegenbauer_poly( 3, a, x) == x**3*(4*a**3/3 + 4*a**2 + a*Q(8, 3)) + x*(-2*a**2 - 2*a) assert gegenbauer_poly(1, S.Half).dummy_eq(x) assert gegenbauer_poly(1, a, polys=True) == Poly(2*a*x, x, domain='ZZ(a)') def test_chebyshevt_poly(): raises(ValueError, lambda: chebyshevt_poly(-1, x)) assert chebyshevt_poly(1, x, polys=True) == Poly(x) assert chebyshevt_poly(0, x) == 1 assert chebyshevt_poly(1, x) == x assert chebyshevt_poly(2, x) == 2*x**2 - 1 assert chebyshevt_poly(3, x) == 4*x**3 - 3*x assert chebyshevt_poly(4, x) == 8*x**4 - 8*x**2 + 1 assert chebyshevt_poly(5, x) == 16*x**5 - 20*x**3 + 5*x assert chebyshevt_poly(6, x) == 32*x**6 - 48*x**4 + 18*x**2 - 1 assert chebyshevt_poly(1).dummy_eq(x) assert chebyshevt_poly(1, polys=True) == Poly(x) def test_chebyshevu_poly(): raises(ValueError, lambda: chebyshevu_poly(-1, x)) assert chebyshevu_poly(1, x, polys=True) == Poly(2*x) assert chebyshevu_poly(0, x) == 1 assert chebyshevu_poly(1, x) == 2*x assert chebyshevu_poly(2, x) == 4*x**2 - 1 assert chebyshevu_poly(3, x) == 8*x**3 - 4*x assert chebyshevu_poly(4, x) == 16*x**4 - 12*x**2 + 1 assert chebyshevu_poly(5, x) == 32*x**5 - 32*x**3 + 6*x assert chebyshevu_poly(6, x) == 64*x**6 - 80*x**4 + 24*x**2 - 1 assert chebyshevu_poly(1).dummy_eq(2*x) assert chebyshevu_poly(1, polys=True) == Poly(2*x) def test_hermite_poly(): raises(ValueError, lambda: hermite_poly(-1, x)) assert hermite_poly(1, x, polys=True) == Poly(2*x) assert hermite_poly(0, x) == 1 assert hermite_poly(1, x) == 2*x assert hermite_poly(2, x) == 4*x**2 - 2 assert hermite_poly(3, x) == 8*x**3 - 12*x assert hermite_poly(4, x) == 16*x**4 - 48*x**2 + 12 assert hermite_poly(5, x) == 32*x**5 - 160*x**3 + 120*x assert hermite_poly(6, x) == 64*x**6 - 480*x**4 + 720*x**2 - 120 assert hermite_poly(1).dummy_eq(2*x) assert hermite_poly(1, polys=True) == Poly(2*x) def test_legendre_poly(): raises(ValueError, lambda: legendre_poly(-1, x)) assert legendre_poly(1, x, polys=True) == Poly(x, domain='QQ') assert legendre_poly(0, x) == 1 assert legendre_poly(1, x) == x assert legendre_poly(2, x) == Q(3, 2)*x**2 - Q(1, 2) assert legendre_poly(3, x) == Q(5, 2)*x**3 - Q(3, 2)*x assert legendre_poly(4, x) == Q(35, 8)*x**4 - Q(30, 8)*x**2 + Q(3, 8) assert legendre_poly(5, x) == Q(63, 8)*x**5 - Q(70, 8)*x**3 + Q(15, 8)*x assert legendre_poly(6, x) == Q( 231, 16)*x**6 - Q(315, 16)*x**4 + Q(105, 16)*x**2 - Q(5, 16) assert legendre_poly(1).dummy_eq(x) assert legendre_poly(1, polys=True) == Poly(x) def test_laguerre_poly(): raises(ValueError, lambda: laguerre_poly(-1, x)) assert laguerre_poly(1, x, polys=True) == Poly(-x + 1, domain='QQ') assert laguerre_poly(0, x) == 1 assert laguerre_poly(1, x) == -x + 1 assert laguerre_poly(2, x) == Q(1, 2)*x**2 - Q(4, 2)*x + 1 assert laguerre_poly(3, x) == -Q(1, 6)*x**3 + Q(9, 6)*x**2 - Q(18, 6)*x + 1 assert laguerre_poly(4, x) == Q( 1, 24)*x**4 - Q(16, 24)*x**3 + Q(72, 24)*x**2 - Q(96, 24)*x + 1 assert laguerre_poly(5, x) == -Q(1, 120)*x**5 + Q(25, 120)*x**4 - Q( 200, 120)*x**3 + Q(600, 120)*x**2 - Q(600, 120)*x + 1 assert laguerre_poly(6, x) == Q(1, 720)*x**6 - Q(36, 720)*x**5 + Q(450, 720)*x**4 - Q(2400, 720)*x**3 + Q(5400, 720)*x**2 - Q(4320, 720)*x + 1 assert laguerre_poly(0, x, a) == 1 assert laguerre_poly(1, x, a) == -x + a + 1 assert laguerre_poly(2, x, a) == x**2/2 + (-a - 2)*x + a**2/2 + a*Q(3, 2) + 1 assert laguerre_poly(3, x, a) == -x**3/6 + (a/2 + Q( 3)/2)*x**2 + (-a**2/2 - a*Q(5, 2) - 3)*x + a**3/6 + a**2 + a*Q(11, 6) + 1 assert laguerre_poly(1).dummy_eq(-x + 1) assert laguerre_poly(1, polys=True) == Poly(-x + 1) sympy-sympy-1.9/sympy/polys/tests/test_partfrac.py000066400000000000000000000153401412543434000226320ustar00rootroot00000000000000"""Tests for algorithms for partial fraction decomposition of rational functions. """ from sympy.polys.partfrac import ( apart_undetermined_coeffs, apart, apart_list, assemble_partfrac_list ) from sympy import (S, Poly, E, pi, I, Matrix, Eq, RootSum, Lambda, Symbol, Dummy, factor, together, sqrt, Expr, Rational) from sympy.testing.pytest import raises, ON_TRAVIS, skip, XFAIL from sympy.abc import x, y, a, b, c def test_apart(): assert apart(1) == 1 assert apart(1, x) == 1 f, g = (x**2 + 1)/(x + 1), 2/(x + 1) + x - 1 assert apart(f, full=False) == g assert apart(f, full=True) == g f, g = 1/(x + 2)/(x + 1), 1/(1 + x) - 1/(2 + x) assert apart(f, full=False) == g assert apart(f, full=True) == g f, g = 1/(x + 1)/(x + 5), -1/(5 + x)/4 + 1/(1 + x)/4 assert apart(f, full=False) == g assert apart(f, full=True) == g assert apart((E*x + 2)/(x - pi)*(x - 1), x) == \ 2 - E + E*pi + E*x + (E*pi + 2)*(pi - 1)/(x - pi) assert apart(Eq((x**2 + 1)/(x + 1), x), x) == Eq(x - 1 + 2/(x + 1), x) assert apart(x/2, y) == x/2 f, g = (x+y)/(2*x - y), Rational(3, 2)*y/(2*x - y) + S.Half assert apart(f, x, full=False) == g assert apart(f, x, full=True) == g f, g = (x+y)/(2*x - y), 3*x/(2*x - y) - 1 assert apart(f, y, full=False) == g assert apart(f, y, full=True) == g raises(NotImplementedError, lambda: apart(1/(x + 1)/(y + 2))) def test_apart_matrix(): M = Matrix(2, 2, lambda i, j: 1/(x + i + 1)/(x + j)) assert apart(M) == Matrix([ [1/x - 1/(x + 1), (x + 1)**(-2)], [1/(2*x) - (S.Half)/(x + 2), 1/(x + 1) - 1/(x + 2)], ]) def test_apart_symbolic(): f = a*x**4 + (2*b + 2*a*c)*x**3 + (4*b*c - a**2 + a*c**2)*x**2 + \ (-2*a*b + 2*b*c**2)*x - b**2 g = a**2*x**4 + (2*a*b + 2*c*a**2)*x**3 + (4*a*b*c + b**2 + a**2*c**2)*x**2 + (2*c*b**2 + 2*a*b*c**2)*x + b**2*c**2 assert apart(f/g, x) == 1/a - 1/(x + c)**2 - b**2/(a*(a*x + b)**2) assert apart(1/((x + a)*(x + b)*(x + c)), x) == \ 1/((a - c)*(b - c)*(c + x)) - 1/((a - b)*(b - c)*(b + x)) + \ 1/((a - b)*(a - c)*(a + x)) def _make_extension_example(): # https://github.com/sympy/sympy/issues/18531 from sympy.core import Mul def mul2(expr): # 2-arg mul hack... return Mul(2, expr, evaluate=False) f = ((x**2 + 1)**3/((x - 1)**2*(x + 1)**2*(-x**2 + 2*x + 1)*(x**2 + 2*x - 1))) g = (1/mul2(x - sqrt(2) + 1) - 1/mul2(x - sqrt(2) - 1) + 1/mul2(x + 1 + sqrt(2)) - 1/mul2(x - 1 + sqrt(2)) + 1/mul2((x + 1)**2) + 1/mul2((x - 1)**2)) return f, g def test_apart_extension(): f = 2/(x**2 + 1) g = I/(x + I) - I/(x - I) assert apart(f, extension=I) == g assert apart(f, gaussian=True) == g f = x/((x - 2)*(x + I)) assert factor(together(apart(f)).expand()) == f f, g = _make_extension_example() # XXX: Only works with dotprodsimp. See test_apart_extension_xfail below from sympy.matrices import dotprodsimp with dotprodsimp(True): assert apart(f, x, extension={sqrt(2)}) == g # XXX: This is XFAIL just because it is slow @XFAIL def test_apart_extension_xfail(): if ON_TRAVIS: skip('Too slow for Travis') f, g = _make_extension_example() assert apart(f, x, extension={sqrt(2)}) == g def test_apart_full(): f = 1/(x**2 + 1) assert apart(f, full=False) == f assert apart(f, full=True).dummy_eq( -RootSum(x**2 + 1, Lambda(a, a/(x - a)), auto=False)/2) f = 1/(x**3 + x + 1) assert apart(f, full=False) == f assert apart(f, full=True).dummy_eq( RootSum(x**3 + x + 1, Lambda(a, (a**2*Rational(6, 31) - a*Rational(9, 31) + Rational(4, 31))/(x - a)), auto=False)) f = 1/(x**5 + 1) assert apart(f, full=False) == \ (Rational(-1, 5))*((x**3 - 2*x**2 + 3*x - 4)/(x**4 - x**3 + x**2 - x + 1)) + (Rational(1, 5))/(x + 1) assert apart(f, full=True).dummy_eq( -RootSum(x**4 - x**3 + x**2 - x + 1, Lambda(a, a/(x - a)), auto=False)/5 + (Rational(1, 5))/(x + 1)) def test_apart_undetermined_coeffs(): p = Poly(2*x - 3) q = Poly(x**9 - x**8 - x**6 + x**5 - 2*x**2 + 3*x - 1) r = (-x**7 - x**6 - x**5 + 4)/(x**8 - x**5 - 2*x + 1) + 1/(x - 1) assert apart_undetermined_coeffs(p, q) == r p = Poly(1, x, domain='ZZ[a,b]') q = Poly((x + a)*(x + b), x, domain='ZZ[a,b]') r = 1/((a - b)*(b + x)) - 1/((a - b)*(a + x)) assert apart_undetermined_coeffs(p, q) == r def test_apart_list(): from sympy.utilities.iterables import numbered_symbols def dummy_eq(i, j): if type(i) in (list, tuple): return all(dummy_eq(i, j) for i, j in zip(i, j)) return i == j or i.dummy_eq(j) w0, w1, w2 = Symbol("w0"), Symbol("w1"), Symbol("w2") _a = Dummy("a") f = (-2*x - 2*x**2) / (3*x**2 - 6*x) got = apart_list(f, x, dummies=numbered_symbols("w")) ans = (-1, Poly(Rational(2, 3), x, domain='QQ'), [(Poly(w0 - 2, w0, domain='ZZ'), Lambda(_a, 2), Lambda(_a, -_a + x), 1)]) assert dummy_eq(got, ans) got = apart_list(2/(x**2-2), x, dummies=numbered_symbols("w")) ans = (1, Poly(0, x, domain='ZZ'), [(Poly(w0**2 - 2, w0, domain='ZZ'), Lambda(_a, _a/2), Lambda(_a, -_a + x), 1)]) assert dummy_eq(got, ans) f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) got = apart_list(f, x, dummies=numbered_symbols("w")) ans = (1, Poly(0, x, domain='ZZ'), [(Poly(w0 - 2, w0, domain='ZZ'), Lambda(_a, 4), Lambda(_a, -_a + x), 1), (Poly(w1**2 - 1, w1, domain='ZZ'), Lambda(_a, -3*_a - 6), Lambda(_a, -_a + x), 2), (Poly(w2 + 1, w2, domain='ZZ'), Lambda(_a, -4), Lambda(_a, -_a + x), 1)]) assert dummy_eq(got, ans) def test_assemble_partfrac_list(): f = 36 / (x**5 - 2*x**4 - 2*x**3 + 4*x**2 + x - 2) pfd = apart_list(f) assert assemble_partfrac_list(pfd) == -4/(x + 1) - 3/(x + 1)**2 - 9/(x - 1)**2 + 4/(x - 2) a = Dummy("a") pfd = (1, Poly(0, x, domain='ZZ'), [([sqrt(2),-sqrt(2)], Lambda(a, a/2), Lambda(a, -a + x), 1)]) assert assemble_partfrac_list(pfd) == -1/(sqrt(2)*(x + sqrt(2))) + 1/(sqrt(2)*(x - sqrt(2))) @XFAIL def test_noncommutative_pseudomultivariate(): # apart doesn't go inside noncommutative expressions class foo(Expr): is_commutative=False e = x/(x + x*y) c = 1/(1 + y) assert apart(e + foo(e)) == c + foo(c) assert apart(e*foo(e)) == c*foo(c) def test_noncommutative(): class foo(Expr): is_commutative=False e = x/(x + x*y) c = 1/(1 + y) assert apart(e + foo()) == c + foo() def test_issue_5798(): assert apart( 2*x/(x**2 + 1) - (x - 1)/(2*(x**2 + 1)) + 1/(2*(x + 1)) - 2/x) == \ (3*x + 1)/(x**2 + 1)/2 + 1/(x + 1)/2 - 2/x sympy-sympy-1.9/sympy/polys/tests/test_polyclasses.py000066400000000000000000000314161412543434000233730ustar00rootroot00000000000000"""Tests for OO layer of several polynomial representations. """ from sympy.polys.domains import ZZ, QQ from sympy.polys.polyclasses import DMP, DMF, ANP from sympy.polys.polyerrors import ExactQuotientFailed, NotInvertible from sympy.polys.specialpolys import f_polys from sympy.testing.pytest import raises f_0, f_1, f_2, f_3, f_4, f_5, f_6 = [ f.to_dense() for f in f_polys() ] def test_DMP___init__(): f = DMP([[0], [], [0, 1, 2], [3]], ZZ) assert f.rep == [[1, 2], [3]] assert f.dom == ZZ assert f.lev == 1 f = DMP([[1, 2], [3]], ZZ, 1) assert f.rep == [[1, 2], [3]] assert f.dom == ZZ assert f.lev == 1 f = DMP({(1, 1): 1, (0, 0): 2}, ZZ, 1) assert f.rep == [[1, 0], [2]] assert f.dom == ZZ assert f.lev == 1 def test_DMP___eq__(): assert DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) == \ DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) assert DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) == \ DMP([[QQ(1), QQ(2)], [QQ(3)]], QQ) assert DMP([[QQ(1), QQ(2)], [QQ(3)]], QQ) == \ DMP([[ZZ(1), ZZ(2)], [ZZ(3)]], ZZ) assert DMP([[[ZZ(1)]]], ZZ) != DMP([[ZZ(1)]], ZZ) assert DMP([[ZZ(1)]], ZZ) != DMP([[[ZZ(1)]]], ZZ) def test_DMP___bool__(): assert bool(DMP([[]], ZZ)) is False assert bool(DMP([[1]], ZZ)) is True def test_DMP_to_dict(): f = DMP([[3], [], [2], [], [8]], ZZ) assert f.to_dict() == \ {(4, 0): 3, (2, 0): 2, (0, 0): 8} assert f.to_sympy_dict() == \ {(4, 0): ZZ.to_sympy(3), (2, 0): ZZ.to_sympy(2), (0, 0): ZZ.to_sympy(8)} def test_DMP_properties(): assert DMP([[]], ZZ).is_zero is True assert DMP([[1]], ZZ).is_zero is False assert DMP([[1]], ZZ).is_one is True assert DMP([[2]], ZZ).is_one is False assert DMP([[1]], ZZ).is_ground is True assert DMP([[1], [2], [1]], ZZ).is_ground is False assert DMP([[1], [2, 0], [1, 0]], ZZ).is_sqf is True assert DMP([[1], [2, 0], [1, 0, 0]], ZZ).is_sqf is False assert DMP([[1, 2], [3]], ZZ).is_monic is True assert DMP([[2, 2], [3]], ZZ).is_monic is False assert DMP([[1, 2], [3]], ZZ).is_primitive is True assert DMP([[2, 4], [6]], ZZ).is_primitive is False def test_DMP_arithmetics(): f = DMP([[2], [2, 0]], ZZ) assert f.mul_ground(2) == DMP([[4], [4, 0]], ZZ) assert f.quo_ground(2) == DMP([[1], [1, 0]], ZZ) raises(ExactQuotientFailed, lambda: f.exquo_ground(3)) f = DMP([[-5]], ZZ) g = DMP([[5]], ZZ) assert f.abs() == g assert abs(f) == g assert g.neg() == f assert -g == f h = DMP([[]], ZZ) assert f.add(g) == h assert f + g == h assert g + f == h assert f + 5 == h assert 5 + f == h h = DMP([[-10]], ZZ) assert f.sub(g) == h assert f - g == h assert g - f == -h assert f - 5 == h assert 5 - f == -h h = DMP([[-25]], ZZ) assert f.mul(g) == h assert f * g == h assert g * f == h assert f * 5 == h assert 5 * f == h h = DMP([[25]], ZZ) assert f.sqr() == h assert f.pow(2) == h assert f**2 == h raises(TypeError, lambda: f.pow('x')) f = DMP([[1], [], [1, 0, 0]], ZZ) g = DMP([[2], [-2, 0]], ZZ) q = DMP([[2], [2, 0]], ZZ) r = DMP([[8, 0, 0]], ZZ) assert f.pdiv(g) == (q, r) assert f.pquo(g) == q assert f.prem(g) == r raises(ExactQuotientFailed, lambda: f.pexquo(g)) f = DMP([[1], [], [1, 0, 0]], ZZ) g = DMP([[1], [-1, 0]], ZZ) q = DMP([[1], [1, 0]], ZZ) r = DMP([[2, 0, 0]], ZZ) assert f.div(g) == (q, r) assert f.quo(g) == q assert f.rem(g) == r assert divmod(f, g) == (q, r) assert f // g == q assert f % g == r raises(ExactQuotientFailed, lambda: f.exquo(g)) def test_DMP_functionality(): f = DMP([[1], [2, 0], [1, 0, 0]], ZZ) g = DMP([[1], [1, 0]], ZZ) h = DMP([[1]], ZZ) assert f.degree() == 2 assert f.degree_list() == (2, 2) assert f.total_degree() == 2 assert f.LC() == ZZ(1) assert f.TC() == ZZ(0) assert f.nth(1, 1) == ZZ(2) raises(TypeError, lambda: f.nth(0, 'x')) assert f.max_norm() == 2 assert f.l1_norm() == 4 u = DMP([[2], [2, 0]], ZZ) assert f.diff(m=1, j=0) == u assert f.diff(m=1, j=1) == u raises(TypeError, lambda: f.diff(m='x', j=0)) u = DMP([1, 2, 1], ZZ) v = DMP([1, 2, 1], ZZ) assert f.eval(a=1, j=0) == u assert f.eval(a=1, j=1) == v assert f.eval(1).eval(1) == ZZ(4) assert f.cofactors(g) == (g, g, h) assert f.gcd(g) == g assert f.lcm(g) == f u = DMP([[QQ(45), QQ(30), QQ(5)]], QQ) v = DMP([[QQ(1), QQ(2, 3), QQ(1, 9)]], QQ) assert u.monic() == v assert (4*f).content() == ZZ(4) assert (4*f).primitive() == (ZZ(4), f) f = DMP([[1], [2], [3], [4], [5], [6]], ZZ) assert f.trunc(3) == DMP([[1], [-1], [], [1], [-1], []], ZZ) f = DMP(f_4, ZZ) assert f.sqf_part() == -f assert f.sqf_list() == (ZZ(-1), [(-f, 1)]) f = DMP([[-1], [], [], [5]], ZZ) g = DMP([[3, 1], [], []], ZZ) h = DMP([[45, 30, 5]], ZZ) r = DMP([675, 675, 225, 25], ZZ) assert f.subresultants(g) == [f, g, h] assert f.resultant(g) == r f = DMP([1, 3, 9, -13], ZZ) assert f.discriminant() == -11664 f = DMP([QQ(2), QQ(0)], QQ) g = DMP([QQ(1), QQ(0), QQ(-16)], QQ) s = DMP([QQ(1, 32), QQ(0)], QQ) t = DMP([QQ(-1, 16)], QQ) h = DMP([QQ(1)], QQ) assert f.half_gcdex(g) == (s, h) assert f.gcdex(g) == (s, t, h) assert f.invert(g) == s f = DMP([[1], [2], [3]], QQ) raises(ValueError, lambda: f.half_gcdex(f)) raises(ValueError, lambda: f.gcdex(f)) raises(ValueError, lambda: f.invert(f)) f = DMP([1, 0, 20, 0, 150, 0, 500, 0, 625, -2, 0, -10, 9], ZZ) g = DMP([1, 0, 0, -2, 9], ZZ) h = DMP([1, 0, 5, 0], ZZ) assert g.compose(h) == f assert f.decompose() == [g, h] f = DMP([[1], [2], [3]], QQ) raises(ValueError, lambda: f.decompose()) raises(ValueError, lambda: f.sturm()) def test_DMP_exclude(): f = [[[[[[[[[[[[[[[[[[[[[[[[[[1]], [[]]]]]]]]]]]]]]]]]]]]]]]]]] J = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 24, 25] assert DMP(f, ZZ).exclude() == (J, DMP([1, 0], ZZ)) assert DMP([[1], [1, 0]], ZZ).exclude() == ([], DMP([[1], [1, 0]], ZZ)) def test_DMF__init__(): f = DMF(([[0], [], [0, 1, 2], [3]], [[1, 2, 3]]), ZZ) assert f.num == [[1, 2], [3]] assert f.den == [[1, 2, 3]] assert f.lev == 1 assert f.dom == ZZ f = DMF(([[1, 2], [3]], [[1, 2, 3]]), ZZ, 1) assert f.num == [[1, 2], [3]] assert f.den == [[1, 2, 3]] assert f.lev == 1 assert f.dom == ZZ f = DMF(([[-1], [-2]], [[3], [-4]]), ZZ) assert f.num == [[-1], [-2]] assert f.den == [[3], [-4]] assert f.lev == 1 assert f.dom == ZZ f = DMF(([[1], [2]], [[-3], [4]]), ZZ) assert f.num == [[-1], [-2]] assert f.den == [[3], [-4]] assert f.lev == 1 assert f.dom == ZZ f = DMF(([[1], [2]], [[-3], [4]]), ZZ) assert f.num == [[-1], [-2]] assert f.den == [[3], [-4]] assert f.lev == 1 assert f.dom == ZZ f = DMF(([[]], [[-3], [4]]), ZZ) assert f.num == [[]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ f = DMF(17, ZZ, 1) assert f.num == [[17]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ f = DMF(([[1], [2]]), ZZ) assert f.num == [[1], [2]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ f = DMF([[0], [], [0, 1, 2], [3]], ZZ) assert f.num == [[1, 2], [3]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ f = DMF({(1, 1): 1, (0, 0): 2}, ZZ, 1) assert f.num == [[1, 0], [2]] assert f.den == [[1]] assert f.lev == 1 assert f.dom == ZZ f = DMF(([[QQ(1)], [QQ(2)]], [[-QQ(3)], [QQ(4)]]), QQ) assert f.num == [[-QQ(1)], [-QQ(2)]] assert f.den == [[QQ(3)], [-QQ(4)]] assert f.lev == 1 assert f.dom == QQ f = DMF(([[QQ(1, 5)], [QQ(2, 5)]], [[-QQ(3, 7)], [QQ(4, 7)]]), QQ) assert f.num == [[-QQ(7)], [-QQ(14)]] assert f.den == [[QQ(15)], [-QQ(20)]] assert f.lev == 1 assert f.dom == QQ raises(ValueError, lambda: DMF(([1], [[1]]), ZZ)) raises(ZeroDivisionError, lambda: DMF(([1], []), ZZ)) def test_DMF__bool__(): assert bool(DMF([[]], ZZ)) is False assert bool(DMF([[1]], ZZ)) is True def test_DMF_properties(): assert DMF([[]], ZZ).is_zero is True assert DMF([[]], ZZ).is_one is False assert DMF([[1]], ZZ).is_zero is False assert DMF([[1]], ZZ).is_one is True assert DMF(([[1]], [[2]]), ZZ).is_one is False def test_DMF_arithmetics(): f = DMF([[7], [-9]], ZZ) g = DMF([[-7], [9]], ZZ) assert f.neg() == -f == g f = DMF(([[1]], [[1], []]), ZZ) g = DMF(([[1]], [[1, 0]]), ZZ) h = DMF(([[1], [1, 0]], [[1, 0], []]), ZZ) assert f.add(g) == f + g == h assert g.add(f) == g + f == h h = DMF(([[-1], [1, 0]], [[1, 0], []]), ZZ) assert f.sub(g) == f - g == h h = DMF(([[1]], [[1, 0], []]), ZZ) assert f.mul(g) == f*g == h assert g.mul(f) == g*f == h h = DMF(([[1, 0]], [[1], []]), ZZ) assert f.quo(g) == f/g == h h = DMF(([[1]], [[1], [], [], []]), ZZ) assert f.pow(3) == f**3 == h h = DMF(([[1]], [[1, 0, 0, 0]]), ZZ) assert g.pow(3) == g**3 == h h = DMF(([[1, 0]], [[1]]), ZZ) assert g.pow(-1) == g**-1 == h def test_ANP___init__(): rep = [QQ(1), QQ(1)] mod = [QQ(1), QQ(0), QQ(1)] f = ANP(rep, mod, QQ) assert f.rep == [QQ(1), QQ(1)] assert f.mod == [QQ(1), QQ(0), QQ(1)] assert f.dom == QQ rep = {1: QQ(1), 0: QQ(1)} mod = {2: QQ(1), 0: QQ(1)} f = ANP(rep, mod, QQ) assert f.rep == [QQ(1), QQ(1)] assert f.mod == [QQ(1), QQ(0), QQ(1)] assert f.dom == QQ f = ANP(1, mod, QQ) assert f.rep == [QQ(1)] assert f.mod == [QQ(1), QQ(0), QQ(1)] assert f.dom == QQ def test_ANP___eq__(): a = ANP([QQ(1), QQ(1)], [QQ(1), QQ(0), QQ(1)], QQ) b = ANP([QQ(1), QQ(1)], [QQ(1), QQ(0), QQ(2)], QQ) assert (a == a) is True assert (a != a) is False assert (a == b) is False assert (a != b) is True b = ANP([QQ(1), QQ(2)], [QQ(1), QQ(0), QQ(1)], QQ) assert (a == b) is False assert (a != b) is True def test_ANP___bool__(): assert bool(ANP([], [QQ(1), QQ(0), QQ(1)], QQ)) is False assert bool(ANP([QQ(1)], [QQ(1), QQ(0), QQ(1)], QQ)) is True def test_ANP_properties(): mod = [QQ(1), QQ(0), QQ(1)] assert ANP([QQ(0)], mod, QQ).is_zero is True assert ANP([QQ(1)], mod, QQ).is_zero is False assert ANP([QQ(1)], mod, QQ).is_one is True assert ANP([QQ(2)], mod, QQ).is_one is False def test_ANP_arithmetics(): mod = [QQ(1), QQ(0), QQ(0), QQ(-2)] a = ANP([QQ(2), QQ(-1), QQ(1)], mod, QQ) b = ANP([QQ(1), QQ(2)], mod, QQ) c = ANP([QQ(-2), QQ(1), QQ(-1)], mod, QQ) assert a.neg() == -a == c c = ANP([QQ(2), QQ(0), QQ(3)], mod, QQ) assert a.add(b) == a + b == c assert b.add(a) == b + a == c c = ANP([QQ(2), QQ(-2), QQ(-1)], mod, QQ) assert a.sub(b) == a - b == c c = ANP([QQ(-2), QQ(2), QQ(1)], mod, QQ) assert b.sub(a) == b - a == c c = ANP([QQ(3), QQ(-1), QQ(6)], mod, QQ) assert a.mul(b) == a*b == c assert b.mul(a) == b*a == c c = ANP([QQ(-1, 43), QQ(9, 43), QQ(5, 43)], mod, QQ) assert a.pow(0) == a**(0) == ANP(1, mod, QQ) assert a.pow(1) == a**(1) == a assert a.pow(-1) == a**(-1) == c assert a.quo(a) == a.mul(a.pow(-1)) == a*a**(-1) == ANP(1, mod, QQ) c = ANP([], [1, 0, 0, -2], QQ) r1 = a.rem(b) (q, r2) = a.div(b) assert r1 == r2 == c == a % b raises(NotInvertible, lambda: a.div(c)) raises(NotInvertible, lambda: a.rem(c)) # Comparison with "hard-coded" value fails despite looking identical # from sympy import Rational # c = ANP([Rational(11, 10), Rational(-1, 5), Rational(-3, 5)], [1, 0, 0, -2], QQ) assert q == a/b # == c def test_ANP_unify(): mod = [QQ(1), QQ(0), QQ(-2)] a = ANP([QQ(1)], mod, QQ) b = ANP([ZZ(1)], mod, ZZ) assert a.unify(b)[0] == QQ assert b.unify(a)[0] == QQ assert a.unify(a)[0] == QQ assert b.unify(b)[0] == ZZ def test___hash__(): # issue 5571 # Make sure int vs. long doesn't affect hashing with Python ground types assert DMP([[1, 2], [3]], ZZ) == DMP([[int(1), int(2)], [int(3)]], ZZ) assert hash(DMP([[1, 2], [3]], ZZ)) == hash(DMP([[int(1), int(2)], [int(3)]], ZZ)) assert DMF( ([[1, 2], [3]], [[1]]), ZZ) == DMF(([[int(1), int(2)], [int(3)]], [[int(1)]]), ZZ) assert hash(DMF(([[1, 2], [3]], [[1]]), ZZ)) == hash(DMF(([[int(1), int(2)], [int(3)]], [[int(1)]]), ZZ)) assert ANP([1, 1], [1, 0, 1], ZZ) == ANP([int(1), int(1)], [int(1), int(0), int(1)], ZZ) assert hash( ANP([1, 1], [1, 0, 1], ZZ)) == hash(ANP([int(1), int(1)], [int(1), int(0), int(1)], ZZ)) sympy-sympy-1.9/sympy/polys/tests/test_polyfuncs.py000066400000000000000000000106061412543434000230520ustar00rootroot00000000000000"""Tests for high-level polynomials manipulation functions. """ from sympy.polys.polyfuncs import ( symmetrize, horner, interpolate, rational_interpolate, viete, ) from sympy.polys.polyerrors import ( MultivariatePolynomialError, ) from sympy import symbols, S from sympy.testing.pytest import raises from sympy.abc import a, b, c, d, e, x, y, z def test_symmetrize(): assert symmetrize(0, x, y, z) == (0, 0) assert symmetrize(1, x, y, z) == (1, 0) s1 = x + y + z s2 = x*y + x*z + y*z assert symmetrize(1) == (1, 0) assert symmetrize(1, formal=True) == (1, 0, []) assert symmetrize(x) == (x, 0) assert symmetrize(x + 1) == (x + 1, 0) assert symmetrize(x, x, y) == (x + y, -y) assert symmetrize(x + 1, x, y) == (x + y + 1, -y) assert symmetrize(x, x, y, z) == (s1, -y - z) assert symmetrize(x + 1, x, y, z) == (s1 + 1, -y - z) assert symmetrize(x**2, x, y, z) == (s1**2 - 2*s2, -y**2 - z**2) assert symmetrize(x**2 + y**2) == (-2*x*y + (x + y)**2, 0) assert symmetrize(x**2 - y**2) == (-2*x*y + (x + y)**2, -2*y**2) assert symmetrize(x**3 + y**2 + a*x**2 + b*y**3, x, y) == \ (-3*x*y*(x + y) - 2*a*x*y + a*(x + y)**2 + (x + y)**3, y**2*(1 - a) + y**3*(b - 1)) U = [u0, u1, u2] = symbols('u:3') assert symmetrize(x + 1, x, y, z, formal=True, symbols=U) == \ (u0 + 1, -y - z, [(u0, x + y + z), (u1, x*y + x*z + y*z), (u2, x*y*z)]) assert symmetrize([1, 2, 3]) == [(1, 0), (2, 0), (3, 0)] assert symmetrize([1, 2, 3], formal=True) == ([(1, 0), (2, 0), (3, 0)], []) assert symmetrize([x + y, x - y]) == [(x + y, 0), (x + y, -2*y)] def test_horner(): assert horner(0) == 0 assert horner(1) == 1 assert horner(x) == x assert horner(x + 1) == x + 1 assert horner(x**2 + 1) == x**2 + 1 assert horner(x**2 + x) == (x + 1)*x assert horner(x**2 + x + 1) == (x + 1)*x + 1 assert horner( 9*x**4 + 8*x**3 + 7*x**2 + 6*x + 5) == (((9*x + 8)*x + 7)*x + 6)*x + 5 assert horner( a*x**4 + b*x**3 + c*x**2 + d*x + e) == (((a*x + b)*x + c)*x + d)*x + e assert horner(4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y, wrt=x) == (( 4*y + 2)*x*y + (2*y + 1)*y)*x assert horner(4*x**2*y**2 + 2*x**2*y + 2*x*y**2 + x*y, wrt=y) == (( 4*x + 2)*y*x + (2*x + 1)*x)*y def test_interpolate(): assert interpolate([1, 4, 9, 16], x) == x**2 assert interpolate([1, 4, 9, 25], x) == S(3)*x**3/2 - S(8)*x**2 + S(33)*x/2 - 9 assert interpolate([(1, 1), (2, 4), (3, 9)], x) == x**2 assert interpolate([(1, 2), (2, 5), (3, 10)], x) == 1 + x**2 assert interpolate({1: 2, 2: 5, 3: 10}, x) == 1 + x**2 assert interpolate({5: 2, 7: 5, 8: 10, 9: 13}, x) == \ -S(13)*x**3/24 + S(12)*x**2 - S(2003)*x/24 + 187 assert interpolate([(1, 3), (0, 6), (2, 5), (5, 7), (-2, 4)], x) == \ S(-61)*x**4/280 + S(247)*x**3/210 + S(139)*x**2/280 - S(1871)*x/420 + 6 assert interpolate((9, 4, 9), 3) == 9 assert interpolate((1, 9, 16), 1) is S.One assert interpolate(((x, 1), (2, 3)), x) is S.One assert interpolate(dict([(x, 1), (2, 3)]), x) is S.One assert interpolate(((2, x), (1, 3)), x) == x**2 - 4*x + 6 def test_rational_interpolate(): x, y = symbols('x,y') xdata = [1, 2, 3, 4, 5, 6] ydata1 = [120, 150, 200, 255, 312, 370] ydata2 = [-210, -35, 105, 231, 350, 465] assert rational_interpolate(list(zip(xdata, ydata1)), 2) == ( (60*x**2 + 60)/x ) assert rational_interpolate(list(zip(xdata, ydata1)), 3) == ( (60*x**2 + 60)/x ) assert rational_interpolate(list(zip(xdata, ydata2)), 2, X=y) == ( (105*y**2 - 525)/(y + 1) ) xdata = list(range(1,11)) ydata = [-1923885361858460, -5212158811973685, -9838050145867125, -15662936261217245, -22469424125057910, -30073793365223685, -38332297297028735, -47132954289530109, -56387719094026320, -66026548943876885] assert rational_interpolate(list(zip(xdata, ydata)), 5) == ( (-12986226192544605*x**4 + 8657484128363070*x**3 - 30301194449270745*x**2 + 4328742064181535*x - 4328742064181535)/(x**3 + 9*x**2 - 3*x + 11)) def test_viete(): r1, r2 = symbols('r1, r2') assert viete( a*x**2 + b*x + c, [r1, r2], x) == [(r1 + r2, -b/a), (r1*r2, c/a)] raises(ValueError, lambda: viete(1, [], x)) raises(ValueError, lambda: viete(x**2 + 1, [r1])) raises(MultivariatePolynomialError, lambda: viete(x + y, [r1])) sympy-sympy-1.9/sympy/polys/tests/test_polymatrix.py000066400000000000000000000160621412543434000232420ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy.polys.polymatrix import PolyMatrix from sympy.polys import Poly from sympy import S, QQ, ZZ, Matrix from sympy.abc import x, y def _test_polymatrix(): pm1 = PolyMatrix([[Poly(x**2, x), Poly(-x, x)], [Poly(x**3, x), Poly(-1 + x, x)]]) v1 = PolyMatrix([[1, 0], [-1, 0]], ring='ZZ[x]') m1 = PolyMatrix([[1, 0], [-1, 0]], ring='ZZ[x]') A = PolyMatrix([[Poly(x**2 + x, x), Poly(0, x)], \ [Poly(x**3 - x + 1, x), Poly(0, x)]]) B = PolyMatrix([[Poly(x**2, x), Poly(-x, x)], [Poly(-x**2, x), Poly(x, x)]]) assert A.ring == ZZ[x] assert isinstance(pm1*v1, PolyMatrix) assert pm1*v1 == A assert pm1*m1 == A assert v1*pm1 == B pm2 = PolyMatrix([[Poly(x**2, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(-x**2, x, domain='QQ'), \ Poly(x**3, x, domain='QQ'), Poly(0, x, domain='QQ'), Poly(-x**3, x, domain='QQ')]]) assert pm2.ring == QQ[x] v2 = PolyMatrix([1, 0, 0, 0, 0, 0], ring='ZZ[x]') m2 = PolyMatrix([1, 0, 0, 0, 0, 0], ring='ZZ[x]') C = PolyMatrix([[Poly(x**2, x, domain='QQ')]]) assert pm2*v2 == C assert pm2*m2 == C pm3 = PolyMatrix([[Poly(x**2, x), S.One]], ring='ZZ[x]') v3 = S.Half*pm3 assert v3 == PolyMatrix([[Poly(S.Half*x**2, x, domain='QQ'), S.Half]], ring='QQ[x]') assert pm3*S.Half == v3 assert v3.ring == QQ[x] pm4 = PolyMatrix([[Poly(x**2, x, domain='ZZ'), Poly(-x**2, x, domain='ZZ')]]) v4 = PolyMatrix([1, -1], ring='ZZ[x]') assert pm4*v4 == PolyMatrix([[Poly(2*x**2, x, domain='ZZ')]]) assert len(PolyMatrix(ring=ZZ[x])) == 0 assert PolyMatrix([1, 0, 0, 1], x)/(-1) == PolyMatrix([-1, 0, 0, -1], x) def test_polymatrix_constructor(): M1 = PolyMatrix([[x, y]], ring=QQ[x,y]) assert M1.ring == QQ[x,y] assert M1.domain == QQ assert M1.gens == (x, y) assert M1.shape == (1, 2) assert M1.rows == 1 assert M1.cols == 2 assert len(M1) == 2 assert list(M1) == [Poly(x, (x, y), domain=QQ), Poly(y, (x, y), domain=QQ)] M2 = PolyMatrix([[x, y]], ring=QQ[x][y]) assert M2.ring == QQ[x][y] assert M2.domain == QQ[x] assert M2.gens == (y,) assert M2.shape == (1, 2) assert M2.rows == 1 assert M2.cols == 2 assert len(M2) == 2 assert list(M2) == [Poly(x, (y,), domain=QQ[x]), Poly(y, (y,), domain=QQ[x])] assert PolyMatrix([[x, y]], y) == PolyMatrix([[x, y]], ring=ZZ.frac_field(x)[y]) assert PolyMatrix([[x, y]], ring='ZZ[x,y]') == PolyMatrix([[x, y]], ring=ZZ[x,y]) assert PolyMatrix([[x, y]], (x, y)) == PolyMatrix([[x, y]], ring=QQ[x,y]) assert PolyMatrix([[x, y]], x, y) == PolyMatrix([[x, y]], ring=QQ[x,y]) assert PolyMatrix([x, y]) == PolyMatrix([[x], [y]], ring=QQ[x,y]) assert PolyMatrix(1, 2, [x, y]) == PolyMatrix([[x, y]], ring=QQ[x,y]) assert PolyMatrix(1, 2, lambda i,j: [x,y][j]) == PolyMatrix([[x, y]], ring=QQ[x,y]) assert PolyMatrix(0, 2, [], x, y).shape == (0, 2) assert PolyMatrix(2, 0, [], x, y).shape == (2, 0) assert PolyMatrix([[], []], x, y).shape == (2, 0) assert PolyMatrix(ring=QQ[x,y]) == PolyMatrix(0, 0, [], ring=QQ[x,y]) == PolyMatrix([], ring=QQ[x,y]) raises(TypeError, lambda: PolyMatrix()) raises(TypeError, lambda: PolyMatrix(1)) assert PolyMatrix([Poly(x), Poly(y)]) == PolyMatrix([[x], [y]], ring=ZZ[x,y]) # XXX: Maybe a bug in parallel_poly_from_expr (x lost from gens and domain): assert PolyMatrix([Poly(y, x), 1]) == PolyMatrix([[y], [1]], ring=QQ[y]) def test_polymatrix_eq(): assert (PolyMatrix([x]) == PolyMatrix([x])) is True assert (PolyMatrix([y]) == PolyMatrix([x])) is False assert (PolyMatrix([x]) != PolyMatrix([x])) is False assert (PolyMatrix([y]) != PolyMatrix([x])) is True assert PolyMatrix([[x, y]]) != PolyMatrix([x, y]) == PolyMatrix([[x], [y]]) assert PolyMatrix([x], ring=QQ[x]) != PolyMatrix([x], ring=ZZ[x]) assert PolyMatrix([x]) != Matrix([x]) assert PolyMatrix([x]).to_Matrix() == Matrix([x]) assert PolyMatrix([1], x) == PolyMatrix([1], x) assert PolyMatrix([1], x) != PolyMatrix([1], y) def test_polymatrix_from_Matrix(): assert PolyMatrix.from_Matrix(Matrix([1, 2]), x) == PolyMatrix([1, 2], x, ring=QQ[x]) assert PolyMatrix.from_Matrix(Matrix([1]), ring=QQ[x]) == PolyMatrix([1], x) pmx = PolyMatrix([1, 2], x) pmy = PolyMatrix([1, 2], y) assert pmx != pmy assert pmx.set_gens(y) == pmy def test_polymatrix_repr(): assert repr(PolyMatrix([[1, 2]], x)) == 'PolyMatrix([[1, 2]], ring=QQ[x])' assert repr(PolyMatrix(0, 2, [], x)) == 'PolyMatrix(0, 2, [], ring=QQ[x])' def test_polymatrix_getitem(): M = PolyMatrix([[1, 2], [3, 4]], x) assert M[:, :] == M assert M[0, :] == PolyMatrix([[1, 2]], x) assert M[:, 0] == PolyMatrix([1, 3], x) assert M[0, 0] == Poly(1, x, domain=QQ) assert M[0] == Poly(1, x, domain=QQ) assert M[:2] == [Poly(1, x, domain=QQ), Poly(2, x, domain=QQ)] def test_polymatrix_arithmetic(): M = PolyMatrix([[1, 2], [3, 4]], x) assert M + M == PolyMatrix([[2, 4], [6, 8]], x) assert M - M == PolyMatrix([[0, 0], [0, 0]], x) assert -M == PolyMatrix([[-1, -2], [-3, -4]], x) raises(TypeError, lambda: M + 1) raises(TypeError, lambda: M - 1) raises(TypeError, lambda: 1 + M) raises(TypeError, lambda: 1 - M) assert M * M == PolyMatrix([[7, 10], [15, 22]], x) assert 2 * M == PolyMatrix([[2, 4], [6, 8]], x) assert M * 2 == PolyMatrix([[2, 4], [6, 8]], x) assert S(2) * M == PolyMatrix([[2, 4], [6, 8]], x) assert M * S(2) == PolyMatrix([[2, 4], [6, 8]], x) raises(TypeError, lambda: [] * M) raises(TypeError, lambda: M * []) M2 = PolyMatrix([[1, 2]], ring=ZZ[x]) assert S.Half * M2 == PolyMatrix([[S.Half, 1]], ring=QQ[x]) assert M2 * S.Half == PolyMatrix([[S.Half, 1]], ring=QQ[x]) assert M / 2 == PolyMatrix([[S(1)/2, 1], [S(3)/2, 2]], x) assert M / Poly(2, x) == PolyMatrix([[S(1)/2, 1], [S(3)/2, 2]], x) raises(TypeError, lambda: M / []) def test_polymatrix_manipulations(): M1 = PolyMatrix([[1, 2], [3, 4]], x) assert M1.transpose() == PolyMatrix([[1, 3], [2, 4]], x) M2 = PolyMatrix([[5, 6], [7, 8]], x) assert M1.row_join(M2) == PolyMatrix([[1, 2, 5, 6], [3, 4, 7, 8]], x) assert M1.col_join(M2) == PolyMatrix([[1, 2], [3, 4], [5, 6], [7, 8]], x) assert M1.applyfunc(lambda e: 2*e) == PolyMatrix([[2, 4], [6, 8]], x) def test_polymatrix_ones_zeros(): assert PolyMatrix.zeros(1, 2, x) == PolyMatrix([[0, 0]], x) assert PolyMatrix.eye(2, x) == PolyMatrix([[1, 0], [0, 1]], x) def test_polymatrix_rref(): M = PolyMatrix([[1, 2], [3, 4]], x) assert M.rref() == (PolyMatrix.eye(2, x), (0, 1)) raises(ValueError, lambda: PolyMatrix([1, 2], ring=ZZ[x]).rref()) raises(ValueError, lambda: PolyMatrix([1, x], ring=QQ[x]).rref()) def test_polymatrix_nullspace(): M = PolyMatrix([[1, 2], [3, 6]], x) assert M.nullspace() == [PolyMatrix([-2, 1], x)] raises(ValueError, lambda: PolyMatrix([1, 2], ring=ZZ[x]).nullspace()) raises(ValueError, lambda: PolyMatrix([1, x], ring=QQ[x]).nullspace()) assert M.rank() == 1 sympy-sympy-1.9/sympy/polys/tests/test_polyoptions.py000066400000000000000000000300401412543434000234210ustar00rootroot00000000000000"""Tests for options manager for :class:`Poly` and public API functions. """ from sympy.polys.polyoptions import ( Options, Expand, Gens, Wrt, Sort, Order, Field, Greedy, Domain, Split, Gaussian, Extension, Modulus, Symmetric, Strict, Auto, Frac, Formal, Polys, Include, All, Gen, Symbols, Method) from sympy.polys.orderings import lex from sympy.polys.domains import FF, GF, ZZ, QQ, QQ_I, RR, CC, EX from sympy.polys.polyerrors import OptionError, GeneratorsError from sympy import Integer, Symbol, I, sqrt from sympy.testing.pytest import raises from sympy.abc import x, y, z def test_Options_clone(): opt = Options((x, y, z), {'domain': 'ZZ'}) assert opt.gens == (x, y, z) assert opt.domain == ZZ assert ('order' in opt) is False new_opt = opt.clone({'gens': (x, y), 'order': 'lex'}) assert opt.gens == (x, y, z) assert opt.domain == ZZ assert ('order' in opt) is False assert new_opt.gens == (x, y) assert new_opt.domain == ZZ assert ('order' in new_opt) is True def test_Expand_preprocess(): assert Expand.preprocess(False) is False assert Expand.preprocess(True) is True assert Expand.preprocess(0) is False assert Expand.preprocess(1) is True raises(OptionError, lambda: Expand.preprocess(x)) def test_Expand_postprocess(): opt = {'expand': True} Expand.postprocess(opt) assert opt == {'expand': True} def test_Gens_preprocess(): assert Gens.preprocess((None,)) == () assert Gens.preprocess((x, y, z)) == (x, y, z) assert Gens.preprocess(((x, y, z),)) == (x, y, z) a = Symbol('a', commutative=False) raises(GeneratorsError, lambda: Gens.preprocess((x, x, y))) raises(GeneratorsError, lambda: Gens.preprocess((x, y, a))) def test_Gens_postprocess(): opt = {'gens': (x, y)} Gens.postprocess(opt) assert opt == {'gens': (x, y)} def test_Wrt_preprocess(): assert Wrt.preprocess(x) == ['x'] assert Wrt.preprocess('') == [] assert Wrt.preprocess(' ') == [] assert Wrt.preprocess('x,y') == ['x', 'y'] assert Wrt.preprocess('x y') == ['x', 'y'] assert Wrt.preprocess('x, y') == ['x', 'y'] assert Wrt.preprocess('x , y') == ['x', 'y'] assert Wrt.preprocess(' x, y') == ['x', 'y'] assert Wrt.preprocess(' x, y') == ['x', 'y'] assert Wrt.preprocess([x, y]) == ['x', 'y'] raises(OptionError, lambda: Wrt.preprocess(',')) raises(OptionError, lambda: Wrt.preprocess(0)) def test_Wrt_postprocess(): opt = {'wrt': ['x']} Wrt.postprocess(opt) assert opt == {'wrt': ['x']} def test_Sort_preprocess(): assert Sort.preprocess([x, y, z]) == ['x', 'y', 'z'] assert Sort.preprocess((x, y, z)) == ['x', 'y', 'z'] assert Sort.preprocess('x > y > z') == ['x', 'y', 'z'] assert Sort.preprocess('x>y>z') == ['x', 'y', 'z'] raises(OptionError, lambda: Sort.preprocess(0)) raises(OptionError, lambda: Sort.preprocess({x, y, z})) def test_Sort_postprocess(): opt = {'sort': 'x > y'} Sort.postprocess(opt) assert opt == {'sort': 'x > y'} def test_Order_preprocess(): assert Order.preprocess('lex') == lex def test_Order_postprocess(): opt = {'order': True} Order.postprocess(opt) assert opt == {'order': True} def test_Field_preprocess(): assert Field.preprocess(False) is False assert Field.preprocess(True) is True assert Field.preprocess(0) is False assert Field.preprocess(1) is True raises(OptionError, lambda: Field.preprocess(x)) def test_Field_postprocess(): opt = {'field': True} Field.postprocess(opt) assert opt == {'field': True} def test_Greedy_preprocess(): assert Greedy.preprocess(False) is False assert Greedy.preprocess(True) is True assert Greedy.preprocess(0) is False assert Greedy.preprocess(1) is True raises(OptionError, lambda: Greedy.preprocess(x)) def test_Greedy_postprocess(): opt = {'greedy': True} Greedy.postprocess(opt) assert opt == {'greedy': True} def test_Domain_preprocess(): assert Domain.preprocess(ZZ) == ZZ assert Domain.preprocess(QQ) == QQ assert Domain.preprocess(EX) == EX assert Domain.preprocess(FF(2)) == FF(2) assert Domain.preprocess(ZZ[x, y]) == ZZ[x, y] assert Domain.preprocess('Z') == ZZ assert Domain.preprocess('Q') == QQ assert Domain.preprocess('ZZ') == ZZ assert Domain.preprocess('QQ') == QQ assert Domain.preprocess('EX') == EX assert Domain.preprocess('FF(23)') == FF(23) assert Domain.preprocess('GF(23)') == GF(23) raises(OptionError, lambda: Domain.preprocess('Z[]')) assert Domain.preprocess('Z[x]') == ZZ[x] assert Domain.preprocess('Q[x]') == QQ[x] assert Domain.preprocess('R[x]') == RR[x] assert Domain.preprocess('C[x]') == CC[x] assert Domain.preprocess('ZZ[x]') == ZZ[x] assert Domain.preprocess('QQ[x]') == QQ[x] assert Domain.preprocess('RR[x]') == RR[x] assert Domain.preprocess('CC[x]') == CC[x] assert Domain.preprocess('Z[x,y]') == ZZ[x, y] assert Domain.preprocess('Q[x,y]') == QQ[x, y] assert Domain.preprocess('R[x,y]') == RR[x, y] assert Domain.preprocess('C[x,y]') == CC[x, y] assert Domain.preprocess('ZZ[x,y]') == ZZ[x, y] assert Domain.preprocess('QQ[x,y]') == QQ[x, y] assert Domain.preprocess('RR[x,y]') == RR[x, y] assert Domain.preprocess('CC[x,y]') == CC[x, y] raises(OptionError, lambda: Domain.preprocess('Z()')) assert Domain.preprocess('Z(x)') == ZZ.frac_field(x) assert Domain.preprocess('Q(x)') == QQ.frac_field(x) assert Domain.preprocess('ZZ(x)') == ZZ.frac_field(x) assert Domain.preprocess('QQ(x)') == QQ.frac_field(x) assert Domain.preprocess('Z(x,y)') == ZZ.frac_field(x, y) assert Domain.preprocess('Q(x,y)') == QQ.frac_field(x, y) assert Domain.preprocess('ZZ(x,y)') == ZZ.frac_field(x, y) assert Domain.preprocess('QQ(x,y)') == QQ.frac_field(x, y) assert Domain.preprocess('Q') == QQ.algebraic_field(I) assert Domain.preprocess('QQ') == QQ.algebraic_field(I) assert Domain.preprocess('Q') == QQ.algebraic_field(sqrt(2), I) assert Domain.preprocess( 'QQ') == QQ.algebraic_field(sqrt(2), I) raises(OptionError, lambda: Domain.preprocess('abc')) def test_Domain_postprocess(): raises(GeneratorsError, lambda: Domain.postprocess({'gens': (x, y), 'domain': ZZ[y, z]})) raises(GeneratorsError, lambda: Domain.postprocess({'gens': (), 'domain': EX})) raises(GeneratorsError, lambda: Domain.postprocess({'domain': EX})) def test_Split_preprocess(): assert Split.preprocess(False) is False assert Split.preprocess(True) is True assert Split.preprocess(0) is False assert Split.preprocess(1) is True raises(OptionError, lambda: Split.preprocess(x)) def test_Split_postprocess(): raises(NotImplementedError, lambda: Split.postprocess({'split': True})) def test_Gaussian_preprocess(): assert Gaussian.preprocess(False) is False assert Gaussian.preprocess(True) is True assert Gaussian.preprocess(0) is False assert Gaussian.preprocess(1) is True raises(OptionError, lambda: Gaussian.preprocess(x)) def test_Gaussian_postprocess(): opt = {'gaussian': True} Gaussian.postprocess(opt) assert opt == { 'gaussian': True, 'domain': QQ_I, } def test_Extension_preprocess(): assert Extension.preprocess(True) is True assert Extension.preprocess(1) is True assert Extension.preprocess([]) is None assert Extension.preprocess(sqrt(2)) == {sqrt(2)} assert Extension.preprocess([sqrt(2)]) == {sqrt(2)} assert Extension.preprocess([sqrt(2), I]) == {sqrt(2), I} raises(OptionError, lambda: Extension.preprocess(False)) raises(OptionError, lambda: Extension.preprocess(0)) def test_Extension_postprocess(): opt = {'extension': {sqrt(2)}} Extension.postprocess(opt) assert opt == { 'extension': {sqrt(2)}, 'domain': QQ.algebraic_field(sqrt(2)), } opt = {'extension': True} Extension.postprocess(opt) assert opt == {'extension': True} def test_Modulus_preprocess(): assert Modulus.preprocess(23) == 23 assert Modulus.preprocess(Integer(23)) == 23 raises(OptionError, lambda: Modulus.preprocess(0)) raises(OptionError, lambda: Modulus.preprocess(x)) def test_Modulus_postprocess(): opt = {'modulus': 5} Modulus.postprocess(opt) assert opt == { 'modulus': 5, 'domain': FF(5), } opt = {'modulus': 5, 'symmetric': False} Modulus.postprocess(opt) assert opt == { 'modulus': 5, 'domain': FF(5, False), 'symmetric': False, } def test_Symmetric_preprocess(): assert Symmetric.preprocess(False) is False assert Symmetric.preprocess(True) is True assert Symmetric.preprocess(0) is False assert Symmetric.preprocess(1) is True raises(OptionError, lambda: Symmetric.preprocess(x)) def test_Symmetric_postprocess(): opt = {'symmetric': True} Symmetric.postprocess(opt) assert opt == {'symmetric': True} def test_Strict_preprocess(): assert Strict.preprocess(False) is False assert Strict.preprocess(True) is True assert Strict.preprocess(0) is False assert Strict.preprocess(1) is True raises(OptionError, lambda: Strict.preprocess(x)) def test_Strict_postprocess(): opt = {'strict': True} Strict.postprocess(opt) assert opt == {'strict': True} def test_Auto_preprocess(): assert Auto.preprocess(False) is False assert Auto.preprocess(True) is True assert Auto.preprocess(0) is False assert Auto.preprocess(1) is True raises(OptionError, lambda: Auto.preprocess(x)) def test_Auto_postprocess(): opt = {'auto': True} Auto.postprocess(opt) assert opt == {'auto': True} def test_Frac_preprocess(): assert Frac.preprocess(False) is False assert Frac.preprocess(True) is True assert Frac.preprocess(0) is False assert Frac.preprocess(1) is True raises(OptionError, lambda: Frac.preprocess(x)) def test_Frac_postprocess(): opt = {'frac': True} Frac.postprocess(opt) assert opt == {'frac': True} def test_Formal_preprocess(): assert Formal.preprocess(False) is False assert Formal.preprocess(True) is True assert Formal.preprocess(0) is False assert Formal.preprocess(1) is True raises(OptionError, lambda: Formal.preprocess(x)) def test_Formal_postprocess(): opt = {'formal': True} Formal.postprocess(opt) assert opt == {'formal': True} def test_Polys_preprocess(): assert Polys.preprocess(False) is False assert Polys.preprocess(True) is True assert Polys.preprocess(0) is False assert Polys.preprocess(1) is True raises(OptionError, lambda: Polys.preprocess(x)) def test_Polys_postprocess(): opt = {'polys': True} Polys.postprocess(opt) assert opt == {'polys': True} def test_Include_preprocess(): assert Include.preprocess(False) is False assert Include.preprocess(True) is True assert Include.preprocess(0) is False assert Include.preprocess(1) is True raises(OptionError, lambda: Include.preprocess(x)) def test_Include_postprocess(): opt = {'include': True} Include.postprocess(opt) assert opt == {'include': True} def test_All_preprocess(): assert All.preprocess(False) is False assert All.preprocess(True) is True assert All.preprocess(0) is False assert All.preprocess(1) is True raises(OptionError, lambda: All.preprocess(x)) def test_All_postprocess(): opt = {'all': True} All.postprocess(opt) assert opt == {'all': True} def test_Gen_postprocess(): opt = {'gen': x} Gen.postprocess(opt) assert opt == {'gen': x} def test_Symbols_preprocess(): raises(OptionError, lambda: Symbols.preprocess(x)) def test_Symbols_postprocess(): opt = {'symbols': [x, y, z]} Symbols.postprocess(opt) assert opt == {'symbols': [x, y, z]} def test_Method_preprocess(): raises(OptionError, lambda: Method.preprocess(10)) def test_Method_postprocess(): opt = {'method': 'f5b'} Method.postprocess(opt) assert opt == {'method': 'f5b'} sympy-sympy-1.9/sympy/polys/tests/test_polyroots.py000066400000000000000000000612361412543434000231070ustar00rootroot00000000000000"""Tests for algorithms for computing symbolic roots of polynomials. """ from sympy import (S, symbols, Symbol, Wild, Rational, sqrt, powsimp, sin, cos, pi, I, Interval, re, im, exp, ZZ, Piecewise, acos, root, conjugate) from sympy.polys import Poly, cyclotomic_poly, intervals, nroots, rootof from sympy.polys.polyroots import (root_factors, roots_linear, roots_quadratic, roots_cubic, roots_quartic, roots_cyclotomic, roots_binomial, preprocess_roots, roots) from sympy.polys.orthopolys import legendre_poly from sympy.polys.polyerrors import PolynomialError from sympy.polys.polyutils import _nsort from sympy.utilities.iterables import cartes from sympy.testing.pytest import raises, slow from sympy.testing.randtest import verify_numerically import mpmath a, b, c, d, e, q, t, x, y, z = symbols('a,b,c,d,e,q,t,x,y,z') def _check(roots): # this is the desired invariant for roots returned # by all_roots. It is trivially true for linear # polynomials. nreal = sum([1 if i.is_real else 0 for i in roots]) assert list(sorted(roots[:nreal])) == list(roots[:nreal]) for ix in range(nreal, len(roots), 2): if not ( roots[ix + 1] == roots[ix] or roots[ix + 1] == conjugate(roots[ix])): return False return True def test_roots_linear(): assert roots_linear(Poly(2*x + 1, x)) == [Rational(-1, 2)] def test_roots_quadratic(): assert roots_quadratic(Poly(2*x**2, x)) == [0, 0] assert roots_quadratic(Poly(2*x**2 + 3*x, x)) == [Rational(-3, 2), 0] assert roots_quadratic(Poly(2*x**2 + 3, x)) == [-I*sqrt(6)/2, I*sqrt(6)/2] assert roots_quadratic(Poly(2*x**2 + 4*x + 3, x)) == [-1 - I*sqrt(2)/2, -1 + I*sqrt(2)/2] _check(Poly(2*x**2 + 4*x + 3, x).all_roots()) f = x**2 + (2*a*e + 2*c*e)/(a - c)*x + (d - b + a*e**2 - c*e**2)/(a - c) assert roots_quadratic(Poly(f, x)) == \ [-e*(a + c)/(a - c) - sqrt(a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c), -e*(a + c)/(a - c) + sqrt(a*b + c*d - a*d - b*c + 4*a*c*e**2)/(a - c)] # check for simplification f = Poly(y*x**2 - 2*x - 2*y, x) assert roots_quadratic(f) == \ [-sqrt(2*y**2 + 1)/y + 1/y, sqrt(2*y**2 + 1)/y + 1/y] f = Poly(x**2 + (-y**2 - 2)*x + y**2 + 1, x) assert roots_quadratic(f) == \ [1,y**2 + 1] f = Poly(sqrt(2)*x**2 - 1, x) r = roots_quadratic(f) assert r == _nsort(r) # issue 8255 f = Poly(-24*x**2 - 180*x + 264) assert [w.n(2) for w in f.all_roots(radicals=True)] == \ [w.n(2) for w in f.all_roots(radicals=False)] for _a, _b, _c in cartes((-2, 2), (-2, 2), (0, -1)): f = Poly(_a*x**2 + _b*x + _c) roots = roots_quadratic(f) assert roots == _nsort(roots) def test_issue_7724(): eq = Poly(x**4*I + x**2 + I, x) assert roots(eq) == { sqrt(I/2 + sqrt(5)*I/2): 1, sqrt(-sqrt(5)*I/2 + I/2): 1, -sqrt(I/2 + sqrt(5)*I/2): 1, -sqrt(-sqrt(5)*I/2 + I/2): 1} def test_issue_8438(): p = Poly([1, y, -2, -3], x).as_expr() roots = roots_cubic(Poly(p, x), x) z = Rational(-3, 2) - I*Rational(7, 2) # this will fail in code given in commit msg post = [r.subs(y, z) for r in roots] assert set(post) == \ set(roots_cubic(Poly(p.subs(y, z), x))) # /!\ if p is not made an expression, this is *very* slow assert all(p.subs({y: z, x: i}).n(2, chop=True) == 0 for i in post) def test_issue_8285(): roots = (Poly(4*x**8 - 1, x)*Poly(x**2 + 1)).all_roots() assert _check(roots) f = Poly(x**4 + 5*x**2 + 6, x) ro = [rootof(f, i) for i in range(4)] roots = Poly(x**4 + 5*x**2 + 6, x).all_roots() assert roots == ro assert _check(roots) # more than 2 complex roots from which to identify the # imaginary ones roots = Poly(2*x**8 - 1).all_roots() assert _check(roots) assert len(Poly(2*x**10 - 1).all_roots()) == 10 # doesn't fail def test_issue_8289(): roots = (Poly(x**2 + 2)*Poly(x**4 + 2)).all_roots() assert _check(roots) roots = Poly(x**6 + 3*x**3 + 2, x).all_roots() assert _check(roots) roots = Poly(x**6 - x + 1).all_roots() assert _check(roots) # all imaginary roots with multiplicity of 2 roots = Poly(x**4 + 4*x**2 + 4, x).all_roots() assert _check(roots) def test_issue_14291(): assert Poly(((x - 1)**2 + 1)*((x - 1)**2 + 2)*(x - 1) ).all_roots() == [1, 1 - I, 1 + I, 1 - sqrt(2)*I, 1 + sqrt(2)*I] p = x**4 + 10*x**2 + 1 ans = [rootof(p, i) for i in range(4)] assert Poly(p).all_roots() == ans _check(ans) def test_issue_13340(): eq = Poly(y**3 + exp(x)*y + x, y, domain='EX') roots_d = roots(eq) assert len(roots_d) == 3 def test_issue_14522(): eq = Poly(x**4 + x**3*(16 + 32*I) + x**2*(-285 + 386*I) + x*(-2824 - 448*I) - 2058 - 6053*I, x) roots_eq = roots(eq) assert all(eq(r) == 0 for r in roots_eq) def test_issue_15076(): sol = roots_quartic(Poly(t**4 - 6*t**2 + t/x - 3, t)) assert sol[0].has(x) def test_issue_16589(): eq = Poly(x**4 - 8*sqrt(2)*x**3 + 4*x**3 - 64*sqrt(2)*x**2 + 1024*x, x) roots_eq = roots(eq) assert 0 in roots_eq def test_roots_cubic(): assert roots_cubic(Poly(2*x**3, x)) == [0, 0, 0] assert roots_cubic(Poly(x**3 - 3*x**2 + 3*x - 1, x)) == [1, 1, 1] # valid for arbitrary y (issue 21263) r = root(y, 3) assert roots_cubic(Poly(x**3 - y, x)) == [r, r*(-S.Half + sqrt(3)*I/2), r*(-S.Half - sqrt(3)*I/2)] # simpler form when y is negative assert roots_cubic(Poly(x**3 - -1, x)) == \ [-1, S.Half - I*sqrt(3)/2, S.Half + I*sqrt(3)/2] assert roots_cubic(Poly(2*x**3 - 3*x**2 - 3*x - 1, x))[0] == \ S.Half + 3**Rational(1, 3)/2 + 3**Rational(2, 3)/2 eq = -x**3 + 2*x**2 + 3*x - 2 assert roots(eq, trig=True, multiple=True) == \ roots_cubic(Poly(eq, x), trig=True) == [ Rational(2, 3) + 2*sqrt(13)*cos(acos(8*sqrt(13)/169)/3)/3, -2*sqrt(13)*sin(-acos(8*sqrt(13)/169)/3 + pi/6)/3 + Rational(2, 3), -2*sqrt(13)*cos(-acos(8*sqrt(13)/169)/3 + pi/3)/3 + Rational(2, 3), ] def test_roots_quartic(): assert roots_quartic(Poly(x**4, x)) == [0, 0, 0, 0] assert roots_quartic(Poly(x**4 + x**3, x)) in [ [-1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, -1] ] assert roots_quartic(Poly(x**4 - x**3, x)) in [ [1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ] lhs = roots_quartic(Poly(x**4 + x, x)) rhs = [S.Half + I*sqrt(3)/2, S.Half - I*sqrt(3)/2, S.Zero, -S.One] assert sorted(lhs, key=hash) == sorted(rhs, key=hash) # test of all branches of roots quartic for i, (a, b, c, d) in enumerate([(1, 2, 3, 0), (3, -7, -9, 9), (1, 2, 3, 4), (1, 2, 3, 4), (-7, -3, 3, -6), (-3, 5, -6, -4), (6, -5, -10, -3)]): if i == 2: c = -a*(a**2/S(8) - b/S(2)) elif i == 3: d = a*(a*(a**2*Rational(3, 256) - b/S(16)) + c/S(4)) eq = x**4 + a*x**3 + b*x**2 + c*x + d ans = roots_quartic(Poly(eq, x)) assert all(eq.subs(x, ai).n(chop=True) == 0 for ai in ans) # not all symbolic quartics are unresolvable eq = Poly(q*x + q/4 + x**4 + x**3 + 2*x**2 - Rational(1, 3), x) sol = roots_quartic(eq) assert all(verify_numerically(eq.subs(x, i), 0) for i in sol) z = symbols('z', negative=True) eq = x**4 + 2*x**3 + 3*x**2 + x*(z + 11) + 5 zans = roots_quartic(Poly(eq, x)) assert all([verify_numerically(eq.subs(((x, i), (z, -1))), 0) for i in zans]) # but some are (see also issue 4989) # it's ok if the solution is not Piecewise, but the tests below should pass eq = Poly(y*x**4 + x**3 - x + z, x) ans = roots_quartic(eq) assert all(type(i) == Piecewise for i in ans) reps = ( dict(y=Rational(-1, 3), z=Rational(-1, 4)), # 4 real dict(y=Rational(-1, 3), z=Rational(-1, 2)), # 2 real dict(y=Rational(-1, 3), z=-2)) # 0 real for rep in reps: sol = roots_quartic(Poly(eq.subs(rep), x)) assert all([verify_numerically(w.subs(rep) - s, 0) for w, s in zip(ans, sol)]) def test_issue_21287(): assert not any(isinstance(i, Piecewise) for i in roots_quartic( Poly(x**4 - x**2*(3 + 5*I) + 2*x*(-1 + I) - 1 + 3*I, x))) def test_roots_cyclotomic(): assert roots_cyclotomic(cyclotomic_poly(1, x, polys=True)) == [1] assert roots_cyclotomic(cyclotomic_poly(2, x, polys=True)) == [-1] assert roots_cyclotomic(cyclotomic_poly( 3, x, polys=True)) == [Rational(-1, 2) - I*sqrt(3)/2, Rational(-1, 2) + I*sqrt(3)/2] assert roots_cyclotomic(cyclotomic_poly(4, x, polys=True)) == [-I, I] assert roots_cyclotomic(cyclotomic_poly( 6, x, polys=True)) == [S.Half - I*sqrt(3)/2, S.Half + I*sqrt(3)/2] assert roots_cyclotomic(cyclotomic_poly(7, x, polys=True)) == [ -cos(pi/7) - I*sin(pi/7), -cos(pi/7) + I*sin(pi/7), -cos(pi*Rational(3, 7)) - I*sin(pi*Rational(3, 7)), -cos(pi*Rational(3, 7)) + I*sin(pi*Rational(3, 7)), cos(pi*Rational(2, 7)) - I*sin(pi*Rational(2, 7)), cos(pi*Rational(2, 7)) + I*sin(pi*Rational(2, 7)), ] assert roots_cyclotomic(cyclotomic_poly(8, x, polys=True)) == [ -sqrt(2)/2 - I*sqrt(2)/2, -sqrt(2)/2 + I*sqrt(2)/2, sqrt(2)/2 - I*sqrt(2)/2, sqrt(2)/2 + I*sqrt(2)/2, ] assert roots_cyclotomic(cyclotomic_poly(12, x, polys=True)) == [ -sqrt(3)/2 - I/2, -sqrt(3)/2 + I/2, sqrt(3)/2 - I/2, sqrt(3)/2 + I/2, ] assert roots_cyclotomic( cyclotomic_poly(1, x, polys=True), factor=True) == [1] assert roots_cyclotomic( cyclotomic_poly(2, x, polys=True), factor=True) == [-1] assert roots_cyclotomic(cyclotomic_poly(3, x, polys=True), factor=True) == \ [-root(-1, 3), -1 + root(-1, 3)] assert roots_cyclotomic(cyclotomic_poly(4, x, polys=True), factor=True) == \ [-I, I] assert roots_cyclotomic(cyclotomic_poly(5, x, polys=True), factor=True) == \ [-root(-1, 5), -root(-1, 5)**3, root(-1, 5)**2, -1 - root(-1, 5)**2 + root(-1, 5) + root(-1, 5)**3] assert roots_cyclotomic(cyclotomic_poly(6, x, polys=True), factor=True) == \ [1 - root(-1, 3), root(-1, 3)] def test_roots_binomial(): assert roots_binomial(Poly(5*x, x)) == [0] assert roots_binomial(Poly(5*x**4, x)) == [0, 0, 0, 0] assert roots_binomial(Poly(5*x + 2, x)) == [Rational(-2, 5)] A = 10**Rational(3, 4)/10 assert roots_binomial(Poly(5*x**4 + 2, x)) == \ [-A - A*I, -A + A*I, A - A*I, A + A*I] _check(roots_binomial(Poly(x**8 - 2))) a1 = Symbol('a1', nonnegative=True) b1 = Symbol('b1', nonnegative=True) r0 = roots_quadratic(Poly(a1*x**2 + b1, x)) r1 = roots_binomial(Poly(a1*x**2 + b1, x)) assert powsimp(r0[0]) == powsimp(r1[0]) assert powsimp(r0[1]) == powsimp(r1[1]) for a, b, s, n in cartes((1, 2), (1, 2), (-1, 1), (2, 3, 4, 5)): if a == b and a != 1: # a == b == 1 is sufficient continue p = Poly(a*x**n + s*b) ans = roots_binomial(p) assert ans == _nsort(ans) # issue 8813 assert roots(Poly(2*x**3 - 16*y**3, x)) == { 2*y*(Rational(-1, 2) - sqrt(3)*I/2): 1, 2*y: 1, 2*y*(Rational(-1, 2) + sqrt(3)*I/2): 1} def test_roots_preprocessing(): f = a*y*x**2 + y - b coeff, poly = preprocess_roots(Poly(f, x)) assert coeff == 1 assert poly == Poly(a*y*x**2 + y - b, x) f = c**3*x**3 + c**2*x**2 + c*x + a coeff, poly = preprocess_roots(Poly(f, x)) assert coeff == 1/c assert poly == Poly(x**3 + x**2 + x + a, x) f = c**3*x**3 + c**2*x**2 + a coeff, poly = preprocess_roots(Poly(f, x)) assert coeff == 1/c assert poly == Poly(x**3 + x**2 + a, x) f = c**3*x**3 + c*x + a coeff, poly = preprocess_roots(Poly(f, x)) assert coeff == 1/c assert poly == Poly(x**3 + x + a, x) f = c**3*x**3 + a coeff, poly = preprocess_roots(Poly(f, x)) assert coeff == 1/c assert poly == Poly(x**3 + a, x) E, F, J, L = symbols("E,F,J,L") f = -21601054687500000000*E**8*J**8/L**16 + \ 508232812500000000*F*x*E**7*J**7/L**14 - \ 4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ 16194716250000*E**5*F**3*J**5*x**3/L**10 - \ 27633173750*E**4*F**4*J**4*x**4/L**8 + \ 14840215*E**3*F**5*J**3*x**5/L**6 + \ 54794*E**2*F**6*J**2*x**6/(5*L**4) - \ 1153*E*J*F**7*x**7/(80*L**2) + \ 633*F**8*x**8/160000 coeff, poly = preprocess_roots(Poly(f, x)) assert coeff == 20*E*J/(F*L**2) assert poly == 633*x**8 - 115300*x**7 + 4383520*x**6 + 296804300*x**5 - 27633173750*x**4 + \ 809735812500*x**3 - 10673859375000*x**2 + 63529101562500*x - 135006591796875 f = Poly(-y**2 + x**2*exp(x), y, domain=ZZ[x, exp(x)]) g = Poly(-y**2 + exp(x), y, domain=ZZ[exp(x)]) assert preprocess_roots(f) == (x, g) def test_roots0(): assert roots(1, x) == {} assert roots(x, x) == {S.Zero: 1} assert roots(x**9, x) == {S.Zero: 9} assert roots(((x - 2)*(x + 3)*(x - 4)).expand(), x) == {-S(3): 1, S(2): 1, S(4): 1} assert roots(2*x + 1, x) == {Rational(-1, 2): 1} assert roots((2*x + 1)**2, x) == {Rational(-1, 2): 2} assert roots((2*x + 1)**5, x) == {Rational(-1, 2): 5} assert roots((2*x + 1)**10, x) == {Rational(-1, 2): 10} assert roots(x**4 - 1, x) == {I: 1, S.One: 1, -S.One: 1, -I: 1} assert roots((x**4 - 1)**2, x) == {I: 2, S.One: 2, -S.One: 2, -I: 2} assert roots(((2*x - 3)**2).expand(), x) == {Rational( 3, 2): 2} assert roots(((2*x + 3)**2).expand(), x) == {Rational(-3, 2): 2} assert roots(((2*x - 3)**3).expand(), x) == {Rational( 3, 2): 3} assert roots(((2*x + 3)**3).expand(), x) == {Rational(-3, 2): 3} assert roots(((2*x - 3)**5).expand(), x) == {Rational( 3, 2): 5} assert roots(((2*x + 3)**5).expand(), x) == {Rational(-3, 2): 5} assert roots(((a*x - b)**5).expand(), x) == { b/a: 5} assert roots(((a*x + b)**5).expand(), x) == {-b/a: 5} assert roots(x**2 + (-a - 1)*x + a, x) == {a: 1, S.One: 1} assert roots(x**4 - 2*x**2 + 1, x) == {S.One: 2, S.NegativeOne: 2} assert roots(x**6 - 4*x**4 + 4*x**3 - x**2, x) == \ {S.One: 2, -1 - sqrt(2): 1, S.Zero: 2, -1 + sqrt(2): 1} assert roots(x**8 - 1, x) == { sqrt(2)/2 + I*sqrt(2)/2: 1, sqrt(2)/2 - I*sqrt(2)/2: 1, -sqrt(2)/2 + I*sqrt(2)/2: 1, -sqrt(2)/2 - I*sqrt(2)/2: 1, S.One: 1, -S.One: 1, I: 1, -I: 1 } f = -2016*x**2 - 5616*x**3 - 2056*x**4 + 3324*x**5 + 2176*x**6 - \ 224*x**7 - 384*x**8 - 64*x**9 assert roots(f) == {S.Zero: 2, -S(2): 2, S(2): 1, Rational(-7, 2): 1, Rational(-3, 2): 1, Rational(-1, 2): 1, Rational(3, 2): 1} assert roots((a + b + c)*x - (a + b + c + d), x) == {(a + b + c + d)/(a + b + c): 1} assert roots(x**3 + x**2 - x + 1, x, cubics=False) == {} assert roots(((x - 2)*( x + 3)*(x - 4)).expand(), x, cubics=False) == {-S(3): 1, S(2): 1, S(4): 1} assert roots(((x - 2)*(x + 3)*(x - 4)*(x - 5)).expand(), x, cubics=False) == \ {-S(3): 1, S(2): 1, S(4): 1, S(5): 1} assert roots(x**3 + 2*x**2 + 4*x + 8, x) == {-S(2): 1, -2*I: 1, 2*I: 1} assert roots(x**3 + 2*x**2 + 4*x + 8, x, cubics=True) == \ {-2*I: 1, 2*I: 1, -S(2): 1} assert roots((x**2 - x)*(x**3 + 2*x**2 + 4*x + 8), x ) == \ {S.One: 1, S.Zero: 1, -S(2): 1, -2*I: 1, 2*I: 1} r1_2, r1_3 = S.Half, Rational(1, 3) x0 = (3*sqrt(33) + 19)**r1_3 x1 = 4/x0/3 x2 = x0/3 x3 = sqrt(3)*I/2 x4 = x3 - r1_2 x5 = -x3 - r1_2 assert roots(x**3 + x**2 - x + 1, x, cubics=True) == { -x1 - x2 - r1_3: 1, -x1/x4 - x2*x4 - r1_3: 1, -x1/x5 - x2*x5 - r1_3: 1, } f = (x**2 + 2*x + 3).subs(x, 2*x**2 + 3*x).subs(x, 5*x - 4) r13_20, r1_20 = [ Rational(*r) for r in ((13, 20), (1, 20)) ] s2 = sqrt(2) assert roots(f, x) == { r13_20 + r1_20*sqrt(1 - 8*I*s2): 1, r13_20 - r1_20*sqrt(1 - 8*I*s2): 1, r13_20 + r1_20*sqrt(1 + 8*I*s2): 1, r13_20 - r1_20*sqrt(1 + 8*I*s2): 1, } f = x**4 + x**3 + x**2 + x + 1 r1_4, r1_8, r5_8 = [ Rational(*r) for r in ((1, 4), (1, 8), (5, 8)) ] assert roots(f, x) == { -r1_4 + r1_4*5**r1_2 + I*(r5_8 + r1_8*5**r1_2)**r1_2: 1, -r1_4 + r1_4*5**r1_2 - I*(r5_8 + r1_8*5**r1_2)**r1_2: 1, -r1_4 - r1_4*5**r1_2 + I*(r5_8 - r1_8*5**r1_2)**r1_2: 1, -r1_4 - r1_4*5**r1_2 - I*(r5_8 - r1_8*5**r1_2)**r1_2: 1, } f = z**3 + (-2 - y)*z**2 + (1 + 2*y - 2*x**2)*z - y + 2*x**2 assert roots(f, z) == { S.One: 1, S.Half + S.Half*y + S.Half*sqrt(1 - 2*y + y**2 + 8*x**2): 1, S.Half + S.Half*y - S.Half*sqrt(1 - 2*y + y**2 + 8*x**2): 1, } assert roots(a*b*c*x**3 + 2*x**2 + 4*x + 8, x, cubics=False) == {} assert roots(a*b*c*x**3 + 2*x**2 + 4*x + 8, x, cubics=True) != {} assert roots(x**4 - 1, x, filter='Z') == {S.One: 1, -S.One: 1} assert roots(x**4 - 1, x, filter='I') == {I: 1, -I: 1} assert roots((x - 1)*(x + 1), x) == {S.One: 1, -S.One: 1} assert roots( (x - 1)*(x + 1), x, predicate=lambda r: r.is_positive) == {S.One: 1} assert roots(x**4 - 1, x, filter='Z', multiple=True) == [-S.One, S.One] assert roots(x**4 - 1, x, filter='I', multiple=True) == [I, -I] ar, br = symbols('a, b', real=True) p = x**2*(ar-br)**2 + 2*x*(br-ar) + 1 assert roots(p, x, filter='R') == {1/(ar - br): 2} assert roots(x**3, x, multiple=True) == [S.Zero, S.Zero, S.Zero] assert roots(1234, x, multiple=True) == [] f = x**6 - x**5 + x**4 - x**3 + x**2 - x + 1 assert roots(f) == { -I*sin(pi/7) + cos(pi/7): 1, -I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 1, -I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 1, I*sin(pi/7) + cos(pi/7): 1, I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 1, I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 1, } g = ((x**2 + 1)*f**2).expand() assert roots(g) == { -I*sin(pi/7) + cos(pi/7): 2, -I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 2, -I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 2, I*sin(pi/7) + cos(pi/7): 2, I*sin(pi*Rational(2, 7)) - cos(pi*Rational(2, 7)): 2, I*sin(pi*Rational(3, 7)) + cos(pi*Rational(3, 7)): 2, -I: 1, I: 1, } r = roots(x**3 + 40*x + 64) real_root = [rx for rx in r if rx.is_real][0] cr = 108 + 6*sqrt(1074) assert real_root == -2*root(cr, 3)/3 + 20/root(cr, 3) eq = Poly((7 + 5*sqrt(2))*x**3 + (-6 - 4*sqrt(2))*x**2 + (-sqrt(2) - 1)*x + 2, x, domain='EX') assert roots(eq) == {-1 + sqrt(2): 1, -2 + 2*sqrt(2): 1, -sqrt(2) + 1: 1} eq = Poly(41*x**5 + 29*sqrt(2)*x**5 - 153*x**4 - 108*sqrt(2)*x**4 + 175*x**3 + 125*sqrt(2)*x**3 - 45*x**2 - 30*sqrt(2)*x**2 - 26*sqrt(2)*x - 26*x + 24, x, domain='EX') assert roots(eq) == {-sqrt(2) + 1: 1, -2 + 2*sqrt(2): 1, -1 + sqrt(2): 1, -4 + 4*sqrt(2): 1, -3 + 3*sqrt(2): 1} eq = Poly(x**3 - 2*x**2 + 6*sqrt(2)*x**2 - 8*sqrt(2)*x + 23*x - 14 + 14*sqrt(2), x, domain='EX') assert roots(eq) == {-2*sqrt(2) + 2: 1, -2*sqrt(2) + 1: 1, -2*sqrt(2) - 1: 1} assert roots(Poly((x + sqrt(2))**3 - 7, x, domain='EX')) == \ {-sqrt(2) + root(7, 3)*(-S.Half - sqrt(3)*I/2): 1, -sqrt(2) + root(7, 3)*(-S.Half + sqrt(3)*I/2): 1, -sqrt(2) + root(7, 3): 1} def test_roots_slow(): """Just test that calculating these roots does not hang. """ a, b, c, d, x = symbols("a,b,c,d,x") f1 = x**2*c + (a/b) + x*c*d - a f2 = x**2*(a + b*(c - d)*a) + x*a*b*c/(b*d - d) + (a*d - c/d) assert list(roots(f1, x).values()) == [1, 1] assert list(roots(f2, x).values()) == [1, 1] (zz, yy, xx, zy, zx, yx, k) = symbols("zz,yy,xx,zy,zx,yx,k") e1 = (zz - k)*(yy - k)*(xx - k) + zy*yx*zx + zx - zy - yx e2 = (zz - k)*yx*yx + zx*(yy - k)*zx + zy*zy*(xx - k) assert list(roots(e1 - e2, k).values()) == [1, 1, 1] f = x**3 + 2*x**2 + 8 R = list(roots(f).keys()) assert not any(i for i in [f.subs(x, ri).n(chop=True) for ri in R]) def test_roots_inexact(): R1 = roots(x**2 + x + 1, x, multiple=True) R2 = roots(x**2 + x + 1.0, x, multiple=True) for r1, r2 in zip(R1, R2): assert abs(r1 - r2) < 1e-12 f = x**4 + 3.0*sqrt(2.0)*x**3 - (78.0 + 24.0*sqrt(3.0))*x**2 \ + 144.0*(2*sqrt(3.0) + 9.0) R1 = roots(f, multiple=True) R2 = (-12.7530479110482, -3.85012393732929, 4.89897948556636, 7.46155167569183) for r1, r2 in zip(R1, R2): assert abs(r1 - r2) < 1e-10 def test_roots_preprocessed(): E, F, J, L = symbols("E,F,J,L") f = -21601054687500000000*E**8*J**8/L**16 + \ 508232812500000000*F*x*E**7*J**7/L**14 - \ 4269543750000000*E**6*F**2*J**6*x**2/L**12 + \ 16194716250000*E**5*F**3*J**5*x**3/L**10 - \ 27633173750*E**4*F**4*J**4*x**4/L**8 + \ 14840215*E**3*F**5*J**3*x**5/L**6 + \ 54794*E**2*F**6*J**2*x**6/(5*L**4) - \ 1153*E*J*F**7*x**7/(80*L**2) + \ 633*F**8*x**8/160000 assert roots(f, x) == {} R1 = roots(f.evalf(), x, multiple=True) R2 = [-1304.88375606366, 97.1168816800648, 186.946430171876, 245.526792947065, 503.441004174773, 791.549343830097, 1273.16678129348, 1850.10650616851] w = Wild('w') p = w*E*J/(F*L**2) assert len(R1) == len(R2) for r1, r2 in zip(R1, R2): match = r1.match(p) assert match is not None and abs(match[w] - r2) < 1e-10 def test_roots_mixed(): f = -1936 - 5056*x - 7592*x**2 + 2704*x**3 - 49*x**4 _re, _im = intervals(f, all=True) _nroots = nroots(f) _sroots = roots(f, multiple=True) _re = [ Interval(a, b) for (a, b), _ in _re ] _im = [ Interval(re(a), re(b))*Interval(im(a), im(b)) for (a, b), _ in _im ] _intervals = _re + _im _sroots = [ r.evalf() for r in _sroots ] _nroots = sorted(_nroots, key=lambda x: x.sort_key()) _sroots = sorted(_sroots, key=lambda x: x.sort_key()) for _roots in (_nroots, _sroots): for i, r in zip(_intervals, _roots): if r.is_real: assert r in i else: assert (re(r), im(r)) in i def test_root_factors(): assert root_factors(Poly(1, x)) == [Poly(1, x)] assert root_factors(Poly(x, x)) == [Poly(x, x)] assert root_factors(x**2 - 1, x) == [x + 1, x - 1] assert root_factors(x**2 - y, x) == [x - sqrt(y), x + sqrt(y)] assert root_factors((x**4 - 1)**2) == \ [x + 1, x + 1, x - 1, x - 1, x - I, x - I, x + I, x + I] assert root_factors(Poly(x**4 - 1, x), filter='Z') == \ [Poly(x + 1, x), Poly(x - 1, x), Poly(x**2 + 1, x)] assert root_factors(8*x**2 + 12*x**4 + 6*x**6 + x**8, x, filter='Q') == \ [x, x, x**6 + 6*x**4 + 12*x**2 + 8] @slow def test_nroots1(): n = 64 p = legendre_poly(n, x, polys=True) raises(mpmath.mp.NoConvergence, lambda: p.nroots(n=3, maxsteps=5)) roots = p.nroots(n=3) # The order of roots matters. They are ordered from smallest to the # largest. assert [str(r) for r in roots] == \ ['-0.999', '-0.996', '-0.991', '-0.983', '-0.973', '-0.961', '-0.946', '-0.930', '-0.911', '-0.889', '-0.866', '-0.841', '-0.813', '-0.784', '-0.753', '-0.720', '-0.685', '-0.649', '-0.611', '-0.572', '-0.531', '-0.489', '-0.446', '-0.402', '-0.357', '-0.311', '-0.265', '-0.217', '-0.170', '-0.121', '-0.0730', '-0.0243', '0.0243', '0.0730', '0.121', '0.170', '0.217', '0.265', '0.311', '0.357', '0.402', '0.446', '0.489', '0.531', '0.572', '0.611', '0.649', '0.685', '0.720', '0.753', '0.784', '0.813', '0.841', '0.866', '0.889', '0.911', '0.930', '0.946', '0.961', '0.973', '0.983', '0.991', '0.996', '0.999'] def test_nroots2(): p = Poly(x**5 + 3*x + 1, x) roots = p.nroots(n=3) # The order of roots matters. The roots are ordered by their real # components (if they agree, then by their imaginary components), # with real roots appearing first. assert [str(r) for r in roots] == \ ['-0.332', '-0.839 - 0.944*I', '-0.839 + 0.944*I', '1.01 - 0.937*I', '1.01 + 0.937*I'] roots = p.nroots(n=5) assert [str(r) for r in roots] == \ ['-0.33199', '-0.83907 - 0.94385*I', '-0.83907 + 0.94385*I', '1.0051 - 0.93726*I', '1.0051 + 0.93726*I'] def test_roots_composite(): assert len(roots(Poly(y**3 + y**2*sqrt(x) + y + x, y, composite=True))) == 3 def test_issue_19113(): eq = cos(x)**3 - cos(x) + 1 raises(PolynomialError, lambda: roots(eq)) sympy-sympy-1.9/sympy/polys/tests/test_polytools.py000066400000000000000000003540341412543434000231020ustar00rootroot00000000000000"""Tests for user-friendly public interface to polynomial functions. """ import pickle from sympy.polys.polytools import ( Poly, PurePoly, poly, parallel_poly_from_expr, degree, degree_list, total_degree, LC, LM, LT, pdiv, prem, pquo, pexquo, div, rem, quo, exquo, half_gcdex, gcdex, invert, subresultants, resultant, discriminant, terms_gcd, cofactors, gcd, gcd_list, lcm, lcm_list, trunc, monic, content, primitive, compose, decompose, sturm, gff_list, gff, sqf_norm, sqf_part, sqf_list, sqf, factor_list, factor, intervals, refine_root, count_roots, real_roots, nroots, ground_roots, nth_power_roots_poly, cancel, reduced, groebner, GroebnerBasis, is_zero_dimensional, _torational_factor_list, to_rational_coeffs) from sympy.polys.polyerrors import ( MultivariatePolynomialError, ExactQuotientFailed, PolificationFailed, ComputationFailed, UnificationFailed, RefinementFailed, GeneratorsNeeded, GeneratorsError, PolynomialError, CoercionFailed, DomainError, OptionError, FlagError) from sympy.polys.polyclasses import DMP from sympy.polys.fields import field from sympy.polys.domains import FF, ZZ, QQ, ZZ_I, QQ_I, RR, EX from sympy.polys.domains.realfield import RealField from sympy.polys.domains.complexfield import ComplexField from sympy.polys.orderings import lex, grlex, grevlex from sympy import ( S, Integer, Rational, Float, Mul, Symbol, sqrt, Piecewise, Derivative, exp, sin, tanh, expand, oo, I, pi, re, im, rootof, Eq, Tuple, Expr, diff) from sympy.core.add import Add from sympy.core.basic import _aresame from sympy.core.compatibility import iterable from sympy.core.mul import _keep_coeff from sympy.core.power import Pow from sympy.testing.pytest import raises, warns_deprecated_sympy from sympy.abc import a, b, c, d, p, q, t, w, x, y, z from sympy import MatrixSymbol, Matrix def _epsilon_eq(a, b): for u, v in zip(a, b): if abs(u - v) > 1e-10: return False return True def _strict_eq(a, b): if type(a) == type(b): if iterable(a): if len(a) == len(b): return all(_strict_eq(c, d) for c, d in zip(a, b)) else: return False else: return isinstance(a, Poly) and a.eq(b, strict=True) else: return False def test_Poly_mixed_operations(): p = Poly(x, x) with warns_deprecated_sympy(): p * exp(x) with warns_deprecated_sympy(): p + exp(x) with warns_deprecated_sympy(): p - exp(x) def test_Poly_from_dict(): K = FF(3) assert Poly.from_dict( {0: 1, 1: 2}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) assert Poly.from_dict( {0: 1, 1: 5}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) assert Poly.from_dict( {(0,): 1, (1,): 2}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) assert Poly.from_dict( {(0,): 1, (1,): 5}, gens=x, domain=K).rep == DMP([K(2), K(1)], K) assert Poly.from_dict({(0, 0): 1, (1, 1): 2}, gens=( x, y), domain=K).rep == DMP([[K(2), K(0)], [K(1)]], K) assert Poly.from_dict({0: 1, 1: 2}, gens=x).rep == DMP([ZZ(2), ZZ(1)], ZZ) assert Poly.from_dict( {0: 1, 1: 2}, gens=x, field=True).rep == DMP([QQ(2), QQ(1)], QQ) assert Poly.from_dict( {0: 1, 1: 2}, gens=x, domain=ZZ).rep == DMP([ZZ(2), ZZ(1)], ZZ) assert Poly.from_dict( {0: 1, 1: 2}, gens=x, domain=QQ).rep == DMP([QQ(2), QQ(1)], QQ) assert Poly.from_dict( {(0,): 1, (1,): 2}, gens=x).rep == DMP([ZZ(2), ZZ(1)], ZZ) assert Poly.from_dict( {(0,): 1, (1,): 2}, gens=x, field=True).rep == DMP([QQ(2), QQ(1)], QQ) assert Poly.from_dict( {(0,): 1, (1,): 2}, gens=x, domain=ZZ).rep == DMP([ZZ(2), ZZ(1)], ZZ) assert Poly.from_dict( {(0,): 1, (1,): 2}, gens=x, domain=QQ).rep == DMP([QQ(2), QQ(1)], QQ) assert Poly.from_dict({(1,): sin(y)}, gens=x, composite=False) == \ Poly(sin(y)*x, x, domain='EX') assert Poly.from_dict({(1,): y}, gens=x, composite=False) == \ Poly(y*x, x, domain='EX') assert Poly.from_dict({(1, 1): 1}, gens=(x, y), composite=False) == \ Poly(x*y, x, y, domain='ZZ') assert Poly.from_dict({(1, 0): y}, gens=(x, z), composite=False) == \ Poly(y*x, x, z, domain='EX') def test_Poly_from_list(): K = FF(3) assert Poly.from_list([2, 1], gens=x, domain=K).rep == DMP([K(2), K(1)], K) assert Poly.from_list([5, 1], gens=x, domain=K).rep == DMP([K(2), K(1)], K) assert Poly.from_list([2, 1], gens=x).rep == DMP([ZZ(2), ZZ(1)], ZZ) assert Poly.from_list([2, 1], gens=x, field=True).rep == DMP([QQ(2), QQ(1)], QQ) assert Poly.from_list([2, 1], gens=x, domain=ZZ).rep == DMP([ZZ(2), ZZ(1)], ZZ) assert Poly.from_list([2, 1], gens=x, domain=QQ).rep == DMP([QQ(2), QQ(1)], QQ) assert Poly.from_list([0, 1.0], gens=x).rep == DMP([RR(1.0)], RR) assert Poly.from_list([1.0, 0], gens=x).rep == DMP([RR(1.0), RR(0.0)], RR) raises(MultivariatePolynomialError, lambda: Poly.from_list([[]], gens=(x, y))) def test_Poly_from_poly(): f = Poly(x + 7, x, domain=ZZ) g = Poly(x + 2, x, modulus=3) h = Poly(x + y, x, y, domain=ZZ) K = FF(3) assert Poly.from_poly(f) == f assert Poly.from_poly(f, domain=K).rep == DMP([K(1), K(1)], K) assert Poly.from_poly(f, domain=ZZ).rep == DMP([1, 7], ZZ) assert Poly.from_poly(f, domain=QQ).rep == DMP([1, 7], QQ) assert Poly.from_poly(f, gens=x) == f assert Poly.from_poly(f, gens=x, domain=K).rep == DMP([K(1), K(1)], K) assert Poly.from_poly(f, gens=x, domain=ZZ).rep == DMP([1, 7], ZZ) assert Poly.from_poly(f, gens=x, domain=QQ).rep == DMP([1, 7], QQ) assert Poly.from_poly(f, gens=y) == Poly(x + 7, y, domain='ZZ[x]') raises(CoercionFailed, lambda: Poly.from_poly(f, gens=y, domain=K)) raises(CoercionFailed, lambda: Poly.from_poly(f, gens=y, domain=ZZ)) raises(CoercionFailed, lambda: Poly.from_poly(f, gens=y, domain=QQ)) assert Poly.from_poly(f, gens=(x, y)) == Poly(x + 7, x, y, domain='ZZ') assert Poly.from_poly( f, gens=(x, y), domain=ZZ) == Poly(x + 7, x, y, domain='ZZ') assert Poly.from_poly( f, gens=(x, y), domain=QQ) == Poly(x + 7, x, y, domain='QQ') assert Poly.from_poly( f, gens=(x, y), modulus=3) == Poly(x + 7, x, y, domain='FF(3)') K = FF(2) assert Poly.from_poly(g) == g assert Poly.from_poly(g, domain=ZZ).rep == DMP([1, -1], ZZ) raises(CoercionFailed, lambda: Poly.from_poly(g, domain=QQ)) assert Poly.from_poly(g, domain=K).rep == DMP([K(1), K(0)], K) assert Poly.from_poly(g, gens=x) == g assert Poly.from_poly(g, gens=x, domain=ZZ).rep == DMP([1, -1], ZZ) raises(CoercionFailed, lambda: Poly.from_poly(g, gens=x, domain=QQ)) assert Poly.from_poly(g, gens=x, domain=K).rep == DMP([K(1), K(0)], K) K = FF(3) assert Poly.from_poly(h) == h assert Poly.from_poly( h, domain=ZZ).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) assert Poly.from_poly( h, domain=QQ).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) assert Poly.from_poly(h, domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) assert Poly.from_poly(h, gens=x) == Poly(x + y, x, domain=ZZ[y]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=x, domain=ZZ)) assert Poly.from_poly( h, gens=x, domain=ZZ[y]) == Poly(x + y, x, domain=ZZ[y]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=x, domain=QQ)) assert Poly.from_poly( h, gens=x, domain=QQ[y]) == Poly(x + y, x, domain=QQ[y]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=x, modulus=3)) assert Poly.from_poly(h, gens=y) == Poly(x + y, y, domain=ZZ[x]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=y, domain=ZZ)) assert Poly.from_poly( h, gens=y, domain=ZZ[x]) == Poly(x + y, y, domain=ZZ[x]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=y, domain=QQ)) assert Poly.from_poly( h, gens=y, domain=QQ[x]) == Poly(x + y, y, domain=QQ[x]) raises(CoercionFailed, lambda: Poly.from_poly(h, gens=y, modulus=3)) assert Poly.from_poly(h, gens=(x, y)) == h assert Poly.from_poly( h, gens=(x, y), domain=ZZ).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) assert Poly.from_poly( h, gens=(x, y), domain=QQ).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) assert Poly.from_poly( h, gens=(x, y), domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) assert Poly.from_poly( h, gens=(y, x)).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) assert Poly.from_poly( h, gens=(y, x), domain=ZZ).rep == DMP([[ZZ(1)], [ZZ(1), ZZ(0)]], ZZ) assert Poly.from_poly( h, gens=(y, x), domain=QQ).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) assert Poly.from_poly( h, gens=(y, x), domain=K).rep == DMP([[K(1)], [K(1), K(0)]], K) assert Poly.from_poly( h, gens=(x, y), field=True).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) assert Poly.from_poly( h, gens=(x, y), field=True).rep == DMP([[QQ(1)], [QQ(1), QQ(0)]], QQ) def test_Poly_from_expr(): raises(GeneratorsNeeded, lambda: Poly.from_expr(S.Zero)) raises(GeneratorsNeeded, lambda: Poly.from_expr(S(7))) F3 = FF(3) assert Poly.from_expr(x + 5, domain=F3).rep == DMP([F3(1), F3(2)], F3) assert Poly.from_expr(y + 5, domain=F3).rep == DMP([F3(1), F3(2)], F3) assert Poly.from_expr(x + 5, x, domain=F3).rep == DMP([F3(1), F3(2)], F3) assert Poly.from_expr(y + 5, y, domain=F3).rep == DMP([F3(1), F3(2)], F3) assert Poly.from_expr(x + y, domain=F3).rep == DMP([[F3(1)], [F3(1), F3(0)]], F3) assert Poly.from_expr(x + y, x, y, domain=F3).rep == DMP([[F3(1)], [F3(1), F3(0)]], F3) assert Poly.from_expr(x + 5).rep == DMP([1, 5], ZZ) assert Poly.from_expr(y + 5).rep == DMP([1, 5], ZZ) assert Poly.from_expr(x + 5, x).rep == DMP([1, 5], ZZ) assert Poly.from_expr(y + 5, y).rep == DMP([1, 5], ZZ) assert Poly.from_expr(x + 5, domain=ZZ).rep == DMP([1, 5], ZZ) assert Poly.from_expr(y + 5, domain=ZZ).rep == DMP([1, 5], ZZ) assert Poly.from_expr(x + 5, x, domain=ZZ).rep == DMP([1, 5], ZZ) assert Poly.from_expr(y + 5, y, domain=ZZ).rep == DMP([1, 5], ZZ) assert Poly.from_expr(x + 5, x, y, domain=ZZ).rep == DMP([[1], [5]], ZZ) assert Poly.from_expr(y + 5, x, y, domain=ZZ).rep == DMP([[1, 5]], ZZ) def test_poly_from_domain_element(): dom = ZZ[x] assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) dom = dom.get_field() assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) dom = QQ[x] assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) dom = dom.get_field() assert Poly(dom(x+1), y, domain=dom).rep == DMP([dom(x+1)], dom) dom = ZZ.old_poly_ring(x) assert Poly(dom([1, 1]), y, domain=dom).rep == DMP([dom([1, 1])], dom) dom = dom.get_field() assert Poly(dom([1, 1]), y, domain=dom).rep == DMP([dom([1, 1])], dom) dom = QQ.old_poly_ring(x) assert Poly(dom([1, 1]), y, domain=dom).rep == DMP([dom([1, 1])], dom) dom = dom.get_field() assert Poly(dom([1, 1]), y, domain=dom).rep == DMP([dom([1, 1])], dom) dom = QQ.algebraic_field(I) assert Poly(dom([1, 1]), x, domain=dom).rep == DMP([dom([1, 1])], dom) def test_Poly__new__(): raises(GeneratorsError, lambda: Poly(x + 1, x, x)) raises(GeneratorsError, lambda: Poly(x + y, x, y, domain=ZZ[x])) raises(GeneratorsError, lambda: Poly(x + y, x, y, domain=ZZ[y])) raises(OptionError, lambda: Poly(x, x, symmetric=True)) raises(OptionError, lambda: Poly(x + 2, x, modulus=3, domain=QQ)) raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, gaussian=True)) raises(OptionError, lambda: Poly(x + 2, x, modulus=3, gaussian=True)) raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, extension=[sqrt(3)])) raises(OptionError, lambda: Poly(x + 2, x, modulus=3, extension=[sqrt(3)])) raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, extension=True)) raises(OptionError, lambda: Poly(x + 2, x, modulus=3, extension=True)) raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, greedy=True)) raises(OptionError, lambda: Poly(x + 2, x, domain=QQ, field=True)) raises(OptionError, lambda: Poly(x + 2, x, domain=ZZ, greedy=False)) raises(OptionError, lambda: Poly(x + 2, x, domain=QQ, field=False)) raises(NotImplementedError, lambda: Poly(x + 1, x, modulus=3, order='grlex')) raises(NotImplementedError, lambda: Poly(x + 1, x, order='grlex')) raises(GeneratorsNeeded, lambda: Poly({1: 2, 0: 1})) raises(GeneratorsNeeded, lambda: Poly([2, 1])) raises(GeneratorsNeeded, lambda: Poly((2, 1))) raises(GeneratorsNeeded, lambda: Poly(1)) f = a*x**2 + b*x + c assert Poly({2: a, 1: b, 0: c}, x) == f assert Poly(iter([a, b, c]), x) == f assert Poly([a, b, c], x) == f assert Poly((a, b, c), x) == f f = Poly({}, x, y, z) assert f.gens == (x, y, z) and f.as_expr() == 0 assert Poly(Poly(a*x + b*y, x, y), x) == Poly(a*x + b*y, x) assert Poly(3*x**2 + 2*x + 1, domain='ZZ').all_coeffs() == [3, 2, 1] assert Poly(3*x**2 + 2*x + 1, domain='QQ').all_coeffs() == [3, 2, 1] assert Poly(3*x**2 + 2*x + 1, domain='RR').all_coeffs() == [3.0, 2.0, 1.0] raises(CoercionFailed, lambda: Poly(3*x**2/5 + x*Rational(2, 5) + 1, domain='ZZ')) assert Poly( 3*x**2/5 + x*Rational(2, 5) + 1, domain='QQ').all_coeffs() == [Rational(3, 5), Rational(2, 5), 1] assert _epsilon_eq( Poly(3*x**2/5 + x*Rational(2, 5) + 1, domain='RR').all_coeffs(), [0.6, 0.4, 1.0]) assert Poly(3.0*x**2 + 2.0*x + 1, domain='ZZ').all_coeffs() == [3, 2, 1] assert Poly(3.0*x**2 + 2.0*x + 1, domain='QQ').all_coeffs() == [3, 2, 1] assert Poly( 3.0*x**2 + 2.0*x + 1, domain='RR').all_coeffs() == [3.0, 2.0, 1.0] raises(CoercionFailed, lambda: Poly(3.1*x**2 + 2.1*x + 1, domain='ZZ')) assert Poly(3.1*x**2 + 2.1*x + 1, domain='QQ').all_coeffs() == [Rational(31, 10), Rational(21, 10), 1] assert Poly(3.1*x**2 + 2.1*x + 1, domain='RR').all_coeffs() == [3.1, 2.1, 1.0] assert Poly({(2, 1): 1, (1, 2): 2, (1, 1): 3}, x, y) == \ Poly(x**2*y + 2*x*y**2 + 3*x*y, x, y) assert Poly(x**2 + 1, extension=I).get_domain() == QQ.algebraic_field(I) f = 3*x**5 - x**4 + x**3 - x** 2 + 65538 assert Poly(f, x, modulus=65537, symmetric=True) == \ Poly(3*x**5 - x**4 + x**3 - x** 2 + 1, x, modulus=65537, symmetric=True) assert Poly(f, x, modulus=65537, symmetric=False) == \ Poly(3*x**5 + 65536*x**4 + x**3 + 65536*x** 2 + 1, x, modulus=65537, symmetric=False) assert isinstance(Poly(x**2 + x + 1.0).get_domain(), RealField) assert isinstance(Poly(x**2 + x + I + 1.0).get_domain(), ComplexField) def test_Poly__args(): assert Poly(x**2 + 1).args == (x**2 + 1, x) def test_Poly__gens(): assert Poly((x - p)*(x - q), x).gens == (x,) assert Poly((x - p)*(x - q), p).gens == (p,) assert Poly((x - p)*(x - q), q).gens == (q,) assert Poly((x - p)*(x - q), x, p).gens == (x, p) assert Poly((x - p)*(x - q), x, q).gens == (x, q) assert Poly((x - p)*(x - q), x, p, q).gens == (x, p, q) assert Poly((x - p)*(x - q), p, x, q).gens == (p, x, q) assert Poly((x - p)*(x - q), p, q, x).gens == (p, q, x) assert Poly((x - p)*(x - q)).gens == (x, p, q) assert Poly((x - p)*(x - q), sort='x > p > q').gens == (x, p, q) assert Poly((x - p)*(x - q), sort='p > x > q').gens == (p, x, q) assert Poly((x - p)*(x - q), sort='p > q > x').gens == (p, q, x) assert Poly((x - p)*(x - q), x, p, q, sort='p > q > x').gens == (x, p, q) assert Poly((x - p)*(x - q), wrt='x').gens == (x, p, q) assert Poly((x - p)*(x - q), wrt='p').gens == (p, x, q) assert Poly((x - p)*(x - q), wrt='q').gens == (q, x, p) assert Poly((x - p)*(x - q), wrt=x).gens == (x, p, q) assert Poly((x - p)*(x - q), wrt=p).gens == (p, x, q) assert Poly((x - p)*(x - q), wrt=q).gens == (q, x, p) assert Poly((x - p)*(x - q), x, p, q, wrt='p').gens == (x, p, q) assert Poly((x - p)*(x - q), wrt='p', sort='q > x').gens == (p, q, x) assert Poly((x - p)*(x - q), wrt='q', sort='p > x').gens == (q, p, x) def test_Poly_zero(): assert Poly(x).zero == Poly(0, x, domain=ZZ) assert Poly(x/2).zero == Poly(0, x, domain=QQ) def test_Poly_one(): assert Poly(x).one == Poly(1, x, domain=ZZ) assert Poly(x/2).one == Poly(1, x, domain=QQ) def test_Poly__unify(): raises(UnificationFailed, lambda: Poly(x)._unify(y)) F3 = FF(3) F5 = FF(5) assert Poly(x, x, modulus=3)._unify(Poly(y, y, modulus=3))[2:] == ( DMP([[F3(1)], []], F3), DMP([[F3(1), F3(0)]], F3)) assert Poly(x, x, modulus=3)._unify(Poly(y, y, modulus=5))[2:] == ( DMP([[F5(1)], []], F5), DMP([[F5(1), F5(0)]], F5)) assert Poly(y, x, y)._unify(Poly(x, x, modulus=3))[2:] == (DMP([[F3(1), F3(0)]], F3), DMP([[F3(1)], []], F3)) assert Poly(x, x, modulus=3)._unify(Poly(y, x, y))[2:] == (DMP([[F3(1)], []], F3), DMP([[F3(1), F3(0)]], F3)) assert Poly(x + 1, x)._unify(Poly(x + 2, x))[2:] == (DMP([1, 1], ZZ), DMP([1, 2], ZZ)) assert Poly(x + 1, x, domain='QQ')._unify(Poly(x + 2, x))[2:] == (DMP([1, 1], QQ), DMP([1, 2], QQ)) assert Poly(x + 1, x)._unify(Poly(x + 2, x, domain='QQ'))[2:] == (DMP([1, 1], QQ), DMP([1, 2], QQ)) assert Poly(x + 1, x)._unify(Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) assert Poly(x + 1, x, domain='QQ')._unify(Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, x)._unify(Poly(x + 2, x, y, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, x, y)._unify(Poly(x + 2, x))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) assert Poly(x + 1, x, y, domain='QQ')._unify(Poly(x + 2, x))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) assert Poly(x + 1, x, y, domain='QQ')._unify(Poly(x + 2, x, y))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, x, y)._unify(Poly(x + 2, x, y, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, x)._unify(Poly(x + 2, y, x))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) assert Poly(x + 1, x, domain='QQ')._unify(Poly(x + 2, y, x))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) assert Poly(x + 1, x)._unify(Poly(x + 2, y, x, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) assert Poly(x + 1, y, x)._unify(Poly(x + 2, x))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) assert Poly(x + 1, y, x, domain='QQ')._unify(Poly(x + 2, x))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) assert Poly(x + 1, y, x)._unify(Poly(x + 2, x, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) assert Poly(x + 1, x, y)._unify(Poly(x + 2, y, x))[2:] == (DMP([[1], [1]], ZZ), DMP([[1], [2]], ZZ)) assert Poly(x + 1, x, y, domain='QQ')._unify(Poly(x + 2, y, x))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, x, y)._unify(Poly(x + 2, y, x, domain='QQ'))[2:] == (DMP([[1], [1]], QQ), DMP([[1], [2]], QQ)) assert Poly(x + 1, y, x)._unify(Poly(x + 2, x, y))[2:] == (DMP([[1, 1]], ZZ), DMP([[1, 2]], ZZ)) assert Poly(x + 1, y, x, domain='QQ')._unify(Poly(x + 2, x, y))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) assert Poly(x + 1, y, x)._unify(Poly(x + 2, x, y, domain='QQ'))[2:] == (DMP([[1, 1]], QQ), DMP([[1, 2]], QQ)) assert Poly(x**2 + I, x, domain=ZZ_I).unify(Poly(x**2 + sqrt(2), x, extension=True)) == \ (Poly(x**2 + I, x, domain='QQ'), Poly(x**2 + sqrt(2), x, domain='QQ')) F, A, B = field("a,b", ZZ) assert Poly(a*x, x, domain='ZZ[a]')._unify(Poly(a*b*x, x, domain='ZZ(a,b)'))[2:] == \ (DMP([A, F(0)], F.to_domain()), DMP([A*B, F(0)], F.to_domain())) assert Poly(a*x, x, domain='ZZ(a)')._unify(Poly(a*b*x, x, domain='ZZ(a,b)'))[2:] == \ (DMP([A, F(0)], F.to_domain()), DMP([A*B, F(0)], F.to_domain())) raises(CoercionFailed, lambda: Poly(Poly(x**2 + x**2*z, y, field=True), domain='ZZ(x)')) f = Poly(t**2 + t/3 + x, t, domain='QQ(x)') g = Poly(t**2 + t/3 + x, t, domain='QQ[x]') assert f._unify(g)[2:] == (f.rep, f.rep) def test_Poly_free_symbols(): assert Poly(x**2 + 1).free_symbols == {x} assert Poly(x**2 + y*z).free_symbols == {x, y, z} assert Poly(x**2 + y*z, x).free_symbols == {x, y, z} assert Poly(x**2 + sin(y*z)).free_symbols == {x, y, z} assert Poly(x**2 + sin(y*z), x).free_symbols == {x, y, z} assert Poly(x**2 + sin(y*z), x, domain=EX).free_symbols == {x, y, z} assert Poly(1 + x + x**2, x, y, z).free_symbols == {x} assert Poly(x + sin(y), z).free_symbols == {x, y} def test_PurePoly_free_symbols(): assert PurePoly(x**2 + 1).free_symbols == set() assert PurePoly(x**2 + y*z).free_symbols == set() assert PurePoly(x**2 + y*z, x).free_symbols == {y, z} assert PurePoly(x**2 + sin(y*z)).free_symbols == set() assert PurePoly(x**2 + sin(y*z), x).free_symbols == {y, z} assert PurePoly(x**2 + sin(y*z), x, domain=EX).free_symbols == {y, z} def test_Poly__eq__(): assert (Poly(x, x) == Poly(x, x)) is True assert (Poly(x, x, domain=QQ) == Poly(x, x)) is False assert (Poly(x, x) == Poly(x, x, domain=QQ)) is False assert (Poly(x, x, domain=ZZ[a]) == Poly(x, x)) is False assert (Poly(x, x) == Poly(x, x, domain=ZZ[a])) is False assert (Poly(x*y, x, y) == Poly(x, x)) is False assert (Poly(x, x, y) == Poly(x, x)) is False assert (Poly(x, x) == Poly(x, x, y)) is False assert (Poly(x**2 + 1, x) == Poly(y**2 + 1, y)) is False assert (Poly(y**2 + 1, y) == Poly(x**2 + 1, x)) is False f = Poly(x, x, domain=ZZ) g = Poly(x, x, domain=QQ) assert f.eq(g) is False assert f.ne(g) is True assert f.eq(g, strict=True) is False assert f.ne(g, strict=True) is True t0 = Symbol('t0') f = Poly((t0/2 + x**2)*t**2 - x**2*t, t, domain='QQ[x,t0]') g = Poly((t0/2 + x**2)*t**2 - x**2*t, t, domain='ZZ(x,t0)') assert (f == g) is False def test_PurePoly__eq__(): assert (PurePoly(x, x) == PurePoly(x, x)) is True assert (PurePoly(x, x, domain=QQ) == PurePoly(x, x)) is True assert (PurePoly(x, x) == PurePoly(x, x, domain=QQ)) is True assert (PurePoly(x, x, domain=ZZ[a]) == PurePoly(x, x)) is True assert (PurePoly(x, x) == PurePoly(x, x, domain=ZZ[a])) is True assert (PurePoly(x*y, x, y) == PurePoly(x, x)) is False assert (PurePoly(x, x, y) == PurePoly(x, x)) is False assert (PurePoly(x, x) == PurePoly(x, x, y)) is False assert (PurePoly(x**2 + 1, x) == PurePoly(y**2 + 1, y)) is True assert (PurePoly(y**2 + 1, y) == PurePoly(x**2 + 1, x)) is True f = PurePoly(x, x, domain=ZZ) g = PurePoly(x, x, domain=QQ) assert f.eq(g) is True assert f.ne(g) is False assert f.eq(g, strict=True) is False assert f.ne(g, strict=True) is True f = PurePoly(x, x, domain=ZZ) g = PurePoly(y, y, domain=QQ) assert f.eq(g) is True assert f.ne(g) is False assert f.eq(g, strict=True) is False assert f.ne(g, strict=True) is True def test_PurePoly_Poly(): assert isinstance(PurePoly(Poly(x**2 + 1)), PurePoly) is True assert isinstance(Poly(PurePoly(x**2 + 1)), Poly) is True def test_Poly_get_domain(): assert Poly(2*x).get_domain() == ZZ assert Poly(2*x, domain='ZZ').get_domain() == ZZ assert Poly(2*x, domain='QQ').get_domain() == QQ assert Poly(x/2).get_domain() == QQ raises(CoercionFailed, lambda: Poly(x/2, domain='ZZ')) assert Poly(x/2, domain='QQ').get_domain() == QQ assert isinstance(Poly(0.2*x).get_domain(), RealField) def test_Poly_set_domain(): assert Poly(2*x + 1).set_domain(ZZ) == Poly(2*x + 1) assert Poly(2*x + 1).set_domain('ZZ') == Poly(2*x + 1) assert Poly(2*x + 1).set_domain(QQ) == Poly(2*x + 1, domain='QQ') assert Poly(2*x + 1).set_domain('QQ') == Poly(2*x + 1, domain='QQ') assert Poly(Rational(2, 10)*x + Rational(1, 10)).set_domain('RR') == Poly(0.2*x + 0.1) assert Poly(0.2*x + 0.1).set_domain('QQ') == Poly(Rational(2, 10)*x + Rational(1, 10)) raises(CoercionFailed, lambda: Poly(x/2 + 1).set_domain(ZZ)) raises(CoercionFailed, lambda: Poly(x + 1, modulus=2).set_domain(QQ)) raises(GeneratorsError, lambda: Poly(x*y, x, y).set_domain(ZZ[y])) def test_Poly_get_modulus(): assert Poly(x**2 + 1, modulus=2).get_modulus() == 2 raises(PolynomialError, lambda: Poly(x**2 + 1).get_modulus()) def test_Poly_set_modulus(): assert Poly( x**2 + 1, modulus=2).set_modulus(7) == Poly(x**2 + 1, modulus=7) assert Poly( x**2 + 5, modulus=7).set_modulus(2) == Poly(x**2 + 1, modulus=2) assert Poly(x**2 + 1).set_modulus(2) == Poly(x**2 + 1, modulus=2) raises(CoercionFailed, lambda: Poly(x/2 + 1).set_modulus(2)) def test_Poly_add_ground(): assert Poly(x + 1).add_ground(2) == Poly(x + 3) def test_Poly_sub_ground(): assert Poly(x + 1).sub_ground(2) == Poly(x - 1) def test_Poly_mul_ground(): assert Poly(x + 1).mul_ground(2) == Poly(2*x + 2) def test_Poly_quo_ground(): assert Poly(2*x + 4).quo_ground(2) == Poly(x + 2) assert Poly(2*x + 3).quo_ground(2) == Poly(x + 1) def test_Poly_exquo_ground(): assert Poly(2*x + 4).exquo_ground(2) == Poly(x + 2) raises(ExactQuotientFailed, lambda: Poly(2*x + 3).exquo_ground(2)) def test_Poly_abs(): assert Poly(-x + 1, x).abs() == abs(Poly(-x + 1, x)) == Poly(x + 1, x) def test_Poly_neg(): assert Poly(-x + 1, x).neg() == -Poly(-x + 1, x) == Poly(x - 1, x) def test_Poly_add(): assert Poly(0, x).add(Poly(0, x)) == Poly(0, x) assert Poly(0, x) + Poly(0, x) == Poly(0, x) assert Poly(1, x).add(Poly(0, x)) == Poly(1, x) assert Poly(1, x, y) + Poly(0, x) == Poly(1, x, y) assert Poly(0, x).add(Poly(1, x, y)) == Poly(1, x, y) assert Poly(0, x, y) + Poly(1, x, y) == Poly(1, x, y) assert Poly(1, x) + x == Poly(x + 1, x) with warns_deprecated_sympy(): Poly(1, x) + sin(x) assert Poly(x, x) + 1 == Poly(x + 1, x) assert 1 + Poly(x, x) == Poly(x + 1, x) def test_Poly_sub(): assert Poly(0, x).sub(Poly(0, x)) == Poly(0, x) assert Poly(0, x) - Poly(0, x) == Poly(0, x) assert Poly(1, x).sub(Poly(0, x)) == Poly(1, x) assert Poly(1, x, y) - Poly(0, x) == Poly(1, x, y) assert Poly(0, x).sub(Poly(1, x, y)) == Poly(-1, x, y) assert Poly(0, x, y) - Poly(1, x, y) == Poly(-1, x, y) assert Poly(1, x) - x == Poly(1 - x, x) with warns_deprecated_sympy(): Poly(1, x) - sin(x) assert Poly(x, x) - 1 == Poly(x - 1, x) assert 1 - Poly(x, x) == Poly(1 - x, x) def test_Poly_mul(): assert Poly(0, x).mul(Poly(0, x)) == Poly(0, x) assert Poly(0, x) * Poly(0, x) == Poly(0, x) assert Poly(2, x).mul(Poly(4, x)) == Poly(8, x) assert Poly(2, x, y) * Poly(4, x) == Poly(8, x, y) assert Poly(4, x).mul(Poly(2, x, y)) == Poly(8, x, y) assert Poly(4, x, y) * Poly(2, x, y) == Poly(8, x, y) assert Poly(1, x) * x == Poly(x, x) with warns_deprecated_sympy(): Poly(1, x) * sin(x) assert Poly(x, x) * 2 == Poly(2*x, x) assert 2 * Poly(x, x) == Poly(2*x, x) def test_issue_13079(): assert Poly(x)*x == Poly(x**2, x, domain='ZZ') assert x*Poly(x) == Poly(x**2, x, domain='ZZ') assert -2*Poly(x) == Poly(-2*x, x, domain='ZZ') assert S(-2)*Poly(x) == Poly(-2*x, x, domain='ZZ') assert Poly(x)*S(-2) == Poly(-2*x, x, domain='ZZ') def test_Poly_sqr(): assert Poly(x*y, x, y).sqr() == Poly(x**2*y**2, x, y) def test_Poly_pow(): assert Poly(x, x).pow(10) == Poly(x**10, x) assert Poly(x, x).pow(Integer(10)) == Poly(x**10, x) assert Poly(2*y, x, y).pow(4) == Poly(16*y**4, x, y) assert Poly(2*y, x, y).pow(Integer(4)) == Poly(16*y**4, x, y) assert Poly(7*x*y, x, y)**3 == Poly(343*x**3*y**3, x, y) raises(TypeError, lambda: Poly(x*y + 1, x, y)**(-1)) raises(TypeError, lambda: Poly(x*y + 1, x, y)**x) def test_Poly_divmod(): f, g = Poly(x**2), Poly(x) q, r = g, Poly(0, x) assert divmod(f, g) == (q, r) assert f // g == q assert f % g == r assert divmod(f, x) == (q, r) assert f // x == q assert f % x == r q, r = Poly(0, x), Poly(2, x) assert divmod(2, g) == (q, r) assert 2 // g == q assert 2 % g == r assert Poly(x)/Poly(x) == 1 assert Poly(x**2)/Poly(x) == x assert Poly(x)/Poly(x**2) == 1/x def test_Poly_eq_ne(): assert (Poly(x + y, x, y) == Poly(x + y, x, y)) is True assert (Poly(x + y, x) == Poly(x + y, x, y)) is False assert (Poly(x + y, x, y) == Poly(x + y, x)) is False assert (Poly(x + y, x) == Poly(x + y, x)) is True assert (Poly(x + y, y) == Poly(x + y, y)) is True assert (Poly(x + y, x, y) == x + y) is True assert (Poly(x + y, x) == x + y) is True assert (Poly(x + y, x, y) == x + y) is True assert (Poly(x + y, x) == x + y) is True assert (Poly(x + y, y) == x + y) is True assert (Poly(x + y, x, y) != Poly(x + y, x, y)) is False assert (Poly(x + y, x) != Poly(x + y, x, y)) is True assert (Poly(x + y, x, y) != Poly(x + y, x)) is True assert (Poly(x + y, x) != Poly(x + y, x)) is False assert (Poly(x + y, y) != Poly(x + y, y)) is False assert (Poly(x + y, x, y) != x + y) is False assert (Poly(x + y, x) != x + y) is False assert (Poly(x + y, x, y) != x + y) is False assert (Poly(x + y, x) != x + y) is False assert (Poly(x + y, y) != x + y) is False assert (Poly(x, x) == sin(x)) is False assert (Poly(x, x) != sin(x)) is True def test_Poly_nonzero(): assert not bool(Poly(0, x)) is True assert not bool(Poly(1, x)) is False def test_Poly_properties(): assert Poly(0, x).is_zero is True assert Poly(1, x).is_zero is False assert Poly(1, x).is_one is True assert Poly(2, x).is_one is False assert Poly(x - 1, x).is_sqf is True assert Poly((x - 1)**2, x).is_sqf is False assert Poly(x - 1, x).is_monic is True assert Poly(2*x - 1, x).is_monic is False assert Poly(3*x + 2, x).is_primitive is True assert Poly(4*x + 2, x).is_primitive is False assert Poly(1, x).is_ground is True assert Poly(x, x).is_ground is False assert Poly(x + y + z + 1).is_linear is True assert Poly(x*y*z + 1).is_linear is False assert Poly(x*y + z + 1).is_quadratic is True assert Poly(x*y*z + 1).is_quadratic is False assert Poly(x*y).is_monomial is True assert Poly(x*y + 1).is_monomial is False assert Poly(x**2 + x*y).is_homogeneous is True assert Poly(x**3 + x*y).is_homogeneous is False assert Poly(x).is_univariate is True assert Poly(x*y).is_univariate is False assert Poly(x*y).is_multivariate is True assert Poly(x).is_multivariate is False assert Poly( x**16 + x**14 - x**10 + x**8 - x**6 + x**2 + 1).is_cyclotomic is False assert Poly( x**16 + x**14 - x**10 - x**8 - x**6 + x**2 + 1).is_cyclotomic is True def test_Poly_is_irreducible(): assert Poly(x**2 + x + 1).is_irreducible is True assert Poly(x**2 + 2*x + 1).is_irreducible is False assert Poly(7*x + 3, modulus=11).is_irreducible is True assert Poly(7*x**2 + 3*x + 1, modulus=11).is_irreducible is False def test_Poly_subs(): assert Poly(x + 1).subs(x, 0) == 1 assert Poly(x + 1).subs(x, x) == Poly(x + 1) assert Poly(x + 1).subs(x, y) == Poly(y + 1) assert Poly(x*y, x).subs(y, x) == x**2 assert Poly(x*y, x).subs(x, y) == y**2 def test_Poly_replace(): assert Poly(x + 1).replace(x) == Poly(x + 1) assert Poly(x + 1).replace(y) == Poly(y + 1) raises(PolynomialError, lambda: Poly(x + y).replace(z)) assert Poly(x + 1).replace(x, x) == Poly(x + 1) assert Poly(x + 1).replace(x, y) == Poly(y + 1) assert Poly(x + y).replace(x, x) == Poly(x + y) assert Poly(x + y).replace(x, z) == Poly(z + y, z, y) assert Poly(x + y).replace(y, y) == Poly(x + y) assert Poly(x + y).replace(y, z) == Poly(x + z, x, z) assert Poly(x + y).replace(z, t) == Poly(x + y) raises(PolynomialError, lambda: Poly(x + y).replace(x, y)) assert Poly(x + y, x).replace(x, z) == Poly(z + y, z) assert Poly(x + y, y).replace(y, z) == Poly(x + z, z) raises(PolynomialError, lambda: Poly(x + y, x).replace(x, y)) raises(PolynomialError, lambda: Poly(x + y, y).replace(y, x)) def test_Poly_reorder(): raises(PolynomialError, lambda: Poly(x + y).reorder(x, z)) assert Poly(x + y, x, y).reorder(x, y) == Poly(x + y, x, y) assert Poly(x + y, x, y).reorder(y, x) == Poly(x + y, y, x) assert Poly(x + y, y, x).reorder(x, y) == Poly(x + y, x, y) assert Poly(x + y, y, x).reorder(y, x) == Poly(x + y, y, x) assert Poly(x + y, x, y).reorder(wrt=x) == Poly(x + y, x, y) assert Poly(x + y, x, y).reorder(wrt=y) == Poly(x + y, y, x) def test_Poly_ltrim(): f = Poly(y**2 + y*z**2, x, y, z).ltrim(y) assert f.as_expr() == y**2 + y*z**2 and f.gens == (y, z) assert Poly(x*y - x, z, x, y).ltrim(1) == Poly(x*y - x, x, y) raises(PolynomialError, lambda: Poly(x*y**2 + y**2, x, y).ltrim(y)) raises(PolynomialError, lambda: Poly(x*y - x, x, y).ltrim(-1)) def test_Poly_has_only_gens(): assert Poly(x*y + 1, x, y, z).has_only_gens(x, y) is True assert Poly(x*y + z, x, y, z).has_only_gens(x, y) is False raises(GeneratorsError, lambda: Poly(x*y**2 + y**2, x, y).has_only_gens(t)) def test_Poly_to_ring(): assert Poly(2*x + 1, domain='ZZ').to_ring() == Poly(2*x + 1, domain='ZZ') assert Poly(2*x + 1, domain='QQ').to_ring() == Poly(2*x + 1, domain='ZZ') raises(CoercionFailed, lambda: Poly(x/2 + 1).to_ring()) raises(DomainError, lambda: Poly(2*x + 1, modulus=3).to_ring()) def test_Poly_to_field(): assert Poly(2*x + 1, domain='ZZ').to_field() == Poly(2*x + 1, domain='QQ') assert Poly(2*x + 1, domain='QQ').to_field() == Poly(2*x + 1, domain='QQ') assert Poly(x/2 + 1, domain='QQ').to_field() == Poly(x/2 + 1, domain='QQ') assert Poly(2*x + 1, modulus=3).to_field() == Poly(2*x + 1, modulus=3) assert Poly(2.0*x + 1.0).to_field() == Poly(2.0*x + 1.0) def test_Poly_to_exact(): assert Poly(2*x).to_exact() == Poly(2*x) assert Poly(x/2).to_exact() == Poly(x/2) assert Poly(0.1*x).to_exact() == Poly(x/10) def test_Poly_retract(): f = Poly(x**2 + 1, x, domain=QQ[y]) assert f.retract() == Poly(x**2 + 1, x, domain='ZZ') assert f.retract(field=True) == Poly(x**2 + 1, x, domain='QQ') assert Poly(0, x, y).retract() == Poly(0, x, y) def test_Poly_slice(): f = Poly(x**3 + 2*x**2 + 3*x + 4) assert f.slice(0, 0) == Poly(0, x) assert f.slice(0, 1) == Poly(4, x) assert f.slice(0, 2) == Poly(3*x + 4, x) assert f.slice(0, 3) == Poly(2*x**2 + 3*x + 4, x) assert f.slice(0, 4) == Poly(x**3 + 2*x**2 + 3*x + 4, x) assert f.slice(x, 0, 0) == Poly(0, x) assert f.slice(x, 0, 1) == Poly(4, x) assert f.slice(x, 0, 2) == Poly(3*x + 4, x) assert f.slice(x, 0, 3) == Poly(2*x**2 + 3*x + 4, x) assert f.slice(x, 0, 4) == Poly(x**3 + 2*x**2 + 3*x + 4, x) def test_Poly_coeffs(): assert Poly(0, x).coeffs() == [0] assert Poly(1, x).coeffs() == [1] assert Poly(2*x + 1, x).coeffs() == [2, 1] assert Poly(7*x**2 + 2*x + 1, x).coeffs() == [7, 2, 1] assert Poly(7*x**4 + 2*x + 1, x).coeffs() == [7, 2, 1] assert Poly(x*y**7 + 2*x**2*y**3).coeffs('lex') == [2, 1] assert Poly(x*y**7 + 2*x**2*y**3).coeffs('grlex') == [1, 2] def test_Poly_monoms(): assert Poly(0, x).monoms() == [(0,)] assert Poly(1, x).monoms() == [(0,)] assert Poly(2*x + 1, x).monoms() == [(1,), (0,)] assert Poly(7*x**2 + 2*x + 1, x).monoms() == [(2,), (1,), (0,)] assert Poly(7*x**4 + 2*x + 1, x).monoms() == [(4,), (1,), (0,)] assert Poly(x*y**7 + 2*x**2*y**3).monoms('lex') == [(2, 3), (1, 7)] assert Poly(x*y**7 + 2*x**2*y**3).monoms('grlex') == [(1, 7), (2, 3)] def test_Poly_terms(): assert Poly(0, x).terms() == [((0,), 0)] assert Poly(1, x).terms() == [((0,), 1)] assert Poly(2*x + 1, x).terms() == [((1,), 2), ((0,), 1)] assert Poly(7*x**2 + 2*x + 1, x).terms() == [((2,), 7), ((1,), 2), ((0,), 1)] assert Poly(7*x**4 + 2*x + 1, x).terms() == [((4,), 7), ((1,), 2), ((0,), 1)] assert Poly( x*y**7 + 2*x**2*y**3).terms('lex') == [((2, 3), 2), ((1, 7), 1)] assert Poly( x*y**7 + 2*x**2*y**3).terms('grlex') == [((1, 7), 1), ((2, 3), 2)] def test_Poly_all_coeffs(): assert Poly(0, x).all_coeffs() == [0] assert Poly(1, x).all_coeffs() == [1] assert Poly(2*x + 1, x).all_coeffs() == [2, 1] assert Poly(7*x**2 + 2*x + 1, x).all_coeffs() == [7, 2, 1] assert Poly(7*x**4 + 2*x + 1, x).all_coeffs() == [7, 0, 0, 2, 1] def test_Poly_all_monoms(): assert Poly(0, x).all_monoms() == [(0,)] assert Poly(1, x).all_monoms() == [(0,)] assert Poly(2*x + 1, x).all_monoms() == [(1,), (0,)] assert Poly(7*x**2 + 2*x + 1, x).all_monoms() == [(2,), (1,), (0,)] assert Poly(7*x**4 + 2*x + 1, x).all_monoms() == [(4,), (3,), (2,), (1,), (0,)] def test_Poly_all_terms(): assert Poly(0, x).all_terms() == [((0,), 0)] assert Poly(1, x).all_terms() == [((0,), 1)] assert Poly(2*x + 1, x).all_terms() == [((1,), 2), ((0,), 1)] assert Poly(7*x**2 + 2*x + 1, x).all_terms() == \ [((2,), 7), ((1,), 2), ((0,), 1)] assert Poly(7*x**4 + 2*x + 1, x).all_terms() == \ [((4,), 7), ((3,), 0), ((2,), 0), ((1,), 2), ((0,), 1)] def test_Poly_termwise(): f = Poly(x**2 + 20*x + 400) g = Poly(x**2 + 2*x + 4) def func(monom, coeff): (k,) = monom return coeff//10**(2 - k) assert f.termwise(func) == g def func(monom, coeff): (k,) = monom return (k,), coeff//10**(2 - k) assert f.termwise(func) == g def test_Poly_length(): assert Poly(0, x).length() == 0 assert Poly(1, x).length() == 1 assert Poly(x, x).length() == 1 assert Poly(x + 1, x).length() == 2 assert Poly(x**2 + 1, x).length() == 2 assert Poly(x**2 + x + 1, x).length() == 3 def test_Poly_as_dict(): assert Poly(0, x).as_dict() == {} assert Poly(0, x, y, z).as_dict() == {} assert Poly(1, x).as_dict() == {(0,): 1} assert Poly(1, x, y, z).as_dict() == {(0, 0, 0): 1} assert Poly(x**2 + 3, x).as_dict() == {(2,): 1, (0,): 3} assert Poly(x**2 + 3, x, y, z).as_dict() == {(2, 0, 0): 1, (0, 0, 0): 3} assert Poly(3*x**2*y*z**3 + 4*x*y + 5*x*z).as_dict() == {(2, 1, 3): 3, (1, 1, 0): 4, (1, 0, 1): 5} def test_Poly_as_expr(): assert Poly(0, x).as_expr() == 0 assert Poly(0, x, y, z).as_expr() == 0 assert Poly(1, x).as_expr() == 1 assert Poly(1, x, y, z).as_expr() == 1 assert Poly(x**2 + 3, x).as_expr() == x**2 + 3 assert Poly(x**2 + 3, x, y, z).as_expr() == x**2 + 3 assert Poly( 3*x**2*y*z**3 + 4*x*y + 5*x*z).as_expr() == 3*x**2*y*z**3 + 4*x*y + 5*x*z f = Poly(x**2 + 2*x*y**2 - y, x, y) assert f.as_expr() == -y + x**2 + 2*x*y**2 assert f.as_expr({x: 5}) == 25 - y + 10*y**2 assert f.as_expr({y: 6}) == -6 + 72*x + x**2 assert f.as_expr({x: 5, y: 6}) == 379 assert f.as_expr(5, 6) == 379 raises(GeneratorsError, lambda: f.as_expr({z: 7})) def test_Poly_lift(): assert Poly(x**4 - I*x + 17*I, x, gaussian=True).lift() == \ Poly(x**16 + 2*x**10 + 578*x**8 + x**4 - 578*x**2 + 83521, x, domain='QQ') def test_Poly_deflate(): assert Poly(0, x).deflate() == ((1,), Poly(0, x)) assert Poly(1, x).deflate() == ((1,), Poly(1, x)) assert Poly(x, x).deflate() == ((1,), Poly(x, x)) assert Poly(x**2, x).deflate() == ((2,), Poly(x, x)) assert Poly(x**17, x).deflate() == ((17,), Poly(x, x)) assert Poly( x**2*y*z**11 + x**4*z**11).deflate() == ((2, 1, 11), Poly(x*y*z + x**2*z)) def test_Poly_inject(): f = Poly(x**2*y + x*y**3 + x*y + 1, x) assert f.inject() == Poly(x**2*y + x*y**3 + x*y + 1, x, y) assert f.inject(front=True) == Poly(y**3*x + y*x**2 + y*x + 1, y, x) def test_Poly_eject(): f = Poly(x**2*y + x*y**3 + x*y + 1, x, y) assert f.eject(x) == Poly(x*y**3 + (x**2 + x)*y + 1, y, domain='ZZ[x]') assert f.eject(y) == Poly(y*x**2 + (y**3 + y)*x + 1, x, domain='ZZ[y]') ex = x + y + z + t + w g = Poly(ex, x, y, z, t, w) assert g.eject(x) == Poly(ex, y, z, t, w, domain='ZZ[x]') assert g.eject(x, y) == Poly(ex, z, t, w, domain='ZZ[x, y]') assert g.eject(x, y, z) == Poly(ex, t, w, domain='ZZ[x, y, z]') assert g.eject(w) == Poly(ex, x, y, z, t, domain='ZZ[w]') assert g.eject(t, w) == Poly(ex, x, y, z, domain='ZZ[t, w]') assert g.eject(z, t, w) == Poly(ex, x, y, domain='ZZ[z, t, w]') raises(DomainError, lambda: Poly(x*y, x, y, domain=ZZ[z]).eject(y)) raises(NotImplementedError, lambda: Poly(x*y, x, y, z).eject(y)) def test_Poly_exclude(): assert Poly(x, x, y).exclude() == Poly(x, x) assert Poly(x*y, x, y).exclude() == Poly(x*y, x, y) assert Poly(1, x, y).exclude() == Poly(1, x, y) def test_Poly__gen_to_level(): assert Poly(1, x, y)._gen_to_level(-2) == 0 assert Poly(1, x, y)._gen_to_level(-1) == 1 assert Poly(1, x, y)._gen_to_level( 0) == 0 assert Poly(1, x, y)._gen_to_level( 1) == 1 raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level(-3)) raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level( 2)) assert Poly(1, x, y)._gen_to_level(x) == 0 assert Poly(1, x, y)._gen_to_level(y) == 1 assert Poly(1, x, y)._gen_to_level('x') == 0 assert Poly(1, x, y)._gen_to_level('y') == 1 raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level(z)) raises(PolynomialError, lambda: Poly(1, x, y)._gen_to_level('z')) def test_Poly_degree(): assert Poly(0, x).degree() is -oo assert Poly(1, x).degree() == 0 assert Poly(x, x).degree() == 1 assert Poly(0, x).degree(gen=0) is -oo assert Poly(1, x).degree(gen=0) == 0 assert Poly(x, x).degree(gen=0) == 1 assert Poly(0, x).degree(gen=x) is -oo assert Poly(1, x).degree(gen=x) == 0 assert Poly(x, x).degree(gen=x) == 1 assert Poly(0, x).degree(gen='x') is -oo assert Poly(1, x).degree(gen='x') == 0 assert Poly(x, x).degree(gen='x') == 1 raises(PolynomialError, lambda: Poly(1, x).degree(gen=1)) raises(PolynomialError, lambda: Poly(1, x).degree(gen=y)) raises(PolynomialError, lambda: Poly(1, x).degree(gen='y')) assert Poly(1, x, y).degree() == 0 assert Poly(2*y, x, y).degree() == 0 assert Poly(x*y, x, y).degree() == 1 assert Poly(1, x, y).degree(gen=x) == 0 assert Poly(2*y, x, y).degree(gen=x) == 0 assert Poly(x*y, x, y).degree(gen=x) == 1 assert Poly(1, x, y).degree(gen=y) == 0 assert Poly(2*y, x, y).degree(gen=y) == 1 assert Poly(x*y, x, y).degree(gen=y) == 1 assert degree(0, x) is -oo assert degree(1, x) == 0 assert degree(x, x) == 1 assert degree(x*y**2, x) == 1 assert degree(x*y**2, y) == 2 assert degree(x*y**2, z) == 0 assert degree(pi) == 1 raises(TypeError, lambda: degree(y**2 + x**3)) raises(TypeError, lambda: degree(y**2 + x**3, 1)) raises(PolynomialError, lambda: degree(x, 1.1)) raises(PolynomialError, lambda: degree(x**2/(x**3 + 1), x)) assert degree(Poly(0,x),z) is -oo assert degree(Poly(1,x),z) == 0 assert degree(Poly(x**2+y**3,y)) == 3 assert degree(Poly(y**2 + x**3, y, x), 1) == 3 assert degree(Poly(y**2 + x**3, x), z) == 0 assert degree(Poly(y**2 + x**3 + z**4, x), z) == 4 def test_Poly_degree_list(): assert Poly(0, x).degree_list() == (-oo,) assert Poly(0, x, y).degree_list() == (-oo, -oo) assert Poly(0, x, y, z).degree_list() == (-oo, -oo, -oo) assert Poly(1, x).degree_list() == (0,) assert Poly(1, x, y).degree_list() == (0, 0) assert Poly(1, x, y, z).degree_list() == (0, 0, 0) assert Poly(x**2*y + x**3*z**2 + 1).degree_list() == (3, 1, 2) assert degree_list(1, x) == (0,) assert degree_list(x, x) == (1,) assert degree_list(x*y**2) == (1, 2) raises(ComputationFailed, lambda: degree_list(1)) def test_Poly_total_degree(): assert Poly(x**2*y + x**3*z**2 + 1).total_degree() == 5 assert Poly(x**2 + z**3).total_degree() == 3 assert Poly(x*y*z + z**4).total_degree() == 4 assert Poly(x**3 + x + 1).total_degree() == 3 assert total_degree(x*y + z**3) == 3 assert total_degree(x*y + z**3, x, y) == 2 assert total_degree(1) == 0 assert total_degree(Poly(y**2 + x**3 + z**4)) == 4 assert total_degree(Poly(y**2 + x**3 + z**4, x)) == 3 assert total_degree(Poly(y**2 + x**3 + z**4, x), z) == 4 assert total_degree(Poly(x**9 + x*z*y + x**3*z**2 + z**7,x), z) == 7 def test_Poly_homogenize(): assert Poly(x**2+y).homogenize(z) == Poly(x**2+y*z) assert Poly(x+y).homogenize(z) == Poly(x+y, x, y, z) assert Poly(x+y**2).homogenize(y) == Poly(x*y+y**2) def test_Poly_homogeneous_order(): assert Poly(0, x, y).homogeneous_order() is -oo assert Poly(1, x, y).homogeneous_order() == 0 assert Poly(x, x, y).homogeneous_order() == 1 assert Poly(x*y, x, y).homogeneous_order() == 2 assert Poly(x + 1, x, y).homogeneous_order() is None assert Poly(x*y + x, x, y).homogeneous_order() is None assert Poly(x**5 + 2*x**3*y**2 + 9*x*y**4).homogeneous_order() == 5 assert Poly(x**5 + 2*x**3*y**3 + 9*x*y**4).homogeneous_order() is None def test_Poly_LC(): assert Poly(0, x).LC() == 0 assert Poly(1, x).LC() == 1 assert Poly(2*x**2 + x, x).LC() == 2 assert Poly(x*y**7 + 2*x**2*y**3).LC('lex') == 2 assert Poly(x*y**7 + 2*x**2*y**3).LC('grlex') == 1 assert LC(x*y**7 + 2*x**2*y**3, order='lex') == 2 assert LC(x*y**7 + 2*x**2*y**3, order='grlex') == 1 def test_Poly_TC(): assert Poly(0, x).TC() == 0 assert Poly(1, x).TC() == 1 assert Poly(2*x**2 + x, x).TC() == 0 def test_Poly_EC(): assert Poly(0, x).EC() == 0 assert Poly(1, x).EC() == 1 assert Poly(2*x**2 + x, x).EC() == 1 assert Poly(x*y**7 + 2*x**2*y**3).EC('lex') == 1 assert Poly(x*y**7 + 2*x**2*y**3).EC('grlex') == 2 def test_Poly_coeff(): assert Poly(0, x).coeff_monomial(1) == 0 assert Poly(0, x).coeff_monomial(x) == 0 assert Poly(1, x).coeff_monomial(1) == 1 assert Poly(1, x).coeff_monomial(x) == 0 assert Poly(x**8, x).coeff_monomial(1) == 0 assert Poly(x**8, x).coeff_monomial(x**7) == 0 assert Poly(x**8, x).coeff_monomial(x**8) == 1 assert Poly(x**8, x).coeff_monomial(x**9) == 0 assert Poly(3*x*y**2 + 1, x, y).coeff_monomial(1) == 1 assert Poly(3*x*y**2 + 1, x, y).coeff_monomial(x*y**2) == 3 p = Poly(24*x*y*exp(8) + 23*x, x, y) assert p.coeff_monomial(x) == 23 assert p.coeff_monomial(y) == 0 assert p.coeff_monomial(x*y) == 24*exp(8) assert p.as_expr().coeff(x) == 24*y*exp(8) + 23 raises(NotImplementedError, lambda: p.coeff(x)) raises(ValueError, lambda: Poly(x + 1).coeff_monomial(0)) raises(ValueError, lambda: Poly(x + 1).coeff_monomial(3*x)) raises(ValueError, lambda: Poly(x + 1).coeff_monomial(3*x*y)) def test_Poly_nth(): assert Poly(0, x).nth(0) == 0 assert Poly(0, x).nth(1) == 0 assert Poly(1, x).nth(0) == 1 assert Poly(1, x).nth(1) == 0 assert Poly(x**8, x).nth(0) == 0 assert Poly(x**8, x).nth(7) == 0 assert Poly(x**8, x).nth(8) == 1 assert Poly(x**8, x).nth(9) == 0 assert Poly(3*x*y**2 + 1, x, y).nth(0, 0) == 1 assert Poly(3*x*y**2 + 1, x, y).nth(1, 2) == 3 raises(ValueError, lambda: Poly(x*y + 1, x, y).nth(1)) def test_Poly_LM(): assert Poly(0, x).LM() == (0,) assert Poly(1, x).LM() == (0,) assert Poly(2*x**2 + x, x).LM() == (2,) assert Poly(x*y**7 + 2*x**2*y**3).LM('lex') == (2, 3) assert Poly(x*y**7 + 2*x**2*y**3).LM('grlex') == (1, 7) assert LM(x*y**7 + 2*x**2*y**3, order='lex') == x**2*y**3 assert LM(x*y**7 + 2*x**2*y**3, order='grlex') == x*y**7 def test_Poly_LM_custom_order(): f = Poly(x**2*y**3*z + x**2*y*z**3 + x*y*z + 1) rev_lex = lambda monom: tuple(reversed(monom)) assert f.LM(order='lex') == (2, 3, 1) assert f.LM(order=rev_lex) == (2, 1, 3) def test_Poly_EM(): assert Poly(0, x).EM() == (0,) assert Poly(1, x).EM() == (0,) assert Poly(2*x**2 + x, x).EM() == (1,) assert Poly(x*y**7 + 2*x**2*y**3).EM('lex') == (1, 7) assert Poly(x*y**7 + 2*x**2*y**3).EM('grlex') == (2, 3) def test_Poly_LT(): assert Poly(0, x).LT() == ((0,), 0) assert Poly(1, x).LT() == ((0,), 1) assert Poly(2*x**2 + x, x).LT() == ((2,), 2) assert Poly(x*y**7 + 2*x**2*y**3).LT('lex') == ((2, 3), 2) assert Poly(x*y**7 + 2*x**2*y**3).LT('grlex') == ((1, 7), 1) assert LT(x*y**7 + 2*x**2*y**3, order='lex') == 2*x**2*y**3 assert LT(x*y**7 + 2*x**2*y**3, order='grlex') == x*y**7 def test_Poly_ET(): assert Poly(0, x).ET() == ((0,), 0) assert Poly(1, x).ET() == ((0,), 1) assert Poly(2*x**2 + x, x).ET() == ((1,), 1) assert Poly(x*y**7 + 2*x**2*y**3).ET('lex') == ((1, 7), 1) assert Poly(x*y**7 + 2*x**2*y**3).ET('grlex') == ((2, 3), 2) def test_Poly_max_norm(): assert Poly(-1, x).max_norm() == 1 assert Poly( 0, x).max_norm() == 0 assert Poly( 1, x).max_norm() == 1 def test_Poly_l1_norm(): assert Poly(-1, x).l1_norm() == 1 assert Poly( 0, x).l1_norm() == 0 assert Poly( 1, x).l1_norm() == 1 def test_Poly_clear_denoms(): coeff, poly = Poly(x + 2, x).clear_denoms() assert coeff == 1 and poly == Poly( x + 2, x, domain='ZZ') and poly.get_domain() == ZZ coeff, poly = Poly(x/2 + 1, x).clear_denoms() assert coeff == 2 and poly == Poly( x + 2, x, domain='QQ') and poly.get_domain() == QQ coeff, poly = Poly(x/2 + 1, x).clear_denoms(convert=True) assert coeff == 2 and poly == Poly( x + 2, x, domain='ZZ') and poly.get_domain() == ZZ coeff, poly = Poly(x/y + 1, x).clear_denoms(convert=True) assert coeff == y and poly == Poly( x + y, x, domain='ZZ[y]') and poly.get_domain() == ZZ[y] coeff, poly = Poly(x/3 + sqrt(2), x, domain='EX').clear_denoms() assert coeff == 3 and poly == Poly( x + 3*sqrt(2), x, domain='EX') and poly.get_domain() == EX coeff, poly = Poly( x/3 + sqrt(2), x, domain='EX').clear_denoms(convert=True) assert coeff == 3 and poly == Poly( x + 3*sqrt(2), x, domain='EX') and poly.get_domain() == EX def test_Poly_rat_clear_denoms(): f = Poly(x**2/y + 1, x) g = Poly(x**3 + y, x) assert f.rat_clear_denoms(g) == \ (Poly(x**2 + y, x), Poly(y*x**3 + y**2, x)) f = f.set_domain(EX) g = g.set_domain(EX) assert f.rat_clear_denoms(g) == (f, g) def test_issue_20427(): f = Poly(-117968192370600*18**(S(1)/3)/(217603955769048*(24201 + 253*sqrt(9165))**(S(1)/3) + 2273005839412*sqrt(9165)*(24201 + 253*sqrt(9165))**(S(1)/3)) - 15720318185*2**(S(2)/3)*3**(S(1)/3)*(24201 + 253*sqrt(9165))**(S(2)/3)/(217603955769048*(24201 + 253*sqrt(9165))** (S(1)/3) + 2273005839412*sqrt(9165)*(24201 + 253*sqrt(9165))**(S(1)/3)) + 15720318185*12**(S(1)/3)*(24201 + 253*sqrt(9165))**(S(2)/3)/( 217603955769048*(24201 + 253*sqrt(9165))**(S(1)/3) + 2273005839412* sqrt(9165)*(24201 + 253*sqrt(9165))**(S(1)/3)) + 117968192370600*2**( S(1)/3)*3**(S(2)/3)/(217603955769048*(24201 + 253*sqrt(9165))**(S(1)/3) + 2273005839412*sqrt(9165)*(24201 + 253*sqrt(9165))**(S(1)/3)), x) assert f == Poly(0, x, domain='EX') def test_Poly_integrate(): assert Poly(x + 1).integrate() == Poly(x**2/2 + x) assert Poly(x + 1).integrate(x) == Poly(x**2/2 + x) assert Poly(x + 1).integrate((x, 1)) == Poly(x**2/2 + x) assert Poly(x*y + 1).integrate(x) == Poly(x**2*y/2 + x) assert Poly(x*y + 1).integrate(y) == Poly(x*y**2/2 + y) assert Poly(x*y + 1).integrate(x, x) == Poly(x**3*y/6 + x**2/2) assert Poly(x*y + 1).integrate(y, y) == Poly(x*y**3/6 + y**2/2) assert Poly(x*y + 1).integrate((x, 2)) == Poly(x**3*y/6 + x**2/2) assert Poly(x*y + 1).integrate((y, 2)) == Poly(x*y**3/6 + y**2/2) assert Poly(x*y + 1).integrate(x, y) == Poly(x**2*y**2/4 + x*y) assert Poly(x*y + 1).integrate(y, x) == Poly(x**2*y**2/4 + x*y) def test_Poly_diff(): assert Poly(x**2 + x).diff() == Poly(2*x + 1) assert Poly(x**2 + x).diff(x) == Poly(2*x + 1) assert Poly(x**2 + x).diff((x, 1)) == Poly(2*x + 1) assert Poly(x**2*y**2 + x*y).diff(x) == Poly(2*x*y**2 + y) assert Poly(x**2*y**2 + x*y).diff(y) == Poly(2*x**2*y + x) assert Poly(x**2*y**2 + x*y).diff(x, x) == Poly(2*y**2, x, y) assert Poly(x**2*y**2 + x*y).diff(y, y) == Poly(2*x**2, x, y) assert Poly(x**2*y**2 + x*y).diff((x, 2)) == Poly(2*y**2, x, y) assert Poly(x**2*y**2 + x*y).diff((y, 2)) == Poly(2*x**2, x, y) assert Poly(x**2*y**2 + x*y).diff(x, y) == Poly(4*x*y + 1) assert Poly(x**2*y**2 + x*y).diff(y, x) == Poly(4*x*y + 1) def test_issue_9585(): assert diff(Poly(x**2 + x)) == Poly(2*x + 1) assert diff(Poly(x**2 + x), x, evaluate=False) == \ Derivative(Poly(x**2 + x), x) assert Derivative(Poly(x**2 + x), x).doit() == Poly(2*x + 1) def test_Poly_eval(): assert Poly(0, x).eval(7) == 0 assert Poly(1, x).eval(7) == 1 assert Poly(x, x).eval(7) == 7 assert Poly(0, x).eval(0, 7) == 0 assert Poly(1, x).eval(0, 7) == 1 assert Poly(x, x).eval(0, 7) == 7 assert Poly(0, x).eval(x, 7) == 0 assert Poly(1, x).eval(x, 7) == 1 assert Poly(x, x).eval(x, 7) == 7 assert Poly(0, x).eval('x', 7) == 0 assert Poly(1, x).eval('x', 7) == 1 assert Poly(x, x).eval('x', 7) == 7 raises(PolynomialError, lambda: Poly(1, x).eval(1, 7)) raises(PolynomialError, lambda: Poly(1, x).eval(y, 7)) raises(PolynomialError, lambda: Poly(1, x).eval('y', 7)) assert Poly(123, x, y).eval(7) == Poly(123, y) assert Poly(2*y, x, y).eval(7) == Poly(2*y, y) assert Poly(x*y, x, y).eval(7) == Poly(7*y, y) assert Poly(123, x, y).eval(x, 7) == Poly(123, y) assert Poly(2*y, x, y).eval(x, 7) == Poly(2*y, y) assert Poly(x*y, x, y).eval(x, 7) == Poly(7*y, y) assert Poly(123, x, y).eval(y, 7) == Poly(123, x) assert Poly(2*y, x, y).eval(y, 7) == Poly(14, x) assert Poly(x*y, x, y).eval(y, 7) == Poly(7*x, x) assert Poly(x*y + y, x, y).eval({x: 7}) == Poly(8*y, y) assert Poly(x*y + y, x, y).eval({y: 7}) == Poly(7*x + 7, x) assert Poly(x*y + y, x, y).eval({x: 6, y: 7}) == 49 assert Poly(x*y + y, x, y).eval({x: 7, y: 6}) == 48 assert Poly(x*y + y, x, y).eval((6, 7)) == 49 assert Poly(x*y + y, x, y).eval([6, 7]) == 49 assert Poly(x + 1, domain='ZZ').eval(S.Half) == Rational(3, 2) assert Poly(x + 1, domain='ZZ').eval(sqrt(2)) == sqrt(2) + 1 raises(ValueError, lambda: Poly(x*y + y, x, y).eval((6, 7, 8))) raises(DomainError, lambda: Poly(x + 1, domain='ZZ').eval(S.Half, auto=False)) # issue 6344 alpha = Symbol('alpha') result = (2*alpha*z - 2*alpha + z**2 + 3)/(z**2 - 2*z + 1) f = Poly(x**2 + (alpha - 1)*x - alpha + 1, x, domain='ZZ[alpha]') assert f.eval((z + 1)/(z - 1)) == result g = Poly(x**2 + (alpha - 1)*x - alpha + 1, x, y, domain='ZZ[alpha]') assert g.eval((z + 1)/(z - 1)) == Poly(result, y, domain='ZZ(alpha,z)') def test_Poly___call__(): f = Poly(2*x*y + 3*x + y + 2*z) assert f(2) == Poly(5*y + 2*z + 6) assert f(2, 5) == Poly(2*z + 31) assert f(2, 5, 7) == 45 def test_parallel_poly_from_expr(): assert parallel_poly_from_expr( [x - 1, x**2 - 1], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [Poly(x - 1, x), x**2 - 1], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [x - 1, Poly(x**2 - 1, x)], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr([Poly( x - 1, x), Poly(x**2 - 1, x)], x)[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [x - 1, x**2 - 1], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] assert parallel_poly_from_expr([Poly( x - 1, x), x**2 - 1], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] assert parallel_poly_from_expr([x - 1, Poly( x**2 - 1, x)], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] assert parallel_poly_from_expr([Poly(x - 1, x), Poly( x**2 - 1, x)], x, y)[0] == [Poly(x - 1, x, y), Poly(x**2 - 1, x, y)] assert parallel_poly_from_expr( [x - 1, x**2 - 1])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [Poly(x - 1, x), x**2 - 1])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [x - 1, Poly(x**2 - 1, x)])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [Poly(x - 1, x), Poly(x**2 - 1, x)])[0] == [Poly(x - 1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [1, x**2 - 1])[0] == [Poly(1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [1, x**2 - 1])[0] == [Poly(1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [1, Poly(x**2 - 1, x)])[0] == [Poly(1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [1, Poly(x**2 - 1, x)])[0] == [Poly(1, x), Poly(x**2 - 1, x)] assert parallel_poly_from_expr( [x**2 - 1, 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] assert parallel_poly_from_expr( [x**2 - 1, 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] assert parallel_poly_from_expr( [Poly(x**2 - 1, x), 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] assert parallel_poly_from_expr( [Poly(x**2 - 1, x), 1])[0] == [Poly(x**2 - 1, x), Poly(1, x)] assert parallel_poly_from_expr([Poly(x, x, y), Poly(y, x, y)], x, y, order='lex')[0] == \ [Poly(x, x, y, domain='ZZ'), Poly(y, x, y, domain='ZZ')] raises(PolificationFailed, lambda: parallel_poly_from_expr([0, 1])) def test_pdiv(): f, g = x**2 - y**2, x - y q, r = x + y, 0 F, G, Q, R = [ Poly(h, x, y) for h in (f, g, q, r) ] assert F.pdiv(G) == (Q, R) assert F.prem(G) == R assert F.pquo(G) == Q assert F.pexquo(G) == Q assert pdiv(f, g) == (q, r) assert prem(f, g) == r assert pquo(f, g) == q assert pexquo(f, g) == q assert pdiv(f, g, x, y) == (q, r) assert prem(f, g, x, y) == r assert pquo(f, g, x, y) == q assert pexquo(f, g, x, y) == q assert pdiv(f, g, (x, y)) == (q, r) assert prem(f, g, (x, y)) == r assert pquo(f, g, (x, y)) == q assert pexquo(f, g, (x, y)) == q assert pdiv(F, G) == (Q, R) assert prem(F, G) == R assert pquo(F, G) == Q assert pexquo(F, G) == Q assert pdiv(f, g, polys=True) == (Q, R) assert prem(f, g, polys=True) == R assert pquo(f, g, polys=True) == Q assert pexquo(f, g, polys=True) == Q assert pdiv(F, G, polys=False) == (q, r) assert prem(F, G, polys=False) == r assert pquo(F, G, polys=False) == q assert pexquo(F, G, polys=False) == q raises(ComputationFailed, lambda: pdiv(4, 2)) raises(ComputationFailed, lambda: prem(4, 2)) raises(ComputationFailed, lambda: pquo(4, 2)) raises(ComputationFailed, lambda: pexquo(4, 2)) def test_div(): f, g = x**2 - y**2, x - y q, r = x + y, 0 F, G, Q, R = [ Poly(h, x, y) for h in (f, g, q, r) ] assert F.div(G) == (Q, R) assert F.rem(G) == R assert F.quo(G) == Q assert F.exquo(G) == Q assert div(f, g) == (q, r) assert rem(f, g) == r assert quo(f, g) == q assert exquo(f, g) == q assert div(f, g, x, y) == (q, r) assert rem(f, g, x, y) == r assert quo(f, g, x, y) == q assert exquo(f, g, x, y) == q assert div(f, g, (x, y)) == (q, r) assert rem(f, g, (x, y)) == r assert quo(f, g, (x, y)) == q assert exquo(f, g, (x, y)) == q assert div(F, G) == (Q, R) assert rem(F, G) == R assert quo(F, G) == Q assert exquo(F, G) == Q assert div(f, g, polys=True) == (Q, R) assert rem(f, g, polys=True) == R assert quo(f, g, polys=True) == Q assert exquo(f, g, polys=True) == Q assert div(F, G, polys=False) == (q, r) assert rem(F, G, polys=False) == r assert quo(F, G, polys=False) == q assert exquo(F, G, polys=False) == q raises(ComputationFailed, lambda: div(4, 2)) raises(ComputationFailed, lambda: rem(4, 2)) raises(ComputationFailed, lambda: quo(4, 2)) raises(ComputationFailed, lambda: exquo(4, 2)) f, g = x**2 + 1, 2*x - 4 qz, rz = 0, x**2 + 1 qq, rq = x/2 + 1, 5 assert div(f, g) == (qq, rq) assert div(f, g, auto=True) == (qq, rq) assert div(f, g, auto=False) == (qz, rz) assert div(f, g, domain=ZZ) == (qz, rz) assert div(f, g, domain=QQ) == (qq, rq) assert div(f, g, domain=ZZ, auto=True) == (qq, rq) assert div(f, g, domain=ZZ, auto=False) == (qz, rz) assert div(f, g, domain=QQ, auto=True) == (qq, rq) assert div(f, g, domain=QQ, auto=False) == (qq, rq) assert rem(f, g) == rq assert rem(f, g, auto=True) == rq assert rem(f, g, auto=False) == rz assert rem(f, g, domain=ZZ) == rz assert rem(f, g, domain=QQ) == rq assert rem(f, g, domain=ZZ, auto=True) == rq assert rem(f, g, domain=ZZ, auto=False) == rz assert rem(f, g, domain=QQ, auto=True) == rq assert rem(f, g, domain=QQ, auto=False) == rq assert quo(f, g) == qq assert quo(f, g, auto=True) == qq assert quo(f, g, auto=False) == qz assert quo(f, g, domain=ZZ) == qz assert quo(f, g, domain=QQ) == qq assert quo(f, g, domain=ZZ, auto=True) == qq assert quo(f, g, domain=ZZ, auto=False) == qz assert quo(f, g, domain=QQ, auto=True) == qq assert quo(f, g, domain=QQ, auto=False) == qq f, g, q = x**2, 2*x, x/2 assert exquo(f, g) == q assert exquo(f, g, auto=True) == q raises(ExactQuotientFailed, lambda: exquo(f, g, auto=False)) raises(ExactQuotientFailed, lambda: exquo(f, g, domain=ZZ)) assert exquo(f, g, domain=QQ) == q assert exquo(f, g, domain=ZZ, auto=True) == q raises(ExactQuotientFailed, lambda: exquo(f, g, domain=ZZ, auto=False)) assert exquo(f, g, domain=QQ, auto=True) == q assert exquo(f, g, domain=QQ, auto=False) == q f, g = Poly(x**2), Poly(x) q, r = f.div(g) assert q.get_domain().is_ZZ and r.get_domain().is_ZZ r = f.rem(g) assert r.get_domain().is_ZZ q = f.quo(g) assert q.get_domain().is_ZZ q = f.exquo(g) assert q.get_domain().is_ZZ f, g = Poly(x+y, x), Poly(2*x+y, x) q, r = f.div(g) assert q.get_domain().is_Frac and r.get_domain().is_Frac # https://github.com/sympy/sympy/issues/19579 p = Poly(2+3*I, x, domain=ZZ_I) q = Poly(1-I, x, domain=ZZ_I) assert p.div(q, auto=False) == \ (Poly(0, x, domain='ZZ_I'), Poly(2 + 3*I, x, domain='ZZ_I')) assert p.div(q, auto=True) == \ (Poly(-S(1)/2 + 5*I/2, x, domain='QQ_I'), Poly(0, x, domain='QQ_I')) def test_issue_7864(): q, r = div(a, .408248290463863*a) assert abs(q - 2.44948974278318) < 1e-14 assert r == 0 def test_gcdex(): f, g = 2*x, x**2 - 16 s, t, h = x/32, Rational(-1, 16), 1 F, G, S, T, H = [ Poly(u, x, domain='QQ') for u in (f, g, s, t, h) ] assert F.half_gcdex(G) == (S, H) assert F.gcdex(G) == (S, T, H) assert F.invert(G) == S assert half_gcdex(f, g) == (s, h) assert gcdex(f, g) == (s, t, h) assert invert(f, g) == s assert half_gcdex(f, g, x) == (s, h) assert gcdex(f, g, x) == (s, t, h) assert invert(f, g, x) == s assert half_gcdex(f, g, (x,)) == (s, h) assert gcdex(f, g, (x,)) == (s, t, h) assert invert(f, g, (x,)) == s assert half_gcdex(F, G) == (S, H) assert gcdex(F, G) == (S, T, H) assert invert(F, G) == S assert half_gcdex(f, g, polys=True) == (S, H) assert gcdex(f, g, polys=True) == (S, T, H) assert invert(f, g, polys=True) == S assert half_gcdex(F, G, polys=False) == (s, h) assert gcdex(F, G, polys=False) == (s, t, h) assert invert(F, G, polys=False) == s assert half_gcdex(100, 2004) == (-20, 4) assert gcdex(100, 2004) == (-20, 1, 4) assert invert(3, 7) == 5 raises(DomainError, lambda: half_gcdex(x + 1, 2*x + 1, auto=False)) raises(DomainError, lambda: gcdex(x + 1, 2*x + 1, auto=False)) raises(DomainError, lambda: invert(x + 1, 2*x + 1, auto=False)) def test_revert(): f = Poly(1 - x**2/2 + x**4/24 - x**6/720) g = Poly(61*x**6/720 + 5*x**4/24 + x**2/2 + 1) assert f.revert(8) == g def test_subresultants(): f, g, h = x**2 - 2*x + 1, x**2 - 1, 2*x - 2 F, G, H = Poly(f), Poly(g), Poly(h) assert F.subresultants(G) == [F, G, H] assert subresultants(f, g) == [f, g, h] assert subresultants(f, g, x) == [f, g, h] assert subresultants(f, g, (x,)) == [f, g, h] assert subresultants(F, G) == [F, G, H] assert subresultants(f, g, polys=True) == [F, G, H] assert subresultants(F, G, polys=False) == [f, g, h] raises(ComputationFailed, lambda: subresultants(4, 2)) def test_resultant(): f, g, h = x**2 - 2*x + 1, x**2 - 1, 0 F, G = Poly(f), Poly(g) assert F.resultant(G) == h assert resultant(f, g) == h assert resultant(f, g, x) == h assert resultant(f, g, (x,)) == h assert resultant(F, G) == h assert resultant(f, g, polys=True) == h assert resultant(F, G, polys=False) == h assert resultant(f, g, includePRS=True) == (h, [f, g, 2*x - 2]) f, g, h = x - a, x - b, a - b F, G, H = Poly(f), Poly(g), Poly(h) assert F.resultant(G) == H assert resultant(f, g) == h assert resultant(f, g, x) == h assert resultant(f, g, (x,)) == h assert resultant(F, G) == H assert resultant(f, g, polys=True) == H assert resultant(F, G, polys=False) == h raises(ComputationFailed, lambda: resultant(4, 2)) def test_discriminant(): f, g = x**3 + 3*x**2 + 9*x - 13, -11664 F = Poly(f) assert F.discriminant() == g assert discriminant(f) == g assert discriminant(f, x) == g assert discriminant(f, (x,)) == g assert discriminant(F) == g assert discriminant(f, polys=True) == g assert discriminant(F, polys=False) == g f, g = a*x**2 + b*x + c, b**2 - 4*a*c F, G = Poly(f), Poly(g) assert F.discriminant() == G assert discriminant(f) == g assert discriminant(f, x, a, b, c) == g assert discriminant(f, (x, a, b, c)) == g assert discriminant(F) == G assert discriminant(f, polys=True) == G assert discriminant(F, polys=False) == g raises(ComputationFailed, lambda: discriminant(4)) def test_dispersion(): # We test only the API here. For more mathematical # tests see the dedicated test file. fp = poly((x + 1)*(x + 2), x) assert sorted(fp.dispersionset()) == [0, 1] assert fp.dispersion() == 1 fp = poly(x**4 - 3*x**2 + 1, x) gp = fp.shift(-3) assert sorted(fp.dispersionset(gp)) == [2, 3, 4] assert fp.dispersion(gp) == 4 def test_gcd_list(): F = [x**3 - 1, x**2 - 1, x**2 - 3*x + 2] assert gcd_list(F) == x - 1 assert gcd_list(F, polys=True) == Poly(x - 1) assert gcd_list([]) == 0 assert gcd_list([1, 2]) == 1 assert gcd_list([4, 6, 8]) == 2 assert gcd_list([x*(y + 42) - x*y - x*42]) == 0 gcd = gcd_list([], x) assert gcd.is_Number and gcd is S.Zero gcd = gcd_list([], x, polys=True) assert gcd.is_Poly and gcd.is_zero a = sqrt(2) assert gcd_list([a, -a]) == gcd_list([-a, a]) == a raises(ComputationFailed, lambda: gcd_list([], polys=True)) def test_lcm_list(): F = [x**3 - 1, x**2 - 1, x**2 - 3*x + 2] assert lcm_list(F) == x**5 - x**4 - 2*x**3 - x**2 + x + 2 assert lcm_list(F, polys=True) == Poly(x**5 - x**4 - 2*x**3 - x**2 + x + 2) assert lcm_list([]) == 1 assert lcm_list([1, 2]) == 2 assert lcm_list([4, 6, 8]) == 24 assert lcm_list([x*(y + 42) - x*y - x*42]) == 0 lcm = lcm_list([], x) assert lcm.is_Number and lcm is S.One lcm = lcm_list([], x, polys=True) assert lcm.is_Poly and lcm.is_one raises(ComputationFailed, lambda: lcm_list([], polys=True)) def test_gcd(): f, g = x**3 - 1, x**2 - 1 s, t = x**2 + x + 1, x + 1 h, r = x - 1, x**4 + x**3 - x - 1 F, G, S, T, H, R = [ Poly(u) for u in (f, g, s, t, h, r) ] assert F.cofactors(G) == (H, S, T) assert F.gcd(G) == H assert F.lcm(G) == R assert cofactors(f, g) == (h, s, t) assert gcd(f, g) == h assert lcm(f, g) == r assert cofactors(f, g, x) == (h, s, t) assert gcd(f, g, x) == h assert lcm(f, g, x) == r assert cofactors(f, g, (x,)) == (h, s, t) assert gcd(f, g, (x,)) == h assert lcm(f, g, (x,)) == r assert cofactors(F, G) == (H, S, T) assert gcd(F, G) == H assert lcm(F, G) == R assert cofactors(f, g, polys=True) == (H, S, T) assert gcd(f, g, polys=True) == H assert lcm(f, g, polys=True) == R assert cofactors(F, G, polys=False) == (h, s, t) assert gcd(F, G, polys=False) == h assert lcm(F, G, polys=False) == r f, g = 1.0*x**2 - 1.0, 1.0*x - 1.0 h, s, t = g, 1.0*x + 1.0, 1.0 assert cofactors(f, g) == (h, s, t) assert gcd(f, g) == h assert lcm(f, g) == f f, g = 1.0*x**2 - 1.0, 1.0*x - 1.0 h, s, t = g, 1.0*x + 1.0, 1.0 assert cofactors(f, g) == (h, s, t) assert gcd(f, g) == h assert lcm(f, g) == f assert cofactors(8, 6) == (2, 4, 3) assert gcd(8, 6) == 2 assert lcm(8, 6) == 24 f, g = x**2 - 3*x - 4, x**3 - 4*x**2 + x - 4 l = x**4 - 3*x**3 - 3*x**2 - 3*x - 4 h, s, t = x - 4, x + 1, x**2 + 1 assert cofactors(f, g, modulus=11) == (h, s, t) assert gcd(f, g, modulus=11) == h assert lcm(f, g, modulus=11) == l f, g = x**2 + 8*x + 7, x**3 + 7*x**2 + x + 7 l = x**4 + 8*x**3 + 8*x**2 + 8*x + 7 h, s, t = x + 7, x + 1, x**2 + 1 assert cofactors(f, g, modulus=11, symmetric=False) == (h, s, t) assert gcd(f, g, modulus=11, symmetric=False) == h assert lcm(f, g, modulus=11, symmetric=False) == l a, b = sqrt(2), -sqrt(2) assert gcd(a, b) == gcd(b, a) == sqrt(2) a, b = sqrt(-2), -sqrt(-2) assert gcd(a, b) == gcd(b, a) == sqrt(2) assert gcd(Poly(x - 2, x), Poly(I*x, x)) == Poly(1, x, domain=ZZ_I) raises(TypeError, lambda: gcd(x)) raises(TypeError, lambda: lcm(x)) def test_gcd_numbers_vs_polys(): assert isinstance(gcd(3, 9), Integer) assert isinstance(gcd(3*x, 9), Integer) assert gcd(3, 9) == 3 assert gcd(3*x, 9) == 3 assert isinstance(gcd(Rational(3, 2), Rational(9, 4)), Rational) assert isinstance(gcd(Rational(3, 2)*x, Rational(9, 4)), Rational) assert gcd(Rational(3, 2), Rational(9, 4)) == Rational(3, 4) assert gcd(Rational(3, 2)*x, Rational(9, 4)) == 1 assert isinstance(gcd(3.0, 9.0), Float) assert isinstance(gcd(3.0*x, 9.0), Float) assert gcd(3.0, 9.0) == 1.0 assert gcd(3.0*x, 9.0) == 1.0 # partial fix of 20597 assert gcd(Mul(2, 3, evaluate=False), 2) == 2 def test_terms_gcd(): assert terms_gcd(1) == 1 assert terms_gcd(1, x) == 1 assert terms_gcd(x - 1) == x - 1 assert terms_gcd(-x - 1) == -x - 1 assert terms_gcd(2*x + 3) == 2*x + 3 assert terms_gcd(6*x + 4) == Mul(2, 3*x + 2, evaluate=False) assert terms_gcd(x**3*y + x*y**3) == x*y*(x**2 + y**2) assert terms_gcd(2*x**3*y + 2*x*y**3) == 2*x*y*(x**2 + y**2) assert terms_gcd(x**3*y/2 + x*y**3/2) == x*y/2*(x**2 + y**2) assert terms_gcd(x**3*y + 2*x*y**3) == x*y*(x**2 + 2*y**2) assert terms_gcd(2*x**3*y + 4*x*y**3) == 2*x*y*(x**2 + 2*y**2) assert terms_gcd(2*x**3*y/3 + 4*x*y**3/5) == x*y*Rational(2, 15)*(5*x**2 + 6*y**2) assert terms_gcd(2.0*x**3*y + 4.1*x*y**3) == x*y*(2.0*x**2 + 4.1*y**2) assert _aresame(terms_gcd(2.0*x + 3), 2.0*x + 3) assert terms_gcd((3 + 3*x)*(x + x*y), expand=False) == \ (3*x + 3)*(x*y + x) assert terms_gcd((3 + 3*x)*(x + x*sin(3 + 3*y)), expand=False, deep=True) == \ 3*x*(x + 1)*(sin(Mul(3, y + 1, evaluate=False)) + 1) assert terms_gcd(sin(x + x*y), deep=True) == \ sin(x*(y + 1)) eq = Eq(2*x, 2*y + 2*z*y) assert terms_gcd(eq) == Eq(2*x, 2*y*(z + 1)) assert terms_gcd(eq, deep=True) == Eq(2*x, 2*y*(z + 1)) raises(TypeError, lambda: terms_gcd(x < 2)) def test_trunc(): f, g = x**5 + 2*x**4 + 3*x**3 + 4*x**2 + 5*x + 6, x**5 - x**4 + x**2 - x F, G = Poly(f), Poly(g) assert F.trunc(3) == G assert trunc(f, 3) == g assert trunc(f, 3, x) == g assert trunc(f, 3, (x,)) == g assert trunc(F, 3) == G assert trunc(f, 3, polys=True) == G assert trunc(F, 3, polys=False) == g f, g = 6*x**5 + 5*x**4 + 4*x**3 + 3*x**2 + 2*x + 1, -x**4 + x**3 - x + 1 F, G = Poly(f), Poly(g) assert F.trunc(3) == G assert trunc(f, 3) == g assert trunc(f, 3, x) == g assert trunc(f, 3, (x,)) == g assert trunc(F, 3) == G assert trunc(f, 3, polys=True) == G assert trunc(F, 3, polys=False) == g f = Poly(x**2 + 2*x + 3, modulus=5) assert f.trunc(2) == Poly(x**2 + 1, modulus=5) def test_monic(): f, g = 2*x - 1, x - S.Half F, G = Poly(f, domain='QQ'), Poly(g) assert F.monic() == G assert monic(f) == g assert monic(f, x) == g assert monic(f, (x,)) == g assert monic(F) == G assert monic(f, polys=True) == G assert monic(F, polys=False) == g raises(ComputationFailed, lambda: monic(4)) assert monic(2*x**2 + 6*x + 4, auto=False) == x**2 + 3*x + 2 raises(ExactQuotientFailed, lambda: monic(2*x + 6*x + 1, auto=False)) assert monic(2.0*x**2 + 6.0*x + 4.0) == 1.0*x**2 + 3.0*x + 2.0 assert monic(2*x**2 + 3*x + 4, modulus=5) == x**2 - x + 2 def test_content(): f, F = 4*x + 2, Poly(4*x + 2) assert F.content() == 2 assert content(f) == 2 raises(ComputationFailed, lambda: content(4)) f = Poly(2*x, modulus=3) assert f.content() == 1 def test_primitive(): f, g = 4*x + 2, 2*x + 1 F, G = Poly(f), Poly(g) assert F.primitive() == (2, G) assert primitive(f) == (2, g) assert primitive(f, x) == (2, g) assert primitive(f, (x,)) == (2, g) assert primitive(F) == (2, G) assert primitive(f, polys=True) == (2, G) assert primitive(F, polys=False) == (2, g) raises(ComputationFailed, lambda: primitive(4)) f = Poly(2*x, modulus=3) g = Poly(2.0*x, domain=RR) assert f.primitive() == (1, f) assert g.primitive() == (1.0, g) assert primitive(S('-3*x/4 + y + 11/8')) == \ S('(1/8, -6*x + 8*y + 11)') def test_compose(): f = x**12 + 20*x**10 + 150*x**8 + 500*x**6 + 625*x**4 - 2*x**3 - 10*x + 9 g = x**4 - 2*x + 9 h = x**3 + 5*x F, G, H = map(Poly, (f, g, h)) assert G.compose(H) == F assert compose(g, h) == f assert compose(g, h, x) == f assert compose(g, h, (x,)) == f assert compose(G, H) == F assert compose(g, h, polys=True) == F assert compose(G, H, polys=False) == f assert F.decompose() == [G, H] assert decompose(f) == [g, h] assert decompose(f, x) == [g, h] assert decompose(f, (x,)) == [g, h] assert decompose(F) == [G, H] assert decompose(f, polys=True) == [G, H] assert decompose(F, polys=False) == [g, h] raises(ComputationFailed, lambda: compose(4, 2)) raises(ComputationFailed, lambda: decompose(4)) assert compose(x**2 - y**2, x - y, x, y) == x**2 - 2*x*y assert compose(x**2 - y**2, x - y, y, x) == -y**2 + 2*x*y def test_shift(): assert Poly(x**2 - 2*x + 1, x).shift(2) == Poly(x**2 + 2*x + 1, x) def test_transform(): # Also test that 3-way unification is done correctly assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1), Poly(x - 1)) == \ Poly(4, x) == \ cancel((x - 1)**2*(x**2 - 2*x + 1).subs(x, (x + 1)/(x - 1))) assert Poly(x**2 - x/2 + 1, x).transform(Poly(x + 1), Poly(x - 1)) == \ Poly(3*x**2/2 + Rational(5, 2), x) == \ cancel((x - 1)**2*(x**2 - x/2 + 1).subs(x, (x + 1)/(x - 1))) assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + S.Half), Poly(x - 1)) == \ Poly(Rational(9, 4), x) == \ cancel((x - 1)**2*(x**2 - 2*x + 1).subs(x, (x + S.Half)/(x - 1))) assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1), Poly(x - S.Half)) == \ Poly(Rational(9, 4), x) == \ cancel((x - S.Half)**2*(x**2 - 2*x + 1).subs(x, (x + 1)/(x - S.Half))) # Unify ZZ, QQ, and RR assert Poly(x**2 - 2*x + 1, x).transform(Poly(x + 1.0), Poly(x - S.Half)) == \ Poly(Rational(9, 4), x, domain='RR') == \ cancel((x - S.Half)**2*(x**2 - 2*x + 1).subs(x, (x + 1.0)/(x - S.Half))) raises(ValueError, lambda: Poly(x*y).transform(Poly(x + 1), Poly(x - 1))) raises(ValueError, lambda: Poly(x).transform(Poly(y + 1), Poly(x - 1))) raises(ValueError, lambda: Poly(x).transform(Poly(x + 1), Poly(y - 1))) raises(ValueError, lambda: Poly(x).transform(Poly(x*y + 1), Poly(x - 1))) raises(ValueError, lambda: Poly(x).transform(Poly(x + 1), Poly(x*y - 1))) def test_sturm(): f, F = x, Poly(x, domain='QQ') g, G = 1, Poly(1, x, domain='QQ') assert F.sturm() == [F, G] assert sturm(f) == [f, g] assert sturm(f, x) == [f, g] assert sturm(f, (x,)) == [f, g] assert sturm(F) == [F, G] assert sturm(f, polys=True) == [F, G] assert sturm(F, polys=False) == [f, g] raises(ComputationFailed, lambda: sturm(4)) raises(DomainError, lambda: sturm(f, auto=False)) f = Poly(S(1024)/(15625*pi**8)*x**5 - S(4096)/(625*pi**8)*x**4 + S(32)/(15625*pi**4)*x**3 - S(128)/(625*pi**4)*x**2 + Rational(1, 62500)*x - Rational(1, 625), x, domain='ZZ(pi)') assert sturm(f) == \ [Poly(x**3 - 100*x**2 + pi**4/64*x - 25*pi**4/16, x, domain='ZZ(pi)'), Poly(3*x**2 - 200*x + pi**4/64, x, domain='ZZ(pi)'), Poly((Rational(20000, 9) - pi**4/96)*x + 25*pi**4/18, x, domain='ZZ(pi)'), Poly((-3686400000000*pi**4 - 11520000*pi**8 - 9*pi**12)/(26214400000000 - 245760000*pi**4 + 576*pi**8), x, domain='ZZ(pi)')] def test_gff(): f = x**5 + 2*x**4 - x**3 - 2*x**2 assert Poly(f).gff_list() == [(Poly(x), 1), (Poly(x + 2), 4)] assert gff_list(f) == [(x, 1), (x + 2, 4)] raises(NotImplementedError, lambda: gff(f)) f = x*(x - 1)**3*(x - 2)**2*(x - 4)**2*(x - 5) assert Poly(f).gff_list() == [( Poly(x**2 - 5*x + 4), 1), (Poly(x**2 - 5*x + 4), 2), (Poly(x), 3)] assert gff_list(f) == [(x**2 - 5*x + 4, 1), (x**2 - 5*x + 4, 2), (x, 3)] raises(NotImplementedError, lambda: gff(f)) def test_norm(): a, b = sqrt(2), sqrt(3) f = Poly(a*x + b*y, x, y, extension=(a, b)) assert f.norm() == Poly(4*x**4 - 12*x**2*y**2 + 9*y**4, x, y, domain='QQ') def test_sqf_norm(): assert sqf_norm(x**2 - 2, extension=sqrt(3)) == \ (1, x**2 - 2*sqrt(3)*x + 1, x**4 - 10*x**2 + 1) assert sqf_norm(x**2 - 3, extension=sqrt(2)) == \ (1, x**2 - 2*sqrt(2)*x - 1, x**4 - 10*x**2 + 1) assert Poly(x**2 - 2, extension=sqrt(3)).sqf_norm() == \ (1, Poly(x**2 - 2*sqrt(3)*x + 1, x, extension=sqrt(3)), Poly(x**4 - 10*x**2 + 1, x, domain='QQ')) assert Poly(x**2 - 3, extension=sqrt(2)).sqf_norm() == \ (1, Poly(x**2 - 2*sqrt(2)*x - 1, x, extension=sqrt(2)), Poly(x**4 - 10*x**2 + 1, x, domain='QQ')) def test_sqf(): f = x**5 - x**3 - x**2 + 1 g = x**3 + 2*x**2 + 2*x + 1 h = x - 1 p = x**4 + x**3 - x - 1 F, G, H, P = map(Poly, (f, g, h, p)) assert F.sqf_part() == P assert sqf_part(f) == p assert sqf_part(f, x) == p assert sqf_part(f, (x,)) == p assert sqf_part(F) == P assert sqf_part(f, polys=True) == P assert sqf_part(F, polys=False) == p assert F.sqf_list() == (1, [(G, 1), (H, 2)]) assert sqf_list(f) == (1, [(g, 1), (h, 2)]) assert sqf_list(f, x) == (1, [(g, 1), (h, 2)]) assert sqf_list(f, (x,)) == (1, [(g, 1), (h, 2)]) assert sqf_list(F) == (1, [(G, 1), (H, 2)]) assert sqf_list(f, polys=True) == (1, [(G, 1), (H, 2)]) assert sqf_list(F, polys=False) == (1, [(g, 1), (h, 2)]) assert F.sqf_list_include() == [(G, 1), (H, 2)] raises(ComputationFailed, lambda: sqf_part(4)) assert sqf(1) == 1 assert sqf_list(1) == (1, []) assert sqf((2*x**2 + 2)**7) == 128*(x**2 + 1)**7 assert sqf(f) == g*h**2 assert sqf(f, x) == g*h**2 assert sqf(f, (x,)) == g*h**2 d = x**2 + y**2 assert sqf(f/d) == (g*h**2)/d assert sqf(f/d, x) == (g*h**2)/d assert sqf(f/d, (x,)) == (g*h**2)/d assert sqf(x - 1) == x - 1 assert sqf(-x - 1) == -x - 1 assert sqf(x - 1) == x - 1 assert sqf(6*x - 10) == Mul(2, 3*x - 5, evaluate=False) assert sqf((6*x - 10)/(3*x - 6)) == Rational(2, 3)*((3*x - 5)/(x - 2)) assert sqf(Poly(x**2 - 2*x + 1)) == (x - 1)**2 f = 3 + x - x*(1 + x) + x**2 assert sqf(f) == 3 f = (x**2 + 2*x + 1)**20000000000 assert sqf(f) == (x + 1)**40000000000 assert sqf_list(f) == (1, [(x + 1, 40000000000)]) def test_factor(): f = x**5 - x**3 - x**2 + 1 u = x + 1 v = x - 1 w = x**2 + x + 1 F, U, V, W = map(Poly, (f, u, v, w)) assert F.factor_list() == (1, [(U, 1), (V, 2), (W, 1)]) assert factor_list(f) == (1, [(u, 1), (v, 2), (w, 1)]) assert factor_list(f, x) == (1, [(u, 1), (v, 2), (w, 1)]) assert factor_list(f, (x,)) == (1, [(u, 1), (v, 2), (w, 1)]) assert factor_list(F) == (1, [(U, 1), (V, 2), (W, 1)]) assert factor_list(f, polys=True) == (1, [(U, 1), (V, 2), (W, 1)]) assert factor_list(F, polys=False) == (1, [(u, 1), (v, 2), (w, 1)]) assert F.factor_list_include() == [(U, 1), (V, 2), (W, 1)] assert factor_list(1) == (1, []) assert factor_list(6) == (6, []) assert factor_list(sqrt(3), x) == (sqrt(3), []) assert factor_list((-1)**x, x) == (1, [(-1, x)]) assert factor_list((2*x)**y, x) == (1, [(2, y), (x, y)]) assert factor_list(sqrt(x*y), x) == (1, [(x*y, S.Half)]) assert factor(6) == 6 and factor(6).is_Integer assert factor_list(3*x) == (3, [(x, 1)]) assert factor_list(3*x**2) == (3, [(x, 2)]) assert factor(3*x) == 3*x assert factor(3*x**2) == 3*x**2 assert factor((2*x**2 + 2)**7) == 128*(x**2 + 1)**7 assert factor(f) == u*v**2*w assert factor(f, x) == u*v**2*w assert factor(f, (x,)) == u*v**2*w g, p, q, r = x**2 - y**2, x - y, x + y, x**2 + 1 assert factor(f/g) == (u*v**2*w)/(p*q) assert factor(f/g, x) == (u*v**2*w)/(p*q) assert factor(f/g, (x,)) == (u*v**2*w)/(p*q) p = Symbol('p', positive=True) i = Symbol('i', integer=True) r = Symbol('r', real=True) assert factor(sqrt(x*y)).is_Pow is True assert factor(sqrt(3*x**2 - 3)) == sqrt(3)*sqrt((x - 1)*(x + 1)) assert factor(sqrt(3*x**2 + 3)) == sqrt(3)*sqrt(x**2 + 1) assert factor((y*x**2 - y)**i) == y**i*(x - 1)**i*(x + 1)**i assert factor((y*x**2 + y)**i) == y**i*(x**2 + 1)**i assert factor((y*x**2 - y)**t) == (y*(x - 1)*(x + 1))**t assert factor((y*x**2 + y)**t) == (y*(x**2 + 1))**t f = sqrt(expand((r**2 + 1)*(p + 1)*(p - 1)*(p - 2)**3)) g = sqrt((p - 2)**3*(p - 1))*sqrt(p + 1)*sqrt(r**2 + 1) assert factor(f) == g assert factor(g) == g g = (x - 1)**5*(r**2 + 1) f = sqrt(expand(g)) assert factor(f) == sqrt(g) f = Poly(sin(1)*x + 1, x, domain=EX) assert f.factor_list() == (1, [(f, 1)]) f = x**4 + 1 assert factor(f) == f assert factor(f, extension=I) == (x**2 - I)*(x**2 + I) assert factor(f, gaussian=True) == (x**2 - I)*(x**2 + I) assert factor( f, extension=sqrt(2)) == (x**2 + sqrt(2)*x + 1)*(x**2 - sqrt(2)*x + 1) assert factor(x**2 + 4*I*x - 4) == (x + 2*I)**2 f = x**2 + 2*I*x - 4 assert factor(f) == f f = 8192*x**2 + x*(22656 + 175232*I) - 921416 + 242313*I f_zzi = I*(x*(64 - 64*I) + 773 + 596*I)**2 f_qqi = 8192*(x + S(177)/128 + 1369*I/128)**2 assert factor(f) == f_zzi assert factor(f, domain=ZZ_I) == f_zzi assert factor(f, domain=QQ_I) == f_qqi f = x**2 + 2*sqrt(2)*x + 2 assert factor(f, extension=sqrt(2)) == (x + sqrt(2))**2 assert factor(f**3, extension=sqrt(2)) == (x + sqrt(2))**6 assert factor(x**2 - 2*y**2, extension=sqrt(2)) == \ (x + sqrt(2)*y)*(x - sqrt(2)*y) assert factor(2*x**2 - 4*y**2, extension=sqrt(2)) == \ 2*((x + sqrt(2)*y)*(x - sqrt(2)*y)) assert factor(x - 1) == x - 1 assert factor(-x - 1) == -x - 1 assert factor(x - 1) == x - 1 assert factor(6*x - 10) == Mul(2, 3*x - 5, evaluate=False) assert factor(x**11 + x + 1, modulus=65537, symmetric=True) == \ (x**2 + x + 1)*(x**9 - x**8 + x**6 - x**5 + x**3 - x** 2 + 1) assert factor(x**11 + x + 1, modulus=65537, symmetric=False) == \ (x**2 + x + 1)*(x**9 + 65536*x**8 + x**6 + 65536*x**5 + x**3 + 65536*x** 2 + 1) f = x/pi + x*sin(x)/pi g = y/(pi**2 + 2*pi + 1) + y*sin(x)/(pi**2 + 2*pi + 1) assert factor(f) == x*(sin(x) + 1)/pi assert factor(g) == y*(sin(x) + 1)/(pi + 1)**2 assert factor(Eq( x**2 + 2*x + 1, x**3 + 1)) == Eq((x + 1)**2, (x + 1)*(x**2 - x + 1)) f = (x**2 - 1)/(x**2 + 4*x + 4) assert factor(f) == (x + 1)*(x - 1)/(x + 2)**2 assert factor(f, x) == (x + 1)*(x - 1)/(x + 2)**2 f = 3 + x - x*(1 + x) + x**2 assert factor(f) == 3 assert factor(f, x) == 3 assert factor(1/(x**2 + 2*x + 1/x) - 1) == -((1 - x + 2*x**2 + x**3)/(1 + 2*x**2 + x**3)) assert factor(f, expand=False) == f raises(PolynomialError, lambda: factor(f, x, expand=False)) raises(FlagError, lambda: factor(x**2 - 1, polys=True)) assert factor([x, Eq(x**2 - y**2, Tuple(x**2 - z**2, 1/x + 1/y))]) == \ [x, Eq((x - y)*(x + y), Tuple((x - z)*(x + z), (x + y)/x/y))] assert not isinstance( Poly(x**3 + x + 1).factor_list()[1][0][0], PurePoly) is True assert isinstance( PurePoly(x**3 + x + 1).factor_list()[1][0][0], PurePoly) is True assert factor(sqrt(-x)) == sqrt(-x) # issue 5917 e = (-2*x*(-x + 1)*(x - 1)*(-x*(-x + 1)*(x - 1) - x*(x - 1)**2)*(x**2*(x - 1) - x*(x - 1) - x) - (-2*x**2*(x - 1)**2 - x*(-x + 1)*(-x*(-x + 1) + x*(x - 1)))*(x**2*(x - 1)**4 - x*(-x*(-x + 1)*(x - 1) - x*(x - 1)**2))) assert factor(e) == 0 # deep option assert factor(sin(x**2 + x) + x, deep=True) == sin(x*(x + 1)) + x assert factor(sin(x**2 + x)*x, deep=True) == sin(x*(x + 1))*x assert factor(sqrt(x**2)) == sqrt(x**2) # issue 13149 assert factor(expand((0.5*x+1)*(0.5*y+1))) == Mul(1.0, 0.5*x + 1.0, 0.5*y + 1.0, evaluate = False) assert factor(expand((0.5*x+0.5)**2)) == 0.25*(1.0*x + 1.0)**2 eq = x**2*y**2 + 11*x**2*y + 30*x**2 + 7*x*y**2 + 77*x*y + 210*x + 12*y**2 + 132*y + 360 assert factor(eq, x) == (x + 3)*(x + 4)*(y**2 + 11*y + 30) assert factor(eq, x, deep=True) == (x + 3)*(x + 4)*(y**2 + 11*y + 30) assert factor(eq, y, deep=True) == (y + 5)*(y + 6)*(x**2 + 7*x + 12) # fraction option f = 5*x + 3*exp(2 - 7*x) assert factor(f, deep=True) == factor(f, deep=True, fraction=True) assert factor(f, deep=True, fraction=False) == 5*x + 3*exp(2)*exp(-7*x) def test_factor_large(): f = (x**2 + 4*x + 4)**10000000*(x**2 + 1)*(x**2 + 2*x + 1)**1234567 g = ((x**2 + 2*x + 1)**3000*y**2 + (x**2 + 2*x + 1)**3000*2*y + ( x**2 + 2*x + 1)**3000) assert factor(f) == (x + 2)**20000000*(x**2 + 1)*(x + 1)**2469134 assert factor(g) == (x + 1)**6000*(y + 1)**2 assert factor_list( f) == (1, [(x + 1, 2469134), (x + 2, 20000000), (x**2 + 1, 1)]) assert factor_list(g) == (1, [(y + 1, 2), (x + 1, 6000)]) f = (x**2 - y**2)**200000*(x**7 + 1) g = (x**2 + y**2)**200000*(x**7 + 1) assert factor(f) == \ (x + 1)*(x - y)**200000*(x + y)**200000*(x**6 - x**5 + x**4 - x**3 + x**2 - x + 1) assert factor(g, gaussian=True) == \ (x + 1)*(x - I*y)**200000*(x + I*y)**200000*(x**6 - x**5 + x**4 - x**3 + x**2 - x + 1) assert factor_list(f) == \ (1, [(x + 1, 1), (x - y, 200000), (x + y, 200000), (x**6 - x**5 + x**4 - x**3 + x**2 - x + 1, 1)]) assert factor_list(g, gaussian=True) == \ (1, [(x + 1, 1), (x - I*y, 200000), (x + I*y, 200000), ( x**6 - x**5 + x**4 - x**3 + x**2 - x + 1, 1)]) def test_factor_noeval(): assert factor(6*x - 10) == Mul(2, 3*x - 5, evaluate=False) assert factor((6*x - 10)/(3*x - 6)) == Mul(Rational(2, 3), 3*x - 5, 1/(x - 2)) def test_intervals(): assert intervals(0) == [] assert intervals(1) == [] assert intervals(x, sqf=True) == [(0, 0)] assert intervals(x) == [((0, 0), 1)] assert intervals(x**128) == [((0, 0), 128)] assert intervals([x**2, x**4]) == [((0, 0), {0: 2, 1: 4})] f = Poly((x*Rational(2, 5) - Rational(17, 3))*(4*x + Rational(1, 257))) assert f.intervals(sqf=True) == [(-1, 0), (14, 15)] assert f.intervals() == [((-1, 0), 1), ((14, 15), 1)] assert f.intervals(fast=True, sqf=True) == [(-1, 0), (14, 15)] assert f.intervals(fast=True) == [((-1, 0), 1), ((14, 15), 1)] assert f.intervals(eps=Rational(1, 10)) == f.intervals(eps=0.1) == \ [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] assert f.intervals(eps=Rational(1, 100)) == f.intervals(eps=0.01) == \ [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] assert f.intervals(eps=Rational(1, 1000)) == f.intervals(eps=0.001) == \ [((Rational(-1, 1002), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] assert f.intervals(eps=Rational(1, 10000)) == f.intervals(eps=0.0001) == \ [((Rational(-1, 1028), Rational(-1, 1028)), 1), ((Rational(85, 6), Rational(85, 6)), 1)] f = (x*Rational(2, 5) - Rational(17, 3))*(4*x + Rational(1, 257)) assert intervals(f, sqf=True) == [(-1, 0), (14, 15)] assert intervals(f) == [((-1, 0), 1), ((14, 15), 1)] assert intervals(f, eps=Rational(1, 10)) == intervals(f, eps=0.1) == \ [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] assert intervals(f, eps=Rational(1, 100)) == intervals(f, eps=0.01) == \ [((Rational(-1, 258), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] assert intervals(f, eps=Rational(1, 1000)) == intervals(f, eps=0.001) == \ [((Rational(-1, 1002), 0), 1), ((Rational(85, 6), Rational(85, 6)), 1)] assert intervals(f, eps=Rational(1, 10000)) == intervals(f, eps=0.0001) == \ [((Rational(-1, 1028), Rational(-1, 1028)), 1), ((Rational(85, 6), Rational(85, 6)), 1)] f = Poly((x**2 - 2)*(x**2 - 3)**7*(x + 1)*(7*x + 3)**3) assert f.intervals() == \ [((-2, Rational(-3, 2)), 7), ((Rational(-3, 2), -1), 1), ((-1, -1), 1), ((-1, 0), 3), ((1, Rational(3, 2)), 1), ((Rational(3, 2), 2), 7)] assert intervals([x**5 - 200, x**5 - 201]) == \ [((Rational(75, 26), Rational(101, 35)), {0: 1}), ((Rational(309, 107), Rational(26, 9)), {1: 1})] assert intervals([x**5 - 200, x**5 - 201], fast=True) == \ [((Rational(75, 26), Rational(101, 35)), {0: 1}), ((Rational(309, 107), Rational(26, 9)), {1: 1})] assert intervals([x**2 - 200, x**2 - 201]) == \ [((Rational(-71, 5), Rational(-85, 6)), {1: 1}), ((Rational(-85, 6), -14), {0: 1}), ((14, Rational(85, 6)), {0: 1}), ((Rational(85, 6), Rational(71, 5)), {1: 1})] assert intervals([x + 1, x + 2, x - 1, x + 1, 1, x - 1, x - 1, (x - 2)**2]) == \ [((-2, -2), {1: 1}), ((-1, -1), {0: 1, 3: 1}), ((1, 1), {2: 1, 5: 1, 6: 1}), ((2, 2), {7: 2})] f, g, h = x**2 - 2, x**4 - 4*x**2 + 4, x - 1 assert intervals(f, inf=Rational(7, 4), sqf=True) == [] assert intervals(f, inf=Rational(7, 5), sqf=True) == [(Rational(7, 5), Rational(3, 2))] assert intervals(f, sup=Rational(7, 4), sqf=True) == [(-2, -1), (1, Rational(3, 2))] assert intervals(f, sup=Rational(7, 5), sqf=True) == [(-2, -1)] assert intervals(g, inf=Rational(7, 4)) == [] assert intervals(g, inf=Rational(7, 5)) == [((Rational(7, 5), Rational(3, 2)), 2)] assert intervals(g, sup=Rational(7, 4)) == [((-2, -1), 2), ((1, Rational(3, 2)), 2)] assert intervals(g, sup=Rational(7, 5)) == [((-2, -1), 2)] assert intervals([g, h], inf=Rational(7, 4)) == [] assert intervals([g, h], inf=Rational(7, 5)) == [((Rational(7, 5), Rational(3, 2)), {0: 2})] assert intervals([g, h], sup=S( 7)/4) == [((-2, -1), {0: 2}), ((1, 1), {1: 1}), ((1, Rational(3, 2)), {0: 2})] assert intervals( [g, h], sup=Rational(7, 5)) == [((-2, -1), {0: 2}), ((1, 1), {1: 1})] assert intervals([x + 2, x**2 - 2]) == \ [((-2, -2), {0: 1}), ((-2, -1), {1: 1}), ((1, 2), {1: 1})] assert intervals([x + 2, x**2 - 2], strict=True) == \ [((-2, -2), {0: 1}), ((Rational(-3, 2), -1), {1: 1}), ((1, 2), {1: 1})] f = 7*z**4 - 19*z**3 + 20*z**2 + 17*z + 20 assert intervals(f) == [] real_part, complex_part = intervals(f, all=True, sqf=True) assert real_part == [] assert all(re(a) < re(r) < re(b) and im( a) < im(r) < im(b) for (a, b), r in zip(complex_part, nroots(f))) assert complex_part == [(Rational(-40, 7) - I*Rational(40, 7), 0), (Rational(-40, 7), I*Rational(40, 7)), (I*Rational(-40, 7), Rational(40, 7)), (0, Rational(40, 7) + I*Rational(40, 7))] real_part, complex_part = intervals(f, all=True, sqf=True, eps=Rational(1, 10)) assert real_part == [] assert all(re(a) < re(r) < re(b) and im( a) < im(r) < im(b) for (a, b), r in zip(complex_part, nroots(f))) raises(ValueError, lambda: intervals(x**2 - 2, eps=10**-100000)) raises(ValueError, lambda: Poly(x**2 - 2).intervals(eps=10**-100000)) raises( ValueError, lambda: intervals([x**2 - 2, x**2 - 3], eps=10**-100000)) def test_refine_root(): f = Poly(x**2 - 2) assert f.refine_root(1, 2, steps=0) == (1, 2) assert f.refine_root(-2, -1, steps=0) == (-2, -1) assert f.refine_root(1, 2, steps=None) == (1, Rational(3, 2)) assert f.refine_root(-2, -1, steps=None) == (Rational(-3, 2), -1) assert f.refine_root(1, 2, steps=1) == (1, Rational(3, 2)) assert f.refine_root(-2, -1, steps=1) == (Rational(-3, 2), -1) assert f.refine_root(1, 2, steps=1, fast=True) == (1, Rational(3, 2)) assert f.refine_root(-2, -1, steps=1, fast=True) == (Rational(-3, 2), -1) assert f.refine_root(1, 2, eps=Rational(1, 100)) == (Rational(24, 17), Rational(17, 12)) assert f.refine_root(1, 2, eps=1e-2) == (Rational(24, 17), Rational(17, 12)) raises(PolynomialError, lambda: (f**2).refine_root(1, 2, check_sqf=True)) raises(RefinementFailed, lambda: (f**2).refine_root(1, 2)) raises(RefinementFailed, lambda: (f**2).refine_root(2, 3)) f = x**2 - 2 assert refine_root(f, 1, 2, steps=1) == (1, Rational(3, 2)) assert refine_root(f, -2, -1, steps=1) == (Rational(-3, 2), -1) assert refine_root(f, 1, 2, steps=1, fast=True) == (1, Rational(3, 2)) assert refine_root(f, -2, -1, steps=1, fast=True) == (Rational(-3, 2), -1) assert refine_root(f, 1, 2, eps=Rational(1, 100)) == (Rational(24, 17), Rational(17, 12)) assert refine_root(f, 1, 2, eps=1e-2) == (Rational(24, 17), Rational(17, 12)) raises(PolynomialError, lambda: refine_root(1, 7, 8, eps=Rational(1, 100))) raises(ValueError, lambda: Poly(f).refine_root(1, 2, eps=10**-100000)) raises(ValueError, lambda: refine_root(f, 1, 2, eps=10**-100000)) def test_count_roots(): assert count_roots(x**2 - 2) == 2 assert count_roots(x**2 - 2, inf=-oo) == 2 assert count_roots(x**2 - 2, sup=+oo) == 2 assert count_roots(x**2 - 2, inf=-oo, sup=+oo) == 2 assert count_roots(x**2 - 2, inf=-2) == 2 assert count_roots(x**2 - 2, inf=-1) == 1 assert count_roots(x**2 - 2, sup=1) == 1 assert count_roots(x**2 - 2, sup=2) == 2 assert count_roots(x**2 - 2, inf=-1, sup=1) == 0 assert count_roots(x**2 - 2, inf=-2, sup=2) == 2 assert count_roots(x**2 - 2, inf=-1, sup=1) == 0 assert count_roots(x**2 - 2, inf=-2, sup=2) == 2 assert count_roots(x**2 + 2) == 0 assert count_roots(x**2 + 2, inf=-2*I) == 2 assert count_roots(x**2 + 2, sup=+2*I) == 2 assert count_roots(x**2 + 2, inf=-2*I, sup=+2*I) == 2 assert count_roots(x**2 + 2, inf=0) == 0 assert count_roots(x**2 + 2, sup=0) == 0 assert count_roots(x**2 + 2, inf=-I) == 1 assert count_roots(x**2 + 2, sup=+I) == 1 assert count_roots(x**2 + 2, inf=+I/2, sup=+I) == 0 assert count_roots(x**2 + 2, inf=-I, sup=-I/2) == 0 raises(PolynomialError, lambda: count_roots(1)) def test_Poly_root(): f = Poly(2*x**3 - 7*x**2 + 4*x + 4) assert f.root(0) == Rational(-1, 2) assert f.root(1) == 2 assert f.root(2) == 2 raises(IndexError, lambda: f.root(3)) assert Poly(x**5 + x + 1).root(0) == rootof(x**3 - x**2 + 1, 0) def test_real_roots(): assert real_roots(x) == [0] assert real_roots(x, multiple=False) == [(0, 1)] assert real_roots(x**3) == [0, 0, 0] assert real_roots(x**3, multiple=False) == [(0, 3)] assert real_roots(x*(x**3 + x + 3)) == [rootof(x**3 + x + 3, 0), 0] assert real_roots(x*(x**3 + x + 3), multiple=False) == [(rootof( x**3 + x + 3, 0), 1), (0, 1)] assert real_roots( x**3*(x**3 + x + 3)) == [rootof(x**3 + x + 3, 0), 0, 0, 0] assert real_roots(x**3*(x**3 + x + 3), multiple=False) == [(rootof( x**3 + x + 3, 0), 1), (0, 3)] f = 2*x**3 - 7*x**2 + 4*x + 4 g = x**3 + x + 1 assert Poly(f).real_roots() == [Rational(-1, 2), 2, 2] assert Poly(g).real_roots() == [rootof(g, 0)] def test_all_roots(): f = 2*x**3 - 7*x**2 + 4*x + 4 g = x**3 + x + 1 assert Poly(f).all_roots() == [Rational(-1, 2), 2, 2] assert Poly(g).all_roots() == [rootof(g, 0), rootof(g, 1), rootof(g, 2)] def test_nroots(): assert Poly(0, x).nroots() == [] assert Poly(1, x).nroots() == [] assert Poly(x**2 - 1, x).nroots() == [-1.0, 1.0] assert Poly(x**2 + 1, x).nroots() == [-1.0*I, 1.0*I] roots = Poly(x**2 - 1, x).nroots() assert roots == [-1.0, 1.0] roots = Poly(x**2 + 1, x).nroots() assert roots == [-1.0*I, 1.0*I] roots = Poly(x**2/3 - Rational(1, 3), x).nroots() assert roots == [-1.0, 1.0] roots = Poly(x**2/3 + Rational(1, 3), x).nroots() assert roots == [-1.0*I, 1.0*I] assert Poly(x**2 + 2*I, x).nroots() == [-1.0 + 1.0*I, 1.0 - 1.0*I] assert Poly( x**2 + 2*I, x, extension=I).nroots() == [-1.0 + 1.0*I, 1.0 - 1.0*I] assert Poly(0.2*x + 0.1).nroots() == [-0.5] roots = nroots(x**5 + x + 1, n=5) eps = Float("1e-5") assert re(roots[0]).epsilon_eq(-0.75487, eps) is S.true assert im(roots[0]) == 0.0 assert re(roots[1]) == -0.5 assert im(roots[1]).epsilon_eq(-0.86602, eps) is S.true assert re(roots[2]) == -0.5 assert im(roots[2]).epsilon_eq(+0.86602, eps) is S.true assert re(roots[3]).epsilon_eq(+0.87743, eps) is S.true assert im(roots[3]).epsilon_eq(-0.74486, eps) is S.true assert re(roots[4]).epsilon_eq(+0.87743, eps) is S.true assert im(roots[4]).epsilon_eq(+0.74486, eps) is S.true eps = Float("1e-6") assert re(roots[0]).epsilon_eq(-0.75487, eps) is S.false assert im(roots[0]) == 0.0 assert re(roots[1]) == -0.5 assert im(roots[1]).epsilon_eq(-0.86602, eps) is S.false assert re(roots[2]) == -0.5 assert im(roots[2]).epsilon_eq(+0.86602, eps) is S.false assert re(roots[3]).epsilon_eq(+0.87743, eps) is S.false assert im(roots[3]).epsilon_eq(-0.74486, eps) is S.false assert re(roots[4]).epsilon_eq(+0.87743, eps) is S.false assert im(roots[4]).epsilon_eq(+0.74486, eps) is S.false raises(DomainError, lambda: Poly(x + y, x).nroots()) raises(MultivariatePolynomialError, lambda: Poly(x + y).nroots()) assert nroots(x**2 - 1) == [-1.0, 1.0] roots = nroots(x**2 - 1) assert roots == [-1.0, 1.0] assert nroots(x + I) == [-1.0*I] assert nroots(x + 2*I) == [-2.0*I] raises(PolynomialError, lambda: nroots(0)) # issue 8296 f = Poly(x**4 - 1) assert f.nroots(2) == [w.n(2) for w in f.all_roots()] assert str(Poly(x**16 + 32*x**14 + 508*x**12 + 5440*x**10 + 39510*x**8 + 204320*x**6 + 755548*x**4 + 1434496*x**2 + 877969).nroots(2)) == ('[-1.7 - 1.9*I, -1.7 + 1.9*I, -1.7 ' '- 2.5*I, -1.7 + 2.5*I, -1.0*I, 1.0*I, -1.7*I, 1.7*I, -2.8*I, ' '2.8*I, -3.4*I, 3.4*I, 1.7 - 1.9*I, 1.7 + 1.9*I, 1.7 - 2.5*I, ' '1.7 + 2.5*I]') def test_ground_roots(): f = x**6 - 4*x**4 + 4*x**3 - x**2 assert Poly(f).ground_roots() == {S.One: 2, S.Zero: 2} assert ground_roots(f) == {S.One: 2, S.Zero: 2} def test_nth_power_roots_poly(): f = x**4 - x**2 + 1 f_2 = (x**2 - x + 1)**2 f_3 = (x**2 + 1)**2 f_4 = (x**2 + x + 1)**2 f_12 = (x - 1)**4 assert nth_power_roots_poly(f, 1) == f raises(ValueError, lambda: nth_power_roots_poly(f, 0)) raises(ValueError, lambda: nth_power_roots_poly(f, x)) assert factor(nth_power_roots_poly(f, 2)) == f_2 assert factor(nth_power_roots_poly(f, 3)) == f_3 assert factor(nth_power_roots_poly(f, 4)) == f_4 assert factor(nth_power_roots_poly(f, 12)) == f_12 raises(MultivariatePolynomialError, lambda: nth_power_roots_poly( x + y, 2, x, y)) def test_torational_factor_list(): p = expand(((x**2-1)*(x-2)).subs({x:x*(1 + sqrt(2))})) assert _torational_factor_list(p, x) == (-2, [ (-x*(1 + sqrt(2))/2 + 1, 1), (-x*(1 + sqrt(2)) - 1, 1), (-x*(1 + sqrt(2)) + 1, 1)]) p = expand(((x**2-1)*(x-2)).subs({x:x*(1 + 2**Rational(1, 4))})) assert _torational_factor_list(p, x) is None def test_cancel(): assert cancel(0) == 0 assert cancel(7) == 7 assert cancel(x) == x assert cancel(oo) is oo assert cancel((2, 3)) == (1, 2, 3) assert cancel((1, 0), x) == (1, 1, 0) assert cancel((0, 1), x) == (1, 0, 1) f, g, p, q = 4*x**2 - 4, 2*x - 2, 2*x + 2, 1 F, G, P, Q = [ Poly(u, x) for u in (f, g, p, q) ] assert F.cancel(G) == (1, P, Q) assert cancel((f, g)) == (1, p, q) assert cancel((f, g), x) == (1, p, q) assert cancel((f, g), (x,)) == (1, p, q) assert cancel((F, G)) == (1, P, Q) assert cancel((f, g), polys=True) == (1, P, Q) assert cancel((F, G), polys=False) == (1, p, q) f = (x**2 - 2)/(x + sqrt(2)) assert cancel(f) == f assert cancel(f, greedy=False) == x - sqrt(2) f = (x**2 - 2)/(x - sqrt(2)) assert cancel(f) == f assert cancel(f, greedy=False) == x + sqrt(2) assert cancel((x**2/4 - 1, x/2 - 1)) == (1, x + 2, 2) # assert cancel((x**2/4 - 1, x/2 - 1)) == (S.Half, x + 2, 1) assert cancel((x**2 - y)/(x - y)) == 1/(x - y)*(x**2 - y) assert cancel((x**2 - y**2)/(x - y), x) == x + y assert cancel((x**2 - y**2)/(x - y), y) == x + y assert cancel((x**2 - y**2)/(x - y)) == x + y assert cancel((x**3 - 1)/(x**2 - 1)) == (x**2 + x + 1)/(x + 1) assert cancel((x**3/2 - S.Half)/(x**2 - 1)) == (x**2 + x + 1)/(2*x + 2) assert cancel((exp(2*x) + 2*exp(x) + 1)/(exp(x) + 1)) == exp(x) + 1 f = Poly(x**2 - a**2, x) g = Poly(x - a, x) F = Poly(x + a, x, domain='ZZ[a]') G = Poly(1, x, domain='ZZ[a]') assert cancel((f, g)) == (1, F, G) f = x**3 + (sqrt(2) - 2)*x**2 - (2*sqrt(2) + 3)*x - 3*sqrt(2) g = x**2 - 2 assert cancel((f, g), extension=True) == (1, x**2 - 2*x - 3, x - sqrt(2)) f = Poly(-2*x + 3, x) g = Poly(-x**9 + x**8 + x**6 - x**5 + 2*x**2 - 3*x + 1, x) assert cancel((f, g)) == (1, -f, -g) f = Poly(y, y, domain='ZZ(x)') g = Poly(1, y, domain='ZZ[x]') assert f.cancel( g) == (1, Poly(y, y, domain='ZZ(x)'), Poly(1, y, domain='ZZ(x)')) assert f.cancel(g, include=True) == ( Poly(y, y, domain='ZZ(x)'), Poly(1, y, domain='ZZ(x)')) f = Poly(5*x*y + x, y, domain='ZZ(x)') g = Poly(2*x**2*y, y, domain='ZZ(x)') assert f.cancel(g, include=True) == ( Poly(5*y + 1, y, domain='ZZ(x)'), Poly(2*x*y, y, domain='ZZ(x)')) f = -(-2*x - 4*y + 0.005*(z - y)**2)/((z - y)*(-z + y + 2)) assert cancel(f).is_Mul == True P = tanh(x - 3.0) Q = tanh(x + 3.0) f = ((-2*P**2 + 2)*(-P**2 + 1)*Q**2/2 + (-2*P**2 + 2)*(-2*Q**2 + 2)*P*Q - (-2*P**2 + 2)*P**2*Q**2 + (-2*Q**2 + 2)*(-Q**2 + 1)*P**2/2 - (-2*Q**2 + 2)*P**2*Q**2)/(2*sqrt(P**2*Q**2 + 0.0001)) \ + (-(-2*P**2 + 2)*P*Q**2/2 - (-2*Q**2 + 2)*P**2*Q/2)*((-2*P**2 + 2)*P*Q**2/2 + (-2*Q**2 + 2)*P**2*Q/2)/(2*(P**2*Q**2 + 0.0001)**Rational(3, 2)) assert cancel(f).is_Mul == True # issue 7022 A = Symbol('A', commutative=False) p1 = Piecewise((A*(x**2 - 1)/(x + 1), x > 1), ((x + 2)/(x**2 + 2*x), True)) p2 = Piecewise((A*(x - 1), x > 1), (1/x, True)) assert cancel(p1) == p2 assert cancel(2*p1) == 2*p2 assert cancel(1 + p1) == 1 + p2 assert cancel((x**2 - 1)/(x + 1)*p1) == (x - 1)*p2 assert cancel((x**2 - 1)/(x + 1) + p1) == (x - 1) + p2 p3 = Piecewise(((x**2 - 1)/(x + 1), x > 1), ((x + 2)/(x**2 + 2*x), True)) p4 = Piecewise(((x - 1), x > 1), (1/x, True)) assert cancel(p3) == p4 assert cancel(2*p3) == 2*p4 assert cancel(1 + p3) == 1 + p4 assert cancel((x**2 - 1)/(x + 1)*p3) == (x - 1)*p4 assert cancel((x**2 - 1)/(x + 1) + p3) == (x - 1) + p4 # issue 9363 M = MatrixSymbol('M', 5, 5) assert cancel(M[0,0] + 7) == M[0,0] + 7 expr = sin(M[1, 4] + M[2, 1] * 5 * M[4, 0]) - 5 * M[1, 2] / z assert cancel(expr) == (z*sin(M[1, 4] + M[2, 1] * 5 * M[4, 0]) - 5 * M[1, 2]) / z assert cancel((x**2 + 1)/(x - I)) == x + I def test_reduced(): f = 2*x**4 + y**2 - x**2 + y**3 G = [x**3 - x, y**3 - y] Q = [2*x, 1] r = x**2 + y**2 + y assert reduced(f, G) == (Q, r) assert reduced(f, G, x, y) == (Q, r) H = groebner(G) assert H.reduce(f) == (Q, r) Q = [Poly(2*x, x, y), Poly(1, x, y)] r = Poly(x**2 + y**2 + y, x, y) assert _strict_eq(reduced(f, G, polys=True), (Q, r)) assert _strict_eq(reduced(f, G, x, y, polys=True), (Q, r)) H = groebner(G, polys=True) assert _strict_eq(H.reduce(f), (Q, r)) f = 2*x**3 + y**3 + 3*y G = groebner([x**2 + y**2 - 1, x*y - 2]) Q = [x**2 - x*y**3/2 + x*y/2 + y**6/4 - y**4/2 + y**2/4, -y**5/4 + y**3/2 + y*Rational(3, 4)] r = 0 assert reduced(f, G) == (Q, r) assert G.reduce(f) == (Q, r) assert reduced(f, G, auto=False)[1] != 0 assert G.reduce(f, auto=False)[1] != 0 assert G.contains(f) is True assert G.contains(f + 1) is False assert reduced(1, [1], x) == ([1], 0) raises(ComputationFailed, lambda: reduced(1, [1])) def test_groebner(): assert groebner([], x, y, z) == [] assert groebner([x**2 + 1, y**4*x + x**3], x, y, order='lex') == [1 + x**2, -1 + y**4] assert groebner([x**2 + 1, y**4*x + x**3, x*y*z**3], x, y, z, order='grevlex') == [-1 + y**4, z**3, 1 + x**2] assert groebner([x**2 + 1, y**4*x + x**3], x, y, order='lex', polys=True) == \ [Poly(1 + x**2, x, y), Poly(-1 + y**4, x, y)] assert groebner([x**2 + 1, y**4*x + x**3, x*y*z**3], x, y, z, order='grevlex', polys=True) == \ [Poly(-1 + y**4, x, y, z), Poly(z**3, x, y, z), Poly(1 + x**2, x, y, z)] assert groebner([x**3 - 1, x**2 - 1]) == [x - 1] assert groebner([Eq(x**3, 1), Eq(x**2, 1)]) == [x - 1] F = [3*x**2 + y*z - 5*x - 1, 2*x + 3*x*y + y**2, x - 3*y + x*z - 2*z**2] f = z**9 - x**2*y**3 - 3*x*y**2*z + 11*y*z**2 + x**2*z**2 - 5 G = groebner(F, x, y, z, modulus=7, symmetric=False) assert G == [1 + x + y + 3*z + 2*z**2 + 2*z**3 + 6*z**4 + z**5, 1 + 3*y + y**2 + 6*z**2 + 3*z**3 + 3*z**4 + 3*z**5 + 4*z**6, 1 + 4*y + 4*z + y*z + 4*z**3 + z**4 + z**6, 6 + 6*z + z**2 + 4*z**3 + 3*z**4 + 6*z**5 + 3*z**6 + z**7] Q, r = reduced(f, G, x, y, z, modulus=7, symmetric=False, polys=True) assert sum([ q*g for q, g in zip(Q, G.polys)], r) == Poly(f, modulus=7) F = [x*y - 2*y, 2*y**2 - x**2] assert groebner(F, x, y, order='grevlex') == \ [y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y] assert groebner(F, y, x, order='grevlex') == \ [x**3 - 2*x**2, -x**2 + 2*y**2, x*y - 2*y] assert groebner(F, order='grevlex', field=True) == \ [y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y] assert groebner([1], x) == [1] assert groebner([x**2 + 2.0*y], x, y) == [1.0*x**2 + 2.0*y] raises(ComputationFailed, lambda: groebner([1])) assert groebner([x**2 - 1, x**3 + 1], method='buchberger') == [x + 1] assert groebner([x**2 - 1, x**3 + 1], method='f5b') == [x + 1] raises(ValueError, lambda: groebner([x, y], method='unknown')) def test_fglm(): F = [a + b + c + d, a*b + a*d + b*c + b*d, a*b*c + a*b*d + a*c*d + b*c*d, a*b*c*d - 1] G = groebner(F, a, b, c, d, order=grlex) B = [ 4*a + 3*d**9 - 4*d**5 - 3*d, 4*b + 4*c - 3*d**9 + 4*d**5 + 7*d, 4*c**2 + 3*d**10 - 4*d**6 - 3*d**2, 4*c*d**4 + 4*c - d**9 + 4*d**5 + 5*d, d**12 - d**8 - d**4 + 1, ] assert groebner(F, a, b, c, d, order=lex) == B assert G.fglm(lex) == B F = [9*x**8 + 36*x**7 - 32*x**6 - 252*x**5 - 78*x**4 + 468*x**3 + 288*x**2 - 108*x + 9, -72*t*x**7 - 252*t*x**6 + 192*t*x**5 + 1260*t*x**4 + 312*t*x**3 - 404*t*x**2 - 576*t*x + \ 108*t - 72*x**7 - 256*x**6 + 192*x**5 + 1280*x**4 + 312*x**3 - 576*x + 96] G = groebner(F, t, x, order=grlex) B = [ 203577793572507451707*t + 627982239411707112*x**7 - 666924143779443762*x**6 - \ 10874593056632447619*x**5 + 5119998792707079562*x**4 + 72917161949456066376*x**3 + \ 20362663855832380362*x**2 - 142079311455258371571*x + 183756699868981873194, 9*x**8 + 36*x**7 - 32*x**6 - 252*x**5 - 78*x**4 + 468*x**3 + 288*x**2 - 108*x + 9, ] assert groebner(F, t, x, order=lex) == B assert G.fglm(lex) == B F = [x**2 - x - 3*y + 1, -2*x + y**2 + y - 1] G = groebner(F, x, y, order=lex) B = [ x**2 - x - 3*y + 1, y**2 - 2*x + y - 1, ] assert groebner(F, x, y, order=grlex) == B assert G.fglm(grlex) == B def test_is_zero_dimensional(): assert is_zero_dimensional([x, y], x, y) is True assert is_zero_dimensional([x**3 + y**2], x, y) is False assert is_zero_dimensional([x, y, z], x, y, z) is True assert is_zero_dimensional([x, y, z], x, y, z, t) is False F = [x*y - z, y*z - x, x*y - y] assert is_zero_dimensional(F, x, y, z) is True F = [x**2 - 2*x*z + 5, x*y**2 + y*z**3, 3*y**2 - 8*z**2] assert is_zero_dimensional(F, x, y, z) is True def test_GroebnerBasis(): F = [x*y - 2*y, 2*y**2 - x**2] G = groebner(F, x, y, order='grevlex') H = [y**3 - 2*y, x**2 - 2*y**2, x*y - 2*y] P = [ Poly(h, x, y) for h in H ] assert groebner(F + [0], x, y, order='grevlex') == G assert isinstance(G, GroebnerBasis) is True assert len(G) == 3 assert G[0] == H[0] and not G[0].is_Poly assert G[1] == H[1] and not G[1].is_Poly assert G[2] == H[2] and not G[2].is_Poly assert G[1:] == H[1:] and not any(g.is_Poly for g in G[1:]) assert G[:2] == H[:2] and not any(g.is_Poly for g in G[1:]) assert G.exprs == H assert G.polys == P assert G.gens == (x, y) assert G.domain == ZZ assert G.order == grevlex assert G == H assert G == tuple(H) assert G == P assert G == tuple(P) assert G != [] G = groebner(F, x, y, order='grevlex', polys=True) assert G[0] == P[0] and G[0].is_Poly assert G[1] == P[1] and G[1].is_Poly assert G[2] == P[2] and G[2].is_Poly assert G[1:] == P[1:] and all(g.is_Poly for g in G[1:]) assert G[:2] == P[:2] and all(g.is_Poly for g in G[1:]) def test_poly(): assert poly(x) == Poly(x, x) assert poly(y) == Poly(y, y) assert poly(x + y) == Poly(x + y, x, y) assert poly(x + sin(x)) == Poly(x + sin(x), x, sin(x)) assert poly(x + y, wrt=y) == Poly(x + y, y, x) assert poly(x + sin(x), wrt=sin(x)) == Poly(x + sin(x), sin(x), x) assert poly(x*y + 2*x*z**2 + 17) == Poly(x*y + 2*x*z**2 + 17, x, y, z) assert poly(2*(y + z)**2 - 1) == Poly(2*y**2 + 4*y*z + 2*z**2 - 1, y, z) assert poly( x*(y + z)**2 - 1) == Poly(x*y**2 + 2*x*y*z + x*z**2 - 1, x, y, z) assert poly(2*x*( y + z)**2 - 1) == Poly(2*x*y**2 + 4*x*y*z + 2*x*z**2 - 1, x, y, z) assert poly(2*( y + z)**2 - x - 1) == Poly(2*y**2 + 4*y*z + 2*z**2 - x - 1, x, y, z) assert poly(x*( y + z)**2 - x - 1) == Poly(x*y**2 + 2*x*y*z + x*z**2 - x - 1, x, y, z) assert poly(2*x*(y + z)**2 - x - 1) == Poly(2*x*y**2 + 4*x*y*z + 2* x*z**2 - x - 1, x, y, z) assert poly(x*y + (x + y)**2 + (x + z)**2) == \ Poly(2*x*z + 3*x*y + y**2 + z**2 + 2*x**2, x, y, z) assert poly(x*y*(x + y)*(x + z)**2) == \ Poly(x**3*y**2 + x*y**2*z**2 + y*x**2*z**2 + 2*z*x**2* y**2 + 2*y*z*x**3 + y*x**4, x, y, z) assert poly(Poly(x + y + z, y, x, z)) == Poly(x + y + z, y, x, z) assert poly((x + y)**2, x) == Poly(x**2 + 2*x*y + y**2, x, domain=ZZ[y]) assert poly((x + y)**2, y) == Poly(x**2 + 2*x*y + y**2, y, domain=ZZ[x]) assert poly(1, x) == Poly(1, x) raises(GeneratorsNeeded, lambda: poly(1)) # issue 6184 assert poly(x + y, x, y) == Poly(x + y, x, y) assert poly(x + y, y, x) == Poly(x + y, y, x) def test_keep_coeff(): u = Mul(2, x + 1, evaluate=False) assert _keep_coeff(S.One, x) == x assert _keep_coeff(S.NegativeOne, x) == -x assert _keep_coeff(S(1.0), x) == 1.0*x assert _keep_coeff(S(-1.0), x) == -1.0*x assert _keep_coeff(S.One, 2*x) == 2*x assert _keep_coeff(S(2), x/2) == x assert _keep_coeff(S(2), sin(x)) == 2*sin(x) assert _keep_coeff(S(2), x + 1) == u assert _keep_coeff(x, 1/x) == 1 assert _keep_coeff(x + 1, S(2)) == u assert _keep_coeff(S.Half, S.One) == S.Half p = Pow(2, 3, evaluate=False) assert _keep_coeff(S(-1), p) == Mul(-1, p, evaluate=False) a = Add(2, p, evaluate=False) assert _keep_coeff(S.Half, a, clear=True ) == Mul(S.Half, a, evaluate=False) assert _keep_coeff(S.Half, a, clear=False ) == Add(1, Mul(S.Half, p, evaluate=False), evaluate=False) def test_poly_matching_consistency(): # Test for this issue: # https://github.com/sympy/sympy/issues/5514 assert I * Poly(x, x) == Poly(I*x, x) assert Poly(x, x) * I == Poly(I*x, x) def test_issue_5786(): assert expand(factor(expand( (x - I*y)*(z - I*t)), extension=[I])) == -I*t*x - t*y + x*z - I*y*z def test_noncommutative(): class foo(Expr): is_commutative=False e = x/(x + x*y) c = 1/( 1 + y) assert cancel(foo(e)) == foo(c) assert cancel(e + foo(e)) == c + foo(c) assert cancel(e*foo(c)) == c*foo(c) def test_to_rational_coeffs(): assert to_rational_coeffs( Poly(x**3 + y*x**2 + sqrt(y), x, domain='EX')) is None # issue 21268 assert to_rational_coeffs( Poly(y**3 + sqrt(2)*y**2*sin(x) + 1, y)) is None assert to_rational_coeffs(Poly(x, y)) is None assert to_rational_coeffs(Poly(sqrt(2)*y)) is None def test_factor_terms(): # issue 7067 assert factor_list(x*(x + y)) == (1, [(x, 1), (x + y, 1)]) assert sqf_list(x*(x + y)) == (1, [(x**2 + x*y, 1)]) def test_as_list(): # issue 14496 assert Poly(x**3 + 2, x, domain='ZZ').as_list() == [1, 0, 0, 2] assert Poly(x**2 + y + 1, x, y, domain='ZZ').as_list() == [[1], [], [1, 1]] assert Poly(x**2 + y + 1, x, y, z, domain='ZZ').as_list() == \ [[[1]], [[]], [[1], [1]]] def test_issue_11198(): assert factor_list(sqrt(2)*x) == (sqrt(2), [(x, 1)]) assert factor_list(sqrt(2)*sin(x), sin(x)) == (sqrt(2), [(sin(x), 1)]) def test_Poly_precision(): # Make sure Poly doesn't lose precision p = Poly(pi.evalf(100)*x) assert p.as_expr() == pi.evalf(100)*x def test_issue_12400(): # Correction of check for negative exponents assert poly(1/(1+sqrt(2)), x) == \ Poly(1/(1+sqrt(2)), x , domain='EX') def test_issue_14364(): assert gcd(S(6)*(1 + sqrt(3))/5, S(3)*(1 + sqrt(3))/10) == Rational(3, 10) * (1 + sqrt(3)) assert gcd(sqrt(5)*Rational(4, 7), sqrt(5)*Rational(2, 3)) == sqrt(5)*Rational(2, 21) assert lcm(Rational(2, 3)*sqrt(3), Rational(5, 6)*sqrt(3)) == S(10)*sqrt(3)/3 assert lcm(3*sqrt(3), 4/sqrt(3)) == 12*sqrt(3) assert lcm(S(5)*(1 + 2**Rational(1, 3))/6, S(3)*(1 + 2**Rational(1, 3))/8) == Rational(15, 2) * (1 + 2**Rational(1, 3)) assert gcd(Rational(2, 3)*sqrt(3), Rational(5, 6)/sqrt(3)) == sqrt(3)/18 assert gcd(S(4)*sqrt(13)/7, S(3)*sqrt(13)/14) == sqrt(13)/14 # gcd_list and lcm_list assert gcd([S(2)*sqrt(47)/7, S(6)*sqrt(47)/5, S(8)*sqrt(47)/5]) == sqrt(47)*Rational(2, 35) assert gcd([S(6)*(1 + sqrt(7))/5, S(2)*(1 + sqrt(7))/7, S(4)*(1 + sqrt(7))/13]) == (1 + sqrt(7))*Rational(2, 455) assert lcm((Rational(7, 2)/sqrt(15), Rational(5, 6)/sqrt(15), Rational(5, 8)/sqrt(15))) == Rational(35, 2)/sqrt(15) assert lcm([S(5)*(2 + 2**Rational(5, 7))/6, S(7)*(2 + 2**Rational(5, 7))/2, S(13)*(2 + 2**Rational(5, 7))/4]) == Rational(455, 2) * (2 + 2**Rational(5, 7)) def test_issue_15669(): x = Symbol("x", positive=True) expr = (16*x**3/(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**2 - 2*2**Rational(4, 5)*x*(-x**2 + sqrt(8*x**2 + (x**2 - 2)**2) + 2)**Rational(3, 5) + 10*x) assert factor(expr, deep=True) == x*(x**2 + 2) def test_issue_17988(): x = Symbol('x') p = poly(x - 1) with warns_deprecated_sympy(): M = Matrix([[poly(x + 1), poly(x + 1)]]) with warns_deprecated_sympy(): assert p * M == M * p == Matrix([[poly(x**2 - 1), poly(x**2 - 1)]]) def test_issue_18205(): assert cancel((2 + I)*(3 - I)) == 7 + I assert cancel((2 + I)*(2 - I)) == 5 def test_issue_8695(): p = (x**2 + 1) * (x - 1)**2 * (x - 2)**3 * (x - 3)**3 result = (1, [(x**2 + 1, 1), (x - 1, 2), (x**2 - 5*x + 6, 3)]) assert sqf_list(p) == result def test_issue_19113(): eq = sin(x)**3 - sin(x) + 1 raises(PolynomialError, lambda: refine_root(eq, 1, 2, 1e-2)) raises(PolynomialError, lambda: count_roots(eq, -1, 1)) raises(PolynomialError, lambda: real_roots(eq)) raises(PolynomialError, lambda: nroots(eq)) raises(PolynomialError, lambda: ground_roots(eq)) raises(PolynomialError, lambda: nth_power_roots_poly(eq, 2)) def test_issue_19360(): f = 2*x**2 - 2*sqrt(2)*x*y + y**2 assert factor(f, extension=sqrt(2)) == 2*(x - (sqrt(2)*y/2))**2 f = -I*t*x - t*y + x*z - I*y*z assert factor(f, extension=I) == (x - I*y)*(-I*t + z) def test_poly_copy_equals_original(): poly = Poly(x + y, x, y, z) copy = poly.copy() assert poly == copy, ( "Copied polynomial not equal to original.") assert poly.gens == copy.gens, ( "Copied polynomial has different generators than original.") def test_deserialized_poly_equals_original(): poly = Poly(x + y, x, y, z) deserialized = pickle.loads(pickle.dumps(poly)) assert poly == deserialized, ( "Deserialized polynomial not equal to original.") assert poly.gens == deserialized.gens, ( "Deserialized polynomial has different generators than original.") def test_issue_20389(): result = degree(x * (x + 1) - x ** 2 - x, x) assert result == -oo def test_issue_20985(): from sympy import symbols w, R = symbols('w R') poly = Poly(1.0 + I*w/R, w, 1/R) assert poly.degree() == S(1) sympy-sympy-1.9/sympy/polys/tests/test_polyutils.py000066400000000000000000000257271412543434000231060ustar00rootroot00000000000000"""Tests for useful utilities for higher level polynomial classes. """ from sympy import (S, Integer, sin, cos, sqrt, symbols, pi, Eq, Integral, exp, Mul, Symbol) from sympy.testing.pytest import raises from sympy.polys.polyutils import ( _nsort, _sort_gens, _unify_gens, _analyze_gens, _sort_factors, parallel_dict_from_expr, dict_from_expr, ) from sympy.polys.polyerrors import PolynomialError from sympy.polys.domains import ZZ x, y, z, p, q, r, s, t, u, v, w = symbols('x,y,z,p,q,r,s,t,u,v,w') A, B = symbols('A,B', commutative=False) def test__nsort(): # issue 6137 r = S('''[3/2 + sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) - 4/sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3)) - 61/(18*(-415/216 + 13*I/12)**(1/3)))/2 - sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3))/2, 3/2 - sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3))/2 - sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) - 4/sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3)) - 61/(18*(-415/216 + 13*I/12)**(1/3)))/2, 3/2 + sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) + 4/sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3)) - 61/(18*(-415/216 + 13*I/12)**(1/3)))/2 + sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3))/2, 3/2 + sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3))/2 - sqrt(-14/3 - 2*(-415/216 + 13*I/12)**(1/3) + 4/sqrt(-7/3 + 61/(18*(-415/216 + 13*I/12)**(1/3)) + 2*(-415/216 + 13*I/12)**(1/3)) - 61/(18*(-415/216 + 13*I/12)**(1/3)))/2]''') ans = [r[1], r[0], r[-1], r[-2]] assert _nsort(r) == ans assert len(_nsort(r, separated=True)[0]) == 0 b, c, a = exp(-1000), exp(-999), exp(-1001) assert _nsort((b, c, a)) == [a, b, c] # issue 12560 a = cos(1)**2 + sin(1)**2 - 1 assert _nsort([a]) == [a] def test__sort_gens(): assert _sort_gens([]) == () assert _sort_gens([x]) == (x,) assert _sort_gens([p]) == (p,) assert _sort_gens([q]) == (q,) assert _sort_gens([x, p]) == (x, p) assert _sort_gens([p, x]) == (x, p) assert _sort_gens([q, p]) == (p, q) assert _sort_gens([q, p, x]) == (x, p, q) assert _sort_gens([x, p, q], wrt=x) == (x, p, q) assert _sort_gens([x, p, q], wrt=p) == (p, x, q) assert _sort_gens([x, p, q], wrt=q) == (q, x, p) assert _sort_gens([x, p, q], wrt='x') == (x, p, q) assert _sort_gens([x, p, q], wrt='p') == (p, x, q) assert _sort_gens([x, p, q], wrt='q') == (q, x, p) assert _sort_gens([x, p, q], wrt='x,q') == (x, q, p) assert _sort_gens([x, p, q], wrt='q,x') == (q, x, p) assert _sort_gens([x, p, q], wrt='p,q') == (p, q, x) assert _sort_gens([x, p, q], wrt='q,p') == (q, p, x) assert _sort_gens([x, p, q], wrt='x, q') == (x, q, p) assert _sort_gens([x, p, q], wrt='q, x') == (q, x, p) assert _sort_gens([x, p, q], wrt='p, q') == (p, q, x) assert _sort_gens([x, p, q], wrt='q, p') == (q, p, x) assert _sort_gens([x, p, q], wrt=[x, 'q']) == (x, q, p) assert _sort_gens([x, p, q], wrt=[q, 'x']) == (q, x, p) assert _sort_gens([x, p, q], wrt=[p, 'q']) == (p, q, x) assert _sort_gens([x, p, q], wrt=[q, 'p']) == (q, p, x) assert _sort_gens([x, p, q], wrt=['x', 'q']) == (x, q, p) assert _sort_gens([x, p, q], wrt=['q', 'x']) == (q, x, p) assert _sort_gens([x, p, q], wrt=['p', 'q']) == (p, q, x) assert _sort_gens([x, p, q], wrt=['q', 'p']) == (q, p, x) assert _sort_gens([x, p, q], sort='x > p > q') == (x, p, q) assert _sort_gens([x, p, q], sort='p > x > q') == (p, x, q) assert _sort_gens([x, p, q], sort='p > q > x') == (p, q, x) assert _sort_gens([x, p, q], wrt='x', sort='q > p') == (x, q, p) assert _sort_gens([x, p, q], wrt='p', sort='q > x') == (p, q, x) assert _sort_gens([x, p, q], wrt='q', sort='p > x') == (q, p, x) # https://github.com/sympy/sympy/issues/19353 n1 = Symbol('\n1') assert _sort_gens([n1]) == (n1,) assert _sort_gens([x, n1]) == (x, n1) X = symbols('x0,x1,x2,x10,x11,x12,x20,x21,x22') assert _sort_gens(X) == X def test__unify_gens(): assert _unify_gens([], []) == () assert _unify_gens([x], [x]) == (x,) assert _unify_gens([y], [y]) == (y,) assert _unify_gens([x, y], [x]) == (x, y) assert _unify_gens([x], [x, y]) == (x, y) assert _unify_gens([x, y], [x, y]) == (x, y) assert _unify_gens([y, x], [y, x]) == (y, x) assert _unify_gens([x], [y]) == (x, y) assert _unify_gens([y], [x]) == (y, x) assert _unify_gens([x], [y, x]) == (y, x) assert _unify_gens([y, x], [x]) == (y, x) assert _unify_gens([x, y, z], [x, y, z]) == (x, y, z) assert _unify_gens([z, y, x], [x, y, z]) == (z, y, x) assert _unify_gens([x, y, z], [z, y, x]) == (x, y, z) assert _unify_gens([z, y, x], [z, y, x]) == (z, y, x) assert _unify_gens([x, y, z], [t, x, p, q, z]) == (t, x, y, p, q, z) def test__analyze_gens(): assert _analyze_gens((x, y, z)) == (x, y, z) assert _analyze_gens([x, y, z]) == (x, y, z) assert _analyze_gens(([x, y, z],)) == (x, y, z) assert _analyze_gens(((x, y, z),)) == (x, y, z) def test__sort_factors(): assert _sort_factors([], multiple=True) == [] assert _sort_factors([], multiple=False) == [] F = [[1, 2, 3], [1, 2], [1]] G = [[1], [1, 2], [1, 2, 3]] assert _sort_factors(F, multiple=False) == G F = [[1, 2], [1, 2, 3], [1, 2], [1]] G = [[1], [1, 2], [1, 2], [1, 2, 3]] assert _sort_factors(F, multiple=False) == G F = [[2, 2], [1, 2, 3], [1, 2], [1]] G = [[1], [1, 2], [2, 2], [1, 2, 3]] assert _sort_factors(F, multiple=False) == G F = [([1, 2, 3], 1), ([1, 2], 1), ([1], 1)] G = [([1], 1), ([1, 2], 1), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G F = [([1, 2], 1), ([1, 2, 3], 1), ([1, 2], 1), ([1], 1)] G = [([1], 1), ([1, 2], 1), ([1, 2], 1), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G F = [([2, 2], 1), ([1, 2, 3], 1), ([1, 2], 1), ([1], 1)] G = [([1], 1), ([1, 2], 1), ([2, 2], 1), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G F = [([2, 2], 1), ([1, 2, 3], 1), ([1, 2], 2), ([1], 1)] G = [([1], 1), ([2, 2], 1), ([1, 2], 2), ([1, 2, 3], 1)] assert _sort_factors(F, multiple=True) == G def test__dict_from_expr_if_gens(): assert dict_from_expr( Integer(17), gens=(x,)) == ({(0,): Integer(17)}, (x,)) assert dict_from_expr( Integer(17), gens=(x, y)) == ({(0, 0): Integer(17)}, (x, y)) assert dict_from_expr( Integer(17), gens=(x, y, z)) == ({(0, 0, 0): Integer(17)}, (x, y, z)) assert dict_from_expr( Integer(-17), gens=(x,)) == ({(0,): Integer(-17)}, (x,)) assert dict_from_expr( Integer(-17), gens=(x, y)) == ({(0, 0): Integer(-17)}, (x, y)) assert dict_from_expr(Integer( -17), gens=(x, y, z)) == ({(0, 0, 0): Integer(-17)}, (x, y, z)) assert dict_from_expr( Integer(17)*x, gens=(x,)) == ({(1,): Integer(17)}, (x,)) assert dict_from_expr( Integer(17)*x, gens=(x, y)) == ({(1, 0): Integer(17)}, (x, y)) assert dict_from_expr(Integer( 17)*x, gens=(x, y, z)) == ({(1, 0, 0): Integer(17)}, (x, y, z)) assert dict_from_expr( Integer(17)*x**7, gens=(x,)) == ({(7,): Integer(17)}, (x,)) assert dict_from_expr( Integer(17)*x**7*y, gens=(x, y)) == ({(7, 1): Integer(17)}, (x, y)) assert dict_from_expr(Integer(17)*x**7*y*z**12, gens=( x, y, z)) == ({(7, 1, 12): Integer(17)}, (x, y, z)) assert dict_from_expr(x + 2*y + 3*z, gens=(x,)) == \ ({(1,): Integer(1), (0,): 2*y + 3*z}, (x,)) assert dict_from_expr(x + 2*y + 3*z, gens=(x, y)) == \ ({(1, 0): Integer(1), (0, 1): Integer(2), (0, 0): 3*z}, (x, y)) assert dict_from_expr(x + 2*y + 3*z, gens=(x, y, z)) == \ ({(1, 0, 0): Integer( 1), (0, 1, 0): Integer(2), (0, 0, 1): Integer(3)}, (x, y, z)) assert dict_from_expr(x*y + 2*x*z + 3*y*z, gens=(x,)) == \ ({(1,): y + 2*z, (0,): 3*y*z}, (x,)) assert dict_from_expr(x*y + 2*x*z + 3*y*z, gens=(x, y)) == \ ({(1, 1): Integer(1), (1, 0): 2*z, (0, 1): 3*z}, (x, y)) assert dict_from_expr(x*y + 2*x*z + 3*y*z, gens=(x, y, z)) == \ ({(1, 1, 0): Integer( 1), (1, 0, 1): Integer(2), (0, 1, 1): Integer(3)}, (x, y, z)) assert dict_from_expr(2**y*x, gens=(x,)) == ({(1,): 2**y}, (x,)) assert dict_from_expr(Integral(x, (x, 1, 2)) + x) == ( {(0, 1): 1, (1, 0): 1}, (x, Integral(x, (x, 1, 2)))) raises(PolynomialError, lambda: dict_from_expr(2**y*x, gens=(x, y))) def test__dict_from_expr_no_gens(): assert dict_from_expr(Integer(17)) == ({(): Integer(17)}, ()) assert dict_from_expr(x) == ({(1,): Integer(1)}, (x,)) assert dict_from_expr(y) == ({(1,): Integer(1)}, (y,)) assert dict_from_expr(x*y) == ({(1, 1): Integer(1)}, (x, y)) assert dict_from_expr( x + y) == ({(1, 0): Integer(1), (0, 1): Integer(1)}, (x, y)) assert dict_from_expr(sqrt(2)) == ({(1,): Integer(1)}, (sqrt(2),)) assert dict_from_expr(sqrt(2), greedy=False) == ({(): sqrt(2)}, ()) assert dict_from_expr(x*y, domain=ZZ[x]) == ({(1,): x}, (y,)) assert dict_from_expr(x*y, domain=ZZ[y]) == ({(1,): y}, (x,)) assert dict_from_expr(3*sqrt( 2)*pi*x*y, extension=None) == ({(1, 1, 1, 1): 3}, (x, y, pi, sqrt(2))) assert dict_from_expr(3*sqrt( 2)*pi*x*y, extension=True) == ({(1, 1, 1): 3*sqrt(2)}, (x, y, pi)) assert dict_from_expr(3*sqrt( 2)*pi*x*y, extension=True) == ({(1, 1, 1): 3*sqrt(2)}, (x, y, pi)) f = cos(x)*sin(x) + cos(x)*sin(y) + cos(y)*sin(x) + cos(y)*sin(y) assert dict_from_expr(f) == ({(0, 1, 0, 1): 1, (0, 1, 1, 0): 1, (1, 0, 0, 1): 1, (1, 0, 1, 0): 1}, (cos(x), cos(y), sin(x), sin(y))) def test__parallel_dict_from_expr_if_gens(): assert parallel_dict_from_expr([x + 2*y + 3*z, Integer(7)], gens=(x,)) == \ ([{(1,): Integer(1), (0,): 2*y + 3*z}, {(0,): Integer(7)}], (x,)) def test__parallel_dict_from_expr_no_gens(): assert parallel_dict_from_expr([x*y, Integer(3)]) == \ ([{(1, 1): Integer(1)}, {(0, 0): Integer(3)}], (x, y)) assert parallel_dict_from_expr([x*y, 2*z, Integer(3)]) == \ ([{(1, 1, 0): Integer( 1)}, {(0, 0, 1): Integer(2)}, {(0, 0, 0): Integer(3)}], (x, y, z)) assert parallel_dict_from_expr((Mul(x, x**2, evaluate=False),)) == \ ([{(3,): 1}], (x,)) def test_parallel_dict_from_expr(): assert parallel_dict_from_expr([Eq(x, 1), Eq( x**2, 2)]) == ([{(0,): -Integer(1), (1,): Integer(1)}, {(0,): -Integer(2), (2,): Integer(1)}], (x,)) raises(PolynomialError, lambda: parallel_dict_from_expr([A*B - B*A])) def test_dict_from_expr(): assert dict_from_expr(Eq(x, 1)) == \ ({(0,): -Integer(1), (1,): Integer(1)}, (x,)) raises(PolynomialError, lambda: dict_from_expr(A*B - B*A)) raises(PolynomialError, lambda: dict_from_expr(S.true)) sympy-sympy-1.9/sympy/polys/tests/test_pythonrational.py000066400000000000000000000100571412543434000241030ustar00rootroot00000000000000"""Tests for PythonRational type. """ from sympy.polys.domains import PythonRational as QQ from sympy.testing.pytest import raises def test_PythonRational__init__(): assert QQ(0).numerator == 0 assert QQ(0).denominator == 1 assert QQ(0, 1).numerator == 0 assert QQ(0, 1).denominator == 1 assert QQ(0, -1).numerator == 0 assert QQ(0, -1).denominator == 1 assert QQ(1).numerator == 1 assert QQ(1).denominator == 1 assert QQ(1, 1).numerator == 1 assert QQ(1, 1).denominator == 1 assert QQ(-1, -1).numerator == 1 assert QQ(-1, -1).denominator == 1 assert QQ(-1).numerator == -1 assert QQ(-1).denominator == 1 assert QQ(-1, 1).numerator == -1 assert QQ(-1, 1).denominator == 1 assert QQ( 1, -1).numerator == -1 assert QQ( 1, -1).denominator == 1 assert QQ(1, 2).numerator == 1 assert QQ(1, 2).denominator == 2 assert QQ(3, 4).numerator == 3 assert QQ(3, 4).denominator == 4 assert QQ(2, 2).numerator == 1 assert QQ(2, 2).denominator == 1 assert QQ(2, 4).numerator == 1 assert QQ(2, 4).denominator == 2 def test_PythonRational__hash__(): assert hash(QQ(0)) == hash(0) assert hash(QQ(1)) == hash(1) assert hash(QQ(117)) == hash(117) def test_PythonRational__int__(): assert int(QQ(-1, 4)) == 0 assert int(QQ( 1, 4)) == 0 assert int(QQ(-5, 4)) == -1 assert int(QQ( 5, 4)) == 1 def test_PythonRational__float__(): assert float(QQ(-1, 2)) == -0.5 assert float(QQ( 1, 2)) == 0.5 def test_PythonRational__abs__(): assert abs(QQ(-1, 2)) == QQ(1, 2) assert abs(QQ( 1, 2)) == QQ(1, 2) def test_PythonRational__pos__(): assert +QQ(-1, 2) == QQ(-1, 2) assert +QQ( 1, 2) == QQ( 1, 2) def test_PythonRational__neg__(): assert -QQ(-1, 2) == QQ( 1, 2) assert -QQ( 1, 2) == QQ(-1, 2) def test_PythonRational__add__(): assert QQ(-1, 2) + QQ( 1, 2) == QQ(0) assert QQ( 1, 2) + QQ(-1, 2) == QQ(0) assert QQ(1, 2) + QQ(1, 2) == QQ(1) assert QQ(1, 2) + QQ(3, 2) == QQ(2) assert QQ(3, 2) + QQ(1, 2) == QQ(2) assert QQ(3, 2) + QQ(3, 2) == QQ(3) assert 1 + QQ(1, 2) == QQ(3, 2) assert QQ(1, 2) + 1 == QQ(3, 2) def test_PythonRational__sub__(): assert QQ(-1, 2) - QQ( 1, 2) == QQ(-1) assert QQ( 1, 2) - QQ(-1, 2) == QQ( 1) assert QQ(1, 2) - QQ(1, 2) == QQ( 0) assert QQ(1, 2) - QQ(3, 2) == QQ(-1) assert QQ(3, 2) - QQ(1, 2) == QQ( 1) assert QQ(3, 2) - QQ(3, 2) == QQ( 0) assert 1 - QQ(1, 2) == QQ( 1, 2) assert QQ(1, 2) - 1 == QQ(-1, 2) def test_PythonRational__mul__(): assert QQ(-1, 2) * QQ( 1, 2) == QQ(-1, 4) assert QQ( 1, 2) * QQ(-1, 2) == QQ(-1, 4) assert QQ(1, 2) * QQ(1, 2) == QQ(1, 4) assert QQ(1, 2) * QQ(3, 2) == QQ(3, 4) assert QQ(3, 2) * QQ(1, 2) == QQ(3, 4) assert QQ(3, 2) * QQ(3, 2) == QQ(9, 4) assert 2 * QQ(1, 2) == QQ(1) assert QQ(1, 2) * 2 == QQ(1) def test_PythonRational__truediv__(): assert QQ(-1, 2) / QQ( 1, 2) == QQ(-1) assert QQ( 1, 2) / QQ(-1, 2) == QQ(-1) assert QQ(1, 2) / QQ(1, 2) == QQ(1) assert QQ(1, 2) / QQ(3, 2) == QQ(1, 3) assert QQ(3, 2) / QQ(1, 2) == QQ(3) assert QQ(3, 2) / QQ(3, 2) == QQ(1) assert 2 / QQ(1, 2) == QQ(4) assert QQ(1, 2) / 2 == QQ(1, 4) raises(ZeroDivisionError, lambda: QQ(1, 2) / QQ(0)) raises(ZeroDivisionError, lambda: QQ(1, 2) / 0) def test_PythonRational__pow__(): assert QQ(1)**10 == QQ(1) assert QQ(2)**10 == QQ(1024) assert QQ(1)**(-10) == QQ(1) assert QQ(2)**(-10) == QQ(1, 1024) def test_PythonRational__eq__(): assert (QQ(1, 2) == QQ(1, 2)) is True assert (QQ(1, 2) != QQ(1, 2)) is False assert (QQ(1, 2) == QQ(1, 3)) is False assert (QQ(1, 2) != QQ(1, 3)) is True def test_PythonRational__lt_le_gt_ge__(): assert (QQ(1, 2) < QQ(1, 4)) is False assert (QQ(1, 2) <= QQ(1, 4)) is False assert (QQ(1, 2) > QQ(1, 4)) is True assert (QQ(1, 2) >= QQ(1, 4)) is True assert (QQ(1, 4) < QQ(1, 2)) is True assert (QQ(1, 4) <= QQ(1, 2)) is True assert (QQ(1, 4) > QQ(1, 2)) is False assert (QQ(1, 4) >= QQ(1, 2)) is False sympy-sympy-1.9/sympy/polys/tests/test_rationaltools.py000066400000000000000000000041151412543434000237200ustar00rootroot00000000000000"""Tests for tools for manipulation of rational expressions. """ from sympy.polys.rationaltools import together from sympy import S, symbols, Rational, sin, exp, Eq, Integral, Mul from sympy.abc import x, y, z A, B = symbols('A,B', commutative=False) def test_together(): assert together(0) == 0 assert together(1) == 1 assert together(x*y*z) == x*y*z assert together(x + y) == x + y assert together(1/x) == 1/x assert together(1/x + 1) == (x + 1)/x assert together(1/x + 3) == (3*x + 1)/x assert together(1/x + x) == (x**2 + 1)/x assert together(1/x + S.Half) == (x + 2)/(2*x) assert together(S.Half + x/2) == Mul(S.Half, x + 1, evaluate=False) assert together(1/x + 2/y) == (2*x + y)/(y*x) assert together(1/(1 + 1/x)) == x/(1 + x) assert together(x/(1 + 1/x)) == x**2/(1 + x) assert together(1/x + 1/y + 1/z) == (x*y + x*z + y*z)/(x*y*z) assert together(1/(1 + x + 1/y + 1/z)) == y*z/(y + z + y*z + x*y*z) assert together(1/(x*y) + 1/(x*y)**2) == y**(-2)*x**(-2)*(1 + x*y) assert together(1/(x*y) + 1/(x*y)**4) == y**(-4)*x**(-4)*(1 + x**3*y**3) assert together(1/(x**7*y) + 1/(x*y)**4) == y**(-4)*x**(-7)*(x**3 + y**3) assert together(5/(2 + 6/(3 + 7/(4 + 8/(5 + 9/x))))) == \ Rational(5, 2)*((171 + 119*x)/(279 + 203*x)) assert together(1 + 1/(x + 1)**2) == (1 + (x + 1)**2)/(x + 1)**2 assert together(1 + 1/(x*(1 + x))) == (1 + x*(1 + x))/(x*(1 + x)) assert together( 1/(x*(x + 1)) + 1/(x*(x + 2))) == (3 + 2*x)/(x*(1 + x)*(2 + x)) assert together(1 + 1/(2*x + 2)**2) == (4*(x + 1)**2 + 1)/(4*(x + 1)**2) assert together(sin(1/x + 1/y)) == sin(1/x + 1/y) assert together(sin(1/x + 1/y), deep=True) == sin((x + y)/(x*y)) assert together(1/exp(x) + 1/(x*exp(x))) == (1 + x)/(x*exp(x)) assert together(1/exp(2*x) + 1/(x*exp(3*x))) == (1 + exp(x)*x)/(x*exp(3*x)) assert together(Integral(1/x + 1/y, x)) == Integral((x + y)/(x*y), x) assert together(Eq(1/x + 1/y, 1 + 1/z)) == Eq((x + y)/(x*y), (z + 1)/z) assert together((A*B)**-1 + (B*A)**-1) == (A*B)**-1 + (B*A)**-1 sympy-sympy-1.9/sympy/polys/tests/test_ring_series.py000066400000000000000000000572511412543434000233500ustar00rootroot00000000000000from sympy.polys.domains import QQ, EX, RR from sympy.polys.rings import ring from sympy.polys.ring_series import (_invert_monoms, rs_integrate, rs_trunc, rs_mul, rs_square, rs_pow, _has_constant_term, rs_hadamard_exp, rs_series_from_list, rs_exp, rs_log, rs_newton, rs_series_inversion, rs_compose_add, rs_asin, rs_atan, rs_atanh, rs_tan, rs_cot, rs_sin, rs_cos, rs_cos_sin, rs_sinh, rs_cosh, rs_tanh, _tan1, rs_fun, rs_nth_root, rs_LambertW, rs_series_reversion, rs_is_puiseux, rs_series) from sympy.testing.pytest import raises from sympy.core.symbol import symbols from sympy.functions import (sin, cos, exp, tan, cot, atan, atanh, tanh, log, sqrt) from sympy.core.numbers import Rational from sympy.core import expand, S def is_close(a, b): tol = 10**(-10) assert abs(a - b) < tol def test_ring_series1(): R, x = ring('x', QQ) p = x**4 + 2*x**3 + 3*x + 4 assert _invert_monoms(p) == 4*x**4 + 3*x**3 + 2*x + 1 assert rs_hadamard_exp(p) == x**4/24 + x**3/3 + 3*x + 4 R, x = ring('x', QQ) p = x**4 + 2*x**3 + 3*x + 4 assert rs_integrate(p, x) == x**5/5 + x**4/2 + 3*x**2/2 + 4*x R, x, y = ring('x, y', QQ) p = x**2*y**2 + x + 1 assert rs_integrate(p, x) == x**3*y**2/3 + x**2/2 + x assert rs_integrate(p, y) == x**2*y**3/3 + x*y + y def test_trunc(): R, x, y, t = ring('x, y, t', QQ) p = (y + t*x)**4 p1 = rs_trunc(p, x, 3) assert p1 == y**4 + 4*y**3*t*x + 6*y**2*t**2*x**2 def test_mul_trunc(): R, x, y, t = ring('x, y, t', QQ) p = 1 + t*x + t*y for i in range(2): p = rs_mul(p, p, t, 3) assert p == 6*x**2*t**2 + 12*x*y*t**2 + 6*y**2*t**2 + 4*x*t + 4*y*t + 1 p = 1 + t*x + t*y + t**2*x*y p1 = rs_mul(p, p, t, 2) assert p1 == 1 + 2*t*x + 2*t*y R1, z = ring('z', QQ) raises(ValueError, lambda: rs_mul(p, z, x, 2)) p1 = 2 + 2*x + 3*x**2 p2 = 3 + x**2 assert rs_mul(p1, p2, x, 4) == 2*x**3 + 11*x**2 + 6*x + 6 def test_square_trunc(): R, x, y, t = ring('x, y, t', QQ) p = (1 + t*x + t*y)*2 p1 = rs_mul(p, p, x, 3) p2 = rs_square(p, x, 3) assert p1 == p2 p = 1 + x + x**2 + x**3 assert rs_square(p, x, 4) == 4*x**3 + 3*x**2 + 2*x + 1 def test_pow_trunc(): R, x, y, z = ring('x, y, z', QQ) p0 = y + x*z p = p0**16 for xx in (x, y, z): p1 = rs_trunc(p, xx, 8) p2 = rs_pow(p0, 16, xx, 8) assert p1 == p2 p = 1 + x p1 = rs_pow(p, 3, x, 2) assert p1 == 1 + 3*x assert rs_pow(p, 0, x, 2) == 1 assert rs_pow(p, -2, x, 2) == 1 - 2*x p = x + y assert rs_pow(p, 3, y, 3) == x**3 + 3*x**2*y + 3*x*y**2 assert rs_pow(1 + x, Rational(2, 3), x, 4) == 4*x**3/81 - x**2/9 + x*Rational(2, 3) + 1 def test_has_constant_term(): R, x, y, z = ring('x, y, z', QQ) p = y + x*z assert _has_constant_term(p, x) p = x + x**4 assert not _has_constant_term(p, x) p = 1 + x + x**4 assert _has_constant_term(p, x) p = x + y + x*z def test_inversion(): R, x = ring('x', QQ) p = 2 + x + 2*x**2 n = 5 p1 = rs_series_inversion(p, x, n) assert rs_trunc(p*p1, x, n) == 1 R, x, y = ring('x, y', QQ) p = 2 + x + 2*x**2 + y*x + x**2*y p1 = rs_series_inversion(p, x, n) assert rs_trunc(p*p1, x, n) == 1 R, x, y = ring('x, y', QQ) p = 1 + x + y raises(NotImplementedError, lambda: rs_series_inversion(p, x, 4)) p = R.zero raises(ZeroDivisionError, lambda: rs_series_inversion(p, x, 3)) def test_series_reversion(): R, x, y = ring('x, y', QQ) p = rs_tan(x, x, 10) assert rs_series_reversion(p, x, 8, y) == rs_atan(y, y, 8) p = rs_sin(x, x, 10) assert rs_series_reversion(p, x, 8, y) == 5*y**7/112 + 3*y**5/40 + \ y**3/6 + y def test_series_from_list(): R, x = ring('x', QQ) p = 1 + 2*x + x**2 + 3*x**3 c = [1, 2, 0, 4, 4] r = rs_series_from_list(p, c, x, 5) pc = R.from_list(list(reversed(c))) r1 = rs_trunc(pc.compose(x, p), x, 5) assert r == r1 R, x, y = ring('x, y', QQ) c = [1, 3, 5, 7] p1 = rs_series_from_list(x + y, c, x, 3, concur=0) p2 = rs_trunc((1 + 3*(x+y) + 5*(x+y)**2 + 7*(x+y)**3), x, 3) assert p1 == p2 R, x = ring('x', QQ) h = 25 p = rs_exp(x, x, h) - 1 p1 = rs_series_from_list(p, c, x, h) p2 = 0 for i, cx in enumerate(c): p2 += cx*rs_pow(p, i, x, h) assert p1 == p2 def test_log(): R, x = ring('x', QQ) p = 1 + x p1 = rs_log(p, x, 4)/x**2 assert p1 == Rational(1, 3)*x - S.Half + x**(-1) p = 1 + x +2*x**2/3 p1 = rs_log(p, x, 9) assert p1 == -17*x**8/648 + 13*x**7/189 - 11*x**6/162 - x**5/45 + \ 7*x**4/36 - x**3/3 + x**2/6 + x p2 = rs_series_inversion(p, x, 9) p3 = rs_log(p2, x, 9) assert p3 == -p1 R, x, y = ring('x, y', QQ) p = 1 + x + 2*y*x**2 p1 = rs_log(p, x, 6) assert p1 == (4*x**5*y**2 - 2*x**5*y - 2*x**4*y**2 + x**5/5 + 2*x**4*y - x**4/4 - 2*x**3*y + x**3/3 + 2*x**2*y - x**2/2 + x) # Constant term in series a = symbols('a') R, x, y = ring('x, y', EX) assert rs_log(x + a, x, 5) == -EX(1/(4*a**4))*x**4 + EX(1/(3*a**3))*x**3 \ - EX(1/(2*a**2))*x**2 + EX(1/a)*x + EX(log(a)) assert rs_log(x + x**2*y + a, x, 4) == -EX(a**(-2))*x**3*y + \ EX(1/(3*a**3))*x**3 + EX(1/a)*x**2*y - EX(1/(2*a**2))*x**2 + \ EX(1/a)*x + EX(log(a)) p = x + x**2 + 3 assert rs_log(p, x, 10).compose(x, 5) == EX(log(3) + Rational(19281291595, 9920232)) def test_exp(): R, x = ring('x', QQ) p = x + x**4 for h in [10, 30]: q = rs_series_inversion(1 + p, x, h) - 1 p1 = rs_exp(q, x, h) q1 = rs_log(p1, x, h) assert q1 == q p1 = rs_exp(p, x, 30) assert p1.coeff(x**29) == QQ(74274246775059676726972369, 353670479749588078181744640000) prec = 21 p = rs_log(1 + x, x, prec) p1 = rs_exp(p, x, prec) assert p1 == x + 1 # Constant term in series a = symbols('a') R, x, y = ring('x, y', QQ[exp(a), a]) assert rs_exp(x + a, x, 5) == exp(a)*x**4/24 + exp(a)*x**3/6 + \ exp(a)*x**2/2 + exp(a)*x + exp(a) assert rs_exp(x + x**2*y + a, x, 5) == exp(a)*x**4*y**2/2 + \ exp(a)*x**4*y/2 + exp(a)*x**4/24 + exp(a)*x**3*y + \ exp(a)*x**3/6 + exp(a)*x**2*y + exp(a)*x**2/2 + exp(a)*x + exp(a) R, x, y = ring('x, y', EX) assert rs_exp(x + a, x, 5) == EX(exp(a)/24)*x**4 + EX(exp(a)/6)*x**3 + \ EX(exp(a)/2)*x**2 + EX(exp(a))*x + EX(exp(a)) assert rs_exp(x + x**2*y + a, x, 5) == EX(exp(a)/2)*x**4*y**2 + \ EX(exp(a)/2)*x**4*y + EX(exp(a)/24)*x**4 + EX(exp(a))*x**3*y + \ EX(exp(a)/6)*x**3 + EX(exp(a))*x**2*y + EX(exp(a)/2)*x**2 + \ EX(exp(a))*x + EX(exp(a)) def test_newton(): R, x = ring('x', QQ) p = x**2 - 2 r = rs_newton(p, x, 4) assert r == 8*x**4 + 4*x**2 + 2 def test_compose_add(): R, x = ring('x', QQ) p1 = x**3 - 1 p2 = x**2 - 2 assert rs_compose_add(p1, p2) == x**6 - 6*x**4 - 2*x**3 + 12*x**2 - 12*x - 7 def test_fun(): R, x, y = ring('x, y', QQ) p = x*y + x**2*y**3 + x**5*y assert rs_fun(p, rs_tan, x, 10) == rs_tan(p, x, 10) assert rs_fun(p, _tan1, x, 10) == _tan1(p, x, 10) def test_nth_root(): R, x, y = ring('x, y', QQ) assert rs_nth_root(1 + x**2*y, 4, x, 10) == -77*x**8*y**4/2048 + \ 7*x**6*y**3/128 - 3*x**4*y**2/32 + x**2*y/4 + 1 assert rs_nth_root(1 + x*y + x**2*y**3, 3, x, 5) == -x**4*y**6/9 + \ 5*x**4*y**5/27 - 10*x**4*y**4/243 - 2*x**3*y**4/9 + 5*x**3*y**3/81 + \ x**2*y**3/3 - x**2*y**2/9 + x*y/3 + 1 assert rs_nth_root(8*x, 3, x, 3) == 2*x**QQ(1, 3) assert rs_nth_root(8*x + x**2 + x**3, 3, x, 3) == x**QQ(4,3)/12 + 2*x**QQ(1,3) r = rs_nth_root(8*x + x**2*y + x**3, 3, x, 4) assert r == -x**QQ(7,3)*y**2/288 + x**QQ(7,3)/12 + x**QQ(4,3)*y/12 + 2*x**QQ(1,3) # Constant term in series a = symbols('a') R, x, y = ring('x, y', EX) assert rs_nth_root(x + a, 3, x, 4) == EX(5/(81*a**QQ(8, 3)))*x**3 - \ EX(1/(9*a**QQ(5, 3)))*x**2 + EX(1/(3*a**QQ(2, 3)))*x + EX(a**QQ(1, 3)) assert rs_nth_root(x**QQ(2, 3) + x**2*y + 5, 2, x, 3) == -EX(sqrt(5)/100)*\ x**QQ(8, 3)*y - EX(sqrt(5)/16000)*x**QQ(8, 3) + EX(sqrt(5)/10)*x**2*y + \ EX(sqrt(5)/2000)*x**2 - EX(sqrt(5)/200)*x**QQ(4, 3) + \ EX(sqrt(5)/10)*x**QQ(2, 3) + EX(sqrt(5)) def test_atan(): R, x, y = ring('x, y', QQ) assert rs_atan(x, x, 9) == -x**7/7 + x**5/5 - x**3/3 + x assert rs_atan(x*y + x**2*y**3, x, 9) == 2*x**8*y**11 - x**8*y**9 + \ 2*x**7*y**9 - x**7*y**7/7 - x**6*y**9/3 + x**6*y**7 - x**5*y**7 + \ x**5*y**5/5 - x**4*y**5 - x**3*y**3/3 + x**2*y**3 + x*y # Constant term in series a = symbols('a') R, x, y = ring('x, y', EX) assert rs_atan(x + a, x, 5) == -EX((a**3 - a)/(a**8 + 4*a**6 + 6*a**4 + \ 4*a**2 + 1))*x**4 + EX((3*a**2 - 1)/(3*a**6 + 9*a**4 + \ 9*a**2 + 3))*x**3 - EX(a/(a**4 + 2*a**2 + 1))*x**2 + \ EX(1/(a**2 + 1))*x + EX(atan(a)) assert rs_atan(x + x**2*y + a, x, 4) == -EX(2*a/(a**4 + 2*a**2 + 1)) \ *x**3*y + EX((3*a**2 - 1)/(3*a**6 + 9*a**4 + 9*a**2 + 3))*x**3 + \ EX(1/(a**2 + 1))*x**2*y - EX(a/(a**4 + 2*a**2 + 1))*x**2 + EX(1/(a**2 \ + 1))*x + EX(atan(a)) def test_asin(): R, x, y = ring('x, y', QQ) assert rs_asin(x + x*y, x, 5) == x**3*y**3/6 + x**3*y**2/2 + x**3*y/2 + \ x**3/6 + x*y + x assert rs_asin(x*y + x**2*y**3, x, 6) == x**5*y**7/2 + 3*x**5*y**5/40 + \ x**4*y**5/2 + x**3*y**3/6 + x**2*y**3 + x*y def test_tan(): R, x, y = ring('x, y', QQ) assert rs_tan(x, x, 9)/x**5 == \ Rational(17, 315)*x**2 + Rational(2, 15) + Rational(1, 3)*x**(-2) + x**(-4) assert rs_tan(x*y + x**2*y**3, x, 9) == 4*x**8*y**11/3 + 17*x**8*y**9/45 + \ 4*x**7*y**9/3 + 17*x**7*y**7/315 + x**6*y**9/3 + 2*x**6*y**7/3 + \ x**5*y**7 + 2*x**5*y**5/15 + x**4*y**5 + x**3*y**3/3 + x**2*y**3 + x*y # Constant term in series a = symbols('a') R, x, y = ring('x, y', QQ[tan(a), a]) assert rs_tan(x + a, x, 5) == (tan(a)**5 + 5*tan(a)**3/3 + 2*tan(a)/3)*x**4 + (tan(a)**4 + 4*tan(a)**2/3 + Rational(1, 3))*x**3 + \ (tan(a)**3 + tan(a))*x**2 + (tan(a)**2 + 1)*x + tan(a) assert rs_tan(x + x**2*y + a, x, 4) == (2*tan(a)**3 + 2*tan(a))*x**3*y + \ (tan(a)**4 + Rational(4, 3)*tan(a)**2 + Rational(1, 3))*x**3 + (tan(a)**2 + 1)*x**2*y + \ (tan(a)**3 + tan(a))*x**2 + (tan(a)**2 + 1)*x + tan(a) R, x, y = ring('x, y', EX) assert rs_tan(x + a, x, 5) == EX(tan(a)**5 + 5*tan(a)**3/3 + 2*tan(a)/3)*x**4 + EX(tan(a)**4 + 4*tan(a)**2/3 + EX(1)/3)*x**3 + \ EX(tan(a)**3 + tan(a))*x**2 + EX(tan(a)**2 + 1)*x + EX(tan(a)) assert rs_tan(x + x**2*y + a, x, 4) == EX(2*tan(a)**3 + 2*tan(a))*x**3*y + EX(tan(a)**4 + 4*tan(a)**2/3 + EX(1)/3)*x**3 + \ EX(tan(a)**2 + 1)*x**2*y + EX(tan(a)**3 + tan(a))*x**2 + \ EX(tan(a)**2 + 1)*x + EX(tan(a)) p = x + x**2 + 5 assert rs_atan(p, x, 10).compose(x, 10) == EX(atan(5) + S(67701870330562640) / \ 668083460499) def test_cot(): R, x, y = ring('x, y', QQ) assert rs_cot(x**6 + x**7, x, 8) == x**(-6) - x**(-5) + x**(-4) - \ x**(-3) + x**(-2) - x**(-1) + 1 - x + x**2 - x**3 + x**4 - x**5 + \ 2*x**6/3 - 4*x**7/3 assert rs_cot(x + x**2*y, x, 5) == -x**4*y**5 - x**4*y/15 + x**3*y**4 - \ x**3/45 - x**2*y**3 - x**2*y/3 + x*y**2 - x/3 - y + x**(-1) def test_sin(): R, x, y = ring('x, y', QQ) assert rs_sin(x, x, 9)/x**5 == \ Rational(-1, 5040)*x**2 + Rational(1, 120) - Rational(1, 6)*x**(-2) + x**(-4) assert rs_sin(x*y + x**2*y**3, x, 9) == x**8*y**11/12 - \ x**8*y**9/720 + x**7*y**9/12 - x**7*y**7/5040 - x**6*y**9/6 + \ x**6*y**7/24 - x**5*y**7/2 + x**5*y**5/120 - x**4*y**5/2 - \ x**3*y**3/6 + x**2*y**3 + x*y # Constant term in series a = symbols('a') R, x, y = ring('x, y', QQ[sin(a), cos(a), a]) assert rs_sin(x + a, x, 5) == sin(a)*x**4/24 - cos(a)*x**3/6 - \ sin(a)*x**2/2 + cos(a)*x + sin(a) assert rs_sin(x + x**2*y + a, x, 5) == -sin(a)*x**4*y**2/2 - \ cos(a)*x**4*y/2 + sin(a)*x**4/24 - sin(a)*x**3*y - cos(a)*x**3/6 + \ cos(a)*x**2*y - sin(a)*x**2/2 + cos(a)*x + sin(a) R, x, y = ring('x, y', EX) assert rs_sin(x + a, x, 5) == EX(sin(a)/24)*x**4 - EX(cos(a)/6)*x**3 - \ EX(sin(a)/2)*x**2 + EX(cos(a))*x + EX(sin(a)) assert rs_sin(x + x**2*y + a, x, 5) == -EX(sin(a)/2)*x**4*y**2 - \ EX(cos(a)/2)*x**4*y + EX(sin(a)/24)*x**4 - EX(sin(a))*x**3*y - \ EX(cos(a)/6)*x**3 + EX(cos(a))*x**2*y - EX(sin(a)/2)*x**2 + \ EX(cos(a))*x + EX(sin(a)) def test_cos(): R, x, y = ring('x, y', QQ) assert rs_cos(x, x, 9)/x**5 == \ Rational(1, 40320)*x**3 - Rational(1, 720)*x + Rational(1, 24)*x**(-1) - S.Half*x**(-3) + x**(-5) assert rs_cos(x*y + x**2*y**3, x, 9) == x**8*y**12/24 - \ x**8*y**10/48 + x**8*y**8/40320 + x**7*y**10/6 - \ x**7*y**8/120 + x**6*y**8/4 - x**6*y**6/720 + x**5*y**6/6 - \ x**4*y**6/2 + x**4*y**4/24 - x**3*y**4 - x**2*y**2/2 + 1 # Constant term in series a = symbols('a') R, x, y = ring('x, y', QQ[sin(a), cos(a), a]) assert rs_cos(x + a, x, 5) == cos(a)*x**4/24 + sin(a)*x**3/6 - \ cos(a)*x**2/2 - sin(a)*x + cos(a) assert rs_cos(x + x**2*y + a, x, 5) == -cos(a)*x**4*y**2/2 + \ sin(a)*x**4*y/2 + cos(a)*x**4/24 - cos(a)*x**3*y + sin(a)*x**3/6 - \ sin(a)*x**2*y - cos(a)*x**2/2 - sin(a)*x + cos(a) R, x, y = ring('x, y', EX) assert rs_cos(x + a, x, 5) == EX(cos(a)/24)*x**4 + EX(sin(a)/6)*x**3 - \ EX(cos(a)/2)*x**2 - EX(sin(a))*x + EX(cos(a)) assert rs_cos(x + x**2*y + a, x, 5) == -EX(cos(a)/2)*x**4*y**2 + \ EX(sin(a)/2)*x**4*y + EX(cos(a)/24)*x**4 - EX(cos(a))*x**3*y + \ EX(sin(a)/6)*x**3 - EX(sin(a))*x**2*y - EX(cos(a)/2)*x**2 - \ EX(sin(a))*x + EX(cos(a)) def test_cos_sin(): R, x, y = ring('x, y', QQ) cos, sin = rs_cos_sin(x, x, 9) assert cos == rs_cos(x, x, 9) assert sin == rs_sin(x, x, 9) cos, sin = rs_cos_sin(x + x*y, x, 5) assert cos == rs_cos(x + x*y, x, 5) assert sin == rs_sin(x + x*y, x, 5) def test_atanh(): R, x, y = ring('x, y', QQ) assert rs_atanh(x, x, 9)/x**5 == Rational(1, 7)*x**2 + Rational(1, 5) + Rational(1, 3)*x**(-2) + x**(-4) assert rs_atanh(x*y + x**2*y**3, x, 9) == 2*x**8*y**11 + x**8*y**9 + \ 2*x**7*y**9 + x**7*y**7/7 + x**6*y**9/3 + x**6*y**7 + x**5*y**7 + \ x**5*y**5/5 + x**4*y**5 + x**3*y**3/3 + x**2*y**3 + x*y # Constant term in series a = symbols('a') R, x, y = ring('x, y', EX) assert rs_atanh(x + a, x, 5) == EX((a**3 + a)/(a**8 - 4*a**6 + 6*a**4 - \ 4*a**2 + 1))*x**4 - EX((3*a**2 + 1)/(3*a**6 - 9*a**4 + \ 9*a**2 - 3))*x**3 + EX(a/(a**4 - 2*a**2 + 1))*x**2 - EX(1/(a**2 - \ 1))*x + EX(atanh(a)) assert rs_atanh(x + x**2*y + a, x, 4) == EX(2*a/(a**4 - 2*a**2 + \ 1))*x**3*y - EX((3*a**2 + 1)/(3*a**6 - 9*a**4 + 9*a**2 - 3))*x**3 - \ EX(1/(a**2 - 1))*x**2*y + EX(a/(a**4 - 2*a**2 + 1))*x**2 - \ EX(1/(a**2 - 1))*x + EX(atanh(a)) p = x + x**2 + 5 assert rs_atanh(p, x, 10).compose(x, 10) == EX(Rational(-733442653682135, 5079158784) \ + atanh(5)) def test_sinh(): R, x, y = ring('x, y', QQ) assert rs_sinh(x, x, 9)/x**5 == Rational(1, 5040)*x**2 + Rational(1, 120) + Rational(1, 6)*x**(-2) + x**(-4) assert rs_sinh(x*y + x**2*y**3, x, 9) == x**8*y**11/12 + \ x**8*y**9/720 + x**7*y**9/12 + x**7*y**7/5040 + x**6*y**9/6 + \ x**6*y**7/24 + x**5*y**7/2 + x**5*y**5/120 + x**4*y**5/2 + \ x**3*y**3/6 + x**2*y**3 + x*y def test_cosh(): R, x, y = ring('x, y', QQ) assert rs_cosh(x, x, 9)/x**5 == Rational(1, 40320)*x**3 + Rational(1, 720)*x + Rational(1, 24)*x**(-1) + \ S.Half*x**(-3) + x**(-5) assert rs_cosh(x*y + x**2*y**3, x, 9) == x**8*y**12/24 + \ x**8*y**10/48 + x**8*y**8/40320 + x**7*y**10/6 + \ x**7*y**8/120 + x**6*y**8/4 + x**6*y**6/720 + x**5*y**6/6 + \ x**4*y**6/2 + x**4*y**4/24 + x**3*y**4 + x**2*y**2/2 + 1 def test_tanh(): R, x, y = ring('x, y', QQ) assert rs_tanh(x, x, 9)/x**5 == Rational(-17, 315)*x**2 + Rational(2, 15) - Rational(1, 3)*x**(-2) + x**(-4) assert rs_tanh(x*y + x**2*y**3, x, 9) == 4*x**8*y**11/3 - \ 17*x**8*y**9/45 + 4*x**7*y**9/3 - 17*x**7*y**7/315 - x**6*y**9/3 + \ 2*x**6*y**7/3 - x**5*y**7 + 2*x**5*y**5/15 - x**4*y**5 - \ x**3*y**3/3 + x**2*y**3 + x*y # Constant term in series a = symbols('a') R, x, y = ring('x, y', EX) assert rs_tanh(x + a, x, 5) == EX(tanh(a)**5 - 5*tanh(a)**3/3 + 2*tanh(a)/3)*x**4 + EX(-tanh(a)**4 + 4*tanh(a)**2/3 - QQ(1, 3))*x**3 + \ EX(tanh(a)**3 - tanh(a))*x**2 + EX(-tanh(a)**2 + 1)*x + EX(tanh(a)) p = rs_tanh(x + x**2*y + a, x, 4) assert (p.compose(x, 10)).compose(y, 5) == EX(-1000*tanh(a)**4 + \ 10100*tanh(a)**3 + 2470*tanh(a)**2/3 - 10099*tanh(a) + QQ(530, 3)) def test_RR(): rs_funcs = [rs_sin, rs_cos, rs_tan, rs_cot, rs_atan, rs_tanh] sympy_funcs = [sin, cos, tan, cot, atan, tanh] R, x, y = ring('x, y', RR) a = symbols('a') for rs_func, sympy_func in zip(rs_funcs, sympy_funcs): p = rs_func(2 + x, x, 5).compose(x, 5) q = sympy_func(2 + a).series(a, 0, 5).removeO() is_close(p.as_expr(), q.subs(a, 5).n()) p = rs_nth_root(2 + x, 5, x, 5).compose(x, 5) q = ((2 + a)**QQ(1, 5)).series(a, 0, 5).removeO() is_close(p.as_expr(), q.subs(a, 5).n()) def test_is_regular(): R, x, y = ring('x, y', QQ) p = 1 + 2*x + x**2 + 3*x**3 assert not rs_is_puiseux(p, x) p = x + x**QQ(1,5)*y assert rs_is_puiseux(p, x) assert not rs_is_puiseux(p, y) p = x + x**2*y**QQ(1,5)*y assert not rs_is_puiseux(p, x) def test_puiseux(): R, x, y = ring('x, y', QQ) p = x**QQ(2,5) + x**QQ(2,3) + x r = rs_series_inversion(p, x, 1) r1 = -x**QQ(14,15) + x**QQ(4,5) - 3*x**QQ(11,15) + x**QQ(2,3) + \ 2*x**QQ(7,15) - x**QQ(2,5) - x**QQ(1,5) + x**QQ(2,15) - x**QQ(-2,15) \ + x**QQ(-2,5) assert r == r1 r = rs_nth_root(1 + p, 3, x, 1) assert r == -x**QQ(4,5)/9 + x**QQ(2,3)/3 + x**QQ(2,5)/3 + 1 r = rs_log(1 + p, x, 1) assert r == -x**QQ(4,5)/2 + x**QQ(2,3) + x**QQ(2,5) r = rs_LambertW(p, x, 1) assert r == -x**QQ(4,5) + x**QQ(2,3) + x**QQ(2,5) p1 = x + x**QQ(1,5)*y r = rs_exp(p1, x, 1) assert r == x**QQ(4,5)*y**4/24 + x**QQ(3,5)*y**3/6 + x**QQ(2,5)*y**2/2 + \ x**QQ(1,5)*y + 1 r = rs_atan(p, x, 2) assert r == -x**QQ(9,5) - x**QQ(26,15) - x**QQ(22,15) - x**QQ(6,5)/3 + \ x + x**QQ(2,3) + x**QQ(2,5) r = rs_atan(p1, x, 2) assert r == x**QQ(9,5)*y**9/9 + x**QQ(9,5)*y**4 - x**QQ(7,5)*y**7/7 - \ x**QQ(7,5)*y**2 + x*y**5/5 + x - x**QQ(3,5)*y**3/3 + x**QQ(1,5)*y r = rs_asin(p, x, 2) assert r == x**QQ(9,5)/2 + x**QQ(26,15)/2 + x**QQ(22,15)/2 + \ x**QQ(6,5)/6 + x + x**QQ(2,3) + x**QQ(2,5) r = rs_cot(p, x, 1) assert r == -x**QQ(14,15) + x**QQ(4,5) - 3*x**QQ(11,15) + \ 2*x**QQ(2,3)/3 + 2*x**QQ(7,15) - 4*x**QQ(2,5)/3 - x**QQ(1,5) + \ x**QQ(2,15) - x**QQ(-2,15) + x**QQ(-2,5) r = rs_cos_sin(p, x, 2) assert r[0] == x**QQ(28,15)/6 - x**QQ(5,3) + x**QQ(8,5)/24 - x**QQ(7,5) - \ x**QQ(4,3)/2 - x**QQ(16,15) - x**QQ(4,5)/2 + 1 assert r[1] == -x**QQ(9,5)/2 - x**QQ(26,15)/2 - x**QQ(22,15)/2 - \ x**QQ(6,5)/6 + x + x**QQ(2,3) + x**QQ(2,5) r = rs_atanh(p, x, 2) assert r == x**QQ(9,5) + x**QQ(26,15) + x**QQ(22,15) + x**QQ(6,5)/3 + x + \ x**QQ(2,3) + x**QQ(2,5) r = rs_sinh(p, x, 2) assert r == x**QQ(9,5)/2 + x**QQ(26,15)/2 + x**QQ(22,15)/2 + \ x**QQ(6,5)/6 + x + x**QQ(2,3) + x**QQ(2,5) r = rs_cosh(p, x, 2) assert r == x**QQ(28,15)/6 + x**QQ(5,3) + x**QQ(8,5)/24 + x**QQ(7,5) + \ x**QQ(4,3)/2 + x**QQ(16,15) + x**QQ(4,5)/2 + 1 r = rs_tanh(p, x, 2) assert r == -x**QQ(9,5) - x**QQ(26,15) - x**QQ(22,15) - x**QQ(6,5)/3 + \ x + x**QQ(2,3) + x**QQ(2,5) def test1(): R, x = ring('x', QQ) r = rs_sin(x, x, 15)*x**(-5) assert r == x**8/6227020800 - x**6/39916800 + x**4/362880 - x**2/5040 + \ QQ(1,120) - x**-2/6 + x**-4 p = rs_sin(x, x, 10) r = rs_nth_root(p, 2, x, 10) assert r == -67*x**QQ(17,2)/29030400 - x**QQ(13,2)/24192 + \ x**QQ(9,2)/1440 - x**QQ(5,2)/12 + x**QQ(1,2) p = rs_sin(x, x, 10) r = rs_nth_root(p, 7, x, 10) r = rs_pow(r, 5, x, 10) assert r == -97*x**QQ(61,7)/124467840 - x**QQ(47,7)/16464 + \ 11*x**QQ(33,7)/3528 - 5*x**QQ(19,7)/42 + x**QQ(5,7) r = rs_exp(x**QQ(1,2), x, 10) assert r == x**QQ(19,2)/121645100408832000 + x**9/6402373705728000 + \ x**QQ(17,2)/355687428096000 + x**8/20922789888000 + \ x**QQ(15,2)/1307674368000 + x**7/87178291200 + \ x**QQ(13,2)/6227020800 + x**6/479001600 + x**QQ(11,2)/39916800 + \ x**5/3628800 + x**QQ(9,2)/362880 + x**4/40320 + x**QQ(7,2)/5040 + \ x**3/720 + x**QQ(5,2)/120 + x**2/24 + x**QQ(3,2)/6 + x/2 + \ x**QQ(1,2) + 1 def test_puiseux2(): R, y = ring('y', QQ) S, x = ring('x', R) p = x + x**QQ(1,5)*y r = rs_atan(p, x, 3) assert r == (y**13/13 + y**8 + 2*y**3)*x**QQ(13,5) - (y**11/11 + y**6 + y)*x**QQ(11,5) + (y**9/9 + y**4)*x**QQ(9,5) - (y**7/7 + y**2)*x**QQ(7,5) + (y**5/5 + 1)*x - y**3*x**QQ(3,5)/3 + y*x**QQ(1,5) def test_rs_series(): x, a, b, c = symbols('x, a, b, c') assert rs_series(a, a, 5).as_expr() == a assert rs_series(sin(a), a, 5).as_expr() == (sin(a).series(a, 0, 5)).removeO() assert rs_series(sin(a) + cos(a), a, 5).as_expr() == ((sin(a) + cos(a)).series(a, 0, 5)).removeO() assert rs_series(sin(a)*cos(a), a, 5).as_expr() == ((sin(a)* cos(a)).series(a, 0, 5)).removeO() p = (sin(a) - a)*(cos(a**2) + a**4/2) assert expand(rs_series(p, a, 10).as_expr()) == expand(p.series(a, 0, 10).removeO()) p = sin(a**2/2 + a/3) + cos(a/5)*sin(a/2)**3 assert expand(rs_series(p, a, 5).as_expr()) == expand(p.series(a, 0, 5).removeO()) p = sin(x**2 + a)*(cos(x**3 - 1) - a - a**2) assert expand(rs_series(p, a, 5).as_expr()) == expand(p.series(a, 0, 5).removeO()) p = sin(a**2 - a/3 + 2)**5*exp(a**3 - a/2) assert expand(rs_series(p, a, 10).as_expr()) == expand(p.series(a, 0, 10).removeO()) p = sin(a + b + c) assert expand(rs_series(p, a, 5).as_expr()) == expand(p.series(a, 0, 5).removeO()) p = tan(sin(a**2 + 4) + b + c) assert expand(rs_series(p, a, 6).as_expr()) == expand(p.series(a, 0, 6).removeO()) p = a**QQ(2,5) + a**QQ(2,3) + a r = rs_series(tan(p), a, 2) assert r.as_expr() == a**QQ(9,5) + a**QQ(26,15) + a**QQ(22,15) + a**QQ(6,5)/3 + \ a + a**QQ(2,3) + a**QQ(2,5) r = rs_series(exp(p), a, 1) assert r.as_expr() == a**QQ(4,5)/2 + a**QQ(2,3) + a**QQ(2,5) + 1 r = rs_series(sin(p), a, 2) assert r.as_expr() == -a**QQ(9,5)/2 - a**QQ(26,15)/2 - a**QQ(22,15)/2 - \ a**QQ(6,5)/6 + a + a**QQ(2,3) + a**QQ(2,5) r = rs_series(cos(p), a, 2) assert r.as_expr() == a**QQ(28,15)/6 - a**QQ(5,3) + a**QQ(8,5)/24 - a**QQ(7,5) - \ a**QQ(4,3)/2 - a**QQ(16,15) - a**QQ(4,5)/2 + 1 assert rs_series(sin(a)/7, a, 5).as_expr() == (sin(a)/7).series(a, 0, 5).removeO() assert rs_series(log(1 + x), x, 5).as_expr() == -x**4/4 + x**3/3 - \ x**2/2 + x assert rs_series(log(1 + 4*x), x, 5).as_expr() == -64*x**4 + 64*x**3/3 - \ 8*x**2 + 4*x assert rs_series(log(1 + x + x**2), x, 10).as_expr() == -2*x**9/9 + \ x**8/8 + x**7/7 - x**6/3 + x**5/5 + x**4/4 - 2*x**3/3 + \ x**2/2 + x assert rs_series(log(1 + x*a**2), x, 7).as_expr() == -x**6*a**12/6 + \ x**5*a**10/5 - x**4*a**8/4 + x**3*a**6/3 - \ x**2*a**4/2 + x*a**2 sympy-sympy-1.9/sympy/polys/tests/test_rings.py000066400000000000000000001242561412543434000221610ustar00rootroot00000000000000"""Test sparse polynomials. """ from functools import reduce from operator import add, mul from sympy.polys.rings import ring, xring, sring, PolyRing, PolyElement from sympy.polys.fields import field, FracField from sympy.polys.domains import ZZ, QQ, RR, FF, EX from sympy.polys.orderings import lex, grlex from sympy.polys.polyerrors import GeneratorsError, \ ExactQuotientFailed, MultivariatePolynomialError, CoercionFailed from sympy.testing.pytest import raises from sympy.core import Symbol, symbols from sympy import sqrt, pi, oo, exp def test_PolyRing___init__(): x, y, z, t = map(Symbol, "xyzt") assert len(PolyRing("x,y,z", ZZ, lex).gens) == 3 assert len(PolyRing(x, ZZ, lex).gens) == 1 assert len(PolyRing(("x", "y", "z"), ZZ, lex).gens) == 3 assert len(PolyRing((x, y, z), ZZ, lex).gens) == 3 assert len(PolyRing("", ZZ, lex).gens) == 0 assert len(PolyRing([], ZZ, lex).gens) == 0 raises(GeneratorsError, lambda: PolyRing(0, ZZ, lex)) assert PolyRing("x", ZZ[t], lex).domain == ZZ[t] assert PolyRing("x", 'ZZ[t]', lex).domain == ZZ[t] assert PolyRing("x", PolyRing("t", ZZ, lex), lex).domain == ZZ[t] raises(GeneratorsError, lambda: PolyRing("x", PolyRing("x", ZZ, lex), lex)) _lex = Symbol("lex") assert PolyRing("x", ZZ, lex).order == lex assert PolyRing("x", ZZ, _lex).order == lex assert PolyRing("x", ZZ, 'lex').order == lex R1 = PolyRing("x,y", ZZ, lex) R2 = PolyRing("x,y", ZZ, lex) R3 = PolyRing("x,y,z", ZZ, lex) assert R1.x == R1.gens[0] assert R1.y == R1.gens[1] assert R1.x == R2.x assert R1.y == R2.y assert R1.x != R3.x assert R1.y != R3.y def test_PolyRing___hash__(): R, x, y, z = ring("x,y,z", QQ) assert hash(R) def test_PolyRing___eq__(): assert ring("x,y,z", QQ)[0] == ring("x,y,z", QQ)[0] assert ring("x,y,z", QQ)[0] is ring("x,y,z", QQ)[0] assert ring("x,y,z", QQ)[0] != ring("x,y,z", ZZ)[0] assert ring("x,y,z", QQ)[0] is not ring("x,y,z", ZZ)[0] assert ring("x,y,z", ZZ)[0] != ring("x,y,z", QQ)[0] assert ring("x,y,z", ZZ)[0] is not ring("x,y,z", QQ)[0] assert ring("x,y,z", QQ)[0] != ring("x,y", QQ)[0] assert ring("x,y,z", QQ)[0] is not ring("x,y", QQ)[0] assert ring("x,y", QQ)[0] != ring("x,y,z", QQ)[0] assert ring("x,y", QQ)[0] is not ring("x,y,z", QQ)[0] def test_PolyRing_ring_new(): R, x, y, z = ring("x,y,z", QQ) assert R.ring_new(7) == R(7) assert R.ring_new(7*x*y*z) == 7*x*y*z f = x**2 + 2*x*y + 3*x + 4*z**2 + 5*z + 6 assert R.ring_new([[[1]], [[2], [3]], [[4, 5, 6]]]) == f assert R.ring_new({(2, 0, 0): 1, (1, 1, 0): 2, (1, 0, 0): 3, (0, 0, 2): 4, (0, 0, 1): 5, (0, 0, 0): 6}) == f assert R.ring_new([((2, 0, 0), 1), ((1, 1, 0), 2), ((1, 0, 0), 3), ((0, 0, 2), 4), ((0, 0, 1), 5), ((0, 0, 0), 6)]) == f R, = ring("", QQ) assert R.ring_new([((), 7)]) == R(7) def test_PolyRing_drop(): R, x,y,z = ring("x,y,z", ZZ) assert R.drop(x) == PolyRing("y,z", ZZ, lex) assert R.drop(y) == PolyRing("x,z", ZZ, lex) assert R.drop(z) == PolyRing("x,y", ZZ, lex) assert R.drop(0) == PolyRing("y,z", ZZ, lex) assert R.drop(0).drop(0) == PolyRing("z", ZZ, lex) assert R.drop(0).drop(0).drop(0) == ZZ assert R.drop(1) == PolyRing("x,z", ZZ, lex) assert R.drop(2) == PolyRing("x,y", ZZ, lex) assert R.drop(2).drop(1) == PolyRing("x", ZZ, lex) assert R.drop(2).drop(1).drop(0) == ZZ raises(ValueError, lambda: R.drop(3)) raises(ValueError, lambda: R.drop(x).drop(y)) def test_PolyRing___getitem__(): R, x,y,z = ring("x,y,z", ZZ) assert R[0:] == PolyRing("x,y,z", ZZ, lex) assert R[1:] == PolyRing("y,z", ZZ, lex) assert R[2:] == PolyRing("z", ZZ, lex) assert R[3:] == ZZ def test_PolyRing_is_(): R = PolyRing("x", QQ, lex) assert R.is_univariate is True assert R.is_multivariate is False R = PolyRing("x,y,z", QQ, lex) assert R.is_univariate is False assert R.is_multivariate is True R = PolyRing("", QQ, lex) assert R.is_univariate is False assert R.is_multivariate is False def test_PolyRing_add(): R, x = ring("x", ZZ) F = [ x**2 + 2*i + 3 for i in range(4) ] assert R.add(F) == reduce(add, F) == 4*x**2 + 24 R, = ring("", ZZ) assert R.add([2, 5, 7]) == 14 def test_PolyRing_mul(): R, x = ring("x", ZZ) F = [ x**2 + 2*i + 3 for i in range(4) ] assert R.mul(F) == reduce(mul, F) == x**8 + 24*x**6 + 206*x**4 + 744*x**2 + 945 R, = ring("", ZZ) assert R.mul([2, 3, 5]) == 30 def test_sring(): x, y, z, t = symbols("x,y,z,t") R = PolyRing("x,y,z", ZZ, lex) assert sring(x + 2*y + 3*z) == (R, R.x + 2*R.y + 3*R.z) R = PolyRing("x,y,z", QQ, lex) assert sring(x + 2*y + z/3) == (R, R.x + 2*R.y + R.z/3) assert sring([x, 2*y, z/3]) == (R, [R.x, 2*R.y, R.z/3]) Rt = PolyRing("t", ZZ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + 2*t*y + 3*t**2*z, x, y, z) == (R, R.x + 2*Rt.t*R.y + 3*Rt.t**2*R.z) Rt = PolyRing("t", QQ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + t*y/2 + t**2*z/3, x, y, z) == (R, R.x + Rt.t*R.y/2 + Rt.t**2*R.z/3) Rt = FracField("t", ZZ, lex) R = PolyRing("x,y,z", Rt, lex) assert sring(x + 2*y/t + t**2*z/3, x, y, z) == (R, R.x + 2*R.y/Rt.t + Rt.t**2*R.z/3) r = sqrt(2) - sqrt(3) R, a = sring(r, extension=True) assert R.domain == QQ.algebraic_field(sqrt(2) + sqrt(3)) assert R.gens == () assert a == R.domain.from_sympy(r) def test_PolyElement___hash__(): R, x, y, z = ring("x,y,z", QQ) assert hash(x*y*z) def test_PolyElement___eq__(): R, x, y = ring("x,y", ZZ, lex) assert ((x*y + 5*x*y) == 6) == False assert ((x*y + 5*x*y) == 6*x*y) == True assert (6 == (x*y + 5*x*y)) == False assert (6*x*y == (x*y + 5*x*y)) == True assert ((x*y - x*y) == 0) == True assert (0 == (x*y - x*y)) == True assert ((x*y - x*y) == 1) == False assert (1 == (x*y - x*y)) == False assert ((x*y - x*y) == 1) == False assert (1 == (x*y - x*y)) == False assert ((x*y + 5*x*y) != 6) == True assert ((x*y + 5*x*y) != 6*x*y) == False assert (6 != (x*y + 5*x*y)) == True assert (6*x*y != (x*y + 5*x*y)) == False assert ((x*y - x*y) != 0) == False assert (0 != (x*y - x*y)) == False assert ((x*y - x*y) != 1) == True assert (1 != (x*y - x*y)) == True assert R.one == QQ(1, 1) == R.one assert R.one == 1 == R.one Rt, t = ring("t", ZZ) R, x, y = ring("x,y", Rt) assert (t**3*x/x == t**3) == True assert (t**3*x/x == t**4) == False def test_PolyElement__lt_le_gt_ge__(): R, x, y = ring("x,y", ZZ) assert R(1) < x < x**2 < x**3 assert R(1) <= x <= x**2 <= x**3 assert x**3 > x**2 > x > R(1) assert x**3 >= x**2 >= x >= R(1) def test_PolyElement_copy(): R, x, y, z = ring("x,y,z", ZZ) f = x*y + 3*z g = f.copy() assert f == g g[(1, 1, 1)] = 7 assert f != g def test_PolyElement_as_expr(): R, x, y, z = ring("x,y,z", ZZ) f = 3*x**2*y - x*y*z + 7*z**3 + 1 X, Y, Z = R.symbols g = 3*X**2*Y - X*Y*Z + 7*Z**3 + 1 assert f != g assert f.as_expr() == g X, Y, Z = symbols("x,y,z") g = 3*X**2*Y - X*Y*Z + 7*Z**3 + 1 assert f != g assert f.as_expr(X, Y, Z) == g raises(ValueError, lambda: f.as_expr(X)) R, = ring("", ZZ) R(3).as_expr() == 3 def test_PolyElement_from_expr(): x, y, z = symbols("x,y,z") R, X, Y, Z = ring((x, y, z), ZZ) f = R.from_expr(1) assert f == 1 and isinstance(f, R.dtype) f = R.from_expr(x) assert f == X and isinstance(f, R.dtype) f = R.from_expr(x*y*z) assert f == X*Y*Z and isinstance(f, R.dtype) f = R.from_expr(x*y*z + x*y + x) assert f == X*Y*Z + X*Y + X and isinstance(f, R.dtype) f = R.from_expr(x**3*y*z + x**2*y**7 + 1) assert f == X**3*Y*Z + X**2*Y**7 + 1 and isinstance(f, R.dtype) r, F = sring([exp(2)]) f = r.from_expr(exp(2)) assert f == F[0] and isinstance(f, r.dtype) raises(ValueError, lambda: R.from_expr(1/x)) raises(ValueError, lambda: R.from_expr(2**x)) raises(ValueError, lambda: R.from_expr(7*x + sqrt(2))) R, = ring("", ZZ) f = R.from_expr(1) assert f == 1 and isinstance(f, R.dtype) def test_PolyElement_degree(): R, x,y,z = ring("x,y,z", ZZ) assert R(0).degree() is -oo assert R(1).degree() == 0 assert (x + 1).degree() == 1 assert (2*y**3 + z).degree() == 0 assert (x*y**3 + z).degree() == 1 assert (x**5*y**3 + z).degree() == 5 assert R(0).degree(x) is -oo assert R(1).degree(x) == 0 assert (x + 1).degree(x) == 1 assert (2*y**3 + z).degree(x) == 0 assert (x*y**3 + z).degree(x) == 1 assert (7*x**5*y**3 + z).degree(x) == 5 assert R(0).degree(y) is -oo assert R(1).degree(y) == 0 assert (x + 1).degree(y) == 0 assert (2*y**3 + z).degree(y) == 3 assert (x*y**3 + z).degree(y) == 3 assert (7*x**5*y**3 + z).degree(y) == 3 assert R(0).degree(z) is -oo assert R(1).degree(z) == 0 assert (x + 1).degree(z) == 0 assert (2*y**3 + z).degree(z) == 1 assert (x*y**3 + z).degree(z) == 1 assert (7*x**5*y**3 + z).degree(z) == 1 R, = ring("", ZZ) assert R(0).degree() is -oo assert R(1).degree() == 0 def test_PolyElement_tail_degree(): R, x,y,z = ring("x,y,z", ZZ) assert R(0).tail_degree() is -oo assert R(1).tail_degree() == 0 assert (x + 1).tail_degree() == 0 assert (2*y**3 + x**3*z).tail_degree() == 0 assert (x*y**3 + x**3*z).tail_degree() == 1 assert (x**5*y**3 + x**3*z).tail_degree() == 3 assert R(0).tail_degree(x) is -oo assert R(1).tail_degree(x) == 0 assert (x + 1).tail_degree(x) == 0 assert (2*y**3 + x**3*z).tail_degree(x) == 0 assert (x*y**3 + x**3*z).tail_degree(x) == 1 assert (7*x**5*y**3 + x**3*z).tail_degree(x) == 3 assert R(0).tail_degree(y) is -oo assert R(1).tail_degree(y) == 0 assert (x + 1).tail_degree(y) == 0 assert (2*y**3 + x**3*z).tail_degree(y) == 0 assert (x*y**3 + x**3*z).tail_degree(y) == 0 assert (7*x**5*y**3 + x**3*z).tail_degree(y) == 0 assert R(0).tail_degree(z) is -oo assert R(1).tail_degree(z) == 0 assert (x + 1).tail_degree(z) == 0 assert (2*y**3 + x**3*z).tail_degree(z) == 0 assert (x*y**3 + x**3*z).tail_degree(z) == 0 assert (7*x**5*y**3 + x**3*z).tail_degree(z) == 0 R, = ring("", ZZ) assert R(0).tail_degree() is -oo assert R(1).tail_degree() == 0 def test_PolyElement_degrees(): R, x,y,z = ring("x,y,z", ZZ) assert R(0).degrees() == (-oo, -oo, -oo) assert R(1).degrees() == (0, 0, 0) assert (x**2*y + x**3*z**2).degrees() == (3, 1, 2) def test_PolyElement_tail_degrees(): R, x,y,z = ring("x,y,z", ZZ) assert R(0).tail_degrees() == (-oo, -oo, -oo) assert R(1).tail_degrees() == (0, 0, 0) assert (x**2*y + x**3*z**2).tail_degrees() == (2, 0, 0) def test_PolyElement_coeff(): R, x, y, z = ring("x,y,z", ZZ, lex) f = 3*x**2*y - x*y*z + 7*z**3 + 23 assert f.coeff(1) == 23 raises(ValueError, lambda: f.coeff(3)) assert f.coeff(x) == 0 assert f.coeff(y) == 0 assert f.coeff(z) == 0 assert f.coeff(x**2*y) == 3 assert f.coeff(x*y*z) == -1 assert f.coeff(z**3) == 7 raises(ValueError, lambda: f.coeff(3*x**2*y)) raises(ValueError, lambda: f.coeff(-x*y*z)) raises(ValueError, lambda: f.coeff(7*z**3)) R, = ring("", ZZ) R(3).coeff(1) == 3 def test_PolyElement_LC(): R, x, y = ring("x,y", QQ, lex) assert R(0).LC == QQ(0) assert (QQ(1,2)*x).LC == QQ(1, 2) assert (QQ(1,4)*x*y + QQ(1,2)*x).LC == QQ(1, 4) def test_PolyElement_LM(): R, x, y = ring("x,y", QQ, lex) assert R(0).LM == (0, 0) assert (QQ(1,2)*x).LM == (1, 0) assert (QQ(1,4)*x*y + QQ(1,2)*x).LM == (1, 1) def test_PolyElement_LT(): R, x, y = ring("x,y", QQ, lex) assert R(0).LT == ((0, 0), QQ(0)) assert (QQ(1,2)*x).LT == ((1, 0), QQ(1, 2)) assert (QQ(1,4)*x*y + QQ(1,2)*x).LT == ((1, 1), QQ(1, 4)) R, = ring("", ZZ) assert R(0).LT == ((), 0) assert R(1).LT == ((), 1) def test_PolyElement_leading_monom(): R, x, y = ring("x,y", QQ, lex) assert R(0).leading_monom() == 0 assert (QQ(1,2)*x).leading_monom() == x assert (QQ(1,4)*x*y + QQ(1,2)*x).leading_monom() == x*y def test_PolyElement_leading_term(): R, x, y = ring("x,y", QQ, lex) assert R(0).leading_term() == 0 assert (QQ(1,2)*x).leading_term() == QQ(1,2)*x assert (QQ(1,4)*x*y + QQ(1,2)*x).leading_term() == QQ(1,4)*x*y def test_PolyElement_terms(): R, x,y,z = ring("x,y,z", QQ) terms = (x**2/3 + y**3/4 + z**4/5).terms() assert terms == [((2,0,0), QQ(1,3)), ((0,3,0), QQ(1,4)), ((0,0,4), QQ(1,5))] R, x,y = ring("x,y", ZZ, lex) f = x*y**7 + 2*x**2*y**3 assert f.terms() == f.terms(lex) == f.terms('lex') == [((2, 3), 2), ((1, 7), 1)] assert f.terms(grlex) == f.terms('grlex') == [((1, 7), 1), ((2, 3), 2)] R, x,y = ring("x,y", ZZ, grlex) f = x*y**7 + 2*x**2*y**3 assert f.terms() == f.terms(grlex) == f.terms('grlex') == [((1, 7), 1), ((2, 3), 2)] assert f.terms(lex) == f.terms('lex') == [((2, 3), 2), ((1, 7), 1)] R, = ring("", ZZ) assert R(3).terms() == [((), 3)] def test_PolyElement_monoms(): R, x,y,z = ring("x,y,z", QQ) monoms = (x**2/3 + y**3/4 + z**4/5).monoms() assert monoms == [(2,0,0), (0,3,0), (0,0,4)] R, x,y = ring("x,y", ZZ, lex) f = x*y**7 + 2*x**2*y**3 assert f.monoms() == f.monoms(lex) == f.monoms('lex') == [(2, 3), (1, 7)] assert f.monoms(grlex) == f.monoms('grlex') == [(1, 7), (2, 3)] R, x,y = ring("x,y", ZZ, grlex) f = x*y**7 + 2*x**2*y**3 assert f.monoms() == f.monoms(grlex) == f.monoms('grlex') == [(1, 7), (2, 3)] assert f.monoms(lex) == f.monoms('lex') == [(2, 3), (1, 7)] def test_PolyElement_coeffs(): R, x,y,z = ring("x,y,z", QQ) coeffs = (x**2/3 + y**3/4 + z**4/5).coeffs() assert coeffs == [QQ(1,3), QQ(1,4), QQ(1,5)] R, x,y = ring("x,y", ZZ, lex) f = x*y**7 + 2*x**2*y**3 assert f.coeffs() == f.coeffs(lex) == f.coeffs('lex') == [2, 1] assert f.coeffs(grlex) == f.coeffs('grlex') == [1, 2] R, x,y = ring("x,y", ZZ, grlex) f = x*y**7 + 2*x**2*y**3 assert f.coeffs() == f.coeffs(grlex) == f.coeffs('grlex') == [1, 2] assert f.coeffs(lex) == f.coeffs('lex') == [2, 1] def test_PolyElement___add__(): Rt, t = ring("t", ZZ) Ruv, u,v = ring("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Ruv) assert dict(x + 3*y) == {(1, 0, 0): 1, (0, 1, 0): 3} assert dict(u + x) == dict(x + u) == {(1, 0, 0): 1, (0, 0, 0): u} assert dict(u + x*y) == dict(x*y + u) == {(1, 1, 0): 1, (0, 0, 0): u} assert dict(u + x*y + z) == dict(x*y + z + u) == {(1, 1, 0): 1, (0, 0, 1): 1, (0, 0, 0): u} assert dict(u*x + x) == dict(x + u*x) == {(1, 0, 0): u + 1} assert dict(u*x + x*y) == dict(x*y + u*x) == {(1, 1, 0): 1, (1, 0, 0): u} assert dict(u*x + x*y + z) == dict(x*y + z + u*x) == {(1, 1, 0): 1, (0, 0, 1): 1, (1, 0, 0): u} raises(TypeError, lambda: t + x) raises(TypeError, lambda: x + t) raises(TypeError, lambda: t + u) raises(TypeError, lambda: u + t) Fuv, u,v = field("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Fuv) assert dict(u + x) == dict(x + u) == {(1, 0, 0): 1, (0, 0, 0): u} Rxyz, x,y,z = ring("x,y,z", EX) assert dict(EX(pi) + x*y*z) == dict(x*y*z + EX(pi)) == {(1, 1, 1): EX(1), (0, 0, 0): EX(pi)} def test_PolyElement___sub__(): Rt, t = ring("t", ZZ) Ruv, u,v = ring("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Ruv) assert dict(x - 3*y) == {(1, 0, 0): 1, (0, 1, 0): -3} assert dict(-u + x) == dict(x - u) == {(1, 0, 0): 1, (0, 0, 0): -u} assert dict(-u + x*y) == dict(x*y - u) == {(1, 1, 0): 1, (0, 0, 0): -u} assert dict(-u + x*y + z) == dict(x*y + z - u) == {(1, 1, 0): 1, (0, 0, 1): 1, (0, 0, 0): -u} assert dict(-u*x + x) == dict(x - u*x) == {(1, 0, 0): -u + 1} assert dict(-u*x + x*y) == dict(x*y - u*x) == {(1, 1, 0): 1, (1, 0, 0): -u} assert dict(-u*x + x*y + z) == dict(x*y + z - u*x) == {(1, 1, 0): 1, (0, 0, 1): 1, (1, 0, 0): -u} raises(TypeError, lambda: t - x) raises(TypeError, lambda: x - t) raises(TypeError, lambda: t - u) raises(TypeError, lambda: u - t) Fuv, u,v = field("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Fuv) assert dict(-u + x) == dict(x - u) == {(1, 0, 0): 1, (0, 0, 0): -u} Rxyz, x,y,z = ring("x,y,z", EX) assert dict(-EX(pi) + x*y*z) == dict(x*y*z - EX(pi)) == {(1, 1, 1): EX(1), (0, 0, 0): -EX(pi)} def test_PolyElement___mul__(): Rt, t = ring("t", ZZ) Ruv, u,v = ring("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Ruv) assert dict(u*x) == dict(x*u) == {(1, 0, 0): u} assert dict(2*u*x + z) == dict(x*2*u + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} assert dict(u*2*x + z) == dict(2*x*u + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} assert dict(2*u*x + z) == dict(x*2*u + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} assert dict(u*x*2 + z) == dict(x*u*2 + z) == {(1, 0, 0): 2*u, (0, 0, 1): 1} assert dict(2*u*x*y + z) == dict(x*y*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(u*2*x*y + z) == dict(2*x*y*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(2*u*x*y + z) == dict(x*y*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(u*x*y*2 + z) == dict(x*y*u*2 + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(2*u*y*x + z) == dict(y*x*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(u*2*y*x + z) == dict(2*y*x*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(2*u*y*x + z) == dict(y*x*2*u + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(u*y*x*2 + z) == dict(y*x*u*2 + z) == {(1, 1, 0): 2*u, (0, 0, 1): 1} assert dict(3*u*(x + y) + z) == dict((x + y)*3*u + z) == {(1, 0, 0): 3*u, (0, 1, 0): 3*u, (0, 0, 1): 1} raises(TypeError, lambda: t*x + z) raises(TypeError, lambda: x*t + z) raises(TypeError, lambda: t*u + z) raises(TypeError, lambda: u*t + z) Fuv, u,v = field("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Fuv) assert dict(u*x) == dict(x*u) == {(1, 0, 0): u} Rxyz, x,y,z = ring("x,y,z", EX) assert dict(EX(pi)*x*y*z) == dict(x*y*z*EX(pi)) == {(1, 1, 1): EX(pi)} def test_PolyElement___truediv__(): R, x,y,z = ring("x,y,z", ZZ) assert (2*x**2 - 4)/2 == x**2 - 2 assert (2*x**2 - 3)/2 == x**2 assert (x**2 - 1).quo(x) == x assert (x**2 - x).quo(x) == x - 1 assert (x**2 - 1)/x == x - x**(-1) assert (x**2 - x)/x == x - 1 assert (x**2 - 1)/(2*x) == x/2 - x**(-1)/2 assert (x**2 - 1).quo(2*x) == 0 assert (x**2 - x)/(x - 1) == (x**2 - x).quo(x - 1) == x R, x,y,z = ring("x,y,z", ZZ) assert len((x**2/3 + y**3/4 + z**4/5).terms()) == 0 R, x,y,z = ring("x,y,z", QQ) assert len((x**2/3 + y**3/4 + z**4/5).terms()) == 3 Rt, t = ring("t", ZZ) Ruv, u,v = ring("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Ruv) assert dict((u**2*x + u)/u) == {(1, 0, 0): u, (0, 0, 0): 1} raises(TypeError, lambda: u/(u**2*x + u)) raises(TypeError, lambda: t/x) raises(TypeError, lambda: x/t) raises(TypeError, lambda: t/u) raises(TypeError, lambda: u/t) R, x = ring("x", ZZ) f, g = x**2 + 2*x + 3, R(0) raises(ZeroDivisionError, lambda: f.div(g)) raises(ZeroDivisionError, lambda: divmod(f, g)) raises(ZeroDivisionError, lambda: f.rem(g)) raises(ZeroDivisionError, lambda: f % g) raises(ZeroDivisionError, lambda: f.quo(g)) raises(ZeroDivisionError, lambda: f / g) raises(ZeroDivisionError, lambda: f.exquo(g)) R, x, y = ring("x,y", ZZ) f, g = x*y + 2*x + 3, R(0) raises(ZeroDivisionError, lambda: f.div(g)) raises(ZeroDivisionError, lambda: divmod(f, g)) raises(ZeroDivisionError, lambda: f.rem(g)) raises(ZeroDivisionError, lambda: f % g) raises(ZeroDivisionError, lambda: f.quo(g)) raises(ZeroDivisionError, lambda: f / g) raises(ZeroDivisionError, lambda: f.exquo(g)) R, x = ring("x", ZZ) f, g = x**2 + 1, 2*x - 4 q, r = R(0), x**2 + 1 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = 3*x**3 + x**2 + x + 5, 5*x**2 - 3*x + 1 q, r = R(0), f assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = 5*x**4 + 4*x**3 + 3*x**2 + 2*x + 1, x**2 + 2*x + 3 q, r = 5*x**2 - 6*x, 20*x + 1 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = 5*x**5 + 4*x**4 + 3*x**3 + 2*x**2 + x, x**4 + 2*x**3 + 9 q, r = 5*x - 6, 15*x**3 + 2*x**2 - 44*x + 54 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) R, x = ring("x", QQ) f, g = x**2 + 1, 2*x - 4 q, r = x/2 + 1, R(5) assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = 3*x**3 + x**2 + x + 5, 5*x**2 - 3*x + 1 q, r = QQ(3, 5)*x + QQ(14, 25), QQ(52, 25)*x + QQ(111, 25) assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) R, x,y = ring("x,y", ZZ) f, g = x**2 - y**2, x - y q, r = x + y, R(0) assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q assert f.exquo(g) == q f, g = x**2 + y**2, x - y q, r = x + y, 2*y**2 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = x**2 + y**2, -x + y q, r = -x - y, 2*y**2 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = x**2 + y**2, 2*x - 2*y q, r = R(0), f assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) R, x,y = ring("x,y", QQ) f, g = x**2 - y**2, x - y q, r = x + y, R(0) assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q assert f.exquo(g) == q f, g = x**2 + y**2, x - y q, r = x + y, 2*y**2 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = x**2 + y**2, -x + y q, r = -x - y, 2*y**2 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) f, g = x**2 + y**2, 2*x - 2*y q, r = x/2 + y/2, 2*y**2 assert f.div(g) == divmod(f, g) == (q, r) assert f.rem(g) == f % g == r assert f.quo(g) == f / g == q raises(ExactQuotientFailed, lambda: f.exquo(g)) def test_PolyElement___pow__(): R, x = ring("x", ZZ, grlex) f = 2*x + 3 assert f**0 == 1 assert f**1 == f raises(ValueError, lambda: f**(-1)) assert x**(-1) == x**(-1) assert f**2 == f._pow_generic(2) == f._pow_multinomial(2) == 4*x**2 + 12*x + 9 assert f**3 == f._pow_generic(3) == f._pow_multinomial(3) == 8*x**3 + 36*x**2 + 54*x + 27 assert f**4 == f._pow_generic(4) == f._pow_multinomial(4) == 16*x**4 + 96*x**3 + 216*x**2 + 216*x + 81 assert f**5 == f._pow_generic(5) == f._pow_multinomial(5) == 32*x**5 + 240*x**4 + 720*x**3 + 1080*x**2 + 810*x + 243 R, x,y,z = ring("x,y,z", ZZ, grlex) f = x**3*y - 2*x*y**2 - 3*z + 1 g = x**6*y**2 - 4*x**4*y**3 - 6*x**3*y*z + 2*x**3*y + 4*x**2*y**4 + 12*x*y**2*z - 4*x*y**2 + 9*z**2 - 6*z + 1 assert f**2 == f._pow_generic(2) == f._pow_multinomial(2) == g R, t = ring("t", ZZ) f = -11200*t**4 - 2604*t**2 + 49 g = 15735193600000000*t**16 + 14633730048000000*t**14 + 4828147466240000*t**12 \ + 598976863027200*t**10 + 3130812416256*t**8 - 2620523775744*t**6 \ + 92413760096*t**4 - 1225431984*t**2 + 5764801 assert f**4 == f._pow_generic(4) == f._pow_multinomial(4) == g def test_PolyElement_div(): R, x = ring("x", ZZ, grlex) f = x**3 - 12*x**2 - 42 g = x - 3 q = x**2 - 9*x - 27 r = -123 assert f.div([g]) == ([q], r) R, x = ring("x", ZZ, grlex) f = x**2 + 2*x + 2 assert f.div([R(1)]) == ([f], 0) R, x = ring("x", QQ, grlex) f = x**2 + 2*x + 2 assert f.div([R(2)]) == ([QQ(1,2)*x**2 + x + 1], 0) R, x,y = ring("x,y", ZZ, grlex) f = 4*x**2*y - 2*x*y + 4*x - 2*y + 8 assert f.div([R(2)]) == ([2*x**2*y - x*y + 2*x - y + 4], 0) assert f.div([2*y]) == ([2*x**2 - x - 1], 4*x + 8) f = x - 1 g = y - 1 assert f.div([g]) == ([0], f) f = x*y**2 + 1 G = [x*y + 1, y + 1] Q = [y, -1] r = 2 assert f.div(G) == (Q, r) f = x**2*y + x*y**2 + y**2 G = [x*y - 1, y**2 - 1] Q = [x + y, 1] r = x + y + 1 assert f.div(G) == (Q, r) G = [y**2 - 1, x*y - 1] Q = [x + 1, x] r = 2*x + 1 assert f.div(G) == (Q, r) R, = ring("", ZZ) assert R(3).div(R(2)) == (0, 3) R, = ring("", QQ) assert R(3).div(R(2)) == (QQ(3, 2), 0) def test_PolyElement_rem(): R, x = ring("x", ZZ, grlex) f = x**3 - 12*x**2 - 42 g = x - 3 r = -123 assert f.rem([g]) == f.div([g])[1] == r R, x,y = ring("x,y", ZZ, grlex) f = 4*x**2*y - 2*x*y + 4*x - 2*y + 8 assert f.rem([R(2)]) == f.div([R(2)])[1] == 0 assert f.rem([2*y]) == f.div([2*y])[1] == 4*x + 8 f = x - 1 g = y - 1 assert f.rem([g]) == f.div([g])[1] == f f = x*y**2 + 1 G = [x*y + 1, y + 1] r = 2 assert f.rem(G) == f.div(G)[1] == r f = x**2*y + x*y**2 + y**2 G = [x*y - 1, y**2 - 1] r = x + y + 1 assert f.rem(G) == f.div(G)[1] == r G = [y**2 - 1, x*y - 1] r = 2*x + 1 assert f.rem(G) == f.div(G)[1] == r def test_PolyElement_deflate(): R, x = ring("x", ZZ) assert (2*x**2).deflate(x**4 + 4*x**2 + 1) == ((2,), [2*x, x**2 + 4*x + 1]) R, x,y = ring("x,y", ZZ) assert R(0).deflate(R(0)) == ((1, 1), [0, 0]) assert R(1).deflate(R(0)) == ((1, 1), [1, 0]) assert R(1).deflate(R(2)) == ((1, 1), [1, 2]) assert R(1).deflate(2*y) == ((1, 1), [1, 2*y]) assert (2*y).deflate(2*y) == ((1, 1), [2*y, 2*y]) assert R(2).deflate(2*y**2) == ((1, 2), [2, 2*y]) assert (2*y**2).deflate(2*y**2) == ((1, 2), [2*y, 2*y]) f = x**4*y**2 + x**2*y + 1 g = x**2*y**3 + x**2*y + 1 assert f.deflate(g) == ((2, 1), [x**2*y**2 + x*y + 1, x*y**3 + x*y + 1]) def test_PolyElement_clear_denoms(): R, x,y = ring("x,y", QQ) assert R(1).clear_denoms() == (ZZ(1), 1) assert R(7).clear_denoms() == (ZZ(1), 7) assert R(QQ(7,3)).clear_denoms() == (3, 7) assert R(QQ(7,3)).clear_denoms() == (3, 7) assert (3*x**2 + x).clear_denoms() == (1, 3*x**2 + x) assert (x**2 + QQ(1,2)*x).clear_denoms() == (2, 2*x**2 + x) rQQ, x,t = ring("x,t", QQ, lex) rZZ, X,T = ring("x,t", ZZ, lex) F = [x - QQ(17824537287975195925064602467992950991718052713078834557692023531499318507213727406844943097,413954288007559433755329699713866804710749652268151059918115348815925474842910720000)*t**7 - QQ(4882321164854282623427463828745855894130208215961904469205260756604820743234704900167747753,12936071500236232304854053116058337647210926633379720622441104650497671088840960000)*t**6 - QQ(36398103304520066098365558157422127347455927422509913596393052633155821154626830576085097433,25872143000472464609708106232116675294421853266759441244882209300995342177681920000)*t**5 - QQ(168108082231614049052707339295479262031324376786405372698857619250210703675982492356828810819,58212321751063045371843239022262519412449169850208742800984970927239519899784320000)*t**4 - QQ(5694176899498574510667890423110567593477487855183144378347226247962949388653159751849449037,1617008937529529038106756639507292205901365829172465077805138081312208886105120000)*t**3 - QQ(154482622347268833757819824809033388503591365487934245386958884099214649755244381307907779,60637835157357338929003373981523457721301218593967440417692678049207833228942000)*t**2 - QQ(2452813096069528207645703151222478123259511586701148682951852876484544822947007791153163,2425513406294293557160134959260938308852048743758697616707707121968313329157680)*t - QQ(34305265428126440542854669008203683099323146152358231964773310260498715579162112959703,202126117191191129763344579938411525737670728646558134725642260164026110763140), t**8 + QQ(693749860237914515552,67859264524169150569)*t**7 + QQ(27761407182086143225024,610733380717522355121)*t**6 + QQ(7785127652157884044288,67859264524169150569)*t**5 + QQ(36567075214771261409792,203577793572507451707)*t**4 + QQ(36336335165196147384320,203577793572507451707)*t**3 + QQ(7452455676042754048000,67859264524169150569)*t**2 + QQ(2593331082514399232000,67859264524169150569)*t + QQ(390399197427343360000,67859264524169150569)] G = [3725588592068034903797967297424801242396746870413359539263038139343329273586196480000*X - 160420835591776763325581422211936558925462474417709511019228211783493866564923546661604487873*T**7 - 1406108495478033395547109582678806497509499966197028487131115097902188374051595011248311352864*T**6 - 5241326875850889518164640374668786338033653548841427557880599579174438246266263602956254030352*T**5 - 10758917262823299139373269714910672770004760114329943852726887632013485035262879510837043892416*T**4 - 13119383576444715672578819534846747735372132018341964647712009275306635391456880068261130581248*T**3 - 9491412317016197146080450036267011389660653495578680036574753839055748080962214787557853941760*T**2 - 3767520915562795326943800040277726397326609797172964377014046018280260848046603967211258368000*T - 632314652371226552085897259159210286886724229880266931574701654721512325555116066073245696000, 610733380717522355121*T**8 + 6243748742141230639968*T**7 + 27761407182086143225024*T**6 + 70066148869420956398592*T**5 + 109701225644313784229376*T**4 + 109009005495588442152960*T**3 + 67072101084384786432000*T**2 + 23339979742629593088000*T + 3513592776846090240000] assert [ f.clear_denoms()[1].set_ring(rZZ) for f in F ] == G def test_PolyElement_cofactors(): R, x, y = ring("x,y", ZZ) f, g = R(0), R(0) assert f.cofactors(g) == (0, 0, 0) f, g = R(2), R(0) assert f.cofactors(g) == (2, 1, 0) f, g = R(-2), R(0) assert f.cofactors(g) == (2, -1, 0) f, g = R(0), R(-2) assert f.cofactors(g) == (2, 0, -1) f, g = R(0), 2*x + 4 assert f.cofactors(g) == (2*x + 4, 0, 1) f, g = 2*x + 4, R(0) assert f.cofactors(g) == (2*x + 4, 1, 0) f, g = R(2), R(2) assert f.cofactors(g) == (2, 1, 1) f, g = R(-2), R(2) assert f.cofactors(g) == (2, -1, 1) f, g = R(2), R(-2) assert f.cofactors(g) == (2, 1, -1) f, g = R(-2), R(-2) assert f.cofactors(g) == (2, -1, -1) f, g = x**2 + 2*x + 1, R(1) assert f.cofactors(g) == (1, x**2 + 2*x + 1, 1) f, g = x**2 + 2*x + 1, R(2) assert f.cofactors(g) == (1, x**2 + 2*x + 1, 2) f, g = 2*x**2 + 4*x + 2, R(2) assert f.cofactors(g) == (2, x**2 + 2*x + 1, 1) f, g = R(2), 2*x**2 + 4*x + 2 assert f.cofactors(g) == (2, 1, x**2 + 2*x + 1) f, g = 2*x**2 + 4*x + 2, x + 1 assert f.cofactors(g) == (x + 1, 2*x + 2, 1) f, g = x + 1, 2*x**2 + 4*x + 2 assert f.cofactors(g) == (x + 1, 1, 2*x + 2) R, x, y, z, t = ring("x,y,z,t", ZZ) f, g = t**2 + 2*t + 1, 2*t + 2 assert f.cofactors(g) == (t + 1, t + 1, 2) f, g = z**2*t**2 + 2*z**2*t + z**2 + z*t + z, t**2 + 2*t + 1 h, cff, cfg = t + 1, z**2*t + z**2 + z, t + 1 assert f.cofactors(g) == (h, cff, cfg) assert g.cofactors(f) == (h, cfg, cff) R, x, y = ring("x,y", QQ) f = QQ(1,2)*x**2 + x + QQ(1,2) g = QQ(1,2)*x + QQ(1,2) h = x + 1 assert f.cofactors(g) == (h, g, QQ(1,2)) assert g.cofactors(f) == (h, QQ(1,2), g) R, x, y = ring("x,y", RR) f = 2.1*x*y**2 - 2.1*x*y + 2.1*x g = 2.1*x**3 h = 1.0*x assert f.cofactors(g) == (h, f/h, g/h) assert g.cofactors(f) == (h, g/h, f/h) def test_PolyElement_gcd(): R, x, y = ring("x,y", QQ) f = QQ(1,2)*x**2 + x + QQ(1,2) g = QQ(1,2)*x + QQ(1,2) assert f.gcd(g) == x + 1 def test_PolyElement_cancel(): R, x, y = ring("x,y", ZZ) f = 2*x**3 + 4*x**2 + 2*x g = 3*x**2 + 3*x F = 2*x + 2 G = 3 assert f.cancel(g) == (F, G) assert (-f).cancel(g) == (-F, G) assert f.cancel(-g) == (-F, G) R, x, y = ring("x,y", QQ) f = QQ(1,2)*x**3 + x**2 + QQ(1,2)*x g = QQ(1,3)*x**2 + QQ(1,3)*x F = 3*x + 3 G = 2 assert f.cancel(g) == (F, G) assert (-f).cancel(g) == (-F, G) assert f.cancel(-g) == (-F, G) Fx, x = field("x", ZZ) Rt, t = ring("t", Fx) f = (-x**2 - 4)/4*t g = t**2 + (x**2 + 2)/2 assert f.cancel(g) == ((-x**2 - 4)*t, 4*t**2 + 2*x**2 + 4) def test_PolyElement_max_norm(): R, x, y = ring("x,y", ZZ) assert R(0).max_norm() == 0 assert R(1).max_norm() == 1 assert (x**3 + 4*x**2 + 2*x + 3).max_norm() == 4 def test_PolyElement_l1_norm(): R, x, y = ring("x,y", ZZ) assert R(0).l1_norm() == 0 assert R(1).l1_norm() == 1 assert (x**3 + 4*x**2 + 2*x + 3).l1_norm() == 10 def test_PolyElement_diff(): R, X = xring("x:11", QQ) f = QQ(288,5)*X[0]**8*X[1]**6*X[4]**3*X[10]**2 + 8*X[0]**2*X[2]**3*X[4]**3 +2*X[0]**2 - 2*X[1]**2 assert f.diff(X[0]) == QQ(2304,5)*X[0]**7*X[1]**6*X[4]**3*X[10]**2 + 16*X[0]*X[2]**3*X[4]**3 + 4*X[0] assert f.diff(X[4]) == QQ(864,5)*X[0]**8*X[1]**6*X[4]**2*X[10]**2 + 24*X[0]**2*X[2]**3*X[4]**2 assert f.diff(X[10]) == QQ(576,5)*X[0]**8*X[1]**6*X[4]**3*X[10] def test_PolyElement___call__(): R, x = ring("x", ZZ) f = 3*x + 1 assert f(0) == 1 assert f(1) == 4 raises(ValueError, lambda: f()) raises(ValueError, lambda: f(0, 1)) raises(CoercionFailed, lambda: f(QQ(1,7))) R, x,y = ring("x,y", ZZ) f = 3*x + y**2 + 1 assert f(0, 0) == 1 assert f(1, 7) == 53 Ry = R.drop(x) assert f(0) == Ry.y**2 + 1 assert f(1) == Ry.y**2 + 4 raises(ValueError, lambda: f()) raises(ValueError, lambda: f(0, 1, 2)) raises(CoercionFailed, lambda: f(1, QQ(1,7))) raises(CoercionFailed, lambda: f(QQ(1,7), 1)) raises(CoercionFailed, lambda: f(QQ(1,7), QQ(1,7))) def test_PolyElement_evaluate(): R, x = ring("x", ZZ) f = x**3 + 4*x**2 + 2*x + 3 r = f.evaluate(x, 0) assert r == 3 and not isinstance(r, PolyElement) raises(CoercionFailed, lambda: f.evaluate(x, QQ(1,7))) R, x, y, z = ring("x,y,z", ZZ) f = (x*y)**3 + 4*(x*y)**2 + 2*x*y + 3 r = f.evaluate(x, 0) assert r == 3 and isinstance(r, R.drop(x).dtype) r = f.evaluate([(x, 0), (y, 0)]) assert r == 3 and isinstance(r, R.drop(x, y).dtype) r = f.evaluate(y, 0) assert r == 3 and isinstance(r, R.drop(y).dtype) r = f.evaluate([(y, 0), (x, 0)]) assert r == 3 and isinstance(r, R.drop(y, x).dtype) r = f.evaluate([(x, 0), (y, 0), (z, 0)]) assert r == 3 and not isinstance(r, PolyElement) raises(CoercionFailed, lambda: f.evaluate([(x, 1), (y, QQ(1,7))])) raises(CoercionFailed, lambda: f.evaluate([(x, QQ(1,7)), (y, 1)])) raises(CoercionFailed, lambda: f.evaluate([(x, QQ(1,7)), (y, QQ(1,7))])) def test_PolyElement_subs(): R, x = ring("x", ZZ) f = x**3 + 4*x**2 + 2*x + 3 r = f.subs(x, 0) assert r == 3 and isinstance(r, R.dtype) raises(CoercionFailed, lambda: f.subs(x, QQ(1,7))) R, x, y, z = ring("x,y,z", ZZ) f = x**3 + 4*x**2 + 2*x + 3 r = f.subs(x, 0) assert r == 3 and isinstance(r, R.dtype) r = f.subs([(x, 0), (y, 0)]) assert r == 3 and isinstance(r, R.dtype) raises(CoercionFailed, lambda: f.subs([(x, 1), (y, QQ(1,7))])) raises(CoercionFailed, lambda: f.subs([(x, QQ(1,7)), (y, 1)])) raises(CoercionFailed, lambda: f.subs([(x, QQ(1,7)), (y, QQ(1,7))])) def test_PolyElement_compose(): R, x = ring("x", ZZ) f = x**3 + 4*x**2 + 2*x + 3 r = f.compose(x, 0) assert r == 3 and isinstance(r, R.dtype) assert f.compose(x, x) == f assert f.compose(x, x**2) == x**6 + 4*x**4 + 2*x**2 + 3 raises(CoercionFailed, lambda: f.compose(x, QQ(1,7))) R, x, y, z = ring("x,y,z", ZZ) f = x**3 + 4*x**2 + 2*x + 3 r = f.compose(x, 0) assert r == 3 and isinstance(r, R.dtype) r = f.compose([(x, 0), (y, 0)]) assert r == 3 and isinstance(r, R.dtype) r = (x**3 + 4*x**2 + 2*x*y*z + 3).compose(x, y*z**2 - 1) q = (y*z**2 - 1)**3 + 4*(y*z**2 - 1)**2 + 2*(y*z**2 - 1)*y*z + 3 assert r == q and isinstance(r, R.dtype) def test_PolyElement_is_(): R, x,y,z = ring("x,y,z", QQ) assert (x - x).is_generator == False assert (x - x).is_ground == True assert (x - x).is_monomial == True assert (x - x).is_term == True assert (x - x + 1).is_generator == False assert (x - x + 1).is_ground == True assert (x - x + 1).is_monomial == True assert (x - x + 1).is_term == True assert x.is_generator == True assert x.is_ground == False assert x.is_monomial == True assert x.is_term == True assert (x*y).is_generator == False assert (x*y).is_ground == False assert (x*y).is_monomial == True assert (x*y).is_term == True assert (3*x).is_generator == False assert (3*x).is_ground == False assert (3*x).is_monomial == False assert (3*x).is_term == True assert (3*x + 1).is_generator == False assert (3*x + 1).is_ground == False assert (3*x + 1).is_monomial == False assert (3*x + 1).is_term == False assert R(0).is_zero is True assert R(1).is_zero is False assert R(0).is_one is False assert R(1).is_one is True assert (x - 1).is_monic is True assert (2*x - 1).is_monic is False assert (3*x + 2).is_primitive is True assert (4*x + 2).is_primitive is False assert (x + y + z + 1).is_linear is True assert (x*y*z + 1).is_linear is False assert (x*y + z + 1).is_quadratic is True assert (x*y*z + 1).is_quadratic is False assert (x - 1).is_squarefree is True assert ((x - 1)**2).is_squarefree is False assert (x**2 + x + 1).is_irreducible is True assert (x**2 + 2*x + 1).is_irreducible is False _, t = ring("t", FF(11)) assert (7*t + 3).is_irreducible is True assert (7*t**2 + 3*t + 1).is_irreducible is False _, u = ring("u", ZZ) f = u**16 + u**14 - u**10 - u**8 - u**6 + u**2 assert f.is_cyclotomic is False assert (f + 1).is_cyclotomic is True raises(MultivariatePolynomialError, lambda: x.is_cyclotomic) R, = ring("", ZZ) assert R(4).is_squarefree is True assert R(6).is_irreducible is True def test_PolyElement_drop(): R, x,y,z = ring("x,y,z", ZZ) assert R(1).drop(0).ring == PolyRing("y,z", ZZ, lex) assert R(1).drop(0).drop(0).ring == PolyRing("z", ZZ, lex) assert isinstance(R(1).drop(0).drop(0).drop(0), R.dtype) is False raises(ValueError, lambda: z.drop(0).drop(0).drop(0)) raises(ValueError, lambda: x.drop(0)) def test_PolyElement_pdiv(): _, x, y = ring("x,y", ZZ) f, g = x**2 - y**2, x - y q, r = x + y, 0 assert f.pdiv(g) == (q, r) assert f.prem(g) == r assert f.pquo(g) == q assert f.pexquo(g) == q def test_PolyElement_gcdex(): _, x = ring("x", QQ) f, g = 2*x, x**2 - 16 s, t, h = x/32, -QQ(1, 16), 1 assert f.half_gcdex(g) == (s, h) assert f.gcdex(g) == (s, t, h) def test_PolyElement_subresultants(): _, x = ring("x", ZZ) f, g, h = x**2 - 2*x + 1, x**2 - 1, 2*x - 2 assert f.subresultants(g) == [f, g, h] def test_PolyElement_resultant(): _, x = ring("x", ZZ) f, g, h = x**2 - 2*x + 1, x**2 - 1, 0 assert f.resultant(g) == h def test_PolyElement_discriminant(): _, x = ring("x", ZZ) f, g = x**3 + 3*x**2 + 9*x - 13, -11664 assert f.discriminant() == g F, a, b, c = ring("a,b,c", ZZ) _, x = ring("x", F) f, g = a*x**2 + b*x + c, b**2 - 4*a*c assert f.discriminant() == g def test_PolyElement_decompose(): _, x = ring("x", ZZ) f = x**12 + 20*x**10 + 150*x**8 + 500*x**6 + 625*x**4 - 2*x**3 - 10*x + 9 g = x**4 - 2*x + 9 h = x**3 + 5*x assert g.compose(x, h) == f assert f.decompose() == [g, h] def test_PolyElement_shift(): _, x = ring("x", ZZ) assert (x**2 - 2*x + 1).shift(2) == x**2 + 2*x + 1 def test_PolyElement_sturm(): F, t = field("t", ZZ) _, x = ring("x", F) f = 1024/(15625*t**8)*x**5 - 4096/(625*t**8)*x**4 + 32/(15625*t**4)*x**3 - 128/(625*t**4)*x**2 + F(1)/62500*x - F(1)/625 assert f.sturm() == [ x**3 - 100*x**2 + t**4/64*x - 25*t**4/16, 3*x**2 - 200*x + t**4/64, (-t**4/96 + F(20000)/9)*x + 25*t**4/18, (-9*t**12 - 11520000*t**8 - 3686400000000*t**4)/(576*t**8 - 245760000*t**4 + 26214400000000), ] def test_PolyElement_gff_list(): _, x = ring("x", ZZ) f = x**5 + 2*x**4 - x**3 - 2*x**2 assert f.gff_list() == [(x, 1), (x + 2, 4)] f = x*(x - 1)**3*(x - 2)**2*(x - 4)**2*(x - 5) assert f.gff_list() == [(x**2 - 5*x + 4, 1), (x**2 - 5*x + 4, 2), (x, 3)] def test_PolyElement_sqf_norm(): R, x = ring("x", QQ.algebraic_field(sqrt(3))) X = R.to_ground().x assert (x**2 - 2).sqf_norm() == (1, x**2 - 2*sqrt(3)*x + 1, X**4 - 10*X**2 + 1) R, x = ring("x", QQ.algebraic_field(sqrt(2))) X = R.to_ground().x assert (x**2 - 3).sqf_norm() == (1, x**2 - 2*sqrt(2)*x - 1, X**4 - 10*X**2 + 1) def test_PolyElement_sqf_list(): _, x = ring("x", ZZ) f = x**5 - x**3 - x**2 + 1 g = x**3 + 2*x**2 + 2*x + 1 h = x - 1 p = x**4 + x**3 - x - 1 assert f.sqf_part() == p assert f.sqf_list() == (1, [(g, 1), (h, 2)]) def test_PolyElement_factor_list(): _, x = ring("x", ZZ) f = x**5 - x**3 - x**2 + 1 u = x + 1 v = x - 1 w = x**2 + x + 1 assert f.factor_list() == (1, [(u, 1), (v, 2), (w, 1)]) def test_issue_21410(): R, x = ring('x', FF(2)) p = x**6 + x**5 + x**4 + x**3 + 1 assert p._pow_multinomial(4) == x**24 + x**20 + x**16 + x**12 + 1 sympy-sympy-1.9/sympy/polys/tests/test_rootisolation.py000066400000000000000000000753441412543434000237470ustar00rootroot00000000000000"""Tests for real and complex root isolation and refinement algorithms. """ from sympy.polys.rings import ring from sympy.polys.domains import ZZ, QQ, EX from sympy.polys.polyerrors import DomainError, RefinementFailed from sympy.testing.pytest import raises def test_dup_sturm(): R, x = ring("x", QQ) assert R.dup_sturm(5) == [1] assert R.dup_sturm(x) == [x, 1] f = x**3 - 2*x**2 + 3*x - 5 assert R.dup_sturm(f) == [f, 3*x**2 - 4*x + 3, -QQ(10,9)*x + QQ(13,3), -QQ(3303,100)] def test_dup_refine_real_root(): R, x = ring("x", ZZ) f = x**2 - 2 assert R.dup_refine_real_root(f, QQ(1), QQ(1), steps=1) == (QQ(1), QQ(1)) assert R.dup_refine_real_root(f, QQ(1), QQ(1), steps=9) == (QQ(1), QQ(1)) raises(ValueError, lambda: R.dup_refine_real_root(f, QQ(-2), QQ(2))) s, t = QQ(1, 1), QQ(2, 1) assert R.dup_refine_real_root(f, s, t, steps=0) == (QQ(1, 1), QQ(2, 1)) assert R.dup_refine_real_root(f, s, t, steps=1) == (QQ(1, 1), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=2) == (QQ(4, 3), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=3) == (QQ(7, 5), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=4) == (QQ(7, 5), QQ(10, 7)) s, t = QQ(1, 1), QQ(3, 2) assert R.dup_refine_real_root(f, s, t, steps=0) == (QQ(1, 1), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=1) == (QQ(4, 3), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=2) == (QQ(7, 5), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=3) == (QQ(7, 5), QQ(10, 7)) assert R.dup_refine_real_root(f, s, t, steps=4) == (QQ(7, 5), QQ(17, 12)) s, t = QQ(1, 1), QQ(5, 3) assert R.dup_refine_real_root(f, s, t, steps=0) == (QQ(1, 1), QQ(5, 3)) assert R.dup_refine_real_root(f, s, t, steps=1) == (QQ(1, 1), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=2) == (QQ(7, 5), QQ(3, 2)) assert R.dup_refine_real_root(f, s, t, steps=3) == (QQ(7, 5), QQ(13, 9)) assert R.dup_refine_real_root(f, s, t, steps=4) == (QQ(7, 5), QQ(27, 19)) s, t = QQ(-1, 1), QQ(-2, 1) assert R.dup_refine_real_root(f, s, t, steps=0) == (-QQ(2, 1), -QQ(1, 1)) assert R.dup_refine_real_root(f, s, t, steps=1) == (-QQ(3, 2), -QQ(1, 1)) assert R.dup_refine_real_root(f, s, t, steps=2) == (-QQ(3, 2), -QQ(4, 3)) assert R.dup_refine_real_root(f, s, t, steps=3) == (-QQ(3, 2), -QQ(7, 5)) assert R.dup_refine_real_root(f, s, t, steps=4) == (-QQ(10, 7), -QQ(7, 5)) raises(RefinementFailed, lambda: R.dup_refine_real_root(f, QQ(0), QQ(1))) s, t, u, v, w = QQ(1), QQ(2), QQ(24, 17), QQ(17, 12), QQ(7, 5) assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100)) == (u, v) assert R.dup_refine_real_root(f, s, t, steps=6) == (u, v) assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100), steps=5) == (w, v) assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100), steps=6) == (u, v) assert R.dup_refine_real_root(f, s, t, eps=QQ(1, 100), steps=7) == (u, v) s, t, u, v = QQ(-2), QQ(-1), QQ(-3, 2), QQ(-4, 3) assert R.dup_refine_real_root(f, s, t, disjoint=QQ(-5)) == (s, t) assert R.dup_refine_real_root(f, s, t, disjoint=-v) == (s, t) assert R.dup_refine_real_root(f, s, t, disjoint=v) == (u, v) s, t, u, v = QQ(1), QQ(2), QQ(4, 3), QQ(3, 2) assert R.dup_refine_real_root(f, s, t, disjoint=QQ(5)) == (s, t) assert R.dup_refine_real_root(f, s, t, disjoint=-u) == (s, t) assert R.dup_refine_real_root(f, s, t, disjoint=u) == (u, v) def test_dup_isolate_real_roots_sqf(): R, x = ring("x", ZZ) assert R.dup_isolate_real_roots_sqf(0) == [] assert R.dup_isolate_real_roots_sqf(5) == [] assert R.dup_isolate_real_roots_sqf(x**2 + x) == [(-1, -1), (0, 0)] assert R.dup_isolate_real_roots_sqf(x**2 - x) == [( 0, 0), (1, 1)] assert R.dup_isolate_real_roots_sqf(x**4 + x + 1) == [] I = [(-2, -1), (1, 2)] assert R.dup_isolate_real_roots_sqf(x**2 - 2) == I assert R.dup_isolate_real_roots_sqf(-x**2 + 2) == I assert R.dup_isolate_real_roots_sqf(x - 1) == \ [(1, 1)] assert R.dup_isolate_real_roots_sqf(x**2 - 3*x + 2) == \ [(1, 1), (2, 2)] assert R.dup_isolate_real_roots_sqf(x**3 - 6*x**2 + 11*x - 6) == \ [(1, 1), (2, 2), (3, 3)] assert R.dup_isolate_real_roots_sqf(x**4 - 10*x**3 + 35*x**2 - 50*x + 24) == \ [(1, 1), (2, 2), (3, 3), (4, 4)] assert R.dup_isolate_real_roots_sqf(x**5 - 15*x**4 + 85*x**3 - 225*x**2 + 274*x - 120) == \ [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5)] assert R.dup_isolate_real_roots_sqf(x - 10) == \ [(10, 10)] assert R.dup_isolate_real_roots_sqf(x**2 - 30*x + 200) == \ [(10, 10), (20, 20)] assert R.dup_isolate_real_roots_sqf(x**3 - 60*x**2 + 1100*x - 6000) == \ [(10, 10), (20, 20), (30, 30)] assert R.dup_isolate_real_roots_sqf(x**4 - 100*x**3 + 3500*x**2 - 50000*x + 240000) == \ [(10, 10), (20, 20), (30, 30), (40, 40)] assert R.dup_isolate_real_roots_sqf(x**5 - 150*x**4 + 8500*x**3 - 225000*x**2 + 2740000*x - 12000000) == \ [(10, 10), (20, 20), (30, 30), (40, 40), (50, 50)] assert R.dup_isolate_real_roots_sqf(x + 1) == \ [(-1, -1)] assert R.dup_isolate_real_roots_sqf(x**2 + 3*x + 2) == \ [(-2, -2), (-1, -1)] assert R.dup_isolate_real_roots_sqf(x**3 + 6*x**2 + 11*x + 6) == \ [(-3, -3), (-2, -2), (-1, -1)] assert R.dup_isolate_real_roots_sqf(x**4 + 10*x**3 + 35*x**2 + 50*x + 24) == \ [(-4, -4), (-3, -3), (-2, -2), (-1, -1)] assert R.dup_isolate_real_roots_sqf(x**5 + 15*x**4 + 85*x**3 + 225*x**2 + 274*x + 120) == \ [(-5, -5), (-4, -4), (-3, -3), (-2, -2), (-1, -1)] assert R.dup_isolate_real_roots_sqf(x + 10) == \ [(-10, -10)] assert R.dup_isolate_real_roots_sqf(x**2 + 30*x + 200) == \ [(-20, -20), (-10, -10)] assert R.dup_isolate_real_roots_sqf(x**3 + 60*x**2 + 1100*x + 6000) == \ [(-30, -30), (-20, -20), (-10, -10)] assert R.dup_isolate_real_roots_sqf(x**4 + 100*x**3 + 3500*x**2 + 50000*x + 240000) == \ [(-40, -40), (-30, -30), (-20, -20), (-10, -10)] assert R.dup_isolate_real_roots_sqf(x**5 + 150*x**4 + 8500*x**3 + 225000*x**2 + 2740000*x + 12000000) == \ [(-50, -50), (-40, -40), (-30, -30), (-20, -20), (-10, -10)] assert R.dup_isolate_real_roots_sqf(x**2 - 5) == [(-3, -2), (2, 3)] assert R.dup_isolate_real_roots_sqf(x**3 - 5) == [(1, 2)] assert R.dup_isolate_real_roots_sqf(x**4 - 5) == [(-2, -1), (1, 2)] assert R.dup_isolate_real_roots_sqf(x**5 - 5) == [(1, 2)] assert R.dup_isolate_real_roots_sqf(x**6 - 5) == [(-2, -1), (1, 2)] assert R.dup_isolate_real_roots_sqf(x**7 - 5) == [(1, 2)] assert R.dup_isolate_real_roots_sqf(x**8 - 5) == [(-2, -1), (1, 2)] assert R.dup_isolate_real_roots_sqf(x**9 - 5) == [(1, 2)] assert R.dup_isolate_real_roots_sqf(x**2 - 1) == \ [(-1, -1), (1, 1)] assert R.dup_isolate_real_roots_sqf(x**3 + 2*x**2 - x - 2) == \ [(-2, -2), (-1, -1), (1, 1)] assert R.dup_isolate_real_roots_sqf(x**4 - 5*x**2 + 4) == \ [(-2, -2), (-1, -1), (1, 1), (2, 2)] assert R.dup_isolate_real_roots_sqf(x**5 + 3*x**4 - 5*x**3 - 15*x**2 + 4*x + 12) == \ [(-3, -3), (-2, -2), (-1, -1), (1, 1), (2, 2)] assert R.dup_isolate_real_roots_sqf(x**6 - 14*x**4 + 49*x**2 - 36) == \ [(-3, -3), (-2, -2), (-1, -1), (1, 1), (2, 2), (3, 3)] assert R.dup_isolate_real_roots_sqf(2*x**7 + x**6 - 28*x**5 - 14*x**4 + 98*x**3 + 49*x**2 - 72*x - 36) == \ [(-3, -3), (-2, -2), (-1, -1), (-1, 0), (1, 1), (2, 2), (3, 3)] assert R.dup_isolate_real_roots_sqf(4*x**8 - 57*x**6 + 210*x**4 - 193*x**2 + 36) == \ [(-3, -3), (-2, -2), (-1, -1), (-1, 0), (0, 1), (1, 1), (2, 2), (3, 3)] f = 9*x**2 - 2 assert R.dup_isolate_real_roots_sqf(f) == \ [(-1, 0), (0, 1)] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 10)) == \ [(QQ(-1, 2), QQ(-3, 7)), (QQ(3, 7), QQ(1, 2))] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100)) == \ [(QQ(-9, 19), QQ(-8, 17)), (QQ(8, 17), QQ(9, 19))] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 1000)) == \ [(QQ(-33, 70), QQ(-8, 17)), (QQ(8, 17), QQ(33, 70))] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 10000)) == \ [(QQ(-33, 70), QQ(-107, 227)), (QQ(107, 227), QQ(33, 70))] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100000)) == \ [(QQ(-305, 647), QQ(-272, 577)), (QQ(272, 577), QQ(305, 647))] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 1000000)) == \ [(QQ(-1121, 2378), QQ(-272, 577)), (QQ(272, 577), QQ(1121, 2378))] f = 200100012*x**5 - 700390052*x**4 + 700490079*x**3 - 200240054*x**2 + 40017*x - 2 assert R.dup_isolate_real_roots_sqf(f) == \ [(QQ(0), QQ(1, 10002)), (QQ(1, 10002), QQ(1, 10002)), (QQ(1, 2), QQ(1, 2)), (QQ(1), QQ(1)), (QQ(2), QQ(2))] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100000)) == \ [(QQ(1, 10003), QQ(1, 10003)), (QQ(1, 10002), QQ(1, 10002)), (QQ(1, 2), QQ(1, 2)), (QQ(1), QQ(1)), (QQ(2), QQ(2))] a, b, c, d = 10000090000001, 2000100003, 10000300007, 10000005000008 f = 20001600074001600021*x**4 \ + 1700135866278935491773999857*x**3 \ - 2000179008931031182161141026995283662899200197*x**2 \ - 800027600594323913802305066986600025*x \ + 100000950000540000725000008 assert R.dup_isolate_real_roots_sqf(f) == \ [(-a, -a), (-1, 0), (0, 1), (d, d)] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100000000000)) == \ [(-QQ(a), -QQ(a)), (-QQ(1, b), -QQ(1, b)), (QQ(1, c), QQ(1, c)), (QQ(d), QQ(d))] (u, v), B, C, (s, t) = R.dup_isolate_real_roots_sqf(f, fast=True) assert u < -a < v and B == (-QQ(1), QQ(0)) and C == (QQ(0), QQ(1)) and s < d < t assert R.dup_isolate_real_roots_sqf(f, fast=True, eps=QQ(1, 100000000000000000000000000000)) == \ [(-QQ(a), -QQ(a)), (-QQ(1, b), -QQ(1, b)), (QQ(1, c), QQ(1, c)), (QQ(d), QQ(d))] f = -10*x**4 + 8*x**3 + 80*x**2 - 32*x - 160 assert R.dup_isolate_real_roots_sqf(f) == \ [(-2, -2), (-2, -1), (2, 2), (2, 3)] assert R.dup_isolate_real_roots_sqf(f, eps=QQ(1, 100)) == \ [(-QQ(2), -QQ(2)), (-QQ(23, 14), -QQ(18, 11)), (QQ(2), QQ(2)), (QQ(39, 16), QQ(22, 9))] f = x - 1 assert R.dup_isolate_real_roots_sqf(f, inf=2) == [] assert R.dup_isolate_real_roots_sqf(f, sup=0) == [] assert R.dup_isolate_real_roots_sqf(f) == [(1, 1)] assert R.dup_isolate_real_roots_sqf(f, inf=1) == [(1, 1)] assert R.dup_isolate_real_roots_sqf(f, sup=1) == [(1, 1)] assert R.dup_isolate_real_roots_sqf(f, inf=1, sup=1) == [(1, 1)] f = x**2 - 2 assert R.dup_isolate_real_roots_sqf(f, inf=QQ(7, 4)) == [] assert R.dup_isolate_real_roots_sqf(f, inf=QQ(7, 5)) == [(QQ(7, 5), QQ(3, 2))] assert R.dup_isolate_real_roots_sqf(f, sup=QQ(7, 5)) == [(-2, -1)] assert R.dup_isolate_real_roots_sqf(f, sup=QQ(7, 4)) == [(-2, -1), (1, QQ(3, 2))] assert R.dup_isolate_real_roots_sqf(f, sup=-QQ(7, 4)) == [] assert R.dup_isolate_real_roots_sqf(f, sup=-QQ(7, 5)) == [(-QQ(3, 2), -QQ(7, 5))] assert R.dup_isolate_real_roots_sqf(f, inf=-QQ(7, 5)) == [(1, 2)] assert R.dup_isolate_real_roots_sqf(f, inf=-QQ(7, 4)) == [(-QQ(3, 2), -1), (1, 2)] I = [(-2, -1), (1, 2)] assert R.dup_isolate_real_roots_sqf(f, inf=-2) == I assert R.dup_isolate_real_roots_sqf(f, sup=+2) == I assert R.dup_isolate_real_roots_sqf(f, inf=-2, sup=2) == I R, x = ring("x", QQ) f = QQ(8, 5)*x**2 - QQ(87374, 3855)*x - QQ(17, 771) assert R.dup_isolate_real_roots_sqf(f) == [(-1, 0), (14, 15)] R, x = ring("x", EX) raises(DomainError, lambda: R.dup_isolate_real_roots_sqf(x + 3)) def test_dup_isolate_real_roots(): R, x = ring("x", ZZ) assert R.dup_isolate_real_roots(0) == [] assert R.dup_isolate_real_roots(3) == [] assert R.dup_isolate_real_roots(5*x) == [((0, 0), 1)] assert R.dup_isolate_real_roots(7*x**4) == [((0, 0), 4)] assert R.dup_isolate_real_roots(x**2 + x) == [((-1, -1), 1), ((0, 0), 1)] assert R.dup_isolate_real_roots(x**2 - x) == [((0, 0), 1), ((1, 1), 1)] assert R.dup_isolate_real_roots(x**4 + x + 1) == [] I = [((-2, -1), 1), ((1, 2), 1)] assert R.dup_isolate_real_roots(x**2 - 2) == I assert R.dup_isolate_real_roots(-x**2 + 2) == I f = 16*x**14 - 96*x**13 + 24*x**12 + 936*x**11 - 1599*x**10 - 2880*x**9 + 9196*x**8 \ + 552*x**7 - 21831*x**6 + 13968*x**5 + 21690*x**4 - 26784*x**3 - 2916*x**2 + 15552*x - 5832 g = R.dup_sqf_part(f) assert R.dup_isolate_real_roots(f) == \ [((-QQ(2), -QQ(3, 2)), 2), ((-QQ(3, 2), -QQ(1, 1)), 3), ((QQ(1), QQ(3, 2)), 3), ((QQ(3, 2), QQ(3, 2)), 4), ((QQ(5, 3), QQ(2)), 2)] assert R.dup_isolate_real_roots_sqf(g) == \ [(-QQ(2), -QQ(3, 2)), (-QQ(3, 2), -QQ(1, 1)), (QQ(1), QQ(3, 2)), (QQ(3, 2), QQ(3, 2)), (QQ(3, 2), QQ(2))] assert R.dup_isolate_real_roots(g) == \ [((-QQ(2), -QQ(3, 2)), 1), ((-QQ(3, 2), -QQ(1, 1)), 1), ((QQ(1), QQ(3, 2)), 1), ((QQ(3, 2), QQ(3, 2)), 1), ((QQ(3, 2), QQ(2)), 1)] f = x - 1 assert R.dup_isolate_real_roots(f, inf=2) == [] assert R.dup_isolate_real_roots(f, sup=0) == [] assert R.dup_isolate_real_roots(f) == [((1, 1), 1)] assert R.dup_isolate_real_roots(f, inf=1) == [((1, 1), 1)] assert R.dup_isolate_real_roots(f, sup=1) == [((1, 1), 1)] assert R.dup_isolate_real_roots(f, inf=1, sup=1) == [((1, 1), 1)] f = x**4 - 4*x**2 + 4 assert R.dup_isolate_real_roots(f, inf=QQ(7, 4)) == [] assert R.dup_isolate_real_roots(f, inf=QQ(7, 5)) == [((QQ(7, 5), QQ(3, 2)), 2)] assert R.dup_isolate_real_roots(f, sup=QQ(7, 5)) == [((-2, -1), 2)] assert R.dup_isolate_real_roots(f, sup=QQ(7, 4)) == [((-2, -1), 2), ((1, QQ(3, 2)), 2)] assert R.dup_isolate_real_roots(f, sup=-QQ(7, 4)) == [] assert R.dup_isolate_real_roots(f, sup=-QQ(7, 5)) == [((-QQ(3, 2), -QQ(7, 5)), 2)] assert R.dup_isolate_real_roots(f, inf=-QQ(7, 5)) == [((1, 2), 2)] assert R.dup_isolate_real_roots(f, inf=-QQ(7, 4)) == [((-QQ(3, 2), -1), 2), ((1, 2), 2)] I = [((-2, -1), 2), ((1, 2), 2)] assert R.dup_isolate_real_roots(f, inf=-2) == I assert R.dup_isolate_real_roots(f, sup=+2) == I assert R.dup_isolate_real_roots(f, inf=-2, sup=2) == I f = x**11 - 3*x**10 - x**9 + 11*x**8 - 8*x**7 - 8*x**6 + 12*x**5 - 4*x**4 assert R.dup_isolate_real_roots(f, basis=False) == \ [((-2, -1), 2), ((0, 0), 4), ((1, 1), 3), ((1, 2), 2)] assert R.dup_isolate_real_roots(f, basis=True) == \ [((-2, -1), 2, [1, 0, -2]), ((0, 0), 4, [1, 0]), ((1, 1), 3, [1, -1]), ((1, 2), 2, [1, 0, -2])] f = (x**45 - 45*x**44 + 990*x**43 - 1) g = (x**46 - 15180*x**43 + 9366819*x**40 - 53524680*x**39 + 260932815*x**38 - 1101716330*x**37 + 4076350421*x**36 - 13340783196*x**35 + 38910617655*x**34 - 101766230790*x**33 + 239877544005*x**32 - 511738760544*x**31 + 991493848554*x**30 - 1749695026860*x**29 + 2818953098830*x**28 - 4154246671960*x**27 + 5608233007146*x**26 - 6943526580276*x**25 + 7890371113950*x**24 - 8233430727600*x**23 + 7890371113950*x**22 - 6943526580276*x**21 + 5608233007146*x**20 - 4154246671960*x**19 + 2818953098830*x**18 - 1749695026860*x**17 + 991493848554*x**16 - 511738760544*x**15 + 239877544005*x**14 - 101766230790*x**13 + 38910617655*x**12 - 13340783196*x**11 + 4076350421*x**10 - 1101716330*x**9 + 260932815*x**8 - 53524680*x**7 + 9366819*x**6 - 1370754*x**5 + 163185*x**4 - 15180*x**3 + 1035*x**2 - 47*x + 1) assert R.dup_isolate_real_roots(f*g) == \ [((0, QQ(1, 2)), 1), ((QQ(2, 3), QQ(3, 4)), 1), ((QQ(3, 4), 1), 1), ((6, 7), 1), ((24, 25), 1)] R, x = ring("x", EX) raises(DomainError, lambda: R.dup_isolate_real_roots(x + 3)) def test_dup_isolate_real_roots_list(): R, x = ring("x", ZZ) assert R.dup_isolate_real_roots_list([x**2 + x, x]) == \ [((-1, -1), {0: 1}), ((0, 0), {0: 1, 1: 1})] assert R.dup_isolate_real_roots_list([x**2 - x, x]) == \ [((0, 0), {0: 1, 1: 1}), ((1, 1), {0: 1})] assert R.dup_isolate_real_roots_list([x + 1, x + 2, x - 1, x + 1, x - 1, x - 1]) == \ [((-QQ(2), -QQ(2)), {1: 1}), ((-QQ(1), -QQ(1)), {0: 1, 3: 1}), ((QQ(1), QQ(1)), {2: 1, 4: 1, 5: 1})] assert R.dup_isolate_real_roots_list([x + 1, x + 2, x - 1, x + 1, x - 1, x + 2]) == \ [((-QQ(2), -QQ(2)), {1: 1, 5: 1}), ((-QQ(1), -QQ(1)), {0: 1, 3: 1}), ((QQ(1), QQ(1)), {2: 1, 4: 1})] f, g = x**4 - 4*x**2 + 4, x - 1 assert R.dup_isolate_real_roots_list([f, g], inf=QQ(7, 4)) == [] assert R.dup_isolate_real_roots_list([f, g], inf=QQ(7, 5)) == \ [((QQ(7, 5), QQ(3, 2)), {0: 2})] assert R.dup_isolate_real_roots_list([f, g], sup=QQ(7, 5)) == \ [((-2, -1), {0: 2}), ((1, 1), {1: 1})] assert R.dup_isolate_real_roots_list([f, g], sup=QQ(7, 4)) == \ [((-2, -1), {0: 2}), ((1, 1), {1: 1}), ((1, QQ(3, 2)), {0: 2})] assert R.dup_isolate_real_roots_list([f, g], sup=-QQ(7, 4)) == [] assert R.dup_isolate_real_roots_list([f, g], sup=-QQ(7, 5)) == \ [((-QQ(3, 2), -QQ(7, 5)), {0: 2})] assert R.dup_isolate_real_roots_list([f, g], inf=-QQ(7, 5)) == \ [((1, 1), {1: 1}), ((1, 2), {0: 2})] assert R.dup_isolate_real_roots_list([f, g], inf=-QQ(7, 4)) == \ [((-QQ(3, 2), -1), {0: 2}), ((1, 1), {1: 1}), ((1, 2), {0: 2})] f, g = 2*x**2 - 1, x**2 - 2 assert R.dup_isolate_real_roots_list([f, g]) == \ [((-QQ(2), -QQ(1)), {1: 1}), ((-QQ(1), QQ(0)), {0: 1}), ((QQ(0), QQ(1)), {0: 1}), ((QQ(1), QQ(2)), {1: 1})] assert R.dup_isolate_real_roots_list([f, g], strict=True) == \ [((-QQ(3, 2), -QQ(4, 3)), {1: 1}), ((-QQ(1), -QQ(2, 3)), {0: 1}), ((QQ(2, 3), QQ(1)), {0: 1}), ((QQ(4, 3), QQ(3, 2)), {1: 1})] f, g = x**2 - 2, x**3 - x**2 - 2*x + 2 assert R.dup_isolate_real_roots_list([f, g]) == \ [((-QQ(2), -QQ(1)), {1: 1, 0: 1}), ((QQ(1), QQ(1)), {1: 1}), ((QQ(1), QQ(2)), {1: 1, 0: 1})] f, g = x**3 - 2*x, x**5 - x**4 - 2*x**3 + 2*x**2 assert R.dup_isolate_real_roots_list([f, g]) == \ [((-QQ(2), -QQ(1)), {1: 1, 0: 1}), ((QQ(0), QQ(0)), {0: 1, 1: 2}), ((QQ(1), QQ(1)), {1: 1}), ((QQ(1), QQ(2)), {1: 1, 0: 1})] f, g = x**9 - 3*x**8 - x**7 + 11*x**6 - 8*x**5 - 8*x**4 + 12*x**3 - 4*x**2, x**5 - 2*x**4 + 3*x**3 - 4*x**2 + 2*x assert R.dup_isolate_real_roots_list([f, g], basis=False) == \ [((-2, -1), {0: 2}), ((0, 0), {0: 2, 1: 1}), ((1, 1), {0: 3, 1: 2}), ((1, 2), {0: 2})] assert R.dup_isolate_real_roots_list([f, g], basis=True) == \ [((-2, -1), {0: 2}, [1, 0, -2]), ((0, 0), {0: 2, 1: 1}, [1, 0]), ((1, 1), {0: 3, 1: 2}, [1, -1]), ((1, 2), {0: 2}, [1, 0, -2])] R, x = ring("x", EX) raises(DomainError, lambda: R.dup_isolate_real_roots_list([x + 3])) def test_dup_isolate_real_roots_list_QQ(): R, x = ring("x", ZZ) f = x**5 - 200 g = x**5 - 201 assert R.dup_isolate_real_roots_list([f, g]) == \ [((QQ(75, 26), QQ(101, 35)), {0: 1}), ((QQ(309, 107), QQ(26, 9)), {1: 1})] R, x = ring("x", QQ) f = -QQ(1, 200)*x**5 + 1 g = -QQ(1, 201)*x**5 + 1 assert R.dup_isolate_real_roots_list([f, g]) == \ [((QQ(75, 26), QQ(101, 35)), {0: 1}), ((QQ(309, 107), QQ(26, 9)), {1: 1})] def test_dup_count_real_roots(): R, x = ring("x", ZZ) assert R.dup_count_real_roots(0) == 0 assert R.dup_count_real_roots(7) == 0 f = x - 1 assert R.dup_count_real_roots(f) == 1 assert R.dup_count_real_roots(f, inf=1) == 1 assert R.dup_count_real_roots(f, sup=0) == 0 assert R.dup_count_real_roots(f, sup=1) == 1 assert R.dup_count_real_roots(f, inf=0, sup=1) == 1 assert R.dup_count_real_roots(f, inf=0, sup=2) == 1 assert R.dup_count_real_roots(f, inf=1, sup=2) == 1 f = x**2 - 2 assert R.dup_count_real_roots(f) == 2 assert R.dup_count_real_roots(f, sup=0) == 1 assert R.dup_count_real_roots(f, inf=-1, sup=1) == 0 # parameters for test_dup_count_complex_roots_n(): n = 1..8 a, b = (-QQ(1), -QQ(1)), (QQ(1), QQ(1)) c, d = ( QQ(0), QQ(0)), (QQ(1), QQ(1)) def test_dup_count_complex_roots_1(): R, x = ring("x", ZZ) # z-1 f = x - 1 assert R.dup_count_complex_roots(f, a, b) == 1 assert R.dup_count_complex_roots(f, c, d) == 1 # z+1 f = x + 1 assert R.dup_count_complex_roots(f, a, b) == 1 assert R.dup_count_complex_roots(f, c, d) == 0 def test_dup_count_complex_roots_2(): R, x = ring("x", ZZ) # (z-1)*(z) f = x**2 - x assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-1)*(-z) f = -x**2 + x assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 2 # (z+1)*(z) f = x**2 + x assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 1 # (z+1)*(-z) f = -x**2 - x assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 1 def test_dup_count_complex_roots_3(): R, x = ring("x", ZZ) # (z-1)*(z+1) f = x**2 - 1 assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-1)*(z+1)*(z) f = x**3 - x assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-1)*(z+1)*(-z) f = -x**3 + x assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 2 def test_dup_count_complex_roots_4(): R, x = ring("x", ZZ) # (z-I)*(z+I) f = x**2 + 1 assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I)*(z+I)*(z) f = x**3 + x assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(-z) f = -x**3 - x assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(z-1) f = x**3 - x**2 + x - 1 assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(z-1)*(z) f = x**4 - x**3 + x**2 - x assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I)*(z+I)*(z-1)*(-z) f = -x**4 + x**3 - x**2 + x assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I)*(z+I)*(z-1)*(z+1) f = x**4 - 1 assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I)*(z+I)*(z-1)*(z+1)*(z) f = x**5 - x assert R.dup_count_complex_roots(f, a, b) == 5 assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I)*(z+I)*(z-1)*(z+1)*(-z) f = -x**5 + x assert R.dup_count_complex_roots(f, a, b) == 5 assert R.dup_count_complex_roots(f, c, d) == 3 def test_dup_count_complex_roots_5(): R, x = ring("x", ZZ) # (z-I+1)*(z+I+1) f = x**2 + 2*x + 2 assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 0 # (z-I+1)*(z+I+1)*(z-1) f = x**3 + x**2 - 2 assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I+1)*(z+I+1)*(z-1)*z f = x**4 + x**3 - 2*x assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I+1)*(z+I+1)*(z+1) f = x**3 + 3*x**2 + 4*x + 2 assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 0 # (z-I+1)*(z+I+1)*(z+1)*z f = x**4 + 3*x**3 + 4*x**2 + 2*x assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I+1)*(z+I+1)*(z-1)*(z+1) f = x**4 + 2*x**3 + x**2 - 2*x - 2 assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I+1)*(z+I+1)*(z-1)*(z+1)*z f = x**5 + 2*x**4 + x**3 - 2*x**2 - 2*x assert R.dup_count_complex_roots(f, a, b) == 5 assert R.dup_count_complex_roots(f, c, d) == 2 def test_dup_count_complex_roots_6(): R, x = ring("x", ZZ) # (z-I-1)*(z+I-1) f = x**2 - 2*x + 2 assert R.dup_count_complex_roots(f, a, b) == 2 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-1) f = x**3 - 3*x**2 + 4*x - 2 assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-1)*z f = x**4 - 3*x**3 + 4*x**2 - 2*x assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I-1)*(z+I-1)*(z+1) f = x**3 - x**2 + 2 assert R.dup_count_complex_roots(f, a, b) == 3 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z+1)*z f = x**4 - x**3 + 2*x assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-1)*(z+1) f = x**4 - 2*x**3 + x**2 + 2*x - 2 assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-1)*(z+1)*z f = x**5 - 2*x**4 + x**3 + 2*x**2 - 2*x assert R.dup_count_complex_roots(f, a, b) == 5 assert R.dup_count_complex_roots(f, c, d) == 3 def test_dup_count_complex_roots_7(): R, x = ring("x", ZZ) # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1) f = x**4 + 4 assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-2) f = x**5 - 2*x**4 + 4*x - 8 assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z**2-2) f = x**6 - 2*x**4 + 4*x**2 - 8 assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1) f = x**5 - x**4 + 4*x - 4 assert R.dup_count_complex_roots(f, a, b) == 5 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*z f = x**6 - x**5 + 4*x**2 - 4*x assert R.dup_count_complex_roots(f, a, b) == 6 assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z+1) f = x**5 + x**4 + 4*x + 4 assert R.dup_count_complex_roots(f, a, b) == 5 assert R.dup_count_complex_roots(f, c, d) == 1 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z+1)*z f = x**6 + x**5 + 4*x**2 + 4*x assert R.dup_count_complex_roots(f, a, b) == 6 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1) f = x**6 - x**4 + 4*x**2 - 4 assert R.dup_count_complex_roots(f, a, b) == 6 assert R.dup_count_complex_roots(f, c, d) == 2 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*z f = x**7 - x**5 + 4*x**3 - 4*x assert R.dup_count_complex_roots(f, a, b) == 7 assert R.dup_count_complex_roots(f, c, d) == 3 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*(z-I)*(z+I) f = x**8 + 3*x**4 - 4 assert R.dup_count_complex_roots(f, a, b) == 8 assert R.dup_count_complex_roots(f, c, d) == 3 def test_dup_count_complex_roots_8(): R, x = ring("x", ZZ) # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*(z-I)*(z+I)*z f = x**9 + 3*x**5 - 4*x assert R.dup_count_complex_roots(f, a, b) == 9 assert R.dup_count_complex_roots(f, c, d) == 4 # (z-I-1)*(z+I-1)*(z-I+1)*(z+I+1)*(z-1)*(z+1)*(z-I)*(z+I)*(z**2-2)*z f = x**11 - 2*x**9 + 3*x**7 - 6*x**5 - 4*x**3 + 8*x assert R.dup_count_complex_roots(f, a, b) == 9 assert R.dup_count_complex_roots(f, c, d) == 4 def test_dup_count_complex_roots_implicit(): R, x = ring("x", ZZ) # z*(z-1)*(z+1)*(z-I)*(z+I) f = x**5 - x assert R.dup_count_complex_roots(f) == 5 assert R.dup_count_complex_roots(f, sup=(0, 0)) == 3 assert R.dup_count_complex_roots(f, inf=(0, 0)) == 3 def test_dup_count_complex_roots_exclude(): R, x = ring("x", ZZ) # z*(z-1)*(z+1)*(z-I)*(z+I) f = x**5 - x a, b = (-QQ(1), QQ(0)), (QQ(1), QQ(1)) assert R.dup_count_complex_roots(f, a, b) == 4 assert R.dup_count_complex_roots(f, a, b, exclude=['S']) == 3 assert R.dup_count_complex_roots(f, a, b, exclude=['N']) == 3 assert R.dup_count_complex_roots(f, a, b, exclude=['S', 'N']) == 2 assert R.dup_count_complex_roots(f, a, b, exclude=['E']) == 4 assert R.dup_count_complex_roots(f, a, b, exclude=['W']) == 4 assert R.dup_count_complex_roots(f, a, b, exclude=['E', 'W']) == 4 assert R.dup_count_complex_roots(f, a, b, exclude=['N', 'S', 'E', 'W']) == 2 assert R.dup_count_complex_roots(f, a, b, exclude=['SW']) == 3 assert R.dup_count_complex_roots(f, a, b, exclude=['SE']) == 3 assert R.dup_count_complex_roots(f, a, b, exclude=['SW', 'SE']) == 2 assert R.dup_count_complex_roots(f, a, b, exclude=['SW', 'SE', 'S']) == 1 assert R.dup_count_complex_roots(f, a, b, exclude=['SW', 'SE', 'S', 'N']) == 0 a, b = (QQ(0), QQ(0)), (QQ(1), QQ(1)) assert R.dup_count_complex_roots(f, a, b, exclude=True) == 1 def test_dup_isolate_complex_roots_sqf(): R, x = ring("x", ZZ) f = x**2 - 2*x + 3 assert R.dup_isolate_complex_roots_sqf(f) == \ [((0, -6), (6, 0)), ((0, 0), (6, 6))] assert [ r.as_tuple() for r in R.dup_isolate_complex_roots_sqf(f, blackbox=True) ] == \ [((0, -6), (6, 0)), ((0, 0), (6, 6))] assert R.dup_isolate_complex_roots_sqf(f, eps=QQ(1, 10)) == \ [((QQ(15, 16), -QQ(3, 2)), (QQ(33, 32), -QQ(45, 32))), ((QQ(15, 16), QQ(45, 32)), (QQ(33, 32), QQ(3, 2)))] assert R.dup_isolate_complex_roots_sqf(f, eps=QQ(1, 100)) == \ [((QQ(255, 256), -QQ(363, 256)), (QQ(513, 512), -QQ(723, 512))), ((QQ(255, 256), QQ(723, 512)), (QQ(513, 512), QQ(363, 256)))] f = 7*x**4 - 19*x**3 + 20*x**2 + 17*x + 20 assert R.dup_isolate_complex_roots_sqf(f) == \ [((-QQ(40, 7), -QQ(40, 7)), (0, 0)), ((-QQ(40, 7), 0), (0, QQ(40, 7))), ((0, -QQ(40, 7)), (QQ(40, 7), 0)), ((0, 0), (QQ(40, 7), QQ(40, 7)))] def test_dup_isolate_all_roots_sqf(): R, x = ring("x", ZZ) f = 4*x**4 - x**3 + 2*x**2 + 5*x assert R.dup_isolate_all_roots_sqf(f) == \ ([(-1, 0), (0, 0)], [((0, -QQ(5, 2)), (QQ(5, 2), 0)), ((0, 0), (QQ(5, 2), QQ(5, 2)))]) assert R.dup_isolate_all_roots_sqf(f, eps=QQ(1, 10)) == \ ([(QQ(-7, 8), QQ(-6, 7)), (0, 0)], [((QQ(35, 64), -QQ(35, 32)), (QQ(5, 8), -QQ(65, 64))), ((QQ(35, 64), QQ(65, 64)), (QQ(5, 8), QQ(35, 32)))]) def test_dup_isolate_all_roots(): R, x = ring("x", ZZ) f = 4*x**4 - x**3 + 2*x**2 + 5*x assert R.dup_isolate_all_roots(f) == \ ([((-1, 0), 1), ((0, 0), 1)], [(((0, -QQ(5, 2)), (QQ(5, 2), 0)), 1), (((0, 0), (QQ(5, 2), QQ(5, 2))), 1)]) assert R.dup_isolate_all_roots(f, eps=QQ(1, 10)) == \ ([((QQ(-7, 8), QQ(-6, 7)), 1), ((0, 0), 1)], [(((QQ(35, 64), -QQ(35, 32)), (QQ(5, 8), -QQ(65, 64))), 1), (((QQ(35, 64), QQ(65, 64)), (QQ(5, 8), QQ(35, 32))), 1)]) f = x**5 + x**4 - 2*x**3 - 2*x**2 + x + 1 raises(NotImplementedError, lambda: R.dup_isolate_all_roots(f)) sympy-sympy-1.9/sympy/polys/tests/test_rootoftools.py000066400000000000000000000467021412543434000234270ustar00rootroot00000000000000"""Tests for the implementation of RootOf class and related tools. """ from sympy.polys.polytools import Poly from sympy.polys.rootoftools import (rootof, RootOf, CRootOf, RootSum, _pure_key_dict as D) from sympy.polys.polyerrors import ( MultivariatePolynomialError, GeneratorsNeeded, PolynomialError, ) from sympy import ( S, sqrt, I, Rational, Float, Lambda, log, exp, tan, Function, Eq, solve, legendre_poly, Integral ) from sympy.testing.pytest import raises, slow from sympy.core.expr import unchanged from sympy.abc import a, b, x, y, z, r def test_CRootOf___new__(): assert rootof(x, 0) == 0 assert rootof(x, -1) == 0 assert rootof(x, S.Zero) == 0 assert rootof(x - 1, 0) == 1 assert rootof(x - 1, -1) == 1 assert rootof(x + 1, 0) == -1 assert rootof(x + 1, -1) == -1 assert rootof(x**2 + 2*x + 3, 0) == -1 - I*sqrt(2) assert rootof(x**2 + 2*x + 3, 1) == -1 + I*sqrt(2) assert rootof(x**2 + 2*x + 3, -1) == -1 + I*sqrt(2) assert rootof(x**2 + 2*x + 3, -2) == -1 - I*sqrt(2) r = rootof(x**2 + 2*x + 3, 0, radicals=False) assert isinstance(r, RootOf) is True r = rootof(x**2 + 2*x + 3, 1, radicals=False) assert isinstance(r, RootOf) is True r = rootof(x**2 + 2*x + 3, -1, radicals=False) assert isinstance(r, RootOf) is True r = rootof(x**2 + 2*x + 3, -2, radicals=False) assert isinstance(r, RootOf) is True assert rootof((x - 1)*(x + 1), 0, radicals=False) == -1 assert rootof((x - 1)*(x + 1), 1, radicals=False) == 1 assert rootof((x - 1)*(x + 1), -1, radicals=False) == 1 assert rootof((x - 1)*(x + 1), -2, radicals=False) == -1 assert rootof((x - 1)*(x + 1), 0, radicals=True) == -1 assert rootof((x - 1)*(x + 1), 1, radicals=True) == 1 assert rootof((x - 1)*(x + 1), -1, radicals=True) == 1 assert rootof((x - 1)*(x + 1), -2, radicals=True) == -1 assert rootof((x - 1)*(x**3 + x + 3), 0) == rootof(x**3 + x + 3, 0) assert rootof((x - 1)*(x**3 + x + 3), 1) == 1 assert rootof((x - 1)*(x**3 + x + 3), 2) == rootof(x**3 + x + 3, 1) assert rootof((x - 1)*(x**3 + x + 3), 3) == rootof(x**3 + x + 3, 2) assert rootof((x - 1)*(x**3 + x + 3), -1) == rootof(x**3 + x + 3, 2) assert rootof((x - 1)*(x**3 + x + 3), -2) == rootof(x**3 + x + 3, 1) assert rootof((x - 1)*(x**3 + x + 3), -3) == 1 assert rootof((x - 1)*(x**3 + x + 3), -4) == rootof(x**3 + x + 3, 0) assert rootof(x**4 + 3*x**3, 0) == -3 assert rootof(x**4 + 3*x**3, 1) == 0 assert rootof(x**4 + 3*x**3, 2) == 0 assert rootof(x**4 + 3*x**3, 3) == 0 raises(GeneratorsNeeded, lambda: rootof(0, 0)) raises(GeneratorsNeeded, lambda: rootof(1, 0)) raises(PolynomialError, lambda: rootof(Poly(0, x), 0)) raises(PolynomialError, lambda: rootof(Poly(1, x), 0)) raises(PolynomialError, lambda: rootof(x - y, 0)) # issue 8617 raises(PolynomialError, lambda: rootof(exp(x), 0)) raises(NotImplementedError, lambda: rootof(x**3 - x + sqrt(2), 0)) raises(NotImplementedError, lambda: rootof(x**3 - x + I, 0)) raises(IndexError, lambda: rootof(x**2 - 1, -4)) raises(IndexError, lambda: rootof(x**2 - 1, -3)) raises(IndexError, lambda: rootof(x**2 - 1, 2)) raises(IndexError, lambda: rootof(x**2 - 1, 3)) raises(ValueError, lambda: rootof(x**2 - 1, x)) assert rootof(Poly(x - y, x), 0) == y assert rootof(Poly(x**2 - y, x), 0) == -sqrt(y) assert rootof(Poly(x**2 - y, x), 1) == sqrt(y) assert rootof(Poly(x**3 - y, x), 0) == y**Rational(1, 3) assert rootof(y*x**3 + y*x + 2*y, x, 0) == -1 raises(NotImplementedError, lambda: rootof(x**3 + x + 2*y, x, 0)) assert rootof(x**3 + x + 1, 0).is_commutative is True def test_CRootOf_attributes(): r = rootof(x**3 + x + 3, 0) assert r.is_number assert r.free_symbols == set() # if the following assertion fails then multivariate polynomials # are apparently supported and the RootOf.free_symbols routine # should be changed to return whatever symbols would not be # the PurePoly dummy symbol raises(NotImplementedError, lambda: rootof(Poly(x**3 + y*x + 1, x), 0)) def test_CRootOf___eq__(): assert (rootof(x**3 + x + 3, 0) == rootof(x**3 + x + 3, 0)) is True assert (rootof(x**3 + x + 3, 0) == rootof(x**3 + x + 3, 1)) is False assert (rootof(x**3 + x + 3, 1) == rootof(x**3 + x + 3, 1)) is True assert (rootof(x**3 + x + 3, 1) == rootof(x**3 + x + 3, 2)) is False assert (rootof(x**3 + x + 3, 2) == rootof(x**3 + x + 3, 2)) is True assert (rootof(x**3 + x + 3, 0) == rootof(y**3 + y + 3, 0)) is True assert (rootof(x**3 + x + 3, 0) == rootof(y**3 + y + 3, 1)) is False assert (rootof(x**3 + x + 3, 1) == rootof(y**3 + y + 3, 1)) is True assert (rootof(x**3 + x + 3, 1) == rootof(y**3 + y + 3, 2)) is False assert (rootof(x**3 + x + 3, 2) == rootof(y**3 + y + 3, 2)) is True def test_CRootOf___eval_Eq__(): f = Function('f') eq = x**3 + x + 3 r = rootof(eq, 2) r1 = rootof(eq, 1) assert Eq(r, r1) is S.false assert Eq(r, r) is S.true assert unchanged(Eq, r, x) assert Eq(r, 0) is S.false assert Eq(r, S.Infinity) is S.false assert Eq(r, I) is S.false assert unchanged(Eq, r, f(0)) sol = solve(eq) for s in sol: if s.is_real: assert Eq(r, s) is S.false r = rootof(eq, 0) for s in sol: if s.is_real: assert Eq(r, s) is S.true eq = x**3 + x + 1 sol = solve(eq) assert [Eq(rootof(eq, i), j) for i in range(3) for j in sol] == [ False, False, True, False, True, False, True, False, False] assert Eq(rootof(eq, 0), 1 + S.ImaginaryUnit) == False def test_CRootOf_is_real(): assert rootof(x**3 + x + 3, 0).is_real is True assert rootof(x**3 + x + 3, 1).is_real is False assert rootof(x**3 + x + 3, 2).is_real is False def test_CRootOf_is_complex(): assert rootof(x**3 + x + 3, 0).is_complex is True def test_CRootOf_subs(): assert rootof(x**3 + x + 1, 0).subs(x, y) == rootof(y**3 + y + 1, 0) def test_CRootOf_diff(): assert rootof(x**3 + x + 1, 0).diff(x) == 0 assert rootof(x**3 + x + 1, 0).diff(y) == 0 @slow def test_CRootOf_evalf(): real = rootof(x**3 + x + 3, 0).evalf(n=20) assert real.epsilon_eq(Float("-1.2134116627622296341")) re, im = rootof(x**3 + x + 3, 1).evalf(n=20).as_real_imag() assert re.epsilon_eq( Float("0.60670583138111481707")) assert im.epsilon_eq(-Float("1.45061224918844152650")) re, im = rootof(x**3 + x + 3, 2).evalf(n=20).as_real_imag() assert re.epsilon_eq(Float("0.60670583138111481707")) assert im.epsilon_eq(Float("1.45061224918844152650")) p = legendre_poly(4, x, polys=True) roots = [str(r.n(17)) for r in p.real_roots()] # magnitudes are given by # sqrt(3/S(7) - 2*sqrt(6/S(5))/7) # and # sqrt(3/S(7) + 2*sqrt(6/S(5))/7) assert roots == [ "-0.86113631159405258", "-0.33998104358485626", "0.33998104358485626", "0.86113631159405258", ] re = rootof(x**5 - 5*x + 12, 0).evalf(n=20) assert re.epsilon_eq(Float("-1.84208596619025438271")) re, im = rootof(x**5 - 5*x + 12, 1).evalf(n=20).as_real_imag() assert re.epsilon_eq(Float("-0.351854240827371999559")) assert im.epsilon_eq(Float("-1.709561043370328882010")) re, im = rootof(x**5 - 5*x + 12, 2).evalf(n=20).as_real_imag() assert re.epsilon_eq(Float("-0.351854240827371999559")) assert im.epsilon_eq(Float("+1.709561043370328882010")) re, im = rootof(x**5 - 5*x + 12, 3).evalf(n=20).as_real_imag() assert re.epsilon_eq(Float("+1.272897223922499190910")) assert im.epsilon_eq(Float("-0.719798681483861386681")) re, im = rootof(x**5 - 5*x + 12, 4).evalf(n=20).as_real_imag() assert re.epsilon_eq(Float("+1.272897223922499190910")) assert im.epsilon_eq(Float("+0.719798681483861386681")) # issue 6393 assert str(rootof(x**5 + 2*x**4 + x**3 - 68719476736, 0).n(3)) == '147.' eq = (531441*x**11 + 3857868*x**10 + 13730229*x**9 + 32597882*x**8 + 55077472*x**7 + 60452000*x**6 + 32172064*x**5 - 4383808*x**4 - 11942912*x**3 - 1506304*x**2 + 1453312*x + 512) a, b = rootof(eq, 1).n(2).as_real_imag() c, d = rootof(eq, 2).n(2).as_real_imag() assert a == c assert b < d assert b == -d # issue 6451 r = rootof(legendre_poly(64, x), 7) assert r.n(2) == r.n(100).n(2) # issue 9019 r0 = rootof(x**2 + 1, 0, radicals=False) r1 = rootof(x**2 + 1, 1, radicals=False) assert r0.n(4) == -1.0*I assert r1.n(4) == 1.0*I # make sure verification is used in case a max/min traps the "root" assert str(rootof(4*x**5 + 16*x**3 + 12*x**2 + 7, 0).n(3)) == '-0.976' # watch out for UnboundLocalError c = CRootOf(90720*x**6 - 4032*x**4 + 84*x**2 - 1, 0) assert c._eval_evalf(2) # doesn't fail # watch out for imaginary parts that don't want to evaluate assert str(RootOf(x**16 + 32*x**14 + 508*x**12 + 5440*x**10 + 39510*x**8 + 204320*x**6 + 755548*x**4 + 1434496*x**2 + 877969, 10).n(2)) == '-3.4*I' assert abs(RootOf(x**4 + 10*x**2 + 1, 0).n(2)) < 0.4 # check reset and args r = [RootOf(x**3 + x + 3, i) for i in range(3)] r[0]._reset() for ri in r: i = ri._get_interval() ri.n(2) assert i != ri._get_interval() ri._reset() assert i == ri._get_interval() assert i == i.func(*i.args) def test_CRootOf_evalf_caching_bug(): r = rootof(x**5 - 5*x + 12, 1) r.n() a = r._get_interval() r = rootof(x**5 - 5*x + 12, 1) r.n() b = r._get_interval() assert a == b def test_CRootOf_real_roots(): assert Poly(x**5 + x + 1).real_roots() == [rootof(x**3 - x**2 + 1, 0)] assert Poly(x**5 + x + 1).real_roots(radicals=False) == [rootof( x**3 - x**2 + 1, 0)] # https://github.com/sympy/sympy/issues/20902 p = Poly(-3*x**4 - 10*x**3 - 12*x**2 - 6*x - 1, x, domain='ZZ') assert CRootOf.real_roots(p) == [S(-1), S(-1), S(-1), S(-1)/3] def test_CRootOf_all_roots(): assert Poly(x**5 + x + 1).all_roots() == [ rootof(x**3 - x**2 + 1, 0), Rational(-1, 2) - sqrt(3)*I/2, Rational(-1, 2) + sqrt(3)*I/2, rootof(x**3 - x**2 + 1, 1), rootof(x**3 - x**2 + 1, 2), ] assert Poly(x**5 + x + 1).all_roots(radicals=False) == [ rootof(x**3 - x**2 + 1, 0), rootof(x**2 + x + 1, 0, radicals=False), rootof(x**2 + x + 1, 1, radicals=False), rootof(x**3 - x**2 + 1, 1), rootof(x**3 - x**2 + 1, 2), ] def test_CRootOf_eval_rational(): p = legendre_poly(4, x, polys=True) roots = [r.eval_rational(n=18) for r in p.real_roots()] for root in roots: assert isinstance(root, Rational) roots = [str(root.n(17)) for root in roots] assert roots == [ "-0.86113631159405258", "-0.33998104358485626", "0.33998104358485626", "0.86113631159405258", ] def test_RootSum___new__(): f = x**3 + x + 3 g = Lambda(r, log(r*x)) s = RootSum(f, g) assert isinstance(s, RootSum) is True assert RootSum(f**2, g) == 2*RootSum(f, g) assert RootSum((x - 7)*f**3, g) == log(7*x) + 3*RootSum(f, g) # issue 5571 assert hash(RootSum((x - 7)*f**3, g)) == hash(log(7*x) + 3*RootSum(f, g)) raises(MultivariatePolynomialError, lambda: RootSum(x**3 + x + y)) raises(ValueError, lambda: RootSum(x**2 + 3, lambda x: x)) assert RootSum(f, exp) == RootSum(f, Lambda(x, exp(x))) assert RootSum(f, log) == RootSum(f, Lambda(x, log(x))) assert isinstance(RootSum(f, auto=False), RootSum) is True assert RootSum(f) == 0 assert RootSum(f, Lambda(x, x)) == 0 assert RootSum(f, Lambda(x, x**2)) == -2 assert RootSum(f, Lambda(x, 1)) == 3 assert RootSum(f, Lambda(x, 2)) == 6 assert RootSum(f, auto=False).is_commutative is True assert RootSum(f, Lambda(x, 1/(x + x**2))) == Rational(11, 3) assert RootSum(f, Lambda(x, y/(x + x**2))) == Rational(11, 3)*y assert RootSum(x**2 - 1, Lambda(x, 3*x**2), x) == 6 assert RootSum(x**2 - y, Lambda(x, 3*x**2), x) == 6*y assert RootSum(x**2 - 1, Lambda(x, z*x**2), x) == 2*z assert RootSum(x**2 - y, Lambda(x, z*x**2), x) == 2*z*y assert RootSum( x**2 - 1, Lambda(x, exp(x)), quadratic=True) == exp(-1) + exp(1) assert RootSum(x**3 + a*x + a**3, tan, x) == \ RootSum(x**3 + x + 1, Lambda(x, tan(a*x))) assert RootSum(a**3*x**3 + a*x + 1, tan, x) == \ RootSum(x**3 + x + 1, Lambda(x, tan(x/a))) def test_RootSum_free_symbols(): assert RootSum(x**3 + x + 3, Lambda(r, exp(r))).free_symbols == set() assert RootSum(x**3 + x + 3, Lambda(r, exp(a*r))).free_symbols == {a} assert RootSum( x**3 + x + y, Lambda(r, exp(a*r)), x).free_symbols == {a, y} def test_RootSum___eq__(): f = Lambda(x, exp(x)) assert (RootSum(x**3 + x + 1, f) == RootSum(x**3 + x + 1, f)) is True assert (RootSum(x**3 + x + 1, f) == RootSum(y**3 + y + 1, f)) is True assert (RootSum(x**3 + x + 1, f) == RootSum(x**3 + x + 2, f)) is False assert (RootSum(x**3 + x + 1, f) == RootSum(y**3 + y + 2, f)) is False def test_RootSum_doit(): rs = RootSum(x**2 + 1, exp) assert isinstance(rs, RootSum) is True assert rs.doit() == exp(-I) + exp(I) rs = RootSum(x**2 + a, exp, x) assert isinstance(rs, RootSum) is True assert rs.doit() == exp(-sqrt(-a)) + exp(sqrt(-a)) def test_RootSum_evalf(): rs = RootSum(x**2 + 1, exp) assert rs.evalf(n=20, chop=True).epsilon_eq(Float("1.0806046117362794348")) assert rs.evalf(n=15, chop=True).epsilon_eq(Float("1.08060461173628")) rs = RootSum(x**2 + a, exp, x) assert rs.evalf() == rs def test_RootSum_diff(): f = x**3 + x + 3 g = Lambda(r, exp(r*x)) h = Lambda(r, r*exp(r*x)) assert RootSum(f, g).diff(x) == RootSum(f, h) def test_RootSum_subs(): f = x**3 + x + 3 g = Lambda(r, exp(r*x)) F = y**3 + y + 3 G = Lambda(r, exp(r*y)) assert RootSum(f, g).subs(y, 1) == RootSum(f, g) assert RootSum(f, g).subs(x, y) == RootSum(F, G) def test_RootSum_rational(): assert RootSum( z**5 - z + 1, Lambda(z, z/(x - z))) == (4*x - 5)/(x**5 - x + 1) f = 161*z**3 + 115*z**2 + 19*z + 1 g = Lambda(z, z*log( -3381*z**4/4 - 3381*z**3/4 - 625*z**2/2 - z*Rational(125, 2) - 5 + exp(x))) assert RootSum(f, g).diff(x) == -( (5*exp(2*x) - 6*exp(x) + 4)*exp(x)/(exp(3*x) - exp(2*x) + 1))/7 def test_RootSum_independent(): f = (x**3 - a)**2*(x**4 - b)**3 g = Lambda(x, 5*tan(x) + 7) h = Lambda(x, tan(x)) r0 = RootSum(x**3 - a, h, x) r1 = RootSum(x**4 - b, h, x) assert RootSum(f, g, x).as_ordered_terms() == [10*r0, 15*r1, 126] def test_issue_7876(): l1 = Poly(x**6 - x + 1, x).all_roots() l2 = [rootof(x**6 - x + 1, i) for i in range(6)] assert frozenset(l1) == frozenset(l2) def test_issue_8316(): f = Poly(7*x**8 - 9) assert len(f.all_roots()) == 8 f = Poly(7*x**8 - 10) assert len(f.all_roots()) == 8 def test__imag_count(): from sympy.polys.rootoftools import _imag_count_of_factor def imag_count(p): return sum([_imag_count_of_factor(f)*m for f, m in p.factor_list()[1]]) assert imag_count(Poly(x**6 + 10*x**2 + 1)) == 2 assert imag_count(Poly(x**2)) == 0 assert imag_count(Poly([1]*3 + [-1], x)) == 0 assert imag_count(Poly(x**3 + 1)) == 0 assert imag_count(Poly(x**2 + 1)) == 2 assert imag_count(Poly(x**2 - 1)) == 0 assert imag_count(Poly(x**4 - 1)) == 2 assert imag_count(Poly(x**4 + 1)) == 0 assert imag_count(Poly([1, 2, 3], x)) == 0 assert imag_count(Poly(x**3 + x + 1)) == 0 assert imag_count(Poly(x**4 + x + 1)) == 0 def q(r1, r2, p): return Poly(((x - r1)*(x - r2)).subs(x, x**p), x) assert imag_count(q(-1, -2, 2)) == 4 assert imag_count(q(-1, 2, 2)) == 2 assert imag_count(q(1, 2, 2)) == 0 assert imag_count(q(1, 2, 4)) == 4 assert imag_count(q(-1, 2, 4)) == 2 assert imag_count(q(-1, -2, 4)) == 0 def test_RootOf_is_imaginary(): r = RootOf(x**4 + 4*x**2 + 1, 1) i = r._get_interval() assert r.is_imaginary and i.ax*i.bx <= 0 def test_is_disjoint(): eq = x**3 + 5*x + 1 ir = rootof(eq, 0)._get_interval() ii = rootof(eq, 1)._get_interval() assert ir.is_disjoint(ii) assert ii.is_disjoint(ir) def test_pure_key_dict(): p = D() assert (x in p) is False assert (1 in p) is False p[x] = 1 assert x in p assert y in p assert p[y] == 1 raises(KeyError, lambda: p[1]) def dont(k): p[k] = 2 raises(ValueError, lambda: dont(1)) @slow def test_eval_approx_relative(): CRootOf.clear_cache() t = [CRootOf(x**3 + 10*x + 1, i) for i in range(3)] assert [i.eval_rational(1e-1) for i in t] == [ Rational(-21, 220), Rational(15, 256) - I*Rational(805, 256), Rational(15, 256) + I*Rational(805, 256)] t[0]._reset() assert [i.eval_rational(1e-1, 1e-4) for i in t] == [ Rational(-21, 220), Rational(3275, 65536) - I*Rational(414645, 131072), Rational(3275, 65536) + I*Rational(414645, 131072)] assert S(t[0]._get_interval().dx) < 1e-1 assert S(t[1]._get_interval().dx) < 1e-1 assert S(t[1]._get_interval().dy) < 1e-4 assert S(t[2]._get_interval().dx) < 1e-1 assert S(t[2]._get_interval().dy) < 1e-4 t[0]._reset() assert [i.eval_rational(1e-4, 1e-4) for i in t] == [ Rational(-2001, 20020), Rational(6545, 131072) - I*Rational(414645, 131072), Rational(6545, 131072) + I*Rational(414645, 131072)] assert S(t[0]._get_interval().dx) < 1e-4 assert S(t[1]._get_interval().dx) < 1e-4 assert S(t[1]._get_interval().dy) < 1e-4 assert S(t[2]._get_interval().dx) < 1e-4 assert S(t[2]._get_interval().dy) < 1e-4 # in the following, the actual relative precision is # less than tested, but it should never be greater t[0]._reset() assert [i.eval_rational(n=2) for i in t] == [ Rational(-202201, 2024022), Rational(104755, 2097152) - I*Rational(6634255, 2097152), Rational(104755, 2097152) + I*Rational(6634255, 2097152)] assert abs(S(t[0]._get_interval().dx)/t[0]) < 1e-2 assert abs(S(t[1]._get_interval().dx)/t[1]).n() < 1e-2 assert abs(S(t[1]._get_interval().dy)/t[1]).n() < 1e-2 assert abs(S(t[2]._get_interval().dx)/t[2]).n() < 1e-2 assert abs(S(t[2]._get_interval().dy)/t[2]).n() < 1e-2 t[0]._reset() assert [i.eval_rational(n=3) for i in t] == [ Rational(-202201, 2024022), Rational(1676045, 33554432) - I*Rational(106148135, 33554432), Rational(1676045, 33554432) + I*Rational(106148135, 33554432)] assert abs(S(t[0]._get_interval().dx)/t[0]) < 1e-3 assert abs(S(t[1]._get_interval().dx)/t[1]).n() < 1e-3 assert abs(S(t[1]._get_interval().dy)/t[1]).n() < 1e-3 assert abs(S(t[2]._get_interval().dx)/t[2]).n() < 1e-3 assert abs(S(t[2]._get_interval().dy)/t[2]).n() < 1e-3 t[0]._reset() a = [i.eval_approx(2) for i in t] assert [str(i) for i in a] == [ '-0.10', '0.05 - 3.2*I', '0.05 + 3.2*I'] assert all(abs(((a[i] - t[i])/t[i]).n()) < 1e-2 for i in range(len(a))) def test_issue_15920(): r = rootof(x**5 - x + 1, 0) p = Integral(x, (x, 1, y)) assert unchanged(Eq, r, p) def test_issue_19113(): eq = y**3 - y + 1 # generator is a canonical x in RootOf assert str(Poly(eq).real_roots()) == '[CRootOf(x**3 - x + 1, 0)]' assert str(Poly(eq.subs(y, tan(y))).real_roots() ) == '[CRootOf(x**3 - x + 1, 0)]' assert str(Poly(eq.subs(y, tan(x))).real_roots() ) == '[CRootOf(x**3 - x + 1, 0)]' sympy-sympy-1.9/sympy/polys/tests/test_solvers.py000066400000000000000000000325271412543434000225330ustar00rootroot00000000000000"""Tests for low-level linear systems solver. """ from sympy.matrices import Matrix from sympy.polys.domains import ZZ, QQ from sympy.polys.fields import field from sympy.polys.rings import ring from sympy.polys.solvers import solve_lin_sys, eqs_to_matrix def test_solve_lin_sys_2x2_one(): domain, x1,x2 = ring("x1,x2", QQ) eqs = [x1 + x2 - 5, 2*x1 - x2] sol = {x1: QQ(5, 3), x2: QQ(10, 3)} _sol = solve_lin_sys(eqs, domain) assert _sol == sol and all(isinstance(s, domain.dtype) for s in _sol) def test_solve_lin_sys_2x4_none(): domain, x1,x2 = ring("x1,x2", QQ) eqs = [x1 - 1, x1 - x2, x1 - 2*x2, x2 - 1] assert solve_lin_sys(eqs, domain) is None def test_solve_lin_sys_3x4_one(): domain, x1,x2,x3 = ring("x1,x2,x3", QQ) eqs = [x1 + 2*x2 + 3*x3, 2*x1 - x2 + x3, 3*x1 + x2 + x3, 5*x2 + 2*x3] sol = {x1: 0, x2: 0, x3: 0} assert solve_lin_sys(eqs, domain) == sol def test_solve_lin_sys_3x3_inf(): domain, x1,x2,x3 = ring("x1,x2,x3", QQ) eqs = [x1 - x2 + 2*x3 - 1, 2*x1 + x2 + x3 - 8, x1 + x2 - 5] sol = {x1: -x3 + 3, x2: x3 + 2} assert solve_lin_sys(eqs, domain) == sol def test_solve_lin_sys_3x4_none(): domain, x1,x2,x3,x4 = ring("x1,x2,x3,x4", QQ) eqs = [2*x1 + x2 + 7*x3 - 7*x4 - 2, -3*x1 + 4*x2 - 5*x3 - 6*x4 - 3, x1 + x2 + 4*x3 - 5*x4 - 2] assert solve_lin_sys(eqs, domain) is None def test_solve_lin_sys_4x7_inf(): domain, x1,x2,x3,x4,x5,x6,x7 = ring("x1,x2,x3,x4,x5,x6,x7", QQ) eqs = [x1 + 4*x2 - x4 + 7*x6 - 9*x7 - 3, 2*x1 + 8*x2 - x3 + 3*x4 + 9*x5 - 13*x6 + 7*x7 - 9, 2*x3 - 3*x4 - 4*x5 + 12*x6 - 8*x7 - 1, -x1 - 4*x2 + 2*x3 + 4*x4 + 8*x5 - 31*x6 + 37*x7 - 4] sol = {x1: 4 - 4*x2 - 2*x5 - x6 + 3*x7, x3: 2 - x5 + 3*x6 - 5*x7, x4: 1 - 2*x5 + 6*x6 - 6*x7} assert solve_lin_sys(eqs, domain) == sol def test_solve_lin_sys_5x5_inf(): domain, x1,x2,x3,x4,x5 = ring("x1,x2,x3,x4,x5", QQ) eqs = [x1 - x2 - 2*x3 + x4 + 11*x5 - 13, x1 - x2 + x3 + x4 + 5*x5 - 16, 2*x1 - 2*x2 + x4 + 10*x5 - 21, 2*x1 - 2*x2 - x3 + 3*x4 + 20*x5 - 38, 2*x1 - 2*x2 + x3 + x4 + 8*x5 - 22] sol = {x1: 6 + x2 - 3*x5, x3: 1 + 2*x5, x4: 9 - 4*x5} assert solve_lin_sys(eqs, domain) == sol def test_solve_lin_sys_6x6_1(): ground, d,r,e,g,i,j,l,o,m,p,q = field("d,r,e,g,i,j,l,o,m,p,q", ZZ) domain, c,f,h,k,n,b = ring("c,f,h,k,n,b", ground) eqs = [b + q/d - c/d, c*(1/d + 1/e + 1/g) - f/g - q/d, f*(1/g + 1/i + 1/j) - c/g - h/i, h*(1/i + 1/l + 1/m) - f/i - k/m, k*(1/m + 1/o + 1/p) - h/m - n/p, n/p - k/p] sol = { b: (e*i*l*q + e*i*m*q + e*i*o*q + e*j*l*q + e*j*m*q + e*j*o*q + e*l*m*q + e*l*o*q + g*i*l*q + g*i*m*q + g*i*o*q + g*j*l*q + g*j*m*q + g*j*o*q + g*l*m*q + g*l*o*q + i*j*l*q + i*j*m*q + i*j*o*q + j*l*m*q + j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), c: (-e*g*i*l*q - e*g*i*m*q - e*g*i*o*q - e*g*j*l*q - e*g*j*m*q - e*g*j*o*q - e*g*l*m*q - e*g*l*o*q - e*i*j*l*q - e*i*j*m*q - e*i*j*o*q - e*j*l*m*q - e*j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), f: (-e*i*j*l*q - e*i*j*m*q - e*i*j*o*q - e*j*l*m*q - e*j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), h: (-e*j*l*m*q - e*j*l*o*q)/(-d*e*i*l - d*e*i*m - d*e*i*o - d*e*j*l - d*e*j*m - d*e*j*o - d*e*l*m - d*e*l*o - d*g*i*l - d*g*i*m - d*g*i*o - d*g*j*l - d*g*j*m - d*g*j*o - d*g*l*m - d*g*l*o - d*i*j*l - d*i*j*m - d*i*j*o - d*j*l*m - d*j*l*o - e*g*i*l - e*g*i*m - e*g*i*o - e*g*j*l - e*g*j*m - e*g*j*o - e*g*l*m - e*g*l*o - e*i*j*l - e*i*j*m - e*i*j*o - e*j*l*m - e*j*l*o), k: e*j*l*o*q/(d*e*i*l + d*e*i*m + d*e*i*o + d*e*j*l + d*e*j*m + d*e*j*o + d*e*l*m + d*e*l*o + d*g*i*l + d*g*i*m + d*g*i*o + d*g*j*l + d*g*j*m + d*g*j*o + d*g*l*m + d*g*l*o + d*i*j*l + d*i*j*m + d*i*j*o + d*j*l*m + d*j*l*o + e*g*i*l + e*g*i*m + e*g*i*o + e*g*j*l + e*g*j*m + e*g*j*o + e*g*l*m + e*g*l*o + e*i*j*l + e*i*j*m + e*i*j*o + e*j*l*m + e*j*l*o), n: e*j*l*o*q/(d*e*i*l + d*e*i*m + d*e*i*o + d*e*j*l + d*e*j*m + d*e*j*o + d*e*l*m + d*e*l*o + d*g*i*l + d*g*i*m + d*g*i*o + d*g*j*l + d*g*j*m + d*g*j*o + d*g*l*m + d*g*l*o + d*i*j*l + d*i*j*m + d*i*j*o + d*j*l*m + d*j*l*o + e*g*i*l + e*g*i*m + e*g*i*o + e*g*j*l + e*g*j*m + e*g*j*o + e*g*l*m + e*g*l*o + e*i*j*l + e*i*j*m + e*i*j*o + e*j*l*m + e*j*l*o), } assert solve_lin_sys(eqs, domain) == sol def test_solve_lin_sys_6x6_2(): ground, d,r,e,g,i,j,l,o,m,p,q = field("d,r,e,g,i,j,l,o,m,p,q", ZZ) domain, c,f,h,k,n,b = ring("c,f,h,k,n,b", ground) eqs = [b + r/d - c/d, c*(1/d + 1/e + 1/g) - f/g - r/d, f*(1/g + 1/i + 1/j) - c/g - h/i, h*(1/i + 1/l + 1/m) - f/i - k/m, k*(1/m + 1/o + 1/p) - h/m - n/p, n*(1/p + 1/q) - k/p] sol = { b: -((l*q*e*o + l*q*g*o + i*m*q*e + i*l*q*e + i*l*p*e + i*j*o*q + j*e*o*q + g*j*o*q + i*e*o*q + g*i*o*q + e*l*o*p + e*l*m*p + e*l*m*o + e*i*o*p + e*i*m*p + e*i*m*o + e*i*l*o + j*e*o*p + j*e*m*q + j*e*m*p + j*e*m*o + j*l*m*q + j*l*m*p + j*l*m*o + i*j*m*p + i*j*m*o + i*j*l*q + i*j*l*o + i*j*m*q + j*l*o*p + j*e*l*o + g*j*o*p + g*j*m*q + g*j*m*p + i*j*l*p + i*j*o*p + j*e*l*q + j*e*l*p + j*l*o*q + g*j*m*o + g*j*l*q + g*j*l*p + g*j*l*o + g*l*o*p + g*l*m*p + g*l*m*o + g*i*m*o + g*i*o*p + g*i*m*q + g*i*m*p + g*i*l*q + g*i*l*p + g*i*l*o + l*m*q*e + l*m*q*g)*r)/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), c: (r*e*(l*q*g*o + i*j*o*q + g*j*o*q + g*i*o*q + j*l*m*q + j*l*m*p + j*l*m*o + i*j*m*p + i*j*m*o + i*j*l*q + i*j*l*o + i*j*m*q + j*l*o*p + g*j*o*p + g*j*m*q + g*j*m*p + i*j*l*p + i*j*o*p + j*l*o*q + g*j*m*o + g*j*l*q + g*j*l*p + g*j*l*o + g*l*o*p + g*l*m*p + g*l*m*o + g*i*m*o + g*i*o*p + g*i*m*q + g*i*m*p + g*i*l*q + g*i*l*p + g*i*l*o + l*m*q*g))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), f: (r*e*j*(l*q*o + l*o*p + l*m*q + l*m*p + l*m*o + i*o*q + i*o*p + i*m*q + i*m*p + i*m*o + i*l*q + i*l*p + i*l*o))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), h: (j*e*r*l*(o*q + o*p + m*q + m*p + m*o))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), k: (j*e*r*o*l*(q + p))/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), n: (j*e*r*o*q*l)/(l*q*d*e*o + l*q*d*g*o + l*q*e*g*o + i*j*d*o*q + i*j*e*o*q + j*d*e*o*q + g*j*d*o*q + g*j*e*o*q + g*i*e*o*q + i*d*e*o*q + g*i*d*o*q + g*i*d*o*p + g*i*d*m*q + g*i*d*m*p + g*i*d*m*o + g*i*d*l*q + g*i*d*l*p + g*i*d*l*o + g*e*l*m*p + g*e*l*o*p + g*j*e*l*q + g*e*l*m*o + g*j*e*m*p + g*j*e*m*o + d*e*l*m*p + d*e*l*m*o + i*d*e*m*p + g*j*e*l*p + g*j*e*l*o + d*e*l*o*p + i*j*d*l*o + i*j*e*o*p + i*j*e*m*q + i*j*d*m*q + i*j*d*m*p + i*j*d*m*o + i*j*d*l*q + i*j*d*l*p + i*j*e*m*p + i*j*e*m*o + i*j*e*l*q + i*j*e*l*p + i*j*e*l*o + i*d*e*m*q + i*d*e*m*o + i*d*e*l*q + i*d*e*l*p + j*d*l*o*p + j*d*e*l*o + g*j*d*o*p + g*j*d*m*q + g*j*d*m*p + g*j*d*m*o + g*j*d*l*q + g*j*d*l*p + g*j*d*l*o + g*j*e*o*p + g*j*e*m*q + g*d*l*o*p + g*d*l*m*p + g*d*l*m*o + j*d*e*m*p + i*d*e*o*p + j*e*o*q*l + j*e*o*p*l + j*e*m*q*l + j*d*e*o*p + j*d*e*m*q + i*j*d*o*p + g*i*e*o*p + j*d*e*m*o + j*d*e*l*q + j*d*e*l*p + j*e*m*p*l + j*e*m*o*l + g*i*e*m*q + g*i*e*m*p + g*i*e*m*o + g*i*e*l*q + g*i*e*l*p + g*i*e*l*o + j*d*l*o*q + j*d*l*m*q + j*d*l*m*p + j*d*l*m*o + i*d*e*l*o + l*m*q*d*e + l*m*q*d*g + l*m*q*e*g), } assert solve_lin_sys(eqs, domain) == sol def test_eqs_to_matrix(): domain, x1,x2 = ring("x1,x2", QQ) eqs_coeff = [{x1: QQ(1), x2: QQ(1)}, {x1: QQ(2), x2: QQ(-1)}] eqs_rhs = [QQ(-5), QQ(0)] M = eqs_to_matrix(eqs_coeff, eqs_rhs, [x1, x2], QQ) assert M.to_Matrix() == Matrix([[1, 1, 5], [2, -1, 0]]) sympy-sympy-1.9/sympy/polys/tests/test_specialpolys.py000066400000000000000000000112731412543434000235400ustar00rootroot00000000000000"""Tests for functions for generating interesting polynomials. """ from sympy import Poly, ZZ, symbols, sqrt, prime, Add from sympy.utilities.iterables import permute_signs from sympy.testing.pytest import raises from sympy.polys.specialpolys import ( swinnerton_dyer_poly, cyclotomic_poly, symmetric_poly, random_poly, interpolating_poly, fateman_poly_F_1, dmp_fateman_poly_F_1, fateman_poly_F_2, dmp_fateman_poly_F_2, fateman_poly_F_3, dmp_fateman_poly_F_3, ) from sympy.abc import x, y, z def test_swinnerton_dyer_poly(): raises(ValueError, lambda: swinnerton_dyer_poly(0, x)) assert swinnerton_dyer_poly(1, x, polys=True) == Poly(x**2 - 2) assert swinnerton_dyer_poly(1, x) == x**2 - 2 assert swinnerton_dyer_poly(2, x) == x**4 - 10*x**2 + 1 assert swinnerton_dyer_poly( 3, x) == x**8 - 40*x**6 + 352*x**4 - 960*x**2 + 576 # we only need to check that the polys arg works but # we may as well test that the roots are correct p = [sqrt(prime(i)) for i in range(1, 5)] assert str([i.n(3) for i in swinnerton_dyer_poly(4, polys=True).all_roots()] ) == str(sorted([Add(*i).n(3) for i in permute_signs(p)])) def test_cyclotomic_poly(): raises(ValueError, lambda: cyclotomic_poly(0, x)) assert cyclotomic_poly(1, x, polys=True) == Poly(x - 1) assert cyclotomic_poly(1, x) == x - 1 assert cyclotomic_poly(2, x) == x + 1 assert cyclotomic_poly(3, x) == x**2 + x + 1 assert cyclotomic_poly(4, x) == x**2 + 1 assert cyclotomic_poly(5, x) == x**4 + x**3 + x**2 + x + 1 assert cyclotomic_poly(6, x) == x**2 - x + 1 def test_symmetric_poly(): raises(ValueError, lambda: symmetric_poly(-1, x, y, z)) raises(ValueError, lambda: symmetric_poly(5, x, y, z)) assert symmetric_poly(1, x, y, z, polys=True) == Poly(x + y + z) assert symmetric_poly(1, (x, y, z), polys=True) == Poly(x + y + z) assert symmetric_poly(0, x, y, z) == 1 assert symmetric_poly(1, x, y, z) == x + y + z assert symmetric_poly(2, x, y, z) == x*y + x*z + y*z assert symmetric_poly(3, x, y, z) == x*y*z def test_random_poly(): poly = random_poly(x, 10, -100, 100, polys=False) assert Poly(poly).degree() == 10 assert all(-100 <= coeff <= 100 for coeff in Poly(poly).coeffs()) is True poly = random_poly(x, 10, -100, 100, polys=True) assert poly.degree() == 10 assert all(-100 <= coeff <= 100 for coeff in poly.coeffs()) is True def test_interpolating_poly(): x0, x1, x2, x3, y0, y1, y2, y3 = symbols('x:4, y:4') assert interpolating_poly(0, x) == 0 assert interpolating_poly(1, x) == y0 assert interpolating_poly(2, x) == \ y0*(x - x1)/(x0 - x1) + y1*(x - x0)/(x1 - x0) assert interpolating_poly(3, x) == \ y0*(x - x1)*(x - x2)/((x0 - x1)*(x0 - x2)) + \ y1*(x - x0)*(x - x2)/((x1 - x0)*(x1 - x2)) + \ y2*(x - x0)*(x - x1)/((x2 - x0)*(x2 - x1)) assert interpolating_poly(4, x) == \ y0*(x - x1)*(x - x2)*(x - x3)/((x0 - x1)*(x0 - x2)*(x0 - x3)) + \ y1*(x - x0)*(x - x2)*(x - x3)/((x1 - x0)*(x1 - x2)*(x1 - x3)) + \ y2*(x - x0)*(x - x1)*(x - x3)/((x2 - x0)*(x2 - x1)*(x2 - x3)) + \ y3*(x - x0)*(x - x1)*(x - x2)/((x3 - x0)*(x3 - x1)*(x3 - x2)) raises(ValueError, lambda: interpolating_poly(2, x, (x, 2), (1, 3))) raises(ValueError, lambda: interpolating_poly(2, x, (x + y, 2), (1, 3))) raises(ValueError, lambda: interpolating_poly(2, x + y, (x, 2), (1, 3))) raises(ValueError, lambda: interpolating_poly(2, 3, (4, 5), (6, 7))) raises(ValueError, lambda: interpolating_poly(2, 3, (4, 5), (6, 7, 8))) assert interpolating_poly(0, x, (1, 2), (3, 4)) == 0 assert interpolating_poly(1, x, (1, 2), (3, 4)) == 3 assert interpolating_poly(2, x, (1, 2), (3, 4)) == x + 2 def test_fateman_poly_F_1(): f, g, h = fateman_poly_F_1(1) F, G, H = dmp_fateman_poly_F_1(1, ZZ) assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] f, g, h = fateman_poly_F_1(3) F, G, H = dmp_fateman_poly_F_1(3, ZZ) assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] def test_fateman_poly_F_2(): f, g, h = fateman_poly_F_2(1) F, G, H = dmp_fateman_poly_F_2(1, ZZ) assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] f, g, h = fateman_poly_F_2(3) F, G, H = dmp_fateman_poly_F_2(3, ZZ) assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] def test_fateman_poly_F_3(): f, g, h = fateman_poly_F_3(1) F, G, H = dmp_fateman_poly_F_3(1, ZZ) assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] f, g, h = fateman_poly_F_3(3) F, G, H = dmp_fateman_poly_F_3(3, ZZ) assert [ t.rep.rep for t in [f, g, h] ] == [F, G, H] sympy-sympy-1.9/sympy/polys/tests/test_sqfreetools.py000066400000000000000000000104431412543434000233750ustar00rootroot00000000000000"""Tests for square-free decomposition algorithms and related tools. """ from sympy.polys.rings import ring from sympy.polys.domains import FF, ZZ, QQ from sympy.polys.specialpolys import f_polys from sympy.testing.pytest import raises f_0, f_1, f_2, f_3, f_4, f_5, f_6 = f_polys() def test_dup_sqf(): R, x = ring("x", ZZ) assert R.dup_sqf_part(0) == 0 assert R.dup_sqf_p(0) is True assert R.dup_sqf_part(7) == 1 assert R.dup_sqf_p(7) is True assert R.dup_sqf_part(2*x + 2) == x + 1 assert R.dup_sqf_p(2*x + 2) is True assert R.dup_sqf_part(x**3 + x + 1) == x**3 + x + 1 assert R.dup_sqf_p(x**3 + x + 1) is True assert R.dup_sqf_part(-x**3 + x + 1) == x**3 - x - 1 assert R.dup_sqf_p(-x**3 + x + 1) is True assert R.dup_sqf_part(2*x**3 + 3*x**2) == 2*x**2 + 3*x assert R.dup_sqf_p(2*x**3 + 3*x**2) is False assert R.dup_sqf_part(-2*x**3 + 3*x**2) == 2*x**2 - 3*x assert R.dup_sqf_p(-2*x**3 + 3*x**2) is False assert R.dup_sqf_list(0) == (0, []) assert R.dup_sqf_list(1) == (1, []) assert R.dup_sqf_list(x) == (1, [(x, 1)]) assert R.dup_sqf_list(2*x**2) == (2, [(x, 2)]) assert R.dup_sqf_list(3*x**3) == (3, [(x, 3)]) assert R.dup_sqf_list(-x**5 + x**4 + x - 1) == \ (-1, [(x**3 + x**2 + x + 1, 1), (x - 1, 2)]) assert R.dup_sqf_list(x**8 + 6*x**6 + 12*x**4 + 8*x**2) == \ ( 1, [(x, 2), (x**2 + 2, 3)]) assert R.dup_sqf_list(2*x**2 + 4*x + 2) == (2, [(x + 1, 2)]) R, x = ring("x", QQ) assert R.dup_sqf_list(2*x**2 + 4*x + 2) == (2, [(x + 1, 2)]) R, x = ring("x", FF(2)) assert R.dup_sqf_list(x**2 + 1) == (1, [(x + 1, 2)]) R, x = ring("x", FF(3)) assert R.dup_sqf_list(x**10 + 2*x**7 + 2*x**4 + x) == \ (1, [(x, 1), (x + 1, 3), (x + 2, 6)]) R1, x = ring("x", ZZ) R2, y = ring("y", FF(3)) f = x**3 + 1 g = y**3 + 1 assert R1.dup_sqf_part(f) == f assert R2.dup_sqf_part(g) == y + 1 assert R1.dup_sqf_p(f) is True assert R2.dup_sqf_p(g) is False R, x, y = ring("x,y", ZZ) A = x**4 - 3*x**2 + 6 D = x**6 - 5*x**4 + 5*x**2 + 4 f, g = D, R.dmp_sub(A, R.dmp_mul(R.dmp_diff(D, 1), y)) res = R.dmp_resultant(f, g) h = (4*y**2 + 1).drop(x) assert R.drop(x).dup_sqf_list(res) == (45796, [(h, 3)]) Rt, t = ring("t", ZZ) R, x = ring("x", Rt) assert R.dup_sqf_list_include(t**3*x**2) == [(t**3, 1), (x, 2)] def test_dmp_sqf(): R, x, y = ring("x,y", ZZ) assert R.dmp_sqf_part(0) == 0 assert R.dmp_sqf_p(0) is True assert R.dmp_sqf_part(7) == 1 assert R.dmp_sqf_p(7) is True assert R.dmp_sqf_list(3) == (3, []) assert R.dmp_sqf_list_include(3) == [(3, 1)] R, x, y, z = ring("x,y,z", ZZ) assert R.dmp_sqf_p(f_0) is True assert R.dmp_sqf_p(f_0**2) is False assert R.dmp_sqf_p(f_1) is True assert R.dmp_sqf_p(f_1**2) is False assert R.dmp_sqf_p(f_2) is True assert R.dmp_sqf_p(f_2**2) is False assert R.dmp_sqf_p(f_3) is True assert R.dmp_sqf_p(f_3**2) is False assert R.dmp_sqf_p(f_5) is False assert R.dmp_sqf_p(f_5**2) is False assert R.dmp_sqf_p(f_4) is True assert R.dmp_sqf_part(f_4) == -f_4 assert R.dmp_sqf_part(f_5) == x + y - z R, x, y, z, t = ring("x,y,z,t", ZZ) assert R.dmp_sqf_p(f_6) is True assert R.dmp_sqf_part(f_6) == f_6 R, x = ring("x", ZZ) f = -x**5 + x**4 + x - 1 assert R.dmp_sqf_list(f) == (-1, [(x**3 + x**2 + x + 1, 1), (x - 1, 2)]) assert R.dmp_sqf_list_include(f) == [(-x**3 - x**2 - x - 1, 1), (x - 1, 2)] R, x, y = ring("x,y", ZZ) f = -x**5 + x**4 + x - 1 assert R.dmp_sqf_list(f) == (-1, [(x**3 + x**2 + x + 1, 1), (x - 1, 2)]) assert R.dmp_sqf_list_include(f) == [(-x**3 - x**2 - x - 1, 1), (x - 1, 2)] f = -x**2 + 2*x - 1 assert R.dmp_sqf_list_include(f) == [(-1, 1), (x - 1, 2)] R, x, y = ring("x,y", FF(2)) raises(NotImplementedError, lambda: R.dmp_sqf_list(y**2 + 1)) def test_dup_gff_list(): R, x = ring("x", ZZ) f = x**5 + 2*x**4 - x**3 - 2*x**2 assert R.dup_gff_list(f) == [(x, 1), (x + 2, 4)] g = x**9 - 20*x**8 + 166*x**7 - 744*x**6 + 1965*x**5 - 3132*x**4 + 2948*x**3 - 1504*x**2 + 320*x assert R.dup_gff_list(g) == [(x**2 - 5*x + 4, 1), (x**2 - 5*x + 4, 2), (x, 3)] raises(ValueError, lambda: R.dup_gff_list(0)) sympy-sympy-1.9/sympy/polys/tests/test_subresultants_qq_zz.py000066400000000000000000000314431412543434000251740ustar00rootroot00000000000000from sympy import var, sturm, subresultants, prem, pquo from sympy.matrices import Matrix from sympy.polys.subresultants_qq_zz import (sylvester, res, res_q, res_z, bezout, subresultants_sylv, modified_subresultants_sylv, subresultants_bezout, modified_subresultants_bezout, backward_eye, sturm_pg, sturm_q, sturm_amv, euclid_pg, euclid_q, euclid_amv, modified_subresultants_pg, subresultants_pg, subresultants_amv_q, quo_z, rem_z, subresultants_amv, modified_subresultants_amv, subresultants_rem, subresultants_vv, subresultants_vv_2) def test_sylvester(): x = var('x') assert sylvester(x**3 -7, 0, x) == sylvester(x**3 -7, 0, x, 1) == Matrix([[0]]) assert sylvester(0, x**3 -7, x) == sylvester(0, x**3 -7, x, 1) == Matrix([[0]]) assert sylvester(x**3 -7, 0, x, 2) == Matrix([[0]]) assert sylvester(0, x**3 -7, x, 2) == Matrix([[0]]) assert sylvester(x**3 -7, 7, x).det() == sylvester(x**3 -7, 7, x, 1).det() == 343 assert sylvester(7, x**3 -7, x).det() == sylvester(7, x**3 -7, x, 1).det() == 343 assert sylvester(x**3 -7, 7, x, 2).det() == -343 assert sylvester(7, x**3 -7, x, 2).det() == 343 assert sylvester(3, 7, x).det() == sylvester(3, 7, x, 1).det() == sylvester(3, 7, x, 2).det() == 1 assert sylvester(3, 0, x).det() == sylvester(3, 0, x, 1).det() == sylvester(3, 0, x, 2).det() == 1 assert sylvester(x - 3, x - 8, x) == sylvester(x - 3, x - 8, x, 1) == sylvester(x - 3, x - 8, x, 2) == Matrix([[1, -3], [1, -8]]) assert sylvester(x**3 - 7*x + 7, 3*x**2 - 7, x) == sylvester(x**3 - 7*x + 7, 3*x**2 - 7, x, 1) == Matrix([[1, 0, -7, 7, 0], [0, 1, 0, -7, 7], [3, 0, -7, 0, 0], [0, 3, 0, -7, 0], [0, 0, 3, 0, -7]]) assert sylvester(x**3 - 7*x + 7, 3*x**2 - 7, x, 2) == Matrix([ [1, 0, -7, 7, 0, 0], [0, 3, 0, -7, 0, 0], [0, 1, 0, -7, 7, 0], [0, 0, 3, 0, -7, 0], [0, 0, 1, 0, -7, 7], [0, 0, 0, 3, 0, -7]]) def test_subresultants_sylv(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_sylv(p, q, x) == subresultants(p, q, x) assert subresultants_sylv(p, q, x)[-1] == res(p, q, x) assert subresultants_sylv(p, q, x) != euclid_amv(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_sylv(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_sylv(p, q, x) == euclid_amv(p, q, x) def test_modified_subresultants_sylv(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 amv_factors = [1, 1, -1, 1, -1, 1] assert modified_subresultants_sylv(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_amv(p, q, x))] assert modified_subresultants_sylv(p, q, x)[-1] != res_q(p + x**8, q, x) assert modified_subresultants_sylv(p, q, x) != sturm_amv(p, q, x) p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert modified_subresultants_sylv(p, q, x) == sturm_amv(p, q, x) assert modified_subresultants_sylv(-p, q, x) != sturm_amv(-p, q, x) def test_res(): x = var('x') assert res(3, 5, x) == 1 def test_res_q(): x = var('x') assert res_q(3, 5, x) == 1 def test_res_z(): x = var('x') assert res_z(3, 5, x) == 1 assert res(3, 5, x) == res_q(3, 5, x) == res_z(3, 5, x) def test_bezout(): x = var('x') p = -2*x**5+7*x**3+9*x**2-3*x+1 q = -10*x**4+21*x**2+18*x-3 assert bezout(p, q, x, 'bz').det() == sylvester(p, q, x, 2).det() assert bezout(p, q, x, 'bz').det() != sylvester(p, q, x, 1).det() assert bezout(p, q, x, 'prs') == backward_eye(5) * bezout(p, q, x, 'bz') * backward_eye(5) def test_subresultants_bezout(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_bezout(p, q, x) == subresultants(p, q, x) assert subresultants_bezout(p, q, x)[-1] == sylvester(p, q, x).det() assert subresultants_bezout(p, q, x) != euclid_amv(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_bezout(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_bezout(p, q, x) == euclid_amv(p, q, x) def test_modified_subresultants_bezout(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 amv_factors = [1, 1, -1, 1, -1, 1] assert modified_subresultants_bezout(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_amv(p, q, x))] assert modified_subresultants_bezout(p, q, x)[-1] != sylvester(p + x**8, q, x).det() assert modified_subresultants_bezout(p, q, x) != sturm_amv(p, q, x) p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert modified_subresultants_bezout(p, q, x) == sturm_amv(p, q, x) assert modified_subresultants_bezout(-p, q, x) != sturm_amv(-p, q, x) def test_sturm_pg(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert sturm_pg(p, q, x)[-1] != sylvester(p, q, x, 2).det() sam_factors = [1, 1, -1, -1, 1, 1] assert sturm_pg(p, q, x) == [i*j for i,j in zip(sam_factors, euclid_pg(p, q, x))] p = -9*x**5 - 5*x**3 - 9 q = -45*x**4 - 15*x**2 assert sturm_pg(p, q, x, 1)[-1] == sylvester(p, q, x, 1).det() assert sturm_pg(p, q, x)[-1] != sylvester(p, q, x, 2).det() assert sturm_pg(-p, q, x)[-1] == sylvester(-p, q, x, 2).det() assert sturm_pg(-p, q, x) == modified_subresultants_pg(-p, q, x) def test_sturm_q(): x = var('x') p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert sturm_q(p, q, x) == sturm(p) assert sturm_q(-p, -q, x) != sturm(-p) def test_sturm_amv(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert sturm_amv(p, q, x)[-1] != sylvester(p, q, x, 2).det() sam_factors = [1, 1, -1, -1, 1, 1] assert sturm_amv(p, q, x) == [i*j for i,j in zip(sam_factors, euclid_amv(p, q, x))] p = -9*x**5 - 5*x**3 - 9 q = -45*x**4 - 15*x**2 assert sturm_amv(p, q, x, 1)[-1] == sylvester(p, q, x, 1).det() assert sturm_amv(p, q, x)[-1] != sylvester(p, q, x, 2).det() assert sturm_amv(-p, q, x)[-1] == sylvester(-p, q, x, 2).det() assert sturm_pg(-p, q, x) == modified_subresultants_pg(-p, q, x) def test_euclid_pg(): x = var('x') p = x**6+x**5-x**4-x**3+x**2-x+1 q = 6*x**5+5*x**4-4*x**3-3*x**2+2*x-1 assert euclid_pg(p, q, x)[-1] == sylvester(p, q, x).det() assert euclid_pg(p, q, x) == subresultants_pg(p, q, x) p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert euclid_pg(p, q, x)[-1] != sylvester(p, q, x, 2).det() sam_factors = [1, 1, -1, -1, 1, 1] assert euclid_pg(p, q, x) == [i*j for i,j in zip(sam_factors, sturm_pg(p, q, x))] def test_euclid_q(): x = var('x') p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert euclid_q(p, q, x)[-1] == -sturm(p)[-1] def test_euclid_amv(): x = var('x') p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert euclid_amv(p, q, x)[-1] == sylvester(p, q, x).det() assert euclid_amv(p, q, x) == subresultants_amv(p, q, x) p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert euclid_amv(p, q, x)[-1] != sylvester(p, q, x, 2).det() sam_factors = [1, 1, -1, -1, 1, 1] assert euclid_amv(p, q, x) == [i*j for i,j in zip(sam_factors, sturm_amv(p, q, x))] def test_modified_subresultants_pg(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 amv_factors = [1, 1, -1, 1, -1, 1] assert modified_subresultants_pg(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_pg(p, q, x))] assert modified_subresultants_pg(p, q, x)[-1] != sylvester(p + x**8, q, x).det() assert modified_subresultants_pg(p, q, x) != sturm_pg(p, q, x) p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert modified_subresultants_pg(p, q, x) == sturm_pg(p, q, x) assert modified_subresultants_pg(-p, q, x) != sturm_pg(-p, q, x) def test_subresultants_pg(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_pg(p, q, x) == subresultants(p, q, x) assert subresultants_pg(p, q, x)[-1] == sylvester(p, q, x).det() assert subresultants_pg(p, q, x) != euclid_pg(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_pg(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_pg(p, q, x) == euclid_pg(p, q, x) def test_subresultants_amv_q(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_amv_q(p, q, x) == subresultants(p, q, x) assert subresultants_amv_q(p, q, x)[-1] == sylvester(p, q, x).det() assert subresultants_amv_q(p, q, x) != euclid_amv(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_amv_q(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_amv(p, q, x) == euclid_amv(p, q, x) def test_rem_z(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert rem_z(p, -q, x) != prem(p, -q, x) def test_quo_z(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert quo_z(p, -q, x) != pquo(p, -q, x) y = var('y') q = 3*x**6 + 5*y**4 - 4*x**2 - 9*x + 21 assert quo_z(p, -q, x) == pquo(p, -q, x) def test_subresultants_amv(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_amv(p, q, x) == subresultants(p, q, x) assert subresultants_amv(p, q, x)[-1] == sylvester(p, q, x).det() assert subresultants_amv(p, q, x) != euclid_amv(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_amv(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_amv(p, q, x) == euclid_amv(p, q, x) def test_modified_subresultants_amv(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 amv_factors = [1, 1, -1, 1, -1, 1] assert modified_subresultants_amv(p, q, x) == [i*j for i, j in zip(amv_factors, subresultants_amv(p, q, x))] assert modified_subresultants_amv(p, q, x)[-1] != sylvester(p + x**8, q, x).det() assert modified_subresultants_amv(p, q, x) != sturm_amv(p, q, x) p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert modified_subresultants_amv(p, q, x) == sturm_amv(p, q, x) assert modified_subresultants_amv(-p, q, x) != sturm_amv(-p, q, x) def test_subresultants_rem(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_rem(p, q, x) == subresultants(p, q, x) assert subresultants_rem(p, q, x)[-1] == sylvester(p, q, x).det() assert subresultants_rem(p, q, x) != euclid_amv(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_rem(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_rem(p, q, x) == euclid_amv(p, q, x) def test_subresultants_vv(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_vv(p, q, x) == subresultants(p, q, x) assert subresultants_vv(p, q, x)[-1] == sylvester(p, q, x).det() assert subresultants_vv(p, q, x) != euclid_amv(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_vv(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_vv(p, q, x) == euclid_amv(p, q, x) def test_subresultants_vv_2(): x = var('x') p = x**8 + x**6 - 3*x**4 - 3*x**3 + 8*x**2 + 2*x - 5 q = 3*x**6 + 5*x**4 - 4*x**2 - 9*x + 21 assert subresultants_vv_2(p, q, x) == subresultants(p, q, x) assert subresultants_vv_2(p, q, x)[-1] == sylvester(p, q, x).det() assert subresultants_vv_2(p, q, x) != euclid_amv(p, q, x) amv_factors = [1, 1, -1, 1, -1, 1] assert subresultants_vv_2(p, q, x) == [i*j for i, j in zip(amv_factors, modified_subresultants_amv(p, q, x))] p = x**3 - 7*x + 7 q = 3*x**2 - 7 assert subresultants_vv_2(p, q, x) == euclid_amv(p, q, x) sympy-sympy-1.9/sympy/printing/000077500000000000000000000000001412543434000167365ustar00rootroot00000000000000sympy-sympy-1.9/sympy/printing/__init__.py000066400000000000000000000042071412543434000210520ustar00rootroot00000000000000"""Printing subsystem""" from .pretty import pager_print, pretty, pretty_print, pprint, pprint_use_unicode, pprint_try_use_unicode from .latex import latex, print_latex, multiline_latex from .mathml import mathml, print_mathml from .python import python, print_python from .pycode import pycode from .codeprinter import print_ccode, print_fcode from .codeprinter import ccode, fcode, cxxcode # noqa:F811 from .glsl import glsl_code, print_glsl from .rcode import rcode, print_rcode from .jscode import jscode, print_jscode from .julia import julia_code from .mathematica import mathematica_code from .octave import octave_code from .rust import rust_code from .gtk import print_gtk from .preview import preview from .repr import srepr from .tree import print_tree from .str import StrPrinter, sstr, sstrrepr from .tableform import TableForm from .dot import dotprint from .maple import maple_code, print_maple_code __all__ = [ # sympy.printing.pretty 'pager_print', 'pretty', 'pretty_print', 'pprint', 'pprint_use_unicode', 'pprint_try_use_unicode', # sympy.printing.latex 'latex', 'print_latex', 'multiline_latex', # sympy.printing.mathml 'mathml', 'print_mathml', # sympy.printing.python 'python', 'print_python', # sympy.printing.pycode 'pycode', # sympy.printing.codeprinter 'ccode', 'print_ccode', 'cxxcode', 'fcode', 'print_fcode', # sympy.printing.glsl 'glsl_code', 'print_glsl', # sympy.printing.rcode 'rcode', 'print_rcode', # sympy.printing.jscode 'jscode', 'print_jscode', # sympy.printing.julia 'julia_code', # sympy.printing.mathematica 'mathematica_code', # sympy.printing.octave 'octave_code', # sympy.printing.rust 'rust_code', # sympy.printing.gtk 'print_gtk', # sympy.printing.preview 'preview', # sympy.printing.repr 'srepr', # sympy.printing.tree 'print_tree', # sympy.printing.str 'StrPrinter', 'sstr', 'sstrrepr', # sympy.printing.tableform 'TableForm', # sympy.printing.dot 'dotprint', # sympy.printing.maple 'maple_code', 'print_maple_code', ] sympy-sympy-1.9/sympy/printing/aesaracode.py000066400000000000000000000426131412543434000214050ustar00rootroot00000000000000from typing import Any, Dict from sympy.core.compatibility import is_sequence from sympy.external import import_module from sympy.printing.printer import Printer import sympy from functools import partial aesara = import_module('aesara') if aesara: aes = aesara.scalar aet = aesara.tensor from aesara.tensor import nlinalg from aesara.tensor.elemwise import Elemwise from aesara.tensor.elemwise import DimShuffle mapping = { sympy.Add: aet.add, sympy.Mul: aet.mul, sympy.Abs: aet.abs_, sympy.sign: aet.sgn, sympy.ceiling: aet.ceil, sympy.floor: aet.floor, sympy.log: aet.log, sympy.exp: aet.exp, sympy.sqrt: aet.sqrt, sympy.cos: aet.cos, sympy.acos: aet.arccos, sympy.sin: aet.sin, sympy.asin: aet.arcsin, sympy.tan: aet.tan, sympy.atan: aet.arctan, sympy.atan2: aet.arctan2, sympy.cosh: aet.cosh, sympy.acosh: aet.arccosh, sympy.sinh: aet.sinh, sympy.asinh: aet.arcsinh, sympy.tanh: aet.tanh, sympy.atanh: aet.arctanh, sympy.re: aet.real, sympy.im: aet.imag, sympy.arg: aet.angle, sympy.erf: aet.erf, sympy.gamma: aet.gamma, sympy.loggamma: aet.gammaln, sympy.Pow: aet.pow, sympy.Eq: aet.eq, sympy.StrictGreaterThan: aet.gt, sympy.StrictLessThan: aet.lt, sympy.LessThan: aet.le, sympy.GreaterThan: aet.ge, sympy.And: aet.and_, sympy.Or: aet.or_, sympy.Max: aet.maximum, # Sympy accept >2 inputs, Aesara only 2 sympy.Min: aet.minimum, # Sympy accept >2 inputs, Aesara only 2 sympy.conjugate: aet.conj, sympy.core.numbers.ImaginaryUnit: lambda:aet.complex(0,1), # Matrices sympy.MatAdd: Elemwise(aes.add), sympy.HadamardProduct: Elemwise(aes.mul), sympy.Trace: nlinalg.trace, sympy.Determinant : nlinalg.det, sympy.Inverse: nlinalg.matrix_inverse, sympy.Transpose: DimShuffle((False, False), [1, 0]), } class AesaraPrinter(Printer): """ Code printer which creates Aesara symbolic expression graphs. Parameters ========== cache : dict Cache dictionary to use. If None (default) will use the global cache. To create a printer which does not depend on or alter global state pass an empty dictionary. Note: the dictionary is not copied on initialization of the printer and will be updated in-place, so using the same dict object when creating multiple printers or making multiple calls to :func:`.aesara_code` or :func:`.aesara_function` means the cache is shared between all these applications. Attributes ========== cache : dict A cache of Aesara variables which have been created for Sympy symbol-like objects (e.g. :class:`sympy.core.symbol.Symbol` or :class:`sympy.matrices.expressions.MatrixSymbol`). This is used to ensure that all references to a given symbol in an expression (or multiple expressions) are printed as the same Aesara variable, which is created only once. Symbols are differentiated only by name and type. The format of the cache's contents should be considered opaque to the user. """ printmethod = "_aesara" def __init__(self, *args, **kwargs): self.cache = kwargs.pop('cache', dict()) super().__init__(*args, **kwargs) def _get_key(self, s, name=None, dtype=None, broadcastable=None): """ Get the cache key for a Sympy object. Parameters ========== s : sympy.core.basic.Basic Sympy object to get key for. name : str Name of object, if it does not have a ``name`` attribute. """ if name is None: name = s.name return (name, type(s), s.args, dtype, broadcastable) def _get_or_create(self, s, name=None, dtype=None, broadcastable=None): """ Get the Aesara variable for a Sympy symbol from the cache, or create it if it does not exist. """ # Defaults if name is None: name = s.name if dtype is None: dtype = 'floatX' if broadcastable is None: broadcastable = () key = self._get_key(s, name, dtype=dtype, broadcastable=broadcastable) if key in self.cache: return self.cache[key] value = aet.tensor(name=name, dtype=dtype, broadcastable=broadcastable) self.cache[key] = value return value def _print_Symbol(self, s, **kwargs): dtype = kwargs.get('dtypes', {}).get(s) bc = kwargs.get('broadcastables', {}).get(s) return self._get_or_create(s, dtype=dtype, broadcastable=bc) def _print_AppliedUndef(self, s, **kwargs): name = str(type(s)) + '_' + str(s.args[0]) dtype = kwargs.get('dtypes', {}).get(s) bc = kwargs.get('broadcastables', {}).get(s) return self._get_or_create(s, name=name, dtype=dtype, broadcastable=bc) def _print_Basic(self, expr, **kwargs): op = mapping[type(expr)] children = [self._print(arg, **kwargs) for arg in expr.args] return op(*children) def _print_Number(self, n, **kwargs): # Integers already taken care of below, interpret as float return float(n.evalf()) def _print_MatrixSymbol(self, X, **kwargs): dtype = kwargs.get('dtypes', {}).get(X) return self._get_or_create(X, dtype=dtype, broadcastable=(None, None)) def _print_DenseMatrix(self, X, **kwargs): if not hasattr(aet, 'stacklists'): raise NotImplementedError( "Matrix translation not yet supported in this version of Aesara") return aet.stacklists([ [self._print(arg, **kwargs) for arg in L] for L in X.tolist() ]) _print_ImmutableMatrix = _print_ImmutableDenseMatrix = _print_DenseMatrix def _print_MatMul(self, expr, **kwargs): children = [self._print(arg, **kwargs) for arg in expr.args] result = children[0] for child in children[1:]: result = aet.dot(result, child) return result def _print_MatPow(self, expr, **kwargs): children = [self._print(arg, **kwargs) for arg in expr.args] result = 1 if isinstance(children[1], int) and children[1] > 0: for i in range(children[1]): result = aet.dot(result, children[0]) else: raise NotImplementedError('''Only non-negative integer powers of matrices can be handled by Aesara at the moment''') return result def _print_MatrixSlice(self, expr, **kwargs): parent = self._print(expr.parent, **kwargs) rowslice = self._print(slice(*expr.rowslice), **kwargs) colslice = self._print(slice(*expr.colslice), **kwargs) return parent[rowslice, colslice] def _print_BlockMatrix(self, expr, **kwargs): nrows, ncols = expr.blocks.shape blocks = [[self._print(expr.blocks[r, c], **kwargs) for c in range(ncols)] for r in range(nrows)] return aet.join(0, *[aet.join(1, *row) for row in blocks]) def _print_slice(self, expr, **kwargs): return slice(*[self._print(i, **kwargs) if isinstance(i, sympy.Basic) else i for i in (expr.start, expr.stop, expr.step)]) def _print_Pi(self, expr, **kwargs): return 3.141592653589793 def _print_Piecewise(self, expr, **kwargs): import numpy as np e, cond = expr.args[0].args # First condition and corresponding value # Print conditional expression and value for first condition p_cond = self._print(cond, **kwargs) p_e = self._print(e, **kwargs) # One condition only if len(expr.args) == 1: # Return value if condition else NaN return aet.switch(p_cond, p_e, np.nan) # Return value_1 if condition_1 else evaluate remaining conditions p_remaining = self._print(sympy.Piecewise(*expr.args[1:]), **kwargs) return aet.switch(p_cond, p_e, p_remaining) def _print_Rational(self, expr, **kwargs): return aet.true_div(self._print(expr.p, **kwargs), self._print(expr.q, **kwargs)) def _print_Integer(self, expr, **kwargs): return expr.p def _print_factorial(self, expr, **kwargs): return self._print(sympy.gamma(expr.args[0] + 1), **kwargs) def _print_Derivative(self, deriv, **kwargs): from aesara.gradient import Rop rv = self._print(deriv.expr, **kwargs) for var in deriv.variables: var = self._print(var, **kwargs) rv = Rop(rv, var, aet.ones_like(var)) return rv def emptyPrinter(self, expr): return expr def doprint(self, expr, dtypes=None, broadcastables=None): """ Convert a Sympy expression to a Aesara graph variable. The ``dtypes`` and ``broadcastables`` arguments are used to specify the data type, dimension, and broadcasting behavior of the Aesara variables corresponding to the free symbols in ``expr``. Each is a mapping from Sympy symbols to the value of the corresponding argument to ``aesara.tensor.var.TensorVariable``. See the corresponding `documentation page`__ for more information on broadcasting in Aesara. .. __: https://aesara.readthedocs.io/en/latest/tutorial/broadcasting.html Parameters ========== expr : sympy.core.expr.Expr Sympy expression to print. dtypes : dict Mapping from Sympy symbols to Aesara datatypes to use when creating new Aesara variables for those symbols. Corresponds to the ``dtype`` argument to ``aesara.tensor.var.TensorVariable``. Defaults to ``'floatX'`` for symbols not included in the mapping. broadcastables : dict Mapping from Sympy symbols to the value of the ``broadcastable`` argument to ``aesara.tensor.var.TensorVariable`` to use when creating Aesara variables for those symbols. Defaults to the empty tuple for symbols not included in the mapping (resulting in a scalar). Returns ======= aesara.graph.basic.Variable A variable corresponding to the expression's value in a Aesara symbolic expression graph. """ if dtypes is None: dtypes = {} if broadcastables is None: broadcastables = {} return self._print(expr, dtypes=dtypes, broadcastables=broadcastables) global_cache = {} # type: Dict[Any, Any] def aesara_code(expr, cache=None, **kwargs): """ Convert a Sympy expression into a Aesara graph variable. Parameters ========== expr : sympy.core.expr.Expr Sympy expression object to convert. cache : dict Cached Aesara variables (see :class:`AesaraPrinter.cache `). Defaults to the module-level global cache. dtypes : dict Passed to :meth:`.AesaraPrinter.doprint`. broadcastables : dict Passed to :meth:`.AesaraPrinter.doprint`. Returns ======= aesara.graph.basic.Variable A variable corresponding to the expression's value in a Aesara symbolic expression graph. """ if not aesara: raise ImportError("aesara is required for aesara_code") if cache is None: cache = global_cache return AesaraPrinter(cache=cache, settings={}).doprint(expr, **kwargs) def dim_handling(inputs, dim=None, dims=None, broadcastables=None): r""" Get value of ``broadcastables`` argument to :func:`.aesara_code` from keyword arguments to :func:`.aesara_function`. Included for backwards compatibility. Parameters ========== inputs Sequence of input symbols. dim : int Common number of dimensions for all inputs. Overrides other arguments if given. dims : dict Mapping from input symbols to number of dimensions. Overrides ``broadcastables`` argument if given. broadcastables : dict Explicit value of ``broadcastables`` argument to :meth:`.AesaraPrinter.doprint`. If not None function will return this value unchanged. Returns ======= dict Dictionary mapping elements of ``inputs`` to their "broadcastable" values (tuple of ``bool``\ s). """ if dim is not None: return {s: (False,) * dim for s in inputs} if dims is not None: maxdim = max(dims.values()) return { s: (False,) * d + (True,) * (maxdim - d) for s, d in dims.items() } if broadcastables is not None: return broadcastables return {} def aesara_function(inputs, outputs, scalar=False, *, dim=None, dims=None, broadcastables=None, **kwargs): """ Create a Aesara function from SymPy expressions. The inputs and outputs are converted to Aesara variables using :func:`.aesara_code` and then passed to ``aesara.function``. Parameters ========== inputs Sequence of symbols which constitute the inputs of the function. outputs Sequence of expressions which constitute the outputs(s) of the function. The free symbols of each expression must be a subset of ``inputs``. scalar : bool Convert 0-dimensional arrays in output to scalars. This will return a Python wrapper function around the Aesara function object. cache : dict Cached Aesara variables (see :class:`AesaraPrinter.cache `). Defaults to the module-level global cache. dtypes : dict Passed to :meth:`.AesaraPrinter.doprint`. broadcastables : dict Passed to :meth:`.AesaraPrinter.doprint`. dims : dict Alternative to ``broadcastables`` argument. Mapping from elements of ``inputs`` to integers indicating the dimension of their associated arrays/tensors. Overrides ``broadcastables`` argument if given. dim : int Another alternative to the ``broadcastables`` argument. Common number of dimensions to use for all arrays/tensors. ``aesara_function([x, y], [...], dim=2)`` is equivalent to using ``broadcastables={x: (False, False), y: (False, False)}``. Returns ======= callable A callable object which takes values of ``inputs`` as positional arguments and returns an output array for each of the expressions in ``outputs``. If ``outputs`` is a single expression the function will return a Numpy array, if it is a list of multiple expressions the function will return a list of arrays. See description of the ``squeeze`` argument above for the behavior when a single output is passed in a list. The returned object will either be an instance of ``aesara.compile.function.types.Function`` or a Python wrapper function around one. In both cases, the returned value will have a ``aesara_function`` attribute which points to the return value of ``aesara.function``. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.printing.aesaracode import aesara_function A simple function with one input and one output: >>> f1 = aesara_function([x], [x**2 - 1], scalar=True) >>> f1(3) 8.0 A function with multiple inputs and one output: >>> f2 = aesara_function([x, y, z], [(x**z + y**z)**(1/z)], scalar=True) >>> f2(3, 4, 2) 5.0 A function with multiple inputs and multiple outputs: >>> f3 = aesara_function([x, y], [x**2 + y**2, x**2 - y**2], scalar=True) >>> f3(2, 3) [13.0, -5.0] See also ======== dim_handling """ if not aesara: raise ImportError("Aesara is required for aesara_function") # Pop off non-aesara keyword args cache = kwargs.pop('cache', {}) dtypes = kwargs.pop('dtypes', {}) broadcastables = dim_handling( inputs, dim=dim, dims=dims, broadcastables=broadcastables, ) # Print inputs/outputs code = partial(aesara_code, cache=cache, dtypes=dtypes, broadcastables=broadcastables) tinputs = list(map(code, inputs)) toutputs = list(map(code, outputs)) #fix constant expressions as variables toutputs = [output if isinstance(output, aesara.graph.basic.Variable) else aet.as_tensor_variable(output) for output in toutputs] if len(toutputs) == 1: toutputs = toutputs[0] # Compile aesara func func = aesara.function(tinputs, toutputs, **kwargs) is_0d = [len(o.variable.broadcastable) == 0 for o in func.outputs] # No wrapper required if not scalar or not any(is_0d): func.aesara_function = func return func # Create wrapper to convert 0-dimensional outputs to scalars def wrapper(*args): out = func(*args) # out can be array(1.0) or [array(1.0), array(2.0)] if is_sequence(out): return [o[()] if is_0d[i] else o for i, o in enumerate(out)] else: return out[()] wrapper.__wrapped__ = func wrapper.__doc__ = func.__doc__ wrapper.aesara_function = func return wrapper sympy-sympy-1.9/sympy/printing/c.py000066400000000000000000000642121412543434000175370ustar00rootroot00000000000000""" C code printer The C89CodePrinter & C99CodePrinter converts single sympy expressions into single C expressions, using the functions defined in math.h where possible. A complete code generator, which uses ccode extensively, can be found in sympy.utilities.codegen. The codegen module can be used to generate complete source code files that are compilable without further modifications. """ from typing import Any, Dict, Tuple from functools import wraps from itertools import chain from sympy.core import S from sympy.codegen.ast import ( Assignment, Pointer, Variable, Declaration, Type, real, complex_, integer, bool_, float32, float64, float80, complex64, complex128, intc, value_const, pointer_const, int8, int16, int32, int64, uint8, uint16, uint32, uint64, untyped, none ) from sympy.printing.codeprinter import CodePrinter, requires from sympy.printing.precedence import precedence, PRECEDENCE from sympy.sets.fancysets import Range # These are defined in the other file so we can avoid importing sympy.codegen # from the top-level 'import sympy'. Export them here as well. from sympy.printing.codeprinter import ccode, print_ccode # noqa:F401 # dictionary mapping sympy function to (argument_conditions, C_function). # Used in C89CodePrinter._print_Function(self) known_functions_C89 = { "Abs": [(lambda x: not x.is_integer, "fabs"), (lambda x: x.is_integer, "abs")], "sin": "sin", "cos": "cos", "tan": "tan", "asin": "asin", "acos": "acos", "atan": "atan", "atan2": "atan2", "exp": "exp", "log": "log", "sinh": "sinh", "cosh": "cosh", "tanh": "tanh", "floor": "floor", "ceiling": "ceil", } known_functions_C99 = dict(known_functions_C89, **{ 'exp2': 'exp2', 'expm1': 'expm1', 'log10': 'log10', 'log2': 'log2', 'log1p': 'log1p', 'Cbrt': 'cbrt', 'hypot': 'hypot', 'fma': 'fma', 'loggamma': 'lgamma', 'erfc': 'erfc', 'Max': 'fmax', 'Min': 'fmin', "asinh": "asinh", "acosh": "acosh", "atanh": "atanh", "erf": "erf", "gamma": "tgamma", }) # These are the core reserved words in the C language. Taken from: # http://en.cppreference.com/w/c/keyword reserved_words = [ 'auto', 'break', 'case', 'char', 'const', 'continue', 'default', 'do', 'double', 'else', 'enum', 'extern', 'float', 'for', 'goto', 'if', 'int', 'long', 'register', 'return', 'short', 'signed', 'sizeof', 'static', 'struct', 'entry', # never standardized, we'll leave it here anyway 'switch', 'typedef', 'union', 'unsigned', 'void', 'volatile', 'while' ] reserved_words_c99 = ['inline', 'restrict'] def get_math_macros(): """ Returns a dictionary with math-related macros from math.h/cmath Note that these macros are not strictly required by the C/C++-standard. For MSVC they are enabled by defining "_USE_MATH_DEFINES" (preferably via a compilation flag). Returns ======= Dictionary mapping sympy expressions to strings (macro names) """ from sympy.codegen.cfunctions import log2, Sqrt from sympy.functions.elementary.exponential import log from sympy.functions.elementary.miscellaneous import sqrt return { S.Exp1: 'M_E', log2(S.Exp1): 'M_LOG2E', 1/log(2): 'M_LOG2E', log(2): 'M_LN2', log(10): 'M_LN10', S.Pi: 'M_PI', S.Pi/2: 'M_PI_2', S.Pi/4: 'M_PI_4', 1/S.Pi: 'M_1_PI', 2/S.Pi: 'M_2_PI', 2/sqrt(S.Pi): 'M_2_SQRTPI', 2/Sqrt(S.Pi): 'M_2_SQRTPI', sqrt(2): 'M_SQRT2', Sqrt(2): 'M_SQRT2', 1/sqrt(2): 'M_SQRT1_2', 1/Sqrt(2): 'M_SQRT1_2' } def _as_macro_if_defined(meth): """ Decorator for printer methods When a Printer's method is decorated using this decorator the expressions printed will first be looked for in the attribute ``math_macros``, and if present it will print the macro name in ``math_macros`` followed by a type suffix for the type ``real``. e.g. printing ``sympy.pi`` would print ``M_PIl`` if real is mapped to float80. """ @wraps(meth) def _meth_wrapper(self, expr, **kwargs): if expr in self.math_macros: return '%s%s' % (self.math_macros[expr], self._get_math_macro_suffix(real)) else: return meth(self, expr, **kwargs) return _meth_wrapper class C89CodePrinter(CodePrinter): """A printer to convert python expressions to strings of c code""" printmethod = "_ccode" language = "C" standard = "C89" reserved_words = set(reserved_words) _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 17, 'user_functions': {}, 'human': True, 'allow_unknown_functions': False, 'contract': True, 'dereference': set(), 'error_on_reserved': False, 'reserved_word_suffix': '_', } # type: Dict[str, Any] type_aliases = { real: float64, complex_: complex128, integer: intc } type_mappings = { real: 'double', intc: 'int', float32: 'float', float64: 'double', integer: 'int', bool_: 'bool', int8: 'int8_t', int16: 'int16_t', int32: 'int32_t', int64: 'int64_t', uint8: 'int8_t', uint16: 'int16_t', uint32: 'int32_t', uint64: 'int64_t', } # type: Dict[Type, Any] type_headers = { bool_: {'stdbool.h'}, int8: {'stdint.h'}, int16: {'stdint.h'}, int32: {'stdint.h'}, int64: {'stdint.h'}, uint8: {'stdint.h'}, uint16: {'stdint.h'}, uint32: {'stdint.h'}, uint64: {'stdint.h'}, } # Macros needed to be defined when using a Type type_macros = {} # type: Dict[Type, Tuple[str, ...]] type_func_suffixes = { float32: 'f', float64: '', float80: 'l' } type_literal_suffixes = { float32: 'F', float64: '', float80: 'L' } type_math_macro_suffixes = { float80: 'l' } math_macros = None _ns = '' # namespace, C++ uses 'std::' # known_functions-dict to copy _kf = known_functions_C89 # type: Dict[str, Any] def __init__(self, settings=None): settings = settings or {} if self.math_macros is None: self.math_macros = settings.pop('math_macros', get_math_macros()) self.type_aliases = dict(chain(self.type_aliases.items(), settings.pop('type_aliases', {}).items())) self.type_mappings = dict(chain(self.type_mappings.items(), settings.pop('type_mappings', {}).items())) self.type_headers = dict(chain(self.type_headers.items(), settings.pop('type_headers', {}).items())) self.type_macros = dict(chain(self.type_macros.items(), settings.pop('type_macros', {}).items())) self.type_func_suffixes = dict(chain(self.type_func_suffixes.items(), settings.pop('type_func_suffixes', {}).items())) self.type_literal_suffixes = dict(chain(self.type_literal_suffixes.items(), settings.pop('type_literal_suffixes', {}).items())) self.type_math_macro_suffixes = dict(chain(self.type_math_macro_suffixes.items(), settings.pop('type_math_macro_suffixes', {}).items())) super().__init__(settings) self.known_functions = dict(self._kf, **settings.get('user_functions', {})) self._dereference = set(settings.get('dereference', [])) self.headers = set() self.libraries = set() self.macros = set() def _rate_index_position(self, p): return p*5 def _get_statement(self, codestring): """ Get code string as a statement - i.e. ending with a semicolon. """ return codestring if codestring.endswith(';') else codestring + ';' def _get_comment(self, text): return "// {}".format(text) def _declare_number_const(self, name, value): type_ = self.type_aliases[real] var = Variable(name, type=type_, value=value.evalf(type_.decimal_dig), attrs={value_const}) decl = Declaration(var) return self._get_statement(self._print(decl)) def _format_code(self, lines): return self.indent_code(lines) def _traverse_matrix_indices(self, mat): rows, cols = mat.shape return ((i, j) for i in range(rows) for j in range(cols)) @_as_macro_if_defined def _print_Mul(self, expr, **kwargs): return super()._print_Mul(expr, **kwargs) @_as_macro_if_defined def _print_Pow(self, expr): if "Pow" in self.known_functions: return self._print_Function(expr) PREC = precedence(expr) suffix = self._get_func_suffix(real) if expr.exp == -1: literal_suffix = self._get_literal_suffix(real) return '1.0%s/%s' % (literal_suffix, self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5: return '%ssqrt%s(%s)' % (self._ns, suffix, self._print(expr.base)) elif expr.exp == S.One/3 and self.standard != 'C89': return '%scbrt%s(%s)' % (self._ns, suffix, self._print(expr.base)) else: return '%spow%s(%s, %s)' % (self._ns, suffix, self._print(expr.base), self._print(expr.exp)) def _print_Mod(self, expr): num, den = expr.args if num.is_integer and den.is_integer: return "(({}) % ({}))".format(self._print(num), self._print(den)) else: return self._print_math_func(expr, known='fmod') def _print_Rational(self, expr): p, q = int(expr.p), int(expr.q) suffix = self._get_literal_suffix(real) return '%d.0%s/%d.0%s' % (p, suffix, q, suffix) def _print_Indexed(self, expr): # calculate index for 1d array offset = getattr(expr.base, 'offset', S.Zero) strides = getattr(expr.base, 'strides', None) indices = expr.indices if strides is None or isinstance(strides, str): dims = expr.shape shift = S.One temp = tuple() if strides == 'C' or strides is None: traversal = reversed(range(expr.rank)) indices = indices[::-1] elif strides == 'F': traversal = range(expr.rank) for i in traversal: temp += (shift,) shift *= dims[i] strides = temp flat_index = sum([x[0]*x[1] for x in zip(indices, strides)]) + offset return "%s[%s]" % (self._print(expr.base.label), self._print(flat_index)) def _print_Idx(self, expr): return self._print(expr.label) @_as_macro_if_defined def _print_NumberSymbol(self, expr): return super()._print_NumberSymbol(expr) def _print_Infinity(self, expr): return 'HUGE_VAL' def _print_NegativeInfinity(self, expr): return '-HUGE_VAL' def _print_Piecewise(self, expr): if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") lines = [] if expr.has(Assignment): for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) {" % self._print(c)) elif i == len(expr.args) - 1 and c == True: lines.append("else {") else: lines.append("else if (%s) {" % self._print(c)) code0 = self._print(e) lines.append(code0) lines.append("}") return "\n".join(lines) else: # The piecewise was used in an expression, need to do inline # operators. This has the downside that inline operators will # not work for statements that span multiple lines (Matrix or # Indexed expressions). ecpairs = ["((%s) ? (\n%s\n)\n" % (self._print(c), self._print(e)) for e, c in expr.args[:-1]] last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr) return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)]) def _print_ITE(self, expr): from sympy.functions import Piecewise _piecewise = Piecewise((expr.args[1], expr.args[0]), (expr.args[2], True)) return self._print(_piecewise) def _print_MatrixElement(self, expr): return "{}[{}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True), expr.j + expr.i*expr.parent.shape[1]) def _print_Symbol(self, expr): name = super()._print_Symbol(expr) if expr in self._settings['dereference']: return '(*{})'.format(name) else: return name def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) def _print_sinc(self, expr): from sympy.functions.elementary.trigonometric import sin from sympy.core.relational import Ne from sympy.functions import Piecewise _piecewise = Piecewise( (sin(expr.args[0]) / expr.args[0], Ne(expr.args[0], 0)), (1, True)) return self._print(_piecewise) def _print_For(self, expr): target = self._print(expr.target) if isinstance(expr.iterable, Range): start, stop, step = expr.iterable.args else: raise NotImplementedError("Only iterable currently supported is Range") body = self._print(expr.body) return ('for ({target} = {start}; {target} < {stop}; {target} += ' '{step}) {{\n{body}\n}}').format(target=target, start=start, stop=stop, step=step, body=body) def _print_sign(self, func): return '((({0}) > 0) - (({0}) < 0))'.format(self._print(func.args[0])) def _print_Max(self, expr): if "Max" in self.known_functions: return self._print_Function(expr) def inner_print_max(args): # The more natural abstraction of creating if len(args) == 1: # and printing smaller Max objects is slow return self._print(args[0]) # when there are many arguments. half = len(args) // 2 return "((%(a)s > %(b)s) ? %(a)s : %(b)s)" % { 'a': inner_print_max(args[:half]), 'b': inner_print_max(args[half:]) } return inner_print_max(expr.args) def _print_Min(self, expr): if "Min" in self.known_functions: return self._print_Function(expr) def inner_print_min(args): # The more natural abstraction of creating if len(args) == 1: # and printing smaller Min objects is slow return self._print(args[0]) # when there are many arguments. half = len(args) // 2 return "((%(a)s < %(b)s) ? %(a)s : %(b)s)" % { 'a': inner_print_min(args[:half]), 'b': inner_print_min(args[half:]) } return inner_print_min(expr.args) def indent_code(self, code): """Accepts a string of code or a list of code lines""" if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) tab = " " inc_token = ('{', '(', '{\n', '(\n') dec_token = ('}', ')') code = [line.lstrip(' \t') for line in code] increase = [int(any(map(line.endswith, inc_token))) for line in code] decrease = [int(any(map(line.startswith, dec_token))) for line in code] pretty = [] level = 0 for n, line in enumerate(code): if line == '' or line == '\n': pretty.append(line) continue level -= decrease[n] pretty.append("%s%s" % (tab*level, line)) level += increase[n] return pretty def _get_func_suffix(self, type_): return self.type_func_suffixes[self.type_aliases.get(type_, type_)] def _get_literal_suffix(self, type_): return self.type_literal_suffixes[self.type_aliases.get(type_, type_)] def _get_math_macro_suffix(self, type_): alias = self.type_aliases.get(type_, type_) dflt = self.type_math_macro_suffixes.get(alias, '') return self.type_math_macro_suffixes.get(type_, dflt) def _print_Type(self, type_): self.headers.update(self.type_headers.get(type_, set())) self.macros.update(self.type_macros.get(type_, set())) return self._print(self.type_mappings.get(type_, type_.name)) def _print_Declaration(self, decl): from sympy.codegen.cnodes import restrict var = decl.variable val = var.value if var.type == untyped: raise ValueError("C does not support untyped variables") if isinstance(var, Pointer): result = '{vc}{t} *{pc} {r}{s}'.format( vc='const ' if value_const in var.attrs else '', t=self._print(var.type), pc=' const' if pointer_const in var.attrs else '', r='restrict ' if restrict in var.attrs else '', s=self._print(var.symbol) ) elif isinstance(var, Variable): result = '{vc}{t} {s}'.format( vc='const ' if value_const in var.attrs else '', t=self._print(var.type), s=self._print(var.symbol) ) else: raise NotImplementedError("Unknown type of var: %s" % type(var)) if val != None: # Must be "!= None", cannot be "is not None" result += ' = %s' % self._print(val) return result def _print_Float(self, flt): type_ = self.type_aliases.get(real, real) self.macros.update(self.type_macros.get(type_, set())) suffix = self._get_literal_suffix(type_) num = str(flt.evalf(type_.decimal_dig)) if 'e' not in num and '.' not in num: num += '.0' num_parts = num.split('e') num_parts[0] = num_parts[0].rstrip('0') if num_parts[0].endswith('.'): num_parts[0] += '0' return 'e'.join(num_parts) + suffix @requires(headers={'stdbool.h'}) def _print_BooleanTrue(self, expr): return 'true' @requires(headers={'stdbool.h'}) def _print_BooleanFalse(self, expr): return 'false' def _print_Element(self, elem): if elem.strides == None: # Must be "== None", cannot be "is None" if elem.offset != None: # Must be "!= None", cannot be "is not None" raise ValueError("Expected strides when offset is given") idxs = ']['.join(map(lambda arg: self._print(arg), elem.indices)) else: global_idx = sum([i*s for i, s in zip(elem.indices, elem.strides)]) if elem.offset != None: # Must be "!= None", cannot be "is not None" global_idx += elem.offset idxs = self._print(global_idx) return "{symb}[{idxs}]".format( symb=self._print(elem.symbol), idxs=idxs ) def _print_CodeBlock(self, expr): """ Elements of code blocks printed as statements. """ return '\n'.join([self._get_statement(self._print(i)) for i in expr.args]) def _print_While(self, expr): return 'while ({condition}) {{\n{body}\n}}'.format(**expr.kwargs( apply=lambda arg: self._print(arg))) def _print_Scope(self, expr): return '{\n%s\n}' % self._print_CodeBlock(expr.body) @requires(headers={'stdio.h'}) def _print_Print(self, expr): return 'printf({fmt}, {pargs})'.format( fmt=self._print(expr.format_string), pargs=', '.join(map(lambda arg: self._print(arg), expr.print_args)) ) def _print_FunctionPrototype(self, expr): pars = ', '.join(map(lambda arg: self._print(Declaration(arg)), expr.parameters)) return "%s %s(%s)" % ( tuple(map(lambda arg: self._print(arg), (expr.return_type, expr.name))) + (pars,) ) def _print_FunctionDefinition(self, expr): return "%s%s" % (self._print_FunctionPrototype(expr), self._print_Scope(expr)) def _print_Return(self, expr): arg, = expr.args return 'return %s' % self._print(arg) def _print_CommaOperator(self, expr): return '(%s)' % ', '.join(map(lambda arg: self._print(arg), expr.args)) def _print_Label(self, expr): if expr.body == none: return '%s:' % str(expr.name) if len(expr.body.args) == 1: return '%s:\n%s' % (str(expr.name), self._print_CodeBlock(expr.body)) return '%s:\n{\n%s\n}' % (str(expr.name), self._print_CodeBlock(expr.body)) def _print_goto(self, expr): return 'goto %s' % expr.label.name def _print_PreIncrement(self, expr): arg, = expr.args return '++(%s)' % self._print(arg) def _print_PostIncrement(self, expr): arg, = expr.args return '(%s)++' % self._print(arg) def _print_PreDecrement(self, expr): arg, = expr.args return '--(%s)' % self._print(arg) def _print_PostDecrement(self, expr): arg, = expr.args return '(%s)--' % self._print(arg) def _print_struct(self, expr): return "%(keyword)s %(name)s {\n%(lines)s}" % dict( keyword=expr.__class__.__name__, name=expr.name, lines=';\n'.join( [self._print(decl) for decl in expr.declarations] + ['']) ) def _print_BreakToken(self, _): return 'break' def _print_ContinueToken(self, _): return 'continue' _print_union = _print_struct class C99CodePrinter(C89CodePrinter): standard = 'C99' reserved_words = set(reserved_words + reserved_words_c99) type_mappings=dict(chain(C89CodePrinter.type_mappings.items(), { complex64: 'float complex', complex128: 'double complex', }.items())) type_headers = dict(chain(C89CodePrinter.type_headers.items(), { complex64: {'complex.h'}, complex128: {'complex.h'} }.items())) # known_functions-dict to copy _kf = known_functions_C99 # type: Dict[str, Any] # functions with versions with 'f' and 'l' suffixes: _prec_funcs = ('fabs fmod remainder remquo fma fmax fmin fdim nan exp exp2' ' expm1 log log10 log2 log1p pow sqrt cbrt hypot sin cos tan' ' asin acos atan atan2 sinh cosh tanh asinh acosh atanh erf' ' erfc tgamma lgamma ceil floor trunc round nearbyint rint' ' frexp ldexp modf scalbn ilogb logb nextafter copysign').split() def _print_Infinity(self, expr): return 'INFINITY' def _print_NegativeInfinity(self, expr): return '-INFINITY' def _print_NaN(self, expr): return 'NAN' # tgamma was already covered by 'known_functions' dict @requires(headers={'math.h'}, libraries={'m'}) @_as_macro_if_defined def _print_math_func(self, expr, nest=False, known=None): if known is None: known = self.known_functions[expr.__class__.__name__] if not isinstance(known, str): for cb, name in known: if cb(*expr.args): known = name break else: raise ValueError("No matching printer") try: return known(self, *expr.args) except TypeError: suffix = self._get_func_suffix(real) if self._ns + known in self._prec_funcs else '' if nest: args = self._print(expr.args[0]) if len(expr.args) > 1: paren_pile = '' for curr_arg in expr.args[1:-1]: paren_pile += ')' args += ', {ns}{name}{suffix}({next}'.format( ns=self._ns, name=known, suffix=suffix, next = self._print(curr_arg) ) args += ', %s%s' % ( self._print(expr.func(expr.args[-1])), paren_pile ) else: args = ', '.join(map(lambda arg: self._print(arg), expr.args)) return '{ns}{name}{suffix}({args})'.format( ns=self._ns, name=known, suffix=suffix, args=args ) def _print_Max(self, expr): return self._print_math_func(expr, nest=True) def _print_Min(self, expr): return self._print_math_func(expr, nest=True) def _get_loop_opening_ending(self, indices): open_lines = [] close_lines = [] loopstart = "for (int %(var)s=%(start)s; %(var)s<%(end)s; %(var)s++){" # C99 for i in indices: # C arrays start at 0 and end at dimension-1 open_lines.append(loopstart % { 'var': self._print(i.label), 'start': self._print(i.lower), 'end': self._print(i.upper + 1)}) close_lines.append("}") return open_lines, close_lines for k in ('Abs Sqrt exp exp2 expm1 log log10 log2 log1p Cbrt hypot fma' ' loggamma sin cos tan asin acos atan atan2 sinh cosh tanh asinh acosh ' 'atanh erf erfc loggamma gamma ceiling floor').split(): setattr(C99CodePrinter, '_print_%s' % k, C99CodePrinter._print_math_func) class C11CodePrinter(C99CodePrinter): @requires(headers={'stdalign.h'}) def _print_alignof(self, expr): arg, = expr.args return 'alignof(%s)' % self._print(arg) c_code_printers = { 'c89': C89CodePrinter, 'c99': C99CodePrinter, 'c11': C11CodePrinter } sympy-sympy-1.9/sympy/printing/ccode.py000066400000000000000000000011451412543434000203660ustar00rootroot00000000000000""" This is a shim file to provide backwards compatibility (ccode.py was renamed to c.py in SymPy 1.7). """ from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="importing from sympy.printing.ccode", useinstead="Import from sympy.printing.c", issue=20256, deprecated_since_version="1.7").warn() from .c import (ccode, print_ccode, known_functions_C89, known_functions_C99, # noqa:F401 reserved_words, reserved_words_c99, get_math_macros, C89CodePrinter, C99CodePrinter, C11CodePrinter, c_code_printers) sympy-sympy-1.9/sympy/printing/codeprinter.py000066400000000000000000000775441412543434000216470ustar00rootroot00000000000000from typing import Any, Dict, Set, Tuple from functools import wraps from sympy.core import Add, Expr, Mul, Pow, S, sympify, Float from sympy.core.basic import Basic from sympy.core.compatibility import default_sort_key from sympy.core.function import Lambda from sympy.core.mul import _keep_coeff from sympy.core.symbol import Symbol from sympy.printing.str import StrPrinter from sympy.printing.precedence import precedence class requires: """ Decorator for registering requirements on print methods. """ def __init__(self, **kwargs): self._req = kwargs def __call__(self, method): def _method_wrapper(self_, *args, **kwargs): for k, v in self._req.items(): getattr(self_, k).update(v) return method(self_, *args, **kwargs) return wraps(method)(_method_wrapper) class AssignmentError(Exception): """ Raised if an assignment variable for a loop is missing. """ pass class CodePrinter(StrPrinter): """ The base class for code-printing subclasses. """ _operators = { 'and': '&&', 'or': '||', 'not': '!', } _default_settings = { 'order': None, 'full_prec': 'auto', 'error_on_reserved': False, 'reserved_word_suffix': '_', 'human': True, 'inline': False, 'allow_unknown_functions': False, } # type: Dict[str, Any] # Functions which are "simple" to rewrite to other functions that # may be supported _rewriteable_functions = { 'erf2': 'erf', 'Li': 'li', 'beta': 'gamma' } def __init__(self, settings=None): super().__init__(settings=settings) if not hasattr(self, 'reserved_words'): self.reserved_words = set() def doprint(self, expr, assign_to=None): """ Print the expression as code. Parameters ---------- expr : Expression The expression to be printed. assign_to : Symbol, string, MatrixSymbol, list of strings or Symbols (optional) If provided, the printed code will set the expression to a variable or multiple variables with the name or names given in ``assign_to``. """ from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.codegen.ast import CodeBlock, Assignment def _handle_assign_to(expr, assign_to): if assign_to is None: return sympify(expr) if isinstance(assign_to, (list, tuple)): if len(expr) != len(assign_to): raise ValueError('Failed to assign an expression of length {} to {} variables'.format(len(expr), len(assign_to))) return CodeBlock(*[_handle_assign_to(lhs, rhs) for lhs, rhs in zip(expr, assign_to)]) if isinstance(assign_to, str): if expr.is_Matrix: assign_to = MatrixSymbol(assign_to, *expr.shape) else: assign_to = Symbol(assign_to) elif not isinstance(assign_to, Basic): raise TypeError("{} cannot assign to object of type {}".format( type(self).__name__, type(assign_to))) return Assignment(assign_to, expr) expr = _handle_assign_to(expr, assign_to) # keep a set of expressions that are not strictly translatable to Code # and number constants that must be declared and initialized self._not_supported = set() self._number_symbols = set() # type: Set[Tuple[Expr, Float]] lines = self._print(expr).splitlines() # format the output if self._settings["human"]: frontlines = [] if self._not_supported: frontlines.append(self._get_comment( "Not supported in {}:".format(self.language))) for expr in sorted(self._not_supported, key=str): frontlines.append(self._get_comment(type(expr).__name__)) for name, value in sorted(self._number_symbols, key=str): frontlines.append(self._declare_number_const(name, value)) lines = frontlines + lines lines = self._format_code(lines) result = "\n".join(lines) else: lines = self._format_code(lines) num_syms = {(k, self._print(v)) for k, v in self._number_symbols} result = (num_syms, self._not_supported, "\n".join(lines)) self._not_supported = set() self._number_symbols = set() return result def _doprint_loops(self, expr, assign_to=None): # Here we print an expression that contains Indexed objects, they # correspond to arrays in the generated code. The low-level implementation # involves looping over array elements and possibly storing results in temporary # variables or accumulate it in the assign_to object. if self._settings.get('contract', True): from sympy.tensor import get_contraction_structure # Setup loops over non-dummy indices -- all terms need these indices = self._get_expression_indices(expr, assign_to) # Setup loops over dummy indices -- each term needs separate treatment dummies = get_contraction_structure(expr) else: indices = [] dummies = {None: (expr,)} openloop, closeloop = self._get_loop_opening_ending(indices) # terms with no summations first if None in dummies: text = StrPrinter.doprint(self, Add(*dummies[None])) else: # If all terms have summations we must initialize array to Zero text = StrPrinter.doprint(self, 0) # skip redundant assignments (where lhs == rhs) lhs_printed = self._print(assign_to) lines = [] if text != lhs_printed: lines.extend(openloop) if assign_to is not None: text = self._get_statement("%s = %s" % (lhs_printed, text)) lines.append(text) lines.extend(closeloop) # then terms with summations for d in dummies: if isinstance(d, tuple): indices = self._sort_optimized(d, expr) openloop_d, closeloop_d = self._get_loop_opening_ending( indices) for term in dummies[d]: if term in dummies and not ([list(f.keys()) for f in dummies[term]] == [[None] for f in dummies[term]]): # If one factor in the term has it's own internal # contractions, those must be computed first. # (temporary variables?) raise NotImplementedError( "FIXME: no support for contractions in factor yet") else: # We need the lhs expression as an accumulator for # the loops, i.e # # for (int d=0; d < dim; d++){ # lhs[] = lhs[] + term[][d] # } ^.................. the accumulator # # We check if the expression already contains the # lhs, and raise an exception if it does, as that # syntax is currently undefined. FIXME: What would be # a good interpretation? if assign_to is None: raise AssignmentError( "need assignment variable for loops") if term.has(assign_to): raise ValueError("FIXME: lhs present in rhs,\ this is undefined in CodePrinter") lines.extend(openloop) lines.extend(openloop_d) text = "%s = %s" % (lhs_printed, StrPrinter.doprint( self, assign_to + term)) lines.append(self._get_statement(text)) lines.extend(closeloop_d) lines.extend(closeloop) return "\n".join(lines) def _get_expression_indices(self, expr, assign_to): from sympy.tensor import get_indices rinds, junk = get_indices(expr) linds, junk = get_indices(assign_to) # support broadcast of scalar if linds and not rinds: rinds = linds if rinds != linds: raise ValueError("lhs indices must match non-dummy" " rhs indices in %s" % expr) return self._sort_optimized(rinds, assign_to) def _sort_optimized(self, indices, expr): from sympy.tensor.indexed import Indexed if not indices: return [] # determine optimized loop order by giving a score to each index # the index with the highest score are put in the innermost loop. score_table = {} for i in indices: score_table[i] = 0 arrays = expr.atoms(Indexed) for arr in arrays: for p, ind in enumerate(arr.indices): try: score_table[ind] += self._rate_index_position(p) except KeyError: pass return sorted(indices, key=lambda x: score_table[x]) def _rate_index_position(self, p): """function to calculate score based on position among indices This method is used to sort loops in an optimized order, see CodePrinter._sort_optimized() """ raise NotImplementedError("This function must be implemented by " "subclass of CodePrinter.") def _get_statement(self, codestring): """Formats a codestring with the proper line ending.""" raise NotImplementedError("This function must be implemented by " "subclass of CodePrinter.") def _get_comment(self, text): """Formats a text string as a comment.""" raise NotImplementedError("This function must be implemented by " "subclass of CodePrinter.") def _declare_number_const(self, name, value): """Declare a numeric constant at the top of a function""" raise NotImplementedError("This function must be implemented by " "subclass of CodePrinter.") def _format_code(self, lines): """Take in a list of lines of code, and format them accordingly. This may include indenting, wrapping long lines, etc...""" raise NotImplementedError("This function must be implemented by " "subclass of CodePrinter.") def _get_loop_opening_ending(self, indices): """Returns a tuple (open_lines, close_lines) containing lists of codelines""" raise NotImplementedError("This function must be implemented by " "subclass of CodePrinter.") def _print_Dummy(self, expr): if expr.name.startswith('Dummy_'): return '_' + expr.name else: return '%s_%d' % (expr.name, expr.dummy_index) def _print_CodeBlock(self, expr): return '\n'.join([self._print(i) for i in expr.args]) def _print_String(self, string): return str(string) def _print_QuotedString(self, arg): return '"%s"' % arg.text def _print_Comment(self, string): return self._get_comment(str(string)) def _print_Assignment(self, expr): from sympy.codegen.ast import Assignment from sympy.functions.elementary.piecewise import Piecewise from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.tensor.indexed import IndexedBase lhs = expr.lhs rhs = expr.rhs # We special case assignments that take multiple lines if isinstance(expr.rhs, Piecewise): # Here we modify Piecewise so each expression is now # an Assignment, and then continue on the print. expressions = [] conditions = [] for (e, c) in rhs.args: expressions.append(Assignment(lhs, e)) conditions.append(c) temp = Piecewise(*zip(expressions, conditions)) return self._print(temp) elif isinstance(lhs, MatrixSymbol): # Here we form an Assignment for each element in the array, # printing each one. lines = [] for (i, j) in self._traverse_matrix_indices(lhs): temp = Assignment(lhs[i, j], rhs[i, j]) code0 = self._print(temp) lines.append(code0) return "\n".join(lines) elif self._settings.get("contract", False) and (lhs.has(IndexedBase) or rhs.has(IndexedBase)): # Here we check if there is looping to be done, and if so # print the required loops. return self._doprint_loops(rhs, lhs) else: lhs_code = self._print(lhs) rhs_code = self._print(rhs) return self._get_statement("%s = %s" % (lhs_code, rhs_code)) def _print_AugmentedAssignment(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) return self._get_statement("{} {} {}".format( *map(lambda arg: self._print(arg), [lhs_code, expr.op, rhs_code]))) def _print_FunctionCall(self, expr): return '%s(%s)' % ( expr.name, ', '.join(map(lambda arg: self._print(arg), expr.function_args))) def _print_Variable(self, expr): return self._print(expr.symbol) def _print_Statement(self, expr): arg, = expr.args return self._get_statement(self._print(arg)) def _print_Symbol(self, expr): name = super()._print_Symbol(expr) if name in self.reserved_words: if self._settings['error_on_reserved']: msg = ('This expression includes the symbol "{}" which is a ' 'reserved keyword in this language.') raise ValueError(msg.format(name)) return name + self._settings['reserved_word_suffix'] else: return name def _print_Function(self, expr): if expr.func.__name__ in self.known_functions: cond_func = self.known_functions[expr.func.__name__] func = None if isinstance(cond_func, str): func = cond_func else: for cond, func in cond_func: if cond(*expr.args): break if func is not None: try: return func(*[self.parenthesize(item, 0) for item in expr.args]) except TypeError: return "%s(%s)" % (func, self.stringify(expr.args, ", ")) elif hasattr(expr, '_imp_') and isinstance(expr._imp_, Lambda): # inlined function return self._print(expr._imp_(*expr.args)) elif (expr.func.__name__ in self._rewriteable_functions and self._rewriteable_functions[expr.func.__name__] in self.known_functions): # Simple rewrite to supported function possible return self._print(expr.rewrite(self._rewriteable_functions[expr.func.__name__])) elif expr.is_Function and self._settings.get('allow_unknown_functions', False): return '%s(%s)' % (self._print(expr.func), ', '.join(map(self._print, expr.args))) else: return self._print_not_supported(expr) _print_Expr = _print_Function # Don't inherit the str-printer method for Heaviside to the code printers _print_Heaviside = None def _print_NumberSymbol(self, expr): if self._settings.get("inline", False): return self._print(Float(expr.evalf(self._settings["precision"]))) else: # A Number symbol that is not implemented here or with _printmethod # is registered and evaluated self._number_symbols.add((expr, Float(expr.evalf(self._settings["precision"])))) return str(expr) def _print_Catalan(self, expr): return self._print_NumberSymbol(expr) def _print_EulerGamma(self, expr): return self._print_NumberSymbol(expr) def _print_GoldenRatio(self, expr): return self._print_NumberSymbol(expr) def _print_TribonacciConstant(self, expr): return self._print_NumberSymbol(expr) def _print_Exp1(self, expr): return self._print_NumberSymbol(expr) def _print_Pi(self, expr): return self._print_NumberSymbol(expr) def _print_And(self, expr): PREC = precedence(expr) return (" %s " % self._operators['and']).join(self.parenthesize(a, PREC) for a in sorted(expr.args, key=default_sort_key)) def _print_Or(self, expr): PREC = precedence(expr) return (" %s " % self._operators['or']).join(self.parenthesize(a, PREC) for a in sorted(expr.args, key=default_sort_key)) def _print_Xor(self, expr): if self._operators.get('xor') is None: return self._print_not_supported(expr) PREC = precedence(expr) return (" %s " % self._operators['xor']).join(self.parenthesize(a, PREC) for a in expr.args) def _print_Equivalent(self, expr): if self._operators.get('equivalent') is None: return self._print_not_supported(expr) PREC = precedence(expr) return (" %s " % self._operators['equivalent']).join(self.parenthesize(a, PREC) for a in expr.args) def _print_Not(self, expr): PREC = precedence(expr) return self._operators['not'] + self.parenthesize(expr.args[0], PREC) def _print_Mul(self, expr): prec = precedence(expr) c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160 pow_paren.append(item) b.append(Pow(item.base, -item.exp)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec) for x in a] b_str = [self.parenthesize(x, prec) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] if not b: return sign + '*'.join(a_str) elif len(b) == 1: return sign + '*'.join(a_str) + "/" + b_str[0] else: return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str) def _print_not_supported(self, expr): try: self._not_supported.add(expr) except TypeError: # not hashable pass return self.emptyPrinter(expr) # The following can not be simply translated into C or Fortran _print_Basic = _print_not_supported _print_ComplexInfinity = _print_not_supported _print_Derivative = _print_not_supported _print_ExprCondPair = _print_not_supported _print_GeometryEntity = _print_not_supported _print_Infinity = _print_not_supported _print_Integral = _print_not_supported _print_Interval = _print_not_supported _print_AccumulationBounds = _print_not_supported _print_Limit = _print_not_supported _print_MatrixBase = _print_not_supported _print_DeferredVector = _print_not_supported _print_NaN = _print_not_supported _print_NegativeInfinity = _print_not_supported _print_Order = _print_not_supported _print_RootOf = _print_not_supported _print_RootsOf = _print_not_supported _print_RootSum = _print_not_supported _print_Uniform = _print_not_supported _print_Unit = _print_not_supported _print_Wild = _print_not_supported _print_WildFunction = _print_not_supported _print_Relational = _print_not_supported # Code printer functions. These are included in this file so that they can be # imported in the top-level __init__.py without importing the sympy.codegen # module. def ccode(expr, assign_to=None, standard='c99', **settings): """Converts an expr to a string of c code Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of line-wrapping, or for expressions that generate multi-line statements. standard : str, optional String specifying the standard. If your compiler supports a more modern standard you may set this to 'c99' to allow the printer to use more math functions. [default='c89']. precision : integer, optional The precision for numbers such as pi [default=17]. user_functions : dict, optional A dictionary where the keys are string representations of either ``FunctionClass`` or ``UndefinedFunction`` instances and the values are their desired C string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)] or [(argument_test, cfunction_formater)]. See below for examples. dereference : iterable, optional An iterable of symbols that should be dereferenced in the printed code expression. These would be values passed by address to the function. For example, if ``dereference=[a]``, the resulting code would print ``(*a)`` instead of ``a``. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. Examples ======== >>> from sympy import ccode, symbols, Rational, sin, ceiling, Abs, Function >>> x, tau = symbols("x, tau") >>> expr = (2*tau)**Rational(7, 2) >>> ccode(expr) '8*M_SQRT2*pow(tau, 7.0/2.0)' >>> ccode(expr, math_macros={}) '8*sqrt(2)*pow(tau, 7.0/2.0)' >>> ccode(sin(x), assign_to="s") 's = sin(x);' >>> from sympy.codegen.ast import real, float80 >>> ccode(expr, type_aliases={real: float80}) '8*M_SQRT2l*powl(tau, 7.0L/2.0L)' Simple custom printing can be defined for certain types by passing a dictionary of {"type" : "function"} to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. >>> custom_functions = { ... "ceiling": "CEIL", ... "Abs": [(lambda x: not x.is_integer, "fabs"), ... (lambda x: x.is_integer, "ABS")], ... "func": "f" ... } >>> func = Function('func') >>> ccode(func(Abs(x) + ceiling(x)), standard='C89', user_functions=custom_functions) 'f(fabs(x) + CEIL(x))' or if the C-function takes a subset of the original arguments: >>> ccode(2**x + 3**x, standard='C99', user_functions={'Pow': [ ... (lambda b, e: b == 2, lambda b, e: 'exp2(%s)' % e), ... (lambda b, e: b != 2, 'pow')]}) 'exp2(x) + pow(3, x)' ``Piecewise`` expressions are converted into conditionals. If an ``assign_to`` variable is provided an if statement is created, otherwise the ternary operator is used. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> expr = Piecewise((x + 1, x > 0), (x, True)) >>> print(ccode(expr, tau, standard='C89')) if (x > 0) { tau = x + 1; } else { tau = x; } Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> ccode(e.rhs, assign_to=e.lhs, contract=False, standard='C89') 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions must be provided to ``assign_to``. Note that any expression that can be generated normally can also exist inside a Matrix: >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) >>> A = MatrixSymbol('A', 3, 1) >>> print(ccode(mat, A, standard='C89')) A[0] = pow(x, 2); if (x > 0) { A[1] = x + 1; } else { A[1] = x; } A[2] = sin(x); """ from sympy.printing.c import c_code_printers return c_code_printers[standard.lower()](settings).doprint(expr, assign_to) def print_ccode(expr, **settings): """Prints C representation of the given expression.""" print(ccode(expr, **settings)) def fcode(expr, assign_to=None, **settings): """Converts an expr to a string of fortran code Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of line-wrapping, or for expressions that generate multi-line statements. precision : integer, optional DEPRECATED. Use type_mappings instead. The precision for numbers such as pi [default=17]. user_functions : dict, optional A dictionary where keys are ``FunctionClass`` instances and values are their string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. See below for examples. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. source_format : optional The source format can be either 'fixed' or 'free'. [default='fixed'] standard : integer, optional The Fortran standard to be followed. This is specified as an integer. Acceptable standards are 66, 77, 90, 95, 2003, and 2008. Default is 77. Note that currently the only distinction internally is between standards before 95, and those 95 and after. This may change later as more features are added. name_mangling : bool, optional If True, then the variables that would become identical in case-insensitive Fortran are mangled by appending different number of ``_`` at the end. If False, SymPy won't interfere with naming of variables. [default=True] Examples ======== >>> from sympy import fcode, symbols, Rational, sin, ceiling, floor >>> x, tau = symbols("x, tau") >>> fcode((2*tau)**Rational(7, 2)) ' 8*sqrt(2.0d0)*tau**(7.0d0/2.0d0)' >>> fcode(sin(x), assign_to="s") ' s = sin(x)' Custom printing can be defined for certain types by passing a dictionary of "type" : "function" to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. >>> custom_functions = { ... "ceiling": "CEIL", ... "floor": [(lambda x: not x.is_integer, "FLOOR1"), ... (lambda x: x.is_integer, "FLOOR2")] ... } >>> fcode(floor(x) + ceiling(x), user_functions=custom_functions) ' CEIL(x) + FLOOR1(x)' ``Piecewise`` expressions are converted into conditionals. If an ``assign_to`` variable is provided an if statement is created, otherwise the ternary operator is used. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> expr = Piecewise((x + 1, x > 0), (x, True)) >>> print(fcode(expr, tau)) if (x > 0) then tau = x + 1 else tau = x end if Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> fcode(e.rhs, assign_to=e.lhs, contract=False) ' Dy(i) = (y(i + 1) - y(i))/(t(i + 1) - t(i))' Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions must be provided to ``assign_to``. Note that any expression that can be generated normally can also exist inside a Matrix: >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) >>> A = MatrixSymbol('A', 3, 1) >>> print(fcode(mat, A)) A(1, 1) = x**2 if (x > 0) then A(2, 1) = x + 1 else A(2, 1) = x end if A(3, 1) = sin(x) """ from sympy.printing.fortran import FCodePrinter return FCodePrinter(settings).doprint(expr, assign_to) def print_fcode(expr, **settings): """Prints the Fortran representation of the given expression. See fcode for the meaning of the optional arguments. """ print(fcode(expr, **settings)) def cxxcode(expr, assign_to=None, standard='c++11', **settings): """ C++ equivalent of :func:`~.ccode`. """ from sympy.printing.cxx import cxx_code_printers return cxx_code_printers[standard.lower()](settings).doprint(expr, assign_to) sympy-sympy-1.9/sympy/printing/conventions.py000066400000000000000000000050051412543434000216550ustar00rootroot00000000000000""" A few practical conventions common to all printers. """ import re from collections.abc import Iterable from sympy import Derivative _name_with_digits_p = re.compile(r'^([^\W\d_]+)(\d+)$', re.U) def split_super_sub(text): """Split a symbol name into a name, superscripts and subscripts The first part of the symbol name is considered to be its actual 'name', followed by super- and subscripts. Each superscript is preceded with a "^" character or by "__". Each subscript is preceded by a "_" character. The three return values are the actual name, a list with superscripts and a list with subscripts. Examples ======== >>> from sympy.printing.conventions import split_super_sub >>> split_super_sub('a_x^1') ('a', ['1'], ['x']) >>> split_super_sub('var_sub1__sup_sub2') ('var', ['sup'], ['sub1', 'sub2']) """ if not text: return text, [], [] pos = 0 name = None supers = [] subs = [] while pos < len(text): start = pos + 1 if text[pos:pos + 2] == "__": start += 1 pos_hat = text.find("^", start) if pos_hat < 0: pos_hat = len(text) pos_usc = text.find("_", start) if pos_usc < 0: pos_usc = len(text) pos_next = min(pos_hat, pos_usc) part = text[pos:pos_next] pos = pos_next if name is None: name = part elif part.startswith("^"): supers.append(part[1:]) elif part.startswith("__"): supers.append(part[2:]) elif part.startswith("_"): subs.append(part[1:]) else: raise RuntimeError("This should never happen.") # Make a little exception when a name ends with digits, i.e. treat them # as a subscript too. m = _name_with_digits_p.match(name) if m: name, sub = m.groups() subs.insert(0, sub) return name, supers, subs def requires_partial(expr): """Return whether a partial derivative symbol is required for printing This requires checking how many free variables there are, filtering out the ones that are integers. Some expressions don't have free variables. In that case, check its variable list explicitly to get the context of the expression. """ if isinstance(expr, Derivative): return requires_partial(expr.expr) if not isinstance(expr.free_symbols, Iterable): return len(set(expr.variables)) > 1 return sum(not s.is_integer for s in expr.free_symbols) > 1 sympy-sympy-1.9/sympy/printing/cxx.py000066400000000000000000000130411412543434000201110ustar00rootroot00000000000000""" C++ code printer """ from itertools import chain from sympy.codegen.ast import Type, none from .c import C89CodePrinter, C99CodePrinter # These are defined in the other file so we can avoid importing sympy.codegen # from the top-level 'import sympy'. Export them here as well. from sympy.printing.codeprinter import cxxcode # noqa:F401 # from http://en.cppreference.com/w/cpp/keyword reserved = { 'C++98': [ 'and', 'and_eq', 'asm', 'auto', 'bitand', 'bitor', 'bool', 'break', 'case', 'catch,', 'char', 'class', 'compl', 'const', 'const_cast', 'continue', 'default', 'delete', 'do', 'double', 'dynamic_cast', 'else', 'enum', 'explicit', 'export', 'extern', 'false', 'float', 'for', 'friend', 'goto', 'if', 'inline', 'int', 'long', 'mutable', 'namespace', 'new', 'not', 'not_eq', 'operator', 'or', 'or_eq', 'private', 'protected', 'public', 'register', 'reinterpret_cast', 'return', 'short', 'signed', 'sizeof', 'static', 'static_cast', 'struct', 'switch', 'template', 'this', 'throw', 'true', 'try', 'typedef', 'typeid', 'typename', 'union', 'unsigned', 'using', 'virtual', 'void', 'volatile', 'wchar_t', 'while', 'xor', 'xor_eq' ] } reserved['C++11'] = reserved['C++98'][:] + [ 'alignas', 'alignof', 'char16_t', 'char32_t', 'constexpr', 'decltype', 'noexcept', 'nullptr', 'static_assert', 'thread_local' ] reserved['C++17'] = reserved['C++11'][:] reserved['C++17'].remove('register') # TM TS: atomic_cancel, atomic_commit, atomic_noexcept, synchronized # concepts TS: concept, requires # module TS: import, module _math_functions = { 'C++98': { 'Mod': 'fmod', 'ceiling': 'ceil', }, 'C++11': { 'gamma': 'tgamma', }, 'C++17': { 'beta': 'beta', 'Ei': 'expint', 'zeta': 'riemann_zeta', } } # from http://en.cppreference.com/w/cpp/header/cmath for k in ('Abs', 'exp', 'log', 'log10', 'sqrt', 'sin', 'cos', 'tan', # 'Pow' 'asin', 'acos', 'atan', 'atan2', 'sinh', 'cosh', 'tanh', 'floor'): _math_functions['C++98'][k] = k.lower() for k in ('asinh', 'acosh', 'atanh', 'erf', 'erfc'): _math_functions['C++11'][k] = k.lower() def _attach_print_method(cls, sympy_name, func_name): meth_name = '_print_%s' % sympy_name if hasattr(cls, meth_name): raise ValueError("Edit method (or subclass) instead of overwriting.") def _print_method(self, expr): return '{}{}({})'.format(self._ns, func_name, ', '.join(map(self._print, expr.args))) _print_method.__doc__ = "Prints code for %s" % k setattr(cls, meth_name, _print_method) def _attach_print_methods(cls, cont): for sympy_name, cxx_name in cont[cls.standard].items(): _attach_print_method(cls, sympy_name, cxx_name) class _CXXCodePrinterBase: printmethod = "_cxxcode" language = 'C++' _ns = 'std::' # namespace def __init__(self, settings=None): super().__init__(settings or {}) def _print_Max(self, expr): from sympy import Max if len(expr.args) == 1: return self._print(expr.args[0]) return "%smax(%s, %s)" % (self._ns, self._print(expr.args[0]), self._print(Max(*expr.args[1:]))) def _print_Min(self, expr): from sympy import Min if len(expr.args) == 1: return self._print(expr.args[0]) return "%smin(%s, %s)" % (self._ns, self._print(expr.args[0]), self._print(Min(*expr.args[1:]))) def _print_using(self, expr): if expr.alias == none: return 'using %s' % expr.type else: raise ValueError("C++98 does not support type aliases") class CXX98CodePrinter(_CXXCodePrinterBase, C89CodePrinter): standard = 'C++98' reserved_words = set(reserved['C++98']) # _attach_print_methods(CXX98CodePrinter, _math_functions) class CXX11CodePrinter(_CXXCodePrinterBase, C99CodePrinter): standard = 'C++11' reserved_words = set(reserved['C++11']) type_mappings = dict(chain( CXX98CodePrinter.type_mappings.items(), { Type('int8'): ('int8_t', {'cstdint'}), Type('int16'): ('int16_t', {'cstdint'}), Type('int32'): ('int32_t', {'cstdint'}), Type('int64'): ('int64_t', {'cstdint'}), Type('uint8'): ('uint8_t', {'cstdint'}), Type('uint16'): ('uint16_t', {'cstdint'}), Type('uint32'): ('uint32_t', {'cstdint'}), Type('uint64'): ('uint64_t', {'cstdint'}), Type('complex64'): ('std::complex', {'complex'}), Type('complex128'): ('std::complex', {'complex'}), Type('bool'): ('bool', None), }.items() )) def _print_using(self, expr): if expr.alias == none: return super()._print_using(expr) else: return 'using %(alias)s = %(type)s' % expr.kwargs(apply=self._print) # _attach_print_methods(CXX11CodePrinter, _math_functions) class CXX17CodePrinter(_CXXCodePrinterBase, C99CodePrinter): standard = 'C++17' reserved_words = set(reserved['C++17']) _kf = dict(C99CodePrinter._kf, **_math_functions['C++17']) def _print_beta(self, expr): return self._print_math_func(expr) def _print_Ei(self, expr): return self._print_math_func(expr) def _print_zeta(self, expr): return self._print_math_func(expr) # _attach_print_methods(CXX17CodePrinter, _math_functions) cxx_code_printers = { 'c++98': CXX98CodePrinter, 'c++11': CXX11CodePrinter, 'c++17': CXX17CodePrinter } sympy-sympy-1.9/sympy/printing/cxxcode.py000066400000000000000000000007711412543434000207520ustar00rootroot00000000000000""" This is a shim file to provide backwards compatibility (cxxcode.py was renamed to cxx.py in SymPy 1.7). """ from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="importing from sympy.printing.cxxcode", useinstead="Import from sympy.printing.cxx", issue=20256, deprecated_since_version="1.7").warn() from .cxx import (cxxcode, reserved, CXX98CodePrinter, # noqa:F401 CXX11CodePrinter, CXX17CodePrinter, cxx_code_printers) sympy-sympy-1.9/sympy/printing/defaults.py000066400000000000000000000002071412543434000211160ustar00rootroot00000000000000from sympy.core._print_helpers import Printable # alias for compatibility Printable.__module__ = __name__ DefaultPrinting = Printable sympy-sympy-1.9/sympy/printing/dot.py000066400000000000000000000201351412543434000200770ustar00rootroot00000000000000from sympy.core.basic import Basic from sympy.core.expr import Expr from sympy.core.symbol import Symbol from sympy.core.numbers import Integer, Rational, Float from sympy.printing.repr import srepr __all__ = ['dotprint'] default_styles = ( (Basic, {'color': 'blue', 'shape': 'ellipse'}), (Expr, {'color': 'black'}) ) slotClasses = (Symbol, Integer, Rational, Float) def purestr(x, with_args=False): """A string that follows ```obj = type(obj)(*obj.args)``` exactly. Parameters ========== with_args : boolean, optional If ``True``, there will be a second argument for the return value, which is a tuple containing ``purestr`` applied to each of the subnodes. If ``False``, there will not be a second argument for the return. Default is ``False`` Examples ======== >>> from sympy import Float, Symbol, MatrixSymbol >>> from sympy import Integer # noqa: F401 >>> from sympy.core.symbol import Str # noqa: F401 >>> from sympy.printing.dot import purestr Applying ``purestr`` for basic symbolic object: >>> code = purestr(Symbol('x')) >>> code "Symbol('x')" >>> eval(code) == Symbol('x') True For basic numeric object: >>> purestr(Float(2)) "Float('2.0', precision=53)" For matrix symbol: >>> code = purestr(MatrixSymbol('x', 2, 2)) >>> code "MatrixSymbol(Str('x'), Integer(2), Integer(2))" >>> eval(code) == MatrixSymbol('x', 2, 2) True With ``with_args=True``: >>> purestr(Float(2), with_args=True) ("Float('2.0', precision=53)", ()) >>> purestr(MatrixSymbol('x', 2, 2), with_args=True) ("MatrixSymbol(Str('x'), Integer(2), Integer(2))", ("Str('x')", 'Integer(2)', 'Integer(2)')) """ sargs = () if not isinstance(x, Basic): rv = str(x) elif not x.args: rv = srepr(x) else: args = x.args sargs = tuple(map(purestr, args)) rv = "%s(%s)"%(type(x).__name__, ', '.join(sargs)) if with_args: rv = rv, sargs return rv def styleof(expr, styles=default_styles): """ Merge style dictionaries in order Examples ======== >>> from sympy import Symbol, Basic, Expr >>> from sympy.printing.dot import styleof >>> styles = [(Basic, {'color': 'blue', 'shape': 'ellipse'}), ... (Expr, {'color': 'black'})] >>> styleof(Basic(1), styles) {'color': 'blue', 'shape': 'ellipse'} >>> x = Symbol('x') >>> styleof(x + 1, styles) # this is an Expr {'color': 'black', 'shape': 'ellipse'} """ style = dict() for typ, sty in styles: if isinstance(expr, typ): style.update(sty) return style def attrprint(d, delimiter=', '): """ Print a dictionary of attributes Examples ======== >>> from sympy.printing.dot import attrprint >>> print(attrprint({'color': 'blue', 'shape': 'ellipse'})) "color"="blue", "shape"="ellipse" """ return delimiter.join('"%s"="%s"'%item for item in sorted(d.items())) def dotnode(expr, styles=default_styles, labelfunc=str, pos=(), repeat=True): """ String defining a node Examples ======== >>> from sympy.printing.dot import dotnode >>> from sympy.abc import x >>> print(dotnode(x)) "Symbol('x')_()" ["color"="black", "label"="x", "shape"="ellipse"]; """ style = styleof(expr, styles) if isinstance(expr, Basic) and not expr.is_Atom: label = str(expr.__class__.__name__) else: label = labelfunc(expr) style['label'] = label expr_str = purestr(expr) if repeat: expr_str += '_%s' % str(pos) return '"%s" [%s];' % (expr_str, attrprint(style)) def dotedges(expr, atom=lambda x: not isinstance(x, Basic), pos=(), repeat=True): """ List of strings for all expr->expr.arg pairs See the docstring of dotprint for explanations of the options. Examples ======== >>> from sympy.printing.dot import dotedges >>> from sympy.abc import x >>> for e in dotedges(x+2): ... print(e) "Add(Integer(2), Symbol('x'))_()" -> "Integer(2)_(0,)"; "Add(Integer(2), Symbol('x'))_()" -> "Symbol('x')_(1,)"; """ if atom(expr): return [] else: expr_str, arg_strs = purestr(expr, with_args=True) if repeat: expr_str += '_%s' % str(pos) arg_strs = ['%s_%s' % (a, str(pos + (i,))) for i, a in enumerate(arg_strs)] return ['"%s" -> "%s";' % (expr_str, a) for a in arg_strs] template = \ """digraph{ # Graph style %(graphstyle)s ######### # Nodes # ######### %(nodes)s ######### # Edges # ######### %(edges)s }""" _graphstyle = {'rankdir': 'TD', 'ordering': 'out'} def dotprint(expr, styles=default_styles, atom=lambda x: not isinstance(x, Basic), maxdepth=None, repeat=True, labelfunc=str, **kwargs): """DOT description of a SymPy expression tree Parameters ========== styles : list of lists composed of (Class, mapping), optional Styles for different classes. The default is .. code-block:: python ( (Basic, {'color': 'blue', 'shape': 'ellipse'}), (Expr, {'color': 'black'}) ) atom : function, optional Function used to determine if an arg is an atom. A good choice is ``lambda x: not x.args``. The default is ``lambda x: not isinstance(x, Basic)``. maxdepth : integer, optional The maximum depth. The default is ``None``, meaning no limit. repeat : boolean, optional Whether to use different nodes for common subexpressions. The default is ``True``. For example, for ``x + x*y`` with ``repeat=True``, it will have two nodes for ``x``; with ``repeat=False``, it will have one node. .. warning:: Even if a node appears twice in the same object like ``x`` in ``Pow(x, x)``, it will still only appear once. Hence, with ``repeat=False``, the number of arrows out of an object might not equal the number of args it has. labelfunc : function, optional A function to create a label for a given leaf node. The default is ``str``. Another good option is ``srepr``. For example with ``str``, the leaf nodes of ``x + 1`` are labeled, ``x`` and ``1``. With ``srepr``, they are labeled ``Symbol('x')`` and ``Integer(1)``. **kwargs : optional Additional keyword arguments are included as styles for the graph. Examples ======== >>> from sympy.printing.dot import dotprint >>> from sympy.abc import x >>> print(dotprint(x+2)) # doctest: +NORMALIZE_WHITESPACE digraph{ # Graph style "ordering"="out" "rankdir"="TD" ######### # Nodes # ######### "Add(Integer(2), Symbol('x'))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; "Integer(2)_(0,)" ["color"="black", "label"="2", "shape"="ellipse"]; "Symbol('x')_(1,)" ["color"="black", "label"="x", "shape"="ellipse"]; ######### # Edges # ######### "Add(Integer(2), Symbol('x'))_()" -> "Integer(2)_(0,)"; "Add(Integer(2), Symbol('x'))_()" -> "Symbol('x')_(1,)"; } """ # repeat works by adding a signature tuple to the end of each node for its # position in the graph. For example, for expr = Add(x, Pow(x, 2)), the x in the # Pow will have the tuple (1, 0), meaning it is expr.args[1].args[0]. graphstyle = _graphstyle.copy() graphstyle.update(kwargs) nodes = [] edges = [] def traverse(e, depth, pos=()): nodes.append(dotnode(e, styles, labelfunc=labelfunc, pos=pos, repeat=repeat)) if maxdepth and depth >= maxdepth: return edges.extend(dotedges(e, atom=atom, pos=pos, repeat=repeat)) [traverse(arg, depth+1, pos + (i,)) for i, arg in enumerate(e.args) if not atom(arg)] traverse(expr, 0) return template%{'graphstyle': attrprint(graphstyle, delimiter='\n'), 'nodes': '\n'.join(nodes), 'edges': '\n'.join(edges)} sympy-sympy-1.9/sympy/printing/fcode.py000066400000000000000000000007041412543434000203710ustar00rootroot00000000000000""" This is a shim file to provide backwards compatibility (fcode.py was renamed to fortran.py in SymPy 1.7). """ from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="importing from sympy.printing.fcode", useinstead="Import from sympy.printing.fortran", issue=20256, deprecated_since_version="1.7").warn() from .fortran import fcode, print_fcode, known_functions, FCodePrinter # noqa:F401 sympy-sympy-1.9/sympy/printing/fortran.py000066400000000000000000000672211412543434000207730ustar00rootroot00000000000000""" Fortran code printer The FCodePrinter converts single sympy expressions into single Fortran expressions, using the functions defined in the Fortran 77 standard where possible. Some useful pointers to Fortran can be found on wikipedia: https://en.wikipedia.org/wiki/Fortran Most of the code below is based on the "Professional Programmer\'s Guide to Fortran77" by Clive G. Page: http://www.star.le.ac.uk/~cgp/prof77.html Fortran is a case-insensitive language. This might cause trouble because SymPy is case sensitive. So, fcode adds underscores to variable names when it is necessary to make them different for Fortran. """ from typing import Dict, Any from collections import defaultdict from itertools import chain import string from sympy.codegen.ast import ( Assignment, Declaration, Pointer, value_const, float32, float64, float80, complex64, complex128, int8, int16, int32, int64, intc, real, integer, bool_, complex_ ) from sympy.codegen.fnodes import ( allocatable, isign, dsign, cmplx, merge, literal_dp, elemental, pure, intent_in, intent_out, intent_inout ) from sympy.core import S, Add, N, Float, Symbol from sympy.core.function import Function from sympy.core.relational import Eq from sympy.sets import Range from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence, PRECEDENCE from sympy.printing.printer import printer_context # These are defined in the other file so we can avoid importing sympy.codegen # from the top-level 'import sympy'. Export them here as well. from sympy.printing.codeprinter import fcode, print_fcode # noqa:F401 known_functions = { "sin": "sin", "cos": "cos", "tan": "tan", "asin": "asin", "acos": "acos", "atan": "atan", "atan2": "atan2", "sinh": "sinh", "cosh": "cosh", "tanh": "tanh", "log": "log", "exp": "exp", "erf": "erf", "Abs": "abs", "conjugate": "conjg", "Max": "max", "Min": "min", } class FCodePrinter(CodePrinter): """A printer to convert sympy expressions to strings of Fortran code""" printmethod = "_fcode" language = "Fortran" type_aliases = { integer: int32, real: float64, complex_: complex128, } type_mappings = { intc: 'integer(c_int)', float32: 'real*4', # real(kind(0.e0)) float64: 'real*8', # real(kind(0.d0)) float80: 'real*10', # real(kind(????)) complex64: 'complex*8', complex128: 'complex*16', int8: 'integer*1', int16: 'integer*2', int32: 'integer*4', int64: 'integer*8', bool_: 'logical' } type_modules = { intc: {'iso_c_binding': 'c_int'} } _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 17, 'user_functions': {}, 'human': True, 'allow_unknown_functions': False, 'source_format': 'fixed', 'contract': True, 'standard': 77, 'name_mangling' : True, } # type: Dict[str, Any] _operators = { 'and': '.and.', 'or': '.or.', 'xor': '.neqv.', 'equivalent': '.eqv.', 'not': '.not. ', } _relationals = { '!=': '/=', } def __init__(self, settings=None): if not settings: settings = {} self.mangled_symbols = {} # Dict showing mapping of all words self.used_name = [] self.type_aliases = dict(chain(self.type_aliases.items(), settings.pop('type_aliases', {}).items())) self.type_mappings = dict(chain(self.type_mappings.items(), settings.pop('type_mappings', {}).items())) super().__init__(settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) # leading columns depend on fixed or free format standards = {66, 77, 90, 95, 2003, 2008} if self._settings['standard'] not in standards: raise ValueError("Unknown Fortran standard: %s" % self._settings[ 'standard']) self.module_uses = defaultdict(set) # e.g.: use iso_c_binding, only: c_int @property def _lead(self): if self._settings['source_format'] == 'fixed': return {'code': " ", 'cont': " @ ", 'comment': "C "} elif self._settings['source_format'] == 'free': return {'code': "", 'cont': " ", 'comment': "! "} else: raise ValueError("Unknown source format: %s" % self._settings['source_format']) def _print_Symbol(self, expr): if self._settings['name_mangling'] == True: if expr not in self.mangled_symbols: name = expr.name while name.lower() in self.used_name: name += '_' self.used_name.append(name.lower()) if name == expr.name: self.mangled_symbols[expr] = expr else: self.mangled_symbols[expr] = Symbol(name) expr = expr.xreplace(self.mangled_symbols) name = super()._print_Symbol(expr) return name def _rate_index_position(self, p): return -p*5 def _get_statement(self, codestring): return codestring def _get_comment(self, text): return "! {}".format(text) def _declare_number_const(self, name, value): return "parameter ({} = {})".format(name, self._print(value)) def _print_NumberSymbol(self, expr): # A Number symbol that is not implemented here or with _printmethod # is registered and evaluated self._number_symbols.add((expr, Float(expr.evalf(self._settings['precision'])))) return str(expr) def _format_code(self, lines): return self._wrap_fortran(self.indent_code(lines)) def _traverse_matrix_indices(self, mat): rows, cols = mat.shape return ((i, j) for j in range(cols) for i in range(rows)) def _get_loop_opening_ending(self, indices): open_lines = [] close_lines = [] for i in indices: # fortran arrays start at 1 and end at dimension var, start, stop = map(self._print, [i.label, i.lower + 1, i.upper + 1]) open_lines.append("do %s = %s, %s" % (var, start, stop)) close_lines.append("end do") return open_lines, close_lines def _print_sign(self, expr): from sympy import Abs arg, = expr.args if arg.is_integer: new_expr = merge(0, isign(1, arg), Eq(arg, 0)) elif (arg.is_complex or arg.is_infinite): new_expr = merge(cmplx(literal_dp(0), literal_dp(0)), arg/Abs(arg), Eq(Abs(arg), literal_dp(0))) else: new_expr = merge(literal_dp(0), dsign(literal_dp(1), arg), Eq(arg, literal_dp(0))) return self._print(new_expr) def _print_Piecewise(self, expr): if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") lines = [] if expr.has(Assignment): for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) then" % self._print(c)) elif i == len(expr.args) - 1 and c == True: lines.append("else") else: lines.append("else if (%s) then" % self._print(c)) lines.append(self._print(e)) lines.append("end if") return "\n".join(lines) elif self._settings["standard"] >= 95: # Only supported in F95 and newer: # The piecewise was used in an expression, need to do inline # operators. This has the downside that inline operators will # not work for statements that span multiple lines (Matrix or # Indexed expressions). pattern = "merge({T}, {F}, {COND})" code = self._print(expr.args[-1].expr) terms = list(expr.args[:-1]) while terms: e, c = terms.pop() expr = self._print(e) cond = self._print(c) code = pattern.format(T=expr, F=code, COND=cond) return code else: # `merge` is not supported prior to F95 raise NotImplementedError("Using Piecewise as an expression using " "inline operators is not supported in " "standards earlier than Fortran95.") def _print_MatrixElement(self, expr): return "{}({}, {})".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True), expr.i + 1, expr.j + 1) def _print_Add(self, expr): # purpose: print complex numbers nicely in Fortran. # collect the purely real and purely imaginary parts: pure_real = [] pure_imaginary = [] mixed = [] for arg in expr.args: if arg.is_number and arg.is_real: pure_real.append(arg) elif arg.is_number and arg.is_imaginary: pure_imaginary.append(arg) else: mixed.append(arg) if pure_imaginary: if mixed: PREC = precedence(expr) term = Add(*mixed) t = self._print(term) if t.startswith('-'): sign = "-" t = t[1:] else: sign = "+" if precedence(term) < PREC: t = "(%s)" % t return "cmplx(%s,%s) %s %s" % ( self._print(Add(*pure_real)), self._print(-S.ImaginaryUnit*Add(*pure_imaginary)), sign, t, ) else: return "cmplx(%s,%s)" % ( self._print(Add(*pure_real)), self._print(-S.ImaginaryUnit*Add(*pure_imaginary)), ) else: return CodePrinter._print_Add(self, expr) def _print_Function(self, expr): # All constant function args are evaluated as floats prec = self._settings['precision'] args = [N(a, prec) for a in expr.args] eval_expr = expr.func(*args) if not isinstance(eval_expr, Function): return self._print(eval_expr) else: return CodePrinter._print_Function(self, expr.func(*args)) def _print_Mod(self, expr): # NOTE : Fortran has the functions mod() and modulo(). modulo() behaves # the same wrt to the sign of the arguments as Python and SymPy's # modulus computations (% and Mod()) but is not available in Fortran 66 # or Fortran 77, thus we raise an error. if self._settings['standard'] in [66, 77]: msg = ("Python % operator and SymPy's Mod() function are not " "supported by Fortran 66 or 77 standards.") raise NotImplementedError(msg) else: x, y = expr.args return " modulo({}, {})".format(self._print(x), self._print(y)) def _print_ImaginaryUnit(self, expr): # purpose: print complex numbers nicely in Fortran. return "cmplx(0,1)" def _print_int(self, expr): return str(expr) def _print_Mul(self, expr): # purpose: print complex numbers nicely in Fortran. if expr.is_number and expr.is_imaginary: return "cmplx(0,%s)" % ( self._print(-S.ImaginaryUnit*expr) ) else: return CodePrinter._print_Mul(self, expr) def _print_Pow(self, expr): PREC = precedence(expr) if expr.exp == -1: return '%s/%s' % ( self._print(literal_dp(1)), self.parenthesize(expr.base, PREC) ) elif expr.exp == 0.5: if expr.base.is_integer: # Fortran intrinsic sqrt() does not accept integer argument if expr.base.is_Number: return 'sqrt(%s.0d0)' % self._print(expr.base) else: return 'sqrt(dble(%s))' % self._print(expr.base) else: return 'sqrt(%s)' % self._print(expr.base) else: return CodePrinter._print_Pow(self, expr) def _print_Rational(self, expr): p, q = int(expr.p), int(expr.q) return "%d.0d0/%d.0d0" % (p, q) def _print_Float(self, expr): printed = CodePrinter._print_Float(self, expr) e = printed.find('e') if e > -1: return "%sd%s" % (printed[:e], printed[e + 1:]) return "%sd0" % printed def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op op = op if op not in self._relationals else self._relationals[op] return "{} {} {}".format(lhs_code, op, rhs_code) def _print_Indexed(self, expr): inds = [ self._print(i) for i in expr.indices ] return "%s(%s)" % (self._print(expr.base.label), ", ".join(inds)) def _print_Idx(self, expr): return self._print(expr.label) def _print_AugmentedAssignment(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) return self._get_statement("{0} = {0} {1} {2}".format( *map(lambda arg: self._print(arg), [lhs_code, expr.binop, rhs_code]))) def _print_sum_(self, sm): params = self._print(sm.array) if sm.dim != None: # Must use '!= None', cannot use 'is not None' params += ', ' + self._print(sm.dim) if sm.mask != None: # Must use '!= None', cannot use 'is not None' params += ', mask=' + self._print(sm.mask) return '%s(%s)' % (sm.__class__.__name__.rstrip('_'), params) def _print_product_(self, prod): return self._print_sum_(prod) def _print_Do(self, do): excl = ['concurrent'] if do.step == 1: excl.append('step') step = '' else: step = ', {step}' return ( 'do {concurrent}{counter} = {first}, {last}'+step+'\n' '{body}\n' 'end do\n' ).format( concurrent='concurrent ' if do.concurrent else '', **do.kwargs(apply=lambda arg: self._print(arg), exclude=excl) ) def _print_ImpliedDoLoop(self, idl): step = '' if idl.step == 1 else ', {step}' return ('({expr}, {counter} = {first}, {last}'+step+')').format( **idl.kwargs(apply=lambda arg: self._print(arg)) ) def _print_For(self, expr): target = self._print(expr.target) if isinstance(expr.iterable, Range): start, stop, step = expr.iterable.args else: raise NotImplementedError("Only iterable currently supported is Range") body = self._print(expr.body) return ('do {target} = {start}, {stop}, {step}\n' '{body}\n' 'end do').format(target=target, start=start, stop=stop, step=step, body=body) def _print_Type(self, type_): type_ = self.type_aliases.get(type_, type_) type_str = self.type_mappings.get(type_, type_.name) module_uses = self.type_modules.get(type_) if module_uses: for k, v in module_uses: self.module_uses[k].add(v) return type_str def _print_Element(self, elem): return '{symbol}({idxs})'.format( symbol=self._print(elem.symbol), idxs=', '.join(map(lambda arg: self._print(arg), elem.indices)) ) def _print_Extent(self, ext): return str(ext) def _print_Declaration(self, expr): var = expr.variable val = var.value dim = var.attr_params('dimension') intents = [intent in var.attrs for intent in (intent_in, intent_out, intent_inout)] if intents.count(True) == 0: intent = '' elif intents.count(True) == 1: intent = ', intent(%s)' % ['in', 'out', 'inout'][intents.index(True)] else: raise ValueError("Multiple intents specified for %s" % self) if isinstance(var, Pointer): raise NotImplementedError("Pointers are not available by default in Fortran.") if self._settings["standard"] >= 90: result = '{t}{vc}{dim}{intent}{alloc} :: {s}'.format( t=self._print(var.type), vc=', parameter' if value_const in var.attrs else '', dim=', dimension(%s)' % ', '.join(map(lambda arg: self._print(arg), dim)) if dim else '', intent=intent, alloc=', allocatable' if allocatable in var.attrs else '', s=self._print(var.symbol) ) if val != None: # Must be "!= None", cannot be "is not None" result += ' = %s' % self._print(val) else: if value_const in var.attrs or val: raise NotImplementedError("F77 init./parameter statem. req. multiple lines.") result = ' '.join(map(lambda arg: self._print(arg), [var.type, var.symbol])) return result def _print_Infinity(self, expr): return '(huge(%s) + 1)' % self._print(literal_dp(0)) def _print_While(self, expr): return 'do while ({condition})\n{body}\nend do'.format(**expr.kwargs( apply=lambda arg: self._print(arg))) def _print_BooleanTrue(self, expr): return '.true.' def _print_BooleanFalse(self, expr): return '.false.' def _pad_leading_columns(self, lines): result = [] for line in lines: if line.startswith('!'): result.append(self._lead['comment'] + line[1:].lstrip()) else: result.append(self._lead['code'] + line) return result def _wrap_fortran(self, lines): """Wrap long Fortran lines Argument: lines -- a list of lines (without \\n character) A comment line is split at white space. Code lines are split with a more complex rule to give nice results. """ # routine to find split point in a code line my_alnum = set("_+-." + string.digits + string.ascii_letters) my_white = set(" \t()") def split_pos_code(line, endpos): if len(line) <= endpos: return len(line) pos = endpos split = lambda pos: \ (line[pos] in my_alnum and line[pos - 1] not in my_alnum) or \ (line[pos] not in my_alnum and line[pos - 1] in my_alnum) or \ (line[pos] in my_white and line[pos - 1] not in my_white) or \ (line[pos] not in my_white and line[pos - 1] in my_white) while not split(pos): pos -= 1 if pos == 0: return endpos return pos # split line by line and add the split lines to result result = [] if self._settings['source_format'] == 'free': trailing = ' &' else: trailing = '' for line in lines: if line.startswith(self._lead['comment']): # comment line if len(line) > 72: pos = line.rfind(" ", 6, 72) if pos == -1: pos = 72 hunk = line[:pos] line = line[pos:].lstrip() result.append(hunk) while line: pos = line.rfind(" ", 0, 66) if pos == -1 or len(line) < 66: pos = 66 hunk = line[:pos] line = line[pos:].lstrip() result.append("%s%s" % (self._lead['comment'], hunk)) else: result.append(line) elif line.startswith(self._lead['code']): # code line pos = split_pos_code(line, 72) hunk = line[:pos].rstrip() line = line[pos:].lstrip() if line: hunk += trailing result.append(hunk) while line: pos = split_pos_code(line, 65) hunk = line[:pos].rstrip() line = line[pos:].lstrip() if line: hunk += trailing result.append("%s%s" % (self._lead['cont'], hunk)) else: result.append(line) return result def indent_code(self, code): """Accepts a string of code or a list of code lines""" if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) free = self._settings['source_format'] == 'free' code = [ line.lstrip(' \t') for line in code ] inc_keyword = ('do ', 'if(', 'if ', 'do\n', 'else', 'program', 'interface') dec_keyword = ('end do', 'enddo', 'end if', 'endif', 'else', 'end program', 'end interface') increase = [ int(any(map(line.startswith, inc_keyword))) for line in code ] decrease = [ int(any(map(line.startswith, dec_keyword))) for line in code ] continuation = [ int(any(map(line.endswith, ['&', '&\n']))) for line in code ] level = 0 cont_padding = 0 tabwidth = 3 new_code = [] for i, line in enumerate(code): if line == '' or line == '\n': new_code.append(line) continue level -= decrease[i] if free: padding = " "*(level*tabwidth + cont_padding) else: padding = " "*level*tabwidth line = "%s%s" % (padding, line) if not free: line = self._pad_leading_columns([line])[0] new_code.append(line) if continuation[i]: cont_padding = 2*tabwidth else: cont_padding = 0 level += increase[i] if not free: return self._wrap_fortran(new_code) return new_code def _print_GoTo(self, goto): if goto.expr: # computed goto return "go to ({labels}), {expr}".format( labels=', '.join(map(lambda arg: self._print(arg), goto.labels)), expr=self._print(goto.expr) ) else: lbl, = goto.labels return "go to %s" % self._print(lbl) def _print_Program(self, prog): return ( "program {name}\n" "{body}\n" "end program\n" ).format(**prog.kwargs(apply=lambda arg: self._print(arg))) def _print_Module(self, mod): return ( "module {name}\n" "{declarations}\n" "\ncontains\n\n" "{definitions}\n" "end module\n" ).format(**mod.kwargs(apply=lambda arg: self._print(arg))) def _print_Stream(self, strm): if strm.name == 'stdout' and self._settings["standard"] >= 2003: self.module_uses['iso_c_binding'].add('stdint=>input_unit') return 'input_unit' elif strm.name == 'stderr' and self._settings["standard"] >= 2003: self.module_uses['iso_c_binding'].add('stdint=>error_unit') return 'error_unit' else: if strm.name == 'stdout': return '*' else: return strm.name def _print_Print(self, ps): if ps.format_string != None: # Must be '!= None', cannot be 'is not None' fmt = self._print(ps.format_string) else: fmt = "*" return "print {fmt}, {iolist}".format(fmt=fmt, iolist=', '.join( map(lambda arg: self._print(arg), ps.print_args))) def _print_Return(self, rs): arg, = rs.args return "{result_name} = {arg}".format( result_name=self._context.get('result_name', 'sympy_result'), arg=self._print(arg) ) def _print_FortranReturn(self, frs): arg, = frs.args if arg: return 'return %s' % self._print(arg) else: return 'return' def _head(self, entity, fp, **kwargs): bind_C_params = fp.attr_params('bind_C') if bind_C_params is None: bind = '' else: bind = ' bind(C, name="%s")' % bind_C_params[0] if bind_C_params else ' bind(C)' result_name = self._settings.get('result_name', None) return ( "{entity}{name}({arg_names}){result}{bind}\n" "{arg_declarations}" ).format( entity=entity, name=self._print(fp.name), arg_names=', '.join([self._print(arg.symbol) for arg in fp.parameters]), result=(' result(%s)' % result_name) if result_name else '', bind=bind, arg_declarations='\n'.join(map(lambda arg: self._print(Declaration(arg)), fp.parameters)) ) def _print_FunctionPrototype(self, fp): entity = "{} function ".format(self._print(fp.return_type)) return ( "interface\n" "{function_head}\n" "end function\n" "end interface" ).format(function_head=self._head(entity, fp)) def _print_FunctionDefinition(self, fd): if elemental in fd.attrs: prefix = 'elemental ' elif pure in fd.attrs: prefix = 'pure ' else: prefix = '' entity = "{} function ".format(self._print(fd.return_type)) with printer_context(self, result_name=fd.name): return ( "{prefix}{function_head}\n" "{body}\n" "end function\n" ).format( prefix=prefix, function_head=self._head(entity, fd), body=self._print(fd.body) ) def _print_Subroutine(self, sub): return ( '{subroutine_head}\n' '{body}\n' 'end subroutine\n' ).format( subroutine_head=self._head('subroutine ', sub), body=self._print(sub.body) ) def _print_SubroutineCall(self, scall): return 'call {name}({args})'.format( name=self._print(scall.name), args=', '.join(map(lambda arg: self._print(arg), scall.subroutine_args)) ) def _print_use_rename(self, rnm): return "%s => %s" % tuple(map(lambda arg: self._print(arg), rnm.args)) def _print_use(self, use): result = 'use %s' % self._print(use.namespace) if use.rename != None: # Must be '!= None', cannot be 'is not None' result += ', ' + ', '.join([self._print(rnm) for rnm in use.rename]) if use.only != None: # Must be '!= None', cannot be 'is not None' result += ', only: ' + ', '.join([self._print(nly) for nly in use.only]) return result def _print_BreakToken(self, _): return 'exit' def _print_ContinueToken(self, _): return 'cycle' def _print_ArrayConstructor(self, ac): fmtstr = "[%s]" if self._settings["standard"] >= 2003 else '(/%s/)' return fmtstr % ', '.join(map(lambda arg: self._print(arg), ac.elements)) sympy-sympy-1.9/sympy/printing/glsl.py000066400000000000000000000500161412543434000202530ustar00rootroot00000000000000from typing import Set from sympy.core import Basic, S from sympy.core.function import _coeff_isneg, Lambda from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence from functools import reduce known_functions = { 'Abs': 'abs', 'sin': 'sin', 'cos': 'cos', 'tan': 'tan', 'acos': 'acos', 'asin': 'asin', 'atan': 'atan', 'atan2': 'atan', 'ceiling': 'ceil', 'floor': 'floor', 'sign': 'sign', 'exp': 'exp', 'log': 'log', 'add': 'add', 'sub': 'sub', 'mul': 'mul', 'pow': 'pow' } class GLSLPrinter(CodePrinter): """ Rudimentary, generic GLSL printing tools. Additional settings: 'use_operators': Boolean (should the printer use operators for +,-,*, or functions?) """ _not_supported = set() # type: Set[Basic] printmethod = "_glsl" language = "GLSL" _default_settings = { 'use_operators': True, 'zero': 0, 'mat_nested': False, 'mat_separator': ',\n', 'mat_transpose': False, 'array_type': 'float', 'glsl_types': True, 'order': None, 'full_prec': 'auto', 'precision': 9, 'user_functions': {}, 'human': True, 'allow_unknown_functions': False, 'contract': True, 'error_on_reserved': False, 'reserved_word_suffix': '_', } def __init__(self, settings={}): CodePrinter.__init__(self, settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) def _rate_index_position(self, p): return p*5 def _get_statement(self, codestring): return "%s;" % codestring def _get_comment(self, text): return "// {}".format(text) def _declare_number_const(self, name, value): return "float {} = {};".format(name, value) def _format_code(self, lines): return self.indent_code(lines) def indent_code(self, code): """Accepts a string of code or a list of code lines""" if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) tab = " " inc_token = ('{', '(', '{\n', '(\n') dec_token = ('}', ')') code = [line.lstrip(' \t') for line in code] increase = [int(any(map(line.endswith, inc_token))) for line in code] decrease = [int(any(map(line.startswith, dec_token))) for line in code] pretty = [] level = 0 for n, line in enumerate(code): if line == '' or line == '\n': pretty.append(line) continue level -= decrease[n] pretty.append("%s%s" % (tab*level, line)) level += increase[n] return pretty def _print_MatrixBase(self, mat): mat_separator = self._settings['mat_separator'] mat_transpose = self._settings['mat_transpose'] column_vector = (mat.rows == 1) if mat_transpose else (mat.cols == 1) A = mat.transpose() if mat_transpose != column_vector else mat glsl_types = self._settings['glsl_types'] array_type = self._settings['array_type'] array_size = A.cols*A.rows array_constructor = "{}[{}]".format(array_type, array_size) if A.cols == 1: return self._print(A[0]); if A.rows <= 4 and A.cols <= 4 and glsl_types: if A.rows == 1: return "vec{}{}".format( A.cols, A.table(self,rowstart='(',rowend=')') ) elif A.rows == A.cols: return "mat{}({})".format( A.rows, A.table(self,rowsep=', ', rowstart='',rowend='') ) else: return "mat{}x{}({})".format( A.cols, A.rows, A.table(self,rowsep=', ', rowstart='',rowend='') ) elif A.cols == 1 or A.rows == 1: return "{}({})".format( array_constructor, A.table(self,rowsep=mat_separator,rowstart='',rowend='') ) elif not self._settings['mat_nested']: return "{}(\n{}\n) /* a {}x{} matrix */".format( array_constructor, A.table(self,rowsep=mat_separator,rowstart='',rowend=''), A.rows, A.cols ) elif self._settings['mat_nested']: return "{}[{}][{}](\n{}\n)".format( array_type, A.rows, A.cols, A.table(self,rowsep=mat_separator,rowstart='float[](',rowend=')') ) def _print_SparseMatrix(self, mat): # do not allow sparse matrices to be made dense return self._print_not_supported(mat) def _traverse_matrix_indices(self, mat): mat_transpose = self._settings['mat_transpose'] if mat_transpose: rows,cols = mat.shape else: cols,rows = mat.shape return ((i, j) for i in range(cols) for j in range(rows)) def _print_MatrixElement(self, expr): # print('begin _print_MatrixElement') nest = self._settings['mat_nested']; glsl_types = self._settings['glsl_types']; mat_transpose = self._settings['mat_transpose']; if mat_transpose: cols,rows = expr.parent.shape i,j = expr.j,expr.i else: rows,cols = expr.parent.shape i,j = expr.i,expr.j pnt = self._print(expr.parent) if glsl_types and ((rows <= 4 and cols <=4) or nest): return "{}[{}][{}]".format(pnt, i, j) else: return "{}[{}]".format(pnt, i + j*rows) def _print_list(self, expr): l = ', '.join(self._print(item) for item in expr) glsl_types = self._settings['glsl_types'] array_type = self._settings['array_type'] array_size = len(expr) array_constructor = '{}[{}]'.format(array_type, array_size) if array_size <= 4 and glsl_types: return 'vec{}({})'.format(array_size, l) else: return '{}({})'.format(array_constructor, l) _print_tuple = _print_list _print_Tuple = _print_list def _get_loop_opening_ending(self, indices): open_lines = [] close_lines = [] loopstart = "for (int %(varble)s=%(start)s; %(varble)s<%(end)s; %(varble)s++){" for i in indices: # GLSL arrays start at 0 and end at dimension-1 open_lines.append(loopstart % { 'varble': self._print(i.label), 'start': self._print(i.lower), 'end': self._print(i.upper + 1)}) close_lines.append("}") return open_lines, close_lines def _print_Function_with_args(self, func, func_args): if func in self.known_functions: cond_func = self.known_functions[func] func = None if isinstance(cond_func, str): func = cond_func else: for cond, func in cond_func: if cond(func_args): break if func is not None: try: return func(*[self.parenthesize(item, 0) for item in func_args]) except TypeError: return '{}({})'.format(func, self.stringify(func_args, ", ")) elif isinstance(func, Lambda): # inlined function return self._print(func(*func_args)) else: return self._print_not_supported(func) def _print_Piecewise(self, expr): from sympy.codegen.ast import Assignment if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") lines = [] if expr.has(Assignment): for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) {" % self._print(c)) elif i == len(expr.args) - 1 and c == True: lines.append("else {") else: lines.append("else if (%s) {" % self._print(c)) code0 = self._print(e) lines.append(code0) lines.append("}") return "\n".join(lines) else: # The piecewise was used in an expression, need to do inline # operators. This has the downside that inline operators will # not work for statements that span multiple lines (Matrix or # Indexed expressions). ecpairs = ["((%s) ? (\n%s\n)\n" % (self._print(c), self._print(e)) for e, c in expr.args[:-1]] last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr) return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)]) def _print_Idx(self, expr): return self._print(expr.label) def _print_Indexed(self, expr): # calculate index for 1d array dims = expr.shape elem = S.Zero offset = S.One for i in reversed(range(expr.rank)): elem += expr.indices[i]*offset offset *= dims[i] return "{}[{}]".format( self._print(expr.base.label), self._print(elem) ) def _print_Pow(self, expr): PREC = precedence(expr) if expr.exp == -1: return '1.0/%s' % (self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5: return 'sqrt(%s)' % self._print(expr.base) else: try: e = self._print(float(expr.exp)) except TypeError: e = self._print(expr.exp) return self._print_Function_with_args('pow', ( self._print(expr.base), e )) def _print_int(self, expr): return str(float(expr)) def _print_Rational(self, expr): return "{}.0/{}.0".format(expr.p, expr.q) def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) def _print_Add(self, expr, order=None): if self._settings['use_operators']: return CodePrinter._print_Add(self, expr, order=order) terms = expr.as_ordered_terms() def partition(p,l): return reduce(lambda x, y: (x[0]+[y], x[1]) if p(y) else (x[0], x[1]+[y]), l, ([], [])) def add(a,b): return self._print_Function_with_args('add', (a, b)) # return self.known_functions['add']+'(%s, %s)' % (a,b) neg, pos = partition(lambda arg: _coeff_isneg(arg), terms) if pos: s = pos = reduce(lambda a,b: add(a,b), map(lambda t: self._print(t),pos)) else: s = pos = self._print(self._settings['zero']) if neg: # sum the absolute values of the negative terms neg = reduce(lambda a,b: add(a,b), map(lambda n: self._print(-n),neg)) # then subtract them from the positive terms s = self._print_Function_with_args('sub', (pos,neg)) # s = self.known_functions['sub']+'(%s, %s)' % (pos,neg) return s def _print_Mul(self, expr, **kwargs): if self._settings['use_operators']: return CodePrinter._print_Mul(self, expr, **kwargs) terms = expr.as_ordered_factors() def mul(a,b): # return self.known_functions['mul']+'(%s, %s)' % (a,b) return self._print_Function_with_args('mul', (a,b)) s = reduce(lambda a,b: mul(a,b), map(lambda t: self._print(t), terms)) return s def glsl_code(expr,assign_to=None,**settings): """Converts an expr to a string of GLSL code Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used for naming the variable or variables to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol`` or ``Indexed`` type object. In cases where ``expr`` would be printed as an array, a list of string or ``Symbol`` objects can also be passed. This is helpful in case of line-wrapping, or for expressions that generate multi-line statements. It can also be used to spread an array-like expression into multiple assignments. use_operators: bool, optional If set to False, then *,/,+,- operators will be replaced with functions mul, add, and sub, which must be implemented by the user, e.g. for implementing non-standard rings or emulated quad/octal precision. [default=True] glsl_types: bool, optional Set this argument to ``False`` in order to avoid using the ``vec`` and ``mat`` types. The printer will instead use arrays (or nested arrays). [default=True] mat_nested: bool, optional GLSL version 4.3 and above support nested arrays (arrays of arrays). Set this to ``True`` to render matrices as nested arrays. [default=False] mat_separator: str, optional By default, matrices are rendered with newlines using this separator, making them easier to read, but less compact. By removing the newline this option can be used to make them more vertically compact. [default=',\n'] mat_transpose: bool, optional GLSL's matrix multiplication implementation assumes column-major indexing. By default, this printer ignores that convention. Setting this option to ``True`` transposes all matrix output. [default=False] array_type: str, optional The GLSL array constructor type. [default='float'] precision : integer, optional The precision for numbers such as pi [default=15]. user_functions : dict, optional A dictionary where keys are ``FunctionClass`` instances and values are their string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, js_function_string)]. See below for examples. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. Examples ======== >>> from sympy import glsl_code, symbols, Rational, sin, ceiling, Abs >>> x, tau = symbols("x, tau") >>> glsl_code((2*tau)**Rational(7, 2)) '8*sqrt(2)*pow(tau, 3.5)' >>> glsl_code(sin(x), assign_to="float y") 'float y = sin(x);' Various GLSL types are supported: >>> from sympy import Matrix, glsl_code >>> glsl_code(Matrix([1,2,3])) 'vec3(1, 2, 3)' >>> glsl_code(Matrix([[1, 2],[3, 4]])) 'mat2(1, 2, 3, 4)' Pass ``mat_transpose = True`` to switch to column-major indexing: >>> glsl_code(Matrix([[1, 2],[3, 4]]), mat_transpose = True) 'mat2(1, 3, 2, 4)' By default, larger matrices get collapsed into float arrays: >>> print(glsl_code( Matrix([[1,2,3,4,5],[6,7,8,9,10]]) )) float[10]( 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ) /* a 2x5 matrix */ The type of array constructor used to print GLSL arrays can be controlled via the ``array_type`` parameter: >>> glsl_code(Matrix([1,2,3,4,5]), array_type='int') 'int[5](1, 2, 3, 4, 5)' Passing a list of strings or ``symbols`` to the ``assign_to`` parameter will yield a multi-line assignment for each item in an array-like expression: >>> x_struct_members = symbols('x.a x.b x.c x.d') >>> print(glsl_code(Matrix([1,2,3,4]), assign_to=x_struct_members)) x.a = 1; x.b = 2; x.c = 3; x.d = 4; This could be useful in cases where it's desirable to modify members of a GLSL ``Struct``. It could also be used to spread items from an array-like expression into various miscellaneous assignments: >>> misc_assignments = ('x[0]', 'x[1]', 'float y', 'float z') >>> print(glsl_code(Matrix([1,2,3,4]), assign_to=misc_assignments)) x[0] = 1; x[1] = 2; float y = 3; float z = 4; Passing ``mat_nested = True`` instead prints out nested float arrays, which are supported in GLSL 4.3 and above. >>> mat = Matrix([ ... [ 0, 1, 2], ... [ 3, 4, 5], ... [ 6, 7, 8], ... [ 9, 10, 11], ... [12, 13, 14]]) >>> print(glsl_code( mat, mat_nested = True )) float[5][3]( float[]( 0, 1, 2), float[]( 3, 4, 5), float[]( 6, 7, 8), float[]( 9, 10, 11), float[](12, 13, 14) ) Custom printing can be defined for certain types by passing a dictionary of "type" : "function" to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, js_function_string)]. >>> custom_functions = { ... "ceiling": "CEIL", ... "Abs": [(lambda x: not x.is_integer, "fabs"), ... (lambda x: x.is_integer, "ABS")] ... } >>> glsl_code(Abs(x) + ceiling(x), user_functions=custom_functions) 'fabs(x) + CEIL(x)' If further control is needed, addition, subtraction, multiplication and division operators can be replaced with ``add``, ``sub``, and ``mul`` functions. This is done by passing ``use_operators = False``: >>> x,y,z = symbols('x,y,z') >>> glsl_code(x*(y+z), use_operators = False) 'mul(x, add(y, z))' >>> glsl_code(x*(y+z*(x-y)**z), use_operators = False) 'mul(x, add(y, mul(z, pow(sub(x, y), z))))' ``Piecewise`` expressions are converted into conditionals. If an ``assign_to`` variable is provided an if statement is created, otherwise the ternary operator is used. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> expr = Piecewise((x + 1, x > 0), (x, True)) >>> print(glsl_code(expr, tau)) if (x > 0) { tau = x + 1; } else { tau = x; } Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> glsl_code(e.rhs, assign_to=e.lhs, contract=False) 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) >>> A = MatrixSymbol('A', 3, 1) >>> print(glsl_code(mat, A)) A[0][0] = pow(x, 2.0); if (x > 0) { A[1][0] = x + 1; } else { A[1][0] = x; } A[2][0] = sin(x); """ return GLSLPrinter(settings).doprint(expr,assign_to) def print_glsl(expr, **settings): """Prints the GLSL representation of the given expression. See GLSLPrinter init function for settings. """ print(glsl_code(expr, **settings)) sympy-sympy-1.9/sympy/printing/gtk.py000066400000000000000000000007221412543434000200760ustar00rootroot00000000000000from sympy.printing.mathml import mathml from sympy.utilities.mathml import c2p import tempfile import subprocess def print_gtk(x, start_viewer=True): """Print to Gtkmathview, a gtk widget capable of rendering MathML. Needs libgtkmathview-bin""" with tempfile.NamedTemporaryFile('w') as file: file.write(c2p(mathml(x), simple=True)) file.flush() if start_viewer: subprocess.check_call(('mathmlviewer', file.name)) sympy-sympy-1.9/sympy/printing/jscode.py000066400000000000000000000263461412543434000205720ustar00rootroot00000000000000""" Javascript code printer The JavascriptCodePrinter converts single sympy expressions into single Javascript expressions, using the functions defined in the Javascript Math object where possible. """ from typing import Any, Dict from sympy.core import S from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence, PRECEDENCE # dictionary mapping sympy function to (argument_conditions, Javascript_function). # Used in JavascriptCodePrinter._print_Function(self) known_functions = { 'Abs': 'Math.abs', 'acos': 'Math.acos', 'acosh': 'Math.acosh', 'asin': 'Math.asin', 'asinh': 'Math.asinh', 'atan': 'Math.atan', 'atan2': 'Math.atan2', 'atanh': 'Math.atanh', 'ceiling': 'Math.ceil', 'cos': 'Math.cos', 'cosh': 'Math.cosh', 'exp': 'Math.exp', 'floor': 'Math.floor', 'log': 'Math.log', 'Max': 'Math.max', 'Min': 'Math.min', 'sign': 'Math.sign', 'sin': 'Math.sin', 'sinh': 'Math.sinh', 'tan': 'Math.tan', 'tanh': 'Math.tanh', } class JavascriptCodePrinter(CodePrinter): """"A Printer to convert python expressions to strings of javascript code """ printmethod = '_javascript' language = 'Javascript' _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 17, 'user_functions': {}, 'human': True, 'allow_unknown_functions': False, 'contract': True, } # type: Dict[str, Any] def __init__(self, settings={}): CodePrinter.__init__(self, settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) def _rate_index_position(self, p): return p*5 def _get_statement(self, codestring): return "%s;" % codestring def _get_comment(self, text): return "// {}".format(text) def _declare_number_const(self, name, value): return "var {} = {};".format(name, value.evalf(self._settings['precision'])) def _format_code(self, lines): return self.indent_code(lines) def _traverse_matrix_indices(self, mat): rows, cols = mat.shape return ((i, j) for i in range(rows) for j in range(cols)) def _get_loop_opening_ending(self, indices): open_lines = [] close_lines = [] loopstart = "for (var %(varble)s=%(start)s; %(varble)s<%(end)s; %(varble)s++){" for i in indices: # Javascript arrays start at 0 and end at dimension-1 open_lines.append(loopstart % { 'varble': self._print(i.label), 'start': self._print(i.lower), 'end': self._print(i.upper + 1)}) close_lines.append("}") return open_lines, close_lines def _print_Pow(self, expr): PREC = precedence(expr) if expr.exp == -1: return '1/%s' % (self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5: return 'Math.sqrt(%s)' % self._print(expr.base) elif expr.exp == S.One/3: return 'Math.cbrt(%s)' % self._print(expr.base) else: return 'Math.pow(%s, %s)' % (self._print(expr.base), self._print(expr.exp)) def _print_Rational(self, expr): p, q = int(expr.p), int(expr.q) return '%d/%d' % (p, q) def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) def _print_Indexed(self, expr): # calculate index for 1d array dims = expr.shape elem = S.Zero offset = S.One for i in reversed(range(expr.rank)): elem += expr.indices[i]*offset offset *= dims[i] return "%s[%s]" % (self._print(expr.base.label), self._print(elem)) def _print_Idx(self, expr): return self._print(expr.label) def _print_Exp1(self, expr): return "Math.E" def _print_Pi(self, expr): return 'Math.PI' def _print_Infinity(self, expr): return 'Number.POSITIVE_INFINITY' def _print_NegativeInfinity(self, expr): return 'Number.NEGATIVE_INFINITY' def _print_Piecewise(self, expr): from sympy.codegen.ast import Assignment if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") lines = [] if expr.has(Assignment): for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) {" % self._print(c)) elif i == len(expr.args) - 1 and c == True: lines.append("else {") else: lines.append("else if (%s) {" % self._print(c)) code0 = self._print(e) lines.append(code0) lines.append("}") return "\n".join(lines) else: # The piecewise was used in an expression, need to do inline # operators. This has the downside that inline operators will # not work for statements that span multiple lines (Matrix or # Indexed expressions). ecpairs = ["((%s) ? (\n%s\n)\n" % (self._print(c), self._print(e)) for e, c in expr.args[:-1]] last_line = ": (\n%s\n)" % self._print(expr.args[-1].expr) return ": ".join(ecpairs) + last_line + " ".join([")"*len(ecpairs)]) def _print_MatrixElement(self, expr): return "{}[{}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True), expr.j + expr.i*expr.parent.shape[1]) def indent_code(self, code): """Accepts a string of code or a list of code lines""" if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) tab = " " inc_token = ('{', '(', '{\n', '(\n') dec_token = ('}', ')') code = [ line.lstrip(' \t') for line in code ] increase = [ int(any(map(line.endswith, inc_token))) for line in code ] decrease = [ int(any(map(line.startswith, dec_token))) for line in code ] pretty = [] level = 0 for n, line in enumerate(code): if line == '' or line == '\n': pretty.append(line) continue level -= decrease[n] pretty.append("%s%s" % (tab*level, line)) level += increase[n] return pretty def jscode(expr, assign_to=None, **settings): """Converts an expr to a string of javascript code Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of line-wrapping, or for expressions that generate multi-line statements. precision : integer, optional The precision for numbers such as pi [default=15]. user_functions : dict, optional A dictionary where keys are ``FunctionClass`` instances and values are their string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, js_function_string)]. See below for examples. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. Examples ======== >>> from sympy import jscode, symbols, Rational, sin, ceiling, Abs >>> x, tau = symbols("x, tau") >>> jscode((2*tau)**Rational(7, 2)) '8*Math.sqrt(2)*Math.pow(tau, 7/2)' >>> jscode(sin(x), assign_to="s") 's = Math.sin(x);' Custom printing can be defined for certain types by passing a dictionary of "type" : "function" to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, js_function_string)]. >>> custom_functions = { ... "ceiling": "CEIL", ... "Abs": [(lambda x: not x.is_integer, "fabs"), ... (lambda x: x.is_integer, "ABS")] ... } >>> jscode(Abs(x) + ceiling(x), user_functions=custom_functions) 'fabs(x) + CEIL(x)' ``Piecewise`` expressions are converted into conditionals. If an ``assign_to`` variable is provided an if statement is created, otherwise the ternary operator is used. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> expr = Piecewise((x + 1, x > 0), (x, True)) >>> print(jscode(expr, tau)) if (x > 0) { tau = x + 1; } else { tau = x; } Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> jscode(e.rhs, assign_to=e.lhs, contract=False) 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions must be provided to ``assign_to``. Note that any expression that can be generated normally can also exist inside a Matrix: >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) >>> A = MatrixSymbol('A', 3, 1) >>> print(jscode(mat, A)) A[0] = Math.pow(x, 2); if (x > 0) { A[1] = x + 1; } else { A[1] = x; } A[2] = Math.sin(x); """ return JavascriptCodePrinter(settings).doprint(expr, assign_to) def print_jscode(expr, **settings): """Prints the Javascript representation of the given expression. See jscode for the meaning of the optional arguments. """ print(jscode(expr, **settings)) sympy-sympy-1.9/sympy/printing/julia.py000066400000000000000000000541661412543434000204300ustar00rootroot00000000000000""" Julia code printer The `JuliaCodePrinter` converts SymPy expressions into Julia expressions. A complete code generator, which uses `julia_code` extensively, can be found in `sympy.utilities.codegen`. The `codegen` module can be used to generate complete source code files. """ from typing import Any, Dict from sympy.core import Mul, Pow, S, Rational from sympy.core.mul import _keep_coeff from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence, PRECEDENCE from re import search # List of known functions. First, those that have the same name in # SymPy and Julia. This is almost certainly incomplete! known_fcns_src1 = ["sin", "cos", "tan", "cot", "sec", "csc", "asin", "acos", "atan", "acot", "asec", "acsc", "sinh", "cosh", "tanh", "coth", "sech", "csch", "asinh", "acosh", "atanh", "acoth", "asech", "acsch", "sinc", "atan2", "sign", "floor", "log", "exp", "cbrt", "sqrt", "erf", "erfc", "erfi", "factorial", "gamma", "digamma", "trigamma", "polygamma", "beta", "airyai", "airyaiprime", "airybi", "airybiprime", "besselj", "bessely", "besseli", "besselk", "erfinv", "erfcinv"] # These functions have different names ("Sympy": "Julia"), more # generally a mapping to (argument_conditions, julia_function). known_fcns_src2 = { "Abs": "abs", "ceiling": "ceil", "conjugate": "conj", "hankel1": "hankelh1", "hankel2": "hankelh2", "im": "imag", "re": "real" } class JuliaCodePrinter(CodePrinter): """ A printer to convert expressions to strings of Julia code. """ printmethod = "_julia" language = "Julia" _operators = { 'and': '&&', 'or': '||', 'not': '!', } _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 17, 'user_functions': {}, 'human': True, 'allow_unknown_functions': False, 'contract': True, 'inline': True, } # type: Dict[str, Any] # Note: contract is for expressing tensors as loops (if True), or just # assignment (if False). FIXME: this should be looked a more carefully # for Julia. def __init__(self, settings={}): super().__init__(settings) self.known_functions = dict(zip(known_fcns_src1, known_fcns_src1)) self.known_functions.update(dict(known_fcns_src2)) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) def _rate_index_position(self, p): return p*5 def _get_statement(self, codestring): return "%s" % codestring def _get_comment(self, text): return "# {}".format(text) def _declare_number_const(self, name, value): return "const {} = {}".format(name, value) def _format_code(self, lines): return self.indent_code(lines) def _traverse_matrix_indices(self, mat): # Julia uses Fortran order (column-major) rows, cols = mat.shape return ((i, j) for j in range(cols) for i in range(rows)) def _get_loop_opening_ending(self, indices): open_lines = [] close_lines = [] for i in indices: # Julia arrays start at 1 and end at dimension var, start, stop = map(self._print, [i.label, i.lower + 1, i.upper + 1]) open_lines.append("for %s = %s:%s" % (var, start, stop)) close_lines.append("end") return open_lines, close_lines def _print_Mul(self, expr): # print complex numbers nicely in Julia if (expr.is_number and expr.is_imaginary and expr.as_coeff_Mul()[0].is_integer): return "%sim" % self._print(-S.ImaginaryUnit*expr) # cribbed from str.py prec = precedence(expr) c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if (item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative): if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160 pow_paren.append(item) b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec) for x in a] b_str = [self.parenthesize(x, prec) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] # from here it differs from str.py to deal with "*" and ".*" def multjoin(a, a_str): # here we probably are assuming the constants will come first r = a_str[0] for i in range(1, len(a)): mulsym = '*' if a[i-1].is_number else '.*' r = r + mulsym + a_str[i] return r if not b: return sign + multjoin(a, a_str) elif len(b) == 1: divsym = '/' if b[0].is_number else './' return sign + multjoin(a, a_str) + divsym + b_str[0] else: divsym = '/' if all([bi.is_number for bi in b]) else './' return (sign + multjoin(a, a_str) + divsym + "(%s)" % multjoin(b, b_str)) def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) def _print_Pow(self, expr): powsymbol = '^' if all([x.is_number for x in expr.args]) else '.^' PREC = precedence(expr) if expr.exp == S.Half: return "sqrt(%s)" % self._print(expr.base) if expr.is_commutative: if expr.exp == -S.Half: sym = '/' if expr.base.is_number else './' return "1" + sym + "sqrt(%s)" % self._print(expr.base) if expr.exp == -S.One: sym = '/' if expr.base.is_number else './' return "1" + sym + "%s" % self.parenthesize(expr.base, PREC) return '%s%s%s' % (self.parenthesize(expr.base, PREC), powsymbol, self.parenthesize(expr.exp, PREC)) def _print_MatPow(self, expr): PREC = precedence(expr) return '%s^%s' % (self.parenthesize(expr.base, PREC), self.parenthesize(expr.exp, PREC)) def _print_Pi(self, expr): if self._settings["inline"]: return "pi" else: return super()._print_NumberSymbol(expr) def _print_ImaginaryUnit(self, expr): return "im" def _print_Exp1(self, expr): if self._settings["inline"]: return "e" else: return super()._print_NumberSymbol(expr) def _print_EulerGamma(self, expr): if self._settings["inline"]: return "eulergamma" else: return super()._print_NumberSymbol(expr) def _print_Catalan(self, expr): if self._settings["inline"]: return "catalan" else: return super()._print_NumberSymbol(expr) def _print_GoldenRatio(self, expr): if self._settings["inline"]: return "golden" else: return super()._print_NumberSymbol(expr) def _print_Assignment(self, expr): from sympy.codegen.ast import Assignment from sympy.functions.elementary.piecewise import Piecewise from sympy.tensor.indexed import IndexedBase # Copied from codeprinter, but remove special MatrixSymbol treatment lhs = expr.lhs rhs = expr.rhs # We special case assignments that take multiple lines if not self._settings["inline"] and isinstance(expr.rhs, Piecewise): # Here we modify Piecewise so each expression is now # an Assignment, and then continue on the print. expressions = [] conditions = [] for (e, c) in rhs.args: expressions.append(Assignment(lhs, e)) conditions.append(c) temp = Piecewise(*zip(expressions, conditions)) return self._print(temp) if self._settings["contract"] and (lhs.has(IndexedBase) or rhs.has(IndexedBase)): # Here we check if there is looping to be done, and if so # print the required loops. return self._doprint_loops(rhs, lhs) else: lhs_code = self._print(lhs) rhs_code = self._print(rhs) return self._get_statement("%s = %s" % (lhs_code, rhs_code)) def _print_Infinity(self, expr): return 'Inf' def _print_NegativeInfinity(self, expr): return '-Inf' def _print_NaN(self, expr): return 'NaN' def _print_list(self, expr): return 'Any[' + ', '.join(self._print(a) for a in expr) + ']' def _print_tuple(self, expr): if len(expr) == 1: return "(%s,)" % self._print(expr[0]) else: return "(%s)" % self.stringify(expr, ", ") _print_Tuple = _print_tuple def _print_BooleanTrue(self, expr): return "true" def _print_BooleanFalse(self, expr): return "false" def _print_bool(self, expr): return str(expr).lower() # Could generate quadrature code for definite Integrals? #_print_Integral = _print_not_supported def _print_MatrixBase(self, A): # Handle zero dimensions: if A.rows == 0 or A.cols == 0: return 'zeros(%s, %s)' % (A.rows, A.cols) elif (A.rows, A.cols) == (1, 1): return "[%s]" % A[0, 0] elif A.rows == 1: return "[%s]" % A.table(self, rowstart='', rowend='', colsep=' ') elif A.cols == 1: # note .table would unnecessarily equispace the rows return "[%s]" % ", ".join([self._print(a) for a in A]) return "[%s]" % A.table(self, rowstart='', rowend='', rowsep=';\n', colsep=' ') def _print_SparseMatrix(self, A): from sympy.matrices import Matrix L = A.col_list(); # make row vectors of the indices and entries I = Matrix([k[0] + 1 for k in L]) J = Matrix([k[1] + 1 for k in L]) AIJ = Matrix([k[2] for k in L]) return "sparse(%s, %s, %s, %s, %s)" % (self._print(I), self._print(J), self._print(AIJ), A.rows, A.cols) def _print_MatrixElement(self, expr): return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \ + '[%s,%s]' % (expr.i + 1, expr.j + 1) def _print_MatrixSlice(self, expr): def strslice(x, lim): l = x[0] + 1 h = x[1] step = x[2] lstr = self._print(l) hstr = 'end' if h == lim else self._print(h) if step == 1: if l == 1 and h == lim: return ':' if l == h: return lstr else: return lstr + ':' + hstr else: return ':'.join((lstr, self._print(step), hstr)) return (self._print(expr.parent) + '[' + strslice(expr.rowslice, expr.parent.shape[0]) + ',' + strslice(expr.colslice, expr.parent.shape[1]) + ']') def _print_Indexed(self, expr): inds = [ self._print(i) for i in expr.indices ] return "%s[%s]" % (self._print(expr.base.label), ",".join(inds)) def _print_Idx(self, expr): return self._print(expr.label) def _print_Identity(self, expr): return "eye(%s)" % self._print(expr.shape[0]) def _print_HadamardProduct(self, expr): return '.*'.join([self.parenthesize(arg, precedence(expr)) for arg in expr.args]) def _print_HadamardPower(self, expr): PREC = precedence(expr) return '.**'.join([ self.parenthesize(expr.base, PREC), self.parenthesize(expr.exp, PREC) ]) # Note: as of 2015, Julia doesn't have spherical Bessel functions def _print_jn(self, expr): from sympy.functions import sqrt, besselj x = expr.argument expr2 = sqrt(S.Pi/(2*x))*besselj(expr.order + S.Half, x) return self._print(expr2) def _print_yn(self, expr): from sympy.functions import sqrt, bessely x = expr.argument expr2 = sqrt(S.Pi/(2*x))*bessely(expr.order + S.Half, x) return self._print(expr2) def _print_Piecewise(self, expr): if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") lines = [] if self._settings["inline"]: # Express each (cond, expr) pair in a nested Horner form: # (condition) .* (expr) + (not cond) .* () # Expressions that result in multiple statements won't work here. ecpairs = ["({}) ? ({}) :".format (self._print(c), self._print(e)) for e, c in expr.args[:-1]] elast = " (%s)" % self._print(expr.args[-1].expr) pw = "\n".join(ecpairs) + elast # Note: current need these outer brackets for 2*pw. Would be # nicer to teach parenthesize() to do this for us when needed! return "(" + pw + ")" else: for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s)" % self._print(c)) elif i == len(expr.args) - 1 and c == True: lines.append("else") else: lines.append("elseif (%s)" % self._print(c)) code0 = self._print(e) lines.append(code0) if i == len(expr.args) - 1: lines.append("end") return "\n".join(lines) def indent_code(self, code): """Accepts a string of code or a list of code lines""" # code mostly copied from ccode if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) tab = " " inc_regex = ('^function ', '^if ', '^elseif ', '^else$', '^for ') dec_regex = ('^end$', '^elseif ', '^else$') # pre-strip left-space from the code code = [ line.lstrip(' \t') for line in code ] increase = [ int(any([search(re, line) for re in inc_regex])) for line in code ] decrease = [ int(any([search(re, line) for re in dec_regex])) for line in code ] pretty = [] level = 0 for n, line in enumerate(code): if line == '' or line == '\n': pretty.append(line) continue level -= decrease[n] pretty.append("%s%s" % (tab*level, line)) level += increase[n] return pretty def julia_code(expr, assign_to=None, **settings): r"""Converts `expr` to a string of Julia code. Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for expressions that generate multi-line statements. precision : integer, optional The precision for numbers such as pi [default=16]. user_functions : dict, optional A dictionary where keys are ``FunctionClass`` instances and values are their string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. See below for examples. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. inline: bool, optional If True, we try to create single-statement code instead of multiple statements. [default=True]. Examples ======== >>> from sympy import julia_code, symbols, sin, pi >>> x = symbols('x') >>> julia_code(sin(x).series(x).removeO()) 'x.^5/120 - x.^3/6 + x' >>> from sympy import Rational, ceiling >>> x, y, tau = symbols("x, y, tau") >>> julia_code((2*tau)**Rational(7, 2)) '8*sqrt(2)*tau.^(7/2)' Note that element-wise (Hadamard) operations are used by default between symbols. This is because its possible in Julia to write "vectorized" code. It is harmless if the values are scalars. >>> julia_code(sin(pi*x*y), assign_to="s") 's = sin(pi*x.*y)' If you need a matrix product "*" or matrix power "^", you can specify the symbol as a ``MatrixSymbol``. >>> from sympy import Symbol, MatrixSymbol >>> n = Symbol('n', integer=True, positive=True) >>> A = MatrixSymbol('A', n, n) >>> julia_code(3*pi*A**3) '(3*pi)*A^3' This class uses several rules to decide which symbol to use a product. Pure numbers use "*", Symbols use ".*" and MatrixSymbols use "*". A HadamardProduct can be used to specify componentwise multiplication ".*" of two MatrixSymbols. There is currently there is no easy way to specify scalar symbols, so sometimes the code might have some minor cosmetic issues. For example, suppose x and y are scalars and A is a Matrix, then while a human programmer might write "(x^2*y)*A^3", we generate: >>> julia_code(x**2*y*A**3) '(x.^2.*y)*A^3' Matrices are supported using Julia inline notation. When using ``assign_to`` with matrices, the name can be specified either as a string or as a ``MatrixSymbol``. The dimensions must align in the latter case. >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([[x**2, sin(x), ceiling(x)]]) >>> julia_code(mat, assign_to='A') 'A = [x.^2 sin(x) ceil(x)]' ``Piecewise`` expressions are implemented with logical masking by default. Alternatively, you can pass "inline=False" to use if-else conditionals. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> pw = Piecewise((x + 1, x > 0), (x, True)) >>> julia_code(pw, assign_to=tau) 'tau = ((x > 0) ? (x + 1) : (x))' Note that any expression that can be generated normally can also exist inside a Matrix: >>> mat = Matrix([[x**2, pw, sin(x)]]) >>> julia_code(mat, assign_to='A') 'A = [x.^2 ((x > 0) ? (x + 1) : (x)) sin(x)]' Custom printing can be defined for certain types by passing a dictionary of "type" : "function" to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e., [(argument_test, cfunction_string)]. This can be used to call a custom Julia function. >>> from sympy import Function >>> f = Function('f') >>> g = Function('g') >>> custom_functions = { ... "f": "existing_julia_fcn", ... "g": [(lambda x: x.is_Matrix, "my_mat_fcn"), ... (lambda x: not x.is_Matrix, "my_fcn")] ... } >>> mat = Matrix([[1, x]]) >>> julia_code(f(x) + g(x) + g(mat), user_functions=custom_functions) 'existing_julia_fcn(x) + my_fcn(x) + my_mat_fcn([1 x])' Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e = Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> julia_code(e.rhs, assign_to=e.lhs, contract=False) 'Dy[i] = (y[i + 1] - y[i])./(t[i + 1] - t[i])' """ return JuliaCodePrinter(settings).doprint(expr, assign_to) def print_julia_code(expr, **settings): """Prints the Julia representation of the given expression. See `julia_code` for the meaning of the optional arguments. """ print(julia_code(expr, **settings)) sympy-sympy-1.9/sympy/printing/lambdarepr.py000066400000000000000000000135271412543434000214310ustar00rootroot00000000000000from .pycode import ( PythonCodePrinter, MpmathPrinter, # MpmathPrinter is imported for backward compatibility ) from .numpy import NumPyPrinter # NumPyPrinter is imported for backward compatibility from sympy.utilities import default_sort_key __all__ = [ 'PythonCodePrinter', 'MpmathPrinter', 'NumPyPrinter', 'LambdaPrinter', 'NumPyPrinter', 'lambdarepr', ] class LambdaPrinter(PythonCodePrinter): """ This printer converts expressions into strings that can be used by lambdify. """ printmethod = "_lambdacode" def _print_And(self, expr): result = ['('] for arg in sorted(expr.args, key=default_sort_key): result.extend(['(', self._print(arg), ')']) result.append(' and ') result = result[:-1] result.append(')') return ''.join(result) def _print_Or(self, expr): result = ['('] for arg in sorted(expr.args, key=default_sort_key): result.extend(['(', self._print(arg), ')']) result.append(' or ') result = result[:-1] result.append(')') return ''.join(result) def _print_Not(self, expr): result = ['(', 'not (', self._print(expr.args[0]), '))'] return ''.join(result) def _print_BooleanTrue(self, expr): return "True" def _print_BooleanFalse(self, expr): return "False" def _print_ITE(self, expr): result = [ '((', self._print(expr.args[1]), ') if (', self._print(expr.args[0]), ') else (', self._print(expr.args[2]), '))' ] return ''.join(result) def _print_NumberSymbol(self, expr): return str(expr) def _print_Pow(self, expr, **kwargs): # XXX Temporary workaround. Should python math printer be # isolated from PythonCodePrinter? return super(PythonCodePrinter, self)._print_Pow(expr, **kwargs) # numexpr works by altering the string passed to numexpr.evaluate # rather than by populating a namespace. Thus a special printer... class NumExprPrinter(LambdaPrinter): # key, value pairs correspond to sympy name and numexpr name # functions not appearing in this dict will raise a TypeError printmethod = "_numexprcode" _numexpr_functions = { 'sin' : 'sin', 'cos' : 'cos', 'tan' : 'tan', 'asin': 'arcsin', 'acos': 'arccos', 'atan': 'arctan', 'atan2' : 'arctan2', 'sinh' : 'sinh', 'cosh' : 'cosh', 'tanh' : 'tanh', 'asinh': 'arcsinh', 'acosh': 'arccosh', 'atanh': 'arctanh', 'ln' : 'log', 'log': 'log', 'exp': 'exp', 'sqrt' : 'sqrt', 'Abs' : 'abs', 'conjugate' : 'conj', 'im' : 'imag', 're' : 'real', 'where' : 'where', 'complex' : 'complex', 'contains' : 'contains', } def _print_ImaginaryUnit(self, expr): return '1j' def _print_seq(self, seq, delimiter=', '): # simplified _print_seq taken from pretty.py s = [self._print(item) for item in seq] if s: return delimiter.join(s) else: return "" def _print_Function(self, e): func_name = e.func.__name__ nstr = self._numexpr_functions.get(func_name, None) if nstr is None: # check for implemented_function if hasattr(e, '_imp_'): return "(%s)" % self._print(e._imp_(*e.args)) else: raise TypeError("numexpr does not support function '%s'" % func_name) return "%s(%s)" % (nstr, self._print_seq(e.args)) def _print_Piecewise(self, expr): "Piecewise function printer" exprs = [self._print(arg.expr) for arg in expr.args] conds = [self._print(arg.cond) for arg in expr.args] # If [default_value, True] is a (expr, cond) sequence in a Piecewise object # it will behave the same as passing the 'default' kwarg to select() # *as long as* it is the last element in expr.args. # If this is not the case, it may be triggered prematurely. ans = [] parenthesis_count = 0 is_last_cond_True = False for cond, expr in zip(conds, exprs): if cond == 'True': ans.append(expr) is_last_cond_True = True break else: ans.append('where(%s, %s, ' % (cond, expr)) parenthesis_count += 1 if not is_last_cond_True: # simplest way to put a nan but raises # 'RuntimeWarning: invalid value encountered in log' ans.append('log(-1)') return ''.join(ans) + ')' * parenthesis_count def _print_ITE(self, expr): from sympy.functions.elementary.piecewise import Piecewise return self._print(expr.rewrite(Piecewise)) def blacklisted(self, expr): raise TypeError("numexpr cannot be used with %s" % expr.__class__.__name__) # blacklist all Matrix printing _print_SparseMatrix = \ _print_MutableSparseMatrix = \ _print_ImmutableSparseMatrix = \ _print_Matrix = \ _print_DenseMatrix = \ _print_MutableDenseMatrix = \ _print_ImmutableMatrix = \ _print_ImmutableDenseMatrix = \ blacklisted # blacklist some python expressions _print_list = \ _print_tuple = \ _print_Tuple = \ _print_dict = \ _print_Dict = \ blacklisted def doprint(self, expr): lstr = super().doprint(expr) return "evaluate('%s', truediv=True)" % lstr for k in NumExprPrinter._numexpr_functions: setattr(NumExprPrinter, '_print_%s' % k, NumExprPrinter._print_Function) def lambdarepr(expr, **settings): """ Returns a string usable for lambdifying. """ return LambdaPrinter(settings).doprint(expr) sympy-sympy-1.9/sympy/printing/latex.py000066400000000000000000003364001412543434000204330ustar00rootroot00000000000000""" A Printer which converts an expression into its LaTeX equivalent. """ from typing import Any, Dict import itertools from sympy.core import Add, Float, Mod, Mul, Number, S, Symbol from sympy.core.alphabets import greeks from sympy.core.containers import Tuple from sympy.core.function import _coeff_isneg, AppliedUndef, Derivative from sympy.core.operations import AssocOp from sympy.core.sympify import SympifyError from sympy.logic.boolalg import true # sympy.printing imports from sympy.printing.precedence import precedence_traditional from sympy.printing.printer import Printer, print_function from sympy.printing.conventions import split_super_sub, requires_partial from sympy.printing.precedence import precedence, PRECEDENCE import mpmath.libmp as mlib from mpmath.libmp import prec_to_dps from sympy.core.compatibility import default_sort_key from sympy.utilities.iterables import has_variety import re # Hand-picked functions which can be used directly in both LaTeX and MathJax # Complete list at # https://docs.mathjax.org/en/latest/tex.html#supported-latex-commands # This variable only contains those functions which sympy uses. accepted_latex_functions = ['arcsin', 'arccos', 'arctan', 'sin', 'cos', 'tan', 'sinh', 'cosh', 'tanh', 'sqrt', 'ln', 'log', 'sec', 'csc', 'cot', 'coth', 're', 'im', 'frac', 'root', 'arg', ] tex_greek_dictionary = { 'Alpha': 'A', 'Beta': 'B', 'Gamma': r'\Gamma', 'Delta': r'\Delta', 'Epsilon': 'E', 'Zeta': 'Z', 'Eta': 'H', 'Theta': r'\Theta', 'Iota': 'I', 'Kappa': 'K', 'Lambda': r'\Lambda', 'Mu': 'M', 'Nu': 'N', 'Xi': r'\Xi', 'omicron': 'o', 'Omicron': 'O', 'Pi': r'\Pi', 'Rho': 'P', 'Sigma': r'\Sigma', 'Tau': 'T', 'Upsilon': r'\Upsilon', 'Phi': r'\Phi', 'Chi': 'X', 'Psi': r'\Psi', 'Omega': r'\Omega', 'lamda': r'\lambda', 'Lamda': r'\Lambda', 'khi': r'\chi', 'Khi': r'X', 'varepsilon': r'\varepsilon', 'varkappa': r'\varkappa', 'varphi': r'\varphi', 'varpi': r'\varpi', 'varrho': r'\varrho', 'varsigma': r'\varsigma', 'vartheta': r'\vartheta', } other_symbols = {'aleph', 'beth', 'daleth', 'gimel', 'ell', 'eth', 'hbar', 'hslash', 'mho', 'wp'} # Variable name modifiers modifier_dict = { # Accents 'mathring': lambda s: r'\mathring{'+s+r'}', 'ddddot': lambda s: r'\ddddot{'+s+r'}', 'dddot': lambda s: r'\dddot{'+s+r'}', 'ddot': lambda s: r'\ddot{'+s+r'}', 'dot': lambda s: r'\dot{'+s+r'}', 'check': lambda s: r'\check{'+s+r'}', 'breve': lambda s: r'\breve{'+s+r'}', 'acute': lambda s: r'\acute{'+s+r'}', 'grave': lambda s: r'\grave{'+s+r'}', 'tilde': lambda s: r'\tilde{'+s+r'}', 'hat': lambda s: r'\hat{'+s+r'}', 'bar': lambda s: r'\bar{'+s+r'}', 'vec': lambda s: r'\vec{'+s+r'}', 'prime': lambda s: "{"+s+"}'", 'prm': lambda s: "{"+s+"}'", # Faces 'bold': lambda s: r'\boldsymbol{'+s+r'}', 'bm': lambda s: r'\boldsymbol{'+s+r'}', 'cal': lambda s: r'\mathcal{'+s+r'}', 'scr': lambda s: r'\mathscr{'+s+r'}', 'frak': lambda s: r'\mathfrak{'+s+r'}', # Brackets 'norm': lambda s: r'\left\|{'+s+r'}\right\|', 'avg': lambda s: r'\left\langle{'+s+r'}\right\rangle', 'abs': lambda s: r'\left|{'+s+r'}\right|', 'mag': lambda s: r'\left|{'+s+r'}\right|', } greek_letters_set = frozenset(greeks) _between_two_numbers_p = ( re.compile(r'[0-9][} ]*$'), # search re.compile(r'[{ ]*[-+0-9]'), # match ) def latex_escape(s): """ Escape a string such that latex interprets it as plaintext. We can't use verbatim easily with mathjax, so escaping is easier. Rules from https://tex.stackexchange.com/a/34586/41112. """ s = s.replace('\\', r'\textbackslash') for c in '&%$#_{}': s = s.replace(c, '\\' + c) s = s.replace('~', r'\textasciitilde') s = s.replace('^', r'\textasciicircum') return s class LatexPrinter(Printer): printmethod = "_latex" _default_settings = { "full_prec": False, "fold_frac_powers": False, "fold_func_brackets": False, "fold_short_frac": None, "inv_trig_style": "abbreviated", "itex": False, "ln_notation": False, "long_frac_ratio": None, "mat_delim": "[", "mat_str": None, "mode": "plain", "mul_symbol": None, "order": None, "symbol_names": {}, "root_notation": True, "mat_symbol_style": "plain", "imaginary_unit": "i", "gothic_re_im": False, "decimal_separator": "period", "perm_cyclic": True, "parenthesize_super": True, "min": None, "max": None, } # type: Dict[str, Any] def __init__(self, settings=None): Printer.__init__(self, settings) if 'mode' in self._settings: valid_modes = ['inline', 'plain', 'equation', 'equation*'] if self._settings['mode'] not in valid_modes: raise ValueError("'mode' must be one of 'inline', 'plain', " "'equation' or 'equation*'") if self._settings['fold_short_frac'] is None and \ self._settings['mode'] == 'inline': self._settings['fold_short_frac'] = True mul_symbol_table = { None: r" ", "ldot": r" \,.\, ", "dot": r" \cdot ", "times": r" \times " } try: self._settings['mul_symbol_latex'] = \ mul_symbol_table[self._settings['mul_symbol']] except KeyError: self._settings['mul_symbol_latex'] = \ self._settings['mul_symbol'] try: self._settings['mul_symbol_latex_numbers'] = \ mul_symbol_table[self._settings['mul_symbol'] or 'dot'] except KeyError: if (self._settings['mul_symbol'].strip() in ['', ' ', '\\', '\\,', '\\:', '\\;', '\\quad']): self._settings['mul_symbol_latex_numbers'] = \ mul_symbol_table['dot'] else: self._settings['mul_symbol_latex_numbers'] = \ self._settings['mul_symbol'] self._delim_dict = {'(': ')', '[': ']'} imaginary_unit_table = { None: r"i", "i": r"i", "ri": r"\mathrm{i}", "ti": r"\text{i}", "j": r"j", "rj": r"\mathrm{j}", "tj": r"\text{j}", } try: self._settings['imaginary_unit_latex'] = \ imaginary_unit_table[self._settings['imaginary_unit']] except KeyError: self._settings['imaginary_unit_latex'] = \ self._settings['imaginary_unit'] def _add_parens(self, s): return r"\left({}\right)".format(s) # TODO: merge this with the above, which requires a lot of test changes def _add_parens_lspace(self, s): return r"\left( {}\right)".format(s) def parenthesize(self, item, level, is_neg=False, strict=False): prec_val = precedence_traditional(item) if is_neg and strict: return self._add_parens(self._print(item)) if (prec_val < level) or ((not strict) and prec_val <= level): return self._add_parens(self._print(item)) else: return self._print(item) def parenthesize_super(self, s): """ Protect superscripts in s If the parenthesize_super option is set, protect with parentheses, else wrap in braces. """ if "^" in s: if self._settings['parenthesize_super']: return self._add_parens(s) else: return "{{{}}}".format(s) return s def doprint(self, expr): tex = Printer.doprint(self, expr) if self._settings['mode'] == 'plain': return tex elif self._settings['mode'] == 'inline': return r"$%s$" % tex elif self._settings['itex']: return r"$$%s$$" % tex else: env_str = self._settings['mode'] return r"\begin{%s}%s\end{%s}" % (env_str, tex, env_str) def _needs_brackets(self, expr): """ Returns True if the expression needs to be wrapped in brackets when printed, False otherwise. For example: a + b => True; a => False; 10 => False; -10 => True. """ return not ((expr.is_Integer and expr.is_nonnegative) or (expr.is_Atom and (expr is not S.NegativeOne and expr.is_Rational is False))) def _needs_function_brackets(self, expr): """ Returns True if the expression needs to be wrapped in brackets when passed as an argument to a function, False otherwise. This is a more liberal version of _needs_brackets, in that many expressions which need to be wrapped in brackets when added/subtracted/raised to a power do not need them when passed to a function. Such an example is a*b. """ if not self._needs_brackets(expr): return False else: # Muls of the form a*b*c... can be folded if expr.is_Mul and not self._mul_is_clean(expr): return True # Pows which don't need brackets can be folded elif expr.is_Pow and not self._pow_is_clean(expr): return True # Add and Function always need brackets elif expr.is_Add or expr.is_Function: return True else: return False def _needs_mul_brackets(self, expr, first=False, last=False): """ Returns True if the expression needs to be wrapped in brackets when printed as part of a Mul, False otherwise. This is True for Add, but also for some container objects that would not need brackets when appearing last in a Mul, e.g. an Integral. ``last=True`` specifies that this expr is the last to appear in a Mul. ``first=True`` specifies that this expr is the first to appear in a Mul. """ from sympy import Integral, Product, Sum if expr.is_Mul: if not first and _coeff_isneg(expr): return True elif precedence_traditional(expr) < PRECEDENCE["Mul"]: return True elif expr.is_Relational: return True if expr.is_Piecewise: return True if any([expr.has(x) for x in (Mod,)]): return True if (not last and any([expr.has(x) for x in (Integral, Product, Sum)])): return True return False def _needs_add_brackets(self, expr): """ Returns True if the expression needs to be wrapped in brackets when printed as part of an Add, False otherwise. This is False for most things. """ if expr.is_Relational: return True if any([expr.has(x) for x in (Mod,)]): return True if expr.is_Add: return True return False def _mul_is_clean(self, expr): for arg in expr.args: if arg.is_Function: return False return True def _pow_is_clean(self, expr): return not self._needs_brackets(expr.base) def _do_exponent(self, expr, exp): if exp is not None: return r"\left(%s\right)^{%s}" % (expr, exp) else: return expr def _print_Basic(self, expr): ls = [self._print(o) for o in expr.args] return self._deal_with_super_sub(expr.__class__.__name__) + \ r"\left(%s\right)" % ", ".join(ls) def _print_bool(self, e): return r"\text{%s}" % e _print_BooleanTrue = _print_bool _print_BooleanFalse = _print_bool def _print_NoneType(self, e): return r"\text{%s}" % e def _print_Add(self, expr, order=None): terms = self._as_ordered_terms(expr, order=order) tex = "" for i, term in enumerate(terms): if i == 0: pass elif _coeff_isneg(term): tex += " - " term = -term else: tex += " + " term_tex = self._print(term) if self._needs_add_brackets(term): term_tex = r"\left(%s\right)" % term_tex tex += term_tex return tex def _print_Cycle(self, expr): from sympy.combinatorics.permutations import Permutation if expr.size == 0: return r"\left( \right)" expr = Permutation(expr) expr_perm = expr.cyclic_form siz = expr.size if expr.array_form[-1] == siz - 1: expr_perm = expr_perm + [[siz - 1]] term_tex = '' for i in expr_perm: term_tex += str(i).replace(',', r"\;") term_tex = term_tex.replace('[', r"\left( ") term_tex = term_tex.replace(']', r"\right)") return term_tex def _print_Permutation(self, expr): from sympy.combinatorics.permutations import Permutation from sympy.utilities.exceptions import SymPyDeprecationWarning perm_cyclic = Permutation.print_cyclic if perm_cyclic is not None: SymPyDeprecationWarning( feature="Permutation.print_cyclic = {}".format(perm_cyclic), useinstead="init_printing(perm_cyclic={})" .format(perm_cyclic), issue=15201, deprecated_since_version="1.6").warn() else: perm_cyclic = self._settings.get("perm_cyclic", True) if perm_cyclic: return self._print_Cycle(expr) if expr.size == 0: return r"\left( \right)" lower = [self._print(arg) for arg in expr.array_form] upper = [self._print(arg) for arg in range(len(lower))] row1 = " & ".join(upper) row2 = " & ".join(lower) mat = r" \\ ".join((row1, row2)) return r"\begin{pmatrix} %s \end{pmatrix}" % mat def _print_AppliedPermutation(self, expr): perm, var = expr.args return r"\sigma_{%s}(%s)" % (self._print(perm), self._print(var)) def _print_Float(self, expr): # Based off of that in StrPrinter dps = prec_to_dps(expr._prec) strip = False if self._settings['full_prec'] else True low = self._settings["min"] if "min" in self._settings else None high = self._settings["max"] if "max" in self._settings else None str_real = mlib.to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high) # Must always have a mul symbol (as 2.5 10^{20} just looks odd) # thus we use the number separator separator = self._settings['mul_symbol_latex_numbers'] if 'e' in str_real: (mant, exp) = str_real.split('e') if exp[0] == '+': exp = exp[1:] if self._settings['decimal_separator'] == 'comma': mant = mant.replace('.','{,}') return r"%s%s10^{%s}" % (mant, separator, exp) elif str_real == "+inf": return r"\infty" elif str_real == "-inf": return r"- \infty" else: if self._settings['decimal_separator'] == 'comma': str_real = str_real.replace('.','{,}') return str_real def _print_Cross(self, expr): vec1 = expr._expr1 vec2 = expr._expr2 return r"%s \times %s" % (self.parenthesize(vec1, PRECEDENCE['Mul']), self.parenthesize(vec2, PRECEDENCE['Mul'])) def _print_Curl(self, expr): vec = expr._expr return r"\nabla\times %s" % self.parenthesize(vec, PRECEDENCE['Mul']) def _print_Divergence(self, expr): vec = expr._expr return r"\nabla\cdot %s" % self.parenthesize(vec, PRECEDENCE['Mul']) def _print_Dot(self, expr): vec1 = expr._expr1 vec2 = expr._expr2 return r"%s \cdot %s" % (self.parenthesize(vec1, PRECEDENCE['Mul']), self.parenthesize(vec2, PRECEDENCE['Mul'])) def _print_Gradient(self, expr): func = expr._expr return r"\nabla %s" % self.parenthesize(func, PRECEDENCE['Mul']) def _print_Laplacian(self, expr): func = expr._expr return r"\triangle %s" % self.parenthesize(func, PRECEDENCE['Mul']) def _print_Mul(self, expr): from sympy.core.power import Pow from sympy.physics.units import Quantity from sympy.simplify import fraction separator = self._settings['mul_symbol_latex'] numbersep = self._settings['mul_symbol_latex_numbers'] def convert(expr): if not expr.is_Mul: return str(self._print(expr)) else: if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: args = list(expr.args) # If quantities are present append them at the back args = sorted(args, key=lambda x: isinstance(x, Quantity) or (isinstance(x, Pow) and isinstance(x.base, Quantity))) return convert_args(args) def convert_args(args): _tex = last_term_tex = "" for i, term in enumerate(args): term_tex = self._print(term) if self._needs_mul_brackets(term, first=(i == 0), last=(i == len(args) - 1)): term_tex = r"\left(%s\right)" % term_tex if _between_two_numbers_p[0].search(last_term_tex) and \ _between_two_numbers_p[1].match(term_tex): # between two numbers _tex += numbersep elif _tex: _tex += separator _tex += term_tex last_term_tex = term_tex return _tex # Check for unevaluated Mul. In this case we need to make sure the # identities are visible, multiple Rational factors are not combined # etc so we display in a straight-forward form that fully preserves all # args and their order. # XXX: _print_Pow calls this routine with instances of Pow... if isinstance(expr, Mul): args = expr.args if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]): return convert_args(args) include_parens = False if _coeff_isneg(expr): expr = -expr tex = "- " if expr.is_Add: tex += "(" include_parens = True else: tex = "" numer, denom = fraction(expr, exact=True) if denom is S.One and Pow(1, -1, evaluate=False) not in expr.args: # use the original expression here, since fraction() may have # altered it when producing numer and denom tex += convert(expr) else: snumer = convert(numer) sdenom = convert(denom) ldenom = len(sdenom.split()) ratio = self._settings['long_frac_ratio'] if self._settings['fold_short_frac'] and ldenom <= 2 and \ "^" not in sdenom: # handle short fractions if self._needs_mul_brackets(numer, last=False): tex += r"\left(%s\right) / %s" % (snumer, sdenom) else: tex += r"%s / %s" % (snumer, sdenom) elif ratio is not None and \ len(snumer.split()) > ratio*ldenom: # handle long fractions if self._needs_mul_brackets(numer, last=True): tex += r"\frac{1}{%s}%s\left(%s\right)" \ % (sdenom, separator, snumer) elif numer.is_Mul: # split a long numerator a = S.One b = S.One for x in numer.args: if self._needs_mul_brackets(x, last=False) or \ len(convert(a*x).split()) > ratio*ldenom or \ (b.is_commutative is x.is_commutative is False): b *= x else: a *= x if self._needs_mul_brackets(b, last=True): tex += r"\frac{%s}{%s}%s\left(%s\right)" \ % (convert(a), sdenom, separator, convert(b)) else: tex += r"\frac{%s}{%s}%s%s" \ % (convert(a), sdenom, separator, convert(b)) else: tex += r"\frac{1}{%s}%s%s" % (sdenom, separator, snumer) else: tex += r"\frac{%s}{%s}" % (snumer, sdenom) if include_parens: tex += ")" return tex def _print_Pow(self, expr): # Treat x**Rational(1,n) as special case if expr.exp.is_Rational and abs(expr.exp.p) == 1 and expr.exp.q != 1 \ and self._settings['root_notation']: base = self._print(expr.base) expq = expr.exp.q if expq == 2: tex = r"\sqrt{%s}" % base elif self._settings['itex']: tex = r"\root{%d}{%s}" % (expq, base) else: tex = r"\sqrt[%d]{%s}" % (expq, base) if expr.exp.is_negative: return r"\frac{1}{%s}" % tex else: return tex elif self._settings['fold_frac_powers'] \ and expr.exp.is_Rational \ and expr.exp.q != 1: base = self.parenthesize(expr.base, PRECEDENCE['Pow']) p, q = expr.exp.p, expr.exp.q # issue #12886: add parentheses for superscripts raised to powers if expr.base.is_Symbol: base = self.parenthesize_super(base) if expr.base.is_Function: return self._print(expr.base, exp="%s/%s" % (p, q)) return r"%s^{%s/%s}" % (base, p, q) elif expr.exp.is_Rational and expr.exp.is_negative and \ expr.base.is_commutative: # special case for 1^(-x), issue 9216 if expr.base == 1: return r"%s^{%s}" % (expr.base, expr.exp) # special case for (1/x)^(-y) and (-1/-x)^(-y), issue 20252 if expr.base.is_Rational and \ expr.base.p*expr.base.q == abs(expr.base.q): if expr.exp == -1: return r"\frac{1}{\frac{%s}{%s}}" % (expr.base.p, expr.base.q) else: return r"\frac{1}{(\frac{%s}{%s})^{%s}}" % (expr.base.p, expr.base.q, abs(expr.exp)) # things like 1/x return self._print_Mul(expr) else: if expr.base.is_Function: return self._print(expr.base, exp=self._print(expr.exp)) else: tex = r"%s^{%s}" return self._helper_print_standard_power(expr, tex) def _helper_print_standard_power(self, expr, template): exp = self._print(expr.exp) # issue #12886: add parentheses around superscripts raised # to powers base = self.parenthesize(expr.base, PRECEDENCE['Pow']) if expr.base.is_Symbol: base = self.parenthesize_super(base) elif (isinstance(expr.base, Derivative) and base.startswith(r'\left(') and re.match(r'\\left\(\\d?d?dot', base) and base.endswith(r'\right)')): # don't use parentheses around dotted derivative base = base[6: -7] # remove outermost added parens return template % (base, exp) def _print_UnevaluatedExpr(self, expr): return self._print(expr.args[0]) def _print_Sum(self, expr): if len(expr.limits) == 1: tex = r"\sum_{%s=%s}^{%s} " % \ tuple([self._print(i) for i in expr.limits[0]]) else: def _format_ineq(l): return r"%s \leq %s \leq %s" % \ tuple([self._print(s) for s in (l[1], l[0], l[2])]) tex = r"\sum_{\substack{%s}} " % \ str.join('\\\\', [_format_ineq(l) for l in expr.limits]) if isinstance(expr.function, Add): tex += r"\left(%s\right)" % self._print(expr.function) else: tex += self._print(expr.function) return tex def _print_Product(self, expr): if len(expr.limits) == 1: tex = r"\prod_{%s=%s}^{%s} " % \ tuple([self._print(i) for i in expr.limits[0]]) else: def _format_ineq(l): return r"%s \leq %s \leq %s" % \ tuple([self._print(s) for s in (l[1], l[0], l[2])]) tex = r"\prod_{\substack{%s}} " % \ str.join('\\\\', [_format_ineq(l) for l in expr.limits]) if isinstance(expr.function, Add): tex += r"\left(%s\right)" % self._print(expr.function) else: tex += self._print(expr.function) return tex def _print_BasisDependent(self, expr): from sympy.vector import Vector o1 = [] if expr == expr.zero: return expr.zero._latex_form if isinstance(expr, Vector): items = expr.separate().items() else: items = [(0, expr)] for system, vect in items: inneritems = list(vect.components.items()) inneritems.sort(key=lambda x: x[0].__str__()) for k, v in inneritems: if v == 1: o1.append(' + ' + k._latex_form) elif v == -1: o1.append(' - ' + k._latex_form) else: arg_str = '(' + self._print(v) + ')' o1.append(' + ' + arg_str + k._latex_form) outstr = (''.join(o1)) if outstr[1] != '-': outstr = outstr[3:] else: outstr = outstr[1:] return outstr def _print_Indexed(self, expr): tex_base = self._print(expr.base) tex = '{'+tex_base+'}'+'_{%s}' % ','.join( map(self._print, expr.indices)) return tex def _print_IndexedBase(self, expr): return self._print(expr.label) def _print_Derivative(self, expr): if requires_partial(expr.expr): diff_symbol = r'\partial' else: diff_symbol = r'd' tex = "" dim = 0 for x, num in reversed(expr.variable_count): dim += num if num == 1: tex += r"%s %s" % (diff_symbol, self._print(x)) else: tex += r"%s %s^{%s}" % (diff_symbol, self.parenthesize_super(self._print(x)), self._print(num)) if dim == 1: tex = r"\frac{%s}{%s}" % (diff_symbol, tex) else: tex = r"\frac{%s^{%s}}{%s}" % (diff_symbol, self._print(dim), tex) if any(_coeff_isneg(i) for i in expr.args): return r"%s %s" % (tex, self.parenthesize(expr.expr, PRECEDENCE["Mul"], is_neg=True, strict=True)) return r"%s %s" % (tex, self.parenthesize(expr.expr, PRECEDENCE["Mul"], is_neg=False, strict=True)) def _print_Subs(self, subs): expr, old, new = subs.args latex_expr = self._print(expr) latex_old = (self._print(e) for e in old) latex_new = (self._print(e) for e in new) latex_subs = r'\\ '.join( e[0] + '=' + e[1] for e in zip(latex_old, latex_new)) return r'\left. %s \right|_{\substack{ %s }}' % (latex_expr, latex_subs) def _print_Integral(self, expr): tex, symbols = "", [] # Only up to \iiiint exists if len(expr.limits) <= 4 and all(len(lim) == 1 for lim in expr.limits): # Use len(expr.limits)-1 so that syntax highlighters don't think # \" is an escaped quote tex = r"\i" + "i"*(len(expr.limits) - 1) + "nt" symbols = [r"\, d%s" % self._print(symbol[0]) for symbol in expr.limits] else: for lim in reversed(expr.limits): symbol = lim[0] tex += r"\int" if len(lim) > 1: if self._settings['mode'] != 'inline' \ and not self._settings['itex']: tex += r"\limits" if len(lim) == 3: tex += "_{%s}^{%s}" % (self._print(lim[1]), self._print(lim[2])) if len(lim) == 2: tex += "^{%s}" % (self._print(lim[1])) symbols.insert(0, r"\, d%s" % self._print(symbol)) return r"%s %s%s" % (tex, self.parenthesize(expr.function, PRECEDENCE["Mul"], is_neg=any(_coeff_isneg(i) for i in expr.args), strict=True), "".join(symbols)) def _print_Limit(self, expr): e, z, z0, dir = expr.args tex = r"\lim_{%s \to " % self._print(z) if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity): tex += r"%s}" % self._print(z0) else: tex += r"%s^%s}" % (self._print(z0), self._print(dir)) if isinstance(e, AssocOp): return r"%s\left(%s\right)" % (tex, self._print(e)) else: return r"%s %s" % (tex, self._print(e)) def _hprint_Function(self, func): r''' Logic to decide how to render a function to latex - if it is a recognized latex name, use the appropriate latex command - if it is a single letter, just use that letter - if it is a longer name, then put \operatorname{} around it and be mindful of undercores in the name ''' func = self._deal_with_super_sub(func) if func in accepted_latex_functions: name = r"\%s" % func elif len(func) == 1 or func.startswith('\\'): name = func else: name = r"\operatorname{%s}" % func return name def _print_Function(self, expr, exp=None): r''' Render functions to LaTeX, handling functions that LaTeX knows about e.g., sin, cos, ... by using the proper LaTeX command (\sin, \cos, ...). For single-letter function names, render them as regular LaTeX math symbols. For multi-letter function names that LaTeX does not know about, (e.g., Li, sech) use \operatorname{} so that the function name is rendered in Roman font and LaTeX handles spacing properly. expr is the expression involving the function exp is an exponent ''' func = expr.func.__name__ if hasattr(self, '_print_' + func) and \ not isinstance(expr, AppliedUndef): return getattr(self, '_print_' + func)(expr, exp) else: args = [str(self._print(arg)) for arg in expr.args] # How inverse trig functions should be displayed, formats are: # abbreviated: asin, full: arcsin, power: sin^-1 inv_trig_style = self._settings['inv_trig_style'] # If we are dealing with a power-style inverse trig function inv_trig_power_case = False # If it is applicable to fold the argument brackets can_fold_brackets = self._settings['fold_func_brackets'] and \ len(args) == 1 and \ not self._needs_function_brackets(expr.args[0]) inv_trig_table = [ "asin", "acos", "atan", "acsc", "asec", "acot", "asinh", "acosh", "atanh", "acsch", "asech", "acoth", ] # If the function is an inverse trig function, handle the style if func in inv_trig_table: if inv_trig_style == "abbreviated": pass elif inv_trig_style == "full": func = "arc" + func[1:] elif inv_trig_style == "power": func = func[1:] inv_trig_power_case = True # Can never fold brackets if we're raised to a power if exp is not None: can_fold_brackets = False if inv_trig_power_case: if func in accepted_latex_functions: name = r"\%s^{-1}" % func else: name = r"\operatorname{%s}^{-1}" % func elif exp is not None: func_tex = self._hprint_Function(func) func_tex = self.parenthesize_super(func_tex) name = r'%s^{%s}' % (func_tex, exp) else: name = self._hprint_Function(func) if can_fold_brackets: if func in accepted_latex_functions: # Wrap argument safely to avoid parse-time conflicts # with the function name itself name += r" {%s}" else: name += r"%s" else: name += r"{\left(%s \right)}" if inv_trig_power_case and exp is not None: name += r"^{%s}" % exp return name % ",".join(args) def _print_UndefinedFunction(self, expr): return self._hprint_Function(str(expr)) def _print_ElementwiseApplyFunction(self, expr): return r"{%s}_{\circ}\left({%s}\right)" % ( self._print(expr.function), self._print(expr.expr), ) @property def _special_function_classes(self): from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.functions.special.gamma_functions import gamma, lowergamma from sympy.functions.special.beta_functions import beta from sympy.functions.special.delta_functions import DiracDelta from sympy.functions.special.error_functions import Chi return {KroneckerDelta: r'\delta', gamma: r'\Gamma', lowergamma: r'\gamma', beta: r'\operatorname{B}', DiracDelta: r'\delta', Chi: r'\operatorname{Chi}'} def _print_FunctionClass(self, expr): for cls in self._special_function_classes: if issubclass(expr, cls) and expr.__name__ == cls.__name__: return self._special_function_classes[cls] return self._hprint_Function(str(expr)) def _print_Lambda(self, expr): symbols, expr = expr.args if len(symbols) == 1: symbols = self._print(symbols[0]) else: symbols = self._print(tuple(symbols)) tex = r"\left( %s \mapsto %s \right)" % (symbols, self._print(expr)) return tex def _print_IdentityFunction(self, expr): return r"\left( x \mapsto x \right)" def _hprint_variadic_function(self, expr, exp=None): args = sorted(expr.args, key=default_sort_key) texargs = [r"%s" % self._print(symbol) for symbol in args] tex = r"\%s\left(%s\right)" % (str(expr.func).lower(), ", ".join(texargs)) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex _print_Min = _print_Max = _hprint_variadic_function def _print_floor(self, expr, exp=None): tex = r"\left\lfloor{%s}\right\rfloor" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_ceiling(self, expr, exp=None): tex = r"\left\lceil{%s}\right\rceil" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_log(self, expr, exp=None): if not self._settings["ln_notation"]: tex = r"\log{\left(%s \right)}" % self._print(expr.args[0]) else: tex = r"\ln{\left(%s \right)}" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_Abs(self, expr, exp=None): tex = r"\left|{%s}\right|" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex _print_Determinant = _print_Abs def _print_re(self, expr, exp=None): if self._settings['gothic_re_im']: tex = r"\Re{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Atom']) else: tex = r"\operatorname{{re}}{{{}}}".format(self.parenthesize(expr.args[0], PRECEDENCE['Atom'])) return self._do_exponent(tex, exp) def _print_im(self, expr, exp=None): if self._settings['gothic_re_im']: tex = r"\Im{%s}" % self.parenthesize(expr.args[0], PRECEDENCE['Atom']) else: tex = r"\operatorname{{im}}{{{}}}".format(self.parenthesize(expr.args[0], PRECEDENCE['Atom'])) return self._do_exponent(tex, exp) def _print_Not(self, e): from sympy import Equivalent, Implies if isinstance(e.args[0], Equivalent): return self._print_Equivalent(e.args[0], r"\not\Leftrightarrow") if isinstance(e.args[0], Implies): return self._print_Implies(e.args[0], r"\not\Rightarrow") if (e.args[0].is_Boolean): return r"\neg \left(%s\right)" % self._print(e.args[0]) else: return r"\neg %s" % self._print(e.args[0]) def _print_LogOp(self, args, char): arg = args[0] if arg.is_Boolean and not arg.is_Not: tex = r"\left(%s\right)" % self._print(arg) else: tex = r"%s" % self._print(arg) for arg in args[1:]: if arg.is_Boolean and not arg.is_Not: tex += r" %s \left(%s\right)" % (char, self._print(arg)) else: tex += r" %s %s" % (char, self._print(arg)) return tex def _print_And(self, e): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, r"\wedge") def _print_Or(self, e): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, r"\vee") def _print_Xor(self, e): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, r"\veebar") def _print_Implies(self, e, altchar=None): return self._print_LogOp(e.args, altchar or r"\Rightarrow") def _print_Equivalent(self, e, altchar=None): args = sorted(e.args, key=default_sort_key) return self._print_LogOp(args, altchar or r"\Leftrightarrow") def _print_conjugate(self, expr, exp=None): tex = r"\overline{%s}" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_polar_lift(self, expr, exp=None): func = r"\operatorname{polar\_lift}" arg = r"{\left(%s \right)}" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}%s" % (func, exp, arg) else: return r"%s%s" % (func, arg) def _print_ExpBase(self, expr, exp=None): # TODO should exp_polar be printed differently? # what about exp_polar(0), exp_polar(1)? tex = r"e^{%s}" % self._print(expr.args[0]) return self._do_exponent(tex, exp) def _print_Exp1(self, expr, exp=None): return "e" def _print_elliptic_k(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"K^{%s}%s" % (exp, tex) else: return r"K%s" % tex def _print_elliptic_f(self, expr, exp=None): tex = r"\left(%s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"F^{%s}%s" % (exp, tex) else: return r"F%s" % tex def _print_elliptic_e(self, expr, exp=None): if len(expr.args) == 2: tex = r"\left(%s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1])) else: tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"E^{%s}%s" % (exp, tex) else: return r"E%s" % tex def _print_elliptic_pi(self, expr, exp=None): if len(expr.args) == 3: tex = r"\left(%s; %s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1]), self._print(expr.args[2])) else: tex = r"\left(%s\middle| %s\right)" % \ (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"\Pi^{%s}%s" % (exp, tex) else: return r"\Pi%s" % tex def _print_beta(self, expr, exp=None): tex = r"\left(%s, %s\right)" % (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"\operatorname{B}^{%s}%s" % (exp, tex) else: return r"\operatorname{B}%s" % tex def _print_betainc(self, expr, exp=None, operator='B'): largs = [self._print(arg) for arg in expr.args] tex = r"\left(%s, %s\right)" % (largs[0], largs[1]) if exp is not None: return r"\operatorname{%s}_{(%s, %s)}^{%s}%s" % (operator, largs[2], largs[3], exp, tex) else: return r"\operatorname{%s}_{(%s, %s)}%s" % (operator, largs[2], largs[3], tex) def _print_betainc_regularized(self, expr, exp=None): return self._print_betainc(expr, exp, operator='I') def _print_uppergamma(self, expr, exp=None): tex = r"\left(%s, %s\right)" % (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"\Gamma^{%s}%s" % (exp, tex) else: return r"\Gamma%s" % tex def _print_lowergamma(self, expr, exp=None): tex = r"\left(%s, %s\right)" % (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"\gamma^{%s}%s" % (exp, tex) else: return r"\gamma%s" % tex def _hprint_one_arg_func(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}%s" % (self._print(expr.func), exp, tex) else: return r"%s%s" % (self._print(expr.func), tex) _print_gamma = _hprint_one_arg_func def _print_Chi(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\operatorname{Chi}^{%s}%s" % (exp, tex) else: return r"\operatorname{Chi}%s" % tex def _print_expint(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[1]) nu = self._print(expr.args[0]) if exp is not None: return r"\operatorname{E}_{%s}^{%s}%s" % (nu, exp, tex) else: return r"\operatorname{E}_{%s}%s" % (nu, tex) def _print_fresnels(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"S^{%s}%s" % (exp, tex) else: return r"S%s" % tex def _print_fresnelc(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"C^{%s}%s" % (exp, tex) else: return r"C%s" % tex def _print_subfactorial(self, expr, exp=None): tex = r"!%s" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) if exp is not None: return r"\left(%s\right)^{%s}" % (tex, exp) else: return tex def _print_factorial(self, expr, exp=None): tex = r"%s!" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_factorial2(self, expr, exp=None): tex = r"%s!!" % self.parenthesize(expr.args[0], PRECEDENCE["Func"]) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_binomial(self, expr, exp=None): tex = r"{\binom{%s}{%s}}" % (self._print(expr.args[0]), self._print(expr.args[1])) if exp is not None: return r"%s^{%s}" % (tex, exp) else: return tex def _print_RisingFactorial(self, expr, exp=None): n, k = expr.args base = r"%s" % self.parenthesize(n, PRECEDENCE['Func']) tex = r"{%s}^{\left(%s\right)}" % (base, self._print(k)) return self._do_exponent(tex, exp) def _print_FallingFactorial(self, expr, exp=None): n, k = expr.args sub = r"%s" % self.parenthesize(k, PRECEDENCE['Func']) tex = r"{\left(%s\right)}_{%s}" % (self._print(n), sub) return self._do_exponent(tex, exp) def _hprint_BesselBase(self, expr, exp, sym): tex = r"%s" % (sym) need_exp = False if exp is not None: if tex.find('^') == -1: tex = r"%s^{%s}" % (tex, exp) else: need_exp = True tex = r"%s_{%s}\left(%s\right)" % (tex, self._print(expr.order), self._print(expr.argument)) if need_exp: tex = self._do_exponent(tex, exp) return tex def _hprint_vec(self, vec): if not vec: return "" s = "" for i in vec[:-1]: s += "%s, " % self._print(i) s += self._print(vec[-1]) return s def _print_besselj(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'J') def _print_besseli(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'I') def _print_besselk(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'K') def _print_bessely(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'Y') def _print_yn(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'y') def _print_jn(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'j') def _print_hankel1(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'H^{(1)}') def _print_hankel2(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'H^{(2)}') def _print_hn1(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'h^{(1)}') def _print_hn2(self, expr, exp=None): return self._hprint_BesselBase(expr, exp, 'h^{(2)}') def _hprint_airy(self, expr, exp=None, notation=""): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"%s^{%s}%s" % (notation, exp, tex) else: return r"%s%s" % (notation, tex) def _hprint_airy_prime(self, expr, exp=None, notation=""): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"{%s^\prime}^{%s}%s" % (notation, exp, tex) else: return r"%s^\prime%s" % (notation, tex) def _print_airyai(self, expr, exp=None): return self._hprint_airy(expr, exp, 'Ai') def _print_airybi(self, expr, exp=None): return self._hprint_airy(expr, exp, 'Bi') def _print_airyaiprime(self, expr, exp=None): return self._hprint_airy_prime(expr, exp, 'Ai') def _print_airybiprime(self, expr, exp=None): return self._hprint_airy_prime(expr, exp, 'Bi') def _print_hyper(self, expr, exp=None): tex = r"{{}_{%s}F_{%s}\left(\begin{matrix} %s \\ %s \end{matrix}" \ r"\middle| {%s} \right)}" % \ (self._print(len(expr.ap)), self._print(len(expr.bq)), self._hprint_vec(expr.ap), self._hprint_vec(expr.bq), self._print(expr.argument)) if exp is not None: tex = r"{%s}^{%s}" % (tex, exp) return tex def _print_meijerg(self, expr, exp=None): tex = r"{G_{%s, %s}^{%s, %s}\left(\begin{matrix} %s & %s \\" \ r"%s & %s \end{matrix} \middle| {%s} \right)}" % \ (self._print(len(expr.ap)), self._print(len(expr.bq)), self._print(len(expr.bm)), self._print(len(expr.an)), self._hprint_vec(expr.an), self._hprint_vec(expr.aother), self._hprint_vec(expr.bm), self._hprint_vec(expr.bother), self._print(expr.argument)) if exp is not None: tex = r"{%s}^{%s}" % (tex, exp) return tex def _print_dirichlet_eta(self, expr, exp=None): tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\eta^{%s}%s" % (exp, tex) return r"\eta%s" % tex def _print_zeta(self, expr, exp=None): if len(expr.args) == 2: tex = r"\left(%s, %s\right)" % tuple(map(self._print, expr.args)) else: tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\zeta^{%s}%s" % (exp, tex) return r"\zeta%s" % tex def _print_stieltjes(self, expr, exp=None): if len(expr.args) == 2: tex = r"_{%s}\left(%s\right)" % tuple(map(self._print, expr.args)) else: tex = r"_{%s}" % self._print(expr.args[0]) if exp is not None: return r"\gamma%s^{%s}" % (tex, exp) return r"\gamma%s" % tex def _print_lerchphi(self, expr, exp=None): tex = r"\left(%s, %s, %s\right)" % tuple(map(self._print, expr.args)) if exp is None: return r"\Phi%s" % tex return r"\Phi^{%s}%s" % (exp, tex) def _print_polylog(self, expr, exp=None): s, z = map(self._print, expr.args) tex = r"\left(%s\right)" % z if exp is None: return r"\operatorname{Li}_{%s}%s" % (s, tex) return r"\operatorname{Li}_{%s}^{%s}%s" % (s, exp, tex) def _print_jacobi(self, expr, exp=None): n, a, b, x = map(self._print, expr.args) tex = r"P_{%s}^{\left(%s,%s\right)}\left(%s\right)" % (n, a, b, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_gegenbauer(self, expr, exp=None): n, a, x = map(self._print, expr.args) tex = r"C_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_chebyshevt(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"T_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_chebyshevu(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"U_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_legendre(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"P_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_assoc_legendre(self, expr, exp=None): n, a, x = map(self._print, expr.args) tex = r"P_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_hermite(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"H_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_laguerre(self, expr, exp=None): n, x = map(self._print, expr.args) tex = r"L_{%s}\left(%s\right)" % (n, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_assoc_laguerre(self, expr, exp=None): n, a, x = map(self._print, expr.args) tex = r"L_{%s}^{\left(%s\right)}\left(%s\right)" % (n, a, x) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_Ynm(self, expr, exp=None): n, m, theta, phi = map(self._print, expr.args) tex = r"Y_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def _print_Znm(self, expr, exp=None): n, m, theta, phi = map(self._print, expr.args) tex = r"Z_{%s}^{%s}\left(%s,%s\right)" % (n, m, theta, phi) if exp is not None: tex = r"\left(" + tex + r"\right)^{%s}" % (exp) return tex def __print_mathieu_functions(self, character, args, prime=False, exp=None): a, q, z = map(self._print, args) sup = r"^{\prime}" if prime else "" exp = "" if not exp else "^{%s}" % exp return r"%s%s\left(%s, %s, %s\right)%s" % (character, sup, a, q, z, exp) def _print_mathieuc(self, expr, exp=None): return self.__print_mathieu_functions("C", expr.args, exp=exp) def _print_mathieus(self, expr, exp=None): return self.__print_mathieu_functions("S", expr.args, exp=exp) def _print_mathieucprime(self, expr, exp=None): return self.__print_mathieu_functions("C", expr.args, prime=True, exp=exp) def _print_mathieusprime(self, expr, exp=None): return self.__print_mathieu_functions("S", expr.args, prime=True, exp=exp) def _print_Rational(self, expr): if expr.q != 1: sign = "" p = expr.p if expr.p < 0: sign = "- " p = -p if self._settings['fold_short_frac']: return r"%s%d / %d" % (sign, p, expr.q) return r"%s\frac{%d}{%d}" % (sign, p, expr.q) else: return self._print(expr.p) def _print_Order(self, expr): s = self._print(expr.expr) if expr.point and any(p != S.Zero for p in expr.point) or \ len(expr.variables) > 1: s += '; ' if len(expr.variables) > 1: s += self._print(expr.variables) elif expr.variables: s += self._print(expr.variables[0]) s += r'\rightarrow ' if len(expr.point) > 1: s += self._print(expr.point) else: s += self._print(expr.point[0]) return r"O\left(%s\right)" % s def _print_Symbol(self, expr, style='plain'): if expr in self._settings['symbol_names']: return self._settings['symbol_names'][expr] return self._deal_with_super_sub(expr.name, style=style) _print_RandomSymbol = _print_Symbol def _deal_with_super_sub(self, string, style='plain'): if '{' in string: name, supers, subs = string, [], [] else: name, supers, subs = split_super_sub(string) name = translate(name) supers = [translate(sup) for sup in supers] subs = [translate(sub) for sub in subs] # apply the style only to the name if style == 'bold': name = "\\mathbf{{{}}}".format(name) # glue all items together: if supers: name += "^{%s}" % " ".join(supers) if subs: name += "_{%s}" % " ".join(subs) return name def _print_Relational(self, expr): if self._settings['itex']: gt = r"\gt" lt = r"\lt" else: gt = ">" lt = "<" charmap = { "==": "=", ">": gt, "<": lt, ">=": r"\geq", "<=": r"\leq", "!=": r"\neq", } return "%s %s %s" % (self._print(expr.lhs), charmap[expr.rel_op], self._print(expr.rhs)) def _print_Piecewise(self, expr): ecpairs = [r"%s & \text{for}\: %s" % (self._print(e), self._print(c)) for e, c in expr.args[:-1]] if expr.args[-1].cond == true: ecpairs.append(r"%s & \text{otherwise}" % self._print(expr.args[-1].expr)) else: ecpairs.append(r"%s & \text{for}\: %s" % (self._print(expr.args[-1].expr), self._print(expr.args[-1].cond))) tex = r"\begin{cases} %s \end{cases}" return tex % r" \\".join(ecpairs) def _print_MatrixBase(self, expr): lines = [] for line in range(expr.rows): # horrible, should be 'rows' lines.append(" & ".join([self._print(i) for i in expr[line, :]])) mat_str = self._settings['mat_str'] if mat_str is None: if self._settings['mode'] == 'inline': mat_str = 'smallmatrix' else: if (expr.cols <= 10) is True: mat_str = 'matrix' else: mat_str = 'array' out_str = r'\begin{%MATSTR%}%s\end{%MATSTR%}' out_str = out_str.replace('%MATSTR%', mat_str) if mat_str == 'array': out_str = out_str.replace('%s', '{' + 'c'*expr.cols + '}%s') if self._settings['mat_delim']: left_delim = self._settings['mat_delim'] right_delim = self._delim_dict[left_delim] out_str = r'\left' + left_delim + out_str + \ r'\right' + right_delim return out_str % r"\\".join(lines) def _print_MatrixElement(self, expr): return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True)\ + '_{%s, %s}' % (self._print(expr.i), self._print(expr.j)) def _print_MatrixSlice(self, expr): def latexslice(x, dim): x = list(x) if x[2] == 1: del x[2] if x[0] == 0: x[0] = None if x[1] == dim: x[1] = None return ':'.join(self._print(xi) if xi is not None else '' for xi in x) return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + r'\left[' + latexslice(expr.rowslice, expr.parent.rows) + ', ' + latexslice(expr.colslice, expr.parent.cols) + r'\right]') def _print_BlockMatrix(self, expr): return self._print(expr.blocks) def _print_Transpose(self, expr): mat = expr.arg from sympy.matrices import MatrixSymbol if not isinstance(mat, MatrixSymbol): return r"\left(%s\right)^{T}" % self._print(mat) else: return "%s^{T}" % self.parenthesize(mat, precedence_traditional(expr), True) def _print_Trace(self, expr): mat = expr.arg return r"\operatorname{tr}\left(%s \right)" % self._print(mat) def _print_Adjoint(self, expr): mat = expr.arg from sympy.matrices import MatrixSymbol if not isinstance(mat, MatrixSymbol): return r"\left(%s\right)^{\dagger}" % self._print(mat) else: return r"%s^{\dagger}" % self._print(mat) def _print_MatMul(self, expr): from sympy import MatMul, Mul parens = lambda x: self.parenthesize(x, precedence_traditional(expr), False) args = expr.args if isinstance(args[0], Mul): args = args[0].as_ordered_factors() + list(args[1:]) else: args = list(args) if isinstance(expr, MatMul) and _coeff_isneg(expr): if args[0] == -1: args = args[1:] else: args[0] = -args[0] return '- ' + ' '.join(map(parens, args)) else: return ' '.join(map(parens, args)) def _print_Mod(self, expr, exp=None): if exp is not None: return r'\left(%s\bmod{%s}\right)^{%s}' % \ (self.parenthesize(expr.args[0], PRECEDENCE['Mul'], strict=True), self._print(expr.args[1]), exp) return r'%s\bmod{%s}' % (self.parenthesize(expr.args[0], PRECEDENCE['Mul'], strict=True), self._print(expr.args[1])) def _print_HadamardProduct(self, expr): args = expr.args prec = PRECEDENCE['Pow'] parens = self.parenthesize return r' \circ '.join( map(lambda arg: parens(arg, prec, strict=True), args)) def _print_HadamardPower(self, expr): if precedence_traditional(expr.exp) < PRECEDENCE["Mul"]: template = r"%s^{\circ \left({%s}\right)}" else: template = r"%s^{\circ {%s}}" return self._helper_print_standard_power(expr, template) def _print_KroneckerProduct(self, expr): args = expr.args prec = PRECEDENCE['Pow'] parens = self.parenthesize return r' \otimes '.join( map(lambda arg: parens(arg, prec, strict=True), args)) def _print_MatPow(self, expr): base, exp = expr.base, expr.exp from sympy.matrices import MatrixSymbol if not isinstance(base, MatrixSymbol): return "\\left(%s\\right)^{%s}" % (self._print(base), self._print(exp)) else: return "%s^{%s}" % (self._print(base), self._print(exp)) def _print_MatrixSymbol(self, expr): return self._print_Symbol(expr, style=self._settings[ 'mat_symbol_style']) def _print_ZeroMatrix(self, Z): return r"\mathbb{0}" if self._settings[ 'mat_symbol_style'] == 'plain' else r"\mathbf{0}" def _print_OneMatrix(self, O): return r"\mathbb{1}" if self._settings[ 'mat_symbol_style'] == 'plain' else r"\mathbf{1}" def _print_Identity(self, I): return r"\mathbb{I}" if self._settings[ 'mat_symbol_style'] == 'plain' else r"\mathbf{I}" def _print_PermutationMatrix(self, P): perm_str = self._print(P.args[0]) return "P_{%s}" % perm_str def _print_NDimArray(self, expr): if expr.rank() == 0: return self._print(expr[()]) mat_str = self._settings['mat_str'] if mat_str is None: if self._settings['mode'] == 'inline': mat_str = 'smallmatrix' else: if (expr.rank() == 0) or (expr.shape[-1] <= 10): mat_str = 'matrix' else: mat_str = 'array' block_str = r'\begin{%MATSTR%}%s\end{%MATSTR%}' block_str = block_str.replace('%MATSTR%', mat_str) if self._settings['mat_delim']: left_delim = self._settings['mat_delim'] right_delim = self._delim_dict[left_delim] block_str = r'\left' + left_delim + block_str + \ r'\right' + right_delim if expr.rank() == 0: return block_str % "" level_str = [[]] + [[] for i in range(expr.rank())] shape_ranges = [list(range(i)) for i in expr.shape] for outer_i in itertools.product(*shape_ranges): level_str[-1].append(self._print(expr[outer_i])) even = True for back_outer_i in range(expr.rank()-1, -1, -1): if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]: break if even: level_str[back_outer_i].append( r" & ".join(level_str[back_outer_i+1])) else: level_str[back_outer_i].append( block_str % (r"\\".join(level_str[back_outer_i+1]))) if len(level_str[back_outer_i+1]) == 1: level_str[back_outer_i][-1] = r"\left[" + \ level_str[back_outer_i][-1] + r"\right]" even = not even level_str[back_outer_i+1] = [] out_str = level_str[0][0] if expr.rank() % 2 == 1: out_str = block_str % out_str return out_str def _printer_tensor_indices(self, name, indices, index_map={}): out_str = self._print(name) last_valence = None prev_map = None for index in indices: new_valence = index.is_up if ((index in index_map) or prev_map) and \ last_valence == new_valence: out_str += "," if last_valence != new_valence: if last_valence is not None: out_str += "}" if index.is_up: out_str += "{}^{" else: out_str += "{}_{" out_str += self._print(index.args[0]) if index in index_map: out_str += "=" out_str += self._print(index_map[index]) prev_map = True else: prev_map = False last_valence = new_valence if last_valence is not None: out_str += "}" return out_str def _print_Tensor(self, expr): name = expr.args[0].args[0] indices = expr.get_indices() return self._printer_tensor_indices(name, indices) def _print_TensorElement(self, expr): name = expr.expr.args[0].args[0] indices = expr.expr.get_indices() index_map = expr.index_map return self._printer_tensor_indices(name, indices, index_map) def _print_TensMul(self, expr): # prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)" sign, args = expr._get_args_for_traditional_printer() return sign + "".join( [self.parenthesize(arg, precedence(expr)) for arg in args] ) def _print_TensAdd(self, expr): a = [] args = expr.args for x in args: a.append(self.parenthesize(x, precedence(expr))) a.sort() s = ' + '.join(a) s = s.replace('+ -', '- ') return s def _print_TensorIndex(self, expr): return "{}%s{%s}" % ( "^" if expr.is_up else "_", self._print(expr.args[0]) ) def _print_PartialDerivative(self, expr): if len(expr.variables) == 1: return r"\frac{\partial}{\partial {%s}}{%s}" % ( self._print(expr.variables[0]), self.parenthesize(expr.expr, PRECEDENCE["Mul"], False) ) else: return r"\frac{\partial^{%s}}{%s}{%s}" % ( len(expr.variables), " ".join([r"\partial {%s}" % self._print(i) for i in expr.variables]), self.parenthesize(expr.expr, PRECEDENCE["Mul"], False) ) def _print_ArraySymbol(self, expr): return self._print(expr.name) def _print_ArrayElement(self, expr): return "{{%s}_{%s}}" % (expr.name, ", ".join([f"{self._print(i)}" for i in expr.indices])) def _print_UniversalSet(self, expr): return r"\mathbb{U}" def _print_frac(self, expr, exp=None): if exp is None: return r"\operatorname{frac}{\left(%s\right)}" % self._print(expr.args[0]) else: return r"\operatorname{frac}{\left(%s\right)}^{%s}" % ( self._print(expr.args[0]), exp) def _print_tuple(self, expr): if self._settings['decimal_separator'] == 'comma': sep = ";" elif self._settings['decimal_separator'] == 'period': sep = "," else: raise ValueError('Unknown Decimal Separator') if len(expr) == 1: # 1-tuple needs a trailing separator return self._add_parens_lspace(self._print(expr[0]) + sep) else: return self._add_parens_lspace( (sep + r" \ ").join([self._print(i) for i in expr])) def _print_TensorProduct(self, expr): elements = [self._print(a) for a in expr.args] return r' \otimes '.join(elements) def _print_WedgeProduct(self, expr): elements = [self._print(a) for a in expr.args] return r' \wedge '.join(elements) def _print_Tuple(self, expr): return self._print_tuple(expr) def _print_list(self, expr): if self._settings['decimal_separator'] == 'comma': return r"\left[ %s\right]" % \ r"; \ ".join([self._print(i) for i in expr]) elif self._settings['decimal_separator'] == 'period': return r"\left[ %s\right]" % \ r", \ ".join([self._print(i) for i in expr]) else: raise ValueError('Unknown Decimal Separator') def _print_dict(self, d): keys = sorted(d.keys(), key=default_sort_key) items = [] for key in keys: val = d[key] items.append("%s : %s" % (self._print(key), self._print(val))) return r"\left\{ %s\right\}" % r", \ ".join(items) def _print_Dict(self, expr): return self._print_dict(expr) def _print_DiracDelta(self, expr, exp=None): if len(expr.args) == 1 or expr.args[1] == 0: tex = r"\delta\left(%s\right)" % self._print(expr.args[0]) else: tex = r"\delta^{\left( %s \right)}\left( %s \right)" % ( self._print(expr.args[1]), self._print(expr.args[0])) if exp: tex = r"\left(%s\right)^{%s}" % (tex, exp) return tex def _print_SingularityFunction(self, expr, exp=None): shift = self._print(expr.args[0] - expr.args[1]) power = self._print(expr.args[2]) tex = r"{\left\langle %s \right\rangle}^{%s}" % (shift, power) if exp is not None: tex = r"{\left({\langle %s \rangle}^{%s}\right)}^{%s}" % (shift, power, exp) return tex def _print_Heaviside(self, expr, exp=None): pargs = ', '.join(self._print(arg) for arg in expr.pargs) tex = r"\theta\left(%s\right)" % pargs if exp: tex = r"\left(%s\right)^{%s}" % (tex, exp) return tex def _print_KroneckerDelta(self, expr, exp=None): i = self._print(expr.args[0]) j = self._print(expr.args[1]) if expr.args[0].is_Atom and expr.args[1].is_Atom: tex = r'\delta_{%s %s}' % (i, j) else: tex = r'\delta_{%s, %s}' % (i, j) if exp is not None: tex = r'\left(%s\right)^{%s}' % (tex, exp) return tex def _print_LeviCivita(self, expr, exp=None): indices = map(self._print, expr.args) if all(x.is_Atom for x in expr.args): tex = r'\varepsilon_{%s}' % " ".join(indices) else: tex = r'\varepsilon_{%s}' % ", ".join(indices) if exp: tex = r'\left(%s\right)^{%s}' % (tex, exp) return tex def _print_RandomDomain(self, d): if hasattr(d, 'as_boolean'): return '\\text{Domain: }' + self._print(d.as_boolean()) elif hasattr(d, 'set'): return ('\\text{Domain: }' + self._print(d.symbols) + '\\text{ in }' + self._print(d.set)) elif hasattr(d, 'symbols'): return '\\text{Domain on }' + self._print(d.symbols) else: return self._print(None) def _print_FiniteSet(self, s): items = sorted(s.args, key=default_sort_key) return self._print_set(items) def _print_set(self, s): items = sorted(s, key=default_sort_key) if self._settings['decimal_separator'] == 'comma': items = "; ".join(map(self._print, items)) elif self._settings['decimal_separator'] == 'period': items = ", ".join(map(self._print, items)) else: raise ValueError('Unknown Decimal Separator') return r"\left\{%s\right\}" % items _print_frozenset = _print_set def _print_Range(self, s): dots = object() if s.has(Symbol): return self._print_Basic(s) if s.start.is_infinite and s.stop.is_infinite: if s.step.is_positive: printset = dots, -1, 0, 1, dots else: printset = dots, 1, 0, -1, dots elif s.start.is_infinite: printset = dots, s[-1] - s.step, s[-1] elif s.stop.is_infinite: it = iter(s) printset = next(it), next(it), dots elif len(s) > 4: it = iter(s) printset = next(it), next(it), dots, s[-1] else: printset = tuple(s) return (r"\left\{" + r", ".join(self._print(el) if el is not dots else r'\ldots' for el in printset) + r"\right\}") def __print_number_polynomial(self, expr, letter, exp=None): if len(expr.args) == 2: if exp is not None: return r"%s_{%s}^{%s}\left(%s\right)" % (letter, self._print(expr.args[0]), exp, self._print(expr.args[1])) return r"%s_{%s}\left(%s\right)" % (letter, self._print(expr.args[0]), self._print(expr.args[1])) tex = r"%s_{%s}" % (letter, self._print(expr.args[0])) if exp is not None: tex = r"%s^{%s}" % (tex, exp) return tex def _print_bernoulli(self, expr, exp=None): return self.__print_number_polynomial(expr, "B", exp) def _print_bell(self, expr, exp=None): if len(expr.args) == 3: tex1 = r"B_{%s, %s}" % (self._print(expr.args[0]), self._print(expr.args[1])) tex2 = r"\left(%s\right)" % r", ".join(self._print(el) for el in expr.args[2]) if exp is not None: tex = r"%s^{%s}%s" % (tex1, exp, tex2) else: tex = tex1 + tex2 return tex return self.__print_number_polynomial(expr, "B", exp) def _print_fibonacci(self, expr, exp=None): return self.__print_number_polynomial(expr, "F", exp) def _print_lucas(self, expr, exp=None): tex = r"L_{%s}" % self._print(expr.args[0]) if exp is not None: tex = r"%s^{%s}" % (tex, exp) return tex def _print_tribonacci(self, expr, exp=None): return self.__print_number_polynomial(expr, "T", exp) def _print_SeqFormula(self, s): dots = object() if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0: return r"\left\{%s\right\}_{%s=%s}^{%s}" % ( self._print(s.formula), self._print(s.variables[0]), self._print(s.start), self._print(s.stop) ) if s.start is S.NegativeInfinity: stop = s.stop printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2), s.coeff(stop - 1), s.coeff(stop)) elif s.stop is S.Infinity or s.length > 4: printset = s[:4] printset.append(dots) else: printset = tuple(s) return (r"\left[" + r", ".join(self._print(el) if el is not dots else r'\ldots' for el in printset) + r"\right]") _print_SeqPer = _print_SeqFormula _print_SeqAdd = _print_SeqFormula _print_SeqMul = _print_SeqFormula def _print_Interval(self, i): if i.start == i.end: return r"\left\{%s\right\}" % self._print(i.start) else: if i.left_open: left = '(' else: left = '[' if i.right_open: right = ')' else: right = ']' return r"\left%s%s, %s\right%s" % \ (left, self._print(i.start), self._print(i.end), right) def _print_AccumulationBounds(self, i): return r"\left\langle %s, %s\right\rangle" % \ (self._print(i.min), self._print(i.max)) def _print_Union(self, u): prec = precedence_traditional(u) args_str = [self.parenthesize(i, prec) for i in u.args] return r" \cup ".join(args_str) def _print_Complement(self, u): prec = precedence_traditional(u) args_str = [self.parenthesize(i, prec) for i in u.args] return r" \setminus ".join(args_str) def _print_Intersection(self, u): prec = precedence_traditional(u) args_str = [self.parenthesize(i, prec) for i in u.args] return r" \cap ".join(args_str) def _print_SymmetricDifference(self, u): prec = precedence_traditional(u) args_str = [self.parenthesize(i, prec) for i in u.args] return r" \triangle ".join(args_str) def _print_ProductSet(self, p): prec = precedence_traditional(p) if len(p.sets) >= 1 and not has_variety(p.sets): return self.parenthesize(p.sets[0], prec) + "^{%d}" % len(p.sets) return r" \times ".join( self.parenthesize(set, prec) for set in p.sets) def _print_EmptySet(self, e): return r"\emptyset" def _print_Naturals(self, n): return r"\mathbb{N}" def _print_Naturals0(self, n): return r"\mathbb{N}_0" def _print_Integers(self, i): return r"\mathbb{Z}" def _print_Rationals(self, i): return r"\mathbb{Q}" def _print_Reals(self, i): return r"\mathbb{R}" def _print_Complexes(self, i): return r"\mathbb{C}" def _print_ImageSet(self, s): expr = s.lamda.expr sig = s.lamda.signature xys = ((self._print(x), self._print(y)) for x, y in zip(sig, s.base_sets)) xinys = r" , ".join(r"%s \in %s" % xy for xy in xys) return r"\left\{%s\; \middle|\; %s\right\}" % (self._print(expr), xinys) def _print_ConditionSet(self, s): vars_print = ', '.join([self._print(var) for var in Tuple(s.sym)]) if s.base_set is S.UniversalSet: return r"\left\{%s\; \middle|\; %s \right\}" % \ (vars_print, self._print(s.condition)) return r"\left\{%s\; \middle|\; %s \in %s \wedge %s \right\}" % ( vars_print, vars_print, self._print(s.base_set), self._print(s.condition)) def _print_ComplexRegion(self, s): vars_print = ', '.join([self._print(var) for var in s.variables]) return r"\left\{%s\; \middle|\; %s \in %s \right\}" % ( self._print(s.expr), vars_print, self._print(s.sets)) def _print_Contains(self, e): return r"%s \in %s" % tuple(self._print(a) for a in e.args) def _print_FourierSeries(self, s): return self._print_Add(s.truncate()) + r' + \ldots' def _print_FormalPowerSeries(self, s): return self._print_Add(s.infinite) def _print_FiniteField(self, expr): return r"\mathbb{F}_{%s}" % expr.mod def _print_IntegerRing(self, expr): return r"\mathbb{Z}" def _print_RationalField(self, expr): return r"\mathbb{Q}" def _print_RealField(self, expr): return r"\mathbb{R}" def _print_ComplexField(self, expr): return r"\mathbb{C}" def _print_PolynomialRing(self, expr): domain = self._print(expr.domain) symbols = ", ".join(map(self._print, expr.symbols)) return r"%s\left[%s\right]" % (domain, symbols) def _print_FractionField(self, expr): domain = self._print(expr.domain) symbols = ", ".join(map(self._print, expr.symbols)) return r"%s\left(%s\right)" % (domain, symbols) def _print_PolynomialRingBase(self, expr): domain = self._print(expr.domain) symbols = ", ".join(map(self._print, expr.symbols)) inv = "" if not expr.is_Poly: inv = r"S_<^{-1}" return r"%s%s\left[%s\right]" % (inv, domain, symbols) def _print_Poly(self, poly): cls = poly.__class__.__name__ terms = [] for monom, coeff in poly.terms(): s_monom = '' for i, exp in enumerate(monom): if exp > 0: if exp == 1: s_monom += self._print(poly.gens[i]) else: s_monom += self._print(pow(poly.gens[i], exp)) if coeff.is_Add: if s_monom: s_coeff = r"\left(%s\right)" % self._print(coeff) else: s_coeff = self._print(coeff) else: if s_monom: if coeff is S.One: terms.extend(['+', s_monom]) continue if coeff is S.NegativeOne: terms.extend(['-', s_monom]) continue s_coeff = self._print(coeff) if not s_monom: s_term = s_coeff else: s_term = s_coeff + " " + s_monom if s_term.startswith('-'): terms.extend(['-', s_term[1:]]) else: terms.extend(['+', s_term]) if terms[0] in ['-', '+']: modifier = terms.pop(0) if modifier == '-': terms[0] = '-' + terms[0] expr = ' '.join(terms) gens = list(map(self._print, poly.gens)) domain = "domain=%s" % self._print(poly.get_domain()) args = ", ".join([expr] + gens + [domain]) if cls in accepted_latex_functions: tex = r"\%s {\left(%s \right)}" % (cls, args) else: tex = r"\operatorname{%s}{\left( %s \right)}" % (cls, args) return tex def _print_ComplexRootOf(self, root): cls = root.__class__.__name__ if cls == "ComplexRootOf": cls = "CRootOf" expr = self._print(root.expr) index = root.index if cls in accepted_latex_functions: return r"\%s {\left(%s, %d\right)}" % (cls, expr, index) else: return r"\operatorname{%s} {\left(%s, %d\right)}" % (cls, expr, index) def _print_RootSum(self, expr): cls = expr.__class__.__name__ args = [self._print(expr.expr)] if expr.fun is not S.IdentityFunction: args.append(self._print(expr.fun)) if cls in accepted_latex_functions: return r"\%s {\left(%s\right)}" % (cls, ", ".join(args)) else: return r"\operatorname{%s} {\left(%s\right)}" % (cls, ", ".join(args)) def _print_PolyElement(self, poly): mul_symbol = self._settings['mul_symbol_latex'] return poly.str(self, PRECEDENCE, "{%s}^{%d}", mul_symbol) def _print_FracElement(self, frac): if frac.denom == 1: return self._print(frac.numer) else: numer = self._print(frac.numer) denom = self._print(frac.denom) return r"\frac{%s}{%s}" % (numer, denom) def _print_euler(self, expr, exp=None): m, x = (expr.args[0], None) if len(expr.args) == 1 else expr.args tex = r"E_{%s}" % self._print(m) if exp is not None: tex = r"%s^{%s}" % (tex, exp) if x is not None: tex = r"%s\left(%s\right)" % (tex, self._print(x)) return tex def _print_catalan(self, expr, exp=None): tex = r"C_{%s}" % self._print(expr.args[0]) if exp is not None: tex = r"%s^{%s}" % (tex, exp) return tex def _print_UnifiedTransform(self, expr, s, inverse=False): return r"\mathcal{{{}}}{}_{{{}}}\left[{}\right]\left({}\right)".format(s, '^{-1}' if inverse else '', self._print(expr.args[1]), self._print(expr.args[0]), self._print(expr.args[2])) def _print_MellinTransform(self, expr): return self._print_UnifiedTransform(expr, 'M') def _print_InverseMellinTransform(self, expr): return self._print_UnifiedTransform(expr, 'M', True) def _print_LaplaceTransform(self, expr): return self._print_UnifiedTransform(expr, 'L') def _print_InverseLaplaceTransform(self, expr): return self._print_UnifiedTransform(expr, 'L', True) def _print_FourierTransform(self, expr): return self._print_UnifiedTransform(expr, 'F') def _print_InverseFourierTransform(self, expr): return self._print_UnifiedTransform(expr, 'F', True) def _print_SineTransform(self, expr): return self._print_UnifiedTransform(expr, 'SIN') def _print_InverseSineTransform(self, expr): return self._print_UnifiedTransform(expr, 'SIN', True) def _print_CosineTransform(self, expr): return self._print_UnifiedTransform(expr, 'COS') def _print_InverseCosineTransform(self, expr): return self._print_UnifiedTransform(expr, 'COS', True) def _print_DMP(self, p): try: if p.ring is not None: # TODO incorporate order return self._print(p.ring.to_sympy(p)) except SympifyError: pass return self._print(repr(p)) def _print_DMF(self, p): return self._print_DMP(p) def _print_Object(self, object): return self._print(Symbol(object.name)) def _print_LambertW(self, expr, exp=None): arg0 = self._print(expr.args[0]) exp = r"^{%s}" % (exp,) if exp is not None else "" if len(expr.args) == 1: result = r"W%s\left(%s\right)" % (exp, arg0) else: arg1 = self._print(expr.args[1]) result = "W{0}_{{{1}}}\\left({2}\\right)".format(exp, arg1, arg0) return result def _print_Morphism(self, morphism): domain = self._print(morphism.domain) codomain = self._print(morphism.codomain) return "%s\\rightarrow %s" % (domain, codomain) def _print_TransferFunction(self, expr): num, den = self._print(expr.num), self._print(expr.den) return r"\frac{%s}{%s}" % (num, den) def _print_Series(self, expr): args = list(expr.args) parens = lambda x: self.parenthesize(x, precedence_traditional(expr), False) return ' '.join(map(parens, args)) def _print_MIMOSeries(self, expr): from sympy.physics.control.lti import MIMOParallel args = list(expr.args)[::-1] parens = lambda x: self.parenthesize(x, precedence_traditional(expr), False) if isinstance(x, MIMOParallel) else self._print(x) return r"\cdot".join(map(parens, args)) def _print_Parallel(self, expr): args = list(expr.args) func = lambda x: self._print(x) return ' + '.join(map(func, args)) def _print_MIMOParallel(self, expr): args = list(expr.args) func = lambda x: self._print(x) return ' + '.join(map(func, args)) def _print_Feedback(self, expr): from sympy.physics.control import TransferFunction, Series num, tf = expr.sys1, TransferFunction(1, 1, expr.var) num_arg_list = list(num.args) if isinstance(num, Series) else [num] den_arg_list = list(expr.sys2.args) if \ isinstance(expr.sys2, Series) else [expr.sys2] den_term_1 = tf if isinstance(num, Series) and isinstance(expr.sys2, Series): den_term_2 = Series(*num_arg_list, *den_arg_list) elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction): if expr.sys2 == tf: den_term_2 = Series(*num_arg_list) else: den_term_2 = tf, Series(*num_arg_list, expr.sys2) elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series): if num == tf: den_term_2 = Series(*den_arg_list) else: den_term_2 = Series(num, *den_arg_list) else: if num == tf: den_term_2 = Series(*den_arg_list) elif expr.sys2 == tf: den_term_2 = Series(*num_arg_list) else: den_term_2 = Series(*num_arg_list, *den_arg_list) numer = self._print(num) denom_1 = self._print(den_term_1) denom_2 = self._print(den_term_2) _sign = "+" if expr.sign == -1 else "-" return r"\frac{%s}{%s %s %s}" % (numer, denom_1, _sign, denom_2) def _print_MIMOFeedback(self, expr): from sympy.physics.control import MIMOSeries inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1)) sys1 = self._print(expr.sys1) _sign = "+" if expr.sign == -1 else "-" return r"\left(I_{\tau} %s %s\right)^{-1} \cdot %s" % (_sign, inv_mat, sys1) def _print_TransferFunctionMatrix(self, expr): mat = self._print(expr._expr_mat) return r"%s_\tau" % mat def _print_NamedMorphism(self, morphism): pretty_name = self._print(Symbol(morphism.name)) pretty_morphism = self._print_Morphism(morphism) return "%s:%s" % (pretty_name, pretty_morphism) def _print_IdentityMorphism(self, morphism): from sympy.categories import NamedMorphism return self._print_NamedMorphism(NamedMorphism( morphism.domain, morphism.codomain, "id")) def _print_CompositeMorphism(self, morphism): # All components of the morphism have names and it is thus # possible to build the name of the composite. component_names_list = [self._print(Symbol(component.name)) for component in morphism.components] component_names_list.reverse() component_names = "\\circ ".join(component_names_list) + ":" pretty_morphism = self._print_Morphism(morphism) return component_names + pretty_morphism def _print_Category(self, morphism): return r"\mathbf{{{}}}".format(self._print(Symbol(morphism.name))) def _print_Diagram(self, diagram): if not diagram.premises: # This is an empty diagram. return self._print(S.EmptySet) latex_result = self._print(diagram.premises) if diagram.conclusions: latex_result += "\\Longrightarrow %s" % \ self._print(diagram.conclusions) return latex_result def _print_DiagramGrid(self, grid): latex_result = "\\begin{array}{%s}\n" % ("c" * grid.width) for i in range(grid.height): for j in range(grid.width): if grid[i, j]: latex_result += latex(grid[i, j]) latex_result += " " if j != grid.width - 1: latex_result += "& " if i != grid.height - 1: latex_result += "\\\\" latex_result += "\n" latex_result += "\\end{array}\n" return latex_result def _print_FreeModule(self, M): return '{{{}}}^{{{}}}'.format(self._print(M.ring), self._print(M.rank)) def _print_FreeModuleElement(self, m): # Print as row vector for convenience, for now. return r"\left[ {} \right]".format(",".join( '{' + self._print(x) + '}' for x in m)) def _print_SubModule(self, m): return r"\left\langle {} \right\rangle".format(",".join( '{' + self._print(x) + '}' for x in m.gens)) def _print_ModuleImplementedIdeal(self, m): return r"\left\langle {} \right\rangle".format(",".join( '{' + self._print(x) + '}' for [x] in m._module.gens)) def _print_Quaternion(self, expr): # TODO: This expression is potentially confusing, # shall we print it as `Quaternion( ... )`? s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) for i in expr.args] a = [s[0]] + [i+" "+j for i, j in zip(s[1:], "ijk")] return " + ".join(a) def _print_QuotientRing(self, R): # TODO nicer fractions for few generators... return r"\frac{{{}}}{{{}}}".format(self._print(R.ring), self._print(R.base_ideal)) def _print_QuotientRingElement(self, x): return r"{{{}}} + {{{}}}".format(self._print(x.data), self._print(x.ring.base_ideal)) def _print_QuotientModuleElement(self, m): return r"{{{}}} + {{{}}}".format(self._print(m.data), self._print(m.module.killed_module)) def _print_QuotientModule(self, M): # TODO nicer fractions for few generators... return r"\frac{{{}}}{{{}}}".format(self._print(M.base), self._print(M.killed_module)) def _print_MatrixHomomorphism(self, h): return r"{{{}}} : {{{}}} \to {{{}}}".format(self._print(h._sympy_matrix()), self._print(h.domain), self._print(h.codomain)) def _print_Manifold(self, manifold): string = manifold.name.name if '{' in string: name, supers, subs = string, [], [] else: name, supers, subs = split_super_sub(string) name = translate(name) supers = [translate(sup) for sup in supers] subs = [translate(sub) for sub in subs] name = r'\text{%s}' % name if supers: name += "^{%s}" % " ".join(supers) if subs: name += "_{%s}" % " ".join(subs) return name def _print_Patch(self, patch): return r'\text{%s}_{%s}' % (self._print(patch.name), self._print(patch.manifold)) def _print_CoordSystem(self, coordsys): return r'\text{%s}^{\text{%s}}_{%s}' % ( self._print(coordsys.name), self._print(coordsys.patch.name), self._print(coordsys.manifold) ) def _print_CovarDerivativeOp(self, cvd): return r'\mathbb{\nabla}_{%s}' % self._print(cvd._wrt) def _print_BaseScalarField(self, field): string = field._coord_sys.symbols[field._index].name return r'\mathbf{{{}}}'.format(self._print(Symbol(string))) def _print_BaseVectorField(self, field): string = field._coord_sys.symbols[field._index].name return r'\partial_{{{}}}'.format(self._print(Symbol(string))) def _print_Differential(self, diff): field = diff._form_field if hasattr(field, '_coord_sys'): string = field._coord_sys.symbols[field._index].name return r'\operatorname{{d}}{}'.format(self._print(Symbol(string))) else: string = self._print(field) return r'\operatorname{{d}}\left({}\right)'.format(string) def _print_Tr(self, p): # TODO: Handle indices contents = self._print(p.args[0]) return r'\operatorname{{tr}}\left({}\right)'.format(contents) def _print_totient(self, expr, exp=None): if exp is not None: return r'\left(\phi\left(%s\right)\right)^{%s}' % \ (self._print(expr.args[0]), exp) return r'\phi\left(%s\right)' % self._print(expr.args[0]) def _print_reduced_totient(self, expr, exp=None): if exp is not None: return r'\left(\lambda\left(%s\right)\right)^{%s}' % \ (self._print(expr.args[0]), exp) return r'\lambda\left(%s\right)' % self._print(expr.args[0]) def _print_divisor_sigma(self, expr, exp=None): if len(expr.args) == 2: tex = r"_%s\left(%s\right)" % tuple(map(self._print, (expr.args[1], expr.args[0]))) else: tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\sigma^{%s}%s" % (exp, tex) return r"\sigma%s" % tex def _print_udivisor_sigma(self, expr, exp=None): if len(expr.args) == 2: tex = r"_%s\left(%s\right)" % tuple(map(self._print, (expr.args[1], expr.args[0]))) else: tex = r"\left(%s\right)" % self._print(expr.args[0]) if exp is not None: return r"\sigma^*^{%s}%s" % (exp, tex) return r"\sigma^*%s" % tex def _print_primenu(self, expr, exp=None): if exp is not None: return r'\left(\nu\left(%s\right)\right)^{%s}' % \ (self._print(expr.args[0]), exp) return r'\nu\left(%s\right)' % self._print(expr.args[0]) def _print_primeomega(self, expr, exp=None): if exp is not None: return r'\left(\Omega\left(%s\right)\right)^{%s}' % \ (self._print(expr.args[0]), exp) return r'\Omega\left(%s\right)' % self._print(expr.args[0]) def _print_Str(self, s): return str(s.name) def _print_float(self, expr): return self._print(Float(expr)) def _print_int(self, expr): return str(expr) def _print_mpz(self, expr): return str(expr) def _print_mpq(self, expr): return str(expr) def _print_Predicate(self, expr): return str(expr) def _print_AppliedPredicate(self, expr): pred = expr.function args = expr.arguments pred_latex = self._print(pred) args_latex = ', '.join([self._print(a) for a in args]) return '%s(%s)' % (pred_latex, args_latex) def emptyPrinter(self, expr): # default to just printing as monospace, like would normally be shown s = super().emptyPrinter(expr) return r"\mathtt{\text{%s}}" % latex_escape(s) def translate(s): r''' Check for a modifier ending the string. If present, convert the modifier to latex and translate the rest recursively. Given a description of a Greek letter or other special character, return the appropriate latex. Let everything else pass as given. >>> from sympy.printing.latex import translate >>> translate('alphahatdotprime') "{\\dot{\\hat{\\alpha}}}'" ''' # Process the rest tex = tex_greek_dictionary.get(s) if tex: return tex elif s.lower() in greek_letters_set: return "\\" + s.lower() elif s in other_symbols: return "\\" + s else: # Process modifiers, if any, and recurse for key in sorted(modifier_dict.keys(), key=lambda k:len(k), reverse=True): if s.lower().endswith(key) and len(s) > len(key): return modifier_dict[key](translate(s[:-len(key)])) return s @print_function(LatexPrinter) def latex(expr, **settings): r"""Convert the given expression to LaTeX string representation. Parameters ========== full_prec: boolean, optional If set to True, a floating point number is printed with full precision. fold_frac_powers : boolean, optional Emit ``^{p/q}`` instead of ``^{\frac{p}{q}}`` for fractional powers. fold_func_brackets : boolean, optional Fold function brackets where applicable. fold_short_frac : boolean, optional Emit ``p / q`` instead of ``\frac{p}{q}`` when the denominator is simple enough (at most two terms and no powers). The default value is ``True`` for inline mode, ``False`` otherwise. inv_trig_style : string, optional How inverse trig functions should be displayed. Can be one of ``abbreviated``, ``full``, or ``power``. Defaults to ``abbreviated``. itex : boolean, optional Specifies if itex-specific syntax is used, including emitting ``$$...$$``. ln_notation : boolean, optional If set to ``True``, ``\ln`` is used instead of default ``\log``. long_frac_ratio : float or None, optional The allowed ratio of the width of the numerator to the width of the denominator before the printer breaks off long fractions. If ``None`` (the default value), long fractions are not broken up. mat_delim : string, optional The delimiter to wrap around matrices. Can be one of ``[``, ``(``, or the empty string. Defaults to ``[``. mat_str : string, optional Which matrix environment string to emit. ``smallmatrix``, ``matrix``, ``array``, etc. Defaults to ``smallmatrix`` for inline mode, ``matrix`` for matrices of no more than 10 columns, and ``array`` otherwise. mode: string, optional Specifies how the generated code will be delimited. ``mode`` can be one of ``plain``, ``inline``, ``equation`` or ``equation*``. If ``mode`` is set to ``plain``, then the resulting code will not be delimited at all (this is the default). If ``mode`` is set to ``inline`` then inline LaTeX ``$...$`` will be used. If ``mode`` is set to ``equation`` or ``equation*``, the resulting code will be enclosed in the ``equation`` or ``equation*`` environment (remember to import ``amsmath`` for ``equation*``), unless the ``itex`` option is set. In the latter case, the ``$$...$$`` syntax is used. mul_symbol : string or None, optional The symbol to use for multiplication. Can be one of ``None``, ``ldot``, ``dot``, or ``times``. order: string, optional Any of the supported monomial orderings (currently ``lex``, ``grlex``, or ``grevlex``), ``old``, and ``none``. This parameter does nothing for Mul objects. Setting order to ``old`` uses the compatibility ordering for Add defined in Printer. For very large expressions, set the ``order`` keyword to ``none`` if speed is a concern. symbol_names : dictionary of strings mapped to symbols, optional Dictionary of symbols and the custom strings they should be emitted as. root_notation : boolean, optional If set to ``False``, exponents of the form 1/n are printed in fractonal form. Default is ``True``, to print exponent in root form. mat_symbol_style : string, optional Can be either ``plain`` (default) or ``bold``. If set to ``bold``, a MatrixSymbol A will be printed as ``\mathbf{A}``, otherwise as ``A``. imaginary_unit : string, optional String to use for the imaginary unit. Defined options are "i" (default) and "j". Adding "r" or "t" in front gives ``\mathrm`` or ``\text``, so "ri" leads to ``\mathrm{i}`` which gives `\mathrm{i}`. gothic_re_im : boolean, optional If set to ``True``, `\Re` and `\Im` is used for ``re`` and ``im``, respectively. The default is ``False`` leading to `\operatorname{re}` and `\operatorname{im}`. decimal_separator : string, optional Specifies what separator to use to separate the whole and fractional parts of a floating point number as in `2.5` for the default, ``period`` or `2{,}5` when ``comma`` is specified. Lists, sets, and tuple are printed with semicolon separating the elements when ``comma`` is chosen. For example, [1; 2; 3] when ``comma`` is chosen and [1,2,3] for when ``period`` is chosen. parenthesize_super : boolean, optional If set to ``False``, superscripted expressions will not be parenthesized when powered. Default is ``True``, which parenthesizes the expression when powered. min: Integer or None, optional Sets the lower bound for the exponent to print floating point numbers in fixed-point format. max: Integer or None, optional Sets the upper bound for the exponent to print floating point numbers in fixed-point format. Notes ===== Not using a print statement for printing, results in double backslashes for latex commands since that's the way Python escapes backslashes in strings. >>> from sympy import latex, Rational >>> from sympy.abc import tau >>> latex((2*tau)**Rational(7,2)) '8 \\sqrt{2} \\tau^{\\frac{7}{2}}' >>> print(latex((2*tau)**Rational(7,2))) 8 \sqrt{2} \tau^{\frac{7}{2}} Examples ======== >>> from sympy import latex, pi, sin, asin, Integral, Matrix, Rational, log >>> from sympy.abc import x, y, mu, r, tau Basic usage: >>> print(latex((2*tau)**Rational(7,2))) 8 \sqrt{2} \tau^{\frac{7}{2}} ``mode`` and ``itex`` options: >>> print(latex((2*mu)**Rational(7,2), mode='plain')) 8 \sqrt{2} \mu^{\frac{7}{2}} >>> print(latex((2*tau)**Rational(7,2), mode='inline')) $8 \sqrt{2} \tau^{7 / 2}$ >>> print(latex((2*mu)**Rational(7,2), mode='equation*')) \begin{equation*}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation*} >>> print(latex((2*mu)**Rational(7,2), mode='equation')) \begin{equation}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation} >>> print(latex((2*mu)**Rational(7,2), mode='equation', itex=True)) $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ >>> print(latex((2*mu)**Rational(7,2), mode='plain')) 8 \sqrt{2} \mu^{\frac{7}{2}} >>> print(latex((2*tau)**Rational(7,2), mode='inline')) $8 \sqrt{2} \tau^{7 / 2}$ >>> print(latex((2*mu)**Rational(7,2), mode='equation*')) \begin{equation*}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation*} >>> print(latex((2*mu)**Rational(7,2), mode='equation')) \begin{equation}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation} >>> print(latex((2*mu)**Rational(7,2), mode='equation', itex=True)) $$8 \sqrt{2} \mu^{\frac{7}{2}}$$ Fraction options: >>> print(latex((2*tau)**Rational(7,2), fold_frac_powers=True)) 8 \sqrt{2} \tau^{7/2} >>> print(latex((2*tau)**sin(Rational(7,2)))) \left(2 \tau\right)^{\sin{\left(\frac{7}{2} \right)}} >>> print(latex((2*tau)**sin(Rational(7,2)), fold_func_brackets=True)) \left(2 \tau\right)^{\sin {\frac{7}{2}}} >>> print(latex(3*x**2/y)) \frac{3 x^{2}}{y} >>> print(latex(3*x**2/y, fold_short_frac=True)) 3 x^{2} / y >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=2)) \frac{\int r\, dr}{2 \pi} >>> print(latex(Integral(r, r)/2/pi, long_frac_ratio=0)) \frac{1}{2 \pi} \int r\, dr Multiplication options: >>> print(latex((2*tau)**sin(Rational(7,2)), mul_symbol="times")) \left(2 \times \tau\right)^{\sin{\left(\frac{7}{2} \right)}} Trig options: >>> print(latex(asin(Rational(7,2)))) \operatorname{asin}{\left(\frac{7}{2} \right)} >>> print(latex(asin(Rational(7,2)), inv_trig_style="full")) \arcsin{\left(\frac{7}{2} \right)} >>> print(latex(asin(Rational(7,2)), inv_trig_style="power")) \sin^{-1}{\left(\frac{7}{2} \right)} Matrix options: >>> print(latex(Matrix(2, 1, [x, y]))) \left[\begin{matrix}x\\y\end{matrix}\right] >>> print(latex(Matrix(2, 1, [x, y]), mat_str = "array")) \left[\begin{array}{c}x\\y\end{array}\right] >>> print(latex(Matrix(2, 1, [x, y]), mat_delim="(")) \left(\begin{matrix}x\\y\end{matrix}\right) Custom printing of symbols: >>> print(latex(x**2, symbol_names={x: 'x_i'})) x_i^{2} Logarithms: >>> print(latex(log(10))) \log{\left(10 \right)} >>> print(latex(log(10), ln_notation=True)) \ln{\left(10 \right)} ``latex()`` also supports the builtin container types :class:`list`, :class:`tuple`, and :class:`dict`: >>> print(latex([2/x, y], mode='inline')) $\left[ 2 / x, \ y\right]$ Unsupported types are rendered as monospaced plaintext: >>> print(latex(int)) \mathtt{\text{}} >>> print(latex("plain % text")) \mathtt{\text{plain \% text}} See :ref:`printer_method_example` for an example of how to override this behavior for your own types by implementing ``_latex``. .. versionchanged:: 1.7.0 Unsupported types no longer have their ``str`` representation treated as valid latex. """ return LatexPrinter(settings).doprint(expr) def print_latex(expr, **settings): """Prints LaTeX representation of the given expression. Takes the same settings as ``latex()``.""" print(latex(expr, **settings)) def multiline_latex(lhs, rhs, terms_per_line=1, environment="align*", use_dots=False, **settings): r""" This function generates a LaTeX equation with a multiline right-hand side in an ``align*``, ``eqnarray`` or ``IEEEeqnarray`` environment. Parameters ========== lhs : Expr Left-hand side of equation rhs : Expr Right-hand side of equation terms_per_line : integer, optional Number of terms per line to print. Default is 1. environment : "string", optional Which LaTeX wnvironment to use for the output. Options are "align*" (default), "eqnarray", and "IEEEeqnarray". use_dots : boolean, optional If ``True``, ``\\dots`` is added to the end of each line. Default is ``False``. Examples ======== >>> from sympy import multiline_latex, symbols, sin, cos, exp, log, I >>> x, y, alpha = symbols('x y alpha') >>> expr = sin(alpha*y) + exp(I*alpha) - cos(log(y)) >>> print(multiline_latex(x, expr)) \begin{align*} x = & e^{i \alpha} \\ & + \sin{\left(\alpha y \right)} \\ & - \cos{\left(\log{\left(y \right)} \right)} \end{align*} Using at most two terms per line: >>> print(multiline_latex(x, expr, 2)) \begin{align*} x = & e^{i \alpha} + \sin{\left(\alpha y \right)} \\ & - \cos{\left(\log{\left(y \right)} \right)} \end{align*} Using ``eqnarray`` and dots: >>> print(multiline_latex(x, expr, terms_per_line=2, environment="eqnarray", use_dots=True)) \begin{eqnarray} x & = & e^{i \alpha} + \sin{\left(\alpha y \right)} \dots\nonumber\\ & & - \cos{\left(\log{\left(y \right)} \right)} \end{eqnarray} Using ``IEEEeqnarray``: >>> print(multiline_latex(x, expr, environment="IEEEeqnarray")) \begin{IEEEeqnarray}{rCl} x & = & e^{i \alpha} \nonumber\\ & & + \sin{\left(\alpha y \right)} \nonumber\\ & & - \cos{\left(\log{\left(y \right)} \right)} \end{IEEEeqnarray} Notes ===== All optional parameters from ``latex`` can also be used. """ # Based on code from https://github.com/sympy/sympy/issues/3001 l = LatexPrinter(**settings) if environment == "eqnarray": result = r'\begin{eqnarray}' + '\n' first_term = '& = &' nonumber = r'\nonumber' end_term = '\n\\end{eqnarray}' doubleet = True elif environment == "IEEEeqnarray": result = r'\begin{IEEEeqnarray}{rCl}' + '\n' first_term = '& = &' nonumber = r'\nonumber' end_term = '\n\\end{IEEEeqnarray}' doubleet = True elif environment == "align*": result = r'\begin{align*}' + '\n' first_term = '= &' nonumber = '' end_term = '\n\\end{align*}' doubleet = False else: raise ValueError("Unknown environment: {}".format(environment)) dots = '' if use_dots: dots=r'\dots' terms = rhs.as_ordered_terms() n_terms = len(terms) term_count = 1 for i in range(n_terms): term = terms[i] term_start = '' term_end = '' sign = '+' if term_count > terms_per_line: if doubleet: term_start = '& & ' else: term_start = '& ' term_count = 1 if term_count == terms_per_line: # End of line if i < n_terms-1: # There are terms remaining term_end = dots + nonumber + r'\\' + '\n' else: term_end = '' if term.as_ordered_factors()[0] == -1: term = -1*term sign = r'-' if i == 0: # beginning if sign == '+': sign = '' result += r'{:s} {:s}{:s} {:s} {:s}'.format(l.doprint(lhs), first_term, sign, l.doprint(term), term_end) else: result += r'{:s}{:s} {:s} {:s}'.format(term_start, sign, l.doprint(term), term_end) term_count += 1 result += end_term return result sympy-sympy-1.9/sympy/printing/llvmjitcode.py000066400000000000000000000405051412543434000216300ustar00rootroot00000000000000''' Use llvmlite to create executable functions from Sympy expressions This module requires llvmlite (https://github.com/numba/llvmlite). ''' import ctypes from sympy.external import import_module from sympy.printing.printer import Printer from sympy import S, IndexedBase from sympy.utilities.decorator import doctest_depends_on llvmlite = import_module('llvmlite') if llvmlite: ll = import_module('llvmlite.ir').ir llvm = import_module('llvmlite.binding').binding llvm.initialize() llvm.initialize_native_target() llvm.initialize_native_asmprinter() __doctest_requires__ = {('llvm_callable'): ['llvmlite']} class LLVMJitPrinter(Printer): '''Convert expressions to LLVM IR''' def __init__(self, module, builder, fn, *args, **kwargs): self.func_arg_map = kwargs.pop("func_arg_map", {}) if not llvmlite: raise ImportError("llvmlite is required for LLVMJITPrinter") super().__init__(*args, **kwargs) self.fp_type = ll.DoubleType() self.module = module self.builder = builder self.fn = fn self.ext_fn = {} # keep track of wrappers to external functions self.tmp_var = {} def _add_tmp_var(self, name, value): self.tmp_var[name] = value def _print_Number(self, n): return ll.Constant(self.fp_type, float(n)) def _print_Integer(self, expr): return ll.Constant(self.fp_type, float(expr.p)) def _print_Symbol(self, s): val = self.tmp_var.get(s) if not val: # look up parameter with name s val = self.func_arg_map.get(s) if not val: raise LookupError("Symbol not found: %s" % s) return val def _print_Pow(self, expr): base0 = self._print(expr.base) if expr.exp == S.NegativeOne: return self.builder.fdiv(ll.Constant(self.fp_type, 1.0), base0) if expr.exp == S.Half: fn = self.ext_fn.get("sqrt") if not fn: fn_type = ll.FunctionType(self.fp_type, [self.fp_type]) fn = ll.Function(self.module, fn_type, "sqrt") self.ext_fn["sqrt"] = fn return self.builder.call(fn, [base0], "sqrt") if expr.exp == 2: return self.builder.fmul(base0, base0) exp0 = self._print(expr.exp) fn = self.ext_fn.get("pow") if not fn: fn_type = ll.FunctionType(self.fp_type, [self.fp_type, self.fp_type]) fn = ll.Function(self.module, fn_type, "pow") self.ext_fn["pow"] = fn return self.builder.call(fn, [base0, exp0], "pow") def _print_Mul(self, expr): nodes = [self._print(a) for a in expr.args] e = nodes[0] for node in nodes[1:]: e = self.builder.fmul(e, node) return e def _print_Add(self, expr): nodes = [self._print(a) for a in expr.args] e = nodes[0] for node in nodes[1:]: e = self.builder.fadd(e, node) return e # TODO - assumes all called functions take one double precision argument. # Should have a list of math library functions to validate this. def _print_Function(self, expr): name = expr.func.__name__ e0 = self._print(expr.args[0]) fn = self.ext_fn.get(name) if not fn: fn_type = ll.FunctionType(self.fp_type, [self.fp_type]) fn = ll.Function(self.module, fn_type, name) self.ext_fn[name] = fn return self.builder.call(fn, [e0], name) def emptyPrinter(self, expr): raise TypeError("Unsupported type for LLVM JIT conversion: %s" % type(expr)) # Used when parameters are passed by array. Often used in callbacks to # handle a variable number of parameters. class LLVMJitCallbackPrinter(LLVMJitPrinter): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) def _print_Indexed(self, expr): array, idx = self.func_arg_map[expr.base] offset = int(expr.indices[0].evalf()) array_ptr = self.builder.gep(array, [ll.Constant(ll.IntType(32), offset)]) fp_array_ptr = self.builder.bitcast(array_ptr, ll.PointerType(self.fp_type)) value = self.builder.load(fp_array_ptr) return value def _print_Symbol(self, s): val = self.tmp_var.get(s) if val: return val array, idx = self.func_arg_map.get(s, [None, 0]) if not array: raise LookupError("Symbol not found: %s" % s) array_ptr = self.builder.gep(array, [ll.Constant(ll.IntType(32), idx)]) fp_array_ptr = self.builder.bitcast(array_ptr, ll.PointerType(self.fp_type)) value = self.builder.load(fp_array_ptr) return value # ensure lifetime of the execution engine persists (else call to compiled # function will seg fault) exe_engines = [] # ensure names for generated functions are unique link_names = set() current_link_suffix = 0 class LLVMJitCode: def __init__(self, signature): self.signature = signature self.fp_type = ll.DoubleType() self.module = ll.Module('mod1') self.fn = None self.llvm_arg_types = [] self.llvm_ret_type = self.fp_type self.param_dict = {} # map symbol name to LLVM function argument self.link_name = '' def _from_ctype(self, ctype): if ctype == ctypes.c_int: return ll.IntType(32) if ctype == ctypes.c_double: return self.fp_type if ctype == ctypes.POINTER(ctypes.c_double): return ll.PointerType(self.fp_type) if ctype == ctypes.c_void_p: return ll.PointerType(ll.IntType(32)) if ctype == ctypes.py_object: return ll.PointerType(ll.IntType(32)) print("Unhandled ctype = %s" % str(ctype)) def _create_args(self, func_args): """Create types for function arguments""" self.llvm_ret_type = self._from_ctype(self.signature.ret_type) self.llvm_arg_types = \ [self._from_ctype(a) for a in self.signature.arg_ctypes] def _create_function_base(self): """Create function with name and type signature""" global link_names, current_link_suffix default_link_name = 'jit_func' current_link_suffix += 1 self.link_name = default_link_name + str(current_link_suffix) link_names.add(self.link_name) fn_type = ll.FunctionType(self.llvm_ret_type, self.llvm_arg_types) self.fn = ll.Function(self.module, fn_type, name=self.link_name) def _create_param_dict(self, func_args): """Mapping of symbolic values to function arguments""" for i, a in enumerate(func_args): self.fn.args[i].name = str(a) self.param_dict[a] = self.fn.args[i] def _create_function(self, expr): """Create function body and return LLVM IR""" bb_entry = self.fn.append_basic_block('entry') builder = ll.IRBuilder(bb_entry) lj = LLVMJitPrinter(self.module, builder, self.fn, func_arg_map=self.param_dict) ret = self._convert_expr(lj, expr) lj.builder.ret(self._wrap_return(lj, ret)) strmod = str(self.module) return strmod def _wrap_return(self, lj, vals): # Return a single double if there is one return value, # else return a tuple of doubles. # Don't wrap return value in this case if self.signature.ret_type == ctypes.c_double: return vals[0] # Use this instead of a real PyObject* void_ptr = ll.PointerType(ll.IntType(32)) # Create a wrapped double: PyObject* PyFloat_FromDouble(double v) wrap_type = ll.FunctionType(void_ptr, [self.fp_type]) wrap_fn = ll.Function(lj.module, wrap_type, "PyFloat_FromDouble") wrapped_vals = [lj.builder.call(wrap_fn, [v]) for v in vals] if len(vals) == 1: final_val = wrapped_vals[0] else: # Create a tuple: PyObject* PyTuple_Pack(Py_ssize_t n, ...) # This should be Py_ssize_t tuple_arg_types = [ll.IntType(32)] tuple_arg_types.extend([void_ptr]*len(vals)) tuple_type = ll.FunctionType(void_ptr, tuple_arg_types) tuple_fn = ll.Function(lj.module, tuple_type, "PyTuple_Pack") tuple_args = [ll.Constant(ll.IntType(32), len(wrapped_vals))] tuple_args.extend(wrapped_vals) final_val = lj.builder.call(tuple_fn, tuple_args) return final_val def _convert_expr(self, lj, expr): try: # Match CSE return data structure. if len(expr) == 2: tmp_exprs = expr[0] final_exprs = expr[1] if len(final_exprs) != 1 and self.signature.ret_type == ctypes.c_double: raise NotImplementedError("Return of multiple expressions not supported for this callback") for name, e in tmp_exprs: val = lj._print(e) lj._add_tmp_var(name, val) except TypeError: final_exprs = [expr] vals = [lj._print(e) for e in final_exprs] return vals def _compile_function(self, strmod): global exe_engines llmod = llvm.parse_assembly(strmod) pmb = llvm.create_pass_manager_builder() pmb.opt_level = 2 pass_manager = llvm.create_module_pass_manager() pmb.populate(pass_manager) pass_manager.run(llmod) target_machine = \ llvm.Target.from_default_triple().create_target_machine() exe_eng = llvm.create_mcjit_compiler(llmod, target_machine) exe_eng.finalize_object() exe_engines.append(exe_eng) if False: print("Assembly") print(target_machine.emit_assembly(llmod)) fptr = exe_eng.get_function_address(self.link_name) return fptr class LLVMJitCodeCallback(LLVMJitCode): def __init__(self, signature): super().__init__(signature) def _create_param_dict(self, func_args): for i, a in enumerate(func_args): if isinstance(a, IndexedBase): self.param_dict[a] = (self.fn.args[i], i) self.fn.args[i].name = str(a) else: self.param_dict[a] = (self.fn.args[self.signature.input_arg], i) def _create_function(self, expr): """Create function body and return LLVM IR""" bb_entry = self.fn.append_basic_block('entry') builder = ll.IRBuilder(bb_entry) lj = LLVMJitCallbackPrinter(self.module, builder, self.fn, func_arg_map=self.param_dict) ret = self._convert_expr(lj, expr) if self.signature.ret_arg: output_fp_ptr = builder.bitcast(self.fn.args[self.signature.ret_arg], ll.PointerType(self.fp_type)) for i, val in enumerate(ret): index = ll.Constant(ll.IntType(32), i) output_array_ptr = builder.gep(output_fp_ptr, [index]) builder.store(val, output_array_ptr) builder.ret(ll.Constant(ll.IntType(32), 0)) # return success else: lj.builder.ret(self._wrap_return(lj, ret)) strmod = str(self.module) return strmod class CodeSignature: def __init__(self, ret_type): self.ret_type = ret_type self.arg_ctypes = [] # Input argument array element index self.input_arg = 0 # For the case output value is referenced through a parameter rather # than the return value self.ret_arg = None def _llvm_jit_code(args, expr, signature, callback_type): """Create a native code function from a Sympy expression""" if callback_type is None: jit = LLVMJitCode(signature) else: jit = LLVMJitCodeCallback(signature) jit._create_args(args) jit._create_function_base() jit._create_param_dict(args) strmod = jit._create_function(expr) if False: print("LLVM IR") print(strmod) fptr = jit._compile_function(strmod) return fptr @doctest_depends_on(modules=('llvmlite', 'scipy')) def llvm_callable(args, expr, callback_type=None): '''Compile function from a Sympy expression Expressions are evaluated using double precision arithmetic. Some single argument math functions (exp, sin, cos, etc.) are supported in expressions. Parameters ========== args : List of Symbol Arguments to the generated function. Usually the free symbols in the expression. Currently each one is assumed to convert to a double precision scalar. expr : Expr, or (Replacements, Expr) as returned from 'cse' Expression to compile. callback_type : string Create function with signature appropriate to use as a callback. Currently supported: 'scipy.integrate' 'scipy.integrate.test' 'cubature' Returns ======= Compiled function that can evaluate the expression. Examples ======== >>> import sympy.printing.llvmjitcode as jit >>> from sympy.abc import a >>> e = a*a + a + 1 >>> e1 = jit.llvm_callable([a], e) >>> e.subs(a, 1.1) # Evaluate via substitution 3.31000000000000 >>> e1(1.1) # Evaluate using JIT-compiled code 3.3100000000000005 Callbacks for integration functions can be JIT compiled. >>> import sympy.printing.llvmjitcode as jit >>> from sympy.abc import a >>> from sympy import integrate >>> from scipy.integrate import quad >>> e = a*a >>> e1 = jit.llvm_callable([a], e, callback_type='scipy.integrate') >>> integrate(e, (a, 0.0, 2.0)) 2.66666666666667 >>> quad(e1, 0.0, 2.0)[0] 2.66666666666667 The 'cubature' callback is for the Python wrapper around the cubature package ( https://github.com/saullocastro/cubature ) and ( http://ab-initio.mit.edu/wiki/index.php/Cubature ) There are two signatures for the SciPy integration callbacks. The first ('scipy.integrate') is the function to be passed to the integration routine, and will pass the signature checks. The second ('scipy.integrate.test') is only useful for directly calling the function using ctypes variables. It will not pass the signature checks for scipy.integrate. The return value from the cse module can also be compiled. This can improve the performance of the compiled function. If multiple expressions are given to cse, the compiled function returns a tuple. The 'cubature' callback handles multiple expressions (set `fdim` to match in the integration call.) >>> import sympy.printing.llvmjitcode as jit >>> from sympy import cse >>> from sympy.abc import x,y >>> e1 = x*x + y*y >>> e2 = 4*(x*x + y*y) + 8.0 >>> after_cse = cse([e1,e2]) >>> after_cse ([(x0, x**2), (x1, y**2)], [x0 + x1, 4*x0 + 4*x1 + 8.0]) >>> j1 = jit.llvm_callable([x,y], after_cse) # doctest: +SKIP >>> j1(1.0, 2.0) # doctest: +SKIP (5.0, 28.0) ''' if not llvmlite: raise ImportError("llvmlite is required for llvmjitcode") signature = CodeSignature(ctypes.py_object) arg_ctypes = [] if callback_type is None: for _ in args: arg_ctype = ctypes.c_double arg_ctypes.append(arg_ctype) elif callback_type == 'scipy.integrate' or callback_type == 'scipy.integrate.test': signature.ret_type = ctypes.c_double arg_ctypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_double)] arg_ctypes_formal = [ctypes.c_int, ctypes.c_double] signature.input_arg = 1 elif callback_type == 'cubature': arg_ctypes = [ctypes.c_int, ctypes.POINTER(ctypes.c_double), ctypes.c_void_p, ctypes.c_int, ctypes.POINTER(ctypes.c_double) ] signature.ret_type = ctypes.c_int signature.input_arg = 1 signature.ret_arg = 4 else: raise ValueError("Unknown callback type: %s" % callback_type) signature.arg_ctypes = arg_ctypes fptr = _llvm_jit_code(args, expr, signature, callback_type) if callback_type and callback_type == 'scipy.integrate': arg_ctypes = arg_ctypes_formal cfunc = ctypes.CFUNCTYPE(signature.ret_type, *arg_ctypes)(fptr) return cfunc sympy-sympy-1.9/sympy/printing/maple.py000066400000000000000000000241531412543434000204130ustar00rootroot00000000000000""" Maple code printer The MapleCodePrinter converts single sympy expressions into single Maple expressions, using the functions defined in the Maple objects where possible. FIXME: This module is still under actively developed. Some functions may be not completed. """ from sympy.core import S from sympy.core.numbers import Integer, IntegerConstant from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence, PRECEDENCE import sympy _known_func_same_name = [ 'sin', 'cos', 'tan', 'sec', 'csc', 'cot', 'sinh', 'cosh', 'tanh', 'sech', 'csch', 'coth', 'exp', 'floor', 'factorial' ] known_functions = { # Sympy -> Maple 'Abs': 'abs', 'log': 'ln', 'asin': 'arcsin', 'acos': 'arccos', 'atan': 'arctan', 'asec': 'arcsec', 'acsc': 'arccsc', 'acot': 'arccot', 'asinh': 'arcsinh', 'acosh': 'arccosh', 'atanh': 'arctanh', 'asech': 'arcsech', 'acsch': 'arccsch', 'acoth': 'arccoth', 'ceiling': 'ceil', 'besseli': 'BesselI', 'besselj': 'BesselJ', 'besselk': 'BesselK', 'bessely': 'BesselY', 'hankelh1': 'HankelH1', 'hankelh2': 'HankelH2', 'airyai': 'AiryAi', 'airybi': 'AiryBi' } for _func in _known_func_same_name: known_functions[_func] = _func number_symbols = { # Sympy -> Maple S.Pi: 'Pi', S.Exp1: 'exp(1)', S.Catalan: 'Catalan', S.EulerGamma: 'gamma', S.GoldenRatio: '(1/2 + (1/2)*sqrt(5))' } spec_relational_ops = { # Sympy -> Maple '==': '=', '!=': '<>' } not_supported_symbol = [ S.ComplexInfinity ] class MapleCodePrinter(CodePrinter): """ Printer which converts a sympy expression into a maple code. """ printmethod = "_maple" language = "maple" _default_settings = { 'order': None, 'full_prec': 'auto', 'human': True, 'inline': True, 'allow_unknown_functions': True, } def __init__(self, settings=None): if settings is None: settings = dict() super().__init__(settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) def _get_statement(self, codestring): return "%s;" % codestring def _get_comment(self, text): return "# {}".format(text) def _declare_number_const(self, name, value): return "{} := {};".format(name, value.evalf(self._settings['precision'])) def _format_code(self, lines): return lines def _print_tuple(self, expr): return self._print(list(expr)) def _print_Tuple(self, expr): return self._print(list(expr)) def _print_Assignment(self, expr): lhs = self._print(expr.lhs) rhs = self._print(expr.rhs) return "{lhs} := {rhs}".format(lhs=lhs, rhs=rhs) def _print_Pow(self, expr, **kwargs): PREC = precedence(expr) if expr.exp == -1: return '1/%s' % (self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5 or expr.exp == S(1) / 2: return 'sqrt(%s)' % self._print(expr.base) elif expr.exp == -0.5 or expr.exp == -S(1) / 2: return '1/sqrt(%s)' % self._print(expr.base) else: return '{base}^{exp}'.format( base=self.parenthesize(expr.base, PREC), exp=self.parenthesize(expr.exp, PREC)) def _print_Piecewise(self, expr): if (expr.args[-1].cond is not True) and (expr.args[-1].cond != S.BooleanTrue): # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") _coup_list = [ ("{c}, {e}".format(c=self._print(c), e=self._print(e)) if c is not True and c is not S.BooleanTrue else "{e}".format( e=self._print(e))) for e, c in expr.args] _inbrace = ', '.join(_coup_list) return 'piecewise({_inbrace})'.format(_inbrace=_inbrace) def _print_Rational(self, expr): p, q = int(expr.p), int(expr.q) return "{p}/{q}".format(p=str(p), q=str(q)) def _print_Relational(self, expr): PREC=precedence(expr) lhs_code = self.parenthesize(expr.lhs, PREC) rhs_code = self.parenthesize(expr.rhs, PREC) op = expr.rel_op if op in spec_relational_ops: op = spec_relational_ops[op] return "{lhs} {rel_op} {rhs}".format(lhs=lhs_code, rel_op=op, rhs=rhs_code) def _print_NumberSymbol(self, expr): return number_symbols[expr] def _print_NegativeInfinity(self, expr): return '-infinity' def _print_Infinity(self, expr): return 'infinity' def _print_Idx(self, expr): return self._print(expr.label) def _print_BooleanTrue(self, expr): return "true" def _print_BooleanFalse(self, expr): return "false" def _print_bool(self, expr): return 'true' if expr else 'false' def _print_NaN(self, expr): return 'undefined' def _get_matrix(self, expr, sparse=False): if expr.cols == 0 or expr.rows == 0: _strM = 'Matrix([], storage = {storage})'.format( storage='sparse' if sparse else 'rectangular') else: _strM = 'Matrix({list}, storage = {storage})'.format( list=self._print(expr.tolist()), storage='sparse' if sparse else 'rectangular') return _strM def _print_MatrixElement(self, expr): return "{parent}[{i_maple}, {j_maple}]".format( parent=self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True), i_maple=self._print(expr.i + 1), j_maple=self._print(expr.j + 1)) def _print_MatrixBase(self, expr): return self._get_matrix(expr, sparse=False) def _print_SparseMatrix(self, expr): return self._get_matrix(expr, sparse=True) def _print_Identity(self, expr): if isinstance(expr.rows, Integer) or isinstance(expr.rows, IntegerConstant): return self._print(sympy.SparseMatrix(expr)) else: return "Matrix({var_size}, shape = identity)".format(var_size=self._print(expr.rows)) def _print_MatMul(self, expr): PREC=precedence(expr) _fact_list = list(expr.args) _const = None if not ( isinstance(_fact_list[0], sympy.MatrixBase) or isinstance( _fact_list[0], sympy.MatrixExpr) or isinstance( _fact_list[0], sympy.MatrixSlice) or isinstance( _fact_list[0], sympy.MatrixSymbol)): _const, _fact_list = _fact_list[0], _fact_list[1:] if _const is None or _const == 1: return '.'.join(self.parenthesize(_m, PREC) for _m in _fact_list) else: return '{c}*{m}'.format(c=_const, m='.'.join(self.parenthesize(_m, PREC) for _m in _fact_list)) def _print_MatPow(self, expr): # This function requires LinearAlgebra Function in Maple return 'MatrixPower({A}, {n})'.format(A=self._print(expr.base), n=self._print(expr.exp)) def _print_HadamardProduct(self, expr): PREC = precedence(expr) _fact_list = list(expr.args) return '*'.join(self.parenthesize(_m, PREC) for _m in _fact_list) def _print_Derivative(self, expr): _f, (_var, _order) = expr.args if _order != 1: _second_arg = '{var}${order}'.format(var=self._print(_var), order=self._print(_order)) else: _second_arg = '{var}'.format(var=self._print(_var)) return 'diff({func_expr}, {sec_arg})'.format(func_expr=self._print(_f), sec_arg=_second_arg) def maple_code(expr, assign_to=None, **settings): r"""Converts ``expr`` to a string of Maple code. Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for expressions that generate multi-line statements. precision : integer, optional The precision for numbers such as pi [default=16]. user_functions : dict, optional A dictionary where keys are ``FunctionClass`` instances and values are their string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. See below for examples. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. inline: bool, optional If True, we try to create single-statement code instead of multiple statements. [default=True]. """ return MapleCodePrinter(settings).doprint(expr, assign_to) def print_maple_code(expr, **settings): """Prints the Maple representation of the given expression. See :func:`maple_code` for the meaning of the optional arguments. Examples ======== >>> from sympy.printing.maple import print_maple_code >>> from sympy import symbols >>> x, y = symbols('x y') >>> print_maple_code(x, assign_to=y) y := x """ print(maple_code(expr, **settings)) sympy-sympy-1.9/sympy/printing/mathematica.py000066400000000000000000000302011412543434000215610ustar00rootroot00000000000000""" Mathematica code printer """ from typing import Any, Dict, Set, Tuple from sympy.core import Basic, Expr, Float from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence # Used in MCodePrinter._print_Function(self) known_functions = { "exp": [(lambda x: True, "Exp")], "log": [(lambda x: True, "Log")], "sin": [(lambda x: True, "Sin")], "cos": [(lambda x: True, "Cos")], "tan": [(lambda x: True, "Tan")], "cot": [(lambda x: True, "Cot")], "sec": [(lambda x: True, "Sec")], "csc": [(lambda x: True, "Csc")], "asin": [(lambda x: True, "ArcSin")], "acos": [(lambda x: True, "ArcCos")], "atan": [(lambda x: True, "ArcTan")], "acot": [(lambda x: True, "ArcCot")], "asec": [(lambda x: True, "ArcSec")], "acsc": [(lambda x: True, "ArcCsc")], "atan2": [(lambda *x: True, "ArcTan")], "sinh": [(lambda x: True, "Sinh")], "cosh": [(lambda x: True, "Cosh")], "tanh": [(lambda x: True, "Tanh")], "coth": [(lambda x: True, "Coth")], "sech": [(lambda x: True, "Sech")], "csch": [(lambda x: True, "Csch")], "asinh": [(lambda x: True, "ArcSinh")], "acosh": [(lambda x: True, "ArcCosh")], "atanh": [(lambda x: True, "ArcTanh")], "acoth": [(lambda x: True, "ArcCoth")], "asech": [(lambda x: True, "ArcSech")], "acsch": [(lambda x: True, "ArcCsch")], "conjugate": [(lambda x: True, "Conjugate")], "Max": [(lambda *x: True, "Max")], "Min": [(lambda *x: True, "Min")], "erf": [(lambda x: True, "Erf")], "erf2": [(lambda *x: True, "Erf")], "erfc": [(lambda x: True, "Erfc")], "erfi": [(lambda x: True, "Erfi")], "erfinv": [(lambda x: True, "InverseErf")], "erfcinv": [(lambda x: True, "InverseErfc")], "erf2inv": [(lambda *x: True, "InverseErf")], "expint": [(lambda *x: True, "ExpIntegralE")], "Ei": [(lambda x: True, "ExpIntegralEi")], "fresnelc": [(lambda x: True, "FresnelC")], "fresnels": [(lambda x: True, "FresnelS")], "gamma": [(lambda x: True, "Gamma")], "uppergamma": [(lambda *x: True, "Gamma")], "polygamma": [(lambda *x: True, "PolyGamma")], "loggamma": [(lambda x: True, "LogGamma")], "beta": [(lambda *x: True, "Beta")], "Ci": [(lambda x: True, "CosIntegral")], "Si": [(lambda x: True, "SinIntegral")], "Chi": [(lambda x: True, "CoshIntegral")], "Shi": [(lambda x: True, "SinhIntegral")], "li": [(lambda x: True, "LogIntegral")], "factorial": [(lambda x: True, "Factorial")], "factorial2": [(lambda x: True, "Factorial2")], "subfactorial": [(lambda x: True, "Subfactorial")], "catalan": [(lambda x: True, "CatalanNumber")], "harmonic": [(lambda *x: True, "HarmonicNumber")], "RisingFactorial": [(lambda *x: True, "Pochhammer")], "FallingFactorial": [(lambda *x: True, "FactorialPower")], "laguerre": [(lambda *x: True, "LaguerreL")], "assoc_laguerre": [(lambda *x: True, "LaguerreL")], "hermite": [(lambda *x: True, "HermiteH")], "jacobi": [(lambda *x: True, "JacobiP")], "gegenbauer": [(lambda *x: True, "GegenbauerC")], "chebyshevt": [(lambda *x: True, "ChebyshevT")], "chebyshevu": [(lambda *x: True, "ChebyshevU")], "legendre": [(lambda *x: True, "LegendreP")], "assoc_legendre": [(lambda *x: True, "LegendreP")], "mathieuc": [(lambda *x: True, "MathieuC")], "mathieus": [(lambda *x: True, "MathieuS")], "mathieucprime": [(lambda *x: True, "MathieuCPrime")], "mathieusprime": [(lambda *x: True, "MathieuSPrime")], "stieltjes": [(lambda x: True, "StieltjesGamma")], "elliptic_e": [(lambda *x: True, "EllipticE")], "elliptic_f": [(lambda *x: True, "EllipticE")], "elliptic_k": [(lambda x: True, "EllipticK")], "elliptic_pi": [(lambda *x: True, "EllipticPi")], "zeta": [(lambda *x: True, "Zeta")], "besseli": [(lambda *x: True, "BesselI")], "besselj": [(lambda *x: True, "BesselJ")], "besselk": [(lambda *x: True, "BesselK")], "bessely": [(lambda *x: True, "BesselY")], "hankel1": [(lambda *x: True, "HankelH1")], "hankel2": [(lambda *x: True, "HankelH2")], "airyai": [(lambda x: True, "AiryAi")], "airybi": [(lambda x: True, "AiryBi")], "airyaiprime": [(lambda x: True, "AiryAiPrime")], "airybiprime": [(lambda x: True, "AiryBiPrime")], "polylog": [(lambda *x: True, "PolyLog")], "lerchphi": [(lambda *x: True, "LerchPhi")], "gcd": [(lambda *x: True, "GCD")], "lcm": [(lambda *x: True, "LCM")], "jn": [(lambda *x: True, "SphericalBesselJ")], "yn": [(lambda *x: True, "SphericalBesselY")], "hyper": [(lambda *x: True, "HypergeometricPFQ")], "meijerg": [(lambda *x: True, "MeijerG")], "appellf1": [(lambda *x: True, "AppellF1")], "DiracDelta": [(lambda x: True, "DiracDelta")], "Heaviside": [(lambda x: True, "HeavisideTheta")], "KroneckerDelta": [(lambda *x: True, "KroneckerDelta")], } class MCodePrinter(CodePrinter): """A printer to convert python expressions to strings of the Wolfram's Mathematica code """ printmethod = "_mcode" language = "Wolfram Language" _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 15, 'user_functions': {}, 'human': True, 'allow_unknown_functions': False, } # type: Dict[str, Any] _number_symbols = set() # type: Set[Tuple[Expr, Float]] _not_supported = set() # type: Set[Basic] def __init__(self, settings={}): """Register function mappings supplied by user""" CodePrinter.__init__(self, settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}).copy() for k, v in userfuncs.items(): if not isinstance(v, list): userfuncs[k] = [(lambda *x: True, v)] self.known_functions.update(userfuncs) def _format_code(self, lines): return lines def _print_Pow(self, expr): PREC = precedence(expr) return '%s^%s' % (self.parenthesize(expr.base, PREC), self.parenthesize(expr.exp, PREC)) def _print_Mul(self, expr): PREC = precedence(expr) c, nc = expr.args_cnc() res = super()._print_Mul(expr.func(*c)) if nc: res += '*' res += '**'.join(self.parenthesize(a, PREC) for a in nc) return res def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) # Primitive numbers def _print_Zero(self, expr): return '0' def _print_One(self, expr): return '1' def _print_NegativeOne(self, expr): return '-1' def _print_Half(self, expr): return '1/2' def _print_ImaginaryUnit(self, expr): return 'I' # Infinity and invalid numbers def _print_Infinity(self, expr): return 'Infinity' def _print_NegativeInfinity(self, expr): return '-Infinity' def _print_ComplexInfinity(self, expr): return 'ComplexInfinity' def _print_NaN(self, expr): return 'Indeterminate' # Mathematical constants def _print_Exp1(self, expr): return 'E' def _print_Pi(self, expr): return 'Pi' def _print_GoldenRatio(self, expr): return 'GoldenRatio' def _print_TribonacciConstant(self, expr): expanded = expr.expand(func=True) PREC = precedence(expr) return self.parenthesize(expanded, PREC) def _print_EulerGamma(self, expr): return 'EulerGamma' def _print_Catalan(self, expr): return 'Catalan' def _print_list(self, expr): return '{' + ', '.join(self.doprint(a) for a in expr) + '}' _print_tuple = _print_list _print_Tuple = _print_list def _print_ImmutableDenseMatrix(self, expr): return self.doprint(expr.tolist()) def _print_ImmutableSparseMatrix(self, expr): from sympy.core.compatibility import default_sort_key def print_rule(pos, val): return '{} -> {}'.format( self.doprint((pos[0]+1, pos[1]+1)), self.doprint(val)) def print_data(): items = sorted(expr.todok().items(), key=default_sort_key) return '{' + \ ', '.join(print_rule(k, v) for k, v in items) + \ '}' def print_dims(): return self.doprint(expr.shape) return 'SparseArray[{}, {}]'.format(print_data(), print_dims()) def _print_ImmutableDenseNDimArray(self, expr): return self.doprint(expr.tolist()) def _print_ImmutableSparseNDimArray(self, expr): def print_string_list(string_list): return '{' + ', '.join(a for a in string_list) + '}' def to_mathematica_index(*args): """Helper function to change Python style indexing to Pathematica indexing. Python indexing (0, 1 ... n-1) -> Mathematica indexing (1, 2 ... n) """ return tuple(i + 1 for i in args) def print_rule(pos, val): """Helper function to print a rule of Mathematica""" return '{} -> {}'.format(self.doprint(pos), self.doprint(val)) def print_data(): """Helper function to print data part of Mathematica sparse array. It uses the fourth notation ``SparseArray[data,{d1,d2,...}]`` from https://reference.wolfram.com/language/ref/SparseArray.html ``data`` must be formatted with rule. """ return print_string_list( [print_rule( to_mathematica_index(*(expr._get_tuple_index(key))), value) for key, value in sorted(expr._sparse_array.items())] ) def print_dims(): """Helper function to print dimensions part of Mathematica sparse array. It uses the fourth notation ``SparseArray[data,{d1,d2,...}]`` from https://reference.wolfram.com/language/ref/SparseArray.html """ return self.doprint(expr.shape) return 'SparseArray[{}, {}]'.format(print_data(), print_dims()) def _print_Function(self, expr): if expr.func.__name__ in self.known_functions: cond_mfunc = self.known_functions[expr.func.__name__] for cond, mfunc in cond_mfunc: if cond(*expr.args): return "%s[%s]" % (mfunc, self.stringify(expr.args, ", ")) elif (expr.func.__name__ in self._rewriteable_functions and self._rewriteable_functions[expr.func.__name__] in self.known_functions): # Simple rewrite to supported function possible return self._print(expr.rewrite(self._rewriteable_functions[expr.func.__name__])) return expr.func.__name__ + "[%s]" % self.stringify(expr.args, ", ") _print_MinMaxBase = _print_Function def _print_LambertW(self, expr): if len(expr.args) == 1: return "ProductLog[{}]".format(self._print(expr.args[0])) return "ProductLog[{}, {}]".format( self._print(expr.args[1]), self._print(expr.args[0])) def _print_Integral(self, expr): if len(expr.variables) == 1 and not expr.limits[0][1:]: args = [expr.args[0], expr.variables[0]] else: args = expr.args return "Hold[Integrate[" + ', '.join(self.doprint(a) for a in args) + "]]" def _print_Sum(self, expr): return "Hold[Sum[" + ', '.join(self.doprint(a) for a in expr.args) + "]]" def _print_Derivative(self, expr): dexpr = expr.expr dvars = [i[0] if i[1] == 1 else i for i in expr.variable_count] return "Hold[D[" + ', '.join(self.doprint(a) for a in [dexpr] + dvars) + "]]" def _get_comment(self, text): return "(* {} *)".format(text) def mathematica_code(expr, **settings): r"""Converts an expr to a string of the Wolfram Mathematica code Examples ======== >>> from sympy import mathematica_code as mcode, symbols, sin >>> x = symbols('x') >>> mcode(sin(x).series(x).removeO()) '(1/120)*x^5 - 1/6*x^3 + x' """ return MCodePrinter(settings).doprint(expr) sympy-sympy-1.9/sympy/printing/mathml.py000066400000000000000000002226741412543434000206070ustar00rootroot00000000000000""" A MathML printer. """ from typing import Any, Dict from sympy import sympify, S, Mul from sympy.core.compatibility import default_sort_key from sympy.core.function import _coeff_isneg from sympy.printing.conventions import split_super_sub, requires_partial from sympy.printing.precedence import \ precedence_traditional, PRECEDENCE, PRECEDENCE_TRADITIONAL from sympy.printing.pretty.pretty_symbology import greek_unicode from sympy.printing.printer import Printer, print_function import mpmath.libmp as mlib from mpmath.libmp import prec_to_dps, repr_dps, to_str as mlib_to_str class MathMLPrinterBase(Printer): """Contains common code required for MathMLContentPrinter and MathMLPresentationPrinter. """ _default_settings = { "order": None, "encoding": "utf-8", "fold_frac_powers": False, "fold_func_brackets": False, "fold_short_frac": None, "inv_trig_style": "abbreviated", "ln_notation": False, "long_frac_ratio": None, "mat_delim": "[", "mat_symbol_style": "plain", "mul_symbol": None, "root_notation": True, "symbol_names": {}, "mul_symbol_mathml_numbers": '·', } # type: Dict[str, Any] def __init__(self, settings=None): Printer.__init__(self, settings) from xml.dom.minidom import Document, Text self.dom = Document() # Workaround to allow strings to remain unescaped # Based on # https://stackoverflow.com/questions/38015864/python-xml-dom-minidom-\ # please-dont-escape-my-strings/38041194 class RawText(Text): def writexml(self, writer, indent='', addindent='', newl=''): if self.data: writer.write('{}{}{}'.format(indent, self.data, newl)) def createRawTextNode(data): r = RawText() r.data = data r.ownerDocument = self.dom return r self.dom.createTextNode = createRawTextNode def doprint(self, expr): """ Prints the expression as MathML. """ mathML = Printer._print(self, expr) unistr = mathML.toxml() xmlbstr = unistr.encode('ascii', 'xmlcharrefreplace') res = xmlbstr.decode() return res def apply_patch(self): # Applying the patch of xml.dom.minidom bug # Date: 2011-11-18 # Description: http://ronrothman.com/public/leftbraned/xml-dom-minidom\ # -toprettyxml-and-silly-whitespace/#best-solution # Issue: http://bugs.python.org/issue4147 # Patch: http://hg.python.org/cpython/rev/7262f8f276ff/ from xml.dom.minidom import Element, Text, Node, _write_data def writexml(self, writer, indent="", addindent="", newl=""): # indent = current indentation # addindent = indentation to add to higher levels # newl = newline string writer.write(indent + "<" + self.tagName) attrs = self._get_attributes() a_names = list(attrs.keys()) a_names.sort() for a_name in a_names: writer.write(" %s=\"" % a_name) _write_data(writer, attrs[a_name].value) writer.write("\"") if self.childNodes: writer.write(">") if (len(self.childNodes) == 1 and self.childNodes[0].nodeType == Node.TEXT_NODE): self.childNodes[0].writexml(writer, '', '', '') else: writer.write(newl) for node in self.childNodes: node.writexml( writer, indent + addindent, addindent, newl) writer.write(indent) writer.write("%s" % (self.tagName, newl)) else: writer.write("/>%s" % (newl)) self._Element_writexml_old = Element.writexml Element.writexml = writexml def writexml(self, writer, indent="", addindent="", newl=""): _write_data(writer, "%s%s%s" % (indent, self.data, newl)) self._Text_writexml_old = Text.writexml Text.writexml = writexml def restore_patch(self): from xml.dom.minidom import Element, Text Element.writexml = self._Element_writexml_old Text.writexml = self._Text_writexml_old class MathMLContentPrinter(MathMLPrinterBase): """Prints an expression to the Content MathML markup language. References: https://www.w3.org/TR/MathML2/chapter4.html """ printmethod = "_mathml_content" def mathml_tag(self, e): """Returns the MathML tag for an expression.""" translate = { 'Add': 'plus', 'Mul': 'times', 'Derivative': 'diff', 'Number': 'cn', 'int': 'cn', 'Pow': 'power', 'Max': 'max', 'Min': 'min', 'Abs': 'abs', 'And': 'and', 'Or': 'or', 'Xor': 'xor', 'Not': 'not', 'Implies': 'implies', 'Symbol': 'ci', 'MatrixSymbol': 'ci', 'RandomSymbol': 'ci', 'Integral': 'int', 'Sum': 'sum', 'sin': 'sin', 'cos': 'cos', 'tan': 'tan', 'cot': 'cot', 'csc': 'csc', 'sec': 'sec', 'sinh': 'sinh', 'cosh': 'cosh', 'tanh': 'tanh', 'coth': 'coth', 'csch': 'csch', 'sech': 'sech', 'asin': 'arcsin', 'asinh': 'arcsinh', 'acos': 'arccos', 'acosh': 'arccosh', 'atan': 'arctan', 'atanh': 'arctanh', 'atan2': 'arctan', 'acot': 'arccot', 'acoth': 'arccoth', 'asec': 'arcsec', 'asech': 'arcsech', 'acsc': 'arccsc', 'acsch': 'arccsch', 'log': 'ln', 'Equality': 'eq', 'Unequality': 'neq', 'GreaterThan': 'geq', 'LessThan': 'leq', 'StrictGreaterThan': 'gt', 'StrictLessThan': 'lt', 'Union': 'union', 'Intersection': 'intersect', } for cls in e.__class__.__mro__: n = cls.__name__ if n in translate: return translate[n] # Not found in the MRO set n = e.__class__.__name__ return n.lower() def _print_Mul(self, expr): if _coeff_isneg(expr): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('minus')) x.appendChild(self._print_Mul(-expr)) return x from sympy.simplify import fraction numer, denom = fraction(expr) if denom is not S.One: x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('divide')) x.appendChild(self._print(numer)) x.appendChild(self._print(denom)) return x coeff, terms = expr.as_coeff_mul() if coeff is S.One and len(terms) == 1: # XXX since the negative coefficient has been handled, I don't # think a coeff of 1 can remain return self._print(terms[0]) if self.order != 'old': terms = Mul._from_args(terms).as_ordered_factors() x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('times')) if coeff != 1: x.appendChild(self._print(coeff)) for term in terms: x.appendChild(self._print(term)) return x def _print_Add(self, expr, order=None): args = self._as_ordered_terms(expr, order=order) lastProcessed = self._print(args[0]) plusNodes = [] for arg in args[1:]: if _coeff_isneg(arg): # use minus x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('minus')) x.appendChild(lastProcessed) x.appendChild(self._print(-arg)) # invert expression since this is now minused lastProcessed = x if arg == args[-1]: plusNodes.append(lastProcessed) else: plusNodes.append(lastProcessed) lastProcessed = self._print(arg) if arg == args[-1]: plusNodes.append(self._print(arg)) if len(plusNodes) == 1: return lastProcessed x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('plus')) while plusNodes: x.appendChild(plusNodes.pop(0)) return x def _print_Piecewise(self, expr): if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") root = self.dom.createElement('piecewise') for i, (e, c) in enumerate(expr.args): if i == len(expr.args) - 1 and c == True: piece = self.dom.createElement('otherwise') piece.appendChild(self._print(e)) else: piece = self.dom.createElement('piece') piece.appendChild(self._print(e)) piece.appendChild(self._print(c)) root.appendChild(piece) return root def _print_MatrixBase(self, m): x = self.dom.createElement('matrix') for i in range(m.rows): x_r = self.dom.createElement('matrixrow') for j in range(m.cols): x_r.appendChild(self._print(m[i, j])) x.appendChild(x_r) return x def _print_Rational(self, e): if e.q == 1: # don't divide x = self.dom.createElement('cn') x.appendChild(self.dom.createTextNode(str(e.p))) return x x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('divide')) # numerator xnum = self.dom.createElement('cn') xnum.appendChild(self.dom.createTextNode(str(e.p))) # denominator xdenom = self.dom.createElement('cn') xdenom.appendChild(self.dom.createTextNode(str(e.q))) x.appendChild(xnum) x.appendChild(xdenom) return x def _print_Limit(self, e): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement(self.mathml_tag(e))) x_1 = self.dom.createElement('bvar') x_2 = self.dom.createElement('lowlimit') x_1.appendChild(self._print(e.args[1])) x_2.appendChild(self._print(e.args[2])) x.appendChild(x_1) x.appendChild(x_2) x.appendChild(self._print(e.args[0])) return x def _print_ImaginaryUnit(self, e): return self.dom.createElement('imaginaryi') def _print_EulerGamma(self, e): return self.dom.createElement('eulergamma') def _print_GoldenRatio(self, e): """We use unicode #x3c6 for Greek letter phi as defined here http://www.w3.org/2003/entities/2007doc/isogrk1.html""" x = self.dom.createElement('cn') x.appendChild(self.dom.createTextNode("\N{GREEK SMALL LETTER PHI}")) return x def _print_Exp1(self, e): return self.dom.createElement('exponentiale') def _print_Pi(self, e): return self.dom.createElement('pi') def _print_Infinity(self, e): return self.dom.createElement('infinity') def _print_NaN(self, e): return self.dom.createElement('notanumber') def _print_EmptySet(self, e): return self.dom.createElement('emptyset') def _print_BooleanTrue(self, e): return self.dom.createElement('true') def _print_BooleanFalse(self, e): return self.dom.createElement('false') def _print_NegativeInfinity(self, e): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('minus')) x.appendChild(self.dom.createElement('infinity')) return x def _print_Integral(self, e): def lime_recur(limits): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement(self.mathml_tag(e))) bvar_elem = self.dom.createElement('bvar') bvar_elem.appendChild(self._print(limits[0][0])) x.appendChild(bvar_elem) if len(limits[0]) == 3: low_elem = self.dom.createElement('lowlimit') low_elem.appendChild(self._print(limits[0][1])) x.appendChild(low_elem) up_elem = self.dom.createElement('uplimit') up_elem.appendChild(self._print(limits[0][2])) x.appendChild(up_elem) if len(limits[0]) == 2: up_elem = self.dom.createElement('uplimit') up_elem.appendChild(self._print(limits[0][1])) x.appendChild(up_elem) if len(limits) == 1: x.appendChild(self._print(e.function)) else: x.appendChild(lime_recur(limits[1:])) return x limits = list(e.limits) limits.reverse() return lime_recur(limits) def _print_Sum(self, e): # Printer can be shared because Sum and Integral have the # same internal representation. return self._print_Integral(e) def _print_Symbol(self, sym): ci = self.dom.createElement(self.mathml_tag(sym)) def join(items): if len(items) > 1: mrow = self.dom.createElement('mml:mrow') for i, item in enumerate(items): if i > 0: mo = self.dom.createElement('mml:mo') mo.appendChild(self.dom.createTextNode(" ")) mrow.appendChild(mo) mi = self.dom.createElement('mml:mi') mi.appendChild(self.dom.createTextNode(item)) mrow.appendChild(mi) return mrow else: mi = self.dom.createElement('mml:mi') mi.appendChild(self.dom.createTextNode(items[0])) return mi # translate name, supers and subs to unicode characters def translate(s): if s in greek_unicode: return greek_unicode.get(s) else: return s name, supers, subs = split_super_sub(sym.name) name = translate(name) supers = [translate(sup) for sup in supers] subs = [translate(sub) for sub in subs] mname = self.dom.createElement('mml:mi') mname.appendChild(self.dom.createTextNode(name)) if not supers: if not subs: ci.appendChild(self.dom.createTextNode(name)) else: msub = self.dom.createElement('mml:msub') msub.appendChild(mname) msub.appendChild(join(subs)) ci.appendChild(msub) else: if not subs: msup = self.dom.createElement('mml:msup') msup.appendChild(mname) msup.appendChild(join(supers)) ci.appendChild(msup) else: msubsup = self.dom.createElement('mml:msubsup') msubsup.appendChild(mname) msubsup.appendChild(join(subs)) msubsup.appendChild(join(supers)) ci.appendChild(msubsup) return ci _print_MatrixSymbol = _print_Symbol _print_RandomSymbol = _print_Symbol def _print_Pow(self, e): # Here we use root instead of power if the exponent is the reciprocal # of an integer if (self._settings['root_notation'] and e.exp.is_Rational and e.exp.p == 1): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('root')) if e.exp.q != 2: xmldeg = self.dom.createElement('degree') xmlcn = self.dom.createElement('cn') xmlcn.appendChild(self.dom.createTextNode(str(e.exp.q))) xmldeg.appendChild(xmlcn) x.appendChild(xmldeg) x.appendChild(self._print(e.base)) return x x = self.dom.createElement('apply') x_1 = self.dom.createElement(self.mathml_tag(e)) x.appendChild(x_1) x.appendChild(self._print(e.base)) x.appendChild(self._print(e.exp)) return x def _print_Number(self, e): x = self.dom.createElement(self.mathml_tag(e)) x.appendChild(self.dom.createTextNode(str(e))) return x def _print_Float(self, e): x = self.dom.createElement(self.mathml_tag(e)) repr_e = mlib_to_str(e._mpf_, repr_dps(e._prec)) x.appendChild(self.dom.createTextNode(repr_e)) return x def _print_Derivative(self, e): x = self.dom.createElement('apply') diff_symbol = self.mathml_tag(e) if requires_partial(e.expr): diff_symbol = 'partialdiff' x.appendChild(self.dom.createElement(diff_symbol)) x_1 = self.dom.createElement('bvar') for sym, times in reversed(e.variable_count): x_1.appendChild(self._print(sym)) if times > 1: degree = self.dom.createElement('degree') degree.appendChild(self._print(sympify(times))) x_1.appendChild(degree) x.appendChild(x_1) x.appendChild(self._print(e.expr)) return x def _print_Function(self, e): x = self.dom.createElement("apply") x.appendChild(self.dom.createElement(self.mathml_tag(e))) for arg in e.args: x.appendChild(self._print(arg)) return x def _print_Basic(self, e): x = self.dom.createElement(self.mathml_tag(e)) for arg in e.args: x.appendChild(self._print(arg)) return x def _print_AssocOp(self, e): x = self.dom.createElement('apply') x_1 = self.dom.createElement(self.mathml_tag(e)) x.appendChild(x_1) for arg in e.args: x.appendChild(self._print(arg)) return x def _print_Relational(self, e): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement(self.mathml_tag(e))) x.appendChild(self._print(e.lhs)) x.appendChild(self._print(e.rhs)) return x def _print_list(self, seq): """MathML reference for the element: http://www.w3.org/TR/MathML2/chapter4.html#contm.list""" dom_element = self.dom.createElement('list') for item in seq: dom_element.appendChild(self._print(item)) return dom_element def _print_int(self, p): dom_element = self.dom.createElement(self.mathml_tag(p)) dom_element.appendChild(self.dom.createTextNode(str(p))) return dom_element _print_Implies = _print_AssocOp _print_Not = _print_AssocOp _print_Xor = _print_AssocOp def _print_FiniteSet(self, e): x = self.dom.createElement('set') for arg in e.args: x.appendChild(self._print(arg)) return x def _print_Complement(self, e): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('setdiff')) for arg in e.args: x.appendChild(self._print(arg)) return x def _print_ProductSet(self, e): x = self.dom.createElement('apply') x.appendChild(self.dom.createElement('cartesianproduct')) for arg in e.args: x.appendChild(self._print(arg)) return x # XXX Symmetric difference is not supported for MathML content printers. class MathMLPresentationPrinter(MathMLPrinterBase): """Prints an expression to the Presentation MathML markup language. References: https://www.w3.org/TR/MathML2/chapter3.html """ printmethod = "_mathml_presentation" def mathml_tag(self, e): """Returns the MathML tag for an expression.""" translate = { 'Number': 'mn', 'Limit': '→', 'Derivative': 'ⅆ', 'int': 'mn', 'Symbol': 'mi', 'Integral': '∫', 'Sum': '∑', 'sin': 'sin', 'cos': 'cos', 'tan': 'tan', 'cot': 'cot', 'asin': 'arcsin', 'asinh': 'arcsinh', 'acos': 'arccos', 'acosh': 'arccosh', 'atan': 'arctan', 'atanh': 'arctanh', 'acot': 'arccot', 'atan2': 'arctan', 'Equality': '=', 'Unequality': '≠', 'GreaterThan': '≥', 'LessThan': '≤', 'StrictGreaterThan': '>', 'StrictLessThan': '<', 'lerchphi': 'Φ', 'zeta': 'ζ', 'dirichlet_eta': 'η', 'elliptic_k': 'Κ', 'lowergamma': 'γ', 'uppergamma': 'Γ', 'gamma': 'Γ', 'totient': 'ϕ', 'reduced_totient': 'λ', 'primenu': 'ν', 'primeomega': 'Ω', 'fresnels': 'S', 'fresnelc': 'C', 'LambertW': 'W', 'Heaviside': 'Θ', 'BooleanTrue': 'True', 'BooleanFalse': 'False', 'NoneType': 'None', 'mathieus': 'S', 'mathieuc': 'C', 'mathieusprime': 'S′', 'mathieucprime': 'C′', } def mul_symbol_selection(): if (self._settings["mul_symbol"] is None or self._settings["mul_symbol"] == 'None'): return '⁢' elif self._settings["mul_symbol"] == 'times': return '×' elif self._settings["mul_symbol"] == 'dot': return '·' elif self._settings["mul_symbol"] == 'ldot': return '․' elif not isinstance(self._settings["mul_symbol"], str): raise TypeError else: return self._settings["mul_symbol"] for cls in e.__class__.__mro__: n = cls.__name__ if n in translate: return translate[n] # Not found in the MRO set if e.__class__.__name__ == "Mul": return mul_symbol_selection() n = e.__class__.__name__ return n.lower() def parenthesize(self, item, level, strict=False): prec_val = precedence_traditional(item) if (prec_val < level) or ((not strict) and prec_val <= level): brac = self.dom.createElement('mfenced') brac.appendChild(self._print(item)) return brac else: return self._print(item) def _print_Mul(self, expr): def multiply(expr, mrow): from sympy.simplify import fraction numer, denom = fraction(expr) if denom is not S.One: frac = self.dom.createElement('mfrac') if self._settings["fold_short_frac"] and len(str(expr)) < 7: frac.setAttribute('bevelled', 'true') xnum = self._print(numer) xden = self._print(denom) frac.appendChild(xnum) frac.appendChild(xden) mrow.appendChild(frac) return mrow coeff, terms = expr.as_coeff_mul() if coeff is S.One and len(terms) == 1: mrow.appendChild(self._print(terms[0])) return mrow if self.order != 'old': terms = Mul._from_args(terms).as_ordered_factors() if coeff != 1: x = self._print(coeff) y = self.dom.createElement('mo') y.appendChild(self.dom.createTextNode(self.mathml_tag(expr))) mrow.appendChild(x) mrow.appendChild(y) for term in terms: mrow.appendChild(self.parenthesize(term, PRECEDENCE['Mul'])) if not term == terms[-1]: y = self.dom.createElement('mo') y.appendChild(self.dom.createTextNode(self.mathml_tag(expr))) mrow.appendChild(y) return mrow mrow = self.dom.createElement('mrow') if _coeff_isneg(expr): x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('-')) mrow.appendChild(x) mrow = multiply(-expr, mrow) else: mrow = multiply(expr, mrow) return mrow def _print_Add(self, expr, order=None): mrow = self.dom.createElement('mrow') args = self._as_ordered_terms(expr, order=order) mrow.appendChild(self._print(args[0])) for arg in args[1:]: if _coeff_isneg(arg): # use minus x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('-')) y = self._print(-arg) # invert expression since this is now minused else: x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('+')) y = self._print(arg) mrow.appendChild(x) mrow.appendChild(y) return mrow def _print_MatrixBase(self, m): table = self.dom.createElement('mtable') for i in range(m.rows): x = self.dom.createElement('mtr') for j in range(m.cols): y = self.dom.createElement('mtd') y.appendChild(self._print(m[i, j])) x.appendChild(y) table.appendChild(x) if self._settings["mat_delim"] == '': return table brac = self.dom.createElement('mfenced') if self._settings["mat_delim"] == "[": brac.setAttribute('close', ']') brac.setAttribute('open', '[') brac.appendChild(table) return brac def _get_printed_Rational(self, e, folded=None): if e.p < 0: p = -e.p else: p = e.p x = self.dom.createElement('mfrac') if folded or self._settings["fold_short_frac"]: x.setAttribute('bevelled', 'true') x.appendChild(self._print(p)) x.appendChild(self._print(e.q)) if e.p < 0: mrow = self.dom.createElement('mrow') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('-')) mrow.appendChild(mo) mrow.appendChild(x) return mrow else: return x def _print_Rational(self, e): if e.q == 1: # don't divide return self._print(e.p) return self._get_printed_Rational(e, self._settings["fold_short_frac"]) def _print_Limit(self, e): mrow = self.dom.createElement('mrow') munder = self.dom.createElement('munder') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode('lim')) x = self.dom.createElement('mrow') x_1 = self._print(e.args[1]) arrow = self.dom.createElement('mo') arrow.appendChild(self.dom.createTextNode(self.mathml_tag(e))) x_2 = self._print(e.args[2]) x.appendChild(x_1) x.appendChild(arrow) x.appendChild(x_2) munder.appendChild(mi) munder.appendChild(x) mrow.appendChild(munder) mrow.appendChild(self._print(e.args[0])) return mrow def _print_ImaginaryUnit(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('ⅈ')) return x def _print_GoldenRatio(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('Φ')) return x def _print_Exp1(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('ⅇ')) return x def _print_Pi(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('π')) return x def _print_Infinity(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('∞')) return x def _print_NegativeInfinity(self, e): mrow = self.dom.createElement('mrow') y = self.dom.createElement('mo') y.appendChild(self.dom.createTextNode('-')) x = self._print_Infinity(e) mrow.appendChild(y) mrow.appendChild(x) return mrow def _print_HBar(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('ℏ')) return x def _print_EulerGamma(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('γ')) return x def _print_TribonacciConstant(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('TribonacciConstant')) return x def _print_Dagger(self, e): msup = self.dom.createElement('msup') msup.appendChild(self._print(e.args[0])) msup.appendChild(self.dom.createTextNode('†')) return msup def _print_Contains(self, e): mrow = self.dom.createElement('mrow') mrow.appendChild(self._print(e.args[0])) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('∈')) mrow.appendChild(mo) mrow.appendChild(self._print(e.args[1])) return mrow def _print_HilbertSpace(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('ℋ')) return x def _print_ComplexSpace(self, e): msup = self.dom.createElement('msup') msup.appendChild(self.dom.createTextNode('𝒞')) msup.appendChild(self._print(e.args[0])) return msup def _print_FockSpace(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('ℱ')) return x def _print_Integral(self, expr): intsymbols = {1: "∫", 2: "∬", 3: "∭"} mrow = self.dom.createElement('mrow') if len(expr.limits) <= 3 and all(len(lim) == 1 for lim in expr.limits): # Only up to three-integral signs exists mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode(intsymbols[len(expr.limits)])) mrow.appendChild(mo) else: # Either more than three or limits provided for lim in reversed(expr.limits): mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode(intsymbols[1])) if len(lim) == 1: mrow.appendChild(mo) if len(lim) == 2: msup = self.dom.createElement('msup') msup.appendChild(mo) msup.appendChild(self._print(lim[1])) mrow.appendChild(msup) if len(lim) == 3: msubsup = self.dom.createElement('msubsup') msubsup.appendChild(mo) msubsup.appendChild(self._print(lim[1])) msubsup.appendChild(self._print(lim[2])) mrow.appendChild(msubsup) # print function mrow.appendChild(self.parenthesize(expr.function, PRECEDENCE["Mul"], strict=True)) # print integration variables for lim in reversed(expr.limits): d = self.dom.createElement('mo') d.appendChild(self.dom.createTextNode('ⅆ')) mrow.appendChild(d) mrow.appendChild(self._print(lim[0])) return mrow def _print_Sum(self, e): limits = list(e.limits) subsup = self.dom.createElement('munderover') low_elem = self._print(limits[0][1]) up_elem = self._print(limits[0][2]) summand = self.dom.createElement('mo') summand.appendChild(self.dom.createTextNode(self.mathml_tag(e))) low = self.dom.createElement('mrow') var = self._print(limits[0][0]) equal = self.dom.createElement('mo') equal.appendChild(self.dom.createTextNode('=')) low.appendChild(var) low.appendChild(equal) low.appendChild(low_elem) subsup.appendChild(summand) subsup.appendChild(low) subsup.appendChild(up_elem) mrow = self.dom.createElement('mrow') mrow.appendChild(subsup) if len(str(e.function)) == 1: mrow.appendChild(self._print(e.function)) else: fence = self.dom.createElement('mfenced') fence.appendChild(self._print(e.function)) mrow.appendChild(fence) return mrow def _print_Symbol(self, sym, style='plain'): def join(items): if len(items) > 1: mrow = self.dom.createElement('mrow') for i, item in enumerate(items): if i > 0: mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode(" ")) mrow.appendChild(mo) mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(item)) mrow.appendChild(mi) return mrow else: mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(items[0])) return mi # translate name, supers and subs to unicode characters def translate(s): if s in greek_unicode: return greek_unicode.get(s) else: return s name, supers, subs = split_super_sub(sym.name) name = translate(name) supers = [translate(sup) for sup in supers] subs = [translate(sub) for sub in subs] mname = self.dom.createElement('mi') mname.appendChild(self.dom.createTextNode(name)) if len(supers) == 0: if len(subs) == 0: x = mname else: x = self.dom.createElement('msub') x.appendChild(mname) x.appendChild(join(subs)) else: if len(subs) == 0: x = self.dom.createElement('msup') x.appendChild(mname) x.appendChild(join(supers)) else: x = self.dom.createElement('msubsup') x.appendChild(mname) x.appendChild(join(subs)) x.appendChild(join(supers)) # Set bold font? if style == 'bold': x.setAttribute('mathvariant', 'bold') return x def _print_MatrixSymbol(self, sym): return self._print_Symbol(sym, style=self._settings['mat_symbol_style']) _print_RandomSymbol = _print_Symbol def _print_conjugate(self, expr): enc = self.dom.createElement('menclose') enc.setAttribute('notation', 'top') enc.appendChild(self._print(expr.args[0])) return enc def _print_operator_after(self, op, expr): row = self.dom.createElement('mrow') row.appendChild(self.parenthesize(expr, PRECEDENCE["Func"])) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode(op)) row.appendChild(mo) return row def _print_factorial(self, expr): return self._print_operator_after('!', expr.args[0]) def _print_factorial2(self, expr): return self._print_operator_after('!!', expr.args[0]) def _print_binomial(self, expr): brac = self.dom.createElement('mfenced') frac = self.dom.createElement('mfrac') frac.setAttribute('linethickness', '0') frac.appendChild(self._print(expr.args[0])) frac.appendChild(self._print(expr.args[1])) brac.appendChild(frac) return brac def _print_Pow(self, e): # Here we use root instead of power if the exponent is the # reciprocal of an integer if (e.exp.is_Rational and abs(e.exp.p) == 1 and e.exp.q != 1 and self._settings['root_notation']): if e.exp.q == 2: x = self.dom.createElement('msqrt') x.appendChild(self._print(e.base)) if e.exp.q != 2: x = self.dom.createElement('mroot') x.appendChild(self._print(e.base)) x.appendChild(self._print(e.exp.q)) if e.exp.p == -1: frac = self.dom.createElement('mfrac') frac.appendChild(self._print(1)) frac.appendChild(x) return frac else: return x if e.exp.is_Rational and e.exp.q != 1: if e.exp.is_negative: top = self.dom.createElement('mfrac') top.appendChild(self._print(1)) x = self.dom.createElement('msup') x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) x.appendChild(self._get_printed_Rational(-e.exp, self._settings['fold_frac_powers'])) top.appendChild(x) return top else: x = self.dom.createElement('msup') x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) x.appendChild(self._get_printed_Rational(e.exp, self._settings['fold_frac_powers'])) return x if e.exp.is_negative: top = self.dom.createElement('mfrac') top.appendChild(self._print(1)) if e.exp == -1: top.appendChild(self._print(e.base)) else: x = self.dom.createElement('msup') x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) x.appendChild(self._print(-e.exp)) top.appendChild(x) return top x = self.dom.createElement('msup') x.appendChild(self.parenthesize(e.base, PRECEDENCE['Pow'])) x.appendChild(self._print(e.exp)) return x def _print_Number(self, e): x = self.dom.createElement(self.mathml_tag(e)) x.appendChild(self.dom.createTextNode(str(e))) return x def _print_AccumulationBounds(self, i): brac = self.dom.createElement('mfenced') brac.setAttribute('close', '\u27e9') brac.setAttribute('open', '\u27e8') brac.appendChild(self._print(i.min)) brac.appendChild(self._print(i.max)) return brac def _print_Derivative(self, e): if requires_partial(e.expr): d = '∂' else: d = self.mathml_tag(e) # Determine denominator m = self.dom.createElement('mrow') dim = 0 # Total diff dimension, for numerator for sym, num in reversed(e.variable_count): dim += num if num >= 2: x = self.dom.createElement('msup') xx = self.dom.createElement('mo') xx.appendChild(self.dom.createTextNode(d)) x.appendChild(xx) x.appendChild(self._print(num)) else: x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode(d)) m.appendChild(x) y = self._print(sym) m.appendChild(y) mnum = self.dom.createElement('mrow') if dim >= 2: x = self.dom.createElement('msup') xx = self.dom.createElement('mo') xx.appendChild(self.dom.createTextNode(d)) x.appendChild(xx) x.appendChild(self._print(dim)) else: x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode(d)) mnum.appendChild(x) mrow = self.dom.createElement('mrow') frac = self.dom.createElement('mfrac') frac.appendChild(mnum) frac.appendChild(m) mrow.appendChild(frac) # Print function mrow.appendChild(self._print(e.expr)) return mrow def _print_Function(self, e): mrow = self.dom.createElement('mrow') x = self.dom.createElement('mi') if self.mathml_tag(e) == 'log' and self._settings["ln_notation"]: x.appendChild(self.dom.createTextNode('ln')) else: x.appendChild(self.dom.createTextNode(self.mathml_tag(e))) y = self.dom.createElement('mfenced') for arg in e.args: y.appendChild(self._print(arg)) mrow.appendChild(x) mrow.appendChild(y) return mrow def _print_Float(self, expr): # Based off of that in StrPrinter dps = prec_to_dps(expr._prec) str_real = mlib.to_str(expr._mpf_, dps, strip_zeros=True) # Must always have a mul symbol (as 2.5 10^{20} just looks odd) # thus we use the number separator separator = self._settings['mul_symbol_mathml_numbers'] mrow = self.dom.createElement('mrow') if 'e' in str_real: (mant, exp) = str_real.split('e') if exp[0] == '+': exp = exp[1:] mn = self.dom.createElement('mn') mn.appendChild(self.dom.createTextNode(mant)) mrow.appendChild(mn) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode(separator)) mrow.appendChild(mo) msup = self.dom.createElement('msup') mn = self.dom.createElement('mn') mn.appendChild(self.dom.createTextNode("10")) msup.appendChild(mn) mn = self.dom.createElement('mn') mn.appendChild(self.dom.createTextNode(exp)) msup.appendChild(mn) mrow.appendChild(msup) return mrow elif str_real == "+inf": return self._print_Infinity(None) elif str_real == "-inf": return self._print_NegativeInfinity(None) else: mn = self.dom.createElement('mn') mn.appendChild(self.dom.createTextNode(str_real)) return mn def _print_polylog(self, expr): mrow = self.dom.createElement('mrow') m = self.dom.createElement('msub') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode('Li')) m.appendChild(mi) m.appendChild(self._print(expr.args[0])) mrow.appendChild(m) brac = self.dom.createElement('mfenced') brac.appendChild(self._print(expr.args[1])) mrow.appendChild(brac) return mrow def _print_Basic(self, e): mrow = self.dom.createElement('mrow') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) mrow.appendChild(mi) brac = self.dom.createElement('mfenced') for arg in e.args: brac.appendChild(self._print(arg)) mrow.appendChild(brac) return mrow def _print_Tuple(self, e): mrow = self.dom.createElement('mrow') x = self.dom.createElement('mfenced') for arg in e.args: x.appendChild(self._print(arg)) mrow.appendChild(x) return mrow def _print_Interval(self, i): mrow = self.dom.createElement('mrow') brac = self.dom.createElement('mfenced') if i.start == i.end: # Most often, this type of Interval is converted to a FiniteSet brac.setAttribute('close', '}') brac.setAttribute('open', '{') brac.appendChild(self._print(i.start)) else: if i.right_open: brac.setAttribute('close', ')') else: brac.setAttribute('close', ']') if i.left_open: brac.setAttribute('open', '(') else: brac.setAttribute('open', '[') brac.appendChild(self._print(i.start)) brac.appendChild(self._print(i.end)) mrow.appendChild(brac) return mrow def _print_Abs(self, expr, exp=None): mrow = self.dom.createElement('mrow') x = self.dom.createElement('mfenced') x.setAttribute('close', '|') x.setAttribute('open', '|') x.appendChild(self._print(expr.args[0])) mrow.appendChild(x) return mrow _print_Determinant = _print_Abs def _print_re_im(self, c, expr): mrow = self.dom.createElement('mrow') mi = self.dom.createElement('mi') mi.setAttribute('mathvariant', 'fraktur') mi.appendChild(self.dom.createTextNode(c)) mrow.appendChild(mi) brac = self.dom.createElement('mfenced') brac.appendChild(self._print(expr)) mrow.appendChild(brac) return mrow def _print_re(self, expr, exp=None): return self._print_re_im('R', expr.args[0]) def _print_im(self, expr, exp=None): return self._print_re_im('I', expr.args[0]) def _print_AssocOp(self, e): mrow = self.dom.createElement('mrow') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) mrow.appendChild(mi) for arg in e.args: mrow.appendChild(self._print(arg)) return mrow def _print_SetOp(self, expr, symbol, prec): mrow = self.dom.createElement('mrow') mrow.appendChild(self.parenthesize(expr.args[0], prec)) for arg in expr.args[1:]: x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode(symbol)) y = self.parenthesize(arg, prec) mrow.appendChild(x) mrow.appendChild(y) return mrow def _print_Union(self, expr): prec = PRECEDENCE_TRADITIONAL['Union'] return self._print_SetOp(expr, '∪', prec) def _print_Intersection(self, expr): prec = PRECEDENCE_TRADITIONAL['Intersection'] return self._print_SetOp(expr, '∩', prec) def _print_Complement(self, expr): prec = PRECEDENCE_TRADITIONAL['Complement'] return self._print_SetOp(expr, '∖', prec) def _print_SymmetricDifference(self, expr): prec = PRECEDENCE_TRADITIONAL['SymmetricDifference'] return self._print_SetOp(expr, '∆', prec) def _print_ProductSet(self, expr): prec = PRECEDENCE_TRADITIONAL['ProductSet'] return self._print_SetOp(expr, '×', prec) def _print_FiniteSet(self, s): return self._print_set(s.args) def _print_set(self, s): items = sorted(s, key=default_sort_key) brac = self.dom.createElement('mfenced') brac.setAttribute('close', '}') brac.setAttribute('open', '{') for item in items: brac.appendChild(self._print(item)) return brac _print_frozenset = _print_set def _print_LogOp(self, args, symbol): mrow = self.dom.createElement('mrow') if args[0].is_Boolean and not args[0].is_Not: brac = self.dom.createElement('mfenced') brac.appendChild(self._print(args[0])) mrow.appendChild(brac) else: mrow.appendChild(self._print(args[0])) for arg in args[1:]: x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode(symbol)) if arg.is_Boolean and not arg.is_Not: y = self.dom.createElement('mfenced') y.appendChild(self._print(arg)) else: y = self._print(arg) mrow.appendChild(x) mrow.appendChild(y) return mrow def _print_BasisDependent(self, expr): from sympy.vector import Vector if expr == expr.zero: # Not clear if this is ever called return self._print(expr.zero) if isinstance(expr, Vector): items = expr.separate().items() else: items = [(0, expr)] mrow = self.dom.createElement('mrow') for system, vect in items: inneritems = list(vect.components.items()) inneritems.sort(key = lambda x:x[0].__str__()) for i, (k, v) in enumerate(inneritems): if v == 1: if i: # No + for first item mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('+')) mrow.appendChild(mo) mrow.appendChild(self._print(k)) elif v == -1: mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('-')) mrow.appendChild(mo) mrow.appendChild(self._print(k)) else: if i: # No + for first item mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('+')) mrow.appendChild(mo) mbrac = self.dom.createElement('mfenced') mbrac.appendChild(self._print(v)) mrow.appendChild(mbrac) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('⁢')) mrow.appendChild(mo) mrow.appendChild(self._print(k)) return mrow def _print_And(self, expr): args = sorted(expr.args, key=default_sort_key) return self._print_LogOp(args, '∧') def _print_Or(self, expr): args = sorted(expr.args, key=default_sort_key) return self._print_LogOp(args, '∨') def _print_Xor(self, expr): args = sorted(expr.args, key=default_sort_key) return self._print_LogOp(args, '⊻') def _print_Implies(self, expr): return self._print_LogOp(expr.args, '⇒') def _print_Equivalent(self, expr): args = sorted(expr.args, key=default_sort_key) return self._print_LogOp(args, '⇔') def _print_Not(self, e): mrow = self.dom.createElement('mrow') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('¬')) mrow.appendChild(mo) if (e.args[0].is_Boolean): x = self.dom.createElement('mfenced') x.appendChild(self._print(e.args[0])) else: x = self._print(e.args[0]) mrow.appendChild(x) return mrow def _print_bool(self, e): mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) return mi _print_BooleanTrue = _print_bool _print_BooleanFalse = _print_bool def _print_NoneType(self, e): mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(self.mathml_tag(e))) return mi def _print_Range(self, s): dots = "\u2026" brac = self.dom.createElement('mfenced') brac.setAttribute('close', '}') brac.setAttribute('open', '{') if s.start.is_infinite and s.stop.is_infinite: if s.step.is_positive: printset = dots, -1, 0, 1, dots else: printset = dots, 1, 0, -1, dots elif s.start.is_infinite: printset = dots, s[-1] - s.step, s[-1] elif s.stop.is_infinite: it = iter(s) printset = next(it), next(it), dots elif len(s) > 4: it = iter(s) printset = next(it), next(it), dots, s[-1] else: printset = tuple(s) for el in printset: if el == dots: mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(dots)) brac.appendChild(mi) else: brac.appendChild(self._print(el)) return brac def _hprint_variadic_function(self, expr): args = sorted(expr.args, key=default_sort_key) mrow = self.dom.createElement('mrow') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode((str(expr.func)).lower())) mrow.appendChild(mo) brac = self.dom.createElement('mfenced') for symbol in args: brac.appendChild(self._print(symbol)) mrow.appendChild(brac) return mrow _print_Min = _print_Max = _hprint_variadic_function def _print_exp(self, expr): msup = self.dom.createElement('msup') msup.appendChild(self._print_Exp1(None)) msup.appendChild(self._print(expr.args[0])) return msup def _print_Relational(self, e): mrow = self.dom.createElement('mrow') mrow.appendChild(self._print(e.lhs)) x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode(self.mathml_tag(e))) mrow.appendChild(x) mrow.appendChild(self._print(e.rhs)) return mrow def _print_int(self, p): dom_element = self.dom.createElement(self.mathml_tag(p)) dom_element.appendChild(self.dom.createTextNode(str(p))) return dom_element def _print_BaseScalar(self, e): msub = self.dom.createElement('msub') index, system = e._id mi = self.dom.createElement('mi') mi.setAttribute('mathvariant', 'bold') mi.appendChild(self.dom.createTextNode(system._variable_names[index])) msub.appendChild(mi) mi = self.dom.createElement('mi') mi.setAttribute('mathvariant', 'bold') mi.appendChild(self.dom.createTextNode(system._name)) msub.appendChild(mi) return msub def _print_BaseVector(self, e): msub = self.dom.createElement('msub') index, system = e._id mover = self.dom.createElement('mover') mi = self.dom.createElement('mi') mi.setAttribute('mathvariant', 'bold') mi.appendChild(self.dom.createTextNode(system._vector_names[index])) mover.appendChild(mi) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('^')) mover.appendChild(mo) msub.appendChild(mover) mi = self.dom.createElement('mi') mi.setAttribute('mathvariant', 'bold') mi.appendChild(self.dom.createTextNode(system._name)) msub.appendChild(mi) return msub def _print_VectorZero(self, e): mover = self.dom.createElement('mover') mi = self.dom.createElement('mi') mi.setAttribute('mathvariant', 'bold') mi.appendChild(self.dom.createTextNode("0")) mover.appendChild(mi) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('^')) mover.appendChild(mo) return mover def _print_Cross(self, expr): mrow = self.dom.createElement('mrow') vec1 = expr._expr1 vec2 = expr._expr2 mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul'])) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('×')) mrow.appendChild(mo) mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul'])) return mrow def _print_Curl(self, expr): mrow = self.dom.createElement('mrow') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('∇')) mrow.appendChild(mo) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('×')) mrow.appendChild(mo) mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) return mrow def _print_Divergence(self, expr): mrow = self.dom.createElement('mrow') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('∇')) mrow.appendChild(mo) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('·')) mrow.appendChild(mo) mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) return mrow def _print_Dot(self, expr): mrow = self.dom.createElement('mrow') vec1 = expr._expr1 vec2 = expr._expr2 mrow.appendChild(self.parenthesize(vec1, PRECEDENCE['Mul'])) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('·')) mrow.appendChild(mo) mrow.appendChild(self.parenthesize(vec2, PRECEDENCE['Mul'])) return mrow def _print_Gradient(self, expr): mrow = self.dom.createElement('mrow') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('∇')) mrow.appendChild(mo) mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) return mrow def _print_Laplacian(self, expr): mrow = self.dom.createElement('mrow') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('∆')) mrow.appendChild(mo) mrow.appendChild(self.parenthesize(expr._expr, PRECEDENCE['Mul'])) return mrow def _print_Integers(self, e): x = self.dom.createElement('mi') x.setAttribute('mathvariant', 'normal') x.appendChild(self.dom.createTextNode('ℤ')) return x def _print_Complexes(self, e): x = self.dom.createElement('mi') x.setAttribute('mathvariant', 'normal') x.appendChild(self.dom.createTextNode('ℂ')) return x def _print_Reals(self, e): x = self.dom.createElement('mi') x.setAttribute('mathvariant', 'normal') x.appendChild(self.dom.createTextNode('ℝ')) return x def _print_Naturals(self, e): x = self.dom.createElement('mi') x.setAttribute('mathvariant', 'normal') x.appendChild(self.dom.createTextNode('ℕ')) return x def _print_Naturals0(self, e): sub = self.dom.createElement('msub') x = self.dom.createElement('mi') x.setAttribute('mathvariant', 'normal') x.appendChild(self.dom.createTextNode('ℕ')) sub.appendChild(x) sub.appendChild(self._print(S.Zero)) return sub def _print_SingularityFunction(self, expr): shift = expr.args[0] - expr.args[1] power = expr.args[2] sup = self.dom.createElement('msup') brac = self.dom.createElement('mfenced') brac.setAttribute('close', '\u27e9') brac.setAttribute('open', '\u27e8') brac.appendChild(self._print(shift)) sup.appendChild(brac) sup.appendChild(self._print(power)) return sup def _print_NaN(self, e): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('NaN')) return x def _print_number_function(self, e, name): # Print name_arg[0] for one argument or name_arg[0](arg[1]) # for more than one argument sub = self.dom.createElement('msub') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode(name)) sub.appendChild(mi) sub.appendChild(self._print(e.args[0])) if len(e.args) == 1: return sub # TODO: copy-pasted from _print_Function: can we do better? mrow = self.dom.createElement('mrow') y = self.dom.createElement('mfenced') for arg in e.args[1:]: y.appendChild(self._print(arg)) mrow.appendChild(sub) mrow.appendChild(y) return mrow def _print_bernoulli(self, e): return self._print_number_function(e, 'B') _print_bell = _print_bernoulli def _print_catalan(self, e): return self._print_number_function(e, 'C') def _print_euler(self, e): return self._print_number_function(e, 'E') def _print_fibonacci(self, e): return self._print_number_function(e, 'F') def _print_lucas(self, e): return self._print_number_function(e, 'L') def _print_stieltjes(self, e): return self._print_number_function(e, 'γ') def _print_tribonacci(self, e): return self._print_number_function(e, 'T') def _print_ComplexInfinity(self, e): x = self.dom.createElement('mover') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('∞')) x.appendChild(mo) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('~')) x.appendChild(mo) return x def _print_EmptySet(self, e): x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('∅')) return x def _print_UniversalSet(self, e): x = self.dom.createElement('mo') x.appendChild(self.dom.createTextNode('𝕌')) return x def _print_Adjoint(self, expr): from sympy.matrices import MatrixSymbol mat = expr.arg sup = self.dom.createElement('msup') if not isinstance(mat, MatrixSymbol): brac = self.dom.createElement('mfenced') brac.appendChild(self._print(mat)) sup.appendChild(brac) else: sup.appendChild(self._print(mat)) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('†')) sup.appendChild(mo) return sup def _print_Transpose(self, expr): from sympy.matrices import MatrixSymbol mat = expr.arg sup = self.dom.createElement('msup') if not isinstance(mat, MatrixSymbol): brac = self.dom.createElement('mfenced') brac.appendChild(self._print(mat)) sup.appendChild(brac) else: sup.appendChild(self._print(mat)) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('T')) sup.appendChild(mo) return sup def _print_Inverse(self, expr): from sympy.matrices import MatrixSymbol mat = expr.arg sup = self.dom.createElement('msup') if not isinstance(mat, MatrixSymbol): brac = self.dom.createElement('mfenced') brac.appendChild(self._print(mat)) sup.appendChild(brac) else: sup.appendChild(self._print(mat)) sup.appendChild(self._print(-1)) return sup def _print_MatMul(self, expr): from sympy import MatMul x = self.dom.createElement('mrow') args = expr.args if isinstance(args[0], Mul): args = args[0].as_ordered_factors() + list(args[1:]) else: args = list(args) if isinstance(expr, MatMul) and _coeff_isneg(expr): if args[0] == -1: args = args[1:] else: args[0] = -args[0] mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('-')) x.appendChild(mo) for arg in args[:-1]: x.appendChild(self.parenthesize(arg, precedence_traditional(expr), False)) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('⁢')) x.appendChild(mo) x.appendChild(self.parenthesize(args[-1], precedence_traditional(expr), False)) return x def _print_MatPow(self, expr): from sympy.matrices import MatrixSymbol base, exp = expr.base, expr.exp sup = self.dom.createElement('msup') if not isinstance(base, MatrixSymbol): brac = self.dom.createElement('mfenced') brac.appendChild(self._print(base)) sup.appendChild(brac) else: sup.appendChild(self._print(base)) sup.appendChild(self._print(exp)) return sup def _print_HadamardProduct(self, expr): x = self.dom.createElement('mrow') args = expr.args for arg in args[:-1]: x.appendChild( self.parenthesize(arg, precedence_traditional(expr), False)) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('∘')) x.appendChild(mo) x.appendChild( self.parenthesize(args[-1], precedence_traditional(expr), False)) return x def _print_ZeroMatrix(self, Z): x = self.dom.createElement('mn') x.appendChild(self.dom.createTextNode('𝟘')) return x def _print_OneMatrix(self, Z): x = self.dom.createElement('mn') x.appendChild(self.dom.createTextNode('𝟙')) return x def _print_Identity(self, I): x = self.dom.createElement('mi') x.appendChild(self.dom.createTextNode('𝕀')) return x def _print_floor(self, e): mrow = self.dom.createElement('mrow') x = self.dom.createElement('mfenced') x.setAttribute('close', '\u230B') x.setAttribute('open', '\u230A') x.appendChild(self._print(e.args[0])) mrow.appendChild(x) return mrow def _print_ceiling(self, e): mrow = self.dom.createElement('mrow') x = self.dom.createElement('mfenced') x.setAttribute('close', '\u2309') x.setAttribute('open', '\u2308') x.appendChild(self._print(e.args[0])) mrow.appendChild(x) return mrow def _print_Lambda(self, e): x = self.dom.createElement('mfenced') mrow = self.dom.createElement('mrow') symbols = e.args[0] if len(symbols) == 1: symbols = self._print(symbols[0]) else: symbols = self._print(symbols) mrow.appendChild(symbols) mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('↦')) mrow.appendChild(mo) mrow.appendChild(self._print(e.args[1])) x.appendChild(mrow) return x def _print_tuple(self, e): x = self.dom.createElement('mfenced') for i in e: x.appendChild(self._print(i)) return x def _print_IndexedBase(self, e): return self._print(e.label) def _print_Indexed(self, e): x = self.dom.createElement('msub') x.appendChild(self._print(e.base)) if len(e.indices) == 1: x.appendChild(self._print(e.indices[0])) return x x.appendChild(self._print(e.indices)) return x def _print_MatrixElement(self, e): x = self.dom.createElement('msub') x.appendChild(self.parenthesize(e.parent, PRECEDENCE["Atom"], strict = True)) brac = self.dom.createElement('mfenced') brac.setAttribute("close", "") brac.setAttribute("open", "") for i in e.indices: brac.appendChild(self._print(i)) x.appendChild(brac) return x def _print_elliptic_f(self, e): x = self.dom.createElement('mrow') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode('𝖥')) x.appendChild(mi) y = self.dom.createElement('mfenced') y.setAttribute("separators", "|") for i in e.args: y.appendChild(self._print(i)) x.appendChild(y) return x def _print_elliptic_e(self, e): x = self.dom.createElement('mrow') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode('𝖤')) x.appendChild(mi) y = self.dom.createElement('mfenced') y.setAttribute("separators", "|") for i in e.args: y.appendChild(self._print(i)) x.appendChild(y) return x def _print_elliptic_pi(self, e): x = self.dom.createElement('mrow') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode('𝛱')) x.appendChild(mi) y = self.dom.createElement('mfenced') if len(e.args) == 2: y.setAttribute("separators", "|") else: y.setAttribute("separators", ";|") for i in e.args: y.appendChild(self._print(i)) x.appendChild(y) return x def _print_Ei(self, e): x = self.dom.createElement('mrow') mi = self.dom.createElement('mi') mi.appendChild(self.dom.createTextNode('Ei')) x.appendChild(mi) x.appendChild(self._print(e.args)) return x def _print_expint(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msub') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('E')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) x.appendChild(y) x.appendChild(self._print(e.args[1:])) return x def _print_jacobi(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msubsup') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('P')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) y.appendChild(self._print(e.args[1:3])) x.appendChild(y) x.appendChild(self._print(e.args[3:])) return x def _print_gegenbauer(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msubsup') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('C')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) y.appendChild(self._print(e.args[1:2])) x.appendChild(y) x.appendChild(self._print(e.args[2:])) return x def _print_chebyshevt(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msub') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('T')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) x.appendChild(y) x.appendChild(self._print(e.args[1:])) return x def _print_chebyshevu(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msub') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('U')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) x.appendChild(y) x.appendChild(self._print(e.args[1:])) return x def _print_legendre(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msub') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('P')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) x.appendChild(y) x.appendChild(self._print(e.args[1:])) return x def _print_assoc_legendre(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msubsup') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('P')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) y.appendChild(self._print(e.args[1:2])) x.appendChild(y) x.appendChild(self._print(e.args[2:])) return x def _print_laguerre(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msub') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('L')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) x.appendChild(y) x.appendChild(self._print(e.args[1:])) return x def _print_assoc_laguerre(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msubsup') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('L')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) y.appendChild(self._print(e.args[1:2])) x.appendChild(y) x.appendChild(self._print(e.args[2:])) return x def _print_hermite(self, e): x = self.dom.createElement('mrow') y = self.dom.createElement('msub') mo = self.dom.createElement('mo') mo.appendChild(self.dom.createTextNode('H')) y.appendChild(mo) y.appendChild(self._print(e.args[0])) x.appendChild(y) x.appendChild(self._print(e.args[1:])) return x @print_function(MathMLPrinterBase) def mathml(expr, printer='content', **settings): """Returns the MathML representation of expr. If printer is presentation then prints Presentation MathML else prints content MathML. """ if printer == 'presentation': return MathMLPresentationPrinter(settings).doprint(expr) else: return MathMLContentPrinter(settings).doprint(expr) def print_mathml(expr, printer='content', **settings): """ Prints a pretty representation of the MathML code for expr. If printer is presentation then prints Presentation MathML else prints content MathML. Examples ======== >>> ## >>> from sympy.printing.mathml import print_mathml >>> from sympy.abc import x >>> print_mathml(x+1) #doctest: +NORMALIZE_WHITESPACE x 1 >>> print_mathml(x+1, printer='presentation') x + 1 """ if printer == 'presentation': s = MathMLPresentationPrinter(settings) else: s = MathMLContentPrinter(settings) xml = s._print(sympify(expr)) s.apply_patch() pretty_xml = xml.toprettyxml() s.restore_patch() print(pretty_xml) # For backward compatibility MathMLPrinter = MathMLContentPrinter sympy-sympy-1.9/sympy/printing/numpy.py000066400000000000000000000457031412543434000204710ustar00rootroot00000000000000from sympy.core import S from .pycode import PythonCodePrinter, _known_functions_math, _print_known_const, _print_known_func, _unpack_integral_limits from .codeprinter import CodePrinter _not_in_numpy = 'erf erfc factorial gamma loggamma'.split() _in_numpy = [(k, v) for k, v in _known_functions_math.items() if k not in _not_in_numpy] _known_functions_numpy = dict(_in_numpy, **{ 'acos': 'arccos', 'acosh': 'arccosh', 'asin': 'arcsin', 'asinh': 'arcsinh', 'atan': 'arctan', 'atan2': 'arctan2', 'atanh': 'arctanh', 'exp2': 'exp2', 'sign': 'sign', 'logaddexp': 'logaddexp', 'logaddexp2': 'logaddexp2', }) _known_constants_numpy = { 'Exp1': 'e', 'Pi': 'pi', 'EulerGamma': 'euler_gamma', 'NaN': 'nan', 'Infinity': 'PINF', 'NegativeInfinity': 'NINF' } _numpy_known_functions = {k: 'numpy.' + v for k, v in _known_functions_numpy.items()} _numpy_known_constants = {k: 'numpy.' + v for k, v in _known_constants_numpy.items()} class NumPyPrinter(PythonCodePrinter): """ Numpy printer which handles vectorized piecewise functions, logical operators, etc. """ _module = 'numpy' _kf = _numpy_known_functions _kc = _numpy_known_constants def __init__(self, settings=None): """ `settings` is passed to CodePrinter.__init__() `module` specifies the array module to use, currently 'NumPy' or 'CuPy' """ self.language = "Python with {}".format(self._module) self.printmethod = "_{}code".format(self._module) self._kf = {**PythonCodePrinter._kf, **self._kf} super().__init__(settings=settings) def _print_seq(self, seq): "General sequence printer: converts to tuple" # Print tuples here instead of lists because numba supports # tuples in nopython mode. delimiter=', ' return '({},)'.format(delimiter.join(self._print(item) for item in seq)) def _print_MatMul(self, expr): "Matrix multiplication printer" if expr.as_coeff_matrices()[0] is not S.One: expr_list = expr.as_coeff_matrices()[1]+[(expr.as_coeff_matrices()[0])] return '({})'.format(').dot('.join(self._print(i) for i in expr_list)) return '({})'.format(').dot('.join(self._print(i) for i in expr.args)) def _print_MatPow(self, expr): "Matrix power printer" return '{}({}, {})'.format(self._module_format(self._module + '.linalg.matrix_power'), self._print(expr.args[0]), self._print(expr.args[1])) def _print_Inverse(self, expr): "Matrix inverse printer" return '{}({})'.format(self._module_format(self._module + '.linalg.inv'), self._print(expr.args[0])) def _print_DotProduct(self, expr): # DotProduct allows any shape order, but numpy.dot does matrix # multiplication, so we have to make sure it gets 1 x n by n x 1. arg1, arg2 = expr.args if arg1.shape[0] != 1: arg1 = arg1.T if arg2.shape[1] != 1: arg2 = arg2.T return "%s(%s, %s)" % (self._module_format(self._module + '.dot'), self._print(arg1), self._print(arg2)) def _print_MatrixSolve(self, expr): return "%s(%s, %s)" % (self._module_format(self._module + '.linalg.solve'), self._print(expr.matrix), self._print(expr.vector)) def _print_ZeroMatrix(self, expr): return '{}({})'.format(self._module_format(self._module + '.zeros'), self._print(expr.shape)) def _print_OneMatrix(self, expr): return '{}({})'.format(self._module_format(self._module + '.ones'), self._print(expr.shape)) def _print_FunctionMatrix(self, expr): from sympy.core.function import Lambda from sympy.abc import i, j lamda = expr.lamda if not isinstance(lamda, Lambda): lamda = Lambda((i, j), lamda(i, j)) return '{}(lambda {}: {}, {})'.format(self._module_format(self._module + '.fromfunction'), ', '.join(self._print(arg) for arg in lamda.args[0]), self._print(lamda.args[1]), self._print(expr.shape)) def _print_HadamardProduct(self, expr): func = self._module_format(self._module + '.multiply') return ''.join('{}({}, '.format(func, self._print(arg)) \ for arg in expr.args[:-1]) + "{}{}".format(self._print(expr.args[-1]), ')' * (len(expr.args) - 1)) def _print_KroneckerProduct(self, expr): func = self._module_format(self._module + '.kron') return ''.join('{}({}, '.format(func, self._print(arg)) \ for arg in expr.args[:-1]) + "{}{}".format(self._print(expr.args[-1]), ')' * (len(expr.args) - 1)) def _print_Adjoint(self, expr): return '{}({}({}))'.format( self._module_format(self._module + '.conjugate'), self._module_format(self._module + '.transpose'), self._print(expr.args[0])) def _print_DiagonalOf(self, expr): vect = '{}({})'.format( self._module_format(self._module + '.diag'), self._print(expr.arg)) return '{}({}, (-1, 1))'.format( self._module_format(self._module + '.reshape'), vect) def _print_DiagMatrix(self, expr): return '{}({})'.format(self._module_format(self._module + '.diagflat'), self._print(expr.args[0])) def _print_DiagonalMatrix(self, expr): return '{}({}, {}({}, {}))'.format(self._module_format(self._module + '.multiply'), self._print(expr.arg), self._module_format(self._module + '.eye'), self._print(expr.shape[0]), self._print(expr.shape[1])) def _print_Piecewise(self, expr): "Piecewise function printer" exprs = '[{}]'.format(','.join(self._print(arg.expr) for arg in expr.args)) conds = '[{}]'.format(','.join(self._print(arg.cond) for arg in expr.args)) # If [default_value, True] is a (expr, cond) sequence in a Piecewise object # it will behave the same as passing the 'default' kwarg to select() # *as long as* it is the last element in expr.args. # If this is not the case, it may be triggered prematurely. return '{}({}, {}, default={})'.format( self._module_format(self._module + '.select'), conds, exprs, self._print(S.NaN)) def _print_Relational(self, expr): "Relational printer for Equality and Unequality" op = { '==' :'equal', '!=' :'not_equal', '<' :'less', '<=' :'less_equal', '>' :'greater', '>=' :'greater_equal', } if expr.rel_op in op: lhs = self._print(expr.lhs) rhs = self._print(expr.rhs) return '{op}({lhs}, {rhs})'.format(op=self._module_format(self._module + '.'+op[expr.rel_op]), lhs=lhs, rhs=rhs) return super()._print_Relational(expr) def _print_And(self, expr): "Logical And printer" # We have to override LambdaPrinter because it uses Python 'and' keyword. # If LambdaPrinter didn't define it, we could use StrPrinter's # version of the function and add 'logical_and' to NUMPY_TRANSLATIONS. return '{}.reduce(({}))'.format(self._module_format(self._module + '.logical_and'), ','.join(self._print(i) for i in expr.args)) def _print_Or(self, expr): "Logical Or printer" # We have to override LambdaPrinter because it uses Python 'or' keyword. # If LambdaPrinter didn't define it, we could use StrPrinter's # version of the function and add 'logical_or' to NUMPY_TRANSLATIONS. return '{}.reduce(({}))'.format(self._module_format(self._module + '.logical_or'), ','.join(self._print(i) for i in expr.args)) def _print_Not(self, expr): "Logical Not printer" # We have to override LambdaPrinter because it uses Python 'not' keyword. # If LambdaPrinter didn't define it, we would still have to define our # own because StrPrinter doesn't define it. return '{}({})'.format(self._module_format(self._module + '.logical_not'), ','.join(self._print(i) for i in expr.args)) def _print_Pow(self, expr, rational=False): # XXX Workaround for negative integer power error from sympy.core.power import Pow if expr.exp.is_integer and expr.exp.is_negative: expr = Pow(expr.base, expr.exp.evalf(), evaluate=False) return self._hprint_Pow(expr, rational=rational, sqrt=self._module + '.sqrt') def _print_Min(self, expr): return '{}(({}), axis=0)'.format(self._module_format(self._module + '.amin'), ','.join(self._print(i) for i in expr.args)) def _print_Max(self, expr): return '{}(({}), axis=0)'.format(self._module_format(self._module + '.amax'), ','.join(self._print(i) for i in expr.args)) def _print_arg(self, expr): return "%s(%s)" % (self._module_format(self._module + '.angle'), self._print(expr.args[0])) def _print_im(self, expr): return "%s(%s)" % (self._module_format(self._module + '.imag'), self._print(expr.args[0])) def _print_Mod(self, expr): return "%s(%s)" % (self._module_format(self._module + '.mod'), ', '.join( map(lambda arg: self._print(arg), expr.args))) def _print_re(self, expr): return "%s(%s)" % (self._module_format(self._module + '.real'), self._print(expr.args[0])) def _print_sinc(self, expr): return "%s(%s)" % (self._module_format(self._module + '.sinc'), self._print(expr.args[0]/S.Pi)) def _print_MatrixBase(self, expr): func = self.known_functions.get(expr.__class__.__name__, None) if func is None: func = self._module_format(self._module + '.array') return "%s(%s)" % (func, self._print(expr.tolist())) def _print_Identity(self, expr): shape = expr.shape if all([dim.is_Integer for dim in shape]): return "%s(%s)" % (self._module_format(self._module + '.eye'), self._print(expr.shape[0])) else: raise NotImplementedError("Symbolic matrix dimensions are not yet supported for identity matrices") def _print_BlockMatrix(self, expr): return '{}({})'.format(self._module_format(self._module + '.block'), self._print(expr.args[0].tolist())) def _print_ArrayTensorProduct(self, expr): array_list = [j for i, arg in enumerate(expr.args) for j in (self._print(arg), "[%i, %i]" % (2*i, 2*i+1))] return "%s(%s)" % (self._module_format(self._module + '.einsum'), ", ".join(array_list)) def _print_ArrayContraction(self, expr): from ..tensor.array.expressions.array_expressions import ArrayTensorProduct base = expr.expr contraction_indices = expr.contraction_indices if not contraction_indices: return self._print(base) if isinstance(base, ArrayTensorProduct): counter = 0 d = {j: min(i) for i in contraction_indices for j in i} indices = [] for rank_arg in base.subranks: lindices = [] for i in range(rank_arg): if counter in d: lindices.append(d[counter]) else: lindices.append(counter) counter += 1 indices.append(lindices) elems = ["%s, %s" % (self._print(arg), ind) for arg, ind in zip(base.args, indices)] return "%s(%s)" % ( self._module_format(self._module + '.einsum'), ", ".join(elems) ) raise NotImplementedError() def _print_ArrayDiagonal(self, expr): diagonal_indices = list(expr.diagonal_indices) if len(diagonal_indices) > 1: # TODO: this should be handled in sympy.codegen.array_utils, # possibly by creating the possibility of unfolding the # ArrayDiagonal object into nested ones. Same reasoning for # the array contraction. raise NotImplementedError if len(diagonal_indices[0]) != 2: raise NotImplementedError return "%s(%s, 0, axis1=%s, axis2=%s)" % ( self._module_format("numpy.diagonal"), self._print(expr.expr), diagonal_indices[0][0], diagonal_indices[0][1], ) def _print_PermuteDims(self, expr): return "%s(%s, %s)" % ( self._module_format("numpy.transpose"), self._print(expr.expr), self._print(expr.permutation.array_form), ) def _print_ArrayAdd(self, expr): return self._expand_fold_binary_op(self._module + '.add', expr.args) _print_lowergamma = CodePrinter._print_not_supported _print_uppergamma = CodePrinter._print_not_supported _print_fresnelc = CodePrinter._print_not_supported _print_fresnels = CodePrinter._print_not_supported for func in _numpy_known_functions: setattr(NumPyPrinter, f'_print_{func}', _print_known_func) for const in _numpy_known_constants: setattr(NumPyPrinter, f'_print_{const}', _print_known_const) _known_functions_scipy_special = { 'erf': 'erf', 'erfc': 'erfc', 'besselj': 'jv', 'bessely': 'yv', 'besseli': 'iv', 'besselk': 'kv', 'cosm1': 'cosm1', 'factorial': 'factorial', 'gamma': 'gamma', 'loggamma': 'gammaln', 'digamma': 'psi', 'RisingFactorial': 'poch', 'jacobi': 'eval_jacobi', 'gegenbauer': 'eval_gegenbauer', 'chebyshevt': 'eval_chebyt', 'chebyshevu': 'eval_chebyu', 'legendre': 'eval_legendre', 'hermite': 'eval_hermite', 'laguerre': 'eval_laguerre', 'assoc_laguerre': 'eval_genlaguerre', 'beta': 'beta', 'LambertW' : 'lambertw', } _known_constants_scipy_constants = { 'GoldenRatio': 'golden_ratio', 'Pi': 'pi', } _scipy_known_functions = {k : "scipy.special." + v for k, v in _known_functions_scipy_special.items()} _scipy_known_constants = {k : "scipy.constants." + v for k, v in _known_constants_scipy_constants.items()} class SciPyPrinter(NumPyPrinter): _kf = {**NumPyPrinter._kf, **_scipy_known_functions} _kc = {**NumPyPrinter._kc, **_scipy_known_constants} def __init__(self, settings=None): super().__init__(settings=settings) self.language = "Python with SciPy and NumPy" def _print_SparseMatrix(self, expr): i, j, data = [], [], [] for (r, c), v in expr.todok().items(): i.append(r) j.append(c) data.append(v) return "{name}(({data}, ({i}, {j})), shape={shape})".format( name=self._module_format('scipy.sparse.coo_matrix'), data=data, i=i, j=j, shape=expr.shape ) _print_ImmutableSparseMatrix = _print_SparseMatrix # SciPy's lpmv has a different order of arguments from assoc_legendre def _print_assoc_legendre(self, expr): return "{0}({2}, {1}, {3})".format( self._module_format('scipy.special.lpmv'), self._print(expr.args[0]), self._print(expr.args[1]), self._print(expr.args[2])) def _print_lowergamma(self, expr): return "{0}({2})*{1}({2}, {3})".format( self._module_format('scipy.special.gamma'), self._module_format('scipy.special.gammainc'), self._print(expr.args[0]), self._print(expr.args[1])) def _print_uppergamma(self, expr): return "{0}({2})*{1}({2}, {3})".format( self._module_format('scipy.special.gamma'), self._module_format('scipy.special.gammaincc'), self._print(expr.args[0]), self._print(expr.args[1])) def _print_betainc(self, expr): betainc = self._module_format('scipy.special.betainc') beta = self._module_format('scipy.special.beta') args = [self._print(arg) for arg in expr.args] return f"({betainc}({args[0]}, {args[1]}, {args[3]}) - {betainc}({args[0]}, {args[1]}, {args[2]})) \ * {beta}({args[0]}, {args[1]})" def _print_betainc_regularized(self, expr): return "{0}({1}, {2}, {4}) - {0}({1}, {2}, {3})".format( self._module_format('scipy.special.betainc'), self._print(expr.args[0]), self._print(expr.args[1]), self._print(expr.args[2]), self._print(expr.args[3])) def _print_fresnels(self, expr): return "{}({})[0]".format( self._module_format("scipy.special.fresnel"), self._print(expr.args[0])) def _print_fresnelc(self, expr): return "{}({})[1]".format( self._module_format("scipy.special.fresnel"), self._print(expr.args[0])) def _print_airyai(self, expr): return "{}({})[0]".format( self._module_format("scipy.special.airy"), self._print(expr.args[0])) def _print_airyaiprime(self, expr): return "{}({})[1]".format( self._module_format("scipy.special.airy"), self._print(expr.args[0])) def _print_airybi(self, expr): return "{}({})[2]".format( self._module_format("scipy.special.airy"), self._print(expr.args[0])) def _print_airybiprime(self, expr): return "{}({})[3]".format( self._module_format("scipy.special.airy"), self._print(expr.args[0])) def _print_Integral(self, e): integration_vars, limits = _unpack_integral_limits(e) if len(limits) == 1: # nicer (but not necessary) to prefer quad over nquad for 1D case module_str = self._module_format("scipy.integrate.quad") limit_str = "%s, %s" % tuple(map(self._print, limits[0])) else: module_str = self._module_format("scipy.integrate.nquad") limit_str = "({})".format(", ".join( "(%s, %s)" % tuple(map(self._print, l)) for l in limits)) return "{}(lambda {}: {}, {})[0]".format( module_str, ", ".join(map(self._print, integration_vars)), self._print(e.args[0]), limit_str) for func in _scipy_known_functions: setattr(SciPyPrinter, f'_print_{func}', _print_known_func) for const in _scipy_known_constants: setattr(SciPyPrinter, f'_print_{const}', _print_known_const) _cupy_known_functions = {k : "cupy." + v for k, v in _known_functions_numpy.items()} _cupy_known_constants = {k : "cupy." + v for k, v in _known_constants_numpy.items()} class CuPyPrinter(NumPyPrinter): """ CuPy printer which handles vectorized piecewise functions, logical operators, etc. """ _module = 'cupy' _kf = _cupy_known_functions _kc = _cupy_known_constants def __init__(self, settings=None): super().__init__(settings=settings) for func in _cupy_known_functions: setattr(CuPyPrinter, f'_print_{func}', _print_known_func) for const in _cupy_known_constants: setattr(CuPyPrinter, f'_print_{const}', _print_known_const) sympy-sympy-1.9/sympy/printing/octave.py000066400000000000000000000616621412543434000206040ustar00rootroot00000000000000""" Octave (and Matlab) code printer The `OctaveCodePrinter` converts SymPy expressions into Octave expressions. It uses a subset of the Octave language for Matlab compatibility. A complete code generator, which uses `octave_code` extensively, can be found in `sympy.utilities.codegen`. The `codegen` module can be used to generate complete source code files. """ from typing import Any, Dict from sympy.core import Mul, Pow, S, Rational from sympy.core.mul import _keep_coeff from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence, PRECEDENCE from re import search # List of known functions. First, those that have the same name in # SymPy and Octave. This is almost certainly incomplete! known_fcns_src1 = ["sin", "cos", "tan", "cot", "sec", "csc", "asin", "acos", "acot", "atan", "atan2", "asec", "acsc", "sinh", "cosh", "tanh", "coth", "csch", "sech", "asinh", "acosh", "atanh", "acoth", "asech", "acsch", "erfc", "erfi", "erf", "erfinv", "erfcinv", "besseli", "besselj", "besselk", "bessely", "bernoulli", "beta", "euler", "exp", "factorial", "floor", "fresnelc", "fresnels", "gamma", "harmonic", "log", "polylog", "sign", "zeta", "legendre"] # These functions have different names ("Sympy": "Octave"), more # generally a mapping to (argument_conditions, octave_function). known_fcns_src2 = { "Abs": "abs", "arg": "angle", # arg/angle ok in Octave but only angle in Matlab "binomial": "bincoeff", "ceiling": "ceil", "chebyshevu": "chebyshevU", "chebyshevt": "chebyshevT", "Chi": "coshint", "Ci": "cosint", "conjugate": "conj", "DiracDelta": "dirac", "Heaviside": "heaviside", "im": "imag", "laguerre": "laguerreL", "LambertW": "lambertw", "li": "logint", "loggamma": "gammaln", "Max": "max", "Min": "min", "Mod": "mod", "polygamma": "psi", "re": "real", "RisingFactorial": "pochhammer", "Shi": "sinhint", "Si": "sinint", } class OctaveCodePrinter(CodePrinter): """ A printer to convert expressions to strings of Octave/Matlab code. """ printmethod = "_octave" language = "Octave" _operators = { 'and': '&', 'or': '|', 'not': '~', } _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 17, 'user_functions': {}, 'human': True, 'allow_unknown_functions': False, 'contract': True, 'inline': True, } # type: Dict[str, Any] # Note: contract is for expressing tensors as loops (if True), or just # assignment (if False). FIXME: this should be looked a more carefully # for Octave. def __init__(self, settings={}): super().__init__(settings) self.known_functions = dict(zip(known_fcns_src1, known_fcns_src1)) self.known_functions.update(dict(known_fcns_src2)) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) def _rate_index_position(self, p): return p*5 def _get_statement(self, codestring): return "%s;" % codestring def _get_comment(self, text): return "% {}".format(text) def _declare_number_const(self, name, value): return "{} = {};".format(name, value) def _format_code(self, lines): return self.indent_code(lines) def _traverse_matrix_indices(self, mat): # Octave uses Fortran order (column-major) rows, cols = mat.shape return ((i, j) for j in range(cols) for i in range(rows)) def _get_loop_opening_ending(self, indices): open_lines = [] close_lines = [] for i in indices: # Octave arrays start at 1 and end at dimension var, start, stop = map(self._print, [i.label, i.lower + 1, i.upper + 1]) open_lines.append("for %s = %s:%s" % (var, start, stop)) close_lines.append("end") return open_lines, close_lines def _print_Mul(self, expr): # print complex numbers nicely in Octave if (expr.is_number and expr.is_imaginary and (S.ImaginaryUnit*expr).is_Integer): return "%si" % self._print(-S.ImaginaryUnit*expr) # cribbed from str.py prec = precedence(expr) c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator for item in args: if (item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative): if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: if len(item.args[0].args) != 1 and isinstance(item.base, Mul): # To avoid situations like #14160 pow_paren.append(item) b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec) for x in a] b_str = [self.parenthesize(x, prec) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] # from here it differs from str.py to deal with "*" and ".*" def multjoin(a, a_str): # here we probably are assuming the constants will come first r = a_str[0] for i in range(1, len(a)): mulsym = '*' if a[i-1].is_number else '.*' r = r + mulsym + a_str[i] return r if not b: return sign + multjoin(a, a_str) elif len(b) == 1: divsym = '/' if b[0].is_number else './' return sign + multjoin(a, a_str) + divsym + b_str[0] else: divsym = '/' if all([bi.is_number for bi in b]) else './' return (sign + multjoin(a, a_str) + divsym + "(%s)" % multjoin(b, b_str)) def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) def _print_Pow(self, expr): powsymbol = '^' if all([x.is_number for x in expr.args]) else '.^' PREC = precedence(expr) if expr.exp == S.Half: return "sqrt(%s)" % self._print(expr.base) if expr.is_commutative: if expr.exp == -S.Half: sym = '/' if expr.base.is_number else './' return "1" + sym + "sqrt(%s)" % self._print(expr.base) if expr.exp == -S.One: sym = '/' if expr.base.is_number else './' return "1" + sym + "%s" % self.parenthesize(expr.base, PREC) return '%s%s%s' % (self.parenthesize(expr.base, PREC), powsymbol, self.parenthesize(expr.exp, PREC)) def _print_MatPow(self, expr): PREC = precedence(expr) return '%s^%s' % (self.parenthesize(expr.base, PREC), self.parenthesize(expr.exp, PREC)) def _print_MatrixSolve(self, expr): PREC = precedence(expr) return "%s \\ %s" % (self.parenthesize(expr.matrix, PREC), self.parenthesize(expr.vector, PREC)) def _print_Pi(self, expr): return 'pi' def _print_ImaginaryUnit(self, expr): return "1i" def _print_Exp1(self, expr): return "exp(1)" def _print_GoldenRatio(self, expr): # FIXME: how to do better, e.g., for octave_code(2*GoldenRatio)? #return self._print((1+sqrt(S(5)))/2) return "(1+sqrt(5))/2" def _print_Assignment(self, expr): from sympy.codegen.ast import Assignment from sympy.functions.elementary.piecewise import Piecewise from sympy.tensor.indexed import IndexedBase # Copied from codeprinter, but remove special MatrixSymbol treatment lhs = expr.lhs rhs = expr.rhs # We special case assignments that take multiple lines if not self._settings["inline"] and isinstance(expr.rhs, Piecewise): # Here we modify Piecewise so each expression is now # an Assignment, and then continue on the print. expressions = [] conditions = [] for (e, c) in rhs.args: expressions.append(Assignment(lhs, e)) conditions.append(c) temp = Piecewise(*zip(expressions, conditions)) return self._print(temp) if self._settings["contract"] and (lhs.has(IndexedBase) or rhs.has(IndexedBase)): # Here we check if there is looping to be done, and if so # print the required loops. return self._doprint_loops(rhs, lhs) else: lhs_code = self._print(lhs) rhs_code = self._print(rhs) return self._get_statement("%s = %s" % (lhs_code, rhs_code)) def _print_Infinity(self, expr): return 'inf' def _print_NegativeInfinity(self, expr): return '-inf' def _print_NaN(self, expr): return 'NaN' def _print_list(self, expr): return '{' + ', '.join(self._print(a) for a in expr) + '}' _print_tuple = _print_list _print_Tuple = _print_list def _print_BooleanTrue(self, expr): return "true" def _print_BooleanFalse(self, expr): return "false" def _print_bool(self, expr): return str(expr).lower() # Could generate quadrature code for definite Integrals? #_print_Integral = _print_not_supported def _print_MatrixBase(self, A): # Handle zero dimensions: if (A.rows, A.cols) == (0, 0): return '[]' elif A.rows == 0 or A.cols == 0: return 'zeros(%s, %s)' % (A.rows, A.cols) elif (A.rows, A.cols) == (1, 1): # Octave does not distinguish between scalars and 1x1 matrices return self._print(A[0, 0]) return "[%s]" % "; ".join(" ".join([self._print(a) for a in A[r, :]]) for r in range(A.rows)) def _print_SparseMatrix(self, A): from sympy.matrices import Matrix L = A.col_list(); # make row vectors of the indices and entries I = Matrix([[k[0] + 1 for k in L]]) J = Matrix([[k[1] + 1 for k in L]]) AIJ = Matrix([[k[2] for k in L]]) return "sparse(%s, %s, %s, %s, %s)" % (self._print(I), self._print(J), self._print(AIJ), A.rows, A.cols) def _print_MatrixElement(self, expr): return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \ + '(%s, %s)' % (expr.i + 1, expr.j + 1) def _print_MatrixSlice(self, expr): def strslice(x, lim): l = x[0] + 1 h = x[1] step = x[2] lstr = self._print(l) hstr = 'end' if h == lim else self._print(h) if step == 1: if l == 1 and h == lim: return ':' if l == h: return lstr else: return lstr + ':' + hstr else: return ':'.join((lstr, self._print(step), hstr)) return (self._print(expr.parent) + '(' + strslice(expr.rowslice, expr.parent.shape[0]) + ', ' + strslice(expr.colslice, expr.parent.shape[1]) + ')') def _print_Indexed(self, expr): inds = [ self._print(i) for i in expr.indices ] return "%s(%s)" % (self._print(expr.base.label), ", ".join(inds)) def _print_Idx(self, expr): return self._print(expr.label) def _print_KroneckerDelta(self, expr): prec = PRECEDENCE["Pow"] return "double(%s == %s)" % tuple(self.parenthesize(x, prec) for x in expr.args) def _print_HadamardProduct(self, expr): return '.*'.join([self.parenthesize(arg, precedence(expr)) for arg in expr.args]) def _print_HadamardPower(self, expr): PREC = precedence(expr) return '.**'.join([ self.parenthesize(expr.base, PREC), self.parenthesize(expr.exp, PREC) ]) def _print_Identity(self, expr): shape = expr.shape if len(shape) == 2 and shape[0] == shape[1]: shape = [shape[0]] s = ", ".join(self._print(n) for n in shape) return "eye(" + s + ")" def _print_lowergamma(self, expr): # Octave implements regularized incomplete gamma function return "(gammainc({1}, {0}).*gamma({0}))".format( self._print(expr.args[0]), self._print(expr.args[1])) def _print_uppergamma(self, expr): return "(gammainc({1}, {0}, 'upper').*gamma({0}))".format( self._print(expr.args[0]), self._print(expr.args[1])) def _print_sinc(self, expr): #Note: Divide by pi because Octave implements normalized sinc function. return "sinc(%s)" % self._print(expr.args[0]/S.Pi) def _print_hankel1(self, expr): return "besselh(%s, 1, %s)" % (self._print(expr.order), self._print(expr.argument)) def _print_hankel2(self, expr): return "besselh(%s, 2, %s)" % (self._print(expr.order), self._print(expr.argument)) # Note: as of 2015, Octave doesn't have spherical Bessel functions def _print_jn(self, expr): from sympy.functions import sqrt, besselj x = expr.argument expr2 = sqrt(S.Pi/(2*x))*besselj(expr.order + S.Half, x) return self._print(expr2) def _print_yn(self, expr): from sympy.functions import sqrt, bessely x = expr.argument expr2 = sqrt(S.Pi/(2*x))*bessely(expr.order + S.Half, x) return self._print(expr2) def _print_airyai(self, expr): return "airy(0, %s)" % self._print(expr.args[0]) def _print_airyaiprime(self, expr): return "airy(1, %s)" % self._print(expr.args[0]) def _print_airybi(self, expr): return "airy(2, %s)" % self._print(expr.args[0]) def _print_airybiprime(self, expr): return "airy(3, %s)" % self._print(expr.args[0]) def _print_expint(self, expr): mu, x = expr.args if mu != 1: return self._print_not_supported(expr) return "expint(%s)" % self._print(x) def _one_or_two_reversed_args(self, expr): assert len(expr.args) <= 2 return '{name}({args})'.format( name=self.known_functions[expr.__class__.__name__], args=", ".join([self._print(x) for x in reversed(expr.args)]) ) _print_DiracDelta = _print_LambertW = _one_or_two_reversed_args def _nested_binary_math_func(self, expr): return '{name}({arg1}, {arg2})'.format( name=self.known_functions[expr.__class__.__name__], arg1=self._print(expr.args[0]), arg2=self._print(expr.func(*expr.args[1:])) ) _print_Max = _print_Min = _nested_binary_math_func def _print_Piecewise(self, expr): if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") lines = [] if self._settings["inline"]: # Express each (cond, expr) pair in a nested Horner form: # (condition) .* (expr) + (not cond) .* () # Expressions that result in multiple statements won't work here. ecpairs = ["({0}).*({1}) + (~({0})).*(".format (self._print(c), self._print(e)) for e, c in expr.args[:-1]] elast = "%s" % self._print(expr.args[-1].expr) pw = " ...\n".join(ecpairs) + elast + ")"*len(ecpairs) # Note: current need these outer brackets for 2*pw. Would be # nicer to teach parenthesize() to do this for us when needed! return "(" + pw + ")" else: for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s)" % self._print(c)) elif i == len(expr.args) - 1 and c == True: lines.append("else") else: lines.append("elseif (%s)" % self._print(c)) code0 = self._print(e) lines.append(code0) if i == len(expr.args) - 1: lines.append("end") return "\n".join(lines) def _print_zeta(self, expr): if len(expr.args) == 1: return "zeta(%s)" % self._print(expr.args[0]) else: # Matlab two argument zeta is not equivalent to SymPy's return self._print_not_supported(expr) def indent_code(self, code): """Accepts a string of code or a list of code lines""" # code mostly copied from ccode if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) tab = " " inc_regex = ('^function ', '^if ', '^elseif ', '^else$', '^for ') dec_regex = ('^end$', '^elseif ', '^else$') # pre-strip left-space from the code code = [ line.lstrip(' \t') for line in code ] increase = [ int(any([search(re, line) for re in inc_regex])) for line in code ] decrease = [ int(any([search(re, line) for re in dec_regex])) for line in code ] pretty = [] level = 0 for n, line in enumerate(code): if line == '' or line == '\n': pretty.append(line) continue level -= decrease[n] pretty.append("%s%s" % (tab*level, line)) level += increase[n] return pretty def octave_code(expr, assign_to=None, **settings): r"""Converts `expr` to a string of Octave (or Matlab) code. The string uses a subset of the Octave language for Matlab compatibility. Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This can be helpful for expressions that generate multi-line statements. precision : integer, optional The precision for numbers such as pi [default=16]. user_functions : dict, optional A dictionary where keys are ``FunctionClass`` instances and values are their string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. See below for examples. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. inline: bool, optional If True, we try to create single-statement code instead of multiple statements. [default=True]. Examples ======== >>> from sympy import octave_code, symbols, sin, pi >>> x = symbols('x') >>> octave_code(sin(x).series(x).removeO()) 'x.^5/120 - x.^3/6 + x' >>> from sympy import Rational, ceiling >>> x, y, tau = symbols("x, y, tau") >>> octave_code((2*tau)**Rational(7, 2)) '8*sqrt(2)*tau.^(7/2)' Note that element-wise (Hadamard) operations are used by default between symbols. This is because its very common in Octave to write "vectorized" code. It is harmless if the values are scalars. >>> octave_code(sin(pi*x*y), assign_to="s") 's = sin(pi*x.*y);' If you need a matrix product "*" or matrix power "^", you can specify the symbol as a ``MatrixSymbol``. >>> from sympy import Symbol, MatrixSymbol >>> n = Symbol('n', integer=True, positive=True) >>> A = MatrixSymbol('A', n, n) >>> octave_code(3*pi*A**3) '(3*pi)*A^3' This class uses several rules to decide which symbol to use a product. Pure numbers use "*", Symbols use ".*" and MatrixSymbols use "*". A HadamardProduct can be used to specify componentwise multiplication ".*" of two MatrixSymbols. There is currently there is no easy way to specify scalar symbols, so sometimes the code might have some minor cosmetic issues. For example, suppose x and y are scalars and A is a Matrix, then while a human programmer might write "(x^2*y)*A^3", we generate: >>> octave_code(x**2*y*A**3) '(x.^2.*y)*A^3' Matrices are supported using Octave inline notation. When using ``assign_to`` with matrices, the name can be specified either as a string or as a ``MatrixSymbol``. The dimensions must align in the latter case. >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([[x**2, sin(x), ceiling(x)]]) >>> octave_code(mat, assign_to='A') 'A = [x.^2 sin(x) ceil(x)];' ``Piecewise`` expressions are implemented with logical masking by default. Alternatively, you can pass "inline=False" to use if-else conditionals. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> pw = Piecewise((x + 1, x > 0), (x, True)) >>> octave_code(pw, assign_to=tau) 'tau = ((x > 0).*(x + 1) + (~(x > 0)).*(x));' Note that any expression that can be generated normally can also exist inside a Matrix: >>> mat = Matrix([[x**2, pw, sin(x)]]) >>> octave_code(mat, assign_to='A') 'A = [x.^2 ((x > 0).*(x + 1) + (~(x > 0)).*(x)) sin(x)];' Custom printing can be defined for certain types by passing a dictionary of "type" : "function" to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e., [(argument_test, cfunction_string)]. This can be used to call a custom Octave function. >>> from sympy import Function >>> f = Function('f') >>> g = Function('g') >>> custom_functions = { ... "f": "existing_octave_fcn", ... "g": [(lambda x: x.is_Matrix, "my_mat_fcn"), ... (lambda x: not x.is_Matrix, "my_fcn")] ... } >>> mat = Matrix([[1, x]]) >>> octave_code(f(x) + g(x) + g(mat), user_functions=custom_functions) 'existing_octave_fcn(x) + my_fcn(x) + my_mat_fcn([1 x])' Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e = Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> octave_code(e.rhs, assign_to=e.lhs, contract=False) 'Dy(i) = (y(i + 1) - y(i))./(t(i + 1) - t(i));' """ return OctaveCodePrinter(settings).doprint(expr, assign_to) def print_octave_code(expr, **settings): """Prints the Octave (or Matlab) representation of the given expression. See `octave_code` for the meaning of the optional arguments. """ print(octave_code(expr, **settings)) sympy-sympy-1.9/sympy/printing/precedence.py000066400000000000000000000122201412543434000214020ustar00rootroot00000000000000"""A module providing information about the necessity of brackets""" from sympy.core.function import _coeff_isneg # Default precedence values for some basic types PRECEDENCE = { "Lambda": 1, "Xor": 10, "Or": 20, "And": 30, "Relational": 35, "Add": 40, "Mul": 50, "Pow": 60, "Func": 70, "Not": 100, "Atom": 1000, "BitwiseOr": 36, "BitwiseXor": 37, "BitwiseAnd": 38 } # A dictionary assigning precedence values to certain classes. These values are # treated like they were inherited, so not every single class has to be named # here. # Do not use this with printers other than StrPrinter PRECEDENCE_VALUES = { "Equivalent": PRECEDENCE["Xor"], "Xor": PRECEDENCE["Xor"], "Implies": PRECEDENCE["Xor"], "Or": PRECEDENCE["Or"], "And": PRECEDENCE["And"], "Add": PRECEDENCE["Add"], "Pow": PRECEDENCE["Pow"], "Relational": PRECEDENCE["Relational"], "Sub": PRECEDENCE["Add"], "Not": PRECEDENCE["Not"], "Function" : PRECEDENCE["Func"], "NegativeInfinity": PRECEDENCE["Add"], "MatAdd": PRECEDENCE["Add"], "MatPow": PRECEDENCE["Pow"], "MatrixSolve": PRECEDENCE["Mul"], "TensAdd": PRECEDENCE["Add"], # As soon as `TensMul` is a subclass of `Mul`, remove this: "TensMul": PRECEDENCE["Mul"], "HadamardProduct": PRECEDENCE["Mul"], "HadamardPower": PRECEDENCE["Pow"], "KroneckerProduct": PRECEDENCE["Mul"], "Equality": PRECEDENCE["Mul"], "Unequality": PRECEDENCE["Mul"], } # Sometimes it's not enough to assign a fixed precedence value to a # class. Then a function can be inserted in this dictionary that takes # an instance of this class as argument and returns the appropriate # precedence value. # Precedence functions def precedence_Mul(item): if _coeff_isneg(item): return PRECEDENCE["Add"] return PRECEDENCE["Mul"] def precedence_Rational(item): if item.p < 0: return PRECEDENCE["Add"] return PRECEDENCE["Mul"] def precedence_Integer(item): if item.p < 0: return PRECEDENCE["Add"] return PRECEDENCE["Atom"] def precedence_Float(item): if item < 0: return PRECEDENCE["Add"] return PRECEDENCE["Atom"] def precedence_PolyElement(item): if item.is_generator: return PRECEDENCE["Atom"] elif item.is_ground: return precedence(item.coeff(1)) elif item.is_term: return PRECEDENCE["Mul"] else: return PRECEDENCE["Add"] def precedence_FracElement(item): if item.denom == 1: return precedence_PolyElement(item.numer) else: return PRECEDENCE["Mul"] def precedence_UnevaluatedExpr(item): return precedence(item.args[0]) PRECEDENCE_FUNCTIONS = { "Integer": precedence_Integer, "Mul": precedence_Mul, "Rational": precedence_Rational, "Float": precedence_Float, "PolyElement": precedence_PolyElement, "FracElement": precedence_FracElement, "UnevaluatedExpr": precedence_UnevaluatedExpr, } def precedence(item): """Returns the precedence of a given object. This is the precedence for StrPrinter. """ if hasattr(item, "precedence"): return item.precedence try: mro = item.__class__.__mro__ except AttributeError: return PRECEDENCE["Atom"] for i in mro: n = i.__name__ if n in PRECEDENCE_FUNCTIONS: return PRECEDENCE_FUNCTIONS[n](item) elif n in PRECEDENCE_VALUES: return PRECEDENCE_VALUES[n] return PRECEDENCE["Atom"] PRECEDENCE_TRADITIONAL = PRECEDENCE.copy() PRECEDENCE_TRADITIONAL['Integral'] = PRECEDENCE["Mul"] PRECEDENCE_TRADITIONAL['Sum'] = PRECEDENCE["Mul"] PRECEDENCE_TRADITIONAL['Product'] = PRECEDENCE["Mul"] PRECEDENCE_TRADITIONAL['Limit'] = PRECEDENCE["Mul"] PRECEDENCE_TRADITIONAL['Derivative'] = PRECEDENCE["Mul"] PRECEDENCE_TRADITIONAL['TensorProduct'] = PRECEDENCE["Mul"] PRECEDENCE_TRADITIONAL['Transpose'] = PRECEDENCE["Pow"] PRECEDENCE_TRADITIONAL['Adjoint'] = PRECEDENCE["Pow"] PRECEDENCE_TRADITIONAL['Dot'] = PRECEDENCE["Mul"] - 1 PRECEDENCE_TRADITIONAL['Cross'] = PRECEDENCE["Mul"] - 1 PRECEDENCE_TRADITIONAL['Gradient'] = PRECEDENCE["Mul"] - 1 PRECEDENCE_TRADITIONAL['Divergence'] = PRECEDENCE["Mul"] - 1 PRECEDENCE_TRADITIONAL['Curl'] = PRECEDENCE["Mul"] - 1 PRECEDENCE_TRADITIONAL['Laplacian'] = PRECEDENCE["Mul"] - 1 PRECEDENCE_TRADITIONAL['Union'] = PRECEDENCE['Xor'] PRECEDENCE_TRADITIONAL['Intersection'] = PRECEDENCE['Xor'] PRECEDENCE_TRADITIONAL['Complement'] = PRECEDENCE['Xor'] PRECEDENCE_TRADITIONAL['SymmetricDifference'] = PRECEDENCE['Xor'] PRECEDENCE_TRADITIONAL['ProductSet'] = PRECEDENCE['Xor'] def precedence_traditional(item): """Returns the precedence of a given object according to the traditional rules of mathematics. This is the precedence for the LaTeX and pretty printer. """ # Integral, Sum, Product, Limit have the precedence of Mul in LaTeX, # the precedence of Atom for other printers: from sympy.core.expr import UnevaluatedExpr if isinstance(item, UnevaluatedExpr): return precedence_traditional(item.args[0]) n = item.__class__.__name__ if n in PRECEDENCE_TRADITIONAL: return PRECEDENCE_TRADITIONAL[n] return precedence(item) sympy-sympy-1.9/sympy/printing/pretty/000077500000000000000000000000001412543434000202655ustar00rootroot00000000000000sympy-sympy-1.9/sympy/printing/pretty/__init__.py000066400000000000000000000005301412543434000223740ustar00rootroot00000000000000"""ASCII-ART 2D pretty-printer""" from .pretty import (pretty, pretty_print, pprint, pprint_use_unicode, pprint_try_use_unicode, pager_print) # if unicode output is available -- let's use it pprint_try_use_unicode() __all__ = [ 'pretty', 'pretty_print', 'pprint', 'pprint_use_unicode', 'pprint_try_use_unicode', 'pager_print', ] sympy-sympy-1.9/sympy/printing/pretty/pretty.py000066400000000000000000003120341412543434000221710ustar00rootroot00000000000000import itertools from sympy.core import S from sympy.core.containers import Tuple from sympy.core.function import _coeff_isneg from sympy.core.mul import Mul from sympy.core.numbers import Number, Rational from sympy.core.power import Pow from sympy.core.symbol import Symbol from sympy.core.sympify import SympifyError from sympy.printing.conventions import requires_partial from sympy.printing.precedence import PRECEDENCE, precedence, precedence_traditional from sympy.printing.printer import Printer, print_function from sympy.printing.str import sstr from sympy.utilities import default_sort_key from sympy.utilities.iterables import has_variety from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.printing.pretty.stringpict import prettyForm, stringPict from sympy.printing.pretty.pretty_symbology import hobj, vobj, xobj, \ xsym, pretty_symbol, pretty_atom, pretty_use_unicode, greek_unicode, U, \ pretty_try_use_unicode, annotated # rename for usage from outside pprint_use_unicode = pretty_use_unicode pprint_try_use_unicode = pretty_try_use_unicode class PrettyPrinter(Printer): """Printer, which converts an expression into 2D ASCII-art figure.""" printmethod = "_pretty" _default_settings = { "order": None, "full_prec": "auto", "use_unicode": None, "wrap_line": True, "num_columns": None, "use_unicode_sqrt_char": True, "root_notation": True, "mat_symbol_style": "plain", "imaginary_unit": "i", "perm_cyclic": True } def __init__(self, settings=None): Printer.__init__(self, settings) if not isinstance(self._settings['imaginary_unit'], str): raise TypeError("'imaginary_unit' must a string, not {}".format(self._settings['imaginary_unit'])) elif self._settings['imaginary_unit'] not in ["i", "j"]: raise ValueError("'imaginary_unit' must be either 'i' or 'j', not '{}'".format(self._settings['imaginary_unit'])) def emptyPrinter(self, expr): return prettyForm(str(expr)) @property def _use_unicode(self): if self._settings['use_unicode']: return True else: return pretty_use_unicode() def doprint(self, expr): return self._print(expr).render(**self._settings) # empty op so _print(stringPict) returns the same def _print_stringPict(self, e): return e def _print_basestring(self, e): return prettyForm(e) def _print_atan2(self, e): pform = prettyForm(*self._print_seq(e.args).parens()) pform = prettyForm(*pform.left('atan2')) return pform def _print_Symbol(self, e, bold_name=False): symb = pretty_symbol(e.name, bold_name) return prettyForm(symb) _print_RandomSymbol = _print_Symbol def _print_MatrixSymbol(self, e): return self._print_Symbol(e, self._settings['mat_symbol_style'] == "bold") def _print_Float(self, e): # we will use StrPrinter's Float printer, but we need to handle the # full_prec ourselves, according to the self._print_level full_prec = self._settings["full_prec"] if full_prec == "auto": full_prec = self._print_level == 1 return prettyForm(sstr(e, full_prec=full_prec)) def _print_Cross(self, e): vec1 = e._expr1 vec2 = e._expr2 pform = self._print(vec2) pform = prettyForm(*pform.left('(')) pform = prettyForm(*pform.right(')')) pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN')))) pform = prettyForm(*pform.left(')')) pform = prettyForm(*pform.left(self._print(vec1))) pform = prettyForm(*pform.left('(')) return pform def _print_Curl(self, e): vec = e._expr pform = self._print(vec) pform = prettyForm(*pform.left('(')) pform = prettyForm(*pform.right(')')) pform = prettyForm(*pform.left(self._print(U('MULTIPLICATION SIGN')))) pform = prettyForm(*pform.left(self._print(U('NABLA')))) return pform def _print_Divergence(self, e): vec = e._expr pform = self._print(vec) pform = prettyForm(*pform.left('(')) pform = prettyForm(*pform.right(')')) pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR')))) pform = prettyForm(*pform.left(self._print(U('NABLA')))) return pform def _print_Dot(self, e): vec1 = e._expr1 vec2 = e._expr2 pform = self._print(vec2) pform = prettyForm(*pform.left('(')) pform = prettyForm(*pform.right(')')) pform = prettyForm(*pform.left(self._print(U('DOT OPERATOR')))) pform = prettyForm(*pform.left(')')) pform = prettyForm(*pform.left(self._print(vec1))) pform = prettyForm(*pform.left('(')) return pform def _print_Gradient(self, e): func = e._expr pform = self._print(func) pform = prettyForm(*pform.left('(')) pform = prettyForm(*pform.right(')')) pform = prettyForm(*pform.left(self._print(U('NABLA')))) return pform def _print_Laplacian(self, e): func = e._expr pform = self._print(func) pform = prettyForm(*pform.left('(')) pform = prettyForm(*pform.right(')')) pform = prettyForm(*pform.left(self._print(U('INCREMENT')))) return pform def _print_Atom(self, e): try: # print atoms like Exp1 or Pi return prettyForm(pretty_atom(e.__class__.__name__, printer=self)) except KeyError: return self.emptyPrinter(e) # Infinity inherits from Number, so we have to override _print_XXX order _print_Infinity = _print_Atom _print_NegativeInfinity = _print_Atom _print_EmptySet = _print_Atom _print_Naturals = _print_Atom _print_Naturals0 = _print_Atom _print_Integers = _print_Atom _print_Rationals = _print_Atom _print_Complexes = _print_Atom _print_EmptySequence = _print_Atom def _print_Reals(self, e): if self._use_unicode: return self._print_Atom(e) else: inf_list = ['-oo', 'oo'] return self._print_seq(inf_list, '(', ')') def _print_subfactorial(self, e): x = e.args[0] pform = self._print(x) # Add parentheses if needed if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol): pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left('!')) return pform def _print_factorial(self, e): x = e.args[0] pform = self._print(x) # Add parentheses if needed if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol): pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.right('!')) return pform def _print_factorial2(self, e): x = e.args[0] pform = self._print(x) # Add parentheses if needed if not ((x.is_Integer and x.is_nonnegative) or x.is_Symbol): pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.right('!!')) return pform def _print_binomial(self, e): n, k = e.args n_pform = self._print(n) k_pform = self._print(k) bar = ' '*max(n_pform.width(), k_pform.width()) pform = prettyForm(*k_pform.above(bar)) pform = prettyForm(*pform.above(n_pform)) pform = prettyForm(*pform.parens('(', ')')) pform.baseline = (pform.baseline + 1)//2 return pform def _print_Relational(self, e): op = prettyForm(' ' + xsym(e.rel_op) + ' ') l = self._print(e.lhs) r = self._print(e.rhs) pform = prettyForm(*stringPict.next(l, op, r)) return pform def _print_Not(self, e): from sympy import Equivalent, Implies if self._use_unicode: arg = e.args[0] pform = self._print(arg) if isinstance(arg, Equivalent): return self._print_Equivalent(arg, altchar="\N{LEFT RIGHT DOUBLE ARROW WITH STROKE}") if isinstance(arg, Implies): return self._print_Implies(arg, altchar="\N{RIGHTWARDS ARROW WITH STROKE}") if arg.is_Boolean and not arg.is_Not: pform = prettyForm(*pform.parens()) return prettyForm(*pform.left("\N{NOT SIGN}")) else: return self._print_Function(e) def __print_Boolean(self, e, char, sort=True): args = e.args if sort: args = sorted(e.args, key=default_sort_key) arg = args[0] pform = self._print(arg) if arg.is_Boolean and not arg.is_Not: pform = prettyForm(*pform.parens()) for arg in args[1:]: pform_arg = self._print(arg) if arg.is_Boolean and not arg.is_Not: pform_arg = prettyForm(*pform_arg.parens()) pform = prettyForm(*pform.right(' %s ' % char)) pform = prettyForm(*pform.right(pform_arg)) return pform def _print_And(self, e): if self._use_unicode: return self.__print_Boolean(e, "\N{LOGICAL AND}") else: return self._print_Function(e, sort=True) def _print_Or(self, e): if self._use_unicode: return self.__print_Boolean(e, "\N{LOGICAL OR}") else: return self._print_Function(e, sort=True) def _print_Xor(self, e): if self._use_unicode: return self.__print_Boolean(e, "\N{XOR}") else: return self._print_Function(e, sort=True) def _print_Nand(self, e): if self._use_unicode: return self.__print_Boolean(e, "\N{NAND}") else: return self._print_Function(e, sort=True) def _print_Nor(self, e): if self._use_unicode: return self.__print_Boolean(e, "\N{NOR}") else: return self._print_Function(e, sort=True) def _print_Implies(self, e, altchar=None): if self._use_unicode: return self.__print_Boolean(e, altchar or "\N{RIGHTWARDS ARROW}", sort=False) else: return self._print_Function(e) def _print_Equivalent(self, e, altchar=None): if self._use_unicode: return self.__print_Boolean(e, altchar or "\N{LEFT RIGHT DOUBLE ARROW}") else: return self._print_Function(e, sort=True) def _print_conjugate(self, e): pform = self._print(e.args[0]) return prettyForm( *pform.above( hobj('_', pform.width())) ) def _print_Abs(self, e): pform = self._print(e.args[0]) pform = prettyForm(*pform.parens('|', '|')) return pform _print_Determinant = _print_Abs def _print_floor(self, e): if self._use_unicode: pform = self._print(e.args[0]) pform = prettyForm(*pform.parens('lfloor', 'rfloor')) return pform else: return self._print_Function(e) def _print_ceiling(self, e): if self._use_unicode: pform = self._print(e.args[0]) pform = prettyForm(*pform.parens('lceil', 'rceil')) return pform else: return self._print_Function(e) def _print_Derivative(self, deriv): if requires_partial(deriv.expr) and self._use_unicode: deriv_symbol = U('PARTIAL DIFFERENTIAL') else: deriv_symbol = r'd' x = None count_total_deriv = 0 for sym, num in reversed(deriv.variable_count): s = self._print(sym) ds = prettyForm(*s.left(deriv_symbol)) count_total_deriv += num if (not num.is_Integer) or (num > 1): ds = ds**prettyForm(str(num)) if x is None: x = ds else: x = prettyForm(*x.right(' ')) x = prettyForm(*x.right(ds)) f = prettyForm( binding=prettyForm.FUNC, *self._print(deriv.expr).parens()) pform = prettyForm(deriv_symbol) if (count_total_deriv > 1) != False: pform = pform**prettyForm(str(count_total_deriv)) pform = prettyForm(*pform.below(stringPict.LINE, x)) pform.baseline = pform.baseline + 1 pform = prettyForm(*stringPict.next(pform, f)) pform.binding = prettyForm.MUL return pform def _print_Cycle(self, dc): from sympy.combinatorics.permutations import Permutation, Cycle # for Empty Cycle if dc == Cycle(): cyc = stringPict('') return prettyForm(*cyc.parens()) dc_list = Permutation(dc.list()).cyclic_form # for Identity Cycle if dc_list == []: cyc = self._print(dc.size - 1) return prettyForm(*cyc.parens()) cyc = stringPict('') for i in dc_list: l = self._print(str(tuple(i)).replace(',', '')) cyc = prettyForm(*cyc.right(l)) return cyc def _print_Permutation(self, expr): from sympy.combinatorics.permutations import Permutation, Cycle perm_cyclic = Permutation.print_cyclic if perm_cyclic is not None: SymPyDeprecationWarning( feature="Permutation.print_cyclic = {}".format(perm_cyclic), useinstead="init_printing(perm_cyclic={})" .format(perm_cyclic), issue=15201, deprecated_since_version="1.6").warn() else: perm_cyclic = self._settings.get("perm_cyclic", True) if perm_cyclic: return self._print_Cycle(Cycle(expr)) lower = expr.array_form upper = list(range(len(lower))) result = stringPict('') first = True for u, l in zip(upper, lower): s1 = self._print(u) s2 = self._print(l) col = prettyForm(*s1.below(s2)) if first: first = False else: col = prettyForm(*col.left(" ")) result = prettyForm(*result.right(col)) return prettyForm(*result.parens()) def _print_Integral(self, integral): f = integral.function # Add parentheses if arg involves addition of terms and # create a pretty form for the argument prettyF = self._print(f) # XXX generalize parens if f.is_Add: prettyF = prettyForm(*prettyF.parens()) # dx dy dz ... arg = prettyF for x in integral.limits: prettyArg = self._print(x[0]) # XXX qparens (parens if needs-parens) if prettyArg.width() > 1: prettyArg = prettyForm(*prettyArg.parens()) arg = prettyForm(*arg.right(' d', prettyArg)) # \int \int \int ... firstterm = True s = None for lim in integral.limits: # Create bar based on the height of the argument h = arg.height() H = h + 2 # XXX hack! ascii_mode = not self._use_unicode if ascii_mode: H += 2 vint = vobj('int', H) # Construct the pretty form with the integral sign and the argument pform = prettyForm(vint) pform.baseline = arg.baseline + ( H - h)//2 # covering the whole argument if len(lim) > 1: # Create pretty forms for endpoints, if definite integral. # Do not print empty endpoints. if len(lim) == 2: prettyA = prettyForm("") prettyB = self._print(lim[1]) if len(lim) == 3: prettyA = self._print(lim[1]) prettyB = self._print(lim[2]) if ascii_mode: # XXX hack # Add spacing so that endpoint can more easily be # identified with the correct integral sign spc = max(1, 3 - prettyB.width()) prettyB = prettyForm(*prettyB.left(' ' * spc)) spc = max(1, 4 - prettyA.width()) prettyA = prettyForm(*prettyA.right(' ' * spc)) pform = prettyForm(*pform.above(prettyB)) pform = prettyForm(*pform.below(prettyA)) if not ascii_mode: # XXX hack pform = prettyForm(*pform.right(' ')) if firstterm: s = pform # first term firstterm = False else: s = prettyForm(*s.left(pform)) pform = prettyForm(*arg.left(s)) pform.binding = prettyForm.MUL return pform def _print_Product(self, expr): func = expr.term pretty_func = self._print(func) horizontal_chr = xobj('_', 1) corner_chr = xobj('_', 1) vertical_chr = xobj('|', 1) if self._use_unicode: # use unicode corners horizontal_chr = xobj('-', 1) corner_chr = '\N{BOX DRAWINGS LIGHT DOWN AND HORIZONTAL}' func_height = pretty_func.height() first = True max_upper = 0 sign_height = 0 for lim in expr.limits: pretty_lower, pretty_upper = self.__print_SumProduct_Limits(lim) width = (func_height + 2) * 5 // 3 - 2 sign_lines = [horizontal_chr + corner_chr + (horizontal_chr * (width-2)) + corner_chr + horizontal_chr] for _ in range(func_height + 1): sign_lines.append(' ' + vertical_chr + (' ' * (width-2)) + vertical_chr + ' ') pretty_sign = stringPict('') pretty_sign = prettyForm(*pretty_sign.stack(*sign_lines)) max_upper = max(max_upper, pretty_upper.height()) if first: sign_height = pretty_sign.height() pretty_sign = prettyForm(*pretty_sign.above(pretty_upper)) pretty_sign = prettyForm(*pretty_sign.below(pretty_lower)) if first: pretty_func.baseline = 0 first = False height = pretty_sign.height() padding = stringPict('') padding = prettyForm(*padding.stack(*[' ']*(height - 1))) pretty_sign = prettyForm(*pretty_sign.right(padding)) pretty_func = prettyForm(*pretty_sign.right(pretty_func)) pretty_func.baseline = max_upper + sign_height//2 pretty_func.binding = prettyForm.MUL return pretty_func def __print_SumProduct_Limits(self, lim): def print_start(lhs, rhs): op = prettyForm(' ' + xsym("==") + ' ') l = self._print(lhs) r = self._print(rhs) pform = prettyForm(*stringPict.next(l, op, r)) return pform prettyUpper = self._print(lim[2]) prettyLower = print_start(lim[0], lim[1]) return prettyLower, prettyUpper def _print_Sum(self, expr): ascii_mode = not self._use_unicode def asum(hrequired, lower, upper, use_ascii): def adjust(s, wid=None, how='<^>'): if not wid or len(s) > wid: return s need = wid - len(s) if how == '<^>' or how == "<" or how not in list('<^>'): return s + ' '*need half = need//2 lead = ' '*half if how == ">": return " "*need + s return lead + s + ' '*(need - len(lead)) h = max(hrequired, 2) d = h//2 w = d + 1 more = hrequired % 2 lines = [] if use_ascii: lines.append("_"*(w) + ' ') lines.append(r"\%s`" % (' '*(w - 1))) for i in range(1, d): lines.append('%s\\%s' % (' '*i, ' '*(w - i))) if more: lines.append('%s)%s' % (' '*(d), ' '*(w - d))) for i in reversed(range(1, d)): lines.append('%s/%s' % (' '*i, ' '*(w - i))) lines.append("/" + "_"*(w - 1) + ',') return d, h + more, lines, more else: w = w + more d = d + more vsum = vobj('sum', 4) lines.append("_"*(w)) for i in range(0, d): lines.append('%s%s%s' % (' '*i, vsum[2], ' '*(w - i - 1))) for i in reversed(range(0, d)): lines.append('%s%s%s' % (' '*i, vsum[4], ' '*(w - i - 1))) lines.append(vsum[8]*(w)) return d, h + 2*more, lines, more f = expr.function prettyF = self._print(f) if f.is_Add: # add parens prettyF = prettyForm(*prettyF.parens()) H = prettyF.height() + 2 # \sum \sum \sum ... first = True max_upper = 0 sign_height = 0 for lim in expr.limits: prettyLower, prettyUpper = self.__print_SumProduct_Limits(lim) max_upper = max(max_upper, prettyUpper.height()) # Create sum sign based on the height of the argument d, h, slines, adjustment = asum( H, prettyLower.width(), prettyUpper.width(), ascii_mode) prettySign = stringPict('') prettySign = prettyForm(*prettySign.stack(*slines)) if first: sign_height = prettySign.height() prettySign = prettyForm(*prettySign.above(prettyUpper)) prettySign = prettyForm(*prettySign.below(prettyLower)) if first: # change F baseline so it centers on the sign prettyF.baseline -= d - (prettyF.height()//2 - prettyF.baseline) first = False # put padding to the right pad = stringPict('') pad = prettyForm(*pad.stack(*[' ']*h)) prettySign = prettyForm(*prettySign.right(pad)) # put the present prettyF to the right prettyF = prettyForm(*prettySign.right(prettyF)) # adjust baseline of ascii mode sigma with an odd height so that it is # exactly through the center ascii_adjustment = ascii_mode if not adjustment else 0 prettyF.baseline = max_upper + sign_height//2 + ascii_adjustment prettyF.binding = prettyForm.MUL return prettyF def _print_Limit(self, l): e, z, z0, dir = l.args E = self._print(e) if precedence(e) <= PRECEDENCE["Mul"]: E = prettyForm(*E.parens('(', ')')) Lim = prettyForm('lim') LimArg = self._print(z) if self._use_unicode: LimArg = prettyForm(*LimArg.right('\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{RIGHTWARDS ARROW}')) else: LimArg = prettyForm(*LimArg.right('->')) LimArg = prettyForm(*LimArg.right(self._print(z0))) if str(dir) == '+-' or z0 in (S.Infinity, S.NegativeInfinity): dir = "" else: if self._use_unicode: dir = '\N{SUPERSCRIPT PLUS SIGN}' if str(dir) == "+" else '\N{SUPERSCRIPT MINUS}' LimArg = prettyForm(*LimArg.right(self._print(dir))) Lim = prettyForm(*Lim.below(LimArg)) Lim = prettyForm(*Lim.right(E), binding=prettyForm.MUL) return Lim def _print_matrix_contents(self, e): """ This method factors out what is essentially grid printing. """ M = e # matrix Ms = {} # i,j -> pretty(M[i,j]) for i in range(M.rows): for j in range(M.cols): Ms[i, j] = self._print(M[i, j]) # h- and v- spacers hsep = 2 vsep = 1 # max width for columns maxw = [-1] * M.cols for j in range(M.cols): maxw[j] = max([Ms[i, j].width() for i in range(M.rows)] or [0]) # drawing result D = None for i in range(M.rows): D_row = None for j in range(M.cols): s = Ms[i, j] # reshape s to maxw # XXX this should be generalized, and go to stringPict.reshape ? assert s.width() <= maxw[j] # hcenter it, +0.5 to the right 2 # ( it's better to align formula starts for say 0 and r ) # XXX this is not good in all cases -- maybe introduce vbaseline? wdelta = maxw[j] - s.width() wleft = wdelta // 2 wright = wdelta - wleft s = prettyForm(*s.right(' '*wright)) s = prettyForm(*s.left(' '*wleft)) # we don't need vcenter cells -- this is automatically done in # a pretty way because when their baselines are taking into # account in .right() if D_row is None: D_row = s # first box in a row continue D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer D_row = prettyForm(*D_row.right(s)) if D is None: D = D_row # first row in a picture continue # v-spacer for _ in range(vsep): D = prettyForm(*D.below(' ')) D = prettyForm(*D.below(D_row)) if D is None: D = prettyForm('') # Empty Matrix return D def _print_MatrixBase(self, e): D = self._print_matrix_contents(e) D.baseline = D.height()//2 D = prettyForm(*D.parens('[', ']')) return D def _print_TensorProduct(self, expr): # This should somehow share the code with _print_WedgeProduct: circled_times = "\u2297" return self._print_seq(expr.args, None, None, circled_times, parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"]) def _print_WedgeProduct(self, expr): # This should somehow share the code with _print_TensorProduct: wedge_symbol = "\u2227" return self._print_seq(expr.args, None, None, wedge_symbol, parenthesize=lambda x: precedence_traditional(x) <= PRECEDENCE["Mul"]) def _print_Trace(self, e): D = self._print(e.arg) D = prettyForm(*D.parens('(',')')) D.baseline = D.height()//2 D = prettyForm(*D.left('\n'*(0) + 'tr')) return D def _print_MatrixElement(self, expr): from sympy.matrices import MatrixSymbol from sympy import Symbol if (isinstance(expr.parent, MatrixSymbol) and expr.i.is_number and expr.j.is_number): return self._print( Symbol(expr.parent.name + '_%d%d' % (expr.i, expr.j))) else: prettyFunc = self._print(expr.parent) prettyFunc = prettyForm(*prettyFunc.parens()) prettyIndices = self._print_seq((expr.i, expr.j), delimiter=', ' ).parens(left='[', right=']')[0] pform = prettyForm(binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyIndices)) # store pform parts so it can be reassembled e.g. when powered pform.prettyFunc = prettyFunc pform.prettyArgs = prettyIndices return pform def _print_MatrixSlice(self, m): # XXX works only for applied functions from sympy.matrices import MatrixSymbol prettyFunc = self._print(m.parent) if not isinstance(m.parent, MatrixSymbol): prettyFunc = prettyForm(*prettyFunc.parens()) def ppslice(x, dim): x = list(x) if x[2] == 1: del x[2] if x[0] == 0: x[0] = '' if x[1] == dim: x[1] = '' return prettyForm(*self._print_seq(x, delimiter=':')) prettyArgs = self._print_seq((ppslice(m.rowslice, m.parent.rows), ppslice(m.colslice, m.parent.cols)), delimiter=', ').parens(left='[', right=']')[0] pform = prettyForm( binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) # store pform parts so it can be reassembled e.g. when powered pform.prettyFunc = prettyFunc pform.prettyArgs = prettyArgs return pform def _print_Transpose(self, expr): pform = self._print(expr.arg) from sympy.matrices import MatrixSymbol if not isinstance(expr.arg, MatrixSymbol): pform = prettyForm(*pform.parens()) pform = pform**(prettyForm('T')) return pform def _print_Adjoint(self, expr): pform = self._print(expr.arg) if self._use_unicode: dag = prettyForm('\N{DAGGER}') else: dag = prettyForm('+') from sympy.matrices import MatrixSymbol if not isinstance(expr.arg, MatrixSymbol): pform = prettyForm(*pform.parens()) pform = pform**dag return pform def _print_BlockMatrix(self, B): if B.blocks.shape == (1, 1): return self._print(B.blocks[0, 0]) return self._print(B.blocks) def _print_MatAdd(self, expr): s = None for item in expr.args: pform = self._print(item) if s is None: s = pform # First element else: coeff = item.as_coeff_mmul()[0] if _coeff_isneg(S(coeff)): s = prettyForm(*stringPict.next(s, ' ')) pform = self._print(item) else: s = prettyForm(*stringPict.next(s, ' + ')) s = prettyForm(*stringPict.next(s, pform)) return s def _print_MatMul(self, expr): args = list(expr.args) from sympy import Add, MatAdd, HadamardProduct, KroneckerProduct for i, a in enumerate(args): if (isinstance(a, (Add, MatAdd, HadamardProduct, KroneckerProduct)) and len(expr.args) > 1): args[i] = prettyForm(*self._print(a).parens()) else: args[i] = self._print(a) return prettyForm.__mul__(*args) def _print_Identity(self, expr): if self._use_unicode: return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL I}') else: return prettyForm('I') def _print_ZeroMatrix(self, expr): if self._use_unicode: return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ZERO}') else: return prettyForm('0') def _print_OneMatrix(self, expr): if self._use_unicode: return prettyForm('\N{MATHEMATICAL DOUBLE-STRUCK DIGIT ONE}') else: return prettyForm('1') def _print_DotProduct(self, expr): args = list(expr.args) for i, a in enumerate(args): args[i] = self._print(a) return prettyForm.__mul__(*args) def _print_MatPow(self, expr): pform = self._print(expr.base) from sympy.matrices import MatrixSymbol if not isinstance(expr.base, MatrixSymbol): pform = prettyForm(*pform.parens()) pform = pform**(self._print(expr.exp)) return pform def _print_HadamardProduct(self, expr): from sympy import MatAdd, MatMul, HadamardProduct if self._use_unicode: delim = pretty_atom('Ring') else: delim = '.*' return self._print_seq(expr.args, None, None, delim, parenthesize=lambda x: isinstance(x, (MatAdd, MatMul, HadamardProduct))) def _print_HadamardPower(self, expr): # from sympy import MatAdd, MatMul if self._use_unicode: circ = pretty_atom('Ring') else: circ = self._print('.') pretty_base = self._print(expr.base) pretty_exp = self._print(expr.exp) if precedence(expr.exp) < PRECEDENCE["Mul"]: pretty_exp = prettyForm(*pretty_exp.parens()) pretty_circ_exp = prettyForm( binding=prettyForm.LINE, *stringPict.next(circ, pretty_exp) ) return pretty_base**pretty_circ_exp def _print_KroneckerProduct(self, expr): from sympy import MatAdd, MatMul if self._use_unicode: delim = ' \N{N-ARY CIRCLED TIMES OPERATOR} ' else: delim = ' x ' return self._print_seq(expr.args, None, None, delim, parenthesize=lambda x: isinstance(x, (MatAdd, MatMul))) def _print_FunctionMatrix(self, X): D = self._print(X.lamda.expr) D = prettyForm(*D.parens('[', ']')) return D def _print_TransferFunction(self, expr): if not expr.num == 1: num, den = expr.num, expr.den res = Mul(num, Pow(den, -1, evaluate=False), evaluate=False) return self._print_Mul(res) else: return self._print(1)/self._print(expr.den) def _print_Series(self, expr): args = list(expr.args) for i, a in enumerate(expr.args): args[i] = prettyForm(*self._print(a).parens()) return prettyForm.__mul__(*args) def _print_MIMOSeries(self, expr): from sympy.physics.control.lti import MIMOParallel args = list(expr.args) pretty_args = [] for i, a in enumerate(reversed(args)): if (isinstance(a, MIMOParallel) and len(expr.args) > 1): expression = self._print(a) expression.baseline = expression.height()//2 pretty_args.append(prettyForm(*expression.parens())) else: expression = self._print(a) expression.baseline = expression.height()//2 pretty_args.append(expression) return prettyForm.__mul__(*pretty_args) def _print_Parallel(self, expr): s = None for item in expr.args: pform = self._print(item) if s is None: s = pform # First element else: s = prettyForm(*stringPict.next(s)) s.baseline = s.height()//2 s = prettyForm(*stringPict.next(s, ' + ')) s = prettyForm(*stringPict.next(s, pform)) return s def _print_MIMOParallel(self, expr): from sympy.physics.control.lti import TransferFunctionMatrix s = None for item in expr.args: pform = self._print(item) if s is None: s = pform # First element else: s = prettyForm(*stringPict.next(s)) s.baseline = s.height()//2 s = prettyForm(*stringPict.next(s, ' + ')) if isinstance(item, TransferFunctionMatrix): s.baseline = s.height() - 1 s = prettyForm(*stringPict.next(s, pform)) # s.baseline = s.height()//2 return s def _print_Feedback(self, expr): from sympy.physics.control import TransferFunction, Series num, tf = expr.sys1, TransferFunction(1, 1, expr.var) num_arg_list = list(num.args) if isinstance(num, Series) else [num] den_arg_list = list(expr.sys2.args) if \ isinstance(expr.sys2, Series) else [expr.sys2] if isinstance(num, Series) and isinstance(expr.sys2, Series): den = Series(*num_arg_list, *den_arg_list) elif isinstance(num, Series) and isinstance(expr.sys2, TransferFunction): if expr.sys2 == tf: den = Series(*num_arg_list) else: den = Series(*num_arg_list, expr.sys2) elif isinstance(num, TransferFunction) and isinstance(expr.sys2, Series): if num == tf: den = Series(*den_arg_list) else: den = Series(num, *den_arg_list) else: if num == tf: den = Series(*den_arg_list) elif expr.sys2 == tf: den = Series(*num_arg_list) else: den = Series(*num_arg_list, *den_arg_list) denom = prettyForm(*stringPict.next(self._print(tf))) denom.baseline = denom.height()//2 denom = prettyForm(*stringPict.next(denom, ' + ')) if expr.sign == -1 \ else prettyForm(*stringPict.next(denom, ' - ')) denom = prettyForm(*stringPict.next(denom, self._print(den))) return self._print(num)/denom def _print_MIMOFeedback(self, expr): from sympy.physics.control import MIMOSeries, TransferFunctionMatrix inv_mat = self._print(MIMOSeries(expr.sys2, expr.sys1)) plant = self._print(expr.sys1) _feedback = prettyForm(*stringPict.next(inv_mat)) _feedback = prettyForm(*stringPict.right("I + ", _feedback)) if expr.sign == -1 \ else prettyForm(*stringPict.right("I - ", _feedback)) _feedback = prettyForm(*stringPict.parens(_feedback)) _feedback.baseline = 0 _feedback = prettyForm(*stringPict.right(_feedback, '-1 ')) _feedback.baseline = _feedback.height()//2 _feedback = prettyForm.__mul__(_feedback, prettyForm(" ")) if isinstance(expr.sys1, TransferFunctionMatrix): _feedback.baseline = _feedback.height() - 1 _feedback = prettyForm(*stringPict.next(_feedback, plant)) return _feedback def _print_TransferFunctionMatrix(self, expr): mat = self._print(expr._expr_mat) mat.baseline = mat.height() - 1 subscript = greek_unicode['tau'] if self._use_unicode else r'{t}' mat = prettyForm(*mat.right(subscript)) return mat def _print_BasisDependent(self, expr): from sympy.vector import Vector if not self._use_unicode: raise NotImplementedError("ASCII pretty printing of BasisDependent is not implemented") if expr == expr.zero: return prettyForm(expr.zero._pretty_form) o1 = [] vectstrs = [] if isinstance(expr, Vector): items = expr.separate().items() else: items = [(0, expr)] for system, vect in items: inneritems = list(vect.components.items()) inneritems.sort(key = lambda x: x[0].__str__()) for k, v in inneritems: #if the coef of the basis vector is 1 #we skip the 1 if v == 1: o1.append("" + k._pretty_form) #Same for -1 elif v == -1: o1.append("(-1) " + k._pretty_form) #For a general expr else: #We always wrap the measure numbers in #parentheses arg_str = self._print( v).parens()[0] o1.append(arg_str + ' ' + k._pretty_form) vectstrs.append(k._pretty_form) #outstr = u("").join(o1) if o1[0].startswith(" + "): o1[0] = o1[0][3:] elif o1[0].startswith(" "): o1[0] = o1[0][1:] #Fixing the newlines lengths = [] strs = [''] flag = [] for i, partstr in enumerate(o1): flag.append(0) # XXX: What is this hack? if '\n' in partstr: tempstr = partstr tempstr = tempstr.replace(vectstrs[i], '') if '\N{right parenthesis extension}' in tempstr: # If scalar is a fraction for paren in range(len(tempstr)): flag[i] = 1 if tempstr[paren] == '\N{right parenthesis extension}': tempstr = tempstr[:paren] + '\N{right parenthesis extension}'\ + ' ' + vectstrs[i] + tempstr[paren + 1:] break elif '\N{RIGHT PARENTHESIS LOWER HOOK}' in tempstr: flag[i] = 1 tempstr = tempstr.replace('\N{RIGHT PARENTHESIS LOWER HOOK}', '\N{RIGHT PARENTHESIS LOWER HOOK}' + ' ' + vectstrs[i]) else: tempstr = tempstr.replace('\N{RIGHT PARENTHESIS UPPER HOOK}', '\N{RIGHT PARENTHESIS UPPER HOOK}' + ' ' + vectstrs[i]) o1[i] = tempstr o1 = [x.split('\n') for x in o1] n_newlines = max([len(x) for x in o1]) # Width of part in its pretty form if 1 in flag: # If there was a fractional scalar for i, parts in enumerate(o1): if len(parts) == 1: # If part has no newline parts.insert(0, ' ' * (len(parts[0]))) flag[i] = 1 for i, parts in enumerate(o1): lengths.append(len(parts[flag[i]])) for j in range(n_newlines): if j+1 <= len(parts): if j >= len(strs): strs.append(' ' * (sum(lengths[:-1]) + 3*(len(lengths)-1))) if j == flag[i]: strs[flag[i]] += parts[flag[i]] + ' + ' else: strs[j] += parts[j] + ' '*(lengths[-1] - len(parts[j])+ 3) else: if j >= len(strs): strs.append(' ' * (sum(lengths[:-1]) + 3*(len(lengths)-1))) strs[j] += ' '*(lengths[-1]+3) return prettyForm('\n'.join([s[:-3] for s in strs])) def _print_NDimArray(self, expr): from sympy import ImmutableMatrix if expr.rank() == 0: return self._print(expr[()]) level_str = [[]] + [[] for i in range(expr.rank())] shape_ranges = [list(range(i)) for i in expr.shape] # leave eventual matrix elements unflattened mat = lambda x: ImmutableMatrix(x, evaluate=False) for outer_i in itertools.product(*shape_ranges): level_str[-1].append(expr[outer_i]) even = True for back_outer_i in range(expr.rank()-1, -1, -1): if len(level_str[back_outer_i+1]) < expr.shape[back_outer_i]: break if even: level_str[back_outer_i].append(level_str[back_outer_i+1]) else: level_str[back_outer_i].append(mat( level_str[back_outer_i+1])) if len(level_str[back_outer_i + 1]) == 1: level_str[back_outer_i][-1] = mat( [[level_str[back_outer_i][-1]]]) even = not even level_str[back_outer_i+1] = [] out_expr = level_str[0][0] if expr.rank() % 2 == 1: out_expr = mat([out_expr]) return self._print(out_expr) def _printer_tensor_indices(self, name, indices, index_map={}): center = stringPict(name) top = stringPict(" "*center.width()) bot = stringPict(" "*center.width()) last_valence = None prev_map = None for i, index in enumerate(indices): indpic = self._print(index.args[0]) if ((index in index_map) or prev_map) and last_valence == index.is_up: if index.is_up: top = prettyForm(*stringPict.next(top, ",")) else: bot = prettyForm(*stringPict.next(bot, ",")) if index in index_map: indpic = prettyForm(*stringPict.next(indpic, "=")) indpic = prettyForm(*stringPict.next(indpic, self._print(index_map[index]))) prev_map = True else: prev_map = False if index.is_up: top = stringPict(*top.right(indpic)) center = stringPict(*center.right(" "*indpic.width())) bot = stringPict(*bot.right(" "*indpic.width())) else: bot = stringPict(*bot.right(indpic)) center = stringPict(*center.right(" "*indpic.width())) top = stringPict(*top.right(" "*indpic.width())) last_valence = index.is_up pict = prettyForm(*center.above(top)) pict = prettyForm(*pict.below(bot)) return pict def _print_Tensor(self, expr): name = expr.args[0].name indices = expr.get_indices() return self._printer_tensor_indices(name, indices) def _print_TensorElement(self, expr): name = expr.expr.args[0].name indices = expr.expr.get_indices() index_map = expr.index_map return self._printer_tensor_indices(name, indices, index_map) def _print_TensMul(self, expr): sign, args = expr._get_args_for_traditional_printer() args = [ prettyForm(*self._print(i).parens()) if precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i) for i in args ] pform = prettyForm.__mul__(*args) if sign: return prettyForm(*pform.left(sign)) else: return pform def _print_TensAdd(self, expr): args = [ prettyForm(*self._print(i).parens()) if precedence_traditional(i) < PRECEDENCE["Mul"] else self._print(i) for i in expr.args ] return prettyForm.__add__(*args) def _print_TensorIndex(self, expr): sym = expr.args[0] if not expr.is_up: sym = -sym return self._print(sym) def _print_PartialDerivative(self, deriv): if self._use_unicode: deriv_symbol = U('PARTIAL DIFFERENTIAL') else: deriv_symbol = r'd' x = None for variable in reversed(deriv.variables): s = self._print(variable) ds = prettyForm(*s.left(deriv_symbol)) if x is None: x = ds else: x = prettyForm(*x.right(' ')) x = prettyForm(*x.right(ds)) f = prettyForm( binding=prettyForm.FUNC, *self._print(deriv.expr).parens()) pform = prettyForm(deriv_symbol) if len(deriv.variables) > 1: pform = pform**self._print(len(deriv.variables)) pform = prettyForm(*pform.below(stringPict.LINE, x)) pform.baseline = pform.baseline + 1 pform = prettyForm(*stringPict.next(pform, f)) pform.binding = prettyForm.MUL return pform def _print_Piecewise(self, pexpr): P = {} for n, ec in enumerate(pexpr.args): P[n, 0] = self._print(ec.expr) if ec.cond == True: P[n, 1] = prettyForm('otherwise') else: P[n, 1] = prettyForm( *prettyForm('for ').right(self._print(ec.cond))) hsep = 2 vsep = 1 len_args = len(pexpr.args) # max widths maxw = [max([P[i, j].width() for i in range(len_args)]) for j in range(2)] # FIXME: Refactor this code and matrix into some tabular environment. # drawing result D = None for i in range(len_args): D_row = None for j in range(2): p = P[i, j] assert p.width() <= maxw[j] wdelta = maxw[j] - p.width() wleft = wdelta // 2 wright = wdelta - wleft p = prettyForm(*p.right(' '*wright)) p = prettyForm(*p.left(' '*wleft)) if D_row is None: D_row = p continue D_row = prettyForm(*D_row.right(' '*hsep)) # h-spacer D_row = prettyForm(*D_row.right(p)) if D is None: D = D_row # first row in a picture continue # v-spacer for _ in range(vsep): D = prettyForm(*D.below(' ')) D = prettyForm(*D.below(D_row)) D = prettyForm(*D.parens('{', '')) D.baseline = D.height()//2 D.binding = prettyForm.OPEN return D def _print_ITE(self, ite): from sympy.functions.elementary.piecewise import Piecewise return self._print(ite.rewrite(Piecewise)) def _hprint_vec(self, v): D = None for a in v: p = a if D is None: D = p else: D = prettyForm(*D.right(', ')) D = prettyForm(*D.right(p)) if D is None: D = stringPict(' ') return D def _hprint_vseparator(self, p1, p2, left=None, right=None, delimiter='', ifascii_nougly=False): if ifascii_nougly and not self._use_unicode: return self._print_seq((p1, '|', p2), left=left, right=right, delimiter=delimiter, ifascii_nougly=True) tmp = self._print_seq((p1, p2,), left=left, right=right, delimiter=delimiter) sep = stringPict(vobj('|', tmp.height()), baseline=tmp.baseline) return self._print_seq((p1, sep, p2), left=left, right=right, delimiter=delimiter) def _print_hyper(self, e): # FIXME refactor Matrix, Piecewise, and this into a tabular environment ap = [self._print(a) for a in e.ap] bq = [self._print(b) for b in e.bq] P = self._print(e.argument) P.baseline = P.height()//2 # Drawing result - first create the ap, bq vectors D = None for v in [ap, bq]: D_row = self._hprint_vec(v) if D is None: D = D_row # first row in a picture else: D = prettyForm(*D.below(' ')) D = prettyForm(*D.below(D_row)) # make sure that the argument `z' is centred vertically D.baseline = D.height()//2 # insert horizontal separator P = prettyForm(*P.left(' ')) D = prettyForm(*D.right(' ')) # insert separating `|` D = self._hprint_vseparator(D, P) # add parens D = prettyForm(*D.parens('(', ')')) # create the F symbol above = D.height()//2 - 1 below = D.height() - above - 1 sz, t, b, add, img = annotated('F') F = prettyForm('\n' * (above - t) + img + '\n' * (below - b), baseline=above + sz) add = (sz + 1)//2 F = prettyForm(*F.left(self._print(len(e.ap)))) F = prettyForm(*F.right(self._print(len(e.bq)))) F.baseline = above + add D = prettyForm(*F.right(' ', D)) return D def _print_meijerg(self, e): # FIXME refactor Matrix, Piecewise, and this into a tabular environment v = {} v[(0, 0)] = [self._print(a) for a in e.an] v[(0, 1)] = [self._print(a) for a in e.aother] v[(1, 0)] = [self._print(b) for b in e.bm] v[(1, 1)] = [self._print(b) for b in e.bother] P = self._print(e.argument) P.baseline = P.height()//2 vp = {} for idx in v: vp[idx] = self._hprint_vec(v[idx]) for i in range(2): maxw = max(vp[(0, i)].width(), vp[(1, i)].width()) for j in range(2): s = vp[(j, i)] left = (maxw - s.width()) // 2 right = maxw - left - s.width() s = prettyForm(*s.left(' ' * left)) s = prettyForm(*s.right(' ' * right)) vp[(j, i)] = s D1 = prettyForm(*vp[(0, 0)].right(' ', vp[(0, 1)])) D1 = prettyForm(*D1.below(' ')) D2 = prettyForm(*vp[(1, 0)].right(' ', vp[(1, 1)])) D = prettyForm(*D1.below(D2)) # make sure that the argument `z' is centred vertically D.baseline = D.height()//2 # insert horizontal separator P = prettyForm(*P.left(' ')) D = prettyForm(*D.right(' ')) # insert separating `|` D = self._hprint_vseparator(D, P) # add parens D = prettyForm(*D.parens('(', ')')) # create the G symbol above = D.height()//2 - 1 below = D.height() - above - 1 sz, t, b, add, img = annotated('G') F = prettyForm('\n' * (above - t) + img + '\n' * (below - b), baseline=above + sz) pp = self._print(len(e.ap)) pq = self._print(len(e.bq)) pm = self._print(len(e.bm)) pn = self._print(len(e.an)) def adjust(p1, p2): diff = p1.width() - p2.width() if diff == 0: return p1, p2 elif diff > 0: return p1, prettyForm(*p2.left(' '*diff)) else: return prettyForm(*p1.left(' '*-diff)), p2 pp, pm = adjust(pp, pm) pq, pn = adjust(pq, pn) pu = prettyForm(*pm.right(', ', pn)) pl = prettyForm(*pp.right(', ', pq)) ht = F.baseline - above - 2 if ht > 0: pu = prettyForm(*pu.below('\n'*ht)) p = prettyForm(*pu.below(pl)) F.baseline = above F = prettyForm(*F.right(p)) F.baseline = above + add D = prettyForm(*F.right(' ', D)) return D def _print_ExpBase(self, e): # TODO should exp_polar be printed differently? # what about exp_polar(0), exp_polar(1)? base = prettyForm(pretty_atom('Exp1', 'e')) return base ** self._print(e.args[0]) def _print_Exp1(self, e): return prettyForm(pretty_atom('Exp1', 'e')) def _print_Function(self, e, sort=False, func_name=None): # optional argument func_name for supplying custom names # XXX works only for applied functions return self._helper_print_function(e.func, e.args, sort=sort, func_name=func_name) def _print_mathieuc(self, e): return self._print_Function(e, func_name='C') def _print_mathieus(self, e): return self._print_Function(e, func_name='S') def _print_mathieucprime(self, e): return self._print_Function(e, func_name="C'") def _print_mathieusprime(self, e): return self._print_Function(e, func_name="S'") def _helper_print_function(self, func, args, sort=False, func_name=None, delimiter=', ', elementwise=False): if sort: args = sorted(args, key=default_sort_key) if not func_name and hasattr(func, "__name__"): func_name = func.__name__ if func_name: prettyFunc = self._print(Symbol(func_name)) else: prettyFunc = prettyForm(*self._print(func).parens()) if elementwise: if self._use_unicode: circ = pretty_atom('Modifier Letter Low Ring') else: circ = '.' circ = self._print(circ) prettyFunc = prettyForm( binding=prettyForm.LINE, *stringPict.next(prettyFunc, circ) ) prettyArgs = prettyForm(*self._print_seq(args, delimiter=delimiter).parens()) pform = prettyForm( binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) # store pform parts so it can be reassembled e.g. when powered pform.prettyFunc = prettyFunc pform.prettyArgs = prettyArgs return pform def _print_ElementwiseApplyFunction(self, e): func = e.function arg = e.expr args = [arg] return self._helper_print_function(func, args, delimiter="", elementwise=True) @property def _special_function_classes(self): from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.functions.special.gamma_functions import gamma, lowergamma from sympy.functions.special.zeta_functions import lerchphi from sympy.functions.special.beta_functions import beta from sympy.functions.special.delta_functions import DiracDelta from sympy.functions.special.error_functions import Chi return {KroneckerDelta: [greek_unicode['delta'], 'delta'], gamma: [greek_unicode['Gamma'], 'Gamma'], lerchphi: [greek_unicode['Phi'], 'lerchphi'], lowergamma: [greek_unicode['gamma'], 'gamma'], beta: [greek_unicode['Beta'], 'B'], DiracDelta: [greek_unicode['delta'], 'delta'], Chi: ['Chi', 'Chi']} def _print_FunctionClass(self, expr): for cls in self._special_function_classes: if issubclass(expr, cls) and expr.__name__ == cls.__name__: if self._use_unicode: return prettyForm(self._special_function_classes[cls][0]) else: return prettyForm(self._special_function_classes[cls][1]) func_name = expr.__name__ return prettyForm(pretty_symbol(func_name)) def _print_GeometryEntity(self, expr): # GeometryEntity is based on Tuple but should not print like a Tuple return self.emptyPrinter(expr) def _print_lerchphi(self, e): func_name = greek_unicode['Phi'] if self._use_unicode else 'lerchphi' return self._print_Function(e, func_name=func_name) def _print_dirichlet_eta(self, e): func_name = greek_unicode['eta'] if self._use_unicode else 'dirichlet_eta' return self._print_Function(e, func_name=func_name) def _print_Heaviside(self, e): func_name = greek_unicode['theta'] if self._use_unicode else 'Heaviside' if e.args[1]==1/2: pform = prettyForm(*self._print(e.args[0]).parens()) pform = prettyForm(*pform.left(func_name)) return pform else: return self._print_Function(e, func_name=func_name) def _print_fresnels(self, e): return self._print_Function(e, func_name="S") def _print_fresnelc(self, e): return self._print_Function(e, func_name="C") def _print_airyai(self, e): return self._print_Function(e, func_name="Ai") def _print_airybi(self, e): return self._print_Function(e, func_name="Bi") def _print_airyaiprime(self, e): return self._print_Function(e, func_name="Ai'") def _print_airybiprime(self, e): return self._print_Function(e, func_name="Bi'") def _print_LambertW(self, e): return self._print_Function(e, func_name="W") def _print_Lambda(self, e): expr = e.expr sig = e.signature if self._use_unicode: arrow = " \N{RIGHTWARDS ARROW FROM BAR} " else: arrow = " -> " if len(sig) == 1 and sig[0].is_symbol: sig = sig[0] var_form = self._print(sig) return prettyForm(*stringPict.next(var_form, arrow, self._print(expr)), binding=8) def _print_Order(self, expr): pform = self._print(expr.expr) if (expr.point and any(p != S.Zero for p in expr.point)) or \ len(expr.variables) > 1: pform = prettyForm(*pform.right("; ")) if len(expr.variables) > 1: pform = prettyForm(*pform.right(self._print(expr.variables))) elif len(expr.variables): pform = prettyForm(*pform.right(self._print(expr.variables[0]))) if self._use_unicode: pform = prettyForm(*pform.right(" \N{RIGHTWARDS ARROW} ")) else: pform = prettyForm(*pform.right(" -> ")) if len(expr.point) > 1: pform = prettyForm(*pform.right(self._print(expr.point))) else: pform = prettyForm(*pform.right(self._print(expr.point[0]))) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left("O")) return pform def _print_SingularityFunction(self, e): if self._use_unicode: shift = self._print(e.args[0]-e.args[1]) n = self._print(e.args[2]) base = prettyForm("<") base = prettyForm(*base.right(shift)) base = prettyForm(*base.right(">")) pform = base**n return pform else: n = self._print(e.args[2]) shift = self._print(e.args[0]-e.args[1]) base = self._print_seq(shift, "<", ">", ' ') return base**n def _print_beta(self, e): func_name = greek_unicode['Beta'] if self._use_unicode else 'B' return self._print_Function(e, func_name=func_name) def _print_betainc(self, e): func_name = "B'" return self._print_Function(e, func_name=func_name) def _print_betainc_regularized(self, e): func_name = 'I' return self._print_Function(e, func_name=func_name) def _print_gamma(self, e): func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma' return self._print_Function(e, func_name=func_name) def _print_uppergamma(self, e): func_name = greek_unicode['Gamma'] if self._use_unicode else 'Gamma' return self._print_Function(e, func_name=func_name) def _print_lowergamma(self, e): func_name = greek_unicode['gamma'] if self._use_unicode else 'lowergamma' return self._print_Function(e, func_name=func_name) def _print_DiracDelta(self, e): if self._use_unicode: if len(e.args) == 2: a = prettyForm(greek_unicode['delta']) b = self._print(e.args[1]) b = prettyForm(*b.parens()) c = self._print(e.args[0]) c = prettyForm(*c.parens()) pform = a**b pform = prettyForm(*pform.right(' ')) pform = prettyForm(*pform.right(c)) return pform pform = self._print(e.args[0]) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left(greek_unicode['delta'])) return pform else: return self._print_Function(e) def _print_expint(self, e): from sympy import Function if e.args[0].is_Integer and self._use_unicode: return self._print_Function(Function('E_%s' % e.args[0])(e.args[1])) return self._print_Function(e) def _print_Chi(self, e): # This needs a special case since otherwise it comes out as greek # letter chi... prettyFunc = prettyForm("Chi") prettyArgs = prettyForm(*self._print_seq(e.args).parens()) pform = prettyForm( binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) # store pform parts so it can be reassembled e.g. when powered pform.prettyFunc = prettyFunc pform.prettyArgs = prettyArgs return pform def _print_elliptic_e(self, e): pforma0 = self._print(e.args[0]) if len(e.args) == 1: pform = pforma0 else: pforma1 = self._print(e.args[1]) pform = self._hprint_vseparator(pforma0, pforma1) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left('E')) return pform def _print_elliptic_k(self, e): pform = self._print(e.args[0]) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left('K')) return pform def _print_elliptic_f(self, e): pforma0 = self._print(e.args[0]) pforma1 = self._print(e.args[1]) pform = self._hprint_vseparator(pforma0, pforma1) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left('F')) return pform def _print_elliptic_pi(self, e): name = greek_unicode['Pi'] if self._use_unicode else 'Pi' pforma0 = self._print(e.args[0]) pforma1 = self._print(e.args[1]) if len(e.args) == 2: pform = self._hprint_vseparator(pforma0, pforma1) else: pforma2 = self._print(e.args[2]) pforma = self._hprint_vseparator(pforma1, pforma2, ifascii_nougly=False) pforma = prettyForm(*pforma.left('; ')) pform = prettyForm(*pforma.left(pforma0)) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left(name)) return pform def _print_GoldenRatio(self, expr): if self._use_unicode: return prettyForm(pretty_symbol('phi')) return self._print(Symbol("GoldenRatio")) def _print_EulerGamma(self, expr): if self._use_unicode: return prettyForm(pretty_symbol('gamma')) return self._print(Symbol("EulerGamma")) def _print_Mod(self, expr): pform = self._print(expr.args[0]) if pform.binding > prettyForm.MUL: pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.right(' mod ')) pform = prettyForm(*pform.right(self._print(expr.args[1]))) pform.binding = prettyForm.OPEN return pform def _print_Add(self, expr, order=None): terms = self._as_ordered_terms(expr, order=order) pforms, indices = [], [] def pretty_negative(pform, index): """Prepend a minus sign to a pretty form. """ #TODO: Move this code to prettyForm if index == 0: if pform.height() > 1: pform_neg = '- ' else: pform_neg = '-' else: pform_neg = ' - ' if (pform.binding > prettyForm.NEG or pform.binding == prettyForm.ADD): p = stringPict(*pform.parens()) else: p = pform p = stringPict.next(pform_neg, p) # Lower the binding to NEG, even if it was higher. Otherwise, it # will print as a + ( - (b)), instead of a - (b). return prettyForm(binding=prettyForm.NEG, *p) for i, term in enumerate(terms): if term.is_Mul and _coeff_isneg(term): coeff, other = term.as_coeff_mul(rational=False) if coeff == -1: negterm = Mul(*other, evaluate=False) else: negterm = Mul(-coeff, *other, evaluate=False) pform = self._print(negterm) pforms.append(pretty_negative(pform, i)) elif term.is_Rational and term.q > 1: pforms.append(None) indices.append(i) elif term.is_Number and term < 0: pform = self._print(-term) pforms.append(pretty_negative(pform, i)) elif term.is_Relational: pforms.append(prettyForm(*self._print(term).parens())) else: pforms.append(self._print(term)) if indices: large = True for pform in pforms: if pform is not None and pform.height() > 1: break else: large = False for i in indices: term, negative = terms[i], False if term < 0: term, negative = -term, True if large: pform = prettyForm(str(term.p))/prettyForm(str(term.q)) else: pform = self._print(term) if negative: pform = pretty_negative(pform, i) pforms[i] = pform return prettyForm.__add__(*pforms) def _print_Mul(self, product): from sympy.physics.units import Quantity # Check for unevaluated Mul. In this case we need to make sure the # identities are visible, multiple Rational factors are not combined # etc so we display in a straight-forward form that fully preserves all # args and their order. args = product.args if args[0] is S.One or any(isinstance(arg, Number) for arg in args[1:]): strargs = list(map(self._print, args)) # XXX: This is a hack to work around the fact that # prettyForm.__mul__ absorbs a leading -1 in the args. Probably it # would be better to fix this in prettyForm.__mul__ instead. negone = strargs[0] == '-1' if negone: strargs[0] = prettyForm('1', 0, 0) obj = prettyForm.__mul__(*strargs) if negone: obj = prettyForm('-' + obj.s, obj.baseline, obj.binding) return obj a = [] # items in the numerator b = [] # items that are in the denominator (if any) if self.order not in ('old', 'none'): args = product.as_ordered_factors() else: args = list(product.args) # If quantities are present append them at the back args = sorted(args, key=lambda x: isinstance(x, Quantity) or (isinstance(x, Pow) and isinstance(x.base, Quantity))) # Gather terms for numerator/denominator for item in args: if item.is_commutative and item.is_Pow and item.exp.is_Rational and item.exp.is_negative: if item.exp != -1: b.append(Pow(item.base, -item.exp, evaluate=False)) else: b.append(Pow(item.base, -item.exp)) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append( Rational(item.p) ) if item.q != 1: b.append( Rational(item.q) ) else: a.append(item) from sympy import Integral, Piecewise, Product, Sum # Convert to pretty forms. Add parens to Add instances if there # is more than one term in the numer/denom for i in range(0, len(a)): if (a[i].is_Add and len(a) > 1) or (i != len(a) - 1 and isinstance(a[i], (Integral, Piecewise, Product, Sum))): a[i] = prettyForm(*self._print(a[i]).parens()) elif a[i].is_Relational: a[i] = prettyForm(*self._print(a[i]).parens()) else: a[i] = self._print(a[i]) for i in range(0, len(b)): if (b[i].is_Add and len(b) > 1) or (i != len(b) - 1 and isinstance(b[i], (Integral, Piecewise, Product, Sum))): b[i] = prettyForm(*self._print(b[i]).parens()) else: b[i] = self._print(b[i]) # Construct a pretty form if len(b) == 0: return prettyForm.__mul__(*a) else: if len(a) == 0: a.append( self._print(S.One) ) return prettyForm.__mul__(*a)/prettyForm.__mul__(*b) # A helper function for _print_Pow to print x**(1/n) def _print_nth_root(self, base, root): bpretty = self._print(base) # In very simple cases, use a single-char root sign if (self._settings['use_unicode_sqrt_char'] and self._use_unicode and root == 2 and bpretty.height() == 1 and (bpretty.width() == 1 or (base.is_Integer and base.is_nonnegative))): return prettyForm(*bpretty.left('\N{SQUARE ROOT}')) # Construct root sign, start with the \/ shape _zZ = xobj('/', 1) rootsign = xobj('\\', 1) + _zZ # Constructing the number to put on root rpretty = self._print(root) # roots look bad if they are not a single line if rpretty.height() != 1: return self._print(base)**self._print(1/root) # If power is half, no number should appear on top of root sign exp = '' if root == 2 else str(rpretty).ljust(2) if len(exp) > 2: rootsign = ' '*(len(exp) - 2) + rootsign # Stack the exponent rootsign = stringPict(exp + '\n' + rootsign) rootsign.baseline = 0 # Diagonal: length is one less than height of base linelength = bpretty.height() - 1 diagonal = stringPict('\n'.join( ' '*(linelength - i - 1) + _zZ + ' '*i for i in range(linelength) )) # Put baseline just below lowest line: next to exp diagonal.baseline = linelength - 1 # Make the root symbol rootsign = prettyForm(*rootsign.right(diagonal)) # Det the baseline to match contents to fix the height # but if the height of bpretty is one, the rootsign must be one higher rootsign.baseline = max(1, bpretty.baseline) #build result s = prettyForm(hobj('_', 2 + bpretty.width())) s = prettyForm(*bpretty.above(s)) s = prettyForm(*s.left(rootsign)) return s def _print_Pow(self, power): from sympy.simplify.simplify import fraction b, e = power.as_base_exp() if power.is_commutative: if e is S.NegativeOne: return prettyForm("1")/self._print(b) n, d = fraction(e) if n is S.One and d.is_Atom and not e.is_Integer and (e.is_Rational or d.is_Symbol) \ and self._settings['root_notation']: return self._print_nth_root(b, d) if e.is_Rational and e < 0: return prettyForm("1")/self._print(Pow(b, -e, evaluate=False)) if b.is_Relational: return prettyForm(*self._print(b).parens()).__pow__(self._print(e)) return self._print(b)**self._print(e) def _print_UnevaluatedExpr(self, expr): return self._print(expr.args[0]) def __print_numer_denom(self, p, q): if q == 1: if p < 0: return prettyForm(str(p), binding=prettyForm.NEG) else: return prettyForm(str(p)) elif abs(p) >= 10 and abs(q) >= 10: # If more than one digit in numer and denom, print larger fraction if p < 0: return prettyForm(str(p), binding=prettyForm.NEG)/prettyForm(str(q)) # Old printing method: #pform = prettyForm(str(-p))/prettyForm(str(q)) #return prettyForm(binding=prettyForm.NEG, *pform.left('- ')) else: return prettyForm(str(p))/prettyForm(str(q)) else: return None def _print_Rational(self, expr): result = self.__print_numer_denom(expr.p, expr.q) if result is not None: return result else: return self.emptyPrinter(expr) def _print_Fraction(self, expr): result = self.__print_numer_denom(expr.numerator, expr.denominator) if result is not None: return result else: return self.emptyPrinter(expr) def _print_ProductSet(self, p): if len(p.sets) >= 1 and not has_variety(p.sets): return self._print(p.sets[0]) ** self._print(len(p.sets)) else: prod_char = "\N{MULTIPLICATION SIGN}" if self._use_unicode else 'x' return self._print_seq(p.sets, None, None, ' %s ' % prod_char, parenthesize=lambda set: set.is_Union or set.is_Intersection or set.is_ProductSet) def _print_FiniteSet(self, s): items = sorted(s.args, key=default_sort_key) return self._print_seq(items, '{', '}', ', ' ) def _print_Range(self, s): if self._use_unicode: dots = "\N{HORIZONTAL ELLIPSIS}" else: dots = '...' if s.start.is_infinite and s.stop.is_infinite: if s.step.is_positive: printset = dots, -1, 0, 1, dots else: printset = dots, 1, 0, -1, dots elif s.start.is_infinite: printset = dots, s[-1] - s.step, s[-1] elif s.stop.is_infinite: it = iter(s) printset = next(it), next(it), dots elif len(s) > 4: it = iter(s) printset = next(it), next(it), dots, s[-1] else: printset = tuple(s) return self._print_seq(printset, '{', '}', ', ' ) def _print_Interval(self, i): if i.start == i.end: return self._print_seq(i.args[:1], '{', '}') else: if i.left_open: left = '(' else: left = '[' if i.right_open: right = ')' else: right = ']' return self._print_seq(i.args[:2], left, right) def _print_AccumulationBounds(self, i): left = '<' right = '>' return self._print_seq(i.args[:2], left, right) def _print_Intersection(self, u): delimiter = ' %s ' % pretty_atom('Intersection', 'n') return self._print_seq(u.args, None, None, delimiter, parenthesize=lambda set: set.is_ProductSet or set.is_Union or set.is_Complement) def _print_Union(self, u): union_delimiter = ' %s ' % pretty_atom('Union', 'U') return self._print_seq(u.args, None, None, union_delimiter, parenthesize=lambda set: set.is_ProductSet or set.is_Intersection or set.is_Complement) def _print_SymmetricDifference(self, u): if not self._use_unicode: raise NotImplementedError("ASCII pretty printing of SymmetricDifference is not implemented") sym_delimeter = ' %s ' % pretty_atom('SymmetricDifference') return self._print_seq(u.args, None, None, sym_delimeter) def _print_Complement(self, u): delimiter = r' \ ' return self._print_seq(u.args, None, None, delimiter, parenthesize=lambda set: set.is_ProductSet or set.is_Intersection or set.is_Union) def _print_ImageSet(self, ts): if self._use_unicode: inn = "\N{SMALL ELEMENT OF}" else: inn = 'in' fun = ts.lamda sets = ts.base_sets signature = fun.signature expr = self._print(fun.expr) # TODO: the stuff to the left of the | and the stuff to the right of # the | should have independent baselines, that way something like # ImageSet(Lambda(x, 1/x**2), S.Naturals) prints the "x in N" part # centered on the right instead of aligned with the fraction bar on # the left. The same also applies to ConditionSet and ComplexRegion if len(signature) == 1: S = self._print_seq((signature[0], inn, sets[0]), delimiter=' ') return self._hprint_vseparator(expr, S, left='{', right='}', ifascii_nougly=True, delimiter=' ') else: pargs = tuple(j for var, setv in zip(signature, sets) for j in (var, ' ', inn, ' ', setv, ", ")) S = self._print_seq(pargs[:-1], delimiter='') return self._hprint_vseparator(expr, S, left='{', right='}', ifascii_nougly=True, delimiter=' ') def _print_ConditionSet(self, ts): if self._use_unicode: inn = "\N{SMALL ELEMENT OF}" # using _and because and is a keyword and it is bad practice to # overwrite them _and = "\N{LOGICAL AND}" else: inn = 'in' _and = 'and' variables = self._print_seq(Tuple(ts.sym)) as_expr = getattr(ts.condition, 'as_expr', None) if as_expr is not None: cond = self._print(ts.condition.as_expr()) else: cond = self._print(ts.condition) if self._use_unicode: cond = self._print(cond) cond = prettyForm(*cond.parens()) if ts.base_set is S.UniversalSet: return self._hprint_vseparator(variables, cond, left="{", right="}", ifascii_nougly=True, delimiter=' ') base = self._print(ts.base_set) C = self._print_seq((variables, inn, base, _and, cond), delimiter=' ') return self._hprint_vseparator(variables, C, left="{", right="}", ifascii_nougly=True, delimiter=' ') def _print_ComplexRegion(self, ts): if self._use_unicode: inn = "\N{SMALL ELEMENT OF}" else: inn = 'in' variables = self._print_seq(ts.variables) expr = self._print(ts.expr) prodsets = self._print(ts.sets) C = self._print_seq((variables, inn, prodsets), delimiter=' ') return self._hprint_vseparator(expr, C, left="{", right="}", ifascii_nougly=True, delimiter=' ') def _print_Contains(self, e): var, set = e.args if self._use_unicode: el = " \N{ELEMENT OF} " return prettyForm(*stringPict.next(self._print(var), el, self._print(set)), binding=8) else: return prettyForm(sstr(e)) def _print_FourierSeries(self, s): if self._use_unicode: dots = "\N{HORIZONTAL ELLIPSIS}" else: dots = '...' return self._print_Add(s.truncate()) + self._print(dots) def _print_FormalPowerSeries(self, s): return self._print_Add(s.infinite) def _print_SetExpr(self, se): pretty_set = prettyForm(*self._print(se.set).parens()) pretty_name = self._print(Symbol("SetExpr")) return prettyForm(*pretty_name.right(pretty_set)) def _print_SeqFormula(self, s): if self._use_unicode: dots = "\N{HORIZONTAL ELLIPSIS}" else: dots = '...' if len(s.start.free_symbols) > 0 or len(s.stop.free_symbols) > 0: raise NotImplementedError("Pretty printing of sequences with symbolic bound not implemented") if s.start is S.NegativeInfinity: stop = s.stop printset = (dots, s.coeff(stop - 3), s.coeff(stop - 2), s.coeff(stop - 1), s.coeff(stop)) elif s.stop is S.Infinity or s.length > 4: printset = s[:4] printset.append(dots) printset = tuple(printset) else: printset = tuple(s) return self._print_list(printset) _print_SeqPer = _print_SeqFormula _print_SeqAdd = _print_SeqFormula _print_SeqMul = _print_SeqFormula def _print_seq(self, seq, left=None, right=None, delimiter=', ', parenthesize=lambda x: False, ifascii_nougly=True): try: pforms = [] for item in seq: pform = self._print(item) if parenthesize(item): pform = prettyForm(*pform.parens()) if pforms: pforms.append(delimiter) pforms.append(pform) if not pforms: s = stringPict('') else: s = prettyForm(*stringPict.next(*pforms)) # XXX: Under the tests from #15686 the above raises: # AttributeError: 'Fake' object has no attribute 'baseline' # This is caught below but that is not the right way to # fix it. except AttributeError: s = None for item in seq: pform = self.doprint(item) if parenthesize(item): pform = prettyForm(*pform.parens()) if s is None: # first element s = pform else : s = prettyForm(*stringPict.next(s, delimiter)) s = prettyForm(*stringPict.next(s, pform)) if s is None: s = stringPict('') s = prettyForm(*s.parens(left, right, ifascii_nougly=ifascii_nougly)) return s def join(self, delimiter, args): pform = None for arg in args: if pform is None: pform = arg else: pform = prettyForm(*pform.right(delimiter)) pform = prettyForm(*pform.right(arg)) if pform is None: return prettyForm("") else: return pform def _print_list(self, l): return self._print_seq(l, '[', ']') def _print_tuple(self, t): if len(t) == 1: ptuple = prettyForm(*stringPict.next(self._print(t[0]), ',')) return prettyForm(*ptuple.parens('(', ')', ifascii_nougly=True)) else: return self._print_seq(t, '(', ')') def _print_Tuple(self, expr): return self._print_tuple(expr) def _print_dict(self, d): keys = sorted(d.keys(), key=default_sort_key) items = [] for k in keys: K = self._print(k) V = self._print(d[k]) s = prettyForm(*stringPict.next(K, ': ', V)) items.append(s) return self._print_seq(items, '{', '}') def _print_Dict(self, d): return self._print_dict(d) def _print_set(self, s): if not s: return prettyForm('set()') items = sorted(s, key=default_sort_key) pretty = self._print_seq(items) pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True)) return pretty def _print_frozenset(self, s): if not s: return prettyForm('frozenset()') items = sorted(s, key=default_sort_key) pretty = self._print_seq(items) pretty = prettyForm(*pretty.parens('{', '}', ifascii_nougly=True)) pretty = prettyForm(*pretty.parens('(', ')', ifascii_nougly=True)) pretty = prettyForm(*stringPict.next(type(s).__name__, pretty)) return pretty def _print_UniversalSet(self, s): if self._use_unicode: return prettyForm("\N{MATHEMATICAL DOUBLE-STRUCK CAPITAL U}") else: return prettyForm('UniversalSet') def _print_PolyRing(self, ring): return prettyForm(sstr(ring)) def _print_FracField(self, field): return prettyForm(sstr(field)) def _print_FreeGroupElement(self, elm): return prettyForm(str(elm)) def _print_PolyElement(self, poly): return prettyForm(sstr(poly)) def _print_FracElement(self, frac): return prettyForm(sstr(frac)) def _print_AlgebraicNumber(self, expr): if expr.is_aliased: return self._print(expr.as_poly().as_expr()) else: return self._print(expr.as_expr()) def _print_ComplexRootOf(self, expr): args = [self._print_Add(expr.expr, order='lex'), expr.index] pform = prettyForm(*self._print_seq(args).parens()) pform = prettyForm(*pform.left('CRootOf')) return pform def _print_RootSum(self, expr): args = [self._print_Add(expr.expr, order='lex')] if expr.fun is not S.IdentityFunction: args.append(self._print(expr.fun)) pform = prettyForm(*self._print_seq(args).parens()) pform = prettyForm(*pform.left('RootSum')) return pform def _print_FiniteField(self, expr): if self._use_unicode: form = '\N{DOUBLE-STRUCK CAPITAL Z}_%d' else: form = 'GF(%d)' return prettyForm(pretty_symbol(form % expr.mod)) def _print_IntegerRing(self, expr): if self._use_unicode: return prettyForm('\N{DOUBLE-STRUCK CAPITAL Z}') else: return prettyForm('ZZ') def _print_RationalField(self, expr): if self._use_unicode: return prettyForm('\N{DOUBLE-STRUCK CAPITAL Q}') else: return prettyForm('QQ') def _print_RealField(self, domain): if self._use_unicode: prefix = '\N{DOUBLE-STRUCK CAPITAL R}' else: prefix = 'RR' if domain.has_default_precision: return prettyForm(prefix) else: return self._print(pretty_symbol(prefix + "_" + str(domain.precision))) def _print_ComplexField(self, domain): if self._use_unicode: prefix = '\N{DOUBLE-STRUCK CAPITAL C}' else: prefix = 'CC' if domain.has_default_precision: return prettyForm(prefix) else: return self._print(pretty_symbol(prefix + "_" + str(domain.precision))) def _print_PolynomialRing(self, expr): args = list(expr.symbols) if not expr.order.is_default: order = prettyForm(*prettyForm("order=").right(self._print(expr.order))) args.append(order) pform = self._print_seq(args, '[', ']') pform = prettyForm(*pform.left(self._print(expr.domain))) return pform def _print_FractionField(self, expr): args = list(expr.symbols) if not expr.order.is_default: order = prettyForm(*prettyForm("order=").right(self._print(expr.order))) args.append(order) pform = self._print_seq(args, '(', ')') pform = prettyForm(*pform.left(self._print(expr.domain))) return pform def _print_PolynomialRingBase(self, expr): g = expr.symbols if str(expr.order) != str(expr.default_order): g = g + ("order=" + str(expr.order),) pform = self._print_seq(g, '[', ']') pform = prettyForm(*pform.left(self._print(expr.domain))) return pform def _print_GroebnerBasis(self, basis): exprs = [ self._print_Add(arg, order=basis.order) for arg in basis.exprs ] exprs = prettyForm(*self.join(", ", exprs).parens(left="[", right="]")) gens = [ self._print(gen) for gen in basis.gens ] domain = prettyForm( *prettyForm("domain=").right(self._print(basis.domain))) order = prettyForm( *prettyForm("order=").right(self._print(basis.order))) pform = self.join(", ", [exprs] + gens + [domain, order]) pform = prettyForm(*pform.parens()) pform = prettyForm(*pform.left(basis.__class__.__name__)) return pform def _print_Subs(self, e): pform = self._print(e.expr) pform = prettyForm(*pform.parens()) h = pform.height() if pform.height() > 1 else 2 rvert = stringPict(vobj('|', h), baseline=pform.baseline) pform = prettyForm(*pform.right(rvert)) b = pform.baseline pform.baseline = pform.height() - 1 pform = prettyForm(*pform.right(self._print_seq([ self._print_seq((self._print(v[0]), xsym('=='), self._print(v[1])), delimiter='') for v in zip(e.variables, e.point) ]))) pform.baseline = b return pform def _print_number_function(self, e, name): # Print name_arg[0] for one argument or name_arg[0](arg[1]) # for more than one argument pform = prettyForm(name) arg = self._print(e.args[0]) pform_arg = prettyForm(" "*arg.width()) pform_arg = prettyForm(*pform_arg.below(arg)) pform = prettyForm(*pform.right(pform_arg)) if len(e.args) == 1: return pform m, x = e.args # TODO: copy-pasted from _print_Function: can we do better? prettyFunc = pform prettyArgs = prettyForm(*self._print_seq([x]).parens()) pform = prettyForm( binding=prettyForm.FUNC, *stringPict.next(prettyFunc, prettyArgs)) pform.prettyFunc = prettyFunc pform.prettyArgs = prettyArgs return pform def _print_euler(self, e): return self._print_number_function(e, "E") def _print_catalan(self, e): return self._print_number_function(e, "C") def _print_bernoulli(self, e): return self._print_number_function(e, "B") _print_bell = _print_bernoulli def _print_lucas(self, e): return self._print_number_function(e, "L") def _print_fibonacci(self, e): return self._print_number_function(e, "F") def _print_tribonacci(self, e): return self._print_number_function(e, "T") def _print_stieltjes(self, e): if self._use_unicode: return self._print_number_function(e, '\N{GREEK SMALL LETTER GAMMA}') else: return self._print_number_function(e, "stieltjes") def _print_KroneckerDelta(self, e): pform = self._print(e.args[0]) pform = prettyForm(*pform.right(prettyForm(','))) pform = prettyForm(*pform.right(self._print(e.args[1]))) if self._use_unicode: a = stringPict(pretty_symbol('delta')) else: a = stringPict('d') b = pform top = stringPict(*b.left(' '*a.width())) bot = stringPict(*a.right(' '*b.width())) return prettyForm(binding=prettyForm.POW, *bot.below(top)) def _print_RandomDomain(self, d): if hasattr(d, 'as_boolean'): pform = self._print('Domain: ') pform = prettyForm(*pform.right(self._print(d.as_boolean()))) return pform elif hasattr(d, 'set'): pform = self._print('Domain: ') pform = prettyForm(*pform.right(self._print(d.symbols))) pform = prettyForm(*pform.right(self._print(' in '))) pform = prettyForm(*pform.right(self._print(d.set))) return pform elif hasattr(d, 'symbols'): pform = self._print('Domain on ') pform = prettyForm(*pform.right(self._print(d.symbols))) return pform else: return self._print(None) def _print_DMP(self, p): try: if p.ring is not None: # TODO incorporate order return self._print(p.ring.to_sympy(p)) except SympifyError: pass return self._print(repr(p)) def _print_DMF(self, p): return self._print_DMP(p) def _print_Object(self, object): return self._print(pretty_symbol(object.name)) def _print_Morphism(self, morphism): arrow = xsym("-->") domain = self._print(morphism.domain) codomain = self._print(morphism.codomain) tail = domain.right(arrow, codomain)[0] return prettyForm(tail) def _print_NamedMorphism(self, morphism): pretty_name = self._print(pretty_symbol(morphism.name)) pretty_morphism = self._print_Morphism(morphism) return prettyForm(pretty_name.right(":", pretty_morphism)[0]) def _print_IdentityMorphism(self, morphism): from sympy.categories import NamedMorphism return self._print_NamedMorphism( NamedMorphism(morphism.domain, morphism.codomain, "id")) def _print_CompositeMorphism(self, morphism): circle = xsym(".") # All components of the morphism have names and it is thus # possible to build the name of the composite. component_names_list = [pretty_symbol(component.name) for component in morphism.components] component_names_list.reverse() component_names = circle.join(component_names_list) + ":" pretty_name = self._print(component_names) pretty_morphism = self._print_Morphism(morphism) return prettyForm(pretty_name.right(pretty_morphism)[0]) def _print_Category(self, category): return self._print(pretty_symbol(category.name)) def _print_Diagram(self, diagram): if not diagram.premises: # This is an empty diagram. return self._print(S.EmptySet) pretty_result = self._print(diagram.premises) if diagram.conclusions: results_arrow = " %s " % xsym("==>") pretty_conclusions = self._print(diagram.conclusions)[0] pretty_result = pretty_result.right( results_arrow, pretty_conclusions) return prettyForm(pretty_result[0]) def _print_DiagramGrid(self, grid): from sympy.matrices import Matrix from sympy import Symbol matrix = Matrix([[grid[i, j] if grid[i, j] else Symbol(" ") for j in range(grid.width)] for i in range(grid.height)]) return self._print_matrix_contents(matrix) def _print_FreeModuleElement(self, m): # Print as row vector for convenience, for now. return self._print_seq(m, '[', ']') def _print_SubModule(self, M): return self._print_seq(M.gens, '<', '>') def _print_FreeModule(self, M): return self._print(M.ring)**self._print(M.rank) def _print_ModuleImplementedIdeal(self, M): return self._print_seq([x for [x] in M._module.gens], '<', '>') def _print_QuotientRing(self, R): return self._print(R.ring) / self._print(R.base_ideal) def _print_QuotientRingElement(self, R): return self._print(R.data) + self._print(R.ring.base_ideal) def _print_QuotientModuleElement(self, m): return self._print(m.data) + self._print(m.module.killed_module) def _print_QuotientModule(self, M): return self._print(M.base) / self._print(M.killed_module) def _print_MatrixHomomorphism(self, h): matrix = self._print(h._sympy_matrix()) matrix.baseline = matrix.height() // 2 pform = prettyForm(*matrix.right(' : ', self._print(h.domain), ' %s> ' % hobj('-', 2), self._print(h.codomain))) return pform def _print_Manifold(self, manifold): return self._print(manifold.name) def _print_Patch(self, patch): return self._print(patch.name) def _print_CoordSystem(self, coords): return self._print(coords.name) def _print_BaseScalarField(self, field): string = field._coord_sys.symbols[field._index].name return self._print(pretty_symbol(string)) def _print_BaseVectorField(self, field): s = U('PARTIAL DIFFERENTIAL') + '_' + field._coord_sys.symbols[field._index].name return self._print(pretty_symbol(s)) def _print_Differential(self, diff): field = diff._form_field if hasattr(field, '_coord_sys'): string = field._coord_sys.symbols[field._index].name return self._print('\N{DOUBLE-STRUCK ITALIC SMALL D} ' + pretty_symbol(string)) else: pform = self._print(field) pform = prettyForm(*pform.parens()) return prettyForm(*pform.left("\N{DOUBLE-STRUCK ITALIC SMALL D}")) def _print_Tr(self, p): #TODO: Handle indices pform = self._print(p.args[0]) pform = prettyForm(*pform.left('%s(' % (p.__class__.__name__))) pform = prettyForm(*pform.right(')')) return pform def _print_primenu(self, e): pform = self._print(e.args[0]) pform = prettyForm(*pform.parens()) if self._use_unicode: pform = prettyForm(*pform.left(greek_unicode['nu'])) else: pform = prettyForm(*pform.left('nu')) return pform def _print_primeomega(self, e): pform = self._print(e.args[0]) pform = prettyForm(*pform.parens()) if self._use_unicode: pform = prettyForm(*pform.left(greek_unicode['Omega'])) else: pform = prettyForm(*pform.left('Omega')) return pform def _print_Quantity(self, e): if e.name.name == 'degree': pform = self._print("\N{DEGREE SIGN}") return pform else: return self.emptyPrinter(e) def _print_AssignmentBase(self, e): op = prettyForm(' ' + xsym(e.op) + ' ') l = self._print(e.lhs) r = self._print(e.rhs) pform = prettyForm(*stringPict.next(l, op, r)) return pform def _print_Str(self, s): return self._print(s.name) @print_function(PrettyPrinter) def pretty(expr, **settings): """Returns a string containing the prettified form of expr. For information on keyword arguments see pretty_print function. """ pp = PrettyPrinter(settings) # XXX: this is an ugly hack, but at least it works use_unicode = pp._settings['use_unicode'] uflag = pretty_use_unicode(use_unicode) try: return pp.doprint(expr) finally: pretty_use_unicode(uflag) def pretty_print(expr, **kwargs): """Prints expr in pretty form. pprint is just a shortcut for this function. Parameters ========== expr : expression The expression to print. wrap_line : bool, optional (default=True) Line wrapping enabled/disabled. num_columns : int or None, optional (default=None) Number of columns before line breaking (default to None which reads the terminal width), useful when using SymPy without terminal. use_unicode : bool or None, optional (default=None) Use unicode characters, such as the Greek letter pi instead of the string pi. full_prec : bool or string, optional (default="auto") Use full precision. order : bool or string, optional (default=None) Set to 'none' for long expressions if slow; default is None. use_unicode_sqrt_char : bool, optional (default=True) Use compact single-character square root symbol (when unambiguous). root_notation : bool, optional (default=True) Set to 'False' for printing exponents of the form 1/n in fractional form. By default exponent is printed in root form. mat_symbol_style : string, optional (default="plain") Set to "bold" for printing MatrixSymbols using a bold mathematical symbol face. By default the standard face is used. imaginary_unit : string, optional (default="i") Letter to use for imaginary unit when use_unicode is True. Can be "i" (default) or "j". """ print(pretty(expr, **kwargs)) pprint = pretty_print def pager_print(expr, **settings): """Prints expr using the pager, in pretty form. This invokes a pager command using pydoc. Lines are not wrapped automatically. This routine is meant to be used with a pager that allows sideways scrolling, like ``less -S``. Parameters are the same as for ``pretty_print``. If you wish to wrap lines, pass ``num_columns=None`` to auto-detect the width of the terminal. """ from pydoc import pager from locale import getpreferredencoding if 'num_columns' not in settings: settings['num_columns'] = 500000 # disable line wrap pager(pretty(expr, **settings).encode(getpreferredencoding())) sympy-sympy-1.9/sympy/printing/pretty/pretty_symbology.py000066400000000000000000000471371412543434000243060ustar00rootroot00000000000000"""Symbolic primitives + unicode/ASCII abstraction for pretty.py""" import sys import warnings from string import ascii_lowercase, ascii_uppercase import unicodedata unicode_warnings = '' def U(name): """ Get a unicode character by name or, None if not found. This exists because older versions of python use older unicode databases. """ try: return unicodedata.lookup(name) except KeyError: global unicode_warnings unicode_warnings += 'No \'%s\' in unicodedata\n' % name return None from sympy.printing.conventions import split_super_sub from sympy.core.alphabets import greeks from sympy.utilities.exceptions import SymPyDeprecationWarning # prefix conventions when constructing tables # L - LATIN i # G - GREEK beta # D - DIGIT 0 # S - SYMBOL + __all__ = ['greek_unicode', 'sub', 'sup', 'xsym', 'vobj', 'hobj', 'pretty_symbol', 'annotated'] _use_unicode = False def pretty_use_unicode(flag=None): """Set whether pretty-printer should use unicode by default""" global _use_unicode global unicode_warnings if flag is None: return _use_unicode if flag and unicode_warnings: # print warnings (if any) on first unicode usage warnings.warn(unicode_warnings) unicode_warnings = '' use_unicode_prev = _use_unicode _use_unicode = flag return use_unicode_prev def pretty_try_use_unicode(): """See if unicode output is available and leverage it if possible""" encoding = getattr(sys.stdout, 'encoding', None) # this happens when e.g. stdout is redirected through a pipe, or is # e.g. a cStringIO.StringO if encoding is None: return # sys.stdout has no encoding symbols = [] # see if we can represent greek alphabet symbols += greek_unicode.values() # and atoms symbols += atoms_table.values() for s in symbols: if s is None: return # common symbols not present! try: s.encode(encoding) except UnicodeEncodeError: return # all the characters were present and encodable pretty_use_unicode(True) def xstr(*args): SymPyDeprecationWarning( feature="``xstr`` function", useinstead="``str``", deprecated_since_version="1.7").warn() return str(*args) # GREEK g = lambda l: U('GREEK SMALL LETTER %s' % l.upper()) G = lambda l: U('GREEK CAPITAL LETTER %s' % l.upper()) greek_letters = list(greeks) # make a copy # deal with Unicode's funny spelling of lambda greek_letters[greek_letters.index('lambda')] = 'lamda' # {} greek letter -> (g,G) greek_unicode = {L: g(L) for L in greek_letters} greek_unicode.update((L[0].upper() + L[1:], G(L)) for L in greek_letters) # aliases greek_unicode['lambda'] = greek_unicode['lamda'] greek_unicode['Lambda'] = greek_unicode['Lamda'] greek_unicode['varsigma'] = '\N{GREEK SMALL LETTER FINAL SIGMA}' # BOLD b = lambda l: U('MATHEMATICAL BOLD SMALL %s' % l.upper()) B = lambda l: U('MATHEMATICAL BOLD CAPITAL %s' % l.upper()) bold_unicode = {l: b(l) for l in ascii_lowercase} bold_unicode.update((L, B(L)) for L in ascii_uppercase) # GREEK BOLD gb = lambda l: U('MATHEMATICAL BOLD SMALL %s' % l.upper()) GB = lambda l: U('MATHEMATICAL BOLD CAPITAL %s' % l.upper()) greek_bold_letters = list(greeks) # make a copy, not strictly required here # deal with Unicode's funny spelling of lambda greek_bold_letters[greek_bold_letters.index('lambda')] = 'lamda' # {} greek letter -> (g,G) greek_bold_unicode = {L: g(L) for L in greek_bold_letters} greek_bold_unicode.update((L[0].upper() + L[1:], G(L)) for L in greek_bold_letters) greek_bold_unicode['lambda'] = greek_unicode['lamda'] greek_bold_unicode['Lambda'] = greek_unicode['Lamda'] greek_bold_unicode['varsigma'] = '\N{MATHEMATICAL BOLD SMALL FINAL SIGMA}' digit_2txt = { '0': 'ZERO', '1': 'ONE', '2': 'TWO', '3': 'THREE', '4': 'FOUR', '5': 'FIVE', '6': 'SIX', '7': 'SEVEN', '8': 'EIGHT', '9': 'NINE', } symb_2txt = { '+': 'PLUS SIGN', '-': 'MINUS', '=': 'EQUALS SIGN', '(': 'LEFT PARENTHESIS', ')': 'RIGHT PARENTHESIS', '[': 'LEFT SQUARE BRACKET', ']': 'RIGHT SQUARE BRACKET', '{': 'LEFT CURLY BRACKET', '}': 'RIGHT CURLY BRACKET', # non-std '{}': 'CURLY BRACKET', 'sum': 'SUMMATION', 'int': 'INTEGRAL', } # SUBSCRIPT & SUPERSCRIPT LSUB = lambda letter: U('LATIN SUBSCRIPT SMALL LETTER %s' % letter.upper()) GSUB = lambda letter: U('GREEK SUBSCRIPT SMALL LETTER %s' % letter.upper()) DSUB = lambda digit: U('SUBSCRIPT %s' % digit_2txt[digit]) SSUB = lambda symb: U('SUBSCRIPT %s' % symb_2txt[symb]) LSUP = lambda letter: U('SUPERSCRIPT LATIN SMALL LETTER %s' % letter.upper()) DSUP = lambda digit: U('SUPERSCRIPT %s' % digit_2txt[digit]) SSUP = lambda symb: U('SUPERSCRIPT %s' % symb_2txt[symb]) sub = {} # symb -> subscript symbol sup = {} # symb -> superscript symbol # latin subscripts for l in 'aeioruvxhklmnpst': sub[l] = LSUB(l) for l in 'in': sup[l] = LSUP(l) for gl in ['beta', 'gamma', 'rho', 'phi', 'chi']: sub[gl] = GSUB(gl) for d in [str(i) for i in range(10)]: sub[d] = DSUB(d) sup[d] = DSUP(d) for s in '+-=()': sub[s] = SSUB(s) sup[s] = SSUP(s) # Variable modifiers # TODO: Make brackets adjust to height of contents modifier_dict = { # Accents 'mathring': lambda s: center_accent(s, '\N{COMBINING RING ABOVE}'), 'ddddot': lambda s: center_accent(s, '\N{COMBINING FOUR DOTS ABOVE}'), 'dddot': lambda s: center_accent(s, '\N{COMBINING THREE DOTS ABOVE}'), 'ddot': lambda s: center_accent(s, '\N{COMBINING DIAERESIS}'), 'dot': lambda s: center_accent(s, '\N{COMBINING DOT ABOVE}'), 'check': lambda s: center_accent(s, '\N{COMBINING CARON}'), 'breve': lambda s: center_accent(s, '\N{COMBINING BREVE}'), 'acute': lambda s: center_accent(s, '\N{COMBINING ACUTE ACCENT}'), 'grave': lambda s: center_accent(s, '\N{COMBINING GRAVE ACCENT}'), 'tilde': lambda s: center_accent(s, '\N{COMBINING TILDE}'), 'hat': lambda s: center_accent(s, '\N{COMBINING CIRCUMFLEX ACCENT}'), 'bar': lambda s: center_accent(s, '\N{COMBINING OVERLINE}'), 'vec': lambda s: center_accent(s, '\N{COMBINING RIGHT ARROW ABOVE}'), 'prime': lambda s: s+'\N{PRIME}', 'prm': lambda s: s+'\N{PRIME}', # # Faces -- these are here for some compatibility with latex printing # 'bold': lambda s: s, # 'bm': lambda s: s, # 'cal': lambda s: s, # 'scr': lambda s: s, # 'frak': lambda s: s, # Brackets 'norm': lambda s: '\N{DOUBLE VERTICAL LINE}'+s+'\N{DOUBLE VERTICAL LINE}', 'avg': lambda s: '\N{MATHEMATICAL LEFT ANGLE BRACKET}'+s+'\N{MATHEMATICAL RIGHT ANGLE BRACKET}', 'abs': lambda s: '\N{VERTICAL LINE}'+s+'\N{VERTICAL LINE}', 'mag': lambda s: '\N{VERTICAL LINE}'+s+'\N{VERTICAL LINE}', } # VERTICAL OBJECTS HUP = lambda symb: U('%s UPPER HOOK' % symb_2txt[symb]) CUP = lambda symb: U('%s UPPER CORNER' % symb_2txt[symb]) MID = lambda symb: U('%s MIDDLE PIECE' % symb_2txt[symb]) EXT = lambda symb: U('%s EXTENSION' % symb_2txt[symb]) HLO = lambda symb: U('%s LOWER HOOK' % symb_2txt[symb]) CLO = lambda symb: U('%s LOWER CORNER' % symb_2txt[symb]) TOP = lambda symb: U('%s TOP' % symb_2txt[symb]) BOT = lambda symb: U('%s BOTTOM' % symb_2txt[symb]) # {} '(' -> (extension, start, end, middle) 1-character _xobj_unicode = { # vertical symbols # (( ext, top, bot, mid ), c1) '(': (( EXT('('), HUP('('), HLO('(') ), '('), ')': (( EXT(')'), HUP(')'), HLO(')') ), ')'), '[': (( EXT('['), CUP('['), CLO('[') ), '['), ']': (( EXT(']'), CUP(']'), CLO(']') ), ']'), '{': (( EXT('{}'), HUP('{'), HLO('{'), MID('{') ), '{'), '}': (( EXT('{}'), HUP('}'), HLO('}'), MID('}') ), '}'), '|': U('BOX DRAWINGS LIGHT VERTICAL'), '<': ((U('BOX DRAWINGS LIGHT VERTICAL'), U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'), U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT')), '<'), '>': ((U('BOX DRAWINGS LIGHT VERTICAL'), U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT')), '>'), 'lfloor': (( EXT('['), EXT('['), CLO('[') ), U('LEFT FLOOR')), 'rfloor': (( EXT(']'), EXT(']'), CLO(']') ), U('RIGHT FLOOR')), 'lceil': (( EXT('['), CUP('['), EXT('[') ), U('LEFT CEILING')), 'rceil': (( EXT(']'), CUP(']'), EXT(']') ), U('RIGHT CEILING')), 'int': (( EXT('int'), U('TOP HALF INTEGRAL'), U('BOTTOM HALF INTEGRAL') ), U('INTEGRAL')), 'sum': (( U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), '_', U('OVERLINE'), U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT')), U('N-ARY SUMMATION')), # horizontal objects #'-': '-', '-': U('BOX DRAWINGS LIGHT HORIZONTAL'), '_': U('LOW LINE'), # We used to use this, but LOW LINE looks better for roots, as it's a # little lower (i.e., it lines up with the / perfectly. But perhaps this # one would still be wanted for some cases? # '_': U('HORIZONTAL SCAN LINE-9'), # diagonal objects '\' & '/' ? '/': U('BOX DRAWINGS LIGHT DIAGONAL UPPER RIGHT TO LOWER LEFT'), '\\': U('BOX DRAWINGS LIGHT DIAGONAL UPPER LEFT TO LOWER RIGHT'), } _xobj_ascii = { # vertical symbols # (( ext, top, bot, mid ), c1) '(': (( '|', '/', '\\' ), '('), ')': (( '|', '\\', '/' ), ')'), # XXX this looks ugly # '[': (( '|', '-', '-' ), '['), # ']': (( '|', '-', '-' ), ']'), # XXX not so ugly :( '[': (( '[', '[', '[' ), '['), ']': (( ']', ']', ']' ), ']'), '{': (( '|', '/', '\\', '<' ), '{'), '}': (( '|', '\\', '/', '>' ), '}'), '|': '|', '<': (( '|', '/', '\\' ), '<'), '>': (( '|', '\\', '/' ), '>'), 'int': ( ' | ', ' /', '/ ' ), # horizontal objects '-': '-', '_': '_', # diagonal objects '\' & '/' ? '/': '/', '\\': '\\', } def xobj(symb, length): """Construct spatial object of given length. return: [] of equal-length strings """ if length <= 0: raise ValueError("Length should be greater than 0") # TODO robustify when no unicodedat available if _use_unicode: _xobj = _xobj_unicode else: _xobj = _xobj_ascii vinfo = _xobj[symb] c1 = top = bot = mid = None if not isinstance(vinfo, tuple): # 1 entry ext = vinfo else: if isinstance(vinfo[0], tuple): # (vlong), c1 vlong = vinfo[0] c1 = vinfo[1] else: # (vlong), c1 vlong = vinfo ext = vlong[0] try: top = vlong[1] bot = vlong[2] mid = vlong[3] except IndexError: pass if c1 is None: c1 = ext if top is None: top = ext if bot is None: bot = ext if mid is not None: if (length % 2) == 0: # even height, but we have to print it somehow anyway... # XXX is it ok? length += 1 else: mid = ext if length == 1: return c1 res = [] next = (length - 2)//2 nmid = (length - 2) - next*2 res += [top] res += [ext]*next res += [mid]*nmid res += [ext]*next res += [bot] return res def vobj(symb, height): """Construct vertical object of a given height see: xobj """ return '\n'.join( xobj(symb, height) ) def hobj(symb, width): """Construct horizontal object of a given width see: xobj """ return ''.join( xobj(symb, width) ) # RADICAL # n -> symbol root = { 2: U('SQUARE ROOT'), # U('RADICAL SYMBOL BOTTOM') 3: U('CUBE ROOT'), 4: U('FOURTH ROOT'), } # RATIONAL VF = lambda txt: U('VULGAR FRACTION %s' % txt) # (p,q) -> symbol frac = { (1, 2): VF('ONE HALF'), (1, 3): VF('ONE THIRD'), (2, 3): VF('TWO THIRDS'), (1, 4): VF('ONE QUARTER'), (3, 4): VF('THREE QUARTERS'), (1, 5): VF('ONE FIFTH'), (2, 5): VF('TWO FIFTHS'), (3, 5): VF('THREE FIFTHS'), (4, 5): VF('FOUR FIFTHS'), (1, 6): VF('ONE SIXTH'), (5, 6): VF('FIVE SIXTHS'), (1, 8): VF('ONE EIGHTH'), (3, 8): VF('THREE EIGHTHS'), (5, 8): VF('FIVE EIGHTHS'), (7, 8): VF('SEVEN EIGHTHS'), } # atom symbols _xsym = { '==': ('=', '='), '<': ('<', '<'), '>': ('>', '>'), '<=': ('<=', U('LESS-THAN OR EQUAL TO')), '>=': ('>=', U('GREATER-THAN OR EQUAL TO')), '!=': ('!=', U('NOT EQUAL TO')), ':=': (':=', ':='), '+=': ('+=', '+='), '-=': ('-=', '-='), '*=': ('*=', '*='), '/=': ('/=', '/='), '%=': ('%=', '%='), '*': ('*', U('DOT OPERATOR')), '-->': ('-->', U('EM DASH') + U('EM DASH') + U('BLACK RIGHT-POINTING TRIANGLE') if U('EM DASH') and U('BLACK RIGHT-POINTING TRIANGLE') else None), '==>': ('==>', U('BOX DRAWINGS DOUBLE HORIZONTAL') + U('BOX DRAWINGS DOUBLE HORIZONTAL') + U('BLACK RIGHT-POINTING TRIANGLE') if U('BOX DRAWINGS DOUBLE HORIZONTAL') and U('BOX DRAWINGS DOUBLE HORIZONTAL') and U('BLACK RIGHT-POINTING TRIANGLE') else None), '.': ('*', U('RING OPERATOR')), } def xsym(sym): """get symbology for a 'character'""" op = _xsym[sym] if _use_unicode: return op[1] else: return op[0] # SYMBOLS atoms_table = { # class how-to-display 'Exp1': U('SCRIPT SMALL E'), 'Pi': U('GREEK SMALL LETTER PI'), 'Infinity': U('INFINITY'), 'NegativeInfinity': U('INFINITY') and ('-' + U('INFINITY')), # XXX what to do here #'ImaginaryUnit': U('GREEK SMALL LETTER IOTA'), #'ImaginaryUnit': U('MATHEMATICAL ITALIC SMALL I'), 'ImaginaryUnit': U('DOUBLE-STRUCK ITALIC SMALL I'), 'EmptySet': U('EMPTY SET'), 'Naturals': U('DOUBLE-STRUCK CAPITAL N'), 'Naturals0': (U('DOUBLE-STRUCK CAPITAL N') and (U('DOUBLE-STRUCK CAPITAL N') + U('SUBSCRIPT ZERO'))), 'Integers': U('DOUBLE-STRUCK CAPITAL Z'), 'Rationals': U('DOUBLE-STRUCK CAPITAL Q'), 'Reals': U('DOUBLE-STRUCK CAPITAL R'), 'Complexes': U('DOUBLE-STRUCK CAPITAL C'), 'Union': U('UNION'), 'SymmetricDifference': U('INCREMENT'), 'Intersection': U('INTERSECTION'), 'Ring': U('RING OPERATOR'), 'Modifier Letter Low Ring':U('Modifier Letter Low Ring'), 'EmptySequence': 'EmptySequence', } def pretty_atom(atom_name, default=None, printer=None): """return pretty representation of an atom""" if _use_unicode: if printer is not None and atom_name == 'ImaginaryUnit' and printer._settings['imaginary_unit'] == 'j': return U('DOUBLE-STRUCK ITALIC SMALL J') else: return atoms_table[atom_name] else: if default is not None: return default raise KeyError('only unicode') # send it default printer def pretty_symbol(symb_name, bold_name=False): """return pretty representation of a symbol""" # let's split symb_name into symbol + index # UC: beta1 # UC: f_beta if not _use_unicode: return symb_name name, sups, subs = split_super_sub(symb_name) def translate(s, bold_name) : if bold_name: gG = greek_bold_unicode.get(s) else: gG = greek_unicode.get(s) if gG is not None: return gG for key in sorted(modifier_dict.keys(), key=lambda k:len(k), reverse=True) : if s.lower().endswith(key) and len(s)>len(key): return modifier_dict[key](translate(s[:-len(key)], bold_name)) if bold_name: return ''.join([bold_unicode[c] for c in s]) return s name = translate(name, bold_name) # Let's prettify sups/subs. If it fails at one of them, pretty sups/subs are # not used at all. def pretty_list(l, mapping): result = [] for s in l: pretty = mapping.get(s) if pretty is None: try: # match by separate characters pretty = ''.join([mapping[c] for c in s]) except (TypeError, KeyError): return None result.append(pretty) return result pretty_sups = pretty_list(sups, sup) if pretty_sups is not None: pretty_subs = pretty_list(subs, sub) else: pretty_subs = None # glue the results into one string if pretty_subs is None: # nice formatting of sups/subs did not work if subs: name += '_'+'_'.join([translate(s, bold_name) for s in subs]) if sups: name += '__'+'__'.join([translate(s, bold_name) for s in sups]) return name else: sups_result = ' '.join(pretty_sups) subs_result = ' '.join(pretty_subs) return ''.join([name, sups_result, subs_result]) def annotated(letter): """ Return a stylised drawing of the letter ``letter``, together with information on how to put annotations (super- and subscripts to the left and to the right) on it. See pretty.py functions _print_meijerg, _print_hyper on how to use this information. """ ucode_pics = { 'F': (2, 0, 2, 0, '\N{BOX DRAWINGS LIGHT DOWN AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\n' '\N{BOX DRAWINGS LIGHT VERTICAL AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\n' '\N{BOX DRAWINGS LIGHT UP}'), 'G': (3, 0, 3, 1, '\N{BOX DRAWINGS LIGHT ARC DOWN AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{BOX DRAWINGS LIGHT ARC DOWN AND LEFT}\n' '\N{BOX DRAWINGS LIGHT VERTICAL}\N{BOX DRAWINGS LIGHT RIGHT}\N{BOX DRAWINGS LIGHT DOWN AND LEFT}\n' '\N{BOX DRAWINGS LIGHT ARC UP AND RIGHT}\N{BOX DRAWINGS LIGHT HORIZONTAL}\N{BOX DRAWINGS LIGHT ARC UP AND LEFT}') } ascii_pics = { 'F': (3, 0, 3, 0, ' _\n|_\n|\n'), 'G': (3, 0, 3, 1, ' __\n/__\n\\_|') } if _use_unicode: return ucode_pics[letter] else: return ascii_pics[letter] _remove_combining = dict.fromkeys(list(range(ord('\N{COMBINING GRAVE ACCENT}'), ord('\N{COMBINING LATIN SMALL LETTER X}'))) + list(range(ord('\N{COMBINING LEFT HARPOON ABOVE}'), ord('\N{COMBINING ASTERISK ABOVE}')))) def is_combining(sym): """Check whether symbol is a unicode modifier. """ return ord(sym) in _remove_combining def center_accent(string, accent): """ Returns a string with accent inserted on the middle character. Useful to put combining accents on symbol names, including multi-character names. Parameters ========== string : string The string to place the accent in. accent : string The combining accent to insert References ========== .. [1] https://en.wikipedia.org/wiki/Combining_character .. [2] https://en.wikipedia.org/wiki/Combining_Diacritical_Marks """ # Accent is placed on the previous character, although it may not always look # like that depending on console midpoint = len(string) // 2 + 1 firstpart = string[:midpoint] secondpart = string[midpoint:] return firstpart + accent + secondpart def line_width(line): """Unicode combining symbols (modifiers) are not ever displayed as separate symbols and thus shouldn't be counted """ return len(line.translate(_remove_combining)) sympy-sympy-1.9/sympy/printing/pretty/stringpict.py000066400000000000000000000444611412543434000230360ustar00rootroot00000000000000"""Prettyprinter by Jurjen Bos. (I hate spammers: mail me at pietjepuk314 at the reverse of ku.oc.oohay). All objects have a method that create a "stringPict", that can be used in the str method for pretty printing. Updates by Jason Gedge (email at cs mun ca) - terminal_string() method - minor fixes and changes (mostly to prettyForm) TODO: - Allow left/center/right alignment options for above/below and top/center/bottom alignment options for left/right """ from .pretty_symbology import hobj, vobj, xsym, xobj, pretty_use_unicode, line_width from sympy.utilities.exceptions import SymPyDeprecationWarning class stringPict: """An ASCII picture. The pictures are represented as a list of equal length strings. """ #special value for stringPict.below LINE = 'line' def __init__(self, s, baseline=0): """Initialize from string. Multiline strings are centered. """ self.s = s #picture is a string that just can be printed self.picture = stringPict.equalLengths(s.splitlines()) #baseline is the line number of the "base line" self.baseline = baseline self.binding = None @staticmethod def equalLengths(lines): # empty lines if not lines: return [''] width = max(line_width(line) for line in lines) return [line.center(width) for line in lines] def height(self): """The height of the picture in characters.""" return len(self.picture) def width(self): """The width of the picture in characters.""" return line_width(self.picture[0]) @staticmethod def next(*args): """Put a string of stringPicts next to each other. Returns string, baseline arguments for stringPict. """ #convert everything to stringPicts objects = [] for arg in args: if isinstance(arg, str): arg = stringPict(arg) objects.append(arg) #make a list of pictures, with equal height and baseline newBaseline = max(obj.baseline for obj in objects) newHeightBelowBaseline = max( obj.height() - obj.baseline for obj in objects) newHeight = newBaseline + newHeightBelowBaseline pictures = [] for obj in objects: oneEmptyLine = [' '*obj.width()] basePadding = newBaseline - obj.baseline totalPadding = newHeight - obj.height() pictures.append( oneEmptyLine * basePadding + obj.picture + oneEmptyLine * (totalPadding - basePadding)) result = [''.join(lines) for lines in zip(*pictures)] return '\n'.join(result), newBaseline def right(self, *args): r"""Put pictures next to this one. Returns string, baseline arguments for stringPict. (Multiline) strings are allowed, and are given a baseline of 0. Examples ======== >>> from sympy.printing.pretty.stringpict import stringPict >>> print(stringPict("10").right(" + ",stringPict("1\r-\r2",1))[0]) 1 10 + - 2 """ return stringPict.next(self, *args) def left(self, *args): """Put pictures (left to right) at left. Returns string, baseline arguments for stringPict. """ return stringPict.next(*(args + (self,))) @staticmethod def stack(*args): """Put pictures on top of each other, from top to bottom. Returns string, baseline arguments for stringPict. The baseline is the baseline of the second picture. Everything is centered. Baseline is the baseline of the second picture. Strings are allowed. The special value stringPict.LINE is a row of '-' extended to the width. """ #convert everything to stringPicts; keep LINE objects = [] for arg in args: if arg is not stringPict.LINE and isinstance(arg, str): arg = stringPict(arg) objects.append(arg) #compute new width newWidth = max( obj.width() for obj in objects if obj is not stringPict.LINE) lineObj = stringPict(hobj('-', newWidth)) #replace LINE with proper lines for i, obj in enumerate(objects): if obj is stringPict.LINE: objects[i] = lineObj #stack the pictures, and center the result newPicture = [] for obj in objects: newPicture.extend(obj.picture) newPicture = [line.center(newWidth) for line in newPicture] newBaseline = objects[0].height() + objects[1].baseline return '\n'.join(newPicture), newBaseline def below(self, *args): """Put pictures under this picture. Returns string, baseline arguments for stringPict. Baseline is baseline of top picture Examples ======== >>> from sympy.printing.pretty.stringpict import stringPict >>> print(stringPict("x+3").below( ... stringPict.LINE, '3')[0]) #doctest: +NORMALIZE_WHITESPACE x+3 --- 3 """ s, baseline = stringPict.stack(self, *args) return s, self.baseline def above(self, *args): """Put pictures above this picture. Returns string, baseline arguments for stringPict. Baseline is baseline of bottom picture. """ string, baseline = stringPict.stack(*(args + (self,))) baseline = len(string.splitlines()) - self.height() + self.baseline return string, baseline def parens(self, left='(', right=')', ifascii_nougly=False): """Put parentheses around self. Returns string, baseline arguments for stringPict. left or right can be None or empty string which means 'no paren from that side' """ h = self.height() b = self.baseline # XXX this is a hack -- ascii parens are ugly! if ifascii_nougly and not pretty_use_unicode(): h = 1 b = 0 res = self if left: lparen = stringPict(vobj(left, h), baseline=b) res = stringPict(*lparen.right(self)) if right: rparen = stringPict(vobj(right, h), baseline=b) res = stringPict(*res.right(rparen)) return ('\n'.join(res.picture), res.baseline) def leftslash(self): """Precede object by a slash of the proper size. """ # XXX not used anywhere ? height = max( self.baseline, self.height() - 1 - self.baseline)*2 + 1 slash = '\n'.join( ' '*(height - i - 1) + xobj('/', 1) + ' '*i for i in range(height) ) return self.left(stringPict(slash, height//2)) def root(self, n=None): """Produce a nice root symbol. Produces ugly results for big n inserts. """ # XXX not used anywhere # XXX duplicate of root drawing in pretty.py #put line over expression result = self.above('_'*self.width()) #construct right half of root symbol height = self.height() slash = '\n'.join( ' ' * (height - i - 1) + '/' + ' ' * i for i in range(height) ) slash = stringPict(slash, height - 1) #left half of root symbol if height > 2: downline = stringPict('\\ \n \\', 1) else: downline = stringPict('\\') #put n on top, as low as possible if n is not None and n.width() > downline.width(): downline = downline.left(' '*(n.width() - downline.width())) downline = downline.above(n) #build root symbol root = downline.right(slash) #glue it on at the proper height #normally, the root symbel is as high as self #which is one less than result #this moves the root symbol one down #if the root became higher, the baseline has to grow too root.baseline = result.baseline - result.height() + root.height() return result.left(root) def render(self, * args, **kwargs): """Return the string form of self. Unless the argument line_break is set to False, it will break the expression in a form that can be printed on the terminal without being broken up. """ if kwargs["wrap_line"] is False: return "\n".join(self.picture) if kwargs["num_columns"] is not None: # Read the argument num_columns if it is not None ncols = kwargs["num_columns"] else: # Attempt to get a terminal width ncols = self.terminal_width() ncols -= 2 if ncols <= 0: ncols = 78 # If smaller than the terminal width, no need to correct if self.width() <= ncols: return type(self.picture[0])(self) # for one-line pictures we don't need v-spacers. on the other hand, for # multiline-pictures, we need v-spacers between blocks, compare: # # 2 2 3 | a*c*e + a*c*f + a*d | a*c*e + a*c*f + a*d | 3.14159265358979323 # 6*x *y + 4*x*y + | | *e + a*d*f + b*c*e | 84626433832795 # | *e + a*d*f + b*c*e | + b*c*f + b*d*e + b | # 3 4 4 | | *d*f | # 4*y*x + x + y | + b*c*f + b*d*e + b | | # | | | # | *d*f i = 0 svals = [] do_vspacers = (self.height() > 1) while i < self.width(): svals.extend([ sval[i:i + ncols] for sval in self.picture ]) if do_vspacers: svals.append("") # a vertical spacer i += ncols if svals[-1] == '': del svals[-1] # Get rid of the last spacer return "\n".join(svals) def terminal_width(self): """Return the terminal width if possible, otherwise return 0. """ ncols = 0 try: import curses import io try: curses.setupterm() ncols = curses.tigetnum('cols') except AttributeError: # windows curses doesn't implement setupterm or tigetnum # code below from # http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/440694 from ctypes import windll, create_string_buffer # stdin handle is -10 # stdout handle is -11 # stderr handle is -12 h = windll.kernel32.GetStdHandle(-12) csbi = create_string_buffer(22) res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) if res: import struct (bufx, bufy, curx, cury, wattr, left, top, right, bottom, maxx, maxy) = struct.unpack("hhhhHhhhhhh", csbi.raw) ncols = right - left + 1 except curses.error: pass except io.UnsupportedOperation: pass except (ImportError, TypeError): pass return ncols def __eq__(self, o): if isinstance(o, str): return '\n'.join(self.picture) == o elif isinstance(o, stringPict): return o.picture == self.picture return False def __hash__(self): return super().__hash__() def __str__(self): return '\n'.join(self.picture) def __repr__(self): return "stringPict(%r,%d)" % ('\n'.join(self.picture), self.baseline) def __getitem__(self, index): return self.picture[index] def __len__(self): return len(self.s) class prettyForm(stringPict): """ Extension of the stringPict class that knows about basic math applications, optimizing double minus signs. "Binding" is interpreted as follows:: ATOM this is an atom: never needs to be parenthesized FUNC this is a function application: parenthesize if added (?) DIV this is a division: make wider division if divided POW this is a power: only parenthesize if exponent MUL this is a multiplication: parenthesize if powered ADD this is an addition: parenthesize if multiplied or powered NEG this is a negative number: optimize if added, parenthesize if multiplied or powered OPEN this is an open object: parenthesize if added, multiplied, or powered (example: Piecewise) """ ATOM, FUNC, DIV, POW, MUL, ADD, NEG, OPEN = range(8) def __init__(self, s, baseline=0, binding=0, unicode=None): """Initialize from stringPict and binding power.""" stringPict.__init__(self, s, baseline) self.binding = binding if unicode is not None: SymPyDeprecationWarning( feature="``unicode`` argument to ``prettyForm``", useinstead="the ``s`` argument", deprecated_since_version="1.7").warn() self._unicode = unicode or s @property def unicode(self): SymPyDeprecationWarning( feature="``prettyForm.unicode`` attribute", useinstead="``stringPrict.s`` attribute", deprecated_since_version="1.7").warn() return self._unicode # Note: code to handle subtraction is in _print_Add def __add__(self, *others): """Make a pretty addition. Addition of negative numbers is simplified. """ arg = self if arg.binding > prettyForm.NEG: arg = stringPict(*arg.parens()) result = [arg] for arg in others: #add parentheses for weak binders if arg.binding > prettyForm.NEG: arg = stringPict(*arg.parens()) #use existing minus sign if available if arg.binding != prettyForm.NEG: result.append(' + ') result.append(arg) return prettyForm(binding=prettyForm.ADD, *stringPict.next(*result)) def __truediv__(self, den, slashed=False): """Make a pretty division; stacked or slashed. """ if slashed: raise NotImplementedError("Can't do slashed fraction yet") num = self if num.binding == prettyForm.DIV: num = stringPict(*num.parens()) if den.binding == prettyForm.DIV: den = stringPict(*den.parens()) if num.binding==prettyForm.NEG: num = num.right(" ")[0] return prettyForm(binding=prettyForm.DIV, *stringPict.stack( num, stringPict.LINE, den)) def __mul__(self, *others): """Make a pretty multiplication. Parentheses are needed around +, - and neg. """ quantity = { 'degree': "\N{DEGREE SIGN}" } if len(others) == 0: return self # We aren't actually multiplying... So nothing to do here. args = self if args.binding > prettyForm.MUL: arg = stringPict(*args.parens()) result = [args] for arg in others: if arg.picture[0] not in quantity.values(): result.append(xsym('*')) #add parentheses for weak binders if arg.binding > prettyForm.MUL: arg = stringPict(*arg.parens()) result.append(arg) len_res = len(result) for i in range(len_res): if i < len_res - 1 and result[i] == '-1' and result[i + 1] == xsym('*'): # substitute -1 by -, like in -1*x -> -x result.pop(i) result.pop(i) result.insert(i, '-') if result[0][0] == '-': # if there is a - sign in front of all # This test was failing to catch a prettyForm.__mul__(prettyForm("-1", 0, 6)) being negative bin = prettyForm.NEG if result[0] == '-': right = result[1] if right.picture[right.baseline][0] == '-': result[0] = '- ' else: bin = prettyForm.MUL return prettyForm(binding=bin, *stringPict.next(*result)) def __repr__(self): return "prettyForm(%r,%d,%d)" % ( '\n'.join(self.picture), self.baseline, self.binding) def __pow__(self, b): """Make a pretty power. """ a = self use_inline_func_form = False if b.binding == prettyForm.POW: b = stringPict(*b.parens()) if a.binding > prettyForm.FUNC: a = stringPict(*a.parens()) elif a.binding == prettyForm.FUNC: # heuristic for when to use inline power if b.height() > 1: a = stringPict(*a.parens()) else: use_inline_func_form = True if use_inline_func_form: # 2 # sin + + (x) b.baseline = a.prettyFunc.baseline + b.height() func = stringPict(*a.prettyFunc.right(b)) return prettyForm(*func.right(a.prettyArgs)) else: # 2 <-- top # (x+y) <-- bot top = stringPict(*b.left(' '*a.width())) bot = stringPict(*a.right(' '*b.width())) return prettyForm(binding=prettyForm.POW, *bot.above(top)) simpleFunctions = ["sin", "cos", "tan"] @staticmethod def apply(function, *args): """Functions of one or more variables. """ if function in prettyForm.simpleFunctions: #simple function: use only space if possible assert len( args) == 1, "Simple function %s must have 1 argument" % function arg = args[0].__pretty__() if arg.binding <= prettyForm.DIV: #optimization: no parentheses necessary return prettyForm(binding=prettyForm.FUNC, *arg.left(function + ' ')) argumentList = [] for arg in args: argumentList.append(',') argumentList.append(arg.__pretty__()) argumentList = stringPict(*stringPict.next(*argumentList[1:])) argumentList = stringPict(*argumentList.parens()) return prettyForm(binding=prettyForm.ATOM, *argumentList.left(function)) sympy-sympy-1.9/sympy/printing/pretty/tests/000077500000000000000000000000001412543434000214275ustar00rootroot00000000000000sympy-sympy-1.9/sympy/printing/pretty/tests/__init__.py000066400000000000000000000000001412543434000235260ustar00rootroot00000000000000sympy-sympy-1.9/sympy/printing/pretty/tests/test_pretty.py000066400000000000000000005277771412543434000244200ustar00rootroot00000000000000# -*- coding: utf-8 -*- from sympy import ( Add, And, Basic, Derivative, Dict, Eq, Equivalent, FF, FiniteSet, Function, Ge, Gt, I, Implies, Integral, SingularityFunction, Lambda, Le, Limit, Lt, Matrix, Mul, Nand, Ne, Nor, Not, O, Or, Pow, Product, QQ, RR, Rational, Ray, rootof, RootSum, S, Segment, Subs, Sum, Symbol, Tuple, Trace, Xor, ZZ, conjugate, groebner, oo, pi, symbols, ilex, grlex, Range, Contains, SeqPer, SeqFormula, SeqAdd, SeqMul, fourier_series, fps, ITE, Complement, Interval, Intersection, Union, EulerGamma, GoldenRatio, LambertW, airyai, airybi, airyaiprime, airybiprime, fresnelc, fresnels, Heaviside, dirichlet_eta, diag, MatrixSlice) from sympy.codegen.ast import (Assignment, AddAugmentedAssignment, SubAugmentedAssignment, MulAugmentedAssignment, DivAugmentedAssignment, ModAugmentedAssignment) from sympy.core.expr import UnevaluatedExpr from sympy.core.trace import Tr from sympy.functions import (Abs, Chi, Ci, Ei, KroneckerDelta, Piecewise, Shi, Si, atan2, beta, binomial, catalan, ceiling, cos, euler, exp, expint, factorial, factorial2, floor, gamma, hyper, log, meijerg, sin, sqrt, subfactorial, tan, uppergamma, lerchphi, elliptic_k, elliptic_f, elliptic_e, elliptic_pi, DiracDelta, bell, bernoulli, fibonacci, tribonacci, lucas, stieltjes, mathieuc, mathieus, mathieusprime, mathieucprime) from sympy.matrices import Adjoint, Inverse, MatrixSymbol, Transpose, KroneckerProduct from sympy.matrices.expressions import hadamard_power from sympy.physics import mechanics from sympy.physics.control.lti import (TransferFunction, Feedback, TransferFunctionMatrix, Series, Parallel, MIMOSeries, MIMOParallel, MIMOFeedback) from sympy.physics.units import joule, degree from sympy.printing.pretty import pprint, pretty as xpretty from sympy.printing.pretty.pretty_symbology import center_accent, is_combining from sympy import ConditionSet from sympy.sets import ImageSet, ProductSet from sympy.sets.setexpr import SetExpr from sympy.tensor.array import (ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableDenseNDimArray, MutableSparseNDimArray, tensorproduct) from sympy.tensor.functions import TensorProduct from sympy.tensor.tensor import (TensorIndexType, tensor_indices, TensorHead, TensorElement, tensor_heads) from sympy.testing.pytest import raises, _both_exp_pow from sympy.vector import CoordSys3D, Gradient, Curl, Divergence, Dot, Cross, Laplacian import sympy as sym class lowergamma(sym.lowergamma): pass # testing notation inheritance by a subclass with same name a, b, c, d, x, y, z, k, n, s, p = symbols('a,b,c,d,x,y,z,k,n,s,p') f = Function("f") th = Symbol('theta') ph = Symbol('phi') """ Expressions whose pretty-printing is tested here: (A '#' to the right of an expression indicates that its various acceptable orderings are accounted for by the tests.) BASIC EXPRESSIONS: oo (x**2) 1/x y*x**-2 x**Rational(-5,2) (-2)**x Pow(3, 1, evaluate=False) (x**2 + x + 1) # 1-x # 1-2*x # x/y -x/y (x+2)/y # (1+x)*y #3 -5*x/(x+10) # correct placement of negative sign 1 - Rational(3,2)*(x+1) -(-x + 5)*(-x - 2*sqrt(2) + 5) - (-y + 5)*(-y + 5) # issue 5524 ORDERING: x**2 + x + 1 1 - x 1 - 2*x 2*x**4 + y**2 - x**2 + y**3 RELATIONAL: Eq(x, y) Lt(x, y) Gt(x, y) Le(x, y) Ge(x, y) Ne(x/(y+1), y**2) # RATIONAL NUMBERS: y*x**-2 y**Rational(3,2) * x**Rational(-5,2) sin(x)**3/tan(x)**2 FUNCTIONS (ABS, CONJ, EXP, FUNCTION BRACES, FACTORIAL, FLOOR, CEILING): (2*x + exp(x)) # Abs(x) Abs(x/(x**2+1)) # Abs(1 / (y - Abs(x))) factorial(n) factorial(2*n) subfactorial(n) subfactorial(2*n) factorial(factorial(factorial(n))) factorial(n+1) # conjugate(x) conjugate(f(x+1)) # f(x) f(x, y) f(x/(y+1), y) # f(x**x**x**x**x**x) sin(x)**2 conjugate(a+b*I) conjugate(exp(a+b*I)) conjugate( f(1 + conjugate(f(x))) ) # f(x/(y+1), y) # denom of first arg floor(1 / (y - floor(x))) ceiling(1 / (y - ceiling(x))) SQRT: sqrt(2) 2**Rational(1,3) 2**Rational(1,1000) sqrt(x**2 + 1) (1 + sqrt(5))**Rational(1,3) 2**(1/x) sqrt(2+pi) (2+(1+x**2)/(2+x))**Rational(1,4)+(1+x**Rational(1,1000))/sqrt(3+x**2) DERIVATIVES: Derivative(log(x), x, evaluate=False) Derivative(log(x), x, evaluate=False) + x # Derivative(log(x) + x**2, x, y, evaluate=False) Derivative(2*x*y, y, x, evaluate=False) + x**2 # beta(alpha).diff(alpha) INTEGRALS: Integral(log(x), x) Integral(x**2, x) Integral((sin(x))**2 / (tan(x))**2) Integral(x**(2**x), x) Integral(x**2, (x,1,2)) Integral(x**2, (x,Rational(1,2),10)) Integral(x**2*y**2, x,y) Integral(x**2, (x, None, 1)) Integral(x**2, (x, 1, None)) Integral(sin(th)/cos(ph), (th,0,pi), (ph, 0, 2*pi)) MATRICES: Matrix([[x**2+1, 1], [y, x+y]]) # Matrix([[x/y, y, th], [0, exp(I*k*ph), 1]]) PIECEWISE: Piecewise((x,x<1),(x**2,True)) ITE: ITE(x, y, z) SEQUENCES (TUPLES, LISTS, DICTIONARIES): () [] {} (1/x,) [x**2, 1/x, x, y, sin(th)**2/cos(ph)**2] (x**2, 1/x, x, y, sin(th)**2/cos(ph)**2) {x: sin(x)} {1/x: 1/y, x: sin(x)**2} # [x**2] (x**2,) {x**2: 1} LIMITS: Limit(x, x, oo) Limit(x**2, x, 0) Limit(1/x, x, 0) Limit(sin(x)/x, x, 0) UNITS: joule => kg*m**2/s SUBS: Subs(f(x), x, ph**2) Subs(f(x).diff(x), x, 0) Subs(f(x).diff(x)/y, (x, y), (0, Rational(1, 2))) ORDER: O(1) O(1/x) O(x**2 + y**2) """ def pretty(expr, order=None): """ASCII pretty-printing""" return xpretty(expr, order=order, use_unicode=False, wrap_line=False) def upretty(expr, order=None): """Unicode pretty-printing""" return xpretty(expr, order=order, use_unicode=True, wrap_line=False) def test_pretty_ascii_str(): assert pretty( 'xxx' ) == 'xxx' assert pretty( "xxx" ) == 'xxx' assert pretty( 'xxx\'xxx' ) == 'xxx\'xxx' assert pretty( 'xxx"xxx' ) == 'xxx\"xxx' assert pretty( 'xxx\"xxx' ) == 'xxx\"xxx' assert pretty( "xxx'xxx" ) == 'xxx\'xxx' assert pretty( "xxx\'xxx" ) == 'xxx\'xxx' assert pretty( "xxx\"xxx" ) == 'xxx\"xxx' assert pretty( "xxx\"xxx\'xxx" ) == 'xxx"xxx\'xxx' assert pretty( "xxx\nxxx" ) == 'xxx\nxxx' def test_pretty_unicode_str(): assert pretty( 'xxx' ) == 'xxx' assert pretty( 'xxx' ) == 'xxx' assert pretty( 'xxx\'xxx' ) == 'xxx\'xxx' assert pretty( 'xxx"xxx' ) == 'xxx\"xxx' assert pretty( 'xxx\"xxx' ) == 'xxx\"xxx' assert pretty( "xxx'xxx" ) == 'xxx\'xxx' assert pretty( "xxx\'xxx" ) == 'xxx\'xxx' assert pretty( "xxx\"xxx" ) == 'xxx\"xxx' assert pretty( "xxx\"xxx\'xxx" ) == 'xxx"xxx\'xxx' assert pretty( "xxx\nxxx" ) == 'xxx\nxxx' def test_upretty_greek(): assert upretty( oo ) == '∞' assert upretty( Symbol('alpha^+_1') ) == 'α⁺₁' assert upretty( Symbol('beta') ) == 'β' assert upretty(Symbol('lambda')) == 'λ' def test_upretty_multiindex(): assert upretty( Symbol('beta12') ) == 'β₁₂' assert upretty( Symbol('Y00') ) == 'Y₀₀' assert upretty( Symbol('Y_00') ) == 'Y₀₀' assert upretty( Symbol('F^+-') ) == 'F⁺⁻' def test_upretty_sub_super(): assert upretty( Symbol('beta_1_2') ) == 'β₁ ₂' assert upretty( Symbol('beta^1^2') ) == 'β¹ ²' assert upretty( Symbol('beta_1^2') ) == 'β²₁' assert upretty( Symbol('beta_10_20') ) == 'β₁₀ ₂₀' assert upretty( Symbol('beta_ax_gamma^i') ) == 'βⁱₐₓ ᵧ' assert upretty( Symbol("F^1^2_3_4") ) == 'F¹ ²₃ ₄' assert upretty( Symbol("F_1_2^3^4") ) == 'F³ ⁴₁ ₂' assert upretty( Symbol("F_1_2_3_4") ) == 'F₁ ₂ ₃ ₄' assert upretty( Symbol("F^1^2^3^4") ) == 'F¹ ² ³ ⁴' def test_upretty_subs_missing_in_24(): assert upretty( Symbol('F_beta') ) == 'Fᵦ' assert upretty( Symbol('F_gamma') ) == 'Fᵧ' assert upretty( Symbol('F_rho') ) == 'Fᵨ' assert upretty( Symbol('F_phi') ) == 'Fᵩ' assert upretty( Symbol('F_chi') ) == 'Fᵪ' assert upretty( Symbol('F_a') ) == 'Fₐ' assert upretty( Symbol('F_e') ) == 'Fₑ' assert upretty( Symbol('F_i') ) == 'Fᵢ' assert upretty( Symbol('F_o') ) == 'Fₒ' assert upretty( Symbol('F_u') ) == 'Fᵤ' assert upretty( Symbol('F_r') ) == 'Fᵣ' assert upretty( Symbol('F_v') ) == 'Fᵥ' assert upretty( Symbol('F_x') ) == 'Fₓ' def test_missing_in_2X_issue_9047(): assert upretty( Symbol('F_h') ) == 'Fₕ' assert upretty( Symbol('F_k') ) == 'Fₖ' assert upretty( Symbol('F_l') ) == 'Fₗ' assert upretty( Symbol('F_m') ) == 'Fₘ' assert upretty( Symbol('F_n') ) == 'Fₙ' assert upretty( Symbol('F_p') ) == 'Fₚ' assert upretty( Symbol('F_s') ) == 'Fₛ' assert upretty( Symbol('F_t') ) == 'Fₜ' def test_upretty_modifiers(): # Accents assert upretty( Symbol('Fmathring') ) == 'F̊' assert upretty( Symbol('Fddddot') ) == 'F⃜' assert upretty( Symbol('Fdddot') ) == 'F⃛' assert upretty( Symbol('Fddot') ) == 'F̈' assert upretty( Symbol('Fdot') ) == 'Ḟ' assert upretty( Symbol('Fcheck') ) == 'F̌' assert upretty( Symbol('Fbreve') ) == 'F̆' assert upretty( Symbol('Facute') ) == 'F́' assert upretty( Symbol('Fgrave') ) == 'F̀' assert upretty( Symbol('Ftilde') ) == 'F̃' assert upretty( Symbol('Fhat') ) == 'F̂' assert upretty( Symbol('Fbar') ) == 'F̅' assert upretty( Symbol('Fvec') ) == 'F⃗' assert upretty( Symbol('Fprime') ) == 'F′' assert upretty( Symbol('Fprm') ) == 'F′' # No faces are actually implemented, but test to make sure the modifiers are stripped assert upretty( Symbol('Fbold') ) == 'Fbold' assert upretty( Symbol('Fbm') ) == 'Fbm' assert upretty( Symbol('Fcal') ) == 'Fcal' assert upretty( Symbol('Fscr') ) == 'Fscr' assert upretty( Symbol('Ffrak') ) == 'Ffrak' # Brackets assert upretty( Symbol('Fnorm') ) == '‖F‖' assert upretty( Symbol('Favg') ) == '⟨F⟩' assert upretty( Symbol('Fabs') ) == '|F|' assert upretty( Symbol('Fmag') ) == '|F|' # Combinations assert upretty( Symbol('xvecdot') ) == 'x⃗̇' assert upretty( Symbol('xDotVec') ) == 'ẋ⃗' assert upretty( Symbol('xHATNorm') ) == '‖x̂‖' assert upretty( Symbol('xMathring_yCheckPRM__zbreveAbs') ) == 'x̊_y̌′__|z̆|' assert upretty( Symbol('alphadothat_nVECDOT__tTildePrime') ) == 'α̇̂_n⃗̇__t̃′' assert upretty( Symbol('x_dot') ) == 'x_dot' assert upretty( Symbol('x__dot') ) == 'x__dot' def test_pretty_Cycle(): from sympy.combinatorics.permutations import Cycle assert pretty(Cycle(1, 2)) == '(1 2)' assert pretty(Cycle(2)) == '(2)' assert pretty(Cycle(1, 3)(4, 5)) == '(1 3)(4 5)' assert pretty(Cycle()) == '()' def test_pretty_Permutation(): from sympy.combinatorics.permutations import Permutation p1 = Permutation(1, 2)(3, 4) assert xpretty(p1, perm_cyclic=True, use_unicode=True) == "(1 2)(3 4)" assert xpretty(p1, perm_cyclic=True, use_unicode=False) == "(1 2)(3 4)" assert xpretty(p1, perm_cyclic=False, use_unicode=True) == \ '⎛0 1 2 3 4⎞\n'\ '⎝0 2 1 4 3⎠' assert xpretty(p1, perm_cyclic=False, use_unicode=False) == \ "/0 1 2 3 4\\\n"\ "\\0 2 1 4 3/" def test_pretty_basic(): assert pretty( -Rational(1)/2 ) == '-1/2' assert pretty( -Rational(13)/22 ) == \ """\ -13 \n\ ----\n\ 22 \ """ expr = oo ascii_str = \ """\ oo\ """ ucode_str = \ """\ ∞\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2) ascii_str = \ """\ 2\n\ x \ """ ucode_str = \ """\ 2\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 1/x ascii_str = \ """\ 1\n\ -\n\ x\ """ ucode_str = \ """\ 1\n\ ─\n\ x\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str # not the same as 1/x expr = x**-1.0 ascii_str = \ """\ -1.0\n\ x \ """ ucode_str = \ """\ -1.0\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str # see issue #2860 expr = Pow(S(2), -1.0, evaluate=False) ascii_str = \ """\ -1.0\n\ 2 \ """ ucode_str = \ """\ -1.0\n\ 2 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = y*x**-2 ascii_str = \ """\ y \n\ --\n\ 2\n\ x \ """ ucode_str = \ """\ y \n\ ──\n\ 2\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str #see issue #14033 expr = x**Rational(1, 3) ascii_str = \ """\ 1/3\n\ x \ """ ucode_str = \ """\ 1/3\n\ x \ """ assert xpretty(expr, use_unicode=False, wrap_line=False,\ root_notation = False) == ascii_str assert xpretty(expr, use_unicode=True, wrap_line=False,\ root_notation = False) == ucode_str expr = x**Rational(-5, 2) ascii_str = \ """\ 1 \n\ ----\n\ 5/2\n\ x \ """ ucode_str = \ """\ 1 \n\ ────\n\ 5/2\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (-2)**x ascii_str = \ """\ x\n\ (-2) \ """ ucode_str = \ """\ x\n\ (-2) \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str # See issue 4923 expr = Pow(3, 1, evaluate=False) ascii_str = \ """\ 1\n\ 3 \ """ ucode_str = \ """\ 1\n\ 3 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2 + x + 1) ascii_str_1 = \ """\ 2\n\ 1 + x + x \ """ ascii_str_2 = \ """\ 2 \n\ x + x + 1\ """ ascii_str_3 = \ """\ 2 \n\ x + 1 + x\ """ ucode_str_1 = \ """\ 2\n\ 1 + x + x \ """ ucode_str_2 = \ """\ 2 \n\ x + x + 1\ """ ucode_str_3 = \ """\ 2 \n\ x + 1 + x\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2, ascii_str_3] assert upretty(expr) in [ucode_str_1, ucode_str_2, ucode_str_3] expr = 1 - x ascii_str_1 = \ """\ 1 - x\ """ ascii_str_2 = \ """\ -x + 1\ """ ucode_str_1 = \ """\ 1 - x\ """ ucode_str_2 = \ """\ -x + 1\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = 1 - 2*x ascii_str_1 = \ """\ 1 - 2*x\ """ ascii_str_2 = \ """\ -2*x + 1\ """ ucode_str_1 = \ """\ 1 - 2⋅x\ """ ucode_str_2 = \ """\ -2⋅x + 1\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = x/y ascii_str = \ """\ x\n\ -\n\ y\ """ ucode_str = \ """\ x\n\ ─\n\ y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -x/y ascii_str = \ """\ -x \n\ ---\n\ y \ """ ucode_str = \ """\ -x \n\ ───\n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x + 2)/y ascii_str_1 = \ """\ 2 + x\n\ -----\n\ y \ """ ascii_str_2 = \ """\ x + 2\n\ -----\n\ y \ """ ucode_str_1 = \ """\ 2 + x\n\ ─────\n\ y \ """ ucode_str_2 = \ """\ x + 2\n\ ─────\n\ y \ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = (1 + x)*y ascii_str_1 = \ """\ y*(1 + x)\ """ ascii_str_2 = \ """\ (1 + x)*y\ """ ascii_str_3 = \ """\ y*(x + 1)\ """ ucode_str_1 = \ """\ y⋅(1 + x)\ """ ucode_str_2 = \ """\ (1 + x)⋅y\ """ ucode_str_3 = \ """\ y⋅(x + 1)\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2, ascii_str_3] assert upretty(expr) in [ucode_str_1, ucode_str_2, ucode_str_3] # Test for correct placement of the negative sign expr = -5*x/(x + 10) ascii_str_1 = \ """\ -5*x \n\ ------\n\ 10 + x\ """ ascii_str_2 = \ """\ -5*x \n\ ------\n\ x + 10\ """ ucode_str_1 = \ """\ -5⋅x \n\ ──────\n\ 10 + x\ """ ucode_str_2 = \ """\ -5⋅x \n\ ──────\n\ x + 10\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = -S.Half - 3*x ascii_str = \ """\ -3*x - 1/2\ """ ucode_str = \ """\ -3⋅x - 1/2\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = S.Half - 3*x ascii_str = \ """\ 1/2 - 3*x\ """ ucode_str = \ """\ 1/2 - 3⋅x\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -S.Half - 3*x/2 ascii_str = \ """\ 3*x 1\n\ - --- - -\n\ 2 2\ """ ucode_str = \ """\ 3⋅x 1\n\ - ─── - ─\n\ 2 2\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = S.Half - 3*x/2 ascii_str = \ """\ 1 3*x\n\ - - ---\n\ 2 2 \ """ ucode_str = \ """\ 1 3⋅x\n\ ─ - ───\n\ 2 2 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_negative_fractions(): expr = -x/y ascii_str =\ """\ -x \n\ ---\n\ y \ """ ucode_str =\ """\ -x \n\ ───\n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -x*z/y ascii_str =\ """\ -x*z \n\ -----\n\ y \ """ ucode_str =\ """\ -x⋅z \n\ ─────\n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = x**2/y ascii_str =\ """\ 2\n\ x \n\ --\n\ y \ """ ucode_str =\ """\ 2\n\ x \n\ ──\n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -x**2/y ascii_str =\ """\ 2 \n\ -x \n\ ----\n\ y \ """ ucode_str =\ """\ 2 \n\ -x \n\ ────\n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -x/(y*z) ascii_str =\ """\ -x \n\ ---\n\ y*z\ """ ucode_str =\ """\ -x \n\ ───\n\ y⋅z\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -a/y**2 ascii_str =\ """\ -a \n\ ---\n\ 2\n\ y \ """ ucode_str =\ """\ -a \n\ ───\n\ 2\n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = y**(-a/b) ascii_str =\ """\ -a \n\ ---\n\ b \n\ y \ """ ucode_str =\ """\ -a \n\ ───\n\ b \n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -1/y**2 ascii_str =\ """\ -1 \n\ ---\n\ 2\n\ y \ """ ucode_str =\ """\ -1 \n\ ───\n\ 2\n\ y \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -10/b**2 ascii_str =\ """\ -10 \n\ ----\n\ 2 \n\ b \ """ ucode_str =\ """\ -10 \n\ ────\n\ 2 \n\ b \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Rational(-200, 37) ascii_str =\ """\ -200 \n\ -----\n\ 37 \ """ ucode_str =\ """\ -200 \n\ ─────\n\ 37 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Mul(0, 1, evaluate=False) assert pretty(expr) == "0*1" assert upretty(expr) == "0⋅1" expr = Mul(1, 0, evaluate=False) assert pretty(expr) == "1*0" assert upretty(expr) == "1⋅0" expr = Mul(1, 1, evaluate=False) assert pretty(expr) == "1*1" assert upretty(expr) == "1⋅1" expr = Mul(1, 1, 1, evaluate=False) assert pretty(expr) == "1*1*1" assert upretty(expr) == "1⋅1⋅1" expr = Mul(1, 2, evaluate=False) assert pretty(expr) == "1*2" assert upretty(expr) == "1⋅2" expr = Add(0, 1, evaluate=False) assert pretty(expr) == "0 + 1" assert upretty(expr) == "0 + 1" expr = Mul(1, 1, 2, evaluate=False) assert pretty(expr) == "1*1*2" assert upretty(expr) == "1⋅1⋅2" expr = Add(0, 0, 1, evaluate=False) assert pretty(expr) == "0 + 0 + 1" assert upretty(expr) == "0 + 0 + 1" expr = Mul(1, -1, evaluate=False) assert pretty(expr) == "1*(-1)" assert upretty(expr) == "1⋅(-1)" expr = Mul(1.0, x, evaluate=False) assert pretty(expr) == "1.0*x" assert upretty(expr) == "1.0⋅x" expr = Mul(1, 1, 2, 3, x, evaluate=False) assert pretty(expr) == "1*1*2*3*x" assert upretty(expr) == "1⋅1⋅2⋅3⋅x" expr = Mul(-1, 1, evaluate=False) assert pretty(expr) == "-1*1" assert upretty(expr) == "-1⋅1" expr = Mul(4, 3, 2, 1, 0, y, x, evaluate=False) assert pretty(expr) == "4*3*2*1*0*y*x" assert upretty(expr) == "4⋅3⋅2⋅1⋅0⋅y⋅x" expr = Mul(4, 3, 2, 1+z, 0, y, x, evaluate=False) assert pretty(expr) == "4*3*2*(z + 1)*0*y*x" assert upretty(expr) == "4⋅3⋅2⋅(z + 1)⋅0⋅y⋅x" expr = Mul(Rational(2, 3), Rational(5, 7), evaluate=False) assert pretty(expr) == "2/3*5/7" assert upretty(expr) == "2/3⋅5/7" def test_issue_5524(): assert pretty(-(-x + 5)*(-x - 2*sqrt(2) + 5) - (-y + 5)*(-y + 5)) == \ """\ 2 / ___ \\\n\ - (5 - y) + (x - 5)*\\-x - 2*\\/ 2 + 5/\ """ assert upretty(-(-x + 5)*(-x - 2*sqrt(2) + 5) - (-y + 5)*(-y + 5)) == \ """\ 2 \n\ - (5 - y) + (x - 5)⋅(-x - 2⋅√2 + 5)\ """ def test_pretty_ordering(): assert pretty(x**2 + x + 1, order='lex') == \ """\ 2 \n\ x + x + 1\ """ assert pretty(x**2 + x + 1, order='rev-lex') == \ """\ 2\n\ 1 + x + x \ """ assert pretty(1 - x, order='lex') == '-x + 1' assert pretty(1 - x, order='rev-lex') == '1 - x' assert pretty(1 - 2*x, order='lex') == '-2*x + 1' assert pretty(1 - 2*x, order='rev-lex') == '1 - 2*x' f = 2*x**4 + y**2 - x**2 + y**3 assert pretty(f, order=None) == \ """\ 4 2 3 2\n\ 2*x - x + y + y \ """ assert pretty(f, order='lex') == \ """\ 4 2 3 2\n\ 2*x - x + y + y \ """ assert pretty(f, order='rev-lex') == \ """\ 2 3 2 4\n\ y + y - x + 2*x \ """ expr = x - x**3/6 + x**5/120 + O(x**6) ascii_str = \ """\ 3 5 \n\ x x / 6\\\n\ x - -- + --- + O\\x /\n\ 6 120 \ """ ucode_str = \ """\ 3 5 \n\ x x ⎛ 6⎞\n\ x - ── + ─── + O⎝x ⎠\n\ 6 120 \ """ assert pretty(expr, order=None) == ascii_str assert upretty(expr, order=None) == ucode_str assert pretty(expr, order='lex') == ascii_str assert upretty(expr, order='lex') == ucode_str assert pretty(expr, order='rev-lex') == ascii_str assert upretty(expr, order='rev-lex') == ucode_str def test_EulerGamma(): assert pretty(EulerGamma) == str(EulerGamma) == "EulerGamma" assert upretty(EulerGamma) == "γ" def test_GoldenRatio(): assert pretty(GoldenRatio) == str(GoldenRatio) == "GoldenRatio" assert upretty(GoldenRatio) == "φ" def test_pretty_relational(): expr = Eq(x, y) ascii_str = \ """\ x = y\ """ ucode_str = \ """\ x = y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lt(x, y) ascii_str = \ """\ x < y\ """ ucode_str = \ """\ x < y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Gt(x, y) ascii_str = \ """\ x > y\ """ ucode_str = \ """\ x > y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Le(x, y) ascii_str = \ """\ x <= y\ """ ucode_str = \ """\ x ≤ y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Ge(x, y) ascii_str = \ """\ x >= y\ """ ucode_str = \ """\ x ≥ y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Ne(x/(y + 1), y**2) ascii_str_1 = \ """\ x 2\n\ ----- != y \n\ 1 + y \ """ ascii_str_2 = \ """\ x 2\n\ ----- != y \n\ y + 1 \ """ ucode_str_1 = \ """\ x 2\n\ ───── ≠ y \n\ 1 + y \ """ ucode_str_2 = \ """\ x 2\n\ ───── ≠ y \n\ y + 1 \ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] def test_Assignment(): expr = Assignment(x, y) ascii_str = \ """\ x := y\ """ ucode_str = \ """\ x := y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_AugmentedAssignment(): expr = AddAugmentedAssignment(x, y) ascii_str = \ """\ x += y\ """ ucode_str = \ """\ x += y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = SubAugmentedAssignment(x, y) ascii_str = \ """\ x -= y\ """ ucode_str = \ """\ x -= y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = MulAugmentedAssignment(x, y) ascii_str = \ """\ x *= y\ """ ucode_str = \ """\ x *= y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = DivAugmentedAssignment(x, y) ascii_str = \ """\ x /= y\ """ ucode_str = \ """\ x /= y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = ModAugmentedAssignment(x, y) ascii_str = \ """\ x %= y\ """ ucode_str = \ """\ x %= y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_rational(): expr = y*x**-2 ascii_str = \ """\ y \n\ --\n\ 2\n\ x \ """ ucode_str = \ """\ y \n\ ──\n\ 2\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = y**Rational(3, 2) * x**Rational(-5, 2) ascii_str = \ """\ 3/2\n\ y \n\ ----\n\ 5/2\n\ x \ """ ucode_str = \ """\ 3/2\n\ y \n\ ────\n\ 5/2\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = sin(x)**3/tan(x)**2 ascii_str = \ """\ 3 \n\ sin (x)\n\ -------\n\ 2 \n\ tan (x)\ """ ucode_str = \ """\ 3 \n\ sin (x)\n\ ───────\n\ 2 \n\ tan (x)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str @_both_exp_pow def test_pretty_functions(): """Tests for Abs, conjugate, exp, function braces, and factorial.""" expr = (2*x + exp(x)) ascii_str_1 = \ """\ x\n\ 2*x + e \ """ ascii_str_2 = \ """\ x \n\ e + 2*x\ """ ucode_str_1 = \ """\ x\n\ 2⋅x + ℯ \ """ ucode_str_2 = \ """\ x \n\ ℯ + 2⋅x\ """ ucode_str_3 = \ """\ x \n\ ℯ + 2⋅x\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2, ucode_str_3] expr = Abs(x) ascii_str = \ """\ |x|\ """ ucode_str = \ """\ │x│\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Abs(x/(x**2 + 1)) ascii_str_1 = \ """\ | x |\n\ |------|\n\ | 2|\n\ |1 + x |\ """ ascii_str_2 = \ """\ | x |\n\ |------|\n\ | 2 |\n\ |x + 1|\ """ ucode_str_1 = \ """\ │ x │\n\ │──────│\n\ │ 2│\n\ │1 + x │\ """ ucode_str_2 = \ """\ │ x │\n\ │──────│\n\ │ 2 │\n\ │x + 1│\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Abs(1 / (y - Abs(x))) ascii_str = \ """\ 1 \n\ ---------\n\ |y - |x||\ """ ucode_str = \ """\ 1 \n\ ─────────\n\ │y - │x││\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str n = Symbol('n', integer=True) expr = factorial(n) ascii_str = \ """\ n!\ """ ucode_str = \ """\ n!\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial(2*n) ascii_str = \ """\ (2*n)!\ """ ucode_str = \ """\ (2⋅n)!\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial(factorial(factorial(n))) ascii_str = \ """\ ((n!)!)!\ """ ucode_str = \ """\ ((n!)!)!\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial(n + 1) ascii_str_1 = \ """\ (1 + n)!\ """ ascii_str_2 = \ """\ (n + 1)!\ """ ucode_str_1 = \ """\ (1 + n)!\ """ ucode_str_2 = \ """\ (n + 1)!\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = subfactorial(n) ascii_str = \ """\ !n\ """ ucode_str = \ """\ !n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = subfactorial(2*n) ascii_str = \ """\ !(2*n)\ """ ucode_str = \ """\ !(2⋅n)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str n = Symbol('n', integer=True) expr = factorial2(n) ascii_str = \ """\ n!!\ """ ucode_str = \ """\ n!!\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial2(2*n) ascii_str = \ """\ (2*n)!!\ """ ucode_str = \ """\ (2⋅n)!!\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial2(factorial2(factorial2(n))) ascii_str = \ """\ ((n!!)!!)!!\ """ ucode_str = \ """\ ((n!!)!!)!!\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = factorial2(n + 1) ascii_str_1 = \ """\ (1 + n)!!\ """ ascii_str_2 = \ """\ (n + 1)!!\ """ ucode_str_1 = \ """\ (1 + n)!!\ """ ucode_str_2 = \ """\ (n + 1)!!\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = 2*binomial(n, k) ascii_str = \ """\ /n\\\n\ 2*| |\n\ \\k/\ """ ucode_str = \ """\ ⎛n⎞\n\ 2⋅⎜ ⎟\n\ ⎝k⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2*binomial(2*n, k) ascii_str = \ """\ /2*n\\\n\ 2*| |\n\ \\ k /\ """ ucode_str = \ """\ ⎛2⋅n⎞\n\ 2⋅⎜ ⎟\n\ ⎝ k ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2*binomial(n**2, k) ascii_str = \ """\ / 2\\\n\ |n |\n\ 2*| |\n\ \\k /\ """ ucode_str = \ """\ ⎛ 2⎞\n\ ⎜n ⎟\n\ 2⋅⎜ ⎟\n\ ⎝k ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = catalan(n) ascii_str = \ """\ C \n\ n\ """ ucode_str = \ """\ C \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = catalan(n) ascii_str = \ """\ C \n\ n\ """ ucode_str = \ """\ C \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = bell(n) ascii_str = \ """\ B \n\ n\ """ ucode_str = \ """\ B \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = bernoulli(n) ascii_str = \ """\ B \n\ n\ """ ucode_str = \ """\ B \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = bernoulli(n, x) ascii_str = \ """\ B (x)\n\ n \ """ ucode_str = \ """\ B (x)\n\ n \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = fibonacci(n) ascii_str = \ """\ F \n\ n\ """ ucode_str = \ """\ F \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = lucas(n) ascii_str = \ """\ L \n\ n\ """ ucode_str = \ """\ L \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = tribonacci(n) ascii_str = \ """\ T \n\ n\ """ ucode_str = \ """\ T \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = stieltjes(n) ascii_str = \ """\ stieltjes \n\ n\ """ ucode_str = \ """\ γ \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = stieltjes(n, x) ascii_str = \ """\ stieltjes (x)\n\ n \ """ ucode_str = \ """\ γ (x)\n\ n \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = mathieuc(x, y, z) ascii_str = 'C(x, y, z)' ucode_str = 'C(x, y, z)' assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = mathieus(x, y, z) ascii_str = 'S(x, y, z)' ucode_str = 'S(x, y, z)' assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = mathieucprime(x, y, z) ascii_str = "C'(x, y, z)" ucode_str = "C'(x, y, z)" assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = mathieusprime(x, y, z) ascii_str = "S'(x, y, z)" ucode_str = "S'(x, y, z)" assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = conjugate(x) ascii_str = \ """\ _\n\ x\ """ ucode_str = \ """\ _\n\ x\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str f = Function('f') expr = conjugate(f(x + 1)) ascii_str_1 = \ """\ ________\n\ f(1 + x)\ """ ascii_str_2 = \ """\ ________\n\ f(x + 1)\ """ ucode_str_1 = \ """\ ________\n\ f(1 + x)\ """ ucode_str_2 = \ """\ ________\n\ f(x + 1)\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = f(x) ascii_str = \ """\ f(x)\ """ ucode_str = \ """\ f(x)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = f(x, y) ascii_str = \ """\ f(x, y)\ """ ucode_str = \ """\ f(x, y)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = f(x/(y + 1), y) ascii_str_1 = \ """\ / x \\\n\ f|-----, y|\n\ \\1 + y /\ """ ascii_str_2 = \ """\ / x \\\n\ f|-----, y|\n\ \\y + 1 /\ """ ucode_str_1 = \ """\ ⎛ x ⎞\n\ f⎜─────, y⎟\n\ ⎝1 + y ⎠\ """ ucode_str_2 = \ """\ ⎛ x ⎞\n\ f⎜─────, y⎟\n\ ⎝y + 1 ⎠\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = f(x**x**x**x**x**x) ascii_str = \ """\ / / / / / x\\\\\\\\\\ | | | | \\x /|||| | | | \\x /||| | | \\x /|| | \\x /| f\\x /\ """ ucode_str = \ """\ ⎛ ⎛ ⎛ ⎛ ⎛ x⎞⎞⎞⎞⎞ ⎜ ⎜ ⎜ ⎜ ⎝x ⎠⎟⎟⎟⎟ ⎜ ⎜ ⎜ ⎝x ⎠⎟⎟⎟ ⎜ ⎜ ⎝x ⎠⎟⎟ ⎜ ⎝x ⎠⎟ f⎝x ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = sin(x)**2 ascii_str = \ """\ 2 \n\ sin (x)\ """ ucode_str = \ """\ 2 \n\ sin (x)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = conjugate(a + b*I) ascii_str = \ """\ _ _\n\ a - I*b\ """ ucode_str = \ """\ _ _\n\ a - ⅈ⋅b\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = conjugate(exp(a + b*I)) ascii_str = \ """\ _ _\n\ a - I*b\n\ e \ """ ucode_str = \ """\ _ _\n\ a - ⅈ⋅b\n\ ℯ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = conjugate( f(1 + conjugate(f(x))) ) ascii_str_1 = \ """\ ___________\n\ / ____\\\n\ f\\1 + f(x)/\ """ ascii_str_2 = \ """\ ___________\n\ /____ \\\n\ f\\f(x) + 1/\ """ ucode_str_1 = \ """\ ___________\n\ ⎛ ____⎞\n\ f⎝1 + f(x)⎠\ """ ucode_str_2 = \ """\ ___________\n\ ⎛____ ⎞\n\ f⎝f(x) + 1⎠\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = f(x/(y + 1), y) ascii_str_1 = \ """\ / x \\\n\ f|-----, y|\n\ \\1 + y /\ """ ascii_str_2 = \ """\ / x \\\n\ f|-----, y|\n\ \\y + 1 /\ """ ucode_str_1 = \ """\ ⎛ x ⎞\n\ f⎜─────, y⎟\n\ ⎝1 + y ⎠\ """ ucode_str_2 = \ """\ ⎛ x ⎞\n\ f⎜─────, y⎟\n\ ⎝y + 1 ⎠\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = floor(1 / (y - floor(x))) ascii_str = \ """\ / 1 \\\n\ floor|------------|\n\ \\y - floor(x)/\ """ ucode_str = \ """\ ⎢ 1 ⎥\n\ ⎢───────⎥\n\ ⎣y - ⌊x⌋⎦\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = ceiling(1 / (y - ceiling(x))) ascii_str = \ """\ / 1 \\\n\ ceiling|--------------|\n\ \\y - ceiling(x)/\ """ ucode_str = \ """\ ⎡ 1 ⎤\n\ ⎢───────⎥\n\ ⎢y - ⌈x⌉⎥\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = euler(n) ascii_str = \ """\ E \n\ n\ """ ucode_str = \ """\ E \n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = euler(1/(1 + 1/(1 + 1/n))) ascii_str = \ """\ E \n\ 1 \n\ ---------\n\ 1 \n\ 1 + -----\n\ 1\n\ 1 + -\n\ n\ """ ucode_str = \ """\ E \n\ 1 \n\ ─────────\n\ 1 \n\ 1 + ─────\n\ 1\n\ 1 + ─\n\ n\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = euler(n, x) ascii_str = \ """\ E (x)\n\ n \ """ ucode_str = \ """\ E (x)\n\ n \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = euler(n, x/2) ascii_str = \ """\ /x\\\n\ E |-|\n\ n\\2/\ """ ucode_str = \ """\ ⎛x⎞\n\ E ⎜─⎟\n\ n⎝2⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_sqrt(): expr = sqrt(2) ascii_str = \ """\ ___\n\ \\/ 2 \ """ ucode_str = \ "√2" assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2**Rational(1, 3) ascii_str = \ """\ 3 ___\n\ \\/ 2 \ """ ucode_str = \ """\ 3 ___\n\ ╲╱ 2 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2**Rational(1, 1000) ascii_str = \ """\ 1000___\n\ \\/ 2 \ """ ucode_str = \ """\ 1000___\n\ ╲╱ 2 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = sqrt(x**2 + 1) ascii_str = \ """\ ________\n\ / 2 \n\ \\/ x + 1 \ """ ucode_str = \ """\ ________\n\ ╱ 2 \n\ ╲╱ x + 1 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (1 + sqrt(5))**Rational(1, 3) ascii_str = \ """\ ___________\n\ 3 / ___ \n\ \\/ 1 + \\/ 5 \ """ ucode_str = \ """\ 3 ________\n\ ╲╱ 1 + √5 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2**(1/x) ascii_str = \ """\ x ___\n\ \\/ 2 \ """ ucode_str = \ """\ x ___\n\ ╲╱ 2 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = sqrt(2 + pi) ascii_str = \ """\ ________\n\ \\/ 2 + pi \ """ ucode_str = \ """\ _______\n\ ╲╱ 2 + π \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (2 + ( 1 + x**2)/(2 + x))**Rational(1, 4) + (1 + x**Rational(1, 1000))/sqrt(3 + x**2) ascii_str = \ """\ ____________ \n\ / 2 1000___ \n\ / x + 1 \\/ x + 1\n\ 4 / 2 + ------ + -----------\n\ \\/ x + 2 ________\n\ / 2 \n\ \\/ x + 3 \ """ ucode_str = \ """\ ____________ \n\ ╱ 2 1000___ \n\ ╱ x + 1 ╲╱ x + 1\n\ 4 ╱ 2 + ────── + ───────────\n\ ╲╱ x + 2 ________\n\ ╱ 2 \n\ ╲╱ x + 3 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_sqrt_char_knob(): # See PR #9234. expr = sqrt(2) ucode_str1 = \ """\ ___\n\ ╲╱ 2 \ """ ucode_str2 = \ "√2" assert xpretty(expr, use_unicode=True, use_unicode_sqrt_char=False) == ucode_str1 assert xpretty(expr, use_unicode=True, use_unicode_sqrt_char=True) == ucode_str2 def test_pretty_sqrt_longsymbol_no_sqrt_char(): # Do not use unicode sqrt char for long symbols (see PR #9234). expr = sqrt(Symbol('C1')) ucode_str = \ """\ ____\n\ ╲╱ C₁ \ """ assert upretty(expr) == ucode_str def test_pretty_KroneckerDelta(): x, y = symbols("x, y") expr = KroneckerDelta(x, y) ascii_str = \ """\ d \n\ x,y\ """ ucode_str = \ """\ δ \n\ x,y\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_product(): n, m, k, l = symbols('n m k l') f = symbols('f', cls=Function) expr = Product(f((n/3)**2), (n, k**2, l)) unicode_str = \ """\ l \n\ ─┬──────┬─ \n\ │ │ ⎛ 2⎞\n\ │ │ ⎜n ⎟\n\ │ │ f⎜──⎟\n\ │ │ ⎝9 ⎠\n\ │ │ \n\ 2 \n\ n = k """ ascii_str = \ """\ l \n\ __________ \n\ | | / 2\\\n\ | | |n |\n\ | | f|--|\n\ | | \\9 /\n\ | | \n\ 2 \n\ n = k """ expr = Product(f((n/3)**2), (n, k**2, l), (l, 1, m)) unicode_str = \ """\ m l \n\ ─┬──────┬─ ─┬──────┬─ \n\ │ │ │ │ ⎛ 2⎞\n\ │ │ │ │ ⎜n ⎟\n\ │ │ │ │ f⎜──⎟\n\ │ │ │ │ ⎝9 ⎠\n\ │ │ │ │ \n\ l = 1 2 \n\ n = k """ ascii_str = \ """\ m l \n\ __________ __________ \n\ | | | | / 2\\\n\ | | | | |n |\n\ | | | | f|--|\n\ | | | | \\9 /\n\ | | | | \n\ l = 1 2 \n\ n = k """ assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str def test_pretty_Lambda(): # S.IdentityFunction is a special case expr = Lambda(y, y) assert pretty(expr) == "x -> x" assert upretty(expr) == "x ↦ x" expr = Lambda(x, x+1) assert pretty(expr) == "x -> x + 1" assert upretty(expr) == "x ↦ x + 1" expr = Lambda(x, x**2) ascii_str = \ """\ 2\n\ x -> x \ """ ucode_str = \ """\ 2\n\ x ↦ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda(x, x**2)**2 ascii_str = \ """\ 2 / 2\\ \n\ \\x -> x / \ """ ucode_str = \ """\ 2 ⎛ 2⎞ \n\ ⎝x ↦ x ⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda((x, y), x) ascii_str = "(x, y) -> x" ucode_str = "(x, y) ↦ x" assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda((x, y), x**2) ascii_str = \ """\ 2\n\ (x, y) -> x \ """ ucode_str = \ """\ 2\n\ (x, y) ↦ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Lambda(((x, y),), x**2) ascii_str = \ """\ 2\n\ ((x, y),) -> x \ """ ucode_str = \ """\ 2\n\ ((x, y),) ↦ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_TransferFunction(): tf1 = TransferFunction(s - 1, s + 1, s) assert upretty(tf1) == "s - 1\n─────\ns + 1" tf2 = TransferFunction(2*s + 1, 3 - p, s) assert upretty(tf2) == "2⋅s + 1\n───────\n 3 - p " tf3 = TransferFunction(p, p + 1, p) assert upretty(tf3) == " p \n─────\np + 1" def test_pretty_Series(): tf1 = TransferFunction(x + y, x - 2*y, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(x**2 + y, y - x, y) tf4 = TransferFunction(2, 3, y) tfm1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) tfm2 = TransferFunctionMatrix([[tf3], [-tf4]]) tfm3 = TransferFunctionMatrix([[tf1, -tf2, -tf3], [tf3, -tf4, tf2]]) tfm4 = TransferFunctionMatrix([[tf1, tf2], [tf3, -tf4], [-tf2, -tf1]]) tfm5 = TransferFunctionMatrix([[-tf2, -tf1], [tf4, -tf3], [tf1, tf2]]) expected1 = \ """\ ⎛ 2 ⎞\n\ ⎛ x + y ⎞ ⎜x + y⎟\n\ ⎜───────⎟⋅⎜──────⎟\n\ ⎝x - 2⋅y⎠ ⎝-x + y⎠\ """ expected2 = \ """\ ⎛-x + y⎞ ⎛ -x - y⎞\n\ ⎜──────⎟⋅⎜───────⎟\n\ ⎝x + y ⎠ ⎝x - 2⋅y⎠\ """ expected3 = \ """\ ⎛ 2 ⎞ \n\ ⎜x + y⎟ ⎛ x + y ⎞ ⎛ -x - y x - y⎞\n\ ⎜──────⎟⋅⎜───────⎟⋅⎜─────── + ─────⎟\n\ ⎝-x + y⎠ ⎝x - 2⋅y⎠ ⎝x - 2⋅y x + y⎠\ """ expected4 = \ """\ ⎛ 2 ⎞\n\ ⎛ x + y x - y⎞ ⎜x - y x + y⎟\n\ ⎜─────── + ─────⎟⋅⎜───── + ──────⎟\n\ ⎝x - 2⋅y x + y⎠ ⎝x + y -x + y⎠\ """ expected5 = \ """\ ⎡ x + y x - y⎤ ⎡ 2 ⎤ \n\ ⎢─────── ─────⎥ ⎢x + y⎥ \n\ ⎢x - 2⋅y x + y⎥ ⎢──────⎥ \n\ ⎢ ⎥ ⎢-x + y⎥ \n\ ⎢ 2 ⎥ ⋅⎢ ⎥ \n\ ⎢x + y 2 ⎥ ⎢ -2 ⎥ \n\ ⎢────── ─ ⎥ ⎢ ─── ⎥ \n\ ⎣-x + y 3 ⎦τ ⎣ 3 ⎦τ\ """ expected6 = \ """\ ⎛⎡ x + y x - y ⎤ ⎡ x - y x + y ⎤ ⎞\n\ ⎜⎢─────── ───── ⎥ ⎢ ───── ───────⎥ ⎟\n\ ⎡ x + y x - y⎤ ⎡ 2 ⎤ ⎜⎢x - 2⋅y x + y ⎥ ⎢ x + y x - 2⋅y⎥ ⎟\n\ ⎢─────── ─────⎥ ⎢ x + y -x + y - x - y⎥ ⎜⎢ ⎥ ⎢ ⎥ ⎟\n\ ⎢x - 2⋅y x + y⎥ ⎢─────── ────── ────────⎥ ⎜⎢ 2 ⎥ ⎢ 2 ⎥ ⎟\n\ ⎢ ⎥ ⎢x - 2⋅y x + y -x + y ⎥ ⎜⎢x + y -2 ⎥ ⎢ -2 x + y ⎥ ⎟\n\ ⎢ 2 ⎥ ⋅⎢ ⎥ ⋅⎜⎢────── ─── ⎥ + ⎢ ─── ────── ⎥ ⎟\n\ ⎢x + y 2 ⎥ ⎢ 2 ⎥ ⎜⎢-x + y 3 ⎥ ⎢ 3 -x + y ⎥ ⎟\n\ ⎢────── ─ ⎥ ⎢x + y -2 x - y ⎥ ⎜⎢ ⎥ ⎢ ⎥ ⎟\n\ ⎣-x + y 3 ⎦τ ⎢────── ─── ───── ⎥ ⎜⎢-x + y -x - y⎥ ⎢ -x - y -x + y ⎥ ⎟\n\ ⎣-x + y 3 x + y ⎦τ ⎜⎢────── ───────⎥ ⎢─────── ────── ⎥ ⎟\n\ ⎝⎣x + y x - 2⋅y⎦τ ⎣x - 2⋅y x + y ⎦τ⎠\ """ assert upretty(Series(tf1, tf3)) == expected1 assert upretty(Series(-tf2, -tf1)) == expected2 assert upretty(Series(tf3, tf1, Parallel(-tf1, tf2))) == expected3 assert upretty(Series(Parallel(tf1, tf2), Parallel(tf2, tf3))) == expected4 assert upretty(MIMOSeries(tfm2, tfm1)) == expected5 assert upretty(MIMOSeries(MIMOParallel(tfm4, -tfm5), tfm3, tfm1)) == expected6 def test_pretty_Parallel(): tf1 = TransferFunction(x + y, x - 2*y, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(x**2 + y, y - x, y) tf4 = TransferFunction(y**2 - x, x**3 + x, y) tfm1 = TransferFunctionMatrix([[tf1, tf2], [tf3, -tf4], [-tf2, -tf1]]) tfm2 = TransferFunctionMatrix([[-tf2, -tf1], [tf4, -tf3], [tf1, tf2]]) tfm3 = TransferFunctionMatrix([[-tf1, tf2], [-tf3, tf4], [tf2, tf1]]) tfm4 = TransferFunctionMatrix([[-tf1, -tf2], [-tf3, -tf4]]) expected1 = \ """\ x + y x - y\n\ ─────── + ─────\n\ x - 2⋅y x + y\ """ expected2 = \ """\ -x + y -x - y\n\ ────── + ───────\n\ x + y x - 2⋅y\ """ expected3 = \ """\ 2 \n\ x + y x + y ⎛ -x - y⎞ ⎛x - y⎞\n\ ────── + ─────── + ⎜───────⎟⋅⎜─────⎟\n\ -x + y x - 2⋅y ⎝x - 2⋅y⎠ ⎝x + y⎠\ """ expected4 = \ """\ ⎛ 2 ⎞\n\ ⎛ x + y ⎞ ⎛x - y⎞ ⎛x - y⎞ ⎜x + y⎟\n\ ⎜───────⎟⋅⎜─────⎟ + ⎜─────⎟⋅⎜──────⎟\n\ ⎝x - 2⋅y⎠ ⎝x + y⎠ ⎝x + y⎠ ⎝-x + y⎠\ """ expected5 = \ """\ ⎡ x + y -x + y ⎤ ⎡ x - y x + y ⎤ ⎡ x + y x - y ⎤ \n\ ⎢─────── ────── ⎥ ⎢ ───── ───────⎥ ⎢─────── ───── ⎥ \n\ ⎢x - 2⋅y x + y ⎥ ⎢ x + y x - 2⋅y⎥ ⎢x - 2⋅y x + y ⎥ \n\ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ \n\ ⎢ 2 2 ⎥ ⎢ 2 2 ⎥ ⎢ 2 2 ⎥ \n\ ⎢x + y x - y ⎥ ⎢x - y x + y ⎥ ⎢x + y x - y ⎥ \n\ ⎢────── ────── ⎥ + ⎢────── ────── ⎥ + ⎢────── ────── ⎥ \n\ ⎢-x + y 3 ⎥ ⎢ 3 -x + y ⎥ ⎢-x + y 3 ⎥ \n\ ⎢ x + x ⎥ ⎢x + x ⎥ ⎢ x + x ⎥ \n\ ⎢ ⎥ ⎢ ⎥ ⎢ ⎥ \n\ ⎢-x + y -x - y⎥ ⎢ -x - y -x + y ⎥ ⎢-x + y -x - y⎥ \n\ ⎢────── ───────⎥ ⎢─────── ────── ⎥ ⎢────── ───────⎥ \n\ ⎣x + y x - 2⋅y⎦τ ⎣x - 2⋅y x + y ⎦τ ⎣x + y x - 2⋅y⎦τ\ """ expected6 = \ """\ ⎡ x - y x + y ⎤ ⎡-x + y -x - y ⎤ \n\ ⎢ ───── ───────⎥ ⎢────── ─────── ⎥ \n\ ⎢ x + y x - 2⋅y⎥ ⎡ -x - y -x + y⎤ ⎢x + y x - 2⋅y ⎥ \n\ ⎢ ⎥ ⎢─────── ──────⎥ ⎢ ⎥ \n\ ⎢ 2 2 ⎥ ⎢x - 2⋅y x + y ⎥ ⎢ 2 2 ⎥ \n\ ⎢x - y x + y ⎥ ⎢ ⎥ ⎢-x + y - x - y⎥ \n\ ⎢────── ────── ⎥ ⋅⎢ 2 2⎥ + ⎢─────── ────────⎥ \n\ ⎢ 3 -x + y ⎥ ⎢- x - y x - y ⎥ ⎢ 3 -x + y ⎥ \n\ ⎢x + x ⎥ ⎢──────── ──────⎥ ⎢ x + x ⎥ \n\ ⎢ ⎥ ⎢ -x + y 3 ⎥ ⎢ ⎥ \n\ ⎢ -x - y -x + y ⎥ ⎣ x + x⎦τ ⎢ x + y x - y ⎥ \n\ ⎢─────── ────── ⎥ ⎢─────── ───── ⎥ \n\ ⎣x - 2⋅y x + y ⎦τ ⎣x - 2⋅y x + y ⎦τ\ """ assert upretty(Parallel(tf1, tf2)) == expected1 assert upretty(Parallel(-tf2, -tf1)) == expected2 assert upretty(Parallel(tf3, tf1, Series(-tf1, tf2))) == expected3 assert upretty(Parallel(Series(tf1, tf2), Series(tf2, tf3))) == expected4 assert upretty(MIMOParallel(-tfm3, -tfm2, tfm1)) == expected5 assert upretty(MIMOParallel(MIMOSeries(tfm4, -tfm2), tfm2)) == expected6 def test_pretty_Feedback(): tf = TransferFunction(1, 1, y) tf1 = TransferFunction(x + y, x - 2*y, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(y**2 - 2*y + 1, y + 5, y) tf4 = TransferFunction(x - 2*y**3, x + y, x) tf5 = TransferFunction(1 - x, x - y, y) tf6 = TransferFunction(2, 2, x) expected1 = \ """\ ⎛1⎞ \n\ ⎜─⎟ \n\ ⎝1⎠ \n\ ─────────────\n\ 1 ⎛ x + y ⎞\n\ ─ + ⎜───────⎟\n\ 1 ⎝x - 2⋅y⎠\ """ expected2 = \ """\ ⎛1⎞ \n\ ⎜─⎟ \n\ ⎝1⎠ \n\ ────────────────────────────────────\n\ ⎛ 2 ⎞\n\ 1 ⎛x - y⎞ ⎛ x + y ⎞ ⎜y - 2⋅y + 1⎟\n\ ─ + ⎜─────⎟⋅⎜───────⎟⋅⎜────────────⎟\n\ 1 ⎝x + y⎠ ⎝x - 2⋅y⎠ ⎝ y + 5 ⎠\ """ expected3 = \ """\ ⎛ x + y ⎞ \n\ ⎜───────⎟ \n\ ⎝x - 2⋅y⎠ \n\ ────────────────────────────────────────────\n\ ⎛ 2 ⎞ \n\ 1 ⎛ x + y ⎞ ⎛x - y⎞ ⎜y - 2⋅y + 1⎟ ⎛1 - x⎞\n\ ─ + ⎜───────⎟⋅⎜─────⎟⋅⎜────────────⎟⋅⎜─────⎟\n\ 1 ⎝x - 2⋅y⎠ ⎝x + y⎠ ⎝ y + 5 ⎠ ⎝x - y⎠\ """ expected4 = \ """\ ⎛ x + y ⎞ ⎛x - y⎞ \n\ ⎜───────⎟⋅⎜─────⎟ \n\ ⎝x - 2⋅y⎠ ⎝x + y⎠ \n\ ─────────────────────\n\ 1 ⎛ x + y ⎞ ⎛x - y⎞\n\ ─ + ⎜───────⎟⋅⎜─────⎟\n\ 1 ⎝x - 2⋅y⎠ ⎝x + y⎠\ """ expected5 = \ """\ ⎛ x + y ⎞ ⎛x - y⎞ \n\ ⎜───────⎟⋅⎜─────⎟ \n\ ⎝x - 2⋅y⎠ ⎝x + y⎠ \n\ ─────────────────────────────\n\ 1 ⎛ x + y ⎞ ⎛x - y⎞ ⎛1 - x⎞\n\ ─ + ⎜───────⎟⋅⎜─────⎟⋅⎜─────⎟\n\ 1 ⎝x - 2⋅y⎠ ⎝x + y⎠ ⎝x - y⎠\ """ expected6 = \ """\ ⎛ 2 ⎞ \n\ ⎜y - 2⋅y + 1⎟ ⎛1 - x⎞ \n\ ⎜────────────⎟⋅⎜─────⎟ \n\ ⎝ y + 5 ⎠ ⎝x - y⎠ \n\ ────────────────────────────────────────────\n\ ⎛ 2 ⎞ \n\ 1 ⎜y - 2⋅y + 1⎟ ⎛1 - x⎞ ⎛x - y⎞ ⎛ x + y ⎞\n\ ─ + ⎜────────────⎟⋅⎜─────⎟⋅⎜─────⎟⋅⎜───────⎟\n\ 1 ⎝ y + 5 ⎠ ⎝x - y⎠ ⎝x + y⎠ ⎝x - 2⋅y⎠\ """ expected7 = \ """\ ⎛ 3⎞ \n\ ⎜x - 2⋅y ⎟ \n\ ⎜────────⎟ \n\ ⎝ x + y ⎠ \n\ ──────────────────\n\ ⎛ 3⎞ \n\ 1 ⎜x - 2⋅y ⎟ ⎛2⎞\n\ ─ + ⎜────────⎟⋅⎜─⎟\n\ 1 ⎝ x + y ⎠ ⎝2⎠\ """ expected8 = \ """\ ⎛1 - x⎞ \n\ ⎜─────⎟ \n\ ⎝x - y⎠ \n\ ───────────\n\ 1 ⎛1 - x⎞\n\ ─ + ⎜─────⎟\n\ 1 ⎝x - y⎠\ """ expected9 = \ """\ ⎛ x + y ⎞ ⎛x - y⎞ \n\ ⎜───────⎟⋅⎜─────⎟ \n\ ⎝x - 2⋅y⎠ ⎝x + y⎠ \n\ ─────────────────────────────\n\ 1 ⎛ x + y ⎞ ⎛x - y⎞ ⎛1 - x⎞\n\ ─ - ⎜───────⎟⋅⎜─────⎟⋅⎜─────⎟\n\ 1 ⎝x - 2⋅y⎠ ⎝x + y⎠ ⎝x - y⎠\ """ expected10 = \ """\ ⎛1 - x⎞ \n\ ⎜─────⎟ \n\ ⎝x - y⎠ \n\ ───────────\n\ 1 ⎛1 - x⎞\n\ ─ - ⎜─────⎟\n\ 1 ⎝x - y⎠\ """ assert upretty(Feedback(tf, tf1)) == expected1 assert upretty(Feedback(tf, tf2*tf1*tf3)) == expected2 assert upretty(Feedback(tf1, tf2*tf3*tf5)) == expected3 assert upretty(Feedback(tf1*tf2, tf)) == expected4 assert upretty(Feedback(tf1*tf2, tf5)) == expected5 assert upretty(Feedback(tf3*tf5, tf2*tf1)) == expected6 assert upretty(Feedback(tf4, tf6)) == expected7 assert upretty(Feedback(tf5, tf)) == expected8 assert upretty(Feedback(tf1*tf2, tf5, 1)) == expected9 assert upretty(Feedback(tf5, tf, 1)) == expected10 def test_pretty_MIMOFeedback(): tf1 = TransferFunction(x + y, x - 2*y, y) tf2 = TransferFunction(x - y, x + y, y) tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) tfm_3 = TransferFunctionMatrix([[tf1, tf1], [tf2, tf2]]) expected1 = \ """\ ⎛ ⎡ x + y x - y ⎤ ⎡ x - y x + y ⎤ ⎞-1 ⎡ x + y x - y ⎤ \n\ ⎜ ⎢─────── ───── ⎥ ⎢ ───── ───────⎥ ⎟ ⎢─────── ───── ⎥ \n\ ⎜ ⎢x - 2⋅y x + y ⎥ ⎢ x + y x - 2⋅y⎥ ⎟ ⎢x - 2⋅y x + y ⎥ \n\ ⎜I - ⎢ ⎥ ⋅⎢ ⎥ ⎟ ⋅ ⎢ ⎥ \n\ ⎜ ⎢ x - y x + y ⎥ ⎢ x + y x - y ⎥ ⎟ ⎢ x - y x + y ⎥ \n\ ⎜ ⎢ ───── ───────⎥ ⎢─────── ───── ⎥ ⎟ ⎢ ───── ───────⎥ \n\ ⎝ ⎣ x + y x - 2⋅y⎦τ ⎣x - 2⋅y x + y ⎦τ⎠ ⎣ x + y x - 2⋅y⎦τ\ """ expected2 = \ """\ ⎛ ⎡ x + y x - y ⎤ ⎡ x - y x + y ⎤ ⎡ x + y x + y ⎤ ⎞-1 ⎡ x + y x - y ⎤ ⎡ x - y x + y ⎤ \n\ ⎜ ⎢─────── ───── ⎥ ⎢ ───── ───────⎥ ⎢─────── ───────⎥ ⎟ ⎢─────── ───── ⎥ ⎢ ───── ───────⎥ \n\ ⎜ ⎢x - 2⋅y x + y ⎥ ⎢ x + y x - 2⋅y⎥ ⎢x - 2⋅y x - 2⋅y⎥ ⎟ ⎢x - 2⋅y x + y ⎥ ⎢ x + y x - 2⋅y⎥ \n\ ⎜I + ⎢ ⎥ ⋅⎢ ⎥ ⋅⎢ ⎥ ⎟ ⋅ ⎢ ⎥ ⋅⎢ ⎥ \n\ ⎜ ⎢ x - y x + y ⎥ ⎢ x + y x - y ⎥ ⎢ x - y x - y ⎥ ⎟ ⎢ x - y x + y ⎥ ⎢ x + y x - y ⎥ \n\ ⎜ ⎢ ───── ───────⎥ ⎢─────── ───── ⎥ ⎢ ───── ───── ⎥ ⎟ ⎢ ───── ───────⎥ ⎢─────── ───── ⎥ \n\ ⎝ ⎣ x + y x - 2⋅y⎦τ ⎣x - 2⋅y x + y ⎦τ ⎣ x + y x + y ⎦τ⎠ ⎣ x + y x - 2⋅y⎦τ ⎣x - 2⋅y x + y ⎦τ\ """ assert upretty(MIMOFeedback(tfm_1, tfm_2, 1)) == \ expected1 # Positive MIMOFeedback assert upretty(MIMOFeedback(tfm_1*tfm_2, tfm_3)) == \ expected2 # Negative MIMOFeedback (Default) def test_pretty_TransferFunctionMatrix(): tf1 = TransferFunction(x + y, x - 2*y, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(y**2 - 2*y + 1, y + 5, y) tf4 = TransferFunction(y, x**2 + x + 1, y) tf5 = TransferFunction(1 - x, x - y, y) tf6 = TransferFunction(2, 2, y) expected1 = \ """\ ⎡ x + y ⎤ \n\ ⎢───────⎥ \n\ ⎢x - 2⋅y⎥ \n\ ⎢ ⎥ \n\ ⎢ x - y ⎥ \n\ ⎢ ───── ⎥ \n\ ⎣ x + y ⎦τ\ """ expected2 = \ """\ ⎡ x + y ⎤ \n\ ⎢ ─────── ⎥ \n\ ⎢ x - 2⋅y ⎥ \n\ ⎢ ⎥ \n\ ⎢ x - y ⎥ \n\ ⎢ ───── ⎥ \n\ ⎢ x + y ⎥ \n\ ⎢ ⎥ \n\ ⎢ 2 ⎥ \n\ ⎢- y + 2⋅y - 1⎥ \n\ ⎢──────────────⎥ \n\ ⎣ y + 5 ⎦τ\ """ expected3 = \ """\ ⎡ x + y x - y ⎤ \n\ ⎢ ─────── ───── ⎥ \n\ ⎢ x - 2⋅y x + y ⎥ \n\ ⎢ ⎥ \n\ ⎢ 2 ⎥ \n\ ⎢y - 2⋅y + 1 y ⎥ \n\ ⎢──────────── ──────────⎥ \n\ ⎢ y + 5 2 ⎥ \n\ ⎢ x + x + 1⎥ \n\ ⎢ ⎥ \n\ ⎢ 1 - x 2 ⎥ \n\ ⎢ ───── ─ ⎥ \n\ ⎣ x - y 2 ⎦τ\ """ expected4 = \ """\ ⎡ x - y x + y y ⎤ \n\ ⎢ ───── ─────── ──────────⎥ \n\ ⎢ x + y x - 2⋅y 2 ⎥ \n\ ⎢ x + x + 1⎥ \n\ ⎢ ⎥ \n\ ⎢ 2 ⎥ \n\ ⎢- y + 2⋅y - 1 x - 1 -2 ⎥ \n\ ⎢────────────── ───── ─── ⎥ \n\ ⎣ y + 5 x - y 2 ⎦τ\ """ expected5 = \ """\ ⎡ x + y x - y x + y y ⎤ \n\ ⎢───────⋅───── ─────── ──────────⎥ \n\ ⎢x - 2⋅y x + y x - 2⋅y 2 ⎥ \n\ ⎢ x + x + 1⎥ \n\ ⎢ ⎥ \n\ ⎢ 1 - x 2 x + y -2 ⎥ \n\ ⎢ ───── + ─ ─────── ─── ⎥ \n\ ⎣ x - y 2 x - 2⋅y 2 ⎦τ\ """ assert upretty(TransferFunctionMatrix([[tf1], [tf2]])) == expected1 assert upretty(TransferFunctionMatrix([[tf1], [tf2], [-tf3]])) == expected2 assert upretty(TransferFunctionMatrix([[tf1, tf2], [tf3, tf4], [tf5, tf6]])) == expected3 assert upretty(TransferFunctionMatrix([[tf2, tf1, tf4], [-tf3, -tf5, -tf6]])) == expected4 assert upretty(TransferFunctionMatrix([[Series(tf2, tf1), tf1, tf4], [Parallel(tf6, tf5), tf1, -tf6]])) == \ expected5 def test_pretty_order(): expr = O(1) ascii_str = \ """\ O(1)\ """ ucode_str = \ """\ O(1)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = O(1/x) ascii_str = \ """\ /1\\\n\ O|-|\n\ \\x/\ """ ucode_str = \ """\ ⎛1⎞\n\ O⎜─⎟\n\ ⎝x⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = O(x**2 + y**2) ascii_str = \ """\ / 2 2 \\\n\ O\\x + y ; (x, y) -> (0, 0)/\ """ ucode_str = \ """\ ⎛ 2 2 ⎞\n\ O⎝x + y ; (x, y) → (0, 0)⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = O(1, (x, oo)) ascii_str = \ """\ O(1; x -> oo)\ """ ucode_str = \ """\ O(1; x → ∞)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = O(1/x, (x, oo)) ascii_str = \ """\ /1 \\\n\ O|-; x -> oo|\n\ \\x /\ """ ucode_str = \ """\ ⎛1 ⎞\n\ O⎜─; x → ∞⎟\n\ ⎝x ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = O(x**2 + y**2, (x, oo), (y, oo)) ascii_str = \ """\ / 2 2 \\\n\ O\\x + y ; (x, y) -> (oo, oo)/\ """ ucode_str = \ """\ ⎛ 2 2 ⎞\n\ O⎝x + y ; (x, y) → (∞, ∞)⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_derivatives(): # Simple expr = Derivative(log(x), x, evaluate=False) ascii_str = \ """\ d \n\ --(log(x))\n\ dx \ """ ucode_str = \ """\ d \n\ ──(log(x))\n\ dx \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Derivative(log(x), x, evaluate=False) + x ascii_str_1 = \ """\ d \n\ x + --(log(x))\n\ dx \ """ ascii_str_2 = \ """\ d \n\ --(log(x)) + x\n\ dx \ """ ucode_str_1 = \ """\ d \n\ x + ──(log(x))\n\ dx \ """ ucode_str_2 = \ """\ d \n\ ──(log(x)) + x\n\ dx \ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] # basic partial derivatives expr = Derivative(log(x + y) + x, x) ascii_str_1 = \ """\ d \n\ --(log(x + y) + x)\n\ dx \ """ ascii_str_2 = \ """\ d \n\ --(x + log(x + y))\n\ dx \ """ ucode_str_1 = \ """\ ∂ \n\ ──(log(x + y) + x)\n\ ∂x \ """ ucode_str_2 = \ """\ ∂ \n\ ──(x + log(x + y))\n\ ∂x \ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2], upretty(expr) # Multiple symbols expr = Derivative(log(x) + x**2, x, y) ascii_str_1 = \ """\ 2 \n\ d / 2\\\n\ -----\\log(x) + x /\n\ dy dx \ """ ascii_str_2 = \ """\ 2 \n\ d / 2 \\\n\ -----\\x + log(x)/\n\ dy dx \ """ ucode_str_1 = \ """\ 2 \n\ d ⎛ 2⎞\n\ ─────⎝log(x) + x ⎠\n\ dy dx \ """ ucode_str_2 = \ """\ 2 \n\ d ⎛ 2 ⎞\n\ ─────⎝x + log(x)⎠\n\ dy dx \ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Derivative(2*x*y, y, x) + x**2 ascii_str_1 = \ """\ 2 \n\ d 2\n\ -----(2*x*y) + x \n\ dx dy \ """ ascii_str_2 = \ """\ 2 \n\ 2 d \n\ x + -----(2*x*y)\n\ dx dy \ """ ucode_str_1 = \ """\ 2 \n\ ∂ 2\n\ ─────(2⋅x⋅y) + x \n\ ∂x ∂y \ """ ucode_str_2 = \ """\ 2 \n\ 2 ∂ \n\ x + ─────(2⋅x⋅y)\n\ ∂x ∂y \ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Derivative(2*x*y, x, x) ascii_str = \ """\ 2 \n\ d \n\ ---(2*x*y)\n\ 2 \n\ dx \ """ ucode_str = \ """\ 2 \n\ ∂ \n\ ───(2⋅x⋅y)\n\ 2 \n\ ∂x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Derivative(2*x*y, x, 17) ascii_str = \ """\ 17 \n\ d \n\ ----(2*x*y)\n\ 17 \n\ dx \ """ ucode_str = \ """\ 17 \n\ ∂ \n\ ────(2⋅x⋅y)\n\ 17 \n\ ∂x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Derivative(2*x*y, x, x, y) ascii_str = \ """\ 3 \n\ d \n\ ------(2*x*y)\n\ 2 \n\ dy dx \ """ ucode_str = \ """\ 3 \n\ ∂ \n\ ──────(2⋅x⋅y)\n\ 2 \n\ ∂y ∂x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str # Greek letters alpha = Symbol('alpha') beta = Function('beta') expr = beta(alpha).diff(alpha) ascii_str = \ """\ d \n\ ------(beta(alpha))\n\ dalpha \ """ ucode_str = \ """\ d \n\ ──(β(α))\n\ dα \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Derivative(f(x), (x, n)) ascii_str = \ """\ n \n\ d \n\ ---(f(x))\n\ n \n\ dx \ """ ucode_str = \ """\ n \n\ d \n\ ───(f(x))\n\ n \n\ dx \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_integrals(): expr = Integral(log(x), x) ascii_str = \ """\ / \n\ | \n\ | log(x) dx\n\ | \n\ / \ """ ucode_str = \ """\ ⌠ \n\ ⎮ log(x) dx\n\ ⌡ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(x**2, x) ascii_str = \ """\ / \n\ | \n\ | 2 \n\ | x dx\n\ | \n\ / \ """ ucode_str = \ """\ ⌠ \n\ ⎮ 2 \n\ ⎮ x dx\n\ ⌡ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral((sin(x))**2 / (tan(x))**2) ascii_str = \ """\ / \n\ | \n\ | 2 \n\ | sin (x) \n\ | ------- dx\n\ | 2 \n\ | tan (x) \n\ | \n\ / \ """ ucode_str = \ """\ ⌠ \n\ ⎮ 2 \n\ ⎮ sin (x) \n\ ⎮ ─────── dx\n\ ⎮ 2 \n\ ⎮ tan (x) \n\ ⌡ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(x**(2**x), x) ascii_str = \ """\ / \n\ | \n\ | / x\\ \n\ | \\2 / \n\ | x dx\n\ | \n\ / \ """ ucode_str = \ """\ ⌠ \n\ ⎮ ⎛ x⎞ \n\ ⎮ ⎝2 ⎠ \n\ ⎮ x dx\n\ ⌡ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(x**2, (x, 1, 2)) ascii_str = \ """\ 2 \n\ / \n\ | \n\ | 2 \n\ | x dx\n\ | \n\ / \n\ 1 \ """ ucode_str = \ """\ 2 \n\ ⌠ \n\ ⎮ 2 \n\ ⎮ x dx\n\ ⌡ \n\ 1 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(x**2, (x, Rational(1, 2), 10)) ascii_str = \ """\ 10 \n\ / \n\ | \n\ | 2 \n\ | x dx\n\ | \n\ / \n\ 1/2 \ """ ucode_str = \ """\ 10 \n\ ⌠ \n\ ⎮ 2 \n\ ⎮ x dx\n\ ⌡ \n\ 1/2 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(x**2*y**2, x, y) ascii_str = \ """\ / / \n\ | | \n\ | | 2 2 \n\ | | x *y dx dy\n\ | | \n\ / / \ """ ucode_str = \ """\ ⌠ ⌠ \n\ ⎮ ⎮ 2 2 \n\ ⎮ ⎮ x ⋅y dx dy\n\ ⌡ ⌡ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(sin(th)/cos(ph), (th, 0, pi), (ph, 0, 2*pi)) ascii_str = \ """\ 2*pi pi \n\ / / \n\ | | \n\ | | sin(theta) \n\ | | ---------- d(theta) d(phi)\n\ | | cos(phi) \n\ | | \n\ / / \n\ 0 0 \ """ ucode_str = \ """\ 2⋅π π \n\ ⌠ ⌠ \n\ ⎮ ⎮ sin(θ) \n\ ⎮ ⎮ ────── dθ dφ\n\ ⎮ ⎮ cos(φ) \n\ ⌡ ⌡ \n\ 0 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_matrix(): # Empty Matrix expr = Matrix() ascii_str = "[]" unicode_str = "[]" assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str expr = Matrix(2, 0, lambda i, j: 0) ascii_str = "[]" unicode_str = "[]" assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str expr = Matrix(0, 2, lambda i, j: 0) ascii_str = "[]" unicode_str = "[]" assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str expr = Matrix([[x**2 + 1, 1], [y, x + y]]) ascii_str_1 = \ """\ [ 2 ] [1 + x 1 ] [ ] [ y x + y]\ """ ascii_str_2 = \ """\ [ 2 ] [x + 1 1 ] [ ] [ y x + y]\ """ ucode_str_1 = \ """\ ⎡ 2 ⎤ ⎢1 + x 1 ⎥ ⎢ ⎥ ⎣ y x + y⎦\ """ ucode_str_2 = \ """\ ⎡ 2 ⎤ ⎢x + 1 1 ⎥ ⎢ ⎥ ⎣ y x + y⎦\ """ assert pretty(expr) in [ascii_str_1, ascii_str_2] assert upretty(expr) in [ucode_str_1, ucode_str_2] expr = Matrix([[x/y, y, th], [0, exp(I*k*ph), 1]]) ascii_str = \ """\ [x ] [- y theta] [y ] [ ] [ I*k*phi ] [0 e 1 ]\ """ ucode_str = \ """\ ⎡x ⎤ ⎢─ y θ⎥ ⎢y ⎥ ⎢ ⎥ ⎢ ⅈ⋅k⋅φ ⎥ ⎣0 ℯ 1⎦\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str unicode_str = \ """\ ⎡v̇_msc_00 0 0 ⎤ ⎢ ⎥ ⎢ 0 v̇_msc_01 0 ⎥ ⎢ ⎥ ⎣ 0 0 v̇_msc_02⎦\ """ expr = diag(*MatrixSymbol('vdot_msc',1,3)) assert upretty(expr) == unicode_str def test_pretty_ndim_arrays(): x, y, z, w = symbols("x y z w") for ArrayType in (ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableDenseNDimArray, MutableSparseNDimArray): # Basic: scalar array M = ArrayType(x) assert pretty(M) == "x" assert upretty(M) == "x" M = ArrayType([[1/x, y], [z, w]]) M1 = ArrayType([1/x, y, z]) M2 = tensorproduct(M1, M) M3 = tensorproduct(M, M) ascii_str = \ """\ [1 ]\n\ [- y]\n\ [x ]\n\ [ ]\n\ [z w]\ """ ucode_str = \ """\ ⎡1 ⎤\n\ ⎢─ y⎥\n\ ⎢x ⎥\n\ ⎢ ⎥\n\ ⎣z w⎦\ """ assert pretty(M) == ascii_str assert upretty(M) == ucode_str ascii_str = \ """\ [1 ]\n\ [- y z]\n\ [x ]\ """ ucode_str = \ """\ ⎡1 ⎤\n\ ⎢─ y z⎥\n\ ⎣x ⎦\ """ assert pretty(M1) == ascii_str assert upretty(M1) == ucode_str ascii_str = \ """\ [[1 y] ]\n\ [[-- -] [z ]]\n\ [[ 2 x] [ y 2 ] [- y*z]]\n\ [[x ] [ - y ] [x ]]\n\ [[ ] [ x ] [ ]]\n\ [[z w] [ ] [ 2 ]]\n\ [[- -] [y*z w*y] [z w*z]]\n\ [[x x] ]\ """ ucode_str = \ """\ ⎡⎡1 y⎤ ⎤\n\ ⎢⎢── ─⎥ ⎡z ⎤⎥\n\ ⎢⎢ 2 x⎥ ⎡ y 2 ⎤ ⎢─ y⋅z⎥⎥\n\ ⎢⎢x ⎥ ⎢ ─ y ⎥ ⎢x ⎥⎥\n\ ⎢⎢ ⎥ ⎢ x ⎥ ⎢ ⎥⎥\n\ ⎢⎢z w⎥ ⎢ ⎥ ⎢ 2 ⎥⎥\n\ ⎢⎢─ ─⎥ ⎣y⋅z w⋅y⎦ ⎣z w⋅z⎦⎥\n\ ⎣⎣x x⎦ ⎦\ """ assert pretty(M2) == ascii_str assert upretty(M2) == ucode_str ascii_str = \ """\ [ [1 y] ]\n\ [ [-- -] ]\n\ [ [ 2 x] [ y 2 ]]\n\ [ [x ] [ - y ]]\n\ [ [ ] [ x ]]\n\ [ [z w] [ ]]\n\ [ [- -] [y*z w*y]]\n\ [ [x x] ]\n\ [ ]\n\ [[z ] [ w ]]\n\ [[- y*z] [ - w*y]]\n\ [[x ] [ x ]]\n\ [[ ] [ ]]\n\ [[ 2 ] [ 2 ]]\n\ [[z w*z] [w*z w ]]\ """ ucode_str = \ """\ ⎡ ⎡1 y⎤ ⎤\n\ ⎢ ⎢── ─⎥ ⎥\n\ ⎢ ⎢ 2 x⎥ ⎡ y 2 ⎤⎥\n\ ⎢ ⎢x ⎥ ⎢ ─ y ⎥⎥\n\ ⎢ ⎢ ⎥ ⎢ x ⎥⎥\n\ ⎢ ⎢z w⎥ ⎢ ⎥⎥\n\ ⎢ ⎢─ ─⎥ ⎣y⋅z w⋅y⎦⎥\n\ ⎢ ⎣x x⎦ ⎥\n\ ⎢ ⎥\n\ ⎢⎡z ⎤ ⎡ w ⎤⎥\n\ ⎢⎢─ y⋅z⎥ ⎢ ─ w⋅y⎥⎥\n\ ⎢⎢x ⎥ ⎢ x ⎥⎥\n\ ⎢⎢ ⎥ ⎢ ⎥⎥\n\ ⎢⎢ 2 ⎥ ⎢ 2 ⎥⎥\n\ ⎣⎣z w⋅z⎦ ⎣w⋅z w ⎦⎦\ """ assert pretty(M3) == ascii_str assert upretty(M3) == ucode_str Mrow = ArrayType([[x, y, 1 / z]]) Mcolumn = ArrayType([[x], [y], [1 / z]]) Mcol2 = ArrayType([Mcolumn.tolist()]) ascii_str = \ """\ [[ 1]]\n\ [[x y -]]\n\ [[ z]]\ """ ucode_str = \ """\ ⎡⎡ 1⎤⎤\n\ ⎢⎢x y ─⎥⎥\n\ ⎣⎣ z⎦⎦\ """ assert pretty(Mrow) == ascii_str assert upretty(Mrow) == ucode_str ascii_str = \ """\ [x]\n\ [ ]\n\ [y]\n\ [ ]\n\ [1]\n\ [-]\n\ [z]\ """ ucode_str = \ """\ ⎡x⎤\n\ ⎢ ⎥\n\ ⎢y⎥\n\ ⎢ ⎥\n\ ⎢1⎥\n\ ⎢─⎥\n\ ⎣z⎦\ """ assert pretty(Mcolumn) == ascii_str assert upretty(Mcolumn) == ucode_str ascii_str = \ """\ [[x]]\n\ [[ ]]\n\ [[y]]\n\ [[ ]]\n\ [[1]]\n\ [[-]]\n\ [[z]]\ """ ucode_str = \ """\ ⎡⎡x⎤⎤\n\ ⎢⎢ ⎥⎥\n\ ⎢⎢y⎥⎥\n\ ⎢⎢ ⎥⎥\n\ ⎢⎢1⎥⎥\n\ ⎢⎢─⎥⎥\n\ ⎣⎣z⎦⎦\ """ assert pretty(Mcol2) == ascii_str assert upretty(Mcol2) == ucode_str def test_tensor_TensorProduct(): A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) assert upretty(TensorProduct(A, B)) == "A\u2297B" assert upretty(TensorProduct(A, B, A)) == "A\u2297B\u2297A" def test_diffgeom_print_WedgeProduct(): from sympy.diffgeom.rn import R2 from sympy.diffgeom import WedgeProduct wp = WedgeProduct(R2.dx, R2.dy) assert upretty(wp) == "ⅆ x∧ⅆ y" def test_Adjoint(): X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) assert pretty(Adjoint(X)) == " +\nX " assert pretty(Adjoint(X + Y)) == " +\n(X + Y) " assert pretty(Adjoint(X) + Adjoint(Y)) == " + +\nX + Y " assert pretty(Adjoint(X*Y)) == " +\n(X*Y) " assert pretty(Adjoint(Y)*Adjoint(X)) == " + +\nY *X " assert pretty(Adjoint(X**2)) == " +\n/ 2\\ \n\\X / " assert pretty(Adjoint(X)**2) == " 2\n/ +\\ \n\\X / " assert pretty(Adjoint(Inverse(X))) == " +\n/ -1\\ \n\\X / " assert pretty(Inverse(Adjoint(X))) == " -1\n/ +\\ \n\\X / " assert pretty(Adjoint(Transpose(X))) == " +\n/ T\\ \n\\X / " assert pretty(Transpose(Adjoint(X))) == " T\n/ +\\ \n\\X / " assert upretty(Adjoint(X)) == " †\nX " assert upretty(Adjoint(X + Y)) == " †\n(X + Y) " assert upretty(Adjoint(X) + Adjoint(Y)) == " † †\nX + Y " assert upretty(Adjoint(X*Y)) == " †\n(X⋅Y) " assert upretty(Adjoint(Y)*Adjoint(X)) == " † †\nY ⋅X " assert upretty(Adjoint(X**2)) == \ " †\n⎛ 2⎞ \n⎝X ⎠ " assert upretty(Adjoint(X)**2) == \ " 2\n⎛ †⎞ \n⎝X ⎠ " assert upretty(Adjoint(Inverse(X))) == \ " †\n⎛ -1⎞ \n⎝X ⎠ " assert upretty(Inverse(Adjoint(X))) == \ " -1\n⎛ †⎞ \n⎝X ⎠ " assert upretty(Adjoint(Transpose(X))) == \ " †\n⎛ T⎞ \n⎝X ⎠ " assert upretty(Transpose(Adjoint(X))) == \ " T\n⎛ †⎞ \n⎝X ⎠ " def test_pretty_Trace_issue_9044(): X = Matrix([[1, 2], [3, 4]]) Y = Matrix([[2, 4], [6, 8]]) ascii_str_1 = \ """\ /[1 2]\\ tr|[ ]| \\[3 4]/\ """ ucode_str_1 = \ """\ ⎛⎡1 2⎤⎞ tr⎜⎢ ⎥⎟ ⎝⎣3 4⎦⎠\ """ ascii_str_2 = \ """\ /[1 2]\\ /[2 4]\\ tr|[ ]| + tr|[ ]| \\[3 4]/ \\[6 8]/\ """ ucode_str_2 = \ """\ ⎛⎡1 2⎤⎞ ⎛⎡2 4⎤⎞ tr⎜⎢ ⎥⎟ + tr⎜⎢ ⎥⎟ ⎝⎣3 4⎦⎠ ⎝⎣6 8⎦⎠\ """ assert pretty(Trace(X)) == ascii_str_1 assert upretty(Trace(X)) == ucode_str_1 assert pretty(Trace(X) + Trace(Y)) == ascii_str_2 assert upretty(Trace(X) + Trace(Y)) == ucode_str_2 def test_MatrixSlice(): n = Symbol('n', integer=True) x, y, z, w, t, = symbols('x y z w t') X = MatrixSymbol('X', n, n) Y = MatrixSymbol('Y', 10, 10) Z = MatrixSymbol('Z', 10, 10) expr = MatrixSlice(X, (None, None, None), (None, None, None)) assert pretty(expr) == upretty(expr) == 'X[:, :]' expr = X[x:x + 1, y:y + 1] assert pretty(expr) == upretty(expr) == 'X[x:x + 1, y:y + 1]' expr = X[x:x + 1:2, y:y + 1:2] assert pretty(expr) == upretty(expr) == 'X[x:x + 1:2, y:y + 1:2]' expr = X[:x, y:] assert pretty(expr) == upretty(expr) == 'X[:x, y:]' expr = X[:x, y:] assert pretty(expr) == upretty(expr) == 'X[:x, y:]' expr = X[x:, :y] assert pretty(expr) == upretty(expr) == 'X[x:, :y]' expr = X[x:y, z:w] assert pretty(expr) == upretty(expr) == 'X[x:y, z:w]' expr = X[x:y:t, w:t:x] assert pretty(expr) == upretty(expr) == 'X[x:y:t, w:t:x]' expr = X[x::y, t::w] assert pretty(expr) == upretty(expr) == 'X[x::y, t::w]' expr = X[:x:y, :t:w] assert pretty(expr) == upretty(expr) == 'X[:x:y, :t:w]' expr = X[::x, ::y] assert pretty(expr) == upretty(expr) == 'X[::x, ::y]' expr = MatrixSlice(X, (0, None, None), (0, None, None)) assert pretty(expr) == upretty(expr) == 'X[:, :]' expr = MatrixSlice(X, (None, n, None), (None, n, None)) assert pretty(expr) == upretty(expr) == 'X[:, :]' expr = MatrixSlice(X, (0, n, None), (0, n, None)) assert pretty(expr) == upretty(expr) == 'X[:, :]' expr = MatrixSlice(X, (0, n, 2), (0, n, 2)) assert pretty(expr) == upretty(expr) == 'X[::2, ::2]' expr = X[1:2:3, 4:5:6] assert pretty(expr) == upretty(expr) == 'X[1:2:3, 4:5:6]' expr = X[1:3:5, 4:6:8] assert pretty(expr) == upretty(expr) == 'X[1:3:5, 4:6:8]' expr = X[1:10:2] assert pretty(expr) == upretty(expr) == 'X[1:10:2, :]' expr = Y[:5, 1:9:2] assert pretty(expr) == upretty(expr) == 'Y[:5, 1:9:2]' expr = Y[:5, 1:10:2] assert pretty(expr) == upretty(expr) == 'Y[:5, 1::2]' expr = Y[5, :5:2] assert pretty(expr) == upretty(expr) == 'Y[5:6, :5:2]' expr = X[0:1, 0:1] assert pretty(expr) == upretty(expr) == 'X[:1, :1]' expr = X[0:1:2, 0:1:2] assert pretty(expr) == upretty(expr) == 'X[:1:2, :1:2]' expr = (Y + Z)[2:, 2:] assert pretty(expr) == upretty(expr) == '(Y + Z)[2:, 2:]' def test_MatrixExpressions(): n = Symbol('n', integer=True) X = MatrixSymbol('X', n, n) assert pretty(X) == upretty(X) == "X" # Apply function elementwise (`ElementwiseApplyFunc`): expr = (X.T*X).applyfunc(sin) ascii_str = """\ / T \\\n\ (d -> sin(d)).\\X *X/\ """ ucode_str = """\ ⎛ T ⎞\n\ (d ↦ sin(d))˳⎝X ⋅X⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str lamda = Lambda(x, 1/x) expr = (n*X).applyfunc(lamda) ascii_str = """\ / 1\\ \n\ |x -> -|.(n*X)\n\ \\ x/ \ """ ucode_str = """\ ⎛ 1⎞ \n\ ⎜x ↦ ─⎟˳(n⋅X)\n\ ⎝ x⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_dotproduct(): from sympy.matrices import Matrix, MatrixSymbol from sympy.matrices.expressions.dotproduct import DotProduct n = symbols("n", integer=True) A = MatrixSymbol('A', n, 1) B = MatrixSymbol('B', n, 1) C = Matrix(1, 3, [1, 2, 3]) D = Matrix(1, 3, [1, 3, 4]) assert pretty(DotProduct(A, B)) == "A*B" assert pretty(DotProduct(C, D)) == "[1 2 3]*[1 3 4]" assert upretty(DotProduct(A, B)) == "A⋅B" assert upretty(DotProduct(C, D)) == "[1 2 3]⋅[1 3 4]" def test_pretty_piecewise(): expr = Piecewise((x, x < 1), (x**2, True)) ascii_str = \ """\ /x for x < 1\n\ | \n\ < 2 \n\ |x otherwise\n\ \\ \ """ ucode_str = \ """\ ⎧x for x < 1\n\ ⎪ \n\ ⎨ 2 \n\ ⎪x otherwise\n\ ⎩ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -Piecewise((x, x < 1), (x**2, True)) ascii_str = \ """\ //x for x < 1\\\n\ || |\n\ -|< 2 |\n\ ||x otherwise|\n\ \\\\ /\ """ ucode_str = \ """\ ⎛⎧x for x < 1⎞\n\ ⎜⎪ ⎟\n\ -⎜⎨ 2 ⎟\n\ ⎜⎪x otherwise⎟\n\ ⎝⎩ ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = x + Piecewise((x, x > 0), (y, True)) + Piecewise((x/y, x < 2), (y**2, x > 2), (1, True)) + 1 ascii_str = \ """\ //x \\ \n\ ||- for x < 2| \n\ ||y | \n\ //x for x > 0\\ || | \n\ x + |< | + |< 2 | + 1\n\ \\\\y otherwise/ ||y for x > 2| \n\ || | \n\ ||1 otherwise| \n\ \\\\ / \ """ ucode_str = \ """\ ⎛⎧x ⎞ \n\ ⎜⎪─ for x < 2⎟ \n\ ⎜⎪y ⎟ \n\ ⎛⎧x for x > 0⎞ ⎜⎪ ⎟ \n\ x + ⎜⎨ ⎟ + ⎜⎨ 2 ⎟ + 1\n\ ⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟ \n\ ⎜⎪ ⎟ \n\ ⎜⎪1 otherwise⎟ \n\ ⎝⎩ ⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = x - Piecewise((x, x > 0), (y, True)) + Piecewise((x/y, x < 2), (y**2, x > 2), (1, True)) + 1 ascii_str = \ """\ //x \\ \n\ ||- for x < 2| \n\ ||y | \n\ //x for x > 0\\ || | \n\ x - |< | + |< 2 | + 1\n\ \\\\y otherwise/ ||y for x > 2| \n\ || | \n\ ||1 otherwise| \n\ \\\\ / \ """ ucode_str = \ """\ ⎛⎧x ⎞ \n\ ⎜⎪─ for x < 2⎟ \n\ ⎜⎪y ⎟ \n\ ⎛⎧x for x > 0⎞ ⎜⎪ ⎟ \n\ x - ⎜⎨ ⎟ + ⎜⎨ 2 ⎟ + 1\n\ ⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟ \n\ ⎜⎪ ⎟ \n\ ⎜⎪1 otherwise⎟ \n\ ⎝⎩ ⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = x*Piecewise((x, x > 0), (y, True)) ascii_str = \ """\ //x for x > 0\\\n\ x*|< |\n\ \\\\y otherwise/\ """ ucode_str = \ """\ ⎛⎧x for x > 0⎞\n\ x⋅⎜⎨ ⎟\n\ ⎝⎩y otherwise⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Piecewise((x, x > 0), (y, True))*Piecewise((x/y, x < 2), (y**2, x > 2), (1, True)) ascii_str = \ """\ //x \\\n\ ||- for x < 2|\n\ ||y |\n\ //x for x > 0\\ || |\n\ |< |*|< 2 |\n\ \\\\y otherwise/ ||y for x > 2|\n\ || |\n\ ||1 otherwise|\n\ \\\\ /\ """ ucode_str = \ """\ ⎛⎧x ⎞\n\ ⎜⎪─ for x < 2⎟\n\ ⎜⎪y ⎟\n\ ⎛⎧x for x > 0⎞ ⎜⎪ ⎟\n\ ⎜⎨ ⎟⋅⎜⎨ 2 ⎟\n\ ⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟\n\ ⎜⎪ ⎟\n\ ⎜⎪1 otherwise⎟\n\ ⎝⎩ ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -Piecewise((x, x > 0), (y, True))*Piecewise((x/y, x < 2), (y**2, x > 2), (1, True)) ascii_str = \ """\ //x \\\n\ ||- for x < 2|\n\ ||y |\n\ //x for x > 0\\ || |\n\ -|< |*|< 2 |\n\ \\\\y otherwise/ ||y for x > 2|\n\ || |\n\ ||1 otherwise|\n\ \\\\ /\ """ ucode_str = \ """\ ⎛⎧x ⎞\n\ ⎜⎪─ for x < 2⎟\n\ ⎜⎪y ⎟\n\ ⎛⎧x for x > 0⎞ ⎜⎪ ⎟\n\ -⎜⎨ ⎟⋅⎜⎨ 2 ⎟\n\ ⎝⎩y otherwise⎠ ⎜⎪y for x > 2⎟\n\ ⎜⎪ ⎟\n\ ⎜⎪1 otherwise⎟\n\ ⎝⎩ ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Piecewise((0, Abs(1/y) < 1), (1, Abs(y) < 1), (y*meijerg(((2, 1), ()), ((), (1, 0)), 1/y), True)) ascii_str = \ """\ / 1 \n\ | 0 for --- < 1\n\ | |y| \n\ | \n\ < 1 for |y| < 1\n\ | \n\ | __0, 2 /2, 1 | 1\\ \n\ |y*/__ | | -| otherwise \n\ \\ \\_|2, 2 \\ 1, 0 | y/ \ """ ucode_str = \ """\ ⎧ 1 \n\ ⎪ 0 for ─── < 1\n\ ⎪ │y│ \n\ ⎪ \n\ ⎨ 1 for │y│ < 1\n\ ⎪ \n\ ⎪ ╭─╮0, 2 ⎛2, 1 │ 1⎞ \n\ ⎪y⋅│╶┐ ⎜ │ ─⎟ otherwise \n\ ⎩ ╰─╯2, 2 ⎝ 1, 0 │ y⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str # XXX: We have to use evaluate=False here because Piecewise._eval_power # denests the power. expr = Pow(Piecewise((x, x > 0), (y, True)), 2, evaluate=False) ascii_str = \ """\ 2\n\ //x for x > 0\\ \n\ |< | \n\ \\\\y otherwise/ \ """ ucode_str = \ """\ 2\n\ ⎛⎧x for x > 0⎞ \n\ ⎜⎨ ⎟ \n\ ⎝⎩y otherwise⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_ITE(): expr = ITE(x, y, z) assert pretty(expr) == ( '/y for x \n' '< \n' '\\z otherwise' ) assert upretty(expr) == """\ ⎧y for x \n\ ⎨ \n\ ⎩z otherwise\ """ def test_pretty_seq(): expr = () ascii_str = \ """\ ()\ """ ucode_str = \ """\ ()\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = [] ascii_str = \ """\ []\ """ ucode_str = \ """\ []\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = {} expr_2 = {} ascii_str = \ """\ {}\ """ ucode_str = \ """\ {}\ """ assert pretty(expr) == ascii_str assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str expr = (1/x,) ascii_str = \ """\ 1 \n\ (-,)\n\ x \ """ ucode_str = \ """\ ⎛1 ⎞\n\ ⎜─,⎟\n\ ⎝x ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = [x**2, 1/x, x, y, sin(th)**2/cos(ph)**2] ascii_str = \ """\ 2 \n\ 2 1 sin (theta) \n\ [x , -, x, y, -----------]\n\ x 2 \n\ cos (phi) \ """ ucode_str = \ """\ ⎡ 2 ⎤\n\ ⎢ 2 1 sin (θ)⎥\n\ ⎢x , ─, x, y, ───────⎥\n\ ⎢ x 2 ⎥\n\ ⎣ cos (φ)⎦\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2, 1/x, x, y, sin(th)**2/cos(ph)**2) ascii_str = \ """\ 2 \n\ 2 1 sin (theta) \n\ (x , -, x, y, -----------)\n\ x 2 \n\ cos (phi) \ """ ucode_str = \ """\ ⎛ 2 ⎞\n\ ⎜ 2 1 sin (θ)⎟\n\ ⎜x , ─, x, y, ───────⎟\n\ ⎜ x 2 ⎟\n\ ⎝ cos (φ)⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Tuple(x**2, 1/x, x, y, sin(th)**2/cos(ph)**2) ascii_str = \ """\ 2 \n\ 2 1 sin (theta) \n\ (x , -, x, y, -----------)\n\ x 2 \n\ cos (phi) \ """ ucode_str = \ """\ ⎛ 2 ⎞\n\ ⎜ 2 1 sin (θ)⎟\n\ ⎜x , ─, x, y, ───────⎟\n\ ⎜ x 2 ⎟\n\ ⎝ cos (φ)⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = {x: sin(x)} expr_2 = Dict({x: sin(x)}) ascii_str = \ """\ {x: sin(x)}\ """ ucode_str = \ """\ {x: sin(x)}\ """ assert pretty(expr) == ascii_str assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str expr = {1/x: 1/y, x: sin(x)**2} expr_2 = Dict({1/x: 1/y, x: sin(x)**2}) ascii_str = \ """\ 1 1 2 \n\ {-: -, x: sin (x)}\n\ x y \ """ ucode_str = \ """\ ⎧1 1 2 ⎫\n\ ⎨─: ─, x: sin (x)⎬\n\ ⎩x y ⎭\ """ assert pretty(expr) == ascii_str assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str # There used to be a bug with pretty-printing sequences of even height. expr = [x**2] ascii_str = \ """\ 2 \n\ [x ]\ """ ucode_str = \ """\ ⎡ 2⎤\n\ ⎣x ⎦\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (x**2,) ascii_str = \ """\ 2 \n\ (x ,)\ """ ucode_str = \ """\ ⎛ 2 ⎞\n\ ⎝x ,⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Tuple(x**2) ascii_str = \ """\ 2 \n\ (x ,)\ """ ucode_str = \ """\ ⎛ 2 ⎞\n\ ⎝x ,⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = {x**2: 1} expr_2 = Dict({x**2: 1}) ascii_str = \ """\ 2 \n\ {x : 1}\ """ ucode_str = \ """\ ⎧ 2 ⎫\n\ ⎨x : 1⎬\n\ ⎩ ⎭\ """ assert pretty(expr) == ascii_str assert pretty(expr_2) == ascii_str assert upretty(expr) == ucode_str assert upretty(expr_2) == ucode_str def test_any_object_in_sequence(): # Cf. issue 5306 b1 = Basic() b2 = Basic(Basic()) expr = [b2, b1] assert pretty(expr) == "[Basic(Basic()), Basic()]" assert upretty(expr) == "[Basic(Basic()), Basic()]" expr = {b2, b1} assert pretty(expr) == "{Basic(), Basic(Basic())}" assert upretty(expr) == "{Basic(), Basic(Basic())}" expr = {b2: b1, b1: b2} expr2 = Dict({b2: b1, b1: b2}) assert pretty(expr) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" assert pretty( expr2) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" assert upretty( expr) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" assert upretty( expr2) == "{Basic(): Basic(Basic()), Basic(Basic()): Basic()}" def test_print_builtin_set(): assert pretty(set()) == 'set()' assert upretty(set()) == 'set()' assert pretty(frozenset()) == 'frozenset()' assert upretty(frozenset()) == 'frozenset()' s1 = {1/x, x} s2 = frozenset(s1) assert pretty(s1) == \ """\ 1 \n\ {-, x} x \ """ assert upretty(s1) == \ """\ ⎧1 ⎫ ⎨─, x⎬ ⎩x ⎭\ """ assert pretty(s2) == \ """\ 1 \n\ frozenset({-, x}) x \ """ assert upretty(s2) == \ """\ ⎛⎧1 ⎫⎞ frozenset⎜⎨─, x⎬⎟ ⎝⎩x ⎭⎠\ """ def test_pretty_sets(): s = FiniteSet assert pretty(s(*[x*y, x**2])) == \ """\ 2 \n\ {x , x*y}\ """ assert pretty(s(*range(1, 6))) == "{1, 2, 3, 4, 5}" assert pretty(s(*range(1, 13))) == "{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}" assert pretty({x*y, x**2}) == \ """\ 2 \n\ {x , x*y}\ """ assert pretty(set(range(1, 6))) == "{1, 2, 3, 4, 5}" assert pretty(set(range(1, 13))) == \ "{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}" assert pretty(frozenset([x*y, x**2])) == \ """\ 2 \n\ frozenset({x , x*y})\ """ assert pretty(frozenset(range(1, 6))) == "frozenset({1, 2, 3, 4, 5})" assert pretty(frozenset(range(1, 13))) == \ "frozenset({1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12})" assert pretty(Range(0, 3, 1)) == '{0, 1, 2}' ascii_str = '{0, 1, ..., 29}' ucode_str = '{0, 1, …, 29}' assert pretty(Range(0, 30, 1)) == ascii_str assert upretty(Range(0, 30, 1)) == ucode_str ascii_str = '{30, 29, ..., 2}' ucode_str = '{30, 29, …, 2}' assert pretty(Range(30, 1, -1)) == ascii_str assert upretty(Range(30, 1, -1)) == ucode_str ascii_str = '{0, 2, ...}' ucode_str = '{0, 2, …}' assert pretty(Range(0, oo, 2)) == ascii_str assert upretty(Range(0, oo, 2)) == ucode_str ascii_str = '{..., 2, 0}' ucode_str = '{…, 2, 0}' assert pretty(Range(oo, -2, -2)) == ascii_str assert upretty(Range(oo, -2, -2)) == ucode_str ascii_str = '{-2, -3, ...}' ucode_str = '{-2, -3, …}' assert pretty(Range(-2, -oo, -1)) == ascii_str assert upretty(Range(-2, -oo, -1)) == ucode_str def test_pretty_SetExpr(): iv = Interval(1, 3) se = SetExpr(iv) ascii_str = "SetExpr([1, 3])" ucode_str = "SetExpr([1, 3])" assert pretty(se) == ascii_str assert upretty(se) == ucode_str def test_pretty_ImageSet(): imgset = ImageSet(Lambda((x, y), x + y), {1, 2, 3}, {3, 4}) ascii_str = '{x + y | x in {1, 2, 3}, y in {3, 4}}' ucode_str = '{x + y │ x ∊ {1, 2, 3}, y ∊ {3, 4}}' assert pretty(imgset) == ascii_str assert upretty(imgset) == ucode_str imgset = ImageSet(Lambda(((x, y),), x + y), ProductSet({1, 2, 3}, {3, 4})) ascii_str = '{x + y | (x, y) in {1, 2, 3} x {3, 4}}' ucode_str = '{x + y │ (x, y) ∊ {1, 2, 3} × {3, 4}}' assert pretty(imgset) == ascii_str assert upretty(imgset) == ucode_str imgset = ImageSet(Lambda(x, x**2), S.Naturals) ascii_str = '''\ 2 \n\ {x | x in Naturals}''' ucode_str = '''\ ⎧ 2 │ ⎫\n\ ⎨x │ x ∊ ℕ⎬\n\ ⎩ │ ⎭''' assert pretty(imgset) == ascii_str assert upretty(imgset) == ucode_str # TODO: The "x in N" parts below should be centered independently of the # 1/x**2 fraction imgset = ImageSet(Lambda(x, 1/x**2), S.Naturals) ascii_str = '''\ 1 \n\ {-- | x in Naturals} 2 \n\ x ''' ucode_str = '''\ ⎧1 │ ⎫\n\ ⎪── │ x ∊ ℕ⎪\n\ ⎨ 2 │ ⎬\n\ ⎪x │ ⎪\n\ ⎩ │ ⎭''' assert pretty(imgset) == ascii_str assert upretty(imgset) == ucode_str imgset = ImageSet(Lambda((x, y), 1/(x + y)**2), S.Naturals, S.Naturals) ascii_str = '''\ 1 \n\ {-------- | x in Naturals, y in Naturals} 2 \n\ (x + y) ''' ucode_str = '''\ ⎧ 1 │ ⎫ ⎪──────── │ x ∊ ℕ, y ∊ ℕ⎪ ⎨ 2 │ ⎬ ⎪(x + y) │ ⎪ ⎩ │ ⎭''' assert pretty(imgset) == ascii_str assert upretty(imgset) == ucode_str def test_pretty_ConditionSet(): from sympy import ConditionSet ascii_str = '{x | x in (-oo, oo) and sin(x) = 0}' ucode_str = '{x │ x ∊ ℝ ∧ (sin(x) = 0)}' assert pretty(ConditionSet(x, Eq(sin(x), 0), S.Reals)) == ascii_str assert upretty(ConditionSet(x, Eq(sin(x), 0), S.Reals)) == ucode_str assert pretty(ConditionSet(x, Contains(x, S.Reals, evaluate=False), FiniteSet(1))) == '{1}' assert upretty(ConditionSet(x, Contains(x, S.Reals, evaluate=False), FiniteSet(1))) == '{1}' assert pretty(ConditionSet(x, And(x > 1, x < -1), FiniteSet(1, 2, 3))) == "EmptySet" assert upretty(ConditionSet(x, And(x > 1, x < -1), FiniteSet(1, 2, 3))) == "∅" assert pretty(ConditionSet(x, Or(x > 1, x < -1), FiniteSet(1, 2))) == '{2}' assert upretty(ConditionSet(x, Or(x > 1, x < -1), FiniteSet(1, 2))) == '{2}' condset = ConditionSet(x, 1/x**2 > 0) ascii_str = '''\ 1 \n\ {x | -- > 0} 2 \n\ x ''' ucode_str = '''\ ⎧ │ ⎛1 ⎞⎫ ⎪x │ ⎜── > 0⎟⎪ ⎨ │ ⎜ 2 ⎟⎬ ⎪ │ ⎝x ⎠⎪ ⎩ │ ⎭''' assert pretty(condset) == ascii_str assert upretty(condset) == ucode_str condset = ConditionSet(x, 1/x**2 > 0, S.Reals) ascii_str = '''\ 1 \n\ {x | x in (-oo, oo) and -- > 0} 2 \n\ x ''' ucode_str = '''\ ⎧ │ ⎛1 ⎞⎫ ⎪x │ x ∊ ℝ ∧ ⎜── > 0⎟⎪ ⎨ │ ⎜ 2 ⎟⎬ ⎪ │ ⎝x ⎠⎪ ⎩ │ ⎭''' assert pretty(condset) == ascii_str assert upretty(condset) == ucode_str def test_pretty_ComplexRegion(): from sympy import ComplexRegion cregion = ComplexRegion(Interval(3, 5)*Interval(4, 6)) ascii_str = '{x + y*I | x, y in [3, 5] x [4, 6]}' ucode_str = '{x + y⋅ⅈ │ x, y ∊ [3, 5] × [4, 6]}' assert pretty(cregion) == ascii_str assert upretty(cregion) == ucode_str cregion = ComplexRegion(Interval(0, 1)*Interval(0, 2*pi), polar=True) ascii_str = '{r*(I*sin(theta) + cos(theta)) | r, theta in [0, 1] x [0, 2*pi)}' ucode_str = '{r⋅(ⅈ⋅sin(θ) + cos(θ)) │ r, θ ∊ [0, 1] × [0, 2⋅π)}' assert pretty(cregion) == ascii_str assert upretty(cregion) == ucode_str cregion = ComplexRegion(Interval(3, 1/a**2)*Interval(4, 6)) ascii_str = '''\ 1 \n\ {x + y*I | x, y in [3, --] x [4, 6]} 2 \n\ a ''' ucode_str = '''\ ⎧ │ ⎡ 1 ⎤ ⎫ ⎪x + y⋅ⅈ │ x, y ∊ ⎢3, ──⎥ × [4, 6]⎪ ⎨ │ ⎢ 2⎥ ⎬ ⎪ │ ⎣ a ⎦ ⎪ ⎩ │ ⎭''' assert pretty(cregion) == ascii_str assert upretty(cregion) == ucode_str cregion = ComplexRegion(Interval(0, 1/a**2)*Interval(0, 2*pi), polar=True) ascii_str = '''\ 1 \n\ {r*(I*sin(theta) + cos(theta)) | r, theta in [0, --] x [0, 2*pi)} 2 \n\ a ''' ucode_str = '''\ ⎧ │ ⎡ 1 ⎤ ⎫ ⎪r⋅(ⅈ⋅sin(θ) + cos(θ)) │ r, θ ∊ ⎢0, ──⎥ × [0, 2⋅π)⎪ ⎨ │ ⎢ 2⎥ ⎬ ⎪ │ ⎣ a ⎦ ⎪ ⎩ │ ⎭''' assert pretty(cregion) == ascii_str assert upretty(cregion) == ucode_str def test_pretty_Union_issue_10414(): a, b = Interval(2, 3), Interval(4, 7) ucode_str = '[2, 3] ∪ [4, 7]' ascii_str = '[2, 3] U [4, 7]' assert upretty(Union(a, b)) == ucode_str assert pretty(Union(a, b)) == ascii_str def test_pretty_Intersection_issue_10414(): x, y, z, w = symbols('x, y, z, w') a, b = Interval(x, y), Interval(z, w) ucode_str = '[x, y] ∩ [z, w]' ascii_str = '[x, y] n [z, w]' assert upretty(Intersection(a, b)) == ucode_str assert pretty(Intersection(a, b)) == ascii_str def test_ProductSet_exponent(): ucode_str = ' 1\n[0, 1] ' assert upretty(Interval(0, 1)**1) == ucode_str ucode_str = ' 2\n[0, 1] ' assert upretty(Interval(0, 1)**2) == ucode_str def test_ProductSet_parenthesis(): ucode_str = '([4, 7] × {1, 2}) ∪ ([2, 3] × [4, 7])' a, b = Interval(2, 3), Interval(4, 7) assert upretty(Union(a*b, b*FiniteSet(1, 2))) == ucode_str def test_ProductSet_prod_char_issue_10413(): ascii_str = '[2, 3] x [4, 7]' ucode_str = '[2, 3] × [4, 7]' a, b = Interval(2, 3), Interval(4, 7) assert pretty(a*b) == ascii_str assert upretty(a*b) == ucode_str def test_pretty_sequences(): s1 = SeqFormula(a**2, (0, oo)) s2 = SeqPer((1, 2)) ascii_str = '[0, 1, 4, 9, ...]' ucode_str = '[0, 1, 4, 9, …]' assert pretty(s1) == ascii_str assert upretty(s1) == ucode_str ascii_str = '[1, 2, 1, 2, ...]' ucode_str = '[1, 2, 1, 2, …]' assert pretty(s2) == ascii_str assert upretty(s2) == ucode_str s3 = SeqFormula(a**2, (0, 2)) s4 = SeqPer((1, 2), (0, 2)) ascii_str = '[0, 1, 4]' ucode_str = '[0, 1, 4]' assert pretty(s3) == ascii_str assert upretty(s3) == ucode_str ascii_str = '[1, 2, 1]' ucode_str = '[1, 2, 1]' assert pretty(s4) == ascii_str assert upretty(s4) == ucode_str s5 = SeqFormula(a**2, (-oo, 0)) s6 = SeqPer((1, 2), (-oo, 0)) ascii_str = '[..., 9, 4, 1, 0]' ucode_str = '[…, 9, 4, 1, 0]' assert pretty(s5) == ascii_str assert upretty(s5) == ucode_str ascii_str = '[..., 2, 1, 2, 1]' ucode_str = '[…, 2, 1, 2, 1]' assert pretty(s6) == ascii_str assert upretty(s6) == ucode_str ascii_str = '[1, 3, 5, 11, ...]' ucode_str = '[1, 3, 5, 11, …]' assert pretty(SeqAdd(s1, s2)) == ascii_str assert upretty(SeqAdd(s1, s2)) == ucode_str ascii_str = '[1, 3, 5]' ucode_str = '[1, 3, 5]' assert pretty(SeqAdd(s3, s4)) == ascii_str assert upretty(SeqAdd(s3, s4)) == ucode_str ascii_str = '[..., 11, 5, 3, 1]' ucode_str = '[…, 11, 5, 3, 1]' assert pretty(SeqAdd(s5, s6)) == ascii_str assert upretty(SeqAdd(s5, s6)) == ucode_str ascii_str = '[0, 2, 4, 18, ...]' ucode_str = '[0, 2, 4, 18, …]' assert pretty(SeqMul(s1, s2)) == ascii_str assert upretty(SeqMul(s1, s2)) == ucode_str ascii_str = '[0, 2, 4]' ucode_str = '[0, 2, 4]' assert pretty(SeqMul(s3, s4)) == ascii_str assert upretty(SeqMul(s3, s4)) == ucode_str ascii_str = '[..., 18, 4, 2, 0]' ucode_str = '[…, 18, 4, 2, 0]' assert pretty(SeqMul(s5, s6)) == ascii_str assert upretty(SeqMul(s5, s6)) == ucode_str # Sequences with symbolic limits, issue 12629 s7 = SeqFormula(a**2, (a, 0, x)) raises(NotImplementedError, lambda: pretty(s7)) raises(NotImplementedError, lambda: upretty(s7)) b = Symbol('b') s8 = SeqFormula(b*a**2, (a, 0, 2)) ascii_str = '[0, b, 4*b]' ucode_str = '[0, b, 4⋅b]' assert pretty(s8) == ascii_str assert upretty(s8) == ucode_str def test_pretty_FourierSeries(): f = fourier_series(x, (x, -pi, pi)) ascii_str = \ """\ 2*sin(3*x) \n\ 2*sin(x) - sin(2*x) + ---------- + ...\n\ 3 \ """ ucode_str = \ """\ 2⋅sin(3⋅x) \n\ 2⋅sin(x) - sin(2⋅x) + ────────── + …\n\ 3 \ """ assert pretty(f) == ascii_str assert upretty(f) == ucode_str def test_pretty_FormalPowerSeries(): f = fps(log(1 + x)) ascii_str = \ """\ oo \n\ ____ \n\ \\ ` \n\ \\ -k k \n\ \\ -(-1) *x \n\ / -----------\n\ / k \n\ /___, \n\ k = 1 \ """ ucode_str = \ """\ ∞ \n\ ____ \n\ ╲ \n\ ╲ -k k \n\ ╲ -(-1) ⋅x \n\ ╱ ───────────\n\ ╱ k \n\ ╱ \n\ ‾‾‾‾ \n\ k = 1 \ """ assert pretty(f) == ascii_str assert upretty(f) == ucode_str def test_pretty_limits(): expr = Limit(x, x, oo) ascii_str = \ """\ lim x\n\ x->oo \ """ ucode_str = \ """\ lim x\n\ x─→∞ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(x**2, x, 0) ascii_str = \ """\ 2\n\ lim x \n\ x->0+ \ """ ucode_str = \ """\ 2\n\ lim x \n\ x─→0⁺ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(1/x, x, 0) ascii_str = \ """\ 1\n\ lim -\n\ x->0+x\ """ ucode_str = \ """\ 1\n\ lim ─\n\ x─→0⁺x\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(sin(x)/x, x, 0) ascii_str = \ """\ /sin(x)\\\n\ lim |------|\n\ x->0+\\ x /\ """ ucode_str = \ """\ ⎛sin(x)⎞\n\ lim ⎜──────⎟\n\ x─→0⁺⎝ x ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(sin(x)/x, x, 0, "-") ascii_str = \ """\ /sin(x)\\\n\ lim |------|\n\ x->0-\\ x /\ """ ucode_str = \ """\ ⎛sin(x)⎞\n\ lim ⎜──────⎟\n\ x─→0⁻⎝ x ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(x + sin(x), x, 0) ascii_str = \ """\ lim (x + sin(x))\n\ x->0+ \ """ ucode_str = \ """\ lim (x + sin(x))\n\ x─→0⁺ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(x, x, 0)**2 ascii_str = \ """\ 2\n\ / lim x\\ \n\ \\x->0+ / \ """ ucode_str = \ """\ 2\n\ ⎛ lim x⎞ \n\ ⎝x─→0⁺ ⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(x*Limit(y/2,y,0), x, 0) ascii_str = \ """\ / /y\\\\\n\ lim |x* lim |-||\n\ x->0+\\ y->0+\\2//\ """ ucode_str = \ """\ ⎛ ⎛y⎞⎞\n\ lim ⎜x⋅ lim ⎜─⎟⎟\n\ x─→0⁺⎝ y─→0⁺⎝2⎠⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = 2*Limit(x*Limit(y/2,y,0), x, 0) ascii_str = \ """\ / /y\\\\\n\ 2* lim |x* lim |-||\n\ x->0+\\ y->0+\\2//\ """ ucode_str = \ """\ ⎛ ⎛y⎞⎞\n\ 2⋅ lim ⎜x⋅ lim ⎜─⎟⎟\n\ x─→0⁺⎝ y─→0⁺⎝2⎠⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Limit(sin(x), x, 0, dir='+-') ascii_str = \ """\ lim sin(x)\n\ x->0 \ """ ucode_str = \ """\ lim sin(x)\n\ x─→0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_ComplexRootOf(): expr = rootof(x**5 + 11*x - 2, 0) ascii_str = \ """\ / 5 \\\n\ CRootOf\\x + 11*x - 2, 0/\ """ ucode_str = \ """\ ⎛ 5 ⎞\n\ CRootOf⎝x + 11⋅x - 2, 0⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_RootSum(): expr = RootSum(x**5 + 11*x - 2, auto=False) ascii_str = \ """\ / 5 \\\n\ RootSum\\x + 11*x - 2/\ """ ucode_str = \ """\ ⎛ 5 ⎞\n\ RootSum⎝x + 11⋅x - 2⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = RootSum(x**5 + 11*x - 2, Lambda(z, exp(z))) ascii_str = \ """\ / 5 z\\\n\ RootSum\\x + 11*x - 2, z -> e /\ """ ucode_str = \ """\ ⎛ 5 z⎞\n\ RootSum⎝x + 11⋅x - 2, z ↦ ℯ ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_GroebnerBasis(): expr = groebner([], x, y) ascii_str = \ """\ GroebnerBasis([], x, y, domain=ZZ, order=lex)\ """ ucode_str = \ """\ GroebnerBasis([], x, y, domain=ℤ, order=lex)\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str F = [x**2 - 3*y - x + 1, y**2 - 2*x + y - 1] expr = groebner(F, x, y, order='grlex') ascii_str = \ """\ /[ 2 2 ] \\\n\ GroebnerBasis\\[x - x - 3*y + 1, y - 2*x + y - 1], x, y, domain=ZZ, order=grlex/\ """ ucode_str = \ """\ ⎛⎡ 2 2 ⎤ ⎞\n\ GroebnerBasis⎝⎣x - x - 3⋅y + 1, y - 2⋅x + y - 1⎦, x, y, domain=ℤ, order=grlex⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = expr.fglm('lex') ascii_str = \ """\ /[ 2 4 3 2 ] \\\n\ GroebnerBasis\\[2*x - y - y + 1, y + 2*y - 3*y - 16*y + 7], x, y, domain=ZZ, order=lex/\ """ ucode_str = \ """\ ⎛⎡ 2 4 3 2 ⎤ ⎞\n\ GroebnerBasis⎝⎣2⋅x - y - y + 1, y + 2⋅y - 3⋅y - 16⋅y + 7⎦, x, y, domain=ℤ, order=lex⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_UniversalSet(): assert pretty(S.UniversalSet) == "UniversalSet" assert upretty(S.UniversalSet) == '𝕌' def test_pretty_Boolean(): expr = Not(x, evaluate=False) assert pretty(expr) == "Not(x)" assert upretty(expr) == "¬x" expr = And(x, y) assert pretty(expr) == "And(x, y)" assert upretty(expr) == "x ∧ y" expr = Or(x, y) assert pretty(expr) == "Or(x, y)" assert upretty(expr) == "x ∨ y" syms = symbols('a:f') expr = And(*syms) assert pretty(expr) == "And(a, b, c, d, e, f)" assert upretty(expr) == "a ∧ b ∧ c ∧ d ∧ e ∧ f" expr = Or(*syms) assert pretty(expr) == "Or(a, b, c, d, e, f)" assert upretty(expr) == "a ∨ b ∨ c ∨ d ∨ e ∨ f" expr = Xor(x, y, evaluate=False) assert pretty(expr) == "Xor(x, y)" assert upretty(expr) == "x ⊻ y" expr = Nand(x, y, evaluate=False) assert pretty(expr) == "Nand(x, y)" assert upretty(expr) == "x ⊼ y" expr = Nor(x, y, evaluate=False) assert pretty(expr) == "Nor(x, y)" assert upretty(expr) == "x ⊽ y" expr = Implies(x, y, evaluate=False) assert pretty(expr) == "Implies(x, y)" assert upretty(expr) == "x → y" # don't sort args expr = Implies(y, x, evaluate=False) assert pretty(expr) == "Implies(y, x)" assert upretty(expr) == "y → x" expr = Equivalent(x, y, evaluate=False) assert pretty(expr) == "Equivalent(x, y)" assert upretty(expr) == "x ⇔ y" expr = Equivalent(y, x, evaluate=False) assert pretty(expr) == "Equivalent(x, y)" assert upretty(expr) == "x ⇔ y" def test_pretty_Domain(): expr = FF(23) assert pretty(expr) == "GF(23)" assert upretty(expr) == "ℤ₂₃" expr = ZZ assert pretty(expr) == "ZZ" assert upretty(expr) == "ℤ" expr = QQ assert pretty(expr) == "QQ" assert upretty(expr) == "ℚ" expr = RR assert pretty(expr) == "RR" assert upretty(expr) == "ℝ" expr = QQ[x] assert pretty(expr) == "QQ[x]" assert upretty(expr) == "ℚ[x]" expr = QQ[x, y] assert pretty(expr) == "QQ[x, y]" assert upretty(expr) == "ℚ[x, y]" expr = ZZ.frac_field(x) assert pretty(expr) == "ZZ(x)" assert upretty(expr) == "ℤ(x)" expr = ZZ.frac_field(x, y) assert pretty(expr) == "ZZ(x, y)" assert upretty(expr) == "ℤ(x, y)" expr = QQ.poly_ring(x, y, order=grlex) assert pretty(expr) == "QQ[x, y, order=grlex]" assert upretty(expr) == "ℚ[x, y, order=grlex]" expr = QQ.poly_ring(x, y, order=ilex) assert pretty(expr) == "QQ[x, y, order=ilex]" assert upretty(expr) == "ℚ[x, y, order=ilex]" def test_pretty_prec(): assert xpretty(S("0.3"), full_prec=True, wrap_line=False) == "0.300000000000000" assert xpretty(S("0.3"), full_prec="auto", wrap_line=False) == "0.300000000000000" assert xpretty(S("0.3"), full_prec=False, wrap_line=False) == "0.3" assert xpretty(S("0.3")*x, full_prec=True, use_unicode=False, wrap_line=False) in [ "0.300000000000000*x", "x*0.300000000000000" ] assert xpretty(S("0.3")*x, full_prec="auto", use_unicode=False, wrap_line=False) in [ "0.3*x", "x*0.3" ] assert xpretty(S("0.3")*x, full_prec=False, use_unicode=False, wrap_line=False) in [ "0.3*x", "x*0.3" ] def test_pprint(): import sys from io import StringIO fd = StringIO() sso = sys.stdout sys.stdout = fd try: pprint(pi, use_unicode=False, wrap_line=False) finally: sys.stdout = sso assert fd.getvalue() == 'pi\n' def test_pretty_class(): """Test that the printer dispatcher correctly handles classes.""" class C: pass # C has no .__class__ and this was causing problems class D: pass assert pretty( C ) == str( C ) assert pretty( D ) == str( D ) def test_pretty_no_wrap_line(): huge_expr = 0 for i in range(20): huge_expr += i*sin(i + x) assert xpretty(huge_expr ).find('\n') != -1 assert xpretty(huge_expr, wrap_line=False).find('\n') == -1 def test_settings(): raises(TypeError, lambda: pretty(S(4), method="garbage")) def test_pretty_sum(): from sympy.abc import x, a, b, k, m, n expr = Sum(k**k, (k, 0, n)) ascii_str = \ """\ n \n\ ___ \n\ \\ ` \n\ \\ k\n\ / k \n\ /__, \n\ k = 0 \ """ ucode_str = \ """\ n \n\ ___ \n\ ╲ \n\ ╲ k\n\ ╱ k \n\ ╱ \n\ ‾‾‾ \n\ k = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(k**k, (k, oo, n)) ascii_str = \ """\ n \n\ ___ \n\ \\ ` \n\ \\ k\n\ / k \n\ /__, \n\ k = oo \ """ ucode_str = \ """\ n \n\ ___ \n\ ╲ \n\ ╲ k\n\ ╱ k \n\ ╱ \n\ ‾‾‾ \n\ k = ∞ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(k**(Integral(x**n, (x, -oo, oo))), (k, 0, n**n)) ascii_str = \ """\ n \n\ n \n\ ______ \n\ \\ ` \n\ \\ oo \n\ \\ / \n\ \\ | \n\ \\ | n \n\ ) | x dx\n\ / | \n\ / / \n\ / -oo \n\ / k \n\ /_____, \n\ k = 0 \ """ ucode_str = \ """\ n \n\ n \n\ ______ \n\ ╲ \n\ ╲ \n\ ╲ ∞ \n\ ╲ ⌠ \n\ ╲ ⎮ n \n\ ╱ ⎮ x dx\n\ ╱ ⌡ \n\ ╱ -∞ \n\ ╱ k \n\ ╱ \n\ ‾‾‾‾‾‾ \n\ k = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(k**( Integral(x**n, (x, -oo, oo))), (k, 0, Integral(x**x, (x, -oo, oo)))) ascii_str = \ """\ oo \n\ / \n\ | \n\ | x \n\ | x dx \n\ | \n\ / \n\ -oo \n\ ______ \n\ \\ ` \n\ \\ oo \n\ \\ / \n\ \\ | \n\ \\ | n \n\ ) | x dx\n\ / | \n\ / / \n\ / -oo \n\ / k \n\ /_____, \n\ k = 0 \ """ ucode_str = \ """\ ∞ \n\ ⌠ \n\ ⎮ x \n\ ⎮ x dx \n\ ⌡ \n\ -∞ \n\ ______ \n\ ╲ \n\ ╲ \n\ ╲ ∞ \n\ ╲ ⌠ \n\ ╲ ⎮ n \n\ ╱ ⎮ x dx\n\ ╱ ⌡ \n\ ╱ -∞ \n\ ╱ k \n\ ╱ \n\ ‾‾‾‾‾‾ \n\ k = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(k**(Integral(x**n, (x, -oo, oo))), ( k, x + n + x**2 + n**2 + (x/n) + (1/x), Integral(x**x, (x, -oo, oo)))) ascii_str = \ """\ oo \n\ / \n\ | \n\ | x \n\ | x dx \n\ | \n\ / \n\ -oo \n\ ______ \n\ \\ ` \n\ \\ oo \n\ \\ / \n\ \\ | \n\ \\ | n \n\ ) | x dx\n\ / | \n\ / / \n\ / -oo \n\ / k \n\ /_____, \n\ 2 2 1 x \n\ k = n + n + x + x + - + - \n\ x n \ """ ucode_str = \ """\ ∞ \n\ ⌠ \n\ ⎮ x \n\ ⎮ x dx \n\ ⌡ \n\ -∞ \n\ ______ \n\ ╲ \n\ ╲ \n\ ╲ ∞ \n\ ╲ ⌠ \n\ ╲ ⎮ n \n\ ╱ ⎮ x dx\n\ ╱ ⌡ \n\ ╱ -∞ \n\ ╱ k \n\ ╱ \n\ ‾‾‾‾‾‾ \n\ 2 2 1 x \n\ k = n + n + x + x + ─ + ─ \n\ x n \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(k**( Integral(x**n, (x, -oo, oo))), (k, 0, x + n + x**2 + n**2 + (x/n) + (1/x))) ascii_str = \ """\ 2 2 1 x \n\ n + n + x + x + - + - \n\ x n \n\ ______ \n\ \\ ` \n\ \\ oo \n\ \\ / \n\ \\ | \n\ \\ | n \n\ ) | x dx\n\ / | \n\ / / \n\ / -oo \n\ / k \n\ /_____, \n\ k = 0 \ """ ucode_str = \ """\ 2 2 1 x \n\ n + n + x + x + ─ + ─ \n\ x n \n\ ______ \n\ ╲ \n\ ╲ \n\ ╲ ∞ \n\ ╲ ⌠ \n\ ╲ ⎮ n \n\ ╱ ⎮ x dx\n\ ╱ ⌡ \n\ ╱ -∞ \n\ ╱ k \n\ ╱ \n\ ‾‾‾‾‾‾ \n\ k = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x, (x, 0, oo)) ascii_str = \ """\ oo \n\ __ \n\ \\ ` \n\ ) x\n\ /_, \n\ x = 0 \ """ ucode_str = \ """\ ∞ \n\ ___ \n\ ╲ \n\ ╲ \n\ ╱ x\n\ ╱ \n\ ‾‾‾ \n\ x = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x**2, (x, 0, oo)) ascii_str = \ """\ oo \n\ ___ \n\ \\ ` \n\ \\ 2\n\ / x \n\ /__, \n\ x = 0 \ """ ucode_str = \ """\ ∞ \n\ ___ \n\ ╲ \n\ ╲ 2\n\ ╱ x \n\ ╱ \n\ ‾‾‾ \n\ x = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x/2, (x, 0, oo)) ascii_str = \ """\ oo \n\ ___ \n\ \\ ` \n\ \\ x\n\ ) -\n\ / 2\n\ /__, \n\ x = 0 \ """ ucode_str = \ """\ ∞ \n\ ____ \n\ ╲ \n\ ╲ \n\ ╲ x\n\ ╱ ─\n\ ╱ 2\n\ ╱ \n\ ‾‾‾‾ \n\ x = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(x**3/2, (x, 0, oo)) ascii_str = \ """\ oo \n\ ____ \n\ \\ ` \n\ \\ 3\n\ \\ x \n\ / --\n\ / 2 \n\ /___, \n\ x = 0 \ """ ucode_str = \ """\ ∞ \n\ ____ \n\ ╲ \n\ ╲ 3\n\ ╲ x \n\ ╱ ──\n\ ╱ 2 \n\ ╱ \n\ ‾‾‾‾ \n\ x = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum((x**3*y**(x/2))**n, (x, 0, oo)) ascii_str = \ """\ oo \n\ ____ \n\ \\ ` \n\ \\ n\n\ \\ / x\\ \n\ ) | -| \n\ / | 3 2| \n\ / \\x *y / \n\ /___, \n\ x = 0 \ """ ucode_str = \ """\ ∞ \n\ _____ \n\ ╲ \n\ ╲ \n\ ╲ n\n\ ╲ ⎛ x⎞ \n\ ╱ ⎜ ─⎟ \n\ ╱ ⎜ 3 2⎟ \n\ ╱ ⎝x ⋅y ⎠ \n\ ╱ \n\ ‾‾‾‾‾ \n\ x = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(1/x**2, (x, 0, oo)) ascii_str = \ """\ oo \n\ ____ \n\ \\ ` \n\ \\ 1 \n\ \\ --\n\ / 2\n\ / x \n\ /___, \n\ x = 0 \ """ ucode_str = \ """\ ∞ \n\ ____ \n\ ╲ \n\ ╲ 1 \n\ ╲ ──\n\ ╱ 2\n\ ╱ x \n\ ╱ \n\ ‾‾‾‾ \n\ x = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(1/y**(a/b), (x, 0, oo)) ascii_str = \ """\ oo \n\ ____ \n\ \\ ` \n\ \\ -a \n\ \\ ---\n\ / b \n\ / y \n\ /___, \n\ x = 0 \ """ ucode_str = \ """\ ∞ \n\ ____ \n\ ╲ \n\ ╲ -a \n\ ╲ ───\n\ ╱ b \n\ ╱ y \n\ ╱ \n\ ‾‾‾‾ \n\ x = 0 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Sum(1/y**(a/b), (x, 0, oo), (y, 1, 2)) ascii_str = \ """\ 2 oo \n\ ____ ____ \n\ \\ ` \\ ` \n\ \\ \\ -a\n\ \\ \\ --\n\ / / b \n\ / / y \n\ /___, /___, \n\ y = 1 x = 0 \ """ ucode_str = \ """\ 2 ∞ \n\ ____ ____ \n\ ╲ ╲ \n\ ╲ ╲ -a\n\ ╲ ╲ ──\n\ ╱ ╱ b \n\ ╱ ╱ y \n\ ╱ ╱ \n\ ‾‾‾‾ ‾‾‾‾ \n\ y = 1 x = 0 \ """ expr = Sum(1/(1 + 1/( 1 + 1/k)) + 1, (k, 111, 1 + 1/n), (k, 1/(1 + m), oo)) + 1/(1 + 1/k) ascii_str = \ """\ 1 \n\ 1 + - \n\ oo n \n\ _____ _____ \n\ \\ ` \\ ` \n\ \\ \\ / 1 \\ \n\ \\ \\ |1 + ---------| \n\ \\ \\ | 1 | 1 \n\ ) ) | 1 + -----| + -----\n\ / / | 1| 1\n\ / / | 1 + -| 1 + -\n\ / / \\ k/ k\n\ /____, /____, \n\ 1 k = 111 \n\ k = ----- \n\ m + 1 \ """ ucode_str = \ """\ 1 \n\ 1 + ─ \n\ ∞ n \n\ ______ ______ \n\ ╲ ╲ \n\ ╲ ╲ \n\ ╲ ╲ ⎛ 1 ⎞ \n\ ╲ ╲ ⎜1 + ─────────⎟ \n\ ╲ ╲ ⎜ 1 ⎟ 1 \n\ ╱ ╱ ⎜ 1 + ─────⎟ + ─────\n\ ╱ ╱ ⎜ 1⎟ 1\n\ ╱ ╱ ⎜ 1 + ─⎟ 1 + ─\n\ ╱ ╱ ⎝ k⎠ k\n\ ╱ ╱ \n\ ‾‾‾‾‾‾ ‾‾‾‾‾‾ \n\ 1 k = 111 \n\ k = ───── \n\ m + 1 \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_units(): expr = joule ascii_str1 = \ """\ 2\n\ kilogram*meter \n\ ---------------\n\ 2 \n\ second \ """ unicode_str1 = \ """\ 2\n\ kilogram⋅meter \n\ ───────────────\n\ 2 \n\ second \ """ ascii_str2 = \ """\ 2\n\ 3*x*y*kilogram*meter \n\ ---------------------\n\ 2 \n\ second \ """ unicode_str2 = \ """\ 2\n\ 3⋅x⋅y⋅kilogram⋅meter \n\ ─────────────────────\n\ 2 \n\ second \ """ from sympy.physics.units import kg, m, s assert upretty(expr) == "joule" assert pretty(expr) == "joule" assert upretty(expr.convert_to(kg*m**2/s**2)) == unicode_str1 assert pretty(expr.convert_to(kg*m**2/s**2)) == ascii_str1 assert upretty(3*kg*x*m**2*y/s**2) == unicode_str2 assert pretty(3*kg*x*m**2*y/s**2) == ascii_str2 def test_pretty_Subs(): f = Function('f') expr = Subs(f(x), x, ph**2) ascii_str = \ """\ (f(x))| 2\n\ |x=phi \ """ unicode_str = \ """\ (f(x))│ 2\n\ │x=φ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str expr = Subs(f(x).diff(x), x, 0) ascii_str = \ """\ /d \\| \n\ |--(f(x))|| \n\ \\dx /|x=0\ """ unicode_str = \ """\ ⎛d ⎞│ \n\ ⎜──(f(x))⎟│ \n\ ⎝dx ⎠│x=0\ """ assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str expr = Subs(f(x).diff(x)/y, (x, y), (0, Rational(1, 2))) ascii_str = \ """\ /d \\| \n\ |--(f(x))|| \n\ |dx || \n\ |--------|| \n\ \\ y /|x=0, y=1/2\ """ unicode_str = \ """\ ⎛d ⎞│ \n\ ⎜──(f(x))⎟│ \n\ ⎜dx ⎟│ \n\ ⎜────────⎟│ \n\ ⎝ y ⎠│x=0, y=1/2\ """ assert pretty(expr) == ascii_str assert upretty(expr) == unicode_str def test_gammas(): assert upretty(lowergamma(x, y)) == "γ(x, y)" assert upretty(uppergamma(x, y)) == "Γ(x, y)" assert xpretty(gamma(x), use_unicode=True) == 'Γ(x)' assert xpretty(gamma, use_unicode=True) == 'Γ' assert xpretty(symbols('gamma', cls=Function)(x), use_unicode=True) == 'γ(x)' assert xpretty(symbols('gamma', cls=Function), use_unicode=True) == 'γ' def test_beta(): assert xpretty(beta(x,y), use_unicode=True) == 'Β(x, y)' assert xpretty(beta(x,y), use_unicode=False) == 'B(x, y)' assert xpretty(beta, use_unicode=True) == 'Β' assert xpretty(beta, use_unicode=False) == 'B' mybeta = Function('beta') assert xpretty(mybeta(x), use_unicode=True) == 'β(x)' assert xpretty(mybeta(x, y, z), use_unicode=False) == 'beta(x, y, z)' assert xpretty(mybeta, use_unicode=True) == 'β' # test that notation passes to subclasses of the same name only def test_function_subclass_different_name(): class mygamma(gamma): pass assert xpretty(mygamma, use_unicode=True) == r"mygamma" assert xpretty(mygamma(x), use_unicode=True) == r"mygamma(x)" def test_SingularityFunction(): assert xpretty(SingularityFunction(x, 0, n), use_unicode=True) == ( """\ n\n\ \ """) assert xpretty(SingularityFunction(x, 1, n), use_unicode=True) == ( """\ n\n\ \ """) assert xpretty(SingularityFunction(x, -1, n), use_unicode=True) == ( """\ n\n\ \ """) assert xpretty(SingularityFunction(x, a, n), use_unicode=True) == ( """\ n\n\ <-a + x> \ """) assert xpretty(SingularityFunction(x, y, n), use_unicode=True) == ( """\ n\n\ \ """) assert xpretty(SingularityFunction(x, 0, n), use_unicode=False) == ( """\ n\n\ \ """) assert xpretty(SingularityFunction(x, 1, n), use_unicode=False) == ( """\ n\n\ \ """) assert xpretty(SingularityFunction(x, -1, n), use_unicode=False) == ( """\ n\n\ \ """) assert xpretty(SingularityFunction(x, a, n), use_unicode=False) == ( """\ n\n\ <-a + x> \ """) assert xpretty(SingularityFunction(x, y, n), use_unicode=False) == ( """\ n\n\ \ """) def test_deltas(): assert xpretty(DiracDelta(x), use_unicode=True) == 'δ(x)' assert xpretty(DiracDelta(x, 1), use_unicode=True) == \ """\ (1) \n\ δ (x)\ """ assert xpretty(x*DiracDelta(x, 1), use_unicode=True) == \ """\ (1) \n\ x⋅δ (x)\ """ def test_hyper(): expr = hyper((), (), z) ucode_str = \ """\ ┌─ ⎛ │ ⎞\n\ ├─ ⎜ │ z⎟\n\ 0╵ 0 ⎝ │ ⎠\ """ ascii_str = \ """\ _ \n\ |_ / | \\\n\ | | | z|\n\ 0 0 \\ | /\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = hyper((), (1,), x) ucode_str = \ """\ ┌─ ⎛ │ ⎞\n\ ├─ ⎜ │ x⎟\n\ 0╵ 1 ⎝1 │ ⎠\ """ ascii_str = \ """\ _ \n\ |_ / | \\\n\ | | | x|\n\ 0 1 \\1 | /\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = hyper([2], [1], x) ucode_str = \ """\ ┌─ ⎛2 │ ⎞\n\ ├─ ⎜ │ x⎟\n\ 1╵ 1 ⎝1 │ ⎠\ """ ascii_str = \ """\ _ \n\ |_ /2 | \\\n\ | | | x|\n\ 1 1 \\1 | /\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = hyper((pi/3, -2*k), (3, 4, 5, -3), x) ucode_str = \ """\ ⎛ π │ ⎞\n\ ┌─ ⎜ ─, -2⋅k │ ⎟\n\ ├─ ⎜ 3 │ x⎟\n\ 2╵ 4 ⎜ │ ⎟\n\ ⎝3, 4, 5, -3 │ ⎠\ """ ascii_str = \ """\ \n\ _ / pi | \\\n\ |_ | --, -2*k | |\n\ | | 3 | x|\n\ 2 4 | | |\n\ \\3, 4, 5, -3 | /\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = hyper((pi, S('2/3'), -2*k), (3, 4, 5, -3), x**2) ucode_str = \ """\ ┌─ ⎛π, 2/3, -2⋅k │ 2⎞\n\ ├─ ⎜ │ x ⎟\n\ 3╵ 4 ⎝3, 4, 5, -3 │ ⎠\ """ ascii_str = \ """\ _ \n\ |_ /pi, 2/3, -2*k | 2\\\n\ | | | x |\n\ 3 4 \\ 3, 4, 5, -3 | /\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = hyper([1, 2], [3, 4], 1/(1/(1/(1/x + 1) + 1) + 1)) ucode_str = \ """\ ⎛ │ 1 ⎞\n\ ⎜ │ ─────────────⎟\n\ ⎜ │ 1 ⎟\n\ ┌─ ⎜1, 2 │ 1 + ─────────⎟\n\ ├─ ⎜ │ 1 ⎟\n\ 2╵ 2 ⎜3, 4 │ 1 + ─────⎟\n\ ⎜ │ 1⎟\n\ ⎜ │ 1 + ─⎟\n\ ⎝ │ x⎠\ """ ascii_str = \ """\ \n\ / | 1 \\\n\ | | -------------|\n\ _ | | 1 |\n\ |_ |1, 2 | 1 + ---------|\n\ | | | 1 |\n\ 2 2 |3, 4 | 1 + -----|\n\ | | 1|\n\ | | 1 + -|\n\ \\ | x/\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_meijerg(): expr = meijerg([pi, pi, x], [1], [0, 1], [1, 2, 3], z) ucode_str = \ """\ ╭─╮2, 3 ⎛π, π, x 1 │ ⎞\n\ │╶┐ ⎜ │ z⎟\n\ ╰─╯4, 5 ⎝ 0, 1 1, 2, 3 │ ⎠\ """ ascii_str = \ """\ __2, 3 /pi, pi, x 1 | \\\n\ /__ | | z|\n\ \\_|4, 5 \\ 0, 1 1, 2, 3 | /\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = meijerg([1, pi/7], [2, pi, 5], [], [], z**2) ucode_str = \ """\ ⎛ π │ ⎞\n\ ╭─╮0, 2 ⎜1, ─ 2, π, 5 │ 2⎟\n\ │╶┐ ⎜ 7 │ z ⎟\n\ ╰─╯5, 0 ⎜ │ ⎟\n\ ⎝ │ ⎠\ """ ascii_str = \ """\ / pi | \\\n\ __0, 2 |1, -- 2, pi, 5 | 2|\n\ /__ | 7 | z |\n\ \\_|5, 0 | | |\n\ \\ | /\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str ucode_str = \ """\ ╭─╮ 1, 10 ⎛1, 1, 1, 1, 1, 1, 1, 1, 1, 1 1 │ ⎞\n\ │╶┐ ⎜ │ z⎟\n\ ╰─╯11, 2 ⎝ 1 1 │ ⎠\ """ ascii_str = \ """\ __ 1, 10 /1, 1, 1, 1, 1, 1, 1, 1, 1, 1 1 | \\\n\ /__ | | z|\n\ \\_|11, 2 \\ 1 1 | /\ """ expr = meijerg([1]*10, [1], [1], [1], z) assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = meijerg([1, 2, ], [4, 3], [3], [4, 5], 1/(1/(1/(1/x + 1) + 1) + 1)) ucode_str = \ """\ ⎛ │ 1 ⎞\n\ ⎜ │ ─────────────⎟\n\ ⎜ │ 1 ⎟\n\ ╭─╮1, 2 ⎜1, 2 4, 3 │ 1 + ─────────⎟\n\ │╶┐ ⎜ │ 1 ⎟\n\ ╰─╯4, 3 ⎜ 3 4, 5 │ 1 + ─────⎟\n\ ⎜ │ 1⎟\n\ ⎜ │ 1 + ─⎟\n\ ⎝ │ x⎠\ """ ascii_str = \ """\ / | 1 \\\n\ | | -------------|\n\ | | 1 |\n\ __1, 2 |1, 2 4, 3 | 1 + ---------|\n\ /__ | | 1 |\n\ \\_|4, 3 | 3 4, 5 | 1 + -----|\n\ | | 1|\n\ | | 1 + -|\n\ \\ | x/\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = Integral(expr, x) ucode_str = \ """\ ⌠ \n\ ⎮ ⎛ │ 1 ⎞ \n\ ⎮ ⎜ │ ─────────────⎟ \n\ ⎮ ⎜ │ 1 ⎟ \n\ ⎮ ╭─╮1, 2 ⎜1, 2 4, 3 │ 1 + ─────────⎟ \n\ ⎮ │╶┐ ⎜ │ 1 ⎟ dx\n\ ⎮ ╰─╯4, 3 ⎜ 3 4, 5 │ 1 + ─────⎟ \n\ ⎮ ⎜ │ 1⎟ \n\ ⎮ ⎜ │ 1 + ─⎟ \n\ ⎮ ⎝ │ x⎠ \n\ ⌡ \ """ ascii_str = \ """\ / \n\ | \n\ | / | 1 \\ \n\ | | | -------------| \n\ | | | 1 | \n\ | __1, 2 |1, 2 4, 3 | 1 + ---------| \n\ | /__ | | 1 | dx\n\ | \\_|4, 3 | 3 4, 5 | 1 + -----| \n\ | | | 1| \n\ | | | 1 + -| \n\ | \\ | x/ \n\ | \n\ / \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_noncommutative(): A, B, C = symbols('A,B,C', commutative=False) expr = A*B*C**-1 ascii_str = \ """\ -1\n\ A*B*C \ """ ucode_str = \ """\ -1\n\ A⋅B⋅C \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = C**-1*A*B ascii_str = \ """\ -1 \n\ C *A*B\ """ ucode_str = \ """\ -1 \n\ C ⋅A⋅B\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A*C**-1*B ascii_str = \ """\ -1 \n\ A*C *B\ """ ucode_str = \ """\ -1 \n\ A⋅C ⋅B\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A*C**-1*B/x ascii_str = \ """\ -1 \n\ A*C *B\n\ -------\n\ x \ """ ucode_str = \ """\ -1 \n\ A⋅C ⋅B\n\ ───────\n\ x \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_special_functions(): x, y = symbols("x y") # atan2 expr = atan2(y/sqrt(200), sqrt(x)) ascii_str = \ """\ / ___ \\\n\ |\\/ 2 *y ___|\n\ atan2|-------, \\/ x |\n\ \\ 20 /\ """ ucode_str = \ """\ ⎛√2⋅y ⎞\n\ atan2⎜────, √x⎟\n\ ⎝ 20 ⎠\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_geometry(): e = Segment((0, 1), (0, 2)) assert pretty(e) == 'Segment2D(Point2D(0, 1), Point2D(0, 2))' e = Ray((1, 1), angle=4.02*pi) assert pretty(e) == 'Ray2D(Point2D(1, 1), Point2D(2, tan(pi/50) + 1))' def test_expint(): expr = Ei(x) string = 'Ei(x)' assert pretty(expr) == string assert upretty(expr) == string expr = expint(1, z) ucode_str = "E₁(z)" ascii_str = "expint(1, z)" assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str assert pretty(Shi(x)) == 'Shi(x)' assert pretty(Si(x)) == 'Si(x)' assert pretty(Ci(x)) == 'Ci(x)' assert pretty(Chi(x)) == 'Chi(x)' assert upretty(Shi(x)) == 'Shi(x)' assert upretty(Si(x)) == 'Si(x)' assert upretty(Ci(x)) == 'Ci(x)' assert upretty(Chi(x)) == 'Chi(x)' def test_elliptic_functions(): ascii_str = \ """\ / 1 \\\n\ K|-----|\n\ \\z + 1/\ """ ucode_str = \ """\ ⎛ 1 ⎞\n\ K⎜─────⎟\n\ ⎝z + 1⎠\ """ expr = elliptic_k(1/(z + 1)) assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str ascii_str = \ """\ / | 1 \\\n\ F|1|-----|\n\ \\ |z + 1/\ """ ucode_str = \ """\ ⎛ │ 1 ⎞\n\ F⎜1│─────⎟\n\ ⎝ │z + 1⎠\ """ expr = elliptic_f(1, 1/(1 + z)) assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str ascii_str = \ """\ / 1 \\\n\ E|-----|\n\ \\z + 1/\ """ ucode_str = \ """\ ⎛ 1 ⎞\n\ E⎜─────⎟\n\ ⎝z + 1⎠\ """ expr = elliptic_e(1/(z + 1)) assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str ascii_str = \ """\ / | 1 \\\n\ E|1|-----|\n\ \\ |z + 1/\ """ ucode_str = \ """\ ⎛ │ 1 ⎞\n\ E⎜1│─────⎟\n\ ⎝ │z + 1⎠\ """ expr = elliptic_e(1, 1/(1 + z)) assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str ascii_str = \ """\ / |4\\\n\ Pi|3|-|\n\ \\ |x/\ """ ucode_str = \ """\ ⎛ │4⎞\n\ Π⎜3│─⎟\n\ ⎝ │x⎠\ """ expr = elliptic_pi(3, 4/x) assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str ascii_str = \ """\ / 4| \\\n\ Pi|3; -|6|\n\ \\ x| /\ """ ucode_str = \ """\ ⎛ 4│ ⎞\n\ Π⎜3; ─│6⎟\n\ ⎝ x│ ⎠\ """ expr = elliptic_pi(3, 4/x, 6) assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_RandomDomain(): from sympy.stats import Normal, Die, Exponential, pspace, where X = Normal('x1', 0, 1) assert upretty(where(X > 0)) == "Domain: 0 < x₁ ∧ x₁ < ∞" D = Die('d1', 6) assert upretty(where(D > 4)) == 'Domain: d₁ = 5 ∨ d₁ = 6' A = Exponential('a', 1) B = Exponential('b', 1) assert upretty(pspace(Tuple(A, B)).domain) == \ 'Domain: 0 ≤ a ∧ 0 ≤ b ∧ a < ∞ ∧ b < ∞' def test_PrettyPoly(): F = QQ.frac_field(x, y) R = QQ.poly_ring(x, y) expr = F.convert(x/(x + y)) assert pretty(expr) == "x/(x + y)" assert upretty(expr) == "x/(x + y)" expr = R.convert(x + y) assert pretty(expr) == "x + y" assert upretty(expr) == "x + y" def test_issue_6285(): assert pretty(Pow(2, -5, evaluate=False)) == '1 \n--\n 5\n2 ' assert pretty(Pow(x, (1/pi))) == \ ' 1 \n'\ ' --\n'\ ' pi\n'\ 'x ' def test_issue_6359(): assert pretty(Integral(x**2, x)**2) == \ """\ 2 / / \\ \n\ | | | \n\ | | 2 | \n\ | | x dx| \n\ | | | \n\ \\/ / \ """ assert upretty(Integral(x**2, x)**2) == \ """\ 2 ⎛⌠ ⎞ \n\ ⎜⎮ 2 ⎟ \n\ ⎜⎮ x dx⎟ \n\ ⎝⌡ ⎠ \ """ assert pretty(Sum(x**2, (x, 0, 1))**2) == \ """\ 2 / 1 \\ \n\ | ___ | \n\ | \\ ` | \n\ | \\ 2| \n\ | / x | \n\ | /__, | \n\ \\x = 0 / \ """ assert upretty(Sum(x**2, (x, 0, 1))**2) == \ """\ 2 ⎛ 1 ⎞ \n\ ⎜ ___ ⎟ \n\ ⎜ ╲ ⎟ \n\ ⎜ ╲ 2⎟ \n\ ⎜ ╱ x ⎟ \n\ ⎜ ╱ ⎟ \n\ ⎜ ‾‾‾ ⎟ \n\ ⎝x = 0 ⎠ \ """ assert pretty(Product(x**2, (x, 1, 2))**2) == \ """\ 2 / 2 \\ \n\ |______ | \n\ | | | 2| \n\ | | | x | \n\ | | | | \n\ \\x = 1 / \ """ assert upretty(Product(x**2, (x, 1, 2))**2) == \ """\ 2 ⎛ 2 ⎞ \n\ ⎜─┬──┬─ ⎟ \n\ ⎜ │ │ 2⎟ \n\ ⎜ │ │ x ⎟ \n\ ⎜ │ │ ⎟ \n\ ⎝x = 1 ⎠ \ """ f = Function('f') assert pretty(Derivative(f(x), x)**2) == \ """\ 2 /d \\ \n\ |--(f(x))| \n\ \\dx / \ """ assert upretty(Derivative(f(x), x)**2) == \ """\ 2 ⎛d ⎞ \n\ ⎜──(f(x))⎟ \n\ ⎝dx ⎠ \ """ def test_issue_6739(): ascii_str = \ """\ 1 \n\ -----\n\ ___\n\ \\/ x \ """ ucode_str = \ """\ 1 \n\ ──\n\ √x\ """ assert pretty(1/sqrt(x)) == ascii_str assert upretty(1/sqrt(x)) == ucode_str def test_complicated_symbol_unchanged(): for symb_name in ["dexpr2_d1tau", "dexpr2^d1tau"]: assert pretty(Symbol(symb_name)) == symb_name def test_categories(): from sympy.categories import (Object, IdentityMorphism, NamedMorphism, Category, Diagram, DiagramGrid) A1 = Object("A1") A2 = Object("A2") A3 = Object("A3") f1 = NamedMorphism(A1, A2, "f1") f2 = NamedMorphism(A2, A3, "f2") id_A1 = IdentityMorphism(A1) K1 = Category("K1") assert pretty(A1) == "A1" assert upretty(A1) == "A₁" assert pretty(f1) == "f1:A1-->A2" assert upretty(f1) == "f₁:A₁——▶A₂" assert pretty(id_A1) == "id:A1-->A1" assert upretty(id_A1) == "id:A₁——▶A₁" assert pretty(f2*f1) == "f2*f1:A1-->A3" assert upretty(f2*f1) == "f₂∘f₁:A₁——▶A₃" assert pretty(K1) == "K1" assert upretty(K1) == "K₁" # Test how diagrams are printed. d = Diagram() assert pretty(d) == "EmptySet" assert upretty(d) == "∅" d = Diagram({f1: "unique", f2: S.EmptySet}) assert pretty(d) == "{f2*f1:A1-->A3: EmptySet, id:A1-->A1: " \ "EmptySet, id:A2-->A2: EmptySet, id:A3-->A3: " \ "EmptySet, f1:A1-->A2: {unique}, f2:A2-->A3: EmptySet}" assert upretty(d) == "{f₂∘f₁:A₁——▶A₃: ∅, id:A₁——▶A₁: ∅, " \ "id:A₂——▶A₂: ∅, id:A₃——▶A₃: ∅, f₁:A₁——▶A₂: {unique}, f₂:A₂——▶A₃: ∅}" d = Diagram({f1: "unique", f2: S.EmptySet}, {f2 * f1: "unique"}) assert pretty(d) == "{f2*f1:A1-->A3: EmptySet, id:A1-->A1: " \ "EmptySet, id:A2-->A2: EmptySet, id:A3-->A3: " \ "EmptySet, f1:A1-->A2: {unique}, f2:A2-->A3: EmptySet}" \ " ==> {f2*f1:A1-->A3: {unique}}" assert upretty(d) == "{f₂∘f₁:A₁——▶A₃: ∅, id:A₁——▶A₁: ∅, id:A₂——▶A₂: " \ "∅, id:A₃——▶A₃: ∅, f₁:A₁——▶A₂: {unique}, f₂:A₂——▶A₃: ∅}" \ " ══▶ {f₂∘f₁:A₁——▶A₃: {unique}}" grid = DiagramGrid(d) assert pretty(grid) == "A1 A2\n \nA3 " assert upretty(grid) == "A₁ A₂\n \nA₃ " def test_PrettyModules(): R = QQ.old_poly_ring(x, y) F = R.free_module(2) M = F.submodule([x, y], [1, x**2]) ucode_str = \ """\ 2\n\ ℚ[x, y] \ """ ascii_str = \ """\ 2\n\ QQ[x, y] \ """ assert upretty(F) == ucode_str assert pretty(F) == ascii_str ucode_str = \ """\ ╱ ⎡ 2⎤╲\n\ ╲[x, y], ⎣1, x ⎦╱\ """ ascii_str = \ """\ 2 \n\ <[x, y], [1, x ]>\ """ assert upretty(M) == ucode_str assert pretty(M) == ascii_str I = R.ideal(x**2, y) ucode_str = \ """\ ╱ 2 ╲\n\ ╲x , y╱\ """ ascii_str = \ """\ 2 \n\ \ """ assert upretty(I) == ucode_str assert pretty(I) == ascii_str Q = F / M ucode_str = \ """\ 2 \n\ ℚ[x, y] \n\ ─────────────────\n\ ╱ ⎡ 2⎤╲\n\ ╲[x, y], ⎣1, x ⎦╱\ """ ascii_str = \ """\ 2 \n\ QQ[x, y] \n\ -----------------\n\ 2 \n\ <[x, y], [1, x ]>\ """ assert upretty(Q) == ucode_str assert pretty(Q) == ascii_str ucode_str = \ """\ ╱⎡ 3⎤ ╲\n\ │⎢ x ⎥ ╱ ⎡ 2⎤╲ ╱ ⎡ 2⎤╲│\n\ │⎢1, ──⎥ + ╲[x, y], ⎣1, x ⎦╱, [2, y] + ╲[x, y], ⎣1, x ⎦╱│\n\ ╲⎣ 2 ⎦ ╱\ """ ascii_str = \ """\ 3 \n\ x 2 2 \n\ <[1, --] + <[x, y], [1, x ]>, [2, y] + <[x, y], [1, x ]>>\n\ 2 \ """ def test_QuotientRing(): R = QQ.old_poly_ring(x)/[x**2 + 1] ucode_str = \ """\ ℚ[x] \n\ ────────\n\ ╱ 2 ╲\n\ ╲x + 1╱\ """ ascii_str = \ """\ QQ[x] \n\ --------\n\ 2 \n\ \ """ assert upretty(R) == ucode_str assert pretty(R) == ascii_str ucode_str = \ """\ ╱ 2 ╲\n\ 1 + ╲x + 1╱\ """ ascii_str = \ """\ 2 \n\ 1 + \ """ assert upretty(R.one) == ucode_str assert pretty(R.one) == ascii_str def test_Homomorphism(): from sympy.polys.agca import homomorphism R = QQ.old_poly_ring(x) expr = homomorphism(R.free_module(1), R.free_module(1), [0]) ucode_str = \ """\ 1 1\n\ [0] : ℚ[x] ──> ℚ[x] \ """ ascii_str = \ """\ 1 1\n\ [0] : QQ[x] --> QQ[x] \ """ assert upretty(expr) == ucode_str assert pretty(expr) == ascii_str expr = homomorphism(R.free_module(2), R.free_module(2), [0, 0]) ucode_str = \ """\ ⎡0 0⎤ 2 2\n\ ⎢ ⎥ : ℚ[x] ──> ℚ[x] \n\ ⎣0 0⎦ \ """ ascii_str = \ """\ [0 0] 2 2\n\ [ ] : QQ[x] --> QQ[x] \n\ [0 0] \ """ assert upretty(expr) == ucode_str assert pretty(expr) == ascii_str expr = homomorphism(R.free_module(1), R.free_module(1) / [[x]], [0]) ucode_str = \ """\ 1\n\ 1 ℚ[x] \n\ [0] : ℚ[x] ──> ─────\n\ <[x]>\ """ ascii_str = \ """\ 1\n\ 1 QQ[x] \n\ [0] : QQ[x] --> ------\n\ <[x]> \ """ assert upretty(expr) == ucode_str assert pretty(expr) == ascii_str def test_Tr(): A, B = symbols('A B', commutative=False) t = Tr(A*B) assert pretty(t) == r'Tr(A*B)' assert upretty(t) == 'Tr(A⋅B)' def test_pretty_Add(): eq = Mul(-2, x - 2, evaluate=False) + 5 assert pretty(eq) == '5 - 2*(x - 2)' def test_issue_7179(): assert upretty(Not(Equivalent(x, y))) == 'x ⇎ y' assert upretty(Not(Implies(x, y))) == 'x ↛ y' def test_issue_7180(): assert upretty(Equivalent(x, y)) == 'x ⇔ y' def test_pretty_Complement(): assert pretty(S.Reals - S.Naturals) == '(-oo, oo) \\ Naturals' assert upretty(S.Reals - S.Naturals) == 'ℝ \\ ℕ' assert pretty(S.Reals - S.Naturals0) == '(-oo, oo) \\ Naturals0' assert upretty(S.Reals - S.Naturals0) == 'ℝ \\ ℕ₀' def test_pretty_SymmetricDifference(): from sympy import SymmetricDifference, Interval from sympy.testing.pytest import raises assert upretty(SymmetricDifference(Interval(2,3), Interval(3,5), \ evaluate = False)) == '[2, 3] ∆ [3, 5]' with raises(NotImplementedError): pretty(SymmetricDifference(Interval(2,3), Interval(3,5), evaluate = False)) def test_pretty_Contains(): assert pretty(Contains(x, S.Integers)) == 'Contains(x, Integers)' assert upretty(Contains(x, S.Integers)) == 'x ∈ ℤ' def test_issue_8292(): from sympy.core import sympify e = sympify('((x+x**4)/(x-1))-(2*(x-1)**4/(x-1)**4)', evaluate=False) ucode_str = \ """\ 4 4 \n\ 2⋅(x - 1) x + x\n\ - ────────── + ──────\n\ 4 x - 1 \n\ (x - 1) \ """ ascii_str = \ """\ 4 4 \n\ 2*(x - 1) x + x\n\ - ---------- + ------\n\ 4 x - 1 \n\ (x - 1) \ """ assert pretty(e) == ascii_str assert upretty(e) == ucode_str def test_issue_4335(): y = Function('y') expr = -y(x).diff(x) ucode_str = \ """\ d \n\ -──(y(x))\n\ dx \ """ ascii_str = \ """\ d \n\ - --(y(x))\n\ dx \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_issue_8344(): from sympy.core import sympify e = sympify('2*x*y**2/1**2 + 1', evaluate=False) ucode_str = \ """\ 2 \n\ 2⋅x⋅y \n\ ────── + 1\n\ 2 \n\ 1 \ """ assert upretty(e) == ucode_str def test_issue_6324(): x = Pow(2, 3, evaluate=False) y = Pow(10, -2, evaluate=False) e = Mul(x, y, evaluate=False) ucode_str = \ """\ 3\n\ 2 \n\ ───\n\ 2\n\ 10 \ """ assert upretty(e) == ucode_str def test_issue_7927(): e = sin(x/2)**cos(x/2) ucode_str = \ """\ ⎛x⎞\n\ cos⎜─⎟\n\ ⎝2⎠\n\ ⎛ ⎛x⎞⎞ \n\ ⎜sin⎜─⎟⎟ \n\ ⎝ ⎝2⎠⎠ \ """ assert upretty(e) == ucode_str e = sin(x)**(S(11)/13) ucode_str = \ """\ 11\n\ ──\n\ 13\n\ (sin(x)) \ """ assert upretty(e) == ucode_str def test_issue_6134(): from sympy.abc import lamda, t phi = Function('phi') e = lamda*x*Integral(phi(t)*pi*sin(pi*t), (t, 0, 1)) + lamda*x**2*Integral(phi(t)*2*pi*sin(2*pi*t), (t, 0, 1)) ucode_str = \ """\ 1 1 \n\ 2 ⌠ ⌠ \n\ λ⋅x ⋅⎮ 2⋅π⋅φ(t)⋅sin(2⋅π⋅t) dt + λ⋅x⋅⎮ π⋅φ(t)⋅sin(π⋅t) dt\n\ ⌡ ⌡ \n\ 0 0 \ """ assert upretty(e) == ucode_str def test_issue_9877(): ucode_str1 = '(2, 3) ∪ ([1, 2] \\ {x})' a, b, c = Interval(2, 3, True, True), Interval(1, 2), FiniteSet(x) assert upretty(Union(a, Complement(b, c))) == ucode_str1 ucode_str2 = '{x} ∩ {y} ∩ ({z} \\ [1, 2])' d, e, f, g = FiniteSet(x), FiniteSet(y), FiniteSet(z), Interval(1, 2) assert upretty(Intersection(d, e, Complement(f, g))) == ucode_str2 def test_issue_13651(): expr1 = c + Mul(-1, a + b, evaluate=False) assert pretty(expr1) == 'c - (a + b)' expr2 = c + Mul(-1, a - b + d, evaluate=False) assert pretty(expr2) == 'c - (a - b + d)' def test_pretty_primenu(): from sympy.ntheory.factor_ import primenu ascii_str1 = "nu(n)" ucode_str1 = "ν(n)" n = symbols('n', integer=True) assert pretty(primenu(n)) == ascii_str1 assert upretty(primenu(n)) == ucode_str1 def test_pretty_primeomega(): from sympy.ntheory.factor_ import primeomega ascii_str1 = "Omega(n)" ucode_str1 = "Ω(n)" n = symbols('n', integer=True) assert pretty(primeomega(n)) == ascii_str1 assert upretty(primeomega(n)) == ucode_str1 def test_pretty_Mod(): from sympy.core import Mod ascii_str1 = "x mod 7" ucode_str1 = "x mod 7" ascii_str2 = "(x + 1) mod 7" ucode_str2 = "(x + 1) mod 7" ascii_str3 = "2*x mod 7" ucode_str3 = "2⋅x mod 7" ascii_str4 = "(x mod 7) + 1" ucode_str4 = "(x mod 7) + 1" ascii_str5 = "2*(x mod 7)" ucode_str5 = "2⋅(x mod 7)" x = symbols('x', integer=True) assert pretty(Mod(x, 7)) == ascii_str1 assert upretty(Mod(x, 7)) == ucode_str1 assert pretty(Mod(x + 1, 7)) == ascii_str2 assert upretty(Mod(x + 1, 7)) == ucode_str2 assert pretty(Mod(2 * x, 7)) == ascii_str3 assert upretty(Mod(2 * x, 7)) == ucode_str3 assert pretty(Mod(x, 7) + 1) == ascii_str4 assert upretty(Mod(x, 7) + 1) == ucode_str4 assert pretty(2 * Mod(x, 7)) == ascii_str5 assert upretty(2 * Mod(x, 7)) == ucode_str5 def test_issue_11801(): assert pretty(Symbol("")) == "" assert upretty(Symbol("")) == "" def test_pretty_UnevaluatedExpr(): x = symbols('x') he = UnevaluatedExpr(1/x) ucode_str = \ """\ 1\n\ ─\n\ x\ """ assert upretty(he) == ucode_str ucode_str = \ """\ 2\n\ ⎛1⎞ \n\ ⎜─⎟ \n\ ⎝x⎠ \ """ assert upretty(he**2) == ucode_str ucode_str = \ """\ 1\n\ 1 + ─\n\ x\ """ assert upretty(he + 1) == ucode_str ucode_str = \ ('''\ 1\n\ x⋅─\n\ x\ ''') assert upretty(x*he) == ucode_str def test_issue_10472(): M = (Matrix([[0, 0], [0, 0]]), Matrix([0, 0])) ucode_str = \ """\ ⎛⎡0 0⎤ ⎡0⎤⎞ ⎜⎢ ⎥, ⎢ ⎥⎟ ⎝⎣0 0⎦ ⎣0⎦⎠\ """ assert upretty(M) == ucode_str def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) ascii_str1 = "A_00" ucode_str1 = "A₀₀" assert pretty(A[0, 0]) == ascii_str1 assert upretty(A[0, 0]) == ucode_str1 ascii_str1 = "3*A_00" ucode_str1 = "3⋅A₀₀" assert pretty(3*A[0, 0]) == ascii_str1 assert upretty(3*A[0, 0]) == ucode_str1 ascii_str1 = "(-B + A)[0, 0]" ucode_str1 = "(-B + A)[0, 0]" F = C[0, 0].subs(C, A - B) assert pretty(F) == ascii_str1 assert upretty(F) == ucode_str1 def test_issue_12675(): from sympy.vector import CoordSys3D x, y, t, j = symbols('x y t j') e = CoordSys3D('e') ucode_str = \ """\ ⎛ t⎞ \n\ ⎜⎛x⎞ ⎟ j_e\n\ ⎜⎜─⎟ ⎟ \n\ ⎝⎝y⎠ ⎠ \ """ assert upretty((x/y)**t*e.j) == ucode_str ucode_str = \ """\ ⎛1⎞ \n\ ⎜─⎟ j_e\n\ ⎝y⎠ \ """ assert upretty((1/y)*e.j) == ucode_str def test_MatrixSymbol_printing(): # test cases for issue #14237 A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) C = MatrixSymbol("C", 3, 3) assert pretty(-A*B*C) == "-A*B*C" assert pretty(A - B) == "-B + A" assert pretty(A*B*C - A*B - B*C) == "-A*B -B*C + A*B*C" # issue #14814 x = MatrixSymbol('x', n, n) y = MatrixSymbol('y*', n, n) assert pretty(x + y) == "x + y*" ascii_str = \ """\ 2 \n\ -2*y* -a*x\ """ assert pretty(-a*x + -2*y*y) == ascii_str def test_degree_printing(): expr1 = 90*degree assert pretty(expr1) == '90°' expr2 = x*degree assert pretty(expr2) == 'x°' expr3 = cos(x*degree + 90*degree) assert pretty(expr3) == 'cos(x° + 90°)' def test_vector_expr_pretty_printing(): A = CoordSys3D('A') assert upretty(Cross(A.i, A.x*A.i+3*A.y*A.j)) == "(i_A)×((x_A) i_A + (3⋅y_A) j_A)" assert upretty(x*Cross(A.i, A.j)) == 'x⋅(i_A)×(j_A)' assert upretty(Curl(A.x*A.i + 3*A.y*A.j)) == "∇×((x_A) i_A + (3⋅y_A) j_A)" assert upretty(Divergence(A.x*A.i + 3*A.y*A.j)) == "∇⋅((x_A) i_A + (3⋅y_A) j_A)" assert upretty(Dot(A.i, A.x*A.i+3*A.y*A.j)) == "(i_A)⋅((x_A) i_A + (3⋅y_A) j_A)" assert upretty(Gradient(A.x+3*A.y)) == "∇(x_A + 3⋅y_A)" assert upretty(Laplacian(A.x+3*A.y)) == "∆(x_A + 3⋅y_A)" # TODO: add support for ASCII pretty. def test_pretty_print_tensor_expr(): L = TensorIndexType("L") i, j, k = tensor_indices("i j k", L) i0 = tensor_indices("i_0", L) A, B, C, D = tensor_heads("A B C D", [L]) H = TensorHead("H", [L, L]) expr = -i ascii_str = \ """\ -i\ """ ucode_str = \ """\ -i\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A(i) ascii_str = \ """\ i\n\ A \n\ \ """ ucode_str = \ """\ i\n\ A \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A(i0) ascii_str = \ """\ i_0\n\ A \n\ \ """ ucode_str = \ """\ i₀\n\ A \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A(-i) ascii_str = \ """\ \n\ A \n\ i\ """ ucode_str = \ """\ \n\ A \n\ i\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = -3*A(-i) ascii_str = \ """\ \n\ -3*A \n\ i\ """ ucode_str = \ """\ \n\ -3⋅A \n\ i\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = H(i, -j) ascii_str = \ """\ i \n\ H \n\ j\ """ ucode_str = \ """\ i \n\ H \n\ j\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = H(i, -i) ascii_str = \ """\ L_0 \n\ H \n\ L_0\ """ ucode_str = \ """\ L₀ \n\ H \n\ L₀\ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = H(i, -j)*A(j)*B(k) ascii_str = \ """\ i L_0 k\n\ H *A *B \n\ L_0 \ """ ucode_str = \ """\ i L₀ k\n\ H ⋅A ⋅B \n\ L₀ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (1+x)*A(i) ascii_str = \ """\ i\n\ (x + 1)*A \n\ \ """ ucode_str = \ """\ i\n\ (x + 1)⋅A \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A(i) + 3*B(i) ascii_str = \ """\ i i\n\ 3*B + A \n\ \ """ ucode_str = \ """\ i i\n\ 3⋅B + A \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_pretty_print_tensor_partial_deriv(): from sympy.tensor.toperators import PartialDerivative from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, tensor_heads L = TensorIndexType("L") i, j, k = tensor_indices("i j k", L) A, B, C, D = tensor_heads("A B C D", [L]) H = TensorHead("H", [L, L]) expr = PartialDerivative(A(i), A(j)) ascii_str = \ """\ d / i\\\n\ ---|A |\n\ j\\ /\n\ dA \n\ \ """ ucode_str = \ """\ ∂ ⎛ i⎞\n\ ───⎜A ⎟\n\ j⎝ ⎠\n\ ∂A \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A(i)*PartialDerivative(H(k, -i), A(j)) ascii_str = \ """\ L_0 d / k \\\n\ A *---|H |\n\ j\\ L_0/\n\ dA \n\ \ """ ucode_str = \ """\ L₀ ∂ ⎛ k ⎞\n\ A ⋅───⎜H ⎟\n\ j⎝ L₀⎠\n\ ∂A \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = A(i)*PartialDerivative(B(k)*C(-i) + 3*H(k, -i), A(j)) ascii_str = \ """\ L_0 d / k k \\\n\ A *---|3*H + B *C |\n\ j\\ L_0 L_0/\n\ dA \n\ \ """ ucode_str = \ """\ L₀ ∂ ⎛ k k ⎞\n\ A ⋅───⎜3⋅H + B ⋅C ⎟\n\ j⎝ L₀ L₀⎠\n\ ∂A \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (A(i) + B(i))*PartialDerivative(C(j), D(j)) ascii_str = \ """\ / i i\\ d / L_0\\\n\ |A + B |*-----|C |\n\ \\ / L_0\\ /\n\ dD \n\ \ """ ucode_str = \ """\ ⎛ i i⎞ ∂ ⎛ L₀⎞\n\ ⎜A + B ⎟⋅────⎜C ⎟\n\ ⎝ ⎠ L₀⎝ ⎠\n\ ∂D \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = (A(i) + B(i))*PartialDerivative(C(-i), D(j)) ascii_str = \ """\ / L_0 L_0\\ d / \\\n\ |A + B |*---|C |\n\ \\ / j\\ L_0/\n\ dD \n\ \ """ ucode_str = \ """\ ⎛ L₀ L₀⎞ ∂ ⎛ ⎞\n\ ⎜A + B ⎟⋅───⎜C ⎟\n\ ⎝ ⎠ j⎝ L₀⎠\n\ ∂D \n\ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = PartialDerivative(B(-i) + A(-i), A(-j), A(-n)) ucode_str = """\ 2 \n\ ∂ ⎛ ⎞\n\ ───────⎜A + B ⎟\n\ ⎝ i i⎠\n\ ∂A ∂A \n\ n j \ """ assert upretty(expr) == ucode_str expr = PartialDerivative(3*A(-i), A(-j), A(-n)) ucode_str = """\ 2 \n\ ∂ ⎛ ⎞\n\ ───────⎜3⋅A ⎟\n\ ⎝ i⎠\n\ ∂A ∂A \n\ n j \ """ assert upretty(expr) == ucode_str expr = TensorElement(H(i, j), {i:1}) ascii_str = \ """\ i=1,j\n\ H \n\ \ """ ucode_str = ascii_str assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = TensorElement(H(i, j), {i: 1, j: 1}) ascii_str = \ """\ i=1,j=1\n\ H \n\ \ """ ucode_str = ascii_str assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = TensorElement(H(i, j), {j: 1}) ascii_str = \ """\ i,j=1\n\ H \n\ \ """ ucode_str = ascii_str expr = TensorElement(H(-i, j), {-i: 1}) ascii_str = \ """\ j\n\ H \n\ i=1 \ """ ucode_str = ascii_str assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_issue_15560(): a = MatrixSymbol('a', 1, 1) e = pretty(a*(KroneckerProduct(a, a))) result = 'a*(a x a)' assert e == result def test_print_lerchphi(): # Part of issue 6013 a = Symbol('a') pretty(lerchphi(a, 1, 2)) uresult = 'Φ(a, 1, 2)' aresult = 'lerchphi(a, 1, 2)' assert pretty(lerchphi(a, 1, 2)) == aresult assert upretty(lerchphi(a, 1, 2)) == uresult def test_issue_15583(): N = mechanics.ReferenceFrame('N') result = '(n_x, n_y, n_z)' e = pretty((N.x, N.y, N.z)) assert e == result def test_matrixSymbolBold(): # Issue 15871 def boldpretty(expr): return xpretty(expr, use_unicode=True, wrap_line=False, mat_symbol_style="bold") from sympy import trace A = MatrixSymbol("A", 2, 2) assert boldpretty(trace(A)) == 'tr(𝐀)' A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) C = MatrixSymbol("C", 3, 3) assert boldpretty(-A) == '-𝐀' assert boldpretty(A - A*B - B) == '-𝐁 -𝐀⋅𝐁 + 𝐀' assert boldpretty(-A*B - A*B*C - B) == '-𝐁 -𝐀⋅𝐁 -𝐀⋅𝐁⋅𝐂' A = MatrixSymbol("Addot", 3, 3) assert boldpretty(A) == '𝐀̈' omega = MatrixSymbol("omega", 3, 3) assert boldpretty(omega) == 'ω' omega = MatrixSymbol("omeganorm", 3, 3) assert boldpretty(omega) == '‖ω‖' a = Symbol('alpha') b = Symbol('b') c = MatrixSymbol("c", 3, 1) d = MatrixSymbol("d", 3, 1) assert boldpretty(a*B*c+b*d) == 'b⋅𝐝 + α⋅𝐁⋅𝐜' d = MatrixSymbol("delta", 3, 1) B = MatrixSymbol("Beta", 3, 3) assert boldpretty(a*B*c+b*d) == 'b⋅δ + α⋅Β⋅𝐜' A = MatrixSymbol("A_2", 3, 3) assert boldpretty(A) == '𝐀₂' def test_center_accent(): assert center_accent('a', '\N{COMBINING TILDE}') == 'ã' assert center_accent('aa', '\N{COMBINING TILDE}') == 'aã' assert center_accent('aaa', '\N{COMBINING TILDE}') == 'aãa' assert center_accent('aaaa', '\N{COMBINING TILDE}') == 'aaãa' assert center_accent('aaaaa', '\N{COMBINING TILDE}') == 'aaãaa' assert center_accent('abcdefg', '\N{COMBINING FOUR DOTS ABOVE}') == 'abcd⃜efg' def test_imaginary_unit(): from sympy import pretty # As it is redefined above assert pretty(1 + I, use_unicode=False) == '1 + I' assert pretty(1 + I, use_unicode=True) == '1 + ⅈ' assert pretty(1 + I, use_unicode=False, imaginary_unit='j') == '1 + I' assert pretty(1 + I, use_unicode=True, imaginary_unit='j') == '1 + ⅉ' raises(TypeError, lambda: pretty(I, imaginary_unit=I)) raises(ValueError, lambda: pretty(I, imaginary_unit="kkk")) def test_str_special_matrices(): from sympy.matrices import Identity, ZeroMatrix, OneMatrix assert pretty(Identity(4)) == 'I' assert upretty(Identity(4)) == '𝕀' assert pretty(ZeroMatrix(2, 2)) == '0' assert upretty(ZeroMatrix(2, 2)) == '𝟘' assert pretty(OneMatrix(2, 2)) == '1' assert upretty(OneMatrix(2, 2)) == '𝟙' def test_pretty_misc_functions(): assert pretty(LambertW(x)) == 'W(x)' assert upretty(LambertW(x)) == 'W(x)' assert pretty(LambertW(x, y)) == 'W(x, y)' assert upretty(LambertW(x, y)) == 'W(x, y)' assert pretty(airyai(x)) == 'Ai(x)' assert upretty(airyai(x)) == 'Ai(x)' assert pretty(airybi(x)) == 'Bi(x)' assert upretty(airybi(x)) == 'Bi(x)' assert pretty(airyaiprime(x)) == "Ai'(x)" assert upretty(airyaiprime(x)) == "Ai'(x)" assert pretty(airybiprime(x)) == "Bi'(x)" assert upretty(airybiprime(x)) == "Bi'(x)" assert pretty(fresnelc(x)) == 'C(x)' assert upretty(fresnelc(x)) == 'C(x)' assert pretty(fresnels(x)) == 'S(x)' assert upretty(fresnels(x)) == 'S(x)' assert pretty(Heaviside(x)) == 'Heaviside(x)' assert upretty(Heaviside(x)) == 'θ(x)' assert pretty(Heaviside(x, y)) == 'Heaviside(x, y)' assert upretty(Heaviside(x, y)) == 'θ(x, y)' assert pretty(dirichlet_eta(x)) == 'dirichlet_eta(x)' assert upretty(dirichlet_eta(x)) == 'η(x)' def test_hadamard_power(): m, n, p = symbols('m, n, p', integer=True) A = MatrixSymbol('A', m, n) B = MatrixSymbol('B', m, n) # Testing printer: expr = hadamard_power(A, n) ascii_str = \ """\ .n\n\ A \ """ ucode_str = \ """\ ∘n\n\ A \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = hadamard_power(A, 1+n) ascii_str = \ """\ .(n + 1)\n\ A \ """ ucode_str = \ """\ ∘(n + 1)\n\ A \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str expr = hadamard_power(A*B.T, 1+n) ascii_str = \ """\ .(n + 1)\n\ / T\\ \n\ \\A*B / \ """ ucode_str = \ """\ ∘(n + 1)\n\ ⎛ T⎞ \n\ ⎝A⋅B ⎠ \ """ assert pretty(expr) == ascii_str assert upretty(expr) == ucode_str def test_issue_17258(): n = Symbol('n', integer=True) assert pretty(Sum(n, (n, -oo, 1))) == \ ' 1 \n'\ ' __ \n'\ ' \\ ` \n'\ ' ) n\n'\ ' /_, \n'\ 'n = -oo ' assert upretty(Sum(n, (n, -oo, 1))) == \ """\ 1 \n\ ___ \n\ ╲ \n\ ╲ \n\ ╱ n\n\ ╱ \n\ ‾‾‾ \n\ n = -∞ \ """ def test_is_combining(): line = "v̇_m" assert [is_combining(sym) for sym in line] == \ [False, True, False, False] def test_issue_17616(): assert pretty(pi**(1/exp(1))) == \ ' / -1\\\n'\ ' \\e /\n'\ 'pi ' assert upretty(pi**(1/exp(1))) == \ ' ⎛ -1⎞\n'\ ' ⎝ℯ ⎠\n'\ 'π ' assert pretty(pi**(1/pi)) == \ ' 1 \n'\ ' --\n'\ ' pi\n'\ 'pi ' assert upretty(pi**(1/pi)) == \ ' 1\n'\ ' ─\n'\ ' π\n'\ 'π ' assert pretty(pi**(1/EulerGamma)) == \ ' 1 \n'\ ' ----------\n'\ ' EulerGamma\n'\ 'pi ' assert upretty(pi**(1/EulerGamma)) == \ ' 1\n'\ ' ─\n'\ ' γ\n'\ 'π ' z = Symbol("x_17") assert upretty(7**(1/z)) == \ 'x₁₇___\n'\ ' ╲╱ 7 ' assert pretty(7**(1/z)) == \ 'x_17___\n'\ ' \\/ 7 ' def test_issue_17857(): assert pretty(Range(-oo, oo)) == '{..., -1, 0, 1, ...}' assert pretty(Range(oo, -oo, -1)) == '{..., 1, 0, -1, ...}' def test_issue_18272(): x = Symbol('x') n = Symbol('n') assert upretty(ConditionSet(x, Eq(-x + exp(x), 0), S.Complexes)) == \ '⎧ │ ⎛ x ⎞⎫\n'\ '⎨x │ x ∊ ℂ ∧ ⎝-x + ℯ = 0⎠⎬\n'\ '⎩ │ ⎭' assert upretty(ConditionSet(x, Contains(n/2, Interval(0, oo)), FiniteSet(-n/2, n/2))) == \ '⎧ │ ⎧-n n⎫ ⎛n ⎞⎫\n'\ '⎨x │ x ∊ ⎨───, ─⎬ ∧ ⎜─ ∈ [0, ∞)⎟⎬\n'\ '⎩ │ ⎩ 2 2⎭ ⎝2 ⎠⎭' assert upretty(ConditionSet(x, Eq(Piecewise((1, x >= 3), (x/2 - 1/2, x >= 2), (1/2, x >= 1), (x/2, True)) - 1/2, 0), Interval(0, 3))) == \ '⎧ │ ⎛⎛⎧ 1 for x ≥ 3⎞ ⎞⎫\n'\ '⎪ │ ⎜⎜⎪ ⎟ ⎟⎪\n'\ '⎪ │ ⎜⎜⎪x ⎟ ⎟⎪\n'\ '⎪ │ ⎜⎜⎪─ - 0.5 for x ≥ 2⎟ ⎟⎪\n'\ '⎪ │ ⎜⎜⎪2 ⎟ ⎟⎪\n'\ '⎨x │ x ∊ [0, 3] ∧ ⎜⎜⎨ ⎟ - 0.5 = 0⎟⎬\n'\ '⎪ │ ⎜⎜⎪ 0.5 for x ≥ 1⎟ ⎟⎪\n'\ '⎪ │ ⎜⎜⎪ ⎟ ⎟⎪\n'\ '⎪ │ ⎜⎜⎪ x ⎟ ⎟⎪\n'\ '⎪ │ ⎜⎜⎪ ─ otherwise⎟ ⎟⎪\n'\ '⎩ │ ⎝⎝⎩ 2 ⎠ ⎠⎭' def test_Str(): from sympy.core.symbol import Str assert pretty(Str('x')) == 'x' def test_diffgeom(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField x,y = symbols('x y', real=True) m = Manifold('M', 2) assert pretty(m) == 'M' p = Patch('P', m) assert pretty(p) == "P" rect = CoordSystem('rect', p, [x, y]) assert pretty(rect) == "rect" b = BaseScalarField(rect, 0) assert pretty(b) == "x" sympy-sympy-1.9/sympy/printing/preview.py000066400000000000000000000270361412543434000210010ustar00rootroot00000000000000import os from os.path import join import shutil import tempfile try: from subprocess import STDOUT, CalledProcessError, check_output except ImportError: pass from sympy.utilities.decorator import doctest_depends_on from .latex import latex __doctest_requires__ = {('preview',): ['pyglet']} def _check_output_no_window(*args, **kwargs): # Avoid showing a cmd.exe window when running this # on Windows if os.name == 'nt': creation_flag = 0x08000000 # CREATE_NO_WINDOW else: creation_flag = 0 # Default value return check_output(*args, creationflags=creation_flag, **kwargs) def _run_pyglet(fname, fmt): from pyglet import window, image, gl from pyglet.window import key if fmt == "png": from pyglet.image.codecs.png import PNGImageDecoder img = image.load(fname, decoder=PNGImageDecoder()) else: raise ValueError("pyglet preview works only for 'png' files.") offset = 25 config = gl.Config(double_buffer=False) win = window.Window( width=img.width + 2*offset, height=img.height + 2*offset, caption="sympy", resizable=False, config=config ) win.set_vsync(False) try: def on_close(): win.has_exit = True win.on_close = on_close def on_key_press(symbol, modifiers): if symbol in [key.Q, key.ESCAPE]: on_close() win.on_key_press = on_key_press def on_expose(): gl.glClearColor(1.0, 1.0, 1.0, 1.0) gl.glClear(gl.GL_COLOR_BUFFER_BIT) img.blit( (win.width - img.width) / 2, (win.height - img.height) / 2 ) win.on_expose = on_expose while not win.has_exit: win.dispatch_events() win.flip() except KeyboardInterrupt: pass win.close() @doctest_depends_on(exe=('latex', 'dvipng'), modules=('pyglet',), disable_viewers=('evince', 'gimp', 'superior-dvi-viewer')) def preview(expr, output='png', viewer=None, euler=True, packages=(), filename=None, outputbuffer=None, preamble=None, dvioptions=None, outputTexFile=None, **latex_settings): r""" View expression or LaTeX markup in PNG, DVI, PostScript or PDF form. If the expr argument is an expression, it will be exported to LaTeX and then compiled using the available TeX distribution. The first argument, 'expr', may also be a LaTeX string. The function will then run the appropriate viewer for the given output format or use the user defined one. By default png output is generated. By default pretty Euler fonts are used for typesetting (they were used to typeset the well known "Concrete Mathematics" book). For that to work, you need the 'eulervm.sty' LaTeX style (in Debian/Ubuntu, install the texlive-fonts-extra package). If you prefer default AMS fonts or your system lacks 'eulervm' LaTeX package then unset the 'euler' keyword argument. To use viewer auto-detection, lets say for 'png' output, issue >>> from sympy import symbols, preview, Symbol >>> x, y = symbols("x,y") >>> preview(x + y, output='png') This will choose 'pyglet' by default. To select a different one, do >>> preview(x + y, output='png', viewer='gimp') The 'png' format is considered special. For all other formats the rules are slightly different. As an example we will take 'dvi' output format. If you would run >>> preview(x + y, output='dvi') then 'view' will look for available 'dvi' viewers on your system (predefined in the function, so it will try evince, first, then kdvi and xdvi). If nothing is found you will need to set the viewer explicitly. >>> preview(x + y, output='dvi', viewer='superior-dvi-viewer') This will skip auto-detection and will run user specified 'superior-dvi-viewer'. If 'view' fails to find it on your system it will gracefully raise an exception. You may also enter 'file' for the viewer argument. Doing so will cause this function to return a file object in read-only mode, if 'filename' is unset. However, if it was set, then 'preview' writes the genereted file to this filename instead. There is also support for writing to a BytesIO like object, which needs to be passed to the 'outputbuffer' argument. >>> from io import BytesIO >>> obj = BytesIO() >>> preview(x + y, output='png', viewer='BytesIO', ... outputbuffer=obj) The LaTeX preamble can be customized by setting the 'preamble' keyword argument. This can be used, e.g., to set a different font size, use a custom documentclass or import certain set of LaTeX packages. >>> preamble = "\\documentclass[10pt]{article}\n" \ ... "\\usepackage{amsmath,amsfonts}\\begin{document}" >>> preview(x + y, output='png', preamble=preamble) If the value of 'output' is different from 'dvi' then command line options can be set ('dvioptions' argument) for the execution of the 'dvi'+output conversion tool. These options have to be in the form of a list of strings (see subprocess.Popen). Additional keyword args will be passed to the latex call, e.g., the symbol_names flag. >>> phidd = Symbol('phidd') >>> preview(phidd, symbol_names={phidd:r'\ddot{\varphi}'}) For post-processing the generated TeX File can be written to a file by passing the desired filename to the 'outputTexFile' keyword argument. To write the TeX code to a file named "sample.tex" and run the default png viewer to display the resulting bitmap, do >>> preview(x + y, outputTexFile="sample.tex") """ special = [ 'pyglet' ] if viewer is None: if output == "png": viewer = "pyglet" else: # sorted in order from most pretty to most ugly # very discussable, but indeed 'gv' looks awful :) # TODO add candidates for windows to list candidates = { "dvi": [ "evince", "okular", "kdvi", "xdvi" ], "ps": [ "evince", "okular", "gsview", "gv" ], "pdf": [ "evince", "okular", "kpdf", "acroread", "xpdf", "gv" ], } try: candidate_viewers = candidates[output] except KeyError: raise ValueError("Invalid output format: %s" % output) from None for candidate in candidate_viewers: path = shutil.which(candidate) if path is not None: viewer = path break else: raise OSError( "No viewers found for '%s' output format." % output) else: if viewer == "file": if filename is None: raise ValueError("filename has to be specified if viewer=\"file\"") elif viewer == "BytesIO": if outputbuffer is None: raise ValueError("outputbuffer has to be a BytesIO " "compatible object if viewer=\"BytesIO\"") elif viewer not in special and not shutil.which(viewer): raise OSError("Unrecognized viewer: %s" % viewer) if preamble is None: actual_packages = packages + ("amsmath", "amsfonts") if euler: actual_packages += ("euler",) package_includes = "\n" + "\n".join(["\\usepackage{%s}" % p for p in actual_packages]) preamble = r"""\documentclass[varwidth,12pt]{standalone} %s \begin{document} """ % (package_includes) else: if packages: raise ValueError("The \"packages\" keyword must not be set if a " "custom LaTeX preamble was specified") if isinstance(expr, str): latex_string = expr else: latex_string = ('$\\displaystyle ' + latex(expr, mode='plain', **latex_settings) + '$') latex_main = preamble + '\n' + latex_string + '\n\n' + r"\end{document}" with tempfile.TemporaryDirectory() as workdir: with open(join(workdir, 'texput.tex'), 'w', encoding='utf-8') as fh: fh.write(latex_main) if outputTexFile is not None: shutil.copyfile(join(workdir, 'texput.tex'), outputTexFile) if not shutil.which('latex'): raise RuntimeError("latex program is not installed") try: _check_output_no_window( ['latex', '-halt-on-error', '-interaction=nonstopmode', 'texput.tex'], cwd=workdir, stderr=STDOUT) except CalledProcessError as e: raise RuntimeError( "'latex' exited abnormally with the following output:\n%s" % e.output) src = "texput.%s" % (output) if output != "dvi": # in order of preference commandnames = { "ps": ["dvips"], "pdf": ["dvipdfmx", "dvipdfm", "dvipdf"], "png": ["dvipng"], "svg": ["dvisvgm"], } try: cmd_variants = commandnames[output] except KeyError: raise ValueError("Invalid output format: %s" % output) from None # find an appropriate command for cmd_variant in cmd_variants: cmd_path = shutil.which(cmd_variant) if cmd_path: cmd = [cmd_path] break else: if len(cmd_variants) > 1: raise RuntimeError("None of %s are installed" % ", ".join(cmd_variants)) else: raise RuntimeError("%s is not installed" % cmd_variants[0]) defaultoptions = { "dvipng": ["-T", "tight", "-z", "9", "--truecolor"], "dvisvgm": ["--no-fonts"], } commandend = { "dvips": ["-o", src, "texput.dvi"], "dvipdf": ["texput.dvi", src], "dvipdfm": ["-o", src, "texput.dvi"], "dvipdfmx": ["-o", src, "texput.dvi"], "dvipng": ["-o", src, "texput.dvi"], "dvisvgm": ["-o", src, "texput.dvi"], } if dvioptions is not None: cmd.extend(dvioptions) else: cmd.extend(defaultoptions.get(cmd_variant, [])) cmd.extend(commandend[cmd_variant]) try: _check_output_no_window(cmd, cwd=workdir, stderr=STDOUT) except CalledProcessError as e: raise RuntimeError( "'%s' exited abnormally with the following output:\n%s" % (' '.join(cmd), e.output)) if viewer == "file": shutil.move(join(workdir, src), filename) elif viewer == "BytesIO": with open(join(workdir, src), 'rb') as fh: outputbuffer.write(fh.read()) elif viewer == "pyglet": try: import pyglet # noqa: F401 except ImportError: raise ImportError("pyglet is required for preview.\n visit http://www.pyglet.org/") return _run_pyglet(join(workdir, src), fmt=output) else: try: _check_output_no_window( [viewer, src], cwd=workdir, stderr=STDOUT) except CalledProcessError as e: raise RuntimeError( "'%s %s' exited abnormally with the following output:\n%s" % (viewer, src, e.output)) sympy-sympy-1.9/sympy/printing/printer.py000066400000000000000000000342101412543434000207730ustar00rootroot00000000000000"""Printing subsystem driver SymPy's printing system works the following way: Any expression can be passed to a designated Printer who then is responsible to return an adequate representation of that expression. **The basic concept is the following:** 1. Let the object print itself if it knows how. 2. Take the best fitting method defined in the printer. 3. As fall-back use the emptyPrinter method for the printer. Which Method is Responsible for Printing? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The whole printing process is started by calling ``.doprint(expr)`` on the printer which you want to use. This method looks for an appropriate method which can print the given expression in the given style that the printer defines. While looking for the method, it follows these steps: 1. **Let the object print itself if it knows how.** The printer looks for a specific method in every object. The name of that method depends on the specific printer and is defined under ``Printer.printmethod``. For example, StrPrinter calls ``_sympystr`` and LatexPrinter calls ``_latex``. Look at the documentation of the printer that you want to use. The name of the method is specified there. This was the original way of doing printing in sympy. Every class had its own latex, mathml, str and repr methods, but it turned out that it is hard to produce a high quality printer, if all the methods are spread out that far. Therefore all printing code was combined into the different printers, which works great for built-in sympy objects, but not that good for user defined classes where it is inconvenient to patch the printers. 2. **Take the best fitting method defined in the printer.** The printer loops through expr classes (class + its bases), and tries to dispatch the work to ``_print_`` e.g., suppose we have the following class hierarchy:: Basic | Atom | Number | Rational then, for ``expr=Rational(...)``, the Printer will try to call printer methods in the order as shown in the figure below:: p._print(expr) | |-- p._print_Rational(expr) | |-- p._print_Number(expr) | |-- p._print_Atom(expr) | `-- p._print_Basic(expr) if ``._print_Rational`` method exists in the printer, then it is called, and the result is returned back. Otherwise, the printer tries to call ``._print_Number`` and so on. 3. **As a fall-back use the emptyPrinter method for the printer.** As fall-back ``self.emptyPrinter`` will be called with the expression. If not defined in the Printer subclass this will be the same as ``str(expr)``. .. _printer_example: Example of Custom Printer ^^^^^^^^^^^^^^^^^^^^^^^^^ In the example below, we have a printer which prints the derivative of a function in a shorter form. .. code-block:: python from sympy import Symbol from sympy.printing.latex import LatexPrinter, print_latex from sympy.core.function import UndefinedFunction, Function class MyLatexPrinter(LatexPrinter): \"\"\"Print derivative of a function of symbols in a shorter form. \"\"\" def _print_Derivative(self, expr): function, *vars = expr.args if not isinstance(type(function), UndefinedFunction) or \\ not all(isinstance(i, Symbol) for i in vars): return super()._print_Derivative(expr) # If you want the printer to work correctly for nested # expressions then use self._print() instead of str() or latex(). # See the example of nested modulo below in the custom printing # method section. return "{}_{{{}}}".format( self._print(Symbol(function.func.__name__)), ''.join(self._print(i) for i in vars)) def print_my_latex(expr): \"\"\" Most of the printers define their own wrappers for print(). These wrappers usually take printer settings. Our printer does not have any settings. \"\"\" print(MyLatexPrinter().doprint(expr)) y = Symbol("y") x = Symbol("x") f = Function("f") expr = f(x, y).diff(x, y) # Print the expression using the normal latex printer and our custom # printer. print_latex(expr) print_my_latex(expr) The output of the code above is:: \\frac{\\partial^{2}}{\\partial x\\partial y} f{\\left(x,y \\right)} f_{xy} .. _printer_method_example: Example of Custom Printing Method ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In the example below, the latex printing of the modulo operator is modified. This is done by overriding the method ``_latex`` of ``Mod``. >>> from sympy import Symbol, Mod, Integer >>> from sympy.printing.latex import print_latex >>> # Always use printer._print() >>> class ModOp(Mod): ... def _latex(self, printer): ... a, b = [printer._print(i) for i in self.args] ... return r"\\operatorname{Mod}{\\left( %s,%s \\right)}" % (a,b) Comparing the output of our custom operator to the builtin one: >>> x = Symbol('x') >>> m = Symbol('m') >>> print_latex(Mod(x, m)) x\\bmod{m} >>> print_latex(ModOp(x, m)) \\operatorname{Mod}{\\left( x,m \\right)} Common mistakes ~~~~~~~~~~~~~~~ It's important to always use ``self._print(obj)`` to print subcomponents of an expression when customizing a printer. Mistakes include: 1. Using ``self.doprint(obj)`` instead: >>> # This example does not work properly, as only the outermost call may use >>> # doprint. >>> class ModOpModeWrong(Mod): ... def _latex(self, printer): ... a, b = [printer.doprint(i) for i in self.args] ... return r"\\operatorname{Mod}{\\left( %s,%s \\right)}" % (a,b) This fails when the `mode` argument is passed to the printer: >>> print_latex(ModOp(x, m), mode='inline') # ok $\\operatorname{Mod}{\\left( x,m \\right)}$ >>> print_latex(ModOpModeWrong(x, m), mode='inline') # bad $\\operatorname{Mod}{\\left( $x$,$m$ \\right)}$ 2. Using ``str(obj)`` instead: >>> class ModOpNestedWrong(Mod): ... def _latex(self, printer): ... a, b = [str(i) for i in self.args] ... return r"\\operatorname{Mod}{\\left( %s,%s \\right)}" % (a,b) This fails on nested objects: >>> # Nested modulo. >>> print_latex(ModOp(ModOp(x, m), Integer(7))) # ok \\operatorname{Mod}{\\left( \\operatorname{Mod}{\\left( x,m \\right)},7 \\right)} >>> print_latex(ModOpNestedWrong(ModOpNestedWrong(x, m), Integer(7))) # bad \\operatorname{Mod}{\\left( ModOpNestedWrong(x, m),7 \\right)} 3. Using ``LatexPrinter()._print(obj)`` instead. >>> from sympy.printing.latex import LatexPrinter >>> class ModOpSettingsWrong(Mod): ... def _latex(self, printer): ... a, b = [LatexPrinter()._print(i) for i in self.args] ... return r"\\operatorname{Mod}{\\left( %s,%s \\right)}" % (a,b) This causes all the settings to be discarded in the subobjects. As an example, the ``full_prec`` setting which shows floats to full precision is ignored: >>> from sympy import Float >>> print_latex(ModOp(Float(1) * x, m), full_prec=True) # ok \\operatorname{Mod}{\\left( 1.00000000000000 x,m \\right)} >>> print_latex(ModOpSettingsWrong(Float(1) * x, m), full_prec=True) # bad \\operatorname{Mod}{\\left( 1.0 x,m \\right)} """ import sys from typing import Any, Dict, Type import inspect from contextlib import contextmanager from functools import cmp_to_key, update_wrapper from sympy import Basic, Add from sympy.core.core import BasicMeta from sympy.core.function import AppliedUndef, UndefinedFunction, Function @contextmanager def printer_context(printer, **kwargs): original = printer._context.copy() try: printer._context.update(kwargs) yield finally: printer._context = original class Printer: """ Generic printer Its job is to provide infrastructure for implementing new printers easily. If you want to define your custom Printer or your custom printing method for your custom class then see the example above: printer_example_ . """ _global_settings = {} # type: Dict[str, Any] _default_settings = {} # type: Dict[str, Any] printmethod = None # type: str @classmethod def _get_initial_settings(cls): settings = cls._default_settings.copy() for key, val in cls._global_settings.items(): if key in cls._default_settings: settings[key] = val return settings def __init__(self, settings=None): self._str = str self._settings = self._get_initial_settings() self._context = dict() # mutable during printing if settings is not None: self._settings.update(settings) if len(self._settings) > len(self._default_settings): for key in self._settings: if key not in self._default_settings: raise TypeError("Unknown setting '%s'." % key) # _print_level is the number of times self._print() was recursively # called. See StrPrinter._print_Float() for an example of usage self._print_level = 0 @classmethod def set_global_settings(cls, **settings): """Set system-wide printing settings. """ for key, val in settings.items(): if val is not None: cls._global_settings[key] = val @property def order(self): if 'order' in self._settings: return self._settings['order'] else: raise AttributeError("No order defined.") def doprint(self, expr): """Returns printer's representation for expr (as a string)""" return self._str(self._print(expr)) def _print(self, expr, **kwargs): """Internal dispatcher Tries the following concepts to print an expression: 1. Let the object print itself if it knows how. 2. Take the best fitting method defined in the printer. 3. As fall-back use the emptyPrinter method for the printer. """ self._print_level += 1 try: # If the printer defines a name for a printing method # (Printer.printmethod) and the object knows for itself how it # should be printed, use that method. if (self.printmethod and hasattr(expr, self.printmethod) and not isinstance(expr, BasicMeta)): return getattr(expr, self.printmethod)(self, **kwargs) # See if the class of expr is known, or if one of its super # classes is known, and use that print function # Exception: ignore the subclasses of Undefined, so that, e.g., # Function('gamma') does not get dispatched to _print_gamma classes = type(expr).__mro__ if AppliedUndef in classes: classes = classes[classes.index(AppliedUndef):] if UndefinedFunction in classes: classes = classes[classes.index(UndefinedFunction):] # Another exception: if someone subclasses a known function, e.g., # gamma, and changes the name, then ignore _print_gamma if Function in classes: i = classes.index(Function) classes = tuple(c for c in classes[:i] if \ c.__name__ == classes[0].__name__ or \ c.__name__.endswith("Base")) + classes[i:] for cls in classes: printmethodname = '_print_' + cls.__name__ printmethod = getattr(self, printmethodname, None) if printmethod is not None: return printmethod(expr, **kwargs) # Unknown object, fall back to the emptyPrinter. return self.emptyPrinter(expr) finally: self._print_level -= 1 def emptyPrinter(self, expr): return str(expr) def _as_ordered_terms(self, expr, order=None): """A compatibility function for ordering terms in Add. """ order = order or self.order if order == 'old': return sorted(Add.make_args(expr), key=cmp_to_key(Basic._compare_pretty)) elif order == 'none': return list(expr.args) else: return expr.as_ordered_terms(order=order) class _PrintFunction: """ Function wrapper to replace ``**settings`` in the signature with printer defaults """ def __init__(self, f, print_cls: Type[Printer]): # find all the non-setting arguments params = list(inspect.signature(f).parameters.values()) assert params.pop(-1).kind == inspect.Parameter.VAR_KEYWORD self.__other_params = params self.__print_cls = print_cls update_wrapper(self, f) def __reduce__(self): # Since this is used as a decorator, it replaces the original function. # The default pickling will try to pickle self.__wrapped__ and fail # because the wrapped function can't be retrieved by name. return self.__wrapped__.__qualname__ def __call__(self, *args, **kwargs): return self.__wrapped__(*args, **kwargs) @property def __signature__(self) -> inspect.Signature: settings = self.__print_cls._get_initial_settings() return inspect.Signature( parameters=self.__other_params + [ inspect.Parameter(k, inspect.Parameter.KEYWORD_ONLY, default=v) for k, v in settings.items() ], return_annotation=self.__wrapped__.__annotations__.get('return', inspect.Signature.empty) # type:ignore ) def print_function(print_cls): """ A decorator to replace kwargs with the printer settings in __signature__ """ def decorator(f): if sys.version_info < (3, 9): # We have to create a subclass so that `help` actually shows the docstring in older python versions. # IPython and Sphinx do not need this, only a raw python console. cls = type(f'{f.__qualname__}_PrintFunction', (_PrintFunction,), dict(__doc__=f.__doc__)) else: cls = _PrintFunction return cls(f, print_cls) return decorator sympy-sympy-1.9/sympy/printing/pycode.py000066400000000000000000000467761412543434000206170ustar00rootroot00000000000000""" Python code printers This module contains python code printers for plain python as well as NumPy & SciPy enabled code. """ from collections import defaultdict from itertools import chain from sympy.core import S from .precedence import precedence from .codeprinter import CodePrinter _kw_py2and3 = { 'and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield', 'None' # 'None' is actually not in Python 2's keyword.kwlist } _kw_only_py2 = {'exec', 'print'} _kw_only_py3 = {'False', 'nonlocal', 'True'} _known_functions = { 'Abs': 'abs', } _known_functions_math = { 'acos': 'acos', 'acosh': 'acosh', 'asin': 'asin', 'asinh': 'asinh', 'atan': 'atan', 'atan2': 'atan2', 'atanh': 'atanh', 'ceiling': 'ceil', 'cos': 'cos', 'cosh': 'cosh', 'erf': 'erf', 'erfc': 'erfc', 'exp': 'exp', 'expm1': 'expm1', 'factorial': 'factorial', 'floor': 'floor', 'gamma': 'gamma', 'hypot': 'hypot', 'loggamma': 'lgamma', 'log': 'log', 'ln': 'log', 'log10': 'log10', 'log1p': 'log1p', 'log2': 'log2', 'sin': 'sin', 'sinh': 'sinh', 'Sqrt': 'sqrt', 'tan': 'tan', 'tanh': 'tanh' } # Not used from ``math``: [copysign isclose isfinite isinf isnan ldexp frexp pow modf # radians trunc fmod fsum gcd degrees fabs] _known_constants_math = { 'Exp1': 'e', 'Pi': 'pi', 'E': 'e' # Only in python >= 3.5: # 'Infinity': 'inf', # 'NaN': 'nan' } def _print_known_func(self, expr): known = self.known_functions[expr.__class__.__name__] return '{name}({args})'.format(name=self._module_format(known), args=', '.join(map(lambda arg: self._print(arg), expr.args))) def _print_known_const(self, expr): known = self.known_constants[expr.__class__.__name__] return self._module_format(known) class AbstractPythonCodePrinter(CodePrinter): printmethod = "_pythoncode" language = "Python" reserved_words = _kw_py2and3.union(_kw_only_py3) modules = None # initialized to a set in __init__ tab = ' ' _kf = dict(chain( _known_functions.items(), [(k, 'math.' + v) for k, v in _known_functions_math.items()] )) _kc = {k: 'math.'+v for k, v in _known_constants_math.items()} _operators = {'and': 'and', 'or': 'or', 'not': 'not'} _default_settings = dict( CodePrinter._default_settings, user_functions={}, precision=17, inline=True, fully_qualified_modules=True, contract=False, standard='python3', ) def __init__(self, settings=None): super().__init__(settings) # Python standard handler std = self._settings['standard'] if std is None: import sys std = 'python{}'.format(sys.version_info.major) if std not in ('python2', 'python3'): raise ValueError('Unrecognized python standard : {}'.format(std)) self.standard = std self.module_imports = defaultdict(set) # Known functions and constants handler self.known_functions = dict(self._kf, **(settings or {}).get( 'user_functions', {})) self.known_constants = dict(self._kc, **(settings or {}).get( 'user_constants', {})) def _declare_number_const(self, name, value): return "%s = %s" % (name, value) def _module_format(self, fqn, register=True): parts = fqn.split('.') if register and len(parts) > 1: self.module_imports['.'.join(parts[:-1])].add(parts[-1]) if self._settings['fully_qualified_modules']: return fqn else: return fqn.split('(')[0].split('[')[0].split('.')[-1] def _format_code(self, lines): return lines def _get_statement(self, codestring): return "{}".format(codestring) def _get_comment(self, text): return " # {}".format(text) def _expand_fold_binary_op(self, op, args): """ This method expands a fold on binary operations. ``functools.reduce`` is an example of a folded operation. For example, the expression `A + B + C + D` is folded into `((A + B) + C) + D` """ if len(args) == 1: return self._print(args[0]) else: return "%s(%s, %s)" % ( self._module_format(op), self._expand_fold_binary_op(op, args[:-1]), self._print(args[-1]), ) def _expand_reduce_binary_op(self, op, args): """ This method expands a reductin on binary operations. Notice: this is NOT the same as ``functools.reduce``. For example, the expression `A + B + C + D` is reduced into: `(A + B) + (C + D)` """ if len(args) == 1: return self._print(args[0]) else: N = len(args) Nhalf = N // 2 return "%s(%s, %s)" % ( self._module_format(op), self._expand_reduce_binary_op(args[:Nhalf]), self._expand_reduce_binary_op(args[Nhalf:]), ) def _get_einsum_string(self, subranks, contraction_indices): letters = self._get_letter_generator_for_einsum() contraction_string = "" counter = 0 d = {j: min(i) for i in contraction_indices for j in i} indices = [] for rank_arg in subranks: lindices = [] for i in range(rank_arg): if counter in d: lindices.append(d[counter]) else: lindices.append(counter) counter += 1 indices.append(lindices) mapping = {} letters_free = [] letters_dum = [] for i in indices: for j in i: if j not in mapping: l = next(letters) mapping[j] = l else: l = mapping[j] contraction_string += l if j in d: if l not in letters_dum: letters_dum.append(l) else: letters_free.append(l) contraction_string += "," contraction_string = contraction_string[:-1] return contraction_string, letters_free, letters_dum def _print_NaN(self, expr): return "float('nan')" def _print_Infinity(self, expr): return "float('inf')" def _print_NegativeInfinity(self, expr): return "float('-inf')" def _print_ComplexInfinity(self, expr): return self._print_NaN(expr) def _print_Mod(self, expr): PREC = precedence(expr) return ('{} % {}'.format(*map(lambda x: self.parenthesize(x, PREC), expr.args))) def _print_Piecewise(self, expr): result = [] i = 0 for arg in expr.args: e = arg.expr c = arg.cond if i == 0: result.append('(') result.append('(') result.append(self._print(e)) result.append(')') result.append(' if ') result.append(self._print(c)) result.append(' else ') i += 1 result = result[:-1] if result[-1] == 'True': result = result[:-2] result.append(')') else: result.append(' else None)') return ''.join(result) def _print_Relational(self, expr): "Relational printer for Equality and Unequality" op = { '==' :'equal', '!=' :'not_equal', '<' :'less', '<=' :'less_equal', '>' :'greater', '>=' :'greater_equal', } if expr.rel_op in op: lhs = self._print(expr.lhs) rhs = self._print(expr.rhs) return '({lhs} {op} {rhs})'.format(op=expr.rel_op, lhs=lhs, rhs=rhs) return super()._print_Relational(expr) def _print_ITE(self, expr): from sympy.functions.elementary.piecewise import Piecewise return self._print(expr.rewrite(Piecewise)) def _print_Sum(self, expr): loops = ( 'for {i} in range({a}, {b}+1)'.format( i=self._print(i), a=self._print(a), b=self._print(b)) for i, a, b in expr.limits) return '(builtins.sum({function} {loops}))'.format( function=self._print(expr.function), loops=' '.join(loops)) def _print_ImaginaryUnit(self, expr): return '1j' def _print_KroneckerDelta(self, expr): a, b = expr.args return '(1 if {a} == {b} else 0)'.format( a = self._print(a), b = self._print(b) ) def _print_MatrixBase(self, expr): name = expr.__class__.__name__ func = self.known_functions.get(name, name) return "%s(%s)" % (func, self._print(expr.tolist())) _print_SparseMatrix = \ _print_MutableSparseMatrix = \ _print_ImmutableSparseMatrix = \ _print_Matrix = \ _print_DenseMatrix = \ _print_MutableDenseMatrix = \ _print_ImmutableMatrix = \ _print_ImmutableDenseMatrix = \ lambda self, expr: self._print_MatrixBase(expr) def _indent_codestring(self, codestring): return '\n'.join([self.tab + line for line in codestring.split('\n')]) def _print_FunctionDefinition(self, fd): body = '\n'.join(map(lambda arg: self._print(arg), fd.body)) return "def {name}({parameters}):\n{body}".format( name=self._print(fd.name), parameters=', '.join([self._print(var.symbol) for var in fd.parameters]), body=self._indent_codestring(body) ) def _print_While(self, whl): body = '\n'.join(map(lambda arg: self._print(arg), whl.body)) return "while {cond}:\n{body}".format( cond=self._print(whl.condition), body=self._indent_codestring(body) ) def _print_Declaration(self, decl): return '%s = %s' % ( self._print(decl.variable.symbol), self._print(decl.variable.value) ) def _print_Return(self, ret): arg, = ret.args return 'return %s' % self._print(arg) def _print_Print(self, prnt): print_args = ', '.join(map(lambda arg: self._print(arg), prnt.print_args)) if prnt.format_string != None: # Must be '!= None', cannot be 'is not None' print_args = '{} % ({})'.format( self._print(prnt.format_string), print_args) if prnt.file != None: # Must be '!= None', cannot be 'is not None' print_args += ', file=%s' % self._print(prnt.file) if self.standard == 'python2': return 'print %s' % print_args return 'print(%s)' % print_args def _print_Stream(self, strm): if str(strm.name) == 'stdout': return self._module_format('sys.stdout') elif str(strm.name) == 'stderr': return self._module_format('sys.stderr') else: return self._print(strm.name) def _print_NoneToken(self, arg): return 'None' def _hprint_Pow(self, expr, rational=False, sqrt='math.sqrt'): """Printing helper function for ``Pow`` Notes ===== This only preprocesses the ``sqrt`` as math formatter Examples ======== >>> from sympy.functions import sqrt >>> from sympy.printing.pycode import PythonCodePrinter >>> from sympy.abc import x Python code printer automatically looks up ``math.sqrt``. >>> printer = PythonCodePrinter({'standard':'python3'}) >>> printer._hprint_Pow(sqrt(x), rational=True) 'x**(1/2)' >>> printer._hprint_Pow(sqrt(x), rational=False) 'math.sqrt(x)' >>> printer._hprint_Pow(1/sqrt(x), rational=True) 'x**(-1/2)' >>> printer._hprint_Pow(1/sqrt(x), rational=False) '1/math.sqrt(x)' Using sqrt from numpy or mpmath >>> printer._hprint_Pow(sqrt(x), sqrt='numpy.sqrt') 'numpy.sqrt(x)' >>> printer._hprint_Pow(sqrt(x), sqrt='mpmath.sqrt') 'mpmath.sqrt(x)' See Also ======== sympy.printing.str.StrPrinter._print_Pow """ PREC = precedence(expr) if expr.exp == S.Half and not rational: func = self._module_format(sqrt) arg = self._print(expr.base) return '{func}({arg})'.format(func=func, arg=arg) if expr.is_commutative: if -expr.exp is S.Half and not rational: func = self._module_format(sqrt) num = self._print(S.One) arg = self._print(expr.base) return "{num}/{func}({arg})".format( num=num, func=func, arg=arg) base_str = self.parenthesize(expr.base, PREC, strict=False) exp_str = self.parenthesize(expr.exp, PREC, strict=False) return "{}**{}".format(base_str, exp_str) class PythonCodePrinter(AbstractPythonCodePrinter): def _print_sign(self, e): return '(0.0 if {e} == 0 else {f}(1, {e}))'.format( f=self._module_format('math.copysign'), e=self._print(e.args[0])) def _print_Not(self, expr): PREC = precedence(expr) return self._operators['not'] + self.parenthesize(expr.args[0], PREC) def _print_Indexed(self, expr): base = expr.args[0] index = expr.args[1:] return "{}[{}]".format(str(base), ", ".join([self._print(ind) for ind in index])) def _print_Pow(self, expr, rational=False): return self._hprint_Pow(expr, rational=rational) def _print_Rational(self, expr): if self.standard == 'python2': return '{}./{}.'.format(expr.p, expr.q) return '{}/{}'.format(expr.p, expr.q) def _print_Half(self, expr): return self._print_Rational(expr) def _print_frac(self, expr): from sympy import Mod return self._print_Mod(Mod(expr.args[0], 1)) _print_lowergamma = CodePrinter._print_not_supported _print_uppergamma = CodePrinter._print_not_supported _print_fresnelc = CodePrinter._print_not_supported _print_fresnels = CodePrinter._print_not_supported for k in PythonCodePrinter._kf: setattr(PythonCodePrinter, '_print_%s' % k, _print_known_func) for k in _known_constants_math: setattr(PythonCodePrinter, '_print_%s' % k, _print_known_const) def pycode(expr, **settings): """ Converts an expr to a string of Python code Parameters ========== expr : Expr A SymPy expression. fully_qualified_modules : bool Whether or not to write out full module names of functions (``math.sin`` vs. ``sin``). default: ``True``. standard : str or None, optional If 'python2', Python 2 sematics will be used. If 'python3', Python 3 sematics will be used. If None, the standard will be automatically detected. Default is 'python3'. And this parameter may be removed in the future. Examples ======== >>> from sympy import tan, Symbol >>> from sympy.printing.pycode import pycode >>> pycode(tan(Symbol('x')) + 1) 'math.tan(x) + 1' """ return PythonCodePrinter(settings).doprint(expr) _not_in_mpmath = 'log1p log2'.split() _in_mpmath = [(k, v) for k, v in _known_functions_math.items() if k not in _not_in_mpmath] _known_functions_mpmath = dict(_in_mpmath, **{ 'beta': 'beta', 'frac': 'frac', 'fresnelc': 'fresnelc', 'fresnels': 'fresnels', 'sign': 'sign', 'loggamma': 'loggamma', }) _known_constants_mpmath = { 'Exp1': 'e', 'Pi': 'pi', 'GoldenRatio': 'phi', 'EulerGamma': 'euler', 'Catalan': 'catalan', 'NaN': 'nan', 'Infinity': 'inf', 'NegativeInfinity': 'ninf' } def _unpack_integral_limits(integral_expr): """ helper function for _print_Integral that - accepts an Integral expression - returns a tuple of - a list variables of integration - a list of tuples of the upper and lower limits of integration """ integration_vars = [] limits = [] for integration_range in integral_expr.limits: if len(integration_range) == 3: integration_var, lower_limit, upper_limit = integration_range else: raise NotImplementedError("Only definite integrals are supported") integration_vars.append(integration_var) limits.append((lower_limit, upper_limit)) return integration_vars, limits class MpmathPrinter(PythonCodePrinter): """ Lambda printer for mpmath which maintains precision for floats """ printmethod = "_mpmathcode" language = "Python with mpmath" _kf = dict(chain( _known_functions.items(), [(k, 'mpmath.' + v) for k, v in _known_functions_mpmath.items()] )) _kc = {k: 'mpmath.'+v for k, v in _known_constants_mpmath.items()} def _print_Float(self, e): # XXX: This does not handle setting mpmath.mp.dps. It is assumed that # the caller of the lambdified function will have set it to sufficient # precision to match the Floats in the expression. # Remove 'mpz' if gmpy is installed. args = str(tuple(map(int, e._mpf_))) return '{func}({args})'.format(func=self._module_format('mpmath.mpf'), args=args) def _print_Rational(self, e): return "{func}({p})/{func}({q})".format( func=self._module_format('mpmath.mpf'), q=self._print(e.q), p=self._print(e.p) ) def _print_Half(self, e): return self._print_Rational(e) def _print_uppergamma(self, e): return "{}({}, {}, {})".format( self._module_format('mpmath.gammainc'), self._print(e.args[0]), self._print(e.args[1]), self._module_format('mpmath.inf')) def _print_lowergamma(self, e): return "{}({}, 0, {})".format( self._module_format('mpmath.gammainc'), self._print(e.args[0]), self._print(e.args[1])) def _print_log2(self, e): return '{0}({1})/{0}(2)'.format( self._module_format('mpmath.log'), self._print(e.args[0])) def _print_log1p(self, e): return '{}({}+1)'.format( self._module_format('mpmath.log'), self._print(e.args[0])) def _print_Pow(self, expr, rational=False): return self._hprint_Pow(expr, rational=rational, sqrt='mpmath.sqrt') def _print_Integral(self, e): integration_vars, limits = _unpack_integral_limits(e) return "{}(lambda {}: {}, {})".format( self._module_format("mpmath.quad"), ", ".join(map(self._print, integration_vars)), self._print(e.args[0]), ", ".join("(%s, %s)" % tuple(map(self._print, l)) for l in limits)) for k in MpmathPrinter._kf: setattr(MpmathPrinter, '_print_%s' % k, _print_known_func) for k in _known_constants_mpmath: setattr(MpmathPrinter, '_print_%s' % k, _print_known_const) class SymPyPrinter(AbstractPythonCodePrinter): language = "Python with SymPy" def _print_Function(self, expr): mod = expr.func.__module__ or '' return '%s(%s)' % (self._module_format(mod + ('.' if mod else '') + expr.func.__name__), ', '.join(map(lambda arg: self._print(arg), expr.args))) def _print_Pow(self, expr, rational=False): return self._hprint_Pow(expr, rational=rational, sqrt='sympy.sqrt') sympy-sympy-1.9/sympy/printing/python.py000066400000000000000000000060641412543434000206370ustar00rootroot00000000000000import keyword as kw import sympy from .repr import ReprPrinter from .str import StrPrinter # A list of classes that should be printed using StrPrinter STRPRINT = ("Add", "Infinity", "Integer", "Mul", "NegativeInfinity", "Pow", "Zero") class PythonPrinter(ReprPrinter, StrPrinter): """A printer which converts an expression into its Python interpretation.""" def __init__(self, settings=None): super().__init__(settings) self.symbols = [] self.functions = [] # Create print methods for classes that should use StrPrinter instead # of ReprPrinter. for name in STRPRINT: f_name = "_print_%s" % name f = getattr(StrPrinter, f_name) setattr(PythonPrinter, f_name, f) def _print_Function(self, expr): func = expr.func.__name__ if not hasattr(sympy, func) and not func in self.functions: self.functions.append(func) return StrPrinter._print_Function(self, expr) # procedure (!) for defining symbols which have be defined in print_python() def _print_Symbol(self, expr): symbol = self._str(expr) if symbol not in self.symbols: self.symbols.append(symbol) return StrPrinter._print_Symbol(self, expr) def _print_module(self, expr): raise ValueError('Modules in the expression are unacceptable') def python(expr, **settings): """Return Python interpretation of passed expression (can be passed to the exec() function without any modifications)""" printer = PythonPrinter(settings) exprp = printer.doprint(expr) result = '' # Returning found symbols and functions renamings = {} for symbolname in printer.symbols: newsymbolname = symbolname # Escape symbol names that are reserved python keywords if kw.iskeyword(newsymbolname): while True: newsymbolname += "_" if (newsymbolname not in printer.symbols and newsymbolname not in printer.functions): renamings[sympy.Symbol( symbolname)] = sympy.Symbol(newsymbolname) break result += newsymbolname + ' = Symbol(\'' + symbolname + '\')\n' for functionname in printer.functions: newfunctionname = functionname # Escape function names that are reserved python keywords if kw.iskeyword(newfunctionname): while True: newfunctionname += "_" if (newfunctionname not in printer.symbols and newfunctionname not in printer.functions): renamings[sympy.Function( functionname)] = sympy.Function(newfunctionname) break result += newfunctionname + ' = Function(\'' + functionname + '\')\n' if renamings: exprp = expr.subs(renamings) result += 'e = ' + printer._str(exprp) return result def print_python(expr, **settings): """Print output of python() function""" print(python(expr, **settings)) sympy-sympy-1.9/sympy/printing/rcode.py000066400000000000000000000344131412543434000204110ustar00rootroot00000000000000""" R code printer The RCodePrinter converts single sympy expressions into single R expressions, using the functions defined in math.h where possible. """ from typing import Any, Dict from sympy.printing.codeprinter import CodePrinter from sympy.printing.precedence import precedence, PRECEDENCE from sympy.sets.fancysets import Range # dictionary mapping sympy function to (argument_conditions, C_function). # Used in RCodePrinter._print_Function(self) known_functions = { #"Abs": [(lambda x: not x.is_integer, "fabs")], "Abs": "abs", "sin": "sin", "cos": "cos", "tan": "tan", "asin": "asin", "acos": "acos", "atan": "atan", "atan2": "atan2", "exp": "exp", "log": "log", "erf": "erf", "sinh": "sinh", "cosh": "cosh", "tanh": "tanh", "asinh": "asinh", "acosh": "acosh", "atanh": "atanh", "floor": "floor", "ceiling": "ceiling", "sign": "sign", "Max": "max", "Min": "min", "factorial": "factorial", "gamma": "gamma", "digamma": "digamma", "trigamma": "trigamma", "beta": "beta", } # These are the core reserved words in the R language. Taken from: # https://cran.r-project.org/doc/manuals/r-release/R-lang.html#Reserved-words reserved_words = ['if', 'else', 'repeat', 'while', 'function', 'for', 'in', 'next', 'break', 'TRUE', 'FALSE', 'NULL', 'Inf', 'NaN', 'NA', 'NA_integer_', 'NA_real_', 'NA_complex_', 'NA_character_', 'volatile'] class RCodePrinter(CodePrinter): """A printer to convert python expressions to strings of R code""" printmethod = "_rcode" language = "R" _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 15, 'user_functions': {}, 'human': True, 'contract': True, 'dereference': set(), 'error_on_reserved': False, 'reserved_word_suffix': '_', } # type: Dict[str, Any] _operators = { 'and': '&', 'or': '|', 'not': '!', } _relationals = { } # type: Dict[str, str] def __init__(self, settings={}): CodePrinter.__init__(self, settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) self._dereference = set(settings.get('dereference', [])) self.reserved_words = set(reserved_words) def _rate_index_position(self, p): return p*5 def _get_statement(self, codestring): return "%s;" % codestring def _get_comment(self, text): return "// {}".format(text) def _declare_number_const(self, name, value): return "{} = {};".format(name, value) def _format_code(self, lines): return self.indent_code(lines) def _traverse_matrix_indices(self, mat): rows, cols = mat.shape return ((i, j) for i in range(rows) for j in range(cols)) def _get_loop_opening_ending(self, indices): """Returns a tuple (open_lines, close_lines) containing lists of codelines """ open_lines = [] close_lines = [] loopstart = "for (%(var)s in %(start)s:%(end)s){" for i in indices: # R arrays start at 1 and end at dimension open_lines.append(loopstart % { 'var': self._print(i.label), 'start': self._print(i.lower+1), 'end': self._print(i.upper + 1)}) close_lines.append("}") return open_lines, close_lines def _print_Pow(self, expr): if "Pow" in self.known_functions: return self._print_Function(expr) PREC = precedence(expr) if expr.exp == -1: return '1.0/%s' % (self.parenthesize(expr.base, PREC)) elif expr.exp == 0.5: return 'sqrt(%s)' % self._print(expr.base) else: return '%s^%s' % (self.parenthesize(expr.base, PREC), self.parenthesize(expr.exp, PREC)) def _print_Rational(self, expr): p, q = int(expr.p), int(expr.q) return '%d.0/%d.0' % (p, q) def _print_Indexed(self, expr): inds = [ self._print(i) for i in expr.indices ] return "%s[%s]" % (self._print(expr.base.label), ", ".join(inds)) def _print_Idx(self, expr): return self._print(expr.label) def _print_Exp1(self, expr): return "exp(1)" def _print_Pi(self, expr): return 'pi' def _print_Infinity(self, expr): return 'Inf' def _print_NegativeInfinity(self, expr): return '-Inf' def _print_Assignment(self, expr): from sympy.codegen.ast import Assignment from sympy.matrices.expressions.matexpr import MatrixSymbol from sympy.tensor.indexed import IndexedBase lhs = expr.lhs rhs = expr.rhs # We special case assignments that take multiple lines #if isinstance(expr.rhs, Piecewise): # from sympy.functions.elementary.piecewise import Piecewise # # Here we modify Piecewise so each expression is now # # an Assignment, and then continue on the print. # expressions = [] # conditions = [] # for (e, c) in rhs.args: # expressions.append(Assignment(lhs, e)) # conditions.append(c) # temp = Piecewise(*zip(expressions, conditions)) # return self._print(temp) #elif isinstance(lhs, MatrixSymbol): if isinstance(lhs, MatrixSymbol): # Here we form an Assignment for each element in the array, # printing each one. lines = [] for (i, j) in self._traverse_matrix_indices(lhs): temp = Assignment(lhs[i, j], rhs[i, j]) code0 = self._print(temp) lines.append(code0) return "\n".join(lines) elif self._settings["contract"] and (lhs.has(IndexedBase) or rhs.has(IndexedBase)): # Here we check if there is looping to be done, and if so # print the required loops. return self._doprint_loops(rhs, lhs) else: lhs_code = self._print(lhs) rhs_code = self._print(rhs) return self._get_statement("%s = %s" % (lhs_code, rhs_code)) def _print_Piecewise(self, expr): # This method is called only for inline if constructs # Top level piecewise is handled in doprint() if expr.args[-1].cond == True: last_line = "%s" % self._print(expr.args[-1].expr) else: last_line = "ifelse(%s,%s,NA)" % (self._print(expr.args[-1].cond), self._print(expr.args[-1].expr)) code=last_line for e, c in reversed(expr.args[:-1]): code= "ifelse(%s,%s," % (self._print(c), self._print(e))+code+")" return(code) def _print_ITE(self, expr): from sympy.functions import Piecewise _piecewise = Piecewise((expr.args[1], expr.args[0]), (expr.args[2], True)) return self._print(_piecewise) def _print_MatrixElement(self, expr): return "{}[{}]".format(self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True), expr.j + expr.i*expr.parent.shape[1]) def _print_Symbol(self, expr): name = super()._print_Symbol(expr) if expr in self._dereference: return '(*{})'.format(name) else: return name def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) def _print_sinc(self, expr): from sympy.functions.elementary.trigonometric import sin from sympy.core.relational import Ne from sympy.functions import Piecewise _piecewise = Piecewise( (sin(expr.args[0]) / expr.args[0], Ne(expr.args[0], 0)), (1, True)) return self._print(_piecewise) def _print_AugmentedAssignment(self, expr): lhs_code = self._print(expr.lhs) op = expr.op rhs_code = self._print(expr.rhs) return "{} {} {};".format(lhs_code, op, rhs_code) def _print_For(self, expr): target = self._print(expr.target) if isinstance(expr.iterable, Range): start, stop, step = expr.iterable.args else: raise NotImplementedError("Only iterable currently supported is Range") body = self._print(expr.body) return ('for ({target} = {start}; {target} < {stop}; {target} += ' '{step}) {{\n{body}\n}}').format(target=target, start=start, stop=stop, step=step, body=body) def indent_code(self, code): """Accepts a string of code or a list of code lines""" if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) tab = " " inc_token = ('{', '(', '{\n', '(\n') dec_token = ('}', ')') code = [ line.lstrip(' \t') for line in code ] increase = [ int(any(map(line.endswith, inc_token))) for line in code ] decrease = [ int(any(map(line.startswith, dec_token))) for line in code ] pretty = [] level = 0 for n, line in enumerate(code): if line == '' or line == '\n': pretty.append(line) continue level -= decrease[n] pretty.append("%s%s" % (tab*level, line)) level += increase[n] return pretty def rcode(expr, assign_to=None, **settings): """Converts an expr to a string of r code Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of line-wrapping, or for expressions that generate multi-line statements. precision : integer, optional The precision for numbers such as pi [default=15]. user_functions : dict, optional A dictionary where the keys are string representations of either ``FunctionClass`` or ``UndefinedFunction`` instances and the values are their desired R string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, rfunction_string)] or [(argument_test, rfunction_formater)]. See below for examples. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. Examples ======== >>> from sympy import rcode, symbols, Rational, sin, ceiling, Abs, Function >>> x, tau = symbols("x, tau") >>> rcode((2*tau)**Rational(7, 2)) '8*sqrt(2)*tau^(7.0/2.0)' >>> rcode(sin(x), assign_to="s") 's = sin(x);' Simple custom printing can be defined for certain types by passing a dictionary of {"type" : "function"} to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. >>> custom_functions = { ... "ceiling": "CEIL", ... "Abs": [(lambda x: not x.is_integer, "fabs"), ... (lambda x: x.is_integer, "ABS")], ... "func": "f" ... } >>> func = Function('func') >>> rcode(func(Abs(x) + ceiling(x)), user_functions=custom_functions) 'f(fabs(x) + CEIL(x))' or if the R-function takes a subset of the original arguments: >>> rcode(2**x + 3**x, user_functions={'Pow': [ ... (lambda b, e: b == 2, lambda b, e: 'exp2(%s)' % e), ... (lambda b, e: b != 2, 'pow')]}) 'exp2(x) + pow(3, x)' ``Piecewise`` expressions are converted into conditionals. If an ``assign_to`` variable is provided an if statement is created, otherwise the ternary operator is used. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> expr = Piecewise((x + 1, x > 0), (x, True)) >>> print(rcode(expr, assign_to=tau)) tau = ifelse(x > 0,x + 1,x); Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> rcode(e.rhs, assign_to=e.lhs, contract=False) 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions must be provided to ``assign_to``. Note that any expression that can be generated normally can also exist inside a Matrix: >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) >>> A = MatrixSymbol('A', 3, 1) >>> print(rcode(mat, A)) A[0] = x^2; A[1] = ifelse(x > 0,x + 1,x); A[2] = sin(x); """ return RCodePrinter(settings).doprint(expr, assign_to) def print_rcode(expr, **settings): """Prints R representation of the given expression.""" print(rcode(expr, **settings)) sympy-sympy-1.9/sympy/printing/repr.py000066400000000000000000000265271412543434000202740ustar00rootroot00000000000000""" A Printer for generating executable code. The most important function here is srepr that returns a string so that the relation eval(srepr(expr))=expr holds in an appropriate environment. """ from typing import Any, Dict from sympy.core.function import AppliedUndef from sympy.core.mul import Mul from mpmath.libmp import repr_dps, to_str as mlib_to_str from .printer import Printer, print_function class ReprPrinter(Printer): printmethod = "_sympyrepr" _default_settings = { "order": None, "perm_cyclic" : True, } # type: Dict[str, Any] def reprify(self, args, sep): """ Prints each item in `args` and joins them with `sep`. """ return sep.join([self.doprint(item) for item in args]) def emptyPrinter(self, expr): """ The fallback printer. """ if isinstance(expr, str): return expr elif hasattr(expr, "__srepr__"): return expr.__srepr__() elif hasattr(expr, "args") and hasattr(expr.args, "__iter__"): l = [] for o in expr.args: l.append(self._print(o)) return expr.__class__.__name__ + '(%s)' % ', '.join(l) elif hasattr(expr, "__module__") and hasattr(expr, "__name__"): return "<'%s.%s'>" % (expr.__module__, expr.__name__) else: return str(expr) def _print_Add(self, expr, order=None): args = self._as_ordered_terms(expr, order=order) nargs = len(args) args = map(self._print, args) clsname = type(expr).__name__ if nargs > 255: # Issue #10259, Python < 3.7 return clsname + "(*[%s])" % ", ".join(args) return clsname + "(%s)" % ", ".join(args) def _print_Cycle(self, expr): return expr.__repr__() def _print_Permutation(self, expr): from sympy.combinatorics.permutations import Permutation, Cycle from sympy.utilities.exceptions import SymPyDeprecationWarning perm_cyclic = Permutation.print_cyclic if perm_cyclic is not None: SymPyDeprecationWarning( feature="Permutation.print_cyclic = {}".format(perm_cyclic), useinstead="init_printing(perm_cyclic={})" .format(perm_cyclic), issue=15201, deprecated_since_version="1.6").warn() else: perm_cyclic = self._settings.get("perm_cyclic", True) if perm_cyclic: if not expr.size: return 'Permutation()' # before taking Cycle notation, see if the last element is # a singleton and move it to the head of the string s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):] last = s.rfind('(') if not last == 0 and ',' not in s[last:]: s = s[last:] + s[:last] return 'Permutation%s' %s else: s = expr.support() if not s: if expr.size < 5: return 'Permutation(%s)' % str(expr.array_form) return 'Permutation([], size=%s)' % expr.size trim = str(expr.array_form[:s[-1] + 1]) + ', size=%s' % expr.size use = full = str(expr.array_form) if len(trim) < len(full): use = trim return 'Permutation(%s)' % use def _print_Function(self, expr): r = self._print(expr.func) r += '(%s)' % ', '.join([self._print(a) for a in expr.args]) return r def _print_Heaviside(self, expr): # Same as _print_Function but uses pargs to suppress default value for # 2nd arg. r = self._print(expr.func) r += '(%s)' % ', '.join([self._print(a) for a in expr.pargs]) return r def _print_FunctionClass(self, expr): if issubclass(expr, AppliedUndef): return 'Function(%r)' % (expr.__name__) else: return expr.__name__ def _print_Half(self, expr): return 'Rational(1, 2)' def _print_RationalConstant(self, expr): return str(expr) def _print_AtomicExpr(self, expr): return str(expr) def _print_NumberSymbol(self, expr): return str(expr) def _print_Integer(self, expr): return 'Integer(%i)' % expr.p def _print_Integers(self, expr): return 'Integers' def _print_Naturals(self, expr): return 'Naturals' def _print_Naturals0(self, expr): return 'Naturals0' def _print_Reals(self, expr): return 'Reals' def _print_EmptySet(self, expr): return 'EmptySet' def _print_EmptySequence(self, expr): return 'EmptySequence' def _print_list(self, expr): return "[%s]" % self.reprify(expr, ", ") def _print_dict(self, expr): sep = ", " dict_kvs = ["%s: %s" % (self.doprint(key), self.doprint(value)) for key, value in expr.items()] return "{%s}" % sep.join(dict_kvs) def _print_set(self, expr): if not expr: return "set()" return "{%s}" % self.reprify(expr, ", ") def _print_MatrixBase(self, expr): # special case for some empty matrices if (expr.rows == 0) ^ (expr.cols == 0): return '%s(%s, %s, %s)' % (expr.__class__.__name__, self._print(expr.rows), self._print(expr.cols), self._print([])) l = [] for i in range(expr.rows): l.append([]) for j in range(expr.cols): l[-1].append(expr[i, j]) return '%s(%s)' % (expr.__class__.__name__, self._print(l)) def _print_BooleanTrue(self, expr): return "true" def _print_BooleanFalse(self, expr): return "false" def _print_NaN(self, expr): return "nan" def _print_Mul(self, expr, order=None): if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) nargs = len(args) args = map(self._print, args) clsname = type(expr).__name__ if nargs > 255: # Issue #10259, Python < 3.7 return clsname + "(*[%s])" % ", ".join(args) return clsname + "(%s)" % ", ".join(args) def _print_Rational(self, expr): return 'Rational(%s, %s)' % (self._print(expr.p), self._print(expr.q)) def _print_PythonRational(self, expr): return "%s(%d, %d)" % (expr.__class__.__name__, expr.p, expr.q) def _print_Fraction(self, expr): return 'Fraction(%s, %s)' % (self._print(expr.numerator), self._print(expr.denominator)) def _print_Float(self, expr): r = mlib_to_str(expr._mpf_, repr_dps(expr._prec)) return "%s('%s', precision=%i)" % (expr.__class__.__name__, r, expr._prec) def _print_Sum2(self, expr): return "Sum2(%s, (%s, %s, %s))" % (self._print(expr.f), self._print(expr.i), self._print(expr.a), self._print(expr.b)) def _print_Str(self, s): return "%s(%s)" % (s.__class__.__name__, self._print(s.name)) def _print_Symbol(self, expr): d = expr._assumptions.generator # print the dummy_index like it was an assumption if expr.is_Dummy: d['dummy_index'] = expr.dummy_index if d == {}: return "%s(%s)" % (expr.__class__.__name__, self._print(expr.name)) else: attr = ['%s=%s' % (k, v) for k, v in d.items()] return "%s(%s, %s)" % (expr.__class__.__name__, self._print(expr.name), ', '.join(attr)) def _print_CoordinateSymbol(self, expr): d = expr._assumptions.generator if d == {}: return "%s(%s, %s)" % ( expr.__class__.__name__, self._print(expr.coord_sys), self._print(expr.index) ) else: attr = ['%s=%s' % (k, v) for k, v in d.items()] return "%s(%s, %s, %s)" % ( expr.__class__.__name__, self._print(expr.coord_sys), self._print(expr.index), ', '.join(attr) ) def _print_Predicate(self, expr): return "Q.%s" % expr.name def _print_AppliedPredicate(self, expr): # will be changed to just expr.args when args overriding is removed args = expr._args return "%s(%s)" % (expr.__class__.__name__, self.reprify(args, ", ")) def _print_str(self, expr): return repr(expr) def _print_tuple(self, expr): if len(expr) == 1: return "(%s,)" % self._print(expr[0]) else: return "(%s)" % self.reprify(expr, ", ") def _print_WildFunction(self, expr): return "%s('%s')" % (expr.__class__.__name__, expr.name) def _print_AlgebraicNumber(self, expr): return "%s(%s, %s)" % (expr.__class__.__name__, self._print(expr.root), self._print(expr.coeffs())) def _print_PolyRing(self, ring): return "%s(%s, %s, %s)" % (ring.__class__.__name__, self._print(ring.symbols), self._print(ring.domain), self._print(ring.order)) def _print_FracField(self, field): return "%s(%s, %s, %s)" % (field.__class__.__name__, self._print(field.symbols), self._print(field.domain), self._print(field.order)) def _print_PolyElement(self, poly): terms = list(poly.terms()) terms.sort(key=poly.ring.order, reverse=True) return "%s(%s, %s)" % (poly.__class__.__name__, self._print(poly.ring), self._print(terms)) def _print_FracElement(self, frac): numer_terms = list(frac.numer.terms()) numer_terms.sort(key=frac.field.order, reverse=True) denom_terms = list(frac.denom.terms()) denom_terms.sort(key=frac.field.order, reverse=True) numer = self._print(numer_terms) denom = self._print(denom_terms) return "%s(%s, %s, %s)" % (frac.__class__.__name__, self._print(frac.field), numer, denom) def _print_FractionField(self, domain): cls = domain.__class__.__name__ field = self._print(domain.field) return "%s(%s)" % (cls, field) def _print_PolynomialRingBase(self, ring): cls = ring.__class__.__name__ dom = self._print(ring.domain) gens = ', '.join(map(self._print, ring.gens)) order = str(ring.order) if order != ring.default_order: orderstr = ", order=" + order else: orderstr = "" return "%s(%s, %s%s)" % (cls, dom, gens, orderstr) def _print_DMP(self, p): cls = p.__class__.__name__ rep = self._print(p.rep) dom = self._print(p.dom) if p.ring is not None: ringstr = ", ring=" + self._print(p.ring) else: ringstr = "" return "%s(%s, %s%s)" % (cls, rep, dom, ringstr) def _print_MonogenicFiniteExtension(self, ext): # The expanded tree shown by srepr(ext.modulus) # is not practical. return "FiniteExtension(%s)" % str(ext.modulus) def _print_ExtensionElement(self, f): rep = self._print(f.rep) ext = self._print(f.ext) return "ExtElem(%s, %s)" % (rep, ext) @print_function(ReprPrinter) def srepr(expr, **settings): """return expr in repr form""" return ReprPrinter(settings).doprint(expr) sympy-sympy-1.9/sympy/printing/rust.py000066400000000000000000000507351412543434000203170ustar00rootroot00000000000000""" Rust code printer The `RustCodePrinter` converts SymPy expressions into Rust expressions. A complete code generator, which uses `rust_code` extensively, can be found in `sympy.utilities.codegen`. The `codegen` module can be used to generate complete source code files. """ # Possible Improvement # # * make sure we follow Rust Style Guidelines_ # * make use of pattern matching # * better support for reference # * generate generic code and use trait to make sure they have specific methods # * use crates_ to get more math support # - num_ # + BigInt_, BigUint_ # + Complex_ # + Rational64_, Rational32_, BigRational_ # # .. _crates: https://crates.io/ # .. _Guidelines: https://github.com/rust-lang/rust/tree/master/src/doc/style # .. _num: http://rust-num.github.io/num/num/ # .. _BigInt: http://rust-num.github.io/num/num/bigint/struct.BigInt.html # .. _BigUint: http://rust-num.github.io/num/num/bigint/struct.BigUint.html # .. _Complex: http://rust-num.github.io/num/num/complex/struct.Complex.html # .. _Rational32: http://rust-num.github.io/num/num/rational/type.Rational32.html # .. _Rational64: http://rust-num.github.io/num/num/rational/type.Rational64.html # .. _BigRational: http://rust-num.github.io/num/num/rational/type.BigRational.html from typing import Any, Dict from sympy.core import S, Rational, Float, Lambda from sympy.printing.codeprinter import CodePrinter # Rust's methods for integer and float can be found at here : # # * `Rust - Primitive Type f64 `_ # * `Rust - Primitive Type i64 `_ # # Function Style : # # 1. args[0].func(args[1:]), method with arguments # 2. args[0].func(), method without arguments # 3. args[1].func(), method without arguments (e.g. (e, x) => x.exp()) # 4. func(args), function with arguments # dictionary mapping sympy function to (argument_conditions, Rust_function). # Used in RustCodePrinter._print_Function(self) # f64 method in Rust known_functions = { # "": "is_nan", # "": "is_infinite", # "": "is_finite", # "": "is_normal", # "": "classify", "floor": "floor", "ceiling": "ceil", # "": "round", # "": "trunc", # "": "fract", "Abs": "abs", "sign": "signum", # "": "is_sign_positive", # "": "is_sign_negative", # "": "mul_add", "Pow": [(lambda base, exp: exp == -S.One, "recip", 2), # 1.0/x (lambda base, exp: exp == S.Half, "sqrt", 2), # x ** 0.5 (lambda base, exp: exp == -S.Half, "sqrt().recip", 2), # 1/(x ** 0.5) (lambda base, exp: exp == Rational(1, 3), "cbrt", 2), # x ** (1/3) (lambda base, exp: base == S.One*2, "exp2", 3), # 2 ** x (lambda base, exp: exp.is_integer, "powi", 1), # x ** y, for i32 (lambda base, exp: not exp.is_integer, "powf", 1)], # x ** y, for f64 "exp": [(lambda exp: True, "exp", 2)], # e ** x "log": "ln", # "": "log", # number.log(base) # "": "log2", # "": "log10", # "": "to_degrees", # "": "to_radians", "Max": "max", "Min": "min", # "": "hypot", # (x**2 + y**2) ** 0.5 "sin": "sin", "cos": "cos", "tan": "tan", "asin": "asin", "acos": "acos", "atan": "atan", "atan2": "atan2", # "": "sin_cos", # "": "exp_m1", # e ** x - 1 # "": "ln_1p", # ln(1 + x) "sinh": "sinh", "cosh": "cosh", "tanh": "tanh", "asinh": "asinh", "acosh": "acosh", "atanh": "atanh", } # i64 method in Rust # known_functions_i64 = { # "": "min_value", # "": "max_value", # "": "from_str_radix", # "": "count_ones", # "": "count_zeros", # "": "leading_zeros", # "": "trainling_zeros", # "": "rotate_left", # "": "rotate_right", # "": "swap_bytes", # "": "from_be", # "": "from_le", # "": "to_be", # to big endian # "": "to_le", # to little endian # "": "checked_add", # "": "checked_sub", # "": "checked_mul", # "": "checked_div", # "": "checked_rem", # "": "checked_neg", # "": "checked_shl", # "": "checked_shr", # "": "checked_abs", # "": "saturating_add", # "": "saturating_sub", # "": "saturating_mul", # "": "wrapping_add", # "": "wrapping_sub", # "": "wrapping_mul", # "": "wrapping_div", # "": "wrapping_rem", # "": "wrapping_neg", # "": "wrapping_shl", # "": "wrapping_shr", # "": "wrapping_abs", # "": "overflowing_add", # "": "overflowing_sub", # "": "overflowing_mul", # "": "overflowing_div", # "": "overflowing_rem", # "": "overflowing_neg", # "": "overflowing_shl", # "": "overflowing_shr", # "": "overflowing_abs", # "Pow": "pow", # "Abs": "abs", # "sign": "signum", # "": "is_positive", # "": "is_negnative", # } # These are the core reserved words in the Rust language. Taken from: # http://doc.rust-lang.org/grammar.html#keywords reserved_words = ['abstract', 'alignof', 'as', 'become', 'box', 'break', 'const', 'continue', 'crate', 'do', 'else', 'enum', 'extern', 'false', 'final', 'fn', 'for', 'if', 'impl', 'in', 'let', 'loop', 'macro', 'match', 'mod', 'move', 'mut', 'offsetof', 'override', 'priv', 'proc', 'pub', 'pure', 'ref', 'return', 'Self', 'self', 'sizeof', 'static', 'struct', 'super', 'trait', 'true', 'type', 'typeof', 'unsafe', 'unsized', 'use', 'virtual', 'where', 'while', 'yield'] class RustCodePrinter(CodePrinter): """A printer to convert python expressions to strings of Rust code""" printmethod = "_rust_code" language = "Rust" _default_settings = { 'order': None, 'full_prec': 'auto', 'precision': 17, 'user_functions': {}, 'human': True, 'contract': True, 'dereference': set(), 'error_on_reserved': False, 'reserved_word_suffix': '_', 'inline': False, } # type: Dict[str, Any] def __init__(self, settings={}): CodePrinter.__init__(self, settings) self.known_functions = dict(known_functions) userfuncs = settings.get('user_functions', {}) self.known_functions.update(userfuncs) self._dereference = set(settings.get('dereference', [])) self.reserved_words = set(reserved_words) def _rate_index_position(self, p): return p*5 def _get_statement(self, codestring): return "%s;" % codestring def _get_comment(self, text): return "// %s" % text def _declare_number_const(self, name, value): return "const %s: f64 = %s;" % (name, value) def _format_code(self, lines): return self.indent_code(lines) def _traverse_matrix_indices(self, mat): rows, cols = mat.shape return ((i, j) for i in range(rows) for j in range(cols)) def _get_loop_opening_ending(self, indices): open_lines = [] close_lines = [] loopstart = "for %(var)s in %(start)s..%(end)s {" for i in indices: # Rust arrays start at 0 and end at dimension-1 open_lines.append(loopstart % { 'var': self._print(i), 'start': self._print(i.lower), 'end': self._print(i.upper + 1)}) close_lines.append("}") return open_lines, close_lines def _print_caller_var(self, expr): if len(expr.args) > 1: # for something like `sin(x + y + z)`, # make sure we can get '(x + y + z).sin()' # instead of 'x + y + z.sin()' return '(' + self._print(expr) + ')' elif expr.is_number: return self._print(expr, _type=True) else: return self._print(expr) def _print_Function(self, expr): """ basic function for printing `Function` Function Style : 1. args[0].func(args[1:]), method with arguments 2. args[0].func(), method without arguments 3. args[1].func(), method without arguments (e.g. (e, x) => x.exp()) 4. func(args), function with arguments """ if expr.func.__name__ in self.known_functions: cond_func = self.known_functions[expr.func.__name__] func = None style = 1 if isinstance(cond_func, str): func = cond_func else: for cond, func, style in cond_func: if cond(*expr.args): break if func is not None: if style == 1: ret = "%(var)s.%(method)s(%(args)s)" % { 'var': self._print_caller_var(expr.args[0]), 'method': func, 'args': self.stringify(expr.args[1:], ", ") if len(expr.args) > 1 else '' } elif style == 2: ret = "%(var)s.%(method)s()" % { 'var': self._print_caller_var(expr.args[0]), 'method': func, } elif style == 3: ret = "%(var)s.%(method)s()" % { 'var': self._print_caller_var(expr.args[1]), 'method': func, } else: ret = "%(func)s(%(args)s)" % { 'func': func, 'args': self.stringify(expr.args, ", "), } return ret elif hasattr(expr, '_imp_') and isinstance(expr._imp_, Lambda): # inlined function return self._print(expr._imp_(*expr.args)) else: return self._print_not_supported(expr) def _print_Pow(self, expr): if expr.base.is_integer and not expr.exp.is_integer: expr = type(expr)(Float(expr.base), expr.exp) return self._print(expr) return self._print_Function(expr) def _print_Float(self, expr, _type=False): ret = super()._print_Float(expr) if _type: return ret + '_f64' else: return ret def _print_Integer(self, expr, _type=False): ret = super()._print_Integer(expr) if _type: return ret + '_i32' else: return ret def _print_Rational(self, expr): p, q = int(expr.p), int(expr.q) return '%d_f64/%d.0' % (p, q) def _print_Relational(self, expr): lhs_code = self._print(expr.lhs) rhs_code = self._print(expr.rhs) op = expr.rel_op return "{} {} {}".format(lhs_code, op, rhs_code) def _print_Indexed(self, expr): # calculate index for 1d array dims = expr.shape elem = S.Zero offset = S.One for i in reversed(range(expr.rank)): elem += expr.indices[i]*offset offset *= dims[i] return "%s[%s]" % (self._print(expr.base.label), self._print(elem)) def _print_Idx(self, expr): return expr.label.name def _print_Dummy(self, expr): return expr.name def _print_Exp1(self, expr, _type=False): return "E" def _print_Pi(self, expr, _type=False): return 'PI' def _print_Infinity(self, expr, _type=False): return 'INFINITY' def _print_NegativeInfinity(self, expr, _type=False): return 'NEG_INFINITY' def _print_BooleanTrue(self, expr, _type=False): return "true" def _print_BooleanFalse(self, expr, _type=False): return "false" def _print_bool(self, expr, _type=False): return str(expr).lower() def _print_NaN(self, expr, _type=False): return "NAN" def _print_Piecewise(self, expr): if expr.args[-1].cond != True: # We need the last conditional to be a True, otherwise the resulting # function may not return a result. raise ValueError("All Piecewise expressions must contain an " "(expr, True) statement to be used as a default " "condition. Without one, the generated " "expression may not evaluate to anything under " "some condition.") lines = [] for i, (e, c) in enumerate(expr.args): if i == 0: lines.append("if (%s) {" % self._print(c)) elif i == len(expr.args) - 1 and c == True: lines[-1] += " else {" else: lines[-1] += " else if (%s) {" % self._print(c) code0 = self._print(e) lines.append(code0) lines.append("}") if self._settings['inline']: return " ".join(lines) else: return "\n".join(lines) def _print_ITE(self, expr): from sympy.functions import Piecewise _piecewise = Piecewise((expr.args[1], expr.args[0]), (expr.args[2], True)) return self._print(_piecewise) def _print_MatrixBase(self, A): if A.cols == 1: return "[%s]" % ", ".join(self._print(a) for a in A) else: raise ValueError("Full Matrix Support in Rust need Crates (https://crates.io/keywords/matrix).") def _print_SparseMatrix(self, mat): # do not allow sparse matrices to be made dense return self._print_not_supported(mat) def _print_MatrixElement(self, expr): return "%s[%s]" % (expr.parent, expr.j + expr.i*expr.parent.shape[1]) def _print_Symbol(self, expr): name = super()._print_Symbol(expr) if expr in self._dereference: return '(*%s)' % name else: return name def _print_Assignment(self, expr): from sympy.tensor.indexed import IndexedBase lhs = expr.lhs rhs = expr.rhs if self._settings["contract"] and (lhs.has(IndexedBase) or rhs.has(IndexedBase)): # Here we check if there is looping to be done, and if so # print the required loops. return self._doprint_loops(rhs, lhs) else: lhs_code = self._print(lhs) rhs_code = self._print(rhs) return self._get_statement("%s = %s" % (lhs_code, rhs_code)) def indent_code(self, code): """Accepts a string of code or a list of code lines""" if isinstance(code, str): code_lines = self.indent_code(code.splitlines(True)) return ''.join(code_lines) tab = " " inc_token = ('{', '(', '{\n', '(\n') dec_token = ('}', ')') code = [ line.lstrip(' \t') for line in code ] increase = [ int(any(map(line.endswith, inc_token))) for line in code ] decrease = [ int(any(map(line.startswith, dec_token))) for line in code ] pretty = [] level = 0 for n, line in enumerate(code): if line == '' or line == '\n': pretty.append(line) continue level -= decrease[n] pretty.append("%s%s" % (tab*level, line)) level += increase[n] return pretty def rust_code(expr, assign_to=None, **settings): """Converts an expr to a string of Rust code Parameters ========== expr : Expr A sympy expression to be converted. assign_to : optional When given, the argument is used as the name of the variable to which the expression is assigned. Can be a string, ``Symbol``, ``MatrixSymbol``, or ``Indexed`` type. This is helpful in case of line-wrapping, or for expressions that generate multi-line statements. precision : integer, optional The precision for numbers such as pi [default=15]. user_functions : dict, optional A dictionary where the keys are string representations of either ``FunctionClass`` or ``UndefinedFunction`` instances and the values are their desired C string representations. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. See below for examples. dereference : iterable, optional An iterable of symbols that should be dereferenced in the printed code expression. These would be values passed by address to the function. For example, if ``dereference=[a]``, the resulting code would print ``(*a)`` instead of ``a``. human : bool, optional If True, the result is a single string that may contain some constant declarations for the number symbols. If False, the same information is returned in a tuple of (symbols_to_declare, not_supported_functions, code_text). [default=True]. contract: bool, optional If True, ``Indexed`` instances are assumed to obey tensor contraction rules and the corresponding nested loops over indices are generated. Setting contract=False will not generate loops, instead the user is responsible to provide values for the indices in the code. [default=True]. Examples ======== >>> from sympy import rust_code, symbols, Rational, sin, ceiling, Abs, Function >>> x, tau = symbols("x, tau") >>> rust_code((2*tau)**Rational(7, 2)) '8*1.4142135623731*tau.powf(7_f64/2.0)' >>> rust_code(sin(x), assign_to="s") 's = x.sin();' Simple custom printing can be defined for certain types by passing a dictionary of {"type" : "function"} to the ``user_functions`` kwarg. Alternatively, the dictionary value can be a list of tuples i.e. [(argument_test, cfunction_string)]. >>> custom_functions = { ... "ceiling": "CEIL", ... "Abs": [(lambda x: not x.is_integer, "fabs", 4), ... (lambda x: x.is_integer, "ABS", 4)], ... "func": "f" ... } >>> func = Function('func') >>> rust_code(func(Abs(x) + ceiling(x)), user_functions=custom_functions) '(fabs(x) + x.CEIL()).f()' ``Piecewise`` expressions are converted into conditionals. If an ``assign_to`` variable is provided an if statement is created, otherwise the ternary operator is used. Note that if the ``Piecewise`` lacks a default term, represented by ``(expr, True)`` then an error will be thrown. This is to prevent generating an expression that may not evaluate to anything. >>> from sympy import Piecewise >>> expr = Piecewise((x + 1, x > 0), (x, True)) >>> print(rust_code(expr, tau)) tau = if (x > 0) { x + 1 } else { x }; Support for loops is provided through ``Indexed`` types. With ``contract=True`` these expressions will be turned into loops, whereas ``contract=False`` will just print the assignment expression that should be looped over: >>> from sympy import Eq, IndexedBase, Idx >>> len_y = 5 >>> y = IndexedBase('y', shape=(len_y,)) >>> t = IndexedBase('t', shape=(len_y,)) >>> Dy = IndexedBase('Dy', shape=(len_y-1,)) >>> i = Idx('i', len_y-1) >>> e=Eq(Dy[i], (y[i+1]-y[i])/(t[i+1]-t[i])) >>> rust_code(e.rhs, assign_to=e.lhs, contract=False) 'Dy[i] = (y[i + 1] - y[i])/(t[i + 1] - t[i]);' Matrices are also supported, but a ``MatrixSymbol`` of the same dimensions must be provided to ``assign_to``. Note that any expression that can be generated normally can also exist inside a Matrix: >>> from sympy import Matrix, MatrixSymbol >>> mat = Matrix([x**2, Piecewise((x + 1, x > 0), (x, True)), sin(x)]) >>> A = MatrixSymbol('A', 3, 1) >>> print(rust_code(mat, A)) A = [x.powi(2), if (x > 0) { x + 1 } else { x }, x.sin()]; """ return RustCodePrinter(settings).doprint(expr, assign_to) def print_rust_code(expr, **settings): """Prints Rust representation of the given expression.""" print(rust_code(expr, **settings)) sympy-sympy-1.9/sympy/printing/str.py000066400000000000000000001002051412543434000201160ustar00rootroot00000000000000""" A Printer for generating readable representation of most sympy classes. """ from typing import Any, Dict from sympy.core import S, Rational, Pow, Basic, Mul, Number from sympy.core.mul import _keep_coeff from sympy.core.function import _coeff_isneg from sympy.sets.sets import FiniteSet from .printer import Printer, print_function from sympy.printing.precedence import precedence, PRECEDENCE from mpmath.libmp import prec_to_dps, to_str as mlib_to_str from sympy.utilities import default_sort_key, sift class StrPrinter(Printer): printmethod = "_sympystr" _default_settings = { "order": None, "full_prec": "auto", "sympy_integers": False, "abbrev": False, "perm_cyclic": True, "min": None, "max": None, } # type: Dict[str, Any] _relationals = dict() # type: Dict[str, str] def parenthesize(self, item, level, strict=False): if (precedence(item) < level) or ((not strict) and precedence(item) <= level): return "(%s)" % self._print(item) else: return self._print(item) def stringify(self, args, sep, level=0): return sep.join([self.parenthesize(item, level) for item in args]) def emptyPrinter(self, expr): if isinstance(expr, str): return expr elif isinstance(expr, Basic): return repr(expr) else: return str(expr) def _print_Add(self, expr, order=None): terms = self._as_ordered_terms(expr, order=order) PREC = precedence(expr) l = [] for term in terms: t = self._print(term) if t.startswith('-'): sign = "-" t = t[1:] else: sign = "+" if precedence(term) < PREC: l.extend([sign, "(%s)" % t]) else: l.extend([sign, t]) sign = l.pop(0) if sign == '+': sign = "" return sign + ' '.join(l) def _print_BooleanTrue(self, expr): return "True" def _print_BooleanFalse(self, expr): return "False" def _print_Not(self, expr): return '~%s' %(self.parenthesize(expr.args[0],PRECEDENCE["Not"])) def _print_And(self, expr): return self.stringify(expr.args, " & ", PRECEDENCE["BitwiseAnd"]) def _print_Or(self, expr): return self.stringify(expr.args, " | ", PRECEDENCE["BitwiseOr"]) def _print_Xor(self, expr): return self.stringify(expr.args, " ^ ", PRECEDENCE["BitwiseXor"]) def _print_AppliedPredicate(self, expr): return '%s(%s)' % ( self._print(expr.function), self.stringify(expr.arguments, ", ")) def _print_Basic(self, expr): l = [self._print(o) for o in expr.args] return expr.__class__.__name__ + "(%s)" % ", ".join(l) def _print_BlockMatrix(self, B): if B.blocks.shape == (1, 1): self._print(B.blocks[0, 0]) return self._print(B.blocks) def _print_Catalan(self, expr): return 'Catalan' def _print_ComplexInfinity(self, expr): return 'zoo' def _print_ConditionSet(self, s): args = tuple([self._print(i) for i in (s.sym, s.condition)]) if s.base_set is S.UniversalSet: return 'ConditionSet(%s, %s)' % args args += (self._print(s.base_set),) return 'ConditionSet(%s, %s, %s)' % args def _print_Derivative(self, expr): dexpr = expr.expr dvars = [i[0] if i[1] == 1 else i for i in expr.variable_count] return 'Derivative(%s)' % ", ".join(map(lambda arg: self._print(arg), [dexpr] + dvars)) def _print_dict(self, d): keys = sorted(d.keys(), key=default_sort_key) items = [] for key in keys: item = "%s: %s" % (self._print(key), self._print(d[key])) items.append(item) return "{%s}" % ", ".join(items) def _print_Dict(self, expr): return self._print_dict(expr) def _print_RandomDomain(self, d): if hasattr(d, 'as_boolean'): return 'Domain: ' + self._print(d.as_boolean()) elif hasattr(d, 'set'): return ('Domain: ' + self._print(d.symbols) + ' in ' + self._print(d.set)) else: return 'Domain on ' + self._print(d.symbols) def _print_Dummy(self, expr): return '_' + expr.name def _print_EulerGamma(self, expr): return 'EulerGamma' def _print_Exp1(self, expr): return 'E' def _print_ExprCondPair(self, expr): return '(%s, %s)' % (self._print(expr.expr), self._print(expr.cond)) def _print_Function(self, expr): return expr.func.__name__ + "(%s)" % self.stringify(expr.args, ", ") def _print_GoldenRatio(self, expr): return 'GoldenRatio' def _print_Heaviside(self, expr): # Same as _print_Function but uses pargs to suppress default 1/2 for # 2nd args return expr.func.__name__ + "(%s)" % self.stringify(expr.pargs, ", ") def _print_TribonacciConstant(self, expr): return 'TribonacciConstant' def _print_ImaginaryUnit(self, expr): return 'I' def _print_Infinity(self, expr): return 'oo' def _print_Integral(self, expr): def _xab_tostr(xab): if len(xab) == 1: return self._print(xab[0]) else: return self._print((xab[0],) + tuple(xab[1:])) L = ', '.join([_xab_tostr(l) for l in expr.limits]) return 'Integral(%s, %s)' % (self._print(expr.function), L) def _print_Interval(self, i): fin = 'Interval{m}({a}, {b})' a, b, l, r = i.args if a.is_infinite and b.is_infinite: m = '' elif a.is_infinite and not r: m = '' elif b.is_infinite and not l: m = '' elif not l and not r: m = '' elif l and r: m = '.open' elif l: m = '.Lopen' else: m = '.Ropen' return fin.format(**{'a': a, 'b': b, 'm': m}) def _print_AccumulationBounds(self, i): return "AccumBounds(%s, %s)" % (self._print(i.min), self._print(i.max)) def _print_Inverse(self, I): return "%s**(-1)" % self.parenthesize(I.arg, PRECEDENCE["Pow"]) def _print_Lambda(self, obj): expr = obj.expr sig = obj.signature if len(sig) == 1 and sig[0].is_symbol: sig = sig[0] return "Lambda(%s, %s)" % (self._print(sig), self._print(expr)) def _print_LatticeOp(self, expr): args = sorted(expr.args, key=default_sort_key) return expr.func.__name__ + "(%s)" % ", ".join(self._print(arg) for arg in args) def _print_Limit(self, expr): e, z, z0, dir = expr.args if str(dir) == "+": return "Limit(%s, %s, %s)" % tuple(map(self._print, (e, z, z0))) else: return "Limit(%s, %s, %s, dir='%s')" % tuple(map(self._print, (e, z, z0, dir))) def _print_list(self, expr): return "[%s]" % self.stringify(expr, ", ") def _print_MatrixBase(self, expr): return expr._format_str(self) def _print_MatrixElement(self, expr): return self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) \ + '[%s, %s]' % (self._print(expr.i), self._print(expr.j)) def _print_MatrixSlice(self, expr): def strslice(x, dim): x = list(x) if x[2] == 1: del x[2] if x[0] == 0: x[0] = '' if x[1] == dim: x[1] = '' return ':'.join(map(lambda arg: self._print(arg), x)) return (self.parenthesize(expr.parent, PRECEDENCE["Atom"], strict=True) + '[' + strslice(expr.rowslice, expr.parent.rows) + ', ' + strslice(expr.colslice, expr.parent.cols) + ']') def _print_DeferredVector(self, expr): return expr.name def _print_Mul(self, expr): prec = precedence(expr) # Check for unevaluated Mul. In this case we need to make sure the # identities are visible, multiple Rational factors are not combined # etc so we display in a straight-forward form that fully preserves all # args and their order. args = expr.args if args[0] is S.One or any( isinstance(a, Number) or a.is_Pow and all(ai.is_Integer for ai in a.args) for a in args[1:]): d, n = sift(args, lambda x: isinstance(x, Pow) and bool(x.exp.as_coeff_Mul()[0] < 0), binary=True) for i, di in enumerate(d): if di.exp.is_Number: e = -di.exp else: dargs = list(di.exp.args) dargs[0] = -dargs[0] e = Mul._from_args(dargs) d[i] = Pow(di.base, e, evaluate=False) if e - 1 else di.base # don't parenthesize first factor if negative if _coeff_isneg(n[0]): pre = [str(n.pop(0))] else: pre = [] nfactors = pre + [self.parenthesize(a, prec, strict=False) for a in n] # don't parenthesize first of denominator unless singleton if len(d) > 1 and _coeff_isneg(d[0]): pre = [str(d.pop(0))] else: pre = [] dfactors = pre + [self.parenthesize(a, prec, strict=False) for a in d] n = '*'.join(nfactors) d = '*'.join(dfactors) if len(dfactors) > 1: return '%s/(%s)' % (n, d) elif dfactors: return '%s/%s' % (n, d) return n c, e = expr.as_coeff_Mul() if c < 0: expr = _keep_coeff(-c, e) sign = "-" else: sign = "" a = [] # items in the numerator b = [] # items that are in the denominator (if any) pow_paren = [] # Will collect all pow with more than one base element and exp = -1 if self.order not in ('old', 'none'): args = expr.as_ordered_factors() else: # use make_args in case expr was something like -x -> x args = Mul.make_args(expr) # Gather args for numerator/denominator def apow(i): b, e = i.as_base_exp() eargs = list(Mul.make_args(e)) if eargs[0] is S.NegativeOne: eargs = eargs[1:] else: eargs[0] = -eargs[0] e = Mul._from_args(eargs) if isinstance(i, Pow): return i.func(b, e, evaluate=False) return i.func(e, evaluate=False) for item in args: if (item.is_commutative and isinstance(item, Pow) and bool(item.exp.as_coeff_Mul()[0] < 0)): if item.exp is not S.NegativeOne: b.append(apow(item)) else: if (len(item.args[0].args) != 1 and isinstance(item.base, (Mul, Pow))): # To avoid situations like #14160 pow_paren.append(item) b.append(item.base) elif item.is_Rational and item is not S.Infinity: if item.p != 1: a.append(Rational(item.p)) if item.q != 1: b.append(Rational(item.q)) else: a.append(item) a = a or [S.One] a_str = [self.parenthesize(x, prec, strict=False) for x in a] b_str = [self.parenthesize(x, prec, strict=False) for x in b] # To parenthesize Pow with exp = -1 and having more than one Symbol for item in pow_paren: if item.base in b: b_str[b.index(item.base)] = "(%s)" % b_str[b.index(item.base)] if not b: return sign + '*'.join(a_str) elif len(b) == 1: return sign + '*'.join(a_str) + "/" + b_str[0] else: return sign + '*'.join(a_str) + "/(%s)" % '*'.join(b_str) def _print_MatMul(self, expr): c, m = expr.as_coeff_mmul() sign = "" if c.is_number: re, im = c.as_real_imag() if im.is_zero and re.is_negative: expr = _keep_coeff(-c, m) sign = "-" elif re.is_zero and im.is_negative: expr = _keep_coeff(-c, m) sign = "-" return sign + '*'.join( [self.parenthesize(arg, precedence(expr)) for arg in expr.args] ) def _print_ElementwiseApplyFunction(self, expr): return "{}.({})".format( expr.function, self._print(expr.expr), ) def _print_NaN(self, expr): return 'nan' def _print_NegativeInfinity(self, expr): return '-oo' def _print_Order(self, expr): if not expr.variables or all(p is S.Zero for p in expr.point): if len(expr.variables) <= 1: return 'O(%s)' % self._print(expr.expr) else: return 'O(%s)' % self.stringify((expr.expr,) + expr.variables, ', ', 0) else: return 'O(%s)' % self.stringify(expr.args, ', ', 0) def _print_Ordinal(self, expr): return expr.__str__() def _print_Cycle(self, expr): return expr.__str__() def _print_Permutation(self, expr): from sympy.combinatorics.permutations import Permutation, Cycle from sympy.utilities.exceptions import SymPyDeprecationWarning perm_cyclic = Permutation.print_cyclic if perm_cyclic is not None: SymPyDeprecationWarning( feature="Permutation.print_cyclic = {}".format(perm_cyclic), useinstead="init_printing(perm_cyclic={})" .format(perm_cyclic), issue=15201, deprecated_since_version="1.6").warn() else: perm_cyclic = self._settings.get("perm_cyclic", True) if perm_cyclic: if not expr.size: return '()' # before taking Cycle notation, see if the last element is # a singleton and move it to the head of the string s = Cycle(expr)(expr.size - 1).__repr__()[len('Cycle'):] last = s.rfind('(') if not last == 0 and ',' not in s[last:]: s = s[last:] + s[:last] s = s.replace(',', '') return s else: s = expr.support() if not s: if expr.size < 5: return 'Permutation(%s)' % self._print(expr.array_form) return 'Permutation([], size=%s)' % self._print(expr.size) trim = self._print(expr.array_form[:s[-1] + 1]) + ', size=%s' % self._print(expr.size) use = full = self._print(expr.array_form) if len(trim) < len(full): use = trim return 'Permutation(%s)' % use def _print_Subs(self, obj): expr, old, new = obj.args if len(obj.point) == 1: old = old[0] new = new[0] return "Subs(%s, %s, %s)" % ( self._print(expr), self._print(old), self._print(new)) def _print_TensorIndex(self, expr): return expr._print() def _print_TensorHead(self, expr): return expr._print() def _print_Tensor(self, expr): return expr._print() def _print_TensMul(self, expr): # prints expressions like "A(a)", "3*A(a)", "(1+x)*A(a)" sign, args = expr._get_args_for_traditional_printer() return sign + "*".join( [self.parenthesize(arg, precedence(expr)) for arg in args] ) def _print_TensAdd(self, expr): return expr._print() def _print_ArraySymbol(self, expr): return self._print(expr.name) def _print_ArrayElement(self, expr): return "%s[%s]" % (expr.name, ", ".join([self._print(i) for i in expr.indices])) def _print_PermutationGroup(self, expr): p = [' %s' % self._print(a) for a in expr.args] return 'PermutationGroup([\n%s])' % ',\n'.join(p) def _print_Pi(self, expr): return 'pi' def _print_PolyRing(self, ring): return "Polynomial ring in %s over %s with %s order" % \ (", ".join(map(lambda rs: self._print(rs), ring.symbols)), self._print(ring.domain), self._print(ring.order)) def _print_FracField(self, field): return "Rational function field in %s over %s with %s order" % \ (", ".join(map(lambda fs: self._print(fs), field.symbols)), self._print(field.domain), self._print(field.order)) def _print_FreeGroupElement(self, elm): return elm.__str__() def _print_GaussianElement(self, poly): return "(%s + %s*I)" % (poly.x, poly.y) def _print_PolyElement(self, poly): return poly.str(self, PRECEDENCE, "%s**%s", "*") def _print_FracElement(self, frac): if frac.denom == 1: return self._print(frac.numer) else: numer = self.parenthesize(frac.numer, PRECEDENCE["Mul"], strict=True) denom = self.parenthesize(frac.denom, PRECEDENCE["Atom"], strict=True) return numer + "/" + denom def _print_Poly(self, expr): ATOM_PREC = PRECEDENCE["Atom"] - 1 terms, gens = [], [ self.parenthesize(s, ATOM_PREC) for s in expr.gens ] for monom, coeff in expr.terms(): s_monom = [] for i, e in enumerate(monom): if e > 0: if e == 1: s_monom.append(gens[i]) else: s_monom.append(gens[i] + "**%d" % e) s_monom = "*".join(s_monom) if coeff.is_Add: if s_monom: s_coeff = "(" + self._print(coeff) + ")" else: s_coeff = self._print(coeff) else: if s_monom: if coeff is S.One: terms.extend(['+', s_monom]) continue if coeff is S.NegativeOne: terms.extend(['-', s_monom]) continue s_coeff = self._print(coeff) if not s_monom: s_term = s_coeff else: s_term = s_coeff + "*" + s_monom if s_term.startswith('-'): terms.extend(['-', s_term[1:]]) else: terms.extend(['+', s_term]) if terms[0] in ['-', '+']: modifier = terms.pop(0) if modifier == '-': terms[0] = '-' + terms[0] format = expr.__class__.__name__ + "(%s, %s" from sympy.polys.polyerrors import PolynomialError try: format += ", modulus=%s" % expr.get_modulus() except PolynomialError: format += ", domain='%s'" % expr.get_domain() format += ")" for index, item in enumerate(gens): if len(item) > 2 and (item[:1] == "(" and item[len(item) - 1:] == ")"): gens[index] = item[1:len(item) - 1] return format % (' '.join(terms), ', '.join(gens)) def _print_UniversalSet(self, p): return 'UniversalSet' def _print_AlgebraicNumber(self, expr): if expr.is_aliased: return self._print(expr.as_poly().as_expr()) else: return self._print(expr.as_expr()) def _print_Pow(self, expr, rational=False): """Printing helper function for ``Pow`` Parameters ========== rational : bool, optional If ``True``, it will not attempt printing ``sqrt(x)`` or ``x**S.Half`` as ``sqrt``, and will use ``x**(1/2)`` instead. See examples for additional details Examples ======== >>> from sympy.functions import sqrt >>> from sympy.printing.str import StrPrinter >>> from sympy.abc import x How ``rational`` keyword works with ``sqrt``: >>> printer = StrPrinter() >>> printer._print_Pow(sqrt(x), rational=True) 'x**(1/2)' >>> printer._print_Pow(sqrt(x), rational=False) 'sqrt(x)' >>> printer._print_Pow(1/sqrt(x), rational=True) 'x**(-1/2)' >>> printer._print_Pow(1/sqrt(x), rational=False) '1/sqrt(x)' Notes ===== ``sqrt(x)`` is canonicalized as ``Pow(x, S.Half)`` in SymPy, so there is no need of defining a separate printer for ``sqrt``. Instead, it should be handled here as well. """ PREC = precedence(expr) if expr.exp is S.Half and not rational: return "sqrt(%s)" % self._print(expr.base) if expr.is_commutative: if -expr.exp is S.Half and not rational: # Note: Don't test "expr.exp == -S.Half" here, because that will # match -0.5, which we don't want. return "%s/sqrt(%s)" % tuple(map(lambda arg: self._print(arg), (S.One, expr.base))) if expr.exp is -S.One: # Similarly to the S.Half case, don't test with "==" here. return '%s/%s' % (self._print(S.One), self.parenthesize(expr.base, PREC, strict=False)) e = self.parenthesize(expr.exp, PREC, strict=False) if self.printmethod == '_sympyrepr' and expr.exp.is_Rational and expr.exp.q != 1: # the parenthesized exp should be '(Rational(a, b))' so strip parens, # but just check to be sure. if e.startswith('(Rational'): return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e[1:-1]) return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), e) def _print_UnevaluatedExpr(self, expr): return self._print(expr.args[0]) def _print_MatPow(self, expr): PREC = precedence(expr) return '%s**%s' % (self.parenthesize(expr.base, PREC, strict=False), self.parenthesize(expr.exp, PREC, strict=False)) def _print_Integer(self, expr): if self._settings.get("sympy_integers", False): return "S(%s)" % (expr) return str(expr.p) def _print_Integers(self, expr): return 'Integers' def _print_Naturals(self, expr): return 'Naturals' def _print_Naturals0(self, expr): return 'Naturals0' def _print_Rationals(self, expr): return 'Rationals' def _print_Reals(self, expr): return 'Reals' def _print_Complexes(self, expr): return 'Complexes' def _print_EmptySet(self, expr): return 'EmptySet' def _print_EmptySequence(self, expr): return 'EmptySequence' def _print_int(self, expr): return str(expr) def _print_mpz(self, expr): return str(expr) def _print_Rational(self, expr): if expr.q == 1: return str(expr.p) else: if self._settings.get("sympy_integers", False): return "S(%s)/%s" % (expr.p, expr.q) return "%s/%s" % (expr.p, expr.q) def _print_PythonRational(self, expr): if expr.q == 1: return str(expr.p) else: return "%d/%d" % (expr.p, expr.q) def _print_Fraction(self, expr): if expr.denominator == 1: return str(expr.numerator) else: return "%s/%s" % (expr.numerator, expr.denominator) def _print_mpq(self, expr): if expr.denominator == 1: return str(expr.numerator) else: return "%s/%s" % (expr.numerator, expr.denominator) def _print_Float(self, expr): prec = expr._prec if prec < 5: dps = 0 else: dps = prec_to_dps(expr._prec) if self._settings["full_prec"] is True: strip = False elif self._settings["full_prec"] is False: strip = True elif self._settings["full_prec"] == "auto": strip = self._print_level > 1 low = self._settings["min"] if "min" in self._settings else None high = self._settings["max"] if "max" in self._settings else None rv = mlib_to_str(expr._mpf_, dps, strip_zeros=strip, min_fixed=low, max_fixed=high) if rv.startswith('-.0'): rv = '-0.' + rv[3:] elif rv.startswith('.0'): rv = '0.' + rv[2:] if rv.startswith('+'): # e.g., +inf -> inf rv = rv[1:] return rv def _print_Relational(self, expr): charmap = { "==": "Eq", "!=": "Ne", ":=": "Assignment", '+=': "AddAugmentedAssignment", "-=": "SubAugmentedAssignment", "*=": "MulAugmentedAssignment", "/=": "DivAugmentedAssignment", "%=": "ModAugmentedAssignment", } if expr.rel_op in charmap: return '%s(%s, %s)' % (charmap[expr.rel_op], self._print(expr.lhs), self._print(expr.rhs)) return '%s %s %s' % (self.parenthesize(expr.lhs, precedence(expr)), self._relationals.get(expr.rel_op) or expr.rel_op, self.parenthesize(expr.rhs, precedence(expr))) def _print_ComplexRootOf(self, expr): return "CRootOf(%s, %d)" % (self._print_Add(expr.expr, order='lex'), expr.index) def _print_RootSum(self, expr): args = [self._print_Add(expr.expr, order='lex')] if expr.fun is not S.IdentityFunction: args.append(self._print(expr.fun)) return "RootSum(%s)" % ", ".join(args) def _print_GroebnerBasis(self, basis): cls = basis.__class__.__name__ exprs = [self._print_Add(arg, order=basis.order) for arg in basis.exprs] exprs = "[%s]" % ", ".join(exprs) gens = [ self._print(gen) for gen in basis.gens ] domain = "domain='%s'" % self._print(basis.domain) order = "order='%s'" % self._print(basis.order) args = [exprs] + gens + [domain, order] return "%s(%s)" % (cls, ", ".join(args)) def _print_set(self, s): items = sorted(s, key=default_sort_key) args = ', '.join(self._print(item) for item in items) if not args: return "set()" return '{%s}' % args def _print_FiniteSet(self, s): items = sorted(s, key=default_sort_key) args = ', '.join(self._print(item) for item in items) if any(item.has(FiniteSet) for item in items): return 'FiniteSet({})'.format(args) return '{{{}}}'.format(args) def _print_Partition(self, s): items = sorted(s, key=default_sort_key) args = ', '.join(self._print(arg) for arg in items) return 'Partition({})'.format(args) def _print_frozenset(self, s): if not s: return "frozenset()" return "frozenset(%s)" % self._print_set(s) def _print_Sum(self, expr): def _xab_tostr(xab): if len(xab) == 1: return self._print(xab[0]) else: return self._print((xab[0],) + tuple(xab[1:])) L = ', '.join([_xab_tostr(l) for l in expr.limits]) return 'Sum(%s, %s)' % (self._print(expr.function), L) def _print_Symbol(self, expr): return expr.name _print_MatrixSymbol = _print_Symbol _print_RandomSymbol = _print_Symbol def _print_Identity(self, expr): return "I" def _print_ZeroMatrix(self, expr): return "0" def _print_OneMatrix(self, expr): return "1" def _print_Predicate(self, expr): return "Q.%s" % expr.name def _print_str(self, expr): return str(expr) def _print_tuple(self, expr): if len(expr) == 1: return "(%s,)" % self._print(expr[0]) else: return "(%s)" % self.stringify(expr, ", ") def _print_Tuple(self, expr): return self._print_tuple(expr) def _print_Transpose(self, T): return "%s.T" % self.parenthesize(T.arg, PRECEDENCE["Pow"]) def _print_Uniform(self, expr): return "Uniform(%s, %s)" % (self._print(expr.a), self._print(expr.b)) def _print_Quantity(self, expr): if self._settings.get("abbrev", False): return "%s" % expr.abbrev return "%s" % expr.name def _print_Quaternion(self, expr): s = [self.parenthesize(i, PRECEDENCE["Mul"], strict=True) for i in expr.args] a = [s[0]] + [i+"*"+j for i, j in zip(s[1:], "ijk")] return " + ".join(a) def _print_Dimension(self, expr): return str(expr) def _print_Wild(self, expr): return expr.name + '_' def _print_WildFunction(self, expr): return expr.name + '_' def _print_WildDot(self, expr): return expr.name def _print_WildPlus(self, expr): return expr.name def _print_WildStar(self, expr): return expr.name def _print_Zero(self, expr): if self._settings.get("sympy_integers", False): return "S(0)" return "0" def _print_DMP(self, p): from sympy.core.sympify import SympifyError try: if p.ring is not None: # TODO incorporate order return self._print(p.ring.to_sympy(p)) except SympifyError: pass cls = p.__class__.__name__ rep = self._print(p.rep) dom = self._print(p.dom) ring = self._print(p.ring) return "%s(%s, %s, %s)" % (cls, rep, dom, ring) def _print_DMF(self, expr): return self._print_DMP(expr) def _print_Object(self, obj): return 'Object("%s")' % obj.name def _print_IdentityMorphism(self, morphism): return 'IdentityMorphism(%s)' % morphism.domain def _print_NamedMorphism(self, morphism): return 'NamedMorphism(%s, %s, "%s")' % \ (morphism.domain, morphism.codomain, morphism.name) def _print_Category(self, category): return 'Category("%s")' % category.name def _print_Manifold(self, manifold): return manifold.name.name def _print_Patch(self, patch): return patch.name.name def _print_CoordSystem(self, coords): return coords.name.name def _print_BaseScalarField(self, field): return field._coord_sys.symbols[field._index].name def _print_BaseVectorField(self, field): return 'e_%s' % field._coord_sys.symbols[field._index].name def _print_Differential(self, diff): field = diff._form_field if hasattr(field, '_coord_sys'): return 'd%s' % field._coord_sys.symbols[field._index].name else: return 'd(%s)' % self._print(field) def _print_Tr(self, expr): #TODO : Handle indices return "%s(%s)" % ("Tr", self._print(expr.args[0])) def _print_Str(self, s): return self._print(s.name) def _print_AppliedBinaryRelation(self, expr): rel = expr.function return '%s(%s, %s)' % (self._print(rel), self._print(expr.lhs), self._print(expr.rhs)) @print_function(StrPrinter) def sstr(expr, **settings): """Returns the expression as a string. For large expressions where speed is a concern, use the setting order='none'. If abbrev=True setting is used then units are printed in abbreviated form. Examples ======== >>> from sympy import symbols, Eq, sstr >>> a, b = symbols('a b') >>> sstr(Eq(a + b, 0)) 'Eq(a + b, 0)' """ p = StrPrinter(settings) s = p.doprint(expr) return s class StrReprPrinter(StrPrinter): """(internal) -- see sstrrepr""" def _print_str(self, s): return repr(s) def _print_Str(self, s): # Str does not to be printed same as str here return "%s(%s)" % (s.__class__.__name__, self._print(s.name)) @print_function(StrReprPrinter) def sstrrepr(expr, **settings): """return expr in mixed str/repr form i.e. strings are returned in repr form with quotes, and everything else is returned in str form. This function could be useful for hooking into sys.displayhook """ p = StrReprPrinter(settings) s = p.doprint(expr) return s sympy-sympy-1.9/sympy/printing/tableform.py000066400000000000000000000266561412543434000213020ustar00rootroot00000000000000from sympy.core.containers import Tuple from types import FunctionType class TableForm: r""" Create a nice table representation of data. Examples ======== >>> from sympy import TableForm >>> t = TableForm([[5, 7], [4, 2], [10, 3]]) >>> print(t) 5 7 4 2 10 3 You can use the SymPy's printing system to produce tables in any format (ascii, latex, html, ...). >>> print(t.as_latex()) \begin{tabular}{l l} $5$ & $7$ \\ $4$ & $2$ \\ $10$ & $3$ \\ \end{tabular} """ def __init__(self, data, **kwarg): """ Creates a TableForm. Parameters: data ... 2D data to be put into the table; data can be given as a Matrix headings ... gives the labels for rows and columns: Can be a single argument that applies to both dimensions: - None ... no labels - "automatic" ... labels are 1, 2, 3, ... Can be a list of labels for rows and columns: The labels for each dimension can be given as None, "automatic", or [l1, l2, ...] e.g. ["automatic", None] will number the rows [default: None] alignments ... alignment of the columns with: - "left" or "<" - "center" or "^" - "right" or ">" When given as a single value, the value is used for all columns. The row headings (if given) will be right justified unless an explicit alignment is given for it and all other columns. [default: "left"] formats ... a list of format strings or functions that accept 3 arguments (entry, row number, col number) and return a string for the table entry. (If a function returns None then the _print method will be used.) wipe_zeros ... Don't show zeros in the table. [default: True] pad ... the string to use to indicate a missing value (e.g. elements that are None or those that are missing from the end of a row (i.e. any row that is shorter than the rest is assumed to have missing values). When None, nothing will be shown for values that are missing from the end of a row; values that are None, however, will be shown. [default: None] Examples ======== >>> from sympy import TableForm, Symbol >>> TableForm([[5, 7], [4, 2], [10, 3]]) 5 7 4 2 10 3 >>> TableForm([list('.'*i) for i in range(1, 4)], headings='automatic') | 1 2 3 --------- 1 | . 2 | . . 3 | . . . >>> TableForm([[Symbol('.'*(j if not i%2 else 1)) for i in range(3)] ... for j in range(4)], alignments='rcl') . . . . .. . .. ... . ... """ from sympy import Symbol, S, Matrix from sympy.core.sympify import SympifyError # We only support 2D data. Check the consistency: if isinstance(data, Matrix): data = data.tolist() _h = len(data) # fill out any short lines pad = kwarg.get('pad', None) ok_None = False if pad is None: pad = " " ok_None = True pad = Symbol(pad) _w = max(len(line) for line in data) for i, line in enumerate(data): if len(line) != _w: line.extend([pad]*(_w - len(line))) for j, lj in enumerate(line): if lj is None: if not ok_None: lj = pad else: try: lj = S(lj) except SympifyError: lj = Symbol(str(lj)) line[j] = lj data[i] = line _lines = Tuple(*data) headings = kwarg.get("headings", [None, None]) if headings == "automatic": _headings = [range(1, _h + 1), range(1, _w + 1)] else: h1, h2 = headings if h1 == "automatic": h1 = range(1, _h + 1) if h2 == "automatic": h2 = range(1, _w + 1) _headings = [h1, h2] allow = ('l', 'r', 'c') alignments = kwarg.get("alignments", "l") def _std_align(a): a = a.strip().lower() if len(a) > 1: return {'left': 'l', 'right': 'r', 'center': 'c'}.get(a, a) else: return {'<': 'l', '>': 'r', '^': 'c'}.get(a, a) std_align = _std_align(alignments) if std_align in allow: _alignments = [std_align]*_w else: _alignments = [] for a in alignments: std_align = _std_align(a) _alignments.append(std_align) if std_align not in ('l', 'r', 'c'): raise ValueError('alignment "%s" unrecognized' % alignments) if _headings[0] and len(_alignments) == _w + 1: _head_align = _alignments[0] _alignments = _alignments[1:] else: _head_align = 'r' if len(_alignments) != _w: raise ValueError( 'wrong number of alignments: expected %s but got %s' % (_w, len(_alignments))) _column_formats = kwarg.get("formats", [None]*_w) _wipe_zeros = kwarg.get("wipe_zeros", True) self._w = _w self._h = _h self._lines = _lines self._headings = _headings self._head_align = _head_align self._alignments = _alignments self._column_formats = _column_formats self._wipe_zeros = _wipe_zeros def __repr__(self): from .str import sstr return sstr(self, order=None) def __str__(self): from .str import sstr return sstr(self, order=None) def as_matrix(self): """Returns the data of the table in Matrix form. Examples ======== >>> from sympy import TableForm >>> t = TableForm([[5, 7], [4, 2], [10, 3]], headings='automatic') >>> t | 1 2 -------- 1 | 5 7 2 | 4 2 3 | 10 3 >>> t.as_matrix() Matrix([ [ 5, 7], [ 4, 2], [10, 3]]) """ from sympy import Matrix return Matrix(self._lines) def as_str(self): # XXX obsolete ? return str(self) def as_latex(self): from .latex import latex return latex(self) def _sympystr(self, p): """ Returns the string representation of 'self'. Examples ======== >>> from sympy import TableForm >>> t = TableForm([[5, 7], [4, 2], [10, 3]]) >>> s = t.as_str() """ column_widths = [0] * self._w lines = [] for line in self._lines: new_line = [] for i in range(self._w): # Format the item somehow if needed: s = str(line[i]) if self._wipe_zeros and (s == "0"): s = " " w = len(s) if w > column_widths[i]: column_widths[i] = w new_line.append(s) lines.append(new_line) # Check heading: if self._headings[0]: self._headings[0] = [str(x) for x in self._headings[0]] _head_width = max([len(x) for x in self._headings[0]]) if self._headings[1]: new_line = [] for i in range(self._w): # Format the item somehow if needed: s = str(self._headings[1][i]) w = len(s) if w > column_widths[i]: column_widths[i] = w new_line.append(s) self._headings[1] = new_line format_str = [] def _align(align, w): return '%%%s%ss' % ( ("-" if align == "l" else ""), str(w)) format_str = [_align(align, w) for align, w in zip(self._alignments, column_widths)] if self._headings[0]: format_str.insert(0, _align(self._head_align, _head_width)) format_str.insert(1, '|') format_str = ' '.join(format_str) + '\n' s = [] if self._headings[1]: d = self._headings[1] if self._headings[0]: d = [""] + d first_line = format_str % tuple(d) s.append(first_line) s.append("-" * (len(first_line) - 1) + "\n") for i, line in enumerate(lines): d = [l if self._alignments[j] != 'c' else l.center(column_widths[j]) for j, l in enumerate(line)] if self._headings[0]: l = self._headings[0][i] l = (l if self._head_align != 'c' else l.center(_head_width)) d = [l] + d s.append(format_str % tuple(d)) return ''.join(s)[:-1] # don't include trailing newline def _latex(self, printer): """ Returns the string representation of 'self'. """ # Check heading: if self._headings[1]: new_line = [] for i in range(self._w): # Format the item somehow if needed: new_line.append(str(self._headings[1][i])) self._headings[1] = new_line alignments = [] if self._headings[0]: self._headings[0] = [str(x) for x in self._headings[0]] alignments = [self._head_align] alignments.extend(self._alignments) s = r"\begin{tabular}{" + " ".join(alignments) + "}\n" if self._headings[1]: d = self._headings[1] if self._headings[0]: d = [""] + d first_line = " & ".join(d) + r" \\" + "\n" s += first_line s += r"\hline" + "\n" for i, line in enumerate(self._lines): d = [] for j, x in enumerate(line): if self._wipe_zeros and (x in (0, "0")): d.append(" ") continue f = self._column_formats[j] if f: if isinstance(f, FunctionType): v = f(x, i, j) if v is None: v = printer._print(x) else: v = f % x d.append(v) else: v = printer._print(x) d.append("$%s$" % v) if self._headings[0]: d = [self._headings[0][i]] + d s += " & ".join(d) + r" \\" + "\n" s += r"\end{tabular}" return s sympy-sympy-1.9/sympy/printing/tensorflow.py000066400000000000000000000247761412543434000215320ustar00rootroot00000000000000from sympy.external.importtools import version_tuple from collections.abc import Iterable from sympy import Mul, S from sympy.codegen.cfunctions import Sqrt from sympy.external import import_module from sympy.printing.precedence import PRECEDENCE from sympy.printing.pycode import AbstractPythonCodePrinter import sympy tensorflow = import_module('tensorflow') class TensorflowPrinter(AbstractPythonCodePrinter): """ Tensorflow printer which handles vectorized piecewise functions, logical operators, max/min, and relational operators. """ printmethod = "_tensorflowcode" mapping = { sympy.Abs: "tensorflow.math.abs", sympy.sign: "tensorflow.math.sign", # XXX May raise error for ints. sympy.ceiling: "tensorflow.math.ceil", sympy.floor: "tensorflow.math.floor", sympy.log: "tensorflow.math.log", sympy.exp: "tensorflow.math.exp", Sqrt: "tensorflow.math.sqrt", sympy.cos: "tensorflow.math.cos", sympy.acos: "tensorflow.math.acos", sympy.sin: "tensorflow.math.sin", sympy.asin: "tensorflow.math.asin", sympy.tan: "tensorflow.math.tan", sympy.atan: "tensorflow.math.atan", sympy.atan2: "tensorflow.math.atan2", # XXX Also may give NaN for complex results. sympy.cosh: "tensorflow.math.cosh", sympy.acosh: "tensorflow.math.acosh", sympy.sinh: "tensorflow.math.sinh", sympy.asinh: "tensorflow.math.asinh", sympy.tanh: "tensorflow.math.tanh", sympy.atanh: "tensorflow.math.atanh", sympy.re: "tensorflow.math.real", sympy.im: "tensorflow.math.imag", sympy.arg: "tensorflow.math.angle", # XXX May raise error for ints and complexes sympy.erf: "tensorflow.math.erf", sympy.loggamma: "tensorflow.math.lgamma", sympy.Eq: "tensorflow.math.equal", sympy.Ne: "tensorflow.math.not_equal", sympy.StrictGreaterThan: "tensorflow.math.greater", sympy.StrictLessThan: "tensorflow.math.less", sympy.LessThan: "tensorflow.math.less_equal", sympy.GreaterThan: "tensorflow.math.greater_equal", sympy.And: "tensorflow.math.logical_and", sympy.Or: "tensorflow.math.logical_or", sympy.Not: "tensorflow.math.logical_not", sympy.Max: "tensorflow.math.maximum", sympy.Min: "tensorflow.math.minimum", # Matrices sympy.MatAdd: "tensorflow.math.add", sympy.HadamardProduct: "tensorflow.math.multiply", sympy.Trace: "tensorflow.linalg.trace", # XXX May raise error for integer matrices. sympy.Determinant : "tensorflow.linalg.det", } _default_settings = dict( AbstractPythonCodePrinter._default_settings, tensorflow_version=None ) def __init__(self, settings=None): super().__init__(settings) version = self._settings['tensorflow_version'] if version is None and tensorflow: version = tensorflow.__version__ self.tensorflow_version = version def _print_Function(self, expr): op = self.mapping.get(type(expr), None) if op is None: return super()._print_Basic(expr) children = [self._print(arg) for arg in expr.args] if len(children) == 1: return "%s(%s)" % ( self._module_format(op), children[0] ) else: return self._expand_fold_binary_op(op, children) _print_Expr = _print_Function _print_Application = _print_Function _print_MatrixExpr = _print_Function # TODO: a better class structure would avoid this mess: _print_Relational = _print_Function _print_Not = _print_Function _print_And = _print_Function _print_Or = _print_Function _print_HadamardProduct = _print_Function _print_Trace = _print_Function _print_Determinant = _print_Function def _print_Inverse(self, expr): op = self._module_format('tensorflow.linalg.inv') return "{}({})".format(op, self._print(expr.arg)) def _print_Transpose(self, expr): version = self.tensorflow_version if version and version_tuple(version) < version_tuple('1.14'): op = self._module_format('tensorflow.matrix_transpose') else: op = self._module_format('tensorflow.linalg.matrix_transpose') return "{}({})".format(op, self._print(expr.arg)) def _print_Derivative(self, expr): variables = expr.variables if any(isinstance(i, Iterable) for i in variables): raise NotImplementedError("derivation by multiple variables is not supported") def unfold(expr, args): if not args: return self._print(expr) return "%s(%s, %s)[0]" % ( self._module_format("tensorflow.gradients"), unfold(expr, args[:-1]), self._print(args[-1]), ) return unfold(expr.expr, variables) def _print_Piecewise(self, expr): version = self.tensorflow_version if version and version_tuple(version) < version_tuple('1.0'): tensorflow_piecewise = "tensorflow.select" else: tensorflow_piecewise = "tensorflow.where" from sympy import Piecewise e, cond = expr.args[0].args if len(expr.args) == 1: return '{}({}, {}, {})'.format( self._module_format(tensorflow_piecewise), self._print(cond), self._print(e), 0) return '{}({}, {}, {})'.format( self._module_format(tensorflow_piecewise), self._print(cond), self._print(e), self._print(Piecewise(*expr.args[1:]))) def _print_Pow(self, expr): # XXX May raise error for # int**float or int**complex or float**complex base, exp = expr.args if expr.exp == S.Half: return "{}({})".format( self._module_format("tensorflow.math.sqrt"), self._print(base)) return "{}({}, {})".format( self._module_format("tensorflow.math.pow"), self._print(base), self._print(exp)) def _print_MatrixBase(self, expr): tensorflow_f = "tensorflow.Variable" if expr.free_symbols else "tensorflow.constant" data = "["+", ".join(["["+", ".join([self._print(j) for j in i])+"]" for i in expr.tolist()])+"]" return "%s(%s)" % ( self._module_format(tensorflow_f), data, ) def _print_MatMul(self, expr): from sympy.matrices.expressions import MatrixExpr mat_args = [arg for arg in expr.args if isinstance(arg, MatrixExpr)] args = [arg for arg in expr.args if arg not in mat_args] if args: return "%s*%s" % ( self.parenthesize(Mul.fromiter(args), PRECEDENCE["Mul"]), self._expand_fold_binary_op( "tensorflow.linalg.matmul", mat_args) ) else: return self._expand_fold_binary_op( "tensorflow.linalg.matmul", mat_args) def _print_MatPow(self, expr): return self._expand_fold_binary_op( "tensorflow.linalg.matmul", [expr.base]*expr.exp) def _print_Assignment(self, expr): # TODO: is this necessary? return "%s = %s" % ( self._print(expr.lhs), self._print(expr.rhs), ) def _print_CodeBlock(self, expr): # TODO: is this necessary? ret = [] for subexpr in expr.args: ret.append(self._print(subexpr)) return "\n".join(ret) def _get_letter_generator_for_einsum(self): for i in range(97, 123): yield chr(i) for i in range(65, 91): yield chr(i) raise ValueError("out of letters") def _print_ArrayTensorProduct(self, expr): letters = self._get_letter_generator_for_einsum() contraction_string = ",".join(["".join([next(letters) for j in range(i)]) for i in expr.subranks]) return '%s("%s", %s)' % ( self._module_format('tensorflow.linalg.einsum'), contraction_string, ", ".join([self._print(arg) for arg in expr.args]) ) def _print_ArrayContraction(self, expr): from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct base = expr.expr contraction_indices = expr.contraction_indices contraction_string, letters_free, letters_dum = self._get_einsum_string(base.subranks, contraction_indices) if not contraction_indices: return self._print(base) if isinstance(base, ArrayTensorProduct): elems = ["%s" % (self._print(arg)) for arg in base.args] return "%s(\"%s\", %s)" % ( self._module_format("tensorflow.linalg.einsum"), contraction_string, ", ".join(elems) ) raise NotImplementedError() def _print_ArrayDiagonal(self, expr): from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct diagonal_indices = list(expr.diagonal_indices) if len(diagonal_indices) > 1: # TODO: this should be handled in sympy.codegen.array_utils, # possibly by creating the possibility of unfolding the # ArrayDiagonal object into nested ones. Same reasoning for # the array contraction. raise NotImplementedError if len(diagonal_indices[0]) != 2: raise NotImplementedError if isinstance(expr.expr, ArrayTensorProduct): subranks = expr.expr.subranks elems = expr.expr.args else: subranks = expr.subranks elems = [expr.expr] diagonal_string, letters_free, letters_dum = self._get_einsum_string(subranks, diagonal_indices) elems = [self._print(i) for i in elems] return '%s("%s", %s)' % ( self._module_format("tensorflow.linalg.einsum"), "{}->{}{}".format(diagonal_string, "".join(letters_free), "".join(letters_dum)), ", ".join(elems) ) def _print_PermuteDims(self, expr): return "%s(%s, %s)" % ( self._module_format("tensorflow.transpose"), self._print(expr.expr), self._print(expr.permutation.array_form), ) def _print_ArrayAdd(self, expr): return self._expand_fold_binary_op('tensorflow.math.add', expr.args) def tensorflow_code(expr, **settings): printer = TensorflowPrinter(settings) return printer.doprint(expr) sympy-sympy-1.9/sympy/printing/tests/000077500000000000000000000000001412543434000201005ustar00rootroot00000000000000sympy-sympy-1.9/sympy/printing/tests/__init__.py000066400000000000000000000000001412543434000221770ustar00rootroot00000000000000sympy-sympy-1.9/sympy/printing/tests/test_aesaracode.py000066400000000000000000000505331412543434000236060ustar00rootroot00000000000000""" Important note on tests in this module - the Aesara printing functions use a global cache by default, which means that tests using it will modify global state and thus not be independent from each other. Instead of using the "cache" keyword argument each time, this module uses the aesara_code_ and aesara_function_ functions defined below which default to using a new, empty cache instead. """ import logging from sympy.external import import_module from sympy.testing.pytest import raises, SKIP aesaralogger = logging.getLogger('aesara.configdefaults') aesaralogger.setLevel(logging.CRITICAL) aesara = import_module('aesara') aesaralogger.setLevel(logging.WARNING) if aesara: import numpy as np aet = aesara.tensor from aesara.scalar.basic import Scalar from aesara.graph.basic import Variable from aesara.tensor.var import TensorVariable from aesara.tensor.elemwise import Elemwise, DimShuffle from aesara.tensor.math import Dot xt, yt, zt = [aet.scalar(name, 'floatX') for name in 'xyz'] Xt, Yt, Zt = [aet.tensor('floatX', (False, False), name=n) for n in 'XYZ'] else: #bin/test will not execute any tests now disabled = True import sympy as sy from sympy import S from sympy.abc import x, y, z, t from sympy.printing.aesaracode import (aesara_code, dim_handling, aesara_function) # Default set of matrix symbols for testing - make square so we can both # multiply and perform elementwise operations between them. X, Y, Z = [sy.MatrixSymbol(n, 4, 4) for n in 'XYZ'] # For testing AppliedUndef f_t = sy.Function('f')(t) def aesara_code_(expr, **kwargs): """ Wrapper for aesara_code that uses a new, empty cache by default. """ kwargs.setdefault('cache', {}) return aesara_code(expr, **kwargs) def aesara_function_(inputs, outputs, **kwargs): """ Wrapper for aesara_function that uses a new, empty cache by default. """ kwargs.setdefault('cache', {}) return aesara_function(inputs, outputs, **kwargs) def fgraph_of(*exprs): """ Transform SymPy expressions into Aesara Computation. Parameters ========== exprs Sympy expressions Returns ======= aesara.graph.fg.FunctionGraph """ outs = list(map(aesara_code_, exprs)) ins = list(aesara.graph.basic.graph_inputs(outs)) ins, outs = aesara.graph.basic.clone(ins, outs) return aesara.graph.fg.FunctionGraph(ins, outs) def aesara_simplify(fgraph): """ Simplify a Aesara Computation. Parameters ========== fgraph : aesara.graph.fg.FunctionGraph Returns ======= aesara.graph.fg.FunctionGraph """ mode = aesara.compile.get_default_mode().excluding("fusion") fgraph = fgraph.clone() mode.optimizer.optimize(fgraph) return fgraph def theq(a, b): """ Test two Aesara objects for equality. Also accepts numeric types and lists/tuples of supported types. Note - debugprint() has a bug where it will accept numeric types but does not respect the "file" argument and in this case and instead prints the number to stdout and returns an empty string. This can lead to tests passing where they should fail because any two numbers will always compare as equal. To prevent this we treat numbers as a separate case. """ numeric_types = (int, float, np.number) a_is_num = isinstance(a, numeric_types) b_is_num = isinstance(b, numeric_types) # Compare numeric types using regular equality if a_is_num or b_is_num: if not (a_is_num and b_is_num): return False return a == b # Compare sequences element-wise a_is_seq = isinstance(a, (tuple, list)) b_is_seq = isinstance(b, (tuple, list)) if a_is_seq or b_is_seq: if not (a_is_seq and b_is_seq) or type(a) != type(b): return False return list(map(theq, a)) == list(map(theq, b)) # Otherwise, assume debugprint() can handle it astr = aesara.printing.debugprint(a, file='str') bstr = aesara.printing.debugprint(b, file='str') # Check for bug mentioned above for argname, argval, argstr in [('a', a, astr), ('b', b, bstr)]: if argstr == '': raise TypeError( 'aesara.printing.debugprint(%s) returned empty string ' '(%s is instance of %r)' % (argname, argname, type(argval)) ) return astr == bstr def test_example_symbols(): """ Check that the example symbols in this module print to their Aesara equivalents, as many of the other tests depend on this. """ assert theq(xt, aesara_code_(x)) assert theq(yt, aesara_code_(y)) assert theq(zt, aesara_code_(z)) assert theq(Xt, aesara_code_(X)) assert theq(Yt, aesara_code_(Y)) assert theq(Zt, aesara_code_(Z)) def test_Symbol(): """ Test printing a Symbol to a aesara variable. """ xx = aesara_code_(x) assert isinstance(xx, Variable) assert xx.broadcastable == () assert xx.name == x.name xx2 = aesara_code_(x, broadcastables={x: (False,)}) assert xx2.broadcastable == (False,) assert xx2.name == x.name def test_MatrixSymbol(): """ Test printing a MatrixSymbol to a aesara variable. """ XX = aesara_code_(X) assert isinstance(XX, TensorVariable) assert XX.broadcastable == (False, False) @SKIP # TODO - this is currently not checked but should be implemented def test_MatrixSymbol_wrong_dims(): """ Test MatrixSymbol with invalid broadcastable. """ bcs = [(), (False,), (True,), (True, False), (False, True,), (True, True)] for bc in bcs: with raises(ValueError): aesara_code_(X, broadcastables={X: bc}) def test_AppliedUndef(): """ Test printing AppliedUndef instance, which works similarly to Symbol. """ ftt = aesara_code_(f_t) assert isinstance(ftt, TensorVariable) assert ftt.broadcastable == () assert ftt.name == 'f_t' def test_add(): expr = x + y comp = aesara_code_(expr) assert comp.owner.op == aesara.tensor.add def test_trig(): assert theq(aesara_code_(sy.sin(x)), aet.sin(xt)) assert theq(aesara_code_(sy.tan(x)), aet.tan(xt)) def test_many(): """ Test printing a complex expression with multiple symbols. """ expr = sy.exp(x**2 + sy.cos(y)) * sy.log(2*z) comp = aesara_code_(expr) expected = aet.exp(xt**2 + aet.cos(yt)) * aet.log(2*zt) assert theq(comp, expected) def test_dtype(): """ Test specifying specific data types through the dtype argument. """ for dtype in ['float32', 'float64', 'int8', 'int16', 'int32', 'int64']: assert aesara_code_(x, dtypes={x: dtype}).type.dtype == dtype # "floatX" type assert aesara_code_(x, dtypes={x: 'floatX'}).type.dtype in ('float32', 'float64') # Type promotion assert aesara_code_(x + 1, dtypes={x: 'float32'}).type.dtype == 'float32' assert aesara_code_(x + y, dtypes={x: 'float64', y: 'float32'}).type.dtype == 'float64' def test_broadcastables(): """ Test the "broadcastables" argument when printing symbol-like objects. """ # No restrictions on shape for s in [x, f_t]: for bc in [(), (False,), (True,), (False, False), (True, False)]: assert aesara_code_(s, broadcastables={s: bc}).broadcastable == bc # TODO - matrix broadcasting? def test_broadcasting(): """ Test "broadcastable" attribute after applying element-wise binary op. """ expr = x + y cases = [ [(), (), ()], [(False,), (False,), (False,)], [(True,), (False,), (False,)], [(False, True), (False, False), (False, False)], [(True, False), (False, False), (False, False)], ] for bc1, bc2, bc3 in cases: comp = aesara_code_(expr, broadcastables={x: bc1, y: bc2}) assert comp.broadcastable == bc3 def test_MatMul(): expr = X*Y*Z expr_t = aesara_code_(expr) assert isinstance(expr_t.owner.op, Dot) assert theq(expr_t, Xt.dot(Yt).dot(Zt)) def test_Transpose(): assert isinstance(aesara_code_(X.T).owner.op, DimShuffle) def test_MatAdd(): expr = X+Y+Z assert isinstance(aesara_code_(expr).owner.op, Elemwise) def test_Rationals(): assert theq(aesara_code_(sy.Integer(2) / 3), aet.true_div(2, 3)) assert theq(aesara_code_(S.Half), aet.true_div(1, 2)) def test_Integers(): assert aesara_code_(sy.Integer(3)) == 3 def test_factorial(): n = sy.Symbol('n') assert aesara_code_(sy.factorial(n)) def test_Derivative(): simp = lambda expr: aesara_simplify(fgraph_of(expr)) assert theq(simp(aesara_code_(sy.Derivative(sy.sin(x), x, evaluate=False))), simp(aesara.grad(aet.sin(xt), xt))) def test_aesara_function_simple(): """ Test aesara_function() with single output. """ f = aesara_function_([x, y], [x+y]) assert f(2, 3) == 5 def test_aesara_function_multi(): """ Test aesara_function() with multiple outputs. """ f = aesara_function_([x, y], [x+y, x-y]) o1, o2 = f(2, 3) assert o1 == 5 assert o2 == -1 def test_aesara_function_numpy(): """ Test aesara_function() vs Numpy implementation. """ f = aesara_function_([x, y], [x+y], dim=1, dtypes={x: 'float64', y: 'float64'}) assert np.linalg.norm(f([1, 2], [3, 4]) - np.asarray([4, 6])) < 1e-9 f = aesara_function_([x, y], [x+y], dtypes={x: 'float64', y: 'float64'}, dim=1) xx = np.arange(3).astype('float64') yy = 2*np.arange(3).astype('float64') assert np.linalg.norm(f(xx, yy) - 3*np.arange(3)) < 1e-9 def test_aesara_function_matrix(): m = sy.Matrix([[x, y], [z, x + y + z]]) expected = np.array([[1.0, 2.0], [3.0, 1.0 + 2.0 + 3.0]]) f = aesara_function_([x, y, z], [m]) np.testing.assert_allclose(f(1.0, 2.0, 3.0), expected) f = aesara_function_([x, y, z], [m], scalar=True) np.testing.assert_allclose(f(1.0, 2.0, 3.0), expected) f = aesara_function_([x, y, z], [m, m]) assert isinstance(f(1.0, 2.0, 3.0), type([])) np.testing.assert_allclose(f(1.0, 2.0, 3.0)[0], expected) np.testing.assert_allclose(f(1.0, 2.0, 3.0)[1], expected) def test_dim_handling(): assert dim_handling([x], dim=2) == {x: (False, False)} assert dim_handling([x, y], dims={x: 1, y: 2}) == {x: (False, True), y: (False, False)} assert dim_handling([x], broadcastables={x: (False,)}) == {x: (False,)} def test_aesara_function_kwargs(): """ Test passing additional kwargs from aesara_function() to aesara.function(). """ import numpy as np f = aesara_function_([x, y, z], [x+y], dim=1, on_unused_input='ignore', dtypes={x: 'float64', y: 'float64', z: 'float64'}) assert np.linalg.norm(f([1, 2], [3, 4], [0, 0]) - np.asarray([4, 6])) < 1e-9 f = aesara_function_([x, y, z], [x+y], dtypes={x: 'float64', y: 'float64', z: 'float64'}, dim=1, on_unused_input='ignore') xx = np.arange(3).astype('float64') yy = 2*np.arange(3).astype('float64') zz = 2*np.arange(3).astype('float64') assert np.linalg.norm(f(xx, yy, zz) - 3*np.arange(3)) < 1e-9 def test_aesara_function_scalar(): """ Test the "scalar" argument to aesara_function(). """ from aesara.compile.function.types import Function args = [ ([x, y], [x + y], None, [0]), # Single 0d output ([X, Y], [X + Y], None, [2]), # Single 2d output ([x, y], [x + y], {x: 0, y: 1}, [1]), # Single 1d output ([x, y], [x + y, x - y], None, [0, 0]), # Two 0d outputs ([x, y, X, Y], [x + y, X + Y], None, [0, 2]), # One 0d output, one 2d ] # Create and test functions with and without the scalar setting for inputs, outputs, in_dims, out_dims in args: for scalar in [False, True]: f = aesara_function_(inputs, outputs, dims=in_dims, scalar=scalar) # Check the aesara_function attribute is set whether wrapped or not assert isinstance(f.aesara_function, Function) # Feed in inputs of the appropriate size and get outputs in_values = [ np.ones([1 if bc else 5 for bc in i.type.broadcastable]) for i in f.aesara_function.input_storage ] out_values = f(*in_values) if not isinstance(out_values, list): out_values = [out_values] # Check output types and shapes assert len(out_dims) == len(out_values) for d, value in zip(out_dims, out_values): if scalar and d == 0: # Should have been converted to a scalar value assert isinstance(value, np.number) else: # Otherwise should be an array assert isinstance(value, np.ndarray) assert value.ndim == d def test_aesara_function_bad_kwarg(): """ Passing an unknown keyword argument to aesara_function() should raise an exception. """ raises(Exception, lambda : aesara_function_([x], [x+1], foobar=3)) def test_slice(): assert aesara_code_(slice(1, 2, 3)) == slice(1, 2, 3) def theq_slice(s1, s2): for attr in ['start', 'stop', 'step']: a1 = getattr(s1, attr) a2 = getattr(s2, attr) if a1 is None or a2 is None: if not (a1 is None or a2 is None): return False elif not theq(a1, a2): return False return True dtypes = {x: 'int32', y: 'int32'} assert theq_slice(aesara_code_(slice(x, y), dtypes=dtypes), slice(xt, yt)) assert theq_slice(aesara_code_(slice(1, x, 3), dtypes=dtypes), slice(1, xt, 3)) def test_MatrixSlice(): from aesara.graph.basic import Constant cache = {} n = sy.Symbol('n', integer=True) X = sy.MatrixSymbol('X', n, n) Y = X[1:2:3, 4:5:6] Yt = aesara_code_(Y, cache=cache) s = Scalar('int64') assert tuple(Yt.owner.op.idx_list) == (slice(s, s, s), slice(s, s, s)) assert Yt.owner.inputs[0] == aesara_code_(X, cache=cache) # == doesn't work in Aesara like it does in SymPy. You have to use # equals. assert all(Yt.owner.inputs[i].equals(Constant(s, i)) for i in range(1, 7)) k = sy.Symbol('k') aesara_code_(k, dtypes={k: 'int32'}) start, stop, step = 4, k, 2 Y = X[start:stop:step] Yt = aesara_code_(Y, dtypes={n: 'int32', k: 'int32'}) # assert Yt.owner.op.idx_list[0].stop == kt def test_BlockMatrix(): n = sy.Symbol('n', integer=True) A, B, C, D = [sy.MatrixSymbol(name, n, n) for name in 'ABCD'] At, Bt, Ct, Dt = map(aesara_code_, (A, B, C, D)) Block = sy.BlockMatrix([[A, B], [C, D]]) Blockt = aesara_code_(Block) solutions = [aet.join(0, aet.join(1, At, Bt), aet.join(1, Ct, Dt)), aet.join(1, aet.join(0, At, Ct), aet.join(0, Bt, Dt))] assert any(theq(Blockt, solution) for solution in solutions) @SKIP def test_BlockMatrix_Inverse_execution(): k, n = 2, 4 dtype = 'float32' A = sy.MatrixSymbol('A', n, k) B = sy.MatrixSymbol('B', n, n) inputs = A, B output = B.I*A cutsizes = {A: [(n//2, n//2), (k//2, k//2)], B: [(n//2, n//2), (n//2, n//2)]} cutinputs = [sy.blockcut(i, *cutsizes[i]) for i in inputs] cutoutput = output.subs(dict(zip(inputs, cutinputs))) dtypes = dict(zip(inputs, [dtype]*len(inputs))) f = aesara_function_(inputs, [output], dtypes=dtypes, cache={}) fblocked = aesara_function_(inputs, [sy.block_collapse(cutoutput)], dtypes=dtypes, cache={}) ninputs = [np.random.rand(*x.shape).astype(dtype) for x in inputs] ninputs = [np.arange(n*k).reshape(A.shape).astype(dtype), np.eye(n).astype(dtype)] ninputs[1] += np.ones(B.shape)*1e-5 assert np.allclose(f(*ninputs), fblocked(*ninputs), rtol=1e-5) def test_DenseMatrix(): from aesara.tensor.basic import Join t = sy.Symbol('theta') for MatrixType in [sy.Matrix, sy.ImmutableMatrix]: X = MatrixType([[sy.cos(t), -sy.sin(t)], [sy.sin(t), sy.cos(t)]]) tX = aesara_code_(X) assert isinstance(tX, TensorVariable) assert isinstance(tX.owner.op, Join) def test_cache_basic(): """ Test single symbol-like objects are cached when printed by themselves. """ # Pairs of objects which should be considered equivalent with respect to caching pairs = [ (x, sy.Symbol('x')), (X, sy.MatrixSymbol('X', *X.shape)), (f_t, sy.Function('f')(sy.Symbol('t'))), ] for s1, s2 in pairs: cache = {} st = aesara_code_(s1, cache=cache) # Test hit with same instance assert aesara_code_(s1, cache=cache) is st # Test miss with same instance but new cache assert aesara_code_(s1, cache={}) is not st # Test hit with different but equivalent instance assert aesara_code_(s2, cache=cache) is st def test_global_cache(): """ Test use of the global cache. """ from sympy.printing.aesaracode import global_cache backup = dict(global_cache) try: # Temporarily empty global cache global_cache.clear() for s in [x, X, f_t]: st = aesara_code(s) assert aesara_code(s) is st finally: # Restore global cache global_cache.update(backup) def test_cache_types_distinct(): """ Test that symbol-like objects of different types (Symbol, MatrixSymbol, AppliedUndef) are distinguished by the cache even if they have the same name. """ symbols = [sy.Symbol('f_t'), sy.MatrixSymbol('f_t', 4, 4), f_t] cache = {} # Single shared cache printed = {} for s in symbols: st = aesara_code_(s, cache=cache) assert st not in printed.values() printed[s] = st # Check all printed objects are distinct assert len(set(map(id, printed.values()))) == len(symbols) # Check retrieving for s, st in printed.items(): assert aesara_code(s, cache=cache) is st def test_symbols_are_created_once(): """ Test that a symbol is cached and reused when it appears in an expression more than once. """ expr = sy.Add(x, x, evaluate=False) comp = aesara_code_(expr) assert theq(comp, xt + xt) assert not theq(comp, xt + aesara_code_(x)) def test_cache_complex(): """ Test caching on a complicated expression with multiple symbols appearing multiple times. """ expr = x ** 2 + (y - sy.exp(x)) * sy.sin(z - x * y) symbol_names = {s.name for s in expr.free_symbols} expr_t = aesara_code_(expr) # Iterate through variables in the Aesara computational graph that the # printed expression depends on seen = set() for v in aesara.graph.basic.ancestors([expr_t]): # Owner-less, non-constant variables should be our symbols if v.owner is None and not isinstance(v, aesara.graph.basic.Constant): # Check it corresponds to a symbol and appears only once assert v.name in symbol_names assert v.name not in seen seen.add(v.name) # Check all were present assert seen == symbol_names def test_Piecewise(): # A piecewise linear expr = sy.Piecewise((0, x<0), (x, x<2), (1, True)) # ___/III result = aesara_code_(expr) assert result.owner.op == aet.switch expected = aet.switch(xt<0, 0, aet.switch(xt<2, xt, 1)) assert theq(result, expected) expr = sy.Piecewise((x, x < 0)) result = aesara_code_(expr) expected = aet.switch(xt < 0, xt, np.nan) assert theq(result, expected) expr = sy.Piecewise((0, sy.And(x>0, x<2)), \ (x, sy.Or(x>2, x<0))) result = aesara_code_(expr) expected = aet.switch(aet.and_(xt>0,xt<2), 0, \ aet.switch(aet.or_(xt>2, xt<0), xt, np.nan)) assert theq(result, expected) def test_Relationals(): assert theq(aesara_code_(sy.Eq(x, y)), aet.eq(xt, yt)) # assert theq(aesara_code_(sy.Ne(x, y)), aet.neq(xt, yt)) # TODO - implement assert theq(aesara_code_(x > y), xt > yt) assert theq(aesara_code_(x < y), xt < yt) assert theq(aesara_code_(x >= y), xt >= yt) assert theq(aesara_code_(x <= y), xt <= yt) def test_complexfunctions(): xt, yt = aesara_code(x, dtypes={x:'complex128'}), aesara_code(y, dtypes={y: 'complex128'}) from sympy import conjugate from aesara.tensor import as_tensor_variable as atv from aesara.tensor import complex as cplx assert theq(aesara_code(y*conjugate(x)), yt*(xt.conj())) assert theq(aesara_code((1+2j)*x), xt*(atv(1.0)+atv(2.0)*cplx(0,1))) def test_constantfunctions(): tf = aesara_function([],[1+1j]) assert(tf()==1+1j) sympy-sympy-1.9/sympy/printing/tests/test_c.py000066400000000000000000000704471412543434000217470ustar00rootroot00000000000000from sympy.core import ( S, pi, oo, symbols, Rational, Integer, Float, Mod, GoldenRatio, EulerGamma, Catalan, Lambda, Dummy, Eq, nan, Mul, Pow ) from sympy.functions import ( Abs, acos, acosh, asin, asinh, atan, atanh, atan2, ceiling, cos, cosh, erf, erfc, exp, floor, gamma, log, loggamma, Max, Min, Piecewise, sign, sin, sinh, sqrt, tan, tanh ) from sympy.sets import Range from sympy.logic import ITE from sympy.codegen import For, aug_assign, Assignment from sympy.testing.pytest import raises, XFAIL, warns_deprecated_sympy from sympy.printing.c import C89CodePrinter, C99CodePrinter, get_math_macros from sympy.codegen.ast import ( AddAugmentedAssignment, Element, Type, FloatType, Declaration, Pointer, Variable, value_const, pointer_const, While, Scope, Print, FunctionPrototype, FunctionDefinition, FunctionCall, Return, real, float32, float64, float80, float128, intc, Comment, CodeBlock ) from sympy.codegen.cfunctions import expm1, log1p, exp2, log2, fma, log10, Cbrt, hypot, Sqrt from sympy.codegen.cnodes import restrict from sympy.utilities.lambdify import implemented_function from sympy.tensor import IndexedBase, Idx from sympy.matrices import Matrix, MatrixSymbol, SparseMatrix from sympy import ccode x, y, z = symbols('x,y,z') def test_printmethod(): class fabs(Abs): def _ccode(self, printer): return "fabs(%s)" % printer._print(self.args[0]) assert ccode(fabs(x)) == "fabs(x)" def test_ccode_sqrt(): assert ccode(sqrt(x)) == "sqrt(x)" assert ccode(x**0.5) == "sqrt(x)" assert ccode(sqrt(x)) == "sqrt(x)" def test_ccode_Pow(): assert ccode(x**3) == "pow(x, 3)" assert ccode(x**(y**3)) == "pow(x, pow(y, 3))" g = implemented_function('g', Lambda(x, 2*x)) assert ccode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "pow(3.5*2*x, -x + pow(y, x))/(pow(x, 2) + y)" assert ccode(x**-1.0) == '1.0/x' assert ccode(x**Rational(2, 3)) == 'pow(x, 2.0/3.0)' assert ccode(x**Rational(2, 3), type_aliases={real: float80}) == 'powl(x, 2.0L/3.0L)' _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi"), (lambda base, exp: not exp.is_integer, "pow")] assert ccode(x**3, user_functions={'Pow': _cond_cfunc}) == 'dpowi(x, 3)' assert ccode(x**0.5, user_functions={'Pow': _cond_cfunc}) == 'pow(x, 0.5)' assert ccode(x**Rational(16, 5), user_functions={'Pow': _cond_cfunc}) == 'pow(x, 16.0/5.0)' _cond_cfunc2 = [(lambda base, exp: base == 2, lambda base, exp: 'exp2(%s)' % exp), (lambda base, exp: base != 2, 'pow')] # Related to gh-11353 assert ccode(2**x, user_functions={'Pow': _cond_cfunc2}) == 'exp2(x)' assert ccode(x**2, user_functions={'Pow': _cond_cfunc2}) == 'pow(x, 2)' # For issue 14160 assert ccode(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False), evaluate=False)) == '-2*x/(y*y)' def test_ccode_Max(): # Test for gh-11926 assert ccode(Max(x,x*x),user_functions={"Max":"my_max", "Pow":"my_pow"}) == 'my_max(x, my_pow(x, 2))' def test_ccode_Min_performance(): #Shouldn't take more than a few seconds big_min = Min(*symbols('a[0:50]')) for curr_standard in ('c89', 'c99', 'c11'): output = ccode(big_min, standard=curr_standard) assert output.count('(') == output.count(')') def test_ccode_constants_mathh(): assert ccode(exp(1)) == "M_E" assert ccode(pi) == "M_PI" assert ccode(oo, standard='c89') == "HUGE_VAL" assert ccode(-oo, standard='c89') == "-HUGE_VAL" assert ccode(oo) == "INFINITY" assert ccode(-oo, standard='c99') == "-INFINITY" assert ccode(pi, type_aliases={real: float80}) == "M_PIl" def test_ccode_constants_other(): assert ccode(2*GoldenRatio) == "const double GoldenRatio = %s;\n2*GoldenRatio" % GoldenRatio.evalf(17) assert ccode( 2*Catalan) == "const double Catalan = %s;\n2*Catalan" % Catalan.evalf(17) assert ccode(2*EulerGamma) == "const double EulerGamma = %s;\n2*EulerGamma" % EulerGamma.evalf(17) def test_ccode_Rational(): assert ccode(Rational(3, 7)) == "3.0/7.0" assert ccode(Rational(3, 7), type_aliases={real: float80}) == "3.0L/7.0L" assert ccode(Rational(18, 9)) == "2" assert ccode(Rational(3, -7)) == "-3.0/7.0" assert ccode(Rational(3, -7), type_aliases={real: float80}) == "-3.0L/7.0L" assert ccode(Rational(-3, -7)) == "3.0/7.0" assert ccode(Rational(-3, -7), type_aliases={real: float80}) == "3.0L/7.0L" assert ccode(x + Rational(3, 7)) == "x + 3.0/7.0" assert ccode(x + Rational(3, 7), type_aliases={real: float80}) == "x + 3.0L/7.0L" assert ccode(Rational(3, 7)*x) == "(3.0/7.0)*x" assert ccode(Rational(3, 7)*x, type_aliases={real: float80}) == "(3.0L/7.0L)*x" def test_ccode_Integer(): assert ccode(Integer(67)) == "67" assert ccode(Integer(-1)) == "-1" def test_ccode_functions(): assert ccode(sin(x) ** cos(x)) == "pow(sin(x), cos(x))" def test_ccode_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert ccode(g(x)) == "2*x" g = implemented_function('g', Lambda(x, 2*x/Catalan)) assert ccode( g(x)) == "const double Catalan = %s;\n2*x/Catalan" % Catalan.evalf(17) A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert ccode(g(A[i]), assign_to=A[i]) == ( "for (int i=0; i y" assert ccode(Ge(x, y)) == "x >= y" def test_ccode_Piecewise(): expr = Piecewise((x, x < 1), (x**2, True)) assert ccode(expr) == ( "((x < 1) ? (\n" " x\n" ")\n" ": (\n" " pow(x, 2)\n" "))") assert ccode(expr, assign_to="c") == ( "if (x < 1) {\n" " c = x;\n" "}\n" "else {\n" " c = pow(x, 2);\n" "}") expr = Piecewise((x, x < 1), (x + 1, x < 2), (x**2, True)) assert ccode(expr) == ( "((x < 1) ? (\n" " x\n" ")\n" ": ((x < 2) ? (\n" " x + 1\n" ")\n" ": (\n" " pow(x, 2)\n" ")))") assert ccode(expr, assign_to='c') == ( "if (x < 1) {\n" " c = x;\n" "}\n" "else if (x < 2) {\n" " c = x + 1;\n" "}\n" "else {\n" " c = pow(x, 2);\n" "}") # Check that Piecewise without a True (default) condition error expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0)) raises(ValueError, lambda: ccode(expr)) def test_ccode_sinc(): from sympy import sinc expr = sinc(x) assert ccode(expr) == ( "((x != 0) ? (\n" " sin(x)/x\n" ")\n" ": (\n" " 1\n" "))") def test_ccode_Piecewise_deep(): p = ccode(2*Piecewise((x, x < 1), (x + 1, x < 2), (x**2, True))) assert p == ( "2*((x < 1) ? (\n" " x\n" ")\n" ": ((x < 2) ? (\n" " x + 1\n" ")\n" ": (\n" " pow(x, 2)\n" ")))") expr = x*y*z + x**2 + y**2 + Piecewise((0, x < 0.5), (1, True)) + cos(z) - 1 assert ccode(expr) == ( "pow(x, 2) + x*y*z + pow(y, 2) + ((x < 0.5) ? (\n" " 0\n" ")\n" ": (\n" " 1\n" ")) + cos(z) - 1") assert ccode(expr, assign_to='c') == ( "c = pow(x, 2) + x*y*z + pow(y, 2) + ((x < 0.5) ? (\n" " 0\n" ")\n" ": (\n" " 1\n" ")) + cos(z) - 1;") def test_ccode_ITE(): expr = ITE(x < 1, y, z) assert ccode(expr) == ( "((x < 1) ? (\n" " y\n" ")\n" ": (\n" " z\n" "))") def test_ccode_settings(): raises(TypeError, lambda: ccode(sin(x), method="garbage")) def test_ccode_Indexed(): from sympy.tensor import IndexedBase, Idx from sympy import symbols s, n, m, o = symbols('s n m o', integer=True) i, j, k = Idx('i', n), Idx('j', m), Idx('k', o) x = IndexedBase('x')[j] A = IndexedBase('A')[i, j] B = IndexedBase('B')[i, j, k] p = C99CodePrinter() assert p._print_Indexed(x) == 'x[j]' assert p._print_Indexed(A) == 'A[%s]' % (m*i+j) assert p._print_Indexed(B) == 'B[%s]' % (i*o*m+j*o+k) A = IndexedBase('A', shape=(5,3))[i, j] assert p._print_Indexed(A) == 'A[%s]' % (3*i + j) A = IndexedBase('A', shape=(5,3), strides='F')[i, j] assert ccode(A) == 'A[%s]' % (i + 5*j) A = IndexedBase('A', shape=(29,29), strides=(1, s), offset=o)[i, j] assert ccode(A) == 'A[o + s*j + i]' Abase = IndexedBase('A', strides=(s, m, n), offset=o) assert ccode(Abase[i, j, k]) == 'A[m*j + n*k + o + s*i]' assert ccode(Abase[2, 3, k]) == 'A[3*m + n*k + o + 2*s]' def test_Element(): assert ccode(Element('x', 'ij')) == 'x[i][j]' assert ccode(Element('x', 'ij', strides='kl', offset='o')) == 'x[i*k + j*l + o]' assert ccode(Element('x', (3,))) == 'x[3]' assert ccode(Element('x', (3,4,5))) == 'x[3][4][5]' def test_ccode_Indexed_without_looking_for_contraction(): len_y = 5 y = IndexedBase('y', shape=(len_y,)) x = IndexedBase('x', shape=(len_y,)) Dy = IndexedBase('Dy', shape=(len_y-1,)) i = Idx('i', len_y-1) e=Eq(Dy[i], (y[i+1]-y[i])/(x[i+1]-x[i])) code0 = ccode(e.rhs, assign_to=e.lhs, contract=False) assert code0 == 'Dy[i] = (y[%s] - y[i])/(x[%s] - x[i]);' % (i + 1, i + 1) def test_ccode_loops_matrix_vector(): n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) s = ( 'for (int i=0; i0), (y, True)), sin(z)]) A = MatrixSymbol('A', 3, 1) assert ccode(mat, A) == ( "A[0] = x*y;\n" "if (y > 0) {\n" " A[1] = x + 2;\n" "}\n" "else {\n" " A[1] = y;\n" "}\n" "A[2] = sin(z);") # Test using MatrixElements in expressions expr = Piecewise((2*A[2, 0], x > 0), (A[2, 0], True)) + sin(A[1, 0]) + A[0, 0] assert ccode(expr) == ( "((x > 0) ? (\n" " 2*A[2]\n" ")\n" ": (\n" " A[2]\n" ")) + sin(A[1]) + A[0]") # Test using MatrixElements in a Matrix q = MatrixSymbol('q', 5, 1) M = MatrixSymbol('M', 3, 3) m = Matrix([[sin(q[1,0]), 0, cos(q[2,0])], [q[1,0] + q[2,0], q[3, 0], 5], [2*q[4, 0]/q[1,0], sqrt(q[0,0]) + 4, 0]]) assert ccode(m, M) == ( "M[0] = sin(q[1]);\n" "M[1] = 0;\n" "M[2] = cos(q[2]);\n" "M[3] = q[1] + q[2];\n" "M[4] = q[3];\n" "M[5] = 5;\n" "M[6] = 2*q[4]/q[1];\n" "M[7] = sqrt(q[0]) + 4;\n" "M[8] = 0;") def test_sparse_matrix(): # gh-15791 assert 'Not supported in C' in ccode(SparseMatrix([[1, 2, 3]])) def test_ccode_reserved_words(): x, y = symbols('x, if') with raises(ValueError): ccode(y**2, error_on_reserved=True, standard='C99') assert ccode(y**2) == 'pow(if_, 2)' assert ccode(x * y**2, dereference=[y]) == 'pow((*if_), 2)*x' assert ccode(y**2, reserved_word_suffix='_unreserved') == 'pow(if_unreserved, 2)' def test_ccode_sign(): expr1, ref1 = sign(x) * y, 'y*(((x) > 0) - ((x) < 0))' expr2, ref2 = sign(cos(x)), '(((cos(x)) > 0) - ((cos(x)) < 0))' expr3, ref3 = sign(2 * x + x**2) * x + x**2, 'pow(x, 2) + x*(((pow(x, 2) + 2*x) > 0) - ((pow(x, 2) + 2*x) < 0))' assert ccode(expr1) == ref1 assert ccode(expr1, 'z') == 'z = %s;' % ref1 assert ccode(expr2) == ref2 assert ccode(expr3) == ref3 def test_ccode_Assignment(): assert ccode(Assignment(x, y + z)) == 'x = y + z;' assert ccode(aug_assign(x, '+', y + z)) == 'x += y + z;' def test_ccode_For(): f = For(x, Range(0, 10, 2), [aug_assign(y, '*', x)]) assert ccode(f) == ("for (x = 0; x < 10; x += 2) {\n" " y *= x;\n" "}") def test_ccode_Max_Min(): assert ccode(Max(x, 0), standard='C89') == '((0 > x) ? 0 : x)' assert ccode(Max(x, 0), standard='C99') == 'fmax(0, x)' assert ccode(Min(x, 0, sqrt(x)), standard='c89') == ( '((0 < ((x < sqrt(x)) ? x : sqrt(x))) ? 0 : ((x < sqrt(x)) ? x : sqrt(x)))' ) def test_ccode_standard(): assert ccode(expm1(x), standard='c99') == 'expm1(x)' assert ccode(nan, standard='c99') == 'NAN' assert ccode(float('nan'), standard='c99') == 'NAN' def test_C89CodePrinter(): c89printer = C89CodePrinter() assert c89printer.language == 'C' assert c89printer.standard == 'C89' assert 'void' in c89printer.reserved_words assert 'template' not in c89printer.reserved_words def test_C99CodePrinter(): assert C99CodePrinter().doprint(expm1(x)) == 'expm1(x)' assert C99CodePrinter().doprint(log1p(x)) == 'log1p(x)' assert C99CodePrinter().doprint(exp2(x)) == 'exp2(x)' assert C99CodePrinter().doprint(log2(x)) == 'log2(x)' assert C99CodePrinter().doprint(fma(x, y, -z)) == 'fma(x, y, -z)' assert C99CodePrinter().doprint(log10(x)) == 'log10(x)' assert C99CodePrinter().doprint(Cbrt(x)) == 'cbrt(x)' # note Cbrt due to cbrt already taken. assert C99CodePrinter().doprint(hypot(x, y)) == 'hypot(x, y)' assert C99CodePrinter().doprint(loggamma(x)) == 'lgamma(x)' assert C99CodePrinter().doprint(Max(x, 3, x**2)) == 'fmax(3, fmax(x, pow(x, 2)))' assert C99CodePrinter().doprint(Min(x, 3)) == 'fmin(3, x)' c99printer = C99CodePrinter() assert c99printer.language == 'C' assert c99printer.standard == 'C99' assert 'restrict' in c99printer.reserved_words assert 'using' not in c99printer.reserved_words @XFAIL def test_C99CodePrinter__precision_f80(): f80_printer = C99CodePrinter(dict(type_aliases={real: float80})) assert f80_printer.doprint(sin(x+Float('2.1'))) == 'sinl(x + 2.1L)' def test_C99CodePrinter__precision(): n = symbols('n', integer=True) f32_printer = C99CodePrinter(dict(type_aliases={real: float32})) f64_printer = C99CodePrinter(dict(type_aliases={real: float64})) f80_printer = C99CodePrinter(dict(type_aliases={real: float80})) assert f32_printer.doprint(sin(x+2.1)) == 'sinf(x + 2.1F)' assert f64_printer.doprint(sin(x+2.1)) == 'sin(x + 2.1000000000000001)' assert f80_printer.doprint(sin(x+Float('2.0'))) == 'sinl(x + 2.0L)' for printer, suffix in zip([f32_printer, f64_printer, f80_printer], ['f', '', 'l']): def check(expr, ref): assert printer.doprint(expr) == ref.format(s=suffix, S=suffix.upper()) check(Abs(n), 'abs(n)') check(Abs(x + 2.0), 'fabs{s}(x + 2.0{S})') check(sin(x + 4.0)**cos(x - 2.0), 'pow{s}(sin{s}(x + 4.0{S}), cos{s}(x - 2.0{S}))') check(exp(x*8.0), 'exp{s}(8.0{S}*x)') check(exp2(x), 'exp2{s}(x)') check(expm1(x*4.0), 'expm1{s}(4.0{S}*x)') check(Mod(n, 2), '((n) % (2))') check(Mod(2*n + 3, 3*n + 5), '((2*n + 3) % (3*n + 5))') check(Mod(x + 2.0, 3.0), 'fmod{s}(1.0{S}*x + 2.0{S}, 3.0{S})') check(Mod(x, 2.0*x + 3.0), 'fmod{s}(1.0{S}*x, 2.0{S}*x + 3.0{S})') check(log(x/2), 'log{s}((1.0{S}/2.0{S})*x)') check(log10(3*x/2), 'log10{s}((3.0{S}/2.0{S})*x)') check(log2(x*8.0), 'log2{s}(8.0{S}*x)') check(log1p(x), 'log1p{s}(x)') check(2**x, 'pow{s}(2, x)') check(2.0**x, 'pow{s}(2.0{S}, x)') check(x**3, 'pow{s}(x, 3)') check(x**4.0, 'pow{s}(x, 4.0{S})') check(sqrt(3+x), 'sqrt{s}(x + 3)') check(Cbrt(x-2.0), 'cbrt{s}(x - 2.0{S})') check(hypot(x, y), 'hypot{s}(x, y)') check(sin(3.*x + 2.), 'sin{s}(3.0{S}*x + 2.0{S})') check(cos(3.*x - 1.), 'cos{s}(3.0{S}*x - 1.0{S})') check(tan(4.*y + 2.), 'tan{s}(4.0{S}*y + 2.0{S})') check(asin(3.*x + 2.), 'asin{s}(3.0{S}*x + 2.0{S})') check(acos(3.*x + 2.), 'acos{s}(3.0{S}*x + 2.0{S})') check(atan(3.*x + 2.), 'atan{s}(3.0{S}*x + 2.0{S})') check(atan2(3.*x, 2.*y), 'atan2{s}(3.0{S}*x, 2.0{S}*y)') check(sinh(3.*x + 2.), 'sinh{s}(3.0{S}*x + 2.0{S})') check(cosh(3.*x - 1.), 'cosh{s}(3.0{S}*x - 1.0{S})') check(tanh(4.0*y + 2.), 'tanh{s}(4.0{S}*y + 2.0{S})') check(asinh(3.*x + 2.), 'asinh{s}(3.0{S}*x + 2.0{S})') check(acosh(3.*x + 2.), 'acosh{s}(3.0{S}*x + 2.0{S})') check(atanh(3.*x + 2.), 'atanh{s}(3.0{S}*x + 2.0{S})') check(erf(42.*x), 'erf{s}(42.0{S}*x)') check(erfc(42.*x), 'erfc{s}(42.0{S}*x)') check(gamma(x), 'tgamma{s}(x)') check(loggamma(x), 'lgamma{s}(x)') check(ceiling(x + 2.), "ceil{s}(x + 2.0{S})") check(floor(x + 2.), "floor{s}(x + 2.0{S})") check(fma(x, y, -z), 'fma{s}(x, y, -z)') check(Max(x, 8.0, x**4.0), 'fmax{s}(8.0{S}, fmax{s}(x, pow{s}(x, 4.0{S})))') check(Min(x, 2.0), 'fmin{s}(2.0{S}, x)') def test_get_math_macros(): macros = get_math_macros() assert macros[exp(1)] == 'M_E' assert macros[1/Sqrt(2)] == 'M_SQRT1_2' def test_ccode_Declaration(): i = symbols('i', integer=True) var1 = Variable(i, type=Type.from_expr(i)) dcl1 = Declaration(var1) assert ccode(dcl1) == 'int i' var2 = Variable(x, type=float32, attrs={value_const}) dcl2a = Declaration(var2) assert ccode(dcl2a) == 'const float x' dcl2b = var2.as_Declaration(value=pi) assert ccode(dcl2b) == 'const float x = M_PI' var3 = Variable(y, type=Type('bool')) dcl3 = Declaration(var3) printer = C89CodePrinter() assert 'stdbool.h' not in printer.headers assert printer.doprint(dcl3) == 'bool y' assert 'stdbool.h' in printer.headers u = symbols('u', real=True) ptr4 = Pointer.deduced(u, attrs={pointer_const, restrict}) dcl4 = Declaration(ptr4) assert ccode(dcl4) == 'double * const restrict u' var5 = Variable(x, Type('__float128'), attrs={value_const}) dcl5a = Declaration(var5) assert ccode(dcl5a) == 'const __float128 x' var5b = Variable(var5.symbol, var5.type, pi, attrs=var5.attrs) dcl5b = Declaration(var5b) assert ccode(dcl5b) == 'const __float128 x = M_PI' def test_C99CodePrinter_custom_type(): # We will look at __float128 (new in glibc 2.26) f128 = FloatType('_Float128', float128.nbits, float128.nmant, float128.nexp) p128 = C99CodePrinter(dict( type_aliases={real: f128}, type_literal_suffixes={f128: 'Q'}, type_func_suffixes={f128: 'f128'}, type_math_macro_suffixes={ real: 'f128', f128: 'f128' }, type_macros={ f128: ('__STDC_WANT_IEC_60559_TYPES_EXT__',) } )) assert p128.doprint(x) == 'x' assert not p128.headers assert not p128.libraries assert not p128.macros assert p128.doprint(2.0) == '2.0Q' assert not p128.headers assert not p128.libraries assert p128.macros == {'__STDC_WANT_IEC_60559_TYPES_EXT__'} assert p128.doprint(Rational(1, 2)) == '1.0Q/2.0Q' assert p128.doprint(sin(x)) == 'sinf128(x)' assert p128.doprint(cos(2., evaluate=False)) == 'cosf128(2.0Q)' assert p128.doprint(x**-1.0) == '1.0Q/x' var5 = Variable(x, f128, attrs={value_const}) dcl5a = Declaration(var5) assert ccode(dcl5a) == 'const _Float128 x' var5b = Variable(x, f128, pi, attrs={value_const}) dcl5b = Declaration(var5b) assert p128.doprint(dcl5b) == 'const _Float128 x = M_PIf128' var5b = Variable(x, f128, value=Catalan.evalf(38), attrs={value_const}) dcl5c = Declaration(var5b) assert p128.doprint(dcl5c) == 'const _Float128 x = %sQ' % Catalan.evalf(f128.decimal_dig) def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert(ccode(A[0, 0]) == "A[0]") assert(ccode(3 * A[0, 0]) == "3*A[0]") F = C[0, 0].subs(C, A - B) assert(ccode(F) == "(A - B)[0]") def test_ccode_math_macros(): assert ccode(z + exp(1)) == 'z + M_E' assert ccode(z + log2(exp(1))) == 'z + M_LOG2E' assert ccode(z + 1/log(2)) == 'z + M_LOG2E' assert ccode(z + log(2)) == 'z + M_LN2' assert ccode(z + log(10)) == 'z + M_LN10' assert ccode(z + pi) == 'z + M_PI' assert ccode(z + pi/2) == 'z + M_PI_2' assert ccode(z + pi/4) == 'z + M_PI_4' assert ccode(z + 1/pi) == 'z + M_1_PI' assert ccode(z + 2/pi) == 'z + M_2_PI' assert ccode(z + 2/sqrt(pi)) == 'z + M_2_SQRTPI' assert ccode(z + 2/Sqrt(pi)) == 'z + M_2_SQRTPI' assert ccode(z + sqrt(2)) == 'z + M_SQRT2' assert ccode(z + Sqrt(2)) == 'z + M_SQRT2' assert ccode(z + 1/sqrt(2)) == 'z + M_SQRT1_2' assert ccode(z + 1/Sqrt(2)) == 'z + M_SQRT1_2' def test_ccode_Type(): assert ccode(Type('float')) == 'float' assert ccode(intc) == 'int' def test_ccode_codegen_ast(): assert ccode(Comment("this is a comment")) == "// this is a comment" assert ccode(While(abs(x) > 1, [aug_assign(x, '-', 1)])) == ( 'while (fabs(x) > 1) {\n' ' x -= 1;\n' '}' ) assert ccode(Scope([AddAugmentedAssignment(x, 1)])) == ( '{\n' ' x += 1;\n' '}' ) inp_x = Declaration(Variable(x, type=real)) assert ccode(FunctionPrototype(real, 'pwer', [inp_x])) == 'double pwer(double x)' assert ccode(FunctionDefinition(real, 'pwer', [inp_x], [Assignment(x, x**2)])) == ( 'double pwer(double x){\n' ' x = pow(x, 2);\n' '}' ) # Elements of CodeBlock are formatted as statements: block = CodeBlock( x, Print([x, y], "%d %d"), FunctionCall('pwer', [x]), Return(x), ) assert ccode(block) == '\n'.join([ 'x;', 'printf("%d %d", x, y);', 'pwer(x);', 'return x;', ]) def test_ccode_submodule(): # Test the compatibility sympy.printing.ccode module imports with warns_deprecated_sympy(): import sympy.printing.ccode # noqa:F401 sympy-sympy-1.9/sympy/printing/tests/test_codeprinter.py000066400000000000000000000026021412543434000240270ustar00rootroot00000000000000from sympy.printing.codeprinter import CodePrinter from sympy.core import symbols from sympy.core.symbol import Dummy from sympy.testing.pytest import raises def setup_test_printer(**kwargs): p = CodePrinter(settings=kwargs) p._not_supported = set() p._number_symbols = set() return p def test_print_Dummy(): d = Dummy('d') p = setup_test_printer() assert p._print_Dummy(d) == "d_%i" % d.dummy_index def test_print_Symbol(): x, y = symbols('x, if') p = setup_test_printer() assert p._print(x) == 'x' assert p._print(y) == 'if' p.reserved_words.update(['if']) assert p._print(y) == 'if_' p = setup_test_printer(error_on_reserved=True) p.reserved_words.update(['if']) with raises(ValueError): p._print(y) p = setup_test_printer(reserved_word_suffix='_He_Man') p.reserved_words.update(['if']) assert p._print(y) == 'if_He_Man' def test_issue_15791(): class CrashingCodePrinter(CodePrinter): def emptyPrinter(self, obj): raise NotImplementedError from sympy.matrices import ( MutableSparseMatrix, ImmutableSparseMatrix, ) c = CrashingCodePrinter() # these should not silently succeed with raises(NotImplementedError): c.doprint(ImmutableSparseMatrix(2, 2, {})) with raises(NotImplementedError): c.doprint(MutableSparseMatrix(2, 2, {})) sympy-sympy-1.9/sympy/printing/tests/test_conventions.py000066400000000000000000000116631412543434000240650ustar00rootroot00000000000000# -*- coding: utf-8 -*- from sympy import symbols, Derivative, Integral, exp, cos, oo, Function from sympy.functions.special.bessel import besselj from sympy.functions.special.polynomials import legendre from sympy.functions.combinatorial.numbers import bell from sympy.printing.conventions import split_super_sub, requires_partial from sympy.testing.pytest import XFAIL def test_super_sub(): assert split_super_sub("beta_13_2") == ("beta", [], ["13", "2"]) assert split_super_sub("beta_132_20") == ("beta", [], ["132", "20"]) assert split_super_sub("beta_13") == ("beta", [], ["13"]) assert split_super_sub("x_a_b") == ("x", [], ["a", "b"]) assert split_super_sub("x_1_2_3") == ("x", [], ["1", "2", "3"]) assert split_super_sub("x_a_b1") == ("x", [], ["a", "b1"]) assert split_super_sub("x_a_1") == ("x", [], ["a", "1"]) assert split_super_sub("x_1_a") == ("x", [], ["1", "a"]) assert split_super_sub("x_1^aa") == ("x", ["aa"], ["1"]) assert split_super_sub("x_1__aa") == ("x", ["aa"], ["1"]) assert split_super_sub("x_11^a") == ("x", ["a"], ["11"]) assert split_super_sub("x_11__a") == ("x", ["a"], ["11"]) assert split_super_sub("x_a_b_c_d") == ("x", [], ["a", "b", "c", "d"]) assert split_super_sub("x_a_b^c^d") == ("x", ["c", "d"], ["a", "b"]) assert split_super_sub("x_a_b__c__d") == ("x", ["c", "d"], ["a", "b"]) assert split_super_sub("x_a^b_c^d") == ("x", ["b", "d"], ["a", "c"]) assert split_super_sub("x_a__b_c__d") == ("x", ["b", "d"], ["a", "c"]) assert split_super_sub("x^a^b_c_d") == ("x", ["a", "b"], ["c", "d"]) assert split_super_sub("x__a__b_c_d") == ("x", ["a", "b"], ["c", "d"]) assert split_super_sub("x^a^b^c^d") == ("x", ["a", "b", "c", "d"], []) assert split_super_sub("x__a__b__c__d") == ("x", ["a", "b", "c", "d"], []) assert split_super_sub("alpha_11") == ("alpha", [], ["11"]) assert split_super_sub("alpha_11_11") == ("alpha", [], ["11", "11"]) assert split_super_sub("w1") == ("w", [], ["1"]) assert split_super_sub("w𝟙") == ("w", [], ["𝟙"]) assert split_super_sub("w11") == ("w", [], ["11"]) assert split_super_sub("w𝟙𝟙") == ("w", [], ["𝟙𝟙"]) assert split_super_sub("w𝟙2𝟙") == ("w", [], ["𝟙2𝟙"]) assert split_super_sub("w1^a") == ("w", ["a"], ["1"]) assert split_super_sub("ω1") == ("ω", [], ["1"]) assert split_super_sub("ω11") == ("ω", [], ["11"]) assert split_super_sub("ω1^a") == ("ω", ["a"], ["1"]) assert split_super_sub("ω𝟙^α") == ("ω", ["α"], ["𝟙"]) assert split_super_sub("ω𝟙2^3α") == ("ω", ["3α"], ["𝟙2"]) assert split_super_sub("") == ("", [], []) def test_requires_partial(): x, y, z, t, nu = symbols('x y z t nu') n = symbols('n', integer=True) f = x * y assert requires_partial(Derivative(f, x)) is True assert requires_partial(Derivative(f, y)) is True ## integrating out one of the variables assert requires_partial(Derivative(Integral(exp(-x * y), (x, 0, oo)), y, evaluate=False)) is False ## bessel function with smooth parameter f = besselj(nu, x) assert requires_partial(Derivative(f, x)) is True assert requires_partial(Derivative(f, nu)) is True ## bessel function with integer parameter f = besselj(n, x) assert requires_partial(Derivative(f, x)) is False # this is not really valid (differentiating with respect to an integer) # but there's no reason to use the partial derivative symbol there. make # sure we don't throw an exception here, though assert requires_partial(Derivative(f, n)) is False ## bell polynomial f = bell(n, x) assert requires_partial(Derivative(f, x)) is False # again, invalid assert requires_partial(Derivative(f, n)) is False ## legendre polynomial f = legendre(0, x) assert requires_partial(Derivative(f, x)) is False f = legendre(n, x) assert requires_partial(Derivative(f, x)) is False # again, invalid assert requires_partial(Derivative(f, n)) is False f = x ** n assert requires_partial(Derivative(f, x)) is False assert requires_partial(Derivative(Integral((x*y) ** n * exp(-x * y), (x, 0, oo)), y, evaluate=False)) is False # parametric equation f = (exp(t), cos(t)) g = sum(f) assert requires_partial(Derivative(g, t)) is False f = symbols('f', cls=Function) assert requires_partial(Derivative(f(x), x)) is False assert requires_partial(Derivative(f(x), y)) is False assert requires_partial(Derivative(f(x, y), x)) is True assert requires_partial(Derivative(f(x, y), y)) is True assert requires_partial(Derivative(f(x, y), z)) is True assert requires_partial(Derivative(f(x, y), x, y)) is True @XFAIL def test_requires_partial_unspecified_variables(): x, y = symbols('x y') # function of unspecified variables f = symbols('f', cls=Function) assert requires_partial(Derivative(f, x)) is False assert requires_partial(Derivative(f, x, y)) is True sympy-sympy-1.9/sympy/printing/tests/test_cupy.py000066400000000000000000000032441412543434000224740ustar00rootroot00000000000000from sympy import lambdify, Sum, sqrt, log from sympy.abc import x, i, a, b from sympy.codegen.numpy_nodes import logaddexp from sympy.printing.numpy import CuPyPrinter, _cupy_known_constants, _cupy_known_functions from sympy.testing.pytest import skip from sympy.external import import_module cp = import_module('cupy') def test_cupy_print(): prntr = CuPyPrinter() assert prntr.doprint(logaddexp(a, b)) == 'cupy.logaddexp(a, b)' assert prntr.doprint(sqrt(x)) == 'cupy.sqrt(x)' assert prntr.doprint(log(x)) == 'cupy.log(x)' assert prntr.doprint("acos(x)") == 'cupy.arccos(x)' assert prntr.doprint("exp(x)") == 'cupy.exp(x)' assert prntr.doprint("Abs(x)") == 'abs(x)' def test_not_cupy_print(): prntr = CuPyPrinter() assert "Not supported" in prntr.doprint("abcd(x)") def test_cupy_sum(): if not cp: skip("CuPy not installed") s = Sum(x ** i, (i, a, b)) f = lambdify((a, b, x), s, 'cupy') a_, b_ = 0, 10 x_ = cp.linspace(-1, +1, 10) assert cp.allclose(f(a_, b_, x_), sum(x_ ** i_ for i_ in range(a_, b_ + 1))) s = Sum(i * x, (i, a, b)) f = lambdify((a, b, x), s, 'numpy') a_, b_ = 0, 10 x_ = cp.linspace(-1, +1, 10) assert cp.allclose(f(a_, b_, x_), sum(i_ * x_ for i_ in range(a_, b_ + 1))) def test_cupy_known_funcs_consts(): assert _cupy_known_constants['NaN'] == 'cupy.nan' assert _cupy_known_constants['EulerGamma'] == 'cupy.euler_gamma' assert _cupy_known_functions['acos'] == 'cupy.arccos' assert _cupy_known_functions['log'] == 'cupy.log' def test_cupy_print_methods(): prntr = CuPyPrinter() assert hasattr(prntr, '_print_acos') assert hasattr(prntr, '_print_log') sympy-sympy-1.9/sympy/printing/tests/test_cxx.py000066400000000000000000000046251412543434000223220ustar00rootroot00000000000000from sympy import symbols from sympy.functions import beta, Ei, zeta, Max, Min, sqrt from sympy.printing.cxx import CXX98CodePrinter, CXX11CodePrinter, CXX17CodePrinter, cxxcode from sympy.codegen.cfunctions import log1p from sympy.testing.pytest import warns_deprecated_sympy x, y, u, v = symbols('x y u v') def test_CXX98CodePrinter(): assert CXX98CodePrinter().doprint(Max(x, 3)) in ('std::max(x, 3)', 'std::max(3, x)') assert CXX98CodePrinter().doprint(Min(x, 3, sqrt(x))) == 'std::min(3, std::min(x, std::sqrt(x)))' cxx98printer = CXX98CodePrinter() assert cxx98printer.language == 'C++' assert cxx98printer.standard == 'C++98' assert 'template' in cxx98printer.reserved_words assert 'alignas' not in cxx98printer.reserved_words def test_CXX11CodePrinter(): assert CXX11CodePrinter().doprint(log1p(x)) == 'std::log1p(x)' cxx11printer = CXX11CodePrinter() assert cxx11printer.language == 'C++' assert cxx11printer.standard == 'C++11' assert 'operator' in cxx11printer.reserved_words assert 'noexcept' in cxx11printer.reserved_words assert 'concept' not in cxx11printer.reserved_words def test_subclass_print_method(): class MyPrinter(CXX11CodePrinter): def _print_log1p(self, expr): return 'my_library::log1p(%s)' % ', '.join(map(self._print, expr.args)) assert MyPrinter().doprint(log1p(x)) == 'my_library::log1p(x)' def test_subclass_print_method__ns(): class MyPrinter(CXX11CodePrinter): _ns = 'my_library::' p = CXX11CodePrinter() myp = MyPrinter() assert p.doprint(log1p(x)) == 'std::log1p(x)' assert myp.doprint(log1p(x)) == 'my_library::log1p(x)' def test_CXX17CodePrinter(): assert CXX17CodePrinter().doprint(beta(x, y)) == 'std::beta(x, y)' assert CXX17CodePrinter().doprint(Ei(x)) == 'std::expint(x)' assert CXX17CodePrinter().doprint(zeta(x)) == 'std::riemann_zeta(x)' def test_cxxcode(): assert sorted(cxxcode(sqrt(x)*.5).split('*')) == sorted(['0.5', 'std::sqrt(x)']) def test_cxxcode_submodule(): # Test the compatibility sympy.printing.cxxcode module imports with warns_deprecated_sympy(): import sympy.printing.cxxcode # noqa:F401 def test_cxxcode_nested_minmax(): assert cxxcode(Max(Min(x, y), Min(u, v))) \ == 'std::max(std::min(u, v), std::min(x, y))' assert cxxcode(Min(Max(x, y), Max(u, v))) \ == 'std::min(std::max(u, v), std::max(x, y))' sympy-sympy-1.9/sympy/printing/tests/test_dot.py000066400000000000000000000104211412543434000222750ustar00rootroot00000000000000from sympy.printing.dot import (purestr, styleof, attrprint, dotnode, dotedges, dotprint) from sympy import Symbol, Integer, Basic, Expr, srepr, Float, symbols from sympy.abc import x def test_purestr(): assert purestr(Symbol('x')) == "Symbol('x')" assert purestr(Basic(1, 2)) == "Basic(1, 2)" assert purestr(Float(2)) == "Float('2.0', precision=53)" assert purestr(Symbol('x'), with_args=True) == ("Symbol('x')", ()) assert purestr(Basic(1, 2), with_args=True) == ('Basic(1, 2)', ('1', '2')) assert purestr(Float(2), with_args=True) == \ ("Float('2.0', precision=53)", ()) def test_styleof(): styles = [(Basic, {'color': 'blue', 'shape': 'ellipse'}), (Expr, {'color': 'black'})] assert styleof(Basic(1), styles) == {'color': 'blue', 'shape': 'ellipse'} assert styleof(x + 1, styles) == {'color': 'black', 'shape': 'ellipse'} def test_attrprint(): assert attrprint({'color': 'blue', 'shape': 'ellipse'}) == \ '"color"="blue", "shape"="ellipse"' def test_dotnode(): assert dotnode(x, repeat=False) == \ '"Symbol(\'x\')" ["color"="black", "label"="x", "shape"="ellipse"];' assert dotnode(x+2, repeat=False) == \ '"Add(Integer(2), Symbol(\'x\'))" ' \ '["color"="black", "label"="Add", "shape"="ellipse"];', \ dotnode(x+2,repeat=0) assert dotnode(x + x**2, repeat=False) == \ '"Add(Symbol(\'x\'), Pow(Symbol(\'x\'), Integer(2)))" ' \ '["color"="black", "label"="Add", "shape"="ellipse"];' assert dotnode(x + x**2, repeat=True) == \ '"Add(Symbol(\'x\'), Pow(Symbol(\'x\'), Integer(2)))_()" ' \ '["color"="black", "label"="Add", "shape"="ellipse"];' def test_dotedges(): assert sorted(dotedges(x+2, repeat=False)) == [ '"Add(Integer(2), Symbol(\'x\'))" -> "Integer(2)";', '"Add(Integer(2), Symbol(\'x\'))" -> "Symbol(\'x\')";' ] assert sorted(dotedges(x + 2, repeat=True)) == [ '"Add(Integer(2), Symbol(\'x\'))_()" -> "Integer(2)_(0,)";', '"Add(Integer(2), Symbol(\'x\'))_()" -> "Symbol(\'x\')_(1,)";' ] def test_dotprint(): text = dotprint(x+2, repeat=False) assert all(e in text for e in dotedges(x+2, repeat=False)) assert all( n in text for n in [dotnode(expr, repeat=False) for expr in (x, Integer(2), x+2)]) assert 'digraph' in text text = dotprint(x+x**2, repeat=False) assert all(e in text for e in dotedges(x+x**2, repeat=False)) assert all( n in text for n in [dotnode(expr, repeat=False) for expr in (x, Integer(2), x**2)]) assert 'digraph' in text text = dotprint(x+x**2, repeat=True) assert all(e in text for e in dotedges(x+x**2, repeat=True)) assert all( n in text for n in [dotnode(expr, pos=()) for expr in [x + x**2]]) text = dotprint(x**x, repeat=True) assert all(e in text for e in dotedges(x**x, repeat=True)) assert all( n in text for n in [dotnode(x, pos=(0,)), dotnode(x, pos=(1,))]) assert 'digraph' in text def test_dotprint_depth(): text = dotprint(3*x+2, depth=1) assert dotnode(3*x+2) in text assert dotnode(x) not in text text = dotprint(3*x+2) assert "depth" not in text def test_Matrix_and_non_basics(): from sympy import MatrixSymbol n = Symbol('n') assert dotprint(MatrixSymbol('X', n, n)) == \ """digraph{ # Graph style "ordering"="out" "rankdir"="TD" ######### # Nodes # ######### "MatrixSymbol(Str('X'), Symbol('n'), Symbol('n'))_()" ["color"="black", "label"="MatrixSymbol", "shape"="ellipse"]; "Str('X')_(0,)" ["color"="blue", "label"="X", "shape"="ellipse"]; "Symbol('n')_(1,)" ["color"="black", "label"="n", "shape"="ellipse"]; "Symbol('n')_(2,)" ["color"="black", "label"="n", "shape"="ellipse"]; ######### # Edges # ######### "MatrixSymbol(Str('X'), Symbol('n'), Symbol('n'))_()" -> "Str('X')_(0,)"; "MatrixSymbol(Str('X'), Symbol('n'), Symbol('n'))_()" -> "Symbol('n')_(1,)"; "MatrixSymbol(Str('X'), Symbol('n'), Symbol('n'))_()" -> "Symbol('n')_(2,)"; }""" def test_labelfunc(): text = dotprint(x + 2, labelfunc=srepr) assert "Symbol('x')" in text assert "Integer(2)" in text def test_commutative(): x, y = symbols('x y', commutative=False) assert dotprint(x + y) == dotprint(y + x) assert dotprint(x*y) != dotprint(y*x) sympy-sympy-1.9/sympy/printing/tests/test_fortran.py000066400000000000000000001020761412543434000231720ustar00rootroot00000000000000from sympy import (sin, cos, atan2, log, exp, gamma, conjugate, sqrt, factorial, Integral, Piecewise, Add, diff, symbols, S, Float, Dummy, Eq, Range, Catalan, EulerGamma, E, GoldenRatio, I, pi, Function, Rational, Integer, Lambda, sign, Mod) from sympy.codegen import For, Assignment, aug_assign from sympy.codegen.ast import Declaration, Variable, float32, float64, \ value_const, real, bool_, While, FunctionPrototype, FunctionDefinition, \ integer, Return from sympy.core.relational import Relational from sympy.logic.boolalg import And, Or, Not, Equivalent, Xor from sympy.matrices import Matrix, MatrixSymbol from sympy.printing.fortran import fcode, FCodePrinter from sympy.tensor import IndexedBase, Idx from sympy.utilities.lambdify import implemented_function from sympy.testing.pytest import raises, warns_deprecated_sympy def test_printmethod(): x = symbols('x') class nint(Function): def _fcode(self, printer): return "nint(%s)" % printer._print(self.args[0]) assert fcode(nint(x)) == " nint(x)" def test_fcode_sign(): #issue 12267 x=symbols('x') y=symbols('y', integer=True) z=symbols('z', complex=True) assert fcode(sign(x), standard=95, source_format='free') == "merge(0d0, dsign(1d0, x), x == 0d0)" assert fcode(sign(y), standard=95, source_format='free') == "merge(0, isign(1, y), y == 0)" assert fcode(sign(z), standard=95, source_format='free') == "merge(cmplx(0d0, 0d0), z/abs(z), abs(z) == 0d0)" raises(NotImplementedError, lambda: fcode(sign(x))) def test_fcode_Pow(): x, y = symbols('x,y') n = symbols('n', integer=True) assert fcode(x**3) == " x**3" assert fcode(x**(y**3)) == " x**(y**3)" assert fcode(1/(sin(x)*3.5)**(x - y**x)/(x**2 + y)) == \ " (3.5d0*sin(x))**(-x + y**x)/(x**2 + y)" assert fcode(sqrt(x)) == ' sqrt(x)' assert fcode(sqrt(n)) == ' sqrt(dble(n))' assert fcode(x**0.5) == ' sqrt(x)' assert fcode(sqrt(x)) == ' sqrt(x)' assert fcode(sqrt(10)) == ' sqrt(10.0d0)' assert fcode(x**-1.0) == ' 1d0/x' assert fcode(x**-2.0, 'y', source_format='free') == 'y = x**(-2.0d0)' # 2823 assert fcode(x**Rational(3, 7)) == ' x**(3.0d0/7.0d0)' def test_fcode_Rational(): x = symbols('x') assert fcode(Rational(3, 7)) == " 3.0d0/7.0d0" assert fcode(Rational(18, 9)) == " 2" assert fcode(Rational(3, -7)) == " -3.0d0/7.0d0" assert fcode(Rational(-3, -7)) == " 3.0d0/7.0d0" assert fcode(x + Rational(3, 7)) == " x + 3.0d0/7.0d0" assert fcode(Rational(3, 7)*x) == " (3.0d0/7.0d0)*x" def test_fcode_Integer(): assert fcode(Integer(67)) == " 67" assert fcode(Integer(-1)) == " -1" def test_fcode_Float(): assert fcode(Float(42.0)) == " 42.0000000000000d0" assert fcode(Float(-1e20)) == " -1.00000000000000d+20" def test_fcode_functions(): x, y = symbols('x,y') assert fcode(sin(x) ** cos(y)) == " sin(x)**cos(y)" raises(NotImplementedError, lambda: fcode(Mod(x, y), standard=66)) raises(NotImplementedError, lambda: fcode(x % y, standard=66)) raises(NotImplementedError, lambda: fcode(Mod(x, y), standard=77)) raises(NotImplementedError, lambda: fcode(x % y, standard=77)) for standard in [90, 95, 2003, 2008]: assert fcode(Mod(x, y), standard=standard) == " modulo(x, y)" assert fcode(x % y, standard=standard) == " modulo(x, y)" def test_case(): ob = FCodePrinter() x,x_,x__,y,X,X_,Y = symbols('x,x_,x__,y,X,X_,Y') assert fcode(exp(x_) + sin(x*y) + cos(X*Y)) == \ ' exp(x_) + sin(x*y) + cos(X__*Y_)' assert fcode(exp(x__) + 2*x*Y*X_**Rational(7, 2)) == \ ' 2*X_**(7.0d0/2.0d0)*Y*x + exp(x__)' assert fcode(exp(x_) + sin(x*y) + cos(X*Y), name_mangling=False) == \ ' exp(x_) + sin(x*y) + cos(X*Y)' assert fcode(x - cos(X), name_mangling=False) == ' x - cos(X)' assert ob.doprint(X*sin(x) + x_, assign_to='me') == ' me = X*sin(x_) + x__' assert ob.doprint(X*sin(x), assign_to='mu') == ' mu = X*sin(x_)' assert ob.doprint(x_, assign_to='ad') == ' ad = x__' n, m = symbols('n,m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) I = Idx('I', n) assert fcode(A[i, I]*x[I], assign_to=y[i], source_format='free') == ( "do i = 1, m\n" " y(i) = 0\n" "end do\n" "do i = 1, m\n" " do I_ = 1, n\n" " y(i) = A(i, I_)*x(I_) + y(i)\n" " end do\n" "end do" ) #issue 6814 def test_fcode_functions_with_integers(): x= symbols('x') log10_17 = log(10).evalf(17) loglog10_17 = '0.8340324452479558d0' assert fcode(x * log(10)) == " x*%sd0" % log10_17 assert fcode(x * log(10)) == " x*%sd0" % log10_17 assert fcode(x * log(S(10))) == " x*%sd0" % log10_17 assert fcode(log(S(10))) == " %sd0" % log10_17 assert fcode(exp(10)) == " %sd0" % exp(10).evalf(17) assert fcode(x * log(log(10))) == " x*%s" % loglog10_17 assert fcode(x * log(log(S(10)))) == " x*%s" % loglog10_17 def test_fcode_NumberSymbol(): prec = 17 p = FCodePrinter() assert fcode(Catalan) == ' parameter (Catalan = %sd0)\n Catalan' % Catalan.evalf(prec) assert fcode(EulerGamma) == ' parameter (EulerGamma = %sd0)\n EulerGamma' % EulerGamma.evalf(prec) assert fcode(E) == ' parameter (E = %sd0)\n E' % E.evalf(prec) assert fcode(GoldenRatio) == ' parameter (GoldenRatio = %sd0)\n GoldenRatio' % GoldenRatio.evalf(prec) assert fcode(pi) == ' parameter (pi = %sd0)\n pi' % pi.evalf(prec) assert fcode( pi, precision=5) == ' parameter (pi = %sd0)\n pi' % pi.evalf(5) assert fcode(Catalan, human=False) == ({ (Catalan, p._print(Catalan.evalf(prec)))}, set(), ' Catalan') assert fcode(EulerGamma, human=False) == ({(EulerGamma, p._print( EulerGamma.evalf(prec)))}, set(), ' EulerGamma') assert fcode(E, human=False) == ( {(E, p._print(E.evalf(prec)))}, set(), ' E') assert fcode(GoldenRatio, human=False) == ({(GoldenRatio, p._print( GoldenRatio.evalf(prec)))}, set(), ' GoldenRatio') assert fcode(pi, human=False) == ( {(pi, p._print(pi.evalf(prec)))}, set(), ' pi') assert fcode(pi, precision=5, human=False) == ( {(pi, p._print(pi.evalf(5)))}, set(), ' pi') def test_fcode_complex(): assert fcode(I) == " cmplx(0,1)" x = symbols('x') assert fcode(4*I) == " cmplx(0,4)" assert fcode(3 + 4*I) == " cmplx(3,4)" assert fcode(3 + 4*I + x) == " cmplx(3,4) + x" assert fcode(I*x) == " cmplx(0,1)*x" assert fcode(3 + 4*I - x) == " cmplx(3,4) - x" x = symbols('x', imaginary=True) assert fcode(5*x) == " 5*x" assert fcode(I*x) == " cmplx(0,1)*x" assert fcode(3 + x) == " x + 3" def test_implicit(): x, y = symbols('x,y') assert fcode(sin(x)) == " sin(x)" assert fcode(atan2(x, y)) == " atan2(x, y)" assert fcode(conjugate(x)) == " conjg(x)" def test_not_fortran(): x = symbols('x') g = Function('g') gamma_f = fcode(gamma(x)) assert gamma_f == "C Not supported in Fortran:\nC gamma\n gamma(x)" assert fcode(Integral(sin(x))) == "C Not supported in Fortran:\nC Integral\n Integral(sin(x), x)" assert fcode(g(x)) == "C Not supported in Fortran:\nC g\n g(x)" def test_user_functions(): x = symbols('x') assert fcode(sin(x), user_functions={"sin": "zsin"}) == " zsin(x)" x = symbols('x') assert fcode( gamma(x), user_functions={"gamma": "mygamma"}) == " mygamma(x)" g = Function('g') assert fcode(g(x), user_functions={"g": "great"}) == " great(x)" n = symbols('n', integer=True) assert fcode( factorial(n), user_functions={"factorial": "fct"}) == " fct(n)" def test_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert fcode(g(x)) == " 2*x" g = implemented_function('g', Lambda(x, 2*pi/x)) assert fcode(g(x)) == ( " parameter (pi = %sd0)\n" " 2*pi/x" ) % pi.evalf(17) A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert fcode(g(A[i]), assign_to=A[i]) == ( " do i = 1, n\n" " A(i) = (A(i) + 1)*(A(i) + 2)*A(i)\n" " end do" ) def test_assign_to(): x = symbols('x') assert fcode(sin(x), assign_to="s") == " s = sin(x)" def test_line_wrapping(): x, y = symbols('x,y') assert fcode(((x + y)**10).expand(), assign_to="var") == ( " var = x**10 + 10*x**9*y + 45*x**8*y**2 + 120*x**7*y**3 + 210*x**6*\n" " @ y**4 + 252*x**5*y**5 + 210*x**4*y**6 + 120*x**3*y**7 + 45*x**2*y\n" " @ **8 + 10*x*y**9 + y**10" ) e = [x**i for i in range(11)] assert fcode(Add(*e)) == ( " x**10 + x**9 + x**8 + x**7 + x**6 + x**5 + x**4 + x**3 + x**2 + x\n" " @ + 1" ) def test_fcode_precedence(): x, y = symbols("x y") assert fcode(And(x < y, y < x + 1), source_format="free") == \ "x < y .and. y < x + 1" assert fcode(Or(x < y, y < x + 1), source_format="free") == \ "x < y .or. y < x + 1" assert fcode(Xor(x < y, y < x + 1, evaluate=False), source_format="free") == "x < y .neqv. y < x + 1" assert fcode(Equivalent(x < y, y < x + 1), source_format="free") == \ "x < y .eqv. y < x + 1" def test_fcode_Logical(): x, y, z = symbols("x y z") # unary Not assert fcode(Not(x), source_format="free") == ".not. x" # binary And assert fcode(And(x, y), source_format="free") == "x .and. y" assert fcode(And(x, Not(y)), source_format="free") == "x .and. .not. y" assert fcode(And(Not(x), y), source_format="free") == "y .and. .not. x" assert fcode(And(Not(x), Not(y)), source_format="free") == \ ".not. x .and. .not. y" assert fcode(Not(And(x, y), evaluate=False), source_format="free") == \ ".not. (x .and. y)" # binary Or assert fcode(Or(x, y), source_format="free") == "x .or. y" assert fcode(Or(x, Not(y)), source_format="free") == "x .or. .not. y" assert fcode(Or(Not(x), y), source_format="free") == "y .or. .not. x" assert fcode(Or(Not(x), Not(y)), source_format="free") == \ ".not. x .or. .not. y" assert fcode(Not(Or(x, y), evaluate=False), source_format="free") == \ ".not. (x .or. y)" # mixed And/Or assert fcode(And(Or(y, z), x), source_format="free") == "x .and. (y .or. z)" assert fcode(And(Or(z, x), y), source_format="free") == "y .and. (x .or. z)" assert fcode(And(Or(x, y), z), source_format="free") == "z .and. (x .or. y)" assert fcode(Or(And(y, z), x), source_format="free") == "x .or. y .and. z" assert fcode(Or(And(z, x), y), source_format="free") == "y .or. x .and. z" assert fcode(Or(And(x, y), z), source_format="free") == "z .or. x .and. y" # trinary And assert fcode(And(x, y, z), source_format="free") == "x .and. y .and. z" assert fcode(And(x, y, Not(z)), source_format="free") == \ "x .and. y .and. .not. z" assert fcode(And(x, Not(y), z), source_format="free") == \ "x .and. z .and. .not. y" assert fcode(And(Not(x), y, z), source_format="free") == \ "y .and. z .and. .not. x" assert fcode(Not(And(x, y, z), evaluate=False), source_format="free") == \ ".not. (x .and. y .and. z)" # trinary Or assert fcode(Or(x, y, z), source_format="free") == "x .or. y .or. z" assert fcode(Or(x, y, Not(z)), source_format="free") == \ "x .or. y .or. .not. z" assert fcode(Or(x, Not(y), z), source_format="free") == \ "x .or. z .or. .not. y" assert fcode(Or(Not(x), y, z), source_format="free") == \ "y .or. z .or. .not. x" assert fcode(Not(Or(x, y, z), evaluate=False), source_format="free") == \ ".not. (x .or. y .or. z)" def test_fcode_Xlogical(): x, y, z = symbols("x y z") # binary Xor assert fcode(Xor(x, y, evaluate=False), source_format="free") == \ "x .neqv. y" assert fcode(Xor(x, Not(y), evaluate=False), source_format="free") == \ "x .neqv. .not. y" assert fcode(Xor(Not(x), y, evaluate=False), source_format="free") == \ "y .neqv. .not. x" assert fcode(Xor(Not(x), Not(y), evaluate=False), source_format="free") == ".not. x .neqv. .not. y" assert fcode(Not(Xor(x, y, evaluate=False), evaluate=False), source_format="free") == ".not. (x .neqv. y)" # binary Equivalent assert fcode(Equivalent(x, y), source_format="free") == "x .eqv. y" assert fcode(Equivalent(x, Not(y)), source_format="free") == \ "x .eqv. .not. y" assert fcode(Equivalent(Not(x), y), source_format="free") == \ "y .eqv. .not. x" assert fcode(Equivalent(Not(x), Not(y)), source_format="free") == \ ".not. x .eqv. .not. y" assert fcode(Not(Equivalent(x, y), evaluate=False), source_format="free") == ".not. (x .eqv. y)" # mixed And/Equivalent assert fcode(Equivalent(And(y, z), x), source_format="free") == \ "x .eqv. y .and. z" assert fcode(Equivalent(And(z, x), y), source_format="free") == \ "y .eqv. x .and. z" assert fcode(Equivalent(And(x, y), z), source_format="free") == \ "z .eqv. x .and. y" assert fcode(And(Equivalent(y, z), x), source_format="free") == \ "x .and. (y .eqv. z)" assert fcode(And(Equivalent(z, x), y), source_format="free") == \ "y .and. (x .eqv. z)" assert fcode(And(Equivalent(x, y), z), source_format="free") == \ "z .and. (x .eqv. y)" # mixed Or/Equivalent assert fcode(Equivalent(Or(y, z), x), source_format="free") == \ "x .eqv. y .or. z" assert fcode(Equivalent(Or(z, x), y), source_format="free") == \ "y .eqv. x .or. z" assert fcode(Equivalent(Or(x, y), z), source_format="free") == \ "z .eqv. x .or. y" assert fcode(Or(Equivalent(y, z), x), source_format="free") == \ "x .or. (y .eqv. z)" assert fcode(Or(Equivalent(z, x), y), source_format="free") == \ "y .or. (x .eqv. z)" assert fcode(Or(Equivalent(x, y), z), source_format="free") == \ "z .or. (x .eqv. y)" # mixed Xor/Equivalent assert fcode(Equivalent(Xor(y, z, evaluate=False), x), source_format="free") == "x .eqv. (y .neqv. z)" assert fcode(Equivalent(Xor(z, x, evaluate=False), y), source_format="free") == "y .eqv. (x .neqv. z)" assert fcode(Equivalent(Xor(x, y, evaluate=False), z), source_format="free") == "z .eqv. (x .neqv. y)" assert fcode(Xor(Equivalent(y, z), x, evaluate=False), source_format="free") == "x .neqv. (y .eqv. z)" assert fcode(Xor(Equivalent(z, x), y, evaluate=False), source_format="free") == "y .neqv. (x .eqv. z)" assert fcode(Xor(Equivalent(x, y), z, evaluate=False), source_format="free") == "z .neqv. (x .eqv. y)" # mixed And/Xor assert fcode(Xor(And(y, z), x, evaluate=False), source_format="free") == \ "x .neqv. y .and. z" assert fcode(Xor(And(z, x), y, evaluate=False), source_format="free") == \ "y .neqv. x .and. z" assert fcode(Xor(And(x, y), z, evaluate=False), source_format="free") == \ "z .neqv. x .and. y" assert fcode(And(Xor(y, z, evaluate=False), x), source_format="free") == \ "x .and. (y .neqv. z)" assert fcode(And(Xor(z, x, evaluate=False), y), source_format="free") == \ "y .and. (x .neqv. z)" assert fcode(And(Xor(x, y, evaluate=False), z), source_format="free") == \ "z .and. (x .neqv. y)" # mixed Or/Xor assert fcode(Xor(Or(y, z), x, evaluate=False), source_format="free") == \ "x .neqv. y .or. z" assert fcode(Xor(Or(z, x), y, evaluate=False), source_format="free") == \ "y .neqv. x .or. z" assert fcode(Xor(Or(x, y), z, evaluate=False), source_format="free") == \ "z .neqv. x .or. y" assert fcode(Or(Xor(y, z, evaluate=False), x), source_format="free") == \ "x .or. (y .neqv. z)" assert fcode(Or(Xor(z, x, evaluate=False), y), source_format="free") == \ "y .or. (x .neqv. z)" assert fcode(Or(Xor(x, y, evaluate=False), z), source_format="free") == \ "z .or. (x .neqv. y)" # trinary Xor assert fcode(Xor(x, y, z, evaluate=False), source_format="free") == \ "x .neqv. y .neqv. z" assert fcode(Xor(x, y, Not(z), evaluate=False), source_format="free") == \ "x .neqv. y .neqv. .not. z" assert fcode(Xor(x, Not(y), z, evaluate=False), source_format="free") == \ "x .neqv. z .neqv. .not. y" assert fcode(Xor(Not(x), y, z, evaluate=False), source_format="free") == \ "y .neqv. z .neqv. .not. x" def test_fcode_Relational(): x, y = symbols("x y") assert fcode(Relational(x, y, "=="), source_format="free") == "x == y" assert fcode(Relational(x, y, "!="), source_format="free") == "x /= y" assert fcode(Relational(x, y, ">="), source_format="free") == "x >= y" assert fcode(Relational(x, y, "<="), source_format="free") == "x <= y" assert fcode(Relational(x, y, ">"), source_format="free") == "x > y" assert fcode(Relational(x, y, "<"), source_format="free") == "x < y" def test_fcode_Piecewise(): x = symbols('x') expr = Piecewise((x, x < 1), (x**2, True)) # Check that inline conditional (merge) fails if standard isn't 95+ raises(NotImplementedError, lambda: fcode(expr)) code = fcode(expr, standard=95) expected = " merge(x, x**2, x < 1)" assert code == expected assert fcode(Piecewise((x, x < 1), (x**2, True)), assign_to="var") == ( " if (x < 1) then\n" " var = x\n" " else\n" " var = x**2\n" " end if" ) a = cos(x)/x b = sin(x)/x for i in range(10): a = diff(a, x) b = diff(b, x) expected = ( " if (x < 0) then\n" " weird_name = -cos(x)/x + 10*sin(x)/x**2 + 90*cos(x)/x**3 - 720*\n" " @ sin(x)/x**4 - 5040*cos(x)/x**5 + 30240*sin(x)/x**6 + 151200*cos(x\n" " @ )/x**7 - 604800*sin(x)/x**8 - 1814400*cos(x)/x**9 + 3628800*sin(x\n" " @ )/x**10 + 3628800*cos(x)/x**11\n" " else\n" " weird_name = -sin(x)/x - 10*cos(x)/x**2 + 90*sin(x)/x**3 + 720*\n" " @ cos(x)/x**4 - 5040*sin(x)/x**5 - 30240*cos(x)/x**6 + 151200*sin(x\n" " @ )/x**7 + 604800*cos(x)/x**8 - 1814400*sin(x)/x**9 - 3628800*cos(x\n" " @ )/x**10 + 3628800*sin(x)/x**11\n" " end if" ) code = fcode(Piecewise((a, x < 0), (b, True)), assign_to="weird_name") assert code == expected code = fcode(Piecewise((x, x < 1), (x**2, x > 1), (sin(x), True)), standard=95) expected = " merge(x, merge(x**2, sin(x), x > 1), x < 1)" assert code == expected # Check that Piecewise without a True (default) condition error expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0)) raises(ValueError, lambda: fcode(expr)) def test_wrap_fortran(): # "########################################################################" printer = FCodePrinter() lines = [ "C This is a long comment on a single line that must be wrapped properly to produce nice output", " this = is + a + long + and + nasty + fortran + statement + that * must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that * must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that * must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that*must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that**must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement(that)/must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement(that)/must + be + wrapped + properly", ] wrapped_lines = printer._wrap_fortran(lines) expected_lines = [ "C This is a long comment on a single line that must be wrapped", "C properly to produce nice output", " this = is + a + long + and + nasty + fortran + statement + that *", " @ must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that *", " @ must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that", " @ * must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that*", " @ must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that*", " @ must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that", " @ *must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement +", " @ that*must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that**", " @ must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that**", " @ must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that", " @ **must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement + that", " @ **must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement +", " @ that**must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement(that)/", " @ must + be + wrapped + properly", " this = is + a + long + and + nasty + fortran + statement(that)", " @ /must + be + wrapped + properly", ] for line in wrapped_lines: assert len(line) <= 72 for w, e in zip(wrapped_lines, expected_lines): assert w == e assert len(wrapped_lines) == len(expected_lines) def test_wrap_fortran_keep_d0(): printer = FCodePrinter() lines = [ ' this_variable_is_very_long_because_we_try_to_test_line_break=1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break = 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break = 10.0d0' ] expected = [ ' this_variable_is_very_long_because_we_try_to_test_line_break=1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =', ' @ 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =', ' @ 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =', ' @ 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =', ' @ 1.0d0', ' this_variable_is_very_long_because_we_try_to_test_line_break =', ' @ 10.0d0' ] assert printer._wrap_fortran(lines) == expected def test_settings(): raises(TypeError, lambda: fcode(S(4), method="garbage")) def test_free_form_code_line(): x, y = symbols('x,y') assert fcode(cos(x) + sin(y), source_format='free') == "sin(y) + cos(x)" def test_free_form_continuation_line(): x, y = symbols('x,y') result = fcode(((cos(x) + sin(y))**(7)).expand(), source_format='free') expected = ( 'sin(y)**7 + 7*sin(y)**6*cos(x) + 21*sin(y)**5*cos(x)**2 + 35*sin(y)**4* &\n' ' cos(x)**3 + 35*sin(y)**3*cos(x)**4 + 21*sin(y)**2*cos(x)**5 + 7* &\n' ' sin(y)*cos(x)**6 + cos(x)**7' ) assert result == expected def test_free_form_comment_line(): printer = FCodePrinter({'source_format': 'free'}) lines = [ "! This is a long comment on a single line that must be wrapped properly to produce nice output"] expected = [ '! This is a long comment on a single line that must be wrapped properly', '! to produce nice output'] assert printer._wrap_fortran(lines) == expected def test_loops(): n, m = symbols('n,m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) expected = ( 'do i = 1, m\n' ' y(i) = 0\n' 'end do\n' 'do i = 1, m\n' ' do j = 1, n\n' ' y(i) = %(rhs)s\n' ' end do\n' 'end do' ) code = fcode(A[i, j]*x[j], assign_to=y[i], source_format='free') assert (code == expected % {'rhs': 'y(i) + A(i, j)*x(j)'} or code == expected % {'rhs': 'y(i) + x(j)*A(i, j)'} or code == expected % {'rhs': 'x(j)*A(i, j) + y(i)'} or code == expected % {'rhs': 'A(i, j)*x(j) + y(i)'}) def test_dummy_loops(): i, m = symbols('i m', integer=True, cls=Dummy) x = IndexedBase('x') y = IndexedBase('y') i = Idx(i, m) expected = ( 'do i_%(icount)i = 1, m_%(mcount)i\n' ' y(i_%(icount)i) = x(i_%(icount)i)\n' 'end do' ) % {'icount': i.label.dummy_index, 'mcount': m.dummy_index} code = fcode(x[i], assign_to=y[i], source_format='free') assert code == expected def test_fcode_Indexed_without_looking_for_contraction(): len_y = 5 y = IndexedBase('y', shape=(len_y,)) x = IndexedBase('x', shape=(len_y,)) Dy = IndexedBase('Dy', shape=(len_y-1,)) i = Idx('i', len_y-1) e=Eq(Dy[i], (y[i+1]-y[i])/(x[i+1]-x[i])) code0 = fcode(e.rhs, assign_to=e.lhs, contract=False) assert code0.endswith('Dy(i) = (y(i + 1) - y(i))/(x(i + 1) - x(i))') def test_derived_classes(): class MyFancyFCodePrinter(FCodePrinter): _default_settings = FCodePrinter._default_settings.copy() printer = MyFancyFCodePrinter() x = symbols('x') assert printer.doprint(sin(x), "bork") == " bork = sin(x)" def test_indent(): codelines = ( 'subroutine test(a)\n' 'integer :: a, i, j\n' '\n' 'do\n' 'do \n' 'do j = 1, 5\n' 'if (a>b) then\n' 'if(b>0) then\n' 'a = 3\n' 'donot_indent_me = 2\n' 'do_not_indent_me_either = 2\n' 'ifIam_indented_something_went_wrong = 2\n' 'if_I_am_indented_something_went_wrong = 2\n' 'end should not be unindented here\n' 'end if\n' 'endif\n' 'end do\n' 'end do\n' 'enddo\n' 'end subroutine\n' '\n' 'subroutine test2(a)\n' 'integer :: a\n' 'do\n' 'a = a + 1\n' 'end do \n' 'end subroutine\n' ) expected = ( 'subroutine test(a)\n' 'integer :: a, i, j\n' '\n' 'do\n' ' do \n' ' do j = 1, 5\n' ' if (a>b) then\n' ' if(b>0) then\n' ' a = 3\n' ' donot_indent_me = 2\n' ' do_not_indent_me_either = 2\n' ' ifIam_indented_something_went_wrong = 2\n' ' if_I_am_indented_something_went_wrong = 2\n' ' end should not be unindented here\n' ' end if\n' ' endif\n' ' end do\n' ' end do\n' 'enddo\n' 'end subroutine\n' '\n' 'subroutine test2(a)\n' 'integer :: a\n' 'do\n' ' a = a + 1\n' 'end do \n' 'end subroutine\n' ) p = FCodePrinter({'source_format': 'free'}) result = p.indent_code(codelines) assert result == expected def test_Matrix_printing(): x, y, z = symbols('x,y,z') # Test returning a Matrix mat = Matrix([x*y, Piecewise((2 + x, y>0), (y, True)), sin(z)]) A = MatrixSymbol('A', 3, 1) assert fcode(mat, A) == ( " A(1, 1) = x*y\n" " if (y > 0) then\n" " A(2, 1) = x + 2\n" " else\n" " A(2, 1) = y\n" " end if\n" " A(3, 1) = sin(z)") # Test using MatrixElements in expressions expr = Piecewise((2*A[2, 0], x > 0), (A[2, 0], True)) + sin(A[1, 0]) + A[0, 0] assert fcode(expr, standard=95) == ( " merge(2*A(3, 1), A(3, 1), x > 0) + sin(A(2, 1)) + A(1, 1)") # Test using MatrixElements in a Matrix q = MatrixSymbol('q', 5, 1) M = MatrixSymbol('M', 3, 3) m = Matrix([[sin(q[1,0]), 0, cos(q[2,0])], [q[1,0] + q[2,0], q[3, 0], 5], [2*q[4, 0]/q[1,0], sqrt(q[0,0]) + 4, 0]]) assert fcode(m, M) == ( " M(1, 1) = sin(q(2, 1))\n" " M(2, 1) = q(2, 1) + q(3, 1)\n" " M(3, 1) = 2*q(5, 1)/q(2, 1)\n" " M(1, 2) = 0\n" " M(2, 2) = q(4, 1)\n" " M(3, 2) = sqrt(q(1, 1)) + 4\n" " M(1, 3) = cos(q(3, 1))\n" " M(2, 3) = 5\n" " M(3, 3) = 0") def test_fcode_For(): x, y = symbols('x y') f = For(x, Range(0, 10, 2), [Assignment(y, x * y)]) sol = fcode(f) assert sol == (" do x = 0, 10, 2\n" " y = x*y\n" " end do") def test_fcode_Declaration(): def check(expr, ref, **kwargs): assert fcode(expr, standard=95, source_format='free', **kwargs) == ref i = symbols('i', integer=True) var1 = Variable.deduced(i) dcl1 = Declaration(var1) check(dcl1, "integer*4 :: i") x, y = symbols('x y') var2 = Variable(x, float32, value=42, attrs={value_const}) dcl2b = Declaration(var2) check(dcl2b, 'real*4, parameter :: x = 42') var3 = Variable(y, type=bool_) dcl3 = Declaration(var3) check(dcl3, 'logical :: y') check(float32, "real*4") check(float64, "real*8") check(real, "real*4", type_aliases={real: float32}) check(real, "real*8", type_aliases={real: float64}) def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert(fcode(A[0, 0]) == " A(1, 1)") assert(fcode(3 * A[0, 0]) == " 3*A(1, 1)") F = C[0, 0].subs(C, A - B) assert(fcode(F) == " (A - B)(1, 1)") def test_aug_assign(): x = symbols('x') assert fcode(aug_assign(x, '+', 1), source_format='free') == 'x = x + 1' def test_While(): x = symbols('x') assert fcode(While(abs(x) > 1, [aug_assign(x, '-', 1)]), source_format='free') == ( 'do while (abs(x) > 1)\n' ' x = x - 1\n' 'end do' ) def test_FunctionPrototype_print(): x = symbols('x') n = symbols('n', integer=True) vx = Variable(x, type=real) vn = Variable(n, type=integer) fp1 = FunctionPrototype(real, 'power', [vx, vn]) # Should be changed to proper test once multi-line generation is working # see https://github.com/sympy/sympy/issues/15824 raises(NotImplementedError, lambda: fcode(fp1)) def test_FunctionDefinition_print(): x = symbols('x') n = symbols('n', integer=True) vx = Variable(x, type=real) vn = Variable(n, type=integer) body = [Assignment(x, x**n), Return(x)] fd1 = FunctionDefinition(real, 'power', [vx, vn], body) # Should be changed to proper test once multi-line generation is working # see https://github.com/sympy/sympy/issues/15824 raises(NotImplementedError, lambda: fcode(fd1)) def test_fcode_submodule(): # Test the compatibility sympy.printing.fcode module imports with warns_deprecated_sympy(): import sympy.printing.fcode # noqa:F401 sympy-sympy-1.9/sympy/printing/tests/test_glsl.py000066400000000000000000000701631412543434000224610ustar00rootroot00000000000000from sympy.core import (pi, symbols, Rational, Integer, GoldenRatio, EulerGamma, Catalan, Lambda, Dummy, Eq, Ne, Le, Lt, Gt, Ge) from sympy.functions import Piecewise, sin, cos, Abs, exp, ceiling, sqrt from sympy.testing.pytest import raises, warns_deprecated_sympy from sympy.printing.glsl import GLSLPrinter from sympy.printing.str import StrPrinter from sympy.utilities.lambdify import implemented_function from sympy.tensor import IndexedBase, Idx from sympy.matrices import Matrix, MatrixSymbol from sympy.core import Tuple from sympy import glsl_code import textwrap x, y, z = symbols('x,y,z') def test_printmethod(): assert glsl_code(Abs(x)) == "abs(x)" def test_print_without_operators(): assert glsl_code(x*y,use_operators = False) == 'mul(x, y)' assert glsl_code(x**y+z,use_operators = False) == 'add(pow(x, y), z)' assert glsl_code(x*(y+z),use_operators = False) == 'mul(x, add(y, z))' assert glsl_code(x*(y+z),use_operators = False) == 'mul(x, add(y, z))' assert glsl_code(x*(y+z**y**0.5),use_operators = False) == 'mul(x, add(y, pow(z, sqrt(y))))' assert glsl_code(-x-y, use_operators=False, zero='zero()') == 'sub(zero(), add(x, y))' assert glsl_code(-x-y, use_operators=False) == 'sub(0.0, add(x, y))' def test_glsl_code_sqrt(): assert glsl_code(sqrt(x)) == "sqrt(x)" assert glsl_code(x**0.5) == "sqrt(x)" assert glsl_code(sqrt(x)) == "sqrt(x)" def test_glsl_code_Pow(): g = implemented_function('g', Lambda(x, 2*x)) assert glsl_code(x**3) == "pow(x, 3.0)" assert glsl_code(x**(y**3)) == "pow(x, pow(y, 3.0))" assert glsl_code(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "pow(3.5*2*x, -x + pow(y, x))/(pow(x, 2.0) + y)" assert glsl_code(x**-1.0) == '1.0/x' def test_glsl_code_Relational(): assert glsl_code(Eq(x, y)) == "x == y" assert glsl_code(Ne(x, y)) == "x != y" assert glsl_code(Le(x, y)) == "x <= y" assert glsl_code(Lt(x, y)) == "x < y" assert glsl_code(Gt(x, y)) == "x > y" assert glsl_code(Ge(x, y)) == "x >= y" def test_glsl_code_constants_mathh(): assert glsl_code(exp(1)) == "float E = 2.71828183;\nE" assert glsl_code(pi) == "float pi = 3.14159265;\npi" # assert glsl_code(oo) == "Number.POSITIVE_INFINITY" # assert glsl_code(-oo) == "Number.NEGATIVE_INFINITY" def test_glsl_code_constants_other(): assert glsl_code(2*GoldenRatio) == "float GoldenRatio = 1.61803399;\n2*GoldenRatio" assert glsl_code(2*Catalan) == "float Catalan = 0.915965594;\n2*Catalan" assert glsl_code(2*EulerGamma) == "float EulerGamma = 0.577215665;\n2*EulerGamma" def test_glsl_code_Rational(): assert glsl_code(Rational(3, 7)) == "3.0/7.0" assert glsl_code(Rational(18, 9)) == "2" assert glsl_code(Rational(3, -7)) == "-3.0/7.0" assert glsl_code(Rational(-3, -7)) == "3.0/7.0" def test_glsl_code_Integer(): assert glsl_code(Integer(67)) == "67" assert glsl_code(Integer(-1)) == "-1" def test_glsl_code_functions(): assert glsl_code(sin(x) ** cos(x)) == "pow(sin(x), cos(x))" def test_glsl_code_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert glsl_code(g(x)) == "2*x" g = implemented_function('g', Lambda(x, 2*x/Catalan)) assert glsl_code(g(x)) == "float Catalan = 0.915965594;\n2*x/Catalan" A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert glsl_code(g(A[i]), assign_to=A[i]) == ( "for (int i=0; i 1), (sin(x), x > 0)) raises(ValueError, lambda: glsl_code(expr)) def test_glsl_code_Piecewise_deep(): p = glsl_code(2*Piecewise((x, x < 1), (x**2, True))) s = \ """\ 2*((x < 1) ? ( x ) : ( pow(x, 2.0) ))\ """ assert p == s def test_glsl_code_settings(): raises(TypeError, lambda: glsl_code(sin(x), method="garbage")) def test_glsl_code_Indexed(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o = symbols('n m o', integer=True) i, j, k = Idx('i', n), Idx('j', m), Idx('k', o) p = GLSLPrinter() p._not_c = set() x = IndexedBase('x')[j] assert p._print_Indexed(x) == 'x[j]' A = IndexedBase('A')[i, j] assert p._print_Indexed(A) == 'A[%s]' % (m*i+j) B = IndexedBase('B')[i, j, k] assert p._print_Indexed(B) == 'B[%s]' % (i*o*m+j*o+k) assert p._not_c == set() def test_glsl_code_list_tuple_Tuple(): assert glsl_code([1,2,3,4]) == 'vec4(1, 2, 3, 4)' assert glsl_code([1,2,3],glsl_types=False) == 'float[3](1, 2, 3)' assert glsl_code([1,2,3]) == glsl_code((1,2,3)) assert glsl_code([1,2,3]) == glsl_code(Tuple(1,2,3)) m = MatrixSymbol('A',3,4) assert glsl_code([m[0],m[1]]) def test_glsl_code_loops_matrix_vector(): n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) s = ( 'for (int i=0; i0), (y, True)), sin(z)]) A = MatrixSymbol('A', 3, 1) assert glsl_code(mat, assign_to=A) == ( '''A[0][0] = x*y; if (y > 0) { A[1][0] = x + 2; } else { A[1][0] = y; } A[2][0] = sin(z);''' ) assert glsl_code(Matrix([A[0],A[1]])) # Test using MatrixElements in expressions expr = Piecewise((2*A[2, 0], x > 0), (A[2, 0], True)) + sin(A[1, 0]) + A[0, 0] assert glsl_code(expr) == ( '''((x > 0) ? ( 2*A[2][0] ) : ( A[2][0] )) + sin(A[1][0]) + A[0][0]''' ) # Test using MatrixElements in a Matrix q = MatrixSymbol('q', 5, 1) M = MatrixSymbol('M', 3, 3) m = Matrix([[sin(q[1,0]), 0, cos(q[2,0])], [q[1,0] + q[2,0], q[3, 0], 5], [2*q[4, 0]/q[1,0], sqrt(q[0,0]) + 4, 0]]) assert glsl_code(m,M) == ( '''M[0][0] = sin(q[1]); M[0][1] = 0; M[0][2] = cos(q[2]); M[1][0] = q[1] + q[2]; M[1][1] = q[3]; M[1][2] = 5; M[2][0] = 2*q[4]/q[1]; M[2][1] = sqrt(q[0]) + 4; M[2][2] = 0;''' ) def test_Matrices_1x7(): gl = glsl_code A = Matrix([1,2,3,4,5,6,7]) assert gl(A) == 'float[7](1, 2, 3, 4, 5, 6, 7)' assert gl(A.transpose()) == 'float[7](1, 2, 3, 4, 5, 6, 7)' def test_Matrices_1x7_array_type_int(): gl = glsl_code A = Matrix([1,2,3,4,5,6,7]) assert gl(A, array_type='int') == 'int[7](1, 2, 3, 4, 5, 6, 7)' def test_Tuple_array_type_custom(): gl = glsl_code A = symbols('a b c') assert gl(A, array_type='AbcType', glsl_types=False) == 'AbcType[3](a, b, c)' def test_Matrices_1x7_spread_assign_to_symbols(): gl = glsl_code A = Matrix([1,2,3,4,5,6,7]) assign_to = symbols('x.a x.b x.c x.d x.e x.f x.g') assert gl(A, assign_to=assign_to) == textwrap.dedent('''\ x.a = 1; x.b = 2; x.c = 3; x.d = 4; x.e = 5; x.f = 6; x.g = 7;''' ) def test_spread_assign_to_nested_symbols(): gl = glsl_code expr = ((1,2,3), (1,2,3)) assign_to = (symbols('a b c'), symbols('x y z')) assert gl(expr, assign_to=assign_to) == textwrap.dedent('''\ a = 1; b = 2; c = 3; x = 1; y = 2; z = 3;''' ) def test_spread_assign_to_deeply_nested_symbols(): gl = glsl_code a, b, c, x, y, z = symbols('a b c x y z') expr = (((1,2),3), ((1,2),3)) assign_to = (((a, b), c), ((x, y), z)) assert gl(expr, assign_to=assign_to) == textwrap.dedent('''\ a = 1; b = 2; c = 3; x = 1; y = 2; z = 3;''' ) def test_matrix_of_tuples_spread_assign_to_symbols(): gl = glsl_code with warns_deprecated_sympy(): expr = Matrix([[(1,2),(3,4)],[(5,6),(7,8)]]) assign_to = (symbols('a b'), symbols('c d'), symbols('e f'), symbols('g h')) assert gl(expr, assign_to) == textwrap.dedent('''\ a = 1; b = 2; c = 3; d = 4; e = 5; f = 6; g = 7; h = 8;''' ) def test_cannot_assign_to_cause_mismatched_length(): expr = (1, 2) assign_to = symbols('x y z') raises(ValueError, lambda: glsl_code(expr, assign_to)) def test_matrix_4x4_assign(): gl = glsl_code expr = MatrixSymbol('A',4,4) * MatrixSymbol('B',4,4) + MatrixSymbol('C',4,4) assign_to = MatrixSymbol('X',4,4) assert gl(expr, assign_to=assign_to) == textwrap.dedent('''\ X[0][0] = A[0][0]*B[0][0] + A[0][1]*B[1][0] + A[0][2]*B[2][0] + A[0][3]*B[3][0] + C[0][0]; X[0][1] = A[0][0]*B[0][1] + A[0][1]*B[1][1] + A[0][2]*B[2][1] + A[0][3]*B[3][1] + C[0][1]; X[0][2] = A[0][0]*B[0][2] + A[0][1]*B[1][2] + A[0][2]*B[2][2] + A[0][3]*B[3][2] + C[0][2]; X[0][3] = A[0][0]*B[0][3] + A[0][1]*B[1][3] + A[0][2]*B[2][3] + A[0][3]*B[3][3] + C[0][3]; X[1][0] = A[1][0]*B[0][0] + A[1][1]*B[1][0] + A[1][2]*B[2][0] + A[1][3]*B[3][0] + C[1][0]; X[1][1] = A[1][0]*B[0][1] + A[1][1]*B[1][1] + A[1][2]*B[2][1] + A[1][3]*B[3][1] + C[1][1]; X[1][2] = A[1][0]*B[0][2] + A[1][1]*B[1][2] + A[1][2]*B[2][2] + A[1][3]*B[3][2] + C[1][2]; X[1][3] = A[1][0]*B[0][3] + A[1][1]*B[1][3] + A[1][2]*B[2][3] + A[1][3]*B[3][3] + C[1][3]; X[2][0] = A[2][0]*B[0][0] + A[2][1]*B[1][0] + A[2][2]*B[2][0] + A[2][3]*B[3][0] + C[2][0]; X[2][1] = A[2][0]*B[0][1] + A[2][1]*B[1][1] + A[2][2]*B[2][1] + A[2][3]*B[3][1] + C[2][1]; X[2][2] = A[2][0]*B[0][2] + A[2][1]*B[1][2] + A[2][2]*B[2][2] + A[2][3]*B[3][2] + C[2][2]; X[2][3] = A[2][0]*B[0][3] + A[2][1]*B[1][3] + A[2][2]*B[2][3] + A[2][3]*B[3][3] + C[2][3]; X[3][0] = A[3][0]*B[0][0] + A[3][1]*B[1][0] + A[3][2]*B[2][0] + A[3][3]*B[3][0] + C[3][0]; X[3][1] = A[3][0]*B[0][1] + A[3][1]*B[1][1] + A[3][2]*B[2][1] + A[3][3]*B[3][1] + C[3][1]; X[3][2] = A[3][0]*B[0][2] + A[3][1]*B[1][2] + A[3][2]*B[2][2] + A[3][3]*B[3][2] + C[3][2]; X[3][3] = A[3][0]*B[0][3] + A[3][1]*B[1][3] + A[3][2]*B[2][3] + A[3][3]*B[3][3] + C[3][3];''' ) def test_1xN_vecs(): gl = glsl_code for i in range(1,10): A = Matrix(range(i)) assert gl(A.transpose()) == gl(A) assert gl(A,mat_transpose=True) == gl(A) if i > 1: if i <= 4: assert gl(A) == 'vec%s(%s)' % (i,', '.join(str(s) for s in range(i))) else: assert gl(A) == 'float[%s](%s)' % (i,', '.join(str(s) for s in range(i))) def test_MxN_mats(): generatedAssertions='def test_misc_mats():\n' for i in range(1,6): for j in range(1,6): A = Matrix([[x + y*j for x in range(j)] for y in range(i)]) gl = glsl_code(A) glTransposed = glsl_code(A,mat_transpose=True) generatedAssertions+=' mat = '+StrPrinter()._print(A)+'\n\n' generatedAssertions+=' gl = \'\'\''+gl+'\'\'\'\n' generatedAssertions+=' glTransposed = \'\'\''+glTransposed+'\'\'\'\n\n' generatedAssertions+=' assert glsl_code(mat) == gl\n' generatedAssertions+=' assert glsl_code(mat,mat_transpose=True) == glTransposed\n' if i == 1 and j == 1: assert gl == '0' elif i <= 4 and j <= 4 and i>1 and j>1: assert gl.startswith('mat%s' % j) assert glTransposed.startswith('mat%s' % i) elif i == 1 and j <= 4: assert gl.startswith('vec') elif j == 1 and i <= 4: assert gl.startswith('vec') elif i == 1: assert gl.startswith('float[%s]('% j*i) assert glTransposed.startswith('float[%s]('% j*i) elif j == 1: assert gl.startswith('float[%s]('% i*j) assert glTransposed.startswith('float[%s]('% i*j) else: assert gl.startswith('float[%s](' % (i*j)) assert glTransposed.startswith('float[%s](' % (i*j)) glNested = glsl_code(A,mat_nested=True) glNestedTransposed = glsl_code(A,mat_transpose=True,mat_nested=True) assert glNested.startswith('float[%s][%s]' % (i,j)) assert glNestedTransposed.startswith('float[%s][%s]' % (j,i)) generatedAssertions+=' glNested = \'\'\''+glNested+'\'\'\'\n' generatedAssertions+=' glNestedTransposed = \'\'\''+glNestedTransposed+'\'\'\'\n\n' generatedAssertions+=' assert glsl_code(mat,mat_nested=True) == glNested\n' generatedAssertions+=' assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed\n\n' generateAssertions = False # set this to true to write bake these generated tests to a file if generateAssertions: gen = open('test_glsl_generated_matrices.py','w') gen.write(generatedAssertions) gen.close() # these assertions were generated from the previous function # glsl has complicated rules and this makes it easier to look over all the cases def test_misc_mats(): mat = Matrix([[0]]) gl = '''0''' glTransposed = '''0''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([[0, 1]]) gl = '''vec2(0, 1)''' glTransposed = '''vec2(0, 1)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([[0, 1, 2]]) gl = '''vec3(0, 1, 2)''' glTransposed = '''vec3(0, 1, 2)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([[0, 1, 2, 3]]) gl = '''vec4(0, 1, 2, 3)''' glTransposed = '''vec4(0, 1, 2, 3)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([[0, 1, 2, 3, 4]]) gl = '''float[5](0, 1, 2, 3, 4)''' glTransposed = '''float[5](0, 1, 2, 3, 4)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0], [1]]) gl = '''vec2(0, 1)''' glTransposed = '''vec2(0, 1)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1], [2, 3]]) gl = '''mat2(0, 1, 2, 3)''' glTransposed = '''mat2(0, 2, 1, 3)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1, 2], [3, 4, 5]]) gl = '''mat3x2(0, 1, 2, 3, 4, 5)''' glTransposed = '''mat2x3(0, 3, 1, 4, 2, 5)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1, 2, 3], [4, 5, 6, 7]]) gl = '''mat4x2(0, 1, 2, 3, 4, 5, 6, 7)''' glTransposed = '''mat2x4(0, 4, 1, 5, 2, 6, 3, 7)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1, 2, 3, 4], [5, 6, 7, 8, 9]]) gl = '''float[10]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ) /* a 2x5 matrix */''' glTransposed = '''float[10]( 0, 5, 1, 6, 2, 7, 3, 8, 4, 9 ) /* a 5x2 matrix */''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed glNested = '''float[2][5]( float[](0, 1, 2, 3, 4), float[](5, 6, 7, 8, 9) )''' glNestedTransposed = '''float[5][2]( float[](0, 5), float[](1, 6), float[](2, 7), float[](3, 8), float[](4, 9) )''' assert glsl_code(mat,mat_nested=True) == glNested assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed mat = Matrix([ [0], [1], [2]]) gl = '''vec3(0, 1, 2)''' glTransposed = '''vec3(0, 1, 2)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1], [2, 3], [4, 5]]) gl = '''mat2x3(0, 1, 2, 3, 4, 5)''' glTransposed = '''mat3x2(0, 2, 4, 1, 3, 5)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1, 2], [3, 4, 5], [6, 7, 8]]) gl = '''mat3(0, 1, 2, 3, 4, 5, 6, 7, 8)''' glTransposed = '''mat3(0, 3, 6, 1, 4, 7, 2, 5, 8)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]) gl = '''mat4x3(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)''' glTransposed = '''mat3x4(0, 4, 8, 1, 5, 9, 2, 6, 10, 3, 7, 11)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14]]) gl = '''float[15]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ) /* a 3x5 matrix */''' glTransposed = '''float[15]( 0, 5, 10, 1, 6, 11, 2, 7, 12, 3, 8, 13, 4, 9, 14 ) /* a 5x3 matrix */''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed glNested = '''float[3][5]( float[]( 0, 1, 2, 3, 4), float[]( 5, 6, 7, 8, 9), float[](10, 11, 12, 13, 14) )''' glNestedTransposed = '''float[5][3]( float[](0, 5, 10), float[](1, 6, 11), float[](2, 7, 12), float[](3, 8, 13), float[](4, 9, 14) )''' assert glsl_code(mat,mat_nested=True) == glNested assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed mat = Matrix([ [0], [1], [2], [3]]) gl = '''vec4(0, 1, 2, 3)''' glTransposed = '''vec4(0, 1, 2, 3)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1], [2, 3], [4, 5], [6, 7]]) gl = '''mat2x4(0, 1, 2, 3, 4, 5, 6, 7)''' glTransposed = '''mat4x2(0, 2, 4, 6, 1, 3, 5, 7)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]) gl = '''mat3x4(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)''' glTransposed = '''mat4x3(0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15]]) gl = '''mat4( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)''' glTransposed = '''mat4(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) gl = '''float[20]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ) /* a 4x5 matrix */''' glTransposed = '''float[20]( 0, 5, 10, 15, 1, 6, 11, 16, 2, 7, 12, 17, 3, 8, 13, 18, 4, 9, 14, 19 ) /* a 5x4 matrix */''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed glNested = '''float[4][5]( float[]( 0, 1, 2, 3, 4), float[]( 5, 6, 7, 8, 9), float[](10, 11, 12, 13, 14), float[](15, 16, 17, 18, 19) )''' glNestedTransposed = '''float[5][4]( float[](0, 5, 10, 15), float[](1, 6, 11, 16), float[](2, 7, 12, 17), float[](3, 8, 13, 18), float[](4, 9, 14, 19) )''' assert glsl_code(mat,mat_nested=True) == glNested assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed mat = Matrix([ [0], [1], [2], [3], [4]]) gl = '''float[5](0, 1, 2, 3, 4)''' glTransposed = '''float[5](0, 1, 2, 3, 4)''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed mat = Matrix([ [0, 1], [2, 3], [4, 5], [6, 7], [8, 9]]) gl = '''float[10]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ) /* a 5x2 matrix */''' glTransposed = '''float[10]( 0, 2, 4, 6, 8, 1, 3, 5, 7, 9 ) /* a 2x5 matrix */''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed glNested = '''float[5][2]( float[](0, 1), float[](2, 3), float[](4, 5), float[](6, 7), float[](8, 9) )''' glNestedTransposed = '''float[2][5]( float[](0, 2, 4, 6, 8), float[](1, 3, 5, 7, 9) )''' assert glsl_code(mat,mat_nested=True) == glNested assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed mat = Matrix([ [ 0, 1, 2], [ 3, 4, 5], [ 6, 7, 8], [ 9, 10, 11], [12, 13, 14]]) gl = '''float[15]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 ) /* a 5x3 matrix */''' glTransposed = '''float[15]( 0, 3, 6, 9, 12, 1, 4, 7, 10, 13, 2, 5, 8, 11, 14 ) /* a 3x5 matrix */''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed glNested = '''float[5][3]( float[]( 0, 1, 2), float[]( 3, 4, 5), float[]( 6, 7, 8), float[]( 9, 10, 11), float[](12, 13, 14) )''' glNestedTransposed = '''float[3][5]( float[](0, 3, 6, 9, 12), float[](1, 4, 7, 10, 13), float[](2, 5, 8, 11, 14) )''' assert glsl_code(mat,mat_nested=True) == glNested assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed mat = Matrix([ [ 0, 1, 2, 3], [ 4, 5, 6, 7], [ 8, 9, 10, 11], [12, 13, 14, 15], [16, 17, 18, 19]]) gl = '''float[20]( 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ) /* a 5x4 matrix */''' glTransposed = '''float[20]( 0, 4, 8, 12, 16, 1, 5, 9, 13, 17, 2, 6, 10, 14, 18, 3, 7, 11, 15, 19 ) /* a 4x5 matrix */''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed glNested = '''float[5][4]( float[]( 0, 1, 2, 3), float[]( 4, 5, 6, 7), float[]( 8, 9, 10, 11), float[](12, 13, 14, 15), float[](16, 17, 18, 19) )''' glNestedTransposed = '''float[4][5]( float[](0, 4, 8, 12, 16), float[](1, 5, 9, 13, 17), float[](2, 6, 10, 14, 18), float[](3, 7, 11, 15, 19) )''' assert glsl_code(mat,mat_nested=True) == glNested assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed mat = Matrix([ [ 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]]) gl = '''float[25]( 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 ) /* a 5x5 matrix */''' glTransposed = '''float[25]( 0, 5, 10, 15, 20, 1, 6, 11, 16, 21, 2, 7, 12, 17, 22, 3, 8, 13, 18, 23, 4, 9, 14, 19, 24 ) /* a 5x5 matrix */''' assert glsl_code(mat) == gl assert glsl_code(mat,mat_transpose=True) == glTransposed glNested = '''float[5][5]( float[]( 0, 1, 2, 3, 4), float[]( 5, 6, 7, 8, 9), float[](10, 11, 12, 13, 14), float[](15, 16, 17, 18, 19), float[](20, 21, 22, 23, 24) )''' glNestedTransposed = '''float[5][5]( float[](0, 5, 10, 15, 20), float[](1, 6, 11, 16, 21), float[](2, 7, 12, 17, 22), float[](3, 8, 13, 18, 23), float[](4, 9, 14, 19, 24) )''' assert glsl_code(mat,mat_nested=True) == glNested assert glsl_code(mat,mat_nested=True,mat_transpose=True) == glNestedTransposed sympy-sympy-1.9/sympy/printing/tests/test_gtk.py000066400000000000000000000006631412543434000223030ustar00rootroot00000000000000from sympy import print_gtk, sin from sympy.testing.pytest import XFAIL, raises # this test fails if python-lxml isn't installed. We don't want to depend on # anything with SymPy @XFAIL def test_1(): from sympy.abc import x print_gtk(x**2, start_viewer=False) print_gtk(x**2 + sin(x)/4, start_viewer=False) def test_settings(): from sympy.abc import x raises(TypeError, lambda: print_gtk(x, method="garbage")) sympy-sympy-1.9/sympy/printing/tests/test_jscode.py000066400000000000000000000260201412543434000227600ustar00rootroot00000000000000from sympy.core import (pi, oo, symbols, Rational, Integer, GoldenRatio, EulerGamma, Catalan, Lambda, Dummy, S, Eq, Ne, Le, Lt, Gt, Ge) from sympy.functions import (Piecewise, sin, cos, Abs, exp, ceiling, sqrt, sinh, cosh, tanh, asin, acos, acosh, Max, Min) from sympy.testing.pytest import raises from sympy.printing.jscode import JavascriptCodePrinter from sympy.utilities.lambdify import implemented_function from sympy.tensor import IndexedBase, Idx from sympy.matrices import Matrix, MatrixSymbol from sympy import jscode x, y, z = symbols('x,y,z') def test_printmethod(): assert jscode(Abs(x)) == "Math.abs(x)" def test_jscode_sqrt(): assert jscode(sqrt(x)) == "Math.sqrt(x)" assert jscode(x**0.5) == "Math.sqrt(x)" assert jscode(x**(S.One/3)) == "Math.cbrt(x)" def test_jscode_Pow(): g = implemented_function('g', Lambda(x, 2*x)) assert jscode(x**3) == "Math.pow(x, 3)" assert jscode(x**(y**3)) == "Math.pow(x, Math.pow(y, 3))" assert jscode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "Math.pow(3.5*2*x, -x + Math.pow(y, x))/(Math.pow(x, 2) + y)" assert jscode(x**-1.0) == '1/x' def test_jscode_constants_mathh(): assert jscode(exp(1)) == "Math.E" assert jscode(pi) == "Math.PI" assert jscode(oo) == "Number.POSITIVE_INFINITY" assert jscode(-oo) == "Number.NEGATIVE_INFINITY" def test_jscode_constants_other(): assert jscode( 2*GoldenRatio) == "var GoldenRatio = %s;\n2*GoldenRatio" % GoldenRatio.evalf(17) assert jscode(2*Catalan) == "var Catalan = %s;\n2*Catalan" % Catalan.evalf(17) assert jscode( 2*EulerGamma) == "var EulerGamma = %s;\n2*EulerGamma" % EulerGamma.evalf(17) def test_jscode_Rational(): assert jscode(Rational(3, 7)) == "3/7" assert jscode(Rational(18, 9)) == "2" assert jscode(Rational(3, -7)) == "-3/7" assert jscode(Rational(-3, -7)) == "3/7" def test_Relational(): assert jscode(Eq(x, y)) == "x == y" assert jscode(Ne(x, y)) == "x != y" assert jscode(Le(x, y)) == "x <= y" assert jscode(Lt(x, y)) == "x < y" assert jscode(Gt(x, y)) == "x > y" assert jscode(Ge(x, y)) == "x >= y" def test_jscode_Integer(): assert jscode(Integer(67)) == "67" assert jscode(Integer(-1)) == "-1" def test_jscode_functions(): assert jscode(sin(x) ** cos(x)) == "Math.pow(Math.sin(x), Math.cos(x))" assert jscode(sinh(x) * cosh(x)) == "Math.sinh(x)*Math.cosh(x)" assert jscode(Max(x, y) + Min(x, y)) == "Math.max(x, y) + Math.min(x, y)" assert jscode(tanh(x)*acosh(y)) == "Math.tanh(x)*Math.acosh(y)" assert jscode(asin(x)-acos(y)) == "-Math.acos(y) + Math.asin(x)" def test_jscode_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert jscode(g(x)) == "2*x" g = implemented_function('g', Lambda(x, 2*x/Catalan)) assert jscode(g(x)) == "var Catalan = %s;\n2*x/Catalan" % Catalan.evalf(17) A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert jscode(g(A[i]), assign_to=A[i]) == ( "for (var i=0; i 1), (sin(x), x > 0)) raises(ValueError, lambda: jscode(expr)) def test_jscode_Piecewise_deep(): p = jscode(2*Piecewise((x, x < 1), (x**2, True))) s = \ """\ 2*((x < 1) ? ( x ) : ( Math.pow(x, 2) ))\ """ assert p == s def test_jscode_settings(): raises(TypeError, lambda: jscode(sin(x), method="garbage")) def test_jscode_Indexed(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o = symbols('n m o', integer=True) i, j, k = Idx('i', n), Idx('j', m), Idx('k', o) p = JavascriptCodePrinter() p._not_c = set() x = IndexedBase('x')[j] assert p._print_Indexed(x) == 'x[j]' A = IndexedBase('A')[i, j] assert p._print_Indexed(A) == 'A[%s]' % (m*i+j) B = IndexedBase('B')[i, j, k] assert p._print_Indexed(B) == 'B[%s]' % (i*o*m+j*o+k) assert p._not_c == set() def test_jscode_loops_matrix_vector(): n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) s = ( 'for (var i=0; i0), (y, True)), sin(z)]) A = MatrixSymbol('A', 3, 1) assert jscode(mat, A) == ( "A[0] = x*y;\n" "if (y > 0) {\n" " A[1] = x + 2;\n" "}\n" "else {\n" " A[1] = y;\n" "}\n" "A[2] = Math.sin(z);") # Test using MatrixElements in expressions expr = Piecewise((2*A[2, 0], x > 0), (A[2, 0], True)) + sin(A[1, 0]) + A[0, 0] assert jscode(expr) == ( "((x > 0) ? (\n" " 2*A[2]\n" ")\n" ": (\n" " A[2]\n" ")) + Math.sin(A[1]) + A[0]") # Test using MatrixElements in a Matrix q = MatrixSymbol('q', 5, 1) M = MatrixSymbol('M', 3, 3) m = Matrix([[sin(q[1,0]), 0, cos(q[2,0])], [q[1,0] + q[2,0], q[3, 0], 5], [2*q[4, 0]/q[1,0], sqrt(q[0,0]) + 4, 0]]) assert jscode(m, M) == ( "M[0] = Math.sin(q[1]);\n" "M[1] = 0;\n" "M[2] = Math.cos(q[2]);\n" "M[3] = q[1] + q[2];\n" "M[4] = q[3];\n" "M[5] = 5;\n" "M[6] = 2*q[4]/q[1];\n" "M[7] = Math.sqrt(q[0]) + 4;\n" "M[8] = 0;") def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert(jscode(A[0, 0]) == "A[0]") assert(jscode(3 * A[0, 0]) == "3*A[0]") F = C[0, 0].subs(C, A - B) assert(jscode(F) == "(A - B)[0]") sympy-sympy-1.9/sympy/printing/tests/test_julia.py000066400000000000000000000323151412543434000226210ustar00rootroot00000000000000from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer, Tuple, Symbol, Eq, Ne, Le, Lt, Gt, Ge) from sympy.core import EulerGamma, GoldenRatio, Catalan, Lambda, Mul, Pow from sympy.functions import Piecewise, sqrt, ceiling, exp, sin, cos from sympy.testing.pytest import raises from sympy.utilities.lambdify import implemented_function from sympy.matrices import (eye, Matrix, MatrixSymbol, Identity, HadamardProduct, SparseMatrix) from sympy.functions.special.bessel import (jn, yn, besselj, bessely, besseli, besselk, hankel1, hankel2, airyai, airybi, airyaiprime, airybiprime) from sympy.testing.pytest import XFAIL from sympy import julia_code x, y, z = symbols('x,y,z') def test_Integer(): assert julia_code(Integer(67)) == "67" assert julia_code(Integer(-1)) == "-1" def test_Rational(): assert julia_code(Rational(3, 7)) == "3/7" assert julia_code(Rational(18, 9)) == "2" assert julia_code(Rational(3, -7)) == "-3/7" assert julia_code(Rational(-3, -7)) == "3/7" assert julia_code(x + Rational(3, 7)) == "x + 3/7" assert julia_code(Rational(3, 7)*x) == "3*x/7" def test_Relational(): assert julia_code(Eq(x, y)) == "x == y" assert julia_code(Ne(x, y)) == "x != y" assert julia_code(Le(x, y)) == "x <= y" assert julia_code(Lt(x, y)) == "x < y" assert julia_code(Gt(x, y)) == "x > y" assert julia_code(Ge(x, y)) == "x >= y" def test_Function(): assert julia_code(sin(x) ** cos(x)) == "sin(x).^cos(x)" assert julia_code(abs(x)) == "abs(x)" assert julia_code(ceiling(x)) == "ceil(x)" def test_Pow(): assert julia_code(x**3) == "x.^3" assert julia_code(x**(y**3)) == "x.^(y.^3)" assert julia_code(x**Rational(2, 3)) == 'x.^(2/3)' g = implemented_function('g', Lambda(x, 2*x)) assert julia_code(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "(3.5*2*x).^(-x + y.^x)./(x.^2 + y)" # For issue 14160 assert julia_code(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False), evaluate=False)) == '-2*x./(y.*y)' def test_basic_ops(): assert julia_code(x*y) == "x.*y" assert julia_code(x + y) == "x + y" assert julia_code(x - y) == "x - y" assert julia_code(-x) == "-x" def test_1_over_x_and_sqrt(): # 1.0 and 0.5 would do something different in regular StrPrinter, # but these are exact in IEEE floating point so no different here. assert julia_code(1/x) == '1./x' assert julia_code(x**-1) == julia_code(x**-1.0) == '1./x' assert julia_code(1/sqrt(x)) == '1./sqrt(x)' assert julia_code(x**-S.Half) == julia_code(x**-0.5) == '1./sqrt(x)' assert julia_code(sqrt(x)) == 'sqrt(x)' assert julia_code(x**S.Half) == julia_code(x**0.5) == 'sqrt(x)' assert julia_code(1/pi) == '1/pi' assert julia_code(pi**-1) == julia_code(pi**-1.0) == '1/pi' assert julia_code(pi**-0.5) == '1/sqrt(pi)' def test_mix_number_mult_symbols(): assert julia_code(3*x) == "3*x" assert julia_code(pi*x) == "pi*x" assert julia_code(3/x) == "3./x" assert julia_code(pi/x) == "pi./x" assert julia_code(x/3) == "x/3" assert julia_code(x/pi) == "x/pi" assert julia_code(x*y) == "x.*y" assert julia_code(3*x*y) == "3*x.*y" assert julia_code(3*pi*x*y) == "3*pi*x.*y" assert julia_code(x/y) == "x./y" assert julia_code(3*x/y) == "3*x./y" assert julia_code(x*y/z) == "x.*y./z" assert julia_code(x/y*z) == "x.*z./y" assert julia_code(1/x/y) == "1./(x.*y)" assert julia_code(2*pi*x/y/z) == "2*pi*x./(y.*z)" assert julia_code(3*pi/x) == "3*pi./x" assert julia_code(S(3)/5) == "3/5" assert julia_code(S(3)/5*x) == "3*x/5" assert julia_code(x/y/z) == "x./(y.*z)" assert julia_code((x+y)/z) == "(x + y)./z" assert julia_code((x+y)/(z+x)) == "(x + y)./(x + z)" assert julia_code((x+y)/EulerGamma) == "(x + y)/eulergamma" assert julia_code(x/3/pi) == "x/(3*pi)" assert julia_code(S(3)/5*x*y/pi) == "3*x.*y/(5*pi)" def test_mix_number_pow_symbols(): assert julia_code(pi**3) == 'pi^3' assert julia_code(x**2) == 'x.^2' assert julia_code(x**(pi**3)) == 'x.^(pi^3)' assert julia_code(x**y) == 'x.^y' assert julia_code(x**(y**z)) == 'x.^(y.^z)' assert julia_code((x**y)**z) == '(x.^y).^z' def test_imag(): I = S('I') assert julia_code(I) == "im" assert julia_code(5*I) == "5im" assert julia_code((S(3)/2)*I) == "3*im/2" assert julia_code(3+4*I) == "3 + 4im" def test_constants(): assert julia_code(pi) == "pi" assert julia_code(oo) == "Inf" assert julia_code(-oo) == "-Inf" assert julia_code(S.NegativeInfinity) == "-Inf" assert julia_code(S.NaN) == "NaN" assert julia_code(S.Exp1) == "e" assert julia_code(exp(1)) == "e" def test_constants_other(): assert julia_code(2*GoldenRatio) == "2*golden" assert julia_code(2*Catalan) == "2*catalan" assert julia_code(2*EulerGamma) == "2*eulergamma" def test_boolean(): assert julia_code(x & y) == "x && y" assert julia_code(x | y) == "x || y" assert julia_code(~x) == "!x" assert julia_code(x & y & z) == "x && y && z" assert julia_code(x | y | z) == "x || y || z" assert julia_code((x & y) | z) == "z || x && y" assert julia_code((x | y) & z) == "z && (x || y)" def test_Matrices(): assert julia_code(Matrix(1, 1, [10])) == "[10]" A = Matrix([[1, sin(x/2), abs(x)], [0, 1, pi], [0, exp(1), ceiling(x)]]); expected = ("[1 sin(x/2) abs(x);\n" "0 1 pi;\n" "0 e ceil(x)]") assert julia_code(A) == expected # row and columns assert julia_code(A[:,0]) == "[1, 0, 0]" assert julia_code(A[0,:]) == "[1 sin(x/2) abs(x)]" # empty matrices assert julia_code(Matrix(0, 0, [])) == 'zeros(0, 0)' assert julia_code(Matrix(0, 3, [])) == 'zeros(0, 3)' # annoying to read but correct assert julia_code(Matrix([[x, x - y, -y]])) == "[x x - y -y]" def test_vector_entries_hadamard(): # For a row or column, user might to use the other dimension A = Matrix([[1, sin(2/x), 3*pi/x/5]]) assert julia_code(A) == "[1 sin(2./x) 3*pi./(5*x)]" assert julia_code(A.T) == "[1, sin(2./x), 3*pi./(5*x)]" @XFAIL def test_Matrices_entries_not_hadamard(): # For Matrix with col >= 2, row >= 2, they need to be scalars # FIXME: is it worth worrying about this? Its not wrong, just # leave it user's responsibility to put scalar data for x. A = Matrix([[1, sin(2/x), 3*pi/x/5], [1, 2, x*y]]) expected = ("[1 sin(2/x) 3*pi/(5*x);\n" "1 2 x*y]") # <- we give x.*y assert julia_code(A) == expected def test_MatrixSymbol(): n = Symbol('n', integer=True) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) assert julia_code(A*B) == "A*B" assert julia_code(B*A) == "B*A" assert julia_code(2*A*B) == "2*A*B" assert julia_code(B*2*A) == "2*B*A" assert julia_code(A*(B + 3*Identity(n))) == "A*(3*eye(n) + B)" assert julia_code(A**(x**2)) == "A^(x.^2)" assert julia_code(A**3) == "A^3" assert julia_code(A**S.Half) == "A^(1/2)" def test_special_matrices(): assert julia_code(6*Identity(3)) == "6*eye(3)" def test_containers(): assert julia_code([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \ "Any[1, 2, 3, Any[4, 5, Any[6, 7]], 8, Any[9, 10], 11]" assert julia_code((1, 2, (3, 4))) == "(1, 2, (3, 4))" assert julia_code([1]) == "Any[1]" assert julia_code((1,)) == "(1,)" assert julia_code(Tuple(*[1, 2, 3])) == "(1, 2, 3)" assert julia_code((1, x*y, (3, x**2))) == "(1, x.*y, (3, x.^2))" # scalar, matrix, empty matrix and empty list assert julia_code((1, eye(3), Matrix(0, 0, []), [])) == "(1, [1 0 0;\n0 1 0;\n0 0 1], zeros(0, 0), Any[])" def test_julia_noninline(): source = julia_code((x+y)/Catalan, assign_to='me', inline=False) expected = ( "const Catalan = %s\n" "me = (x + y)/Catalan" ) % Catalan.evalf(17) assert source == expected def test_julia_piecewise(): expr = Piecewise((x, x < 1), (x**2, True)) assert julia_code(expr) == "((x < 1) ? (x) : (x.^2))" assert julia_code(expr, assign_to="r") == ( "r = ((x < 1) ? (x) : (x.^2))") assert julia_code(expr, assign_to="r", inline=False) == ( "if (x < 1)\n" " r = x\n" "else\n" " r = x.^2\n" "end") expr = Piecewise((x**2, x < 1), (x**3, x < 2), (x**4, x < 3), (x**5, True)) expected = ("((x < 1) ? (x.^2) :\n" "(x < 2) ? (x.^3) :\n" "(x < 3) ? (x.^4) : (x.^5))") assert julia_code(expr) == expected assert julia_code(expr, assign_to="r") == "r = " + expected assert julia_code(expr, assign_to="r", inline=False) == ( "if (x < 1)\n" " r = x.^2\n" "elseif (x < 2)\n" " r = x.^3\n" "elseif (x < 3)\n" " r = x.^4\n" "else\n" " r = x.^5\n" "end") # Check that Piecewise without a True (default) condition error expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0)) raises(ValueError, lambda: julia_code(expr)) def test_julia_piecewise_times_const(): pw = Piecewise((x, x < 1), (x**2, True)) assert julia_code(2*pw) == "2*((x < 1) ? (x) : (x.^2))" assert julia_code(pw/x) == "((x < 1) ? (x) : (x.^2))./x" assert julia_code(pw/(x*y)) == "((x < 1) ? (x) : (x.^2))./(x.*y)" assert julia_code(pw/3) == "((x < 1) ? (x) : (x.^2))/3" def test_julia_matrix_assign_to(): A = Matrix([[1, 2, 3]]) assert julia_code(A, assign_to='a') == "a = [1 2 3]" A = Matrix([[1, 2], [3, 4]]) assert julia_code(A, assign_to='A') == "A = [1 2;\n3 4]" def test_julia_matrix_assign_to_more(): # assigning to Symbol or MatrixSymbol requires lhs/rhs match A = Matrix([[1, 2, 3]]) B = MatrixSymbol('B', 1, 3) C = MatrixSymbol('C', 2, 3) assert julia_code(A, assign_to=B) == "B = [1 2 3]" raises(ValueError, lambda: julia_code(A, assign_to=x)) raises(ValueError, lambda: julia_code(A, assign_to=C)) def test_julia_matrix_1x1(): A = Matrix([[3]]) B = MatrixSymbol('B', 1, 1) C = MatrixSymbol('C', 1, 2) assert julia_code(A, assign_to=B) == "B = [3]" # FIXME? #assert julia_code(A, assign_to=x) == "x = [3]" raises(ValueError, lambda: julia_code(A, assign_to=C)) def test_julia_matrix_elements(): A = Matrix([[x, 2, x*y]]) assert julia_code(A[0, 0]**2 + A[0, 1] + A[0, 2]) == "x.^2 + x.*y + 2" A = MatrixSymbol('AA', 1, 3) assert julia_code(A) == "AA" assert julia_code(A[0, 0]**2 + sin(A[0,1]) + A[0,2]) == \ "sin(AA[1,2]) + AA[1,1].^2 + AA[1,3]" assert julia_code(sum(A)) == "AA[1,1] + AA[1,2] + AA[1,3]" def test_julia_boolean(): assert julia_code(True) == "true" assert julia_code(S.true) == "true" assert julia_code(False) == "false" assert julia_code(S.false) == "false" def test_julia_not_supported(): assert julia_code(S.ComplexInfinity) == ( "# Not supported in Julia:\n" "# ComplexInfinity\n" "zoo" ) f = Function('f') assert julia_code(f(x).diff(x)) == ( "# Not supported in Julia:\n" "# Derivative\n" "Derivative(f(x), x)" ) def test_trick_indent_with_end_else_words(): # words starting with "end" or "else" do not confuse the indenter t1 = S('endless'); t2 = S('elsewhere'); pw = Piecewise((t1, x < 0), (t2, x <= 1), (1, True)) assert julia_code(pw, inline=False) == ( "if (x < 0)\n" " endless\n" "elseif (x <= 1)\n" " elsewhere\n" "else\n" " 1\n" "end") def test_haramard(): A = MatrixSymbol('A', 3, 3) B = MatrixSymbol('B', 3, 3) v = MatrixSymbol('v', 3, 1) h = MatrixSymbol('h', 1, 3) C = HadamardProduct(A, B) assert julia_code(C) == "A.*B" assert julia_code(C*v) == "(A.*B)*v" assert julia_code(h*C*v) == "h*(A.*B)*v" assert julia_code(C*A) == "(A.*B)*A" # mixing Hadamard and scalar strange b/c we vectorize scalars assert julia_code(C*x*y) == "(x.*y)*(A.*B)" def test_sparse(): M = SparseMatrix(5, 6, {}) M[2, 2] = 10; M[1, 2] = 20; M[1, 3] = 22; M[0, 3] = 30; M[3, 0] = x*y; assert julia_code(M) == ( "sparse([4, 2, 3, 1, 2], [1, 3, 3, 4, 4], [x.*y, 20, 10, 30, 22], 5, 6)" ) def test_specfun(): n = Symbol('n') for f in [besselj, bessely, besseli, besselk]: assert julia_code(f(n, x)) == f.__name__ + '(n, x)' for f in [airyai, airyaiprime, airybi, airybiprime]: assert julia_code(f(x)) == f.__name__ + '(x)' assert julia_code(hankel1(n, x)) == 'hankelh1(n, x)' assert julia_code(hankel2(n, x)) == 'hankelh2(n, x)' assert julia_code(jn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*besselj(n + 1/2, x)/2' assert julia_code(yn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*bessely(n + 1/2, x)/2' def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert(julia_code(A[0, 0]) == "A[1,1]") assert(julia_code(3 * A[0, 0]) == "3*A[1,1]") F = C[0, 0].subs(C, A - B) assert(julia_code(F) == "(A - B)[1,1]") sympy-sympy-1.9/sympy/printing/tests/test_lambdarepr.py000066400000000000000000000146201412543434000236250ustar00rootroot00000000000000from sympy import symbols, sin, Matrix, Interval, Piecewise, Sum, lambdify, \ Expr, sqrt from sympy.testing.pytest import raises from sympy.printing.tensorflow import TensorflowPrinter from sympy.printing.lambdarepr import lambdarepr, LambdaPrinter, NumExprPrinter x, y, z = symbols("x,y,z") i, a, b = symbols("i,a,b") j, c, d = symbols("j,c,d") def test_basic(): assert lambdarepr(x*y) == "x*y" assert lambdarepr(x + y) in ["y + x", "x + y"] assert lambdarepr(x**y) == "x**y" def test_matrix(): A = Matrix([[x, y], [y*x, z**2]]) # assert lambdarepr(A) == "ImmutableDenseMatrix([[x, y], [x*y, z**2]])" # Test printing a Matrix that has an element that is printed differently # with the LambdaPrinter than in the StrPrinter. p = Piecewise((x, True), evaluate=False) A = Matrix([p]) assert lambdarepr(A) == "ImmutableDenseMatrix([[((x))]])" def test_piecewise(): # In each case, test eval() the lambdarepr() to make sure there are a # correct number of parentheses. It will give a SyntaxError if there aren't. h = "lambda x: " p = Piecewise((x, True), evaluate=False) l = lambdarepr(p) eval(h + l) assert l == "((x))" p = Piecewise((x, x < 0)) l = lambdarepr(p) eval(h + l) assert l == "((x) if (x < 0) else None)" p = Piecewise( (1, x < 1), (2, x < 2), (0, True) ) l = lambdarepr(p) eval(h + l) assert l == "((1) if (x < 1) else (2) if (x < 2) else (0))" p = Piecewise( (1, x < 1), (2, x < 2), ) l = lambdarepr(p) eval(h + l) assert l == "((1) if (x < 1) else (2) if (x < 2) else None)" p = Piecewise( (x, x < 1), (x**2, Interval(3, 4, True, False).contains(x)), (0, True), ) l = lambdarepr(p) eval(h + l) assert l == "((x) if (x < 1) else (x**2) if (((x <= 4)) and ((x > 3))) else (0))" p = Piecewise( (x**2, x < 0), (x, x < 1), (2 - x, x >= 1), (0, True), evaluate=False ) l = lambdarepr(p) eval(h + l) assert l == "((x**2) if (x < 0) else (x) if (x < 1)"\ " else (2 - x) if (x >= 1) else (0))" p = Piecewise( (x**2, x < 0), (x, x < 1), (2 - x, x >= 1), evaluate=False ) l = lambdarepr(p) eval(h + l) assert l == "((x**2) if (x < 0) else (x) if (x < 1)"\ " else (2 - x) if (x >= 1) else None)" p = Piecewise( (1, x >= 1), (2, x >= 2), (3, x >= 3), (4, x >= 4), (5, x >= 5), (6, True) ) l = lambdarepr(p) eval(h + l) assert l == "((1) if (x >= 1) else (2) if (x >= 2) else (3) if (x >= 3)"\ " else (4) if (x >= 4) else (5) if (x >= 5) else (6))" p = Piecewise( (1, x <= 1), (2, x <= 2), (3, x <= 3), (4, x <= 4), (5, x <= 5), (6, True) ) l = lambdarepr(p) eval(h + l) assert l == "((1) if (x <= 1) else (2) if (x <= 2) else (3) if (x <= 3)"\ " else (4) if (x <= 4) else (5) if (x <= 5) else (6))" p = Piecewise( (1, x > 1), (2, x > 2), (3, x > 3), (4, x > 4), (5, x > 5), (6, True) ) l = lambdarepr(p) eval(h + l) assert l =="((1) if (x > 1) else (2) if (x > 2) else (3) if (x > 3)"\ " else (4) if (x > 4) else (5) if (x > 5) else (6))" p = Piecewise( (1, x < 1), (2, x < 2), (3, x < 3), (4, x < 4), (5, x < 5), (6, True) ) l = lambdarepr(p) eval(h + l) assert l == "((1) if (x < 1) else (2) if (x < 2) else (3) if (x < 3)"\ " else (4) if (x < 4) else (5) if (x < 5) else (6))" p = Piecewise( (Piecewise( (1, x > 0), (2, True) ), y > 0), (3, True) ) l = lambdarepr(p) eval(h + l) assert l == "((((1) if (x > 0) else (2))) if (y > 0) else (3))" def test_sum__1(): # In each case, test eval() the lambdarepr() to make sure that # it evaluates to the same results as the symbolic expression s = Sum(x ** i, (i, a, b)) l = lambdarepr(s) assert l == "(builtins.sum(x**i for i in range(a, b+1)))" args = x, a, b f = lambdify(args, s) v = 2, 3, 8 assert f(*v) == s.subs(zip(args, v)).doit() def test_sum__2(): s = Sum(i * x, (i, a, b)) l = lambdarepr(s) assert l == "(builtins.sum(i*x for i in range(a, b+1)))" args = x, a, b f = lambdify(args, s) v = 2, 3, 8 assert f(*v) == s.subs(zip(args, v)).doit() def test_multiple_sums(): s = Sum(i * x + j, (i, a, b), (j, c, d)) l = lambdarepr(s) assert l == "(builtins.sum(i*x + j for i in range(a, b+1) for j in range(c, d+1)))" args = x, a, b, c, d f = lambdify(args, s) vals = 2, 3, 4, 5, 6 f_ref = s.subs(zip(args, vals)).doit() f_res = f(*vals) assert f_res == f_ref def test_sqrt(): prntr = LambdaPrinter({'standard' : 'python2'}) assert prntr._print_Pow(sqrt(x), rational=False) == 'sqrt(x)' assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1./2.)' prntr = LambdaPrinter({'standard' : 'python3'}) assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)' def test_settings(): raises(TypeError, lambda: lambdarepr(sin(x), method="garbage")) def test_numexpr(): # test ITE rewrite as Piecewise from sympy.logic.boolalg import ITE expr = ITE(x > 0, True, False, evaluate=False) assert NumExprPrinter().doprint(expr) == \ "evaluate('where((x > 0), True, False)', truediv=True)" class CustomPrintedObject(Expr): def _lambdacode(self, printer): return 'lambda' def _tensorflowcode(self, printer): return 'tensorflow' def _numpycode(self, printer): return 'numpy' def _numexprcode(self, printer): return 'numexpr' def _mpmathcode(self, printer): return 'mpmath' def test_printmethod(): # In each case, printmethod is called to test # its working obj = CustomPrintedObject() assert LambdaPrinter().doprint(obj) == 'lambda' assert TensorflowPrinter().doprint(obj) == 'tensorflow' assert NumExprPrinter().doprint(obj) == "evaluate('numexpr', truediv=True)" assert NumExprPrinter().doprint(Piecewise((y, x >= 0), (z, x < 0))) == \ "evaluate('where((x >= 0), y, z)', truediv=True)" sympy-sympy-1.9/sympy/printing/tests/test_latex.py000066400000000000000000003440131412543434000226330ustar00rootroot00000000000000from sympy.tensor.array.expressions.array_expressions import ArraySymbol, ArrayElement from sympy.tensor.toperators import PartialDerivative from sympy import ( Abs, Chi, Ci, CosineTransform, Dict, Ei, Eq, FallingFactorial, FiniteSet, Float, FourierTransform, Function, Indexed, IndexedBase, Integral, Interval, InverseCosineTransform, InverseFourierTransform, Derivative, InverseLaplaceTransform, InverseMellinTransform, InverseSineTransform, Lambda, LaplaceTransform, Limit, Matrix, Max, MellinTransform, Min, Mul, Order, Piecewise, Poly, ring, field, ZZ, Pow, Product, Range, Rational, Integer, RisingFactorial, rootof, RootSum, S, Shi, Si, SineTransform, Subs, Sum, Symbol, ImageSet, Tuple, Ynm, Znm, arg, asin, acsc, asinh, Mod, assoc_laguerre, assoc_legendre, beta, binomial, catalan, ceiling, chebyshevt, chebyshevu, conjugate, cot, coth, diff, dirichlet_eta, euler, exp, expint, factorial, factorial2, floor, gamma, gegenbauer, hermite, hyper, im, jacobi, laguerre, legendre, lerchphi, log, frac, meijerg, oo, polar_lift, polylog, re, root, sin, sqrt, symbols, uppergamma, zeta, subfactorial, totient, elliptic_k, elliptic_f, elliptic_e, elliptic_pi, cos, tan, Wild, true, false, Equivalent, Not, Contains, divisor_sigma, SeqPer, SeqFormula, MatrixSlice, SeqAdd, SeqMul, fourier_series, pi, ConditionSet, ComplexRegion, fps, AccumBounds, reduced_totient, primenu, primeomega, SingularityFunction, stieltjes, mathieuc, mathieus, mathieucprime, mathieusprime, UnevaluatedExpr, Quaternion, I, KroneckerProduct, LambertW) from sympy.ntheory.factor_ import udivisor_sigma from sympy.abc import mu, tau from sympy.printing.latex import (latex, translate, greek_letters_set, tex_greek_dictionary, multiline_latex, latex_escape, LatexPrinter) from sympy.tensor.array import (ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableSparseNDimArray, MutableDenseNDimArray, tensorproduct) from sympy.testing.pytest import XFAIL, raises, _both_exp_pow from sympy.functions import DiracDelta, Heaviside, KroneckerDelta, LeviCivita from sympy.functions.combinatorial.numbers import bernoulli, bell, lucas, \ fibonacci, tribonacci from sympy.logic import Implies from sympy.logic.boolalg import And, Or, Xor from sympy.physics.control.lti import TransferFunction, Series, Parallel, \ Feedback, TransferFunctionMatrix, MIMOSeries, MIMOParallel, MIMOFeedback from sympy.physics.quantum import Commutator, Operator from sympy.physics.units import meter, gibibyte, microgram, second from sympy.core.trace import Tr from sympy.combinatorics.permutations import \ Cycle, Permutation, AppliedPermutation from sympy.matrices.expressions.permutation import PermutationMatrix from sympy import MatrixSymbol, ln from sympy.vector import CoordSys3D, Cross, Curl, Dot, Divergence, Gradient, Laplacian from sympy.sets.setexpr import SetExpr from sympy.sets.sets import \ Union, Intersection, Complement, SymmetricDifference, ProductSet import sympy as sym class lowergamma(sym.lowergamma): pass # testing notation inheritance by a subclass with same name x, y, z, t, w, a, b, c, s, p = symbols('x y z t w a b c s p') k, m, n = symbols('k m n', integer=True) def test_printmethod(): class R(Abs): def _latex(self, printer): return "foo(%s)" % printer._print(self.args[0]) assert latex(R(x)) == r"foo(x)" class R(Abs): def _latex(self, printer): return "foo" assert latex(R(x)) == r"foo" def test_latex_basic(): assert latex(1 + x) == r"x + 1" assert latex(x**2) == r"x^{2}" assert latex(x**(1 + x)) == r"x^{x + 1}" assert latex(x**3 + x + 1 + x**2) == r"x^{3} + x^{2} + x + 1" assert latex(2*x*y) == r"2 x y" assert latex(2*x*y, mul_symbol='dot') == r"2 \cdot x \cdot y" assert latex(3*x**2*y, mul_symbol='\\,') == r"3\,x^{2}\,y" assert latex(1.5*3**x, mul_symbol='\\,') == r"1.5 \cdot 3^{x}" assert latex(Mul(0, 1, evaluate=False)) == r'0 \cdot 1' assert latex(Mul(1, 0, evaluate=False)) == r'1 \cdot 0' assert latex(Mul(1, 1, evaluate=False)) == r'1 \cdot 1' assert latex(Mul(-1, 1, evaluate=False)) == r'\left(-1\right) 1' assert latex(Mul(1, 1, 1, evaluate=False)) == r'1 \cdot 1 \cdot 1' assert latex(Mul(1, 2, evaluate=False)) == r'1 \cdot 2' assert latex(Mul(1, S.Half, evaluate=False)) == r'1 \frac{1}{2}' assert latex(Mul(1, 1, S.Half, evaluate=False)) == \ r'1 \cdot 1 \frac{1}{2}' assert latex(Mul(1, 1, 2, 3, x, evaluate=False)) == \ r'1 \cdot 1 \cdot 2 \cdot 3 x' assert latex(Mul(1, -1, evaluate=False)) == r'1 \left(-1\right)' assert latex(Mul(4, 3, 2, 1, 0, y, x, evaluate=False)) == \ r'4 \cdot 3 \cdot 2 \cdot 1 \cdot 0 y x' assert latex(Mul(4, 3, 2, 1+z, 0, y, x, evaluate=False)) == \ r'4 \cdot 3 \cdot 2 \left(z + 1\right) 0 y x' assert latex(Mul(Rational(2, 3), Rational(5, 7), evaluate=False)) == \ r'\frac{2}{3} \frac{5}{7}' assert latex(1/x) == r"\frac{1}{x}" assert latex(1/x, fold_short_frac=True) == r"1 / x" assert latex(-S(3)/2) == r"- \frac{3}{2}" assert latex(-S(3)/2, fold_short_frac=True) == r"- 3 / 2" assert latex(1/x**2) == r"\frac{1}{x^{2}}" assert latex(1/(x + y)/2) == r"\frac{1}{2 \left(x + y\right)}" assert latex(x/2) == r"\frac{x}{2}" assert latex(x/2, fold_short_frac=True) == r"x / 2" assert latex((x + y)/(2*x)) == r"\frac{x + y}{2 x}" assert latex((x + y)/(2*x), fold_short_frac=True) == \ r"\left(x + y\right) / 2 x" assert latex((x + y)/(2*x), long_frac_ratio=0) == \ r"\frac{1}{2 x} \left(x + y\right)" assert latex((x + y)/x) == r"\frac{x + y}{x}" assert latex((x + y)/x, long_frac_ratio=3) == r"\frac{x + y}{x}" assert latex((2*sqrt(2)*x)/3) == r"\frac{2 \sqrt{2} x}{3}" assert latex((2*sqrt(2)*x)/3, long_frac_ratio=2) == \ r"\frac{2 x}{3} \sqrt{2}" assert latex(binomial(x, y)) == r"{\binom{x}{y}}" x_star = Symbol('x^*') f = Function('f') assert latex(x_star**2) == r"\left(x^{*}\right)^{2}" assert latex(x_star**2, parenthesize_super=False) == r"{x^{*}}^{2}" assert latex(Derivative(f(x_star), x_star,2)) == r"\frac{d^{2}}{d \left(x^{*}\right)^{2}} f{\left(x^{*} \right)}" assert latex(Derivative(f(x_star), x_star,2), parenthesize_super=False) == r"\frac{d^{2}}{d {x^{*}}^{2}} f{\left(x^{*} \right)}" assert latex(2*Integral(x, x)/3) == r"\frac{2 \int x\, dx}{3}" assert latex(2*Integral(x, x)/3, fold_short_frac=True) == \ r"\left(2 \int x\, dx\right) / 3" assert latex(sqrt(x)) == r"\sqrt{x}" assert latex(x**Rational(1, 3)) == r"\sqrt[3]{x}" assert latex(x**Rational(1, 3), root_notation=False) == r"x^{\frac{1}{3}}" assert latex(sqrt(x)**3) == r"x^{\frac{3}{2}}" assert latex(sqrt(x), itex=True) == r"\sqrt{x}" assert latex(x**Rational(1, 3), itex=True) == r"\root{3}{x}" assert latex(sqrt(x)**3, itex=True) == r"x^{\frac{3}{2}}" assert latex(x**Rational(3, 4)) == r"x^{\frac{3}{4}}" assert latex(x**Rational(3, 4), fold_frac_powers=True) == r"x^{3/4}" assert latex((x + 1)**Rational(3, 4)) == \ r"\left(x + 1\right)^{\frac{3}{4}}" assert latex((x + 1)**Rational(3, 4), fold_frac_powers=True) == \ r"\left(x + 1\right)^{3/4}" assert latex(1.5e20*x) == r"1.5 \cdot 10^{20} x" assert latex(1.5e20*x, mul_symbol='dot') == r"1.5 \cdot 10^{20} \cdot x" assert latex(1.5e20*x, mul_symbol='times') == \ r"1.5 \times 10^{20} \times x" assert latex(1/sin(x)) == r"\frac{1}{\sin{\left(x \right)}}" assert latex(sin(x)**-1) == r"\frac{1}{\sin{\left(x \right)}}" assert latex(sin(x)**Rational(3, 2)) == \ r"\sin^{\frac{3}{2}}{\left(x \right)}" assert latex(sin(x)**Rational(3, 2), fold_frac_powers=True) == \ r"\sin^{3/2}{\left(x \right)}" assert latex(~x) == r"\neg x" assert latex(x & y) == r"x \wedge y" assert latex(x & y & z) == r"x \wedge y \wedge z" assert latex(x | y) == r"x \vee y" assert latex(x | y | z) == r"x \vee y \vee z" assert latex((x & y) | z) == r"z \vee \left(x \wedge y\right)" assert latex(Implies(x, y)) == r"x \Rightarrow y" assert latex(~(x >> ~y)) == r"x \not\Rightarrow \neg y" assert latex(Implies(Or(x,y), z)) == r"\left(x \vee y\right) \Rightarrow z" assert latex(Implies(z, Or(x,y))) == r"z \Rightarrow \left(x \vee y\right)" assert latex(~(x & y)) == r"\neg \left(x \wedge y\right)" assert latex(~x, symbol_names={x: "x_i"}) == r"\neg x_i" assert latex(x & y, symbol_names={x: "x_i", y: "y_i"}) == \ r"x_i \wedge y_i" assert latex(x & y & z, symbol_names={x: "x_i", y: "y_i", z: "z_i"}) == \ r"x_i \wedge y_i \wedge z_i" assert latex(x | y, symbol_names={x: "x_i", y: "y_i"}) == r"x_i \vee y_i" assert latex(x | y | z, symbol_names={x: "x_i", y: "y_i", z: "z_i"}) == \ r"x_i \vee y_i \vee z_i" assert latex((x & y) | z, symbol_names={x: "x_i", y: "y_i", z: "z_i"}) == \ r"z_i \vee \left(x_i \wedge y_i\right)" assert latex(Implies(x, y), symbol_names={x: "x_i", y: "y_i"}) == \ r"x_i \Rightarrow y_i" assert latex(Pow(Rational(1, 3), -1, evaluate=False)) == r"\frac{1}{\frac{1}{3}}" assert latex(Pow(Rational(1, 3), -2, evaluate=False)) == r"\frac{1}{(\frac{1}{3})^{2}}" assert latex(Pow(Integer(1)/100, -1, evaluate=False)) == r"\frac{1}{\frac{1}{100}}" p = Symbol('p', positive=True) assert latex(exp(-p)*log(p)) == r"e^{- p} \log{\left(p \right)}" def test_latex_builtins(): assert latex(True) == r"\text{True}" assert latex(False) == r"\text{False}" assert latex(None) == r"\text{None}" assert latex(true) == r"\text{True}" assert latex(false) == r'\text{False}' def test_latex_SingularityFunction(): assert latex(SingularityFunction(x, 4, 5)) == \ r"{\left\langle x - 4 \right\rangle}^{5}" assert latex(SingularityFunction(x, -3, 4)) == \ r"{\left\langle x + 3 \right\rangle}^{4}" assert latex(SingularityFunction(x, 0, 4)) == \ r"{\left\langle x \right\rangle}^{4}" assert latex(SingularityFunction(x, a, n)) == \ r"{\left\langle - a + x \right\rangle}^{n}" assert latex(SingularityFunction(x, 4, -2)) == \ r"{\left\langle x - 4 \right\rangle}^{-2}" assert latex(SingularityFunction(x, 4, -1)) == \ r"{\left\langle x - 4 \right\rangle}^{-1}" assert latex(SingularityFunction(x, 4, 5)**3) == \ r"{\left({\langle x - 4 \rangle}^{5}\right)}^{3}" assert latex(SingularityFunction(x, -3, 4)**3) == \ r"{\left({\langle x + 3 \rangle}^{4}\right)}^{3}" assert latex(SingularityFunction(x, 0, 4)**3) == \ r"{\left({\langle x \rangle}^{4}\right)}^{3}" assert latex(SingularityFunction(x, a, n)**3) == \ r"{\left({\langle - a + x \rangle}^{n}\right)}^{3}" assert latex(SingularityFunction(x, 4, -2)**3) == \ r"{\left({\langle x - 4 \rangle}^{-2}\right)}^{3}" assert latex((SingularityFunction(x, 4, -1)**3)**3) == \ r"{\left({\langle x - 4 \rangle}^{-1}\right)}^{9}" def test_latex_cycle(): assert latex(Cycle(1, 2, 4)) == r"\left( 1\; 2\; 4\right)" assert latex(Cycle(1, 2)(4, 5, 6)) == \ r"\left( 1\; 2\right)\left( 4\; 5\; 6\right)" assert latex(Cycle()) == r"\left( \right)" def test_latex_permutation(): assert latex(Permutation(1, 2, 4)) == r"\left( 1\; 2\; 4\right)" assert latex(Permutation(1, 2)(4, 5, 6)) == \ r"\left( 1\; 2\right)\left( 4\; 5\; 6\right)" assert latex(Permutation()) == r"\left( \right)" assert latex(Permutation(2, 4)*Permutation(5)) == \ r"\left( 2\; 4\right)\left( 5\right)" assert latex(Permutation(5)) == r"\left( 5\right)" assert latex(Permutation(0, 1), perm_cyclic=False) == \ r"\begin{pmatrix} 0 & 1 \\ 1 & 0 \end{pmatrix}" assert latex(Permutation(0, 1)(2, 3), perm_cyclic=False) == \ r"\begin{pmatrix} 0 & 1 & 2 & 3 \\ 1 & 0 & 3 & 2 \end{pmatrix}" assert latex(Permutation(), perm_cyclic=False) == \ r"\left( \right)" def test_latex_Float(): assert latex(Float(1.0e100)) == r"1.0 \cdot 10^{100}" assert latex(Float(1.0e-100)) == r"1.0 \cdot 10^{-100}" assert latex(Float(1.0e-100), mul_symbol="times") == \ r"1.0 \times 10^{-100}" assert latex(Float('10000.0'), full_prec=False, min=-2, max=2) == \ r"1.0 \cdot 10^{4}" assert latex(Float('10000.0'), full_prec=False, min=-2, max=4) == \ r"1.0 \cdot 10^{4}" assert latex(Float('10000.0'), full_prec=False, min=-2, max=5) == \ r"10000.0" assert latex(Float('0.099999'), full_prec=True, min=-2, max=5) == \ r"9.99990000000000 \cdot 10^{-2}" def test_latex_vector_expressions(): A = CoordSys3D('A') assert latex(Cross(A.i, A.j*A.x*3+A.k)) == \ r"\mathbf{\hat{i}_{A}} \times \left((3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}} + \mathbf{\hat{k}_{A}}\right)" assert latex(Cross(A.i, A.j)) == \ r"\mathbf{\hat{i}_{A}} \times \mathbf{\hat{j}_{A}}" assert latex(x*Cross(A.i, A.j)) == \ r"x \left(\mathbf{\hat{i}_{A}} \times \mathbf{\hat{j}_{A}}\right)" assert latex(Cross(x*A.i, A.j)) == \ r'- \mathbf{\hat{j}_{A}} \times \left((x)\mathbf{\hat{i}_{A}}\right)' assert latex(Curl(3*A.x*A.j)) == \ r"\nabla\times \left((3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}}\right)" assert latex(Curl(3*A.x*A.j+A.i)) == \ r"\nabla\times \left(\mathbf{\hat{i}_{A}} + (3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}}\right)" assert latex(Curl(3*x*A.x*A.j)) == \ r"\nabla\times \left((3 \mathbf{{x}_{A}} x)\mathbf{\hat{j}_{A}}\right)" assert latex(x*Curl(3*A.x*A.j)) == \ r"x \left(\nabla\times \left((3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}}\right)\right)" assert latex(Divergence(3*A.x*A.j+A.i)) == \ r"\nabla\cdot \left(\mathbf{\hat{i}_{A}} + (3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}}\right)" assert latex(Divergence(3*A.x*A.j)) == \ r"\nabla\cdot \left((3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}}\right)" assert latex(x*Divergence(3*A.x*A.j)) == \ r"x \left(\nabla\cdot \left((3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}}\right)\right)" assert latex(Dot(A.i, A.j*A.x*3+A.k)) == \ r"\mathbf{\hat{i}_{A}} \cdot \left((3 \mathbf{{x}_{A}})\mathbf{\hat{j}_{A}} + \mathbf{\hat{k}_{A}}\right)" assert latex(Dot(A.i, A.j)) == \ r"\mathbf{\hat{i}_{A}} \cdot \mathbf{\hat{j}_{A}}" assert latex(Dot(x*A.i, A.j)) == \ r"\mathbf{\hat{j}_{A}} \cdot \left((x)\mathbf{\hat{i}_{A}}\right)" assert latex(x*Dot(A.i, A.j)) == \ r"x \left(\mathbf{\hat{i}_{A}} \cdot \mathbf{\hat{j}_{A}}\right)" assert latex(Gradient(A.x)) == r"\nabla \mathbf{{x}_{A}}" assert latex(Gradient(A.x + 3*A.y)) == \ r"\nabla \left(\mathbf{{x}_{A}} + 3 \mathbf{{y}_{A}}\right)" assert latex(x*Gradient(A.x)) == r"x \left(\nabla \mathbf{{x}_{A}}\right)" assert latex(Gradient(x*A.x)) == r"\nabla \left(\mathbf{{x}_{A}} x\right)" assert latex(Laplacian(A.x)) == r"\triangle \mathbf{{x}_{A}}" assert latex(Laplacian(A.x + 3*A.y)) == \ r"\triangle \left(\mathbf{{x}_{A}} + 3 \mathbf{{y}_{A}}\right)" assert latex(x*Laplacian(A.x)) == r"x \left(\triangle \mathbf{{x}_{A}}\right)" assert latex(Laplacian(x*A.x)) == r"\triangle \left(\mathbf{{x}_{A}} x\right)" def test_latex_symbols(): Gamma, lmbda, rho = symbols('Gamma, lambda, rho') tau, Tau, TAU, taU = symbols('tau, Tau, TAU, taU') assert latex(tau) == r"\tau" assert latex(Tau) == r"T" assert latex(TAU) == r"\tau" assert latex(taU) == r"\tau" # Check that all capitalized greek letters are handled explicitly capitalized_letters = {l.capitalize() for l in greek_letters_set} assert len(capitalized_letters - set(tex_greek_dictionary.keys())) == 0 assert latex(Gamma + lmbda) == r"\Gamma + \lambda" assert latex(Gamma * lmbda) == r"\Gamma \lambda" assert latex(Symbol('q1')) == r"q_{1}" assert latex(Symbol('q21')) == r"q_{21}" assert latex(Symbol('epsilon0')) == r"\epsilon_{0}" assert latex(Symbol('omega1')) == r"\omega_{1}" assert latex(Symbol('91')) == r"91" assert latex(Symbol('alpha_new')) == r"\alpha_{new}" assert latex(Symbol('C^orig')) == r"C^{orig}" assert latex(Symbol('x^alpha')) == r"x^{\alpha}" assert latex(Symbol('beta^alpha')) == r"\beta^{\alpha}" assert latex(Symbol('e^Alpha')) == r"e^{A}" assert latex(Symbol('omega_alpha^beta')) == r"\omega^{\beta}_{\alpha}" assert latex(Symbol('omega') ** Symbol('beta')) == r"\omega^{\beta}" @XFAIL def test_latex_symbols_failing(): rho, mass, volume = symbols('rho, mass, volume') assert latex( volume * rho == mass) == r"\rho \mathrm{volume} = \mathrm{mass}" assert latex(volume / mass * rho == 1) == \ r"\rho \mathrm{volume} {\mathrm{mass}}^{(-1)} = 1" assert latex(mass**3 * volume**3) == \ r"{\mathrm{mass}}^{3} \cdot {\mathrm{volume}}^{3}" @_both_exp_pow def test_latex_functions(): assert latex(exp(x)) == r"e^{x}" assert latex(exp(1) + exp(2)) == r"e + e^{2}" f = Function('f') assert latex(f(x)) == r'f{\left(x \right)}' assert latex(f) == r'f' g = Function('g') assert latex(g(x, y)) == r'g{\left(x,y \right)}' assert latex(g) == r'g' h = Function('h') assert latex(h(x, y, z)) == r'h{\left(x,y,z \right)}' assert latex(h) == r'h' Li = Function('Li') assert latex(Li) == r'\operatorname{Li}' assert latex(Li(x)) == r'\operatorname{Li}{\left(x \right)}' mybeta = Function('beta') # not to be confused with the beta function assert latex(mybeta(x, y, z)) == r"\beta{\left(x,y,z \right)}" assert latex(beta(x, y)) == r'\operatorname{B}\left(x, y\right)' assert latex(beta(x, y)**2) == r'\operatorname{B}^{2}\left(x, y\right)' assert latex(mybeta(x)) == r"\beta{\left(x \right)}" assert latex(mybeta) == r"\beta" g = Function('gamma') # not to be confused with the gamma function assert latex(g(x, y, z)) == r"\gamma{\left(x,y,z \right)}" assert latex(g(x)) == r"\gamma{\left(x \right)}" assert latex(g) == r"\gamma" a1 = Function('a_1') assert latex(a1) == r"\operatorname{a_{1}}" assert latex(a1(x)) == r"\operatorname{a_{1}}{\left(x \right)}" # issue 5868 omega1 = Function('omega1') assert latex(omega1) == r"\omega_{1}" assert latex(omega1(x)) == r"\omega_{1}{\left(x \right)}" assert latex(sin(x)) == r"\sin{\left(x \right)}" assert latex(sin(x), fold_func_brackets=True) == r"\sin {x}" assert latex(sin(2*x**2), fold_func_brackets=True) == \ r"\sin {2 x^{2}}" assert latex(sin(x**2), fold_func_brackets=True) == \ r"\sin {x^{2}}" assert latex(asin(x)**2) == r"\operatorname{asin}^{2}{\left(x \right)}" assert latex(asin(x)**2, inv_trig_style="full") == \ r"\arcsin^{2}{\left(x \right)}" assert latex(asin(x)**2, inv_trig_style="power") == \ r"\sin^{-1}{\left(x \right)}^{2}" assert latex(asin(x**2), inv_trig_style="power", fold_func_brackets=True) == \ r"\sin^{-1} {x^{2}}" assert latex(acsc(x), inv_trig_style="full") == \ r"\operatorname{arccsc}{\left(x \right)}" assert latex(asinh(x), inv_trig_style="full") == \ r"\operatorname{arcsinh}{\left(x \right)}" assert latex(factorial(k)) == r"k!" assert latex(factorial(-k)) == r"\left(- k\right)!" assert latex(factorial(k)**2) == r"k!^{2}" assert latex(subfactorial(k)) == r"!k" assert latex(subfactorial(-k)) == r"!\left(- k\right)" assert latex(subfactorial(k)**2) == r"\left(!k\right)^{2}" assert latex(factorial2(k)) == r"k!!" assert latex(factorial2(-k)) == r"\left(- k\right)!!" assert latex(factorial2(k)**2) == r"k!!^{2}" assert latex(binomial(2, k)) == r"{\binom{2}{k}}" assert latex(binomial(2, k)**2) == r"{\binom{2}{k}}^{2}" assert latex(FallingFactorial(3, k)) == r"{\left(3\right)}_{k}" assert latex(RisingFactorial(3, k)) == r"{3}^{\left(k\right)}" assert latex(floor(x)) == r"\left\lfloor{x}\right\rfloor" assert latex(ceiling(x)) == r"\left\lceil{x}\right\rceil" assert latex(frac(x)) == r"\operatorname{frac}{\left(x\right)}" assert latex(floor(x)**2) == r"\left\lfloor{x}\right\rfloor^{2}" assert latex(ceiling(x)**2) == r"\left\lceil{x}\right\rceil^{2}" assert latex(frac(x)**2) == r"\operatorname{frac}{\left(x\right)}^{2}" assert latex(Min(x, 2, x**3)) == r"\min\left(2, x, x^{3}\right)" assert latex(Min(x, y)**2) == r"\min\left(x, y\right)^{2}" assert latex(Max(x, 2, x**3)) == r"\max\left(2, x, x^{3}\right)" assert latex(Max(x, y)**2) == r"\max\left(x, y\right)^{2}" assert latex(Abs(x)) == r"\left|{x}\right|" assert latex(Abs(x)**2) == r"\left|{x}\right|^{2}" assert latex(re(x)) == r"\operatorname{re}{\left(x\right)}" assert latex(re(x + y)) == \ r"\operatorname{re}{\left(x\right)} + \operatorname{re}{\left(y\right)}" assert latex(im(x)) == r"\operatorname{im}{\left(x\right)}" assert latex(conjugate(x)) == r"\overline{x}" assert latex(conjugate(x)**2) == r"\overline{x}^{2}" assert latex(conjugate(x**2)) == r"\overline{x}^{2}" assert latex(gamma(x)) == r"\Gamma\left(x\right)" w = Wild('w') assert latex(gamma(w)) == r"\Gamma\left(w\right)" assert latex(Order(x)) == r"O\left(x\right)" assert latex(Order(x, x)) == r"O\left(x\right)" assert latex(Order(x, (x, 0))) == r"O\left(x\right)" assert latex(Order(x, (x, oo))) == r"O\left(x; x\rightarrow \infty\right)" assert latex(Order(x - y, (x, y))) == \ r"O\left(x - y; x\rightarrow y\right)" assert latex(Order(x, x, y)) == \ r"O\left(x; \left( x, \ y\right)\rightarrow \left( 0, \ 0\right)\right)" assert latex(Order(x, x, y)) == \ r"O\left(x; \left( x, \ y\right)\rightarrow \left( 0, \ 0\right)\right)" assert latex(Order(x, (x, oo), (y, oo))) == \ r"O\left(x; \left( x, \ y\right)\rightarrow \left( \infty, \ \infty\right)\right)" assert latex(lowergamma(x, y)) == r'\gamma\left(x, y\right)' assert latex(lowergamma(x, y)**2) == r'\gamma^{2}\left(x, y\right)' assert latex(uppergamma(x, y)) == r'\Gamma\left(x, y\right)' assert latex(uppergamma(x, y)**2) == r'\Gamma^{2}\left(x, y\right)' assert latex(cot(x)) == r'\cot{\left(x \right)}' assert latex(coth(x)) == r'\coth{\left(x \right)}' assert latex(re(x)) == r'\operatorname{re}{\left(x\right)}' assert latex(im(x)) == r'\operatorname{im}{\left(x\right)}' assert latex(root(x, y)) == r'x^{\frac{1}{y}}' assert latex(arg(x)) == r'\arg{\left(x \right)}' assert latex(zeta(x)) == r"\zeta\left(x\right)" assert latex(zeta(x)**2) == r"\zeta^{2}\left(x\right)" assert latex(zeta(x, y)) == r"\zeta\left(x, y\right)" assert latex(zeta(x, y)**2) == r"\zeta^{2}\left(x, y\right)" assert latex(dirichlet_eta(x)) == r"\eta\left(x\right)" assert latex(dirichlet_eta(x)**2) == r"\eta^{2}\left(x\right)" assert latex(polylog(x, y)) == r"\operatorname{Li}_{x}\left(y\right)" assert latex( polylog(x, y)**2) == r"\operatorname{Li}_{x}^{2}\left(y\right)" assert latex(lerchphi(x, y, n)) == r"\Phi\left(x, y, n\right)" assert latex(lerchphi(x, y, n)**2) == r"\Phi^{2}\left(x, y, n\right)" assert latex(stieltjes(x)) == r"\gamma_{x}" assert latex(stieltjes(x)**2) == r"\gamma_{x}^{2}" assert latex(stieltjes(x, y)) == r"\gamma_{x}\left(y\right)" assert latex(stieltjes(x, y)**2) == r"\gamma_{x}\left(y\right)^{2}" assert latex(elliptic_k(z)) == r"K\left(z\right)" assert latex(elliptic_k(z)**2) == r"K^{2}\left(z\right)" assert latex(elliptic_f(x, y)) == r"F\left(x\middle| y\right)" assert latex(elliptic_f(x, y)**2) == r"F^{2}\left(x\middle| y\right)" assert latex(elliptic_e(x, y)) == r"E\left(x\middle| y\right)" assert latex(elliptic_e(x, y)**2) == r"E^{2}\left(x\middle| y\right)" assert latex(elliptic_e(z)) == r"E\left(z\right)" assert latex(elliptic_e(z)**2) == r"E^{2}\left(z\right)" assert latex(elliptic_pi(x, y, z)) == r"\Pi\left(x; y\middle| z\right)" assert latex(elliptic_pi(x, y, z)**2) == \ r"\Pi^{2}\left(x; y\middle| z\right)" assert latex(elliptic_pi(x, y)) == r"\Pi\left(x\middle| y\right)" assert latex(elliptic_pi(x, y)**2) == r"\Pi^{2}\left(x\middle| y\right)" assert latex(Ei(x)) == r'\operatorname{Ei}{\left(x \right)}' assert latex(Ei(x)**2) == r'\operatorname{Ei}^{2}{\left(x \right)}' assert latex(expint(x, y)) == r'\operatorname{E}_{x}\left(y\right)' assert latex(expint(x, y)**2) == r'\operatorname{E}_{x}^{2}\left(y\right)' assert latex(Shi(x)**2) == r'\operatorname{Shi}^{2}{\left(x \right)}' assert latex(Si(x)**2) == r'\operatorname{Si}^{2}{\left(x \right)}' assert latex(Ci(x)**2) == r'\operatorname{Ci}^{2}{\left(x \right)}' assert latex(Chi(x)**2) == r'\operatorname{Chi}^{2}\left(x\right)' assert latex(Chi(x)) == r'\operatorname{Chi}\left(x\right)' assert latex(jacobi(n, a, b, x)) == \ r'P_{n}^{\left(a,b\right)}\left(x\right)' assert latex(jacobi(n, a, b, x)**2) == \ r'\left(P_{n}^{\left(a,b\right)}\left(x\right)\right)^{2}' assert latex(gegenbauer(n, a, x)) == \ r'C_{n}^{\left(a\right)}\left(x\right)' assert latex(gegenbauer(n, a, x)**2) == \ r'\left(C_{n}^{\left(a\right)}\left(x\right)\right)^{2}' assert latex(chebyshevt(n, x)) == r'T_{n}\left(x\right)' assert latex(chebyshevt(n, x)**2) == \ r'\left(T_{n}\left(x\right)\right)^{2}' assert latex(chebyshevu(n, x)) == r'U_{n}\left(x\right)' assert latex(chebyshevu(n, x)**2) == \ r'\left(U_{n}\left(x\right)\right)^{2}' assert latex(legendre(n, x)) == r'P_{n}\left(x\right)' assert latex(legendre(n, x)**2) == r'\left(P_{n}\left(x\right)\right)^{2}' assert latex(assoc_legendre(n, a, x)) == \ r'P_{n}^{\left(a\right)}\left(x\right)' assert latex(assoc_legendre(n, a, x)**2) == \ r'\left(P_{n}^{\left(a\right)}\left(x\right)\right)^{2}' assert latex(laguerre(n, x)) == r'L_{n}\left(x\right)' assert latex(laguerre(n, x)**2) == r'\left(L_{n}\left(x\right)\right)^{2}' assert latex(assoc_laguerre(n, a, x)) == \ r'L_{n}^{\left(a\right)}\left(x\right)' assert latex(assoc_laguerre(n, a, x)**2) == \ r'\left(L_{n}^{\left(a\right)}\left(x\right)\right)^{2}' assert latex(hermite(n, x)) == r'H_{n}\left(x\right)' assert latex(hermite(n, x)**2) == r'\left(H_{n}\left(x\right)\right)^{2}' theta = Symbol("theta", real=True) phi = Symbol("phi", real=True) assert latex(Ynm(n, m, theta, phi)) == r'Y_{n}^{m}\left(\theta,\phi\right)' assert latex(Ynm(n, m, theta, phi)**3) == \ r'\left(Y_{n}^{m}\left(\theta,\phi\right)\right)^{3}' assert latex(Znm(n, m, theta, phi)) == r'Z_{n}^{m}\left(\theta,\phi\right)' assert latex(Znm(n, m, theta, phi)**3) == \ r'\left(Z_{n}^{m}\left(\theta,\phi\right)\right)^{3}' # Test latex printing of function names with "_" assert latex(polar_lift(0)) == \ r"\operatorname{polar\_lift}{\left(0 \right)}" assert latex(polar_lift(0)**3) == \ r"\operatorname{polar\_lift}^{3}{\left(0 \right)}" assert latex(totient(n)) == r'\phi\left(n\right)' assert latex(totient(n) ** 2) == r'\left(\phi\left(n\right)\right)^{2}' assert latex(reduced_totient(n)) == r'\lambda\left(n\right)' assert latex(reduced_totient(n) ** 2) == \ r'\left(\lambda\left(n\right)\right)^{2}' assert latex(divisor_sigma(x)) == r"\sigma\left(x\right)" assert latex(divisor_sigma(x)**2) == r"\sigma^{2}\left(x\right)" assert latex(divisor_sigma(x, y)) == r"\sigma_y\left(x\right)" assert latex(divisor_sigma(x, y)**2) == r"\sigma^{2}_y\left(x\right)" assert latex(udivisor_sigma(x)) == r"\sigma^*\left(x\right)" assert latex(udivisor_sigma(x)**2) == r"\sigma^*^{2}\left(x\right)" assert latex(udivisor_sigma(x, y)) == r"\sigma^*_y\left(x\right)" assert latex(udivisor_sigma(x, y)**2) == r"\sigma^*^{2}_y\left(x\right)" assert latex(primenu(n)) == r'\nu\left(n\right)' assert latex(primenu(n) ** 2) == r'\left(\nu\left(n\right)\right)^{2}' assert latex(primeomega(n)) == r'\Omega\left(n\right)' assert latex(primeomega(n) ** 2) == \ r'\left(\Omega\left(n\right)\right)^{2}' assert latex(LambertW(n)) == r'W\left(n\right)' assert latex(LambertW(n, -1)) == r'W_{-1}\left(n\right)' assert latex(LambertW(n, k)) == r'W_{k}\left(n\right)' assert latex(LambertW(n) * LambertW(n)) == r"W^{2}\left(n\right)" assert latex(Pow(LambertW(n), 2)) == r"W^{2}\left(n\right)" assert latex(LambertW(n)**k) == r"W^{k}\left(n\right)" assert latex(LambertW(n, k)**p) == r"W^{p}_{k}\left(n\right)" assert latex(Mod(x, 7)) == r'x\bmod{7}' assert latex(Mod(x + 1, 7)) == r'\left(x + 1\right)\bmod{7}' assert latex(Mod(2 * x, 7)) == r'2 x\bmod{7}' assert latex(Mod(x, 7) + 1) == r'\left(x\bmod{7}\right) + 1' assert latex(2 * Mod(x, 7)) == r'2 \left(x\bmod{7}\right)' # some unknown function name should get rendered with \operatorname fjlkd = Function('fjlkd') assert latex(fjlkd(x)) == r'\operatorname{fjlkd}{\left(x \right)}' # even when it is referred to without an argument assert latex(fjlkd) == r'\operatorname{fjlkd}' # test that notation passes to subclasses of the same name only def test_function_subclass_different_name(): class mygamma(gamma): pass assert latex(mygamma) == r"\operatorname{mygamma}" assert latex(mygamma(x)) == r"\operatorname{mygamma}{\left(x \right)}" def test_hyper_printing(): from sympy import pi from sympy.abc import x, z assert latex(meijerg(Tuple(pi, pi, x), Tuple(1), (0, 1), Tuple(1, 2, 3/pi), z)) == \ r'{G_{4, 5}^{2, 3}\left(\begin{matrix} \pi, \pi, x & 1 \\0, 1 & 1, 2, '\ r'\frac{3}{\pi} \end{matrix} \middle| {z} \right)}' assert latex(meijerg(Tuple(), Tuple(1), (0,), Tuple(), z)) == \ r'{G_{1, 1}^{1, 0}\left(\begin{matrix} & 1 \\0 & \end{matrix} \middle| {z} \right)}' assert latex(hyper((x, 2), (3,), z)) == \ r'{{}_{2}F_{1}\left(\begin{matrix} x, 2 ' \ r'\\ 3 \end{matrix}\middle| {z} \right)}' assert latex(hyper(Tuple(), Tuple(1), z)) == \ r'{{}_{0}F_{1}\left(\begin{matrix} ' \ r'\\ 1 \end{matrix}\middle| {z} \right)}' def test_latex_bessel(): from sympy.functions.special.bessel import (besselj, bessely, besseli, besselk, hankel1, hankel2, jn, yn, hn1, hn2) from sympy.abc import z assert latex(besselj(n, z**2)**k) == r'J^{k}_{n}\left(z^{2}\right)' assert latex(bessely(n, z)) == r'Y_{n}\left(z\right)' assert latex(besseli(n, z)) == r'I_{n}\left(z\right)' assert latex(besselk(n, z)) == r'K_{n}\left(z\right)' assert latex(hankel1(n, z**2)**2) == \ r'\left(H^{(1)}_{n}\left(z^{2}\right)\right)^{2}' assert latex(hankel2(n, z)) == r'H^{(2)}_{n}\left(z\right)' assert latex(jn(n, z)) == r'j_{n}\left(z\right)' assert latex(yn(n, z)) == r'y_{n}\left(z\right)' assert latex(hn1(n, z)) == r'h^{(1)}_{n}\left(z\right)' assert latex(hn2(n, z)) == r'h^{(2)}_{n}\left(z\right)' def test_latex_fresnel(): from sympy.functions.special.error_functions import (fresnels, fresnelc) from sympy.abc import z assert latex(fresnels(z)) == r'S\left(z\right)' assert latex(fresnelc(z)) == r'C\left(z\right)' assert latex(fresnels(z)**2) == r'S^{2}\left(z\right)' assert latex(fresnelc(z)**2) == r'C^{2}\left(z\right)' def test_latex_brackets(): assert latex((-1)**x) == r"\left(-1\right)^{x}" def test_latex_indexed(): Psi_symbol = Symbol('Psi_0', complex=True, real=False) Psi_indexed = IndexedBase(Symbol('Psi', complex=True, real=False)) symbol_latex = latex(Psi_symbol * conjugate(Psi_symbol)) indexed_latex = latex(Psi_indexed[0] * conjugate(Psi_indexed[0])) # \\overline{{\\Psi}_{0}} {\\Psi}_{0} vs. \\Psi_{0} \\overline{\\Psi_{0}} assert symbol_latex == r'\Psi_{0} \overline{\Psi_{0}}' assert indexed_latex == r'\overline{{\Psi}_{0}} {\Psi}_{0}' # Symbol('gamma') gives r'\gamma' assert latex(Indexed('x1', Symbol('i'))) == r'{x_{1}}_{i}' assert latex(IndexedBase('gamma')) == r'\gamma' assert latex(IndexedBase('a b')) == r'a b' assert latex(IndexedBase('a_b')) == r'a_{b}' def test_latex_derivatives(): # regular "d" for ordinary derivatives assert latex(diff(x**3, x, evaluate=False)) == \ r"\frac{d}{d x} x^{3}" assert latex(diff(sin(x) + x**2, x, evaluate=False)) == \ r"\frac{d}{d x} \left(x^{2} + \sin{\left(x \right)}\right)" assert latex(diff(diff(sin(x) + x**2, x, evaluate=False), evaluate=False))\ == \ r"\frac{d^{2}}{d x^{2}} \left(x^{2} + \sin{\left(x \right)}\right)" assert latex(diff(diff(diff(sin(x) + x**2, x, evaluate=False), evaluate=False), evaluate=False)) == \ r"\frac{d^{3}}{d x^{3}} \left(x^{2} + \sin{\left(x \right)}\right)" # \partial for partial derivatives assert latex(diff(sin(x * y), x, evaluate=False)) == \ r"\frac{\partial}{\partial x} \sin{\left(x y \right)}" assert latex(diff(sin(x * y) + x**2, x, evaluate=False)) == \ r"\frac{\partial}{\partial x} \left(x^{2} + \sin{\left(x y \right)}\right)" assert latex(diff(diff(sin(x*y) + x**2, x, evaluate=False), x, evaluate=False)) == \ r"\frac{\partial^{2}}{\partial x^{2}} \left(x^{2} + \sin{\left(x y \right)}\right)" assert latex(diff(diff(diff(sin(x*y) + x**2, x, evaluate=False), x, evaluate=False), x, evaluate=False)) == \ r"\frac{\partial^{3}}{\partial x^{3}} \left(x^{2} + \sin{\left(x y \right)}\right)" # mixed partial derivatives f = Function("f") assert latex(diff(diff(f(x, y), x, evaluate=False), y, evaluate=False)) == \ r"\frac{\partial^{2}}{\partial y\partial x} " + latex(f(x, y)) assert latex(diff(diff(diff(f(x, y), x, evaluate=False), x, evaluate=False), y, evaluate=False)) == \ r"\frac{\partial^{3}}{\partial y\partial x^{2}} " + latex(f(x, y)) # for negative nested Derivative assert latex(diff(-diff(y**2,x,evaluate=False),x,evaluate=False)) == r'\frac{d}{d x} \left(- \frac{d}{d x} y^{2}\right)' assert latex(diff(diff(-diff(diff(y,x,evaluate=False),x,evaluate=False),x,evaluate=False),x,evaluate=False)) == \ r'\frac{d^{2}}{d x^{2}} \left(- \frac{d^{2}}{d x^{2}} y\right)' # use ordinary d when one of the variables has been integrated out assert latex(diff(Integral(exp(-x*y), (x, 0, oo)), y, evaluate=False)) == \ r"\frac{d}{d y} \int\limits_{0}^{\infty} e^{- x y}\, dx" # Derivative wrapped in power: assert latex(diff(x, x, evaluate=False)**2) == \ r"\left(\frac{d}{d x} x\right)^{2}" assert latex(diff(f(x), x)**2) == \ r"\left(\frac{d}{d x} f{\left(x \right)}\right)^{2}" assert latex(diff(f(x), (x, n))) == \ r"\frac{d^{n}}{d x^{n}} f{\left(x \right)}" x1 = Symbol('x1') x2 = Symbol('x2') assert latex(diff(f(x1, x2), x1)) == r'\frac{\partial}{\partial x_{1}} f{\left(x_{1},x_{2} \right)}' n1 = Symbol('n1') assert latex(diff(f(x), (x, n1))) == r'\frac{d^{n_{1}}}{d x^{n_{1}}} f{\left(x \right)}' n2 = Symbol('n2') assert latex(diff(f(x), (x, Max(n1, n2)))) == \ r'\frac{d^{\max\left(n_{1}, n_{2}\right)}}{d x^{\max\left(n_{1}, n_{2}\right)}} f{\left(x \right)}' def test_latex_subs(): assert latex(Subs(x*y, (x, y), (1, 2))) == r'\left. x y \right|_{\substack{ x=1\\ y=2 }}' def test_latex_integrals(): assert latex(Integral(log(x), x)) == r"\int \log{\left(x \right)}\, dx" assert latex(Integral(x**2, (x, 0, 1))) == \ r"\int\limits_{0}^{1} x^{2}\, dx" assert latex(Integral(x**2, (x, 10, 20))) == \ r"\int\limits_{10}^{20} x^{2}\, dx" assert latex(Integral(y*x**2, (x, 0, 1), y)) == \ r"\int\int\limits_{0}^{1} x^{2} y\, dx\, dy" assert latex(Integral(y*x**2, (x, 0, 1), y), mode='equation*') == \ r"\begin{equation*}\int\int\limits_{0}^{1} x^{2} y\, dx\, dy\end{equation*}" assert latex(Integral(y*x**2, (x, 0, 1), y), mode='equation*', itex=True) \ == r"$$\int\int_{0}^{1} x^{2} y\, dx\, dy$$" assert latex(Integral(x, (x, 0))) == r"\int\limits^{0} x\, dx" assert latex(Integral(x*y, x, y)) == r"\iint x y\, dx\, dy" assert latex(Integral(x*y*z, x, y, z)) == r"\iiint x y z\, dx\, dy\, dz" assert latex(Integral(x*y*z*t, x, y, z, t)) == \ r"\iiiint t x y z\, dx\, dy\, dz\, dt" assert latex(Integral(x, x, x, x, x, x, x)) == \ r"\int\int\int\int\int\int x\, dx\, dx\, dx\, dx\, dx\, dx" assert latex(Integral(x, x, y, (z, 0, 1))) == \ r"\int\limits_{0}^{1}\int\int x\, dx\, dy\, dz" # for negative nested Integral assert latex(Integral(-Integral(y**2,x),x)) == \ r'\int \left(- \int y^{2}\, dx\right)\, dx' assert latex(Integral(-Integral(-Integral(y,x),x),x)) == \ r'\int \left(- \int \left(- \int y\, dx\right)\, dx\right)\, dx' # fix issue #10806 assert latex(Integral(z, z)**2) == r"\left(\int z\, dz\right)^{2}" assert latex(Integral(x + z, z)) == r"\int \left(x + z\right)\, dz" assert latex(Integral(x+z/2, z)) == \ r"\int \left(x + \frac{z}{2}\right)\, dz" assert latex(Integral(x**y, z)) == r"\int x^{y}\, dz" def test_latex_sets(): for s in (frozenset, set): assert latex(s([x*y, x**2])) == r"\left\{x^{2}, x y\right\}" assert latex(s(range(1, 6))) == r"\left\{1, 2, 3, 4, 5\right\}" assert latex(s(range(1, 13))) == \ r"\left\{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12\right\}" s = FiniteSet assert latex(s(*[x*y, x**2])) == r"\left\{x^{2}, x y\right\}" assert latex(s(*range(1, 6))) == r"\left\{1, 2, 3, 4, 5\right\}" assert latex(s(*range(1, 13))) == \ r"\left\{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12\right\}" def test_latex_SetExpr(): iv = Interval(1, 3) se = SetExpr(iv) assert latex(se) == r"SetExpr\left(\left[1, 3\right]\right)" def test_latex_Range(): assert latex(Range(1, 51)) == r'\left\{1, 2, \ldots, 50\right\}' assert latex(Range(1, 4)) == r'\left\{1, 2, 3\right\}' assert latex(Range(0, 3, 1)) == r'\left\{0, 1, 2\right\}' assert latex(Range(0, 30, 1)) == r'\left\{0, 1, \ldots, 29\right\}' assert latex(Range(30, 1, -1)) == r'\left\{30, 29, \ldots, 2\right\}' assert latex(Range(0, oo, 2)) == r'\left\{0, 2, \ldots\right\}' assert latex(Range(oo, -2, -2)) == r'\left\{\ldots, 2, 0\right\}' assert latex(Range(-2, -oo, -1)) == r'\left\{-2, -3, \ldots\right\}' assert latex(Range(-oo, oo)) == r'\left\{\ldots, -1, 0, 1, \ldots\right\}' assert latex(Range(oo, -oo, -1)) == r'\left\{\ldots, 1, 0, -1, \ldots\right\}' a, b, c = symbols('a:c') assert latex(Range(a, b, c)) == r'Range\left(a, b, c\right)' assert latex(Range(a, 10, 1)) == r'Range\left(a, 10, 1\right)' assert latex(Range(0, b, 1)) == r'Range\left(0, b, 1\right)' assert latex(Range(0, 10, c)) == r'Range\left(0, 10, c\right)' def test_latex_sequences(): s1 = SeqFormula(a**2, (0, oo)) s2 = SeqPer((1, 2)) latex_str = r'\left[0, 1, 4, 9, \ldots\right]' assert latex(s1) == latex_str latex_str = r'\left[1, 2, 1, 2, \ldots\right]' assert latex(s2) == latex_str s3 = SeqFormula(a**2, (0, 2)) s4 = SeqPer((1, 2), (0, 2)) latex_str = r'\left[0, 1, 4\right]' assert latex(s3) == latex_str latex_str = r'\left[1, 2, 1\right]' assert latex(s4) == latex_str s5 = SeqFormula(a**2, (-oo, 0)) s6 = SeqPer((1, 2), (-oo, 0)) latex_str = r'\left[\ldots, 9, 4, 1, 0\right]' assert latex(s5) == latex_str latex_str = r'\left[\ldots, 2, 1, 2, 1\right]' assert latex(s6) == latex_str latex_str = r'\left[1, 3, 5, 11, \ldots\right]' assert latex(SeqAdd(s1, s2)) == latex_str latex_str = r'\left[1, 3, 5\right]' assert latex(SeqAdd(s3, s4)) == latex_str latex_str = r'\left[\ldots, 11, 5, 3, 1\right]' assert latex(SeqAdd(s5, s6)) == latex_str latex_str = r'\left[0, 2, 4, 18, \ldots\right]' assert latex(SeqMul(s1, s2)) == latex_str latex_str = r'\left[0, 2, 4\right]' assert latex(SeqMul(s3, s4)) == latex_str latex_str = r'\left[\ldots, 18, 4, 2, 0\right]' assert latex(SeqMul(s5, s6)) == latex_str # Sequences with symbolic limits, issue 12629 s7 = SeqFormula(a**2, (a, 0, x)) latex_str = r'\left\{a^{2}\right\}_{a=0}^{x}' assert latex(s7) == latex_str b = Symbol('b') s8 = SeqFormula(b*a**2, (a, 0, 2)) latex_str = r'\left[0, b, 4 b\right]' assert latex(s8) == latex_str def test_latex_FourierSeries(): latex_str = \ r'2 \sin{\left(x \right)} - \sin{\left(2 x \right)} + \frac{2 \sin{\left(3 x \right)}}{3} + \ldots' assert latex(fourier_series(x, (x, -pi, pi))) == latex_str def test_latex_FormalPowerSeries(): latex_str = r'\sum_{k=1}^{\infty} - \frac{\left(-1\right)^{- k} x^{k}}{k}' assert latex(fps(log(1 + x))) == latex_str def test_latex_intervals(): a = Symbol('a', real=True) assert latex(Interval(0, 0)) == r"\left\{0\right\}" assert latex(Interval(0, a)) == r"\left[0, a\right]" assert latex(Interval(0, a, False, False)) == r"\left[0, a\right]" assert latex(Interval(0, a, True, False)) == r"\left(0, a\right]" assert latex(Interval(0, a, False, True)) == r"\left[0, a\right)" assert latex(Interval(0, a, True, True)) == r"\left(0, a\right)" def test_latex_AccumuBounds(): a = Symbol('a', real=True) assert latex(AccumBounds(0, 1)) == r"\left\langle 0, 1\right\rangle" assert latex(AccumBounds(0, a)) == r"\left\langle 0, a\right\rangle" assert latex(AccumBounds(a + 1, a + 2)) == \ r"\left\langle a + 1, a + 2\right\rangle" def test_latex_emptyset(): assert latex(S.EmptySet) == r"\emptyset" def test_latex_universalset(): assert latex(S.UniversalSet) == r"\mathbb{U}" def test_latex_commutator(): A = Operator('A') B = Operator('B') comm = Commutator(B, A) assert latex(comm.doit()) == r"- (A B - B A)" def test_latex_union(): assert latex(Union(Interval(0, 1), Interval(2, 3))) == \ r"\left[0, 1\right] \cup \left[2, 3\right]" assert latex(Union(Interval(1, 1), Interval(2, 2), Interval(3, 4))) == \ r"\left\{1, 2\right\} \cup \left[3, 4\right]" def test_latex_intersection(): assert latex(Intersection(Interval(0, 1), Interval(x, y))) == \ r"\left[0, 1\right] \cap \left[x, y\right]" def test_latex_symmetric_difference(): assert latex(SymmetricDifference(Interval(2, 5), Interval(4, 7), evaluate=False)) == \ r'\left[2, 5\right] \triangle \left[4, 7\right]' def test_latex_Complement(): assert latex(Complement(S.Reals, S.Naturals)) == \ r"\mathbb{R} \setminus \mathbb{N}" def test_latex_productset(): line = Interval(0, 1) bigline = Interval(0, 10) fset = FiniteSet(1, 2, 3) assert latex(line**2) == r"%s^{2}" % latex(line) assert latex(line**10) == r"%s^{10}" % latex(line) assert latex((line * bigline * fset).flatten()) == r"%s \times %s \times %s" % ( latex(line), latex(bigline), latex(fset)) def test_set_operators_parenthesis(): a, b, c, d = symbols('a:d') A = FiniteSet(a) B = FiniteSet(b) C = FiniteSet(c) D = FiniteSet(d) U1 = Union(A, B, evaluate=False) U2 = Union(C, D, evaluate=False) I1 = Intersection(A, B, evaluate=False) I2 = Intersection(C, D, evaluate=False) C1 = Complement(A, B, evaluate=False) C2 = Complement(C, D, evaluate=False) D1 = SymmetricDifference(A, B, evaluate=False) D2 = SymmetricDifference(C, D, evaluate=False) # XXX ProductSet does not support evaluate keyword P1 = ProductSet(A, B) P2 = ProductSet(C, D) assert latex(Intersection(A, U2, evaluate=False)) == \ r'\left\{a\right\} \cap ' \ r'\left(\left\{c\right\} \cup \left\{d\right\}\right)' assert latex(Intersection(U1, U2, evaluate=False)) == \ r'\left(\left\{a\right\} \cup \left\{b\right\}\right) ' \ r'\cap \left(\left\{c\right\} \cup \left\{d\right\}\right)' assert latex(Intersection(C1, C2, evaluate=False)) == \ r'\left(\left\{a\right\} \setminus ' \ r'\left\{b\right\}\right) \cap \left(\left\{c\right\} ' \ r'\setminus \left\{d\right\}\right)' assert latex(Intersection(D1, D2, evaluate=False)) == \ r'\left(\left\{a\right\} \triangle ' \ r'\left\{b\right\}\right) \cap \left(\left\{c\right\} ' \ r'\triangle \left\{d\right\}\right)' assert latex(Intersection(P1, P2, evaluate=False)) == \ r'\left(\left\{a\right\} \times \left\{b\right\}\right) ' \ r'\cap \left(\left\{c\right\} \times ' \ r'\left\{d\right\}\right)' assert latex(Union(A, I2, evaluate=False)) == \ r'\left\{a\right\} \cup ' \ r'\left(\left\{c\right\} \cap \left\{d\right\}\right)' assert latex(Union(I1, I2, evaluate=False)) == \ r'\left(\left\{a\right\} \cap \left\{b\right\}\right) ' \ r'\cup \left(\left\{c\right\} \cap \left\{d\right\}\right)' assert latex(Union(C1, C2, evaluate=False)) == \ r'\left(\left\{a\right\} \setminus ' \ r'\left\{b\right\}\right) \cup \left(\left\{c\right\} ' \ r'\setminus \left\{d\right\}\right)' assert latex(Union(D1, D2, evaluate=False)) == \ r'\left(\left\{a\right\} \triangle ' \ r'\left\{b\right\}\right) \cup \left(\left\{c\right\} ' \ r'\triangle \left\{d\right\}\right)' assert latex(Union(P1, P2, evaluate=False)) == \ r'\left(\left\{a\right\} \times \left\{b\right\}\right) ' \ r'\cup \left(\left\{c\right\} \times ' \ r'\left\{d\right\}\right)' assert latex(Complement(A, C2, evaluate=False)) == \ r'\left\{a\right\} \setminus \left(\left\{c\right\} ' \ r'\setminus \left\{d\right\}\right)' assert latex(Complement(U1, U2, evaluate=False)) == \ r'\left(\left\{a\right\} \cup \left\{b\right\}\right) ' \ r'\setminus \left(\left\{c\right\} \cup ' \ r'\left\{d\right\}\right)' assert latex(Complement(I1, I2, evaluate=False)) == \ r'\left(\left\{a\right\} \cap \left\{b\right\}\right) ' \ r'\setminus \left(\left\{c\right\} \cap ' \ r'\left\{d\right\}\right)' assert latex(Complement(D1, D2, evaluate=False)) == \ r'\left(\left\{a\right\} \triangle ' \ r'\left\{b\right\}\right) \setminus ' \ r'\left(\left\{c\right\} \triangle \left\{d\right\}\right)' assert latex(Complement(P1, P2, evaluate=False)) == \ r'\left(\left\{a\right\} \times \left\{b\right\}\right) '\ r'\setminus \left(\left\{c\right\} \times '\ r'\left\{d\right\}\right)' assert latex(SymmetricDifference(A, D2, evaluate=False)) == \ r'\left\{a\right\} \triangle \left(\left\{c\right\} ' \ r'\triangle \left\{d\right\}\right)' assert latex(SymmetricDifference(U1, U2, evaluate=False)) == \ r'\left(\left\{a\right\} \cup \left\{b\right\}\right) ' \ r'\triangle \left(\left\{c\right\} \cup ' \ r'\left\{d\right\}\right)' assert latex(SymmetricDifference(I1, I2, evaluate=False)) == \ r'\left(\left\{a\right\} \cap \left\{b\right\}\right) ' \ r'\triangle \left(\left\{c\right\} \cap ' \ r'\left\{d\right\}\right)' assert latex(SymmetricDifference(C1, C2, evaluate=False)) == \ r'\left(\left\{a\right\} \setminus ' \ r'\left\{b\right\}\right) \triangle ' \ r'\left(\left\{c\right\} \setminus \left\{d\right\}\right)' assert latex(SymmetricDifference(P1, P2, evaluate=False)) == \ r'\left(\left\{a\right\} \times \left\{b\right\}\right) ' \ r'\triangle \left(\left\{c\right\} \times ' \ r'\left\{d\right\}\right)' # XXX This can be incorrect since cartesian product is not associative assert latex(ProductSet(A, P2).flatten()) == \ r'\left\{a\right\} \times \left\{c\right\} \times ' \ r'\left\{d\right\}' assert latex(ProductSet(U1, U2)) == \ r'\left(\left\{a\right\} \cup \left\{b\right\}\right) ' \ r'\times \left(\left\{c\right\} \cup ' \ r'\left\{d\right\}\right)' assert latex(ProductSet(I1, I2)) == \ r'\left(\left\{a\right\} \cap \left\{b\right\}\right) ' \ r'\times \left(\left\{c\right\} \cap ' \ r'\left\{d\right\}\right)' assert latex(ProductSet(C1, C2)) == \ r'\left(\left\{a\right\} \setminus ' \ r'\left\{b\right\}\right) \times \left(\left\{c\right\} ' \ r'\setminus \left\{d\right\}\right)' assert latex(ProductSet(D1, D2)) == \ r'\left(\left\{a\right\} \triangle ' \ r'\left\{b\right\}\right) \times \left(\left\{c\right\} ' \ r'\triangle \left\{d\right\}\right)' def test_latex_Complexes(): assert latex(S.Complexes) == r"\mathbb{C}" def test_latex_Naturals(): assert latex(S.Naturals) == r"\mathbb{N}" def test_latex_Naturals0(): assert latex(S.Naturals0) == r"\mathbb{N}_0" def test_latex_Integers(): assert latex(S.Integers) == r"\mathbb{Z}" def test_latex_ImageSet(): x = Symbol('x') assert latex(ImageSet(Lambda(x, x**2), S.Naturals)) == \ r"\left\{x^{2}\; \middle|\; x \in \mathbb{N}\right\}" y = Symbol('y') imgset = ImageSet(Lambda((x, y), x + y), {1, 2, 3}, {3, 4}) assert latex(imgset) == \ r"\left\{x + y\; \middle|\; x \in \left\{1, 2, 3\right\} , y \in \left\{3, 4\right\}\right\}" imgset = ImageSet(Lambda(((x, y),), x + y), ProductSet({1, 2, 3}, {3, 4})) assert latex(imgset) == \ r"\left\{x + y\; \middle|\; \left( x, \ y\right) \in \left\{1, 2, 3\right\} \times \left\{3, 4\right\}\right\}" def test_latex_ConditionSet(): x = Symbol('x') assert latex(ConditionSet(x, Eq(x**2, 1), S.Reals)) == \ r"\left\{x\; \middle|\; x \in \mathbb{R} \wedge x^{2} = 1 \right\}" assert latex(ConditionSet(x, Eq(x**2, 1), S.UniversalSet)) == \ r"\left\{x\; \middle|\; x^{2} = 1 \right\}" def test_latex_ComplexRegion(): assert latex(ComplexRegion(Interval(3, 5)*Interval(4, 6))) == \ r"\left\{x + y i\; \middle|\; x, y \in \left[3, 5\right] \times \left[4, 6\right] \right\}" assert latex(ComplexRegion(Interval(0, 1)*Interval(0, 2*pi), polar=True)) == \ r"\left\{r \left(i \sin{\left(\theta \right)} + \cos{\left(\theta "\ r"\right)}\right)\; \middle|\; r, \theta \in \left[0, 1\right] \times \left[0, 2 \pi\right) \right\}" def test_latex_Contains(): x = Symbol('x') assert latex(Contains(x, S.Naturals)) == r"x \in \mathbb{N}" def test_latex_sum(): assert latex(Sum(x*y**2, (x, -2, 2), (y, -5, 5))) == \ r"\sum_{\substack{-2 \leq x \leq 2\\-5 \leq y \leq 5}} x y^{2}" assert latex(Sum(x**2, (x, -2, 2))) == \ r"\sum_{x=-2}^{2} x^{2}" assert latex(Sum(x**2 + y, (x, -2, 2))) == \ r"\sum_{x=-2}^{2} \left(x^{2} + y\right)" assert latex(Sum(x**2 + y, (x, -2, 2))**2) == \ r"\left(\sum_{x=-2}^{2} \left(x^{2} + y\right)\right)^{2}" def test_latex_product(): assert latex(Product(x*y**2, (x, -2, 2), (y, -5, 5))) == \ r"\prod_{\substack{-2 \leq x \leq 2\\-5 \leq y \leq 5}} x y^{2}" assert latex(Product(x**2, (x, -2, 2))) == \ r"\prod_{x=-2}^{2} x^{2}" assert latex(Product(x**2 + y, (x, -2, 2))) == \ r"\prod_{x=-2}^{2} \left(x^{2} + y\right)" assert latex(Product(x, (x, -2, 2))**2) == \ r"\left(\prod_{x=-2}^{2} x\right)^{2}" def test_latex_limits(): assert latex(Limit(x, x, oo)) == r"\lim_{x \to \infty} x" # issue 8175 f = Function('f') assert latex(Limit(f(x), x, 0)) == r"\lim_{x \to 0^+} f{\left(x \right)}" assert latex(Limit(f(x), x, 0, "-")) == \ r"\lim_{x \to 0^-} f{\left(x \right)}" # issue #10806 assert latex(Limit(f(x), x, 0)**2) == \ r"\left(\lim_{x \to 0^+} f{\left(x \right)}\right)^{2}" # bi-directional limit assert latex(Limit(f(x), x, 0, dir='+-')) == \ r"\lim_{x \to 0} f{\left(x \right)}" def test_latex_log(): assert latex(log(x)) == r"\log{\left(x \right)}" assert latex(ln(x)) == r"\log{\left(x \right)}" assert latex(log(x), ln_notation=True) == r"\ln{\left(x \right)}" assert latex(log(x)+log(y)) == \ r"\log{\left(x \right)} + \log{\left(y \right)}" assert latex(log(x)+log(y), ln_notation=True) == \ r"\ln{\left(x \right)} + \ln{\left(y \right)}" assert latex(pow(log(x), x)) == r"\log{\left(x \right)}^{x}" assert latex(pow(log(x), x), ln_notation=True) == \ r"\ln{\left(x \right)}^{x}" def test_issue_3568(): beta = Symbol(r'\beta') y = beta + x assert latex(y) in [r'\beta + x', r'x + \beta'] beta = Symbol(r'beta') y = beta + x assert latex(y) in [r'\beta + x', r'x + \beta'] def test_latex(): assert latex((2*tau)**Rational(7, 2)) == r"8 \sqrt{2} \tau^{\frac{7}{2}}" assert latex((2*mu)**Rational(7, 2), mode='equation*') == \ r"\begin{equation*}8 \sqrt{2} \mu^{\frac{7}{2}}\end{equation*}" assert latex((2*mu)**Rational(7, 2), mode='equation', itex=True) == \ r"$$8 \sqrt{2} \mu^{\frac{7}{2}}$$" assert latex([2/x, y]) == r"\left[ \frac{2}{x}, \ y\right]" def test_latex_dict(): d = {Rational(1): 1, x**2: 2, x: 3, x**3: 4} assert latex(d) == \ r'\left\{ 1 : 1, \ x : 3, \ x^{2} : 2, \ x^{3} : 4\right\}' D = Dict(d) assert latex(D) == \ r'\left\{ 1 : 1, \ x : 3, \ x^{2} : 2, \ x^{3} : 4\right\}' def test_latex_list(): ll = [Symbol('omega1'), Symbol('a'), Symbol('alpha')] assert latex(ll) == r'\left[ \omega_{1}, \ a, \ \alpha\right]' def test_latex_rational(): # tests issue 3973 assert latex(-Rational(1, 2)) == r"- \frac{1}{2}" assert latex(Rational(-1, 2)) == r"- \frac{1}{2}" assert latex(Rational(1, -2)) == r"- \frac{1}{2}" assert latex(-Rational(-1, 2)) == r"\frac{1}{2}" assert latex(-Rational(1, 2)*x) == r"- \frac{x}{2}" assert latex(-Rational(1, 2)*x + Rational(-2, 3)*y) == \ r"- \frac{x}{2} - \frac{2 y}{3}" def test_latex_inverse(): # tests issue 4129 assert latex(1/x) == r"\frac{1}{x}" assert latex(1/(x + y)) == r"\frac{1}{x + y}" def test_latex_DiracDelta(): assert latex(DiracDelta(x)) == r"\delta\left(x\right)" assert latex(DiracDelta(x)**2) == r"\left(\delta\left(x\right)\right)^{2}" assert latex(DiracDelta(x, 0)) == r"\delta\left(x\right)" assert latex(DiracDelta(x, 5)) == \ r"\delta^{\left( 5 \right)}\left( x \right)" assert latex(DiracDelta(x, 5)**2) == \ r"\left(\delta^{\left( 5 \right)}\left( x \right)\right)^{2}" def test_latex_Heaviside(): assert latex(Heaviside(x)) == r"\theta\left(x\right)" assert latex(Heaviside(x)**2) == r"\left(\theta\left(x\right)\right)^{2}" def test_latex_KroneckerDelta(): assert latex(KroneckerDelta(x, y)) == r"\delta_{x y}" assert latex(KroneckerDelta(x, y + 1)) == r"\delta_{x, y + 1}" # issue 6578 assert latex(KroneckerDelta(x + 1, y)) == r"\delta_{y, x + 1}" assert latex(Pow(KroneckerDelta(x, y), 2, evaluate=False)) == \ r"\left(\delta_{x y}\right)^{2}" def test_latex_LeviCivita(): assert latex(LeviCivita(x, y, z)) == r"\varepsilon_{x y z}" assert latex(LeviCivita(x, y, z)**2) == \ r"\left(\varepsilon_{x y z}\right)^{2}" assert latex(LeviCivita(x, y, z + 1)) == r"\varepsilon_{x, y, z + 1}" assert latex(LeviCivita(x, y + 1, z)) == r"\varepsilon_{x, y + 1, z}" assert latex(LeviCivita(x + 1, y, z)) == r"\varepsilon_{x + 1, y, z}" def test_mode(): expr = x + y assert latex(expr) == r'x + y' assert latex(expr, mode='plain') == r'x + y' assert latex(expr, mode='inline') == r'$x + y$' assert latex( expr, mode='equation*') == r'\begin{equation*}x + y\end{equation*}' assert latex( expr, mode='equation') == r'\begin{equation}x + y\end{equation}' raises(ValueError, lambda: latex(expr, mode='foo')) def test_latex_mathieu(): assert latex(mathieuc(x, y, z)) == r"C\left(x, y, z\right)" assert latex(mathieus(x, y, z)) == r"S\left(x, y, z\right)" assert latex(mathieuc(x, y, z)**2) == r"C\left(x, y, z\right)^{2}" assert latex(mathieus(x, y, z)**2) == r"S\left(x, y, z\right)^{2}" assert latex(mathieucprime(x, y, z)) == r"C^{\prime}\left(x, y, z\right)" assert latex(mathieusprime(x, y, z)) == r"S^{\prime}\left(x, y, z\right)" assert latex(mathieucprime(x, y, z)**2) == r"C^{\prime}\left(x, y, z\right)^{2}" assert latex(mathieusprime(x, y, z)**2) == r"S^{\prime}\left(x, y, z\right)^{2}" def test_latex_Piecewise(): p = Piecewise((x, x < 1), (x**2, True)) assert latex(p) == r"\begin{cases} x & \text{for}\: x < 1 \\x^{2} &" \ r" \text{otherwise} \end{cases}" assert latex(p, itex=True) == \ r"\begin{cases} x & \text{for}\: x \lt 1 \\x^{2} &" \ r" \text{otherwise} \end{cases}" p = Piecewise((x, x < 0), (0, x >= 0)) assert latex(p) == r'\begin{cases} x & \text{for}\: x < 0 \\0 &' \ r' \text{otherwise} \end{cases}' A, B = symbols("A B", commutative=False) p = Piecewise((A**2, Eq(A, B)), (A*B, True)) s = r"\begin{cases} A^{2} & \text{for}\: A = B \\A B & \text{otherwise} \end{cases}" assert latex(p) == s assert latex(A*p) == r"A \left(%s\right)" % s assert latex(p*A) == r"\left(%s\right) A" % s assert latex(Piecewise((x, x < 1), (x**2, x < 2))) == \ r'\begin{cases} x & ' \ r'\text{for}\: x < 1 \\x^{2} & \text{for}\: x < 2 \end{cases}' def test_latex_Matrix(): M = Matrix([[1 + x, y], [y, x - 1]]) assert latex(M) == \ r'\left[\begin{matrix}x + 1 & y\\y & x - 1\end{matrix}\right]' assert latex(M, mode='inline') == \ r'$\left[\begin{smallmatrix}x + 1 & y\\' \ r'y & x - 1\end{smallmatrix}\right]$' assert latex(M, mat_str='array') == \ r'\left[\begin{array}{cc}x + 1 & y\\y & x - 1\end{array}\right]' assert latex(M, mat_str='bmatrix') == \ r'\left[\begin{bmatrix}x + 1 & y\\y & x - 1\end{bmatrix}\right]' assert latex(M, mat_delim=None, mat_str='bmatrix') == \ r'\begin{bmatrix}x + 1 & y\\y & x - 1\end{bmatrix}' M2 = Matrix(1, 11, range(11)) assert latex(M2) == \ r'\left[\begin{array}{ccccccccccc}' \ r'0 & 1 & 2 & 3 & 4 & 5 & 6 & 7 & 8 & 9 & 10\end{array}\right]' def test_latex_matrix_with_functions(): t = symbols('t') theta1 = symbols('theta1', cls=Function) M = Matrix([[sin(theta1(t)), cos(theta1(t))], [cos(theta1(t).diff(t)), sin(theta1(t).diff(t))]]) expected = (r'\left[\begin{matrix}\sin{\left(' r'\theta_{1}{\left(t \right)} \right)} & ' r'\cos{\left(\theta_{1}{\left(t \right)} \right)' r'}\\\cos{\left(\frac{d}{d t} \theta_{1}{\left(t ' r'\right)} \right)} & \sin{\left(\frac{d}{d t} ' r'\theta_{1}{\left(t \right)} \right' r')}\end{matrix}\right]') assert latex(M) == expected def test_latex_NDimArray(): x, y, z, w = symbols("x y z w") for ArrayType in (ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableDenseNDimArray, MutableSparseNDimArray): # Basic: scalar array M = ArrayType(x) assert latex(M) == r"x" M = ArrayType([[1 / x, y], [z, w]]) M1 = ArrayType([1 / x, y, z]) M2 = tensorproduct(M1, M) M3 = tensorproduct(M, M) assert latex(M) == \ r'\left[\begin{matrix}\frac{1}{x} & y\\z & w\end{matrix}\right]' assert latex(M1) == \ r"\left[\begin{matrix}\frac{1}{x} & y & z\end{matrix}\right]" assert latex(M2) == \ r"\left[\begin{matrix}" \ r"\left[\begin{matrix}\frac{1}{x^{2}} & \frac{y}{x}\\\frac{z}{x} & \frac{w}{x}\end{matrix}\right] & " \ r"\left[\begin{matrix}\frac{y}{x} & y^{2}\\y z & w y\end{matrix}\right] & " \ r"\left[\begin{matrix}\frac{z}{x} & y z\\z^{2} & w z\end{matrix}\right]" \ r"\end{matrix}\right]" assert latex(M3) == \ r"""\left[\begin{matrix}"""\ r"""\left[\begin{matrix}\frac{1}{x^{2}} & \frac{y}{x}\\\frac{z}{x} & \frac{w}{x}\end{matrix}\right] & """\ r"""\left[\begin{matrix}\frac{y}{x} & y^{2}\\y z & w y\end{matrix}\right]\\"""\ r"""\left[\begin{matrix}\frac{z}{x} & y z\\z^{2} & w z\end{matrix}\right] & """\ r"""\left[\begin{matrix}\frac{w}{x} & w y\\w z & w^{2}\end{matrix}\right]"""\ r"""\end{matrix}\right]""" Mrow = ArrayType([[x, y, 1/z]]) Mcolumn = ArrayType([[x], [y], [1/z]]) Mcol2 = ArrayType([Mcolumn.tolist()]) assert latex(Mrow) == \ r"\left[\left[\begin{matrix}x & y & \frac{1}{z}\end{matrix}\right]\right]" assert latex(Mcolumn) == \ r"\left[\begin{matrix}x\\y\\\frac{1}{z}\end{matrix}\right]" assert latex(Mcol2) == \ r'\left[\begin{matrix}\left[\begin{matrix}x\\y\\\frac{1}{z}\end{matrix}\right]\end{matrix}\right]' def test_latex_mul_symbol(): assert latex(4*4**x, mul_symbol='times') == r"4 \times 4^{x}" assert latex(4*4**x, mul_symbol='dot') == r"4 \cdot 4^{x}" assert latex(4*4**x, mul_symbol='ldot') == r"4 \,.\, 4^{x}" assert latex(4*x, mul_symbol='times') == r"4 \times x" assert latex(4*x, mul_symbol='dot') == r"4 \cdot x" assert latex(4*x, mul_symbol='ldot') == r"4 \,.\, x" def test_latex_issue_4381(): y = 4*4**log(2) assert latex(y) == r'4 \cdot 4^{\log{\left(2 \right)}}' assert latex(1/y) == r'\frac{1}{4 \cdot 4^{\log{\left(2 \right)}}}' def test_latex_issue_4576(): assert latex(Symbol("beta_13_2")) == r"\beta_{13 2}" assert latex(Symbol("beta_132_20")) == r"\beta_{132 20}" assert latex(Symbol("beta_13")) == r"\beta_{13}" assert latex(Symbol("x_a_b")) == r"x_{a b}" assert latex(Symbol("x_1_2_3")) == r"x_{1 2 3}" assert latex(Symbol("x_a_b1")) == r"x_{a b1}" assert latex(Symbol("x_a_1")) == r"x_{a 1}" assert latex(Symbol("x_1_a")) == r"x_{1 a}" assert latex(Symbol("x_1^aa")) == r"x^{aa}_{1}" assert latex(Symbol("x_1__aa")) == r"x^{aa}_{1}" assert latex(Symbol("x_11^a")) == r"x^{a}_{11}" assert latex(Symbol("x_11__a")) == r"x^{a}_{11}" assert latex(Symbol("x_a_a_a_a")) == r"x_{a a a a}" assert latex(Symbol("x_a_a^a^a")) == r"x^{a a}_{a a}" assert latex(Symbol("x_a_a__a__a")) == r"x^{a a}_{a a}" assert latex(Symbol("alpha_11")) == r"\alpha_{11}" assert latex(Symbol("alpha_11_11")) == r"\alpha_{11 11}" assert latex(Symbol("alpha_alpha")) == r"\alpha_{\alpha}" assert latex(Symbol("alpha^aleph")) == r"\alpha^{\aleph}" assert latex(Symbol("alpha__aleph")) == r"\alpha^{\aleph}" def test_latex_pow_fraction(): x = Symbol('x') # Testing exp assert r'e^{-x}' in latex(exp(-x)/2).replace(' ', '') # Remove Whitespace # Testing e^{-x} in case future changes alter behavior of muls or fracs # In particular current output is \frac{1}{2}e^{- x} but perhaps this will # change to \frac{e^{-x}}{2} # Testing general, non-exp, power assert r'3^{-x}' in latex(3**-x/2).replace(' ', '') def test_noncommutative(): A, B, C = symbols('A,B,C', commutative=False) assert latex(A*B*C**-1) == r"A B C^{-1}" assert latex(C**-1*A*B) == r"C^{-1} A B" assert latex(A*C**-1*B) == r"A C^{-1} B" def test_latex_order(): expr = x**3 + x**2*y + y**4 + 3*x*y**3 assert latex(expr, order='lex') == r"x^{3} + x^{2} y + 3 x y^{3} + y^{4}" assert latex( expr, order='rev-lex') == r"y^{4} + 3 x y^{3} + x^{2} y + x^{3}" assert latex(expr, order='none') == r"x^{3} + y^{4} + y x^{2} + 3 x y^{3}" def test_latex_Lambda(): assert latex(Lambda(x, x + 1)) == r"\left( x \mapsto x + 1 \right)" assert latex(Lambda((x, y), x + 1)) == r"\left( \left( x, \ y\right) \mapsto x + 1 \right)" assert latex(Lambda(x, x)) == r"\left( x \mapsto x \right)" def test_latex_PolyElement(): Ruv, u, v = ring("u,v", ZZ) Rxyz, x, y, z = ring("x,y,z", Ruv) assert latex(x - x) == r"0" assert latex(x - 1) == r"x - 1" assert latex(x + 1) == r"x + 1" assert latex((u**2 + 3*u*v + 1)*x**2*y + u + 1) == \ r"\left({u}^{2} + 3 u v + 1\right) {x}^{2} y + u + 1" assert latex((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x) == \ r"\left({u}^{2} + 3 u v + 1\right) {x}^{2} y + \left(u + 1\right) x" assert latex((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1) == \ r"\left({u}^{2} + 3 u v + 1\right) {x}^{2} y + \left(u + 1\right) x + 1" assert latex((-u**2 + 3*u*v - 1)*x**2*y - (u + 1)*x - 1) == \ r"-\left({u}^{2} - 3 u v + 1\right) {x}^{2} y - \left(u + 1\right) x - 1" assert latex(-(v**2 + v + 1)*x + 3*u*v + 1) == \ r"-\left({v}^{2} + v + 1\right) x + 3 u v + 1" assert latex(-(v**2 + v + 1)*x - 3*u*v + 1) == \ r"-\left({v}^{2} + v + 1\right) x - 3 u v + 1" def test_latex_FracElement(): Fuv, u, v = field("u,v", ZZ) Fxyzt, x, y, z, t = field("x,y,z,t", Fuv) assert latex(x - x) == r"0" assert latex(x - 1) == r"x - 1" assert latex(x + 1) == r"x + 1" assert latex(x/3) == r"\frac{x}{3}" assert latex(x/z) == r"\frac{x}{z}" assert latex(x*y/z) == r"\frac{x y}{z}" assert latex(x/(z*t)) == r"\frac{x}{z t}" assert latex(x*y/(z*t)) == r"\frac{x y}{z t}" assert latex((x - 1)/y) == r"\frac{x - 1}{y}" assert latex((x + 1)/y) == r"\frac{x + 1}{y}" assert latex((-x - 1)/y) == r"\frac{-x - 1}{y}" assert latex((x + 1)/(y*z)) == r"\frac{x + 1}{y z}" assert latex(-y/(x + 1)) == r"\frac{-y}{x + 1}" assert latex(y*z/(x + 1)) == r"\frac{y z}{x + 1}" assert latex(((u + 1)*x*y + 1)/((v - 1)*z - 1)) == \ r"\frac{\left(u + 1\right) x y + 1}{\left(v - 1\right) z - 1}" assert latex(((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1)) == \ r"\frac{\left(u + 1\right) x y + 1}{\left(v - 1\right) z - u v t - 1}" def test_latex_Poly(): assert latex(Poly(x**2 + 2 * x, x)) == \ r"\operatorname{Poly}{\left( x^{2} + 2 x, x, domain=\mathbb{Z} \right)}" assert latex(Poly(x/y, x)) == \ r"\operatorname{Poly}{\left( \frac{1}{y} x, x, domain=\mathbb{Z}\left(y\right) \right)}" assert latex(Poly(2.0*x + y)) == \ r"\operatorname{Poly}{\left( 2.0 x + 1.0 y, x, y, domain=\mathbb{R} \right)}" def test_latex_Poly_order(): assert latex(Poly([a, 1, b, 2, c, 3], x)) == \ r'\operatorname{Poly}{\left( a x^{5} + x^{4} + b x^{3} + 2 x^{2} + c'\ r' x + 3, x, domain=\mathbb{Z}\left[a, b, c\right] \right)}' assert latex(Poly([a, 1, b+c, 2, 3], x)) == \ r'\operatorname{Poly}{\left( a x^{4} + x^{3} + \left(b + c\right) '\ r'x^{2} + 2 x + 3, x, domain=\mathbb{Z}\left[a, b, c\right] \right)}' assert latex(Poly(a*x**3 + x**2*y - x*y - c*y**3 - b*x*y**2 + y - a*x + b, (x, y))) == \ r'\operatorname{Poly}{\left( a x^{3} + x^{2}y - b xy^{2} - xy - '\ r'a x - c y^{3} + y + b, x, y, domain=\mathbb{Z}\left[a, b, c\right] \right)}' def test_latex_ComplexRootOf(): assert latex(rootof(x**5 + x + 3, 0)) == \ r"\operatorname{CRootOf} {\left(x^{5} + x + 3, 0\right)}" def test_latex_RootSum(): assert latex(RootSum(x**5 + x + 3, sin)) == \ r"\operatorname{RootSum} {\left(x^{5} + x + 3, \left( x \mapsto \sin{\left(x \right)} \right)\right)}" def test_settings(): raises(TypeError, lambda: latex(x*y, method="garbage")) def test_latex_numbers(): assert latex(catalan(n)) == r"C_{n}" assert latex(catalan(n)**2) == r"C_{n}^{2}" assert latex(bernoulli(n)) == r"B_{n}" assert latex(bernoulli(n, x)) == r"B_{n}\left(x\right)" assert latex(bernoulli(n)**2) == r"B_{n}^{2}" assert latex(bernoulli(n, x)**2) == r"B_{n}^{2}\left(x\right)" assert latex(bell(n)) == r"B_{n}" assert latex(bell(n, x)) == r"B_{n}\left(x\right)" assert latex(bell(n, m, (x, y))) == r"B_{n, m}\left(x, y\right)" assert latex(bell(n)**2) == r"B_{n}^{2}" assert latex(bell(n, x)**2) == r"B_{n}^{2}\left(x\right)" assert latex(bell(n, m, (x, y))**2) == r"B_{n, m}^{2}\left(x, y\right)" assert latex(fibonacci(n)) == r"F_{n}" assert latex(fibonacci(n, x)) == r"F_{n}\left(x\right)" assert latex(fibonacci(n)**2) == r"F_{n}^{2}" assert latex(fibonacci(n, x)**2) == r"F_{n}^{2}\left(x\right)" assert latex(lucas(n)) == r"L_{n}" assert latex(lucas(n)**2) == r"L_{n}^{2}" assert latex(tribonacci(n)) == r"T_{n}" assert latex(tribonacci(n, x)) == r"T_{n}\left(x\right)" assert latex(tribonacci(n)**2) == r"T_{n}^{2}" assert latex(tribonacci(n, x)**2) == r"T_{n}^{2}\left(x\right)" def test_latex_euler(): assert latex(euler(n)) == r"E_{n}" assert latex(euler(n, x)) == r"E_{n}\left(x\right)" assert latex(euler(n, x)**2) == r"E_{n}^{2}\left(x\right)" def test_lamda(): assert latex(Symbol('lamda')) == r"\lambda" assert latex(Symbol('Lamda')) == r"\Lambda" def test_custom_symbol_names(): x = Symbol('x') y = Symbol('y') assert latex(x) == r"x" assert latex(x, symbol_names={x: "x_i"}) == r"x_i" assert latex(x + y, symbol_names={x: "x_i"}) == r"x_i + y" assert latex(x**2, symbol_names={x: "x_i"}) == r"x_i^{2}" assert latex(x + y, symbol_names={x: "x_i", y: "y_j"}) == r"x_i + y_j" def test_matAdd(): from sympy import MatrixSymbol from sympy.printing.latex import LatexPrinter C = MatrixSymbol('C', 5, 5) B = MatrixSymbol('B', 5, 5) l = LatexPrinter() assert l._print(C - 2*B) in [r'- 2 B + C', r'C -2 B'] assert l._print(C + 2*B) in [r'2 B + C', r'C + 2 B'] assert l._print(B - 2*C) in [r'B - 2 C', r'- 2 C + B'] assert l._print(B + 2*C) in [r'B + 2 C', r'2 C + B'] def test_matMul(): from sympy import MatrixSymbol from sympy.printing.latex import LatexPrinter A = MatrixSymbol('A', 5, 5) B = MatrixSymbol('B', 5, 5) x = Symbol('x') lp = LatexPrinter() assert lp._print_MatMul(2*A) == r'2 A' assert lp._print_MatMul(2*x*A) == r'2 x A' assert lp._print_MatMul(-2*A) == r'- 2 A' assert lp._print_MatMul(1.5*A) == r'1.5 A' assert lp._print_MatMul(sqrt(2)*A) == r'\sqrt{2} A' assert lp._print_MatMul(-sqrt(2)*A) == r'- \sqrt{2} A' assert lp._print_MatMul(2*sqrt(2)*x*A) == r'2 \sqrt{2} x A' assert lp._print_MatMul(-2*A*(A + 2*B)) in [r'- 2 A \left(A + 2 B\right)', r'- 2 A \left(2 B + A\right)'] def test_latex_MatrixSlice(): n = Symbol('n', integer=True) x, y, z, w, t, = symbols('x y z w t') X = MatrixSymbol('X', n, n) Y = MatrixSymbol('Y', 10, 10) Z = MatrixSymbol('Z', 10, 10) assert latex(MatrixSlice(X, (None, None, None), (None, None, None))) == r'X\left[:, :\right]' assert latex(X[x:x + 1, y:y + 1]) == r'X\left[x:x + 1, y:y + 1\right]' assert latex(X[x:x + 1:2, y:y + 1:2]) == r'X\left[x:x + 1:2, y:y + 1:2\right]' assert latex(X[:x, y:]) == r'X\left[:x, y:\right]' assert latex(X[:x, y:]) == r'X\left[:x, y:\right]' assert latex(X[x:, :y]) == r'X\left[x:, :y\right]' assert latex(X[x:y, z:w]) == r'X\left[x:y, z:w\right]' assert latex(X[x:y:t, w:t:x]) == r'X\left[x:y:t, w:t:x\right]' assert latex(X[x::y, t::w]) == r'X\left[x::y, t::w\right]' assert latex(X[:x:y, :t:w]) == r'X\left[:x:y, :t:w\right]' assert latex(X[::x, ::y]) == r'X\left[::x, ::y\right]' assert latex(MatrixSlice(X, (0, None, None), (0, None, None))) == r'X\left[:, :\right]' assert latex(MatrixSlice(X, (None, n, None), (None, n, None))) == r'X\left[:, :\right]' assert latex(MatrixSlice(X, (0, n, None), (0, n, None))) == r'X\left[:, :\right]' assert latex(MatrixSlice(X, (0, n, 2), (0, n, 2))) == r'X\left[::2, ::2\right]' assert latex(X[1:2:3, 4:5:6]) == r'X\left[1:2:3, 4:5:6\right]' assert latex(X[1:3:5, 4:6:8]) == r'X\left[1:3:5, 4:6:8\right]' assert latex(X[1:10:2]) == r'X\left[1:10:2, :\right]' assert latex(Y[:5, 1:9:2]) == r'Y\left[:5, 1:9:2\right]' assert latex(Y[:5, 1:10:2]) == r'Y\left[:5, 1::2\right]' assert latex(Y[5, :5:2]) == r'Y\left[5:6, :5:2\right]' assert latex(X[0:1, 0:1]) == r'X\left[:1, :1\right]' assert latex(X[0:1:2, 0:1:2]) == r'X\left[:1:2, :1:2\right]' assert latex((Y + Z)[2:, 2:]) == r'\left(Y + Z\right)\left[2:, 2:\right]' def test_latex_RandomDomain(): from sympy.stats import Normal, Die, Exponential, pspace, where from sympy.stats.rv import RandomDomain X = Normal('x1', 0, 1) assert latex(where(X > 0)) == r"\text{Domain: }0 < x_{1} \wedge x_{1} < \infty" D = Die('d1', 6) assert latex(where(D > 4)) == r"\text{Domain: }d_{1} = 5 \vee d_{1} = 6" A = Exponential('a', 1) B = Exponential('b', 1) assert latex( pspace(Tuple(A, B)).domain) == \ r"\text{Domain: }0 \leq a \wedge 0 \leq b \wedge a < \infty \wedge b < \infty" assert latex(RandomDomain(FiniteSet(x), FiniteSet(1, 2))) == \ r'\text{Domain: }\left\{x\right\}\text{ in }\left\{1, 2\right\}' def test_PrettyPoly(): from sympy.polys.domains import QQ F = QQ.frac_field(x, y) R = QQ[x, y] assert latex(F.convert(x/(x + y))) == latex(x/(x + y)) assert latex(R.convert(x + y)) == latex(x + y) def test_integral_transforms(): x = Symbol("x") k = Symbol("k") f = Function("f") a = Symbol("a") b = Symbol("b") assert latex(MellinTransform(f(x), x, k)) == \ r"\mathcal{M}_{x}\left[f{\left(x \right)}\right]\left(k\right)" assert latex(InverseMellinTransform(f(k), k, x, a, b)) == \ r"\mathcal{M}^{-1}_{k}\left[f{\left(k \right)}\right]\left(x\right)" assert latex(LaplaceTransform(f(x), x, k)) == \ r"\mathcal{L}_{x}\left[f{\left(x \right)}\right]\left(k\right)" assert latex(InverseLaplaceTransform(f(k), k, x, (a, b))) == \ r"\mathcal{L}^{-1}_{k}\left[f{\left(k \right)}\right]\left(x\right)" assert latex(FourierTransform(f(x), x, k)) == \ r"\mathcal{F}_{x}\left[f{\left(x \right)}\right]\left(k\right)" assert latex(InverseFourierTransform(f(k), k, x)) == \ r"\mathcal{F}^{-1}_{k}\left[f{\left(k \right)}\right]\left(x\right)" assert latex(CosineTransform(f(x), x, k)) == \ r"\mathcal{COS}_{x}\left[f{\left(x \right)}\right]\left(k\right)" assert latex(InverseCosineTransform(f(k), k, x)) == \ r"\mathcal{COS}^{-1}_{k}\left[f{\left(k \right)}\right]\left(x\right)" assert latex(SineTransform(f(x), x, k)) == \ r"\mathcal{SIN}_{x}\left[f{\left(x \right)}\right]\left(k\right)" assert latex(InverseSineTransform(f(k), k, x)) == \ r"\mathcal{SIN}^{-1}_{k}\left[f{\left(k \right)}\right]\left(x\right)" def test_PolynomialRingBase(): from sympy.polys.domains import QQ assert latex(QQ.old_poly_ring(x, y)) == r"\mathbb{Q}\left[x, y\right]" assert latex(QQ.old_poly_ring(x, y, order="ilex")) == \ r"S_<^{-1}\mathbb{Q}\left[x, y\right]" def test_categories(): from sympy.categories import (Object, IdentityMorphism, NamedMorphism, Category, Diagram, DiagramGrid) A1 = Object("A1") A2 = Object("A2") A3 = Object("A3") f1 = NamedMorphism(A1, A2, "f1") f2 = NamedMorphism(A2, A3, "f2") id_A1 = IdentityMorphism(A1) K1 = Category("K1") assert latex(A1) == r"A_{1}" assert latex(f1) == r"f_{1}:A_{1}\rightarrow A_{2}" assert latex(id_A1) == r"id:A_{1}\rightarrow A_{1}" assert latex(f2*f1) == r"f_{2}\circ f_{1}:A_{1}\rightarrow A_{3}" assert latex(K1) == r"\mathbf{K_{1}}" d = Diagram() assert latex(d) == r"\emptyset" d = Diagram({f1: "unique", f2: S.EmptySet}) assert latex(d) == r"\left\{ f_{2}\circ f_{1}:A_{1}" \ r"\rightarrow A_{3} : \emptyset, \ id:A_{1}\rightarrow " \ r"A_{1} : \emptyset, \ id:A_{2}\rightarrow A_{2} : " \ r"\emptyset, \ id:A_{3}\rightarrow A_{3} : \emptyset, " \ r"\ f_{1}:A_{1}\rightarrow A_{2} : \left\{unique\right\}, " \ r"\ f_{2}:A_{2}\rightarrow A_{3} : \emptyset\right\}" d = Diagram({f1: "unique", f2: S.EmptySet}, {f2 * f1: "unique"}) assert latex(d) == r"\left\{ f_{2}\circ f_{1}:A_{1}" \ r"\rightarrow A_{3} : \emptyset, \ id:A_{1}\rightarrow " \ r"A_{1} : \emptyset, \ id:A_{2}\rightarrow A_{2} : " \ r"\emptyset, \ id:A_{3}\rightarrow A_{3} : \emptyset, " \ r"\ f_{1}:A_{1}\rightarrow A_{2} : \left\{unique\right\}," \ r" \ f_{2}:A_{2}\rightarrow A_{3} : \emptyset\right\}" \ r"\Longrightarrow \left\{ f_{2}\circ f_{1}:A_{1}" \ r"\rightarrow A_{3} : \left\{unique\right\}\right\}" # A linear diagram. A = Object("A") B = Object("B") C = Object("C") f = NamedMorphism(A, B, "f") g = NamedMorphism(B, C, "g") d = Diagram([f, g]) grid = DiagramGrid(d) assert latex(grid) == r"\begin{array}{cc}" + "\n" \ r"A & B \\" + "\n" \ r" & C " + "\n" \ r"\end{array}" + "\n" def test_Modules(): from sympy.polys.domains import QQ from sympy.polys.agca import homomorphism R = QQ.old_poly_ring(x, y) F = R.free_module(2) M = F.submodule([x, y], [1, x**2]) assert latex(F) == r"{\mathbb{Q}\left[x, y\right]}^{2}" assert latex(M) == \ r"\left\langle {\left[ {x},{y} \right]},{\left[ {1},{x^{2}} \right]} \right\rangle" I = R.ideal(x**2, y) assert latex(I) == r"\left\langle {x^{2}},{y} \right\rangle" Q = F / M assert latex(Q) == \ r"\frac{{\mathbb{Q}\left[x, y\right]}^{2}}{\left\langle {\left[ {x},"\ r"{y} \right]},{\left[ {1},{x^{2}} \right]} \right\rangle}" assert latex(Q.submodule([1, x**3/2], [2, y])) == \ r"\left\langle {{\left[ {1},{\frac{x^{3}}{2}} \right]} + {\left"\ r"\langle {\left[ {x},{y} \right]},{\left[ {1},{x^{2}} \right]} "\ r"\right\rangle}},{{\left[ {2},{y} \right]} + {\left\langle {\left[ "\ r"{x},{y} \right]},{\left[ {1},{x^{2}} \right]} \right\rangle}} \right\rangle" h = homomorphism(QQ.old_poly_ring(x).free_module(2), QQ.old_poly_ring(x).free_module(2), [0, 0]) assert latex(h) == \ r"{\left[\begin{matrix}0 & 0\\0 & 0\end{matrix}\right]} : "\ r"{{\mathbb{Q}\left[x\right]}^{2}} \to {{\mathbb{Q}\left[x\right]}^{2}}" def test_QuotientRing(): from sympy.polys.domains import QQ R = QQ.old_poly_ring(x)/[x**2 + 1] assert latex(R) == \ r"\frac{\mathbb{Q}\left[x\right]}{\left\langle {x^{2} + 1} \right\rangle}" assert latex(R.one) == r"{1} + {\left\langle {x^{2} + 1} \right\rangle}" def test_Tr(): #TODO: Handle indices A, B = symbols('A B', commutative=False) t = Tr(A*B) assert latex(t) == r'\operatorname{tr}\left(A B\right)' def test_Adjoint(): from sympy.matrices import MatrixSymbol, Adjoint, Inverse, Transpose X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) assert latex(Adjoint(X)) == r'X^{\dagger}' assert latex(Adjoint(X + Y)) == r'\left(X + Y\right)^{\dagger}' assert latex(Adjoint(X) + Adjoint(Y)) == r'X^{\dagger} + Y^{\dagger}' assert latex(Adjoint(X*Y)) == r'\left(X Y\right)^{\dagger}' assert latex(Adjoint(Y)*Adjoint(X)) == r'Y^{\dagger} X^{\dagger}' assert latex(Adjoint(X**2)) == r'\left(X^{2}\right)^{\dagger}' assert latex(Adjoint(X)**2) == r'\left(X^{\dagger}\right)^{2}' assert latex(Adjoint(Inverse(X))) == r'\left(X^{-1}\right)^{\dagger}' assert latex(Inverse(Adjoint(X))) == r'\left(X^{\dagger}\right)^{-1}' assert latex(Adjoint(Transpose(X))) == r'\left(X^{T}\right)^{\dagger}' assert latex(Transpose(Adjoint(X))) == r'\left(X^{\dagger}\right)^{T}' assert latex(Transpose(Adjoint(X) + Y)) == r'\left(X^{\dagger} + Y\right)^{T}' def test_Transpose(): from sympy.matrices import Transpose, MatPow, HadamardPower X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) assert latex(Transpose(X)) == r'X^{T}' assert latex(Transpose(X + Y)) == r'\left(X + Y\right)^{T}' assert latex(Transpose(HadamardPower(X, 2))) == r'\left(X^{\circ {2}}\right)^{T}' assert latex(HadamardPower(Transpose(X), 2)) == r'\left(X^{T}\right)^{\circ {2}}' assert latex(Transpose(MatPow(X, 2))) == r'\left(X^{2}\right)^{T}' assert latex(MatPow(Transpose(X), 2)) == r'\left(X^{T}\right)^{2}' def test_Hadamard(): from sympy.matrices import MatrixSymbol, HadamardProduct, HadamardPower from sympy.matrices.expressions import MatAdd, MatMul, MatPow X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) assert latex(HadamardProduct(X, Y*Y)) == r'X \circ Y^{2}' assert latex(HadamardProduct(X, Y)*Y) == r'\left(X \circ Y\right) Y' assert latex(HadamardPower(X, 2)) == r'X^{\circ {2}}' assert latex(HadamardPower(X, -1)) == r'X^{\circ \left({-1}\right)}' assert latex(HadamardPower(MatAdd(X, Y), 2)) == \ r'\left(X + Y\right)^{\circ {2}}' assert latex(HadamardPower(MatMul(X, Y), 2)) == \ r'\left(X Y\right)^{\circ {2}}' assert latex(HadamardPower(MatPow(X, -1), -1)) == \ r'\left(X^{-1}\right)^{\circ \left({-1}\right)}' assert latex(MatPow(HadamardPower(X, -1), -1)) == \ r'\left(X^{\circ \left({-1}\right)}\right)^{-1}' assert latex(HadamardPower(X, n+1)) == \ r'X^{\circ \left({n + 1}\right)}' def test_ElementwiseApplyFunction(): from sympy.matrices import MatrixSymbol X = MatrixSymbol('X', 2, 2) expr = (X.T*X).applyfunc(sin) assert latex(expr) == r"{\left( d \mapsto \sin{\left(d \right)} \right)}_{\circ}\left({X^{T} X}\right)" expr = X.applyfunc(Lambda(x, 1/x)) assert latex(expr) == r'{\left( x \mapsto \frac{1}{x} \right)}_{\circ}\left({X}\right)' def test_ZeroMatrix(): from sympy import ZeroMatrix assert latex(ZeroMatrix(1, 1), mat_symbol_style='plain') == r"\mathbb{0}" assert latex(ZeroMatrix(1, 1), mat_symbol_style='bold') == r"\mathbf{0}" def test_OneMatrix(): from sympy import OneMatrix assert latex(OneMatrix(3, 4), mat_symbol_style='plain') == r"\mathbb{1}" assert latex(OneMatrix(3, 4), mat_symbol_style='bold') == r"\mathbf{1}" def test_Identity(): from sympy import Identity assert latex(Identity(1), mat_symbol_style='plain') == r"\mathbb{I}" assert latex(Identity(1), mat_symbol_style='bold') == r"\mathbf{I}" def test_boolean_args_order(): syms = symbols('a:f') expr = And(*syms) assert latex(expr) == r'a \wedge b \wedge c \wedge d \wedge e \wedge f' expr = Or(*syms) assert latex(expr) == r'a \vee b \vee c \vee d \vee e \vee f' expr = Equivalent(*syms) assert latex(expr) == \ r'a \Leftrightarrow b \Leftrightarrow c \Leftrightarrow d \Leftrightarrow e \Leftrightarrow f' expr = Xor(*syms) assert latex(expr) == \ r'a \veebar b \veebar c \veebar d \veebar e \veebar f' def test_imaginary(): i = sqrt(-1) assert latex(i) == r'i' def test_builtins_without_args(): assert latex(sin) == r'\sin' assert latex(cos) == r'\cos' assert latex(tan) == r'\tan' assert latex(log) == r'\log' assert latex(Ei) == r'\operatorname{Ei}' assert latex(zeta) == r'\zeta' def test_latex_greek_functions(): # bug because capital greeks that have roman equivalents should not use # \Alpha, \Beta, \Eta, etc. s = Function('Alpha') assert latex(s) == r'A' assert latex(s(x)) == r'A{\left(x \right)}' s = Function('Beta') assert latex(s) == r'B' s = Function('Eta') assert latex(s) == r'H' assert latex(s(x)) == r'H{\left(x \right)}' # bug because sympy.core.numbers.Pi is special p = Function('Pi') # assert latex(p(x)) == r'\Pi{\left(x \right)}' assert latex(p) == r'\Pi' # bug because not all greeks are included c = Function('chi') assert latex(c(x)) == r'\chi{\left(x \right)}' assert latex(c) == r'\chi' def test_translate(): s = 'Alpha' assert translate(s) == r'A' s = 'Beta' assert translate(s) == r'B' s = 'Eta' assert translate(s) == r'H' s = 'omicron' assert translate(s) == r'o' s = 'Pi' assert translate(s) == r'\Pi' s = 'pi' assert translate(s) == r'\pi' s = 'LamdaHatDOT' assert translate(s) == r'\dot{\hat{\Lambda}}' def test_other_symbols(): from sympy.printing.latex import other_symbols for s in other_symbols: assert latex(symbols(s)) == r"" "\\" + s def test_modifiers(): # Test each modifier individually in the simplest case # (with funny capitalizations) assert latex(symbols("xMathring")) == r"\mathring{x}" assert latex(symbols("xCheck")) == r"\check{x}" assert latex(symbols("xBreve")) == r"\breve{x}" assert latex(symbols("xAcute")) == r"\acute{x}" assert latex(symbols("xGrave")) == r"\grave{x}" assert latex(symbols("xTilde")) == r"\tilde{x}" assert latex(symbols("xPrime")) == r"{x}'" assert latex(symbols("xddDDot")) == r"\ddddot{x}" assert latex(symbols("xDdDot")) == r"\dddot{x}" assert latex(symbols("xDDot")) == r"\ddot{x}" assert latex(symbols("xBold")) == r"\boldsymbol{x}" assert latex(symbols("xnOrM")) == r"\left\|{x}\right\|" assert latex(symbols("xAVG")) == r"\left\langle{x}\right\rangle" assert latex(symbols("xHat")) == r"\hat{x}" assert latex(symbols("xDot")) == r"\dot{x}" assert latex(symbols("xBar")) == r"\bar{x}" assert latex(symbols("xVec")) == r"\vec{x}" assert latex(symbols("xAbs")) == r"\left|{x}\right|" assert latex(symbols("xMag")) == r"\left|{x}\right|" assert latex(symbols("xPrM")) == r"{x}'" assert latex(symbols("xBM")) == r"\boldsymbol{x}" # Test strings that are *only* the names of modifiers assert latex(symbols("Mathring")) == r"Mathring" assert latex(symbols("Check")) == r"Check" assert latex(symbols("Breve")) == r"Breve" assert latex(symbols("Acute")) == r"Acute" assert latex(symbols("Grave")) == r"Grave" assert latex(symbols("Tilde")) == r"Tilde" assert latex(symbols("Prime")) == r"Prime" assert latex(symbols("DDot")) == r"\dot{D}" assert latex(symbols("Bold")) == r"Bold" assert latex(symbols("NORm")) == r"NORm" assert latex(symbols("AVG")) == r"AVG" assert latex(symbols("Hat")) == r"Hat" assert latex(symbols("Dot")) == r"Dot" assert latex(symbols("Bar")) == r"Bar" assert latex(symbols("Vec")) == r"Vec" assert latex(symbols("Abs")) == r"Abs" assert latex(symbols("Mag")) == r"Mag" assert latex(symbols("PrM")) == r"PrM" assert latex(symbols("BM")) == r"BM" assert latex(symbols("hbar")) == r"\hbar" # Check a few combinations assert latex(symbols("xvecdot")) == r"\dot{\vec{x}}" assert latex(symbols("xDotVec")) == r"\vec{\dot{x}}" assert latex(symbols("xHATNorm")) == r"\left\|{\hat{x}}\right\|" # Check a couple big, ugly combinations assert latex(symbols('xMathringBm_yCheckPRM__zbreveAbs')) == \ r"\boldsymbol{\mathring{x}}^{\left|{\breve{z}}\right|}_{{\check{y}}'}" assert latex(symbols('alphadothat_nVECDOT__tTildePrime')) == \ r"\hat{\dot{\alpha}}^{{\tilde{t}}'}_{\dot{\vec{n}}}" def test_greek_symbols(): assert latex(Symbol('alpha')) == r'\alpha' assert latex(Symbol('beta')) == r'\beta' assert latex(Symbol('gamma')) == r'\gamma' assert latex(Symbol('delta')) == r'\delta' assert latex(Symbol('epsilon')) == r'\epsilon' assert latex(Symbol('zeta')) == r'\zeta' assert latex(Symbol('eta')) == r'\eta' assert latex(Symbol('theta')) == r'\theta' assert latex(Symbol('iota')) == r'\iota' assert latex(Symbol('kappa')) == r'\kappa' assert latex(Symbol('lambda')) == r'\lambda' assert latex(Symbol('mu')) == r'\mu' assert latex(Symbol('nu')) == r'\nu' assert latex(Symbol('xi')) == r'\xi' assert latex(Symbol('omicron')) == r'o' assert latex(Symbol('pi')) == r'\pi' assert latex(Symbol('rho')) == r'\rho' assert latex(Symbol('sigma')) == r'\sigma' assert latex(Symbol('tau')) == r'\tau' assert latex(Symbol('upsilon')) == r'\upsilon' assert latex(Symbol('phi')) == r'\phi' assert latex(Symbol('chi')) == r'\chi' assert latex(Symbol('psi')) == r'\psi' assert latex(Symbol('omega')) == r'\omega' assert latex(Symbol('Alpha')) == r'A' assert latex(Symbol('Beta')) == r'B' assert latex(Symbol('Gamma')) == r'\Gamma' assert latex(Symbol('Delta')) == r'\Delta' assert latex(Symbol('Epsilon')) == r'E' assert latex(Symbol('Zeta')) == r'Z' assert latex(Symbol('Eta')) == r'H' assert latex(Symbol('Theta')) == r'\Theta' assert latex(Symbol('Iota')) == r'I' assert latex(Symbol('Kappa')) == r'K' assert latex(Symbol('Lambda')) == r'\Lambda' assert latex(Symbol('Mu')) == r'M' assert latex(Symbol('Nu')) == r'N' assert latex(Symbol('Xi')) == r'\Xi' assert latex(Symbol('Omicron')) == r'O' assert latex(Symbol('Pi')) == r'\Pi' assert latex(Symbol('Rho')) == r'P' assert latex(Symbol('Sigma')) == r'\Sigma' assert latex(Symbol('Tau')) == r'T' assert latex(Symbol('Upsilon')) == r'\Upsilon' assert latex(Symbol('Phi')) == r'\Phi' assert latex(Symbol('Chi')) == r'X' assert latex(Symbol('Psi')) == r'\Psi' assert latex(Symbol('Omega')) == r'\Omega' assert latex(Symbol('varepsilon')) == r'\varepsilon' assert latex(Symbol('varkappa')) == r'\varkappa' assert latex(Symbol('varphi')) == r'\varphi' assert latex(Symbol('varpi')) == r'\varpi' assert latex(Symbol('varrho')) == r'\varrho' assert latex(Symbol('varsigma')) == r'\varsigma' assert latex(Symbol('vartheta')) == r'\vartheta' def test_fancyset_symbols(): assert latex(S.Rationals) == r'\mathbb{Q}' assert latex(S.Naturals) == r'\mathbb{N}' assert latex(S.Naturals0) == r'\mathbb{N}_0' assert latex(S.Integers) == r'\mathbb{Z}' assert latex(S.Reals) == r'\mathbb{R}' assert latex(S.Complexes) == r'\mathbb{C}' @XFAIL def test_builtin_without_args_mismatched_names(): assert latex(CosineTransform) == r'\mathcal{COS}' def test_builtin_no_args(): assert latex(Chi) == r'\operatorname{Chi}' assert latex(beta) == r'\operatorname{B}' assert latex(gamma) == r'\Gamma' assert latex(KroneckerDelta) == r'\delta' assert latex(DiracDelta) == r'\delta' assert latex(lowergamma) == r'\gamma' def test_issue_6853(): p = Function('Pi') assert latex(p(x)) == r"\Pi{\left(x \right)}" def test_Mul(): e = Mul(-2, x + 1, evaluate=False) assert latex(e) == r'- 2 \left(x + 1\right)' e = Mul(2, x + 1, evaluate=False) assert latex(e) == r'2 \left(x + 1\right)' e = Mul(S.Half, x + 1, evaluate=False) assert latex(e) == r'\frac{x + 1}{2}' e = Mul(y, x + 1, evaluate=False) assert latex(e) == r'y \left(x + 1\right)' e = Mul(-y, x + 1, evaluate=False) assert latex(e) == r'- y \left(x + 1\right)' e = Mul(-2, x + 1) assert latex(e) == r'- 2 x - 2' e = Mul(2, x + 1) assert latex(e) == r'2 x + 2' def test_Pow(): e = Pow(2, 2, evaluate=False) assert latex(e) == r'2^{2}' assert latex(x**(Rational(-1, 3))) == r'\frac{1}{\sqrt[3]{x}}' x2 = Symbol(r'x^2') assert latex(x2**2) == r'\left(x^{2}\right)^{2}' def test_issue_7180(): assert latex(Equivalent(x, y)) == r"x \Leftrightarrow y" assert latex(Not(Equivalent(x, y))) == r"x \not\Leftrightarrow y" def test_issue_8409(): assert latex(S.Half**n) == r"\left(\frac{1}{2}\right)^{n}" def test_issue_8470(): from sympy.parsing.sympy_parser import parse_expr e = parse_expr("-B*A", evaluate=False) assert latex(e) == r"A \left(- B\right)" def test_issue_15439(): x = MatrixSymbol('x', 2, 2) y = MatrixSymbol('y', 2, 2) assert latex((x * y).subs(y, -y)) == r"x \left(- y\right)" assert latex((x * y).subs(y, -2*y)) == r"x \left(- 2 y\right)" assert latex((x * y).subs(x, -x)) == r"- x y" def test_issue_2934(): assert latex(Symbol(r'\frac{a_1}{b_1}')) == r'\frac{a_1}{b_1}' def test_issue_10489(): latexSymbolWithBrace = r'C_{x_{0}}' s = Symbol(latexSymbolWithBrace) assert latex(s) == latexSymbolWithBrace assert latex(cos(s)) == r'\cos{\left(C_{x_{0}} \right)}' def test_issue_12886(): m__1, l__1 = symbols('m__1, l__1') assert latex(m__1**2 + l__1**2) == \ r'\left(l^{1}\right)^{2} + \left(m^{1}\right)^{2}' def test_issue_13559(): from sympy.parsing.sympy_parser import parse_expr expr = parse_expr('5/1', evaluate=False) assert latex(expr) == r"\frac{5}{1}" def test_issue_13651(): expr = c + Mul(-1, a + b, evaluate=False) assert latex(expr) == r"c - \left(a + b\right)" def test_latex_UnevaluatedExpr(): x = symbols("x") he = UnevaluatedExpr(1/x) assert latex(he) == latex(1/x) == r"\frac{1}{x}" assert latex(he**2) == r"\left(\frac{1}{x}\right)^{2}" assert latex(he + 1) == r"1 + \frac{1}{x}" assert latex(x*he) == r"x \frac{1}{x}" def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert latex(A[0, 0]) == r"A_{0, 0}" assert latex(3 * A[0, 0]) == r"3 A_{0, 0}" F = C[0, 0].subs(C, A - B) assert latex(F) == r"\left(A - B\right)_{0, 0}" i, j, k = symbols("i j k") M = MatrixSymbol("M", k, k) N = MatrixSymbol("N", k, k) assert latex((M*N)[i, j]) == \ r'\sum_{i_{1}=0}^{k - 1} M_{i, i_{1}} N_{i_{1}, j}' def test_MatrixSymbol_printing(): # test cases for issue #14237 A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) C = MatrixSymbol("C", 3, 3) assert latex(-A) == r"- A" assert latex(A - A*B - B) == r"A - A B - B" assert latex(-A*B - A*B*C - B) == r"- A B - A B C - B" def test_KroneckerProduct_printing(): A = MatrixSymbol('A', 3, 3) B = MatrixSymbol('B', 2, 2) assert latex(KroneckerProduct(A, B)) == r'A \otimes B' def test_Series_printing(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y) assert latex(Series(tf1, tf2)) == \ r'\left(\frac{x y^{2} - z}{- t^{3} + y^{3}}\right) \left(\frac{x - y}{x + y}\right)' assert latex(Series(tf1, tf2, tf3)) == \ r'\left(\frac{x y^{2} - z}{- t^{3} + y^{3}}\right) \left(\frac{x - y}{x + y}\right) \left(\frac{t x^{2} - t^{w} x + w}{t - y}\right)' assert latex(Series(-tf2, tf1)) == \ r'\left(\frac{- x + y}{x + y}\right) \left(\frac{x y^{2} - z}{- t^{3} + y^{3}}\right)' M_1 = Matrix([[5/s], [5/(2*s)]]) T_1 = TransferFunctionMatrix.from_Matrix(M_1, s) M_2 = Matrix([[5, 6*s**3]]) T_2 = TransferFunctionMatrix.from_Matrix(M_2, s) # Brackets assert latex(T_1*(T_2 + T_2)) == \ r'\left[\begin{matrix}\frac{5}{s}\\\frac{5}{2 s}\end{matrix}\right]_\tau\cdot\left(\left[\begin{matrix}\frac{5}{1} &' \ r' \frac{6 s^{3}}{1}\end{matrix}\right]_\tau + \left[\begin{matrix}\frac{5}{1} & \frac{6 s^{3}}{1}\end{matrix}\right]_\tau\right)' \ == latex(MIMOSeries(MIMOParallel(T_2, T_2), T_1)) # No Brackets M_3 = Matrix([[5, 6], [6, 5/s]]) T_3 = TransferFunctionMatrix.from_Matrix(M_3, s) assert latex(T_1*T_2 + T_3) == r'\left[\begin{matrix}\frac{5}{s}\\\frac{5}{2 s}\end{matrix}\right]_\tau\cdot\left[\begin{matrix}' \ r'\frac{5}{1} & \frac{6 s^{3}}{1}\end{matrix}\right]_\tau + \left[\begin{matrix}\frac{5}{1} & \frac{6}{1}\\\frac{6}{1} & ' \ r'\frac{5}{s}\end{matrix}\right]_\tau' == latex(MIMOParallel(MIMOSeries(T_2, T_1), T_3)) def test_TransferFunction_printing(): tf1 = TransferFunction(x - 1, x + 1, x) assert latex(tf1) == r"\frac{x - 1}{x + 1}" tf2 = TransferFunction(x + 1, 2 - y, x) assert latex(tf2) == r"\frac{x + 1}{2 - y}" tf3 = TransferFunction(y, y**2 + 2*y + 3, y) assert latex(tf3) == r"\frac{y}{y^{2} + 2 y + 3}" def test_Parallel_printing(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) assert latex(Parallel(tf1, tf2)) == \ r'\frac{x y^{2} - z}{- t^{3} + y^{3}} + \frac{x - y}{x + y}' assert latex(Parallel(-tf2, tf1)) == \ r'\frac{- x + y}{x + y} + \frac{x y^{2} - z}{- t^{3} + y^{3}}' M_1 = Matrix([[5, 6], [6, 5/s]]) T_1 = TransferFunctionMatrix.from_Matrix(M_1, s) M_2 = Matrix([[5/s, 6], [6, 5/(s - 1)]]) T_2 = TransferFunctionMatrix.from_Matrix(M_2, s) M_3 = Matrix([[6, 5/(s*(s - 1))], [5, 6]]) T_3 = TransferFunctionMatrix.from_Matrix(M_3, s) assert latex(T_1 + T_2 + T_3) == r'\left[\begin{matrix}\frac{5}{1} & \frac{6}{1}\\\frac{6}{1} & \frac{5}{s}\end{matrix}\right]' \ r'_\tau + \left[\begin{matrix}\frac{5}{s} & \frac{6}{1}\\\frac{6}{1} & \frac{5}{s - 1}\end{matrix}\right]_\tau + \left[\begin{matrix}' \ r'\frac{6}{1} & \frac{5}{s \left(s - 1\right)}\\\frac{5}{1} & \frac{6}{1}\end{matrix}\right]_\tau' \ == latex(MIMOParallel(T_1, T_2, T_3)) == latex(MIMOParallel(T_1, MIMOParallel(T_2, T_3))) == latex(MIMOParallel(MIMOParallel(T_1, T_2), T_3)) def test_TransferFunctionMatrix_printing(): tf1 = TransferFunction(p, p + x, p) tf2 = TransferFunction(-s + p, p + s, p) tf3 = TransferFunction(p, y**2 + 2*y + 3, p) assert latex(TransferFunctionMatrix([[tf1], [tf2]])) == \ r'\left[\begin{matrix}\frac{p}{p + x}\\\frac{p - s}{p + s}\end{matrix}\right]_\tau' assert latex(TransferFunctionMatrix([[tf1, tf2], [tf3, -tf1]])) == \ r'\left[\begin{matrix}\frac{p}{p + x} & \frac{p - s}{p + s}\\\frac{p}{y^{2} + 2 y + 3} & \frac{\left(-1\right) p}{p + x}\end{matrix}\right]_\tau' def test_Feedback_printing(): tf1 = TransferFunction(p, p + x, p) tf2 = TransferFunction(-s + p, p + s, p) # Negative Feedback (Default) assert latex(Feedback(tf1, tf2)) == \ r'\frac{\frac{p}{p + x}}{\frac{1}{1} + \left(\frac{p}{p + x}\right) \left(\frac{p - s}{p + s}\right)}' assert latex(Feedback(tf1*tf2, TransferFunction(1, 1, p))) == \ r'\frac{\left(\frac{p}{p + x}\right) \left(\frac{p - s}{p + s}\right)}{\frac{1}{1} + \left(\frac{p}{p + x}\right) \left(\frac{p - s}{p + s}\right)}' # Positive Feedback assert latex(Feedback(tf1, tf2, 1)) == \ r'\frac{\frac{p}{p + x}}{\frac{1}{1} - \left(\frac{p}{p + x}\right) \left(\frac{p - s}{p + s}\right)}' assert latex(Feedback(tf1*tf2, sign=1)) == \ r'\frac{\left(\frac{p}{p + x}\right) \left(\frac{p - s}{p + s}\right)}{\frac{1}{1} - \left(\frac{p}{p + x}\right) \left(\frac{p - s}{p + s}\right)}' def test_MIMOFeedback_printing(): tf1 = TransferFunction(1, s, s) tf2 = TransferFunction(s, s**2 - 1, s) tf3 = TransferFunction(s, s - 1, s) tf4 = TransferFunction(s**2, s**2 - 1, s) tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf3, tf4]]) tfm_2 = TransferFunctionMatrix([[tf4, tf3], [tf2, tf1]]) # Negative Feedback (Default) assert latex(MIMOFeedback(tfm_1, tfm_2)) == \ r'\left(I_{\tau} + \left[\begin{matrix}\frac{1}{s} & \frac{s}{s^{2} - 1}\\\frac{s}{s - 1} & \frac{s^{2}}{s^{2} - 1}\end{matrix}\right]_\tau\cdot\left[' \ r'\begin{matrix}\frac{s^{2}}{s^{2} - 1} & \frac{s}{s - 1}\\\frac{s}{s^{2} - 1} & \frac{1}{s}\end{matrix}\right]_\tau\right)^{-1} \cdot \left[\begin{matrix}' \ r'\frac{1}{s} & \frac{s}{s^{2} - 1}\\\frac{s}{s - 1} & \frac{s^{2}}{s^{2} - 1}\end{matrix}\right]_\tau' # Positive Feedback assert latex(MIMOFeedback(tfm_1*tfm_2, tfm_1, 1)) == \ r'\left(I_{\tau} - \left[\begin{matrix}\frac{1}{s} & \frac{s}{s^{2} - 1}\\\frac{s}{s - 1} & \frac{s^{2}}{s^{2} - 1}\end{matrix}\right]_\tau\cdot\left' \ r'[\begin{matrix}\frac{s^{2}}{s^{2} - 1} & \frac{s}{s - 1}\\\frac{s}{s^{2} - 1} & \frac{1}{s}\end{matrix}\right]_\tau\cdot\left[\begin{matrix}\frac{1}{s} & \frac{s}{s^{2} - 1}' \ r'\\\frac{s}{s - 1} & \frac{s^{2}}{s^{2} - 1}\end{matrix}\right]_\tau\right)^{-1} \cdot \left[\begin{matrix}\frac{1}{s} & \frac{s}{s^{2} - 1}' \ r'\\\frac{s}{s - 1} & \frac{s^{2}}{s^{2} - 1}\end{matrix}\right]_\tau\cdot\left[\begin{matrix}\frac{s^{2}}{s^{2} - 1} & \frac{s}{s - 1}\\\frac{s}{s^{2} - 1}' \ r' & \frac{1}{s}\end{matrix}\right]_\tau' def test_Quaternion_latex_printing(): q = Quaternion(x, y, z, t) assert latex(q) == r"x + y i + z j + t k" q = Quaternion(x, y, z, x*t) assert latex(q) == r"x + y i + z j + t x k" q = Quaternion(x, y, z, x + t) assert latex(q) == r"x + y i + z j + \left(t + x\right) k" def test_TensorProduct_printing(): from sympy.tensor.functions import TensorProduct A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) assert latex(TensorProduct(A, B)) == r"A \otimes B" def test_WedgeProduct_printing(): from sympy.diffgeom.rn import R2 from sympy.diffgeom import WedgeProduct wp = WedgeProduct(R2.dx, R2.dy) assert latex(wp) == r"\operatorname{d}x \wedge \operatorname{d}y" def test_issue_9216(): expr_1 = Pow(1, -1, evaluate=False) assert latex(expr_1) == r"1^{-1}" expr_2 = Pow(1, Pow(1, -1, evaluate=False), evaluate=False) assert latex(expr_2) == r"1^{1^{-1}}" expr_3 = Pow(3, -2, evaluate=False) assert latex(expr_3) == r"\frac{1}{9}" expr_4 = Pow(1, -2, evaluate=False) assert latex(expr_4) == r"1^{-2}" def test_latex_printer_tensor(): from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, tensor_heads L = TensorIndexType("L") i, j, k, l = tensor_indices("i j k l", L) i0 = tensor_indices("i_0", L) A, B, C, D = tensor_heads("A B C D", [L]) H = TensorHead("H", [L, L]) K = TensorHead("K", [L, L, L, L]) assert latex(i) == r"{}^{i}" assert latex(-i) == r"{}_{i}" expr = A(i) assert latex(expr) == r"A{}^{i}" expr = A(i0) assert latex(expr) == r"A{}^{i_{0}}" expr = A(-i) assert latex(expr) == r"A{}_{i}" expr = -3*A(i) assert latex(expr) == r"-3A{}^{i}" expr = K(i, j, -k, -i0) assert latex(expr) == r"K{}^{ij}{}_{ki_{0}}" expr = K(i, -j, -k, i0) assert latex(expr) == r"K{}^{i}{}_{jk}{}^{i_{0}}" expr = K(i, -j, k, -i0) assert latex(expr) == r"K{}^{i}{}_{j}{}^{k}{}_{i_{0}}" expr = H(i, -j) assert latex(expr) == r"H{}^{i}{}_{j}" expr = H(i, j) assert latex(expr) == r"H{}^{ij}" expr = H(-i, -j) assert latex(expr) == r"H{}_{ij}" expr = (1+x)*A(i) assert latex(expr) == r"\left(x + 1\right)A{}^{i}" expr = H(i, -i) assert latex(expr) == r"H{}^{L_{0}}{}_{L_{0}}" expr = H(i, -j)*A(j)*B(k) assert latex(expr) == r"H{}^{i}{}_{L_{0}}A{}^{L_{0}}B{}^{k}" expr = A(i) + 3*B(i) assert latex(expr) == r"3B{}^{i} + A{}^{i}" # Test ``TensorElement``: from sympy.tensor.tensor import TensorElement expr = TensorElement(K(i, j, k, l), {i: 3, k: 2}) assert latex(expr) == r'K{}^{i=3,j,k=2,l}' expr = TensorElement(K(i, j, k, l), {i: 3}) assert latex(expr) == r'K{}^{i=3,jkl}' expr = TensorElement(K(i, -j, k, l), {i: 3, k: 2}) assert latex(expr) == r'K{}^{i=3}{}_{j}{}^{k=2,l}' expr = TensorElement(K(i, -j, k, -l), {i: 3, k: 2}) assert latex(expr) == r'K{}^{i=3}{}_{j}{}^{k=2}{}_{l}' expr = TensorElement(K(i, j, -k, -l), {i: 3, -k: 2}) assert latex(expr) == r'K{}^{i=3,j}{}_{k=2,l}' expr = TensorElement(K(i, j, -k, -l), {i: 3}) assert latex(expr) == r'K{}^{i=3,j}{}_{kl}' expr = PartialDerivative(A(i), A(i)) assert latex(expr) == r"\frac{\partial}{\partial {A{}^{L_{0}}}}{A{}^{L_{0}}}" expr = PartialDerivative(A(-i), A(-j)) assert latex(expr) == r"\frac{\partial}{\partial {A{}_{j}}}{A{}_{i}}" expr = PartialDerivative(K(i, j, -k, -l), A(m), A(-n)) assert latex(expr) == r"\frac{\partial^{2}}{\partial {A{}^{m}} \partial {A{}_{n}}}{K{}^{ij}{}_{kl}}" expr = PartialDerivative(B(-i) + A(-i), A(-j), A(-n)) assert latex(expr) == r"\frac{\partial^{2}}{\partial {A{}_{j}} \partial {A{}_{n}}}{\left(A{}_{i} + B{}_{i}\right)}" expr = PartialDerivative(3*A(-i), A(-j), A(-n)) assert latex(expr) == r"\frac{\partial^{2}}{\partial {A{}_{j}} \partial {A{}_{n}}}{\left(3A{}_{i}\right)}" def test_multiline_latex(): a, b, c, d, e, f = symbols('a b c d e f') expr = -a + 2*b -3*c +4*d -5*e expected = r"\begin{eqnarray}" + "\n"\ r"f & = &- a \nonumber\\" + "\n"\ r"& & + 2 b \nonumber\\" + "\n"\ r"& & - 3 c \nonumber\\" + "\n"\ r"& & + 4 d \nonumber\\" + "\n"\ r"& & - 5 e " + "\n"\ r"\end{eqnarray}" assert multiline_latex(f, expr, environment="eqnarray") == expected expected2 = r'\begin{eqnarray}' + '\n'\ r'f & = &- a + 2 b \nonumber\\' + '\n'\ r'& & - 3 c + 4 d \nonumber\\' + '\n'\ r'& & - 5 e ' + '\n'\ r'\end{eqnarray}' assert multiline_latex(f, expr, 2, environment="eqnarray") == expected2 expected3 = r'\begin{eqnarray}' + '\n'\ r'f & = &- a + 2 b - 3 c \nonumber\\'+ '\n'\ r'& & + 4 d - 5 e ' + '\n'\ r'\end{eqnarray}' assert multiline_latex(f, expr, 3, environment="eqnarray") == expected3 expected3dots = r'\begin{eqnarray}' + '\n'\ r'f & = &- a + 2 b - 3 c \dots\nonumber\\'+ '\n'\ r'& & + 4 d - 5 e ' + '\n'\ r'\end{eqnarray}' assert multiline_latex(f, expr, 3, environment="eqnarray", use_dots=True) == expected3dots expected3align = r'\begin{align*}' + '\n'\ r'f = &- a + 2 b - 3 c \\'+ '\n'\ r'& + 4 d - 5 e ' + '\n'\ r'\end{align*}' assert multiline_latex(f, expr, 3) == expected3align assert multiline_latex(f, expr, 3, environment='align*') == expected3align expected2ieee = r'\begin{IEEEeqnarray}{rCl}' + '\n'\ r'f & = &- a + 2 b \nonumber\\' + '\n'\ r'& & - 3 c + 4 d \nonumber\\' + '\n'\ r'& & - 5 e ' + '\n'\ r'\end{IEEEeqnarray}' assert multiline_latex(f, expr, 2, environment="IEEEeqnarray") == expected2ieee raises(ValueError, lambda: multiline_latex(f, expr, environment="foo")) def test_issue_15353(): from sympy import ConditionSet, Tuple, S, sin, cos a, x = symbols('a x') # Obtained from nonlinsolve([(sin(a*x)),cos(a*x)],[x,a]) sol = ConditionSet( Tuple(x, a), Eq(sin(a*x), 0) & Eq(cos(a*x), 0), S.Complexes**2) assert latex(sol) == \ r'\left\{\left( x, \ a\right)\; \middle|\; \left( x, \ a\right) \in ' \ r'\mathbb{C}^{2} \wedge \sin{\left(a x \right)} = 0 \wedge ' \ r'\cos{\left(a x \right)} = 0 \right\}' def test_trace(): # Issue 15303 from sympy import trace A = MatrixSymbol("A", 2, 2) assert latex(trace(A)) == r"\operatorname{tr}\left(A \right)" assert latex(trace(A**2)) == r"\operatorname{tr}\left(A^{2} \right)" def test_print_basic(): # Issue 15303 from sympy import Basic, Expr # dummy class for testing printing where the function is not # implemented in latex.py class UnimplementedExpr(Expr): def __new__(cls, e): return Basic.__new__(cls, e) # dummy function for testing def unimplemented_expr(expr): return UnimplementedExpr(expr).doit() # override class name to use superscript / subscript def unimplemented_expr_sup_sub(expr): result = UnimplementedExpr(expr) result.__class__.__name__ = 'UnimplementedExpr_x^1' return result assert latex(unimplemented_expr(x)) == r'UnimplementedExpr\left(x\right)' assert latex(unimplemented_expr(x**2)) == \ r'UnimplementedExpr\left(x^{2}\right)' assert latex(unimplemented_expr_sup_sub(x)) == \ r'UnimplementedExpr^{1}_{x}\left(x\right)' def test_MatrixSymbol_bold(): # Issue #15871 from sympy import trace A = MatrixSymbol("A", 2, 2) assert latex(trace(A), mat_symbol_style='bold') == \ r"\operatorname{tr}\left(\mathbf{A} \right)" assert latex(trace(A), mat_symbol_style='plain') == \ r"\operatorname{tr}\left(A \right)" A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) C = MatrixSymbol("C", 3, 3) assert latex(-A, mat_symbol_style='bold') == r"- \mathbf{A}" assert latex(A - A*B - B, mat_symbol_style='bold') == \ r"\mathbf{A} - \mathbf{A} \mathbf{B} - \mathbf{B}" assert latex(-A*B - A*B*C - B, mat_symbol_style='bold') == \ r"- \mathbf{A} \mathbf{B} - \mathbf{A} \mathbf{B} \mathbf{C} - \mathbf{B}" A_k = MatrixSymbol("A_k", 3, 3) assert latex(A_k, mat_symbol_style='bold') == r"\mathbf{A}_{k}" A = MatrixSymbol(r"\nabla_k", 3, 3) assert latex(A, mat_symbol_style='bold') == r"\mathbf{\nabla}_{k}" def test_AppliedPermutation(): p = Permutation(0, 1, 2) x = Symbol('x') assert latex(AppliedPermutation(p, x)) == \ r'\sigma_{\left( 0\; 1\; 2\right)}(x)' def test_PermutationMatrix(): p = Permutation(0, 1, 2) assert latex(PermutationMatrix(p)) == r'P_{\left( 0\; 1\; 2\right)}' p = Permutation(0, 3)(1, 2) assert latex(PermutationMatrix(p)) == \ r'P_{\left( 0\; 3\right)\left( 1\; 2\right)}' def test_imaginary_unit(): assert latex(1 + I) == r'1 + i' assert latex(1 + I, imaginary_unit='i') == r'1 + i' assert latex(1 + I, imaginary_unit='j') == r'1 + j' assert latex(1 + I, imaginary_unit='foo') == r'1 + foo' assert latex(I, imaginary_unit="ti") == r'\text{i}' assert latex(I, imaginary_unit="tj") == r'\text{j}' def test_text_re_im(): assert latex(im(x), gothic_re_im=True) == r'\Im{\left(x\right)}' assert latex(im(x), gothic_re_im=False) == r'\operatorname{im}{\left(x\right)}' assert latex(re(x), gothic_re_im=True) == r'\Re{\left(x\right)}' assert latex(re(x), gothic_re_im=False) == r'\operatorname{re}{\left(x\right)}' def test_latex_diffgeom(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField, Differential from sympy.diffgeom.rn import R2 x,y = symbols('x y', real=True) m = Manifold('M', 2) assert latex(m) == r'\text{M}' p = Patch('P', m) assert latex(p) == r'\text{P}_{\text{M}}' rect = CoordSystem('rect', p, [x, y]) assert latex(rect) == r'\text{rect}^{\text{P}}_{\text{M}}' b = BaseScalarField(rect, 0) assert latex(b) == r'\mathbf{x}' g = Function('g') s_field = g(R2.x, R2.y) assert latex(Differential(s_field)) == \ r'\operatorname{d}\left(g{\left(\mathbf{x},\mathbf{y} \right)}\right)' def test_unit_printing(): assert latex(5*meter) == r'5 \text{m}' assert latex(3*gibibyte) == r'3 \text{gibibyte}' assert latex(4*microgram/second) == r'\frac{4 \mu\text{g}}{\text{s}}' def test_issue_17092(): x_star = Symbol('x^*') assert latex(Derivative(x_star, x_star,2)) == r'\frac{d^{2}}{d \left(x^{*}\right)^{2}} x^{*}' def test_latex_decimal_separator(): x, y, z, t = symbols('x y z t') k, m, n = symbols('k m n', integer=True) f, g, h = symbols('f g h', cls=Function) # comma decimal_separator assert(latex([1, 2.3, 4.5], decimal_separator='comma') == r'\left[ 1; \ 2{,}3; \ 4{,}5\right]') assert(latex(FiniteSet(1, 2.3, 4.5), decimal_separator='comma') == r'\left\{1; 2{,}3; 4{,}5\right\}') assert(latex((1, 2.3, 4.6), decimal_separator = 'comma') == r'\left( 1; \ 2{,}3; \ 4{,}6\right)') assert(latex((1,), decimal_separator='comma') == r'\left( 1;\right)') # period decimal_separator assert(latex([1, 2.3, 4.5], decimal_separator='period') == r'\left[ 1, \ 2.3, \ 4.5\right]' ) assert(latex(FiniteSet(1, 2.3, 4.5), decimal_separator='period') == r'\left\{1, 2.3, 4.5\right\}') assert(latex((1, 2.3, 4.6), decimal_separator = 'period') == r'\left( 1, \ 2.3, \ 4.6\right)') assert(latex((1,), decimal_separator='period') == r'\left( 1,\right)') # default decimal_separator assert(latex([1, 2.3, 4.5]) == r'\left[ 1, \ 2.3, \ 4.5\right]') assert(latex(FiniteSet(1, 2.3, 4.5)) == r'\left\{1, 2.3, 4.5\right\}') assert(latex((1, 2.3, 4.6)) == r'\left( 1, \ 2.3, \ 4.6\right)') assert(latex((1,)) == r'\left( 1,\right)') assert(latex(Mul(3.4,5.3), decimal_separator = 'comma') == r'18{,}02') assert(latex(3.4*5.3, decimal_separator = 'comma') == r'18{,}02') x = symbols('x') y = symbols('y') z = symbols('z') assert(latex(x*5.3 + 2**y**3.4 + 4.5 + z, decimal_separator = 'comma') == r'2^{y^{3{,}4}} + 5{,}3 x + z + 4{,}5') assert(latex(0.987, decimal_separator='comma') == r'0{,}987') assert(latex(S(0.987), decimal_separator='comma') == r'0{,}987') assert(latex(.3, decimal_separator='comma') == r'0{,}3') assert(latex(S(.3), decimal_separator='comma') == r'0{,}3') assert(latex(5.8*10**(-7), decimal_separator='comma') == r'5{,}8 \cdot 10^{-7}') assert(latex(S(5.7)*10**(-7), decimal_separator='comma') == r'5{,}7 \cdot 10^{-7}') assert(latex(S(5.7*10**(-7)), decimal_separator='comma') == r'5{,}7 \cdot 10^{-7}') x = symbols('x') assert(latex(1.2*x+3.4, decimal_separator='comma') == r'1{,}2 x + 3{,}4') assert(latex(FiniteSet(1, 2.3, 4.5), decimal_separator='period') == r'\left\{1, 2.3, 4.5\right\}') # Error Handling tests raises(ValueError, lambda: latex([1,2.3,4.5], decimal_separator='non_existing_decimal_separator_in_list')) raises(ValueError, lambda: latex(FiniteSet(1,2.3,4.5), decimal_separator='non_existing_decimal_separator_in_set')) raises(ValueError, lambda: latex((1,2.3,4.5), decimal_separator='non_existing_decimal_separator_in_tuple')) def test_Str(): from sympy.core.symbol import Str assert str(Str('x')) == r'x' def test_latex_escape(): assert latex_escape(r"~^\&%$#_{}") == "".join([ r'\textasciitilde', r'\textasciicircum', r'\textbackslash', r'\&', r'\%', r'\$', r'\#', r'\_', r'\{', r'\}', ]) def test_emptyPrinter(): class MyObject: def __repr__(self): return "" # unknown objects are monospaced assert latex(MyObject()) == r"\mathtt{\text{}}" # even if they are nested within other objects assert latex((MyObject(),)) == r"\left( \mathtt{\text{}},\right)" def test_global_settings(): import inspect # settings should be visible in the signature of `latex` assert inspect.signature(latex).parameters['imaginary_unit'].default == r'i' assert latex(I) == r'i' try: # but changing the defaults... LatexPrinter.set_global_settings(imaginary_unit='j') # ... should change the signature assert inspect.signature(latex).parameters['imaginary_unit'].default == r'j' assert latex(I) == r'j' finally: # there's no public API to undo this, but we need to make sure we do # so as not to impact other tests del LatexPrinter._global_settings['imaginary_unit'] # check we really did undo it assert inspect.signature(latex).parameters['imaginary_unit'].default == r'i' assert latex(I) == r'i' def test_pickleable(): # this tests that the _PrintFunction instance is pickleable import pickle assert pickle.loads(pickle.dumps(latex)) is latex def test_printing_latex_array_expressions(): assert latex(ArraySymbol("A", 2, 3, 4)) == "A" assert latex(ArrayElement("A", (2, 1/(1-x), 0))) == "{{A}_{2, \\frac{1}{1 - x}, 0}}" sympy-sympy-1.9/sympy/printing/tests/test_llvmjit.py000066400000000000000000000126701412543434000232000ustar00rootroot00000000000000from sympy.external import import_module from sympy.testing.pytest import raises import ctypes if import_module('llvmlite'): import sympy.printing.llvmjitcode as g else: disabled = True import sympy from sympy.abc import a, b, n # copied from numpy.isclose documentation def isclose(a, b): rtol = 1e-5 atol = 1e-8 return abs(a-b) <= atol + rtol*abs(b) def test_simple_expr(): e = a + 1.0 f = g.llvm_callable([a], e) res = float(e.subs({a: 4.0}).evalf()) jit_res = f(4.0) assert isclose(jit_res, res) def test_two_arg(): e = 4.0*a + b + 3.0 f = g.llvm_callable([a, b], e) res = float(e.subs({a: 4.0, b: 3.0}).evalf()) jit_res = f(4.0, 3.0) assert isclose(jit_res, res) def test_func(): e = 4.0*sympy.exp(-a) f = g.llvm_callable([a], e) res = float(e.subs({a: 1.5}).evalf()) jit_res = f(1.5) assert isclose(jit_res, res) def test_two_func(): e = 4.0*sympy.exp(-a) + sympy.exp(b) f = g.llvm_callable([a, b], e) res = float(e.subs({a: 1.5, b: 2.0}).evalf()) jit_res = f(1.5, 2.0) assert isclose(jit_res, res) def test_two_sqrt(): e = 4.0*sympy.sqrt(a) + sympy.sqrt(b) f = g.llvm_callable([a, b], e) res = float(e.subs({a: 1.5, b: 2.0}).evalf()) jit_res = f(1.5, 2.0) assert isclose(jit_res, res) def test_two_pow(): e = a**1.5 + b**7 f = g.llvm_callable([a, b], e) res = float(e.subs({a: 1.5, b: 2.0}).evalf()) jit_res = f(1.5, 2.0) assert isclose(jit_res, res) def test_callback(): e = a + 1.2 f = g.llvm_callable([a], e, callback_type='scipy.integrate.test') m = ctypes.c_int(1) array_type = ctypes.c_double * 1 inp = {a: 2.2} array = array_type(inp[a]) jit_res = f(m, array) res = float(e.subs(inp).evalf()) assert isclose(jit_res, res) def test_callback_cubature(): e = a + 1.2 f = g.llvm_callable([a], e, callback_type='cubature') m = ctypes.c_int(1) array_type = ctypes.c_double * 1 inp = {a: 2.2} array = array_type(inp[a]) out_array = array_type(0.0) jit_ret = f(m, array, None, m, out_array) assert jit_ret == 0 res = float(e.subs(inp).evalf()) assert isclose(out_array[0], res) def test_callback_two(): e = 3*a*b f = g.llvm_callable([a, b], e, callback_type='scipy.integrate.test') m = ctypes.c_int(2) array_type = ctypes.c_double * 2 inp = {a: 0.2, b: 1.7} array = array_type(inp[a], inp[b]) jit_res = f(m, array) res = float(e.subs(inp).evalf()) assert isclose(jit_res, res) def test_callback_alt_two(): d = sympy.IndexedBase('d') e = 3*d[0]*d[1] f = g.llvm_callable([n, d], e, callback_type='scipy.integrate.test') m = ctypes.c_int(2) array_type = ctypes.c_double * 2 inp = {d[0]: 0.2, d[1]: 1.7} array = array_type(inp[d[0]], inp[d[1]]) jit_res = f(m, array) res = float(e.subs(inp).evalf()) assert isclose(jit_res, res) def test_multiple_statements(): # Match return from CSE e = [[(b, 4.0*a)], [b + 5]] f = g.llvm_callable([a], e) b_val = e[0][0][1].subs({a: 1.5}) res = float(e[1][0].subs({b: b_val}).evalf()) jit_res = f(1.5) assert isclose(jit_res, res) f_callback = g.llvm_callable([a], e, callback_type='scipy.integrate.test') m = ctypes.c_int(1) array_type = ctypes.c_double * 1 array = array_type(1.5) jit_callback_res = f_callback(m, array) assert isclose(jit_callback_res, res) def test_cse(): e = a*a + b*b + sympy.exp(-a*a - b*b) e2 = sympy.cse(e) f = g.llvm_callable([a, b], e2) res = float(e.subs({a: 2.3, b: 0.1}).evalf()) jit_res = f(2.3, 0.1) assert isclose(jit_res, res) def eval_cse(e, sub_dict): tmp_dict = dict() for tmp_name, tmp_expr in e[0]: e2 = tmp_expr.subs(sub_dict) e3 = e2.subs(tmp_dict) tmp_dict[tmp_name] = e3 return [e.subs(sub_dict).subs(tmp_dict) for e in e[1]] def test_cse_multiple(): e1 = a*a e2 = a*a + b*b e3 = sympy.cse([e1, e2]) raises(NotImplementedError, lambda: g.llvm_callable([a, b], e3, callback_type='scipy.integrate')) # XXX: The commented lines below lead to a segfault in Python 3.9 although # they work fine in Python 3.8. It is not sufficient to mark the test as # XFAIL because it crashes the test runner. #f = g.llvm_callable([a, b], e3) #jit_res = f(0.1, 1.5) #assert len(jit_res) == 2 #res = eval_cse(e3, {a: 0.1, b: 1.5}) #assert isclose(res[0], jit_res[0]) #assert isclose(res[1], jit_res[1]) def test_callback_cubature_multiple(): e1 = a*a e2 = a*a + b*b e3 = sympy.cse([e1, e2, 4*e2]) f = g.llvm_callable([a, b], e3, callback_type='cubature') # Number of input variables ndim = 2 # Number of output expression values outdim = 3 m = ctypes.c_int(ndim) fdim = ctypes.c_int(outdim) array_type = ctypes.c_double * ndim out_array_type = ctypes.c_double * outdim inp = {a: 0.2, b: 1.5} array = array_type(inp[a], inp[b]) out_array = out_array_type() jit_ret = f(m, array, None, fdim, out_array) assert jit_ret == 0 res = eval_cse(e3, inp) assert isclose(out_array[0], res[0]) assert isclose(out_array[1], res[1]) assert isclose(out_array[2], res[2]) def test_symbol_not_found(): e = a*a + b raises(LookupError, lambda: g.llvm_callable([a], e)) def test_bad_callback(): e = a raises(ValueError, lambda: g.llvm_callable([a], e, callback_type='bad_callback')) sympy-sympy-1.9/sympy/printing/tests/test_maple.py000066400000000000000000000312001412543434000226030ustar00rootroot00000000000000from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer, Tuple, Symbol, Eq, Ne, Le, Lt, Gt, Ge) from sympy.core import EulerGamma, GoldenRatio, Catalan, Lambda, Mul, Pow from sympy.functions import Piecewise, sqrt, ceiling, exp, sin, cos from sympy.testing.pytest import raises from sympy.utilities.lambdify import implemented_function from sympy.matrices import (eye, Matrix, MatrixSymbol, Identity, HadamardProduct, SparseMatrix) from sympy.functions.special.bessel import besseli from sympy import maple_code x, y, z = symbols('x,y,z') def test_Integer(): assert maple_code(Integer(67)) == "67" assert maple_code(Integer(-1)) == "-1" def test_Rational(): assert maple_code(Rational(3, 7)) == "3/7" assert maple_code(Rational(18, 9)) == "2" assert maple_code(Rational(3, -7)) == "-3/7" assert maple_code(Rational(-3, -7)) == "3/7" assert maple_code(x + Rational(3, 7)) == "x + 3/7" assert maple_code(Rational(3, 7) * x) == '(3/7)*x' def test_Relational(): assert maple_code(Eq(x, y)) == "x = y" assert maple_code(Ne(x, y)) == "x <> y" assert maple_code(Le(x, y)) == "x <= y" assert maple_code(Lt(x, y)) == "x < y" assert maple_code(Gt(x, y)) == "x > y" assert maple_code(Ge(x, y)) == "x >= y" def test_Function(): assert maple_code(sin(x) ** cos(x)) == "sin(x)^cos(x)" assert maple_code(abs(x)) == "abs(x)" assert maple_code(ceiling(x)) == "ceil(x)" def test_Pow(): assert maple_code(x ** 3) == "x^3" assert maple_code(x ** (y ** 3)) == "x^(y^3)" assert maple_code((x ** 3) ** y) == "(x^3)^y" assert maple_code(x ** Rational(2, 3)) == 'x^(2/3)' g = implemented_function('g', Lambda(x, 2 * x)) assert maple_code(1 / (g(x) * 3.5) ** (x - y ** x) / (x ** 2 + y)) == \ "(3.5*2*x)^(-x + y^x)/(x^2 + y)" # For issue 14160 assert maple_code(Mul(-2, x, Pow(Mul(y, y, evaluate=False), -1, evaluate=False), evaluate=False)) == '-2*x/(y*y)' def test_basic_ops(): assert maple_code(x * y) == "x*y" assert maple_code(x + y) == "x + y" assert maple_code(x - y) == "x - y" assert maple_code(-x) == "-x" def test_1_over_x_and_sqrt(): # 1.0 and 0.5 would do something different in regular StrPrinter, # but these are exact in IEEE floating point so no different here. assert maple_code(1 / x) == '1/x' assert maple_code(x ** -1) == maple_code(x ** -1.0) == '1/x' assert maple_code(1 / sqrt(x)) == '1/sqrt(x)' assert maple_code(x ** -S.Half) == maple_code(x ** -0.5) == '1/sqrt(x)' assert maple_code(sqrt(x)) == 'sqrt(x)' assert maple_code(x ** S.Half) == maple_code(x ** 0.5) == 'sqrt(x)' assert maple_code(1 / pi) == '1/Pi' assert maple_code(pi ** -1) == maple_code(pi ** -1.0) == '1/Pi' assert maple_code(pi ** -0.5) == '1/sqrt(Pi)' def test_mix_number_mult_symbols(): assert maple_code(3 * x) == "3*x" assert maple_code(pi * x) == "Pi*x" assert maple_code(3 / x) == "3/x" assert maple_code(pi / x) == "Pi/x" assert maple_code(x / 3) == '(1/3)*x' assert maple_code(x / pi) == "x/Pi" assert maple_code(x * y) == "x*y" assert maple_code(3 * x * y) == "3*x*y" assert maple_code(3 * pi * x * y) == "3*Pi*x*y" assert maple_code(x / y) == "x/y" assert maple_code(3 * x / y) == "3*x/y" assert maple_code(x * y / z) == "x*y/z" assert maple_code(x / y * z) == "x*z/y" assert maple_code(1 / x / y) == "1/(x*y)" assert maple_code(2 * pi * x / y / z) == "2*Pi*x/(y*z)" assert maple_code(3 * pi / x) == "3*Pi/x" assert maple_code(S(3) / 5) == "3/5" assert maple_code(S(3) / 5 * x) == '(3/5)*x' assert maple_code(x / y / z) == "x/(y*z)" assert maple_code((x + y) / z) == "(x + y)/z" assert maple_code((x + y) / (z + x)) == "(x + y)/(x + z)" assert maple_code((x + y) / EulerGamma) == '(x + y)/gamma' assert maple_code(x / 3 / pi) == '(1/3)*x/Pi' assert maple_code(S(3) / 5 * x * y / pi) == '(3/5)*x*y/Pi' def test_mix_number_pow_symbols(): assert maple_code(pi ** 3) == 'Pi^3' assert maple_code(x ** 2) == 'x^2' assert maple_code(x ** (pi ** 3)) == 'x^(Pi^3)' assert maple_code(x ** y) == 'x^y' assert maple_code(x ** (y ** z)) == 'x^(y^z)' assert maple_code((x ** y) ** z) == '(x^y)^z' def test_imag(): I = S('I') assert maple_code(I) == "I" assert maple_code(5 * I) == "5*I" assert maple_code((S(3) / 2) * I) == "(3/2)*I" assert maple_code(3 + 4 * I) == "3 + 4*I" def test_constants(): assert maple_code(pi) == "Pi" assert maple_code(oo) == "infinity" assert maple_code(-oo) == "-infinity" assert maple_code(S.NegativeInfinity) == "-infinity" assert maple_code(S.NaN) == "undefined" assert maple_code(S.Exp1) == "exp(1)" assert maple_code(exp(1)) == "exp(1)" def test_constants_other(): assert maple_code(2 * GoldenRatio) == '2*(1/2 + (1/2)*sqrt(5))' assert maple_code(2 * Catalan) == '2*Catalan' assert maple_code(2 * EulerGamma) == "2*gamma" def test_boolean(): assert maple_code(x & y) == "x && y" assert maple_code(x | y) == "x || y" assert maple_code(~x) == "!x" assert maple_code(x & y & z) == "x && y && z" assert maple_code(x | y | z) == "x || y || z" assert maple_code((x & y) | z) == "z || x && y" assert maple_code((x | y) & z) == "z && (x || y)" def test_Matrices(): assert maple_code(Matrix(1, 1, [10])) == \ 'Matrix([[10]], storage = rectangular)' A = Matrix([[1, sin(x / 2), abs(x)], [0, 1, pi], [0, exp(1), ceiling(x)]]) expected = \ 'Matrix(' \ '[[1, sin((1/2)*x), abs(x)],' \ ' [0, 1, Pi],' \ ' [0, exp(1), ceil(x)]], ' \ 'storage = rectangular)' assert maple_code(A) == expected # row and columns assert maple_code(A[:, 0]) == \ 'Matrix([[1], [0], [0]], storage = rectangular)' assert maple_code(A[0, :]) == \ 'Matrix([[1, sin((1/2)*x), abs(x)]], storage = rectangular)' assert maple_code(Matrix([[x, x - y, -y]])) == \ 'Matrix([[x, x - y, -y]], storage = rectangular)' # empty matrices assert maple_code(Matrix(0, 0, [])) == \ 'Matrix([], storage = rectangular)' assert maple_code(Matrix(0, 3, [])) == \ 'Matrix([], storage = rectangular)' def test_SparseMatrices(): assert maple_code(SparseMatrix(Identity(2))) == 'Matrix([[1, 0], [0, 1]], storage = sparse)' def test_vector_entries_hadamard(): # For a row or column, user might to use the other dimension A = Matrix([[1, sin(2 / x), 3 * pi / x / 5]]) assert maple_code(A) == \ 'Matrix([[1, sin(2/x), (3/5)*Pi/x]], storage = rectangular)' assert maple_code(A.T) == \ 'Matrix([[1], [sin(2/x)], [(3/5)*Pi/x]], storage = rectangular)' def test_Matrices_entries_not_hadamard(): A = Matrix([[1, sin(2 / x), 3 * pi / x / 5], [1, 2, x * y]]) expected = \ 'Matrix([[1, sin(2/x), (3/5)*Pi/x], [1, 2, x*y]], ' \ 'storage = rectangular)' assert maple_code(A) == expected def test_MatrixSymbol(): n = Symbol('n', integer=True) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) assert maple_code(A * B) == "A.B" assert maple_code(B * A) == "B.A" assert maple_code(2 * A * B) == "2*A.B" assert maple_code(B * 2 * A) == "2*B.A" assert maple_code( A * (B + 3 * Identity(n))) == "A.(3*Matrix(n, shape = identity) + B)" assert maple_code(A ** (x ** 2)) == "MatrixPower(A, x^2)" assert maple_code(A ** 3) == "MatrixPower(A, 3)" assert maple_code(A ** (S.Half)) == "MatrixPower(A, 1/2)" def test_special_matrices(): assert maple_code(6 * Identity(3)) == "6*Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], storage = sparse)" assert maple_code(Identity(x)) == 'Matrix(x, shape = identity)' def test_containers(): assert maple_code([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \ "[1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]" assert maple_code((1, 2, (3, 4))) == "[1, 2, [3, 4]]" assert maple_code([1]) == "[1]" assert maple_code((1,)) == "[1]" assert maple_code(Tuple(*[1, 2, 3])) == "[1, 2, 3]" assert maple_code((1, x * y, (3, x ** 2))) == "[1, x*y, [3, x^2]]" # scalar, matrix, empty matrix and empty list assert maple_code((1, eye(3), Matrix(0, 0, []), [])) == \ "[1, Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]], storage = rectangular), Matrix([], storage = rectangular), []]" def test_maple_noninline(): source = maple_code((x + y)/Catalan, assign_to='me', inline=False) expected = "me := (x + y)/Catalan" assert source == expected def test_maple_matrix_assign_to(): A = Matrix([[1, 2, 3]]) assert maple_code(A, assign_to='a') == "a := Matrix([[1, 2, 3]], storage = rectangular)" A = Matrix([[1, 2], [3, 4]]) assert maple_code(A, assign_to='A') == "A := Matrix([[1, 2], [3, 4]], storage = rectangular)" def test_maple_matrix_assign_to_more(): # assigning to Symbol or MatrixSymbol requires lhs/rhs match A = Matrix([[1, 2, 3]]) B = MatrixSymbol('B', 1, 3) C = MatrixSymbol('C', 2, 3) assert maple_code(A, assign_to=B) == "B := Matrix([[1, 2, 3]], storage = rectangular)" raises(ValueError, lambda: maple_code(A, assign_to=x)) raises(ValueError, lambda: maple_code(A, assign_to=C)) def test_maple_matrix_1x1(): A = Matrix([[3]]) assert maple_code(A, assign_to='B') == "B := Matrix([[3]], storage = rectangular)" def test_maple_matrix_elements(): A = Matrix([[x, 2, x * y]]) assert maple_code(A[0, 0] ** 2 + A[0, 1] + A[0, 2]) == "x^2 + x*y + 2" AA = MatrixSymbol('AA', 1, 3) assert maple_code(AA) == "AA" assert maple_code(AA[0, 0] ** 2 + sin(AA[0, 1]) + AA[0, 2]) == \ "sin(AA[1, 2]) + AA[1, 1]^2 + AA[1, 3]" assert maple_code(sum(AA)) == "AA[1, 1] + AA[1, 2] + AA[1, 3]" def test_maple_boolean(): assert maple_code(True) == "true" assert maple_code(S.true) == "true" assert maple_code(False) == "false" assert maple_code(S.false) == "false" def test_sparse(): M = SparseMatrix(5, 6, {}) M[2, 2] = 10 M[1, 2] = 20 M[1, 3] = 22 M[0, 3] = 30 M[3, 0] = x * y assert maple_code(M) == \ 'Matrix([[0, 0, 0, 30, 0, 0],' \ ' [0, 0, 20, 22, 0, 0],' \ ' [0, 0, 10, 0, 0, 0],' \ ' [x*y, 0, 0, 0, 0, 0],' \ ' [0, 0, 0, 0, 0, 0]], ' \ 'storage = sparse)' # Not an important point. def test_maple_not_supported(): assert maple_code(S.ComplexInfinity) == ( "# Not supported in maple:\n" "# ComplexInfinity\n" "zoo" ) # PROBLEM def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) assert (maple_code(A[0, 0]) == "A[1, 1]") assert (maple_code(3 * A[0, 0]) == "3*A[1, 1]") F = A-B assert (maple_code(F[0,0]) == "A[1, 1] - B[1, 1]") def test_hadamard(): A = MatrixSymbol('A', 3, 3) B = MatrixSymbol('B', 3, 3) v = MatrixSymbol('v', 3, 1) h = MatrixSymbol('h', 1, 3) C = HadamardProduct(A, B) assert maple_code(C) == "A*B" assert maple_code(C * v) == "(A*B).v" # HadamardProduct is higher than dot product. assert maple_code(h * C * v) == "h.(A*B).v" assert maple_code(C * A) == "(A*B).A" # mixing Hadamard and scalar strange b/c we vectorize scalars assert maple_code(C * x * y) == "x*y*(A*B)" def test_maple_piecewise(): expr = Piecewise((x, x < 1), (x ** 2, True)) assert maple_code(expr) == "piecewise(x < 1, x, x^2)" assert maple_code(expr, assign_to="r") == ( "r := piecewise(x < 1, x, x^2)") expr = Piecewise((x ** 2, x < 1), (x ** 3, x < 2), (x ** 4, x < 3), (x ** 5, True)) expected = "piecewise(x < 1, x^2, x < 2, x^3, x < 3, x^4, x^5)" assert maple_code(expr) == expected assert maple_code(expr, assign_to="r") == "r := " + expected # Check that Piecewise without a True (default) condition error expr = Piecewise((x, x < 1), (x ** 2, x > 1), (sin(x), x > 0)) raises(ValueError, lambda: maple_code(expr)) def test_maple_piecewise_times_const(): pw = Piecewise((x, x < 1), (x ** 2, True)) assert maple_code(2 * pw) == "2*piecewise(x < 1, x, x^2)" assert maple_code(pw / x) == "piecewise(x < 1, x, x^2)/x" assert maple_code(pw / (x * y)) == "piecewise(x < 1, x, x^2)/(x*y)" assert maple_code(pw / 3) == "(1/3)*piecewise(x < 1, x, x^2)" def test_maple_derivatives(): f = Function('f') assert maple_code(f(x).diff(x)) == 'diff(f(x), x)' assert maple_code(f(x).diff(x, 2)) == 'diff(f(x), x$2)' def test_specfun(): assert maple_code('asin(x)') == 'arcsin(x)' assert maple_code(besseli(x, y)) == 'BesselI(x, y)' sympy-sympy-1.9/sympy/printing/tests/test_mathematica.py000066400000000000000000000252651412543434000240000ustar00rootroot00000000000000from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer, Tuple, Derivative, Eq, Ne, Le, Lt, Gt, Ge) from sympy.integrals import Integral from sympy.concrete import Sum from sympy.functions import (exp, sin, cos, fresnelc, fresnels, conjugate, Max, Min, gamma, polygamma, loggamma, erf, erfi, erfc, erf2, expint, erfinv, erfcinv, Ei, Si, Ci, li, Shi, Chi, uppergamma, beta, subfactorial, erf2inv, factorial, factorial2, catalan, RisingFactorial, FallingFactorial, harmonic, atan2, sec, acsc, hermite, laguerre, assoc_laguerre, jacobi, gegenbauer, chebyshevt, chebyshevu, legendre, assoc_legendre, Li, LambertW) from sympy import mathematica_code as mcode x, y, z, w = symbols('x,y,z,w') f = Function('f') def test_Integer(): assert mcode(Integer(67)) == "67" assert mcode(Integer(-1)) == "-1" def test_Rational(): assert mcode(Rational(3, 7)) == "3/7" assert mcode(Rational(18, 9)) == "2" assert mcode(Rational(3, -7)) == "-3/7" assert mcode(Rational(-3, -7)) == "3/7" assert mcode(x + Rational(3, 7)) == "x + 3/7" assert mcode(Rational(3, 7)*x) == "(3/7)*x" def test_Relational(): assert mcode(Eq(x, y)) == "x == y" assert mcode(Ne(x, y)) == "x != y" assert mcode(Le(x, y)) == "x <= y" assert mcode(Lt(x, y)) == "x < y" assert mcode(Gt(x, y)) == "x > y" assert mcode(Ge(x, y)) == "x >= y" def test_Function(): assert mcode(f(x, y, z)) == "f[x, y, z]" assert mcode(sin(x) ** cos(x)) == "Sin[x]^Cos[x]" assert mcode(sec(x) * acsc(x)) == "ArcCsc[x]*Sec[x]" assert mcode(atan2(x, y)) == "ArcTan[x, y]" assert mcode(conjugate(x)) == "Conjugate[x]" assert mcode(Max(x, y, z)*Min(y, z)) == "Max[x, y, z]*Min[y, z]" assert mcode(fresnelc(x)) == "FresnelC[x]" assert mcode(fresnels(x)) == "FresnelS[x]" assert mcode(gamma(x)) == "Gamma[x]" assert mcode(uppergamma(x, y)) == "Gamma[x, y]" assert mcode(polygamma(x, y)) == "PolyGamma[x, y]" assert mcode(loggamma(x)) == "LogGamma[x]" assert mcode(erf(x)) == "Erf[x]" assert mcode(erfc(x)) == "Erfc[x]" assert mcode(erfi(x)) == "Erfi[x]" assert mcode(erf2(x, y)) == "Erf[x, y]" assert mcode(expint(x, y)) == "ExpIntegralE[x, y]" assert mcode(erfcinv(x)) == "InverseErfc[x]" assert mcode(erfinv(x)) == "InverseErf[x]" assert mcode(erf2inv(x, y)) == "InverseErf[x, y]" assert mcode(Ei(x)) == "ExpIntegralEi[x]" assert mcode(Ci(x)) == "CosIntegral[x]" assert mcode(li(x)) == "LogIntegral[x]" assert mcode(Si(x)) == "SinIntegral[x]" assert mcode(Shi(x)) == "SinhIntegral[x]" assert mcode(Chi(x)) == "CoshIntegral[x]" assert mcode(beta(x, y)) == "Beta[x, y]" assert mcode(factorial(x)) == "Factorial[x]" assert mcode(factorial2(x)) == "Factorial2[x]" assert mcode(subfactorial(x)) == "Subfactorial[x]" assert mcode(FallingFactorial(x, y)) == "FactorialPower[x, y]" assert mcode(RisingFactorial(x, y)) == "Pochhammer[x, y]" assert mcode(catalan(x)) == "CatalanNumber[x]" assert mcode(harmonic(x)) == "HarmonicNumber[x]" assert mcode(harmonic(x, y)) == "HarmonicNumber[x, y]" assert mcode(Li(x)) == "LogIntegral[x] - LogIntegral[2]" assert mcode(LambertW(x)) == "ProductLog[x]" assert mcode(LambertW(x, -1)) == "ProductLog[-1, x]" assert mcode(LambertW(x, y)) == "ProductLog[y, x]" def test_special_polynomials(): assert mcode(hermite(x, y)) == "HermiteH[x, y]" assert mcode(laguerre(x, y)) == "LaguerreL[x, y]" assert mcode(assoc_laguerre(x, y, z)) == "LaguerreL[x, y, z]" assert mcode(jacobi(x, y, z, w)) == "JacobiP[x, y, z, w]" assert mcode(gegenbauer(x, y, z)) == "GegenbauerC[x, y, z]" assert mcode(chebyshevt(x, y)) == "ChebyshevT[x, y]" assert mcode(chebyshevu(x, y)) == "ChebyshevU[x, y]" assert mcode(legendre(x, y)) == "LegendreP[x, y]" assert mcode(assoc_legendre(x, y, z)) == "LegendreP[x, y, z]" def test_Pow(): assert mcode(x**3) == "x^3" assert mcode(x**(y**3)) == "x^(y^3)" assert mcode(1/(f(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "(3.5*f[x])^(-x + y^x)/(x^2 + y)" assert mcode(x**-1.0) == 'x^(-1.0)' assert mcode(x**Rational(2, 3)) == 'x^(2/3)' def test_Mul(): A, B, C, D = symbols('A B C D', commutative=False) assert mcode(x*y*z) == "x*y*z" assert mcode(x*y*A) == "x*y*A" assert mcode(x*y*A*B) == "x*y*A**B" assert mcode(x*y*A*B*C) == "x*y*A**B**C" assert mcode(x*A*B*(C + D)*A*y) == "x*y*A**B**(C + D)**A" def test_constants(): assert mcode(S.Zero) == "0" assert mcode(S.One) == "1" assert mcode(S.NegativeOne) == "-1" assert mcode(S.Half) == "1/2" assert mcode(S.ImaginaryUnit) == "I" assert mcode(oo) == "Infinity" assert mcode(S.NegativeInfinity) == "-Infinity" assert mcode(S.ComplexInfinity) == "ComplexInfinity" assert mcode(S.NaN) == "Indeterminate" assert mcode(S.Exp1) == "E" assert mcode(pi) == "Pi" assert mcode(S.GoldenRatio) == "GoldenRatio" assert mcode(S.TribonacciConstant) == \ "(1/3 + (1/3)*(19 - 3*33^(1/2))^(1/3) + " \ "(1/3)*(3*33^(1/2) + 19)^(1/3))" assert mcode(2*S.TribonacciConstant) == \ "2*(1/3 + (1/3)*(19 - 3*33^(1/2))^(1/3) + " \ "(1/3)*(3*33^(1/2) + 19)^(1/3))" assert mcode(S.EulerGamma) == "EulerGamma" assert mcode(S.Catalan) == "Catalan" def test_containers(): assert mcode([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \ "{1, 2, 3, {4, 5, {6, 7}}, 8, {9, 10}, 11}" assert mcode((1, 2, (3, 4))) == "{1, 2, {3, 4}}" assert mcode([1]) == "{1}" assert mcode((1,)) == "{1}" assert mcode(Tuple(*[1, 2, 3])) == "{1, 2, 3}" def test_matrices(): from sympy.matrices import MutableDenseMatrix, MutableSparseMatrix, \ ImmutableDenseMatrix, ImmutableSparseMatrix A = MutableDenseMatrix( [[1, -1, 0, 0], [0, 1, -1, 0], [0, 0, 1, -1], [0, 0, 0, 1]] ) B = MutableSparseMatrix(A) C = ImmutableDenseMatrix(A) D = ImmutableSparseMatrix(A) assert mcode(C) == mcode(A) == \ "{{1, -1, 0, 0}, " \ "{0, 1, -1, 0}, " \ "{0, 0, 1, -1}, " \ "{0, 0, 0, 1}}" assert mcode(D) == mcode(B) == \ "SparseArray[{" \ "{1, 1} -> 1, {1, 2} -> -1, {2, 2} -> 1, {2, 3} -> -1, " \ "{3, 3} -> 1, {3, 4} -> -1, {4, 4} -> 1" \ "}, {4, 4}]" # Trivial cases of matrices assert mcode(MutableDenseMatrix(0, 0, [])) == '{}' assert mcode(MutableSparseMatrix(0, 0, [])) == 'SparseArray[{}, {0, 0}]' assert mcode(MutableDenseMatrix(0, 3, [])) == '{}' assert mcode(MutableSparseMatrix(0, 3, [])) == 'SparseArray[{}, {0, 3}]' assert mcode(MutableDenseMatrix(3, 0, [])) == '{{}, {}, {}}' assert mcode(MutableSparseMatrix(3, 0, [])) == 'SparseArray[{}, {3, 0}]' def test_NDArray(): from sympy.tensor.array import ( MutableDenseNDimArray, ImmutableDenseNDimArray, MutableSparseNDimArray, ImmutableSparseNDimArray) example = MutableDenseNDimArray( [[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]], [[13, 14, 15, 16], [17, 18, 19, 20], [21, 22, 23, 24]]] ) assert mcode(example) == \ "{{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, " \ "{{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}}" example = ImmutableDenseNDimArray(example) assert mcode(example) == \ "{{{1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12}}, " \ "{{13, 14, 15, 16}, {17, 18, 19, 20}, {21, 22, 23, 24}}}" example = MutableSparseNDimArray(example) assert mcode(example) == \ "SparseArray[{" \ "{1, 1, 1} -> 1, {1, 1, 2} -> 2, {1, 1, 3} -> 3, " \ "{1, 1, 4} -> 4, {1, 2, 1} -> 5, {1, 2, 2} -> 6, " \ "{1, 2, 3} -> 7, {1, 2, 4} -> 8, {1, 3, 1} -> 9, " \ "{1, 3, 2} -> 10, {1, 3, 3} -> 11, {1, 3, 4} -> 12, " \ "{2, 1, 1} -> 13, {2, 1, 2} -> 14, {2, 1, 3} -> 15, " \ "{2, 1, 4} -> 16, {2, 2, 1} -> 17, {2, 2, 2} -> 18, " \ "{2, 2, 3} -> 19, {2, 2, 4} -> 20, {2, 3, 1} -> 21, " \ "{2, 3, 2} -> 22, {2, 3, 3} -> 23, {2, 3, 4} -> 24" \ "}, {2, 3, 4}]" example = ImmutableSparseNDimArray(example) assert mcode(example) == \ "SparseArray[{" \ "{1, 1, 1} -> 1, {1, 1, 2} -> 2, {1, 1, 3} -> 3, " \ "{1, 1, 4} -> 4, {1, 2, 1} -> 5, {1, 2, 2} -> 6, " \ "{1, 2, 3} -> 7, {1, 2, 4} -> 8, {1, 3, 1} -> 9, " \ "{1, 3, 2} -> 10, {1, 3, 3} -> 11, {1, 3, 4} -> 12, " \ "{2, 1, 1} -> 13, {2, 1, 2} -> 14, {2, 1, 3} -> 15, " \ "{2, 1, 4} -> 16, {2, 2, 1} -> 17, {2, 2, 2} -> 18, " \ "{2, 2, 3} -> 19, {2, 2, 4} -> 20, {2, 3, 1} -> 21, " \ "{2, 3, 2} -> 22, {2, 3, 3} -> 23, {2, 3, 4} -> 24" \ "}, {2, 3, 4}]" def test_Integral(): assert mcode(Integral(sin(sin(x)), x)) == "Hold[Integrate[Sin[Sin[x]], x]]" assert mcode(Integral(exp(-x**2 - y**2), (x, -oo, oo), (y, -oo, oo))) == \ "Hold[Integrate[Exp[-x^2 - y^2], {x, -Infinity, Infinity}, " \ "{y, -Infinity, Infinity}]]" def test_Derivative(): assert mcode(Derivative(sin(x), x)) == "Hold[D[Sin[x], x]]" assert mcode(Derivative(x, x)) == "Hold[D[x, x]]" assert mcode(Derivative(sin(x)*y**4, x, 2)) == "Hold[D[y^4*Sin[x], {x, 2}]]" assert mcode(Derivative(sin(x)*y**4, x, y, x)) == "Hold[D[y^4*Sin[x], x, y, x]]" assert mcode(Derivative(sin(x)*y**4, x, y, 3, x)) == "Hold[D[y^4*Sin[x], x, {y, 3}, x]]" def test_Sum(): assert mcode(Sum(sin(x), (x, 0, 10))) == "Hold[Sum[Sin[x], {x, 0, 10}]]" assert mcode(Sum(exp(-x**2 - y**2), (x, -oo, oo), (y, -oo, oo))) == \ "Hold[Sum[Exp[-x^2 - y^2], {x, -Infinity, Infinity}, " \ "{y, -Infinity, Infinity}]]" def test_comment(): from sympy.printing.mathematica import MCodePrinter assert MCodePrinter()._get_comment("Hello World") == \ "(* Hello World *)" def test_userfuncs(): # Dictionary mutation test some_function = symbols("some_function", cls=Function) my_user_functions = {"some_function": "SomeFunction"} assert mcode( some_function(z), user_functions=my_user_functions) == \ 'SomeFunction[z]' assert mcode( some_function(z), user_functions=my_user_functions) == \ 'SomeFunction[z]' # List argument test my_user_functions = \ {"some_function": [(lambda x: True, "SomeOtherFunction")]} assert mcode( some_function(z), user_functions=my_user_functions) == \ 'SomeOtherFunction[z]' sympy-sympy-1.9/sympy/printing/tests/test_mathml.py000066400000000000000000002712141412543434000230020ustar00rootroot00000000000000from sympy import diff, Integral, Limit, sin, Symbol, Integer, Rational, cos, \ tan, asin, acos, atan, sinh, cosh, tanh, asinh, acosh, atanh, E, I, oo, \ pi, GoldenRatio, EulerGamma, Sum, Eq, Ne, Ge, Lt, Float, Matrix, Basic, \ S, MatrixSymbol, Function, Derivative, log, true, false, Range, Min, Max, \ Lambda, IndexedBase, symbols, zoo, elliptic_f, elliptic_e, elliptic_pi, Ei, \ expint, jacobi, gegenbauer, chebyshevt, chebyshevu, legendre, assoc_legendre, \ laguerre, assoc_laguerre, hermite, euler, stieltjes, mathieuc, mathieus, \ mathieucprime, mathieusprime, TribonacciConstant, Contains, LambertW, \ cot, coth, acot, acoth, csc, acsc, csch, acsch, sec, asec, sech, asech from sympy import elliptic_k, totient, reduced_totient, primenu, primeomega, \ fresnelc, fresnels, Heaviside from sympy.calculus.util import AccumBounds from sympy.core.containers import Tuple from sympy.functions.combinatorial.factorials import factorial, factorial2, \ binomial from sympy.functions.combinatorial.numbers import bernoulli, bell, lucas, \ fibonacci, tribonacci, catalan from sympy.functions.elementary.complexes import re, im, Abs, conjugate from sympy.functions.elementary.exponential import exp from sympy.functions.elementary.integers import floor, ceiling from sympy.functions.special.gamma_functions import gamma, lowergamma, uppergamma from sympy.functions.special.singularity_functions import SingularityFunction from sympy.functions.special.zeta_functions import polylog, lerchphi, zeta, dirichlet_eta from sympy.logic.boolalg import And, Or, Implies, Equivalent, Xor, Not from sympy.matrices.expressions.determinant import Determinant from sympy.physics.quantum import ComplexSpace, HilbertSpace, FockSpace, hbar, Dagger from sympy.printing.mathml import mathml, MathMLContentPrinter, \ MathMLPresentationPrinter, MathMLPrinter from sympy.sets.sets import FiniteSet, Union, Intersection, Complement, \ SymmetricDifference, Interval, EmptySet, ProductSet from sympy.stats.rv import RandomSymbol from sympy.testing.pytest import raises from sympy.vector import CoordSys3D, Cross, Curl, Dot, Divergence, Gradient, Laplacian from sympy import sympify x, y, z, a, b, c, d, e, n = symbols('x:z a:e n') mp = MathMLContentPrinter() mpp = MathMLPresentationPrinter() def test_mathml_printer(): m = MathMLPrinter() assert m.doprint(1+x) == mp.doprint(1+x) def test_content_printmethod(): assert mp.doprint(1 + x) == 'x1' def test_content_mathml_core(): mml_1 = mp._print(1 + x) assert mml_1.nodeName == 'apply' nodes = mml_1.childNodes assert len(nodes) == 3 assert nodes[0].nodeName == 'plus' assert nodes[0].hasChildNodes() is False assert nodes[0].nodeValue is None assert nodes[1].nodeName in ['cn', 'ci'] if nodes[1].nodeName == 'cn': assert nodes[1].childNodes[0].nodeValue == '1' assert nodes[2].childNodes[0].nodeValue == 'x' else: assert nodes[1].childNodes[0].nodeValue == 'x' assert nodes[2].childNodes[0].nodeValue == '1' mml_2 = mp._print(x**2) assert mml_2.nodeName == 'apply' nodes = mml_2.childNodes assert nodes[1].childNodes[0].nodeValue == 'x' assert nodes[2].childNodes[0].nodeValue == '2' mml_3 = mp._print(2*x) assert mml_3.nodeName == 'apply' nodes = mml_3.childNodes assert nodes[0].nodeName == 'times' assert nodes[1].childNodes[0].nodeValue == '2' assert nodes[2].childNodes[0].nodeValue == 'x' mml = mp._print(Float(1.0, 2)*x) assert mml.nodeName == 'apply' nodes = mml.childNodes assert nodes[0].nodeName == 'times' assert nodes[1].childNodes[0].nodeValue == '1.0' assert nodes[2].childNodes[0].nodeValue == 'x' def test_content_mathml_functions(): mml_1 = mp._print(sin(x)) assert mml_1.nodeName == 'apply' assert mml_1.childNodes[0].nodeName == 'sin' assert mml_1.childNodes[1].nodeName == 'ci' mml_2 = mp._print(diff(sin(x), x, evaluate=False)) assert mml_2.nodeName == 'apply' assert mml_2.childNodes[0].nodeName == 'diff' assert mml_2.childNodes[1].nodeName == 'bvar' assert mml_2.childNodes[1].childNodes[ 0].nodeName == 'ci' # below bvar there's x/ci> mml_3 = mp._print(diff(cos(x*y), x, evaluate=False)) assert mml_3.nodeName == 'apply' assert mml_3.childNodes[0].nodeName == 'partialdiff' assert mml_3.childNodes[1].nodeName == 'bvar' assert mml_3.childNodes[1].childNodes[ 0].nodeName == 'ci' # below bvar there's x/ci> def test_content_mathml_limits(): # XXX No unevaluated limits lim_fun = sin(x)/x mml_1 = mp._print(Limit(lim_fun, x, 0)) assert mml_1.childNodes[0].nodeName == 'limit' assert mml_1.childNodes[1].nodeName == 'bvar' assert mml_1.childNodes[2].nodeName == 'lowlimit' assert mml_1.childNodes[3].toxml() == mp._print(lim_fun).toxml() def test_content_mathml_integrals(): integrand = x mml_1 = mp._print(Integral(integrand, (x, 0, 1))) assert mml_1.childNodes[0].nodeName == 'int' assert mml_1.childNodes[1].nodeName == 'bvar' assert mml_1.childNodes[2].nodeName == 'lowlimit' assert mml_1.childNodes[3].nodeName == 'uplimit' assert mml_1.childNodes[4].toxml() == mp._print(integrand).toxml() def test_content_mathml_matrices(): A = Matrix([1, 2, 3]) B = Matrix([[0, 5, 4], [2, 3, 1], [9, 7, 9]]) mll_1 = mp._print(A) assert mll_1.childNodes[0].nodeName == 'matrixrow' assert mll_1.childNodes[0].childNodes[0].nodeName == 'cn' assert mll_1.childNodes[0].childNodes[0].childNodes[0].nodeValue == '1' assert mll_1.childNodes[1].nodeName == 'matrixrow' assert mll_1.childNodes[1].childNodes[0].nodeName == 'cn' assert mll_1.childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' assert mll_1.childNodes[2].nodeName == 'matrixrow' assert mll_1.childNodes[2].childNodes[0].nodeName == 'cn' assert mll_1.childNodes[2].childNodes[0].childNodes[0].nodeValue == '3' mll_2 = mp._print(B) assert mll_2.childNodes[0].nodeName == 'matrixrow' assert mll_2.childNodes[0].childNodes[0].nodeName == 'cn' assert mll_2.childNodes[0].childNodes[0].childNodes[0].nodeValue == '0' assert mll_2.childNodes[0].childNodes[1].nodeName == 'cn' assert mll_2.childNodes[0].childNodes[1].childNodes[0].nodeValue == '5' assert mll_2.childNodes[0].childNodes[2].nodeName == 'cn' assert mll_2.childNodes[0].childNodes[2].childNodes[0].nodeValue == '4' assert mll_2.childNodes[1].nodeName == 'matrixrow' assert mll_2.childNodes[1].childNodes[0].nodeName == 'cn' assert mll_2.childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' assert mll_2.childNodes[1].childNodes[1].nodeName == 'cn' assert mll_2.childNodes[1].childNodes[1].childNodes[0].nodeValue == '3' assert mll_2.childNodes[1].childNodes[2].nodeName == 'cn' assert mll_2.childNodes[1].childNodes[2].childNodes[0].nodeValue == '1' assert mll_2.childNodes[2].nodeName == 'matrixrow' assert mll_2.childNodes[2].childNodes[0].nodeName == 'cn' assert mll_2.childNodes[2].childNodes[0].childNodes[0].nodeValue == '9' assert mll_2.childNodes[2].childNodes[1].nodeName == 'cn' assert mll_2.childNodes[2].childNodes[1].childNodes[0].nodeValue == '7' assert mll_2.childNodes[2].childNodes[2].nodeName == 'cn' assert mll_2.childNodes[2].childNodes[2].childNodes[0].nodeValue == '9' def test_content_mathml_sums(): summand = x mml_1 = mp._print(Sum(summand, (x, 1, 10))) assert mml_1.childNodes[0].nodeName == 'sum' assert mml_1.childNodes[1].nodeName == 'bvar' assert mml_1.childNodes[2].nodeName == 'lowlimit' assert mml_1.childNodes[3].nodeName == 'uplimit' assert mml_1.childNodes[4].toxml() == mp._print(summand).toxml() def test_content_mathml_tuples(): mml_1 = mp._print([2]) assert mml_1.nodeName == 'list' assert mml_1.childNodes[0].nodeName == 'cn' assert len(mml_1.childNodes) == 1 mml_2 = mp._print([2, Integer(1)]) assert mml_2.nodeName == 'list' assert mml_2.childNodes[0].nodeName == 'cn' assert mml_2.childNodes[1].nodeName == 'cn' assert len(mml_2.childNodes) == 2 def test_content_mathml_add(): mml = mp._print(x**5 - x**4 + x) assert mml.childNodes[0].nodeName == 'plus' assert mml.childNodes[1].childNodes[0].nodeName == 'minus' assert mml.childNodes[1].childNodes[1].nodeName == 'apply' def test_content_mathml_Rational(): mml_1 = mp._print(Rational(1, 1)) """should just return a number""" assert mml_1.nodeName == 'cn' mml_2 = mp._print(Rational(2, 5)) assert mml_2.childNodes[0].nodeName == 'divide' def test_content_mathml_constants(): mml = mp._print(I) assert mml.nodeName == 'imaginaryi' mml = mp._print(E) assert mml.nodeName == 'exponentiale' mml = mp._print(oo) assert mml.nodeName == 'infinity' mml = mp._print(pi) assert mml.nodeName == 'pi' assert mathml(GoldenRatio) == 'φ' mml = mathml(EulerGamma) assert mml == '' mml = mathml(EmptySet()) assert mml == '' mml = mathml(S.true) assert mml == '' mml = mathml(S.false) assert mml == '' mml = mathml(S.NaN) assert mml == '' def test_content_mathml_trig(): mml = mp._print(sin(x)) assert mml.childNodes[0].nodeName == 'sin' mml = mp._print(cos(x)) assert mml.childNodes[0].nodeName == 'cos' mml = mp._print(tan(x)) assert mml.childNodes[0].nodeName == 'tan' mml = mp._print(cot(x)) assert mml.childNodes[0].nodeName == 'cot' mml = mp._print(csc(x)) assert mml.childNodes[0].nodeName == 'csc' mml = mp._print(sec(x)) assert mml.childNodes[0].nodeName == 'sec' mml = mp._print(asin(x)) assert mml.childNodes[0].nodeName == 'arcsin' mml = mp._print(acos(x)) assert mml.childNodes[0].nodeName == 'arccos' mml = mp._print(atan(x)) assert mml.childNodes[0].nodeName == 'arctan' mml = mp._print(acot(x)) assert mml.childNodes[0].nodeName == 'arccot' mml = mp._print(acsc(x)) assert mml.childNodes[0].nodeName == 'arccsc' mml = mp._print(asec(x)) assert mml.childNodes[0].nodeName == 'arcsec' mml = mp._print(sinh(x)) assert mml.childNodes[0].nodeName == 'sinh' mml = mp._print(cosh(x)) assert mml.childNodes[0].nodeName == 'cosh' mml = mp._print(tanh(x)) assert mml.childNodes[0].nodeName == 'tanh' mml = mp._print(coth(x)) assert mml.childNodes[0].nodeName == 'coth' mml = mp._print(csch(x)) assert mml.childNodes[0].nodeName == 'csch' mml = mp._print(sech(x)) assert mml.childNodes[0].nodeName == 'sech' mml = mp._print(asinh(x)) assert mml.childNodes[0].nodeName == 'arcsinh' mml = mp._print(atanh(x)) assert mml.childNodes[0].nodeName == 'arctanh' mml = mp._print(acosh(x)) assert mml.childNodes[0].nodeName == 'arccosh' mml = mp._print(acoth(x)) assert mml.childNodes[0].nodeName == 'arccoth' mml = mp._print(acsch(x)) assert mml.childNodes[0].nodeName == 'arccsch' mml = mp._print(asech(x)) assert mml.childNodes[0].nodeName == 'arcsech' def test_content_mathml_relational(): mml_1 = mp._print(Eq(x, 1)) assert mml_1.nodeName == 'apply' assert mml_1.childNodes[0].nodeName == 'eq' assert mml_1.childNodes[1].nodeName == 'ci' assert mml_1.childNodes[1].childNodes[0].nodeValue == 'x' assert mml_1.childNodes[2].nodeName == 'cn' assert mml_1.childNodes[2].childNodes[0].nodeValue == '1' mml_2 = mp._print(Ne(1, x)) assert mml_2.nodeName == 'apply' assert mml_2.childNodes[0].nodeName == 'neq' assert mml_2.childNodes[1].nodeName == 'cn' assert mml_2.childNodes[1].childNodes[0].nodeValue == '1' assert mml_2.childNodes[2].nodeName == 'ci' assert mml_2.childNodes[2].childNodes[0].nodeValue == 'x' mml_3 = mp._print(Ge(1, x)) assert mml_3.nodeName == 'apply' assert mml_3.childNodes[0].nodeName == 'geq' assert mml_3.childNodes[1].nodeName == 'cn' assert mml_3.childNodes[1].childNodes[0].nodeValue == '1' assert mml_3.childNodes[2].nodeName == 'ci' assert mml_3.childNodes[2].childNodes[0].nodeValue == 'x' mml_4 = mp._print(Lt(1, x)) assert mml_4.nodeName == 'apply' assert mml_4.childNodes[0].nodeName == 'lt' assert mml_4.childNodes[1].nodeName == 'cn' assert mml_4.childNodes[1].childNodes[0].nodeValue == '1' assert mml_4.childNodes[2].nodeName == 'ci' assert mml_4.childNodes[2].childNodes[0].nodeValue == 'x' def test_content_symbol(): mml = mp._print(x) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeValue == 'x' del mml mml = mp._print(Symbol("x^2")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msup' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeValue == '2' del mml mml = mp._print(Symbol("x__2")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msup' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeValue == '2' del mml mml = mp._print(Symbol("x_2")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msub' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeValue == '2' del mml mml = mp._print(Symbol("x^3_2")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msubsup' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeValue == '2' assert mml.childNodes[0].childNodes[2].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[2].childNodes[0].nodeValue == '3' del mml mml = mp._print(Symbol("x__3_2")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msubsup' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeValue == '2' assert mml.childNodes[0].childNodes[2].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[2].childNodes[0].nodeValue == '3' del mml mml = mp._print(Symbol("x_2_a")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msub' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mrow' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[ 0].nodeValue == '2' assert mml.childNodes[0].childNodes[1].childNodes[1].nodeName == 'mml:mo' assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[ 0].nodeValue == ' ' assert mml.childNodes[0].childNodes[1].childNodes[2].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[ 0].nodeValue == 'a' del mml mml = mp._print(Symbol("x^2^a")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msup' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mrow' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[ 0].nodeValue == '2' assert mml.childNodes[0].childNodes[1].childNodes[1].nodeName == 'mml:mo' assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[ 0].nodeValue == ' ' assert mml.childNodes[0].childNodes[1].childNodes[2].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[ 0].nodeValue == 'a' del mml mml = mp._print(Symbol("x__2__a")) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeName == 'mml:msup' assert mml.childNodes[0].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].nodeName == 'mml:mrow' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[0].childNodes[ 0].nodeValue == '2' assert mml.childNodes[0].childNodes[1].childNodes[1].nodeName == 'mml:mo' assert mml.childNodes[0].childNodes[1].childNodes[1].childNodes[ 0].nodeValue == ' ' assert mml.childNodes[0].childNodes[1].childNodes[2].nodeName == 'mml:mi' assert mml.childNodes[0].childNodes[1].childNodes[2].childNodes[ 0].nodeValue == 'a' del mml def test_content_mathml_greek(): mml = mp._print(Symbol('alpha')) assert mml.nodeName == 'ci' assert mml.childNodes[0].nodeValue == '\N{GREEK SMALL LETTER ALPHA}' assert mp.doprint(Symbol('alpha')) == 'α' assert mp.doprint(Symbol('beta')) == 'β' assert mp.doprint(Symbol('gamma')) == 'γ' assert mp.doprint(Symbol('delta')) == 'δ' assert mp.doprint(Symbol('epsilon')) == 'ε' assert mp.doprint(Symbol('zeta')) == 'ζ' assert mp.doprint(Symbol('eta')) == 'η' assert mp.doprint(Symbol('theta')) == 'θ' assert mp.doprint(Symbol('iota')) == 'ι' assert mp.doprint(Symbol('kappa')) == 'κ' assert mp.doprint(Symbol('lambda')) == 'λ' assert mp.doprint(Symbol('mu')) == 'μ' assert mp.doprint(Symbol('nu')) == 'ν' assert mp.doprint(Symbol('xi')) == 'ξ' assert mp.doprint(Symbol('omicron')) == 'ο' assert mp.doprint(Symbol('pi')) == 'π' assert mp.doprint(Symbol('rho')) == 'ρ' assert mp.doprint(Symbol('varsigma')) == 'ς' assert mp.doprint(Symbol('sigma')) == 'σ' assert mp.doprint(Symbol('tau')) == 'τ' assert mp.doprint(Symbol('upsilon')) == 'υ' assert mp.doprint(Symbol('phi')) == 'φ' assert mp.doprint(Symbol('chi')) == 'χ' assert mp.doprint(Symbol('psi')) == 'ψ' assert mp.doprint(Symbol('omega')) == 'ω' assert mp.doprint(Symbol('Alpha')) == 'Α' assert mp.doprint(Symbol('Beta')) == 'Β' assert mp.doprint(Symbol('Gamma')) == 'Γ' assert mp.doprint(Symbol('Delta')) == 'Δ' assert mp.doprint(Symbol('Epsilon')) == 'Ε' assert mp.doprint(Symbol('Zeta')) == 'Ζ' assert mp.doprint(Symbol('Eta')) == 'Η' assert mp.doprint(Symbol('Theta')) == 'Θ' assert mp.doprint(Symbol('Iota')) == 'Ι' assert mp.doprint(Symbol('Kappa')) == 'Κ' assert mp.doprint(Symbol('Lambda')) == 'Λ' assert mp.doprint(Symbol('Mu')) == 'Μ' assert mp.doprint(Symbol('Nu')) == 'Ν' assert mp.doprint(Symbol('Xi')) == 'Ξ' assert mp.doprint(Symbol('Omicron')) == 'Ο' assert mp.doprint(Symbol('Pi')) == 'Π' assert mp.doprint(Symbol('Rho')) == 'Ρ' assert mp.doprint(Symbol('Sigma')) == 'Σ' assert mp.doprint(Symbol('Tau')) == 'Τ' assert mp.doprint(Symbol('Upsilon')) == 'Υ' assert mp.doprint(Symbol('Phi')) == 'Φ' assert mp.doprint(Symbol('Chi')) == 'Χ' assert mp.doprint(Symbol('Psi')) == 'Ψ' assert mp.doprint(Symbol('Omega')) == 'Ω' def test_content_mathml_order(): expr = x**3 + x**2*y + 3*x*y**3 + y**4 mp = MathMLContentPrinter({'order': 'lex'}) mml = mp._print(expr) assert mml.childNodes[1].childNodes[0].nodeName == 'power' assert mml.childNodes[1].childNodes[1].childNodes[0].data == 'x' assert mml.childNodes[1].childNodes[2].childNodes[0].data == '3' assert mml.childNodes[4].childNodes[0].nodeName == 'power' assert mml.childNodes[4].childNodes[1].childNodes[0].data == 'y' assert mml.childNodes[4].childNodes[2].childNodes[0].data == '4' mp = MathMLContentPrinter({'order': 'rev-lex'}) mml = mp._print(expr) assert mml.childNodes[1].childNodes[0].nodeName == 'power' assert mml.childNodes[1].childNodes[1].childNodes[0].data == 'y' assert mml.childNodes[1].childNodes[2].childNodes[0].data == '4' assert mml.childNodes[4].childNodes[0].nodeName == 'power' assert mml.childNodes[4].childNodes[1].childNodes[0].data == 'x' assert mml.childNodes[4].childNodes[2].childNodes[0].data == '3' def test_content_settings(): raises(TypeError, lambda: mathml(x, method="garbage")) def test_content_mathml_logic(): assert mathml(And(x, y)) == 'xy' assert mathml(Or(x, y)) == 'xy' assert mathml(Xor(x, y)) == 'xy' assert mathml(Implies(x, y)) == 'xy' assert mathml(Not(x)) == 'x' def test_content_finite_sets(): assert mathml(FiniteSet(a)) == 'a' assert mathml(FiniteSet(a, b)) == 'ab' assert mathml(FiniteSet(FiniteSet(a, b), c)) == \ 'cab' A = FiniteSet(a) B = FiniteSet(b) C = FiniteSet(c) D = FiniteSet(d) U1 = Union(A, B, evaluate=False) U2 = Union(C, D, evaluate=False) I1 = Intersection(A, B, evaluate=False) I2 = Intersection(C, D, evaluate=False) C1 = Complement(A, B, evaluate=False) C2 = Complement(C, D, evaluate=False) # XXX ProductSet does not support evaluate keyword P1 = ProductSet(A, B) P2 = ProductSet(C, D) assert mathml(U1) == \ 'ab' assert mathml(I1) == \ 'ab' \ '' assert mathml(C1) == \ 'ab' assert mathml(P1) == \ 'ab' \ '' assert mathml(Intersection(A, U2, evaluate=False)) == \ 'a' \ 'cd' assert mathml(Intersection(U1, U2, evaluate=False)) == \ 'a' \ 'bc' \ 'd' # XXX Does the parenthesis appear correctly for these examples in mathjax? assert mathml(Intersection(C1, C2, evaluate=False)) == \ 'a' \ 'bc' \ 'd' assert mathml(Intersection(P1, P2, evaluate=False)) == \ 'a' \ 'b' \ 'cd' assert mathml(Union(A, I2, evaluate=False)) == \ 'a' \ 'cd' assert mathml(Union(I1, I2, evaluate=False)) == \ 'a' \ 'bc' \ 'd' assert mathml(Union(C1, C2, evaluate=False)) == \ 'a' \ 'bc' \ 'd' assert mathml(Union(P1, P2, evaluate=False)) == \ 'a' \ 'b' \ 'cd' assert mathml(Complement(A, C2, evaluate=False)) == \ 'a' \ 'cd' assert mathml(Complement(U1, U2, evaluate=False)) == \ 'a' \ 'bc' \ 'd' assert mathml(Complement(I1, I2, evaluate=False)) == \ 'a' \ 'bc' \ 'd' assert mathml(Complement(P1, P2, evaluate=False)) == \ 'a' \ 'b' \ 'cd' assert mathml(ProductSet(A, P2)) == \ 'a' \ 'c' \ 'd' assert mathml(ProductSet(U1, U2)) == \ 'a' \ 'bc' \ 'd' assert mathml(ProductSet(I1, I2)) == \ 'a' \ 'b' \ 'cd' assert mathml(ProductSet(C1, C2)) == \ 'a' \ 'b' \ 'cd' def test_presentation_printmethod(): assert mpp.doprint(1 + x) == 'x+1' assert mpp.doprint(x**2) == 'x2' assert mpp.doprint(x**-1) == '1x' assert mpp.doprint(x**-2) == \ '1x2' assert mpp.doprint(2*x) == \ '2x' def test_presentation_mathml_core(): mml_1 = mpp._print(1 + x) assert mml_1.nodeName == 'mrow' nodes = mml_1.childNodes assert len(nodes) == 3 assert nodes[0].nodeName in ['mi', 'mn'] assert nodes[1].nodeName == 'mo' if nodes[0].nodeName == 'mn': assert nodes[0].childNodes[0].nodeValue == '1' assert nodes[2].childNodes[0].nodeValue == 'x' else: assert nodes[0].childNodes[0].nodeValue == 'x' assert nodes[2].childNodes[0].nodeValue == '1' mml_2 = mpp._print(x**2) assert mml_2.nodeName == 'msup' nodes = mml_2.childNodes assert nodes[0].childNodes[0].nodeValue == 'x' assert nodes[1].childNodes[0].nodeValue == '2' mml_3 = mpp._print(2*x) assert mml_3.nodeName == 'mrow' nodes = mml_3.childNodes assert nodes[0].childNodes[0].nodeValue == '2' assert nodes[1].childNodes[0].nodeValue == '⁢' assert nodes[2].childNodes[0].nodeValue == 'x' mml = mpp._print(Float(1.0, 2)*x) assert mml.nodeName == 'mrow' nodes = mml.childNodes assert nodes[0].childNodes[0].nodeValue == '1.0' assert nodes[1].childNodes[0].nodeValue == '⁢' assert nodes[2].childNodes[0].nodeValue == 'x' def test_presentation_mathml_functions(): mml_1 = mpp._print(sin(x)) assert mml_1.childNodes[0].childNodes[0 ].nodeValue == 'sin' assert mml_1.childNodes[1].childNodes[0 ].childNodes[0].nodeValue == 'x' mml_2 = mpp._print(diff(sin(x), x, evaluate=False)) assert mml_2.nodeName == 'mrow' assert mml_2.childNodes[0].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == 'ⅆ' assert mml_2.childNodes[1].childNodes[1 ].nodeName == 'mfenced' assert mml_2.childNodes[0].childNodes[1 ].childNodes[0].childNodes[0].nodeValue == 'ⅆ' mml_3 = mpp._print(diff(cos(x*y), x, evaluate=False)) assert mml_3.childNodes[0].nodeName == 'mfrac' assert mml_3.childNodes[0].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == '∂' assert mml_3.childNodes[1].childNodes[0 ].childNodes[0].nodeValue == 'cos' def test_print_derivative(): f = Function('f') d = Derivative(f(x, y, z), x, z, x, z, z, y) assert mathml(d) == \ 'yz2xzxxyz' assert mathml(d, printer='presentation') == \ '6y2zxzxfxyz' def test_presentation_mathml_limits(): lim_fun = sin(x)/x mml_1 = mpp._print(Limit(lim_fun, x, 0)) assert mml_1.childNodes[0].nodeName == 'munder' assert mml_1.childNodes[0].childNodes[0 ].childNodes[0].nodeValue == 'lim' assert mml_1.childNodes[0].childNodes[1 ].childNodes[0].childNodes[0 ].nodeValue == 'x' assert mml_1.childNodes[0].childNodes[1 ].childNodes[1].childNodes[0 ].nodeValue == '→' assert mml_1.childNodes[0].childNodes[1 ].childNodes[2].childNodes[0 ].nodeValue == '0' def test_presentation_mathml_integrals(): assert mpp.doprint(Integral(x, (x, 0, 1))) == \ '01'\ 'xx' assert mpp.doprint(Integral(log(x), x)) == \ 'logx'\ 'x' assert mpp.doprint(Integral(x*y, x, y)) == \ 'x'\ 'yyx' z, w = symbols('z w') assert mpp.doprint(Integral(x*y*z, x, y, z)) == \ 'x'\ 'yz'\ 'zyx' assert mpp.doprint(Integral(x*y*z*w, x, y, z, w)) == \ ''\ 'w'\ 'xy'\ 'zw'\ 'zyx' assert mpp.doprint(Integral(x, x, y, (z, 0, 1))) == \ '01'\ 'xz'\ 'yx' assert mpp.doprint(Integral(x, (x, 0))) == \ '0x'\ 'x' def test_presentation_mathml_matrices(): A = Matrix([1, 2, 3]) B = Matrix([[0, 5, 4], [2, 3, 1], [9, 7, 9]]) mll_1 = mpp._print(A) assert mll_1.childNodes[0].nodeName == 'mtable' assert mll_1.childNodes[0].childNodes[0].nodeName == 'mtr' assert len(mll_1.childNodes[0].childNodes) == 3 assert mll_1.childNodes[0].childNodes[0].childNodes[0].nodeName == 'mtd' assert len(mll_1.childNodes[0].childNodes[0].childNodes) == 1 assert mll_1.childNodes[0].childNodes[0].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == '1' assert mll_1.childNodes[0].childNodes[1].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == '2' assert mll_1.childNodes[0].childNodes[2].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == '3' mll_2 = mpp._print(B) assert mll_2.childNodes[0].nodeName == 'mtable' assert mll_2.childNodes[0].childNodes[0].nodeName == 'mtr' assert len(mll_2.childNodes[0].childNodes) == 3 assert mll_2.childNodes[0].childNodes[0].childNodes[0].nodeName == 'mtd' assert len(mll_2.childNodes[0].childNodes[0].childNodes) == 3 assert mll_2.childNodes[0].childNodes[0].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == '0' assert mll_2.childNodes[0].childNodes[0].childNodes[1 ].childNodes[0].childNodes[0].nodeValue == '5' assert mll_2.childNodes[0].childNodes[0].childNodes[2 ].childNodes[0].childNodes[0].nodeValue == '4' assert mll_2.childNodes[0].childNodes[1].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == '2' assert mll_2.childNodes[0].childNodes[1].childNodes[1 ].childNodes[0].childNodes[0].nodeValue == '3' assert mll_2.childNodes[0].childNodes[1].childNodes[2 ].childNodes[0].childNodes[0].nodeValue == '1' assert mll_2.childNodes[0].childNodes[2].childNodes[0 ].childNodes[0].childNodes[0].nodeValue == '9' assert mll_2.childNodes[0].childNodes[2].childNodes[1 ].childNodes[0].childNodes[0].nodeValue == '7' assert mll_2.childNodes[0].childNodes[2].childNodes[2 ].childNodes[0].childNodes[0].nodeValue == '9' def test_presentation_mathml_sums(): summand = x mml_1 = mpp._print(Sum(summand, (x, 1, 10))) assert mml_1.childNodes[0].nodeName == 'munderover' assert len(mml_1.childNodes[0].childNodes) == 3 assert mml_1.childNodes[0].childNodes[0].childNodes[0 ].nodeValue == '∑' assert len(mml_1.childNodes[0].childNodes[1].childNodes) == 3 assert mml_1.childNodes[0].childNodes[2].childNodes[0 ].nodeValue == '10' assert mml_1.childNodes[1].childNodes[0].nodeValue == 'x' def test_presentation_mathml_add(): mml = mpp._print(x**5 - x**4 + x) assert len(mml.childNodes) == 5 assert mml.childNodes[0].childNodes[0].childNodes[0 ].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].childNodes[0 ].nodeValue == '5' assert mml.childNodes[1].childNodes[0].nodeValue == '-' assert mml.childNodes[2].childNodes[0].childNodes[0 ].nodeValue == 'x' assert mml.childNodes[2].childNodes[1].childNodes[0 ].nodeValue == '4' assert mml.childNodes[3].childNodes[0].nodeValue == '+' assert mml.childNodes[4].childNodes[0].nodeValue == 'x' def test_presentation_mathml_Rational(): mml_1 = mpp._print(Rational(1, 1)) assert mml_1.nodeName == 'mn' mml_2 = mpp._print(Rational(2, 5)) assert mml_2.nodeName == 'mfrac' assert mml_2.childNodes[0].childNodes[0].nodeValue == '2' assert mml_2.childNodes[1].childNodes[0].nodeValue == '5' def test_presentation_mathml_constants(): mml = mpp._print(I) assert mml.childNodes[0].nodeValue == 'ⅈ' mml = mpp._print(E) assert mml.childNodes[0].nodeValue == 'ⅇ' mml = mpp._print(oo) assert mml.childNodes[0].nodeValue == '∞' mml = mpp._print(pi) assert mml.childNodes[0].nodeValue == 'π' assert mathml(GoldenRatio, printer='presentation') == 'Φ' assert mathml(zoo, printer='presentation') == \ '~' assert mathml(S.NaN, printer='presentation') == 'NaN' def test_presentation_mathml_trig(): mml = mpp._print(sin(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'sin' mml = mpp._print(cos(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'cos' mml = mpp._print(tan(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'tan' mml = mpp._print(asin(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'arcsin' mml = mpp._print(acos(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'arccos' mml = mpp._print(atan(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'arctan' mml = mpp._print(sinh(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'sinh' mml = mpp._print(cosh(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'cosh' mml = mpp._print(tanh(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'tanh' mml = mpp._print(asinh(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'arcsinh' mml = mpp._print(atanh(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'arctanh' mml = mpp._print(acosh(x)) assert mml.childNodes[0].childNodes[0].nodeValue == 'arccosh' def test_presentation_mathml_relational(): mml_1 = mpp._print(Eq(x, 1)) assert len(mml_1.childNodes) == 3 assert mml_1.childNodes[0].nodeName == 'mi' assert mml_1.childNodes[0].childNodes[0].nodeValue == 'x' assert mml_1.childNodes[1].nodeName == 'mo' assert mml_1.childNodes[1].childNodes[0].nodeValue == '=' assert mml_1.childNodes[2].nodeName == 'mn' assert mml_1.childNodes[2].childNodes[0].nodeValue == '1' mml_2 = mpp._print(Ne(1, x)) assert len(mml_2.childNodes) == 3 assert mml_2.childNodes[0].nodeName == 'mn' assert mml_2.childNodes[0].childNodes[0].nodeValue == '1' assert mml_2.childNodes[1].nodeName == 'mo' assert mml_2.childNodes[1].childNodes[0].nodeValue == '≠' assert mml_2.childNodes[2].nodeName == 'mi' assert mml_2.childNodes[2].childNodes[0].nodeValue == 'x' mml_3 = mpp._print(Ge(1, x)) assert len(mml_3.childNodes) == 3 assert mml_3.childNodes[0].nodeName == 'mn' assert mml_3.childNodes[0].childNodes[0].nodeValue == '1' assert mml_3.childNodes[1].nodeName == 'mo' assert mml_3.childNodes[1].childNodes[0].nodeValue == '≥' assert mml_3.childNodes[2].nodeName == 'mi' assert mml_3.childNodes[2].childNodes[0].nodeValue == 'x' mml_4 = mpp._print(Lt(1, x)) assert len(mml_4.childNodes) == 3 assert mml_4.childNodes[0].nodeName == 'mn' assert mml_4.childNodes[0].childNodes[0].nodeValue == '1' assert mml_4.childNodes[1].nodeName == 'mo' assert mml_4.childNodes[1].childNodes[0].nodeValue == '<' assert mml_4.childNodes[2].nodeName == 'mi' assert mml_4.childNodes[2].childNodes[0].nodeValue == 'x' def test_presentation_symbol(): mml = mpp._print(x) assert mml.nodeName == 'mi' assert mml.childNodes[0].nodeValue == 'x' del mml mml = mpp._print(Symbol("x^2")) assert mml.nodeName == 'msup' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].nodeValue == '2' del mml mml = mpp._print(Symbol("x__2")) assert mml.nodeName == 'msup' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].nodeValue == '2' del mml mml = mpp._print(Symbol("x_2")) assert mml.nodeName == 'msub' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].nodeValue == '2' del mml mml = mpp._print(Symbol("x^3_2")) assert mml.nodeName == 'msubsup' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].nodeValue == '2' assert mml.childNodes[2].nodeName == 'mi' assert mml.childNodes[2].childNodes[0].nodeValue == '3' del mml mml = mpp._print(Symbol("x__3_2")) assert mml.nodeName == 'msubsup' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].nodeValue == '2' assert mml.childNodes[2].nodeName == 'mi' assert mml.childNodes[2].childNodes[0].nodeValue == '3' del mml mml = mpp._print(Symbol("x_2_a")) assert mml.nodeName == 'msub' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mrow' assert mml.childNodes[1].childNodes[0].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' assert mml.childNodes[1].childNodes[1].nodeName == 'mo' assert mml.childNodes[1].childNodes[1].childNodes[0].nodeValue == ' ' assert mml.childNodes[1].childNodes[2].nodeName == 'mi' assert mml.childNodes[1].childNodes[2].childNodes[0].nodeValue == 'a' del mml mml = mpp._print(Symbol("x^2^a")) assert mml.nodeName == 'msup' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mrow' assert mml.childNodes[1].childNodes[0].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' assert mml.childNodes[1].childNodes[1].nodeName == 'mo' assert mml.childNodes[1].childNodes[1].childNodes[0].nodeValue == ' ' assert mml.childNodes[1].childNodes[2].nodeName == 'mi' assert mml.childNodes[1].childNodes[2].childNodes[0].nodeValue == 'a' del mml mml = mpp._print(Symbol("x__2__a")) assert mml.nodeName == 'msup' assert mml.childNodes[0].nodeName == 'mi' assert mml.childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[1].nodeName == 'mrow' assert mml.childNodes[1].childNodes[0].nodeName == 'mi' assert mml.childNodes[1].childNodes[0].childNodes[0].nodeValue == '2' assert mml.childNodes[1].childNodes[1].nodeName == 'mo' assert mml.childNodes[1].childNodes[1].childNodes[0].nodeValue == ' ' assert mml.childNodes[1].childNodes[2].nodeName == 'mi' assert mml.childNodes[1].childNodes[2].childNodes[0].nodeValue == 'a' del mml def test_presentation_mathml_greek(): mml = mpp._print(Symbol('alpha')) assert mml.nodeName == 'mi' assert mml.childNodes[0].nodeValue == '\N{GREEK SMALL LETTER ALPHA}' assert mpp.doprint(Symbol('alpha')) == 'α' assert mpp.doprint(Symbol('beta')) == 'β' assert mpp.doprint(Symbol('gamma')) == 'γ' assert mpp.doprint(Symbol('delta')) == 'δ' assert mpp.doprint(Symbol('epsilon')) == 'ε' assert mpp.doprint(Symbol('zeta')) == 'ζ' assert mpp.doprint(Symbol('eta')) == 'η' assert mpp.doprint(Symbol('theta')) == 'θ' assert mpp.doprint(Symbol('iota')) == 'ι' assert mpp.doprint(Symbol('kappa')) == 'κ' assert mpp.doprint(Symbol('lambda')) == 'λ' assert mpp.doprint(Symbol('mu')) == 'μ' assert mpp.doprint(Symbol('nu')) == 'ν' assert mpp.doprint(Symbol('xi')) == 'ξ' assert mpp.doprint(Symbol('omicron')) == 'ο' assert mpp.doprint(Symbol('pi')) == 'π' assert mpp.doprint(Symbol('rho')) == 'ρ' assert mpp.doprint(Symbol('varsigma')) == 'ς' assert mpp.doprint(Symbol('sigma')) == 'σ' assert mpp.doprint(Symbol('tau')) == 'τ' assert mpp.doprint(Symbol('upsilon')) == 'υ' assert mpp.doprint(Symbol('phi')) == 'φ' assert mpp.doprint(Symbol('chi')) == 'χ' assert mpp.doprint(Symbol('psi')) == 'ψ' assert mpp.doprint(Symbol('omega')) == 'ω' assert mpp.doprint(Symbol('Alpha')) == 'Α' assert mpp.doprint(Symbol('Beta')) == 'Β' assert mpp.doprint(Symbol('Gamma')) == 'Γ' assert mpp.doprint(Symbol('Delta')) == 'Δ' assert mpp.doprint(Symbol('Epsilon')) == 'Ε' assert mpp.doprint(Symbol('Zeta')) == 'Ζ' assert mpp.doprint(Symbol('Eta')) == 'Η' assert mpp.doprint(Symbol('Theta')) == 'Θ' assert mpp.doprint(Symbol('Iota')) == 'Ι' assert mpp.doprint(Symbol('Kappa')) == 'Κ' assert mpp.doprint(Symbol('Lambda')) == 'Λ' assert mpp.doprint(Symbol('Mu')) == 'Μ' assert mpp.doprint(Symbol('Nu')) == 'Ν' assert mpp.doprint(Symbol('Xi')) == 'Ξ' assert mpp.doprint(Symbol('Omicron')) == 'Ο' assert mpp.doprint(Symbol('Pi')) == 'Π' assert mpp.doprint(Symbol('Rho')) == 'Ρ' assert mpp.doprint(Symbol('Sigma')) == 'Σ' assert mpp.doprint(Symbol('Tau')) == 'Τ' assert mpp.doprint(Symbol('Upsilon')) == 'Υ' assert mpp.doprint(Symbol('Phi')) == 'Φ' assert mpp.doprint(Symbol('Chi')) == 'Χ' assert mpp.doprint(Symbol('Psi')) == 'Ψ' assert mpp.doprint(Symbol('Omega')) == 'Ω' def test_presentation_mathml_order(): expr = x**3 + x**2*y + 3*x*y**3 + y**4 mp = MathMLPresentationPrinter({'order': 'lex'}) mml = mp._print(expr) assert mml.childNodes[0].nodeName == 'msup' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeValue == '3' assert mml.childNodes[6].nodeName == 'msup' assert mml.childNodes[6].childNodes[0].childNodes[0].nodeValue == 'y' assert mml.childNodes[6].childNodes[1].childNodes[0].nodeValue == '4' mp = MathMLPresentationPrinter({'order': 'rev-lex'}) mml = mp._print(expr) assert mml.childNodes[0].nodeName == 'msup' assert mml.childNodes[0].childNodes[0].childNodes[0].nodeValue == 'y' assert mml.childNodes[0].childNodes[1].childNodes[0].nodeValue == '4' assert mml.childNodes[6].nodeName == 'msup' assert mml.childNodes[6].childNodes[0].childNodes[0].nodeValue == 'x' assert mml.childNodes[6].childNodes[1].childNodes[0].nodeValue == '3' def test_print_intervals(): a = Symbol('a', real=True) assert mpp.doprint(Interval(0, a)) == \ '0a' assert mpp.doprint(Interval(0, a, False, False)) == \ '0a' assert mpp.doprint(Interval(0, a, True, False)) == \ '0a' assert mpp.doprint(Interval(0, a, False, True)) == \ '0a' assert mpp.doprint(Interval(0, a, True, True)) == \ '0a' def test_print_tuples(): assert mpp.doprint(Tuple(0,)) == \ '0' assert mpp.doprint(Tuple(0, a)) == \ '0a' assert mpp.doprint(Tuple(0, a, a)) == \ '0aa' assert mpp.doprint(Tuple(0, 1, 2, 3, 4)) == \ '01234' assert mpp.doprint(Tuple(0, 1, Tuple(2, 3, 4))) == \ '0123'\ '4' def test_print_re_im(): assert mpp.doprint(re(x)) == \ 'Rx' assert mpp.doprint(im(x)) == \ 'Ix' assert mpp.doprint(re(x + 1)) == \ 'Rx'\ '+1' assert mpp.doprint(im(x + 1)) == \ 'Ix' def test_print_Abs(): assert mpp.doprint(Abs(x)) == \ 'x' assert mpp.doprint(Abs(x + 1)) == \ 'x+1' def test_print_Determinant(): assert mpp.doprint(Determinant(Matrix([[1, 2], [3, 4]]))) == \ '1234' def test_presentation_settings(): raises(TypeError, lambda: mathml(x, printer='presentation', method="garbage")) def test_toprettyxml_hooking(): # test that the patch doesn't influence the behavior of the standard # library import xml.dom.minidom doc1 = xml.dom.minidom.parseString( "x1") doc2 = xml.dom.minidom.parseString( "x+1") prettyxml_old1 = doc1.toprettyxml() prettyxml_old2 = doc2.toprettyxml() mp.apply_patch() mp.restore_patch() assert prettyxml_old1 == doc1.toprettyxml() assert prettyxml_old2 == doc2.toprettyxml() def test_print_domains(): from sympy import Complexes, Integers, Naturals, Naturals0, Reals assert mpp.doprint(Complexes) == '' assert mpp.doprint(Integers) == '' assert mpp.doprint(Naturals) == '' assert mpp.doprint(Naturals0) == \ '0' assert mpp.doprint(Reals) == '' def test_print_expression_with_minus(): assert mpp.doprint(-x) == '-x' assert mpp.doprint(-x/y) == \ '-xy' assert mpp.doprint(-Rational(1, 2)) == \ '-12' def test_print_AssocOp(): from sympy.core.operations import AssocOp class TestAssocOp(AssocOp): identity = 0 expr = TestAssocOp(1, 2) mpp.doprint(expr) == \ 'testassocop21' def test_print_basic(): expr = Basic(1, 2) assert mpp.doprint(expr) == \ 'basic12' assert mp.doprint(expr) == '12' def test_mat_delim_print(): expr = Matrix([[1, 2], [3, 4]]) assert mathml(expr, printer='presentation', mat_delim='[') == \ '1'\ '234'\ '' assert mathml(expr, printer='presentation', mat_delim='(') == \ '12'\ '34' assert mathml(expr, printer='presentation', mat_delim='') == \ '12'\ '34' def test_ln_notation_print(): expr = log(x) assert mathml(expr, printer='presentation') == \ 'logx' assert mathml(expr, printer='presentation', ln_notation=False) == \ 'logx' assert mathml(expr, printer='presentation', ln_notation=True) == \ 'lnx' def test_mul_symbol_print(): expr = x * y assert mathml(expr, printer='presentation') == \ 'xy' assert mathml(expr, printer='presentation', mul_symbol=None) == \ 'xy' assert mathml(expr, printer='presentation', mul_symbol='dot') == \ 'x·y' assert mathml(expr, printer='presentation', mul_symbol='ldot') == \ 'xy' assert mathml(expr, printer='presentation', mul_symbol='times') == \ 'x×y' def test_print_lerchphi(): assert mpp.doprint(lerchphi(1, 2, 3)) == \ 'Φ123' def test_print_polylog(): assert mp.doprint(polylog(x, y)) == \ 'xy' assert mpp.doprint(polylog(x, y)) == \ 'Lixy' def test_print_set_frozenset(): f = frozenset({1, 5, 3}) assert mpp.doprint(f) == \ '135' s = set({1, 2, 3}) assert mpp.doprint(s) == \ '123' def test_print_FiniteSet(): f1 = FiniteSet(x, 1, 3) assert mpp.doprint(f1) == \ '13x' def test_print_LambertW(): assert mpp.doprint(LambertW(x)) == 'Wx' assert mpp.doprint(LambertW(x, y)) == 'Wxy' def test_print_EmptySet(): assert mpp.doprint(EmptySet()) == '' def test_print_UniversalSet(): assert mpp.doprint(S.UniversalSet) == '𝕌' def test_print_spaces(): assert mpp.doprint(HilbertSpace()) == '' assert mpp.doprint(ComplexSpace(2)) == '𝒞2' assert mpp.doprint(FockSpace()) == '' def test_print_constants(): assert mpp.doprint(hbar) == '' assert mpp.doprint(TribonacciConstant) == 'TribonacciConstant' assert mpp.doprint(EulerGamma) == 'γ' def test_print_Contains(): assert mpp.doprint(Contains(x, S.Naturals)) == \ 'x' def test_print_Dagger(): assert mpp.doprint(Dagger(x)) == 'x' def test_print_SetOp(): f1 = FiniteSet(x, 1, 3) f2 = FiniteSet(y, 2, 4) prntr = lambda x: mathml(x, printer='presentation') assert prntr(Union(f1, f2, evaluate=False)) == \ '13x'\ '2'\ '4y' assert prntr(Intersection(f1, f2, evaluate=False)) == \ '13x'\ '2'\ '4y' assert prntr(Complement(f1, f2, evaluate=False)) == \ '13x'\ '2'\ '4y' assert prntr(SymmetricDifference(f1, f2, evaluate=False)) == \ '13x'\ '2'\ '4y' A = FiniteSet(a) C = FiniteSet(c) D = FiniteSet(d) U1 = Union(C, D, evaluate=False) I1 = Intersection(C, D, evaluate=False) C1 = Complement(C, D, evaluate=False) D1 = SymmetricDifference(C, D, evaluate=False) # XXX ProductSet does not support evaluate keyword P1 = ProductSet(C, D) assert prntr(Union(A, I1, evaluate=False)) == \ 'a' \ '' \ 'c' \ 'd' assert prntr(Intersection(A, C1, evaluate=False)) == \ 'a' \ '' \ 'c' \ 'd' assert prntr(Complement(A, D1, evaluate=False)) == \ 'a' \ '' \ 'c' \ 'd' assert prntr(SymmetricDifference(A, P1, evaluate=False)) == \ 'a' \ '' \ 'c×' \ 'd' assert prntr(ProductSet(A, U1)) == \ 'a' \ '×' \ 'c' \ 'd' def test_print_logic(): assert mpp.doprint(And(x, y)) == \ 'xy' assert mpp.doprint(Or(x, y)) == \ 'xy' assert mpp.doprint(Xor(x, y)) == \ 'xy' assert mpp.doprint(Implies(x, y)) == \ 'xy' assert mpp.doprint(Equivalent(x, y)) == \ 'xy' assert mpp.doprint(And(Eq(x, y), x > 4)) == \ 'x=y'\ 'x>4' assert mpp.doprint(And(Eq(x, 3), y < 3, x > y + 1)) == \ 'x=3'\ 'x>y+1'\ 'y<3' assert mpp.doprint(Or(Eq(x, y), x > 4)) == \ 'x=y'\ 'x>4' assert mpp.doprint(And(Eq(x, 3), Or(y < 3, x > y + 1))) == \ 'x=3'\ 'x>y+'\ '1y<'\ '3' assert mpp.doprint(Not(x)) == '¬x' assert mpp.doprint(Not(And(x, y))) == \ '¬x'\ 'y' def test_root_notation_print(): assert mathml(x**(S.One/3), printer='presentation') == \ 'x3' assert mathml(x**(S.One/3), printer='presentation', root_notation=False) ==\ 'x13' assert mathml(x**(S.One/3), printer='content') == \ '3x' assert mathml(x**(S.One/3), printer='content', root_notation=False) == \ 'x13' assert mathml(x**(Rational(-1, 3)), printer='presentation') == \ '1x3' assert mathml(x**(Rational(-1, 3)), printer='presentation', root_notation=False) \ == '1x13' def test_fold_frac_powers_print(): expr = x ** Rational(5, 2) assert mathml(expr, printer='presentation') == \ 'x52' assert mathml(expr, printer='presentation', fold_frac_powers=True) == \ 'x52' assert mathml(expr, printer='presentation', fold_frac_powers=False) == \ 'x52' def test_fold_short_frac_print(): expr = Rational(2, 5) assert mathml(expr, printer='presentation') == \ '25' assert mathml(expr, printer='presentation', fold_short_frac=True) == \ '25' assert mathml(expr, printer='presentation', fold_short_frac=False) == \ '25' def test_print_factorials(): assert mpp.doprint(factorial(x)) == 'x!' assert mpp.doprint(factorial(x + 1)) == \ 'x+1!' assert mpp.doprint(factorial2(x)) == 'x!!' assert mpp.doprint(factorial2(x + 1)) == \ 'x+1!!' assert mpp.doprint(binomial(x, y)) == \ 'xy' assert mpp.doprint(binomial(4, x + y)) == \ '4x'\ '+y' def test_print_floor(): expr = floor(x) assert mathml(expr, printer='presentation') == \ 'x' def test_print_ceiling(): expr = ceiling(x) assert mathml(expr, printer='presentation') == \ 'x' def test_print_Lambda(): expr = Lambda(x, x+1) assert mathml(expr, printer='presentation') == \ 'xx+'\ '1' expr = Lambda((x, y), x + y) assert mathml(expr, printer='presentation') == \ 'xy'\ 'x+y' def test_print_conjugate(): assert mpp.doprint(conjugate(x)) == \ 'x' assert mpp.doprint(conjugate(x + 1)) == \ 'x+1' def test_print_AccumBounds(): a = Symbol('a', real=True) assert mpp.doprint(AccumBounds(0, 1)) == '01' assert mpp.doprint(AccumBounds(0, a)) == '0a' assert mpp.doprint(AccumBounds(a + 1, a + 2)) == 'a+1a+2' def test_print_Float(): assert mpp.doprint(Float(1e100)) == '1.0·10100' assert mpp.doprint(Float(1e-100)) == '1.0·10-100' assert mpp.doprint(Float(-1e100)) == '-1.0·10100' assert mpp.doprint(Float(1.0*oo)) == '' assert mpp.doprint(Float(-1.0*oo)) == '-' def test_print_different_functions(): assert mpp.doprint(gamma(x)) == 'Γx' assert mpp.doprint(lowergamma(x, y)) == 'γxy' assert mpp.doprint(uppergamma(x, y)) == 'Γxy' assert mpp.doprint(zeta(x)) == 'ζx' assert mpp.doprint(zeta(x, y)) == 'ζxy' assert mpp.doprint(dirichlet_eta(x)) == 'ηx' assert mpp.doprint(elliptic_k(x)) == 'Κx' assert mpp.doprint(totient(x)) == 'ϕx' assert mpp.doprint(reduced_totient(x)) == 'λx' assert mpp.doprint(primenu(x)) == 'νx' assert mpp.doprint(primeomega(x)) == 'Ωx' assert mpp.doprint(fresnels(x)) == 'Sx' assert mpp.doprint(fresnelc(x)) == 'Cx' assert mpp.doprint(Heaviside(x)) == 'Θx12' def test_mathml_builtins(): assert mpp.doprint(None) == 'None' assert mpp.doprint(true) == 'True' assert mpp.doprint(false) == 'False' def test_mathml_Range(): assert mpp.doprint(Range(1, 51)) == \ '1250' assert mpp.doprint(Range(1, 4)) == \ '123' assert mpp.doprint(Range(0, 3, 1)) == \ '012' assert mpp.doprint(Range(0, 30, 1)) == \ '0129' assert mpp.doprint(Range(30, 1, -1)) == \ '3029'\ '2' assert mpp.doprint(Range(0, oo, 2)) == \ '02' assert mpp.doprint(Range(oo, -2, -2)) == \ '20' assert mpp.doprint(Range(-2, -oo, -1)) == \ '-2-3' def test_print_exp(): assert mpp.doprint(exp(x)) == \ 'x' assert mpp.doprint(exp(1) + exp(2)) == \ '+2' def test_print_MinMax(): assert mpp.doprint(Min(x, y)) == \ 'minxy' assert mpp.doprint(Min(x, 2, x**3)) == \ 'min2xx'\ '3' assert mpp.doprint(Max(x, y)) == \ 'maxxy' assert mpp.doprint(Max(x, 2, x**3)) == \ 'max2xx'\ '3' def test_mathml_presentation_numbers(): n = Symbol('n') assert mathml(catalan(n), printer='presentation') == \ 'Cn' assert mathml(bernoulli(n), printer='presentation') == \ 'Bn' assert mathml(bell(n), printer='presentation') == \ 'Bn' assert mathml(euler(n), printer='presentation') == \ 'En' assert mathml(fibonacci(n), printer='presentation') == \ 'Fn' assert mathml(lucas(n), printer='presentation') == \ 'Ln' assert mathml(tribonacci(n), printer='presentation') == \ 'Tn' assert mathml(bernoulli(n, x), printer='presentation') == \ 'Bnx' assert mathml(bell(n, x), printer='presentation') == \ 'Bnx' assert mathml(euler(n, x), printer='presentation') == \ 'Enx' assert mathml(fibonacci(n, x), printer='presentation') == \ 'Fnx' assert mathml(tribonacci(n, x), printer='presentation') == \ 'Tnx' def test_mathml_presentation_mathieu(): assert mathml(mathieuc(x, y, z), printer='presentation') == \ 'Cxyz' assert mathml(mathieus(x, y, z), printer='presentation') == \ 'Sxyz' assert mathml(mathieucprime(x, y, z), printer='presentation') == \ 'C′xyz' assert mathml(mathieusprime(x, y, z), printer='presentation') == \ 'S′xyz' def test_mathml_presentation_stieltjes(): assert mathml(stieltjes(n), printer='presentation') == \ 'γn' assert mathml(stieltjes(n, x), printer='presentation') == \ 'γnx' def test_print_matrix_symbol(): A = MatrixSymbol('A', 1, 2) assert mpp.doprint(A) == 'A' assert mp.doprint(A) == 'A' assert mathml(A, printer='presentation', mat_symbol_style="bold") == \ 'A' # No effect in content printer assert mathml(A, mat_symbol_style="bold") == 'A' def test_print_hadamard(): from sympy.matrices.expressions import HadamardProduct from sympy.matrices.expressions import Transpose X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) assert mathml(HadamardProduct(X, Y*Y), printer="presentation") == \ '' \ 'X' \ '' \ 'Y2' \ '' assert mathml(HadamardProduct(X, Y)*Y, printer="presentation") == \ '' \ '' \ 'XY' \ '' \ 'Y' \ '' assert mathml(HadamardProduct(X, Y, Y), printer="presentation") == \ '' \ 'X' \ 'Y' \ 'Y' \ '' assert mathml( Transpose(HadamardProduct(X, Y)), printer="presentation") == \ '' \ '' \ 'XY' \ '' \ 'T' \ '' def test_print_random_symbol(): R = RandomSymbol(Symbol('R')) assert mpp.doprint(R) == 'R' assert mp.doprint(R) == 'R' def test_print_IndexedBase(): assert mathml(IndexedBase(a)[b], printer='presentation') == \ 'ab' assert mathml(IndexedBase(a)[b, c, d], printer='presentation') == \ 'abcd' assert mathml(IndexedBase(a)[b]*IndexedBase(c)[d]*IndexedBase(e), printer='presentation') == \ 'ab⁢'\ 'cde' def test_print_Indexed(): assert mathml(IndexedBase(a), printer='presentation') == 'a' assert mathml(IndexedBase(a/b), printer='presentation') == \ 'ab' assert mathml(IndexedBase((a, b)), printer='presentation') == \ 'ab' def test_print_MatrixElement(): i, j = symbols('i j') A = MatrixSymbol('A', i, j) assert mathml(A[0,0],printer = 'presentation') == \ 'A00' assert mathml(A[i,j], printer = 'presentation') == \ 'Aij' assert mathml(A[i*j,0], printer = 'presentation') == \ 'Aij0' def test_print_Vector(): ACS = CoordSys3D('A') assert mathml(Cross(ACS.i, ACS.j*ACS.x*3 + ACS.k), printer='presentation') == \ 'i^'\ 'A×'\ '3'\ 'xA'\ ''\ 'j^'\ 'A+'\ 'k^'\ 'A' assert mathml(Cross(ACS.i, ACS.j), printer='presentation') == \ 'i^'\ 'A×'\ 'j^'\ 'A' assert mathml(x*Cross(ACS.i, ACS.j), printer='presentation') == \ 'x'\ 'i^'\ 'A×'\ 'j^'\ 'A' assert mathml(Cross(x*ACS.i, ACS.j), printer='presentation') == \ '-j'\ '^A'\ '×x'\ 'i'\ '^A'\ '' assert mathml(Curl(3*ACS.x*ACS.j), printer='presentation') == \ '×'\ '3'\ 'xA'\ ''\ 'j^'\ 'A' assert mathml(Curl(3*x*ACS.x*ACS.j), printer='presentation') == \ '×'\ '3x'\ 'A'\ 'x'\ 'j^'\ 'A' assert mathml(x*Curl(3*ACS.x*ACS.j), printer='presentation') == \ 'x'\ '×3'\ 'x'\ 'A'\ 'j'\ '^A'\ '' assert mathml(Curl(3*x*ACS.x*ACS.j + ACS.i), printer='presentation') == \ '×'\ 'i^'\ 'A+'\ '3x'\ 'A'\ 'x'\ 'j^'\ 'A' assert mathml(Divergence(3*ACS.x*ACS.j), printer='presentation') == \ '·'\ '3x'\ 'A'\ 'j'\ '^A' assert mathml(x*Divergence(3*ACS.x*ACS.j), printer='presentation') == \ 'x'\ '·3'\ 'x'\ 'A'\ 'j'\ '^A'\ '' assert mathml(Divergence(3*x*ACS.x*ACS.j + ACS.i), printer='presentation') == \ '·'\ 'i^'\ 'A+'\ '3'\ 'xA'\ 'x'\ 'j'\ '^A' assert mathml(Dot(ACS.i, ACS.j*ACS.x*3+ACS.k), printer='presentation') == \ 'i^'\ 'A·'\ '3'\ 'xA'\ ''\ 'j^'\ 'A+'\ 'k^'\ 'A' assert mathml(Dot(ACS.i, ACS.j), printer='presentation') == \ 'i^'\ 'A·'\ 'j^'\ 'A' assert mathml(Dot(x*ACS.i, ACS.j), printer='presentation') == \ 'j^'\ 'A·'\ 'x'\ 'i^'\ 'A' assert mathml(x*Dot(ACS.i, ACS.j), printer='presentation') == \ 'x'\ 'i^'\ 'A·'\ 'j^'\ 'A' assert mathml(Gradient(ACS.x), printer='presentation') == \ 'x'\ 'A' assert mathml(Gradient(ACS.x + 3*ACS.y), printer='presentation') == \ ''\ 'xA+3'\ 'y'\ 'A' assert mathml(x*Gradient(ACS.x), printer='presentation') == \ 'x'\ 'xA'\ '' assert mathml(Gradient(x*ACS.x), printer='presentation') == \ ''\ 'xA'\ 'x' assert mathml(Cross(ACS.x, ACS.z) + Cross(ACS.z, ACS.x), printer='presentation') == \ '0^' assert mathml(Cross(ACS.z, ACS.x), printer='presentation') == \ '-x'\ 'A×'\ 'zA' assert mathml(Laplacian(ACS.x), printer='presentation') == \ 'x'\ 'A' assert mathml(Laplacian(ACS.x + 3*ACS.y), printer='presentation') == \ ''\ 'xA+3'\ 'y'\ 'A' assert mathml(x*Laplacian(ACS.x), printer='presentation') == \ 'x'\ 'xA'\ '' assert mathml(Laplacian(x*ACS.x), printer='presentation') == \ ''\ 'xA'\ 'x' def test_print_elliptic_f(): assert mathml(elliptic_f(x, y), printer = 'presentation') == \ '𝖥xy' assert mathml(elliptic_f(x/y, y), printer = 'presentation') == \ '𝖥xyy' def test_print_elliptic_e(): assert mathml(elliptic_e(x), printer = 'presentation') == \ '𝖤x' assert mathml(elliptic_e(x, y), printer = 'presentation') == \ '𝖤xy' def test_print_elliptic_pi(): assert mathml(elliptic_pi(x, y), printer = 'presentation') == \ '𝛱xy' assert mathml(elliptic_pi(x, y, z), printer = 'presentation') == \ '𝛱xyz' def test_print_Ei(): assert mathml(Ei(x), printer = 'presentation') == \ 'Eix' assert mathml(Ei(x**y), printer = 'presentation') == \ 'Eixy' def test_print_expint(): assert mathml(expint(x, y), printer = 'presentation') == \ 'Exy' assert mathml(expint(IndexedBase(x)[1], IndexedBase(x)[2]), printer = 'presentation') == \ 'Ex1x2' def test_print_jacobi(): assert mathml(jacobi(n, a, b, x), printer = 'presentation') == \ 'Pnabx' def test_print_gegenbauer(): assert mathml(gegenbauer(n, a, x), printer = 'presentation') == \ 'Cnax' def test_print_chebyshevt(): assert mathml(chebyshevt(n, x), printer = 'presentation') == \ 'Tnx' def test_print_chebyshevu(): assert mathml(chebyshevu(n, x), printer = 'presentation') == \ 'Unx' def test_print_legendre(): assert mathml(legendre(n, x), printer = 'presentation') == \ 'Pnx' def test_print_assoc_legendre(): assert mathml(assoc_legendre(n, a, x), printer = 'presentation') == \ 'Pnax' def test_print_laguerre(): assert mathml(laguerre(n, x), printer = 'presentation') == \ 'Lnx' def test_print_assoc_laguerre(): assert mathml(assoc_laguerre(n, a, x), printer = 'presentation') == \ 'Lnax' def test_print_hermite(): assert mathml(hermite(n, x), printer = 'presentation') == \ 'Hnx' def test_mathml_SingularityFunction(): assert mathml(SingularityFunction(x, 4, 5), printer='presentation') == \ 'x' \ '-45' assert mathml(SingularityFunction(x, -3, 4), printer='presentation') == \ 'x' \ '+34' assert mathml(SingularityFunction(x, 0, 4), printer='presentation') == \ 'x' \ '4' assert mathml(SingularityFunction(x, a, n), printer='presentation') == \ '' \ '-a+x' \ 'n' assert mathml(SingularityFunction(x, 4, -2), printer='presentation') == \ 'x' \ '-4-2' assert mathml(SingularityFunction(x, 4, -1), printer='presentation') == \ 'x' \ '-4-1' def test_mathml_matrix_functions(): from sympy.matrices import MatrixSymbol, Adjoint, Inverse, Transpose X = MatrixSymbol('X', 2, 2) Y = MatrixSymbol('Y', 2, 2) assert mathml(Adjoint(X), printer='presentation') == \ 'X' assert mathml(Adjoint(X + Y), printer='presentation') == \ 'X+Y' assert mathml(Adjoint(X) + Adjoint(Y), printer='presentation') == \ 'X+' \ 'Y' assert mathml(Adjoint(X*Y), printer='presentation') == \ 'X' \ 'Y' assert mathml(Adjoint(Y)*Adjoint(X), printer='presentation') == \ 'Y⁢' \ 'X' assert mathml(Adjoint(X**2), printer='presentation') == \ 'X2' assert mathml(Adjoint(X)**2, printer='presentation') == \ 'X2' assert mathml(Adjoint(Inverse(X)), printer='presentation') == \ 'X-1' assert mathml(Inverse(Adjoint(X)), printer='presentation') == \ 'X-1' assert mathml(Adjoint(Transpose(X)), printer='presentation') == \ 'XT' assert mathml(Transpose(Adjoint(X)), printer='presentation') == \ 'XT' assert mathml(Transpose(Adjoint(X) + Y), printer='presentation') == \ 'X' \ '+YT' assert mathml(Transpose(X), printer='presentation') == \ 'XT' assert mathml(Transpose(X + Y), printer='presentation') == \ 'X+YT' def test_mathml_special_matrices(): from sympy.matrices import Identity, ZeroMatrix, OneMatrix assert mathml(Identity(4), printer='presentation') == '𝕀' assert mathml(ZeroMatrix(2, 2), printer='presentation') == '𝟘' assert mathml(OneMatrix(2, 2), printer='presentation') == '𝟙' def test_mathml_piecewise(): from sympy import Piecewise # Content MathML assert mathml(Piecewise((x, x <= 1), (x**2, True))) == \ 'xx1x2' raises(ValueError, lambda: mathml(Piecewise((x, x <= 1)))) def test_issue_17857(): assert mathml(Range(-oo, oo), printer='presentation') == \ '-101' assert mathml(Range(oo, -oo, -1), printer='presentation') == \ '10-1' def test_float_roundtrip(): x = sympify(0.8975979010256552) y = float(mp.doprint(x).strip('')) assert x == y sympy-sympy-1.9/sympy/printing/tests/test_numpy.py000066400000000000000000000224011412543434000226600ustar00rootroot00000000000000from sympy import ( Piecewise, lambdify, Equality, Unequality, Sum, Mod, sqrt, MatrixSymbol, BlockMatrix, Identity ) from sympy import eye from sympy.abc import x, i, j, a, b, c, d from sympy.core import Pow from sympy.codegen.matrix_nodes import MatrixSolve from sympy.codegen.numpy_nodes import logaddexp, logaddexp2 from sympy.codegen.cfunctions import log1p, expm1, hypot, log10, exp2, log2, Sqrt from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayAdd, \ PermuteDims, ArrayDiagonal from sympy.printing.numpy import NumPyPrinter, SciPyPrinter, _numpy_known_constants, \ _numpy_known_functions, _scipy_known_constants, _scipy_known_functions from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array from sympy.testing.pytest import warns_deprecated_sympy from sympy.testing.pytest import skip, raises from sympy.external import import_module np = import_module('numpy') def test_numpy_piecewise_regression(): """ NumPyPrinter needs to print Piecewise()'s choicelist as a list to avoid breaking compatibility with numpy 1.8. This is not necessary in numpy 1.9+. See gh-9747 and gh-9749 for details. """ printer = NumPyPrinter() p = Piecewise((1, x < 0), (0, True)) assert printer.doprint(p) == \ 'numpy.select([numpy.less(x, 0),True], [1,0], default=numpy.nan)' assert printer.module_imports == {'numpy': {'select', 'less', 'nan'}} def test_numpy_logaddexp(): lae = logaddexp(a, b) assert NumPyPrinter().doprint(lae) == 'numpy.logaddexp(a, b)' lae2 = logaddexp2(a, b) assert NumPyPrinter().doprint(lae2) == 'numpy.logaddexp2(a, b)' def test_sum(): if not np: skip("NumPy not installed") s = Sum(x ** i, (i, a, b)) f = lambdify((a, b, x), s, 'numpy') a_, b_ = 0, 10 x_ = np.linspace(-1, +1, 10) assert np.allclose(f(a_, b_, x_), sum(x_ ** i_ for i_ in range(a_, b_ + 1))) s = Sum(i * x, (i, a, b)) f = lambdify((a, b, x), s, 'numpy') a_, b_ = 0, 10 x_ = np.linspace(-1, +1, 10) assert np.allclose(f(a_, b_, x_), sum(i_ * x_ for i_ in range(a_, b_ + 1))) def test_multiple_sums(): if not np: skip("NumPy not installed") s = Sum((x + j) * i, (i, a, b), (j, c, d)) f = lambdify((a, b, c, d, x), s, 'numpy') a_, b_ = 0, 10 c_, d_ = 11, 21 x_ = np.linspace(-1, +1, 10) assert np.allclose(f(a_, b_, c_, d_, x_), sum((x_ + j_) * i_ for i_ in range(a_, b_ + 1) for j_ in range(c_, d_ + 1))) def test_codegen_einsum(): if not np: skip("NumPy not installed") M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) cg = convert_matrix_to_array(M * N) f = lambdify((M, N), cg, 'numpy') ma = np.matrix([[1, 2], [3, 4]]) mb = np.matrix([[1,-2], [-1, 3]]) assert (f(ma, mb) == ma*mb).all() def test_codegen_extra(): if not np: skip("NumPy not installed") M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) P = MatrixSymbol("P", 2, 2) Q = MatrixSymbol("Q", 2, 2) ma = np.matrix([[1, 2], [3, 4]]) mb = np.matrix([[1,-2], [-1, 3]]) mc = np.matrix([[2, 0], [1, 2]]) md = np.matrix([[1,-1], [4, 7]]) cg = ArrayTensorProduct(M, N) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == np.einsum(ma, [0, 1], mb, [2, 3])).all() cg = ArrayAdd(M, N) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == ma+mb).all() cg = ArrayAdd(M, N, P) f = lambdify((M, N, P), cg, 'numpy') assert (f(ma, mb, mc) == ma+mb+mc).all() cg = ArrayAdd(M, N, P, Q) f = lambdify((M, N, P, Q), cg, 'numpy') assert (f(ma, mb, mc, md) == ma+mb+mc+md).all() cg = PermuteDims(M, [1, 0]) f = lambdify((M,), cg, 'numpy') assert (f(ma) == ma.T).all() cg = PermuteDims(ArrayTensorProduct(M, N), [1, 2, 3, 0]) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == np.transpose(np.einsum(ma, [0, 1], mb, [2, 3]), (1, 2, 3, 0))).all() cg = ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2)) f = lambdify((M, N), cg, 'numpy') assert (f(ma, mb) == np.diagonal(np.einsum(ma, [0, 1], mb, [2, 3]), axis1=1, axis2=2)).all() def test_relational(): if not np: skip("NumPy not installed") e = Equality(x, 1) f = lambdify((x,), e) x_ = np.array([0, 1, 2]) assert np.array_equal(f(x_), [False, True, False]) e = Unequality(x, 1) f = lambdify((x,), e) x_ = np.array([0, 1, 2]) assert np.array_equal(f(x_), [True, False, True]) e = (x < 1) f = lambdify((x,), e) x_ = np.array([0, 1, 2]) assert np.array_equal(f(x_), [True, False, False]) e = (x <= 1) f = lambdify((x,), e) x_ = np.array([0, 1, 2]) assert np.array_equal(f(x_), [True, True, False]) e = (x > 1) f = lambdify((x,), e) x_ = np.array([0, 1, 2]) assert np.array_equal(f(x_), [False, False, True]) e = (x >= 1) f = lambdify((x,), e) x_ = np.array([0, 1, 2]) assert np.array_equal(f(x_), [False, True, True]) def test_mod(): if not np: skip("NumPy not installed") e = Mod(a, b) f = lambdify((a, b), e) a_ = np.array([0, 1, 2, 3]) b_ = 2 assert np.array_equal(f(a_, b_), [0, 1, 0, 1]) a_ = np.array([0, 1, 2, 3]) b_ = np.array([2, 2, 2, 2]) assert np.array_equal(f(a_, b_), [0, 1, 0, 1]) a_ = np.array([2, 3, 4, 5]) b_ = np.array([2, 3, 4, 5]) assert np.array_equal(f(a_, b_), [0, 0, 0, 0]) def test_pow(): if not np: skip('NumPy not installed') expr = Pow(2, -1, evaluate=False) f = lambdify([], expr, 'numpy') assert f() == 0.5 def test_expm1(): if not np: skip("NumPy not installed") f = lambdify((a,), expm1(a), 'numpy') assert abs(f(1e-10) - 1e-10 - 5e-21) < 1e-22 def test_log1p(): if not np: skip("NumPy not installed") f = lambdify((a,), log1p(a), 'numpy') assert abs(f(1e-99) - 1e-99) < 1e-100 def test_hypot(): if not np: skip("NumPy not installed") assert abs(lambdify((a, b), hypot(a, b), 'numpy')(3, 4) - 5) < 1e-16 def test_log10(): if not np: skip("NumPy not installed") assert abs(lambdify((a,), log10(a), 'numpy')(100) - 2) < 1e-16 def test_exp2(): if not np: skip("NumPy not installed") assert abs(lambdify((a,), exp2(a), 'numpy')(5) - 32) < 1e-16 def test_log2(): if not np: skip("NumPy not installed") assert abs(lambdify((a,), log2(a), 'numpy')(256) - 8) < 1e-16 def test_Sqrt(): if not np: skip("NumPy not installed") assert abs(lambdify((a,), Sqrt(a), 'numpy')(4) - 2) < 1e-16 def test_sqrt(): if not np: skip("NumPy not installed") assert abs(lambdify((a,), sqrt(a), 'numpy')(4) - 2) < 1e-16 def test_matsolve(): if not np: skip("NumPy not installed") M = MatrixSymbol("M", 3, 3) x = MatrixSymbol("x", 3, 1) expr = M**(-1) * x + x matsolve_expr = MatrixSolve(M, x) + x f = lambdify((M, x), expr) f_matsolve = lambdify((M, x), matsolve_expr) m0 = np.array([[1, 2, 3], [3, 2, 5], [5, 6, 7]]) assert np.linalg.matrix_rank(m0) == 3 x0 = np.array([3, 4, 5]) assert np.allclose(f_matsolve(m0, x0), f(m0, x0)) def test_issue_15601(): if not np: skip("Numpy not installed") M = MatrixSymbol("M", 3, 3) N = MatrixSymbol("N", 3, 3) expr = M*N f = lambdify((M, N), expr, "numpy") with warns_deprecated_sympy(): ans = f(eye(3), eye(3)) assert np.array_equal(ans, np.array([1, 0, 0, 0, 1, 0, 0, 0, 1])) def test_16857(): if not np: skip("NumPy not installed") a_1 = MatrixSymbol('a_1', 10, 3) a_2 = MatrixSymbol('a_2', 10, 3) a_3 = MatrixSymbol('a_3', 10, 3) a_4 = MatrixSymbol('a_4', 10, 3) A = BlockMatrix([[a_1, a_2], [a_3, a_4]]) assert A.shape == (20, 6) printer = NumPyPrinter() assert printer.doprint(A) == 'numpy.block([[a_1, a_2], [a_3, a_4]])' def test_issue_17006(): if not np: skip("NumPy not installed") M = MatrixSymbol("M", 2, 2) f = lambdify(M, M + Identity(2)) ma = np.array([[1, 2], [3, 4]]) mr = np.array([[2, 2], [3, 5]]) assert (f(ma) == mr).all() from sympy import symbols n = symbols('n', integer=True) N = MatrixSymbol("M", n, n) raises(NotImplementedError, lambda: lambdify(N, N + Identity(n))) def test_numpy_known_funcs_consts(): assert _numpy_known_constants['NaN'] == 'numpy.nan' assert _numpy_known_constants['EulerGamma'] == 'numpy.euler_gamma' assert _numpy_known_functions['acos'] == 'numpy.arccos' assert _numpy_known_functions['log'] == 'numpy.log' def test_scipy_known_funcs_consts(): assert _scipy_known_constants['GoldenRatio'] == 'scipy.constants.golden_ratio' assert _scipy_known_constants['Pi'] == 'scipy.constants.pi' assert _scipy_known_functions['erf'] == 'scipy.special.erf' assert _scipy_known_functions['factorial'] == 'scipy.special.factorial' def test_numpy_print_methods(): prntr = NumPyPrinter() assert hasattr(prntr, '_print_acos') assert hasattr(prntr, '_print_log') def test_scipy_print_methods(): prntr = SciPyPrinter() assert hasattr(prntr, '_print_acos') assert hasattr(prntr, '_print_log') assert hasattr(prntr, '_print_erf') assert hasattr(prntr, '_print_factorial') assert hasattr(prntr, '_print_chebyshevt') sympy-sympy-1.9/sympy/printing/tests/test_octave.py000066400000000000000000000436751412543434000230110ustar00rootroot00000000000000from sympy.core import (S, pi, oo, symbols, Function, Rational, Integer, Tuple, Symbol, EulerGamma, GoldenRatio, Catalan, Lambda, Mul, Pow, Mod, Eq, Ne, Le, Lt, Gt, Ge) from sympy.codegen.matrix_nodes import MatrixSolve from sympy.functions import (arg, atan2, bernoulli, beta, ceiling, chebyshevu, chebyshevt, conjugate, DiracDelta, exp, expint, factorial, floor, harmonic, Heaviside, im, laguerre, LambertW, log, Max, Min, Piecewise, polylog, re, RisingFactorial, sign, sinc, sqrt, zeta, binomial, legendre) from sympy.functions import (sin, cos, tan, cot, sec, csc, asin, acos, acot, atan, asec, acsc, sinh, cosh, tanh, coth, csch, sech, asinh, acosh, atanh, acoth, asech, acsch) from sympy.testing.pytest import raises, XFAIL from sympy.utilities.lambdify import implemented_function from sympy.matrices import (eye, Matrix, MatrixSymbol, Identity, HadamardProduct, SparseMatrix, HadamardPower) from sympy.functions.special.bessel import (jn, yn, besselj, bessely, besseli, besselk, hankel1, hankel2, airyai, airybi, airyaiprime, airybiprime) from sympy.functions.special.gamma_functions import (gamma, lowergamma, uppergamma, loggamma, polygamma) from sympy.functions.special.error_functions import (Chi, Ci, erf, erfc, erfi, erfcinv, erfinv, fresnelc, fresnels, li, Shi, Si, Li, erf2) from sympy import octave_code from sympy import octave_code as mcode x, y, z = symbols('x,y,z') def test_Integer(): assert mcode(Integer(67)) == "67" assert mcode(Integer(-1)) == "-1" def test_Rational(): assert mcode(Rational(3, 7)) == "3/7" assert mcode(Rational(18, 9)) == "2" assert mcode(Rational(3, -7)) == "-3/7" assert mcode(Rational(-3, -7)) == "3/7" assert mcode(x + Rational(3, 7)) == "x + 3/7" assert mcode(Rational(3, 7)*x) == "3*x/7" def test_Relational(): assert mcode(Eq(x, y)) == "x == y" assert mcode(Ne(x, y)) == "x != y" assert mcode(Le(x, y)) == "x <= y" assert mcode(Lt(x, y)) == "x < y" assert mcode(Gt(x, y)) == "x > y" assert mcode(Ge(x, y)) == "x >= y" def test_Function(): assert mcode(sin(x) ** cos(x)) == "sin(x).^cos(x)" assert mcode(sign(x)) == "sign(x)" assert mcode(exp(x)) == "exp(x)" assert mcode(log(x)) == "log(x)" assert mcode(factorial(x)) == "factorial(x)" assert mcode(floor(x)) == "floor(x)" assert mcode(atan2(y, x)) == "atan2(y, x)" assert mcode(beta(x, y)) == 'beta(x, y)' assert mcode(polylog(x, y)) == 'polylog(x, y)' assert mcode(harmonic(x)) == 'harmonic(x)' assert mcode(bernoulli(x)) == "bernoulli(x)" assert mcode(bernoulli(x, y)) == "bernoulli(x, y)" assert mcode(legendre(x, y)) == "legendre(x, y)" def test_Function_change_name(): assert mcode(abs(x)) == "abs(x)" assert mcode(ceiling(x)) == "ceil(x)" assert mcode(arg(x)) == "angle(x)" assert mcode(im(x)) == "imag(x)" assert mcode(re(x)) == "real(x)" assert mcode(conjugate(x)) == "conj(x)" assert mcode(chebyshevt(y, x)) == "chebyshevT(y, x)" assert mcode(chebyshevu(y, x)) == "chebyshevU(y, x)" assert mcode(laguerre(x, y)) == "laguerreL(x, y)" assert mcode(Chi(x)) == "coshint(x)" assert mcode(Shi(x)) == "sinhint(x)" assert mcode(Ci(x)) == "cosint(x)" assert mcode(Si(x)) == "sinint(x)" assert mcode(li(x)) == "logint(x)" assert mcode(loggamma(x)) == "gammaln(x)" assert mcode(polygamma(x, y)) == "psi(x, y)" assert mcode(RisingFactorial(x, y)) == "pochhammer(x, y)" assert mcode(DiracDelta(x)) == "dirac(x)" assert mcode(DiracDelta(x, 3)) == "dirac(3, x)" assert mcode(Heaviside(x)) == "heaviside(x, 1/2)" assert mcode(Heaviside(x, y)) == "heaviside(x, y)" assert mcode(binomial(x, y)) == "bincoeff(x, y)" assert mcode(Mod(x, y)) == "mod(x, y)" def test_minmax(): assert mcode(Max(x, y) + Min(x, y)) == "max(x, y) + min(x, y)" assert mcode(Max(x, y, z)) == "max(x, max(y, z))" assert mcode(Min(x, y, z)) == "min(x, min(y, z))" def test_Pow(): assert mcode(x**3) == "x.^3" assert mcode(x**(y**3)) == "x.^(y.^3)" assert mcode(x**Rational(2, 3)) == 'x.^(2/3)' g = implemented_function('g', Lambda(x, 2*x)) assert mcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "(3.5*2*x).^(-x + y.^x)./(x.^2 + y)" # For issue 14160 assert mcode(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False), evaluate=False)) == '-2*x./(y.*y)' def test_basic_ops(): assert mcode(x*y) == "x.*y" assert mcode(x + y) == "x + y" assert mcode(x - y) == "x - y" assert mcode(-x) == "-x" def test_1_over_x_and_sqrt(): # 1.0 and 0.5 would do something different in regular StrPrinter, # but these are exact in IEEE floating point so no different here. assert mcode(1/x) == '1./x' assert mcode(x**-1) == mcode(x**-1.0) == '1./x' assert mcode(1/sqrt(x)) == '1./sqrt(x)' assert mcode(x**-S.Half) == mcode(x**-0.5) == '1./sqrt(x)' assert mcode(sqrt(x)) == 'sqrt(x)' assert mcode(x**S.Half) == mcode(x**0.5) == 'sqrt(x)' assert mcode(1/pi) == '1/pi' assert mcode(pi**-1) == mcode(pi**-1.0) == '1/pi' assert mcode(pi**-0.5) == '1/sqrt(pi)' def test_mix_number_mult_symbols(): assert mcode(3*x) == "3*x" assert mcode(pi*x) == "pi*x" assert mcode(3/x) == "3./x" assert mcode(pi/x) == "pi./x" assert mcode(x/3) == "x/3" assert mcode(x/pi) == "x/pi" assert mcode(x*y) == "x.*y" assert mcode(3*x*y) == "3*x.*y" assert mcode(3*pi*x*y) == "3*pi*x.*y" assert mcode(x/y) == "x./y" assert mcode(3*x/y) == "3*x./y" assert mcode(x*y/z) == "x.*y./z" assert mcode(x/y*z) == "x.*z./y" assert mcode(1/x/y) == "1./(x.*y)" assert mcode(2*pi*x/y/z) == "2*pi*x./(y.*z)" assert mcode(3*pi/x) == "3*pi./x" assert mcode(S(3)/5) == "3/5" assert mcode(S(3)/5*x) == "3*x/5" assert mcode(x/y/z) == "x./(y.*z)" assert mcode((x+y)/z) == "(x + y)./z" assert mcode((x+y)/(z+x)) == "(x + y)./(x + z)" assert mcode((x+y)/EulerGamma) == "(x + y)/%s" % EulerGamma.evalf(17) assert mcode(x/3/pi) == "x/(3*pi)" assert mcode(S(3)/5*x*y/pi) == "3*x.*y/(5*pi)" def test_mix_number_pow_symbols(): assert mcode(pi**3) == 'pi^3' assert mcode(x**2) == 'x.^2' assert mcode(x**(pi**3)) == 'x.^(pi^3)' assert mcode(x**y) == 'x.^y' assert mcode(x**(y**z)) == 'x.^(y.^z)' assert mcode((x**y)**z) == '(x.^y).^z' def test_imag(): I = S('I') assert mcode(I) == "1i" assert mcode(5*I) == "5i" assert mcode((S(3)/2)*I) == "3*1i/2" assert mcode(3+4*I) == "3 + 4i" assert mcode(sqrt(3)*I) == "sqrt(3)*1i" def test_constants(): assert mcode(pi) == "pi" assert mcode(oo) == "inf" assert mcode(-oo) == "-inf" assert mcode(S.NegativeInfinity) == "-inf" assert mcode(S.NaN) == "NaN" assert mcode(S.Exp1) == "exp(1)" assert mcode(exp(1)) == "exp(1)" def test_constants_other(): assert mcode(2*GoldenRatio) == "2*(1+sqrt(5))/2" assert mcode(2*Catalan) == "2*%s" % Catalan.evalf(17) assert mcode(2*EulerGamma) == "2*%s" % EulerGamma.evalf(17) def test_boolean(): assert mcode(x & y) == "x & y" assert mcode(x | y) == "x | y" assert mcode(~x) == "~x" assert mcode(x & y & z) == "x & y & z" assert mcode(x | y | z) == "x | y | z" assert mcode((x & y) | z) == "z | x & y" assert mcode((x | y) & z) == "z & (x | y)" def test_KroneckerDelta(): from sympy.functions import KroneckerDelta assert mcode(KroneckerDelta(x, y)) == "double(x == y)" assert mcode(KroneckerDelta(x, y + 1)) == "double(x == (y + 1))" assert mcode(KroneckerDelta(2**x, y)) == "double((2.^x) == y)" def test_Matrices(): assert mcode(Matrix(1, 1, [10])) == "10" A = Matrix([[1, sin(x/2), abs(x)], [0, 1, pi], [0, exp(1), ceiling(x)]]); expected = "[1 sin(x/2) abs(x); 0 1 pi; 0 exp(1) ceil(x)]" assert mcode(A) == expected # row and columns assert mcode(A[:,0]) == "[1; 0; 0]" assert mcode(A[0,:]) == "[1 sin(x/2) abs(x)]" # empty matrices assert mcode(Matrix(0, 0, [])) == '[]' assert mcode(Matrix(0, 3, [])) == 'zeros(0, 3)' # annoying to read but correct assert mcode(Matrix([[x, x - y, -y]])) == "[x x - y -y]" def test_vector_entries_hadamard(): # For a row or column, user might to use the other dimension A = Matrix([[1, sin(2/x), 3*pi/x/5]]) assert mcode(A) == "[1 sin(2./x) 3*pi./(5*x)]" assert mcode(A.T) == "[1; sin(2./x); 3*pi./(5*x)]" @XFAIL def test_Matrices_entries_not_hadamard(): # For Matrix with col >= 2, row >= 2, they need to be scalars # FIXME: is it worth worrying about this? Its not wrong, just # leave it user's responsibility to put scalar data for x. A = Matrix([[1, sin(2/x), 3*pi/x/5], [1, 2, x*y]]) expected = ("[1 sin(2/x) 3*pi/(5*x);\n" "1 2 x*y]") # <- we give x.*y assert mcode(A) == expected def test_MatrixSymbol(): n = Symbol('n', integer=True) A = MatrixSymbol('A', n, n) B = MatrixSymbol('B', n, n) assert mcode(A*B) == "A*B" assert mcode(B*A) == "B*A" assert mcode(2*A*B) == "2*A*B" assert mcode(B*2*A) == "2*B*A" assert mcode(A*(B + 3*Identity(n))) == "A*(3*eye(n) + B)" assert mcode(A**(x**2)) == "A^(x.^2)" assert mcode(A**3) == "A^3" assert mcode(A**S.Half) == "A^(1/2)" def test_MatrixSolve(): n = Symbol('n', integer=True) A = MatrixSymbol('A', n, n) x = MatrixSymbol('x', n, 1) assert mcode(MatrixSolve(A, x)) == "A \\ x" def test_special_matrices(): assert mcode(6*Identity(3)) == "6*eye(3)" def test_containers(): assert mcode([1, 2, 3, [4, 5, [6, 7]], 8, [9, 10], 11]) == \ "{1, 2, 3, {4, 5, {6, 7}}, 8, {9, 10}, 11}" assert mcode((1, 2, (3, 4))) == "{1, 2, {3, 4}}" assert mcode([1]) == "{1}" assert mcode((1,)) == "{1}" assert mcode(Tuple(*[1, 2, 3])) == "{1, 2, 3}" assert mcode((1, x*y, (3, x**2))) == "{1, x.*y, {3, x.^2}}" # scalar, matrix, empty matrix and empty list assert mcode((1, eye(3), Matrix(0, 0, []), [])) == "{1, [1 0 0; 0 1 0; 0 0 1], [], {}}" def test_octave_noninline(): source = mcode((x+y)/Catalan, assign_to='me', inline=False) expected = ( "Catalan = %s;\n" "me = (x + y)/Catalan;" ) % Catalan.evalf(17) assert source == expected def test_octave_piecewise(): expr = Piecewise((x, x < 1), (x**2, True)) assert mcode(expr) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))" assert mcode(expr, assign_to="r") == ( "r = ((x < 1).*(x) + (~(x < 1)).*(x.^2));") assert mcode(expr, assign_to="r", inline=False) == ( "if (x < 1)\n" " r = x;\n" "else\n" " r = x.^2;\n" "end") expr = Piecewise((x**2, x < 1), (x**3, x < 2), (x**4, x < 3), (x**5, True)) expected = ("((x < 1).*(x.^2) + (~(x < 1)).*( ...\n" "(x < 2).*(x.^3) + (~(x < 2)).*( ...\n" "(x < 3).*(x.^4) + (~(x < 3)).*(x.^5))))") assert mcode(expr) == expected assert mcode(expr, assign_to="r") == "r = " + expected + ";" assert mcode(expr, assign_to="r", inline=False) == ( "if (x < 1)\n" " r = x.^2;\n" "elseif (x < 2)\n" " r = x.^3;\n" "elseif (x < 3)\n" " r = x.^4;\n" "else\n" " r = x.^5;\n" "end") # Check that Piecewise without a True (default) condition error expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0)) raises(ValueError, lambda: mcode(expr)) def test_octave_piecewise_times_const(): pw = Piecewise((x, x < 1), (x**2, True)) assert mcode(2*pw) == "2*((x < 1).*(x) + (~(x < 1)).*(x.^2))" assert mcode(pw/x) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))./x" assert mcode(pw/(x*y)) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))./(x.*y)" assert mcode(pw/3) == "((x < 1).*(x) + (~(x < 1)).*(x.^2))/3" def test_octave_matrix_assign_to(): A = Matrix([[1, 2, 3]]) assert mcode(A, assign_to='a') == "a = [1 2 3];" A = Matrix([[1, 2], [3, 4]]) assert mcode(A, assign_to='A') == "A = [1 2; 3 4];" def test_octave_matrix_assign_to_more(): # assigning to Symbol or MatrixSymbol requires lhs/rhs match A = Matrix([[1, 2, 3]]) B = MatrixSymbol('B', 1, 3) C = MatrixSymbol('C', 2, 3) assert mcode(A, assign_to=B) == "B = [1 2 3];" raises(ValueError, lambda: mcode(A, assign_to=x)) raises(ValueError, lambda: mcode(A, assign_to=C)) def test_octave_matrix_1x1(): A = Matrix([[3]]) B = MatrixSymbol('B', 1, 1) C = MatrixSymbol('C', 1, 2) assert mcode(A, assign_to=B) == "B = 3;" # FIXME? #assert mcode(A, assign_to=x) == "x = 3;" raises(ValueError, lambda: mcode(A, assign_to=C)) def test_octave_matrix_elements(): A = Matrix([[x, 2, x*y]]) assert mcode(A[0, 0]**2 + A[0, 1] + A[0, 2]) == "x.^2 + x.*y + 2" A = MatrixSymbol('AA', 1, 3) assert mcode(A) == "AA" assert mcode(A[0, 0]**2 + sin(A[0,1]) + A[0,2]) == \ "sin(AA(1, 2)) + AA(1, 1).^2 + AA(1, 3)" assert mcode(sum(A)) == "AA(1, 1) + AA(1, 2) + AA(1, 3)" def test_octave_boolean(): assert mcode(True) == "true" assert mcode(S.true) == "true" assert mcode(False) == "false" assert mcode(S.false) == "false" def test_octave_not_supported(): assert mcode(S.ComplexInfinity) == ( "% Not supported in Octave:\n" "% ComplexInfinity\n" "zoo" ) f = Function('f') assert mcode(f(x).diff(x)) == ( "% Not supported in Octave:\n" "% Derivative\n" "Derivative(f(x), x)" ) def test_octave_not_supported_not_on_whitelist(): from sympy import assoc_laguerre assert mcode(assoc_laguerre(x, y, z)) == ( "% Not supported in Octave:\n" "% assoc_laguerre\n" "assoc_laguerre(x, y, z)" ) def test_octave_expint(): assert mcode(expint(1, x)) == "expint(x)" assert mcode(expint(2, x)) == ( "% Not supported in Octave:\n" "% expint\n" "expint(2, x)" ) assert mcode(expint(y, x)) == ( "% Not supported in Octave:\n" "% expint\n" "expint(y, x)" ) def test_trick_indent_with_end_else_words(): # words starting with "end" or "else" do not confuse the indenter t1 = S('endless'); t2 = S('elsewhere'); pw = Piecewise((t1, x < 0), (t2, x <= 1), (1, True)) assert mcode(pw, inline=False) == ( "if (x < 0)\n" " endless\n" "elseif (x <= 1)\n" " elsewhere\n" "else\n" " 1\n" "end") def test_hadamard(): A = MatrixSymbol('A', 3, 3) B = MatrixSymbol('B', 3, 3) v = MatrixSymbol('v', 3, 1) h = MatrixSymbol('h', 1, 3) C = HadamardProduct(A, B) n = Symbol('n') assert mcode(C) == "A.*B" assert mcode(C*v) == "(A.*B)*v" assert mcode(h*C*v) == "h*(A.*B)*v" assert mcode(C*A) == "(A.*B)*A" # mixing Hadamard and scalar strange b/c we vectorize scalars assert mcode(C*x*y) == "(x.*y)*(A.*B)" # Testing HadamardPower: assert mcode(HadamardPower(A, n)) == "A.**n" assert mcode(HadamardPower(A, 1+n)) == "A.**(n + 1)" assert mcode(HadamardPower(A*B.T, 1+n)) == "(A*B.T).**(n + 1)" def test_sparse(): M = SparseMatrix(5, 6, {}) M[2, 2] = 10; M[1, 2] = 20; M[1, 3] = 22; M[0, 3] = 30; M[3, 0] = x*y; assert mcode(M) == ( "sparse([4 2 3 1 2], [1 3 3 4 4], [x.*y 20 10 30 22], 5, 6)" ) def test_sinc(): assert mcode(sinc(x)) == 'sinc(x/pi)' assert mcode(sinc(x + 3)) == 'sinc((x + 3)/pi)' assert mcode(sinc(pi*(x + 3))) == 'sinc(x + 3)' def test_trigfun(): for f in (sin, cos, tan, cot, sec, csc, asin, acos, acot, atan, asec, acsc, sinh, cosh, tanh, coth, csch, sech, asinh, acosh, atanh, acoth, asech, acsch): assert octave_code(f(x) == f.__name__ + '(x)') def test_specfun(): n = Symbol('n') for f in [besselj, bessely, besseli, besselk]: assert octave_code(f(n, x)) == f.__name__ + '(n, x)' for f in (erfc, erfi, erf, erfinv, erfcinv, fresnelc, fresnels, gamma): assert octave_code(f(x)) == f.__name__ + '(x)' assert octave_code(hankel1(n, x)) == 'besselh(n, 1, x)' assert octave_code(hankel2(n, x)) == 'besselh(n, 2, x)' assert octave_code(airyai(x)) == 'airy(0, x)' assert octave_code(airyaiprime(x)) == 'airy(1, x)' assert octave_code(airybi(x)) == 'airy(2, x)' assert octave_code(airybiprime(x)) == 'airy(3, x)' assert octave_code(uppergamma(n, x)) == '(gammainc(x, n, \'upper\').*gamma(n))' assert octave_code(lowergamma(n, x)) == '(gammainc(x, n).*gamma(n))' assert octave_code(z**lowergamma(n, x)) == 'z.^(gammainc(x, n).*gamma(n))' assert octave_code(jn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*besselj(n + 1/2, x)/2' assert octave_code(yn(n, x)) == 'sqrt(2)*sqrt(pi)*sqrt(1./x).*bessely(n + 1/2, x)/2' assert octave_code(LambertW(x)) == 'lambertw(x)' assert octave_code(LambertW(x, n)) == 'lambertw(n, x)' def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert mcode(A[0, 0]) == "A(1, 1)" assert mcode(3 * A[0, 0]) == "3*A(1, 1)" F = C[0, 0].subs(C, A - B) assert mcode(F) == "(A - B)(1, 1)" def test_zeta_printing_issue_14820(): assert octave_code(zeta(x)) == 'zeta(x)' assert octave_code(zeta(x, y)) == '% Not supported in Octave:\n% zeta\nzeta(x, y)' def test_automatic_rewrite(): assert octave_code(Li(x)) == 'logint(x) - logint(2)' assert octave_code(erf2(x, y)) == '-erf(x) + erf(y)' sympy-sympy-1.9/sympy/printing/tests/test_precedence.py000066400000000000000000000053431412543434000236130ustar00rootroot00000000000000from sympy.concrete.products import Product from sympy.concrete.summations import Sum from sympy.core.function import Derivative from sympy.core.numbers import Integer, Rational, Float, oo from sympy.core.relational import Rel from sympy.core.symbol import symbols from sympy.functions import sin from sympy.integrals.integrals import Integral from sympy.series.order import Order from sympy.printing.precedence import precedence, PRECEDENCE x, y = symbols("x,y") def test_Add(): assert precedence(x + y) == PRECEDENCE["Add"] assert precedence(x*y + 1) == PRECEDENCE["Add"] def test_Function(): assert precedence(sin(x)) == PRECEDENCE["Func"] def test_Derivative(): assert precedence(Derivative(x, y)) == PRECEDENCE["Atom"] def test_Integral(): assert precedence(Integral(x, y)) == PRECEDENCE["Atom"] def test_Mul(): assert precedence(x*y) == PRECEDENCE["Mul"] assert precedence(-x*y) == PRECEDENCE["Add"] def test_Number(): assert precedence(Integer(0)) == PRECEDENCE["Atom"] assert precedence(Integer(1)) == PRECEDENCE["Atom"] assert precedence(Integer(-1)) == PRECEDENCE["Add"] assert precedence(Integer(10)) == PRECEDENCE["Atom"] assert precedence(Rational(5, 2)) == PRECEDENCE["Mul"] assert precedence(Rational(-5, 2)) == PRECEDENCE["Add"] assert precedence(Float(5)) == PRECEDENCE["Atom"] assert precedence(Float(-5)) == PRECEDENCE["Add"] assert precedence(oo) == PRECEDENCE["Atom"] assert precedence(-oo) == PRECEDENCE["Add"] def test_Order(): assert precedence(Order(x)) == PRECEDENCE["Atom"] def test_Pow(): assert precedence(x**y) == PRECEDENCE["Pow"] assert precedence(-x**y) == PRECEDENCE["Add"] assert precedence(x**-y) == PRECEDENCE["Pow"] def test_Product(): assert precedence(Product(x, (x, y, y + 1))) == PRECEDENCE["Atom"] def test_Relational(): assert precedence(Rel(x + y, y, "<")) == PRECEDENCE["Relational"] def test_Sum(): assert precedence(Sum(x, (x, y, y + 1))) == PRECEDENCE["Atom"] def test_Symbol(): assert precedence(x) == PRECEDENCE["Atom"] def test_And_Or(): # precedence relations between logical operators, ... assert precedence(x & y) > precedence(x | y) assert precedence(~y) > precedence(x & y) # ... and with other operators (cfr. other programming languages) assert precedence(x + y) > precedence(x | y) assert precedence(x + y) > precedence(x & y) assert precedence(x*y) > precedence(x | y) assert precedence(x*y) > precedence(x & y) assert precedence(~y) > precedence(x*y) assert precedence(~y) > precedence(x - y) # double checks assert precedence(x & y) == PRECEDENCE["And"] assert precedence(x | y) == PRECEDENCE["Or"] assert precedence(~y) == PRECEDENCE["Not"] sympy-sympy-1.9/sympy/printing/tests/test_preview.py000066400000000000000000000015771412543434000232040ustar00rootroot00000000000000# -*- coding: utf-8 -*- from sympy import Symbol, Piecewise, Eq from sympy.printing.preview import preview from io import BytesIO def test_preview(): x = Symbol('x') obj = BytesIO() try: preview(x, output='png', viewer='BytesIO', outputbuffer=obj) except RuntimeError: pass # latex not installed on CI server def test_preview_unicode_symbol(): # issue 9107 a = Symbol('α') obj = BytesIO() try: preview(a, output='png', viewer='BytesIO', outputbuffer=obj) except RuntimeError: pass # latex not installed on CI server def test_preview_latex_construct_in_expr(): # see PR 9801 x = Symbol('x') pw = Piecewise((1, Eq(x, 0)), (0, True)) obj = BytesIO() try: preview(pw, output='png', viewer='BytesIO', outputbuffer=obj) except RuntimeError: pass # latex not installed on CI server sympy-sympy-1.9/sympy/printing/tests/test_pycode.py000066400000000000000000000315051412543434000230000ustar00rootroot00000000000000from sympy.codegen import Assignment from sympy.codegen.ast import none from sympy.codegen.cfunctions import expm1, log1p from sympy.codegen.scipy_nodes import cosm1 from sympy.codegen.matrix_nodes import MatrixSolve from sympy.core import Expr, Mod, symbols, Eq, Le, Gt, zoo, oo, Rational, Pow from sympy.core.numbers import pi from sympy.core.singleton import S from sympy.functions import acos, KroneckerDelta, Piecewise, sign, sqrt from sympy.logic import And, Or from sympy.matrices import SparseMatrix, MatrixSymbol, Identity from sympy.printing.pycode import ( MpmathPrinter, PythonCodePrinter, pycode, SymPyPrinter ) from sympy.printing.numpy import NumPyPrinter, SciPyPrinter from sympy.testing.pytest import raises from sympy.tensor import IndexedBase from sympy.testing.pytest import skip from sympy.external import import_module from sympy.functions.special.gamma_functions import loggamma x, y, z = symbols('x y z') p = IndexedBase("p") def test_PythonCodePrinter(): prntr = PythonCodePrinter() assert not prntr.module_imports assert prntr.doprint(x**y) == 'x**y' assert prntr.doprint(Mod(x, 2)) == 'x % 2' assert prntr.doprint(And(x, y)) == 'x and y' assert prntr.doprint(Or(x, y)) == 'x or y' assert not prntr.module_imports assert prntr.doprint(pi) == 'math.pi' assert prntr.module_imports == {'math': {'pi'}} assert prntr.doprint(x**Rational(1, 2)) == 'math.sqrt(x)' assert prntr.doprint(sqrt(x)) == 'math.sqrt(x)' assert prntr.module_imports == {'math': {'pi', 'sqrt'}} assert prntr.doprint(acos(x)) == 'math.acos(x)' assert prntr.doprint(Assignment(x, 2)) == 'x = 2' assert prntr.doprint(Piecewise((1, Eq(x, 0)), (2, x>6))) == '((1) if (x == 0) else (2) if (x > 6) else None)' assert prntr.doprint(Piecewise((2, Le(x, 0)), (3, Gt(x, 0)), evaluate=False)) == '((2) if (x <= 0) else'\ ' (3) if (x > 0) else None)' assert prntr.doprint(sign(x)) == '(0.0 if x == 0 else math.copysign(1, x))' assert prntr.doprint(p[0, 1]) == 'p[0, 1]' assert prntr.doprint(KroneckerDelta(x,y)) == '(1 if x == y else 0)' def test_PythonCodePrinter_standard(): import sys prntr = PythonCodePrinter({'standard':None}) python_version = sys.version_info.major if python_version == 2: assert prntr.standard == 'python2' if python_version == 3: assert prntr.standard == 'python3' raises(ValueError, lambda: PythonCodePrinter({'standard':'python4'})) def test_MpmathPrinter(): p = MpmathPrinter() assert p.doprint(sign(x)) == 'mpmath.sign(x)' assert p.doprint(Rational(1, 2)) == 'mpmath.mpf(1)/mpmath.mpf(2)' assert p.doprint(S.Exp1) == 'mpmath.e' assert p.doprint(S.Pi) == 'mpmath.pi' assert p.doprint(S.GoldenRatio) == 'mpmath.phi' assert p.doprint(S.EulerGamma) == 'mpmath.euler' assert p.doprint(S.NaN) == 'mpmath.nan' assert p.doprint(S.Infinity) == 'mpmath.inf' assert p.doprint(S.NegativeInfinity) == 'mpmath.ninf' assert p.doprint(loggamma(x)) == 'mpmath.loggamma(x)' def test_NumPyPrinter(): from sympy import (Lambda, ZeroMatrix, OneMatrix, FunctionMatrix, HadamardProduct, KroneckerProduct, Adjoint, DiagonalOf, DiagMatrix, DiagonalMatrix) from sympy.abc import a, b p = NumPyPrinter() assert p.doprint(sign(x)) == 'numpy.sign(x)' A = MatrixSymbol("A", 2, 2) B = MatrixSymbol("B", 2, 2) C = MatrixSymbol("C", 1, 5) D = MatrixSymbol("D", 3, 4) assert p.doprint(A**(-1)) == "numpy.linalg.inv(A)" assert p.doprint(A**5) == "numpy.linalg.matrix_power(A, 5)" assert p.doprint(Identity(3)) == "numpy.eye(3)" u = MatrixSymbol('x', 2, 1) v = MatrixSymbol('y', 2, 1) assert p.doprint(MatrixSolve(A, u)) == 'numpy.linalg.solve(A, x)' assert p.doprint(MatrixSolve(A, u) + v) == 'numpy.linalg.solve(A, x) + y' assert p.doprint(ZeroMatrix(2, 3)) == "numpy.zeros((2, 3))" assert p.doprint(OneMatrix(2, 3)) == "numpy.ones((2, 3))" assert p.doprint(FunctionMatrix(4, 5, Lambda((a, b), a + b))) == \ "numpy.fromfunction(lambda a, b: a + b, (4, 5))" assert p.doprint(HadamardProduct(A, B)) == "numpy.multiply(A, B)" assert p.doprint(KroneckerProduct(A, B)) == "numpy.kron(A, B)" assert p.doprint(Adjoint(A)) == "numpy.conjugate(numpy.transpose(A))" assert p.doprint(DiagonalOf(A)) == "numpy.reshape(numpy.diag(A), (-1, 1))" assert p.doprint(DiagMatrix(C)) == "numpy.diagflat(C)" assert p.doprint(DiagonalMatrix(D)) == "numpy.multiply(D, numpy.eye(3, 4))" # Workaround for numpy negative integer power errors assert p.doprint(x**-1) == 'x**(-1.0)' assert p.doprint(x**-2) == 'x**(-2.0)' expr = Pow(2, -1, evaluate=False) assert p.doprint(expr) == "2**(-1.0)" assert p.doprint(S.Exp1) == 'numpy.e' assert p.doprint(S.Pi) == 'numpy.pi' assert p.doprint(S.EulerGamma) == 'numpy.euler_gamma' assert p.doprint(S.NaN) == 'numpy.nan' assert p.doprint(S.Infinity) == 'numpy.PINF' assert p.doprint(S.NegativeInfinity) == 'numpy.NINF' def test_issue_18770(): numpy = import_module('numpy') if not numpy: skip("numpy not installed.") from sympy import lambdify, Min, Max expr1 = Min(0.1*x + 3, x + 1, 0.5*x + 1) func = lambdify(x, expr1, "numpy") assert (func(numpy.linspace(0, 3, 3)) == [1.0 , 1.75, 2.5 ]).all() assert func(4) == 3 expr1 = Max(x**2 , x**3) func = lambdify(x,expr1, "numpy") assert (func(numpy.linspace(-1 , 2, 4)) == [1, 0, 1, 8] ).all() assert func(4) == 64 def test_SciPyPrinter(): p = SciPyPrinter() expr = acos(x) assert 'numpy' not in p.module_imports assert p.doprint(expr) == 'numpy.arccos(x)' assert 'numpy' in p.module_imports assert not any(m.startswith('scipy') for m in p.module_imports) smat = SparseMatrix(2, 5, {(0, 1): 3}) assert p.doprint(smat) == \ 'scipy.sparse.coo_matrix(([3], ([0], [1])), shape=(2, 5))' assert 'scipy.sparse' in p.module_imports assert p.doprint(S.GoldenRatio) == 'scipy.constants.golden_ratio' assert p.doprint(S.Pi) == 'scipy.constants.pi' assert p.doprint(S.Exp1) == 'numpy.e' def test_pycode_reserved_words(): s1, s2 = symbols('if else') raises(ValueError, lambda: pycode(s1 + s2, error_on_reserved=True)) py_str = pycode(s1 + s2) assert py_str in ('else_ + if_', 'if_ + else_') def test_sqrt(): prntr = PythonCodePrinter() assert prntr._print_Pow(sqrt(x), rational=False) == 'math.sqrt(x)' assert prntr._print_Pow(1/sqrt(x), rational=False) == '1/math.sqrt(x)' prntr = PythonCodePrinter({'standard' : 'python2'}) assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1./2.)' assert prntr._print_Pow(1/sqrt(x), rational=True) == 'x**(-1./2.)' prntr = PythonCodePrinter({'standard' : 'python3'}) assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)' assert prntr._print_Pow(1/sqrt(x), rational=True) == 'x**(-1/2)' prntr = MpmathPrinter() assert prntr._print_Pow(sqrt(x), rational=False) == 'mpmath.sqrt(x)' assert prntr._print_Pow(sqrt(x), rational=True) == \ "x**(mpmath.mpf(1)/mpmath.mpf(2))" prntr = NumPyPrinter() assert prntr._print_Pow(sqrt(x), rational=False) == 'numpy.sqrt(x)' assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)' prntr = SciPyPrinter() assert prntr._print_Pow(sqrt(x), rational=False) == 'numpy.sqrt(x)' assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)' prntr = SymPyPrinter() assert prntr._print_Pow(sqrt(x), rational=False) == 'sympy.sqrt(x)' assert prntr._print_Pow(sqrt(x), rational=True) == 'x**(1/2)' def test_frac(): from sympy import frac expr = frac(x) prntr = NumPyPrinter() assert prntr.doprint(expr) == 'numpy.mod(x, 1)' prntr = SciPyPrinter() assert prntr.doprint(expr) == 'numpy.mod(x, 1)' prntr = PythonCodePrinter() assert prntr.doprint(expr) == 'x % 1' prntr = MpmathPrinter() assert prntr.doprint(expr) == 'mpmath.frac(x)' prntr = SymPyPrinter() assert prntr.doprint(expr) == 'sympy.functions.elementary.integers.frac(x)' class CustomPrintedObject(Expr): def _numpycode(self, printer): return 'numpy' def _mpmathcode(self, printer): return 'mpmath' def test_printmethod(): obj = CustomPrintedObject() assert NumPyPrinter().doprint(obj) == 'numpy' assert MpmathPrinter().doprint(obj) == 'mpmath' def test_codegen_ast_nodes(): assert pycode(none) == 'None' def test_issue_14283(): prntr = PythonCodePrinter() assert prntr.doprint(zoo) == "float('nan')" assert prntr.doprint(-oo) == "float('-inf')" def test_NumPyPrinter_print_seq(): n = NumPyPrinter() assert n._print_seq(range(2)) == '(0, 1,)' def test_issue_16535_16536(): from sympy import lowergamma, uppergamma a = symbols('a') expr1 = lowergamma(a, x) expr2 = uppergamma(a, x) prntr = SciPyPrinter() assert prntr.doprint(expr1) == 'scipy.special.gamma(a)*scipy.special.gammainc(a, x)' assert prntr.doprint(expr2) == 'scipy.special.gamma(a)*scipy.special.gammaincc(a, x)' prntr = NumPyPrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) prntr = PythonCodePrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) def test_Integral(): from sympy import Integral, exp single = Integral(exp(-x), (x, 0, oo)) double = Integral(x**2*exp(x*y), (x, -z, z), (y, 0, z)) indefinite = Integral(x**2, x) evaluateat = Integral(x**2, (x, 1)) prntr = SciPyPrinter() assert prntr.doprint(single) == 'scipy.integrate.quad(lambda x: numpy.exp(-x), 0, numpy.PINF)[0]' assert prntr.doprint(double) == 'scipy.integrate.nquad(lambda x, y: x**2*numpy.exp(x*y), ((-z, z), (0, z)))[0]' raises(NotImplementedError, lambda: prntr.doprint(indefinite)) raises(NotImplementedError, lambda: prntr.doprint(evaluateat)) prntr = MpmathPrinter() assert prntr.doprint(single) == 'mpmath.quad(lambda x: mpmath.exp(-x), (0, mpmath.inf))' assert prntr.doprint(double) == 'mpmath.quad(lambda x, y: x**2*mpmath.exp(x*y), (-z, z), (0, z))' raises(NotImplementedError, lambda: prntr.doprint(indefinite)) raises(NotImplementedError, lambda: prntr.doprint(evaluateat)) def test_fresnel_integrals(): from sympy import fresnelc, fresnels expr1 = fresnelc(x) expr2 = fresnels(x) prntr = SciPyPrinter() assert prntr.doprint(expr1) == 'scipy.special.fresnel(x)[1]' assert prntr.doprint(expr2) == 'scipy.special.fresnel(x)[0]' prntr = NumPyPrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) prntr = PythonCodePrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) prntr = MpmathPrinter() assert prntr.doprint(expr1) == 'mpmath.fresnelc(x)' assert prntr.doprint(expr2) == 'mpmath.fresnels(x)' def test_beta(): from sympy import beta expr = beta(x, y) prntr = SciPyPrinter() assert prntr.doprint(expr) == 'scipy.special.beta(x, y)' prntr = NumPyPrinter() assert prntr.doprint(expr) == 'math.gamma(x)*math.gamma(y)/math.gamma(x + y)' prntr = PythonCodePrinter() assert prntr.doprint(expr) == 'math.gamma(x)*math.gamma(y)/math.gamma(x + y)' prntr = PythonCodePrinter({'allow_unknown_functions': True}) assert prntr.doprint(expr) == 'math.gamma(x)*math.gamma(y)/math.gamma(x + y)' prntr = MpmathPrinter() assert prntr.doprint(expr) == 'mpmath.beta(x, y)' def test_airy(): from sympy import airyai, airybi expr1 = airyai(x) expr2 = airybi(x) prntr = SciPyPrinter() assert prntr.doprint(expr1) == 'scipy.special.airy(x)[0]' assert prntr.doprint(expr2) == 'scipy.special.airy(x)[2]' prntr = NumPyPrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) prntr = PythonCodePrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) def test_airy_prime(): from sympy import airyaiprime, airybiprime expr1 = airyaiprime(x) expr2 = airybiprime(x) prntr = SciPyPrinter() assert prntr.doprint(expr1) == 'scipy.special.airy(x)[1]' assert prntr.doprint(expr2) == 'scipy.special.airy(x)[3]' prntr = NumPyPrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) prntr = PythonCodePrinter() assert "Not supported" in prntr.doprint(expr1) assert "Not supported" in prntr.doprint(expr2) def test_numerical_accuracy_functions(): prntr = SciPyPrinter() assert prntr.doprint(expm1(x)) == 'numpy.expm1(x)' assert prntr.doprint(log1p(x)) == 'numpy.log1p(x)' assert prntr.doprint(cosm1(x)) == 'scipy.special.cosm1(x)' sympy-sympy-1.9/sympy/printing/tests/test_python.py000066400000000000000000000164701412543434000230420ustar00rootroot00000000000000from sympy import (Symbol, symbols, oo, limit, Rational, Integral, Derivative, log, exp, sqrt, pi, Function, sin, Eq, Ge, Le, Gt, Lt, Ne, Abs, conjugate, I, Matrix) from sympy.printing.python import python from sympy.testing.pytest import raises, XFAIL x, y = symbols('x,y') th = Symbol('theta') ph = Symbol('phi') def test_python_basic(): # Simple numbers/symbols assert python(-Rational(1)/2) == "e = Rational(-1, 2)" assert python(-Rational(13)/22) == "e = Rational(-13, 22)" assert python(oo) == "e = oo" # Powers assert python(x**2) == "x = Symbol(\'x\')\ne = x**2" assert python(1/x) == "x = Symbol('x')\ne = 1/x" assert python(y*x**-2) == "y = Symbol('y')\nx = Symbol('x')\ne = y/x**2" assert python( x**Rational(-5, 2)) == "x = Symbol('x')\ne = x**Rational(-5, 2)" # Sums of terms assert python(x**2 + x + 1) in [ "x = Symbol('x')\ne = 1 + x + x**2", "x = Symbol('x')\ne = x + x**2 + 1", "x = Symbol('x')\ne = x**2 + x + 1", ] assert python(1 - x) in [ "x = Symbol('x')\ne = 1 - x", "x = Symbol('x')\ne = -x + 1"] assert python(1 - 2*x) in [ "x = Symbol('x')\ne = 1 - 2*x", "x = Symbol('x')\ne = -2*x + 1"] assert python(1 - Rational(3, 2)*y/x) in [ "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3/2*y/x", "y = Symbol('y')\nx = Symbol('x')\ne = -3/2*y/x + 1", "y = Symbol('y')\nx = Symbol('x')\ne = 1 - 3*y/(2*x)"] # Multiplication assert python(x/y) == "x = Symbol('x')\ny = Symbol('y')\ne = x/y" assert python(-x/y) == "x = Symbol('x')\ny = Symbol('y')\ne = -x/y" assert python((x + 2)/y) in [ "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(2 + x)", "y = Symbol('y')\nx = Symbol('x')\ne = 1/y*(x + 2)", "x = Symbol('x')\ny = Symbol('y')\ne = 1/y*(2 + x)", "x = Symbol('x')\ny = Symbol('y')\ne = (2 + x)/y", "x = Symbol('x')\ny = Symbol('y')\ne = (x + 2)/y"] assert python((1 + x)*y) in [ "y = Symbol('y')\nx = Symbol('x')\ne = y*(1 + x)", "y = Symbol('y')\nx = Symbol('x')\ne = y*(x + 1)", ] # Check for proper placement of negative sign assert python(-5*x/(x + 10)) == "x = Symbol('x')\ne = -5*x/(x + 10)" assert python(1 - Rational(3, 2)*(x + 1)) in [ "x = Symbol('x')\ne = Rational(-3, 2)*x + Rational(-1, 2)", "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)", "x = Symbol('x')\ne = -3*x/2 + Rational(-1, 2)" ] def test_python_keyword_symbol_name_escaping(): # Check for escaping of keywords assert python( 5*Symbol("lambda")) == "lambda_ = Symbol('lambda')\ne = 5*lambda_" assert (python(5*Symbol("lambda") + 7*Symbol("lambda_")) == "lambda__ = Symbol('lambda')\nlambda_ = Symbol('lambda_')\ne = 7*lambda_ + 5*lambda__") assert (python(5*Symbol("for") + Function("for_")(8)) == "for__ = Symbol('for')\nfor_ = Function('for_')\ne = 5*for__ + for_(8)") def test_python_keyword_function_name_escaping(): assert python( 5*Function("for")(8)) == "for_ = Function('for')\ne = 5*for_(8)" def test_python_relational(): assert python(Eq(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = Eq(x, y)" assert python(Ge(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x >= y" assert python(Le(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x <= y" assert python(Gt(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x > y" assert python(Lt(x, y)) == "x = Symbol('x')\ny = Symbol('y')\ne = x < y" assert python(Ne(x/(y + 1), y**2)) in [ "x = Symbol('x')\ny = Symbol('y')\ne = Ne(x/(1 + y), y**2)", "x = Symbol('x')\ny = Symbol('y')\ne = Ne(x/(y + 1), y**2)"] def test_python_functions(): # Simple assert python(2*x + exp(x)) in "x = Symbol('x')\ne = 2*x + exp(x)" assert python(sqrt(2)) == 'e = sqrt(2)' assert python(2**Rational(1, 3)) == 'e = 2**Rational(1, 3)' assert python(sqrt(2 + pi)) == 'e = sqrt(2 + pi)' assert python((2 + pi)**Rational(1, 3)) == 'e = (2 + pi)**Rational(1, 3)' assert python(2**Rational(1, 4)) == 'e = 2**Rational(1, 4)' assert python(Abs(x)) == "x = Symbol('x')\ne = Abs(x)" assert python( Abs(x/(x**2 + 1))) in ["x = Symbol('x')\ne = Abs(x/(1 + x**2))", "x = Symbol('x')\ne = Abs(x/(x**2 + 1))"] # Univariate/Multivariate functions f = Function('f') assert python(f(x)) == "x = Symbol('x')\nf = Function('f')\ne = f(x)" assert python(f(x, y)) == "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x, y)" assert python(f(x/(y + 1), y)) in [ "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x/(1 + y), y)", "x = Symbol('x')\ny = Symbol('y')\nf = Function('f')\ne = f(x/(y + 1), y)"] # Nesting of square roots assert python(sqrt((sqrt(x + 1)) + 1)) in [ "x = Symbol('x')\ne = sqrt(1 + sqrt(1 + x))", "x = Symbol('x')\ne = sqrt(sqrt(x + 1) + 1)"] # Nesting of powers assert python((((x + 1)**Rational(1, 3)) + 1)**Rational(1, 3)) in [ "x = Symbol('x')\ne = (1 + (1 + x)**Rational(1, 3))**Rational(1, 3)", "x = Symbol('x')\ne = ((x + 1)**Rational(1, 3) + 1)**Rational(1, 3)"] # Function powers assert python(sin(x)**2) == "x = Symbol('x')\ne = sin(x)**2" @XFAIL def test_python_functions_conjugates(): a, b = map(Symbol, 'ab') assert python( conjugate(a + b*I) ) == '_ _\na - I*b' assert python( conjugate(exp(a + b*I)) ) == ' _ _\n a - I*b\ne ' def test_python_derivatives(): # Simple f_1 = Derivative(log(x), x, evaluate=False) assert python(f_1) == "x = Symbol('x')\ne = Derivative(log(x), x)" f_2 = Derivative(log(x), x, evaluate=False) + x assert python(f_2) == "x = Symbol('x')\ne = x + Derivative(log(x), x)" # Multiple symbols f_3 = Derivative(log(x) + x**2, x, y, evaluate=False) assert python(f_3) == \ "x = Symbol('x')\ny = Symbol('y')\ne = Derivative(x**2 + log(x), x, y)" f_4 = Derivative(2*x*y, y, x, evaluate=False) + x**2 assert python(f_4) in [ "x = Symbol('x')\ny = Symbol('y')\ne = x**2 + Derivative(2*x*y, y, x)", "x = Symbol('x')\ny = Symbol('y')\ne = Derivative(2*x*y, y, x) + x**2"] def test_python_integrals(): # Simple f_1 = Integral(log(x), x) assert python(f_1) == "x = Symbol('x')\ne = Integral(log(x), x)" f_2 = Integral(x**2, x) assert python(f_2) == "x = Symbol('x')\ne = Integral(x**2, x)" # Double nesting of pow f_3 = Integral(x**(2**x), x) assert python(f_3) == "x = Symbol('x')\ne = Integral(x**(2**x), x)" # Definite integrals f_4 = Integral(x**2, (x, 1, 2)) assert python(f_4) == "x = Symbol('x')\ne = Integral(x**2, (x, 1, 2))" f_5 = Integral(x**2, (x, Rational(1, 2), 10)) assert python( f_5) == "x = Symbol('x')\ne = Integral(x**2, (x, Rational(1, 2), 10))" # Nested integrals f_6 = Integral(x**2*y**2, x, y) assert python(f_6) == "x = Symbol('x')\ny = Symbol('y')\ne = Integral(x**2*y**2, x, y)" def test_python_matrix(): p = python(Matrix([[x**2+1, 1], [y, x+y]])) s = "x = Symbol('x')\ny = Symbol('y')\ne = MutableDenseMatrix([[x**2 + 1, 1], [y, x + y]])" assert p == s def test_python_limits(): assert python(limit(x, x, oo)) == 'e = oo' assert python(limit(x**2, x, 0)) == 'e = 0' def test_settings(): raises(TypeError, lambda: python(x, method="garbage")) sympy-sympy-1.9/sympy/printing/tests/test_rcode.py000066400000000000000000000334251412543434000226140ustar00rootroot00000000000000from sympy.core import (S, pi, oo, Symbol, symbols, Rational, Integer, GoldenRatio, EulerGamma, Catalan, Lambda, Dummy, Eq) from sympy.functions import (Piecewise, sin, cos, Abs, exp, ceiling, sqrt, gamma, sign, Max, Min, factorial, beta) from sympy.sets import Range from sympy.logic import ITE from sympy.codegen import For, aug_assign, Assignment from sympy.testing.pytest import raises from sympy.printing.rcode import RCodePrinter from sympy.utilities.lambdify import implemented_function from sympy.tensor import IndexedBase, Idx from sympy.matrices import Matrix, MatrixSymbol from sympy import rcode x, y, z = symbols('x,y,z') def test_printmethod(): class fabs(Abs): def _rcode(self, printer): return "abs(%s)" % printer._print(self.args[0]) assert rcode(fabs(x)) == "abs(x)" def test_rcode_sqrt(): assert rcode(sqrt(x)) == "sqrt(x)" assert rcode(x**0.5) == "sqrt(x)" assert rcode(sqrt(x)) == "sqrt(x)" def test_rcode_Pow(): assert rcode(x**3) == "x^3" assert rcode(x**(y**3)) == "x^(y^3)" g = implemented_function('g', Lambda(x, 2*x)) assert rcode(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "(3.5*2*x)^(-x + y^x)/(x^2 + y)" assert rcode(x**-1.0) == '1.0/x' assert rcode(x**Rational(2, 3)) == 'x^(2.0/3.0)' _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi"), (lambda base, exp: not exp.is_integer, "pow")] assert rcode(x**3, user_functions={'Pow': _cond_cfunc}) == 'dpowi(x, 3)' assert rcode(x**3.2, user_functions={'Pow': _cond_cfunc}) == 'pow(x, 3.2)' def test_rcode_Max(): # Test for gh-11926 assert rcode(Max(x,x*x),user_functions={"Max":"my_max", "Pow":"my_pow"}) == 'my_max(x, my_pow(x, 2))' def test_rcode_constants_mathh(): assert rcode(exp(1)) == "exp(1)" assert rcode(pi) == "pi" assert rcode(oo) == "Inf" assert rcode(-oo) == "-Inf" def test_rcode_constants_other(): assert rcode(2*GoldenRatio) == "GoldenRatio = 1.61803398874989;\n2*GoldenRatio" assert rcode( 2*Catalan) == "Catalan = 0.915965594177219;\n2*Catalan" assert rcode(2*EulerGamma) == "EulerGamma = 0.577215664901533;\n2*EulerGamma" def test_rcode_Rational(): assert rcode(Rational(3, 7)) == "3.0/7.0" assert rcode(Rational(18, 9)) == "2" assert rcode(Rational(3, -7)) == "-3.0/7.0" assert rcode(Rational(-3, -7)) == "3.0/7.0" assert rcode(x + Rational(3, 7)) == "x + 3.0/7.0" assert rcode(Rational(3, 7)*x) == "(3.0/7.0)*x" def test_rcode_Integer(): assert rcode(Integer(67)) == "67" assert rcode(Integer(-1)) == "-1" def test_rcode_functions(): assert rcode(sin(x) ** cos(x)) == "sin(x)^cos(x)" assert rcode(factorial(x) + gamma(y)) == "factorial(x) + gamma(y)" assert rcode(beta(Min(x, y), Max(x, y))) == "beta(min(x, y), max(x, y))" def test_rcode_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert rcode(g(x)) == "2*x" g = implemented_function('g', Lambda(x, 2*x/Catalan)) assert rcode( g(x)) == "Catalan = %s;\n2*x/Catalan" % Catalan.n() A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) res=rcode(g(A[i]), assign_to=A[i]) ref=( "for (i in 1:n){\n" " A[i] = (A[i] + 1)*(A[i] + 2)*A[i];\n" "}" ) assert res == ref def test_rcode_exceptions(): assert rcode(ceiling(x)) == "ceiling(x)" assert rcode(Abs(x)) == "abs(x)" assert rcode(gamma(x)) == "gamma(x)" def test_rcode_user_functions(): x = symbols('x', integer=False) n = symbols('n', integer=True) custom_functions = { "ceiling": "myceil", "Abs": [(lambda x: not x.is_integer, "fabs"), (lambda x: x.is_integer, "abs")], } assert rcode(ceiling(x), user_functions=custom_functions) == "myceil(x)" assert rcode(Abs(x), user_functions=custom_functions) == "fabs(x)" assert rcode(Abs(n), user_functions=custom_functions) == "abs(n)" def test_rcode_boolean(): assert rcode(True) == "True" assert rcode(S.true) == "True" assert rcode(False) == "False" assert rcode(S.false) == "False" assert rcode(x & y) == "x & y" assert rcode(x | y) == "x | y" assert rcode(~x) == "!x" assert rcode(x & y & z) == "x & y & z" assert rcode(x | y | z) == "x | y | z" assert rcode((x & y) | z) == "z | x & y" assert rcode((x | y) & z) == "z & (x | y)" def test_rcode_Relational(): from sympy import Eq, Ne, Le, Lt, Gt, Ge assert rcode(Eq(x, y)) == "x == y" assert rcode(Ne(x, y)) == "x != y" assert rcode(Le(x, y)) == "x <= y" assert rcode(Lt(x, y)) == "x < y" assert rcode(Gt(x, y)) == "x > y" assert rcode(Ge(x, y)) == "x >= y" def test_rcode_Piecewise(): expr = Piecewise((x, x < 1), (x**2, True)) res=rcode(expr) ref="ifelse(x < 1,x,x^2)" assert res == ref tau=Symbol("tau") res=rcode(expr,tau) ref="tau = ifelse(x < 1,x,x^2);" assert res == ref expr = 2*Piecewise((x, x < 1), (x**2, x<2), (x**3,True)) assert rcode(expr) == "2*ifelse(x < 1,x,ifelse(x < 2,x^2,x^3))" res = rcode(expr, assign_to='c') assert res == "c = 2*ifelse(x < 1,x,ifelse(x < 2,x^2,x^3));" # Check that Piecewise without a True (default) condition error #expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0)) #raises(ValueError, lambda: rcode(expr)) expr = 2*Piecewise((x, x < 1), (x**2, x<2)) assert(rcode(expr))== "2*ifelse(x < 1,x,ifelse(x < 2,x^2,NA))" def test_rcode_sinc(): from sympy import sinc expr = sinc(x) res = rcode(expr) ref = "ifelse(x != 0,sin(x)/x,1)" assert res == ref def test_rcode_Piecewise_deep(): p = rcode(2*Piecewise((x, x < 1), (x + 1, x < 2), (x**2, True))) assert p == "2*ifelse(x < 1,x,ifelse(x < 2,x + 1,x^2))" expr = x*y*z + x**2 + y**2 + Piecewise((0, x < 0.5), (1, True)) + cos(z) - 1 p = rcode(expr) ref="x^2 + x*y*z + y^2 + ifelse(x < 0.5,0,1) + cos(z) - 1" assert p == ref ref="c = x^2 + x*y*z + y^2 + ifelse(x < 0.5,0,1) + cos(z) - 1;" p = rcode(expr, assign_to='c') assert p == ref def test_rcode_ITE(): expr = ITE(x < 1, y, z) p = rcode(expr) ref="ifelse(x < 1,y,z)" assert p == ref def test_rcode_settings(): raises(TypeError, lambda: rcode(sin(x), method="garbage")) def test_rcode_Indexed(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o = symbols('n m o', integer=True) i, j, k = Idx('i', n), Idx('j', m), Idx('k', o) p = RCodePrinter() p._not_r = set() x = IndexedBase('x')[j] assert p._print_Indexed(x) == 'x[j]' A = IndexedBase('A')[i, j] assert p._print_Indexed(A) == 'A[i, j]' B = IndexedBase('B')[i, j, k] assert p._print_Indexed(B) == 'B[i, j, k]' assert p._not_r == set() def test_rcode_Indexed_without_looking_for_contraction(): len_y = 5 y = IndexedBase('y', shape=(len_y,)) x = IndexedBase('x', shape=(len_y,)) Dy = IndexedBase('Dy', shape=(len_y-1,)) i = Idx('i', len_y-1) e=Eq(Dy[i], (y[i+1]-y[i])/(x[i+1]-x[i])) code0 = rcode(e.rhs, assign_to=e.lhs, contract=False) assert code0 == 'Dy[i] = (y[%s] - y[i])/(x[%s] - x[i]);' % (i + 1, i + 1) def test_rcode_loops_matrix_vector(): n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) s = ( 'for (i in 1:m){\n' ' y[i] = 0;\n' '}\n' 'for (i in 1:m){\n' ' for (j in 1:n){\n' ' y[i] = A[i, j]*x[j] + y[i];\n' ' }\n' '}' ) c = rcode(A[i, j]*x[j], assign_to=y[i]) assert c == s def test_dummy_loops(): # the following line could also be # [Dummy(s, integer=True) for s in 'im'] # or [Dummy(integer=True) for s in 'im'] i, m = symbols('i m', integer=True, cls=Dummy) x = IndexedBase('x') y = IndexedBase('y') i = Idx(i, m) expected = ( 'for (i_%(icount)i in 1:m_%(mcount)i){\n' ' y[i_%(icount)i] = x[i_%(icount)i];\n' '}' ) % {'icount': i.label.dummy_index, 'mcount': m.dummy_index} code = rcode(x[i], assign_to=y[i]) assert code == expected def test_rcode_loops_add(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') z = IndexedBase('z') i = Idx('i', m) j = Idx('j', n) s = ( 'for (i in 1:m){\n' ' y[i] = x[i] + z[i];\n' '}\n' 'for (i in 1:m){\n' ' for (j in 1:n){\n' ' y[i] = A[i, j]*x[j] + y[i];\n' ' }\n' '}' ) c = rcode(A[i, j]*x[j] + x[i] + z[i], assign_to=y[i]) assert c == s def test_rcode_loops_multiple_contractions(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o, p = symbols('n m o p', integer=True) a = IndexedBase('a') b = IndexedBase('b') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) k = Idx('k', o) l = Idx('l', p) s = ( 'for (i in 1:m){\n' ' y[i] = 0;\n' '}\n' 'for (i in 1:m){\n' ' for (j in 1:n){\n' ' for (k in 1:o){\n' ' for (l in 1:p){\n' ' y[i] = a[i, j, k, l]*b[j, k, l] + y[i];\n' ' }\n' ' }\n' ' }\n' '}' ) c = rcode(b[j, k, l]*a[i, j, k, l], assign_to=y[i]) assert c == s def test_rcode_loops_addfactor(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o, p = symbols('n m o p', integer=True) a = IndexedBase('a') b = IndexedBase('b') c = IndexedBase('c') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) k = Idx('k', o) l = Idx('l', p) s = ( 'for (i in 1:m){\n' ' y[i] = 0;\n' '}\n' 'for (i in 1:m){\n' ' for (j in 1:n){\n' ' for (k in 1:o){\n' ' for (l in 1:p){\n' ' y[i] = (a[i, j, k, l] + b[i, j, k, l])*c[j, k, l] + y[i];\n' ' }\n' ' }\n' ' }\n' '}' ) c = rcode((a[i, j, k, l] + b[i, j, k, l])*c[j, k, l], assign_to=y[i]) assert c == s def test_rcode_loops_multiple_terms(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o, p = symbols('n m o p', integer=True) a = IndexedBase('a') b = IndexedBase('b') c = IndexedBase('c') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) k = Idx('k', o) s0 = ( 'for (i in 1:m){\n' ' y[i] = 0;\n' '}\n' ) s1 = ( 'for (i in 1:m){\n' ' for (j in 1:n){\n' ' for (k in 1:o){\n' ' y[i] = b[j]*b[k]*c[i, j, k] + y[i];\n' ' }\n' ' }\n' '}\n' ) s2 = ( 'for (i in 1:m){\n' ' for (k in 1:o){\n' ' y[i] = a[i, k]*b[k] + y[i];\n' ' }\n' '}\n' ) s3 = ( 'for (i in 1:m){\n' ' for (j in 1:n){\n' ' y[i] = a[i, j]*b[j] + y[i];\n' ' }\n' '}\n' ) c = rcode( b[j]*a[i, j] + b[k]*a[i, k] + b[j]*b[k]*c[i, j, k], assign_to=y[i]) ref=dict() ref[0] = s0 + s1 + s2 + s3[:-1] ref[1] = s0 + s1 + s3 + s2[:-1] ref[2] = s0 + s2 + s1 + s3[:-1] ref[3] = s0 + s2 + s3 + s1[:-1] ref[4] = s0 + s3 + s1 + s2[:-1] ref[5] = s0 + s3 + s2 + s1[:-1] assert (c == ref[0] or c == ref[1] or c == ref[2] or c == ref[3] or c == ref[4] or c == ref[5]) def test_dereference_printing(): expr = x + y + sin(z) + z assert rcode(expr, dereference=[z]) == "x + y + (*z) + sin((*z))" def test_Matrix_printing(): # Test returning a Matrix mat = Matrix([x*y, Piecewise((2 + x, y>0), (y, True)), sin(z)]) A = MatrixSymbol('A', 3, 1) p = rcode(mat, A) assert p == ( "A[0] = x*y;\n" "A[1] = ifelse(y > 0,x + 2,y);\n" "A[2] = sin(z);") # Test using MatrixElements in expressions expr = Piecewise((2*A[2, 0], x > 0), (A[2, 0], True)) + sin(A[1, 0]) + A[0, 0] p = rcode(expr) assert p == ("ifelse(x > 0,2*A[2],A[2]) + sin(A[1]) + A[0]") # Test using MatrixElements in a Matrix q = MatrixSymbol('q', 5, 1) M = MatrixSymbol('M', 3, 3) m = Matrix([[sin(q[1,0]), 0, cos(q[2,0])], [q[1,0] + q[2,0], q[3, 0], 5], [2*q[4, 0]/q[1,0], sqrt(q[0,0]) + 4, 0]]) assert rcode(m, M) == ( "M[0] = sin(q[1]);\n" "M[1] = 0;\n" "M[2] = cos(q[2]);\n" "M[3] = q[1] + q[2];\n" "M[4] = q[3];\n" "M[5] = 5;\n" "M[6] = 2*q[4]/q[1];\n" "M[7] = sqrt(q[0]) + 4;\n" "M[8] = 0;") def test_rcode_sgn(): expr = sign(x) * y assert rcode(expr) == 'y*sign(x)' p = rcode(expr, 'z') assert p == 'z = y*sign(x);' p = rcode(sign(2 * x + x**2) * x + x**2) assert p == "x^2 + x*sign(x^2 + 2*x)" expr = sign(cos(x)) p = rcode(expr) assert p == 'sign(cos(x))' def test_rcode_Assignment(): assert rcode(Assignment(x, y + z)) == 'x = y + z;' assert rcode(aug_assign(x, '+', y + z)) == 'x += y + z;' def test_rcode_For(): f = For(x, Range(0, 10, 2), [aug_assign(y, '*', x)]) sol = rcode(f) assert sol == ("for (x = 0; x < 10; x += 2) {\n" " y *= x;\n" "}") def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert(rcode(A[0, 0]) == "A[0]") assert(rcode(3 * A[0, 0]) == "3*A[0]") F = C[0, 0].subs(C, A - B) assert(rcode(F) == "(A - B)[0]") sympy-sympy-1.9/sympy/printing/tests/test_repr.py000066400000000000000000000262361412543434000224720ustar00rootroot00000000000000from typing import Any, Dict from sympy.testing.pytest import raises from sympy import (symbols, sympify, Function, Integer, Matrix, Abs, Heaviside, Rational, Float, S, WildFunction, ImmutableDenseMatrix, sin, true, false, ones, sqrt, root, AlgebraicNumber, Symbol, Dummy, Wild, MatrixSymbol, Q) from sympy.combinatorics import Cycle, Permutation from sympy.core.symbol import Str from sympy.geometry import Point, Ellipse from sympy.printing import srepr from sympy.polys import ring, field, ZZ, QQ, lex, grlex, Poly from sympy.polys.polyclasses import DMP from sympy.polys.agca.extensions import FiniteExtension x, y = symbols('x,y') # eval(srepr(expr)) == expr has to succeed in the right environment. The right # environment is the scope of "from sympy import *" for most cases. ENV = {"Str": Str} # type: Dict[str, Any] exec("from sympy import *", ENV) def sT(expr, string, import_stmt=None): """ sT := sreprTest Tests that srepr delivers the expected string and that the condition eval(srepr(expr))==expr holds. """ if import_stmt is None: ENV2 = ENV else: ENV2 = ENV.copy() exec(import_stmt, ENV2) assert srepr(expr) == string assert eval(string, ENV2) == expr def test_printmethod(): class R(Abs): def _sympyrepr(self, printer): return "foo(%s)" % printer._print(self.args[0]) assert srepr(R(x)) == "foo(Symbol('x'))" def test_Add(): sT(x + y, "Add(Symbol('x'), Symbol('y'))") assert srepr(x**2 + 1, order='lex') == "Add(Pow(Symbol('x'), Integer(2)), Integer(1))" assert srepr(x**2 + 1, order='old') == "Add(Integer(1), Pow(Symbol('x'), Integer(2)))" assert srepr(sympify('x + 3 - 2', evaluate=False), order='none') == "Add(Symbol('x'), Integer(3), Mul(Integer(-1), Integer(2)))" def test_more_than_255_args_issue_10259(): from sympy import Add, Mul for op in (Add, Mul): expr = op(*symbols('x:256')) assert eval(srepr(expr)) == expr def test_Function(): sT(Function("f")(x), "Function('f')(Symbol('x'))") # test unapplied Function sT(Function('f'), "Function('f')") sT(sin(x), "sin(Symbol('x'))") sT(sin, "sin") def test_Heaviside(): sT(Heaviside(x), "Heaviside(Symbol('x'))") sT(Heaviside(x, 1), "Heaviside(Symbol('x'), Integer(1))") def test_Geometry(): sT(Point(0, 0), "Point2D(Integer(0), Integer(0))") sT(Ellipse(Point(0, 0), 5, 1), "Ellipse(Point2D(Integer(0), Integer(0)), Integer(5), Integer(1))") # TODO more tests def test_Singletons(): sT(S.Catalan, 'Catalan') sT(S.ComplexInfinity, 'zoo') sT(S.EulerGamma, 'EulerGamma') sT(S.Exp1, 'E') sT(S.GoldenRatio, 'GoldenRatio') sT(S.TribonacciConstant, 'TribonacciConstant') sT(S.Half, 'Rational(1, 2)') sT(S.ImaginaryUnit, 'I') sT(S.Infinity, 'oo') sT(S.NaN, 'nan') sT(S.NegativeInfinity, '-oo') sT(S.NegativeOne, 'Integer(-1)') sT(S.One, 'Integer(1)') sT(S.Pi, 'pi') sT(S.Zero, 'Integer(0)') def test_Integer(): sT(Integer(4), "Integer(4)") def test_list(): sT([x, Integer(4)], "[Symbol('x'), Integer(4)]") def test_Matrix(): for cls, name in [(Matrix, "MutableDenseMatrix"), (ImmutableDenseMatrix, "ImmutableDenseMatrix")]: sT(cls([[x**+1, 1], [y, x + y]]), "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])" % name) sT(cls(), "%s([])" % name) sT(cls([[x**+1, 1], [y, x + y]]), "%s([[Symbol('x'), Integer(1)], [Symbol('y'), Add(Symbol('x'), Symbol('y'))]])" % name) def test_empty_Matrix(): sT(ones(0, 3), "MutableDenseMatrix(0, 3, [])") sT(ones(4, 0), "MutableDenseMatrix(4, 0, [])") sT(ones(0, 0), "MutableDenseMatrix([])") def test_Rational(): sT(Rational(1, 3), "Rational(1, 3)") sT(Rational(-1, 3), "Rational(-1, 3)") def test_Float(): sT(Float('1.23', dps=3), "Float('1.22998', precision=13)") sT(Float('1.23456789', dps=9), "Float('1.23456788994', precision=33)") sT(Float('1.234567890123456789', dps=19), "Float('1.234567890123456789013', precision=66)") sT(Float('0.60038617995049726', dps=15), "Float('0.60038617995049726', precision=53)") sT(Float('1.23', precision=13), "Float('1.22998', precision=13)") sT(Float('1.23456789', precision=33), "Float('1.23456788994', precision=33)") sT(Float('1.234567890123456789', precision=66), "Float('1.234567890123456789013', precision=66)") sT(Float('0.60038617995049726', precision=53), "Float('0.60038617995049726', precision=53)") sT(Float('0.60038617995049726', 15), "Float('0.60038617995049726', precision=53)") def test_Symbol(): sT(x, "Symbol('x')") sT(y, "Symbol('y')") sT(Symbol('x', negative=True), "Symbol('x', negative=True)") def test_Symbol_two_assumptions(): x = Symbol('x', negative=0, integer=1) # order could vary s1 = "Symbol('x', integer=True, negative=False)" s2 = "Symbol('x', negative=False, integer=True)" assert srepr(x) in (s1, s2) assert eval(srepr(x), ENV) == x def test_Symbol_no_special_commutative_treatment(): sT(Symbol('x'), "Symbol('x')") sT(Symbol('x', commutative=False), "Symbol('x', commutative=False)") sT(Symbol('x', commutative=0), "Symbol('x', commutative=False)") sT(Symbol('x', commutative=True), "Symbol('x', commutative=True)") sT(Symbol('x', commutative=1), "Symbol('x', commutative=True)") def test_Wild(): sT(Wild('x', even=True), "Wild('x', even=True)") def test_Dummy(): d = Dummy('d') sT(d, "Dummy('d', dummy_index=%s)" % str(d.dummy_index)) def test_Dummy_assumption(): d = Dummy('d', nonzero=True) assert d == eval(srepr(d)) s1 = "Dummy('d', dummy_index=%s, nonzero=True)" % str(d.dummy_index) s2 = "Dummy('d', nonzero=True, dummy_index=%s)" % str(d.dummy_index) assert srepr(d) in (s1, s2) def test_Dummy_from_Symbol(): # should not get the full dictionary of assumptions n = Symbol('n', integer=True) d = n.as_dummy() assert srepr(d ) == "Dummy('n', dummy_index=%s)" % str(d.dummy_index) def test_tuple(): sT((x,), "(Symbol('x'),)") sT((x, y), "(Symbol('x'), Symbol('y'))") def test_WildFunction(): sT(WildFunction('w'), "WildFunction('w')") def test_settins(): raises(TypeError, lambda: srepr(x, method="garbage")) def test_Mul(): sT(3*x**3*y, "Mul(Integer(3), Pow(Symbol('x'), Integer(3)), Symbol('y'))") assert srepr(3*x**3*y, order='old') == "Mul(Integer(3), Symbol('y'), Pow(Symbol('x'), Integer(3)))" assert srepr(sympify('(x+4)*2*x*7', evaluate=False), order='none') == "Mul(Add(Symbol('x'), Integer(4)), Integer(2), Symbol('x'), Integer(7))" def test_AlgebraicNumber(): a = AlgebraicNumber(sqrt(2)) sT(a, "AlgebraicNumber(Pow(Integer(2), Rational(1, 2)), [Integer(1), Integer(0)])") a = AlgebraicNumber(root(-2, 3)) sT(a, "AlgebraicNumber(Pow(Integer(-2), Rational(1, 3)), [Integer(1), Integer(0)])") def test_PolyRing(): assert srepr(ring("x", ZZ, lex)[0]) == "PolyRing((Symbol('x'),), ZZ, lex)" assert srepr(ring("x,y", QQ, grlex)[0]) == "PolyRing((Symbol('x'), Symbol('y')), QQ, grlex)" assert srepr(ring("x,y,z", ZZ["t"], lex)[0]) == "PolyRing((Symbol('x'), Symbol('y'), Symbol('z')), ZZ[t], lex)" def test_FracField(): assert srepr(field("x", ZZ, lex)[0]) == "FracField((Symbol('x'),), ZZ, lex)" assert srepr(field("x,y", QQ, grlex)[0]) == "FracField((Symbol('x'), Symbol('y')), QQ, grlex)" assert srepr(field("x,y,z", ZZ["t"], lex)[0]) == "FracField((Symbol('x'), Symbol('y'), Symbol('z')), ZZ[t], lex)" def test_PolyElement(): R, x, y = ring("x,y", ZZ) assert srepr(3*x**2*y + 1) == "PolyElement(PolyRing((Symbol('x'), Symbol('y')), ZZ, lex), [((2, 1), 3), ((0, 0), 1)])" def test_FracElement(): F, x, y = field("x,y", ZZ) assert srepr((3*x**2*y + 1)/(x - y**2)) == "FracElement(FracField((Symbol('x'), Symbol('y')), ZZ, lex), [((2, 1), 3), ((0, 0), 1)], [((1, 0), 1), ((0, 2), -1)])" def test_FractionField(): assert srepr(QQ.frac_field(x)) == \ "FractionField(FracField((Symbol('x'),), QQ, lex))" assert srepr(QQ.frac_field(x, y, order=grlex)) == \ "FractionField(FracField((Symbol('x'), Symbol('y')), QQ, grlex))" def test_PolynomialRingBase(): assert srepr(ZZ.old_poly_ring(x)) == \ "GlobalPolynomialRing(ZZ, Symbol('x'))" assert srepr(ZZ[x].old_poly_ring(y)) == \ "GlobalPolynomialRing(ZZ[x], Symbol('y'))" assert srepr(QQ.frac_field(x).old_poly_ring(y)) == \ "GlobalPolynomialRing(FractionField(FracField((Symbol('x'),), QQ, lex)), Symbol('y'))" def test_DMP(): assert srepr(DMP([1, 2], ZZ)) == 'DMP([1, 2], ZZ)' assert srepr(ZZ.old_poly_ring(x)([1, 2])) == \ "DMP([1, 2], ZZ, ring=GlobalPolynomialRing(ZZ, Symbol('x')))" def test_FiniteExtension(): assert srepr(FiniteExtension(Poly(x**2 + 1, x))) == \ "FiniteExtension(Poly(x**2 + 1, x, domain='ZZ'))" def test_ExtensionElement(): A = FiniteExtension(Poly(x**2 + 1, x)) assert srepr(A.generator) == \ "ExtElem(DMP([1, 0], ZZ, ring=GlobalPolynomialRing(ZZ, Symbol('x'))), FiniteExtension(Poly(x**2 + 1, x, domain='ZZ')))" def test_BooleanAtom(): assert srepr(true) == "true" assert srepr(false) == "false" def test_Integers(): sT(S.Integers, "Integers") def test_Naturals(): sT(S.Naturals, "Naturals") def test_Naturals0(): sT(S.Naturals0, "Naturals0") def test_Reals(): sT(S.Reals, "Reals") def test_matrix_expressions(): n = symbols('n', integer=True) A = MatrixSymbol("A", n, n) B = MatrixSymbol("B", n, n) sT(A, "MatrixSymbol(Str('A'), Symbol('n', integer=True), Symbol('n', integer=True))") sT(A*B, "MatMul(MatrixSymbol(Str('A'), Symbol('n', integer=True), Symbol('n', integer=True)), MatrixSymbol(Str('B'), Symbol('n', integer=True), Symbol('n', integer=True)))") sT(A + B, "MatAdd(MatrixSymbol(Str('A'), Symbol('n', integer=True), Symbol('n', integer=True)), MatrixSymbol(Str('B'), Symbol('n', integer=True), Symbol('n', integer=True)))") def test_Cycle(): # FIXME: sT fails because Cycle is not immutable and calling srepr(Cycle(1, 2)) # adds keys to the Cycle dict (GH-17661) #import_stmt = "from sympy.combinatorics import Cycle" #sT(Cycle(1, 2), "Cycle(1, 2)", import_stmt) assert srepr(Cycle(1, 2)) == "Cycle(1, 2)" def test_Permutation(): import_stmt = "from sympy.combinatorics import Permutation" sT(Permutation(1, 2), "Permutation(1, 2)", import_stmt) def test_dict(): from sympy import srepr from sympy.abc import x, y, z d = {} assert srepr(d) == "{}" d = {x: y} assert srepr(d) == "{Symbol('x'): Symbol('y')}" d = {x: y, y: z} assert srepr(d) in ( "{Symbol('x'): Symbol('y'), Symbol('y'): Symbol('z')}", "{Symbol('y'): Symbol('z'), Symbol('x'): Symbol('y')}", ) d = {x: {y: z}} assert srepr(d) == "{Symbol('x'): {Symbol('y'): Symbol('z')}}" def test_set(): from sympy import srepr from sympy.abc import x, y s = set() assert srepr(s) == "set()" s = {x, y} assert srepr(s) in ("{Symbol('x'), Symbol('y')}", "{Symbol('y'), Symbol('x')}") def test_Predicate(): sT(Q.even, "Q.even") def test_AppliedPredicate(): sT(Q.even(Symbol('z')), "AppliedPredicate(Q.even, Symbol('z'))") sympy-sympy-1.9/sympy/printing/tests/test_rust.py000066400000000000000000000265741412543434000225240ustar00rootroot00000000000000from sympy.core import (S, pi, oo, symbols, Rational, Integer, GoldenRatio, EulerGamma, Catalan, Lambda, Dummy, Eq, Ne, Le, Lt, Gt, Ge) from sympy.functions import (Piecewise, sin, cos, Abs, exp, ceiling, sqrt, sign) from sympy.logic import ITE from sympy.testing.pytest import raises from sympy.utilities.lambdify import implemented_function from sympy.tensor import IndexedBase, Idx from sympy.matrices import MatrixSymbol, SparseMatrix, Matrix from sympy import rust_code x, y, z = symbols('x,y,z') def test_Integer(): assert rust_code(Integer(42)) == "42" assert rust_code(Integer(-56)) == "-56" def test_Relational(): assert rust_code(Eq(x, y)) == "x == y" assert rust_code(Ne(x, y)) == "x != y" assert rust_code(Le(x, y)) == "x <= y" assert rust_code(Lt(x, y)) == "x < y" assert rust_code(Gt(x, y)) == "x > y" assert rust_code(Ge(x, y)) == "x >= y" def test_Rational(): assert rust_code(Rational(3, 7)) == "3_f64/7.0" assert rust_code(Rational(18, 9)) == "2" assert rust_code(Rational(3, -7)) == "-3_f64/7.0" assert rust_code(Rational(-3, -7)) == "3_f64/7.0" assert rust_code(x + Rational(3, 7)) == "x + 3_f64/7.0" assert rust_code(Rational(3, 7)*x) == "(3_f64/7.0)*x" def test_basic_ops(): assert rust_code(x + y) == "x + y" assert rust_code(x - y) == "x - y" assert rust_code(x * y) == "x*y" assert rust_code(x / y) == "x/y" assert rust_code(-x) == "-x" def test_printmethod(): class fabs(Abs): def _rust_code(self, printer): return "%s.fabs()" % printer._print(self.args[0]) assert rust_code(fabs(x)) == "x.fabs()" a = MatrixSymbol("a", 1 ,3) assert rust_code(a[0,0]) == 'a[0]' def test_Functions(): assert rust_code(sin(x) ** cos(x)) == "x.sin().powf(x.cos())" assert rust_code(abs(x)) == "x.abs()" assert rust_code(ceiling(x)) == "x.ceil()" def test_Pow(): assert rust_code(1/x) == "x.recip()" assert rust_code(x**-1) == rust_code(x**-1.0) == "x.recip()" assert rust_code(sqrt(x)) == "x.sqrt()" assert rust_code(x**S.Half) == rust_code(x**0.5) == "x.sqrt()" assert rust_code(1/sqrt(x)) == "x.sqrt().recip()" assert rust_code(x**-S.Half) == rust_code(x**-0.5) == "x.sqrt().recip()" assert rust_code(1/pi) == "PI.recip()" assert rust_code(pi**-1) == rust_code(pi**-1.0) == "PI.recip()" assert rust_code(pi**-0.5) == "PI.sqrt().recip()" assert rust_code(x**Rational(1, 3)) == "x.cbrt()" assert rust_code(2**x) == "x.exp2()" assert rust_code(exp(x)) == "x.exp()" assert rust_code(x**3) == "x.powi(3)" assert rust_code(x**(y**3)) == "x.powf(y.powi(3))" assert rust_code(x**Rational(2, 3)) == "x.powf(2_f64/3.0)" g = implemented_function('g', Lambda(x, 2*x)) assert rust_code(1/(g(x)*3.5)**(x - y**x)/(x**2 + y)) == \ "(3.5*2*x).powf(-x + y.powf(x))/(x.powi(2) + y)" _cond_cfunc = [(lambda base, exp: exp.is_integer, "dpowi", 1), (lambda base, exp: not exp.is_integer, "pow", 1)] assert rust_code(x**3, user_functions={'Pow': _cond_cfunc}) == 'x.dpowi(3)' assert rust_code(x**3.2, user_functions={'Pow': _cond_cfunc}) == 'x.pow(3.2)' def test_constants(): assert rust_code(pi) == "PI" assert rust_code(oo) == "INFINITY" assert rust_code(S.Infinity) == "INFINITY" assert rust_code(-oo) == "NEG_INFINITY" assert rust_code(S.NegativeInfinity) == "NEG_INFINITY" assert rust_code(S.NaN) == "NAN" assert rust_code(exp(1)) == "E" assert rust_code(S.Exp1) == "E" def test_constants_other(): assert rust_code(2*GoldenRatio) == "const GoldenRatio: f64 = %s;\n2*GoldenRatio" % GoldenRatio.evalf(17) assert rust_code( 2*Catalan) == "const Catalan: f64 = %s;\n2*Catalan" % Catalan.evalf(17) assert rust_code(2*EulerGamma) == "const EulerGamma: f64 = %s;\n2*EulerGamma" % EulerGamma.evalf(17) def test_boolean(): assert rust_code(True) == "true" assert rust_code(S.true) == "true" assert rust_code(False) == "false" assert rust_code(S.false) == "false" assert rust_code(x & y) == "x && y" assert rust_code(x | y) == "x || y" assert rust_code(~x) == "!x" assert rust_code(x & y & z) == "x && y && z" assert rust_code(x | y | z) == "x || y || z" assert rust_code((x & y) | z) == "z || x && y" assert rust_code((x | y) & z) == "z && (x || y)" def test_Piecewise(): expr = Piecewise((x, x < 1), (x + 2, True)) assert rust_code(expr) == ( "if (x < 1) {\n" " x\n" "} else {\n" " x + 2\n" "}") assert rust_code(expr, assign_to="r") == ( "r = if (x < 1) {\n" " x\n" "} else {\n" " x + 2\n" "};") assert rust_code(expr, assign_to="r", inline=True) == ( "r = if (x < 1) { x } else { x + 2 };") expr = Piecewise((x, x < 1), (x + 1, x < 5), (x + 2, True)) assert rust_code(expr, inline=True) == ( "if (x < 1) { x } else if (x < 5) { x + 1 } else { x + 2 }") assert rust_code(expr, assign_to="r", inline=True) == ( "r = if (x < 1) { x } else if (x < 5) { x + 1 } else { x + 2 };") assert rust_code(expr, assign_to="r") == ( "r = if (x < 1) {\n" " x\n" "} else if (x < 5) {\n" " x + 1\n" "} else {\n" " x + 2\n" "};") expr = 2*Piecewise((x, x < 1), (x + 1, x < 5), (x + 2, True)) assert rust_code(expr, inline=True) == ( "2*if (x < 1) { x } else if (x < 5) { x + 1 } else { x + 2 }") expr = 2*Piecewise((x, x < 1), (x + 1, x < 5), (x + 2, True)) - 42 assert rust_code(expr, inline=True) == ( "2*if (x < 1) { x } else if (x < 5) { x + 1 } else { x + 2 } - 42") # Check that Piecewise without a True (default) condition error expr = Piecewise((x, x < 1), (x**2, x > 1), (sin(x), x > 0)) raises(ValueError, lambda: rust_code(expr)) def test_dereference_printing(): expr = x + y + sin(z) + z assert rust_code(expr, dereference=[z]) == "x + y + (*z) + (*z).sin()" def test_sign(): expr = sign(x) * y assert rust_code(expr) == "y*x.signum()" assert rust_code(expr, assign_to='r') == "r = y*x.signum();" expr = sign(x + y) + 42 assert rust_code(expr) == "(x + y).signum() + 42" assert rust_code(expr, assign_to='r') == "r = (x + y).signum() + 42;" expr = sign(cos(x)) assert rust_code(expr) == "x.cos().signum()" def test_reserved_words(): x, y = symbols("x if") expr = sin(y) assert rust_code(expr) == "if_.sin()" assert rust_code(expr, dereference=[y]) == "(*if_).sin()" assert rust_code(expr, reserved_word_suffix='_unreserved') == "if_unreserved.sin()" with raises(ValueError): rust_code(expr, error_on_reserved=True) def test_ITE(): expr = ITE(x < 1, y, z) assert rust_code(expr) == ( "if (x < 1) {\n" " y\n" "} else {\n" " z\n" "}") def test_Indexed(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o = symbols('n m o', integer=True) i, j, k = Idx('i', n), Idx('j', m), Idx('k', o) x = IndexedBase('x')[j] assert rust_code(x) == "x[j]" A = IndexedBase('A')[i, j] assert rust_code(A) == "A[m*i + j]" B = IndexedBase('B')[i, j, k] assert rust_code(B) == "B[m*o*i + o*j + k]" def test_dummy_loops(): i, m = symbols('i m', integer=True, cls=Dummy) x = IndexedBase('x') y = IndexedBase('y') i = Idx(i, m) assert rust_code(x[i], assign_to=y[i]) == ( "for i in 0..m {\n" " y[i] = x[i];\n" "}") def test_loops(): from sympy.tensor import IndexedBase, Idx from sympy import symbols m, n = symbols('m n', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') z = IndexedBase('z') i = Idx('i', m) j = Idx('j', n) assert rust_code(A[i, j]*x[j], assign_to=y[i]) == ( "for i in 0..m {\n" " y[i] = 0;\n" "}\n" "for i in 0..m {\n" " for j in 0..n {\n" " y[i] = A[n*i + j]*x[j] + y[i];\n" " }\n" "}") assert rust_code(A[i, j]*x[j] + x[i] + z[i], assign_to=y[i]) == ( "for i in 0..m {\n" " y[i] = x[i] + z[i];\n" "}\n" "for i in 0..m {\n" " for j in 0..n {\n" " y[i] = A[n*i + j]*x[j] + y[i];\n" " }\n" "}") def test_loops_multiple_contractions(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o, p = symbols('n m o p', integer=True) a = IndexedBase('a') b = IndexedBase('b') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) k = Idx('k', o) l = Idx('l', p) assert rust_code(b[j, k, l]*a[i, j, k, l], assign_to=y[i]) == ( "for i in 0..m {\n" " y[i] = 0;\n" "}\n" "for i in 0..m {\n" " for j in 0..n {\n" " for k in 0..o {\n" " for l in 0..p {\n" " y[i] = a[%s]*b[%s] + y[i];\n" % (i*n*o*p + j*o*p + k*p + l, j*o*p + k*p + l) +\ " }\n" " }\n" " }\n" "}") def test_loops_addfactor(): from sympy.tensor import IndexedBase, Idx from sympy import symbols m, n, o, p = symbols('m n o p', integer=True) a = IndexedBase('a') b = IndexedBase('b') c = IndexedBase('c') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) k = Idx('k', o) l = Idx('l', p) code = rust_code((a[i, j, k, l] + b[i, j, k, l])*c[j, k, l], assign_to=y[i]) assert code == ( "for i in 0..m {\n" " y[i] = 0;\n" "}\n" "for i in 0..m {\n" " for j in 0..n {\n" " for k in 0..o {\n" " for l in 0..p {\n" " y[i] = (a[%s] + b[%s])*c[%s] + y[i];\n" % (i*n*o*p + j*o*p + k*p + l, i*n*o*p + j*o*p + k*p + l, j*o*p + k*p + l) +\ " }\n" " }\n" " }\n" "}") def test_settings(): raises(TypeError, lambda: rust_code(sin(x), method="garbage")) def test_inline_function(): x = symbols('x') g = implemented_function('g', Lambda(x, 2*x)) assert rust_code(g(x)) == "2*x" g = implemented_function('g', Lambda(x, 2*x/Catalan)) assert rust_code(g(x)) == ( "const Catalan: f64 = %s;\n2*x/Catalan" % Catalan.evalf(17)) A = IndexedBase('A') i = Idx('i', symbols('n', integer=True)) g = implemented_function('g', Lambda(x, x*(1 + x)*(2 + x))) assert rust_code(g(A[i]), assign_to=A[i]) == ( "for i in 0..n {\n" " A[i] = (A[i] + 1)*(A[i] + 2)*A[i];\n" "}") def test_user_functions(): x = symbols('x', integer=False) n = symbols('n', integer=True) custom_functions = { "ceiling": "ceil", "Abs": [(lambda x: not x.is_integer, "fabs", 4), (lambda x: x.is_integer, "abs", 4)], } assert rust_code(ceiling(x), user_functions=custom_functions) == "x.ceil()" assert rust_code(Abs(x), user_functions=custom_functions) == "fabs(x)" assert rust_code(Abs(n), user_functions=custom_functions) == "abs(n)" def test_matrix(): assert rust_code(Matrix([1, 2, 3])) == '[1, 2, 3]' with raises(ValueError): rust_code(Matrix([[1, 2, 3]])) def test_sparse_matrix(): # gh-15791 assert 'Not supported in Rust' in rust_code(SparseMatrix([[1, 2, 3]])) sympy-sympy-1.9/sympy/printing/tests/test_str.py000066400000000000000000001161161412543434000223270ustar00rootroot00000000000000from sympy import (Add, Abs, Catalan, cos, Derivative, E, EulerGamma, exp, factorial, factorial2, Function, GoldenRatio, Heaviside, TribonacciConstant, I, Integer, Integral, Interval, Lambda, Limit, Matrix, nan, O, oo, pi, Pow, Rational, Float, Rel, S, sin, SparseMatrix, sqrt, summation, Sum, Symbol, symbols, Wild, WildFunction, zeta, zoo, Dummy, Dict, Tuple, FiniteSet, factor, subfactorial, true, false, Equivalent, Xor, Complement, SymmetricDifference, AccumBounds, UnevaluatedExpr, Eq, Ne, Quaternion, Subs, MatrixSymbol, MatrixSlice, Q,) from sympy.combinatorics.partitions import Partition from sympy.core import Expr, Mul from sympy.core.parameters import _exp_is_pow from sympy.external import import_module from sympy.physics.control.lti import TransferFunction, Series, Parallel, \ Feedback, TransferFunctionMatrix, MIMOSeries, MIMOParallel, MIMOFeedback from sympy.physics.units import second, joule from sympy.polys import (Poly, rootof, RootSum, groebner, ring, field, ZZ, QQ, ZZ_I, QQ_I, lex, grlex) from sympy.geometry import Point, Circle, Polygon, Ellipse, Triangle from sympy.tensor import NDimArray from sympy.tensor.array.expressions.array_expressions import ArraySymbol, ArrayElement from sympy.testing.pytest import raises from sympy.printing import sstr, sstrrepr, StrPrinter from sympy.core.trace import Tr x, y, z, w, t = symbols('x,y,z,w,t') d = Dummy('d') def test_printmethod(): class R(Abs): def _sympystr(self, printer): return "foo(%s)" % printer._print(self.args[0]) assert sstr(R(x)) == "foo(x)" class R(Abs): def _sympystr(self, printer): return "foo" assert sstr(R(x)) == "foo" def test_Abs(): assert str(Abs(x)) == "Abs(x)" assert str(Abs(Rational(1, 6))) == "1/6" assert str(Abs(Rational(-1, 6))) == "1/6" def test_Add(): assert str(x + y) == "x + y" assert str(x + 1) == "x + 1" assert str(x + x**2) == "x**2 + x" assert str(Add(0, 1, evaluate=False)) == "0 + 1" assert str(Add(0, 0, 1, evaluate=False)) == "0 + 0 + 1" assert str(1.0*x) == "1.0*x" assert str(5 + x + y + x*y + x**2 + y**2) == "x**2 + x*y + x + y**2 + y + 5" assert str(1 + x + x**2/2 + x**3/3) == "x**3/3 + x**2/2 + x + 1" assert str(2*x - 7*x**2 + 2 + 3*y) == "-7*x**2 + 2*x + 3*y + 2" assert str(x - y) == "x - y" assert str(2 - x) == "2 - x" assert str(x - 2) == "x - 2" assert str(x - y - z - w) == "-w + x - y - z" assert str(x - z*y**2*z*w) == "-w*y**2*z**2 + x" assert str(x - 1*y*x*y) == "-x*y**2 + x" assert str(sin(x).series(x, 0, 15)) == "x - x**3/6 + x**5/120 - x**7/5040 + x**9/362880 - x**11/39916800 + x**13/6227020800 + O(x**15)" def test_Catalan(): assert str(Catalan) == "Catalan" def test_ComplexInfinity(): assert str(zoo) == "zoo" def test_Derivative(): assert str(Derivative(x, y)) == "Derivative(x, y)" assert str(Derivative(x**2, x, evaluate=False)) == "Derivative(x**2, x)" assert str(Derivative( x**2/y, x, y, evaluate=False)) == "Derivative(x**2/y, x, y)" def test_dict(): assert str({1: 1 + x}) == sstr({1: 1 + x}) == "{1: x + 1}" assert str({1: x**2, 2: y*x}) in ("{1: x**2, 2: x*y}", "{2: x*y, 1: x**2}") assert sstr({1: x**2, 2: y*x}) == "{1: x**2, 2: x*y}" def test_Dict(): assert str(Dict({1: 1 + x})) == sstr({1: 1 + x}) == "{1: x + 1}" assert str(Dict({1: x**2, 2: y*x})) in ( "{1: x**2, 2: x*y}", "{2: x*y, 1: x**2}") assert sstr(Dict({1: x**2, 2: y*x})) == "{1: x**2, 2: x*y}" def test_Dummy(): assert str(d) == "_d" assert str(d + x) == "_d + x" def test_EulerGamma(): assert str(EulerGamma) == "EulerGamma" def test_Exp(): assert str(E) == "E" with _exp_is_pow(True): assert str(exp(x)) == "E**x" def test_factorial(): n = Symbol('n', integer=True) assert str(factorial(-2)) == "zoo" assert str(factorial(0)) == "1" assert str(factorial(7)) == "5040" assert str(factorial(n)) == "factorial(n)" assert str(factorial(2*n)) == "factorial(2*n)" assert str(factorial(factorial(n))) == 'factorial(factorial(n))' assert str(factorial(factorial2(n))) == 'factorial(factorial2(n))' assert str(factorial2(factorial(n))) == 'factorial2(factorial(n))' assert str(factorial2(factorial2(n))) == 'factorial2(factorial2(n))' assert str(subfactorial(3)) == "2" assert str(subfactorial(n)) == "subfactorial(n)" assert str(subfactorial(2*n)) == "subfactorial(2*n)" def test_Function(): f = Function('f') fx = f(x) w = WildFunction('w') assert str(f) == "f" assert str(fx) == "f(x)" assert str(w) == "w_" def test_Geometry(): assert sstr(Point(0, 0)) == 'Point2D(0, 0)' assert sstr(Circle(Point(0, 0), 3)) == 'Circle(Point2D(0, 0), 3)' assert sstr(Ellipse(Point(1, 2), 3, 4)) == 'Ellipse(Point2D(1, 2), 3, 4)' assert sstr(Triangle(Point(1, 1), Point(7, 8), Point(0, -1))) == \ 'Triangle(Point2D(1, 1), Point2D(7, 8), Point2D(0, -1))' assert sstr(Polygon(Point(5, 6), Point(-2, -3), Point(0, 0), Point(4, 7))) == \ 'Polygon(Point2D(5, 6), Point2D(-2, -3), Point2D(0, 0), Point2D(4, 7))' assert sstr(Triangle(Point(0, 0), Point(1, 0), Point(0, 1)), sympy_integers=True) == \ 'Triangle(Point2D(S(0), S(0)), Point2D(S(1), S(0)), Point2D(S(0), S(1)))' assert sstr(Ellipse(Point(1, 2), 3, 4), sympy_integers=True) == \ 'Ellipse(Point2D(S(1), S(2)), S(3), S(4))' def test_GoldenRatio(): assert str(GoldenRatio) == "GoldenRatio" def test_Heaviside(): assert str(Heaviside(x)) == str(Heaviside(x, S.Half)) == "Heaviside(x)" assert str(Heaviside(x, 1)) == "Heaviside(x, 1)" def test_TribonacciConstant(): assert str(TribonacciConstant) == "TribonacciConstant" def test_ImaginaryUnit(): assert str(I) == "I" def test_Infinity(): assert str(oo) == "oo" assert str(oo*I) == "oo*I" def test_Integer(): assert str(Integer(-1)) == "-1" assert str(Integer(1)) == "1" assert str(Integer(-3)) == "-3" assert str(Integer(0)) == "0" assert str(Integer(25)) == "25" def test_Integral(): assert str(Integral(sin(x), y)) == "Integral(sin(x), y)" assert str(Integral(sin(x), (y, 0, 1))) == "Integral(sin(x), (y, 0, 1))" def test_Interval(): n = (S.NegativeInfinity, 1, 2, S.Infinity) for i in range(len(n)): for j in range(i + 1, len(n)): for l in (True, False): for r in (True, False): ival = Interval(n[i], n[j], l, r) assert S(str(ival)) == ival def test_AccumBounds(): a = Symbol('a', real=True) assert str(AccumBounds(0, a)) == "AccumBounds(0, a)" assert str(AccumBounds(0, 1)) == "AccumBounds(0, 1)" def test_Lambda(): assert str(Lambda(d, d**2)) == "Lambda(_d, _d**2)" # issue 2908 assert str(Lambda((), 1)) == "Lambda((), 1)" assert str(Lambda((), x)) == "Lambda((), x)" assert str(Lambda((x, y), x+y)) == "Lambda((x, y), x + y)" assert str(Lambda(((x, y),), x+y)) == "Lambda(((x, y),), x + y)" def test_Limit(): assert str(Limit(sin(x)/x, x, y)) == "Limit(sin(x)/x, x, y)" assert str(Limit(1/x, x, 0)) == "Limit(1/x, x, 0)" assert str( Limit(sin(x)/x, x, y, dir="-")) == "Limit(sin(x)/x, x, y, dir='-')" def test_list(): assert str([x]) == sstr([x]) == "[x]" assert str([x**2, x*y + 1]) == sstr([x**2, x*y + 1]) == "[x**2, x*y + 1]" assert str([x**2, [y + x]]) == sstr([x**2, [y + x]]) == "[x**2, [x + y]]" def test_Matrix_str(): M = Matrix([[x**+1, 1], [y, x + y]]) assert str(M) == "Matrix([[x, 1], [y, x + y]])" assert sstr(M) == "Matrix([\n[x, 1],\n[y, x + y]])" M = Matrix([[1]]) assert str(M) == sstr(M) == "Matrix([[1]])" M = Matrix([[1, 2]]) assert str(M) == sstr(M) == "Matrix([[1, 2]])" M = Matrix() assert str(M) == sstr(M) == "Matrix(0, 0, [])" M = Matrix(0, 1, lambda i, j: 0) assert str(M) == sstr(M) == "Matrix(0, 1, [])" def test_Mul(): assert str(x/y) == "x/y" assert str(y/x) == "y/x" assert str(x/y/z) == "x/(y*z)" assert str((x + 1)/(y + 2)) == "(x + 1)/(y + 2)" assert str(2*x/3) == '2*x/3' assert str(-2*x/3) == '-2*x/3' assert str(-1.0*x) == '-1.0*x' assert str(1.0*x) == '1.0*x' assert str(Mul(0, 1, evaluate=False)) == '0*1' assert str(Mul(1, 0, evaluate=False)) == '1*0' assert str(Mul(1, 1, evaluate=False)) == '1*1' assert str(Mul(1, 1, 1, evaluate=False)) == '1*1*1' assert str(Mul(1, 2, evaluate=False)) == '1*2' assert str(Mul(1, S.Half, evaluate=False)) == '1*(1/2)' assert str(Mul(1, 1, S.Half, evaluate=False)) == '1*1*(1/2)' assert str(Mul(1, 1, 2, 3, x, evaluate=False)) == '1*1*2*3*x' assert str(Mul(1, -1, evaluate=False)) == '1*(-1)' assert str(Mul(-1, 1, evaluate=False)) == '-1*1' assert str(Mul(4, 3, 2, 1, 0, y, x, evaluate=False)) == '4*3*2*1*0*y*x' assert str(Mul(4, 3, 2, 1+z, 0, y, x, evaluate=False)) == '4*3*2*(z + 1)*0*y*x' assert str(Mul(Rational(2, 3), Rational(5, 7), evaluate=False)) == '(2/3)*(5/7)' # For issue 14160 assert str(Mul(-2, x, Pow(Mul(y,y,evaluate=False), -1, evaluate=False), evaluate=False)) == '-2*x/(y*y)' # issue 21537 assert str(Mul(x, Pow(1/y, -1, evaluate=False), evaluate=False)) == 'x/(1/y)' class CustomClass1(Expr): is_commutative = True class CustomClass2(Expr): is_commutative = True cc1 = CustomClass1() cc2 = CustomClass2() assert str(Rational(2)*cc1) == '2*CustomClass1()' assert str(cc1*Rational(2)) == '2*CustomClass1()' assert str(cc1*Float("1.5")) == '1.5*CustomClass1()' assert str(cc2*Rational(2)) == '2*CustomClass2()' assert str(cc2*Rational(2)*cc1) == '2*CustomClass1()*CustomClass2()' assert str(cc1*Rational(2)*cc2) == '2*CustomClass1()*CustomClass2()' def test_NaN(): assert str(nan) == "nan" def test_NegativeInfinity(): assert str(-oo) == "-oo" def test_Order(): assert str(O(x)) == "O(x)" assert str(O(x**2)) == "O(x**2)" assert str(O(x*y)) == "O(x*y, x, y)" assert str(O(x, x)) == "O(x)" assert str(O(x, (x, 0))) == "O(x)" assert str(O(x, (x, oo))) == "O(x, (x, oo))" assert str(O(x, x, y)) == "O(x, x, y)" assert str(O(x, x, y)) == "O(x, x, y)" assert str(O(x, (x, oo), (y, oo))) == "O(x, (x, oo), (y, oo))" def test_Permutation_Cycle(): from sympy.combinatorics import Permutation, Cycle # general principle: economically, canonically show all moved elements # and the size of the permutation. for p, s in [ (Cycle(), '()'), (Cycle(2), '(2)'), (Cycle(2, 1), '(1 2)'), (Cycle(1, 2)(5)(6, 7)(10), '(1 2)(6 7)(10)'), (Cycle(3, 4)(1, 2)(3, 4), '(1 2)(4)'), ]: assert sstr(p) == s for p, s in [ (Permutation([]), 'Permutation([])'), (Permutation([], size=1), 'Permutation([0])'), (Permutation([], size=2), 'Permutation([0, 1])'), (Permutation([], size=10), 'Permutation([], size=10)'), (Permutation([1, 0, 2]), 'Permutation([1, 0, 2])'), (Permutation([1, 0, 2, 3, 4, 5]), 'Permutation([1, 0], size=6)'), (Permutation([1, 0, 2, 3, 4, 5], size=10), 'Permutation([1, 0], size=10)'), ]: assert sstr(p, perm_cyclic=False) == s for p, s in [ (Permutation([]), '()'), (Permutation([], size=1), '(0)'), (Permutation([], size=2), '(1)'), (Permutation([], size=10), '(9)'), (Permutation([1, 0, 2]), '(2)(0 1)'), (Permutation([1, 0, 2, 3, 4, 5]), '(5)(0 1)'), (Permutation([1, 0, 2, 3, 4, 5], size=10), '(9)(0 1)'), (Permutation([0, 1, 3, 2, 4, 5], size=10), '(9)(2 3)'), ]: assert sstr(p) == s def test_Pi(): assert str(pi) == "pi" def test_Poly(): assert str(Poly(0, x)) == "Poly(0, x, domain='ZZ')" assert str(Poly(1, x)) == "Poly(1, x, domain='ZZ')" assert str(Poly(x, x)) == "Poly(x, x, domain='ZZ')" assert str(Poly(2*x + 1, x)) == "Poly(2*x + 1, x, domain='ZZ')" assert str(Poly(2*x - 1, x)) == "Poly(2*x - 1, x, domain='ZZ')" assert str(Poly(-1, x)) == "Poly(-1, x, domain='ZZ')" assert str(Poly(-x, x)) == "Poly(-x, x, domain='ZZ')" assert str(Poly(-2*x + 1, x)) == "Poly(-2*x + 1, x, domain='ZZ')" assert str(Poly(-2*x - 1, x)) == "Poly(-2*x - 1, x, domain='ZZ')" assert str(Poly(x - 1, x)) == "Poly(x - 1, x, domain='ZZ')" assert str(Poly(2*x + x**5, x)) == "Poly(x**5 + 2*x, x, domain='ZZ')" assert str(Poly(3**(2*x), 3**x)) == "Poly((3**x)**2, 3**x, domain='ZZ')" assert str(Poly((x**2)**x)) == "Poly(((x**2)**x), (x**2)**x, domain='ZZ')" assert str(Poly((x + y)**3, (x + y), expand=False) ) == "Poly((x + y)**3, x + y, domain='ZZ')" assert str(Poly((x - 1)**2, (x - 1), expand=False) ) == "Poly((x - 1)**2, x - 1, domain='ZZ')" assert str( Poly(x**2 + 1 + y, x)) == "Poly(x**2 + y + 1, x, domain='ZZ[y]')" assert str( Poly(x**2 - 1 + y, x)) == "Poly(x**2 + y - 1, x, domain='ZZ[y]')" assert str(Poly(x**2 + I*x, x)) == "Poly(x**2 + I*x, x, domain='ZZ_I')" assert str(Poly(x**2 - I*x, x)) == "Poly(x**2 - I*x, x, domain='ZZ_I')" assert str(Poly(-x*y*z + x*y - 1, x, y, z) ) == "Poly(-x*y*z + x*y - 1, x, y, z, domain='ZZ')" assert str(Poly(-w*x**21*y**7*z + (1 + w)*z**3 - 2*x*z + 1, x, y, z)) == \ "Poly(-w*x**21*y**7*z - 2*x*z + (w + 1)*z**3 + 1, x, y, z, domain='ZZ[w]')" assert str(Poly(x**2 + 1, x, modulus=2)) == "Poly(x**2 + 1, x, modulus=2)" assert str(Poly(2*x**2 + 3*x + 4, x, modulus=17)) == "Poly(2*x**2 + 3*x + 4, x, modulus=17)" def test_PolyRing(): assert str(ring("x", ZZ, lex)[0]) == "Polynomial ring in x over ZZ with lex order" assert str(ring("x,y", QQ, grlex)[0]) == "Polynomial ring in x, y over QQ with grlex order" assert str(ring("x,y,z", ZZ["t"], lex)[0]) == "Polynomial ring in x, y, z over ZZ[t] with lex order" def test_FracField(): assert str(field("x", ZZ, lex)[0]) == "Rational function field in x over ZZ with lex order" assert str(field("x,y", QQ, grlex)[0]) == "Rational function field in x, y over QQ with grlex order" assert str(field("x,y,z", ZZ["t"], lex)[0]) == "Rational function field in x, y, z over ZZ[t] with lex order" def test_PolyElement(): Ruv, u,v = ring("u,v", ZZ) Rxyz, x,y,z = ring("x,y,z", Ruv) Rx_zzi, xz = ring("x", ZZ_I) assert str(x - x) == "0" assert str(x - 1) == "x - 1" assert str(x + 1) == "x + 1" assert str(x**2) == "x**2" assert str(x**(-2)) == "x**(-2)" assert str(x**QQ(1, 2)) == "x**(1/2)" assert str((u**2 + 3*u*v + 1)*x**2*y + u + 1) == "(u**2 + 3*u*v + 1)*x**2*y + u + 1" assert str((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x) == "(u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x" assert str((u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1) == "(u**2 + 3*u*v + 1)*x**2*y + (u + 1)*x + 1" assert str((-u**2 + 3*u*v - 1)*x**2*y - (u + 1)*x - 1) == "-(u**2 - 3*u*v + 1)*x**2*y - (u + 1)*x - 1" assert str(-(v**2 + v + 1)*x + 3*u*v + 1) == "-(v**2 + v + 1)*x + 3*u*v + 1" assert str(-(v**2 + v + 1)*x - 3*u*v + 1) == "-(v**2 + v + 1)*x - 3*u*v + 1" assert str((1+I)*xz + 2) == "(1 + 1*I)*x + (2 + 0*I)" def test_FracElement(): Fuv, u,v = field("u,v", ZZ) Fxyzt, x,y,z,t = field("x,y,z,t", Fuv) Rx_zzi, xz = field("x", QQ_I) i = QQ_I(0, 1) assert str(x - x) == "0" assert str(x - 1) == "x - 1" assert str(x + 1) == "x + 1" assert str(x/3) == "x/3" assert str(x/z) == "x/z" assert str(x*y/z) == "x*y/z" assert str(x/(z*t)) == "x/(z*t)" assert str(x*y/(z*t)) == "x*y/(z*t)" assert str((x - 1)/y) == "(x - 1)/y" assert str((x + 1)/y) == "(x + 1)/y" assert str((-x - 1)/y) == "(-x - 1)/y" assert str((x + 1)/(y*z)) == "(x + 1)/(y*z)" assert str(-y/(x + 1)) == "-y/(x + 1)" assert str(y*z/(x + 1)) == "y*z/(x + 1)" assert str(((u + 1)*x*y + 1)/((v - 1)*z - 1)) == "((u + 1)*x*y + 1)/((v - 1)*z - 1)" assert str(((u + 1)*x*y + 1)/((v - 1)*z - t*u*v - 1)) == "((u + 1)*x*y + 1)/((v - 1)*z - u*v*t - 1)" assert str((1+i)/xz) == "(1 + 1*I)/x" assert str(((1+i)*xz - i)/xz) == "((1 + 1*I)*x + (0 + -1*I))/x" def test_GaussianInteger(): assert str(ZZ_I(1, 0)) == "1" assert str(ZZ_I(-1, 0)) == "-1" assert str(ZZ_I(0, 1)) == "I" assert str(ZZ_I(0, -1)) == "-I" assert str(ZZ_I(0, 2)) == "2*I" assert str(ZZ_I(0, -2)) == "-2*I" assert str(ZZ_I(1, 1)) == "1 + I" assert str(ZZ_I(-1, -1)) == "-1 - I" assert str(ZZ_I(-1, -2)) == "-1 - 2*I" def test_GaussianRational(): assert str(QQ_I(1, 0)) == "1" assert str(QQ_I(QQ(2, 3), 0)) == "2/3" assert str(QQ_I(0, QQ(2, 3))) == "2*I/3" assert str(QQ_I(QQ(1, 2), QQ(-2, 3))) == "1/2 - 2*I/3" def test_Pow(): assert str(x**-1) == "1/x" assert str(x**-2) == "x**(-2)" assert str(x**2) == "x**2" assert str((x + y)**-1) == "1/(x + y)" assert str((x + y)**-2) == "(x + y)**(-2)" assert str((x + y)**2) == "(x + y)**2" assert str((x + y)**(1 + x)) == "(x + y)**(x + 1)" assert str(x**Rational(1, 3)) == "x**(1/3)" assert str(1/x**Rational(1, 3)) == "x**(-1/3)" assert str(sqrt(sqrt(x))) == "x**(1/4)" # not the same as x**-1 assert str(x**-1.0) == 'x**(-1.0)' # see issue #2860 assert str(Pow(S(2), -1.0, evaluate=False)) == '2**(-1.0)' def test_sqrt(): assert str(sqrt(x)) == "sqrt(x)" assert str(sqrt(x**2)) == "sqrt(x**2)" assert str(1/sqrt(x)) == "1/sqrt(x)" assert str(1/sqrt(x**2)) == "1/sqrt(x**2)" assert str(y/sqrt(x)) == "y/sqrt(x)" assert str(x**0.5) == "x**0.5" assert str(1/x**0.5) == "x**(-0.5)" def test_Rational(): n1 = Rational(1, 4) n2 = Rational(1, 3) n3 = Rational(2, 4) n4 = Rational(2, -4) n5 = Rational(0) n7 = Rational(3) n8 = Rational(-3) assert str(n1*n2) == "1/12" assert str(n1*n2) == "1/12" assert str(n3) == "1/2" assert str(n1*n3) == "1/8" assert str(n1 + n3) == "3/4" assert str(n1 + n2) == "7/12" assert str(n1 + n4) == "-1/4" assert str(n4*n4) == "1/4" assert str(n4 + n2) == "-1/6" assert str(n4 + n5) == "-1/2" assert str(n4*n5) == "0" assert str(n3 + n4) == "0" assert str(n1**n7) == "1/64" assert str(n2**n7) == "1/27" assert str(n2**n8) == "27" assert str(n7**n8) == "1/27" assert str(Rational("-25")) == "-25" assert str(Rational("1.25")) == "5/4" assert str(Rational("-2.6e-2")) == "-13/500" assert str(S("25/7")) == "25/7" assert str(S("-123/569")) == "-123/569" assert str(S("0.1[23]", rational=1)) == "61/495" assert str(S("5.1[666]", rational=1)) == "31/6" assert str(S("-5.1[666]", rational=1)) == "-31/6" assert str(S("0.[9]", rational=1)) == "1" assert str(S("-0.[9]", rational=1)) == "-1" assert str(sqrt(Rational(1, 4))) == "1/2" assert str(sqrt(Rational(1, 36))) == "1/6" assert str((123**25) ** Rational(1, 25)) == "123" assert str((123**25 + 1)**Rational(1, 25)) != "123" assert str((123**25 - 1)**Rational(1, 25)) != "123" assert str((123**25 - 1)**Rational(1, 25)) != "122" assert str(sqrt(Rational(81, 36))**3) == "27/8" assert str(1/sqrt(Rational(81, 36))**3) == "8/27" assert str(sqrt(-4)) == str(2*I) assert str(2**Rational(1, 10**10)) == "2**(1/10000000000)" assert sstr(Rational(2, 3), sympy_integers=True) == "S(2)/3" x = Symbol("x") assert sstr(x**Rational(2, 3), sympy_integers=True) == "x**(S(2)/3)" assert sstr(Eq(x, Rational(2, 3)), sympy_integers=True) == "Eq(x, S(2)/3)" assert sstr(Limit(x, x, Rational(7, 2)), sympy_integers=True) == \ "Limit(x, x, S(7)/2)" def test_Float(): # NOTE dps is the whole number of decimal digits assert str(Float('1.23', dps=1 + 2)) == '1.23' assert str(Float('1.23456789', dps=1 + 8)) == '1.23456789' assert str( Float('1.234567890123456789', dps=1 + 18)) == '1.234567890123456789' assert str(pi.evalf(1 + 2)) == '3.14' assert str(pi.evalf(1 + 14)) == '3.14159265358979' assert str(pi.evalf(1 + 64)) == ('3.141592653589793238462643383279' '5028841971693993751058209749445923') assert str(pi.round(-1)) == '0.0' assert str((pi**400 - (pi**400).round(1)).n(2)) == '-0.e+88' assert sstr(Float("100"), full_prec=False, min=-2, max=2) == '1.0e+2' assert sstr(Float("100"), full_prec=False, min=-2, max=3) == '100.0' assert sstr(Float("0.1"), full_prec=False, min=-2, max=3) == '0.1' assert sstr(Float("0.099"), min=-2, max=3) == '9.90000000000000e-2' def test_Relational(): assert str(Rel(x, y, "<")) == "x < y" assert str(Rel(x + y, y, "==")) == "Eq(x + y, y)" assert str(Rel(x, y, "!=")) == "Ne(x, y)" assert str(Eq(x, 1) | Eq(x, 2)) == "Eq(x, 1) | Eq(x, 2)" assert str(Ne(x, 1) & Ne(x, 2)) == "Ne(x, 1) & Ne(x, 2)" def test_AppliedBinaryRelation(): assert str(Q.eq(x, y)) == "Q.eq(x, y)" assert str(Q.ne(x, y)) == "Q.ne(x, y)" def test_CRootOf(): assert str(rootof(x**5 + 2*x - 1, 0)) == "CRootOf(x**5 + 2*x - 1, 0)" def test_RootSum(): f = x**5 + 2*x - 1 assert str( RootSum(f, Lambda(z, z), auto=False)) == "RootSum(x**5 + 2*x - 1)" assert str(RootSum(f, Lambda( z, z**2), auto=False)) == "RootSum(x**5 + 2*x - 1, Lambda(z, z**2))" def test_GroebnerBasis(): assert str(groebner( [], x, y)) == "GroebnerBasis([], x, y, domain='ZZ', order='lex')" F = [x**2 - 3*y - x + 1, y**2 - 2*x + y - 1] assert str(groebner(F, order='grlex')) == \ "GroebnerBasis([x**2 - x - 3*y + 1, y**2 - 2*x + y - 1], x, y, domain='ZZ', order='grlex')" assert str(groebner(F, order='lex')) == \ "GroebnerBasis([2*x - y**2 - y + 1, y**4 + 2*y**3 - 3*y**2 - 16*y + 7], x, y, domain='ZZ', order='lex')" def test_set(): assert sstr(set()) == 'set()' assert sstr(frozenset()) == 'frozenset()' assert sstr({1}) == '{1}' assert sstr(frozenset([1])) == 'frozenset({1})' assert sstr({1, 2, 3}) == '{1, 2, 3}' assert sstr(frozenset([1, 2, 3])) == 'frozenset({1, 2, 3})' assert sstr( {1, x, x**2, x**3, x**4}) == '{1, x, x**2, x**3, x**4}' assert sstr( frozenset([1, x, x**2, x**3, x**4])) == 'frozenset({1, x, x**2, x**3, x**4})' def test_SparseMatrix(): M = SparseMatrix([[x**+1, 1], [y, x + y]]) assert str(M) == "Matrix([[x, 1], [y, x + y]])" assert sstr(M) == "Matrix([\n[x, 1],\n[y, x + y]])" def test_Sum(): assert str(summation(cos(3*z), (z, x, y))) == "Sum(cos(3*z), (z, x, y))" assert str(Sum(x*y**2, (x, -2, 2), (y, -5, 5))) == \ "Sum(x*y**2, (x, -2, 2), (y, -5, 5))" def test_Symbol(): assert str(y) == "y" assert str(x) == "x" e = x assert str(e) == "x" def test_tuple(): assert str((x,)) == sstr((x,)) == "(x,)" assert str((x + y, 1 + x)) == sstr((x + y, 1 + x)) == "(x + y, x + 1)" assert str((x + y, ( 1 + x, x**2))) == sstr((x + y, (1 + x, x**2))) == "(x + y, (x + 1, x**2))" def test_Series_str(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y) assert str(Series(tf1, tf2)) == \ "Series(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y))" assert str(Series(tf1, tf2, tf3)) == \ "Series(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y), TransferFunction(t*x**2 - t**w*x + w, t - y, y))" assert str(Series(-tf2, tf1)) == \ "Series(TransferFunction(-x + y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y))" def test_MIMOSeries_str(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) assert str(MIMOSeries(tfm_1, tfm_2)) == \ "MIMOSeries(TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), "\ "(TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)))), "\ "TransferFunctionMatrix(((TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)), "\ "(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)))))" def test_TransferFunction_str(): tf1 = TransferFunction(x - 1, x + 1, x) assert str(tf1) == "TransferFunction(x - 1, x + 1, x)" tf2 = TransferFunction(x + 1, 2 - y, x) assert str(tf2) == "TransferFunction(x + 1, 2 - y, x)" tf3 = TransferFunction(y, y**2 + 2*y + 3, y) assert str(tf3) == "TransferFunction(y, y**2 + 2*y + 3, y)" def test_Parallel_str(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y) assert str(Parallel(tf1, tf2)) == \ "Parallel(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y))" assert str(Parallel(tf1, tf2, tf3)) == \ "Parallel(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y), TransferFunction(t*x**2 - t**w*x + w, t - y, y))" assert str(Parallel(-tf2, tf1)) == \ "Parallel(TransferFunction(-x + y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y))" def test_MIMOParallel_str(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) tfm_1 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) tfm_2 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) assert str(MIMOParallel(tfm_1, tfm_2)) == \ "MIMOParallel(TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), "\ "(TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)))), "\ "TransferFunctionMatrix(((TransferFunction(x - y, x + y, y), TransferFunction(x*y**2 - z, -t**3 + y**3, y)), "\ "(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)))))" def test_Feedback_str(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y) assert str(Feedback(tf1*tf2, tf3)) == \ "Feedback(Series(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), " \ "TransferFunction(t*x**2 - t**w*x + w, t - y, y), -1)" assert str(Feedback(tf1, TransferFunction(1, 1, y), 1)) == \ "Feedback(TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(1, 1, y), 1)" def test_MIMOFeedback_str(): tf1 = TransferFunction(x**2 - y**3, y - z, x) tf2 = TransferFunction(y - x, z + y, x) tfm_1 = TransferFunctionMatrix([[tf2, tf1], [tf1, tf2]]) tfm_2 = TransferFunctionMatrix([[tf1, tf2], [tf2, tf1]]) assert (str(MIMOFeedback(tfm_1, tfm_2)) \ == "MIMOFeedback(TransferFunctionMatrix(((TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x))," \ " (TransferFunction(x**2 - y**3, y - z, x), TransferFunction(-x + y, y + z, x)))), " \ "TransferFunctionMatrix(((TransferFunction(x**2 - y**3, y - z, x), " \ "TransferFunction(-x + y, y + z, x)), (TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x)))), -1)") assert (str(MIMOFeedback(tfm_1, tfm_2, 1)) \ == "MIMOFeedback(TransferFunctionMatrix(((TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x)), " \ "(TransferFunction(x**2 - y**3, y - z, x), TransferFunction(-x + y, y + z, x)))), " \ "TransferFunctionMatrix(((TransferFunction(x**2 - y**3, y - z, x), TransferFunction(-x + y, y + z, x)), "\ "(TransferFunction(-x + y, y + z, x), TransferFunction(x**2 - y**3, y - z, x)))), 1)") def test_TransferFunctionMatrix_str(): tf1 = TransferFunction(x*y**2 - z, y**3 - t**3, y) tf2 = TransferFunction(x - y, x + y, y) tf3 = TransferFunction(t*x**2 - t**w*x + w, t - y, y) assert str(TransferFunctionMatrix([[tf1], [tf2]])) == \ "TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y),), (TransferFunction(x - y, x + y, y),)))" assert str(TransferFunctionMatrix([[tf1, tf2], [tf3, tf2]])) == \ "TransferFunctionMatrix(((TransferFunction(x*y**2 - z, -t**3 + y**3, y), TransferFunction(x - y, x + y, y)), (TransferFunction(t*x**2 - t**w*x + w, t - y, y), TransferFunction(x - y, x + y, y))))" def test_Quaternion_str_printer(): q = Quaternion(x, y, z, t) assert str(q) == "x + y*i + z*j + t*k" q = Quaternion(x,y,z,x*t) assert str(q) == "x + y*i + z*j + t*x*k" q = Quaternion(x,y,z,x+t) assert str(q) == "x + y*i + z*j + (t + x)*k" def test_Quantity_str(): assert sstr(second, abbrev=True) == "s" assert sstr(joule, abbrev=True) == "J" assert str(second) == "second" assert str(joule) == "joule" def test_wild_str(): # Check expressions containing Wild not causing infinite recursion w = Wild('x') assert str(w + 1) == 'x_ + 1' assert str(exp(2**w) + 5) == 'exp(2**x_) + 5' assert str(3*w + 1) == '3*x_ + 1' assert str(1/w + 1) == '1 + 1/x_' assert str(w**2 + 1) == 'x_**2 + 1' assert str(1/(1 - w)) == '1/(1 - x_)' def test_wild_matchpy(): from sympy.utilities.matchpy_connector import WildDot, WildPlus, WildStar matchpy = import_module("matchpy") if matchpy is None: return wd = WildDot('w_') wp = WildPlus('w__') ws = WildStar('w___') assert str(wd) == 'w_' assert str(wp) == 'w__' assert str(ws) == 'w___' assert str(wp/ws + 2**wd) == '2**w_ + w__/w___' assert str(sin(wd)*cos(wp)*sqrt(ws)) == 'sqrt(w___)*sin(w_)*cos(w__)' def test_zeta(): assert str(zeta(3)) == "zeta(3)" def test_issue_3101(): e = x - y a = str(e) b = str(e) assert a == b def test_issue_3103(): e = -2*sqrt(x) - y/sqrt(x)/2 assert str(e) not in ["(-2)*x**1/2(-1/2)*x**(-1/2)*y", "-2*x**1/2(-1/2)*x**(-1/2)*y", "-2*x**1/2-1/2*x**-1/2*w"] assert str(e) == "-2*sqrt(x) - y/(2*sqrt(x))" def test_issue_4021(): e = Integral(x, x) + 1 assert str(e) == 'Integral(x, x) + 1' def test_sstrrepr(): assert sstr('abc') == 'abc' assert sstrrepr('abc') == "'abc'" e = ['a', 'b', 'c', x] assert sstr(e) == "[a, b, c, x]" assert sstrrepr(e) == "['a', 'b', 'c', x]" def test_infinity(): assert sstr(oo*I) == "oo*I" def test_full_prec(): assert sstr(S("0.3"), full_prec=True) == "0.300000000000000" assert sstr(S("0.3"), full_prec="auto") == "0.300000000000000" assert sstr(S("0.3"), full_prec=False) == "0.3" assert sstr(S("0.3")*x, full_prec=True) in [ "0.300000000000000*x", "x*0.300000000000000" ] assert sstr(S("0.3")*x, full_prec="auto") in [ "0.3*x", "x*0.3" ] assert sstr(S("0.3")*x, full_prec=False) in [ "0.3*x", "x*0.3" ] def test_noncommutative(): A, B, C = symbols('A,B,C', commutative=False) assert sstr(A*B*C**-1) == "A*B*C**(-1)" assert sstr(C**-1*A*B) == "C**(-1)*A*B" assert sstr(A*C**-1*B) == "A*C**(-1)*B" assert sstr(sqrt(A)) == "sqrt(A)" assert sstr(1/sqrt(A)) == "A**(-1/2)" def test_empty_printer(): str_printer = StrPrinter() assert str_printer.emptyPrinter("foo") == "foo" assert str_printer.emptyPrinter(x*y) == "x*y" assert str_printer.emptyPrinter(32) == "32" def test_settings(): raises(TypeError, lambda: sstr(S(4), method="garbage")) def test_RandomDomain(): from sympy.stats import Normal, Die, Exponential, pspace, where X = Normal('x1', 0, 1) assert str(where(X > 0)) == "Domain: (0 < x1) & (x1 < oo)" D = Die('d1', 6) assert str(where(D > 4)) == "Domain: Eq(d1, 5) | Eq(d1, 6)" A = Exponential('a', 1) B = Exponential('b', 1) assert str(pspace(Tuple(A, B)).domain) == "Domain: (0 <= a) & (0 <= b) & (a < oo) & (b < oo)" def test_FiniteSet(): assert str(FiniteSet(*range(1, 51))) == ( '{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, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50}' ) assert str(FiniteSet(*range(1, 6))) == '{1, 2, 3, 4, 5}' assert str(FiniteSet(*[x*y, x**2])) == '{x**2, x*y}' assert str(FiniteSet(FiniteSet(FiniteSet(x, y), 5), FiniteSet(x,y), 5) ) == 'FiniteSet(5, FiniteSet(5, {x, y}), {x, y})' def test_Partition(): assert str(Partition(FiniteSet(x, y), {z})) == 'Partition({z}, {x, y})' def test_UniversalSet(): assert str(S.UniversalSet) == 'UniversalSet' def test_PrettyPoly(): from sympy.polys.domains import QQ F = QQ.frac_field(x, y) R = QQ[x, y] assert sstr(F.convert(x/(x + y))) == sstr(x/(x + y)) assert sstr(R.convert(x + y)) == sstr(x + y) def test_categories(): from sympy.categories import (Object, NamedMorphism, IdentityMorphism, Category) A = Object("A") B = Object("B") f = NamedMorphism(A, B, "f") id_A = IdentityMorphism(A) K = Category("K") assert str(A) == 'Object("A")' assert str(f) == 'NamedMorphism(Object("A"), Object("B"), "f")' assert str(id_A) == 'IdentityMorphism(Object("A"))' assert str(K) == 'Category("K")' def test_Tr(): A, B = symbols('A B', commutative=False) t = Tr(A*B) assert str(t) == 'Tr(A*B)' def test_issue_6387(): assert str(factor(-3.0*z + 3)) == '-3.0*(1.0*z - 1.0)' def test_MatMul_MatAdd(): from sympy import MatrixSymbol X, Y = MatrixSymbol("X", 2, 2), MatrixSymbol("Y", 2, 2) assert str(2*(X + Y)) == "2*X + 2*Y" assert str(I*X) == "I*X" assert str(-I*X) == "-I*X" assert str((1 + I)*X) == '(1 + I)*X' assert str(-(1 + I)*X) == '(-1 - I)*X' def test_MatrixSlice(): n = Symbol('n', integer=True) X = MatrixSymbol('X', n, n) Y = MatrixSymbol('Y', 10, 10) Z = MatrixSymbol('Z', 10, 10) assert str(MatrixSlice(X, (None, None, None), (None, None, None))) == 'X[:, :]' assert str(X[x:x + 1, y:y + 1]) == 'X[x:x + 1, y:y + 1]' assert str(X[x:x + 1:2, y:y + 1:2]) == 'X[x:x + 1:2, y:y + 1:2]' assert str(X[:x, y:]) == 'X[:x, y:]' assert str(X[:x, y:]) == 'X[:x, y:]' assert str(X[x:, :y]) == 'X[x:, :y]' assert str(X[x:y, z:w]) == 'X[x:y, z:w]' assert str(X[x:y:t, w:t:x]) == 'X[x:y:t, w:t:x]' assert str(X[x::y, t::w]) == 'X[x::y, t::w]' assert str(X[:x:y, :t:w]) == 'X[:x:y, :t:w]' assert str(X[::x, ::y]) == 'X[::x, ::y]' assert str(MatrixSlice(X, (0, None, None), (0, None, None))) == 'X[:, :]' assert str(MatrixSlice(X, (None, n, None), (None, n, None))) == 'X[:, :]' assert str(MatrixSlice(X, (0, n, None), (0, n, None))) == 'X[:, :]' assert str(MatrixSlice(X, (0, n, 2), (0, n, 2))) == 'X[::2, ::2]' assert str(X[1:2:3, 4:5:6]) == 'X[1:2:3, 4:5:6]' assert str(X[1:3:5, 4:6:8]) == 'X[1:3:5, 4:6:8]' assert str(X[1:10:2]) == 'X[1:10:2, :]' assert str(Y[:5, 1:9:2]) == 'Y[:5, 1:9:2]' assert str(Y[:5, 1:10:2]) == 'Y[:5, 1::2]' assert str(Y[5, :5:2]) == 'Y[5:6, :5:2]' assert str(X[0:1, 0:1]) == 'X[:1, :1]' assert str(X[0:1:2, 0:1:2]) == 'X[:1:2, :1:2]' assert str((Y + Z)[2:, 2:]) == '(Y + Z)[2:, 2:]' def test_true_false(): assert str(true) == repr(true) == sstr(true) == "True" assert str(false) == repr(false) == sstr(false) == "False" def test_Equivalent(): assert str(Equivalent(y, x)) == "Equivalent(x, y)" def test_Xor(): assert str(Xor(y, x, evaluate=False)) == "x ^ y" def test_Complement(): assert str(Complement(S.Reals, S.Naturals)) == 'Complement(Reals, Naturals)' def test_SymmetricDifference(): assert str(SymmetricDifference(Interval(2, 3), Interval(3, 4),evaluate=False)) == \ 'SymmetricDifference(Interval(2, 3), Interval(3, 4))' def test_UnevaluatedExpr(): a, b = symbols("a b") expr1 = 2*UnevaluatedExpr(a+b) assert str(expr1) == "2*(a + b)" def test_MatrixElement_printing(): # test cases for issue #11821 A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert(str(A[0, 0]) == "A[0, 0]") assert(str(3 * A[0, 0]) == "3*A[0, 0]") F = C[0, 0].subs(C, A - B) assert str(F) == "(A - B)[0, 0]" def test_MatrixSymbol_printing(): A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) assert str(A - A*B - B) == "A - A*B - B" assert str(A*B - (A+B)) == "-A + A*B - B" assert str(A**(-1)) == "A**(-1)" assert str(A**3) == "A**3" def test_MatrixExpressions(): n = Symbol('n', integer=True) X = MatrixSymbol('X', n, n) assert str(X) == "X" # Apply function elementwise (`ElementwiseApplyFunc`): expr = (X.T*X).applyfunc(sin) assert str(expr) == 'Lambda(_d, sin(_d)).(X.T*X)' lamda = Lambda(x, 1/x) expr = (n*X).applyfunc(lamda) assert str(expr) == 'Lambda(x, 1/x).(n*X)' def test_Subs_printing(): assert str(Subs(x, (x,), (1,))) == 'Subs(x, x, 1)' assert str(Subs(x + y, (x, y), (1, 2))) == 'Subs(x + y, (x, y), (1, 2))' def test_issue_15716(): e = Integral(factorial(x), (x, -oo, oo)) assert e.as_terms() == ([(e, ((1.0, 0.0), (1,), ()))], [e]) def test_str_special_matrices(): from sympy.matrices import Identity, ZeroMatrix, OneMatrix assert str(Identity(4)) == 'I' assert str(ZeroMatrix(2, 2)) == '0' assert str(OneMatrix(2, 2)) == '1' def test_issue_14567(): assert factorial(Sum(-1, (x, 0, 0))) + y # doesn't raise an error def test_issue_21823(): assert str(Partition([1, 2])) == 'Partition({1, 2})' assert str(Partition({1, 2})) == 'Partition({1, 2})' def test_issue_21119_21460(): ss = lambda x: str(S(x, evaluate=False)) assert ss('4/2') == '4/2' assert ss('4/-2') == '4/(-2)' assert ss('-4/2') == '-4/2' assert ss('-4/-2') == '-4/(-2)' assert ss('-2*3/-1') == '-2*3/(-1)' assert ss('-2*3/-1/2') == '-2*3/(-1*2)' assert ss('4/2/1') == '4/(2*1)' assert ss('-2/-1/2') == '-2/(-1*2)' assert ss('2*3*4**(-2*3)') == '2*3/4**(2*3)' assert ss('2*3*1*4**(-2*3)') == '2*3*1/4**(2*3)' def test_Str(): from sympy.core.symbol import Str assert str(Str('x')) == 'x' assert sstrrepr(Str('x')) == "Str('x')" def test_diffgeom(): from sympy.diffgeom import Manifold, Patch, CoordSystem, BaseScalarField x,y = symbols('x y', real=True) m = Manifold('M', 2) assert str(m) == "M" p = Patch('P', m) assert str(p) == "P" rect = CoordSystem('rect', p, [x, y]) assert str(rect) == "rect" b = BaseScalarField(rect, 0) assert str(b) == "x" def test_NDimArray(): assert sstr(NDimArray(1.0), full_prec=True) == '1.00000000000000' assert sstr(NDimArray(1.0), full_prec=False) == '1.0' assert sstr(NDimArray([1.0, 2.0]), full_prec=True) == '[1.00000000000000, 2.00000000000000]' assert sstr(NDimArray([1.0, 2.0]), full_prec=False) == '[1.0, 2.0]' def test_Predicate(): assert sstr(Q.even) == 'Q.even' def test_AppliedPredicate(): assert sstr(Q.even(x)) == 'Q.even(x)' def test_printing_str_array_expressions(): assert sstr(ArraySymbol("A", 2, 3, 4)) == "A" assert sstr(ArrayElement("A", (2, 1/(1-x), 0))) == "A[2, 1/(1 - x), 0]" sympy-sympy-1.9/sympy/printing/tests/test_tableform.py000066400000000000000000000130111412543434000234600ustar00rootroot00000000000000from sympy import TableForm, S from sympy.printing.latex import latex from sympy.abc import x from sympy.functions.elementary.miscellaneous import sqrt from sympy.functions.elementary.trigonometric import sin from sympy.testing.pytest import raises from textwrap import dedent def test_TableForm(): s = str(TableForm([["a", "b"], ["c", "d"], ["e", 0]], headings="automatic")) assert s == ( ' | 1 2\n' '-------\n' '1 | a b\n' '2 | c d\n' '3 | e ' ) s = str(TableForm([["a", "b"], ["c", "d"], ["e", 0]], headings="automatic", wipe_zeros=False)) assert s == dedent('''\ | 1 2 ------- 1 | a b 2 | c d 3 | e 0''') s = str(TableForm([[x**2, "b"], ["c", x**2], ["e", "f"]], headings=("automatic", None))) assert s == ( '1 | x**2 b \n' '2 | c x**2\n' '3 | e f ' ) s = str(TableForm([["a", "b"], ["c", "d"], ["e", "f"]], headings=(None, "automatic"))) assert s == dedent('''\ 1 2 --- a b c d e f''') s = str(TableForm([[5, 7], [4, 2], [10, 3]], headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]])) assert s == ( ' | y1 y2\n' '---------------\n' 'Group A | 5 7 \n' 'Group B | 4 2 \n' 'Group C | 10 3 ' ) raises( ValueError, lambda: TableForm( [[5, 7], [4, 2], [10, 3]], headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]], alignments="middle") ) s = str(TableForm([[5, 7], [4, 2], [10, 3]], headings=[["Group A", "Group B", "Group C"], ["y1", "y2"]], alignments="right")) assert s == dedent('''\ | y1 y2 --------------- Group A | 5 7 Group B | 4 2 Group C | 10 3''') # other alignment permutations d = [[1, 100], [100, 1]] s = TableForm(d, headings=(('xxx', 'x'), None), alignments='l') assert str(s) == ( 'xxx | 1 100\n' ' x | 100 1 ' ) s = TableForm(d, headings=(('xxx', 'x'), None), alignments='lr') assert str(s) == dedent('''\ xxx | 1 100 x | 100 1''') s = TableForm(d, headings=(('xxx', 'x'), None), alignments='clr') assert str(s) == dedent('''\ xxx | 1 100 x | 100 1''') s = TableForm(d, headings=(('xxx', 'x'), None)) assert str(s) == ( 'xxx | 1 100\n' ' x | 100 1 ' ) raises(ValueError, lambda: TableForm(d, alignments='clr')) #pad s = str(TableForm([[None, "-", 2], [1]], pad='?')) assert s == dedent('''\ ? - 2 1 ? ?''') def test_TableForm_latex(): s = latex(TableForm([[0, x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]], wipe_zeros=True, headings=("automatic", "automatic"))) assert s == ( '\\begin{tabular}{r l l}\n' ' & 1 & 2 \\\\\n' '\\hline\n' '1 & & $x^{3}$ \\\\\n' '2 & $c$ & $\\frac{1}{4}$ \\\\\n' '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n' '\\end{tabular}' ) s = latex(TableForm([[0, x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]], wipe_zeros=True, headings=("automatic", "automatic"), alignments='l')) assert s == ( '\\begin{tabular}{r l l}\n' ' & 1 & 2 \\\\\n' '\\hline\n' '1 & & $x^{3}$ \\\\\n' '2 & $c$ & $\\frac{1}{4}$ \\\\\n' '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n' '\\end{tabular}' ) s = latex(TableForm([[0, x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]], wipe_zeros=True, headings=("automatic", "automatic"), alignments='l'*3)) assert s == ( '\\begin{tabular}{l l l}\n' ' & 1 & 2 \\\\\n' '\\hline\n' '1 & & $x^{3}$ \\\\\n' '2 & $c$ & $\\frac{1}{4}$ \\\\\n' '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n' '\\end{tabular}' ) s = latex(TableForm([["a", x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]], headings=("automatic", "automatic"))) assert s == ( '\\begin{tabular}{r l l}\n' ' & 1 & 2 \\\\\n' '\\hline\n' '1 & $a$ & $x^{3}$ \\\\\n' '2 & $c$ & $\\frac{1}{4}$ \\\\\n' '3 & $\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n' '\\end{tabular}' ) s = latex(TableForm([["a", x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]], formats=['(%s)', None], headings=("automatic", "automatic"))) assert s == ( '\\begin{tabular}{r l l}\n' ' & 1 & 2 \\\\\n' '\\hline\n' '1 & (a) & $x^{3}$ \\\\\n' '2 & (c) & $\\frac{1}{4}$ \\\\\n' '3 & (sqrt(x)) & $\\sin{\\left(x^{2} \\right)}$ \\\\\n' '\\end{tabular}' ) def neg_in_paren(x, i, j): if i % 2: return ('(%s)' if x < 0 else '%s') % x else: pass # use default print s = latex(TableForm([[-1, 2], [-3, 4]], formats=[neg_in_paren]*2, headings=("automatic", "automatic"))) assert s == ( '\\begin{tabular}{r l l}\n' ' & 1 & 2 \\\\\n' '\\hline\n' '1 & -1 & 2 \\\\\n' '2 & (-3) & 4 \\\\\n' '\\end{tabular}' ) s = latex(TableForm([["a", x**3], ["c", S.One/4], [sqrt(x), sin(x**2)]])) assert s == ( '\\begin{tabular}{l l}\n' '$a$ & $x^{3}$ \\\\\n' '$c$ & $\\frac{1}{4}$ \\\\\n' '$\\sqrt{x}$ & $\\sin{\\left(x^{2} \\right)}$ \\\\\n' '\\end{tabular}' ) sympy-sympy-1.9/sympy/printing/tests/test_tensorflow.py000066400000000000000000000363671412543434000237320ustar00rootroot00000000000000import random from sympy import symbols, Derivative from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayAdd, \ PermuteDims, ArrayDiagonal from sympy.core.relational import Eq, Ne, Ge, Gt, Le, Lt from sympy.external import import_module from sympy.functions import \ Abs, ceiling, exp, floor, sign, sin, asin, sqrt, cos, \ acos, tan, atan, atan2, cosh, acosh, sinh, asinh, tanh, atanh, \ re, im, arg, erf, loggamma, log from sympy.matrices import Matrix, MatrixBase, eye, randMatrix from sympy.matrices.expressions import \ Determinant, HadamardProduct, Inverse, MatrixSymbol, Trace from sympy.printing.tensorflow import tensorflow_code from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array from sympy.utilities.lambdify import lambdify from sympy.testing.pytest import skip from sympy.testing.pytest import XFAIL tf = tensorflow = import_module("tensorflow") if tensorflow: # Hide Tensorflow warnings import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' M = MatrixSymbol("M", 3, 3) N = MatrixSymbol("N", 3, 3) P = MatrixSymbol("P", 3, 3) Q = MatrixSymbol("Q", 3, 3) x, y, z, t = symbols("x y z t") if tf is not None: llo = [[j for j in range(i, i+3)] for i in range(0, 9, 3)] m3x3 = tf.constant(llo) m3x3sympy = Matrix(llo) def _compare_tensorflow_matrix(variables, expr, use_float=False): f = lambdify(variables, expr, 'tensorflow') if not use_float: random_matrices = [randMatrix(v.rows, v.cols) for v in variables] else: random_matrices = [randMatrix(v.rows, v.cols)/100. for v in variables] graph = tf.Graph() r = None with graph.as_default(): random_variables = [eval(tensorflow_code(i)) for i in random_matrices] session = tf.compat.v1.Session(graph=graph) r = session.run(f(*random_variables)) e = expr.subs({k: v for k, v in zip(variables, random_matrices)}) e = e.doit() if e.is_Matrix: if not isinstance(e, MatrixBase): e = e.as_explicit() e = e.tolist() if not use_float: assert (r == e).all() else: r = [i for row in r for i in row] e = [i for row in e for i in row] assert all( abs(a-b) < 10**-(4-int(log(abs(a), 10))) for a, b in zip(r, e)) # Creating a custom inverse test. # See https://github.com/sympy/sympy/issues/18469 def _compare_tensorflow_matrix_inverse(variables, expr, use_float=False): f = lambdify(variables, expr, 'tensorflow') if not use_float: random_matrices = [eye(v.rows, v.cols)*4 for v in variables] else: random_matrices = [eye(v.rows, v.cols)*3.14 for v in variables] graph = tf.Graph() r = None with graph.as_default(): random_variables = [eval(tensorflow_code(i)) for i in random_matrices] session = tf.compat.v1.Session(graph=graph) r = session.run(f(*random_variables)) e = expr.subs({k: v for k, v in zip(variables, random_matrices)}) e = e.doit() if e.is_Matrix: if not isinstance(e, MatrixBase): e = e.as_explicit() e = e.tolist() if not use_float: assert (r == e).all() else: r = [i for row in r for i in row] e = [i for row in e for i in row] assert all( abs(a-b) < 10**-(4-int(log(abs(a), 10))) for a, b in zip(r, e)) def _compare_tensorflow_matrix_scalar(variables, expr): f = lambdify(variables, expr, 'tensorflow') random_matrices = [ randMatrix(v.rows, v.cols).evalf() / 100 for v in variables] graph = tf.Graph() r = None with graph.as_default(): random_variables = [eval(tensorflow_code(i)) for i in random_matrices] session = tf.compat.v1.Session(graph=graph) r = session.run(f(*random_variables)) e = expr.subs({k: v for k, v in zip(variables, random_matrices)}) e = e.doit() assert abs(r-e) < 10**-6 def _compare_tensorflow_scalar( variables, expr, rng=lambda: random.randint(0, 10)): f = lambdify(variables, expr, 'tensorflow') rvs = [rng() for v in variables] graph = tf.Graph() r = None with graph.as_default(): tf_rvs = [eval(tensorflow_code(i)) for i in rvs] session = tf.compat.v1.Session(graph=graph) r = session.run(f(*tf_rvs)) e = expr.subs({k: v for k, v in zip(variables, rvs)}).evalf().doit() assert abs(r-e) < 10**-6 def _compare_tensorflow_relational( variables, expr, rng=lambda: random.randint(0, 10)): f = lambdify(variables, expr, 'tensorflow') rvs = [rng() for v in variables] graph = tf.Graph() r = None with graph.as_default(): tf_rvs = [eval(tensorflow_code(i)) for i in rvs] session = tf.compat.v1.Session(graph=graph) r = session.run(f(*tf_rvs)) e = expr.subs({k: v for k, v in zip(variables, rvs)}).doit() assert r == e def test_tensorflow_printing(): assert tensorflow_code(eye(3)) == \ "tensorflow.constant([[1, 0, 0], [0, 1, 0], [0, 0, 1]])" expr = Matrix([[x, sin(y)], [exp(z), -t]]) assert tensorflow_code(expr) == \ "tensorflow.Variable(" \ "[[x, tensorflow.math.sin(y)]," \ " [tensorflow.math.exp(z), -t]])" # This (random) test is XFAIL because it fails occasionally # See https://github.com/sympy/sympy/issues/18469 @XFAIL def test_tensorflow_math(): if not tf: skip("TensorFlow not installed") expr = Abs(x) assert tensorflow_code(expr) == "tensorflow.math.abs(x)" _compare_tensorflow_scalar((x,), expr) expr = sign(x) assert tensorflow_code(expr) == "tensorflow.math.sign(x)" _compare_tensorflow_scalar((x,), expr) expr = ceiling(x) assert tensorflow_code(expr) == "tensorflow.math.ceil(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = floor(x) assert tensorflow_code(expr) == "tensorflow.math.floor(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = exp(x) assert tensorflow_code(expr) == "tensorflow.math.exp(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = sqrt(x) assert tensorflow_code(expr) == "tensorflow.math.sqrt(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = x ** 4 assert tensorflow_code(expr) == "tensorflow.math.pow(x, 4)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = cos(x) assert tensorflow_code(expr) == "tensorflow.math.cos(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = acos(x) assert tensorflow_code(expr) == "tensorflow.math.acos(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(0, 0.95)) expr = sin(x) assert tensorflow_code(expr) == "tensorflow.math.sin(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = asin(x) assert tensorflow_code(expr) == "tensorflow.math.asin(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = tan(x) assert tensorflow_code(expr) == "tensorflow.math.tan(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = atan(x) assert tensorflow_code(expr) == "tensorflow.math.atan(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = atan2(y, x) assert tensorflow_code(expr) == "tensorflow.math.atan2(y, x)" _compare_tensorflow_scalar((y, x), expr, rng=lambda: random.random()) expr = cosh(x) assert tensorflow_code(expr) == "tensorflow.math.cosh(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.random()) expr = acosh(x) assert tensorflow_code(expr) == "tensorflow.math.acosh(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2)) expr = sinh(x) assert tensorflow_code(expr) == "tensorflow.math.sinh(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2)) expr = asinh(x) assert tensorflow_code(expr) == "tensorflow.math.asinh(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2)) expr = tanh(x) assert tensorflow_code(expr) == "tensorflow.math.tanh(x)" _compare_tensorflow_scalar((x,), expr, rng=lambda: random.uniform(1, 2)) expr = atanh(x) assert tensorflow_code(expr) == "tensorflow.math.atanh(x)" _compare_tensorflow_scalar( (x,), expr, rng=lambda: random.uniform(-.5, .5)) expr = erf(x) assert tensorflow_code(expr) == "tensorflow.math.erf(x)" _compare_tensorflow_scalar( (x,), expr, rng=lambda: random.random()) expr = loggamma(x) assert tensorflow_code(expr) == "tensorflow.math.lgamma(x)" _compare_tensorflow_scalar( (x,), expr, rng=lambda: random.random()) def test_tensorflow_complexes(): assert tensorflow_code(re(x)) == "tensorflow.math.real(x)" assert tensorflow_code(im(x)) == "tensorflow.math.imag(x)" assert tensorflow_code(arg(x)) == "tensorflow.math.angle(x)" def test_tensorflow_relational(): if not tf: skip("TensorFlow not installed") expr = Eq(x, y) assert tensorflow_code(expr) == "tensorflow.math.equal(x, y)" _compare_tensorflow_relational((x, y), expr) expr = Ne(x, y) assert tensorflow_code(expr) == "tensorflow.math.not_equal(x, y)" _compare_tensorflow_relational((x, y), expr) expr = Ge(x, y) assert tensorflow_code(expr) == "tensorflow.math.greater_equal(x, y)" _compare_tensorflow_relational((x, y), expr) expr = Gt(x, y) assert tensorflow_code(expr) == "tensorflow.math.greater(x, y)" _compare_tensorflow_relational((x, y), expr) expr = Le(x, y) assert tensorflow_code(expr) == "tensorflow.math.less_equal(x, y)" _compare_tensorflow_relational((x, y), expr) expr = Lt(x, y) assert tensorflow_code(expr) == "tensorflow.math.less(x, y)" _compare_tensorflow_relational((x, y), expr) # This (random) test is XFAIL because it fails occasionally # See https://github.com/sympy/sympy/issues/18469 @XFAIL def test_tensorflow_matrices(): if not tf: skip("TensorFlow not installed") expr = M assert tensorflow_code(expr) == "M" _compare_tensorflow_matrix((M,), expr) expr = M + N assert tensorflow_code(expr) == "tensorflow.math.add(M, N)" _compare_tensorflow_matrix((M, N), expr) expr = M * N assert tensorflow_code(expr) == "tensorflow.linalg.matmul(M, N)" _compare_tensorflow_matrix((M, N), expr) expr = HadamardProduct(M, N) assert tensorflow_code(expr) == "tensorflow.math.multiply(M, N)" _compare_tensorflow_matrix((M, N), expr) expr = M*N*P*Q assert tensorflow_code(expr) == \ "tensorflow.linalg.matmul(" \ "tensorflow.linalg.matmul(" \ "tensorflow.linalg.matmul(M, N), P), Q)" _compare_tensorflow_matrix((M, N, P, Q), expr) expr = M**3 assert tensorflow_code(expr) == \ "tensorflow.linalg.matmul(tensorflow.linalg.matmul(M, M), M)" _compare_tensorflow_matrix((M,), expr) expr = Trace(M) assert tensorflow_code(expr) == "tensorflow.linalg.trace(M)" _compare_tensorflow_matrix((M,), expr) expr = Determinant(M) assert tensorflow_code(expr) == "tensorflow.linalg.det(M)" _compare_tensorflow_matrix_scalar((M,), expr) expr = Inverse(M) assert tensorflow_code(expr) == "tensorflow.linalg.inv(M)" _compare_tensorflow_matrix_inverse((M,), expr, use_float=True) expr = M.T assert tensorflow_code(expr, tensorflow_version='1.14') == \ "tensorflow.linalg.matrix_transpose(M)" assert tensorflow_code(expr, tensorflow_version='1.13') == \ "tensorflow.matrix_transpose(M)" _compare_tensorflow_matrix((M,), expr) def test_codegen_einsum(): if not tf: skip("TensorFlow not installed") graph = tf.Graph() with graph.as_default(): session = tf.compat.v1.Session(graph=graph) M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) cg = convert_matrix_to_array(M * N) f = lambdify((M, N), cg, 'tensorflow') ma = tf.constant([[1, 2], [3, 4]]) mb = tf.constant([[1,-2], [-1, 3]]) y = session.run(f(ma, mb)) c = session.run(tf.matmul(ma, mb)) assert (y == c).all() def test_codegen_extra(): if not tf: skip("TensorFlow not installed") graph = tf.Graph() with graph.as_default(): session = tf.compat.v1.Session() M = MatrixSymbol("M", 2, 2) N = MatrixSymbol("N", 2, 2) P = MatrixSymbol("P", 2, 2) Q = MatrixSymbol("Q", 2, 2) ma = tf.constant([[1, 2], [3, 4]]) mb = tf.constant([[1,-2], [-1, 3]]) mc = tf.constant([[2, 0], [1, 2]]) md = tf.constant([[1,-1], [4, 7]]) cg = ArrayTensorProduct(M, N) assert tensorflow_code(cg) == \ 'tensorflow.linalg.einsum("ab,cd", M, N)' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(tf.einsum("ij,kl", ma, mb)) assert (y == c).all() cg = ArrayAdd(M, N) assert tensorflow_code(cg) == 'tensorflow.math.add(M, N)' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(ma + mb) assert (y == c).all() cg = ArrayAdd(M, N, P) assert tensorflow_code(cg) == \ 'tensorflow.math.add(tensorflow.math.add(M, N), P)' f = lambdify((M, N, P), cg, 'tensorflow') y = session.run(f(ma, mb, mc)) c = session.run(ma + mb + mc) assert (y == c).all() cg = ArrayAdd(M, N, P, Q) assert tensorflow_code(cg) == \ 'tensorflow.math.add(' \ 'tensorflow.math.add(tensorflow.math.add(M, N), P), Q)' f = lambdify((M, N, P, Q), cg, 'tensorflow') y = session.run(f(ma, mb, mc, md)) c = session.run(ma + mb + mc + md) assert (y == c).all() cg = PermuteDims(M, [1, 0]) assert tensorflow_code(cg) == 'tensorflow.transpose(M, [1, 0])' f = lambdify((M,), cg, 'tensorflow') y = session.run(f(ma)) c = session.run(tf.transpose(ma)) assert (y == c).all() cg = PermuteDims(ArrayTensorProduct(M, N), [1, 2, 3, 0]) assert tensorflow_code(cg) == \ 'tensorflow.transpose(' \ 'tensorflow.linalg.einsum("ab,cd", M, N), [1, 2, 3, 0])' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(tf.transpose(tf.einsum("ab,cd", ma, mb), [1, 2, 3, 0])) assert (y == c).all() cg = ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2)) assert tensorflow_code(cg) == \ 'tensorflow.linalg.einsum("ab,bc->acb", M, N)' f = lambdify((M, N), cg, 'tensorflow') y = session.run(f(ma, mb)) c = session.run(tf.einsum("ab,bc->acb", ma, mb)) assert (y == c).all() def test_MatrixElement_printing(): A = MatrixSymbol("A", 1, 3) B = MatrixSymbol("B", 1, 3) C = MatrixSymbol("C", 1, 3) assert tensorflow_code(A[0, 0]) == "A[0, 0]" assert tensorflow_code(3 * A[0, 0]) == "3*A[0, 0]" F = C[0, 0].subs(C, A - B) assert tensorflow_code(F) == "(tensorflow.math.add((-1)*B, A))[0, 0]" def test_tensorflow_Derivative(): expr = Derivative(sin(x), x) assert tensorflow_code(expr) == \ "tensorflow.gradients(tensorflow.math.sin(x), x)[0]" sympy-sympy-1.9/sympy/printing/tests/test_theanocode.py000066400000000000000000000505451412543434000236330ustar00rootroot00000000000000""" Important note on tests in this module - the Theano printing functions use a global cache by default, which means that tests using it will modify global state and thus not be independent from each other. Instead of using the "cache" keyword argument each time, this module uses the theano_code_ and theano_function_ functions defined below which default to using a new, empty cache instead. """ import logging from sympy.external import import_module from sympy.testing.pytest import raises, SKIP, warns_deprecated_sympy theanologger = logging.getLogger('theano.configdefaults') theanologger.setLevel(logging.CRITICAL) theano = import_module('theano') theanologger.setLevel(logging.WARNING) if theano: import numpy as np ts = theano.scalar tt = theano.tensor xt, yt, zt = [tt.scalar(name, 'floatX') for name in 'xyz'] Xt, Yt, Zt = [tt.tensor('floatX', (False, False), name=n) for n in 'XYZ'] else: #bin/test will not execute any tests now disabled = True import sympy as sy from sympy import S from sympy.abc import x, y, z, t from sympy.printing.theanocode import (theano_code, dim_handling, theano_function) # Default set of matrix symbols for testing - make square so we can both # multiply and perform elementwise operations between them. X, Y, Z = [sy.MatrixSymbol(n, 4, 4) for n in 'XYZ'] # For testing AppliedUndef f_t = sy.Function('f')(t) def theano_code_(expr, **kwargs): """ Wrapper for theano_code that uses a new, empty cache by default. """ kwargs.setdefault('cache', {}) with warns_deprecated_sympy(): return theano_code(expr, **kwargs) def theano_function_(inputs, outputs, **kwargs): """ Wrapper for theano_function that uses a new, empty cache by default. """ kwargs.setdefault('cache', {}) with warns_deprecated_sympy(): return theano_function(inputs, outputs, **kwargs) def fgraph_of(*exprs): """ Transform SymPy expressions into Theano Computation. Parameters ========== exprs Sympy expressions Returns ======= theano.gof.FunctionGraph """ outs = list(map(theano_code_, exprs)) ins = theano.gof.graph.inputs(outs) ins, outs = theano.gof.graph.clone(ins, outs) return theano.gof.FunctionGraph(ins, outs) def theano_simplify(fgraph): """ Simplify a Theano Computation. Parameters ========== fgraph : theano.gof.FunctionGraph Returns ======= theano.gof.FunctionGraph """ mode = theano.compile.get_default_mode().excluding("fusion") fgraph = fgraph.clone() mode.optimizer.optimize(fgraph) return fgraph def theq(a, b): """ Test two Theano objects for equality. Also accepts numeric types and lists/tuples of supported types. Note - debugprint() has a bug where it will accept numeric types but does not respect the "file" argument and in this case and instead prints the number to stdout and returns an empty string. This can lead to tests passing where they should fail because any two numbers will always compare as equal. To prevent this we treat numbers as a separate case. """ numeric_types = (int, float, np.number) a_is_num = isinstance(a, numeric_types) b_is_num = isinstance(b, numeric_types) # Compare numeric types using regular equality if a_is_num or b_is_num: if not (a_is_num and b_is_num): return False return a == b # Compare sequences element-wise a_is_seq = isinstance(a, (tuple, list)) b_is_seq = isinstance(b, (tuple, list)) if a_is_seq or b_is_seq: if not (a_is_seq and b_is_seq) or type(a) != type(b): return False return list(map(theq, a)) == list(map(theq, b)) # Otherwise, assume debugprint() can handle it astr = theano.printing.debugprint(a, file='str') bstr = theano.printing.debugprint(b, file='str') # Check for bug mentioned above for argname, argval, argstr in [('a', a, astr), ('b', b, bstr)]: if argstr == '': raise TypeError( 'theano.printing.debugprint(%s) returned empty string ' '(%s is instance of %r)' % (argname, argname, type(argval)) ) return astr == bstr def test_example_symbols(): """ Check that the example symbols in this module print to their Theano equivalents, as many of the other tests depend on this. """ assert theq(xt, theano_code_(x)) assert theq(yt, theano_code_(y)) assert theq(zt, theano_code_(z)) assert theq(Xt, theano_code_(X)) assert theq(Yt, theano_code_(Y)) assert theq(Zt, theano_code_(Z)) def test_Symbol(): """ Test printing a Symbol to a theano variable. """ xx = theano_code_(x) assert isinstance(xx, (tt.TensorVariable, ts.ScalarVariable)) assert xx.broadcastable == () assert xx.name == x.name xx2 = theano_code_(x, broadcastables={x: (False,)}) assert xx2.broadcastable == (False,) assert xx2.name == x.name def test_MatrixSymbol(): """ Test printing a MatrixSymbol to a theano variable. """ XX = theano_code_(X) assert isinstance(XX, tt.TensorVariable) assert XX.broadcastable == (False, False) @SKIP # TODO - this is currently not checked but should be implemented def test_MatrixSymbol_wrong_dims(): """ Test MatrixSymbol with invalid broadcastable. """ bcs = [(), (False,), (True,), (True, False), (False, True,), (True, True)] for bc in bcs: with raises(ValueError): theano_code_(X, broadcastables={X: bc}) def test_AppliedUndef(): """ Test printing AppliedUndef instance, which works similarly to Symbol. """ ftt = theano_code_(f_t) assert isinstance(ftt, tt.TensorVariable) assert ftt.broadcastable == () assert ftt.name == 'f_t' def test_add(): expr = x + y comp = theano_code_(expr) assert comp.owner.op == theano.tensor.add def test_trig(): assert theq(theano_code_(sy.sin(x)), tt.sin(xt)) assert theq(theano_code_(sy.tan(x)), tt.tan(xt)) def test_many(): """ Test printing a complex expression with multiple symbols. """ expr = sy.exp(x**2 + sy.cos(y)) * sy.log(2*z) comp = theano_code_(expr) expected = tt.exp(xt**2 + tt.cos(yt)) * tt.log(2*zt) assert theq(comp, expected) def test_dtype(): """ Test specifying specific data types through the dtype argument. """ for dtype in ['float32', 'float64', 'int8', 'int16', 'int32', 'int64']: assert theano_code_(x, dtypes={x: dtype}).type.dtype == dtype # "floatX" type assert theano_code_(x, dtypes={x: 'floatX'}).type.dtype in ('float32', 'float64') # Type promotion assert theano_code_(x + 1, dtypes={x: 'float32'}).type.dtype == 'float32' assert theano_code_(x + y, dtypes={x: 'float64', y: 'float32'}).type.dtype == 'float64' def test_broadcastables(): """ Test the "broadcastables" argument when printing symbol-like objects. """ # No restrictions on shape for s in [x, f_t]: for bc in [(), (False,), (True,), (False, False), (True, False)]: assert theano_code_(s, broadcastables={s: bc}).broadcastable == bc # TODO - matrix broadcasting? def test_broadcasting(): """ Test "broadcastable" attribute after applying element-wise binary op. """ expr = x + y cases = [ [(), (), ()], [(False,), (False,), (False,)], [(True,), (False,), (False,)], [(False, True), (False, False), (False, False)], [(True, False), (False, False), (False, False)], ] for bc1, bc2, bc3 in cases: comp = theano_code_(expr, broadcastables={x: bc1, y: bc2}) assert comp.broadcastable == bc3 def test_MatMul(): expr = X*Y*Z expr_t = theano_code_(expr) assert isinstance(expr_t.owner.op, tt.Dot) assert theq(expr_t, Xt.dot(Yt).dot(Zt)) def test_Transpose(): assert isinstance(theano_code_(X.T).owner.op, tt.DimShuffle) def test_MatAdd(): expr = X+Y+Z assert isinstance(theano_code_(expr).owner.op, tt.Elemwise) def test_Rationals(): assert theq(theano_code_(sy.Integer(2) / 3), tt.true_div(2, 3)) assert theq(theano_code_(S.Half), tt.true_div(1, 2)) def test_Integers(): assert theano_code_(sy.Integer(3)) == 3 def test_factorial(): n = sy.Symbol('n') assert theano_code_(sy.factorial(n)) def test_Derivative(): simp = lambda expr: theano_simplify(fgraph_of(expr)) assert theq(simp(theano_code_(sy.Derivative(sy.sin(x), x, evaluate=False))), simp(theano.grad(tt.sin(xt), xt))) def test_theano_function_simple(): """ Test theano_function() with single output. """ f = theano_function_([x, y], [x+y]) assert f(2, 3) == 5 def test_theano_function_multi(): """ Test theano_function() with multiple outputs. """ f = theano_function_([x, y], [x+y, x-y]) o1, o2 = f(2, 3) assert o1 == 5 assert o2 == -1 def test_theano_function_numpy(): """ Test theano_function() vs Numpy implementation. """ f = theano_function_([x, y], [x+y], dim=1, dtypes={x: 'float64', y: 'float64'}) assert np.linalg.norm(f([1, 2], [3, 4]) - np.asarray([4, 6])) < 1e-9 f = theano_function_([x, y], [x+y], dtypes={x: 'float64', y: 'float64'}, dim=1) xx = np.arange(3).astype('float64') yy = 2*np.arange(3).astype('float64') assert np.linalg.norm(f(xx, yy) - 3*np.arange(3)) < 1e-9 def test_theano_function_matrix(): m = sy.Matrix([[x, y], [z, x + y + z]]) expected = np.array([[1.0, 2.0], [3.0, 1.0 + 2.0 + 3.0]]) f = theano_function_([x, y, z], [m]) np.testing.assert_allclose(f(1.0, 2.0, 3.0), expected) f = theano_function_([x, y, z], [m], scalar=True) np.testing.assert_allclose(f(1.0, 2.0, 3.0), expected) f = theano_function_([x, y, z], [m, m]) assert isinstance(f(1.0, 2.0, 3.0), type([])) np.testing.assert_allclose(f(1.0, 2.0, 3.0)[0], expected) np.testing.assert_allclose(f(1.0, 2.0, 3.0)[1], expected) def test_dim_handling(): assert dim_handling([x], dim=2) == {x: (False, False)} assert dim_handling([x, y], dims={x: 1, y: 2}) == {x: (False, True), y: (False, False)} assert dim_handling([x], broadcastables={x: (False,)}) == {x: (False,)} def test_theano_function_kwargs(): """ Test passing additional kwargs from theano_function() to theano.function(). """ import numpy as np f = theano_function_([x, y, z], [x+y], dim=1, on_unused_input='ignore', dtypes={x: 'float64', y: 'float64', z: 'float64'}) assert np.linalg.norm(f([1, 2], [3, 4], [0, 0]) - np.asarray([4, 6])) < 1e-9 f = theano_function_([x, y, z], [x+y], dtypes={x: 'float64', y: 'float64', z: 'float64'}, dim=1, on_unused_input='ignore') xx = np.arange(3).astype('float64') yy = 2*np.arange(3).astype('float64') zz = 2*np.arange(3).astype('float64') assert np.linalg.norm(f(xx, yy, zz) - 3*np.arange(3)) < 1e-9 def test_theano_function_scalar(): """ Test the "scalar" argument to theano_function(). """ args = [ ([x, y], [x + y], None, [0]), # Single 0d output ([X, Y], [X + Y], None, [2]), # Single 2d output ([x, y], [x + y], {x: 0, y: 1}, [1]), # Single 1d output ([x, y], [x + y, x - y], None, [0, 0]), # Two 0d outputs ([x, y, X, Y], [x + y, X + Y], None, [0, 2]), # One 0d output, one 2d ] # Create and test functions with and without the scalar setting for inputs, outputs, in_dims, out_dims in args: for scalar in [False, True]: f = theano_function_(inputs, outputs, dims=in_dims, scalar=scalar) # Check the theano_function attribute is set whether wrapped or not assert isinstance(f.theano_function, theano.compile.function_module.Function) # Feed in inputs of the appropriate size and get outputs in_values = [ np.ones([1 if bc else 5 for bc in i.type.broadcastable]) for i in f.theano_function.input_storage ] out_values = f(*in_values) if not isinstance(out_values, list): out_values = [out_values] # Check output types and shapes assert len(out_dims) == len(out_values) for d, value in zip(out_dims, out_values): if scalar and d == 0: # Should have been converted to a scalar value assert isinstance(value, np.number) else: # Otherwise should be an array assert isinstance(value, np.ndarray) assert value.ndim == d def test_theano_function_bad_kwarg(): """ Passing an unknown keyword argument to theano_function() should raise an exception. """ raises(Exception, lambda : theano_function_([x], [x+1], foobar=3)) def test_slice(): assert theano_code_(slice(1, 2, 3)) == slice(1, 2, 3) def theq_slice(s1, s2): for attr in ['start', 'stop', 'step']: a1 = getattr(s1, attr) a2 = getattr(s2, attr) if a1 is None or a2 is None: if not (a1 is None or a2 is None): return False elif not theq(a1, a2): return False return True dtypes = {x: 'int32', y: 'int32'} assert theq_slice(theano_code_(slice(x, y), dtypes=dtypes), slice(xt, yt)) assert theq_slice(theano_code_(slice(1, x, 3), dtypes=dtypes), slice(1, xt, 3)) def test_MatrixSlice(): from theano import Constant cache = {} n = sy.Symbol('n', integer=True) X = sy.MatrixSymbol('X', n, n) Y = X[1:2:3, 4:5:6] Yt = theano_code_(Y, cache=cache) s = ts.Scalar('int64') assert tuple(Yt.owner.op.idx_list) == (slice(s, s, s), slice(s, s, s)) assert Yt.owner.inputs[0] == theano_code_(X, cache=cache) # == doesn't work in theano like it does in SymPy. You have to use # equals. assert all(Yt.owner.inputs[i].equals(Constant(s, i)) for i in range(1, 7)) k = sy.Symbol('k') theano_code_(k, dtypes={k: 'int32'}) start, stop, step = 4, k, 2 Y = X[start:stop:step] Yt = theano_code_(Y, dtypes={n: 'int32', k: 'int32'}) # assert Yt.owner.op.idx_list[0].stop == kt def test_BlockMatrix(): n = sy.Symbol('n', integer=True) A, B, C, D = [sy.MatrixSymbol(name, n, n) for name in 'ABCD'] At, Bt, Ct, Dt = map(theano_code_, (A, B, C, D)) Block = sy.BlockMatrix([[A, B], [C, D]]) Blockt = theano_code_(Block) solutions = [tt.join(0, tt.join(1, At, Bt), tt.join(1, Ct, Dt)), tt.join(1, tt.join(0, At, Ct), tt.join(0, Bt, Dt))] assert any(theq(Blockt, solution) for solution in solutions) @SKIP def test_BlockMatrix_Inverse_execution(): k, n = 2, 4 dtype = 'float32' A = sy.MatrixSymbol('A', n, k) B = sy.MatrixSymbol('B', n, n) inputs = A, B output = B.I*A cutsizes = {A: [(n//2, n//2), (k//2, k//2)], B: [(n//2, n//2), (n//2, n//2)]} cutinputs = [sy.blockcut(i, *cutsizes[i]) for i in inputs] cutoutput = output.subs(dict(zip(inputs, cutinputs))) dtypes = dict(zip(inputs, [dtype]*len(inputs))) f = theano_function_(inputs, [output], dtypes=dtypes, cache={}) fblocked = theano_function_(inputs, [sy.block_collapse(cutoutput)], dtypes=dtypes, cache={}) ninputs = [np.random.rand(*x.shape).astype(dtype) for x in inputs] ninputs = [np.arange(n*k).reshape(A.shape).astype(dtype), np.eye(n).astype(dtype)] ninputs[1] += np.ones(B.shape)*1e-5 assert np.allclose(f(*ninputs), fblocked(*ninputs), rtol=1e-5) def test_DenseMatrix(): t = sy.Symbol('theta') for MatrixType in [sy.Matrix, sy.ImmutableMatrix]: X = MatrixType([[sy.cos(t), -sy.sin(t)], [sy.sin(t), sy.cos(t)]]) tX = theano_code_(X) assert isinstance(tX, tt.TensorVariable) assert tX.owner.op == tt.join_ def test_cache_basic(): """ Test single symbol-like objects are cached when printed by themselves. """ # Pairs of objects which should be considered equivalent with respect to caching pairs = [ (x, sy.Symbol('x')), (X, sy.MatrixSymbol('X', *X.shape)), (f_t, sy.Function('f')(sy.Symbol('t'))), ] for s1, s2 in pairs: cache = {} st = theano_code_(s1, cache=cache) # Test hit with same instance assert theano_code_(s1, cache=cache) is st # Test miss with same instance but new cache assert theano_code_(s1, cache={}) is not st # Test hit with different but equivalent instance assert theano_code_(s2, cache=cache) is st def test_global_cache(): """ Test use of the global cache. """ from sympy.printing.theanocode import global_cache backup = dict(global_cache) try: # Temporarily empty global cache global_cache.clear() for s in [x, X, f_t]: with warns_deprecated_sympy(): st = theano_code(s) assert theano_code(s) is st finally: # Restore global cache global_cache.update(backup) def test_cache_types_distinct(): """ Test that symbol-like objects of different types (Symbol, MatrixSymbol, AppliedUndef) are distinguished by the cache even if they have the same name. """ symbols = [sy.Symbol('f_t'), sy.MatrixSymbol('f_t', 4, 4), f_t] cache = {} # Single shared cache printed = {} for s in symbols: st = theano_code_(s, cache=cache) assert st not in printed.values() printed[s] = st # Check all printed objects are distinct assert len(set(map(id, printed.values()))) == len(symbols) # Check retrieving for s, st in printed.items(): with warns_deprecated_sympy(): assert theano_code(s, cache=cache) is st def test_symbols_are_created_once(): """ Test that a symbol is cached and reused when it appears in an expression more than once. """ expr = sy.Add(x, x, evaluate=False) comp = theano_code_(expr) assert theq(comp, xt + xt) assert not theq(comp, xt + theano_code_(x)) def test_cache_complex(): """ Test caching on a complicated expression with multiple symbols appearing multiple times. """ expr = x ** 2 + (y - sy.exp(x)) * sy.sin(z - x * y) symbol_names = {s.name for s in expr.free_symbols} expr_t = theano_code_(expr) # Iterate through variables in the Theano computational graph that the # printed expression depends on seen = set() for v in theano.gof.graph.ancestors([expr_t]): # Owner-less, non-constant variables should be our symbols if v.owner is None and not isinstance(v, theano.gof.graph.Constant): # Check it corresponds to a symbol and appears only once assert v.name in symbol_names assert v.name not in seen seen.add(v.name) # Check all were present assert seen == symbol_names def test_Piecewise(): # A piecewise linear expr = sy.Piecewise((0, x<0), (x, x<2), (1, True)) # ___/III result = theano_code_(expr) assert result.owner.op == tt.switch expected = tt.switch(xt<0, 0, tt.switch(xt<2, xt, 1)) assert theq(result, expected) expr = sy.Piecewise((x, x < 0)) result = theano_code_(expr) expected = tt.switch(xt < 0, xt, np.nan) assert theq(result, expected) expr = sy.Piecewise((0, sy.And(x>0, x<2)), \ (x, sy.Or(x>2, x<0))) result = theano_code_(expr) expected = tt.switch(tt.and_(xt>0,xt<2), 0, \ tt.switch(tt.or_(xt>2, xt<0), xt, np.nan)) assert theq(result, expected) def test_Relationals(): assert theq(theano_code_(sy.Eq(x, y)), tt.eq(xt, yt)) # assert theq(theano_code_(sy.Ne(x, y)), tt.neq(xt, yt)) # TODO - implement assert theq(theano_code_(x > y), xt > yt) assert theq(theano_code_(x < y), xt < yt) assert theq(theano_code_(x >= y), xt >= yt) assert theq(theano_code_(x <= y), xt <= yt) def test_complexfunctions(): with warns_deprecated_sympy(): xt, yt = theano_code_(x, dtypes={x:'complex128'}), theano_code_(y, dtypes={y: 'complex128'}) from sympy import conjugate from theano.tensor import as_tensor_variable as atv from theano.tensor import complex as cplx with warns_deprecated_sympy(): assert theq(theano_code_(y*conjugate(x)), yt*(xt.conj())) assert theq(theano_code_((1+2j)*x), xt*(atv(1.0)+atv(2.0)*cplx(0,1))) def test_constantfunctions(): with warns_deprecated_sympy(): tf = theano_function_([],[1+1j]) assert(tf()==1+1j) sympy-sympy-1.9/sympy/printing/tests/test_tree.py000066400000000000000000000137001412543434000224510ustar00rootroot00000000000000from sympy.printing.tree import tree from sympy.testing.pytest import XFAIL # Remove this flag after making _assumptions cache deterministic. @XFAIL def test_print_tree_MatAdd(): from sympy.matrices.expressions import MatrixSymbol A = MatrixSymbol('A', 3, 3) B = MatrixSymbol('B', 3, 3) test_str = [ 'MatAdd: A + B\n', 'algebraic: False\n', 'commutative: False\n', 'complex: False\n', 'composite: False\n', 'even: False\n', 'extended_negative: False\n', 'extended_nonnegative: False\n', 'extended_nonpositive: False\n', 'extended_nonzero: False\n', 'extended_positive: False\n', 'extended_real: False\n', 'imaginary: False\n', 'integer: False\n', 'irrational: False\n', 'negative: False\n', 'noninteger: False\n', 'nonnegative: False\n', 'nonpositive: False\n', 'nonzero: False\n', 'odd: False\n', 'positive: False\n', 'prime: False\n', 'rational: False\n', 'real: False\n', 'transcendental: False\n', 'zero: False\n', '+-MatrixSymbol: A\n', '| algebraic: False\n', '| commutative: False\n', '| complex: False\n', '| composite: False\n', '| even: False\n', '| extended_negative: False\n', '| extended_nonnegative: False\n', '| extended_nonpositive: False\n', '| extended_nonzero: False\n', '| extended_positive: False\n', '| extended_real: False\n', '| imaginary: False\n', '| integer: False\n', '| irrational: False\n', '| negative: False\n', '| noninteger: False\n', '| nonnegative: False\n', '| nonpositive: False\n', '| nonzero: False\n', '| odd: False\n', '| positive: False\n', '| prime: False\n', '| rational: False\n', '| real: False\n', '| transcendental: False\n', '| zero: False\n', '| +-Symbol: A\n', '| | commutative: True\n', '| +-Integer: 3\n', '| | algebraic: True\n', '| | commutative: True\n', '| | complex: True\n', '| | extended_negative: False\n', '| | extended_nonnegative: True\n', '| | extended_real: True\n', '| | finite: True\n', '| | hermitian: True\n', '| | imaginary: False\n', '| | infinite: False\n', '| | integer: True\n', '| | irrational: False\n', '| | negative: False\n', '| | noninteger: False\n', '| | nonnegative: True\n', '| | rational: True\n', '| | real: True\n', '| | transcendental: False\n', '| +-Integer: 3\n', '| algebraic: True\n', '| commutative: True\n', '| complex: True\n', '| extended_negative: False\n', '| extended_nonnegative: True\n', '| extended_real: True\n', '| finite: True\n', '| hermitian: True\n', '| imaginary: False\n', '| infinite: False\n', '| integer: True\n', '| irrational: False\n', '| negative: False\n', '| noninteger: False\n', '| nonnegative: True\n', '| rational: True\n', '| real: True\n', '| transcendental: False\n', '+-MatrixSymbol: B\n', ' algebraic: False\n', ' commutative: False\n', ' complex: False\n', ' composite: False\n', ' even: False\n', ' extended_negative: False\n', ' extended_nonnegative: False\n', ' extended_nonpositive: False\n', ' extended_nonzero: False\n', ' extended_positive: False\n', ' extended_real: False\n', ' imaginary: False\n', ' integer: False\n', ' irrational: False\n', ' negative: False\n', ' noninteger: False\n', ' nonnegative: False\n', ' nonpositive: False\n', ' nonzero: False\n', ' odd: False\n', ' positive: False\n', ' prime: False\n', ' rational: False\n', ' real: False\n', ' transcendental: False\n', ' zero: False\n', ' +-Symbol: B\n', ' | commutative: True\n', ' +-Integer: 3\n', ' | algebraic: True\n', ' | commutative: True\n', ' | complex: True\n', ' | extended_negative: False\n', ' | extended_nonnegative: True\n', ' | extended_real: True\n', ' | finite: True\n', ' | hermitian: True\n', ' | imaginary: False\n', ' | infinite: False\n', ' | integer: True\n', ' | irrational: False\n', ' | negative: False\n', ' | noninteger: False\n', ' | nonnegative: True\n', ' | rational: True\n', ' | real: True\n', ' | transcendental: False\n', ' +-Integer: 3\n', ' algebraic: True\n', ' commutative: True\n', ' complex: True\n', ' extended_negative: False\n', ' extended_nonnegative: True\n', ' extended_real: True\n', ' finite: True\n', ' hermitian: True\n', ' imaginary: False\n', ' infinite: False\n', ' integer: True\n', ' irrational: False\n', ' negative: False\n', ' noninteger: False\n', ' nonnegative: True\n', ' rational: True\n', ' real: True\n', ' transcendental: False\n' ] assert tree(A + B) == "".join(test_str) def test_print_tree_MatAdd_noassumptions(): from sympy.matrices.expressions import MatrixSymbol A = MatrixSymbol('A', 3, 3) B = MatrixSymbol('B', 3, 3) test_str = \ """MatAdd: A + B +-MatrixSymbol: A | +-Str: A | +-Integer: 3 | +-Integer: 3 +-MatrixSymbol: B +-Str: B +-Integer: 3 +-Integer: 3 """ assert tree(A + B, assumptions=False) == test_str sympy-sympy-1.9/sympy/printing/theanocode.py000066400000000000000000000434241412543434000214300ustar00rootroot00000000000000from typing import Any, Dict from sympy.core.compatibility import is_sequence from sympy.external import import_module from sympy.printing.printer import Printer import sympy from functools import partial from sympy.utilities.decorator import doctest_depends_on from sympy.utilities.exceptions import SymPyDeprecationWarning theano = import_module('theano') if theano: ts = theano.scalar tt = theano.tensor from theano.sandbox import linalg as tlinalg mapping = { sympy.Add: tt.add, sympy.Mul: tt.mul, sympy.Abs: tt.abs_, sympy.sign: tt.sgn, sympy.ceiling: tt.ceil, sympy.floor: tt.floor, sympy.log: tt.log, sympy.exp: tt.exp, sympy.sqrt: tt.sqrt, sympy.cos: tt.cos, sympy.acos: tt.arccos, sympy.sin: tt.sin, sympy.asin: tt.arcsin, sympy.tan: tt.tan, sympy.atan: tt.arctan, sympy.atan2: tt.arctan2, sympy.cosh: tt.cosh, sympy.acosh: tt.arccosh, sympy.sinh: tt.sinh, sympy.asinh: tt.arcsinh, sympy.tanh: tt.tanh, sympy.atanh: tt.arctanh, sympy.re: tt.real, sympy.im: tt.imag, sympy.arg: tt.angle, sympy.erf: tt.erf, sympy.gamma: tt.gamma, sympy.loggamma: tt.gammaln, sympy.Pow: tt.pow, sympy.Eq: tt.eq, sympy.StrictGreaterThan: tt.gt, sympy.StrictLessThan: tt.lt, sympy.LessThan: tt.le, sympy.GreaterThan: tt.ge, sympy.And: tt.and_, sympy.Or: tt.or_, sympy.Max: tt.maximum, # Sympy accept >2 inputs, Theano only 2 sympy.Min: tt.minimum, # Sympy accept >2 inputs, Theano only 2 sympy.conjugate: tt.conj, sympy.core.numbers.ImaginaryUnit: lambda:tt.complex(0,1), # Matrices sympy.MatAdd: tt.Elemwise(ts.add), sympy.HadamardProduct: tt.Elemwise(ts.mul), sympy.Trace: tlinalg.trace, sympy.Determinant : tlinalg.det, sympy.Inverse: tlinalg.matrix_inverse, sympy.Transpose: tt.DimShuffle((False, False), [1, 0]), } class TheanoPrinter(Printer): """ Code printer which creates Theano symbolic expression graphs. Parameters ========== cache : dict Cache dictionary to use. If None (default) will use the global cache. To create a printer which does not depend on or alter global state pass an empty dictionary. Note: the dictionary is not copied on initialization of the printer and will be updated in-place, so using the same dict object when creating multiple printers or making multiple calls to :func:`.theano_code` or :func:`.theano_function` means the cache is shared between all these applications. Attributes ========== cache : dict A cache of Theano variables which have been created for Sympy symbol-like objects (e.g. :class:`sympy.core.symbol.Symbol` or :class:`sympy.matrices.expressions.MatrixSymbol`). This is used to ensure that all references to a given symbol in an expression (or multiple expressions) are printed as the same Theano variable, which is created only once. Symbols are differentiated only by name and type. The format of the cache's contents should be considered opaque to the user. """ printmethod = "_theano" def __init__(self, *args, **kwargs): self.cache = kwargs.pop('cache', dict()) super().__init__(*args, **kwargs) def _get_key(self, s, name=None, dtype=None, broadcastable=None): """ Get the cache key for a Sympy object. Parameters ========== s : sympy.core.basic.Basic Sympy object to get key for. name : str Name of object, if it does not have a ``name`` attribute. """ if name is None: name = s.name return (name, type(s), s.args, dtype, broadcastable) def _get_or_create(self, s, name=None, dtype=None, broadcastable=None): """ Get the Theano variable for a Sympy symbol from the cache, or create it if it does not exist. """ # Defaults if name is None: name = s.name if dtype is None: dtype = 'floatX' if broadcastable is None: broadcastable = () key = self._get_key(s, name, dtype=dtype, broadcastable=broadcastable) if key in self.cache: return self.cache[key] value = tt.tensor(name=name, dtype=dtype, broadcastable=broadcastable) self.cache[key] = value return value def _print_Symbol(self, s, **kwargs): dtype = kwargs.get('dtypes', {}).get(s) bc = kwargs.get('broadcastables', {}).get(s) return self._get_or_create(s, dtype=dtype, broadcastable=bc) def _print_AppliedUndef(self, s, **kwargs): name = str(type(s)) + '_' + str(s.args[0]) dtype = kwargs.get('dtypes', {}).get(s) bc = kwargs.get('broadcastables', {}).get(s) return self._get_or_create(s, name=name, dtype=dtype, broadcastable=bc) def _print_Basic(self, expr, **kwargs): op = mapping[type(expr)] children = [self._print(arg, **kwargs) for arg in expr.args] return op(*children) def _print_Number(self, n, **kwargs): # Integers already taken care of below, interpret as float return float(n.evalf()) def _print_MatrixSymbol(self, X, **kwargs): dtype = kwargs.get('dtypes', {}).get(X) return self._get_or_create(X, dtype=dtype, broadcastable=(None, None)) def _print_DenseMatrix(self, X, **kwargs): if not hasattr(tt, 'stacklists'): raise NotImplementedError( "Matrix translation not yet supported in this version of Theano") return tt.stacklists([ [self._print(arg, **kwargs) for arg in L] for L in X.tolist() ]) _print_ImmutableMatrix = _print_ImmutableDenseMatrix = _print_DenseMatrix def _print_MatMul(self, expr, **kwargs): children = [self._print(arg, **kwargs) for arg in expr.args] result = children[0] for child in children[1:]: result = tt.dot(result, child) return result def _print_MatPow(self, expr, **kwargs): children = [self._print(arg, **kwargs) for arg in expr.args] result = 1 if isinstance(children[1], int) and children[1] > 0: for i in range(children[1]): result = tt.dot(result, children[0]) else: raise NotImplementedError('''Only non-negative integer powers of matrices can be handled by Theano at the moment''') return result def _print_MatrixSlice(self, expr, **kwargs): parent = self._print(expr.parent, **kwargs) rowslice = self._print(slice(*expr.rowslice), **kwargs) colslice = self._print(slice(*expr.colslice), **kwargs) return parent[rowslice, colslice] def _print_BlockMatrix(self, expr, **kwargs): nrows, ncols = expr.blocks.shape blocks = [[self._print(expr.blocks[r, c], **kwargs) for c in range(ncols)] for r in range(nrows)] return tt.join(0, *[tt.join(1, *row) for row in blocks]) def _print_slice(self, expr, **kwargs): return slice(*[self._print(i, **kwargs) if isinstance(i, sympy.Basic) else i for i in (expr.start, expr.stop, expr.step)]) def _print_Pi(self, expr, **kwargs): return 3.141592653589793 def _print_Piecewise(self, expr, **kwargs): import numpy as np e, cond = expr.args[0].args # First condition and corresponding value # Print conditional expression and value for first condition p_cond = self._print(cond, **kwargs) p_e = self._print(e, **kwargs) # One condition only if len(expr.args) == 1: # Return value if condition else NaN return tt.switch(p_cond, p_e, np.nan) # Return value_1 if condition_1 else evaluate remaining conditions p_remaining = self._print(sympy.Piecewise(*expr.args[1:]), **kwargs) return tt.switch(p_cond, p_e, p_remaining) def _print_Rational(self, expr, **kwargs): return tt.true_div(self._print(expr.p, **kwargs), self._print(expr.q, **kwargs)) def _print_Integer(self, expr, **kwargs): return expr.p def _print_factorial(self, expr, **kwargs): return self._print(sympy.gamma(expr.args[0] + 1), **kwargs) def _print_Derivative(self, deriv, **kwargs): rv = self._print(deriv.expr, **kwargs) for var in deriv.variables: var = self._print(var, **kwargs) rv = tt.Rop(rv, var, tt.ones_like(var)) return rv def emptyPrinter(self, expr): return expr def doprint(self, expr, dtypes=None, broadcastables=None): """ Convert a Sympy expression to a Theano graph variable. The ``dtypes`` and ``broadcastables`` arguments are used to specify the data type, dimension, and broadcasting behavior of the Theano variables corresponding to the free symbols in ``expr``. Each is a mapping from Sympy symbols to the value of the corresponding argument to ``theano.tensor.Tensor``. See the corresponding `documentation page`__ for more information on broadcasting in Theano. .. __: http://deeplearning.net/software/theano/tutorial/broadcasting.html Parameters ========== expr : sympy.core.expr.Expr Sympy expression to print. dtypes : dict Mapping from Sympy symbols to Theano datatypes to use when creating new Theano variables for those symbols. Corresponds to the ``dtype`` argument to ``theano.tensor.Tensor``. Defaults to ``'floatX'`` for symbols not included in the mapping. broadcastables : dict Mapping from Sympy symbols to the value of the ``broadcastable`` argument to ``theano.tensor.Tensor`` to use when creating Theano variables for those symbols. Defaults to the empty tuple for symbols not included in the mapping (resulting in a scalar). Returns ======= theano.gof.graph.Variable A variable corresponding to the expression's value in a Theano symbolic expression graph. """ if dtypes is None: dtypes = {} if broadcastables is None: broadcastables = {} return self._print(expr, dtypes=dtypes, broadcastables=broadcastables) global_cache = {} # type: Dict[Any, Any] def theano_code(expr, cache=None, **kwargs): """ Convert a Sympy expression into a Theano graph variable. Parameters ========== expr : sympy.core.expr.Expr Sympy expression object to convert. cache : dict Cached Theano variables (see :class:`TheanoPrinter.cache `). Defaults to the module-level global cache. dtypes : dict Passed to :meth:`.TheanoPrinter.doprint`. broadcastables : dict Passed to :meth:`.TheanoPrinter.doprint`. Returns ======= theano.gof.graph.Variable A variable corresponding to the expression's value in a Theano symbolic expression graph. """ SymPyDeprecationWarning( feature="sympy.printing.theanocode", useinstead="Theano is deprecated; use Aesara and sympy.printing.aesaracode", issue=21150, deprecated_since_version="1.8").warn() if not theano: raise ImportError("theano is required for theano_code") if cache is None: cache = global_cache return TheanoPrinter(cache=cache, settings={}).doprint(expr, **kwargs) def dim_handling(inputs, dim=None, dims=None, broadcastables=None): r""" Get value of ``broadcastables`` argument to :func:`.theano_code` from keyword arguments to :func:`.theano_function`. Included for backwards compatibility. Parameters ========== inputs Sequence of input symbols. dim : int Common number of dimensions for all inputs. Overrides other arguments if given. dims : dict Mapping from input symbols to number of dimensions. Overrides ``broadcastables`` argument if given. broadcastables : dict Explicit value of ``broadcastables`` argument to :meth:`.TheanoPrinter.doprint`. If not None function will return this value unchanged. Returns ======= dict Dictionary mapping elements of ``inputs`` to their "broadcastable" values (tuple of ``bool``\ s). """ if dim is not None: return {s: (False,) * dim for s in inputs} if dims is not None: maxdim = max(dims.values()) return { s: (False,) * d + (True,) * (maxdim - d) for s, d in dims.items() } if broadcastables is not None: return broadcastables return {} @doctest_depends_on(modules=('theano',)) def theano_function(inputs, outputs, scalar=False, *, dim=None, dims=None, broadcastables=None, **kwargs): """ Create a Theano function from SymPy expressions. The inputs and outputs are converted to Theano variables using :func:`.theano_code` and then passed to ``theano.function``. Parameters ========== inputs Sequence of symbols which constitute the inputs of the function. outputs Sequence of expressions which constitute the outputs(s) of the function. The free symbols of each expression must be a subset of ``inputs``. scalar : bool Convert 0-dimensional arrays in output to scalars. This will return a Python wrapper function around the Theano function object. cache : dict Cached Theano variables (see :class:`TheanoPrinter.cache `). Defaults to the module-level global cache. dtypes : dict Passed to :meth:`.TheanoPrinter.doprint`. broadcastables : dict Passed to :meth:`.TheanoPrinter.doprint`. dims : dict Alternative to ``broadcastables`` argument. Mapping from elements of ``inputs`` to integers indicating the dimension of their associated arrays/tensors. Overrides ``broadcastables`` argument if given. dim : int Another alternative to the ``broadcastables`` argument. Common number of dimensions to use for all arrays/tensors. ``theano_function([x, y], [...], dim=2)`` is equivalent to using ``broadcastables={x: (False, False), y: (False, False)}``. Returns ======= callable A callable object which takes values of ``inputs`` as positional arguments and returns an output array for each of the expressions in ``outputs``. If ``outputs`` is a single expression the function will return a Numpy array, if it is a list of multiple expressions the function will return a list of arrays. See description of the ``squeeze`` argument above for the behavior when a single output is passed in a list. The returned object will either be an instance of ``theano.compile.function_module.Function`` or a Python wrapper function around one. In both cases, the returned value will have a ``theano_function`` attribute which points to the return value of ``theano.function``. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.printing.theanocode import theano_function A simple function with one input and one output: >>> f1 = theano_function([x], [x**2 - 1], scalar=True) >>> f1(3) 8.0 A function with multiple inputs and one output: >>> f2 = theano_function([x, y, z], [(x**z + y**z)**(1/z)], scalar=True) >>> f2(3, 4, 2) 5.0 A function with multiple inputs and multiple outputs: >>> f3 = theano_function([x, y], [x**2 + y**2, x**2 - y**2], scalar=True) >>> f3(2, 3) [13.0, -5.0] See also ======== dim_handling """ SymPyDeprecationWarning( feature="sympy.printing.theanocode", useinstead="Theano is deprecated; use Aesara and sympy.printing.aesaracode", issue=21150, deprecated_since_version="1.8").warn() if not theano: raise ImportError("theano is required for theano_function") # Pop off non-theano keyword args cache = kwargs.pop('cache', {}) dtypes = kwargs.pop('dtypes', {}) broadcastables = dim_handling( inputs, dim=dim, dims=dims, broadcastables=broadcastables, ) # Print inputs/outputs code = partial(theano_code, cache=cache, dtypes=dtypes, broadcastables=broadcastables) tinputs = list(map(code, inputs)) toutputs = list(map(code, outputs)) #fix constant expressions as variables toutputs = [output if isinstance(output, theano.Variable) else tt.as_tensor_variable(output) for output in toutputs] if len(toutputs) == 1: toutputs = toutputs[0] # Compile theano func func = theano.function(tinputs, toutputs, **kwargs) is_0d = [len(o.variable.broadcastable) == 0 for o in func.outputs] # No wrapper required if not scalar or not any(is_0d): func.theano_function = func return func # Create wrapper to convert 0-dimensional outputs to scalars def wrapper(*args): out = func(*args) # out can be array(1.0) or [array(1.0), array(2.0)] if is_sequence(out): return [o[()] if is_0d[i] else o for i, o in enumerate(out)] else: return out[()] wrapper.__wrapped__ = func wrapper.__doc__ = func.__doc__ wrapper.theano_function = func return wrapper sympy-sympy-1.9/sympy/printing/tree.py000066400000000000000000000074401412543434000202540ustar00rootroot00000000000000def pprint_nodes(subtrees): """ Prettyprints systems of nodes. Examples ======== >>> from sympy.printing.tree import pprint_nodes >>> print(pprint_nodes(["a", "b1\\nb2", "c"])) +-a +-b1 | b2 +-c """ def indent(s, type=1): x = s.split("\n") r = "+-%s\n" % x[0] for a in x[1:]: if a == "": continue if type == 1: r += "| %s\n" % a else: r += " %s\n" % a return r if not subtrees: return "" f = "" for a in subtrees[:-1]: f += indent(a) f += indent(subtrees[-1], 2) return f def print_node(node, assumptions=True): """ Returns information about the "node". This includes class name, string representation and assumptions. Parameters ========== assumptions : bool, optional See the ``assumptions`` keyword in ``tree`` """ s = "%s: %s\n" % (node.__class__.__name__, str(node)) if assumptions: d = node._assumptions else: d = None if d: for a in sorted(d): v = d[a] if v is None: continue s += "%s: %s\n" % (a, v) return s def tree(node, assumptions=True): """ Returns a tree representation of "node" as a string. It uses print_node() together with pprint_nodes() on node.args recursively. Parameters ========== asssumptions : bool, optional The flag to decide whether to print out all the assumption data (such as ``is_integer`, ``is_real``) associated with the expression or not. Enabling the flag makes the result verbose, and the printed result may not be determinisitic because of the randomness used in backtracing the assumptions. See Also ======== print_tree """ subtrees = [] for arg in node.args: subtrees.append(tree(arg, assumptions=assumptions)) s = print_node(node, assumptions=assumptions) + pprint_nodes(subtrees) return s def print_tree(node, assumptions=True): """ Prints a tree representation of "node". Parameters ========== asssumptions : bool, optional The flag to decide whether to print out all the assumption data (such as ``is_integer`, ``is_real``) associated with the expression or not. Enabling the flag makes the result verbose, and the printed result may not be determinisitic because of the randomness used in backtracing the assumptions. Examples ======== >>> from sympy.printing import print_tree >>> from sympy import Symbol >>> x = Symbol('x', odd=True) >>> y = Symbol('y', even=True) Printing with full assumptions information: >>> print_tree(y**x) Pow: y**x +-Symbol: y | algebraic: True | commutative: True | complex: True | even: True | extended_real: True | finite: True | hermitian: True | imaginary: False | infinite: False | integer: True | irrational: False | noninteger: False | odd: False | rational: True | real: True | transcendental: False +-Symbol: x algebraic: True commutative: True complex: True even: False extended_nonzero: True extended_real: True finite: True hermitian: True imaginary: False infinite: False integer: True irrational: False noninteger: False nonzero: True odd: True rational: True real: True transcendental: False zero: False Hiding the assumptions: >>> print_tree(y**x, assumptions=False) Pow: y**x +-Symbol: y +-Symbol: x See Also ======== tree """ print(tree(node, assumptions=assumptions)) sympy-sympy-1.9/sympy/release.py000066400000000000000000000000241412543434000170720ustar00rootroot00000000000000__version__ = "1.9" sympy-sympy-1.9/sympy/sandbox/000077500000000000000000000000001412543434000165425ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sandbox/__init__.py000066400000000000000000000002751412543434000206570ustar00rootroot00000000000000""" Sandbox module of SymPy. This module contains experimental code, use at your own risk! There is no warranty that this code will still be located here in future versions of SymPy. """ sympy-sympy-1.9/sympy/sandbox/indexed_integrals.py000066400000000000000000000037551412543434000226160ustar00rootroot00000000000000from sympy.tensor import Indexed from sympy import Integral, Dummy, sympify, Tuple class IndexedIntegral(Integral): """ Experimental class to test integration by indexed variables. Usage is analogue to ``Integral``, it simply adds awareness of integration over indices. Contraction of non-identical index symbols referring to the same ``IndexedBase`` is not yet supported. Examples ======== >>> from sympy.sandbox.indexed_integrals import IndexedIntegral >>> from sympy import IndexedBase, symbols >>> A = IndexedBase('A') >>> i, j = symbols('i j', integer=True) >>> ii = IndexedIntegral(A[i], A[i]) >>> ii Integral(_A[i], _A[i]) >>> ii.doit() A[i]**2/2 If the indices are different, indexed objects are considered to be different variables: >>> i2 = IndexedIntegral(A[j], A[i]) >>> i2 Integral(A[j], _A[i]) >>> i2.doit() A[i]*A[j] """ def __new__(cls, function, *limits, **assumptions): repl, limits = IndexedIntegral._indexed_process_limits(limits) function = sympify(function) function = function.xreplace(repl) obj = Integral.__new__(cls, function, *limits, **assumptions) obj._indexed_repl = repl obj._indexed_reverse_repl = {val: key for key, val in repl.items()} return obj def doit(self): res = super().doit() return res.xreplace(self._indexed_reverse_repl) @staticmethod def _indexed_process_limits(limits): repl = {} newlimits = [] for i in limits: if isinstance(i, (tuple, list, Tuple)): v = i[0] vrest = i[1:] else: v = i vrest = () if isinstance(v, Indexed): if v not in repl: r = Dummy(str(v)) repl[v] = r newlimits.append((r,)+vrest) else: newlimits.append(i) return repl, newlimits sympy-sympy-1.9/sympy/sandbox/tests/000077500000000000000000000000001412543434000177045ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sandbox/tests/__init__.py000066400000000000000000000000001412543434000220030ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sandbox/tests/test_indexed_integrals.py000066400000000000000000000020671412543434000250120ustar00rootroot00000000000000from sympy.sandbox.indexed_integrals import IndexedIntegral from sympy import IndexedBase, Idx, symbols, sin, cos def test_indexed_integrals(): A = IndexedBase('A') i, j = symbols('i j', integer=True) a1, a2 = symbols('a1:3', cls=Idx) assert isinstance(a1, Idx) assert IndexedIntegral(1, A[i]).doit() == A[i] assert IndexedIntegral(A[i], A[i]).doit() == A[i] ** 2 / 2 assert IndexedIntegral(A[j], A[i]).doit() == A[i] * A[j] assert IndexedIntegral(A[i] * A[j], A[i]).doit() == A[i] ** 2 * A[j] / 2 assert IndexedIntegral(sin(A[i]), A[i]).doit() == -cos(A[i]) assert IndexedIntegral(sin(A[j]), A[i]).doit() == sin(A[j]) * A[i] assert IndexedIntegral(1, A[a1]).doit() == A[a1] assert IndexedIntegral(A[a1], A[a1]).doit() == A[a1] ** 2 / 2 assert IndexedIntegral(A[a2], A[a1]).doit() == A[a1] * A[a2] assert IndexedIntegral(A[a1] * A[a2], A[a1]).doit() == A[a1] ** 2 * A[a2] / 2 assert IndexedIntegral(sin(A[a1]), A[a1]).doit() == -cos(A[a1]) assert IndexedIntegral(sin(A[a2]), A[a1]).doit() == sin(A[a2]) * A[a1] sympy-sympy-1.9/sympy/series/000077500000000000000000000000001412543434000163765ustar00rootroot00000000000000sympy-sympy-1.9/sympy/series/__init__.py000066400000000000000000000013761412543434000205160ustar00rootroot00000000000000"""A module that handles series: find a limit, order the series etc. """ from .order import Order from .limits import limit, Limit from .gruntz import gruntz from .series import series from .approximants import approximants from .residues import residue from .sequences import SeqPer, SeqFormula, sequence, SeqAdd, SeqMul from .fourier import fourier_series from .formal import fps from .limitseq import difference_delta, limit_seq from sympy.core.singleton import S EmptySequence = S.EmptySequence O = Order __all__ = ['Order', 'O', 'limit', 'Limit', 'gruntz', 'series', 'approximants', 'residue', 'EmptySequence', 'SeqPer', 'SeqFormula', 'sequence', 'SeqAdd', 'SeqMul', 'fourier_series', 'fps', 'difference_delta', 'limit_seq' ] sympy-sympy-1.9/sympy/series/acceleration.py000066400000000000000000000062611412543434000214060ustar00rootroot00000000000000""" Convergence acceleration / extrapolation methods for series and sequences. References: Carl M. Bender & Steven A. Orszag, "Advanced Mathematical Methods for Scientists and Engineers: Asymptotic Methods and Perturbation Theory", Springer 1999. (Shanks transformation: pp. 368-375, Richardson extrapolation: pp. 375-377.) """ from sympy import factorial, Integer, S def richardson(A, k, n, N): """ Calculate an approximation for lim k->oo A(k) using Richardson extrapolation with the terms A(n), A(n+1), ..., A(n+N+1). Choosing N ~= 2*n often gives good results. Examples ======== A simple example is to calculate exp(1) using the limit definition. This limit converges slowly; n = 100 only produces two accurate digits: >>> from sympy.abc import n >>> e = (1 + 1/n)**n >>> print(round(e.subs(n, 100).evalf(), 10)) 2.7048138294 Richardson extrapolation with 11 appropriately chosen terms gives a value that is accurate to the indicated precision: >>> from sympy import E >>> from sympy.series.acceleration import richardson >>> print(round(richardson(e, n, 10, 20).evalf(), 10)) 2.7182818285 >>> print(round(E.evalf(), 10)) 2.7182818285 Another useful application is to speed up convergence of series. Computing 100 terms of the zeta(2) series 1/k**2 yields only two accurate digits: >>> from sympy.abc import k, n >>> from sympy import Sum >>> A = Sum(k**-2, (k, 1, n)) >>> print(round(A.subs(n, 100).evalf(), 10)) 1.6349839002 Richardson extrapolation performs much better: >>> from sympy import pi >>> print(round(richardson(A, n, 10, 20).evalf(), 10)) 1.6449340668 >>> print(round(((pi**2)/6).evalf(), 10)) # Exact value 1.6449340668 """ s = S.Zero for j in range(0, N + 1): s += A.subs(k, Integer(n + j)).doit() * (n + j)**N * (-1)**(j + N) / \ (factorial(j) * factorial(N - j)) return s def shanks(A, k, n, m=1): """ Calculate an approximation for lim k->oo A(k) using the n-term Shanks transformation S(A)(n). With m > 1, calculate the m-fold recursive Shanks transformation S(S(...S(A)...))(n). The Shanks transformation is useful for summing Taylor series that converge slowly near a pole or singularity, e.g. for log(2): >>> from sympy.abc import k, n >>> from sympy import Sum, Integer >>> from sympy.series.acceleration import shanks >>> A = Sum(Integer(-1)**(k+1) / k, (k, 1, n)) >>> print(round(A.subs(n, 100).doit().evalf(), 10)) 0.6881721793 >>> print(round(shanks(A, n, 25).evalf(), 10)) 0.6931396564 >>> print(round(shanks(A, n, 25, 5).evalf(), 10)) 0.6931471806 The correct value is 0.6931471805599453094172321215. """ table = [A.subs(k, Integer(j)).doit() for j in range(n + m + 2)] table2 = table[:] for i in range(1, m + 1): for j in range(i, n + m + 1): x, y, z = table[j - 1], table[j], table[j + 1] table2[j] = (z*x - y**2) / (z + x - 2*y) table = table2[:] return table[n] sympy-sympy-1.9/sympy/series/approximants.py000066400000000000000000000060531412543434000215010ustar00rootroot00000000000000from sympy import Integer from sympy.core import Symbol from sympy.utilities import public @public def approximants(l, X=Symbol('x'), simplify=False): """ Return a generator for consecutive Pade approximants for a series. It can also be used for computing the rational generating function of a series when possible, since the last approximant returned by the generator will be the generating function (if any). Explanation =========== The input list can contain more complex expressions than integer or rational numbers; symbols may also be involved in the computation. An example below show how to compute the generating function of the whole Pascal triangle. The generator can be asked to apply the sympy.simplify function on each generated term, which will make the computation slower; however it may be useful when symbols are involved in the expressions. Examples ======== >>> from sympy.series import approximants >>> from sympy import lucas, fibonacci, symbols, binomial >>> g = [lucas(k) for k in range(16)] >>> [e for e in approximants(g)] [2, -4/(x - 2), (5*x - 2)/(3*x - 1), (x - 2)/(x**2 + x - 1)] >>> h = [fibonacci(k) for k in range(16)] >>> [e for e in approximants(h)] [x, -x/(x - 1), (x**2 - x)/(2*x - 1), -x/(x**2 + x - 1)] >>> x, t = symbols("x,t") >>> p=[sum(binomial(k,i)*x**i for i in range(k+1)) for k in range(16)] >>> y = approximants(p, t) >>> for k in range(3): print(next(y)) 1 (x + 1)/((-x - 1)*(t*(x + 1) + (x + 1)/(-x - 1))) nan >>> y = approximants(p, t, simplify=True) >>> for k in range(3): print(next(y)) 1 -1/(t*(x + 1) - 1) nan See Also ======== See function sympy.concrete.guess.guess_generating_function_rational and function mpmath.pade """ p1, q1 = [Integer(1)], [Integer(0)] p2, q2 = [Integer(0)], [Integer(1)] while len(l): b = 0 while l[b]==0: b += 1 if b == len(l): return m = [Integer(1)/l[b]] for k in range(b+1, len(l)): s = 0 for j in range(b, k): s -= l[j+1] * m[b-j-1] m.append(s/l[b]) l = m a, l[0] = l[0], 0 p = [0] * max(len(p2), b+len(p1)) q = [0] * max(len(q2), b+len(q1)) for k in range(len(p2)): p[k] = a*p2[k] for k in range(b, b+len(p1)): p[k] += p1[k-b] for k in range(len(q2)): q[k] = a*q2[k] for k in range(b, b+len(q1)): q[k] += q1[k-b] while p[-1]==0: p.pop() while q[-1]==0: q.pop() p1, p2 = p2, p q1, q2 = q2, q # yield result from sympy import denom, lcm, simplify as simp c = 1 for x in p: c = lcm(c, denom(x)) for x in q: c = lcm(c, denom(x)) out = ( sum(c*e*X**k for k, e in enumerate(p)) / sum(c*e*X**k for k, e in enumerate(q)) ) if simplify: yield(simp(out)) else: yield out return sympy-sympy-1.9/sympy/series/aseries.py000066400000000000000000000003771412543434000204120ustar00rootroot00000000000000from sympy.core.sympify import sympify def aseries(expr, x=None, n=6, bound=0, hir=False): """ See the docstring of Expr.aseries() for complete details of this wrapper. """ expr = sympify(expr) return expr.aseries(x, n, bound, hir) sympy-sympy-1.9/sympy/series/benchmarks/000077500000000000000000000000001412543434000205135ustar00rootroot00000000000000sympy-sympy-1.9/sympy/series/benchmarks/__init__.py000066400000000000000000000000001412543434000226120ustar00rootroot00000000000000sympy-sympy-1.9/sympy/series/benchmarks/bench_limit.py000066400000000000000000000001441412543434000233410ustar00rootroot00000000000000from sympy import Symbol, limit, oo x = Symbol('x') def timeit_limit_1x(): limit(1/x, x, oo) sympy-sympy-1.9/sympy/series/benchmarks/bench_order.py000066400000000000000000000002231412543434000233340ustar00rootroot00000000000000from sympy import Symbol, O, Add x = Symbol('x') l = list(x**i for i in range(1000)) l.append(O(x**1001)) def timeit_order_1x(): _ = Add(*l) sympy-sympy-1.9/sympy/series/formal.py000066400000000000000000001450431412543434000202370ustar00rootroot00000000000000"""Formal Power Series""" from collections import defaultdict from sympy import oo, zoo, nan from sympy.core.add import Add from sympy.core.compatibility import iterable from sympy.core.expr import Expr from sympy.core.function import Derivative, Function, expand from sympy.core.mul import Mul from sympy.core.numbers import Rational from sympy.core.relational import Eq from sympy.sets.sets import Interval from sympy.core.singleton import S from sympy.core.symbol import Wild, Dummy, symbols, Symbol from sympy.core.sympify import sympify from sympy.discrete.convolutions import convolution from sympy.functions.combinatorial.factorials import binomial, factorial, rf from sympy.functions.combinatorial.numbers import bell from sympy.functions.elementary.integers import floor, frac, ceiling from sympy.functions.elementary.miscellaneous import Min, Max from sympy.functions.elementary.piecewise import Piecewise from sympy.series.limits import Limit from sympy.series.order import Order from sympy.simplify.powsimp import powsimp from sympy.series.sequences import sequence from sympy.series.series_class import SeriesBase def rational_algorithm(f, x, k, order=4, full=False): """ Rational algorithm for computing formula of coefficients of Formal Power Series of a function. Explanation =========== Applicable when f(x) or some derivative of f(x) is a rational function in x. :func:`rational_algorithm` uses :func:`~.apart` function for partial fraction decomposition. :func:`~.apart` by default uses 'undetermined coefficients method'. By setting ``full=True``, 'Bronstein's algorithm' can be used instead. Looks for derivative of a function up to 4'th order (by default). This can be overridden using order option. Parameters ========== x : Symbol order : int, optional Order of the derivative of ``f``, Default is 4. full : bool Returns ======= formula : Expr ind : Expr Independent terms. order : int full : bool Examples ======== >>> from sympy import log, atan >>> from sympy.series.formal import rational_algorithm as ra >>> from sympy.abc import x, k >>> ra(1 / (1 - x), x, k) (1, 0, 0) >>> ra(log(1 + x), x, k) (-1/((-1)**k*k), 0, 1) >>> ra(atan(x), x, k, full=True) ((-I/(2*(-I)**k) + I/(2*I**k))/k, 0, 1) Notes ===== By setting ``full=True``, range of admissible functions to be solved using ``rational_algorithm`` can be increased. This option should be used carefully as it can significantly slow down the computation as ``doit`` is performed on the :class:`~.RootSum` object returned by the :func:`~.apart` function. Use ``full=False`` whenever possible. See Also ======== sympy.polys.partfrac.apart References ========== .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf .. [2] Power Series in Computer Algebra - Wolfram Koepf """ from sympy.polys import RootSum, apart from sympy.integrals import integrate diff = f ds = [] # list of diff for i in range(order + 1): if i: diff = diff.diff(x) if diff.is_rational_function(x): coeff, sep = S.Zero, S.Zero terms = apart(diff, x, full=full) if terms.has(RootSum): terms = terms.doit() for t in Add.make_args(terms): num, den = t.as_numer_denom() if not den.has(x): sep += t else: if isinstance(den, Mul): # m*(n*x - a)**j -> (n*x - a)**j ind = den.as_independent(x) den = ind[1] num /= ind[0] # (n*x - a)**j -> (x - b) den, j = den.as_base_exp() a, xterm = den.as_coeff_add(x) # term -> m/x**n if not a: sep += t continue xc = xterm[0].coeff(x) a /= -xc num /= xc**j ak = ((-1)**j * num * binomial(j + k - 1, k).rewrite(factorial) / a**(j + k)) coeff += ak # Hacky, better way? if coeff.is_zero: return None if (coeff.has(x) or coeff.has(zoo) or coeff.has(oo) or coeff.has(nan)): return None for j in range(i): coeff = (coeff / (k + j + 1)) sep = integrate(sep, x) sep += (ds.pop() - sep).limit(x, 0) # constant of integration return (coeff.subs(k, k - i), sep, i) else: ds.append(diff) return None def rational_independent(terms, x): """ Returns a list of all the rationally independent terms. Examples ======== >>> from sympy import sin, cos >>> from sympy.series.formal import rational_independent >>> from sympy.abc import x >>> rational_independent([cos(x), sin(x)], x) [cos(x), sin(x)] >>> rational_independent([x**2, sin(x), x*sin(x), x**3], x) [x**3 + x**2, x*sin(x) + sin(x)] """ if not terms: return [] ind = terms[0:1] for t in terms[1:]: n = t.as_independent(x)[1] for i, term in enumerate(ind): d = term.as_independent(x)[1] q = (n / d).cancel() if q.is_rational_function(x): ind[i] += t break else: ind.append(t) return ind def simpleDE(f, x, g, order=4): r""" Generates simple DE. Explanation =========== DE is of the form .. math:: f^k(x) + \sum\limits_{j=0}^{k-1} A_j f^j(x) = 0 where :math:`A_j` should be rational function in x. Generates DE's upto order 4 (default). DE's can also have free parameters. By increasing order, higher order DE's can be found. Yields a tuple of (DE, order). """ from sympy.solvers.solveset import linsolve a = symbols('a:%d' % (order)) def _makeDE(k): eq = f.diff(x, k) + Add(*[a[i]*f.diff(x, i) for i in range(0, k)]) DE = g(x).diff(x, k) + Add(*[a[i]*g(x).diff(x, i) for i in range(0, k)]) return eq, DE found = False for k in range(1, order + 1): eq, DE = _makeDE(k) eq = eq.expand() terms = eq.as_ordered_terms() ind = rational_independent(terms, x) if found or len(ind) == k: sol = dict(zip(a, (i for s in linsolve(ind, a[:k]) for i in s))) if sol: found = True DE = DE.subs(sol) DE = DE.as_numer_denom()[0] DE = DE.factor().as_coeff_mul(Derivative)[1][0] yield DE.collect(Derivative(g(x))), k def exp_re(DE, r, k): """Converts a DE with constant coefficients (explike) into a RE. Explanation =========== Performs the substitution: .. math:: f^j(x) \\to r(k + j) Normalises the terms so that lowest order of a term is always r(k). Examples ======== >>> from sympy import Function, Derivative >>> from sympy.series.formal import exp_re >>> from sympy.abc import x, k >>> f, r = Function('f'), Function('r') >>> exp_re(-f(x) + Derivative(f(x)), r, k) -r(k) + r(k + 1) >>> exp_re(Derivative(f(x), x) + Derivative(f(x), (x, 2)), r, k) r(k) + r(k + 1) See Also ======== sympy.series.formal.hyper_re """ RE = S.Zero g = DE.atoms(Function).pop() mini = None for t in Add.make_args(DE): coeff, d = t.as_independent(g) if isinstance(d, Derivative): j = d.derivative_count else: j = 0 if mini is None or j < mini: mini = j RE += coeff * r(k + j) if mini: RE = RE.subs(k, k - mini) return RE def hyper_re(DE, r, k): """ Converts a DE into a RE. Explanation =========== Performs the substitution: .. math:: x^l f^j(x) \\to (k + 1 - l)_j . a_{k + j - l} Normalises the terms so that lowest order of a term is always r(k). Examples ======== >>> from sympy import Function, Derivative >>> from sympy.series.formal import hyper_re >>> from sympy.abc import x, k >>> f, r = Function('f'), Function('r') >>> hyper_re(-f(x) + Derivative(f(x)), r, k) (k + 1)*r(k + 1) - r(k) >>> hyper_re(-x*f(x) + Derivative(f(x), (x, 2)), r, k) (k + 2)*(k + 3)*r(k + 3) - r(k) See Also ======== sympy.series.formal.exp_re """ RE = S.Zero g = DE.atoms(Function).pop() x = g.atoms(Symbol).pop() mini = None for t in Add.make_args(DE.expand()): coeff, d = t.as_independent(g) c, v = coeff.as_independent(x) l = v.as_coeff_exponent(x)[1] if isinstance(d, Derivative): j = d.derivative_count else: j = 0 RE += c * rf(k + 1 - l, j) * r(k + j - l) if mini is None or j - l < mini: mini = j - l RE = RE.subs(k, k - mini) m = Wild('m') return RE.collect(r(k + m)) def _transformation_a(f, x, P, Q, k, m, shift): f *= x**(-shift) P = P.subs(k, k + shift) Q = Q.subs(k, k + shift) return f, P, Q, m def _transformation_c(f, x, P, Q, k, m, scale): f = f.subs(x, x**scale) P = P.subs(k, k / scale) Q = Q.subs(k, k / scale) m *= scale return f, P, Q, m def _transformation_e(f, x, P, Q, k, m): f = f.diff(x) P = P.subs(k, k + 1) * (k + m + 1) Q = Q.subs(k, k + 1) * (k + 1) return f, P, Q, m def _apply_shift(sol, shift): return [(res, cond + shift) for res, cond in sol] def _apply_scale(sol, scale): return [(res, cond / scale) for res, cond in sol] def _apply_integrate(sol, x, k): return [(res / ((cond + 1)*(cond.as_coeff_Add()[1].coeff(k))), cond + 1) for res, cond in sol] def _compute_formula(f, x, P, Q, k, m, k_max): """Computes the formula for f.""" from sympy.polys import roots sol = [] for i in range(k_max + 1, k_max + m + 1): if (i < 0) == True: continue r = f.diff(x, i).limit(x, 0) / factorial(i) if r.is_zero: continue kterm = m*k + i res = r p = P.subs(k, kterm) q = Q.subs(k, kterm) c1 = p.subs(k, 1/k).leadterm(k)[0] c2 = q.subs(k, 1/k).leadterm(k)[0] res *= (-c1 / c2)**k for r, mul in roots(p, k).items(): res *= rf(-r, k)**mul for r, mul in roots(q, k).items(): res /= rf(-r, k)**mul sol.append((res, kterm)) return sol def _rsolve_hypergeometric(f, x, P, Q, k, m): """ Recursive wrapper to rsolve_hypergeometric. Explanation =========== Returns a Tuple of (formula, series independent terms, maximum power of x in independent terms) if successful otherwise ``None``. See :func:`rsolve_hypergeometric` for details. """ from sympy.polys import lcm, roots from sympy.integrals import integrate # transformation - c proots, qroots = roots(P, k), roots(Q, k) all_roots = dict(proots) all_roots.update(qroots) scale = lcm([r.as_numer_denom()[1] for r, t in all_roots.items() if r.is_rational]) f, P, Q, m = _transformation_c(f, x, P, Q, k, m, scale) # transformation - a qroots = roots(Q, k) if qroots: k_min = Min(*qroots.keys()) else: k_min = S.Zero shift = k_min + m f, P, Q, m = _transformation_a(f, x, P, Q, k, m, shift) l = (x*f).limit(x, 0) if not isinstance(l, Limit) and l != 0: # Ideally should only be l != 0 return None qroots = roots(Q, k) if qroots: k_max = Max(*qroots.keys()) else: k_max = S.Zero ind, mp = S.Zero, -oo for i in range(k_max + m + 1): r = f.diff(x, i).limit(x, 0) / factorial(i) if r.is_finite is False: old_f = f f, P, Q, m = _transformation_a(f, x, P, Q, k, m, i) f, P, Q, m = _transformation_e(f, x, P, Q, k, m) sol, ind, mp = _rsolve_hypergeometric(f, x, P, Q, k, m) sol = _apply_integrate(sol, x, k) sol = _apply_shift(sol, i) ind = integrate(ind, x) ind += (old_f - ind).limit(x, 0) # constant of integration mp += 1 return sol, ind, mp elif r: ind += r*x**(i + shift) pow_x = Rational((i + shift), scale) if pow_x > mp: mp = pow_x # maximum power of x ind = ind.subs(x, x**(1/scale)) sol = _compute_formula(f, x, P, Q, k, m, k_max) sol = _apply_shift(sol, shift) sol = _apply_scale(sol, scale) return sol, ind, mp def rsolve_hypergeometric(f, x, P, Q, k, m): """ Solves RE of hypergeometric type. Explanation =========== Attempts to solve RE of the form Q(k)*a(k + m) - P(k)*a(k) Transformations that preserve Hypergeometric type: a. x**n*f(x): b(k + m) = R(k - n)*b(k) b. f(A*x): b(k + m) = A**m*R(k)*b(k) c. f(x**n): b(k + n*m) = R(k/n)*b(k) d. f(x**(1/m)): b(k + 1) = R(k*m)*b(k) e. f'(x): b(k + m) = ((k + m + 1)/(k + 1))*R(k + 1)*b(k) Some of these transformations have been used to solve the RE. Returns ======= formula : Expr ind : Expr Independent terms. order : int Examples ======== >>> from sympy import exp, ln, S >>> from sympy.series.formal import rsolve_hypergeometric as rh >>> from sympy.abc import x, k >>> rh(exp(x), x, -S.One, (k + 1), k, 1) (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1) >>> rh(ln(1 + x), x, k**2, k*(k + 1), k, 1) (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1), Eq(Mod(k, 1), 0)), (0, True)), x, 2) References ========== .. [1] Formal Power Series - Dominik Gruntz, Wolfram Koepf .. [2] Power Series in Computer Algebra - Wolfram Koepf """ result = _rsolve_hypergeometric(f, x, P, Q, k, m) if result is None: return None sol_list, ind, mp = result sol_dict = defaultdict(lambda: S.Zero) for res, cond in sol_list: j, mk = cond.as_coeff_Add() c = mk.coeff(k) if j.is_integer is False: res *= x**frac(j) j = floor(j) res = res.subs(k, (k - j) / c) cond = Eq(k % c, j % c) sol_dict[cond] += res # Group together formula for same conditions sol = [] for cond, res in sol_dict.items(): sol.append((res, cond)) sol.append((S.Zero, True)) sol = Piecewise(*sol) if mp is -oo: s = S.Zero elif mp.is_integer is False: s = ceiling(mp) else: s = mp + 1 # save all the terms of # form 1/x**k in ind if s < 0: ind += sum(sequence(sol * x**k, (k, s, -1))) s = S.Zero return (sol, ind, s) def _solve_hyper_RE(f, x, RE, g, k): """See docstring of :func:`rsolve_hypergeometric` for details.""" terms = Add.make_args(RE) if len(terms) == 2: gs = list(RE.atoms(Function)) P, Q = map(RE.coeff, gs) m = gs[1].args[0] - gs[0].args[0] if m < 0: P, Q = Q, P m = abs(m) return rsolve_hypergeometric(f, x, P, Q, k, m) def _solve_explike_DE(f, x, DE, g, k): """Solves DE with constant coefficients.""" from sympy.solvers import rsolve for t in Add.make_args(DE): coeff, d = t.as_independent(g) if coeff.free_symbols: return RE = exp_re(DE, g, k) init = {} for i in range(len(Add.make_args(RE))): if i: f = f.diff(x) init[g(k).subs(k, i)] = f.limit(x, 0) sol = rsolve(RE, g(k), init) if sol: return (sol / factorial(k), S.Zero, S.Zero) def _solve_simple(f, x, DE, g, k): """Converts DE into RE and solves using :func:`rsolve`.""" from sympy.solvers import rsolve RE = hyper_re(DE, g, k) init = {} for i in range(len(Add.make_args(RE))): if i: f = f.diff(x) init[g(k).subs(k, i)] = f.limit(x, 0) / factorial(i) sol = rsolve(RE, g(k), init) if sol: return (sol, S.Zero, S.Zero) def _transform_explike_DE(DE, g, x, order, syms): """Converts DE with free parameters into DE with constant coefficients.""" from sympy.solvers.solveset import linsolve eq = [] highest_coeff = DE.coeff(Derivative(g(x), x, order)) for i in range(order): coeff = DE.coeff(Derivative(g(x), x, i)) coeff = (coeff / highest_coeff).expand().collect(x) for t in Add.make_args(coeff): eq.append(t) temp = [] for e in eq: if e.has(x): break elif e.has(Symbol): temp.append(e) else: eq = temp if eq: sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s))) if sol: DE = DE.subs(sol) DE = DE.factor().as_coeff_mul(Derivative)[1][0] DE = DE.collect(Derivative(g(x))) return DE def _transform_DE_RE(DE, g, k, order, syms): """Converts DE with free parameters into RE of hypergeometric type.""" from sympy.solvers.solveset import linsolve RE = hyper_re(DE, g, k) eq = [] for i in range(1, order): coeff = RE.coeff(g(k + i)) eq.append(coeff) sol = dict(zip(syms, (i for s in linsolve(eq, list(syms)) for i in s))) if sol: m = Wild('m') RE = RE.subs(sol) RE = RE.factor().as_numer_denom()[0].collect(g(k + m)) RE = RE.as_coeff_mul(g)[1][0] for i in range(order): # smallest order should be g(k) if RE.coeff(g(k + i)) and i: RE = RE.subs(k, k - i) break return RE def solve_de(f, x, DE, order, g, k): """ Solves the DE. Explanation =========== Tries to solve DE by either converting into a RE containing two terms or converting into a DE having constant coefficients. Returns ======= formula : Expr ind : Expr Independent terms. order : int Examples ======== >>> from sympy import Derivative as D, Function >>> from sympy import exp, ln >>> from sympy.series.formal import solve_de >>> from sympy.abc import x, k >>> f = Function('f') >>> solve_de(exp(x), x, D(f(x), x) - f(x), 1, f, k) (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1) >>> solve_de(ln(1 + x), x, (x + 1)*D(f(x), x, 2) + D(f(x)), 2, f, k) (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1), Eq(Mod(k, 1), 0)), (0, True)), x, 2) """ sol = None syms = DE.free_symbols.difference({g, x}) if syms: RE = _transform_DE_RE(DE, g, k, order, syms) else: RE = hyper_re(DE, g, k) if not RE.free_symbols.difference({k}): sol = _solve_hyper_RE(f, x, RE, g, k) if sol: return sol if syms: DE = _transform_explike_DE(DE, g, x, order, syms) if not DE.free_symbols.difference({x}): sol = _solve_explike_DE(f, x, DE, g, k) if sol: return sol def hyper_algorithm(f, x, k, order=4): """ Hypergeometric algorithm for computing Formal Power Series. Explanation =========== Steps: * Generates DE * Convert the DE into RE * Solves the RE Examples ======== >>> from sympy import exp, ln >>> from sympy.series.formal import hyper_algorithm >>> from sympy.abc import x, k >>> hyper_algorithm(exp(x), x, k) (Piecewise((1/factorial(k), Eq(Mod(k, 1), 0)), (0, True)), 1, 1) >>> hyper_algorithm(ln(1 + x), x, k) (Piecewise(((-1)**(k - 1)*factorial(k - 1)/RisingFactorial(2, k - 1), Eq(Mod(k, 1), 0)), (0, True)), x, 2) See Also ======== sympy.series.formal.simpleDE sympy.series.formal.solve_de """ g = Function('g') des = [] # list of DE's sol = None for DE, i in simpleDE(f, x, g, order): if DE is not None: sol = solve_de(f, x, DE, i, g, k) if sol: return sol if not DE.free_symbols.difference({x}): des.append(DE) # If nothing works # Try plain rsolve for DE in des: sol = _solve_simple(f, x, DE, g, k) if sol: return sol def _compute_fps(f, x, x0, dir, hyper, order, rational, full): """Recursive wrapper to compute fps. See :func:`compute_fps` for details. """ if x0 in [S.Infinity, S.NegativeInfinity]: dir = S.One if x0 is S.Infinity else -S.One temp = f.subs(x, 1/x) result = _compute_fps(temp, x, 0, dir, hyper, order, rational, full) if result is None: return None return (result[0], result[1].subs(x, 1/x), result[2].subs(x, 1/x)) elif x0 or dir == -S.One: if dir == -S.One: rep = -x + x0 rep2 = -x rep2b = x0 else: rep = x + x0 rep2 = x rep2b = -x0 temp = f.subs(x, rep) result = _compute_fps(temp, x, 0, S.One, hyper, order, rational, full) if result is None: return None return (result[0], result[1].subs(x, rep2 + rep2b), result[2].subs(x, rep2 + rep2b)) if f.is_polynomial(x): k = Dummy('k') ak = sequence(Coeff(f, x, k), (k, 1, oo)) xk = sequence(x**k, (k, 0, oo)) ind = f.coeff(x, 0) return ak, xk, ind # Break instances of Add # this allows application of different # algorithms on different terms increasing the # range of admissible functions. if isinstance(f, Add): result = False ak = sequence(S.Zero, (0, oo)) ind, xk = S.Zero, None for t in Add.make_args(f): res = _compute_fps(t, x, 0, S.One, hyper, order, rational, full) if res: if not result: result = True xk = res[1] if res[0].start > ak.start: seq = ak s, f = ak.start, res[0].start else: seq = res[0] s, f = res[0].start, ak.start save = Add(*[z[0]*z[1] for z in zip(seq[0:(f - s)], xk[s:f])]) ak += res[0] ind += res[2] + save else: ind += t if result: return ak, xk, ind return None # The symbolic term - symb, if present, is being separated from the function # Otherwise symb is being set to S.One syms = f.free_symbols.difference({x}) (f, symb) = expand(f).as_independent(*syms) if symb.is_zero: symb = S.One symb = powsimp(symb) result = None # from here on it's x0=0 and dir=1 handling k = Dummy('k') if rational: result = rational_algorithm(f, x, k, order, full) if result is None and hyper: result = hyper_algorithm(f, x, k, order) if result is None: return None ak = sequence(result[0], (k, result[2], oo)) xk_formula = powsimp(x**k * symb) xk = sequence(xk_formula, (k, 0, oo)) ind = powsimp(result[1] * symb) return ak, xk, ind def compute_fps(f, x, x0=0, dir=1, hyper=True, order=4, rational=True, full=False): """ Computes the formula for Formal Power Series of a function. Explanation =========== Tries to compute the formula by applying the following techniques (in order): * rational_algorithm * Hypergeometric algorithm Parameters ========== x : Symbol x0 : number, optional Point to perform series expansion about. Default is 0. dir : {1, -1, '+', '-'}, optional If dir is 1 or '+' the series is calculated from the right and for -1 or '-' the series is calculated from the left. For smooth functions this flag will not alter the results. Default is 1. hyper : {True, False}, optional Set hyper to False to skip the hypergeometric algorithm. By default it is set to False. order : int, optional Order of the derivative of ``f``, Default is 4. rational : {True, False}, optional Set rational to False to skip rational algorithm. By default it is set to True. full : {True, False}, optional Set full to True to increase the range of rational algorithm. See :func:`rational_algorithm` for details. By default it is set to False. Returns ======= ak : sequence Sequence of coefficients. xk : sequence Sequence of powers of x. ind : Expr Independent terms. mul : Pow Common terms. See Also ======== sympy.series.formal.rational_algorithm sympy.series.formal.hyper_algorithm """ f = sympify(f) x = sympify(x) if not f.has(x): return None x0 = sympify(x0) if dir == '+': dir = S.One elif dir == '-': dir = -S.One elif dir not in [S.One, -S.One]: raise ValueError("Dir must be '+' or '-'") else: dir = sympify(dir) return _compute_fps(f, x, x0, dir, hyper, order, rational, full) class Coeff(Function): """ Coeff(p, x, n) represents the nth coefficient of the polynomial p in x """ @classmethod def eval(cls, p, x, n): if p.is_polynomial(x) and n.is_integer: return p.coeff(x, n) class FormalPowerSeries(SeriesBase): """ Represents Formal Power Series of a function. Explanation =========== No computation is performed. This class should only to be used to represent a series. No checks are performed. For computing a series use :func:`fps`. See Also ======== sympy.series.formal.fps """ def __new__(cls, *args): args = map(sympify, args) return Expr.__new__(cls, *args) def __init__(self, *args): ak = args[4][0] k = ak.variables[0] self.ak_seq = sequence(ak.formula, (k, 1, oo)) self.fact_seq = sequence(factorial(k), (k, 1, oo)) self.bell_coeff_seq = self.ak_seq * self.fact_seq self.sign_seq = sequence((-1, 1), (k, 1, oo)) @property def function(self): return self.args[0] @property def x(self): return self.args[1] @property def x0(self): return self.args[2] @property def dir(self): return self.args[3] @property def ak(self): return self.args[4][0] @property def xk(self): return self.args[4][1] @property def ind(self): return self.args[4][2] @property def interval(self): return Interval(0, oo) @property def start(self): return self.interval.inf @property def stop(self): return self.interval.sup @property def length(self): return oo @property def infinite(self): """Returns an infinite representation of the series""" from sympy.concrete import Sum ak, xk = self.ak, self.xk k = ak.variables[0] inf_sum = Sum(ak.formula * xk.formula, (k, ak.start, ak.stop)) return self.ind + inf_sum def _get_pow_x(self, term): """Returns the power of x in a term.""" xterm, pow_x = term.as_independent(self.x)[1].as_base_exp() if not xterm.has(self.x): return S.Zero return pow_x def polynomial(self, n=6): """ Truncated series as polynomial. Explanation =========== Returns series expansion of ``f`` upto order ``O(x**n)`` as a polynomial(without ``O`` term). """ terms = [] sym = self.free_symbols for i, t in enumerate(self): xp = self._get_pow_x(t) if xp.has(*sym): xp = xp.as_coeff_add(*sym)[0] if xp >= n: break elif xp.is_integer is True and i == n + 1: break elif t is not S.Zero: terms.append(t) return Add(*terms) def truncate(self, n=6): """ Truncated series. Explanation =========== Returns truncated series expansion of f upto order ``O(x**n)``. If n is ``None``, returns an infinite iterator. """ if n is None: return iter(self) x, x0 = self.x, self.x0 pt_xk = self.xk.coeff(n) if x0 is S.NegativeInfinity: x0 = S.Infinity return self.polynomial(n) + Order(pt_xk, (x, x0)) def zero_coeff(self): return self._eval_term(0) def _eval_term(self, pt): try: pt_xk = self.xk.coeff(pt) pt_ak = self.ak.coeff(pt).simplify() # Simplify the coefficients except IndexError: term = S.Zero else: term = (pt_ak * pt_xk) if self.ind: ind = S.Zero sym = self.free_symbols for t in Add.make_args(self.ind): pow_x = self._get_pow_x(t) if pow_x.has(*sym): pow_x = pow_x.as_coeff_add(*sym)[0] if pt == 0 and pow_x < 1: ind += t elif pow_x >= pt and pow_x < pt + 1: ind += t term += ind return term.collect(self.x) def _eval_subs(self, old, new): x = self.x if old.has(x): return self def _eval_as_leading_term(self, x, logx=None, cdir=0): for t in self: if t is not S.Zero: return t def _eval_derivative(self, x): f = self.function.diff(x) ind = self.ind.diff(x) pow_xk = self._get_pow_x(self.xk.formula) ak = self.ak k = ak.variables[0] if ak.formula.has(x): form = [] for e, c in ak.formula.args: temp = S.Zero for t in Add.make_args(e): pow_x = self._get_pow_x(t) temp += t * (pow_xk + pow_x) form.append((temp, c)) form = Piecewise(*form) ak = sequence(form.subs(k, k + 1), (k, ak.start - 1, ak.stop)) else: ak = sequence((ak.formula * pow_xk).subs(k, k + 1), (k, ak.start - 1, ak.stop)) return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind)) def integrate(self, x=None, **kwargs): """ Integrate Formal Power Series. Examples ======== >>> from sympy import fps, sin, integrate >>> from sympy.abc import x >>> f = fps(sin(x)) >>> f.integrate(x).truncate() -1 + x**2/2 - x**4/24 + O(x**6) >>> integrate(f, (x, 0, 1)) 1 - cos(1) """ from sympy.integrals import integrate if x is None: x = self.x elif iterable(x): return integrate(self.function, x) f = integrate(self.function, x) ind = integrate(self.ind, x) ind += (f - ind).limit(x, 0) # constant of integration pow_xk = self._get_pow_x(self.xk.formula) ak = self.ak k = ak.variables[0] if ak.formula.has(x): form = [] for e, c in ak.formula.args: temp = S.Zero for t in Add.make_args(e): pow_x = self._get_pow_x(t) temp += t / (pow_xk + pow_x + 1) form.append((temp, c)) form = Piecewise(*form) ak = sequence(form.subs(k, k - 1), (k, ak.start + 1, ak.stop)) else: ak = sequence((ak.formula / (pow_xk + 1)).subs(k, k - 1), (k, ak.start + 1, ak.stop)) return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind)) def product(self, other, x=None, n=6): """ Multiplies two Formal Power Series, using discrete convolution and return the truncated terms upto specified order. Parameters ========== n : Number, optional Specifies the order of the term up to which the polynomial should be truncated. Examples ======== >>> from sympy import fps, sin, exp >>> from sympy.abc import x >>> f1 = fps(sin(x)) >>> f2 = fps(exp(x)) >>> f1.product(f2, x).truncate(4) x + x**2 + x**3/3 + O(x**4) See Also ======== sympy.discrete.convolutions sympy.series.formal.FormalPowerSeriesProduct """ if n is None: return iter(self) other = sympify(other) if not isinstance(other, FormalPowerSeries): raise ValueError("Both series should be an instance of FormalPowerSeries" " class.") if self.dir != other.dir: raise ValueError("Both series should be calculated from the" " same direction.") elif self.x0 != other.x0: raise ValueError("Both series should be calculated about the" " same point.") elif self.x != other.x: raise ValueError("Both series should have the same symbol.") return FormalPowerSeriesProduct(self, other) def coeff_bell(self, n): r""" self.coeff_bell(n) returns a sequence of Bell polynomials of the second kind. Note that ``n`` should be a integer. The second kind of Bell polynomials (are sometimes called "partial" Bell polynomials or incomplete Bell polynomials) are defined as .. math:: B_{n,k}(x_1, x_2,\dotsc x_{n-k+1}) = \sum_{j_1+j_2+j_2+\dotsb=k \atop j_1+2j_2+3j_2+\dotsb=n} \frac{n!}{j_1!j_2!\dotsb j_{n-k+1}!} \left(\frac{x_1}{1!} \right)^{j_1} \left(\frac{x_2}{2!} \right)^{j_2} \dotsb \left(\frac{x_{n-k+1}}{(n-k+1)!} \right) ^{j_{n-k+1}}. * ``bell(n, k, (x1, x2, ...))`` gives Bell polynomials of the second kind, `B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1})`. See Also ======== sympy.functions.combinatorial.numbers.bell """ inner_coeffs = [bell(n, j, tuple(self.bell_coeff_seq[:n-j+1])) for j in range(1, n+1)] k = Dummy('k') return sequence(tuple(inner_coeffs), (k, 1, oo)) def compose(self, other, x=None, n=6): r""" Returns the truncated terms of the formal power series of the composed function, up to specified ``n``. Explanation =========== If ``f`` and ``g`` are two formal power series of two different functions, then the coefficient sequence ``ak`` of the composed formal power series `fp` will be as follows. .. math:: \sum\limits_{k=0}^{n} b_k B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1}) Parameters ========== n : Number, optional Specifies the order of the term up to which the polynomial should be truncated. Examples ======== >>> from sympy import fps, sin, exp >>> from sympy.abc import x >>> f1 = fps(exp(x)) >>> f2 = fps(sin(x)) >>> f1.compose(f2, x).truncate() 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6) >>> f1.compose(f2, x).truncate(8) 1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + O(x**8) See Also ======== sympy.functions.combinatorial.numbers.bell sympy.series.formal.FormalPowerSeriesCompose References ========== .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974. """ if n is None: return iter(self) other = sympify(other) if not isinstance(other, FormalPowerSeries): raise ValueError("Both series should be an instance of FormalPowerSeries" " class.") if self.dir != other.dir: raise ValueError("Both series should be calculated from the" " same direction.") elif self.x0 != other.x0: raise ValueError("Both series should be calculated about the" " same point.") elif self.x != other.x: raise ValueError("Both series should have the same symbol.") if other._eval_term(0).as_coeff_mul(other.x)[0] is not S.Zero: raise ValueError("The formal power series of the inner function should not have any " "constant coefficient term.") return FormalPowerSeriesCompose(self, other) def inverse(self, x=None, n=6): r""" Returns the truncated terms of the inverse of the formal power series, up to specified ``n``. Explanation =========== If ``f`` and ``g`` are two formal power series of two different functions, then the coefficient sequence ``ak`` of the composed formal power series ``fp`` will be as follows. .. math:: \sum\limits_{k=0}^{n} (-1)^{k} x_0^{-k-1} B_{n,k}(x_1, x_2, \dotsc, x_{n-k+1}) Parameters ========== n : Number, optional Specifies the order of the term up to which the polynomial should be truncated. Examples ======== >>> from sympy import fps, exp, cos >>> from sympy.abc import x >>> f1 = fps(exp(x)) >>> f2 = fps(cos(x)) >>> f1.inverse(x).truncate() 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + O(x**6) >>> f2.inverse(x).truncate(8) 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + O(x**8) See Also ======== sympy.functions.combinatorial.numbers.bell sympy.series.formal.FormalPowerSeriesInverse References ========== .. [1] Comtet, Louis: Advanced combinatorics; the art of finite and infinite expansions. Reidel, 1974. """ if n is None: return iter(self) if self._eval_term(0).is_zero: raise ValueError("Constant coefficient should exist for an inverse of a formal" " power series to exist.") return FormalPowerSeriesInverse(self) def __add__(self, other): other = sympify(other) if isinstance(other, FormalPowerSeries): if self.dir != other.dir: raise ValueError("Both series should be calculated from the" " same direction.") elif self.x0 != other.x0: raise ValueError("Both series should be calculated about the" " same point.") x, y = self.x, other.x f = self.function + other.function.subs(y, x) if self.x not in f.free_symbols: return f ak = self.ak + other.ak if self.ak.start > other.ak.start: seq = other.ak s, e = other.ak.start, self.ak.start else: seq = self.ak s, e = self.ak.start, other.ak.start save = Add(*[z[0]*z[1] for z in zip(seq[0:(e - s)], self.xk[s:e])]) ind = self.ind + other.ind + save return self.func(f, x, self.x0, self.dir, (ak, self.xk, ind)) elif not other.has(self.x): f = self.function + other ind = self.ind + other return self.func(f, self.x, self.x0, self.dir, (self.ak, self.xk, ind)) return Add(self, other) def __radd__(self, other): return self.__add__(other) def __neg__(self): return self.func(-self.function, self.x, self.x0, self.dir, (-self.ak, self.xk, -self.ind)) def __sub__(self, other): return self.__add__(-other) def __rsub__(self, other): return (-self).__add__(other) def __mul__(self, other): other = sympify(other) if other.has(self.x): return Mul(self, other) f = self.function * other ak = self.ak.coeff_mul(other) ind = self.ind * other return self.func(f, self.x, self.x0, self.dir, (ak, self.xk, ind)) def __rmul__(self, other): return self.__mul__(other) class FiniteFormalPowerSeries(FormalPowerSeries): """Base Class for Product, Compose and Inverse classes""" def __init__(self, *args): pass @property def ffps(self): return self.args[0] @property def gfps(self): return self.args[1] @property def f(self): return self.ffps.function @property def g(self): return self.gfps.function @property def infinite(self): raise NotImplementedError("No infinite version for an object of" " FiniteFormalPowerSeries class.") def _eval_terms(self, n): raise NotImplementedError("(%s)._eval_terms()" % self) def _eval_term(self, pt): raise NotImplementedError("By the current logic, one can get terms" "upto a certain order, instead of getting term by term.") def polynomial(self, n): return self._eval_terms(n) def truncate(self, n=6): ffps = self.ffps pt_xk = ffps.xk.coeff(n) x, x0 = ffps.x, ffps.x0 return self.polynomial(n) + Order(pt_xk, (x, x0)) def _eval_derivative(self, x): raise NotImplementedError def integrate(self, x): raise NotImplementedError class FormalPowerSeriesProduct(FiniteFormalPowerSeries): """Represents the product of two formal power series of two functions. Explanation =========== No computation is performed. Terms are calculated using a term by term logic, instead of a point by point logic. There are two differences between a :obj:`FormalPowerSeries` object and a :obj:`FormalPowerSeriesProduct` object. The first argument contains the two functions involved in the product. Also, the coefficient sequence contains both the coefficient sequence of the formal power series of the involved functions. See Also ======== sympy.series.formal.FormalPowerSeries sympy.series.formal.FiniteFormalPowerSeries """ def __init__(self, *args): ffps, gfps = self.ffps, self.gfps k = ffps.ak.variables[0] self.coeff1 = sequence(ffps.ak.formula, (k, 0, oo)) k = gfps.ak.variables[0] self.coeff2 = sequence(gfps.ak.formula, (k, 0, oo)) @property def function(self): """Function of the product of two formal power series.""" return self.f * self.g def _eval_terms(self, n): """ Returns the first ``n`` terms of the product formal power series. Term by term logic is implemented here. Examples ======== >>> from sympy import fps, sin, exp >>> from sympy.abc import x >>> f1 = fps(sin(x)) >>> f2 = fps(exp(x)) >>> fprod = f1.product(f2, x) >>> fprod._eval_terms(4) x**3/3 + x**2 + x See Also ======== sympy.series.formal.FormalPowerSeries.product """ coeff1, coeff2 = self.coeff1, self.coeff2 aks = convolution(coeff1[:n], coeff2[:n]) terms = [] for i in range(0, n): terms.append(aks[i] * self.ffps.xk.coeff(i)) return Add(*terms) class FormalPowerSeriesCompose(FiniteFormalPowerSeries): """ Represents the composed formal power series of two functions. Explanation =========== No computation is performed. Terms are calculated using a term by term logic, instead of a point by point logic. There are two differences between a :obj:`FormalPowerSeries` object and a :obj:`FormalPowerSeriesCompose` object. The first argument contains the outer function and the inner function involved in the omposition. Also, the coefficient sequence contains the generic sequence which is to be multiplied by a custom ``bell_seq`` finite sequence. The finite terms will then be added up to get the final terms. See Also ======== sympy.series.formal.FormalPowerSeries sympy.series.formal.FiniteFormalPowerSeries """ @property def function(self): """Function for the composed formal power series.""" f, g, x = self.f, self.g, self.ffps.x return f.subs(x, g) def _eval_terms(self, n): """ Returns the first `n` terms of the composed formal power series. Term by term logic is implemented here. Explanation =========== The coefficient sequence of the :obj:`FormalPowerSeriesCompose` object is the generic sequence. It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get the final terms for the polynomial. Examples ======== >>> from sympy import fps, sin, exp >>> from sympy.abc import x >>> f1 = fps(exp(x)) >>> f2 = fps(sin(x)) >>> fcomp = f1.compose(f2, x) >>> fcomp._eval_terms(6) -x**5/15 - x**4/8 + x**2/2 + x + 1 >>> fcomp._eval_terms(8) x**7/90 - x**6/240 - x**5/15 - x**4/8 + x**2/2 + x + 1 See Also ======== sympy.series.formal.FormalPowerSeries.compose sympy.series.formal.FormalPowerSeries.coeff_bell """ ffps, gfps = self.ffps, self.gfps terms = [ffps.zero_coeff()] for i in range(1, n): bell_seq = gfps.coeff_bell(i) seq = (ffps.bell_coeff_seq * bell_seq) terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i)) return Add(*terms) class FormalPowerSeriesInverse(FiniteFormalPowerSeries): """ Represents the Inverse of a formal power series. Explanation =========== No computation is performed. Terms are calculated using a term by term logic, instead of a point by point logic. There is a single difference between a :obj:`FormalPowerSeries` object and a :obj:`FormalPowerSeriesInverse` object. The coefficient sequence contains the generic sequence which is to be multiplied by a custom ``bell_seq`` finite sequence. The finite terms will then be added up to get the final terms. See Also ======== sympy.series.formal.FormalPowerSeries sympy.series.formal.FiniteFormalPowerSeries """ def __init__(self, *args): ffps = self.ffps k = ffps.xk.variables[0] inv = ffps.zero_coeff() inv_seq = sequence(inv ** (-(k + 1)), (k, 1, oo)) self.aux_seq = ffps.sign_seq * ffps.fact_seq * inv_seq @property def function(self): """Function for the inverse of a formal power series.""" f = self.f return 1 / f @property def g(self): raise ValueError("Only one function is considered while performing" "inverse of a formal power series.") @property def gfps(self): raise ValueError("Only one function is considered while performing" "inverse of a formal power series.") def _eval_terms(self, n): """ Returns the first ``n`` terms of the composed formal power series. Term by term logic is implemented here. Explanation =========== The coefficient sequence of the `FormalPowerSeriesInverse` object is the generic sequence. It is multiplied by ``bell_seq`` to get a sequence, whose terms are added up to get the final terms for the polynomial. Examples ======== >>> from sympy import fps, exp, cos >>> from sympy.abc import x >>> f1 = fps(exp(x)) >>> f2 = fps(cos(x)) >>> finv1, finv2 = f1.inverse(), f2.inverse() >>> finv1._eval_terms(6) -x**5/120 + x**4/24 - x**3/6 + x**2/2 - x + 1 >>> finv2._eval_terms(8) 61*x**6/720 + 5*x**4/24 + x**2/2 + 1 See Also ======== sympy.series.formal.FormalPowerSeries.inverse sympy.series.formal.FormalPowerSeries.coeff_bell """ ffps = self.ffps terms = [ffps.zero_coeff()] for i in range(1, n): bell_seq = ffps.coeff_bell(i) seq = (self.aux_seq * bell_seq) terms.append(Add(*(seq[:i])) / ffps.fact_seq[i-1] * ffps.xk.coeff(i)) return Add(*terms) def fps(f, x=None, x0=0, dir=1, hyper=True, order=4, rational=True, full=False): """ Generates Formal Power Series of ``f``. Explanation =========== Returns the formal series expansion of ``f`` around ``x = x0`` with respect to ``x`` in the form of a ``FormalPowerSeries`` object. Formal Power Series is represented using an explicit formula computed using different algorithms. See :func:`compute_fps` for the more details regarding the computation of formula. Parameters ========== x : Symbol, optional If x is None and ``f`` is univariate, the univariate symbols will be supplied, otherwise an error will be raised. x0 : number, optional Point to perform series expansion about. Default is 0. dir : {1, -1, '+', '-'}, optional If dir is 1 or '+' the series is calculated from the right and for -1 or '-' the series is calculated from the left. For smooth functions this flag will not alter the results. Default is 1. hyper : {True, False}, optional Set hyper to False to skip the hypergeometric algorithm. By default it is set to False. order : int, optional Order of the derivative of ``f``, Default is 4. rational : {True, False}, optional Set rational to False to skip rational algorithm. By default it is set to True. full : {True, False}, optional Set full to True to increase the range of rational algorithm. See :func:`rational_algorithm` for details. By default it is set to False. Examples ======== >>> from sympy import fps, ln, atan, sin >>> from sympy.abc import x, n Rational Functions >>> fps(ln(1 + x)).truncate() x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6) >>> fps(atan(x), full=True).truncate() x - x**3/3 + x**5/5 + O(x**6) Symbolic Functions >>> fps(x**n*sin(x**2), x).truncate(8) -x**(n + 6)/6 + x**(n + 2) + O(x**(n + 8)) See Also ======== sympy.series.formal.FormalPowerSeries sympy.series.formal.compute_fps """ f = sympify(f) if x is None: free = f.free_symbols if len(free) == 1: x = free.pop() elif not free: return f else: raise NotImplementedError("multivariate formal power series") result = compute_fps(f, x, x0, dir, hyper, order, rational, full) if result is None: return f return FormalPowerSeries(f, x, x0, dir, result) sympy-sympy-1.9/sympy/series/fourier.py000066400000000000000000000544161412543434000204350ustar00rootroot00000000000000"""Fourier Series""" from sympy import pi, oo, Wild from sympy.core.expr import Expr from sympy.core.add import Add from sympy.core.compatibility import is_sequence from sympy.core.containers import Tuple from sympy.core.singleton import S from sympy.core.symbol import Dummy, Symbol from sympy.core.sympify import sympify from sympy.functions.elementary.trigonometric import sin, cos, sinc from sympy.series.series_class import SeriesBase from sympy.series.sequences import SeqFormula from sympy.sets.sets import Interval from sympy.simplify.fu import TR2, TR1, TR10, sincos_to_sum def fourier_cos_seq(func, limits, n): """Returns the cos sequence in a Fourier series""" from sympy.integrals import integrate x, L = limits[0], limits[2] - limits[1] cos_term = cos(2*n*pi*x / L) formula = 2 * cos_term * integrate(func * cos_term, limits) / L a0 = formula.subs(n, S.Zero) / 2 return a0, SeqFormula(2 * cos_term * integrate(func * cos_term, limits) / L, (n, 1, oo)) def fourier_sin_seq(func, limits, n): """Returns the sin sequence in a Fourier series""" from sympy.integrals import integrate x, L = limits[0], limits[2] - limits[1] sin_term = sin(2*n*pi*x / L) return SeqFormula(2 * sin_term * integrate(func * sin_term, limits) / L, (n, 1, oo)) def _process_limits(func, limits): """ Limits should be of the form (x, start, stop). x should be a symbol. Both start and stop should be bounded. Explanation =========== * If x is not given, x is determined from func. * If limits is None. Limit of the form (x, -pi, pi) is returned. Examples ======== >>> from sympy.series.fourier import _process_limits as pari >>> from sympy.abc import x >>> pari(x**2, (x, -2, 2)) (x, -2, 2) >>> pari(x**2, (-2, 2)) (x, -2, 2) >>> pari(x**2, None) (x, -pi, pi) """ def _find_x(func): free = func.free_symbols if len(free) == 1: return free.pop() elif not free: return Dummy('k') else: raise ValueError( " specify dummy variables for %s. If the function contains" " more than one free symbol, a dummy variable should be" " supplied explicitly e.g. FourierSeries(m*n**2, (n, -pi, pi))" % func) x, start, stop = None, None, None if limits is None: x, start, stop = _find_x(func), -pi, pi if is_sequence(limits, Tuple): if len(limits) == 3: x, start, stop = limits elif len(limits) == 2: x = _find_x(func) start, stop = limits if not isinstance(x, Symbol) or start is None or stop is None: raise ValueError('Invalid limits given: %s' % str(limits)) unbounded = [S.NegativeInfinity, S.Infinity] if start in unbounded or stop in unbounded: raise ValueError("Both the start and end value should be bounded") return sympify((x, start, stop)) def finite_check(f, x, L): def check_fx(exprs, x): return x not in exprs.free_symbols def check_sincos(_expr, x, L): if isinstance(_expr, (sin, cos)): sincos_args = _expr.args[0] if sincos_args.match(a*(pi/L)*x + b) is not None: return True else: return False _expr = sincos_to_sum(TR2(TR1(f))) add_coeff = _expr.as_coeff_add() a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k != S.Zero, ]) b = Wild('b', properties=[lambda k: x not in k.free_symbols, ]) for s in add_coeff[1]: mul_coeffs = s.as_coeff_mul()[1] for t in mul_coeffs: if not (check_fx(t, x) or check_sincos(t, x, L)): return False, f return True, _expr class FourierSeries(SeriesBase): r"""Represents Fourier sine/cosine series. Explanation =========== This class only represents a fourier series. No computation is performed. For how to compute Fourier series, see the :func:`fourier_series` docstring. See Also ======== sympy.series.fourier.fourier_series """ def __new__(cls, *args): args = map(sympify, args) return Expr.__new__(cls, *args) @property def function(self): return self.args[0] @property def x(self): return self.args[1][0] @property def period(self): return (self.args[1][1], self.args[1][2]) @property def a0(self): return self.args[2][0] @property def an(self): return self.args[2][1] @property def bn(self): return self.args[2][2] @property def interval(self): return Interval(0, oo) @property def start(self): return self.interval.inf @property def stop(self): return self.interval.sup @property def length(self): return oo @property def L(self): return abs(self.period[1] - self.period[0]) / 2 def _eval_subs(self, old, new): x = self.x if old.has(x): return self def truncate(self, n=3): """ Return the first n nonzero terms of the series. If ``n`` is None return an iterator. Parameters ========== n : int or None Amount of non-zero terms in approximation or None. Returns ======= Expr or iterator : Approximation of function expanded into Fourier series. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x, (x, -pi, pi)) >>> s.truncate(4) 2*sin(x) - sin(2*x) + 2*sin(3*x)/3 - sin(4*x)/2 See Also ======== sympy.series.fourier.FourierSeries.sigma_approximation """ if n is None: return iter(self) terms = [] for t in self: if len(terms) == n: break if t is not S.Zero: terms.append(t) return Add(*terms) def sigma_approximation(self, n=3): r""" Return :math:`\sigma`-approximation of Fourier series with respect to order n. Explanation =========== Sigma approximation adjusts a Fourier summation to eliminate the Gibbs phenomenon which would otherwise occur at discontinuities. A sigma-approximated summation for a Fourier series of a T-periodical function can be written as .. math:: s(\theta) = \frac{1}{2} a_0 + \sum _{k=1}^{m-1} \operatorname{sinc} \Bigl( \frac{k}{m} \Bigr) \cdot \left[ a_k \cos \Bigl( \frac{2\pi k}{T} \theta \Bigr) + b_k \sin \Bigl( \frac{2\pi k}{T} \theta \Bigr) \right], where :math:`a_0, a_k, b_k, k=1,\ldots,{m-1}` are standard Fourier series coefficients and :math:`\operatorname{sinc} \Bigl( \frac{k}{m} \Bigr)` is a Lanczos :math:`\sigma` factor (expressed in terms of normalized :math:`\operatorname{sinc}` function). Parameters ========== n : int Highest order of the terms taken into account in approximation. Returns ======= Expr : Sigma approximation of function expanded into Fourier series. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x, (x, -pi, pi)) >>> s.sigma_approximation(4) 2*sin(x)*sinc(pi/4) - 2*sin(2*x)/pi + 2*sin(3*x)*sinc(3*pi/4)/3 See Also ======== sympy.series.fourier.FourierSeries.truncate Notes ===== The behaviour of :meth:`~sympy.series.fourier.FourierSeries.sigma_approximation` is different from :meth:`~sympy.series.fourier.FourierSeries.truncate` - it takes all nonzero terms of degree smaller than n, rather than first n nonzero ones. References ========== .. [1] https://en.wikipedia.org/wiki/Gibbs_phenomenon .. [2] https://en.wikipedia.org/wiki/Sigma_approximation """ terms = [sinc(pi * i / n) * t for i, t in enumerate(self[:n]) if t is not S.Zero] return Add(*terms) def shift(self, s): """ Shift the function by a term independent of x. Explanation =========== f(x) -> f(x) + s This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.shift(1).truncate() -4*cos(x) + cos(2*x) + 1 + pi**2/3 """ s, x = sympify(s), self.x if x in s.free_symbols: raise ValueError("'%s' should be independent of %s" % (s, x)) a0 = self.a0 + s sfunc = self.function + s return self.func(sfunc, self.args[1], (a0, self.an, self.bn)) def shiftx(self, s): """ Shift x by a term independent of x. Explanation =========== f(x) -> f(x + s) This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.shiftx(1).truncate() -4*cos(x + 1) + cos(2*x + 2) + pi**2/3 """ s, x = sympify(s), self.x if x in s.free_symbols: raise ValueError("'%s' should be independent of %s" % (s, x)) an = self.an.subs(x, x + s) bn = self.bn.subs(x, x + s) sfunc = self.function.subs(x, x + s) return self.func(sfunc, self.args[1], (self.a0, an, bn)) def scale(self, s): """ Scale the function by a term independent of x. Explanation =========== f(x) -> s * f(x) This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.scale(2).truncate() -8*cos(x) + 2*cos(2*x) + 2*pi**2/3 """ s, x = sympify(s), self.x if x in s.free_symbols: raise ValueError("'%s' should be independent of %s" % (s, x)) an = self.an.coeff_mul(s) bn = self.bn.coeff_mul(s) a0 = self.a0 * s sfunc = self.args[0] * s return self.func(sfunc, self.args[1], (a0, an, bn)) def scalex(self, s): """ Scale x by a term independent of x. Explanation =========== f(x) -> f(s*x) This is fast, if Fourier series of f(x) is already computed. Examples ======== >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> s = fourier_series(x**2, (x, -pi, pi)) >>> s.scalex(2).truncate() -4*cos(2*x) + cos(4*x) + pi**2/3 """ s, x = sympify(s), self.x if x in s.free_symbols: raise ValueError("'%s' should be independent of %s" % (s, x)) an = self.an.subs(x, x * s) bn = self.bn.subs(x, x * s) sfunc = self.function.subs(x, x * s) return self.func(sfunc, self.args[1], (self.a0, an, bn)) def _eval_as_leading_term(self, x, logx=None, cdir=0): for t in self: if t is not S.Zero: return t def _eval_term(self, pt): if pt == 0: return self.a0 return self.an.coeff(pt) + self.bn.coeff(pt) def __neg__(self): return self.scale(-1) def __add__(self, other): if isinstance(other, FourierSeries): if self.period != other.period: raise ValueError("Both the series should have same periods") x, y = self.x, other.x function = self.function + other.function.subs(y, x) if self.x not in function.free_symbols: return function an = self.an + other.an bn = self.bn + other.bn a0 = self.a0 + other.a0 return self.func(function, self.args[1], (a0, an, bn)) return Add(self, other) def __sub__(self, other): return self.__add__(-other) class FiniteFourierSeries(FourierSeries): r"""Represents Finite Fourier sine/cosine series. For how to compute Fourier series, see the :func:`fourier_series` docstring. Parameters ========== f : Expr Expression for finding fourier_series limits : ( x, start, stop) x is the independent variable for the expression f (start, stop) is the period of the fourier series exprs: (a0, an, bn) or Expr a0 is the constant term a0 of the fourier series an is a dictionary of coefficients of cos terms an[k] = coefficient of cos(pi*(k/L)*x) bn is a dictionary of coefficients of sin terms bn[k] = coefficient of sin(pi*(k/L)*x) or exprs can be an expression to be converted to fourier form Methods ======= This class is an extension of FourierSeries class. Please refer to sympy.series.fourier.FourierSeries for further information. See Also ======== sympy.series.fourier.FourierSeries sympy.series.fourier.fourier_series """ def __new__(cls, f, limits, exprs): f = sympify(f) limits = sympify(limits) exprs = sympify(exprs) if not (type(exprs) == Tuple and len(exprs) == 3): # exprs is not of form (a0, an, bn) # Converts the expression to fourier form c, e = exprs.as_coeff_add() rexpr = c + Add(*[TR10(i) for i in e]) a0, exp_ls = rexpr.expand(trig=False, power_base=False, power_exp=False, log=False).as_coeff_add() x = limits[0] L = abs(limits[2] - limits[1]) / 2 a = Wild('a', properties=[lambda k: k.is_Integer, lambda k: k is not S.Zero, ]) b = Wild('b', properties=[lambda k: x not in k.free_symbols, ]) an = dict() bn = dict() # separates the coefficients of sin and cos terms in dictionaries an, and bn for p in exp_ls: t = p.match(b * cos(a * (pi / L) * x)) q = p.match(b * sin(a * (pi / L) * x)) if t: an[t[a]] = t[b] + an.get(t[a], S.Zero) elif q: bn[q[a]] = q[b] + bn.get(q[a], S.Zero) else: a0 += p exprs = Tuple(a0, an, bn) return Expr.__new__(cls, f, limits, exprs) @property def interval(self): _length = 1 if self.a0 else 0 _length += max(set(self.an.keys()).union(set(self.bn.keys()))) + 1 return Interval(0, _length) @property def length(self): return self.stop - self.start def shiftx(self, s): s, x = sympify(s), self.x if x in s.free_symbols: raise ValueError("'%s' should be independent of %s" % (s, x)) _expr = self.truncate().subs(x, x + s) sfunc = self.function.subs(x, x + s) return self.func(sfunc, self.args[1], _expr) def scale(self, s): s, x = sympify(s), self.x if x in s.free_symbols: raise ValueError("'%s' should be independent of %s" % (s, x)) _expr = self.truncate() * s sfunc = self.function * s return self.func(sfunc, self.args[1], _expr) def scalex(self, s): s, x = sympify(s), self.x if x in s.free_symbols: raise ValueError("'%s' should be independent of %s" % (s, x)) _expr = self.truncate().subs(x, x * s) sfunc = self.function.subs(x, x * s) return self.func(sfunc, self.args[1], _expr) def _eval_term(self, pt): if pt == 0: return self.a0 _term = self.an.get(pt, S.Zero) * cos(pt * (pi / self.L) * self.x) \ + self.bn.get(pt, S.Zero) * sin(pt * (pi / self.L) * self.x) return _term def __add__(self, other): if isinstance(other, FourierSeries): return other.__add__(fourier_series(self.function, self.args[1],\ finite=False)) elif isinstance(other, FiniteFourierSeries): if self.period != other.period: raise ValueError("Both the series should have same periods") x, y = self.x, other.x function = self.function + other.function.subs(y, x) if self.x not in function.free_symbols: return function return fourier_series(function, limits=self.args[1]) def fourier_series(f, limits=None, finite=True): r"""Computes the Fourier trigonometric series expansion. Explanation =========== Fourier trigonometric series of $f(x)$ over the interval $(a, b)$ is defined as: .. math:: \frac{a_0}{2} + \sum_{n=1}^{\infty} (a_n \cos(\frac{2n \pi x}{L}) + b_n \sin(\frac{2n \pi x}{L})) where the coefficients are: .. math:: L = b - a .. math:: a_0 = \frac{2}{L} \int_{a}^{b}{f(x) dx} .. math:: a_n = \frac{2}{L} \int_{a}^{b}{f(x) \cos(\frac{2n \pi x}{L}) dx} .. math:: b_n = \frac{2}{L} \int_{a}^{b}{f(x) \sin(\frac{2n \pi x}{L}) dx} The condition whether the function $f(x)$ given should be periodic or not is more than necessary, because it is sufficient to consider the series to be converging to $f(x)$ only in the given interval, not throughout the whole real line. This also brings a lot of ease for the computation because you don't have to make $f(x)$ artificially periodic by wrapping it with piecewise, modulo operations, but you can shape the function to look like the desired periodic function only in the interval $(a, b)$, and the computed series will automatically become the series of the periodic version of $f(x)$. This property is illustrated in the examples section below. Parameters ========== limits : (sym, start, end), optional *sym* denotes the symbol the series is computed with respect to. *start* and *end* denotes the start and the end of the interval where the fourier series converges to the given function. Default range is specified as $-\pi$ and $\pi$. Returns ======= FourierSeries A symbolic object representing the Fourier trigonometric series. Examples ======== Computing the Fourier series of $f(x) = x^2$: >>> from sympy import fourier_series, pi >>> from sympy.abc import x >>> f = x**2 >>> s = fourier_series(f, (x, -pi, pi)) >>> s1 = s.truncate(n=3) >>> s1 -4*cos(x) + cos(2*x) + pi**2/3 Shifting of the Fourier series: >>> s.shift(1).truncate() -4*cos(x) + cos(2*x) + 1 + pi**2/3 >>> s.shiftx(1).truncate() -4*cos(x + 1) + cos(2*x + 2) + pi**2/3 Scaling of the Fourier series: >>> s.scale(2).truncate() -8*cos(x) + 2*cos(2*x) + 2*pi**2/3 >>> s.scalex(2).truncate() -4*cos(2*x) + cos(4*x) + pi**2/3 Computing the Fourier series of $f(x) = x$: This illustrates how truncating to the higher order gives better convergence. .. plot:: :context: reset :format: doctest :include-source: True >>> from sympy import fourier_series, pi, plot >>> from sympy.abc import x >>> f = x >>> s = fourier_series(f, (x, -pi, pi)) >>> s1 = s.truncate(n = 3) >>> s2 = s.truncate(n = 5) >>> s3 = s.truncate(n = 7) >>> p = plot(f, s1, s2, s3, (x, -pi, pi), show=False, legend=True) >>> p[0].line_color = (0, 0, 0) >>> p[0].label = 'x' >>> p[1].line_color = (0.7, 0.7, 0.7) >>> p[1].label = 'n=3' >>> p[2].line_color = (0.5, 0.5, 0.5) >>> p[2].label = 'n=5' >>> p[3].line_color = (0.3, 0.3, 0.3) >>> p[3].label = 'n=7' >>> p.show() This illustrates how the series converges to different sawtooth waves if the different ranges are specified. .. plot:: :context: close-figs :format: doctest :include-source: True >>> s1 = fourier_series(x, (x, -1, 1)).truncate(10) >>> s2 = fourier_series(x, (x, -pi, pi)).truncate(10) >>> s3 = fourier_series(x, (x, 0, 1)).truncate(10) >>> p = plot(x, s1, s2, s3, (x, -5, 5), show=False, legend=True) >>> p[0].line_color = (0, 0, 0) >>> p[0].label = 'x' >>> p[1].line_color = (0.7, 0.7, 0.7) >>> p[1].label = '[-1, 1]' >>> p[2].line_color = (0.5, 0.5, 0.5) >>> p[2].label = '[-pi, pi]' >>> p[3].line_color = (0.3, 0.3, 0.3) >>> p[3].label = '[0, 1]' >>> p.show() Notes ===== Computing Fourier series can be slow due to the integration required in computing an, bn. It is faster to compute Fourier series of a function by using shifting and scaling on an already computed Fourier series rather than computing again. e.g. If the Fourier series of ``x**2`` is known the Fourier series of ``x**2 - 1`` can be found by shifting by ``-1``. See Also ======== sympy.series.fourier.FourierSeries References ========== .. [1] https://mathworld.wolfram.com/FourierSeries.html """ f = sympify(f) limits = _process_limits(f, limits) x = limits[0] if x not in f.free_symbols: return f if finite: L = abs(limits[2] - limits[1]) / 2 is_finite, res_f = finite_check(f, x, L) if is_finite: return FiniteFourierSeries(f, limits, res_f) n = Dummy('n') center = (limits[1] + limits[2]) / 2 if center.is_zero: neg_f = f.subs(x, -x) if f == neg_f: a0, an = fourier_cos_seq(f, limits, n) bn = SeqFormula(0, (1, oo)) return FourierSeries(f, limits, (a0, an, bn)) elif f == -neg_f: a0 = S.Zero an = SeqFormula(0, (1, oo)) bn = fourier_sin_seq(f, limits, n) return FourierSeries(f, limits, (a0, an, bn)) a0, an = fourier_cos_seq(f, limits, n) bn = fourier_sin_seq(f, limits, n) return FourierSeries(f, limits, (a0, an, bn)) sympy-sympy-1.9/sympy/series/gruntz.py000066400000000000000000000553731412543434000203160ustar00rootroot00000000000000""" Limits ====== Implemented according to the PhD thesis http://www.cybertester.com/data/gruntz.pdf, which contains very thorough descriptions of the algorithm including many examples. We summarize here the gist of it. All functions are sorted according to how rapidly varying they are at infinity using the following rules. Any two functions f and g can be compared using the properties of L: L=lim log|f(x)| / log|g(x)| (for x -> oo) We define >, < ~ according to:: 1. f > g .... L=+-oo we say that: - f is greater than any power of g - f is more rapidly varying than g - f goes to infinity/zero faster than g 2. f < g .... L=0 we say that: - f is lower than any power of g 3. f ~ g .... L!=0, +-oo we say that: - both f and g are bounded from above and below by suitable integral powers of the other Examples ======== :: 2 < x < exp(x) < exp(x**2) < exp(exp(x)) 2 ~ 3 ~ -5 x ~ x**2 ~ x**3 ~ 1/x ~ x**m ~ -x exp(x) ~ exp(-x) ~ exp(2x) ~ exp(x)**2 ~ exp(x+exp(-x)) f ~ 1/f So we can divide all the functions into comparability classes (x and x^2 belong to one class, exp(x) and exp(-x) belong to some other class). In principle, we could compare any two functions, but in our algorithm, we don't compare anything below the class 2~3~-5 (for example log(x) is below this), so we set 2~3~-5 as the lowest comparability class. Given the function f, we find the list of most rapidly varying (mrv set) subexpressions of it. This list belongs to the same comparability class. Let's say it is {exp(x), exp(2x)}. Using the rule f ~ 1/f we find an element "w" (either from the list or a new one) from the same comparability class which goes to zero at infinity. In our example we set w=exp(-x) (but we could also set w=exp(-2x) or w=exp(-3x) ...). We rewrite the mrv set using w, in our case {1/w, 1/w^2}, and substitute it into f. Then we expand f into a series in w:: f = c0*w^e0 + c1*w^e1 + ... + O(w^en), where e0oo, lim f = lim c0*w^e0, because all the other terms go to zero, because w goes to zero faster than the ci and ei. So:: for e0>0, lim f = 0 for e0<0, lim f = +-oo (the sign depends on the sign of c0) for e0=0, lim f = lim c0 We need to recursively compute limits at several places of the algorithm, but as is shown in the PhD thesis, it always finishes. Important functions from the implementation: compare(a, b, x) compares "a" and "b" by computing the limit L. mrv(e, x) returns list of most rapidly varying (mrv) subexpressions of "e" rewrite(e, Omega, x, wsym) rewrites "e" in terms of w leadterm(f, x) returns the lowest power term in the series of f mrv_leadterm(e, x) returns the lead term (c0, e0) for e limitinf(e, x) computes lim e (for x->oo) limit(e, z, z0) computes any limit by converting it to the case x->oo All the functions are really simple and straightforward except rewrite(), which is the most difficult/complex part of the algorithm. When the algorithm fails, the bugs are usually in the series expansion (i.e. in SymPy) or in rewrite. This code is almost exact rewrite of the Maple code inside the Gruntz thesis. Debugging --------- Because the gruntz algorithm is highly recursive, it's difficult to figure out what went wrong inside a debugger. Instead, turn on nice debug prints by defining the environment variable SYMPY_DEBUG. For example: [user@localhost]: SYMPY_DEBUG=True ./bin/isympy In [1]: limit(sin(x)/x, x, 0) limitinf(_x*sin(1/_x), _x) = 1 +-mrv_leadterm(_x*sin(1/_x), _x) = (1, 0) | +-mrv(_x*sin(1/_x), _x) = set([_x]) | | +-mrv(_x, _x) = set([_x]) | | +-mrv(sin(1/_x), _x) = set([_x]) | | +-mrv(1/_x, _x) = set([_x]) | | +-mrv(_x, _x) = set([_x]) | +-mrv_leadterm(exp(_x)*sin(exp(-_x)), _x, set([exp(_x)])) = (1, 0) | +-rewrite(exp(_x)*sin(exp(-_x)), set([exp(_x)]), _x, _w) = (1/_w*sin(_w), -_x) | +-sign(_x, _x) = 1 | +-mrv_leadterm(1, _x) = (1, 0) +-sign(0, _x) = 0 +-limitinf(1, _x) = 1 And check manually which line is wrong. Then go to the source code and debug this function to figure out the exact problem. """ from functools import reduce from sympy import cacheit from sympy.core import Basic, S, oo, I, Dummy, Wild, Mul, PoleError from sympy.functions import log, exp from sympy.series.order import Order from sympy.simplify import logcombine from sympy.simplify.powsimp import powsimp, powdenest from sympy.utilities.misc import debug_decorator as debug from sympy.utilities.timeutils import timethis timeit = timethis('gruntz') def compare(a, b, x): """Returns "<" if a" for a>b""" # log(exp(...)) must always be simplified here for termination la, lb = log(a), log(b) if isinstance(a, Basic) and (isinstance(a, exp) or (a.is_Pow and a.base == S.Exp1)): la = a.exp if isinstance(b, Basic) and (isinstance(b, exp) or (b.is_Pow and b.base == S.Exp1)): lb = b.exp c = limitinf(la/lb, x) if c == 0: return "<" elif c.is_infinite: return ">" else: return "=" class SubsSet(dict): """ Stores (expr, dummy) pairs, and how to rewrite expr-s. Explanation =========== The gruntz algorithm needs to rewrite certain expressions in term of a new variable w. We cannot use subs, because it is just too smart for us. For example:: > Omega=[exp(exp(_p - exp(-_p))/(1 - 1/_p)), exp(exp(_p))] > O2=[exp(-exp(_p) + exp(-exp(-_p))*exp(_p)/(1 - 1/_p))/_w, 1/_w] > e = exp(exp(_p - exp(-_p))/(1 - 1/_p)) - exp(exp(_p)) > e.subs(Omega[0],O2[0]).subs(Omega[1],O2[1]) -1/w + exp(exp(p)*exp(-exp(-p))/(1 - 1/p)) is really not what we want! So we do it the hard way and keep track of all the things we potentially want to substitute by dummy variables. Consider the expression:: exp(x - exp(-x)) + exp(x) + x. The mrv set is {exp(x), exp(-x), exp(x - exp(-x))}. We introduce corresponding dummy variables d1, d2, d3 and rewrite:: d3 + d1 + x. This class first of all keeps track of the mapping expr->variable, i.e. will at this stage be a dictionary:: {exp(x): d1, exp(-x): d2, exp(x - exp(-x)): d3}. [It turns out to be more convenient this way round.] But sometimes expressions in the mrv set have other expressions from the mrv set as subexpressions, and we need to keep track of that as well. In this case, d3 is really exp(x - d2), so rewrites at this stage is:: {d3: exp(x-d2)}. The function rewrite uses all this information to correctly rewrite our expression in terms of w. In this case w can be chosen to be exp(-x), i.e. d2. The correct rewriting then is:: exp(-w)/w + 1/w + x. """ def __init__(self): self.rewrites = {} def __repr__(self): return super().__repr__() + ', ' + self.rewrites.__repr__() def __getitem__(self, key): if not key in self: self[key] = Dummy() return dict.__getitem__(self, key) def do_subs(self, e): """Substitute the variables with expressions""" for expr, var in self.items(): e = e.xreplace({var: expr}) return e def meets(self, s2): """Tell whether or not self and s2 have non-empty intersection""" return set(self.keys()).intersection(list(s2.keys())) != set() def union(self, s2, exps=None): """Compute the union of self and s2, adjusting exps""" res = self.copy() tr = {} for expr, var in s2.items(): if expr in self: if exps: exps = exps.xreplace({var: res[expr]}) tr[var] = res[expr] else: res[expr] = var for var, rewr in s2.rewrites.items(): res.rewrites[var] = rewr.xreplace(tr) return res, exps def copy(self): """Create a shallow copy of SubsSet""" r = SubsSet() r.rewrites = self.rewrites.copy() for expr, var in self.items(): r[expr] = var return r @debug def mrv(e, x): """Returns a SubsSet of most rapidly varying (mrv) subexpressions of 'e', and e rewritten in terms of these""" e = powsimp(e, deep=True, combine='exp') if not isinstance(e, Basic): raise TypeError("e should be an instance of Basic") if not e.has(x): return SubsSet(), e elif e == x: s = SubsSet() return s, s[x] elif e.is_Mul or e.is_Add: i, d = e.as_independent(x) # throw away x-independent terms if d.func != e.func: s, expr = mrv(d, x) return s, e.func(i, expr) a, b = d.as_two_terms() s1, e1 = mrv(a, x) s2, e2 = mrv(b, x) return mrv_max1(s1, s2, e.func(i, e1, e2), x) elif e.is_Pow and e.base != S.Exp1: e1 = S.One while e.is_Pow: b1 = e.base e1 *= e.exp e = b1 if b1 == 1: return SubsSet(), b1 if e1.has(x): base_lim = limitinf(b1, x) if base_lim is S.One: return mrv(exp(e1 * (b1 - 1)), x) return mrv(exp(e1 * log(b1)), x) else: s, expr = mrv(b1, x) return s, expr**e1 elif isinstance(e, log): s, expr = mrv(e.args[0], x) return s, log(expr) elif isinstance(e, exp) or (e.is_Pow and e.base == S.Exp1): # We know from the theory of this algorithm that exp(log(...)) may always # be simplified here, and doing so is vital for termination. if isinstance(e.exp, log): return mrv(e.exp.args[0], x) # if a product has an infinite factor the result will be # infinite if there is no zero, otherwise NaN; here, we # consider the result infinite if any factor is infinite li = limitinf(e.exp, x) if any(_.is_infinite for _ in Mul.make_args(li)): s1 = SubsSet() e1 = s1[e] s2, e2 = mrv(e.exp, x) su = s1.union(s2)[0] su.rewrites[e1] = exp(e2) return mrv_max3(s1, e1, s2, exp(e2), su, e1, x) else: s, expr = mrv(e.exp, x) return s, exp(expr) elif e.is_Function: l = [mrv(a, x) for a in e.args] l2 = [s for (s, _) in l if s != SubsSet()] if len(l2) != 1: # e.g. something like BesselJ(x, x) raise NotImplementedError("MRV set computation for functions in" " several variables not implemented.") s, ss = l2[0], SubsSet() args = [ss.do_subs(x[1]) for x in l] return s, e.func(*args) elif e.is_Derivative: raise NotImplementedError("MRV set computation for derviatives" " not implemented yet.") raise NotImplementedError( "Don't know how to calculate the mrv of '%s'" % e) def mrv_max3(f, expsf, g, expsg, union, expsboth, x): """ Computes the maximum of two sets of expressions f and g, which are in the same comparability class, i.e. max() compares (two elements of) f and g and returns either (f, expsf) [if f is larger], (g, expsg) [if g is larger] or (union, expsboth) [if f, g are of the same class]. """ if not isinstance(f, SubsSet): raise TypeError("f should be an instance of SubsSet") if not isinstance(g, SubsSet): raise TypeError("g should be an instance of SubsSet") if f == SubsSet(): return g, expsg elif g == SubsSet(): return f, expsf elif f.meets(g): return union, expsboth c = compare(list(f.keys())[0], list(g.keys())[0], x) if c == ">": return f, expsf elif c == "<": return g, expsg else: if c != "=": raise ValueError("c should be =") return union, expsboth def mrv_max1(f, g, exps, x): """Computes the maximum of two sets of expressions f and g, which are in the same comparability class, i.e. mrv_max1() compares (two elements of) f and g and returns the set, which is in the higher comparability class of the union of both, if they have the same order of variation. Also returns exps, with the appropriate substitutions made. """ u, b = f.union(g, exps) return mrv_max3(f, g.do_subs(exps), g, f.do_subs(exps), u, b, x) @debug @cacheit @timeit def sign(e, x): """ Returns a sign of an expression e(x) for x->oo. :: e > 0 for x sufficiently large ... 1 e == 0 for x sufficiently large ... 0 e < 0 for x sufficiently large ... -1 The result of this function is currently undefined if e changes sign arbitrarily often for arbitrarily large x (e.g. sin(x)). Note that this returns zero only if e is *constantly* zero for x sufficiently large. [If e is constant, of course, this is just the same thing as the sign of e.] """ from sympy import sign as _sign if not isinstance(e, Basic): raise TypeError("e should be an instance of Basic") if e.is_positive: return 1 elif e.is_negative: return -1 elif e.is_zero: return 0 elif not e.has(x): e = logcombine(e) return _sign(e) elif e == x: return 1 elif e.is_Mul: a, b = e.as_two_terms() sa = sign(a, x) if not sa: return 0 return sa * sign(b, x) elif isinstance(e, exp): return 1 elif e.is_Pow: if e.base == S.Exp1: return 1 s = sign(e.base, x) if s == 1: return 1 if e.exp.is_Integer: return s**e.exp elif isinstance(e, log): return sign(e.args[0] - 1, x) # if all else fails, do it the hard way c0, e0 = mrv_leadterm(e, x) return sign(c0, x) @debug @timeit @cacheit def limitinf(e, x, leadsimp=False): """Limit e(x) for x-> oo. Explanation =========== If ``leadsimp`` is True, an attempt is made to simplify the leading term of the series expansion of ``e``. That may succeed even if ``e`` cannot be simplified. """ # rewrite e in terms of tractable functions only if not e.has(x): return e # e is a constant if e.has(Order): e = e.expand().removeO() if not x.is_positive or x.is_integer: # We make sure that x.is_positive is True and x.is_integer is None # so we get all the correct mathematical behavior from the expression. # We need a fresh variable. p = Dummy('p', positive=True) e = e.subs(x, p) x = p e = e.rewrite('tractable', deep=True, limitvar=x) e = powdenest(e) c0, e0 = mrv_leadterm(e, x) sig = sign(e0, x) if sig == 1: return S.Zero # e0>0: lim f = 0 elif sig == -1: # e0<0: lim f = +-oo (the sign depends on the sign of c0) if c0.match(I*Wild("a", exclude=[I])): return c0*oo s = sign(c0, x) # the leading term shouldn't be 0: if s == 0: raise ValueError("Leading term should not be 0") return s*oo elif sig == 0: if leadsimp: c0 = c0.simplify() return limitinf(c0, x, leadsimp) # e0=0: lim f = lim c0 else: raise ValueError("{} could not be evaluated".format(sig)) def moveup2(s, x): r = SubsSet() for expr, var in s.items(): r[expr.xreplace({x: exp(x)})] = var for var, expr in s.rewrites.items(): r.rewrites[var] = s.rewrites[var].xreplace({x: exp(x)}) return r def moveup(l, x): return [e.xreplace({x: exp(x)}) for e in l] @debug @timeit def calculate_series(e, x, logx=None): """ Calculates at least one term of the series of ``e`` in ``x``. This is a place that fails most often, so it is in its own function. """ from sympy.polys import cancel from sympy.simplify import bottom_up for t in e.lseries(x, logx=logx): # bottom_up function is required for a specific case - when e is # -exp(p/(p + 1)) + exp(-p**2/(p + 1) + p). No current simplification # methods reduce this to 0 while not expanding polynomials. t = bottom_up(t, lambda w: getattr(w, 'normal', lambda: w)()) t = cancel(t, expand=False).factor() if t.has(exp) and t.has(log): t = powdenest(t) if not t.is_zero: break return t @debug @timeit @cacheit def mrv_leadterm(e, x): """Returns (c0, e0) for e.""" Omega = SubsSet() if not e.has(x): return (e, S.Zero) if Omega == SubsSet(): Omega, exps = mrv(e, x) if not Omega: # e really does not depend on x after simplification return exps, S.Zero if x in Omega: # move the whole omega up (exponentiate each term): Omega_up = moveup2(Omega, x) exps_up = moveup([exps], x)[0] # NOTE: there is no need to move this down! Omega = Omega_up exps = exps_up # # The positive dummy, w, is used here so log(w*2) etc. will expand; # a unique dummy is needed in this algorithm # # For limits of complex functions, the algorithm would have to be # improved, or just find limits of Re and Im components separately. # w = Dummy("w", real=True, positive=True) f, logw = rewrite(exps, Omega, x, w) series = calculate_series(f, w, logx=logw) try: lt = series.leadterm(w, logx=logw) except (ValueError, PoleError): lt = f.as_coeff_exponent(w) # as_coeff_exponent won't always split in required form. It may simply # return (f, 0) when a better form may be obtained. Example (-x)**(-pi) # can be written as (-1**(-pi), -pi) which as_coeff_exponent does not return if lt[0].has(w): base = f.as_base_exp()[0].as_coeff_exponent(w) ex = f.as_base_exp()[1] lt = (base[0]**ex, base[1]*ex) return (lt[0].subs(log(w), logw), lt[1]) def build_expression_tree(Omega, rewrites): r""" Helper function for rewrite. We need to sort Omega (mrv set) so that we replace an expression before we replace any expression in terms of which it has to be rewritten:: e1 ---> e2 ---> e3 \ -> e4 Here we can do e1, e2, e3, e4 or e1, e2, e4, e3. To do this we assemble the nodes into a tree, and sort them by height. This function builds the tree, rewrites then sorts the nodes. """ class Node: def ht(self): return reduce(lambda x, y: x + y, [x.ht() for x in self.before], 1) nodes = {} for expr, v in Omega: n = Node() n.before = [] n.var = v n.expr = expr nodes[v] = n for _, v in Omega: if v in rewrites: n = nodes[v] r = rewrites[v] for _, v2 in Omega: if r.has(v2): n.before.append(nodes[v2]) return nodes @debug @timeit def rewrite(e, Omega, x, wsym): """e(x) ... the function Omega ... the mrv set wsym ... the symbol which is going to be used for w Returns the rewritten e in terms of w and log(w). See test_rewrite1() for examples and correct results. """ from sympy import ilcm if not isinstance(Omega, SubsSet): raise TypeError("Omega should be an instance of SubsSet") if len(Omega) == 0: raise ValueError("Length can not be 0") # all items in Omega must be exponentials for t in Omega.keys(): if not isinstance(t, exp): raise ValueError("Value should be exp") rewrites = Omega.rewrites Omega = list(Omega.items()) nodes = build_expression_tree(Omega, rewrites) Omega.sort(key=lambda x: nodes[x[1]].ht(), reverse=True) # make sure we know the sign of each exp() term; after the loop, # g is going to be the "w" - the simplest one in the mrv set for g, _ in Omega: sig = sign(g.exp, x) if sig != 1 and sig != -1: raise NotImplementedError('Result depends on the sign of %s' % sig) if sig == 1: wsym = 1/wsym # if g goes to oo, substitute 1/w # O2 is a list, which results by rewriting each item in Omega using "w" O2 = [] denominators = [] for f, var in Omega: c = limitinf(f.exp/g.exp, x) if c.is_Rational: denominators.append(c.q) arg = f.exp if var in rewrites: if not isinstance(rewrites[var], exp): raise ValueError("Value should be exp") arg = rewrites[var].args[0] O2.append((var, exp((arg - c*g.exp).expand())*wsym**c)) # Remember that Omega contains subexpressions of "e". So now we find # them in "e" and substitute them for our rewriting, stored in O2 # the following powsimp is necessary to automatically combine exponentials, # so that the .xreplace() below succeeds: # TODO this should not be necessary f = powsimp(e, deep=True, combine='exp') for a, b in O2: f = f.xreplace({a: b}) for _, var in Omega: assert not f.has(var) # finally compute the logarithm of w (logw). logw = g.exp if sig == 1: logw = -logw # log(w)->log(1/w)=-log(w) # Some parts of sympy have difficulty computing series expansions with # non-integral exponents. The following heuristic improves the situation: exponent = reduce(ilcm, denominators, 1) f = f.subs({wsym: wsym**exponent}) logw /= exponent return f, logw def gruntz(e, z, z0, dir="+"): """ Compute the limit of e(z) at the point z0 using the Gruntz algorithm. Explanation =========== ``z0`` can be any expression, including oo and -oo. For ``dir="+"`` (default) it calculates the limit from the right (z->z0+) and for ``dir="-"`` the limit from the left (z->z0-). For infinite z0 (oo or -oo), the dir argument doesn't matter. This algorithm is fully described in the module docstring in the gruntz.py file. It relies heavily on the series expansion. Most frequently, gruntz() is only used if the faster limit() function (which uses heuristics) fails. """ if not z.is_symbol: raise NotImplementedError("Second argument must be a Symbol") # convert all limits to the limit z->oo; sign of z is handled in limitinf r = None if z0 == oo: e0 = e elif z0 == -oo: e0 = e.subs(z, -z) else: if str(dir) == "-": e0 = e.subs(z, z0 - 1/z) elif str(dir) == "+": e0 = e.subs(z, z0 + 1/z) else: raise NotImplementedError("dir must be '+' or '-'") try: r = limitinf(e0, z) except ValueError: r = limitinf(e0, z, leadsimp=True) # This is a bit of a heuristic for nice results... we always rewrite # tractable functions in terms of familiar intractable ones. # It might be nicer to rewrite the exactly to what they were initially, # but that would take some work to implement. return r.rewrite('intractable', deep=True) sympy-sympy-1.9/sympy/series/kauers.py000066400000000000000000000032701412543434000202440ustar00rootroot00000000000000def finite_diff(expression, variable, increment=1): """ Takes as input a polynomial expression and the variable used to construct it and returns the difference between function's value when the input is incremented to 1 and the original function value. If you want an increment other than one supply it as a third argument. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.series.kauers import finite_diff >>> finite_diff(x**2, x) 2*x + 1 >>> finite_diff(y**3 + 2*y**2 + 3*y + 4, y) 3*y**2 + 7*y + 6 >>> finite_diff(x**2 + 3*x + 8, x, 2) 4*x + 10 >>> finite_diff(z**3 + 8*z, z, 3) 9*z**2 + 27*z + 51 """ expression = expression.expand() expression2 = expression.subs(variable, variable + increment) expression2 = expression2.expand() return expression2 - expression def finite_diff_kauers(sum): """ Takes as input a Sum instance and returns the difference between the sum with the upper index incremented by 1 and the original sum. For example, if S(n) is a sum, then finite_diff_kauers will return S(n + 1) - S(n). Examples ======== >>> from sympy.series.kauers import finite_diff_kauers >>> from sympy import Sum >>> from sympy.abc import x, y, m, n, k >>> finite_diff_kauers(Sum(k, (k, 1, n))) n + 1 >>> finite_diff_kauers(Sum(1/k, (k, 1, n))) 1/(n + 1) >>> finite_diff_kauers(Sum((x*y**2), (x, 1, n), (y, 1, m))) (m + 1)**2*(n + 1) >>> finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n))) (m + 1)*(n + 1) """ function = sum.function for l in sum.limits: function = function.subs(l[0], l[- 1] + 1) return function sympy-sympy-1.9/sympy/series/limits.py000066400000000000000000000263111412543434000202540ustar00rootroot00000000000000from sympy.core import S, Symbol, Add, sympify, Expr, PoleError, Mul from sympy.core.exprtools import factor_terms from sympy.functions.combinatorial.factorials import factorial from sympy.functions.special.gamma_functions import gamma from sympy.polys import PolynomialError, factor from sympy.series.order import Order from sympy.simplify.ratsimp import ratsimp from sympy.simplify.simplify import together from .gruntz import gruntz def limit(e, z, z0, dir="+"): """Computes the limit of ``e(z)`` at the point ``z0``. Parameters ========== e : expression, the limit of which is to be taken z : symbol representing the variable in the limit. Other symbols are treated as constants. Multivariate limits are not supported. z0 : the value toward which ``z`` tends. Can be any expression, including ``oo`` and ``-oo``. dir : string, optional (default: "+") The limit is bi-directional if ``dir="+-"``, from the right (z->z0+) if ``dir="+"``, and from the left (z->z0-) if ``dir="-"``. For infinite ``z0`` (``oo`` or ``-oo``), the ``dir`` argument is determined from the direction of the infinity (i.e., ``dir="-"`` for ``oo``). Examples ======== >>> from sympy import limit, sin, oo >>> from sympy.abc import x >>> limit(sin(x)/x, x, 0) 1 >>> limit(1/x, x, 0) # default dir='+' oo >>> limit(1/x, x, 0, dir="-") -oo >>> limit(1/x, x, 0, dir='+-') zoo >>> limit(1/x, x, oo) 0 Notes ===== First we try some heuristics for easy and frequent cases like "x", "1/x", "x**2" and similar, so that it's fast. For all other cases, we use the Gruntz algorithm (see the gruntz() function). See Also ======== limit_seq : returns the limit of a sequence. """ return Limit(e, z, z0, dir).doit(deep=False) def heuristics(e, z, z0, dir): """Computes the limit of an expression term-wise. Parameters are the same as for the ``limit`` function. Works with the arguments of expression ``e`` one by one, computing the limit of each and then combining the results. This approach works only for simple limits, but it is fast. """ from sympy.calculus.util import AccumBounds rv = None if abs(z0) is S.Infinity: rv = limit(e.subs(z, 1/z), z, S.Zero, "+" if z0 is S.Infinity else "-") if isinstance(rv, Limit): return elif e.is_Mul or e.is_Add or e.is_Pow or e.is_Function: r = [] for a in e.args: l = limit(a, z, z0, dir) if l.has(S.Infinity) and l.is_finite is None: if isinstance(e, Add): m = factor_terms(e) if not isinstance(m, Mul): # try together m = together(m) if not isinstance(m, Mul): # try factor if the previous methods failed m = factor(e) if isinstance(m, Mul): return heuristics(m, z, z0, dir) return return elif isinstance(l, Limit): return elif l is S.NaN: return else: r.append(l) if r: rv = e.func(*r) if rv is S.NaN and e.is_Mul and any(isinstance(rr, AccumBounds) for rr in r): r2 = [] e2 = [] for ii in range(len(r)): if isinstance(r[ii], AccumBounds): r2.append(r[ii]) else: e2.append(e.args[ii]) if len(e2) > 0: e3 = Mul(*e2).simplify() l = limit(e3, z, z0, dir) rv = l * Mul(*r2) if rv is S.NaN: try: rat_e = ratsimp(e) except PolynomialError: return if rat_e is S.NaN or rat_e == e: return return limit(rat_e, z, z0, dir) return rv class Limit(Expr): """Represents an unevaluated limit. Examples ======== >>> from sympy import Limit, sin >>> from sympy.abc import x >>> Limit(sin(x)/x, x, 0) Limit(sin(x)/x, x, 0) >>> Limit(1/x, x, 0, dir="-") Limit(1/x, x, 0, dir='-') """ def __new__(cls, e, z, z0, dir="+"): e = sympify(e) z = sympify(z) z0 = sympify(z0) if z0 is S.Infinity: dir = "-" elif z0 is S.NegativeInfinity: dir = "+" if(z0.has(z)): raise NotImplementedError("Limits approaching a variable point are" " not supported (%s -> %s)" % (z, z0)) if isinstance(dir, str): dir = Symbol(dir) elif not isinstance(dir, Symbol): raise TypeError("direction must be of type basestring or " "Symbol, not %s" % type(dir)) if str(dir) not in ('+', '-', '+-'): raise ValueError("direction must be one of '+', '-' " "or '+-', not %s" % dir) obj = Expr.__new__(cls) obj._args = (e, z, z0, dir) return obj @property def free_symbols(self): e = self.args[0] isyms = e.free_symbols isyms.difference_update(self.args[1].free_symbols) isyms.update(self.args[2].free_symbols) return isyms def pow_heuristics(self): from sympy import exp, log expr, z, z0, _ = self.args b, e = expr.base, expr.exp if not b.has(z): res = limit(e*log(b), z, z0) return exp(res) ex_lim = limit(e, z, z0) base_lim = limit(b, z, z0) if base_lim is S.One: if ex_lim in (S.Infinity, S.NegativeInfinity): res = limit(e*(b - 1), z, z0) return exp(res) if base_lim is S.NegativeInfinity and ex_lim is S.Infinity: return S.ComplexInfinity def doit(self, **hints): """Evaluates the limit. Parameters ========== deep : bool, optional (default: True) Invoke the ``doit`` method of the expressions involved before taking the limit. hints : optional keyword arguments To be passed to ``doit`` methods; only used if deep is True. """ from sympy import Abs, sign e, z, z0, dir = self.args if z0 is S.ComplexInfinity: raise NotImplementedError("Limits at complex " "infinity are not implemented") if hints.get('deep', True): e = e.doit(**hints) z = z.doit(**hints) z0 = z0.doit(**hints) if e == z: return z0 if not e.has(z): return e if z0 is S.NaN: return S.NaN if e.has(S.Infinity, S.NegativeInfinity, S.ComplexInfinity, S.NaN): return self if e.is_Order: return Order(limit(e.expr, z, z0), *e.args[1:]) cdir = 0 if str(dir) == "+": cdir = 1 elif str(dir) == "-": cdir = -1 def set_signs(expr): if not expr.args: return expr newargs = tuple(set_signs(arg) for arg in expr.args) if newargs != expr.args: expr = expr.func(*newargs) abs_flag = isinstance(expr, Abs) sign_flag = isinstance(expr, sign) if abs_flag or sign_flag: sig = limit(expr.args[0], z, z0, dir) if sig.is_zero: sig = limit(1/expr.args[0], z, z0, dir) if sig.is_extended_real: if (sig < 0) == True: return -expr.args[0] if abs_flag else S.NegativeOne elif (sig > 0) == True: return expr.args[0] if abs_flag else S.One return expr e = set_signs(e) if e.is_meromorphic(z, z0): if abs(z0) is S.Infinity: newe = e.subs(z, -1/z) else: newe = e.subs(z, z + z0) try: coeff, ex = newe.leadterm(z, cdir=cdir) except ValueError: pass else: if ex > 0: return S.Zero elif ex == 0: return coeff if str(dir) == "+" or not(int(ex) & 1): return S.Infinity*sign(coeff) elif str(dir) == "-": return S.NegativeInfinity*sign(coeff) else: return S.ComplexInfinity if abs(z0) is S.Infinity: if e.is_Mul: e = factor_terms(e) newe = e.subs(z, 1/z) # cdir changes sign as oo- should become 0+ cdir = -cdir else: newe = e.subs(z, z + z0) try: coeff, ex = newe.leadterm(z, cdir=cdir) except (ValueError, NotImplementedError, PoleError): # The NotImplementedError catching is for custom functions if e.is_Pow: r = self.pow_heuristics() if r is not None: return r else: if coeff.has(S.Infinity, S.NegativeInfinity, S.ComplexInfinity): return self if not coeff.has(z): if ex.is_positive: return S.Zero elif ex == 0: return coeff elif ex.is_negative: if ex.is_integer: if str(dir) == "-" or ex.is_even: return S.Infinity*sign(coeff) elif str(dir) == "+": return S.NegativeInfinity*sign(coeff) else: return S.ComplexInfinity else: if str(dir) == "+": return S.Infinity*sign(coeff) elif str(dir) == "-": return S.NegativeInfinity*sign(coeff)*S.NegativeOne**(S.One + ex) else: return S.ComplexInfinity # gruntz fails on factorials but works with the gamma function # If no factorial term is present, e should remain unchanged. # factorial is defined to be zero for negative inputs (which # differs from gamma) so only rewrite for positive z0. if z0.is_extended_positive: e = e.rewrite(factorial, gamma) l = None try: if str(dir) == '+-': r = gruntz(e, z, z0, '+') l = gruntz(e, z, z0, '-') if l != r: raise ValueError("The limit does not exist since " "left hand limit = %s and right hand limit = %s" % (l, r)) else: r = gruntz(e, z, z0, dir) if r is S.NaN or l is S.NaN: raise PoleError() except (PoleError, ValueError): if l is not None: raise r = heuristics(e, z, z0, dir) if r is None: return self return r sympy-sympy-1.9/sympy/series/limitseq.py000066400000000000000000000170061412543434000206030ustar00rootroot00000000000000"""Limits of sequences""" from sympy.core.add import Add from sympy.core.function import PoleError from sympy.core.power import Pow from sympy.core.singleton import S from sympy.core.symbol import Dummy from sympy.core.sympify import sympify from sympy.functions.combinatorial.numbers import fibonacci from sympy.functions.combinatorial.factorials import factorial, subfactorial from sympy.functions.special.gamma_functions import gamma from sympy.functions.elementary.complexes import Abs from sympy.functions.elementary.miscellaneous import Max, Min from sympy.functions.elementary.trigonometric import cos, sin from sympy.series.limits import Limit def difference_delta(expr, n=None, step=1): """Difference Operator. Explanation =========== Discrete analog of differential operator. Given a sequence x[n], returns the sequence x[n + step] - x[n]. Examples ======== >>> from sympy import difference_delta as dd >>> from sympy.abc import n >>> dd(n*(n + 1), n) 2*n + 2 >>> dd(n*(n + 1), n, 2) 4*n + 6 References ========== .. [1] https://reference.wolfram.com/language/ref/DifferenceDelta.html """ expr = sympify(expr) if n is None: f = expr.free_symbols if len(f) == 1: n = f.pop() elif len(f) == 0: return S.Zero else: raise ValueError("Since there is more than one variable in the" " expression, a variable must be supplied to" " take the difference of %s" % expr) step = sympify(step) if step.is_number is False or step.is_finite is False: raise ValueError("Step should be a finite number.") if hasattr(expr, '_eval_difference_delta'): result = expr._eval_difference_delta(n, step) if result: return result return expr.subs(n, n + step) - expr def dominant(expr, n): """Finds the dominant term in a sum, that is a term that dominates every other term. Explanation =========== If limit(a/b, n, oo) is oo then a dominates b. If limit(a/b, n, oo) is 0 then b dominates a. Otherwise, a and b are comparable. If there is no unique dominant term, then returns ``None``. Examples ======== >>> from sympy import Sum >>> from sympy.series.limitseq import dominant >>> from sympy.abc import n, k >>> dominant(5*n**3 + 4*n**2 + n + 1, n) 5*n**3 >>> dominant(2**n + Sum(k, (k, 0, n)), n) 2**n See Also ======== sympy.series.limitseq.dominant """ terms = Add.make_args(expr.expand(func=True)) term0 = terms[-1] comp = [term0] # comparable terms for t in terms[:-1]: e = (term0 / t).gammasimp() l = limit_seq(e, n) if l is None: return None elif l.is_zero: term0 = t comp = [term0] elif l not in [S.Infinity, S.NegativeInfinity]: comp.append(t) if len(comp) > 1: return None return term0 def _limit_inf(expr, n): try: return Limit(expr, n, S.Infinity).doit(deep=False) except (NotImplementedError, PoleError): return None def _limit_seq(expr, n, trials): from sympy.concrete.summations import Sum for i in range(trials): if not expr.has(Sum): result = _limit_inf(expr, n) if result is not None: return result num, den = expr.as_numer_denom() if not den.has(n) or not num.has(n): result = _limit_inf(expr.doit(), n) if result is not None: return result return None num, den = (difference_delta(t.expand(), n) for t in [num, den]) expr = (num / den).gammasimp() if not expr.has(Sum): result = _limit_inf(expr, n) if result is not None: return result num, den = expr.as_numer_denom() num = dominant(num, n) if num is None: return None den = dominant(den, n) if den is None: return None expr = (num / den).gammasimp() def limit_seq(expr, n=None, trials=5): """Finds the limit of a sequence as index ``n`` tends to infinity. Parameters ========== expr : Expr SymPy expression for the ``n-th`` term of the sequence n : Symbol, optional The index of the sequence, an integer that tends to positive infinity. If None, inferred from the expression unless it has multiple symbols. trials: int, optional The algorithm is highly recursive. ``trials`` is a safeguard from infinite recursion in case the limit is not easily computed by the algorithm. Try increasing ``trials`` if the algorithm returns ``None``. Admissible Terms ================ The algorithm is designed for sequences built from rational functions, indefinite sums, and indefinite products over an indeterminate n. Terms of alternating sign are also allowed, but more complex oscillatory behavior is not supported. Examples ======== >>> from sympy import limit_seq, Sum, binomial >>> from sympy.abc import n, k, m >>> limit_seq((5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5), n) 5/3 >>> limit_seq(binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n)), n) 3/4 >>> limit_seq(Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n), n) 4 See Also ======== sympy.series.limitseq.dominant References ========== .. [1] Computing Limits of Sequences - Manuel Kauers """ from sympy.concrete.summations import Sum from sympy.calculus.util import AccumulationBounds if n is None: free = expr.free_symbols if len(free) == 1: n = free.pop() elif not free: return expr else: raise ValueError("Expression has more than one variable. " "Please specify a variable.") elif n not in expr.free_symbols: return expr expr = expr.rewrite(fibonacci, S.GoldenRatio) expr = expr.rewrite(factorial, subfactorial, gamma) n_ = Dummy("n", integer=True, positive=True) n1 = Dummy("n", odd=True, positive=True) n2 = Dummy("n", even=True, positive=True) # If there is a negative term raised to a power involving n, or a # trigonometric function, then consider even and odd n separately. powers = (p.as_base_exp() for p in expr.atoms(Pow)) if (any(b.is_negative and e.has(n) for b, e in powers) or expr.has(cos, sin)): L1 = _limit_seq(expr.xreplace({n: n1}), n1, trials) if L1 is not None: L2 = _limit_seq(expr.xreplace({n: n2}), n2, trials) if L1 != L2: if L1.is_comparable and L2.is_comparable: return AccumulationBounds(Min(L1, L2), Max(L1, L2)) else: return None else: L1 = _limit_seq(expr.xreplace({n: n_}), n_, trials) if L1 is not None: return L1 else: if expr.is_Add: limits = [limit_seq(term, n, trials) for term in expr.args] if any(result is None for result in limits): return None else: return Add(*limits) # Maybe the absolute value is easier to deal with (though not if # it has a Sum). If it tends to 0, the limit is 0. elif not expr.has(Sum): lim = _limit_seq(Abs(expr.xreplace({n: n_})), n_, trials) if lim is not None and lim.is_zero: return S.Zero sympy-sympy-1.9/sympy/series/order.py000066400000000000000000000444461412543434000200770ustar00rootroot00000000000000from sympy.core import S, sympify, Expr, Dummy from sympy.core import Add, Mul, expand_power_base, expand_log from sympy.core.cache import cacheit from sympy.core.compatibility import default_sort_key, is_sequence from sympy.core.containers import Tuple from sympy.sets.sets import Complement from sympy.utilities.iterables import uniq class Order(Expr): r""" Represents the limiting behavior of some function. Explanation =========== The order of a function characterizes the function based on the limiting behavior of the function as it goes to some limit. Only taking the limit point to be a number is currently supported. This is expressed in big O notation [1]_. The formal definition for the order of a function `g(x)` about a point `a` is such that `g(x) = O(f(x))` as `x \rightarrow a` if and only if for any `\delta > 0` there exists a `M > 0` such that `|g(x)| \leq M|f(x)|` for `|x-a| < \delta`. This is equivalent to `\lim_{x \rightarrow a} \sup |g(x)/f(x)| < \infty`. Let's illustrate it on the following example by taking the expansion of `\sin(x)` about 0: .. math :: \sin(x) = x - x^3/3! + O(x^5) where in this case `O(x^5) = x^5/5! - x^7/7! + \cdots`. By the definition of `O`, for any `\delta > 0` there is an `M` such that: .. math :: |x^5/5! - x^7/7! + ....| <= M|x^5| \text{ for } |x| < \delta or by the alternate definition: .. math :: \lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| < \infty which surely is true, because .. math :: \lim_{x \rightarrow 0} | (x^5/5! - x^7/7! + ....) / x^5| = 1/5! As it is usually used, the order of a function can be intuitively thought of representing all terms of powers greater than the one specified. For example, `O(x^3)` corresponds to any terms proportional to `x^3, x^4,\ldots` and any higher power. For a polynomial, this leaves terms proportional to `x^2`, `x` and constants. Examples ======== >>> from sympy import O, oo, cos, pi >>> from sympy.abc import x, y >>> O(x + x**2) O(x) >>> O(x + x**2, (x, 0)) O(x) >>> O(x + x**2, (x, oo)) O(x**2, (x, oo)) >>> O(1 + x*y) O(1, x, y) >>> O(1 + x*y, (x, 0), (y, 0)) O(1, x, y) >>> O(1 + x*y, (x, oo), (y, oo)) O(x*y, (x, oo), (y, oo)) >>> O(1) in O(1, x) True >>> O(1, x) in O(1) False >>> O(x) in O(1, x) True >>> O(x**2) in O(x) True >>> O(x)*x O(x**2) >>> O(x) - O(x) O(x) >>> O(cos(x)) O(1) >>> O(cos(x), (x, pi/2)) O(x - pi/2, (x, pi/2)) References ========== .. [1] `Big O notation `_ Notes ===== In ``O(f(x), x)`` the expression ``f(x)`` is assumed to have a leading term. ``O(f(x), x)`` is automatically transformed to ``O(f(x).as_leading_term(x),x)``. ``O(expr*f(x), x)`` is ``O(f(x), x)`` ``O(expr, x)`` is ``O(1)`` ``O(0, x)`` is 0. Multivariate O is also supported: ``O(f(x, y), x, y)`` is transformed to ``O(f(x, y).as_leading_term(x,y).as_leading_term(y), x, y)`` In the multivariate case, it is assumed the limits w.r.t. the various symbols commute. If no symbols are passed then all symbols in the expression are used and the limit point is assumed to be zero. """ is_Order = True __slots__ = () @cacheit def __new__(cls, expr, *args, **kwargs): expr = sympify(expr) if not args: if expr.is_Order: variables = expr.variables point = expr.point else: variables = list(expr.free_symbols) point = [S.Zero]*len(variables) else: args = list(args if is_sequence(args) else [args]) variables, point = [], [] if is_sequence(args[0]): for a in args: v, p = list(map(sympify, a)) variables.append(v) point.append(p) else: variables = list(map(sympify, args)) point = [S.Zero]*len(variables) if not all(v.is_symbol for v in variables): raise TypeError('Variables are not symbols, got %s' % variables) if len(list(uniq(variables))) != len(variables): raise ValueError('Variables are supposed to be unique symbols, got %s' % variables) if expr.is_Order: expr_vp = dict(expr.args[1:]) new_vp = dict(expr_vp) vp = dict(zip(variables, point)) for v, p in vp.items(): if v in new_vp.keys(): if p != new_vp[v]: raise NotImplementedError( "Mixing Order at different points is not supported.") else: new_vp[v] = p if set(expr_vp.keys()) == set(new_vp.keys()): return expr else: variables = list(new_vp.keys()) point = [new_vp[v] for v in variables] if expr is S.NaN: return S.NaN if any(x in p.free_symbols for x in variables for p in point): raise ValueError('Got %s as a point.' % point) if variables: if any(p != point[0] for p in point): raise NotImplementedError( "Multivariable orders at different points are not supported.") if point[0] is S.Infinity: s = {k: 1/Dummy() for k in variables} rs = {1/v: 1/k for k, v in s.items()} ps = [S.Zero for p in point] elif point[0] is S.NegativeInfinity: s = {k: -1/Dummy() for k in variables} rs = {-1/v: -1/k for k, v in s.items()} ps = [S.Zero for p in point] elif point[0] is not S.Zero: s = {k: Dummy() + point[0] for k in variables} rs = {(v - point[0]).together(): k - point[0] for k, v in s.items()} ps = [S.Zero for p in point] else: s = () rs = () ps = list(point) expr = expr.subs(s) if expr.is_Add: expr = expr.factor() if s: args = tuple([r[0] for r in rs.items()]) else: args = tuple(variables) if len(variables) > 1: # XXX: better way? We need this expand() to # workaround e.g: expr = x*(x + y). # (x*(x + y)).as_leading_term(x, y) currently returns # x*y (wrong order term!). That's why we want to deal with # expand()'ed expr (handled in "if expr.is_Add" branch below). expr = expr.expand() old_expr = None while old_expr != expr: old_expr = expr if expr.is_Add: lst = expr.extract_leading_order(args) expr = Add(*[f.expr for (e, f) in lst]) elif expr: from sympy import PoleError, Function try: expr = expr.as_leading_term(*args) except PoleError: if isinstance(expr, Function) or\ all(isinstance(arg, Function) for arg in expr.args): # It is not possible to simplify an expression # containing only functions (which raise error on # call to leading term) further pass else: orders = [] pts = tuple(zip(args, ps)) for arg in expr.args: try: lt = arg.as_leading_term(*args) except PoleError: lt = arg if lt not in args: order = Order(lt) else: order = Order(lt, *pts) orders.append(order) if expr.is_Add: new_expr = Order(Add(*orders), *pts) if new_expr.is_Add: new_expr = Order(Add(*[a.expr for a in new_expr.args]), *pts) expr = new_expr.expr elif expr.is_Mul: expr = Mul(*[a.expr for a in orders]) elif expr.is_Pow: expr = orders[0].expr**orders[1].expr expr = expr.as_independent(*args, as_Add=False)[1] expr = expand_power_base(expr) expr = expand_log(expr) if len(args) == 1: # The definition of O(f(x)) symbol explicitly stated that # the argument of f(x) is irrelevant. That's why we can # combine some power exponents (only "on top" of the # expression tree for f(x)), e.g.: # x**p * (-x)**q -> x**(p+q) for real p, q. x = args[0] margs = list(Mul.make_args( expr.as_independent(x, as_Add=False)[1])) for i, t in enumerate(margs): if t.is_Pow: b, q = t.args if b in (x, -x) and q.is_real and not q.has(x): margs[i] = x**q elif b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) elif b.is_Mul and b.args[0] is S.NegativeOne: b = -b if b.is_Pow and not b.exp.has(x): b, r = b.args if b in (x, -x) and r.is_real: margs[i] = x**(r*q) expr = Mul(*margs) expr = expr.subs(rs) if expr.is_Order: expr = expr.expr if not expr.has(*variables) and not expr.is_zero: expr = S.One # create Order instance: vp = dict(zip(variables, point)) variables.sort(key=default_sort_key) point = [vp[v] for v in variables] args = (expr,) + Tuple(*zip(variables, point)) obj = Expr.__new__(cls, *args) return obj def _eval_nseries(self, x, n, logx, cdir=0): return self @property def expr(self): return self.args[0] @property def variables(self): if self.args[1:]: return tuple(x[0] for x in self.args[1:]) else: return () @property def point(self): if self.args[1:]: return tuple(x[1] for x in self.args[1:]) else: return () @property def free_symbols(self): return self.expr.free_symbols | set(self.variables) def _eval_power(b, e): if e.is_Number and e.is_nonnegative: return b.func(b.expr ** e, *b.args[1:]) if e == O(1): return b return def as_expr_variables(self, order_symbols): if order_symbols is None: order_symbols = self.args[1:] else: if (not all(o[1] == order_symbols[0][1] for o in order_symbols) and not all(p == self.point[0] for p in self.point)): # pragma: no cover raise NotImplementedError('Order at points other than 0 ' 'or oo not supported, got %s as a point.' % self.point) if order_symbols and order_symbols[0][1] != self.point[0]: raise NotImplementedError( "Multiplying Order at different points is not supported.") order_symbols = dict(order_symbols) for s, p in dict(self.args[1:]).items(): if s not in order_symbols.keys(): order_symbols[s] = p order_symbols = sorted(order_symbols.items(), key=lambda x: default_sort_key(x[0])) return self.expr, tuple(order_symbols) def removeO(self): return S.Zero def getO(self): return self @cacheit def contains(self, expr): r""" Return True if expr belongs to Order(self.expr, \*self.variables). Return False if self belongs to expr. Return None if the inclusion relation cannot be determined (e.g. when self and expr have different symbols). """ from sympy import powsimp if expr.is_zero: return True if expr is S.NaN: return False point = self.point[0] if self.point else S.Zero if expr.is_Order: if (any(p != point for p in expr.point) or any(p != point for p in self.point)): return None if expr.expr == self.expr: # O(1) + O(1), O(1) + O(1, x), etc. return all([x in self.args[1:] for x in expr.args[1:]]) if expr.expr.is_Add: return all([self.contains(x) for x in expr.expr.args]) if self.expr.is_Add and point.is_zero: return any([self.func(x, *self.args[1:]).contains(expr) for x in self.expr.args]) if self.variables and expr.variables: common_symbols = tuple( [s for s in self.variables if s in expr.variables]) elif self.variables: common_symbols = self.variables else: common_symbols = expr.variables if not common_symbols: return None if (self.expr.is_Pow and len(self.variables) == 1 and self.variables == expr.variables): symbol = self.variables[0] other = expr.expr.as_independent(symbol, as_Add=False)[1] if (other.is_Pow and other.base == symbol and self.expr.base == symbol): if point.is_zero: rv = (self.expr.exp - other.exp).is_nonpositive if point.is_infinite: rv = (self.expr.exp - other.exp).is_nonnegative if rv is not None: return rv r = None ratio = self.expr/expr.expr ratio = powsimp(ratio, deep=True, combine='exp') for s in common_symbols: from sympy.series.limits import Limit l = Limit(ratio, s, point).doit(heuristics=False) if not isinstance(l, Limit): l = l != 0 else: l = None if r is None: r = l else: if r != l: return return r if self.expr.is_Pow and len(self.variables) == 1: symbol = self.variables[0] other = expr.as_independent(symbol, as_Add=False)[1] if (other.is_Pow and other.base == symbol and self.expr.base == symbol): if point.is_zero: rv = (self.expr.exp - other.exp).is_nonpositive if point.is_infinite: rv = (self.expr.exp - other.exp).is_nonnegative if rv is not None: return rv obj = self.func(expr, *self.args[1:]) return self.contains(obj) def __contains__(self, other): result = self.contains(other) if result is None: raise TypeError('contains did not evaluate to a bool') return result def _eval_subs(self, old, new): if old in self.variables: newexpr = self.expr.subs(old, new) i = self.variables.index(old) newvars = list(self.variables) newpt = list(self.point) if new.is_symbol: newvars[i] = new else: syms = new.free_symbols if len(syms) == 1 or old in syms: if old in syms: var = self.variables[i] else: var = syms.pop() # First, try to substitute self.point in the "new" # expr to see if this is a fixed point. # E.g. O(y).subs(y, sin(x)) point = new.subs(var, self.point[i]) if point != self.point[i]: from sympy.solvers.solveset import solveset d = Dummy() sol = solveset(old - new.subs(var, d), d) if isinstance(sol, Complement): e1 = sol.args[0] e2 = sol.args[1] sol = set(e1) - set(e2) res = [dict(zip((d, ), sol))] point = d.subs(res[0]).limit(old, self.point[i]) newvars[i] = var newpt[i] = point elif old not in syms: del newvars[i], newpt[i] if not syms and new == self.point[i]: newvars.extend(syms) newpt.extend([S.Zero]*len(syms)) else: return return Order(newexpr, *zip(newvars, newpt)) def _eval_conjugate(self): expr = self.expr._eval_conjugate() if expr is not None: return self.func(expr, *self.args[1:]) def _eval_derivative(self, x): return self.func(self.expr.diff(x), *self.args[1:]) or self def _eval_transpose(self): expr = self.expr._eval_transpose() if expr is not None: return self.func(expr, *self.args[1:]) def __neg__(self): return self O = Order sympy-sympy-1.9/sympy/series/residues.py000066400000000000000000000040541412543434000205760ustar00rootroot00000000000000""" This module implements the Residue function and related tools for working with residues. """ from sympy import sympify from sympy.utilities.timeutils import timethis @timethis('residue') def residue(expr, x, x0): """ Finds the residue of ``expr`` at the point x=x0. The residue is defined as the coefficient of ``1/(x-x0)`` in the power series expansion about ``x=x0``. Examples ======== >>> from sympy import Symbol, residue, sin >>> x = Symbol("x") >>> residue(1/x, x, 0) 1 >>> residue(1/x**2, x, 0) 0 >>> residue(2/sin(x), x, 0) 2 This function is essential for the Residue Theorem [1]. References ========== .. [1] https://en.wikipedia.org/wiki/Residue_theorem """ # The current implementation uses series expansion to # calculate it. A more general implementation is explained in # the section 5.6 of the Bronstein's book {M. Bronstein: # Symbolic Integration I, Springer Verlag (2005)}. For purely # rational functions, the algorithm is much easier. See # sections 2.4, 2.5, and 2.7 (this section actually gives an # algorithm for computing any Laurent series coefficient for # a rational function). The theory in section 2.4 will help to # understand why the resultant works in the general algorithm. # For the definition of a resultant, see section 1.4 (and any # previous sections for more review). from sympy import collect, Mul, Order, S expr = sympify(expr) if x0 != 0: expr = expr.subs(x, x + x0) for n in [0, 1, 2, 4, 8, 16, 32]: s = expr.nseries(x, n=n) if not s.has(Order) or s.getn() >= 0: break s = collect(s.removeO(), x) if s.is_Add: args = s.args else: args = [s] res = S.Zero for arg in args: c, m = arg.as_coeff_mul(x) m = Mul(*m) if not (m == 1 or m == x or (m.is_Pow and m.exp.is_Integer)): raise NotImplementedError('term of unexpected form: %s' % m) if m == 1/x: res += c return res sympy-sympy-1.9/sympy/series/sequences.py000066400000000000000000001053621412543434000207520ustar00rootroot00000000000000from sympy.core.basic import Basic from sympy.core.cache import cacheit from sympy.core.compatibility import is_sequence, iterable, ordered from sympy.core.containers import Tuple from sympy.core.decorators import call_highest_priority from sympy.core.parameters import global_parameters from sympy.core.function import AppliedUndef from sympy.core.mul import Mul from sympy.core.numbers import Integer from sympy.core.relational import Eq from sympy.core.singleton import S, Singleton from sympy.core.symbol import Dummy, Symbol, Wild from sympy.core.sympify import sympify from sympy.polys import lcm, factor from sympy.sets.sets import Interval, Intersection from sympy.simplify import simplify from sympy.tensor.indexed import Idx from sympy.utilities.iterables import flatten from sympy import expand ############################################################################### # SEQUENCES # ############################################################################### class SeqBase(Basic): """Base class for sequences""" is_commutative = True _op_priority = 15 @staticmethod def _start_key(expr): """Return start (if possible) else S.Infinity. adapted from Set._infimum_key """ try: start = expr.start except (NotImplementedError, AttributeError, ValueError): start = S.Infinity return start def _intersect_interval(self, other): """Returns start and stop. Takes intersection over the two intervals. """ interval = Intersection(self.interval, other.interval) return interval.inf, interval.sup @property def gen(self): """Returns the generator for the sequence""" raise NotImplementedError("(%s).gen" % self) @property def interval(self): """The interval on which the sequence is defined""" raise NotImplementedError("(%s).interval" % self) @property def start(self): """The starting point of the sequence. This point is included""" raise NotImplementedError("(%s).start" % self) @property def stop(self): """The ending point of the sequence. This point is included""" raise NotImplementedError("(%s).stop" % self) @property def length(self): """Length of the sequence""" raise NotImplementedError("(%s).length" % self) @property def variables(self): """Returns a tuple of variables that are bounded""" return () @property def free_symbols(self): """ This method returns the symbols in the object, excluding those that take on a specific value (i.e. the dummy symbols). Examples ======== >>> from sympy import SeqFormula >>> from sympy.abc import n, m >>> SeqFormula(m*n**2, (n, 0, 5)).free_symbols {m} """ return ({j for i in self.args for j in i.free_symbols .difference(self.variables)}) @cacheit def coeff(self, pt): """Returns the coefficient at point pt""" if pt < self.start or pt > self.stop: raise IndexError("Index %s out of bounds %s" % (pt, self.interval)) return self._eval_coeff(pt) def _eval_coeff(self, pt): raise NotImplementedError("The _eval_coeff method should be added to" "%s to return coefficient so it is available" "when coeff calls it." % self.func) def _ith_point(self, i): """Returns the i'th point of a sequence. Explanation =========== If start point is negative infinity, point is returned from the end. Assumes the first point to be indexed zero. Examples ========= >>> from sympy import oo >>> from sympy.series.sequences import SeqPer bounded >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(0) -10 >>> SeqPer((1, 2, 3), (-10, 10))._ith_point(5) -5 End is at infinity >>> SeqPer((1, 2, 3), (0, oo))._ith_point(5) 5 Starts at negative infinity >>> SeqPer((1, 2, 3), (-oo, 0))._ith_point(5) -5 """ if self.start is S.NegativeInfinity: initial = self.stop else: initial = self.start if self.start is S.NegativeInfinity: step = -1 else: step = 1 return initial + i*step def _add(self, other): """ Should only be used internally. Explanation =========== self._add(other) returns a new, term-wise added sequence if self knows how to add with other, otherwise it returns ``None``. ``other`` should only be a sequence object. Used within :class:`SeqAdd` class. """ return None def _mul(self, other): """ Should only be used internally. Explanation =========== self._mul(other) returns a new, term-wise multiplied sequence if self knows how to multiply with other, otherwise it returns ``None``. ``other`` should only be a sequence object. Used within :class:`SeqMul` class. """ return None def coeff_mul(self, other): """ Should be used when ``other`` is not a sequence. Should be defined to define custom behaviour. Examples ======== >>> from sympy import SeqFormula >>> from sympy.abc import n >>> SeqFormula(n**2).coeff_mul(2) SeqFormula(2*n**2, (n, 0, oo)) Notes ===== '*' defines multiplication of sequences with sequences only. """ return Mul(self, other) def __add__(self, other): """Returns the term-wise addition of 'self' and 'other'. ``other`` should be a sequence. Examples ======== >>> from sympy import SeqFormula >>> from sympy.abc import n >>> SeqFormula(n**2) + SeqFormula(n**3) SeqFormula(n**3 + n**2, (n, 0, oo)) """ if not isinstance(other, SeqBase): raise TypeError('cannot add sequence and %s' % type(other)) return SeqAdd(self, other) @call_highest_priority('__add__') def __radd__(self, other): return self + other def __sub__(self, other): """Returns the term-wise subtraction of ``self`` and ``other``. ``other`` should be a sequence. Examples ======== >>> from sympy import SeqFormula >>> from sympy.abc import n >>> SeqFormula(n**2) - (SeqFormula(n)) SeqFormula(n**2 - n, (n, 0, oo)) """ if not isinstance(other, SeqBase): raise TypeError('cannot subtract sequence and %s' % type(other)) return SeqAdd(self, -other) @call_highest_priority('__sub__') def __rsub__(self, other): return (-self) + other def __neg__(self): """Negates the sequence. Examples ======== >>> from sympy import SeqFormula >>> from sympy.abc import n >>> -SeqFormula(n**2) SeqFormula(-n**2, (n, 0, oo)) """ return self.coeff_mul(-1) def __mul__(self, other): """Returns the term-wise multiplication of 'self' and 'other'. ``other`` should be a sequence. For ``other`` not being a sequence see :func:`coeff_mul` method. Examples ======== >>> from sympy import SeqFormula >>> from sympy.abc import n >>> SeqFormula(n**2) * (SeqFormula(n)) SeqFormula(n**3, (n, 0, oo)) """ if not isinstance(other, SeqBase): raise TypeError('cannot multiply sequence and %s' % type(other)) return SeqMul(self, other) @call_highest_priority('__mul__') def __rmul__(self, other): return self * other def __iter__(self): for i in range(self.length): pt = self._ith_point(i) yield self.coeff(pt) def __getitem__(self, index): if isinstance(index, int): index = self._ith_point(index) return self.coeff(index) elif isinstance(index, slice): start, stop = index.start, index.stop if start is None: start = 0 if stop is None: stop = self.length return [self.coeff(self._ith_point(i)) for i in range(start, stop, index.step or 1)] def find_linear_recurrence(self,n,d=None,gfvar=None): r""" Finds the shortest linear recurrence that satisfies the first n terms of sequence of order `\leq` ``n/2`` if possible. If ``d`` is specified, find shortest linear recurrence of order `\leq` min(d, n/2) if possible. Returns list of coefficients ``[b(1), b(2), ...]`` corresponding to the recurrence relation ``x(n) = b(1)*x(n-1) + b(2)*x(n-2) + ...`` Returns ``[]`` if no recurrence is found. If gfvar is specified, also returns ordinary generating function as a function of gfvar. Examples ======== >>> from sympy import sequence, sqrt, oo, lucas >>> from sympy.abc import n, x, y >>> sequence(n**2).find_linear_recurrence(10, 2) [] >>> sequence(n**2).find_linear_recurrence(10) [3, -3, 1] >>> sequence(2**n).find_linear_recurrence(10) [2] >>> sequence(23*n**4+91*n**2).find_linear_recurrence(10) [5, -10, 10, -5, 1] >>> sequence(sqrt(5)*(((1 + sqrt(5))/2)**n - (-(1 + sqrt(5))/2)**(-n))/5).find_linear_recurrence(10) [1, 1] >>> sequence(x+y*(-2)**(-n), (n, 0, oo)).find_linear_recurrence(30) [1/2, 1/2] >>> sequence(3*5**n + 12).find_linear_recurrence(20,gfvar=x) ([6, -5], 3*(5 - 21*x)/((x - 1)*(5*x - 1))) >>> sequence(lucas(n)).find_linear_recurrence(15,gfvar=x) ([1, 1], (x - 2)/(x**2 + x - 1)) """ from sympy.matrices import Matrix x = [simplify(expand(t)) for t in self[:n]] lx = len(x) if d is None: r = lx//2 else: r = min(d,lx//2) coeffs = [] for l in range(1, r+1): l2 = 2*l mlist = [] for k in range(l): mlist.append(x[k:k+l]) m = Matrix(mlist) if m.det() != 0: y = simplify(m.LUsolve(Matrix(x[l:l2]))) if lx == l2: coeffs = flatten(y[::-1]) break mlist = [] for k in range(l,lx-l): mlist.append(x[k:k+l]) m = Matrix(mlist) if m*y == Matrix(x[l2:]): coeffs = flatten(y[::-1]) break if gfvar is None: return coeffs else: l = len(coeffs) if l == 0: return [], None else: n, d = x[l-1]*gfvar**(l-1), 1 - coeffs[l-1]*gfvar**l for i in range(l-1): n += x[i]*gfvar**i for j in range(l-i-1): n -= coeffs[i]*x[j]*gfvar**(i+j+1) d -= coeffs[i]*gfvar**(i+1) return coeffs, simplify(factor(n)/factor(d)) class EmptySequence(SeqBase, metaclass=Singleton): """Represents an empty sequence. The empty sequence is also available as a singleton as ``S.EmptySequence``. Examples ======== >>> from sympy import EmptySequence, SeqPer >>> from sympy.abc import x >>> EmptySequence EmptySequence >>> SeqPer((1, 2), (x, 0, 10)) + EmptySequence SeqPer((1, 2), (x, 0, 10)) >>> SeqPer((1, 2)) * EmptySequence EmptySequence >>> EmptySequence.coeff_mul(-1) EmptySequence """ @property def interval(self): return S.EmptySet @property def length(self): return S.Zero def coeff_mul(self, coeff): """See docstring of SeqBase.coeff_mul""" return self def __iter__(self): return iter([]) class SeqExpr(SeqBase): """Sequence expression class. Various sequences should inherit from this class. Examples ======== >>> from sympy.series.sequences import SeqExpr >>> from sympy.abc import x >>> s = SeqExpr((1, 2, 3), (x, 0, 10)) >>> s.gen (1, 2, 3) >>> s.interval Interval(0, 10) >>> s.length 11 See Also ======== sympy.series.sequences.SeqPer sympy.series.sequences.SeqFormula """ @property def gen(self): return self.args[0] @property def interval(self): return Interval(self.args[1][1], self.args[1][2]) @property def start(self): return self.interval.inf @property def stop(self): return self.interval.sup @property def length(self): return self.stop - self.start + 1 @property def variables(self): return (self.args[1][0],) class SeqPer(SeqExpr): """ Represents a periodic sequence. The elements are repeated after a given period. Examples ======== >>> from sympy import SeqPer, oo >>> from sympy.abc import k >>> s = SeqPer((1, 2, 3), (0, 5)) >>> s.periodical (1, 2, 3) >>> s.period 3 For value at a particular point >>> s.coeff(3) 1 supports slicing >>> s[:] [1, 2, 3, 1, 2, 3] iterable >>> list(s) [1, 2, 3, 1, 2, 3] sequence starts from negative infinity >>> SeqPer((1, 2, 3), (-oo, 0))[0:6] [1, 2, 3, 1, 2, 3] Periodic formulas >>> SeqPer((k, k**2, k**3), (k, 0, oo))[0:6] [0, 1, 8, 3, 16, 125] See Also ======== sympy.series.sequences.SeqFormula """ def __new__(cls, periodical, limits=None): periodical = sympify(periodical) def _find_x(periodical): free = periodical.free_symbols if len(periodical.free_symbols) == 1: return free.pop() else: return Dummy('k') x, start, stop = None, None, None if limits is None: x, start, stop = _find_x(periodical), 0, S.Infinity if is_sequence(limits, Tuple): if len(limits) == 3: x, start, stop = limits elif len(limits) == 2: x = _find_x(periodical) start, stop = limits if not isinstance(x, (Symbol, Idx)) or start is None or stop is None: raise ValueError('Invalid limits given: %s' % str(limits)) if start is S.NegativeInfinity and stop is S.Infinity: raise ValueError("Both the start and end value" "cannot be unbounded") limits = sympify((x, start, stop)) if is_sequence(periodical, Tuple): periodical = sympify(tuple(flatten(periodical))) else: raise ValueError("invalid period %s should be something " "like e.g (1, 2) " % periodical) if Interval(limits[1], limits[2]) is S.EmptySet: return S.EmptySequence return Basic.__new__(cls, periodical, limits) @property def period(self): return len(self.gen) @property def periodical(self): return self.gen def _eval_coeff(self, pt): if self.start is S.NegativeInfinity: idx = (self.stop - pt) % self.period else: idx = (pt - self.start) % self.period return self.periodical[idx].subs(self.variables[0], pt) def _add(self, other): """See docstring of SeqBase._add""" if isinstance(other, SeqPer): per1, lper1 = self.periodical, self.period per2, lper2 = other.periodical, other.period per_length = lcm(lper1, lper2) new_per = [] for x in range(per_length): ele1 = per1[x % lper1] ele2 = per2[x % lper2] new_per.append(ele1 + ele2) start, stop = self._intersect_interval(other) return SeqPer(new_per, (self.variables[0], start, stop)) def _mul(self, other): """See docstring of SeqBase._mul""" if isinstance(other, SeqPer): per1, lper1 = self.periodical, self.period per2, lper2 = other.periodical, other.period per_length = lcm(lper1, lper2) new_per = [] for x in range(per_length): ele1 = per1[x % lper1] ele2 = per2[x % lper2] new_per.append(ele1 * ele2) start, stop = self._intersect_interval(other) return SeqPer(new_per, (self.variables[0], start, stop)) def coeff_mul(self, coeff): """See docstring of SeqBase.coeff_mul""" coeff = sympify(coeff) per = [x * coeff for x in self.periodical] return SeqPer(per, self.args[1]) class SeqFormula(SeqExpr): """ Represents sequence based on a formula. Elements are generated using a formula. Examples ======== >>> from sympy import SeqFormula, oo, Symbol >>> n = Symbol('n') >>> s = SeqFormula(n**2, (n, 0, 5)) >>> s.formula n**2 For value at a particular point >>> s.coeff(3) 9 supports slicing >>> s[:] [0, 1, 4, 9, 16, 25] iterable >>> list(s) [0, 1, 4, 9, 16, 25] sequence starts from negative infinity >>> SeqFormula(n**2, (-oo, 0))[0:6] [0, 1, 4, 9, 16, 25] See Also ======== sympy.series.sequences.SeqPer """ def __new__(cls, formula, limits=None): formula = sympify(formula) def _find_x(formula): free = formula.free_symbols if len(free) == 1: return free.pop() elif not free: return Dummy('k') else: raise ValueError( " specify dummy variables for %s. If the formula contains" " more than one free symbol, a dummy variable should be" " supplied explicitly e.g., SeqFormula(m*n**2, (n, 0, 5))" % formula) x, start, stop = None, None, None if limits is None: x, start, stop = _find_x(formula), 0, S.Infinity if is_sequence(limits, Tuple): if len(limits) == 3: x, start, stop = limits elif len(limits) == 2: x = _find_x(formula) start, stop = limits if not isinstance(x, (Symbol, Idx)) or start is None or stop is None: raise ValueError('Invalid limits given: %s' % str(limits)) if start is S.NegativeInfinity and stop is S.Infinity: raise ValueError("Both the start and end value " "cannot be unbounded") limits = sympify((x, start, stop)) if Interval(limits[1], limits[2]) is S.EmptySet: return S.EmptySequence return Basic.__new__(cls, formula, limits) @property def formula(self): return self.gen def _eval_coeff(self, pt): d = self.variables[0] return self.formula.subs(d, pt) def _add(self, other): """See docstring of SeqBase._add""" if isinstance(other, SeqFormula): form1, v1 = self.formula, self.variables[0] form2, v2 = other.formula, other.variables[0] formula = form1 + form2.subs(v2, v1) start, stop = self._intersect_interval(other) return SeqFormula(formula, (v1, start, stop)) def _mul(self, other): """See docstring of SeqBase._mul""" if isinstance(other, SeqFormula): form1, v1 = self.formula, self.variables[0] form2, v2 = other.formula, other.variables[0] formula = form1 * form2.subs(v2, v1) start, stop = self._intersect_interval(other) return SeqFormula(formula, (v1, start, stop)) def coeff_mul(self, coeff): """See docstring of SeqBase.coeff_mul""" coeff = sympify(coeff) formula = self.formula * coeff return SeqFormula(formula, self.args[1]) def expand(self, *args, **kwargs): return SeqFormula(expand(self.formula, *args, **kwargs), self.args[1]) class RecursiveSeq(SeqBase): """ A finite degree recursive sequence. Explanation =========== That is, a sequence a(n) that depends on a fixed, finite number of its previous values. The general form is a(n) = f(a(n - 1), a(n - 2), ..., a(n - d)) for some fixed, positive integer d, where f is some function defined by a SymPy expression. Parameters ========== recurrence : SymPy expression defining recurrence This is *not* an equality, only the expression that the nth term is equal to. For example, if :code:`a(n) = f(a(n - 1), ..., a(n - d))`, then the expression should be :code:`f(a(n - 1), ..., a(n - d))`. yn : applied undefined function Represents the nth term of the sequence as e.g. :code:`y(n)` where :code:`y` is an undefined function and `n` is the sequence index. n : symbolic argument The name of the variable that the recurrence is in, e.g., :code:`n` if the recurrence function is :code:`y(n)`. initial : iterable with length equal to the degree of the recurrence The initial values of the recurrence. start : start value of sequence (inclusive) Examples ======== >>> from sympy import Function, symbols >>> from sympy.series.sequences import RecursiveSeq >>> y = Function("y") >>> n = symbols("n") >>> fib = RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, [0, 1]) >>> fib.coeff(3) # Value at a particular point 2 >>> fib[:6] # supports slicing [0, 1, 1, 2, 3, 5] >>> fib.recurrence # inspect recurrence Eq(y(n), y(n - 2) + y(n - 1)) >>> fib.degree # automatically determine degree 2 >>> for x in zip(range(10), fib): # supports iteration ... print(x) (0, 0) (1, 1) (2, 1) (3, 2) (4, 3) (5, 5) (6, 8) (7, 13) (8, 21) (9, 34) See Also ======== sympy.series.sequences.SeqFormula """ def __new__(cls, recurrence, yn, n, initial=None, start=0): if not isinstance(yn, AppliedUndef): raise TypeError("recurrence sequence must be an applied undefined function" ", found `{}`".format(yn)) if not isinstance(n, Basic) or not n.is_symbol: raise TypeError("recurrence variable must be a symbol" ", found `{}`".format(n)) if yn.args != (n,): raise TypeError("recurrence sequence does not match symbol") y = yn.func k = Wild("k", exclude=(n,)) degree = 0 # Find all applications of y in the recurrence and check that: # 1. The function y is only being used with a single argument; and # 2. All arguments are n + k for constant negative integers k. prev_ys = recurrence.find(y) for prev_y in prev_ys: if len(prev_y.args) != 1: raise TypeError("Recurrence should be in a single variable") shift = prev_y.args[0].match(n + k)[k] if not (shift.is_constant() and shift.is_integer and shift < 0): raise TypeError("Recurrence should have constant," " negative, integer shifts" " (found {})".format(prev_y)) if -shift > degree: degree = -shift if not initial: initial = [Dummy("c_{}".format(k)) for k in range(degree)] if len(initial) != degree: raise ValueError("Number of initial terms must equal degree") degree = Integer(degree) start = sympify(start) initial = Tuple(*(sympify(x) for x in initial)) seq = Basic.__new__(cls, recurrence, yn, n, initial, start) seq.cache = {y(start + k): init for k, init in enumerate(initial)} seq.degree = degree return seq @property def _recurrence(self): """Equation defining recurrence.""" return self.args[0] @property def recurrence(self): """Equation defining recurrence.""" return Eq(self.yn, self.args[0]) @property def yn(self): """Applied function representing the nth term""" return self.args[1] @property def y(self): """Undefined function for the nth term of the sequence""" return self.yn.func @property def n(self): """Sequence index symbol""" return self.args[2] @property def initial(self): """The initial values of the sequence""" return self.args[3] @property def start(self): """The starting point of the sequence. This point is included""" return self.args[4] @property def stop(self): """The ending point of the sequence. (oo)""" return S.Infinity @property def interval(self): """Interval on which sequence is defined.""" return (self.start, S.Infinity) def _eval_coeff(self, index): if index - self.start < len(self.cache): return self.cache[self.y(index)] for current in range(len(self.cache), index + 1): # Use xreplace over subs for performance. # See issue #10697. seq_index = self.start + current current_recurrence = self._recurrence.xreplace({self.n: seq_index}) new_term = current_recurrence.xreplace(self.cache) self.cache[self.y(seq_index)] = new_term return self.cache[self.y(self.start + current)] def __iter__(self): index = self.start while True: yield self._eval_coeff(index) index += 1 def sequence(seq, limits=None): """ Returns appropriate sequence object. Explanation =========== If ``seq`` is a sympy sequence, returns :class:`SeqPer` object otherwise returns :class:`SeqFormula` object. Examples ======== >>> from sympy import sequence >>> from sympy.abc import n >>> sequence(n**2, (n, 0, 5)) SeqFormula(n**2, (n, 0, 5)) >>> sequence((1, 2, 3), (n, 0, 5)) SeqPer((1, 2, 3), (n, 0, 5)) See Also ======== sympy.series.sequences.SeqPer sympy.series.sequences.SeqFormula """ seq = sympify(seq) if is_sequence(seq, Tuple): return SeqPer(seq, limits) else: return SeqFormula(seq, limits) ############################################################################### # OPERATIONS # ############################################################################### class SeqExprOp(SeqBase): """ Base class for operations on sequences. Examples ======== >>> from sympy.series.sequences import SeqExprOp, sequence >>> from sympy.abc import n >>> s1 = sequence(n**2, (n, 0, 10)) >>> s2 = sequence((1, 2, 3), (n, 5, 10)) >>> s = SeqExprOp(s1, s2) >>> s.gen (n**2, (1, 2, 3)) >>> s.interval Interval(5, 10) >>> s.length 6 See Also ======== sympy.series.sequences.SeqAdd sympy.series.sequences.SeqMul """ @property def gen(self): """Generator for the sequence. returns a tuple of generators of all the argument sequences. """ return tuple(a.gen for a in self.args) @property def interval(self): """Sequence is defined on the intersection of all the intervals of respective sequences """ return Intersection(*(a.interval for a in self.args)) @property def start(self): return self.interval.inf @property def stop(self): return self.interval.sup @property def variables(self): """Cumulative of all the bound variables""" return tuple(flatten([a.variables for a in self.args])) @property def length(self): return self.stop - self.start + 1 class SeqAdd(SeqExprOp): """Represents term-wise addition of sequences. Rules: * The interval on which sequence is defined is the intersection of respective intervals of sequences. * Anything + :class:`EmptySequence` remains unchanged. * Other rules are defined in ``_add`` methods of sequence classes. Examples ======== >>> from sympy import EmptySequence, oo, SeqAdd, SeqPer, SeqFormula >>> from sympy.abc import n >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), EmptySequence) SeqPer((1, 2), (n, 0, oo)) >>> SeqAdd(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10))) EmptySequence >>> SeqAdd(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2, (n, 0, oo))) SeqAdd(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo))) >>> SeqAdd(SeqFormula(n**3), SeqFormula(n**2)) SeqFormula(n**3 + n**2, (n, 0, oo)) See Also ======== sympy.series.sequences.SeqMul """ def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_parameters.evaluate) # flatten inputs args = list(args) # adapted from sympy.sets.sets.Union def _flatten(arg): if isinstance(arg, SeqBase): if isinstance(arg, SeqAdd): return sum(map(_flatten, arg.args), []) else: return [arg] if iterable(arg): return sum(map(_flatten, arg), []) raise TypeError("Input must be Sequences or " " iterables of Sequences") args = _flatten(args) args = [a for a in args if a is not S.EmptySequence] # Addition of no sequences is EmptySequence if not args: return S.EmptySequence if Intersection(*(a.interval for a in args)) is S.EmptySet: return S.EmptySequence # reduce using known rules if evaluate: return SeqAdd.reduce(args) args = list(ordered(args, SeqBase._start_key)) return Basic.__new__(cls, *args) @staticmethod def reduce(args): """Simplify :class:`SeqAdd` using known rules. Iterates through all pairs and ask the constituent sequences if they can simplify themselves with any other constituent. Notes ===== adapted from ``Union.reduce`` """ new_args = True while new_args: for id1, s in enumerate(args): new_args = False for id2, t in enumerate(args): if id1 == id2: continue new_seq = s._add(t) # This returns None if s does not know how to add # with t. Returns the newly added sequence otherwise if new_seq is not None: new_args = [a for a in args if a not in (s, t)] new_args.append(new_seq) break if new_args: args = new_args break if len(args) == 1: return args.pop() else: return SeqAdd(args, evaluate=False) def _eval_coeff(self, pt): """adds up the coefficients of all the sequences at point pt""" return sum(a.coeff(pt) for a in self.args) class SeqMul(SeqExprOp): r"""Represents term-wise multiplication of sequences. Explanation =========== Handles multiplication of sequences only. For multiplication with other objects see :func:`SeqBase.coeff_mul`. Rules: * The interval on which sequence is defined is the intersection of respective intervals of sequences. * Anything \* :class:`EmptySequence` returns :class:`EmptySequence`. * Other rules are defined in ``_mul`` methods of sequence classes. Examples ======== >>> from sympy import EmptySequence, oo, SeqMul, SeqPer, SeqFormula >>> from sympy.abc import n >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), EmptySequence) EmptySequence >>> SeqMul(SeqPer((1, 2), (n, 0, 5)), SeqPer((1, 2), (n, 6, 10))) EmptySequence >>> SeqMul(SeqPer((1, 2), (n, 0, oo)), SeqFormula(n**2)) SeqMul(SeqFormula(n**2, (n, 0, oo)), SeqPer((1, 2), (n, 0, oo))) >>> SeqMul(SeqFormula(n**3), SeqFormula(n**2)) SeqFormula(n**5, (n, 0, oo)) See Also ======== sympy.series.sequences.SeqAdd """ def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_parameters.evaluate) # flatten inputs args = list(args) # adapted from sympy.sets.sets.Union def _flatten(arg): if isinstance(arg, SeqBase): if isinstance(arg, SeqMul): return sum(map(_flatten, arg.args), []) else: return [arg] elif iterable(arg): return sum(map(_flatten, arg), []) raise TypeError("Input must be Sequences or " " iterables of Sequences") args = _flatten(args) # Multiplication of no sequences is EmptySequence if not args: return S.EmptySequence if Intersection(*(a.interval for a in args)) is S.EmptySet: return S.EmptySequence # reduce using known rules if evaluate: return SeqMul.reduce(args) args = list(ordered(args, SeqBase._start_key)) return Basic.__new__(cls, *args) @staticmethod def reduce(args): """Simplify a :class:`SeqMul` using known rules. Explanation =========== Iterates through all pairs and ask the constituent sequences if they can simplify themselves with any other constituent. Notes ===== adapted from ``Union.reduce`` """ new_args = True while new_args: for id1, s in enumerate(args): new_args = False for id2, t in enumerate(args): if id1 == id2: continue new_seq = s._mul(t) # This returns None if s does not know how to multiply # with t. Returns the newly multiplied sequence otherwise if new_seq is not None: new_args = [a for a in args if a not in (s, t)] new_args.append(new_seq) break if new_args: args = new_args break if len(args) == 1: return args.pop() else: return SeqMul(args, evaluate=False) def _eval_coeff(self, pt): """multiplies the coefficients of all the sequences at point pt""" val = 1 for a in self.args: val *= a.coeff(pt) return val sympy-sympy-1.9/sympy/series/series.py000066400000000000000000000035051412543434000202450ustar00rootroot00000000000000from sympy.core.sympify import sympify def series(expr, x=None, x0=0, n=6, dir="+"): """Series expansion of expr around point `x = x0`. Parameters ========== expr : Expression The expression whose series is to be expanded. x : Symbol It is the variable of the expression to be calculated. x0 : Value The value around which ``x`` is calculated. Can be any value from ``-oo`` to ``oo``. n : Value The number of terms upto which the series is to be expanded. dir : String, optional The series-expansion can be bi-directional. If ``dir="+"``, then (x->x0+). If ``dir="-", then (x->x0-). For infinite ``x0`` (``oo`` or ``-oo``), the ``dir`` argument is determined from the direction of the infinity (i.e., ``dir="-"`` for ``oo``). Examples ======== >>> from sympy import series, tan, oo >>> from sympy.abc import x >>> f = tan(x) >>> series(f, x, 2, 6, "+") tan(2) + (1 + tan(2)**2)*(x - 2) + (x - 2)**2*(tan(2)**3 + tan(2)) + (x - 2)**3*(1/3 + 4*tan(2)**2/3 + tan(2)**4) + (x - 2)**4*(tan(2)**5 + 5*tan(2)**3/3 + 2*tan(2)/3) + (x - 2)**5*(2/15 + 17*tan(2)**2/15 + 2*tan(2)**4 + tan(2)**6) + O((x - 2)**6, (x, 2)) >>> series(f, x, 2, 3, "-") tan(2) + (2 - x)*(-tan(2)**2 - 1) + (2 - x)**2*(tan(2)**3 + tan(2)) + O((x - 2)**3, (x, 2)) >>> series(f, x, 2, oo, "+") Traceback (most recent call last): ... TypeError: 'Infinity' object cannot be interpreted as an integer Returns ======= Expr Series expansion of the expression about x0 See Also ======== sympy.core.expr.Expr.series: See the docstring of Expr.series() for complete details of this wrapper. """ expr = sympify(expr) return expr.series(x, x0, n, dir) sympy-sympy-1.9/sympy/series/series_class.py000066400000000000000000000055461412543434000214410ustar00rootroot00000000000000""" Contains the base class for series Made using sequences in mind """ from sympy.core.expr import Expr from sympy.core.singleton import S from sympy.core.cache import cacheit class SeriesBase(Expr): """Base Class for series""" @property def interval(self): """The interval on which the series is defined""" raise NotImplementedError("(%s).interval" % self) @property def start(self): """The starting point of the series. This point is included""" raise NotImplementedError("(%s).start" % self) @property def stop(self): """The ending point of the series. This point is included""" raise NotImplementedError("(%s).stop" % self) @property def length(self): """Length of the series expansion""" raise NotImplementedError("(%s).length" % self) @property def variables(self): """Returns a tuple of variables that are bounded""" return () @property def free_symbols(self): """ This method returns the symbols in the object, excluding those that take on a specific value (i.e. the dummy symbols). """ return ({j for i in self.args for j in i.free_symbols} .difference(self.variables)) @cacheit def term(self, pt): """Term at point pt of a series""" if pt < self.start or pt > self.stop: raise IndexError("Index %s out of bounds %s" % (pt, self.interval)) return self._eval_term(pt) def _eval_term(self, pt): raise NotImplementedError("The _eval_term method should be added to" "%s to return series term so it is available" "when 'term' calls it." % self.func) def _ith_point(self, i): """ Returns the i'th point of a series If start point is negative infinity, point is returned from the end. Assumes the first point to be indexed zero. Examples ======== TODO """ if self.start is S.NegativeInfinity: initial = self.stop step = -1 else: initial = self.start step = 1 return initial + i*step def __iter__(self): i = 0 while i < self.length: pt = self._ith_point(i) yield self.term(pt) i += 1 def __getitem__(self, index): if isinstance(index, int): index = self._ith_point(index) return self.term(index) elif isinstance(index, slice): start, stop = index.start, index.stop if start is None: start = 0 if stop is None: stop = self.length return [self.term(self._ith_point(i)) for i in range(start, stop, index.step or 1)] sympy-sympy-1.9/sympy/series/tests/000077500000000000000000000000001412543434000175405ustar00rootroot00000000000000sympy-sympy-1.9/sympy/series/tests/__init__.py000066400000000000000000000000001412543434000216370ustar00rootroot00000000000000sympy-sympy-1.9/sympy/series/tests/test_approximants.py000066400000000000000000000016261412543434000237030ustar00rootroot00000000000000from sympy.series import approximants from sympy import lucas, fibonacci, symbols, binomial def test_approximants(): x, t = symbols("x,t") g = [lucas(k) for k in range(16)] assert [e for e in approximants(g)] == ( [2, -4/(x - 2), (5*x - 2)/(3*x - 1), (x - 2)/(x**2 + x - 1)] ) g = [lucas(k)+fibonacci(k+2) for k in range(16)] assert [e for e in approximants(g)] == ( [3, -3/(x - 1), (3*x - 3)/(2*x - 1), -3/(x**2 + x - 1)] ) g = [lucas(k)**2 for k in range(16)] assert [e for e in approximants(g)] == ( [4, -16/(x - 4), (35*x - 4)/(9*x - 1), (37*x - 28)/(13*x**2 + 11*x - 7), (50*x**2 + 63*x - 52)/(37*x**2 + 19*x - 13), (-x**2 - 7*x + 4)/(x**3 - 2*x**2 - 2*x + 1)] ) p = [sum(binomial(k,i)*x**i for i in range(k+1)) for k in range(16)] y = approximants(p, t, simplify=True) assert next(y) == 1 assert next(y) == -1/(t*(x + 1) - 1) sympy-sympy-1.9/sympy/series/tests/test_aseries.py000066400000000000000000000034041412543434000226050ustar00rootroot00000000000000from sympy import (Symbol, exp, log, sqrt, O, oo, sin, cos, PoleError) from sympy.abc import x from sympy.testing.pytest import raises def test_simple(): # Gruntz' theses pp. 91 to 96 # 6.6 e = sin(1/x + exp(-x)) - sin(1/x) assert e.aseries(x) == (1/(24*x**4) - 1/(2*x**2) + 1 + O(x**(-6), (x, oo)))*exp(-x) e = exp(x) * (exp(1/x + exp(-x)) - exp(1/x)) assert e.aseries(x, n=4) == 1/(6*x**3) + 1/(2*x**2) + 1/x + 1 + O(x**(-4), (x, oo)) e = exp(exp(x) / (1 - 1/x)) assert e.aseries(x) == exp(exp(x) / (1 - 1/x)) # The implementation of bound in aseries is incorrect currently. This test # should be commented out when that is fixed. # assert e.aseries(x, bound=3) == exp(exp(x) / x**2)*exp(exp(x) / x)*exp(-exp(x) + exp(x)/(1 - 1/x) - \ # exp(x) / x - exp(x) / x**2) * exp(exp(x)) e = exp(sin(1/x + exp(-exp(x)))) - exp(sin(1/x)) assert e.aseries(x, n=4) == (-1/(2*x**3) + 1/x + 1 + O(x**(-4), (x, oo)))*exp(-exp(x)) e = exp(exp(x)) * (exp(sin(1/x + 1/exp(exp(x)))) - exp(sin(1/x))) assert e.aseries(x, n=4) == -1/(2*x**3) + 1/x + 1 + O(x**(-4), (x, oo)) n = Symbol('n', integer=True) e = (sqrt(n)*log(n)**2*exp(sqrt(log(n))*log(log(n))**2*exp(sqrt(log(log(n)))*log(log(log(n)))**3)))/n assert e.aseries(n) == \ exp(exp(sqrt(log(log(n)))*log(log(log(n)))**3)*sqrt(log(n))*log(log(n))**2)*log(n)**2/sqrt(n) def test_hierarchical(): e = sin(1/x + exp(-x)) assert e.aseries(x, n=3, hir=True) == -exp(-2*x)*sin(1/x)/2 + \ exp(-x)*cos(1/x) + sin(1/x) + O(exp(-3*x), (x, oo)) e = sin(x) * cos(exp(-x)) assert e.aseries(x, hir=True) == exp(-4*x)*sin(x)/24 - \ exp(-2*x)*sin(x)/2 + sin(x) + O(exp(-6*x), (x, oo)) raises(PoleError, lambda: e.aseries(x)) sympy-sympy-1.9/sympy/series/tests/test_demidovich.py000066400000000000000000000110511412543434000232620ustar00rootroot00000000000000from sympy import limit, Symbol, oo, sqrt, Rational, log, exp, cos, sin, tan, \ pi, asin, together, root, S # Numbers listed with the tests refer to problem numbers in the book # "Anti-demidovich, problemas resueltos, Ed. URSS" x = Symbol("x") def test_leadterm(): assert (3 + 2*x**(log(3)/log(2) - 1)).leadterm(x) == (3, 0) def root3(x): return root(x, 3) def root4(x): return root(x, 4) def test_Limits_simple_0(): assert limit((2**(x + 1) + 3**(x + 1))/(2**x + 3**x), x, oo) == 3 # 175 def test_Limits_simple_1(): assert limit((x + 1)*(x + 2)*(x + 3)/x**3, x, oo) == 1 # 172 assert limit(sqrt(x + 1) - sqrt(x), x, oo) == 0 # 179 assert limit((2*x - 3)*(3*x + 5)*(4*x - 6)/(3*x**3 + x - 1), x, oo) == 8 # Primjer 1 assert limit(x/root3(x**3 + 10), x, oo) == 1 # Primjer 2 assert limit((x + 1)**2/(x**2 + 1), x, oo) == 1 # 181 def test_Limits_simple_2(): assert limit(1000*x/(x**2 - 1), x, oo) == 0 # 182 assert limit((x**2 - 5*x + 1)/(3*x + 7), x, oo) is oo # 183 assert limit((2*x**2 - x + 3)/(x**3 - 8*x + 5), x, oo) == 0 # 184 assert limit((2*x**2 - 3*x - 4)/sqrt(x**4 + 1), x, oo) == 2 # 186 assert limit((2*x + 3)/(x + root3(x)), x, oo) == 2 # 187 assert limit(x**2/(10 + x*sqrt(x)), x, oo) is oo # 188 assert limit(root3(x**2 + 1)/(x + 1), x, oo) == 0 # 189 assert limit(sqrt(x)/sqrt(x + sqrt(x + sqrt(x))), x, oo) == 1 # 190 def test_Limits_simple_3a(): a = Symbol('a') #issue 3513 assert together(limit((x**2 - (a + 1)*x + a)/(x**3 - a**3), x, a)) == \ (a - 1)/(3*a**2) # 196 def test_Limits_simple_3b(): h = Symbol("h") assert limit(((x + h)**3 - x**3)/h, h, 0) == 3*x**2 # 197 assert limit((1/(1 - x) - 3/(1 - x**3)), x, 1) == -1 # 198 assert limit((sqrt(1 + x) - 1)/(root3(1 + x) - 1), x, 0) == Rational(3)/2 # Primer 4 assert limit((sqrt(x) - 1)/(x - 1), x, 1) == Rational(1)/2 # 199 assert limit((sqrt(x) - 8)/(root3(x) - 4), x, 64) == 3 # 200 assert limit((root3(x) - 1)/(root4(x) - 1), x, 1) == Rational(4)/3 # 201 assert limit( (root3(x**2) - 2*root3(x) + 1)/(x - 1)**2, x, 1) == Rational(1)/9 # 202 def test_Limits_simple_4a(): a = Symbol('a') assert limit((sqrt(x) - sqrt(a))/(x - a), x, a) == 1/(2*sqrt(a)) # Primer 5 assert limit((sqrt(x) - 1)/(root3(x) - 1), x, 1) == Rational(3, 2) # 205 assert limit((sqrt(1 + x) - sqrt(1 - x))/x, x, 0) == 1 # 207 assert limit(sqrt(x**2 - 5*x + 6) - x, x, oo) == Rational(-5, 2) # 213 def test_limits_simple_4aa(): assert limit(x*(sqrt(x**2 + 1) - x), x, oo) == Rational(1)/2 # 214 def test_Limits_simple_4b(): #issue 3511 assert limit(x - root3(x**3 - 1), x, oo) == 0 # 215 def test_Limits_simple_4c(): assert limit(log(1 + exp(x))/x, x, -oo) == 0 # 267a assert limit(log(1 + exp(x))/x, x, oo) == 1 # 267b def test_bounded(): assert limit(sin(x)/x, x, oo) == 0 # 216b assert limit(x*sin(1/x), x, 0) == 0 # 227a def test_f1a(): #issue 3508: assert limit((sin(2*x)/x)**(1 + x), x, 0) == 2 # Primer 7 def test_f1a2(): #issue 3509: assert limit(((x - 1)/(x + 1))**x, x, oo) == exp(-2) # Primer 9 def test_f1b(): m = Symbol("m") n = Symbol("n") h = Symbol("h") a = Symbol("a") assert limit(sin(x)/x, x, 2) == sin(2)/2 # 216a assert limit(sin(3*x)/x, x, 0) == 3 # 217 assert limit(sin(5*x)/sin(2*x), x, 0) == Rational(5, 2) # 218 assert limit(sin(pi*x)/sin(3*pi*x), x, 0) == Rational(1, 3) # 219 assert limit(x*sin(pi/x), x, oo) == pi # 220 assert limit((1 - cos(x))/x**2, x, 0) == S.Half # 221 assert limit(x*sin(1/x), x, oo) == 1 # 227b assert limit((cos(m*x) - cos(n*x))/x**2, x, 0) == -m**2/2 + n**2/2 # 232 assert limit((tan(x) - sin(x))/x**3, x, 0) == S.Half # 233 assert limit((x - sin(2*x))/(x + sin(3*x)), x, 0) == -Rational(1, 4) # 237 assert limit((1 - sqrt(cos(x)))/x**2, x, 0) == Rational(1, 4) # 239 assert limit((sqrt(1 + sin(x)) - sqrt(1 - sin(x)))/x, x, 0) == 1 # 240 assert limit((1 + h/x)**x, x, oo) == exp(h) # Primer 9 assert limit((sin(x) - sin(a))/(x - a), x, a) == cos(a) # 222, *176 assert limit((cos(x) - cos(a))/(x - a), x, a) == -sin(a) # 223 assert limit((sin(x + h) - sin(x))/h, h, 0) == cos(x) # 225 def test_f2a(): assert limit(((x + 1)/(2*x + 1))**(x**2), x, oo) == 0 # Primer 8 def test_f2(): assert limit((sqrt( cos(x)) - root3(cos(x)))/(sin(x)**2), x, 0) == -Rational(1, 12) # *184 def test_f3(): a = Symbol('a') #issue 3504 assert limit(asin(a*x)/x, x, 0) == a sympy-sympy-1.9/sympy/series/tests/test_formal.py000066400000000000000000000526111412543434000224360ustar00rootroot00000000000000from sympy import (symbols, factorial, sqrt, Rational, atan, I, log, fps, O, Sum, oo, S, pi, cos, sin, Function, exp, Derivative, asin, airyai, acos, acosh, gamma, erf, asech, Add, Mul, integrate) from sympy.series.formal import (rational_algorithm, FormalPowerSeries, FormalPowerSeriesProduct, FormalPowerSeriesCompose, FormalPowerSeriesInverse, simpleDE, rational_independent, exp_re, hyper_re) from sympy.testing.pytest import raises, XFAIL, slow x, y, z = symbols('x y z') n, m, k = symbols('n m k', integer=True) f, r = Function('f'), Function('r') def test_rational_algorithm(): f = 1 / ((x - 1)**2 * (x - 2)) assert rational_algorithm(f, x, k) == \ (-2**(-k - 1) + 1 - (factorial(k + 1) / factorial(k)), 0, 0) f = (1 + x + x**2 + x**3) / ((x - 1) * (x - 2)) assert rational_algorithm(f, x, k) == \ (-15*2**(-k - 1) + 4, x + 4, 0) f = z / (y*m - m*x - y*x + x**2) assert rational_algorithm(f, x, k) == \ (((-y**(-k - 1)*z) / (y - m)) + ((m**(-k - 1)*z) / (y - m)), 0, 0) f = x / (1 - x - x**2) assert rational_algorithm(f, x, k) is None assert rational_algorithm(f, x, k, full=True) == \ (((Rational(-1, 2) + sqrt(5)/2)**(-k - 1) * (-sqrt(5)/10 + S.Half)) + ((-sqrt(5)/2 - S.Half)**(-k - 1) * (sqrt(5)/10 + S.Half)), 0, 0) f = 1 / (x**2 + 2*x + 2) assert rational_algorithm(f, x, k) is None assert rational_algorithm(f, x, k, full=True) == \ ((I*(-1 + I)**(-k - 1)) / 2 - (I*(-1 - I)**(-k - 1)) / 2, 0, 0) f = log(1 + x) assert rational_algorithm(f, x, k) == \ (-(-1)**(-k) / k, 0, 1) f = atan(x) assert rational_algorithm(f, x, k) is None assert rational_algorithm(f, x, k, full=True) == \ (((I*I**(-k)) / 2 - (I*(-I)**(-k)) / 2) / k, 0, 1) f = x*atan(x) - log(1 + x**2) / 2 assert rational_algorithm(f, x, k) is None assert rational_algorithm(f, x, k, full=True) == \ (((I*I**(-k + 1)) / 2 - (I*(-I)**(-k + 1)) / 2) / (k*(k - 1)), 0, 2) f = log((1 + x) / (1 - x)) / 2 - atan(x) assert rational_algorithm(f, x, k) is None assert rational_algorithm(f, x, k, full=True) == \ ((-(-1)**(-k) / 2 - (I*I**(-k)) / 2 + (I*(-I)**(-k)) / 2 + S.Half) / k, 0, 1) assert rational_algorithm(cos(x), x, k) is None def test_rational_independent(): ri = rational_independent assert ri([], x) == [] assert ri([cos(x), sin(x)], x) == [cos(x), sin(x)] assert ri([x**2, sin(x), x*sin(x), x**3], x) == \ [x**3 + x**2, x*sin(x) + sin(x)] assert ri([S.One, x*log(x), log(x), sin(x)/x, cos(x), sin(x), x], x) == \ [x + 1, x*log(x) + log(x), sin(x)/x + sin(x), cos(x)] def test_simpleDE(): # Tests just the first valid DE for DE in simpleDE(exp(x), x, f): assert DE == (-f(x) + Derivative(f(x), x), 1) break for DE in simpleDE(sin(x), x, f): assert DE == (f(x) + Derivative(f(x), x, x), 2) break for DE in simpleDE(log(1 + x), x, f): assert DE == ((x + 1)*Derivative(f(x), x, 2) + Derivative(f(x), x), 2) break for DE in simpleDE(asin(x), x, f): assert DE == (x*Derivative(f(x), x) + (x**2 - 1)*Derivative(f(x), x, x), 2) break for DE in simpleDE(exp(x)*sin(x), x, f): assert DE == (2*f(x) - 2*Derivative(f(x)) + Derivative(f(x), x, x), 2) break for DE in simpleDE(((1 + x)/(1 - x))**n, x, f): assert DE == (2*n*f(x) + (x**2 - 1)*Derivative(f(x), x), 1) break for DE in simpleDE(airyai(x), x, f): assert DE == (-x*f(x) + Derivative(f(x), x, x), 2) break def test_exp_re(): d = -f(x) + Derivative(f(x), x) assert exp_re(d, r, k) == -r(k) + r(k + 1) d = f(x) + Derivative(f(x), x, x) assert exp_re(d, r, k) == r(k) + r(k + 2) d = f(x) + Derivative(f(x), x) + Derivative(f(x), x, x) assert exp_re(d, r, k) == r(k) + r(k + 1) + r(k + 2) d = Derivative(f(x), x) + Derivative(f(x), x, x) assert exp_re(d, r, k) == r(k) + r(k + 1) d = Derivative(f(x), x, 3) + Derivative(f(x), x, 4) + Derivative(f(x)) assert exp_re(d, r, k) == r(k) + r(k + 2) + r(k + 3) def test_hyper_re(): d = f(x) + Derivative(f(x), x, x) assert hyper_re(d, r, k) == r(k) + (k+1)*(k+2)*r(k + 2) d = -x*f(x) + Derivative(f(x), x, x) assert hyper_re(d, r, k) == (k + 2)*(k + 3)*r(k + 3) - r(k) d = 2*f(x) - 2*Derivative(f(x), x) + Derivative(f(x), x, x) assert hyper_re(d, r, k) == \ (-2*k - 2)*r(k + 1) + (k + 1)*(k + 2)*r(k + 2) + 2*r(k) d = 2*n*f(x) + (x**2 - 1)*Derivative(f(x), x) assert hyper_re(d, r, k) == \ k*r(k) + 2*n*r(k + 1) + (-k - 2)*r(k + 2) d = (x**10 + 4)*Derivative(f(x), x) + x*(x**10 - 1)*Derivative(f(x), x, x) assert hyper_re(d, r, k) == \ (k*(k - 1) + k)*r(k) + (4*k - (k + 9)*(k + 10) + 40)*r(k + 10) d = ((x**2 - 1)*Derivative(f(x), x, 3) + 3*x*Derivative(f(x), x, x) + Derivative(f(x), x)) assert hyper_re(d, r, k) == \ ((k*(k - 2)*(k - 1) + 3*k*(k - 1) + k)*r(k) + (-k*(k + 1)*(k + 2))*r(k + 2)) def test_fps(): assert fps(1) == 1 assert fps(2, x) == 2 assert fps(2, x, dir='+') == 2 assert fps(2, x, dir='-') == 2 assert fps(1/x + 1/x**2) == 1/x + 1/x**2 assert fps(log(1 + x), hyper=False, rational=False) == log(1 + x) f = fps(x**2 + x + 1) assert isinstance(f, FormalPowerSeries) assert f.function == x**2 + x + 1 assert f[0] == 1 assert f[2] == x**2 assert f.truncate(4) == x**2 + x + 1 + O(x**4) assert f.polynomial() == x**2 + x + 1 f = fps(log(1 + x)) assert isinstance(f, FormalPowerSeries) assert f.function == log(1 + x) assert f.subs(x, y) == f assert f[:5] == [0, x, -x**2/2, x**3/3, -x**4/4] assert f.as_leading_term(x) == x assert f.polynomial(6) == x - x**2/2 + x**3/3 - x**4/4 + x**5/5 k = f.ak.variables[0] assert f.infinite == Sum((-(-1)**(-k)*x**k)/k, (k, 1, oo)) ft, s = f.truncate(n=None), f[:5] for i, t in enumerate(ft): if i == 5: break assert s[i] == t f = sin(x).fps(x) assert isinstance(f, FormalPowerSeries) assert f.truncate() == x - x**3/6 + x**5/120 + O(x**6) raises(NotImplementedError, lambda: fps(y*x)) raises(ValueError, lambda: fps(x, dir=0)) @slow def test_fps__rational(): assert fps(1/x) == (1/x) assert fps((x**2 + x + 1) / x**3, dir=-1) == (x**2 + x + 1) / x**3 f = 1 / ((x - 1)**2 * (x - 2)) assert fps(f, x).truncate() == \ (Rational(-1, 2) - x*Rational(5, 4) - 17*x**2/8 - 49*x**3/16 - 129*x**4/32 - 321*x**5/64 + O(x**6)) f = (1 + x + x**2 + x**3) / ((x - 1) * (x - 2)) assert fps(f, x).truncate() == \ (S.Half + x*Rational(5, 4) + 17*x**2/8 + 49*x**3/16 + 113*x**4/32 + 241*x**5/64 + O(x**6)) f = x / (1 - x - x**2) assert fps(f, x, full=True).truncate() == \ x + x**2 + 2*x**3 + 3*x**4 + 5*x**5 + O(x**6) f = 1 / (x**2 + 2*x + 2) assert fps(f, x, full=True).truncate() == \ S.Half - x/2 + x**2/4 - x**4/8 + x**5/8 + O(x**6) f = log(1 + x) assert fps(f, x).truncate() == \ x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6) assert fps(f, x, dir=1).truncate() == fps(f, x, dir=-1).truncate() assert fps(f, x, 2).truncate() == \ (log(3) - Rational(2, 3) - (x - 2)**2/18 + (x - 2)**3/81 - (x - 2)**4/324 + (x - 2)**5/1215 + x/3 + O((x - 2)**6, (x, 2))) assert fps(f, x, 2, dir=-1).truncate() == \ (log(3) - Rational(2, 3) - (-x + 2)**2/18 - (-x + 2)**3/81 - (-x + 2)**4/324 - (-x + 2)**5/1215 + x/3 + O((x - 2)**6, (x, 2))) f = atan(x) assert fps(f, x, full=True).truncate() == x - x**3/3 + x**5/5 + O(x**6) assert fps(f, x, full=True, dir=1).truncate() == \ fps(f, x, full=True, dir=-1).truncate() assert fps(f, x, 2, full=True).truncate() == \ (atan(2) - Rational(2, 5) - 2*(x - 2)**2/25 + 11*(x - 2)**3/375 - 6*(x - 2)**4/625 + 41*(x - 2)**5/15625 + x/5 + O((x - 2)**6, (x, 2))) assert fps(f, x, 2, full=True, dir=-1).truncate() == \ (atan(2) - Rational(2, 5) - 2*(-x + 2)**2/25 - 11*(-x + 2)**3/375 - 6*(-x + 2)**4/625 - 41*(-x + 2)**5/15625 + x/5 + O((x - 2)**6, (x, 2))) f = x*atan(x) - log(1 + x**2) / 2 assert fps(f, x, full=True).truncate() == x**2/2 - x**4/12 + O(x**6) f = log((1 + x) / (1 - x)) / 2 - atan(x) assert fps(f, x, full=True).truncate(n=10) == 2*x**3/3 + 2*x**7/7 + O(x**10) @slow def test_fps__hyper(): f = sin(x) assert fps(f, x).truncate() == x - x**3/6 + x**5/120 + O(x**6) f = cos(x) assert fps(f, x).truncate() == 1 - x**2/2 + x**4/24 + O(x**6) f = exp(x) assert fps(f, x).truncate() == \ 1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + O(x**6) f = atan(x) assert fps(f, x).truncate() == x - x**3/3 + x**5/5 + O(x**6) f = exp(acos(x)) assert fps(f, x).truncate() == \ (exp(pi/2) - x*exp(pi/2) + x**2*exp(pi/2)/2 - x**3*exp(pi/2)/3 + 5*x**4*exp(pi/2)/24 - x**5*exp(pi/2)/6 + O(x**6)) f = exp(acosh(x)) assert fps(f, x).truncate() == I + x - I*x**2/2 - I*x**4/8 + O(x**6) f = atan(1/x) assert fps(f, x).truncate() == pi/2 - x + x**3/3 - x**5/5 + O(x**6) f = x*atan(x) - log(1 + x**2) / 2 assert fps(f, x, rational=False).truncate() == x**2/2 - x**4/12 + O(x**6) f = log(1 + x) assert fps(f, x, rational=False).truncate() == \ x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6) f = airyai(x**2) assert fps(f, x).truncate() == \ (3**Rational(5, 6)*gamma(Rational(1, 3))/(6*pi) - 3**Rational(2, 3)*x**2/(3*gamma(Rational(1, 3))) + O(x**6)) f = exp(x)*sin(x) assert fps(f, x).truncate() == x + x**2 + x**3/3 - x**5/30 + O(x**6) f = exp(x)*sin(x)/x assert fps(f, x).truncate() == 1 + x + x**2/3 - x**4/30 - x**5/90 + O(x**6) f = sin(x) * cos(x) assert fps(f, x).truncate() == x - 2*x**3/3 + 2*x**5/15 + O(x**6) def test_fps_shift(): f = x**-5*sin(x) assert fps(f, x).truncate() == \ 1/x**4 - 1/(6*x**2) + Rational(1, 120) - x**2/5040 + x**4/362880 + O(x**6) f = x**2*atan(x) assert fps(f, x, rational=False).truncate() == \ x**3 - x**5/3 + O(x**6) f = cos(sqrt(x))*x assert fps(f, x).truncate() == \ x - x**2/2 + x**3/24 - x**4/720 + x**5/40320 + O(x**6) f = x**2*cos(sqrt(x)) assert fps(f, x).truncate() == \ x**2 - x**3/2 + x**4/24 - x**5/720 + O(x**6) def test_fps__Add_expr(): f = x*atan(x) - log(1 + x**2) / 2 assert fps(f, x).truncate() == x**2/2 - x**4/12 + O(x**6) f = sin(x) + cos(x) - exp(x) + log(1 + x) assert fps(f, x).truncate() == x - 3*x**2/2 - x**4/4 + x**5/5 + O(x**6) f = 1/x + sin(x) assert fps(f, x).truncate() == 1/x + x - x**3/6 + x**5/120 + O(x**6) f = sin(x) - cos(x) + 1/(x - 1) assert fps(f, x).truncate() == \ -2 - x**2/2 - 7*x**3/6 - 25*x**4/24 - 119*x**5/120 + O(x**6) def test_fps__asymptotic(): f = exp(x) assert fps(f, x, oo) == f assert fps(f, x, -oo).truncate() == O(1/x**6, (x, oo)) f = erf(x) assert fps(f, x, oo).truncate() == 1 + O(1/x**6, (x, oo)) assert fps(f, x, -oo).truncate() == -1 + O(1/x**6, (x, oo)) f = atan(x) assert fps(f, x, oo, full=True).truncate() == \ -1/(5*x**5) + 1/(3*x**3) - 1/x + pi/2 + O(1/x**6, (x, oo)) assert fps(f, x, -oo, full=True).truncate() == \ -1/(5*x**5) + 1/(3*x**3) - 1/x - pi/2 + O(1/x**6, (x, oo)) f = log(1 + x) assert fps(f, x, oo) != \ (-1/(5*x**5) - 1/(4*x**4) + 1/(3*x**3) - 1/(2*x**2) + 1/x - log(1/x) + O(1/x**6, (x, oo))) assert fps(f, x, -oo) != \ (-1/(5*x**5) - 1/(4*x**4) + 1/(3*x**3) - 1/(2*x**2) + 1/x + I*pi - log(-1/x) + O(1/x**6, (x, oo))) def test_fps__fractional(): f = sin(sqrt(x)) / x assert fps(f, x).truncate() == \ (1/sqrt(x) - sqrt(x)/6 + x**Rational(3, 2)/120 - x**Rational(5, 2)/5040 + x**Rational(7, 2)/362880 - x**Rational(9, 2)/39916800 + x**Rational(11, 2)/6227020800 + O(x**6)) f = sin(sqrt(x)) * x assert fps(f, x).truncate() == \ (x**Rational(3, 2) - x**Rational(5, 2)/6 + x**Rational(7, 2)/120 - x**Rational(9, 2)/5040 + x**Rational(11, 2)/362880 + O(x**6)) f = atan(sqrt(x)) / x**2 assert fps(f, x).truncate() == \ (x**Rational(-3, 2) - x**Rational(-1, 2)/3 + x**S.Half/5 - x**Rational(3, 2)/7 + x**Rational(5, 2)/9 - x**Rational(7, 2)/11 + x**Rational(9, 2)/13 - x**Rational(11, 2)/15 + O(x**6)) f = exp(sqrt(x)) assert fps(f, x).truncate().expand() == \ (1 + x/2 + x**2/24 + x**3/720 + x**4/40320 + x**5/3628800 + sqrt(x) + x**Rational(3, 2)/6 + x**Rational(5, 2)/120 + x**Rational(7, 2)/5040 + x**Rational(9, 2)/362880 + x**Rational(11, 2)/39916800 + O(x**6)) f = exp(sqrt(x))*x assert fps(f, x).truncate().expand() == \ (x + x**2/2 + x**3/24 + x**4/720 + x**5/40320 + x**Rational(3, 2) + x**Rational(5, 2)/6 + x**Rational(7, 2)/120 + x**Rational(9, 2)/5040 + x**Rational(11, 2)/362880 + O(x**6)) def test_fps__logarithmic_singularity(): f = log(1 + 1/x) assert fps(f, x) != \ -log(x) + x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6) assert fps(f, x, rational=False) != \ -log(x) + x - x**2/2 + x**3/3 - x**4/4 + x**5/5 + O(x**6) @XFAIL def test_fps__logarithmic_singularity_fail(): f = asech(x) # Algorithms for computing limits probably needs improvemnts assert fps(f, x) == log(2) - log(x) - x**2/4 - 3*x**4/64 + O(x**6) def test_fps_symbolic(): f = x**n*sin(x**2) assert fps(f, x).truncate(8) == x**(n + 2) - x**(n + 6)/6 + O(x**(n + 8), x) f = x**n*log(1 + x) fp = fps(f, x) k = fp.ak.variables[0] assert fp.infinite == \ Sum((-(-1)**(-k)*x**(k + n))/k, (k, 1, oo)) f = (x - 2)**n*log(1 + x) assert fps(f, x, 2).truncate() == \ ((x - 2)**n*log(3) + (x - 2)**(n + 1)/3 - (x - 2)**(n + 2)/18 + (x - 2)**(n + 3)/81 - (x - 2)**(n + 4)/324 + (x - 2)**(n + 5)/1215 + O((x - 2)**(n + 6), (x, 2))) f = x**(n - 2)*cos(x) assert fps(f, x).truncate() == \ (x**(n - 2) - x**n/2 + x**(n + 2)/24 - x**(n + 4)/720 + O(x**(n + 6), x)) f = x**(n - 2)*sin(x) + x**n*exp(x) assert fps(f, x).truncate() == \ (x**(n - 1) + x**n + 5*x**(n + 1)/6 + x**(n + 2)/2 + 7*x**(n + 3)/40 + x**(n + 4)/24 + 41*x**(n + 5)/5040 + O(x**(n + 6), x)) f = x**n*atan(x) assert fps(f, x, oo).truncate() == \ (-x**(n - 5)/5 + x**(n - 3)/3 + x**n*(pi/2 - 1/x) + O((1/x)**(-n)/x**6, (x, oo))) f = x**(n/2)*cos(x) assert fps(f, x).truncate() == \ x**(n/2) - x**(n/2 + 2)/2 + x**(n/2 + 4)/24 + O(x**(n/2 + 6), x) f = x**(n + m)*sin(x) assert fps(f, x).truncate() == \ x**(m + n + 1) - x**(m + n + 3)/6 + x**(m + n + 5)/120 + O(x**(m + n + 6), x) def test_fps__slow(): f = x*exp(x)*sin(2*x) # TODO: rsolve needs improvement assert fps(f, x).truncate() == 2*x**2 + 2*x**3 - x**4/3 - x**5 + O(x**6) def test_fps__operations(): f1, f2 = fps(sin(x)), fps(cos(x)) fsum = f1 + f2 assert fsum.function == sin(x) + cos(x) assert fsum.truncate() == \ 1 + x - x**2/2 - x**3/6 + x**4/24 + x**5/120 + O(x**6) fsum = f1 + 1 assert fsum.function == sin(x) + 1 assert fsum.truncate() == 1 + x - x**3/6 + x**5/120 + O(x**6) fsum = 1 + f2 assert fsum.function == cos(x) + 1 assert fsum.truncate() == 2 - x**2/2 + x**4/24 + O(x**6) assert (f1 + x) == Add(f1, x) assert -f2.truncate() == -1 + x**2/2 - x**4/24 + O(x**6) assert (f1 - f1) is S.Zero fsub = f1 - f2 assert fsub.function == sin(x) - cos(x) assert fsub.truncate() == \ -1 + x + x**2/2 - x**3/6 - x**4/24 + x**5/120 + O(x**6) fsub = f1 - 1 assert fsub.function == sin(x) - 1 assert fsub.truncate() == -1 + x - x**3/6 + x**5/120 + O(x**6) fsub = 1 - f2 assert fsub.function == -cos(x) + 1 assert fsub.truncate() == x**2/2 - x**4/24 + O(x**6) raises(ValueError, lambda: f1 + fps(exp(x), dir=-1)) raises(ValueError, lambda: f1 + fps(exp(x), x0=1)) fm = f1 * 3 assert fm.function == 3*sin(x) assert fm.truncate() == 3*x - x**3/2 + x**5/40 + O(x**6) fm = 3 * f2 assert fm.function == 3*cos(x) assert fm.truncate() == 3 - 3*x**2/2 + x**4/8 + O(x**6) assert (f1 * f2) == Mul(f1, f2) assert (f1 * x) == Mul(f1, x) fd = f1.diff() assert fd.function == cos(x) assert fd.truncate() == 1 - x**2/2 + x**4/24 + O(x**6) fd = f2.diff() assert fd.function == -sin(x) assert fd.truncate() == -x + x**3/6 - x**5/120 + O(x**6) fd = f2.diff().diff() assert fd.function == -cos(x) assert fd.truncate() == -1 + x**2/2 - x**4/24 + O(x**6) f3 = fps(exp(sqrt(x))) fd = f3.diff() assert fd.truncate().expand() == \ (1/(2*sqrt(x)) + S.Half + x/12 + x**2/240 + x**3/10080 + x**4/725760 + x**5/79833600 + sqrt(x)/4 + x**Rational(3, 2)/48 + x**Rational(5, 2)/1440 + x**Rational(7, 2)/80640 + x**Rational(9, 2)/7257600 + x**Rational(11, 2)/958003200 + O(x**6)) assert f1.integrate((x, 0, 1)) == -cos(1) + 1 assert integrate(f1, (x, 0, 1)) == -cos(1) + 1 fi = integrate(f1, x) assert fi.function == -cos(x) assert fi.truncate() == -1 + x**2/2 - x**4/24 + O(x**6) fi = f2.integrate(x) assert fi.function == sin(x) assert fi.truncate() == x - x**3/6 + x**5/120 + O(x**6) def test_fps__product(): f1, f2, f3 = fps(sin(x)), fps(exp(x)), fps(cos(x)) raises(ValueError, lambda: f1.product(exp(x), x)) raises(ValueError, lambda: f1.product(fps(exp(x), dir=-1), x, 4)) raises(ValueError, lambda: f1.product(fps(exp(x), x0=1), x, 4)) raises(ValueError, lambda: f1.product(fps(exp(y)), x, 4)) fprod = f1.product(f2, x) assert isinstance(fprod, FormalPowerSeriesProduct) assert isinstance(fprod.ffps, FormalPowerSeries) assert isinstance(fprod.gfps, FormalPowerSeries) assert fprod.f == sin(x) assert fprod.g == exp(x) assert fprod.function == sin(x) * exp(x) assert fprod._eval_terms(4) == x + x**2 + x**3/3 assert fprod.truncate(4) == x + x**2 + x**3/3 + O(x**4) assert fprod.polynomial(4) == x + x**2 + x**3/3 raises(NotImplementedError, lambda: fprod._eval_term(5)) raises(NotImplementedError, lambda: fprod.infinite) raises(NotImplementedError, lambda: fprod._eval_derivative(x)) raises(NotImplementedError, lambda: fprod.integrate(x)) assert f1.product(f3, x)._eval_terms(4) == x - 2*x**3/3 assert f1.product(f3, x).truncate(4) == x - 2*x**3/3 + O(x**4) def test_fps__compose(): f1, f2, f3 = fps(exp(x)), fps(sin(x)), fps(cos(x)) raises(ValueError, lambda: f1.compose(sin(x), x)) raises(ValueError, lambda: f1.compose(fps(sin(x), dir=-1), x, 4)) raises(ValueError, lambda: f1.compose(fps(sin(x), x0=1), x, 4)) raises(ValueError, lambda: f1.compose(fps(sin(y)), x, 4)) raises(ValueError, lambda: f1.compose(f3, x)) raises(ValueError, lambda: f2.compose(f3, x)) fcomp = f1.compose(f2, x) assert isinstance(fcomp, FormalPowerSeriesCompose) assert isinstance(fcomp.ffps, FormalPowerSeries) assert isinstance(fcomp.gfps, FormalPowerSeries) assert fcomp.f == exp(x) assert fcomp.g == sin(x) assert fcomp.function == exp(sin(x)) assert fcomp._eval_terms(6) == 1 + x + x**2/2 - x**4/8 - x**5/15 assert fcomp.truncate() == 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6) assert fcomp.truncate(5) == 1 + x + x**2/2 - x**4/8 + O(x**5) raises(NotImplementedError, lambda: fcomp._eval_term(5)) raises(NotImplementedError, lambda: fcomp.infinite) raises(NotImplementedError, lambda: fcomp._eval_derivative(x)) raises(NotImplementedError, lambda: fcomp.integrate(x)) assert f1.compose(f2, x).truncate(4) == 1 + x + x**2/2 + O(x**4) assert f1.compose(f2, x).truncate(8) == \ 1 + x + x**2/2 - x**4/8 - x**5/15 - x**6/240 + x**7/90 + O(x**8) assert f1.compose(f2, x).truncate(6) == \ 1 + x + x**2/2 - x**4/8 - x**5/15 + O(x**6) assert f2.compose(f2, x).truncate(4) == x - x**3/3 + O(x**4) assert f2.compose(f2, x).truncate(8) == x - x**3/3 + x**5/10 - 8*x**7/315 + O(x**8) assert f2.compose(f2, x).truncate(6) == x - x**3/3 + x**5/10 + O(x**6) def test_fps__inverse(): f1, f2, f3 = fps(sin(x)), fps(exp(x)), fps(cos(x)) raises(ValueError, lambda: f1.inverse(x)) finv = f2.inverse(x) assert isinstance(finv, FormalPowerSeriesInverse) assert isinstance(finv.ffps, FormalPowerSeries) raises(ValueError, lambda: finv.gfps) assert finv.f == exp(x) assert finv.function == exp(-x) assert finv._eval_terms(5) == 1 - x + x**2/2 - x**3/6 + x**4/24 assert finv.truncate() == 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + O(x**6) assert finv.truncate(5) == 1 - x + x**2/2 - x**3/6 + x**4/24 + O(x**5) raises(NotImplementedError, lambda: finv._eval_term(5)) raises(ValueError, lambda: finv.g) raises(NotImplementedError, lambda: finv.infinite) raises(NotImplementedError, lambda: finv._eval_derivative(x)) raises(NotImplementedError, lambda: finv.integrate(x)) assert f2.inverse(x).truncate(8) == \ 1 - x + x**2/2 - x**3/6 + x**4/24 - x**5/120 + x**6/720 - x**7/5040 + O(x**8) assert f3.inverse(x).truncate() == 1 + x**2/2 + 5*x**4/24 + O(x**6) assert f3.inverse(x).truncate(8) == 1 + x**2/2 + 5*x**4/24 + 61*x**6/720 + O(x**8) sympy-sympy-1.9/sympy/series/tests/test_fourier.py000066400000000000000000000130001412543434000226160ustar00rootroot00000000000000from sympy import (symbols, pi, Piecewise, sin, cos, sinc, Rational, S, oo, fourier_series, Add, log, exp, tan) from sympy.series.fourier import FourierSeries from sympy.testing.pytest import raises from sympy.core.cache import lru_cache x, y, z = symbols('x y z') # Don't declare these during import because they are slow @lru_cache() def _get_examples(): fo = fourier_series(x, (x, -pi, pi)) fe = fourier_series(x**2, (-pi, pi)) fp = fourier_series(Piecewise((0, x < 0), (pi, True)), (x, -pi, pi)) return fo, fe, fp def test_FourierSeries(): fo, fe, fp = _get_examples() assert fourier_series(1, (-pi, pi)) == 1 assert (Piecewise((0, x < 0), (pi, True)). fourier_series((x, -pi, pi)).truncate()) == fp.truncate() assert isinstance(fo, FourierSeries) assert fo.function == x assert fo.x == x assert fo.period == (-pi, pi) assert fo.term(3) == 2*sin(3*x) / 3 assert fe.term(3) == -4*cos(3*x) / 9 assert fp.term(3) == 2*sin(3*x) / 3 assert fo.as_leading_term(x) == 2*sin(x) assert fe.as_leading_term(x) == pi**2 / 3 assert fp.as_leading_term(x) == pi / 2 assert fo.truncate() == 2*sin(x) - sin(2*x) + (2*sin(3*x) / 3) assert fe.truncate() == -4*cos(x) + cos(2*x) + pi**2 / 3 assert fp.truncate() == 2*sin(x) + (2*sin(3*x) / 3) + pi / 2 fot = fo.truncate(n=None) s = [0, 2*sin(x), -sin(2*x)] for i, t in enumerate(fot): if i == 3: break assert s[i] == t def _check_iter(f, i): for ind, t in enumerate(f): assert t == f[ind] if ind == i: break _check_iter(fo, 3) _check_iter(fe, 3) _check_iter(fp, 3) assert fo.subs(x, x**2) == fo raises(ValueError, lambda: fourier_series(x, (0, 1, 2))) raises(ValueError, lambda: fourier_series(x, (x, 0, oo))) raises(ValueError, lambda: fourier_series(x*y, (0, oo))) def test_FourierSeries_2(): p = Piecewise((0, x < 0), (x, True)) f = fourier_series(p, (x, -2, 2)) assert f.term(3) == (2*sin(3*pi*x / 2) / (3*pi) - 4*cos(3*pi*x / 2) / (9*pi**2)) assert f.truncate() == (2*sin(pi*x / 2) / pi - sin(pi*x) / pi - 4*cos(pi*x / 2) / pi**2 + S.Half) def test_square_wave(): """Test if fourier_series approximates discontinuous function correctly.""" square_wave = Piecewise((1, x < pi), (-1, True)) s = fourier_series(square_wave, (x, 0, 2*pi)) assert s.truncate(3) == 4 / pi * sin(x) + 4 / (3 * pi) * sin(3 * x) + \ 4 / (5 * pi) * sin(5 * x) assert s.sigma_approximation(4) == 4 / pi * sin(x) * sinc(pi / 4) + \ 4 / (3 * pi) * sin(3 * x) * sinc(3 * pi / 4) def test_sawtooth_wave(): s = fourier_series(x, (x, 0, pi)) assert s.truncate(4) == \ pi/2 - sin(2*x) - sin(4*x)/2 - sin(6*x)/3 s = fourier_series(x, (x, 0, 1)) assert s.truncate(4) == \ S.Half - sin(2*pi*x)/pi - sin(4*pi*x)/(2*pi) - sin(6*pi*x)/(3*pi) def test_FourierSeries__operations(): fo, fe, fp = _get_examples() fes = fe.scale(-1).shift(pi**2) assert fes.truncate() == 4*cos(x) - cos(2*x) + 2*pi**2 / 3 assert fp.shift(-pi/2).truncate() == (2*sin(x) + (2*sin(3*x) / 3) + (2*sin(5*x) / 5)) fos = fo.scale(3) assert fos.truncate() == 6*sin(x) - 3*sin(2*x) + 2*sin(3*x) fx = fe.scalex(2).shiftx(1) assert fx.truncate() == -4*cos(2*x + 2) + cos(4*x + 4) + pi**2 / 3 fl = fe.scalex(3).shift(-pi).scalex(2).shiftx(1).scale(4) assert fl.truncate() == (-16*cos(6*x + 6) + 4*cos(12*x + 12) - 4*pi + 4*pi**2 / 3) raises(ValueError, lambda: fo.shift(x)) raises(ValueError, lambda: fo.shiftx(sin(x))) raises(ValueError, lambda: fo.scale(x*y)) raises(ValueError, lambda: fo.scalex(x**2)) def test_FourierSeries__neg(): fo, fe, fp = _get_examples() assert (-fo).truncate() == -2*sin(x) + sin(2*x) - (2*sin(3*x) / 3) assert (-fe).truncate() == +4*cos(x) - cos(2*x) - pi**2 / 3 def test_FourierSeries__add__sub(): fo, fe, fp = _get_examples() assert fo + fo == fo.scale(2) assert fo - fo == 0 assert -fe - fe == fe.scale(-2) assert (fo + fe).truncate() == 2*sin(x) - sin(2*x) - 4*cos(x) + cos(2*x) \ + pi**2 / 3 assert (fo - fe).truncate() == 2*sin(x) - sin(2*x) + 4*cos(x) - cos(2*x) \ - pi**2 / 3 assert isinstance(fo + 1, Add) raises(ValueError, lambda: fo + fourier_series(x, (x, 0, 2))) def test_FourierSeries_finite(): assert fourier_series(sin(x)).truncate(1) == sin(x) # assert type(fourier_series(sin(x)*log(x))).truncate() == FourierSeries # assert type(fourier_series(sin(x**2+6))).truncate() == FourierSeries assert fourier_series(sin(x)*log(y)*exp(z),(x,pi,-pi)).truncate() == sin(x)*log(y)*exp(z) assert fourier_series(sin(x)**6).truncate(oo) == -15*cos(2*x)/32 + 3*cos(4*x)/16 - cos(6*x)/32 \ + Rational(5, 16) assert fourier_series(sin(x) ** 6).truncate() == -15 * cos(2 * x) / 32 + 3 * cos(4 * x) / 16 \ + Rational(5, 16) assert fourier_series(sin(4*x+3) + cos(3*x+4)).truncate(oo) == -sin(4)*sin(3*x) + sin(4*x)*cos(3) \ + cos(4)*cos(3*x) + sin(3)*cos(4*x) assert fourier_series(sin(x)+cos(x)*tan(x)).truncate(oo) == 2*sin(x) assert fourier_series(cos(pi*x), (x, -1, 1)).truncate(oo) == cos(pi*x) assert fourier_series(cos(3*pi*x + 4) - sin(4*pi*x)*log(pi*y) , (x, -1, 1)).truncate(oo) == -log(pi*y)*sin(4*pi*x)\ - sin(4)*sin(3*pi*x) + cos(4)*cos(3*pi*x) sympy-sympy-1.9/sympy/series/tests/test_gruntz.py000066400000000000000000000363471412543434000225170ustar00rootroot00000000000000from sympy import Symbol, exp, log, oo, Rational, I, sin, gamma, loggamma, S, \ atan, acot, pi, cancel, E, erf, sqrt, zeta, cos, digamma, Integer, Ei, EulerGamma from sympy.functions.elementary.hyperbolic import cosh, coth, sinh, tanh from sympy.series.gruntz import compare, mrv, rewrite, mrv_leadterm, gruntz, \ sign from sympy.testing.pytest import XFAIL, skip, slow """ This test suite is testing the limit algorithm using the bottom up approach. See the documentation in limits2.py. The algorithm itself is highly recursive by nature, so "compare" is logically the lowest part of the algorithm, yet in some sense it's the most complex part, because it needs to calculate a limit to return the result. Nevertheless, the rest of the algorithm depends on compare working correctly. """ x = Symbol('x', real=True) m = Symbol('m', real=True) runslow = False def _sskip(): if not runslow: skip("slow") @slow def test_gruntz_evaluation(): # Gruntz' thesis pp. 122 to 123 # 8.1 assert gruntz(exp(x)*(exp(1/x - exp(-x)) - exp(1/x)), x, oo) == -1 # 8.2 assert gruntz(exp(x)*(exp(1/x + exp(-x) + exp(-x**2)) - exp(1/x - exp(-exp(x)))), x, oo) == 1 # 8.3 assert gruntz(exp(exp(x - exp(-x))/(1 - 1/x)) - exp(exp(x)), x, oo) is oo # 8.5 assert gruntz(exp(exp(exp(x + exp(-x)))) / exp(exp(exp(x))), x, oo) is oo # 8.6 assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x - exp(-exp(x))))), x, oo) is oo # 8.7 assert gruntz(exp(exp(exp(x))) / exp(exp(exp(x - exp(-exp(exp(x)))))), x, oo) == 1 # 8.8 assert gruntz(exp(exp(x)) / exp(exp(x - exp(-exp(exp(x))))), x, oo) == 1 # 8.9 assert gruntz(log(x)**2 * exp(sqrt(log(x))*(log(log(x)))**2 * exp(sqrt(log(log(x))) * (log(log(log(x))))**3)) / sqrt(x), x, oo) == 0 # 8.10 assert gruntz((x*log(x)*(log(x*exp(x) - x**2))**2) / (log(log(x**2 + 2*exp(exp(3*x**3*log(x)))))), x, oo) == Rational(1, 3) # 8.11 assert gruntz((exp(x*exp(-x)/(exp(-x) + exp(-2*x**2/(x + 1)))) - exp(x))/x, x, oo) == -exp(2) # 8.12 assert gruntz((3**x + 5**x)**(1/x), x, oo) == 5 # 8.13 assert gruntz(x/log(x**(log(x**(log(2)/log(x))))), x, oo) is oo # 8.14 assert gruntz(exp(exp(2*log(x**5 + x)*log(log(x)))) / exp(exp(10*log(x)*log(log(x)))), x, oo) is oo # 8.15 assert gruntz(exp(exp(Rational(5, 2)*x**Rational(-5, 7) + Rational(21, 8)*x**Rational(6, 11) + 2*x**(-8) + Rational(54, 17)*x**Rational(49, 45)))**8 / log(log(-log(Rational(4, 3)*x**Rational(-5, 14))))**Rational(7, 6), x, oo) is oo # 8.16 assert gruntz((exp(4*x*exp(-x)/(1/exp(x) + 1/exp(2*x**2/(x + 1)))) - exp(x)) / exp(x)**4, x, oo) == 1 # 8.17 assert gruntz(exp(x*exp(-x)/(exp(-x) + exp(-2*x**2/(x + 1))))/exp(x), x, oo) \ == 1 # 8.19 assert gruntz(log(x)*(log(log(x) + log(log(x))) - log(log(x))) / (log(log(x) + log(log(log(x))))), x, oo) == 1 # 8.20 assert gruntz(exp((log(log(x + exp(log(x)*log(log(x)))))) / (log(log(log(exp(x) + x + log(x)))))), x, oo) == E # Another assert gruntz(exp(exp(exp(x + exp(-x)))) / exp(exp(x)), x, oo) is oo def test_gruntz_evaluation_slow(): _sskip() # 8.4 assert gruntz(exp(exp(exp(x)/(1 - 1/x))) - exp(exp(exp(x)/(1 - 1/x - log(x)**(-log(x))))), x, oo) is -oo # 8.18 assert gruntz((exp(exp(-x/(1 + exp(-x))))*exp(-x/(1 + exp(-x/(1 + exp(-x))))) *exp(exp(-x + exp(-x/(1 + exp(-x)))))) / (exp(-x/(1 + exp(-x))))**2 - exp(x) + x, x, oo) == 2 @slow def test_gruntz_eval_special(): # Gruntz, p. 126 assert gruntz(exp(x)*(sin(1/x + exp(-x)) - sin(1/x + exp(-x**2))), x, oo) == 1 assert gruntz((erf(x - exp(-exp(x))) - erf(x)) * exp(exp(x)) * exp(x**2), x, oo) == -2/sqrt(pi) assert gruntz(exp(exp(x)) * (exp(sin(1/x + exp(-exp(x)))) - exp(sin(1/x))), x, oo) == 1 assert gruntz(exp(x)*(gamma(x + exp(-x)) - gamma(x)), x, oo) is oo assert gruntz(exp(exp(digamma(digamma(x))))/x, x, oo) == exp(Rational(-1, 2)) assert gruntz(exp(exp(digamma(log(x))))/x, x, oo) == exp(Rational(-1, 2)) assert gruntz(digamma(digamma(digamma(x))), x, oo) is oo assert gruntz(loggamma(loggamma(x)), x, oo) is oo assert gruntz(((gamma(x + 1/gamma(x)) - gamma(x))/log(x) - cos(1/x)) * x*log(x), x, oo) == Rational(-1, 2) assert gruntz(x * (gamma(x - 1/gamma(x)) - gamma(x) + log(x)), x, oo) \ == S.Half assert gruntz((gamma(x + 1/gamma(x)) - gamma(x)) / log(x), x, oo) == 1 def test_gruntz_eval_special_slow(): _sskip() assert gruntz(gamma(x + 1)/sqrt(2*pi) - exp(-x)*(x**(x + S.Half) + x**(x - S.Half)/12), x, oo) is oo assert gruntz(exp(exp(exp(digamma(digamma(digamma(x))))))/x, x, oo) == 0 @XFAIL def test_grunts_eval_special_slow_sometimes_fail(): _sskip() # XXX This sometimes fails!!! assert gruntz(exp(gamma(x - exp(-x))*exp(1/x)) - exp(gamma(x)), x, oo) is oo @XFAIL def test_gruntz_eval_special_fail(): # TODO exponential integral Ei assert gruntz( (Ei(x - exp(-exp(x))) - Ei(x)) *exp(-x)*exp(exp(x))*x, x, oo) == -1 # TODO zeta function series assert gruntz( exp((log(2) + 1)*x) * (zeta(x + exp(-x)) - zeta(x)), x, oo) == -log(2) # TODO 8.35 - 8.37 (bessel, max-min) def test_gruntz_hyperbolic(): assert gruntz(cosh(x), x, oo) is oo assert gruntz(cosh(x), x, -oo) is oo assert gruntz(sinh(x), x, oo) is oo assert gruntz(sinh(x), x, -oo) is -oo assert gruntz(2*cosh(x)*exp(x), x, oo) is oo assert gruntz(2*cosh(x)*exp(x), x, -oo) == 1 assert gruntz(2*sinh(x)*exp(x), x, oo) is oo assert gruntz(2*sinh(x)*exp(x), x, -oo) == -1 assert gruntz(tanh(x), x, oo) == 1 assert gruntz(tanh(x), x, -oo) == -1 assert gruntz(coth(x), x, oo) == 1 assert gruntz(coth(x), x, -oo) == -1 def test_compare1(): assert compare(2, x, x) == "<" assert compare(x, exp(x), x) == "<" assert compare(exp(x), exp(x**2), x) == "<" assert compare(exp(x**2), exp(exp(x)), x) == "<" assert compare(1, exp(exp(x)), x) == "<" assert compare(x, 2, x) == ">" assert compare(exp(x), x, x) == ">" assert compare(exp(x**2), exp(x), x) == ">" assert compare(exp(exp(x)), exp(x**2), x) == ">" assert compare(exp(exp(x)), 1, x) == ">" assert compare(2, 3, x) == "=" assert compare(3, -5, x) == "=" assert compare(2, -5, x) == "=" assert compare(x, x**2, x) == "=" assert compare(x**2, x**3, x) == "=" assert compare(x**3, 1/x, x) == "=" assert compare(1/x, x**m, x) == "=" assert compare(x**m, -x, x) == "=" assert compare(exp(x), exp(-x), x) == "=" assert compare(exp(-x), exp(2*x), x) == "=" assert compare(exp(2*x), exp(x)**2, x) == "=" assert compare(exp(x)**2, exp(x + exp(-x)), x) == "=" assert compare(exp(x), exp(x + exp(-x)), x) == "=" assert compare(exp(x**2), 1/exp(x**2), x) == "=" def test_compare2(): assert compare(exp(x), x**5, x) == ">" assert compare(exp(x**2), exp(x)**2, x) == ">" assert compare(exp(x), exp(x + exp(-x)), x) == "=" assert compare(exp(x + exp(-x)), exp(x), x) == "=" assert compare(exp(x + exp(-x)), exp(-x), x) == "=" assert compare(exp(-x), x, x) == ">" assert compare(x, exp(-x), x) == "<" assert compare(exp(x + 1/x), x, x) == ">" assert compare(exp(-exp(x)), exp(x), x) == ">" assert compare(exp(exp(-exp(x)) + x), exp(-exp(x)), x) == "<" def test_compare3(): assert compare(exp(exp(x)), exp(x + exp(-exp(x))), x) == ">" def test_sign1(): assert sign(Rational(0), x) == 0 assert sign(Rational(3), x) == 1 assert sign(Rational(-5), x) == -1 assert sign(log(x), x) == 1 assert sign(exp(-x), x) == 1 assert sign(exp(x), x) == 1 assert sign(-exp(x), x) == -1 assert sign(3 - 1/x, x) == 1 assert sign(-3 - 1/x, x) == -1 assert sign(sin(1/x), x) == 1 assert sign((x**Integer(2)), x) == 1 assert sign(x**2, x) == 1 assert sign(x**5, x) == 1 def test_sign2(): assert sign(x, x) == 1 assert sign(-x, x) == -1 y = Symbol("y", positive=True) assert sign(y, x) == 1 assert sign(-y, x) == -1 assert sign(y*x, x) == 1 assert sign(-y*x, x) == -1 def mmrv(a, b): return set(mrv(a, b)[0].keys()) def test_mrv1(): assert mmrv(x, x) == {x} assert mmrv(x + 1/x, x) == {x} assert mmrv(x**2, x) == {x} assert mmrv(log(x), x) == {x} assert mmrv(exp(x), x) == {exp(x)} assert mmrv(exp(-x), x) == {exp(-x)} assert mmrv(exp(x**2), x) == {exp(x**2)} assert mmrv(-exp(1/x), x) == {x} assert mmrv(exp(x + 1/x), x) == {exp(x + 1/x)} def test_mrv2a(): assert mmrv(exp(x + exp(-exp(x))), x) == {exp(-exp(x))} assert mmrv(exp(x + exp(-x)), x) == {exp(x + exp(-x)), exp(-x)} assert mmrv(exp(1/x + exp(-x)), x) == {exp(-x)} #sometimes infinite recursion due to log(exp(x**2)) not simplifying def test_mrv2b(): assert mmrv(exp(x + exp(-x**2)), x) == {exp(-x**2)} #sometimes infinite recursion due to log(exp(x**2)) not simplifying def test_mrv2c(): assert mmrv( exp(-x + 1/x**2) - exp(x + 1/x), x) == {exp(x + 1/x), exp(1/x**2 - x)} #sometimes infinite recursion due to log(exp(x**2)) not simplifying def test_mrv3(): assert mmrv(exp(x**2) + x*exp(x) + log(x)**x/x, x) == {exp(x**2)} assert mmrv( exp(x)*(exp(1/x + exp(-x)) - exp(1/x)), x) == {exp(x), exp(-x)} assert mmrv(log( x**2 + 2*exp(exp(3*x**3*log(x)))), x) == {exp(exp(3*x**3*log(x)))} assert mmrv(log(x - log(x))/log(x), x) == {x} assert mmrv( (exp(1/x - exp(-x)) - exp(1/x))*exp(x), x) == {exp(x), exp(-x)} assert mmrv( 1/exp(-x + exp(-x)) - exp(x), x) == {exp(x), exp(-x), exp(x - exp(-x))} assert mmrv(log(log(x*exp(x*exp(x)) + 1)), x) == {exp(x*exp(x))} assert mmrv(exp(exp(log(log(x) + 1/x))), x) == {x} def test_mrv4(): ln = log assert mmrv((ln(ln(x) + ln(ln(x))) - ln(ln(x)))/ln(ln(x) + ln(ln(ln(x))))*ln(x), x) == {x} assert mmrv(log(log(x*exp(x*exp(x)) + 1)) - exp(exp(log(log(x) + 1/x))), x) == \ {exp(x*exp(x))} def mrewrite(a, b, c): return rewrite(a[1], a[0], b, c) def test_rewrite1(): e = exp(x) assert mrewrite(mrv(e, x), x, m) == (1/m, -x) e = exp(x**2) assert mrewrite(mrv(e, x), x, m) == (1/m, -x**2) e = exp(x + 1/x) assert mrewrite(mrv(e, x), x, m) == (1/m, -x - 1/x) e = 1/exp(-x + exp(-x)) - exp(x) assert mrewrite(mrv(e, x), x, m) == (1/(m*exp(m)) - 1/m, -x) def test_rewrite2(): e = exp(x)*log(log(exp(x))) assert mmrv(e, x) == {exp(x)} assert mrewrite(mrv(e, x), x, m) == (1/m*log(x), -x) #sometimes infinite recursion due to log(exp(x**2)) not simplifying def test_rewrite3(): e = exp(-x + 1/x**2) - exp(x + 1/x) #both of these are correct and should be equivalent: assert mrewrite(mrv(e, x), x, m) in [(-1/m + m*exp( 1/x + 1/x**2), -x - 1/x), (m - 1/m*exp(1/x + x**(-2)), x**(-2) - x)] def test_mrv_leadterm1(): assert mrv_leadterm(-exp(1/x), x) == (-1, 0) assert mrv_leadterm(1/exp(-x + exp(-x)) - exp(x), x) == (-1, 0) assert mrv_leadterm( (exp(1/x - exp(-x)) - exp(1/x))*exp(x), x) == (-exp(1/x), 0) def test_mrv_leadterm2(): #Gruntz: p51, 3.25 assert mrv_leadterm((log(exp(x) + x) - x)/log(exp(x) + log(x))*exp(x), x) == \ (1, 0) def test_mrv_leadterm3(): #Gruntz: p56, 3.27 assert mmrv(exp(-x + exp(-x)*exp(-x*log(x))), x) == {exp(-x - x*log(x))} assert mrv_leadterm(exp(-x + exp(-x)*exp(-x*log(x))), x) == (exp(-x), 0) def test_limit1(): assert gruntz(x, x, oo) is oo assert gruntz(x, x, -oo) is -oo assert gruntz(-x, x, oo) is -oo assert gruntz(x**2, x, -oo) is oo assert gruntz(-x**2, x, oo) is -oo assert gruntz(x*log(x), x, 0, dir="+") == 0 assert gruntz(1/x, x, oo) == 0 assert gruntz(exp(x), x, oo) is oo assert gruntz(-exp(x), x, oo) is -oo assert gruntz(exp(x)/x, x, oo) is oo assert gruntz(1/x - exp(-x), x, oo) == 0 assert gruntz(x + 1/x, x, oo) is oo def test_limit2(): assert gruntz(x**x, x, 0, dir="+") == 1 assert gruntz((exp(x) - 1)/x, x, 0) == 1 assert gruntz(1 + 1/x, x, oo) == 1 assert gruntz(-exp(1/x), x, oo) == -1 assert gruntz(x + exp(-x), x, oo) is oo assert gruntz(x + exp(-x**2), x, oo) is oo assert gruntz(x + exp(-exp(x)), x, oo) is oo assert gruntz(13 + 1/x - exp(-x), x, oo) == 13 def test_limit3(): a = Symbol('a') assert gruntz(x - log(1 + exp(x)), x, oo) == 0 assert gruntz(x - log(a + exp(x)), x, oo) == 0 assert gruntz(exp(x)/(1 + exp(x)), x, oo) == 1 assert gruntz(exp(x)/(a + exp(x)), x, oo) == 1 def test_limit4(): #issue 3463 assert gruntz((3**x + 5**x)**(1/x), x, oo) == 5 #issue 3463 assert gruntz((3**(1/x) + 5**(1/x))**x, x, 0) == 5 @XFAIL def test_MrvTestCase_page47_ex3_21(): h = exp(-x/(1 + exp(-x))) expr = exp(h)*exp(-x/(1 + h))*exp(exp(-x + h))/h**2 - exp(x) + x assert mmrv(expr, x) == {1/h, exp(-x), exp(x), exp(x - h), exp(x/(1 + h))} def test_I(): from sympy import sign y = Symbol("y") assert gruntz(I*x, x, oo) == I*oo assert gruntz(y*I*x, x, oo) == y*I*oo assert gruntz(y*3*I*x, x, oo) == y*I*oo assert gruntz(y*3*sin(I)*x, x, oo).simplify().rewrite(sign) == y*I*oo def test_issue_4814(): assert gruntz((x + 1)**(1/log(x + 1)), x, oo) == E def test_intractable(): assert gruntz(1/gamma(x), x, oo) == 0 assert gruntz(1/loggamma(x), x, oo) == 0 assert gruntz(gamma(x)/loggamma(x), x, oo) is oo assert gruntz(exp(gamma(x))/gamma(x), x, oo) is oo assert gruntz(gamma(x), x, 3) == 2 assert gruntz(gamma(Rational(1, 7) + 1/x), x, oo) == gamma(Rational(1, 7)) assert gruntz(log(x**x)/log(gamma(x)), x, oo) == 1 assert gruntz(log(gamma(gamma(x)))/exp(x), x, oo) is oo def test_aseries_trig(): assert cancel(gruntz(1/log(atan(x)), x, oo) - 1/(log(pi) + log(S.Half))) == 0 assert gruntz(1/acot(x), x, -oo) is -oo def test_exp_log_series(): assert gruntz(x/log(log(x*exp(x))), x, oo) is oo def test_issue_3644(): assert gruntz(((x**7 + x + 1)/(2**x + x**2))**(-1/x), x, oo) == 2 def test_issue_6843(): n = Symbol('n', integer=True, positive=True) r = (n + 1)*x**(n + 1)/(x**(n + 1) - 1) - x/(x - 1) assert gruntz(r, x, 1).simplify() == n/2 def test_issue_4190(): assert gruntz(x - gamma(1/x), x, oo) == S.EulerGamma @XFAIL def test_issue_5172(): n = Symbol('n') r = Symbol('r', positive=True) c = Symbol('c') p = Symbol('p', positive=True) m = Symbol('m', negative=True) expr = ((2*n*(n - r + 1)/(n + r*(n - r + 1)))**c + \ (r - 1)*(n*(n - r + 2)/(n + r*(n - r + 1)))**c - n)/(n**c - n) expr = expr.subs(c, c + 1) assert gruntz(expr.subs(c, m), n, oo) == 1 # fail: assert gruntz(expr.subs(c, p), n, oo).simplify() == \ (2**(p + 1) + r - 1)/(r + 1)**(p + 1) def test_issue_4109(): assert gruntz(1/gamma(x), x, 0) == 0 assert gruntz(x*gamma(x), x, 0) == 1 def test_issue_6682(): assert gruntz(exp(2*Ei(-x))/x**2, x, 0) == exp(2*EulerGamma) def test_issue_7096(): from sympy.functions import sign assert gruntz(x**-pi, x, 0, dir='-') == oo*sign((-1)**(-pi)) sympy-sympy-1.9/sympy/series/tests/test_kauers.py000066400000000000000000000020101412543434000224340ustar00rootroot00000000000000from sympy.series.kauers import finite_diff from sympy.series.kauers import finite_diff_kauers from sympy.abc import x, y, z, m, n, w from sympy import sin, cos from sympy import pi from sympy import Sum def test_finite_diff(): assert finite_diff(x**2 + 2*x + 1, x) == 2*x + 3 assert finite_diff(y**3 + 2*y**2 + 3*y + 5, y) == 3*y**2 + 7*y + 6 assert finite_diff(z**2 - 2*z + 3, z) == 2*z - 1 assert finite_diff(w**2 + 3*w - 2, w) == 2*w + 4 assert finite_diff(sin(x), x, pi/6) == -sin(x) + sin(x + pi/6) assert finite_diff(cos(y), y, pi/3) == -cos(y) + cos(y + pi/3) assert finite_diff(x**2 - 2*x + 3, x, 2) == 4*x assert finite_diff(n**2 - 2*n + 3, n, 3) == 6*n + 3 def test_finite_diff_kauers(): assert finite_diff_kauers(Sum(x**2, (x, 1, n))) == (n + 1)**2 assert finite_diff_kauers(Sum(y, (y, 1, m))) == (m + 1) assert finite_diff_kauers(Sum((x*y), (x, 1, m), (y, 1, n))) == (m + 1)*(n + 1) assert finite_diff_kauers(Sum((x*y**2), (x, 1, m), (y, 1, n))) == (n + 1)**2*(m + 1) sympy-sympy-1.9/sympy/series/tests/test_limits.py000066400000000000000000000776461412543434000224760ustar00rootroot00000000000000from itertools import product as cartes from sympy import ( limit, exp, oo, log, sqrt, Limit, sin, floor, cos, ceiling, sinh, atan, Abs, gamma, Symbol, S, pi, Integral, Rational, I, E, besselj, tan, cot, integrate, Sum, sign, Function, subfactorial, symbols, binomial, simplify, frac, Float, sec, zoo, fresnelc, fresnels, real_root, acos, erf, erfc, erfi, LambertW, factorial, digamma, uppergamma, re, Ei, EulerGamma, asin, atanh, acot, acoth, asec, acsc, cbrt, besselk) from sympy.calculus.util import AccumBounds from sympy.core.mul import Mul from sympy.series.limits import heuristics from sympy.series.order import Order from sympy.testing.pytest import XFAIL, raises from sympy.abc import x, y, z, k n = Symbol('n', integer=True, positive=True) def test_basic1(): assert limit(x, x, oo) is oo assert limit(x, x, -oo) is -oo assert limit(-x, x, oo) is -oo assert limit(x**2, x, -oo) is oo assert limit(-x**2, x, oo) is -oo assert limit(x*log(x), x, 0, dir="+") == 0 assert limit(1/x, x, oo) == 0 assert limit(exp(x), x, oo) is oo assert limit(-exp(x), x, oo) is -oo assert limit(exp(x)/x, x, oo) is oo assert limit(1/x - exp(-x), x, oo) == 0 assert limit(x + 1/x, x, oo) is oo assert limit(x - x**2, x, oo) is -oo assert limit((1 + x)**(1 + sqrt(2)), x, 0) == 1 assert limit((1 + x)**oo, x, 0) == Limit((x + 1)**oo, x, 0) assert limit((1 + x)**oo, x, 0, dir='-') == Limit((x + 1)**oo, x, 0, dir='-') assert limit((1 + x + y)**oo, x, 0, dir='-') == Limit((1 + x + y)**oo, x, 0, dir='-') assert limit(y/x/log(x), x, 0) == -oo*sign(y) assert limit(cos(x + y)/x, x, 0) == sign(cos(y))*oo assert limit(gamma(1/x + 3), x, oo) == 2 assert limit(S.NaN, x, -oo) is S.NaN assert limit(Order(2)*x, x, S.NaN) is S.NaN assert limit(1/(x - 1), x, 1, dir="+") is oo assert limit(1/(x - 1), x, 1, dir="-") is -oo assert limit(1/(5 - x)**3, x, 5, dir="+") is -oo assert limit(1/(5 - x)**3, x, 5, dir="-") is oo assert limit(1/sin(x), x, pi, dir="+") is -oo assert limit(1/sin(x), x, pi, dir="-") is oo assert limit(1/cos(x), x, pi/2, dir="+") is -oo assert limit(1/cos(x), x, pi/2, dir="-") is oo assert limit(1/tan(x**3), x, (2*pi)**Rational(1, 3), dir="+") is oo assert limit(1/tan(x**3), x, (2*pi)**Rational(1, 3), dir="-") is -oo assert limit(1/cot(x)**3, x, (pi*Rational(3, 2)), dir="+") is -oo assert limit(1/cot(x)**3, x, (pi*Rational(3, 2)), dir="-") is oo # test bi-directional limits assert limit(sin(x)/x, x, 0, dir="+-") == 1 assert limit(x**2, x, 0, dir="+-") == 0 assert limit(1/x**2, x, 0, dir="+-") is oo # test failing bi-directional limits assert limit(1/x, x, 0, dir="+-") is zoo # approaching 0 # from dir="+" assert limit(1 + 1/x, x, 0) is oo # from dir='-' # Add assert limit(1 + 1/x, x, 0, dir='-') is -oo # Pow assert limit(x**(-2), x, 0, dir='-') is oo assert limit(x**(-3), x, 0, dir='-') is -oo assert limit(1/sqrt(x), x, 0, dir='-') == (-oo)*I assert limit(x**2, x, 0, dir='-') == 0 assert limit(sqrt(x), x, 0, dir='-') == 0 assert limit(x**-pi, x, 0, dir='-') == -oo*(-1)**(1 - pi) assert limit((1 + cos(x))**oo, x, 0) == Limit((cos(x) + 1)**oo, x, 0) def test_basic2(): assert limit(x**x, x, 0, dir="+") == 1 assert limit((exp(x) - 1)/x, x, 0) == 1 assert limit(1 + 1/x, x, oo) == 1 assert limit(-exp(1/x), x, oo) == -1 assert limit(x + exp(-x), x, oo) is oo assert limit(x + exp(-x**2), x, oo) is oo assert limit(x + exp(-exp(x)), x, oo) is oo assert limit(13 + 1/x - exp(-x), x, oo) == 13 def test_basic3(): assert limit(1/x, x, 0, dir="+") is oo assert limit(1/x, x, 0, dir="-") is -oo def test_basic4(): assert limit(2*x + y*x, x, 0) == 0 assert limit(2*x + y*x, x, 1) == 2 + y assert limit(2*x**8 + y*x**(-3), x, -2) == 512 - y/8 assert limit(sqrt(x + 1) - sqrt(x), x, oo) == 0 assert integrate(1/(x**3 + 1), (x, 0, oo)) == 2*pi*sqrt(3)/9 def test_log(): # https://github.com/sympy/sympy/issues/21598 a, b, c = symbols('a b c', positive=True) A = log(a/b) - (log(a) - log(b)) assert A.limit(a, oo) == 0 assert (A * c).limit(a, oo) == 0 tau, x = symbols('tau x', positive=True) # The value of manualintegrate in the issue expr = tau**2*((tau - 1)*(tau + 1)*log(x + 1)/(tau**2 + 1)**2 + 1/((tau**2\ + 1)*(x + 1)) - (-2*tau*atan(x/tau) + (tau**2/2 - 1/2)*log(tau**2\ + x**2))/(tau**2 + 1)**2) assert limit(expr, x, oo) == pi*tau**3/(tau**2 + 1)**2 def test_piecewise(): # https://github.com/sympy/sympy/issues/18363 assert limit((real_root(x - 6, 3) + 2)/(x + 2), x, -2, '+') == Rational(1, 12) def test_basic5(): class my(Function): @classmethod def eval(cls, arg): if arg is S.Infinity: return S.NaN assert limit(my(x), x, oo) == Limit(my(x), x, oo) def test_issue_3885(): assert limit(x*y + x*z, z, 2) == x*y + 2*x def test_Limit(): assert Limit(sin(x)/x, x, 0) != 1 assert Limit(sin(x)/x, x, 0).doit() == 1 assert Limit(x, x, 0, dir='+-').args == (x, x, 0, Symbol('+-')) def test_floor(): assert limit(floor(x), x, -2, "+") == -2 assert limit(floor(x), x, -2, "-") == -3 assert limit(floor(x), x, -1, "+") == -1 assert limit(floor(x), x, -1, "-") == -2 assert limit(floor(x), x, 0, "+") == 0 assert limit(floor(x), x, 0, "-") == -1 assert limit(floor(x), x, 1, "+") == 1 assert limit(floor(x), x, 1, "-") == 0 assert limit(floor(x), x, 2, "+") == 2 assert limit(floor(x), x, 2, "-") == 1 assert limit(floor(x), x, 248, "+") == 248 assert limit(floor(x), x, 248, "-") == 247 # https://github.com/sympy/sympy/issues/14478 assert limit(x*floor(3/x)/2, x, 0, '+') == Rational(3, 2) assert limit(floor(x + 1/2) - floor(x), x, oo) == AccumBounds(-0.5, 1.5) def test_floor_requires_robust_assumptions(): assert limit(floor(sin(x)), x, 0, "+") == 0 assert limit(floor(sin(x)), x, 0, "-") == -1 assert limit(floor(cos(x)), x, 0, "+") == 0 assert limit(floor(cos(x)), x, 0, "-") == 0 assert limit(floor(5 + sin(x)), x, 0, "+") == 5 assert limit(floor(5 + sin(x)), x, 0, "-") == 4 assert limit(floor(5 + cos(x)), x, 0, "+") == 5 assert limit(floor(5 + cos(x)), x, 0, "-") == 5 def test_ceiling(): assert limit(ceiling(x), x, -2, "+") == -1 assert limit(ceiling(x), x, -2, "-") == -2 assert limit(ceiling(x), x, -1, "+") == 0 assert limit(ceiling(x), x, -1, "-") == -1 assert limit(ceiling(x), x, 0, "+") == 1 assert limit(ceiling(x), x, 0, "-") == 0 assert limit(ceiling(x), x, 1, "+") == 2 assert limit(ceiling(x), x, 1, "-") == 1 assert limit(ceiling(x), x, 2, "+") == 3 assert limit(ceiling(x), x, 2, "-") == 2 assert limit(ceiling(x), x, 248, "+") == 249 assert limit(ceiling(x), x, 248, "-") == 248 # https://github.com/sympy/sympy/issues/14478 assert limit(x*ceiling(3/x)/2, x, 0, '+') == Rational(3, 2) assert limit(ceiling(x + 1/2) - ceiling(x), x, oo) == AccumBounds(-0.5, 1.5) def test_ceiling_requires_robust_assumptions(): assert limit(ceiling(sin(x)), x, 0, "+") == 1 assert limit(ceiling(sin(x)), x, 0, "-") == 0 assert limit(ceiling(cos(x)), x, 0, "+") == 1 assert limit(ceiling(cos(x)), x, 0, "-") == 1 assert limit(ceiling(5 + sin(x)), x, 0, "+") == 6 assert limit(ceiling(5 + sin(x)), x, 0, "-") == 5 assert limit(ceiling(5 + cos(x)), x, 0, "+") == 6 assert limit(ceiling(5 + cos(x)), x, 0, "-") == 6 def test_atan(): x = Symbol("x", real=True) assert limit(atan(x)*sin(1/x), x, 0) == 0 assert limit(atan(x) + sqrt(x + 1) - sqrt(x), x, oo) == pi/2 def test_set_signs(): assert limit(abs(x), x, 0) == 0 assert limit(abs(sin(x)), x, 0) == 0 assert limit(abs(cos(x)), x, 0) == 1 assert limit(abs(sin(x + 1)), x, 0) == sin(1) # https://github.com/sympy/sympy/issues/9449 assert limit((Abs(x + y) - Abs(x - y))/(2*x), x, 0) == sign(y) # https://github.com/sympy/sympy/issues/12398 assert limit(Abs(log(x)/x**3), x, oo) == 0 assert limit(x*(Abs(log(x)/x**3)/Abs(log(x + 1)/(x + 1)**3) - 1), x, oo) == 3 # https://github.com/sympy/sympy/issues/18501 assert limit(Abs(log(x - 1)**3 - 1), x, 1, '+') == oo # https://github.com/sympy/sympy/issues/18997 assert limit(Abs(log(x)), x, 0) == oo assert limit(Abs(log(Abs(x))), x, 0) == oo # https://github.com/sympy/sympy/issues/19026 z = Symbol('z', positive=True) assert limit(Abs(log(z) + 1)/log(z), z, oo) == 1 # https://github.com/sympy/sympy/issues/20704 assert limit(z*(Abs(1/z + y) - Abs(y - 1/z))/2, z, 0) == 0 # https://github.com/sympy/sympy/issues/21606 assert limit(cos(z)/sign(z), z, pi, '-') == -1 def test_heuristic(): x = Symbol("x", real=True) assert heuristics(sin(1/x) + atan(x), x, 0, '+') == AccumBounds(-1, 1) assert limit(log(2 + sqrt(atan(x))*sqrt(sin(1/x))), x, 0) == log(2) def test_issue_3871(): z = Symbol("z", positive=True) f = -1/z*exp(-z*x) assert limit(f, x, oo) == 0 assert f.limit(x, oo) == 0 def test_exponential(): n = Symbol('n') x = Symbol('x', real=True) assert limit((1 + x/n)**n, n, oo) == exp(x) assert limit((1 + x/(2*n))**n, n, oo) == exp(x/2) assert limit((1 + x/(2*n + 1))**n, n, oo) == exp(x/2) assert limit(((x - 1)/(x + 1))**x, x, oo) == exp(-2) assert limit(1 + (1 + 1/x)**x, x, oo) == 1 + S.Exp1 assert limit((2 + 6*x)**x/(6*x)**x, x, oo) == exp(S('1/3')) def test_exponential2(): n = Symbol('n') assert limit((1 + x/(n + sin(n)))**n, n, oo) == exp(x) def test_doit(): f = Integral(2 * x, x) l = Limit(f, x, oo) assert l.doit() is oo def test_series_AccumBounds(): assert limit(sin(k) - sin(k + 1), k, oo) == AccumBounds(-2, 2) assert limit(cos(k) - cos(k + 1) + 1, k, oo) == AccumBounds(-1, 3) # not the exact bound assert limit(sin(k) - sin(k)*cos(k), k, oo) == AccumBounds(-2, 2) # test for issue #9934 t1 = Mul(AccumBounds(-S(3)/2 + cos(1)/2, cos(1)/2 + S.Half), 1/(-1 + cos(1))) assert limit(simplify(Sum(cos(n).rewrite(exp), (n, 0, k)).doit().rewrite(sin)), k, oo) == t1 t2 = Mul(AccumBounds(-1 + sin(1)/2, sin(1)/2 + 1), 1/(1 - cos(1))) assert limit(simplify(Sum(sin(n).rewrite(exp), (n, 0, k)).doit().rewrite(sin)), k, oo) == t2 assert limit(frac(x)**x, x, oo) == AccumBounds(0, oo) # wolfram gives (0, 1) assert limit(((sin(x) + 1)/2)**x, x, oo) == AccumBounds(0, oo) # wolfram says 0 @XFAIL def test_doit2(): f = Integral(2 * x, x) l = Limit(f, x, oo) # limit() breaks on the contained Integral. assert l.doit(deep=False) == l def test_issue_2929(): assert limit((x * exp(x))/(exp(x) - 1), x, -oo) == 0 def test_issue_3792(): assert limit((1 - cos(x))/x**2, x, S.Half) == 4 - 4*cos(S.Half) assert limit(sin(sin(x + 1) + 1), x, 0) == sin(1 + sin(1)) assert limit(abs(sin(x + 1) + 1), x, 0) == 1 + sin(1) def test_issue_4090(): assert limit(1/(x + 3), x, 2) == Rational(1, 5) assert limit(1/(x + pi), x, 2) == S.One/(2 + pi) assert limit(log(x)/(x**2 + 3), x, 2) == log(2)/7 assert limit(log(x)/(x**2 + pi), x, 2) == log(2)/(4 + pi) def test_issue_4547(): assert limit(cot(x), x, 0, dir='+') is oo assert limit(cot(x), x, pi/2, dir='+') == 0 def test_issue_5164(): assert limit(x**0.5, x, oo) == oo**0.5 is oo assert limit(x**0.5, x, 16) == S(16)**0.5 assert limit(x**0.5, x, 0) == 0 assert limit(x**(-0.5), x, oo) == 0 assert limit(x**(-0.5), x, 4) == S(4)**(-0.5) def test_issue_5383(): func = (1.0 * 1 + 1.0 * x)**(1.0 * 1 / x) assert limit(func, x, 0) == E.n() def test_issue_14793(): expr = ((x + S(1)/2) * log(x) - x + log(2*pi)/2 - \ log(factorial(x)) + S(1)/(12*x))*x**3 assert limit(expr, x, oo) == S(1)/360 def test_issue_5183(): # using list(...) so py.test can recalculate values tests = list(cartes([x, -x], [-1, 1], [2, 3, S.Half, Rational(2, 3)], ['-', '+'])) results = (oo, oo, -oo, oo, -oo*I, oo, -oo*(-1)**Rational(1, 3), oo, 0, 0, 0, 0, 0, 0, 0, 0, oo, oo, oo, -oo, oo, -oo*I, oo, -oo*(-1)**Rational(1, 3), 0, 0, 0, 0, 0, 0, 0, 0) assert len(tests) == len(results) for i, (args, res) in enumerate(zip(tests, results)): y, s, e, d = args eq = y**(s*e) try: assert limit(eq, x, 0, dir=d) == res except AssertionError: if 0: # change to 1 if you want to see the failing tests print() print(i, res, eq, d, limit(eq, x, 0, dir=d)) else: assert None def test_issue_5184(): assert limit(sin(x)/x, x, oo) == 0 assert limit(atan(x), x, oo) == pi/2 assert limit(gamma(x), x, oo) is oo assert limit(cos(x)/x, x, oo) == 0 assert limit(gamma(x), x, S.Half) == sqrt(pi) r = Symbol('r', real=True) assert limit(r*sin(1/r), r, 0) == 0 def test_issue_5229(): assert limit((1 + y)**(1/y) - S.Exp1, y, 0) == 0 def test_issue_4546(): # using list(...) so py.test can recalculate values tests = list(cartes([cot, tan], [-pi/2, 0, pi/2, pi, pi*Rational(3, 2)], ['-', '+'])) results = (0, 0, -oo, oo, 0, 0, -oo, oo, 0, 0, oo, -oo, 0, 0, oo, -oo, 0, 0, oo, -oo) assert len(tests) == len(results) for i, (args, res) in enumerate(zip(tests, results)): f, l, d = args eq = f(x) try: assert limit(eq, x, l, dir=d) == res except AssertionError: if 0: # change to 1 if you want to see the failing tests print() print(i, res, eq, l, d, limit(eq, x, l, dir=d)) else: assert None def test_issue_3934(): assert limit((1 + x**log(3))**(1/x), x, 0) == 1 assert limit((5**(1/x) + 3**(1/x))**x, x, 0) == 5 def test_calculate_series(): # needs gruntz calculate_series to go to n = 32 assert limit(x**Rational(77, 3)/(1 + x**Rational(77, 3)), x, oo) == 1 # needs gruntz calculate_series to go to n = 128 assert limit(x**101.1/(1 + x**101.1), x, oo) == 1 def test_issue_5955(): assert limit((x**16)/(1 + x**16), x, oo) == 1 assert limit((x**100)/(1 + x**100), x, oo) == 1 assert limit((x**1885)/(1 + x**1885), x, oo) == 1 assert limit((x**1000/((x + 1)**1000 + exp(-x))), x, oo) == 1 def test_newissue(): assert limit(exp(1/sin(x))/exp(cot(x)), x, 0) == 1 def test_extended_real_line(): assert limit(x - oo, x, oo) == Limit(x - oo, x, oo) assert limit(1/(x + sin(x)) - oo, x, 0) == Limit(1/(x + sin(x)) - oo, x, 0) assert limit(oo/x, x, oo) == Limit(oo/x, x, oo) assert limit(x - oo + 1/x, x, oo) == Limit(x - oo + 1/x, x, oo) @XFAIL def test_order_oo(): x = Symbol('x', positive=True) assert Order(x)*oo != Order(1, x) assert limit(oo/(x**2 - 4), x, oo) is oo def test_issue_5436(): raises(NotImplementedError, lambda: limit(exp(x*y), x, oo)) raises(NotImplementedError, lambda: limit(exp(-x*y), x, oo)) def test_Limit_dir(): raises(TypeError, lambda: Limit(x, x, 0, dir=0)) raises(ValueError, lambda: Limit(x, x, 0, dir='0')) def test_polynomial(): assert limit((x + 1)**1000/((x + 1)**1000 + 1), x, oo) == 1 assert limit((x + 1)**1000/((x + 1)**1000 + 1), x, -oo) == 1 def test_rational(): assert limit(1/y - (1/(y + x) + x/(y + x)/y)/z, x, oo) == (z - 1)/(y*z) assert limit(1/y - (1/(y + x) + x/(y + x)/y)/z, x, -oo) == (z - 1)/(y*z) def test_issue_5740(): assert limit(log(x)*z - log(2*x)*y, x, 0) == oo*sign(y - z) def test_issue_6366(): n = Symbol('n', integer=True, positive=True) r = (n + 1)*x**(n + 1)/(x**(n + 1) - 1) - x/(x - 1) assert limit(r, x, 1).cancel() == n/2 def test_factorial(): from sympy import factorial, E f = factorial(x) assert limit(f, x, oo) is oo assert limit(x/f, x, oo) == 0 # see Stirling's approximation: # https://en.wikipedia.org/wiki/Stirling's_approximation assert limit(f/(sqrt(2*pi*x)*(x/E)**x), x, oo) == 1 assert limit(f, x, -oo) == factorial(-oo) def test_issue_6560(): e = (5*x**3/4 - x*Rational(3, 4) + (y*(3*x**2/2 - S.Half) + 35*x**4/8 - 15*x**2/4 + Rational(3, 8))/(2*(y + 1))) assert limit(e, y, oo) == 5*x**3/4 + 3*x**2/4 - 3*x/4 - Rational(1, 4) @XFAIL def test_issue_5172(): n = Symbol('n') r = Symbol('r', positive=True) c = Symbol('c') p = Symbol('p', positive=True) m = Symbol('m', negative=True) expr = ((2*n*(n - r + 1)/(n + r*(n - r + 1)))**c + (r - 1)*(n*(n - r + 2)/(n + r*(n - r + 1)))**c - n)/(n**c - n) expr = expr.subs(c, c + 1) raises(NotImplementedError, lambda: limit(expr, n, oo)) assert limit(expr.subs(c, m), n, oo) == 1 assert limit(expr.subs(c, p), n, oo).simplify() == \ (2**(p + 1) + r - 1)/(r + 1)**(p + 1) def test_issue_7088(): a = Symbol('a') assert limit(sqrt(x/(x + a)), x, oo) == 1 def test_branch_cuts(): assert limit(asin(I*x + 2), x, 0) == pi - asin(2) assert limit(asin(I*x + 2), x, 0, '-') == asin(2) assert limit(asin(I*x - 2), x, 0) == -asin(2) assert limit(asin(I*x - 2), x, 0, '-') == -pi + asin(2) assert limit(acos(I*x + 2), x, 0) == -acos(2) assert limit(acos(I*x + 2), x, 0, '-') == acos(2) assert limit(acos(I*x - 2), x, 0) == acos(-2) assert limit(acos(I*x - 2), x, 0, '-') == 2*pi - acos(-2) assert limit(atan(x + 2*I), x, 0) == I*atanh(2) assert limit(atan(x + 2*I), x, 0, '-') == -pi + I*atanh(2) assert limit(atan(x - 2*I), x, 0) == pi - I*atanh(2) assert limit(atan(x - 2*I), x, 0, '-') == -I*atanh(2) assert limit(atan(1/x), x, 0) == pi/2 assert limit(atan(1/x), x, 0, '-') == -pi/2 assert limit(atan(x), x, oo) == pi/2 assert limit(atan(x), x, -oo) == -pi/2 assert limit(acot(x + S(1)/2*I), x, 0) == pi - I*acoth(S(1)/2) assert limit(acot(x + S(1)/2*I), x, 0, '-') == -I*acoth(S(1)/2) assert limit(acot(x - S(1)/2*I), x, 0) == I*acoth(S(1)/2) assert limit(acot(x - S(1)/2*I), x, 0, '-') == -pi + I*acoth(S(1)/2) assert limit(acot(x), x, 0) == pi/2 assert limit(acot(x), x, 0, '-') == -pi/2 assert limit(asec(I*x + S(1)/2), x, 0) == asec(S(1)/2) assert limit(asec(I*x + S(1)/2), x, 0, '-') == -asec(S(1)/2) assert limit(asec(I*x - S(1)/2), x, 0) == 2*pi - asec(-S(1)/2) assert limit(asec(I*x - S(1)/2), x, 0, '-') == asec(-S(1)/2) assert limit(acsc(I*x + S(1)/2), x, 0) == acsc(S(1)/2) assert limit(acsc(I*x + S(1)/2), x, 0, '-') == pi - acsc(S(1)/2) assert limit(acsc(I*x - S(1)/2), x, 0) == -pi + acsc(S(1)/2) assert limit(acsc(I*x - S(1)/2), x, 0, '-') == -acsc(S(1)/2) assert limit(log(I*x - 1), x, 0) == I*pi assert limit(log(I*x - 1), x, 0, '-') == -I*pi assert limit(log(-I*x - 1), x, 0) == -I*pi assert limit(log(-I*x - 1), x, 0, '-') == I*pi assert limit(sqrt(I*x - 1), x, 0) == I assert limit(sqrt(I*x - 1), x, 0, '-') == -I assert limit(sqrt(-I*x - 1), x, 0) == -I assert limit(sqrt(-I*x - 1), x, 0, '-') == I assert limit(cbrt(I*x - 1), x, 0) == (-1)**(S(1)/3) assert limit(cbrt(I*x - 1), x, 0, '-') == -(-1)**(S(2)/3) assert limit(cbrt(-I*x - 1), x, 0) == -(-1)**(S(2)/3) assert limit(cbrt(-I*x - 1), x, 0, '-') == (-1)**(S(1)/3) def test_issue_6364(): a = Symbol('a') e = z/(1 - sqrt(1 + z)*sin(a)**2 - sqrt(1 - z)*cos(a)**2) assert limit(e, z, 0) == 1/(cos(a)**2 - S.Half) def test_issue_4099(): a = Symbol('a') assert limit(a/x, x, 0) == oo*sign(a) assert limit(-a/x, x, 0) == -oo*sign(a) assert limit(-a*x, x, oo) == -oo*sign(a) assert limit(a*x, x, oo) == oo*sign(a) def test_issue_4503(): dx = Symbol('dx') assert limit((sqrt(1 + exp(x + dx)) - sqrt(1 + exp(x)))/dx, dx, 0) == \ exp(x)/(2*sqrt(exp(x) + 1)) def test_issue_8208(): assert limit(n**(Rational(1, 1e9) - 1), n, oo) == 0 def test_issue_8229(): assert limit((x**Rational(1, 4) - 2)/(sqrt(x) - 4)**Rational(2, 3), x, 16) == 0 def test_issue_8433(): d, t = symbols('d t', positive=True) assert limit(erf(1 - t/d), t, oo) == -1 def test_issue_8481(): k = Symbol('k', integer=True, nonnegative=True) lamda = Symbol('lamda', real=True, positive=True) limit(lamda**k * exp(-lamda) / factorial(k), k, oo) == 0 def test_issue_8730(): assert limit(subfactorial(x), x, oo) is oo def test_issue_9252(): n = Symbol('n', integer=True) c = Symbol('c', positive=True) assert limit((log(n))**(n/log(n)) / (1 + c)**n, n, oo) == 0 # limit should depend on the value of c raises(NotImplementedError, lambda: limit((log(n))**(n/log(n)) / c**n, n, oo)) def test_issue_9558(): assert limit(sin(x)**15, x, 0, '-') == 0 def test_issue_10801(): # make sure limits work with binomial assert limit(16**k / (k * binomial(2*k, k)**2), k, oo) == pi def test_issue_10976(): s, x = symbols('s x', real=True) assert limit(erf(s*x)/erf(s), s, 0) == x def test_issue_9041(): assert limit(factorial(n) / ((n/exp(1))**n * sqrt(2*pi*n)), n, oo) == 1 def test_issue_9205(): x, y, a = symbols('x, y, a') assert Limit(x, x, a).free_symbols == {a} assert Limit(x, x, a, '-').free_symbols == {a} assert Limit(x + y, x + y, a).free_symbols == {a} assert Limit(-x**2 + y, x**2, a).free_symbols == {y, a} def test_issue_9471(): assert limit(((27**(log(n,3)))/n**3),n,oo) == 1 assert limit(((27**(log(n,3)+1))/n**3),n,oo) == 27 def test_issue_11496(): assert limit(erfc(log(1/x)), x, oo) == 2 def test_issue_11879(): assert simplify(limit(((x+y)**n-x**n)/y, y, 0)) == n*x**(n-1) def test_limit_with_Float(): k = symbols("k") assert limit(1.0 ** k, k, oo) == 1 assert limit(0.3*1.0**k, k, oo) == Float(0.3) def test_issue_10610(): assert limit(3**x*3**(-x - 1)*(x + 1)**2/x**2, x, oo) == Rational(1, 3) def test_issue_6599(): assert limit((n + cos(n))/n, n, oo) == 1 def test_issue_12555(): assert limit((3**x + 2* x**10) / (x**10 + exp(x)), x, -oo) == 2 assert limit((3**x + 2* x**10) / (x**10 + exp(x)), x, oo) is oo def test_issue_12769(): r, z, x = symbols('r z x', real=True) a, b, s0, K, F0, s, T = symbols('a b s0 K F0 s T', positive=True, real=True) fx = (F0**b*K**b*r*s0 - sqrt((F0**2*K**(2*b)*a**2*(b - 1) + \ F0**(2*b)*K**2*a**2*(b - 1) + F0**(2*b)*K**(2*b)*s0**2*(b - 1)*(b**2 - 2*b + 1) - \ 2*F0**(2*b)*K**(b + 1)*a*r*s0*(b**2 - 2*b + 1) + \ 2*F0**(b + 1)*K**(2*b)*a*r*s0*(b**2 - 2*b + 1) - \ 2*F0**(b + 1)*K**(b + 1)*a**2*(b - 1))/((b - 1)*(b**2 - 2*b + 1))))*(b*r - b - r + 1) assert fx.subs(K, F0).factor(deep=True) == limit(fx, K, F0).factor(deep=True) def test_issue_13332(): assert limit(sqrt(30)*5**(-5*x - 1)*(46656*x)**x*(5*x + 2)**(5*x + 5*S.Half) * (6*x + 2)**(-6*x - 5*S.Half), x, oo) == Rational(25, 36) def test_issue_12564(): assert limit(x**2 + x*sin(x) + cos(x), x, -oo) is oo assert limit(x**2 + x*sin(x) + cos(x), x, oo) is oo assert limit(((x + cos(x))**2).expand(), x, oo) is oo assert limit(((x + sin(x))**2).expand(), x, oo) is oo assert limit(((x + cos(x))**2).expand(), x, -oo) is oo assert limit(((x + sin(x))**2).expand(), x, -oo) is oo def test_issue_14456(): raises(NotImplementedError, lambda: Limit(exp(x), x, zoo).doit()) raises(NotImplementedError, lambda: Limit(x**2/(x+1), x, zoo).doit()) def test_issue_14411(): assert limit(3*sec(4*pi*x - x/3), x, 3*pi/(24*pi - 2)) is -oo def test_issue_13382(): assert limit(x*(((x + 1)**2 + 1)/(x**2 + 1) - 1), x, oo) == 2 def test_issue_13403(): assert limit(x*(-1 + (x + log(x + 1) + 1)/(x + log(x))), x ,oo) == 1 def test_issue_13416(): assert limit((-x**3*log(x)**3 + (x - 1)*(x + 1)**2*log(x + 1)**3)/(x**2*log(x)**3), x ,oo) == 1 def test_issue_13462(): assert limit(n**2*(2*n*(-(1 - 1/(2*n))**x + 1) - x - (-x**2/4 + x/4)/n), n, oo) == x**3/24 - x**2/8 + x/12 def test_issue_13750(): a = Symbol('a') assert limit(erf(a - x), x, oo) == -1 assert limit(erf(sqrt(x) - x), x, oo) == -1 def test_issue_14514(): assert limit((1/(log(x)**log(x)))**(1/x), x, oo) == 1 def test_issue_14574(): assert limit(sqrt(x)*cos(x - x**2) / (x + 1), x, oo) == 0 def test_issue_10102(): assert limit(fresnels(x), x, oo) == S.Half assert limit(3 + fresnels(x), x, oo) == 3 + S.Half assert limit(5*fresnels(x), x, oo) == Rational(5, 2) assert limit(fresnelc(x), x, oo) == S.Half assert limit(fresnels(x), x, -oo) == Rational(-1, 2) assert limit(4*fresnelc(x), x, -oo) == -2 def test_issue_14377(): raises(NotImplementedError, lambda: limit(exp(I*x)*sin(pi*x), x, oo)) def test_issue_15146(): e = (x/2) * (-2*x**3 - 2*(x**3 - 1) * x**2 * digamma(x**3 + 1) + \ 2*(x**3 - 1) * x**2 * digamma(x**3 + x + 1) + x + 3) assert limit(e, x, oo) == S(1)/3 def test_issue_15202(): e = (2**x*(2 + 2**(-x)*(-2*2**x + x + 2))/(x + 1))**(x + 1) assert limit(e, x, oo) == exp(1) e = (log(x, 2)**7 + 10*x*factorial(x) + 5**x) / (factorial(x + 1) + 3*factorial(x) + 10**x) assert limit(e, x, oo) == 10 def test_issue_15282(): assert limit((x**2000 - (x + 1)**2000) / x**1999, x, oo) == -2000 def test_issue_15984(): assert limit((-x + log(exp(x) + 1))/x, x, oo, dir='-') == 0 def test_issue_13571(): assert limit(uppergamma(x, 1) / gamma(x), x, oo) == 1 def test_issue_13575(): assert limit(acos(erfi(x)), x, 1) == acos(erfi(S.One)) def test_issue_17325(): assert Limit(sin(x)/x, x, 0, dir="+-").doit() == 1 assert Limit(x**2, x, 0, dir="+-").doit() == 0 assert Limit(1/x**2, x, 0, dir="+-").doit() is oo assert Limit(1/x, x, 0, dir="+-").doit() is zoo def test_issue_10978(): assert LambertW(x).limit(x, 0) == 0 def test_issue_14313_comment(): assert limit(floor(n/2), n, oo) is oo @XFAIL def test_issue_15323(): d = ((1 - 1/x)**x).diff(x) assert limit(d, x, 1, dir='+') == 1 def test_issue_12571(): assert limit(-LambertW(-log(x))/log(x), x, 1) == 1 def test_issue_14590(): assert limit((x**3*((x + 1)/x)**x)/((x + 1)*(x + 2)*(x + 3)), x, oo) == exp(1) def test_issue_14393(): a, b = symbols('a b') assert limit((x**b - y**b)/(x**a - y**a), x, y) == b*y**(-a + b)/a def test_issue_14556(): assert limit(factorial(n + 1)**(1/(n + 1)) - factorial(n)**(1/n), n, oo) == exp(-1) def test_issue_14811(): assert limit(((1 + ((S(2)/3)**(x + 1)))**(2**x))/(2**((S(4)/3)**(x - 1))), x, oo) == oo def test_issue_14874(): assert limit(besselk(0, x), x, oo) == 0 def test_issue_16222(): assert limit(exp(x), x, 1000000000) == exp(1000000000) def test_issue_16714(): assert limit(((x**(x + 1) + (x + 1)**x) / x**(x + 1))**x, x, oo) == exp(exp(1)) def test_issue_16722(): z = symbols('z', positive=True) assert limit(binomial(n + z, n)*n**-z, n, oo) == 1/gamma(z + 1) z = symbols('z', positive=True, integer=True) assert limit(binomial(n + z, n)*n**-z, n, oo) == 1/gamma(z + 1) def test_issue_17431(): assert limit(((n + 1) + 1) / (((n + 1) + 2) * factorial(n + 1)) * (n + 2) * factorial(n) / (n + 1), n, oo) == 0 assert limit((n + 2)**2*factorial(n)/((n + 1)*(n + 3)*factorial(n + 1)) , n, oo) == 0 assert limit((n + 1) * factorial(n) / (n * factorial(n + 1)), n, oo) == 0 def test_issue_17671(): assert limit(Ei(-log(x)) - log(log(x))/x, x, 1) == EulerGamma def test_issue_17751(): a, b, c, x = symbols('a b c x', positive=True) assert limit((a + 1)*x - sqrt((a + 1)**2*x**2 + b*x + c), x, oo) == -b/(2*a + 2) def test_issue_17792(): assert limit(factorial(n)/sqrt(n)*(exp(1)/n)**n, n, oo) == sqrt(2)*sqrt(pi) def test_issue_18118(): assert limit(sign(sin(x)), x, 0, "-") == -1 assert limit(sign(sin(x)), x, 0, "+") == 1 def test_issue_18306(): assert limit(sin(sqrt(x))/sqrt(sin(x)), x, 0, '+') == 1 def test_issue_18378(): assert limit(log(exp(3*x) + x)/log(exp(x) + x**100), x, oo) == 3 def test_issue_18399(): assert limit((1 - S(1)/2*x)**(3*x), x, oo) is zoo assert limit((-x)**x, x, oo) is zoo def test_issue_18442(): assert limit(tan(x)**(2**(sqrt(pi))), x, oo, dir='-') == Limit(tan(x)**(2**(sqrt(pi))), x, oo, dir='-') def test_issue_18452(): assert limit(abs(log(x))**x, x, 0) == 1 assert limit(abs(log(x))**x, x, 0, "-") == 1 def test_issue_18482(): assert limit((2*exp(3*x)/(exp(2*x) + 1))**(1/x), x, oo) == exp(1) def test_issue_18508(): assert limit(sin(x)/sqrt(1-cos(x)), x, 0) == sqrt(2) assert limit(sin(x)/sqrt(1-cos(x)), x, 0, dir='+') == sqrt(2) assert limit(sin(x)/sqrt(1-cos(x)), x, 0, dir='-') == -sqrt(2) def test_issue_18969(): a, b = symbols('a b', positive=True) assert limit(LambertW(a), a, b) == LambertW(b) assert limit(exp(LambertW(a)), a, b) == exp(LambertW(b)) def test_issue_18992(): assert limit(n/(factorial(n)**(1/n)), n, oo) == exp(1) def test_issue_19067(): x = Symbol('x') assert limit(gamma(x)/(gamma(x - 1)*gamma(x + 2)), x, 0) == -1 def test_issue_19586(): assert limit(x**(2**x*3**(-x)), x, oo) == 1 def test_issue_13715(): n = Symbol('n') p = Symbol('p', zero=True) assert limit(n + p, n, 0) == 0 def test_issue_15055(): assert limit(n**3*((-n - 1)*sin(1/n) + (n + 2)*sin(1/(n + 1)))/(-n + 1), n, oo) == 1 def test_issue_16708(): m, vi = symbols('m vi', positive=True) B, ti, d = symbols('B ti d') assert limit((B*ti*vi - sqrt(m)*sqrt(-2*B*d*vi + m*(vi)**2) + m*vi)/(B*vi), B, 0) == (d + ti*vi)/vi def test_issue_19739(): assert limit((-S(1)/4)**x, x, oo) == 0 def test_issue_19766(): assert limit(2**(-x)*sqrt(4**(x + 1) + 1), x, oo) == 2 def test_issue_19770(): m = Symbol('m') # the result is not 0 for non-real m assert limit(cos(m*x)/x, x, oo) == Limit(cos(m*x)/x, x, oo, dir='-') m = Symbol('m', real=True) # can be improved to give the correct result 0 assert limit(cos(m*x)/x, x, oo) == Limit(cos(m*x)/x, x, oo, dir='-') m = Symbol('m', nonzero=True) assert limit(cos(m*x), x, oo) == AccumBounds(-1, 1) assert limit(cos(m*x)/x, x, oo) == 0 def test_issue_7535(): assert limit(tan(x)/sin(tan(x)), x, pi/2) == Limit(tan(x)/sin(tan(x)), x, pi/2, dir='+') assert limit(tan(x)/sin(tan(x)), x, pi/2, dir='-') == Limit(tan(x)/sin(tan(x)), x, pi/2, dir='-') assert limit(tan(x)/sin(tan(x)), x, pi/2, dir='+-') == Limit(tan(x)/sin(tan(x)), x, pi/2, dir='+-') assert limit(sin(tan(x)),x,pi/2) == AccumBounds(-1, 1) assert -oo*(1/sin(-oo)) == AccumBounds(-oo, oo) assert oo*(1/sin(oo)) == AccumBounds(-oo, oo) assert oo*(1/sin(-oo)) == AccumBounds(-oo, oo) assert -oo*(1/sin(oo)) == AccumBounds(-oo, oo) def test_issue_20365(): assert limit(((x + 1)**(1/x) - E)/x, x, 0) == -E/2 def test_issue_21031(): assert limit(((1 + x)**(1/x) - (1 + 2*x)**(1/(2*x)))/asin(x), x, 0) == E/2 def test_issue_21038(): assert limit(sin(pi*x)/(3*x - 12), x, 4) == pi/3 def test_issue_20578(): expr = abs(x) * sin(1/x) assert limit(expr,x,0,'+') == 0 assert limit(expr,x,0,'-') == 0 assert limit(expr,x,0,'+-') == 0 def test_issue_21415(): exp = (x-1)*cos(1/(x-1)) assert exp.limit(x,1) == 0 assert exp.expand().limit(x,1) == 0 def test_issue_21530(): assert limit(sinh(n + 1)/sinh(n), n, oo) == E def test_issue_21550(): r = (sqrt(5) - 1)/2 assert limit((x - r)/(x**2 + x - 1), x, r) == sqrt(5)/5 def test_issue_21661(): out = limit((x**(x + 1) * (log(x) + 1) + 1) / x, x, 11) assert out == S(3138428376722)/11 + 285311670611*log(11) def test_issue_21701(): assert limit((besselj(z, x)/x**z).subs(z, 7), x, 0) == S(1)/645120 def test_issue_21721(): a = Symbol('a', real=True) I = integrate(1/(pi*(1 + (x - a)**2)), x) assert I.limit(x, oo) == S.Half def test_issue_21756(): term = (1 - exp(-2*I*pi*z))/(1 - exp(-2*I*pi*z/5)) assert term.limit(z, 0) == 5 assert re(term).limit(z, 0) == 5 def test_issue_21785(): a = Symbol('a') assert sqrt((-a**2 + x**2)/(1 - x**2)).limit(a, 1, '-') == I sympy-sympy-1.9/sympy/series/tests/test_limitseq.py000066400000000000000000000116711412543434000230060ustar00rootroot00000000000000from sympy import (symbols, Symbol, oo, Sum, harmonic, exp, Add, S, binomial, factorial, log, fibonacci, subfactorial, sin, cos, pi, I, sqrt, Rational, gamma) from sympy.series.limitseq import limit_seq from sympy.series.limitseq import difference_delta as dd from sympy.testing.pytest import raises, XFAIL from sympy.calculus.util import AccumulationBounds n, m, k = symbols('n m k', integer=True) def test_difference_delta(): e = n*(n + 1) e2 = e * k assert dd(e) == 2*n + 2 assert dd(e2, n, 2) == k*(4*n + 6) raises(ValueError, lambda: dd(e2)) raises(ValueError, lambda: dd(e2, n, oo)) def test_difference_delta__Sum(): e = Sum(1/k, (k, 1, n)) assert dd(e, n) == 1/(n + 1) assert dd(e, n, 5) == Add(*[1/(i + n + 1) for i in range(5)]) e = Sum(1/k, (k, 1, 3*n)) assert dd(e, n) == Add(*[1/(i + 3*n + 1) for i in range(3)]) e = n * Sum(1/k, (k, 1, n)) assert dd(e, n) == 1 + Sum(1/k, (k, 1, n)) e = Sum(1/k, (k, 1, n), (m, 1, n)) assert dd(e, n) == harmonic(n) def test_difference_delta__Add(): e = n + n*(n + 1) assert dd(e, n) == 2*n + 3 assert dd(e, n, 2) == 4*n + 8 e = n + Sum(1/k, (k, 1, n)) assert dd(e, n) == 1 + 1/(n + 1) assert dd(e, n, 5) == 5 + Add(*[1/(i + n + 1) for i in range(5)]) def test_difference_delta__Pow(): e = 4**n assert dd(e, n) == 3*4**n assert dd(e, n, 2) == 15*4**n e = 4**(2*n) assert dd(e, n) == 15*4**(2*n) assert dd(e, n, 2) == 255*4**(2*n) e = n**4 assert dd(e, n) == (n + 1)**4 - n**4 e = n**n assert dd(e, n) == (n + 1)**(n + 1) - n**n def test_limit_seq(): e = binomial(2*n, n) / Sum(binomial(2*k, k), (k, 1, n)) assert limit_seq(e) == S(3) / 4 assert limit_seq(e, m) == e e = (5*n**3 + 3*n**2 + 4) / (3*n**3 + 4*n - 5) assert limit_seq(e, n) == S(5) / 3 e = (harmonic(n) * Sum(harmonic(k), (k, 1, n))) / (n * harmonic(2*n)**2) assert limit_seq(e, n) == 1 e = Sum(k**2 * Sum(2**m/m, (m, 1, k)), (k, 1, n)) / (2**n*n) assert limit_seq(e, n) == 4 e = (Sum(binomial(3*k, k) * binomial(5*k, k), (k, 1, n)) / (binomial(3*n, n) * binomial(5*n, n))) assert limit_seq(e, n) == S(84375) / 83351 e = Sum(harmonic(k)**2/k, (k, 1, 2*n)) / harmonic(n)**3 assert limit_seq(e, n) == S.One / 3 raises(ValueError, lambda: limit_seq(e * m)) def test_alternating_sign(): assert limit_seq((-1)**n/n**2, n) == 0 assert limit_seq((-2)**(n+1)/(n + 3**n), n) == 0 assert limit_seq((2*n + (-1)**n)/(n + 1), n) == 2 assert limit_seq(sin(pi*n), n) == 0 assert limit_seq(cos(2*pi*n), n) == 1 assert limit_seq((S.NegativeOne/5)**n, n) == 0 assert limit_seq((Rational(-1, 5))**n, n) == 0 assert limit_seq((I/3)**n, n) == 0 assert limit_seq(sqrt(n)*(I/2)**n, n) == 0 assert limit_seq(n**7*(I/3)**n, n) == 0 assert limit_seq(n/(n + 1) + (I/2)**n, n) == 1 def test_accum_bounds(): assert limit_seq((-1)**n, n) == AccumulationBounds(-1, 1) assert limit_seq(cos(pi*n), n) == AccumulationBounds(-1, 1) assert limit_seq(sin(pi*n/2)**2, n) == AccumulationBounds(0, 1) assert limit_seq(2*(-3)**n/(n + 3**n), n) == AccumulationBounds(-2, 2) assert limit_seq(3*n/(n + 1) + 2*(-1)**n, n) == AccumulationBounds(1, 5) def test_limitseq_sum(): from sympy.abc import x, y, z assert limit_seq(Sum(1/x, (x, 1, y)) - log(y), y) == S.EulerGamma assert limit_seq(Sum(1/x, (x, 1, y)) - 1/y, y) is S.Infinity assert (limit_seq(binomial(2*x, x) / Sum(binomial(2*y, y), (y, 1, x)), x) == S(3) / 4) assert (limit_seq(Sum(y**2 * Sum(2**z/z, (z, 1, y)), (y, 1, x)) / (2**x*x), x) == 4) def test_issue_9308(): assert limit_seq(subfactorial(n)/factorial(n), n) == exp(-1) def test_issue_10382(): n = Symbol('n', integer=True) assert limit_seq(fibonacci(n+1)/fibonacci(n), n) == S.GoldenRatio def test_issue_11672(): assert limit_seq(Rational(-1, 2)**n, n) == 0 def test_issue_16735(): assert limit_seq(5**n/factorial(n), n) == 0 def test_issue_19868(): assert limit_seq(1/gamma(n + S.One/2), n) == 0 @XFAIL def test_limit_seq_fail(): # improve Summation algorithm or add ad-hoc criteria e = (harmonic(n)**3 * Sum(1/harmonic(k), (k, 1, n)) / (n * Sum(harmonic(k)/k, (k, 1, n)))) assert limit_seq(e, n) == 2 # No unique dominant term e = (Sum(2**k * binomial(2*k, k) / k**2, (k, 1, n)) / (Sum(2**k/k*2, (k, 1, n)) * Sum(binomial(2*k, k), (k, 1, n)))) assert limit_seq(e, n) == S(3) / 7 # Simplifications of summations needs to be improved. e = n**3*Sum(2**k/k**2, (k, 1, n))**2 / (2**n * Sum(2**k/k, (k, 1, n))) assert limit_seq(e, n) == 2 e = (harmonic(n) * Sum(2**k/k, (k, 1, n)) / (n * Sum(2**k*harmonic(k)/k**2, (k, 1, n)))) assert limit_seq(e, n) == 1 e = (Sum(2**k*factorial(k) / k**2, (k, 1, 2*n)) / (Sum(4**k/k**2, (k, 1, n)) * Sum(factorial(k), (k, 1, 2*n)))) assert limit_seq(e, n) == S(3) / 16 sympy-sympy-1.9/sympy/series/tests/test_lseries.py000066400000000000000000000032061412543434000226200ustar00rootroot00000000000000from sympy import sin, cos, exp, tanh, E, S, Order from sympy.abc import x, y def test_sin(): e = sin(x).lseries(x) assert next(e) == x assert next(e) == -x**3/6 assert next(e) == x**5/120 def test_cos(): e = cos(x).lseries(x) assert next(e) == 1 assert next(e) == -x**2/2 assert next(e) == x**4/24 def test_exp(): e = exp(x).lseries(x) assert next(e) == 1 assert next(e) == x assert next(e) == x**2/2 assert next(e) == x**3/6 def test_exp2(): e = exp(cos(x)).lseries(x) assert next(e) == E assert next(e) == -E*x**2/2 assert next(e) == E*x**4/6 assert next(e) == -31*E*x**6/720 def test_simple(): assert [t for t in x.lseries()] == [x] assert [t for t in S.One.lseries(x)] == [1] assert not next((x/(x + y)).lseries(y)).has(Order) def test_issue_5183(): s = (x + 1/x).lseries() assert [si for si in s] == [1/x, x] assert next((x + x**2).lseries()) == x assert next(((1 + x)**7).lseries(x)) == 1 assert next((sin(x + y)).series(x, n=3).lseries(y)) == x # it would be nice if all terms were grouped, but in the # following case that would mean that all the terms would have # to be known since, for example, every term has a constant in it. s = ((1 + x)**7).series(x, 1, n=None) assert [next(s) for i in range(2)] == [128, -448 + 448*x] def test_issue_6999(): s = tanh(x).lseries(x, 1) assert next(s) == tanh(1) assert next(s) == x - (x - 1)*tanh(1)**2 - 1 assert next(s) == -(x - 1)**2*tanh(1) + (x - 1)**2*tanh(1)**3 assert next(s) == -(x - 1)**3*tanh(1)**4 - (x - 1)**3/3 + \ 4*(x - 1)**3*tanh(1)**2/3 sympy-sympy-1.9/sympy/series/tests/test_nseries.py000066400000000000000000000405231412543434000226250ustar00rootroot00000000000000from sympy import (Symbol, Rational, ln, exp, log, sqrt, E, O, pi, I, sinh, sin, cosh, cos, tanh, coth, asinh, acosh, atanh, acoth, tan, cot, Integer, PoleError, floor, ceiling, asin, symbols, limit, sign, cbrt, Derivative, S) from sympy.abc import x, y, z from sympy.testing.pytest import raises, XFAIL def test_simple_1(): assert x.nseries(x, n=5) == x assert y.nseries(x, n=5) == y assert (1/(x*y)).nseries(y, n=5) == 1/(x*y) assert Rational(3, 4).nseries(x, n=5) == Rational(3, 4) assert x.nseries() == x def test_mul_0(): assert (x*ln(x)).nseries(x, n=5) == x*ln(x) def test_mul_1(): assert (x*ln(2 + x)).nseries(x, n=5) == x*log(2) + x**2/2 - x**3/8 + \ x**4/24 + O(x**5) assert (x*ln(1 + x)).nseries( x, n=5) == x**2 - x**3/2 + x**4/3 + O(x**5) def test_pow_0(): assert (x**2).nseries(x, n=5) == x**2 assert (1/x).nseries(x, n=5) == 1/x assert (1/x**2).nseries(x, n=5) == 1/x**2 assert (x**Rational(2, 3)).nseries(x, n=5) == (x**Rational(2, 3)) assert (sqrt(x)**3).nseries(x, n=5) == (sqrt(x)**3) def test_pow_1(): assert ((1 + x)**2).nseries(x, n=5) == x**2 + 2*x + 1 # https://github.com/sympy/sympy/issues/21075 assert ((sqrt(x) + 1)**2).nseries(x) == 2*sqrt(x) + x + 1 assert ((sqrt(x) + cbrt(x))**2).nseries(x) == 2*x**Rational(5, 6)\ + x**Rational(2, 3) + x def test_geometric_1(): assert (1/(1 - x)).nseries(x, n=5) == 1 + x + x**2 + x**3 + x**4 + O(x**5) assert (x/(1 - x)).nseries(x, n=6) == x + x**2 + x**3 + x**4 + x**5 + O(x**6) assert (x**3/(1 - x)).nseries(x, n=8) == x**3 + x**4 + x**5 + x**6 + \ x**7 + O(x**8) def test_sqrt_1(): assert sqrt(1 + x).nseries(x, n=5) == 1 + x/2 - x**2/8 + x**3/16 - 5*x**4/128 + O(x**5) def test_exp_1(): assert exp(x).nseries(x, n=5) == 1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5) assert exp(x).nseries(x, n=12) == 1 + x + x**2/2 + x**3/6 + x**4/24 + x**5/120 + \ x**6/720 + x**7/5040 + x**8/40320 + x**9/362880 + x**10/3628800 + \ x**11/39916800 + O(x**12) assert exp(1/x).nseries(x, n=5) == exp(1/x) assert exp(1/(1 + x)).nseries(x, n=4) == \ (E*(1 - x - 13*x**3/6 + 3*x**2/2)).expand() + O(x**4) assert exp(2 + x).nseries(x, n=5) == \ (exp(2)*(1 + x + x**2/2 + x**3/6 + x**4/24)).expand() + O(x**5) def test_exp_sqrt_1(): assert exp(1 + sqrt(x)).nseries(x, n=3) == \ (exp(1)*(1 + sqrt(x) + x/2 + sqrt(x)*x/6)).expand() + O(sqrt(x)**3) def test_power_x_x1(): assert (exp(x*ln(x))).nseries(x, n=4) == \ 1 + x*log(x) + x**2*log(x)**2/2 + x**3*log(x)**3/6 + O(x**4*log(x)**4) def test_power_x_x2(): assert (x**x).nseries(x, n=4) == \ 1 + x*log(x) + x**2*log(x)**2/2 + x**3*log(x)**3/6 + O(x**4*log(x)**4) def test_log_singular1(): assert log(1 + 1/x).nseries(x, n=5) == x - log(x) - x**2/2 + x**3/3 - \ x**4/4 + O(x**5) def test_log_power1(): e = 1 / (1/x + x ** (log(3)/log(2))) assert e.nseries(x, n=5) == -x**(log(3)/log(2) + 2) + x + O(x**5) def test_log_series(): l = Symbol('l') e = 1/(1 - log(x)) assert e.nseries(x, n=5, logx=l) == 1/(1 - l) def test_log2(): e = log(-1/x) assert e.nseries(x, n=5) == -log(x) + log(-1) def test_log3(): l = Symbol('l') e = 1/log(-1/x) assert e.nseries(x, n=4, logx=l) == 1/(-l + log(-1)) def test_series1(): e = sin(x) assert e.nseries(x, 0, 0) != 0 assert e.nseries(x, 0, 0) == O(1, x) assert e.nseries(x, 0, 1) == O(x, x) assert e.nseries(x, 0, 2) == x + O(x**2, x) assert e.nseries(x, 0, 3) == x + O(x**3, x) assert e.nseries(x, 0, 4) == x - x**3/6 + O(x**4, x) e = (exp(x) - 1)/x assert e.nseries(x, 0, 3) == 1 + x/2 + x**2/6 + O(x**3) assert x.nseries(x, 0, 2) == x @XFAIL def test_series1_failing(): assert x.nseries(x, 0, 0) == O(1, x) assert x.nseries(x, 0, 1) == O(x, x) def test_seriesbug1(): assert (1/x).nseries(x, 0, 3) == 1/x assert (x + 1/x).nseries(x, 0, 3) == x + 1/x def test_series2x(): assert ((x + 1)**(-2)).nseries(x, 0, 4) == 1 - 2*x + 3*x**2 - 4*x**3 + O(x**4, x) assert ((x + 1)**(-1)).nseries(x, 0, 4) == 1 - x + x**2 - x**3 + O(x**4, x) assert ((x + 1)**0).nseries(x, 0, 3) == 1 assert ((x + 1)**1).nseries(x, 0, 3) == 1 + x assert ((x + 1)**2).nseries(x, 0, 3) == x**2 + 2*x + 1 assert ((x + 1)**3).nseries(x, 0, 3) == 1 + 3*x + 3*x**2 + O(x**3) assert (1/(1 + x)).nseries(x, 0, 4) == 1 - x + x**2 - x**3 + O(x**4, x) assert (x + 3/(1 + 2*x)).nseries(x, 0, 4) == 3 - 5*x + 12*x**2 - 24*x**3 + O(x**4, x) assert ((1/x + 1)**3).nseries(x, 0, 3) == 1 + 3/x + 3/x**2 + x**(-3) assert (1/(1 + 1/x)).nseries(x, 0, 4) == x - x**2 + x**3 - O(x**4, x) assert (1/(1 + 1/x**2)).nseries(x, 0, 6) == x**2 - x**4 + O(x**6, x) def test_bug2(): # 1/log(0)*log(0) problem w = Symbol("w") e = (w**(-1) + w**( -log(3)*log(2)**(-1)))**(-1)*(3*w**(-log(3)*log(2)**(-1)) + 2*w**(-1)) e = e.expand() assert e.nseries(w, 0, 4).subs(w, 0) == 3 def test_exp(): e = (1 + x)**(1/x) assert e.nseries(x, n=3) == exp(1) - x*exp(1)/2 + 11*exp(1)*x**2/24 + O(x**3) def test_exp2(): w = Symbol("w") e = w**(1 - log(x)/(log(2) + log(x))) logw = Symbol("logw") assert e.nseries( w, 0, 1, logx=logw) == exp(logw*log(2)/(log(x) + log(2))) def test_bug3(): e = (2/x + 3/x**2)/(1/x + 1/x**2) assert e.nseries(x, n=3) == 3 - x + x**2 + O(x**3) def test_generalexponent(): p = 2 e = (2/x + 3/x**p)/(1/x + 1/x**p) assert e.nseries(x, 0, 3) == 3 - x + x**2 + O(x**3) p = S.Half e = (2/x + 3/x**p)/(1/x + 1/x**p) assert e.nseries(x, 0, 2) == 2 - x + sqrt(x) + x**(S(3)/2) + O(x**2) e = 1 + sqrt(x) assert e.nseries(x, 0, 4) == 1 + sqrt(x) # more complicated example def test_genexp_x(): e = 1/(1 + sqrt(x)) assert e.nseries(x, 0, 2) == \ 1 + x - sqrt(x) - sqrt(x)**3 + O(x**2, x) # more complicated example def test_genexp_x2(): p = Rational(3, 2) e = (2/x + 3/x**p)/(1/x + 1/x**p) assert e.nseries(x, 0, 3) == 3 + x + x**2 - sqrt(x) - x**(S(3)/2) - x**(S(5)/2) + O(x**3) def test_seriesbug2(): w = Symbol("w") #simple case (1): e = ((2*w)/w)**(1 + w) assert e.nseries(w, 0, 1) == 2 + O(w, w) assert e.nseries(w, 0, 1).subs(w, 0) == 2 def test_seriesbug2b(): w = Symbol("w") #test sin e = sin(2*w)/w assert e.nseries(w, 0, 3) == 2 - 4*w**2/3 + O(w**3) def test_seriesbug2d(): w = Symbol("w", real=True) e = log(sin(2*w)/w) assert e.series(w, n=5) == log(2) - 2*w**2/3 - 4*w**4/45 + O(w**5) def test_seriesbug2c(): w = Symbol("w", real=True) #more complicated case, but sin(x)~x, so the result is the same as in (1) e = (sin(2*w)/w)**(1 + w) assert e.series(w, 0, 1) == 2 + O(w) assert e.series(w, 0, 3) == 2 + 2*w*log(2) + \ w**2*(Rational(-4, 3) + log(2)**2) + O(w**3) assert e.series(w, 0, 2).subs(w, 0) == 2 def test_expbug4(): x = Symbol("x", real=True) assert (log( sin(2*x)/x)*(1 + x)).series(x, 0, 2) == log(2) + x*log(2) + O(x**2, x) assert exp( log(sin(2*x)/x)*(1 + x)).series(x, 0, 2) == 2 + 2*x*log(2) + O(x**2) assert exp(log(2) + O(x)).nseries(x, 0, 2) == 2 + O(x) assert ((2 + O(x))**(1 + x)).nseries(x, 0, 2) == 2 + O(x) def test_logbug4(): assert log(2 + O(x)).nseries(x, 0, 2) == log(2) + O(x, x) def test_expbug5(): assert exp(log(1 + x)/x).nseries(x, n=3) == exp(1) + -exp(1)*x/2 + 11*exp(1)*x**2/24 + O(x**3) assert exp(O(x)).nseries(x, 0, 2) == 1 + O(x) def test_sinsinbug(): assert sin(sin(x)).nseries(x, 0, 8) == x - x**3/3 + x**5/10 - 8*x**7/315 + O(x**8) def test_issue_3258(): a = x/(exp(x) - 1) assert a.nseries(x, 0, 5) == 1 - x/2 - x**4/720 + x**2/12 + O(x**5) def test_issue_3204(): x = Symbol("x", nonnegative=True) f = sin(x**3)**Rational(1, 3) assert f.nseries(x, 0, 17) == x - x**7/18 - x**13/3240 + O(x**17) def test_issue_3224(): f = sqrt(1 - sqrt(y)) assert f.nseries(y, 0, 2) == 1 - sqrt(y)/2 - y/8 - sqrt(y)**3/16 + O(y**2) def test_issue_3463(): from sympy import symbols w, i = symbols('w,i') r = log(5)/log(3) p = w**(-1 + r) e = 1/x*(-log(w**(1 + r)) + log(w + w**r)) e_ser = -r*log(w)/x + p/x - p**2/(2*x) + O(w) assert e.nseries(w, n=1) == e_ser def test_sin(): assert sin(8*x).nseries(x, n=4) == 8*x - 256*x**3/3 + O(x**4) assert sin(x + y).nseries(x, n=1) == sin(y) + O(x) assert sin(x + y).nseries(x, n=2) == sin(y) + cos(y)*x + O(x**2) assert sin(x + y).nseries(x, n=5) == sin(y) + cos(y)*x - sin(y)*x**2/2 - \ cos(y)*x**3/6 + sin(y)*x**4/24 + O(x**5) def test_issue_3515(): e = sin(8*x)/x assert e.nseries(x, n=6) == 8 - 256*x**2/3 + 4096*x**4/15 + O(x**6) def test_issue_3505(): e = sin(x)**(-4)*(sqrt(cos(x))*sin(x)**2 - cos(x)**Rational(1, 3)*sin(x)**2) assert e.nseries(x, n=9) == Rational(-1, 12) - 7*x**2/288 - \ 43*x**4/10368 - 1123*x**6/2488320 + 377*x**8/29859840 + O(x**9) def test_issue_3501(): a = Symbol("a") e = x**(-2)*(x*sin(a + x) - x*sin(a)) assert e.nseries(x, n=6) == cos(a) - sin(a)*x/2 - cos(a)*x**2/6 + \ x**3*sin(a)/24 + x**4*cos(a)/120 - x**5*sin(a)/720 + O(x**6) e = x**(-2)*(x*cos(a + x) - x*cos(a)) assert e.nseries(x, n=6) == -sin(a) - cos(a)*x/2 + sin(a)*x**2/6 + \ cos(a)*x**3/24 - x**4*sin(a)/120 - x**5*cos(a)/720 + O(x**6) def test_issue_3502(): e = sin(5*x)/sin(2*x) assert e.nseries(x, n=2) == Rational(5, 2) + O(x**2) assert e.nseries(x, n=6) == \ Rational(5, 2) - 35*x**2/4 + 329*x**4/48 + O(x**6) def test_issue_3503(): e = sin(2 + x)/(2 + x) assert e.nseries(x, n=2) == sin(2)/2 + x*cos(2)/2 - x*sin(2)/4 + O(x**2) def test_issue_3506(): e = (x + sin(3*x))**(-2)*(x*(x + sin(3*x)) - (x + sin(3*x))*sin(2*x)) assert e.nseries(x, n=7) == \ Rational(-1, 4) + 5*x**2/96 + 91*x**4/768 + 11117*x**6/129024 + O(x**7) def test_issue_3508(): x = Symbol("x", real=True) assert log(sin(x)).series(x, n=5) == log(x) - x**2/6 - x**4/180 + O(x**5) e = -log(x) + x*(-log(x) + log(sin(2*x))) + log(sin(2*x)) assert e.series(x, n=5) == \ log(2) + log(2)*x - 2*x**2/3 - 2*x**3/3 - 4*x**4/45 + O(x**5) def test_issue_3507(): e = x**(-4)*(x**2 - x**2*sqrt(cos(x))) assert e.nseries(x, n=9) == \ Rational(1, 4) + x**2/96 + 19*x**4/5760 + 559*x**6/645120 + 29161*x**8/116121600 + O(x**9) def test_issue_3639(): assert sin(cos(x)).nseries(x, n=5) == \ sin(1) - x**2*cos(1)/2 - x**4*sin(1)/8 + x**4*cos(1)/24 + O(x**5) def test_hyperbolic(): assert sinh(x).nseries(x, n=6) == x + x**3/6 + x**5/120 + O(x**6) assert cosh(x).nseries(x, n=5) == 1 + x**2/2 + x**4/24 + O(x**5) assert tanh(x).nseries(x, n=6) == x - x**3/3 + 2*x**5/15 + O(x**6) assert coth(x).nseries(x, n=6) == \ 1/x - x**3/45 + x/3 + 2*x**5/945 + O(x**6) assert asinh(x).nseries(x, n=6) == x - x**3/6 + 3*x**5/40 + O(x**6) assert acosh(x).nseries(x, n=6) == \ pi*I/2 - I*x - 3*I*x**5/40 - I*x**3/6 + O(x**6) assert atanh(x).nseries(x, n=6) == x + x**3/3 + x**5/5 + O(x**6) assert acoth(x).nseries(x, n=6) == x + x**3/3 + x**5/5 + pi*I/2 + O(x**6) def test_series2(): w = Symbol("w", real=True) x = Symbol("x", real=True) e = w**(-2)*(w*exp(1/x - w) - w*exp(1/x)) assert e.nseries(w, n=4) == -exp(1/x) + w*exp(1/x)/2 - w**2*exp(1/x)/6 + w**3*exp(1/x)/24 + O(w**4) def test_series3(): w = Symbol("w", real=True) e = w**(-6)*(w**3*tan(w) - w**3*sin(w)) assert e.nseries(w, n=8) == Integer(1)/2 + w**2/8 + 13*w**4/240 + 529*w**6/24192 + O(w**8) def test_bug4(): w = Symbol("w") e = x/(w**4 + x**2*w**4 + 2*x*w**4)*w**4 assert e.nseries(w, n=2).removeO().expand() in [x/(1 + 2*x + x**2), 1/(1 + x/2 + 1/x/2)/2, 1/x/(1 + 2/x + x**(-2))] def test_bug5(): w = Symbol("w") l = Symbol('l') e = (-log(w) + log(1 + w*log(x)))**(-2)*w**(-2)*((-log(w) + log(1 + x*w))*(-log(w) + log(1 + w*log(x)))*w - x*(-log(w) + log(1 + w*log(x)))*w) assert e.nseries(w, n=0, logx=l) == x/w/l + 1/w + O(1, w) assert e.nseries(w, n=1, logx=l) == x/w/l + 1/w - x/l + 1/l*log(x) \ + x*log(x)/l**2 + O(w) def test_issue_4115(): assert (sin(x)/(1 - cos(x))).nseries(x, n=1) == 2/x + O(x) assert (sin(x)**2/(1 - cos(x))).nseries(x, n=1) == 2 + O(x) def test_pole(): raises(PoleError, lambda: sin(1/x).series(x, 0, 5)) raises(PoleError, lambda: sin(1 + 1/x).series(x, 0, 5)) raises(PoleError, lambda: (x*sin(1/x)).series(x, 0, 5)) def test_expsinbug(): assert exp(sin(x)).series(x, 0, 0) == O(1, x) assert exp(sin(x)).series(x, 0, 1) == 1 + O(x) assert exp(sin(x)).series(x, 0, 2) == 1 + x + O(x**2) assert exp(sin(x)).series(x, 0, 3) == 1 + x + x**2/2 + O(x**3) assert exp(sin(x)).series(x, 0, 4) == 1 + x + x**2/2 + O(x**4) assert exp(sin(x)).series(x, 0, 5) == 1 + x + x**2/2 - x**4/8 + O(x**5) def test_floor(): x = Symbol('x') assert floor(x).series(x) == 0 assert floor(-x).series(x) == -1 assert floor(sin(x)).series(x) == 0 assert floor(sin(-x)).series(x) == -1 assert floor(x**3).series(x) == 0 assert floor(-x**3).series(x) == -1 assert floor(cos(x)).series(x) == 0 assert floor(cos(-x)).series(x) == 0 assert floor(5 + sin(x)).series(x) == 5 assert floor(5 + sin(-x)).series(x) == 4 assert floor(x).series(x, 2) == 2 assert floor(-x).series(x, 2) == -3 x = Symbol('x', negative=True) assert floor(x + 1.5).series(x) == 1 def test_ceiling(): assert ceiling(x).series(x) == 1 assert ceiling(-x).series(x) == 0 assert ceiling(sin(x)).series(x) == 1 assert ceiling(sin(-x)).series(x) == 0 assert ceiling(1 - cos(x)).series(x) == 1 assert ceiling(1 - cos(-x)).series(x) == 1 assert ceiling(x).series(x, 2) == 3 assert ceiling(-x).series(x, 2) == -2 def test_abs(): a = Symbol('a') assert abs(x).nseries(x, n=4) == x assert abs(-x).nseries(x, n=4) == x assert abs(x + 1).nseries(x, n=4) == x + 1 assert abs(sin(x)).nseries(x, n=4) == x - Rational(1, 6)*x**3 + O(x**4) assert abs(sin(-x)).nseries(x, n=4) == x - Rational(1, 6)*x**3 + O(x**4) assert abs(x - a).nseries(x, 1) == -a*sign(1 - a) + (x - 1)*sign(1 - a) + sign(1 - a) def test_dir(): assert abs(x).series(x, 0, dir="+") == x assert abs(x).series(x, 0, dir="-") == -x assert floor(x + 2).series(x, 0, dir='+') == 2 assert floor(x + 2).series(x, 0, dir='-') == 1 assert floor(x + 2.2).series(x, 0, dir='-') == 2 assert ceiling(x + 2.2).series(x, 0, dir='-') == 3 assert sin(x + y).series(x, 0, dir='-') == sin(x + y).series(x, 0, dir='+') def test_issue_3504(): a = Symbol("a") e = asin(a*x)/x assert e.series(x, 4, n=2).removeO() == \ (x - 4)*(a/(4*sqrt(-16*a**2 + 1)) - asin(4*a)/16) + asin(4*a)/4 def test_issue_4441(): a, b = symbols('a,b') f = 1/(1 + a*x) assert f.series(x, 0, 5) == 1 - a*x + a**2*x**2 - a**3*x**3 + \ a**4*x**4 + O(x**5) f = 1/(1 + (a + b)*x) assert f.series(x, 0, 3) == 1 + x*(-a - b)\ + x**2*(a + b)**2 + O(x**3) def test_issue_4329(): assert tan(x).series(x, pi/2, n=3).removeO() == \ -pi/6 + x/3 - 1/(x - pi/2) assert cot(x).series(x, pi, n=3).removeO() == \ -x/3 + pi/3 + 1/(x - pi) assert limit(tan(x)**tan(2*x), x, pi/4) == exp(-1) def test_issue_5183(): assert abs(x + x**2).series(n=1) == O(x) assert abs(x + x**2).series(n=2) == x + O(x**2) assert ((1 + x)**2).series(x, n=6) == x**2 + 2*x + 1 assert (1 + 1/x).series() == 1 + 1/x assert Derivative(exp(x).series(), x).doit() == \ 1 + x + x**2/2 + x**3/6 + x**4/24 + O(x**5) def test_issue_5654(): a = Symbol('a') assert (1/(x**2+a**2)**2).nseries(x, x0=I*a, n=0) == \ -I/(4*a**3*(-I*a + x)) - 1/(4*a**2*(-I*a + x)**2) + O(1, (x, I*a)) assert (1/(x**2+a**2)**2).nseries(x, x0=I*a, n=1) == 3/(16*a**4) \ -I/(4*a**3*(-I*a + x)) - 1/(4*a**2*(-I*a + x)**2) + O(-I*a + x, (x, I*a)) def test_issue_5925(): sx = sqrt(x + z).series(z, 0, 1) sxy = sqrt(x + y + z).series(z, 0, 1) s1, s2 = sx.subs(x, x + y), sxy assert (s1 - s2).expand().removeO().simplify() == 0 sx = sqrt(x + z).series(z, 0, 1) sxy = sqrt(x + y + z).series(z, 0, 1) assert sxy.subs({x:1, y:2}) == sx.subs(x, 3) def test_exp_2(): assert exp(x**3).nseries(x, 0, 14) == 1 + x**3 + x**6/2 + x**9/6 + x**12/24 + O(x**14) sympy-sympy-1.9/sympy/series/tests/test_order.py000066400000000000000000000356311412543434000222740ustar00rootroot00000000000000from sympy import (Symbol, Rational, Order, exp, ln, log, nan, oo, O, pi, I, S, Integral, sin, cos, sqrt, conjugate, expand, transpose, symbols, Function, Add) from sympy.core.expr import unchanged from sympy.testing.pytest import raises from sympy.abc import w, x, y, z def test_caching_bug(): #needs to be a first test, so that all caches are clean #cache it O(w) #and test that this won't raise an exception O(w**(-1/x/log(3)*log(5)), w) def test_free_symbols(): assert Order(1).free_symbols == set() assert Order(x).free_symbols == {x} assert Order(1, x).free_symbols == {x} assert Order(x*y).free_symbols == {x, y} assert Order(x, x, y).free_symbols == {x, y} def test_simple_1(): o = Rational(0) assert Order(2*x) == Order(x) assert Order(x)*3 == Order(x) assert -28*Order(x) == Order(x) assert Order(Order(x)) == Order(x) assert Order(Order(x), y) == Order(Order(x), x, y) assert Order(-23) == Order(1) assert Order(exp(x)) == Order(1, x) assert Order(exp(1/x)).expr == exp(1/x) assert Order(x*exp(1/x)).expr == x*exp(1/x) assert Order(x**(o/3)).expr == x**(o/3) assert Order(x**(o*Rational(5, 3))).expr == x**(o*Rational(5, 3)) assert Order(x**2 + x + y, x) == O(1, x) assert Order(x**2 + x + y, y) == O(1, y) raises(ValueError, lambda: Order(exp(x), x, x)) raises(TypeError, lambda: Order(x, 2 - x)) def test_simple_2(): assert Order(2*x)*x == Order(x**2) assert Order(2*x)/x == Order(1, x) assert Order(2*x)*x*exp(1/x) == Order(x**2*exp(1/x)) assert (Order(2*x)*x*exp(1/x)/ln(x)**3).expr == x**2*exp(1/x)*ln(x)**-3 def test_simple_3(): assert Order(x) + x == Order(x) assert Order(x) + 2 == 2 + Order(x) assert Order(x) + x**2 == Order(x) assert Order(x) + 1/x == 1/x + Order(x) assert Order(1/x) + 1/x**2 == 1/x**2 + Order(1/x) assert Order(x) + exp(1/x) == Order(x) + exp(1/x) def test_simple_4(): assert Order(x)**2 == Order(x**2) def test_simple_5(): assert Order(x) + Order(x**2) == Order(x) assert Order(x) + Order(x**-2) == Order(x**-2) assert Order(x) + Order(1/x) == Order(1/x) def test_simple_6(): assert Order(x) - Order(x) == Order(x) assert Order(x) + Order(1) == Order(1) assert Order(x) + Order(x**2) == Order(x) assert Order(1/x) + Order(1) == Order(1/x) assert Order(x) + Order(exp(1/x)) == Order(exp(1/x)) assert Order(x**3) + Order(exp(2/x)) == Order(exp(2/x)) assert Order(x**-3) + Order(exp(2/x)) == Order(exp(2/x)) def test_simple_7(): assert 1 + O(1) == O(1) assert 2 + O(1) == O(1) assert x + O(1) == O(1) assert 1/x + O(1) == 1/x + O(1) def test_simple_8(): assert O(sqrt(-x)) == O(sqrt(x)) assert O(x**2*sqrt(x)) == O(x**Rational(5, 2)) assert O(x**3*sqrt(-(-x)**3)) == O(x**Rational(9, 2)) assert O(x**Rational(3, 2)*sqrt((-x)**3)) == O(x**3) assert O(x*(-2*x)**(I/2)) == O(x*(-x)**(I/2)) def test_as_expr_variables(): assert Order(x).as_expr_variables(None) == (x, ((x, 0),)) assert Order(x).as_expr_variables(((x, 0),)) == (x, ((x, 0),)) assert Order(y).as_expr_variables(((x, 0),)) == (y, ((x, 0), (y, 0))) assert Order(y).as_expr_variables(((x, 0), (y, 0))) == (y, ((x, 0), (y, 0))) def test_contains_0(): assert Order(1, x).contains(Order(1, x)) assert Order(1, x).contains(Order(1)) assert Order(1).contains(Order(1, x)) is False def test_contains_1(): assert Order(x).contains(Order(x)) assert Order(x).contains(Order(x**2)) assert not Order(x**2).contains(Order(x)) assert not Order(x).contains(Order(1/x)) assert not Order(1/x).contains(Order(exp(1/x))) assert not Order(x).contains(Order(exp(1/x))) assert Order(1/x).contains(Order(x)) assert Order(exp(1/x)).contains(Order(x)) assert Order(exp(1/x)).contains(Order(1/x)) assert Order(exp(1/x)).contains(Order(exp(1/x))) assert Order(exp(2/x)).contains(Order(exp(1/x))) assert not Order(exp(1/x)).contains(Order(exp(2/x))) def test_contains_2(): assert Order(x).contains(Order(y)) is None assert Order(x).contains(Order(y*x)) assert Order(y*x).contains(Order(x)) assert Order(y).contains(Order(x*y)) assert Order(x).contains(Order(y**2*x)) def test_contains_3(): assert Order(x*y**2).contains(Order(x**2*y)) is None assert Order(x**2*y).contains(Order(x*y**2)) is None def test_contains_4(): assert Order(sin(1/x**2)).contains(Order(cos(1/x**2))) is True assert Order(cos(1/x**2)).contains(Order(sin(1/x**2))) is True def test_contains(): assert Order(1, x) not in Order(1) assert Order(1) in Order(1, x) raises(TypeError, lambda: Order(x*y**2) in Order(x**2*y)) def test_add_1(): assert Order(x + x) == Order(x) assert Order(3*x - 2*x**2) == Order(x) assert Order(1 + x) == Order(1, x) assert Order(1 + 1/x) == Order(1/x) assert Order(ln(x) + 1/ln(x)) == Order(ln(x)) assert Order(exp(1/x) + x) == Order(exp(1/x)) assert Order(exp(1/x) + 1/x**20) == Order(exp(1/x)) def test_ln_args(): assert O(log(x)) + O(log(2*x)) == O(log(x)) assert O(log(x)) + O(log(x**3)) == O(log(x)) assert O(log(x*y)) + O(log(x) + log(y)) == O(log(x*y)) def test_multivar_0(): assert Order(x*y).expr == x*y assert Order(x*y**2).expr == x*y**2 assert Order(x*y, x).expr == x assert Order(x*y**2, y).expr == y**2 assert Order(x*y*z).expr == x*y*z assert Order(x/y).expr == x/y assert Order(x*exp(1/y)).expr == x*exp(1/y) assert Order(exp(x)*exp(1/y)).expr == exp(x)*exp(1/y) def test_multivar_0a(): assert Order(exp(1/x)*exp(1/y)).expr == exp(1/x)*exp(1/y) def test_multivar_1(): assert Order(x + y).expr == x + y assert Order(x + 2*y).expr == x + y assert (Order(x + y) + x).expr == (x + y) assert (Order(x + y) + x**2) == Order(x + y) assert (Order(x + y) + 1/x) == 1/x + Order(x + y) assert Order(x**2 + y*x).expr == x**2 + y*x def test_multivar_2(): assert Order(x**2*y + y**2*x, x, y).expr == x**2*y + y**2*x def test_multivar_mul_1(): assert Order(x + y)*x == Order(x**2 + y*x, x, y) def test_multivar_3(): assert (Order(x) + Order(y)).args in [ (Order(x), Order(y)), (Order(y), Order(x))] assert Order(x) + Order(y) + Order(x + y) == Order(x + y) assert (Order(x**2*y) + Order(y**2*x)).args in [ (Order(x*y**2), Order(y*x**2)), (Order(y*x**2), Order(x*y**2))] assert (Order(x**2*y) + Order(y*x)) == Order(x*y) def test_issue_3468(): y = Symbol('y', negative=True) z = Symbol('z', complex=True) # check that Order does not modify assumptions about symbols Order(x) Order(y) Order(z) assert x.is_positive is None assert y.is_positive is False assert z.is_positive is None def test_leading_order(): assert (x + 1 + 1/x**5).extract_leading_order(x) == ((1/x**5, O(1/x**5)),) assert (1 + 1/x).extract_leading_order(x) == ((1/x, O(1/x)),) assert (1 + x).extract_leading_order(x) == ((1, O(1, x)),) assert (1 + x**2).extract_leading_order(x) == ((1, O(1, x)),) assert (2 + x**2).extract_leading_order(x) == ((2, O(1, x)),) assert (x + x**2).extract_leading_order(x) == ((x, O(x)),) def test_leading_order2(): assert set((2 + pi + x**2).extract_leading_order(x)) == {(pi, O(1, x)), (S(2), O(1, x))} assert set((2*x + pi*x + x**2).extract_leading_order(x)) == {(2*x, O(x)), (x*pi, O(x))} def test_order_leadterm(): assert O(x**2)._eval_as_leading_term(x) == O(x**2) def test_order_symbols(): e = x*y*sin(x)*Integral(x, (x, 1, 2)) assert O(e) == O(x**2*y, x, y) assert O(e, x) == O(x**2) def test_nan(): assert O(nan) is nan assert not O(x).contains(nan) def test_O1(): assert O(1, x) * x == O(x) assert O(1, y) * x == O(1, y) def test_getn(): # other lines are tested incidentally by the suite assert O(x).getn() == 1 assert O(x/log(x)).getn() == 1 assert O(x**2/log(x)**2).getn() == 2 assert O(x*log(x)).getn() == 1 raises(NotImplementedError, lambda: (O(x) + O(y)).getn()) def test_diff(): assert O(x**2).diff(x) == O(x) def test_getO(): assert (x).getO() is None assert (x).removeO() == x assert (O(x)).getO() == O(x) assert (O(x)).removeO() == 0 assert (z + O(x) + O(y)).getO() == O(x) + O(y) assert (z + O(x) + O(y)).removeO() == z raises(NotImplementedError, lambda: (O(x) + O(y)).getn()) def test_leading_term(): from sympy import digamma assert O(1/digamma(1/x)) == O(1/log(x)) def test_eval(): assert Order(x).subs(Order(x), 1) == 1 assert Order(x).subs(x, y) == Order(y) assert Order(x).subs(y, x) == Order(x) assert Order(x).subs(x, x + y) == Order(x + y, (x, -y)) assert (O(1)**x).is_Pow def test_issue_4279(): a, b = symbols('a b') assert O(a, a, b) + O(1, a, b) == O(1, a, b) assert O(b, a, b) + O(1, a, b) == O(1, a, b) assert O(a + b, a, b) + O(1, a, b) == O(1, a, b) assert O(1, a, b) + O(a, a, b) == O(1, a, b) assert O(1, a, b) + O(b, a, b) == O(1, a, b) assert O(1, a, b) + O(a + b, a, b) == O(1, a, b) def test_issue_4855(): assert 1/O(1) != O(1) assert 1/O(x) != O(1/x) assert 1/O(x, (x, oo)) != O(1/x, (x, oo)) f = Function('f') assert 1/O(f(x)) != O(1/x) def test_order_conjugate_transpose(): x = Symbol('x', real=True) y = Symbol('y', imaginary=True) assert conjugate(Order(x)) == Order(conjugate(x)) assert conjugate(Order(y)) == Order(conjugate(y)) assert conjugate(Order(x**2)) == Order(conjugate(x)**2) assert conjugate(Order(y**2)) == Order(conjugate(y)**2) assert transpose(Order(x)) == Order(transpose(x)) assert transpose(Order(y)) == Order(transpose(y)) assert transpose(Order(x**2)) == Order(transpose(x)**2) assert transpose(Order(y**2)) == Order(transpose(y)**2) def test_order_noncommutative(): A = Symbol('A', commutative=False) assert Order(A + A*x, x) == Order(1, x) assert (A + A*x)*Order(x) == Order(x) assert (A*x)*Order(x) == Order(x**2, x) assert expand((1 + Order(x))*A*A*x) == A*A*x + Order(x**2, x) assert expand((A*A + Order(x))*x) == A*A*x + Order(x**2, x) assert expand((A + Order(x))*A*x) == A*A*x + Order(x**2, x) def test_issue_6753(): assert (1 + x**2)**10000*O(x) == O(x) def test_order_at_infinity(): assert Order(1 + x, (x, oo)) == Order(x, (x, oo)) assert Order(3*x, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo))*3 == Order(x, (x, oo)) assert -28*Order(x, (x, oo)) == Order(x, (x, oo)) assert Order(Order(x, (x, oo)), (x, oo)) == Order(x, (x, oo)) assert Order(Order(x, (x, oo)), (y, oo)) == Order(x, (x, oo), (y, oo)) assert Order(3, (x, oo)) == Order(1, (x, oo)) assert Order(x**2 + x + y, (x, oo)) == O(x**2, (x, oo)) assert Order(x**2 + x + y, (y, oo)) == O(y, (y, oo)) assert Order(2*x, (x, oo))*x == Order(x**2, (x, oo)) assert Order(2*x, (x, oo))/x == Order(1, (x, oo)) assert Order(2*x, (x, oo))*x*exp(1/x) == Order(x**2*exp(1/x), (x, oo)) assert Order(2*x, (x, oo))*x*exp(1/x)/ln(x)**3 == Order(x**2*exp(1/x)*ln(x)**-3, (x, oo)) assert Order(x, (x, oo)) + 1/x == 1/x + Order(x, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo)) + 1 == 1 + Order(x, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo)) + x == x + Order(x, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo)) + x**2 == x**2 + Order(x, (x, oo)) assert Order(1/x, (x, oo)) + 1/x**2 == 1/x**2 + Order(1/x, (x, oo)) == Order(1/x, (x, oo)) assert Order(x, (x, oo)) + exp(1/x) == exp(1/x) + Order(x, (x, oo)) assert Order(x, (x, oo))**2 == Order(x**2, (x, oo)) assert Order(x, (x, oo)) + Order(x**2, (x, oo)) == Order(x**2, (x, oo)) assert Order(x, (x, oo)) + Order(x**-2, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo)) + Order(1/x, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo)) - Order(x, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo)) + Order(1, (x, oo)) == Order(x, (x, oo)) assert Order(x, (x, oo)) + Order(x**2, (x, oo)) == Order(x**2, (x, oo)) assert Order(1/x, (x, oo)) + Order(1, (x, oo)) == Order(1, (x, oo)) assert Order(x, (x, oo)) + Order(exp(1/x), (x, oo)) == Order(x, (x, oo)) assert Order(x**3, (x, oo)) + Order(exp(2/x), (x, oo)) == Order(x**3, (x, oo)) assert Order(x**-3, (x, oo)) + Order(exp(2/x), (x, oo)) == Order(exp(2/x), (x, oo)) # issue 7207 assert Order(exp(x), (x, oo)).expr == Order(2*exp(x), (x, oo)).expr == exp(x) assert Order(y**x, (x, oo)).expr == Order(2*y**x, (x, oo)).expr == exp(log(y)*x) # issue 19545 assert Order(1/x - 3/(3*x + 2), (x, oo)).expr == x**(-2) def test_mixing_order_at_zero_and_infinity(): assert (Order(x, (x, 0)) + Order(x, (x, oo))).is_Add assert Order(x, (x, 0)) + Order(x, (x, oo)) == Order(x, (x, oo)) + Order(x, (x, 0)) assert Order(Order(x, (x, oo))) == Order(x, (x, oo)) # not supported (yet) raises(NotImplementedError, lambda: Order(x, (x, 0))*Order(x, (x, oo))) raises(NotImplementedError, lambda: Order(x, (x, oo))*Order(x, (x, 0))) raises(NotImplementedError, lambda: Order(Order(x, (x, oo)), y)) raises(NotImplementedError, lambda: Order(Order(x), (x, oo))) def test_order_at_some_point(): assert Order(x, (x, 1)) == Order(1, (x, 1)) assert Order(2*x - 2, (x, 1)) == Order(x - 1, (x, 1)) assert Order(-x + 1, (x, 1)) == Order(x - 1, (x, 1)) assert Order(x - 1, (x, 1))**2 == Order((x - 1)**2, (x, 1)) assert Order(x - 2, (x, 2)) - O(x - 2, (x, 2)) == Order(x - 2, (x, 2)) def test_order_subs_limits(): # issue 3333 assert (1 + Order(x)).subs(x, 1/x) == 1 + Order(1/x, (x, oo)) assert (1 + Order(x)).limit(x, 0) == 1 # issue 5769 assert ((x + Order(x**2))/x).limit(x, 0) == 1 assert Order(x**2).subs(x, y - 1) == Order((y - 1)**2, (y, 1)) assert Order(10*x**2, (x, 2)).subs(x, y - 1) == Order(1, (y, 3)) def test_issue_9351(): assert exp(x).series(x, 10, 1) == exp(10) + Order(x - 10, (x, 10)) def test_issue_9192(): assert O(1)*O(1) == O(1) assert O(1)**O(1) == O(1) def test_issue_9910(): assert O(x*log(x) + sin(x), (x, oo)) == O(x*log(x), (x, oo)) def test_performance_of_adding_order(): l = list(x**i for i in range(1000)) l.append(O(x**1001)) assert Add(*l).subs(x,1) == O(1) def test_issue_14622(): assert (x**(-4) + x**(-3) + x**(-1) + O(x**(-6), (x, oo))).as_numer_denom() == ( x**4 + x**5 + x**7 + O(x**2, (x, oo)), x**8) assert (x**3 + O(x**2, (x, oo))).is_Add assert O(x**2, (x, oo)).contains(x**3) is False assert O(x, (x, oo)).contains(O(x, (x, 0))) is None assert O(x, (x, 0)).contains(O(x, (x, oo))) is None raises(NotImplementedError, lambda: O(x**3).contains(x**w)) def test_issue_15539(): assert O(1/x**2 + 1/x**4, (x, -oo)) == O(1/x**2, (x, -oo)) assert O(1/x**4 + exp(x), (x, -oo)) == O(1/x**4, (x, -oo)) assert O(1/x**4 + exp(-x), (x, -oo)) == O(exp(-x), (x, -oo)) assert O(1/x, (x, oo)).subs(x, -x) == O(-1/x, (x, -oo)) def test_issue_18606(): assert unchanged(Order, 0) sympy-sympy-1.9/sympy/series/tests/test_residues.py000066400000000000000000000051471412543434000230030ustar00rootroot00000000000000from sympy import (residue, Symbol, Function, sin, I, exp, log, pi, S, factorial, sqrt, Rational, tan, cot, tanh) from sympy.testing.pytest import XFAIL, raises from sympy.abc import x, z, a, s def test_basic1(): assert residue(1/x, x, 0) == 1 assert residue(-2/x, x, 0) == -2 assert residue(81/x, x, 0) == 81 assert residue(1/x**2, x, 0) == 0 assert residue(0, x, 0) == 0 assert residue(5, x, 0) == 0 assert residue(x, x, 0) == 0 assert residue(x**2, x, 0) == 0 def test_basic2(): assert residue(1/x, x, 1) == 0 assert residue(-2/x, x, 1) == 0 assert residue(81/x, x, -1) == 0 assert residue(1/x**2, x, 1) == 0 assert residue(0, x, 1) == 0 assert residue(5, x, 1) == 0 assert residue(x, x, 1) == 0 assert residue(x**2, x, 5) == 0 def test_f(): f = Function("f") assert residue(f(x)/x**5, x, 0) == f(x).diff(x, 4).subs(x, 0)/24 def test_functions(): assert residue(1/sin(x), x, 0) == 1 assert residue(2/sin(x), x, 0) == 2 assert residue(1/sin(x)**2, x, 0) == 0 assert residue(1/sin(x)**5, x, 0) == Rational(3, 8) def test_expressions(): assert residue(1/(x + 1), x, 0) == 0 assert residue(1/(x + 1), x, -1) == 1 assert residue(1/(x**2 + 1), x, -1) == 0 assert residue(1/(x**2 + 1), x, I) == -I/2 assert residue(1/(x**2 + 1), x, -I) == I/2 assert residue(1/(x**4 + 1), x, 0) == 0 assert residue(1/(x**4 + 1), x, exp(I*pi/4)).equals(-(Rational(1, 4) + I/4)/sqrt(2)) assert residue(1/(x**2 + a**2)**2, x, a*I) == -I/4/a**3 @XFAIL def test_expressions_failing(): n = Symbol('n', integer=True, positive=True) assert residue(exp(z)/(z - pi*I/4*a)**n, z, I*pi*a) == \ exp(I*pi*a/4)/factorial(n - 1) def test_NotImplemented(): raises(NotImplementedError, lambda: residue(exp(1/z), z, 0)) def test_bug(): assert residue(2**(z)*(s + z)*(1 - s - z)/z**2, z, 0) == \ 1 + s*log(2) - s**2*log(2) - 2*s def test_issue_5654(): assert residue(1/(x**2 + a**2)**2, x, a*I) == -I/(4*a**3) def test_issue_6499(): assert residue(1/(exp(z) - 1), z, 0) == 1 def test_issue_14037(): assert residue(sin(x**50)/x**51, x, 0) == 1 def test_issue_21176(): f = x**2*cot(pi*x)/(x**4 + 1) assert residue(f, x, -sqrt(2)/2 - sqrt(2)*I/2).cancel().together(deep=True)\ == sqrt(2)*(1 - I)/(8*tan(sqrt(2)*pi*(1 + I)/2)) def test_issue_21177(): r = -sqrt(3)*tanh(sqrt(3)*pi/2)/3 a = residue(cot(pi*x)/((x - 1)*(x - 2) + 1), x, S(3)/2 - sqrt(3)*I/2) b = residue(cot(pi*x)/(x**2 - 3*x + 3), x, S(3)/2 - sqrt(3)*I/2) assert a == r assert (b - a).cancel() == 0 sympy-sympy-1.9/sympy/series/tests/test_sequences.py000066400000000000000000000245541412543434000231560ustar00rootroot00000000000000from sympy import (S, Tuple, symbols, Interval, EmptySequence, oo, SeqPer, SeqFormula, sequence, SeqAdd, SeqMul, Indexed, Idx, sqrt, fibonacci, tribonacci, sin, cos, exp, Rational, Symbol, Function) from sympy.series.sequences import SeqExpr, SeqExprOp, RecursiveSeq from sympy.testing.pytest import raises, slow x, y, z = symbols('x y z') n, m = symbols('n m') def test_EmptySequence(): assert S.EmptySequence is EmptySequence assert S.EmptySequence.interval is S.EmptySet assert S.EmptySequence.length is S.Zero assert list(S.EmptySequence) == [] def test_SeqExpr(): s = SeqExpr((1, n, y), (x, 0, 10)) assert isinstance(s, SeqExpr) assert s.gen == (1, n, y) assert s.interval == Interval(0, 10) assert s.start == 0 assert s.stop == 10 assert s.length == 11 assert s.variables == (x,) assert SeqExpr((1, 2, 3), (x, 0, oo)).length is oo def test_SeqPer(): s = SeqPer((1, n, 3), (x, 0, 5)) assert isinstance(s, SeqPer) assert s.periodical == Tuple(1, n, 3) assert s.period == 3 assert s.coeff(3) == 1 assert s.free_symbols == {n} assert list(s) == [1, n, 3, 1, n, 3] assert s[:] == [1, n, 3, 1, n, 3] assert SeqPer((1, n, 3), (x, -oo, 0))[0:6] == [1, n, 3, 1, n, 3] raises(ValueError, lambda: SeqPer((1, 2, 3), (0, 1, 2))) raises(ValueError, lambda: SeqPer((1, 2, 3), (x, -oo, oo))) raises(ValueError, lambda: SeqPer(n**2, (0, oo))) assert SeqPer((n, n**2, n**3), (m, 0, oo))[:6] == \ [n, n**2, n**3, n, n**2, n**3] assert SeqPer((n, n**2, n**3), (n, 0, oo))[:6] == [0, 1, 8, 3, 16, 125] assert SeqPer((n, m), (n, 0, oo))[:6] == [0, m, 2, m, 4, m] def test_SeqFormula(): s = SeqFormula(n**2, (n, 0, 5)) assert isinstance(s, SeqFormula) assert s.formula == n**2 assert s.coeff(3) == 9 assert list(s) == [i**2 for i in range(6)] assert s[:] == [i**2 for i in range(6)] assert SeqFormula(n**2, (n, -oo, 0))[0:6] == [i**2 for i in range(6)] assert SeqFormula(n**2, (0, oo)) == SeqFormula(n**2, (n, 0, oo)) assert SeqFormula(n**2, (0, m)).subs(m, x) == SeqFormula(n**2, (0, x)) assert SeqFormula(m*n**2, (n, 0, oo)).subs(m, x) == \ SeqFormula(x*n**2, (n, 0, oo)) raises(ValueError, lambda: SeqFormula(n**2, (0, 1, 2))) raises(ValueError, lambda: SeqFormula(n**2, (n, -oo, oo))) raises(ValueError, lambda: SeqFormula(m*n**2, (0, oo))) seq = SeqFormula(x*(y**2 + z), (z, 1, 100)) assert seq.expand() == SeqFormula(x*y**2 + x*z, (z, 1, 100)) seq = SeqFormula(sin(x*(y**2 + z)),(z, 1, 100)) assert seq.expand(trig=True) == SeqFormula(sin(x*y**2)*cos(x*z) + sin(x*z)*cos(x*y**2), (z, 1, 100)) assert seq.expand() == SeqFormula(sin(x*y**2 + x*z), (z, 1, 100)) assert seq.expand(trig=False) == SeqFormula(sin(x*y**2 + x*z), (z, 1, 100)) seq = SeqFormula(exp(x*(y**2 + z)), (z, 1, 100)) assert seq.expand() == SeqFormula(exp(x*y**2)*exp(x*z), (z, 1, 100)) assert seq.expand(power_exp=False) == SeqFormula(exp(x*y**2 + x*z), (z, 1, 100)) assert seq.expand(mul=False, power_exp=False) == SeqFormula(exp(x*(y**2 + z)), (z, 1, 100)) def test_sequence(): form = SeqFormula(n**2, (n, 0, 5)) per = SeqPer((1, 2, 3), (n, 0, 5)) inter = SeqFormula(n**2) assert sequence(n**2, (n, 0, 5)) == form assert sequence((1, 2, 3), (n, 0, 5)) == per assert sequence(n**2) == inter def test_SeqExprOp(): form = SeqFormula(n**2, (n, 0, 10)) per = SeqPer((1, 2, 3), (m, 5, 10)) s = SeqExprOp(form, per) assert s.gen == (n**2, (1, 2, 3)) assert s.interval == Interval(5, 10) assert s.start == 5 assert s.stop == 10 assert s.length == 6 assert s.variables == (n, m) def test_SeqAdd(): per = SeqPer((1, 2, 3), (n, 0, oo)) form = SeqFormula(n**2) per_bou = SeqPer((1, 2), (n, 1, 5)) form_bou = SeqFormula(n**2, (6, 10)) form_bou2 = SeqFormula(n**2, (1, 5)) assert SeqAdd() == S.EmptySequence assert SeqAdd(S.EmptySequence) == S.EmptySequence assert SeqAdd(per) == per assert SeqAdd(per, S.EmptySequence) == per assert SeqAdd(per_bou, form_bou) == S.EmptySequence s = SeqAdd(per_bou, form_bou2, evaluate=False) assert s.args == (form_bou2, per_bou) assert s[:] == [2, 6, 10, 18, 26] assert list(s) == [2, 6, 10, 18, 26] assert isinstance(SeqAdd(per, per_bou, evaluate=False), SeqAdd) s1 = SeqAdd(per, per_bou) assert isinstance(s1, SeqPer) assert s1 == SeqPer((2, 4, 4, 3, 3, 5), (n, 1, 5)) s2 = SeqAdd(form, form_bou) assert isinstance(s2, SeqFormula) assert s2 == SeqFormula(2*n**2, (6, 10)) assert SeqAdd(form, form_bou, per) == \ SeqAdd(per, SeqFormula(2*n**2, (6, 10))) assert SeqAdd(form, SeqAdd(form_bou, per)) == \ SeqAdd(per, SeqFormula(2*n**2, (6, 10))) assert SeqAdd(per, SeqAdd(form, form_bou), evaluate=False) == \ SeqAdd(per, SeqFormula(2*n**2, (6, 10))) assert SeqAdd(SeqPer((1, 2), (n, 0, oo)), SeqPer((1, 2), (m, 0, oo))) == \ SeqPer((2, 4), (n, 0, oo)) def test_SeqMul(): per = SeqPer((1, 2, 3), (n, 0, oo)) form = SeqFormula(n**2) per_bou = SeqPer((1, 2), (n, 1, 5)) form_bou = SeqFormula(n**2, (n, 6, 10)) form_bou2 = SeqFormula(n**2, (1, 5)) assert SeqMul() == S.EmptySequence assert SeqMul(S.EmptySequence) == S.EmptySequence assert SeqMul(per) == per assert SeqMul(per, S.EmptySequence) == S.EmptySequence assert SeqMul(per_bou, form_bou) == S.EmptySequence s = SeqMul(per_bou, form_bou2, evaluate=False) assert s.args == (form_bou2, per_bou) assert s[:] == [1, 8, 9, 32, 25] assert list(s) == [1, 8, 9, 32, 25] assert isinstance(SeqMul(per, per_bou, evaluate=False), SeqMul) s1 = SeqMul(per, per_bou) assert isinstance(s1, SeqPer) assert s1 == SeqPer((1, 4, 3, 2, 2, 6), (n, 1, 5)) s2 = SeqMul(form, form_bou) assert isinstance(s2, SeqFormula) assert s2 == SeqFormula(n**4, (6, 10)) assert SeqMul(form, form_bou, per) == \ SeqMul(per, SeqFormula(n**4, (6, 10))) assert SeqMul(form, SeqMul(form_bou, per)) == \ SeqMul(per, SeqFormula(n**4, (6, 10))) assert SeqMul(per, SeqMul(form, form_bou2, evaluate=False), evaluate=False) == \ SeqMul(form, per, form_bou2, evaluate=False) assert SeqMul(SeqPer((1, 2), (n, 0, oo)), SeqPer((1, 2), (n, 0, oo))) == \ SeqPer((1, 4), (n, 0, oo)) def test_add(): per = SeqPer((1, 2), (n, 0, oo)) form = SeqFormula(n**2) assert per + (SeqPer((2, 3))) == SeqPer((3, 5), (n, 0, oo)) assert form + SeqFormula(n**3) == SeqFormula(n**2 + n**3) assert per + form == SeqAdd(per, form) raises(TypeError, lambda: per + n) raises(TypeError, lambda: n + per) def test_sub(): per = SeqPer((1, 2), (n, 0, oo)) form = SeqFormula(n**2) assert per - (SeqPer((2, 3))) == SeqPer((-1, -1), (n, 0, oo)) assert form - (SeqFormula(n**3)) == SeqFormula(n**2 - n**3) assert per - form == SeqAdd(per, -form) raises(TypeError, lambda: per - n) raises(TypeError, lambda: n - per) def test_mul__coeff_mul(): assert SeqPer((1, 2), (n, 0, oo)).coeff_mul(2) == SeqPer((2, 4), (n, 0, oo)) assert SeqFormula(n**2).coeff_mul(2) == SeqFormula(2*n**2) assert S.EmptySequence.coeff_mul(100) == S.EmptySequence assert SeqPer((1, 2), (n, 0, oo)) * (SeqPer((2, 3))) == \ SeqPer((2, 6), (n, 0, oo)) assert SeqFormula(n**2) * SeqFormula(n**3) == SeqFormula(n**5) assert S.EmptySequence * SeqFormula(n**2) == S.EmptySequence assert SeqFormula(n**2) * S.EmptySequence == S.EmptySequence raises(TypeError, lambda: sequence(n**2) * n) raises(TypeError, lambda: n * sequence(n**2)) def test_neg(): assert -SeqPer((1, -2), (n, 0, oo)) == SeqPer((-1, 2), (n, 0, oo)) assert -SeqFormula(n**2) == SeqFormula(-n**2) def test_operations(): per = SeqPer((1, 2), (n, 0, oo)) per2 = SeqPer((2, 4), (n, 0, oo)) form = SeqFormula(n**2) form2 = SeqFormula(n**3) assert per + form + form2 == SeqAdd(per, form, form2) assert per + form - form2 == SeqAdd(per, form, -form2) assert per + form - S.EmptySequence == SeqAdd(per, form) assert per + per2 + form == SeqAdd(SeqPer((3, 6), (n, 0, oo)), form) assert S.EmptySequence - per == -per assert form + form == SeqFormula(2*n**2) assert per * form * form2 == SeqMul(per, form, form2) assert form * form == SeqFormula(n**4) assert form * -form == SeqFormula(-n**4) assert form * (per + form2) == SeqMul(form, SeqAdd(per, form2)) assert form * (per + per) == SeqMul(form, per2) assert form.coeff_mul(m) == SeqFormula(m*n**2, (n, 0, oo)) assert per.coeff_mul(m) == SeqPer((m, 2*m), (n, 0, oo)) def test_Idx_limits(): i = symbols('i', cls=Idx) r = Indexed('r', i) assert SeqFormula(r, (i, 0, 5))[:] == [r.subs(i, j) for j in range(6)] assert SeqPer((1, 2), (i, 0, 5))[:] == [1, 2, 1, 2, 1, 2] @slow def test_find_linear_recurrence(): assert sequence((0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55), \ (n, 0, 10)).find_linear_recurrence(11) == [1, 1] assert sequence((1, 2, 4, 7, 28, 128, 582, 2745, 13021, 61699, 292521, \ 1387138), (n, 0, 11)).find_linear_recurrence(12) == [5, -2, 6, -11] assert sequence(x*n**3+y*n, (n, 0, oo)).find_linear_recurrence(10) \ == [4, -6, 4, -1] assert sequence(x**n, (n,0,20)).find_linear_recurrence(21) == [x] assert sequence((1,2,3)).find_linear_recurrence(10, 5) == [0, 0, 1] assert sequence(((1 + sqrt(5))/2)**n + \ (-(1 + sqrt(5))/2)**(-n)).find_linear_recurrence(10) == [1, 1] assert sequence(x*((1 + sqrt(5))/2)**n + y*(-(1 + sqrt(5))/2)**(-n), \ (n,0,oo)).find_linear_recurrence(10) == [1, 1] assert sequence((1,2,3,4,6),(n, 0, 4)).find_linear_recurrence(5) == [] assert sequence((2,3,4,5,6,79),(n, 0, 5)).find_linear_recurrence(6,gfvar=x) \ == ([], None) assert sequence((2,3,4,5,8,30),(n, 0, 5)).find_linear_recurrence(6,gfvar=x) \ == ([Rational(19, 2), -20, Rational(27, 2)], (-31*x**2 + 32*x - 4)/(27*x**3 - 40*x**2 + 19*x -2)) assert sequence(fibonacci(n)).find_linear_recurrence(30,gfvar=x) \ == ([1, 1], -x/(x**2 + x - 1)) assert sequence(tribonacci(n)).find_linear_recurrence(30,gfvar=x) \ == ([1, 1, 1], -x/(x**3 + x**2 + x - 1)) def test_RecursiveSeq(): y = Function('y') n = Symbol('n') fib = RecursiveSeq(y(n - 1) + y(n - 2), y(n), n, [0, 1]) assert fib.coeff(3) == 2 sympy-sympy-1.9/sympy/series/tests/test_series.py000066400000000000000000000326021412543434000224460ustar00rootroot00000000000000from sympy import sin, cos, exp, E, series, oo, S, Derivative, O, Integral, \ Function, PoleError, log, sqrt, N, Symbol, Subs, pi, symbols, atan, LambertW, Rational from sympy.abc import x, y, n, k from sympy.testing.pytest import raises from sympy.series.gruntz import calculate_series def test_sin(): e1 = sin(x).series(x, 0) e2 = series(sin(x), x, 0) assert e1 == e2 def test_cos(): e1 = cos(x).series(x, 0) e2 = series(cos(x), x, 0) assert e1 == e2 def test_exp(): e1 = exp(x).series(x, 0) e2 = series(exp(x), x, 0) assert e1 == e2 def test_exp2(): e1 = exp(cos(x)).series(x, 0) e2 = series(exp(cos(x)), x, 0) assert e1 == e2 def test_issue_5223(): assert series(1, x) == 1 assert next(S.Zero.lseries(x)) == 0 assert cos(x).series() == cos(x).series(x) raises(ValueError, lambda: cos(x + y).series()) raises(ValueError, lambda: x.series(dir="")) assert (cos(x).series(x, 1) - cos(x + 1).series(x).subs(x, x - 1)).removeO() == 0 e = cos(x).series(x, 1, n=None) assert [next(e) for i in range(2)] == [cos(1), -((x - 1)*sin(1))] e = cos(x).series(x, 1, n=None, dir='-') assert [next(e) for i in range(2)] == [cos(1), (1 - x)*sin(1)] # the following test is exact so no need for x -> x - 1 replacement assert abs(x).series(x, 1, dir='-') == x assert exp(x).series(x, 1, dir='-', n=3).removeO() == \ E - E*(-x + 1) + E*(-x + 1)**2/2 D = Derivative assert D(x**2 + x**3*y**2, x, 2, y, 1).series(x).doit() == 12*x*y assert next(D(cos(x), x).lseries()) == D(1, x) assert D( exp(x), x).series(n=3) == D(1, x) + D(x, x) + D(x**2/2, x) + D(x**3/6, x) + O(x**3) assert Integral(x, (x, 1, 3), (y, 1, x)).series(x) == -4 + 4*x assert (1 + x + O(x**2)).getn() == 2 assert (1 + x).getn() is None raises(PoleError, lambda: ((1/sin(x))**oo).series()) logx = Symbol('logx') assert ((sin(x))**y).nseries(x, n=1, logx=logx) == \ exp(y*logx) + O(x*exp(y*logx), x) assert sin(1/x).series(x, oo, n=5) == 1/x - 1/(6*x**3) + O(x**(-5), (x, oo)) assert abs(x).series(x, oo, n=5, dir='+') == x assert abs(x).series(x, -oo, n=5, dir='-') == -x assert abs(-x).series(x, oo, n=5, dir='+') == x assert abs(-x).series(x, -oo, n=5, dir='-') == -x assert exp(x*log(x)).series(n=3) == \ 1 + x*log(x) + x**2*log(x)**2/2 + O(x**3*log(x)**3) # XXX is this right? If not, fix "ngot > n" handling in expr. p = Symbol('p', positive=True) assert exp(sqrt(p)**3*log(p)).series(n=3) == \ 1 + p**S('3/2')*log(p) + O(p**3*log(p)**3) assert exp(sin(x)*log(x)).series(n=2) == 1 + x*log(x) + O(x**2*log(x)**2) def test_issue_11313(): assert Integral(cos(x), x).series(x) == sin(x).series(x) assert Derivative(sin(x), x).series(x, n=3).doit() == cos(x).series(x, n=3) assert Derivative(x**3, x).as_leading_term(x) == 3*x**2 assert Derivative(x**3, y).as_leading_term(x) == 0 assert Derivative(sin(x), x).as_leading_term(x) == 1 assert Derivative(cos(x), x).as_leading_term(x) == -x # This result is equivalent to zero, zero is not return because # `Expr.series` doesn't currently detect an `x` in its `free_symbol`s. assert Derivative(1, x).as_leading_term(x) == Derivative(1, x) assert Derivative(exp(x), x).series(x).doit() == exp(x).series(x) assert 1 + Integral(exp(x), x).series(x) == exp(x).series(x) assert Derivative(log(x), x).series(x).doit() == (1/x).series(x) assert Integral(log(x), x).series(x) == Integral(log(x), x).doit().series(x).removeO() def test_series_of_Subs(): from sympy.abc import x, y, z subs1 = Subs(sin(x), x, y) subs2 = Subs(sin(x) * cos(z), x, y) subs3 = Subs(sin(x * z), (x, z), (y, x)) assert subs1.series(x) == subs1 subs1_series = (Subs(x, x, y) + Subs(-x**3/6, x, y) + Subs(x**5/120, x, y) + O(y**6)) assert subs1.series() == subs1_series assert subs1.series(y) == subs1_series assert subs1.series(z) == subs1 assert subs2.series(z) == (Subs(z**4*sin(x)/24, x, y) + Subs(-z**2*sin(x)/2, x, y) + Subs(sin(x), x, y) + O(z**6)) assert subs3.series(x).doit() == subs3.doit().series(x) assert subs3.series(z).doit() == sin(x*y) raises(ValueError, lambda: Subs(x + 2*y, y, z).series()) assert Subs(x + y, y, z).series(x).doit() == x + z def test_issue_3978(): f = Function('f') assert f(x).series(x, 0, 3, dir='-') == \ f(0) + x*Subs(Derivative(f(x), x), x, 0) + \ x**2*Subs(Derivative(f(x), x, x), x, 0)/2 + O(x**3) assert f(x).series(x, 0, 3) == \ f(0) + x*Subs(Derivative(f(x), x), x, 0) + \ x**2*Subs(Derivative(f(x), x, x), x, 0)/2 + O(x**3) assert f(x**2).series(x, 0, 3) == \ f(0) + x**2*Subs(Derivative(f(x), x), x, 0) + O(x**3) assert f(x**2+1).series(x, 0, 3) == \ f(1) + x**2*Subs(Derivative(f(x), x), x, 1) + O(x**3) class TestF(Function): pass assert TestF(x).series(x, 0, 3) == TestF(0) + \ x*Subs(Derivative(TestF(x), x), x, 0) + \ x**2*Subs(Derivative(TestF(x), x, x), x, 0)/2 + O(x**3) from sympy.series.acceleration import richardson, shanks from sympy import Sum, Integer def test_acceleration(): e = (1 + 1/n)**n assert round(richardson(e, n, 10, 20).evalf(), 10) == round(E.evalf(), 10) A = Sum(Integer(-1)**(k + 1) / k, (k, 1, n)) assert round(shanks(A, n, 25).evalf(), 4) == round(log(2).evalf(), 4) assert round(shanks(A, n, 25, 5).evalf(), 10) == round(log(2).evalf(), 10) def test_issue_5852(): assert series(1/cos(x/log(x)), x, 0) == 1 + x**2/(2*log(x)**2) + \ 5*x**4/(24*log(x)**4) + O(x**6) def test_issue_4583(): assert cos(1 + x + x**2).series(x, 0, 5) == cos(1) - x*sin(1) + \ x**2*(-sin(1) - cos(1)/2) + x**3*(-cos(1) + sin(1)/6) + \ x**4*(-11*cos(1)/24 + sin(1)/2) + O(x**5) def test_issue_6318(): eq = (1/x)**Rational(2, 3) assert (eq + 1).as_leading_term(x) == eq def test_x_is_base_detection(): eq = (x**2)**Rational(2, 3) assert eq.series() == x**Rational(4, 3) def test_sin_power(): e = sin(x)**1.2 assert calculate_series(e, x) == x**1.2 def test_issue_7203(): assert series(cos(x), x, pi, 3) == \ -1 + (x - pi)**2/2 + O((x - pi)**3, (x, pi)) def test_exp_product_positive_factors(): a, b = symbols('a, b', positive=True) x = a * b assert series(exp(x), x, n=8) == 1 + a*b + a**2*b**2/2 + \ a**3*b**3/6 + a**4*b**4/24 + a**5*b**5/120 + a**6*b**6/720 + \ a**7*b**7/5040 + O(a**8*b**8, a, b) def test_issue_8805(): assert series(1, n=8) == 1 def test_issue_9549(): y = (x**2 + x + 1) / (x**3 + x**2) assert series(y, x, oo) == x**(-5) - 1/x**4 + x**(-3) + 1/x + O(x**(-6), (x, oo)) def test_issue_10761(): assert series(1/(x**-2 + x**-3), x, 0) == x**3 - x**4 + x**5 + O(x**6) def test_issue_12578(): y = (1 - 1/(x/2 - 1/(2*x))**4)**(S(1)/8) assert y.series(x, 0, n=17) == 1 - 2*x**4 - 8*x**6 - 34*x**8 - 152*x**10 - 714*x**12 - \ 3472*x**14 - 17318*x**16 + O(x**17) def test_issue_12791(): beta = symbols('beta', real=True, positive=True) theta, varphi = symbols('theta varphi', real=True) expr = (-beta**2*varphi*sin(theta) + beta**2*cos(theta) + \ beta*varphi*sin(theta) - beta*cos(theta) - beta + 1)/(beta*cos(theta) - 1)**2 sol = 0.5/(0.5*cos(theta) - 1.0)**2 - 0.25*cos(theta)/(0.5*cos(theta)\ - 1.0)**2 + (beta - 0.5)*(-0.25*varphi*sin(2*theta) - 1.5*cos(theta)\ + 0.25*cos(2*theta) + 1.25)/(0.5*cos(theta) - 1.0)**3\ + 0.25*varphi*sin(theta)/(0.5*cos(theta) - 1.0)**2 + O((beta - 0.5)**2, (beta, 0.5)) assert expr.series(beta, 0.5, 2).trigsimp() == sol def test_issue_14885(): assert series(x**Rational(-3, 2)*exp(x), x, 0) == (x**Rational(-3, 2) + 1/sqrt(x) + sqrt(x)/2 + x**Rational(3, 2)/6 + x**Rational(5, 2)/24 + x**Rational(7, 2)/120 + x**Rational(9, 2)/720 + x**Rational(11, 2)/5040 + O(x**6)) def test_issue_15539(): assert series(atan(x), x, -oo) == (-1/(5*x**5) + 1/(3*x**3) - 1/x - pi/2 + O(x**(-6), (x, -oo))) assert series(atan(x), x, oo) == (-1/(5*x**5) + 1/(3*x**3) - 1/x + pi/2 + O(x**(-6), (x, oo))) def test_issue_7259(): assert series(LambertW(x), x) == x - x**2 + 3*x**3/2 - 8*x**4/3 + 125*x**5/24 + O(x**6) assert series(LambertW(x**2), x, n=8) == x**2 - x**4 + 3*x**6/2 + O(x**8) assert series(LambertW(sin(x)), x, n=4) == x - x**2 + 4*x**3/3 + O(x**4) def test_issue_11884(): assert cos(x).series(x, 1, n=1) == cos(1) + O(x - 1, (x, 1)) def test_issue_18008(): y = x*(1 + x*(1 - x))/((1 + x*(1 - x)) - (1 - x)*(1 - x)) assert y.series(x, oo, n=4) == -9/(32*x**3) - 3/(16*x**2) - 1/(8*x) + S(1)/4 + x/2 + \ O(x**(-4), (x, oo)) def test_issue_18842(): f = log(x/(1 - x)) assert f.series(x, 0.491, n=1).removeO().nsimplify() == \ -S(180019443780011)/5000000000000000 def test_issue_19534(): dt = symbols('dt', real=True) expr = 16*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0)/45 + \ 49*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \ 0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \ 0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \ 0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.96296296296296296296*dt + 1.0) + 0.051640768506639183825*dt + \ dt*(1/2 - sqrt(21)/14) + 1.0)/180 + 49*dt*(-0.23637909581542530626*dt*(2.0*dt + 1.0) - \ 0.74817562366625959291*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.88085458023927036857*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \ 0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.96296296296296296296*dt + 1.0) + \ 2.1165151389911680013*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \ 0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \ 0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \ 0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.96296296296296296296*dt + 1.0) + 0.22431393315265061193*dt + 1.0) - \ 1.1854881643947648988*dt + dt*(sqrt(21)/14 + 1/2) + 1.0)/180 + \ dt*(0.66666666666666666667*dt*(2.0*dt + 1.0) + \ 6.0173399699313066769*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \ 4.1117044797036320069*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \ 0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.96296296296296296296*dt + 1.0) - \ 7.0189140975801991157*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \ 0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \ 0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \ 0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.96296296296296296296*dt + 1.0) + 0.22431393315265061193*dt + 1.0) + \ 0.94010945196161777522*dt*(-0.23637909581542530626*dt*(2.0*dt + 1.0) - \ 0.74817562366625959291*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.88085458023927036857*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \ 0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.96296296296296296296*dt + 1.0) + \ 2.1165151389911680013*dt*(-0.049335189898860408029*dt*(2.0*dt + 1.0) + \ 0.29601113939316244817*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) - \ 0.12564355335492979587*dt*(0.074074074074074074074*dt*(2.0*dt + 1.0) + \ 0.2962962962962962963*dt*(0.125*dt*(2.0*dt + 1.0) + 0.875*dt + 1.0) + \ 0.96296296296296296296*dt + 1.0) + 0.22431393315265061193*dt + 1.0) - \ 0.35816132904077632692*dt + 1.0) + 5.5065024887242400038*dt + 1.0)/20 + dt/20 + 1 assert N(expr.series(dt, 0, 8), 20) == -0.00092592592592592596126*dt**7 + 0.0027777777777777783175*dt**6 + \ 0.016666666666666656027*dt**5 + 0.083333333333333300952*dt**4 + 0.33333333333333337034*dt**3 + \ 1.0*dt**2 + 1.0*dt + 1.0 def test_issue_11407(): a, b, c, x = symbols('a b c x') assert series(sqrt(a + b + c*x), x, 0, 1) == sqrt(a + b) + O(x) assert series(sqrt(a + b + c + c*x), x, 0, 1) == sqrt(a + b + c) + O(x) def test_issue_14037(): assert (sin(x**50)/x**51).series(x, n=0) == 1/x + O(1, x) def test_issue_20551(): expr = (exp(x)/x).series(x, n=None) terms = [ next(expr) for i in range(3) ] assert terms == [1/x, 1, x/2] def test_issue_20697(): p_0, p_1, p_2, p_3, b_0, b_1, b_2 = symbols('p_0 p_1 p_2 p_3 b_0 b_1 b_2') Q = (p_0 + (p_1 + (p_2 + p_3/y)/y)/y)/(1 + ((p_3/(b_0*y) + (b_0*p_2\ - b_1*p_3)/b_0**2)/y + (b_0**2*p_1 - b_0*b_1*p_2 - p_3*(b_0*b_2\ - b_1**2))/b_0**3)/y) assert Q.series(y, n=3).ratsimp() == b_2*y**2 + b_1*y + b_0 + O(y**3) def test_issue_21245(): fi = (1 + sqrt(5))/2 assert (1/(1 - x - x**2)).series(x, 1/fi, 1).factor() == \ (-6964*sqrt(5) - 15572 + 2440*sqrt(5)*x + 5456*x\ + O((x - 2/(1 + sqrt(5)))**2, (x, 2/(1 + sqrt(5)))))/((1 + sqrt(5))**2\ *(20 + 9*sqrt(5))**2*(x + sqrt(5)*x - 2)) def test_issue_21938(): expr = sin(1/x + exp(-x)) - sin(1/x) assert expr.series(x, oo) == (1/(24*x**4) - 1/(2*x**2) + 1 + O(x**(-6), (x, oo)))*exp(-x) sympy-sympy-1.9/sympy/sets/000077500000000000000000000000001412543434000160625ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sets/__init__.py000066400000000000000000000017521412543434000202000ustar00rootroot00000000000000from .sets import (Set, Interval, Union, FiniteSet, ProductSet, Intersection, imageset, Complement, SymmetricDifference, DisjointUnion) from .fancysets import ImageSet, Range, ComplexRegion from .contains import Contains from .conditionset import ConditionSet from .ordinals import Ordinal, OmegaPower, ord0 from .powerset import PowerSet from ..core.singleton import S from .handlers.comparison import _eval_is_eq # noqa:F401 Reals = S.Reals Naturals = S.Naturals Naturals0 = S.Naturals0 UniversalSet = S.UniversalSet EmptySet = S.EmptySet Integers = S.Integers Rationals = S.Rationals __all__ = [ 'Set', 'Interval', 'Union', 'EmptySet', 'FiniteSet', 'ProductSet', 'Intersection', 'imageset', 'Complement', 'SymmetricDifference', 'DisjointUnion', 'ImageSet', 'Range', 'ComplexRegion', 'Reals', 'Contains', 'ConditionSet', 'Ordinal', 'OmegaPower', 'ord0', 'PowerSet', 'Reals', 'Naturals', 'Naturals0', 'UniversalSet', 'Integers', 'Rationals', ] sympy-sympy-1.9/sympy/sets/conditionset.py000066400000000000000000000171461412543434000211470ustar00rootroot00000000000000from sympy import S from sympy.core.basic import Basic from sympy.core.containers import Tuple from sympy.core.function import Lambda from sympy.core.logic import fuzzy_bool from sympy.core.relational import Eq from sympy.core.symbol import Dummy from sympy.core.sympify import _sympify from sympy.logic.boolalg import And, as_Boolean from sympy.utilities.iterables import sift from sympy.utilities.exceptions import SymPyDeprecationWarning from .contains import Contains from .sets import Set, EmptySet, Union, FiniteSet adummy = Dummy('conditionset') class ConditionSet(Set): """ Set of elements which satisfies a given condition. {x | condition(x) is True for x in S} Examples ======== >>> from sympy import Symbol, S, ConditionSet, pi, Eq, sin, Interval >>> from sympy.abc import x, y, z >>> sin_sols = ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi)) >>> 2*pi in sin_sols True >>> pi/2 in sin_sols False >>> 3*pi in sin_sols False >>> 5 in ConditionSet(x, x**2 > 4, S.Reals) True If the value is not in the base set, the result is false: >>> 5 in ConditionSet(x, x**2 > 4, Interval(2, 4)) False Notes ===== Symbols with assumptions should be avoided or else the condition may evaluate without consideration of the set: >>> n = Symbol('n', negative=True) >>> cond = (n > 0); cond False >>> ConditionSet(n, cond, S.Integers) EmptySet Only free symbols can be changed by using `subs`: >>> c = ConditionSet(x, x < 1, {x, z}) >>> c.subs(x, y) ConditionSet(x, x < 1, {y, z}) To check if ``pi`` is in ``c`` use: >>> pi in c False If no base set is specified, the universal set is implied: >>> ConditionSet(x, x < 1).base_set UniversalSet Only symbols or symbol-like expressions can be used: >>> ConditionSet(x + 1, x + 1 < 1, S.Integers) Traceback (most recent call last): ... ValueError: non-symbol dummy not recognized in condition When the base set is a ConditionSet, the symbols will be unified if possible with preference for the outermost symbols: >>> ConditionSet(x, x < y, ConditionSet(z, z + y < 2, S.Integers)) ConditionSet(x, (x < y) & (x + y < 2), Integers) """ def __new__(cls, sym, condition, base_set=S.UniversalSet): from sympy.core.function import BadSignatureError from sympy.utilities.iterables import flatten, has_dups sym = _sympify(sym) flat = flatten([sym]) if has_dups(flat): raise BadSignatureError("Duplicate symbols detected") base_set = _sympify(base_set) if not isinstance(base_set, Set): raise TypeError( 'base set should be a Set object, not %s' % base_set) condition = _sympify(condition) if isinstance(condition, FiniteSet): condition_orig = condition temp = (Eq(lhs, 0) for lhs in condition) condition = And(*temp) SymPyDeprecationWarning( feature="Using {} for condition".format(condition_orig), issue=17651, deprecated_since_version='1.5', useinstead="{} for condition".format(condition) ).warn() condition = as_Boolean(condition) if condition is S.true: return base_set if condition is S.false: return S.EmptySet if isinstance(base_set, EmptySet): return base_set # no simple answers, so now check syms for i in flat: if not getattr(i, '_diff_wrt', False): raise ValueError('`%s` is not symbol-like' % i) if base_set.contains(sym) is S.false: raise TypeError('sym `%s` is not in base_set `%s`' % (sym, base_set)) know = None if isinstance(base_set, FiniteSet): sifted = sift( base_set, lambda _: fuzzy_bool(condition.subs(sym, _))) if sifted[None]: know = FiniteSet(*sifted[True]) base_set = FiniteSet(*sifted[None]) else: return FiniteSet(*sifted[True]) if isinstance(base_set, cls): s, c, b = base_set.args def sig(s): return cls(s, Eq(adummy, 0)).as_dummy().sym sa, sb = map(sig, (sym, s)) if sa != sb: raise BadSignatureError('sym does not match sym of base set') reps = dict(zip(flatten([sym]), flatten([s]))) if s == sym: condition = And(condition, c) base_set = b elif not c.free_symbols & sym.free_symbols: reps = {v: k for k, v in reps.items()} condition = And(condition, c.xreplace(reps)) base_set = b elif not condition.free_symbols & s.free_symbols: sym = sym.xreplace(reps) condition = And(condition.xreplace(reps), c) base_set = b # flatten ConditionSet(Contains(ConditionSet())) expressions if isinstance(condition, Contains) and (sym == condition.args[0]): if isinstance(condition.args[1], Set): return condition.args[1].intersect(base_set) rv = Basic.__new__(cls, sym, condition, base_set) return rv if know is None else Union(know, rv) sym = property(lambda self: self.args[0]) condition = property(lambda self: self.args[1]) base_set = property(lambda self: self.args[2]) @property def free_symbols(self): cond_syms = self.condition.free_symbols - self.sym.free_symbols return cond_syms | self.base_set.free_symbols @property def bound_symbols(self): from sympy.utilities.iterables import flatten return flatten([self.sym]) def _contains(self, other): def ok_sig(a, b): tuples = [isinstance(i, Tuple) for i in (a, b)] c = tuples.count(True) if c == 1: return False if c == 0: return True return len(a) == len(b) and all( ok_sig(i, j) for i, j in zip(a, b)) if not ok_sig(self.sym, other): return S.false # try doing base_cond first and return # False immediately if it is False base_cond = Contains(other, self.base_set) if base_cond is S.false: return S.false # Substitute other into condition. This could raise e.g. for # ConditionSet(x, 1/x >= 0, Reals).contains(0) lamda = Lambda((self.sym,), self.condition) try: lambda_cond = lamda(other) except TypeError: return Contains(other, self, evaluate=False) else: return And(base_cond, lambda_cond) def as_relational(self, other): f = Lambda(self.sym, self.condition) if isinstance(self.sym, Tuple): f = f(*other) else: f = f(other) return And(f, self.base_set.contains(other)) def _eval_subs(self, old, new): sym, cond, base = self.args dsym = sym.subs(old, adummy) insym = dsym.has(adummy) # prioritize changing a symbol in the base newbase = base.subs(old, new) if newbase != base: if not insym: cond = cond.subs(old, new) return self.func(sym, cond, newbase) if insym: pass # no change of bound symbols via subs elif getattr(new, '_diff_wrt', False): cond = cond.subs(old, new) else: pass # let error about the symbol raise from __new__ return self.func(sym, cond, base) sympy-sympy-1.9/sympy/sets/contains.py000066400000000000000000000024231412543434000202530ustar00rootroot00000000000000from sympy.core import S from sympy.core.relational import Eq, Ne from sympy.logic.boolalg import BooleanFunction from sympy.utilities.misc import func_name class Contains(BooleanFunction): """ Asserts that x is an element of the set S. Examples ======== >>> from sympy import Symbol, Integer, S >>> from sympy.sets.contains import Contains >>> Contains(Integer(2), S.Integers) True >>> Contains(Integer(-2), S.Naturals) False >>> i = Symbol('i', integer=True) >>> Contains(i, S.Naturals) Contains(i, Naturals) References ========== .. [1] https://en.wikipedia.org/wiki/Element_%28mathematics%29 """ @classmethod def eval(cls, x, s): from sympy.sets.sets import Set if not isinstance(s, Set): raise TypeError('expecting Set, not %s' % func_name(s)) ret = s.contains(x) if not isinstance(ret, Contains) and ( ret in (S.true, S.false) or isinstance(ret, Set)): return ret @property def binary_symbols(self): return set().union(*[i.binary_symbols for i in self.args[1].args if i.is_Boolean or i.is_Symbol or isinstance(i, (Eq, Ne))]) def as_set(self): raise NotImplementedError() sympy-sympy-1.9/sympy/sets/fancysets.py000066400000000000000000001347001412543434000204400ustar00rootroot00000000000000from functools import reduce from sympy.core.basic import Basic from sympy.core.containers import Tuple from sympy.core.expr import Expr from sympy.core.function import Lambda from sympy.core.logic import fuzzy_not, fuzzy_or, fuzzy_and from sympy.core.numbers import oo from sympy.core.relational import Eq, is_eq from sympy.core.singleton import Singleton, S from sympy.core.symbol import Dummy, symbols, Symbol from sympy.core.sympify import _sympify, sympify, converter from sympy.logic.boolalg import And, Or from sympy.sets.sets import (Set, Interval, Union, FiniteSet, ProductSet) from sympy.utilities.misc import filldedent from sympy.utilities.iterables import cartes class Rationals(Set, metaclass=Singleton): """ Represents the rational numbers. This set is also available as the Singleton, S.Rationals. Examples ======== >>> from sympy import S >>> S.Half in S.Rationals True >>> iterable = iter(S.Rationals) >>> [next(iterable) for i in range(12)] [0, 1, -1, 1/2, 2, -1/2, -2, 1/3, 3, -1/3, -3, 2/3] """ is_iterable = True _inf = S.NegativeInfinity _sup = S.Infinity is_empty = False is_finite_set = False def _contains(self, other): if not isinstance(other, Expr): return False return other.is_rational def __iter__(self): from sympy.core.numbers import igcd, Rational yield S.Zero yield S.One yield S.NegativeOne d = 2 while True: for n in range(d): if igcd(n, d) == 1: yield Rational(n, d) yield Rational(d, n) yield Rational(-n, d) yield Rational(-d, n) d += 1 @property def _boundary(self): return S.Reals class Naturals(Set, metaclass=Singleton): """ Represents the natural numbers (or counting numbers) which are all positive integers starting from 1. This set is also available as the Singleton, S.Naturals. Examples ======== >>> from sympy import S, Interval, pprint >>> 5 in S.Naturals True >>> iterable = iter(S.Naturals) >>> next(iterable) 1 >>> next(iterable) 2 >>> next(iterable) 3 >>> pprint(S.Naturals.intersect(Interval(0, 10))) {1, 2, ..., 10} See Also ======== Naturals0 : non-negative integers (i.e. includes 0, too) Integers : also includes negative integers """ is_iterable = True _inf = S.One _sup = S.Infinity is_empty = False is_finite_set = False def _contains(self, other): if not isinstance(other, Expr): return False elif other.is_positive and other.is_integer: return True elif other.is_integer is False or other.is_positive is False: return False def _eval_is_subset(self, other): return Range(1, oo).is_subset(other) def _eval_is_superset(self, other): return Range(1, oo).is_superset(other) def __iter__(self): i = self._inf while True: yield i i = i + 1 @property def _boundary(self): return self def as_relational(self, x): from sympy.functions.elementary.integers import floor return And(Eq(floor(x), x), x >= self.inf, x < oo) class Naturals0(Naturals): """Represents the whole numbers which are all the non-negative integers, inclusive of zero. See Also ======== Naturals : positive integers; does not include 0 Integers : also includes the negative integers """ _inf = S.Zero def _contains(self, other): if not isinstance(other, Expr): return S.false elif other.is_integer and other.is_nonnegative: return S.true elif other.is_integer is False or other.is_nonnegative is False: return S.false def _eval_is_subset(self, other): return Range(oo).is_subset(other) def _eval_is_superset(self, other): return Range(oo).is_superset(other) class Integers(Set, metaclass=Singleton): """ Represents all integers: positive, negative and zero. This set is also available as the Singleton, S.Integers. Examples ======== >>> from sympy import S, Interval, pprint >>> 5 in S.Naturals True >>> iterable = iter(S.Integers) >>> next(iterable) 0 >>> next(iterable) 1 >>> next(iterable) -1 >>> next(iterable) 2 >>> pprint(S.Integers.intersect(Interval(-4, 4))) {-4, -3, ..., 4} See Also ======== Naturals0 : non-negative integers Integers : positive and negative integers and zero """ is_iterable = True is_empty = False is_finite_set = False def _contains(self, other): if not isinstance(other, Expr): return S.false return other.is_integer def __iter__(self): yield S.Zero i = S.One while True: yield i yield -i i = i + 1 @property def _inf(self): return S.NegativeInfinity @property def _sup(self): return S.Infinity @property def _boundary(self): return self def as_relational(self, x): from sympy.functions.elementary.integers import floor return And(Eq(floor(x), x), -oo < x, x < oo) def _eval_is_subset(self, other): return Range(-oo, oo).is_subset(other) def _eval_is_superset(self, other): return Range(-oo, oo).is_superset(other) class Reals(Interval, metaclass=Singleton): """ Represents all real numbers from negative infinity to positive infinity, including all integer, rational and irrational numbers. This set is also available as the Singleton, S.Reals. Examples ======== >>> from sympy import S, Rational, pi, I >>> 5 in S.Reals True >>> Rational(-1, 2) in S.Reals True >>> pi in S.Reals True >>> 3*I in S.Reals False >>> S.Reals.contains(pi) True See Also ======== ComplexRegion """ @property def start(self): return S.NegativeInfinity @property def end(self): return S.Infinity @property def left_open(self): return True @property def right_open(self): return True def __eq__(self, other): return other == Interval(S.NegativeInfinity, S.Infinity) def __hash__(self): return hash(Interval(S.NegativeInfinity, S.Infinity)) class ImageSet(Set): """ Image of a set under a mathematical function. The transformation must be given as a Lambda function which has as many arguments as the elements of the set upon which it operates, e.g. 1 argument when acting on the set of integers or 2 arguments when acting on a complex region. This function is not normally called directly, but is called from `imageset`. Examples ======== >>> from sympy import Symbol, S, pi, Dummy, Lambda >>> from sympy.sets.sets import FiniteSet, Interval >>> from sympy.sets.fancysets import ImageSet >>> x = Symbol('x') >>> N = S.Naturals >>> squares = ImageSet(Lambda(x, x**2), N) # {x**2 for x in N} >>> 4 in squares True >>> 5 in squares False >>> FiniteSet(0, 1, 2, 3, 4, 5, 6, 7, 9, 10).intersect(squares) {1, 4, 9} >>> square_iterable = iter(squares) >>> for i in range(4): ... next(square_iterable) 1 4 9 16 If you want to get value for `x` = 2, 1/2 etc. (Please check whether the `x` value is in `base_set` or not before passing it as args) >>> squares.lamda(2) 4 >>> squares.lamda(S(1)/2) 1/4 >>> n = Dummy('n') >>> solutions = ImageSet(Lambda(n, n*pi), S.Integers) # solutions of sin(x) = 0 >>> dom = Interval(-1, 1) >>> dom.intersect(solutions) {0} See Also ======== sympy.sets.sets.imageset """ def __new__(cls, flambda, *sets): if not isinstance(flambda, Lambda): raise ValueError('First argument must be a Lambda') signature = flambda.signature if len(signature) != len(sets): raise ValueError('Incompatible signature') sets = [_sympify(s) for s in sets] if not all(isinstance(s, Set) for s in sets): raise TypeError("Set arguments to ImageSet should of type Set") if not all(cls._check_sig(sg, st) for sg, st in zip(signature, sets)): raise ValueError("Signature %s does not match sets %s" % (signature, sets)) if flambda is S.IdentityFunction and len(sets) == 1: return sets[0] if not set(flambda.variables) & flambda.expr.free_symbols: is_empty = fuzzy_or(s.is_empty for s in sets) if is_empty == True: return S.EmptySet elif is_empty == False: return FiniteSet(flambda.expr) return Basic.__new__(cls, flambda, *sets) lamda = property(lambda self: self.args[0]) base_sets = property(lambda self: self.args[1:]) @property def base_set(self): # XXX: Maybe deprecate this? It is poorly defined in handling # the multivariate case... sets = self.base_sets if len(sets) == 1: return sets[0] else: return ProductSet(*sets).flatten() @property def base_pset(self): return ProductSet(*self.base_sets) @classmethod def _check_sig(cls, sig_i, set_i): if sig_i.is_symbol: return True elif isinstance(set_i, ProductSet): sets = set_i.sets if len(sig_i) != len(sets): return False # Recurse through the signature for nested tuples: return all(cls._check_sig(ts, ps) for ts, ps in zip(sig_i, sets)) else: # XXX: Need a better way of checking whether a set is a set of # Tuples or not. For example a FiniteSet can contain Tuples # but so can an ImageSet or a ConditionSet. Others like # Integers, Reals etc can not contain Tuples. We could just # list the possibilities here... Current code for e.g. # _contains probably only works for ProductSet. return True # Give the benefit of the doubt def __iter__(self): already_seen = set() for i in self.base_pset: val = self.lamda(*i) if val in already_seen: continue else: already_seen.add(val) yield val def _is_multivariate(self): return len(self.lamda.variables) > 1 def _contains(self, other): from sympy.solvers.solveset import _solveset_multi def get_symsetmap(signature, base_sets): '''Attempt to get a map of symbols to base_sets''' queue = list(zip(signature, base_sets)) symsetmap = {} for sig, base_set in queue: if sig.is_symbol: symsetmap[sig] = base_set elif base_set.is_ProductSet: sets = base_set.sets if len(sig) != len(sets): raise ValueError("Incompatible signature") # Recurse queue.extend(zip(sig, sets)) else: # If we get here then we have something like sig = (x, y) and # base_set = {(1, 2), (3, 4)}. For now we give up. return None return symsetmap def get_equations(expr, candidate): '''Find the equations relating symbols in expr and candidate.''' queue = [(expr, candidate)] for e, c in queue: if not isinstance(e, Tuple): yield Eq(e, c) elif not isinstance(c, Tuple) or len(e) != len(c): yield False return else: queue.extend(zip(e, c)) # Get the basic objects together: other = _sympify(other) expr = self.lamda.expr sig = self.lamda.signature variables = self.lamda.variables base_sets = self.base_sets # Use dummy symbols for ImageSet parameters so they don't match # anything in other rep = {v: Dummy(v.name) for v in variables} variables = [v.subs(rep) for v in variables] sig = sig.subs(rep) expr = expr.subs(rep) # Map the parts of other to those in the Lambda expr equations = [] for eq in get_equations(expr, other): # Unsatisfiable equation? if eq is False: return False equations.append(eq) # Map the symbols in the signature to the corresponding domains symsetmap = get_symsetmap(sig, base_sets) if symsetmap is None: # Can't factor the base sets to a ProductSet return None # Which of the variables in the Lambda signature need to be solved for? symss = (eq.free_symbols for eq in equations) variables = set(variables) & reduce(set.union, symss, set()) # Use internal multivariate solveset variables = tuple(variables) base_sets = [symsetmap[v] for v in variables] solnset = _solveset_multi(equations, variables, base_sets) if solnset is None: return None return fuzzy_not(solnset.is_empty) @property def is_iterable(self): return all(s.is_iterable for s in self.base_sets) def doit(self, **kwargs): from sympy.sets.setexpr import SetExpr f = self.lamda sig = f.signature if len(sig) == 1 and sig[0].is_symbol and isinstance(f.expr, Expr): base_set = self.base_sets[0] return SetExpr(base_set)._eval_func(f).set if all(s.is_FiniteSet for s in self.base_sets): return FiniteSet(*(f(*a) for a in cartes(*self.base_sets))) return self class Range(Set): """ Represents a range of integers. Can be called as Range(stop), Range(start, stop), or Range(start, stop, step); when step is not given it defaults to 1. `Range(stop)` is the same as `Range(0, stop, 1)` and the stop value (juse as for Python ranges) is not included in the Range values. >>> from sympy import Range >>> list(Range(3)) [0, 1, 2] The step can also be negative: >>> list(Range(10, 0, -2)) [10, 8, 6, 4, 2] The stop value is made canonical so equivalent ranges always have the same args: >>> Range(0, 10, 3) Range(0, 12, 3) Infinite ranges are allowed. ``oo`` and ``-oo`` are never included in the set (``Range`` is always a subset of ``Integers``). If the starting point is infinite, then the final value is ``stop - step``. To iterate such a range, it needs to be reversed: >>> from sympy import oo >>> r = Range(-oo, 1) >>> r[-1] 0 >>> next(iter(r)) Traceback (most recent call last): ... TypeError: Cannot iterate over Range with infinite start >>> next(iter(r.reversed)) 0 Although Range is a set (and supports the normal set operations) it maintains the order of the elements and can be used in contexts where `range` would be used. >>> from sympy import Interval >>> Range(0, 10, 2).intersect(Interval(3, 7)) Range(4, 8, 2) >>> list(_) [4, 6] Although slicing of a Range will always return a Range -- possibly empty -- an empty set will be returned from any intersection that is empty: >>> Range(3)[:0] Range(0, 0, 1) >>> Range(3).intersect(Interval(4, oo)) EmptySet >>> Range(3).intersect(Range(4, oo)) EmptySet Range will accept symbolic arguments but has very limited support for doing anything other than displaying the Range: >>> from sympy import Symbol, pprint >>> from sympy.abc import i, j, k >>> Range(i, j, k).start i >>> Range(i, j, k).inf Traceback (most recent call last): ... ValueError: invalid method for symbolic range Better success will be had when using integer symbols: >>> n = Symbol('n', integer=True) >>> r = Range(n, n + 20, 3) >>> r.inf n >>> pprint(r) {n, n + 3, ..., n + 18} """ is_iterable = True def __new__(cls, *args): from sympy.functions.elementary.integers import ceiling if len(args) == 1: if isinstance(args[0], range): raise TypeError( 'use sympify(%s) to convert range to Range' % args[0]) # expand range slc = slice(*args) if slc.step == 0: raise ValueError("step cannot be 0") start, stop, step = slc.start or 0, slc.stop, slc.step or 1 try: ok = [] for w in (start, stop, step): w = sympify(w) if w in [S.NegativeInfinity, S.Infinity] or ( w.has(Symbol) and w.is_integer != False): ok.append(w) elif not w.is_Integer: if w.is_infinite: raise ValueError('infinite symbols not allowed') raise ValueError else: ok.append(w) except ValueError: raise ValueError(filldedent(''' Finite arguments to Range must be integers; `imageset` can define other cases, e.g. use `imageset(i, i/10, Range(3))` to give [0, 1/10, 1/5].''')) start, stop, step = ok null = False if any(i.has(Symbol) for i in (start, stop, step)): dif = stop - start n = dif/step if n.is_Rational: from sympy import floor if dif == 0: null = True else: # (x, x + 5, 2) or (x, 3*x, x) n = floor(n) end = start + n*step if dif.is_Rational: # (x, x + 5, 2) if (end - stop).is_negative: end += step else: # (x, 3*x, x) if (end/stop - 1).is_negative: end += step elif n.is_extended_negative: null = True else: end = stop # other methods like sup and reversed must fail elif start.is_infinite: span = step*(stop - start) if span is S.NaN or span <= 0: null = True elif step.is_Integer and stop.is_infinite and abs(step) != 1: raise ValueError(filldedent(''' Step size must be %s in this case.''' % (1 if step > 0 else -1))) else: end = stop else: oostep = step.is_infinite if oostep: step = S.One if step > 0 else S.NegativeOne n = ceiling((stop - start)/step) if n <= 0: null = True elif oostep: step = S.One # make it canonical end = start + step else: end = start + n*step if null: start = end = S.Zero step = S.One return Basic.__new__(cls, start, end, step) start = property(lambda self: self.args[0]) stop = property(lambda self: self.args[1]) step = property(lambda self: self.args[2]) @property def reversed(self): """Return an equivalent Range in the opposite order. Examples ======== >>> from sympy import Range >>> Range(10).reversed Range(9, -1, -1) """ if self.has(Symbol): n = (self.stop - self.start)/self.step if not n.is_extended_positive or not all( i.is_integer or i.is_infinite for i in self.args): raise ValueError('invalid method for symbolic range') if self.start == self.stop: return self return self.func( self.stop - self.step, self.start - self.step, -self.step) def _contains(self, other): if self.start == self.stop: return S.false if other.is_infinite: return S.false if not other.is_integer: return other.is_integer if self.has(Symbol): n = (self.stop - self.start)/self.step if not n.is_extended_positive or not all( i.is_integer or i.is_infinite for i in self.args): return else: n = self.size if self.start.is_finite: ref = self.start elif self.stop.is_finite: ref = self.stop else: # both infinite; step is +/- 1 (enforced by __new__) return S.true if n == 1: return Eq(other, self[0]) res = (ref - other) % self.step if res == S.Zero: if self.has(Symbol): d = Dummy('i') return self.as_relational(d).subs(d, other) return And(other >= self.inf, other <= self.sup) elif res.is_Integer: # off sequence return S.false else: # symbolic/unsimplified residue modulo step return None def __iter__(self): n = self.size # validate if not (n.has(S.Infinity) or n.has(S.NegativeInfinity) or n.is_Integer): raise TypeError("Cannot iterate over symbolic Range") if self.start in [S.NegativeInfinity, S.Infinity]: raise TypeError("Cannot iterate over Range with infinite start") elif self.start != self.stop: i = self.start if n.is_infinite: while True: yield i i += self.step else: for j in range(n): yield i i += self.step def __len__(self): rv = self.size if rv is S.Infinity: raise ValueError('Use .size to get the length of an infinite Range') return int(rv) @property def size(self): if self.start == self.stop: return S.Zero dif = self.stop - self.start n = dif/self.step if n.is_infinite: return S.Infinity if n.is_extended_nonnegative and all(i.is_integer for i in self.args): from sympy.functions.elementary.integers import floor return abs(floor(n)) raise ValueError('Invalid method for symbolic Range') @property def is_finite_set(self): if self.start.is_integer and self.stop.is_integer: return True return self.size.is_finite def __bool__(self): # this only distinguishes between definite null range # and non-null/unknown null; getting True doesn't mean # that it actually is not null b = is_eq(self.start, self.stop) if b is None: raise ValueError('cannot tell if Range is null or not') return not bool(b) def __getitem__(self, i): from sympy.functions.elementary.integers import ceiling ooslice = "cannot slice from the end with an infinite value" zerostep = "slice step cannot be zero" infinite = "slicing not possible on range with infinite start" # if we had to take every other element in the following # oo, ..., 6, 4, 2, 0 # we might get oo, ..., 4, 0 or oo, ..., 6, 2 ambiguous = "cannot unambiguously re-stride from the end " + \ "with an infinite value" if isinstance(i, slice): if self.size.is_finite: # validates, too if self.start == self.stop: return Range(0) start, stop, step = i.indices(self.size) n = ceiling((stop - start)/step) if n <= 0: return Range(0) canonical_stop = start + n*step end = canonical_stop - step ss = step*self.step return Range(self[start], self[end] + ss, ss) else: # infinite Range start = i.start stop = i.stop if i.step == 0: raise ValueError(zerostep) step = i.step or 1 ss = step*self.step #--------------------- # handle infinite Range # i.e. Range(-oo, oo) or Range(oo, -oo, -1) # -------------------- if self.start.is_infinite and self.stop.is_infinite: raise ValueError(infinite) #--------------------- # handle infinite on right # e.g. Range(0, oo) or Range(0, -oo, -1) # -------------------- if self.stop.is_infinite: # start and stop are not interdependent -- # they only depend on step --so we use the # equivalent reversed values return self.reversed[ stop if stop is None else -stop + 1: start if start is None else -start: step].reversed #--------------------- # handle infinite on the left # e.g. Range(oo, 0, -1) or Range(-oo, 0) # -------------------- # consider combinations of # start/stop {== None, < 0, == 0, > 0} and # step {< 0, > 0} if start is None: if stop is None: if step < 0: return Range(self[-1], self.start, ss) elif step > 1: raise ValueError(ambiguous) else: # == 1 return self elif stop < 0: if step < 0: return Range(self[-1], self[stop], ss) else: # > 0 return Range(self.start, self[stop], ss) elif stop == 0: if step > 0: return Range(0) else: # < 0 raise ValueError(ooslice) elif stop == 1: if step > 0: raise ValueError(ooslice) # infinite singleton else: # < 0 raise ValueError(ooslice) else: # > 1 raise ValueError(ooslice) elif start < 0: if stop is None: if step < 0: return Range(self[start], self.start, ss) else: # > 0 return Range(self[start], self.stop, ss) elif stop < 0: return Range(self[start], self[stop], ss) elif stop == 0: if step < 0: raise ValueError(ooslice) else: # > 0 return Range(0) elif stop > 0: raise ValueError(ooslice) elif start == 0: if stop is None: if step < 0: raise ValueError(ooslice) # infinite singleton elif step > 1: raise ValueError(ambiguous) else: # == 1 return self elif stop < 0: if step > 1: raise ValueError(ambiguous) elif step == 1: return Range(self.start, self[stop], ss) else: # < 0 return Range(0) else: # >= 0 raise ValueError(ooslice) elif start > 0: raise ValueError(ooslice) else: if self.start == self.stop: raise IndexError('Range index out of range') if not (all(i.is_integer or i.is_infinite for i in self.args) and ((self.stop - self.start)/ self.step).is_extended_positive): raise ValueError('Invalid method for symbolic Range') if i == 0: if self.start.is_infinite: raise ValueError(ooslice) return self.start if i == -1: if self.stop.is_infinite: raise ValueError(ooslice) return self.stop - self.step n = self.size # must be known for any other index rv = (self.stop if i < 0 else self.start) + i*self.step if rv.is_infinite: raise ValueError(ooslice) val = (rv - self.start)/self.step rel = fuzzy_or([val.is_infinite, fuzzy_and([val.is_nonnegative, (n-val).is_nonnegative])]) if rel: return rv if rel is None: raise ValueError('Invalid method for symbolic Range') raise IndexError("Range index out of range") @property def _inf(self): if not self: return S.EmptySet.inf if self.has(Symbol): if all(i.is_integer or i.is_infinite for i in self.args): dif = self.stop - self.start if self.step.is_positive and dif.is_positive: return self.start elif self.step.is_negative and dif.is_negative: return self.stop - self.step raise ValueError('invalid method for symbolic range') if self.step > 0: return self.start else: return self.stop - self.step @property def _sup(self): if not self: return S.EmptySet.sup if self.has(Symbol): if all(i.is_integer or i.is_infinite for i in self.args): dif = self.stop - self.start if self.step.is_positive and dif.is_positive: return self.stop - self.step elif self.step.is_negative and dif.is_negative: return self.start raise ValueError('invalid method for symbolic range') if self.step > 0: return self.stop - self.step else: return self.start @property def _boundary(self): return self def as_relational(self, x): """Rewrite a Range in terms of equalities and logic operators. """ from sympy.core.mod import Mod if self.start.is_infinite: assert not self.stop.is_infinite # by instantiation a = self.reversed.start else: a = self.start step = self.step in_seq = Eq(Mod(x - a, step), 0) ints = And(Eq(Mod(a, 1), 0), Eq(Mod(step, 1), 0)) n = (self.stop - self.start)/self.step if n == 0: return S.EmptySet.as_relational(x) if n == 1: return And(Eq(x, a), ints) try: a, b = self.inf, self.sup except ValueError: a = None if a is not None: range_cond = And( x > a if a.is_infinite else x >= a, x < b if b.is_infinite else x <= b) else: a, b = self.start, self.stop - self.step range_cond = Or( And(self.step >= 1, x > a if a.is_infinite else x >= a, x < b if b.is_infinite else x <= b), And(self.step <= -1, x < a if a.is_infinite else x <= a, x > b if b.is_infinite else x >= b)) return And(in_seq, ints, range_cond) converter[range] = lambda r: Range(r.start, r.stop, r.step) def normalize_theta_set(theta): """ Normalize a Real Set `theta` in the Interval [0, 2*pi). It returns a normalized value of theta in the Set. For Interval, a maximum of one cycle [0, 2*pi], is returned i.e. for theta equal to [0, 10*pi], returned normalized value would be [0, 2*pi). As of now intervals with end points as non-multiples of `pi` is not supported. Raises ====== NotImplementedError The algorithms for Normalizing theta Set are not yet implemented. ValueError The input is not valid, i.e. the input is not a real set. RuntimeError It is a bug, please report to the github issue tracker. Examples ======== >>> from sympy.sets.fancysets import normalize_theta_set >>> from sympy import Interval, FiniteSet, pi >>> normalize_theta_set(Interval(9*pi/2, 5*pi)) Interval(pi/2, pi) >>> normalize_theta_set(Interval(-3*pi/2, pi/2)) Interval.Ropen(0, 2*pi) >>> normalize_theta_set(Interval(-pi/2, pi/2)) Union(Interval(0, pi/2), Interval.Ropen(3*pi/2, 2*pi)) >>> normalize_theta_set(Interval(-4*pi, 3*pi)) Interval.Ropen(0, 2*pi) >>> normalize_theta_set(Interval(-3*pi/2, -pi/2)) Interval(pi/2, 3*pi/2) >>> normalize_theta_set(FiniteSet(0, pi, 3*pi)) {0, pi} """ from sympy.functions.elementary.trigonometric import _pi_coeff as coeff if theta.is_Interval: interval_len = theta.measure # one complete circle if interval_len >= 2*S.Pi: if interval_len == 2*S.Pi and theta.left_open and theta.right_open: k = coeff(theta.start) return Union(Interval(0, k*S.Pi, False, True), Interval(k*S.Pi, 2*S.Pi, True, True)) return Interval(0, 2*S.Pi, False, True) k_start, k_end = coeff(theta.start), coeff(theta.end) if k_start is None or k_end is None: raise NotImplementedError("Normalizing theta without pi as coefficient is " "not yet implemented") new_start = k_start*S.Pi new_end = k_end*S.Pi if new_start > new_end: return Union(Interval(S.Zero, new_end, False, theta.right_open), Interval(new_start, 2*S.Pi, theta.left_open, True)) else: return Interval(new_start, new_end, theta.left_open, theta.right_open) elif theta.is_FiniteSet: new_theta = [] for element in theta: k = coeff(element) if k is None: raise NotImplementedError('Normalizing theta without pi as ' 'coefficient, is not Implemented.') else: new_theta.append(k*S.Pi) return FiniteSet(*new_theta) elif theta.is_Union: return Union(*[normalize_theta_set(interval) for interval in theta.args]) elif theta.is_subset(S.Reals): raise NotImplementedError("Normalizing theta when, it is of type %s is not " "implemented" % type(theta)) else: raise ValueError(" %s is not a real set" % (theta)) class ComplexRegion(Set): """ Represents the Set of all Complex Numbers. It can represent a region of Complex Plane in both the standard forms Polar and Rectangular coordinates. * Polar Form Input is in the form of the ProductSet or Union of ProductSets of the intervals of r and theta, & use the flag polar=True. Z = {z in C | z = r*[cos(theta) + I*sin(theta)], r in [r], theta in [theta]} * Rectangular Form Input is in the form of the ProductSet or Union of ProductSets of interval of x and y the of the Complex numbers in a Plane. Default input type is in rectangular form. Z = {z in C | z = x + I*y, x in [Re(z)], y in [Im(z)]} Examples ======== >>> from sympy.sets.fancysets import ComplexRegion >>> from sympy.sets import Interval >>> from sympy import S, I, Union >>> a = Interval(2, 3) >>> b = Interval(4, 6) >>> c = Interval(1, 8) >>> c1 = ComplexRegion(a*b) # Rectangular Form >>> c1 CartesianComplexRegion(ProductSet(Interval(2, 3), Interval(4, 6))) * c1 represents the rectangular region in complex plane surrounded by the coordinates (2, 4), (3, 4), (3, 6) and (2, 6), of the four vertices. >>> c2 = ComplexRegion(Union(a*b, b*c)) >>> c2 CartesianComplexRegion(Union(ProductSet(Interval(2, 3), Interval(4, 6)), ProductSet(Interval(4, 6), Interval(1, 8)))) * c2 represents the Union of two rectangular regions in complex plane. One of them surrounded by the coordinates of c1 and other surrounded by the coordinates (4, 1), (6, 1), (6, 8) and (4, 8). >>> 2.5 + 4.5*I in c1 True >>> 2.5 + 6.5*I in c1 False >>> r = Interval(0, 1) >>> theta = Interval(0, 2*S.Pi) >>> c2 = ComplexRegion(r*theta, polar=True) # Polar Form >>> c2 # unit Disk PolarComplexRegion(ProductSet(Interval(0, 1), Interval.Ropen(0, 2*pi))) * c2 represents the region in complex plane inside the Unit Disk centered at the origin. >>> 0.5 + 0.5*I in c2 True >>> 1 + 2*I in c2 False >>> unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, 2*S.Pi), polar=True) >>> upper_half_unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, S.Pi), polar=True) >>> intersection = unit_disk.intersect(upper_half_unit_disk) >>> intersection PolarComplexRegion(ProductSet(Interval(0, 1), Interval(0, pi))) >>> intersection == upper_half_unit_disk True See Also ======== CartesianComplexRegion PolarComplexRegion Complexes """ is_ComplexRegion = True def __new__(cls, sets, polar=False): if polar is False: return CartesianComplexRegion(sets) elif polar is True: return PolarComplexRegion(sets) else: raise ValueError("polar should be either True or False") @property def sets(self): """ Return raw input sets to the self. Examples ======== >>> from sympy import Interval, ComplexRegion, Union >>> a = Interval(2, 3) >>> b = Interval(4, 5) >>> c = Interval(1, 7) >>> C1 = ComplexRegion(a*b) >>> C1.sets ProductSet(Interval(2, 3), Interval(4, 5)) >>> C2 = ComplexRegion(Union(a*b, b*c)) >>> C2.sets Union(ProductSet(Interval(2, 3), Interval(4, 5)), ProductSet(Interval(4, 5), Interval(1, 7))) """ return self.args[0] @property def psets(self): """ Return a tuple of sets (ProductSets) input of the self. Examples ======== >>> from sympy import Interval, ComplexRegion, Union >>> a = Interval(2, 3) >>> b = Interval(4, 5) >>> c = Interval(1, 7) >>> C1 = ComplexRegion(a*b) >>> C1.psets (ProductSet(Interval(2, 3), Interval(4, 5)),) >>> C2 = ComplexRegion(Union(a*b, b*c)) >>> C2.psets (ProductSet(Interval(2, 3), Interval(4, 5)), ProductSet(Interval(4, 5), Interval(1, 7))) """ if self.sets.is_ProductSet: psets = () psets = psets + (self.sets, ) else: psets = self.sets.args return psets @property def a_interval(self): """ Return the union of intervals of `x` when, self is in rectangular form, or the union of intervals of `r` when self is in polar form. Examples ======== >>> from sympy import Interval, ComplexRegion, Union >>> a = Interval(2, 3) >>> b = Interval(4, 5) >>> c = Interval(1, 7) >>> C1 = ComplexRegion(a*b) >>> C1.a_interval Interval(2, 3) >>> C2 = ComplexRegion(Union(a*b, b*c)) >>> C2.a_interval Union(Interval(2, 3), Interval(4, 5)) """ a_interval = [] for element in self.psets: a_interval.append(element.args[0]) a_interval = Union(*a_interval) return a_interval @property def b_interval(self): """ Return the union of intervals of `y` when, self is in rectangular form, or the union of intervals of `theta` when self is in polar form. Examples ======== >>> from sympy import Interval, ComplexRegion, Union >>> a = Interval(2, 3) >>> b = Interval(4, 5) >>> c = Interval(1, 7) >>> C1 = ComplexRegion(a*b) >>> C1.b_interval Interval(4, 5) >>> C2 = ComplexRegion(Union(a*b, b*c)) >>> C2.b_interval Interval(1, 7) """ b_interval = [] for element in self.psets: b_interval.append(element.args[1]) b_interval = Union(*b_interval) return b_interval @property def _measure(self): """ The measure of self.sets. Examples ======== >>> from sympy import Interval, ComplexRegion, S >>> a, b = Interval(2, 5), Interval(4, 8) >>> c = Interval(0, 2*S.Pi) >>> c1 = ComplexRegion(a*b) >>> c1.measure 12 >>> c2 = ComplexRegion(a*c, polar=True) >>> c2.measure 6*pi """ return self.sets._measure @classmethod def from_real(cls, sets): """ Converts given subset of real numbers to a complex region. Examples ======== >>> from sympy import Interval, ComplexRegion >>> unit = Interval(0,1) >>> ComplexRegion.from_real(unit) CartesianComplexRegion(ProductSet(Interval(0, 1), {0})) """ if not sets.is_subset(S.Reals): raise ValueError("sets must be a subset of the real line") return CartesianComplexRegion(sets * FiniteSet(0)) def _contains(self, other): from sympy.functions import arg, Abs from sympy.core.containers import Tuple other = sympify(other) isTuple = isinstance(other, Tuple) if isTuple and len(other) != 2: raise ValueError('expecting Tuple of length 2') # If the other is not an Expression, and neither a Tuple if not isinstance(other, Expr) and not isinstance(other, Tuple): return S.false # self in rectangular form if not self.polar: re, im = other if isTuple else other.as_real_imag() return fuzzy_or(fuzzy_and([ pset.args[0]._contains(re), pset.args[1]._contains(im)]) for pset in self.psets) # self in polar form elif self.polar: if other.is_zero: # ignore undefined complex argument return fuzzy_or(pset.args[0]._contains(S.Zero) for pset in self.psets) if isTuple: r, theta = other else: r, theta = Abs(other), arg(other) if theta.is_real and theta.is_number: # angles in psets are normalized to [0, 2pi) theta %= 2*S.Pi return fuzzy_or(fuzzy_and([ pset.args[0]._contains(r), pset.args[1]._contains(theta)]) for pset in self.psets) class CartesianComplexRegion(ComplexRegion): """ Set representing a square region of the complex plane. Z = {z in C | z = x + I*y, x in [Re(z)], y in [Im(z)]} Examples ======== >>> from sympy.sets.fancysets import ComplexRegion >>> from sympy.sets.sets import Interval >>> from sympy import I >>> region = ComplexRegion(Interval(1, 3) * Interval(4, 6)) >>> 2 + 5*I in region True >>> 5*I in region False See also ======== ComplexRegion PolarComplexRegion Complexes """ polar = False variables = symbols('x, y', cls=Dummy) def __new__(cls, sets): if sets == S.Reals*S.Reals: return S.Complexes if all(_a.is_FiniteSet for _a in sets.args) and (len(sets.args) == 2): # ** ProductSet of FiniteSets in the Complex Plane. ** # For Cases like ComplexRegion({2, 4}*{3}), It # would return {2 + 3*I, 4 + 3*I} # FIXME: This should probably be handled with something like: # return ImageSet(Lambda((x, y), x+I*y), sets).rewrite(FiniteSet) complex_num = [] for x in sets.args[0]: for y in sets.args[1]: complex_num.append(x + S.ImaginaryUnit*y) return FiniteSet(*complex_num) else: return Set.__new__(cls, sets) @property def expr(self): x, y = self.variables return x + S.ImaginaryUnit*y class PolarComplexRegion(ComplexRegion): """ Set representing a polar region of the complex plane. Z = {z in C | z = r*[cos(theta) + I*sin(theta)], r in [r], theta in [theta]} Examples ======== >>> from sympy.sets.fancysets import ComplexRegion, Interval >>> from sympy import oo, pi, I >>> rset = Interval(0, oo) >>> thetaset = Interval(0, pi) >>> upper_half_plane = ComplexRegion(rset * thetaset, polar=True) >>> 1 + I in upper_half_plane True >>> 1 - I in upper_half_plane False See also ======== ComplexRegion CartesianComplexRegion Complexes """ polar = True variables = symbols('r, theta', cls=Dummy) def __new__(cls, sets): new_sets = [] # sets is Union of ProductSets if not sets.is_ProductSet: for k in sets.args: new_sets.append(k) # sets is ProductSets else: new_sets.append(sets) # Normalize input theta for k, v in enumerate(new_sets): new_sets[k] = ProductSet(v.args[0], normalize_theta_set(v.args[1])) sets = Union(*new_sets) return Set.__new__(cls, sets) @property def expr(self): from sympy.functions.elementary.trigonometric import sin, cos r, theta = self.variables return r*(cos(theta) + S.ImaginaryUnit*sin(theta)) class Complexes(CartesianComplexRegion, metaclass=Singleton): """ The Set of all complex numbers Examples ======== >>> from sympy import S, I >>> S.Complexes Complexes >>> 1 + I in S.Complexes True See also ======== Reals ComplexRegion """ is_empty = False is_finite_set = False # Override property from superclass since Complexes has no args @property def sets(self): return ProductSet(S.Reals, S.Reals) def __new__(cls): return Set.__new__(cls) def __str__(self): return "S.Complexes" def __repr__(self): return "S.Complexes" sympy-sympy-1.9/sympy/sets/handlers/000077500000000000000000000000001412543434000176625ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sets/handlers/__init__.py000066400000000000000000000000001412543434000217610ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sets/handlers/add.py000066400000000000000000000042041412543434000207640ustar00rootroot00000000000000from sympy import symbols, S, oo from sympy.core import Basic, Expr from sympy.core.numbers import Infinity, NegativeInfinity from sympy.multipledispatch import dispatch from sympy.sets import Interval, FiniteSet # XXX: The functions in this module are clearly not tested and are broken in a # number of ways. _x, _y = symbols("x y") @dispatch(Basic, Basic) # type: ignore # noqa:F811 def _set_add(x, y): # noqa:F811 return None @dispatch(Expr, Expr) # type: ignore # noqa:F811 def _set_add(x, y): # noqa:F811 return x+y @dispatch(Interval, Interval) # type: ignore # noqa:F811 def _set_add(x, y): # noqa:F811 """ Additions in interval arithmetic https://en.wikipedia.org/wiki/Interval_arithmetic """ return Interval(x.start + y.start, x.end + y.end, x.left_open or y.left_open, x.right_open or y.right_open) @dispatch(Interval, Infinity) # type: ignore # noqa:F811 def _set_add(x, y): # noqa:F811 if x.start is S.NegativeInfinity: return Interval(-oo, oo) return FiniteSet({S.Infinity}) @dispatch(Interval, NegativeInfinity) # type: ignore # noqa:F811 def _set_add(x, y): # noqa:F811 if x.end is S.Infinity: return Interval(-oo, oo) return FiniteSet({S.NegativeInfinity}) @dispatch(Basic, Basic) # type: ignore def _set_sub(x, y): # noqa:F811 return None @dispatch(Expr, Expr) # type: ignore # noqa:F811 def _set_sub(x, y): # noqa:F811 return x-y @dispatch(Interval, Interval) # type: ignore # noqa:F811 def _set_sub(x, y): # noqa:F811 """ Subtractions in interval arithmetic https://en.wikipedia.org/wiki/Interval_arithmetic """ return Interval(x.start - y.end, x.end - y.start, x.left_open or y.right_open, x.right_open or y.left_open) @dispatch(Interval, Infinity) # type: ignore # noqa:F811 def _set_sub(x, y): # noqa:F811 if x.start is S.NegativeInfinity: return Interval(-oo, oo) return FiniteSet(-oo) @dispatch(Interval, NegativeInfinity) # type: ignore # noqa:F811 def _set_sub(x, y): # noqa:F811 if x.start is S.NegativeInfinity: return Interval(-oo, oo) return FiniteSet(-oo) sympy-sympy-1.9/sympy/sets/handlers/comparison.py000066400000000000000000000031011412543434000224010ustar00rootroot00000000000000from sympy.core.relational import Eq, is_eq from sympy.core.basic import Basic from sympy.core.logic import fuzzy_and, fuzzy_bool from sympy.logic.boolalg import And from sympy.multipledispatch import dispatch from sympy.sets.sets import tfn, ProductSet, Interval, FiniteSet, Set @dispatch(Interval, FiniteSet) # type:ignore def _eval_is_eq(lhs, rhs): # noqa: F811 return False @dispatch(FiniteSet, Interval) # type:ignore def _eval_is_eq(lhs, rhs): # noqa: F811 return False @dispatch(Interval, Interval) # type:ignore def _eval_is_eq(lhs, rhs): # noqa: F811 return And(Eq(lhs.left, rhs.left), Eq(lhs.right, rhs.right), lhs.left_open == rhs.left_open, lhs.right_open == rhs.right_open) @dispatch(FiniteSet, FiniteSet) # type:ignore def _eval_is_eq(lhs, rhs): # noqa: F811 def all_in_both(): s_set = set(lhs.args) o_set = set(rhs.args) yield fuzzy_and(lhs._contains(e) for e in o_set - s_set) yield fuzzy_and(rhs._contains(e) for e in s_set - o_set) return tfn[fuzzy_and(all_in_both())] @dispatch(ProductSet, ProductSet) # type:ignore def _eval_is_eq(lhs, rhs): # noqa: F811 if len(lhs.sets) != len(rhs.sets): return False eqs = (is_eq(x, y) for x, y in zip(lhs.sets, rhs.sets)) return tfn[fuzzy_and(map(fuzzy_bool, eqs))] @dispatch(Set, Basic) # type:ignore def _eval_is_eq(lhs, rhs): # noqa: F811 return False @dispatch(Set, Set) # type:ignore def _eval_is_eq(lhs, rhs): # noqa: F811 return tfn[fuzzy_and(a.is_subset(b) for a, b in [(lhs, rhs), (rhs, lhs)])] sympy-sympy-1.9/sympy/sets/handlers/functions.py000066400000000000000000000210641412543434000222470ustar00rootroot00000000000000from sympy import Set, symbols, exp, log, S, Wild, Dummy, oo, Float from sympy.core import Expr, Add from sympy.core.function import Lambda, _coeff_isneg, FunctionClass from sympy.logic.boolalg import true from sympy.multipledispatch import dispatch from sympy.sets import (imageset, Interval, FiniteSet, Union, ImageSet, EmptySet, Intersection, Range) from sympy.sets.fancysets import Integers, Naturals, Reals from sympy.functions.elementary.exponential import match_real_imag _x, _y = symbols("x y") FunctionUnion = (FunctionClass, Lambda) @dispatch(FunctionClass, Set) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 return None @dispatch(FunctionUnion, FiniteSet) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 return FiniteSet(*map(f, x)) @dispatch(Lambda, Interval) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 from sympy.functions.elementary.miscellaneous import Min, Max from sympy.solvers.solveset import solveset from sympy.core.function import diff, Lambda from sympy.series import limit from sympy.calculus.singularities import singularities from sympy.sets import Complement # TODO: handle functions with infinitely many solutions (eg, sin, tan) # TODO: handle multivariate functions expr = f.expr if len(expr.free_symbols) > 1 or len(f.variables) != 1: return var = f.variables[0] if not var.is_real: if expr.subs(var, Dummy(real=True)).is_real is False: return if expr.is_Piecewise: result = S.EmptySet domain_set = x for (p_expr, p_cond) in expr.args: if p_cond is true: intrvl = domain_set else: intrvl = p_cond.as_set() intrvl = Intersection(domain_set, intrvl) if p_expr.is_Number: image = FiniteSet(p_expr) else: image = imageset(Lambda(var, p_expr), intrvl) result = Union(result, image) # remove the part which has been `imaged` domain_set = Complement(domain_set, intrvl) if domain_set is S.EmptySet: break return result if not x.start.is_comparable or not x.end.is_comparable: return try: from sympy.polys.polyutils import _nsort sing = list(singularities(expr, var, x)) if len(sing) > 1: sing = _nsort(sing) except NotImplementedError: return if x.left_open: _start = limit(expr, var, x.start, dir="+") elif x.start not in sing: _start = f(x.start) if x.right_open: _end = limit(expr, var, x.end, dir="-") elif x.end not in sing: _end = f(x.end) if len(sing) == 0: soln_expr = solveset(diff(expr, var), var) if not (isinstance(soln_expr, FiniteSet) or soln_expr is EmptySet): return solns = list(soln_expr) extr = [_start, _end] + [f(i) for i in solns if i.is_real and i in x] start, end = Min(*extr), Max(*extr) left_open, right_open = False, False if _start <= _end: # the minimum or maximum value can occur simultaneously # on both the edge of the interval and in some interior # point if start == _start and start not in solns: left_open = x.left_open if end == _end and end not in solns: right_open = x.right_open else: if start == _end and start not in solns: left_open = x.right_open if end == _start and end not in solns: right_open = x.left_open return Interval(start, end, left_open, right_open) else: return imageset(f, Interval(x.start, sing[0], x.left_open, True)) + \ Union(*[imageset(f, Interval(sing[i], sing[i + 1], True, True)) for i in range(0, len(sing) - 1)]) + \ imageset(f, Interval(sing[-1], x.end, True, x.right_open)) @dispatch(FunctionClass, Interval) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 if f == exp: return Interval(exp(x.start), exp(x.end), x.left_open, x.right_open) elif f == log: return Interval(log(x.start), log(x.end), x.left_open, x.right_open) return ImageSet(Lambda(_x, f(_x)), x) @dispatch(FunctionUnion, Union) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 return Union(*(imageset(f, arg) for arg in x.args)) @dispatch(FunctionUnion, Intersection) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 from sympy.sets.sets import is_function_invertible_in_set # If the function is invertible, intersect the maps of the sets. if is_function_invertible_in_set(f, x): return Intersection(*(imageset(f, arg) for arg in x.args)) else: return ImageSet(Lambda(_x, f(_x)), x) @dispatch(FunctionUnion, type(EmptySet)) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 return x @dispatch(FunctionUnion, Set) # type: ignore # noqa:F811 def _set_function(f, x): # noqa:F811 return ImageSet(Lambda(_x, f(_x)), x) @dispatch(FunctionUnion, Range) # type: ignore # noqa:F811 def _set_function(f, self): # noqa:F811 from sympy.core.function import expand_mul if not self: return S.EmptySet if not isinstance(f.expr, Expr): return if self.size == 1: return FiniteSet(f(self[0])) if f is S.IdentityFunction: return self x = f.variables[0] expr = f.expr # handle f that is linear in f's variable if x not in expr.free_symbols or x in expr.diff(x).free_symbols: return if self.start.is_finite: F = f(self.step*x + self.start) # for i in range(len(self)) else: F = f(-self.step*x + self[-1]) F = expand_mul(F) if F != expr: return imageset(x, F, Range(self.size)) @dispatch(FunctionUnion, Integers) # type: ignore # noqa:F811 def _set_function(f, self): # noqa:F811 expr = f.expr if not isinstance(expr, Expr): return n = f.variables[0] if expr == abs(n): return S.Naturals0 # f(x) + c and f(-x) + c cover the same integers # so choose the form that has the fewest negatives c = f(0) fx = f(n) - c f_x = f(-n) - c neg_count = lambda e: sum(_coeff_isneg(_) for _ in Add.make_args(e)) if neg_count(f_x) < neg_count(fx): expr = f_x + c a = Wild('a', exclude=[n]) b = Wild('b', exclude=[n]) match = expr.match(a*n + b) if match and match[a] and ( not match[a].atoms(Float) and not match[b].atoms(Float)): # canonical shift a, b = match[a], match[b] if a in [1, -1]: # drop integer addends in b nonint = [] for bi in Add.make_args(b): if not bi.is_integer: nonint.append(bi) b = Add(*nonint) if b.is_number and a.is_real: # avoid Mod for complex numbers, #11391 br, bi = match_real_imag(b) if br and br.is_comparable and a.is_comparable: br %= a b = br + S.ImaginaryUnit*bi elif b.is_number and a.is_imaginary: br, bi = match_real_imag(b) ai = a/S.ImaginaryUnit if bi and bi.is_comparable and ai.is_comparable: bi %= ai b = br + S.ImaginaryUnit*bi expr = a*n + b if expr != f.expr: return ImageSet(Lambda(n, expr), S.Integers) @dispatch(FunctionUnion, Naturals) # type: ignore # noqa:F811 def _set_function(f, self): # noqa:F811 expr = f.expr if not isinstance(expr, Expr): return x = f.variables[0] if not expr.free_symbols - {x}: if expr == abs(x): if self is S.Naturals: return self return S.Naturals0 step = expr.coeff(x) c = expr.subs(x, 0) if c.is_Integer and step.is_Integer and expr == step*x + c: if self is S.Naturals: c += step if step > 0: if step == 1: if c == 0: return S.Naturals0 elif c == 1: return S.Naturals return Range(c, oo, step) return Range(c, -oo, step) @dispatch(FunctionUnion, Reals) # type: ignore # noqa:F811 def _set_function(f, self): # noqa:F811 expr = f.expr if not isinstance(expr, Expr): return return _set_function(f, Interval(-oo, oo)) sympy-sympy-1.9/sympy/sets/handlers/intersection.py000066400000000000000000000411071412543434000227450ustar00rootroot00000000000000from sympy import (S, Dummy, Lambda, symbols, Interval, Intersection, Set, EmptySet, FiniteSet, Union, ComplexRegion, Mul) from sympy.multipledispatch import dispatch from sympy.sets.conditionset import ConditionSet from sympy.sets.fancysets import (Integers, Naturals, Reals, Range, ImageSet, Rationals) from sympy.sets.sets import UniversalSet, imageset, ProductSet from sympy.simplify.radsimp import numer @dispatch(ConditionSet, ConditionSet) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return None @dispatch(ConditionSet, Set) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return ConditionSet(a.sym, a.condition, Intersection(a.base_set, b)) @dispatch(Naturals, Integers) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return a @dispatch(Naturals, Naturals) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return a if a is S.Naturals else b @dispatch(Interval, Naturals) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return intersection_sets(b, a) @dispatch(ComplexRegion, Set) # type: ignore # noqa:F811 def intersection_sets(self, other): # noqa:F811 if other.is_ComplexRegion: # self in rectangular form if (not self.polar) and (not other.polar): return ComplexRegion(Intersection(self.sets, other.sets)) # self in polar form elif self.polar and other.polar: r1, theta1 = self.a_interval, self.b_interval r2, theta2 = other.a_interval, other.b_interval new_r_interval = Intersection(r1, r2) new_theta_interval = Intersection(theta1, theta2) # 0 and 2*Pi means the same if ((2*S.Pi in theta1 and S.Zero in theta2) or (2*S.Pi in theta2 and S.Zero in theta1)): new_theta_interval = Union(new_theta_interval, FiniteSet(0)) return ComplexRegion(new_r_interval*new_theta_interval, polar=True) if other.is_subset(S.Reals): new_interval = [] x = symbols("x", cls=Dummy, real=True) # self in rectangular form if not self.polar: for element in self.psets: if S.Zero in element.args[1]: new_interval.append(element.args[0]) new_interval = Union(*new_interval) return Intersection(new_interval, other) # self in polar form elif self.polar: for element in self.psets: if S.Zero in element.args[1]: new_interval.append(element.args[0]) if S.Pi in element.args[1]: new_interval.append(ImageSet(Lambda(x, -x), element.args[0])) if S.Zero in element.args[0]: new_interval.append(FiniteSet(0)) new_interval = Union(*new_interval) return Intersection(new_interval, other) @dispatch(Integers, Reals) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return a @dispatch(Range, Interval) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 from sympy.functions.elementary.integers import floor, ceiling if not all(i.is_number for i in b.args[:2]): return # In case of null Range, return an EmptySet. if a.size == 0: return S.EmptySet # trim down to self's size, and represent # as a Range with step 1. start = ceiling(max(b.inf, a.inf)) if start not in b: start += 1 end = floor(min(b.sup, a.sup)) if end not in b: end -= 1 return intersection_sets(a, Range(start, end + 1)) @dispatch(Range, Naturals) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return intersection_sets(a, Interval(b.inf, S.Infinity)) @dispatch(Range, Range) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 from sympy.solvers.diophantine.diophantine import diop_linear from sympy.core.numbers import ilcm from sympy import sign # non-overlap quick exits if not b: return S.EmptySet if not a: return S.EmptySet if b.sup < a.inf: return S.EmptySet if b.inf > a.sup: return S.EmptySet # work with finite end at the start r1 = a if r1.start.is_infinite: r1 = r1.reversed r2 = b if r2.start.is_infinite: r2 = r2.reversed # If both ends are infinite then it means that one Range is just the set # of all integers (the step must be 1). if r1.start.is_infinite: return b if r2.start.is_infinite: return a # this equation represents the values of the Range; # it's a linear equation eq = lambda r, i: r.start + i*r.step # we want to know when the two equations might # have integer solutions so we use the diophantine # solver va, vb = diop_linear(eq(r1, Dummy('a')) - eq(r2, Dummy('b'))) # check for no solution no_solution = va is None and vb is None if no_solution: return S.EmptySet # there is a solution # ------------------- # find the coincident point, c a0 = va.as_coeff_Add()[0] c = eq(r1, a0) # find the first point, if possible, in each range # since c may not be that point def _first_finite_point(r1, c): if c == r1.start: return c # st is the signed step we need to take to # get from c to r1.start st = sign(r1.start - c)*step # use Range to calculate the first point: # we want to get as close as possible to # r1.start; the Range will not be null since # it will at least contain c s1 = Range(c, r1.start + st, st)[-1] if s1 == r1.start: pass else: # if we didn't hit r1.start then, if the # sign of st didn't match the sign of r1.step # we are off by one and s1 is not in r1 if sign(r1.step) != sign(st): s1 -= st if s1 not in r1: return return s1 # calculate the step size of the new Range step = abs(ilcm(r1.step, r2.step)) s1 = _first_finite_point(r1, c) if s1 is None: return S.EmptySet s2 = _first_finite_point(r2, c) if s2 is None: return S.EmptySet # replace the corresponding start or stop in # the original Ranges with these points; the # result must have at least one point since # we know that s1 and s2 are in the Ranges def _updated_range(r, first): st = sign(r.step)*step if r.start.is_finite: rv = Range(first, r.stop, st) else: rv = Range(r.start, first + st, st) return rv r1 = _updated_range(a, s1) r2 = _updated_range(b, s2) # work with them both in the increasing direction if sign(r1.step) < 0: r1 = r1.reversed if sign(r2.step) < 0: r2 = r2.reversed # return clipped Range with positive step; it # can't be empty at this point start = max(r1.start, r2.start) stop = min(r1.stop, r2.stop) return Range(start, stop, step) @dispatch(Range, Integers) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return a @dispatch(ImageSet, Set) # type: ignore # noqa:F811 def intersection_sets(self, other): # noqa:F811 from sympy.solvers.diophantine import diophantine # Only handle the straight-forward univariate case if (len(self.lamda.variables) > 1 or self.lamda.signature != self.lamda.variables): return None base_set = self.base_sets[0] # Intersection between ImageSets with Integers as base set # For {f(n) : n in Integers} & {g(m) : m in Integers} we solve the # diophantine equations f(n)=g(m). # If the solutions for n are {h(t) : t in Integers} then we return # {f(h(t)) : t in integers}. # If the solutions for n are {n_1, n_2, ..., n_k} then we return # {f(n_i) : 1 <= i <= k}. if base_set is S.Integers: gm = None if isinstance(other, ImageSet) and other.base_sets == (S.Integers,): gm = other.lamda.expr var = other.lamda.variables[0] # Symbol of second ImageSet lambda must be distinct from first m = Dummy('m') gm = gm.subs(var, m) elif other is S.Integers: m = gm = Dummy('m') if gm is not None: fn = self.lamda.expr n = self.lamda.variables[0] try: solns = list(diophantine(fn - gm, syms=(n, m), permute=True)) except (TypeError, NotImplementedError): # TypeError if equation not polynomial with rational coeff. # NotImplementedError if correct format but no solver. return # 3 cases are possible for solns: # - empty set, # - one or more parametric (infinite) solutions, # - a finite number of (non-parametric) solution couples. # Among those, there is one type of solution set that is # not helpful here: multiple parametric solutions. if len(solns) == 0: return EmptySet elif any(not isinstance(s, int) and s.free_symbols for tupl in solns for s in tupl): if len(solns) == 1: soln, solm = solns[0] (t,) = soln.free_symbols expr = fn.subs(n, soln.subs(t, n)).expand() return imageset(Lambda(n, expr), S.Integers) else: return else: return FiniteSet(*(fn.subs(n, s[0]) for s in solns)) if other == S.Reals: from sympy.core.function import expand_complex from sympy.solvers.solvers import denoms, solve_linear from sympy.core.relational import Eq def _solution_union(exprs, sym): # return a union of linear solutions to i in expr; # if i cannot be solved, use a ConditionSet for solution sols = [] for i in exprs: x, xis = solve_linear(i, 0, [sym]) if x == sym: sols.append(FiniteSet(xis)) else: sols.append(ConditionSet(sym, Eq(i, 0))) return Union(*sols) f = self.lamda.expr n = self.lamda.variables[0] n_ = Dummy(n.name, real=True) f_ = f.subs(n, n_) re, im = f_.as_real_imag() im = expand_complex(im) re = re.subs(n_, n) im = im.subs(n_, n) ifree = im.free_symbols lam = Lambda(n, re) if im.is_zero: # allow re-evaluation # of self in this case to make # the result canonical pass elif im.is_zero is False: return S.EmptySet elif ifree != {n}: return None else: # univarite imaginary part in same variable; # use numer instead of as_numer_denom to keep # this as fast as possible while still handling # simple cases base_set &= _solution_union( Mul.make_args(numer(im)), n) # exclude values that make denominators 0 base_set -= _solution_union(denoms(f), n) return imageset(lam, base_set) elif isinstance(other, Interval): from sympy.solvers.solveset import (invert_real, invert_complex, solveset) f = self.lamda.expr n = self.lamda.variables[0] new_inf, new_sup = None, None new_lopen, new_ropen = other.left_open, other.right_open if f.is_real: inverter = invert_real else: inverter = invert_complex g1, h1 = inverter(f, other.inf, n) g2, h2 = inverter(f, other.sup, n) if all(isinstance(i, FiniteSet) for i in (h1, h2)): if g1 == n: if len(h1) == 1: new_inf = h1.args[0] if g2 == n: if len(h2) == 1: new_sup = h2.args[0] # TODO: Design a technique to handle multiple-inverse # functions # Any of the new boundary values cannot be determined if any(i is None for i in (new_sup, new_inf)): return range_set = S.EmptySet if all(i.is_real for i in (new_sup, new_inf)): # this assumes continuity of underlying function # however fixes the case when it is decreasing if new_inf > new_sup: new_inf, new_sup = new_sup, new_inf new_interval = Interval(new_inf, new_sup, new_lopen, new_ropen) range_set = base_set.intersect(new_interval) else: if other.is_subset(S.Reals): solutions = solveset(f, n, S.Reals) if not isinstance(range_set, (ImageSet, ConditionSet)): range_set = solutions.intersect(other) else: return if range_set is S.EmptySet: return S.EmptySet elif isinstance(range_set, Range) and range_set.size is not S.Infinity: range_set = FiniteSet(*list(range_set)) if range_set is not None: return imageset(Lambda(n, f), range_set) return else: return @dispatch(ProductSet, ProductSet) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 if len(b.args) != len(a.args): return S.EmptySet return ProductSet(*(i.intersect(j) for i, j in zip(a.sets, b.sets))) @dispatch(Interval, Interval) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 # handle (-oo, oo) infty = S.NegativeInfinity, S.Infinity if a == Interval(*infty): l, r = a.left, a.right if l.is_real or l in infty or r.is_real or r in infty: return b # We can't intersect [0,3] with [x,6] -- we don't know if x>0 or x<0 if not a._is_comparable(b): return None empty = False if a.start <= b.end and b.start <= a.end: # Get topology right. if a.start < b.start: start = b.start left_open = b.left_open elif a.start > b.start: start = a.start left_open = a.left_open else: start = a.start left_open = a.left_open or b.left_open if a.end < b.end: end = a.end right_open = a.right_open elif a.end > b.end: end = b.end right_open = b.right_open else: end = a.end right_open = a.right_open or b.right_open if end - start == 0 and (left_open or right_open): empty = True else: empty = True if empty: return S.EmptySet return Interval(start, end, left_open, right_open) @dispatch(type(EmptySet), Set) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return S.EmptySet @dispatch(UniversalSet, Set) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return b @dispatch(FiniteSet, FiniteSet) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return FiniteSet(*(a._elements & b._elements)) @dispatch(FiniteSet, Set) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 try: return FiniteSet(*[el for el in a if el in b]) except TypeError: return None # could not evaluate `el in b` due to symbolic ranges. @dispatch(Set, Set) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return None @dispatch(Integers, Rationals) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return a @dispatch(Naturals, Rationals) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return a @dispatch(Rationals, Reals) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return a def _intlike_interval(a, b): try: from sympy.functions.elementary.integers import floor, ceiling if b._inf is S.NegativeInfinity and b._sup is S.Infinity: return a s = Range(max(a.inf, ceiling(b.left)), floor(b.right) + 1) return intersection_sets(s, b) # take out endpoints if open interval except ValueError: return None @dispatch(Integers, Interval) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return _intlike_interval(a, b) @dispatch(Naturals, Interval) # type: ignore # noqa:F811 def intersection_sets(a, b): # noqa:F811 return _intlike_interval(a, b) sympy-sympy-1.9/sympy/sets/handlers/issubset.py000066400000000000000000000122041412543434000220740ustar00rootroot00000000000000from sympy import S, Symbol from sympy.core.logic import fuzzy_and, fuzzy_bool, fuzzy_not, fuzzy_or from sympy.core.relational import Eq from sympy.sets.sets import FiniteSet, Interval, Set, Union, ProductSet from sympy.sets.fancysets import Complexes, Reals, Range, Rationals from sympy.multipledispatch import dispatch _inf_sets = [S.Naturals, S.Naturals0, S.Integers, S.Rationals, S.Reals, S.Complexes] @dispatch(Set, Set) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 return None @dispatch(Interval, Interval) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 # This is correct but can be made more comprehensive... if fuzzy_bool(a.start < b.start): return False if fuzzy_bool(a.end > b.end): return False if (b.left_open and not a.left_open and fuzzy_bool(Eq(a.start, b.start))): return False if (b.right_open and not a.right_open and fuzzy_bool(Eq(a.end, b.end))): return False @dispatch(Interval, FiniteSet) # type: ignore # noqa:F811 def is_subset_sets(a_interval, b_fs): # noqa:F811 # An Interval can only be a subset of a finite set if it is finite # which can only happen if it has zero measure. if fuzzy_not(a_interval.measure.is_zero): return False @dispatch(Interval, Union) # type: ignore # noqa:F811 def is_subset_sets(a_interval, b_u): # noqa:F811 if all(isinstance(s, (Interval, FiniteSet)) for s in b_u.args): intervals = [s for s in b_u.args if isinstance(s, Interval)] if all(fuzzy_bool(a_interval.start < s.start) for s in intervals): return False if all(fuzzy_bool(a_interval.end > s.end) for s in intervals): return False if a_interval.measure.is_nonzero: no_overlap = lambda s1, s2: fuzzy_or([ fuzzy_bool(s1.end <= s2.start), fuzzy_bool(s1.start >= s2.end), ]) if all(no_overlap(s, a_interval) for s in intervals): return False @dispatch(Range, Range) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 if a.step == b.step == 1: return fuzzy_and([fuzzy_bool(a.start >= b.start), fuzzy_bool(a.stop <= b.stop)]) @dispatch(Range, Interval) # type: ignore # noqa:F811 def is_subset_sets(a_range, b_interval): # noqa:F811 if a_range.step.is_positive: if b_interval.left_open and a_range.inf.is_finite: cond_left = a_range.inf > b_interval.left else: cond_left = a_range.inf >= b_interval.left if b_interval.right_open and a_range.sup.is_finite: cond_right = a_range.sup < b_interval.right else: cond_right = a_range.sup <= b_interval.right return fuzzy_and([cond_left, cond_right]) @dispatch(Range, FiniteSet) # type: ignore # noqa:F811 def is_subset_sets(a_range, b_finiteset): # noqa:F811 try: a_size = a_range.size except ValueError: # symbolic Range of unknown size return None if a_size > len(b_finiteset): return False elif any(arg.has(Symbol) for arg in a_range.args): return fuzzy_and(b_finiteset.contains(x) for x in a_range) else: # Checking A \ B == EmptySet is more efficient than repeated naive # membership checks on an arbitrary FiniteSet. a_set = set(a_range) b_remaining = len(b_finiteset) # Symbolic expressions and numbers of unknown type (integer or not) are # all counted as "candidates", i.e. *potentially* matching some a in # a_range. cnt_candidate = 0 for b in b_finiteset: if b.is_Integer: a_set.discard(b) elif fuzzy_not(b.is_integer): pass else: cnt_candidate += 1 b_remaining -= 1 if len(a_set) > b_remaining + cnt_candidate: return False if len(a_set) == 0: return True return None @dispatch(Interval, Range) # type: ignore # noqa:F811 def is_subset_sets(a_interval, b_range): # noqa:F811 if a_interval.measure.is_extended_nonzero: return False @dispatch(Interval, Rationals) # type: ignore # noqa:F811 def is_subset_sets(a_interval, b_rationals): # noqa:F811 if a_interval.measure.is_extended_nonzero: return False @dispatch(Range, Complexes) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 return True @dispatch(Complexes, Interval) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 return False @dispatch(Complexes, Range) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 return False @dispatch(Complexes, Rationals) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 return False @dispatch(Rationals, Reals) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 return True @dispatch(Rationals, Range) # type: ignore # noqa:F811 def is_subset_sets(a, b): # noqa:F811 return False @dispatch(ProductSet, FiniteSet) # type: ignore # noqa:F811 def is_subset_sets(a_ps, b_fs): # noqa:F811 return fuzzy_and(b_fs.contains(x) for x in a_ps) sympy-sympy-1.9/sympy/sets/handlers/mul.py000066400000000000000000000040171412543434000210330ustar00rootroot00000000000000from sympy import Set, symbols from sympy.core import Basic, Expr from sympy.multipledispatch import dispatch from sympy.sets import Interval _x, _y = symbols("x y") @dispatch(Basic, Basic) # type: ignore # noqa:F811 def _set_mul(x, y): # noqa:F811 return None @dispatch(Set, Set) # type: ignore # noqa:F811 def _set_mul(x, y): # noqa:F811 return None @dispatch(Expr, Expr) # type: ignore # noqa:F811 def _set_mul(x, y): # noqa:F811 return x*y @dispatch(Interval, Interval) # type: ignore # noqa:F811 def _set_mul(x, y): # noqa:F811 """ Multiplications in interval arithmetic https://en.wikipedia.org/wiki/Interval_arithmetic """ # TODO: some intervals containing 0 and oo will fail as 0*oo returns nan. comvals = ( (x.start * y.start, bool(x.left_open or y.left_open)), (x.start * y.end, bool(x.left_open or y.right_open)), (x.end * y.start, bool(x.right_open or y.left_open)), (x.end * y.end, bool(x.right_open or y.right_open)), ) # TODO: handle symbolic intervals minval, minopen = min(comvals) maxval, maxopen = max(comvals) return Interval( minval, maxval, minopen, maxopen ) @dispatch(Basic, Basic) # type: ignore # noqa:F811 def _set_div(x, y): # noqa:F811 return None @dispatch(Expr, Expr) # type: ignore # noqa:F811 def _set_div(x, y): # noqa:F811 return x/y @dispatch(Set, Set) # type: ignore # noqa:F811 # noqa:F811 def _set_div(x, y): # noqa:F811 return None @dispatch(Interval, Interval) # type: ignore # noqa:F811 def _set_div(x, y): # noqa:F811 """ Divisions in interval arithmetic https://en.wikipedia.org/wiki/Interval_arithmetic """ from sympy.sets.setexpr import set_mul from sympy import oo if (y.start*y.end).is_negative: return Interval(-oo, oo) if y.start == 0: s2 = oo else: s2 = 1/y.start if y.end == 0: s1 = -oo else: s1 = 1/y.end return set_mul(x, Interval(s1, s2, y.right_open, y.left_open)) sympy-sympy-1.9/sympy/sets/handlers/power.py000066400000000000000000000062641412543434000214000ustar00rootroot00000000000000from sympy import Min, Max, Set, Lambda, symbols, S, oo from sympy.core import Basic, Expr, Integer from sympy.core.numbers import Infinity, NegativeInfinity, Zero from sympy.multipledispatch import dispatch from sympy.sets import Interval, FiniteSet, Union, ImageSet _x, _y = symbols("x y") @dispatch(Basic, Basic) # type: ignore # noqa:F811 def _set_pow(x, y): # noqa:F811 return None @dispatch(Set, Set) # type: ignore # noqa:F811 def _set_pow(x, y): # noqa:F811 return ImageSet(Lambda((_x, _y), (_x ** _y)), x, y) @dispatch(Expr, Expr) # type: ignore # noqa:F811 def _set_pow(x, y): # noqa:F811 return x**y @dispatch(Interval, Zero) # type: ignore # noqa:F811 def _set_pow(x, z): # noqa:F811 return FiniteSet(S.One) @dispatch(Interval, Integer) # type: ignore # noqa:F811 def _set_pow(x, exponent): # noqa:F811 """ Powers in interval arithmetic https://en.wikipedia.org/wiki/Interval_arithmetic """ s1 = x.start**exponent s2 = x.end**exponent if ((s2 > s1) if exponent > 0 else (x.end > -x.start)) == True: left_open = x.left_open right_open = x.right_open # TODO: handle unevaluated condition. sleft = s2 else: # TODO: `s2 > s1` could be unevaluated. left_open = x.right_open right_open = x.left_open sleft = s1 if x.start.is_positive: return Interval( Min(s1, s2), Max(s1, s2), left_open, right_open) elif x.end.is_negative: return Interval( Min(s1, s2), Max(s1, s2), left_open, right_open) # Case where x.start < 0 and x.end > 0: if exponent.is_odd: if exponent.is_negative: if x.start.is_zero: return Interval(s2, oo, x.right_open) if x.end.is_zero: return Interval(-oo, s1, True, x.left_open) return Union(Interval(-oo, s1, True, x.left_open), Interval(s2, oo, x.right_open)) else: return Interval(s1, s2, x.left_open, x.right_open) elif exponent.is_even: if exponent.is_negative: if x.start.is_zero: return Interval(s2, oo, x.right_open) if x.end.is_zero: return Interval(s1, oo, x.left_open) return Interval(0, oo) else: return Interval(S.Zero, sleft, S.Zero not in x, left_open) @dispatch(Interval, Infinity) # type: ignore # noqa:F811 def _set_pow(b, e): # noqa:F811 # TODO: add logic for open intervals? if b.start.is_nonnegative: if b.end < 1: return FiniteSet(S.Zero) if b.start > 1: return FiniteSet(S.Infinity) return Interval(0, oo) elif b.end.is_negative: if b.start > -1: return FiniteSet(S.Zero) if b.end < -1: return FiniteSet(-oo, oo) return Interval(-oo, oo) else: if b.start > -1: if b.end < 1: return FiniteSet(S.Zero) return Interval(0, oo) return Interval(-oo, oo) @dispatch(Interval, NegativeInfinity) # type: ignore # noqa:F811 def _set_pow(b, e): # noqa:F811 from sympy.sets.setexpr import set_div return _set_pow(set_div(S.One, b), oo) sympy-sympy-1.9/sympy/sets/handlers/union.py000066400000000000000000000114211412543434000213630ustar00rootroot00000000000000from sympy import (Interval, Intersection, Set, EmptySet, S, sympify, FiniteSet, Union, ComplexRegion, ProductSet) from sympy.multipledispatch import dispatch from sympy.sets.fancysets import (Naturals, Naturals0, Integers, Rationals, Reals) from sympy.sets.sets import UniversalSet @dispatch(Naturals0, Naturals) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return a @dispatch(Rationals, Naturals) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return a @dispatch(Rationals, Naturals0) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return a @dispatch(Reals, Naturals) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return a @dispatch(Reals, Naturals0) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return a @dispatch(Reals, Rationals) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return a @dispatch(Integers, Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 intersect = Intersection(a, b) if intersect == a: return b elif intersect == b: return a @dispatch(ComplexRegion, Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 if b.is_subset(S.Reals): # treat a subset of reals as a complex region b = ComplexRegion.from_real(b) if b.is_ComplexRegion: # a in rectangular form if (not a.polar) and (not b.polar): return ComplexRegion(Union(a.sets, b.sets)) # a in polar form elif a.polar and b.polar: return ComplexRegion(Union(a.sets, b.sets), polar=True) return None @dispatch(type(EmptySet), Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return b @dispatch(UniversalSet, Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return a @dispatch(ProductSet, ProductSet) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 if b.is_subset(a): return a if len(b.sets) != len(a.sets): return None if len(a.sets) == 2: a1, a2 = a.sets b1, b2 = b.sets if a1 == b1: return a1 * Union(a2, b2) if a2 == b2: return Union(a1, b1) * a2 return None @dispatch(ProductSet, Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 if b.is_subset(a): return a return None @dispatch(Interval, Interval) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 if a._is_comparable(b): from sympy.functions.elementary.miscellaneous import Min, Max # Non-overlapping intervals end = Min(a.end, b.end) start = Max(a.start, b.start) if (end < start or (end == start and (end not in a and end not in b))): return None else: start = Min(a.start, b.start) end = Max(a.end, b.end) left_open = ((a.start != start or a.left_open) and (b.start != start or b.left_open)) right_open = ((a.end != end or a.right_open) and (b.end != end or b.right_open)) return Interval(start, end, left_open, right_open) @dispatch(Interval, UniversalSet) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return S.UniversalSet @dispatch(Interval, Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 # If I have open end points and these endpoints are contained in b # But only in case, when endpoints are finite. Because # interval does not contain oo or -oo. open_left_in_b_and_finite = (a.left_open and sympify(b.contains(a.start)) is S.true and a.start.is_finite) open_right_in_b_and_finite = (a.right_open and sympify(b.contains(a.end)) is S.true and a.end.is_finite) if open_left_in_b_and_finite or open_right_in_b_and_finite: # Fill in my end points and return open_left = a.left_open and a.start not in b open_right = a.right_open and a.end not in b new_a = Interval(a.start, a.end, open_left, open_right) return {new_a, b} return None @dispatch(FiniteSet, FiniteSet) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return FiniteSet(*(a._elements | b._elements)) @dispatch(FiniteSet, Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 # If `b` set contains one of my elements, remove it from `a` if any(b.contains(x) == True for x in a): return { FiniteSet(*[x for x in a if b.contains(x) != True]), b} return None @dispatch(Set, Set) # type: ignore # noqa:F811 def union_sets(a, b): # noqa:F811 return None sympy-sympy-1.9/sympy/sets/ordinals.py000066400000000000000000000166371412543434000202640ustar00rootroot00000000000000from sympy.core import Basic, Integer import operator class OmegaPower(Basic): """ Represents ordinal exponential and multiplication terms one of the building blocks of the Ordinal class. In OmegaPower(a, b) a represents exponent and b represents multiplicity. """ def __new__(cls, a, b): if isinstance(b, int): b = Integer(b) if not isinstance(b, Integer) or b <= 0: raise TypeError("multiplicity must be a positive integer") if not isinstance(a, Ordinal): a = Ordinal.convert(a) return Basic.__new__(cls, a, b) @property def exp(self): return self.args[0] @property def mult(self): return self.args[1] def _compare_term(self, other, op): if self.exp == other.exp: return op(self.mult, other.mult) else: return op(self.exp, other.exp) def __eq__(self, other): if not isinstance(other, OmegaPower): try: other = OmegaPower(0, other) except TypeError: return NotImplemented return self.args == other.args def __hash__(self): return Basic.__hash__(self) def __lt__(self, other): if not isinstance(other, OmegaPower): try: other = OmegaPower(0, other) except TypeError: return NotImplemented return self._compare_term(other, operator.lt) class Ordinal(Basic): """ Represents ordinals in Cantor normal form. Internally, this class is just a list of instances of OmegaPower. Examples ======== >>> from sympy.sets import Ordinal, OmegaPower >>> from sympy.sets.ordinals import omega >>> w = omega >>> w.is_limit_ordinal True >>> Ordinal(OmegaPower(w + 1 ,1), OmegaPower(3, 2)) w**(w + 1) + w**3*2 >>> 3 + w w >>> (w + 1) * w w**2 References ========== .. [1] https://en.wikipedia.org/wiki/Ordinal_arithmetic """ def __new__(cls, *terms): obj = super().__new__(cls, *terms) powers = [i.exp for i in obj.args] if not all(powers[i] >= powers[i+1] for i in range(len(powers) - 1)): raise ValueError("powers must be in decreasing order") return obj @property def terms(self): return self.args @property def leading_term(self): if self == ord0: raise ValueError("ordinal zero has no leading term") return self.terms[0] @property def trailing_term(self): if self == ord0: raise ValueError("ordinal zero has no trailing term") return self.terms[-1] @property def is_successor_ordinal(self): try: return self.trailing_term.exp == ord0 except ValueError: return False @property def is_limit_ordinal(self): try: return not self.trailing_term.exp == ord0 except ValueError: return False @property def degree(self): return self.leading_term.exp @classmethod def convert(cls, integer_value): if integer_value == 0: return ord0 return Ordinal(OmegaPower(0, integer_value)) def __eq__(self, other): if not isinstance(other, Ordinal): try: other = Ordinal.convert(other) except TypeError: return NotImplemented return self.terms == other.terms def __hash__(self): return hash(self.args) def __lt__(self, other): if not isinstance(other, Ordinal): try: other = Ordinal.convert(other) except TypeError: return NotImplemented for term_self, term_other in zip(self.terms, other.terms): if term_self != term_other: return term_self < term_other return len(self.terms) < len(other.terms) def __le__(self, other): return (self == other or self < other) def __gt__(self, other): return not self <= other def __ge__(self, other): return not self < other def __str__(self): net_str = "" plus_count = 0 if self == ord0: return 'ord0' for i in self.terms: if plus_count: net_str += " + " if i.exp == ord0: net_str += str(i.mult) elif i.exp == 1: net_str += 'w' elif len(i.exp.terms) > 1 or i.exp.is_limit_ordinal: net_str += 'w**(%s)'%i.exp else: net_str += 'w**%s'%i.exp if not i.mult == 1 and not i.exp == ord0: net_str += '*%s'%i.mult plus_count += 1 return(net_str) __repr__ = __str__ def __add__(self, other): if not isinstance(other, Ordinal): try: other = Ordinal.convert(other) except TypeError: return NotImplemented if other == ord0: return self a_terms = list(self.terms) b_terms = list(other.terms) r = len(a_terms) - 1 b_exp = other.degree while r >= 0 and a_terms[r].exp < b_exp: r -= 1 if r < 0: terms = b_terms elif a_terms[r].exp == b_exp: sum_term = OmegaPower(b_exp, a_terms[r].mult + other.leading_term.mult) terms = a_terms[:r] + [sum_term] + b_terms[1:] else: terms = a_terms[:r+1] + b_terms return Ordinal(*terms) def __radd__(self, other): if not isinstance(other, Ordinal): try: other = Ordinal.convert(other) except TypeError: return NotImplemented return other + self def __mul__(self, other): if not isinstance(other, Ordinal): try: other = Ordinal.convert(other) except TypeError: return NotImplemented if ord0 in (self, other): return ord0 a_exp = self.degree a_mult = self.leading_term.mult sum = [] if other.is_limit_ordinal: for arg in other.terms: sum.append(OmegaPower(a_exp + arg.exp, arg.mult)) else: for arg in other.terms[:-1]: sum.append(OmegaPower(a_exp + arg.exp, arg.mult)) b_mult = other.trailing_term.mult sum.append(OmegaPower(a_exp, a_mult*b_mult)) sum += list(self.terms[1:]) return Ordinal(*sum) def __rmul__(self, other): if not isinstance(other, Ordinal): try: other = Ordinal.convert(other) except TypeError: return NotImplemented return other * self def __pow__(self, other): if not self == omega: return NotImplemented return Ordinal(OmegaPower(other, 1)) class OrdinalZero(Ordinal): """The ordinal zero. OrdinalZero can be imported as ``ord0``. """ pass class OrdinalOmega(Ordinal): """The ordinal omega which forms the base of all ordinals in cantor normal form. OrdinalOmega can be imported as ``omega``. Examples ======== >>> from sympy.sets.ordinals import omega >>> omega + omega w*2 """ def __new__(cls): return Ordinal.__new__(cls) @property def terms(self): return (OmegaPower(1, 1),) ord0 = OrdinalZero() omega = OrdinalOmega() sympy-sympy-1.9/sympy/sets/powerset.py000066400000000000000000000055171412543434000203140ustar00rootroot00000000000000from sympy.core.decorators import _sympifyit from sympy.core.parameters import global_parameters from sympy.core.logic import fuzzy_bool from sympy.core.singleton import S from sympy.core.sympify import _sympify from .sets import Set class PowerSet(Set): r"""A symbolic object representing a power set. Parameters ========== arg : Set The set to take power of. evaluate : bool The flag to control evaluation. If the evaluation is disabled for finite sets, it can take advantage of using subset test as a membership test. Notes ===== Power set `\mathcal{P}(S)` is defined as a set containing all the subsets of `S`. If the set `S` is a finite set, its power set would have `2^{\left| S \right|}` elements, where `\left| S \right|` denotes the cardinality of `S`. Examples ======== >>> from sympy.sets.powerset import PowerSet >>> from sympy import S, FiniteSet A power set of a finite set: >>> PowerSet(FiniteSet(1, 2, 3)) PowerSet({1, 2, 3}) A power set of an empty set: >>> PowerSet(S.EmptySet) PowerSet(EmptySet) >>> PowerSet(PowerSet(S.EmptySet)) PowerSet(PowerSet(EmptySet)) A power set of an infinite set: >>> PowerSet(S.Reals) PowerSet(Reals) Evaluating the power set of a finite set to its explicit form: >>> PowerSet(FiniteSet(1, 2, 3)).rewrite(FiniteSet) FiniteSet(EmptySet, {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}) References ========== .. [1] https://en.wikipedia.org/wiki/Power_set .. [2] https://en.wikipedia.org/wiki/Axiom_of_power_set """ def __new__(cls, arg, evaluate=None): if evaluate is None: evaluate=global_parameters.evaluate arg = _sympify(arg) if not isinstance(arg, Set): raise ValueError('{} must be a set.'.format(arg)) return super().__new__(cls, arg) @property def arg(self): return self.args[0] def _eval_rewrite_as_FiniteSet(self, *args, **kwargs): arg = self.arg if arg.is_FiniteSet: return arg.powerset() return None @_sympifyit('other', NotImplemented) def _contains(self, other): if not isinstance(other, Set): return None return fuzzy_bool(self.arg.is_superset(other)) def _eval_is_subset(self, other): if isinstance(other, PowerSet): return self.arg.is_subset(other.arg) def __len__(self): return 2 ** len(self.arg) def __iter__(self): from .sets import FiniteSet found = [S.EmptySet] yield S.EmptySet for x in self.arg: temp = [] x = FiniteSet(x) for y in found: new = x + y yield new temp.append(new) found.extend(temp) sympy-sympy-1.9/sympy/sets/setexpr.py000066400000000000000000000057241412543434000201360ustar00rootroot00000000000000from sympy.core import Expr from sympy.core.decorators import call_highest_priority, _sympifyit from sympy.sets import ImageSet from sympy.sets.sets import set_add, set_sub, set_mul, set_div, set_pow, set_function class SetExpr(Expr): """An expression that can take on values of a set. Examples ======== >>> from sympy import Interval, FiniteSet >>> from sympy.sets.setexpr import SetExpr >>> a = SetExpr(Interval(0, 5)) >>> b = SetExpr(FiniteSet(1, 10)) >>> (a + b).set Union(Interval(1, 6), Interval(10, 15)) >>> (2*a + b).set Interval(1, 20) """ _op_priority = 11.0 def __new__(cls, setarg): return Expr.__new__(cls, setarg) set = property(lambda self: self.args[0]) def _latex(self, printer): return r"SetExpr\left({}\right)".format(printer._print(self.set)) @_sympifyit('other', NotImplemented) @call_highest_priority('__radd__') def __add__(self, other): return _setexpr_apply_operation(set_add, self, other) @_sympifyit('other', NotImplemented) @call_highest_priority('__add__') def __radd__(self, other): return _setexpr_apply_operation(set_add, other, self) @_sympifyit('other', NotImplemented) @call_highest_priority('__rmul__') def __mul__(self, other): return _setexpr_apply_operation(set_mul, self, other) @_sympifyit('other', NotImplemented) @call_highest_priority('__mul__') def __rmul__(self, other): return _setexpr_apply_operation(set_mul, other, self) @_sympifyit('other', NotImplemented) @call_highest_priority('__rsub__') def __sub__(self, other): return _setexpr_apply_operation(set_sub, self, other) @_sympifyit('other', NotImplemented) @call_highest_priority('__sub__') def __rsub__(self, other): return _setexpr_apply_operation(set_sub, other, self) @_sympifyit('other', NotImplemented) @call_highest_priority('__rpow__') def __pow__(self, other): return _setexpr_apply_operation(set_pow, self, other) @_sympifyit('other', NotImplemented) @call_highest_priority('__pow__') def __rpow__(self, other): return _setexpr_apply_operation(set_pow, other, self) @_sympifyit('other', NotImplemented) @call_highest_priority('__rtruediv__') def __truediv__(self, other): return _setexpr_apply_operation(set_div, self, other) @_sympifyit('other', NotImplemented) @call_highest_priority('__truediv__') def __rtruediv__(self, other): return _setexpr_apply_operation(set_div, other, self) def _eval_func(self, func): # TODO: this could be implemented straight into `imageset`: res = set_function(func, self.set) if res is None: return SetExpr(ImageSet(func, self.set)) return SetExpr(res) def _setexpr_apply_operation(op, x, y): if isinstance(x, SetExpr): x = x.set if isinstance(y, SetExpr): y = y.set out = op(x, y) return SetExpr(out) sympy-sympy-1.9/sympy/sets/sets.py000066400000000000000000002153671412543434000174300ustar00rootroot00000000000000from typing import Optional from collections import defaultdict import inspect from sympy.core.basic import Basic from sympy.core.compatibility import iterable, ordered, reduce from sympy.core.containers import Tuple from sympy.core.decorators import (deprecated, sympify_method_args, sympify_return) from sympy.core.evalf import EvalfMixin, prec_to_dps from sympy.core.parameters import global_parameters from sympy.core.expr import Expr from sympy.core.logic import (FuzzyBool, fuzzy_bool, fuzzy_or, fuzzy_and, fuzzy_not) from sympy.core.numbers import Float from sympy.core.operations import LatticeOp from sympy.core.relational import Eq, Ne, is_lt from sympy.core.singleton import Singleton, S from sympy.core.symbol import Symbol, Dummy, uniquely_named_symbol from sympy.core.sympify import _sympify, sympify, converter from sympy.logic.boolalg import And, Or, Not, Xor, true, false from sympy.sets.contains import Contains from sympy.utilities import subsets from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.iterables import iproduct, sift, roundrobin from sympy.utilities.misc import func_name, filldedent from mpmath import mpi, mpf tfn = defaultdict(lambda: None, { True: S.true, S.true: S.true, False: S.false, S.false: S.false}) @sympify_method_args class Set(Basic, EvalfMixin): """ The base class for any kind of set. Explanation =========== This is not meant to be used directly as a container of items. It does not behave like the builtin ``set``; see :class:`FiniteSet` for that. Real intervals are represented by the :class:`Interval` class and unions of sets by the :class:`Union` class. The empty set is represented by the :class:`EmptySet` class and available as a singleton as ``S.EmptySet``. """ is_number = False is_iterable = False is_interval = False is_FiniteSet = False is_Interval = False is_ProductSet = False is_Union = False is_Intersection = None # type: Optional[bool] is_UniversalSet = None # type: Optional[bool] is_Complement = None # type: Optional[bool] is_ComplexRegion = False is_empty = None # type: FuzzyBool is_finite_set = None # type: FuzzyBool @property # type: ignore @deprecated(useinstead="is S.EmptySet or is_empty", issue=16946, deprecated_since_version="1.5") def is_EmptySet(self): return None @staticmethod def _infimum_key(expr): """ Return infimum (if possible) else S.Infinity. """ try: infimum = expr.inf assert infimum.is_comparable infimum = infimum.evalf() # issue #18505 except (NotImplementedError, AttributeError, AssertionError, ValueError): infimum = S.Infinity return infimum def union(self, other): """ Returns the union of ``self`` and ``other``. Examples ======== As a shortcut it is possible to use the '+' operator: >>> from sympy import Interval, FiniteSet >>> Interval(0, 1).union(Interval(2, 3)) Union(Interval(0, 1), Interval(2, 3)) >>> Interval(0, 1) + Interval(2, 3) Union(Interval(0, 1), Interval(2, 3)) >>> Interval(1, 2, True, True) + FiniteSet(2, 3) Union({3}, Interval.Lopen(1, 2)) Similarly it is possible to use the '-' operator for set differences: >>> Interval(0, 2) - Interval(0, 1) Interval.Lopen(1, 2) >>> Interval(1, 3) - FiniteSet(2) Union(Interval.Ropen(1, 2), Interval.Lopen(2, 3)) """ return Union(self, other) def intersect(self, other): """ Returns the intersection of 'self' and 'other'. Examples ======== >>> from sympy import Interval >>> Interval(1, 3).intersect(Interval(1, 2)) Interval(1, 2) >>> from sympy import imageset, Lambda, symbols, S >>> n, m = symbols('n m') >>> a = imageset(Lambda(n, 2*n), S.Integers) >>> a.intersect(imageset(Lambda(m, 2*m + 1), S.Integers)) EmptySet """ return Intersection(self, other) def intersection(self, other): """ Alias for :meth:`intersect()` """ return self.intersect(other) def is_disjoint(self, other): """ Returns True if ``self`` and ``other`` are disjoint. Examples ======== >>> from sympy import Interval >>> Interval(0, 2).is_disjoint(Interval(1, 2)) False >>> Interval(0, 2).is_disjoint(Interval(3, 4)) True References ========== .. [1] https://en.wikipedia.org/wiki/Disjoint_sets """ return self.intersect(other) == S.EmptySet def isdisjoint(self, other): """ Alias for :meth:`is_disjoint()` """ return self.is_disjoint(other) def complement(self, universe): r""" The complement of 'self' w.r.t the given universe. Examples ======== >>> from sympy import Interval, S >>> Interval(0, 1).complement(S.Reals) Union(Interval.open(-oo, 0), Interval.open(1, oo)) >>> Interval(0, 1).complement(S.UniversalSet) Complement(UniversalSet, Interval(0, 1)) """ return Complement(universe, self) def _complement(self, other): # this behaves as other - self if isinstance(self, ProductSet) and isinstance(other, ProductSet): # If self and other are disjoint then other - self == self if len(self.sets) != len(other.sets): return other # There can be other ways to represent this but this gives: # (A x B) - (C x D) = ((A - C) x B) U (A x (B - D)) overlaps = [] pairs = list(zip(self.sets, other.sets)) for n in range(len(pairs)): sets = (o if i != n else o-s for i, (s, o) in enumerate(pairs)) overlaps.append(ProductSet(*sets)) return Union(*overlaps) elif isinstance(other, Interval): if isinstance(self, Interval) or isinstance(self, FiniteSet): return Intersection(other, self.complement(S.Reals)) elif isinstance(other, Union): return Union(*(o - self for o in other.args)) elif isinstance(other, Complement): return Complement(other.args[0], Union(other.args[1], self), evaluate=False) elif isinstance(other, EmptySet): return S.EmptySet elif isinstance(other, FiniteSet): from sympy.utilities.iterables import sift sifted = sift(other, lambda x: fuzzy_bool(self.contains(x))) # ignore those that are contained in self return Union(FiniteSet(*(sifted[False])), Complement(FiniteSet(*(sifted[None])), self, evaluate=False) if sifted[None] else S.EmptySet) def symmetric_difference(self, other): """ Returns symmetric difference of ``self`` and ``other``. Examples ======== >>> from sympy import Interval, S >>> Interval(1, 3).symmetric_difference(S.Reals) Union(Interval.open(-oo, 1), Interval.open(3, oo)) >>> Interval(1, 10).symmetric_difference(S.Reals) Union(Interval.open(-oo, 1), Interval.open(10, oo)) >>> from sympy import S, EmptySet >>> S.Reals.symmetric_difference(EmptySet) Reals References ========== .. [1] https://en.wikipedia.org/wiki/Symmetric_difference """ return SymmetricDifference(self, other) def _symmetric_difference(self, other): return Union(Complement(self, other), Complement(other, self)) @property def inf(self): """ The infimum of ``self``. Examples ======== >>> from sympy import Interval, Union >>> Interval(0, 1).inf 0 >>> Union(Interval(0, 1), Interval(2, 3)).inf 0 """ return self._inf @property def _inf(self): raise NotImplementedError("(%s)._inf" % self) @property def sup(self): """ The supremum of ``self``. Examples ======== >>> from sympy import Interval, Union >>> Interval(0, 1).sup 1 >>> Union(Interval(0, 1), Interval(2, 3)).sup 3 """ return self._sup @property def _sup(self): raise NotImplementedError("(%s)._sup" % self) def contains(self, other): """ Returns a SymPy value indicating whether ``other`` is contained in ``self``: ``true`` if it is, ``false`` if it isn't, else an unevaluated ``Contains`` expression (or, as in the case of ConditionSet and a union of FiniteSet/Intervals, an expression indicating the conditions for containment). Examples ======== >>> from sympy import Interval, S >>> from sympy.abc import x >>> Interval(0, 1).contains(0.5) True As a shortcut it is possible to use the 'in' operator, but that will raise an error unless an affirmative true or false is not obtained. >>> Interval(0, 1).contains(x) (0 <= x) & (x <= 1) >>> x in Interval(0, 1) Traceback (most recent call last): ... TypeError: did not evaluate to a bool: None The result of 'in' is a bool, not a SymPy value >>> 1 in Interval(0, 2) True >>> _ is S.true False """ other = sympify(other, strict=True) c = self._contains(other) if isinstance(c, Contains): return c if c is None: return Contains(other, self, evaluate=False) b = tfn[c] if b is None: return c return b def _contains(self, other): raise NotImplementedError(filldedent(''' (%s)._contains(%s) is not defined. This method, when defined, will receive a sympified object. The method should return True, False, None or something that expresses what must be true for the containment of that object in self to be evaluated. If None is returned then a generic Contains object will be returned by the ``contains`` method.''' % (self, other))) def is_subset(self, other): """ Returns True if ``self`` is a subset of ``other``. Examples ======== >>> from sympy import Interval >>> Interval(0, 0.5).is_subset(Interval(0, 1)) True >>> Interval(0, 1).is_subset(Interval(0, 1, left_open=True)) False """ if not isinstance(other, Set): raise ValueError("Unknown argument '%s'" % other) # Handle the trivial cases if self == other: return True is_empty = self.is_empty if is_empty is True: return True elif fuzzy_not(is_empty) and other.is_empty: return False if self.is_finite_set is False and other.is_finite_set: return False # Dispatch on subclass rules ret = self._eval_is_subset(other) if ret is not None: return ret ret = other._eval_is_superset(self) if ret is not None: return ret # Use pairwise rules from multiple dispatch from sympy.sets.handlers.issubset import is_subset_sets ret = is_subset_sets(self, other) if ret is not None: return ret # Fall back on computing the intersection # XXX: We shouldn't do this. A query like this should be handled # without evaluating new Set objects. It should be the other way round # so that the intersect method uses is_subset for evaluation. if self.intersect(other) == self: return True def _eval_is_subset(self, other): '''Returns a fuzzy bool for whether self is a subset of other.''' return None def _eval_is_superset(self, other): '''Returns a fuzzy bool for whether self is a subset of other.''' return None # This should be deprecated: def issubset(self, other): """ Alias for :meth:`is_subset()` """ return self.is_subset(other) def is_proper_subset(self, other): """ Returns True if ``self`` is a proper subset of ``other``. Examples ======== >>> from sympy import Interval >>> Interval(0, 0.5).is_proper_subset(Interval(0, 1)) True >>> Interval(0, 1).is_proper_subset(Interval(0, 1)) False """ if isinstance(other, Set): return self != other and self.is_subset(other) else: raise ValueError("Unknown argument '%s'" % other) def is_superset(self, other): """ Returns True if ``self`` is a superset of ``other``. Examples ======== >>> from sympy import Interval >>> Interval(0, 0.5).is_superset(Interval(0, 1)) False >>> Interval(0, 1).is_superset(Interval(0, 1, left_open=True)) True """ if isinstance(other, Set): return other.is_subset(self) else: raise ValueError("Unknown argument '%s'" % other) # This should be deprecated: def issuperset(self, other): """ Alias for :meth:`is_superset()` """ return self.is_superset(other) def is_proper_superset(self, other): """ Returns True if ``self`` is a proper superset of ``other``. Examples ======== >>> from sympy import Interval >>> Interval(0, 1).is_proper_superset(Interval(0, 0.5)) True >>> Interval(0, 1).is_proper_superset(Interval(0, 1)) False """ if isinstance(other, Set): return self != other and self.is_superset(other) else: raise ValueError("Unknown argument '%s'" % other) def _eval_powerset(self): from .powerset import PowerSet return PowerSet(self) def powerset(self): """ Find the Power set of ``self``. Examples ======== >>> from sympy import EmptySet, FiniteSet, Interval A power set of an empty set: >>> A = EmptySet >>> A.powerset() {EmptySet} A power set of a finite set: >>> A = FiniteSet(1, 2) >>> a, b, c = FiniteSet(1), FiniteSet(2), FiniteSet(1, 2) >>> A.powerset() == FiniteSet(a, b, c, EmptySet) True A power set of an interval: >>> Interval(1, 2).powerset() PowerSet(Interval(1, 2)) References ========== .. [1] https://en.wikipedia.org/wiki/Power_set """ return self._eval_powerset() @property def measure(self): """ The (Lebesgue) measure of ``self``. Examples ======== >>> from sympy import Interval, Union >>> Interval(0, 1).measure 1 >>> Union(Interval(0, 1), Interval(2, 3)).measure 2 """ return self._measure @property def boundary(self): """ The boundary or frontier of a set. Explanation =========== A point x is on the boundary of a set S if 1. x is in the closure of S. I.e. Every neighborhood of x contains a point in S. 2. x is not in the interior of S. I.e. There does not exist an open set centered on x contained entirely within S. There are the points on the outer rim of S. If S is open then these points need not actually be contained within S. For example, the boundary of an interval is its start and end points. This is true regardless of whether or not the interval is open. Examples ======== >>> from sympy import Interval >>> Interval(0, 1).boundary {0, 1} >>> Interval(0, 1, True, False).boundary {0, 1} """ return self._boundary @property def is_open(self): """ Property method to check whether a set is open. Explanation =========== A set is open if and only if it has an empty intersection with its boundary. In particular, a subset A of the reals is open if and only if each one of its points is contained in an open interval that is a subset of A. Examples ======== >>> from sympy import S >>> S.Reals.is_open True >>> S.Rationals.is_open False """ return Intersection(self, self.boundary).is_empty @property def is_closed(self): """ A property method to check whether a set is closed. Explanation =========== A set is closed if its complement is an open set. The closedness of a subset of the reals is determined with respect to R and its standard topology. Examples ======== >>> from sympy import Interval >>> Interval(0, 1).is_closed True """ return self.boundary.is_subset(self) @property def closure(self): """ Property method which returns the closure of a set. The closure is defined as the union of the set itself and its boundary. Examples ======== >>> from sympy import S, Interval >>> S.Reals.closure Reals >>> Interval(0, 1).closure Interval(0, 1) """ return self + self.boundary @property def interior(self): """ Property method which returns the interior of a set. The interior of a set S consists all points of S that do not belong to the boundary of S. Examples ======== >>> from sympy import Interval >>> Interval(0, 1).interior Interval.open(0, 1) >>> Interval(0, 1).boundary.interior EmptySet """ return self - self.boundary @property def _boundary(self): raise NotImplementedError() @property def _measure(self): raise NotImplementedError("(%s)._measure" % self) def _eval_evalf(self, prec): return self.func(*[arg.evalf(n=prec_to_dps(prec)) for arg in self.args]) @sympify_return([('other', 'Set')], NotImplemented) def __add__(self, other): return self.union(other) @sympify_return([('other', 'Set')], NotImplemented) def __or__(self, other): return self.union(other) @sympify_return([('other', 'Set')], NotImplemented) def __and__(self, other): return self.intersect(other) @sympify_return([('other', 'Set')], NotImplemented) def __mul__(self, other): return ProductSet(self, other) @sympify_return([('other', 'Set')], NotImplemented) def __xor__(self, other): return SymmetricDifference(self, other) @sympify_return([('exp', Expr)], NotImplemented) def __pow__(self, exp): if not (exp.is_Integer and exp >= 0): raise ValueError("%s: Exponent must be a positive Integer" % exp) return ProductSet(*[self]*exp) @sympify_return([('other', 'Set')], NotImplemented) def __sub__(self, other): return Complement(self, other) def __contains__(self, other): other = _sympify(other) c = self._contains(other) b = tfn[c] if b is None: # x in y must evaluate to T or F; to entertain a None # result with Set use y.contains(x) raise TypeError('did not evaluate to a bool: %r' % c) return b class ProductSet(Set): """ Represents a Cartesian Product of Sets. Explanation =========== Returns a Cartesian product given several sets as either an iterable or individual arguments. Can use '*' operator on any sets for convenient shorthand. Examples ======== >>> from sympy import Interval, FiniteSet, ProductSet >>> I = Interval(0, 5); S = FiniteSet(1, 2, 3) >>> ProductSet(I, S) ProductSet(Interval(0, 5), {1, 2, 3}) >>> (2, 2) in ProductSet(I, S) True >>> Interval(0, 1) * Interval(0, 1) # The unit square ProductSet(Interval(0, 1), Interval(0, 1)) >>> coin = FiniteSet('H', 'T') >>> set(coin**2) {(H, H), (H, T), (T, H), (T, T)} The Cartesian product is not commutative or associative e.g.: >>> I*S == S*I False >>> (I*I)*I == I*(I*I) False Notes ===== - Passes most operations down to the argument sets References ========== .. [1] https://en.wikipedia.org/wiki/Cartesian_product """ is_ProductSet = True def __new__(cls, *sets, **assumptions): if len(sets) == 1 and iterable(sets[0]) and not isinstance(sets[0], (Set, set)): SymPyDeprecationWarning( feature="ProductSet(iterable)", useinstead="ProductSet(*iterable)", issue=17557, deprecated_since_version="1.5" ).warn() sets = tuple(sets[0]) sets = [sympify(s) for s in sets] if not all(isinstance(s, Set) for s in sets): raise TypeError("Arguments to ProductSet should be of type Set") # Nullary product of sets is *not* the empty set if len(sets) == 0: return FiniteSet(()) if S.EmptySet in sets: return S.EmptySet return Basic.__new__(cls, *sets, **assumptions) @property def sets(self): return self.args def flatten(self): def _flatten(sets): for s in sets: if s.is_ProductSet: yield from _flatten(s.sets) else: yield s return ProductSet(*_flatten(self.sets)) def _contains(self, element): """ 'in' operator for ProductSets. Examples ======== >>> from sympy import Interval >>> (2, 3) in Interval(0, 5) * Interval(0, 5) True >>> (10, 10) in Interval(0, 5) * Interval(0, 5) False Passes operation on to constituent sets """ if element.is_Symbol: return None if not isinstance(element, Tuple) or len(element) != len(self.sets): return False return fuzzy_and(s._contains(e) for s, e in zip(self.sets, element)) def as_relational(self, *symbols): symbols = [_sympify(s) for s in symbols] if len(symbols) != len(self.sets) or not all( i.is_Symbol for i in symbols): raise ValueError( 'number of symbols must match the number of sets') return And(*[s.as_relational(i) for s, i in zip(self.sets, symbols)]) @property def _boundary(self): return Union(*(ProductSet(*(b + b.boundary if i != j else b.boundary for j, b in enumerate(self.sets))) for i, a in enumerate(self.sets))) @property def is_iterable(self): """ A property method which tests whether a set is iterable or not. Returns True if set is iterable, otherwise returns False. Examples ======== >>> from sympy import FiniteSet, Interval >>> I = Interval(0, 1) >>> A = FiniteSet(1, 2, 3, 4, 5) >>> I.is_iterable False >>> A.is_iterable True """ return all(set.is_iterable for set in self.sets) def __iter__(self): """ A method which implements is_iterable property method. If self.is_iterable returns True (both constituent sets are iterable), then return the Cartesian Product. Otherwise, raise TypeError. """ return iproduct(*self.sets) @property def is_empty(self): return fuzzy_or(s.is_empty for s in self.sets) @property def is_finite_set(self): all_finite = fuzzy_and(s.is_finite_set for s in self.sets) return fuzzy_or([self.is_empty, all_finite]) @property def _measure(self): measure = 1 for s in self.sets: measure *= s.measure return measure def __len__(self): return reduce(lambda a, b: a*b, (len(s) for s in self.args)) def __bool__(self): return all([bool(s) for s in self.sets]) class Interval(Set): """ Represents a real interval as a Set. Usage: Returns an interval with end points "start" and "end". For left_open=True (default left_open is False) the interval will be open on the left. Similarly, for right_open=True the interval will be open on the right. Examples ======== >>> from sympy import Symbol, Interval >>> Interval(0, 1) Interval(0, 1) >>> Interval.Ropen(0, 1) Interval.Ropen(0, 1) >>> Interval.Ropen(0, 1) Interval.Ropen(0, 1) >>> Interval.Lopen(0, 1) Interval.Lopen(0, 1) >>> Interval.open(0, 1) Interval.open(0, 1) >>> a = Symbol('a', real=True) >>> Interval(0, a) Interval(0, a) Notes ===== - Only real end points are supported - Interval(a, b) with a > b will return the empty set - Use the evalf() method to turn an Interval into an mpmath 'mpi' interval instance References ========== .. [1] https://en.wikipedia.org/wiki/Interval_%28mathematics%29 """ is_Interval = True def __new__(cls, start, end, left_open=False, right_open=False): start = _sympify(start) end = _sympify(end) left_open = _sympify(left_open) right_open = _sympify(right_open) if not all(isinstance(a, (type(true), type(false))) for a in [left_open, right_open]): raise NotImplementedError( "left_open and right_open can have only true/false values, " "got %s and %s" % (left_open, right_open)) # Only allow real intervals if fuzzy_not(fuzzy_and(i.is_extended_real for i in (start, end, end-start))): raise ValueError("Non-real intervals are not supported") # evaluate if possible if is_lt(end, start): return S.EmptySet elif (end - start).is_negative: return S.EmptySet if end == start and (left_open or right_open): return S.EmptySet if end == start and not (left_open or right_open): if start is S.Infinity or start is S.NegativeInfinity: return S.EmptySet return FiniteSet(end) # Make sure infinite interval end points are open. if start is S.NegativeInfinity: left_open = true if end is S.Infinity: right_open = true if start == S.Infinity or end == S.NegativeInfinity: return S.EmptySet return Basic.__new__(cls, start, end, left_open, right_open) @property def start(self): """ The left end point of ``self``. This property takes the same value as the 'inf' property. Examples ======== >>> from sympy import Interval >>> Interval(0, 1).start 0 """ return self._args[0] @property def end(self): """ The right end point of 'self'. This property takes the same value as the 'sup' property. Examples ======== >>> from sympy import Interval >>> Interval(0, 1).end 1 """ return self._args[1] @property def left_open(self): """ True if ``self`` is left-open. Examples ======== >>> from sympy import Interval >>> Interval(0, 1, left_open=True).left_open True >>> Interval(0, 1, left_open=False).left_open False """ return self._args[2] @property def right_open(self): """ True if ``self`` is right-open. Examples ======== >>> from sympy import Interval >>> Interval(0, 1, right_open=True).right_open True >>> Interval(0, 1, right_open=False).right_open False """ return self._args[3] @classmethod def open(cls, a, b): """Return an interval including neither boundary.""" return cls(a, b, True, True) @classmethod def Lopen(cls, a, b): """Return an interval not including the left boundary.""" return cls(a, b, True, False) @classmethod def Ropen(cls, a, b): """Return an interval not including the right boundary.""" return cls(a, b, False, True) @property def _inf(self): return self.start @property def _sup(self): return self.end @property def left(self): return self.start @property def right(self): return self.end @property def is_empty(self): if self.left_open or self.right_open: cond = self.start >= self.end # One/both bounds open else: cond = self.start > self.end # Both bounds closed return fuzzy_bool(cond) @property def is_finite_set(self): return self.measure.is_zero def _complement(self, other): if other == S.Reals: a = Interval(S.NegativeInfinity, self.start, True, not self.left_open) b = Interval(self.end, S.Infinity, not self.right_open, True) return Union(a, b) if isinstance(other, FiniteSet): nums = [m for m in other.args if m.is_number] if nums == []: return None return Set._complement(self, other) @property def _boundary(self): finite_points = [p for p in (self.start, self.end) if abs(p) != S.Infinity] return FiniteSet(*finite_points) def _contains(self, other): if (not isinstance(other, Expr) or other is S.NaN or other.is_real is False): return false if self.start is S.NegativeInfinity and self.end is S.Infinity: if other.is_real is not None: return other.is_real d = Dummy() return self.as_relational(d).subs(d, other) def as_relational(self, x): """Rewrite an interval in terms of inequalities and logic operators.""" x = sympify(x) if self.right_open: right = x < self.end else: right = x <= self.end if self.left_open: left = self.start < x else: left = self.start <= x return And(left, right) @property def _measure(self): return self.end - self.start def to_mpi(self, prec=53): return mpi(mpf(self.start._eval_evalf(prec)), mpf(self.end._eval_evalf(prec))) def _eval_evalf(self, prec): return Interval(self.left._evalf(prec), self.right._evalf(prec), left_open=self.left_open, right_open=self.right_open) def _is_comparable(self, other): is_comparable = self.start.is_comparable is_comparable &= self.end.is_comparable is_comparable &= other.start.is_comparable is_comparable &= other.end.is_comparable return is_comparable @property def is_left_unbounded(self): """Return ``True`` if the left endpoint is negative infinity. """ return self.left is S.NegativeInfinity or self.left == Float("-inf") @property def is_right_unbounded(self): """Return ``True`` if the right endpoint is positive infinity. """ return self.right is S.Infinity or self.right == Float("+inf") def _eval_Eq(self, other): if not isinstance(other, Interval): if isinstance(other, FiniteSet): return false elif isinstance(other, Set): return None return false class Union(Set, LatticeOp): """ Represents a union of sets as a :class:`Set`. Examples ======== >>> from sympy import Union, Interval >>> Union(Interval(1, 2), Interval(3, 4)) Union(Interval(1, 2), Interval(3, 4)) The Union constructor will always try to merge overlapping intervals, if possible. For example: >>> Union(Interval(1, 2), Interval(2, 3)) Interval(1, 3) See Also ======== Intersection References ========== .. [1] https://en.wikipedia.org/wiki/Union_%28set_theory%29 """ is_Union = True @property def identity(self): return S.EmptySet @property def zero(self): return S.UniversalSet def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_parameters.evaluate) # flatten inputs to merge intersections and iterables args = _sympify(args) # Reduce sets using known rules if evaluate: args = list(cls._new_args_filter(args)) return simplify_union(args) args = list(ordered(args, Set._infimum_key)) obj = Basic.__new__(cls, *args) obj._argset = frozenset(args) return obj @property def args(self): return self._args def _complement(self, universe): # DeMorgan's Law return Intersection(s.complement(universe) for s in self.args) @property def _inf(self): # We use Min so that sup is meaningful in combination with symbolic # interval end points. from sympy.functions.elementary.miscellaneous import Min return Min(*[set.inf for set in self.args]) @property def _sup(self): # We use Max so that sup is meaningful in combination with symbolic # end points. from sympy.functions.elementary.miscellaneous import Max return Max(*[set.sup for set in self.args]) @property def is_empty(self): return fuzzy_and(set.is_empty for set in self.args) @property def is_finite_set(self): return fuzzy_and(set.is_finite_set for set in self.args) @property def _measure(self): # Measure of a union is the sum of the measures of the sets minus # the sum of their pairwise intersections plus the sum of their # triple-wise intersections minus ... etc... # Sets is a collection of intersections and a set of elementary # sets which made up those intersections (called "sos" for set of sets) # An example element might of this list might be: # ( {A,B,C}, A.intersect(B).intersect(C) ) # Start with just elementary sets ( ({A}, A), ({B}, B), ... ) # Then get and subtract ( ({A,B}, (A int B), ... ) while non-zero sets = [(FiniteSet(s), s) for s in self.args] measure = 0 parity = 1 while sets: # Add up the measure of these sets and add or subtract it to total measure += parity * sum(inter.measure for sos, inter in sets) # For each intersection in sets, compute the intersection with every # other set not already part of the intersection. sets = ((sos + FiniteSet(newset), newset.intersect(intersection)) for sos, intersection in sets for newset in self.args if newset not in sos) # Clear out sets with no measure sets = [(sos, inter) for sos, inter in sets if inter.measure != 0] # Clear out duplicates sos_list = [] sets_list = [] for set in sets: if set[0] in sos_list: continue else: sos_list.append(set[0]) sets_list.append(set) sets = sets_list # Flip Parity - next time subtract/add if we added/subtracted here parity *= -1 return measure @property def _boundary(self): def boundary_of_set(i): """ The boundary of set i minus interior of all other sets """ b = self.args[i].boundary for j, a in enumerate(self.args): if j != i: b = b - a.interior return b return Union(*map(boundary_of_set, range(len(self.args)))) def _contains(self, other): return Or(*[s.contains(other) for s in self.args]) def is_subset(self, other): return fuzzy_and(s.is_subset(other) for s in self.args) def as_relational(self, symbol): """Rewrite a Union in terms of equalities and logic operators. """ if (len(self.args) == 2 and all(isinstance(i, Interval) for i in self.args)): # optimization to give 3 args as (x > 1) & (x < 5) & Ne(x, 3) # instead of as 4, ((1 <= x) & (x < 3)) | ((x <= 5) & (3 < x)) a, b = self.args if (a.sup == b.inf and not any(a.sup in i for i in self.args)): return And(Ne(symbol, a.sup), symbol < b.sup, symbol > a.inf) return Or(*[i.as_relational(symbol) for i in self.args]) @property def is_iterable(self): return all(arg.is_iterable for arg in self.args) def __iter__(self): return roundrobin(*(iter(arg) for arg in self.args)) class Intersection(Set, LatticeOp): """ Represents an intersection of sets as a :class:`Set`. Examples ======== >>> from sympy import Intersection, Interval >>> Intersection(Interval(1, 3), Interval(2, 4)) Interval(2, 3) We often use the .intersect method >>> Interval(1,3).intersect(Interval(2,4)) Interval(2, 3) See Also ======== Union References ========== .. [1] https://en.wikipedia.org/wiki/Intersection_%28set_theory%29 """ is_Intersection = True @property def identity(self): return S.UniversalSet @property def zero(self): return S.EmptySet def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_parameters.evaluate) # flatten inputs to merge intersections and iterables args = list(ordered(set(_sympify(args)))) # Reduce sets using known rules if evaluate: args = list(cls._new_args_filter(args)) return simplify_intersection(args) args = list(ordered(args, Set._infimum_key)) obj = Basic.__new__(cls, *args) obj._argset = frozenset(args) return obj @property def args(self): return self._args @property def is_iterable(self): return any(arg.is_iterable for arg in self.args) @property def is_finite_set(self): if fuzzy_or(arg.is_finite_set for arg in self.args): return True @property def _inf(self): raise NotImplementedError() @property def _sup(self): raise NotImplementedError() def _contains(self, other): return And(*[set.contains(other) for set in self.args]) def __iter__(self): sets_sift = sift(self.args, lambda x: x.is_iterable) completed = False candidates = sets_sift[True] + sets_sift[None] finite_candidates, others = [], [] for candidate in candidates: length = None try: length = len(candidate) except TypeError: others.append(candidate) if length is not None: finite_candidates.append(candidate) finite_candidates.sort(key=len) for s in finite_candidates + others: other_sets = set(self.args) - {s} other = Intersection(*other_sets, evaluate=False) completed = True for x in s: try: if x in other: yield x except TypeError: completed = False if completed: return if not completed: if not candidates: raise TypeError("None of the constituent sets are iterable") raise TypeError( "The computation had not completed because of the " "undecidable set membership is found in every candidates.") @staticmethod def _handle_finite_sets(args): '''Simplify intersection of one or more FiniteSets and other sets''' # First separate the FiniteSets from the others fs_args, others = sift(args, lambda x: x.is_FiniteSet, binary=True) # Let the caller handle intersection of non-FiniteSets if not fs_args: return # Convert to Python sets and build the set of all elements fs_sets = [set(fs) for fs in fs_args] all_elements = reduce(lambda a, b: a | b, fs_sets, set()) # Extract elements that are definitely in or definitely not in the # intersection. Here we check contains for all of args. definite = set() for e in all_elements: inall = fuzzy_and(s.contains(e) for s in args) if inall is True: definite.add(e) if inall is not None: for s in fs_sets: s.discard(e) # At this point all elements in all of fs_sets are possibly in the # intersection. In some cases this is because they are definitely in # the intersection of the finite sets but it's not clear if they are # members of others. We might have {m, n}, {m}, and Reals where we # don't know if m or n is real. We want to remove n here but it is # possibly in because it might be equal to m. So what we do now is # extract the elements that are definitely in the remaining finite # sets iteratively until we end up with {n}, {}. At that point if we # get any empty set all remaining elements are discarded. fs_elements = reduce(lambda a, b: a | b, fs_sets, set()) # Need fuzzy containment testing fs_symsets = [FiniteSet(*s) for s in fs_sets] while fs_elements: for e in fs_elements: infs = fuzzy_and(s.contains(e) for s in fs_symsets) if infs is True: definite.add(e) if infs is not None: for n, s in enumerate(fs_sets): # Update Python set and FiniteSet if e in s: s.remove(e) fs_symsets[n] = FiniteSet(*s) fs_elements.remove(e) break # If we completed the for loop without removing anything we are # done so quit the outer while loop else: break # If any of the sets of remainder elements is empty then we discard # all of them for the intersection. if not all(fs_sets): fs_sets = [set()] # Here we fold back the definitely included elements into each fs. # Since they are definitely included they must have been members of # each FiniteSet to begin with. We could instead fold these in with a # Union at the end to get e.g. {3}|({x}&{y}) rather than {3,x}&{3,y}. if definite: fs_sets = [fs | definite for fs in fs_sets] if fs_sets == [set()]: return S.EmptySet sets = [FiniteSet(*s) for s in fs_sets] # Any set in others is redundant if it contains all the elements that # are in the finite sets so we don't need it in the Intersection all_elements = reduce(lambda a, b: a | b, fs_sets, set()) is_redundant = lambda o: all(fuzzy_bool(o.contains(e)) for e in all_elements) others = [o for o in others if not is_redundant(o)] if others: rest = Intersection(*others) # XXX: Maybe this shortcut should be at the beginning. For large # FiniteSets it could much more efficient to process the other # sets first... if rest is S.EmptySet: return S.EmptySet # Flatten the Intersection if rest.is_Intersection: sets.extend(rest.args) else: sets.append(rest) if len(sets) == 1: return sets[0] else: return Intersection(*sets, evaluate=False) def as_relational(self, symbol): """Rewrite an Intersection in terms of equalities and logic operators""" return And(*[set.as_relational(symbol) for set in self.args]) class Complement(Set): r"""Represents the set difference or relative complement of a set with another set. `A - B = \{x \in A \mid x \notin B\}` Examples ======== >>> from sympy import Complement, FiniteSet >>> Complement(FiniteSet(0, 1, 2), FiniteSet(1)) {0, 2} See Also ========= Intersection, Union References ========== .. [1] http://mathworld.wolfram.com/ComplementSet.html """ is_Complement = True def __new__(cls, a, b, evaluate=True): if evaluate: return Complement.reduce(a, b) return Basic.__new__(cls, a, b) @staticmethod def reduce(A, B): """ Simplify a :class:`Complement`. """ if B == S.UniversalSet or A.is_subset(B): return S.EmptySet if isinstance(B, Union): return Intersection(*(s.complement(A) for s in B.args)) result = B._complement(A) if result is not None: return result else: return Complement(A, B, evaluate=False) def _contains(self, other): A = self.args[0] B = self.args[1] return And(A.contains(other), Not(B.contains(other))) def as_relational(self, symbol): """Rewrite a complement in terms of equalities and logic operators""" A, B = self.args A_rel = A.as_relational(symbol) B_rel = Not(B.as_relational(symbol)) return And(A_rel, B_rel) @property def is_iterable(self): if self.args[0].is_iterable: return True @property def is_finite_set(self): A, B = self.args a_finite = A.is_finite_set if a_finite is True: return True elif a_finite is False and B.is_finite_set: return False def __iter__(self): A, B = self.args for a in A: if a not in B: yield a else: continue class EmptySet(Set, metaclass=Singleton): """ Represents the empty set. The empty set is available as a singleton as S.EmptySet. Examples ======== >>> from sympy import S, Interval >>> S.EmptySet EmptySet >>> Interval(1, 2).intersect(S.EmptySet) EmptySet See Also ======== UniversalSet References ========== .. [1] https://en.wikipedia.org/wiki/Empty_set """ is_empty = True is_finite_set = True is_FiniteSet = True @property # type: ignore @deprecated(useinstead="is S.EmptySet or is_empty", issue=16946, deprecated_since_version="1.5") def is_EmptySet(self): return True @property def _measure(self): return 0 def _contains(self, other): return false def as_relational(self, symbol): return false def __len__(self): return 0 def __iter__(self): return iter([]) def _eval_powerset(self): return FiniteSet(self) @property def _boundary(self): return self def _complement(self, other): return other def _symmetric_difference(self, other): return other class UniversalSet(Set, metaclass=Singleton): """ Represents the set of all things. The universal set is available as a singleton as S.UniversalSet. Examples ======== >>> from sympy import S, Interval >>> S.UniversalSet UniversalSet >>> Interval(1, 2).intersect(S.UniversalSet) Interval(1, 2) See Also ======== EmptySet References ========== .. [1] https://en.wikipedia.org/wiki/Universal_set """ is_UniversalSet = True is_empty = False is_finite_set = False def _complement(self, other): return S.EmptySet def _symmetric_difference(self, other): return other @property def _measure(self): return S.Infinity def _contains(self, other): return true def as_relational(self, symbol): return true @property def _boundary(self): return S.EmptySet class FiniteSet(Set): """ Represents a finite set of discrete numbers. Examples ======== >>> from sympy import FiniteSet >>> FiniteSet(1, 2, 3, 4) {1, 2, 3, 4} >>> 3 in FiniteSet(1, 2, 3, 4) True >>> members = [1, 2, 3, 4] >>> f = FiniteSet(*members) >>> f {1, 2, 3, 4} >>> f - FiniteSet(2) {1, 3, 4} >>> f + FiniteSet(2, 5) {1, 2, 3, 4, 5} References ========== .. [1] https://en.wikipedia.org/wiki/Finite_set """ is_FiniteSet = True is_iterable = True is_empty = False is_finite_set = True def __new__(cls, *args, **kwargs): evaluate = kwargs.get('evaluate', global_parameters.evaluate) if evaluate: args = list(map(sympify, args)) if len(args) == 0: return S.EmptySet else: args = list(map(sympify, args)) # keep the form of the first canonical arg dargs = {} for i in reversed(list(ordered(args))): if i.is_Symbol: dargs[i] = i else: try: dargs[i.as_dummy()] = i except TypeError: # e.g. i = class without args like `Interval` dargs[i] = i _args_set = set(dargs.values()) args = list(ordered(_args_set, Set._infimum_key)) obj = Basic.__new__(cls, *args) obj._args_set = _args_set return obj def __iter__(self): return iter(self.args) def _complement(self, other): if isinstance(other, Interval): # Splitting in sub-intervals is only done for S.Reals; # other cases that need splitting will first pass through # Set._complement(). nums, syms = [], [] for m in self.args: if m.is_number and m.is_real: nums.append(m) elif m.is_real == False: pass # drop non-reals else: syms.append(m) # various symbolic expressions if other == S.Reals and nums != []: nums.sort() intervals = [] # Build up a list of intervals between the elements intervals += [Interval(S.NegativeInfinity, nums[0], True, True)] for a, b in zip(nums[:-1], nums[1:]): intervals.append(Interval(a, b, True, True)) # both open intervals.append(Interval(nums[-1], S.Infinity, True, True)) if syms != []: return Complement(Union(*intervals, evaluate=False), FiniteSet(*syms), evaluate=False) else: return Union(*intervals, evaluate=False) elif nums == []: # no splitting necessary or possible: if syms: return Complement(other, FiniteSet(*syms), evaluate=False) else: return other elif isinstance(other, FiniteSet): unk = [] for i in self: c = sympify(other.contains(i)) if c is not S.true and c is not S.false: unk.append(i) unk = FiniteSet(*unk) if unk == self: return not_true = [] for i in other: c = sympify(self.contains(i)) if c is not S.true: not_true.append(i) return Complement(FiniteSet(*not_true), unk) return Set._complement(self, other) def _contains(self, other): """ Tests whether an element, other, is in the set. Explanation =========== The actual test is for mathematical equality (as opposed to syntactical equality). In the worst case all elements of the set must be checked. Examples ======== >>> from sympy import FiniteSet >>> 1 in FiniteSet(1, 2) True >>> 5 in FiniteSet(1, 2) False """ if other in self._args_set: return True else: # evaluate=True is needed to override evaluate=False context; # we need Eq to do the evaluation return fuzzy_or(fuzzy_bool(Eq(e, other, evaluate=True)) for e in self.args) def _eval_is_subset(self, other): return fuzzy_and(other._contains(e) for e in self.args) @property def _boundary(self): return self @property def _inf(self): from sympy.functions.elementary.miscellaneous import Min return Min(*self) @property def _sup(self): from sympy.functions.elementary.miscellaneous import Max return Max(*self) @property def measure(self): return 0 def __len__(self): return len(self.args) def as_relational(self, symbol): """Rewrite a FiniteSet in terms of equalities and logic operators. """ from sympy.core.relational import Eq return Or(*[Eq(symbol, elem) for elem in self]) def compare(self, other): return (hash(self) - hash(other)) def _eval_evalf(self, prec): return FiniteSet(*[elem.evalf(n=prec_to_dps(prec)) for elem in self]) def _eval_simplify(self, **kwargs): from sympy.simplify import simplify return FiniteSet(*[simplify(elem, **kwargs) for elem in self]) @property def _sorted_args(self): return self.args def _eval_powerset(self): return self.func(*[self.func(*s) for s in subsets(self.args)]) def _eval_rewrite_as_PowerSet(self, *args, **kwargs): """Rewriting method for a finite set to a power set.""" from .powerset import PowerSet is2pow = lambda n: bool(n and not n & (n - 1)) if not is2pow(len(self)): return None fs_test = lambda arg: isinstance(arg, Set) and arg.is_FiniteSet if not all(fs_test(arg) for arg in args): return None biggest = max(args, key=len) for arg in subsets(biggest.args): arg_set = FiniteSet(*arg) if arg_set not in args: return None return PowerSet(biggest) def __ge__(self, other): if not isinstance(other, Set): raise TypeError("Invalid comparison of set with %s" % func_name(other)) return other.is_subset(self) def __gt__(self, other): if not isinstance(other, Set): raise TypeError("Invalid comparison of set with %s" % func_name(other)) return self.is_proper_superset(other) def __le__(self, other): if not isinstance(other, Set): raise TypeError("Invalid comparison of set with %s" % func_name(other)) return self.is_subset(other) def __lt__(self, other): if not isinstance(other, Set): raise TypeError("Invalid comparison of set with %s" % func_name(other)) return self.is_proper_subset(other) converter[set] = lambda x: FiniteSet(*x) converter[frozenset] = lambda x: FiniteSet(*x) class SymmetricDifference(Set): """Represents the set of elements which are in either of the sets and not in their intersection. Examples ======== >>> from sympy import SymmetricDifference, FiniteSet >>> SymmetricDifference(FiniteSet(1, 2, 3), FiniteSet(3, 4, 5)) {1, 2, 4, 5} See Also ======== Complement, Union References ========== .. [1] https://en.wikipedia.org/wiki/Symmetric_difference """ is_SymmetricDifference = True def __new__(cls, a, b, evaluate=True): if evaluate: return SymmetricDifference.reduce(a, b) return Basic.__new__(cls, a, b) @staticmethod def reduce(A, B): result = B._symmetric_difference(A) if result is not None: return result else: return SymmetricDifference(A, B, evaluate=False) def as_relational(self, symbol): """Rewrite a symmetric_difference in terms of equalities and logic operators""" A, B = self.args A_rel = A.as_relational(symbol) B_rel = B.as_relational(symbol) return Xor(A_rel, B_rel) @property def is_iterable(self): if all(arg.is_iterable for arg in self.args): return True def __iter__(self): args = self.args union = roundrobin(*(iter(arg) for arg in args)) for item in union: count = 0 for s in args: if item in s: count += 1 if count % 2 == 1: yield item class DisjointUnion(Set): """ Represents the disjoint union (also known as the external disjoint union) of a finite number of sets. Examples ======== >>> from sympy import DisjointUnion, FiniteSet, Interval, Union, Symbol >>> A = FiniteSet(1, 2, 3) >>> B = Interval(0, 5) >>> DisjointUnion(A, B) DisjointUnion({1, 2, 3}, Interval(0, 5)) >>> DisjointUnion(A, B).rewrite(Union) Union(ProductSet({1, 2, 3}, {0}), ProductSet(Interval(0, 5), {1})) >>> C = FiniteSet(Symbol('x'), Symbol('y'), Symbol('z')) >>> DisjointUnion(C, C) DisjointUnion({x, y, z}, {x, y, z}) >>> DisjointUnion(C, C).rewrite(Union) ProductSet({x, y, z}, {0, 1}) References ========== https://en.wikipedia.org/wiki/Disjoint_union """ def __new__(cls, *sets): dj_collection = [] for set_i in sets: if isinstance(set_i, Set): dj_collection.append(set_i) else: raise TypeError("Invalid input: '%s', input args \ to DisjointUnion must be Sets" % set_i) obj = Basic.__new__(cls, *dj_collection) return obj @property def sets(self): return self.args @property def is_empty(self): return fuzzy_and(s.is_empty for s in self.sets) @property def is_finite_set(self): all_finite = fuzzy_and(s.is_finite_set for s in self.sets) return fuzzy_or([self.is_empty, all_finite]) @property def is_iterable(self): if self.is_empty: return False iter_flag = True for set_i in self.sets: if not set_i.is_empty: iter_flag = iter_flag and set_i.is_iterable return iter_flag def _eval_rewrite_as_Union(self, *sets): """ Rewrites the disjoint union as the union of (``set`` x {``i``}) where ``set`` is the element in ``sets`` at index = ``i`` """ dj_union = EmptySet() index = 0 for set_i in sets: if isinstance(set_i, Set): cross = ProductSet(set_i, FiniteSet(index)) dj_union = Union(dj_union, cross) index = index + 1 return dj_union def _contains(self, element): """ 'in' operator for DisjointUnion Examples ======== >>> from sympy import Interval, DisjointUnion >>> D = DisjointUnion(Interval(0, 1), Interval(0, 2)) >>> (0.5, 0) in D True >>> (0.5, 1) in D True >>> (1.5, 0) in D False >>> (1.5, 1) in D True Passes operation on to constituent sets """ if not isinstance(element, Tuple) or len(element) != 2: return False if not element[1].is_Integer: return False if element[1] >= len(self.sets) or element[1] < 0: return False return element[0] in self.sets[element[1]] def __iter__(self): if self.is_iterable: from sympy.core.numbers import Integer iters = [] for i, s in enumerate(self.sets): iters.append(iproduct(s, {Integer(i)})) return iter(roundrobin(*iters)) else: raise ValueError("'%s' is not iterable." % self) def __len__(self): """ Returns the length of the disjoint union, i.e., the number of elements in the set. Examples ======== >>> from sympy import FiniteSet, DisjointUnion, EmptySet >>> D1 = DisjointUnion(FiniteSet(1, 2, 3, 4), EmptySet, FiniteSet(3, 4, 5)) >>> len(D1) 7 >>> D2 = DisjointUnion(FiniteSet(3, 5, 7), EmptySet, FiniteSet(3, 5, 7)) >>> len(D2) 6 >>> D3 = DisjointUnion(EmptySet, EmptySet) >>> len(D3) 0 Adds up the lengths of the constituent sets. """ if self.is_finite_set: size = 0 for set in self.sets: size += len(set) return size else: raise ValueError("'%s' is not a finite set." % self) def imageset(*args): r""" Return an image of the set under transformation ``f``. Explanation =========== If this function can't compute the image, it returns an unevaluated ImageSet object. .. math:: \{ f(x) \mid x \in \mathrm{self} \} Examples ======== >>> from sympy import S, Interval, imageset, sin, Lambda >>> from sympy.abc import x >>> imageset(x, 2*x, Interval(0, 2)) Interval(0, 4) >>> imageset(lambda x: 2*x, Interval(0, 2)) Interval(0, 4) >>> imageset(Lambda(x, sin(x)), Interval(-2, 1)) ImageSet(Lambda(x, sin(x)), Interval(-2, 1)) >>> imageset(sin, Interval(-2, 1)) ImageSet(Lambda(x, sin(x)), Interval(-2, 1)) >>> imageset(lambda y: x + y, Interval(-2, 1)) ImageSet(Lambda(y, x + y), Interval(-2, 1)) Expressions applied to the set of Integers are simplified to show as few negatives as possible and linear expressions are converted to a canonical form. If this is not desirable then the unevaluated ImageSet should be used. >>> imageset(x, -2*x + 5, S.Integers) ImageSet(Lambda(x, 2*x + 1), Integers) See Also ======== sympy.sets.fancysets.ImageSet """ from sympy.core import Lambda from sympy.sets.fancysets import ImageSet from sympy.sets.setexpr import set_function if len(args) < 2: raise ValueError('imageset expects at least 2 args, got: %s' % len(args)) if isinstance(args[0], (Symbol, tuple)) and len(args) > 2: f = Lambda(args[0], args[1]) set_list = args[2:] else: f = args[0] set_list = args[1:] if isinstance(f, Lambda): pass elif callable(f): nargs = getattr(f, 'nargs', {}) if nargs: if len(nargs) != 1: raise NotImplementedError(filldedent(''' This function can take more than 1 arg but the potentially complicated set input has not been analyzed at this point to know its dimensions. TODO ''')) N = nargs.args[0] if N == 1: s = 'x' else: s = [Symbol('x%i' % i) for i in range(1, N + 1)] else: s = inspect.signature(f).parameters dexpr = _sympify(f(*[Dummy() for i in s])) var = tuple(uniquely_named_symbol( Symbol(i), dexpr) for i in s) f = Lambda(var, f(*var)) else: raise TypeError(filldedent(''' expecting lambda, Lambda, or FunctionClass, not \'%s\'.''' % func_name(f))) if any(not isinstance(s, Set) for s in set_list): name = [func_name(s) for s in set_list] raise ValueError( 'arguments after mapping should be sets, not %s' % name) if len(set_list) == 1: set = set_list[0] try: # TypeError if arg count != set dimensions r = set_function(f, set) if r is None: raise TypeError if not r: return r except TypeError: r = ImageSet(f, set) if isinstance(r, ImageSet): f, set = r.args if f.variables[0] == f.expr: return set if isinstance(set, ImageSet): # XXX: Maybe this should just be: # f2 = set.lambda # fun = Lambda(f2.signature, f(*f2.expr)) # return imageset(fun, *set.base_sets) if len(set.lamda.variables) == 1 and len(f.variables) == 1: x = set.lamda.variables[0] y = f.variables[0] return imageset( Lambda(x, f.expr.subs(y, set.lamda.expr)), *set.base_sets) if r is not None: return r return ImageSet(f, *set_list) def is_function_invertible_in_set(func, setv): """ Checks whether function ``func`` is invertible when the domain is restricted to set ``setv``. """ from sympy import exp, log # Functions known to always be invertible: if func in (exp, log): return True u = Dummy("u") fdiff = func(u).diff(u) # monotonous functions: # TODO: check subsets (`func` in `setv`) if (fdiff > 0) == True or (fdiff < 0) == True: return True # TODO: support more return None def simplify_union(args): """ Simplify a :class:`Union` using known rules. Explanation =========== We first start with global rules like 'Merge all FiniteSets' Then we iterate through all pairs and ask the constituent sets if they can simplify themselves with any other constituent. This process depends on ``union_sets(a, b)`` functions. """ from sympy.sets.handlers.union import union_sets # ===== Global Rules ===== if not args: return S.EmptySet for arg in args: if not isinstance(arg, Set): raise TypeError("Input args to Union must be Sets") # Merge all finite sets finite_sets = [x for x in args if x.is_FiniteSet] if len(finite_sets) > 1: a = (x for set in finite_sets for x in set) finite_set = FiniteSet(*a) args = [finite_set] + [x for x in args if not x.is_FiniteSet] # ===== Pair-wise Rules ===== # Here we depend on rules built into the constituent sets args = set(args) new_args = True while new_args: for s in args: new_args = False for t in args - {s}: new_set = union_sets(s, t) # This returns None if s does not know how to intersect # with t. Returns the newly intersected set otherwise if new_set is not None: if not isinstance(new_set, set): new_set = {new_set} new_args = (args - {s, t}).union(new_set) break if new_args: args = new_args break if len(args) == 1: return args.pop() else: return Union(*args, evaluate=False) def simplify_intersection(args): """ Simplify an intersection using known rules. Explanation =========== We first start with global rules like 'if any empty sets return empty set' and 'distribute any unions' Then we iterate through all pairs and ask the constituent sets if they can simplify themselves with any other constituent """ # ===== Global Rules ===== if not args: return S.UniversalSet for arg in args: if not isinstance(arg, Set): raise TypeError("Input args to Union must be Sets") # If any EmptySets return EmptySet if S.EmptySet in args: return S.EmptySet # Handle Finite sets rv = Intersection._handle_finite_sets(args) if rv is not None: return rv # If any of the sets are unions, return a Union of Intersections for s in args: if s.is_Union: other_sets = set(args) - {s} if len(other_sets) > 0: other = Intersection(*other_sets) return Union(*(Intersection(arg, other) for arg in s.args)) else: return Union(*[arg for arg in s.args]) for s in args: if s.is_Complement: args.remove(s) other_sets = args + [s.args[0]] return Complement(Intersection(*other_sets), s.args[1]) from sympy.sets.handlers.intersection import intersection_sets # At this stage we are guaranteed not to have any # EmptySets, FiniteSets, or Unions in the intersection # ===== Pair-wise Rules ===== # Here we depend on rules built into the constituent sets args = set(args) new_args = True while new_args: for s in args: new_args = False for t in args - {s}: new_set = intersection_sets(s, t) # This returns None if s does not know how to intersect # with t. Returns the newly intersected set otherwise if new_set is not None: new_args = (args - {s, t}).union({new_set}) break if new_args: args = new_args break if len(args) == 1: return args.pop() else: return Intersection(*args, evaluate=False) def _handle_finite_sets(op, x, y, commutative): # Handle finite sets: fs_args, other = sift([x, y], lambda x: isinstance(x, FiniteSet), binary=True) if len(fs_args) == 2: return FiniteSet(*[op(i, j) for i in fs_args[0] for j in fs_args[1]]) elif len(fs_args) == 1: sets = [_apply_operation(op, other[0], i, commutative) for i in fs_args[0]] return Union(*sets) else: return None def _apply_operation(op, x, y, commutative): from sympy.sets import ImageSet from sympy import symbols,Lambda d = Dummy('d') out = _handle_finite_sets(op, x, y, commutative) if out is None: out = op(x, y) if out is None and commutative: out = op(y, x) if out is None: _x, _y = symbols("x y") if isinstance(x, Set) and not isinstance(y, Set): out = ImageSet(Lambda(d, op(d, y)), x).doit() elif not isinstance(x, Set) and isinstance(y, Set): out = ImageSet(Lambda(d, op(x, d)), y).doit() else: out = ImageSet(Lambda((_x, _y), op(_x, _y)), x, y) return out def set_add(x, y): from sympy.sets.handlers.add import _set_add return _apply_operation(_set_add, x, y, commutative=True) def set_sub(x, y): from sympy.sets.handlers.add import _set_sub return _apply_operation(_set_sub, x, y, commutative=False) def set_mul(x, y): from sympy.sets.handlers.mul import _set_mul return _apply_operation(_set_mul, x, y, commutative=True) def set_div(x, y): from sympy.sets.handlers.mul import _set_div return _apply_operation(_set_div, x, y, commutative=False) def set_pow(x, y): from sympy.sets.handlers.power import _set_pow return _apply_operation(_set_pow, x, y, commutative=False) def set_function(f, x): from sympy.sets.handlers.functions import _set_function return _set_function(f, x) sympy-sympy-1.9/sympy/sets/tests/000077500000000000000000000000001412543434000172245ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sets/tests/__init__.py000066400000000000000000000000001412543434000213230ustar00rootroot00000000000000sympy-sympy-1.9/sympy/sets/tests/test_conditionset.py000066400000000000000000000246751412543434000233550ustar00rootroot00000000000000from sympy.core.expr import unchanged from sympy.sets import (ConditionSet, Intersection, FiniteSet, EmptySet, Union, Contains, ImageSet) from sympy import (Symbol, Eq, Ne, S, Abs, sin, asin, pi, Interval, And, Mod, oo, Function, Lambda, symbols, Matrix, MatrixSymbol) from sympy.testing.pytest import raises, warns_deprecated_sympy w = Symbol('w') x = Symbol('x') y = Symbol('y') z = Symbol('z') f = Function('f') def test_CondSet(): sin_sols_principal = ConditionSet(x, Eq(sin(x), 0), Interval(0, 2*pi, False, True)) assert pi in sin_sols_principal assert pi/2 not in sin_sols_principal assert 3*pi not in sin_sols_principal assert oo not in sin_sols_principal assert 5 in ConditionSet(x, x**2 > 4, S.Reals) assert 1 not in ConditionSet(x, x**2 > 4, S.Reals) # in this case, 0 is not part of the base set so # it can't be in any subset selected by the condition assert 0 not in ConditionSet(x, y > 5, Interval(1, 7)) # since 'in' requires a true/false, the following raises # an error because the given value provides no information # for the condition to evaluate (since the condition does # not depend on the dummy symbol): the result is `y > 5`. # In this case, ConditionSet is just acting like # Piecewise((Interval(1, 7), y > 5), (S.EmptySet, True)). raises(TypeError, lambda: 6 in ConditionSet(x, y > 5, Interval(1, 7))) X = MatrixSymbol('X', 2, 2) matrix_set = ConditionSet(X, Eq(X*Matrix([[1, 1], [1, 1]]), X)) Y = Matrix([[0, 0], [0, 0]]) assert matrix_set.contains(Y).doit() is S.true Z = Matrix([[1, 2], [3, 4]]) assert matrix_set.contains(Z).doit() is S.false assert isinstance(ConditionSet(x, x < 1, {x, y}).base_set, FiniteSet) raises(TypeError, lambda: ConditionSet(x, x + 1, {x, y})) raises(TypeError, lambda: ConditionSet(x, x, 1)) I = S.Integers U = S.UniversalSet C = ConditionSet assert C(x, False, I) is S.EmptySet assert C(x, True, I) is I assert C(x, x < 1, C(x, x < 2, I) ) == C(x, (x < 1) & (x < 2), I) assert C(y, y < 1, C(x, y < 2, I) ) == C(x, (x < 1) & (y < 2), I), C(y, y < 1, C(x, y < 2, I)) assert C(y, y < 1, C(x, x < 2, I) ) == C(y, (y < 1) & (y < 2), I) assert C(y, y < 1, C(x, y < x, I) ) == C(x, (x < 1) & (y < x), I) assert unchanged(C, y, x < 1, C(x, y < x, I)) assert ConditionSet(x, x < 1).base_set is U # arg checking is not done at instantiation but this # will raise an error when containment is tested assert ConditionSet((x,), x < 1).base_set is U c = ConditionSet((x, y), x < y, I**2) assert (1, 2) in c assert (1, pi) not in c raises(TypeError, lambda: C(x, x > 1, C((x, y), x > 1, I**2))) # signature mismatch since only 3 args are accepted raises(TypeError, lambda: C((x, y), x + y < 2, U, U)) def test_CondSet_intersect(): input_conditionset = ConditionSet(x, x**2 > 4, Interval(1, 4, False, False)) other_domain = Interval(0, 3, False, False) output_conditionset = ConditionSet(x, x**2 > 4, Interval( 1, 3, False, False)) assert Intersection(input_conditionset, other_domain ) == output_conditionset def test_issue_9849(): assert ConditionSet(x, Eq(x, x), S.Naturals ) is S.Naturals assert ConditionSet(x, Eq(Abs(sin(x)), -1), S.Naturals ) == S.EmptySet def test_simplified_FiniteSet_in_CondSet(): assert ConditionSet(x, And(x < 1, x > -3), FiniteSet(0, 1, 2) ) == FiniteSet(0) assert ConditionSet(x, x < 0, FiniteSet(0, 1, 2)) == EmptySet assert ConditionSet(x, And(x < -3), EmptySet) == EmptySet y = Symbol('y') assert (ConditionSet(x, And(x > 0), FiniteSet(-1, 0, 1, y)) == Union(FiniteSet(1), ConditionSet(x, And(x > 0), FiniteSet(y)))) assert (ConditionSet(x, Eq(Mod(x, 3), 1), FiniteSet(1, 4, 2, y)) == Union(FiniteSet(1, 4), ConditionSet(x, Eq(Mod(x, 3), 1), FiniteSet(y)))) def test_free_symbols(): assert ConditionSet(x, Eq(y, 0), FiniteSet(z) ).free_symbols == {y, z} assert ConditionSet(x, Eq(x, 0), FiniteSet(z) ).free_symbols == {z} assert ConditionSet(x, Eq(x, 0), FiniteSet(x, z) ).free_symbols == {x, z} assert ConditionSet(x, Eq(x, 0), ImageSet(Lambda(y, y**2), S.Integers)).free_symbols == set() def test_bound_symbols(): assert ConditionSet(x, Eq(y, 0), FiniteSet(z) ).bound_symbols == [x] assert ConditionSet(x, Eq(x, 0), FiniteSet(x, y) ).bound_symbols == [x] assert ConditionSet(x, x < 10, ImageSet(Lambda(y, y**2), S.Integers) ).bound_symbols == [x] assert ConditionSet(x, x < 10, ConditionSet(y, y > 1, S.Integers) ).bound_symbols == [x] def test_as_dummy(): _0, _1 = symbols('_0 _1') assert ConditionSet(x, x < 1, Interval(y, oo) ).as_dummy() == ConditionSet(_0, _0 < 1, Interval(y, oo)) assert ConditionSet(x, x < 1, Interval(x, oo) ).as_dummy() == ConditionSet(_0, _0 < 1, Interval(x, oo)) assert ConditionSet(x, x < 1, ImageSet(Lambda(y, y**2), S.Integers) ).as_dummy() == ConditionSet( _0, _0 < 1, ImageSet(Lambda(_0, _0**2), S.Integers)) e = ConditionSet((x, y), x <= y, S.Reals**2) assert e.bound_symbols == [x, y] assert e.as_dummy() == ConditionSet((_0, _1), _0 <= _1, S.Reals**2) assert e.as_dummy() == ConditionSet((y, x), y <= x, S.Reals**2 ).as_dummy() def test_subs_CondSet(): s = FiniteSet(z, y) c = ConditionSet(x, x < 2, s) assert c.subs(x, y) == c assert c.subs(z, y) == ConditionSet(x, x < 2, FiniteSet(y)) assert c.xreplace({x: y}) == ConditionSet(y, y < 2, s) assert ConditionSet(x, x < y, s ).subs(y, w) == ConditionSet(x, x < w, s.subs(y, w)) # if the user uses assumptions that cause the condition # to evaluate, that can't be helped from SymPy's end n = Symbol('n', negative=True) assert ConditionSet(n, 0 < n, S.Integers) is S.EmptySet p = Symbol('p', positive=True) assert ConditionSet(n, n < y, S.Integers ).subs(n, x) == ConditionSet(n, n < y, S.Integers) raises(ValueError, lambda: ConditionSet( x + 1, x < 1, S.Integers)) assert ConditionSet( p, n < x, Interval(-5, 5)).subs(x, p) == Interval(-5, 5), ConditionSet( p, n < x, Interval(-5, 5)).subs(x, p) assert ConditionSet( n, n < x, Interval(-oo, 0)).subs(x, p ) == Interval(-oo, 0) assert ConditionSet(f(x), f(x) < 1, {w, z} ).subs(f(x), y) == ConditionSet(f(x), f(x) < 1, {w, z}) # issue 17341 k = Symbol('k') img1 = ImageSet(Lambda(k, 2*k*pi + asin(y)), S.Integers) img2 = ImageSet(Lambda(k, 2*k*pi + asin(S.One/3)), S.Integers) assert ConditionSet(x, Contains( y, Interval(-1,1)), img1).subs(y, S.One/3).dummy_eq(img2) assert (0, 1) in ConditionSet((x, y), x + y < 3, S.Integers**2) raises(TypeError, lambda: ConditionSet(n, n < -10, Interval(0, 10))) def test_subs_CondSet_tebr(): with warns_deprecated_sympy(): assert ConditionSet((x, y), {x + 1, x + y}, S.Reals**2) == \ ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals**2) def test_dummy_eq(): C = ConditionSet I = S.Integers c = C(x, x < 1, I) assert c.dummy_eq(C(y, y < 1, I)) assert c.dummy_eq(1) == False assert c.dummy_eq(C(x, x < 1, S.Reals)) == False c1 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals**2) c2 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Reals**2) c3 = ConditionSet((x, y), Eq(x + 1, 0) & Eq(x + y, 0), S.Complexes**2) assert c1.dummy_eq(c2) assert c1.dummy_eq(c3) is False assert c.dummy_eq(c1) is False assert c1.dummy_eq(c) is False # issue 19496 m = Symbol('m') n = Symbol('n') a = Symbol('a') d1 = ImageSet(Lambda(m, m*pi), S.Integers) d2 = ImageSet(Lambda(n, n*pi), S.Integers) c1 = ConditionSet(x, Ne(a, 0), d1) c2 = ConditionSet(x, Ne(a, 0), d2) assert c1.dummy_eq(c2) def test_contains(): assert 6 in ConditionSet(x, x > 5, Interval(1, 7)) assert (8 in ConditionSet(x, y > 5, Interval(1, 7))) is False # `in` should give True or False; in this case there is not # enough information for that result raises(TypeError, lambda: 6 in ConditionSet(x, y > 5, Interval(1, 7))) # here, there is enough information but the comparison is # not defined raises(TypeError, lambda: 0 in ConditionSet(x, 1/x >= 0, S.Reals)) assert ConditionSet(x, y > 5, Interval(1, 7) ).contains(6) == (y > 5) assert ConditionSet(x, y > 5, Interval(1, 7) ).contains(8) is S.false assert ConditionSet(x, y > 5, Interval(1, 7) ).contains(w) == And(Contains(w, Interval(1, 7)), y > 5) # This returns an unevaluated Contains object # because 1/0 should not be defined for 1 and 0 in the context of # reals. assert ConditionSet(x, 1/x >= 0, S.Reals).contains(0) == \ Contains(0, ConditionSet(x, 1/x >= 0, S.Reals), evaluate=False) c = ConditionSet((x, y), x + y > 1, S.Integers**2) assert not c.contains(1) assert c.contains((2, 1)) assert not c.contains((0, 1)) c = ConditionSet((w, (x, y)), w + x + y > 1, S.Integers*S.Integers**2) assert not c.contains(1) assert not c.contains((1, 2)) assert not c.contains(((1, 2), 3)) assert not c.contains(((1, 2), (3, 4))) assert c.contains((1, (3, 4))) def test_as_relational(): assert ConditionSet((x, y), x > 1, S.Integers**2).as_relational((x, y) ) == (x > 1) & Contains((x, y), S.Integers**2) assert ConditionSet(x, x > 1, S.Integers).as_relational(x ) == Contains(x, S.Integers) & (x > 1) def test_flatten(): """Tests whether there is basic denesting functionality""" inner = ConditionSet(x, sin(x) + x > 0) outer = ConditionSet(x, Contains(x, inner), S.Reals) assert outer == ConditionSet(x, sin(x) + x > 0, S.Reals) inner = ConditionSet(y, sin(y) + y > 0) outer = ConditionSet(x, Contains(y, inner), S.Reals) assert outer != ConditionSet(x, sin(x) + x > 0, S.Reals) inner = ConditionSet(x, sin(x) + x > 0).intersect(Interval(-1, 1)) outer = ConditionSet(x, Contains(x, inner), S.Reals) assert outer == ConditionSet(x, sin(x) + x > 0, Interval(-1, 1)) def test_duplicate(): from sympy.core.function import BadSignatureError # test coverage for line 95 in conditionset.py, check for duplicates in symbols dup = symbols('a,a') raises(BadSignatureError, lambda: ConditionSet(dup, x < 0)) sympy-sympy-1.9/sympy/sets/tests/test_contains.py000066400000000000000000000026471412543434000224640ustar00rootroot00000000000000from sympy import Symbol, Contains, S, Interval, FiniteSet, oo, Eq from sympy.core.expr import unchanged from sympy.testing.pytest import raises def test_contains_basic(): raises(TypeError, lambda: Contains(S.Integers, 1)) assert Contains(2, S.Integers) is S.true assert Contains(-2, S.Naturals) is S.false i = Symbol('i', integer=True) assert Contains(i, S.Naturals) == Contains(i, S.Naturals, evaluate=False) def test_issue_6194(): x = Symbol('x') assert unchanged(Contains, x, Interval(0, 1)) assert Interval(0, 1).contains(x) == (S.Zero <= x) & (x <= 1) assert Contains(x, FiniteSet(0)) != S.false assert Contains(x, Interval(1, 1)) != S.false assert Contains(x, S.Integers) != S.false def test_issue_10326(): assert Contains(oo, Interval(-oo, oo)) == False assert Contains(-oo, Interval(-oo, oo)) == False def test_binary_symbols(): x = Symbol('x') y = Symbol('y') z = Symbol('z') assert Contains(x, FiniteSet(y, Eq(z, True)) ).binary_symbols == {y, z} def test_as_set(): x = Symbol('x') y = Symbol('y') # Contains is a BooleanFunction whose value depends on an arg's # containment in a Set -- rewriting as a Set is not yet implemented raises(NotImplementedError, lambda: Contains(x, FiniteSet(y)).as_set()) def test_type_error(): # Pass in a parameter not of type "set" raises(TypeError, lambda: Contains(2, None)) sympy-sympy-1.9/sympy/sets/tests/test_fancysets.py000066400000000000000000001360351412543434000226440ustar00rootroot00000000000000 from sympy.core.expr import unchanged from sympy.sets.fancysets import (ImageSet, Range, normalize_theta_set, ComplexRegion) from sympy.sets.sets import (FiniteSet, Interval, Union, imageset, Intersection, ProductSet, Contains) from sympy.sets.conditionset import ConditionSet from sympy.simplify.simplify import simplify from sympy import (S, Symbol, Lambda, symbols, cos, sin, pi, oo, Basic, Rational, sqrt, tan, log, exp, Abs, I, Tuple, eye, Dummy, floor, And, Eq) from sympy.utilities.iterables import cartes from sympy.testing.pytest import XFAIL, raises from sympy.abc import x, y, t, z from sympy.core.mod import Mod import itertools def test_naturals(): N = S.Naturals assert 5 in N assert -5 not in N assert 5.5 not in N ni = iter(N) a, b, c, d = next(ni), next(ni), next(ni), next(ni) assert (a, b, c, d) == (1, 2, 3, 4) assert isinstance(a, Basic) assert N.intersect(Interval(-5, 5)) == Range(1, 6) assert N.intersect(Interval(-5, 5, True, True)) == Range(1, 5) assert N.boundary == N assert N.is_open == False assert N.is_closed == True assert N.inf == 1 assert N.sup is oo assert not N.contains(oo) for s in (S.Naturals0, S.Naturals): assert s.intersection(S.Reals) is s assert s.is_subset(S.Reals) assert N.as_relational(x) == And(Eq(floor(x), x), x >= 1, x < oo) def test_naturals0(): N = S.Naturals0 assert 0 in N assert -1 not in N assert next(iter(N)) == 0 assert not N.contains(oo) assert N.contains(sin(x)) == Contains(sin(x), N) def test_integers(): Z = S.Integers assert 5 in Z assert -5 in Z assert 5.5 not in Z assert not Z.contains(oo) assert not Z.contains(-oo) zi = iter(Z) a, b, c, d = next(zi), next(zi), next(zi), next(zi) assert (a, b, c, d) == (0, 1, -1, 2) assert isinstance(a, Basic) assert Z.intersect(Interval(-5, 5)) == Range(-5, 6) assert Z.intersect(Interval(-5, 5, True, True)) == Range(-4, 5) assert Z.intersect(Interval(5, S.Infinity)) == Range(5, S.Infinity) assert Z.intersect(Interval.Lopen(5, S.Infinity)) == Range(6, S.Infinity) assert Z.inf is -oo assert Z.sup is oo assert Z.boundary == Z assert Z.is_open == False assert Z.is_closed == True assert Z.as_relational(x) == And(Eq(floor(x), x), -oo < x, x < oo) def test_ImageSet(): raises(ValueError, lambda: ImageSet(x, S.Integers)) assert ImageSet(Lambda(x, 1), S.Integers) == FiniteSet(1) assert ImageSet(Lambda(x, y), S.Integers) == {y} assert ImageSet(Lambda(x, 1), S.EmptySet) == S.EmptySet empty = Intersection(FiniteSet(log(2)/pi), S.Integers) assert unchanged(ImageSet, Lambda(x, 1), empty) # issue #17471 squares = ImageSet(Lambda(x, x**2), S.Naturals) assert 4 in squares assert 5 not in squares assert FiniteSet(*range(10)).intersect(squares) == FiniteSet(1, 4, 9) assert 16 not in squares.intersect(Interval(0, 10)) si = iter(squares) a, b, c, d = next(si), next(si), next(si), next(si) assert (a, b, c, d) == (1, 4, 9, 16) harmonics = ImageSet(Lambda(x, 1/x), S.Naturals) assert Rational(1, 5) in harmonics assert Rational(.25) in harmonics assert 0.25 not in harmonics assert Rational(.3) not in harmonics assert (1, 2) not in harmonics assert harmonics.is_iterable assert imageset(x, -x, Interval(0, 1)) == Interval(-1, 0) assert ImageSet(Lambda(x, x**2), Interval(0, 2)).doit() == Interval(0, 4) assert ImageSet(Lambda((x, y), 2*x), {4}, {3}).doit() == FiniteSet(8) assert (ImageSet(Lambda((x, y), x+y), {1, 2, 3}, {10, 20, 30}).doit() == FiniteSet(11, 12, 13, 21, 22, 23, 31, 32, 33)) c = Interval(1, 3) * Interval(1, 3) assert Tuple(2, 6) in ImageSet(Lambda(((x, y),), (x, 2*y)), c) assert Tuple(2, S.Half) in ImageSet(Lambda(((x, y),), (x, 1/y)), c) assert Tuple(2, -2) not in ImageSet(Lambda(((x, y),), (x, y**2)), c) assert Tuple(2, -2) in ImageSet(Lambda(((x, y),), (x, -2)), c) c3 = ProductSet(Interval(3, 7), Interval(8, 11), Interval(5, 9)) assert Tuple(8, 3, 9) in ImageSet(Lambda(((t, y, x),), (y, t, x)), c3) assert Tuple(Rational(1, 8), 3, 9) in ImageSet(Lambda(((t, y, x),), (1/y, t, x)), c3) assert 2/pi not in ImageSet(Lambda(((x, y),), 2/x), c) assert 2/S(100) not in ImageSet(Lambda(((x, y),), 2/x), c) assert Rational(2, 3) in ImageSet(Lambda(((x, y),), 2/x), c) S1 = imageset(lambda x, y: x + y, S.Integers, S.Naturals) assert S1.base_pset == ProductSet(S.Integers, S.Naturals) assert S1.base_sets == (S.Integers, S.Naturals) # Passing a set instead of a FiniteSet shouldn't raise assert unchanged(ImageSet, Lambda(x, x**2), {1, 2, 3}) S2 = ImageSet(Lambda(((x, y),), x+y), {(1, 2), (3, 4)}) assert 3 in S2.doit() # FIXME: This doesn't yet work: #assert 3 in S2 assert S2._contains(3) is None raises(TypeError, lambda: ImageSet(Lambda(x, x**2), 1)) def test_image_is_ImageSet(): assert isinstance(imageset(x, sqrt(sin(x)), Range(5)), ImageSet) def test_halfcircle(): r, th = symbols('r, theta', real=True) L = Lambda(((r, th),), (r*cos(th), r*sin(th))) halfcircle = ImageSet(L, Interval(0, 1)*Interval(0, pi)) assert (1, 0) in halfcircle assert (0, -1) not in halfcircle assert (0, 0) in halfcircle assert halfcircle._contains((r, 0)) is None # This one doesn't work: #assert (r, 2*pi) not in halfcircle assert not halfcircle.is_iterable def test_ImageSet_iterator_not_injective(): L = Lambda(x, x - x % 2) # produces 0, 2, 2, 4, 4, 6, 6, ... evens = ImageSet(L, S.Naturals) i = iter(evens) # No repeats here assert (next(i), next(i), next(i), next(i)) == (0, 2, 4, 6) def test_inf_Range_len(): raises(ValueError, lambda: len(Range(0, oo, 2))) assert Range(0, oo, 2).size is S.Infinity assert Range(0, -oo, -2).size is S.Infinity assert Range(oo, 0, -2).size is S.Infinity assert Range(-oo, 0, 2).size is S.Infinity def test_Range_set(): empty = Range(0) assert Range(5) == Range(0, 5) == Range(0, 5, 1) r = Range(10, 20, 2) assert 12 in r assert 8 not in r assert 11 not in r assert 30 not in r assert list(Range(0, 5)) == list(range(5)) assert list(Range(5, 0, -1)) == list(range(5, 0, -1)) assert Range(5, 15).sup == 14 assert Range(5, 15).inf == 5 assert Range(15, 5, -1).sup == 15 assert Range(15, 5, -1).inf == 6 assert Range(10, 67, 10).sup == 60 assert Range(60, 7, -10).inf == 10 assert len(Range(10, 38, 10)) == 3 assert Range(0, 0, 5) == empty assert Range(oo, oo, 1) == empty assert Range(oo, 1, 1) == empty assert Range(-oo, 1, -1) == empty assert Range(1, oo, -1) == empty assert Range(1, -oo, 1) == empty assert Range(1, -4, oo) == empty ip = symbols('ip', positive=True) assert Range(0, ip, -1) == empty assert Range(0, -ip, 1) == empty assert Range(1, -4, -oo) == Range(1, 2) assert Range(1, 4, oo) == Range(1, 2) assert Range(-oo, oo).size == oo assert Range(oo, -oo, -1).size == oo raises(ValueError, lambda: Range(-oo, oo, 2)) raises(ValueError, lambda: Range(x, pi, y)) raises(ValueError, lambda: Range(x, y, 0)) assert 5 in Range(0, oo, 5) assert -5 in Range(-oo, 0, 5) assert oo not in Range(0, oo) ni = symbols('ni', integer=False) assert ni not in Range(oo) u = symbols('u', integer=None) assert Range(oo).contains(u) is not False inf = symbols('inf', infinite=True) assert inf not in Range(-oo, oo) raises(ValueError, lambda: Range(0, oo, 2)[-1]) raises(ValueError, lambda: Range(0, -oo, -2)[-1]) assert Range(-oo, 1, 1)[-1] is S.Zero assert Range(oo, 1, -1)[-1] == 2 assert inf not in Range(oo) assert Range(1, 10, 1)[-1] == 9 assert all(i.is_Integer for i in Range(0, -1, 1)) it = iter(Range(-oo, 0, 2)) raises(TypeError, lambda: next(it)) assert empty.intersect(S.Integers) == empty assert Range(-1, 10, 1).intersect(S.Integers) == Range(-1, 10, 1) assert Range(-1, 10, 1).intersect(S.Naturals) == Range(1, 10, 1) assert Range(-1, 10, 1).intersect(S.Naturals0) == Range(0, 10, 1) # test slicing assert Range(1, 10, 1)[5] == 6 assert Range(1, 12, 2)[5] == 11 assert Range(1, 10, 1)[-1] == 9 assert Range(1, 10, 3)[-1] == 7 raises(ValueError, lambda: Range(oo,0,-1)[1:3:0]) raises(ValueError, lambda: Range(oo,0,-1)[:1]) raises(ValueError, lambda: Range(1, oo)[-2]) raises(ValueError, lambda: Range(-oo, 1)[2]) raises(IndexError, lambda: Range(10)[-20]) raises(IndexError, lambda: Range(10)[20]) raises(ValueError, lambda: Range(2, -oo, -2)[2:2:0]) assert Range(2, -oo, -2)[2:2:2] == empty assert Range(2, -oo, -2)[:2:2] == Range(2, -2, -4) raises(ValueError, lambda: Range(-oo, 4, 2)[:2:2]) assert Range(-oo, 4, 2)[::-2] == Range(2, -oo, -4) raises(ValueError, lambda: Range(-oo, 4, 2)[::2]) assert Range(oo, 2, -2)[::] == Range(oo, 2, -2) assert Range(-oo, 4, 2)[:-2:-2] == Range(2, 0, -4) assert Range(-oo, 4, 2)[:-2:2] == Range(-oo, 0, 4) raises(ValueError, lambda: Range(-oo, 4, 2)[:0:-2]) raises(ValueError, lambda: Range(-oo, 4, 2)[:2:-2]) assert Range(-oo, 4, 2)[-2::-2] == Range(0, -oo, -4) raises(ValueError, lambda: Range(-oo, 4, 2)[-2:0:-2]) raises(ValueError, lambda: Range(-oo, 4, 2)[0::2]) assert Range(oo, 2, -2)[0::] == Range(oo, 2, -2) raises(ValueError, lambda: Range(-oo, 4, 2)[0:-2:2]) assert Range(oo, 2, -2)[0:-2:] == Range(oo, 6, -2) raises(ValueError, lambda: Range(oo, 2, -2)[0:2:]) raises(ValueError, lambda: Range(-oo, 4, 2)[2::-1]) assert Range(-oo, 4, 2)[-2::2] == Range(0, 4, 4) assert Range(oo, 0, -2)[-10:0:2] == empty raises(ValueError, lambda: Range(oo, 0, -2)[0]) raises(ValueError, lambda: Range(oo, 0, -2)[-10:10:2]) raises(ValueError, lambda: Range(oo, 0, -2)[0::-2]) assert Range(oo, 0, -2)[0:-4:-2] == empty assert Range(oo, 0, -2)[:0:2] == empty raises(ValueError, lambda: Range(oo, 0, -2)[:1:-1]) # test empty Range assert Range(x, x, y) == empty assert empty.reversed == empty assert 0 not in empty assert list(empty) == [] assert len(empty) == 0 assert empty.size is S.Zero assert empty.intersect(FiniteSet(0)) is S.EmptySet assert bool(empty) is False raises(IndexError, lambda: empty[0]) assert empty[:0] == empty raises(NotImplementedError, lambda: empty.inf) raises(NotImplementedError, lambda: empty.sup) assert empty.as_relational(x) is S.false AB = [None] + list(range(12)) for R in [ Range(1, 10), Range(1, 10, 2), ]: r = list(R) for a, b, c in cartes(AB, AB, [-3, -1, None, 1, 3]): for reverse in range(2): r = list(reversed(r)) R = R.reversed result = list(R[a:b:c]) ans = r[a:b:c] txt = ('\n%s[%s:%s:%s] = %s -> %s' % ( R, a, b, c, result, ans)) check = ans == result assert check, txt assert Range(1, 10, 1).boundary == Range(1, 10, 1) for r in (Range(1, 10, 2), Range(1, oo, 2)): rev = r.reversed assert r.inf == rev.inf and r.sup == rev.sup assert r.step == -rev.step builtin_range = range raises(TypeError, lambda: Range(builtin_range(1))) assert S(builtin_range(10)) == Range(10) assert S(builtin_range(1000000000000)) == Range(1000000000000) # test Range.as_relational assert Range(1, 4).as_relational(x) == (x >= 1) & (x <= 3) & Eq(Mod(x, 1), 0) assert Range(oo, 1, -2).as_relational(x) == (x >= 3) & (x < oo) & Eq(Mod(x + 1, -2), 0) def test_Range_symbolic(): # symbolic Range xr = Range(x, x + 4, 5) sr = Range(x, y, t) i = Symbol('i', integer=True) ip = Symbol('i', integer=True, positive=True) ipr = Range(ip) inr = Range(0, -ip, -1) ir = Range(i, i + 19, 2) ir2 = Range(i, i*8, 3*i) i = Symbol('i', integer=True) inf = symbols('inf', infinite=True) raises(ValueError, lambda: Range(inf)) raises(ValueError, lambda: Range(inf, 0, -1)) raises(ValueError, lambda: Range(inf, inf, 1)) raises(ValueError, lambda: Range(1, 1, inf)) # args assert xr.args == (x, x + 5, 5) assert sr.args == (x, y, t) assert ir.args == (i, i + 20, 2) assert ir2.args == (i, 10*i, 3*i) # reversed raises(ValueError, lambda: xr.reversed) raises(ValueError, lambda: sr.reversed) assert ipr.reversed.args == (ip - 1, -1, -1) assert inr.reversed.args == (-ip + 1, 1, 1) assert ir.reversed.args == (i + 18, i - 2, -2) assert ir2.reversed.args == (7*i, -2*i, -3*i) # contains assert inf not in sr assert inf not in ir assert 0 in ipr assert 0 in inr raises(TypeError, lambda: 1 in ipr) raises(TypeError, lambda: -1 in inr) assert .1 not in sr assert .1 not in ir assert i + 1 not in ir assert i + 2 in ir raises(TypeError, lambda: x in xr) # XXX is this what contains is supposed to do? raises(TypeError, lambda: 1 in sr) # XXX is this what contains is supposed to do? # iter raises(ValueError, lambda: next(iter(xr))) raises(ValueError, lambda: next(iter(sr))) assert next(iter(ir)) == i assert next(iter(ir2)) == i assert sr.intersect(S.Integers) == sr assert sr.intersect(FiniteSet(x)) == Intersection({x}, sr) raises(ValueError, lambda: sr[:2]) raises(ValueError, lambda: xr[0]) raises(ValueError, lambda: sr[0]) # len assert len(ir) == ir.size == 10 assert len(ir2) == ir2.size == 3 raises(ValueError, lambda: len(xr)) raises(ValueError, lambda: xr.size) raises(ValueError, lambda: len(sr)) raises(ValueError, lambda: sr.size) # bool assert bool(Range(0)) == False assert bool(xr) assert bool(ir) assert bool(ipr) assert bool(inr) raises(ValueError, lambda: bool(sr)) raises(ValueError, lambda: bool(ir2)) # inf raises(ValueError, lambda: xr.inf) raises(ValueError, lambda: sr.inf) assert ipr.inf == 0 assert inr.inf == -ip + 1 assert ir.inf == i raises(ValueError, lambda: ir2.inf) # sup raises(ValueError, lambda: xr.sup) raises(ValueError, lambda: sr.sup) assert ipr.sup == ip - 1 assert inr.sup == 0 assert ir.inf == i raises(ValueError, lambda: ir2.sup) # getitem raises(ValueError, lambda: xr[0]) raises(ValueError, lambda: sr[0]) raises(ValueError, lambda: sr[-1]) raises(ValueError, lambda: sr[:2]) assert ir[:2] == Range(i, i + 4, 2) assert ir[0] == i assert ir[-2] == i + 16 assert ir[-1] == i + 18 assert ir2[:2] == Range(i, 7*i, 3*i) assert ir2[0] == i assert ir2[-2] == 4*i assert ir2[-1] == 7*i raises(ValueError, lambda: Range(i)[-1]) assert ipr[0] == ipr.inf == 0 assert ipr[-1] == ipr.sup == ip - 1 assert inr[0] == inr.sup == 0 assert inr[-1] == inr.inf == -ip + 1 raises(ValueError, lambda: ipr[-2]) assert ir.inf == i assert ir.sup == i + 18 raises(ValueError, lambda: Range(i).inf) # as_relational assert ir.as_relational(x) == ((x >= i) & (x <= i + 18) & Eq(Mod(-i + x, 2), 0)) assert ir2.as_relational(x) == Eq( Mod(-i + x, 3*i), 0) & (((x >= i) & (x <= 7*i) & (3*i >= 1)) | ((x <= i) & (x >= 7*i) & (3*i <= -1))) assert Range(i, i + 1).as_relational(x) == Eq(x, i) assert sr.as_relational(z) == Eq( Mod(t, 1), 0) & Eq(Mod(x, 1), 0) & Eq(Mod(-x + z, t), 0 ) & (((z >= x) & (z <= -t + y) & (t >= 1)) | ((z <= x) & (z >= -t + y) & (t <= -1))) assert xr.as_relational(z) == Eq(z, x) & Eq(Mod(x, 1), 0) # symbols can clash if user wants (but it must be integer) assert xr.as_relational(x) == Eq(Mod(x, 1), 0) # contains() for symbolic values (issue #18146) e = Symbol('e', integer=True, even=True) o = Symbol('o', integer=True, odd=True) assert Range(5).contains(i) == And(i >= 0, i <= 4) assert Range(1).contains(i) == Eq(i, 0) assert Range(-oo, 5, 1).contains(i) == (i <= 4) assert Range(-oo, oo).contains(i) == True assert Range(0, 8, 2).contains(i) == Contains(i, Range(0, 8, 2)) assert Range(0, 8, 2).contains(e) == And(e >= 0, e <= 6) assert Range(0, 8, 2).contains(2*i) == And(2*i >= 0, 2*i <= 6) assert Range(0, 8, 2).contains(o) == False assert Range(1, 9, 2).contains(e) == False assert Range(1, 9, 2).contains(o) == And(o >= 1, o <= 7) assert Range(8, 0, -2).contains(o) == False assert Range(9, 1, -2).contains(o) == And(o >= 3, o <= 9) assert Range(-oo, 8, 2).contains(i) == Contains(i, Range(-oo, 8, 2)) def test_range_range_intersection(): for a, b, r in [ (Range(0), Range(1), S.EmptySet), (Range(3), Range(4, oo), S.EmptySet), (Range(3), Range(-3, -1), S.EmptySet), (Range(1, 3), Range(0, 3), Range(1, 3)), (Range(1, 3), Range(1, 4), Range(1, 3)), (Range(1, oo, 2), Range(2, oo, 2), S.EmptySet), (Range(0, oo, 2), Range(oo), Range(0, oo, 2)), (Range(0, oo, 2), Range(100), Range(0, 100, 2)), (Range(2, oo, 2), Range(oo), Range(2, oo, 2)), (Range(0, oo, 2), Range(5, 6), S.EmptySet), (Range(2, 80, 1), Range(55, 71, 4), Range(55, 71, 4)), (Range(0, 6, 3), Range(-oo, 5, 3), S.EmptySet), (Range(0, oo, 2), Range(5, oo, 3), Range(8, oo, 6)), (Range(4, 6, 2), Range(2, 16, 7), S.EmptySet),]: assert a.intersect(b) == r assert a.intersect(b.reversed) == r assert a.reversed.intersect(b) == r assert a.reversed.intersect(b.reversed) == r a, b = b, a assert a.intersect(b) == r assert a.intersect(b.reversed) == r assert a.reversed.intersect(b) == r assert a.reversed.intersect(b.reversed) == r def test_range_interval_intersection(): p = symbols('p', positive=True) assert isinstance(Range(3).intersect(Interval(p, p + 2)), Intersection) assert Range(4).intersect(Interval(0, 3)) == Range(4) assert Range(4).intersect(Interval(-oo, oo)) == Range(4) assert Range(4).intersect(Interval(1, oo)) == Range(1, 4) assert Range(4).intersect(Interval(1.1, oo)) == Range(2, 4) assert Range(4).intersect(Interval(0.1, 3)) == Range(1, 4) assert Range(4).intersect(Interval(0.1, 3.1)) == Range(1, 4) assert Range(4).intersect(Interval.open(0, 3)) == Range(1, 3) assert Range(4).intersect(Interval.open(0.1, 0.5)) is S.EmptySet # Null Range intersections assert Range(0).intersect(Interval(0.2, 0.8)) is S.EmptySet assert Range(0).intersect(Interval(-oo, oo)) is S.EmptySet def test_range_is_finite_set(): assert Range(-100, 100).is_finite_set is True assert Range(2, oo).is_finite_set is False assert Range(-oo, 50).is_finite_set is False assert Range(-oo, oo).is_finite_set is False assert Range(oo, -oo).is_finite_set is True assert Range(0, 0).is_finite_set is True assert Range(oo, oo).is_finite_set is True assert Range(-oo, -oo).is_finite_set is True n = Symbol('n', integer=True) m = Symbol('m', integer=True) assert Range(n, n + 49).is_finite_set is True assert Range(n, 0).is_finite_set is True assert Range(-3, n + 7).is_finite_set is True assert Range(n, m).is_finite_set is True assert Range(n + m, m - n).is_finite_set is True assert Range(n, n + m + n).is_finite_set is True assert Range(n, oo).is_finite_set is False assert Range(-oo, n).is_finite_set is False # assert Range(n, -oo).is_finite_set is True # assert Range(oo, n).is_finite_set is True # Above tests fail due to a (potential) bug in sympy.sets.fancysets.Range.size (See issue #18999) def test_Integers_eval_imageset(): ans = ImageSet(Lambda(x, 2*x + Rational(3, 7)), S.Integers) im = imageset(Lambda(x, -2*x + Rational(3, 7)), S.Integers) assert im == ans im = imageset(Lambda(x, -2*x - Rational(11, 7)), S.Integers) assert im == ans y = Symbol('y') L = imageset(x, 2*x + y, S.Integers) assert y + 4 in L a, b, c = 0.092, 0.433, 0.341 assert a in imageset(x, a + c*x, S.Integers) assert b in imageset(x, b + c*x, S.Integers) _x = symbols('x', negative=True) eq = _x**2 - _x + 1 assert imageset(_x, eq, S.Integers).lamda.expr == _x**2 + _x + 1 eq = 3*_x - 1 assert imageset(_x, eq, S.Integers).lamda.expr == 3*_x + 2 assert imageset(x, (x, 1/x), S.Integers) == \ ImageSet(Lambda(x, (x, 1/x)), S.Integers) def test_Range_eval_imageset(): a, b, c = symbols('a b c') assert imageset(x, a*(x + b) + c, Range(3)) == \ imageset(x, a*x + a*b + c, Range(3)) eq = (x + 1)**2 assert imageset(x, eq, Range(3)).lamda.expr == eq eq = a*(x + b) + c r = Range(3, -3, -2) imset = imageset(x, eq, r) assert imset.lamda.expr != eq assert list(imset) == [eq.subs(x, i).expand() for i in list(r)] def test_fun(): assert (FiniteSet(*ImageSet(Lambda(x, sin(pi*x/4)), Range(-10, 11))) == FiniteSet(-1, -sqrt(2)/2, 0, sqrt(2)/2, 1)) def test_Reals(): assert 5 in S.Reals assert S.Pi in S.Reals assert -sqrt(2) in S.Reals assert (2, 5) not in S.Reals assert sqrt(-1) not in S.Reals assert S.Reals == Interval(-oo, oo) assert S.Reals != Interval(0, oo) assert S.Reals.is_subset(Interval(-oo, oo)) assert S.Reals.intersect(Range(-oo, oo)) == Range(-oo, oo) def test_Complex(): assert 5 in S.Complexes assert 5 + 4*I in S.Complexes assert S.Pi in S.Complexes assert -sqrt(2) in S.Complexes assert -I in S.Complexes assert sqrt(-1) in S.Complexes assert S.Complexes.intersect(S.Reals) == S.Reals assert S.Complexes.union(S.Reals) == S.Complexes assert S.Complexes == ComplexRegion(S.Reals*S.Reals) assert (S.Complexes == ComplexRegion(Interval(1, 2)*Interval(3, 4))) == False assert str(S.Complexes) == "S.Complexes" assert repr(S.Complexes) == "S.Complexes" def take(n, iterable): "Return first n items of the iterable as a list" return list(itertools.islice(iterable, n)) def test_intersections(): assert S.Integers.intersect(S.Reals) == S.Integers assert 5 in S.Integers.intersect(S.Reals) assert 5 in S.Integers.intersect(S.Reals) assert -5 not in S.Naturals.intersect(S.Reals) assert 5.5 not in S.Integers.intersect(S.Reals) assert 5 in S.Integers.intersect(Interval(3, oo)) assert -5 in S.Integers.intersect(Interval(-oo, 3)) assert all(x.is_Integer for x in take(10, S.Integers.intersect(Interval(3, oo)) )) def test_infinitely_indexed_set_1(): from sympy.abc import n, m, t assert imageset(Lambda(n, n), S.Integers) == imageset(Lambda(m, m), S.Integers) assert imageset(Lambda(n, 2*n), S.Integers).intersect( imageset(Lambda(m, 2*m + 1), S.Integers)) is S.EmptySet assert imageset(Lambda(n, 2*n), S.Integers).intersect( imageset(Lambda(n, 2*n + 1), S.Integers)) is S.EmptySet assert imageset(Lambda(m, 2*m), S.Integers).intersect( imageset(Lambda(n, 3*n), S.Integers)).dummy_eq( ImageSet(Lambda(t, 6*t), S.Integers)) assert imageset(x, x/2 + Rational(1, 3), S.Integers).intersect(S.Integers) is S.EmptySet assert imageset(x, x/2 + S.Half, S.Integers).intersect(S.Integers) is S.Integers # https://github.com/sympy/sympy/issues/17355 S53 = ImageSet(Lambda(n, 5*n + 3), S.Integers) assert S53.intersect(S.Integers) == S53 def test_infinitely_indexed_set_2(): from sympy.abc import n a = Symbol('a', integer=True) assert imageset(Lambda(n, n), S.Integers) == \ imageset(Lambda(n, n + a), S.Integers) assert imageset(Lambda(n, n + pi), S.Integers) == \ imageset(Lambda(n, n + a + pi), S.Integers) assert imageset(Lambda(n, n), S.Integers) == \ imageset(Lambda(n, -n + a), S.Integers) assert imageset(Lambda(n, -6*n), S.Integers) == \ ImageSet(Lambda(n, 6*n), S.Integers) assert imageset(Lambda(n, 2*n + pi), S.Integers) == \ ImageSet(Lambda(n, 2*n + pi - 2), S.Integers) def test_imageset_intersect_real(): from sympy import I from sympy.abc import n assert imageset(Lambda(n, n + (n - 1)*(n + 1)*I), S.Integers).intersect(S.Reals) == FiniteSet(-1, 1) im = (n - 1)*(n + S.Half) assert imageset(Lambda(n, n + im*I), S.Integers ).intersect(S.Reals) == FiniteSet(1) assert imageset(Lambda(n, n + im*(n + 1)*I), S.Naturals0 ).intersect(S.Reals) == FiniteSet(1) assert imageset(Lambda(n, n/2 + im.expand()*I), S.Integers ).intersect(S.Reals) == ImageSet(Lambda(x, x/2), ConditionSet( n, Eq(n**2 - n/2 - S(1)/2, 0), S.Integers)) assert imageset(Lambda(n, n/(1/n - 1) + im*(n + 1)*I), S.Integers ).intersect(S.Reals) == FiniteSet(S.Half) assert imageset(Lambda(n, n/(n - 6) + (n - 3)*(n + 1)*I/(2*n + 2)), S.Integers).intersect( S.Reals) == FiniteSet(-1) assert imageset(Lambda(n, n/(n**2 - 9) + (n - 3)*(n + 1)*I/(2*n + 2)), S.Integers).intersect( S.Reals) is S.EmptySet s = ImageSet( Lambda(n, -I*(I*(2*pi*n - pi/4) + log(Abs(sqrt(-I))))), S.Integers) # s is unevaluated, but after intersection the result # should be canonical assert s.intersect(S.Reals) == imageset( Lambda(n, 2*n*pi - pi/4), S.Integers) == ImageSet( Lambda(n, 2*pi*n + pi*Rational(7, 4)), S.Integers) def test_imageset_intersect_interval(): from sympy.abc import n f1 = ImageSet(Lambda(n, n*pi), S.Integers) f2 = ImageSet(Lambda(n, 2*n), Interval(0, pi)) f3 = ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers) # complex expressions f4 = ImageSet(Lambda(n, n*I*pi), S.Integers) f5 = ImageSet(Lambda(n, 2*I*n*pi + pi/2), S.Integers) # non-linear expressions f6 = ImageSet(Lambda(n, log(n)), S.Integers) f7 = ImageSet(Lambda(n, n**2), S.Integers) f8 = ImageSet(Lambda(n, Abs(n)), S.Integers) f9 = ImageSet(Lambda(n, exp(n)), S.Naturals0) assert f1.intersect(Interval(-1, 1)) == FiniteSet(0) assert f1.intersect(Interval(0, 2*pi, False, True)) == FiniteSet(0, pi) assert f2.intersect(Interval(1, 2)) == Interval(1, 2) assert f3.intersect(Interval(-1, 1)) == S.EmptySet assert f3.intersect(Interval(-5, 5)) == FiniteSet(pi*Rational(-3, 2), pi/2) assert f4.intersect(Interval(-1, 1)) == FiniteSet(0) assert f4.intersect(Interval(1, 2)) == S.EmptySet assert f5.intersect(Interval(0, 1)) == S.EmptySet assert f6.intersect(Interval(0, 1)) == FiniteSet(S.Zero, log(2)) assert f7.intersect(Interval(0, 10)) == Intersection(f7, Interval(0, 10)) assert f8.intersect(Interval(0, 2)) == Intersection(f8, Interval(0, 2)) assert f9.intersect(Interval(1, 2)) == Intersection(f9, Interval(1, 2)) def test_imageset_intersect_diophantine(): from sympy.abc import m, n # Check that same lambda variable for both ImageSets is handled correctly img1 = ImageSet(Lambda(n, 2*n + 1), S.Integers) img2 = ImageSet(Lambda(n, 4*n + 1), S.Integers) assert img1.intersect(img2) == img2 # Empty solution set returned by diophantine: assert ImageSet(Lambda(n, 2*n), S.Integers).intersect( ImageSet(Lambda(n, 2*n + 1), S.Integers)) == S.EmptySet # Check intersection with S.Integers: assert ImageSet(Lambda(n, 9/n + 20*n/3), S.Integers).intersect( S.Integers) == FiniteSet(-61, -23, 23, 61) # Single solution (2, 3) for diophantine solution: assert ImageSet(Lambda(n, (n - 2)**2), S.Integers).intersect( ImageSet(Lambda(n, -(n - 3)**2), S.Integers)) == FiniteSet(0) # Single parametric solution for diophantine solution: assert ImageSet(Lambda(n, n**2 + 5), S.Integers).intersect( ImageSet(Lambda(m, 2*m), S.Integers)).dummy_eq(ImageSet( Lambda(n, 4*n**2 + 4*n + 6), S.Integers)) # 4 non-parametric solution couples for dioph. equation: assert ImageSet(Lambda(n, n**2 - 9), S.Integers).intersect( ImageSet(Lambda(m, -m**2), S.Integers)) == FiniteSet(-9, 0) # Double parametric solution for diophantine solution: assert ImageSet(Lambda(m, m**2 + 40), S.Integers).intersect( ImageSet(Lambda(n, 41*n), S.Integers)).dummy_eq(Intersection( ImageSet(Lambda(m, m**2 + 40), S.Integers), ImageSet(Lambda(n, 41*n), S.Integers))) # Check that diophantine returns *all* (8) solutions (permute=True) assert ImageSet(Lambda(n, n**4 - 2**4), S.Integers).intersect( ImageSet(Lambda(m, -m**4 + 3**4), S.Integers)) == FiniteSet(0, 65) assert ImageSet(Lambda(n, pi/12 + n*5*pi/12), S.Integers).intersect( ImageSet(Lambda(n, 7*pi/12 + n*11*pi/12), S.Integers)).dummy_eq(ImageSet( Lambda(n, 55*pi*n/12 + 17*pi/4), S.Integers)) # TypeError raised by diophantine (#18081) assert ImageSet(Lambda(n, n*log(2)), S.Integers).intersection( S.Integers).dummy_eq(Intersection(ImageSet( Lambda(n, n*log(2)), S.Integers), S.Integers)) # NotImplementedError raised by diophantine (no solver for cubic_thue) assert ImageSet(Lambda(n, n**3 + 1), S.Integers).intersect( ImageSet(Lambda(n, n**3), S.Integers)).dummy_eq(Intersection( ImageSet(Lambda(n, n**3 + 1), S.Integers), ImageSet(Lambda(n, n**3), S.Integers))) def test_infinitely_indexed_set_3(): from sympy.abc import n, m, t assert imageset(Lambda(m, 2*pi*m), S.Integers).intersect( imageset(Lambda(n, 3*pi*n), S.Integers)).dummy_eq( ImageSet(Lambda(t, 6*pi*t), S.Integers)) assert imageset(Lambda(n, 2*n + 1), S.Integers) == \ imageset(Lambda(n, 2*n - 1), S.Integers) assert imageset(Lambda(n, 3*n + 2), S.Integers) == \ imageset(Lambda(n, 3*n - 1), S.Integers) def test_ImageSet_simplification(): from sympy.abc import n, m assert imageset(Lambda(n, n), S.Integers) == S.Integers assert imageset(Lambda(n, sin(n)), imageset(Lambda(m, tan(m)), S.Integers)) == \ imageset(Lambda(m, sin(tan(m))), S.Integers) assert imageset(n, 1 + 2*n, S.Naturals) == Range(3, oo, 2) assert imageset(n, 1 + 2*n, S.Naturals0) == Range(1, oo, 2) assert imageset(n, 1 - 2*n, S.Naturals) == Range(-1, -oo, -2) def test_ImageSet_contains(): from sympy.abc import x assert (2, S.Half) in imageset(x, (x, 1/x), S.Integers) assert imageset(x, x + I*3, S.Integers).intersection(S.Reals) is S.EmptySet i = Dummy(integer=True) q = imageset(x, x + I*y, S.Integers).intersection(S.Reals) assert q.subs(y, I*i).intersection(S.Integers) is S.Integers q = imageset(x, x + I*y/x, S.Integers).intersection(S.Reals) assert q.subs(y, 0) is S.Integers assert q.subs(y, I*i*x).intersection(S.Integers) is S.Integers z = cos(1)**2 + sin(1)**2 - 1 q = imageset(x, x + I*z, S.Integers).intersection(S.Reals) assert q is not S.EmptySet def test_ComplexRegion_contains(): r = Symbol('r', real=True) # contains in ComplexRegion a = Interval(2, 3) b = Interval(4, 6) c = Interval(7, 9) c1 = ComplexRegion(a*b) c2 = ComplexRegion(Union(a*b, c*a)) assert 2.5 + 4.5*I in c1 assert 2 + 4*I in c1 assert 3 + 4*I in c1 assert 8 + 2.5*I in c2 assert 2.5 + 6.1*I not in c1 assert 4.5 + 3.2*I not in c1 assert c1.contains(x) == Contains(x, c1, evaluate=False) assert c1.contains(r) == False assert c2.contains(x) == Contains(x, c2, evaluate=False) assert c2.contains(r) == False r1 = Interval(0, 1) theta1 = Interval(0, 2*S.Pi) c3 = ComplexRegion(r1*theta1, polar=True) assert (0.5 + I*Rational(6, 10)) in c3 assert (S.Half + I*Rational(6, 10)) in c3 assert (S.Half + .6*I) in c3 assert (0.5 + .6*I) in c3 assert I in c3 assert 1 in c3 assert 0 in c3 assert 1 + I not in c3 assert 1 - I not in c3 assert c3.contains(x) == Contains(x, c3, evaluate=False) assert c3.contains(r + 2*I) == Contains( r + 2*I, c3, evaluate=False) # is in fact False assert c3.contains(1/(1 + r**2)) == Contains( 1/(1 + r**2), c3, evaluate=False) # is in fact True r2 = Interval(0, 3) theta2 = Interval(pi, 2*pi, left_open=True) c4 = ComplexRegion(r2*theta2, polar=True) assert c4.contains(0) == True assert c4.contains(2 + I) == False assert c4.contains(-2 + I) == False assert c4.contains(-2 - I) == True assert c4.contains(2 - I) == True assert c4.contains(-2) == False assert c4.contains(2) == True assert c4.contains(x) == Contains(x, c4, evaluate=False) assert c4.contains(3/(1 + r**2)) == Contains( 3/(1 + r**2), c4, evaluate=False) # is in fact True raises(ValueError, lambda: ComplexRegion(r1*theta1, polar=2)) def test_symbolic_Range(): n = Symbol('n') raises(ValueError, lambda: Range(n)[0]) raises(IndexError, lambda: Range(n, n)[0]) raises(ValueError, lambda: Range(n, n+1)[0]) raises(ValueError, lambda: Range(n).size) n = Symbol('n', integer=True) raises(ValueError, lambda: Range(n)[0]) raises(IndexError, lambda: Range(n, n)[0]) assert Range(n, n+1)[0] == n raises(ValueError, lambda: Range(n).size) assert Range(n, n+1).size == 1 n = Symbol('n', integer=True, nonnegative=True) raises(ValueError, lambda: Range(n)[0]) raises(IndexError, lambda: Range(n, n)[0]) assert Range(n+1)[0] == 0 assert Range(n, n+1)[0] == n assert Range(n).size == n assert Range(n+1).size == n+1 assert Range(n, n+1).size == 1 n = Symbol('n', integer=True, positive=True) assert Range(n)[0] == 0 assert Range(n, n+1)[0] == n assert Range(n).size == n assert Range(n, n+1).size == 1 m = Symbol('m', integer=True, positive=True) assert Range(n, n+m)[0] == n assert Range(n, n+m).size == m assert Range(n, n+1).size == 1 assert Range(n, n+m, 2).size == floor(m/2) m = Symbol('m', integer=True, positive=True, even=True) assert Range(n, n+m, 2).size == m/2 def test_issue_18400(): n = Symbol('n', integer=True) raises(ValueError, lambda: imageset(lambda x: x*2, Range(n))) n = Symbol('n', integer=True, positive=True) # No exception assert imageset(lambda x: x*2, Range(n)) == imageset(lambda x: x*2, Range(n)) def test_ComplexRegion_intersect(): # Polar form X_axis = ComplexRegion(Interval(0, oo)*FiniteSet(0, S.Pi), polar=True) unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, 2*S.Pi), polar=True) upper_half_unit_disk = ComplexRegion(Interval(0, 1)*Interval(0, S.Pi), polar=True) upper_half_disk = ComplexRegion(Interval(0, oo)*Interval(0, S.Pi), polar=True) lower_half_disk = ComplexRegion(Interval(0, oo)*Interval(S.Pi, 2*S.Pi), polar=True) right_half_disk = ComplexRegion(Interval(0, oo)*Interval(-S.Pi/2, S.Pi/2), polar=True) first_quad_disk = ComplexRegion(Interval(0, oo)*Interval(0, S.Pi/2), polar=True) assert upper_half_disk.intersect(unit_disk) == upper_half_unit_disk assert right_half_disk.intersect(first_quad_disk) == first_quad_disk assert upper_half_disk.intersect(right_half_disk) == first_quad_disk assert upper_half_disk.intersect(lower_half_disk) == X_axis c1 = ComplexRegion(Interval(0, 4)*Interval(0, 2*S.Pi), polar=True) assert c1.intersect(Interval(1, 5)) == Interval(1, 4) assert c1.intersect(Interval(4, 9)) == FiniteSet(4) assert c1.intersect(Interval(5, 12)) is S.EmptySet # Rectangular form X_axis = ComplexRegion(Interval(-oo, oo)*FiniteSet(0)) unit_square = ComplexRegion(Interval(-1, 1)*Interval(-1, 1)) upper_half_unit_square = ComplexRegion(Interval(-1, 1)*Interval(0, 1)) upper_half_plane = ComplexRegion(Interval(-oo, oo)*Interval(0, oo)) lower_half_plane = ComplexRegion(Interval(-oo, oo)*Interval(-oo, 0)) right_half_plane = ComplexRegion(Interval(0, oo)*Interval(-oo, oo)) first_quad_plane = ComplexRegion(Interval(0, oo)*Interval(0, oo)) assert upper_half_plane.intersect(unit_square) == upper_half_unit_square assert right_half_plane.intersect(first_quad_plane) == first_quad_plane assert upper_half_plane.intersect(right_half_plane) == first_quad_plane assert upper_half_plane.intersect(lower_half_plane) == X_axis c1 = ComplexRegion(Interval(-5, 5)*Interval(-10, 10)) assert c1.intersect(Interval(2, 7)) == Interval(2, 5) assert c1.intersect(Interval(5, 7)) == FiniteSet(5) assert c1.intersect(Interval(6, 9)) is S.EmptySet # unevaluated object C1 = ComplexRegion(Interval(0, 1)*Interval(0, 2*S.Pi), polar=True) C2 = ComplexRegion(Interval(-1, 1)*Interval(-1, 1)) assert C1.intersect(C2) == Intersection(C1, C2, evaluate=False) def test_ComplexRegion_union(): # Polar form c1 = ComplexRegion(Interval(0, 1)*Interval(0, 2*S.Pi), polar=True) c2 = ComplexRegion(Interval(0, 1)*Interval(0, S.Pi), polar=True) c3 = ComplexRegion(Interval(0, oo)*Interval(0, S.Pi), polar=True) c4 = ComplexRegion(Interval(0, oo)*Interval(S.Pi, 2*S.Pi), polar=True) p1 = Union(Interval(0, 1)*Interval(0, 2*S.Pi), Interval(0, 1)*Interval(0, S.Pi)) p2 = Union(Interval(0, oo)*Interval(0, S.Pi), Interval(0, oo)*Interval(S.Pi, 2*S.Pi)) assert c1.union(c2) == ComplexRegion(p1, polar=True) assert c3.union(c4) == ComplexRegion(p2, polar=True) # Rectangular form c5 = ComplexRegion(Interval(2, 5)*Interval(6, 9)) c6 = ComplexRegion(Interval(4, 6)*Interval(10, 12)) c7 = ComplexRegion(Interval(0, 10)*Interval(-10, 0)) c8 = ComplexRegion(Interval(12, 16)*Interval(14, 20)) p3 = Union(Interval(2, 5)*Interval(6, 9), Interval(4, 6)*Interval(10, 12)) p4 = Union(Interval(0, 10)*Interval(-10, 0), Interval(12, 16)*Interval(14, 20)) assert c5.union(c6) == ComplexRegion(p3) assert c7.union(c8) == ComplexRegion(p4) assert c1.union(Interval(2, 4)) == Union(c1, Interval(2, 4), evaluate=False) assert c5.union(Interval(2, 4)) == Union(c5, ComplexRegion.from_real(Interval(2, 4))) def test_ComplexRegion_from_real(): c1 = ComplexRegion(Interval(0, 1) * Interval(0, 2 * S.Pi), polar=True) raises(ValueError, lambda: c1.from_real(c1)) assert c1.from_real(Interval(-1, 1)) == ComplexRegion(Interval(-1, 1) * FiniteSet(0), False) def test_ComplexRegion_measure(): a, b = Interval(2, 5), Interval(4, 8) theta1, theta2 = Interval(0, 2*S.Pi), Interval(0, S.Pi) c1 = ComplexRegion(a*b) c2 = ComplexRegion(Union(a*theta1, b*theta2), polar=True) assert c1.measure == 12 assert c2.measure == 9*pi def test_normalize_theta_set(): # Interval assert normalize_theta_set(Interval(pi, 2*pi)) == \ Union(FiniteSet(0), Interval.Ropen(pi, 2*pi)) assert normalize_theta_set(Interval(pi*Rational(9, 2), 5*pi)) == Interval(pi/2, pi) assert normalize_theta_set(Interval(pi*Rational(-3, 2), pi/2)) == Interval.Ropen(0, 2*pi) assert normalize_theta_set(Interval.open(pi*Rational(-3, 2), pi/2)) == \ Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi)) assert normalize_theta_set(Interval.open(pi*Rational(-7, 2), pi*Rational(-3, 2))) == \ Union(Interval.Ropen(0, pi/2), Interval.open(pi/2, 2*pi)) assert normalize_theta_set(Interval(-pi/2, pi/2)) == \ Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval.open(-pi/2, pi/2)) == \ Union(Interval.Ropen(0, pi/2), Interval.open(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval(-4*pi, 3*pi)) == Interval.Ropen(0, 2*pi) assert normalize_theta_set(Interval(pi*Rational(-3, 2), -pi/2)) == Interval(pi/2, pi*Rational(3, 2)) assert normalize_theta_set(Interval.open(0, 2*pi)) == Interval.open(0, 2*pi) assert normalize_theta_set(Interval.Ropen(-pi/2, pi/2)) == \ Union(Interval.Ropen(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval.Lopen(-pi/2, pi/2)) == \ Union(Interval(0, pi/2), Interval.open(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval(-pi/2, pi/2)) == \ Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) assert normalize_theta_set(Interval.open(4*pi, pi*Rational(9, 2))) == Interval.open(0, pi/2) assert normalize_theta_set(Interval.Lopen(4*pi, pi*Rational(9, 2))) == Interval.Lopen(0, pi/2) assert normalize_theta_set(Interval.Ropen(4*pi, pi*Rational(9, 2))) == Interval.Ropen(0, pi/2) assert normalize_theta_set(Interval.open(3*pi, 5*pi)) == \ Union(Interval.Ropen(0, pi), Interval.open(pi, 2*pi)) # FiniteSet assert normalize_theta_set(FiniteSet(0, pi, 3*pi)) == FiniteSet(0, pi) assert normalize_theta_set(FiniteSet(0, pi/2, pi, 2*pi)) == FiniteSet(0, pi/2, pi) assert normalize_theta_set(FiniteSet(0, -pi/2, -pi, -2*pi)) == FiniteSet(0, pi, pi*Rational(3, 2)) assert normalize_theta_set(FiniteSet(pi*Rational(-3, 2), pi/2)) == \ FiniteSet(pi/2) assert normalize_theta_set(FiniteSet(2*pi)) == FiniteSet(0) # Unions assert normalize_theta_set(Union(Interval(0, pi/3), Interval(pi/2, pi))) == \ Union(Interval(0, pi/3), Interval(pi/2, pi)) assert normalize_theta_set(Union(Interval(0, pi), Interval(2*pi, pi*Rational(7, 3)))) == \ Interval(0, pi) # ValueError for non-real sets raises(ValueError, lambda: normalize_theta_set(S.Complexes)) # NotImplementedError for subset of reals raises(NotImplementedError, lambda: normalize_theta_set(Interval(0, 1))) # NotImplementedError without pi as coefficient raises(NotImplementedError, lambda: normalize_theta_set(Interval(1, 2*pi))) raises(NotImplementedError, lambda: normalize_theta_set(Interval(2*pi, 10))) raises(NotImplementedError, lambda: normalize_theta_set(FiniteSet(0, 3, 3*pi))) def test_ComplexRegion_FiniteSet(): x, y, z, a, b, c = symbols('x y z a b c') # Issue #9669 assert ComplexRegion(FiniteSet(a, b, c)*FiniteSet(x, y, z)) == \ FiniteSet(a + I*x, a + I*y, a + I*z, b + I*x, b + I*y, b + I*z, c + I*x, c + I*y, c + I*z) assert ComplexRegion(FiniteSet(2)*FiniteSet(3)) == FiniteSet(2 + 3*I) def test_union_RealSubSet(): assert (S.Complexes).union(Interval(1, 2)) == S.Complexes assert (S.Complexes).union(S.Integers) == S.Complexes def test_issue_9980(): c1 = ComplexRegion(Interval(1, 2)*Interval(2, 3)) c2 = ComplexRegion(Interval(1, 5)*Interval(1, 3)) R = Union(c1, c2) assert simplify(R) == ComplexRegion(Union(Interval(1, 2)*Interval(2, 3), \ Interval(1, 5)*Interval(1, 3)), False) assert c1.func(*c1.args) == c1 assert R.func(*R.args) == R def test_issue_11732(): interval12 = Interval(1, 2) finiteset1234 = FiniteSet(1, 2, 3, 4) pointComplex = Tuple(1, 5) assert (interval12 in S.Naturals) == False assert (interval12 in S.Naturals0) == False assert (interval12 in S.Integers) == False assert (interval12 in S.Complexes) == False assert (finiteset1234 in S.Naturals) == False assert (finiteset1234 in S.Naturals0) == False assert (finiteset1234 in S.Integers) == False assert (finiteset1234 in S.Complexes) == False assert (pointComplex in S.Naturals) == False assert (pointComplex in S.Naturals0) == False assert (pointComplex in S.Integers) == False assert (pointComplex in S.Complexes) == True def test_issue_11730(): unit = Interval(0, 1) square = ComplexRegion(unit ** 2) assert Union(S.Complexes, FiniteSet(oo)) != S.Complexes assert Union(S.Complexes, FiniteSet(eye(4))) != S.Complexes assert Union(unit, square) == square assert Intersection(S.Reals, square) == unit def test_issue_11938(): unit = Interval(0, 1) ival = Interval(1, 2) cr1 = ComplexRegion(ival * unit) assert Intersection(cr1, S.Reals) == ival assert Intersection(cr1, unit) == FiniteSet(1) arg1 = Interval(0, S.Pi) arg2 = FiniteSet(S.Pi) arg3 = Interval(S.Pi / 4, 3 * S.Pi / 4) cp1 = ComplexRegion(unit * arg1, polar=True) cp2 = ComplexRegion(unit * arg2, polar=True) cp3 = ComplexRegion(unit * arg3, polar=True) assert Intersection(cp1, S.Reals) == Interval(-1, 1) assert Intersection(cp2, S.Reals) == Interval(-1, 0) assert Intersection(cp3, S.Reals) == FiniteSet(0) def test_issue_11914(): a, b = Interval(0, 1), Interval(0, pi) c, d = Interval(2, 3), Interval(pi, 3 * pi / 2) cp1 = ComplexRegion(a * b, polar=True) cp2 = ComplexRegion(c * d, polar=True) assert -3 in cp1.union(cp2) assert -3 in cp2.union(cp1) assert -5 not in cp1.union(cp2) def test_issue_9543(): assert ImageSet(Lambda(x, x**2), S.Naturals).is_subset(S.Reals) def test_issue_16871(): assert ImageSet(Lambda(x, x), FiniteSet(1)) == {1} assert ImageSet(Lambda(x, x - 3), S.Integers ).intersection(S.Integers) is S.Integers @XFAIL def test_issue_16871b(): assert ImageSet(Lambda(x, x - 3), S.Integers).is_subset(S.Integers) def test_issue_18050(): assert imageset(Lambda(x, I*x + 1), S.Integers ) == ImageSet(Lambda(x, I*x + 1), S.Integers) assert imageset(Lambda(x, 3*I*x + 4 + 8*I), S.Integers ) == ImageSet(Lambda(x, 3*I*x + 4 + 2*I), S.Integers) # no 'Mod' for next 2 tests: assert imageset(Lambda(x, 2*x + 3*I), S.Integers ) == ImageSet(Lambda(x, 2*x + 3*I), S.Integers) r = Symbol('r', positive=True) assert imageset(Lambda(x, r*x + 10), S.Integers ) == ImageSet(Lambda(x, r*x + 10), S.Integers) # reduce real part: assert imageset(Lambda(x, 3*x + 8 + 5*I), S.Integers ) == ImageSet(Lambda(x, 3*x + 2 + 5*I), S.Integers) def test_Rationals(): assert S.Integers.is_subset(S.Rationals) assert S.Naturals.is_subset(S.Rationals) assert S.Naturals0.is_subset(S.Rationals) assert S.Rationals.is_subset(S.Reals) assert S.Rationals.inf is -oo assert S.Rationals.sup is oo it = iter(S.Rationals) assert [next(it) for i in range(12)] == [ 0, 1, -1, S.Half, 2, Rational(-1, 2), -2, Rational(1, 3), 3, Rational(-1, 3), -3, Rational(2, 3)] assert Basic() not in S.Rationals assert S.Half in S.Rationals assert S.Rationals.contains(0.5) == Contains(0.5, S.Rationals, evaluate=False) assert 2 in S.Rationals r = symbols('r', rational=True) assert r in S.Rationals raises(TypeError, lambda: x in S.Rationals) # issue #18134: assert S.Rationals.boundary == S.Reals assert S.Rationals.closure == S.Reals assert S.Rationals.is_open == False assert S.Rationals.is_closed == False def test_NZQRC_unions(): # check that all trivial number set unions are simplified: nbrsets = (S.Naturals, S.Naturals0, S.Integers, S.Rationals, S.Reals, S.Complexes) unions = (Union(a, b) for a in nbrsets for b in nbrsets) assert all(u.is_Union is False for u in unions) def test_imageset_intersection(): n = Dummy() s = ImageSet(Lambda(n, -I*(I*(2*pi*n - pi/4) + log(Abs(sqrt(-I))))), S.Integers) assert s.intersect(S.Reals) == ImageSet( Lambda(n, 2*pi*n + pi*Rational(7, 4)), S.Integers) def test_issue_17858(): assert 1 in Range(-oo, oo) assert 0 in Range(oo, -oo, -1) assert oo not in Range(-oo, oo) assert -oo not in Range(-oo, oo) def test_issue_17859(): r = Range(-oo,oo) raises(ValueError,lambda: r[::2]) raises(ValueError, lambda: r[::-2]) r = Range(oo,-oo,-1) raises(ValueError,lambda: r[::2]) raises(ValueError, lambda: r[::-2]) sympy-sympy-1.9/sympy/sets/tests/test_ordinals.py000066400000000000000000000051151412543434000224520ustar00rootroot00000000000000from sympy.sets.ordinals import Ordinal, OmegaPower, ord0, omega from sympy.testing.pytest import raises def test_string_ordinals(): assert str(omega) == 'w' assert str(Ordinal(OmegaPower(5, 3), OmegaPower(3, 2))) == 'w**5*3 + w**3*2' assert str(Ordinal(OmegaPower(5, 3), OmegaPower(0, 5))) == 'w**5*3 + 5' assert str(Ordinal(OmegaPower(1, 3), OmegaPower(0, 5))) == 'w*3 + 5' assert str(Ordinal(OmegaPower(omega + 1 ,1), OmegaPower(3, 2))) == 'w**(w + 1) + w**3*2' def test_addition_with_integers(): assert 3 + Ordinal(OmegaPower(5, 3)) == Ordinal(OmegaPower(5, 3)) assert Ordinal(OmegaPower(5, 3))+3 == Ordinal(OmegaPower(5, 3), OmegaPower(0, 3)) assert Ordinal(OmegaPower(5, 3), OmegaPower(0, 2))+3 == \ Ordinal(OmegaPower(5, 3), OmegaPower(0, 5)) def test_addition_with_ordinals(): assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) + Ordinal(OmegaPower(3, 3)) == \ Ordinal(OmegaPower(5, 3), OmegaPower(3, 5)) assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) + Ordinal(OmegaPower(4, 2)) == \ Ordinal(OmegaPower(5, 3), OmegaPower(4, 2)) assert Ordinal(OmegaPower(omega, 2), OmegaPower(3, 2)) + Ordinal(OmegaPower(4, 2)) == \ Ordinal(OmegaPower(omega, 2), OmegaPower(4, 2)) def test_comparison(): assert Ordinal(OmegaPower(5, 3)) > Ordinal(OmegaPower(4, 3), OmegaPower(2, 1)) assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) < Ordinal(OmegaPower(5, 4)) assert Ordinal(OmegaPower(5, 4)) < Ordinal(OmegaPower(5, 5), OmegaPower(4, 1)) assert Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) == \ Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) assert not Ordinal(OmegaPower(5, 3), OmegaPower(3, 2)) == Ordinal(OmegaPower(5, 3)) assert Ordinal(OmegaPower(omega, 3)) > Ordinal(OmegaPower(5, 3)) def test_multiplication_with_integers(): w = omega assert 3*w == w assert w*9 == Ordinal(OmegaPower(1, 9)) def test_multiplication(): w = omega assert w*(w + 1) == w*w + w assert (w + 1)*(w + 1) == w*w + w + 1 assert w*1 == w assert 1*w == w assert w*ord0 == ord0 assert ord0*w == ord0 assert w**w == w * w**w assert (w**w)*w*w == w**(w + 2) def test_exponentiation(): w = omega assert w**2 == w*w assert w**3 == w*w*w assert w**(w + 1) == Ordinal(OmegaPower(omega + 1, 1)) assert (w**w)*(w**w) == w**(w*2) def test_comapre_not_instance(): w = OmegaPower(omega + 1, 1) assert(not (w == None)) assert(not (w < 5)) raises(TypeError, lambda: w < 6.66) def test_is_successort(): w = Ordinal(OmegaPower(5, 1)) assert not w.is_successor_ordinal sympy-sympy-1.9/sympy/sets/tests/test_powerset.py000066400000000000000000000113041412543434000225040ustar00rootroot00000000000000from sympy.core.expr import unchanged from sympy.core.singleton import S from sympy.core.symbol import Symbol from sympy.sets.contains import Contains from sympy.sets.fancysets import Interval from sympy.sets.powerset import PowerSet from sympy.sets.sets import FiniteSet from sympy.testing.pytest import raises, XFAIL def test_powerset_creation(): assert unchanged(PowerSet, FiniteSet(1, 2)) assert unchanged(PowerSet, S.EmptySet) raises(ValueError, lambda: PowerSet(123)) assert unchanged(PowerSet, S.Reals) assert unchanged(PowerSet, S.Integers) def test_powerset_rewrite_FiniteSet(): assert PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) == \ FiniteSet(S.EmptySet, FiniteSet(1), FiniteSet(2), FiniteSet(1, 2)) assert PowerSet(S.EmptySet).rewrite(FiniteSet) == FiniteSet(S.EmptySet) assert PowerSet(S.Naturals).rewrite(FiniteSet) == PowerSet(S.Naturals) def test_finiteset_rewrite_powerset(): assert FiniteSet(S.EmptySet).rewrite(PowerSet) == PowerSet(S.EmptySet) assert FiniteSet( S.EmptySet, FiniteSet(1), FiniteSet(2), FiniteSet(1, 2)).rewrite(PowerSet) == \ PowerSet(FiniteSet(1, 2)) assert FiniteSet(1, 2, 3).rewrite(PowerSet) == FiniteSet(1, 2, 3) def test_powerset__contains__(): subset_series = [ S.EmptySet, FiniteSet(1, 2), S.Naturals, S.Naturals0, S.Integers, S.Rationals, S.Reals, S.Complexes] l = len(subset_series) for i in range(l): for j in range(l): if i <= j: assert subset_series[i] in \ PowerSet(subset_series[j], evaluate=False) else: assert subset_series[i] not in \ PowerSet(subset_series[j], evaluate=False) @XFAIL def test_failing_powerset__contains__(): # XXX These are failing when evaluate=True, # but using unevaluated PowerSet works fine. assert FiniteSet(1, 2) not in PowerSet(S.EmptySet).rewrite(FiniteSet) assert S.Naturals not in PowerSet(S.EmptySet).rewrite(FiniteSet) assert S.Naturals not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) assert S.Naturals0 not in PowerSet(S.EmptySet).rewrite(FiniteSet) assert S.Naturals0 not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) assert S.Integers not in PowerSet(S.EmptySet).rewrite(FiniteSet) assert S.Integers not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) assert S.Rationals not in PowerSet(S.EmptySet).rewrite(FiniteSet) assert S.Rationals not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) assert S.Reals not in PowerSet(S.EmptySet).rewrite(FiniteSet) assert S.Reals not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) assert S.Complexes not in PowerSet(S.EmptySet).rewrite(FiniteSet) assert S.Complexes not in PowerSet(FiniteSet(1, 2)).rewrite(FiniteSet) def test_powerset__len__(): A = PowerSet(S.EmptySet, evaluate=False) assert len(A) == 1 A = PowerSet(A, evaluate=False) assert len(A) == 2 A = PowerSet(A, evaluate=False) assert len(A) == 4 A = PowerSet(A, evaluate=False) assert len(A) == 16 def test_powerset__iter__(): a = PowerSet(FiniteSet(1, 2)).__iter__() assert next(a) == S.EmptySet assert next(a) == FiniteSet(1) assert next(a) == FiniteSet(2) assert next(a) == FiniteSet(1, 2) a = PowerSet(S.Naturals).__iter__() assert next(a) == S.EmptySet assert next(a) == FiniteSet(1) assert next(a) == FiniteSet(2) assert next(a) == FiniteSet(1, 2) assert next(a) == FiniteSet(3) assert next(a) == FiniteSet(1, 3) assert next(a) == FiniteSet(2, 3) assert next(a) == FiniteSet(1, 2, 3) def test_powerset_contains(): A = PowerSet(FiniteSet(1), evaluate=False) assert A.contains(2) == Contains(2, A) x = Symbol('x') A = PowerSet(FiniteSet(x), evaluate=False) assert A.contains(FiniteSet(1)) == Contains(FiniteSet(1), A) def test_powerset_method(): # EmptySet A = FiniteSet() pset = A.powerset() assert len(pset) == 1 assert pset == FiniteSet(S.EmptySet) # FiniteSets A = FiniteSet(1, 2) pset = A.powerset() assert len(pset) == 2**len(A) assert pset == FiniteSet(FiniteSet(), FiniteSet(1), FiniteSet(2), A) # Not finite sets A = Interval(0, 1) assert A.powerset() == PowerSet(A) def test_is_subset(): # covers line 101-102 # initalize powerset(1), which is a subset of powerset(1,2) subset = PowerSet(FiniteSet(1)) pset = PowerSet(FiniteSet(1, 2)) bad_set = PowerSet(FiniteSet(2, 3)) # assert "subset" is subset of pset == True assert subset.is_subset(pset) # assert "bad_set" is subset of pset == False assert not pset.is_subset(bad_set) sympy-sympy-1.9/sympy/sets/tests/test_setexpr.py000066400000000000000000000342271412543434000223370ustar00rootroot00000000000000from sympy.sets.setexpr import SetExpr from sympy.sets import Interval, FiniteSet, Intersection, ImageSet, Union from sympy import (Expr, Set, exp, log, cos, Symbol, Min, Max, S, oo, I, symbols, Lambda, Dummy, Rational) a, x = symbols("a, x") _d = Dummy("d") def test_setexpr(): se = SetExpr(Interval(0, 1)) assert isinstance(se.set, Set) assert isinstance(se, Expr) def test_scalar_funcs(): assert SetExpr(Interval(0, 1)).set == Interval(0, 1) a, b = Symbol('a', real=True), Symbol('b', real=True) a, b = 1, 2 # TODO: add support for more functions in the future: for f in [exp, log]: input_se = f(SetExpr(Interval(a, b))) output = input_se.set expected = Interval(Min(f(a), f(b)), Max(f(a), f(b))) assert output == expected def test_Add_Mul(): assert (SetExpr(Interval(0, 1)) + 1).set == Interval(1, 2) assert (SetExpr(Interval(0, 1))*2).set == Interval(0, 2) def test_Pow(): assert (SetExpr(Interval(0, 2))**2).set == Interval(0, 4) def test_compound(): assert (exp(SetExpr(Interval(0, 1))*2 + 1)).set == \ Interval(exp(1), exp(3)) def test_Interval_Interval(): assert (SetExpr(Interval(1, 2)) + SetExpr(Interval(10, 20))).set == \ Interval(11, 22) assert (SetExpr(Interval(1, 2))*SetExpr(Interval(10, 20))).set == \ Interval(10, 40) def test_FiniteSet_FiniteSet(): assert (SetExpr(FiniteSet(1, 2, 3)) + SetExpr(FiniteSet(1, 2))).set == \ FiniteSet(2, 3, 4, 5) assert (SetExpr(FiniteSet(1, 2, 3))*SetExpr(FiniteSet(1, 2))).set == \ FiniteSet(1, 2, 3, 4, 6) def test_Interval_FiniteSet(): assert (SetExpr(FiniteSet(1, 2)) + SetExpr(Interval(0, 10))).set == \ Interval(1, 12) def test_Many_Sets(): assert (SetExpr(Interval(0, 1)) + SetExpr(Interval(2, 3)) + SetExpr(FiniteSet(10, 11, 12))).set == Interval(12, 16) def test_same_setexprs_are_not_identical(): a = SetExpr(FiniteSet(0, 1)) b = SetExpr(FiniteSet(0, 1)) assert (a + b).set == FiniteSet(0, 1, 2) # Cannont detect the set being the same: # assert (a + a).set == FiniteSet(0, 2) def test_Interval_arithmetic(): i12cc = SetExpr(Interval(1, 2)) i12lo = SetExpr(Interval.Lopen(1, 2)) i12ro = SetExpr(Interval.Ropen(1, 2)) i12o = SetExpr(Interval.open(1, 2)) n23cc = SetExpr(Interval(-2, 3)) n23lo = SetExpr(Interval.Lopen(-2, 3)) n23ro = SetExpr(Interval.Ropen(-2, 3)) n23o = SetExpr(Interval.open(-2, 3)) n3n2cc = SetExpr(Interval(-3, -2)) assert i12cc + i12cc == SetExpr(Interval(2, 4)) assert i12cc - i12cc == SetExpr(Interval(-1, 1)) assert i12cc*i12cc == SetExpr(Interval(1, 4)) assert i12cc/i12cc == SetExpr(Interval(S.Half, 2)) assert i12cc**2 == SetExpr(Interval(1, 4)) assert i12cc**3 == SetExpr(Interval(1, 8)) assert i12lo + i12ro == SetExpr(Interval.open(2, 4)) assert i12lo - i12ro == SetExpr(Interval.Lopen(-1, 1)) assert i12lo*i12ro == SetExpr(Interval.open(1, 4)) assert i12lo/i12ro == SetExpr(Interval.Lopen(S.Half, 2)) assert i12lo + i12lo == SetExpr(Interval.Lopen(2, 4)) assert i12lo - i12lo == SetExpr(Interval.open(-1, 1)) assert i12lo*i12lo == SetExpr(Interval.Lopen(1, 4)) assert i12lo/i12lo == SetExpr(Interval.open(S.Half, 2)) assert i12lo + i12cc == SetExpr(Interval.Lopen(2, 4)) assert i12lo - i12cc == SetExpr(Interval.Lopen(-1, 1)) assert i12lo*i12cc == SetExpr(Interval.Lopen(1, 4)) assert i12lo/i12cc == SetExpr(Interval.Lopen(S.Half, 2)) assert i12lo + i12o == SetExpr(Interval.open(2, 4)) assert i12lo - i12o == SetExpr(Interval.open(-1, 1)) assert i12lo*i12o == SetExpr(Interval.open(1, 4)) assert i12lo/i12o == SetExpr(Interval.open(S.Half, 2)) assert i12lo**2 == SetExpr(Interval.Lopen(1, 4)) assert i12lo**3 == SetExpr(Interval.Lopen(1, 8)) assert i12ro + i12ro == SetExpr(Interval.Ropen(2, 4)) assert i12ro - i12ro == SetExpr(Interval.open(-1, 1)) assert i12ro*i12ro == SetExpr(Interval.Ropen(1, 4)) assert i12ro/i12ro == SetExpr(Interval.open(S.Half, 2)) assert i12ro + i12cc == SetExpr(Interval.Ropen(2, 4)) assert i12ro - i12cc == SetExpr(Interval.Ropen(-1, 1)) assert i12ro*i12cc == SetExpr(Interval.Ropen(1, 4)) assert i12ro/i12cc == SetExpr(Interval.Ropen(S.Half, 2)) assert i12ro + i12o == SetExpr(Interval.open(2, 4)) assert i12ro - i12o == SetExpr(Interval.open(-1, 1)) assert i12ro*i12o == SetExpr(Interval.open(1, 4)) assert i12ro/i12o == SetExpr(Interval.open(S.Half, 2)) assert i12ro**2 == SetExpr(Interval.Ropen(1, 4)) assert i12ro**3 == SetExpr(Interval.Ropen(1, 8)) assert i12o + i12lo == SetExpr(Interval.open(2, 4)) assert i12o - i12lo == SetExpr(Interval.open(-1, 1)) assert i12o*i12lo == SetExpr(Interval.open(1, 4)) assert i12o/i12lo == SetExpr(Interval.open(S.Half, 2)) assert i12o + i12ro == SetExpr(Interval.open(2, 4)) assert i12o - i12ro == SetExpr(Interval.open(-1, 1)) assert i12o*i12ro == SetExpr(Interval.open(1, 4)) assert i12o/i12ro == SetExpr(Interval.open(S.Half, 2)) assert i12o + i12cc == SetExpr(Interval.open(2, 4)) assert i12o - i12cc == SetExpr(Interval.open(-1, 1)) assert i12o*i12cc == SetExpr(Interval.open(1, 4)) assert i12o/i12cc == SetExpr(Interval.open(S.Half, 2)) assert i12o**2 == SetExpr(Interval.open(1, 4)) assert i12o**3 == SetExpr(Interval.open(1, 8)) assert n23cc + n23cc == SetExpr(Interval(-4, 6)) assert n23cc - n23cc == SetExpr(Interval(-5, 5)) assert n23cc*n23cc == SetExpr(Interval(-6, 9)) assert n23cc/n23cc == SetExpr(Interval.open(-oo, oo)) assert n23cc + n23ro == SetExpr(Interval.Ropen(-4, 6)) assert n23cc - n23ro == SetExpr(Interval.Lopen(-5, 5)) assert n23cc*n23ro == SetExpr(Interval.Ropen(-6, 9)) assert n23cc/n23ro == SetExpr(Interval.Lopen(-oo, oo)) assert n23cc + n23lo == SetExpr(Interval.Lopen(-4, 6)) assert n23cc - n23lo == SetExpr(Interval.Ropen(-5, 5)) assert n23cc*n23lo == SetExpr(Interval(-6, 9)) assert n23cc/n23lo == SetExpr(Interval.open(-oo, oo)) assert n23cc + n23o == SetExpr(Interval.open(-4, 6)) assert n23cc - n23o == SetExpr(Interval.open(-5, 5)) assert n23cc*n23o == SetExpr(Interval.open(-6, 9)) assert n23cc/n23o == SetExpr(Interval.open(-oo, oo)) assert n23cc**2 == SetExpr(Interval(0, 9)) assert n23cc**3 == SetExpr(Interval(-8, 27)) n32cc = SetExpr(Interval(-3, 2)) n32lo = SetExpr(Interval.Lopen(-3, 2)) n32ro = SetExpr(Interval.Ropen(-3, 2)) assert n32cc*n32lo == SetExpr(Interval.Ropen(-6, 9)) assert n32cc*n32cc == SetExpr(Interval(-6, 9)) assert n32lo*n32cc == SetExpr(Interval.Ropen(-6, 9)) assert n32cc*n32ro == SetExpr(Interval(-6, 9)) assert n32lo*n32ro == SetExpr(Interval.Ropen(-6, 9)) assert n32cc/n32lo == SetExpr(Interval.Ropen(-oo, oo)) assert i12cc/n32lo == SetExpr(Interval.Ropen(-oo, oo)) assert n3n2cc**2 == SetExpr(Interval(4, 9)) assert n3n2cc**3 == SetExpr(Interval(-27, -8)) assert n23cc + i12cc == SetExpr(Interval(-1, 5)) assert n23cc - i12cc == SetExpr(Interval(-4, 2)) assert n23cc*i12cc == SetExpr(Interval(-4, 6)) assert n23cc/i12cc == SetExpr(Interval(-2, 3)) def test_SetExpr_Intersection(): x, y, z, w = symbols("x y z w") set1 = Interval(x, y) set2 = Interval(w, z) inter = Intersection(set1, set2) se = SetExpr(inter) assert exp(se).set == Intersection( ImageSet(Lambda(x, exp(x)), set1), ImageSet(Lambda(x, exp(x)), set2)) assert cos(se).set == ImageSet(Lambda(x, cos(x)), inter) def test_SetExpr_Interval_div(): # TODO: some expressions cannot be calculated due to bugs (currently # commented): assert SetExpr(Interval(-3, -2))/SetExpr(Interval(-2, 1)) == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(2, 3))/SetExpr(Interval(-2, 2)) == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(-3, -2))/SetExpr(Interval(0, 4)) == SetExpr(Interval(-oo, Rational(-1, 2))) assert SetExpr(Interval(2, 4))/SetExpr(Interval(-3, 0)) == SetExpr(Interval(-oo, Rational(-2, 3))) assert SetExpr(Interval(2, 4))/SetExpr(Interval(0, 3)) == SetExpr(Interval(Rational(2, 3), oo)) # assert SetExpr(Interval(0, 1))/SetExpr(Interval(0, 1)) == SetExpr(Interval(0, oo)) # assert SetExpr(Interval(-1, 0))/SetExpr(Interval(0, 1)) == SetExpr(Interval(-oo, 0)) assert SetExpr(Interval(-1, 2))/SetExpr(Interval(-2, 2)) == SetExpr(Interval(-oo, oo)) assert 1/SetExpr(Interval(-1, 2)) == SetExpr(Union(Interval(-oo, -1), Interval(S.Half, oo))) assert 1/SetExpr(Interval(0, 2)) == SetExpr(Interval(S.Half, oo)) assert (-1)/SetExpr(Interval(0, 2)) == SetExpr(Interval(-oo, Rational(-1, 2))) # assert 1/SetExpr(Interval(-oo, 0)) == SetExpr(Interval.open(-oo, 0)) assert 1/SetExpr(Interval(-1, 0)) == SetExpr(Interval(-oo, -1)) # assert (-2)/SetExpr(Interval(-oo, 0)) == SetExpr(Interval(0, oo)) # assert 1/SetExpr(Interval(-oo, -1)) == SetExpr(Interval(-1, 0)) # assert SetExpr(Interval(1, 2))/a == Mul(SetExpr(Interval(1, 2)), 1/a, evaluate=False) # assert SetExpr(Interval(1, 2))/0 == SetExpr(Interval(1, 2))*zoo # assert SetExpr(Interval(1, oo))/oo == SetExpr(Interval(0, oo)) # assert SetExpr(Interval(1, oo))/(-oo) == SetExpr(Interval(-oo, 0)) # assert SetExpr(Interval(-oo, -1))/oo == SetExpr(Interval(-oo, 0)) # assert SetExpr(Interval(-oo, -1))/(-oo) == SetExpr(Interval(0, oo)) # assert SetExpr(Interval(-oo, oo))/oo == SetExpr(Interval(-oo, oo)) # assert SetExpr(Interval(-oo, oo))/(-oo) == SetExpr(Interval(-oo, oo)) # assert SetExpr(Interval(-1, oo))/oo == SetExpr(Interval(0, oo)) # assert SetExpr(Interval(-1, oo))/(-oo) == SetExpr(Interval(-oo, 0)) # assert SetExpr(Interval(-oo, 1))/oo == SetExpr(Interval(-oo, 0)) # assert SetExpr(Interval(-oo, 1))/(-oo) == SetExpr(Interval(0, oo)) def test_SetExpr_Interval_pow(): assert SetExpr(Interval(0, 2))**2 == SetExpr(Interval(0, 4)) assert SetExpr(Interval(-1, 1))**2 == SetExpr(Interval(0, 1)) assert SetExpr(Interval(1, 2))**2 == SetExpr(Interval(1, 4)) assert SetExpr(Interval(-1, 2))**3 == SetExpr(Interval(-1, 8)) assert SetExpr(Interval(-1, 1))**0 == SetExpr(FiniteSet(1)) #assert SetExpr(Interval(1, 2))**Rational(5, 2) == SetExpr(Interval(1, 4*sqrt(2))) #assert SetExpr(Interval(-1, 2))**Rational(1, 3) == SetExpr(Interval(-1, 2**Rational(1, 3))) #assert SetExpr(Interval(0, 2))**S.Half == SetExpr(Interval(0, sqrt(2))) #assert SetExpr(Interval(-4, 2))**Rational(2, 3) == SetExpr(Interval(0, 2*2**Rational(1, 3))) #assert SetExpr(Interval(-1, 5))**S.Half == SetExpr(Interval(0, sqrt(5))) #assert SetExpr(Interval(-oo, 2))**S.Half == SetExpr(Interval(0, sqrt(2))) #assert SetExpr(Interval(-2, 3))**(Rational(-1, 4)) == SetExpr(Interval(0, oo)) assert SetExpr(Interval(1, 5))**(-2) == SetExpr(Interval(Rational(1, 25), 1)) assert SetExpr(Interval(-1, 3))**(-2) == SetExpr(Interval(0, oo)) assert SetExpr(Interval(0, 2))**(-2) == SetExpr(Interval(Rational(1, 4), oo)) assert SetExpr(Interval(-1, 2))**(-3) == SetExpr(Union(Interval(-oo, -1), Interval(Rational(1, 8), oo))) assert SetExpr(Interval(-3, -2))**(-3) == SetExpr(Interval(Rational(-1, 8), Rational(-1, 27))) assert SetExpr(Interval(-3, -2))**(-2) == SetExpr(Interval(Rational(1, 9), Rational(1, 4))) #assert SetExpr(Interval(0, oo))**S.Half == SetExpr(Interval(0, oo)) #assert SetExpr(Interval(-oo, -1))**Rational(1, 3) == SetExpr(Interval(-oo, -1)) #assert SetExpr(Interval(-2, 3))**(Rational(-1, 3)) == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(-oo, 0))**(-2) == SetExpr(Interval.open(0, oo)) assert SetExpr(Interval(-2, 0))**(-2) == SetExpr(Interval(Rational(1, 4), oo)) assert SetExpr(Interval(Rational(1, 3), S.Half))**oo == SetExpr(FiniteSet(0)) assert SetExpr(Interval(0, S.Half))**oo == SetExpr(FiniteSet(0)) assert SetExpr(Interval(S.Half, 1))**oo == SetExpr(Interval(0, oo)) assert SetExpr(Interval(0, 1))**oo == SetExpr(Interval(0, oo)) assert SetExpr(Interval(2, 3))**oo == SetExpr(FiniteSet(oo)) assert SetExpr(Interval(1, 2))**oo == SetExpr(Interval(0, oo)) assert SetExpr(Interval(S.Half, 3))**oo == SetExpr(Interval(0, oo)) assert SetExpr(Interval(Rational(-1, 3), Rational(-1, 4)))**oo == SetExpr(FiniteSet(0)) assert SetExpr(Interval(-1, Rational(-1, 2)))**oo == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(-3, -2))**oo == SetExpr(FiniteSet(-oo, oo)) assert SetExpr(Interval(-2, -1))**oo == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(-2, Rational(-1, 2)))**oo == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(Rational(-1, 2), S.Half))**oo == SetExpr(FiniteSet(0)) assert SetExpr(Interval(Rational(-1, 2), 1))**oo == SetExpr(Interval(0, oo)) assert SetExpr(Interval(Rational(-2, 3), 2))**oo == SetExpr(Interval(0, oo)) assert SetExpr(Interval(-1, 1))**oo == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(-1, S.Half))**oo == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(-1, 2))**oo == SetExpr(Interval(-oo, oo)) assert SetExpr(Interval(-2, S.Half))**oo == SetExpr(Interval(-oo, oo)) assert (SetExpr(Interval(1, 2))**x).dummy_eq(SetExpr(ImageSet(Lambda(_d, _d**x), Interval(1, 2)))) assert SetExpr(Interval(2, 3))**(-oo) == SetExpr(FiniteSet(0)) assert SetExpr(Interval(0, 2))**(-oo) == SetExpr(Interval(0, oo)) assert (SetExpr(Interval(-1, 2))**(-oo)).dummy_eq(SetExpr(ImageSet(Lambda(_d, _d**(-oo)), Interval(-1, 2)))) def test_SetExpr_Integers(): assert SetExpr(S.Integers) + 1 == SetExpr(S.Integers) assert (SetExpr(S.Integers) + I).dummy_eq( SetExpr(ImageSet(Lambda(_d, _d + I), S.Integers))) assert SetExpr(S.Integers)*(-1) == SetExpr(S.Integers) assert (SetExpr(S.Integers)*2).dummy_eq( SetExpr(ImageSet(Lambda(_d, 2*_d), S.Integers))) assert (SetExpr(S.Integers)*I).dummy_eq( SetExpr(ImageSet(Lambda(_d, I*_d), S.Integers))) # issue #18050: assert SetExpr(S.Integers)._eval_func(Lambda(x, I*x + 1)).dummy_eq( SetExpr(ImageSet(Lambda(_d, I*_d + 1), S.Integers))) # needs improvement: assert (SetExpr(S.Integers)*I + 1).dummy_eq( SetExpr(ImageSet(Lambda(x, x + 1), ImageSet(Lambda(_d, _d*I), S.Integers)))) sympy-sympy-1.9/sympy/sets/tests/test_sets.py000066400000000000000000001733641412543434000216310ustar00rootroot00000000000000from sympy import (Symbol, Set, Union, Interval, oo, S, sympify, nan, Max, Min, Float, DisjointUnion, FiniteSet, Intersection, imageset, I, true, false, ProductSet, sqrt, Complement, EmptySet, sin, cos, Lambda, ImageSet, pi, Pow, Contains, Sum, rootof, SymmetricDifference, Piecewise, Matrix, Range, Add, symbols, zoo, Rational) from mpmath import mpi from sympy.core.expr import unchanged from sympy.core.relational import Eq, Ne, Le, Lt, LessThan from sympy.logic import And, Or, Xor from sympy.testing.pytest import raises, XFAIL, warns_deprecated_sympy from sympy.abc import x, y, z, m, n def test_imageset(): ints = S.Integers assert imageset(x, x - 1, S.Naturals) is S.Naturals0 assert imageset(x, x + 1, S.Naturals0) is S.Naturals assert imageset(x, abs(x), S.Naturals0) is S.Naturals0 assert imageset(x, abs(x), S.Naturals) is S.Naturals assert imageset(x, abs(x), S.Integers) is S.Naturals0 # issue 16878a r = symbols('r', real=True) assert imageset(x, (x, x), S.Reals)._contains((1, r)) == None assert imageset(x, (x, x), S.Reals)._contains((1, 2)) == False assert (r, r) in imageset(x, (x, x), S.Reals) assert 1 + I in imageset(x, x + I, S.Reals) assert {1} not in imageset(x, (x,), S.Reals) assert (1, 1) not in imageset(x, (x,) , S.Reals) raises(TypeError, lambda: imageset(x, ints)) raises(ValueError, lambda: imageset(x, y, z, ints)) raises(ValueError, lambda: imageset(Lambda(x, cos(x)), y)) assert (1, 2) in imageset(Lambda((x, y), (x, y)), ints, ints) raises(ValueError, lambda: imageset(Lambda(x, x), ints, ints)) assert imageset(cos, ints) == ImageSet(Lambda(x, cos(x)), ints) def f(x): return cos(x) assert imageset(f, ints) == imageset(x, cos(x), ints) f = lambda x: cos(x) assert imageset(f, ints) == ImageSet(Lambda(x, cos(x)), ints) assert imageset(x, 1, ints) == FiniteSet(1) assert imageset(x, y, ints) == {y} assert imageset((x, y), (1, z), ints, S.Reals) == {(1, z)} clash = Symbol('x', integer=true) assert (str(imageset(lambda x: x + clash, Interval(-2, 1)).lamda.expr) in ('x0 + x', 'x + x0')) x1, x2 = symbols("x1, x2") assert imageset(lambda x, y: Add(x, y), Interval(1, 2), Interval(2, 3)).dummy_eq( ImageSet(Lambda((x1, x2), x1 + x2), Interval(1, 2), Interval(2, 3))) def test_is_empty(): for s in [S.Naturals, S.Naturals0, S.Integers, S.Rationals, S.Reals, S.UniversalSet]: assert s.is_empty is False assert S.EmptySet.is_empty is True def test_is_finiteset(): for s in [S.Naturals, S.Naturals0, S.Integers, S.Rationals, S.Reals, S.UniversalSet]: assert s.is_finite_set is False assert S.EmptySet.is_finite_set is True assert FiniteSet(1, 2).is_finite_set is True assert Interval(1, 2).is_finite_set is False assert Interval(x, y).is_finite_set is None assert ProductSet(FiniteSet(1), FiniteSet(2)).is_finite_set is True assert ProductSet(FiniteSet(1), Interval(1, 2)).is_finite_set is False assert ProductSet(FiniteSet(1), Interval(x, y)).is_finite_set is None assert Union(Interval(0, 1), Interval(2, 3)).is_finite_set is False assert Union(FiniteSet(1), Interval(2, 3)).is_finite_set is False assert Union(FiniteSet(1), FiniteSet(2)).is_finite_set is True assert Union(FiniteSet(1), Interval(x, y)).is_finite_set is None assert Intersection(Interval(x, y), FiniteSet(1)).is_finite_set is True assert Intersection(Interval(x, y), Interval(1, 2)).is_finite_set is None assert Intersection(FiniteSet(x), FiniteSet(y)).is_finite_set is True assert Complement(FiniteSet(1), Interval(x, y)).is_finite_set is True assert Complement(Interval(x, y), FiniteSet(1)).is_finite_set is None assert Complement(Interval(1, 2), FiniteSet(x)).is_finite_set is False assert DisjointUnion(Interval(-5, 3), FiniteSet(x, y)).is_finite_set is False assert DisjointUnion(S.EmptySet, FiniteSet(x, y), S.EmptySet).is_finite_set is True def test_deprecated_is_EmptySet(): with warns_deprecated_sympy(): S.EmptySet.is_EmptySet def test_interval_arguments(): assert Interval(0, oo) == Interval(0, oo, False, True) assert Interval(0, oo).right_open is true assert Interval(-oo, 0) == Interval(-oo, 0, True, False) assert Interval(-oo, 0).left_open is true assert Interval(oo, -oo) == S.EmptySet assert Interval(oo, oo) == S.EmptySet assert Interval(-oo, -oo) == S.EmptySet assert Interval(oo, x) == S.EmptySet assert Interval(oo, oo) == S.EmptySet assert Interval(x, -oo) == S.EmptySet assert Interval(x, x) == {x} assert isinstance(Interval(1, 1), FiniteSet) e = Sum(x, (x, 1, 3)) assert isinstance(Interval(e, e), FiniteSet) assert Interval(1, 0) == S.EmptySet assert Interval(1, 1).measure == 0 assert Interval(1, 1, False, True) == S.EmptySet assert Interval(1, 1, True, False) == S.EmptySet assert Interval(1, 1, True, True) == S.EmptySet assert isinstance(Interval(0, Symbol('a')), Interval) assert Interval(Symbol('a', real=True, positive=True), 0) == S.EmptySet raises(ValueError, lambda: Interval(0, S.ImaginaryUnit)) raises(ValueError, lambda: Interval(0, Symbol('z', extended_real=False))) raises(ValueError, lambda: Interval(x, x + S.ImaginaryUnit)) raises(NotImplementedError, lambda: Interval(0, 1, And(x, y))) raises(NotImplementedError, lambda: Interval(0, 1, False, And(x, y))) raises(NotImplementedError, lambda: Interval(0, 1, z, And(x, y))) def test_interval_symbolic_end_points(): a = Symbol('a', real=True) assert Union(Interval(0, a), Interval(0, 3)).sup == Max(a, 3) assert Union(Interval(a, 0), Interval(-3, 0)).inf == Min(-3, a) assert Interval(0, a).contains(1) == LessThan(1, a) def test_interval_is_empty(): x, y = symbols('x, y') r = Symbol('r', real=True) p = Symbol('p', positive=True) n = Symbol('n', negative=True) nn = Symbol('nn', nonnegative=True) assert Interval(1, 2).is_empty == False assert Interval(3, 3).is_empty == False # FiniteSet assert Interval(r, r).is_empty == False # FiniteSet assert Interval(r, r + nn).is_empty == False assert Interval(x, x).is_empty == False assert Interval(1, oo).is_empty == False assert Interval(-oo, oo).is_empty == False assert Interval(-oo, 1).is_empty == False assert Interval(x, y).is_empty == None assert Interval(r, oo).is_empty == False # real implies finite assert Interval(n, 0).is_empty == False assert Interval(n, 0, left_open=True).is_empty == False assert Interval(p, 0).is_empty == True # EmptySet assert Interval(nn, 0).is_empty == None assert Interval(n, p).is_empty == False assert Interval(0, p, left_open=True).is_empty == False assert Interval(0, p, right_open=True).is_empty == False assert Interval(0, nn, left_open=True).is_empty == None assert Interval(0, nn, right_open=True).is_empty == None def test_union(): assert Union(Interval(1, 2), Interval(2, 3)) == Interval(1, 3) assert Union(Interval(1, 2), Interval(2, 3, True)) == Interval(1, 3) assert Union(Interval(1, 3), Interval(2, 4)) == Interval(1, 4) assert Union(Interval(1, 2), Interval(1, 3)) == Interval(1, 3) assert Union(Interval(1, 3), Interval(1, 2)) == Interval(1, 3) assert Union(Interval(1, 3, False, True), Interval(1, 2)) == \ Interval(1, 3, False, True) assert Union(Interval(1, 3), Interval(1, 2, False, True)) == Interval(1, 3) assert Union(Interval(1, 2, True), Interval(1, 3)) == Interval(1, 3) assert Union(Interval(1, 2, True), Interval(1, 3, True)) == \ Interval(1, 3, True) assert Union(Interval(1, 2, True), Interval(1, 3, True, True)) == \ Interval(1, 3, True, True) assert Union(Interval(1, 2, True, True), Interval(1, 3, True)) == \ Interval(1, 3, True) assert Union(Interval(1, 3), Interval(2, 3)) == Interval(1, 3) assert Union(Interval(1, 3, False, True), Interval(2, 3)) == \ Interval(1, 3) assert Union(Interval(1, 2, False, True), Interval(2, 3, True)) != \ Interval(1, 3) assert Union(Interval(1, 2), S.EmptySet) == Interval(1, 2) assert Union(S.EmptySet) == S.EmptySet assert Union(Interval(0, 1), *[FiniteSet(1.0/n) for n in range(1, 10)]) == \ Interval(0, 1) # issue #18241: x = Symbol('x') assert Union(Interval(0, 1), FiniteSet(1, x)) == Union( Interval(0, 1), FiniteSet(x)) assert unchanged(Union, Interval(0, 1), FiniteSet(2, x)) assert Interval(1, 2).union(Interval(2, 3)) == \ Interval(1, 2) + Interval(2, 3) assert Interval(1, 2).union(Interval(2, 3)) == Interval(1, 3) assert Union(Set()) == Set() assert FiniteSet(1) + FiniteSet(2) + FiniteSet(3) == FiniteSet(1, 2, 3) assert FiniteSet('ham') + FiniteSet('eggs') == FiniteSet('ham', 'eggs') assert FiniteSet(1, 2, 3) + S.EmptySet == FiniteSet(1, 2, 3) assert FiniteSet(1, 2, 3) & FiniteSet(2, 3, 4) == FiniteSet(2, 3) assert FiniteSet(1, 2, 3) | FiniteSet(2, 3, 4) == FiniteSet(1, 2, 3, 4) assert FiniteSet(1, 2, 3) & S.EmptySet == S.EmptySet assert FiniteSet(1, 2, 3) | S.EmptySet == FiniteSet(1, 2, 3) x = Symbol("x") y = Symbol("y") z = Symbol("z") assert S.EmptySet | FiniteSet(x, FiniteSet(y, z)) == \ FiniteSet(x, FiniteSet(y, z)) # Test that Intervals and FiniteSets play nicely assert Interval(1, 3) + FiniteSet(2) == Interval(1, 3) assert Interval(1, 3, True, True) + FiniteSet(3) == \ Interval(1, 3, True, False) X = Interval(1, 3) + FiniteSet(5) Y = Interval(1, 2) + FiniteSet(3) XandY = X.intersect(Y) assert 2 in X and 3 in X and 3 in XandY assert XandY.is_subset(X) and XandY.is_subset(Y) raises(TypeError, lambda: Union(1, 2, 3)) assert X.is_iterable is False # issue 7843 assert Union(S.EmptySet, FiniteSet(-sqrt(-I), sqrt(-I))) == \ FiniteSet(-sqrt(-I), sqrt(-I)) assert Union(S.Reals, S.Integers) == S.Reals def test_union_iter(): # Use Range because it is ordered u = Union(Range(3), Range(5), Range(4), evaluate=False) # Round robin assert list(u) == [0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 4] def test_union_is_empty(): assert (Interval(x, y) + FiniteSet(1)).is_empty == False assert (Interval(x, y) + Interval(-x, y)).is_empty == None def test_difference(): assert Interval(1, 3) - Interval(1, 2) == Interval(2, 3, True) assert Interval(1, 3) - Interval(2, 3) == Interval(1, 2, False, True) assert Interval(1, 3, True) - Interval(2, 3) == Interval(1, 2, True, True) assert Interval(1, 3, True) - Interval(2, 3, True) == \ Interval(1, 2, True, False) assert Interval(0, 2) - FiniteSet(1) == \ Union(Interval(0, 1, False, True), Interval(1, 2, True, False)) # issue #18119 assert S.Reals - FiniteSet(I) == S.Reals assert S.Reals - FiniteSet(-I, I) == S.Reals assert Interval(0, 10) - FiniteSet(-I, I) == Interval(0, 10) assert Interval(0, 10) - FiniteSet(1, I) == Union( Interval.Ropen(0, 1), Interval.Lopen(1, 10)) assert S.Reals - FiniteSet(1, 2 + I, x, y**2) == Complement( Union(Interval.open(-oo, 1), Interval.open(1, oo)), FiniteSet(x, y**2), evaluate=False) assert FiniteSet(1, 2, 3) - FiniteSet(2) == FiniteSet(1, 3) assert FiniteSet('ham', 'eggs') - FiniteSet('eggs') == FiniteSet('ham') assert FiniteSet(1, 2, 3, 4) - Interval(2, 10, True, False) == \ FiniteSet(1, 2) assert FiniteSet(1, 2, 3, 4) - S.EmptySet == FiniteSet(1, 2, 3, 4) assert Union(Interval(0, 2), FiniteSet(2, 3, 4)) - Interval(1, 3) == \ Union(Interval(0, 1, False, True), FiniteSet(4)) assert -1 in S.Reals - S.Naturals def test_Complement(): A = FiniteSet(1, 3, 4) B = FiniteSet(3, 4) C = Interval(1, 3) D = Interval(1, 2) assert Complement(A, B, evaluate=False).is_iterable is True assert Complement(A, C, evaluate=False).is_iterable is True assert Complement(C, D, evaluate=False).is_iterable is None assert FiniteSet(*Complement(A, B, evaluate=False)) == FiniteSet(1) assert FiniteSet(*Complement(A, C, evaluate=False)) == FiniteSet(4) raises(TypeError, lambda: FiniteSet(*Complement(C, A, evaluate=False))) assert Complement(Interval(1, 3), Interval(1, 2)) == Interval(2, 3, True) assert Complement(FiniteSet(1, 3, 4), FiniteSet(3, 4)) == FiniteSet(1) assert Complement(Union(Interval(0, 2), FiniteSet(2, 3, 4)), Interval(1, 3)) == \ Union(Interval(0, 1, False, True), FiniteSet(4)) assert not 3 in Complement(Interval(0, 5), Interval(1, 4), evaluate=False) assert -1 in Complement(S.Reals, S.Naturals, evaluate=False) assert not 1 in Complement(S.Reals, S.Naturals, evaluate=False) assert Complement(S.Integers, S.UniversalSet) == EmptySet assert S.UniversalSet.complement(S.Integers) == EmptySet assert (not 0 in S.Reals.intersect(S.Integers - FiniteSet(0))) assert S.EmptySet - S.Integers == S.EmptySet assert (S.Integers - FiniteSet(0)) - FiniteSet(1) == S.Integers - FiniteSet(0, 1) assert S.Reals - Union(S.Naturals, FiniteSet(pi)) == \ Intersection(S.Reals - S.Naturals, S.Reals - FiniteSet(pi)) # issue 12712 assert Complement(FiniteSet(x, y, 2), Interval(-10, 10)) == \ Complement(FiniteSet(x, y), Interval(-10, 10)) A = FiniteSet(*symbols('a:c')) B = FiniteSet(*symbols('d:f')) assert unchanged(Complement, ProductSet(A, A), B) A2 = ProductSet(A, A) B3 = ProductSet(B, B, B) assert A2 - B3 == A2 assert B3 - A2 == B3 def test_set_operations_nonsets(): '''Tests that e.g. FiniteSet(1) * 2 raises TypeError''' ops = [ lambda a, b: a + b, lambda a, b: a - b, lambda a, b: a * b, lambda a, b: a / b, lambda a, b: a // b, lambda a, b: a | b, lambda a, b: a & b, lambda a, b: a ^ b, # FiniteSet(1) ** 2 gives a ProductSet #lambda a, b: a ** b, ] Sx = FiniteSet(x) Sy = FiniteSet(y) sets = [ {1}, FiniteSet(1), Interval(1, 2), Union(Sx, Interval(1, 2)), Intersection(Sx, Sy), Complement(Sx, Sy), ProductSet(Sx, Sy), S.EmptySet, ] nums = [0, 1, 2, S(0), S(1), S(2)] for si in sets: for ni in nums: for op in ops: raises(TypeError, lambda : op(si, ni)) raises(TypeError, lambda : op(ni, si)) raises(TypeError, lambda: si ** object()) raises(TypeError, lambda: si ** {1}) def test_complement(): assert Interval(0, 1).complement(S.Reals) == \ Union(Interval(-oo, 0, True, True), Interval(1, oo, True, True)) assert Interval(0, 1, True, False).complement(S.Reals) == \ Union(Interval(-oo, 0, True, False), Interval(1, oo, True, True)) assert Interval(0, 1, False, True).complement(S.Reals) == \ Union(Interval(-oo, 0, True, True), Interval(1, oo, False, True)) assert Interval(0, 1, True, True).complement(S.Reals) == \ Union(Interval(-oo, 0, True, False), Interval(1, oo, False, True)) assert S.UniversalSet.complement(S.EmptySet) == S.EmptySet assert S.UniversalSet.complement(S.Reals) == S.EmptySet assert S.UniversalSet.complement(S.UniversalSet) == S.EmptySet assert S.EmptySet.complement(S.Reals) == S.Reals assert Union(Interval(0, 1), Interval(2, 3)).complement(S.Reals) == \ Union(Interval(-oo, 0, True, True), Interval(1, 2, True, True), Interval(3, oo, True, True)) assert FiniteSet(0).complement(S.Reals) == \ Union(Interval(-oo, 0, True, True), Interval(0, oo, True, True)) assert (FiniteSet(5) + Interval(S.NegativeInfinity, 0)).complement(S.Reals) == \ Interval(0, 5, True, True) + Interval(5, S.Infinity, True, True) assert FiniteSet(1, 2, 3).complement(S.Reals) == \ Interval(S.NegativeInfinity, 1, True, True) + \ Interval(1, 2, True, True) + Interval(2, 3, True, True) +\ Interval(3, S.Infinity, True, True) assert FiniteSet(x).complement(S.Reals) == Complement(S.Reals, FiniteSet(x)) assert FiniteSet(0, x).complement(S.Reals) == Complement(Interval(-oo, 0, True, True) + Interval(0, oo, True, True) , FiniteSet(x), evaluate=False) square = Interval(0, 1) * Interval(0, 1) notsquare = square.complement(S.Reals*S.Reals) assert all(pt in square for pt in [(0, 0), (.5, .5), (1, 0), (1, 1)]) assert not any( pt in notsquare for pt in [(0, 0), (.5, .5), (1, 0), (1, 1)]) assert not any(pt in square for pt in [(-1, 0), (1.5, .5), (10, 10)]) assert all(pt in notsquare for pt in [(-1, 0), (1.5, .5), (10, 10)]) def test_intersect1(): assert all(S.Integers.intersection(i) is i for i in (S.Naturals, S.Naturals0)) assert all(i.intersection(S.Integers) is i for i in (S.Naturals, S.Naturals0)) s = S.Naturals0 assert S.Naturals.intersection(s) is S.Naturals assert s.intersection(S.Naturals) is S.Naturals x = Symbol('x') assert Interval(0, 2).intersect(Interval(1, 2)) == Interval(1, 2) assert Interval(0, 2).intersect(Interval(1, 2, True)) == \ Interval(1, 2, True) assert Interval(0, 2, True).intersect(Interval(1, 2)) == \ Interval(1, 2, False, False) assert Interval(0, 2, True, True).intersect(Interval(1, 2)) == \ Interval(1, 2, False, True) assert Interval(0, 2).intersect(Union(Interval(0, 1), Interval(2, 3))) == \ Union(Interval(0, 1), Interval(2, 2)) assert FiniteSet(1, 2).intersect(FiniteSet(1, 2, 3)) == FiniteSet(1, 2) assert FiniteSet(1, 2, x).intersect(FiniteSet(x)) == FiniteSet(x) assert FiniteSet('ham', 'eggs').intersect(FiniteSet('ham')) == \ FiniteSet('ham') assert FiniteSet(1, 2, 3, 4, 5).intersect(S.EmptySet) == S.EmptySet assert Interval(0, 5).intersect(FiniteSet(1, 3)) == FiniteSet(1, 3) assert Interval(0, 1, True, True).intersect(FiniteSet(1)) == S.EmptySet assert Union(Interval(0, 1), Interval(2, 3)).intersect(Interval(1, 2)) == \ Union(Interval(1, 1), Interval(2, 2)) assert Union(Interval(0, 1), Interval(2, 3)).intersect(Interval(0, 2)) == \ Union(Interval(0, 1), Interval(2, 2)) assert Union(Interval(0, 1), Interval(2, 3)).intersect(Interval(1, 2, True, True)) == \ S.EmptySet assert Union(Interval(0, 1), Interval(2, 3)).intersect(S.EmptySet) == \ S.EmptySet assert Union(Interval(0, 5), FiniteSet('ham')).intersect(FiniteSet(2, 3, 4, 5, 6)) == \ Intersection(FiniteSet(2, 3, 4, 5, 6), Union(FiniteSet('ham'), Interval(0, 5))) assert Intersection(FiniteSet(1, 2, 3), Interval(2, x), Interval(3, y)) == \ Intersection(FiniteSet(3), Interval(2, x), Interval(3, y), evaluate=False) assert Intersection(FiniteSet(1, 2), Interval(0, 3), Interval(x, y)) == \ Intersection({1, 2}, Interval(x, y), evaluate=False) assert Intersection(FiniteSet(1, 2, 4), Interval(0, 3), Interval(x, y)) == \ Intersection({1, 2}, Interval(x, y), evaluate=False) # XXX: Is the real=True necessary here? # https://github.com/sympy/sympy/issues/17532 m, n = symbols('m, n', real=True) assert Intersection(FiniteSet(m), FiniteSet(m, n), Interval(m, m+1)) == \ FiniteSet(m) # issue 8217 assert Intersection(FiniteSet(x), FiniteSet(y)) == \ Intersection(FiniteSet(x), FiniteSet(y), evaluate=False) assert FiniteSet(x).intersect(S.Reals) == \ Intersection(S.Reals, FiniteSet(x), evaluate=False) # tests for the intersection alias assert Interval(0, 5).intersection(FiniteSet(1, 3)) == FiniteSet(1, 3) assert Interval(0, 1, True, True).intersection(FiniteSet(1)) == S.EmptySet assert Union(Interval(0, 1), Interval(2, 3)).intersection(Interval(1, 2)) == \ Union(Interval(1, 1), Interval(2, 2)) def test_intersection(): # iterable i = Intersection(FiniteSet(1, 2, 3), Interval(2, 5), evaluate=False) assert i.is_iterable assert set(i) == {S(2), S(3)} # challenging intervals x = Symbol('x', real=True) i = Intersection(Interval(0, 3), Interval(x, 6)) assert (5 in i) is False raises(TypeError, lambda: 2 in i) # Singleton special cases assert Intersection(Interval(0, 1), S.EmptySet) == S.EmptySet assert Intersection(Interval(-oo, oo), Interval(-oo, x)) == Interval(-oo, x) # Products line = Interval(0, 5) i = Intersection(line**2, line**3, evaluate=False) assert (2, 2) not in i assert (2, 2, 2) not in i raises(TypeError, lambda: list(i)) a = Intersection(Intersection(S.Integers, S.Naturals, evaluate=False), S.Reals, evaluate=False) assert a._argset == frozenset([Intersection(S.Naturals, S.Integers, evaluate=False), S.Reals]) assert Intersection(S.Complexes, FiniteSet(S.ComplexInfinity)) == S.EmptySet # issue 12178 assert Intersection() == S.UniversalSet # issue 16987 assert Intersection({1}, {1}, {x}) == Intersection({1}, {x}) def test_issue_9623(): n = Symbol('n') a = S.Reals b = Interval(0, oo) c = FiniteSet(n) assert Intersection(a, b, c) == Intersection(b, c) assert Intersection(Interval(1, 2), Interval(3, 4), FiniteSet(n)) == EmptySet def test_is_disjoint(): assert Interval(0, 2).is_disjoint(Interval(1, 2)) == False assert Interval(0, 2).is_disjoint(Interval(3, 4)) == True def test_ProductSet__len__(): A = FiniteSet(1, 2) B = FiniteSet(1, 2, 3) assert ProductSet(A).__len__() == 2 assert ProductSet(A).__len__() is not S(2) assert ProductSet(A, B).__len__() == 6 assert ProductSet(A, B).__len__() is not S(6) def test_ProductSet(): # ProductSet is always a set of Tuples assert ProductSet(S.Reals) == S.Reals ** 1 assert ProductSet(S.Reals, S.Reals) == S.Reals ** 2 assert ProductSet(S.Reals, S.Reals, S.Reals) == S.Reals ** 3 assert ProductSet(S.Reals) != S.Reals assert ProductSet(S.Reals, S.Reals) == S.Reals * S.Reals assert ProductSet(S.Reals, S.Reals, S.Reals) != S.Reals * S.Reals * S.Reals assert ProductSet(S.Reals, S.Reals, S.Reals) == (S.Reals * S.Reals * S.Reals).flatten() assert 1 not in ProductSet(S.Reals) assert (1,) in ProductSet(S.Reals) assert 1 not in ProductSet(S.Reals, S.Reals) assert (1, 2) in ProductSet(S.Reals, S.Reals) assert (1, I) not in ProductSet(S.Reals, S.Reals) assert (1, 2, 3) in ProductSet(S.Reals, S.Reals, S.Reals) assert (1, 2, 3) in S.Reals ** 3 assert (1, 2, 3) not in S.Reals * S.Reals * S.Reals assert ((1, 2), 3) in S.Reals * S.Reals * S.Reals assert (1, (2, 3)) not in S.Reals * S.Reals * S.Reals assert (1, (2, 3)) in S.Reals * (S.Reals * S.Reals) assert ProductSet() == FiniteSet(()) assert ProductSet(S.Reals, S.EmptySet) == S.EmptySet # See GH-17458 for ni in range(5): Rn = ProductSet(*(S.Reals,) * ni) assert (1,) * ni in Rn assert 1 not in Rn assert (S.Reals * S.Reals) * S.Reals != S.Reals * (S.Reals * S.Reals) S1 = S.Reals S2 = S.Integers x1 = pi x2 = 3 assert x1 in S1 assert x2 in S2 assert (x1, x2) in S1 * S2 S3 = S1 * S2 x3 = (x1, x2) assert x3 in S3 assert (x3, x3) in S3 * S3 assert x3 + x3 not in S3 * S3 raises(ValueError, lambda: S.Reals**-1) with warns_deprecated_sympy(): ProductSet(FiniteSet(s) for s in range(2)) raises(TypeError, lambda: ProductSet(None)) S1 = FiniteSet(1, 2) S2 = FiniteSet(3, 4) S3 = ProductSet(S1, S2) assert (S3.as_relational(x, y) == And(S1.as_relational(x), S2.as_relational(y)) == And(Or(Eq(x, 1), Eq(x, 2)), Or(Eq(y, 3), Eq(y, 4)))) raises(ValueError, lambda: S3.as_relational(x)) raises(ValueError, lambda: S3.as_relational(x, 1)) raises(ValueError, lambda: ProductSet(Interval(0, 1)).as_relational(x, y)) Z2 = ProductSet(S.Integers, S.Integers) assert Z2.contains((1, 2)) is S.true assert Z2.contains((1,)) is S.false assert Z2.contains(x) == Contains(x, Z2, evaluate=False) assert Z2.contains(x).subs(x, 1) is S.false assert Z2.contains((x, 1)).subs(x, 2) is S.true assert Z2.contains((x, y)) == Contains((x, y), Z2, evaluate=False) assert unchanged(Contains, (x, y), Z2) assert Contains((1, 2), Z2) is S.true def test_ProductSet_of_single_arg_is_not_arg(): assert unchanged(ProductSet, Interval(0, 1)) assert unchanged(ProductSet, ProductSet(Interval(0, 1))) def test_ProductSet_is_empty(): assert ProductSet(S.Integers, S.Reals).is_empty == False assert ProductSet(Interval(x, 1), S.Reals).is_empty == None def test_interval_subs(): a = Symbol('a', real=True) assert Interval(0, a).subs(a, 2) == Interval(0, 2) assert Interval(a, 0).subs(a, 2) == S.EmptySet def test_interval_to_mpi(): assert Interval(0, 1).to_mpi() == mpi(0, 1) assert Interval(0, 1, True, False).to_mpi() == mpi(0, 1) assert type(Interval(0, 1).to_mpi()) == type(mpi(0, 1)) def test_set_evalf(): assert Interval(S(11)/64, S.Half).evalf() == Interval( Float('0.171875'), Float('0.5')) assert Interval(x, S.Half, right_open=True).evalf() == Interval( x, Float('0.5'), right_open=True) assert Interval(-oo, S.Half).evalf() == Interval(-oo, Float('0.5')) assert FiniteSet(2, x).evalf() == FiniteSet(Float('2.0'), x) def test_measure(): a = Symbol('a', real=True) assert Interval(1, 3).measure == 2 assert Interval(0, a).measure == a assert Interval(1, a).measure == a - 1 assert Union(Interval(1, 2), Interval(3, 4)).measure == 2 assert Union(Interval(1, 2), Interval(3, 4), FiniteSet(5, 6, 7)).measure \ == 2 assert FiniteSet(1, 2, oo, a, -oo, -5).measure == 0 assert S.EmptySet.measure == 0 square = Interval(0, 10) * Interval(0, 10) offsetsquare = Interval(5, 15) * Interval(5, 15) band = Interval(-oo, oo) * Interval(2, 4) assert square.measure == offsetsquare.measure == 100 assert (square + offsetsquare).measure == 175 # there is some overlap assert (square - offsetsquare).measure == 75 assert (square * FiniteSet(1, 2, 3)).measure == 0 assert (square.intersect(band)).measure == 20 assert (square + band).measure is oo assert (band * FiniteSet(1, 2, 3)).measure is nan def test_is_subset(): assert Interval(0, 1).is_subset(Interval(0, 2)) is True assert Interval(0, 3).is_subset(Interval(0, 2)) is False assert Interval(0, 1).is_subset(FiniteSet(0, 1)) is False assert FiniteSet(1, 2).is_subset(FiniteSet(1, 2, 3, 4)) assert FiniteSet(4, 5).is_subset(FiniteSet(1, 2, 3, 4)) is False assert FiniteSet(1).is_subset(Interval(0, 2)) assert FiniteSet(1, 2).is_subset(Interval(0, 2, True, True)) is False assert (Interval(1, 2) + FiniteSet(3)).is_subset( Interval(0, 2, False, True) + FiniteSet(2, 3)) assert Interval(3, 4).is_subset(Union(Interval(0, 1), Interval(2, 5))) is True assert Interval(3, 6).is_subset(Union(Interval(0, 1), Interval(2, 5))) is False assert FiniteSet(1, 2, 3, 4).is_subset(Interval(0, 5)) is True assert S.EmptySet.is_subset(FiniteSet(1, 2, 3)) is True assert Interval(0, 1).is_subset(S.EmptySet) is False assert S.EmptySet.is_subset(S.EmptySet) is True raises(ValueError, lambda: S.EmptySet.is_subset(1)) # tests for the issubset alias assert FiniteSet(1, 2, 3, 4).issubset(Interval(0, 5)) is True assert S.EmptySet.issubset(FiniteSet(1, 2, 3)) is True assert S.Naturals.is_subset(S.Integers) assert S.Naturals0.is_subset(S.Integers) assert FiniteSet(x).is_subset(FiniteSet(y)) is None assert FiniteSet(x).is_subset(FiniteSet(y).subs(y, x)) is True assert FiniteSet(x).is_subset(FiniteSet(y).subs(y, x+1)) is False assert Interval(0, 1).is_subset(Interval(0, 1, left_open=True)) is False assert Interval(-2, 3).is_subset(Union(Interval(-oo, -2), Interval(3, oo))) is False n = Symbol('n', integer=True) assert Range(-3, 4, 1).is_subset(FiniteSet(-10, 10)) is False assert Range(S(10)**100).is_subset(FiniteSet(0, 1, 2)) is False assert Range(6, 0, -2).is_subset(FiniteSet(2, 4, 6)) is True assert Range(1, oo).is_subset(FiniteSet(1, 2)) is False assert Range(-oo, 1).is_subset(FiniteSet(1)) is False assert Range(3).is_subset(FiniteSet(0, 1, n)) is None assert Range(n, n + 2).is_subset(FiniteSet(n, n + 1)) is True assert Range(5).is_subset(Interval(0, 4, right_open=True)) is False #issue 19513 assert imageset(Lambda(n, 1/n), S.Integers).is_subset(S.Reals) is None def test_is_proper_subset(): assert Interval(0, 1).is_proper_subset(Interval(0, 2)) is True assert Interval(0, 3).is_proper_subset(Interval(0, 2)) is False assert S.EmptySet.is_proper_subset(FiniteSet(1, 2, 3)) is True raises(ValueError, lambda: Interval(0, 1).is_proper_subset(0)) def test_is_superset(): assert Interval(0, 1).is_superset(Interval(0, 2)) == False assert Interval(0, 3).is_superset(Interval(0, 2)) assert FiniteSet(1, 2).is_superset(FiniteSet(1, 2, 3, 4)) == False assert FiniteSet(4, 5).is_superset(FiniteSet(1, 2, 3, 4)) == False assert FiniteSet(1).is_superset(Interval(0, 2)) == False assert FiniteSet(1, 2).is_superset(Interval(0, 2, True, True)) == False assert (Interval(1, 2) + FiniteSet(3)).is_superset( Interval(0, 2, False, True) + FiniteSet(2, 3)) == False assert Interval(3, 4).is_superset(Union(Interval(0, 1), Interval(2, 5))) == False assert FiniteSet(1, 2, 3, 4).is_superset(Interval(0, 5)) == False assert S.EmptySet.is_superset(FiniteSet(1, 2, 3)) == False assert Interval(0, 1).is_superset(S.EmptySet) == True assert S.EmptySet.is_superset(S.EmptySet) == True raises(ValueError, lambda: S.EmptySet.is_superset(1)) # tests for the issuperset alias assert Interval(0, 1).issuperset(S.EmptySet) == True assert S.EmptySet.issuperset(S.EmptySet) == True def test_is_proper_superset(): assert Interval(0, 1).is_proper_superset(Interval(0, 2)) is False assert Interval(0, 3).is_proper_superset(Interval(0, 2)) is True assert FiniteSet(1, 2, 3).is_proper_superset(S.EmptySet) is True raises(ValueError, lambda: Interval(0, 1).is_proper_superset(0)) def test_contains(): assert Interval(0, 2).contains(1) is S.true assert Interval(0, 2).contains(3) is S.false assert Interval(0, 2, True, False).contains(0) is S.false assert Interval(0, 2, True, False).contains(2) is S.true assert Interval(0, 2, False, True).contains(0) is S.true assert Interval(0, 2, False, True).contains(2) is S.false assert Interval(0, 2, True, True).contains(0) is S.false assert Interval(0, 2, True, True).contains(2) is S.false assert (Interval(0, 2) in Interval(0, 2)) is False assert FiniteSet(1, 2, 3).contains(2) is S.true assert FiniteSet(1, 2, Symbol('x')).contains(Symbol('x')) is S.true assert FiniteSet(y)._contains(x) is None raises(TypeError, lambda: x in FiniteSet(y)) assert FiniteSet({x, y})._contains({x}) is None assert FiniteSet({x, y}).subs(y, x)._contains({x}) is True assert FiniteSet({x, y}).subs(y, x+1)._contains({x}) is False # issue 8197 from sympy.abc import a, b assert isinstance(FiniteSet(b).contains(-a), Contains) assert isinstance(FiniteSet(b).contains(a), Contains) assert isinstance(FiniteSet(a).contains(1), Contains) raises(TypeError, lambda: 1 in FiniteSet(a)) # issue 8209 rad1 = Pow(Pow(2, Rational(1, 3)) - 1, Rational(1, 3)) rad2 = Pow(Rational(1, 9), Rational(1, 3)) - Pow(Rational(2, 9), Rational(1, 3)) + Pow(Rational(4, 9), Rational(1, 3)) s1 = FiniteSet(rad1) s2 = FiniteSet(rad2) assert s1 - s2 == S.EmptySet items = [1, 2, S.Infinity, S('ham'), -1.1] fset = FiniteSet(*items) assert all(item in fset for item in items) assert all(fset.contains(item) is S.true for item in items) assert Union(Interval(0, 1), Interval(2, 5)).contains(3) is S.true assert Union(Interval(0, 1), Interval(2, 5)).contains(6) is S.false assert Union(Interval(0, 1), FiniteSet(2, 5)).contains(3) is S.false assert S.EmptySet.contains(1) is S.false assert FiniteSet(rootof(x**3 + x - 1, 0)).contains(S.Infinity) is S.false assert rootof(x**5 + x**3 + 1, 0) in S.Reals assert not rootof(x**5 + x**3 + 1, 1) in S.Reals # non-bool results assert Union(Interval(1, 2), Interval(3, 4)).contains(x) == \ Or(And(S.One <= x, x <= 2), And(S(3) <= x, x <= 4)) assert Intersection(Interval(1, x), Interval(2, 3)).contains(y) == \ And(y <= 3, y <= x, S.One <= y, S(2) <= y) assert (S.Complexes).contains(S.ComplexInfinity) == S.false def test_interval_symbolic(): x = Symbol('x') e = Interval(0, 1) assert e.contains(x) == And(S.Zero <= x, x <= 1) raises(TypeError, lambda: x in e) e = Interval(0, 1, True, True) assert e.contains(x) == And(S.Zero < x, x < 1) c = Symbol('c', real=False) assert Interval(x, x + 1).contains(c) == False e = Symbol('e', extended_real=True) assert Interval(-oo, oo).contains(e) == And( S.NegativeInfinity < e, e < S.Infinity) def test_union_contains(): x = Symbol('x') i1 = Interval(0, 1) i2 = Interval(2, 3) i3 = Union(i1, i2) assert i3.as_relational(x) == Or(And(S.Zero <= x, x <= 1), And(S(2) <= x, x <= 3)) raises(TypeError, lambda: x in i3) e = i3.contains(x) assert e == i3.as_relational(x) assert e.subs(x, -0.5) is false assert e.subs(x, 0.5) is true assert e.subs(x, 1.5) is false assert e.subs(x, 2.5) is true assert e.subs(x, 3.5) is false U = Interval(0, 2, True, True) + Interval(10, oo) + FiniteSet(-1, 2, 5, 6) assert all(el not in U for el in [0, 4, -oo]) assert all(el in U for el in [2, 5, 10]) def test_is_number(): assert Interval(0, 1).is_number is False assert Set().is_number is False def test_Interval_is_left_unbounded(): assert Interval(3, 4).is_left_unbounded is False assert Interval(-oo, 3).is_left_unbounded is True assert Interval(Float("-inf"), 3).is_left_unbounded is True def test_Interval_is_right_unbounded(): assert Interval(3, 4).is_right_unbounded is False assert Interval(3, oo).is_right_unbounded is True assert Interval(3, Float("+inf")).is_right_unbounded is True def test_Interval_as_relational(): x = Symbol('x') assert Interval(-1, 2, False, False).as_relational(x) == \ And(Le(-1, x), Le(x, 2)) assert Interval(-1, 2, True, False).as_relational(x) == \ And(Lt(-1, x), Le(x, 2)) assert Interval(-1, 2, False, True).as_relational(x) == \ And(Le(-1, x), Lt(x, 2)) assert Interval(-1, 2, True, True).as_relational(x) == \ And(Lt(-1, x), Lt(x, 2)) assert Interval(-oo, 2, right_open=False).as_relational(x) == And(Lt(-oo, x), Le(x, 2)) assert Interval(-oo, 2, right_open=True).as_relational(x) == And(Lt(-oo, x), Lt(x, 2)) assert Interval(-2, oo, left_open=False).as_relational(x) == And(Le(-2, x), Lt(x, oo)) assert Interval(-2, oo, left_open=True).as_relational(x) == And(Lt(-2, x), Lt(x, oo)) assert Interval(-oo, oo).as_relational(x) == And(Lt(-oo, x), Lt(x, oo)) x = Symbol('x', real=True) y = Symbol('y', real=True) assert Interval(x, y).as_relational(x) == (x <= y) assert Interval(y, x).as_relational(x) == (y <= x) def test_Finite_as_relational(): x = Symbol('x') y = Symbol('y') assert FiniteSet(1, 2).as_relational(x) == Or(Eq(x, 1), Eq(x, 2)) assert FiniteSet(y, -5).as_relational(x) == Or(Eq(x, y), Eq(x, -5)) def test_Union_as_relational(): x = Symbol('x') assert (Interval(0, 1) + FiniteSet(2)).as_relational(x) == \ Or(And(Le(0, x), Le(x, 1)), Eq(x, 2)) assert (Interval(0, 1, True, True) + FiniteSet(1)).as_relational(x) == \ And(Lt(0, x), Le(x, 1)) assert Or(x < 0, x > 0).as_set().as_relational(x) == \ And((x > -oo), (x < oo), Ne(x, 0)) assert (Interval.Ropen(1, 3) + Interval.Lopen(3, 5) ).as_relational(x) == And((x > 1), (x < 5), Ne(x, 3)) def test_Intersection_as_relational(): x = Symbol('x') assert (Intersection(Interval(0, 1), FiniteSet(2), evaluate=False).as_relational(x) == And(And(Le(0, x), Le(x, 1)), Eq(x, 2))) def test_Complement_as_relational(): x = Symbol('x') expr = Complement(Interval(0, 1), FiniteSet(2), evaluate=False) assert expr.as_relational(x) == \ And(Le(0, x), Le(x, 1), Ne(x, 2)) @XFAIL def test_Complement_as_relational_fail(): x = Symbol('x') expr = Complement(Interval(0, 1), FiniteSet(2), evaluate=False) # XXX This example fails because 0 <= x changes to x >= 0 # during the evaluation. assert expr.as_relational(x) == \ (0 <= x) & (x <= 1) & Ne(x, 2) def test_SymmetricDifference_as_relational(): x = Symbol('x') expr = SymmetricDifference(Interval(0, 1), FiniteSet(2), evaluate=False) assert expr.as_relational(x) == Xor(Eq(x, 2), Le(0, x) & Le(x, 1)) def test_EmptySet(): assert S.EmptySet.as_relational(Symbol('x')) is S.false assert S.EmptySet.intersect(S.UniversalSet) == S.EmptySet assert S.EmptySet.boundary == S.EmptySet def test_finite_basic(): x = Symbol('x') A = FiniteSet(1, 2, 3) B = FiniteSet(3, 4, 5) AorB = Union(A, B) AandB = A.intersect(B) assert A.is_subset(AorB) and B.is_subset(AorB) assert AandB.is_subset(A) assert AandB == FiniteSet(3) assert A.inf == 1 and A.sup == 3 assert AorB.inf == 1 and AorB.sup == 5 assert FiniteSet(x, 1, 5).sup == Max(x, 5) assert FiniteSet(x, 1, 5).inf == Min(x, 1) # issue 7335 assert FiniteSet(S.EmptySet) != S.EmptySet assert FiniteSet(FiniteSet(1, 2, 3)) != FiniteSet(1, 2, 3) assert FiniteSet((1, 2, 3)) != FiniteSet(1, 2, 3) # Ensure a variety of types can exist in a FiniteSet assert FiniteSet((1, 2), Float, A, -5, x, 'eggs', x**2, Interval) assert (A > B) is False assert (A >= B) is False assert (A < B) is False assert (A <= B) is False assert AorB > A and AorB > B assert AorB >= A and AorB >= B assert A >= A and A <= A assert A >= AandB and B >= AandB assert A > AandB and B > AandB assert FiniteSet(1.0) == FiniteSet(1) def test_product_basic(): H, T = 'H', 'T' unit_line = Interval(0, 1) d6 = FiniteSet(1, 2, 3, 4, 5, 6) d4 = FiniteSet(1, 2, 3, 4) coin = FiniteSet(H, T) square = unit_line * unit_line assert (0, 0) in square assert 0 not in square assert (H, T) in coin ** 2 assert (.5, .5, .5) in (square * unit_line).flatten() assert ((.5, .5), .5) in square * unit_line assert (H, 3, 3) in (coin * d6 * d6).flatten() assert ((H, 3), 3) in coin * d6 * d6 HH, TT = sympify(H), sympify(T) assert set(coin**2) == {(HH, HH), (HH, TT), (TT, HH), (TT, TT)} assert (d4*d4).is_subset(d6*d6) assert square.complement(Interval(-oo, oo)*Interval(-oo, oo)) == Union( (Interval(-oo, 0, True, True) + Interval(1, oo, True, True))*Interval(-oo, oo), Interval(-oo, oo)*(Interval(-oo, 0, True, True) + Interval(1, oo, True, True))) assert (Interval(-5, 5)**3).is_subset(Interval(-10, 10)**3) assert not (Interval(-10, 10)**3).is_subset(Interval(-5, 5)**3) assert not (Interval(-5, 5)**2).is_subset(Interval(-10, 10)**3) assert (Interval(.2, .5)*FiniteSet(.5)).is_subset(square) # segment in square assert len(coin*coin*coin) == 8 assert len(S.EmptySet*S.EmptySet) == 0 assert len(S.EmptySet*coin) == 0 raises(TypeError, lambda: len(coin*Interval(0, 2))) def test_real(): x = Symbol('x', real=True, finite=True) I = Interval(0, 5) J = Interval(10, 20) A = FiniteSet(1, 2, 30, x, S.Pi) B = FiniteSet(-4, 0) C = FiniteSet(100) D = FiniteSet('Ham', 'Eggs') assert all(s.is_subset(S.Reals) for s in [I, J, A, B, C]) assert not D.is_subset(S.Reals) assert all((a + b).is_subset(S.Reals) for a in [I, J, A, B, C] for b in [I, J, A, B, C]) assert not any((a + D).is_subset(S.Reals) for a in [I, J, A, B, C, D]) assert not (I + A + D).is_subset(S.Reals) def test_supinf(): x = Symbol('x', real=True) y = Symbol('y', real=True) assert (Interval(0, 1) + FiniteSet(2)).sup == 2 assert (Interval(0, 1) + FiniteSet(2)).inf == 0 assert (Interval(0, 1) + FiniteSet(x)).sup == Max(1, x) assert (Interval(0, 1) + FiniteSet(x)).inf == Min(0, x) assert FiniteSet(5, 1, x).sup == Max(5, x) assert FiniteSet(5, 1, x).inf == Min(1, x) assert FiniteSet(5, 1, x, y).sup == Max(5, x, y) assert FiniteSet(5, 1, x, y).inf == Min(1, x, y) assert FiniteSet(5, 1, x, y, S.Infinity, S.NegativeInfinity).sup == \ S.Infinity assert FiniteSet(5, 1, x, y, S.Infinity, S.NegativeInfinity).inf == \ S.NegativeInfinity assert FiniteSet('Ham', 'Eggs').sup == Max('Ham', 'Eggs') def test_universalset(): U = S.UniversalSet x = Symbol('x') assert U.as_relational(x) is S.true assert U.union(Interval(2, 4)) == U assert U.intersect(Interval(2, 4)) == Interval(2, 4) assert U.measure is S.Infinity assert U.boundary == S.EmptySet assert U.contains(0) is S.true def test_Union_of_ProductSets_shares(): line = Interval(0, 2) points = FiniteSet(0, 1, 2) assert Union(line * line, line * points) == line * line def test_Interval_free_symbols(): # issue 6211 assert Interval(0, 1).free_symbols == set() x = Symbol('x', real=True) assert Interval(0, x).free_symbols == {x} def test_image_interval(): from sympy.core.numbers import Rational x = Symbol('x', real=True) a = Symbol('a', real=True) assert imageset(x, 2*x, Interval(-2, 1)) == Interval(-4, 2) assert imageset(x, 2*x, Interval(-2, 1, True, False)) == \ Interval(-4, 2, True, False) assert imageset(x, x**2, Interval(-2, 1, True, False)) == \ Interval(0, 4, False, True) assert imageset(x, x**2, Interval(-2, 1)) == Interval(0, 4) assert imageset(x, x**2, Interval(-2, 1, True, False)) == \ Interval(0, 4, False, True) assert imageset(x, x**2, Interval(-2, 1, True, True)) == \ Interval(0, 4, False, True) assert imageset(x, (x - 2)**2, Interval(1, 3)) == Interval(0, 1) assert imageset(x, 3*x**4 - 26*x**3 + 78*x**2 - 90*x, Interval(0, 4)) == \ Interval(-35, 0) # Multiple Maxima assert imageset(x, x + 1/x, Interval(-oo, oo)) == Interval(-oo, -2) \ + Interval(2, oo) # Single Infinite discontinuity assert imageset(x, 1/x + 1/(x-1)**2, Interval(0, 2, True, False)) == \ Interval(Rational(3, 2), oo, False) # Multiple Infinite discontinuities # Test for Python lambda assert imageset(lambda x: 2*x, Interval(-2, 1)) == Interval(-4, 2) assert imageset(Lambda(x, a*x), Interval(0, 1)) == \ ImageSet(Lambda(x, a*x), Interval(0, 1)) assert imageset(Lambda(x, sin(cos(x))), Interval(0, 1)) == \ ImageSet(Lambda(x, sin(cos(x))), Interval(0, 1)) def test_image_piecewise(): f = Piecewise((x, x <= -1), (1/x**2, x <= 5), (x**3, True)) f1 = Piecewise((0, x <= 1), (1, x <= 2), (2, True)) assert imageset(x, f, Interval(-5, 5)) == Union(Interval(-5, -1), Interval(Rational(1, 25), oo)) assert imageset(x, f1, Interval(1, 2)) == FiniteSet(0, 1) @XFAIL # See: https://github.com/sympy/sympy/pull/2723#discussion_r8659826 def test_image_Intersection(): x = Symbol('x', real=True) y = Symbol('y', real=True) assert imageset(x, x**2, Interval(-2, 0).intersect(Interval(x, y))) == \ Interval(0, 4).intersect(Interval(Min(x**2, y**2), Max(x**2, y**2))) def test_image_FiniteSet(): x = Symbol('x', real=True) assert imageset(x, 2*x, FiniteSet(1, 2, 3)) == FiniteSet(2, 4, 6) def test_image_Union(): x = Symbol('x', real=True) assert imageset(x, x**2, Interval(-2, 0) + FiniteSet(1, 2, 3)) == \ (Interval(0, 4) + FiniteSet(9)) def test_image_EmptySet(): x = Symbol('x', real=True) assert imageset(x, 2*x, S.EmptySet) == S.EmptySet def test_issue_5724_7680(): assert I not in S.Reals # issue 7680 assert Interval(-oo, oo).contains(I) is S.false def test_boundary(): assert FiniteSet(1).boundary == FiniteSet(1) assert all(Interval(0, 1, left_open, right_open).boundary == FiniteSet(0, 1) for left_open in (true, false) for right_open in (true, false)) def test_boundary_Union(): assert (Interval(0, 1) + Interval(2, 3)).boundary == FiniteSet(0, 1, 2, 3) assert ((Interval(0, 1, False, True) + Interval(1, 2, True, False)).boundary == FiniteSet(0, 1, 2)) assert (Interval(0, 1) + FiniteSet(2)).boundary == FiniteSet(0, 1, 2) assert Union(Interval(0, 10), Interval(5, 15), evaluate=False).boundary \ == FiniteSet(0, 15) assert Union(Interval(0, 10), Interval(0, 1), evaluate=False).boundary \ == FiniteSet(0, 10) assert Union(Interval(0, 10, True, True), Interval(10, 15, True, True), evaluate=False).boundary \ == FiniteSet(0, 10, 15) @XFAIL def test_union_boundary_of_joining_sets(): """ Testing the boundary of unions is a hard problem """ assert Union(Interval(0, 10), Interval(10, 15), evaluate=False).boundary \ == FiniteSet(0, 15) def test_boundary_ProductSet(): open_square = Interval(0, 1, True, True) ** 2 assert open_square.boundary == (FiniteSet(0, 1) * Interval(0, 1) + Interval(0, 1) * FiniteSet(0, 1)) second_square = Interval(1, 2, True, True) * Interval(0, 1, True, True) assert (open_square + second_square).boundary == ( FiniteSet(0, 1) * Interval(0, 1) + FiniteSet(1, 2) * Interval(0, 1) + Interval(0, 1) * FiniteSet(0, 1) + Interval(1, 2) * FiniteSet(0, 1)) def test_boundary_ProductSet_line(): line_in_r2 = Interval(0, 1) * FiniteSet(0) assert line_in_r2.boundary == line_in_r2 def test_is_open(): assert Interval(0, 1, False, False).is_open is False assert Interval(0, 1, True, False).is_open is False assert Interval(0, 1, True, True).is_open is True assert FiniteSet(1, 2, 3).is_open is False def test_is_closed(): assert Interval(0, 1, False, False).is_closed is True assert Interval(0, 1, True, False).is_closed is False assert FiniteSet(1, 2, 3).is_closed is True def test_closure(): assert Interval(0, 1, False, True).closure == Interval(0, 1, False, False) def test_interior(): assert Interval(0, 1, False, True).interior == Interval(0, 1, True, True) def test_issue_7841(): raises(TypeError, lambda: x in S.Reals) def test_Eq(): assert Eq(Interval(0, 1), Interval(0, 1)) assert Eq(Interval(0, 1), Interval(0, 2)) == False s1 = FiniteSet(0, 1) s2 = FiniteSet(1, 2) assert Eq(s1, s1) assert Eq(s1, s2) == False assert Eq(s1*s2, s1*s2) assert Eq(s1*s2, s2*s1) == False assert unchanged(Eq, FiniteSet({x, y}), FiniteSet({x})) assert Eq(FiniteSet({x, y}).subs(y, x), FiniteSet({x})) is S.true assert Eq(FiniteSet({x, y}), FiniteSet({x})).subs(y, x) is S.true assert Eq(FiniteSet({x, y}).subs(y, x+1), FiniteSet({x})) is S.false assert Eq(FiniteSet({x, y}), FiniteSet({x})).subs(y, x+1) is S.false assert Eq(ProductSet({1}, {2}), Interval(1, 2)) is S.false assert Eq(ProductSet({1}), ProductSet({1}, {2})) is S.false assert Eq(FiniteSet(()), FiniteSet(1)) is S.false assert Eq(ProductSet(), FiniteSet(1)) is S.false i1 = Interval(0, 1) i2 = Interval(x, y) assert unchanged(Eq, ProductSet(i1, i1), ProductSet(i2, i2)) def test_SymmetricDifference(): A = FiniteSet(0, 1, 2, 3, 4, 5) B = FiniteSet(2, 4, 6, 8, 10) C = Interval(8, 10) assert SymmetricDifference(A, B, evaluate=False).is_iterable is True assert SymmetricDifference(A, C, evaluate=False).is_iterable is None assert FiniteSet(*SymmetricDifference(A, B, evaluate=False)) == \ FiniteSet(0, 1, 3, 5, 6, 8, 10) raises(TypeError, lambda: FiniteSet(*SymmetricDifference(A, C, evaluate=False))) assert SymmetricDifference(FiniteSet(0, 1, 2, 3, 4, 5), \ FiniteSet(2, 4, 6, 8, 10)) == FiniteSet(0, 1, 3, 5, 6, 8, 10) assert SymmetricDifference(FiniteSet(2, 3, 4), FiniteSet(2, 3 , 4 , 5)) \ == FiniteSet(5) assert FiniteSet(1, 2, 3, 4, 5) ^ FiniteSet(1, 2, 5, 6) == \ FiniteSet(3, 4, 6) assert Set(S(1), S(2) , S(3)) ^ Set(S(2), S(3), S(4)) == Union(Set(S(1), S(2), S(3)) - Set(S(2), S(3), S(4)), \ Set(S(2), S(3), S(4)) - Set(S(1), S(2), S(3))) assert Interval(0, 4) ^ Interval(2, 5) == Union(Interval(0, 4) - \ Interval(2, 5), Interval(2, 5) - Interval(0, 4)) def test_issue_9536(): from sympy.functions.elementary.exponential import log a = Symbol('a', real=True) assert FiniteSet(log(a)).intersect(S.Reals) == Intersection(S.Reals, FiniteSet(log(a))) def test_issue_9637(): n = Symbol('n') a = FiniteSet(n) b = FiniteSet(2, n) assert Complement(S.Reals, a) == Complement(S.Reals, a, evaluate=False) assert Complement(Interval(1, 3), a) == Complement(Interval(1, 3), a, evaluate=False) assert Complement(Interval(1, 3), b) == \ Complement(Union(Interval(1, 2, False, True), Interval(2, 3, True, False)), a) assert Complement(a, S.Reals) == Complement(a, S.Reals, evaluate=False) assert Complement(a, Interval(1, 3)) == Complement(a, Interval(1, 3), evaluate=False) def test_issue_9808(): # See https://github.com/sympy/sympy/issues/16342 assert Complement(FiniteSet(y), FiniteSet(1)) == Complement(FiniteSet(y), FiniteSet(1), evaluate=False) assert Complement(FiniteSet(1, 2, x), FiniteSet(x, y, 2, 3)) == \ Complement(FiniteSet(1), FiniteSet(y), evaluate=False) def test_issue_9956(): assert Union(Interval(-oo, oo), FiniteSet(1)) == Interval(-oo, oo) assert Interval(-oo, oo).contains(1) is S.true def test_issue_Symbol_inter(): i = Interval(0, oo) r = S.Reals mat = Matrix([0, 0, 0]) assert Intersection(r, i, FiniteSet(m), FiniteSet(m, n)) == \ Intersection(i, FiniteSet(m)) assert Intersection(FiniteSet(1, m, n), FiniteSet(m, n, 2), i) == \ Intersection(i, FiniteSet(m, n)) assert Intersection(FiniteSet(m, n, x), FiniteSet(m, z), r) == \ Intersection(Intersection({m, z}, {m, n, x}), r) assert Intersection(FiniteSet(m, n, 3), FiniteSet(m, n, x), r) == \ Intersection(FiniteSet(3, m, n), FiniteSet(m, n, x), r, evaluate=False) assert Intersection(FiniteSet(m, n, 3), FiniteSet(m, n, 2, 3), r) == \ Intersection(FiniteSet(3, m, n), r) assert Intersection(r, FiniteSet(mat, 2, n), FiniteSet(0, mat, n)) == \ Intersection(r, FiniteSet(n)) assert Intersection(FiniteSet(sin(x), cos(x)), FiniteSet(sin(x), cos(x), 1), r) == \ Intersection(r, FiniteSet(sin(x), cos(x))) assert Intersection(FiniteSet(x**2, 1, sin(x)), FiniteSet(x**2, 2, sin(x)), r) == \ Intersection(r, FiniteSet(x**2, sin(x))) def test_issue_11827(): assert S.Naturals0**4 def test_issue_10113(): f = x**2/(x**2 - 4) assert imageset(x, f, S.Reals) == Union(Interval(-oo, 0), Interval(1, oo, True, True)) assert imageset(x, f, Interval(-2, 2)) == Interval(-oo, 0) assert imageset(x, f, Interval(-2, 3)) == Union(Interval(-oo, 0), Interval(Rational(9, 5), oo)) def test_issue_10248(): raises( TypeError, lambda: list(Intersection(S.Reals, FiniteSet(x))) ) A = Symbol('A', real=True) assert list(Intersection(S.Reals, FiniteSet(A))) == [A] def test_issue_9447(): a = Interval(0, 1) + Interval(2, 3) assert Complement(S.UniversalSet, a) == Complement( S.UniversalSet, Union(Interval(0, 1), Interval(2, 3)), evaluate=False) assert Complement(S.Naturals, a) == Complement( S.Naturals, Union(Interval(0, 1), Interval(2, 3)), evaluate=False) def test_issue_10337(): assert (FiniteSet(2) == 3) is False assert (FiniteSet(2) != 3) is True raises(TypeError, lambda: FiniteSet(2) < 3) raises(TypeError, lambda: FiniteSet(2) <= 3) raises(TypeError, lambda: FiniteSet(2) > 3) raises(TypeError, lambda: FiniteSet(2) >= 3) def test_issue_10326(): bad = [ EmptySet, FiniteSet(1), Interval(1, 2), S.ComplexInfinity, S.ImaginaryUnit, S.Infinity, S.NaN, S.NegativeInfinity, ] interval = Interval(0, 5) for i in bad: assert i not in interval x = Symbol('x', real=True) nr = Symbol('nr', extended_real=False) assert x + 1 in Interval(x, x + 4) assert nr not in Interval(x, x + 4) assert Interval(1, 2) in FiniteSet(Interval(0, 5), Interval(1, 2)) assert Interval(-oo, oo).contains(oo) is S.false assert Interval(-oo, oo).contains(-oo) is S.false def test_issue_2799(): U = S.UniversalSet a = Symbol('a', real=True) inf_interval = Interval(a, oo) R = S.Reals assert U + inf_interval == inf_interval + U assert U + R == R + U assert R + inf_interval == inf_interval + R def test_issue_9706(): assert Interval(-oo, 0).closure == Interval(-oo, 0, True, False) assert Interval(0, oo).closure == Interval(0, oo, False, True) assert Interval(-oo, oo).closure == Interval(-oo, oo) def test_issue_8257(): reals_plus_infinity = Union(Interval(-oo, oo), FiniteSet(oo)) reals_plus_negativeinfinity = Union(Interval(-oo, oo), FiniteSet(-oo)) assert Interval(-oo, oo) + FiniteSet(oo) == reals_plus_infinity assert FiniteSet(oo) + Interval(-oo, oo) == reals_plus_infinity assert Interval(-oo, oo) + FiniteSet(-oo) == reals_plus_negativeinfinity assert FiniteSet(-oo) + Interval(-oo, oo) == reals_plus_negativeinfinity def test_issue_10931(): assert S.Integers - S.Integers == EmptySet assert S.Integers - S.Reals == EmptySet def test_issue_11174(): soln = Intersection(Interval(-oo, oo), FiniteSet(-x), evaluate=False) assert Intersection(FiniteSet(-x), S.Reals) == soln soln = Intersection(S.Reals, FiniteSet(x), evaluate=False) assert Intersection(FiniteSet(x), S.Reals) == soln def test_issue_18505(): assert ImageSet(Lambda(n, sqrt(pi*n/2 - 1 + pi/2)), S.Integers).contains(0) == \ Contains(0, ImageSet(Lambda(n, sqrt(pi*n/2 - 1 + pi/2)), S.Integers)) def test_finite_set_intersection(): # The following should not produce recursion errors # Note: some of these are not completely correct. See # https://github.com/sympy/sympy/issues/16342. assert Intersection(FiniteSet(-oo, x), FiniteSet(x)) == FiniteSet(x) assert Intersection._handle_finite_sets([FiniteSet(-oo, x), FiniteSet(0, x)]) == FiniteSet(x) assert Intersection._handle_finite_sets([FiniteSet(-oo, x), FiniteSet(x)]) == FiniteSet(x) assert Intersection._handle_finite_sets([FiniteSet(2, 3, x, y), FiniteSet(1, 2, x)]) == \ Intersection._handle_finite_sets([FiniteSet(1, 2, x), FiniteSet(2, 3, x, y)]) == \ Intersection(FiniteSet(1, 2, x), FiniteSet(2, 3, x, y)) == \ Intersection(FiniteSet(1, 2, x), FiniteSet(2, x, y)) assert FiniteSet(1+x-y) & FiniteSet(1) == \ FiniteSet(1) & FiniteSet(1+x-y) == \ Intersection(FiniteSet(1+x-y), FiniteSet(1), evaluate=False) assert FiniteSet(1) & FiniteSet(x) == FiniteSet(x) & FiniteSet(1) == \ Intersection(FiniteSet(1), FiniteSet(x), evaluate=False) assert FiniteSet({x}) & FiniteSet({x, y}) == \ Intersection(FiniteSet({x}), FiniteSet({x, y}), evaluate=False) def test_union_intersection_constructor(): # The actual exception does not matter here, so long as these fail sets = [FiniteSet(1), FiniteSet(2)] raises(Exception, lambda: Union(sets)) raises(Exception, lambda: Intersection(sets)) raises(Exception, lambda: Union(tuple(sets))) raises(Exception, lambda: Intersection(tuple(sets))) raises(Exception, lambda: Union(i for i in sets)) raises(Exception, lambda: Intersection(i for i in sets)) # Python sets are treated the same as FiniteSet # The union of a single set (of sets) is the set (of sets) itself assert Union(set(sets)) == FiniteSet(*sets) assert Intersection(set(sets)) == FiniteSet(*sets) assert Union({1}, {2}) == FiniteSet(1, 2) assert Intersection({1, 2}, {2, 3}) == FiniteSet(2) def test_Union_contains(): assert zoo not in Union( Interval.open(-oo, 0), Interval.open(0, oo)) @XFAIL def test_issue_16878b(): # in intersection_sets for (ImageSet, Set) there is no code # that handles the base_set of S.Reals like there is # for Integers assert imageset(x, (x, x), S.Reals).is_subset(S.Reals**2) is True def test_DisjointUnion(): assert DisjointUnion(FiniteSet(1, 2, 3), FiniteSet(1, 2, 3), FiniteSet(1, 2, 3)).rewrite(Union) == (FiniteSet(1, 2, 3) * FiniteSet(0, 1, 2)) assert DisjointUnion(Interval(1, 3), Interval(2, 4)).rewrite(Union) == Union(Interval(1, 3) * FiniteSet(0), Interval(2, 4) * FiniteSet(1)) assert DisjointUnion(Interval(0, 5), Interval(0, 5)).rewrite(Union) == Union(Interval(0, 5) * FiniteSet(0), Interval(0, 5) * FiniteSet(1)) assert DisjointUnion(Interval(-1, 2), S.EmptySet, S.EmptySet).rewrite(Union) == Interval(-1, 2) * FiniteSet(0) assert DisjointUnion(Interval(-1, 2)).rewrite(Union) == Interval(-1, 2) * FiniteSet(0) assert DisjointUnion(S.EmptySet, Interval(-1, 2), S.EmptySet).rewrite(Union) == Interval(-1, 2) * FiniteSet(1) assert DisjointUnion(Interval(-oo, oo)).rewrite(Union) == Interval(-oo, oo) * FiniteSet(0) assert DisjointUnion(S.EmptySet).rewrite(Union) == S.EmptySet assert DisjointUnion().rewrite(Union) == S.EmptySet raises(TypeError, lambda: DisjointUnion(Symbol('n'))) x = Symbol("x") y = Symbol("y") z = Symbol("z") assert DisjointUnion(FiniteSet(x), FiniteSet(y, z)).rewrite(Union) == (FiniteSet(x) * FiniteSet(0)) + (FiniteSet(y, z) * FiniteSet(1)) def test_DisjointUnion_is_empty(): assert DisjointUnion(S.EmptySet).is_empty is True assert DisjointUnion(S.EmptySet, S.EmptySet).is_empty is True assert DisjointUnion(S.EmptySet, FiniteSet(1, 2, 3)).is_empty is False def test_DisjointUnion_is_iterable(): assert DisjointUnion(S.Integers, S.Naturals, S.Rationals).is_iterable is True assert DisjointUnion(S.EmptySet, S.Reals).is_iterable is False assert DisjointUnion(FiniteSet(1, 2, 3), S.EmptySet, FiniteSet(x, y)).is_iterable is True assert DisjointUnion(S.EmptySet, S.EmptySet).is_iterable is False def test_DisjointUnion_contains(): assert (0, 0) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (0, 1) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (0, 2) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (1, 0) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (1, 1) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (1, 2) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (2, 0) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (2, 1) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (2, 2) in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (0, 1, 2) not in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (0, 0.5) not in DisjointUnion(FiniteSet(0.5)) assert (0, 5) not in DisjointUnion(FiniteSet(0, 1, 2), FiniteSet(0, 1, 2), FiniteSet(0, 1, 2)) assert (x, 0) in DisjointUnion(FiniteSet(x, y, z), S.EmptySet, FiniteSet(y)) assert (y, 0) in DisjointUnion(FiniteSet(x, y, z), S.EmptySet, FiniteSet(y)) assert (z, 0) in DisjointUnion(FiniteSet(x, y, z), S.EmptySet, FiniteSet(y)) assert (y, 2) in DisjointUnion(FiniteSet(x, y, z), S.EmptySet, FiniteSet(y)) assert (0.5, 0) in DisjointUnion(Interval(0, 1), Interval(0, 2)) assert (0.5, 1) in DisjointUnion(Interval(0, 1), Interval(0, 2)) assert (1.5, 0) not in DisjointUnion(Interval(0, 1), Interval(0, 2)) assert (1.5, 1) in DisjointUnion(Interval(0, 1), Interval(0, 2)) def test_DisjointUnion_iter(): D = DisjointUnion(FiniteSet(3, 5, 7, 9), FiniteSet(x, y, z)) it = iter(D) L1 = [(x, 1), (y, 1), (z, 1)] L2 = [(3, 0), (5, 0), (7, 0), (9, 0)] nxt = next(it) assert nxt in L2 L2.remove(nxt) nxt = next(it) assert nxt in L1 L1.remove(nxt) nxt = next(it) assert nxt in L2 L2.remove(nxt) nxt = next(it) assert nxt in L1 L1.remove(nxt) nxt = next(it) assert nxt in L2 L2.remove(nxt) nxt = next(it) assert nxt in L1 L1.remove(nxt) nxt = next(it) assert nxt in L2 L2.remove(nxt) raises(StopIteration, lambda: next(it)) raises(ValueError, lambda: iter(DisjointUnion(Interval(0, 1), S.EmptySet))) def test_DisjointUnion_len(): assert len(DisjointUnion(FiniteSet(3, 5, 7, 9), FiniteSet(x, y, z))) == 7 assert len(DisjointUnion(S.EmptySet, S.EmptySet, FiniteSet(x, y, z), S.EmptySet)) == 3 raises(ValueError, lambda: len(DisjointUnion(Interval(0, 1), S.EmptySet))) def test_issue_20089(): B = FiniteSet(FiniteSet(1, 2), FiniteSet(1)) assert not 1 in B assert not 1.0 in B assert not Eq(1, FiniteSet(1, 2)) assert FiniteSet(1) in B A = FiniteSet(1, 2) assert A in B assert B.issubset(B) assert not A.issubset(B) assert 1 in A C = FiniteSet(FiniteSet(1, 2), FiniteSet(1), 1, 2) assert A.issubset(C) assert B.issubset(C) def test_issue_19378(): a = FiniteSet(1, 2) b = ProductSet(a, a) c = FiniteSet((1, 1), (1, 2), (2, 1), (2, 2)) assert b.is_subset(c) is True d = FiniteSet(1) assert b.is_subset(d) is False assert Eq(c, b).simplify() is S.true assert Eq(a, c).simplify() is S.false assert Eq({1}, {x}).simplify() == Eq({1}, {x}) def test_issue_20379(): #https://github.com/sympy/sympy/issues/20379 x = pi - 3.14159265358979 assert FiniteSet(x).evalf(2) == FiniteSet(Float('3.23108914886517e-15', 2)) def test_finiteset_simplify(): S = FiniteSet(1, cos(1)**2 + sin(1)**2) assert S.simplify() == {1} sympy-sympy-1.9/sympy/simplify/000077500000000000000000000000001412543434000167405ustar00rootroot00000000000000sympy-sympy-1.9/sympy/simplify/__init__.py000066400000000000000000000024771412543434000210630ustar00rootroot00000000000000"""The module helps converting SymPy expressions into shorter forms of them. for example: the expression E**(pi*I) will be converted into -1 the expression (x+x)**2 will be converted into 4*x**2 """ from .simplify import (simplify, hypersimp, hypersimilar, logcombine, separatevars, posify, besselsimp, kroneckersimp, signsimp, bottom_up, nsimplify) from .fu import FU, fu from .sqrtdenest import sqrtdenest from .cse_main import cse from .traversaltools import use from .epathtools import epath, EPath from .hyperexpand import hyperexpand from .radsimp import collect, rcollect, radsimp, collect_const, fraction, numer, denom from .trigsimp import trigsimp, exptrigsimp from .powsimp import powsimp, powdenest from .combsimp import combsimp from .gammasimp import gammasimp from .ratsimp import ratsimp, ratsimpmodprime __all__ = [ 'simplify', 'hypersimp', 'hypersimilar', 'logcombine', 'separatevars', 'posify', 'besselsimp', 'kroneckersimp', 'signsimp', 'bottom_up', 'nsimplify', 'FU', 'fu', 'sqrtdenest', 'cse', 'use', 'epath', 'EPath', 'hyperexpand', 'collect', 'rcollect', 'radsimp', 'collect_const', 'fraction', 'numer', 'denom', 'trigsimp', 'exptrigsimp', 'powsimp', 'powdenest', 'combsimp', 'gammasimp', 'ratsimp', 'ratsimpmodprime', ] sympy-sympy-1.9/sympy/simplify/combsimp.py000066400000000000000000000070531412543434000211300ustar00rootroot00000000000000from sympy.core import Mul from sympy.core.basic import preorder_traversal from sympy.core.function import count_ops from sympy.functions.combinatorial.factorials import binomial, factorial from sympy.functions import gamma from sympy.simplify.gammasimp import gammasimp, _gammasimp from sympy.utilities.timeutils import timethis @timethis('combsimp') def combsimp(expr): r""" Simplify combinatorial expressions. Explanation =========== This function takes as input an expression containing factorials, binomials, Pochhammer symbol and other "combinatorial" functions, and tries to minimize the number of those functions and reduce the size of their arguments. The algorithm works by rewriting all combinatorial functions as gamma functions and applying gammasimp() except simplification steps that may make an integer argument non-integer. See docstring of gammasimp for more information. Then it rewrites expression in terms of factorials and binomials by rewriting gammas as factorials and converting (a+b)!/a!b! into binomials. If expression has gamma functions or combinatorial functions with non-integer argument, it is automatically passed to gammasimp. Examples ======== >>> from sympy.simplify import combsimp >>> from sympy import factorial, binomial, symbols >>> n, k = symbols('n k', integer = True) >>> combsimp(factorial(n)/factorial(n - 3)) n*(n - 2)*(n - 1) >>> combsimp(binomial(n+1, k+1)/binomial(n, k)) (n + 1)/(k + 1) """ expr = expr.rewrite(gamma, piecewise=False) if any(isinstance(node, gamma) and not node.args[0].is_integer for node in preorder_traversal(expr)): return gammasimp(expr); expr = _gammasimp(expr, as_comb = True) expr = _gamma_as_comb(expr) return expr def _gamma_as_comb(expr): """ Helper function for combsimp. Rewrites expression in terms of factorials and binomials """ expr = expr.rewrite(factorial) from .simplify import bottom_up def f(rv): if not rv.is_Mul: return rv rvd = rv.as_powers_dict() nd_fact_args = [[], []] # numerator, denominator for k in rvd: if isinstance(k, factorial) and rvd[k].is_Integer: if rvd[k].is_positive: nd_fact_args[0].extend([k.args[0]]*rvd[k]) else: nd_fact_args[1].extend([k.args[0]]*-rvd[k]) rvd[k] = 0 if not nd_fact_args[0] or not nd_fact_args[1]: return rv hit = False for m in range(2): i = 0 while i < len(nd_fact_args[m]): ai = nd_fact_args[m][i] for j in range(i + 1, len(nd_fact_args[m])): aj = nd_fact_args[m][j] sum = ai + aj if sum in nd_fact_args[1 - m]: hit = True nd_fact_args[1 - m].remove(sum) del nd_fact_args[m][j] del nd_fact_args[m][i] rvd[binomial(sum, ai if count_ops(ai) < count_ops(aj) else aj)] += ( -1 if m == 0 else 1) break else: i += 1 if hit: return Mul(*([k**rvd[k] for k in rvd] + [factorial(k) for k in nd_fact_args[0]]))/Mul(*[factorial(k) for k in nd_fact_args[1]]) return rv return bottom_up(expr, f) sympy-sympy-1.9/sympy/simplify/cse_main.py000066400000000000000000000731721412543434000211020ustar00rootroot00000000000000""" Tools for doing common subexpression elimination. """ from sympy.core import Basic, Mul, Add, Pow, sympify, Symbol from sympy.core.compatibility import iterable from sympy.core.containers import Tuple, OrderedSet from sympy.core.exprtools import factor_terms from sympy.core.function import _coeff_isneg from sympy.core.singleton import S from sympy.utilities.iterables import numbered_symbols, sift, \ topological_sort, ordered from . import cse_opts # (preprocessor, postprocessor) pairs which are commonly useful. They should # each take a sympy expression and return a possibly transformed expression. # When used in the function ``cse()``, the target expressions will be transformed # by each of the preprocessor functions in order. After the common # subexpressions are eliminated, each resulting expression will have the # postprocessor functions transform them in *reverse* order in order to undo the # transformation if necessary. This allows the algorithm to operate on # a representation of the expressions that allows for more optimization # opportunities. # ``None`` can be used to specify no transformation for either the preprocessor or # postprocessor. basic_optimizations = [(cse_opts.sub_pre, cse_opts.sub_post), (factor_terms, None)] # sometimes we want the output in a different format; non-trivial # transformations can be put here for users # =============================================================== def reps_toposort(r): """Sort replacements ``r`` so (k1, v1) appears before (k2, v2) if k2 is in v1's free symbols. This orders items in the way that cse returns its results (hence, in order to use the replacements in a substitution option it would make sense to reverse the order). Examples ======== >>> from sympy.simplify.cse_main import reps_toposort >>> from sympy.abc import x, y >>> from sympy import Eq >>> for l, r in reps_toposort([(x, y + 1), (y, 2)]): ... print(Eq(l, r)) ... Eq(y, 2) Eq(x, y + 1) """ r = sympify(r) E = [] for c1, (k1, v1) in enumerate(r): for c2, (k2, v2) in enumerate(r): if k1 in v2.free_symbols: E.append((c1, c2)) return [r[i] for i in topological_sort((range(len(r)), E))] def cse_separate(r, e): """Move expressions that are in the form (symbol, expr) out of the expressions and sort them into the replacements using the reps_toposort. Examples ======== >>> from sympy.simplify.cse_main import cse_separate >>> from sympy.abc import x, y, z >>> from sympy import cos, exp, cse, Eq, symbols >>> x0, x1 = symbols('x:2') >>> eq = (x + 1 + exp((x + 1)/(y + 1)) + cos(y + 1)) >>> cse([eq, Eq(x, z + 1), z - 2], postprocess=cse_separate) in [ ... [[(x0, y + 1), (x, z + 1), (x1, x + 1)], ... [x1 + exp(x1/x0) + cos(x0), z - 2]], ... [[(x1, y + 1), (x, z + 1), (x0, x + 1)], ... [x0 + exp(x0/x1) + cos(x1), z - 2]]] ... True """ d = sift(e, lambda w: w.is_Equality and w.lhs.is_Symbol) r = r + [w.args for w in d[True]] e = d[False] return [reps_toposort(r), e] def cse_release_variables(r, e): """ Return tuples giving ``(a, b)`` where ``a`` is a symbol and ``b`` is either an expression or None. The value of None is used when a symbol is no longer needed for subsequent expressions. Use of such output can reduce the memory footprint of lambdified expressions that contain large, repeated subexpressions. Examples ======== >>> from sympy import cse >>> from sympy.simplify.cse_main import cse_release_variables >>> from sympy.abc import x, y >>> eqs = [(x + y - 1)**2, x, x + y, (x + y)/(2*x + 1) + (x + y - 1)**2, (2*x + 1)**(x + y)] >>> defs, rvs = cse_release_variables(*cse(eqs)) >>> for i in defs: ... print(i) ... (x0, x + y) (x1, (x0 - 1)**2) (x2, 2*x + 1) (_3, x0/x2 + x1) (_4, x2**x0) (x2, None) (_0, x1) (x1, None) (_2, x0) (x0, None) (_1, x) >>> print(rvs) (_0, _1, _2, _3, _4) """ if not r: return r, e from sympy import symbols s, p = zip(*r) esyms = symbols('_:%d' % len(e)) syms = list(esyms) s = list(s) in_use = set(s) p = list(p) # sort e so those with most sub-expressions appear first e = [(e[i], syms[i]) for i in range(len(e))] e, syms = zip(*sorted(e, key=lambda x: -sum([p[s.index(i)].count_ops() for i in x[0].free_symbols & in_use]))) syms = list(syms) p += e rv = [] i = len(p) - 1 while i >= 0: _p = p.pop() c = in_use & _p.free_symbols if c: # sorting for canonical results rv.extend([(s, None) for s in sorted(c, key=str)]) if i >= len(r): rv.append((syms.pop(), _p)) else: rv.append((s[i], _p)) in_use -= c i -= 1 rv.reverse() return rv, esyms # ====end of cse postprocess idioms=========================== def preprocess_for_cse(expr, optimizations): """ Preprocess an expression to optimize for common subexpression elimination. Parameters ========== expr : sympy expression The target expression to optimize. optimizations : list of (callable, callable) pairs The (preprocessor, postprocessor) pairs. Returns ======= expr : sympy expression The transformed expression. """ for pre, post in optimizations: if pre is not None: expr = pre(expr) return expr def postprocess_for_cse(expr, optimizations): """Postprocess an expression after common subexpression elimination to return the expression to canonical SymPy form. Parameters ========== expr : sympy expression The target expression to transform. optimizations : list of (callable, callable) pairs, optional The (preprocessor, postprocessor) pairs. The postprocessors will be applied in reversed order to undo the effects of the preprocessors correctly. Returns ======= expr : sympy expression The transformed expression. """ for pre, post in reversed(optimizations): if post is not None: expr = post(expr) return expr class FuncArgTracker: """ A class which manages a mapping from functions to arguments and an inverse mapping from arguments to functions. """ def __init__(self, funcs): # To minimize the number of symbolic comparisons, all function arguments # get assigned a value number. self.value_numbers = {} self.value_number_to_value = [] # Both of these maps use integer indices for arguments / functions. self.arg_to_funcset = [] self.func_to_argset = [] for func_i, func in enumerate(funcs): func_argset = OrderedSet() for func_arg in func.args: arg_number = self.get_or_add_value_number(func_arg) func_argset.add(arg_number) self.arg_to_funcset[arg_number].add(func_i) self.func_to_argset.append(func_argset) def get_args_in_value_order(self, argset): """ Return the list of arguments in sorted order according to their value numbers. """ return [self.value_number_to_value[argn] for argn in sorted(argset)] def get_or_add_value_number(self, value): """ Return the value number for the given argument. """ nvalues = len(self.value_numbers) value_number = self.value_numbers.setdefault(value, nvalues) if value_number == nvalues: self.value_number_to_value.append(value) self.arg_to_funcset.append(OrderedSet()) return value_number def stop_arg_tracking(self, func_i): """ Remove the function func_i from the argument to function mapping. """ for arg in self.func_to_argset[func_i]: self.arg_to_funcset[arg].remove(func_i) def get_common_arg_candidates(self, argset, min_func_i=0): """Return a dict whose keys are function numbers. The entries of the dict are the number of arguments said function has in common with ``argset``. Entries have at least 2 items in common. All keys have value at least ``min_func_i``. """ from collections import defaultdict count_map = defaultdict(lambda: 0) if not argset: return count_map funcsets = [self.arg_to_funcset[arg] for arg in argset] # As an optimization below, we handle the largest funcset separately from # the others. largest_funcset = max(funcsets, key=len) for funcset in funcsets: if largest_funcset is funcset: continue for func_i in funcset: if func_i >= min_func_i: count_map[func_i] += 1 # We pick the smaller of the two containers (count_map, largest_funcset) # to iterate over to reduce the number of iterations needed. (smaller_funcs_container, larger_funcs_container) = sorted( [largest_funcset, count_map], key=len) for func_i in smaller_funcs_container: # Not already in count_map? It can't possibly be in the output, so # skip it. if count_map[func_i] < 1: continue if func_i in larger_funcs_container: count_map[func_i] += 1 return {k: v for k, v in count_map.items() if v >= 2} def get_subset_candidates(self, argset, restrict_to_funcset=None): """ Return a set of functions each of which whose argument list contains ``argset``, optionally filtered only to contain functions in ``restrict_to_funcset``. """ iarg = iter(argset) indices = OrderedSet( fi for fi in self.arg_to_funcset[next(iarg)]) if restrict_to_funcset is not None: indices &= restrict_to_funcset for arg in iarg: indices &= self.arg_to_funcset[arg] return indices def update_func_argset(self, func_i, new_argset): """ Update a function with a new set of arguments. """ new_args = OrderedSet(new_argset) old_args = self.func_to_argset[func_i] for deleted_arg in old_args - new_args: self.arg_to_funcset[deleted_arg].remove(func_i) for added_arg in new_args - old_args: self.arg_to_funcset[added_arg].add(func_i) self.func_to_argset[func_i].clear() self.func_to_argset[func_i].update(new_args) class Unevaluated: def __init__(self, func, args): self.func = func self.args = args def __str__(self): return "Uneval<{}>({})".format( self.func, ", ".join(str(a) for a in self.args)) def as_unevaluated_basic(self): return self.func(*self.args, evaluate=False) @property def free_symbols(self): return set().union(*[a.free_symbols for a in self.args]) __repr__ = __str__ def match_common_args(func_class, funcs, opt_subs): """ Recognize and extract common subexpressions of function arguments within a set of function calls. For instance, for the following function calls:: x + z + y sin(x + y) this will extract a common subexpression of `x + y`:: w = x + y w + z sin(w) The function we work with is assumed to be associative and commutative. Parameters ========== func_class: class The function class (e.g. Add, Mul) funcs: list of functions A list of function calls. opt_subs: dict A dictionary of substitutions which this function may update. """ # Sort to ensure that whole-function subexpressions come before the items # that use them. funcs = sorted(funcs, key=lambda f: len(f.args)) arg_tracker = FuncArgTracker(funcs) changed = OrderedSet() for i in range(len(funcs)): common_arg_candidates_counts = arg_tracker.get_common_arg_candidates( arg_tracker.func_to_argset[i], min_func_i=i + 1) # Sort the candidates in order of match size. # This makes us try combining smaller matches first. common_arg_candidates = OrderedSet(sorted( common_arg_candidates_counts.keys(), key=lambda k: (common_arg_candidates_counts[k], k))) while common_arg_candidates: j = common_arg_candidates.pop(last=False) com_args = arg_tracker.func_to_argset[i].intersection( arg_tracker.func_to_argset[j]) if len(com_args) <= 1: # This may happen if a set of common arguments was already # combined in a previous iteration. continue # For all sets, replace the common symbols by the function # over them, to allow recursive matches. diff_i = arg_tracker.func_to_argset[i].difference(com_args) if diff_i: # com_func needs to be unevaluated to allow for recursive matches. com_func = Unevaluated( func_class, arg_tracker.get_args_in_value_order(com_args)) com_func_number = arg_tracker.get_or_add_value_number(com_func) arg_tracker.update_func_argset(i, diff_i | OrderedSet([com_func_number])) changed.add(i) else: # Treat the whole expression as a CSE. # # The reason this needs to be done is somewhat subtle. Within # tree_cse(), to_eliminate only contains expressions that are # seen more than once. The problem is unevaluated expressions # do not compare equal to the evaluated equivalent. So # tree_cse() won't mark funcs[i] as a CSE if we use an # unevaluated version. com_func_number = arg_tracker.get_or_add_value_number(funcs[i]) diff_j = arg_tracker.func_to_argset[j].difference(com_args) arg_tracker.update_func_argset(j, diff_j | OrderedSet([com_func_number])) changed.add(j) for k in arg_tracker.get_subset_candidates( com_args, common_arg_candidates): diff_k = arg_tracker.func_to_argset[k].difference(com_args) arg_tracker.update_func_argset(k, diff_k | OrderedSet([com_func_number])) changed.add(k) if i in changed: opt_subs[funcs[i]] = Unevaluated(func_class, arg_tracker.get_args_in_value_order(arg_tracker.func_to_argset[i])) arg_tracker.stop_arg_tracking(i) def opt_cse(exprs, order='canonical'): """Find optimization opportunities in Adds, Muls, Pows and negative coefficient Muls. Parameters ========== exprs : list of sympy expressions The expressions to optimize. order : string, 'none' or 'canonical' The order by which Mul and Add arguments are processed. For large expressions where speed is a concern, use the setting order='none'. Returns ======= opt_subs : dictionary of expression substitutions The expression substitutions which can be useful to optimize CSE. Examples ======== >>> from sympy.simplify.cse_main import opt_cse >>> from sympy.abc import x >>> opt_subs = opt_cse([x**-2]) >>> k, v = list(opt_subs.keys())[0], list(opt_subs.values())[0] >>> print((k, v.as_unevaluated_basic())) (x**(-2), 1/(x**2)) """ from sympy.matrices.expressions import MatAdd, MatMul, MatPow opt_subs = dict() adds = OrderedSet() muls = OrderedSet() seen_subexp = set() def _find_opts(expr): if not isinstance(expr, (Basic, Unevaluated)): return if expr.is_Atom or expr.is_Order: return if iterable(expr): list(map(_find_opts, expr)) return if expr in seen_subexp: return expr seen_subexp.add(expr) list(map(_find_opts, expr.args)) if _coeff_isneg(expr): neg_expr = -expr if not neg_expr.is_Atom: opt_subs[expr] = Unevaluated(Mul, (S.NegativeOne, neg_expr)) seen_subexp.add(neg_expr) expr = neg_expr if isinstance(expr, (Mul, MatMul)): muls.add(expr) elif isinstance(expr, (Add, MatAdd)): adds.add(expr) elif isinstance(expr, (Pow, MatPow)): base, exp = expr.base, expr.exp if _coeff_isneg(exp): opt_subs[expr] = Unevaluated(Pow, (Pow(base, -exp), -1)) for e in exprs: if isinstance(e, (Basic, Unevaluated)): _find_opts(e) # split muls into commutative commutative_muls = OrderedSet() for m in muls: c, nc = m.args_cnc(cset=False) if c: c_mul = m.func(*c) if nc: if c_mul == 1: new_obj = m.func(*nc) else: new_obj = m.func(c_mul, m.func(*nc), evaluate=False) opt_subs[m] = new_obj if len(c) > 1: commutative_muls.add(c_mul) match_common_args(Add, adds, opt_subs) match_common_args(Mul, commutative_muls, opt_subs) return opt_subs def tree_cse(exprs, symbols, opt_subs=None, order='canonical', ignore=()): """Perform raw CSE on expression tree, taking opt_subs into account. Parameters ========== exprs : list of sympy expressions The expressions to reduce. symbols : infinite iterator yielding unique Symbols The symbols used to label the common subexpressions which are pulled out. opt_subs : dictionary of expression substitutions The expressions to be substituted before any CSE action is performed. order : string, 'none' or 'canonical' The order by which Mul and Add arguments are processed. For large expressions where speed is a concern, use the setting order='none'. ignore : iterable of Symbols Substitutions containing any Symbol from ``ignore`` will be ignored. """ from sympy.matrices.expressions import MatrixExpr, MatrixSymbol, MatMul, MatAdd from sympy.polys.rootoftools import RootOf if opt_subs is None: opt_subs = dict() ## Find repeated sub-expressions to_eliminate = set() seen_subexp = set() excluded_symbols = set() def _find_repeated(expr): if not isinstance(expr, (Basic, Unevaluated)): return if isinstance(expr, RootOf): return if isinstance(expr, Basic) and (expr.is_Atom or expr.is_Order): if expr.is_Symbol: excluded_symbols.add(expr) return if iterable(expr): args = expr else: if expr in seen_subexp: for ign in ignore: if ign in expr.free_symbols: break else: to_eliminate.add(expr) return seen_subexp.add(expr) if expr in opt_subs: expr = opt_subs[expr] args = expr.args list(map(_find_repeated, args)) for e in exprs: if isinstance(e, Basic): _find_repeated(e) ## Rebuild tree # Remove symbols from the generator that conflict with names in the expressions. symbols = (symbol for symbol in symbols if symbol not in excluded_symbols) replacements = [] subs = dict() def _rebuild(expr): if not isinstance(expr, (Basic, Unevaluated)): return expr if not expr.args: return expr if iterable(expr): new_args = [_rebuild(arg) for arg in expr] return expr.func(*new_args) if expr in subs: return subs[expr] orig_expr = expr if expr in opt_subs: expr = opt_subs[expr] # If enabled, parse Muls and Adds arguments by order to ensure # replacement order independent from hashes if order != 'none': if isinstance(expr, (Mul, MatMul)): c, nc = expr.args_cnc() if c == [1]: args = nc else: args = list(ordered(c)) + nc elif isinstance(expr, (Add, MatAdd)): args = list(ordered(expr.args)) else: args = expr.args else: args = expr.args new_args = list(map(_rebuild, args)) if isinstance(expr, Unevaluated) or new_args != args: new_expr = expr.func(*new_args) else: new_expr = expr if orig_expr in to_eliminate: try: sym = next(symbols) except StopIteration: raise ValueError("Symbols iterator ran out of symbols.") if isinstance(orig_expr, MatrixExpr): sym = MatrixSymbol(sym.name, orig_expr.rows, orig_expr.cols) subs[orig_expr] = sym replacements.append((sym, new_expr)) return sym else: return new_expr reduced_exprs = [] for e in exprs: if isinstance(e, Basic): reduced_e = _rebuild(e) else: reduced_e = e reduced_exprs.append(reduced_e) return replacements, reduced_exprs def cse(exprs, symbols=None, optimizations=None, postprocess=None, order='canonical', ignore=(), list=True): """ Perform common subexpression elimination on an expression. Parameters ========== exprs : list of sympy expressions, or a single sympy expression The expressions to reduce. symbols : infinite iterator yielding unique Symbols The symbols used to label the common subexpressions which are pulled out. The ``numbered_symbols`` generator is useful. The default is a stream of symbols of the form "x0", "x1", etc. This must be an infinite iterator. optimizations : list of (callable, callable) pairs The (preprocessor, postprocessor) pairs of external optimization functions. Optionally 'basic' can be passed for a set of predefined basic optimizations. Such 'basic' optimizations were used by default in old implementation, however they can be really slow on larger expressions. Now, no pre or post optimizations are made by default. postprocess : a function which accepts the two return values of cse and returns the desired form of output from cse, e.g. if you want the replacements reversed the function might be the following lambda: lambda r, e: return reversed(r), e order : string, 'none' or 'canonical' The order by which Mul and Add arguments are processed. If set to 'canonical', arguments will be canonically ordered. If set to 'none', ordering will be faster but dependent on expressions hashes, thus machine dependent and variable. For large expressions where speed is a concern, use the setting order='none'. ignore : iterable of Symbols Substitutions containing any Symbol from ``ignore`` will be ignored. list : bool, (default True) Returns expression in list or else with same type as input (when False). Returns ======= replacements : list of (Symbol, expression) pairs All of the common subexpressions that were replaced. Subexpressions earlier in this list might show up in subexpressions later in this list. reduced_exprs : list of sympy expressions The reduced expressions with all of the replacements above. Examples ======== >>> from sympy import cse, SparseMatrix >>> from sympy.abc import x, y, z, w >>> cse(((w + x + y + z)*(w + y + z))/(w + x)**3) ([(x0, y + z), (x1, w + x)], [(w + x0)*(x0 + x1)/x1**3]) Note that currently, y + z will not get substituted if -y - z is used. >>> cse(((w + x + y + z)*(w - y - z))/(w + x)**3) ([(x0, w + x)], [(w - y - z)*(x0 + y + z)/x0**3]) List of expressions with recursive substitutions: >>> m = SparseMatrix([x + y, x + y + z]) >>> cse([(x+y)**2, x + y + z, y + z, x + z + y, m]) ([(x0, x + y), (x1, x0 + z)], [x0**2, x1, y + z, x1, Matrix([ [x0], [x1]])]) Note: the type and mutability of input matrices is retained. >>> isinstance(_[1][-1], SparseMatrix) True The user may disallow substitutions containing certain symbols: >>> cse([y**2*(x + 1), 3*y**2*(x + 1)], ignore=(y,)) ([(x0, x + 1)], [x0*y**2, 3*x0*y**2]) The default return value for the reduced expression(s) is a list, even if there is only one expression. The `list` flag preserves the type of the input in the output: >>> cse(x) ([], [x]) >>> cse(x, list=False) ([], x) """ from sympy.matrices import (MatrixBase, Matrix, ImmutableMatrix, SparseMatrix, ImmutableSparseMatrix) if not list: return _cse_homogeneous(exprs, symbols=symbols, optimizations=optimizations, postprocess=postprocess, order=order, ignore=ignore) if isinstance(exprs, (int, float)): exprs = sympify(exprs) # Handle the case if just one expression was passed. if isinstance(exprs, (Basic, MatrixBase)): exprs = [exprs] copy = exprs temp = [] for e in exprs: if isinstance(e, (Matrix, ImmutableMatrix)): temp.append(Tuple(*e.flat())) elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)): temp.append(Tuple(*e.todok().items())) else: temp.append(e) exprs = temp del temp if optimizations is None: optimizations = [] elif optimizations == 'basic': optimizations = basic_optimizations # Preprocess the expressions to give us better optimization opportunities. reduced_exprs = [preprocess_for_cse(e, optimizations) for e in exprs] if symbols is None: symbols = numbered_symbols(cls=Symbol) else: # In case we get passed an iterable with an __iter__ method instead of # an actual iterator. symbols = iter(symbols) # Find other optimization opportunities. opt_subs = opt_cse(reduced_exprs, order) # Main CSE algorithm. replacements, reduced_exprs = tree_cse(reduced_exprs, symbols, opt_subs, order, ignore) # Postprocess the expressions to return the expressions to canonical form. exprs = copy for i, (sym, subtree) in enumerate(replacements): subtree = postprocess_for_cse(subtree, optimizations) replacements[i] = (sym, subtree) reduced_exprs = [postprocess_for_cse(e, optimizations) for e in reduced_exprs] # Get the matrices back for i, e in enumerate(exprs): if isinstance(e, (Matrix, ImmutableMatrix)): reduced_exprs[i] = Matrix(e.rows, e.cols, reduced_exprs[i]) if isinstance(e, ImmutableMatrix): reduced_exprs[i] = reduced_exprs[i].as_immutable() elif isinstance(e, (SparseMatrix, ImmutableSparseMatrix)): m = SparseMatrix(e.rows, e.cols, {}) for k, v in reduced_exprs[i]: m[k] = v if isinstance(e, ImmutableSparseMatrix): m = m.as_immutable() reduced_exprs[i] = m if postprocess is None: return replacements, reduced_exprs return postprocess(replacements, reduced_exprs) def _cse_homogeneous(exprs, **kwargs): """ Same as ``cse`` but the ``reduced_exprs`` are returned with the same type as ``exprs`` or a sympified version of the same. Parameters ========== exprs : an Expr, iterable of Expr or dictionary with Expr values the expressions in which repeated subexpressions will be identified kwargs : additional arguments for the ``cse`` function Returns ======= replacements : list of (Symbol, expression) pairs All of the common subexpressions that were replaced. Subexpressions earlier in this list might show up in subexpressions later in this list. reduced_exprs : list of sympy expressions The reduced expressions with all of the replacements above. Examples ======== >>> from sympy.simplify.cse_main import cse >>> from sympy import cos, Tuple, Matrix >>> from sympy.abc import x >>> output = lambda x: type(cse(x, list=False)[1]) >>> output(1) >>> output('cos(x)') >>> output(cos(x)) cos >>> output(Tuple(1, x)) >>> output(Matrix([[1,0], [0,1]])) >>> output([1, x]) >>> output((1, x)) >>> output({1, x}) """ if isinstance(exprs, str): from sympy import sympify replacements, reduced_exprs = _cse_homogeneous( sympify(exprs), **kwargs) return replacements, repr(reduced_exprs) if isinstance(exprs, (list, tuple, set)): replacements, reduced_exprs = cse(exprs, **kwargs) return replacements, type(exprs)(reduced_exprs) if isinstance(exprs, dict): keys = list(exprs.keys()) # In order to guarantee the order of the elements. replacements, values = cse([exprs[k] for k in keys], **kwargs) reduced_exprs = dict(zip(keys, values)) return replacements, reduced_exprs try: replacements, (reduced_exprs,) = cse(exprs, **kwargs) except TypeError: # For example 'mpf' objects return [], exprs else: return replacements, reduced_exprs sympy-sympy-1.9/sympy/simplify/cse_opts.py000066400000000000000000000031251412543434000211320ustar00rootroot00000000000000""" Optimizations of the expression tree representation for better CSE opportunities. """ from sympy.core import Add, Basic, Mul from sympy.core.basic import preorder_traversal from sympy.core.singleton import S from sympy.utilities.iterables import default_sort_key def sub_pre(e): """ Replace y - x with -(x - y) if -1 can be extracted from y - x. """ # replacing Add, A, from which -1 can be extracted with -1*-A adds = [a for a in e.atoms(Add) if a.could_extract_minus_sign()] reps = {} ignore = set() for a in adds: na = -a if na.is_Mul: # e.g. MatExpr ignore.add(a) continue reps[a] = Mul._from_args([S.NegativeOne, na]) e = e.xreplace(reps) # repeat again for persisting Adds but mark these with a leading 1, -1 # e.g. y - x -> 1*-1*(x - y) if isinstance(e, Basic): negs = {} for a in sorted(e.atoms(Add), key=default_sort_key): if a in ignore: continue if a in reps: negs[a] = reps[a] elif a.could_extract_minus_sign(): negs[a] = Mul._from_args([S.One, S.NegativeOne, -a]) e = e.xreplace(negs) return e def sub_post(e): """ Replace 1*-1*x with -x. """ replacements = [] for node in preorder_traversal(e): if isinstance(node, Mul) and \ node.args[0] is S.One and node.args[1] is S.NegativeOne: replacements.append((node, -Mul._from_args(node.args[2:]))) for node, replacement in replacements: e = e.xreplace({node: replacement}) return e sympy-sympy-1.9/sympy/simplify/epathtools.py000066400000000000000000000237011412543434000214770ustar00rootroot00000000000000"""Tools for manipulation of expressions using paths. """ from sympy.core import Basic class EPath: r""" Manipulate expressions using paths. EPath grammar in EBNF notation:: literal ::= /[A-Za-z_][A-Za-z_0-9]*/ number ::= /-?\d+/ type ::= literal attribute ::= literal "?" all ::= "*" slice ::= "[" number? (":" number? (":" number?)?)? "]" range ::= all | slice query ::= (type | attribute) ("|" (type | attribute))* selector ::= range | query range? path ::= "/" selector ("/" selector)* See the docstring of the epath() function. """ __slots__ = ("_path", "_epath") def __new__(cls, path): """Construct new EPath. """ if isinstance(path, EPath): return path if not path: raise ValueError("empty EPath") _path = path if path[0] == '/': path = path[1:] else: raise NotImplementedError("non-root EPath") epath = [] for selector in path.split('/'): selector = selector.strip() if not selector: raise ValueError("empty selector") index = 0 for c in selector: if c.isalnum() or c == '_' or c == '|' or c == '?': index += 1 else: break attrs = [] types = [] if index: elements = selector[:index] selector = selector[index:] for element in elements.split('|'): element = element.strip() if not element: raise ValueError("empty element") if element.endswith('?'): attrs.append(element[:-1]) else: types.append(element) span = None if selector == '*': pass else: if selector.startswith('['): try: i = selector.index(']') except ValueError: raise ValueError("expected ']', got EOL") _span, span = selector[1:i], [] if ':' not in _span: span = int(_span) else: for elt in _span.split(':', 3): if not elt: span.append(None) else: span.append(int(elt)) span = slice(*span) selector = selector[i + 1:] if selector: raise ValueError("trailing characters in selector") epath.append((attrs, types, span)) obj = object.__new__(cls) obj._path = _path obj._epath = epath return obj def __repr__(self): return "%s(%r)" % (self.__class__.__name__, self._path) def _get_ordered_args(self, expr): """Sort ``expr.args`` using printing order. """ if expr.is_Add: return expr.as_ordered_terms() elif expr.is_Mul: return expr.as_ordered_factors() else: return expr.args def _hasattrs(self, expr, attrs): """Check if ``expr`` has any of ``attrs``. """ for attr in attrs: if not hasattr(expr, attr): return False return True def _hastypes(self, expr, types): """Check if ``expr`` is any of ``types``. """ _types = [ cls.__name__ for cls in expr.__class__.mro() ] return bool(set(_types).intersection(types)) def _has(self, expr, attrs, types): """Apply ``_hasattrs`` and ``_hastypes`` to ``expr``. """ if not (attrs or types): return True if attrs and self._hasattrs(expr, attrs): return True if types and self._hastypes(expr, types): return True return False def apply(self, expr, func, args=None, kwargs=None): """ Modify parts of an expression selected by a path. Examples ======== >>> from sympy.simplify.epathtools import EPath >>> from sympy import sin, cos, E >>> from sympy.abc import x, y, z, t >>> path = EPath("/*/[0]/Symbol") >>> expr = [((x, 1), 2), ((3, y), z)] >>> path.apply(expr, lambda expr: expr**2) [((x**2, 1), 2), ((3, y**2), z)] >>> path = EPath("/*/*/Symbol") >>> expr = t + sin(x + 1) + cos(x + y + E) >>> path.apply(expr, lambda expr: 2*expr) t + sin(2*x + 1) + cos(2*x + 2*y + E) """ def _apply(path, expr, func): if not path: return func(expr) else: selector, path = path[0], path[1:] attrs, types, span = selector if isinstance(expr, Basic): if not expr.is_Atom: args, basic = self._get_ordered_args(expr), True else: return expr elif hasattr(expr, '__iter__'): args, basic = expr, False else: return expr args = list(args) if span is not None: if type(span) == slice: indices = range(*span.indices(len(args))) else: indices = [span] else: indices = range(len(args)) for i in indices: try: arg = args[i] except IndexError: continue if self._has(arg, attrs, types): args[i] = _apply(path, arg, func) if basic: return expr.func(*args) else: return expr.__class__(args) _args, _kwargs = args or (), kwargs or {} _func = lambda expr: func(expr, *_args, **_kwargs) return _apply(self._epath, expr, _func) def select(self, expr): """ Retrieve parts of an expression selected by a path. Examples ======== >>> from sympy.simplify.epathtools import EPath >>> from sympy import sin, cos, E >>> from sympy.abc import x, y, z, t >>> path = EPath("/*/[0]/Symbol") >>> expr = [((x, 1), 2), ((3, y), z)] >>> path.select(expr) [x, y] >>> path = EPath("/*/*/Symbol") >>> expr = t + sin(x + 1) + cos(x + y + E) >>> path.select(expr) [x, x, y] """ result = [] def _select(path, expr): if not path: result.append(expr) else: selector, path = path[0], path[1:] attrs, types, span = selector if isinstance(expr, Basic): args = self._get_ordered_args(expr) elif hasattr(expr, '__iter__'): args = expr else: return if span is not None: if type(span) == slice: args = args[span] else: try: args = [args[span]] except IndexError: return for arg in args: if self._has(arg, attrs, types): _select(path, arg) _select(self._epath, expr) return result def epath(path, expr=None, func=None, args=None, kwargs=None): r""" Manipulate parts of an expression selected by a path. Explanation =========== This function allows to manipulate large nested expressions in single line of code, utilizing techniques to those applied in XML processing standards (e.g. XPath). If ``func`` is ``None``, :func:`epath` retrieves elements selected by the ``path``. Otherwise it applies ``func`` to each matching element. Note that it is more efficient to create an EPath object and use the select and apply methods of that object, since this will compile the path string only once. This function should only be used as a convenient shortcut for interactive use. This is the supported syntax: * select all: ``/*`` Equivalent of ``for arg in args:``. * select slice: ``/[0]`` or ``/[1:5]`` or ``/[1:5:2]`` Supports standard Python's slice syntax. * select by type: ``/list`` or ``/list|tuple`` Emulates ``isinstance()``. * select by attribute: ``/__iter__?`` Emulates ``hasattr()``. Parameters ========== path : str | EPath A path as a string or a compiled EPath. expr : Basic | iterable An expression or a container of expressions. func : callable (optional) A callable that will be applied to matching parts. args : tuple (optional) Additional positional arguments to ``func``. kwargs : dict (optional) Additional keyword arguments to ``func``. Examples ======== >>> from sympy.simplify.epathtools import epath >>> from sympy import sin, cos, E >>> from sympy.abc import x, y, z, t >>> path = "/*/[0]/Symbol" >>> expr = [((x, 1), 2), ((3, y), z)] >>> epath(path, expr) [x, y] >>> epath(path, expr, lambda expr: expr**2) [((x**2, 1), 2), ((3, y**2), z)] >>> path = "/*/*/Symbol" >>> expr = t + sin(x + 1) + cos(x + y + E) >>> epath(path, expr) [x, x, y] >>> epath(path, expr, lambda expr: 2*expr) t + sin(2*x + 1) + cos(2*x + 2*y + E) """ _epath = EPath(path) if expr is None: return _epath if func is None: return _epath.select(expr) else: return _epath.apply(expr, func, args, kwargs) sympy-sympy-1.9/sympy/simplify/fu.py000066400000000000000000001706251412543434000177370ustar00rootroot00000000000000from collections import defaultdict from sympy.core.add import Add from sympy.core.basic import S from sympy.core.compatibility import ordered from sympy.core.expr import Expr from sympy.core.exprtools import Factors, gcd_terms, factor_terms from sympy.core.function import expand_mul from sympy.core.mul import Mul from sympy.core.numbers import pi, I from sympy.core.power import Pow from sympy.core.symbol import Dummy from sympy.core.sympify import sympify from sympy.functions.combinatorial.factorials import binomial from sympy.functions.elementary.hyperbolic import ( cosh, sinh, tanh, coth, sech, csch, HyperbolicFunction) from sympy.functions.elementary.trigonometric import ( cos, sin, tan, cot, sec, csc, sqrt, TrigonometricFunction) from sympy.ntheory.factor_ import perfect_power from sympy.polys.polytools import factor from sympy.simplify.simplify import bottom_up from sympy.strategies.tree import greedy from sympy.strategies.core import identity, debug from sympy import SYMPY_DEBUG # ================== Fu-like tools =========================== def TR0(rv): """Simplification of rational polynomials, trying to simplify the expression, e.g. combine things like 3*x + 2*x, etc.... """ # although it would be nice to use cancel, it doesn't work # with noncommutatives return rv.normal().factor().expand() def TR1(rv): """Replace sec, csc with 1/cos, 1/sin Examples ======== >>> from sympy.simplify.fu import TR1, sec, csc >>> from sympy.abc import x >>> TR1(2*csc(x) + sec(x)) 1/cos(x) + 2/sin(x) """ def f(rv): if isinstance(rv, sec): a = rv.args[0] return S.One/cos(a) elif isinstance(rv, csc): a = rv.args[0] return S.One/sin(a) return rv return bottom_up(rv, f) def TR2(rv): """Replace tan and cot with sin/cos and cos/sin Examples ======== >>> from sympy.simplify.fu import TR2 >>> from sympy.abc import x >>> from sympy import tan, cot, sin, cos >>> TR2(tan(x)) sin(x)/cos(x) >>> TR2(cot(x)) cos(x)/sin(x) >>> TR2(tan(tan(x) - sin(x)/cos(x))) 0 """ def f(rv): if isinstance(rv, tan): a = rv.args[0] return sin(a)/cos(a) elif isinstance(rv, cot): a = rv.args[0] return cos(a)/sin(a) return rv return bottom_up(rv, f) def TR2i(rv, half=False): """Converts ratios involving sin and cos as follows:: sin(x)/cos(x) -> tan(x) sin(x)/(cos(x) + 1) -> tan(x/2) if half=True Examples ======== >>> from sympy.simplify.fu import TR2i >>> from sympy.abc import x, a >>> from sympy import sin, cos >>> TR2i(sin(x)/cos(x)) tan(x) Powers of the numerator and denominator are also recognized >>> TR2i(sin(x)**2/(cos(x) + 1)**2, half=True) tan(x/2)**2 The transformation does not take place unless assumptions allow (i.e. the base must be positive or the exponent must be an integer for both numerator and denominator) >>> TR2i(sin(x)**a/(cos(x) + 1)**a) sin(x)**a/(cos(x) + 1)**a """ def f(rv): if not rv.is_Mul: return rv n, d = rv.as_numer_denom() if n.is_Atom or d.is_Atom: return rv def ok(k, e): # initial filtering of factors return ( (e.is_integer or k.is_positive) and ( k.func in (sin, cos) or (half and k.is_Add and len(k.args) >= 2 and any(any(isinstance(ai, cos) or ai.is_Pow and ai.base is cos for ai in Mul.make_args(a)) for a in k.args)))) n = n.as_powers_dict() ndone = [(k, n.pop(k)) for k in list(n.keys()) if not ok(k, n[k])] if not n: return rv d = d.as_powers_dict() ddone = [(k, d.pop(k)) for k in list(d.keys()) if not ok(k, d[k])] if not d: return rv # factoring if necessary def factorize(d, ddone): newk = [] for k in d: if k.is_Add and len(k.args) > 1: knew = factor(k) if half else factor_terms(k) if knew != k: newk.append((k, knew)) if newk: for i, (k, knew) in enumerate(newk): del d[k] newk[i] = knew newk = Mul(*newk).as_powers_dict() for k in newk: v = d[k] + newk[k] if ok(k, v): d[k] = v else: ddone.append((k, v)) del newk factorize(n, ndone) factorize(d, ddone) # joining t = [] for k in n: if isinstance(k, sin): a = cos(k.args[0], evaluate=False) if a in d and d[a] == n[k]: t.append(tan(k.args[0])**n[k]) n[k] = d[a] = None elif half: a1 = 1 + a if a1 in d and d[a1] == n[k]: t.append((tan(k.args[0]/2))**n[k]) n[k] = d[a1] = None elif isinstance(k, cos): a = sin(k.args[0], evaluate=False) if a in d and d[a] == n[k]: t.append(tan(k.args[0])**-n[k]) n[k] = d[a] = None elif half and k.is_Add and k.args[0] is S.One and \ isinstance(k.args[1], cos): a = sin(k.args[1].args[0], evaluate=False) if a in d and d[a] == n[k] and (d[a].is_integer or \ a.is_positive): t.append(tan(a.args[0]/2)**-n[k]) n[k] = d[a] = None if t: rv = Mul(*(t + [b**e for b, e in n.items() if e]))/\ Mul(*[b**e for b, e in d.items() if e]) rv *= Mul(*[b**e for b, e in ndone])/Mul(*[b**e for b, e in ddone]) return rv return bottom_up(rv, f) def TR3(rv): """Induced formula: example sin(-a) = -sin(a) Examples ======== >>> from sympy.simplify.fu import TR3 >>> from sympy.abc import x, y >>> from sympy import pi >>> from sympy import cos >>> TR3(cos(y - x*(y - x))) cos(x*(x - y) + y) >>> cos(pi/2 + x) -sin(x) >>> cos(30*pi/2 + x) -cos(x) """ from sympy.simplify.simplify import signsimp # Negative argument (already automatic for funcs like sin(-x) -> -sin(x) # but more complicated expressions can use it, too). Also, trig angles # between pi/4 and pi/2 are not reduced to an angle between 0 and pi/4. # The following are automatically handled: # Argument of type: pi/2 +/- angle # Argument of type: pi +/- angle # Argument of type : 2k*pi +/- angle def f(rv): if not isinstance(rv, TrigonometricFunction): return rv rv = rv.func(signsimp(rv.args[0])) if not isinstance(rv, TrigonometricFunction): return rv if (rv.args[0] - S.Pi/4).is_positive is (S.Pi/2 - rv.args[0]).is_positive is True: fmap = {cos: sin, sin: cos, tan: cot, cot: tan, sec: csc, csc: sec} rv = fmap[rv.func](S.Pi/2 - rv.args[0]) return rv return bottom_up(rv, f) def TR4(rv): """Identify values of special angles. a= 0 pi/6 pi/4 pi/3 pi/2 ---------------------------------------------------- sin(a) 0 1/2 sqrt(2)/2 sqrt(3)/2 1 cos(a) 1 sqrt(3)/2 sqrt(2)/2 1/2 0 tan(a) 0 sqt(3)/3 1 sqrt(3) -- Examples ======== >>> from sympy import pi >>> from sympy import cos, sin, tan, cot >>> for s in (0, pi/6, pi/4, pi/3, pi/2): ... print('%s %s %s %s' % (cos(s), sin(s), tan(s), cot(s))) ... 1 0 0 zoo sqrt(3)/2 1/2 sqrt(3)/3 sqrt(3) sqrt(2)/2 sqrt(2)/2 1 1 1/2 sqrt(3)/2 sqrt(3) sqrt(3)/3 0 1 zoo 0 """ # special values at 0, pi/6, pi/4, pi/3, pi/2 already handled return rv def _TR56(rv, f, g, h, max, pow): """Helper for TR5 and TR6 to replace f**2 with h(g**2) Options ======= max : controls size of exponent that can appear on f e.g. if max=4 then f**4 will be changed to h(g**2)**2. pow : controls whether the exponent must be a perfect power of 2 e.g. if pow=True (and max >= 6) then f**6 will not be changed but f**8 will be changed to h(g**2)**4 >>> from sympy.simplify.fu import _TR56 as T >>> from sympy.abc import x >>> from sympy import sin, cos >>> h = lambda x: 1 - x >>> T(sin(x)**3, sin, cos, h, 4, False) (1 - cos(x)**2)*sin(x) >>> T(sin(x)**6, sin, cos, h, 6, False) (1 - cos(x)**2)**3 >>> T(sin(x)**6, sin, cos, h, 6, True) sin(x)**6 >>> T(sin(x)**8, sin, cos, h, 10, True) (1 - cos(x)**2)**4 """ def _f(rv): # I'm not sure if this transformation should target all even powers # or only those expressible as powers of 2. Also, should it only # make the changes in powers that appear in sums -- making an isolated # change is not going to allow a simplification as far as I can tell. if not (rv.is_Pow and rv.base.func == f): return rv if not rv.exp.is_real: return rv if (rv.exp < 0) == True: return rv if (rv.exp > max) == True: return rv if rv.exp == 1: return rv if rv.exp == 2: return h(g(rv.base.args[0])**2) else: if rv.exp % 2 == 1: e = rv.exp//2 return f(rv.base.args[0])*h(g(rv.base.args[0])**2)**e elif rv.exp == 4: e = 2 elif not pow: if rv.exp % 2: return rv e = rv.exp//2 else: p = perfect_power(rv.exp) if not p: return rv e = rv.exp//2 return h(g(rv.base.args[0])**2)**e return bottom_up(rv, _f) def TR5(rv, max=4, pow=False): """Replacement of sin**2 with 1 - cos(x)**2. See _TR56 docstring for advanced use of ``max`` and ``pow``. Examples ======== >>> from sympy.simplify.fu import TR5 >>> from sympy.abc import x >>> from sympy import sin >>> TR5(sin(x)**2) 1 - cos(x)**2 >>> TR5(sin(x)**-2) # unchanged sin(x)**(-2) >>> TR5(sin(x)**4) (1 - cos(x)**2)**2 """ return _TR56(rv, sin, cos, lambda x: 1 - x, max=max, pow=pow) def TR6(rv, max=4, pow=False): """Replacement of cos**2 with 1 - sin(x)**2. See _TR56 docstring for advanced use of ``max`` and ``pow``. Examples ======== >>> from sympy.simplify.fu import TR6 >>> from sympy.abc import x >>> from sympy import cos >>> TR6(cos(x)**2) 1 - sin(x)**2 >>> TR6(cos(x)**-2) #unchanged cos(x)**(-2) >>> TR6(cos(x)**4) (1 - sin(x)**2)**2 """ return _TR56(rv, cos, sin, lambda x: 1 - x, max=max, pow=pow) def TR7(rv): """Lowering the degree of cos(x)**2. Examples ======== >>> from sympy.simplify.fu import TR7 >>> from sympy.abc import x >>> from sympy import cos >>> TR7(cos(x)**2) cos(2*x)/2 + 1/2 >>> TR7(cos(x)**2 + 1) cos(2*x)/2 + 3/2 """ def f(rv): if not (rv.is_Pow and rv.base.func == cos and rv.exp == 2): return rv return (1 + cos(2*rv.base.args[0]))/2 return bottom_up(rv, f) def TR8(rv, first=True): """Converting products of ``cos`` and/or ``sin`` to a sum or difference of ``cos`` and or ``sin`` terms. Examples ======== >>> from sympy.simplify.fu import TR8 >>> from sympy import cos, sin >>> TR8(cos(2)*cos(3)) cos(5)/2 + cos(1)/2 >>> TR8(cos(2)*sin(3)) sin(5)/2 + sin(1)/2 >>> TR8(sin(2)*sin(3)) -cos(5)/2 + cos(1)/2 """ def f(rv): if not ( rv.is_Mul or rv.is_Pow and rv.base.func in (cos, sin) and (rv.exp.is_integer or rv.base.is_positive)): return rv if first: n, d = [expand_mul(i) for i in rv.as_numer_denom()] newn = TR8(n, first=False) newd = TR8(d, first=False) if newn != n or newd != d: rv = gcd_terms(newn/newd) if rv.is_Mul and rv.args[0].is_Rational and \ len(rv.args) == 2 and rv.args[1].is_Add: rv = Mul(*rv.as_coeff_Mul()) return rv args = {cos: [], sin: [], None: []} for a in ordered(Mul.make_args(rv)): if a.func in (cos, sin): args[a.func].append(a.args[0]) elif (a.is_Pow and a.exp.is_Integer and a.exp > 0 and \ a.base.func in (cos, sin)): # XXX this is ok but pathological expression could be handled # more efficiently as in TRmorrie args[a.base.func].extend([a.base.args[0]]*a.exp) else: args[None].append(a) c = args[cos] s = args[sin] if not (c and s or len(c) > 1 or len(s) > 1): return rv args = args[None] n = min(len(c), len(s)) for i in range(n): a1 = s.pop() a2 = c.pop() args.append((sin(a1 + a2) + sin(a1 - a2))/2) while len(c) > 1: a1 = c.pop() a2 = c.pop() args.append((cos(a1 + a2) + cos(a1 - a2))/2) if c: args.append(cos(c.pop())) while len(s) > 1: a1 = s.pop() a2 = s.pop() args.append((-cos(a1 + a2) + cos(a1 - a2))/2) if s: args.append(sin(s.pop())) return TR8(expand_mul(Mul(*args))) return bottom_up(rv, f) def TR9(rv): """Sum of ``cos`` or ``sin`` terms as a product of ``cos`` or ``sin``. Examples ======== >>> from sympy.simplify.fu import TR9 >>> from sympy import cos, sin >>> TR9(cos(1) + cos(2)) 2*cos(1/2)*cos(3/2) >>> TR9(cos(1) + 2*sin(1) + 2*sin(2)) cos(1) + 4*sin(3/2)*cos(1/2) If no change is made by TR9, no re-arrangement of the expression will be made. For example, though factoring of common term is attempted, if the factored expression wasn't changed, the original expression will be returned: >>> TR9(cos(3) + cos(3)*cos(2)) cos(3) + cos(2)*cos(3) """ def f(rv): if not rv.is_Add: return rv def do(rv, first=True): # cos(a)+/-cos(b) can be combined into a product of cosines and # sin(a)+/-sin(b) can be combined into a product of cosine and # sine. # # If there are more than two args, the pairs which "work" will # have a gcd extractable and the remaining two terms will have # the above structure -- all pairs must be checked to find the # ones that work. args that don't have a common set of symbols # are skipped since this doesn't lead to a simpler formula and # also has the arbitrariness of combining, for example, the x # and y term instead of the y and z term in something like # cos(x) + cos(y) + cos(z). if not rv.is_Add: return rv args = list(ordered(rv.args)) if len(args) != 2: hit = False for i in range(len(args)): ai = args[i] if ai is None: continue for j in range(i + 1, len(args)): aj = args[j] if aj is None: continue was = ai + aj new = do(was) if new != was: args[i] = new # update in place args[j] = None hit = True break # go to next i if hit: rv = Add(*[_f for _f in args if _f]) if rv.is_Add: rv = do(rv) return rv # two-arg Add split = trig_split(*args) if not split: return rv gcd, n1, n2, a, b, iscos = split # application of rule if possible if iscos: if n1 == n2: return gcd*n1*2*cos((a + b)/2)*cos((a - b)/2) if n1 < 0: a, b = b, a return -2*gcd*sin((a + b)/2)*sin((a - b)/2) else: if n1 == n2: return gcd*n1*2*sin((a + b)/2)*cos((a - b)/2) if n1 < 0: a, b = b, a return 2*gcd*cos((a + b)/2)*sin((a - b)/2) return process_common_addends(rv, do) # DON'T sift by free symbols return bottom_up(rv, f) def TR10(rv, first=True): """Separate sums in ``cos`` and ``sin``. Examples ======== >>> from sympy.simplify.fu import TR10 >>> from sympy.abc import a, b, c >>> from sympy import cos, sin >>> TR10(cos(a + b)) -sin(a)*sin(b) + cos(a)*cos(b) >>> TR10(sin(a + b)) sin(a)*cos(b) + sin(b)*cos(a) >>> TR10(sin(a + b + c)) (-sin(a)*sin(b) + cos(a)*cos(b))*sin(c) + \ (sin(a)*cos(b) + sin(b)*cos(a))*cos(c) """ def f(rv): if not rv.func in (cos, sin): return rv f = rv.func arg = rv.args[0] if arg.is_Add: if first: args = list(ordered(arg.args)) else: args = list(arg.args) a = args.pop() b = Add._from_args(args) if b.is_Add: if f == sin: return sin(a)*TR10(cos(b), first=False) + \ cos(a)*TR10(sin(b), first=False) else: return cos(a)*TR10(cos(b), first=False) - \ sin(a)*TR10(sin(b), first=False) else: if f == sin: return sin(a)*cos(b) + cos(a)*sin(b) else: return cos(a)*cos(b) - sin(a)*sin(b) return rv return bottom_up(rv, f) def TR10i(rv): """Sum of products to function of sum. Examples ======== >>> from sympy.simplify.fu import TR10i >>> from sympy import cos, sin, sqrt >>> from sympy.abc import x >>> TR10i(cos(1)*cos(3) + sin(1)*sin(3)) cos(2) >>> TR10i(cos(1)*sin(3) + sin(1)*cos(3) + cos(3)) cos(3) + sin(4) >>> TR10i(sqrt(2)*cos(x)*x + sqrt(6)*sin(x)*x) 2*sqrt(2)*x*sin(x + pi/6) """ global _ROOT2, _ROOT3, _invROOT3 if _ROOT2 is None: _roots() def f(rv): if not rv.is_Add: return rv def do(rv, first=True): # args which can be expressed as A*(cos(a)*cos(b)+/-sin(a)*sin(b)) # or B*(cos(a)*sin(b)+/-cos(b)*sin(a)) can be combined into # A*f(a+/-b) where f is either sin or cos. # # If there are more than two args, the pairs which "work" will have # a gcd extractable and the remaining two terms will have the above # structure -- all pairs must be checked to find the ones that # work. if not rv.is_Add: return rv args = list(ordered(rv.args)) if len(args) != 2: hit = False for i in range(len(args)): ai = args[i] if ai is None: continue for j in range(i + 1, len(args)): aj = args[j] if aj is None: continue was = ai + aj new = do(was) if new != was: args[i] = new # update in place args[j] = None hit = True break # go to next i if hit: rv = Add(*[_f for _f in args if _f]) if rv.is_Add: rv = do(rv) return rv # two-arg Add split = trig_split(*args, two=True) if not split: return rv gcd, n1, n2, a, b, same = split # identify and get c1 to be cos then apply rule if possible if same: # coscos, sinsin gcd = n1*gcd if n1 == n2: return gcd*cos(a - b) return gcd*cos(a + b) else: #cossin, cossin gcd = n1*gcd if n1 == n2: return gcd*sin(a + b) return gcd*sin(b - a) rv = process_common_addends( rv, do, lambda x: tuple(ordered(x.free_symbols))) # need to check for inducible pairs in ratio of sqrt(3):1 that # appeared in different lists when sorting by coefficient while rv.is_Add: byrad = defaultdict(list) for a in rv.args: hit = 0 if a.is_Mul: for ai in a.args: if ai.is_Pow and ai.exp is S.Half and \ ai.base.is_Integer: byrad[ai].append(a) hit = 1 break if not hit: byrad[S.One].append(a) # no need to check all pairs -- just check for the onees # that have the right ratio args = [] for a in byrad: for b in [_ROOT3*a, _invROOT3]: if b in byrad: for i in range(len(byrad[a])): if byrad[a][i] is None: continue for j in range(len(byrad[b])): if byrad[b][j] is None: continue was = Add(byrad[a][i] + byrad[b][j]) new = do(was) if new != was: args.append(new) byrad[a][i] = None byrad[b][j] = None break if args: rv = Add(*(args + [Add(*[_f for _f in v if _f]) for v in byrad.values()])) else: rv = do(rv) # final pass to resolve any new inducible pairs break return rv return bottom_up(rv, f) def TR11(rv, base=None): """Function of double angle to product. The ``base`` argument can be used to indicate what is the un-doubled argument, e.g. if 3*pi/7 is the base then cosine and sine functions with argument 6*pi/7 will be replaced. Examples ======== >>> from sympy.simplify.fu import TR11 >>> from sympy import cos, sin, pi >>> from sympy.abc import x >>> TR11(sin(2*x)) 2*sin(x)*cos(x) >>> TR11(cos(2*x)) -sin(x)**2 + cos(x)**2 >>> TR11(sin(4*x)) 4*(-sin(x)**2 + cos(x)**2)*sin(x)*cos(x) >>> TR11(sin(4*x/3)) 4*(-sin(x/3)**2 + cos(x/3)**2)*sin(x/3)*cos(x/3) If the arguments are simply integers, no change is made unless a base is provided: >>> TR11(cos(2)) cos(2) >>> TR11(cos(4), 2) -sin(2)**2 + cos(2)**2 There is a subtle issue here in that autosimplification will convert some higher angles to lower angles >>> cos(6*pi/7) + cos(3*pi/7) -cos(pi/7) + cos(3*pi/7) The 6*pi/7 angle is now pi/7 but can be targeted with TR11 by supplying the 3*pi/7 base: >>> TR11(_, 3*pi/7) -sin(3*pi/7)**2 + cos(3*pi/7)**2 + cos(3*pi/7) """ def f(rv): if not rv.func in (cos, sin): return rv if base: f = rv.func t = f(base*2) co = S.One if t.is_Mul: co, t = t.as_coeff_Mul() if not t.func in (cos, sin): return rv if rv.args[0] == t.args[0]: c = cos(base) s = sin(base) if f is cos: return (c**2 - s**2)/co else: return 2*c*s/co return rv elif not rv.args[0].is_Number: # make a change if the leading coefficient's numerator is # divisible by 2 c, m = rv.args[0].as_coeff_Mul(rational=True) if c.p % 2 == 0: arg = c.p//2*m/c.q c = TR11(cos(arg)) s = TR11(sin(arg)) if rv.func == sin: rv = 2*s*c else: rv = c**2 - s**2 return rv return bottom_up(rv, f) def _TR11(rv): """ Helper for TR11 to find half-arguments for sin in factors of num/den that appear in cos or sin factors in the den/num. Examples ======== >>> from sympy.simplify.fu import TR11, _TR11 >>> from sympy import cos, sin >>> from sympy.abc import x >>> TR11(sin(x/3)/(cos(x/6))) sin(x/3)/cos(x/6) >>> _TR11(sin(x/3)/(cos(x/6))) 2*sin(x/6) >>> TR11(sin(x/6)/(sin(x/3))) sin(x/6)/sin(x/3) >>> _TR11(sin(x/6)/(sin(x/3))) 1/(2*cos(x/6)) """ def f(rv): if not isinstance(rv, Expr): return rv def sincos_args(flat): # find arguments of sin and cos that # appears as bases in args of flat # and have Integer exponents args = defaultdict(set) for fi in Mul.make_args(flat): b, e = fi.as_base_exp() if e.is_Integer and e > 0: if b.func in (cos, sin): args[b.func].add(b.args[0]) return args num_args, den_args = map(sincos_args, rv.as_numer_denom()) def handle_match(rv, num_args, den_args): # for arg in sin args of num_args, look for arg/2 # in den_args and pass this half-angle to TR11 # for handling in rv for narg in num_args[sin]: half = narg/2 if half in den_args[cos]: func = cos elif half in den_args[sin]: func = sin else: continue rv = TR11(rv, half) den_args[func].remove(half) return rv # sin in num, sin or cos in den rv = handle_match(rv, num_args, den_args) # sin in den, sin or cos in num rv = handle_match(rv, den_args, num_args) return rv return bottom_up(rv, f) def TR12(rv, first=True): """Separate sums in ``tan``. Examples ======== >>> from sympy.abc import x, y >>> from sympy import tan >>> from sympy.simplify.fu import TR12 >>> TR12(tan(x + y)) (tan(x) + tan(y))/(-tan(x)*tan(y) + 1) """ def f(rv): if not rv.func == tan: return rv arg = rv.args[0] if arg.is_Add: if first: args = list(ordered(arg.args)) else: args = list(arg.args) a = args.pop() b = Add._from_args(args) if b.is_Add: tb = TR12(tan(b), first=False) else: tb = tan(b) return (tan(a) + tb)/(1 - tan(a)*tb) return rv return bottom_up(rv, f) def TR12i(rv): """Combine tan arguments as (tan(y) + tan(x))/(tan(x)*tan(y) - 1) -> -tan(x + y). Examples ======== >>> from sympy.simplify.fu import TR12i >>> from sympy import tan >>> from sympy.abc import a, b, c >>> ta, tb, tc = [tan(i) for i in (a, b, c)] >>> TR12i((ta + tb)/(-ta*tb + 1)) tan(a + b) >>> TR12i((ta + tb)/(ta*tb - 1)) -tan(a + b) >>> TR12i((-ta - tb)/(ta*tb - 1)) tan(a + b) >>> eq = (ta + tb)/(-ta*tb + 1)**2*(-3*ta - 3*tc)/(2*(ta*tc - 1)) >>> TR12i(eq.expand()) -3*tan(a + b)*tan(a + c)/(2*(tan(a) + tan(b) - 1)) """ from sympy import factor def f(rv): if not (rv.is_Add or rv.is_Mul or rv.is_Pow): return rv n, d = rv.as_numer_denom() if not d.args or not n.args: return rv dok = {} def ok(di): m = as_f_sign_1(di) if m: g, f, s = m if s is S.NegativeOne and f.is_Mul and len(f.args) == 2 and \ all(isinstance(fi, tan) for fi in f.args): return g, f d_args = list(Mul.make_args(d)) for i, di in enumerate(d_args): m = ok(di) if m: g, t = m s = Add(*[_.args[0] for _ in t.args]) dok[s] = S.One d_args[i] = g continue if di.is_Add: di = factor(di) if di.is_Mul: d_args.extend(di.args) d_args[i] = S.One elif di.is_Pow and (di.exp.is_integer or di.base.is_positive): m = ok(di.base) if m: g, t = m s = Add(*[_.args[0] for _ in t.args]) dok[s] = di.exp d_args[i] = g**di.exp else: di = factor(di) if di.is_Mul: d_args.extend(di.args) d_args[i] = S.One if not dok: return rv def ok(ni): if ni.is_Add and len(ni.args) == 2: a, b = ni.args if isinstance(a, tan) and isinstance(b, tan): return a, b n_args = list(Mul.make_args(factor_terms(n))) hit = False for i, ni in enumerate(n_args): m = ok(ni) if not m: m = ok(-ni) if m: n_args[i] = S.NegativeOne else: if ni.is_Add: ni = factor(ni) if ni.is_Mul: n_args.extend(ni.args) n_args[i] = S.One continue elif ni.is_Pow and ( ni.exp.is_integer or ni.base.is_positive): m = ok(ni.base) if m: n_args[i] = S.One else: ni = factor(ni) if ni.is_Mul: n_args.extend(ni.args) n_args[i] = S.One continue else: continue else: n_args[i] = S.One hit = True s = Add(*[_.args[0] for _ in m]) ed = dok[s] newed = ed.extract_additively(S.One) if newed is not None: if newed: dok[s] = newed else: dok.pop(s) n_args[i] *= -tan(s) if hit: rv = Mul(*n_args)/Mul(*d_args)/Mul(*[(Add(*[ tan(a) for a in i.args]) - 1)**e for i, e in dok.items()]) return rv return bottom_up(rv, f) def TR13(rv): """Change products of ``tan`` or ``cot``. Examples ======== >>> from sympy.simplify.fu import TR13 >>> from sympy import tan, cot >>> TR13(tan(3)*tan(2)) -tan(2)/tan(5) - tan(3)/tan(5) + 1 >>> TR13(cot(3)*cot(2)) cot(2)*cot(5) + 1 + cot(3)*cot(5) """ def f(rv): if not rv.is_Mul: return rv # XXX handle products of powers? or let power-reducing handle it? args = {tan: [], cot: [], None: []} for a in ordered(Mul.make_args(rv)): if a.func in (tan, cot): args[a.func].append(a.args[0]) else: args[None].append(a) t = args[tan] c = args[cot] if len(t) < 2 and len(c) < 2: return rv args = args[None] while len(t) > 1: t1 = t.pop() t2 = t.pop() args.append(1 - (tan(t1)/tan(t1 + t2) + tan(t2)/tan(t1 + t2))) if t: args.append(tan(t.pop())) while len(c) > 1: t1 = c.pop() t2 = c.pop() args.append(1 + cot(t1)*cot(t1 + t2) + cot(t2)*cot(t1 + t2)) if c: args.append(cot(c.pop())) return Mul(*args) return bottom_up(rv, f) def TRmorrie(rv): """Returns cos(x)*cos(2*x)*...*cos(2**(k-1)*x) -> sin(2**k*x)/(2**k*sin(x)) Examples ======== >>> from sympy.simplify.fu import TRmorrie, TR8, TR3 >>> from sympy.abc import x >>> from sympy import Mul, cos, pi >>> TRmorrie(cos(x)*cos(2*x)) sin(4*x)/(4*sin(x)) >>> TRmorrie(7*Mul(*[cos(x) for x in range(10)])) 7*sin(12)*sin(16)*cos(5)*cos(7)*cos(9)/(64*sin(1)*sin(3)) Sometimes autosimplification will cause a power to be not recognized. e.g. in the following, cos(4*pi/7) automatically simplifies to -cos(3*pi/7) so only 2 of the 3 terms are recognized: >>> TRmorrie(cos(pi/7)*cos(2*pi/7)*cos(4*pi/7)) -sin(3*pi/7)*cos(3*pi/7)/(4*sin(pi/7)) A touch by TR8 resolves the expression to a Rational >>> TR8(_) -1/8 In this case, if eq is unsimplified, the answer is obtained directly: >>> eq = cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9) >>> TRmorrie(eq) 1/16 But if angles are made canonical with TR3 then the answer is not simplified without further work: >>> TR3(eq) sin(pi/18)*cos(pi/9)*cos(2*pi/9)/2 >>> TRmorrie(_) sin(pi/18)*sin(4*pi/9)/(8*sin(pi/9)) >>> TR8(_) cos(7*pi/18)/(16*sin(pi/9)) >>> TR3(_) 1/16 The original expression would have resolve to 1/16 directly with TR8, however: >>> TR8(eq) 1/16 References ========== .. [1] https://en.wikipedia.org/wiki/Morrie%27s_law """ def f(rv, first=True): if not rv.is_Mul: return rv if first: n, d = rv.as_numer_denom() return f(n, 0)/f(d, 0) args = defaultdict(list) coss = {} other = [] for c in rv.args: b, e = c.as_base_exp() if e.is_Integer and isinstance(b, cos): co, a = b.args[0].as_coeff_Mul() args[a].append(co) coss[b] = e else: other.append(c) new = [] for a in args: c = args[a] c.sort() while c: k = 0 cc = ci = c[0] while cc in c: k += 1 cc *= 2 if k > 1: newarg = sin(2**k*ci*a)/2**k/sin(ci*a) # see how many times this can be taken take = None ccs = [] for i in range(k): cc /= 2 key = cos(a*cc, evaluate=False) ccs.append(cc) take = min(coss[key], take or coss[key]) # update exponent counts for i in range(k): cc = ccs.pop() key = cos(a*cc, evaluate=False) coss[key] -= take if not coss[key]: c.remove(cc) new.append(newarg**take) else: b = cos(c.pop(0)*a) other.append(b**coss[b]) if new: rv = Mul(*(new + other + [ cos(k*a, evaluate=False) for a in args for k in args[a]])) return rv return bottom_up(rv, f) def TR14(rv, first=True): """Convert factored powers of sin and cos identities into simpler expressions. Examples ======== >>> from sympy.simplify.fu import TR14 >>> from sympy.abc import x, y >>> from sympy import cos, sin >>> TR14((cos(x) - 1)*(cos(x) + 1)) -sin(x)**2 >>> TR14((sin(x) - 1)*(sin(x) + 1)) -cos(x)**2 >>> p1 = (cos(x) + 1)*(cos(x) - 1) >>> p2 = (cos(y) - 1)*2*(cos(y) + 1) >>> p3 = (3*(cos(y) - 1))*(3*(cos(y) + 1)) >>> TR14(p1*p2*p3*(x - 1)) -18*(x - 1)*sin(x)**2*sin(y)**4 """ def f(rv): if not rv.is_Mul: return rv if first: # sort them by location in numerator and denominator # so the code below can just deal with positive exponents n, d = rv.as_numer_denom() if d is not S.One: newn = TR14(n, first=False) newd = TR14(d, first=False) if newn != n or newd != d: rv = newn/newd return rv other = [] process = [] for a in rv.args: if a.is_Pow: b, e = a.as_base_exp() if not (e.is_integer or b.is_positive): other.append(a) continue a = b else: e = S.One m = as_f_sign_1(a) if not m or m[1].func not in (cos, sin): if e is S.One: other.append(a) else: other.append(a**e) continue g, f, si = m process.append((g, e.is_Number, e, f, si, a)) # sort them to get like terms next to each other process = list(ordered(process)) # keep track of whether there was any change nother = len(other) # access keys keys = (g, t, e, f, si, a) = list(range(6)) while process: A = process.pop(0) if process: B = process[0] if A[e].is_Number and B[e].is_Number: # both exponents are numbers if A[f] == B[f]: if A[si] != B[si]: B = process.pop(0) take = min(A[e], B[e]) # reinsert any remainder # the B will likely sort after A so check it first if B[e] != take: rem = [B[i] for i in keys] rem[e] -= take process.insert(0, rem) elif A[e] != take: rem = [A[i] for i in keys] rem[e] -= take process.insert(0, rem) if isinstance(A[f], cos): t = sin else: t = cos other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take) continue elif A[e] == B[e]: # both exponents are equal symbols if A[f] == B[f]: if A[si] != B[si]: B = process.pop(0) take = A[e] if isinstance(A[f], cos): t = sin else: t = cos other.append((-A[g]*B[g]*t(A[f].args[0])**2)**take) continue # either we are done or neither condition above applied other.append(A[a]**A[e]) if len(other) != nother: rv = Mul(*other) return rv return bottom_up(rv, f) def TR15(rv, max=4, pow=False): """Convert sin(x)**-2 to 1 + cot(x)**2. See _TR56 docstring for advanced use of ``max`` and ``pow``. Examples ======== >>> from sympy.simplify.fu import TR15 >>> from sympy.abc import x >>> from sympy import sin >>> TR15(1 - 1/sin(x)**2) -cot(x)**2 """ def f(rv): if not (isinstance(rv, Pow) and isinstance(rv.base, sin)): return rv e = rv.exp if e % 2 == 1: return TR15(rv.base**(e + 1))/rv.base ia = 1/rv a = _TR56(ia, sin, cot, lambda x: 1 + x, max=max, pow=pow) if a != ia: rv = a return rv return bottom_up(rv, f) def TR16(rv, max=4, pow=False): """Convert cos(x)**-2 to 1 + tan(x)**2. See _TR56 docstring for advanced use of ``max`` and ``pow``. Examples ======== >>> from sympy.simplify.fu import TR16 >>> from sympy.abc import x >>> from sympy import cos >>> TR16(1 - 1/cos(x)**2) -tan(x)**2 """ def f(rv): if not (isinstance(rv, Pow) and isinstance(rv.base, cos)): return rv e = rv.exp if e % 2 == 1: return TR15(rv.base**(e + 1))/rv.base ia = 1/rv a = _TR56(ia, cos, tan, lambda x: 1 + x, max=max, pow=pow) if a != ia: rv = a return rv return bottom_up(rv, f) def TR111(rv): """Convert f(x)**-i to g(x)**i where either ``i`` is an integer or the base is positive and f, g are: tan, cot; sin, csc; or cos, sec. Examples ======== >>> from sympy.simplify.fu import TR111 >>> from sympy.abc import x >>> from sympy import tan >>> TR111(1 - 1/tan(x)**2) 1 - cot(x)**2 """ def f(rv): if not ( isinstance(rv, Pow) and (rv.base.is_positive or rv.exp.is_integer and rv.exp.is_negative)): return rv if isinstance(rv.base, tan): return cot(rv.base.args[0])**-rv.exp elif isinstance(rv.base, sin): return csc(rv.base.args[0])**-rv.exp elif isinstance(rv.base, cos): return sec(rv.base.args[0])**-rv.exp return rv return bottom_up(rv, f) def TR22(rv, max=4, pow=False): """Convert tan(x)**2 to sec(x)**2 - 1 and cot(x)**2 to csc(x)**2 - 1. See _TR56 docstring for advanced use of ``max`` and ``pow``. Examples ======== >>> from sympy.simplify.fu import TR22 >>> from sympy.abc import x >>> from sympy import tan, cot >>> TR22(1 + tan(x)**2) sec(x)**2 >>> TR22(1 + cot(x)**2) csc(x)**2 """ def f(rv): if not (isinstance(rv, Pow) and rv.base.func in (cot, tan)): return rv rv = _TR56(rv, tan, sec, lambda x: x - 1, max=max, pow=pow) rv = _TR56(rv, cot, csc, lambda x: x - 1, max=max, pow=pow) return rv return bottom_up(rv, f) def TRpower(rv): """Convert sin(x)**n and cos(x)**n with positive n to sums. Examples ======== >>> from sympy.simplify.fu import TRpower >>> from sympy.abc import x >>> from sympy import cos, sin >>> TRpower(sin(x)**6) -15*cos(2*x)/32 + 3*cos(4*x)/16 - cos(6*x)/32 + 5/16 >>> TRpower(sin(x)**3*cos(2*x)**4) (3*sin(x)/4 - sin(3*x)/4)*(cos(4*x)/2 + cos(8*x)/8 + 3/8) References ========== .. [1] https://en.wikipedia.org/wiki/List_of_trigonometric_identities#Power-reduction_formulae """ def f(rv): if not (isinstance(rv, Pow) and isinstance(rv.base, (sin, cos))): return rv b, n = rv.as_base_exp() x = b.args[0] if n.is_Integer and n.is_positive: if n.is_odd and isinstance(b, cos): rv = 2**(1-n)*Add(*[binomial(n, k)*cos((n - 2*k)*x) for k in range((n + 1)/2)]) elif n.is_odd and isinstance(b, sin): rv = 2**(1-n)*(-1)**((n-1)/2)*Add(*[binomial(n, k)* (-1)**k*sin((n - 2*k)*x) for k in range((n + 1)/2)]) elif n.is_even and isinstance(b, cos): rv = 2**(1-n)*Add(*[binomial(n, k)*cos((n - 2*k)*x) for k in range(n/2)]) elif n.is_even and isinstance(b, sin): rv = 2**(1-n)*(-1)**(n/2)*Add(*[binomial(n, k)* (-1)**k*cos((n - 2*k)*x) for k in range(n/2)]) if n.is_even: rv += 2**(-n)*binomial(n, n/2) return rv return bottom_up(rv, f) def L(rv): """Return count of trigonometric functions in expression. Examples ======== >>> from sympy.simplify.fu import L >>> from sympy.abc import x >>> from sympy import cos, sin >>> L(cos(x)+sin(x)) 2 """ return S(rv.count(TrigonometricFunction)) # ============== end of basic Fu-like tools ===================== if SYMPY_DEBUG: (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13, TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22 )= list(map(debug, (TR0, TR1, TR2, TR3, TR4, TR5, TR6, TR7, TR8, TR9, TR10, TR11, TR12, TR13, TR2i, TRmorrie, TR14, TR15, TR16, TR12i, TR111, TR22))) # tuples are chains -- (f, g) -> lambda x: g(f(x)) # lists are choices -- [f, g] -> lambda x: min(f(x), g(x), key=objective) CTR1 = [(TR5, TR0), (TR6, TR0), identity] CTR2 = (TR11, [(TR5, TR0), (TR6, TR0), TR0]) CTR3 = [(TRmorrie, TR8, TR0), (TRmorrie, TR8, TR10i, TR0), identity] CTR4 = [(TR4, TR10i), identity] RL1 = (TR4, TR3, TR4, TR12, TR4, TR13, TR4, TR0) # XXX it's a little unclear how this one is to be implemented # see Fu paper of reference, page 7. What is the Union symbol referring to? # The diagram shows all these as one chain of transformations, but the # text refers to them being applied independently. Also, a break # if L starts to increase has not been implemented. RL2 = [ (TR4, TR3, TR10, TR4, TR3, TR11), (TR5, TR7, TR11, TR4), (CTR3, CTR1, TR9, CTR2, TR4, TR9, TR9, CTR4), identity, ] def fu(rv, measure=lambda x: (L(x), x.count_ops())): """Attempt to simplify expression by using transformation rules given in the algorithm by Fu et al. :func:`fu` will try to minimize the objective function ``measure``. By default this first minimizes the number of trig terms and then minimizes the number of total operations. Examples ======== >>> from sympy.simplify.fu import fu >>> from sympy import cos, sin, tan, pi, S, sqrt >>> from sympy.abc import x, y, a, b >>> fu(sin(50)**2 + cos(50)**2 + sin(pi/6)) 3/2 >>> fu(sqrt(6)*cos(x) + sqrt(2)*sin(x)) 2*sqrt(2)*sin(x + pi/3) CTR1 example >>> eq = sin(x)**4 - cos(y)**2 + sin(y)**2 + 2*cos(x)**2 >>> fu(eq) cos(x)**4 - 2*cos(y)**2 + 2 CTR2 example >>> fu(S.Half - cos(2*x)/2) sin(x)**2 CTR3 example >>> fu(sin(a)*(cos(b) - sin(b)) + cos(a)*(sin(b) + cos(b))) sqrt(2)*sin(a + b + pi/4) CTR4 example >>> fu(sqrt(3)*cos(x)/2 + sin(x)/2) sin(x + pi/3) Example 1 >>> fu(1-sin(2*x)**2/4-sin(y)**2-cos(x)**4) -cos(x)**2 + cos(y)**2 Example 2 >>> fu(cos(4*pi/9)) sin(pi/18) >>> fu(cos(pi/9)*cos(2*pi/9)*cos(3*pi/9)*cos(4*pi/9)) 1/16 Example 3 >>> fu(tan(7*pi/18)+tan(5*pi/18)-sqrt(3)*tan(5*pi/18)*tan(7*pi/18)) -sqrt(3) Objective function example >>> fu(sin(x)/cos(x)) # default objective function tan(x) >>> fu(sin(x)/cos(x), measure=lambda x: -x.count_ops()) # maximize op count sin(x)/cos(x) References ========== .. [1] https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.657.2478&rep=rep1&type=pdf """ fRL1 = greedy(RL1, measure) fRL2 = greedy(RL2, measure) was = rv rv = sympify(rv) if not isinstance(rv, Expr): return rv.func(*[fu(a, measure=measure) for a in rv.args]) rv = TR1(rv) if rv.has(tan, cot): rv1 = fRL1(rv) if (measure(rv1) < measure(rv)): rv = rv1 if rv.has(tan, cot): rv = TR2(rv) if rv.has(sin, cos): rv1 = fRL2(rv) rv2 = TR8(TRmorrie(rv1)) rv = min([was, rv, rv1, rv2], key=measure) return min(TR2i(rv), rv, key=measure) def process_common_addends(rv, do, key2=None, key1=True): """Apply ``do`` to addends of ``rv`` that (if ``key1=True``) share at least a common absolute value of their coefficient and the value of ``key2`` when applied to the argument. If ``key1`` is False ``key2`` must be supplied and will be the only key applied. """ # collect by absolute value of coefficient and key2 absc = defaultdict(list) if key1: for a in rv.args: c, a = a.as_coeff_Mul() if c < 0: c = -c a = -a # put the sign on `a` absc[(c, key2(a) if key2 else 1)].append(a) elif key2: for a in rv.args: absc[(S.One, key2(a))].append(a) else: raise ValueError('must have at least one key') args = [] hit = False for k in absc: v = absc[k] c, _ = k if len(v) > 1: e = Add(*v, evaluate=False) new = do(e) if new != e: e = new hit = True args.append(c*e) else: args.append(c*v[0]) if hit: rv = Add(*args) return rv fufuncs = ''' TR0 TR1 TR2 TR3 TR4 TR5 TR6 TR7 TR8 TR9 TR10 TR10i TR11 TR12 TR13 L TR2i TRmorrie TR12i TR14 TR15 TR16 TR111 TR22'''.split() FU = dict(list(zip(fufuncs, list(map(locals().get, fufuncs))))) def _roots(): global _ROOT2, _ROOT3, _invROOT3 _ROOT2, _ROOT3 = sqrt(2), sqrt(3) _invROOT3 = 1/_ROOT3 _ROOT2 = None def trig_split(a, b, two=False): """Return the gcd, s1, s2, a1, a2, bool where If two is False (default) then:: a + b = gcd*(s1*f(a1) + s2*f(a2)) where f = cos if bool else sin else: if bool, a + b was +/- cos(a1)*cos(a2) +/- sin(a1)*sin(a2) and equals n1*gcd*cos(a - b) if n1 == n2 else n1*gcd*cos(a + b) else a + b was +/- cos(a1)*sin(a2) +/- sin(a1)*cos(a2) and equals n1*gcd*sin(a + b) if n1 = n2 else n1*gcd*sin(b - a) Examples ======== >>> from sympy.simplify.fu import trig_split >>> from sympy.abc import x, y, z >>> from sympy import cos, sin, sqrt >>> trig_split(cos(x), cos(y)) (1, 1, 1, x, y, True) >>> trig_split(2*cos(x), -2*cos(y)) (2, 1, -1, x, y, True) >>> trig_split(cos(x)*sin(y), cos(y)*sin(y)) (sin(y), 1, 1, x, y, True) >>> trig_split(cos(x), -sqrt(3)*sin(x), two=True) (2, 1, -1, x, pi/6, False) >>> trig_split(cos(x), sin(x), two=True) (sqrt(2), 1, 1, x, pi/4, False) >>> trig_split(cos(x), -sin(x), two=True) (sqrt(2), 1, -1, x, pi/4, False) >>> trig_split(sqrt(2)*cos(x), -sqrt(6)*sin(x), two=True) (2*sqrt(2), 1, -1, x, pi/6, False) >>> trig_split(-sqrt(6)*cos(x), -sqrt(2)*sin(x), two=True) (-2*sqrt(2), 1, 1, x, pi/3, False) >>> trig_split(cos(x)/sqrt(6), sin(x)/sqrt(2), two=True) (sqrt(6)/3, 1, 1, x, pi/6, False) >>> trig_split(-sqrt(6)*cos(x)*sin(y), -sqrt(2)*sin(x)*sin(y), two=True) (-2*sqrt(2)*sin(y), 1, 1, x, pi/3, False) >>> trig_split(cos(x), sin(x)) >>> trig_split(cos(x), sin(z)) >>> trig_split(2*cos(x), -sin(x)) >>> trig_split(cos(x), -sqrt(3)*sin(x)) >>> trig_split(cos(x)*cos(y), sin(x)*sin(z)) >>> trig_split(cos(x)*cos(y), sin(x)*sin(y)) >>> trig_split(-sqrt(6)*cos(x), sqrt(2)*sin(x)*sin(y), two=True) """ global _ROOT2, _ROOT3, _invROOT3 if _ROOT2 is None: _roots() a, b = [Factors(i) for i in (a, b)] ua, ub = a.normal(b) gcd = a.gcd(b).as_expr() n1 = n2 = 1 if S.NegativeOne in ua.factors: ua = ua.quo(S.NegativeOne) n1 = -n1 elif S.NegativeOne in ub.factors: ub = ub.quo(S.NegativeOne) n2 = -n2 a, b = [i.as_expr() for i in (ua, ub)] def pow_cos_sin(a, two): """Return ``a`` as a tuple (r, c, s) such that ``a = (r or 1)*(c or 1)*(s or 1)``. Three arguments are returned (radical, c-factor, s-factor) as long as the conditions set by ``two`` are met; otherwise None is returned. If ``two`` is True there will be one or two non-None values in the tuple: c and s or c and r or s and r or s or c with c being a cosine function (if possible) else a sine, and s being a sine function (if possible) else oosine. If ``two`` is False then there will only be a c or s term in the tuple. ``two`` also require that either two cos and/or sin be present (with the condition that if the functions are the same the arguments are different or vice versa) or that a single cosine or a single sine be present with an optional radical. If the above conditions dictated by ``two`` are not met then None is returned. """ c = s = None co = S.One if a.is_Mul: co, a = a.as_coeff_Mul() if len(a.args) > 2 or not two: return None if a.is_Mul: args = list(a.args) else: args = [a] a = args.pop(0) if isinstance(a, cos): c = a elif isinstance(a, sin): s = a elif a.is_Pow and a.exp is S.Half: # autoeval doesn't allow -1/2 co *= a else: return None if args: b = args[0] if isinstance(b, cos): if c: s = b else: c = b elif isinstance(b, sin): if s: c = b else: s = b elif b.is_Pow and b.exp is S.Half: co *= b else: return None return co if co is not S.One else None, c, s elif isinstance(a, cos): c = a elif isinstance(a, sin): s = a if c is None and s is None: return co = co if co is not S.One else None return co, c, s # get the parts m = pow_cos_sin(a, two) if m is None: return coa, ca, sa = m m = pow_cos_sin(b, two) if m is None: return cob, cb, sb = m # check them if (not ca) and cb or ca and isinstance(ca, sin): coa, ca, sa, cob, cb, sb = cob, cb, sb, coa, ca, sa n1, n2 = n2, n1 if not two: # need cos(x) and cos(y) or sin(x) and sin(y) c = ca or sa s = cb or sb if not isinstance(c, s.func): return None return gcd, n1, n2, c.args[0], s.args[0], isinstance(c, cos) else: if not coa and not cob: if (ca and cb and sa and sb): if isinstance(ca, sa.func) is not isinstance(cb, sb.func): return args = {j.args for j in (ca, sa)} if not all(i.args in args for i in (cb, sb)): return return gcd, n1, n2, ca.args[0], sa.args[0], isinstance(ca, sa.func) if ca and sa or cb and sb or \ two and (ca is None and sa is None or cb is None and sb is None): return c = ca or sa s = cb or sb if c.args != s.args: return if not coa: coa = S.One if not cob: cob = S.One if coa is cob: gcd *= _ROOT2 return gcd, n1, n2, c.args[0], pi/4, False elif coa/cob == _ROOT3: gcd *= 2*cob return gcd, n1, n2, c.args[0], pi/3, False elif coa/cob == _invROOT3: gcd *= 2*coa return gcd, n1, n2, c.args[0], pi/6, False def as_f_sign_1(e): """If ``e`` is a sum that can be written as ``g*(a + s)`` where ``s`` is ``+/-1``, return ``g``, ``a``, and ``s`` where ``a`` does not have a leading negative coefficient. Examples ======== >>> from sympy.simplify.fu import as_f_sign_1 >>> from sympy.abc import x >>> as_f_sign_1(x + 1) (1, x, 1) >>> as_f_sign_1(x - 1) (1, x, -1) >>> as_f_sign_1(-x + 1) (-1, x, -1) >>> as_f_sign_1(-x - 1) (-1, x, 1) >>> as_f_sign_1(2*x + 2) (2, x, 1) """ if not e.is_Add or len(e.args) != 2: return # exact match a, b = e.args if a in (S.NegativeOne, S.One): g = S.One if b.is_Mul and b.args[0].is_Number and b.args[0] < 0: a, b = -a, -b g = -g return g, b, a # gcd match a, b = [Factors(i) for i in e.args] ua, ub = a.normal(b) gcd = a.gcd(b).as_expr() if S.NegativeOne in ua.factors: ua = ua.quo(S.NegativeOne) n1 = -1 n2 = 1 elif S.NegativeOne in ub.factors: ub = ub.quo(S.NegativeOne) n1 = 1 n2 = -1 else: n1 = n2 = 1 a, b = [i.as_expr() for i in (ua, ub)] if a is S.One: a, b = b, a n1, n2 = n2, n1 if n1 == -1: gcd = -gcd n2 = -n2 if b is S.One: return gcd, a, n2 def _osborne(e, d): """Replace all hyperbolic functions with trig functions using the Osborne rule. Notes ===== ``d`` is a dummy variable to prevent automatic evaluation of trigonometric/hyperbolic functions. References ========== .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function """ def f(rv): if not isinstance(rv, HyperbolicFunction): return rv a = rv.args[0] a = a*d if not a.is_Add else Add._from_args([i*d for i in a.args]) if isinstance(rv, sinh): return I*sin(a) elif isinstance(rv, cosh): return cos(a) elif isinstance(rv, tanh): return I*tan(a) elif isinstance(rv, coth): return cot(a)/I elif isinstance(rv, sech): return sec(a) elif isinstance(rv, csch): return csc(a)/I else: raise NotImplementedError('unhandled %s' % rv.func) return bottom_up(e, f) def _osbornei(e, d): """Replace all trig functions with hyperbolic functions using the Osborne rule. Notes ===== ``d`` is a dummy variable to prevent automatic evaluation of trigonometric/hyperbolic functions. References ========== .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function """ def f(rv): if not isinstance(rv, TrigonometricFunction): return rv const, x = rv.args[0].as_independent(d, as_Add=True) a = x.xreplace({d: S.One}) + const*I if isinstance(rv, sin): return sinh(a)/I elif isinstance(rv, cos): return cosh(a) elif isinstance(rv, tan): return tanh(a)/I elif isinstance(rv, cot): return coth(a)*I elif isinstance(rv, sec): return sech(a) elif isinstance(rv, csc): return csch(a)*I else: raise NotImplementedError('unhandled %s' % rv.func) return bottom_up(e, f) def hyper_as_trig(rv): """Return an expression containing hyperbolic functions in terms of trigonometric functions. Any trigonometric functions initially present are replaced with Dummy symbols and the function to undo the masking and the conversion back to hyperbolics is also returned. It should always be true that:: t, f = hyper_as_trig(expr) expr == f(t) Examples ======== >>> from sympy.simplify.fu import hyper_as_trig, fu >>> from sympy.abc import x >>> from sympy import cosh, sinh >>> eq = sinh(x)**2 + cosh(x)**2 >>> t, f = hyper_as_trig(eq) >>> f(fu(t)) cosh(2*x) References ========== .. [1] https://en.wikipedia.org/wiki/Hyperbolic_function """ from sympy.simplify.simplify import signsimp from sympy.simplify.radsimp import collect # mask off trig functions trigs = rv.atoms(TrigonometricFunction) reps = [(t, Dummy()) for t in trigs] masked = rv.xreplace(dict(reps)) # get inversion substitutions in place reps = [(v, k) for k, v in reps] d = Dummy() return _osborne(masked, d), lambda x: collect(signsimp( _osbornei(x, d).xreplace(dict(reps))), S.ImaginaryUnit) def sincos_to_sum(expr): """Convert products and powers of sin and cos to sums. Explanation =========== Applied power reduction TRpower first, then expands products, and converts products to sums with TR8. Examples ======== >>> from sympy.simplify.fu import sincos_to_sum >>> from sympy.abc import x >>> from sympy import cos, sin >>> sincos_to_sum(16*sin(x)**3*cos(2*x)**2) 7*sin(x) - 5*sin(3*x) + 3*sin(5*x) - sin(7*x) """ if not expr.has(cos, sin): return expr else: return TR8(expand_mul(TRpower(expr))) sympy-sympy-1.9/sympy/simplify/gammasimp.py000066400000000000000000000446321412543434000212760ustar00rootroot00000000000000from sympy.core import Function, S, Mul, Pow, Add from sympy.core.compatibility import ordered, default_sort_key from sympy.core.function import count_ops, expand_func from sympy.functions.combinatorial.factorials import binomial from sympy.functions import gamma, sqrt, sin from sympy.polys import factor, cancel from sympy.utilities.iterables import sift, uniq def gammasimp(expr): r""" Simplify expressions with gamma functions. Explanation =========== This function takes as input an expression containing gamma functions or functions that can be rewritten in terms of gamma functions and tries to minimize the number of those functions and reduce the size of their arguments. The algorithm works by rewriting all gamma functions as expressions involving rising factorials (Pochhammer symbols) and applies recurrence relations and other transformations applicable to rising factorials, to reduce their arguments, possibly letting the resulting rising factorial to cancel. Rising factorials with the second argument being an integer are expanded into polynomial forms and finally all other rising factorial are rewritten in terms of gamma functions. Then the following two steps are performed. 1. Reduce the number of gammas by applying the reflection theorem gamma(x)*gamma(1-x) == pi/sin(pi*x). 2. Reduce the number of gammas by applying the multiplication theorem gamma(x)*gamma(x+1/n)*...*gamma(x+(n-1)/n) == C*gamma(n*x). It then reduces the number of prefactors by absorbing them into gammas where possible and expands gammas with rational argument. All transformation rules can be found (or was derived from) here: .. [1] http://functions.wolfram.com/GammaBetaErf/Pochhammer/17/01/02/ .. [2] http://functions.wolfram.com/GammaBetaErf/Pochhammer/27/01/0005/ Examples ======== >>> from sympy.simplify import gammasimp >>> from sympy import gamma, Symbol >>> from sympy.abc import x >>> n = Symbol('n', integer = True) >>> gammasimp(gamma(x)/gamma(x - 3)) (x - 3)*(x - 2)*(x - 1) >>> gammasimp(gamma(n + 3)) gamma(n + 3) """ expr = expr.rewrite(gamma) return _gammasimp(expr, as_comb = False) def _gammasimp(expr, as_comb): """ Helper function for gammasimp and combsimp. Explanation =========== Simplifies expressions written in terms of gamma function. If as_comb is True, it tries to preserve integer arguments. See docstring of gammasimp for more information. This was part of combsimp() in combsimp.py. """ expr = expr.replace(gamma, lambda n: _rf(1, (n - 1).expand())) if as_comb: expr = expr.replace(_rf, lambda a, b: gamma(b + 1)) else: expr = expr.replace(_rf, lambda a, b: gamma(a + b)/gamma(a)) def rule(n, k): coeff, rewrite = S.One, False cn, _n = n.as_coeff_Add() if _n and cn.is_Integer and cn: coeff *= _rf(_n + 1, cn)/_rf(_n - k + 1, cn) rewrite = True n = _n # this sort of binomial has already been removed by # rising factorials but is left here in case the order # of rule application is changed if k.is_Add: ck, _k = k.as_coeff_Add() if _k and ck.is_Integer and ck: coeff *= _rf(n - ck - _k + 1, ck)/_rf(_k + 1, ck) rewrite = True k = _k if count_ops(k) > count_ops(n - k): rewrite = True k = n - k if rewrite: return coeff*binomial(n, k) expr = expr.replace(binomial, rule) def rule_gamma(expr, level=0): """ Simplify products of gamma functions further. """ if expr.is_Atom: return expr def gamma_rat(x): # helper to simplify ratios of gammas was = x.count(gamma) xx = x.replace(gamma, lambda n: _rf(1, (n - 1).expand() ).replace(_rf, lambda a, b: gamma(a + b)/gamma(a))) if xx.count(gamma) < was: x = xx return x def gamma_factor(x): # return True if there is a gamma factor in shallow args if isinstance(x, gamma): return True if x.is_Add or x.is_Mul: return any(gamma_factor(xi) for xi in x.args) if x.is_Pow and (x.exp.is_integer or x.base.is_positive): return gamma_factor(x.base) return False # recursion step if level == 0: expr = expr.func(*[rule_gamma(x, level + 1) for x in expr.args]) level += 1 if not expr.is_Mul: return expr # non-commutative step if level == 1: args, nc = expr.args_cnc() if not args: return expr if nc: return rule_gamma(Mul._from_args(args), level + 1)*Mul._from_args(nc) level += 1 # pure gamma handling, not factor absorption if level == 2: T, F = sift(expr.args, gamma_factor, binary=True) gamma_ind = Mul(*F) d = Mul(*T) nd, dd = d.as_numer_denom() for ipass in range(2): args = list(ordered(Mul.make_args(nd))) for i, ni in enumerate(args): if ni.is_Add: ni, dd = Add(*[ rule_gamma(gamma_rat(a/dd), level + 1) for a in ni.args] ).as_numer_denom() args[i] = ni if not dd.has(gamma): break nd = Mul(*args) if ipass == 0 and not gamma_factor(nd): break nd, dd = dd, nd # now process in reversed order expr = gamma_ind*nd/dd if not (expr.is_Mul and (gamma_factor(dd) or gamma_factor(nd))): return expr level += 1 # iteration until constant if level == 3: while True: was = expr expr = rule_gamma(expr, 4) if expr == was: return expr numer_gammas = [] denom_gammas = [] numer_others = [] denom_others = [] def explicate(p): if p is S.One: return None, [] b, e = p.as_base_exp() if e.is_Integer: if isinstance(b, gamma): return True, [b.args[0]]*e else: return False, [b]*e else: return False, [p] newargs = list(ordered(expr.args)) while newargs: n, d = newargs.pop().as_numer_denom() isg, l = explicate(n) if isg: numer_gammas.extend(l) elif isg is False: numer_others.extend(l) isg, l = explicate(d) if isg: denom_gammas.extend(l) elif isg is False: denom_others.extend(l) # =========== level 2 work: pure gamma manipulation ========= if not as_comb: # Try to reduce the number of gamma factors by applying the # reflection formula gamma(x)*gamma(1-x) = pi/sin(pi*x) for gammas, numer, denom in [( numer_gammas, numer_others, denom_others), (denom_gammas, denom_others, numer_others)]: new = [] while gammas: g1 = gammas.pop() if g1.is_integer: new.append(g1) continue for i, g2 in enumerate(gammas): n = g1 + g2 - 1 if not n.is_Integer: continue numer.append(S.Pi) denom.append(sin(S.Pi*g1)) gammas.pop(i) if n > 0: for k in range(n): numer.append(1 - g1 + k) elif n < 0: for k in range(-n): denom.append(-g1 - k) break else: new.append(g1) # /!\ updating IN PLACE gammas[:] = new # Try to reduce the number of gammas by using the duplication # theorem to cancel an upper and lower: gamma(2*s)/gamma(s) = # 2**(2*s + 1)/(4*sqrt(pi))*gamma(s + 1/2). Although this could # be done with higher argument ratios like gamma(3*x)/gamma(x), # this would not reduce the number of gammas as in this case. for ng, dg, no, do in [(numer_gammas, denom_gammas, numer_others, denom_others), (denom_gammas, numer_gammas, denom_others, numer_others)]: while True: for x in ng: for y in dg: n = x - 2*y if n.is_Integer: break else: continue break else: break ng.remove(x) dg.remove(y) if n > 0: for k in range(n): no.append(2*y + k) elif n < 0: for k in range(-n): do.append(2*y - 1 - k) ng.append(y + S.Half) no.append(2**(2*y - 1)) do.append(sqrt(S.Pi)) # Try to reduce the number of gamma factors by applying the # multiplication theorem (used when n gammas with args differing # by 1/n mod 1 are encountered). # # run of 2 with args differing by 1/2 # # >>> gammasimp(gamma(x)*gamma(x+S.Half)) # 2*sqrt(2)*2**(-2*x - 1/2)*sqrt(pi)*gamma(2*x) # # run of 3 args differing by 1/3 (mod 1) # # >>> gammasimp(gamma(x)*gamma(x+S(1)/3)*gamma(x+S(2)/3)) # 6*3**(-3*x - 1/2)*pi*gamma(3*x) # >>> gammasimp(gamma(x)*gamma(x+S(1)/3)*gamma(x+S(5)/3)) # 2*3**(-3*x - 1/2)*pi*(3*x + 2)*gamma(3*x) # def _run(coeffs): # find runs in coeffs such that the difference in terms (mod 1) # of t1, t2, ..., tn is 1/n u = list(uniq(coeffs)) for i in range(len(u)): dj = ([((u[j] - u[i]) % 1, j) for j in range(i + 1, len(u))]) for one, j in dj: if one.p == 1 and one.q != 1: n = one.q got = [i] get = list(range(1, n)) for d, j in dj: m = n*d if m.is_Integer and m in get: get.remove(m) got.append(j) if not get: break else: continue for i, j in enumerate(got): c = u[j] coeffs.remove(c) got[i] = c return one.q, got[0], got[1:] def _mult_thm(gammas, numer, denom): # pull off and analyze the leading coefficient from each gamma arg # looking for runs in those Rationals # expr -> coeff + resid -> rats[resid] = coeff rats = {} for g in gammas: c, resid = g.as_coeff_Add() rats.setdefault(resid, []).append(c) # look for runs in Rationals for each resid keys = sorted(rats, key=default_sort_key) for resid in keys: coeffs = list(sorted(rats[resid])) new = [] while True: run = _run(coeffs) if run is None: break # process the sequence that was found: # 1) convert all the gamma functions to have the right # argument (could be off by an integer) # 2) append the factors corresponding to the theorem # 3) append the new gamma function n, ui, other = run # (1) for u in other: con = resid + u - 1 for k in range(int(u - ui)): numer.append(con - k) con = n*(resid + ui) # for (2) and (3) # (2) numer.append((2*S.Pi)**(S(n - 1)/2)* n**(S.Half - con)) # (3) new.append(con) # restore resid to coeffs rats[resid] = [resid + c for c in coeffs] + new # rebuild the gamma arguments g = [] for resid in keys: g += rats[resid] # /!\ updating IN PLACE gammas[:] = g for l, numer, denom in [(numer_gammas, numer_others, denom_others), (denom_gammas, denom_others, numer_others)]: _mult_thm(l, numer, denom) # =========== level >= 2 work: factor absorption ========= if level >= 2: # Try to absorb factors into the gammas: x*gamma(x) -> gamma(x + 1) # and gamma(x)/(x - 1) -> gamma(x - 1) # This code (in particular repeated calls to find_fuzzy) can be very # slow. def find_fuzzy(l, x): if not l: return S1, T1 = compute_ST(x) for y in l: S2, T2 = inv[y] if T1 != T2 or (not S1.intersection(S2) and (S1 != set() or S2 != set())): continue # XXX we want some simplification (e.g. cancel or # simplify) but no matter what it's slow. a = len(cancel(x/y).free_symbols) b = len(x.free_symbols) c = len(y.free_symbols) # TODO is there a better heuristic? if a == 0 and (b > 0 or c > 0): return y # We thus try to avoid expensive calls by building the following # "invariants": For every factor or gamma function argument # - the set of free symbols S # - the set of functional components T # We will only try to absorb if T1==T2 and (S1 intersect S2 != emptyset # or S1 == S2 == emptyset) inv = {} def compute_ST(expr): if expr in inv: return inv[expr] return (expr.free_symbols, expr.atoms(Function).union( {e.exp for e in expr.atoms(Pow)})) def update_ST(expr): inv[expr] = compute_ST(expr) for expr in numer_gammas + denom_gammas + numer_others + denom_others: update_ST(expr) for gammas, numer, denom in [( numer_gammas, numer_others, denom_others), (denom_gammas, denom_others, numer_others)]: new = [] while gammas: g = gammas.pop() cont = True while cont: cont = False y = find_fuzzy(numer, g) if y is not None: numer.remove(y) if y != g: numer.append(y/g) update_ST(y/g) g += 1 cont = True y = find_fuzzy(denom, g - 1) if y is not None: denom.remove(y) if y != g - 1: numer.append((g - 1)/y) update_ST((g - 1)/y) g -= 1 cont = True new.append(g) # /!\ updating IN PLACE gammas[:] = new # =========== rebuild expr ================================== return Mul(*[gamma(g) for g in numer_gammas]) \ / Mul(*[gamma(g) for g in denom_gammas]) \ * Mul(*numer_others) / Mul(*denom_others) # (for some reason we cannot use Basic.replace in this case) was = factor(expr) expr = rule_gamma(was) if expr != was: expr = factor(expr) expr = expr.replace(gamma, lambda n: expand_func(gamma(n)) if n.is_Rational else gamma(n)) return expr class _rf(Function): @classmethod def eval(cls, a, b): if b.is_Integer: if not b: return S.One n, result = int(b), S.One if n > 0: for i in range(n): result *= a + i return result elif n < 0: for i in range(1, -n + 1): result *= a - i return 1/result else: if b.is_Add: c, _b = b.as_coeff_Add() if c.is_Integer: if c > 0: return _rf(a, _b)*_rf(a + _b, c) elif c < 0: return _rf(a, _b)/_rf(a + _b + c, -c) if a.is_Add: c, _a = a.as_coeff_Add() if c.is_Integer: if c > 0: return _rf(_a, b)*_rf(_a + b, c)/_rf(_a, c) elif c < 0: return _rf(_a, b)*_rf(_a + c, -c)/_rf(_a + b + c, -c) sympy-sympy-1.9/sympy/simplify/hyperexpand.py000066400000000000000000002453161412543434000216540ustar00rootroot00000000000000""" Expand Hypergeometric (and Meijer G) functions into named special functions. The algorithm for doing this uses a collection of lookup tables of hypergeometric functions, and various of their properties, to expand many hypergeometric functions in terms of special functions. It is based on the following paper: Kelly B. Roach. Meijer G Function Representations. In: Proceedings of the 1997 International Symposium on Symbolic and Algebraic Computation, pages 205-211, New York, 1997. ACM. It is described in great(er) detail in the Sphinx documentation. """ # SUMMARY OF EXTENSIONS FOR MEIJER G FUNCTIONS # # o z**rho G(ap, bq; z) = G(ap + rho, bq + rho; z) # # o denote z*d/dz by D # # o It is helpful to keep in mind that ap and bq play essentially symmetric # roles: G(1/z) has slightly altered parameters, with ap and bq interchanged. # # o There are four shift operators: # A_J = b_J - D, J = 1, ..., n # B_J = 1 - a_j + D, J = 1, ..., m # C_J = -b_J + D, J = m+1, ..., q # D_J = a_J - 1 - D, J = n+1, ..., p # # A_J, C_J increment b_J # B_J, D_J decrement a_J # # o The corresponding four inverse-shift operators are defined if there # is no cancellation. Thus e.g. an index a_J (upper or lower) can be # incremented if a_J != b_i for i = 1, ..., q. # # o Order reduction: if b_j - a_i is a non-negative integer, where # j <= m and i > n, the corresponding quotient of gamma functions reduces # to a polynomial. Hence the G function can be expressed using a G-function # of lower order. # Similarly if j > m and i <= n. # # Secondly, there are paired index theorems [Adamchik, The evaluation of # integrals of Bessel functions via G-function identities]. Suppose there # are three parameters a, b, c, where a is an a_i, i <= n, b is a b_j, # j <= m and c is a denominator parameter (i.e. a_i, i > n or b_j, j > m). # Suppose further all three differ by integers. # Then the order can be reduced. # TODO work this out in detail. # # o An index quadruple is called suitable if its order cannot be reduced. # If there exists a sequence of shift operators transforming one index # quadruple into another, we say one is reachable from the other. # # o Deciding if one index quadruple is reachable from another is tricky. For # this reason, we use hand-built routines to match and instantiate formulas. # from collections import defaultdict from itertools import product from sympy import SYMPY_DEBUG from sympy.core import (S, Dummy, symbols, sympify, Tuple, expand, I, pi, Mul, EulerGamma, oo, zoo, expand_func, Add, nan, Expr, Rational) from sympy.core.compatibility import default_sort_key, reduce from sympy.core.mod import Mod from sympy.functions import (exp, sqrt, root, log, lowergamma, cos, besseli, gamma, uppergamma, expint, erf, sin, besselj, Ei, Ci, Si, Shi, sinh, cosh, Chi, fresnels, fresnelc, polar_lift, exp_polar, floor, ceiling, rf, factorial, lerchphi, Piecewise, re, elliptic_k, elliptic_e) from sympy.functions.elementary.complexes import polarify, unpolarify from sympy.functions.special.hyper import (hyper, HyperRep_atanh, HyperRep_power1, HyperRep_power2, HyperRep_log1, HyperRep_asin1, HyperRep_asin2, HyperRep_sqrts1, HyperRep_sqrts2, HyperRep_log2, HyperRep_cosasin, HyperRep_sinasin, meijerg) from sympy.polys import poly, Poly from sympy.series import residue from sympy.simplify import simplify # type: ignore from sympy.simplify.powsimp import powdenest from sympy.utilities.iterables import sift # function to define "buckets" def _mod1(x): # TODO see if this can work as Mod(x, 1); this will require # different handling of the "buckets" since these need to # be sorted and that fails when there is a mixture of # integers and expressions with parameters. With the current # Mod behavior, Mod(k, 1) == Mod(1, 1) == 0 if k is an integer. # Although the sorting can be done with Basic.compare, this may # still require different handling of the sorted buckets. if x.is_Number: return Mod(x, 1) c, x = x.as_coeff_Add() return Mod(c, 1) + x # leave add formulae at the top for easy reference def add_formulae(formulae): """ Create our knowledge base. """ from sympy.matrices import Matrix a, b, c, z = symbols('a b c, z', cls=Dummy) def add(ap, bq, res): func = Hyper_Function(ap, bq) formulae.append(Formula(func, z, res, (a, b, c))) def addb(ap, bq, B, C, M): func = Hyper_Function(ap, bq) formulae.append(Formula(func, z, None, (a, b, c), B, C, M)) # Luke, Y. L. (1969), The Special Functions and Their Approximations, # Volume 1, section 6.2 # 0F0 add((), (), exp(z)) # 1F0 add((a, ), (), HyperRep_power1(-a, z)) # 2F1 addb((a, a - S.Half), (2*a, ), Matrix([HyperRep_power2(a, z), HyperRep_power2(a + S.Half, z)/2]), Matrix([[1, 0]]), Matrix([[(a - S.Half)*z/(1 - z), (S.Half - a)*z/(1 - z)], [a/(1 - z), a*(z - 2)/(1 - z)]])) addb((1, 1), (2, ), Matrix([HyperRep_log1(z), 1]), Matrix([[-1/z, 0]]), Matrix([[0, z/(z - 1)], [0, 0]])) addb((S.Half, 1), (S('3/2'), ), Matrix([HyperRep_atanh(z), 1]), Matrix([[1, 0]]), Matrix([[Rational(-1, 2), 1/(1 - z)/2], [0, 0]])) addb((S.Half, S.Half), (S('3/2'), ), Matrix([HyperRep_asin1(z), HyperRep_power1(Rational(-1, 2), z)]), Matrix([[1, 0]]), Matrix([[Rational(-1, 2), S.Half], [0, z/(1 - z)/2]])) addb((a, S.Half + a), (S.Half, ), Matrix([HyperRep_sqrts1(-a, z), -HyperRep_sqrts2(-a - S.Half, z)]), Matrix([[1, 0]]), Matrix([[0, -a], [z*(-2*a - 1)/2/(1 - z), S.Half - z*(-2*a - 1)/(1 - z)]])) # A. P. Prudnikov, Yu. A. Brychkov and O. I. Marichev (1990). # Integrals and Series: More Special Functions, Vol. 3,. # Gordon and Breach Science Publisher addb([a, -a], [S.Half], Matrix([HyperRep_cosasin(a, z), HyperRep_sinasin(a, z)]), Matrix([[1, 0]]), Matrix([[0, -a], [a*z/(1 - z), 1/(1 - z)/2]])) addb([1, 1], [3*S.Half], Matrix([HyperRep_asin2(z), 1]), Matrix([[1, 0]]), Matrix([[(z - S.Half)/(1 - z), 1/(1 - z)/2], [0, 0]])) # Complete elliptic integrals K(z) and E(z), both a 2F1 function addb([S.Half, S.Half], [S.One], Matrix([elliptic_k(z), elliptic_e(z)]), Matrix([[2/pi, 0]]), Matrix([[Rational(-1, 2), -1/(2*z-2)], [Rational(-1, 2), S.Half]])) addb([Rational(-1, 2), S.Half], [S.One], Matrix([elliptic_k(z), elliptic_e(z)]), Matrix([[0, 2/pi]]), Matrix([[Rational(-1, 2), -1/(2*z-2)], [Rational(-1, 2), S.Half]])) # 3F2 addb([Rational(-1, 2), 1, 1], [S.Half, 2], Matrix([z*HyperRep_atanh(z), HyperRep_log1(z), 1]), Matrix([[Rational(-2, 3), -S.One/(3*z), Rational(2, 3)]]), Matrix([[S.Half, 0, z/(1 - z)/2], [0, 0, z/(z - 1)], [0, 0, 0]])) # actually the formula for 3/2 is much nicer ... addb([Rational(-1, 2), 1, 1], [2, 2], Matrix([HyperRep_power1(S.Half, z), HyperRep_log2(z), 1]), Matrix([[Rational(4, 9) - 16/(9*z), 4/(3*z), 16/(9*z)]]), Matrix([[z/2/(z - 1), 0, 0], [1/(2*(z - 1)), 0, S.Half], [0, 0, 0]])) # 1F1 addb([1], [b], Matrix([z**(1 - b) * exp(z) * lowergamma(b - 1, z), 1]), Matrix([[b - 1, 0]]), Matrix([[1 - b + z, 1], [0, 0]])) addb([a], [2*a], Matrix([z**(S.Half - a)*exp(z/2)*besseli(a - S.Half, z/2) * gamma(a + S.Half)/4**(S.Half - a), z**(S.Half - a)*exp(z/2)*besseli(a + S.Half, z/2) * gamma(a + S.Half)/4**(S.Half - a)]), Matrix([[1, 0]]), Matrix([[z/2, z/2], [z/2, (z/2 - 2*a)]])) mz = polar_lift(-1)*z addb([a], [a + 1], Matrix([mz**(-a)*a*lowergamma(a, mz), a*exp(z)]), Matrix([[1, 0]]), Matrix([[-a, 1], [0, z]])) # This one is redundant. add([Rational(-1, 2)], [S.Half], exp(z) - sqrt(pi*z)*(-I)*erf(I*sqrt(z))) # Added to get nice results for Laplace transform of Fresnel functions # http://functions.wolfram.com/07.22.03.6437.01 # Basic rule #add([1], [Rational(3, 4), Rational(5, 4)], # sqrt(pi) * (cos(2*sqrt(polar_lift(-1)*z))*fresnelc(2*root(polar_lift(-1)*z,4)/sqrt(pi)) + # sin(2*sqrt(polar_lift(-1)*z))*fresnels(2*root(polar_lift(-1)*z,4)/sqrt(pi))) # / (2*root(polar_lift(-1)*z,4))) # Manually tuned rule addb([1], [Rational(3, 4), Rational(5, 4)], Matrix([ sqrt(pi)*(I*sinh(2*sqrt(z))*fresnels(2*root(z, 4)*exp(I*pi/4)/sqrt(pi)) + cosh(2*sqrt(z))*fresnelc(2*root(z, 4)*exp(I*pi/4)/sqrt(pi))) * exp(-I*pi/4)/(2*root(z, 4)), sqrt(pi)*root(z, 4)*(sinh(2*sqrt(z))*fresnelc(2*root(z, 4)*exp(I*pi/4)/sqrt(pi)) + I*cosh(2*sqrt(z))*fresnels(2*root(z, 4)*exp(I*pi/4)/sqrt(pi))) *exp(-I*pi/4)/2, 1 ]), Matrix([[1, 0, 0]]), Matrix([[Rational(-1, 4), 1, Rational(1, 4)], [ z, Rational(1, 4), 0], [ 0, 0, 0]])) # 2F2 addb([S.Half, a], [Rational(3, 2), a + 1], Matrix([a/(2*a - 1)*(-I)*sqrt(pi/z)*erf(I*sqrt(z)), a/(2*a - 1)*(polar_lift(-1)*z)**(-a)* lowergamma(a, polar_lift(-1)*z), a/(2*a - 1)*exp(z)]), Matrix([[1, -1, 0]]), Matrix([[Rational(-1, 2), 0, 1], [0, -a, 1], [0, 0, z]])) # We make a "basis" of four functions instead of three, and give EulerGamma # an extra slot (it could just be a coefficient to 1). The advantage is # that this way Polys will not see multivariate polynomials (it treats # EulerGamma as an indeterminate), which is *way* faster. addb([1, 1], [2, 2], Matrix([Ei(z) - log(z), exp(z), 1, EulerGamma]), Matrix([[1/z, 0, 0, -1/z]]), Matrix([[0, 1, -1, 0], [0, z, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]])) # 0F1 add((), (S.Half, ), cosh(2*sqrt(z))) addb([], [b], Matrix([gamma(b)*z**((1 - b)/2)*besseli(b - 1, 2*sqrt(z)), gamma(b)*z**(1 - b/2)*besseli(b, 2*sqrt(z))]), Matrix([[1, 0]]), Matrix([[0, 1], [z, (1 - b)]])) # 0F3 x = 4*z**Rational(1, 4) def fp(a, z): return besseli(a, x) + besselj(a, x) def fm(a, z): return besseli(a, x) - besselj(a, x) # TODO branching addb([], [S.Half, a, a + S.Half], Matrix([fp(2*a - 1, z), fm(2*a, z)*z**Rational(1, 4), fm(2*a - 1, z)*sqrt(z), fp(2*a, z)*z**Rational(3, 4)]) * 2**(-2*a)*gamma(2*a)*z**((1 - 2*a)/4), Matrix([[1, 0, 0, 0]]), Matrix([[0, 1, 0, 0], [0, S.Half - a, 1, 0], [0, 0, S.Half, 1], [z, 0, 0, 1 - a]])) x = 2*(4*z)**Rational(1, 4)*exp_polar(I*pi/4) addb([], [a, a + S.Half, 2*a], (2*sqrt(polar_lift(-1)*z))**(1 - 2*a)*gamma(2*a)**2 * Matrix([besselj(2*a - 1, x)*besseli(2*a - 1, x), x*(besseli(2*a, x)*besselj(2*a - 1, x) - besseli(2*a - 1, x)*besselj(2*a, x)), x**2*besseli(2*a, x)*besselj(2*a, x), x**3*(besseli(2*a, x)*besselj(2*a - 1, x) + besseli(2*a - 1, x)*besselj(2*a, x))]), Matrix([[1, 0, 0, 0]]), Matrix([[0, Rational(1, 4), 0, 0], [0, (1 - 2*a)/2, Rational(-1, 2), 0], [0, 0, 1 - 2*a, Rational(1, 4)], [-32*z, 0, 0, 1 - a]])) # 1F2 addb([a], [a - S.Half, 2*a], Matrix([z**(S.Half - a)*besseli(a - S.Half, sqrt(z))**2, z**(1 - a)*besseli(a - S.Half, sqrt(z)) *besseli(a - Rational(3, 2), sqrt(z)), z**(Rational(3, 2) - a)*besseli(a - Rational(3, 2), sqrt(z))**2]), Matrix([[-gamma(a + S.Half)**2/4**(S.Half - a), 2*gamma(a - S.Half)*gamma(a + S.Half)/4**(1 - a), 0]]), Matrix([[1 - 2*a, 1, 0], [z/2, S.Half - a, S.Half], [0, z, 0]])) addb([S.Half], [b, 2 - b], pi*(1 - b)/sin(pi*b)* Matrix([besseli(1 - b, sqrt(z))*besseli(b - 1, sqrt(z)), sqrt(z)*(besseli(-b, sqrt(z))*besseli(b - 1, sqrt(z)) + besseli(1 - b, sqrt(z))*besseli(b, sqrt(z))), besseli(-b, sqrt(z))*besseli(b, sqrt(z))]), Matrix([[1, 0, 0]]), Matrix([[b - 1, S.Half, 0], [z, 0, z], [0, S.Half, -b]])) addb([S.Half], [Rational(3, 2), Rational(3, 2)], Matrix([Shi(2*sqrt(z))/2/sqrt(z), sinh(2*sqrt(z))/2/sqrt(z), cosh(2*sqrt(z))]), Matrix([[1, 0, 0]]), Matrix([[Rational(-1, 2), S.Half, 0], [0, Rational(-1, 2), S.Half], [0, 2*z, 0]])) # FresnelS # Basic rule #add([Rational(3, 4)], [Rational(3, 2),Rational(7, 4)], 6*fresnels( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) / ( pi * (exp(pi*I/4)*root(z,4)*2/sqrt(pi))**3 ) ) # Manually tuned rule addb([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)], Matrix( [ fresnels( exp( pi*I/4)*root( z, 4)*2/sqrt( pi) ) / ( pi * (exp(pi*I/4)*root(z, 4)*2/sqrt(pi))**3 ), sinh(2*sqrt(z))/sqrt(z), cosh(2*sqrt(z)) ]), Matrix([[6, 0, 0]]), Matrix([[Rational(-3, 4), Rational(1, 16), 0], [ 0, Rational(-1, 2), 1], [ 0, z, 0]])) # FresnelC # Basic rule #add([Rational(1, 4)], [S.Half,Rational(5, 4)], fresnelc( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) / ( exp(pi*I/4)*root(z,4)*2/sqrt(pi) ) ) # Manually tuned rule addb([Rational(1, 4)], [S.Half, Rational(5, 4)], Matrix( [ sqrt( pi)*exp( -I*pi/4)*fresnelc( 2*root(z, 4)*exp(I*pi/4)/sqrt(pi))/(2*root(z, 4)), cosh(2*sqrt(z)), sinh(2*sqrt(z))*sqrt(z) ]), Matrix([[1, 0, 0]]), Matrix([[Rational(-1, 4), Rational(1, 4), 0 ], [ 0, 0, 1 ], [ 0, z, S.Half]])) # 2F3 # XXX with this five-parameter formula is pretty slow with the current # Formula.find_instantiations (creates 2!*3!*3**(2+3) ~ 3000 # instantiations ... But it's not too bad. addb([a, a + S.Half], [2*a, b, 2*a - b + 1], gamma(b)*gamma(2*a - b + 1) * (sqrt(z)/2)**(1 - 2*a) * Matrix([besseli(b - 1, sqrt(z))*besseli(2*a - b, sqrt(z)), sqrt(z)*besseli(b, sqrt(z))*besseli(2*a - b, sqrt(z)), sqrt(z)*besseli(b - 1, sqrt(z))*besseli(2*a - b + 1, sqrt(z)), besseli(b, sqrt(z))*besseli(2*a - b + 1, sqrt(z))]), Matrix([[1, 0, 0, 0]]), Matrix([[0, S.Half, S.Half, 0], [z/2, 1 - b, 0, z/2], [z/2, 0, b - 2*a, z/2], [0, S.Half, S.Half, -2*a]])) # (C/f above comment about eulergamma in the basis). addb([1, 1], [2, 2, Rational(3, 2)], Matrix([Chi(2*sqrt(z)) - log(2*sqrt(z)), cosh(2*sqrt(z)), sqrt(z)*sinh(2*sqrt(z)), 1, EulerGamma]), Matrix([[1/z, 0, 0, 0, -1/z]]), Matrix([[0, S.Half, 0, Rational(-1, 2), 0], [0, 0, 1, 0, 0], [0, z, S.Half, 0, 0], [0, 0, 0, 0, 0], [0, 0, 0, 0, 0]])) # 3F3 # This is rule: http://functions.wolfram.com/07.31.03.0134.01 # Initial reason to add it was a nice solution for # integrate(erf(a*z)/z**2, z) and same for erfc and erfi. # Basic rule # add([1, 1, a], [2, 2, a+1], (a/(z*(a-1)**2)) * # (1 - (-z)**(1-a) * (gamma(a) - uppergamma(a,-z)) # - (a-1) * (EulerGamma + uppergamma(0,-z) + log(-z)) # - exp(z))) # Manually tuned rule addb([1, 1, a], [2, 2, a+1], Matrix([a*(log(-z) + expint(1, -z) + EulerGamma)/(z*(a**2 - 2*a + 1)), a*(-z)**(-a)*(gamma(a) - uppergamma(a, -z))/(a - 1)**2, a*exp(z)/(a**2 - 2*a + 1), a/(z*(a**2 - 2*a + 1))]), Matrix([[1-a, 1, -1/z, 1]]), Matrix([[-1,0,-1/z,1], [0,-a,1,0], [0,0,z,0], [0,0,0,-1]])) def add_meijerg_formulae(formulae): from sympy.matrices import Matrix a, b, c, z = list(map(Dummy, 'abcz')) rho = Dummy('rho') def add(an, ap, bm, bq, B, C, M, matcher): formulae.append(MeijerFormula(an, ap, bm, bq, z, [a, b, c, rho], B, C, M, matcher)) def detect_uppergamma(func): x = func.an[0] y, z = func.bm swapped = False if not _mod1((x - y).simplify()): swapped = True (y, z) = (z, y) if _mod1((x - z).simplify()) or x - z > 0: return None l = [y, x] if swapped: l = [x, y] return {rho: y, a: x - y}, G_Function([x], [], l, []) add([a + rho], [], [rho, a + rho], [], Matrix([gamma(1 - a)*z**rho*exp(z)*uppergamma(a, z), gamma(1 - a)*z**(a + rho)]), Matrix([[1, 0]]), Matrix([[rho + z, -1], [0, a + rho]]), detect_uppergamma) def detect_3113(func): """http://functions.wolfram.com/07.34.03.0984.01""" x = func.an[0] u, v, w = func.bm if _mod1((u - v).simplify()) == 0: if _mod1((v - w).simplify()) == 0: return sig = (S.Half, S.Half, S.Zero) x1, x2, y = u, v, w else: if _mod1((x - u).simplify()) == 0: sig = (S.Half, S.Zero, S.Half) x1, y, x2 = u, v, w else: sig = (S.Zero, S.Half, S.Half) y, x1, x2 = u, v, w if (_mod1((x - x1).simplify()) != 0 or _mod1((x - x2).simplify()) != 0 or _mod1((x - y).simplify()) != S.Half or x - x1 > 0 or x - x2 > 0): return return {a: x}, G_Function([x], [], [x - S.Half + t for t in sig], []) s = sin(2*sqrt(z)) c_ = cos(2*sqrt(z)) S_ = Si(2*sqrt(z)) - pi/2 C = Ci(2*sqrt(z)) add([a], [], [a, a, a - S.Half], [], Matrix([sqrt(pi)*z**(a - S.Half)*(c_*S_ - s*C), sqrt(pi)*z**a*(s*S_ + c_*C), sqrt(pi)*z**a]), Matrix([[-2, 0, 0]]), Matrix([[a - S.Half, -1, 0], [z, a, S.Half], [0, 0, a]]), detect_3113) def make_simp(z): """ Create a function that simplifies rational functions in ``z``. """ def simp(expr): """ Efficiently simplify the rational function ``expr``. """ numer, denom = expr.as_numer_denom() numer = numer.expand() # denom = denom.expand() # is this needed? c, numer, denom = poly(numer, z).cancel(poly(denom, z)) return c * numer.as_expr() / denom.as_expr() return simp def debug(*args): if SYMPY_DEBUG: for a in args: print(a, end="") print() class Hyper_Function(Expr): """ A generalized hypergeometric function. """ def __new__(cls, ap, bq): obj = super().__new__(cls) obj.ap = Tuple(*list(map(expand, ap))) obj.bq = Tuple(*list(map(expand, bq))) return obj @property def args(self): return (self.ap, self.bq) @property def sizes(self): return (len(self.ap), len(self.bq)) @property def gamma(self): """ Number of upper parameters that are negative integers This is a transformation invariant. """ return sum(bool(x.is_integer and x.is_negative) for x in self.ap) def _hashable_content(self): return super()._hashable_content() + (self.ap, self.bq) def __call__(self, arg): return hyper(self.ap, self.bq, arg) def build_invariants(self): """ Compute the invariant vector. Explanation =========== The invariant vector is: (gamma, ((s1, n1), ..., (sk, nk)), ((t1, m1), ..., (tr, mr))) where gamma is the number of integer a < 0, s1 < ... < sk nl is the number of parameters a_i congruent to sl mod 1 t1 < ... < tr ml is the number of parameters b_i congruent to tl mod 1 If the index pair contains parameters, then this is not truly an invariant, since the parameters cannot be sorted uniquely mod1. Examples ======== >>> from sympy.simplify.hyperexpand import Hyper_Function >>> from sympy import S >>> ap = (S.Half, S.One/3, S(-1)/2, -2) >>> bq = (1, 2) Here gamma = 1, k = 3, s1 = 0, s2 = 1/3, s3 = 1/2 n1 = 1, n2 = 1, n2 = 2 r = 1, t1 = 0 m1 = 2: >>> Hyper_Function(ap, bq).build_invariants() (1, ((0, 1), (1/3, 1), (1/2, 2)), ((0, 2),)) """ abuckets, bbuckets = sift(self.ap, _mod1), sift(self.bq, _mod1) def tr(bucket): bucket = list(bucket.items()) if not any(isinstance(x[0], Mod) for x in bucket): bucket.sort(key=lambda x: default_sort_key(x[0])) bucket = tuple([(mod, len(values)) for mod, values in bucket if values]) return bucket return (self.gamma, tr(abuckets), tr(bbuckets)) def difficulty(self, func): """ Estimate how many steps it takes to reach ``func`` from self. Return -1 if impossible. """ if self.gamma != func.gamma: return -1 oabuckets, obbuckets, abuckets, bbuckets = [sift(params, _mod1) for params in (self.ap, self.bq, func.ap, func.bq)] diff = 0 for bucket, obucket in [(abuckets, oabuckets), (bbuckets, obbuckets)]: for mod in set(list(bucket.keys()) + list(obucket.keys())): if (not mod in bucket) or (not mod in obucket) \ or len(bucket[mod]) != len(obucket[mod]): return -1 l1 = list(bucket[mod]) l2 = list(obucket[mod]) l1.sort() l2.sort() for i, j in zip(l1, l2): diff += abs(i - j) return diff def _is_suitable_origin(self): """ Decide if ``self`` is a suitable origin. Explanation =========== A function is a suitable origin iff: * none of the ai equals bj + n, with n a non-negative integer * none of the ai is zero * none of the bj is a non-positive integer Note that this gives meaningful results only when none of the indices are symbolic. """ for a in self.ap: for b in self.bq: if (a - b).is_integer and (a - b).is_negative is False: return False for a in self.ap: if a == 0: return False for b in self.bq: if b.is_integer and b.is_nonpositive: return False return True class G_Function(Expr): """ A Meijer G-function. """ def __new__(cls, an, ap, bm, bq): obj = super().__new__(cls) obj.an = Tuple(*list(map(expand, an))) obj.ap = Tuple(*list(map(expand, ap))) obj.bm = Tuple(*list(map(expand, bm))) obj.bq = Tuple(*list(map(expand, bq))) return obj @property def args(self): return (self.an, self.ap, self.bm, self.bq) def _hashable_content(self): return super()._hashable_content() + self.args def __call__(self, z): return meijerg(self.an, self.ap, self.bm, self.bq, z) def compute_buckets(self): """ Compute buckets for the fours sets of parameters. Explanation =========== We guarantee that any two equal Mod objects returned are actually the same, and that the buckets are sorted by real part (an and bq descendending, bm and ap ascending). Examples ======== >>> from sympy.simplify.hyperexpand import G_Function >>> from sympy.abc import y >>> from sympy import S >>> a, b = [1, 3, 2, S(3)/2], [1 + y, y, 2, y + 3] >>> G_Function(a, b, [2], [y]).compute_buckets() ({0: [3, 2, 1], 1/2: [3/2]}, {0: [2], y: [y, y + 1, y + 3]}, {0: [2]}, {y: [y]}) """ dicts = pan, pap, pbm, pbq = [defaultdict(list) for i in range(4)] for dic, lis in zip(dicts, (self.an, self.ap, self.bm, self.bq)): for x in lis: dic[_mod1(x)].append(x) for dic, flip in zip(dicts, (True, False, False, True)): for m, items in dic.items(): x0 = items[0] items.sort(key=lambda x: x - x0, reverse=flip) dic[m] = items return tuple([dict(w) for w in dicts]) @property def signature(self): return (len(self.an), len(self.ap), len(self.bm), len(self.bq)) # Dummy variable. _x = Dummy('x') class Formula: """ This class represents hypergeometric formulae. Explanation =========== Its data members are: - z, the argument - closed_form, the closed form expression - symbols, the free symbols (parameters) in the formula - func, the function - B, C, M (see _compute_basis) Examples ======== >>> from sympy.abc import a, b, z >>> from sympy.simplify.hyperexpand import Formula, Hyper_Function >>> func = Hyper_Function((a/2, a/3 + b, (1+a)/2), (a, b, (a+b)/7)) >>> f = Formula(func, z, None, [a, b]) """ def _compute_basis(self, closed_form): """ Compute a set of functions B=(f1, ..., fn), a nxn matrix M and a 1xn matrix C such that: closed_form = C B z d/dz B = M B. """ from sympy.matrices import Matrix, eye, zeros afactors = [_x + a for a in self.func.ap] bfactors = [_x + b - 1 for b in self.func.bq] expr = _x*Mul(*bfactors) - self.z*Mul(*afactors) poly = Poly(expr, _x) n = poly.degree() - 1 b = [closed_form] for _ in range(n): b.append(self.z*b[-1].diff(self.z)) self.B = Matrix(b) self.C = Matrix([[1] + [0]*n]) m = eye(n) m = m.col_insert(0, zeros(n, 1)) l = poly.all_coeffs()[1:] l.reverse() self.M = m.row_insert(n, -Matrix([l])/poly.all_coeffs()[0]) def __init__(self, func, z, res, symbols, B=None, C=None, M=None): z = sympify(z) res = sympify(res) symbols = [x for x in sympify(symbols) if func.has(x)] self.z = z self.symbols = symbols self.B = B self.C = C self.M = M self.func = func # TODO with symbolic parameters, it could be advantageous # (for prettier answers) to compute a basis only *after* # instantiation if res is not None: self._compute_basis(res) @property def closed_form(self): return reduce(lambda s,m: s+m[0]*m[1], zip(self.C, self.B), S.Zero) def find_instantiations(self, func): """ Find substitutions of the free symbols that match ``func``. Return the substitution dictionaries as a list. Note that the returned instantiations need not actually match, or be valid! """ from sympy.solvers import solve ap = func.ap bq = func.bq if len(ap) != len(self.func.ap) or len(bq) != len(self.func.bq): raise TypeError('Cannot instantiate other number of parameters') symbol_values = [] for a in self.symbols: if a in self.func.ap.args: symbol_values.append(ap) elif a in self.func.bq.args: symbol_values.append(bq) else: raise ValueError("At least one of the parameters of the " "formula must be equal to %s" % (a,)) base_repl = [dict(list(zip(self.symbols, values))) for values in product(*symbol_values)] abuckets, bbuckets = [sift(params, _mod1) for params in [ap, bq]] a_inv, b_inv = [{a: len(vals) for a, vals in bucket.items()} for bucket in [abuckets, bbuckets]] critical_values = [[0] for _ in self.symbols] result = [] _n = Dummy() for repl in base_repl: symb_a, symb_b = [sift(params, lambda x: _mod1(x.xreplace(repl))) for params in [self.func.ap, self.func.bq]] for bucket, obucket in [(abuckets, symb_a), (bbuckets, symb_b)]: for mod in set(list(bucket.keys()) + list(obucket.keys())): if (not mod in bucket) or (not mod in obucket) \ or len(bucket[mod]) != len(obucket[mod]): break for a, vals in zip(self.symbols, critical_values): if repl[a].free_symbols: continue exprs = [expr for expr in obucket[mod] if expr.has(a)] repl0 = repl.copy() repl0[a] += _n for expr in exprs: for target in bucket[mod]: n0, = solve(expr.xreplace(repl0) - target, _n) if n0.free_symbols: raise ValueError("Value should not be true") vals.append(n0) else: values = [] for a, vals in zip(self.symbols, critical_values): a0 = repl[a] min_ = floor(min(vals)) max_ = ceiling(max(vals)) values.append([a0 + n for n in range(min_, max_ + 1)]) result.extend(dict(list(zip(self.symbols, l))) for l in product(*values)) return result class FormulaCollection: """ A collection of formulae to use as origins. """ def __init__(self): """ Doing this globally at module init time is a pain ... """ self.symbolic_formulae = {} self.concrete_formulae = {} self.formulae = [] add_formulae(self.formulae) # Now process the formulae into a helpful form. # These dicts are indexed by (p, q). for f in self.formulae: sizes = f.func.sizes if len(f.symbols) > 0: self.symbolic_formulae.setdefault(sizes, []).append(f) else: inv = f.func.build_invariants() self.concrete_formulae.setdefault(sizes, {})[inv] = f def lookup_origin(self, func): """ Given the suitable target ``func``, try to find an origin in our knowledge base. Examples ======== >>> from sympy.simplify.hyperexpand import (FormulaCollection, ... Hyper_Function) >>> f = FormulaCollection() >>> f.lookup_origin(Hyper_Function((), ())).closed_form exp(_z) >>> f.lookup_origin(Hyper_Function([1], ())).closed_form HyperRep_power1(-1, _z) >>> from sympy import S >>> i = Hyper_Function([S('1/4'), S('3/4 + 4')], [S.Half]) >>> f.lookup_origin(i).closed_form HyperRep_sqrts1(-1/4, _z) """ inv = func.build_invariants() sizes = func.sizes if sizes in self.concrete_formulae and \ inv in self.concrete_formulae[sizes]: return self.concrete_formulae[sizes][inv] # We don't have a concrete formula. Try to instantiate. if not sizes in self.symbolic_formulae: return None # Too bad... possible = [] for f in self.symbolic_formulae[sizes]: repls = f.find_instantiations(func) for repl in repls: func2 = f.func.xreplace(repl) if not func2._is_suitable_origin(): continue diff = func2.difficulty(func) if diff == -1: continue possible.append((diff, repl, f, func2)) # find the nearest origin possible.sort(key=lambda x: x[0]) for _, repl, f, func2 in possible: f2 = Formula(func2, f.z, None, [], f.B.subs(repl), f.C.subs(repl), f.M.subs(repl)) if not any(e.has(S.NaN, oo, -oo, zoo) for e in [f2.B, f2.M, f2.C]): return f2 return None class MeijerFormula: """ This class represents a Meijer G-function formula. Its data members are: - z, the argument - symbols, the free symbols (parameters) in the formula - func, the function - B, C, M (c/f ordinary Formula) """ def __init__(self, an, ap, bm, bq, z, symbols, B, C, M, matcher): an, ap, bm, bq = [Tuple(*list(map(expand, w))) for w in [an, ap, bm, bq]] self.func = G_Function(an, ap, bm, bq) self.z = z self.symbols = symbols self._matcher = matcher self.B = B self.C = C self.M = M @property def closed_form(self): return reduce(lambda s,m: s+m[0]*m[1], zip(self.C, self.B), S.Zero) def try_instantiate(self, func): """ Try to instantiate the current formula to (almost) match func. This uses the _matcher passed on init. """ if func.signature != self.func.signature: return None res = self._matcher(func) if res is not None: subs, newfunc = res return MeijerFormula(newfunc.an, newfunc.ap, newfunc.bm, newfunc.bq, self.z, [], self.B.subs(subs), self.C.subs(subs), self.M.subs(subs), None) class MeijerFormulaCollection: """ This class holds a collection of meijer g formulae. """ def __init__(self): formulae = [] add_meijerg_formulae(formulae) self.formulae = defaultdict(list) for formula in formulae: self.formulae[formula.func.signature].append(formula) self.formulae = dict(self.formulae) def lookup_origin(self, func): """ Try to find a formula that matches func. """ if not func.signature in self.formulae: return None for formula in self.formulae[func.signature]: res = formula.try_instantiate(func) if res is not None: return res class Operator: """ Base class for operators to be applied to our functions. Explanation =========== These operators are differential operators. They are by convention expressed in the variable D = z*d/dz (although this base class does not actually care). Note that when the operator is applied to an object, we typically do *not* blindly differentiate but instead use a different representation of the z*d/dz operator (see make_derivative_operator). To subclass from this, define a __init__ method that initializes a self._poly variable. This variable stores a polynomial. By convention the generator is z*d/dz, and acts to the right of all coefficients. Thus this poly x**2 + 2*z*x + 1 represents the differential operator (z*d/dz)**2 + 2*z**2*d/dz. This class is used only in the implementation of the hypergeometric function expansion algorithm. """ def apply(self, obj, op): """ Apply ``self`` to the object ``obj``, where the generator is ``op``. Examples ======== >>> from sympy.simplify.hyperexpand import Operator >>> from sympy.polys.polytools import Poly >>> from sympy.abc import x, y, z >>> op = Operator() >>> op._poly = Poly(x**2 + z*x + y, x) >>> op.apply(z**7, lambda f: f.diff(z)) y*z**7 + 7*z**7 + 42*z**5 """ coeffs = self._poly.all_coeffs() coeffs.reverse() diffs = [obj] for c in coeffs[1:]: diffs.append(op(diffs[-1])) r = coeffs[0]*diffs[0] for c, d in zip(coeffs[1:], diffs[1:]): r += c*d return r class MultOperator(Operator): """ Simply multiply by a "constant" """ def __init__(self, p): self._poly = Poly(p, _x) class ShiftA(Operator): """ Increment an upper index. """ def __init__(self, ai): ai = sympify(ai) if ai == 0: raise ValueError('Cannot increment zero upper index.') self._poly = Poly(_x/ai + 1, _x) def __str__(self): return '' % (1/self._poly.all_coeffs()[0]) class ShiftB(Operator): """ Decrement a lower index. """ def __init__(self, bi): bi = sympify(bi) if bi == 1: raise ValueError('Cannot decrement unit lower index.') self._poly = Poly(_x/(bi - 1) + 1, _x) def __str__(self): return '' % (1/self._poly.all_coeffs()[0] + 1) class UnShiftA(Operator): """ Decrement an upper index. """ def __init__(self, ap, bq, i, z): """ Note: i counts from zero! """ ap, bq, i = list(map(sympify, [ap, bq, i])) self._ap = ap self._bq = bq self._i = i ap = list(ap) bq = list(bq) ai = ap.pop(i) - 1 if ai == 0: raise ValueError('Cannot decrement unit upper index.') m = Poly(z*ai, _x) for a in ap: m *= Poly(_x + a, _x) A = Dummy('A') n = D = Poly(ai*A - ai, A) for b in bq: n *= D + (b - 1).as_poly(A) b0 = -n.nth(0) if b0 == 0: raise ValueError('Cannot decrement upper index: ' 'cancels with lower') n = Poly(Poly(n.all_coeffs()[:-1], A).as_expr().subs(A, _x/ai + 1), _x) self._poly = Poly((n - m)/b0, _x) def __str__(self): return '' % (self._i, self._ap, self._bq) class UnShiftB(Operator): """ Increment a lower index. """ def __init__(self, ap, bq, i, z): """ Note: i counts from zero! """ ap, bq, i = list(map(sympify, [ap, bq, i])) self._ap = ap self._bq = bq self._i = i ap = list(ap) bq = list(bq) bi = bq.pop(i) + 1 if bi == 0: raise ValueError('Cannot increment -1 lower index.') m = Poly(_x*(bi - 1), _x) for b in bq: m *= Poly(_x + b - 1, _x) B = Dummy('B') D = Poly((bi - 1)*B - bi + 1, B) n = Poly(z, B) for a in ap: n *= (D + a.as_poly(B)) b0 = n.nth(0) if b0 == 0: raise ValueError('Cannot increment index: cancels with upper') n = Poly(Poly(n.all_coeffs()[:-1], B).as_expr().subs( B, _x/(bi - 1) + 1), _x) self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, self._ap, self._bq) class MeijerShiftA(Operator): """ Increment an upper b index. """ def __init__(self, bi): bi = sympify(bi) self._poly = Poly(bi - _x, _x) def __str__(self): return '' % (self._poly.all_coeffs()[1]) class MeijerShiftB(Operator): """ Decrement an upper a index. """ def __init__(self, bi): bi = sympify(bi) self._poly = Poly(1 - bi + _x, _x) def __str__(self): return '' % (1 - self._poly.all_coeffs()[1]) class MeijerShiftC(Operator): """ Increment a lower b index. """ def __init__(self, bi): bi = sympify(bi) self._poly = Poly(-bi + _x, _x) def __str__(self): return '' % (-self._poly.all_coeffs()[1]) class MeijerShiftD(Operator): """ Decrement a lower a index. """ def __init__(self, bi): bi = sympify(bi) self._poly = Poly(bi - 1 - _x, _x) def __str__(self): return '' % (self._poly.all_coeffs()[1] + 1) class MeijerUnShiftA(Operator): """ Decrement an upper b index. """ def __init__(self, an, ap, bm, bq, i, z): """ Note: i counts from zero! """ an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) self._an = an self._ap = ap self._bm = bm self._bq = bq self._i = i an = list(an) ap = list(ap) bm = list(bm) bq = list(bq) bi = bm.pop(i) - 1 m = Poly(1, _x) for b in bm: m *= Poly(b - _x, _x) for b in bq: m *= Poly(_x - b, _x) A = Dummy('A') D = Poly(bi - A, A) n = Poly(z, A) for a in an: n *= (D + 1 - a) for a in ap: n *= (-D + a - 1) b0 = n.nth(0) if b0 == 0: raise ValueError('Cannot decrement upper b index (cancels)') n = Poly(Poly(n.all_coeffs()[:-1], A).as_expr().subs(A, bi - _x), _x) self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, self._an, self._ap, self._bm, self._bq) class MeijerUnShiftB(Operator): """ Increment an upper a index. """ def __init__(self, an, ap, bm, bq, i, z): """ Note: i counts from zero! """ an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) self._an = an self._ap = ap self._bm = bm self._bq = bq self._i = i an = list(an) ap = list(ap) bm = list(bm) bq = list(bq) ai = an.pop(i) + 1 m = Poly(z, _x) for a in an: m *= Poly(1 - a + _x, _x) for a in ap: m *= Poly(a - 1 - _x, _x) B = Dummy('B') D = Poly(B + ai - 1, B) n = Poly(1, B) for b in bm: n *= (-D + b) for b in bq: n *= (D - b) b0 = n.nth(0) if b0 == 0: raise ValueError('Cannot increment upper a index (cancels)') n = Poly(Poly(n.all_coeffs()[:-1], B).as_expr().subs( B, 1 - ai + _x), _x) self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, self._an, self._ap, self._bm, self._bq) class MeijerUnShiftC(Operator): """ Decrement a lower b index. """ # XXX this is "essentially" the same as MeijerUnShiftA. This "essentially" # can be made rigorous using the functional equation G(1/z) = G'(z), # where G' denotes a G function of slightly altered parameters. # However, sorting out the details seems harder than just coding it # again. def __init__(self, an, ap, bm, bq, i, z): """ Note: i counts from zero! """ an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) self._an = an self._ap = ap self._bm = bm self._bq = bq self._i = i an = list(an) ap = list(ap) bm = list(bm) bq = list(bq) bi = bq.pop(i) - 1 m = Poly(1, _x) for b in bm: m *= Poly(b - _x, _x) for b in bq: m *= Poly(_x - b, _x) C = Dummy('C') D = Poly(bi + C, C) n = Poly(z, C) for a in an: n *= (D + 1 - a) for a in ap: n *= (-D + a - 1) b0 = n.nth(0) if b0 == 0: raise ValueError('Cannot decrement lower b index (cancels)') n = Poly(Poly(n.all_coeffs()[:-1], C).as_expr().subs(C, _x - bi), _x) self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, self._an, self._ap, self._bm, self._bq) class MeijerUnShiftD(Operator): """ Increment a lower a index. """ # XXX This is essentially the same as MeijerUnShiftA. # See comment at MeijerUnShiftC. def __init__(self, an, ap, bm, bq, i, z): """ Note: i counts from zero! """ an, ap, bm, bq, i = list(map(sympify, [an, ap, bm, bq, i])) self._an = an self._ap = ap self._bm = bm self._bq = bq self._i = i an = list(an) ap = list(ap) bm = list(bm) bq = list(bq) ai = ap.pop(i) + 1 m = Poly(z, _x) for a in an: m *= Poly(1 - a + _x, _x) for a in ap: m *= Poly(a - 1 - _x, _x) B = Dummy('B') # - this is the shift operator `D_I` D = Poly(ai - 1 - B, B) n = Poly(1, B) for b in bm: n *= (-D + b) for b in bq: n *= (D - b) b0 = n.nth(0) if b0 == 0: raise ValueError('Cannot increment lower a index (cancels)') n = Poly(Poly(n.all_coeffs()[:-1], B).as_expr().subs( B, ai - 1 - _x), _x) self._poly = Poly((m - n)/b0, _x) def __str__(self): return '' % (self._i, self._an, self._ap, self._bm, self._bq) class ReduceOrder(Operator): """ Reduce Order by cancelling an upper and a lower index. """ def __new__(cls, ai, bj): """ For convenience if reduction is not possible, return None. """ ai = sympify(ai) bj = sympify(bj) n = ai - bj if not n.is_Integer or n < 0: return None if bj.is_integer and bj.is_nonpositive: return None expr = Operator.__new__(cls) p = S.One for k in range(n): p *= (_x + bj + k)/(bj + k) expr._poly = Poly(p, _x) expr._a = ai expr._b = bj return expr @classmethod def _meijer(cls, b, a, sign): """ Cancel b + sign*s and a + sign*s This is for meijer G functions. """ b = sympify(b) a = sympify(a) n = b - a if n.is_negative or not n.is_Integer: return None expr = Operator.__new__(cls) p = S.One for k in range(n): p *= (sign*_x + a + k) expr._poly = Poly(p, _x) if sign == -1: expr._a = b expr._b = a else: expr._b = Add(1, a - 1, evaluate=False) expr._a = Add(1, b - 1, evaluate=False) return expr @classmethod def meijer_minus(cls, b, a): return cls._meijer(b, a, -1) @classmethod def meijer_plus(cls, a, b): return cls._meijer(1 - a, 1 - b, 1) def __str__(self): return '' % \ (self._a, self._b) def _reduce_order(ap, bq, gen, key): """ Order reduction algorithm used in Hypergeometric and Meijer G """ ap = list(ap) bq = list(bq) ap.sort(key=key) bq.sort(key=key) nap = [] # we will edit bq in place operators = [] for a in ap: op = None for i in range(len(bq)): op = gen(a, bq[i]) if op is not None: bq.pop(i) break if op is None: nap.append(a) else: operators.append(op) return nap, bq, operators def reduce_order(func): """ Given the hypergeometric function ``func``, find a sequence of operators to reduces order as much as possible. Explanation =========== Return (newfunc, [operators]), where applying the operators to the hypergeometric function newfunc yields func. Examples ======== >>> from sympy.simplify.hyperexpand import reduce_order, Hyper_Function >>> reduce_order(Hyper_Function((1, 2), (3, 4))) (Hyper_Function((1, 2), (3, 4)), []) >>> reduce_order(Hyper_Function((1,), (1,))) (Hyper_Function((), ()), []) >>> reduce_order(Hyper_Function((2, 4), (3, 3))) (Hyper_Function((2,), (3,)), []) """ nap, nbq, operators = _reduce_order(func.ap, func.bq, ReduceOrder, default_sort_key) return Hyper_Function(Tuple(*nap), Tuple(*nbq)), operators def reduce_order_meijer(func): """ Given the Meijer G function parameters, ``func``, find a sequence of operators that reduces order as much as possible. Return newfunc, [operators]. Examples ======== >>> from sympy.simplify.hyperexpand import (reduce_order_meijer, ... G_Function) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 2]))[0] G_Function((4, 3), (5, 6), (3, 4), (2, 1)) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [3, 4], [1, 8]))[0] G_Function((3,), (5, 6), (3, 4), (1,)) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [1, 5]))[0] G_Function((3,), (), (), (1,)) >>> reduce_order_meijer(G_Function([3, 4], [5, 6], [7, 5], [5, 3]))[0] G_Function((), (), (), ()) """ nan, nbq, ops1 = _reduce_order(func.an, func.bq, ReduceOrder.meijer_plus, lambda x: default_sort_key(-x)) nbm, nap, ops2 = _reduce_order(func.bm, func.ap, ReduceOrder.meijer_minus, default_sort_key) return G_Function(nan, nap, nbm, nbq), ops1 + ops2 def make_derivative_operator(M, z): """ Create a derivative operator, to be passed to Operator.apply. """ def doit(C): r = z*C.diff(z) + C*M r = r.applyfunc(make_simp(z)) return r return doit def apply_operators(obj, ops, op): """ Apply the list of operators ``ops`` to object ``obj``, substituting ``op`` for the generator. """ res = obj for o in reversed(ops): res = o.apply(res, op) return res def devise_plan(target, origin, z): """ Devise a plan (consisting of shift and un-shift operators) to be applied to the hypergeometric function ``target`` to yield ``origin``. Returns a list of operators. Examples ======== >>> from sympy.simplify.hyperexpand import devise_plan, Hyper_Function >>> from sympy.abc import z Nothing to do: >>> devise_plan(Hyper_Function((1, 2), ()), Hyper_Function((1, 2), ()), z) [] >>> devise_plan(Hyper_Function((), (1, 2)), Hyper_Function((), (1, 2)), z) [] Very simple plans: >>> devise_plan(Hyper_Function((2,), ()), Hyper_Function((1,), ()), z) [] >>> devise_plan(Hyper_Function((), (2,)), Hyper_Function((), (1,)), z) [] Several buckets: >>> from sympy import S >>> devise_plan(Hyper_Function((1, S.Half), ()), ... Hyper_Function((2, S('3/2')), ()), z) #doctest: +NORMALIZE_WHITESPACE [, ] A slightly more complicated plan: >>> devise_plan(Hyper_Function((1, 3), ()), Hyper_Function((2, 2), ()), z) [, ] Another more complicated plan: (note that the ap have to be shifted first!) >>> devise_plan(Hyper_Function((1, -1), (2,)), Hyper_Function((3, -2), (4,)), z) [, , , , ] """ abuckets, bbuckets, nabuckets, nbbuckets = [sift(params, _mod1) for params in (target.ap, target.bq, origin.ap, origin.bq)] if len(list(abuckets.keys())) != len(list(nabuckets.keys())) or \ len(list(bbuckets.keys())) != len(list(nbbuckets.keys())): raise ValueError('%s not reachable from %s' % (target, origin)) ops = [] def do_shifts(fro, to, inc, dec): ops = [] for i in range(len(fro)): if to[i] - fro[i] > 0: sh = inc ch = 1 else: sh = dec ch = -1 while to[i] != fro[i]: ops += [sh(fro, i)] fro[i] += ch return ops def do_shifts_a(nal, nbk, al, aother, bother): """ Shift us from (nal, nbk) to (al, nbk). """ return do_shifts(nal, al, lambda p, i: ShiftA(p[i]), lambda p, i: UnShiftA(p + aother, nbk + bother, i, z)) def do_shifts_b(nal, nbk, bk, aother, bother): """ Shift us from (nal, nbk) to (nal, bk). """ return do_shifts(nbk, bk, lambda p, i: UnShiftB(nal + aother, p + bother, i, z), lambda p, i: ShiftB(p[i])) for r in sorted(list(abuckets.keys()) + list(bbuckets.keys()), key=default_sort_key): al = () nal = () bk = () nbk = () if r in abuckets: al = abuckets[r] nal = nabuckets[r] if r in bbuckets: bk = bbuckets[r] nbk = nbbuckets[r] if len(al) != len(nal) or len(bk) != len(nbk): raise ValueError('%s not reachable from %s' % (target, origin)) al, nal, bk, nbk = [sorted(list(w), key=default_sort_key) for w in [al, nal, bk, nbk]] def others(dic, key): l = [] for k, value in dic.items(): if k != key: l += list(dic[k]) return l aother = others(nabuckets, r) bother = others(nbbuckets, r) if len(al) == 0: # there can be no complications, just shift the bs as we please ops += do_shifts_b([], nbk, bk, aother, bother) elif len(bk) == 0: # there can be no complications, just shift the as as we please ops += do_shifts_a(nal, [], al, aother, bother) else: namax = nal[-1] amax = al[-1] if nbk[0] - namax <= 0 or bk[0] - amax <= 0: raise ValueError('Non-suitable parameters.') if namax - amax > 0: # we are going to shift down - first do the as, then the bs ops += do_shifts_a(nal, nbk, al, aother, bother) ops += do_shifts_b(al, nbk, bk, aother, bother) else: # we are going to shift up - first do the bs, then the as ops += do_shifts_b(nal, nbk, bk, aother, bother) ops += do_shifts_a(nal, bk, al, aother, bother) nabuckets[r] = al nbbuckets[r] = bk ops.reverse() return ops def try_shifted_sum(func, z): """ Try to recognise a hypergeometric sum that starts from k > 0. """ abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) if len(abuckets[S.Zero]) != 1: return None r = abuckets[S.Zero][0] if r <= 0: return None if not S.Zero in bbuckets: return None l = list(bbuckets[S.Zero]) l.sort() k = l[0] if k <= 0: return None nap = list(func.ap) nap.remove(r) nbq = list(func.bq) nbq.remove(k) k -= 1 nap = [x - k for x in nap] nbq = [x - k for x in nbq] ops = [] for n in range(r - 1): ops.append(ShiftA(n + 1)) ops.reverse() fac = factorial(k)/z**k for a in nap: fac /= rf(a, k) for b in nbq: fac *= rf(b, k) ops += [MultOperator(fac)] p = 0 for n in range(k): m = z**n/factorial(n) for a in nap: m *= rf(a, n) for b in nbq: m /= rf(b, n) p += m return Hyper_Function(nap, nbq), ops, -p def try_polynomial(func, z): """ Recognise polynomial cases. Returns None if not such a case. Requires order to be fully reduced. """ abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) a0 = abuckets[S.Zero] b0 = bbuckets[S.Zero] a0.sort() b0.sort() al0 = [x for x in a0 if x <= 0] bl0 = [x for x in b0 if x <= 0] if bl0 and all(a < bl0[-1] for a in al0): return oo if not al0: return None a = al0[-1] fac = 1 res = S.One for n in Tuple(*list(range(-a))): fac *= z fac /= n + 1 for a in func.ap: fac *= a + n for b in func.bq: fac /= b + n res += fac return res def try_lerchphi(func): """ Try to find an expression for Hyper_Function ``func`` in terms of Lerch Transcendents. Return None if no such expression can be found. """ # This is actually quite simple, and is described in Roach's paper, # section 18. # We don't need to implement the reduction to polylog here, this # is handled by expand_func. from sympy.matrices import Matrix, zeros from sympy.polys import apart # First we need to figure out if the summation coefficient is a rational # function of the summation index, and construct that rational function. abuckets, bbuckets = sift(func.ap, _mod1), sift(func.bq, _mod1) paired = {} for key, value in abuckets.items(): if key != 0 and not key in bbuckets: return None bvalue = bbuckets[key] paired[key] = (list(value), list(bvalue)) bbuckets.pop(key, None) if bbuckets != {}: return None if not S.Zero in abuckets: return None aints, bints = paired[S.Zero] # Account for the additional n! in denominator paired[S.Zero] = (aints, bints + [1]) t = Dummy('t') numer = S.One denom = S.One for key, (avalue, bvalue) in paired.items(): if len(avalue) != len(bvalue): return None # Note that since order has been reduced fully, all the b are # bigger than all the a they differ from by an integer. In particular # if there are any negative b left, this function is not well-defined. for a, b in zip(avalue, bvalue): if (a - b).is_positive: k = a - b numer *= rf(b + t, k) denom *= rf(b, k) else: k = b - a numer *= rf(a, k) denom *= rf(a + t, k) # Now do a partial fraction decomposition. # We assemble two structures: a list monomials of pairs (a, b) representing # a*t**b (b a non-negative integer), and a dict terms, where # terms[a] = [(b, c)] means that there is a term b/(t-a)**c. part = apart(numer/denom, t) args = Add.make_args(part) monomials = [] terms = {} for arg in args: numer, denom = arg.as_numer_denom() if not denom.has(t): p = Poly(numer, t) if not p.is_monomial: raise TypeError("p should be monomial") ((b, ), a) = p.LT() monomials += [(a/denom, b)] continue if numer.has(t): raise NotImplementedError('Need partial fraction decomposition' ' with linear denominators') indep, [dep] = denom.as_coeff_mul(t) n = 1 if dep.is_Pow: n = dep.exp dep = dep.base if dep == t: a == 0 elif dep.is_Add: a, tmp = dep.as_independent(t) b = 1 if tmp != t: b, _ = tmp.as_independent(t) if dep != b*t + a: raise NotImplementedError('unrecognised form %s' % dep) a /= b indep *= b**n else: raise NotImplementedError('unrecognised form of partial fraction') terms.setdefault(a, []).append((numer/indep, n)) # Now that we have this information, assemble our formula. All the # monomials yield rational functions and go into one basis element. # The terms[a] are related by differentiation. If the largest exponent is # n, we need lerchphi(z, k, a) for k = 1, 2, ..., n. # deriv maps a basis to its derivative, expressed as a C(z)-linear # combination of other basis elements. deriv = {} coeffs = {} z = Dummy('z') monomials.sort(key=lambda x: x[1]) mon = {0: 1/(1 - z)} if monomials: for k in range(monomials[-1][1]): mon[k + 1] = z*mon[k].diff(z) for a, n in monomials: coeffs.setdefault(S.One, []).append(a*mon[n]) for a, l in terms.items(): for c, k in l: coeffs.setdefault(lerchphi(z, k, a), []).append(c) l.sort(key=lambda x: x[1]) for k in range(2, l[-1][1] + 1): deriv[lerchphi(z, k, a)] = [(-a, lerchphi(z, k, a)), (1, lerchphi(z, k - 1, a))] deriv[lerchphi(z, 1, a)] = [(-a, lerchphi(z, 1, a)), (1/(1 - z), S.One)] trans = {} for n, b in enumerate([S.One] + list(deriv.keys())): trans[b] = n basis = [expand_func(b) for (b, _) in sorted(list(trans.items()), key=lambda x:x[1])] B = Matrix(basis) C = Matrix([[0]*len(B)]) for b, c in coeffs.items(): C[trans[b]] = Add(*c) M = zeros(len(B)) for b, l in deriv.items(): for c, b2 in l: M[trans[b], trans[b2]] = c return Formula(func, z, None, [], B, C, M) def build_hypergeometric_formula(func): """ Create a formula object representing the hypergeometric function ``func``. """ # We know that no `ap` are negative integers, otherwise "detect poly" # would have kicked in. However, `ap` could be empty. In this case we can # use a different basis. # I'm not aware of a basis that works in all cases. from sympy import zeros, Matrix, eye z = Dummy('z') if func.ap: afactors = [_x + a for a in func.ap] bfactors = [_x + b - 1 for b in func.bq] expr = _x*Mul(*bfactors) - z*Mul(*afactors) poly = Poly(expr, _x) n = poly.degree() basis = [] M = zeros(n) for k in range(n): a = func.ap[0] + k basis += [hyper([a] + list(func.ap[1:]), func.bq, z)] if k < n - 1: M[k, k] = -a M[k, k + 1] = a B = Matrix(basis) C = Matrix([[1] + [0]*(n - 1)]) derivs = [eye(n)] for k in range(n): derivs.append(M*derivs[k]) l = poly.all_coeffs() l.reverse() res = [0]*n for k, c in enumerate(l): for r, d in enumerate(C*derivs[k]): res[r] += c*d for k, c in enumerate(res): M[n - 1, k] = -c/derivs[n - 1][0, n - 1]/poly.all_coeffs()[0] return Formula(func, z, None, [], B, C, M) else: # Since there are no `ap`, none of the `bq` can be non-positive # integers. basis = [] bq = list(func.bq[:]) for i in range(len(bq)): basis += [hyper([], bq, z)] bq[i] += 1 basis += [hyper([], bq, z)] B = Matrix(basis) n = len(B) C = Matrix([[1] + [0]*(n - 1)]) M = zeros(n) M[0, n - 1] = z/Mul(*func.bq) for k in range(1, n): M[k, k - 1] = func.bq[k - 1] M[k, k] = -func.bq[k - 1] return Formula(func, z, None, [], B, C, M) def hyperexpand_special(ap, bq, z): """ Try to find a closed-form expression for hyper(ap, bq, z), where ``z`` is supposed to be a "special" value, e.g. 1. This function tries various of the classical summation formulae (Gauss, Saalschuetz, etc). """ # This code is very ad-hoc. There are many clever algorithms # (notably Zeilberger's) related to this problem. # For now we just want a few simple cases to work. p, q = len(ap), len(bq) z_ = z z = unpolarify(z) if z == 0: return S.One if p == 2 and q == 1: # 2F1 a, b, c = ap + bq if z == 1: # Gauss return gamma(c - a - b)*gamma(c)/gamma(c - a)/gamma(c - b) if z == -1 and simplify(b - a + c) == 1: b, a = a, b if z == -1 and simplify(a - b + c) == 1: # Kummer if b.is_integer and b.is_negative: return 2*cos(pi*b/2)*gamma(-b)*gamma(b - a + 1) \ /gamma(-b/2)/gamma(b/2 - a + 1) else: return gamma(b/2 + 1)*gamma(b - a + 1) \ /gamma(b + 1)/gamma(b/2 - a + 1) # TODO tons of more formulae # investigate what algorithms exist return hyper(ap, bq, z_) _collection = None def _hyperexpand(func, z, ops0=[], z0=Dummy('z0'), premult=1, prem=0, rewrite='default'): """ Try to find an expression for the hypergeometric function ``func``. Explanation =========== The result is expressed in terms of a dummy variable ``z0``. Then it is multiplied by ``premult``. Then ``ops0`` is applied. ``premult`` must be a*z**prem for some a independent of ``z``. """ if z.is_zero: return S.One z = polarify(z, subs=False) if rewrite == 'default': rewrite = 'nonrepsmall' def carryout_plan(f, ops): C = apply_operators(f.C.subs(f.z, z0), ops, make_derivative_operator(f.M.subs(f.z, z0), z0)) from sympy import eye C = apply_operators(C, ops0, make_derivative_operator(f.M.subs(f.z, z0) + prem*eye(f.M.shape[0]), z0)) if premult == 1: C = C.applyfunc(make_simp(z0)) r = reduce(lambda s,m: s+m[0]*m[1], zip(C, f.B.subs(f.z, z0)), S.Zero)*premult res = r.subs(z0, z) if rewrite: res = res.rewrite(rewrite) return res # TODO # The following would be possible: # *) PFD Duplication (see Kelly Roach's paper) # *) In a similar spirit, try_lerchphi() can be generalised considerably. global _collection if _collection is None: _collection = FormulaCollection() debug('Trying to expand hypergeometric function ', func) # First reduce order as much as possible. func, ops = reduce_order(func) if ops: debug(' Reduced order to ', func) else: debug(' Could not reduce order.') # Now try polynomial cases res = try_polynomial(func, z0) if res is not None: debug(' Recognised polynomial.') p = apply_operators(res, ops, lambda f: z0*f.diff(z0)) p = apply_operators(p*premult, ops0, lambda f: z0*f.diff(z0)) return unpolarify(simplify(p).subs(z0, z)) # Try to recognise a shifted sum. p = S.Zero res = try_shifted_sum(func, z0) if res is not None: func, nops, p = res debug(' Recognised shifted sum, reduced order to ', func) ops += nops # apply the plan for poly p = apply_operators(p, ops, lambda f: z0*f.diff(z0)) p = apply_operators(p*premult, ops0, lambda f: z0*f.diff(z0)) p = simplify(p).subs(z0, z) # Try special expansions early. if unpolarify(z) in [1, -1] and (len(func.ap), len(func.bq)) == (2, 1): f = build_hypergeometric_formula(func) r = carryout_plan(f, ops).replace(hyper, hyperexpand_special) if not r.has(hyper): return r + p # Try to find a formula in our collection formula = _collection.lookup_origin(func) # Now try a lerch phi formula if formula is None: formula = try_lerchphi(func) if formula is None: debug(' Could not find an origin. ', 'Will return answer in terms of ' 'simpler hypergeometric functions.') formula = build_hypergeometric_formula(func) debug(' Found an origin: ', formula.closed_form, ' ', formula.func) # We need to find the operators that convert formula into func. ops += devise_plan(func, formula.func, z0) # Now carry out the plan. r = carryout_plan(formula, ops) + p return powdenest(r, polar=True).replace(hyper, hyperexpand_special) def devise_plan_meijer(fro, to, z): """ Find operators to convert G-function ``fro`` into G-function ``to``. Explanation =========== It is assumed that ``fro`` and ``to`` have the same signatures, and that in fact any corresponding pair of parameters differs by integers, and a direct path is possible. I.e. if there are parameters a1 b1 c1 and a2 b2 c2 it is assumed that a1 can be shifted to a2, etc. The only thing this routine determines is the order of shifts to apply, nothing clever will be tried. It is also assumed that ``fro`` is suitable. Examples ======== >>> from sympy.simplify.hyperexpand import (devise_plan_meijer, ... G_Function) >>> from sympy.abc import z Empty plan: >>> devise_plan_meijer(G_Function([1], [2], [3], [4]), ... G_Function([1], [2], [3], [4]), z) [] Very simple plans: >>> devise_plan_meijer(G_Function([0], [], [], []), ... G_Function([1], [], [], []), z) [] >>> devise_plan_meijer(G_Function([0], [], [], []), ... G_Function([-1], [], [], []), z) [] >>> devise_plan_meijer(G_Function([], [1], [], []), ... G_Function([], [2], [], []), z) [] Slightly more complicated plans: >>> devise_plan_meijer(G_Function([0], [], [], []), ... G_Function([2], [], [], []), z) [, ] >>> devise_plan_meijer(G_Function([0], [], [0], []), ... G_Function([-1], [], [1], []), z) [, ] Order matters: >>> devise_plan_meijer(G_Function([0], [], [0], []), ... G_Function([1], [], [1], []), z) [, ] """ # TODO for now, we use the following simple heuristic: inverse-shift # when possible, shift otherwise. Give up if we cannot make progress. def try_shift(f, t, shifter, diff, counter): """ Try to apply ``shifter`` in order to bring some element in ``f`` nearer to its counterpart in ``to``. ``diff`` is +/- 1 and determines the effect of ``shifter``. Counter is a list of elements blocking the shift. Return an operator if change was possible, else None. """ for idx, (a, b) in enumerate(zip(f, t)): if ( (a - b).is_integer and (b - a)/diff > 0 and all(a != x for x in counter)): sh = shifter(idx) f[idx] += diff return sh fan = list(fro.an) fap = list(fro.ap) fbm = list(fro.bm) fbq = list(fro.bq) ops = [] change = True while change: change = False op = try_shift(fan, to.an, lambda i: MeijerUnShiftB(fan, fap, fbm, fbq, i, z), 1, fbm + fbq) if op is not None: ops += [op] change = True continue op = try_shift(fap, to.ap, lambda i: MeijerUnShiftD(fan, fap, fbm, fbq, i, z), 1, fbm + fbq) if op is not None: ops += [op] change = True continue op = try_shift(fbm, to.bm, lambda i: MeijerUnShiftA(fan, fap, fbm, fbq, i, z), -1, fan + fap) if op is not None: ops += [op] change = True continue op = try_shift(fbq, to.bq, lambda i: MeijerUnShiftC(fan, fap, fbm, fbq, i, z), -1, fan + fap) if op is not None: ops += [op] change = True continue op = try_shift(fan, to.an, lambda i: MeijerShiftB(fan[i]), -1, []) if op is not None: ops += [op] change = True continue op = try_shift(fap, to.ap, lambda i: MeijerShiftD(fap[i]), -1, []) if op is not None: ops += [op] change = True continue op = try_shift(fbm, to.bm, lambda i: MeijerShiftA(fbm[i]), 1, []) if op is not None: ops += [op] change = True continue op = try_shift(fbq, to.bq, lambda i: MeijerShiftC(fbq[i]), 1, []) if op is not None: ops += [op] change = True continue if fan != list(to.an) or fap != list(to.ap) or fbm != list(to.bm) or \ fbq != list(to.bq): raise NotImplementedError('Could not devise plan.') ops.reverse() return ops _meijercollection = None def _meijergexpand(func, z0, allow_hyper=False, rewrite='default', place=None): """ Try to find an expression for the Meijer G function specified by the G_Function ``func``. If ``allow_hyper`` is True, then returning an expression in terms of hypergeometric functions is allowed. Currently this just does Slater's theorem. If expansions exist both at zero and at infinity, ``place`` can be set to ``0`` or ``zoo`` for the preferred choice. """ global _meijercollection if _meijercollection is None: _meijercollection = MeijerFormulaCollection() if rewrite == 'default': rewrite = None func0 = func debug('Try to expand Meijer G function corresponding to ', func) # We will play games with analytic continuation - rather use a fresh symbol z = Dummy('z') func, ops = reduce_order_meijer(func) if ops: debug(' Reduced order to ', func) else: debug(' Could not reduce order.') # Try to find a direct formula f = _meijercollection.lookup_origin(func) if f is not None: debug(' Found a Meijer G formula: ', f.func) ops += devise_plan_meijer(f.func, func, z) # Now carry out the plan. C = apply_operators(f.C.subs(f.z, z), ops, make_derivative_operator(f.M.subs(f.z, z), z)) C = C.applyfunc(make_simp(z)) r = C*f.B.subs(f.z, z) r = r[0].subs(z, z0) return powdenest(r, polar=True) debug(" Could not find a direct formula. Trying Slater's theorem.") # TODO the following would be possible: # *) Paired Index Theorems # *) PFD Duplication # (See Kelly Roach's paper for details on either.) # # TODO Also, we tend to create combinations of gamma functions that can be # simplified. def can_do(pbm, pap): """ Test if slater applies. """ for i in pbm: if len(pbm[i]) > 1: l = 0 if i in pap: l = len(pap[i]) if l + 1 < len(pbm[i]): return False return True def do_slater(an, bm, ap, bq, z, zfinal): # zfinal is the value that will eventually be substituted for z. # We pass it to _hyperexpand to improve performance. func = G_Function(an, bm, ap, bq) _, pbm, pap, _ = func.compute_buckets() if not can_do(pbm, pap): return S.Zero, False cond = len(an) + len(ap) < len(bm) + len(bq) if len(an) + len(ap) == len(bm) + len(bq): cond = abs(z) < 1 if cond is False: return S.Zero, False res = S.Zero for m in pbm: if len(pbm[m]) == 1: bh = pbm[m][0] fac = 1 bo = list(bm) bo.remove(bh) for bj in bo: fac *= gamma(bj - bh) for aj in an: fac *= gamma(1 + bh - aj) for bj in bq: fac /= gamma(1 + bh - bj) for aj in ap: fac /= gamma(aj - bh) nap = [1 + bh - a for a in list(an) + list(ap)] nbq = [1 + bh - b for b in list(bo) + list(bq)] k = polar_lift(S.NegativeOne**(len(ap) - len(bm))) harg = k*zfinal # NOTE even though k "is" +-1, this has to be t/k instead of # t*k ... we are using polar numbers for consistency! premult = (t/k)**bh hyp = _hyperexpand(Hyper_Function(nap, nbq), harg, ops, t, premult, bh, rewrite=None) res += fac * hyp else: b_ = pbm[m][0] ki = [bi - b_ for bi in pbm[m][1:]] u = len(ki) li = [ai - b_ for ai in pap[m][:u + 1]] bo = list(bm) for b in pbm[m]: bo.remove(b) ao = list(ap) for a in pap[m][:u]: ao.remove(a) lu = li[-1] di = [l - k for (l, k) in zip(li, ki)] # We first work out the integrand: s = Dummy('s') integrand = z**s for b in bm: if not Mod(b, 1) and b.is_Number: b = int(round(b)) integrand *= gamma(b - s) for a in an: integrand *= gamma(1 - a + s) for b in bq: integrand /= gamma(1 - b + s) for a in ap: integrand /= gamma(a - s) # Now sum the finitely many residues: # XXX This speeds up some cases - is it a good idea? integrand = expand_func(integrand) for r in range(int(round(lu))): resid = residue(integrand, s, b_ + r) resid = apply_operators(resid, ops, lambda f: z*f.diff(z)) res -= resid # Now the hypergeometric term. au = b_ + lu k = polar_lift(S.NegativeOne**(len(ao) + len(bo) + 1)) harg = k*zfinal premult = (t/k)**au nap = [1 + au - a for a in list(an) + list(ap)] + [1] nbq = [1 + au - b for b in list(bm) + list(bq)] hyp = _hyperexpand(Hyper_Function(nap, nbq), harg, ops, t, premult, au, rewrite=None) C = S.NegativeOne**(lu)/factorial(lu) for i in range(u): C *= S.NegativeOne**di[i]/rf(lu - li[i] + 1, di[i]) for a in an: C *= gamma(1 - a + au) for b in bo: C *= gamma(b - au) for a in ao: C /= gamma(a - au) for b in bq: C /= gamma(1 - b + au) res += C*hyp return res, cond t = Dummy('t') slater1, cond1 = do_slater(func.an, func.bm, func.ap, func.bq, z, z0) def tr(l): return [1 - x for x in l] for op in ops: op._poly = Poly(op._poly.subs({z: 1/t, _x: -_x}), _x) slater2, cond2 = do_slater(tr(func.bm), tr(func.an), tr(func.bq), tr(func.ap), t, 1/z0) slater1 = powdenest(slater1.subs(z, z0), polar=True) slater2 = powdenest(slater2.subs(t, 1/z0), polar=True) if not isinstance(cond2, bool): cond2 = cond2.subs(t, 1/z) m = func(z) if m.delta > 0 or \ (m.delta == 0 and len(m.ap) == len(m.bq) and (re(m.nu) < -1) is not False and polar_lift(z0) == polar_lift(1)): # The condition delta > 0 means that the convergence region is # connected. Any expression we find can be continued analytically # to the entire convergence region. # The conditions delta==0, p==q, re(nu) < -1 imply that G is continuous # on the positive reals, so the values at z=1 agree. if cond1 is not False: cond1 = True if cond2 is not False: cond2 = True if cond1 is True: slater1 = slater1.rewrite(rewrite or 'nonrep') else: slater1 = slater1.rewrite(rewrite or 'nonrepsmall') if cond2 is True: slater2 = slater2.rewrite(rewrite or 'nonrep') else: slater2 = slater2.rewrite(rewrite or 'nonrepsmall') if cond1 is not False and cond2 is not False: # If one condition is False, there is no choice. if place == 0: cond2 = False if place == zoo: cond1 = False if not isinstance(cond1, bool): cond1 = cond1.subs(z, z0) if not isinstance(cond2, bool): cond2 = cond2.subs(z, z0) def weight(expr, cond): if cond is True: c0 = 0 elif cond is False: c0 = 1 else: c0 = 2 if expr.has(oo, zoo, -oo, nan): # XXX this actually should not happen, but consider # S('meijerg(((0, -1/2, 0, -1/2, 1/2), ()), ((0,), # (-1/2, -1/2, -1/2, -1)), exp_polar(I*pi))/4') c0 = 3 return (c0, expr.count(hyper), expr.count_ops()) w1 = weight(slater1, cond1) w2 = weight(slater2, cond2) if min(w1, w2) <= (0, 1, oo): if w1 < w2: return slater1 else: return slater2 if max(w1[0], w2[0]) <= 1 and max(w1[1], w2[1]) <= 1: return Piecewise((slater1, cond1), (slater2, cond2), (func0(z0), True)) # We couldn't find an expression without hypergeometric functions. # TODO it would be helpful to give conditions under which the integral # is known to diverge. r = Piecewise((slater1, cond1), (slater2, cond2), (func0(z0), True)) if r.has(hyper) and not allow_hyper: debug(' Could express using hypergeometric functions, ' 'but not allowed.') if not r.has(hyper) or allow_hyper: return r return func0(z0) def hyperexpand(f, allow_hyper=False, rewrite='default', place=None): """ Expand hypergeometric functions. If allow_hyper is True, allow partial simplification (that is a result different from input, but still containing hypergeometric functions). If a G-function has expansions both at zero and at infinity, ``place`` can be set to ``0`` or ``zoo`` to indicate the preferred choice. Examples ======== >>> from sympy.simplify.hyperexpand import hyperexpand >>> from sympy.functions import hyper >>> from sympy.abc import z >>> hyperexpand(hyper([], [], z)) exp(z) Non-hyperegeometric parts of the expression and hypergeometric expressions that are not recognised are left unchanged: >>> hyperexpand(1 + hyper([1, 1, 1], [], z)) hyper((1, 1, 1), (), z) + 1 """ f = sympify(f) def do_replace(ap, bq, z): r = _hyperexpand(Hyper_Function(ap, bq), z, rewrite=rewrite) if r is None: return hyper(ap, bq, z) else: return r def do_meijer(ap, bq, z): r = _meijergexpand(G_Function(ap[0], ap[1], bq[0], bq[1]), z, allow_hyper, rewrite=rewrite, place=place) if not r.has(nan, zoo, oo, -oo): return r return f.replace(hyper, do_replace).replace(meijerg, do_meijer) sympy-sympy-1.9/sympy/simplify/hyperexpand_doc.py000066400000000000000000000006601412543434000224700ustar00rootroot00000000000000""" This module cooks up a docstring when imported. Its only purpose is to be displayed in the sphinx documentation. """ from sympy import latex, Eq, hyper from sympy.simplify.hyperexpand import FormulaCollection c = FormulaCollection() doc = "" for f in c.formulae: obj = Eq(hyper(f.func.ap, f.func.bq, f.z), f.closed_form.rewrite('nonrepsmall')) doc += ".. math::\n %s\n" % latex(obj) __doc__ = doc sympy-sympy-1.9/sympy/simplify/powsimp.py000066400000000000000000000633741412543434000210250ustar00rootroot00000000000000from collections import defaultdict from sympy.core.function import expand_log, count_ops from sympy.core import sympify, Basic, Dummy, S, Add, Mul, Pow, expand_mul, factor_terms from sympy.core.compatibility import ordered, default_sort_key, reduce from sympy.core.numbers import Integer, Rational from sympy.core.mul import prod, _keep_coeff from sympy.core.rules import Transform from sympy.functions import exp_polar, exp, log, root, polarify, unpolarify from sympy.polys import lcm, gcd from sympy.ntheory.factor_ import multiplicity def powsimp(expr, deep=False, combine='all', force=False, measure=count_ops): """ reduces expression by combining powers with similar bases and exponents. Explanation =========== If ``deep`` is ``True`` then powsimp() will also simplify arguments of functions. By default ``deep`` is set to ``False``. If ``force`` is ``True`` then bases will be combined without checking for assumptions, e.g. sqrt(x)*sqrt(y) -> sqrt(x*y) which is not true if x and y are both negative. You can make powsimp() only combine bases or only combine exponents by changing combine='base' or combine='exp'. By default, combine='all', which does both. combine='base' will only combine:: a a a 2x x x * y => (x*y) as well as things like 2 => 4 and combine='exp' will only combine :: a b (a + b) x * x => x combine='exp' will strictly only combine exponents in the way that used to be automatic. Also use deep=True if you need the old behavior. When combine='all', 'exp' is evaluated first. Consider the first example below for when there could be an ambiguity relating to this. This is done so things like the second example can be completely combined. If you want 'base' combined first, do something like powsimp(powsimp(expr, combine='base'), combine='exp'). Examples ======== >>> from sympy import powsimp, exp, log, symbols >>> from sympy.abc import x, y, z, n >>> powsimp(x**y*x**z*y**z, combine='all') x**(y + z)*y**z >>> powsimp(x**y*x**z*y**z, combine='exp') x**(y + z)*y**z >>> powsimp(x**y*x**z*y**z, combine='base', force=True) x**y*(x*y)**z >>> powsimp(x**z*x**y*n**z*n**y, combine='all', force=True) (n*x)**(y + z) >>> powsimp(x**z*x**y*n**z*n**y, combine='exp') n**(y + z)*x**(y + z) >>> powsimp(x**z*x**y*n**z*n**y, combine='base', force=True) (n*x)**y*(n*x)**z >>> x, y = symbols('x y', positive=True) >>> powsimp(log(exp(x)*exp(y))) log(exp(x)*exp(y)) >>> powsimp(log(exp(x)*exp(y)), deep=True) x + y Radicals with Mul bases will be combined if combine='exp' >>> from sympy import sqrt >>> x, y = symbols('x y') Two radicals are automatically joined through Mul: >>> a=sqrt(x*sqrt(y)) >>> a*a**3 == a**4 True But if an integer power of that radical has been autoexpanded then Mul does not join the resulting factors: >>> a**4 # auto expands to a Mul, no longer a Pow x**2*y >>> _*a # so Mul doesn't combine them x**2*y*sqrt(x*sqrt(y)) >>> powsimp(_) # but powsimp will (x*sqrt(y))**(5/2) >>> powsimp(x*y*a) # but won't when doing so would violate assumptions x*y*sqrt(x*sqrt(y)) """ from sympy.matrices.expressions.matexpr import MatrixSymbol def recurse(arg, **kwargs): _deep = kwargs.get('deep', deep) _combine = kwargs.get('combine', combine) _force = kwargs.get('force', force) _measure = kwargs.get('measure', measure) return powsimp(arg, _deep, _combine, _force, _measure) expr = sympify(expr) if (not isinstance(expr, Basic) or isinstance(expr, MatrixSymbol) or ( expr.is_Atom or expr in (exp_polar(0), exp_polar(1)))): return expr if deep or expr.is_Add or expr.is_Mul and _y not in expr.args: expr = expr.func(*[recurse(w) for w in expr.args]) if expr.is_Pow: return recurse(expr*_y, deep=False)/_y if not expr.is_Mul: return expr # handle the Mul if combine in ('exp', 'all'): # Collect base/exp data, while maintaining order in the # non-commutative parts of the product c_powers = defaultdict(list) nc_part = [] newexpr = [] coeff = S.One for term in expr.args: if term.is_Rational: coeff *= term continue if term.is_Pow: term = _denest_pow(term) if term.is_commutative: b, e = term.as_base_exp() if deep: b, e = [recurse(i) for i in [b, e]] if b.is_Pow or isinstance(b, exp): # don't let smthg like sqrt(x**a) split into x**a, 1/2 # or else it will be joined as x**(a/2) later b, e = b**e, S.One c_powers[b].append(e) else: # This is the logic that combines exponents for equal, # but non-commutative bases: A**x*A**y == A**(x+y). if nc_part: b1, e1 = nc_part[-1].as_base_exp() b2, e2 = term.as_base_exp() if (b1 == b2 and e1.is_commutative and e2.is_commutative): nc_part[-1] = Pow(b1, Add(e1, e2)) continue nc_part.append(term) # add up exponents of common bases for b, e in ordered(iter(c_powers.items())): # allow 2**x/4 -> 2**(x - 2); don't do this when b and e are # Numbers since autoevaluation will undo it, e.g. # 2**(1/3)/4 -> 2**(1/3 - 2) -> 2**(1/3)/4 if (b and b.is_Rational and not all(ei.is_Number for ei in e) and \ coeff is not S.One and b not in (S.One, S.NegativeOne)): m = multiplicity(abs(b), abs(coeff)) if m: e.append(m) coeff /= b**m c_powers[b] = Add(*e) if coeff is not S.One: if coeff in c_powers: c_powers[coeff] += S.One else: c_powers[coeff] = S.One # convert to plain dictionary c_powers = dict(c_powers) # check for base and inverted base pairs be = list(c_powers.items()) skip = set() # skip if we already saw them for b, e in be: if b in skip: continue bpos = b.is_positive or b.is_polar if bpos: binv = 1/b if b != binv and binv in c_powers: if b.as_numer_denom()[0] is S.One: c_powers.pop(b) c_powers[binv] -= e else: skip.add(binv) e = c_powers.pop(binv) c_powers[b] -= e # check for base and negated base pairs be = list(c_powers.items()) _n = S.NegativeOne for b, e in be: if (b.is_Symbol or b.is_Add) and -b in c_powers and b in c_powers: if (b.is_positive is not None or e.is_integer): if e.is_integer or b.is_negative: c_powers[-b] += c_powers.pop(b) else: # (-b).is_positive so use its e e = c_powers.pop(-b) c_powers[b] += e if _n in c_powers: c_powers[_n] += e else: c_powers[_n] = e # filter c_powers and convert to a list c_powers = [(b, e) for b, e in c_powers.items() if e] # ============================================================== # check for Mul bases of Rational powers that can be combined with # separated bases, e.g. x*sqrt(x*y)*sqrt(x*sqrt(x*y)) -> # (x*sqrt(x*y))**(3/2) # ---------------- helper functions def ratq(x): '''Return Rational part of x's exponent as it appears in the bkey. ''' return bkey(x)[0][1] def bkey(b, e=None): '''Return (b**s, c.q), c.p where e -> c*s. If e is not given then it will be taken by using as_base_exp() on the input b. e.g. x**3/2 -> (x, 2), 3 x**y -> (x**y, 1), 1 x**(2*y/3) -> (x**y, 3), 2 exp(x/2) -> (exp(a), 2), 1 ''' if e is not None: # coming from c_powers or from below if e.is_Integer: return (b, S.One), e elif e.is_Rational: return (b, Integer(e.q)), Integer(e.p) else: c, m = e.as_coeff_Mul(rational=True) if c is not S.One: if m.is_integer: return (b, Integer(c.q)), m*Integer(c.p) return (b**m, Integer(c.q)), Integer(c.p) else: return (b**e, S.One), S.One else: return bkey(*b.as_base_exp()) def update(b): '''Decide what to do with base, b. If its exponent is now an integer multiple of the Rational denominator, then remove it and put the factors of its base in the common_b dictionary or update the existing bases if necessary. If it has been zeroed out, simply remove the base. ''' newe, r = divmod(common_b[b], b[1]) if not r: common_b.pop(b) if newe: for m in Mul.make_args(b[0]**newe): b, e = bkey(m) if b not in common_b: common_b[b] = 0 common_b[b] += e if b[1] != 1: bases.append(b) # ---------------- end of helper functions # assemble a dictionary of the factors having a Rational power common_b = {} done = [] bases = [] for b, e in c_powers: b, e = bkey(b, e) if b in common_b: common_b[b] = common_b[b] + e else: common_b[b] = e if b[1] != 1 and b[0].is_Mul: bases.append(b) bases.sort(key=default_sort_key) # this makes tie-breaking canonical bases.sort(key=measure, reverse=True) # handle longest first for base in bases: if base not in common_b: # it may have been removed already continue b, exponent = base last = False # True when no factor of base is a radical qlcm = 1 # the lcm of the radical denominators while True: bstart = b qstart = qlcm bb = [] # list of factors ee = [] # (factor's expo. and it's current value in common_b) for bi in Mul.make_args(b): bib, bie = bkey(bi) if bib not in common_b or common_b[bib] < bie: ee = bb = [] # failed break ee.append([bie, common_b[bib]]) bb.append(bib) if ee: # find the number of integral extractions possible # e.g. [(1, 2), (2, 2)] -> min(2/1, 2/2) -> 1 min1 = ee[0][1]//ee[0][0] for i in range(1, len(ee)): rat = ee[i][1]//ee[i][0] if rat < 1: break min1 = min(min1, rat) else: # update base factor counts # e.g. if ee = [(2, 5), (3, 6)] then min1 = 2 # and the new base counts will be 5-2*2 and 6-2*3 for i in range(len(bb)): common_b[bb[i]] -= min1*ee[i][0] update(bb[i]) # update the count of the base # e.g. x**2*y*sqrt(x*sqrt(y)) the count of x*sqrt(y) # will increase by 4 to give bkey (x*sqrt(y), 2, 5) common_b[base] += min1*qstart*exponent if (last # no more radicals in base or len(common_b) == 1 # nothing left to join with or all(k[1] == 1 for k in common_b) # no rad's in common_b ): break # see what we can exponentiate base by to remove any radicals # so we know what to search for # e.g. if base were x**(1/2)*y**(1/3) then we should # exponentiate by 6 and look for powers of x and y in the ratio # of 2 to 3 qlcm = lcm([ratq(bi) for bi in Mul.make_args(bstart)]) if qlcm == 1: break # we are done b = bstart**qlcm qlcm *= qstart if all(ratq(bi) == 1 for bi in Mul.make_args(b)): last = True # we are going to be done after this next pass # this base no longer can find anything to join with and # since it was longer than any other we are done with it b, q = base done.append((b, common_b.pop(base)*Rational(1, q))) # update c_powers and get ready to continue with powsimp c_powers = done # there may be terms still in common_b that were bases that were # identified as needing processing, so remove those, too for (b, q), e in common_b.items(): if (b.is_Pow or isinstance(b, exp)) and \ q is not S.One and not b.exp.is_Rational: b, be = b.as_base_exp() b = b**(be/q) else: b = root(b, q) c_powers.append((b, e)) check = len(c_powers) c_powers = dict(c_powers) assert len(c_powers) == check # there should have been no duplicates # ============================================================== # rebuild the expression newexpr = expr.func(*(newexpr + [Pow(b, e) for b, e in c_powers.items()])) if combine == 'exp': return expr.func(newexpr, expr.func(*nc_part)) else: return recurse(expr.func(*nc_part), combine='base') * \ recurse(newexpr, combine='base') elif combine == 'base': # Build c_powers and nc_part. These must both be lists not # dicts because exp's are not combined. c_powers = [] nc_part = [] for term in expr.args: if term.is_commutative: c_powers.append(list(term.as_base_exp())) else: nc_part.append(term) # Pull out numerical coefficients from exponent if assumptions allow # e.g., 2**(2*x) => 4**x for i in range(len(c_powers)): b, e = c_powers[i] if not (all(x.is_nonnegative for x in b.as_numer_denom()) or e.is_integer or force or b.is_polar): continue exp_c, exp_t = e.as_coeff_Mul(rational=True) if exp_c is not S.One and exp_t is not S.One: c_powers[i] = [Pow(b, exp_c), exp_t] # Combine bases whenever they have the same exponent and # assumptions allow # first gather the potential bases under the common exponent c_exp = defaultdict(list) for b, e in c_powers: if deep: e = recurse(e) c_exp[e].append(b) del c_powers # Merge back in the results of the above to form a new product c_powers = defaultdict(list) for e in c_exp: bases = c_exp[e] # calculate the new base for e if len(bases) == 1: new_base = bases[0] elif e.is_integer or force: new_base = expr.func(*bases) else: # see which ones can be joined unk = [] nonneg = [] neg = [] for bi in bases: if bi.is_negative: neg.append(bi) elif bi.is_nonnegative: nonneg.append(bi) elif bi.is_polar: nonneg.append( bi) # polar can be treated like non-negative else: unk.append(bi) if len(unk) == 1 and not neg or len(neg) == 1 and not unk: # a single neg or a single unk can join the rest nonneg.extend(unk + neg) unk = neg = [] elif neg: # their negative signs cancel in groups of 2*q if we know # that e = p/q else we have to treat them as unknown israt = False if e.is_Rational: israt = True else: p, d = e.as_numer_denom() if p.is_integer and d.is_integer: israt = True if israt: neg = [-w for w in neg] unk.extend([S.NegativeOne]*len(neg)) else: unk.extend(neg) neg = [] del israt # these shouldn't be joined for b in unk: c_powers[b].append(e) # here is a new joined base new_base = expr.func(*(nonneg + neg)) # if there are positive parts they will just get separated # again unless some change is made def _terms(e): # return the number of terms of this expression # when multiplied out -- assuming no joining of terms if e.is_Add: return sum([_terms(ai) for ai in e.args]) if e.is_Mul: return prod([_terms(mi) for mi in e.args]) return 1 xnew_base = expand_mul(new_base, deep=False) if len(Add.make_args(xnew_base)) < _terms(new_base): new_base = factor_terms(xnew_base) c_powers[new_base].append(e) # break out the powers from c_powers now c_part = [Pow(b, ei) for b, e in c_powers.items() for ei in e] # we're done return expr.func(*(c_part + nc_part)) else: raise ValueError("combine must be one of ('all', 'exp', 'base').") def powdenest(eq, force=False, polar=False): r""" Collect exponents on powers as assumptions allow. Explanation =========== Given ``(bb**be)**e``, this can be simplified as follows: * if ``bb`` is positive, or * ``e`` is an integer, or * ``|be| < 1`` then this simplifies to ``bb**(be*e)`` Given a product of powers raised to a power, ``(bb1**be1 * bb2**be2...)**e``, simplification can be done as follows: - if e is positive, the gcd of all bei can be joined with e; - all non-negative bb can be separated from those that are negative and their gcd can be joined with e; autosimplification already handles this separation. - integer factors from powers that have integers in the denominator of the exponent can be removed from any term and the gcd of such integers can be joined with e Setting ``force`` to ``True`` will make symbols that are not explicitly negative behave as though they are positive, resulting in more denesting. Setting ``polar`` to ``True`` will do simplifications on the Riemann surface of the logarithm, also resulting in more denestings. When there are sums of logs in exp() then a product of powers may be obtained e.g. ``exp(3*(log(a) + 2*log(b)))`` - > ``a**3*b**6``. Examples ======== >>> from sympy.abc import a, b, x, y, z >>> from sympy import Symbol, exp, log, sqrt, symbols, powdenest >>> powdenest((x**(2*a/3))**(3*x)) (x**(2*a/3))**(3*x) >>> powdenest(exp(3*x*log(2))) 2**(3*x) Assumptions may prevent expansion: >>> powdenest(sqrt(x**2)) sqrt(x**2) >>> p = symbols('p', positive=True) >>> powdenest(sqrt(p**2)) p No other expansion is done. >>> i, j = symbols('i,j', integer=True) >>> powdenest((x**x)**(i + j)) # -X-> (x**x)**i*(x**x)**j x**(x*(i + j)) But exp() will be denested by moving all non-log terms outside of the function; this may result in the collapsing of the exp to a power with a different base: >>> powdenest(exp(3*y*log(x))) x**(3*y) >>> powdenest(exp(y*(log(a) + log(b)))) (a*b)**y >>> powdenest(exp(3*(log(a) + log(b)))) a**3*b**3 If assumptions allow, symbols can also be moved to the outermost exponent: >>> i = Symbol('i', integer=True) >>> powdenest(((x**(2*i))**(3*y))**x) ((x**(2*i))**(3*y))**x >>> powdenest(((x**(2*i))**(3*y))**x, force=True) x**(6*i*x*y) >>> powdenest(((x**(2*a/3))**(3*y/i))**x) ((x**(2*a/3))**(3*y/i))**x >>> powdenest((x**(2*i)*y**(4*i))**z, force=True) (x*y**2)**(2*i*z) >>> n = Symbol('n', negative=True) >>> powdenest((x**i)**y, force=True) x**(i*y) >>> powdenest((n**i)**x, force=True) (n**i)**x """ from sympy.simplify.simplify import posify if force: def _denest(b, e): if not isinstance(b, (Pow, exp)): return b.is_positive, Pow(b, e, evaluate=False) return _denest(b.base, b.exp*e) reps = [] for p in eq.atoms(Pow, exp): if isinstance(p.base, (Pow, exp)): ok, dp = _denest(*p.args) if ok is not False: reps.append((p, dp)) if reps: eq = eq.subs(reps) eq, reps = posify(eq) return powdenest(eq, force=False, polar=polar).xreplace(reps) if polar: eq, rep = polarify(eq) return unpolarify(powdenest(unpolarify(eq, exponents_only=True)), rep) new = powsimp(sympify(eq)) return new.xreplace(Transform( _denest_pow, filter=lambda m: m.is_Pow or isinstance(m, exp))) _y = Dummy('y') def _denest_pow(eq): """ Denest powers. This is a helper function for powdenest that performs the actual transformation. """ from sympy.simplify.simplify import logcombine b, e = eq.as_base_exp() if b.is_Pow or isinstance(b.func, exp) and e != 1: new = b._eval_power(e) if new is not None: eq = new b, e = new.as_base_exp() # denest exp with log terms in exponent if b is S.Exp1 and e.is_Mul: logs = [] other = [] for ei in e.args: if any(isinstance(ai, log) for ai in Add.make_args(ei)): logs.append(ei) else: other.append(ei) logs = logcombine(Mul(*logs)) return Pow(exp(logs), Mul(*other)) _, be = b.as_base_exp() if be is S.One and not (b.is_Mul or b.is_Rational and b.q != 1 or b.is_positive): return eq # denest eq which is either pos**e or Pow**e or Mul**e or # Mul(b1**e1, b2**e2) # handle polar numbers specially polars, nonpolars = [], [] for bb in Mul.make_args(b): if bb.is_polar: polars.append(bb.as_base_exp()) else: nonpolars.append(bb) if len(polars) == 1 and not polars[0][0].is_Mul: return Pow(polars[0][0], polars[0][1]*e)*powdenest(Mul(*nonpolars)**e) elif polars: return Mul(*[powdenest(bb**(ee*e)) for (bb, ee) in polars]) \ *powdenest(Mul(*nonpolars)**e) if b.is_Integer: # use log to see if there is a power here logb = expand_log(log(b)) if logb.is_Mul: c, logb = logb.args e *= c base = logb.args[0] return Pow(base, e) # if b is not a Mul or any factor is an atom then there is nothing to do if not b.is_Mul or any(s.is_Atom for s in Mul.make_args(b)): return eq # let log handle the case of the base of the argument being a Mul, e.g. # sqrt(x**(2*i)*y**(6*i)) -> x**i*y**(3**i) if x and y are positive; we # will take the log, expand it, and then factor out the common powers that # now appear as coefficient. We do this manually since terms_gcd pulls out # fractions, terms_gcd(x+x*y/2) -> x*(y + 2)/2 and we don't want the 1/2; # gcd won't pull out numerators from a fraction: gcd(3*x, 9*x/2) -> x but # we want 3*x. Neither work with noncommutatives. def nc_gcd(aa, bb): a, b = [i.as_coeff_Mul() for i in [aa, bb]] c = gcd(a[0], b[0]).as_numer_denom()[0] g = Mul(*(a[1].args_cnc(cset=True)[0] & b[1].args_cnc(cset=True)[0])) return _keep_coeff(c, g) glogb = expand_log(log(b)) if glogb.is_Add: args = glogb.args g = reduce(nc_gcd, args) if g != 1: cg, rg = g.as_coeff_Mul() glogb = _keep_coeff(cg, rg*Add(*[a/g for a in args])) # now put the log back together again if isinstance(glogb, log) or not glogb.is_Mul: if glogb.args[0].is_Pow or isinstance(glogb.args[0], exp): glogb = _denest_pow(glogb.args[0]) if (abs(glogb.exp) < 1) == True: return Pow(glogb.base, glogb.exp*e) return eq # the log(b) was a Mul so join any adds with logcombine add = [] other = [] for a in glogb.args: if a.is_Add: add.append(a) else: other.append(a) return Pow(exp(logcombine(Mul(*add))), e*Mul(*other)) sympy-sympy-1.9/sympy/simplify/radsimp.py000066400000000000000000001165661412543434000207700ustar00rootroot00000000000000from collections import defaultdict from sympy import SYMPY_DEBUG from sympy.core import expand_power_base, sympify, Add, S, Mul, Derivative, Pow, symbols, expand_mul from sympy.core.add import _unevaluated_Add from sympy.core.compatibility import iterable, ordered, default_sort_key from sympy.core.parameters import global_parameters from sympy.core.exprtools import Factors, gcd_terms from sympy.core.function import _mexpand from sympy.core.mul import _keep_coeff, _unevaluated_Mul from sympy.core.numbers import Rational, zoo, nan from sympy.functions import exp, sqrt, log from sympy.functions.elementary.complexes import Abs from sympy.polys import gcd from sympy.simplify.sqrtdenest import sqrtdenest def collect(expr, syms, func=None, evaluate=None, exact=False, distribute_order_term=True): """ Collect additive terms of an expression. Explanation =========== This function collects additive terms of an expression with respect to a list of expression up to powers with rational exponents. By the term symbol here are meant arbitrary expressions, which can contain powers, products, sums etc. In other words symbol is a pattern which will be searched for in the expression's terms. The input expression is not expanded by :func:`collect`, so user is expected to provide an expression in an appropriate form. This makes :func:`collect` more predictable as there is no magic happening behind the scenes. However, it is important to note, that powers of products are converted to products of powers using the :func:`~.expand_power_base` function. There are two possible types of output. First, if ``evaluate`` flag is set, this function will return an expression with collected terms or else it will return a dictionary with expressions up to rational powers as keys and collected coefficients as values. Examples ======== >>> from sympy import S, collect, expand, factor, Wild >>> from sympy.abc import a, b, c, x, y This function can collect symbolic coefficients in polynomials or rational expressions. It will manage to find all integer or rational powers of collection variable:: >>> collect(a*x**2 + b*x**2 + a*x - b*x + c, x) c + x**2*(a + b) + x*(a - b) The same result can be achieved in dictionary form:: >>> d = collect(a*x**2 + b*x**2 + a*x - b*x + c, x, evaluate=False) >>> d[x**2] a + b >>> d[x] a - b >>> d[S.One] c You can also work with multivariate polynomials. However, remember that this function is greedy so it will care only about a single symbol at time, in specification order:: >>> collect(x**2 + y*x**2 + x*y + y + a*y, [x, y]) x**2*(y + 1) + x*y + y*(a + 1) Also more complicated expressions can be used as patterns:: >>> from sympy import sin, log >>> collect(a*sin(2*x) + b*sin(2*x), sin(2*x)) (a + b)*sin(2*x) >>> collect(a*x*log(x) + b*(x*log(x)), x*log(x)) x*(a + b)*log(x) You can use wildcards in the pattern:: >>> w = Wild('w1') >>> collect(a*x**y - b*x**y, w**y) x**y*(a - b) It is also possible to work with symbolic powers, although it has more complicated behavior, because in this case power's base and symbolic part of the exponent are treated as a single symbol:: >>> collect(a*x**c + b*x**c, x) a*x**c + b*x**c >>> collect(a*x**c + b*x**c, x**c) x**c*(a + b) However if you incorporate rationals to the exponents, then you will get well known behavior:: >>> collect(a*x**(2*c) + b*x**(2*c), x**c) x**(2*c)*(a + b) Note also that all previously stated facts about :func:`collect` function apply to the exponential function, so you can get:: >>> from sympy import exp >>> collect(a*exp(2*x) + b*exp(2*x), exp(x)) (a + b)*exp(2*x) If you are interested only in collecting specific powers of some symbols then set ``exact`` flag in arguments:: >>> collect(a*x**7 + b*x**7, x, exact=True) a*x**7 + b*x**7 >>> collect(a*x**7 + b*x**7, x**7, exact=True) x**7*(a + b) You can also apply this function to differential equations, where derivatives of arbitrary order can be collected. Note that if you collect with respect to a function or a derivative of a function, all derivatives of that function will also be collected. Use ``exact=True`` to prevent this from happening:: >>> from sympy import Derivative as D, collect, Function >>> f = Function('f') (x) >>> collect(a*D(f,x) + b*D(f,x), D(f,x)) (a + b)*Derivative(f(x), x) >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), f) (a + b)*Derivative(f(x), (x, 2)) >>> collect(a*D(D(f,x),x) + b*D(D(f,x),x), D(f,x), exact=True) a*Derivative(f(x), (x, 2)) + b*Derivative(f(x), (x, 2)) >>> collect(a*D(f,x) + b*D(f,x) + a*f + b*f, f) (a + b)*f(x) + (a + b)*Derivative(f(x), x) Or you can even match both derivative order and exponent at the same time:: >>> collect(a*D(D(f,x),x)**2 + b*D(D(f,x),x)**2, D(f,x)) (a + b)*Derivative(f(x), (x, 2))**2 Finally, you can apply a function to each of the collected coefficients. For example you can factorize symbolic coefficients of polynomial:: >>> f = expand((x + a + 1)**3) >>> collect(f, x, factor) x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + (a + 1)**3 .. note:: Arguments are expected to be in expanded form, so you might have to call :func:`~.expand` prior to calling this function. See Also ======== collect_const, collect_sqrt, rcollect """ from sympy.core.assumptions import assumptions from sympy.utilities.iterables import sift from sympy.core.symbol import Dummy, Wild expr = sympify(expr) syms = [sympify(i) for i in (syms if iterable(syms) else [syms])] # replace syms[i] if it is not x, -x or has Wild symbols cond = lambda x: x.is_Symbol or (-x).is_Symbol or bool( x.atoms(Wild)) _, nonsyms = sift(syms, cond, binary=True) if nonsyms: reps = dict(zip(nonsyms, [Dummy(**assumptions(i)) for i in nonsyms])) syms = [reps.get(s, s) for s in syms] rv = collect(expr.subs(reps), syms, func=func, evaluate=evaluate, exact=exact, distribute_order_term=distribute_order_term) urep = {v: k for k, v in reps.items()} if not isinstance(rv, dict): return rv.xreplace(urep) else: return {urep.get(k, k).xreplace(urep): v.xreplace(urep) for k, v in rv.items()} if evaluate is None: evaluate = global_parameters.evaluate def make_expression(terms): product = [] for term, rat, sym, deriv in terms: if deriv is not None: var, order = deriv while order > 0: term, order = Derivative(term, var), order - 1 if sym is None: if rat is S.One: product.append(term) else: product.append(Pow(term, rat)) else: product.append(Pow(term, rat*sym)) return Mul(*product) def parse_derivative(deriv): # scan derivatives tower in the input expression and return # underlying function and maximal differentiation order expr, sym, order = deriv.expr, deriv.variables[0], 1 for s in deriv.variables[1:]: if s == sym: order += 1 else: raise NotImplementedError( 'Improve MV Derivative support in collect') while isinstance(expr, Derivative): s0 = expr.variables[0] for s in expr.variables: if s != s0: raise NotImplementedError( 'Improve MV Derivative support in collect') if s0 == sym: expr, order = expr.expr, order + len(expr.variables) else: break return expr, (sym, Rational(order)) def parse_term(expr): """Parses expression expr and outputs tuple (sexpr, rat_expo, sym_expo, deriv) where: - sexpr is the base expression - rat_expo is the rational exponent that sexpr is raised to - sym_expo is the symbolic exponent that sexpr is raised to - deriv contains the derivatives the the expression For example, the output of x would be (x, 1, None, None) the output of 2**x would be (2, 1, x, None). """ rat_expo, sym_expo = S.One, None sexpr, deriv = expr, None if expr.is_Pow: if isinstance(expr.base, Derivative): sexpr, deriv = parse_derivative(expr.base) else: sexpr = expr.base if expr.base == S.Exp1: arg = expr.exp if arg.is_Rational: sexpr, rat_expo = S.Exp1, arg elif arg.is_Mul: coeff, tail = arg.as_coeff_Mul(rational=True) sexpr, rat_expo = exp(tail), coeff elif expr.exp.is_Number: rat_expo = expr.exp else: coeff, tail = expr.exp.as_coeff_Mul() if coeff.is_Number: rat_expo, sym_expo = coeff, tail else: sym_expo = expr.exp elif isinstance(expr, exp): arg = expr.exp if arg.is_Rational: sexpr, rat_expo = S.Exp1, arg elif arg.is_Mul: coeff, tail = arg.as_coeff_Mul(rational=True) sexpr, rat_expo = exp(tail), coeff elif isinstance(expr, Derivative): sexpr, deriv = parse_derivative(expr) return sexpr, rat_expo, sym_expo, deriv def parse_expression(terms, pattern): """Parse terms searching for a pattern. Terms is a list of tuples as returned by parse_terms; Pattern is an expression treated as a product of factors. """ pattern = Mul.make_args(pattern) if len(terms) < len(pattern): # pattern is longer than matched product # so no chance for positive parsing result return None else: pattern = [parse_term(elem) for elem in pattern] terms = terms[:] # need a copy elems, common_expo, has_deriv = [], None, False for elem, e_rat, e_sym, e_ord in pattern: if elem.is_Number and e_rat == 1 and e_sym is None: # a constant is a match for everything continue for j in range(len(terms)): if terms[j] is None: continue term, t_rat, t_sym, t_ord = terms[j] # keeping track of whether one of the terms had # a derivative or not as this will require rebuilding # the expression later if t_ord is not None: has_deriv = True if (term.match(elem) is not None and (t_sym == e_sym or t_sym is not None and e_sym is not None and t_sym.match(e_sym) is not None)): if exact is False: # we don't have to be exact so find common exponent # for both expression's term and pattern's element expo = t_rat / e_rat if common_expo is None: # first time common_expo = expo else: # common exponent was negotiated before so # there is no chance for a pattern match unless # common and current exponents are equal if common_expo != expo: common_expo = 1 else: # we ought to be exact so all fields of # interest must match in every details if e_rat != t_rat or e_ord != t_ord: continue # found common term so remove it from the expression # and try to match next element in the pattern elems.append(terms[j]) terms[j] = None break else: # pattern element not found return None return [_f for _f in terms if _f], elems, common_expo, has_deriv if evaluate: if expr.is_Add: o = expr.getO() or 0 expr = expr.func(*[ collect(a, syms, func, True, exact, distribute_order_term) for a in expr.args if a != o]) + o elif expr.is_Mul: return expr.func(*[ collect(term, syms, func, True, exact, distribute_order_term) for term in expr.args]) elif expr.is_Pow: b = collect( expr.base, syms, func, True, exact, distribute_order_term) return Pow(b, expr.exp) syms = [expand_power_base(i, deep=False) for i in syms] order_term = None if distribute_order_term: order_term = expr.getO() if order_term is not None: if order_term.has(*syms): order_term = None else: expr = expr.removeO() summa = [expand_power_base(i, deep=False) for i in Add.make_args(expr)] collected, disliked = defaultdict(list), S.Zero for product in summa: c, nc = product.args_cnc(split_1=False) args = list(ordered(c)) + nc terms = [parse_term(i) for i in args] small_first = True for symbol in syms: if SYMPY_DEBUG: print("DEBUG: parsing of expression %s with symbol %s " % ( str(terms), str(symbol)) ) if isinstance(symbol, Derivative) and small_first: terms = list(reversed(terms)) small_first = not small_first result = parse_expression(terms, symbol) if SYMPY_DEBUG: print("DEBUG: returned %s" % str(result)) if result is not None: if not symbol.is_commutative: raise AttributeError("Can not collect noncommutative symbol") terms, elems, common_expo, has_deriv = result # when there was derivative in current pattern we # will need to rebuild its expression from scratch if not has_deriv: margs = [] for elem in elems: if elem[2] is None: e = elem[1] else: e = elem[1]*elem[2] margs.append(Pow(elem[0], e)) index = Mul(*margs) else: index = make_expression(elems) terms = expand_power_base(make_expression(terms), deep=False) index = expand_power_base(index, deep=False) collected[index].append(terms) break else: # none of the patterns matched disliked += product # add terms now for each key collected = {k: Add(*v) for k, v in collected.items()} if disliked is not S.Zero: collected[S.One] = disliked if order_term is not None: for key, val in collected.items(): collected[key] = val + order_term if func is not None: collected = { key: func(val) for key, val in collected.items()} if evaluate: return Add(*[key*val for key, val in collected.items()]) else: return collected def rcollect(expr, *vars): """ Recursively collect sums in an expression. Examples ======== >>> from sympy.simplify import rcollect >>> from sympy.abc import x, y >>> expr = (x**2*y + x*y + x + y)/(x + y) >>> rcollect(expr, y) (x + y*(x**2 + x + 1))/(x + y) See Also ======== collect, collect_const, collect_sqrt """ if expr.is_Atom or not expr.has(*vars): return expr else: expr = expr.__class__(*[rcollect(arg, *vars) for arg in expr.args]) if expr.is_Add: return collect(expr, vars) else: return expr def collect_sqrt(expr, evaluate=None): """Return expr with terms having common square roots collected together. If ``evaluate`` is False a count indicating the number of sqrt-containing terms will be returned and, if non-zero, the terms of the Add will be returned, else the expression itself will be returned as a single term. If ``evaluate`` is True, the expression with any collected terms will be returned. Note: since I = sqrt(-1), it is collected, too. Examples ======== >>> from sympy import sqrt >>> from sympy.simplify.radsimp import collect_sqrt >>> from sympy.abc import a, b >>> r2, r3, r5 = [sqrt(i) for i in [2, 3, 5]] >>> collect_sqrt(a*r2 + b*r2) sqrt(2)*(a + b) >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r3) sqrt(2)*(a + b) + sqrt(3)*(a + b) >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r5) sqrt(3)*a + sqrt(5)*b + sqrt(2)*(a + b) If evaluate is False then the arguments will be sorted and returned as a list and a count of the number of sqrt-containing terms will be returned: >>> collect_sqrt(a*r2 + b*r2 + a*r3 + b*r5, evaluate=False) ((sqrt(3)*a, sqrt(5)*b, sqrt(2)*(a + b)), 3) >>> collect_sqrt(a*sqrt(2) + b, evaluate=False) ((b, sqrt(2)*a), 1) >>> collect_sqrt(a + b, evaluate=False) ((a + b,), 0) See Also ======== collect, collect_const, rcollect """ if evaluate is None: evaluate = global_parameters.evaluate # this step will help to standardize any complex arguments # of sqrts coeff, expr = expr.as_content_primitive() vars = set() for a in Add.make_args(expr): for m in a.args_cnc()[0]: if m.is_number and ( m.is_Pow and m.exp.is_Rational and m.exp.q == 2 or m is S.ImaginaryUnit): vars.add(m) # we only want radicals, so exclude Number handling; in this case # d will be evaluated d = collect_const(expr, *vars, Numbers=False) hit = expr != d if not evaluate: nrad = 0 # make the evaluated args canonical args = list(ordered(Add.make_args(d))) for i, m in enumerate(args): c, nc = m.args_cnc() for ci in c: # XXX should this be restricted to ci.is_number as above? if ci.is_Pow and ci.exp.is_Rational and ci.exp.q == 2 or \ ci is S.ImaginaryUnit: nrad += 1 break args[i] *= coeff if not (hit or nrad): args = [Add(*args)] return tuple(args), nrad return coeff*d def collect_abs(expr): """Return ``expr`` with arguments of multiple Abs in a term collected under a single instance. Examples ======== >>> from sympy.simplify.radsimp import collect_abs >>> from sympy.abc import x >>> collect_abs(abs(x + 1)/abs(x**2 - 1)) Abs((x + 1)/(x**2 - 1)) >>> collect_abs(abs(1/x)) Abs(1/x) """ def _abs(mul): from sympy.core.mul import _mulsort c, nc = mul.args_cnc() a = [] o = [] for i in c: if isinstance(i, Abs): a.append(i.args[0]) elif isinstance(i, Pow) and isinstance(i.base, Abs) and i.exp.is_real: a.append(i.base.args[0]**i.exp) else: o.append(i) if len(a) < 2 and not any(i.exp.is_negative for i in a if isinstance(i, Pow)): return mul absarg = Mul(*a) A = Abs(absarg) args = [A] args.extend(o) if not A.has(Abs): args.extend(nc) return Mul(*args) if not isinstance(A, Abs): # reevaluate and make it unevaluated A = Abs(absarg, evaluate=False) args[0] = A _mulsort(args) args.extend(nc) # nc always go last return Mul._from_args(args, is_commutative=not nc) return expr.replace( lambda x: isinstance(x, Mul), lambda x: _abs(x)).replace( lambda x: isinstance(x, Pow), lambda x: _abs(x)) def collect_const(expr, *vars, Numbers=True): """A non-greedy collection of terms with similar number coefficients in an Add expr. If ``vars`` is given then only those constants will be targeted. Although any Number can also be targeted, if this is not desired set ``Numbers=False`` and no Float or Rational will be collected. Parameters ========== expr : sympy expression This parameter defines the expression the expression from which terms with similar coefficients are to be collected. A non-Add expression is returned as it is. vars : variable length collection of Numbers, optional Specifies the constants to target for collection. Can be multiple in number. Numbers : bool Specifies to target all instance of :class:`sympy.core.numbers.Number` class. If ``Numbers=False``, then no Float or Rational will be collected. Returns ======= expr : Expr Returns an expression with similar coefficient terms collected. Examples ======== >>> from sympy import sqrt >>> from sympy.abc import s, x, y, z >>> from sympy.simplify.radsimp import collect_const >>> collect_const(sqrt(3) + sqrt(3)*(1 + sqrt(2))) sqrt(3)*(sqrt(2) + 2) >>> collect_const(sqrt(3)*s + sqrt(7)*s + sqrt(3) + sqrt(7)) (sqrt(3) + sqrt(7))*(s + 1) >>> s = sqrt(2) + 2 >>> collect_const(sqrt(3)*s + sqrt(3) + sqrt(7)*s + sqrt(7)) (sqrt(2) + 3)*(sqrt(3) + sqrt(7)) >>> collect_const(sqrt(3)*s + sqrt(3) + sqrt(7)*s + sqrt(7), sqrt(3)) sqrt(7) + sqrt(3)*(sqrt(2) + 3) + sqrt(7)*(sqrt(2) + 2) The collection is sign-sensitive, giving higher precedence to the unsigned values: >>> collect_const(x - y - z) x - (y + z) >>> collect_const(-y - z) -(y + z) >>> collect_const(2*x - 2*y - 2*z, 2) 2*(x - y - z) >>> collect_const(2*x - 2*y - 2*z, -2) 2*x - 2*(y + z) See Also ======== collect, collect_sqrt, rcollect """ if not expr.is_Add: return expr recurse = False if not vars: recurse = True vars = set() for a in expr.args: for m in Mul.make_args(a): if m.is_number: vars.add(m) else: vars = sympify(vars) if not Numbers: vars = [v for v in vars if not v.is_Number] vars = list(ordered(vars)) for v in vars: terms = defaultdict(list) Fv = Factors(v) for m in Add.make_args(expr): f = Factors(m) q, r = f.div(Fv) if r.is_one: # only accept this as a true factor if # it didn't change an exponent from an Integer # to a non-Integer, e.g. 2/sqrt(2) -> sqrt(2) # -- we aren't looking for this sort of change fwas = f.factors.copy() fnow = q.factors if not any(k in fwas and fwas[k].is_Integer and not fnow[k].is_Integer for k in fnow): terms[v].append(q.as_expr()) continue terms[S.One].append(m) args = [] hit = False uneval = False for k in ordered(terms): v = terms[k] if k is S.One: args.extend(v) continue if len(v) > 1: v = Add(*v) hit = True if recurse and v != expr: vars.append(v) else: v = v[0] # be careful not to let uneval become True unless # it must be because it's going to be more expensive # to rebuild the expression as an unevaluated one if Numbers and k.is_Number and v.is_Add: args.append(_keep_coeff(k, v, sign=True)) uneval = True else: args.append(k*v) if hit: if uneval: expr = _unevaluated_Add(*args) else: expr = Add(*args) if not expr.is_Add: break return expr def radsimp(expr, symbolic=True, max_terms=4): r""" Rationalize the denominator by removing square roots. Explanation =========== The expression returned from radsimp must be used with caution since if the denominator contains symbols, it will be possible to make substitutions that violate the assumptions of the simplification process: that for a denominator matching a + b*sqrt(c), a != +/-b*sqrt(c). (If there are no symbols, this assumptions is made valid by collecting terms of sqrt(c) so the match variable ``a`` does not contain ``sqrt(c)``.) If you do not want the simplification to occur for symbolic denominators, set ``symbolic`` to False. If there are more than ``max_terms`` radical terms then the expression is returned unchanged. Examples ======== >>> from sympy import radsimp, sqrt, Symbol, pprint >>> from sympy import factor_terms, fraction, signsimp >>> from sympy.simplify.radsimp import collect_sqrt >>> from sympy.abc import a, b, c >>> radsimp(1/(2 + sqrt(2))) (2 - sqrt(2))/2 >>> x,y = map(Symbol, 'xy') >>> e = ((2 + 2*sqrt(2))*x + (2 + sqrt(8))*y)/(2 + sqrt(2)) >>> radsimp(e) sqrt(2)*(x + y) No simplification beyond removal of the gcd is done. One might want to polish the result a little, however, by collecting square root terms: >>> r2 = sqrt(2) >>> r5 = sqrt(5) >>> ans = radsimp(1/(y*r2 + x*r2 + a*r5 + b*r5)); pprint(ans) ___ ___ ___ ___ \/ 5 *a + \/ 5 *b - \/ 2 *x - \/ 2 *y ------------------------------------------ 2 2 2 2 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y >>> n, d = fraction(ans) >>> pprint(factor_terms(signsimp(collect_sqrt(n))/d, radical=True)) ___ ___ \/ 5 *(a + b) - \/ 2 *(x + y) ------------------------------------------ 2 2 2 2 5*a + 10*a*b + 5*b - 2*x - 4*x*y - 2*y If radicals in the denominator cannot be removed or there is no denominator, the original expression will be returned. >>> radsimp(sqrt(2)*x + sqrt(2)) sqrt(2)*x + sqrt(2) Results with symbols will not always be valid for all substitutions: >>> eq = 1/(a + b*sqrt(c)) >>> eq.subs(a, b*sqrt(c)) 1/(2*b*sqrt(c)) >>> radsimp(eq).subs(a, b*sqrt(c)) nan If ``symbolic=False``, symbolic denominators will not be transformed (but numeric denominators will still be processed): >>> radsimp(eq, symbolic=False) 1/(a + b*sqrt(c)) """ from sympy.simplify.simplify import signsimp syms = symbols("a:d A:D") def _num(rterms): # return the multiplier that will simplify the expression described # by rterms [(sqrt arg, coeff), ... ] a, b, c, d, A, B, C, D = syms if len(rterms) == 2: reps = dict(list(zip([A, a, B, b], [j for i in rterms for j in i]))) return ( sqrt(A)*a - sqrt(B)*b).xreplace(reps) if len(rterms) == 3: reps = dict(list(zip([A, a, B, b, C, c], [j for i in rterms for j in i]))) return ( (sqrt(A)*a + sqrt(B)*b - sqrt(C)*c)*(2*sqrt(A)*sqrt(B)*a*b - A*a**2 - B*b**2 + C*c**2)).xreplace(reps) elif len(rterms) == 4: reps = dict(list(zip([A, a, B, b, C, c, D, d], [j for i in rterms for j in i]))) return ((sqrt(A)*a + sqrt(B)*b - sqrt(C)*c - sqrt(D)*d)*(2*sqrt(A)*sqrt(B)*a*b - A*a**2 - B*b**2 - 2*sqrt(C)*sqrt(D)*c*d + C*c**2 + D*d**2)*(-8*sqrt(A)*sqrt(B)*sqrt(C)*sqrt(D)*a*b*c*d + A**2*a**4 - 2*A*B*a**2*b**2 - 2*A*C*a**2*c**2 - 2*A*D*a**2*d**2 + B**2*b**4 - 2*B*C*b**2*c**2 - 2*B*D*b**2*d**2 + C**2*c**4 - 2*C*D*c**2*d**2 + D**2*d**4)).xreplace(reps) elif len(rterms) == 1: return sqrt(rterms[0][0]) else: raise NotImplementedError def ispow2(d, log2=False): if not d.is_Pow: return False e = d.exp if e.is_Rational and e.q == 2 or symbolic and denom(e) == 2: return True if log2: q = 1 if e.is_Rational: q = e.q elif symbolic: d = denom(e) if d.is_Integer: q = d if q != 1 and log(q, 2).is_Integer: return True return False def handle(expr): # Handle first reduces to the case # expr = 1/d, where d is an add, or d is base**p/2. # We do this by recursively calling handle on each piece. from sympy.simplify.simplify import nsimplify n, d = fraction(expr) if expr.is_Atom or (d.is_Atom and n.is_Atom): return expr elif not n.is_Atom: n = n.func(*[handle(a) for a in n.args]) return _unevaluated_Mul(n, handle(1/d)) elif n is not S.One: return _unevaluated_Mul(n, handle(1/d)) elif d.is_Mul: return _unevaluated_Mul(*[handle(1/d) for d in d.args]) # By this step, expr is 1/d, and d is not a mul. if not symbolic and d.free_symbols: return expr if ispow2(d): d2 = sqrtdenest(sqrt(d.base))**numer(d.exp) if d2 != d: return handle(1/d2) elif d.is_Pow and (d.exp.is_integer or d.base.is_positive): # (1/d**i) = (1/d)**i return handle(1/d.base)**d.exp if not (d.is_Add or ispow2(d)): return 1/d.func(*[handle(a) for a in d.args]) # handle 1/d treating d as an Add (though it may not be) keep = True # keep changes that are made # flatten it and collect radicals after checking for special # conditions d = _mexpand(d) # did it change? if d.is_Atom: return 1/d # is it a number that might be handled easily? if d.is_number: _d = nsimplify(d) if _d.is_Number and _d.equals(d): return 1/_d while True: # collect similar terms collected = defaultdict(list) for m in Add.make_args(d): # d might have become non-Add p2 = [] other = [] for i in Mul.make_args(m): if ispow2(i, log2=True): p2.append(i.base if i.exp is S.Half else i.base**(2*i.exp)) elif i is S.ImaginaryUnit: p2.append(S.NegativeOne) else: other.append(i) collected[tuple(ordered(p2))].append(Mul(*other)) rterms = list(ordered(list(collected.items()))) rterms = [(Mul(*i), Add(*j)) for i, j in rterms] nrad = len(rterms) - (1 if rterms[0][0] is S.One else 0) if nrad < 1: break elif nrad > max_terms: # there may have been invalid operations leading to this point # so don't keep changes, e.g. this expression is troublesome # in collecting terms so as not to raise the issue of 2834: # r = sqrt(sqrt(5) + 5) # eq = 1/(sqrt(5)*r + 2*sqrt(5)*sqrt(-sqrt(5) + 5) + 5*r) keep = False break if len(rterms) > 4: # in general, only 4 terms can be removed with repeated squaring # but other considerations can guide selection of radical terms # so that radicals are removed if all([x.is_Integer and (y**2).is_Rational for x, y in rterms]): nd, d = rad_rationalize(S.One, Add._from_args( [sqrt(x)*y for x, y in rterms])) n *= nd else: # is there anything else that might be attempted? keep = False break from sympy.simplify.powsimp import powsimp, powdenest num = powsimp(_num(rterms)) n *= num d *= num d = powdenest(_mexpand(d), force=symbolic) if d.has(S.Zero, nan, zoo): return expr if d.is_Atom: break if not keep: return expr return _unevaluated_Mul(n, 1/d) coeff, expr = expr.as_coeff_Add() expr = expr.normal() old = fraction(expr) n, d = fraction(handle(expr)) if old != (n, d): if not d.is_Atom: was = (n, d) n = signsimp(n, evaluate=False) d = signsimp(d, evaluate=False) u = Factors(_unevaluated_Mul(n, 1/d)) u = _unevaluated_Mul(*[k**v for k, v in u.factors.items()]) n, d = fraction(u) if old == (n, d): n, d = was n = expand_mul(n) if d.is_Number or d.is_Add: n2, d2 = fraction(gcd_terms(_unevaluated_Mul(n, 1/d))) if d2.is_Number or (d2.count_ops() <= d.count_ops()): n, d = [signsimp(i) for i in (n2, d2)] if n.is_Mul and n.args[0].is_Number: n = n.func(*n.args) return coeff + _unevaluated_Mul(n, 1/d) def rad_rationalize(num, den): """ Rationalize ``num/den`` by removing square roots in the denominator; num and den are sum of terms whose squares are positive rationals. Examples ======== >>> from sympy import sqrt >>> from sympy.simplify.radsimp import rad_rationalize >>> rad_rationalize(sqrt(3), 1 + sqrt(2)/3) (-sqrt(3) + sqrt(6)/3, -7/9) """ if not den.is_Add: return num, den g, a, b = split_surds(den) a = a*sqrt(g) num = _mexpand((a - b)*num) den = _mexpand(a**2 - b**2) return rad_rationalize(num, den) def fraction(expr, exact=False): """Returns a pair with expression's numerator and denominator. If the given expression is not a fraction then this function will return the tuple (expr, 1). This function will not make any attempt to simplify nested fractions or to do any term rewriting at all. If only one of the numerator/denominator pair is needed then use numer(expr) or denom(expr) functions respectively. >>> from sympy import fraction, Rational, Symbol >>> from sympy.abc import x, y >>> fraction(x/y) (x, y) >>> fraction(x) (x, 1) >>> fraction(1/y**2) (1, y**2) >>> fraction(x*y/2) (x*y, 2) >>> fraction(Rational(1, 2)) (1, 2) This function will also work fine with assumptions: >>> k = Symbol('k', negative=True) >>> fraction(x * y**k) (x, y**(-k)) If we know nothing about sign of some exponent and ``exact`` flag is unset, then structure this exponent's structure will be analyzed and pretty fraction will be returned: >>> from sympy import exp, Mul >>> fraction(2*x**(-y)) (2, x**y) >>> fraction(exp(-x)) (1, exp(x)) >>> fraction(exp(-x), exact=True) (exp(-x), 1) The ``exact`` flag will also keep any unevaluated Muls from being evaluated: >>> u = Mul(2, x + 1, evaluate=False) >>> fraction(u) (2*x + 2, 1) >>> fraction(u, exact=True) (2*(x + 1), 1) """ expr = sympify(expr) numer, denom = [], [] for term in Mul.make_args(expr): if term.is_commutative and (term.is_Pow or isinstance(term, exp)): b, ex = term.as_base_exp() if ex.is_negative: if ex is S.NegativeOne: denom.append(b) elif exact: if ex.is_constant(): denom.append(Pow(b, -ex)) else: numer.append(term) else: denom.append(Pow(b, -ex)) elif ex.is_positive: numer.append(term) elif not exact and ex.is_Mul: n, d = term.as_numer_denom() if n != 1: numer.append(n) denom.append(d) else: numer.append(term) elif term.is_Rational and not term.is_Integer: if term.p != 1: numer.append(term.p) denom.append(term.q) else: numer.append(term) return Mul(*numer, evaluate=not exact), Mul(*denom, evaluate=not exact) def numer(expr): return fraction(expr)[0] def denom(expr): return fraction(expr)[1] def fraction_expand(expr, **hints): return expr.expand(frac=True, **hints) def numer_expand(expr, **hints): a, b = fraction(expr) return a.expand(numer=True, **hints) / b def denom_expand(expr, **hints): a, b = fraction(expr) return a / b.expand(denom=True, **hints) expand_numer = numer_expand expand_denom = denom_expand expand_fraction = fraction_expand def split_surds(expr): """ Split an expression with terms whose squares are positive rationals into a sum of terms whose surds squared have gcd equal to g and a sum of terms with surds squared prime with g. Examples ======== >>> from sympy import sqrt >>> from sympy.simplify.radsimp import split_surds >>> split_surds(3*sqrt(3) + sqrt(5)/7 + sqrt(6) + sqrt(10) + sqrt(15)) (3, sqrt(2) + sqrt(5) + 3, sqrt(5)/7 + sqrt(10)) """ args = sorted(expr.args, key=default_sort_key) coeff_muls = [x.as_coeff_Mul() for x in args] surds = [x[1]**2 for x in coeff_muls if x[1].is_Pow] surds.sort(key=default_sort_key) g, b1, b2 = _split_gcd(*surds) g2 = g if not b2 and len(b1) >= 2: b1n = [x/g for x in b1] b1n = [x for x in b1n if x != 1] # only a common factor has been factored; split again g1, b1n, b2 = _split_gcd(*b1n) g2 = g*g1 a1v, a2v = [], [] for c, s in coeff_muls: if s.is_Pow and s.exp == S.Half: s1 = s.base if s1 in b1: a1v.append(c*sqrt(s1/g2)) else: a2v.append(c*s) else: a2v.append(c*s) a = Add(*a1v) b = Add(*a2v) return g2, a, b def _split_gcd(*a): """ Split the list of integers ``a`` into a list of integers, ``a1`` having ``g = gcd(a1)``, and a list ``a2`` whose elements are not divisible by ``g``. Returns ``g, a1, a2``. Examples ======== >>> from sympy.simplify.radsimp import _split_gcd >>> _split_gcd(55, 35, 22, 14, 77, 10) (5, [55, 35, 10], [22, 14, 77]) """ g = a[0] b1 = [g] b2 = [] for x in a[1:]: g1 = gcd(g, x) if g1 == 1: b2.append(x) else: g = g1 b1.append(x) return g, b1, b2 sympy-sympy-1.9/sympy/simplify/ratsimp.py000066400000000000000000000166641412543434000210060ustar00rootroot00000000000000from itertools import combinations_with_replacement from sympy.core import symbols, Add, Dummy from sympy.core.numbers import Rational from sympy.polys import cancel, ComputationFailed, parallel_poly_from_expr, reduced, Poly from sympy.polys.monomials import Monomial, monomial_div from sympy.polys.polyerrors import DomainError, PolificationFailed from sympy.utilities.misc import debug def ratsimp(expr): """ Put an expression over a common denominator, cancel and reduce. Examples ======== >>> from sympy import ratsimp >>> from sympy.abc import x, y >>> ratsimp(1/x + 1/y) (x + y)/(x*y) """ f, g = cancel(expr).as_numer_denom() try: Q, r = reduced(f, [g], field=True, expand=False) except ComputationFailed: return f/g return Add(*Q) + cancel(r/g) def ratsimpmodprime(expr, G, *gens, quick=True, polynomial=False, **args): """ Simplifies a rational expression ``expr`` modulo the prime ideal generated by ``G``. ``G`` should be a Groebner basis of the ideal. Examples ======== >>> from sympy.simplify.ratsimp import ratsimpmodprime >>> from sympy.abc import x, y >>> eq = (x + y**5 + y)/(x - y) >>> ratsimpmodprime(eq, [x*y**5 - x - y], x, y, order='lex') (-x**2 - x*y - x - y)/(-x**2 + x*y) If ``polynomial`` is ``False``, the algorithm computes a rational simplification which minimizes the sum of the total degrees of the numerator and the denominator. If ``polynomial`` is ``True``, this function just brings numerator and denominator into a canonical form. This is much faster, but has potentially worse results. References ========== .. [1] M. Monagan, R. Pearce, Rational Simplification Modulo a Polynomial Ideal, http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.163.6984 (specifically, the second algorithm) """ from sympy import solve debug('ratsimpmodprime', expr) # usual preparation of polynomials: num, denom = cancel(expr).as_numer_denom() try: polys, opt = parallel_poly_from_expr([num, denom] + G, *gens, **args) except PolificationFailed: return expr domain = opt.domain if domain.has_assoc_Field: opt.domain = domain.get_field() else: raise DomainError( "can't compute rational simplification over %s" % domain) # compute only once leading_monomials = [g.LM(opt.order) for g in polys[2:]] tested = set() def staircase(n): """ Compute all monomials with degree less than ``n`` that are not divisible by any element of ``leading_monomials``. """ if n == 0: return [1] S = [] for mi in combinations_with_replacement(range(len(opt.gens)), n): m = [0]*len(opt.gens) for i in mi: m[i] += 1 if all([monomial_div(m, lmg) is None for lmg in leading_monomials]): S.append(m) return [Monomial(s).as_expr(*opt.gens) for s in S] + staircase(n - 1) def _ratsimpmodprime(a, b, allsol, N=0, D=0): r""" Computes a rational simplification of ``a/b`` which minimizes the sum of the total degrees of the numerator and the denominator. Explanation =========== The algorithm proceeds by looking at ``a * d - b * c`` modulo the ideal generated by ``G`` for some ``c`` and ``d`` with degree less than ``a`` and ``b`` respectively. The coefficients of ``c`` and ``d`` are indeterminates and thus the coefficients of the normalform of ``a * d - b * c`` are linear polynomials in these indeterminates. If these linear polynomials, considered as system of equations, have a nontrivial solution, then `\frac{a}{b} \equiv \frac{c}{d}` modulo the ideal generated by ``G``. So, by construction, the degree of ``c`` and ``d`` is less than the degree of ``a`` and ``b``, so a simpler representation has been found. After a simpler representation has been found, the algorithm tries to reduce the degree of the numerator and denominator and returns the result afterwards. As an extension, if quick=False, we look at all possible degrees such that the total degree is less than *or equal to* the best current solution. We retain a list of all solutions of minimal degree, and try to find the best one at the end. """ c, d = a, b steps = 0 maxdeg = a.total_degree() + b.total_degree() if quick: bound = maxdeg - 1 else: bound = maxdeg while N + D <= bound: if (N, D) in tested: break tested.add((N, D)) M1 = staircase(N) M2 = staircase(D) debug('%s / %s: %s, %s' % (N, D, M1, M2)) Cs = symbols("c:%d" % len(M1), cls=Dummy) Ds = symbols("d:%d" % len(M2), cls=Dummy) ng = Cs + Ds c_hat = Poly( sum([Cs[i] * M1[i] for i in range(len(M1))]), opt.gens + ng) d_hat = Poly( sum([Ds[i] * M2[i] for i in range(len(M2))]), opt.gens + ng) r = reduced(a * d_hat - b * c_hat, G, opt.gens + ng, order=opt.order, polys=True)[1] S = Poly(r, gens=opt.gens).coeffs() sol = solve(S, Cs + Ds, particular=True, quick=True) if sol and not all([s == 0 for s in sol.values()]): c = c_hat.subs(sol) d = d_hat.subs(sol) # The "free" variables occurring before as parameters # might still be in the substituted c, d, so set them # to the value chosen before: c = c.subs(dict(list(zip(Cs + Ds, [1] * (len(Cs) + len(Ds)))))) d = d.subs(dict(list(zip(Cs + Ds, [1] * (len(Cs) + len(Ds)))))) c = Poly(c, opt.gens) d = Poly(d, opt.gens) if d == 0: raise ValueError('Ideal not prime?') allsol.append((c_hat, d_hat, S, Cs + Ds)) if N + D != maxdeg: allsol = [allsol[-1]] break steps += 1 N += 1 D += 1 if steps > 0: c, d, allsol = _ratsimpmodprime(c, d, allsol, N, D - steps) c, d, allsol = _ratsimpmodprime(c, d, allsol, N - steps, D) return c, d, allsol # preprocessing. this improves performance a bit when deg(num) # and deg(denom) are large: num = reduced(num, G, opt.gens, order=opt.order)[1] denom = reduced(denom, G, opt.gens, order=opt.order)[1] if polynomial: return (num/denom).cancel() c, d, allsol = _ratsimpmodprime( Poly(num, opt.gens, domain=opt.domain), Poly(denom, opt.gens, domain=opt.domain), []) if not quick and allsol: debug('Looking for best minimal solution. Got: %s' % len(allsol)) newsol = [] for c_hat, d_hat, S, ng in allsol: sol = solve(S, ng, particular=True, quick=False) newsol.append((c_hat.subs(sol), d_hat.subs(sol))) c, d = min(newsol, key=lambda x: len(x[0].terms()) + len(x[1].terms())) if not domain.is_Field: cn, c = c.clear_denoms(convert=True) dn, d = d.clear_denoms(convert=True) r = Rational(cn, dn) else: r = Rational(1) return (c*r.q)/(d*r.p) sympy-sympy-1.9/sympy/simplify/simplify.py000066400000000000000000002172441412543434000211600ustar00rootroot00000000000000from collections import defaultdict from sympy.core import (Basic, S, Add, Mul, Pow, Symbol, sympify, expand_func, Function, Dummy, Expr, factor_terms, expand_power_exp, Eq) from sympy.core.compatibility import iterable, ordered, as_int from sympy.core.parameters import global_parameters from sympy.core.function import (expand_log, count_ops, _mexpand, _coeff_isneg, nfloat, expand_mul) from sympy.core.numbers import Float, I, pi, Rational, Integer from sympy.core.relational import Relational from sympy.core.rules import Transform from sympy.core.sympify import _sympify from sympy.functions import gamma, exp, sqrt, log, exp_polar, re from sympy.functions.combinatorial.factorials import CombinatorialFunction from sympy.functions.elementary.complexes import unpolarify, Abs from sympy.functions.elementary.exponential import ExpBase from sympy.functions.elementary.hyperbolic import HyperbolicFunction from sympy.functions.elementary.integers import ceiling from sympy.functions.elementary.piecewise import Piecewise, piecewise_fold from sympy.functions.elementary.trigonometric import TrigonometricFunction from sympy.functions.special.bessel import besselj, besseli, besselk, jn, bessely from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.polys import together, cancel, factor from sympy.simplify.combsimp import combsimp from sympy.simplify.cse_opts import sub_pre, sub_post from sympy.simplify.powsimp import powsimp from sympy.simplify.radsimp import radsimp, fraction, collect_abs from sympy.simplify.sqrtdenest import sqrtdenest from sympy.simplify.trigsimp import trigsimp, exptrigsimp from sympy.utilities.iterables import has_variety, sift import mpmath def separatevars(expr, symbols=[], dict=False, force=False): """ Separates variables in an expression, if possible. By default, it separates with respect to all symbols in an expression and collects constant coefficients that are independent of symbols. Explanation =========== If ``dict=True`` then the separated terms will be returned in a dictionary keyed to their corresponding symbols. By default, all symbols in the expression will appear as keys; if symbols are provided, then all those symbols will be used as keys, and any terms in the expression containing other symbols or non-symbols will be returned keyed to the string 'coeff'. (Passing None for symbols will return the expression in a dictionary keyed to 'coeff'.) If ``force=True``, then bases of powers will be separated regardless of assumptions on the symbols involved. Notes ===== The order of the factors is determined by Mul, so that the separated expressions may not necessarily be grouped together. Although factoring is necessary to separate variables in some expressions, it is not necessary in all cases, so one should not count on the returned factors being factored. Examples ======== >>> from sympy.abc import x, y, z, alpha >>> from sympy import separatevars, sin >>> separatevars((x*y)**y) (x*y)**y >>> separatevars((x*y)**y, force=True) x**y*y**y >>> e = 2*x**2*z*sin(y)+2*z*x**2 >>> separatevars(e) 2*x**2*z*(sin(y) + 1) >>> separatevars(e, symbols=(x, y), dict=True) {'coeff': 2*z, x: x**2, y: sin(y) + 1} >>> separatevars(e, [x, y, alpha], dict=True) {'coeff': 2*z, alpha: 1, x: x**2, y: sin(y) + 1} If the expression is not really separable, or is only partially separable, separatevars will do the best it can to separate it by using factoring. >>> separatevars(x + x*y - 3*x**2) -x*(3*x - y - 1) If the expression is not separable then expr is returned unchanged or (if dict=True) then None is returned. >>> eq = 2*x + y*sin(x) >>> separatevars(eq) == eq True >>> separatevars(2*x + y*sin(x), symbols=(x, y), dict=True) is None True """ expr = sympify(expr) if dict: return _separatevars_dict(_separatevars(expr, force), symbols) else: return _separatevars(expr, force) def _separatevars(expr, force): if isinstance(expr, Abs): arg = expr.args[0] if arg.is_Mul and not arg.is_number: s = separatevars(arg, dict=True, force=force) if s is not None: return Mul(*map(expr.func, s.values())) else: return expr if len(expr.free_symbols) < 2: return expr # don't destroy a Mul since much of the work may already be done if expr.is_Mul: args = list(expr.args) changed = False for i, a in enumerate(args): args[i] = separatevars(a, force) changed = changed or args[i] != a if changed: expr = expr.func(*args) return expr # get a Pow ready for expansion if expr.is_Pow and expr.base != S.Exp1: expr = Pow(separatevars(expr.base, force=force), expr.exp) # First try other expansion methods expr = expr.expand(mul=False, multinomial=False, force=force) _expr, reps = posify(expr) if force else (expr, {}) expr = factor(_expr).subs(reps) if not expr.is_Add: return expr # Find any common coefficients to pull out args = list(expr.args) commonc = args[0].args_cnc(cset=True, warn=False)[0] for i in args[1:]: commonc &= i.args_cnc(cset=True, warn=False)[0] commonc = Mul(*commonc) commonc = commonc.as_coeff_Mul()[1] # ignore constants commonc_set = commonc.args_cnc(cset=True, warn=False)[0] # remove them for i, a in enumerate(args): c, nc = a.args_cnc(cset=True, warn=False) c = c - commonc_set args[i] = Mul(*c)*Mul(*nc) nonsepar = Add(*args) if len(nonsepar.free_symbols) > 1: _expr = nonsepar _expr, reps = posify(_expr) if force else (_expr, {}) _expr = (factor(_expr)).subs(reps) if not _expr.is_Add: nonsepar = _expr return commonc*nonsepar def _separatevars_dict(expr, symbols): if symbols: if not all(t.is_Atom for t in symbols): raise ValueError("symbols must be Atoms.") symbols = list(symbols) elif symbols is None: return {'coeff': expr} else: symbols = list(expr.free_symbols) if not symbols: return None ret = {i: [] for i in symbols + ['coeff']} for i in Mul.make_args(expr): expsym = i.free_symbols intersection = set(symbols).intersection(expsym) if len(intersection) > 1: return None if len(intersection) == 0: # There are no symbols, so it is part of the coefficient ret['coeff'].append(i) else: ret[intersection.pop()].append(i) # rebuild for k, v in ret.items(): ret[k] = Mul(*v) return ret def _is_sum_surds(p): args = p.args if p.is_Add else [p] for y in args: if not ((y**2).is_Rational and y.is_extended_real): return False return True def posify(eq): """Return ``eq`` (with generic symbols made positive) and a dictionary containing the mapping between the old and new symbols. Explanation =========== Any symbol that has positive=None will be replaced with a positive dummy symbol having the same name. This replacement will allow more symbolic processing of expressions, especially those involving powers and logarithms. A dictionary that can be sent to subs to restore ``eq`` to its original symbols is also returned. >>> from sympy import posify, Symbol, log, solve >>> from sympy.abc import x >>> posify(x + Symbol('p', positive=True) + Symbol('n', negative=True)) (_x + n + p, {_x: x}) >>> eq = 1/x >>> log(eq).expand() log(1/x) >>> log(posify(eq)[0]).expand() -log(_x) >>> p, rep = posify(eq) >>> log(p).expand().subs(rep) -log(x) It is possible to apply the same transformations to an iterable of expressions: >>> eq = x**2 - 4 >>> solve(eq, x) [-2, 2] >>> eq_x, reps = posify([eq, x]); eq_x [_x**2 - 4, _x] >>> solve(*eq_x) [2] """ eq = sympify(eq) if iterable(eq): f = type(eq) eq = list(eq) syms = set() for e in eq: syms = syms.union(e.atoms(Symbol)) reps = {} for s in syms: reps.update({v: k for k, v in posify(s)[1].items()}) for i, e in enumerate(eq): eq[i] = e.subs(reps) return f(eq), {r: s for s, r in reps.items()} reps = {s: Dummy(s.name, positive=True, **s.assumptions0) for s in eq.free_symbols if s.is_positive is None} eq = eq.subs(reps) return eq, {r: s for s, r in reps.items()} def hypersimp(f, k): """Given combinatorial term f(k) simplify its consecutive term ratio i.e. f(k+1)/f(k). The input term can be composed of functions and integer sequences which have equivalent representation in terms of gamma special function. Explanation =========== The algorithm performs three basic steps: 1. Rewrite all functions in terms of gamma, if possible. 2. Rewrite all occurrences of gamma in terms of products of gamma and rising factorial with integer, absolute constant exponent. 3. Perform simplification of nested fractions, powers and if the resulting expression is a quotient of polynomials, reduce their total degree. If f(k) is hypergeometric then as result we arrive with a quotient of polynomials of minimal degree. Otherwise None is returned. For more information on the implemented algorithm refer to: 1. W. Koepf, Algorithms for m-fold Hypergeometric Summation, Journal of Symbolic Computation (1995) 20, 399-417 """ f = sympify(f) g = f.subs(k, k + 1) / f g = g.rewrite(gamma) if g.has(Piecewise): g = piecewise_fold(g) g = g.args[-1][0] g = expand_func(g) g = powsimp(g, deep=True, combine='exp') if g.is_rational_function(k): return simplify(g, ratio=S.Infinity) else: return None def hypersimilar(f, g, k): """ Returns True if ``f`` and ``g`` are hyper-similar. Explanation =========== Similarity in hypergeometric sense means that a quotient of f(k) and g(k) is a rational function in ``k``. This procedure is useful in solving recurrence relations. For more information see hypersimp(). """ f, g = list(map(sympify, (f, g))) h = (f/g).rewrite(gamma) h = h.expand(func=True, basic=False) return h.is_rational_function(k) def signsimp(expr, evaluate=None): """Make all Add sub-expressions canonical wrt sign. Explanation =========== If an Add subexpression, ``a``, can have a sign extracted, as determined by could_extract_minus_sign, it is replaced with Mul(-1, a, evaluate=False). This allows signs to be extracted from powers and products. Examples ======== >>> from sympy import signsimp, exp, symbols >>> from sympy.abc import x, y >>> i = symbols('i', odd=True) >>> n = -1 + 1/x >>> n/x/(-n)**2 - 1/n/x (-1 + 1/x)/(x*(1 - 1/x)**2) - 1/(x*(-1 + 1/x)) >>> signsimp(_) 0 >>> x*n + x*-n x*(-1 + 1/x) + x*(1 - 1/x) >>> signsimp(_) 0 Since powers automatically handle leading signs >>> (-2)**i -2**i signsimp can be used to put the base of a power with an integer exponent into canonical form: >>> n**i (-1 + 1/x)**i By default, signsimp doesn't leave behind any hollow simplification: if making an Add canonical wrt sign didn't change the expression, the original Add is restored. If this is not desired then the keyword ``evaluate`` can be set to False: >>> e = exp(y - x) >>> signsimp(e) == e True >>> signsimp(e, evaluate=False) exp(-(x - y)) """ if evaluate is None: evaluate = global_parameters.evaluate expr = sympify(expr) if not isinstance(expr, (Expr, Relational)) or expr.is_Atom: return expr e = sub_post(sub_pre(expr)) if not isinstance(e, (Expr, Relational)) or e.is_Atom: return e if e.is_Add: return e.func(*[signsimp(a, evaluate) for a in e.args]) if evaluate: e = e.xreplace({m: -(-m) for m in e.atoms(Mul) if -(-m) != m}) return e def simplify(expr, ratio=1.7, measure=count_ops, rational=False, inverse=False, doit=True, **kwargs): """Simplifies the given expression. Explanation =========== Simplification is not a well defined term and the exact strategies this function tries can change in the future versions of SymPy. If your algorithm relies on "simplification" (whatever it is), try to determine what you need exactly - is it powsimp()?, radsimp()?, together()?, logcombine()?, or something else? And use this particular function directly, because those are well defined and thus your algorithm will be robust. Nonetheless, especially for interactive use, or when you don't know anything about the structure of the expression, simplify() tries to apply intelligent heuristics to make the input expression "simpler". For example: >>> from sympy import simplify, cos, sin >>> from sympy.abc import x, y >>> a = (x + x**2)/(x*sin(y)**2 + x*cos(y)**2) >>> a (x**2 + x)/(x*sin(y)**2 + x*cos(y)**2) >>> simplify(a) x + 1 Note that we could have obtained the same result by using specific simplification functions: >>> from sympy import trigsimp, cancel >>> trigsimp(a) (x**2 + x)/x >>> cancel(_) x + 1 In some cases, applying :func:`simplify` may actually result in some more complicated expression. The default ``ratio=1.7`` prevents more extreme cases: if (result length)/(input length) > ratio, then input is returned unmodified. The ``measure`` parameter lets you specify the function used to determine how complex an expression is. The function should take a single argument as an expression and return a number such that if expression ``a`` is more complex than expression ``b``, then ``measure(a) > measure(b)``. The default measure function is :func:`~.count_ops`, which returns the total number of operations in the expression. For example, if ``ratio=1``, ``simplify`` output can't be longer than input. :: >>> from sympy import sqrt, simplify, count_ops, oo >>> root = 1/(sqrt(2)+3) Since ``simplify(root)`` would result in a slightly longer expression, root is returned unchanged instead:: >>> simplify(root, ratio=1) == root True If ``ratio=oo``, simplify will be applied anyway:: >>> count_ops(simplify(root, ratio=oo)) > count_ops(root) True Note that the shortest expression is not necessary the simplest, so setting ``ratio`` to 1 may not be a good idea. Heuristically, the default value ``ratio=1.7`` seems like a reasonable choice. You can easily define your own measure function based on what you feel should represent the "size" or "complexity" of the input expression. Note that some choices, such as ``lambda expr: len(str(expr))`` may appear to be good metrics, but have other problems (in this case, the measure function may slow down simplify too much for very large expressions). If you don't know what a good metric would be, the default, ``count_ops``, is a good one. For example: >>> from sympy import symbols, log >>> a, b = symbols('a b', positive=True) >>> g = log(a) + log(b) + log(a)*log(1/b) >>> h = simplify(g) >>> h log(a*b**(1 - log(a))) >>> count_ops(g) 8 >>> count_ops(h) 5 So you can see that ``h`` is simpler than ``g`` using the count_ops metric. However, we may not like how ``simplify`` (in this case, using ``logcombine``) has created the ``b**(log(1/a) + 1)`` term. A simple way to reduce this would be to give more weight to powers as operations in ``count_ops``. We can do this by using the ``visual=True`` option: >>> print(count_ops(g, visual=True)) 2*ADD + DIV + 4*LOG + MUL >>> print(count_ops(h, visual=True)) 2*LOG + MUL + POW + SUB >>> from sympy import Symbol, S >>> def my_measure(expr): ... POW = Symbol('POW') ... # Discourage powers by giving POW a weight of 10 ... count = count_ops(expr, visual=True).subs(POW, 10) ... # Every other operation gets a weight of 1 (the default) ... count = count.replace(Symbol, type(S.One)) ... return count >>> my_measure(g) 8 >>> my_measure(h) 14 >>> 15./8 > 1.7 # 1.7 is the default ratio True >>> simplify(g, measure=my_measure) -log(a)*log(b) + log(a) + log(b) Note that because ``simplify()`` internally tries many different simplification strategies and then compares them using the measure function, we get a completely different result that is still different from the input expression by doing this. If ``rational=True``, Floats will be recast as Rationals before simplification. If ``rational=None``, Floats will be recast as Rationals but the result will be recast as Floats. If rational=False(default) then nothing will be done to the Floats. If ``inverse=True``, it will be assumed that a composition of inverse functions, such as sin and asin, can be cancelled in any order. For example, ``asin(sin(x))`` will yield ``x`` without checking whether x belongs to the set where this relation is true. The default is False. Note that ``simplify()`` automatically calls ``doit()`` on the final expression. You can avoid this behavior by passing ``doit=False`` as an argument. Also, it should be noted that simplifying the boolian expression is not well defined. If the expression prefers automatic evaluation (such as :obj:`~.Eq()` or :obj:`~.Or()`), simplification will return ``True`` or ``False`` if truth value can be determined. If the expression is not evaluated by default (such as :obj:`~.Predicate()`), simplification will not reduce it and you should use :func:`~.refine()` or :func:`~.ask()` function. This inconsistency will be resolved in future version. See Also ======== sympy.assumptions.refine.refine : Simplification using assumptions. sympy.assumptions.ask.ask : Query for boolean expressions using assumptions. """ def shorter(*choices): """ Return the choice that has the fewest ops. In case of a tie, the expression listed first is selected. """ if not has_variety(choices): return choices[0] return min(choices, key=measure) def done(e): rv = e.doit() if doit else e return shorter(rv, collect_abs(rv)) expr = sympify(expr, rational=rational) kwargs = dict( ratio=kwargs.get('ratio', ratio), measure=kwargs.get('measure', measure), rational=kwargs.get('rational', rational), inverse=kwargs.get('inverse', inverse), doit=kwargs.get('doit', doit)) # no routine for Expr needs to check for is_zero if isinstance(expr, Expr) and expr.is_zero: return S.Zero _eval_simplify = getattr(expr, '_eval_simplify', None) if _eval_simplify is not None: return _eval_simplify(**kwargs) original_expr = expr = collect_abs(signsimp(expr)) if not isinstance(expr, Basic) or not expr.args: # XXX: temporary hack return expr if inverse and expr.has(Function): expr = inversecombine(expr) if not expr.args: # simplified to atomic return expr # do deep simplification handled = Add, Mul, Pow, ExpBase expr = expr.replace( # here, checking for x.args is not enough because Basic has # args but Basic does not always play well with replace, e.g. # when simultaneous is True found expressions will be masked # off with a Dummy but not all Basic objects in an expression # can be replaced with a Dummy lambda x: isinstance(x, Expr) and x.args and not isinstance( x, handled), lambda x: x.func(*[simplify(i, **kwargs) for i in x.args]), simultaneous=False) if not isinstance(expr, handled): return done(expr) if not expr.is_commutative: expr = nc_simplify(expr) # TODO: Apply different strategies, considering expression pattern: # is it a purely rational function? Is there any trigonometric function?... # See also https://github.com/sympy/sympy/pull/185. # rationalize Floats floats = False if rational is not False and expr.has(Float): floats = True expr = nsimplify(expr, rational=True) expr = bottom_up(expr, lambda w: getattr(w, 'normal', lambda: w)()) expr = Mul(*powsimp(expr).as_content_primitive()) _e = cancel(expr) expr1 = shorter(_e, _mexpand(_e).cancel()) # issue 6829 expr2 = shorter(together(expr, deep=True), together(expr1, deep=True)) if ratio is S.Infinity: expr = expr2 else: expr = shorter(expr2, expr1, expr) if not isinstance(expr, Basic): # XXX: temporary hack return expr expr = factor_terms(expr, sign=False) from sympy.simplify.hyperexpand import hyperexpand from sympy.functions.special.bessel import BesselBase from sympy import Sum, Product, Integral from sympy.functions.elementary.complexes import sign # must come before `Piecewise` since this introduces more `Piecewise` terms if expr.has(sign): expr = expr.rewrite(Abs) # Deal with Piecewise separately to avoid recursive growth of expressions if expr.has(Piecewise): # Fold into a single Piecewise expr = piecewise_fold(expr) # Apply doit, if doit=True expr = done(expr) # Still a Piecewise? if expr.has(Piecewise): # Fold into a single Piecewise, in case doit lead to some # expressions being Piecewise expr = piecewise_fold(expr) # kroneckersimp also affects Piecewise if expr.has(KroneckerDelta): expr = kroneckersimp(expr) # Still a Piecewise? if expr.has(Piecewise): from sympy.functions.elementary.piecewise import piecewise_simplify # Do not apply doit on the segments as it has already # been done above, but simplify expr = piecewise_simplify(expr, deep=True, doit=False) # Still a Piecewise? if expr.has(Piecewise): # Try factor common terms expr = shorter(expr, factor_terms(expr)) # As all expressions have been simplified above with the # complete simplify, nothing more needs to be done here return expr # hyperexpand automatically only works on hypergeometric terms # Do this after the Piecewise part to avoid recursive expansion expr = hyperexpand(expr) if expr.has(KroneckerDelta): expr = kroneckersimp(expr) if expr.has(BesselBase): expr = besselsimp(expr) if expr.has(TrigonometricFunction, HyperbolicFunction): expr = trigsimp(expr, deep=True) if expr.has(log): expr = shorter(expand_log(expr, deep=True), logcombine(expr)) if expr.has(CombinatorialFunction, gamma): # expression with gamma functions or non-integer arguments is # automatically passed to gammasimp expr = combsimp(expr) if expr.has(Sum): expr = sum_simplify(expr, **kwargs) if expr.has(Integral): expr = expr.xreplace({ i: factor_terms(i) for i in expr.atoms(Integral)}) if expr.has(Product): expr = product_simplify(expr) from sympy.physics.units import Quantity from sympy.physics.units.util import quantity_simplify if expr.has(Quantity): expr = quantity_simplify(expr) short = shorter(powsimp(expr, combine='exp', deep=True), powsimp(expr), expr) short = shorter(short, cancel(short)) short = shorter(short, factor_terms(short), expand_power_exp(expand_mul(short))) if short.has(TrigonometricFunction, HyperbolicFunction, ExpBase, exp): short = exptrigsimp(short) # get rid of hollow 2-arg Mul factorization hollow_mul = Transform( lambda x: Mul(*x.args), lambda x: x.is_Mul and len(x.args) == 2 and x.args[0].is_Number and x.args[1].is_Add and x.is_commutative) expr = short.xreplace(hollow_mul) numer, denom = expr.as_numer_denom() if denom.is_Add: n, d = fraction(radsimp(1/denom, symbolic=False, max_terms=1)) if n is not S.One: expr = (numer*n).expand()/d if expr.could_extract_minus_sign(): n, d = fraction(expr) if d != 0: expr = signsimp(-n/(-d)) if measure(expr) > ratio*measure(original_expr): expr = original_expr # restore floats if floats and rational is None: expr = nfloat(expr, exponent=False) return done(expr) def sum_simplify(s, **kwargs): """Main function for Sum simplification""" from sympy.concrete.summations import Sum from sympy.core.function import expand if not isinstance(s, Add): s = s.xreplace({a: sum_simplify(a, **kwargs) for a in s.atoms(Add) if a.has(Sum)}) s = expand(s) if not isinstance(s, Add): return s terms = s.args s_t = [] # Sum Terms o_t = [] # Other Terms for term in terms: sum_terms, other = sift(Mul.make_args(term), lambda i: isinstance(i, Sum), binary=True) if not sum_terms: o_t.append(term) continue other = [Mul(*other)] s_t.append(Mul(*(other + [s._eval_simplify(**kwargs) for s in sum_terms]))) result = Add(sum_combine(s_t), *o_t) return result def sum_combine(s_t): """Helper function for Sum simplification Attempts to simplify a list of sums, by combining limits / sum function's returns the simplified sum """ from sympy.concrete.summations import Sum used = [False] * len(s_t) for method in range(2): for i, s_term1 in enumerate(s_t): if not used[i]: for j, s_term2 in enumerate(s_t): if not used[j] and i != j: temp = sum_add(s_term1, s_term2, method) if isinstance(temp, Sum) or isinstance(temp, Mul): s_t[i] = temp s_term1 = s_t[i] used[j] = True result = S.Zero for i, s_term in enumerate(s_t): if not used[i]: result = Add(result, s_term) return result def factor_sum(self, limits=None, radical=False, clear=False, fraction=False, sign=True): """Return Sum with constant factors extracted. If ``limits`` is specified then ``self`` is the summand; the other keywords are passed to ``factor_terms``. Examples ======== >>> from sympy import Sum >>> from sympy.abc import x, y >>> from sympy.simplify.simplify import factor_sum >>> s = Sum(x*y, (x, 1, 3)) >>> factor_sum(s) y*Sum(x, (x, 1, 3)) >>> factor_sum(s.function, s.limits) y*Sum(x, (x, 1, 3)) """ # XXX deprecate in favor of direct call to factor_terms from sympy.concrete.summations import Sum kwargs = dict(radical=radical, clear=clear, fraction=fraction, sign=sign) expr = Sum(self, *limits) if limits else self return factor_terms(expr, **kwargs) def sum_add(self, other, method=0): """Helper function for Sum simplification""" from sympy.concrete.summations import Sum from sympy import Mul #we know this is something in terms of a constant * a sum #so we temporarily put the constants inside for simplification #then simplify the result def __refactor(val): args = Mul.make_args(val) sumv = next(x for x in args if isinstance(x, Sum)) constant = Mul(*[x for x in args if x != sumv]) return Sum(constant * sumv.function, *sumv.limits) if isinstance(self, Mul): rself = __refactor(self) else: rself = self if isinstance(other, Mul): rother = __refactor(other) else: rother = other if type(rself) == type(rother): if method == 0: if rself.limits == rother.limits: return factor_sum(Sum(rself.function + rother.function, *rself.limits)) elif method == 1: if simplify(rself.function - rother.function) == 0: if len(rself.limits) == len(rother.limits) == 1: i = rself.limits[0][0] x1 = rself.limits[0][1] y1 = rself.limits[0][2] j = rother.limits[0][0] x2 = rother.limits[0][1] y2 = rother.limits[0][2] if i == j: if x2 == y1 + 1: return factor_sum(Sum(rself.function, (i, x1, y2))) elif x1 == y2 + 1: return factor_sum(Sum(rself.function, (i, x2, y1))) return Add(self, other) def product_simplify(s): """Main function for Product simplification""" from sympy.concrete.products import Product terms = Mul.make_args(s) p_t = [] # Product Terms o_t = [] # Other Terms for term in terms: if isinstance(term, Product): p_t.append(term) else: o_t.append(term) used = [False] * len(p_t) for method in range(2): for i, p_term1 in enumerate(p_t): if not used[i]: for j, p_term2 in enumerate(p_t): if not used[j] and i != j: if isinstance(product_mul(p_term1, p_term2, method), Product): p_t[i] = product_mul(p_term1, p_term2, method) used[j] = True result = Mul(*o_t) for i, p_term in enumerate(p_t): if not used[i]: result = Mul(result, p_term) return result def product_mul(self, other, method=0): """Helper function for Product simplification""" from sympy.concrete.products import Product if type(self) == type(other): if method == 0: if self.limits == other.limits: return Product(self.function * other.function, *self.limits) elif method == 1: if simplify(self.function - other.function) == 0: if len(self.limits) == len(other.limits) == 1: i = self.limits[0][0] x1 = self.limits[0][1] y1 = self.limits[0][2] j = other.limits[0][0] x2 = other.limits[0][1] y2 = other.limits[0][2] if i == j: if x2 == y1 + 1: return Product(self.function, (i, x1, y2)) elif x1 == y2 + 1: return Product(self.function, (i, x2, y1)) return Mul(self, other) def _nthroot_solve(p, n, prec): """ helper function for ``nthroot`` It denests ``p**Rational(1, n)`` using its minimal polynomial """ from sympy.polys.numberfields import _minimal_polynomial_sq from sympy.solvers import solve while n % 2 == 0: p = sqrtdenest(sqrt(p)) n = n // 2 if n == 1: return p pn = p**Rational(1, n) x = Symbol('x') f = _minimal_polynomial_sq(p, n, x) if f is None: return None sols = solve(f, x) for sol in sols: if abs(sol - pn).n() < 1./10**prec: sol = sqrtdenest(sol) if _mexpand(sol**n) == p: return sol def logcombine(expr, force=False): """ Takes logarithms and combines them using the following rules: - log(x) + log(y) == log(x*y) if both are positive - a*log(x) == log(x**a) if x is positive and a is real If ``force`` is ``True`` then the assumptions above will be assumed to hold if there is no assumption already in place on a quantity. For example, if ``a`` is imaginary or the argument negative, force will not perform a combination but if ``a`` is a symbol with no assumptions the change will take place. Examples ======== >>> from sympy import Symbol, symbols, log, logcombine, I >>> from sympy.abc import a, x, y, z >>> logcombine(a*log(x) + log(y) - log(z)) a*log(x) + log(y) - log(z) >>> logcombine(a*log(x) + log(y) - log(z), force=True) log(x**a*y/z) >>> x,y,z = symbols('x,y,z', positive=True) >>> a = Symbol('a', real=True) >>> logcombine(a*log(x) + log(y) - log(z)) log(x**a*y/z) The transformation is limited to factors and/or terms that contain logs, so the result depends on the initial state of expansion: >>> eq = (2 + 3*I)*log(x) >>> logcombine(eq, force=True) == eq True >>> logcombine(eq.expand(), force=True) log(x**2) + I*log(x**3) See Also ======== posify: replace all symbols with symbols having positive assumptions sympy.core.function.expand_log: expand the logarithms of products and powers; the opposite of logcombine """ def f(rv): if not (rv.is_Add or rv.is_Mul): return rv def gooda(a): # bool to tell whether the leading ``a`` in ``a*log(x)`` # could appear as log(x**a) return (a is not S.NegativeOne and # -1 *could* go, but we disallow (a.is_extended_real or force and a.is_extended_real is not False)) def goodlog(l): # bool to tell whether log ``l``'s argument can combine with others a = l.args[0] return a.is_positive or force and a.is_nonpositive is not False other = [] logs = [] log1 = defaultdict(list) for a in Add.make_args(rv): if isinstance(a, log) and goodlog(a): log1[()].append(([], a)) elif not a.is_Mul: other.append(a) else: ot = [] co = [] lo = [] for ai in a.args: if ai.is_Rational and ai < 0: ot.append(S.NegativeOne) co.append(-ai) elif isinstance(ai, log) and goodlog(ai): lo.append(ai) elif gooda(ai): co.append(ai) else: ot.append(ai) if len(lo) > 1: logs.append((ot, co, lo)) elif lo: log1[tuple(ot)].append((co, lo[0])) else: other.append(a) # if there is only one log in other, put it with the # good logs if len(other) == 1 and isinstance(other[0], log): log1[()].append(([], other.pop())) # if there is only one log at each coefficient and none have # an exponent to place inside the log then there is nothing to do if not logs and all(len(log1[k]) == 1 and log1[k][0] == [] for k in log1): return rv # collapse multi-logs as far as possible in a canonical way # TODO: see if x*log(a)+x*log(a)*log(b) -> x*log(a)*(1+log(b))? # -- in this case, it's unambiguous, but if it were were a log(c) in # each term then it's arbitrary whether they are grouped by log(a) or # by log(c). So for now, just leave this alone; it's probably better to # let the user decide for o, e, l in logs: l = list(ordered(l)) e = log(l.pop(0).args[0]**Mul(*e)) while l: li = l.pop(0) e = log(li.args[0]**e) c, l = Mul(*o), e if isinstance(l, log): # it should be, but check to be sure log1[(c,)].append(([], l)) else: other.append(c*l) # logs that have the same coefficient can multiply for k in list(log1.keys()): log1[Mul(*k)] = log(logcombine(Mul(*[ l.args[0]**Mul(*c) for c, l in log1.pop(k)]), force=force), evaluate=False) # logs that have oppositely signed coefficients can divide for k in ordered(list(log1.keys())): if not k in log1: # already popped as -k continue if -k in log1: # figure out which has the minus sign; the one with # more op counts should be the one num, den = k, -k if num.count_ops() > den.count_ops(): num, den = den, num other.append( num*log(log1.pop(num).args[0]/log1.pop(den).args[0], evaluate=False)) else: other.append(k*log1.pop(k)) return Add(*other) return bottom_up(expr, f) def inversecombine(expr): """Simplify the composition of a function and its inverse. Explanation =========== No attention is paid to whether the inverse is a left inverse or a right inverse; thus, the result will in general not be equivalent to the original expression. Examples ======== >>> from sympy.simplify.simplify import inversecombine >>> from sympy import asin, sin, log, exp >>> from sympy.abc import x >>> inversecombine(asin(sin(x))) x >>> inversecombine(2*log(exp(3*x))) 6*x """ def f(rv): if isinstance(rv, log): if isinstance(rv.args[0], exp) or (rv.args[0].is_Pow and rv.args[0].base == S.Exp1): rv = rv.args[0].exp elif rv.is_Function and hasattr(rv, "inverse"): if (len(rv.args) == 1 and len(rv.args[0].args) == 1 and isinstance(rv.args[0], rv.inverse(argindex=1))): rv = rv.args[0].args[0] if rv.is_Pow and rv.base == S.Exp1: if isinstance(rv.exp, log): rv = rv.exp.args[0] return rv return bottom_up(expr, f) def walk(e, *target): """Iterate through the args that are the given types (target) and return a list of the args that were traversed; arguments that are not of the specified types are not traversed. Examples ======== >>> from sympy.simplify.simplify import walk >>> from sympy import Min, Max >>> from sympy.abc import x, y, z >>> list(walk(Min(x, Max(y, Min(1, z))), Min)) [Min(x, Max(y, Min(1, z)))] >>> list(walk(Min(x, Max(y, Min(1, z))), Min, Max)) [Min(x, Max(y, Min(1, z))), Max(y, Min(1, z)), Min(1, z)] See Also ======== bottom_up """ if isinstance(e, target): yield e for i in e.args: yield from walk(i, *target) def bottom_up(rv, F, atoms=False, nonbasic=False): """Apply ``F`` to all expressions in an expression tree from the bottom up. If ``atoms`` is True, apply ``F`` even if there are no args; if ``nonbasic`` is True, try to apply ``F`` to non-Basic objects. """ args = getattr(rv, 'args', None) if args is not None: if args: args = tuple([bottom_up(a, F, atoms, nonbasic) for a in args]) if args != rv.args: rv = rv.func(*args) rv = F(rv) elif atoms: rv = F(rv) else: if nonbasic: try: rv = F(rv) except TypeError: pass return rv def kroneckersimp(expr): """ Simplify expressions with KroneckerDelta. The only simplification currently attempted is to identify multiplicative cancellation: Examples ======== >>> from sympy import KroneckerDelta, kroneckersimp >>> from sympy.abc import i >>> kroneckersimp(1 + KroneckerDelta(0, i) * KroneckerDelta(1, i)) 1 """ def args_cancel(args1, args2): for i1 in range(2): for i2 in range(2): a1 = args1[i1] a2 = args2[i2] a3 = args1[(i1 + 1) % 2] a4 = args2[(i2 + 1) % 2] if Eq(a1, a2) is S.true and Eq(a3, a4) is S.false: return True return False def cancel_kronecker_mul(m): from sympy.utilities.iterables import subsets args = m.args deltas = [a for a in args if isinstance(a, KroneckerDelta)] for delta1, delta2 in subsets(deltas, 2): args1 = delta1.args args2 = delta2.args if args_cancel(args1, args2): return 0*m return m if not expr.has(KroneckerDelta): return expr if expr.has(Piecewise): expr = expr.rewrite(KroneckerDelta) newexpr = expr expr = None while newexpr != expr: expr = newexpr newexpr = expr.replace(lambda e: isinstance(e, Mul), cancel_kronecker_mul) return expr def besselsimp(expr): """ Simplify bessel-type functions. Explanation =========== This routine tries to simplify bessel-type functions. Currently it only works on the Bessel J and I functions, however. It works by looking at all such functions in turn, and eliminating factors of "I" and "-1" (actually their polar equivalents) in front of the argument. Then, functions of half-integer order are rewritten using strigonometric functions and functions of integer order (> 1) are rewritten using functions of low order. Finally, if the expression was changed, compute factorization of the result with factor(). >>> from sympy import besselj, besseli, besselsimp, polar_lift, I, S >>> from sympy.abc import z, nu >>> besselsimp(besselj(nu, z*polar_lift(-1))) exp(I*pi*nu)*besselj(nu, z) >>> besselsimp(besseli(nu, z*polar_lift(-I))) exp(-I*pi*nu/2)*besselj(nu, z) >>> besselsimp(besseli(S(-1)/2, z)) sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) >>> besselsimp(z*besseli(0, z) + z*(besseli(2, z))/2 + besseli(1, z)) 3*z*besseli(0, z)/2 """ # TODO # - better algorithm? # - simplify (cos(pi*b)*besselj(b,z) - besselj(-b,z))/sin(pi*b) ... # - use contiguity relations? def replacer(fro, to, factors): factors = set(factors) def repl(nu, z): if factors.intersection(Mul.make_args(z)): return to(nu, z) return fro(nu, z) return repl def torewrite(fro, to): def tofunc(nu, z): return fro(nu, z).rewrite(to) return tofunc def tominus(fro): def tofunc(nu, z): return exp(I*pi*nu)*fro(nu, exp_polar(-I*pi)*z) return tofunc orig_expr = expr ifactors = [I, exp_polar(I*pi/2), exp_polar(-I*pi/2)] expr = expr.replace( besselj, replacer(besselj, torewrite(besselj, besseli), ifactors)) expr = expr.replace( besseli, replacer(besseli, torewrite(besseli, besselj), ifactors)) minusfactors = [-1, exp_polar(I*pi)] expr = expr.replace( besselj, replacer(besselj, tominus(besselj), minusfactors)) expr = expr.replace( besseli, replacer(besseli, tominus(besseli), minusfactors)) z0 = Dummy('z') def expander(fro): def repl(nu, z): if (nu % 1) == S.Half: return simplify(trigsimp(unpolarify( fro(nu, z0).rewrite(besselj).rewrite(jn).expand( func=True)).subs(z0, z))) elif nu.is_Integer and nu > 1: return fro(nu, z).expand(func=True) return fro(nu, z) return repl expr = expr.replace(besselj, expander(besselj)) expr = expr.replace(bessely, expander(bessely)) expr = expr.replace(besseli, expander(besseli)) expr = expr.replace(besselk, expander(besselk)) def _bessel_simp_recursion(expr): def _use_recursion(bessel, expr): while True: bessels = expr.find(lambda x: isinstance(x, bessel)) try: for ba in sorted(bessels, key=lambda x: re(x.args[0])): a, x = ba.args bap1 = bessel(a+1, x) bap2 = bessel(a+2, x) if expr.has(bap1) and expr.has(bap2): expr = expr.subs(ba, 2*(a+1)/x*bap1 - bap2) break else: return expr except (ValueError, TypeError): return expr if expr.has(besselj): expr = _use_recursion(besselj, expr) if expr.has(bessely): expr = _use_recursion(bessely, expr) return expr expr = _bessel_simp_recursion(expr) if expr != orig_expr: expr = expr.factor() return expr def nthroot(expr, n, max_len=4, prec=15): """ Compute a real nth-root of a sum of surds. Parameters ========== expr : sum of surds n : integer max_len : maximum number of surds passed as constants to ``nsimplify`` Algorithm ========= First ``nsimplify`` is used to get a candidate root; if it is not a root the minimal polynomial is computed; the answer is one of its roots. Examples ======== >>> from sympy.simplify.simplify import nthroot >>> from sympy import sqrt >>> nthroot(90 + 34*sqrt(7), 3) sqrt(7) + 3 """ expr = sympify(expr) n = sympify(n) p = expr**Rational(1, n) if not n.is_integer: return p if not _is_sum_surds(expr): return p surds = [] coeff_muls = [x.as_coeff_Mul() for x in expr.args] for x, y in coeff_muls: if not x.is_rational: return p if y is S.One: continue if not (y.is_Pow and y.exp == S.Half and y.base.is_integer): return p surds.append(y) surds.sort() surds = surds[:max_len] if expr < 0 and n % 2 == 1: p = (-expr)**Rational(1, n) a = nsimplify(p, constants=surds) res = a if _mexpand(a**n) == _mexpand(-expr) else p return -res a = nsimplify(p, constants=surds) if _mexpand(a) is not _mexpand(p) and _mexpand(a**n) == _mexpand(expr): return _mexpand(a) expr = _nthroot_solve(expr, n, prec) if expr is None: return p return expr def nsimplify(expr, constants=(), tolerance=None, full=False, rational=None, rational_conversion='base10'): """ Find a simple representation for a number or, if there are free symbols or if ``rational=True``, then replace Floats with their Rational equivalents. If no change is made and rational is not False then Floats will at least be converted to Rationals. Explanation =========== For numerical expressions, a simple formula that numerically matches the given numerical expression is sought (and the input should be possible to evalf to a precision of at least 30 digits). Optionally, a list of (rationally independent) constants to include in the formula may be given. A lower tolerance may be set to find less exact matches. If no tolerance is given then the least precise value will set the tolerance (e.g. Floats default to 15 digits of precision, so would be tolerance=10**-15). With ``full=True``, a more extensive search is performed (this is useful to find simpler numbers when the tolerance is set low). When converting to rational, if rational_conversion='base10' (the default), then convert floats to rationals using their base-10 (string) representation. When rational_conversion='exact' it uses the exact, base-2 representation. Examples ======== >>> from sympy import nsimplify, sqrt, GoldenRatio, exp, I, pi >>> nsimplify(4/(1+sqrt(5)), [GoldenRatio]) -2 + 2*GoldenRatio >>> nsimplify((1/(exp(3*pi*I/5)+1))) 1/2 - I*sqrt(sqrt(5)/10 + 1/4) >>> nsimplify(I**I, [pi]) exp(-pi/2) >>> nsimplify(pi, tolerance=0.01) 22/7 >>> nsimplify(0.333333333333333, rational=True, rational_conversion='exact') 6004799503160655/18014398509481984 >>> nsimplify(0.333333333333333, rational=True) 1/3 See Also ======== sympy.core.function.nfloat """ try: return sympify(as_int(expr)) except (TypeError, ValueError): pass expr = sympify(expr).xreplace({ Float('inf'): S.Infinity, Float('-inf'): S.NegativeInfinity, }) if expr is S.Infinity or expr is S.NegativeInfinity: return expr if rational or expr.free_symbols: return _real_to_rational(expr, tolerance, rational_conversion) # SymPy's default tolerance for Rationals is 15; other numbers may have # lower tolerances set, so use them to pick the largest tolerance if None # was given if tolerance is None: tolerance = 10**-min([15] + [mpmath.libmp.libmpf.prec_to_dps(n._prec) for n in expr.atoms(Float)]) # XXX should prec be set independent of tolerance or should it be computed # from tolerance? prec = 30 bprec = int(prec*3.33) constants_dict = {} for constant in constants: constant = sympify(constant) v = constant.evalf(prec) if not v.is_Float: raise ValueError("constants must be real-valued") constants_dict[str(constant)] = v._to_mpmath(bprec) exprval = expr.evalf(prec, chop=True) re, im = exprval.as_real_imag() # safety check to make sure that this evaluated to a number if not (re.is_Number and im.is_Number): return expr def nsimplify_real(x): orig = mpmath.mp.dps xv = x._to_mpmath(bprec) try: # We'll be happy with low precision if a simple fraction if not (tolerance or full): mpmath.mp.dps = 15 rat = mpmath.pslq([xv, 1]) if rat is not None: return Rational(-int(rat[1]), int(rat[0])) mpmath.mp.dps = prec newexpr = mpmath.identify(xv, constants=constants_dict, tol=tolerance, full=full) if not newexpr: raise ValueError if full: newexpr = newexpr[0] expr = sympify(newexpr) if x and not expr: # don't let x become 0 raise ValueError if expr.is_finite is False and not xv in [mpmath.inf, mpmath.ninf]: raise ValueError return expr finally: # even though there are returns above, this is executed # before leaving mpmath.mp.dps = orig try: if re: re = nsimplify_real(re) if im: im = nsimplify_real(im) except ValueError: if rational is None: return _real_to_rational(expr, rational_conversion=rational_conversion) return expr rv = re + im*S.ImaginaryUnit # if there was a change or rational is explicitly not wanted # return the value, else return the Rational representation if rv != expr or rational is False: return rv return _real_to_rational(expr, rational_conversion=rational_conversion) def _real_to_rational(expr, tolerance=None, rational_conversion='base10'): """ Replace all reals in expr with rationals. Examples ======== >>> from sympy.simplify.simplify import _real_to_rational >>> from sympy.abc import x >>> _real_to_rational(.76 + .1*x**.5) sqrt(x)/10 + 19/25 If rational_conversion='base10', this uses the base-10 string. If rational_conversion='exact', the exact, base-2 representation is used. >>> _real_to_rational(0.333333333333333, rational_conversion='exact') 6004799503160655/18014398509481984 >>> _real_to_rational(0.333333333333333) 1/3 """ expr = _sympify(expr) inf = Float('inf') p = expr reps = {} reduce_num = None if tolerance is not None and tolerance < 1: reduce_num = ceiling(1/tolerance) for fl in p.atoms(Float): key = fl if reduce_num is not None: r = Rational(fl).limit_denominator(reduce_num) elif (tolerance is not None and tolerance >= 1 and fl.is_Integer is False): r = Rational(tolerance*round(fl/tolerance) ).limit_denominator(int(tolerance)) else: if rational_conversion == 'exact': r = Rational(fl) reps[key] = r continue elif rational_conversion != 'base10': raise ValueError("rational_conversion must be 'base10' or 'exact'") r = nsimplify(fl, rational=False) # e.g. log(3).n() -> log(3) instead of a Rational if fl and not r: r = Rational(fl) elif not r.is_Rational: if fl == inf or fl == -inf: r = S.ComplexInfinity elif fl < 0: fl = -fl d = Pow(10, int(mpmath.log(fl)/mpmath.log(10))) r = -Rational(str(fl/d))*d elif fl > 0: d = Pow(10, int(mpmath.log(fl)/mpmath.log(10))) r = Rational(str(fl/d))*d else: r = Integer(0) reps[key] = r return p.subs(reps, simultaneous=True) def clear_coefficients(expr, rhs=S.Zero): """Return `p, r` where `p` is the expression obtained when Rational additive and multiplicative coefficients of `expr` have been stripped away in a naive fashion (i.e. without simplification). The operations needed to remove the coefficients will be applied to `rhs` and returned as `r`. Examples ======== >>> from sympy.simplify.simplify import clear_coefficients >>> from sympy.abc import x, y >>> from sympy import Dummy >>> expr = 4*y*(6*x + 3) >>> clear_coefficients(expr - 2) (y*(2*x + 1), 1/6) When solving 2 or more expressions like `expr = a`, `expr = b`, etc..., it is advantageous to provide a Dummy symbol for `rhs` and simply replace it with `a`, `b`, etc... in `r`. >>> rhs = Dummy('rhs') >>> clear_coefficients(expr, rhs) (y*(2*x + 1), _rhs/12) >>> _[1].subs(rhs, 2) 1/6 """ was = None free = expr.free_symbols if expr.is_Rational: return (S.Zero, rhs - expr) while expr and was != expr: was = expr m, expr = ( expr.as_content_primitive() if free else factor_terms(expr).as_coeff_Mul(rational=True)) rhs /= m c, expr = expr.as_coeff_Add(rational=True) rhs -= c expr = signsimp(expr, evaluate = False) if _coeff_isneg(expr): expr = -expr rhs = -rhs return expr, rhs def nc_simplify(expr, deep=True): ''' Simplify a non-commutative expression composed of multiplication and raising to a power by grouping repeated subterms into one power. Priority is given to simplifications that give the fewest number of arguments in the end (for example, in a*b*a*b*c*a*b*c simplifying to (a*b)**2*c*a*b*c gives 5 arguments while a*b*(a*b*c)**2 has 3). If ``expr`` is a sum of such terms, the sum of the simplified terms is returned. Keyword argument ``deep`` controls whether or not subexpressions nested deeper inside the main expression are simplified. See examples below. Setting `deep` to `False` can save time on nested expressions that don't need simplifying on all levels. Examples ======== >>> from sympy import symbols >>> from sympy.simplify.simplify import nc_simplify >>> a, b, c = symbols("a b c", commutative=False) >>> nc_simplify(a*b*a*b*c*a*b*c) a*b*(a*b*c)**2 >>> expr = a**2*b*a**4*b*a**4 >>> nc_simplify(expr) a**2*(b*a**4)**2 >>> nc_simplify(a*b*a*b*c**2*(a*b)**2*c**2) ((a*b)**2*c**2)**2 >>> nc_simplify(a*b*a*b + 2*a*c*a**2*c*a**2*c*a) (a*b)**2 + 2*(a*c*a)**3 >>> nc_simplify(b**-1*a**-1*(a*b)**2) a*b >>> nc_simplify(a**-1*b**-1*c*a) (b*a)**(-1)*c*a >>> expr = (a*b*a*b)**2*a*c*a*c >>> nc_simplify(expr) (a*b)**4*(a*c)**2 >>> nc_simplify(expr, deep=False) (a*b*a*b)**2*(a*c)**2 ''' from sympy.matrices.expressions import (MatrixExpr, MatAdd, MatMul, MatPow, MatrixSymbol) from sympy.core.exprtools import factor_nc if isinstance(expr, MatrixExpr): expr = expr.doit(inv_expand=False) _Add, _Mul, _Pow, _Symbol = MatAdd, MatMul, MatPow, MatrixSymbol else: _Add, _Mul, _Pow, _Symbol = Add, Mul, Pow, Symbol # =========== Auxiliary functions ======================== def _overlaps(args): # Calculate a list of lists m such that m[i][j] contains the lengths # of all possible overlaps between args[:i+1] and args[i+1+j:]. # An overlap is a suffix of the prefix that matches a prefix # of the suffix. # For example, let expr=c*a*b*a*b*a*b*a*b. Then m[3][0] contains # the lengths of overlaps of c*a*b*a*b with a*b*a*b. The overlaps # are a*b*a*b, a*b and the empty word so that m[3][0]=[4,2,0]. # All overlaps rather than only the longest one are recorded # because this information helps calculate other overlap lengths. m = [[([1, 0] if a == args[0] else [0]) for a in args[1:]]] for i in range(1, len(args)): overlaps = [] j = 0 for j in range(len(args) - i - 1): overlap = [] for v in m[i-1][j+1]: if j + i + 1 + v < len(args) and args[i] == args[j+i+1+v]: overlap.append(v + 1) overlap += [0] overlaps.append(overlap) m.append(overlaps) return m def _reduce_inverses(_args): # replace consecutive negative powers by an inverse # of a product of positive powers, e.g. a**-1*b**-1*c # will simplify to (a*b)**-1*c; # return that new args list and the number of negative # powers in it (inv_tot) inv_tot = 0 # total number of inverses inverses = [] args = [] for arg in _args: if isinstance(arg, _Pow) and arg.args[1] < 0: inverses = [arg**-1] + inverses inv_tot += 1 else: if len(inverses) == 1: args.append(inverses[0]**-1) elif len(inverses) > 1: args.append(_Pow(_Mul(*inverses), -1)) inv_tot -= len(inverses) - 1 inverses = [] args.append(arg) if inverses: args.append(_Pow(_Mul(*inverses), -1)) inv_tot -= len(inverses) - 1 return inv_tot, tuple(args) def get_score(s): # compute the number of arguments of s # (including in nested expressions) overall # but ignore exponents if isinstance(s, _Pow): return get_score(s.args[0]) elif isinstance(s, (_Add, _Mul)): return sum([get_score(a) for a in s.args]) return 1 def compare(s, alt_s): # compare two possible simplifications and return a # "better" one if s != alt_s and get_score(alt_s) < get_score(s): return alt_s return s # ======================================================== if not isinstance(expr, (_Add, _Mul, _Pow)) or expr.is_commutative: return expr args = expr.args[:] if isinstance(expr, _Pow): if deep: return _Pow(nc_simplify(args[0]), args[1]).doit() else: return expr elif isinstance(expr, _Add): return _Add(*[nc_simplify(a, deep=deep) for a in args]).doit() else: # get the non-commutative part c_args, args = expr.args_cnc() com_coeff = Mul(*c_args) if com_coeff != 1: return com_coeff*nc_simplify(expr/com_coeff, deep=deep) inv_tot, args = _reduce_inverses(args) # if most arguments are negative, work with the inverse # of the expression, e.g. a**-1*b*a**-1*c**-1 will become # (c*a*b**-1*a)**-1 at the end so can work with c*a*b**-1*a invert = False if inv_tot > len(args)/2: invert = True args = [a**-1 for a in args[::-1]] if deep: args = tuple(nc_simplify(a) for a in args) m = _overlaps(args) # simps will be {subterm: end} where `end` is the ending # index of a sequence of repetitions of subterm; # this is for not wasting time with subterms that are part # of longer, already considered sequences simps = {} post = 1 pre = 1 # the simplification coefficient is the number of # arguments by which contracting a given sequence # would reduce the word; e.g. in a*b*a*b*c*a*b*c, # contracting a*b*a*b to (a*b)**2 removes 3 arguments # while a*b*c*a*b*c to (a*b*c)**2 removes 6. It's # better to contract the latter so simplification # with a maximum simplification coefficient will be chosen max_simp_coeff = 0 simp = None # information about future simplification for i in range(1, len(args)): simp_coeff = 0 l = 0 # length of a subterm p = 0 # the power of a subterm if i < len(args) - 1: rep = m[i][0] start = i # starting index of the repeated sequence end = i+1 # ending index of the repeated sequence if i == len(args)-1 or rep == [0]: # no subterm is repeated at this stage, at least as # far as the arguments are concerned - there may be # a repetition if powers are taken into account if (isinstance(args[i], _Pow) and not isinstance(args[i].args[0], _Symbol)): subterm = args[i].args[0].args l = len(subterm) if args[i-l:i] == subterm: # e.g. a*b in a*b*(a*b)**2 is not repeated # in args (= [a, b, (a*b)**2]) but it # can be matched here p += 1 start -= l if args[i+1:i+1+l] == subterm: # e.g. a*b in (a*b)**2*a*b p += 1 end += l if p: p += args[i].args[1] else: continue else: l = rep[0] # length of the longest repeated subterm at this point start -= l - 1 subterm = args[start:end] p = 2 end += l if subterm in simps and simps[subterm] >= start: # the subterm is part of a sequence that # has already been considered continue # count how many times it's repeated while end < len(args): if l in m[end-1][0]: p += 1 end += l elif isinstance(args[end], _Pow) and args[end].args[0].args == subterm: # for cases like a*b*a*b*(a*b)**2*a*b p += args[end].args[1] end += 1 else: break # see if another match can be made, e.g. # for b*a**2 in b*a**2*b*a**3 or a*b in # a**2*b*a*b pre_exp = 0 pre_arg = 1 if start - l >= 0 and args[start-l+1:start] == subterm[1:]: if isinstance(subterm[0], _Pow): pre_arg = subterm[0].args[0] exp = subterm[0].args[1] else: pre_arg = subterm[0] exp = 1 if isinstance(args[start-l], _Pow) and args[start-l].args[0] == pre_arg: pre_exp = args[start-l].args[1] - exp start -= l p += 1 elif args[start-l] == pre_arg: pre_exp = 1 - exp start -= l p += 1 post_exp = 0 post_arg = 1 if end + l - 1 < len(args) and args[end:end+l-1] == subterm[:-1]: if isinstance(subterm[-1], _Pow): post_arg = subterm[-1].args[0] exp = subterm[-1].args[1] else: post_arg = subterm[-1] exp = 1 if isinstance(args[end+l-1], _Pow) and args[end+l-1].args[0] == post_arg: post_exp = args[end+l-1].args[1] - exp end += l p += 1 elif args[end+l-1] == post_arg: post_exp = 1 - exp end += l p += 1 # Consider a*b*a**2*b*a**2*b*a: # b*a**2 is explicitly repeated, but note # that in this case a*b*a is also repeated # so there are two possible simplifications: # a*(b*a**2)**3*a**-1 or (a*b*a)**3 # The latter is obviously simpler. # But in a*b*a**2*b**2*a**2 the simplifications are # a*(b*a**2)**2 and (a*b*a)**3*a in which case # it's better to stick with the shorter subterm if post_exp and exp % 2 == 0 and start > 0: exp = exp/2 _pre_exp = 1 _post_exp = 1 if isinstance(args[start-1], _Pow) and args[start-1].args[0] == post_arg: _post_exp = post_exp + exp _pre_exp = args[start-1].args[1] - exp elif args[start-1] == post_arg: _post_exp = post_exp + exp _pre_exp = 1 - exp if _pre_exp == 0 or _post_exp == 0: if not pre_exp: start -= 1 post_exp = _post_exp pre_exp = _pre_exp pre_arg = post_arg subterm = (post_arg**exp,) + subterm[:-1] + (post_arg**exp,) simp_coeff += end-start if post_exp: simp_coeff -= 1 if pre_exp: simp_coeff -= 1 simps[subterm] = end if simp_coeff > max_simp_coeff: max_simp_coeff = simp_coeff simp = (start, _Mul(*subterm), p, end, l) pre = pre_arg**pre_exp post = post_arg**post_exp if simp: subterm = _Pow(nc_simplify(simp[1], deep=deep), simp[2]) pre = nc_simplify(_Mul(*args[:simp[0]])*pre, deep=deep) post = post*nc_simplify(_Mul(*args[simp[3]:]), deep=deep) simp = pre*subterm*post if pre != 1 or post != 1: # new simplifications may be possible but no need # to recurse over arguments simp = nc_simplify(simp, deep=False) else: simp = _Mul(*args) if invert: simp = _Pow(simp, -1) # see if factor_nc(expr) is simplified better if not isinstance(expr, MatrixExpr): f_expr = factor_nc(expr) if f_expr != expr: alt_simp = nc_simplify(f_expr, deep=deep) simp = compare(simp, alt_simp) else: simp = simp.doit(inv_expand=False) return simp def dotprodsimp(expr, withsimp=False): """Simplification for a sum of products targeted at the kind of blowup that occurs during summation of products. Intended to reduce expression blowup during matrix multiplication or other similar operations. Only works with algebraic expressions and does not recurse into non. Parameters ========== withsimp : bool, optional Specifies whether a flag should be returned along with the expression to indicate roughly whether simplification was successful. It is used in ``MatrixArithmetic._eval_pow_by_recursion`` to avoid attempting to simplify an expression repetitively which does not simplify. """ def count_ops_alg(expr): """Optimized count algebraic operations with no recursion into non-algebraic args that ``core.function.count_ops`` does. Also returns whether rational functions may be present according to negative exponents of powers or non-number fractions. Returns ======= ops, ratfunc : int, bool ``ops`` is the number of algebraic operations starting at the top level expression (not recursing into non-alg children). ``ratfunc`` specifies whether the expression MAY contain rational functions which ``cancel`` MIGHT optimize. """ ops = 0 args = [expr] ratfunc = False while args: a = args.pop() if not isinstance(a, Basic): continue if a.is_Rational: if a is not S.One: # -1/3 = NEG + DIV ops += bool (a.p < 0) + bool (a.q != 1) elif a.is_Mul: if _coeff_isneg(a): ops += 1 if a.args[0] is S.NegativeOne: a = a.as_two_terms()[1] else: a = -a n, d = fraction(a) if n.is_Integer: ops += 1 + bool (n < 0) args.append(d) # won't be -Mul but could be Add elif d is not S.One: if not d.is_Integer: args.append(d) ratfunc=True ops += 1 args.append(n) # could be -Mul else: ops += len(a.args) - 1 args.extend(a.args) elif a.is_Add: laargs = len(a.args) negs = 0 for ai in a.args: if _coeff_isneg(ai): negs += 1 ai = -ai args.append(ai) ops += laargs - (negs != laargs) # -x - y = NEG + SUB elif a.is_Pow: ops += 1 args.append(a.base) if not ratfunc: ratfunc = a.exp.is_negative is not False return ops, ratfunc def nonalg_subs_dummies(expr, dummies): """Substitute dummy variables for non-algebraic expressions to avoid evaluation of non-algebraic terms that ``polys.polytools.cancel`` does. """ if not expr.args: return expr if expr.is_Add or expr.is_Mul or expr.is_Pow: args = None for i, a in enumerate(expr.args): c = nonalg_subs_dummies(a, dummies) if c is a: continue if args is None: args = list(expr.args) args[i] = c if args is None: return expr return expr.func(*args) return dummies.setdefault(expr, Dummy()) simplified = False # doesn't really mean simplified, rather "can simplify again" if isinstance(expr, Basic) and (expr.is_Add or expr.is_Mul or expr.is_Pow): expr2 = expr.expand(deep=True, modulus=None, power_base=False, power_exp=False, mul=True, log=False, multinomial=True, basic=False) if expr2 != expr: expr = expr2 simplified = True exprops, ratfunc = count_ops_alg(expr) if exprops >= 6: # empirically tested cutoff for expensive simplification if ratfunc: dummies = {} expr2 = nonalg_subs_dummies(expr, dummies) if expr2 is expr or count_ops_alg(expr2)[0] >= 6: # check again after substitution expr3 = cancel(expr2) if expr3 != expr2: expr = expr3.subs([(d, e) for e, d in dummies.items()]) simplified = True # very special case: x/(x-1) - 1/(x-1) -> 1 elif (exprops == 5 and expr.is_Add and expr.args [0].is_Mul and expr.args [1].is_Mul and expr.args [0].args [-1].is_Pow and expr.args [1].args [-1].is_Pow and expr.args [0].args [-1].exp is S.NegativeOne and expr.args [1].args [-1].exp is S.NegativeOne): expr2 = together (expr) expr2ops = count_ops_alg(expr2)[0] if expr2ops < exprops: expr = expr2 simplified = True else: simplified = True return (expr, simplified) if withsimp else expr sympy-sympy-1.9/sympy/simplify/sqrtdenest.py000066400000000000000000000521341412543434000215130ustar00rootroot00000000000000from sympy.core import Add, Expr, Mul, S, sympify from sympy.core.function import _mexpand, count_ops, expand_mul from sympy.core.symbol import Dummy from sympy.functions import root, sign, sqrt from sympy.polys import Poly, PolynomialError from sympy.utilities import default_sort_key def is_sqrt(expr): """Return True if expr is a sqrt, otherwise False.""" return expr.is_Pow and expr.exp.is_Rational and abs(expr.exp) is S.Half def sqrt_depth(p): """Return the maximum depth of any square root argument of p. >>> from sympy.functions.elementary.miscellaneous import sqrt >>> from sympy.simplify.sqrtdenest import sqrt_depth Neither of these square roots contains any other square roots so the depth is 1: >>> sqrt_depth(1 + sqrt(2)*(1 + sqrt(3))) 1 The sqrt(3) is contained within a square root so the depth is 2: >>> sqrt_depth(1 + sqrt(2)*sqrt(1 + sqrt(3))) 2 """ if p is S.ImaginaryUnit: return 1 if p.is_Atom: return 0 elif p.is_Add or p.is_Mul: return max([sqrt_depth(x) for x in p.args], key=default_sort_key) elif is_sqrt(p): return sqrt_depth(p.base) + 1 else: return 0 def is_algebraic(p): """Return True if p is comprised of only Rationals or square roots of Rationals and algebraic operations. Examples ======== >>> from sympy.functions.elementary.miscellaneous import sqrt >>> from sympy.simplify.sqrtdenest import is_algebraic >>> from sympy import cos >>> is_algebraic(sqrt(2)*(3/(sqrt(7) + sqrt(5)*sqrt(2)))) True >>> is_algebraic(sqrt(2)*(3/(sqrt(7) + sqrt(5)*cos(2)))) False """ if p.is_Rational: return True elif p.is_Atom: return False elif is_sqrt(p) or p.is_Pow and p.exp.is_Integer: return is_algebraic(p.base) elif p.is_Add or p.is_Mul: return all(is_algebraic(x) for x in p.args) else: return False def _subsets(n): """ Returns all possible subsets of the set (0, 1, ..., n-1) except the empty set, listed in reversed lexicographical order according to binary representation, so that the case of the fourth root is treated last. Examples ======== >>> from sympy.simplify.sqrtdenest import _subsets >>> _subsets(2) [[1, 0], [0, 1], [1, 1]] """ if n == 1: a = [[1]] elif n == 2: a = [[1, 0], [0, 1], [1, 1]] elif n == 3: a = [[1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1]] else: b = _subsets(n - 1) a0 = [x + [0] for x in b] a1 = [x + [1] for x in b] a = a0 + [[0]*(n - 1) + [1]] + a1 return a def sqrtdenest(expr, max_iter=3): """Denests sqrts in an expression that contain other square roots if possible, otherwise returns the expr unchanged. This is based on the algorithms of [1]. Examples ======== >>> from sympy.simplify.sqrtdenest import sqrtdenest >>> from sympy import sqrt >>> sqrtdenest(sqrt(5 + 2 * sqrt(6))) sqrt(2) + sqrt(3) See Also ======== sympy.solvers.solvers.unrad References ========== .. [1] http://researcher.watson.ibm.com/researcher/files/us-fagin/symb85.pdf .. [2] D. J. Jeffrey and A. D. Rich, 'Symplifying Square Roots of Square Roots by Denesting' (available at http://www.cybertester.com/data/denest.pdf) """ expr = expand_mul(sympify(expr)) for i in range(max_iter): z = _sqrtdenest0(expr) if expr == z: return expr expr = z return expr def _sqrt_match(p): """Return [a, b, r] for p.match(a + b*sqrt(r)) where, in addition to matching, sqrt(r) also has then maximal sqrt_depth among addends of p. Examples ======== >>> from sympy.functions.elementary.miscellaneous import sqrt >>> from sympy.simplify.sqrtdenest import _sqrt_match >>> _sqrt_match(1 + sqrt(2) + sqrt(2)*sqrt(3) + 2*sqrt(1+sqrt(5))) [1 + sqrt(2) + sqrt(6), 2, 1 + sqrt(5)] """ from sympy.simplify.radsimp import split_surds p = _mexpand(p) if p.is_Number: res = (p, S.Zero, S.Zero) elif p.is_Add: pargs = sorted(p.args, key=default_sort_key) sqargs = [x**2 for x in pargs] if all(sq.is_Rational and sq.is_positive for sq in sqargs): r, b, a = split_surds(p) res = a, b, r return list(res) # to make the process canonical, the argument is included in the tuple # so when the max is selected, it will be the largest arg having a # given depth v = [(sqrt_depth(x), x, i) for i, x in enumerate(pargs)] nmax = max(v, key=default_sort_key) if nmax[0] == 0: res = [] else: # select r depth, _, i = nmax r = pargs.pop(i) v.pop(i) b = S.One if r.is_Mul: bv = [] rv = [] for x in r.args: if sqrt_depth(x) < depth: bv.append(x) else: rv.append(x) b = Mul._from_args(bv) r = Mul._from_args(rv) # collect terms comtaining r a1 = [] b1 = [b] for x in v: if x[0] < depth: a1.append(x[1]) else: x1 = x[1] if x1 == r: b1.append(1) else: if x1.is_Mul: x1args = list(x1.args) if r in x1args: x1args.remove(r) b1.append(Mul(*x1args)) else: a1.append(x[1]) else: a1.append(x[1]) a = Add(*a1) b = Add(*b1) res = (a, b, r**2) else: b, r = p.as_coeff_Mul() if is_sqrt(r): res = (S.Zero, b, r**2) else: res = [] return list(res) class SqrtdenestStopIteration(StopIteration): pass def _sqrtdenest0(expr): """Returns expr after denesting its arguments.""" if is_sqrt(expr): n, d = expr.as_numer_denom() if d is S.One: # n is a square root if n.base.is_Add: args = sorted(n.base.args, key=default_sort_key) if len(args) > 2 and all((x**2).is_Integer for x in args): try: return _sqrtdenest_rec(n) except SqrtdenestStopIteration: pass expr = sqrt(_mexpand(Add(*[_sqrtdenest0(x) for x in args]))) return _sqrtdenest1(expr) else: n, d = [_sqrtdenest0(i) for i in (n, d)] return n/d if isinstance(expr, Add): cs = [] args = [] for arg in expr.args: c, a = arg.as_coeff_Mul() cs.append(c) args.append(a) if all(c.is_Rational for c in cs) and all(is_sqrt(arg) for arg in args): return _sqrt_ratcomb(cs, args) if isinstance(expr, Expr): args = expr.args if args: return expr.func(*[_sqrtdenest0(a) for a in args]) return expr def _sqrtdenest_rec(expr): """Helper that denests the square root of three or more surds. Explanation =========== It returns the denested expression; if it cannot be denested it throws SqrtdenestStopIteration Algorithm: expr.base is in the extension Q_m = Q(sqrt(r_1),..,sqrt(r_k)); split expr.base = a + b*sqrt(r_k), where `a` and `b` are on Q_(m-1) = Q(sqrt(r_1),..,sqrt(r_(k-1))); then a**2 - b**2*r_k is on Q_(m-1); denest sqrt(a**2 - b**2*r_k) and so on. See [1], section 6. Examples ======== >>> from sympy import sqrt >>> from sympy.simplify.sqrtdenest import _sqrtdenest_rec >>> _sqrtdenest_rec(sqrt(-72*sqrt(2) + 158*sqrt(5) + 498)) -sqrt(10) + sqrt(2) + 9 + 9*sqrt(5) >>> w=-6*sqrt(55)-6*sqrt(35)-2*sqrt(22)-2*sqrt(14)+2*sqrt(77)+6*sqrt(10)+65 >>> _sqrtdenest_rec(sqrt(w)) -sqrt(11) - sqrt(7) + sqrt(2) + 3*sqrt(5) """ from sympy.simplify.radsimp import radsimp, rad_rationalize, split_surds if not expr.is_Pow: return sqrtdenest(expr) if expr.base < 0: return sqrt(-1)*_sqrtdenest_rec(sqrt(-expr.base)) g, a, b = split_surds(expr.base) a = a*sqrt(g) if a < b: a, b = b, a c2 = _mexpand(a**2 - b**2) if len(c2.args) > 2: g, a1, b1 = split_surds(c2) a1 = a1*sqrt(g) if a1 < b1: a1, b1 = b1, a1 c2_1 = _mexpand(a1**2 - b1**2) c_1 = _sqrtdenest_rec(sqrt(c2_1)) d_1 = _sqrtdenest_rec(sqrt(a1 + c_1)) num, den = rad_rationalize(b1, d_1) c = _mexpand(d_1/sqrt(2) + num/(den*sqrt(2))) else: c = _sqrtdenest1(sqrt(c2)) if sqrt_depth(c) > 1: raise SqrtdenestStopIteration ac = a + c if len(ac.args) >= len(expr.args): if count_ops(ac) >= count_ops(expr.base): raise SqrtdenestStopIteration d = sqrtdenest(sqrt(ac)) if sqrt_depth(d) > 1: raise SqrtdenestStopIteration num, den = rad_rationalize(b, d) r = d/sqrt(2) + num/(den*sqrt(2)) r = radsimp(r) return _mexpand(r) def _sqrtdenest1(expr, denester=True): """Return denested expr after denesting with simpler methods or, that failing, using the denester.""" from sympy.simplify.simplify import radsimp if not is_sqrt(expr): return expr a = expr.base if a.is_Atom: return expr val = _sqrt_match(a) if not val: return expr a, b, r = val # try a quick numeric denesting d2 = _mexpand(a**2 - b**2*r) if d2.is_Rational: if d2.is_positive: z = _sqrt_numeric_denest(a, b, r, d2) if z is not None: return z else: # fourth root case # sqrtdenest(sqrt(3 + 2*sqrt(3))) = # sqrt(2)*3**(1/4)/2 + sqrt(2)*3**(3/4)/2 dr2 = _mexpand(-d2*r) dr = sqrt(dr2) if dr.is_Rational: z = _sqrt_numeric_denest(_mexpand(b*r), a, r, dr2) if z is not None: return z/root(r, 4) else: z = _sqrt_symbolic_denest(a, b, r) if z is not None: return z if not denester or not is_algebraic(expr): return expr res = sqrt_biquadratic_denest(expr, a, b, r, d2) if res: return res # now call to the denester av0 = [a, b, r, d2] z = _denester([radsimp(expr**2)], av0, 0, sqrt_depth(expr))[0] if av0[1] is None: return expr if z is not None: if sqrt_depth(z) == sqrt_depth(expr) and count_ops(z) > count_ops(expr): return expr return z return expr def _sqrt_symbolic_denest(a, b, r): """Given an expression, sqrt(a + b*sqrt(b)), return the denested expression or None. Explanation =========== If r = ra + rb*sqrt(rr), try replacing sqrt(rr) in ``a`` with (y**2 - ra)/rb, and if the result is a quadratic, ca*y**2 + cb*y + cc, and (cb + b)**2 - 4*ca*cc is 0, then sqrt(a + b*sqrt(r)) can be rewritten as sqrt(ca*(sqrt(r) + (cb + b)/(2*ca))**2). Examples ======== >>> from sympy.simplify.sqrtdenest import _sqrt_symbolic_denest, sqrtdenest >>> from sympy import sqrt, Symbol >>> from sympy.abc import x >>> a, b, r = 16 - 2*sqrt(29), 2, -10*sqrt(29) + 55 >>> _sqrt_symbolic_denest(a, b, r) sqrt(11 - 2*sqrt(29)) + sqrt(5) If the expression is numeric, it will be simplified: >>> w = sqrt(sqrt(sqrt(3) + 1) + 1) + 1 + sqrt(2) >>> sqrtdenest(sqrt((w**2).expand())) 1 + sqrt(2) + sqrt(1 + sqrt(1 + sqrt(3))) Otherwise, it will only be simplified if assumptions allow: >>> w = w.subs(sqrt(3), sqrt(x + 3)) >>> sqrtdenest(sqrt((w**2).expand())) sqrt((sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2))**2) Notice that the argument of the sqrt is a square. If x is made positive then the sqrt of the square is resolved: >>> _.subs(x, Symbol('x', positive=True)) sqrt(sqrt(sqrt(x + 3) + 1) + 1) + 1 + sqrt(2) """ a, b, r = map(sympify, (a, b, r)) rval = _sqrt_match(r) if not rval: return None ra, rb, rr = rval if rb: y = Dummy('y', positive=True) try: newa = Poly(a.subs(sqrt(rr), (y**2 - ra)/rb), y) except PolynomialError: return None if newa.degree() == 2: ca, cb, cc = newa.all_coeffs() cb += b if _mexpand(cb**2 - 4*ca*cc).equals(0): z = sqrt(ca*(sqrt(r) + cb/(2*ca))**2) if z.is_number: z = _mexpand(Mul._from_args(z.as_content_primitive())) return z def _sqrt_numeric_denest(a, b, r, d2): r"""Helper that denest $\sqrt{a + b \sqrt{r}}, d^2 = a^2 - b^2 r > 0$ If it cannot be denested, it returns ``None``. """ d = sqrt(d2) s = a + d # sqrt_depth(res) <= sqrt_depth(s) + 1 # sqrt_depth(expr) = sqrt_depth(r) + 2 # there is denesting if sqrt_depth(s) + 1 < sqrt_depth(r) + 2 # if s**2 is Number there is a fourth root if sqrt_depth(s) < sqrt_depth(r) + 1 or (s**2).is_Rational: s1, s2 = sign(s), sign(b) if s1 == s2 == -1: s1 = s2 = 1 res = (s1 * sqrt(a + d) + s2 * sqrt(a - d)) * sqrt(2) / 2 return res.expand() def sqrt_biquadratic_denest(expr, a, b, r, d2): """denest expr = sqrt(a + b*sqrt(r)) where a, b, r are linear combinations of square roots of positive rationals on the rationals (SQRR) and r > 0, b != 0, d2 = a**2 - b**2*r > 0 If it cannot denest it returns None. Explanation =========== Search for a solution A of type SQRR of the biquadratic equation 4*A**4 - 4*a*A**2 + b**2*r = 0 (1) sqd = sqrt(a**2 - b**2*r) Choosing the sqrt to be positive, the possible solutions are A = sqrt(a/2 +/- sqd/2) Since a, b, r are SQRR, then a**2 - b**2*r is a SQRR, so if sqd can be denested, it is done by _sqrtdenest_rec, and the result is a SQRR. Similarly for A. Examples of solutions (in both cases a and sqd are positive): Example of expr with solution sqrt(a/2 + sqd/2) but not solution sqrt(a/2 - sqd/2): expr = sqrt(-sqrt(15) - sqrt(2)*sqrt(-sqrt(5) + 5) - sqrt(3) + 8) a = -sqrt(15) - sqrt(3) + 8; sqd = -2*sqrt(5) - 2 + 4*sqrt(3) Example of expr with solution sqrt(a/2 - sqd/2) but not solution sqrt(a/2 + sqd/2): w = 2 + r2 + r3 + (1 + r3)*sqrt(2 + r2 + 5*r3) expr = sqrt((w**2).expand()) a = 4*sqrt(6) + 8*sqrt(2) + 47 + 28*sqrt(3) sqd = 29 + 20*sqrt(3) Define B = b/2*A; eq.(1) implies a = A**2 + B**2*r; then expr**2 = a + b*sqrt(r) = (A + B*sqrt(r))**2 Examples ======== >>> from sympy import sqrt >>> from sympy.simplify.sqrtdenest import _sqrt_match, sqrt_biquadratic_denest >>> z = sqrt((2*sqrt(2) + 4)*sqrt(2 + sqrt(2)) + 5*sqrt(2) + 8) >>> a, b, r = _sqrt_match(z**2) >>> d2 = a**2 - b**2*r >>> sqrt_biquadratic_denest(z, a, b, r, d2) sqrt(2) + sqrt(sqrt(2) + 2) + 2 """ from sympy.simplify.radsimp import radsimp, rad_rationalize if r <= 0 or d2 < 0 or not b or sqrt_depth(expr.base) < 2: return None for x in (a, b, r): for y in x.args: y2 = y**2 if not y2.is_Integer or not y2.is_positive: return None sqd = _mexpand(sqrtdenest(sqrt(radsimp(d2)))) if sqrt_depth(sqd) > 1: return None x1, x2 = [a/2 + sqd/2, a/2 - sqd/2] # look for a solution A with depth 1 for x in (x1, x2): A = sqrtdenest(sqrt(x)) if sqrt_depth(A) > 1: continue Bn, Bd = rad_rationalize(b, _mexpand(2*A)) B = Bn/Bd z = A + B*sqrt(r) if z < 0: z = -z return _mexpand(z) return None def _denester(nested, av0, h, max_depth_level): """Denests a list of expressions that contain nested square roots. Explanation =========== Algorithm based on . It is assumed that all of the elements of 'nested' share the same bottom-level radicand. (This is stated in the paper, on page 177, in the paragraph immediately preceding the algorithm.) When evaluating all of the arguments in parallel, the bottom-level radicand only needs to be denested once. This means that calling _denester with x arguments results in a recursive invocation with x+1 arguments; hence _denester has polynomial complexity. However, if the arguments were evaluated separately, each call would result in two recursive invocations, and the algorithm would have exponential complexity. This is discussed in the paper in the middle paragraph of page 179. """ from sympy.simplify.simplify import radsimp if h > max_depth_level: return None, None if av0[1] is None: return None, None if (av0[0] is None and all(n.is_Number for n in nested)): # no arguments are nested for f in _subsets(len(nested)): # test subset 'f' of nested p = _mexpand(Mul(*[nested[i] for i in range(len(f)) if f[i]])) if f.count(1) > 1 and f[-1]: p = -p sqp = sqrt(p) if sqp.is_Rational: return sqp, f # got a perfect square so return its square root. # Otherwise, return the radicand from the previous invocation. return sqrt(nested[-1]), [0]*len(nested) else: R = None if av0[0] is not None: values = [av0[:2]] R = av0[2] nested2 = [av0[3], R] av0[0] = None else: values = list(filter(None, [_sqrt_match(expr) for expr in nested])) for v in values: if v[2]: # Since if b=0, r is not defined if R is not None: if R != v[2]: av0[1] = None return None, None else: R = v[2] if R is None: # return the radicand from the previous invocation return sqrt(nested[-1]), [0]*len(nested) nested2 = [_mexpand(v[0]**2) - _mexpand(R*v[1]**2) for v in values] + [R] d, f = _denester(nested2, av0, h + 1, max_depth_level) if not f: return None, None if not any(f[i] for i in range(len(nested))): v = values[-1] return sqrt(v[0] + _mexpand(v[1]*d)), f else: p = Mul(*[nested[i] for i in range(len(nested)) if f[i]]) v = _sqrt_match(p) if 1 in f and f.index(1) < len(nested) - 1 and f[len(nested) - 1]: v[0] = -v[0] v[1] = -v[1] if not f[len(nested)]: # Solution denests with square roots vad = _mexpand(v[0] + d) if vad <= 0: # return the radicand from the previous invocation. return sqrt(nested[-1]), [0]*len(nested) if not(sqrt_depth(vad) <= sqrt_depth(R) + 1 or (vad**2).is_Number): av0[1] = None return None, None sqvad = _sqrtdenest1(sqrt(vad), denester=False) if not (sqrt_depth(sqvad) <= sqrt_depth(R) + 1): av0[1] = None return None, None sqvad1 = radsimp(1/sqvad) res = _mexpand(sqvad/sqrt(2) + (v[1]*sqrt(R)*sqvad1/sqrt(2))) return res, f # sign(v[1])*sqrt(_mexpand(v[1]**2*R*vad1/2))), f else: # Solution requires a fourth root s2 = _mexpand(v[1]*R) + d if s2 <= 0: return sqrt(nested[-1]), [0]*len(nested) FR, s = root(_mexpand(R), 4), sqrt(s2) return _mexpand(s/(sqrt(2)*FR) + v[0]*FR/(sqrt(2)*s)), f def _sqrt_ratcomb(cs, args): """Denest rational combinations of radicals. Based on section 5 of [1]. Examples ======== >>> from sympy import sqrt >>> from sympy.simplify.sqrtdenest import sqrtdenest >>> z = sqrt(1+sqrt(3)) + sqrt(3+3*sqrt(3)) - sqrt(10+6*sqrt(3)) >>> sqrtdenest(z) 0 """ from sympy.simplify.radsimp import radsimp # check if there exists a pair of sqrt that can be denested def find(a): n = len(a) for i in range(n - 1): for j in range(i + 1, n): s1 = a[i].base s2 = a[j].base p = _mexpand(s1 * s2) s = sqrtdenest(sqrt(p)) if s != sqrt(p): return s, i, j indices = find(args) if indices is None: return Add(*[c * arg for c, arg in zip(cs, args)]) s, i1, i2 = indices c2 = cs.pop(i2) args.pop(i2) a1 = args[i1] # replace a2 by s/a1 cs[i1] += radsimp(c2 * s / a1.base) return _sqrt_ratcomb(cs, args) sympy-sympy-1.9/sympy/simplify/tests/000077500000000000000000000000001412543434000201025ustar00rootroot00000000000000sympy-sympy-1.9/sympy/simplify/tests/__init__.py000066400000000000000000000000001412543434000222010ustar00rootroot00000000000000sympy-sympy-1.9/sympy/simplify/tests/test_combsimp.py000066400000000000000000000053431412543434000233310ustar00rootroot00000000000000from sympy import ( combsimp, factorial, gamma, binomial, FallingFactorial, RisingFactorial, symbols, Rational) from sympy.abc import x def test_combsimp(): k, m, n = symbols('k m n', integer = True) assert combsimp(factorial(n)) == factorial(n) assert combsimp(binomial(n, k)) == binomial(n, k) assert combsimp(factorial(n)/factorial(n - 3)) == n*(-1 + n)*(-2 + n) assert combsimp(binomial(n + 1, k + 1)/binomial(n, k)) == (1 + n)/(1 + k) assert combsimp(binomial(3*n + 4, n + 1)/binomial(3*n + 1, n)) == \ Rational(3, 2)*((3*n + 2)*(3*n + 4)/((n + 1)*(2*n + 3))) assert combsimp(factorial(n)**2/factorial(n - 3)) == \ factorial(n)*n*(-1 + n)*(-2 + n) assert combsimp(factorial(n)*binomial(n + 1, k + 1)/binomial(n, k)) == \ factorial(n + 1)/(1 + k) assert combsimp(gamma(n + 3)) == factorial(n + 2) assert combsimp(factorial(x)) == gamma(x + 1) # issue 9699 assert combsimp((n + 1)*factorial(n)) == factorial(n + 1) assert combsimp(factorial(n)/n) == factorial(n-1) # issue 6658 assert combsimp(binomial(n, n - k)) == binomial(n, k) # issue 6341, 7135 assert combsimp(factorial(n)/(factorial(k)*factorial(n - k))) == \ binomial(n, k) assert combsimp(factorial(k)*factorial(n - k)/factorial(n)) == \ 1/binomial(n, k) assert combsimp(factorial(2*n)/factorial(n)**2) == binomial(2*n, n) assert combsimp(factorial(2*n)*factorial(k)*factorial(n - k)/ factorial(n)**3) == binomial(2*n, n)/binomial(n, k) assert combsimp(factorial(n*(1 + n) - n**2 - n)) == 1 assert combsimp(6*FallingFactorial(-4, n)/factorial(n)) == \ (-1)**n*(n + 1)*(n + 2)*(n + 3) assert combsimp(6*FallingFactorial(-4, n - 1)/factorial(n - 1)) == \ (-1)**(n - 1)*n*(n + 1)*(n + 2) assert combsimp(6*FallingFactorial(-4, n - 3)/factorial(n - 3)) == \ (-1)**(n - 3)*n*(n - 1)*(n - 2) assert combsimp(6*FallingFactorial(-4, -n - 1)/factorial(-n - 1)) == \ -(-1)**(-n - 1)*n*(n - 1)*(n - 2) assert combsimp(6*RisingFactorial(4, n)/factorial(n)) == \ (n + 1)*(n + 2)*(n + 3) assert combsimp(6*RisingFactorial(4, n - 1)/factorial(n - 1)) == \ n*(n + 1)*(n + 2) assert combsimp(6*RisingFactorial(4, n - 3)/factorial(n - 3)) == \ n*(n - 1)*(n - 2) assert combsimp(6*RisingFactorial(4, -n - 1)/factorial(-n - 1)) == \ -n*(n - 1)*(n - 2) def test_issue_6878(): n = symbols('n', integer=True) assert combsimp(RisingFactorial(-10, n)) == 3628800*(-1)**n/factorial(10 - n) def test_issue_14528(): p = symbols("p", integer=True, positive=True) assert combsimp(binomial(1,p)) == 1/(factorial(p)*factorial(1-p)) assert combsimp(factorial(2-p)) == factorial(2-p) sympy-sympy-1.9/sympy/simplify/tests/test_cse.py000066400000000000000000000447071412543434000223010ustar00rootroot00000000000000from functools import reduce import itertools from operator import add from sympy import ( Add, Mul, Pow, Symbol, exp, sqrt, symbols, sympify, cse, Matrix, S, cos, sin, Eq, Function, Tuple, CRootOf, IndexedBase, Idx, Piecewise, O, signsimp ) from sympy.core.function import count_ops from sympy.simplify.cse_opts import sub_pre, sub_post from sympy.functions.special.hyper import meijerg from sympy.simplify import cse_main, cse_opts from sympy.utilities.iterables import subsets from sympy.testing.pytest import XFAIL, raises from sympy.matrices import (MutableDenseMatrix, MutableSparseMatrix, ImmutableDenseMatrix, ImmutableSparseMatrix) from sympy.matrices.expressions import MatrixSymbol w, x, y, z = symbols('w,x,y,z') x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12 = symbols('x:13') def test_numbered_symbols(): ns = cse_main.numbered_symbols(prefix='y') assert list(itertools.islice( ns, 0, 10)) == [Symbol('y%s' % i) for i in range(0, 10)] ns = cse_main.numbered_symbols(prefix='y') assert list(itertools.islice( ns, 10, 20)) == [Symbol('y%s' % i) for i in range(10, 20)] ns = cse_main.numbered_symbols() assert list(itertools.islice( ns, 0, 10)) == [Symbol('x%s' % i) for i in range(0, 10)] # Dummy "optimization" functions for testing. def opt1(expr): return expr + y def opt2(expr): return expr*z def test_preprocess_for_cse(): assert cse_main.preprocess_for_cse(x, [(opt1, None)]) == x + y assert cse_main.preprocess_for_cse(x, [(None, opt1)]) == x assert cse_main.preprocess_for_cse(x, [(None, None)]) == x assert cse_main.preprocess_for_cse(x, [(opt1, opt2)]) == x + y assert cse_main.preprocess_for_cse( x, [(opt1, None), (opt2, None)]) == (x + y)*z def test_postprocess_for_cse(): assert cse_main.postprocess_for_cse(x, [(opt1, None)]) == x assert cse_main.postprocess_for_cse(x, [(None, opt1)]) == x + y assert cse_main.postprocess_for_cse(x, [(None, None)]) == x assert cse_main.postprocess_for_cse(x, [(opt1, opt2)]) == x*z # Note the reverse order of application. assert cse_main.postprocess_for_cse( x, [(None, opt1), (None, opt2)]) == x*z + y def test_cse_single(): # Simple substitution. e = Add(Pow(x + y, 2), sqrt(x + y)) substs, reduced = cse([e]) assert substs == [(x0, x + y)] assert reduced == [sqrt(x0) + x0**2] subst42, (red42,) = cse([42]) # issue_15082 assert len(subst42) == 0 and red42 == 42 subst_half, (red_half,) = cse([0.5]) assert len(subst_half) == 0 and red_half == 0.5 def test_cse_single2(): # Simple substitution, test for being able to pass the expression directly e = Add(Pow(x + y, 2), sqrt(x + y)) substs, reduced = cse(e) assert substs == [(x0, x + y)] assert reduced == [sqrt(x0) + x0**2] substs, reduced = cse(Matrix([[1]])) assert isinstance(reduced[0], Matrix) subst42, (red42,) = cse(42) # issue 15082 assert len(subst42) == 0 and red42 == 42 subst_half, (red_half,) = cse(0.5) # issue 15082 assert len(subst_half) == 0 and red_half == 0.5 def test_cse_not_possible(): # No substitution possible. e = Add(x, y) substs, reduced = cse([e]) assert substs == [] assert reduced == [x + y] # issue 6329 eq = (meijerg((1, 2), (y, 4), (5,), [], x) + meijerg((1, 3), (y, 4), (5,), [], x)) assert cse(eq) == ([], [eq]) def test_nested_substitution(): # Substitution within a substitution. e = Add(Pow(w*x + y, 2), sqrt(w*x + y)) substs, reduced = cse([e]) assert substs == [(x0, w*x + y)] assert reduced == [sqrt(x0) + x0**2] def test_subtraction_opt(): # Make sure subtraction is optimized. e = (x - y)*(z - y) + exp((x - y)*(z - y)) substs, reduced = cse( [e], optimizations=[(cse_opts.sub_pre, cse_opts.sub_post)]) assert substs == [(x0, (x - y)*(y - z))] assert reduced == [-x0 + exp(-x0)] e = -(x - y)*(z - y) + exp(-(x - y)*(z - y)) substs, reduced = cse( [e], optimizations=[(cse_opts.sub_pre, cse_opts.sub_post)]) assert substs == [(x0, (x - y)*(y - z))] assert reduced == [x0 + exp(x0)] # issue 4077 n = -1 + 1/x e = n/x/(-n)**2 - 1/n/x assert cse(e, optimizations=[(cse_opts.sub_pre, cse_opts.sub_post)]) == \ ([], [0]) def test_multiple_expressions(): e1 = (x + y)*z e2 = (x + y)*w substs, reduced = cse([e1, e2]) assert substs == [(x0, x + y)] assert reduced == [x0*z, x0*w] l = [w*x*y + z, w*y] substs, reduced = cse(l) rsubsts, _ = cse(reversed(l)) assert substs == rsubsts assert reduced == [z + x*x0, x0] l = [w*x*y, w*x*y + z, w*y] substs, reduced = cse(l) rsubsts, _ = cse(reversed(l)) assert substs == rsubsts assert reduced == [x1, x1 + z, x0] l = [(x - z)*(y - z), x - z, y - z] substs, reduced = cse(l) rsubsts, _ = cse(reversed(l)) assert substs == [(x0, -z), (x1, x + x0), (x2, x0 + y)] assert rsubsts == [(x0, -z), (x1, x0 + y), (x2, x + x0)] assert reduced == [x1*x2, x1, x2] l = [w*y + w + x + y + z, w*x*y] assert cse(l) == ([(x0, w*y)], [w + x + x0 + y + z, x*x0]) assert cse([x + y, x + y + z]) == ([(x0, x + y)], [x0, z + x0]) assert cse([x + y, x + z]) == ([], [x + y, x + z]) assert cse([x*y, z + x*y, x*y*z + 3]) == \ ([(x0, x*y)], [x0, z + x0, 3 + x0*z]) @XFAIL # CSE of non-commutative Mul terms is disabled def test_non_commutative_cse(): A, B, C = symbols('A B C', commutative=False) l = [A*B*C, A*C] assert cse(l) == ([], l) l = [A*B*C, A*B] assert cse(l) == ([(x0, A*B)], [x0*C, x0]) # Test if CSE of non-commutative Mul terms is disabled def test_bypass_non_commutatives(): A, B, C = symbols('A B C', commutative=False) l = [A*B*C, A*C] assert cse(l) == ([], l) l = [A*B*C, A*B] assert cse(l) == ([], l) l = [B*C, A*B*C] assert cse(l) == ([], l) @XFAIL # CSE fails when replacing non-commutative sub-expressions def test_non_commutative_order(): A, B, C = symbols('A B C', commutative=False) x0 = symbols('x0', commutative=False) l = [B+C, A*(B+C)] assert cse(l) == ([(x0, B+C)], [x0, A*x0]) @XFAIL # Worked in gh-11232, but was reverted due to performance considerations def test_issue_10228(): assert cse([x*y**2 + x*y]) == ([(x0, x*y)], [x0*y + x0]) assert cse([x + y, 2*x + y]) == ([(x0, x + y)], [x0, x + x0]) assert cse((w + 2*x + y + z, w + x + 1)) == ( [(x0, w + x)], [x0 + x + y + z, x0 + 1]) assert cse(((w + x + y + z)*(w - x))/(w + x)) == ( [(x0, w + x)], [(x0 + y + z)*(w - x)/x0]) a, b, c, d, f, g, j, m = symbols('a, b, c, d, f, g, j, m') exprs = (d*g**2*j*m, 4*a*f*g*m, a*b*c*f**2) assert cse(exprs) == ( [(x0, g*m), (x1, a*f)], [d*g*j*x0, 4*x0*x1, b*c*f*x1] ) @XFAIL def test_powers(): assert cse(x*y**2 + x*y) == ([(x0, x*y)], [x0*y + x0]) def test_issue_4498(): assert cse(w/(x - y) + z/(y - x), optimizations='basic') == \ ([], [(w - z)/(x - y)]) def test_issue_4020(): assert cse(x**5 + x**4 + x**3 + x**2, optimizations='basic') \ == ([(x0, x**2)], [x0*(x**3 + x + x0 + 1)]) def test_issue_4203(): assert cse(sin(x**x)/x**x) == ([(x0, x**x)], [sin(x0)/x0]) def test_issue_6263(): e = Eq(x*(-x + 1) + x*(x - 1), 0) assert cse(e, optimizations='basic') == ([], [True]) def test_dont_cse_tuples(): from sympy import Subs f = Function("f") g = Function("g") name_val, (expr,) = cse( Subs(f(x, y), (x, y), (0, 1)) + Subs(g(x, y), (x, y), (0, 1))) assert name_val == [] assert expr == (Subs(f(x, y), (x, y), (0, 1)) + Subs(g(x, y), (x, y), (0, 1))) name_val, (expr,) = cse( Subs(f(x, y), (x, y), (0, x + y)) + Subs(g(x, y), (x, y), (0, x + y))) assert name_val == [(x0, x + y)] assert expr == Subs(f(x, y), (x, y), (0, x0)) + \ Subs(g(x, y), (x, y), (0, x0)) def test_pow_invpow(): assert cse(1/x**2 + x**2) == \ ([(x0, x**2)], [x0 + 1/x0]) assert cse(x**2 + (1 + 1/x**2)/x**2) == \ ([(x0, x**2), (x1, 1/x0)], [x0 + x1*(x1 + 1)]) assert cse(1/x**2 + (1 + 1/x**2)*x**2) == \ ([(x0, x**2), (x1, 1/x0)], [x0*(x1 + 1) + x1]) assert cse(cos(1/x**2) + sin(1/x**2)) == \ ([(x0, x**(-2))], [sin(x0) + cos(x0)]) assert cse(cos(x**2) + sin(x**2)) == \ ([(x0, x**2)], [sin(x0) + cos(x0)]) assert cse(y/(2 + x**2) + z/x**2/y) == \ ([(x0, x**2)], [y/(x0 + 2) + z/(x0*y)]) assert cse(exp(x**2) + x**2*cos(1/x**2)) == \ ([(x0, x**2)], [x0*cos(1/x0) + exp(x0)]) assert cse((1 + 1/x**2)/x**2) == \ ([(x0, x**(-2))], [x0*(x0 + 1)]) assert cse(x**(2*y) + x**(-2*y)) == \ ([(x0, x**(2*y))], [x0 + 1/x0]) def test_postprocess(): eq = (x + 1 + exp((x + 1)/(y + 1)) + cos(y + 1)) assert cse([eq, Eq(x, z + 1), z - 2, (z + 1)*(x + 1)], postprocess=cse_main.cse_separate) == \ [[(x0, y + 1), (x2, z + 1), (x, x2), (x1, x + 1)], [x1 + exp(x1/x0) + cos(x0), z - 2, x1*x2]] def test_issue_4499(): # previously, this gave 16 constants from sympy.abc import a, b B = Function('B') G = Function('G') t = Tuple(* (a, a + S.Half, 2*a, b, 2*a - b + 1, (sqrt(z)/2)**(-2*a + 1)*B(2*a - b, sqrt(z))*B(b - 1, sqrt(z))*G(b)*G(2*a - b + 1), sqrt(z)*(sqrt(z)/2)**(-2*a + 1)*B(b, sqrt(z))*B(2*a - b, sqrt(z))*G(b)*G(2*a - b + 1), sqrt(z)*(sqrt(z)/2)**(-2*a + 1)*B(b - 1, sqrt(z))*B(2*a - b + 1, sqrt(z))*G(b)*G(2*a - b + 1), (sqrt(z)/2)**(-2*a + 1)*B(b, sqrt(z))*B(2*a - b + 1, sqrt(z))*G(b)*G(2*a - b + 1), 1, 0, S.Half, z/2, -b + 1, -2*a + b, -2*a)) c = cse(t) ans = ( [(x0, 2*a), (x1, -b), (x2, x0 + x1), (x3, x2 + 1), (x4, sqrt(z)), (x5, B(b - 1, x4)), (x6, -x0), (x7, (x4/2)**(x6 + 1)*G(b)*G(x3)), (x8, x7*B(x2, x4)), (x9, B(b, x4)), (x10, x7*B(x3, x4))], [(a, a + S.Half, x0, b, x3, x5*x8, x4*x8*x9, x10*x4*x5, x10*x9, 1, 0, S.Half, z/2, x1 + 1, b + x6, x6)]) assert ans == c def test_issue_6169(): r = CRootOf(x**6 - 4*x**5 - 2, 1) assert cse(r) == ([], [r]) # and a check that the right thing is done with the new # mechanism assert sub_post(sub_pre((-x - y)*z - x - y)) == -z*(x + y) - x - y def test_cse_Indexed(): len_y = 5 y = IndexedBase('y', shape=(len_y,)) x = IndexedBase('x', shape=(len_y,)) i = Idx('i', len_y-1) expr1 = (y[i+1]-y[i])/(x[i+1]-x[i]) expr2 = 1/(x[i+1]-x[i]) replacements, reduced_exprs = cse([expr1, expr2]) assert len(replacements) > 0 def test_cse_MatrixSymbol(): # MatrixSymbols have non-Basic args, so make sure that works A = MatrixSymbol("A", 3, 3) assert cse(A) == ([], [A]) n = symbols('n', integer=True) B = MatrixSymbol("B", n, n) assert cse(B) == ([], [B]) def test_cse_MatrixExpr(): from sympy import MatrixSymbol A = MatrixSymbol('A', 3, 3) y = MatrixSymbol('y', 3, 1) expr1 = (A.T*A).I * A * y expr2 = (A.T*A) * A * y replacements, reduced_exprs = cse([expr1, expr2]) assert len(replacements) > 0 replacements, reduced_exprs = cse([expr1 + expr2, expr1]) assert replacements replacements, reduced_exprs = cse([A**2, A + A**2]) assert replacements def test_Piecewise(): f = Piecewise((-z + x*y, Eq(y, 0)), (-z - x*y, True)) ans = cse(f) actual_ans = ([(x0, -z), (x1, x*y)], [Piecewise((x0 + x1, Eq(y, 0)), (x0 - x1, True))]) assert ans == actual_ans def test_ignore_order_terms(): eq = exp(x).series(x,0,3) + sin(y+x**3) - 1 assert cse(eq) == ([], [sin(x**3 + y) + x + x**2/2 + O(x**3)]) def test_name_conflict(): z1 = x0 + y z2 = x2 + x3 l = [cos(z1) + z1, cos(z2) + z2, x0 + x2] substs, reduced = cse(l) assert [e.subs(reversed(substs)) for e in reduced] == l def test_name_conflict_cust_symbols(): z1 = x0 + y z2 = x2 + x3 l = [cos(z1) + z1, cos(z2) + z2, x0 + x2] substs, reduced = cse(l, symbols("x:10")) assert [e.subs(reversed(substs)) for e in reduced] == l def test_symbols_exhausted_error(): l = cos(x+y)+x+y+cos(w+y)+sin(w+y) sym = [x, y, z] with raises(ValueError): cse(l, symbols=sym) def test_issue_7840(): # daveknippers' example C393 = sympify( \ 'Piecewise((C391 - 1.65, C390 < 0.5), (Piecewise((C391 - 1.65, \ C391 > 2.35), (C392, True)), True))' ) C391 = sympify( \ 'Piecewise((2.05*C390**(-1.03), C390 < 0.5), (2.5*C390**(-0.625), True))' ) C393 = C393.subs('C391',C391) # simple substitution sub = {} sub['C390'] = 0.703451854 sub['C392'] = 1.01417794 ss_answer = C393.subs(sub) # cse substitutions,new_eqn = cse(C393) for pair in substitutions: sub[pair[0].name] = pair[1].subs(sub) cse_answer = new_eqn[0].subs(sub) # both methods should be the same assert ss_answer == cse_answer # GitRay's example expr = sympify( "Piecewise((Symbol('ON'), Equality(Symbol('mode'), Symbol('ON'))), \ (Piecewise((Piecewise((Symbol('OFF'), StrictLessThan(Symbol('x'), \ Symbol('threshold'))), (Symbol('ON'), true)), Equality(Symbol('mode'), \ Symbol('AUTO'))), (Symbol('OFF'), true)), true))" ) substitutions, new_eqn = cse(expr) # this Piecewise should be exactly the same assert new_eqn[0] == expr # there should not be any replacements assert len(substitutions) < 1 def test_issue_8891(): for cls in (MutableDenseMatrix, MutableSparseMatrix, ImmutableDenseMatrix, ImmutableSparseMatrix): m = cls(2, 2, [x + y, 0, 0, 0]) res = cse([x + y, m]) ans = ([(x0, x + y)], [x0, cls([[x0, 0], [0, 0]])]) assert res == ans assert isinstance(res[1][-1], cls) def test_issue_11230(): # a specific test that always failed a, b, f, k, l, i = symbols('a b f k l i') p = [a*b*f*k*l, a*i*k**2*l, f*i*k**2*l] R, C = cse(p) assert not any(i.is_Mul for a in C for i in a.args) # random tests for the issue from random import choice from sympy.core.function import expand_mul s = symbols('a:m') # 35 Mul tests, none of which should ever fail ex = [Mul(*[choice(s) for i in range(5)]) for i in range(7)] for p in subsets(ex, 3): p = list(p) R, C = cse(p) assert not any(i.is_Mul for a in C for i in a.args) for ri in reversed(R): for i in range(len(C)): C[i] = C[i].subs(*ri) assert p == C # 35 Add tests, none of which should ever fail ex = [Add(*[choice(s[:7]) for i in range(5)]) for i in range(7)] for p in subsets(ex, 3): p = list(p) R, C = cse(p) assert not any(i.is_Add for a in C for i in a.args) for ri in reversed(R): for i in range(len(C)): C[i] = C[i].subs(*ri) # use expand_mul to handle cases like this: # p = [a + 2*b + 2*e, 2*b + c + 2*e, b + 2*c + 2*g] # x0 = 2*(b + e) is identified giving a rebuilt p that # is now `[a + 2*(b + e), c + 2*(b + e), b + 2*c + 2*g]` assert p == [expand_mul(i) for i in C] @XFAIL def test_issue_11577(): def check(eq): r, c = cse(eq) assert eq.count_ops() >= \ len(r) + sum([i[1].count_ops() for i in r]) + \ count_ops(c) eq = x**5*y**2 + x**5*y + x**5 assert cse(eq) == ( [(x0, x**4), (x1, x*y)], [x**5 + x0*x1*y + x0*x1]) # ([(x0, x**5*y)], [x0*y + x0 + x**5]) or # ([(x0, x**5)], [x0*y**2 + x0*y + x0]) check(eq) eq = x**2/(y + 1)**2 + x/(y + 1) assert cse(eq) == ( [(x0, y + 1)], [x**2/x0**2 + x/x0]) # ([(x0, x/(y + 1))], [x0**2 + x0]) check(eq) def test_hollow_rejection(): eq = [x + 3, x + 4] assert cse(eq) == ([], eq) def test_cse_ignore(): exprs = [exp(y)*(3*y + 3*sqrt(x+1)), exp(y)*(5*y + 5*sqrt(x+1))] subst1, red1 = cse(exprs) assert any(y in sub.free_symbols for _, sub in subst1), "cse failed to identify any term with y" subst2, red2 = cse(exprs, ignore=(y,)) # y is not allowed in substitutions assert not any(y in sub.free_symbols for _, sub in subst2), "Sub-expressions containing y must be ignored" assert any(sub - sqrt(x + 1) == 0 for _, sub in subst2), "cse failed to identify sqrt(x + 1) as sub-expression" def test_cse_ignore_issue_15002(): l = [ w*exp(x)*exp(-z), exp(y)*exp(x)*exp(-z) ] substs, reduced = cse(l, ignore=(x,)) rl = [e.subs(reversed(substs)) for e in reduced] assert rl == l def test_cse__performance(): nexprs, nterms = 3, 20 x = symbols('x:%d' % nterms) exprs = [ reduce(add, [x[j]*(-1)**(i+j) for j in range(nterms)]) for i in range(nexprs) ] assert (exprs[0] + exprs[1]).simplify() == 0 subst, red = cse(exprs) assert len(subst) > 0, "exprs[0] == -exprs[2], i.e. a CSE" for i, e in enumerate(red): assert (e.subs(reversed(subst)) - exprs[i]).simplify() == 0 def test_issue_12070(): exprs = [x + y, 2 + x + y, x + y + z, 3 + x + y + z] subst, red = cse(exprs) assert 6 >= (len(subst) + sum([v.count_ops() for k, v in subst]) + count_ops(red)) def test_issue_13000(): eq = x/(-4*x**2 + y**2) cse_eq = cse(eq)[1][0] assert cse_eq == eq def test_issue_18203(): eq = CRootOf(x**5 + 11*x - 2, 0) + CRootOf(x**5 + 11*x - 2, 1) assert cse(eq) == ([], [eq]) def test_unevaluated_mul(): eq = Mul(x + y, x + y, evaluate=False) assert cse(eq) == ([(x0, x + y)], [x0**2]) def test_cse_release_variables(): from sympy.simplify.cse_main import cse_release_variables _0, _1, _2, _3, _4 = symbols('_:5') eqs = [(x + y - 1)**2, x, x + y, (x + y)/(2*x + 1) + (x + y - 1)**2, (2*x + 1)**(x + y)] r, e = cse(eqs, postprocess=cse_release_variables) # this can change in keeping with the intention of the function assert r, e == ([ (x0, x + y), (x1, (x0 - 1)**2), (x2, 2*x + 1), (_3, x0/x2 + x1), (_4, x2**x0), (x2, None), (_0, x1), (x1, None), (_2, x0), (x0, None), (_1, x)], (_0, _1, _2, _3, _4)) r.reverse() assert eqs == [i.subs(r) for i in e] def test_cse_list(): _cse = lambda x: cse(x, list=False) assert _cse(x) == ([], x) assert _cse('x') == ([], 'x') it = [x] for c in (list, tuple, set, Tuple): assert _cse(c(it)) == ([], c(it)) d = {x: 1} assert _cse(d) == ([], d) def test_issue_18991(): A = MatrixSymbol('A', 2, 2) assert signsimp(-A * A - A) == -A * A - A def test_unevaluated_Mul(): m = [Mul(1, 2, evaluate=False)] assert cse(m) == ([], m) sympy-sympy-1.9/sympy/simplify/tests/test_epathtools.py000066400000000000000000000066021412543434000237010ustar00rootroot00000000000000"""Tests for tools for manipulation of expressions using paths. """ from sympy.simplify.epathtools import epath, EPath from sympy.testing.pytest import raises from sympy import sin, cos, E from sympy.abc import x, y, z, t def test_epath_select(): expr = [((x, 1, t), 2), ((3, y, 4), z)] assert epath("/*", expr) == [((x, 1, t), 2), ((3, y, 4), z)] assert epath("/*/*", expr) == [(x, 1, t), 2, (3, y, 4), z] assert epath("/*/*/*", expr) == [x, 1, t, 3, y, 4] assert epath("/*/*/*/*", expr) == [] assert epath("/[:]", expr) == [((x, 1, t), 2), ((3, y, 4), z)] assert epath("/[:]/[:]", expr) == [(x, 1, t), 2, (3, y, 4), z] assert epath("/[:]/[:]/[:]", expr) == [x, 1, t, 3, y, 4] assert epath("/[:]/[:]/[:]/[:]", expr) == [] assert epath("/*/[:]", expr) == [(x, 1, t), 2, (3, y, 4), z] assert epath("/*/[0]", expr) == [(x, 1, t), (3, y, 4)] assert epath("/*/[1]", expr) == [2, z] assert epath("/*/[2]", expr) == [] assert epath("/*/int", expr) == [2] assert epath("/*/Symbol", expr) == [z] assert epath("/*/tuple", expr) == [(x, 1, t), (3, y, 4)] assert epath("/*/__iter__?", expr) == [(x, 1, t), (3, y, 4)] assert epath("/*/int|tuple", expr) == [(x, 1, t), 2, (3, y, 4)] assert epath("/*/Symbol|tuple", expr) == [(x, 1, t), (3, y, 4), z] assert epath("/*/int|Symbol|tuple", expr) == [(x, 1, t), 2, (3, y, 4), z] assert epath("/*/int|__iter__?", expr) == [(x, 1, t), 2, (3, y, 4)] assert epath("/*/Symbol|__iter__?", expr) == [(x, 1, t), (3, y, 4), z] assert epath( "/*/int|Symbol|__iter__?", expr) == [(x, 1, t), 2, (3, y, 4), z] assert epath("/*/[0]/int", expr) == [1, 3, 4] assert epath("/*/[0]/Symbol", expr) == [x, t, y] assert epath("/*/[0]/int[1:]", expr) == [1, 4] assert epath("/*/[0]/Symbol[1:]", expr) == [t, y] assert epath("/Symbol", x + y + z + 1) == [x, y, z] assert epath("/*/*/Symbol", t + sin(x + 1) + cos(x + y + E)) == [x, x, y] def test_epath_apply(): expr = [((x, 1, t), 2), ((3, y, 4), z)] func = lambda expr: expr**2 assert epath("/*", expr, list) == [[(x, 1, t), 2], [(3, y, 4), z]] assert epath("/*/[0]", expr, list) == [([x, 1, t], 2), ([3, y, 4], z)] assert epath("/*/[1]", expr, func) == [((x, 1, t), 4), ((3, y, 4), z**2)] assert epath("/*/[2]", expr, list) == expr assert epath("/*/[0]/int", expr, func) == [((x, 1, t), 2), ((9, y, 16), z)] assert epath("/*/[0]/Symbol", expr, func) == [((x**2, 1, t**2), 2), ((3, y**2, 4), z)] assert epath( "/*/[0]/int[1:]", expr, func) == [((x, 1, t), 2), ((3, y, 16), z)] assert epath("/*/[0]/Symbol[1:]", expr, func) == [((x, 1, t**2), 2), ((3, y**2, 4), z)] assert epath("/Symbol", x + y + z + 1, func) == x**2 + y**2 + z**2 + 1 assert epath("/*/*/Symbol", t + sin(x + 1) + cos(x + y + E), func) == \ t + sin(x**2 + 1) + cos(x**2 + y**2 + E) def test_EPath(): assert EPath("/*/[0]")._path == "/*/[0]" assert EPath(EPath("/*/[0]"))._path == "/*/[0]" assert isinstance(epath("/*/[0]"), EPath) is True assert repr(EPath("/*/[0]")) == "EPath('/*/[0]')" raises(ValueError, lambda: EPath("")) raises(ValueError, lambda: EPath("/")) raises(ValueError, lambda: EPath("/|x")) raises(ValueError, lambda: EPath("/[")) raises(ValueError, lambda: EPath("/[0]%")) raises(NotImplementedError, lambda: EPath("Symbol")) sympy-sympy-1.9/sympy/simplify/tests/test_fu.py000066400000000000000000000435101412543434000221300ustar00rootroot00000000000000from sympy import ( Add, Mul, S, Symbol, cos, cot, pi, I, sin, sqrt, tan, root, csc, sec, powsimp, symbols, sinh, cosh, tanh, coth, sech, csch, Dummy, Rational) from sympy.simplify.fu import ( L, TR1, TR10, TR10i, TR11, _TR11, TR12, TR12i, TR13, TR14, TR15, TR16, TR111, TR2, TR2i, TR3, TR5, TR6, TR7, TR8, TR9, TRmorrie, _TR56 as T, TRpower, hyper_as_trig, fu, process_common_addends, trig_split, as_f_sign_1) from sympy.testing.randtest import verify_numerically from sympy.abc import a, b, c, x, y, z def test_TR1(): assert TR1(2*csc(x) + sec(x)) == 1/cos(x) + 2/sin(x) def test_TR2(): assert TR2(tan(x)) == sin(x)/cos(x) assert TR2(cot(x)) == cos(x)/sin(x) assert TR2(tan(tan(x) - sin(x)/cos(x))) == 0 def test_TR2i(): # just a reminder that ratios of powers only simplify if both # numerator and denominator satisfy the condition that each # has a positive base or an integer exponent; e.g. the following, # at y=-1, x=1/2 gives sqrt(2)*I != -sqrt(2)*I assert powsimp(2**x/y**x) != (2/y)**x assert TR2i(sin(x)/cos(x)) == tan(x) assert TR2i(sin(x)*sin(y)/cos(x)) == tan(x)*sin(y) assert TR2i(1/(sin(x)/cos(x))) == 1/tan(x) assert TR2i(1/(sin(x)*sin(y)/cos(x))) == 1/tan(x)/sin(y) assert TR2i(sin(x)/2/(cos(x) + 1)) == sin(x)/(cos(x) + 1)/2 assert TR2i(sin(x)/2/(cos(x) + 1), half=True) == tan(x/2)/2 assert TR2i(sin(1)/(cos(1) + 1), half=True) == tan(S.Half) assert TR2i(sin(2)/(cos(2) + 1), half=True) == tan(1) assert TR2i(sin(4)/(cos(4) + 1), half=True) == tan(2) assert TR2i(sin(5)/(cos(5) + 1), half=True) == tan(5*S.Half) assert TR2i((cos(1) + 1)/sin(1), half=True) == 1/tan(S.Half) assert TR2i((cos(2) + 1)/sin(2), half=True) == 1/tan(1) assert TR2i((cos(4) + 1)/sin(4), half=True) == 1/tan(2) assert TR2i((cos(5) + 1)/sin(5), half=True) == 1/tan(5*S.Half) assert TR2i((cos(1) + 1)**(-a)*sin(1)**a, half=True) == tan(S.Half)**a assert TR2i((cos(2) + 1)**(-a)*sin(2)**a, half=True) == tan(1)**a assert TR2i((cos(4) + 1)**(-a)*sin(4)**a, half=True) == (cos(4) + 1)**(-a)*sin(4)**a assert TR2i((cos(5) + 1)**(-a)*sin(5)**a, half=True) == (cos(5) + 1)**(-a)*sin(5)**a assert TR2i((cos(1) + 1)**a*sin(1)**(-a), half=True) == tan(S.Half)**(-a) assert TR2i((cos(2) + 1)**a*sin(2)**(-a), half=True) == tan(1)**(-a) assert TR2i((cos(4) + 1)**a*sin(4)**(-a), half=True) == (cos(4) + 1)**a*sin(4)**(-a) assert TR2i((cos(5) + 1)**a*sin(5)**(-a), half=True) == (cos(5) + 1)**a*sin(5)**(-a) i = symbols('i', integer=True) assert TR2i(((cos(5) + 1)**i*sin(5)**(-i)), half=True) == tan(5*S.Half)**(-i) assert TR2i(1/((cos(5) + 1)**i*sin(5)**(-i)), half=True) == tan(5*S.Half)**i def test_TR3(): assert TR3(cos(y - x*(y - x))) == cos(x*(x - y) + y) assert cos(pi/2 + x) == -sin(x) assert cos(30*pi/2 + x) == -cos(x) for f in (cos, sin, tan, cot, csc, sec): i = f(pi*Rational(3, 7)) j = TR3(i) assert verify_numerically(i, j) and i.func != j.func def test__TR56(): h = lambda x: 1 - x assert T(sin(x)**3, sin, cos, h, 4, False) == sin(x)*(-cos(x)**2 + 1) assert T(sin(x)**10, sin, cos, h, 4, False) == sin(x)**10 assert T(sin(x)**6, sin, cos, h, 6, False) == (-cos(x)**2 + 1)**3 assert T(sin(x)**6, sin, cos, h, 6, True) == sin(x)**6 assert T(sin(x)**8, sin, cos, h, 10, True) == (-cos(x)**2 + 1)**4 # issue 17137 assert T(sin(x)**I, sin, cos, h, 4, True) == sin(x)**I assert T(sin(x)**(2*I + 1), sin, cos, h, 4, True) == sin(x)**(2*I + 1) def test_TR5(): assert TR5(sin(x)**2) == -cos(x)**2 + 1 assert TR5(sin(x)**-2) == sin(x)**(-2) assert TR5(sin(x)**4) == (-cos(x)**2 + 1)**2 def test_TR6(): assert TR6(cos(x)**2) == -sin(x)**2 + 1 assert TR6(cos(x)**-2) == cos(x)**(-2) assert TR6(cos(x)**4) == (-sin(x)**2 + 1)**2 def test_TR7(): assert TR7(cos(x)**2) == cos(2*x)/2 + S.Half assert TR7(cos(x)**2 + 1) == cos(2*x)/2 + Rational(3, 2) def test_TR8(): assert TR8(cos(2)*cos(3)) == cos(5)/2 + cos(1)/2 assert TR8(cos(2)*sin(3)) == sin(5)/2 + sin(1)/2 assert TR8(sin(2)*sin(3)) == -cos(5)/2 + cos(1)/2 assert TR8(sin(1)*sin(2)*sin(3)) == sin(4)/4 - sin(6)/4 + sin(2)/4 assert TR8(cos(2)*cos(3)*cos(4)*cos(5)) == \ cos(4)/4 + cos(10)/8 + cos(2)/8 + cos(8)/8 + cos(14)/8 + \ cos(6)/8 + Rational(1, 8) assert TR8(cos(2)*cos(3)*cos(4)*cos(5)*cos(6)) == \ cos(10)/8 + cos(4)/8 + 3*cos(2)/16 + cos(16)/16 + cos(8)/8 + \ cos(14)/16 + cos(20)/16 + cos(12)/16 + Rational(1, 16) + cos(6)/8 assert TR8(sin(pi*Rational(3, 7))**2*cos(pi*Rational(3, 7))**2/(16*sin(pi/7)**2)) == Rational(1, 64) def test_TR9(): a = S.Half b = 3*a assert TR9(a) == a assert TR9(cos(1) + cos(2)) == 2*cos(a)*cos(b) assert TR9(cos(1) - cos(2)) == 2*sin(a)*sin(b) assert TR9(sin(1) - sin(2)) == -2*sin(a)*cos(b) assert TR9(sin(1) + sin(2)) == 2*sin(b)*cos(a) assert TR9(cos(1) + 2*sin(1) + 2*sin(2)) == cos(1) + 4*sin(b)*cos(a) assert TR9(cos(4) + cos(2) + 2*cos(1)*cos(3)) == 4*cos(1)*cos(3) assert TR9((cos(4) + cos(2))/cos(3)/2 + cos(3)) == 2*cos(1)*cos(2) assert TR9(cos(3) + cos(4) + cos(5) + cos(6)) == \ 4*cos(S.Half)*cos(1)*cos(Rational(9, 2)) assert TR9(cos(3) + cos(3)*cos(2)) == cos(3) + cos(2)*cos(3) assert TR9(-cos(y) + cos(x*y)) == -2*sin(x*y/2 - y/2)*sin(x*y/2 + y/2) assert TR9(-sin(y) + sin(x*y)) == 2*sin(x*y/2 - y/2)*cos(x*y/2 + y/2) c = cos(x) s = sin(x) for si in ((1, 1), (1, -1), (-1, 1), (-1, -1)): for a in ((c, s), (s, c), (cos(x), cos(x*y)), (sin(x), sin(x*y))): args = zip(si, a) ex = Add(*[Mul(*ai) for ai in args]) t = TR9(ex) assert not (a[0].func == a[1].func and ( not verify_numerically(ex, t.expand(trig=True)) or t.is_Add) or a[1].func != a[0].func and ex != t) def test_TR10(): assert TR10(cos(a + b)) == -sin(a)*sin(b) + cos(a)*cos(b) assert TR10(sin(a + b)) == sin(a)*cos(b) + sin(b)*cos(a) assert TR10(sin(a + b + c)) == \ (-sin(a)*sin(b) + cos(a)*cos(b))*sin(c) + \ (sin(a)*cos(b) + sin(b)*cos(a))*cos(c) assert TR10(cos(a + b + c)) == \ (-sin(a)*sin(b) + cos(a)*cos(b))*cos(c) - \ (sin(a)*cos(b) + sin(b)*cos(a))*sin(c) def test_TR10i(): assert TR10i(cos(1)*cos(3) + sin(1)*sin(3)) == cos(2) assert TR10i(cos(1)*cos(3) - sin(1)*sin(3)) == cos(4) assert TR10i(cos(1)*sin(3) - sin(1)*cos(3)) == sin(2) assert TR10i(cos(1)*sin(3) + sin(1)*cos(3)) == sin(4) assert TR10i(cos(1)*sin(3) + sin(1)*cos(3) + 7) == sin(4) + 7 assert TR10i(cos(1)*sin(3) + sin(1)*cos(3) + cos(3)) == cos(3) + sin(4) assert TR10i(2*cos(1)*sin(3) + 2*sin(1)*cos(3) + cos(3)) == \ 2*sin(4) + cos(3) assert TR10i(cos(2)*cos(3) + sin(2)*(cos(1)*sin(2) + cos(2)*sin(1))) == \ cos(1) eq = (cos(2)*cos(3) + sin(2)*( cos(1)*sin(2) + cos(2)*sin(1)))*cos(5) + sin(1)*sin(5) assert TR10i(eq) == TR10i(eq.expand()) == cos(4) assert TR10i(sqrt(2)*cos(x)*x + sqrt(6)*sin(x)*x) == \ 2*sqrt(2)*x*sin(x + pi/6) assert TR10i(cos(x)/sqrt(6) + sin(x)/sqrt(2) + cos(x)/sqrt(6)/3 + sin(x)/sqrt(2)/3) == 4*sqrt(6)*sin(x + pi/6)/9 assert TR10i(cos(x)/sqrt(6) + sin(x)/sqrt(2) + cos(y)/sqrt(6)/3 + sin(y)/sqrt(2)/3) == \ sqrt(6)*sin(x + pi/6)/3 + sqrt(6)*sin(y + pi/6)/9 assert TR10i(cos(x) + sqrt(3)*sin(x) + 2*sqrt(3)*cos(x + pi/6)) == 4*cos(x) assert TR10i(cos(x) + sqrt(3)*sin(x) + 2*sqrt(3)*cos(x + pi/6) + 4*sin(x)) == 4*sqrt(2)*sin(x + pi/4) assert TR10i(cos(2)*sin(3) + sin(2)*cos(4)) == \ sin(2)*cos(4) + sin(3)*cos(2) A = Symbol('A', commutative=False) assert TR10i(sqrt(2)*cos(x)*A + sqrt(6)*sin(x)*A) == \ 2*sqrt(2)*sin(x + pi/6)*A c = cos(x) s = sin(x) h = sin(y) r = cos(y) for si in ((1, 1), (1, -1), (-1, 1), (-1, -1)): for argsi in ((c*r, s*h), (c*h, s*r)): # explicit 2-args args = zip(si, argsi) ex = Add(*[Mul(*ai) for ai in args]) t = TR10i(ex) assert not (ex - t.expand(trig=True) or t.is_Add) c = cos(x) s = sin(x) h = sin(pi/6) r = cos(pi/6) for si in ((1, 1), (1, -1), (-1, 1), (-1, -1)): for argsi in ((c*r, s*h), (c*h, s*r)): # induced args = zip(si, argsi) ex = Add(*[Mul(*ai) for ai in args]) t = TR10i(ex) assert not (ex - t.expand(trig=True) or t.is_Add) def test_TR11(): assert TR11(sin(2*x)) == 2*sin(x)*cos(x) assert TR11(sin(4*x)) == 4*((-sin(x)**2 + cos(x)**2)*sin(x)*cos(x)) assert TR11(sin(x*Rational(4, 3))) == \ 4*((-sin(x/3)**2 + cos(x/3)**2)*sin(x/3)*cos(x/3)) assert TR11(cos(2*x)) == -sin(x)**2 + cos(x)**2 assert TR11(cos(4*x)) == \ (-sin(x)**2 + cos(x)**2)**2 - 4*sin(x)**2*cos(x)**2 assert TR11(cos(2)) == cos(2) assert TR11(cos(pi*Rational(3, 7)), pi*Rational(2, 7)) == -cos(pi*Rational(2, 7))**2 + sin(pi*Rational(2, 7))**2 assert TR11(cos(4), 2) == -sin(2)**2 + cos(2)**2 assert TR11(cos(6), 2) == cos(6) assert TR11(sin(x)/cos(x/2), x/2) == 2*sin(x/2) def test__TR11(): assert _TR11(sin(x/3)*sin(2*x)*sin(x/4)/(cos(x/6)*cos(x/8))) == \ 4*sin(x/8)*sin(x/6)*sin(2*x),_TR11(sin(x/3)*sin(2*x)*sin(x/4)/(cos(x/6)*cos(x/8))) assert _TR11(sin(x/3)/cos(x/6)) == 2*sin(x/6) assert _TR11(cos(x/6)/sin(x/3)) == 1/(2*sin(x/6)) assert _TR11(sin(2*x)*cos(x/8)/sin(x/4)) == sin(2*x)/(2*sin(x/8)), _TR11(sin(2*x)*cos(x/8)/sin(x/4)) assert _TR11(sin(x)/sin(x/2)) == 2*cos(x/2) def test_TR12(): assert TR12(tan(x + y)) == (tan(x) + tan(y))/(-tan(x)*tan(y) + 1) assert TR12(tan(x + y + z)) ==\ (tan(z) + (tan(x) + tan(y))/(-tan(x)*tan(y) + 1))/( 1 - (tan(x) + tan(y))*tan(z)/(-tan(x)*tan(y) + 1)) assert TR12(tan(x*y)) == tan(x*y) def test_TR13(): assert TR13(tan(3)*tan(2)) == -tan(2)/tan(5) - tan(3)/tan(5) + 1 assert TR13(cot(3)*cot(2)) == 1 + cot(3)*cot(5) + cot(2)*cot(5) assert TR13(tan(1)*tan(2)*tan(3)) == \ (-tan(2)/tan(5) - tan(3)/tan(5) + 1)*tan(1) assert TR13(tan(1)*tan(2)*cot(3)) == \ (-tan(2)/tan(3) + 1 - tan(1)/tan(3))*cot(3) def test_L(): assert L(cos(x) + sin(x)) == 2 def test_fu(): assert fu(sin(50)**2 + cos(50)**2 + sin(pi/6)) == Rational(3, 2) assert fu(sqrt(6)*cos(x) + sqrt(2)*sin(x)) == 2*sqrt(2)*sin(x + pi/3) eq = sin(x)**4 - cos(y)**2 + sin(y)**2 + 2*cos(x)**2 assert fu(eq) == cos(x)**4 - 2*cos(y)**2 + 2 assert fu(S.Half - cos(2*x)/2) == sin(x)**2 assert fu(sin(a)*(cos(b) - sin(b)) + cos(a)*(sin(b) + cos(b))) == \ sqrt(2)*sin(a + b + pi/4) assert fu(sqrt(3)*cos(x)/2 + sin(x)/2) == sin(x + pi/3) assert fu(1 - sin(2*x)**2/4 - sin(y)**2 - cos(x)**4) == \ -cos(x)**2 + cos(y)**2 assert fu(cos(pi*Rational(4, 9))) == sin(pi/18) assert fu(cos(pi/9)*cos(pi*Rational(2, 9))*cos(pi*Rational(3, 9))*cos(pi*Rational(4, 9))) == Rational(1, 16) assert fu( tan(pi*Rational(7, 18)) + tan(pi*Rational(5, 18)) - sqrt(3)*tan(pi*Rational(5, 18))*tan(pi*Rational(7, 18))) == \ -sqrt(3) assert fu(tan(1)*tan(2)) == tan(1)*tan(2) expr = Mul(*[cos(2**i) for i in range(10)]) assert fu(expr) == sin(1024)/(1024*sin(1)) # issue #18059: assert fu(cos(x) + sqrt(sin(x)**2)) == cos(x) + sqrt(sin(x)**2) assert fu((-14*sin(x)**3 + 35*sin(x) + 6*sqrt(3)*cos(x)**3 + 9*sqrt(3)*cos(x))/((cos(2*x) + 4))) == \ 7*sin(x) + 3*sqrt(3)*cos(x) def test_objective(): assert fu(sin(x)/cos(x), measure=lambda x: x.count_ops()) == \ tan(x) assert fu(sin(x)/cos(x), measure=lambda x: -x.count_ops()) == \ sin(x)/cos(x) def test_process_common_addends(): # this tests that the args are not evaluated as they are given to do # and that key2 works when key1 is False do = lambda x: Add(*[i**(i%2) for i in x.args]) process_common_addends(Add(*[1, 2, 3, 4], evaluate=False), do, key2=lambda x: x%2, key1=False) == 1**1 + 3**1 + 2**0 + 4**0 def test_trig_split(): assert trig_split(cos(x), cos(y)) == (1, 1, 1, x, y, True) assert trig_split(2*cos(x), -2*cos(y)) == (2, 1, -1, x, y, True) assert trig_split(cos(x)*sin(y), cos(y)*sin(y)) == \ (sin(y), 1, 1, x, y, True) assert trig_split(cos(x), -sqrt(3)*sin(x), two=True) == \ (2, 1, -1, x, pi/6, False) assert trig_split(cos(x), sin(x), two=True) == \ (sqrt(2), 1, 1, x, pi/4, False) assert trig_split(cos(x), -sin(x), two=True) == \ (sqrt(2), 1, -1, x, pi/4, False) assert trig_split(sqrt(2)*cos(x), -sqrt(6)*sin(x), two=True) == \ (2*sqrt(2), 1, -1, x, pi/6, False) assert trig_split(-sqrt(6)*cos(x), -sqrt(2)*sin(x), two=True) == \ (-2*sqrt(2), 1, 1, x, pi/3, False) assert trig_split(cos(x)/sqrt(6), sin(x)/sqrt(2), two=True) == \ (sqrt(6)/3, 1, 1, x, pi/6, False) assert trig_split(-sqrt(6)*cos(x)*sin(y), -sqrt(2)*sin(x)*sin(y), two=True) == \ (-2*sqrt(2)*sin(y), 1, 1, x, pi/3, False) assert trig_split(cos(x), sin(x)) is None assert trig_split(cos(x), sin(z)) is None assert trig_split(2*cos(x), -sin(x)) is None assert trig_split(cos(x), -sqrt(3)*sin(x)) is None assert trig_split(cos(x)*cos(y), sin(x)*sin(z)) is None assert trig_split(cos(x)*cos(y), sin(x)*sin(y)) is None assert trig_split(-sqrt(6)*cos(x), sqrt(2)*sin(x)*sin(y), two=True) is \ None assert trig_split(sqrt(3)*sqrt(x), cos(3), two=True) is None assert trig_split(sqrt(3)*root(x, 3), sin(3)*cos(2), two=True) is None assert trig_split(cos(5)*cos(6), cos(7)*sin(5), two=True) is None def test_TRmorrie(): assert TRmorrie(7*Mul(*[cos(i) for i in range(10)])) == \ 7*sin(12)*sin(16)*cos(5)*cos(7)*cos(9)/(64*sin(1)*sin(3)) assert TRmorrie(x) == x assert TRmorrie(2*x) == 2*x e = cos(pi/7)*cos(pi*Rational(2, 7))*cos(pi*Rational(4, 7)) assert TR8(TRmorrie(e)) == Rational(-1, 8) e = Mul(*[cos(2**i*pi/17) for i in range(1, 17)]) assert TR8(TR3(TRmorrie(e))) == Rational(1, 65536) # issue 17063 eq = cos(x)/cos(x/2) assert TRmorrie(eq) == eq # issue #20430 eq = cos(x/2)*sin(x/2)*cos(x)**3 assert TRmorrie(eq) == sin(2*x)*cos(x)**2/4 def test_TRpower(): assert TRpower(1/sin(x)**2) == 1/sin(x)**2 assert TRpower(cos(x)**3*sin(x/2)**4) == \ (3*cos(x)/4 + cos(3*x)/4)*(-cos(x)/2 + cos(2*x)/8 + Rational(3, 8)) for k in range(2, 8): assert verify_numerically(sin(x)**k, TRpower(sin(x)**k)) assert verify_numerically(cos(x)**k, TRpower(cos(x)**k)) def test_hyper_as_trig(): from sympy.simplify.fu import _osborne as o, _osbornei as i, TR12 eq = sinh(x)**2 + cosh(x)**2 t, f = hyper_as_trig(eq) assert f(fu(t)) == cosh(2*x) e, f = hyper_as_trig(tanh(x + y)) assert f(TR12(e)) == (tanh(x) + tanh(y))/(tanh(x)*tanh(y) + 1) d = Dummy() assert o(sinh(x), d) == I*sin(x*d) assert o(tanh(x), d) == I*tan(x*d) assert o(coth(x), d) == cot(x*d)/I assert o(cosh(x), d) == cos(x*d) assert o(sech(x), d) == sec(x*d) assert o(csch(x), d) == csc(x*d)/I for func in (sinh, cosh, tanh, coth, sech, csch): h = func(pi) assert i(o(h, d), d) == h # /!\ the _osborne functions are not meant to work # in the o(i(trig, d), d) direction so we just check # that they work as they are supposed to work assert i(cos(x*y + z), y) == cosh(x + z*I) assert i(sin(x*y + z), y) == sinh(x + z*I)/I assert i(tan(x*y + z), y) == tanh(x + z*I)/I assert i(cot(x*y + z), y) == coth(x + z*I)*I assert i(sec(x*y + z), y) == sech(x + z*I) assert i(csc(x*y + z), y) == csch(x + z*I)*I def test_TR12i(): ta, tb, tc = [tan(i) for i in (a, b, c)] assert TR12i((ta + tb)/(-ta*tb + 1)) == tan(a + b) assert TR12i((ta + tb)/(ta*tb - 1)) == -tan(a + b) assert TR12i((-ta - tb)/(ta*tb - 1)) == tan(a + b) eq = (ta + tb)/(-ta*tb + 1)**2*(-3*ta - 3*tc)/(2*(ta*tc - 1)) assert TR12i(eq.expand()) == \ -3*tan(a + b)*tan(a + c)/(tan(a) + tan(b) - 1)/2 assert TR12i(tan(x)/sin(x)) == tan(x)/sin(x) eq = (ta + cos(2))/(-ta*tb + 1) assert TR12i(eq) == eq eq = (ta + tb + 2)**2/(-ta*tb + 1) assert TR12i(eq) == eq eq = ta/(-ta*tb + 1) assert TR12i(eq) == eq eq = (((ta + tb)*(a + 1)).expand())**2/(ta*tb - 1) assert TR12i(eq) == -(a + 1)**2*tan(a + b) def test_TR14(): eq = (cos(x) - 1)*(cos(x) + 1) ans = -sin(x)**2 assert TR14(eq) == ans assert TR14(1/eq) == 1/ans assert TR14((cos(x) - 1)**2*(cos(x) + 1)**2) == ans**2 assert TR14((cos(x) - 1)**2*(cos(x) + 1)**3) == ans**2*(cos(x) + 1) assert TR14((cos(x) - 1)**3*(cos(x) + 1)**2) == ans**2*(cos(x) - 1) eq = (cos(x) - 1)**y*(cos(x) + 1)**y assert TR14(eq) == eq eq = (cos(x) - 2)**y*(cos(x) + 1) assert TR14(eq) == eq eq = (tan(x) - 2)**2*(cos(x) + 1) assert TR14(eq) == eq i = symbols('i', integer=True) assert TR14((cos(x) - 1)**i*(cos(x) + 1)**i) == ans**i assert TR14((sin(x) - 1)**i*(sin(x) + 1)**i) == (-cos(x)**2)**i # could use extraction in this case eq = (cos(x) - 1)**(i + 1)*(cos(x) + 1)**i assert TR14(eq) in [(cos(x) - 1)*ans**i, eq] assert TR14((sin(x) - 1)*(sin(x) + 1)) == -cos(x)**2 p1 = (cos(x) + 1)*(cos(x) - 1) p2 = (cos(y) - 1)*2*(cos(y) + 1) p3 = (3*(cos(y) - 1))*(3*(cos(y) + 1)) assert TR14(p1*p2*p3*(x - 1)) == -18*((x - 1)*sin(x)**2*sin(y)**4) def test_TR15_16_17(): assert TR15(1 - 1/sin(x)**2) == -cot(x)**2 assert TR16(1 - 1/cos(x)**2) == -tan(x)**2 assert TR111(1 - 1/tan(x)**2) == 1 - cot(x)**2 def test_as_f_sign_1(): assert as_f_sign_1(x + 1) == (1, x, 1) assert as_f_sign_1(x - 1) == (1, x, -1) assert as_f_sign_1(-x + 1) == (-1, x, -1) assert as_f_sign_1(-x - 1) == (-1, x, 1) assert as_f_sign_1(2*x + 2) == (2, x, 1) assert as_f_sign_1(x*y - y) == (y, x, -1) assert as_f_sign_1(-x*y + y) == (-y, x, -1) sympy-sympy-1.9/sympy/simplify/tests/test_function.py000066400000000000000000000042271412543434000233450ustar00rootroot00000000000000""" Unit tests for Hyper_Function""" from sympy.core import symbols, Dummy, Tuple, S, Rational from sympy.functions import hyper from sympy.simplify.hyperexpand import Hyper_Function def test_attrs(): a, b = symbols('a, b', cls=Dummy) f = Hyper_Function([2, a], [b]) assert f.ap == Tuple(2, a) assert f.bq == Tuple(b) assert f.args == (Tuple(2, a), Tuple(b)) assert f.sizes == (2, 1) def test_call(): a, b, x = symbols('a, b, x', cls=Dummy) f = Hyper_Function([2, a], [b]) assert f(x) == hyper([2, a], [b], x) def test_has(): a, b, c = symbols('a, b, c', cls=Dummy) f = Hyper_Function([2, -a], [b]) assert f.has(a) assert f.has(Tuple(b)) assert not f.has(c) def test_eq(): assert Hyper_Function([1], []) == Hyper_Function([1], []) assert (Hyper_Function([1], []) != Hyper_Function([1], [])) is False assert Hyper_Function([1], []) != Hyper_Function([2], []) assert Hyper_Function([1], []) != Hyper_Function([1, 2], []) assert Hyper_Function([1], []) != Hyper_Function([1], [2]) def test_gamma(): assert Hyper_Function([2, 3], [-1]).gamma == 0 assert Hyper_Function([-2, -3], [-1]).gamma == 2 n = Dummy(integer=True) assert Hyper_Function([-1, n, 1], []).gamma == 1 assert Hyper_Function([-1, -n, 1], []).gamma == 1 p = Dummy(integer=True, positive=True) assert Hyper_Function([-1, p, 1], []).gamma == 1 assert Hyper_Function([-1, -p, 1], []).gamma == 2 def test_suitable_origin(): assert Hyper_Function((S.Half,), (Rational(3, 2),))._is_suitable_origin() is True assert Hyper_Function((S.Half,), (S.Half,))._is_suitable_origin() is False assert Hyper_Function((S.Half,), (Rational(-1, 2),))._is_suitable_origin() is False assert Hyper_Function((S.Half,), (0,))._is_suitable_origin() is False assert Hyper_Function((S.Half,), (-1, 1,))._is_suitable_origin() is False assert Hyper_Function((S.Half, 0), (1,))._is_suitable_origin() is False assert Hyper_Function((S.Half, 1), (2, Rational(-2, 3)))._is_suitable_origin() is True assert Hyper_Function((S.Half, 1), (2, Rational(-2, 3), Rational(3, 2)))._is_suitable_origin() is True sympy-sympy-1.9/sympy/simplify/tests/test_gammasimp.py000066400000000000000000000105001412543434000234620ustar00rootroot00000000000000from sympy import ( Rational, gammasimp, factorial, gamma, binomial, pi, S, sin, exp, Piecewise, powsimp, sqrt, simplify, symbols, cos, rf) from sympy.abc import x, y, n, k def test_gammasimp(): R = Rational # was part of test_combsimp_gamma() in test_combsimp.py assert gammasimp(gamma(x)) == gamma(x) assert gammasimp(gamma(x + 1)/x) == gamma(x) assert gammasimp(gamma(x)/(x - 1)) == gamma(x - 1) assert gammasimp(x*gamma(x)) == gamma(x + 1) assert gammasimp((x + 1)*gamma(x + 1)) == gamma(x + 2) assert gammasimp(gamma(x + y)*(x + y)) == gamma(x + y + 1) assert gammasimp(x/gamma(x + 1)) == 1/gamma(x) assert gammasimp((x + 1)**2/gamma(x + 2)) == (x + 1)/gamma(x + 1) assert gammasimp(x*gamma(x) + gamma(x + 3)/(x + 2)) == \ (x + 2)*gamma(x + 1) assert gammasimp(gamma(2*x)*x) == gamma(2*x + 1)/2 assert gammasimp(gamma(2*x)/(x - S.Half)) == 2*gamma(2*x - 1) assert gammasimp(gamma(x)*gamma(1 - x)) == pi/sin(pi*x) assert gammasimp(gamma(x)*gamma(-x)) == -pi/(x*sin(pi*x)) assert gammasimp(1/gamma(x + 3)/gamma(1 - x)) == \ sin(pi*x)/(pi*x*(x + 1)*(x + 2)) assert gammasimp(factorial(n + 2)) == gamma(n + 3) assert gammasimp(binomial(n, k)) == \ gamma(n + 1)/(gamma(k + 1)*gamma(-k + n + 1)) assert powsimp(gammasimp( gamma(x)*gamma(x + S.Half)*gamma(y)/gamma(x + y))) == \ 2**(-2*x + 1)*sqrt(pi)*gamma(2*x)*gamma(y)/gamma(x + y) assert gammasimp(1/gamma(x)/gamma(x - Rational(1, 3))/gamma(x + Rational(1, 3))) == \ 3**(3*x - Rational(3, 2))/(2*pi*gamma(3*x - 1)) assert simplify( gamma(S.Half + x/2)*gamma(1 + x/2)/gamma(1 + x)/sqrt(pi)*2**x) == 1 assert gammasimp(gamma(Rational(-1, 4))*gamma(Rational(-3, 4))) == 16*sqrt(2)*pi/3 assert powsimp(gammasimp(gamma(2*x)/gamma(x))) == \ 2**(2*x - 1)*gamma(x + S.Half)/sqrt(pi) # issue 6792 e = (-gamma(k)*gamma(k + 2) + gamma(k + 1)**2)/gamma(k)**2 assert gammasimp(e) == -k assert gammasimp(1/e) == -1/k e = (gamma(x) + gamma(x + 1))/gamma(x) assert gammasimp(e) == x + 1 assert gammasimp(1/e) == 1/(x + 1) e = (gamma(x) + gamma(x + 2))*(gamma(x - 1) + gamma(x))/gamma(x) assert gammasimp(e) == (x**2 + x + 1)*gamma(x + 1)/(x - 1) e = (-gamma(k)*gamma(k + 2) + gamma(k + 1)**2)/gamma(k)**2 assert gammasimp(e**2) == k**2 assert gammasimp(e**2/gamma(k + 1)) == k/gamma(k) a = R(1, 2) + R(1, 3) b = a + R(1, 3) assert gammasimp(gamma(2*k)/gamma(k)*gamma(k + a)*gamma(k + b)) 3*2**(2*k + 1)*3**(-3*k - 2)*sqrt(pi)*gamma(3*k + R(3, 2))/2 # issue 9699 assert gammasimp((x + 1)*factorial(x)/gamma(y)) == gamma(x + 2)/gamma(y) assert gammasimp(rf(x + n, k)*binomial(n, k)).simplify() == Piecewise( (gamma(n + 1)*gamma(k + n + x)/(gamma(k + 1)*gamma(n + x)*gamma(-k + n + 1)), n > -x), ((-1)**k*gamma(n + 1)*gamma(-n - x + 1)/(gamma(k + 1)*gamma(-k + n + 1)*gamma(-k - n - x + 1)), True)) A, B = symbols('A B', commutative=False) assert gammasimp(e*B*A) == gammasimp(e)*B*A # check iteration assert gammasimp(gamma(2*k)/gamma(k)*gamma(-k - R(1, 2))) == ( -2**(2*k + 1)*sqrt(pi)/(2*((2*k + 1)*cos(pi*k)))) assert gammasimp( gamma(k)*gamma(k + R(1, 3))*gamma(k + R(2, 3))/gamma(k*R(3, 2))) == ( 3*2**(3*k + 1)*3**(-3*k - S.Half)*sqrt(pi)*gamma(k*R(3, 2) + S.Half)/2) # issue 6153 assert gammasimp(gamma(Rational(1, 4))/gamma(Rational(5, 4))) == 4 # was part of test_combsimp() in test_combsimp.py assert gammasimp(binomial(n + 2, k + S.Half)) == gamma(n + 3)/ \ (gamma(k + R(3, 2))*gamma(-k + n + R(5, 2))) assert gammasimp(binomial(n + 2, k + 2.0)) == \ gamma(n + 3)/(gamma(k + 3.0)*gamma(-k + n + 1)) # issue 11548 assert gammasimp(binomial(0, x)) == sin(pi*x)/(pi*x) e = gamma(n + Rational(1, 3))*gamma(n + R(2, 3)) assert gammasimp(e) == e assert gammasimp(gamma(4*n + S.Half)/gamma(2*n - R(3, 4))) == \ 2**(4*n - R(5, 2))*(8*n - 3)*gamma(2*n + R(3, 4))/sqrt(pi) i, m = symbols('i m', integer = True) e = gamma(exp(i)) assert gammasimp(e) == e e = gamma(m + 3) assert gammasimp(e) == e e = gamma(m + 1)/(gamma(i + 1)*gamma(-i + m + 1)) assert gammasimp(e) == e p = symbols("p", integer=True, positive=True) assert gammasimp(gamma(-p+4)) == gamma(-p+4) sympy-sympy-1.9/sympy/simplify/tests/test_hyperexpand.py000066400000000000000000001156241412543434000240530ustar00rootroot00000000000000from random import randrange from sympy.simplify.hyperexpand import (ShiftA, ShiftB, UnShiftA, UnShiftB, MeijerShiftA, MeijerShiftB, MeijerShiftC, MeijerShiftD, MeijerUnShiftA, MeijerUnShiftB, MeijerUnShiftC, MeijerUnShiftD, ReduceOrder, reduce_order, apply_operators, devise_plan, make_derivative_operator, Formula, hyperexpand, Hyper_Function, G_Function, reduce_order_meijer, build_hypergeometric_formula) from sympy import hyper, I, S, meijerg, Piecewise, Tuple, Sum, binomial, Expr from sympy.abc import z, a, b, c from sympy.testing.pytest import XFAIL, raises, slow, ON_TRAVIS, skip from sympy.testing.randtest import verify_numerically as tn from sympy import (cos, sin, log, exp, asin, lowergamma, atanh, besseli, gamma, sqrt, pi, erf, exp_polar, Rational) def test_branch_bug(): assert hyperexpand(hyper((Rational(-1, 3), S.Half), (Rational(2, 3), Rational(3, 2)), -z)) == \ -z**S('1/3')*lowergamma(exp_polar(I*pi)/3, z)/5 \ + sqrt(pi)*erf(sqrt(z))/(5*sqrt(z)) assert hyperexpand(meijerg([Rational(7, 6), 1], [], [Rational(2, 3)], [Rational(1, 6), 0], z)) == \ 2*z**S('2/3')*(2*sqrt(pi)*erf(sqrt(z))/sqrt(z) - 2*lowergamma( Rational(2, 3), z)/z**S('2/3'))*gamma(Rational(2, 3))/gamma(Rational(5, 3)) def test_hyperexpand(): # Luke, Y. L. (1969), The Special Functions and Their Approximations, # Volume 1, section 6.2 assert hyperexpand(hyper([], [], z)) == exp(z) assert hyperexpand(hyper([1, 1], [2], -z)*z) == log(1 + z) assert hyperexpand(hyper([], [S.Half], -z**2/4)) == cos(z) assert hyperexpand(z*hyper([], [S('3/2')], -z**2/4)) == sin(z) assert hyperexpand(hyper([S('1/2'), S('1/2')], [S('3/2')], z**2)*z) \ == asin(z) assert isinstance(Sum(binomial(2, z)*z**2, (z, 0, a)).doit(), Expr) def can_do(ap, bq, numerical=True, div=1, lowerplane=False): from sympy import exp_polar, exp r = hyperexpand(hyper(ap, bq, z)) if r.has(hyper): return False if not numerical: return True repl = {} randsyms = r.free_symbols - {z} while randsyms: # Only randomly generated parameters are checked. for n, ai in enumerate(randsyms): repl[ai] = randcplx(n)/div if not any([b.is_Integer and b <= 0 for b in Tuple(*bq).subs(repl)]): break [a, b, c, d] = [2, -1, 3, 1] if lowerplane: [a, b, c, d] = [2, -2, 3, -1] return tn( hyper(ap, bq, z).subs(repl), r.replace(exp_polar, exp).subs(repl), z, a=a, b=b, c=c, d=d) def test_roach(): # Kelly B. Roach. Meijer G Function Representations. # Section "Gallery" assert can_do([S.Half], [Rational(9, 2)]) assert can_do([], [1, Rational(5, 2), 4]) assert can_do([Rational(-1, 2), 1, 2], [3, 4]) assert can_do([Rational(1, 3)], [Rational(-2, 3), Rational(-1, 2), S.Half, 1]) assert can_do([Rational(-3, 2), Rational(-1, 2)], [Rational(-5, 2), 1]) assert can_do([Rational(-3, 2), ], [Rational(-1, 2), S.Half]) # shine-integral assert can_do([Rational(-3, 2), Rational(-1, 2)], [2]) # elliptic integrals @XFAIL def test_roach_fail(): assert can_do([Rational(-1, 2), 1], [Rational(1, 4), S.Half, Rational(3, 4)]) # PFDD assert can_do([Rational(3, 2)], [Rational(5, 2), 5]) # struve function assert can_do([Rational(-1, 2), S.Half, 1], [Rational(3, 2), Rational(5, 2)]) # polylog, pfdd assert can_do([1, 2, 3], [S.Half, 4]) # XXX ? assert can_do([S.Half], [Rational(-1, 3), Rational(-1, 2), Rational(-2, 3)]) # PFDD ? # For the long table tests, see end of file def test_polynomial(): from sympy import oo assert hyperexpand(hyper([], [-1], z)) is oo assert hyperexpand(hyper([-2], [-1], z)) is oo assert hyperexpand(hyper([0, 0], [-1], z)) == 1 assert can_do([-5, -2, randcplx(), randcplx()], [-10, randcplx()]) assert hyperexpand(hyper((-1, 1), (-2,), z)) == 1 + z/2 def test_hyperexpand_bases(): assert hyperexpand(hyper([2], [a], z)) == \ a + z**(-a + 1)*(-a**2 + 3*a + z*(a - 1) - 2)*exp(z)* \ lowergamma(a - 1, z) - 1 # TODO [a+1, aRational(-1, 2)], [2*a] assert hyperexpand(hyper([1, 2], [3], z)) == -2/z - 2*log(-z + 1)/z**2 assert hyperexpand(hyper([S.Half, 2], [Rational(3, 2)], z)) == \ -1/(2*z - 2) + atanh(sqrt(z))/sqrt(z)/2 assert hyperexpand(hyper([S.Half, S.Half], [Rational(5, 2)], z)) == \ (-3*z + 3)/4/(z*sqrt(-z + 1)) \ + (6*z - 3)*asin(sqrt(z))/(4*z**Rational(3, 2)) assert hyperexpand(hyper([1, 2], [Rational(3, 2)], z)) == -1/(2*z - 2) \ - asin(sqrt(z))/(sqrt(z)*(2*z - 2)*sqrt(-z + 1)) assert hyperexpand(hyper([Rational(-1, 2) - 1, 1, 2], [S.Half, 3], z)) == \ sqrt(z)*(z*Rational(6, 7) - Rational(6, 5))*atanh(sqrt(z)) \ + (-30*z**2 + 32*z - 6)/35/z - 6*log(-z + 1)/(35*z**2) assert hyperexpand(hyper([1 + S.Half, 1, 1], [2, 2], z)) == \ -4*log(sqrt(-z + 1)/2 + S.Half)/z # TODO hyperexpand(hyper([a], [2*a + 1], z)) # TODO [S.Half, a], [Rational(3, 2), a+1] assert hyperexpand(hyper([2], [b, 1], z)) == \ z**(-b/2 + S.Half)*besseli(b - 1, 2*sqrt(z))*gamma(b) \ + z**(-b/2 + 1)*besseli(b, 2*sqrt(z))*gamma(b) # TODO [a], [a - S.Half, 2*a] def test_hyperexpand_parametric(): assert hyperexpand(hyper([a, S.Half + a], [S.Half], z)) \ == (1 + sqrt(z))**(-2*a)/2 + (1 - sqrt(z))**(-2*a)/2 assert hyperexpand(hyper([a, Rational(-1, 2) + a], [2*a], z)) \ == 2**(2*a - 1)*((-z + 1)**S.Half + 1)**(-2*a + 1) def test_shifted_sum(): from sympy import simplify assert simplify(hyperexpand(z**4*hyper([2], [3, S('3/2')], -z**2))) \ == z*sin(2*z) + (-z**2 + S.Half)*cos(2*z) - S.Half def _randrat(): """ Steer clear of integers. """ return S(randrange(25) + 10)/50 def randcplx(offset=-1): """ Polys is not good with real coefficients. """ return _randrat() + I*_randrat() + I*(1 + offset) @slow def test_formulae(): from sympy.simplify.hyperexpand import FormulaCollection formulae = FormulaCollection().formulae for formula in formulae: h = formula.func(formula.z) rep = {} for n, sym in enumerate(formula.symbols): rep[sym] = randcplx(n) # NOTE hyperexpand returns truly branched functions. We know we are # on the main sheet, but numerical evaluation can still go wrong # (e.g. if exp_polar cannot be evalf'd). # Just replace all exp_polar by exp, this usually works. # first test if the closed-form is actually correct h = h.subs(rep) closed_form = formula.closed_form.subs(rep).rewrite('nonrepsmall') z = formula.z assert tn(h, closed_form.replace(exp_polar, exp), z) # now test the computed matrix cl = (formula.C * formula.B)[0].subs(rep).rewrite('nonrepsmall') assert tn(closed_form.replace( exp_polar, exp), cl.replace(exp_polar, exp), z) deriv1 = z*formula.B.applyfunc(lambda t: t.rewrite( 'nonrepsmall')).diff(z) deriv2 = formula.M * formula.B for d1, d2 in zip(deriv1, deriv2): assert tn(d1.subs(rep).replace(exp_polar, exp), d2.subs(rep).rewrite('nonrepsmall').replace(exp_polar, exp), z) def test_meijerg_formulae(): from sympy.simplify.hyperexpand import MeijerFormulaCollection formulae = MeijerFormulaCollection().formulae for sig in formulae: for formula in formulae[sig]: g = meijerg(formula.func.an, formula.func.ap, formula.func.bm, formula.func.bq, formula.z) rep = {} for sym in formula.symbols: rep[sym] = randcplx() # first test if the closed-form is actually correct g = g.subs(rep) closed_form = formula.closed_form.subs(rep) z = formula.z assert tn(g, closed_form, z) # now test the computed matrix cl = (formula.C * formula.B)[0].subs(rep) assert tn(closed_form, cl, z) deriv1 = z*formula.B.diff(z) deriv2 = formula.M * formula.B for d1, d2 in zip(deriv1, deriv2): assert tn(d1.subs(rep), d2.subs(rep), z) def op(f): return z*f.diff(z) def test_plan(): assert devise_plan(Hyper_Function([0], ()), Hyper_Function([0], ()), z) == [] with raises(ValueError): devise_plan(Hyper_Function([1], ()), Hyper_Function((), ()), z) with raises(ValueError): devise_plan(Hyper_Function([2], [1]), Hyper_Function([2], [2]), z) with raises(ValueError): devise_plan(Hyper_Function([2], []), Hyper_Function([S("1/2")], []), z) # We cannot use pi/(10000 + n) because polys is insanely slow. a1, a2, b1 = (randcplx(n) for n in range(3)) b1 += 2*I h = hyper([a1, a2], [b1], z) h2 = hyper((a1 + 1, a2), [b1], z) assert tn(apply_operators(h, devise_plan(Hyper_Function((a1 + 1, a2), [b1]), Hyper_Function((a1, a2), [b1]), z), op), h2, z) h2 = hyper((a1 + 1, a2 - 1), [b1], z) assert tn(apply_operators(h, devise_plan(Hyper_Function((a1 + 1, a2 - 1), [b1]), Hyper_Function((a1, a2), [b1]), z), op), h2, z) def test_plan_derivatives(): a1, a2, a3 = 1, 2, S('1/2') b1, b2 = 3, S('5/2') h = Hyper_Function((a1, a2, a3), (b1, b2)) h2 = Hyper_Function((a1 + 1, a2 + 1, a3 + 2), (b1 + 1, b2 + 1)) ops = devise_plan(h2, h, z) f = Formula(h, z, h(z), []) deriv = make_derivative_operator(f.M, z) assert tn((apply_operators(f.C, ops, deriv)*f.B)[0], h2(z), z) h2 = Hyper_Function((a1, a2 - 1, a3 - 2), (b1 - 1, b2 - 1)) ops = devise_plan(h2, h, z) assert tn((apply_operators(f.C, ops, deriv)*f.B)[0], h2(z), z) def test_reduction_operators(): a1, a2, b1 = (randcplx(n) for n in range(3)) h = hyper([a1], [b1], z) assert ReduceOrder(2, 0) is None assert ReduceOrder(2, -1) is None assert ReduceOrder(1, S('1/2')) is None h2 = hyper((a1, a2), (b1, a2), z) assert tn(ReduceOrder(a2, a2).apply(h, op), h2, z) h2 = hyper((a1, a2 + 1), (b1, a2), z) assert tn(ReduceOrder(a2 + 1, a2).apply(h, op), h2, z) h2 = hyper((a2 + 4, a1), (b1, a2), z) assert tn(ReduceOrder(a2 + 4, a2).apply(h, op), h2, z) # test several step order reduction ap = (a2 + 4, a1, b1 + 1) bq = (a2, b1, b1) func, ops = reduce_order(Hyper_Function(ap, bq)) assert func.ap == (a1,) assert func.bq == (b1,) assert tn(apply_operators(h, ops, op), hyper(ap, bq, z), z) def test_shift_operators(): a1, a2, b1, b2, b3 = (randcplx(n) for n in range(5)) h = hyper((a1, a2), (b1, b2, b3), z) raises(ValueError, lambda: ShiftA(0)) raises(ValueError, lambda: ShiftB(1)) assert tn(ShiftA(a1).apply(h, op), hyper((a1 + 1, a2), (b1, b2, b3), z), z) assert tn(ShiftA(a2).apply(h, op), hyper((a1, a2 + 1), (b1, b2, b3), z), z) assert tn(ShiftB(b1).apply(h, op), hyper((a1, a2), (b1 - 1, b2, b3), z), z) assert tn(ShiftB(b2).apply(h, op), hyper((a1, a2), (b1, b2 - 1, b3), z), z) assert tn(ShiftB(b3).apply(h, op), hyper((a1, a2), (b1, b2, b3 - 1), z), z) def test_ushift_operators(): a1, a2, b1, b2, b3 = (randcplx(n) for n in range(5)) h = hyper((a1, a2), (b1, b2, b3), z) raises(ValueError, lambda: UnShiftA((1,), (), 0, z)) raises(ValueError, lambda: UnShiftB((), (-1,), 0, z)) raises(ValueError, lambda: UnShiftA((1,), (0, -1, 1), 0, z)) raises(ValueError, lambda: UnShiftB((0, 1), (1,), 0, z)) s = UnShiftA((a1, a2), (b1, b2, b3), 0, z) assert tn(s.apply(h, op), hyper((a1 - 1, a2), (b1, b2, b3), z), z) s = UnShiftA((a1, a2), (b1, b2, b3), 1, z) assert tn(s.apply(h, op), hyper((a1, a2 - 1), (b1, b2, b3), z), z) s = UnShiftB((a1, a2), (b1, b2, b3), 0, z) assert tn(s.apply(h, op), hyper((a1, a2), (b1 + 1, b2, b3), z), z) s = UnShiftB((a1, a2), (b1, b2, b3), 1, z) assert tn(s.apply(h, op), hyper((a1, a2), (b1, b2 + 1, b3), z), z) s = UnShiftB((a1, a2), (b1, b2, b3), 2, z) assert tn(s.apply(h, op), hyper((a1, a2), (b1, b2, b3 + 1), z), z) def can_do_meijer(a1, a2, b1, b2, numeric=True): """ This helper function tries to hyperexpand() the meijer g-function corresponding to the parameters a1, a2, b1, b2. It returns False if this expansion still contains g-functions. If numeric is True, it also tests the so-obtained formula numerically (at random values) and returns False if the test fails. Else it returns True. """ from sympy import unpolarify, expand r = hyperexpand(meijerg(a1, a2, b1, b2, z)) if r.has(meijerg): return False # NOTE hyperexpand() returns a truly branched function, whereas numerical # evaluation only works on the main branch. Since we are evaluating on # the main branch, this should not be a problem, but expressions like # exp_polar(I*pi/2*x)**a are evaluated incorrectly. We thus have to get # rid of them. The expand heuristically does this... r = unpolarify(expand(r, force=True, power_base=True, power_exp=False, mul=False, log=False, multinomial=False, basic=False)) if not numeric: return True repl = {} for n, ai in enumerate(meijerg(a1, a2, b1, b2, z).free_symbols - {z}): repl[ai] = randcplx(n) return tn(meijerg(a1, a2, b1, b2, z).subs(repl), r.subs(repl), z) @slow def test_meijerg_expand(): from sympy import gammasimp, simplify # from mpmath docs assert hyperexpand(meijerg([[], []], [[0], []], -z)) == exp(z) assert hyperexpand(meijerg([[1, 1], []], [[1], [0]], z)) == \ log(z + 1) assert hyperexpand(meijerg([[1, 1], []], [[1], [1]], z)) == \ z/(z + 1) assert hyperexpand(meijerg([[], []], [[S.Half], [0]], (z/2)**2)) \ == sin(z)/sqrt(pi) assert hyperexpand(meijerg([[], []], [[0], [S.Half]], (z/2)**2)) \ == cos(z)/sqrt(pi) assert can_do_meijer([], [a], [a - 1, a - S.Half], []) assert can_do_meijer([], [], [a/2], [-a/2], False) # branches... assert can_do_meijer([a], [b], [a], [b, a - 1]) # wikipedia assert hyperexpand(meijerg([1], [], [], [0], z)) == \ Piecewise((0, abs(z) < 1), (1, abs(1/z) < 1), (meijerg([1], [], [], [0], z), True)) assert hyperexpand(meijerg([], [1], [0], [], z)) == \ Piecewise((1, abs(z) < 1), (0, abs(1/z) < 1), (meijerg([], [1], [0], [], z), True)) # The Special Functions and their Approximations assert can_do_meijer([], [], [a + b/2], [a, a - b/2, a + S.Half]) assert can_do_meijer( [], [], [a], [b], False) # branches only agree for small z assert can_do_meijer([], [S.Half], [a], [-a]) assert can_do_meijer([], [], [a, b], []) assert can_do_meijer([], [], [a, b], []) assert can_do_meijer([], [], [a, a + S.Half], [b, b + S.Half]) assert can_do_meijer([], [], [a, -a], [0, S.Half], False) # dito assert can_do_meijer([], [], [a, a + S.Half, b, b + S.Half], []) assert can_do_meijer([S.Half], [], [0], [a, -a]) assert can_do_meijer([S.Half], [], [a], [0, -a], False) # dito assert can_do_meijer([], [a - S.Half], [a, b], [a - S.Half], False) assert can_do_meijer([], [a + S.Half], [a + b, a - b, a], [], False) assert can_do_meijer([a + S.Half], [], [b, 2*a - b, a], [], False) # This for example is actually zero. assert can_do_meijer([], [], [], [a, b]) # Testing a bug: assert hyperexpand(meijerg([0, 2], [], [], [-1, 1], z)) == \ Piecewise((0, abs(z) < 1), (z*(1 - 1/z**2)/2, abs(1/z) < 1), (meijerg([0, 2], [], [], [-1, 1], z), True)) # Test that the simplest possible answer is returned: assert gammasimp(simplify(hyperexpand( meijerg([1], [1 - a], [-a/2, -a/2 + S.Half], [], 1/z)))) == \ -2*sqrt(pi)*(sqrt(z + 1) + 1)**a/a # Test that hyper is returned assert hyperexpand(meijerg([1], [], [a], [0, 0], z)) == hyper( (a,), (a + 1, a + 1), z*exp_polar(I*pi))*z**a*gamma(a)/gamma(a + 1)**2 # Test place option f = meijerg(((0, 1), ()), ((S.Half,), (0,)), z**2) assert hyperexpand(f) == sqrt(pi)/sqrt(1 + z**(-2)) assert hyperexpand(f, place=0) == sqrt(pi)*z/sqrt(z**2 + 1) def test_meijerg_lookup(): from sympy import uppergamma, Si, Ci assert hyperexpand(meijerg([a], [], [b, a], [], z)) == \ z**b*exp(z)*gamma(-a + b + 1)*uppergamma(a - b, z) assert hyperexpand(meijerg([0], [], [0, 0], [], z)) == \ exp(z)*uppergamma(0, z) assert can_do_meijer([a], [], [b, a + 1], []) assert can_do_meijer([a], [], [b + 2, a], []) assert can_do_meijer([a], [], [b - 2, a], []) assert hyperexpand(meijerg([a], [], [a, a, a - S.Half], [], z)) == \ -sqrt(pi)*z**(a - S.Half)*(2*cos(2*sqrt(z))*(Si(2*sqrt(z)) - pi/2) - 2*sin(2*sqrt(z))*Ci(2*sqrt(z))) == \ hyperexpand(meijerg([a], [], [a, a - S.Half, a], [], z)) == \ hyperexpand(meijerg([a], [], [a - S.Half, a, a], [], z)) assert can_do_meijer([a - 1], [], [a + 2, a - Rational(3, 2), a + 1], []) @XFAIL def test_meijerg_expand_fail(): # These basically test hyper([], [1/2 - a, 1/2 + 1, 1/2], z), # which is *very* messy. But since the meijer g actually yields a # sum of bessel functions, things can sometimes be simplified a lot and # are then put into tables... assert can_do_meijer([], [], [a + S.Half], [a, a - b/2, a + b/2]) assert can_do_meijer([], [], [0, S.Half], [a, -a]) assert can_do_meijer([], [], [3*a - S.Half, a, -a - S.Half], [a - S.Half]) assert can_do_meijer([], [], [0, a - S.Half, -a - S.Half], [S.Half]) assert can_do_meijer([], [], [a, b + S.Half, b], [2*b - a]) assert can_do_meijer([], [], [a, b + S.Half, b, 2*b - a]) assert can_do_meijer([S.Half], [], [-a, a], [0]) @slow def test_meijerg(): # carefully set up the parameters. # NOTE: this used to fail sometimes. I believe it is fixed, but if you # hit an inexplicable test failure here, please let me know the seed. a1, a2 = (randcplx(n) - 5*I - n*I for n in range(2)) b1, b2 = (randcplx(n) + 5*I + n*I for n in range(2)) b3, b4, b5, a3, a4, a5 = (randcplx() for n in range(6)) g = meijerg([a1], [a3, a4], [b1], [b3, b4], z) assert ReduceOrder.meijer_minus(3, 4) is None assert ReduceOrder.meijer_plus(4, 3) is None g2 = meijerg([a1, a2], [a3, a4], [b1], [b3, b4, a2], z) assert tn(ReduceOrder.meijer_plus(a2, a2).apply(g, op), g2, z) g2 = meijerg([a1, a2], [a3, a4], [b1], [b3, b4, a2 + 1], z) assert tn(ReduceOrder.meijer_plus(a2, a2 + 1).apply(g, op), g2, z) g2 = meijerg([a1, a2 - 1], [a3, a4], [b1], [b3, b4, a2 + 2], z) assert tn(ReduceOrder.meijer_plus(a2 - 1, a2 + 2).apply(g, op), g2, z) g2 = meijerg([a1], [a3, a4, b2 - 1], [b1, b2 + 2], [b3, b4], z) assert tn(ReduceOrder.meijer_minus( b2 + 2, b2 - 1).apply(g, op), g2, z, tol=1e-6) # test several-step reduction an = [a1, a2] bq = [b3, b4, a2 + 1] ap = [a3, a4, b2 - 1] bm = [b1, b2 + 1] niq, ops = reduce_order_meijer(G_Function(an, ap, bm, bq)) assert niq.an == (a1,) assert set(niq.ap) == {a3, a4} assert niq.bm == (b1,) assert set(niq.bq) == {b3, b4} assert tn(apply_operators(g, ops, op), meijerg(an, ap, bm, bq, z), z) def test_meijerg_shift_operators(): # carefully set up the parameters. XXX this still fails sometimes a1, a2, a3, a4, a5, b1, b2, b3, b4, b5 = (randcplx(n) for n in range(10)) g = meijerg([a1], [a3, a4], [b1], [b3, b4], z) assert tn(MeijerShiftA(b1).apply(g, op), meijerg([a1], [a3, a4], [b1 + 1], [b3, b4], z), z) assert tn(MeijerShiftB(a1).apply(g, op), meijerg([a1 - 1], [a3, a4], [b1], [b3, b4], z), z) assert tn(MeijerShiftC(b3).apply(g, op), meijerg([a1], [a3, a4], [b1], [b3 + 1, b4], z), z) assert tn(MeijerShiftD(a3).apply(g, op), meijerg([a1], [a3 - 1, a4], [b1], [b3, b4], z), z) s = MeijerUnShiftA([a1], [a3, a4], [b1], [b3, b4], 0, z) assert tn( s.apply(g, op), meijerg([a1], [a3, a4], [b1 - 1], [b3, b4], z), z) s = MeijerUnShiftC([a1], [a3, a4], [b1], [b3, b4], 0, z) assert tn( s.apply(g, op), meijerg([a1], [a3, a4], [b1], [b3 - 1, b4], z), z) s = MeijerUnShiftB([a1], [a3, a4], [b1], [b3, b4], 0, z) assert tn( s.apply(g, op), meijerg([a1 + 1], [a3, a4], [b1], [b3, b4], z), z) s = MeijerUnShiftD([a1], [a3, a4], [b1], [b3, b4], 0, z) assert tn( s.apply(g, op), meijerg([a1], [a3 + 1, a4], [b1], [b3, b4], z), z) @slow def test_meijerg_confluence(): def t(m, a, b): from sympy import sympify, Piecewise a, b = sympify([a, b]) m_ = m m = hyperexpand(m) if not m == Piecewise((a, abs(z) < 1), (b, abs(1/z) < 1), (m_, True)): return False if not (m.args[0].args[0] == a and m.args[1].args[0] == b): return False z0 = randcplx()/10 if abs(m.subs(z, z0).n() - a.subs(z, z0).n()).n() > 1e-10: return False if abs(m.subs(z, 1/z0).n() - b.subs(z, 1/z0).n()).n() > 1e-10: return False return True assert t(meijerg([], [1, 1], [0, 0], [], z), -log(z), 0) assert t(meijerg( [], [3, 1], [0, 0], [], z), -z**2/4 + z - log(z)/2 - Rational(3, 4), 0) assert t(meijerg([], [3, 1], [-1, 0], [], z), z**2/12 - z/2 + log(z)/2 + Rational(1, 4) + 1/(6*z), 0) assert t(meijerg([], [1, 1, 1, 1], [0, 0, 0, 0], [], z), -log(z)**3/6, 0) assert t(meijerg([1, 1], [], [], [0, 0], z), 0, -log(1/z)) assert t(meijerg([1, 1], [2, 2], [1, 1], [0, 0], z), -z*log(z) + 2*z, -log(1/z) + 2) assert t(meijerg([S.Half], [1, 1], [0, 0], [Rational(3, 2)], z), log(z)/2 - 1, 0) def u(an, ap, bm, bq): m = meijerg(an, ap, bm, bq, z) m2 = hyperexpand(m, allow_hyper=True) if m2.has(meijerg) and not (m2.is_Piecewise and len(m2.args) == 3): return False return tn(m, m2, z) assert u([], [1], [0, 0], []) assert u([1, 1], [], [], [0]) assert u([1, 1], [2, 2, 5], [1, 1, 6], [0, 0]) assert u([1, 1], [2, 2, 5], [1, 1, 6], [0]) def test_meijerg_with_Floats(): # see issue #10681 from sympy import RR f = meijerg(((3.0, 1), ()), ((Rational(3, 2),), (0,)), z) a = -2.3632718012073 g = a*z**Rational(3, 2)*hyper((-0.5, Rational(3, 2)), (Rational(5, 2),), z*exp_polar(I*pi)) assert RR.almosteq((hyperexpand(f)/g).n(), 1.0, 1e-12) def test_lerchphi(): from sympy import gammasimp, exp_polar, polylog, log, lerchphi assert hyperexpand(hyper([1, a], [a + 1], z)/a) == lerchphi(z, 1, a) assert hyperexpand( hyper([1, a, a], [a + 1, a + 1], z)/a**2) == lerchphi(z, 2, a) assert hyperexpand(hyper([1, a, a, a], [a + 1, a + 1, a + 1], z)/a**3) == \ lerchphi(z, 3, a) assert hyperexpand(hyper([1] + [a]*10, [a + 1]*10, z)/a**10) == \ lerchphi(z, 10, a) assert gammasimp(hyperexpand(meijerg([0, 1 - a], [], [0], [-a], exp_polar(-I*pi)*z))) == lerchphi(z, 1, a) assert gammasimp(hyperexpand(meijerg([0, 1 - a, 1 - a], [], [0], [-a, -a], exp_polar(-I*pi)*z))) == lerchphi(z, 2, a) assert gammasimp(hyperexpand(meijerg([0, 1 - a, 1 - a, 1 - a], [], [0], [-a, -a, -a], exp_polar(-I*pi)*z))) == lerchphi(z, 3, a) assert hyperexpand(z*hyper([1, 1], [2], z)) == -log(1 + -z) assert hyperexpand(z*hyper([1, 1, 1], [2, 2], z)) == polylog(2, z) assert hyperexpand(z*hyper([1, 1, 1, 1], [2, 2, 2], z)) == polylog(3, z) assert hyperexpand(hyper([1, a, 1 + S.Half], [a + 1, S.Half], z)) == \ -2*a/(z - 1) + (-2*a**2 + a)*lerchphi(z, 1, a) # Now numerical tests. These make sure reductions etc are carried out # correctly # a rational function (polylog at negative integer order) assert can_do([2, 2, 2], [1, 1]) # NOTE these contain log(1-x) etc ... better make sure we have |z| < 1 # reduction of order for polylog assert can_do([1, 1, 1, b + 5], [2, 2, b], div=10) # reduction of order for lerchphi # XXX lerchphi in mpmath is flaky assert can_do( [1, a, a, a, b + 5], [a + 1, a + 1, a + 1, b], numerical=False) # test a bug from sympy import Abs assert hyperexpand(hyper([S.Half, S.Half, S.Half, 1], [Rational(3, 2), Rational(3, 2), Rational(3, 2)], Rational(1, 4))) == \ Abs(-polylog(3, exp_polar(I*pi)/2) + polylog(3, S.Half)) def test_partial_simp(): # First test that hypergeometric function formulae work. a, b, c, d, e = (randcplx() for _ in range(5)) for func in [Hyper_Function([a, b, c], [d, e]), Hyper_Function([], [a, b, c, d, e])]: f = build_hypergeometric_formula(func) z = f.z assert f.closed_form == func(z) deriv1 = f.B.diff(z)*z deriv2 = f.M*f.B for func1, func2 in zip(deriv1, deriv2): assert tn(func1, func2, z) # Now test that formulae are partially simplified. from sympy.abc import a, b, z assert hyperexpand(hyper([3, a], [1, b], z)) == \ (-a*b/2 + a*z/2 + 2*a)*hyper([a + 1], [b], z) \ + (a*b/2 - 2*a + 1)*hyper([a], [b], z) assert tn( hyperexpand(hyper([3, d], [1, e], z)), hyper([3, d], [1, e], z), z) assert hyperexpand(hyper([3], [1, a, b], z)) == \ hyper((), (a, b), z) \ + z*hyper((), (a + 1, b), z)/(2*a) \ - z*(b - 4)*hyper((), (a + 1, b + 1), z)/(2*a*b) assert tn( hyperexpand(hyper([3], [1, d, e], z)), hyper([3], [1, d, e], z), z) def test_hyperexpand_special(): assert hyperexpand(hyper([a, b], [c], 1)) == \ gamma(c)*gamma(c - a - b)/gamma(c - a)/gamma(c - b) assert hyperexpand(hyper([a, b], [1 + a - b], -1)) == \ gamma(1 + a/2)*gamma(1 + a - b)/gamma(1 + a)/gamma(1 + a/2 - b) assert hyperexpand(hyper([a, b], [1 + b - a], -1)) == \ gamma(1 + b/2)*gamma(1 + b - a)/gamma(1 + b)/gamma(1 + b/2 - a) assert hyperexpand(meijerg([1 - z - a/2], [1 - z + a/2], [b/2], [-b/2], 1)) == \ gamma(1 - 2*z)*gamma(z + a/2 + b/2)/gamma(1 - z + a/2 - b/2) \ /gamma(1 - z - a/2 + b/2)/gamma(1 - z + a/2 + b/2) assert hyperexpand(hyper([a], [b], 0)) == 1 assert hyper([a], [b], 0) != 0 def test_Mod1_behavior(): from sympy import Symbol, simplify, lowergamma n = Symbol('n', integer=True) # Note: this should not hang. assert simplify(hyperexpand(meijerg([1], [], [n + 1], [0], z))) == \ lowergamma(n + 1, z) @slow def test_prudnikov_misc(): assert can_do([1, (3 + I)/2, (3 - I)/2], [Rational(3, 2), 2]) assert can_do([S.Half, a - 1], [Rational(3, 2), a + 1], lowerplane=True) assert can_do([], [b + 1]) assert can_do([a], [a - 1, b + 1]) assert can_do([a], [a - S.Half, 2*a]) assert can_do([a], [a - S.Half, 2*a + 1]) assert can_do([a], [a - S.Half, 2*a - 1]) assert can_do([a], [a + S.Half, 2*a]) assert can_do([a], [a + S.Half, 2*a + 1]) assert can_do([a], [a + S.Half, 2*a - 1]) assert can_do([S.Half], [b, 2 - b]) assert can_do([S.Half], [b, 3 - b]) assert can_do([1], [2, b]) assert can_do([a, a + S.Half], [2*a, b, 2*a - b + 1]) assert can_do([a, a + S.Half], [S.Half, 2*a, 2*a + S.Half]) assert can_do([a], [a + 1], lowerplane=True) # lowergamma def test_prudnikov_1(): # A. P. Prudnikov, Yu. A. Brychkov and O. I. Marichev (1990). # Integrals and Series: More Special Functions, Vol. 3,. # Gordon and Breach Science Publisher # 7.3.1 assert can_do([a, -a], [S.Half]) assert can_do([a, 1 - a], [S.Half]) assert can_do([a, 1 - a], [Rational(3, 2)]) assert can_do([a, 2 - a], [S.Half]) assert can_do([a, 2 - a], [Rational(3, 2)]) assert can_do([a, 2 - a], [Rational(3, 2)]) assert can_do([a, a + S.Half], [2*a - 1]) assert can_do([a, a + S.Half], [2*a]) assert can_do([a, a + S.Half], [2*a + 1]) assert can_do([a, a + S.Half], [S.Half]) assert can_do([a, a + S.Half], [Rational(3, 2)]) assert can_do([a, a/2 + 1], [a/2]) assert can_do([1, b], [2]) assert can_do([1, b], [b + 1], numerical=False) # Lerch Phi # NOTE: branches are complicated for |z| > 1 assert can_do([a], [2*a]) assert can_do([a], [2*a + 1]) assert can_do([a], [2*a - 1]) @slow def test_prudnikov_2(): h = S.Half assert can_do([-h, -h], [h]) assert can_do([-h, h], [3*h]) assert can_do([-h, h], [5*h]) assert can_do([-h, h], [7*h]) assert can_do([-h, 1], [h]) for p in [-h, h]: for n in [-h, h, 1, 3*h, 2, 5*h, 3, 7*h, 4]: for m in [-h, h, 3*h, 5*h, 7*h]: assert can_do([p, n], [m]) for n in [1, 2, 3, 4]: for m in [1, 2, 3, 4]: assert can_do([p, n], [m]) @slow def test_prudnikov_3(): if ON_TRAVIS: # See https://github.com/sympy/sympy/pull/12795 skip("Too slow for travis.") h = S.Half assert can_do([Rational(1, 4), Rational(3, 4)], [h]) assert can_do([Rational(1, 4), Rational(3, 4)], [3*h]) assert can_do([Rational(1, 3), Rational(2, 3)], [3*h]) assert can_do([Rational(3, 4), Rational(5, 4)], [h]) assert can_do([Rational(3, 4), Rational(5, 4)], [3*h]) for p in [1, 2, 3, 4]: for n in [-h, h, 1, 3*h, 2, 5*h, 3, 7*h, 4, 9*h]: for m in [1, 3*h, 2, 5*h, 3, 7*h, 4]: assert can_do([p, m], [n]) @slow def test_prudnikov_4(): h = S.Half for p in [3*h, 5*h, 7*h]: for n in [-h, h, 3*h, 5*h, 7*h]: for m in [3*h, 2, 5*h, 3, 7*h, 4]: assert can_do([p, m], [n]) for n in [1, 2, 3, 4]: for m in [2, 3, 4]: assert can_do([p, m], [n]) @slow def test_prudnikov_5(): h = S.Half for p in [1, 2, 3]: for q in range(p, 4): for r in [1, 2, 3]: for s in range(r, 4): assert can_do([-h, p, q], [r, s]) for p in [h, 1, 3*h, 2, 5*h, 3]: for q in [h, 3*h, 5*h]: for r in [h, 3*h, 5*h]: for s in [h, 3*h, 5*h]: if s <= q and s <= r: assert can_do([-h, p, q], [r, s]) for p in [h, 1, 3*h, 2, 5*h, 3]: for q in [1, 2, 3]: for r in [h, 3*h, 5*h]: for s in [1, 2, 3]: assert can_do([-h, p, q], [r, s]) @slow def test_prudnikov_6(): h = S.Half for m in [3*h, 5*h]: for n in [1, 2, 3]: for q in [h, 1, 2]: for p in [1, 2, 3]: assert can_do([h, q, p], [m, n]) for q in [1, 2, 3]: for p in [3*h, 5*h]: assert can_do([h, q, p], [m, n]) for q in [1, 2]: for p in [1, 2, 3]: for m in [1, 2, 3]: for n in [1, 2, 3]: assert can_do([h, q, p], [m, n]) assert can_do([h, h, 5*h], [3*h, 3*h]) assert can_do([h, 1, 5*h], [3*h, 3*h]) assert can_do([h, 2, 2], [1, 3]) # pages 435 to 457 contain more PFDD and stuff like this @slow def test_prudnikov_7(): assert can_do([3], [6]) h = S.Half for n in [h, 3*h, 5*h, 7*h]: assert can_do([-h], [n]) for m in [-h, h, 1, 3*h, 2, 5*h, 3, 7*h, 4]: # HERE for n in [-h, h, 3*h, 5*h, 7*h, 1, 2, 3, 4]: assert can_do([m], [n]) @slow def test_prudnikov_8(): h = S.Half # 7.12.2 for ai in [1, 2, 3]: for bi in [1, 2, 3]: for ci in range(1, ai + 1): for di in [h, 1, 3*h, 2, 5*h, 3]: assert can_do([ai, bi], [ci, di]) for bi in [3*h, 5*h]: for ci in [h, 1, 3*h, 2, 5*h, 3]: for di in [1, 2, 3]: assert can_do([ai, bi], [ci, di]) for ai in [-h, h, 3*h, 5*h]: for bi in [1, 2, 3]: for ci in [h, 1, 3*h, 2, 5*h, 3]: for di in [1, 2, 3]: assert can_do([ai, bi], [ci, di]) for bi in [h, 3*h, 5*h]: for ci in [h, 3*h, 5*h, 3]: for di in [h, 1, 3*h, 2, 5*h, 3]: if ci <= bi: assert can_do([ai, bi], [ci, di]) def test_prudnikov_9(): # 7.13.1 [we have a general formula ... so this is a bit pointless] for i in range(9): assert can_do([], [(S(i) + 1)/2]) for i in range(5): assert can_do([], [-(2*S(i) + 1)/2]) @slow def test_prudnikov_10(): # 7.14.2 h = S.Half for p in [-h, h, 1, 3*h, 2, 5*h, 3, 7*h, 4]: for m in [1, 2, 3, 4]: for n in range(m, 5): assert can_do([p], [m, n]) for p in [1, 2, 3, 4]: for n in [h, 3*h, 5*h, 7*h]: for m in [1, 2, 3, 4]: assert can_do([p], [n, m]) for p in [3*h, 5*h, 7*h]: for m in [h, 1, 2, 5*h, 3, 7*h, 4]: assert can_do([p], [h, m]) assert can_do([p], [3*h, m]) for m in [h, 1, 2, 5*h, 3, 7*h, 4]: assert can_do([7*h], [5*h, m]) assert can_do([Rational(-1, 2)], [S.Half, S.Half]) # shine-integral shi def test_prudnikov_11(): # 7.15 assert can_do([a, a + S.Half], [2*a, b, 2*a - b]) assert can_do([a, a + S.Half], [Rational(3, 2), 2*a, 2*a - S.Half]) assert can_do([Rational(1, 4), Rational(3, 4)], [S.Half, S.Half, 1]) assert can_do([Rational(5, 4), Rational(3, 4)], [Rational(3, 2), S.Half, 2]) assert can_do([Rational(5, 4), Rational(3, 4)], [Rational(3, 2), Rational(3, 2), 1]) assert can_do([Rational(5, 4), Rational(7, 4)], [Rational(3, 2), Rational(5, 2), 2]) assert can_do([1, 1], [Rational(3, 2), 2, 2]) # cosh-integral chi def test_prudnikov_12(): # 7.16 assert can_do( [], [a, a + S.Half, 2*a], False) # branches only agree for some z! assert can_do([], [a, a + S.Half, 2*a + 1], False) # dito assert can_do([], [S.Half, a, a + S.Half]) assert can_do([], [Rational(3, 2), a, a + S.Half]) assert can_do([], [Rational(1, 4), S.Half, Rational(3, 4)]) assert can_do([], [S.Half, S.Half, 1]) assert can_do([], [S.Half, Rational(3, 2), 1]) assert can_do([], [Rational(3, 4), Rational(3, 2), Rational(5, 4)]) assert can_do([], [1, 1, Rational(3, 2)]) assert can_do([], [1, 2, Rational(3, 2)]) assert can_do([], [1, Rational(3, 2), Rational(3, 2)]) assert can_do([], [Rational(5, 4), Rational(3, 2), Rational(7, 4)]) assert can_do([], [2, Rational(3, 2), Rational(3, 2)]) @slow def test_prudnikov_2F1(): h = S.Half # Elliptic integrals for p in [-h, h]: for m in [h, 3*h, 5*h, 7*h]: for n in [1, 2, 3, 4]: assert can_do([p, m], [n]) @XFAIL def test_prudnikov_fail_2F1(): assert can_do([a, b], [b + 1]) # incomplete beta function assert can_do([-1, b], [c]) # Poly. also -2, -3 etc # TODO polys # Legendre functions: assert can_do([a, b], [a + b + S.Half]) assert can_do([a, b], [a + b - S.Half]) assert can_do([a, b], [a + b + Rational(3, 2)]) assert can_do([a, b], [(a + b + 1)/2]) assert can_do([a, b], [(a + b)/2 + 1]) assert can_do([a, b], [a - b + 1]) assert can_do([a, b], [a - b + 2]) assert can_do([a, b], [2*b]) assert can_do([a, b], [S.Half]) assert can_do([a, b], [Rational(3, 2)]) assert can_do([a, 1 - a], [c]) assert can_do([a, 2 - a], [c]) assert can_do([a, 3 - a], [c]) assert can_do([a, a + S.Half], [c]) assert can_do([1, b], [c]) assert can_do([1, b], [Rational(3, 2)]) assert can_do([Rational(1, 4), Rational(3, 4)], [1]) # PFDD o = S.One assert can_do([o/8, 1], [o/8*9]) assert can_do([o/6, 1], [o/6*7]) assert can_do([o/6, 1], [o/6*13]) assert can_do([o/5, 1], [o/5*6]) assert can_do([o/5, 1], [o/5*11]) assert can_do([o/4, 1], [o/4*5]) assert can_do([o/4, 1], [o/4*9]) assert can_do([o/3, 1], [o/3*4]) assert can_do([o/3, 1], [o/3*7]) assert can_do([o/8*3, 1], [o/8*11]) assert can_do([o/5*2, 1], [o/5*7]) assert can_do([o/5*2, 1], [o/5*12]) assert can_do([o/5*3, 1], [o/5*8]) assert can_do([o/5*3, 1], [o/5*13]) assert can_do([o/8*5, 1], [o/8*13]) assert can_do([o/4*3, 1], [o/4*7]) assert can_do([o/4*3, 1], [o/4*11]) assert can_do([o/3*2, 1], [o/3*5]) assert can_do([o/3*2, 1], [o/3*8]) assert can_do([o/5*4, 1], [o/5*9]) assert can_do([o/5*4, 1], [o/5*14]) assert can_do([o/6*5, 1], [o/6*11]) assert can_do([o/6*5, 1], [o/6*17]) assert can_do([o/8*7, 1], [o/8*15]) @XFAIL def test_prudnikov_fail_3F2(): assert can_do([a, a + Rational(1, 3), a + Rational(2, 3)], [Rational(1, 3), Rational(2, 3)]) assert can_do([a, a + Rational(1, 3), a + Rational(2, 3)], [Rational(2, 3), Rational(4, 3)]) assert can_do([a, a + Rational(1, 3), a + Rational(2, 3)], [Rational(4, 3), Rational(5, 3)]) # page 421 assert can_do([a, a + Rational(1, 3), a + Rational(2, 3)], [a*Rational(3, 2), (3*a + 1)/2]) # pages 422 ... assert can_do([Rational(-1, 2), S.Half, S.Half], [1, 1]) # elliptic integrals assert can_do([Rational(-1, 2), S.Half, 1], [Rational(3, 2), Rational(3, 2)]) # TODO LOTS more # PFDD assert can_do([Rational(1, 8), Rational(3, 8), 1], [Rational(9, 8), Rational(11, 8)]) assert can_do([Rational(1, 8), Rational(5, 8), 1], [Rational(9, 8), Rational(13, 8)]) assert can_do([Rational(1, 8), Rational(7, 8), 1], [Rational(9, 8), Rational(15, 8)]) assert can_do([Rational(1, 6), Rational(1, 3), 1], [Rational(7, 6), Rational(4, 3)]) assert can_do([Rational(1, 6), Rational(2, 3), 1], [Rational(7, 6), Rational(5, 3)]) assert can_do([Rational(1, 6), Rational(2, 3), 1], [Rational(5, 3), Rational(13, 6)]) assert can_do([S.Half, 1, 1], [Rational(1, 4), Rational(3, 4)]) # LOTS more @XFAIL def test_prudnikov_fail_other(): # 7.11.2 # 7.12.1 assert can_do([1, a], [b, 1 - 2*a + b]) # ??? # 7.14.2 assert can_do([Rational(-1, 2)], [S.Half, 1]) # struve assert can_do([1], [S.Half, S.Half]) # struve assert can_do([Rational(1, 4)], [S.Half, Rational(5, 4)]) # PFDD assert can_do([Rational(3, 4)], [Rational(3, 2), Rational(7, 4)]) # PFDD assert can_do([1], [Rational(1, 4), Rational(3, 4)]) # PFDD assert can_do([1], [Rational(3, 4), Rational(5, 4)]) # PFDD assert can_do([1], [Rational(5, 4), Rational(7, 4)]) # PFDD # TODO LOTS more # 7.15.2 assert can_do([S.Half, 1], [Rational(3, 4), Rational(5, 4), Rational(3, 2)]) # PFDD assert can_do([S.Half, 1], [Rational(7, 4), Rational(5, 4), Rational(3, 2)]) # PFDD # 7.16.1 assert can_do([], [Rational(1, 3), S(2/3)]) # PFDD assert can_do([], [Rational(2, 3), S(4/3)]) # PFDD assert can_do([], [Rational(5, 3), S(4/3)]) # PFDD # XXX this does not *evaluate* right?? assert can_do([], [a, a + S.Half, 2*a - 1]) def test_bug(): h = hyper([-1, 1], [z], -1) assert hyperexpand(h) == (z + 1)/z def test_omgissue_203(): h = hyper((-5, -3, -4), (-6, -6), 1) assert hyperexpand(h) == Rational(1, 30) h = hyper((-6, -7, -5), (-6, -6), 1) assert hyperexpand(h) == Rational(-1, 6) sympy-sympy-1.9/sympy/simplify/tests/test_powsimp.py000066400000000000000000000321361412543434000232160ustar00rootroot00000000000000from sympy import ( symbols, powsimp, MatrixSymbol, sqrt, pi, Mul, gamma, Function, S, I, exp, simplify, sin, E, log, hyper, Symbol, Dummy, powdenest, root, Rational, oo, signsimp) from sympy.core.symbol import Str from sympy.abc import x, y, z, a, b def test_powsimp(): x, y, z, n = symbols('x,y,z,n') f = Function('f') assert powsimp( 4**x * 2**(-x) * 2**(-x) ) == 1 assert powsimp( (-4)**x * (-2)**(-x) * 2**(-x) ) == 1 assert powsimp( f(4**x * 2**(-x) * 2**(-x)) ) == f(4**x * 2**(-x) * 2**(-x)) assert powsimp( f(4**x * 2**(-x) * 2**(-x)), deep=True ) == f(1) assert exp(x)*exp(y) == exp(x)*exp(y) assert powsimp(exp(x)*exp(y)) == exp(x + y) assert powsimp(exp(x)*exp(y)*2**x*2**y) == (2*E)**(x + y) assert powsimp(exp(x)*exp(y)*2**x*2**y, combine='exp') == \ exp(x + y)*2**(x + y) assert powsimp(exp(x)*exp(y)*exp(2)*sin(x) + sin(y) + 2**x*2**y) == \ exp(2 + x + y)*sin(x) + sin(y) + 2**(x + y) assert powsimp(sin(exp(x)*exp(y))) == sin(exp(x)*exp(y)) assert powsimp(sin(exp(x)*exp(y)), deep=True) == sin(exp(x + y)) assert powsimp(x**2*x**y) == x**(2 + y) # This should remain factored, because 'exp' with deep=True is supposed # to act like old automatic exponent combining. assert powsimp((1 + E*exp(E))*exp(-E), combine='exp', deep=True) == \ (1 + exp(1 + E))*exp(-E) assert powsimp((1 + E*exp(E))*exp(-E), deep=True) == \ (1 + exp(1 + E))*exp(-E) assert powsimp((1 + E*exp(E))*exp(-E)) == (1 + exp(1 + E))*exp(-E) assert powsimp((1 + E*exp(E))*exp(-E), combine='exp') == \ (1 + exp(1 + E))*exp(-E) assert powsimp((1 + E*exp(E))*exp(-E), combine='base') == \ (1 + E*exp(E))*exp(-E) x, y = symbols('x,y', nonnegative=True) n = Symbol('n', real=True) assert powsimp(y**n * (y/x)**(-n)) == x**n assert powsimp(x**(x**(x*y)*y**(x*y))*y**(x**(x*y)*y**(x*y)), deep=True) \ == (x*y)**(x*y)**(x*y) assert powsimp(2**(2**(2*x)*x), deep=False) == 2**(2**(2*x)*x) assert powsimp(2**(2**(2*x)*x), deep=True) == 2**(x*4**x) assert powsimp( exp(-x + exp(-x)*exp(-x*log(x))), deep=False, combine='exp') == \ exp(-x + exp(-x)*exp(-x*log(x))) assert powsimp( exp(-x + exp(-x)*exp(-x*log(x))), deep=False, combine='exp') == \ exp(-x + exp(-x)*exp(-x*log(x))) assert powsimp((x + y)/(3*z), deep=False, combine='exp') == (x + y)/(3*z) assert powsimp((x/3 + y/3)/z, deep=True, combine='exp') == (x/3 + y/3)/z assert powsimp(exp(x)/(1 + exp(x)*exp(y)), deep=True) == \ exp(x)/(1 + exp(x + y)) assert powsimp(x*y**(z**x*z**y), deep=True) == x*y**(z**(x + y)) assert powsimp((z**x*z**y)**x, deep=True) == (z**(x + y))**x assert powsimp(x*(z**x*z**y)**x, deep=True) == x*(z**(x + y))**x p = symbols('p', positive=True) assert powsimp((1/x)**log(2)/x) == (1/x)**(1 + log(2)) assert powsimp((1/p)**log(2)/p) == p**(-1 - log(2)) # coefficient of exponent can only be simplified for positive bases assert powsimp(2**(2*x)) == 4**x assert powsimp((-1)**(2*x)) == (-1)**(2*x) i = symbols('i', integer=True) assert powsimp((-1)**(2*i)) == 1 assert powsimp((-1)**(-x)) != (-1)**x # could be 1/((-1)**x), but is not # force=True overrides assumptions assert powsimp((-1)**(2*x), force=True) == 1 # rational exponents allow combining of negative terms w, n, m = symbols('w n m', negative=True) e = i/a # not a rational exponent if `a` is unknown ex = w**e*n**e*m**e assert powsimp(ex) == m**(i/a)*n**(i/a)*w**(i/a) e = i/3 ex = w**e*n**e*m**e assert powsimp(ex) == (-1)**i*(-m*n*w)**(i/3) e = (3 + i)/i ex = w**e*n**e*m**e assert powsimp(ex) == (-1)**(3*e)*(-m*n*w)**e eq = x**(a*Rational(2, 3)) # eq != (x**a)**(2/3) (try x = -1 and a = 3 to see) assert powsimp(eq).exp == eq.exp == a*Rational(2, 3) # powdenest goes the other direction assert powsimp(2**(2*x)) == 4**x assert powsimp(exp(p/2)) == exp(p/2) # issue 6368 eq = Mul(*[sqrt(Dummy(imaginary=True)) for i in range(3)]) assert powsimp(eq) == eq and eq.is_Mul assert all(powsimp(e) == e for e in (sqrt(x**a), sqrt(x**2))) # issue 8836 assert str( powsimp(exp(I*pi/3)*root(-1,3)) ) == '(-1)**(2/3)' # issue 9183 assert powsimp(-0.1**x) == -0.1**x # issue 10095 assert powsimp((1/(2*E))**oo) == (exp(-1)/2)**oo # PR 13131 eq = sin(2*x)**2*sin(2.0*x)**2 assert powsimp(eq) == eq # issue 14615 assert powsimp(x**2*y**3*(x*y**2)**Rational(3, 2) ) == x*y*(x*y**2)**Rational(5, 2) def test_powsimp_negated_base(): assert powsimp((-x + y)/sqrt(x - y)) == -sqrt(x - y) assert powsimp((-x + y)*(-z + y)/sqrt(x - y)/sqrt(z - y)) == sqrt(x - y)*sqrt(z - y) p = symbols('p', positive=True) reps = {p: 2, a: S.Half} assert powsimp((-p)**a/p**a).subs(reps) == ((-1)**a).subs(reps) assert powsimp((-p)**a*p**a).subs(reps) == ((-p**2)**a).subs(reps) n = symbols('n', negative=True) reps = {p: -2, a: S.Half} assert powsimp((-n)**a/n**a).subs(reps) == (-1)**(-a).subs(a, S.Half) assert powsimp((-n)**a*n**a).subs(reps) == ((-n**2)**a).subs(reps) # if x is 0 then the lhs is 0**a*oo**a which is not (-1)**a eq = (-x)**a/x**a assert powsimp(eq) == eq def test_powsimp_nc(): x, y, z = symbols('x,y,z') A, B, C = symbols('A B C', commutative=False) assert powsimp(A**x*A**y, combine='all') == A**(x + y) assert powsimp(A**x*A**y, combine='base') == A**x*A**y assert powsimp(A**x*A**y, combine='exp') == A**(x + y) assert powsimp(A**x*B**x, combine='all') == A**x*B**x assert powsimp(A**x*B**x, combine='base') == A**x*B**x assert powsimp(A**x*B**x, combine='exp') == A**x*B**x assert powsimp(B**x*A**x, combine='all') == B**x*A**x assert powsimp(B**x*A**x, combine='base') == B**x*A**x assert powsimp(B**x*A**x, combine='exp') == B**x*A**x assert powsimp(A**x*A**y*A**z, combine='all') == A**(x + y + z) assert powsimp(A**x*A**y*A**z, combine='base') == A**x*A**y*A**z assert powsimp(A**x*A**y*A**z, combine='exp') == A**(x + y + z) assert powsimp(A**x*B**x*C**x, combine='all') == A**x*B**x*C**x assert powsimp(A**x*B**x*C**x, combine='base') == A**x*B**x*C**x assert powsimp(A**x*B**x*C**x, combine='exp') == A**x*B**x*C**x assert powsimp(B**x*A**x*C**x, combine='all') == B**x*A**x*C**x assert powsimp(B**x*A**x*C**x, combine='base') == B**x*A**x*C**x assert powsimp(B**x*A**x*C**x, combine='exp') == B**x*A**x*C**x def test_issue_6440(): assert powsimp(16*2**a*8**b) == 2**(a + 3*b + 4) def test_powdenest(): from sympy import powdenest from sympy.abc import x, y, z, a, b p, q = symbols('p q', positive=True) i, j = symbols('i,j', integer=True) assert powdenest(x) == x assert powdenest(x + 2*(x**(a*Rational(2, 3)))**(3*x)) == (x + 2*(x**(a*Rational(2, 3)))**(3*x)) assert powdenest((exp(a*Rational(2, 3)))**(3*x)) # -X-> (exp(a/3))**(6*x) assert powdenest((x**(a*Rational(2, 3)))**(3*x)) == ((x**(a*Rational(2, 3)))**(3*x)) assert powdenest(exp(3*x*log(2))) == 2**(3*x) assert powdenest(sqrt(p**2)) == p eq = p**(2*i)*q**(4*i) assert powdenest(eq) == (p*q**2)**(2*i) # -X-> (x**x)**i*(x**x)**j == x**(x*(i + j)) assert powdenest((x**x)**(i + j)) assert powdenest(exp(3*y*log(x))) == x**(3*y) assert powdenest(exp(y*(log(a) + log(b)))) == (a*b)**y assert powdenest(exp(3*(log(a) + log(b)))) == a**3*b**3 assert powdenest(((x**(2*i))**(3*y))**x) == ((x**(2*i))**(3*y))**x assert powdenest(((x**(2*i))**(3*y))**x, force=True) == x**(6*i*x*y) assert powdenest(((x**(a*Rational(2, 3)))**(3*y/i))**x) == \ (((x**(a*Rational(2, 3)))**(3*y/i))**x) assert powdenest((x**(2*i)*y**(4*i))**z, force=True) == (x*y**2)**(2*i*z) assert powdenest((p**(2*i)*q**(4*i))**j) == (p*q**2)**(2*i*j) e = ((p**(2*a))**(3*y))**x assert powdenest(e) == e e = ((x**2*y**4)**a)**(x*y) assert powdenest(e) == e e = (((x**2*y**4)**a)**(x*y))**3 assert powdenest(e) == ((x**2*y**4)**a)**(3*x*y) assert powdenest((((x**2*y**4)**a)**(x*y)), force=True) == \ (x*y**2)**(2*a*x*y) assert powdenest((((x**2*y**4)**a)**(x*y))**3, force=True) == \ (x*y**2)**(6*a*x*y) assert powdenest((x**2*y**6)**i) != (x*y**3)**(2*i) x, y = symbols('x,y', positive=True) assert powdenest((x**2*y**6)**i) == (x*y**3)**(2*i) assert powdenest((x**(i*Rational(2, 3))*y**(i/2))**(2*i)) == (x**Rational(4, 3)*y)**(i**2) assert powdenest(sqrt(x**(2*i)*y**(6*i))) == (x*y**3)**i assert powdenest(4**x) == 2**(2*x) assert powdenest((4**x)**y) == 2**(2*x*y) assert powdenest(4**x*y) == 2**(2*x)*y def test_powdenest_polar(): x, y, z = symbols('x y z', polar=True) a, b, c = symbols('a b c') assert powdenest((x*y*z)**a) == x**a*y**a*z**a assert powdenest((x**a*y**b)**c) == x**(a*c)*y**(b*c) assert powdenest(((x**a)**b*y**c)**c) == x**(a*b*c)*y**(c**2) def test_issue_5805(): arg = ((gamma(x)*hyper((), (), x))*pi)**2 assert powdenest(arg) == (pi*gamma(x)*hyper((), (), x))**2 assert arg.is_positive is None def test_issue_9324_powsimp_on_matrix_symbol(): M = MatrixSymbol('M', 10, 10) expr = powsimp(M, deep=True) assert expr == M assert expr.args[0] == Str('M') def test_issue_6367(): z = -5*sqrt(2)/(2*sqrt(2*sqrt(29) + 29)) + sqrt(-sqrt(29)/29 + S.Half) assert Mul(*[powsimp(a) for a in Mul.make_args(z.normal())]) == 0 assert powsimp(z.normal()) == 0 assert simplify(z) == 0 assert powsimp(sqrt(2 + sqrt(3))*sqrt(2 - sqrt(3)) + 1) == 2 assert powsimp(z) != 0 def test_powsimp_polar(): from sympy import polar_lift, exp_polar x, y, z = symbols('x y z') p, q, r = symbols('p q r', polar=True) assert (polar_lift(-1))**(2*x) == exp_polar(2*pi*I*x) assert powsimp(p**x * q**x) == (p*q)**x assert p**x * (1/p)**x == 1 assert (1/p)**x == p**(-x) assert exp_polar(x)*exp_polar(y) == exp_polar(x)*exp_polar(y) assert powsimp(exp_polar(x)*exp_polar(y)) == exp_polar(x + y) assert powsimp(exp_polar(x)*exp_polar(y)*p**x*p**y) == \ (p*exp_polar(1))**(x + y) assert powsimp(exp_polar(x)*exp_polar(y)*p**x*p**y, combine='exp') == \ exp_polar(x + y)*p**(x + y) assert powsimp( exp_polar(x)*exp_polar(y)*exp_polar(2)*sin(x) + sin(y) + p**x*p**y) \ == p**(x + y) + sin(x)*exp_polar(2 + x + y) + sin(y) assert powsimp(sin(exp_polar(x)*exp_polar(y))) == \ sin(exp_polar(x)*exp_polar(y)) assert powsimp(sin(exp_polar(x)*exp_polar(y)), deep=True) == \ sin(exp_polar(x + y)) def test_issue_5728(): b = x*sqrt(y) a = sqrt(b) c = sqrt(sqrt(x)*y) assert powsimp(a*b) == sqrt(b)**3 assert powsimp(a*b**2*sqrt(y)) == sqrt(y)*a**5 assert powsimp(a*x**2*c**3*y) == c**3*a**5 assert powsimp(a*x*c**3*y**2) == c**7*a assert powsimp(x*c**3*y**2) == c**7 assert powsimp(x*c**3*y) == x*y*c**3 assert powsimp(sqrt(x)*c**3*y) == c**5 assert powsimp(sqrt(x)*a**3*sqrt(y)) == sqrt(x)*sqrt(y)*a**3 assert powsimp(Mul(sqrt(x)*c**3*sqrt(y), y, evaluate=False)) == \ sqrt(x)*sqrt(y)**3*c**3 assert powsimp(a**2*a*x**2*y) == a**7 # symbolic powers work, too b = x**y*y a = b*sqrt(b) assert a.is_Mul is True assert powsimp(a) == sqrt(b)**3 # as does exp a = x*exp(y*Rational(2, 3)) assert powsimp(a*sqrt(a)) == sqrt(a)**3 assert powsimp(a**2*sqrt(a)) == sqrt(a)**5 assert powsimp(a**2*sqrt(sqrt(a))) == sqrt(sqrt(a))**9 def test_issue_from_PR1599(): n1, n2, n3, n4 = symbols('n1 n2 n3 n4', negative=True) assert (powsimp(sqrt(n1)*sqrt(n2)*sqrt(n3)) == -I*sqrt(-n1)*sqrt(-n2)*sqrt(-n3)) assert (powsimp(root(n1, 3)*root(n2, 3)*root(n3, 3)*root(n4, 3)) == -(-1)**Rational(1, 3)* (-n1)**Rational(1, 3)*(-n2)**Rational(1, 3)*(-n3)**Rational(1, 3)*(-n4)**Rational(1, 3)) def test_issue_10195(): a = Symbol('a', integer=True) l = Symbol('l', even=True, nonzero=True) n = Symbol('n', odd=True) e_x = (-1)**(n/2 - S.Half) - (-1)**(n*Rational(3, 2) - S.Half) assert powsimp((-1)**(l/2)) == I**l assert powsimp((-1)**(n/2)) == I**n assert powsimp((-1)**(n*Rational(3, 2))) == -I**n assert powsimp(e_x) == (-1)**(n/2 - S.Half) + (-1)**(n*Rational(3, 2) + S.Half) assert powsimp((-1)**(a*Rational(3, 2))) == (-I)**a def test_issue_15709(): assert powsimp(3**x*Rational(2, 3)) == 2*3**(x-1) assert powsimp(2*3**x/3) == 2*3**(x-1) def test_issue_11981(): x, y = symbols('x y', commutative=False) assert powsimp((x*y)**2 * (y*x)**2) == (x*y)**2 * (y*x)**2 def test_issue_17524(): a = symbols("a", real=True) e = (-1 - a**2)*sqrt(1 + a**2) assert signsimp(powsimp(e)) == signsimp(e) == -(a**2 + 1)**(S(3)/2) def test_issue_19627(): # if you use force the user must verify assert powdenest(sqrt(sin(x)**2), force=True) == sin(x) assert powdenest((x**(S.Half/y))**(2*y), force=True) == x from sympy import expand_power_base e = 1 - a expr = (exp(z/e)*x**(b/e)*y**((1 - b)/e))**e assert powdenest(expand_power_base(expr, force=True), force=True ) == x**b*y**(1 - b)*exp(z) sympy-sympy-1.9/sympy/simplify/tests/test_radsimp.py000066400000000000000000000430711412543434000231570ustar00rootroot00000000000000from sympy import ( sqrt, Derivative, symbols, collect, Function, factor, Wild, S, collect_const, log, fraction, I, cos, Add, O,sin, rcollect, Mul, Pow, radsimp, diff, root, Symbol, Rational, exp, Abs) from sympy.core.expr import unchanged from sympy.core.mul import _unevaluated_Mul as umul from sympy.simplify.radsimp import (_unevaluated_Add, collect_sqrt, fraction_expand, collect_abs) from sympy.testing.pytest import raises from sympy.abc import x, y, z, a, b, c, d def test_radsimp(): r2 = sqrt(2) r3 = sqrt(3) r5 = sqrt(5) r7 = sqrt(7) assert fraction(radsimp(1/r2)) == (sqrt(2), 2) assert radsimp(1/(1 + r2)) == \ -1 + sqrt(2) assert radsimp(1/(r2 + r3)) == \ -sqrt(2) + sqrt(3) assert fraction(radsimp(1/(1 + r2 + r3))) == \ (-sqrt(6) + sqrt(2) + 2, 4) assert fraction(radsimp(1/(r2 + r3 + r5))) == \ (-sqrt(30) + 2*sqrt(3) + 3*sqrt(2), 12) assert fraction(radsimp(1/(1 + r2 + r3 + r5))) == ( (-34*sqrt(10) - 26*sqrt(15) - 55*sqrt(3) - 61*sqrt(2) + 14*sqrt(30) + 93 + 46*sqrt(6) + 53*sqrt(5), 71)) assert fraction(radsimp(1/(r2 + r3 + r5 + r7))) == ( (-50*sqrt(42) - 133*sqrt(5) - 34*sqrt(70) - 145*sqrt(3) + 22*sqrt(105) + 185*sqrt(2) + 62*sqrt(30) + 135*sqrt(7), 215)) z = radsimp(1/(1 + r2/3 + r3/5 + r5 + r7)) assert len((3616791619821680643598*z).args) == 16 assert radsimp(1/z) == 1/z assert radsimp(1/z, max_terms=20).expand() == 1 + r2/3 + r3/5 + r5 + r7 assert radsimp(1/(r2*3)) == \ sqrt(2)/6 assert radsimp(1/(r2*a + r3 + r5 + r7)) == ( (8*sqrt(2)*a**7 - 8*sqrt(7)*a**6 - 8*sqrt(5)*a**6 - 8*sqrt(3)*a**6 - 180*sqrt(2)*a**5 + 8*sqrt(30)*a**5 + 8*sqrt(42)*a**5 + 8*sqrt(70)*a**5 - 24*sqrt(105)*a**4 + 84*sqrt(3)*a**4 + 100*sqrt(5)*a**4 + 116*sqrt(7)*a**4 - 72*sqrt(70)*a**3 - 40*sqrt(42)*a**3 - 8*sqrt(30)*a**3 + 782*sqrt(2)*a**3 - 462*sqrt(3)*a**2 - 302*sqrt(7)*a**2 - 254*sqrt(5)*a**2 + 120*sqrt(105)*a**2 - 795*sqrt(2)*a - 62*sqrt(30)*a + 82*sqrt(42)*a + 98*sqrt(70)*a - 118*sqrt(105) + 59*sqrt(7) + 295*sqrt(5) + 531*sqrt(3))/(16*a**8 - 480*a**6 + 3128*a**4 - 6360*a**2 + 3481)) assert radsimp(1/(r2*a + r2*b + r3 + r7)) == ( (sqrt(2)*a*(a + b)**2 - 5*sqrt(2)*a + sqrt(42)*a + sqrt(2)*b*(a + b)**2 - 5*sqrt(2)*b + sqrt(42)*b - sqrt(7)*(a + b)**2 - sqrt(3)*(a + b)**2 - 2*sqrt(3) + 2*sqrt(7))/(2*a**4 + 8*a**3*b + 12*a**2*b**2 - 20*a**2 + 8*a*b**3 - 40*a*b + 2*b**4 - 20*b**2 + 8)) assert radsimp(1/(r2*a + r2*b + r2*c + r2*d)) == \ sqrt(2)/(2*a + 2*b + 2*c + 2*d) assert radsimp(1/(1 + r2*a + r2*b + r2*c + r2*d)) == ( (sqrt(2)*a + sqrt(2)*b + sqrt(2)*c + sqrt(2)*d - 1)/(2*a**2 + 4*a*b + 4*a*c + 4*a*d + 2*b**2 + 4*b*c + 4*b*d + 2*c**2 + 4*c*d + 2*d**2 - 1)) assert radsimp((y**2 - x)/(y - sqrt(x))) == \ sqrt(x) + y assert radsimp(-(y**2 - x)/(y - sqrt(x))) == \ -(sqrt(x) + y) assert radsimp(1/(1 - I + a*I)) == \ (-I*a + 1 + I)/(a**2 - 2*a + 2) assert radsimp(1/((-x + y)*(x - sqrt(y)))) == \ (-x - sqrt(y))/((x - y)*(x**2 - y)) e = (3 + 3*sqrt(2))*x*(3*x - 3*sqrt(y)) assert radsimp(e) == x*(3 + 3*sqrt(2))*(3*x - 3*sqrt(y)) assert radsimp(1/e) == ( (-9*x + 9*sqrt(2)*x - 9*sqrt(y) + 9*sqrt(2)*sqrt(y))/(9*x*(9*x**2 - 9*y))) assert radsimp(1 + 1/(1 + sqrt(3))) == \ Mul(S.Half, -1 + sqrt(3), evaluate=False) + 1 A = symbols("A", commutative=False) assert radsimp(x**2 + sqrt(2)*x**2 - sqrt(2)*x*A) == \ x**2 + sqrt(2)*x**2 - sqrt(2)*x*A assert radsimp(1/sqrt(5 + 2 * sqrt(6))) == -sqrt(2) + sqrt(3) assert radsimp(1/sqrt(5 + 2 * sqrt(6))**3) == -(-sqrt(3) + sqrt(2))**3 # issue 6532 assert fraction(radsimp(1/sqrt(x))) == (sqrt(x), x) assert fraction(radsimp(1/sqrt(2*x + 3))) == (sqrt(2*x + 3), 2*x + 3) assert fraction(radsimp(1/sqrt(2*(x + 3)))) == (sqrt(2*x + 6), 2*x + 6) # issue 5994 e = S('-(2 + 2*sqrt(2) + 4*2**(1/4))/' '(1 + 2**(3/4) + 3*2**(1/4) + 3*sqrt(2))') assert radsimp(e).expand() == -2*2**Rational(3, 4) - 2*2**Rational(1, 4) + 2 + 2*sqrt(2) # issue 5986 (modifications to radimp didn't initially recognize this so # the test is included here) assert radsimp(1/(-sqrt(5)/2 - S.Half + (-sqrt(5)/2 - S.Half)**2)) == 1 # from issue 5934 eq = ( (-240*sqrt(2)*sqrt(sqrt(5) + 5)*sqrt(8*sqrt(5) + 40) - 360*sqrt(2)*sqrt(-8*sqrt(5) + 40)*sqrt(-sqrt(5) + 5) - 120*sqrt(10)*sqrt(-8*sqrt(5) + 40)*sqrt(-sqrt(5) + 5) + 120*sqrt(2)*sqrt(-sqrt(5) + 5)*sqrt(8*sqrt(5) + 40) + 120*sqrt(2)*sqrt(-8*sqrt(5) + 40)*sqrt(sqrt(5) + 5) + 120*sqrt(10)*sqrt(-sqrt(5) + 5)*sqrt(8*sqrt(5) + 40) + 120*sqrt(10)*sqrt(-8*sqrt(5) + 40)*sqrt(sqrt(5) + 5))/(-36000 - 7200*sqrt(5) + (12*sqrt(10)*sqrt(sqrt(5) + 5) + 24*sqrt(10)*sqrt(-sqrt(5) + 5))**2)) assert radsimp(eq) is S.NaN # it's 0/0 # work with normal form e = 1/sqrt(sqrt(7)/7 + 2*sqrt(2) + 3*sqrt(3) + 5*sqrt(5)) + 3 assert radsimp(e) == ( -sqrt(sqrt(7) + 14*sqrt(2) + 21*sqrt(3) + 35*sqrt(5))*(-11654899*sqrt(35) - 1577436*sqrt(210) - 1278438*sqrt(15) - 1346996*sqrt(10) + 1635060*sqrt(6) + 5709765 + 7539830*sqrt(14) + 8291415*sqrt(21))/1300423175 + 3) # obey power rules base = sqrt(3) - sqrt(2) assert radsimp(1/base**3) == (sqrt(3) + sqrt(2))**3 assert radsimp(1/(-base)**3) == -(sqrt(2) + sqrt(3))**3 assert radsimp(1/(-base)**x) == (-base)**(-x) assert radsimp(1/base**x) == (sqrt(2) + sqrt(3))**x assert radsimp(root(1/(-1 - sqrt(2)), -x)) == (-1)**(-1/x)*(1 + sqrt(2))**(1/x) # recurse e = cos(1/(1 + sqrt(2))) assert radsimp(e) == cos(-sqrt(2) + 1) assert radsimp(e/2) == cos(-sqrt(2) + 1)/2 assert radsimp(1/e) == 1/cos(-sqrt(2) + 1) assert radsimp(2/e) == 2/cos(-sqrt(2) + 1) assert fraction(radsimp(e/sqrt(x))) == (sqrt(x)*cos(-sqrt(2)+1), x) # test that symbolic denominators are not processed r = 1 + sqrt(2) assert radsimp(x/r, symbolic=False) == -x*(-sqrt(2) + 1) assert radsimp(x/(y + r), symbolic=False) == x/(y + 1 + sqrt(2)) assert radsimp(x/(y + r)/r, symbolic=False) == \ -x*(-sqrt(2) + 1)/(y + 1 + sqrt(2)) # issue 7408 eq = sqrt(x)/sqrt(y) assert radsimp(eq) == umul(sqrt(x), sqrt(y), 1/y) assert radsimp(eq, symbolic=False) == eq # issue 7498 assert radsimp(sqrt(x)/sqrt(y)**3) == umul(sqrt(x), sqrt(y**3), 1/y**3) # for coverage eq = sqrt(x)/y**2 assert radsimp(eq) == eq def test_radsimp_issue_3214(): c, p = symbols('c p', positive=True) s = sqrt(c**2 - p**2) b = (c + I*p - s)/(c + I*p + s) assert radsimp(b) == -I*(c + I*p - sqrt(c**2 - p**2))**2/(2*c*p) def test_collect_1(): """Collect with respect to a Symbol""" x, y, z, n = symbols('x,y,z,n') assert collect(1, x) == 1 assert collect( x + y*x, x ) == x * (1 + y) assert collect( x + x**2, x ) == x + x**2 assert collect( x**2 + y*x**2, x ) == (x**2)*(1 + y) assert collect( x**2 + y*x, x ) == x*y + x**2 assert collect( 2*x**2 + y*x**2 + 3*x*y, [x] ) == x**2*(2 + y) + 3*x*y assert collect( 2*x**2 + y*x**2 + 3*x*y, [y] ) == 2*x**2 + y*(x**2 + 3*x) assert collect( ((1 + y + x)**4).expand(), x) == ((1 + y)**4).expand() + \ x*(4*(1 + y)**3).expand() + x**2*(6*(1 + y)**2).expand() + \ x**3*(4*(1 + y)).expand() + x**4 # symbols can be given as any iterable expr = x + y assert collect(expr, expr.free_symbols) == expr def test_collect_2(): """Collect with respect to a sum""" a, b, x = symbols('a,b,x') assert collect(a*(cos(x) + sin(x)) + b*(cos(x) + sin(x)), sin(x) + cos(x)) == (a + b)*(cos(x) + sin(x)) def test_collect_3(): """Collect with respect to a product""" a, b, c = symbols('a,b,c') f = Function('f') x, y, z, n = symbols('x,y,z,n') assert collect(-x/8 + x*y, -x) == x*(y - Rational(1, 8)) assert collect( 1 + x*(y**2), x*y ) == 1 + x*(y**2) assert collect( x*y + a*x*y, x*y) == x*y*(1 + a) assert collect( 1 + x*y + a*x*y, x*y) == 1 + x*y*(1 + a) assert collect(a*x*f(x) + b*(x*f(x)), x*f(x)) == x*(a + b)*f(x) assert collect(a*x*log(x) + b*(x*log(x)), x*log(x)) == x*(a + b)*log(x) assert collect(a*x**2*log(x)**2 + b*(x*log(x))**2, x*log(x)) == \ x**2*log(x)**2*(a + b) # with respect to a product of three symbols assert collect(y*x*z + a*x*y*z, x*y*z) == (1 + a)*x*y*z def test_collect_4(): """Collect with respect to a power""" a, b, c, x = symbols('a,b,c,x') assert collect(a*x**c + b*x**c, x**c) == x**c*(a + b) # issue 6096: 2 stays with c (unless c is integer or x is positive0 assert collect(a*x**(2*c) + b*x**(2*c), x**c) == x**(2*c)*(a + b) def test_collect_5(): """Collect with respect to a tuple""" a, x, y, z, n = symbols('a,x,y,z,n') assert collect(x**2*y**4 + z*(x*y**2)**2 + z + a*z, [x*y**2, z]) in [ z*(1 + a + x**2*y**4) + x**2*y**4, z*(1 + a) + x**2*y**4*(1 + z) ] assert collect((1 + (x + y) + (x + y)**2).expand(), [x, y]) == 1 + y + x*(1 + 2*y) + x**2 + y**2 def test_collect_pr19431(): """Unevaluated collect with respect to a product""" a = symbols('a') assert collect(a**2*(a**2 + 1), a**2, evaluate=False)[a**2] == (a**2 + 1) def test_collect_D(): D = Derivative f = Function('f') x, a, b = symbols('x,a,b') fx = D(f(x), x) fxx = D(f(x), x, x) assert collect(a*fx + b*fx, fx) == (a + b)*fx assert collect(a*D(fx, x) + b*D(fx, x), fx) == (a + b)*D(fx, x) assert collect(a*fxx + b*fxx, fx) == (a + b)*D(fx, x) # issue 4784 assert collect(5*f(x) + 3*fx, fx) == 5*f(x) + 3*fx assert collect(f(x) + f(x)*diff(f(x), x) + x*diff(f(x), x)*f(x), f(x).diff(x)) == \ (x*f(x) + f(x))*D(f(x), x) + f(x) assert collect(f(x) + f(x)*diff(f(x), x) + x*diff(f(x), x)*f(x), f(x).diff(x), exact=True) == \ (x*f(x) + f(x))*D(f(x), x) + f(x) assert collect(1/f(x) + 1/f(x)*diff(f(x), x) + x*diff(f(x), x)/f(x), f(x).diff(x), exact=True) == \ (1/f(x) + x/f(x))*D(f(x), x) + 1/f(x) e = (1 + x*fx + fx)/f(x) assert collect(e.expand(), fx) == fx*(x/f(x) + 1/f(x)) + 1/f(x) def test_collect_func(): f = ((x + a + 1)**3).expand() assert collect(f, x) == a**3 + 3*a**2 + 3*a + x**3 + x**2*(3*a + 3) + \ x*(3*a**2 + 6*a + 3) + 1 assert collect(f, x, factor) == x**3 + 3*x**2*(a + 1) + 3*x*(a + 1)**2 + \ (a + 1)**3 assert collect(f, x, evaluate=False) == { S.One: a**3 + 3*a**2 + 3*a + 1, x: 3*a**2 + 6*a + 3, x**2: 3*a + 3, x**3: 1 } assert collect(f, x, factor, evaluate=False) == { S.One: (a + 1)**3, x: 3*(a + 1)**2, x**2: umul(S(3), a + 1), x**3: 1} def test_collect_order(): a, b, x, t = symbols('a,b,x,t') assert collect(t + t*x + t*x**2 + O(x**3), t) == t*(1 + x + x**2 + O(x**3)) assert collect(t + t*x + x**2 + O(x**3), t) == \ t*(1 + x + O(x**3)) + x**2 + O(x**3) f = a*x + b*x + c*x**2 + d*x**2 + O(x**3) g = x*(a + b) + x**2*(c + d) + O(x**3) assert collect(f, x) == g assert collect(f, x, distribute_order_term=False) == g f = sin(a + b).series(b, 0, 10) assert collect(f, [sin(a), cos(a)]) == \ sin(a)*cos(b).series(b, 0, 10) + cos(a)*sin(b).series(b, 0, 10) assert collect(f, [sin(a), cos(a)], distribute_order_term=False) == \ sin(a)*cos(b).series(b, 0, 10).removeO() + \ cos(a)*sin(b).series(b, 0, 10).removeO() + O(b**10) def test_rcollect(): assert rcollect((x**2*y + x*y + x + y)/(x + y), y) == \ (x + y*(1 + x + x**2))/(x + y) assert rcollect(sqrt(-((x + 1)*(y + 1))), z) == sqrt(-((x + 1)*(y + 1))) def test_collect_D_0(): D = Derivative f = Function('f') x, a, b = symbols('x,a,b') fxx = D(f(x), x, x) assert collect(a*fxx + b*fxx, fxx) == (a + b)*fxx def test_collect_Wild(): """Collect with respect to functions with Wild argument""" a, b, x, y = symbols('a b x y') f = Function('f') w1 = Wild('.1') w2 = Wild('.2') assert collect(f(x) + a*f(x), f(w1)) == (1 + a)*f(x) assert collect(f(x, y) + a*f(x, y), f(w1)) == f(x, y) + a*f(x, y) assert collect(f(x, y) + a*f(x, y), f(w1, w2)) == (1 + a)*f(x, y) assert collect(f(x, y) + a*f(x, y), f(w1, w1)) == f(x, y) + a*f(x, y) assert collect(f(x, x) + a*f(x, x), f(w1, w1)) == (1 + a)*f(x, x) assert collect(a*(x + 1)**y + (x + 1)**y, w1**y) == (1 + a)*(x + 1)**y assert collect(a*(x + 1)**y + (x + 1)**y, w1**b) == \ a*(x + 1)**y + (x + 1)**y assert collect(a*(x + 1)**y + (x + 1)**y, (x + 1)**w2) == \ (1 + a)*(x + 1)**y assert collect(a*(x + 1)**y + (x + 1)**y, w1**w2) == (1 + a)*(x + 1)**y def test_collect_const(): # coverage not provided by above tests assert collect_const(2*sqrt(3) + 4*a*sqrt(5)) == \ 2*(2*sqrt(5)*a + sqrt(3)) # let the primitive reabsorb assert collect_const(2*sqrt(3) + 4*a*sqrt(5), sqrt(3)) == \ 2*sqrt(3) + 4*a*sqrt(5) assert collect_const(sqrt(2)*(1 + sqrt(2)) + sqrt(3) + x*sqrt(2)) == \ sqrt(2)*(x + 1 + sqrt(2)) + sqrt(3) # issue 5290 assert collect_const(2*x + 2*y + 1, 2) == \ collect_const(2*x + 2*y + 1) == \ Add(S.One, Mul(2, x + y, evaluate=False), evaluate=False) assert collect_const(-y - z) == Mul(-1, y + z, evaluate=False) assert collect_const(2*x - 2*y - 2*z, 2) == \ Mul(2, x - y - z, evaluate=False) assert collect_const(2*x - 2*y - 2*z, -2) == \ _unevaluated_Add(2*x, Mul(-2, y + z, evaluate=False)) # this is why the content_primitive is used eq = (sqrt(15 + 5*sqrt(2))*x + sqrt(3 + sqrt(2))*y)*2 assert collect_sqrt(eq + 2) == \ 2*sqrt(sqrt(2) + 3)*(sqrt(5)*x + y) + 2 # issue 16296 assert collect_const(a + b + x/2 + y/2) == a + b + Mul(S.Half, x + y, evaluate=False) def test_issue_13143(): f = Function('f') fx = f(x).diff(x) e = f(x) + fx + f(x)*fx # collect function before derivative assert collect(e, Wild('w')) == f(x)*(fx + 1) + fx e = f(x) + f(x)*fx + x*fx*f(x) assert collect(e, fx) == (x*f(x) + f(x))*fx + f(x) assert collect(e, f(x)) == (x*fx + fx + 1)*f(x) e = f(x) + fx + f(x)*fx assert collect(e, [f(x), fx]) == f(x)*(1 + fx) + fx assert collect(e, [fx, f(x)]) == fx*(1 + f(x)) + f(x) def test_issue_6097(): assert collect(a*y**(2.0*x) + b*y**(2.0*x), y**x) == (a + b)*(y**x)**2.0 assert collect(a*2**(2.0*x) + b*2**(2.0*x), 2**x) == (a + b)*(2**x)**2.0 def test_fraction_expand(): eq = (x + y)*y/x assert eq.expand(frac=True) == fraction_expand(eq) == (x*y + y**2)/x assert eq.expand() == y + y**2/x def test_fraction(): x, y, z = map(Symbol, 'xyz') A = Symbol('A', commutative=False) assert fraction(S.Half) == (1, 2) assert fraction(x) == (x, 1) assert fraction(1/x) == (1, x) assert fraction(x/y) == (x, y) assert fraction(x/2) == (x, 2) assert fraction(x*y/z) == (x*y, z) assert fraction(x/(y*z)) == (x, y*z) assert fraction(1/y**2) == (1, y**2) assert fraction(x/y**2) == (x, y**2) assert fraction((x**2 + 1)/y) == (x**2 + 1, y) assert fraction(x*(y + 1)/y**7) == (x*(y + 1), y**7) assert fraction(exp(-x), exact=True) == (exp(-x), 1) assert fraction((1/(x + y))/2, exact=True) == (1, Mul(2,(x + y), evaluate=False)) assert fraction(x*A/y) == (x*A, y) assert fraction(x*A**-1/y) == (x*A**-1, y) n = symbols('n', negative=True) assert fraction(exp(n)) == (1, exp(-n)) assert fraction(exp(-n)) == (exp(-n), 1) p = symbols('p', positive=True) assert fraction(exp(-p)*log(p), exact=True) == (exp(-p)*log(p), 1) m = Mul(1, 1, S.Half, evaluate=False) assert fraction(m) == (1, 2) assert fraction(m, exact=True) == (Mul(1, 1, evaluate=False), 2) m = Mul(1, 1, S.Half, S.Half, Pow(1, -1, evaluate=False), evaluate=False) assert fraction(m) == (1, 4) assert fraction(m, exact=True) == \ (Mul(1, 1, evaluate=False), Mul(2, 2, 1, evaluate=False)) def test_issue_5615(): aA, Re, a, b, D = symbols('aA Re a b D') e = ((D**3*a + b*aA**3)/Re).expand() assert collect(e, [aA**3/Re, a]) == e def test_issue_5933(): from sympy import Polygon, RegularPolygon, denom x = Polygon(*RegularPolygon((0, 0), 1, 5).vertices).centroid.x assert abs(denom(x).n()) > 1e-12 assert abs(denom(radsimp(x))) > 1e-12 # in case simplify didn't handle it def test_issue_14608(): a, b = symbols('a b', commutative=False) x, y = symbols('x y') raises(AttributeError, lambda: collect(a*b + b*a, a)) assert collect(x*y + y*(x+1), a) == x*y + y*(x+1) assert collect(x*y + y*(x+1) + a*b + b*a, y) == y*(2*x + 1) + a*b + b*a def test_collect_abs(): s = abs(x) + abs(y) assert collect_abs(s) == s assert unchanged(Mul, abs(x), abs(y)) ans = Abs(x*y) assert isinstance(ans, Abs) assert collect_abs(abs(x)*abs(y)) == ans assert collect_abs(1 + exp(abs(x)*abs(y))) == 1 + exp(ans) # See https://github.com/sympy/sympy/issues/12910 p = Symbol('p', positive=True) assert collect_abs(p/abs(1-p)).is_commutative is True def test_issue_19149(): eq = exp(3*x/4) assert collect(eq, exp(x)) == eq def test_issue_19719(): a, b = symbols('a, b') expr = a**2 * (b + 1) + (7 + 1/b)/a collected = collect(expr, (a**2, 1/a), evaluate=False) # Would return {_Dummy_20**(-2): b + 1, 1/a: 7 + 1/b} without xreplace assert collected == {a**2: b + 1, 1/a: 7 + 1/b} def test_issue_21355(): assert radsimp(1/(x + sqrt(x**2))) == 1/(x + sqrt(x**2)) assert radsimp(1/(x - sqrt(x**2))) == 1/(x - sqrt(x**2)) sympy-sympy-1.9/sympy/simplify/tests/test_ratsimp.py000066400000000000000000000036531412543434000232010ustar00rootroot00000000000000from sympy import ratsimpmodprime, ratsimp, Rational, sqrt, pi, log, erf, GF from sympy.abc import x, y, z, t, a, b, c, d, e def test_ratsimp(): f, g = 1/x + 1/y, (x + y)/(x*y) assert f != g and ratsimp(f) == g f, g = 1/(1 + 1/x), 1 - 1/(x + 1) assert f != g and ratsimp(f) == g f, g = x/(x + y) + y/(x + y), 1 assert f != g and ratsimp(f) == g f, g = -x - y - y**2/(x + y) + x**2/(x + y), -2*y assert f != g and ratsimp(f) == g f = (a*c*x*y + a*c*z - b*d*x*y - b*d*z - b*t*x*y - b*t*x - b*t*z + e*x)/(x*y + z) G = [a*c - b*d - b*t + (-b*t*x + e*x)/(x*y + z), a*c - b*d - b*t - ( b*t*x - e*x)/(x*y + z)] assert f != g and ratsimp(f) in G A = sqrt(pi) B = log(erf(x) - 1) C = log(erf(x) + 1) D = 8 - 8*erf(x) f = A*B/D - A*C/D + A*C*erf(x)/D - A*B*erf(x)/D + 2*A/D assert ratsimp(f) == A*B/8 - A*C/8 - A/(4*erf(x) - 4) def test_ratsimpmodprime(): a = y**5 + x + y b = x - y F = [x*y**5 - x - y] assert ratsimpmodprime(a/b, F, x, y, order='lex') == \ (-x**2 - x*y - x - y) / (-x**2 + x*y) a = x + y**2 - 2 b = x + y**2 - y - 1 F = [x*y - 1] assert ratsimpmodprime(a/b, F, x, y, order='lex') == \ (1 + y - x)/(y - x) a = 5*x**3 + 21*x**2 + 4*x*y + 23*x + 12*y + 15 b = 7*x**3 - y*x**2 + 31*x**2 + 2*x*y + 15*y + 37*x + 21 F = [x**2 + y**2 - 1] assert ratsimpmodprime(a/b, F, x, y, order='lex') == \ (1 + 5*y - 5*x)/(8*y - 6*x) a = x*y - x - 2*y + 4 b = x + y**2 - 2*y F = [x - 2, y - 3] assert ratsimpmodprime(a/b, F, x, y, order='lex') == \ Rational(2, 5) # Test a bug where denominators would be dropped assert ratsimpmodprime(x, [y - 2*x], order='lex') == \ y/2 a = (x**5 + 2*x**4 + 2*x**3 + 2*x**2 + x + 2/x + x**(-2)) assert ratsimpmodprime(a, [x + 1], domain=GF(2)) == 1 assert ratsimpmodprime(a, [x + 1], domain=GF(3)) == -1 sympy-sympy-1.9/sympy/simplify/tests/test_rewrite.py000066400000000000000000000017251412543434000232010ustar00rootroot00000000000000from sympy import sin, cos, exp, cot, I, symbols from sympy.testing.pytest import _both_exp_pow x, y, z, n = symbols('x,y,z,n') @_both_exp_pow def test_has(): assert cot(x).has(x) assert cot(x).has(cot) assert not cot(x).has(sin) assert sin(x).has(x) assert sin(x).has(sin) assert not sin(x).has(cot) assert exp(x).has(exp) @_both_exp_pow def test_sin_exp_rewrite(): assert sin(x).rewrite(sin, exp) == -I/2*(exp(I*x) - exp(-I*x)) assert sin(x).rewrite(sin, exp).rewrite(exp, sin) == sin(x) assert cos(x).rewrite(cos, exp).rewrite(exp, cos) == cos(x) assert (sin(5*y) - sin( 2*x)).rewrite(sin, exp).rewrite(exp, sin) == sin(5*y) - sin(2*x) assert sin(x + y).rewrite(sin, exp).rewrite(exp, sin) == sin(x + y) assert cos(x + y).rewrite(cos, exp).rewrite(exp, cos) == cos(x + y) # This next test currently passes... not clear whether it should or not? assert cos(x).rewrite(cos, exp).rewrite(exp, sin) == cos(x) sympy-sympy-1.9/sympy/simplify/tests/test_simplify.py000066400000000000000000001137131412543434000233550ustar00rootroot00000000000000from sympy import ( Abs, acos, Add, asin, atan, Basic, binomial, besselsimp, cos, cosh, count_ops, csch, diff, E, Eq, erf, exp, exp_polar, expand, expand_multinomial, factor, factorial, Float, Function, gamma, GoldenRatio, hyper, hypersimp, I, Integral, integrate, KroneckerDelta, log, logcombine, Lt, Matrix, MatrixSymbol, Mul, nsimplify, oo, pi, Piecewise, Poly, posify, rad, Rational, S, separatevars, signsimp, simplify, sign, sin, sinc, sinh, solve, sqrt, Sum, Symbol, symbols, sympify, tan, zoo, And, Gt, Ge, Le, Or) from sympy.core.mul import _keep_coeff from sympy.core.expr import unchanged from sympy.simplify.simplify import nthroot, inversecombine from sympy.testing.pytest import XFAIL, slow, _both_exp_pow from sympy.abc import x, y, z, t, a, b, c, d, e, f, g, h, i, n def test_issue_7263(): assert abs((simplify(30.8**2 - 82.5**2 * sin(rad(11.6))**2)).evalf() - \ 673.447451402970) < 1e-12 def test_factorial_simplify(): # There are more tests in test_factorials.py. x = Symbol('x') assert simplify(factorial(x)/x) == gamma(x) assert simplify(factorial(factorial(x))) == factorial(factorial(x)) def test_simplify_expr(): x, y, z, k, n, m, w, s, A = symbols('x,y,z,k,n,m,w,s,A') f = Function('f') assert all(simplify(tmp) == tmp for tmp in [I, E, oo, x, -x, -oo, -E, -I]) e = 1/x + 1/y assert e != (x + y)/(x*y) assert simplify(e) == (x + y)/(x*y) e = A**2*s**4/(4*pi*k*m**3) assert simplify(e) == e e = (4 + 4*x - 2*(2 + 2*x))/(2 + 2*x) assert simplify(e) == 0 e = (-4*x*y**2 - 2*y**3 - 2*x**2*y)/(x + y)**2 assert simplify(e) == -2*y e = -x - y - (x + y)**(-1)*y**2 + (x + y)**(-1)*x**2 assert simplify(e) == -2*y e = (x + x*y)/x assert simplify(e) == 1 + y e = (f(x) + y*f(x))/f(x) assert simplify(e) == 1 + y e = (2 * (1/n - cos(n * pi)/n))/pi assert simplify(e) == (-cos(pi*n) + 1)/(pi*n)*2 e = integrate(1/(x**3 + 1), x).diff(x) assert simplify(e) == 1/(x**3 + 1) e = integrate(x/(x**2 + 3*x + 1), x).diff(x) assert simplify(e) == x/(x**2 + 3*x + 1) f = Symbol('f') A = Matrix([[2*k - m*w**2, -k], [-k, k - m*w**2]]).inv() assert simplify((A*Matrix([0, f]))[1] - (-f*(2*k - m*w**2)/(k**2 - (k - m*w**2)*(2*k - m*w**2)))) == 0 f = -x + y/(z + t) + z*x/(z + t) + z*a/(z + t) + t*x/(z + t) assert simplify(f) == (y + a*z)/(z + t) # issue 10347 expr = -x*(y**2 - 1)*(2*y**2*(x**2 - 1)/(a*(x**2 - y**2)**2) + (x**2 - 1) /(a*(x**2 - y**2)))/(a*(x**2 - y**2)) + x*(-2*x**2*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*sin(z)/(a*(x**2 - y**2)**2) - x**2*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*sin(z)/(a*(x**2 - 1)*(x**2 - y**2)) + (x**2*sqrt((-x**2 + 1)* (y**2 - 1))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*sin(z)/(x**2 - 1) + sqrt( (-x**2 + 1)*(y**2 - 1))*(x*(-x*y**2 + x)/sqrt(-x**2*y**2 + x**2 + y**2 - 1) + sqrt(-x**2*y**2 + x**2 + y**2 - 1))*sin(z))/(a*sqrt((-x**2 + 1)*( y**2 - 1))*(x**2 - y**2)))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*sin(z)/(a* (x**2 - y**2)) + x*(-2*x**2*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos(z)/(a* (x**2 - y**2)**2) - x**2*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos(z)/(a* (x**2 - 1)*(x**2 - y**2)) + (x**2*sqrt((-x**2 + 1)*(y**2 - 1))*sqrt(-x**2 *y**2 + x**2 + y**2 - 1)*cos(z)/(x**2 - 1) + x*sqrt((-x**2 + 1)*(y**2 - 1))*(-x*y**2 + x)*cos(z)/sqrt(-x**2*y**2 + x**2 + y**2 - 1) + sqrt((-x**2 + 1)*(y**2 - 1))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos(z))/(a*sqrt((-x**2 + 1)*(y**2 - 1))*(x**2 - y**2)))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos( z)/(a*(x**2 - y**2)) - y*sqrt((-x**2 + 1)*(y**2 - 1))*(-x*y*sqrt(-x**2* y**2 + x**2 + y**2 - 1)*sin(z)/(a*(x**2 - y**2)*(y**2 - 1)) + 2*x*y*sqrt( -x**2*y**2 + x**2 + y**2 - 1)*sin(z)/(a*(x**2 - y**2)**2) + (x*y*sqrt(( -x**2 + 1)*(y**2 - 1))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*sin(z)/(y**2 - 1) + x*sqrt((-x**2 + 1)*(y**2 - 1))*(-x**2*y + y)*sin(z)/sqrt(-x**2*y**2 + x**2 + y**2 - 1))/(a*sqrt((-x**2 + 1)*(y**2 - 1))*(x**2 - y**2)))*sin( z)/(a*(x**2 - y**2)) + y*(x**2 - 1)*(-2*x*y*(x**2 - 1)/(a*(x**2 - y**2) **2) + 2*x*y/(a*(x**2 - y**2)))/(a*(x**2 - y**2)) + y*(x**2 - 1)*(y**2 - 1)*(-x*y*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos(z)/(a*(x**2 - y**2)*(y**2 - 1)) + 2*x*y*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos(z)/(a*(x**2 - y**2) **2) + (x*y*sqrt((-x**2 + 1)*(y**2 - 1))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos(z)/(y**2 - 1) + x*sqrt((-x**2 + 1)*(y**2 - 1))*(-x**2*y + y)*cos( z)/sqrt(-x**2*y**2 + x**2 + y**2 - 1))/(a*sqrt((-x**2 + 1)*(y**2 - 1) )*(x**2 - y**2)))*cos(z)/(a*sqrt((-x**2 + 1)*(y**2 - 1))*(x**2 - y**2) ) - x*sqrt((-x**2 + 1)*(y**2 - 1))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*sin( z)**2/(a**2*(x**2 - 1)*(x**2 - y**2)*(y**2 - 1)) - x*sqrt((-x**2 + 1)*( y**2 - 1))*sqrt(-x**2*y**2 + x**2 + y**2 - 1)*cos(z)**2/(a**2*(x**2 - 1)*( x**2 - y**2)*(y**2 - 1)) assert simplify(expr) == 2*x/(a**2*(x**2 - y**2)) #issue 17631 assert simplify('((-1/2)*Boole(True)*Boole(False)-1)*Boole(True)') == \ Mul(sympify('(2 + Boole(True)*Boole(False))'), sympify('-Boole(True)/2')) A, B = symbols('A,B', commutative=False) assert simplify(A*B - B*A) == A*B - B*A assert simplify(A/(1 + y/x)) == x*A/(x + y) assert simplify(A*(1/x + 1/y)) == A/x + A/y #(x + y)*A/(x*y) assert simplify(log(2) + log(3)) == log(6) assert simplify(log(2*x) - log(2)) == log(x) assert simplify(hyper([], [], x)) == exp(x) def test_issue_3557(): f_1 = x*a + y*b + z*c - 1 f_2 = x*d + y*e + z*f - 1 f_3 = x*g + y*h + z*i - 1 solutions = solve([f_1, f_2, f_3], x, y, z, simplify=False) assert simplify(solutions[y]) == \ (a*i + c*d + f*g - a*f - c*g - d*i)/ \ (a*e*i + b*f*g + c*d*h - a*f*h - b*d*i - c*e*g) def test_simplify_other(): assert simplify(sin(x)**2 + cos(x)**2) == 1 assert simplify(gamma(x + 1)/gamma(x)) == x assert simplify(sin(x)**2 + cos(x)**2 + factorial(x)/gamma(x)) == 1 + x assert simplify( Eq(sin(x)**2 + cos(x)**2, factorial(x)/gamma(x))) == Eq(x, 1) nc = symbols('nc', commutative=False) assert simplify(x + x*nc) == x*(1 + nc) # issue 6123 # f = exp(-I*(k*sqrt(t) + x/(2*sqrt(t)))**2) # ans = integrate(f, (k, -oo, oo), conds='none') ans = I*(-pi*x*exp(I*pi*Rational(-3, 4) + I*x**2/(4*t))*erf(x*exp(I*pi*Rational(-3, 4))/ (2*sqrt(t)))/(2*sqrt(t)) + pi*x*exp(I*pi*Rational(-3, 4) + I*x**2/(4*t))/ (2*sqrt(t)))*exp(-I*x**2/(4*t))/(sqrt(pi)*x) - I*sqrt(pi) * \ (-erf(x*exp(I*pi/4)/(2*sqrt(t))) + 1)*exp(I*pi/4)/(2*sqrt(t)) assert simplify(ans) == -(-1)**Rational(3, 4)*sqrt(pi)/sqrt(t) # issue 6370 assert simplify(2**(2 + x)/4) == 2**x @_both_exp_pow def test_simplify_complex(): cosAsExp = cos(x)._eval_rewrite_as_exp(x) tanAsExp = tan(x)._eval_rewrite_as_exp(x) assert simplify(cosAsExp*tanAsExp) == sin(x) # issue 4341 # issue 10124 assert simplify(exp(Matrix([[0, -1], [1, 0]]))) == Matrix([[cos(1), -sin(1)], [sin(1), cos(1)]]) def test_simplify_ratio(): # roots of x**3-3*x+5 roots = ['(1/2 - sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3) + 1/((1/2 - ' 'sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3))', '1/((1/2 + sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3)) + ' '(1/2 + sqrt(3)*I/2)*(sqrt(21)/2 + 5/2)**(1/3)', '-(sqrt(21)/2 + 5/2)**(1/3) - 1/(sqrt(21)/2 + 5/2)**(1/3)'] for r in roots: r = S(r) assert count_ops(simplify(r, ratio=1)) <= count_ops(r) # If ratio=oo, simplify() is always applied: assert simplify(r, ratio=oo) is not r def test_simplify_measure(): measure1 = lambda expr: len(str(expr)) measure2 = lambda expr: -count_ops(expr) # Return the most complicated result expr = (x + 1)/(x + sin(x)**2 + cos(x)**2) assert measure1(simplify(expr, measure=measure1)) <= measure1(expr) assert measure2(simplify(expr, measure=measure2)) <= measure2(expr) expr2 = Eq(sin(x)**2 + cos(x)**2, 1) assert measure1(simplify(expr2, measure=measure1)) <= measure1(expr2) assert measure2(simplify(expr2, measure=measure2)) <= measure2(expr2) def test_simplify_rational(): expr = 2**x*2.**y assert simplify(expr, rational = True) == 2**(x+y) assert simplify(expr, rational = None) == 2.0**(x+y) assert simplify(expr, rational = False) == expr assert simplify('0.9 - 0.8 - 0.1', rational = True) == 0 def test_simplify_issue_1308(): assert simplify(exp(Rational(-1, 2)) + exp(Rational(-3, 2))) == \ (1 + E)*exp(Rational(-3, 2)) def test_issue_5652(): assert simplify(E + exp(-E)) == exp(-E) + E n = symbols('n', commutative=False) assert simplify(n + n**(-n)) == n + n**(-n) def test_simplify_fail1(): x = Symbol('x') y = Symbol('y') e = (x + y)**2/(-4*x*y**2 - 2*y**3 - 2*x**2*y) assert simplify(e) == 1 / (-2*y) def test_nthroot(): assert nthroot(90 + 34*sqrt(7), 3) == sqrt(7) + 3 q = 1 + sqrt(2) - 2*sqrt(3) + sqrt(6) + sqrt(7) assert nthroot(expand_multinomial(q**3), 3) == q assert nthroot(41 + 29*sqrt(2), 5) == 1 + sqrt(2) assert nthroot(-41 - 29*sqrt(2), 5) == -1 - sqrt(2) expr = 1320*sqrt(10) + 4216 + 2576*sqrt(6) + 1640*sqrt(15) assert nthroot(expr, 5) == 1 + sqrt(6) + sqrt(15) q = 1 + sqrt(2) + sqrt(3) + sqrt(5) assert expand_multinomial(nthroot(expand_multinomial(q**5), 5)) == q q = 1 + sqrt(2) + 7*sqrt(6) + 2*sqrt(10) assert nthroot(expand_multinomial(q**5), 5, 8) == q q = 1 + sqrt(2) - 2*sqrt(3) + 1171*sqrt(6) assert nthroot(expand_multinomial(q**3), 3) == q assert nthroot(expand_multinomial(q**6), 6) == q def test_nthroot1(): q = 1 + sqrt(2) + sqrt(3) + S.One/10**20 p = expand_multinomial(q**5) assert nthroot(p, 5) == q q = 1 + sqrt(2) + sqrt(3) + S.One/10**30 p = expand_multinomial(q**5) assert nthroot(p, 5) == q @_both_exp_pow def test_separatevars(): x, y, z, n = symbols('x,y,z,n') assert separatevars(2*n*x*z + 2*x*y*z) == 2*x*z*(n + y) assert separatevars(x*z + x*y*z) == x*z*(1 + y) assert separatevars(pi*x*z + pi*x*y*z) == pi*x*z*(1 + y) assert separatevars(x*y**2*sin(x) + x*sin(x)*sin(y)) == \ x*(sin(y) + y**2)*sin(x) assert separatevars(x*exp(x + y) + x*exp(x)) == x*(1 + exp(y))*exp(x) assert separatevars((x*(y + 1))**z).is_Pow # != x**z*(1 + y)**z assert separatevars(1 + x + y + x*y) == (x + 1)*(y + 1) assert separatevars(y/pi*exp(-(z - x)/cos(n))) == \ y*exp(x/cos(n))*exp(-z/cos(n))/pi assert separatevars((x + y)*(x - y) + y**2 + 2*x + 1) == (x + 1)**2 # issue 4858 p = Symbol('p', positive=True) assert separatevars(sqrt(p**2 + x*p**2)) == p*sqrt(1 + x) assert separatevars(sqrt(y*(p**2 + x*p**2))) == p*sqrt(y*(1 + x)) assert separatevars(sqrt(y*(p**2 + x*p**2)), force=True) == \ p*sqrt(y)*sqrt(1 + x) # issue 4865 assert separatevars(sqrt(x*y)).is_Pow assert separatevars(sqrt(x*y), force=True) == sqrt(x)*sqrt(y) # issue 4957 # any type sequence for symbols is fine assert separatevars(((2*x + 2)*y), dict=True, symbols=()) == \ {'coeff': 1, x: 2*x + 2, y: y} # separable assert separatevars(((2*x + 2)*y), dict=True, symbols=[x]) == \ {'coeff': y, x: 2*x + 2} assert separatevars(((2*x + 2)*y), dict=True, symbols=[]) == \ {'coeff': 1, x: 2*x + 2, y: y} assert separatevars(((2*x + 2)*y), dict=True) == \ {'coeff': 1, x: 2*x + 2, y: y} assert separatevars(((2*x + 2)*y), dict=True, symbols=None) == \ {'coeff': y*(2*x + 2)} # not separable assert separatevars(3, dict=True) is None assert separatevars(2*x + y, dict=True, symbols=()) is None assert separatevars(2*x + y, dict=True) is None assert separatevars(2*x + y, dict=True, symbols=None) == {'coeff': 2*x + y} # issue 4808 n, m = symbols('n,m', commutative=False) assert separatevars(m + n*m) == (1 + n)*m assert separatevars(x + x*n) == x*(1 + n) # issue 4910 f = Function('f') assert separatevars(f(x) + x*f(x)) == f(x) + x*f(x) # a noncommutable object present eq = x*(1 + hyper((), (), y*z)) assert separatevars(eq) == eq s = separatevars(abs(x*y)) assert s == abs(x)*abs(y) and s.is_Mul z = cos(1)**2 + sin(1)**2 - 1 a = abs(x*z) s = separatevars(a) assert not a.is_Mul and s.is_Mul and s == abs(x)*abs(z) s = separatevars(abs(x*y*z)) assert s == abs(x)*abs(y)*abs(z) # abs(x+y)/abs(z) would be better but we test this here to # see that it doesn't raise assert separatevars(abs((x+y)/z)) == abs((x+y)/z) def test_separatevars_advanced_factor(): x, y, z = symbols('x,y,z') assert separatevars(1 + log(x)*log(y) + log(x) + log(y)) == \ (log(x) + 1)*(log(y) + 1) assert separatevars(1 + x - log(z) - x*log(z) - exp(y)*log(z) - x*exp(y)*log(z) + x*exp(y) + exp(y)) == \ -((x + 1)*(log(z) - 1)*(exp(y) + 1)) x, y = symbols('x,y', positive=True) assert separatevars(1 + log(x**log(y)) + log(x*y)) == \ (log(x) + 1)*(log(y) + 1) def test_hypersimp(): n, k = symbols('n,k', integer=True) assert hypersimp(factorial(k), k) == k + 1 assert hypersimp(factorial(k**2), k) is None assert hypersimp(1/factorial(k), k) == 1/(k + 1) assert hypersimp(2**k/factorial(k)**2, k) == 2/(k + 1)**2 assert hypersimp(binomial(n, k), k) == (n - k)/(k + 1) assert hypersimp(binomial(n + 1, k), k) == (n - k + 1)/(k + 1) term = (4*k + 1)*factorial(k)/factorial(2*k + 1) assert hypersimp(term, k) == S.Half*((4*k + 5)/(3 + 14*k + 8*k**2)) term = 1/((2*k - 1)*factorial(2*k + 1)) assert hypersimp(term, k) == (k - S.Half)/((k + 1)*(2*k + 1)*(2*k + 3)) term = binomial(n, k)*(-1)**k/factorial(k) assert hypersimp(term, k) == (k - n)/(k + 1)**2 def test_nsimplify(): x = Symbol("x") assert nsimplify(0) == 0 assert nsimplify(-1) == -1 assert nsimplify(1) == 1 assert nsimplify(1 + x) == 1 + x assert nsimplify(2.7) == Rational(27, 10) assert nsimplify(1 - GoldenRatio) == (1 - sqrt(5))/2 assert nsimplify((1 + sqrt(5))/4, [GoldenRatio]) == GoldenRatio/2 assert nsimplify(2/GoldenRatio, [GoldenRatio]) == 2*GoldenRatio - 2 assert nsimplify(exp(pi*I*Rational(5, 3), evaluate=False)) == \ sympify('1/2 - sqrt(3)*I/2') assert nsimplify(sin(pi*Rational(3, 5), evaluate=False)) == \ sympify('sqrt(sqrt(5)/8 + 5/8)') assert nsimplify(sqrt(atan('1', evaluate=False))*(2 + I), [pi]) == \ sqrt(pi) + sqrt(pi)/2*I assert nsimplify(2 + exp(2*atan('1/4')*I)) == sympify('49/17 + 8*I/17') assert nsimplify(pi, tolerance=0.01) == Rational(22, 7) assert nsimplify(pi, tolerance=0.001) == Rational(355, 113) assert nsimplify(0.33333, tolerance=1e-4) == Rational(1, 3) assert nsimplify(2.0**(1/3.), tolerance=0.001) == Rational(635, 504) assert nsimplify(2.0**(1/3.), tolerance=0.001, full=True) == \ 2**Rational(1, 3) assert nsimplify(x + .5, rational=True) == S.Half + x assert nsimplify(1/.3 + x, rational=True) == Rational(10, 3) + x assert nsimplify(log(3).n(), rational=True) == \ sympify('109861228866811/100000000000000') assert nsimplify(Float(0.272198261287950), [pi, log(2)]) == pi*log(2)/8 assert nsimplify(Float(0.272198261287950).n(3), [pi, log(2)]) == \ -pi/4 - log(2) + Rational(7, 4) assert nsimplify(x/7.0) == x/7 assert nsimplify(pi/1e2) == pi/100 assert nsimplify(pi/1e2, rational=False) == pi/100.0 assert nsimplify(pi/1e-7) == 10000000*pi assert not nsimplify( factor(-3.0*z**2*(z**2)**(-2.5) + 3*(z**2)**(-1.5))).atoms(Float) e = x**0.0 assert e.is_Pow and nsimplify(x**0.0) == 1 assert nsimplify(3.333333, tolerance=0.1, rational=True) == Rational(10, 3) assert nsimplify(3.333333, tolerance=0.01, rational=True) == Rational(10, 3) assert nsimplify(3.666666, tolerance=0.1, rational=True) == Rational(11, 3) assert nsimplify(3.666666, tolerance=0.01, rational=True) == Rational(11, 3) assert nsimplify(33, tolerance=10, rational=True) == Rational(33) assert nsimplify(33.33, tolerance=10, rational=True) == Rational(30) assert nsimplify(37.76, tolerance=10, rational=True) == Rational(40) assert nsimplify(-203.1) == Rational(-2031, 10) assert nsimplify(.2, tolerance=0) == Rational(1, 5) assert nsimplify(-.2, tolerance=0) == Rational(-1, 5) assert nsimplify(.2222, tolerance=0) == Rational(1111, 5000) assert nsimplify(-.2222, tolerance=0) == Rational(-1111, 5000) # issue 7211, PR 4112 assert nsimplify(S(2e-8)) == Rational(1, 50000000) # issue 7322 direct test assert nsimplify(1e-42, rational=True) != 0 # issue 10336 inf = Float('inf') infs = (-oo, oo, inf, -inf) for zi in infs: ans = sign(zi)*oo assert nsimplify(zi) == ans assert nsimplify(zi + x) == x + ans assert nsimplify(0.33333333, rational=True, rational_conversion='exact') == Rational(0.33333333) # Make sure nsimplify on expressions uses full precision assert nsimplify(pi.evalf(100)*x, rational_conversion='exact').evalf(100) == pi.evalf(100)*x def test_issue_9448(): tmp = sympify("1/(1 - (-1)**(2/3) - (-1)**(1/3)) + 1/(1 + (-1)**(2/3) + (-1)**(1/3))") assert nsimplify(tmp) == S.Half def test_extract_minus_sign(): x = Symbol("x") y = Symbol("y") a = Symbol("a") b = Symbol("b") assert simplify(-x/-y) == x/y assert simplify(-x/y) == -x/y assert simplify(x/y) == x/y assert simplify(x/-y) == -x/y assert simplify(-x/0) == zoo*x assert simplify(Rational(-5, 0)) is zoo assert simplify(-a*x/(-y - b)) == a*x/(b + y) def test_diff(): x = Symbol("x") y = Symbol("y") f = Function("f") g = Function("g") assert simplify(g(x).diff(x)*f(x).diff(x) - f(x).diff(x)*g(x).diff(x)) == 0 assert simplify(2*f(x)*f(x).diff(x) - diff(f(x)**2, x)) == 0 assert simplify(diff(1/f(x), x) + f(x).diff(x)/f(x)**2) == 0 assert simplify(f(x).diff(x, y) - f(x).diff(y, x)) == 0 def test_logcombine_1(): x, y = symbols("x,y") a = Symbol("a") z, w = symbols("z,w", positive=True) b = Symbol("b", real=True) assert logcombine(log(x) + 2*log(y)) == log(x) + 2*log(y) assert logcombine(log(x) + 2*log(y), force=True) == log(x*y**2) assert logcombine(a*log(w) + log(z)) == a*log(w) + log(z) assert logcombine(b*log(z) + b*log(x)) == log(z**b) + b*log(x) assert logcombine(b*log(z) - log(w)) == log(z**b/w) assert logcombine(log(x)*log(z)) == log(x)*log(z) assert logcombine(log(w)*log(x)) == log(w)*log(x) assert logcombine(cos(-2*log(z) + b*log(w))) in [cos(log(w**b/z**2)), cos(log(z**2/w**b))] assert logcombine(log(log(x) - log(y)) - log(z), force=True) == \ log(log(x/y)/z) assert logcombine((2 + I)*log(x), force=True) == (2 + I)*log(x) assert logcombine((x**2 + log(x) - log(y))/(x*y), force=True) == \ (x**2 + log(x/y))/(x*y) # the following could also give log(z*x**log(y**2)), what we # are testing is that a canonical result is obtained assert logcombine(log(x)*2*log(y) + log(z), force=True) == \ log(z*y**log(x**2)) assert logcombine((x*y + sqrt(x**4 + y**4) + log(x) - log(y))/(pi*x**Rational(2, 3)* sqrt(y)**3), force=True) == ( x*y + sqrt(x**4 + y**4) + log(x/y))/(pi*x**Rational(2, 3)*y**Rational(3, 2)) assert logcombine(gamma(-log(x/y))*acos(-log(x/y)), force=True) == \ acos(-log(x/y))*gamma(-log(x/y)) assert logcombine(2*log(z)*log(w)*log(x) + log(z) + log(w)) == \ log(z**log(w**2))*log(x) + log(w*z) assert logcombine(3*log(w) + 3*log(z)) == log(w**3*z**3) assert logcombine(x*(y + 1) + log(2) + log(3)) == x*(y + 1) + log(6) assert logcombine((x + y)*log(w) + (-x - y)*log(3)) == (x + y)*log(w/3) # a single unknown can combine assert logcombine(log(x) + log(2)) == log(2*x) eq = log(abs(x)) + log(abs(y)) assert logcombine(eq) == eq reps = {x: 0, y: 0} assert log(abs(x)*abs(y)).subs(reps) != eq.subs(reps) def test_logcombine_complex_coeff(): i = Integral((sin(x**2) + cos(x**3))/x, x) assert logcombine(i, force=True) == i assert logcombine(i + 2*log(x), force=True) == \ i + log(x**2) def test_issue_5950(): x, y = symbols("x,y", positive=True) assert logcombine(log(3) - log(2)) == log(Rational(3,2), evaluate=False) assert logcombine(log(x) - log(y)) == log(x/y) assert logcombine(log(Rational(3,2), evaluate=False) - log(2)) == \ log(Rational(3,4), evaluate=False) def test_posify(): from sympy.abc import x assert str(posify( x + Symbol('p', positive=True) + Symbol('n', negative=True))) == '(_x + n + p, {_x: x})' eq, rep = posify(1/x) assert log(eq).expand().subs(rep) == -log(x) assert str(posify([x, 1 + x])) == '([_x, _x + 1], {_x: x})' x = symbols('x') p = symbols('p', positive=True) n = symbols('n', negative=True) orig = [x, n, p] modified, reps = posify(orig) assert str(modified) == '[_x, n, p]' assert [w.subs(reps) for w in modified] == orig assert str(Integral(posify(1/x + y)[0], (y, 1, 3)).expand()) == \ 'Integral(1/_x, (y, 1, 3)) + Integral(_y, (y, 1, 3))' assert str(Sum(posify(1/x**n)[0], (n,1,3)).expand()) == \ 'Sum(_x**(-n), (n, 1, 3))' # issue 16438 k = Symbol('k', finite=True) eq, rep = posify(k) assert eq.assumptions0 == {'positive': True, 'zero': False, 'imaginary': False, 'nonpositive': False, 'commutative': True, 'hermitian': True, 'real': True, 'nonzero': True, 'nonnegative': True, 'negative': False, 'complex': True, 'finite': True, 'infinite': False, 'extended_real':True, 'extended_negative': False, 'extended_nonnegative': True, 'extended_nonpositive': False, 'extended_nonzero': True, 'extended_positive': True} def test_issue_4194(): # simplify should call cancel from sympy.abc import x, y f = Function('f') assert simplify((4*x + 6*f(y))/(2*x + 3*f(y))) == 2 @XFAIL def test_simplify_float_vs_integer(): # Test for issue 4473: # https://github.com/sympy/sympy/issues/4473 assert simplify(x**2.0 - x**2) == 0 assert simplify(x**2 - x**2.0) == 0 def test_as_content_primitive(): assert (x/2 + y).as_content_primitive() == (S.Half, x + 2*y) assert (x/2 + y).as_content_primitive(clear=False) == (S.One, x/2 + y) assert (y*(x/2 + y)).as_content_primitive() == (S.Half, y*(x + 2*y)) assert (y*(x/2 + y)).as_content_primitive(clear=False) == (S.One, y*(x/2 + y)) # although the _as_content_primitive methods do not alter the underlying structure, # the as_content_primitive function will touch up the expression and join # bases that would otherwise have not been joined. assert (x*(2 + 2*x)*(3*x + 3)**2).as_content_primitive() == \ (18, x*(x + 1)**3) assert (2 + 2*x + 2*y*(3 + 3*y)).as_content_primitive() == \ (2, x + 3*y*(y + 1) + 1) assert ((2 + 6*x)**2).as_content_primitive() == \ (4, (3*x + 1)**2) assert ((2 + 6*x)**(2*y)).as_content_primitive() == \ (1, (_keep_coeff(S(2), (3*x + 1)))**(2*y)) assert (5 + 10*x + 2*y*(3 + 3*y)).as_content_primitive() == \ (1, 10*x + 6*y*(y + 1) + 5) assert (5*(x*(1 + y)) + 2*x*(3 + 3*y)).as_content_primitive() == \ (11, x*(y + 1)) assert ((5*(x*(1 + y)) + 2*x*(3 + 3*y))**2).as_content_primitive() == \ (121, x**2*(y + 1)**2) assert (y**2).as_content_primitive() == \ (1, y**2) assert (S.Infinity).as_content_primitive() == (1, oo) eq = x**(2 + y) assert (eq).as_content_primitive() == (1, eq) assert (S.Half**(2 + x)).as_content_primitive() == (Rational(1, 4), 2**-x) assert (Rational(-1, 2)**(2 + x)).as_content_primitive() == \ (Rational(1, 4), (Rational(-1, 2))**x) assert (Rational(-1, 2)**(2 + x)).as_content_primitive() == \ (Rational(1, 4), Rational(-1, 2)**x) assert (4**((1 + y)/2)).as_content_primitive() == (2, 4**(y/2)) assert (3**((1 + y)/2)).as_content_primitive() == \ (1, 3**(Mul(S.Half, 1 + y, evaluate=False))) assert (5**Rational(3, 4)).as_content_primitive() == (1, 5**Rational(3, 4)) assert (5**Rational(7, 4)).as_content_primitive() == (5, 5**Rational(3, 4)) assert Add(z*Rational(5, 7), 0.5*x, y*Rational(3, 2), evaluate=False).as_content_primitive() == \ (Rational(1, 14), 7.0*x + 21*y + 10*z) assert (2**Rational(3, 4) + 2**Rational(1, 4)*sqrt(3)).as_content_primitive(radical=True) == \ (1, 2**Rational(1, 4)*(sqrt(2) + sqrt(3))) def test_signsimp(): e = x*(-x + 1) + x*(x - 1) assert signsimp(Eq(e, 0)) is S.true assert Abs(x - 1) == Abs(1 - x) assert signsimp(y - x) == y - x assert signsimp(y - x, evaluate=False) == Mul(-1, x - y, evaluate=False) def test_besselsimp(): from sympy import besselj, besseli, cosh, cosine_transform, bessely assert besselsimp(exp(-I*pi*y/2)*besseli(y, z*exp_polar(I*pi/2))) == \ besselj(y, z) assert besselsimp(exp(-I*pi*a/2)*besseli(a, 2*sqrt(x)*exp_polar(I*pi/2))) == \ besselj(a, 2*sqrt(x)) assert besselsimp(sqrt(2)*sqrt(pi)*x**Rational(1, 4)*exp(I*pi/4)*exp(-I*pi*a/2) * besseli(Rational(-1, 2), sqrt(x)*exp_polar(I*pi/2)) * besseli(a, sqrt(x)*exp_polar(I*pi/2))/2) == \ besselj(a, sqrt(x)) * cos(sqrt(x)) assert besselsimp(besseli(Rational(-1, 2), z)) == \ sqrt(2)*cosh(z)/(sqrt(pi)*sqrt(z)) assert besselsimp(besseli(a, z*exp_polar(-I*pi/2))) == \ exp(-I*pi*a/2)*besselj(a, z) assert cosine_transform(1/t*sin(a/t), t, y) == \ sqrt(2)*sqrt(pi)*besselj(0, 2*sqrt(a)*sqrt(y))/2 assert besselsimp(x**2*(a*(-2*besselj(5*I, x) + besselj(-2 + 5*I, x) + besselj(2 + 5*I, x)) + b*(-2*bessely(5*I, x) + bessely(-2 + 5*I, x) + bessely(2 + 5*I, x)))/4 + x*(a*(besselj(-1 + 5*I, x)/2 - besselj(1 + 5*I, x)/2) + b*(bessely(-1 + 5*I, x)/2 - bessely(1 + 5*I, x)/2)) + (x**2 + 25)*(a*besselj(5*I, x) + b*bessely(5*I, x))) == 0 assert besselsimp(81*x**2*(a*(besselj(Rational(-5, 3), 9*x) - 2*besselj(Rational(1, 3), 9*x) + besselj(Rational(7, 3), 9*x)) + b*(bessely(Rational(-5, 3), 9*x) - 2*bessely(Rational(1, 3), 9*x) + bessely(Rational(7, 3), 9*x)))/4 + x*(a*(9*besselj(Rational(-2, 3), 9*x)/2 - 9*besselj(Rational(4, 3), 9*x)/2) + b*(9*bessely(Rational(-2, 3), 9*x)/2 - 9*bessely(Rational(4, 3), 9*x)/2)) + (81*x**2 - Rational(1, 9))*(a*besselj(Rational(1, 3), 9*x) + b*bessely(Rational(1, 3), 9*x))) == 0 assert besselsimp(besselj(a-1,x) + besselj(a+1, x) - 2*a*besselj(a, x)/x) == 0 assert besselsimp(besselj(a-1,x) + besselj(a+1, x) + besselj(a, x)) == (2*a + x)*besselj(a, x)/x assert besselsimp(x**2* besselj(a,x) + x**3*besselj(a+1, x) + besselj(a+2, x)) == \ 2*a*x*besselj(a + 1, x) + x**3*besselj(a + 1, x) - x**2*besselj(a + 2, x) + 2*x*besselj(a + 1, x) + besselj(a + 2, x) def test_Piecewise(): e1 = x*(x + y) - y*(x + y) e2 = sin(x)**2 + cos(x)**2 e3 = expand((x + y)*y/x) s1 = simplify(e1) s2 = simplify(e2) s3 = simplify(e3) assert simplify(Piecewise((e1, x < e2), (e3, True))) == \ Piecewise((s1, x < s2), (s3, True)) def test_polymorphism(): class A(Basic): def _eval_simplify(x, **kwargs): return S.One a = A(5, 2) assert simplify(a) == 1 def test_issue_from_PR1599(): n1, n2, n3, n4 = symbols('n1 n2 n3 n4', negative=True) assert simplify(I*sqrt(n1)) == -sqrt(-n1) def test_issue_6811(): eq = (x + 2*y)*(2*x + 2) assert simplify(eq) == (x + 1)*(x + 2*y)*2 # reject the 2-arg Mul -- these are a headache for test writing assert simplify(eq.expand()) == \ 2*x**2 + 4*x*y + 2*x + 4*y def test_issue_6920(): e = [cos(x) + I*sin(x), cos(x) - I*sin(x), cosh(x) - sinh(x), cosh(x) + sinh(x)] ok = [exp(I*x), exp(-I*x), exp(-x), exp(x)] # wrap in f to show that the change happens wherever ei occurs f = Function('f') assert [simplify(f(ei)).args[0] for ei in e] == ok def test_issue_7001(): from sympy.abc import r, R assert simplify(-(r*Piecewise((pi*Rational(4, 3), r <= R), (-8*pi*R**3/(3*r**3), True)) + 2*Piecewise((pi*r*Rational(4, 3), r <= R), (4*pi*R**3/(3*r**2), True)))/(4*pi*r)) == \ Piecewise((-1, r <= R), (0, True)) def test_inequality_no_auto_simplify(): # no simplify on creation but can be simplified lhs = cos(x)**2 + sin(x)**2 rhs = 2 e = Lt(lhs, rhs, evaluate=False) assert e is not S.true assert simplify(e) def test_issue_9398(): from sympy import Number, cancel assert cancel(1e-14) != 0 assert cancel(1e-14*I) != 0 assert simplify(1e-14) != 0 assert simplify(1e-14*I) != 0 assert (I*Number(1.)*Number(10)**Number(-14)).simplify() != 0 assert cancel(1e-20) != 0 assert cancel(1e-20*I) != 0 assert simplify(1e-20) != 0 assert simplify(1e-20*I) != 0 assert cancel(1e-100) != 0 assert cancel(1e-100*I) != 0 assert simplify(1e-100) != 0 assert simplify(1e-100*I) != 0 f = Float("1e-1000") assert cancel(f) != 0 assert cancel(f*I) != 0 assert simplify(f) != 0 assert simplify(f*I) != 0 def test_issue_9324_simplify(): M = MatrixSymbol('M', 10, 10) e = M[0, 0] + M[5, 4] + 1304 assert simplify(e) == e def test_issue_9817_simplify(): # simplify on trace of substituted explicit quadratic form of matrix # expressions (a scalar) should return without errors (AttributeError) # See issue #9817 and #9190 for the original bug more discussion on this from sympy.matrices.expressions import Identity, trace v = MatrixSymbol('v', 3, 1) A = MatrixSymbol('A', 3, 3) x = Matrix([i + 1 for i in range(3)]) X = Identity(3) quadratic = v.T * A * v assert simplify((trace(quadratic.as_explicit())).xreplace({v:x, A:X})) == 14 def test_issue_13474(): x = Symbol('x') assert simplify(x + csch(sinc(1))) == x + csch(sinc(1)) @_both_exp_pow def test_simplify_function_inverse(): # "inverse" attribute does not guarantee that f(g(x)) is x # so this simplification should not happen automatically. # See issue #12140 x, y = symbols('x, y') g = Function('g') class f(Function): def inverse(self, argindex=1): return g assert simplify(f(g(x))) == f(g(x)) assert inversecombine(f(g(x))) == x assert simplify(f(g(x)), inverse=True) == x assert simplify(f(g(sin(x)**2 + cos(x)**2)), inverse=True) == 1 assert simplify(f(g(x, y)), inverse=True) == f(g(x, y)) assert unchanged(asin, sin(x)) assert simplify(asin(sin(x))) == asin(sin(x)) assert simplify(2*asin(sin(3*x)), inverse=True) == 6*x assert simplify(log(exp(x))) == log(exp(x)) assert simplify(log(exp(x)), inverse=True) == x assert simplify(exp(log(x)), inverse=True) == x assert simplify(log(exp(x), 2), inverse=True) == x/log(2) assert simplify(log(exp(x), 2, evaluate=False), inverse=True) == x/log(2) def test_clear_coefficients(): from sympy.simplify.simplify import clear_coefficients assert clear_coefficients(4*y*(6*x + 3)) == (y*(2*x + 1), 0) assert clear_coefficients(4*y*(6*x + 3) - 2) == (y*(2*x + 1), Rational(1, 6)) assert clear_coefficients(4*y*(6*x + 3) - 2, x) == (y*(2*x + 1), x/12 + Rational(1, 6)) assert clear_coefficients(sqrt(2) - 2) == (sqrt(2), 2) assert clear_coefficients(4*sqrt(2) - 2) == (sqrt(2), S.Half) assert clear_coefficients(S(3), x) == (0, x - 3) assert clear_coefficients(S.Infinity, x) == (S.Infinity, x) assert clear_coefficients(-S.Pi, x) == (S.Pi, -x) assert clear_coefficients(2 - S.Pi/3, x) == (pi, -3*x + 6) def test_nc_simplify(): from sympy.simplify.simplify import nc_simplify from sympy.matrices.expressions import MatPow, Identity from sympy.core import Pow from functools import reduce a, b, c, d = symbols('a b c d', commutative = False) x = Symbol('x') A = MatrixSymbol("A", x, x) B = MatrixSymbol("B", x, x) C = MatrixSymbol("C", x, x) D = MatrixSymbol("D", x, x) subst = {a: A, b: B, c: C, d:D} funcs = {Add: lambda x,y: x+y, Mul: lambda x,y: x*y } def _to_matrix(expr): if expr in subst: return subst[expr] if isinstance(expr, Pow): return MatPow(_to_matrix(expr.args[0]), expr.args[1]) elif isinstance(expr, (Add, Mul)): return reduce(funcs[expr.func],[_to_matrix(a) for a in expr.args]) else: return expr*Identity(x) def _check(expr, simplified, deep=True, matrix=True): assert nc_simplify(expr, deep=deep) == simplified assert expand(expr) == expand(simplified) if matrix: m_simp = _to_matrix(simplified).doit(inv_expand=False) assert nc_simplify(_to_matrix(expr), deep=deep) == m_simp _check(a*b*a*b*a*b*c*(a*b)**3*c, ((a*b)**3*c)**2) _check(a*b*(a*b)**-2*a*b, 1) _check(a**2*b*a*b*a*b*(a*b)**-1, a*(a*b)**2, matrix=False) _check(b*a*b**2*a*b**2*a*b**2, b*(a*b**2)**3) _check(a*b*a**2*b*a**2*b*a**3, (a*b*a)**3*a**2) _check(a**2*b*a**4*b*a**4*b*a**2, (a**2*b*a**2)**3) _check(a**3*b*a**4*b*a**4*b*a, a**3*(b*a**4)**3*a**-3) _check(a*b*a*b + a*b*c*x*a*b*c, (a*b)**2 + x*(a*b*c)**2) _check(a*b*a*b*c*a*b*a*b*c, ((a*b)**2*c)**2) _check(b**-1*a**-1*(a*b)**2, a*b) _check(a**-1*b*c**-1, (c*b**-1*a)**-1) expr = a**3*b*a**4*b*a**4*b*a**2*b*a**2*(b*a**2)**2*b*a**2*b*a**2 for _ in range(10): expr *= a*b _check(expr, a**3*(b*a**4)**2*(b*a**2)**6*(a*b)**10) _check((a*b*a*b)**2, (a*b*a*b)**2, deep=False) _check(a*b*(c*d)**2, a*b*(c*d)**2) expr = b**-1*(a**-1*b**-1 - a**-1*c*b**-1)**-1*a**-1 assert nc_simplify(expr) == (1-c)**-1 # commutative expressions should be returned without an error assert nc_simplify(2*x**2) == 2*x**2 def test_issue_15965(): A = Sum(z*x**y, (x, 1, a)) anew = z*Sum(x**y, (x, 1, a)) B = Integral(x*y, x) bdo = x**2*y/2 assert simplify(A + B) == anew + bdo assert simplify(A) == anew assert simplify(B) == bdo assert simplify(B, doit=False) == y*Integral(x, x) def test_issue_17137(): assert simplify(cos(x)**I) == cos(x)**I assert simplify(cos(x)**(2 + 3*I)) == cos(x)**(2 + 3*I) def test_issue_21869(): x = Symbol('x', real=True) y = Symbol('y', real=True) expr = And(Eq(x**2, 4), Le(x, y)) assert expr.simplify() == expr expr = And(Eq(x**2, 4), Eq(x, 2)) assert expr.simplify() == Eq(x, 2) expr = And(Eq(x**3, x**2), Eq(x, 1)) assert expr.simplify() == Eq(x, 1) expr = And(Eq(sin(x), x**2), Eq(x, 0)) assert expr.simplify() == Eq(x, 0) expr = And(Eq(x**3, x**2), Eq(x, 2)) assert expr.simplify() == S.false expr = And(Eq(y, x**2), Eq(x, 1)) assert expr.simplify() == And(Eq(y,1), Eq(x, 1)) expr = And(Eq(y**2, 1), Eq(y, x**2), Eq(x, 1)) assert expr.simplify() == And(Eq(y,1), Eq(x, 1)) expr = And(Eq(y**2, 4), Eq(y, 2*x**2), Eq(x, 1)) assert expr.simplify() == And(Eq(y,2), Eq(x, 1)) expr = And(Eq(y**2, 4), Eq(y, x**2), Eq(x, 1)) assert expr.simplify() == S.false def test_issue_7971(): z = Integral(x, (x, 1, 1)) assert z != 0 assert simplify(z) is S.Zero @slow def test_issue_17141_slow(): # Should not give RecursionError assert simplify((2**acos(I+1)**2).rewrite('log')) == 2**((pi + 2*I*log(-1 + sqrt(1 - 2*I) + I))**2/4) def test_issue_17141(): # Check that there is no RecursionError assert simplify(x**(1 / acos(I))) == x**(2/(pi - 2*I*log(1 + sqrt(2)))) assert simplify(acos(-I)**2*acos(I)**2) == \ log(1 + sqrt(2))**4 + pi**2*log(1 + sqrt(2))**2/2 + pi**4/16 assert simplify(2**acos(I)**2) == 2**((pi - 2*I*log(1 + sqrt(2)))**2/4) p = 2**acos(I+1)**2 assert simplify(p) == p def test_simplify_kroneckerdelta(): i, j = symbols("i j") K = KroneckerDelta assert simplify(K(i, j)) == K(i, j) assert simplify(K(0, j)) == K(0, j) assert simplify(K(i, 0)) == K(i, 0) assert simplify(K(0, j).rewrite(Piecewise) * K(1, j)) == 0 assert simplify(K(1, i) + Piecewise((1, Eq(j, 2)), (0, True))) == K(1, i) + K(2, j) # issue 17214 assert simplify(K(0, j) * K(1, j)) == 0 n = Symbol('n', integer=True) assert simplify(K(0, n) * K(1, n)) == 0 M = Matrix(4, 4, lambda i, j: K(j - i, n) if i <= j else 0) assert simplify(M**2) == Matrix([[K(0, n), 0, K(1, n), 0], [0, K(0, n), 0, K(1, n)], [0, 0, K(0, n), 0], [0, 0, 0, K(0, n)]]) def test_issue_17292(): assert simplify(abs(x)/abs(x**2)) == 1/abs(x) # this is bigger than the issue: check that deep processing works assert simplify(5*abs((x**2 - 1)/(x - 1))) == 5*Abs(x + 1) def test_issue_19822(): expr = And(Gt(n-2, 1), Gt(n, 1)) assert simplify(expr) == Gt(n, 3) def test_issue_18645(): expr = And(Ge(x, 3), Le(x, 3)) assert simplify(expr) == Eq(x, 3) expr = And(Eq(x, 3), Le(x, 3)) assert simplify(expr) == Eq(x, 3) @XFAIL def test_issue_18642(): i = Symbol("i", integer=True) n = Symbol("n", integer=True) expr = And(Eq(i, 2 * n), Le(i, 2*n -1)) assert simplify(expr) == S.false @XFAIL def test_issue_18389(): n = Symbol("n", integer=True) expr = Eq(n, 0) | (n >= 1) assert simplify(expr) == Ge(n, 0) def test_issue_8373(): x = Symbol('x', real=True) assert simplify(Or(x < 1, x >= 1)) == S.true def test_issue_7950(): expr = And(Eq(x, 1), Eq(x, 2)) assert simplify(expr) == S.false def test_issue_19484(): assert simplify(sign(x) * Abs(x)) == x e = x + sign(x + x**3) assert simplify(Abs(x + x**3)*e) == x**3 + x*Abs(x**3 + x) + x e = x**2 + sign(x**3 + 1) assert simplify(Abs(x**3 + 1) * e) == x**3 + x**2*Abs(x**3 + 1) + 1 f = Function('f') e = x + sign(x + f(x)**3) assert simplify(Abs(x + f(x)**3) * e) == x*Abs(x + f(x)**3) + x + f(x)**3 def test_issue_19161(): polynomial = Poly('x**2').simplify() assert (polynomial-x**2).simplify() == 0 sympy-sympy-1.9/sympy/simplify/tests/test_sqrtdenest.py000066400000000000000000000163231412543434000237140ustar00rootroot00000000000000from sympy import ( sqrt, root, Symbol, sqrtdenest, Integral, cos, Rational, I, Integer) from sympy.simplify.sqrtdenest import ( _subsets as subsets, _sqrt_numeric_denest) from sympy.testing.pytest import slow r2, r3, r5, r6, r7, r10, r15, r29 = [sqrt(x) for x in [2, 3, 5, 6, 7, 10, 15, 29]] def test_sqrtdenest(): d = {sqrt(5 + 2 * r6): r2 + r3, sqrt(5. + 2 * r6): sqrt(5. + 2 * r6), sqrt(5. + 4*sqrt(5 + 2 * r6)): sqrt(5.0 + 4*r2 + 4*r3), sqrt(r2): sqrt(r2), sqrt(5 + r7): sqrt(5 + r7), sqrt(3 + sqrt(5 + 2*r7)): 3*r2*(5 + 2*r7)**Rational(1, 4)/(2*sqrt(6 + 3*r7)) + r2*sqrt(6 + 3*r7)/(2*(5 + 2*r7)**Rational(1, 4)), sqrt(3 + 2*r3): 3**Rational(3, 4)*(r6/2 + 3*r2/2)/3} for i in d: assert sqrtdenest(i) == d[i], i def test_sqrtdenest2(): assert sqrtdenest(sqrt(16 - 2*r29 + 2*sqrt(55 - 10*r29))) == \ r5 + sqrt(11 - 2*r29) e = sqrt(-r5 + sqrt(-2*r29 + 2*sqrt(-10*r29 + 55) + 16)) assert sqrtdenest(e) == root(-2*r29 + 11, 4) r = sqrt(1 + r7) assert sqrtdenest(sqrt(1 + r)) == sqrt(1 + r) e = sqrt(((1 + sqrt(1 + 2*sqrt(3 + r2 + r5)))**2).expand()) assert sqrtdenest(e) == 1 + sqrt(1 + 2*sqrt(r2 + r5 + 3)) assert sqrtdenest(sqrt(5*r3 + 6*r2)) == \ sqrt(2)*root(3, 4) + root(3, 4)**3 assert sqrtdenest(sqrt(((1 + r5 + sqrt(1 + r3))**2).expand())) == \ 1 + r5 + sqrt(1 + r3) assert sqrtdenest(sqrt(((1 + r5 + r7 + sqrt(1 + r3))**2).expand())) == \ 1 + sqrt(1 + r3) + r5 + r7 e = sqrt(((1 + cos(2) + cos(3) + sqrt(1 + r3))**2).expand()) assert sqrtdenest(e) == cos(3) + cos(2) + 1 + sqrt(1 + r3) e = sqrt(-2*r10 + 2*r2*sqrt(-2*r10 + 11) + 14) assert sqrtdenest(e) == sqrt(-2*r10 - 2*r2 + 4*r5 + 14) # check that the result is not more complicated than the input z = sqrt(-2*r29 + cos(2) + 2*sqrt(-10*r29 + 55) + 16) assert sqrtdenest(z) == z assert sqrtdenest(sqrt(r6 + sqrt(15))) == sqrt(r6 + sqrt(15)) z = sqrt(15 - 2*sqrt(31) + 2*sqrt(55 - 10*r29)) assert sqrtdenest(z) == z def test_sqrtdenest_rec(): assert sqrtdenest(sqrt(-4*sqrt(14) - 2*r6 + 4*sqrt(21) + 33)) == \ -r2 + r3 + 2*r7 assert sqrtdenest(sqrt(-28*r7 - 14*r5 + 4*sqrt(35) + 82)) == \ -7 + r5 + 2*r7 assert sqrtdenest(sqrt(6*r2/11 + 2*sqrt(22)/11 + 6*sqrt(11)/11 + 2)) == \ sqrt(11)*(r2 + 3 + sqrt(11))/11 assert sqrtdenest(sqrt(468*r3 + 3024*r2 + 2912*r6 + 19735)) == \ 9*r3 + 26 + 56*r6 z = sqrt(-490*r3 - 98*sqrt(115) - 98*sqrt(345) - 2107) assert sqrtdenest(z) == sqrt(-1)*(7*r5 + 7*r15 + 7*sqrt(23)) z = sqrt(-4*sqrt(14) - 2*r6 + 4*sqrt(21) + 34) assert sqrtdenest(z) == z assert sqrtdenest(sqrt(-8*r2 - 2*r5 + 18)) == -r10 + 1 + r2 + r5 assert sqrtdenest(sqrt(8*r2 + 2*r5 - 18)) == \ sqrt(-1)*(-r10 + 1 + r2 + r5) assert sqrtdenest(sqrt(8*r2/3 + 14*r5/3 + Rational(154, 9))) == \ -r10/3 + r2 + r5 + 3 assert sqrtdenest(sqrt(sqrt(2*r6 + 5) + sqrt(2*r7 + 8))) == \ sqrt(1 + r2 + r3 + r7) assert sqrtdenest(sqrt(4*r15 + 8*r5 + 12*r3 + 24)) == 1 + r3 + r5 + r15 w = 1 + r2 + r3 + r5 + r7 assert sqrtdenest(sqrt((w**2).expand())) == w z = sqrt((w**2).expand() + 1) assert sqrtdenest(z) == z z = sqrt(2*r10 + 6*r2 + 4*r5 + 12 + 10*r15 + 30*r3) assert sqrtdenest(z) == z def test_issue_6241(): z = sqrt( -320 + 32*sqrt(5) + 64*r15) assert sqrtdenest(z) == z def test_sqrtdenest3(): z = sqrt(13 - 2*r10 + 2*r2*sqrt(-2*r10 + 11)) assert sqrtdenest(z) == -1 + r2 + r10 assert sqrtdenest(z, max_iter=1) == -1 + sqrt(2) + sqrt(10) z = sqrt(sqrt(r2 + 2) + 2) assert sqrtdenest(z) == z assert sqrtdenest(sqrt(-2*r10 + 4*r2*sqrt(-2*r10 + 11) + 20)) == \ sqrt(-2*r10 - 4*r2 + 8*r5 + 20) assert sqrtdenest(sqrt((112 + 70*r2) + (46 + 34*r2)*r5)) == \ r10 + 5 + 4*r2 + 3*r5 z = sqrt(5 + sqrt(2*r6 + 5)*sqrt(-2*r29 + 2*sqrt(-10*r29 + 55) + 16)) r = sqrt(-2*r29 + 11) assert sqrtdenest(z) == sqrt(r2*r + r3*r + r10 + r15 + 5) @slow def test_sqrtdenest3_slow(): # Slow because of the equals, not the sqrtdenest # Using == does not work as 7*(sqrt(-2*r29 + 11) + r5) is expanded # automatically n = sqrt(2*r6/7 + 2*r7/7 + 2*sqrt(42)/7 + 2) d = sqrt(16 - 2*r29 + 2*sqrt(55 - 10*r29)) assert sqrtdenest(n/d).equals( r7*(1 + r6 + r7)/(7*(sqrt(-2*r29 + 11) + r5))) def test_sqrtdenest4(): # see Denest_en.pdf in https://github.com/sympy/sympy/issues/3192 z = sqrt(8 - r2*sqrt(5 - r5) - sqrt(3)*(1 + r5)) z1 = sqrtdenest(z) c = sqrt(-r5 + 5) z1 = ((-r15*c - r3*c + c + r5*c - r6 - r2 + r10 + sqrt(30))/4).expand() assert sqrtdenest(z) == z1 z = sqrt(2*r2*sqrt(r2 + 2) + 5*r2 + 4*sqrt(r2 + 2) + 8) assert sqrtdenest(z) == r2 + sqrt(r2 + 2) + 2 w = 2 + r2 + r3 + (1 + r3)*sqrt(2 + r2 + 5*r3) z = sqrt((w**2).expand()) assert sqrtdenest(z) == w.expand() def test_sqrt_symbolic_denest(): x = Symbol('x') z = sqrt(((1 + sqrt(sqrt(2 + x) + 3))**2).expand()) assert sqrtdenest(z) == sqrt((1 + sqrt(sqrt(2 + x) + 3))**2) z = sqrt(((1 + sqrt(sqrt(2 + cos(1)) + 3))**2).expand()) assert sqrtdenest(z) == 1 + sqrt(sqrt(2 + cos(1)) + 3) z = ((1 + cos(2))**4 + 1).expand() assert sqrtdenest(z) == z z = sqrt(((1 + sqrt(sqrt(2 + cos(3*x)) + 3))**2 + 1).expand()) assert sqrtdenest(z) == z c = cos(3) c2 = c**2 assert sqrtdenest(sqrt(2*sqrt(1 + r3)*c + c2 + 1 + r3*c2)) == \ -1 - sqrt(1 + r3)*c ra = sqrt(1 + r3) z = sqrt(20*ra*sqrt(3 + 3*r3) + 12*r3*ra*sqrt(3 + 3*r3) + 64*r3 + 112) assert sqrtdenest(z) == z def test_issue_5857(): from sympy.abc import x, y z = sqrt(1/(4*r3 + 7) + 1) ans = (r2 + r6)/(r3 + 2) assert sqrtdenest(z) == ans assert sqrtdenest(1 + z) == 1 + ans assert sqrtdenest(Integral(z + 1, (x, 1, 2))) == \ Integral(1 + ans, (x, 1, 2)) assert sqrtdenest(x + sqrt(y)) == x + sqrt(y) ans = (r2 + r6)/(r3 + 2) assert sqrtdenest(z) == ans assert sqrtdenest(1 + z) == 1 + ans assert sqrtdenest(Integral(z + 1, (x, 1, 2))) == \ Integral(1 + ans, (x, 1, 2)) assert sqrtdenest(x + sqrt(y)) == x + sqrt(y) def test_subsets(): assert subsets(1) == [[1]] assert subsets(4) == [ [1, 0, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 1, 0], [1, 0, 1, 0], [0, 1, 1, 0], [1, 1, 1, 0], [0, 0, 0, 1], [1, 0, 0, 1], [0, 1, 0, 1], [1, 1, 0, 1], [0, 0, 1, 1], [1, 0, 1, 1], [0, 1, 1, 1], [1, 1, 1, 1]] def test_issue_5653(): assert sqrtdenest( sqrt(2 + sqrt(2 + sqrt(2)))) == sqrt(2 + sqrt(2 + sqrt(2))) def test_issue_12420(): assert sqrtdenest((3 - sqrt(2)*sqrt(4 + 3*I) + 3*I)/2) == I e = 3 - sqrt(2)*sqrt(4 + I) + 3*I assert sqrtdenest(e) == e def test_sqrt_ratcomb(): assert sqrtdenest(sqrt(1 + r3) + sqrt(3 + 3*r3) - sqrt(10 + 6*r3)) == 0 def test_issue_18041(): e = -sqrt(-2 + 2*sqrt(3)*I) assert sqrtdenest(e) == -1 - sqrt(3)*I def test_issue_19914(): a = Integer(-8) b = Integer(-1) r = Integer(63) d2 = a*a - b*b*r assert _sqrt_numeric_denest(a, b, r, d2) == \ sqrt(14)*I/2 + 3*sqrt(2)*I/2 assert sqrtdenest(sqrt(-8-sqrt(63))) == sqrt(14)*I/2 + 3*sqrt(2)*I/2 sympy-sympy-1.9/sympy/simplify/tests/test_traversaltools.py000066400000000000000000000015531412543434000246030ustar00rootroot00000000000000"""Tools for applying functions to specified parts of expressions. """ from sympy.simplify.traversaltools import use from sympy import expand, factor, I from sympy.abc import x, y def test_use(): assert use(0, expand) == 0 f = (x + y)**2*x + 1 assert use(f, expand, level=0) == x**3 + 2*x**2*y + x*y**2 + + 1 assert use(f, expand, level=1) == x**3 + 2*x**2*y + x*y**2 + + 1 assert use(f, expand, level=2) == 1 + x*(2*x*y + x**2 + y**2) assert use(f, expand, level=3) == (x + y)**2*x + 1 f = (x**2 + 1)**2 - 1 kwargs = {'gaussian': True} assert use(f, factor, level=0, kwargs=kwargs) == x**2*(x**2 + 2) assert use(f, factor, level=1, kwargs=kwargs) == (x + I)**2*(x - I)**2 - 1 assert use(f, factor, level=2, kwargs=kwargs) == (x + I)**2*(x - I)**2 - 1 assert use(f, factor, level=3, kwargs=kwargs) == (x**2 + 1)**2 - 1 sympy-sympy-1.9/sympy/simplify/tests/test_trigsimp.py000066400000000000000000000441641412543434000233620ustar00rootroot00000000000000from sympy import ( symbols, sin, simplify, cos, trigsimp, tan, exptrigsimp,sinh, cosh, diff, cot, Subs, exp, tanh, S, integrate, I,Matrix, Symbol, coth, pi, log, count_ops, sqrt, E, expand, Piecewise , Rational ) from sympy.testing.pytest import XFAIL from sympy.abc import x, y def test_trigsimp1(): x, y = symbols('x,y') assert trigsimp(1 - sin(x)**2) == cos(x)**2 assert trigsimp(1 - cos(x)**2) == sin(x)**2 assert trigsimp(sin(x)**2 + cos(x)**2) == 1 assert trigsimp(1 + tan(x)**2) == 1/cos(x)**2 assert trigsimp(1/cos(x)**2 - 1) == tan(x)**2 assert trigsimp(1/cos(x)**2 - tan(x)**2) == 1 assert trigsimp(1 + cot(x)**2) == 1/sin(x)**2 assert trigsimp(1/sin(x)**2 - 1) == 1/tan(x)**2 assert trigsimp(1/sin(x)**2 - cot(x)**2) == 1 assert trigsimp(5*cos(x)**2 + 5*sin(x)**2) == 5 assert trigsimp(5*cos(x/2)**2 + 2*sin(x/2)**2) == 3*cos(x)/2 + Rational(7, 2) assert trigsimp(sin(x)/cos(x)) == tan(x) assert trigsimp(2*tan(x)*cos(x)) == 2*sin(x) assert trigsimp(cot(x)**3*sin(x)**3) == cos(x)**3 assert trigsimp(y*tan(x)**2/sin(x)**2) == y/cos(x)**2 assert trigsimp(cot(x)/cos(x)) == 1/sin(x) assert trigsimp(sin(x + y) + sin(x - y)) == 2*sin(x)*cos(y) assert trigsimp(sin(x + y) - sin(x - y)) == 2*sin(y)*cos(x) assert trigsimp(cos(x + y) + cos(x - y)) == 2*cos(x)*cos(y) assert trigsimp(cos(x + y) - cos(x - y)) == -2*sin(x)*sin(y) assert trigsimp(tan(x + y) - tan(x)/(1 - tan(x)*tan(y))) == \ sin(y)/(-sin(y)*tan(x) + cos(y)) # -tan(y)/(tan(x)*tan(y) - 1) assert trigsimp(sinh(x + y) + sinh(x - y)) == 2*sinh(x)*cosh(y) assert trigsimp(sinh(x + y) - sinh(x - y)) == 2*sinh(y)*cosh(x) assert trigsimp(cosh(x + y) + cosh(x - y)) == 2*cosh(x)*cosh(y) assert trigsimp(cosh(x + y) - cosh(x - y)) == 2*sinh(x)*sinh(y) assert trigsimp(tanh(x + y) - tanh(x)/(1 + tanh(x)*tanh(y))) == \ sinh(y)/(sinh(y)*tanh(x) + cosh(y)) assert trigsimp(cos(0.12345)**2 + sin(0.12345)**2) == 1 e = 2*sin(x)**2 + 2*cos(x)**2 assert trigsimp(log(e)) == log(2) def test_trigsimp1a(): assert trigsimp(sin(2)**2*cos(3)*exp(2)/cos(2)**2) == tan(2)**2*cos(3)*exp(2) assert trigsimp(tan(2)**2*cos(3)*exp(2)*cos(2)**2) == sin(2)**2*cos(3)*exp(2) assert trigsimp(cot(2)*cos(3)*exp(2)*sin(2)) == cos(3)*exp(2)*cos(2) assert trigsimp(tan(2)*cos(3)*exp(2)/sin(2)) == cos(3)*exp(2)/cos(2) assert trigsimp(cot(2)*cos(3)*exp(2)/cos(2)) == cos(3)*exp(2)/sin(2) assert trigsimp(cot(2)*cos(3)*exp(2)*tan(2)) == cos(3)*exp(2) assert trigsimp(sinh(2)*cos(3)*exp(2)/cosh(2)) == tanh(2)*cos(3)*exp(2) assert trigsimp(tanh(2)*cos(3)*exp(2)*cosh(2)) == sinh(2)*cos(3)*exp(2) assert trigsimp(coth(2)*cos(3)*exp(2)*sinh(2)) == cosh(2)*cos(3)*exp(2) assert trigsimp(tanh(2)*cos(3)*exp(2)/sinh(2)) == cos(3)*exp(2)/cosh(2) assert trigsimp(coth(2)*cos(3)*exp(2)/cosh(2)) == cos(3)*exp(2)/sinh(2) assert trigsimp(coth(2)*cos(3)*exp(2)*tanh(2)) == cos(3)*exp(2) def test_trigsimp2(): x, y = symbols('x,y') assert trigsimp(cos(x)**2*sin(y)**2 + cos(x)**2*cos(y)**2 + sin(x)**2, recursive=True) == 1 assert trigsimp(sin(x)**2*sin(y)**2 + sin(x)**2*cos(y)**2 + cos(x)**2, recursive=True) == 1 assert trigsimp( Subs(x, x, sin(y)**2 + cos(y)**2)) == Subs(x, x, 1) def test_issue_4373(): x = Symbol("x") assert abs(trigsimp(2.0*sin(x)**2 + 2.0*cos(x)**2) - 2.0) < 1e-10 def test_trigsimp3(): x, y = symbols('x,y') assert trigsimp(sin(x)/cos(x)) == tan(x) assert trigsimp(sin(x)**2/cos(x)**2) == tan(x)**2 assert trigsimp(sin(x)**3/cos(x)**3) == tan(x)**3 assert trigsimp(sin(x)**10/cos(x)**10) == tan(x)**10 assert trigsimp(cos(x)/sin(x)) == 1/tan(x) assert trigsimp(cos(x)**2/sin(x)**2) == 1/tan(x)**2 assert trigsimp(cos(x)**10/sin(x)**10) == 1/tan(x)**10 assert trigsimp(tan(x)) == trigsimp(sin(x)/cos(x)) def test_issue_4661(): a, x, y = symbols('a x y') eq = -4*sin(x)**4 + 4*cos(x)**4 - 8*cos(x)**2 assert trigsimp(eq) == -4 n = sin(x)**6 + 4*sin(x)**4*cos(x)**2 + 5*sin(x)**2*cos(x)**4 + 2*cos(x)**6 d = -sin(x)**2 - 2*cos(x)**2 assert simplify(n/d) == -1 assert trigsimp(-2*cos(x)**2 + cos(x)**4 - sin(x)**4) == -1 eq = (- sin(x)**3/4)*cos(x) + (cos(x)**3/4)*sin(x) - sin(2*x)*cos(2*x)/8 assert trigsimp(eq) == 0 def test_issue_4494(): a, b = symbols('a b') eq = sin(a)**2*sin(b)**2 + cos(a)**2*cos(b)**2*tan(a)**2 + cos(a)**2 assert trigsimp(eq) == 1 def test_issue_5948(): a, x, y = symbols('a x y') assert trigsimp(diff(integrate(cos(x)/sin(x)**7, x), x)) == \ cos(x)/sin(x)**7 def test_issue_4775(): a, x, y = symbols('a x y') assert trigsimp(sin(x)*cos(y)+cos(x)*sin(y)) == sin(x + y) assert trigsimp(sin(x)*cos(y)+cos(x)*sin(y)+3) == sin(x + y) + 3 def test_issue_4280(): a, x, y = symbols('a x y') assert trigsimp(cos(x)**2 + cos(y)**2*sin(x)**2 + sin(y)**2*sin(x)**2) == 1 assert trigsimp(a**2*sin(x)**2 + a**2*cos(y)**2*cos(x)**2 + a**2*cos(x)**2*sin(y)**2) == a**2 assert trigsimp(a**2*cos(y)**2*sin(x)**2 + a**2*sin(y)**2*sin(x)**2) == a**2*sin(x)**2 def test_issue_3210(): eqs = (sin(2)*cos(3) + sin(3)*cos(2), -sin(2)*sin(3) + cos(2)*cos(3), sin(2)*cos(3) - sin(3)*cos(2), sin(2)*sin(3) + cos(2)*cos(3), sin(2)*sin(3) + cos(2)*cos(3) + cos(2), sinh(2)*cosh(3) + sinh(3)*cosh(2), sinh(2)*sinh(3) + cosh(2)*cosh(3), ) assert [trigsimp(e) for e in eqs] == [ sin(5), cos(5), -sin(1), cos(1), cos(1) + cos(2), sinh(5), cosh(5), ] def test_trigsimp_issues(): a, x, y = symbols('a x y') # issue 4625 - factor_terms works, too assert trigsimp(sin(x)**3 + cos(x)**2*sin(x)) == sin(x) # issue 5948 assert trigsimp(diff(integrate(cos(x)/sin(x)**3, x), x)) == \ cos(x)/sin(x)**3 assert trigsimp(diff(integrate(sin(x)/cos(x)**3, x), x)) == \ sin(x)/cos(x)**3 # check integer exponents e = sin(x)**y/cos(x)**y assert trigsimp(e) == e assert trigsimp(e.subs(y, 2)) == tan(x)**2 assert trigsimp(e.subs(x, 1)) == tan(1)**y # check for multiple patterns assert (cos(x)**2/sin(x)**2*cos(y)**2/sin(y)**2).trigsimp() == \ 1/tan(x)**2/tan(y)**2 assert trigsimp(cos(x)/sin(x)*cos(x+y)/sin(x+y)) == \ 1/(tan(x)*tan(x + y)) eq = cos(2)*(cos(3) + 1)**2/(cos(3) - 1)**2 assert trigsimp(eq) == eq.factor() # factor makes denom (-1 + cos(3))**2 assert trigsimp(cos(2)*(cos(3) + 1)**2*(cos(3) - 1)**2) == \ cos(2)*sin(3)**4 # issue 6789; this generates an expression that formerly caused # trigsimp to hang assert cot(x).equals(tan(x)) is False # nan or the unchanged expression is ok, but not sin(1) z = cos(x)**2 + sin(x)**2 - 1 z1 = tan(x)**2 - 1/cot(x)**2 n = (1 + z1/z) assert trigsimp(sin(n)) != sin(1) eq = x*(n - 1) - x*n assert trigsimp(eq) is S.NaN assert trigsimp(eq, recursive=True) is S.NaN assert trigsimp(1).is_Integer assert trigsimp(-sin(x)**4 - 2*sin(x)**2*cos(x)**2 - cos(x)**4) == -1 def test_trigsimp_issue_2515(): x = Symbol('x') assert trigsimp(x*cos(x)*tan(x)) == x*sin(x) assert trigsimp(-sin(x) + cos(x)*tan(x)) == 0 def test_trigsimp_issue_3826(): assert trigsimp(tan(2*x).expand(trig=True)) == tan(2*x) def test_trigsimp_issue_4032(): n = Symbol('n', integer=True, positive=True) assert trigsimp(2**(n/2)*cos(pi*n/4)/2 + 2**(n - 1)/2) == \ 2**(n/2)*cos(pi*n/4)/2 + 2**n/4 def test_trigsimp_issue_7761(): assert trigsimp(cosh(pi/4)) == cosh(pi/4) def test_trigsimp_noncommutative(): x, y = symbols('x,y') A, B = symbols('A,B', commutative=False) assert trigsimp(A - A*sin(x)**2) == A*cos(x)**2 assert trigsimp(A - A*cos(x)**2) == A*sin(x)**2 assert trigsimp(A*sin(x)**2 + A*cos(x)**2) == A assert trigsimp(A + A*tan(x)**2) == A/cos(x)**2 assert trigsimp(A/cos(x)**2 - A) == A*tan(x)**2 assert trigsimp(A/cos(x)**2 - A*tan(x)**2) == A assert trigsimp(A + A*cot(x)**2) == A/sin(x)**2 assert trigsimp(A/sin(x)**2 - A) == A/tan(x)**2 assert trigsimp(A/sin(x)**2 - A*cot(x)**2) == A assert trigsimp(y*A*cos(x)**2 + y*A*sin(x)**2) == y*A assert trigsimp(A*sin(x)/cos(x)) == A*tan(x) assert trigsimp(A*tan(x)*cos(x)) == A*sin(x) assert trigsimp(A*cot(x)**3*sin(x)**3) == A*cos(x)**3 assert trigsimp(y*A*tan(x)**2/sin(x)**2) == y*A/cos(x)**2 assert trigsimp(A*cot(x)/cos(x)) == A/sin(x) assert trigsimp(A*sin(x + y) + A*sin(x - y)) == 2*A*sin(x)*cos(y) assert trigsimp(A*sin(x + y) - A*sin(x - y)) == 2*A*sin(y)*cos(x) assert trigsimp(A*cos(x + y) + A*cos(x - y)) == 2*A*cos(x)*cos(y) assert trigsimp(A*cos(x + y) - A*cos(x - y)) == -2*A*sin(x)*sin(y) assert trigsimp(A*sinh(x + y) + A*sinh(x - y)) == 2*A*sinh(x)*cosh(y) assert trigsimp(A*sinh(x + y) - A*sinh(x - y)) == 2*A*sinh(y)*cosh(x) assert trigsimp(A*cosh(x + y) + A*cosh(x - y)) == 2*A*cosh(x)*cosh(y) assert trigsimp(A*cosh(x + y) - A*cosh(x - y)) == 2*A*sinh(x)*sinh(y) assert trigsimp(A*cos(0.12345)**2 + A*sin(0.12345)**2) == 1.0*A def test_hyperbolic_simp(): x, y = symbols('x,y') assert trigsimp(sinh(x)**2 + 1) == cosh(x)**2 assert trigsimp(cosh(x)**2 - 1) == sinh(x)**2 assert trigsimp(cosh(x)**2 - sinh(x)**2) == 1 assert trigsimp(1 - tanh(x)**2) == 1/cosh(x)**2 assert trigsimp(1 - 1/cosh(x)**2) == tanh(x)**2 assert trigsimp(tanh(x)**2 + 1/cosh(x)**2) == 1 assert trigsimp(coth(x)**2 - 1) == 1/sinh(x)**2 assert trigsimp(1/sinh(x)**2 + 1) == 1/tanh(x)**2 assert trigsimp(coth(x)**2 - 1/sinh(x)**2) == 1 assert trigsimp(5*cosh(x)**2 - 5*sinh(x)**2) == 5 assert trigsimp(5*cosh(x/2)**2 - 2*sinh(x/2)**2) == 3*cosh(x)/2 + Rational(7, 2) assert trigsimp(sinh(x)/cosh(x)) == tanh(x) assert trigsimp(tanh(x)) == trigsimp(sinh(x)/cosh(x)) assert trigsimp(cosh(x)/sinh(x)) == 1/tanh(x) assert trigsimp(2*tanh(x)*cosh(x)) == 2*sinh(x) assert trigsimp(coth(x)**3*sinh(x)**3) == cosh(x)**3 assert trigsimp(y*tanh(x)**2/sinh(x)**2) == y/cosh(x)**2 assert trigsimp(coth(x)/cosh(x)) == 1/sinh(x) for a in (pi/6*I, pi/4*I, pi/3*I): assert trigsimp(sinh(a)*cosh(x) + cosh(a)*sinh(x)) == sinh(x + a) assert trigsimp(-sinh(a)*cosh(x) + cosh(a)*sinh(x)) == sinh(x - a) e = 2*cosh(x)**2 - 2*sinh(x)**2 assert trigsimp(log(e)) == log(2) # issue 19535: assert trigsimp(sqrt(cosh(x)**2 - 1)) == sqrt(sinh(x)**2) assert trigsimp(cosh(x)**2*cosh(y)**2 - cosh(x)**2*sinh(y)**2 - sinh(x)**2, recursive=True) == 1 assert trigsimp(sinh(x)**2*sinh(y)**2 - sinh(x)**2*cosh(y)**2 + cosh(x)**2, recursive=True) == 1 assert abs(trigsimp(2.0*cosh(x)**2 - 2.0*sinh(x)**2) - 2.0) < 1e-10 assert trigsimp(sinh(x)**2/cosh(x)**2) == tanh(x)**2 assert trigsimp(sinh(x)**3/cosh(x)**3) == tanh(x)**3 assert trigsimp(sinh(x)**10/cosh(x)**10) == tanh(x)**10 assert trigsimp(cosh(x)**3/sinh(x)**3) == 1/tanh(x)**3 assert trigsimp(cosh(x)/sinh(x)) == 1/tanh(x) assert trigsimp(cosh(x)**2/sinh(x)**2) == 1/tanh(x)**2 assert trigsimp(cosh(x)**10/sinh(x)**10) == 1/tanh(x)**10 assert trigsimp(x*cosh(x)*tanh(x)) == x*sinh(x) assert trigsimp(-sinh(x) + cosh(x)*tanh(x)) == 0 assert tan(x) != 1/cot(x) # cot doesn't auto-simplify assert trigsimp(tan(x) - 1/cot(x)) == 0 assert trigsimp(3*tanh(x)**7 - 2/coth(x)**7) == tanh(x)**7 def test_trigsimp_groebner(): from sympy.simplify.trigsimp import trigsimp_groebner c = cos(x) s = sin(x) ex = (4*s*c + 12*s + 5*c**3 + 21*c**2 + 23*c + 15)/( -s*c**2 + 2*s*c + 15*s + 7*c**3 + 31*c**2 + 37*c + 21) resnum = (5*s - 5*c + 1) resdenom = (8*s - 6*c) results = [resnum/resdenom, (-resnum)/(-resdenom)] assert trigsimp_groebner(ex) in results assert trigsimp_groebner(s/c, hints=[tan]) == tan(x) assert trigsimp_groebner(c*s) == c*s assert trigsimp((-s + 1)/c + c/(-s + 1), method='groebner') == 2/c assert trigsimp((-s + 1)/c + c/(-s + 1), method='groebner', polynomial=True) == 2/c # Test quick=False works assert trigsimp_groebner(ex, hints=[2]) in results assert trigsimp_groebner(ex, hints=[int(2)]) in results # test "I" assert trigsimp_groebner(sin(I*x)/cos(I*x), hints=[tanh]) == I*tanh(x) # test hyperbolic / sums assert trigsimp_groebner((tanh(x)+tanh(y))/(1+tanh(x)*tanh(y)), hints=[(tanh, x, y)]) == tanh(x + y) def test_issue_2827_trigsimp_methods(): measure1 = lambda expr: len(str(expr)) measure2 = lambda expr: -count_ops(expr) # Return the most complicated result expr = (x + 1)/(x + sin(x)**2 + cos(x)**2) ans = Matrix([1]) M = Matrix([expr]) assert trigsimp(M, method='fu', measure=measure1) == ans assert trigsimp(M, method='fu', measure=measure2) != ans # all methods should work with Basic expressions even if they # aren't Expr M = Matrix.eye(1) assert all(trigsimp(M, method=m) == M for m in 'fu matching groebner old'.split()) # watch for E in exptrigsimp, not only exp() eq = 1/sqrt(E) + E assert exptrigsimp(eq) == eq def test_issue_15129_trigsimp_methods(): t1 = Matrix([sin(Rational(1, 50)), cos(Rational(1, 50)), 0]) t2 = Matrix([sin(Rational(1, 25)), cos(Rational(1, 25)), 0]) t3 = Matrix([cos(Rational(1, 25)), sin(Rational(1, 25)), 0]) r1 = t1.dot(t2) r2 = t1.dot(t3) assert trigsimp(r1) == cos(Rational(1, 50)) assert trigsimp(r2) == sin(Rational(3, 50)) def test_exptrigsimp(): def valid(a, b): from sympy.testing.randtest import verify_numerically as tn if not (tn(a, b) and a == b): return False return True assert exptrigsimp(exp(x) + exp(-x)) == 2*cosh(x) assert exptrigsimp(exp(x) - exp(-x)) == 2*sinh(x) assert exptrigsimp((2*exp(x)-2*exp(-x))/(exp(x)+exp(-x))) == 2*tanh(x) assert exptrigsimp((2*exp(2*x)-2)/(exp(2*x)+1)) == 2*tanh(x) e = [cos(x) + I*sin(x), cos(x) - I*sin(x), cosh(x) - sinh(x), cosh(x) + sinh(x)] ok = [exp(I*x), exp(-I*x), exp(-x), exp(x)] assert all(valid(i, j) for i, j in zip( [exptrigsimp(ei) for ei in e], ok)) ue = [cos(x) + sin(x), cos(x) - sin(x), cosh(x) + I*sinh(x), cosh(x) - I*sinh(x)] assert [exptrigsimp(ei) == ei for ei in ue] res = [] ok = [y*tanh(1), 1/(y*tanh(1)), I*y*tan(1), -I/(y*tan(1)), y*tanh(x), 1/(y*tanh(x)), I*y*tan(x), -I/(y*tan(x)), y*tanh(1 + I), 1/(y*tanh(1 + I))] for a in (1, I, x, I*x, 1 + I): w = exp(a) eq = y*(w - 1/w)/(w + 1/w) res.append(simplify(eq)) res.append(simplify(1/eq)) assert all(valid(i, j) for i, j in zip(res, ok)) for a in range(1, 3): w = exp(a) e = w + 1/w s = simplify(e) assert s == exptrigsimp(e) assert valid(s, 2*cosh(a)) e = w - 1/w s = simplify(e) assert s == exptrigsimp(e) assert valid(s, 2*sinh(a)) def test_exptrigsimp_noncommutative(): a,b = symbols('a b', commutative=False) x = Symbol('x', commutative=True) assert exp(a + x) == exptrigsimp(exp(a)*exp(x)) p = exp(a)*exp(b) - exp(b)*exp(a) assert p == exptrigsimp(p) != 0 def test_powsimp_on_numbers(): assert 2**(Rational(1, 3) - 2) == 2**Rational(1, 3)/4 @XFAIL def test_issue_6811_fail(): # from doc/src/modules/physics/mechanics/examples.rst, the current `eq` # at Line 576 (in different variables) was formerly the equivalent and # shorter expression given below...it would be nice to get the short one # back again xp, y, x, z = symbols('xp, y, x, z') eq = 4*(-19*sin(x)*y + 5*sin(3*x)*y + 15*cos(2*x)*z - 21*z)*xp/(9*cos(x) - 5*cos(3*x)) assert trigsimp(eq) == -2*(2*cos(x)*tan(x)*y + 3*z)*xp/cos(x) def test_Piecewise(): e1 = x*(x + y) - y*(x + y) e2 = sin(x)**2 + cos(x)**2 e3 = expand((x + y)*y/x) # s1 = simplify(e1) s2 = simplify(e2) # s3 = simplify(e3) # trigsimp tries not to touch non-trig containing args assert trigsimp(Piecewise((e1, e3 < e2), (e3, True))) == \ Piecewise((e1, e3 < s2), (e3, True)) def test_issue_21594(): assert simplify(exp(Rational(1,2)) + exp(Rational(-1,2))) == cosh(S.Half)*2 def test_trigsimp_old(): x, y = symbols('x,y') assert trigsimp(1 - sin(x)**2, old=True) == cos(x)**2 assert trigsimp(1 - cos(x)**2, old=True) == sin(x)**2 assert trigsimp(sin(x)**2 + cos(x)**2, old=True) == 1 assert trigsimp(1 + tan(x)**2, old=True) == 1/cos(x)**2 assert trigsimp(1/cos(x)**2 - 1, old=True) == tan(x)**2 assert trigsimp(1/cos(x)**2 - tan(x)**2, old=True) == 1 assert trigsimp(1 + cot(x)**2, old=True) == 1/sin(x)**2 assert trigsimp(1/sin(x)**2 - cot(x)**2, old=True) == 1 assert trigsimp(5*cos(x)**2 + 5*sin(x)**2, old=True) == 5 assert trigsimp(sin(x)/cos(x), old=True) == tan(x) assert trigsimp(2*tan(x)*cos(x), old=True) == 2*sin(x) assert trigsimp(cot(x)**3*sin(x)**3, old=True) == cos(x)**3 assert trigsimp(y*tan(x)**2/sin(x)**2, old=True) == y/cos(x)**2 assert trigsimp(cot(x)/cos(x), old=True) == 1/sin(x) assert trigsimp(sin(x + y) + sin(x - y), old=True) == 2*sin(x)*cos(y) assert trigsimp(sin(x + y) - sin(x - y), old=True) == 2*sin(y)*cos(x) assert trigsimp(cos(x + y) + cos(x - y), old=True) == 2*cos(x)*cos(y) assert trigsimp(cos(x + y) - cos(x - y), old=True) == -2*sin(x)*sin(y) assert trigsimp(sinh(x + y) + sinh(x - y), old=True) == 2*sinh(x)*cosh(y) assert trigsimp(sinh(x + y) - sinh(x - y), old=True) == 2*sinh(y)*cosh(x) assert trigsimp(cosh(x + y) + cosh(x - y), old=True) == 2*cosh(x)*cosh(y) assert trigsimp(cosh(x + y) - cosh(x - y), old=True) == 2*sinh(x)*sinh(y) assert trigsimp(cos(0.12345)**2 + sin(0.12345)**2, old=True) == 1 assert trigsimp(sin(x)/cos(x), old=True, method='combined') == tan(x) assert trigsimp(sin(x)/cos(x), old=True, method='groebner') == sin(x)/cos(x) assert trigsimp(sin(x)/cos(x), old=True, method='groebner', hints=[tan]) == tan(x) assert trigsimp(1-sin(sin(x)**2+cos(x)**2)**2, old=True, deep=True) == cos(1)**2 sympy-sympy-1.9/sympy/simplify/traversaltools.py000066400000000000000000000015751412543434000224060ustar00rootroot00000000000000"""Tools for applying functions to specified parts of expressions. """ from sympy.core import sympify def use(expr, func, level=0, args=(), kwargs={}): """ Use ``func`` to transform ``expr`` at the given level. Examples ======== >>> from sympy import use, expand >>> from sympy.abc import x, y >>> f = (x + y)**2*x + 1 >>> use(f, expand, level=2) x*(x**2 + 2*x*y + y**2) + 1 >>> expand(f) x**3 + 2*x**2*y + x*y**2 + 1 """ def _use(expr, level): if not level: return func(expr, *args, **kwargs) else: if expr.is_Atom: return expr else: level -= 1 _args = [] for arg in expr.args: _args.append(_use(arg, level)) return expr.__class__(*_args) return _use(sympify(expr), level) sympy-sympy-1.9/sympy/simplify/trigsimp.py000066400000000000000000001275631412543434000211660ustar00rootroot00000000000000from collections import defaultdict from functools import reduce from sympy.core import (sympify, Basic, S, Expr, expand_mul, factor_terms, Mul, Dummy, igcd, FunctionClass, Add, symbols, Wild, expand) from sympy.core.cache import cacheit from sympy.core.compatibility import iterable, SYMPY_INTS from sympy.core.function import count_ops, _mexpand from sympy.core.numbers import I, Integer from sympy.functions import sin, cos, exp, cosh, tanh, sinh, tan, cot, coth from sympy.functions.elementary.hyperbolic import HyperbolicFunction from sympy.functions.elementary.trigonometric import TrigonometricFunction from sympy.polys import Poly, factor, cancel, parallel_poly_from_expr from sympy.polys.domains import ZZ from sympy.polys.polyerrors import PolificationFailed from sympy.polys.polytools import groebner from sympy.simplify.cse_main import cse from sympy.strategies.core import identity from sympy.strategies.tree import greedy from sympy.utilities.misc import debug def trigsimp_groebner(expr, hints=[], quick=False, order="grlex", polynomial=False): """ Simplify trigonometric expressions using a groebner basis algorithm. Explanation =========== This routine takes a fraction involving trigonometric or hyperbolic expressions, and tries to simplify it. The primary metric is the total degree. Some attempts are made to choose the simplest possible expression of the minimal degree, but this is non-rigorous, and also very slow (see the ``quick=True`` option). If ``polynomial`` is set to True, instead of simplifying numerator and denominator together, this function just brings numerator and denominator into a canonical form. This is much faster, but has potentially worse results. However, if the input is a polynomial, then the result is guaranteed to be an equivalent polynomial of minimal degree. The most important option is hints. Its entries can be any of the following: - a natural number - a function - an iterable of the form (func, var1, var2, ...) - anything else, interpreted as a generator A number is used to indicate that the search space should be increased. A function is used to indicate that said function is likely to occur in a simplified expression. An iterable is used indicate that func(var1 + var2 + ...) is likely to occur in a simplified . An additional generator also indicates that it is likely to occur. (See examples below). This routine carries out various computationally intensive algorithms. The option ``quick=True`` can be used to suppress one particularly slow step (at the expense of potentially more complicated results, but never at the expense of increased total degree). Examples ======== >>> from sympy.abc import x, y >>> from sympy import sin, tan, cos, sinh, cosh, tanh >>> from sympy.simplify.trigsimp import trigsimp_groebner Suppose you want to simplify ``sin(x)*cos(x)``. Naively, nothing happens: >>> ex = sin(x)*cos(x) >>> trigsimp_groebner(ex) sin(x)*cos(x) This is because ``trigsimp_groebner`` only looks for a simplification involving just ``sin(x)`` and ``cos(x)``. You can tell it to also try ``2*x`` by passing ``hints=[2]``: >>> trigsimp_groebner(ex, hints=[2]) sin(2*x)/2 >>> trigsimp_groebner(sin(x)**2 - cos(x)**2, hints=[2]) -cos(2*x) Increasing the search space this way can quickly become expensive. A much faster way is to give a specific expression that is likely to occur: >>> trigsimp_groebner(ex, hints=[sin(2*x)]) sin(2*x)/2 Hyperbolic expressions are similarly supported: >>> trigsimp_groebner(sinh(2*x)/sinh(x)) 2*cosh(x) Note how no hints had to be passed, since the expression already involved ``2*x``. The tangent function is also supported. You can either pass ``tan`` in the hints, to indicate that tan should be tried whenever cosine or sine are, or you can pass a specific generator: >>> trigsimp_groebner(sin(x)/cos(x), hints=[tan]) tan(x) >>> trigsimp_groebner(sinh(x)/cosh(x), hints=[tanh(x)]) tanh(x) Finally, you can use the iterable form to suggest that angle sum formulae should be tried: >>> ex = (tan(x) + tan(y))/(1 - tan(x)*tan(y)) >>> trigsimp_groebner(ex, hints=[(tan, x, y)]) tan(x + y) """ # TODO # - preprocess by replacing everything by funcs we can handle # - optionally use cot instead of tan # - more intelligent hinting. # For example, if the ideal is small, and we have sin(x), sin(y), # add sin(x + y) automatically... ? # - algebraic numbers ... # - expressions of lowest degree are not distinguished properly # e.g. 1 - sin(x)**2 # - we could try to order the generators intelligently, so as to influence # which monomials appear in the quotient basis # THEORY # ------ # Ratsimpmodprime above can be used to "simplify" a rational function # modulo a prime ideal. "Simplify" mainly means finding an equivalent # expression of lower total degree. # # We intend to use this to simplify trigonometric functions. To do that, # we need to decide (a) which ring to use, and (b) modulo which ideal to # simplify. In practice, (a) means settling on a list of "generators" # a, b, c, ..., such that the fraction we want to simplify is a rational # function in a, b, c, ..., with coefficients in ZZ (integers). # (2) means that we have to decide what relations to impose on the # generators. There are two practical problems: # (1) The ideal has to be *prime* (a technical term). # (2) The relations have to be polynomials in the generators. # # We typically have two kinds of generators: # - trigonometric expressions, like sin(x), cos(5*x), etc # - "everything else", like gamma(x), pi, etc. # # Since this function is trigsimp, we will concentrate on what to do with # trigonometric expressions. We can also simplify hyperbolic expressions, # but the extensions should be clear. # # One crucial point is that all *other* generators really should behave # like indeterminates. In particular if (say) "I" is one of them, then # in fact I**2 + 1 = 0 and we may and will compute non-sensical # expressions. However, we can work with a dummy and add the relation # I**2 + 1 = 0 to our ideal, then substitute back in the end. # # Now regarding trigonometric generators. We split them into groups, # according to the argument of the trigonometric functions. We want to # organise this in such a way that most trigonometric identities apply in # the same group. For example, given sin(x), cos(2*x) and cos(y), we would # group as [sin(x), cos(2*x)] and [cos(y)]. # # Our prime ideal will be built in three steps: # (1) For each group, compute a "geometrically prime" ideal of relations. # Geometrically prime means that it generates a prime ideal in # CC[gens], not just ZZ[gens]. # (2) Take the union of all the generators of the ideals for all groups. # By the geometric primality condition, this is still prime. # (3) Add further inter-group relations which preserve primality. # # Step (1) works as follows. We will isolate common factors in the # argument, so that all our generators are of the form sin(n*x), cos(n*x) # or tan(n*x), with n an integer. Suppose first there are no tan terms. # The ideal [sin(x)**2 + cos(x)**2 - 1] is geometrically prime, since # X**2 + Y**2 - 1 is irreducible over CC. # Now, if we have a generator sin(n*x), than we can, using trig identities, # express sin(n*x) as a polynomial in sin(x) and cos(x). We can add this # relation to the ideal, preserving geometric primality, since the quotient # ring is unchanged. # Thus we have treated all sin and cos terms. # For tan(n*x), we add a relation tan(n*x)*cos(n*x) - sin(n*x) = 0. # (This requires of course that we already have relations for cos(n*x) and # sin(n*x).) It is not obvious, but it seems that this preserves geometric # primality. # XXX A real proof would be nice. HELP! # Sketch that is a prime ideal of # CC[S, C, T]: # - it suffices to show that the projective closure in CP**3 is # irreducible # - using the half-angle substitutions, we can express sin(x), tan(x), # cos(x) as rational functions in tan(x/2) # - from this, we get a rational map from CP**1 to our curve # - this is a morphism, hence the curve is prime # # Step (2) is trivial. # # Step (3) works by adding selected relations of the form # sin(x + y) - sin(x)*cos(y) - sin(y)*cos(x), etc. Geometric primality is # preserved by the same argument as before. def parse_hints(hints): """Split hints into (n, funcs, iterables, gens).""" n = 1 funcs, iterables, gens = [], [], [] for e in hints: if isinstance(e, (SYMPY_INTS, Integer)): n = e elif isinstance(e, FunctionClass): funcs.append(e) elif iterable(e): iterables.append((e[0], e[1:])) # XXX sin(x+2y)? # Note: we go through polys so e.g. # sin(-x) -> -sin(x) -> sin(x) gens.extend(parallel_poly_from_expr( [e[0](x) for x in e[1:]] + [e[0](Add(*e[1:]))])[1].gens) else: gens.append(e) return n, funcs, iterables, gens def build_ideal(x, terms): """ Build generators for our ideal. ``Terms`` is an iterable with elements of the form (fn, coeff), indicating that we have a generator fn(coeff*x). If any of the terms is trigonometric, sin(x) and cos(x) are guaranteed to appear in terms. Similarly for hyperbolic functions. For tan(n*x), sin(n*x) and cos(n*x) are guaranteed. """ I = [] y = Dummy('y') for fn, coeff in terms: for c, s, t, rel in ( [cos, sin, tan, cos(x)**2 + sin(x)**2 - 1], [cosh, sinh, tanh, cosh(x)**2 - sinh(x)**2 - 1]): if coeff == 1 and fn in [c, s]: I.append(rel) elif fn == t: I.append(t(coeff*x)*c(coeff*x) - s(coeff*x)) elif fn in [c, s]: cn = fn(coeff*y).expand(trig=True).subs(y, x) I.append(fn(coeff*x) - cn) return list(set(I)) def analyse_gens(gens, hints): """ Analyse the generators ``gens``, using the hints ``hints``. The meaning of ``hints`` is described in the main docstring. Return a new list of generators, and also the ideal we should work with. """ # First parse the hints n, funcs, iterables, extragens = parse_hints(hints) debug('n=%s' % n, 'funcs:', funcs, 'iterables:', iterables, 'extragens:', extragens) # We just add the extragens to gens and analyse them as before gens = list(gens) gens.extend(extragens) # remove duplicates funcs = list(set(funcs)) iterables = list(set(iterables)) gens = list(set(gens)) # all the functions we can do anything with allfuncs = {sin, cos, tan, sinh, cosh, tanh} # sin(3*x) -> ((3, x), sin) trigterms = [(g.args[0].as_coeff_mul(), g.func) for g in gens if g.func in allfuncs] # Our list of new generators - start with anything that we cannot # work with (i.e. is not a trigonometric term) freegens = [g for g in gens if g.func not in allfuncs] newgens = [] trigdict = {} for (coeff, var), fn in trigterms: trigdict.setdefault(var, []).append((coeff, fn)) res = [] # the ideal for key, val in trigdict.items(): # We have now assembeled a dictionary. Its keys are common # arguments in trigonometric expressions, and values are lists of # pairs (fn, coeff). x0, (fn, coeff) in trigdict means that we # need to deal with fn(coeff*x0). We take the rational gcd of the # coeffs, call it ``gcd``. We then use x = x0/gcd as "base symbol", # all other arguments are integral multiples thereof. # We will build an ideal which works with sin(x), cos(x). # If hint tan is provided, also work with tan(x). Moreover, if # n > 1, also work with sin(k*x) for k <= n, and similarly for cos # (and tan if the hint is provided). Finally, any generators which # the ideal does not work with but we need to accommodate (either # because it was in expr or because it was provided as a hint) # we also build into the ideal. # This selection process is expressed in the list ``terms``. # build_ideal then generates the actual relations in our ideal, # from this list. fns = [x[1] for x in val] val = [x[0] for x in val] gcd = reduce(igcd, val) terms = [(fn, v/gcd) for (fn, v) in zip(fns, val)] fs = set(funcs + fns) for c, s, t in ([cos, sin, tan], [cosh, sinh, tanh]): if any(x in fs for x in (c, s, t)): fs.add(c) fs.add(s) for fn in fs: for k in range(1, n + 1): terms.append((fn, k)) extra = [] for fn, v in terms: if fn == tan: extra.append((sin, v)) extra.append((cos, v)) if fn in [sin, cos] and tan in fs: extra.append((tan, v)) if fn == tanh: extra.append((sinh, v)) extra.append((cosh, v)) if fn in [sinh, cosh] and tanh in fs: extra.append((tanh, v)) terms.extend(extra) x = gcd*Mul(*key) r = build_ideal(x, terms) res.extend(r) newgens.extend({fn(v*x) for fn, v in terms}) # Add generators for compound expressions from iterables for fn, args in iterables: if fn == tan: # Tan expressions are recovered from sin and cos. iterables.extend([(sin, args), (cos, args)]) elif fn == tanh: # Tanh expressions are recovered from sihn and cosh. iterables.extend([(sinh, args), (cosh, args)]) else: dummys = symbols('d:%i' % len(args), cls=Dummy) expr = fn( Add(*dummys)).expand(trig=True).subs(list(zip(dummys, args))) res.append(fn(Add(*args)) - expr) if myI in gens: res.append(myI**2 + 1) freegens.remove(myI) newgens.append(myI) return res, freegens, newgens myI = Dummy('I') expr = expr.subs(S.ImaginaryUnit, myI) subs = [(myI, S.ImaginaryUnit)] num, denom = cancel(expr).as_numer_denom() try: (pnum, pdenom), opt = parallel_poly_from_expr([num, denom]) except PolificationFailed: return expr debug('initial gens:', opt.gens) ideal, freegens, gens = analyse_gens(opt.gens, hints) debug('ideal:', ideal) debug('new gens:', gens, " -- len", len(gens)) debug('free gens:', freegens, " -- len", len(gens)) # NOTE we force the domain to be ZZ to stop polys from injecting generators # (which is usually a sign of a bug in the way we build the ideal) if not gens: return expr G = groebner(ideal, order=order, gens=gens, domain=ZZ) debug('groebner basis:', list(G), " -- len", len(G)) # If our fraction is a polynomial in the free generators, simplify all # coefficients separately: from sympy.simplify.ratsimp import ratsimpmodprime if freegens and pdenom.has_only_gens(*set(gens).intersection(pdenom.gens)): num = Poly(num, gens=gens+freegens).eject(*gens) res = [] for monom, coeff in num.terms(): ourgens = set(parallel_poly_from_expr([coeff, denom])[1].gens) # We compute the transitive closure of all generators that can # be reached from our generators through relations in the ideal. changed = True while changed: changed = False for p in ideal: p = Poly(p) if not ourgens.issuperset(p.gens) and \ not p.has_only_gens(*set(p.gens).difference(ourgens)): changed = True ourgens.update(p.exclude().gens) # NOTE preserve order! realgens = [x for x in gens if x in ourgens] # The generators of the ideal have now been (implicitly) split # into two groups: those involving ourgens and those that don't. # Since we took the transitive closure above, these two groups # live in subgrings generated by a *disjoint* set of variables. # Any sensible groebner basis algorithm will preserve this disjoint # structure (i.e. the elements of the groebner basis can be split # similarly), and and the two subsets of the groebner basis then # form groebner bases by themselves. (For the smaller generating # sets, of course.) ourG = [g.as_expr() for g in G.polys if g.has_only_gens(*ourgens.intersection(g.gens))] res.append(Mul(*[a**b for a, b in zip(freegens, monom)]) * \ ratsimpmodprime(coeff/denom, ourG, order=order, gens=realgens, quick=quick, domain=ZZ, polynomial=polynomial).subs(subs)) return Add(*res) # NOTE The following is simpler and has less assumptions on the # groebner basis algorithm. If the above turns out to be broken, # use this. return Add(*[Mul(*[a**b for a, b in zip(freegens, monom)]) * \ ratsimpmodprime(coeff/denom, list(G), order=order, gens=gens, quick=quick, domain=ZZ) for monom, coeff in num.terms()]) else: return ratsimpmodprime( expr, list(G), order=order, gens=freegens+gens, quick=quick, domain=ZZ, polynomial=polynomial).subs(subs) _trigs = (TrigonometricFunction, HyperbolicFunction) def trigsimp(expr, **opts): """ reduces expression by using known trig identities Explanation =========== method: - Determine the method to use. Valid choices are 'matching' (default), 'groebner', 'combined', and 'fu'. If 'matching', simplify the expression recursively by targeting common patterns. If 'groebner', apply an experimental groebner basis algorithm. In this case further options are forwarded to ``trigsimp_groebner``, please refer to its docstring. If 'combined', first run the groebner basis algorithm with small default parameters, then run the 'matching' algorithm. 'fu' runs the collection of trigonometric transformations described by Fu, et al. (see the `fu` docstring). Examples ======== >>> from sympy import trigsimp, sin, cos, log >>> from sympy.abc import x >>> e = 2*sin(x)**2 + 2*cos(x)**2 >>> trigsimp(e) 2 Simplification occurs wherever trigonometric functions are located. >>> trigsimp(log(e)) log(2) Using `method="groebner"` (or `"combined"`) might lead to greater simplification. The old trigsimp routine can be accessed as with method 'old'. >>> from sympy import coth, tanh >>> t = 3*tanh(x)**7 - 2/coth(x)**7 >>> trigsimp(t, method='old') == t True >>> trigsimp(t) tanh(x)**7 """ from sympy.simplify.fu import fu expr = sympify(expr) _eval_trigsimp = getattr(expr, '_eval_trigsimp', None) if _eval_trigsimp is not None: return _eval_trigsimp(**opts) old = opts.pop('old', False) if not old: opts.pop('deep', None) opts.pop('recursive', None) method = opts.pop('method', 'matching') else: method = 'old' def groebnersimp(ex, **opts): def traverse(e): if e.is_Atom: return e args = [traverse(x) for x in e.args] if e.is_Function or e.is_Pow: args = [trigsimp_groebner(x, **opts) for x in args] return e.func(*args) new = traverse(ex) if not isinstance(new, Expr): return new return trigsimp_groebner(new, **opts) trigsimpfunc = { 'fu': (lambda x: fu(x, **opts)), 'matching': (lambda x: futrig(x)), 'groebner': (lambda x: groebnersimp(x, **opts)), 'combined': (lambda x: futrig(groebnersimp(x, polynomial=True, hints=[2, tan]))), 'old': lambda x: trigsimp_old(x, **opts), }[method] return trigsimpfunc(expr) def exptrigsimp(expr): """ Simplifies exponential / trigonometric / hyperbolic functions. Examples ======== >>> from sympy import exptrigsimp, exp, cosh, sinh >>> from sympy.abc import z >>> exptrigsimp(exp(z) + exp(-z)) 2*cosh(z) >>> exptrigsimp(cosh(z) - sinh(z)) exp(-z) """ from sympy.simplify.fu import hyper_as_trig, TR2i from sympy.simplify.simplify import bottom_up def exp_trig(e): # select the better of e, and e rewritten in terms of exp or trig # functions choices = [e] if e.has(*_trigs): choices.append(e.rewrite(exp)) choices.append(e.rewrite(cos)) return min(*choices, key=count_ops) newexpr = bottom_up(expr, exp_trig) def f(rv): if not rv.is_Mul: return rv commutative_part, noncommutative_part = rv.args_cnc() # Since as_powers_dict loses order information, # if there is more than one noncommutative factor, # it should only be used to simplify the commutative part. if (len(noncommutative_part) > 1): return f(Mul(*commutative_part))*Mul(*noncommutative_part) rvd = rv.as_powers_dict() newd = rvd.copy() def signlog(expr, sign=S.One): if expr is S.Exp1: return sign, S.One elif isinstance(expr, exp) or (expr.is_Pow and expr.base == S.Exp1): return sign, expr.exp elif sign is S.One: return signlog(-expr, sign=-S.One) else: return None, None ee = rvd[S.Exp1] for k in rvd: if k.is_Add and len(k.args) == 2: # k == c*(1 + sign*E**x) c = k.args[0] sign, x = signlog(k.args[1]/c) if not x: continue m = rvd[k] newd[k] -= m if ee == -x*m/2: # sinh and cosh newd[S.Exp1] -= ee ee = 0 if sign == 1: newd[2*c*cosh(x/2)] += m else: newd[-2*c*sinh(x/2)] += m elif newd[1 - sign*S.Exp1**x] == -m: # tanh del newd[1 - sign*S.Exp1**x] if sign == 1: newd[-c/tanh(x/2)] += m else: newd[-c*tanh(x/2)] += m else: newd[1 + sign*S.Exp1**x] += m newd[c] += m return Mul(*[k**newd[k] for k in newd]) newexpr = bottom_up(newexpr, f) # sin/cos and sinh/cosh ratios to tan and tanh, respectively if newexpr.has(HyperbolicFunction): e, f = hyper_as_trig(newexpr) newexpr = f(TR2i(e)) if newexpr.has(TrigonometricFunction): newexpr = TR2i(newexpr) # can we ever generate an I where there was none previously? if not (newexpr.has(I) and not expr.has(I)): expr = newexpr return expr #-------------------- the old trigsimp routines --------------------- def trigsimp_old(expr, *, first=True, **opts): """ Reduces expression by using known trig identities. Notes ===== deep: - Apply trigsimp inside all objects with arguments recursive: - Use common subexpression elimination (cse()) and apply trigsimp recursively (this is quite expensive if the expression is large) method: - Determine the method to use. Valid choices are 'matching' (default), 'groebner', 'combined', 'fu' and 'futrig'. If 'matching', simplify the expression recursively by pattern matching. If 'groebner', apply an experimental groebner basis algorithm. In this case further options are forwarded to ``trigsimp_groebner``, please refer to its docstring. If 'combined', first run the groebner basis algorithm with small default parameters, then run the 'matching' algorithm. 'fu' runs the collection of trigonometric transformations described by Fu, et al. (see the `fu` docstring) while `futrig` runs a subset of Fu-transforms that mimic the behavior of `trigsimp`. compare: - show input and output from `trigsimp` and `futrig` when different, but returns the `trigsimp` value. Examples ======== >>> from sympy import trigsimp, sin, cos, log, cot >>> from sympy.abc import x >>> e = 2*sin(x)**2 + 2*cos(x)**2 >>> trigsimp(e, old=True) 2 >>> trigsimp(log(e), old=True) log(2*sin(x)**2 + 2*cos(x)**2) >>> trigsimp(log(e), deep=True, old=True) log(2) Using `method="groebner"` (or `"combined"`) can sometimes lead to a lot more simplification: >>> e = (-sin(x) + 1)/cos(x) + cos(x)/(-sin(x) + 1) >>> trigsimp(e, old=True) (1 - sin(x))/cos(x) + cos(x)/(1 - sin(x)) >>> trigsimp(e, method="groebner", old=True) 2/cos(x) >>> trigsimp(1/cot(x)**2, compare=True, old=True) futrig: tan(x)**2 cot(x)**(-2) """ old = expr if first: if not expr.has(*_trigs): return expr trigsyms = set().union(*[t.free_symbols for t in expr.atoms(*_trigs)]) if len(trigsyms) > 1: from sympy.simplify.simplify import separatevars d = separatevars(expr) if d.is_Mul: d = separatevars(d, dict=True) or d if isinstance(d, dict): expr = 1 for k, v in d.items(): # remove hollow factoring was = v v = expand_mul(v) opts['first'] = False vnew = trigsimp(v, **opts) if vnew == v: vnew = was expr *= vnew old = expr else: if d.is_Add: for s in trigsyms: r, e = expr.as_independent(s) if r: opts['first'] = False expr = r + trigsimp(e, **opts) if not expr.is_Add: break old = expr recursive = opts.pop('recursive', False) deep = opts.pop('deep', False) method = opts.pop('method', 'matching') def groebnersimp(ex, deep, **opts): def traverse(e): if e.is_Atom: return e args = [traverse(x) for x in e.args] if e.is_Function or e.is_Pow: args = [trigsimp_groebner(x, **opts) for x in args] return e.func(*args) if deep: ex = traverse(ex) return trigsimp_groebner(ex, **opts) trigsimpfunc = { 'matching': (lambda x, d: _trigsimp(x, d)), 'groebner': (lambda x, d: groebnersimp(x, d, **opts)), 'combined': (lambda x, d: _trigsimp(groebnersimp(x, d, polynomial=True, hints=[2, tan]), d)) }[method] if recursive: w, g = cse(expr) g = trigsimpfunc(g[0], deep) for sub in reversed(w): g = g.subs(sub[0], sub[1]) g = trigsimpfunc(g, deep) result = g else: result = trigsimpfunc(expr, deep) if opts.get('compare', False): f = futrig(old) if f != result: print('\tfutrig:', f) return result def _dotrig(a, b): """Helper to tell whether ``a`` and ``b`` have the same sorts of symbols in them -- no need to test hyperbolic patterns against expressions that have no hyperbolics in them.""" return a.func == b.func and ( a.has(TrigonometricFunction) and b.has(TrigonometricFunction) or a.has(HyperbolicFunction) and b.has(HyperbolicFunction)) _trigpat = None def _trigpats(): global _trigpat a, b, c = symbols('a b c', cls=Wild) d = Wild('d', commutative=False) # for the simplifications like sinh/cosh -> tanh: # DO NOT REORDER THE FIRST 14 since these are assumed to be in this # order in _match_div_rewrite. matchers_division = ( (a*sin(b)**c/cos(b)**c, a*tan(b)**c, sin(b), cos(b)), (a*tan(b)**c*cos(b)**c, a*sin(b)**c, sin(b), cos(b)), (a*cot(b)**c*sin(b)**c, a*cos(b)**c, sin(b), cos(b)), (a*tan(b)**c/sin(b)**c, a/cos(b)**c, sin(b), cos(b)), (a*cot(b)**c/cos(b)**c, a/sin(b)**c, sin(b), cos(b)), (a*cot(b)**c*tan(b)**c, a, sin(b), cos(b)), (a*(cos(b) + 1)**c*(cos(b) - 1)**c, a*(-sin(b)**2)**c, cos(b) + 1, cos(b) - 1), (a*(sin(b) + 1)**c*(sin(b) - 1)**c, a*(-cos(b)**2)**c, sin(b) + 1, sin(b) - 1), (a*sinh(b)**c/cosh(b)**c, a*tanh(b)**c, S.One, S.One), (a*tanh(b)**c*cosh(b)**c, a*sinh(b)**c, S.One, S.One), (a*coth(b)**c*sinh(b)**c, a*cosh(b)**c, S.One, S.One), (a*tanh(b)**c/sinh(b)**c, a/cosh(b)**c, S.One, S.One), (a*coth(b)**c/cosh(b)**c, a/sinh(b)**c, S.One, S.One), (a*coth(b)**c*tanh(b)**c, a, S.One, S.One), (c*(tanh(a) + tanh(b))/(1 + tanh(a)*tanh(b)), tanh(a + b)*c, S.One, S.One), ) matchers_add = ( (c*sin(a)*cos(b) + c*cos(a)*sin(b) + d, sin(a + b)*c + d), (c*cos(a)*cos(b) - c*sin(a)*sin(b) + d, cos(a + b)*c + d), (c*sin(a)*cos(b) - c*cos(a)*sin(b) + d, sin(a - b)*c + d), (c*cos(a)*cos(b) + c*sin(a)*sin(b) + d, cos(a - b)*c + d), (c*sinh(a)*cosh(b) + c*sinh(b)*cosh(a) + d, sinh(a + b)*c + d), (c*cosh(a)*cosh(b) + c*sinh(a)*sinh(b) + d, cosh(a + b)*c + d), ) # for cos(x)**2 + sin(x)**2 -> 1 matchers_identity = ( (a*sin(b)**2, a - a*cos(b)**2), (a*tan(b)**2, a*(1/cos(b))**2 - a), (a*cot(b)**2, a*(1/sin(b))**2 - a), (a*sin(b + c), a*(sin(b)*cos(c) + sin(c)*cos(b))), (a*cos(b + c), a*(cos(b)*cos(c) - sin(b)*sin(c))), (a*tan(b + c), a*((tan(b) + tan(c))/(1 - tan(b)*tan(c)))), (a*sinh(b)**2, a*cosh(b)**2 - a), (a*tanh(b)**2, a - a*(1/cosh(b))**2), (a*coth(b)**2, a + a*(1/sinh(b))**2), (a*sinh(b + c), a*(sinh(b)*cosh(c) + sinh(c)*cosh(b))), (a*cosh(b + c), a*(cosh(b)*cosh(c) + sinh(b)*sinh(c))), (a*tanh(b + c), a*((tanh(b) + tanh(c))/(1 + tanh(b)*tanh(c)))), ) # Reduce any lingering artifacts, such as sin(x)**2 changing # to 1-cos(x)**2 when sin(x)**2 was "simpler" artifacts = ( (a - a*cos(b)**2 + c, a*sin(b)**2 + c, cos), (a - a*(1/cos(b))**2 + c, -a*tan(b)**2 + c, cos), (a - a*(1/sin(b))**2 + c, -a*cot(b)**2 + c, sin), (a - a*cosh(b)**2 + c, -a*sinh(b)**2 + c, cosh), (a - a*(1/cosh(b))**2 + c, a*tanh(b)**2 + c, cosh), (a + a*(1/sinh(b))**2 + c, a*coth(b)**2 + c, sinh), # same as above but with noncommutative prefactor (a*d - a*d*cos(b)**2 + c, a*d*sin(b)**2 + c, cos), (a*d - a*d*(1/cos(b))**2 + c, -a*d*tan(b)**2 + c, cos), (a*d - a*d*(1/sin(b))**2 + c, -a*d*cot(b)**2 + c, sin), (a*d - a*d*cosh(b)**2 + c, -a*d*sinh(b)**2 + c, cosh), (a*d - a*d*(1/cosh(b))**2 + c, a*d*tanh(b)**2 + c, cosh), (a*d + a*d*(1/sinh(b))**2 + c, a*d*coth(b)**2 + c, sinh), ) _trigpat = (a, b, c, d, matchers_division, matchers_add, matchers_identity, artifacts) return _trigpat def _replace_mul_fpowxgpow(expr, f, g, rexp, h, rexph): """Helper for _match_div_rewrite. Replace f(b_)**c_*g(b_)**(rexp(c_)) with h(b)**rexph(c) if f(b_) and g(b_) are both positive or if c_ is an integer. """ # assert expr.is_Mul and expr.is_commutative and f != g fargs = defaultdict(int) gargs = defaultdict(int) args = [] for x in expr.args: if x.is_Pow or x.func in (f, g): b, e = x.as_base_exp() if b.is_positive or e.is_integer: if b.func == f: fargs[b.args[0]] += e continue elif b.func == g: gargs[b.args[0]] += e continue args.append(x) common = set(fargs) & set(gargs) hit = False while common: key = common.pop() fe = fargs.pop(key) ge = gargs.pop(key) if fe == rexp(ge): args.append(h(key)**rexph(fe)) hit = True else: fargs[key] = fe gargs[key] = ge if not hit: return expr while fargs: key, e = fargs.popitem() args.append(f(key)**e) while gargs: key, e = gargs.popitem() args.append(g(key)**e) return Mul(*args) _idn = lambda x: x _midn = lambda x: -x _one = lambda x: S.One def _match_div_rewrite(expr, i): """helper for __trigsimp""" if i == 0: expr = _replace_mul_fpowxgpow(expr, sin, cos, _midn, tan, _idn) elif i == 1: expr = _replace_mul_fpowxgpow(expr, tan, cos, _idn, sin, _idn) elif i == 2: expr = _replace_mul_fpowxgpow(expr, cot, sin, _idn, cos, _idn) elif i == 3: expr = _replace_mul_fpowxgpow(expr, tan, sin, _midn, cos, _midn) elif i == 4: expr = _replace_mul_fpowxgpow(expr, cot, cos, _midn, sin, _midn) elif i == 5: expr = _replace_mul_fpowxgpow(expr, cot, tan, _idn, _one, _idn) # i in (6, 7) is skipped elif i == 8: expr = _replace_mul_fpowxgpow(expr, sinh, cosh, _midn, tanh, _idn) elif i == 9: expr = _replace_mul_fpowxgpow(expr, tanh, cosh, _idn, sinh, _idn) elif i == 10: expr = _replace_mul_fpowxgpow(expr, coth, sinh, _idn, cosh, _idn) elif i == 11: expr = _replace_mul_fpowxgpow(expr, tanh, sinh, _midn, cosh, _midn) elif i == 12: expr = _replace_mul_fpowxgpow(expr, coth, cosh, _midn, sinh, _midn) elif i == 13: expr = _replace_mul_fpowxgpow(expr, coth, tanh, _idn, _one, _idn) else: return None return expr def _trigsimp(expr, deep=False): # protect the cache from non-trig patterns; we only allow # trig patterns to enter the cache if expr.has(*_trigs): return __trigsimp(expr, deep) return expr @cacheit def __trigsimp(expr, deep=False): """recursive helper for trigsimp""" from sympy.simplify.fu import TR10i if _trigpat is None: _trigpats() a, b, c, d, matchers_division, matchers_add, \ matchers_identity, artifacts = _trigpat if expr.is_Mul: # do some simplifications like sin/cos -> tan: if not expr.is_commutative: com, nc = expr.args_cnc() expr = _trigsimp(Mul._from_args(com), deep)*Mul._from_args(nc) else: for i, (pattern, simp, ok1, ok2) in enumerate(matchers_division): if not _dotrig(expr, pattern): continue newexpr = _match_div_rewrite(expr, i) if newexpr is not None: if newexpr != expr: expr = newexpr break else: continue # use SymPy matching instead res = expr.match(pattern) if res and res.get(c, 0): if not res[c].is_integer: ok = ok1.subs(res) if not ok.is_positive: continue ok = ok2.subs(res) if not ok.is_positive: continue # if "a" contains any of trig or hyperbolic funcs with # argument "b" then skip the simplification if any(w.args[0] == res[b] for w in res[a].atoms( TrigonometricFunction, HyperbolicFunction)): continue # simplify and finish: expr = simp.subs(res) break # process below if expr.is_Add: args = [] for term in expr.args: if not term.is_commutative: com, nc = term.args_cnc() nc = Mul._from_args(nc) term = Mul._from_args(com) else: nc = S.One term = _trigsimp(term, deep) for pattern, result in matchers_identity: res = term.match(pattern) if res is not None: term = result.subs(res) break args.append(term*nc) if args != expr.args: expr = Add(*args) expr = min(expr, expand(expr), key=count_ops) if expr.is_Add: for pattern, result in matchers_add: if not _dotrig(expr, pattern): continue expr = TR10i(expr) if expr.has(HyperbolicFunction): res = expr.match(pattern) # if "d" contains any trig or hyperbolic funcs with # argument "a" or "b" then skip the simplification; # this isn't perfect -- see tests if res is None or not (a in res and b in res) or any( w.args[0] in (res[a], res[b]) for w in res[d].atoms( TrigonometricFunction, HyperbolicFunction)): continue expr = result.subs(res) break # Reduce any lingering artifacts, such as sin(x)**2 changing # to 1 - cos(x)**2 when sin(x)**2 was "simpler" for pattern, result, ex in artifacts: if not _dotrig(expr, pattern): continue # Substitute a new wild that excludes some function(s) # to help influence a better match. This is because # sometimes, for example, 'a' would match sec(x)**2 a_t = Wild('a', exclude=[ex]) pattern = pattern.subs(a, a_t) result = result.subs(a, a_t) m = expr.match(pattern) was = None while m and was != expr: was = expr if m[a_t] == 0 or \ -m[a_t] in m[c].args or m[a_t] + m[c] == 0: break if d in m and m[a_t]*m[d] + m[c] == 0: break expr = result.subs(m) m = expr.match(pattern) m.setdefault(c, S.Zero) elif expr.is_Mul or expr.is_Pow or deep and expr.args: expr = expr.func(*[_trigsimp(a, deep) for a in expr.args]) try: if not expr.has(*_trigs): raise TypeError e = expr.atoms(exp) new = expr.rewrite(exp, deep=deep) if new == e: raise TypeError fnew = factor(new) if fnew != new: new = sorted([new, factor(new)], key=count_ops)[0] # if all exp that were introduced disappeared then accept it if not (new.atoms(exp) - e): expr = new except TypeError: pass return expr #------------------- end of old trigsimp routines -------------------- def futrig(e, *, hyper=True, **kwargs): """Return simplified ``e`` using Fu-like transformations. This is not the "Fu" algorithm. This is called by default from ``trigsimp``. By default, hyperbolics subexpressions will be simplified, but this can be disabled by setting ``hyper=False``. Examples ======== >>> from sympy import trigsimp, tan, sinh, tanh >>> from sympy.simplify.trigsimp import futrig >>> from sympy.abc import x >>> trigsimp(1/tan(x)**2) tan(x)**(-2) >>> futrig(sinh(x)/tanh(x)) cosh(x) """ from sympy.simplify.fu import hyper_as_trig from sympy.simplify.simplify import bottom_up e = sympify(e) if not isinstance(e, Basic): return e if not e.args: return e old = e e = bottom_up(e, _futrig) if hyper and e.has(HyperbolicFunction): e, f = hyper_as_trig(e) e = f(bottom_up(e, _futrig)) if e != old and e.is_Mul and e.args[0].is_Rational: # redistribute leading coeff on 2-arg Add e = Mul(*e.as_coeff_Mul()) return e def _futrig(e): """Helper for futrig.""" from sympy.simplify.fu import ( TR1, TR2, TR3, TR2i, TR10, L, TR10i, TR8, TR6, TR15, TR16, TR111, TR5, TRmorrie, TR11, _TR11, TR14, TR22, TR12) from sympy.core.compatibility import _nodes if not e.has(TrigonometricFunction): return e if e.is_Mul: coeff, e = e.as_independent(TrigonometricFunction) else: coeff = None Lops = lambda x: (L(x), x.count_ops(), _nodes(x), len(x.args), x.is_Add) trigs = lambda x: x.has(TrigonometricFunction) tree = [identity, ( TR3, # canonical angles TR1, # sec-csc -> cos-sin TR12, # expand tan of sum lambda x: _eapply(factor, x, trigs), TR2, # tan-cot -> sin-cos [identity, lambda x: _eapply(_mexpand, x, trigs)], TR2i, # sin-cos ratio -> tan lambda x: _eapply(lambda i: factor(i.normal()), x, trigs), TR14, # factored identities TR5, # sin-pow -> cos_pow TR10, # sin-cos of sums -> sin-cos prod TR11, _TR11, TR6, # reduce double angles and rewrite cos pows lambda x: _eapply(factor, x, trigs), TR14, # factored powers of identities [identity, lambda x: _eapply(_mexpand, x, trigs)], TR10i, # sin-cos products > sin-cos of sums TRmorrie, [identity, TR8], # sin-cos products -> sin-cos of sums [identity, lambda x: TR2i(TR2(x))], # tan -> sin-cos -> tan [ lambda x: _eapply(expand_mul, TR5(x), trigs), lambda x: _eapply( expand_mul, TR15(x), trigs)], # pos/neg powers of sin [ lambda x: _eapply(expand_mul, TR6(x), trigs), lambda x: _eapply( expand_mul, TR16(x), trigs)], # pos/neg powers of cos TR111, # tan, sin, cos to neg power -> cot, csc, sec [identity, TR2i], # sin-cos ratio to tan [identity, lambda x: _eapply( expand_mul, TR22(x), trigs)], # tan-cot to sec-csc TR1, TR2, TR2i, [identity, lambda x: _eapply( factor_terms, TR12(x), trigs)], # expand tan of sum )] e = greedy(tree, objective=Lops)(e) if coeff is not None: e = coeff * e return e def _is_Expr(e): """_eapply helper to tell whether ``e`` and all its args are Exprs.""" from sympy import Derivative if isinstance(e, Derivative): return _is_Expr(e.expr) if not isinstance(e, Expr): return False return all(_is_Expr(i) for i in e.args) def _eapply(func, e, cond=None): """Apply ``func`` to ``e`` if all args are Exprs else only apply it to those args that *are* Exprs.""" if not isinstance(e, Expr): return e if _is_Expr(e) or not e.args: return func(e) return e.func(*[ _eapply(func, ei) if (cond is None or cond(ei)) else ei for ei in e.args]) sympy-sympy-1.9/sympy/solvers/000077500000000000000000000000001412543434000166015ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/__init__.py000066400000000000000000000042421412543434000207140ustar00rootroot00000000000000"""A module for solving all kinds of equations. Examples ======== >>> from sympy.solvers import solve >>> from sympy.abc import x >>> solve(x**5+5*x**4+10*x**3+10*x**2+5*x+1,x) [-1] """ from sympy.core.assumptions import check_assumptions, failing_assumptions from .solvers import solve, solve_linear_system, solve_linear_system_LU, \ solve_undetermined_coeffs, nsolve, solve_linear, checksol, \ det_quick, inv_quick from .diophantine import diophantine from .recurr import rsolve, rsolve_poly, rsolve_ratio, rsolve_hyper from .ode import checkodesol, classify_ode, dsolve, \ homogeneous_order from .polysys import solve_poly_system, solve_triangulated from .pde import pde_separate, pde_separate_add, pde_separate_mul, \ pdsolve, classify_pde, checkpdesol from .deutils import ode_order from .inequalities import reduce_inequalities, reduce_abs_inequality, \ reduce_abs_inequalities, solve_poly_inequality, solve_rational_inequalities, solve_univariate_inequality from .decompogen import decompogen from .solveset import solveset, linsolve, linear_eq_to_matrix, nonlinsolve, substitution # This is here instead of sympy/sets/__init__.py to avoid circular import issues from ..core.singleton import S Complexes = S.Complexes __all__ = [ 'solve', 'solve_linear_system', 'solve_linear_system_LU', 'solve_undetermined_coeffs', 'nsolve', 'solve_linear', 'checksol', 'det_quick', 'inv_quick', 'check_assumptions', 'failing_assumptions', 'diophantine', 'rsolve', 'rsolve_poly', 'rsolve_ratio', 'rsolve_hyper', 'checkodesol', 'classify_ode', 'dsolve', 'homogeneous_order', 'solve_poly_system', 'solve_triangulated', 'pde_separate', 'pde_separate_add', 'pde_separate_mul', 'pdsolve', 'classify_pde', 'checkpdesol', 'ode_order', 'reduce_inequalities', 'reduce_abs_inequality', 'reduce_abs_inequalities', 'solve_poly_inequality', 'solve_rational_inequalities', 'solve_univariate_inequality', 'decompogen', 'solveset', 'linsolve', 'linear_eq_to_matrix', 'nonlinsolve', 'substitution', # This is here instead of sympy/sets/__init__.py to avoid circular import issues 'Complexes', ] sympy-sympy-1.9/sympy/solvers/benchmarks/000077500000000000000000000000001412543434000207165ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/benchmarks/__init__.py000066400000000000000000000000001412543434000230150ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/benchmarks/bench_solvers.py000066400000000000000000000003211412543434000241200ustar00rootroot00000000000000from sympy import zeros, eye, Symbol, solve_linear_system N = 8 M = zeros(N, N + 1) M[:, :N] = eye(N) S = [Symbol('A%i' % i) for i in range(N)] def timeit_linsolve_trivial(): solve_linear_system(M, *S) sympy-sympy-1.9/sympy/solvers/bivariate.py000066400000000000000000000427321412543434000211310ustar00rootroot00000000000000from sympy.core.add import Add from sympy.core.compatibility import ordered from sympy.core.function import expand_log from sympy.core.power import Pow from sympy.core.singleton import S from sympy.core.symbol import Dummy from sympy.functions.elementary.exponential import (LambertW, exp, log) from sympy.functions.elementary.miscellaneous import root from sympy.polys.polyroots import roots from sympy.polys.polytools import Poly, factor from sympy.core.function import _mexpand from sympy.simplify.simplify import separatevars from sympy.simplify.radsimp import collect from sympy.simplify.simplify import powsimp from sympy.solvers.solvers import solve, _invert from sympy.utilities.iterables import uniq def _filtered_gens(poly, symbol): """process the generators of ``poly``, returning the set of generators that have ``symbol``. If there are two generators that are inverses of each other, prefer the one that has no denominator. Examples ======== >>> from sympy.solvers.bivariate import _filtered_gens >>> from sympy import Poly, exp >>> from sympy.abc import x >>> _filtered_gens(Poly(x + 1/x + exp(x)), x) {x, exp(x)} """ gens = {g for g in poly.gens if symbol in g.free_symbols} for g in list(gens): ag = 1/g if g in gens and ag in gens: if ag.as_numer_denom()[1] is not S.One: g = ag gens.remove(g) return gens def _mostfunc(lhs, func, X=None): """Returns the term in lhs which contains the most of the func-type things e.g. log(log(x)) wins over log(x) if both terms appear. ``func`` can be a function (exp, log, etc...) or any other SymPy object, like Pow. If ``X`` is not ``None``, then the function returns the term composed with the most ``func`` having the specified variable. Examples ======== >>> from sympy.solvers.bivariate import _mostfunc >>> from sympy.functions.elementary.exponential import exp >>> from sympy.abc import x, y >>> _mostfunc(exp(x) + exp(exp(x) + 2), exp) exp(exp(x) + 2) >>> _mostfunc(exp(x) + exp(exp(y) + 2), exp) exp(exp(y) + 2) >>> _mostfunc(exp(x) + exp(exp(y) + 2), exp, x) exp(x) >>> _mostfunc(x, exp, x) is None True >>> _mostfunc(exp(x) + exp(x*y), exp, x) exp(x) """ fterms = [tmp for tmp in lhs.atoms(func) if (not X or X.is_Symbol and X in tmp.free_symbols or not X.is_Symbol and tmp.has(X))] if len(fterms) == 1: return fterms[0] elif fterms: return max(list(ordered(fterms)), key=lambda x: x.count(func)) return None def _linab(arg, symbol): """Return ``a, b, X`` assuming ``arg`` can be written as ``a*X + b`` where ``X`` is a symbol-dependent factor and ``a`` and ``b`` are independent of ``symbol``. Examples ======== >>> from sympy.functions.elementary.exponential import exp >>> from sympy.solvers.bivariate import _linab >>> from sympy.abc import x, y >>> from sympy import S >>> _linab(S(2), x) (2, 0, 1) >>> _linab(2*x, x) (2, 0, x) >>> _linab(y + y*x + 2*x, x) (y + 2, y, x) >>> _linab(3 + 2*exp(x), x) (2, 3, exp(x)) """ from sympy.core.exprtools import factor_terms arg = factor_terms(arg.expand()) ind, dep = arg.as_independent(symbol) if arg.is_Mul and dep.is_Add: a, b, x = _linab(dep, symbol) return ind*a, ind*b, x if not arg.is_Add: b = 0 a, x = ind, dep else: b = ind a, x = separatevars(dep).as_independent(symbol, as_Add=False) if x.could_extract_minus_sign(): a = -a x = -x return a, b, x def _lambert(eq, x): """ Given an expression assumed to be in the form ``F(X, a..f) = a*log(b*X + c) + d*X + f = 0`` where X = g(x) and x = g^-1(X), return the Lambert solution, ``x = g^-1(-c/b + (a/d)*W(d/(a*b)*exp(c*d/a/b)*exp(-f/a)))``. """ eq = _mexpand(expand_log(eq)) mainlog = _mostfunc(eq, log, x) if not mainlog: return [] # violated assumptions other = eq.subs(mainlog, 0) if isinstance(-other, log): eq = (eq - other).subs(mainlog, mainlog.args[0]) mainlog = mainlog.args[0] if not isinstance(mainlog, log): return [] # violated assumptions other = -(-other).args[0] eq += other if not x in other.free_symbols: return [] # violated assumptions d, f, X2 = _linab(other, x) logterm = collect(eq - other, mainlog) a = logterm.as_coefficient(mainlog) if a is None or x in a.free_symbols: return [] # violated assumptions logarg = mainlog.args[0] b, c, X1 = _linab(logarg, x) if X1 != X2: return [] # violated assumptions # invert the generator X1 so we have x(u) u = Dummy('rhs') xusolns = solve(X1 - u, x) # There are infinitely many branches for LambertW # but only branches for k = -1 and 0 might be real. The k = 0 # branch is real and the k = -1 branch is real if the LambertW argumen # in in range [-1/e, 0]. Since `solve` does not return infinite # solutions we will only include the -1 branch if it tests as real. # Otherwise, inclusion of any LambertW in the solution indicates to # the user that there are imaginary solutions corresponding to # different k values. lambert_real_branches = [-1, 0] sol = [] # solution of the given Lambert equation is like # sol = -c/b + (a/d)*LambertW(arg, k), # where arg = d/(a*b)*exp((c*d-b*f)/a/b) and k in lambert_real_branches. # Instead of considering the single arg, `d/(a*b)*exp((c*d-b*f)/a/b)`, # the individual `p` roots obtained when writing `exp((c*d-b*f)/a/b)` # as `exp(A/p) = exp(A)**(1/p)`, where `p` is an Integer, are used. # calculating args for LambertW num, den = ((c*d-b*f)/a/b).as_numer_denom() p, den = den.as_coeff_Mul() e = exp(num/den) t = Dummy('t') args = [d/(a*b)*t for t in roots(t**p - e, t).keys()] # calculating solutions from args for arg in args: for k in lambert_real_branches: w = LambertW(arg, k) if k and not w.is_real: continue rhs = -c/b + (a/d)*w for xu in xusolns: sol.append(xu.subs(u, rhs)) return sol def _solve_lambert(f, symbol, gens): """Return solution to ``f`` if it is a Lambert-type expression else raise NotImplementedError. For ``f(X, a..f) = a*log(b*X + c) + d*X - f = 0`` the solution for ``X`` is ``X = -c/b + (a/d)*W(d/(a*b)*exp(c*d/a/b)*exp(f/a))``. There are a variety of forms for `f(X, a..f)` as enumerated below: 1a1) if B**B = R for R not in [0, 1] (since those cases would already be solved before getting here) then log of both sides gives log(B) + log(log(B)) = log(log(R)) and X = log(B), a = 1, b = 1, c = 0, d = 1, f = log(log(R)) 1a2) if B*(b*log(B) + c)**a = R then log of both sides gives log(B) + a*log(b*log(B) + c) = log(R) and X = log(B), d=1, f=log(R) 1b) if a*log(b*B + c) + d*B = R and X = B, f = R 2a) if (b*B + c)*exp(d*B + g) = R then log of both sides gives log(b*B + c) + d*B + g = log(R) and X = B, a = 1, f = log(R) - g 2b) if g*exp(d*B + h) - b*B = c then the log form is log(g) + d*B + h - log(b*B + c) = 0 and X = B, a = -1, f = -h - log(g) 3) if d*p**(a*B + g) - b*B = c then the log form is log(d) + (a*B + g)*log(p) - log(b*B + c) = 0 and X = B, a = -1, d = a*log(p), f = -log(d) - g*log(p) """ def _solve_even_degree_expr(expr, t, symbol): """Return the unique solutions of equations derived from ``expr`` by replacing ``t`` with ``+/- symbol``. Parameters ========== expr : Expr The expression which includes a dummy variable t to be replaced with +symbol and -symbol. symbol : Symbol The symbol for which a solution is being sought. Returns ======= List of unique solution of the two equations generated by replacing ``t`` with positive and negative ``symbol``. Notes ===== If ``expr = 2*log(t) + x/2` then solutions for ``2*log(x) + x/2 = 0`` and ``2*log(-x) + x/2 = 0`` are returned by this function. Though this may seem counter-intuitive, one must note that the ``expr`` being solved here has been derived from a different expression. For an expression like ``eq = x**2*g(x) = 1``, if we take the log of both sides we obtain ``log(x**2) + log(g(x)) = 0``. If x is positive then this simplifies to ``2*log(x) + log(g(x)) = 0``; the Lambert-solving routines will return solutions for this, but we must also consider the solutions for ``2*log(-x) + log(g(x))`` since those must also be a solution of ``eq`` which has the same value when the ``x`` in ``x**2`` is negated. If `g(x)` does not have even powers of symbol then we don't want to replace the ``x`` there with ``-x``. So the role of the ``t`` in the expression received by this function is to mark where ``+/-x`` should be inserted before obtaining the Lambert solutions. """ nlhs, plhs = [ expr.xreplace({t: sgn*symbol}) for sgn in (-1, 1)] sols = _solve_lambert(nlhs, symbol, gens) if plhs != nlhs: sols.extend(_solve_lambert(plhs, symbol, gens)) # uniq is needed for a case like # 2*log(t) - log(-z**2) + log(z + log(x) + log(z)) # where subtituting t with +/-x gives all the same solution; # uniq, rather than list(set()), is used to maintain canonical # order return list(uniq(sols)) nrhs, lhs = f.as_independent(symbol, as_Add=True) rhs = -nrhs lamcheck = [tmp for tmp in gens if (tmp.func in [exp, log] or (tmp.is_Pow and symbol in tmp.exp.free_symbols))] if not lamcheck: raise NotImplementedError() if lhs.is_Add or lhs.is_Mul: # replacing all even_degrees of symbol with dummy variable t # since these will need special handling; non-Add/Mul do not # need this handling t = Dummy('t', **symbol.assumptions0) lhs = lhs.replace( lambda i: # find symbol**even i.is_Pow and i.base == symbol and i.exp.is_even, lambda i: # replace t**even t**i.exp) if lhs.is_Add and lhs.has(t): t_indep = lhs.subs(t, 0) t_term = lhs - t_indep _rhs = rhs - t_indep if not t_term.is_Add and _rhs and not ( t_term.has(S.ComplexInfinity, S.NaN)): eq = expand_log(log(t_term) - log(_rhs)) return _solve_even_degree_expr(eq, t, symbol) elif lhs.is_Mul and rhs: # this needs to happen whether t is present or not lhs = expand_log(log(lhs), force=True) rhs = log(rhs) if lhs.has(t) and lhs.is_Add: # it expanded from Mul to Add eq = lhs - rhs return _solve_even_degree_expr(eq, t, symbol) # restore symbol in lhs lhs = lhs.xreplace({t: symbol}) lhs = powsimp(factor(lhs, deep=True)) # make sure we have inverted as completely as possible r = Dummy() i, lhs = _invert(lhs - r, symbol) rhs = i.xreplace({r: rhs}) # For the first forms: # # 1a1) B**B = R will arrive here as B*log(B) = log(R) # lhs is Mul so take log of both sides: # log(B) + log(log(B)) = log(log(R)) # 1a2) B*(b*log(B) + c)**a = R will arrive unchanged so # lhs is Mul, so take log of both sides: # log(B) + a*log(b*log(B) + c) = log(R) # 1b) d*log(a*B + b) + c*B = R will arrive unchanged so # lhs is Add, so isolate c*B and expand log of both sides: # log(c) + log(B) = log(R - d*log(a*B + b)) soln = [] if not soln: mainlog = _mostfunc(lhs, log, symbol) if mainlog: if lhs.is_Mul and rhs != 0: soln = _lambert(log(lhs) - log(rhs), symbol) elif lhs.is_Add: other = lhs.subs(mainlog, 0) if other and not other.is_Add and [ tmp for tmp in other.atoms(Pow) if symbol in tmp.free_symbols]: if not rhs: diff = log(other) - log(other - lhs) else: diff = log(lhs - other) - log(rhs - other) soln = _lambert(expand_log(diff), symbol) else: #it's ready to go soln = _lambert(lhs - rhs, symbol) # For the next forms, # # collect on main exp # 2a) (b*B + c)*exp(d*B + g) = R # lhs is mul, so take log of both sides: # log(b*B + c) + d*B = log(R) - g # 2b) g*exp(d*B + h) - b*B = R # lhs is add, so add b*B to both sides, # take the log of both sides and rearrange to give # log(R + b*B) - d*B = log(g) + h if not soln: mainexp = _mostfunc(lhs, exp, symbol) if mainexp: lhs = collect(lhs, mainexp) if lhs.is_Mul and rhs != 0: soln = _lambert(expand_log(log(lhs) - log(rhs)), symbol) elif lhs.is_Add: # move all but mainexp-containing term to rhs other = lhs.subs(mainexp, 0) mainterm = lhs - other rhs = rhs - other if (mainterm.could_extract_minus_sign() and rhs.could_extract_minus_sign()): mainterm *= -1 rhs *= -1 diff = log(mainterm) - log(rhs) soln = _lambert(expand_log(diff), symbol) # For the last form: # # 3) d*p**(a*B + g) - b*B = c # collect on main pow, add b*B to both sides, # take log of both sides and rearrange to give # a*B*log(p) - log(b*B + c) = -log(d) - g*log(p) if not soln: mainpow = _mostfunc(lhs, Pow, symbol) if mainpow and symbol in mainpow.exp.free_symbols: lhs = collect(lhs, mainpow) if lhs.is_Mul and rhs != 0: # b*B = 0 soln = _lambert(expand_log(log(lhs) - log(rhs)), symbol) elif lhs.is_Add: # move all but mainpow-containing term to rhs other = lhs.subs(mainpow, 0) mainterm = lhs - other rhs = rhs - other diff = log(mainterm) - log(rhs) soln = _lambert(expand_log(diff), symbol) if not soln: raise NotImplementedError('%s does not appear to have a solution in ' 'terms of LambertW' % f) return list(ordered(soln)) def bivariate_type(f, x, y, *, first=True): """Given an expression, f, 3 tests will be done to see what type of composite bivariate it might be, options for u(x, y) are:: x*y x+y x*y+x x*y+y If it matches one of these types, ``u(x, y)``, ``P(u)`` and dummy variable ``u`` will be returned. Solving ``P(u)`` for ``u`` and equating the solutions to ``u(x, y)`` and then solving for ``x`` or ``y`` is equivalent to solving the original expression for ``x`` or ``y``. If ``x`` and ``y`` represent two functions in the same variable, e.g. ``x = g(t)`` and ``y = h(t)``, then if ``u(x, y) - p`` can be solved for ``t`` then these represent the solutions to ``P(u) = 0`` when ``p`` are the solutions of ``P(u) = 0``. Only positive values of ``u`` are considered. Examples ======== >>> from sympy.solvers.solvers import solve >>> from sympy.solvers.bivariate import bivariate_type >>> from sympy.abc import x, y >>> eq = (x**2 - 3).subs(x, x + y) >>> bivariate_type(eq, x, y) (x + y, _u**2 - 3, _u) >>> uxy, pu, u = _ >>> usol = solve(pu, u); usol [sqrt(3)] >>> [solve(uxy - s) for s in solve(pu, u)] [[{x: -y + sqrt(3)}]] >>> all(eq.subs(s).equals(0) for sol in _ for s in sol) True """ u = Dummy('u', positive=True) if first: p = Poly(f, x, y) f = p.as_expr() _x = Dummy() _y = Dummy() rv = bivariate_type(Poly(f.subs({x: _x, y: _y}), _x, _y), _x, _y, first=False) if rv: reps = {_x: x, _y: y} return rv[0].xreplace(reps), rv[1].xreplace(reps), rv[2] return p = f f = p.as_expr() # f(x*y) args = Add.make_args(p.as_expr()) new = [] for a in args: a = _mexpand(a.subs(x, u/y)) free = a.free_symbols if x in free or y in free: break new.append(a) else: return x*y, Add(*new), u def ok(f, v, c): new = _mexpand(f.subs(v, c)) free = new.free_symbols return None if (x in free or y in free) else new # f(a*x + b*y) new = [] d = p.degree(x) if p.degree(y) == d: a = root(p.coeff_monomial(x**d), d) b = root(p.coeff_monomial(y**d), d) new = ok(f, x, (u - b*y)/a) if new is not None: return a*x + b*y, new, u # f(a*x*y + b*y) new = [] d = p.degree(x) if p.degree(y) == d: for itry in range(2): a = root(p.coeff_monomial(x**d*y**d), d) b = root(p.coeff_monomial(y**d), d) new = ok(f, x, (u - b*y)/a/y) if new is not None: return a*x*y + b*y, new, u x, y = y, x sympy-sympy-1.9/sympy/solvers/decompogen.py000066400000000000000000000061111412543434000212720ustar00rootroot00000000000000from sympy.core import (Function, Pow, sympify, Expr) from sympy.core.relational import Relational from sympy.polys import Poly, decompose from sympy.utilities.misc import func_name def decompogen(f, symbol): """ Computes General functional decomposition of ``f``. Given an expression ``f``, returns a list ``[f_1, f_2, ..., f_n]``, where:: f = f_1 o f_2 o ... f_n = f_1(f_2(... f_n)) Note: This is a General decomposition function. It also decomposes Polynomials. For only Polynomial decomposition see ``decompose`` in polys. Examples ======== >>> from sympy.solvers.decompogen import decompogen >>> from sympy.abc import x >>> from sympy import sqrt, sin, cos >>> decompogen(sin(cos(x)), x) [sin(x), cos(x)] >>> decompogen(sin(x)**2 + sin(x) + 1, x) [x**2 + x + 1, sin(x)] >>> decompogen(sqrt(6*x**2 - 5), x) [sqrt(x), 6*x**2 - 5] >>> decompogen(sin(sqrt(cos(x**2 + 1))), x) [sin(x), sqrt(x), cos(x), x**2 + 1] >>> decompogen(x**4 + 2*x**3 - x - 1, x) [x**2 - x - 1, x**2 + x] """ f = sympify(f) if not isinstance(f, Expr) or isinstance(f, Relational): raise TypeError('expecting Expr but got: `%s`' % func_name(f)) if symbol not in f.free_symbols: return [f] result = [] # ===== Simple Functions ===== # if isinstance(f, (Function, Pow)): from sympy import S if f.is_Pow and f.base == S.Exp1: arg = f.exp else: arg = f.args[0] if arg == symbol: return [f] result += [f.subs(arg, symbol)] + decompogen(arg, symbol) return result # ===== Convert to Polynomial ===== # fp = Poly(f) gens = list(filter(lambda x: symbol in x.free_symbols , fp.gens)) if len(gens) == 1 and gens[0] != symbol: f1 = f.subs(gens[0], symbol) f2 = gens[0] result += [f1] + decompogen(f2, symbol) return result # ===== Polynomial decompose() ====== # try: result += decompose(f) return result except ValueError: return [f] def compogen(g_s, symbol): """ Returns the composition of functions. Given a list of functions ``g_s``, returns their composition ``f``, where: f = g_1 o g_2 o .. o g_n Note: This is a General composition function. It also composes Polynomials. For only Polynomial composition see ``compose`` in polys. Examples ======== >>> from sympy.solvers.decompogen import compogen >>> from sympy.abc import x >>> from sympy import sqrt, sin, cos >>> compogen([sin(x), cos(x)], x) sin(cos(x)) >>> compogen([x**2 + x + 1, sin(x)], x) sin(x)**2 + sin(x) + 1 >>> compogen([sqrt(x), 6*x**2 - 5], x) sqrt(6*x**2 - 5) >>> compogen([sin(x), sqrt(x), cos(x), x**2 + 1], x) sin(sqrt(cos(x**2 + 1))) >>> compogen([x**2 - x - 1, x**2 + x], x) -x**2 - x + (x**2 + x)**2 - 1 """ if len(g_s) == 1: return g_s[0] foo = g_s[0].subs(symbol, g_s[1]) if len(g_s) == 2: return foo return compogen([foo] + g_s[2:], symbol) sympy-sympy-1.9/sympy/solvers/deutils.py000066400000000000000000000241421412543434000206270ustar00rootroot00000000000000"""Utility functions for classifying and solving ordinary and partial differential equations. Contains ======== _preprocess ode_order _desolve """ from sympy.core import Pow from sympy.core.function import Derivative, AppliedUndef from sympy.core.relational import Equality from sympy.core.symbol import Wild def _preprocess(expr, func=None, hint='_Integral'): """Prepare expr for solving by making sure that differentiation is done so that only func remains in unevaluated derivatives and (if hint doesn't end with _Integral) that doit is applied to all other derivatives. If hint is None, don't do any differentiation. (Currently this may cause some simple differential equations to fail.) In case func is None, an attempt will be made to autodetect the function to be solved for. >>> from sympy.solvers.deutils import _preprocess >>> from sympy import Derivative, Function >>> from sympy.abc import x, y, z >>> f, g = map(Function, 'fg') If f(x)**p == 0 and p>0 then we can solve for f(x)=0 >>> _preprocess((f(x).diff(x)-4)**5, f(x)) (Derivative(f(x), x) - 4, f(x)) Apply doit to derivatives that contain more than the function of interest: >>> _preprocess(Derivative(f(x) + x, x)) (Derivative(f(x), x) + 1, f(x)) Do others if the differentiation variable(s) intersect with those of the function of interest or contain the function of interest: >>> _preprocess(Derivative(g(x), y, z), f(y)) (0, f(y)) >>> _preprocess(Derivative(f(y), z), f(y)) (0, f(y)) Do others if the hint doesn't end in '_Integral' (the default assumes that it does): >>> _preprocess(Derivative(g(x), y), f(x)) (Derivative(g(x), y), f(x)) >>> _preprocess(Derivative(f(x), y), f(x), hint='') (0, f(x)) Don't do any derivatives if hint is None: >>> eq = Derivative(f(x) + 1, x) + Derivative(f(x), y) >>> _preprocess(eq, f(x), hint=None) (Derivative(f(x) + 1, x) + Derivative(f(x), y), f(x)) If it's not clear what the function of interest is, it must be given: >>> eq = Derivative(f(x) + g(x), x) >>> _preprocess(eq, g(x)) (Derivative(f(x), x) + Derivative(g(x), x), g(x)) >>> try: _preprocess(eq) ... except ValueError: print("A ValueError was raised.") A ValueError was raised. """ if isinstance(expr, Pow): # if f(x)**p=0 then f(x)=0 (p>0) if (expr.exp).is_positive: expr = expr.base derivs = expr.atoms(Derivative) if not func: funcs = set().union(*[d.atoms(AppliedUndef) for d in derivs]) if len(funcs) != 1: raise ValueError('The function cannot be ' 'automatically detected for %s.' % expr) func = funcs.pop() fvars = set(func.args) if hint is None: return expr, func reps = [(d, d.doit()) for d in derivs if not hint.endswith('_Integral') or d.has(func) or set(d.variables) & fvars] eq = expr.subs(reps) return eq, func def ode_order(expr, func): """ Returns the order of a given differential equation with respect to func. This function is implemented recursively. Examples ======== >>> from sympy import Function >>> from sympy.solvers.deutils import ode_order >>> from sympy.abc import x >>> f, g = map(Function, ['f', 'g']) >>> ode_order(f(x).diff(x, 2) + f(x).diff(x)**2 + ... f(x).diff(x), f(x)) 2 >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), f(x)) 2 >>> ode_order(f(x).diff(x, 2) + g(x).diff(x, 3), g(x)) 3 """ a = Wild('a', exclude=[func]) if expr.match(a): return 0 if isinstance(expr, Derivative): if expr.args[0] == func: return len(expr.variables) else: order = 0 for arg in expr.args[0].args: order = max(order, ode_order(arg, func) + len(expr.variables)) return order else: order = 0 for arg in expr.args: order = max(order, ode_order(arg, func)) return order def _desolve(eq, func=None, hint="default", ics=None, simplify=True, *, prep=True, **kwargs): """This is a helper function to dsolve and pdsolve in the ode and pde modules. If the hint provided to the function is "default", then a dict with the following keys are returned 'func' - It provides the function for which the differential equation has to be solved. This is useful when the expression has more than one function in it. 'default' - The default key as returned by classifier functions in ode and pde.py 'hint' - The hint given by the user for which the differential equation is to be solved. If the hint given by the user is 'default', then the value of 'hint' and 'default' is the same. 'order' - The order of the function as returned by ode_order 'match' - It returns the match as given by the classifier functions, for the default hint. If the hint provided to the function is not "default" and is not in ('all', 'all_Integral', 'best'), then a dict with the above mentioned keys is returned along with the keys which are returned when dict in classify_ode or classify_pde is set True If the hint given is in ('all', 'all_Integral', 'best'), then this function returns a nested dict, with the keys, being the set of classified hints returned by classifier functions, and the values being the dict of form as mentioned above. Key 'eq' is a common key to all the above mentioned hints which returns an expression if eq given by user is an Equality. See Also ======== classify_ode(ode.py) classify_pde(pde.py) """ if isinstance(eq, Equality): eq = eq.lhs - eq.rhs # preprocess the equation and find func if not given if prep or func is None: eq, func = _preprocess(eq, func) prep = False # type is an argument passed by the solve functions in ode and pde.py # that identifies whether the function caller is an ordinary # or partial differential equation. Accordingly corresponding # changes are made in the function. type = kwargs.get('type', None) xi = kwargs.get('xi') eta = kwargs.get('eta') x0 = kwargs.get('x0', 0) terms = kwargs.get('n') if type == 'ode': from sympy.solvers.ode import classify_ode, allhints classifier = classify_ode string = 'ODE ' dummy = '' elif type == 'pde': from sympy.solvers.pde import classify_pde, allhints classifier = classify_pde string = 'PDE ' dummy = 'p' # Magic that should only be used internally. Prevents classify_ode from # being called more than it needs to be by passing its results through # recursive calls. if kwargs.get('classify', True): hints = classifier(eq, func, dict=True, ics=ics, xi=xi, eta=eta, n=terms, x0=x0, hint=hint, prep=prep) else: # Here is what all this means: # # hint: The hint method given to _desolve() by the user. # hints: The dictionary of hints that match the DE, along with other # information (including the internal pass-through magic). # default: The default hint to return, the first hint from allhints # that matches the hint; obtained from classify_ode(). # match: Dictionary containing the match dictionary for each hint # (the parts of the DE for solving). When going through the # hints in "all", this holds the match string for the current # hint. # order: The order of the DE, as determined by ode_order(). hints = kwargs.get('hint', {'default': hint, hint: kwargs['match'], 'order': kwargs['order']}) if not hints['default']: # classify_ode will set hints['default'] to None if no hints match. if hint not in allhints and hint != 'default': raise ValueError("Hint not recognized: " + hint) elif hint not in hints['ordered_hints'] and hint != 'default': raise ValueError(string + str(eq) + " does not match hint " + hint) # If dsolve can't solve the purely algebraic equation then dsolve will raise # ValueError elif hints['order'] == 0: raise ValueError( str(eq) + " is not a solvable differential equation in " + str(func)) else: raise NotImplementedError(dummy + "solve" + ": Cannot solve " + str(eq)) if hint == 'default': return _desolve(eq, func, ics=ics, hint=hints['default'], simplify=simplify, prep=prep, x0=x0, classify=False, order=hints['order'], match=hints[hints['default']], xi=xi, eta=eta, n=terms, type=type) elif hint in ('all', 'all_Integral', 'best'): retdict = {} gethints = set(hints) - {'order', 'default', 'ordered_hints'} if hint == 'all_Integral': for i in hints: if i.endswith('_Integral'): gethints.remove(i[:-len('_Integral')]) # special cases for k in ["1st_homogeneous_coeff_best", "1st_power_series", "lie_group", "2nd_power_series_ordinary", "2nd_power_series_regular"]: if k in gethints: gethints.remove(k) for i in gethints: sol = _desolve(eq, func, ics=ics, hint=i, x0=x0, simplify=simplify, prep=prep, classify=False, n=terms, order=hints['order'], match=hints[i], type=type) retdict[i] = sol retdict['all'] = True retdict['eq'] = eq return retdict elif hint not in allhints: # and hint not in ('default', 'ordered_hints'): raise ValueError("Hint not recognized: " + hint) elif hint not in hints: raise ValueError(string + str(eq) + " does not match hint " + hint) else: # Key added to identify the hint needed to solve the equation hints['hint'] = hint hints.update({'func': func, 'eq': eq}) return hints sympy-sympy-1.9/sympy/solvers/diophantine/000077500000000000000000000000001412543434000211035ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/diophantine/__init__.py000066400000000000000000000002001412543434000232040ustar00rootroot00000000000000from .diophantine import diophantine, classify_diop, diop_solve __all__ = [ 'diophantine', 'classify_diop', 'diop_solve' ] sympy-sympy-1.9/sympy/solvers/diophantine/diophantine.py000066400000000000000000003516141412543434000237710ustar00rootroot00000000000000from sympy.core.add import Add from sympy.core.assumptions import check_assumptions from sympy.core.containers import Tuple from sympy.core.compatibility import as_int, is_sequence, ordered from sympy.core.exprtools import factor_terms from sympy.core.function import _mexpand from sympy.core.mul import Mul from sympy.core.numbers import Rational from sympy.core.numbers import igcdex, ilcm, igcd from sympy.core.power import integer_nthroot, isqrt from sympy.core.relational import Eq from sympy.core.singleton import S from sympy.core.symbol import Symbol, symbols from sympy.core.sympify import _sympify from sympy.functions.elementary.complexes import sign from sympy.functions.elementary.integers import floor from sympy.functions.elementary.miscellaneous import sqrt from sympy.matrices.dense import MutableDenseMatrix as Matrix from sympy.ntheory.factor_ import ( divisors, factorint, multiplicity, perfect_power) from sympy.ntheory.generate import nextprime from sympy.ntheory.primetest import is_square, isprime from sympy.ntheory.residue_ntheory import sqrt_mod from sympy.polys.polyerrors import GeneratorsNeeded from sympy.polys.polytools import Poly, factor_list from sympy.simplify.simplify import signsimp from sympy.solvers.solveset import solveset_real from sympy.utilities import default_sort_key, numbered_symbols from sympy.utilities.misc import filldedent # these are imported with 'from sympy.solvers.diophantine import * __all__ = ['diophantine', 'classify_diop'] class DiophantineSolutionSet(set): """ Container for a set of solutions to a particular diophantine equation. The base representation is a set of tuples representing each of the solutions. Parameters ========== symbols : list List of free symbols in the original equation. parameters: list List of parameters to be used in the solution. Examples ======== Adding solutions: >>> from sympy.solvers.diophantine.diophantine import DiophantineSolutionSet >>> from sympy.abc import x, y, t, u >>> s1 = DiophantineSolutionSet([x, y], [t, u]) >>> s1 set() >>> s1.add((2, 3)) >>> s1.add((-1, u)) >>> s1 {(-1, u), (2, 3)} >>> s2 = DiophantineSolutionSet([x, y], [t, u]) >>> s2.add((3, 4)) >>> s1.update(*s2) >>> s1 {(-1, u), (2, 3), (3, 4)} Conversion of solutions into dicts: >>> list(s1.dict_iterator()) [{x: -1, y: u}, {x: 2, y: 3}, {x: 3, y: 4}] Substituting values: >>> s3 = DiophantineSolutionSet([x, y], [t, u]) >>> s3.add((t**2, t + u)) >>> s3 {(t**2, t + u)} >>> s3.subs({t: 2, u: 3}) {(4, 5)} >>> s3.subs(t, -1) {(1, u - 1)} >>> s3.subs(t, 3) {(9, u + 3)} Evaluation at specific values. Positional arguments are given in the same order as the parameters: >>> s3(-2, 3) {(4, 1)} >>> s3(5) {(25, u + 5)} >>> s3(None, 2) {(t**2, t + 2)} """ def __init__(self, symbols_seq, parameters): super().__init__() if not is_sequence(symbols_seq): raise ValueError("Symbols must be given as a sequence.") if not is_sequence(parameters): raise ValueError("Parameters must be given as a sequence.") self.symbols = tuple(symbols_seq) self.parameters = tuple(parameters) def add(self, solution): if len(solution) != len(self.symbols): raise ValueError("Solution should have a length of %s, not %s" % (len(self.symbols), len(solution))) super().add(Tuple(*solution)) def update(self, *solutions): for solution in solutions: self.add(solution) def dict_iterator(self): for solution in ordered(self): yield dict(zip(self.symbols, solution)) def subs(self, *args, **kwargs): result = DiophantineSolutionSet(self.symbols, self.parameters) for solution in self: result.add(solution.subs(*args, **kwargs)) return result def __call__(self, *args): if len(args) > len(self.parameters): raise ValueError("Evaluation should have at most %s values, not %s" % (len(self.parameters), len(args))) return self.subs(list(zip(self.parameters, args))) class DiophantineEquationType: """ Internal representation of a particular diophantine equation type. Parameters ========== equation : The diophantine equation that is being solved. free_symbols : list (optional) The symbols being solved for. Attributes ========== total_degree : The maximum of the degrees of all terms in the equation homogeneous : Does the equation contain a term of degree 0 homogeneous_order : Does the equation contain any coefficient that is in the symbols being solved for dimension : The number of symbols being solved for """ name = None # type: str def __init__(self, equation, free_symbols=None): self.equation = _sympify(equation).expand(force=True) if free_symbols is not None: self.free_symbols = free_symbols else: self.free_symbols = list(self.equation.free_symbols) self.free_symbols.sort(key=default_sort_key) if not self.free_symbols: raise ValueError('equation should have 1 or more free symbols') self.coeff = self.equation.as_coefficients_dict() if not all(_is_int(c) for c in self.coeff.values()): raise TypeError("Coefficients should be Integers") self.total_degree = Poly(self.equation).total_degree() self.homogeneous = 1 not in self.coeff self.homogeneous_order = not (set(self.coeff) & set(self.free_symbols)) self.dimension = len(self.free_symbols) self._parameters = None def matches(self): """ Determine whether the given equation can be matched to the particular equation type. """ return False @property def n_parameters(self): return self.dimension @property def parameters(self): if self._parameters is None: self._parameters = symbols('t_:%i' % (self.n_parameters,), integer=True) return self._parameters def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet: raise NotImplementedError('No solver has been written for %s.' % self.name) def pre_solve(self, parameters=None): if not self.matches(): raise ValueError("This equation does not match the %s equation type." % self.name) if parameters is not None: if len(parameters) != self.n_parameters: raise ValueError("Expected %s parameter(s) but got %s" % (self.n_parameters, len(parameters))) self._parameters = parameters class Univariate(DiophantineEquationType): """ Representation of a univariate diophantine equation. A univariate diophantine equation is an equation of the form `a_{0} + a_{1}x + a_{2}x^2 + .. + a_{n}x^n = 0` where `a_{1}, a_{2}, ..a_{n}` are integer constants and `x` is an integer variable. Examples ======== >>> from sympy.solvers.diophantine.diophantine import Univariate >>> from sympy.abc import x >>> Univariate((x - 2)*(x - 3)**2).solve() # solves equation (x - 2)*(x - 3)**2 == 0 {(2,), (3,)} """ name = 'univariate' def matches(self): return self.dimension == 1 def solve(self, parameters=None, limit=None): self.pre_solve(parameters) result = DiophantineSolutionSet(self.free_symbols, parameters=self.parameters) for i in solveset_real(self.equation, self.free_symbols[0]).intersect(S.Integers): result.add((i,)) return result class Linear(DiophantineEquationType): """ Representation of a linear diophantine equation. A linear diophantine equation is an equation of the form `a_{1}x_{1} + a_{2}x_{2} + .. + a_{n}x_{n} = 0` where `a_{1}, a_{2}, ..a_{n}` are integer constants and `x_{1}, x_{2}, ..x_{n}` are integer variables. Examples ======== >>> from sympy.solvers.diophantine.diophantine import Linear >>> from sympy.abc import x, y, z >>> l1 = Linear(2*x - 3*y - 5) >>> l1.matches() # is this equation linear True >>> l1.solve() # solves equation 2*x - 3*y - 5 == 0 {(3*t_0 - 5, 2*t_0 - 5)} Here x = -3*t_0 - 5 and y = -2*t_0 - 5 >>> Linear(2*x - 3*y - 4*z -3).solve() {(t_0, 2*t_0 + 4*t_1 + 3, -t_0 - 3*t_1 - 3)} """ name = 'linear' def matches(self): return self.total_degree == 1 def solve(self, parameters=None, limit=None): self.pre_solve(parameters) coeff = self.coeff var = self.free_symbols if 1 in coeff: # negate coeff[] because input is of the form: ax + by + c == 0 # but is used as: ax + by == -c c = -coeff[1] else: c = 0 result = DiophantineSolutionSet(var, parameters=self.parameters) params = result.parameters if len(var) == 1: q, r = divmod(c, coeff[var[0]]) if not r: result.add((q,)) return result else: return result ''' base_solution_linear() can solve diophantine equations of the form: a*x + b*y == c We break down multivariate linear diophantine equations into a series of bivariate linear diophantine equations which can then be solved individually by base_solution_linear(). Consider the following: a_0*x_0 + a_1*x_1 + a_2*x_2 == c which can be re-written as: a_0*x_0 + g_0*y_0 == c where g_0 == gcd(a_1, a_2) and y == (a_1*x_1)/g_0 + (a_2*x_2)/g_0 This leaves us with two binary linear diophantine equations. For the first equation: a == a_0 b == g_0 c == c For the second: a == a_1/g_0 b == a_2/g_0 c == the solution we find for y_0 in the first equation. The arrays A and B are the arrays of integers used for 'a' and 'b' in each of the n-1 bivariate equations we solve. ''' A = [coeff[v] for v in var] B = [] if len(var) > 2: B.append(igcd(A[-2], A[-1])) A[-2] = A[-2] // B[0] A[-1] = A[-1] // B[0] for i in range(len(A) - 3, 0, -1): gcd = igcd(B[0], A[i]) B[0] = B[0] // gcd A[i] = A[i] // gcd B.insert(0, gcd) B.append(A[-1]) ''' Consider the trivariate linear equation: 4*x_0 + 6*x_1 + 3*x_2 == 2 This can be re-written as: 4*x_0 + 3*y_0 == 2 where y_0 == 2*x_1 + x_2 (Note that gcd(3, 6) == 3) The complete integral solution to this equation is: x_0 == 2 + 3*t_0 y_0 == -2 - 4*t_0 where 't_0' is any integer. Now that we have a solution for 'x_0', find 'x_1' and 'x_2': 2*x_1 + x_2 == -2 - 4*t_0 We can then solve for '-2' and '-4' independently, and combine the results: 2*x_1a + x_2a == -2 x_1a == 0 + t_0 x_2a == -2 - 2*t_0 2*x_1b + x_2b == -4*t_0 x_1b == 0*t_0 + t_1 x_2b == -4*t_0 - 2*t_1 ==> x_1 == t_0 + t_1 x_2 == -2 - 6*t_0 - 2*t_1 where 't_0' and 't_1' are any integers. Note that: 4*(2 + 3*t_0) + 6*(t_0 + t_1) + 3*(-2 - 6*t_0 - 2*t_1) == 2 for any integral values of 't_0', 't_1'; as required. This method is generalised for many variables, below. ''' solutions = [] for i in range(len(B)): tot_x, tot_y = [], [] for j, arg in enumerate(Add.make_args(c)): if arg.is_Integer: # example: 5 -> k = 5 k, p = arg, S.One pnew = params[0] else: # arg is a Mul or Symbol # example: 3*t_1 -> k = 3 # example: t_0 -> k = 1 k, p = arg.as_coeff_Mul() pnew = params[params.index(p) + 1] sol = sol_x, sol_y = base_solution_linear(k, A[i], B[i], pnew) if p is S.One: if None in sol: return result else: # convert a + b*pnew -> a*p + b*pnew if isinstance(sol_x, Add): sol_x = sol_x.args[0]*p + sol_x.args[1] if isinstance(sol_y, Add): sol_y = sol_y.args[0]*p + sol_y.args[1] tot_x.append(sol_x) tot_y.append(sol_y) solutions.append(Add(*tot_x)) c = Add(*tot_y) solutions.append(c) result.add(solutions) return result class BinaryQuadratic(DiophantineEquationType): """ Representation of a binary quadratic diophantine equation. A binary quadratic diophantine equation is an equation of the form `Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0`, where `A, B, C, D, E, F` are integer constants and `x` and `y` are integer variables. Examples ======== >>> from sympy.abc import x, y >>> from sympy.solvers.diophantine.diophantine import BinaryQuadratic >>> b1 = BinaryQuadratic(x**3 + y**2 + 1) >>> b1.matches() False >>> b2 = BinaryQuadratic(x**2 + y**2 + 2*x + 2*y + 2) >>> b2.matches() True >>> b2.solve() {(-1, -1)} References ========== .. [1] Methods to solve Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0, [online], Available: http://www.alpertron.com.ar/METHODS.HTM .. [2] Solving the equation ax^2+ bxy + cy^2 + dx + ey + f= 0, [online], Available: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf """ name = 'binary_quadratic' def matches(self): return self.total_degree == 2 and self.dimension == 2 def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet: self.pre_solve(parameters) var = self.free_symbols coeff = self.coeff x, y = var A = coeff[x**2] B = coeff[x*y] C = coeff[y**2] D = coeff[x] E = coeff[y] F = coeff[S.One] A, B, C, D, E, F = [as_int(i) for i in _remove_gcd(A, B, C, D, E, F)] # (1) Simple-Hyperbolic case: A = C = 0, B != 0 # In this case equation can be converted to (Bx + E)(By + D) = DE - BF # We consider two cases; DE - BF = 0 and DE - BF != 0 # More details, http://www.alpertron.com.ar/METHODS.HTM#SHyperb result = DiophantineSolutionSet(var, self.parameters) t, u = result.parameters discr = B**2 - 4*A*C if A == 0 and C == 0 and B != 0: if D*E - B*F == 0: q, r = divmod(E, B) if not r: result.add((-q, t)) q, r = divmod(D, B) if not r: result.add((t, -q)) else: div = divisors(D*E - B*F) div = div + [-term for term in div] for d in div: x0, r = divmod(d - E, B) if not r: q, r = divmod(D*E - B*F, d) if not r: y0, r = divmod(q - D, B) if not r: result.add((x0, y0)) # (2) Parabolic case: B**2 - 4*A*C = 0 # There are two subcases to be considered in this case. # sqrt(c)D - sqrt(a)E = 0 and sqrt(c)D - sqrt(a)E != 0 # More Details, http://www.alpertron.com.ar/METHODS.HTM#Parabol elif discr == 0: if A == 0: s = BinaryQuadratic(self.equation, free_symbols=[y, x]).solve(parameters=[t, u]) for soln in s: result.add((soln[1], soln[0])) else: g = sign(A)*igcd(A, C) a = A // g c = C // g e = sign(B / A) sqa = isqrt(a) sqc = isqrt(c) _c = e*sqc*D - sqa*E if not _c: z = symbols("z", real=True) eq = sqa*g*z**2 + D*z + sqa*F roots = solveset_real(eq, z).intersect(S.Integers) for root in roots: ans = diop_solve(sqa*x + e*sqc*y - root) result.add((ans[0], ans[1])) elif _is_int(c): solve_x = lambda u: -e*sqc*g*_c*t**2 - (E + 2*e*sqc*g*u)*t \ - (e*sqc*g*u**2 + E*u + e*sqc*F) // _c solve_y = lambda u: sqa*g*_c*t**2 + (D + 2*sqa*g*u)*t \ + (sqa*g*u**2 + D*u + sqa*F) // _c for z0 in range(0, abs(_c)): # Check if the coefficients of y and x obtained are integers or not if (divisible(sqa*g*z0**2 + D*z0 + sqa*F, _c) and divisible(e*sqc*g*z0**2 + E*z0 + e*sqc*F, _c)): result.add((solve_x(z0), solve_y(z0))) # (3) Method used when B**2 - 4*A*C is a square, is described in p. 6 of the below paper # by John P. Robertson. # https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf elif is_square(discr): if A != 0: r = sqrt(discr) u, v = symbols("u, v", integer=True) eq = _mexpand( 4*A*r*u*v + 4*A*D*(B*v + r*u + r*v - B*u) + 2*A*4*A*E*(u - v) + 4*A*r*4*A*F) solution = diop_solve(eq, t) for s0, t0 in solution: num = B*t0 + r*s0 + r*t0 - B*s0 x_0 = S(num) / (4*A*r) y_0 = S(s0 - t0) / (2*r) if isinstance(s0, Symbol) or isinstance(t0, Symbol): if len(check_param(x_0, y_0, 4*A*r, parameters)) > 0: ans = check_param(x_0, y_0, 4*A*r, parameters) result.update(*ans) elif x_0.is_Integer and y_0.is_Integer: if is_solution_quad(var, coeff, x_0, y_0): result.add((x_0, y_0)) else: s = BinaryQuadratic(self.equation, free_symbols=var[::-1]).solve(parameters=[t, u]) # Interchange x and y while s: result.add(s.pop()[::-1]) # and solution <--------+ # (4) B**2 - 4*A*C > 0 and B**2 - 4*A*C not a square or B**2 - 4*A*C < 0 else: P, Q = _transformation_to_DN(var, coeff) D, N = _find_DN(var, coeff) solns_pell = diop_DN(D, N) if D < 0: for x0, y0 in solns_pell: for x in [-x0, x0]: for y in [-y0, y0]: s = P*Matrix([x, y]) + Q try: result.add([as_int(_) for _ in s]) except ValueError: pass else: # In this case equation can be transformed into a Pell equation solns_pell = set(solns_pell) for X, Y in list(solns_pell): solns_pell.add((-X, -Y)) a = diop_DN(D, 1) T = a[0][0] U = a[0][1] if all(_is_int(_) for _ in P[:4] + Q[:2]): for r, s in solns_pell: _a = (r + s*sqrt(D))*(T + U*sqrt(D))**t _b = (r - s*sqrt(D))*(T - U*sqrt(D))**t x_n = _mexpand(S(_a + _b) / 2) y_n = _mexpand(S(_a - _b) / (2*sqrt(D))) s = P*Matrix([x_n, y_n]) + Q result.add(s) else: L = ilcm(*[_.q for _ in P[:4] + Q[:2]]) k = 1 T_k = T U_k = U while (T_k - 1) % L != 0 or U_k % L != 0: T_k, U_k = T_k*T + D*U_k*U, T_k*U + U_k*T k += 1 for X, Y in solns_pell: for i in range(k): if all(_is_int(_) for _ in P*Matrix([X, Y]) + Q): _a = (X + sqrt(D)*Y)*(T_k + sqrt(D)*U_k)**t _b = (X - sqrt(D)*Y)*(T_k - sqrt(D)*U_k)**t Xt = S(_a + _b) / 2 Yt = S(_a - _b) / (2*sqrt(D)) s = P*Matrix([Xt, Yt]) + Q result.add(s) X, Y = X*T + D*U*Y, X*U + Y*T return result class InhomogeneousTernaryQuadratic(DiophantineEquationType): """ Representation of an inhomogeneous ternary quadratic. No solver is currently implemented for this equation type. """ name = 'inhomogeneous_ternary_quadratic' def matches(self): if not (self.total_degree == 2 and self.dimension == 3): return False if not self.homogeneous: return False return not self.homogeneous_order class HomogeneousTernaryQuadraticNormal(DiophantineEquationType): """ Representation of a homogeneous ternary quadratic normal diophantine equation. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadraticNormal >>> HomogeneousTernaryQuadraticNormal(4*x**2 - 5*y**2 + z**2).solve() {(1, 2, 4)} """ name = 'homogeneous_ternary_quadratic_normal' def matches(self): if not (self.total_degree == 2 and self.dimension == 3): return False if not self.homogeneous: return False if not self.homogeneous_order: return False nonzero = [k for k in self.coeff if self.coeff[k]] return len(nonzero) == 3 and all(i**2 in nonzero for i in self.free_symbols) def solve(self, parameters=None, limit=None) -> DiophantineSolutionSet: self.pre_solve(parameters) var = self.free_symbols coeff = self.coeff x, y, z = var a = coeff[x**2] b = coeff[y**2] c = coeff[z**2] (sqf_of_a, sqf_of_b, sqf_of_c), (a_1, b_1, c_1), (a_2, b_2, c_2) = \ sqf_normal(a, b, c, steps=True) A = -a_2*c_2 B = -b_2*c_2 result = DiophantineSolutionSet(var, parameters=self.parameters) # If following two conditions are satisfied then there are no solutions if A < 0 and B < 0: return result if ( sqrt_mod(-b_2*c_2, a_2) is None or sqrt_mod(-c_2*a_2, b_2) is None or sqrt_mod(-a_2*b_2, c_2) is None): return result z_0, x_0, y_0 = descent(A, B) z_0, q = _rational_pq(z_0, abs(c_2)) x_0 *= q y_0 *= q x_0, y_0, z_0 = _remove_gcd(x_0, y_0, z_0) # Holzer reduction if sign(a) == sign(b): x_0, y_0, z_0 = holzer(x_0, y_0, z_0, abs(a_2), abs(b_2), abs(c_2)) elif sign(a) == sign(c): x_0, z_0, y_0 = holzer(x_0, z_0, y_0, abs(a_2), abs(c_2), abs(b_2)) else: y_0, z_0, x_0 = holzer(y_0, z_0, x_0, abs(b_2), abs(c_2), abs(a_2)) x_0 = reconstruct(b_1, c_1, x_0) y_0 = reconstruct(a_1, c_1, y_0) z_0 = reconstruct(a_1, b_1, z_0) sq_lcm = ilcm(sqf_of_a, sqf_of_b, sqf_of_c) x_0 = abs(x_0*sq_lcm // sqf_of_a) y_0 = abs(y_0*sq_lcm // sqf_of_b) z_0 = abs(z_0*sq_lcm // sqf_of_c) result.add(_remove_gcd(x_0, y_0, z_0)) return result class HomogeneousTernaryQuadratic(DiophantineEquationType): """ Representation of a homogeneous ternary quadratic diophantine equation. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.solvers.diophantine.diophantine import HomogeneousTernaryQuadratic >>> HomogeneousTernaryQuadratic(x**2 + y**2 - 3*z**2 + x*y).solve() {(-1, 2, 1)} >>> HomogeneousTernaryQuadratic(3*x**2 + y**2 - 3*z**2 + 5*x*y + y*z).solve() {(3, 12, 13)} """ name = 'homogeneous_ternary_quadratic' def matches(self): if not (self.total_degree == 2 and self.dimension == 3): return False if not self.homogeneous: return False if not self.homogeneous_order: return False nonzero = [k for k in self.coeff if self.coeff[k]] return not (len(nonzero) == 3 and all(i**2 in nonzero for i in self.free_symbols)) def solve(self, parameters=None, limit=None): self.pre_solve(parameters) _var = self.free_symbols coeff = self.coeff x, y, z = _var var = [x, y, z] # Equations of the form B*x*y + C*z*x + E*y*z = 0 and At least two of the # coefficients A, B, C are non-zero. # There are infinitely many solutions for the equation. # Ex: (0, 0, t), (0, t, 0), (t, 0, 0) # Equation can be re-written as y*(B*x + E*z) = -C*x*z and we can find rather # unobvious solutions. Set y = -C and B*x + E*z = x*z. The latter can be solved by # using methods for binary quadratic diophantine equations. Let's select the # solution which minimizes |x| + |z| result = DiophantineSolutionSet(var, parameters=self.parameters) def unpack_sol(sol): if len(sol) > 0: return list(sol)[0] return None, None, None if not any(coeff[i**2] for i in var): if coeff[x*z]: sols = diophantine(coeff[x*y]*x + coeff[y*z]*z - x*z) s = sols.pop() min_sum = abs(s[0]) + abs(s[1]) for r in sols: m = abs(r[0]) + abs(r[1]) if m < min_sum: s = r min_sum = m result.add(_remove_gcd(s[0], -coeff[x*z], s[1])) return result else: var[0], var[1] = _var[1], _var[0] y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) if x_0 is not None: result.add((x_0, y_0, z_0)) return result if coeff[x**2] == 0: # If the coefficient of x is zero change the variables if coeff[y**2] == 0: var[0], var[2] = _var[2], _var[0] z_0, y_0, x_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) else: var[0], var[1] = _var[1], _var[0] y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) else: if coeff[x*y] or coeff[x*z]: # Apply the transformation x --> X - (B*y + C*z)/(2*A) A = coeff[x**2] B = coeff[x*y] C = coeff[x*z] D = coeff[y**2] E = coeff[y*z] F = coeff[z**2] _coeff = dict() _coeff[x**2] = 4*A**2 _coeff[y**2] = 4*A*D - B**2 _coeff[z**2] = 4*A*F - C**2 _coeff[y*z] = 4*A*E - 2*B*C _coeff[x*y] = 0 _coeff[x*z] = 0 x_0, y_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, _coeff)) if x_0 is None: return result p, q = _rational_pq(B*y_0 + C*z_0, 2*A) x_0, y_0, z_0 = x_0*q - p, y_0*q, z_0*q elif coeff[z*y] != 0: if coeff[y**2] == 0: if coeff[z**2] == 0: # Equations of the form A*x**2 + E*yz = 0. A = coeff[x**2] E = coeff[y*z] b, a = _rational_pq(-E, A) x_0, y_0, z_0 = b, a, b else: # Ax**2 + E*y*z + F*z**2 = 0 var[0], var[2] = _var[2], _var[0] z_0, y_0, x_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) else: # A*x**2 + D*y**2 + E*y*z + F*z**2 = 0, C may be zero var[0], var[1] = _var[1], _var[0] y_0, x_0, z_0 = unpack_sol(_diop_ternary_quadratic(var, coeff)) else: # Ax**2 + D*y**2 + F*z**2 = 0, C may be zero x_0, y_0, z_0 = unpack_sol(_diop_ternary_quadratic_normal(var, coeff)) if x_0 is None: return result result.add(_remove_gcd(x_0, y_0, z_0)) return result class InhomogeneousGeneralQuadratic(DiophantineEquationType): """ Representation of an inhomogeneous general quadratic. No solver is currently implemented for this equation type. """ name = 'inhomogeneous_general_quadratic' def matches(self): if not (self.total_degree == 2 and self.dimension >= 3): return False if not self.homogeneous_order: return True else: # there may be Pow keys like x**2 or Mul keys like x*y if any(k.is_Mul for k in self.coeff): # cross terms return not self.homogeneous return False class HomogeneousGeneralQuadratic(DiophantineEquationType): """ Representation of a homogeneous general quadratic. No solver is currently implemented for this equation type. """ name = 'homogeneous_general_quadratic' def matches(self): if not (self.total_degree == 2 and self.dimension >= 3): return False if not self.homogeneous_order: return False else: # there may be Pow keys like x**2 or Mul keys like x*y if any(k.is_Mul for k in self.coeff): # cross terms return self.homogeneous return False class GeneralSumOfSquares(DiophantineEquationType): r""" Representation of the diophantine equation `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`. Details ======= When `n = 3` if `k = 4^a(8m + 7)` for some `a, m \in Z` then there will be no solutions. Refer [1]_ for more details. Examples ======== >>> from sympy.solvers.diophantine.diophantine import GeneralSumOfSquares >>> from sympy.abc import a, b, c, d, e >>> GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve() {(15, 22, 22, 24, 24)} By default only 1 solution is returned. Use the `limit` keyword for more: >>> sorted(GeneralSumOfSquares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345).solve(limit=3)) [(15, 22, 22, 24, 24), (16, 19, 24, 24, 24), (16, 20, 22, 23, 26)] References ========== .. [1] Representing an integer as a sum of three squares, [online], Available: http://www.proofwiki.org/wiki/Integer_as_Sum_of_Three_Squares """ name = 'general_sum_of_squares' def matches(self): if not (self.total_degree == 2 and self.dimension >= 3): return False if not self.homogeneous_order: return False if any(k.is_Mul for k in self.coeff): return False return all(self.coeff[k] == 1 for k in self.coeff if k != 1) def solve(self, parameters=None, limit=1): self.pre_solve(parameters) var = self.free_symbols k = -int(self.coeff[1]) n = self.dimension result = DiophantineSolutionSet(var, parameters=self.parameters) if k < 0 or limit < 1: return result signs = [-1 if x.is_nonpositive else 1 for x in var] negs = signs.count(-1) != 0 took = 0 for t in sum_of_squares(k, n, zeros=True): if negs: result.add([signs[i]*j for i, j in enumerate(t)]) else: result.add(t) took += 1 if took == limit: break return result class GeneralPythagorean(DiophantineEquationType): """ Representation of the general pythagorean equation, `a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0`. Examples ======== >>> from sympy.solvers.diophantine.diophantine import GeneralPythagorean >>> from sympy.abc import a, b, c, d, e, x, y, z, t >>> GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve() {(t_0**2 + t_1**2 - t_2**2, 2*t_0*t_2, 2*t_1*t_2, t_0**2 + t_1**2 + t_2**2)} >>> GeneralPythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2).solve(parameters=[x, y, z, t]) {(-10*t**2 + 10*x**2 + 10*y**2 + 10*z**2, 15*t**2 + 15*x**2 + 15*y**2 + 15*z**2, 15*t*x, 12*t*y, 60*t*z)} """ name = 'general_pythagorean' def matches(self): if not (self.total_degree == 2 and self.dimension >= 3): return False if not self.homogeneous_order: return False if any(k.is_Mul for k in self.coeff): return False if all(self.coeff[k] == 1 for k in self.coeff if k != 1): return False if not all(is_square(abs(self.coeff[k])) for k in self.coeff): return False # all but one has the same sign # e.g. 4*x**2 + y**2 - 4*z**2 return abs(sum(sign(self.coeff[k]) for k in self.coeff)) == self.dimension - 2 @property def n_parameters(self): return self.dimension - 1 def solve(self, parameters=None, limit=1): self.pre_solve(parameters) coeff = self.coeff var = self.free_symbols n = self.dimension if sign(coeff[var[0] ** 2]) + sign(coeff[var[1] ** 2]) + sign(coeff[var[2] ** 2]) < 0: for key in coeff.keys(): coeff[key] = -coeff[key] result = DiophantineSolutionSet(var, parameters=self.parameters) index = 0 for i, v in enumerate(var): if sign(coeff[v ** 2]) == -1: index = i m = result.parameters ith = sum(m_i ** 2 for m_i in m) L = [ith - 2 * m[n - 2] ** 2] L.extend([2 * m[i] * m[n - 2] for i in range(n - 2)]) sol = L[:index] + [ith] + L[index:] lcm = 1 for i, v in enumerate(var): if i == index or (index > 0 and i == 0) or (index == 0 and i == 1): lcm = ilcm(lcm, sqrt(abs(coeff[v ** 2]))) else: s = sqrt(coeff[v ** 2]) lcm = ilcm(lcm, s if _odd(s) else s // 2) for i, v in enumerate(var): sol[i] = (lcm * sol[i]) / sqrt(abs(coeff[v ** 2])) result.add(sol) return result class CubicThue(DiophantineEquationType): """ Representation of a cubic Thue diophantine equation. A cubic Thue diophantine equation is a polynomial of the form `f(x, y) = r` of degree 3, where `x` and `y` are integers and `r` is a rational number. No solver is currently implemented for this equation type. Examples ======== >>> from sympy.abc import x, y >>> from sympy.solvers.diophantine.diophantine import CubicThue >>> c1 = CubicThue(x**3 + y**2 + 1) >>> c1.matches() True """ name = 'cubic_thue' def matches(self): return self.total_degree == 3 and self.dimension == 2 class GeneralSumOfEvenPowers(DiophantineEquationType): """ Representation of the diophantine equation `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0` where `e` is an even, integer power. Examples ======== >>> from sympy.solvers.diophantine.diophantine import GeneralSumOfEvenPowers >>> from sympy.abc import a, b >>> GeneralSumOfEvenPowers(a**4 + b**4 - (2**4 + 3**4)).solve() {(2, 3)} """ name = 'general_sum_of_even_powers' def matches(self): if not self.total_degree > 3: return False if self.total_degree % 2 != 0: return False if not all(k.is_Pow and k.exp == self.total_degree for k in self.coeff if k != 1): return False return all(self.coeff[k] == 1 for k in self.coeff if k != 1) def solve(self, parameters=None, limit=1): self.pre_solve(parameters) var = self.free_symbols coeff = self.coeff p = None for q in coeff.keys(): if q.is_Pow and coeff[q]: p = q.exp k = len(var) n = -coeff[1] result = DiophantineSolutionSet(var, parameters=self.parameters) if n < 0 or limit < 1: return result sign = [-1 if x.is_nonpositive else 1 for x in var] negs = sign.count(-1) != 0 took = 0 for t in power_representation(n, p, k): if negs: result.add([sign[i]*j for i, j in enumerate(t)]) else: result.add(t) took += 1 if took == limit: break return result # these types are known (but not necessarily handled) # note that order is important here (in the current solver state) all_diop_classes = [ Linear, Univariate, BinaryQuadratic, InhomogeneousTernaryQuadratic, HomogeneousTernaryQuadraticNormal, HomogeneousTernaryQuadratic, InhomogeneousGeneralQuadratic, HomogeneousGeneralQuadratic, GeneralSumOfSquares, GeneralPythagorean, CubicThue, GeneralSumOfEvenPowers, ] diop_known = {diop_class.name for diop_class in all_diop_classes} def _is_int(i): try: as_int(i) return True except ValueError: pass def _sorted_tuple(*i): return tuple(sorted(i)) def _remove_gcd(*x): try: g = igcd(*x) except ValueError: fx = list(filter(None, x)) if len(fx) < 2: return x g = igcd(*[i.as_content_primitive()[0] for i in fx]) except TypeError: raise TypeError('_remove_gcd(a,b,c) or _remove_gcd(*container)') if g == 1: return x return tuple([i//g for i in x]) def _rational_pq(a, b): # return `(numer, denom)` for a/b; sign in numer and gcd removed return _remove_gcd(sign(b)*a, abs(b)) def _nint_or_floor(p, q): # return nearest int to p/q; in case of tie return floor(p/q) w, r = divmod(p, q) if abs(r) <= abs(q)//2: return w return w + 1 def _odd(i): return i % 2 != 0 def _even(i): return i % 2 == 0 def diophantine(eq, param=symbols("t", integer=True), syms=None, permute=False): """ Simplify the solution procedure of diophantine equation ``eq`` by converting it into a product of terms which should equal zero. Explanation =========== For example, when solving, `x^2 - y^2 = 0` this is treated as `(x + y)(x - y) = 0` and `x + y = 0` and `x - y = 0` are solved independently and combined. Each term is solved by calling ``diop_solve()``. (Although it is possible to call ``diop_solve()`` directly, one must be careful to pass an equation in the correct form and to interpret the output correctly; ``diophantine()`` is the public-facing function to use in general.) Output of ``diophantine()`` is a set of tuples. The elements of the tuple are the solutions for each variable in the equation and are arranged according to the alphabetic ordering of the variables. e.g. For an equation with two variables, `a` and `b`, the first element of the tuple is the solution for `a` and the second for `b`. Usage ===== ``diophantine(eq, t, syms)``: Solve the diophantine equation ``eq``. ``t`` is the optional parameter to be used by ``diop_solve()``. ``syms`` is an optional list of symbols which determines the order of the elements in the returned tuple. By default, only the base solution is returned. If ``permute`` is set to True then permutations of the base solution and/or permutations of the signs of the values will be returned when applicable. Examples ======== >>> from sympy.solvers.diophantine import diophantine >>> from sympy.abc import a, b >>> eq = a**4 + b**4 - (2**4 + 3**4) >>> diophantine(eq) {(2, 3)} >>> diophantine(eq, permute=True) {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)} Details ======= ``eq`` should be an expression which is assumed to be zero. ``t`` is the parameter to be used in the solution. Examples ======== >>> from sympy.abc import x, y, z >>> diophantine(x**2 - y**2) {(t_0, -t_0), (t_0, t_0)} >>> diophantine(x*(2*x + 3*y - z)) {(0, n1, n2), (t_0, t_1, 2*t_0 + 3*t_1)} >>> diophantine(x**2 + 3*x*y + 4*x) {(0, n1), (3*t_0 - 4, -t_0)} See Also ======== diop_solve() sympy.utilities.iterables.permute_signs sympy.utilities.iterables.signed_permutations """ from sympy.utilities.iterables import ( subsets, permute_signs, signed_permutations) eq = _sympify(eq) if isinstance(eq, Eq): eq = eq.lhs - eq.rhs try: var = list(eq.expand(force=True).free_symbols) var.sort(key=default_sort_key) if syms: if not is_sequence(syms): raise TypeError( 'syms should be given as a sequence, e.g. a list') syms = [i for i in syms if i in var] if syms != var: dict_sym_index = dict(zip(syms, range(len(syms)))) return {tuple([t[dict_sym_index[i]] for i in var]) for t in diophantine(eq, param, permute=permute)} n, d = eq.as_numer_denom() if n.is_number: return set() if not d.is_number: dsol = diophantine(d) good = diophantine(n) - dsol return {s for s in good if _mexpand(d.subs(zip(var, s)))} else: eq = n eq = factor_terms(eq) assert not eq.is_number eq = eq.as_independent(*var, as_Add=False)[1] p = Poly(eq) assert not any(g.is_number for g in p.gens) eq = p.as_expr() assert eq.is_polynomial() except (GeneratorsNeeded, AssertionError): raise TypeError(filldedent(''' Equation should be a polynomial with Rational coefficients.''')) # permute only sign do_permute_signs = False # permute sign and values do_permute_signs_var = False # permute few signs permute_few_signs = False try: # if we know that factoring should not be attempted, skip # the factoring step v, c, t = classify_diop(eq) # check for permute sign if permute: len_var = len(v) permute_signs_for = [ GeneralSumOfSquares.name, GeneralSumOfEvenPowers.name] permute_signs_check = [ HomogeneousTernaryQuadratic.name, HomogeneousTernaryQuadraticNormal.name, BinaryQuadratic.name] if t in permute_signs_for: do_permute_signs_var = True elif t in permute_signs_check: # if all the variables in eq have even powers # then do_permute_sign = True if len_var == 3: var_mul = list(subsets(v, 2)) # here var_mul is like [(x, y), (x, z), (y, z)] xy_coeff = True x_coeff = True var1_mul_var2 = map(lambda a: a[0]*a[1], var_mul) # if coeff(y*z), coeff(y*x), coeff(x*z) is not 0 then # `xy_coeff` => True and do_permute_sign => False. # Means no permuted solution. for v1_mul_v2 in var1_mul_var2: try: coeff = c[v1_mul_v2] except KeyError: coeff = 0 xy_coeff = bool(xy_coeff) and bool(coeff) var_mul = list(subsets(v, 1)) # here var_mul is like [(x,), (y, )] for v1 in var_mul: try: coeff = c[v1[0]] except KeyError: coeff = 0 x_coeff = bool(x_coeff) and bool(coeff) if not any([xy_coeff, x_coeff]): # means only x**2, y**2, z**2, const is present do_permute_signs = True elif not x_coeff: permute_few_signs = True elif len_var == 2: var_mul = list(subsets(v, 2)) # here var_mul is like [(x, y)] xy_coeff = True x_coeff = True var1_mul_var2 = map(lambda x: x[0]*x[1], var_mul) for v1_mul_v2 in var1_mul_var2: try: coeff = c[v1_mul_v2] except KeyError: coeff = 0 xy_coeff = bool(xy_coeff) and bool(coeff) var_mul = list(subsets(v, 1)) # here var_mul is like [(x,), (y, )] for v1 in var_mul: try: coeff = c[v1[0]] except KeyError: coeff = 0 x_coeff = bool(x_coeff) and bool(coeff) if not any([xy_coeff, x_coeff]): # means only x**2, y**2 and const is present # so we can get more soln by permuting this soln. do_permute_signs = True elif not x_coeff: # when coeff(x), coeff(y) is not present then signs of # x, y can be permuted such that their sign are same # as sign of x*y. # e.g 1. (x_val,y_val)=> (x_val,y_val), (-x_val,-y_val) # 2. (-x_vall, y_val)=> (-x_val,y_val), (x_val,-y_val) permute_few_signs = True if t == 'general_sum_of_squares': # trying to factor such expressions will sometimes hang terms = [(eq, 1)] else: raise TypeError except (TypeError, NotImplementedError): fl = factor_list(eq) if fl[0].is_Rational and fl[0] != 1: return diophantine(eq/fl[0], param=param, syms=syms, permute=permute) terms = fl[1] sols = set() for term in terms: base, _ = term var_t, _, eq_type = classify_diop(base, _dict=False) _, base = signsimp(base, evaluate=False).as_coeff_Mul() solution = diop_solve(base, param) if eq_type in [ Linear.name, HomogeneousTernaryQuadratic.name, HomogeneousTernaryQuadraticNormal.name, GeneralPythagorean.name]: sols.add(merge_solution(var, var_t, solution)) elif eq_type in [ BinaryQuadratic.name, GeneralSumOfSquares.name, GeneralSumOfEvenPowers.name, Univariate.name]: for sol in solution: sols.add(merge_solution(var, var_t, sol)) else: raise NotImplementedError('unhandled type: %s' % eq_type) # remove null merge results if () in sols: sols.remove(()) null = tuple([0]*len(var)) # if there is no solution, return trivial solution if not sols and eq.subs(zip(var, null)).is_zero: sols.add(null) final_soln = set() for sol in sols: if all(_is_int(s) for s in sol): if do_permute_signs: permuted_sign = set(permute_signs(sol)) final_soln.update(permuted_sign) elif permute_few_signs: lst = list(permute_signs(sol)) lst = list(filter(lambda x: x[0]*x[1] == sol[1]*sol[0], lst)) permuted_sign = set(lst) final_soln.update(permuted_sign) elif do_permute_signs_var: permuted_sign_var = set(signed_permutations(sol)) final_soln.update(permuted_sign_var) else: final_soln.add(sol) else: final_soln.add(sol) return final_soln def merge_solution(var, var_t, solution): """ This is used to construct the full solution from the solutions of sub equations. Explanation =========== For example when solving the equation `(x - y)(x^2 + y^2 - z^2) = 0`, solutions for each of the equations `x - y = 0` and `x^2 + y^2 - z^2` are found independently. Solutions for `x - y = 0` are `(x, y) = (t, t)`. But we should introduce a value for z when we output the solution for the original equation. This function converts `(t, t)` into `(t, t, n_{1})` where `n_{1}` is an integer parameter. """ sol = [] if None in solution: return () solution = iter(solution) params = numbered_symbols("n", integer=True, start=1) for v in var: if v in var_t: sol.append(next(solution)) else: sol.append(next(params)) for val, symb in zip(sol, var): if check_assumptions(val, **symb.assumptions0) is False: return tuple() return tuple(sol) def _diop_solve(eq, params=None): for diop_type in all_diop_classes: if diop_type(eq).matches(): return diop_type(eq).solve(parameters=params) def diop_solve(eq, param=symbols("t", integer=True)): """ Solves the diophantine equation ``eq``. Explanation =========== Unlike ``diophantine()``, factoring of ``eq`` is not attempted. Uses ``classify_diop()`` to determine the type of the equation and calls the appropriate solver function. Use of ``diophantine()`` is recommended over other helper functions. ``diop_solve()`` can return either a set or a tuple depending on the nature of the equation. Usage ===== ``diop_solve(eq, t)``: Solve diophantine equation, ``eq`` using ``t`` as a parameter if needed. Details ======= ``eq`` should be an expression which is assumed to be zero. ``t`` is a parameter to be used in the solution. Examples ======== >>> from sympy.solvers.diophantine import diop_solve >>> from sympy.abc import x, y, z, w >>> diop_solve(2*x + 3*y - 5) (3*t_0 - 5, 5 - 2*t_0) >>> diop_solve(4*x + 3*y - 4*z + 5) (t_0, 8*t_0 + 4*t_1 + 5, 7*t_0 + 3*t_1 + 5) >>> diop_solve(x + 3*y - 4*z + w - 6) (t_0, t_0 + t_1, 6*t_0 + 5*t_1 + 4*t_2 - 6, 5*t_0 + 4*t_1 + 3*t_2 - 6) >>> diop_solve(x**2 + y**2 - 5) {(-2, -1), (-2, 1), (-1, -2), (-1, 2), (1, -2), (1, 2), (2, -1), (2, 1)} See Also ======== diophantine() """ var, coeff, eq_type = classify_diop(eq, _dict=False) if eq_type == Linear.name: return diop_linear(eq, param) elif eq_type == BinaryQuadratic.name: return diop_quadratic(eq, param) elif eq_type == HomogeneousTernaryQuadratic.name: return diop_ternary_quadratic(eq, parameterize=True) elif eq_type == HomogeneousTernaryQuadraticNormal.name: return diop_ternary_quadratic_normal(eq, parameterize=True) elif eq_type == GeneralPythagorean.name: return diop_general_pythagorean(eq, param) elif eq_type == Univariate.name: return diop_univariate(eq) elif eq_type == GeneralSumOfSquares.name: return diop_general_sum_of_squares(eq, limit=S.Infinity) elif eq_type == GeneralSumOfEvenPowers.name: return diop_general_sum_of_even_powers(eq, limit=S.Infinity) if eq_type is not None and eq_type not in diop_known: raise ValueError(filldedent(''' Alhough this type of equation was identified, it is not yet handled. It should, however, be listed in `diop_known` at the top of this file. Developers should see comments at the end of `classify_diop`. ''')) # pragma: no cover else: raise NotImplementedError( 'No solver has been written for %s.' % eq_type) def classify_diop(eq, _dict=True): # docstring supplied externally matched = False diop_type = None for diop_class in all_diop_classes: diop_type = diop_class(eq) if diop_type.matches(): matched = True break if matched: return diop_type.free_symbols, dict(diop_type.coeff) if _dict else diop_type.coeff, diop_type.name # new diop type instructions # -------------------------- # if this error raises and the equation *can* be classified, # * it should be identified in the if-block above # * the type should be added to the diop_known # if a solver can be written for it, # * a dedicated handler should be written (e.g. diop_linear) # * it should be passed to that handler in diop_solve raise NotImplementedError(filldedent(''' This equation is not yet recognized or else has not been simplified sufficiently to put it in a form recognized by diop_classify().''')) classify_diop.func_doc = ( # type: ignore ''' Helper routine used by diop_solve() to find information about ``eq``. Explanation =========== Returns a tuple containing the type of the diophantine equation along with the variables (free symbols) and their coefficients. Variables are returned as a list and coefficients are returned as a dict with the key being the respective term and the constant term is keyed to 1. The type is one of the following: * %s Usage ===== ``classify_diop(eq)``: Return variables, coefficients and type of the ``eq``. Details ======= ``eq`` should be an expression which is assumed to be zero. ``_dict`` is for internal use: when True (default) a dict is returned, otherwise a defaultdict which supplies 0 for missing keys is returned. Examples ======== >>> from sympy.solvers.diophantine import classify_diop >>> from sympy.abc import x, y, z, w, t >>> classify_diop(4*x + 6*y - 4) ([x, y], {1: -4, x: 4, y: 6}, 'linear') >>> classify_diop(x + 3*y -4*z + 5) ([x, y, z], {1: 5, x: 1, y: 3, z: -4}, 'linear') >>> classify_diop(x**2 + y**2 - x*y + x + 5) ([x, y], {1: 5, x: 1, x**2: 1, y**2: 1, x*y: -1}, 'binary_quadratic') ''' % ('\n * '.join(sorted(diop_known)))) def diop_linear(eq, param=symbols("t", integer=True)): """ Solves linear diophantine equations. A linear diophantine equation is an equation of the form `a_{1}x_{1} + a_{2}x_{2} + .. + a_{n}x_{n} = 0` where `a_{1}, a_{2}, ..a_{n}` are integer constants and `x_{1}, x_{2}, ..x_{n}` are integer variables. Usage ===== ``diop_linear(eq)``: Returns a tuple containing solutions to the diophantine equation ``eq``. Values in the tuple is arranged in the same order as the sorted variables. Details ======= ``eq`` is a linear diophantine equation which is assumed to be zero. ``param`` is the parameter to be used in the solution. Examples ======== >>> from sympy.solvers.diophantine.diophantine import diop_linear >>> from sympy.abc import x, y, z >>> diop_linear(2*x - 3*y - 5) # solves equation 2*x - 3*y - 5 == 0 (3*t_0 - 5, 2*t_0 - 5) Here x = -3*t_0 - 5 and y = -2*t_0 - 5 >>> diop_linear(2*x - 3*y - 4*z -3) (t_0, 2*t_0 + 4*t_1 + 3, -t_0 - 3*t_1 - 3) See Also ======== diop_quadratic(), diop_ternary_quadratic(), diop_general_pythagorean(), diop_general_sum_of_squares() """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == Linear.name: parameters = None if param is not None: parameters = symbols('%s_0:%i' % (param, len(var)), integer=True) result = Linear(eq).solve(parameters=parameters) if param is None: result = result(*[0]*len(result.parameters)) if len(result) > 0: return list(result)[0] else: return tuple([None]*len(result.parameters)) def base_solution_linear(c, a, b, t=None): """ Return the base solution for the linear equation, `ax + by = c`. Explanation =========== Used by ``diop_linear()`` to find the base solution of a linear Diophantine equation. If ``t`` is given then the parametrized solution is returned. Usage ===== ``base_solution_linear(c, a, b, t)``: ``a``, ``b``, ``c`` are coefficients in `ax + by = c` and ``t`` is the parameter to be used in the solution. Examples ======== >>> from sympy.solvers.diophantine.diophantine import base_solution_linear >>> from sympy.abc import t >>> base_solution_linear(5, 2, 3) # equation 2*x + 3*y = 5 (-5, 5) >>> base_solution_linear(0, 5, 7) # equation 5*x + 7*y = 0 (0, 0) >>> base_solution_linear(5, 2, 3, t) # equation 2*x + 3*y = 5 (3*t - 5, 5 - 2*t) >>> base_solution_linear(0, 5, 7, t) # equation 5*x + 7*y = 0 (7*t, -5*t) """ a, b, c = _remove_gcd(a, b, c) if c == 0: if t is not None: if b < 0: t = -t return (b*t , -a*t) else: return (0, 0) else: x0, y0, d = igcdex(abs(a), abs(b)) x0 *= sign(a) y0 *= sign(b) if divisible(c, d): if t is not None: if b < 0: t = -t return (c*x0 + b*t, c*y0 - a*t) else: return (c*x0, c*y0) else: return (None, None) def diop_univariate(eq): """ Solves a univariate diophantine equations. Explanation =========== A univariate diophantine equation is an equation of the form `a_{0} + a_{1}x + a_{2}x^2 + .. + a_{n}x^n = 0` where `a_{1}, a_{2}, ..a_{n}` are integer constants and `x` is an integer variable. Usage ===== ``diop_univariate(eq)``: Returns a set containing solutions to the diophantine equation ``eq``. Details ======= ``eq`` is a univariate diophantine equation which is assumed to be zero. Examples ======== >>> from sympy.solvers.diophantine.diophantine import diop_univariate >>> from sympy.abc import x >>> diop_univariate((x - 2)*(x - 3)**2) # solves equation (x - 2)*(x - 3)**2 == 0 {(2,), (3,)} """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == Univariate.name: return {(int(i),) for i in solveset_real( eq, var[0]).intersect(S.Integers)} def divisible(a, b): """ Returns `True` if ``a`` is divisible by ``b`` and `False` otherwise. """ return not a % b def diop_quadratic(eq, param=symbols("t", integer=True)): """ Solves quadratic diophantine equations. i.e. equations of the form `Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0`. Returns a set containing the tuples `(x, y)` which contains the solutions. If there are no solutions then `(None, None)` is returned. Usage ===== ``diop_quadratic(eq, param)``: ``eq`` is a quadratic binary diophantine equation. ``param`` is used to indicate the parameter to be used in the solution. Details ======= ``eq`` should be an expression which is assumed to be zero. ``param`` is a parameter to be used in the solution. Examples ======== >>> from sympy.abc import x, y, t >>> from sympy.solvers.diophantine.diophantine import diop_quadratic >>> diop_quadratic(x**2 + y**2 + 2*x + 2*y + 2, t) {(-1, -1)} References ========== .. [1] Methods to solve Ax^2 + Bxy + Cy^2 + Dx + Ey + F = 0, [online], Available: http://www.alpertron.com.ar/METHODS.HTM .. [2] Solving the equation ax^2+ bxy + cy^2 + dx + ey + f= 0, [online], Available: https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf See Also ======== diop_linear(), diop_ternary_quadratic(), diop_general_sum_of_squares(), diop_general_pythagorean() """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == BinaryQuadratic.name: if param is not None: parameters = [param, Symbol("u", integer=True)] else: parameters = None return set(BinaryQuadratic(eq).solve(parameters=parameters)) def is_solution_quad(var, coeff, u, v): """ Check whether `(u, v)` is solution to the quadratic binary diophantine equation with the variable list ``var`` and coefficient dictionary ``coeff``. Not intended for use by normal users. """ reps = dict(zip(var, (u, v))) eq = Add(*[j*i.xreplace(reps) for i, j in coeff.items()]) return _mexpand(eq) == 0 def diop_DN(D, N, t=symbols("t", integer=True)): """ Solves the equation `x^2 - Dy^2 = N`. Explanation =========== Mainly concerned with the case `D > 0, D` is not a perfect square, which is the same as the generalized Pell equation. The LMM algorithm [1]_ is used to solve this equation. Returns one solution tuple, (`x, y)` for each class of the solutions. Other solutions of the class can be constructed according to the values of ``D`` and ``N``. Usage ===== ``diop_DN(D, N, t)``: D and N are integers as in `x^2 - Dy^2 = N` and ``t`` is the parameter to be used in the solutions. Details ======= ``D`` and ``N`` correspond to D and N in the equation. ``t`` is the parameter to be used in the solutions. Examples ======== >>> from sympy.solvers.diophantine.diophantine import diop_DN >>> diop_DN(13, -4) # Solves equation x**2 - 13*y**2 = -4 [(3, 1), (393, 109), (36, 10)] The output can be interpreted as follows: There are three fundamental solutions to the equation `x^2 - 13y^2 = -4` given by (3, 1), (393, 109) and (36, 10). Each tuple is in the form (x, y), i.e. solution (3, 1) means that `x = 3` and `y = 1`. >>> diop_DN(986, 1) # Solves equation x**2 - 986*y**2 = 1 [(49299, 1570)] See Also ======== find_DN(), diop_bf_DN() References ========== .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P. Robertson, July 31, 2004, Pages 16 - 17. [online], Available: https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf """ if D < 0: if N == 0: return [(0, 0)] elif N < 0: return [] elif N > 0: sol = [] for d in divisors(square_factor(N)): sols = cornacchia(1, -D, N // d**2) if sols: for x, y in sols: sol.append((d*x, d*y)) if D == -1: sol.append((d*y, d*x)) return sol elif D == 0: if N < 0: return [] if N == 0: return [(0, t)] sN, _exact = integer_nthroot(N, 2) if _exact: return [(sN, t)] else: return [] else: # D > 0 sD, _exact = integer_nthroot(D, 2) if _exact: if N == 0: return [(sD*t, t)] else: sol = [] for y in range(floor(sign(N)*(N - 1)/(2*sD)) + 1): try: sq, _exact = integer_nthroot(D*y**2 + N, 2) except ValueError: _exact = False if _exact: sol.append((sq, y)) return sol elif 1 < N**2 < D: # It is much faster to call `_special_diop_DN`. return _special_diop_DN(D, N) else: if N == 0: return [(0, 0)] elif abs(N) == 1: pqa = PQa(0, 1, D) j = 0 G = [] B = [] for i in pqa: a = i[2] G.append(i[5]) B.append(i[4]) if j != 0 and a == 2*sD: break j = j + 1 if _odd(j): if N == -1: x = G[j - 1] y = B[j - 1] else: count = j while count < 2*j - 1: i = next(pqa) G.append(i[5]) B.append(i[4]) count += 1 x = G[count] y = B[count] else: if N == 1: x = G[j - 1] y = B[j - 1] else: return [] return [(x, y)] else: fs = [] sol = [] div = divisors(N) for d in div: if divisible(N, d**2): fs.append(d) for f in fs: m = N // f**2 zs = sqrt_mod(D, abs(m), all_roots=True) zs = [i for i in zs if i <= abs(m) // 2 ] if abs(m) != 2: zs = zs + [-i for i in zs if i] # omit dupl 0 for z in zs: pqa = PQa(z, abs(m), D) j = 0 G = [] B = [] for i in pqa: G.append(i[5]) B.append(i[4]) if j != 0 and abs(i[1]) == 1: r = G[j-1] s = B[j-1] if r**2 - D*s**2 == m: sol.append((f*r, f*s)) elif diop_DN(D, -1) != []: a = diop_DN(D, -1) sol.append((f*(r*a[0][0] + a[0][1]*s*D), f*(r*a[0][1] + s*a[0][0]))) break j = j + 1 if j == length(z, abs(m), D): break return sol def _special_diop_DN(D, N): """ Solves the equation `x^2 - Dy^2 = N` for the special case where `1 < N**2 < D` and `D` is not a perfect square. It is better to call `diop_DN` rather than this function, as the former checks the condition `1 < N**2 < D`, and calls the latter only if appropriate. Usage ===== WARNING: Internal method. Do not call directly! ``_special_diop_DN(D, N)``: D and N are integers as in `x^2 - Dy^2 = N`. Details ======= ``D`` and ``N`` correspond to D and N in the equation. Examples ======== >>> from sympy.solvers.diophantine.diophantine import _special_diop_DN >>> _special_diop_DN(13, -3) # Solves equation x**2 - 13*y**2 = -3 [(7, 2), (137, 38)] The output can be interpreted as follows: There are two fundamental solutions to the equation `x^2 - 13y^2 = -3` given by (7, 2) and (137, 38). Each tuple is in the form (x, y), i.e. solution (7, 2) means that `x = 7` and `y = 2`. >>> _special_diop_DN(2445, -20) # Solves equation x**2 - 2445*y**2 = -20 [(445, 9), (17625560, 356454), (698095554475, 14118073569)] See Also ======== diop_DN() References ========== .. [1] Section 4.4.4 of the following book: Quadratic Diophantine Equations, T. Andreescu and D. Andrica, Springer, 2015. """ # The following assertion was removed for efficiency, with the understanding # that this method is not called directly. The parent method, `diop_DN` # is responsible for performing the appropriate checks. # # assert (1 < N**2 < D) and (not integer_nthroot(D, 2)[1]) sqrt_D = sqrt(D) F = [(N, 1)] f = 2 while True: f2 = f**2 if f2 > abs(N): break n, r = divmod(N, f2) if r == 0: F.append((n, f)) f += 1 P = 0 Q = 1 G0, G1 = 0, 1 B0, B1 = 1, 0 solutions = [] i = 0 while True: a = floor((P + sqrt_D) / Q) P = a*Q - P Q = (D - P**2) // Q G2 = a*G1 + G0 B2 = a*B1 + B0 for n, f in F: if G2**2 - D*B2**2 == n: solutions.append((f*G2, f*B2)) i += 1 if Q == 1 and i % 2 == 0: break G0, G1 = G1, G2 B0, B1 = B1, B2 return solutions def cornacchia(a, b, m): r""" Solves `ax^2 + by^2 = m` where `\gcd(a, b) = 1 = gcd(a, m)` and `a, b > 0`. Explanation =========== Uses the algorithm due to Cornacchia. The method only finds primitive solutions, i.e. ones with `\gcd(x, y) = 1`. So this method can't be used to find the solutions of `x^2 + y^2 = 20` since the only solution to former is `(x, y) = (4, 2)` and it is not primitive. When `a = b`, only the solutions with `x \leq y` are found. For more details, see the References. Examples ======== >>> from sympy.solvers.diophantine.diophantine import cornacchia >>> cornacchia(2, 3, 35) # equation 2x**2 + 3y**2 = 35 {(2, 3), (4, 1)} >>> cornacchia(1, 1, 25) # equation x**2 + y**2 = 25 {(4, 3)} References =========== .. [1] A. Nitaj, "L'algorithme de Cornacchia" .. [2] Solving the diophantine equation ax**2 + by**2 = m by Cornacchia's method, [online], Available: http://www.numbertheory.org/php/cornacchia.html See Also ======== sympy.utilities.iterables.signed_permutations """ sols = set() a1 = igcdex(a, m)[0] v = sqrt_mod(-b*a1, m, all_roots=True) if not v: return None for t in v: if t < m // 2: continue u, r = t, m while True: u, r = r, u % r if a*r**2 < m: break m1 = m - a*r**2 if m1 % b == 0: m1 = m1 // b s, _exact = integer_nthroot(m1, 2) if _exact: if a == b and r < s: r, s = s, r sols.add((int(r), int(s))) return sols def PQa(P_0, Q_0, D): r""" Returns useful information needed to solve the Pell equation. Explanation =========== There are six sequences of integers defined related to the continued fraction representation of `\\frac{P + \sqrt{D}}{Q}`, namely {`P_{i}`}, {`Q_{i}`}, {`a_{i}`},{`A_{i}`}, {`B_{i}`}, {`G_{i}`}. ``PQa()`` Returns these values as a 6-tuple in the same order as mentioned above. Refer [1]_ for more detailed information. Usage ===== ``PQa(P_0, Q_0, D)``: ``P_0``, ``Q_0`` and ``D`` are integers corresponding to `P_{0}`, `Q_{0}` and `D` in the continued fraction `\\frac{P_{0} + \sqrt{D}}{Q_{0}}`. Also it's assumed that `P_{0}^2 == D mod(|Q_{0}|)` and `D` is square free. Examples ======== >>> from sympy.solvers.diophantine.diophantine import PQa >>> pqa = PQa(13, 4, 5) # (13 + sqrt(5))/4 >>> next(pqa) # (P_0, Q_0, a_0, A_0, B_0, G_0) (13, 4, 3, 3, 1, -1) >>> next(pqa) # (P_1, Q_1, a_1, A_1, B_1, G_1) (-1, 1, 1, 4, 1, 3) References ========== .. [1] Solving the generalized Pell equation x^2 - Dy^2 = N, John P. Robertson, July 31, 2004, Pages 4 - 8. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf """ A_i_2 = B_i_1 = 0 A_i_1 = B_i_2 = 1 G_i_2 = -P_0 G_i_1 = Q_0 P_i = P_0 Q_i = Q_0 while True: a_i = floor((P_i + sqrt(D))/Q_i) A_i = a_i*A_i_1 + A_i_2 B_i = a_i*B_i_1 + B_i_2 G_i = a_i*G_i_1 + G_i_2 yield P_i, Q_i, a_i, A_i, B_i, G_i A_i_1, A_i_2 = A_i, A_i_1 B_i_1, B_i_2 = B_i, B_i_1 G_i_1, G_i_2 = G_i, G_i_1 P_i = a_i*Q_i - P_i Q_i = (D - P_i**2)/Q_i def diop_bf_DN(D, N, t=symbols("t", integer=True)): r""" Uses brute force to solve the equation, `x^2 - Dy^2 = N`. Explanation =========== Mainly concerned with the generalized Pell equation which is the case when `D > 0, D` is not a perfect square. For more information on the case refer [1]_. Let `(t, u)` be the minimal positive solution of the equation `x^2 - Dy^2 = 1`. Then this method requires `\sqrt{\\frac{\mid N \mid (t \pm 1)}{2D}}` to be small. Usage ===== ``diop_bf_DN(D, N, t)``: ``D`` and ``N`` are coefficients in `x^2 - Dy^2 = N` and ``t`` is the parameter to be used in the solutions. Details ======= ``D`` and ``N`` correspond to D and N in the equation. ``t`` is the parameter to be used in the solutions. Examples ======== >>> from sympy.solvers.diophantine.diophantine import diop_bf_DN >>> diop_bf_DN(13, -4) [(3, 1), (-3, 1), (36, 10)] >>> diop_bf_DN(986, 1) [(49299, 1570)] See Also ======== diop_DN() References ========== .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P. Robertson, July 31, 2004, Page 15. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf """ D = as_int(D) N = as_int(N) sol = [] a = diop_DN(D, 1) u = a[0][0] if abs(N) == 1: return diop_DN(D, N) elif N > 1: L1 = 0 L2 = integer_nthroot(int(N*(u - 1)/(2*D)), 2)[0] + 1 elif N < -1: L1, _exact = integer_nthroot(-int(N/D), 2) if not _exact: L1 += 1 L2 = integer_nthroot(-int(N*(u + 1)/(2*D)), 2)[0] + 1 else: # N = 0 if D < 0: return [(0, 0)] elif D == 0: return [(0, t)] else: sD, _exact = integer_nthroot(D, 2) if _exact: return [(sD*t, t), (-sD*t, t)] else: return [(0, 0)] for y in range(L1, L2): try: x, _exact = integer_nthroot(N + D*y**2, 2) except ValueError: _exact = False if _exact: sol.append((x, y)) if not equivalent(x, y, -x, y, D, N): sol.append((-x, y)) return sol def equivalent(u, v, r, s, D, N): """ Returns True if two solutions `(u, v)` and `(r, s)` of `x^2 - Dy^2 = N` belongs to the same equivalence class and False otherwise. Explanation =========== Two solutions `(u, v)` and `(r, s)` to the above equation fall to the same equivalence class iff both `(ur - Dvs)` and `(us - vr)` are divisible by `N`. See reference [1]_. No test is performed to test whether `(u, v)` and `(r, s)` are actually solutions to the equation. User should take care of this. Usage ===== ``equivalent(u, v, r, s, D, N)``: `(u, v)` and `(r, s)` are two solutions of the equation `x^2 - Dy^2 = N` and all parameters involved are integers. Examples ======== >>> from sympy.solvers.diophantine.diophantine import equivalent >>> equivalent(18, 5, -18, -5, 13, -1) True >>> equivalent(3, 1, -18, 393, 109, -4) False References ========== .. [1] Solving the generalized Pell equation x**2 - D*y**2 = N, John P. Robertson, July 31, 2004, Page 12. https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf """ return divisible(u*r - D*v*s, N) and divisible(u*s - v*r, N) def length(P, Q, D): r""" Returns the (length of aperiodic part + length of periodic part) of continued fraction representation of `\\frac{P + \sqrt{D}}{Q}`. It is important to remember that this does NOT return the length of the periodic part but the sum of the lengths of the two parts as mentioned above. Usage ===== ``length(P, Q, D)``: ``P``, ``Q`` and ``D`` are integers corresponding to the continued fraction `\\frac{P + \sqrt{D}}{Q}`. Details ======= ``P``, ``D`` and ``Q`` corresponds to P, D and Q in the continued fraction, `\\frac{P + \sqrt{D}}{Q}`. Examples ======== >>> from sympy.solvers.diophantine.diophantine import length >>> length(-2 , 4, 5) # (-2 + sqrt(5))/4 3 >>> length(-5, 4, 17) # (-5 + sqrt(17))/4 4 See Also ======== sympy.ntheory.continued_fraction.continued_fraction_periodic """ from sympy.ntheory.continued_fraction import continued_fraction_periodic v = continued_fraction_periodic(P, Q, D) if type(v[-1]) is list: rpt = len(v[-1]) nonrpt = len(v) - 1 else: rpt = 0 nonrpt = len(v) return rpt + nonrpt def transformation_to_DN(eq): """ This function transforms general quadratic, `ax^2 + bxy + cy^2 + dx + ey + f = 0` to more easy to deal with `X^2 - DY^2 = N` form. Explanation =========== This is used to solve the general quadratic equation by transforming it to the latter form. Refer [1]_ for more detailed information on the transformation. This function returns a tuple (A, B) where A is a 2 X 2 matrix and B is a 2 X 1 matrix such that, Transpose([x y]) = A * Transpose([X Y]) + B Usage ===== ``transformation_to_DN(eq)``: where ``eq`` is the quadratic to be transformed. Examples ======== >>> from sympy.abc import x, y >>> from sympy.solvers.diophantine.diophantine import transformation_to_DN >>> A, B = transformation_to_DN(x**2 - 3*x*y - y**2 - 2*y + 1) >>> A Matrix([ [1/26, 3/26], [ 0, 1/13]]) >>> B Matrix([ [-6/13], [-4/13]]) A, B returned are such that Transpose((x y)) = A * Transpose((X Y)) + B. Substituting these values for `x` and `y` and a bit of simplifying work will give an equation of the form `x^2 - Dy^2 = N`. >>> from sympy.abc import X, Y >>> from sympy import Matrix, simplify >>> u = (A*Matrix([X, Y]) + B)[0] # Transformation for x >>> u X/26 + 3*Y/26 - 6/13 >>> v = (A*Matrix([X, Y]) + B)[1] # Transformation for y >>> v Y/13 - 4/13 Next we will substitute these formulas for `x` and `y` and do ``simplify()``. >>> eq = simplify((x**2 - 3*x*y - y**2 - 2*y + 1).subs(zip((x, y), (u, v)))) >>> eq X**2/676 - Y**2/52 + 17/13 By multiplying the denominator appropriately, we can get a Pell equation in the standard form. >>> eq * 676 X**2 - 13*Y**2 + 884 If only the final equation is needed, ``find_DN()`` can be used. See Also ======== find_DN() References ========== .. [1] Solving the equation ax^2 + bxy + cy^2 + dx + ey + f = 0, John P.Robertson, May 8, 2003, Page 7 - 11. https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == BinaryQuadratic.name: return _transformation_to_DN(var, coeff) def _transformation_to_DN(var, coeff): x, y = var a = coeff[x**2] b = coeff[x*y] c = coeff[y**2] d = coeff[x] e = coeff[y] f = coeff[1] a, b, c, d, e, f = [as_int(i) for i in _remove_gcd(a, b, c, d, e, f)] X, Y = symbols("X, Y", integer=True) if b: B, C = _rational_pq(2*a, b) A, T = _rational_pq(a, B**2) # eq_1 = A*B*X**2 + B*(c*T - A*C**2)*Y**2 + d*T*X + (B*e*T - d*T*C)*Y + f*T*B coeff = {X**2: A*B, X*Y: 0, Y**2: B*(c*T - A*C**2), X: d*T, Y: B*e*T - d*T*C, 1: f*T*B} A_0, B_0 = _transformation_to_DN([X, Y], coeff) return Matrix(2, 2, [S.One/B, -S(C)/B, 0, 1])*A_0, Matrix(2, 2, [S.One/B, -S(C)/B, 0, 1])*B_0 else: if d: B, C = _rational_pq(2*a, d) A, T = _rational_pq(a, B**2) # eq_2 = A*X**2 + c*T*Y**2 + e*T*Y + f*T - A*C**2 coeff = {X**2: A, X*Y: 0, Y**2: c*T, X: 0, Y: e*T, 1: f*T - A*C**2} A_0, B_0 = _transformation_to_DN([X, Y], coeff) return Matrix(2, 2, [S.One/B, 0, 0, 1])*A_0, Matrix(2, 2, [S.One/B, 0, 0, 1])*B_0 + Matrix([-S(C)/B, 0]) else: if e: B, C = _rational_pq(2*c, e) A, T = _rational_pq(c, B**2) # eq_3 = a*T*X**2 + A*Y**2 + f*T - A*C**2 coeff = {X**2: a*T, X*Y: 0, Y**2: A, X: 0, Y: 0, 1: f*T - A*C**2} A_0, B_0 = _transformation_to_DN([X, Y], coeff) return Matrix(2, 2, [1, 0, 0, S.One/B])*A_0, Matrix(2, 2, [1, 0, 0, S.One/B])*B_0 + Matrix([0, -S(C)/B]) else: # TODO: pre-simplification: Not necessary but may simplify # the equation. return Matrix(2, 2, [S.One/a, 0, 0, 1]), Matrix([0, 0]) def find_DN(eq): """ This function returns a tuple, `(D, N)` of the simplified form, `x^2 - Dy^2 = N`, corresponding to the general quadratic, `ax^2 + bxy + cy^2 + dx + ey + f = 0`. Solving the general quadratic is then equivalent to solving the equation `X^2 - DY^2 = N` and transforming the solutions by using the transformation matrices returned by ``transformation_to_DN()``. Usage ===== ``find_DN(eq)``: where ``eq`` is the quadratic to be transformed. Examples ======== >>> from sympy.abc import x, y >>> from sympy.solvers.diophantine.diophantine import find_DN >>> find_DN(x**2 - 3*x*y - y**2 - 2*y + 1) (13, -884) Interpretation of the output is that we get `X^2 -13Y^2 = -884` after transforming `x^2 - 3xy - y^2 - 2y + 1` using the transformation returned by ``transformation_to_DN()``. See Also ======== transformation_to_DN() References ========== .. [1] Solving the equation ax^2 + bxy + cy^2 + dx + ey + f = 0, John P.Robertson, May 8, 2003, Page 7 - 11. https://web.archive.org/web/20160323033111/http://www.jpr2718.org/ax2p.pdf """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == BinaryQuadratic.name: return _find_DN(var, coeff) def _find_DN(var, coeff): x, y = var X, Y = symbols("X, Y", integer=True) A, B = _transformation_to_DN(var, coeff) u = (A*Matrix([X, Y]) + B)[0] v = (A*Matrix([X, Y]) + B)[1] eq = x**2*coeff[x**2] + x*y*coeff[x*y] + y**2*coeff[y**2] + x*coeff[x] + y*coeff[y] + coeff[1] simplified = _mexpand(eq.subs(zip((x, y), (u, v)))) coeff = simplified.as_coefficients_dict() return -coeff[Y**2]/coeff[X**2], -coeff[1]/coeff[X**2] def check_param(x, y, a, params): """ If there is a number modulo ``a`` such that ``x`` and ``y`` are both integers, then return a parametric representation for ``x`` and ``y`` else return (None, None). Here ``x`` and ``y`` are functions of ``t``. """ from sympy.simplify.simplify import clear_coefficients if x.is_number and not x.is_Integer: return DiophantineSolutionSet([x, y], parameters=params) if y.is_number and not y.is_Integer: return DiophantineSolutionSet([x, y], parameters=params) m, n = symbols("m, n", integer=True) c, p = (m*x + n*y).as_content_primitive() if a % c.q: return DiophantineSolutionSet([x, y], parameters=params) # clear_coefficients(mx + b, R)[1] -> (R - b)/m eq = clear_coefficients(x, m)[1] - clear_coefficients(y, n)[1] junk, eq = eq.as_content_primitive() return _diop_solve(eq, params=params) def diop_ternary_quadratic(eq, parameterize=False): """ Solves the general quadratic ternary form, `ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0`. Returns a tuple `(x, y, z)` which is a base solution for the above equation. If there are no solutions, `(None, None, None)` is returned. Usage ===== ``diop_ternary_quadratic(eq)``: Return a tuple containing a basic solution to ``eq``. Details ======= ``eq`` should be an homogeneous expression of degree two in three variables and it is assumed to be zero. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic >>> diop_ternary_quadratic(x**2 + 3*y**2 - z**2) (1, 0, 1) >>> diop_ternary_quadratic(4*x**2 + 5*y**2 - z**2) (1, 0, 2) >>> diop_ternary_quadratic(45*x**2 - 7*y**2 - 8*x*y - z**2) (28, 45, 105) >>> diop_ternary_quadratic(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y) (9, 1, 5) """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type in ( HomogeneousTernaryQuadratic.name, HomogeneousTernaryQuadraticNormal.name): sol = _diop_ternary_quadratic(var, coeff) if len(sol) > 0: x_0, y_0, z_0 = list(sol)[0] else: x_0, y_0, z_0 = None, None, None if parameterize: return _parametrize_ternary_quadratic( (x_0, y_0, z_0), var, coeff) return x_0, y_0, z_0 def _diop_ternary_quadratic(_var, coeff): eq = sum([i*coeff[i] for i in coeff]) if HomogeneousTernaryQuadratic(eq).matches(): return HomogeneousTernaryQuadratic(eq, free_symbols=_var).solve() elif HomogeneousTernaryQuadraticNormal(eq).matches(): return HomogeneousTernaryQuadraticNormal(eq, free_symbols=_var).solve() def transformation_to_normal(eq): """ Returns the transformation Matrix that converts a general ternary quadratic equation ``eq`` (`ax^2 + by^2 + cz^2 + dxy + eyz + fxz`) to a form without cross terms: `ax^2 + by^2 + cz^2 = 0`. This is not used in solving ternary quadratics; it is only implemented for the sake of completeness. """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type in ( "homogeneous_ternary_quadratic", "homogeneous_ternary_quadratic_normal"): return _transformation_to_normal(var, coeff) def _transformation_to_normal(var, coeff): _var = list(var) # copy x, y, z = var if not any(coeff[i**2] for i in var): # https://math.stackexchange.com/questions/448051/transform-quadratic-ternary-form-to-normal-form/448065#448065 a = coeff[x*y] b = coeff[y*z] c = coeff[x*z] swap = False if not a: # b can't be 0 or else there aren't 3 vars swap = True a, b = b, a T = Matrix(((1, 1, -b/a), (1, -1, -c/a), (0, 0, 1))) if swap: T.row_swap(0, 1) T.col_swap(0, 1) return T if coeff[x**2] == 0: # If the coefficient of x is zero change the variables if coeff[y**2] == 0: _var[0], _var[2] = var[2], var[0] T = _transformation_to_normal(_var, coeff) T.row_swap(0, 2) T.col_swap(0, 2) return T else: _var[0], _var[1] = var[1], var[0] T = _transformation_to_normal(_var, coeff) T.row_swap(0, 1) T.col_swap(0, 1) return T # Apply the transformation x --> X - (B*Y + C*Z)/(2*A) if coeff[x*y] != 0 or coeff[x*z] != 0: A = coeff[x**2] B = coeff[x*y] C = coeff[x*z] D = coeff[y**2] E = coeff[y*z] F = coeff[z**2] _coeff = dict() _coeff[x**2] = 4*A**2 _coeff[y**2] = 4*A*D - B**2 _coeff[z**2] = 4*A*F - C**2 _coeff[y*z] = 4*A*E - 2*B*C _coeff[x*y] = 0 _coeff[x*z] = 0 T_0 = _transformation_to_normal(_var, _coeff) return Matrix(3, 3, [1, S(-B)/(2*A), S(-C)/(2*A), 0, 1, 0, 0, 0, 1])*T_0 elif coeff[y*z] != 0: if coeff[y**2] == 0: if coeff[z**2] == 0: # Equations of the form A*x**2 + E*yz = 0. # Apply transformation y -> Y + Z ans z -> Y - Z return Matrix(3, 3, [1, 0, 0, 0, 1, 1, 0, 1, -1]) else: # Ax**2 + E*y*z + F*z**2 = 0 _var[0], _var[2] = var[2], var[0] T = _transformation_to_normal(_var, coeff) T.row_swap(0, 2) T.col_swap(0, 2) return T else: # A*x**2 + D*y**2 + E*y*z + F*z**2 = 0, F may be zero _var[0], _var[1] = var[1], var[0] T = _transformation_to_normal(_var, coeff) T.row_swap(0, 1) T.col_swap(0, 1) return T else: return Matrix.eye(3) def parametrize_ternary_quadratic(eq): """ Returns the parametrized general solution for the ternary quadratic equation ``eq`` which has the form `ax^2 + by^2 + cz^2 + fxy + gyz + hxz = 0`. Examples ======== >>> from sympy import Tuple, ordered >>> from sympy.abc import x, y, z >>> from sympy.solvers.diophantine.diophantine import parametrize_ternary_quadratic The parametrized solution may be returned with three parameters: >>> parametrize_ternary_quadratic(2*x**2 + y**2 - 2*z**2) (p**2 - 2*q**2, -2*p**2 + 4*p*q - 4*p*r - 4*q**2, p**2 - 4*p*q + 2*q**2 - 4*q*r) There might also be only two parameters: >>> parametrize_ternary_quadratic(4*x**2 + 2*y**2 - 3*z**2) (2*p**2 - 3*q**2, -4*p**2 + 12*p*q - 6*q**2, 4*p**2 - 8*p*q + 6*q**2) Notes ===== Consider ``p`` and ``q`` in the previous 2-parameter solution and observe that more than one solution can be represented by a given pair of parameters. If `p` and ``q`` are not coprime, this is trivially true since the common factor will also be a common factor of the solution values. But it may also be true even when ``p`` and ``q`` are coprime: >>> sol = Tuple(*_) >>> p, q = ordered(sol.free_symbols) >>> sol.subs([(p, 3), (q, 2)]) (6, 12, 12) >>> sol.subs([(q, 1), (p, 1)]) (-1, 2, 2) >>> sol.subs([(q, 0), (p, 1)]) (2, -4, 4) >>> sol.subs([(q, 1), (p, 0)]) (-3, -6, 6) Except for sign and a common factor, these are equivalent to the solution of (1, 2, 2). References ========== .. [1] The algorithmic resolution of Diophantine equations, Nigel P. Smart, London Mathematical Society Student Texts 41, Cambridge University Press, Cambridge, 1998. """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type in ( "homogeneous_ternary_quadratic", "homogeneous_ternary_quadratic_normal"): x_0, y_0, z_0 = list(_diop_ternary_quadratic(var, coeff))[0] return _parametrize_ternary_quadratic( (x_0, y_0, z_0), var, coeff) def _parametrize_ternary_quadratic(solution, _var, coeff): # called for a*x**2 + b*y**2 + c*z**2 + d*x*y + e*y*z + f*x*z = 0 assert 1 not in coeff x_0, y_0, z_0 = solution v = list(_var) # copy if x_0 is None: return (None, None, None) if solution.count(0) >= 2: # if there are 2 zeros the equation reduces # to k*X**2 == 0 where X is x, y, or z so X must # be zero, too. So there is only the trivial # solution. return (None, None, None) if x_0 == 0: v[0], v[1] = v[1], v[0] y_p, x_p, z_p = _parametrize_ternary_quadratic( (y_0, x_0, z_0), v, coeff) return x_p, y_p, z_p x, y, z = v r, p, q = symbols("r, p, q", integer=True) eq = sum(k*v for k, v in coeff.items()) eq_1 = _mexpand(eq.subs(zip( (x, y, z), (r*x_0, r*y_0 + p, r*z_0 + q)))) A, B = eq_1.as_independent(r, as_Add=True) x = A*x_0 y = (A*y_0 - _mexpand(B/r*p)) z = (A*z_0 - _mexpand(B/r*q)) return _remove_gcd(x, y, z) def diop_ternary_quadratic_normal(eq, parameterize=False): """ Solves the quadratic ternary diophantine equation, `ax^2 + by^2 + cz^2 = 0`. Explanation =========== Here the coefficients `a`, `b`, and `c` should be non zero. Otherwise the equation will be a quadratic binary or univariate equation. If solvable, returns a tuple `(x, y, z)` that satisfies the given equation. If the equation does not have integer solutions, `(None, None, None)` is returned. Usage ===== ``diop_ternary_quadratic_normal(eq)``: where ``eq`` is an equation of the form `ax^2 + by^2 + cz^2 = 0`. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.solvers.diophantine.diophantine import diop_ternary_quadratic_normal >>> diop_ternary_quadratic_normal(x**2 + 3*y**2 - z**2) (1, 0, 1) >>> diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2) (1, 0, 2) >>> diop_ternary_quadratic_normal(34*x**2 - 3*y**2 - 301*z**2) (4, 9, 1) """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == HomogeneousTernaryQuadraticNormal.name: sol = _diop_ternary_quadratic_normal(var, coeff) if len(sol) > 0: x_0, y_0, z_0 = list(sol)[0] else: x_0, y_0, z_0 = None, None, None if parameterize: return _parametrize_ternary_quadratic( (x_0, y_0, z_0), var, coeff) return x_0, y_0, z_0 def _diop_ternary_quadratic_normal(var, coeff): eq = sum([i * coeff[i] for i in coeff]) return HomogeneousTernaryQuadraticNormal(eq, free_symbols=var).solve() def sqf_normal(a, b, c, steps=False): """ Return `a', b', c'`, the coefficients of the square-free normal form of `ax^2 + by^2 + cz^2 = 0`, where `a', b', c'` are pairwise prime. If `steps` is True then also return three tuples: `sq`, `sqf`, and `(a', b', c')` where `sq` contains the square factors of `a`, `b` and `c` after removing the `gcd(a, b, c)`; `sqf` contains the values of `a`, `b` and `c` after removing both the `gcd(a, b, c)` and the square factors. The solutions for `ax^2 + by^2 + cz^2 = 0` can be recovered from the solutions of `a'x^2 + b'y^2 + c'z^2 = 0`. Examples ======== >>> from sympy.solvers.diophantine.diophantine import sqf_normal >>> sqf_normal(2 * 3**2 * 5, 2 * 5 * 11, 2 * 7**2 * 11) (11, 1, 5) >>> sqf_normal(2 * 3**2 * 5, 2 * 5 * 11, 2 * 7**2 * 11, True) ((3, 1, 7), (5, 55, 11), (11, 1, 5)) References ========== .. [1] Legendre's Theorem, Legrange's Descent, http://public.csusm.edu/aitken_html/notes/legendre.pdf See Also ======== reconstruct() """ ABC = _remove_gcd(a, b, c) sq = tuple(square_factor(i) for i in ABC) sqf = A, B, C = tuple([i//j**2 for i,j in zip(ABC, sq)]) pc = igcd(A, B) A /= pc B /= pc pa = igcd(B, C) B /= pa C /= pa pb = igcd(A, C) A /= pb B /= pb A *= pa B *= pb C *= pc if steps: return (sq, sqf, (A, B, C)) else: return A, B, C def square_factor(a): r""" Returns an integer `c` s.t. `a = c^2k, \ c,k \in Z`. Here `k` is square free. `a` can be given as an integer or a dictionary of factors. Examples ======== >>> from sympy.solvers.diophantine.diophantine import square_factor >>> square_factor(24) 2 >>> square_factor(-36*3) 6 >>> square_factor(1) 1 >>> square_factor({3: 2, 2: 1, -1: 1}) # -18 3 See Also ======== sympy.ntheory.factor_.core """ f = a if isinstance(a, dict) else factorint(a) return Mul(*[p**(e//2) for p, e in f.items()]) def reconstruct(A, B, z): """ Reconstruct the `z` value of an equivalent solution of `ax^2 + by^2 + cz^2` from the `z` value of a solution of the square-free normal form of the equation, `a'*x^2 + b'*y^2 + c'*z^2`, where `a'`, `b'` and `c'` are square free and `gcd(a', b', c') == 1`. """ f = factorint(igcd(A, B)) for p, e in f.items(): if e != 1: raise ValueError('a and b should be square-free') z *= p return z def ldescent(A, B): """ Return a non-trivial solution to `w^2 = Ax^2 + By^2` using Lagrange's method; return None if there is no such solution. . Here, `A \\neq 0` and `B \\neq 0` and `A` and `B` are square free. Output a tuple `(w_0, x_0, y_0)` which is a solution to the above equation. Examples ======== >>> from sympy.solvers.diophantine.diophantine import ldescent >>> ldescent(1, 1) # w^2 = x^2 + y^2 (1, 1, 0) >>> ldescent(4, -7) # w^2 = 4x^2 - 7y^2 (2, -1, 0) This means that `x = -1, y = 0` and `w = 2` is a solution to the equation `w^2 = 4x^2 - 7y^2` >>> ldescent(5, -1) # w^2 = 5x^2 - y^2 (2, 1, -1) References ========== .. [1] The algorithmic resolution of Diophantine equations, Nigel P. Smart, London Mathematical Society Student Texts 41, Cambridge University Press, Cambridge, 1998. .. [2] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin, [online], Available: http://eprints.nottingham.ac.uk/60/1/kvxefz87.pdf """ if abs(A) > abs(B): w, y, x = ldescent(B, A) return w, x, y if A == 1: return (1, 1, 0) if B == 1: return (1, 0, 1) if B == -1: # and A == -1 return r = sqrt_mod(A, B) Q = (r**2 - A) // B if Q == 0: B_0 = 1 d = 0 else: div = divisors(Q) B_0 = None for i in div: sQ, _exact = integer_nthroot(abs(Q) // i, 2) if _exact: B_0, d = sign(Q)*i, sQ break if B_0 is not None: W, X, Y = ldescent(A, B_0) return _remove_gcd((-A*X + r*W), (r*X - W), Y*(B_0*d)) def descent(A, B): """ Returns a non-trivial solution, (x, y, z), to `x^2 = Ay^2 + Bz^2` using Lagrange's descent method with lattice-reduction. `A` and `B` are assumed to be valid for such a solution to exist. This is faster than the normal Lagrange's descent algorithm because the Gaussian reduction is used. Examples ======== >>> from sympy.solvers.diophantine.diophantine import descent >>> descent(3, 1) # x**2 = 3*y**2 + z**2 (1, 0, 1) `(x, y, z) = (1, 0, 1)` is a solution to the above equation. >>> descent(41, -113) (-16, -3, 1) References ========== .. [1] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin, Mathematics of Computation, Volume 00, Number 0. """ if abs(A) > abs(B): x, y, z = descent(B, A) return x, z, y if B == 1: return (1, 0, 1) if A == 1: return (1, 1, 0) if B == -A: return (0, 1, 1) if B == A: x, z, y = descent(-1, A) return (A*y, z, x) w = sqrt_mod(A, B) x_0, z_0 = gaussian_reduce(w, A, B) t = (x_0**2 - A*z_0**2) // B t_2 = square_factor(t) t_1 = t // t_2**2 x_1, z_1, y_1 = descent(A, t_1) return _remove_gcd(x_0*x_1 + A*z_0*z_1, z_0*x_1 + x_0*z_1, t_1*t_2*y_1) def gaussian_reduce(w, a, b): r""" Returns a reduced solution `(x, z)` to the congruence `X^2 - aZ^2 \equiv 0 \ (mod \ b)` so that `x^2 + |a|z^2` is minimal. Details ======= Here ``w`` is a solution of the congruence `x^2 \equiv a \ (mod \ b)` References ========== .. [1] Gaussian lattice Reduction [online]. Available: http://home.ie.cuhk.edu.hk/~wkshum/wordpress/?p=404 .. [2] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin, Mathematics of Computation, Volume 00, Number 0. """ u = (0, 1) v = (1, 0) if dot(u, v, w, a, b) < 0: v = (-v[0], -v[1]) if norm(u, w, a, b) < norm(v, w, a, b): u, v = v, u while norm(u, w, a, b) > norm(v, w, a, b): k = dot(u, v, w, a, b) // dot(v, v, w, a, b) u, v = v, (u[0]- k*v[0], u[1]- k*v[1]) u, v = v, u if dot(u, v, w, a, b) < dot(v, v, w, a, b)/2 or norm((u[0]-v[0], u[1]-v[1]), w, a, b) > norm(v, w, a, b): c = v else: c = (u[0] - v[0], u[1] - v[1]) return c[0]*w + b*c[1], c[0] def dot(u, v, w, a, b): r""" Returns a special dot product of the vectors `u = (u_{1}, u_{2})` and `v = (v_{1}, v_{2})` which is defined in order to reduce solution of the congruence equation `X^2 - aZ^2 \equiv 0 \ (mod \ b)`. """ u_1, u_2 = u v_1, v_2 = v return (w*u_1 + b*u_2)*(w*v_1 + b*v_2) + abs(a)*u_1*v_1 def norm(u, w, a, b): r""" Returns the norm of the vector `u = (u_{1}, u_{2})` under the dot product defined by `u \cdot v = (wu_{1} + bu_{2})(w*v_{1} + bv_{2}) + |a|*u_{1}*v_{1}` where `u = (u_{1}, u_{2})` and `v = (v_{1}, v_{2})`. """ u_1, u_2 = u return sqrt(dot((u_1, u_2), (u_1, u_2), w, a, b)) def holzer(x, y, z, a, b, c): r""" Simplify the solution `(x, y, z)` of the equation `ax^2 + by^2 = cz^2` with `a, b, c > 0` and `z^2 \geq \mid ab \mid` to a new reduced solution `(x', y', z')` such that `z'^2 \leq \mid ab \mid`. The algorithm is an interpretation of Mordell's reduction as described on page 8 of Cremona and Rusin's paper [1]_ and the work of Mordell in reference [2]_. References ========== .. [1] Efficient Solution of Rational Conices, J. E. Cremona and D. Rusin, Mathematics of Computation, Volume 00, Number 0. .. [2] Diophantine Equations, L. J. Mordell, page 48. """ if _odd(c): k = 2*c else: k = c//2 small = a*b*c step = 0 while True: t1, t2, t3 = a*x**2, b*y**2, c*z**2 # check that it's a solution if t1 + t2 != t3: if step == 0: raise ValueError('bad starting solution') break x_0, y_0, z_0 = x, y, z if max(t1, t2, t3) <= small: # Holzer condition break uv = u, v = base_solution_linear(k, y_0, -x_0) if None in uv: break p, q = -(a*u*x_0 + b*v*y_0), c*z_0 r = Rational(p, q) if _even(c): w = _nint_or_floor(p, q) assert abs(w - r) <= S.Half else: w = p//q # floor if _odd(a*u + b*v + c*w): w += 1 assert abs(w - r) <= S.One A = (a*u**2 + b*v**2 + c*w**2) B = (a*u*x_0 + b*v*y_0 + c*w*z_0) x = Rational(x_0*A - 2*u*B, k) y = Rational(y_0*A - 2*v*B, k) z = Rational(z_0*A - 2*w*B, k) assert all(i.is_Integer for i in (x, y, z)) step += 1 return tuple([int(i) for i in (x_0, y_0, z_0)]) def diop_general_pythagorean(eq, param=symbols("m", integer=True)): """ Solves the general pythagorean equation, `a_{1}^2x_{1}^2 + a_{2}^2x_{2}^2 + . . . + a_{n}^2x_{n}^2 - a_{n + 1}^2x_{n + 1}^2 = 0`. Returns a tuple which contains a parametrized solution to the equation, sorted in the same order as the input variables. Usage ===== ``diop_general_pythagorean(eq, param)``: where ``eq`` is a general pythagorean equation which is assumed to be zero and ``param`` is the base parameter used to construct other parameters by subscripting. Examples ======== >>> from sympy.solvers.diophantine.diophantine import diop_general_pythagorean >>> from sympy.abc import a, b, c, d, e >>> diop_general_pythagorean(a**2 + b**2 + c**2 - d**2) (m1**2 + m2**2 - m3**2, 2*m1*m3, 2*m2*m3, m1**2 + m2**2 + m3**2) >>> diop_general_pythagorean(9*a**2 - 4*b**2 + 16*c**2 + 25*d**2 + e**2) (10*m1**2 + 10*m2**2 + 10*m3**2 - 10*m4**2, 15*m1**2 + 15*m2**2 + 15*m3**2 + 15*m4**2, 15*m1*m4, 12*m2*m4, 60*m3*m4) """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == GeneralPythagorean.name: if param is None: params = None else: params = symbols('%s1:%i' % (param, len(var)), integer=True) return list(GeneralPythagorean(eq).solve(parameters=params))[0] def diop_general_sum_of_squares(eq, limit=1): r""" Solves the equation `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`. Returns at most ``limit`` number of solutions. Usage ===== ``general_sum_of_squares(eq, limit)`` : Here ``eq`` is an expression which is assumed to be zero. Also, ``eq`` should be in the form, `x_{1}^2 + x_{2}^2 + . . . + x_{n}^2 - k = 0`. Details ======= When `n = 3` if `k = 4^a(8m + 7)` for some `a, m \in Z` then there will be no solutions. Refer [1]_ for more details. Examples ======== >>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_squares >>> from sympy.abc import a, b, c, d, e >>> diop_general_sum_of_squares(a**2 + b**2 + c**2 + d**2 + e**2 - 2345) {(15, 22, 22, 24, 24)} Reference ========= .. [1] Representing an integer as a sum of three squares, [online], Available: http://www.proofwiki.org/wiki/Integer_as_Sum_of_Three_Squares """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == GeneralSumOfSquares.name: return set(GeneralSumOfSquares(eq).solve(limit=limit)) def diop_general_sum_of_even_powers(eq, limit=1): """ Solves the equation `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0` where `e` is an even, integer power. Returns at most ``limit`` number of solutions. Usage ===== ``general_sum_of_even_powers(eq, limit)`` : Here ``eq`` is an expression which is assumed to be zero. Also, ``eq`` should be in the form, `x_{1}^e + x_{2}^e + . . . + x_{n}^e - k = 0`. Examples ======== >>> from sympy.solvers.diophantine.diophantine import diop_general_sum_of_even_powers >>> from sympy.abc import a, b >>> diop_general_sum_of_even_powers(a**4 + b**4 - (2**4 + 3**4)) {(2, 3)} See Also ======== power_representation """ var, coeff, diop_type = classify_diop(eq, _dict=False) if diop_type == GeneralSumOfEvenPowers.name: return set(GeneralSumOfEvenPowers(eq).solve(limit=limit)) ## Functions below this comment can be more suitably grouped under ## an Additive number theory module rather than the Diophantine ## equation module. def partition(n, k=None, zeros=False): """ Returns a generator that can be used to generate partitions of an integer `n`. Explanation =========== A partition of `n` is a set of positive integers which add up to `n`. For example, partitions of 3 are 3, 1 + 2, 1 + 1 + 1. A partition is returned as a tuple. If ``k`` equals None, then all possible partitions are returned irrespective of their size, otherwise only the partitions of size ``k`` are returned. If the ``zero`` parameter is set to True then a suitable number of zeros are added at the end of every partition of size less than ``k``. ``zero`` parameter is considered only if ``k`` is not None. When the partitions are over, the last `next()` call throws the ``StopIteration`` exception, so this function should always be used inside a try - except block. Details ======= ``partition(n, k)``: Here ``n`` is a positive integer and ``k`` is the size of the partition which is also positive integer. Examples ======== >>> from sympy.solvers.diophantine.diophantine import partition >>> f = partition(5) >>> next(f) (1, 1, 1, 1, 1) >>> next(f) (1, 1, 1, 2) >>> g = partition(5, 3) >>> next(g) (1, 1, 3) >>> next(g) (1, 2, 2) >>> g = partition(5, 3, zeros=True) >>> next(g) (0, 0, 5) """ from sympy.utilities.iterables import ordered_partitions if not zeros or k is None: for i in ordered_partitions(n, k): yield tuple(i) else: for m in range(1, k + 1): for i in ordered_partitions(n, m): i = tuple(i) yield (0,)*(k - len(i)) + i def prime_as_sum_of_two_squares(p): """ Represent a prime `p` as a unique sum of two squares; this can only be done if the prime is congruent to 1 mod 4. Examples ======== >>> from sympy.solvers.diophantine.diophantine import prime_as_sum_of_two_squares >>> prime_as_sum_of_two_squares(7) # can't be done >>> prime_as_sum_of_two_squares(5) (1, 2) Reference ========= .. [1] Representing a number as a sum of four squares, [online], Available: http://schorn.ch/lagrange.html See Also ======== sum_of_squares() """ if not p % 4 == 1: return if p % 8 == 5: b = 2 else: b = 3 while pow(b, (p - 1) // 2, p) == 1: b = nextprime(b) b = pow(b, (p - 1) // 4, p) a = p while b**2 > p: a, b = b, a % b return (int(a % b), int(b)) # convert from long def sum_of_three_squares(n): r""" Returns a 3-tuple `(a, b, c)` such that `a^2 + b^2 + c^2 = n` and `a, b, c \geq 0`. Returns None if `n = 4^a(8m + 7)` for some `a, m \in Z`. See [1]_ for more details. Usage ===== ``sum_of_three_squares(n)``: Here ``n`` is a non-negative integer. Examples ======== >>> from sympy.solvers.diophantine.diophantine import sum_of_three_squares >>> sum_of_three_squares(44542) (18, 37, 207) References ========== .. [1] Representing a number as a sum of three squares, [online], Available: http://schorn.ch/lagrange.html See Also ======== sum_of_squares() """ special = {1:(1, 0, 0), 2:(1, 1, 0), 3:(1, 1, 1), 10: (1, 3, 0), 34: (3, 3, 4), 58:(3, 7, 0), 85:(6, 7, 0), 130:(3, 11, 0), 214:(3, 6, 13), 226:(8, 9, 9), 370:(8, 9, 15), 526:(6, 7, 21), 706:(15, 15, 16), 730:(1, 27, 0), 1414:(6, 17, 33), 1906:(13, 21, 36), 2986: (21, 32, 39), 9634: (56, 57, 57)} v = 0 if n == 0: return (0, 0, 0) v = multiplicity(4, n) n //= 4**v if n % 8 == 7: return if n in special.keys(): x, y, z = special[n] return _sorted_tuple(2**v*x, 2**v*y, 2**v*z) s, _exact = integer_nthroot(n, 2) if _exact: return (2**v*s, 0, 0) x = None if n % 8 == 3: s = s if _odd(s) else s - 1 for x in range(s, -1, -2): N = (n - x**2) // 2 if isprime(N): y, z = prime_as_sum_of_two_squares(N) return _sorted_tuple(2**v*x, 2**v*(y + z), 2**v*abs(y - z)) return if n % 8 == 2 or n % 8 == 6: s = s if _odd(s) else s - 1 else: s = s - 1 if _odd(s) else s for x in range(s, -1, -2): N = n - x**2 if isprime(N): y, z = prime_as_sum_of_two_squares(N) return _sorted_tuple(2**v*x, 2**v*y, 2**v*z) def sum_of_four_squares(n): r""" Returns a 4-tuple `(a, b, c, d)` such that `a^2 + b^2 + c^2 + d^2 = n`. Here `a, b, c, d \geq 0`. Usage ===== ``sum_of_four_squares(n)``: Here ``n`` is a non-negative integer. Examples ======== >>> from sympy.solvers.diophantine.diophantine import sum_of_four_squares >>> sum_of_four_squares(3456) (8, 8, 32, 48) >>> sum_of_four_squares(1294585930293) (0, 1234, 2161, 1137796) References ========== .. [1] Representing a number as a sum of four squares, [online], Available: http://schorn.ch/lagrange.html See Also ======== sum_of_squares() """ if n == 0: return (0, 0, 0, 0) v = multiplicity(4, n) n //= 4**v if n % 8 == 7: d = 2 n = n - 4 elif n % 8 == 6 or n % 8 == 2: d = 1 n = n - 1 else: d = 0 x, y, z = sum_of_three_squares(n) return _sorted_tuple(2**v*d, 2**v*x, 2**v*y, 2**v*z) def power_representation(n, p, k, zeros=False): r""" Returns a generator for finding k-tuples of integers, `(n_{1}, n_{2}, . . . n_{k})`, such that `n = n_{1}^p + n_{2}^p + . . . n_{k}^p`. Usage ===== ``power_representation(n, p, k, zeros)``: Represent non-negative number ``n`` as a sum of ``k`` ``p``\ th powers. If ``zeros`` is true, then the solutions is allowed to contain zeros. Examples ======== >>> from sympy.solvers.diophantine.diophantine import power_representation Represent 1729 as a sum of two cubes: >>> f = power_representation(1729, 3, 2) >>> next(f) (9, 10) >>> next(f) (1, 12) If the flag `zeros` is True, the solution may contain tuples with zeros; any such solutions will be generated after the solutions without zeros: >>> list(power_representation(125, 2, 3, zeros=True)) [(5, 6, 8), (3, 4, 10), (0, 5, 10), (0, 2, 11)] For even `p` the `permute_sign` function can be used to get all signed values: >>> from sympy.utilities.iterables import permute_signs >>> list(permute_signs((1, 12))) [(1, 12), (-1, 12), (1, -12), (-1, -12)] All possible signed permutations can also be obtained: >>> from sympy.utilities.iterables import signed_permutations >>> list(signed_permutations((1, 12))) [(1, 12), (-1, 12), (1, -12), (-1, -12), (12, 1), (-12, 1), (12, -1), (-12, -1)] """ n, p, k = [as_int(i) for i in (n, p, k)] if n < 0: if p % 2: for t in power_representation(-n, p, k, zeros): yield tuple(-i for i in t) return if p < 1 or k < 1: raise ValueError(filldedent(''' Expecting positive integers for `(p, k)`, but got `(%s, %s)`''' % (p, k))) if n == 0: if zeros: yield (0,)*k return if k == 1: if p == 1: yield (n,) else: be = perfect_power(n) if be: b, e = be d, r = divmod(e, p) if not r: yield (b**d,) return if p == 1: for t in partition(n, k, zeros=zeros): yield t return if p == 2: feasible = _can_do_sum_of_squares(n, k) if not feasible: return if not zeros and n > 33 and k >= 5 and k <= n and n - k in ( 13, 10, 7, 5, 4, 2, 1): '''Todd G. Will, "When Is n^2 a Sum of k Squares?", [online]. Available: https://www.maa.org/sites/default/files/Will-MMz-201037918.pdf''' return if feasible is not True: # it's prime and k == 2 yield prime_as_sum_of_two_squares(n) return if k == 2 and p > 2: be = perfect_power(n) if be and be[1] % p == 0: return # Fermat: a**n + b**n = c**n has no solution for n > 2 if n >= k: a = integer_nthroot(n - (k - 1), p)[0] for t in pow_rep_recursive(a, k, n, [], p): yield tuple(reversed(t)) if zeros: a = integer_nthroot(n, p)[0] for i in range(1, k): for t in pow_rep_recursive(a, i, n, [], p): yield tuple(reversed(t + (0,)*(k - i))) sum_of_powers = power_representation def pow_rep_recursive(n_i, k, n_remaining, terms, p): if k == 0 and n_remaining == 0: yield tuple(terms) else: if n_i >= 1 and k > 0: yield from pow_rep_recursive(n_i - 1, k, n_remaining, terms, p) residual = n_remaining - pow(n_i, p) if residual >= 0: yield from pow_rep_recursive(n_i, k - 1, residual, terms + [n_i], p) def sum_of_squares(n, k, zeros=False): """Return a generator that yields the k-tuples of nonnegative values, the squares of which sum to n. If zeros is False (default) then the solution will not contain zeros. The nonnegative elements of a tuple are sorted. * If k == 1 and n is square, (n,) is returned. * If k == 2 then n can only be written as a sum of squares if every prime in the factorization of n that has the form 4*k + 3 has an even multiplicity. If n is prime then it can only be written as a sum of two squares if it is in the form 4*k + 1. * if k == 3 then n can be written as a sum of squares if it does not have the form 4**m*(8*k + 7). * all integers can be written as the sum of 4 squares. * if k > 4 then n can be partitioned and each partition can be written as a sum of 4 squares; if n is not evenly divisible by 4 then n can be written as a sum of squares only if the an additional partition can be written as sum of squares. For example, if k = 6 then n is partitioned into two parts, the first being written as a sum of 4 squares and the second being written as a sum of 2 squares -- which can only be done if the condition above for k = 2 can be met, so this will automatically reject certain partitions of n. Examples ======== >>> from sympy.solvers.diophantine.diophantine import sum_of_squares >>> list(sum_of_squares(25, 2)) [(3, 4)] >>> list(sum_of_squares(25, 2, True)) [(3, 4), (0, 5)] >>> list(sum_of_squares(25, 4)) [(1, 2, 2, 4)] See Also ======== sympy.utilities.iterables.signed_permutations """ yield from power_representation(n, 2, k, zeros) def _can_do_sum_of_squares(n, k): """Return True if n can be written as the sum of k squares, False if it can't, or 1 if ``k == 2`` and ``n`` is prime (in which case it *can* be written as a sum of two squares). A False is returned only if it can't be written as ``k``-squares, even if 0s are allowed. """ if k < 1: return False if n < 0: return False if n == 0: return True if k == 1: return is_square(n) if k == 2: if n in (1, 2): return True if isprime(n): if n % 4 == 1: return 1 # signal that it was prime return False else: f = factorint(n) for p, m in f.items(): # we can proceed iff no prime factor in the form 4*k + 3 # has an odd multiplicity if (p % 4 == 3) and m % 2: return False return True if k == 3: if (n//4**multiplicity(4, n)) % 8 == 7: return False # every number can be written as a sum of 4 squares; for k > 4 partitions # can be 0 return True sympy-sympy-1.9/sympy/solvers/diophantine/tests/000077500000000000000000000000001412543434000222455ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/diophantine/tests/__init__.py000066400000000000000000000000001412543434000243440ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/diophantine/tests/test_diophantine.py000066400000000000000000001211311412543434000261570ustar00rootroot00000000000000from sympy import (Add, Matrix, Mul, S, symbols, Eq, pi, factorint, oo, powsimp, Rational) from sympy.core.function import _mexpand from sympy.core.compatibility import ordered from sympy.functions.elementary.trigonometric import sin from sympy.solvers.diophantine import diophantine from sympy.solvers.diophantine.diophantine import (diop_DN, diop_solve, diop_ternary_quadratic_normal, diop_general_pythagorean, diop_ternary_quadratic, diop_linear, diop_quadratic, diop_general_sum_of_squares, diop_general_sum_of_even_powers, descent, diop_bf_DN, divisible, equivalent, find_DN, ldescent, length, reconstruct, partition, power_representation, prime_as_sum_of_two_squares, square_factor, sum_of_four_squares, sum_of_three_squares, transformation_to_DN, transformation_to_normal, classify_diop, base_solution_linear, cornacchia, sqf_normal, gaussian_reduce, holzer, check_param, parametrize_ternary_quadratic, sum_of_powers, sum_of_squares, _diop_ternary_quadratic_normal, _nint_or_floor, _odd, _even, _remove_gcd, _can_do_sum_of_squares, DiophantineSolutionSet, GeneralPythagorean, BinaryQuadratic) from sympy.utilities import default_sort_key from sympy.testing.pytest import slow, raises, XFAIL from sympy.utilities.iterables import ( signed_permutations) a, b, c, d, p, q, x, y, z, w, t, u, v, X, Y, Z = symbols( "a, b, c, d, p, q, x, y, z, w, t, u, v, X, Y, Z", integer=True) t_0, t_1, t_2, t_3, t_4, t_5, t_6 = symbols("t_:7", integer=True) m1, m2, m3 = symbols('m1:4', integer=True) n1 = symbols('n1', integer=True) def diop_simplify(eq): return _mexpand(powsimp(_mexpand(eq))) def test_input_format(): raises(TypeError, lambda: diophantine(sin(x))) raises(TypeError, lambda: diophantine(x/pi - 3)) def test_nosols(): # diophantine should sympify eq so that these are equivalent assert diophantine(3) == set() assert diophantine(S(3)) == set() def test_univariate(): assert diop_solve((x - 1)*(x - 2)**2) == {(1,), (2,)} assert diop_solve((x - 1)*(x - 2)) == {(1,), (2,)} def test_classify_diop(): raises(TypeError, lambda: classify_diop(x**2/3 - 1)) raises(ValueError, lambda: classify_diop(1)) raises(NotImplementedError, lambda: classify_diop(w*x*y*z - 1)) raises(NotImplementedError, lambda: classify_diop(x**3 + y**3 + z**4 - 90)) assert classify_diop(14*x**2 + 15*x - 42) == ( [x], {1: -42, x: 15, x**2: 14}, 'univariate') assert classify_diop(x*y + z) == ( [x, y, z], {x*y: 1, z: 1}, 'inhomogeneous_ternary_quadratic') assert classify_diop(x*y + z + w + x**2) == ( [w, x, y, z], {x*y: 1, w: 1, x**2: 1, z: 1}, 'inhomogeneous_general_quadratic') assert classify_diop(x*y + x*z + x**2 + 1) == ( [x, y, z], {x*y: 1, x*z: 1, x**2: 1, 1: 1}, 'inhomogeneous_general_quadratic') assert classify_diop(x*y + z + w + 42) == ( [w, x, y, z], {x*y: 1, w: 1, 1: 42, z: 1}, 'inhomogeneous_general_quadratic') assert classify_diop(x*y + z*w) == ( [w, x, y, z], {x*y: 1, w*z: 1}, 'homogeneous_general_quadratic') assert classify_diop(x*y**2 + 1) == ( [x, y], {x*y**2: 1, 1: 1}, 'cubic_thue') assert classify_diop(x**4 + y**4 + z**4 - (1 + 16 + 81)) == ( [x, y, z], {1: -98, x**4: 1, z**4: 1, y**4: 1}, 'general_sum_of_even_powers') assert classify_diop(x**2 + y**2 + z**2) == ( [x, y, z], {x**2: 1, y**2: 1, z**2: 1}, 'homogeneous_ternary_quadratic_normal') def test_linear(): assert diop_solve(x) == (0,) assert diop_solve(1*x) == (0,) assert diop_solve(3*x) == (0,) assert diop_solve(x + 1) == (-1,) assert diop_solve(2*x + 1) == (None,) assert diop_solve(2*x + 4) == (-2,) assert diop_solve(y + x) == (t_0, -t_0) assert diop_solve(y + x + 0) == (t_0, -t_0) assert diop_solve(y + x - 0) == (t_0, -t_0) assert diop_solve(0*x - y - 5) == (-5,) assert diop_solve(3*y + 2*x - 5) == (3*t_0 - 5, -2*t_0 + 5) assert diop_solve(2*x - 3*y - 5) == (3*t_0 - 5, 2*t_0 - 5) assert diop_solve(-2*x - 3*y - 5) == (3*t_0 + 5, -2*t_0 - 5) assert diop_solve(7*x + 5*y) == (5*t_0, -7*t_0) assert diop_solve(2*x + 4*y) == (2*t_0, -t_0) assert diop_solve(4*x + 6*y - 4) == (3*t_0 - 2, -2*t_0 + 2) assert diop_solve(4*x + 6*y - 3) == (None, None) assert diop_solve(0*x + 3*y - 4*z + 5) == (4*t_0 + 5, 3*t_0 + 5) assert diop_solve(4*x + 3*y - 4*z + 5) == (t_0, 8*t_0 + 4*t_1 + 5, 7*t_0 + 3*t_1 + 5) assert diop_solve(4*x + 3*y - 4*z + 5, None) == (0, 5, 5) assert diop_solve(4*x + 2*y + 8*z - 5) == (None, None, None) assert diop_solve(5*x + 7*y - 2*z - 6) == (t_0, -3*t_0 + 2*t_1 + 6, -8*t_0 + 7*t_1 + 18) assert diop_solve(3*x - 6*y + 12*z - 9) == (2*t_0 + 3, t_0 + 2*t_1, t_1) assert diop_solve(6*w + 9*x + 20*y - z) == (t_0, t_1, t_1 + t_2, 6*t_0 + 29*t_1 + 20*t_2) # to ignore constant factors, use diophantine raises(TypeError, lambda: diop_solve(x/2)) def test_quadratic_simple_hyperbolic_case(): # Simple Hyperbolic case: A = C = 0 and B != 0 assert diop_solve(3*x*y + 34*x - 12*y + 1) == \ {(-133, -11), (5, -57)} assert diop_solve(6*x*y + 2*x + 3*y + 1) == set() assert diop_solve(-13*x*y + 2*x - 4*y - 54) == {(27, 0)} assert diop_solve(-27*x*y - 30*x - 12*y - 54) == {(-14, -1)} assert diop_solve(2*x*y + 5*x + 56*y + 7) == {(-161, -3), (-47, -6), (-35, -12), (-29, -69), (-27, 64), (-21, 7), (-9, 1), (105, -2)} assert diop_solve(6*x*y + 9*x + 2*y + 3) == set() assert diop_solve(x*y + x + y + 1) == {(-1, t), (t, -1)} assert diophantine(48*x*y) def test_quadratic_elliptical_case(): # Elliptical case: B**2 - 4AC < 0 assert diop_solve(42*x**2 + 8*x*y + 15*y**2 + 23*x + 17*y - 4915) == {(-11, -1)} assert diop_solve(4*x**2 + 3*y**2 + 5*x - 11*y + 12) == set() assert diop_solve(x**2 + y**2 + 2*x + 2*y + 2) == {(-1, -1)} assert diop_solve(15*x**2 - 9*x*y + 14*y**2 - 23*x - 14*y - 4950) == {(-15, 6)} assert diop_solve(10*x**2 + 12*x*y + 12*y**2 - 34) == \ {(-1, -1), (-1, 2), (1, -2), (1, 1)} def test_quadratic_parabolic_case(): # Parabolic case: B**2 - 4AC = 0 assert check_solutions(8*x**2 - 24*x*y + 18*y**2 + 5*x + 7*y + 16) assert check_solutions(8*x**2 - 24*x*y + 18*y**2 + 6*x + 12*y - 6) assert check_solutions(8*x**2 + 24*x*y + 18*y**2 + 4*x + 6*y - 7) assert check_solutions(-4*x**2 + 4*x*y - y**2 + 2*x - 3) assert check_solutions(x**2 + 2*x*y + y**2 + 2*x + 2*y + 1) assert check_solutions(x**2 - 2*x*y + y**2 + 2*x + 2*y + 1) assert check_solutions(y**2 - 41*x + 40) def test_quadratic_perfect_square(): # B**2 - 4*A*C > 0 # B**2 - 4*A*C is a perfect square assert check_solutions(48*x*y) assert check_solutions(4*x**2 - 5*x*y + y**2 + 2) assert check_solutions(-2*x**2 - 3*x*y + 2*y**2 -2*x - 17*y + 25) assert check_solutions(12*x**2 + 13*x*y + 3*y**2 - 2*x + 3*y - 12) assert check_solutions(8*x**2 + 10*x*y + 2*y**2 - 32*x - 13*y - 23) assert check_solutions(4*x**2 - 4*x*y - 3*y- 8*x - 3) assert check_solutions(- 4*x*y - 4*y**2 - 3*y- 5*x - 10) assert check_solutions(x**2 - y**2 - 2*x - 2*y) assert check_solutions(x**2 - 9*y**2 - 2*x - 6*y) assert check_solutions(4*x**2 - 9*y**2 - 4*x - 12*y - 3) def test_quadratic_non_perfect_square(): # B**2 - 4*A*C is not a perfect square # Used check_solutions() since the solutions are complex expressions involving # square roots and exponents assert check_solutions(x**2 - 2*x - 5*y**2) assert check_solutions(3*x**2 - 2*y**2 - 2*x - 2*y) assert check_solutions(x**2 - x*y - y**2 - 3*y) assert check_solutions(x**2 - 9*y**2 - 2*x - 6*y) assert BinaryQuadratic(x**2 + y**2 + 2*x + 2*y + 2).solve() == {(-1, -1)} def test_issue_9106(): eq = -48 - 2*x*(3*x - 1) + y*(3*y - 1) v = (x, y) for sol in diophantine(eq): assert not diop_simplify(eq.xreplace(dict(zip(v, sol)))) def test_issue_18138(): eq = x**2 - x - y**2 v = (x, y) for sol in diophantine(eq): assert not diop_simplify(eq.xreplace(dict(zip(v, sol)))) @slow def test_quadratic_non_perfect_slow(): assert check_solutions(8*x**2 + 10*x*y - 2*y**2 - 32*x - 13*y - 23) # This leads to very large numbers. # assert check_solutions(5*x**2 - 13*x*y + y**2 - 4*x - 4*y - 15) assert check_solutions(-3*x**2 - 2*x*y + 7*y**2 - 5*x - 7) assert check_solutions(-4 - x + 4*x**2 - y - 3*x*y - 4*y**2) assert check_solutions(1 + 2*x + 2*x**2 + 2*y + x*y - 2*y**2) def test_DN(): # Most of the test cases were adapted from, # Solving the generalized Pell equation x**2 - D*y**2 = N, John P. Robertson, July 31, 2004. # https://web.archive.org/web/20160323033128/http://www.jpr2718.org/pell.pdf # others are verified using Wolfram Alpha. # Covers cases where D <= 0 or D > 0 and D is a square or N = 0 # Solutions are straightforward in these cases. assert diop_DN(3, 0) == [(0, 0)] assert diop_DN(-17, -5) == [] assert diop_DN(-19, 23) == [(2, 1)] assert diop_DN(-13, 17) == [(2, 1)] assert diop_DN(-15, 13) == [] assert diop_DN(0, 5) == [] assert diop_DN(0, 9) == [(3, t)] assert diop_DN(9, 0) == [(3*t, t)] assert diop_DN(16, 24) == [] assert diop_DN(9, 180) == [(18, 4)] assert diop_DN(9, -180) == [(12, 6)] assert diop_DN(7, 0) == [(0, 0)] # When equation is x**2 + y**2 = N # Solutions are interchangeable assert diop_DN(-1, 5) == [(2, 1), (1, 2)] assert diop_DN(-1, 169) == [(12, 5), (5, 12), (13, 0), (0, 13)] # D > 0 and D is not a square # N = 1 assert diop_DN(13, 1) == [(649, 180)] assert diop_DN(980, 1) == [(51841, 1656)] assert diop_DN(981, 1) == [(158070671986249, 5046808151700)] assert diop_DN(986, 1) == [(49299, 1570)] assert diop_DN(991, 1) == [(379516400906811930638014896080, 12055735790331359447442538767)] assert diop_DN(17, 1) == [(33, 8)] assert diop_DN(19, 1) == [(170, 39)] # N = -1 assert diop_DN(13, -1) == [(18, 5)] assert diop_DN(991, -1) == [] assert diop_DN(41, -1) == [(32, 5)] assert diop_DN(290, -1) == [(17, 1)] assert diop_DN(21257, -1) == [(13913102721304, 95427381109)] assert diop_DN(32, -1) == [] # |N| > 1 # Some tests were created using calculator at # http://www.numbertheory.org/php/patz.html assert diop_DN(13, -4) == [(3, 1), (393, 109), (36, 10)] # Source I referred returned (3, 1), (393, 109) and (-3, 1) as fundamental solutions # So (-3, 1) and (393, 109) should be in the same equivalent class assert equivalent(-3, 1, 393, 109, 13, -4) == True assert diop_DN(13, 27) == [(220, 61), (40, 11), (768, 213), (12, 3)] assert set(diop_DN(157, 12)) == {(13, 1), (10663, 851), (579160, 46222), (483790960, 38610722), (26277068347, 2097138361), (21950079635497, 1751807067011)} assert diop_DN(13, 25) == [(3245, 900)] assert diop_DN(192, 18) == [] assert diop_DN(23, 13) == [(-6, 1), (6, 1)] assert diop_DN(167, 2) == [(13, 1)] assert diop_DN(167, -2) == [] assert diop_DN(123, -2) == [(11, 1)] # One calculator returned [(11, 1), (-11, 1)] but both of these are in # the same equivalence class assert equivalent(11, 1, -11, 1, 123, -2) assert diop_DN(123, -23) == [(-10, 1), (10, 1)] assert diop_DN(0, 0, t) == [(0, t)] assert diop_DN(0, -1, t) == [] def test_bf_pell(): assert diop_bf_DN(13, -4) == [(3, 1), (-3, 1), (36, 10)] assert diop_bf_DN(13, 27) == [(12, 3), (-12, 3), (40, 11), (-40, 11)] assert diop_bf_DN(167, -2) == [] assert diop_bf_DN(1729, 1) == [(44611924489705, 1072885712316)] assert diop_bf_DN(89, -8) == [(9, 1), (-9, 1)] assert diop_bf_DN(21257, -1) == [(13913102721304, 95427381109)] assert diop_bf_DN(340, -4) == [(756, 41)] assert diop_bf_DN(-1, 0, t) == [(0, 0)] assert diop_bf_DN(0, 0, t) == [(0, t)] assert diop_bf_DN(4, 0, t) == [(2*t, t), (-2*t, t)] assert diop_bf_DN(3, 0, t) == [(0, 0)] assert diop_bf_DN(1, -2, t) == [] def test_length(): assert length(2, 1, 0) == 1 assert length(-2, 4, 5) == 3 assert length(-5, 4, 17) == 4 assert length(0, 4, 13) == 6 assert length(7, 13, 11) == 23 assert length(1, 6, 4) == 2 def is_pell_transformation_ok(eq): """ Test whether X*Y, X, or Y terms are present in the equation after transforming the equation using the transformation returned by transformation_to_pell(). If they are not present we are good. Moreover, coefficient of X**2 should be a divisor of coefficient of Y**2 and the constant term. """ A, B = transformation_to_DN(eq) u = (A*Matrix([X, Y]) + B)[0] v = (A*Matrix([X, Y]) + B)[1] simplified = diop_simplify(eq.subs(zip((x, y), (u, v)))) coeff = dict([reversed(t.as_independent(*[X, Y])) for t in simplified.args]) for term in [X*Y, X, Y]: if term in coeff.keys(): return False for term in [X**2, Y**2, 1]: if term not in coeff.keys(): coeff[term] = 0 if coeff[X**2] != 0: return divisible(coeff[Y**2], coeff[X**2]) and \ divisible(coeff[1], coeff[X**2]) return True def test_transformation_to_pell(): assert is_pell_transformation_ok(-13*x**2 - 7*x*y + y**2 + 2*x - 2*y - 14) assert is_pell_transformation_ok(-17*x**2 + 19*x*y - 7*y**2 - 5*x - 13*y - 23) assert is_pell_transformation_ok(x**2 - y**2 + 17) assert is_pell_transformation_ok(-x**2 + 7*y**2 - 23) assert is_pell_transformation_ok(25*x**2 - 45*x*y + 5*y**2 - 5*x - 10*y + 5) assert is_pell_transformation_ok(190*x**2 + 30*x*y + y**2 - 3*y - 170*x - 130) assert is_pell_transformation_ok(x**2 - 2*x*y -190*y**2 - 7*y - 23*x - 89) assert is_pell_transformation_ok(15*x**2 - 9*x*y + 14*y**2 - 23*x - 14*y - 4950) def test_find_DN(): assert find_DN(x**2 - 2*x - y**2) == (1, 1) assert find_DN(x**2 - 3*y**2 - 5) == (3, 5) assert find_DN(x**2 - 2*x*y - 4*y**2 - 7) == (5, 7) assert find_DN(4*x**2 - 8*x*y - y**2 - 9) == (20, 36) assert find_DN(7*x**2 - 2*x*y - y**2 - 12) == (8, 84) assert find_DN(-3*x**2 + 4*x*y -y**2) == (1, 0) assert find_DN(-13*x**2 - 7*x*y + y**2 + 2*x - 2*y -14) == (101, -7825480) def test_ldescent(): # Equations which have solutions u = ([(13, 23), (3, -11), (41, -113), (4, -7), (-7, 4), (91, -3), (1, 1), (1, -1), (4, 32), (17, 13), (123689, 1), (19, -570)]) for a, b in u: w, x, y = ldescent(a, b) assert a*x**2 + b*y**2 == w**2 assert ldescent(-1, -1) is None def test_diop_ternary_quadratic_normal(): assert check_solutions(234*x**2 - 65601*y**2 - z**2) assert check_solutions(23*x**2 + 616*y**2 - z**2) assert check_solutions(5*x**2 + 4*y**2 - z**2) assert check_solutions(3*x**2 + 6*y**2 - 3*z**2) assert check_solutions(x**2 + 3*y**2 - z**2) assert check_solutions(4*x**2 + 5*y**2 - z**2) assert check_solutions(x**2 + y**2 - z**2) assert check_solutions(16*x**2 + y**2 - 25*z**2) assert check_solutions(6*x**2 - y**2 + 10*z**2) assert check_solutions(213*x**2 + 12*y**2 - 9*z**2) assert check_solutions(34*x**2 - 3*y**2 - 301*z**2) assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2) def is_normal_transformation_ok(eq): A = transformation_to_normal(eq) X, Y, Z = A*Matrix([x, y, z]) simplified = diop_simplify(eq.subs(zip((x, y, z), (X, Y, Z)))) coeff = dict([reversed(t.as_independent(*[X, Y, Z])) for t in simplified.args]) for term in [X*Y, Y*Z, X*Z]: if term in coeff.keys(): return False return True def test_transformation_to_normal(): assert is_normal_transformation_ok(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z) assert is_normal_transformation_ok(x**2 + 3*y**2 - 100*z**2) assert is_normal_transformation_ok(x**2 + 23*y*z) assert is_normal_transformation_ok(3*y**2 - 100*z**2 - 12*x*y) assert is_normal_transformation_ok(x**2 + 23*x*y - 34*y*z + 12*x*z) assert is_normal_transformation_ok(z**2 + 34*x*y - 23*y*z + x*z) assert is_normal_transformation_ok(x**2 + y**2 + z**2 - x*y - y*z - x*z) assert is_normal_transformation_ok(x**2 + 2*y*z + 3*z**2) assert is_normal_transformation_ok(x*y + 2*x*z + 3*y*z) assert is_normal_transformation_ok(2*x*z + 3*y*z) def test_diop_ternary_quadratic(): assert check_solutions(2*x**2 + z**2 + y**2 - 4*x*y) assert check_solutions(x**2 - y**2 - z**2 - x*y - y*z) assert check_solutions(3*x**2 - x*y - y*z - x*z) assert check_solutions(x**2 - y*z - x*z) assert check_solutions(5*x**2 - 3*x*y - x*z) assert check_solutions(4*x**2 - 5*y**2 - x*z) assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) assert check_solutions(8*x**2 - 12*y*z) assert check_solutions(45*x**2 - 7*y**2 - 8*x*y - z**2) assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y -8*x*y) assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z) assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 17*y*z) assert check_solutions(x**2 + 3*y**2 + z**2 - x*y - 16*y*z + 12*x*z) assert check_solutions(x**2 + 3*y**2 + z**2 - 13*x*y - 16*y*z + 12*x*z) assert check_solutions(x*y - 7*y*z + 13*x*z) assert diop_ternary_quadratic_normal(x**2 + y**2 + z**2) == (None, None, None) assert diop_ternary_quadratic_normal(x**2 + y**2) is None raises(ValueError, lambda: _diop_ternary_quadratic_normal((x, y, z), {x*y: 1, x**2: 2, y**2: 3, z**2: 0})) eq = -2*x*y - 6*x*z + 7*y**2 - 3*y*z + 4*z**2 assert diop_ternary_quadratic(eq) == (7, 2, 0) assert diop_ternary_quadratic_normal(4*x**2 + 5*y**2 - z**2) == \ (1, 0, 2) assert diop_ternary_quadratic(x*y + 2*y*z) == \ (-2, 0, n1) eq = -5*x*y - 8*x*z - 3*y*z + 8*z**2 assert parametrize_ternary_quadratic(eq) == \ (8*p**2 - 3*p*q, -8*p*q + 8*q**2, 5*p*q) # this cannot be tested with diophantine because it will # factor into a product assert diop_solve(x*y + 2*y*z) == (-2*p*q, -n1*p**2 + p**2, p*q) def test_square_factor(): assert square_factor(1) == square_factor(-1) == 1 assert square_factor(0) == 1 assert square_factor(5) == square_factor(-5) == 1 assert square_factor(4) == square_factor(-4) == 2 assert square_factor(12) == square_factor(-12) == 2 assert square_factor(6) == 1 assert square_factor(18) == 3 assert square_factor(52) == 2 assert square_factor(49) == 7 assert square_factor(392) == 14 assert square_factor(factorint(-12)) == 2 def test_parametrize_ternary_quadratic(): assert check_solutions(x**2 + y**2 - z**2) assert check_solutions(x**2 + 2*x*y + z**2) assert check_solutions(234*x**2 - 65601*y**2 - z**2) assert check_solutions(3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) assert check_solutions(x**2 - y**2 - z**2) assert check_solutions(x**2 - 49*y**2 - z**2 + 13*z*y - 8*x*y) assert check_solutions(8*x*y + z**2) assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2) assert check_solutions(236*x**2 - 225*y**2 - 11*x*y - 13*y*z - 17*x*z) assert check_solutions(90*x**2 + 3*y**2 + 5*x*y + 2*z*y + 5*x*z) assert check_solutions(124*x**2 - 30*y**2 - 7729*z**2) def test_no_square_ternary_quadratic(): assert check_solutions(2*x*y + y*z - 3*x*z) assert check_solutions(189*x*y - 345*y*z - 12*x*z) assert check_solutions(23*x*y + 34*y*z) assert check_solutions(x*y + y*z + z*x) assert check_solutions(23*x*y + 23*y*z + 23*x*z) def test_descent(): u = ([(13, 23), (3, -11), (41, -113), (91, -3), (1, 1), (1, -1), (17, 13), (123689, 1), (19, -570)]) for a, b in u: w, x, y = descent(a, b) assert a*x**2 + b*y**2 == w**2 # the docstring warns against bad input, so these are expected results # - can't both be negative raises(TypeError, lambda: descent(-1, -3)) # A can't be zero unless B != 1 raises(ZeroDivisionError, lambda: descent(0, 3)) # supposed to be square-free raises(TypeError, lambda: descent(4, 3)) def test_diophantine(): assert check_solutions((x - y)*(y - z)*(z - x)) assert check_solutions((x - y)*(x**2 + y**2 - z**2)) assert check_solutions((x - 3*y + 7*z)*(x**2 + y**2 - z**2)) assert check_solutions(x**2 - 3*y**2 - 1) assert check_solutions(y**2 + 7*x*y) assert check_solutions(x**2 - 3*x*y + y**2) assert check_solutions(z*(x**2 - y**2 - 15)) assert check_solutions(x*(2*y - 2*z + 5)) assert check_solutions((x**2 - 3*y**2 - 1)*(x**2 - y**2 - 15)) assert check_solutions((x**2 - 3*y**2 - 1)*(y - 7*z)) assert check_solutions((x**2 + y**2 - z**2)*(x - 7*y - 3*z + 4*w)) # Following test case caused problems in parametric representation # But this can be solved by factoring out y. # No need to use methods for ternary quadratic equations. assert check_solutions(y**2 - 7*x*y + 4*y*z) assert check_solutions(x**2 - 2*x + 1) assert diophantine(x - y) == diophantine(Eq(x, y)) # 18196 eq = x**4 + y**4 - 97 assert diophantine(eq, permute=True) == diophantine(-eq, permute=True) assert diophantine(3*x*pi - 2*y*pi) == {(2*t_0, 3*t_0)} eq = x**2 + y**2 + z**2 - 14 base_sol = {(1, 2, 3)} assert diophantine(eq) == base_sol complete_soln = set(signed_permutations(base_sol.pop())) assert diophantine(eq, permute=True) == complete_soln assert diophantine(x**2 + x*Rational(15, 14) - 3) == set() # test issue 11049 eq = 92*x**2 - 99*y**2 - z**2 coeff = eq.as_coefficients_dict() assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ {(9, 7, 51)} assert diophantine(eq) == {( 891*p**2 + 9*q**2, -693*p**2 - 102*p*q + 7*q**2, 5049*p**2 - 1386*p*q - 51*q**2)} eq = 2*x**2 + 2*y**2 - z**2 coeff = eq.as_coefficients_dict() assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ {(1, 1, 2)} assert diophantine(eq) == {( 2*p**2 - q**2, -2*p**2 + 4*p*q - q**2, 4*p**2 - 4*p*q + 2*q**2)} eq = 411*x**2+57*y**2-221*z**2 coeff = eq.as_coefficients_dict() assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ {(2021, 2645, 3066)} assert diophantine(eq) == \ {(115197*p**2 - 446641*q**2, -150765*p**2 + 1355172*p*q - 584545*q**2, 174762*p**2 - 301530*p*q + 677586*q**2)} eq = 573*x**2+267*y**2-984*z**2 coeff = eq.as_coefficients_dict() assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ {(49, 233, 127)} assert diophantine(eq) == \ {(4361*p**2 - 16072*q**2, -20737*p**2 + 83312*p*q - 76424*q**2, 11303*p**2 - 41474*p*q + 41656*q**2)} # this produces factors during reconstruction eq = x**2 + 3*y**2 - 12*z**2 coeff = eq.as_coefficients_dict() assert _diop_ternary_quadratic_normal((x, y, z), coeff) == \ {(0, 2, 1)} assert diophantine(eq) == \ {(24*p*q, 2*p**2 - 24*q**2, p**2 + 12*q**2)} # solvers have not been written for every type raises(NotImplementedError, lambda: diophantine(x*y**2 + 1)) # rational expressions assert diophantine(1/x) == set() assert diophantine(1/x + 1/y - S.Half) == {(6, 3), (-2, 1), (4, 4), (1, -2), (3, 6)} assert diophantine(x**2 + y**2 +3*x- 5, permute=True) == \ {(-1, 1), (-4, -1), (1, -1), (1, 1), (-4, 1), (-1, -1), (4, 1), (4, -1)} #test issue 18186 assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(x, y), permute=True) == \ {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)} assert diophantine(y**4 + x**4 - 2**4 - 3**4, syms=(y, x), permute=True) == \ {(-3, -2), (-3, 2), (-2, -3), (-2, 3), (2, -3), (2, 3), (3, -2), (3, 2)} # issue 18122 assert check_solutions(x**2-y) assert check_solutions(y**2-x) assert diophantine((x**2-y), t) == {(t, t**2)} assert diophantine((y**2-x), t) == {(t**2, -t)} def test_general_pythagorean(): from sympy.abc import a, b, c, d, e assert check_solutions(a**2 + b**2 + c**2 - d**2) assert check_solutions(a**2 + 4*b**2 + 4*c**2 - d**2) assert check_solutions(9*a**2 + 4*b**2 + 4*c**2 - d**2) assert check_solutions(9*a**2 + 4*b**2 - 25*d**2 + 4*c**2 ) assert check_solutions(9*a**2 - 16*d**2 + 4*b**2 + 4*c**2) assert check_solutions(-e**2 + 9*a**2 + 4*b**2 + 4*c**2 + 25*d**2) assert check_solutions(16*a**2 - b**2 + 9*c**2 + d**2 + 25*e**2) assert GeneralPythagorean(a**2 + b**2 + c**2 - d**2).solve(parameters=[x, y, z]) == \ {(x**2 + y**2 - z**2, 2*x*z, 2*y*z, x**2 + y**2 + z**2)} def test_diop_general_sum_of_squares_quick(): for i in range(3, 10): assert check_solutions(sum(i**2 for i in symbols(':%i' % i)) - i) assert diop_general_sum_of_squares(x**2 + y**2 - 2) is None assert diop_general_sum_of_squares(x**2 + y**2 + z**2 + 2) == set() eq = x**2 + y**2 + z**2 - (1 + 4 + 9) assert diop_general_sum_of_squares(eq) == \ {(1, 2, 3)} eq = u**2 + v**2 + x**2 + y**2 + z**2 - 1313 assert len(diop_general_sum_of_squares(eq, 3)) == 3 # issue 11016 var = symbols(':5') + (symbols('6', negative=True),) eq = Add(*[i**2 for i in var]) - 112 base_soln = {(0, 1, 1, 5, 6, -7), (1, 1, 1, 3, 6, -8), (2, 3, 3, 4, 5, -7), (0, 1, 1, 1, 3, -10), (0, 0, 4, 4, 4, -8), (1, 2, 3, 3, 5, -8), (0, 1, 2, 3, 7, -7), (2, 2, 4, 4, 6, -6), (1, 1, 3, 4, 6, -7), (0, 2, 3, 3, 3, -9), (0, 0, 2, 2, 2, -10), (1, 1, 2, 3, 4, -9), (0, 1, 1, 2, 5, -9), (0, 0, 2, 6, 6, -6), (1, 3, 4, 5, 5, -6), (0, 2, 2, 2, 6, -8), (0, 3, 3, 3, 6, -7), (0, 2, 3, 5, 5, -7), (0, 1, 5, 5, 5, -6)} assert diophantine(eq) == base_soln assert len(diophantine(eq, permute=True)) == 196800 # handle negated squares with signsimp assert diophantine(12 - x**2 - y**2 - z**2) == {(2, 2, 2)} # diophantine handles simplification, so classify_diop should # not have to look for additional patterns that are removed # by diophantine eq = a**2 + b**2 + c**2 + d**2 - 4 raises(NotImplementedError, lambda: classify_diop(-eq)) def test_diop_partition(): for n in [8, 10]: for k in range(1, 8): for p in partition(n, k): assert len(p) == k assert [p for p in partition(3, 5)] == [] assert [list(p) for p in partition(3, 5, 1)] == [ [0, 0, 0, 0, 3], [0, 0, 0, 1, 2], [0, 0, 1, 1, 1]] assert list(partition(0)) == [()] assert list(partition(1, 0)) == [()] assert [list(i) for i in partition(3)] == [[1, 1, 1], [1, 2], [3]] def test_prime_as_sum_of_two_squares(): for i in [5, 13, 17, 29, 37, 41, 2341, 3557, 34841, 64601]: a, b = prime_as_sum_of_two_squares(i) assert a**2 + b**2 == i assert prime_as_sum_of_two_squares(7) is None ans = prime_as_sum_of_two_squares(800029) assert ans == (450, 773) and type(ans[0]) is int def test_sum_of_three_squares(): for i in [0, 1, 2, 34, 123, 34304595905, 34304595905394941, 343045959052344, 800, 801, 802, 803, 804, 805, 806]: a, b, c = sum_of_three_squares(i) assert a**2 + b**2 + c**2 == i assert sum_of_three_squares(7) is None assert sum_of_three_squares((4**5)*15) is None assert sum_of_three_squares(25) == (5, 0, 0) assert sum_of_three_squares(4) == (0, 0, 2) def test_sum_of_four_squares(): from random import randint # this should never fail n = randint(1, 100000000000000) assert sum(i**2 for i in sum_of_four_squares(n)) == n assert sum_of_four_squares(0) == (0, 0, 0, 0) assert sum_of_four_squares(14) == (0, 1, 2, 3) assert sum_of_four_squares(15) == (1, 1, 2, 3) assert sum_of_four_squares(18) == (1, 2, 2, 3) assert sum_of_four_squares(19) == (0, 1, 3, 3) assert sum_of_four_squares(48) == (0, 4, 4, 4) def test_power_representation(): tests = [(1729, 3, 2), (234, 2, 4), (2, 1, 2), (3, 1, 3), (5, 2, 2), (12352, 2, 4), (32760, 2, 3)] for test in tests: n, p, k = test f = power_representation(n, p, k) while True: try: l = next(f) assert len(l) == k chk_sum = 0 for l_i in l: chk_sum = chk_sum + l_i**p assert chk_sum == n except StopIteration: break assert list(power_representation(20, 2, 4, True)) == \ [(1, 1, 3, 3), (0, 0, 2, 4)] raises(ValueError, lambda: list(power_representation(1.2, 2, 2))) raises(ValueError, lambda: list(power_representation(2, 0, 2))) raises(ValueError, lambda: list(power_representation(2, 2, 0))) assert list(power_representation(-1, 2, 2)) == [] assert list(power_representation(1, 1, 1)) == [(1,)] assert list(power_representation(3, 2, 1)) == [] assert list(power_representation(4, 2, 1)) == [(2,)] assert list(power_representation(3**4, 4, 6, zeros=True)) == \ [(1, 2, 2, 2, 2, 2), (0, 0, 0, 0, 0, 3)] assert list(power_representation(3**4, 4, 5, zeros=False)) == [] assert list(power_representation(-2, 3, 2)) == [(-1, -1)] assert list(power_representation(-2, 4, 2)) == [] assert list(power_representation(0, 3, 2, True)) == [(0, 0)] assert list(power_representation(0, 3, 2, False)) == [] # when we are dealing with squares, do feasibility checks assert len(list(power_representation(4**10*(8*10 + 7), 2, 3))) == 0 # there will be a recursion error if these aren't recognized big = 2**30 for i in [13, 10, 7, 5, 4, 2, 1]: assert list(sum_of_powers(big, 2, big - i)) == [] def test_assumptions(): """ Test whether diophantine respects the assumptions. """ #Test case taken from the below so question regarding assumptions in diophantine module #https://stackoverflow.com/questions/23301941/how-can-i-declare-natural-symbols-with-sympy m, n = symbols('m n', integer=True, positive=True) diof = diophantine(n**2 + m*n - 500) assert diof == {(5, 20), (40, 10), (95, 5), (121, 4), (248, 2), (499, 1)} a, b = symbols('a b', integer=True, positive=False) diof = diophantine(a*b + 2*a + 3*b - 6) assert diof == {(-15, -3), (-9, -4), (-7, -5), (-6, -6), (-5, -8), (-4, -14)} def check_solutions(eq): """ Determines whether solutions returned by diophantine() satisfy the original equation. Hope to generalize this so we can remove functions like check_ternay_quadratic, check_solutions_normal, check_solutions() """ s = diophantine(eq) factors = Mul.make_args(eq) var = list(eq.free_symbols) var.sort(key=default_sort_key) while s: solution = s.pop() for f in factors: if diop_simplify(f.subs(zip(var, solution))) == 0: break else: return False return True def test_diopcoverage(): eq = (2*x + y + 1)**2 assert diop_solve(eq) == {(t_0, -2*t_0 - 1)} eq = 2*x**2 + 6*x*y + 12*x + 4*y**2 + 18*y + 18 assert diop_solve(eq) == {(t, -t - 3), (2*t - 3, -t)} assert diop_quadratic(x + y**2 - 3) == {(-t**2 + 3, -t)} assert diop_linear(x + y - 3) == (t_0, 3 - t_0) assert base_solution_linear(0, 1, 2, t=None) == (0, 0) ans = (3*t - 1, -2*t + 1) assert base_solution_linear(4, 8, 12, t) == ans assert base_solution_linear(4, 8, 12, t=None) == tuple(_.subs(t, 0) for _ in ans) assert cornacchia(1, 1, 20) is None assert cornacchia(1, 1, 5) == {(2, 1)} assert cornacchia(1, 2, 17) == {(3, 2)} raises(ValueError, lambda: reconstruct(4, 20, 1)) assert gaussian_reduce(4, 1, 3) == (1, 1) eq = -w**2 - x**2 - y**2 + z**2 assert diop_general_pythagorean(eq) == \ diop_general_pythagorean(-eq) == \ (m1**2 + m2**2 - m3**2, 2*m1*m3, 2*m2*m3, m1**2 + m2**2 + m3**2) assert len(check_param(S(3) + x/3, S(4) + x/2, S(2), [x])) == 0 assert len(check_param(Rational(3, 2), S(4) + x, S(2), [x])) == 0 assert len(check_param(S(4) + x, Rational(3, 2), S(2), [x])) == 0 assert _nint_or_floor(16, 10) == 2 assert _odd(1) == (not _even(1)) == True assert _odd(0) == (not _even(0)) == False assert _remove_gcd(2, 4, 6) == (1, 2, 3) raises(TypeError, lambda: _remove_gcd((2, 4, 6))) assert sqf_normal(2*3**2*5, 2*5*11, 2*7**2*11) == \ (11, 1, 5) # it's ok if these pass some day when the solvers are implemented raises(NotImplementedError, lambda: diophantine(x**2 + y**2 + x*y + 2*y*z - 12)) raises(NotImplementedError, lambda: diophantine(x**3 + y**2)) assert diop_quadratic(x**2 + y**2 - 1**2 - 3**4) == \ {(-9, -1), (-9, 1), (-1, -9), (-1, 9), (1, -9), (1, 9), (9, -1), (9, 1)} def test_holzer(): # if the input is good, don't let it diverge in holzer() # (but see test_fail_holzer below) assert holzer(2, 7, 13, 4, 79, 23) == (2, 7, 13) # None in uv condition met; solution is not Holzer reduced # so this will hopefully change but is here for coverage assert holzer(2, 6, 2, 1, 1, 10) == (2, 6, 2) raises(ValueError, lambda: holzer(2, 7, 14, 4, 79, 23)) @XFAIL def test_fail_holzer(): eq = lambda x, y, z: a*x**2 + b*y**2 - c*z**2 a, b, c = 4, 79, 23 x, y, z = xyz = 26, 1, 11 X, Y, Z = ans = 2, 7, 13 assert eq(*xyz) == 0 assert eq(*ans) == 0 assert max(a*x**2, b*y**2, c*z**2) <= a*b*c assert max(a*X**2, b*Y**2, c*Z**2) <= a*b*c h = holzer(x, y, z, a, b, c) assert h == ans # it would be nice to get the smaller soln def test_issue_9539(): assert diophantine(6*w + 9*y + 20*x - z) == \ {(t_0, t_1, t_1 + t_2, 6*t_0 + 29*t_1 + 9*t_2)} def test_issue_8943(): assert diophantine( 3*(x**2 + y**2 + z**2) - 14*(x*y + y*z + z*x)) == \ {(0, 0, 0)} def test_diop_sum_of_even_powers(): eq = x**4 + y**4 + z**4 - 2673 assert diop_solve(eq) == {(3, 6, 6), (2, 4, 7)} assert diop_general_sum_of_even_powers(eq, 2) == {(3, 6, 6), (2, 4, 7)} raises(NotImplementedError, lambda: diop_general_sum_of_even_powers(-eq, 2)) neg = symbols('neg', negative=True) eq = x**4 + y**4 + neg**4 - 2673 assert diop_general_sum_of_even_powers(eq) == {(-3, 6, 6)} assert diophantine(x**4 + y**4 + 2) == set() assert diop_general_sum_of_even_powers(x**4 + y**4 - 2, limit=0) == set() def test_sum_of_squares_powers(): tru = {(0, 0, 1, 1, 11), (0, 0, 5, 7, 7), (0, 1, 3, 7, 8), (0, 1, 4, 5, 9), (0, 3, 4, 7, 7), (0, 3, 5, 5, 8), (1, 1, 2, 6, 9), (1, 1, 6, 6, 7), (1, 2, 3, 3, 10), (1, 3, 4, 4, 9), (1, 5, 5, 6, 6), (2, 2, 3, 5, 9), (2, 3, 5, 6, 7), (3, 3, 4, 5, 8)} eq = u**2 + v**2 + x**2 + y**2 + z**2 - 123 ans = diop_general_sum_of_squares(eq, oo) # allow oo to be used assert len(ans) == 14 assert ans == tru raises(ValueError, lambda: list(sum_of_squares(10, -1))) assert list(sum_of_squares(-10, 2)) == [] assert list(sum_of_squares(2, 3)) == [] assert list(sum_of_squares(0, 3, True)) == [(0, 0, 0)] assert list(sum_of_squares(0, 3)) == [] assert list(sum_of_squares(4, 1)) == [(2,)] assert list(sum_of_squares(5, 1)) == [] assert list(sum_of_squares(50, 2)) == [(5, 5), (1, 7)] assert list(sum_of_squares(11, 5, True)) == [ (1, 1, 1, 2, 2), (0, 0, 1, 1, 3)] assert list(sum_of_squares(8, 8)) == [(1, 1, 1, 1, 1, 1, 1, 1)] assert [len(list(sum_of_squares(i, 5, True))) for i in range(30)] == [ 1, 1, 1, 1, 2, 2, 1, 1, 2, 2, 2, 2, 2, 3, 2, 1, 3, 3, 3, 3, 4, 3, 3, 2, 2, 4, 4, 4, 4, 5] assert [len(list(sum_of_squares(i, 5))) for i in range(30)] == [ 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 3] for i in range(30): s1 = set(sum_of_squares(i, 5, True)) assert not s1 or all(sum(j**2 for j in t) == i for t in s1) s2 = set(sum_of_squares(i, 5)) assert all(sum(j**2 for j in t) == i for t in s2) raises(ValueError, lambda: list(sum_of_powers(2, -1, 1))) raises(ValueError, lambda: list(sum_of_powers(2, 1, -1))) assert list(sum_of_powers(-2, 3, 2)) == [(-1, -1)] assert list(sum_of_powers(-2, 4, 2)) == [] assert list(sum_of_powers(2, 1, 1)) == [(2,)] assert list(sum_of_powers(2, 1, 3, True)) == [(0, 0, 2), (0, 1, 1)] assert list(sum_of_powers(5, 1, 2, True)) == [(0, 5), (1, 4), (2, 3)] assert list(sum_of_powers(6, 2, 2)) == [] assert list(sum_of_powers(3**5, 3, 1)) == [] assert list(sum_of_powers(3**6, 3, 1)) == [(9,)] and (9**3 == 3**6) assert list(sum_of_powers(2**1000, 5, 2)) == [] def test__can_do_sum_of_squares(): assert _can_do_sum_of_squares(3, -1) is False assert _can_do_sum_of_squares(-3, 1) is False assert _can_do_sum_of_squares(0, 1) assert _can_do_sum_of_squares(4, 1) assert _can_do_sum_of_squares(1, 2) assert _can_do_sum_of_squares(2, 2) assert _can_do_sum_of_squares(3, 2) is False def test_diophantine_permute_sign(): from sympy.abc import a, b, c, d, e eq = a**4 + b**4 - (2**4 + 3**4) base_sol = {(2, 3)} assert diophantine(eq) == base_sol complete_soln = set(signed_permutations(base_sol.pop())) assert diophantine(eq, permute=True) == complete_soln eq = a**2 + b**2 + c**2 + d**2 + e**2 - 234 assert len(diophantine(eq)) == 35 assert len(diophantine(eq, permute=True)) == 62000 soln = {(-1, -1), (-1, 2), (1, -2), (1, 1)} assert diophantine(10*x**2 + 12*x*y + 12*y**2 - 34, permute=True) == soln @XFAIL def test_not_implemented(): eq = x**2 + y**4 - 1**2 - 3**4 assert diophantine(eq, syms=[x, y]) == {(9, 1), (1, 3)} def test_issue_9538(): eq = x - 3*y + 2 assert diophantine(eq, syms=[y,x]) == {(t_0, 3*t_0 - 2)} raises(TypeError, lambda: diophantine(eq, syms={y, x})) def test_ternary_quadratic(): # solution with 3 parameters s = diophantine(2*x**2 + y**2 - 2*z**2) p, q, r = ordered(S(s).free_symbols) assert s == {( p**2 - 2*q**2, -2*p**2 + 4*p*q - 4*p*r - 4*q**2, p**2 - 4*p*q + 2*q**2 - 4*q*r)} # solution with Mul in solution s = diophantine(x**2 + 2*y**2 - 2*z**2) assert s == {(4*p*q, p**2 - 2*q**2, p**2 + 2*q**2)} # solution with no Mul in solution s = diophantine(2*x**2 + 2*y**2 - z**2) assert s == {(2*p**2 - q**2, -2*p**2 + 4*p*q - q**2, 4*p**2 - 4*p*q + 2*q**2)} # reduced form when parametrized s = diophantine(3*x**2 + 72*y**2 - 27*z**2) assert s == {(24*p**2 - 9*q**2, 6*p*q, 8*p**2 + 3*q**2)} assert parametrize_ternary_quadratic( 3*x**2 + 2*y**2 - z**2 - 2*x*y + 5*y*z - 7*y*z) == ( 2*p**2 - 2*p*q - q**2, 2*p**2 + 2*p*q - q**2, 2*p**2 - 2*p*q + 3*q**2) assert parametrize_ternary_quadratic( 124*x**2 - 30*y**2 - 7729*z**2) == ( -1410*p**2 - 363263*q**2, 2700*p**2 + 30916*p*q - 695610*q**2, -60*p**2 + 5400*p*q + 15458*q**2) def test_diophantine_solution_set(): s1 = DiophantineSolutionSet([], []) assert set(s1) == set() assert s1.symbols == () assert s1.parameters == () raises(ValueError, lambda: s1.add((x,))) assert list(s1.dict_iterator()) == [] s2 = DiophantineSolutionSet([x, y], [t, u]) assert s2.symbols == (x, y) assert s2.parameters == (t, u) raises(ValueError, lambda: s2.add((1,))) s2.add((3, 4)) assert set(s2) == {(3, 4)} s2.update((3, 4), (-1, u)) assert set(s2) == {(3, 4), (-1, u)} raises(ValueError, lambda: s1.update(s2)) assert list(s2.dict_iterator()) == [{x: -1, y: u}, {x: 3, y: 4}] s3 = DiophantineSolutionSet([x, y, z], [t, u]) assert len(s3.parameters) == 2 s3.add((t**2 + u, t - u, 1)) assert set(s3) == {(t**2 + u, t - u, 1)} assert s3.subs(t, 2) == {(u + 4, 2 - u, 1)} assert s3(2) == {(u + 4, 2 - u, 1)} assert s3.subs({t: 7, u: 8}) == {(57, -1, 1)} assert s3(7, 8) == {(57, -1, 1)} assert s3.subs({t: 5}) == {(u + 25, 5 - u, 1)} assert s3(5) == {(u + 25, 5 - u, 1)} assert s3.subs(u, -3) == {(t**2 - 3, t + 3, 1)} assert s3(None, -3) == {(t**2 - 3, t + 3, 1)} assert s3.subs({t: 2, u: 8}) == {(12, -6, 1)} assert s3(2, 8) == {(12, -6, 1)} assert s3.subs({t: 5, u: -3}) == {(22, 8, 1)} assert s3(5, -3) == {(22, 8, 1)} raises(ValueError, lambda: s3.subs(x=1)) raises(ValueError, lambda: s3.subs(1, 2, 3)) raises(ValueError, lambda: s3.add(())) raises(ValueError, lambda: s3.add((1, 2, 3, 4))) raises(ValueError, lambda: s3.add((1, 2))) raises(ValueError, lambda: s3(1, 2, 3)) raises(TypeError, lambda: s3(t=1)) s4 = DiophantineSolutionSet([x, y], [t, u]) s4.add((t, 11*t)) s4.add((-t, 22*t)) assert s4(0, 0) == {(0, 0)} def test_quadratic_parameter_passing(): eq = -33*x*y + 3*y**2 solution = BinaryQuadratic(eq).solve(parameters=[t, u]) # test that parameters are passed all the way to the final solution assert solution == {(t, 11*t), (-t, 22*t)} assert solution(0, 0) == {(0, 0)} sympy-sympy-1.9/sympy/solvers/inequalities.py000066400000000000000000001016161412543434000216540ustar00rootroot00000000000000"""Tools for solving inequalities and systems of inequalities. """ from sympy.core import Symbol, Dummy, sympify from sympy.core.compatibility import iterable from sympy.core.exprtools import factor_terms from sympy.core.relational import Relational, Eq, Ge, Lt from sympy.sets import Interval from sympy.sets.sets import FiniteSet, Union, EmptySet, Intersection from sympy.core.singleton import S from sympy.core.function import expand_mul from sympy.functions import Abs from sympy.logic import And from sympy.polys import Poly, PolynomialError, parallel_poly_from_expr from sympy.polys.polyutils import _nsort from sympy.utilities.iterables import sift from sympy.utilities.misc import filldedent def solve_poly_inequality(poly, rel): """Solve a polynomial inequality with rational coefficients. Examples ======== >>> from sympy import Poly >>> from sympy.abc import x >>> from sympy.solvers.inequalities import solve_poly_inequality >>> solve_poly_inequality(Poly(x, x, domain='ZZ'), '==') [{0}] >>> solve_poly_inequality(Poly(x**2 - 1, x, domain='ZZ'), '!=') [Interval.open(-oo, -1), Interval.open(-1, 1), Interval.open(1, oo)] >>> solve_poly_inequality(Poly(x**2 - 1, x, domain='ZZ'), '==') [{-1}, {1}] See Also ======== solve_poly_inequalities """ if not isinstance(poly, Poly): raise ValueError( 'For efficiency reasons, `poly` should be a Poly instance') if poly.as_expr().is_number: t = Relational(poly.as_expr(), 0, rel) if t is S.true: return [S.Reals] elif t is S.false: return [S.EmptySet] else: raise NotImplementedError( "could not determine truth value of %s" % t) reals, intervals = poly.real_roots(multiple=False), [] if rel == '==': for root, _ in reals: interval = Interval(root, root) intervals.append(interval) elif rel == '!=': left = S.NegativeInfinity for right, _ in reals + [(S.Infinity, 1)]: interval = Interval(left, right, True, True) intervals.append(interval) left = right else: if poly.LC() > 0: sign = +1 else: sign = -1 eq_sign, equal = None, False if rel == '>': eq_sign = +1 elif rel == '<': eq_sign = -1 elif rel == '>=': eq_sign, equal = +1, True elif rel == '<=': eq_sign, equal = -1, True else: raise ValueError("'%s' is not a valid relation" % rel) right, right_open = S.Infinity, True for left, multiplicity in reversed(reals): if multiplicity % 2: if sign == eq_sign: intervals.insert( 0, Interval(left, right, not equal, right_open)) sign, right, right_open = -sign, left, not equal else: if sign == eq_sign and not equal: intervals.insert( 0, Interval(left, right, True, right_open)) right, right_open = left, True elif sign != eq_sign and equal: intervals.insert(0, Interval(left, left)) if sign == eq_sign: intervals.insert( 0, Interval(S.NegativeInfinity, right, True, right_open)) return intervals def solve_poly_inequalities(polys): """Solve polynomial inequalities with rational coefficients. Examples ======== >>> from sympy.solvers.inequalities import solve_poly_inequalities >>> from sympy.polys import Poly >>> from sympy.abc import x >>> solve_poly_inequalities((( ... Poly(x**2 - 3), ">"), ( ... Poly(-x**2 + 1), ">"))) Union(Interval.open(-oo, -sqrt(3)), Interval.open(-1, 1), Interval.open(sqrt(3), oo)) """ from sympy import Union return Union(*[s for p in polys for s in solve_poly_inequality(*p)]) def solve_rational_inequalities(eqs): """Solve a system of rational inequalities with rational coefficients. Examples ======== >>> from sympy.abc import x >>> from sympy import Poly >>> from sympy.solvers.inequalities import solve_rational_inequalities >>> solve_rational_inequalities([[ ... ((Poly(-x + 1), Poly(1, x)), '>='), ... ((Poly(-x + 1), Poly(1, x)), '<=')]]) {1} >>> solve_rational_inequalities([[ ... ((Poly(x), Poly(1, x)), '!='), ... ((Poly(-x + 1), Poly(1, x)), '>=')]]) Union(Interval.open(-oo, 0), Interval.Lopen(0, 1)) See Also ======== solve_poly_inequality """ result = S.EmptySet for _eqs in eqs: if not _eqs: continue global_intervals = [Interval(S.NegativeInfinity, S.Infinity)] for (numer, denom), rel in _eqs: numer_intervals = solve_poly_inequality(numer*denom, rel) denom_intervals = solve_poly_inequality(denom, '==') intervals = [] for numer_interval in numer_intervals: for global_interval in global_intervals: interval = numer_interval.intersect(global_interval) if interval is not S.EmptySet: intervals.append(interval) global_intervals = intervals intervals = [] for global_interval in global_intervals: for denom_interval in denom_intervals: global_interval -= denom_interval if global_interval is not S.EmptySet: intervals.append(global_interval) global_intervals = intervals if not global_intervals: break for interval in global_intervals: result = result.union(interval) return result def reduce_rational_inequalities(exprs, gen, relational=True): """Reduce a system of rational inequalities with rational coefficients. Examples ======== >>> from sympy import Symbol >>> from sympy.solvers.inequalities import reduce_rational_inequalities >>> x = Symbol('x', real=True) >>> reduce_rational_inequalities([[x**2 <= 0]], x) Eq(x, 0) >>> reduce_rational_inequalities([[x + 2 > 0]], x) -2 < x >>> reduce_rational_inequalities([[(x + 2, ">")]], x) -2 < x >>> reduce_rational_inequalities([[x + 2]], x) Eq(x, -2) This function find the non-infinite solution set so if the unknown symbol is declared as extended real rather than real then the result may include finiteness conditions: >>> y = Symbol('y', extended_real=True) >>> reduce_rational_inequalities([[y + 2 > 0]], y) (-2 < y) & (y < oo) """ exact = True eqs = [] solution = S.Reals if exprs else S.EmptySet for _exprs in exprs: _eqs = [] for expr in _exprs: if isinstance(expr, tuple): expr, rel = expr else: if expr.is_Relational: expr, rel = expr.lhs - expr.rhs, expr.rel_op else: expr, rel = expr, '==' if expr is S.true: numer, denom, rel = S.Zero, S.One, '==' elif expr is S.false: numer, denom, rel = S.One, S.One, '==' else: numer, denom = expr.together().as_numer_denom() try: (numer, denom), opt = parallel_poly_from_expr( (numer, denom), gen) except PolynomialError: raise PolynomialError(filldedent(''' only polynomials and rational functions are supported in this context. ''')) if not opt.domain.is_Exact: numer, denom, exact = numer.to_exact(), denom.to_exact(), False domain = opt.domain.get_exact() if not (domain.is_ZZ or domain.is_QQ): expr = numer/denom expr = Relational(expr, 0, rel) solution &= solve_univariate_inequality(expr, gen, relational=False) else: _eqs.append(((numer, denom), rel)) if _eqs: eqs.append(_eqs) if eqs: solution &= solve_rational_inequalities(eqs) exclude = solve_rational_inequalities([[((d, d.one), '==') for i in eqs for ((n, d), _) in i if d.has(gen)]]) solution -= exclude if not exact and solution: solution = solution.evalf() if relational: solution = solution.as_relational(gen) return solution def reduce_abs_inequality(expr, rel, gen): """Reduce an inequality with nested absolute values. Examples ======== >>> from sympy import Abs, Symbol >>> from sympy.solvers.inequalities import reduce_abs_inequality >>> x = Symbol('x', real=True) >>> reduce_abs_inequality(Abs(x - 5) - 3, '<', x) (2 < x) & (x < 8) >>> reduce_abs_inequality(Abs(x + 2)*3 - 13, '<', x) (-19/3 < x) & (x < 7/3) See Also ======== reduce_abs_inequalities """ if gen.is_extended_real is False: raise TypeError(filldedent(''' can't solve inequalities with absolute values containing non-real variables. ''')) def _bottom_up_scan(expr): exprs = [] if expr.is_Add or expr.is_Mul: op = expr.func for arg in expr.args: _exprs = _bottom_up_scan(arg) if not exprs: exprs = _exprs else: args = [] for expr, conds in exprs: for _expr, _conds in _exprs: args.append((op(expr, _expr), conds + _conds)) exprs = args elif expr.is_Pow: n = expr.exp if not n.is_Integer: raise ValueError("Only Integer Powers are allowed on Abs.") _exprs = _bottom_up_scan(expr.base) for expr, conds in _exprs: exprs.append((expr**n, conds)) elif isinstance(expr, Abs): _exprs = _bottom_up_scan(expr.args[0]) for expr, conds in _exprs: exprs.append(( expr, conds + [Ge(expr, 0)])) exprs.append((-expr, conds + [Lt(expr, 0)])) else: exprs = [(expr, [])] return exprs exprs = _bottom_up_scan(expr) mapping = {'<': '>', '<=': '>='} inequalities = [] for expr, conds in exprs: if rel not in mapping.keys(): expr = Relational( expr, 0, rel) else: expr = Relational(-expr, 0, mapping[rel]) inequalities.append([expr] + conds) return reduce_rational_inequalities(inequalities, gen) def reduce_abs_inequalities(exprs, gen): """Reduce a system of inequalities with nested absolute values. Examples ======== >>> from sympy import Abs, Symbol >>> from sympy.solvers.inequalities import reduce_abs_inequalities >>> x = Symbol('x', extended_real=True) >>> reduce_abs_inequalities([(Abs(3*x - 5) - 7, '<'), ... (Abs(x + 25) - 13, '>')], x) (-2/3 < x) & (x < 4) & (((-oo < x) & (x < -38)) | ((-12 < x) & (x < oo))) >>> reduce_abs_inequalities([(Abs(x - 4) + Abs(3*x - 5) - 7, '<')], x) (1/2 < x) & (x < 4) See Also ======== reduce_abs_inequality """ return And(*[ reduce_abs_inequality(expr, rel, gen) for expr, rel in exprs ]) def solve_univariate_inequality(expr, gen, relational=True, domain=S.Reals, continuous=False): """Solves a real univariate inequality. Parameters ========== expr : Relational The target inequality gen : Symbol The variable for which the inequality is solved relational : bool A Relational type output is expected or not domain : Set The domain over which the equation is solved continuous: bool True if expr is known to be continuous over the given domain (and so continuous_domain() doesn't need to be called on it) Raises ====== NotImplementedError The solution of the inequality cannot be determined due to limitation in :func:`sympy.solvers.solveset.solvify`. Notes ===== Currently, we cannot solve all the inequalities due to limitations in :func:`sympy.solvers.solveset.solvify`. Also, the solution returned for trigonometric inequalities are restricted in its periodic interval. See Also ======== sympy.solvers.solveset.solvify: solver returning solveset solutions with solve's output API Examples ======== >>> from sympy.solvers.inequalities import solve_univariate_inequality >>> from sympy import Symbol, sin, Interval, S >>> x = Symbol('x') >>> solve_univariate_inequality(x**2 >= 4, x) ((2 <= x) & (x < oo)) | ((x <= -2) & (-oo < x)) >>> solve_univariate_inequality(x**2 >= 4, x, relational=False) Union(Interval(-oo, -2), Interval(2, oo)) >>> domain = Interval(0, S.Infinity) >>> solve_univariate_inequality(x**2 >= 4, x, False, domain) Interval(2, oo) >>> solve_univariate_inequality(sin(x) > 0, x, relational=False) Interval.open(0, pi) """ from sympy import im from sympy.calculus.util import (continuous_domain, periodicity, function_range) from sympy.solvers.solvers import denoms from sympy.solvers.solveset import solvify, solveset if domain.is_subset(S.Reals) is False: raise NotImplementedError(filldedent(''' Inequalities in the complex domain are not supported. Try the real domain by setting domain=S.Reals''')) elif domain is not S.Reals: rv = solve_univariate_inequality( expr, gen, relational=False, continuous=continuous).intersection(domain) if relational: rv = rv.as_relational(gen) return rv else: pass # continue with attempt to solve in Real domain # This keeps the function independent of the assumptions about `gen`. # `solveset` makes sure this function is called only when the domain is # real. _gen = gen _domain = domain if gen.is_extended_real is False: rv = S.EmptySet return rv if not relational else rv.as_relational(_gen) elif gen.is_extended_real is None: gen = Dummy('gen', extended_real=True) try: expr = expr.xreplace({_gen: gen}) except TypeError: raise TypeError(filldedent(''' When gen is real, the relational has a complex part which leads to an invalid comparison like I < 0. ''')) rv = None if expr is S.true: rv = domain elif expr is S.false: rv = S.EmptySet else: e = expr.lhs - expr.rhs period = periodicity(e, gen) if period == S.Zero: e = expand_mul(e) const = expr.func(e, 0) if const is S.true: rv = domain elif const is S.false: rv = S.EmptySet elif period is not None: frange = function_range(e, gen, domain) rel = expr.rel_op if rel == '<' or rel == '<=': if expr.func(frange.sup, 0): rv = domain elif not expr.func(frange.inf, 0): rv = S.EmptySet elif rel == '>' or rel == '>=': if expr.func(frange.inf, 0): rv = domain elif not expr.func(frange.sup, 0): rv = S.EmptySet inf, sup = domain.inf, domain.sup if sup - inf is S.Infinity: domain = Interval(0, period, False, True).intersect(_domain) _domain = domain if rv is None: n, d = e.as_numer_denom() try: if gen not in n.free_symbols and len(e.free_symbols) > 1: raise ValueError # this might raise ValueError on its own # or it might give None... solns = solvify(e, gen, domain) if solns is None: # in which case we raise ValueError raise ValueError except (ValueError, NotImplementedError): # replace gen with generic x since it's # univariate anyway raise NotImplementedError(filldedent(''' The inequality, %s, cannot be solved using solve_univariate_inequality. ''' % expr.subs(gen, Symbol('x')))) expanded_e = expand_mul(e) def valid(x): # this is used to see if gen=x satisfies the # relational by substituting it into the # expanded form and testing against 0, e.g. # if expr = x*(x + 1) < 2 then e = x*(x + 1) - 2 # and expanded_e = x**2 + x - 2; the test is # whether a given value of x satisfies # x**2 + x - 2 < 0 # # expanded_e, expr and gen used from enclosing scope v = expanded_e.subs(gen, expand_mul(x)) try: r = expr.func(v, 0) except TypeError: r = S.false if r in (S.true, S.false): return r if v.is_extended_real is False: return S.false else: v = v.n(2) if v.is_comparable: return expr.func(v, 0) # not comparable or couldn't be evaluated raise NotImplementedError( 'relationship did not evaluate: %s' % r) singularities = [] for d in denoms(expr, gen): singularities.extend(solvify(d, gen, domain)) if not continuous: domain = continuous_domain(expanded_e, gen, domain) include_x = '=' in expr.rel_op and expr.rel_op != '!=' try: discontinuities = set(domain.boundary - FiniteSet(domain.inf, domain.sup)) # remove points that are not between inf and sup of domain critical_points = FiniteSet(*(solns + singularities + list( discontinuities))).intersection( Interval(domain.inf, domain.sup, domain.inf not in domain, domain.sup not in domain)) if all(r.is_number for r in critical_points): reals = _nsort(critical_points, separated=True)[0] else: sifted = sift(critical_points, lambda x: x.is_extended_real) if sifted[None]: # there were some roots that weren't known # to be real raise NotImplementedError try: reals = sifted[True] if len(reals) > 1: reals = list(sorted(reals)) except TypeError: raise NotImplementedError except NotImplementedError: raise NotImplementedError('sorting of these roots is not supported') # If expr contains imaginary coefficients, only take real # values of x for which the imaginary part is 0 make_real = S.Reals if im(expanded_e) != S.Zero: check = True im_sol = FiniteSet() try: a = solveset(im(expanded_e), gen, domain) if not isinstance(a, Interval): for z in a: if z not in singularities and valid(z) and z.is_extended_real: im_sol += FiniteSet(z) else: start, end = a.inf, a.sup for z in _nsort(critical_points + FiniteSet(end)): valid_start = valid(start) if start != end: valid_z = valid(z) pt = _pt(start, z) if pt not in singularities and pt.is_extended_real and valid(pt): if valid_start and valid_z: im_sol += Interval(start, z) elif valid_start: im_sol += Interval.Ropen(start, z) elif valid_z: im_sol += Interval.Lopen(start, z) else: im_sol += Interval.open(start, z) start = z for s in singularities: im_sol -= FiniteSet(s) except (TypeError): im_sol = S.Reals check = False if isinstance(im_sol, EmptySet): raise ValueError(filldedent(''' %s contains imaginary parts which cannot be made 0 for any value of %s satisfying the inequality, leading to relations like I < 0. ''' % (expr.subs(gen, _gen), _gen))) make_real = make_real.intersect(im_sol) sol_sets = [S.EmptySet] start = domain.inf if start in domain and valid(start) and start.is_finite: sol_sets.append(FiniteSet(start)) for x in reals: end = x if valid(_pt(start, end)): sol_sets.append(Interval(start, end, True, True)) if x in singularities: singularities.remove(x) else: if x in discontinuities: discontinuities.remove(x) _valid = valid(x) else: # it's a solution _valid = include_x if _valid: sol_sets.append(FiniteSet(x)) start = end end = domain.sup if end in domain and valid(end) and end.is_finite: sol_sets.append(FiniteSet(end)) if valid(_pt(start, end)): sol_sets.append(Interval.open(start, end)) if im(expanded_e) != S.Zero and check: rv = (make_real).intersect(_domain) else: rv = Intersection( (Union(*sol_sets)), make_real, _domain).subs(gen, _gen) return rv if not relational else rv.as_relational(_gen) def _pt(start, end): """Return a point between start and end""" if not start.is_infinite and not end.is_infinite: pt = (start + end)/2 elif start.is_infinite and end.is_infinite: pt = S.Zero else: if (start.is_infinite and start.is_extended_positive is None or end.is_infinite and end.is_extended_positive is None): raise ValueError('cannot proceed with unsigned infinite values') if (end.is_infinite and end.is_extended_negative or start.is_infinite and start.is_extended_positive): start, end = end, start # if possible, use a multiple of self which has # better behavior when checking assumptions than # an expression obtained by adding or subtracting 1 if end.is_infinite: if start.is_extended_positive: pt = start*2 elif start.is_extended_negative: pt = start*S.Half else: pt = start + 1 elif start.is_infinite: if end.is_extended_positive: pt = end*S.Half elif end.is_extended_negative: pt = end*2 else: pt = end - 1 return pt def _solve_inequality(ie, s, linear=False): """Return the inequality with s isolated on the left, if possible. If the relationship is non-linear, a solution involving And or Or may be returned. False or True are returned if the relationship is never True or always True, respectively. If `linear` is True (default is False) an `s`-dependent expression will be isolated on the left, if possible but it will not be solved for `s` unless the expression is linear in `s`. Furthermore, only "safe" operations which don't change the sense of the relationship are applied: no division by an unsigned value is attempted unless the relationship involves Eq or Ne and no division by a value not known to be nonzero is ever attempted. Examples ======== >>> from sympy import Eq, Symbol >>> from sympy.solvers.inequalities import _solve_inequality as f >>> from sympy.abc import x, y For linear expressions, the symbol can be isolated: >>> f(x - 2 < 0, x) x < 2 >>> f(-x - 6 < x, x) x > -3 Sometimes nonlinear relationships will be False >>> f(x**2 + 4 < 0, x) False Or they may involve more than one region of values: >>> f(x**2 - 4 < 0, x) (-2 < x) & (x < 2) To restrict the solution to a relational, set linear=True and only the x-dependent portion will be isolated on the left: >>> f(x**2 - 4 < 0, x, linear=True) x**2 < 4 Division of only nonzero quantities is allowed, so x cannot be isolated by dividing by y: >>> y.is_nonzero is None # it is unknown whether it is 0 or not True >>> f(x*y < 1, x) x*y < 1 And while an equality (or inequality) still holds after dividing by a non-zero quantity >>> nz = Symbol('nz', nonzero=True) >>> f(Eq(x*nz, 1), x) Eq(x, 1/nz) the sign must be known for other inequalities involving > or <: >>> f(x*nz <= 1, x) nz*x <= 1 >>> p = Symbol('p', positive=True) >>> f(x*p <= 1, x) x <= 1/p When there are denominators in the original expression that are removed by expansion, conditions for them will be returned as part of the result: >>> f(x < x*(2/x - 1), x) (x < 1) & Ne(x, 0) """ from sympy.solvers.solvers import denoms if s not in ie.free_symbols: return ie if ie.rhs == s: ie = ie.reversed if ie.lhs == s and s not in ie.rhs.free_symbols: return ie def classify(ie, s, i): # return True or False if ie evaluates when substituting s with # i else None (if unevaluated) or NaN (when there is an error # in evaluating) try: v = ie.subs(s, i) if v is S.NaN: return v elif v not in (True, False): return return v except TypeError: return S.NaN rv = None oo = S.Infinity expr = ie.lhs - ie.rhs try: p = Poly(expr, s) if p.degree() == 0: rv = ie.func(p.as_expr(), 0) elif not linear and p.degree() > 1: # handle in except clause raise NotImplementedError except (PolynomialError, NotImplementedError): if not linear: try: rv = reduce_rational_inequalities([[ie]], s) except PolynomialError: rv = solve_univariate_inequality(ie, s) # remove restrictions wrt +/-oo that may have been # applied when using sets to simplify the relationship okoo = classify(ie, s, oo) if okoo is S.true and classify(rv, s, oo) is S.false: rv = rv.subs(s < oo, True) oknoo = classify(ie, s, -oo) if (oknoo is S.true and classify(rv, s, -oo) is S.false): rv = rv.subs(-oo < s, True) rv = rv.subs(s > -oo, True) if rv is S.true: rv = (s <= oo) if okoo is S.true else (s < oo) if oknoo is not S.true: rv = And(-oo < s, rv) else: p = Poly(expr) conds = [] if rv is None: e = p.as_expr() # this is in expanded form # Do a safe inversion of e, moving non-s terms # to the rhs and dividing by a nonzero factor if # the relational is Eq/Ne; for other relationals # the sign must also be positive or negative rhs = 0 b, ax = e.as_independent(s, as_Add=True) e -= b rhs -= b ef = factor_terms(e) a, e = ef.as_independent(s, as_Add=False) if (a.is_zero != False or # don't divide by potential 0 a.is_negative == a.is_positive is None and # if sign is not known then ie.rel_op not in ('!=', '==')): # reject if not Eq/Ne e = ef a = S.One rhs /= a if a.is_positive: rv = ie.func(e, rhs) else: rv = ie.reversed.func(e, rhs) # return conditions under which the value is # valid, too. beginning_denoms = denoms(ie.lhs) | denoms(ie.rhs) current_denoms = denoms(rv) for d in beginning_denoms - current_denoms: c = _solve_inequality(Eq(d, 0), s, linear=linear) if isinstance(c, Eq) and c.lhs == s: if classify(rv, s, c.rhs) is S.true: # rv is permitting this value but it shouldn't conds.append(~c) for i in (-oo, oo): if (classify(rv, s, i) is S.true and classify(ie, s, i) is not S.true): conds.append(s < i if i is oo else i < s) conds.append(rv) return And(*conds) def _reduce_inequalities(inequalities, symbols): # helper for reduce_inequalities poly_part, abs_part = {}, {} other = [] for inequality in inequalities: expr, rel = inequality.lhs, inequality.rel_op # rhs is 0 # check for gens using atoms which is more strict than free_symbols to # guard against EX domain which won't be handled by # reduce_rational_inequalities gens = expr.atoms(Symbol) if len(gens) == 1: gen = gens.pop() else: common = expr.free_symbols & symbols if len(common) == 1: gen = common.pop() other.append(_solve_inequality(Relational(expr, 0, rel), gen)) continue else: raise NotImplementedError(filldedent(''' inequality has more than one symbol of interest. ''')) if expr.is_polynomial(gen): poly_part.setdefault(gen, []).append((expr, rel)) else: components = expr.find(lambda u: u.has(gen) and ( u.is_Function or u.is_Pow and not u.exp.is_Integer)) if components and all(isinstance(i, Abs) for i in components): abs_part.setdefault(gen, []).append((expr, rel)) else: other.append(_solve_inequality(Relational(expr, 0, rel), gen)) poly_reduced = [] abs_reduced = [] for gen, exprs in poly_part.items(): poly_reduced.append(reduce_rational_inequalities([exprs], gen)) for gen, exprs in abs_part.items(): abs_reduced.append(reduce_abs_inequalities(exprs, gen)) return And(*(poly_reduced + abs_reduced + other)) def reduce_inequalities(inequalities, symbols=[]): """Reduce a system of inequalities with rational coefficients. Examples ======== >>> from sympy.abc import x, y >>> from sympy.solvers.inequalities import reduce_inequalities >>> reduce_inequalities(0 <= x + 3, []) (-3 <= x) & (x < oo) >>> reduce_inequalities(0 <= x + y*2 - 1, [x]) (x < oo) & (x >= 1 - 2*y) """ if not iterable(inequalities): inequalities = [inequalities] inequalities = [sympify(i) for i in inequalities] gens = set().union(*[i.free_symbols for i in inequalities]) if not iterable(symbols): symbols = [symbols] symbols = (set(symbols) or gens) & gens if any(i.is_extended_real is False for i in symbols): raise TypeError(filldedent(''' inequalities cannot contain symbols that are not real. ''')) # make vanilla symbol real recast = {i: Dummy(i.name, extended_real=True) for i in gens if i.is_extended_real is None} inequalities = [i.xreplace(recast) for i in inequalities] symbols = {i.xreplace(recast) for i in symbols} # prefilter keep = [] for i in inequalities: if isinstance(i, Relational): i = i.func(i.lhs.as_expr() - i.rhs.as_expr(), 0) elif i not in (True, False): i = Eq(i, 0) if i == True: continue elif i == False: return S.false if i.lhs.is_number: raise NotImplementedError( "could not determine truth value of %s" % i) keep.append(i) inequalities = keep del keep # solve system rv = _reduce_inequalities(inequalities, symbols) # restore original symbols and return return rv.xreplace({v: k for k, v in recast.items()}) sympy-sympy-1.9/sympy/solvers/ode/000077500000000000000000000000001412543434000173505ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/ode/__init__.py000066400000000000000000000007241412543434000214640ustar00rootroot00000000000000from .ode import (allhints, checkinfsol, classify_ode, constantsimp, dsolve, homogeneous_order) from .lie_group import infinitesimals from .subscheck import checkodesol from .systems import (canonical_odes, linear_ode_to_matrix, linodesolve) __all__ = [ 'allhints', 'checkinfsol', 'checkodesol', 'classify_ode', 'constantsimp', 'dsolve', 'homogeneous_order', 'infinitesimals', 'canonical_odes', 'linear_ode_to_matrix', 'linodesolve' ] sympy-sympy-1.9/sympy/solvers/ode/hypergeometric.py000066400000000000000000000227151412543434000227570ustar00rootroot00000000000000r''' This module contains the implementation of the 2nd_hypergeometric hint for dsolve. This is an incomplete implementation of the algorithm described in [1]. The algorithm solves 2nd order linear ODEs of the form .. math:: y'' + A(x) y' + B(x) y = 0\text{,} where `A` and `B` are rational functions. The algorithm should find any solution of the form .. math:: y = P(x) _pF_q(..; ..;\frac{\alpha x^k + \beta}{\gamma x^k + \delta})\text{,} where pFq is any of 2F1, 1F1 or 0F1 and `P` is an "arbitrary function". Currently only the 2F1 case is implemented in SymPy but the other cases are described in the paper and could be implemented in future (contributions welcome!). References ========== .. [1] L. Chan, E.S. Cheb-Terrab, Non-Liouvillian solutions for second order linear ODEs, (2004). https://arxiv.org/abs/math-ph/0402063 ''' from sympy.core import S, Pow from sympy.core.function import expand from sympy.core.relational import Eq from sympy.core.symbol import Symbol, Wild from sympy.functions import exp, sqrt, hyper from sympy.integrals import Integral from sympy.polys import roots, gcd from sympy.polys.polytools import cancel, factor from sympy.simplify import collect, simplify, logcombine from sympy.simplify.powsimp import powdenest from sympy.solvers.ode.ode import get_numbered_constants def match_2nd_hypergeometric(eq, func): x = func.args[0] df = func.diff(x) a3 = Wild('a3', exclude=[func, func.diff(x), func.diff(x, 2)]) b3 = Wild('b3', exclude=[func, func.diff(x), func.diff(x, 2)]) c3 = Wild('c3', exclude=[func, func.diff(x), func.diff(x, 2)]) deq = a3*(func.diff(x, 2)) + b3*df + c3*func r = collect(eq, [func.diff(x, 2), func.diff(x), func]).match(deq) if r: if not all([r[key].is_polynomial() for key in r]): n, d = eq.as_numer_denom() eq = expand(n) r = collect(eq, [func.diff(x, 2), func.diff(x), func]).match(deq) if r and r[a3]!=0: A = cancel(r[b3]/r[a3]) B = cancel(r[c3]/r[a3]) return [A, B] else: return [] def equivalence_hypergeometric(A, B, func): # This method for finding the equivalence is only for 2F1 type. # We can extend it for 1F1 and 0F1 type also. x = func.args[0] # making given equation in normal form I1 = factor(cancel(A.diff(x)/2 + A**2/4 - B)) # computing shifted invariant(J1) of the equation J1 = factor(cancel(x**2*I1 + S(1)/4)) num, dem = J1.as_numer_denom() num = powdenest(expand(num)) dem = powdenest(expand(dem)) # this function will compute the different powers of variable(x) in J1. # then it will help in finding value of k. k is power of x such that we can express # J1 = x**k * J0(x**k) then all the powers in J0 become integers. def _power_counting(num): _pow = {0} for val in num: if val.has(x): if isinstance(val, Pow) and val.as_base_exp()[0] == x: _pow.add(val.as_base_exp()[1]) elif val == x: _pow.add(val.as_base_exp()[1]) else: _pow.update(_power_counting(val.args)) return _pow pow_num = _power_counting((num, )) pow_dem = _power_counting((dem, )) pow_dem.update(pow_num) _pow = pow_dem k = gcd(_pow) # computing I0 of the given equation I0 = powdenest(simplify(factor(((J1/k**2) - S(1)/4)/((x**k)**2))), force=True) I0 = factor(cancel(powdenest(I0.subs(x, x**(S(1)/k)), force=True))) num, dem = I0.as_numer_denom() max_num_pow = max(_power_counting((num, ))) dem_args = dem.args sing_point = [] dem_pow = [] # calculating singular point of I0. for arg in dem_args: if arg.has(x): if isinstance(arg, Pow): # (x-a)**n dem_pow.append(arg.as_base_exp()[1]) sing_point.append(list(roots(arg.as_base_exp()[0], x).keys())[0]) else: # (x-a) type dem_pow.append(arg.as_base_exp()[1]) sing_point.append(list(roots(arg, x).keys())[0]) dem_pow.sort() # checking if equivalence is exists or not. if equivalence(max_num_pow, dem_pow) == "2F1": return {'I0':I0, 'k':k, 'sing_point':sing_point, 'type':"2F1"} else: return None def match_2nd_2F1_hypergeometric(I, k, sing_point, func): x = func.args[0] a = Wild("a") b = Wild("b") c = Wild("c") t = Wild("t") s = Wild("s") r = Wild("r") alpha = Wild("alpha") beta = Wild("beta") gamma = Wild("gamma") delta = Wild("delta") # I0 of the standerd 2F1 equation. I0 = ((a-b+1)*(a-b-1)*x**2 + 2*((1-a-b)*c + 2*a*b)*x + c*(c-2))/(4*x**2*(x-1)**2) if sing_point != [0, 1]: # If singular point is [0, 1] then we have standerd equation. eqs = [] sing_eqs = [-beta/alpha, -delta/gamma, (delta-beta)/(alpha-gamma)] # making equations for the finding the mobius transformation for i in range(3): if i>> from sympy import Function, Eq, pprint >>> from sympy.abc import x, y >>> xi, eta, h = map(Function, ['xi', 'eta', 'h']) >>> h = h(x, y) # dy/dx = h >>> eta = eta(x, y) >>> xi = xi(x, y) >>> genform = Eq(eta.diff(x) + (eta.diff(y) - xi.diff(x))*h ... - (xi.diff(y))*h**2 - xi*(h.diff(x)) - eta*(h.diff(y)), 0) >>> pprint(genform) /d d \ d 2 d |--(eta(x, y)) - --(xi(x, y))|*h(x, y) - eta(x, y)*--(h(x, y)) - h (x, y)*--(x \dy dx / dy dy d d i(x, y)) - xi(x, y)*--(h(x, y)) + --(eta(x, y)) = 0 dx dx Solving the above mentioned PDE is not trivial, and can be solved only by making intelligent assumptions for `\xi` and `\eta` (heuristics). Once an infinitesimal is found, the attempt to find more heuristics stops. This is done to optimise the speed of solving the differential equation. If a list of all the infinitesimals is needed, ``hint`` should be flagged as ``all``, which gives the complete list of infinitesimals. If the infinitesimals for a particular heuristic needs to be found, it can be passed as a flag to ``hint``. Examples ======== >>> from sympy import Function >>> from sympy.solvers.ode.lie_group import infinitesimals >>> from sympy.abc import x >>> f = Function('f') >>> eq = f(x).diff(x) - x**2*f(x) >>> infinitesimals(eq) [{eta(x, f(x)): exp(x**3/3), xi(x, f(x)): 0}] References ========== - Solving differential equations by Symmetry Groups, John Starrett, pp. 1 - pp. 14 """ if isinstance(eq, Equality): eq = eq.lhs - eq.rhs if not func: eq, func = _preprocess(eq) variables = func.args if len(variables) != 1: raise ValueError("ODE's have only one independent variable") else: x = variables[0] if not order: order = ode_order(eq, func) if order != 1: raise NotImplementedError("Infinitesimals for only " "first order ODE's have been implemented") else: df = func.diff(x) # Matching differential equation of the form a*df + b a = Wild('a', exclude = [df]) b = Wild('b', exclude = [df]) if match: # Used by lie_group hint h = match['h'] y = match['y'] else: match = collect(expand(eq), df).match(a*df + b) if match: h = -simplify(match[b]/match[a]) else: try: sol = solve(eq, df) except NotImplementedError: raise NotImplementedError("Infinitesimals for the " "first order ODE could not be found") else: h = sol[0] # Find infinitesimals for one solution y = Dummy("y") h = h.subs(func, y) u = Dummy("u") hx = h.diff(x) hy = h.diff(y) hinv = ((1/h).subs([(x, u), (y, x)])).subs(u, y) # Inverse ODE match = {'h': h, 'func': func, 'hx': hx, 'hy': hy, 'y': y, 'hinv': hinv} if hint == 'all': xieta = [] for heuristic in lie_heuristics: function = globals()['lie_heuristic_' + heuristic] inflist = function(match, comp=True) if inflist: xieta.extend([inf for inf in inflist if inf not in xieta]) if xieta: return xieta else: raise NotImplementedError("Infinitesimals could not be found for " "the given ODE") elif hint == 'default': for heuristic in lie_heuristics: function = globals()['lie_heuristic_' + heuristic] xieta = function(match, comp=False) if xieta: return xieta raise NotImplementedError("Infinitesimals could not be found for" " the given ODE") elif hint not in lie_heuristics: raise ValueError("Heuristic not recognized: " + hint) else: function = globals()['lie_heuristic_' + hint] xieta = function(match, comp=True) if xieta: return xieta else: raise ValueError("Infinitesimals could not be found using the" " given heuristic") def lie_heuristic_abaco1_simple(match, comp=False): r""" The first heuristic uses the following four sets of assumptions on `\xi` and `\eta` .. math:: \xi = 0, \eta = f(x) .. math:: \xi = 0, \eta = f(y) .. math:: \xi = f(x), \eta = 0 .. math:: \xi = f(y), \eta = 0 The success of this heuristic is determined by algebraic factorisation. For the first assumption `\xi = 0` and `\eta` to be a function of `x`, the PDE .. math:: \frac{\partial \eta}{\partial x} + (\frac{\partial \eta}{\partial y} - \frac{\partial \xi}{\partial x})*h - \frac{\partial \xi}{\partial y}*h^{2} - \xi*\frac{\partial h}{\partial x} - \eta*\frac{\partial h}{\partial y} = 0 reduces to `f'(x) - f\frac{\partial h}{\partial y} = 0` If `\frac{\partial h}{\partial y}` is a function of `x`, then this can usually be integrated easily. A similar idea is applied to the other 3 assumptions as well. References ========== - E.S Cheb-Terrab, L.G.S Duarte and L.A,C.P da Mota, Computer Algebra Solving of First Order ODEs Using Symmetry Methods, pp. 8 """ xieta = [] y = match['y'] h = match['h'] func = match['func'] x = func.args[0] hx = match['hx'] hy = match['hy'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) hysym = hy.free_symbols if y not in hysym: try: fx = exp(integrate(hy, x)) except NotImplementedError: pass else: inf = {xi: S.Zero, eta: fx} if not comp: return [inf] if comp and inf not in xieta: xieta.append(inf) factor = hy/h facsym = factor.free_symbols if x not in facsym: try: fy = exp(integrate(factor, y)) except NotImplementedError: pass else: inf = {xi: S.Zero, eta: fy.subs(y, func)} if not comp: return [inf] if comp and inf not in xieta: xieta.append(inf) factor = -hx/h facsym = factor.free_symbols if y not in facsym: try: fx = exp(integrate(factor, x)) except NotImplementedError: pass else: inf = {xi: fx, eta: S.Zero} if not comp: return [inf] if comp and inf not in xieta: xieta.append(inf) factor = -hx/(h**2) facsym = factor.free_symbols if x not in facsym: try: fy = exp(integrate(factor, y)) except NotImplementedError: pass else: inf = {xi: fy.subs(y, func), eta: S.Zero} if not comp: return [inf] if comp and inf not in xieta: xieta.append(inf) if xieta: return xieta def lie_heuristic_abaco1_product(match, comp=False): r""" The second heuristic uses the following two assumptions on `\xi` and `\eta` .. math:: \eta = 0, \xi = f(x)*g(y) .. math:: \eta = f(x)*g(y), \xi = 0 The first assumption of this heuristic holds good if `\frac{1}{h^{2}}\frac{\partial^2}{\partial x \partial y}\log(h)` is separable in `x` and `y`, then the separated factors containing `x` is `f(x)`, and `g(y)` is obtained by .. math:: e^{\int f\frac{\partial}{\partial x}\left(\frac{1}{f*h}\right)\,dy} provided `f\frac{\partial}{\partial x}\left(\frac{1}{f*h}\right)` is a function of `y` only. The second assumption holds good if `\frac{dy}{dx} = h(x, y)` is rewritten as `\frac{dy}{dx} = \frac{1}{h(y, x)}` and the same properties of the first assumption satisfies. After obtaining `f(x)` and `g(y)`, the coordinates are again interchanged, to get `\eta` as `f(x)*g(y)` References ========== - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order ODE Patterns, pp. 7 - pp. 8 """ xieta = [] y = match['y'] h = match['h'] hinv = match['hinv'] func = match['func'] x = func.args[0] xi = Function('xi')(x, func) eta = Function('eta')(x, func) inf = separatevars(((log(h).diff(y)).diff(x))/h**2, dict=True, symbols=[x, y]) if inf and inf['coeff']: fx = inf[x] gy = simplify(fx*((1/(fx*h)).diff(x))) gysyms = gy.free_symbols if x not in gysyms: gy = exp(integrate(gy, y)) inf = {eta: S.Zero, xi: (fx*gy).subs(y, func)} if not comp: return [inf] if comp and inf not in xieta: xieta.append(inf) u1 = Dummy("u1") inf = separatevars(((log(hinv).diff(y)).diff(x))/hinv**2, dict=True, symbols=[x, y]) if inf and inf['coeff']: fx = inf[x] gy = simplify(fx*((1/(fx*hinv)).diff(x))) gysyms = gy.free_symbols if x not in gysyms: gy = exp(integrate(gy, y)) etaval = fx*gy etaval = (etaval.subs([(x, u1), (y, x)])).subs(u1, y) inf = {eta: etaval.subs(y, func), xi: S.Zero} if not comp: return [inf] if comp and inf not in xieta: xieta.append(inf) if xieta: return xieta def lie_heuristic_bivariate(match, comp=False): r""" The third heuristic assumes the infinitesimals `\xi` and `\eta` to be bi-variate polynomials in `x` and `y`. The assumption made here for the logic below is that `h` is a rational function in `x` and `y` though that may not be necessary for the infinitesimals to be bivariate polynomials. The coefficients of the infinitesimals are found out by substituting them in the PDE and grouping similar terms that are polynomials and since they form a linear system, solve and check for non trivial solutions. The degree of the assumed bivariates are increased till a certain maximum value. References ========== - Lie Groups and Differential Equations pp. 327 - pp. 329 """ h = match['h'] hx = match['hx'] hy = match['hy'] func = match['func'] x = func.args[0] y = match['y'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) if h.is_rational_function(): # The maximum degree that the infinitesimals can take is # calculated by this technique. etax, etay, etad, xix, xiy, xid = symbols("etax etay etad xix xiy xid") ipde = etax + (etay - xix)*h - xiy*h**2 - xid*hx - etad*hy num, denom = cancel(ipde).as_numer_denom() deg = Poly(num, x, y).total_degree() deta = Function('deta')(x, y) dxi = Function('dxi')(x, y) ipde = (deta.diff(x) + (deta.diff(y) - dxi.diff(x))*h - (dxi.diff(y))*h**2 - dxi*hx - deta*hy) xieq = Symbol("xi0") etaeq = Symbol("eta0") for i in range(deg + 1): if i: xieq += Add(*[ Symbol("xi_" + str(power) + "_" + str(i - power))*x**power*y**(i - power) for power in range(i + 1)]) etaeq += Add(*[ Symbol("eta_" + str(power) + "_" + str(i - power))*x**power*y**(i - power) for power in range(i + 1)]) pden, denom = (ipde.subs({dxi: xieq, deta: etaeq}).doit()).as_numer_denom() pden = expand(pden) # If the individual terms are monomials, the coefficients # are grouped if pden.is_polynomial(x, y) and pden.is_Add: polyy = Poly(pden, x, y).as_dict() if polyy: symset = xieq.free_symbols.union(etaeq.free_symbols) - {x, y} soldict = solve(polyy.values(), *symset) if isinstance(soldict, list): soldict = soldict[0] if any(soldict.values()): xired = xieq.subs(soldict) etared = etaeq.subs(soldict) # Scaling is done by substituting one for the parameters # This can be any number except zero. dict_ = {sym: 1 for sym in symset} inf = {eta: etared.subs(dict_).subs(y, func), xi: xired.subs(dict_).subs(y, func)} return [inf] def lie_heuristic_chi(match, comp=False): r""" The aim of the fourth heuristic is to find the function `\chi(x, y)` that satisfies the PDE `\frac{d\chi}{dx} + h\frac{d\chi}{dx} - \frac{\partial h}{\partial y}\chi = 0`. This assumes `\chi` to be a bivariate polynomial in `x` and `y`. By intuition, `h` should be a rational function in `x` and `y`. The method used here is to substitute a general binomial for `\chi` up to a certain maximum degree is reached. The coefficients of the polynomials, are calculated by by collecting terms of the same order in `x` and `y`. After finding `\chi`, the next step is to use `\eta = \xi*h + \chi`, to determine `\xi` and `\eta`. This can be done by dividing `\chi` by `h` which would give `-\xi` as the quotient and `\eta` as the remainder. References ========== - E.S Cheb-Terrab, L.G.S Duarte and L.A,C.P da Mota, Computer Algebra Solving of First Order ODEs Using Symmetry Methods, pp. 8 """ h = match['h'] hy = match['hy'] func = match['func'] x = func.args[0] y = match['y'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) if h.is_rational_function(): schi, schix, schiy = symbols("schi, schix, schiy") cpde = schix + h*schiy - hy*schi num, denom = cancel(cpde).as_numer_denom() deg = Poly(num, x, y).total_degree() chi = Function('chi')(x, y) chix = chi.diff(x) chiy = chi.diff(y) cpde = chix + h*chiy - hy*chi chieq = Symbol("chi") for i in range(1, deg + 1): chieq += Add(*[ Symbol("chi_" + str(power) + "_" + str(i - power))*x**power*y**(i - power) for power in range(i + 1)]) cnum, cden = cancel(cpde.subs({chi : chieq}).doit()).as_numer_denom() cnum = expand(cnum) if cnum.is_polynomial(x, y) and cnum.is_Add: cpoly = Poly(cnum, x, y).as_dict() if cpoly: solsyms = chieq.free_symbols - {x, y} soldict = solve(cpoly.values(), *solsyms) if isinstance(soldict, list): soldict = soldict[0] if any(soldict.values()): chieq = chieq.subs(soldict) dict_ = {sym: 1 for sym in solsyms} chieq = chieq.subs(dict_) # After finding chi, the main aim is to find out # eta, xi by the equation eta = xi*h + chi # One method to set xi, would be rearranging it to # (eta/h) - xi = (chi/h). This would mean dividing # chi by h would give -xi as the quotient and eta # as the remainder. Thanks to Sean Vig for suggesting # this method. xic, etac = div(chieq, h) inf = {eta: etac.subs(y, func), xi: -xic.subs(y, func)} return [inf] def lie_heuristic_function_sum(match, comp=False): r""" This heuristic uses the following two assumptions on `\xi` and `\eta` .. math:: \eta = 0, \xi = f(x) + g(y) .. math:: \eta = f(x) + g(y), \xi = 0 The first assumption of this heuristic holds good if .. math:: \frac{\partial}{\partial y}[(h\frac{\partial^{2}}{ \partial x^{2}}(h^{-1}))^{-1}] is separable in `x` and `y`, 1. The separated factors containing `y` is `\frac{\partial g}{\partial y}`. From this `g(y)` can be determined. 2. The separated factors containing `x` is `f''(x)`. 3. `h\frac{\partial^{2}}{\partial x^{2}}(h^{-1})` equals `\frac{f''(x)}{f(x) + g(y)}`. From this `f(x)` can be determined. The second assumption holds good if `\frac{dy}{dx} = h(x, y)` is rewritten as `\frac{dy}{dx} = \frac{1}{h(y, x)}` and the same properties of the first assumption satisfies. After obtaining `f(x)` and `g(y)`, the coordinates are again interchanged, to get `\eta` as `f(x) + g(y)`. For both assumptions, the constant factors are separated among `g(y)` and `f''(x)`, such that `f''(x)` obtained from 3] is the same as that obtained from 2]. If not possible, then this heuristic fails. References ========== - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order ODE Patterns, pp. 7 - pp. 8 """ xieta = [] h = match['h'] func = match['func'] hinv = match['hinv'] x = func.args[0] y = match['y'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) for odefac in [h, hinv]: factor = odefac*((1/odefac).diff(x, 2)) sep = separatevars((1/factor).diff(y), dict=True, symbols=[x, y]) if sep and sep['coeff'] and sep[x].has(x) and sep[y].has(y): k = Dummy("k") try: gy = k*integrate(sep[y], y) except NotImplementedError: pass else: fdd = 1/(k*sep[x]*sep['coeff']) fx = simplify(fdd/factor - gy) check = simplify(fx.diff(x, 2) - fdd) if fx: if not check: fx = fx.subs(k, 1) gy = (gy/k) else: sol = solve(check, k) if sol: sol = sol[0] fx = fx.subs(k, sol) gy = (gy/k)*sol else: continue if odefac == hinv: # Inverse ODE fx = fx.subs(x, y) gy = gy.subs(y, x) etaval = factor_terms(fx + gy) if etaval.is_Mul: etaval = Mul(*[arg for arg in etaval.args if arg.has(x, y)]) if odefac == hinv: # Inverse ODE inf = {eta: etaval.subs(y, func), xi : S.Zero} else: inf = {xi: etaval.subs(y, func), eta : S.Zero} if not comp: return [inf] else: xieta.append(inf) if xieta: return xieta def lie_heuristic_abaco2_similar(match, comp=False): r""" This heuristic uses the following two assumptions on `\xi` and `\eta` .. math:: \eta = g(x), \xi = f(x) .. math:: \eta = f(y), \xi = g(y) For the first assumption, 1. First `\frac{\frac{\partial h}{\partial y}}{\frac{\partial^{2} h}{ \partial yy}}` is calculated. Let us say this value is A 2. If this is constant, then `h` is matched to the form `A(x) + B(x)e^{ \frac{y}{C}}` then, `\frac{e^{\int \frac{A(x)}{C} \,dx}}{B(x)}` gives `f(x)` and `A(x)*f(x)` gives `g(x)` 3. Otherwise `\frac{\frac{\partial A}{\partial X}}{\frac{\partial A}{ \partial Y}} = \gamma` is calculated. If a] `\gamma` is a function of `x` alone b] `\frac{\gamma\frac{\partial h}{\partial y} - \gamma'(x) - \frac{ \partial h}{\partial x}}{h + \gamma} = G` is a function of `x` alone. then, `e^{\int G \,dx}` gives `f(x)` and `-\gamma*f(x)` gives `g(x)` The second assumption holds good if `\frac{dy}{dx} = h(x, y)` is rewritten as `\frac{dy}{dx} = \frac{1}{h(y, x)}` and the same properties of the first assumption satisfies. After obtaining `f(x)` and `g(x)`, the coordinates are again interchanged, to get `\xi` as `f(x^*)` and `\eta` as `g(y^*)` References ========== - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order ODE Patterns, pp. 10 - pp. 12 """ h = match['h'] hx = match['hx'] hy = match['hy'] func = match['func'] hinv = match['hinv'] x = func.args[0] y = match['y'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) factor = cancel(h.diff(y)/h.diff(y, 2)) factorx = factor.diff(x) factory = factor.diff(y) if not factor.has(x) and not factor.has(y): A = Wild('A', exclude=[y]) B = Wild('B', exclude=[y]) C = Wild('C', exclude=[x, y]) match = h.match(A + B*exp(y/C)) try: tau = exp(-integrate(match[A]/match[C]), x)/match[B] except NotImplementedError: pass else: gx = match[A]*tau return [{xi: tau, eta: gx}] else: gamma = cancel(factorx/factory) if not gamma.has(y): tauint = cancel((gamma*hy - gamma.diff(x) - hx)/(h + gamma)) if not tauint.has(y): try: tau = exp(integrate(tauint, x)) except NotImplementedError: pass else: gx = -tau*gamma return [{xi: tau, eta: gx}] factor = cancel(hinv.diff(y)/hinv.diff(y, 2)) factorx = factor.diff(x) factory = factor.diff(y) if not factor.has(x) and not factor.has(y): A = Wild('A', exclude=[y]) B = Wild('B', exclude=[y]) C = Wild('C', exclude=[x, y]) match = h.match(A + B*exp(y/C)) try: tau = exp(-integrate(match[A]/match[C]), x)/match[B] except NotImplementedError: pass else: gx = match[A]*tau return [{eta: tau.subs(x, func), xi: gx.subs(x, func)}] else: gamma = cancel(factorx/factory) if not gamma.has(y): tauint = cancel((gamma*hinv.diff(y) - gamma.diff(x) - hinv.diff(x))/( hinv + gamma)) if not tauint.has(y): try: tau = exp(integrate(tauint, x)) except NotImplementedError: pass else: gx = -tau*gamma return [{eta: tau.subs(x, func), xi: gx.subs(x, func)}] def lie_heuristic_abaco2_unique_unknown(match, comp=False): r""" This heuristic assumes the presence of unknown functions or known functions with non-integer powers. 1. A list of all functions and non-integer powers containing x and y 2. Loop over each element `f` in the list, find `\frac{\frac{\partial f}{\partial x}}{ \frac{\partial f}{\partial x}} = R` If it is separable in `x` and `y`, let `X` be the factors containing `x`. Then a] Check if `\xi = X` and `\eta = -\frac{X}{R}` satisfy the PDE. If yes, then return `\xi` and `\eta` b] Check if `\xi = \frac{-R}{X}` and `\eta = -\frac{1}{X}` satisfy the PDE. If yes, then return `\xi` and `\eta` If not, then check if a] :math:`\xi = -R,\eta = 1` b] :math:`\xi = 1, \eta = -\frac{1}{R}` are solutions. References ========== - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order ODE Patterns, pp. 10 - pp. 12 """ h = match['h'] hx = match['hx'] hy = match['hy'] func = match['func'] x = func.args[0] y = match['y'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) funclist = [] for atom in h.atoms(Pow): base, exp = atom.as_base_exp() if base.has(x) and base.has(y): if not exp.is_Integer: funclist.append(atom) for function in h.atoms(AppliedUndef): syms = function.free_symbols if x in syms and y in syms: funclist.append(function) for f in funclist: frac = cancel(f.diff(y)/f.diff(x)) sep = separatevars(frac, dict=True, symbols=[x, y]) if sep and sep['coeff']: xitry1 = sep[x] etatry1 = -1/(sep[y]*sep['coeff']) pde1 = etatry1.diff(y)*h - xitry1.diff(x)*h - xitry1*hx - etatry1*hy if not simplify(pde1): return [{xi: xitry1, eta: etatry1.subs(y, func)}] xitry2 = 1/etatry1 etatry2 = 1/xitry1 pde2 = etatry2.diff(x) - (xitry2.diff(y))*h**2 - xitry2*hx - etatry2*hy if not simplify(expand(pde2)): return [{xi: xitry2.subs(y, func), eta: etatry2}] else: etatry = -1/frac pde = etatry.diff(x) + etatry.diff(y)*h - hx - etatry*hy if not simplify(pde): return [{xi: S.One, eta: etatry.subs(y, func)}] xitry = -frac pde = -xitry.diff(x)*h -xitry.diff(y)*h**2 - xitry*hx -hy if not simplify(expand(pde)): return [{xi: xitry.subs(y, func), eta: S.One}] def lie_heuristic_abaco2_unique_general(match, comp=False): r""" This heuristic finds if infinitesimals of the form `\eta = f(x)`, `\xi = g(y)` without making any assumptions on `h`. The complete sequence of steps is given in the paper mentioned below. References ========== - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order ODE Patterns, pp. 10 - pp. 12 """ hx = match['hx'] hy = match['hy'] func = match['func'] x = func.args[0] y = match['y'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) A = hx.diff(y) B = hy.diff(y) + hy**2 C = hx.diff(x) - hx**2 if not (A and B and C): return Ax = A.diff(x) Ay = A.diff(y) Axy = Ax.diff(y) Axx = Ax.diff(x) Ayy = Ay.diff(y) D = simplify(2*Axy + hx*Ay - Ax*hy + (hx*hy + 2*A)*A)*A - 3*Ax*Ay if not D: E1 = simplify(3*Ax**2 + ((hx**2 + 2*C)*A - 2*Axx)*A) if E1: E2 = simplify((2*Ayy + (2*B - hy**2)*A)*A - 3*Ay**2) if not E2: E3 = simplify( E1*((28*Ax + 4*hx*A)*A**3 - E1*(hy*A + Ay)) - E1.diff(x)*8*A**4) if not E3: etaval = cancel((4*A**3*(Ax - hx*A) + E1*(hy*A - Ay))/(S(2)*A*E1)) if x not in etaval: try: etaval = exp(integrate(etaval, y)) except NotImplementedError: pass else: xival = -4*A**3*etaval/E1 if y not in xival: return [{xi: xival, eta: etaval.subs(y, func)}] else: E1 = simplify((2*Ayy + (2*B - hy**2)*A)*A - 3*Ay**2) if E1: E2 = simplify( 4*A**3*D - D**2 + E1*((2*Axx - (hx**2 + 2*C)*A)*A - 3*Ax**2)) if not E2: E3 = simplify( -(A*D)*E1.diff(y) + ((E1.diff(x) - hy*D)*A + 3*Ay*D + (A*hx - 3*Ax)*E1)*E1) if not E3: etaval = cancel(((A*hx - Ax)*E1 - (Ay + A*hy)*D)/(S(2)*A*D)) if x not in etaval: try: etaval = exp(integrate(etaval, y)) except NotImplementedError: pass else: xival = -E1*etaval/D if y not in xival: return [{xi: xival, eta: etaval.subs(y, func)}] def lie_heuristic_linear(match, comp=False): r""" This heuristic assumes 1. `\xi = ax + by + c` and 2. `\eta = fx + gy + h` After substituting the following assumptions in the determining PDE, it reduces to .. math:: f + (g - a)h - bh^{2} - (ax + by + c)\frac{\partial h}{\partial x} - (fx + gy + c)\frac{\partial h}{\partial y} Solving the reduced PDE obtained, using the method of characteristics, becomes impractical. The method followed is grouping similar terms and solving the system of linear equations obtained. The difference between the bivariate heuristic is that `h` need not be a rational function in this case. References ========== - E.S. Cheb-Terrab, A.D. Roche, Symmetries and First Order ODE Patterns, pp. 10 - pp. 12 """ h = match['h'] hx = match['hx'] hy = match['hy'] func = match['func'] x = func.args[0] y = match['y'] xi = Function('xi')(x, func) eta = Function('eta')(x, func) coeffdict = {} symbols = numbered_symbols("c", cls=Dummy) symlist = [next(symbols) for _ in islice(symbols, 6)] C0, C1, C2, C3, C4, C5 = symlist pde = C3 + (C4 - C0)*h - (C0*x + C1*y + C2)*hx - (C3*x + C4*y + C5)*hy - C1*h**2 pde, denom = pde.as_numer_denom() pde = powsimp(expand(pde)) if pde.is_Add: terms = pde.args for term in terms: if term.is_Mul: rem = Mul(*[m for m in term.args if not m.has(x, y)]) xypart = term/rem if xypart not in coeffdict: coeffdict[xypart] = rem else: coeffdict[xypart] += rem else: if term not in coeffdict: coeffdict[term] = S.One else: coeffdict[term] += S.One sollist = coeffdict.values() soldict = solve(sollist, symlist) if soldict: if isinstance(soldict, list): soldict = soldict[0] subval = soldict.values() if any(t for t in subval): onedict = dict(zip(symlist, [1]*6)) xival = C0*x + C1*func + C2 etaval = C3*x + C4*func + C5 xival = xival.subs(soldict) etaval = etaval.subs(soldict) xival = xival.subs(onedict) etaval = etaval.subs(onedict) return [{xi: xival, eta: etaval}] def _lie_group_remove(coords): r""" This function is strictly meant for internal use by the Lie group ODE solving method. It replaces arbitrary functions returned by pdsolve as follows: 1] If coords is an arbitrary function, then its argument is returned. 2] An arbitrary function in an Add object is replaced by zero. 3] An arbitrary function in a Mul object is replaced by one. 4] If there is no arbitrary function coords is returned unchanged. Examples ======== >>> from sympy.solvers.ode.lie_group import _lie_group_remove >>> from sympy import Function >>> from sympy.abc import x, y >>> F = Function("F") >>> eq = x**2*y >>> _lie_group_remove(eq) x**2*y >>> eq = F(x**2*y) >>> _lie_group_remove(eq) x**2*y >>> eq = x*y**2 + F(x**3) >>> _lie_group_remove(eq) x*y**2 >>> eq = (F(x**3) + y)*x**4 >>> _lie_group_remove(eq) x**4*y """ if isinstance(coords, AppliedUndef): return coords.args[0] elif coords.is_Add: subfunc = coords.atoms(AppliedUndef) if subfunc: for func in subfunc: coords = coords.subs(func, 0) return coords elif coords.is_Pow: base, expr = coords.as_base_exp() base = _lie_group_remove(base) expr = _lie_group_remove(expr) return base**expr elif coords.is_Mul: mulargs = [] coordargs = coords.args for arg in coordargs: if not isinstance(coords, AppliedUndef): mulargs.append(_lie_group_remove(arg)) return Mul(*mulargs) return coords sympy-sympy-1.9/sympy/solvers/ode/nonhomogeneous.py000066400000000000000000000433771412543434000230030ustar00rootroot00000000000000r""" This File contains helper functions for nth_linear_constant_coeff_undetermined_coefficients, nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients, nth_linear_constant_coeff_variation_of_parameters, and nth_linear_euler_eq_nonhomogeneous_variation_of_parameters. All the functions in this file are used by more than one solvers so, instead of creating instances in other classes for using them it is better to keep it here as separate helpers. """ from collections import defaultdict from sympy.core import Add, S from sympy.core.function import diff, expand, _mexpand, expand_mul from sympy.core.relational import Eq from sympy.core.symbol import Dummy, Wild from sympy.functions import exp, cos, cosh, im, log, re, sin, sinh, \ atan2, conjugate from sympy.integrals import Integral from sympy.polys import (Poly, RootOf, rootof, roots) from sympy.simplify import collect, simplify, separatevars, powsimp, trigsimp from sympy.utilities import numbered_symbols, default_sort_key from sympy.solvers.solvers import solve from sympy.matrices import wronskian from .subscheck import sub_func_doit from sympy.solvers.ode.ode import get_numbered_constants def _test_term(coeff, func, order): r""" Linear Euler ODEs have the form K*x**order*diff(y(x), x, order) = F(x), where K is independent of x and y(x), order>= 0. So we need to check that for each term, coeff == K*x**order from some K. We have a few cases, since coeff may have several different types. """ x = func.args[0] f = func.func if order < 0: raise ValueError("order should be greater than 0") if coeff == 0: return True if order == 0: if x in coeff.free_symbols: return False return True if coeff.is_Mul: if coeff.has(f(x)): return False return x**order in coeff.args elif coeff.is_Pow: return coeff.as_base_exp() == (x, order) elif order == 1: return x == coeff return False def _get_euler_characteristic_eq_sols(eq, func, match_obj): r""" Returns the solution of homogeneous part of the linear euler ODE and the list of roots of characteristic equation. The parameter ``match_obj`` is a dict of order:coeff terms, where order is the order of the derivative on each term, and coeff is the coefficient of that derivative. """ x = func.args[0] f = func.func # First, set up characteristic equation. chareq, symbol = S.Zero, Dummy('x') for i in match_obj: if i >= 0: chareq += (match_obj[i]*diff(x**symbol, x, i)*x**-symbol).expand() chareq = Poly(chareq, symbol) chareqroots = [rootof(chareq, k) for k in range(chareq.degree())] collectterms = [] # A generator of constants constants = list(get_numbered_constants(eq, num=chareq.degree()*2)) constants.reverse() # Create a dict root: multiplicity or charroots charroots = defaultdict(int) for root in chareqroots: charroots[root] += 1 gsol = S.Zero ln = log for root, multiplicity in charroots.items(): for i in range(multiplicity): if isinstance(root, RootOf): gsol += (x**root) * constants.pop() if multiplicity != 1: raise ValueError("Value should be 1") collectterms = [(0, root, 0)] + collectterms elif root.is_real: gsol += ln(x)**i*(x**root) * constants.pop() collectterms = [(i, root, 0)] + collectterms else: reroot = re(root) imroot = im(root) gsol += ln(x)**i * (x**reroot) * ( constants.pop() * sin(abs(imroot)*ln(x)) + constants.pop() * cos(imroot*ln(x))) collectterms = [(i, reroot, imroot)] + collectterms gsol = Eq(f(x), gsol) gensols = [] # Keep track of when to use sin or cos for nonzero imroot for i, reroot, imroot in collectterms: if imroot == 0: gensols.append(ln(x)**i*x**reroot) else: sin_form = ln(x)**i*x**reroot*sin(abs(imroot)*ln(x)) if sin_form in gensols: cos_form = ln(x)**i*x**reroot*cos(imroot*ln(x)) gensols.append(cos_form) else: gensols.append(sin_form) return gsol, gensols def _solve_variation_of_parameters(eq, func, roots, homogen_sol, order, match_obj, simplify_flag=True): r""" Helper function for the method of variation of parameters and nonhomogeneous euler eq. See the :py:meth:`~sympy.solvers.ode.single.NthLinearConstantCoeffVariationOfParameters` docstring for more information on this method. The parameter are ``match_obj`` should be a dictionary that has the following keys: ``list`` A list of solutions to the homogeneous equation. ``sol`` The general solution. """ f = func.func x = func.args[0] r = match_obj psol = 0 wr = wronskian(roots, x) if simplify_flag: wr = simplify(wr) # We need much better simplification for # some ODEs. See issue 4662, for example. # To reduce commonly occurring sin(x)**2 + cos(x)**2 to 1 wr = trigsimp(wr, deep=True, recursive=True) if not wr: # The wronskian will be 0 iff the solutions are not linearly # independent. raise NotImplementedError("Cannot find " + str(order) + " solutions to the homogeneous equation necessary to apply " + "variation of parameters to " + str(eq) + " (Wronskian == 0)") if len(roots) != order: raise NotImplementedError("Cannot find " + str(order) + " solutions to the homogeneous equation necessary to apply " + "variation of parameters to " + str(eq) + " (number of terms != order)") negoneterm = (-1)**(order) for i in roots: psol += negoneterm*Integral(wronskian([sol for sol in roots if sol != i], x)*r[-1]/wr, x)*i/r[order] negoneterm *= -1 if simplify_flag: psol = simplify(psol) psol = trigsimp(psol, deep=True) return Eq(f(x), homogen_sol.rhs + psol) def _get_const_characteristic_eq_sols(r, func, order): r""" Returns the roots of characteristic equation of constant coefficient linear ODE and list of collectterms which is later on used by simplification to use collect on solution. The parameter `r` is a dict of order:coeff terms, where order is the order of the derivative on each term, and coeff is the coefficient of that derivative. """ x = func.args[0] # First, set up characteristic equation. chareq, symbol = S.Zero, Dummy('x') for i in r.keys(): if type(i) == str or i < 0: pass else: chareq += r[i]*symbol**i chareq = Poly(chareq, symbol) # Can't just call roots because it doesn't return rootof for unsolveable # polynomials. chareqroots = roots(chareq, multiple=True) if len(chareqroots) != order: chareqroots = [rootof(chareq, k) for k in range(chareq.degree())] chareq_is_complex = not all([i.is_real for i in chareq.all_coeffs()]) # Create a dict root: multiplicity or charroots charroots = defaultdict(int) for root in chareqroots: charroots[root] += 1 # We need to keep track of terms so we can run collect() at the end. # This is necessary for constantsimp to work properly. collectterms = [] gensols = [] conjugate_roots = [] # used to prevent double-use of conjugate roots # Loop over roots in theorder provided by roots/rootof... for root in chareqroots: # but don't repoeat multiple roots. if root not in charroots: continue multiplicity = charroots.pop(root) for i in range(multiplicity): if chareq_is_complex: gensols.append(x**i*exp(root*x)) collectterms = [(i, root, 0)] + collectterms continue reroot = re(root) imroot = im(root) if imroot.has(atan2) and reroot.has(atan2): # Remove this condition when re and im stop returning # circular atan2 usages. gensols.append(x**i*exp(root*x)) collectterms = [(i, root, 0)] + collectterms else: if root in conjugate_roots: collectterms = [(i, reroot, imroot)] + collectterms continue if imroot == 0: gensols.append(x**i*exp(reroot*x)) collectterms = [(i, reroot, 0)] + collectterms continue conjugate_roots.append(conjugate(root)) gensols.append(x**i*exp(reroot*x) * sin(abs(imroot) * x)) gensols.append(x**i*exp(reroot*x) * cos( imroot * x)) # This ordering is important collectterms = [(i, reroot, imroot)] + collectterms return gensols, collectterms # Ideally these kind of simplification functions shouldn't be part of solvers. # odesimp should be improved to handle these kind of specific simplifications. def _get_simplified_sol(sol, func, collectterms): r""" Helper function which collects the solution on collectterms. Ideally this should be handled by odesimp.It is used only when the simplify is set to True in dsolve. The parameter ``collectterms`` is a list of tuple (i, reroot, imroot) where `i` is the multiplicity of the root, reroot is real part and imroot being the imaginary part. """ f = func.func x = func.args[0] collectterms.sort(key=default_sort_key) collectterms.reverse() assert len(sol) == 1 and sol[0].lhs == f(x) sol = sol[0].rhs sol = expand_mul(sol) for i, reroot, imroot in collectterms: sol = collect(sol, x**i*exp(reroot*x)*sin(abs(imroot)*x)) sol = collect(sol, x**i*exp(reroot*x)*cos(imroot*x)) for i, reroot, imroot in collectterms: sol = collect(sol, x**i*exp(reroot*x)) sol = powsimp(sol) return Eq(f(x), sol) def _undetermined_coefficients_match(expr, x, func=None, eq_homogeneous=S.Zero): r""" Returns a trial function match if undetermined coefficients can be applied to ``expr``, and ``None`` otherwise. A trial expression can be found for an expression for use with the method of undetermined coefficients if the expression is an additive/multiplicative combination of constants, polynomials in `x` (the independent variable of expr), `\sin(a x + b)`, `\cos(a x + b)`, and `e^{a x}` terms (in other words, it has a finite number of linearly independent derivatives). Note that you may still need to multiply each term returned here by sufficient `x` to make it linearly independent with the solutions to the homogeneous equation. This is intended for internal use by ``undetermined_coefficients`` hints. SymPy currently has no way to convert `\sin^n(x) \cos^m(y)` into a sum of only `\sin(a x)` and `\cos(b x)` terms, so these are not implemented. So, for example, you will need to manually convert `\sin^2(x)` into `[1 + \cos(2 x)]/2` to properly apply the method of undetermined coefficients on it. Examples ======== >>> from sympy import log, exp >>> from sympy.solvers.ode.nonhomogeneous import _undetermined_coefficients_match >>> from sympy.abc import x >>> _undetermined_coefficients_match(9*x*exp(x) + exp(-x), x) {'test': True, 'trialset': {x*exp(x), exp(-x), exp(x)}} >>> _undetermined_coefficients_match(log(x), x) {'test': False} """ a = Wild('a', exclude=[x]) b = Wild('b', exclude=[x]) expr = powsimp(expr, combine='exp') # exp(x)*exp(2*x + 1) => exp(3*x + 1) retdict = {} def _test_term(expr, x): r""" Test if ``expr`` fits the proper form for undetermined coefficients. """ if not expr.has(x): return True elif expr.is_Add: return all(_test_term(i, x) for i in expr.args) elif expr.is_Mul: if expr.has(sin, cos): foundtrig = False # Make sure that there is only one trig function in the args. # See the docstring. for i in expr.args: if i.has(sin, cos): if foundtrig: return False else: foundtrig = True return all(_test_term(i, x) for i in expr.args) elif expr.is_Function: if expr.func in (sin, cos, exp, sinh, cosh): if expr.args[0].match(a*x + b): return True else: return False else: return False elif expr.is_Pow and expr.base.is_Symbol and expr.exp.is_Integer and \ expr.exp >= 0: return True elif expr.is_Pow and expr.base.is_number: if expr.exp.match(a*x + b): return True else: return False elif expr.is_Symbol or expr.is_number: return True else: return False def _get_trial_set(expr, x, exprs=set()): r""" Returns a set of trial terms for undetermined coefficients. The idea behind undetermined coefficients is that the terms expression repeat themselves after a finite number of derivatives, except for the coefficients (they are linearly dependent). So if we collect these, we should have the terms of our trial function. """ def _remove_coefficient(expr, x): r""" Returns the expression without a coefficient. Similar to expr.as_independent(x)[1], except it only works multiplicatively. """ term = S.One if expr.is_Mul: for i in expr.args: if i.has(x): term *= i elif expr.has(x): term = expr return term expr = expand_mul(expr) if expr.is_Add: for term in expr.args: if _remove_coefficient(term, x) in exprs: pass else: exprs.add(_remove_coefficient(term, x)) exprs = exprs.union(_get_trial_set(term, x, exprs)) else: term = _remove_coefficient(expr, x) tmpset = exprs.union({term}) oldset = set() while tmpset != oldset: # If you get stuck in this loop, then _test_term is probably # broken oldset = tmpset.copy() expr = expr.diff(x) term = _remove_coefficient(expr, x) if term.is_Add: tmpset = tmpset.union(_get_trial_set(term, x, tmpset)) else: tmpset.add(term) exprs = tmpset return exprs def is_homogeneous_solution(term): r""" This function checks whether the given trialset contains any root of homogenous equation""" return expand(sub_func_doit(eq_homogeneous, func, term)).is_zero retdict['test'] = _test_term(expr, x) if retdict['test']: # Try to generate a list of trial solutions that will have the # undetermined coefficients. Note that if any of these are not linearly # independent with any of the solutions to the homogeneous equation, # then they will need to be multiplied by sufficient x to make them so. # This function DOES NOT do that (it doesn't even look at the # homogeneous equation). temp_set = set() for i in Add.make_args(expr): act = _get_trial_set(i, x) if eq_homogeneous is not S.Zero: while any(is_homogeneous_solution(ts) for ts in act): act = {x*ts for ts in act} temp_set = temp_set.union(act) retdict['trialset'] = temp_set return retdict def _solve_undetermined_coefficients(eq, func, order, match, trialset): r""" Helper function for the method of undetermined coefficients. See the :py:meth:`~sympy.solvers.ode.single.NthLinearConstantCoeffUndeterminedCoefficients` docstring for more information on this method. The parameter ``trialset`` is the set of trial functions as returned by ``_undetermined_coefficients_match()['trialset']``. The parameter ``match`` should be a dictionary that has the following keys: ``list`` A list of solutions to the homogeneous equation. ``sol`` The general solution. """ r = match coeffs = numbered_symbols('a', cls=Dummy) coefflist = [] gensols = r['list'] gsol = r['sol'] f = func.func x = func.args[0] if len(gensols) != order: raise NotImplementedError("Cannot find " + str(order) + " solutions to the homogeneous equation necessary to apply" + " undetermined coefficients to " + str(eq) + " (number of terms != order)") trialfunc = 0 for i in trialset: c = next(coeffs) coefflist.append(c) trialfunc += c*i eqs = sub_func_doit(eq, f(x), trialfunc) coeffsdict = dict(list(zip(trialset, [0]*(len(trialset) + 1)))) eqs = _mexpand(eqs) for i in Add.make_args(eqs): s = separatevars(i, dict=True, symbols=[x]) if coeffsdict.get(s[x]): coeffsdict[s[x]] += s['coeff'] else: coeffsdict[s[x]] = s['coeff'] coeffvals = solve(list(coeffsdict.values()), coefflist) if not coeffvals: raise NotImplementedError( "Could not solve `%s` using the " "method of undetermined coefficients " "(unable to solve for coefficients)." % eq) psol = trialfunc.subs(coeffvals) return Eq(f(x), gsol.rhs + psol) sympy-sympy-1.9/sympy/solvers/ode/ode.py000066400000000000000000004335001412543434000204760ustar00rootroot00000000000000r""" This module contains :py:meth:`~sympy.solvers.ode.dsolve` and different helper functions that it uses. :py:meth:`~sympy.solvers.ode.dsolve` solves ordinary differential equations. See the docstring on the various functions for their uses. Note that partial differential equations support is in ``pde.py``. Note that hint functions have docstrings describing their various methods, but they are intended for internal use. Use ``dsolve(ode, func, hint=hint)`` to solve an ODE using a specific hint. See also the docstring on :py:meth:`~sympy.solvers.ode.dsolve`. **Functions in this module** These are the user functions in this module: - :py:meth:`~sympy.solvers.ode.dsolve` - Solves ODEs. - :py:meth:`~sympy.solvers.ode.classify_ode` - Classifies ODEs into possible hints for :py:meth:`~sympy.solvers.ode.dsolve`. - :py:meth:`~sympy.solvers.ode.checkodesol` - Checks if an equation is the solution to an ODE. - :py:meth:`~sympy.solvers.ode.homogeneous_order` - Returns the homogeneous order of an expression. - :py:meth:`~sympy.solvers.ode.infinitesimals` - Returns the infinitesimals of the Lie group of point transformations of an ODE, such that it is invariant. - :py:meth:`~sympy.solvers.ode.checkinfsol` - Checks if the given infinitesimals are the actual infinitesimals of a first order ODE. These are the non-solver helper functions that are for internal use. The user should use the various options to :py:meth:`~sympy.solvers.ode.dsolve` to obtain the functionality provided by these functions: - :py:meth:`~sympy.solvers.ode.ode.odesimp` - Does all forms of ODE simplification. - :py:meth:`~sympy.solvers.ode.ode.ode_sol_simplicity` - A key function for comparing solutions by simplicity. - :py:meth:`~sympy.solvers.ode.constantsimp` - Simplifies arbitrary constants. - :py:meth:`~sympy.solvers.ode.ode.constant_renumber` - Renumber arbitrary constants. - :py:meth:`~sympy.solvers.ode.ode._handle_Integral` - Evaluate unevaluated Integrals. See also the docstrings of these functions. **Currently implemented solver methods** The following methods are implemented for solving ordinary differential equations. See the docstrings of the various hint functions for more information on each (run ``help(ode)``): - 1st order separable differential equations. - 1st order differential equations whose coefficients or `dx` and `dy` are functions homogeneous of the same order. - 1st order exact differential equations. - 1st order linear differential equations. - 1st order Bernoulli differential equations. - Power series solutions for first order differential equations. - Lie Group method of solving first order differential equations. - 2nd order Liouville differential equations. - Power series solutions for second order differential equations at ordinary and regular singular points. - `n`\th order differential equation that can be solved with algebraic rearrangement and integration. - `n`\th order linear homogeneous differential equation with constant coefficients. - `n`\th order linear inhomogeneous differential equation with constant coefficients using the method of undetermined coefficients. - `n`\th order linear inhomogeneous differential equation with constant coefficients using the method of variation of parameters. **Philosophy behind this module** This module is designed to make it easy to add new ODE solving methods without having to mess with the solving code for other methods. The idea is that there is a :py:meth:`~sympy.solvers.ode.classify_ode` function, which takes in an ODE and tells you what hints, if any, will solve the ODE. It does this without attempting to solve the ODE, so it is fast. Each solving method is a hint, and it has its own function, named ``ode_``. That function takes in the ODE and any match expression gathered by :py:meth:`~sympy.solvers.ode.classify_ode` and returns a solved result. If this result has any integrals in it, the hint function will return an unevaluated :py:class:`~sympy.integrals.integrals.Integral` class. :py:meth:`~sympy.solvers.ode.dsolve`, which is the user wrapper function around all of this, will then call :py:meth:`~sympy.solvers.ode.ode.odesimp` on the result, which, among other things, will attempt to solve the equation for the dependent variable (the function we are solving for), simplify the arbitrary constants in the expression, and evaluate any integrals, if the hint allows it. **How to add new solution methods** If you have an ODE that you want :py:meth:`~sympy.solvers.ode.dsolve` to be able to solve, try to avoid adding special case code here. Instead, try finding a general method that will solve your ODE, as well as others. This way, the :py:mod:`~sympy.solvers.ode` module will become more robust, and unhindered by special case hacks. WolphramAlpha and Maple's DETools[odeadvisor] function are two resources you can use to classify a specific ODE. It is also better for a method to work with an `n`\th order ODE instead of only with specific orders, if possible. To add a new method, there are a few things that you need to do. First, you need a hint name for your method. Try to name your hint so that it is unambiguous with all other methods, including ones that may not be implemented yet. If your method uses integrals, also include a ``hint_Integral`` hint. If there is more than one way to solve ODEs with your method, include a hint for each one, as well as a ``_best`` hint. Your ``ode__best()`` function should choose the best using min with ``ode_sol_simplicity`` as the key argument. See :obj:`~sympy.solvers.ode.single.HomogeneousCoeffBest`, for example. The function that uses your method will be called ``ode_()``, so the hint must only use characters that are allowed in a Python function name (alphanumeric characters and the underscore '``_``' character). Include a function for every hint, except for ``_Integral`` hints (:py:meth:`~sympy.solvers.ode.dsolve` takes care of those automatically). Hint names should be all lowercase, unless a word is commonly capitalized (such as Integral or Bernoulli). If you have a hint that you do not want to run with ``all_Integral`` that doesn't have an ``_Integral`` counterpart (such as a best hint that would defeat the purpose of ``all_Integral``), you will need to remove it manually in the :py:meth:`~sympy.solvers.ode.dsolve` code. See also the :py:meth:`~sympy.solvers.ode.classify_ode` docstring for guidelines on writing a hint name. Determine *in general* how the solutions returned by your method compare with other methods that can potentially solve the same ODEs. Then, put your hints in the :py:data:`~sympy.solvers.ode.allhints` tuple in the order that they should be called. The ordering of this tuple determines which hints are default. Note that exceptions are ok, because it is easy for the user to choose individual hints with :py:meth:`~sympy.solvers.ode.dsolve`. In general, ``_Integral`` variants should go at the end of the list, and ``_best`` variants should go before the various hints they apply to. For example, the ``undetermined_coefficients`` hint comes before the ``variation_of_parameters`` hint because, even though variation of parameters is more general than undetermined coefficients, undetermined coefficients generally returns cleaner results for the ODEs that it can solve than variation of parameters does, and it does not require integration, so it is much faster. Next, you need to have a match expression or a function that matches the type of the ODE, which you should put in :py:meth:`~sympy.solvers.ode.classify_ode` (if the match function is more than just a few lines. It should match the ODE without solving for it as much as possible, so that :py:meth:`~sympy.solvers.ode.classify_ode` remains fast and is not hindered by bugs in solving code. Be sure to consider corner cases. For example, if your solution method involves dividing by something, make sure you exclude the case where that division will be 0. In most cases, the matching of the ODE will also give you the various parts that you need to solve it. You should put that in a dictionary (``.match()`` will do this for you), and add that as ``matching_hints['hint'] = matchdict`` in the relevant part of :py:meth:`~sympy.solvers.ode.classify_ode`. :py:meth:`~sympy.solvers.ode.classify_ode` will then send this to :py:meth:`~sympy.solvers.ode.dsolve`, which will send it to your function as the ``match`` argument. Your function should be named ``ode_(eq, func, order, match)`. If you need to send more information, put it in the ``match`` dictionary. For example, if you had to substitute in a dummy variable in :py:meth:`~sympy.solvers.ode.classify_ode` to match the ODE, you will need to pass it to your function using the `match` dict to access it. You can access the independent variable using ``func.args[0]``, and the dependent variable (the function you are trying to solve for) as ``func.func``. If, while trying to solve the ODE, you find that you cannot, raise ``NotImplementedError``. :py:meth:`~sympy.solvers.ode.dsolve` will catch this error with the ``all`` meta-hint, rather than causing the whole routine to fail. Add a docstring to your function that describes the method employed. Like with anything else in SymPy, you will need to add a doctest to the docstring, in addition to real tests in ``test_ode.py``. Try to maintain consistency with the other hint functions' docstrings. Add your method to the list at the top of this docstring. Also, add your method to ``ode.rst`` in the ``docs/src`` directory, so that the Sphinx docs will pull its docstring into the main SymPy documentation. Be sure to make the Sphinx documentation by running ``make html`` from within the doc directory to verify that the docstring formats correctly. If your solution method involves integrating, use :py:obj:`~.Integral` instead of :py:meth:`~sympy.core.expr.Expr.integrate`. This allows the user to bypass hard/slow integration by using the ``_Integral`` variant of your hint. In most cases, calling :py:meth:`sympy.core.basic.Basic.doit` will integrate your solution. If this is not the case, you will need to write special code in :py:meth:`~sympy.solvers.ode.ode._handle_Integral`. Arbitrary constants should be symbols named ``C1``, ``C2``, and so on. All solution methods should return an equality instance. If you need an arbitrary number of arbitrary constants, you can use ``constants = numbered_symbols(prefix='C', cls=Symbol, start=1)``. If it is possible to solve for the dependent function in a general way, do so. Otherwise, do as best as you can, but do not call solve in your ``ode_()`` function. :py:meth:`~sympy.solvers.ode.ode.odesimp` will attempt to solve the solution for you, so you do not need to do that. Lastly, if your ODE has a common simplification that can be applied to your solutions, you can add a special case in :py:meth:`~sympy.solvers.ode.ode.odesimp` for it. For example, solutions returned from the ``1st_homogeneous_coeff`` hints often have many :obj:`~sympy.functions.elementary.exponential.log` terms, so :py:meth:`~sympy.solvers.ode.ode.odesimp` calls :py:meth:`~sympy.simplify.simplify.logcombine` on them (it also helps to write the arbitrary constant as ``log(C1)`` instead of ``C1`` in this case). Also consider common ways that you can rearrange your solution to have :py:meth:`~sympy.solvers.ode.constantsimp` take better advantage of it. It is better to put simplification in :py:meth:`~sympy.solvers.ode.ode.odesimp` than in your method, because it can then be turned off with the simplify flag in :py:meth:`~sympy.solvers.ode.dsolve`. If you have any extraneous simplification in your function, be sure to only run it using ``if match.get('simplify', True):``, especially if it can be slow or if it can reduce the domain of the solution. Finally, as with every contribution to SymPy, your method will need to be tested. Add a test for each method in ``test_ode.py``. Follow the conventions there, i.e., test the solver using ``dsolve(eq, f(x), hint=your_hint)``, and also test the solution using :py:meth:`~sympy.solvers.ode.checkodesol` (you can put these in a separate tests and skip/XFAIL if it runs too slow/doesn't work). Be sure to call your hint specifically in :py:meth:`~sympy.solvers.ode.dsolve`, that way the test won't be broken simply by the introduction of another matching hint. If your method works for higher order (>1) ODEs, you will need to run ``sol = constant_renumber(sol, 'C', 1, order)`` for each solution, where ``order`` is the order of the ODE. This is because ``constant_renumber`` renumbers the arbitrary constants by printing order, which is platform dependent. Try to test every corner case of your solver, including a range of orders if it is a `n`\th order solver, but if your solver is slow, such as if it involves hard integration, try to keep the test run time down. Feel free to refactor existing hints to avoid duplicating code or creating inconsistencies. If you can show that your method exactly duplicates an existing method, including in the simplicity and speed of obtaining the solutions, then you can remove the old, less general method. The existing code is tested extensively in ``test_ode.py``, so if anything is broken, one of those tests will surely fail. """ from sympy.core import Add, S, Mul, Pow, oo from sympy.core.compatibility import ordered, iterable from sympy.core.containers import Tuple from sympy.core.expr import AtomicExpr, Expr from sympy.core.function import (Function, Derivative, AppliedUndef, diff, expand, expand_mul, Subs) from sympy.core.multidimensional import vectorize from sympy.core.numbers import NaN, zoo, Number from sympy.core.relational import Equality, Eq from sympy.core.symbol import Symbol, Wild, Dummy, symbols from sympy.core.sympify import sympify from sympy.logic.boolalg import (BooleanAtom, BooleanTrue, BooleanFalse) from sympy.functions import exp, log, sqrt from sympy.functions.combinatorial.factorials import factorial from sympy.integrals.integrals import Integral from sympy.polys import (Poly, terms_gcd, PolynomialError, lcm) from sympy.polys.polytools import cancel from sympy.series import Order from sympy.series.series import series from sympy.simplify import (collect, logcombine, powsimp, # type: ignore separatevars, simplify, cse) from sympy.simplify.radsimp import collect_const from sympy.solvers import checksol, solve from sympy.utilities import numbered_symbols, default_sort_key, sift from sympy.utilities.iterables import uniq from sympy.solvers.deutils import _preprocess, ode_order, _desolve #: This is a list of hints in the order that they should be preferred by #: :py:meth:`~sympy.solvers.ode.classify_ode`. In general, hints earlier in the #: list should produce simpler solutions than those later in the list (for #: ODEs that fit both). For now, the order of this list is based on empirical #: observations by the developers of SymPy. #: #: The hint used by :py:meth:`~sympy.solvers.ode.dsolve` for a specific ODE #: can be overridden (see the docstring). #: #: In general, ``_Integral`` hints are grouped at the end of the list, unless #: there is a method that returns an unevaluable integral most of the time #: (which go near the end of the list anyway). ``default``, ``all``, #: ``best``, and ``all_Integral`` meta-hints should not be included in this #: list, but ``_best`` and ``_Integral`` hints should be included. allhints = ( "factorable", "nth_algebraic", "separable", "1st_exact", "1st_linear", "Bernoulli", "1st_rational_riccati", "Riccati_special_minus2", "1st_homogeneous_coeff_best", "1st_homogeneous_coeff_subs_indep_div_dep", "1st_homogeneous_coeff_subs_dep_div_indep", "almost_linear", "linear_coefficients", "separable_reduced", "1st_power_series", "lie_group", "nth_linear_constant_coeff_homogeneous", "nth_linear_euler_eq_homogeneous", "nth_linear_constant_coeff_undetermined_coefficients", "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients", "nth_linear_constant_coeff_variation_of_parameters", "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters", "Liouville", "2nd_linear_airy", "2nd_linear_bessel", "2nd_hypergeometric", "2nd_hypergeometric_Integral", "nth_order_reducible", "2nd_power_series_ordinary", "2nd_power_series_regular", "nth_algebraic_Integral", "separable_Integral", "1st_exact_Integral", "1st_linear_Integral", "Bernoulli_Integral", "1st_homogeneous_coeff_subs_indep_div_dep_Integral", "1st_homogeneous_coeff_subs_dep_div_indep_Integral", "almost_linear_Integral", "linear_coefficients_Integral", "separable_reduced_Integral", "nth_linear_constant_coeff_variation_of_parameters_Integral", "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters_Integral", "Liouville_Integral", "2nd_nonlinear_autonomous_conserved", "2nd_nonlinear_autonomous_conserved_Integral", ) def get_numbered_constants(eq, num=1, start=1, prefix='C'): """ Returns a list of constants that do not occur in eq already. """ ncs = iter_numbered_constants(eq, start, prefix) Cs = [next(ncs) for i in range(num)] return (Cs[0] if num == 1 else tuple(Cs)) def iter_numbered_constants(eq, start=1, prefix='C'): """ Returns an iterator of constants that do not occur in eq already. """ if isinstance(eq, (Expr, Eq)): eq = [eq] elif not iterable(eq): raise ValueError("Expected Expr or iterable but got %s" % eq) atom_set = set().union(*[i.free_symbols for i in eq]) func_set = set().union(*[i.atoms(Function) for i in eq]) if func_set: atom_set |= {Symbol(str(f.func)) for f in func_set} return numbered_symbols(start=start, prefix=prefix, exclude=atom_set) def dsolve(eq, func=None, hint="default", simplify=True, ics= None, xi=None, eta=None, x0=0, n=6, **kwargs): r""" Solves any (supported) kind of ordinary differential equation and system of ordinary differential equations. For single ordinary differential equation ========================================= It is classified under this when number of equation in ``eq`` is one. **Usage** ``dsolve(eq, f(x), hint)`` -> Solve ordinary differential equation ``eq`` for function ``f(x)``, using method ``hint``. **Details** ``eq`` can be any supported ordinary differential equation (see the :py:mod:`~sympy.solvers.ode` docstring for supported methods). This can either be an :py:class:`~sympy.core.relational.Equality`, or an expression, which is assumed to be equal to ``0``. ``f(x)`` is a function of one variable whose derivatives in that variable make up the ordinary differential equation ``eq``. In many cases it is not necessary to provide this; it will be autodetected (and an error raised if it couldn't be detected). ``hint`` is the solving method that you want dsolve to use. Use ``classify_ode(eq, f(x))`` to get all of the possible hints for an ODE. The default hint, ``default``, will use whatever hint is returned first by :py:meth:`~sympy.solvers.ode.classify_ode`. See Hints below for more options that you can use for hint. ``simplify`` enables simplification by :py:meth:`~sympy.solvers.ode.ode.odesimp`. See its docstring for more information. Turn this off, for example, to disable solving of solutions for ``func`` or simplification of arbitrary constants. It will still integrate with this hint. Note that the solution may contain more arbitrary constants than the order of the ODE with this option enabled. ``xi`` and ``eta`` are the infinitesimal functions of an ordinary differential equation. They are the infinitesimals of the Lie group of point transformations for which the differential equation is invariant. The user can specify values for the infinitesimals. If nothing is specified, ``xi`` and ``eta`` are calculated using :py:meth:`~sympy.solvers.ode.infinitesimals` with the help of various heuristics. ``ics`` is the set of initial/boundary conditions for the differential equation. It should be given in the form of ``{f(x0): x1, f(x).diff(x).subs(x, x2): x3}`` and so on. For power series solutions, if no initial conditions are specified ``f(0)`` is assumed to be ``C0`` and the power series solution is calculated about 0. ``x0`` is the point about which the power series solution of a differential equation is to be evaluated. ``n`` gives the exponent of the dependent variable up to which the power series solution of a differential equation is to be evaluated. **Hints** Aside from the various solving methods, there are also some meta-hints that you can pass to :py:meth:`~sympy.solvers.ode.dsolve`: ``default``: This uses whatever hint is returned first by :py:meth:`~sympy.solvers.ode.classify_ode`. This is the default argument to :py:meth:`~sympy.solvers.ode.dsolve`. ``all``: To make :py:meth:`~sympy.solvers.ode.dsolve` apply all relevant classification hints, use ``dsolve(ODE, func, hint="all")``. This will return a dictionary of ``hint:solution`` terms. If a hint causes dsolve to raise the ``NotImplementedError``, value of that hint's key will be the exception object raised. The dictionary will also include some special keys: - ``order``: The order of the ODE. See also :py:meth:`~sympy.solvers.deutils.ode_order` in ``deutils.py``. - ``best``: The simplest hint; what would be returned by ``best`` below. - ``best_hint``: The hint that would produce the solution given by ``best``. If more than one hint produces the best solution, the first one in the tuple returned by :py:meth:`~sympy.solvers.ode.classify_ode` is chosen. - ``default``: The solution that would be returned by default. This is the one produced by the hint that appears first in the tuple returned by :py:meth:`~sympy.solvers.ode.classify_ode`. ``all_Integral``: This is the same as ``all``, except if a hint also has a corresponding ``_Integral`` hint, it only returns the ``_Integral`` hint. This is useful if ``all`` causes :py:meth:`~sympy.solvers.ode.dsolve` to hang because of a difficult or impossible integral. This meta-hint will also be much faster than ``all``, because :py:meth:`~sympy.core.expr.Expr.integrate` is an expensive routine. ``best``: To have :py:meth:`~sympy.solvers.ode.dsolve` try all methods and return the simplest one. This takes into account whether the solution is solvable in the function, whether it contains any Integral classes (i.e. unevaluatable integrals), and which one is the shortest in size. See also the :py:meth:`~sympy.solvers.ode.classify_ode` docstring for more info on hints, and the :py:mod:`~sympy.solvers.ode` docstring for a list of all supported hints. **Tips** - You can declare the derivative of an unknown function this way: >>> from sympy import Function, Derivative >>> from sympy.abc import x # x is the independent variable >>> f = Function("f")(x) # f is a function of x >>> # f_ will be the derivative of f with respect to x >>> f_ = Derivative(f, x) - See ``test_ode.py`` for many tests, which serves also as a set of examples for how to use :py:meth:`~sympy.solvers.ode.dsolve`. - :py:meth:`~sympy.solvers.ode.dsolve` always returns an :py:class:`~sympy.core.relational.Equality` class (except for the case when the hint is ``all`` or ``all_Integral``). If possible, it solves the solution explicitly for the function being solved for. Otherwise, it returns an implicit solution. - Arbitrary constants are symbols named ``C1``, ``C2``, and so on. - Because all solutions should be mathematically equivalent, some hints may return the exact same result for an ODE. Often, though, two different hints will return the same solution formatted differently. The two should be equivalent. Also note that sometimes the values of the arbitrary constants in two different solutions may not be the same, because one constant may have "absorbed" other constants into it. - Do ``help(ode.ode_)`` to get help more information on a specific hint, where ```` is the name of a hint without ``_Integral``. For system of ordinary differential equations ============================================= **Usage** ``dsolve(eq, func)`` -> Solve a system of ordinary differential equations ``eq`` for ``func`` being list of functions including `x(t)`, `y(t)`, `z(t)` where number of functions in the list depends upon the number of equations provided in ``eq``. **Details** ``eq`` can be any supported system of ordinary differential equations This can either be an :py:class:`~sympy.core.relational.Equality`, or an expression, which is assumed to be equal to ``0``. ``func`` holds ``x(t)`` and ``y(t)`` being functions of one variable which together with some of their derivatives make up the system of ordinary differential equation ``eq``. It is not necessary to provide this; it will be autodetected (and an error raised if it couldn't be detected). **Hints** The hints are formed by parameters returned by classify_sysode, combining them give hints name used later for forming method name. Examples ======== >>> from sympy import Function, dsolve, Eq, Derivative, sin, cos, symbols >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(Derivative(f(x), x, x) + 9*f(x), f(x)) Eq(f(x), C1*sin(3*x) + C2*cos(3*x)) >>> eq = sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x) >>> dsolve(eq, hint='1st_exact') [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))] >>> dsolve(eq, hint='almost_linear') [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))] >>> t = symbols('t') >>> x, y = symbols('x, y', cls=Function) >>> eq = (Eq(Derivative(x(t),t), 12*t*x(t) + 8*y(t)), Eq(Derivative(y(t),t), 21*x(t) + 7*t*y(t))) >>> dsolve(eq) [Eq(x(t), C1*x0(t) + C2*x0(t)*Integral(8*exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)**2, t)), Eq(y(t), C1*y0(t) + C2*(y0(t)*Integral(8*exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)**2, t) + exp(Integral(7*t, t))*exp(Integral(12*t, t))/x0(t)))] >>> eq = (Eq(Derivative(x(t),t),x(t)*y(t)*sin(t)), Eq(Derivative(y(t),t),y(t)**2*sin(t))) >>> dsolve(eq) {Eq(x(t), -exp(C1)/(C2*exp(C1) - cos(t))), Eq(y(t), -1/(C1 - cos(t)))} """ if iterable(eq): from sympy.solvers.ode.systems import dsolve_system # This may have to be changed in future # when we have weakly and strongly # connected components. This have to # changed to show the systems that haven't # been solved. try: sol = dsolve_system(eq, funcs=func, ics=ics, doit=True) return sol[0] if len(sol) == 1 else sol except NotImplementedError: pass match = classify_sysode(eq, func) eq = match['eq'] order = match['order'] func = match['func'] t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] # keep highest order term coefficient positive for i in range(len(eq)): for func_ in func: if isinstance(func_, list): pass else: if eq[i].coeff(diff(func[i],t,ode_order(eq[i], func[i]))).is_negative: eq[i] = -eq[i] match['eq'] = eq if len(set(order.values()))!=1: raise ValueError("It solves only those systems of equations whose orders are equal") match['order'] = list(order.values())[0] def recur_len(l): return sum(recur_len(item) if isinstance(item,list) else 1 for item in l) if recur_len(func) != len(eq): raise ValueError("dsolve() and classify_sysode() work with " "number of functions being equal to number of equations") if match['type_of_equation'] is None: raise NotImplementedError else: if match['is_linear'] == True: solvefunc = globals()['sysode_linear_%(no_of_equation)seq_order%(order)s' % match] else: solvefunc = globals()['sysode_nonlinear_%(no_of_equation)seq_order%(order)s' % match] sols = solvefunc(match) if ics: constants = Tuple(*sols).free_symbols - Tuple(*eq).free_symbols solved_constants = solve_ics(sols, func, constants, ics) return [sol.subs(solved_constants) for sol in sols] return sols else: given_hint = hint # hint given by the user # See the docstring of _desolve for more details. hints = _desolve(eq, func=func, hint=hint, simplify=True, xi=xi, eta=eta, type='ode', ics=ics, x0=x0, n=n, **kwargs) eq = hints.pop('eq', eq) all_ = hints.pop('all', False) if all_: retdict = {} failed_hints = {} gethints = classify_ode(eq, dict=True, hint='all') orderedhints = gethints['ordered_hints'] for hint in hints: try: rv = _helper_simplify(eq, hint, hints[hint], simplify) except NotImplementedError as detail: failed_hints[hint] = detail else: retdict[hint] = rv func = hints[hint]['func'] retdict['best'] = min(list(retdict.values()), key=lambda x: ode_sol_simplicity(x, func, trysolving=not simplify)) if given_hint == 'best': return retdict['best'] for i in orderedhints: if retdict['best'] == retdict.get(i, None): retdict['best_hint'] = i break retdict['default'] = gethints['default'] retdict['order'] = gethints['order'] retdict.update(failed_hints) return retdict else: # The key 'hint' stores the hint needed to be solved for. hint = hints['hint'] return _helper_simplify(eq, hint, hints, simplify, ics=ics) def _helper_simplify(eq, hint, match, simplify=True, ics=None, **kwargs): r""" Helper function of dsolve that calls the respective :py:mod:`~sympy.solvers.ode` functions to solve for the ordinary differential equations. This minimizes the computation in calling :py:meth:`~sympy.solvers.deutils._desolve` multiple times. """ r = match func = r['func'] order = r['order'] match = r[hint] if isinstance(match, SingleODESolver): solvefunc = match elif hint.endswith('_Integral'): solvefunc = globals()['ode_' + hint[:-len('_Integral')]] else: solvefunc = globals()['ode_' + hint] free = eq.free_symbols cons = lambda s: s.free_symbols.difference(free) if simplify: # odesimp() will attempt to integrate, if necessary, apply constantsimp(), # attempt to solve for func, and apply any other hint specific # simplifications if isinstance(solvefunc, SingleODESolver): sols = solvefunc.get_general_solution() else: sols = solvefunc(eq, func, order, match) if iterable(sols): rv = [odesimp(eq, s, func, hint) for s in sols] else: rv = odesimp(eq, sols, func, hint) else: # We still want to integrate (you can disable it separately with the hint) if isinstance(solvefunc, SingleODESolver): exprs = solvefunc.get_general_solution(simplify=False) else: match['simplify'] = False # Some hints can take advantage of this option exprs = solvefunc(eq, func, order, match) if isinstance(exprs, list): rv = [_handle_Integral(expr, func, hint) for expr in exprs] else: rv = _handle_Integral(exprs, func, hint) if isinstance(rv, list): if simplify: rv = _remove_redundant_solutions(eq, rv, order, func.args[0]) if len(rv) == 1: rv = rv[0] if ics and not 'power_series' in hint: if isinstance(rv, (Expr, Eq)): solved_constants = solve_ics([rv], [r['func']], cons(rv), ics) rv = rv.subs(solved_constants) else: rv1 = [] for s in rv: try: solved_constants = solve_ics([s], [r['func']], cons(s), ics) except ValueError: continue rv1.append(s.subs(solved_constants)) if len(rv1) == 1: return rv1[0] rv = rv1 return rv def solve_ics(sols, funcs, constants, ics): """ Solve for the constants given initial conditions ``sols`` is a list of solutions. ``funcs`` is a list of functions. ``constants`` is a list of constants. ``ics`` is the set of initial/boundary conditions for the differential equation. It should be given in the form of ``{f(x0): x1, f(x).diff(x).subs(x, x2): x3}`` and so on. Returns a dictionary mapping constants to values. ``solution.subs(constants)`` will replace the constants in ``solution``. Example ======= >>> # From dsolve(f(x).diff(x) - f(x), f(x)) >>> from sympy import symbols, Eq, exp, Function >>> from sympy.solvers.ode.ode import solve_ics >>> f = Function('f') >>> x, C1 = symbols('x C1') >>> sols = [Eq(f(x), C1*exp(x))] >>> funcs = [f(x)] >>> constants = [C1] >>> ics = {f(0): 2} >>> solved_constants = solve_ics(sols, funcs, constants, ics) >>> solved_constants {C1: 2} >>> sols[0].subs(solved_constants) Eq(f(x), 2*exp(x)) """ # Assume ics are of the form f(x0): value or Subs(diff(f(x), x, n), (x, # x0)): value (currently checked by classify_ode). To solve, replace x # with x0, f(x0) with value, then solve for constants. For f^(n)(x0), # differentiate the solution n times, so that f^(n)(x) appears. x = funcs[0].args[0] diff_sols = [] subs_sols = [] diff_variables = set() for funcarg, value in ics.items(): if isinstance(funcarg, AppliedUndef): x0 = funcarg.args[0] matching_func = [f for f in funcs if f.func == funcarg.func][0] S = sols elif isinstance(funcarg, (Subs, Derivative)): if isinstance(funcarg, Subs): # Make sure it stays a subs. Otherwise subs below will produce # a different looking term. funcarg = funcarg.doit() if isinstance(funcarg, Subs): deriv = funcarg.expr x0 = funcarg.point[0] variables = funcarg.expr.variables matching_func = deriv elif isinstance(funcarg, Derivative): deriv = funcarg x0 = funcarg.variables[0] variables = (x,)*len(funcarg.variables) matching_func = deriv.subs(x0, x) if variables not in diff_variables: for sol in sols: if sol.has(deriv.expr.func): diff_sols.append(Eq(sol.lhs.diff(*variables), sol.rhs.diff(*variables))) diff_variables.add(variables) S = diff_sols else: raise NotImplementedError("Unrecognized initial condition") for sol in S: if sol.has(matching_func): sol2 = sol sol2 = sol2.subs(x, x0) sol2 = sol2.subs(funcarg, value) # This check is necessary because of issue #15724 if not isinstance(sol2, BooleanAtom) or not subs_sols: subs_sols = [s for s in subs_sols if not isinstance(s, BooleanAtom)] subs_sols.append(sol2) # TODO: Use solveset here try: solved_constants = solve(subs_sols, constants, dict=True) except NotImplementedError: solved_constants = [] # XXX: We can't differentiate between the solution not existing because of # invalid initial conditions, and not existing because solve is not smart # enough. If we could use solveset, this might be improvable, but for now, # we use NotImplementedError in this case. if not solved_constants: raise ValueError("Couldn't solve for initial conditions") if solved_constants == True: raise ValueError("Initial conditions did not produce any solutions for constants. Perhaps they are degenerate.") if len(solved_constants) > 1: raise NotImplementedError("Initial conditions produced too many solutions for constants") return solved_constants[0] def classify_ode(eq, func=None, dict=False, ics=None, *, prep=True, xi=None, eta=None, n=None, **kwargs): r""" Returns a tuple of possible :py:meth:`~sympy.solvers.ode.dsolve` classifications for an ODE. The tuple is ordered so that first item is the classification that :py:meth:`~sympy.solvers.ode.dsolve` uses to solve the ODE by default. In general, classifications at the near the beginning of the list will produce better solutions faster than those near the end, thought there are always exceptions. To make :py:meth:`~sympy.solvers.ode.dsolve` use a different classification, use ``dsolve(ODE, func, hint=)``. See also the :py:meth:`~sympy.solvers.ode.dsolve` docstring for different meta-hints you can use. If ``dict`` is true, :py:meth:`~sympy.solvers.ode.classify_ode` will return a dictionary of ``hint:match`` expression terms. This is intended for internal use by :py:meth:`~sympy.solvers.ode.dsolve`. Note that because dictionaries are ordered arbitrarily, this will most likely not be in the same order as the tuple. You can get help on different hints by executing ``help(ode.ode_hintname)``, where ``hintname`` is the name of the hint without ``_Integral``. See :py:data:`~sympy.solvers.ode.allhints` or the :py:mod:`~sympy.solvers.ode` docstring for a list of all supported hints that can be returned from :py:meth:`~sympy.solvers.ode.classify_ode`. Notes ===== These are remarks on hint names. ``_Integral`` If a classification has ``_Integral`` at the end, it will return the expression with an unevaluated :py:class:`~.Integral` class in it. Note that a hint may do this anyway if :py:meth:`~sympy.core.expr.Expr.integrate` cannot do the integral, though just using an ``_Integral`` will do so much faster. Indeed, an ``_Integral`` hint will always be faster than its corresponding hint without ``_Integral`` because :py:meth:`~sympy.core.expr.Expr.integrate` is an expensive routine. If :py:meth:`~sympy.solvers.ode.dsolve` hangs, it is probably because :py:meth:`~sympy.core.expr.Expr.integrate` is hanging on a tough or impossible integral. Try using an ``_Integral`` hint or ``all_Integral`` to get it return something. Note that some hints do not have ``_Integral`` counterparts. This is because :py:func:`~sympy.integrals.integrals.integrate` is not used in solving the ODE for those method. For example, `n`\th order linear homogeneous ODEs with constant coefficients do not require integration to solve, so there is no ``nth_linear_homogeneous_constant_coeff_Integrate`` hint. You can easily evaluate any unevaluated :py:class:`~sympy.integrals.integrals.Integral`\s in an expression by doing ``expr.doit()``. Ordinals Some hints contain an ordinal such as ``1st_linear``. This is to help differentiate them from other hints, as well as from other methods that may not be implemented yet. If a hint has ``nth`` in it, such as the ``nth_linear`` hints, this means that the method used to applies to ODEs of any order. ``indep`` and ``dep`` Some hints contain the words ``indep`` or ``dep``. These reference the independent variable and the dependent function, respectively. For example, if an ODE is in terms of `f(x)`, then ``indep`` will refer to `x` and ``dep`` will refer to `f`. ``subs`` If a hints has the word ``subs`` in it, it means the the ODE is solved by substituting the expression given after the word ``subs`` for a single dummy variable. This is usually in terms of ``indep`` and ``dep`` as above. The substituted expression will be written only in characters allowed for names of Python objects, meaning operators will be spelled out. For example, ``indep``/``dep`` will be written as ``indep_div_dep``. ``coeff`` The word ``coeff`` in a hint refers to the coefficients of something in the ODE, usually of the derivative terms. See the docstring for the individual methods for more info (``help(ode)``). This is contrast to ``coefficients``, as in ``undetermined_coefficients``, which refers to the common name of a method. ``_best`` Methods that have more than one fundamental way to solve will have a hint for each sub-method and a ``_best`` meta-classification. This will evaluate all hints and return the best, using the same considerations as the normal ``best`` meta-hint. Examples ======== >>> from sympy import Function, classify_ode, Eq >>> from sympy.abc import x >>> f = Function('f') >>> classify_ode(Eq(f(x).diff(x), 0), f(x)) ('nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_homogeneous', 'nth_linear_euler_eq_homogeneous', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral') >>> classify_ode(f(x).diff(x, 2) + 3*f(x).diff(x) + 2*f(x) - 4) ('nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', 'nth_linear_constant_coeff_variation_of_parameters_Integral') """ ics = sympify(ics) if func and len(func.args) != 1: raise ValueError("dsolve() and classify_ode() only " "work with functions of one variable, not %s" % func) if isinstance(eq, Equality): eq = eq.lhs - eq.rhs # Some methods want the unprocessed equation eq_orig = eq if prep or func is None: eq, func_ = _preprocess(eq, func) if func is None: func = func_ x = func.args[0] f = func.func y = Dummy('y') terms = n order = ode_order(eq, f(x)) # hint:matchdict or hint:(tuple of matchdicts) # Also will contain "default": and "order":order items. matching_hints = {"order": order} df = f(x).diff(x) a = Wild('a', exclude=[f(x)]) d = Wild('d', exclude=[df, f(x).diff(x, 2)]) e = Wild('e', exclude=[df]) n = Wild('n', exclude=[x, f(x), df]) c1 = Wild('c1', exclude=[x]) a3 = Wild('a3', exclude=[f(x), df, f(x).diff(x, 2)]) b3 = Wild('b3', exclude=[f(x), df, f(x).diff(x, 2)]) c3 = Wild('c3', exclude=[f(x), df, f(x).diff(x, 2)]) boundary = {} # Used to extract initial conditions C1 = Symbol("C1") # Preprocessing to get the initial conditions out if ics is not None: for funcarg in ics: # Separating derivatives if isinstance(funcarg, (Subs, Derivative)): # f(x).diff(x).subs(x, 0) is a Subs, but f(x).diff(x).subs(x, # y) is a Derivative if isinstance(funcarg, Subs): deriv = funcarg.expr old = funcarg.variables[0] new = funcarg.point[0] elif isinstance(funcarg, Derivative): deriv = funcarg # No information on this. Just assume it was x old = x new = funcarg.variables[0] if (isinstance(deriv, Derivative) and isinstance(deriv.args[0], AppliedUndef) and deriv.args[0].func == f and len(deriv.args[0].args) == 1 and old == x and not new.has(x) and all(i == deriv.variables[0] for i in deriv.variables) and not ics[funcarg].has(f)): dorder = ode_order(deriv, x) temp = 'f' + str(dorder) boundary.update({temp: new, temp + 'val': ics[funcarg]}) else: raise ValueError("Enter valid boundary conditions for Derivatives") # Separating functions elif isinstance(funcarg, AppliedUndef): if (funcarg.func == f and len(funcarg.args) == 1 and not funcarg.args[0].has(x) and not ics[funcarg].has(f)): boundary.update({'f0': funcarg.args[0], 'f0val': ics[funcarg]}) else: raise ValueError("Enter valid boundary conditions for Function") else: raise ValueError("Enter boundary conditions of the form ics={f(point): value, f(x).diff(x, order).subs(x, point): value}") ode = SingleODEProblem(eq_orig, func, x, prep=prep, xi=xi, eta=eta) user_hint = kwargs.get('hint', 'default') # Used when dsolve is called without an explicit hint. # We exit early to return the first valid match early_exit = (user_hint=='default') if user_hint.endswith('_Integral'): user_hint = user_hint[:-len('_Integral')] user_map = solver_map # An explicit hint has been given to dsolve # Skip matching code for other hints if user_hint not in ['default', 'all', 'all_Integral', 'best'] and user_hint in solver_map: user_map = {user_hint: solver_map[user_hint]} for hint in user_map: solver = user_map[hint](ode) if solver.matches(): matching_hints[hint] = solver if user_map[hint].has_integral: matching_hints[hint + "_Integral"] = solver if dict and early_exit: matching_hints["default"] = hint return matching_hints eq = expand(eq) # Precondition to try remove f(x) from highest order derivative reduced_eq = None if eq.is_Add: deriv_coef = eq.coeff(f(x).diff(x, order)) if deriv_coef not in (1, 0): r = deriv_coef.match(a*f(x)**c1) if r and r[c1]: den = f(x)**r[c1] reduced_eq = Add(*[arg/den for arg in eq.args]) if not reduced_eq: reduced_eq = eq if order == 1: # NON-REDUCED FORM OF EQUATION matches r = collect(eq, df, exact=True).match(d + e * df) if r: r['d'] = d r['e'] = e r['y'] = y r[d] = r[d].subs(f(x), y) r[e] = r[e].subs(f(x), y) # FIRST ORDER POWER SERIES WHICH NEEDS INITIAL CONDITIONS # TODO: Hint first order series should match only if d/e is analytic. # For now, only d/e and (d/e).diff(arg) is checked for existence at # at a given point. # This is currently done internally in ode_1st_power_series. point = boundary.get('f0', 0) value = boundary.get('f0val', C1) check = cancel(r[d]/r[e]) check1 = check.subs({x: point, y: value}) if not check1.has(oo) and not check1.has(zoo) and \ not check1.has(NaN) and not check1.has(-oo): check2 = (check1.diff(x)).subs({x: point, y: value}) if not check2.has(oo) and not check2.has(zoo) and \ not check2.has(NaN) and not check2.has(-oo): rseries = r.copy() rseries.update({'terms': terms, 'f0': point, 'f0val': value}) matching_hints["1st_power_series"] = rseries elif order == 2: # Homogeneous second order differential equation of the form # a3*f(x).diff(x, 2) + b3*f(x).diff(x) + c3 # It has a definite power series solution at point x0 if, b3/a3 and c3/a3 # are analytic at x0. deq = a3*(f(x).diff(x, 2)) + b3*df + c3*f(x) r = collect(reduced_eq, [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) ordinary = False if r: if not all([r[key].is_polynomial() for key in r]): n, d = reduced_eq.as_numer_denom() reduced_eq = expand(n) r = collect(reduced_eq, [f(x).diff(x, 2), f(x).diff(x), f(x)]).match(deq) if r and r[a3] != 0: p = cancel(r[b3]/r[a3]) # Used below q = cancel(r[c3]/r[a3]) # Used below point = kwargs.get('x0', 0) check = p.subs(x, point) if not check.has(oo, NaN, zoo, -oo): check = q.subs(x, point) if not check.has(oo, NaN, zoo, -oo): ordinary = True r.update({'a3': a3, 'b3': b3, 'c3': c3, 'x0': point, 'terms': terms}) matching_hints["2nd_power_series_ordinary"] = r # Checking if the differential equation has a regular singular point # at x0. It has a regular singular point at x0, if (b3/a3)*(x - x0) # and (c3/a3)*((x - x0)**2) are analytic at x0. if not ordinary: p = cancel((x - point)*p) check = p.subs(x, point) if not check.has(oo, NaN, zoo, -oo): q = cancel(((x - point)**2)*q) check = q.subs(x, point) if not check.has(oo, NaN, zoo, -oo): coeff_dict = {'p': p, 'q': q, 'x0': point, 'terms': terms} matching_hints["2nd_power_series_regular"] = coeff_dict # Order keys based on allhints. retlist = [i for i in allhints if i in matching_hints] if dict: # Dictionaries are ordered arbitrarily, so make note of which # hint would come first for dsolve(). Use an ordered dict in Py 3. matching_hints["default"] = retlist[0] if retlist else None matching_hints["ordered_hints"] = tuple(retlist) return matching_hints else: return tuple(retlist) def classify_sysode(eq, funcs=None, **kwargs): r""" Returns a dictionary of parameter names and values that define the system of ordinary differential equations in ``eq``. The parameters are further used in :py:meth:`~sympy.solvers.ode.dsolve` for solving that system. Some parameter names and values are: 'is_linear' (boolean), which tells whether the given system is linear. Note that "linear" here refers to the operator: terms such as ``x*diff(x,t)`` are nonlinear, whereas terms like ``sin(t)*diff(x,t)`` are still linear operators. 'func' (list) contains the :py:class:`~sympy.core.function.Function`s that appear with a derivative in the ODE, i.e. those that we are trying to solve the ODE for. 'order' (dict) with the maximum derivative for each element of the 'func' parameter. 'func_coeff' (dict or Matrix) with the coefficient for each triple ``(equation number, function, order)```. The coefficients are those subexpressions that do not appear in 'func', and hence can be considered constant for purposes of ODE solving. The value of this parameter can also be a Matrix if the system of ODEs are linear first order of the form X' = AX where X is the vector of dependent variables. Here, this function returns the coefficient matrix A. 'eq' (list) with the equations from ``eq``, sympified and transformed into expressions (we are solving for these expressions to be zero). 'no_of_equations' (int) is the number of equations (same as ``len(eq)``). 'type_of_equation' (string) is an internal classification of the type of ODE. 'is_constant' (boolean), which tells if the system of ODEs is constant coefficient or not. This key is temporary addition for now and is in the match dict only when the system of ODEs is linear first order constant coefficient homogeneous. So, this key's value is True for now if it is available else it doesn't exist. 'is_homogeneous' (boolean), which tells if the system of ODEs is homogeneous. Like the key 'is_constant', this key is a temporary addition and it is True since this key value is available only when the system is linear first order constant coefficient homogeneous. References ========== -http://eqworld.ipmnet.ru/en/solutions/sysode/sode-toc1.htm -A. D. Polyanin and A. V. Manzhirov, Handbook of Mathematics for Engineers and Scientists Examples ======== >>> from sympy import Function, Eq, symbols, diff >>> from sympy.solvers.ode.ode import classify_sysode >>> from sympy.abc import t >>> f, x, y = symbols('f, x, y', cls=Function) >>> k, l, m, n = symbols('k, l, m, n', Integer=True) >>> x1 = diff(x(t), t) ; y1 = diff(y(t), t) >>> x2 = diff(x(t), t, t) ; y2 = diff(y(t), t, t) >>> eq = (Eq(x1, 12*x(t) - 6*y(t)), Eq(y1, 11*x(t) + 3*y(t))) >>> classify_sysode(eq) {'eq': [-12*x(t) + 6*y(t) + Derivative(x(t), t), -11*x(t) - 3*y(t) + Derivative(y(t), t)], 'func': [x(t), y(t)], 'func_coeff': {(0, x(t), 0): -12, (0, x(t), 1): 1, (0, y(t), 0): 6, (0, y(t), 1): 0, (1, x(t), 0): -11, (1, x(t), 1): 0, (1, y(t), 0): -3, (1, y(t), 1): 1}, 'is_linear': True, 'no_of_equation': 2, 'order': {x(t): 1, y(t): 1}, 'type_of_equation': None} >>> eq = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t) + 2), Eq(diff(y(t),t), -t**2*x(t) + 5*t*y(t))) >>> classify_sysode(eq) {'eq': [-t**2*y(t) - 5*t*x(t) + Derivative(x(t), t) - 2, t**2*x(t) - 5*t*y(t) + Derivative(y(t), t)], 'func': [x(t), y(t)], 'func_coeff': {(0, x(t), 0): -5*t, (0, x(t), 1): 1, (0, y(t), 0): -t**2, (0, y(t), 1): 0, (1, x(t), 0): t**2, (1, x(t), 1): 0, (1, y(t), 0): -5*t, (1, y(t), 1): 1}, 'is_linear': True, 'no_of_equation': 2, 'order': {x(t): 1, y(t): 1}, 'type_of_equation': None} """ # Sympify equations and convert iterables of equations into # a list of equations def _sympify(eq): return list(map(sympify, eq if iterable(eq) else [eq])) eq, funcs = (_sympify(w) for w in [eq, funcs]) for i, fi in enumerate(eq): if isinstance(fi, Equality): eq[i] = fi.lhs - fi.rhs t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] matching_hints = {"no_of_equation":i+1} matching_hints['eq'] = eq if i==0: raise ValueError("classify_sysode() works for systems of ODEs. " "For scalar ODEs, classify_ode should be used") # find all the functions if not given order = dict() if funcs==[None]: funcs = _extract_funcs(eq) funcs = list(set(funcs)) if len(funcs) != len(eq): raise ValueError("Number of functions given is not equal to the number of equations %s" % funcs) # This logic of list of lists in funcs to # be replaced later. func_dict = dict() for func in funcs: if not order.get(func, False): max_order = 0 for i, eqs_ in enumerate(eq): order_ = ode_order(eqs_,func) if max_order < order_: max_order = order_ eq_no = i if eq_no in func_dict: func_dict[eq_no] = [func_dict[eq_no], func] else: func_dict[eq_no] = func order[func] = max_order funcs = [func_dict[i] for i in range(len(func_dict))] matching_hints['func'] = funcs for func in funcs: if isinstance(func, list): for func_elem in func: if len(func_elem.args) != 1: raise ValueError("dsolve() and classify_sysode() work with " "functions of one variable only, not %s" % func) else: if func and len(func.args) != 1: raise ValueError("dsolve() and classify_sysode() work with " "functions of one variable only, not %s" % func) # find the order of all equation in system of odes matching_hints["order"] = order # find coefficients of terms f(t), diff(f(t),t) and higher derivatives # and similarly for other functions g(t), diff(g(t),t) in all equations. # Here j denotes the equation number, funcs[l] denotes the function about # which we are talking about and k denotes the order of function funcs[l] # whose coefficient we are calculating. def linearity_check(eqs, j, func, is_linear_): for k in range(order[func] + 1): func_coef[j, func, k] = collect(eqs.expand(), [diff(func, t, k)]).coeff(diff(func, t, k)) if is_linear_ == True: if func_coef[j, func, k] == 0: if k == 0: coef = eqs.as_independent(func, as_Add=True)[1] for xr in range(1, ode_order(eqs,func) + 1): coef -= eqs.as_independent(diff(func, t, xr), as_Add=True)[1] if coef != 0: is_linear_ = False else: if eqs.as_independent(diff(func, t, k), as_Add=True)[1]: is_linear_ = False else: for func_ in funcs: if isinstance(func_, list): for elem_func_ in func_: dep = func_coef[j, func, k].as_independent(elem_func_, as_Add=True)[1] if dep != 0: is_linear_ = False else: dep = func_coef[j, func, k].as_independent(func_, as_Add=True)[1] if dep != 0: is_linear_ = False return is_linear_ func_coef = {} is_linear = True for j, eqs in enumerate(eq): for func in funcs: if isinstance(func, list): for func_elem in func: is_linear = linearity_check(eqs, j, func_elem, is_linear) else: is_linear = linearity_check(eqs, j, func, is_linear) matching_hints['func_coeff'] = func_coef matching_hints['is_linear'] = is_linear if len(set(order.values())) == 1: order_eq = list(matching_hints['order'].values())[0] if matching_hints['is_linear'] == True: if matching_hints['no_of_equation'] == 2: if order_eq == 1: type_of_equation = check_linear_2eq_order1(eq, funcs, func_coef) else: type_of_equation = None # If the equation doesn't match up with any of the # general case solvers in systems.py and the number # of equations is greater than 2, then NotImplementedError # should be raised. else: type_of_equation = None else: if matching_hints['no_of_equation'] == 2: if order_eq == 1: type_of_equation = check_nonlinear_2eq_order1(eq, funcs, func_coef) else: type_of_equation = None elif matching_hints['no_of_equation'] == 3: if order_eq == 1: type_of_equation = check_nonlinear_3eq_order1(eq, funcs, func_coef) else: type_of_equation = None else: type_of_equation = None else: type_of_equation = None matching_hints['type_of_equation'] = type_of_equation return matching_hints def check_linear_2eq_order1(eq, func, func_coef): x = func[0].func y = func[1].func fc = func_coef t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] r = dict() # for equations Eq(a1*diff(x(t),t), b1*x(t) + c1*y(t) + d1) # and Eq(a2*diff(y(t),t), b2*x(t) + c2*y(t) + d2) r['a1'] = fc[0,x(t),1] ; r['a2'] = fc[1,y(t),1] r['b1'] = -fc[0,x(t),0]/fc[0,x(t),1] ; r['b2'] = -fc[1,x(t),0]/fc[1,y(t),1] r['c1'] = -fc[0,y(t),0]/fc[0,x(t),1] ; r['c2'] = -fc[1,y(t),0]/fc[1,y(t),1] forcing = [S.Zero,S.Zero] for i in range(2): for j in Add.make_args(eq[i]): if not j.has(x(t), y(t)): forcing[i] += j if not (forcing[0].has(t) or forcing[1].has(t)): # We can handle homogeneous case and simple constant forcings r['d1'] = forcing[0] r['d2'] = forcing[1] else: # Issue #9244: nonhomogeneous linear systems are not supported return None # Conditions to check for type 6 whose equations are Eq(diff(x(t),t), f(t)*x(t) + g(t)*y(t)) and # Eq(diff(y(t),t), a*[f(t) + a*h(t)]x(t) + a*[g(t) - h(t)]*y(t)) p = 0 q = 0 p1 = cancel(r['b2']/(cancel(r['b2']/r['c2']).as_numer_denom()[0])) p2 = cancel(r['b1']/(cancel(r['b1']/r['c1']).as_numer_denom()[0])) for n, i in enumerate([p1, p2]): for j in Mul.make_args(collect_const(i)): if not j.has(t): q = j if q and n==0: if ((r['b2']/j - r['b1'])/(r['c1'] - r['c2']/j)) == j: p = 1 elif q and n==1: if ((r['b1']/j - r['b2'])/(r['c2'] - r['c1']/j)) == j: p = 2 # End of condition for type 6 if r['d1']!=0 or r['d2']!=0: return None else: if all(not r[k].has(t) for k in 'a1 a2 b1 b2 c1 c2'.split()): return None else: r['b1'] = r['b1']/r['a1'] ; r['b2'] = r['b2']/r['a2'] r['c1'] = r['c1']/r['a1'] ; r['c2'] = r['c2']/r['a2'] if p: return "type6" else: # Equations for type 7 are Eq(diff(x(t),t), f(t)*x(t) + g(t)*y(t)) and Eq(diff(y(t),t), h(t)*x(t) + p(t)*y(t)) return "type7" def check_nonlinear_2eq_order1(eq, func, func_coef): t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] f = Wild('f') g = Wild('g') u, v = symbols('u, v', cls=Dummy) def check_type(x, y): r1 = eq[0].match(t*diff(x(t),t) - x(t) + f) r2 = eq[1].match(t*diff(y(t),t) - y(t) + g) if not (r1 and r2): r1 = eq[0].match(diff(x(t),t) - x(t)/t + f/t) r2 = eq[1].match(diff(y(t),t) - y(t)/t + g/t) if not (r1 and r2): r1 = (-eq[0]).match(t*diff(x(t),t) - x(t) + f) r2 = (-eq[1]).match(t*diff(y(t),t) - y(t) + g) if not (r1 and r2): r1 = (-eq[0]).match(diff(x(t),t) - x(t)/t + f/t) r2 = (-eq[1]).match(diff(y(t),t) - y(t)/t + g/t) if r1 and r2 and not (r1[f].subs(diff(x(t),t),u).subs(diff(y(t),t),v).has(t) \ or r2[g].subs(diff(x(t),t),u).subs(diff(y(t),t),v).has(t)): return 'type5' else: return None for func_ in func: if isinstance(func_, list): x = func[0][0].func y = func[0][1].func eq_type = check_type(x, y) if not eq_type: eq_type = check_type(y, x) return eq_type x = func[0].func y = func[1].func fc = func_coef n = Wild('n', exclude=[x(t),y(t)]) f1 = Wild('f1', exclude=[v,t]) f2 = Wild('f2', exclude=[v,t]) g1 = Wild('g1', exclude=[u,t]) g2 = Wild('g2', exclude=[u,t]) for i in range(2): eqs = 0 for terms in Add.make_args(eq[i]): eqs += terms/fc[i,func[i],1] eq[i] = eqs r = eq[0].match(diff(x(t),t) - x(t)**n*f) if r: g = (diff(y(t),t) - eq[1])/r[f] if r and not (g.has(x(t)) or g.subs(y(t),v).has(t) or r[f].subs(x(t),u).subs(y(t),v).has(t)): return 'type1' r = eq[0].match(diff(x(t),t) - exp(n*x(t))*f) if r: g = (diff(y(t),t) - eq[1])/r[f] if r and not (g.has(x(t)) or g.subs(y(t),v).has(t) or r[f].subs(x(t),u).subs(y(t),v).has(t)): return 'type2' g = Wild('g') r1 = eq[0].match(diff(x(t),t) - f) r2 = eq[1].match(diff(y(t),t) - g) if r1 and r2 and not (r1[f].subs(x(t),u).subs(y(t),v).has(t) or \ r2[g].subs(x(t),u).subs(y(t),v).has(t)): return 'type3' r1 = eq[0].match(diff(x(t),t) - f) r2 = eq[1].match(diff(y(t),t) - g) num, den = ( (r1[f].subs(x(t),u).subs(y(t),v))/ (r2[g].subs(x(t),u).subs(y(t),v))).as_numer_denom() R1 = num.match(f1*g1) R2 = den.match(f2*g2) # phi = (r1[f].subs(x(t),u).subs(y(t),v))/num if R1 and R2: return 'type4' return None def check_nonlinear_2eq_order2(eq, func, func_coef): return None def check_nonlinear_3eq_order1(eq, func, func_coef): x = func[0].func y = func[1].func z = func[2].func fc = func_coef t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] u, v, w = symbols('u, v, w', cls=Dummy) a = Wild('a', exclude=[x(t), y(t), z(t), t]) b = Wild('b', exclude=[x(t), y(t), z(t), t]) c = Wild('c', exclude=[x(t), y(t), z(t), t]) f = Wild('f') F1 = Wild('F1') F2 = Wild('F2') F3 = Wild('F3') for i in range(3): eqs = 0 for terms in Add.make_args(eq[i]): eqs += terms/fc[i,func[i],1] eq[i] = eqs r1 = eq[0].match(diff(x(t),t) - a*y(t)*z(t)) r2 = eq[1].match(diff(y(t),t) - b*z(t)*x(t)) r3 = eq[2].match(diff(z(t),t) - c*x(t)*y(t)) if r1 and r2 and r3: num1, den1 = r1[a].as_numer_denom() num2, den2 = r2[b].as_numer_denom() num3, den3 = r3[c].as_numer_denom() if solve([num1*u-den1*(v-w), num2*v-den2*(w-u), num3*w-den3*(u-v)],[u, v]): return 'type1' r = eq[0].match(diff(x(t),t) - y(t)*z(t)*f) if r: r1 = collect_const(r[f]).match(a*f) r2 = ((diff(y(t),t) - eq[1])/r1[f]).match(b*z(t)*x(t)) r3 = ((diff(z(t),t) - eq[2])/r1[f]).match(c*x(t)*y(t)) if r1 and r2 and r3: num1, den1 = r1[a].as_numer_denom() num2, den2 = r2[b].as_numer_denom() num3, den3 = r3[c].as_numer_denom() if solve([num1*u-den1*(v-w), num2*v-den2*(w-u), num3*w-den3*(u-v)],[u, v]): return 'type2' r = eq[0].match(diff(x(t),t) - (F2-F3)) if r: r1 = collect_const(r[F2]).match(c*F2) r1.update(collect_const(r[F3]).match(b*F3)) if r1: if eq[1].has(r1[F2]) and not eq[1].has(r1[F3]): r1[F2], r1[F3] = r1[F3], r1[F2] r1[c], r1[b] = -r1[b], -r1[c] r2 = eq[1].match(diff(y(t),t) - a*r1[F3] + r1[c]*F1) if r2: r3 = (eq[2] == diff(z(t),t) - r1[b]*r2[F1] + r2[a]*r1[F2]) if r1 and r2 and r3: return 'type3' r = eq[0].match(diff(x(t),t) - z(t)*F2 + y(t)*F3) if r: r1 = collect_const(r[F2]).match(c*F2) r1.update(collect_const(r[F3]).match(b*F3)) if r1: if eq[1].has(r1[F2]) and not eq[1].has(r1[F3]): r1[F2], r1[F3] = r1[F3], r1[F2] r1[c], r1[b] = -r1[b], -r1[c] r2 = (diff(y(t),t) - eq[1]).match(a*x(t)*r1[F3] - r1[c]*z(t)*F1) if r2: r3 = (diff(z(t),t) - eq[2] == r1[b]*y(t)*r2[F1] - r2[a]*x(t)*r1[F2]) if r1 and r2 and r3: return 'type4' r = (diff(x(t),t) - eq[0]).match(x(t)*(F2 - F3)) if r: r1 = collect_const(r[F2]).match(c*F2) r1.update(collect_const(r[F3]).match(b*F3)) if r1: if eq[1].has(r1[F2]) and not eq[1].has(r1[F3]): r1[F2], r1[F3] = r1[F3], r1[F2] r1[c], r1[b] = -r1[b], -r1[c] r2 = (diff(y(t),t) - eq[1]).match(y(t)*(a*r1[F3] - r1[c]*F1)) if r2: r3 = (diff(z(t),t) - eq[2] == z(t)*(r1[b]*r2[F1] - r2[a]*r1[F2])) if r1 and r2 and r3: return 'type5' return None def check_nonlinear_3eq_order2(eq, func, func_coef): return None @vectorize(0) def odesimp(ode, eq, func, hint): r""" Simplifies solutions of ODEs, including trying to solve for ``func`` and running :py:meth:`~sympy.solvers.ode.constantsimp`. It may use knowledge of the type of solution that the hint returns to apply additional simplifications. It also attempts to integrate any :py:class:`~sympy.integrals.integrals.Integral`\s in the expression, if the hint is not an ``_Integral`` hint. This function should have no effect on expressions returned by :py:meth:`~sympy.solvers.ode.dsolve`, as :py:meth:`~sympy.solvers.ode.dsolve` already calls :py:meth:`~sympy.solvers.ode.ode.odesimp`, but the individual hint functions do not call :py:meth:`~sympy.solvers.ode.ode.odesimp` (because the :py:meth:`~sympy.solvers.ode.dsolve` wrapper does). Therefore, this function is designed for mainly internal use. Examples ======== >>> from sympy import sin, symbols, dsolve, pprint, Function >>> from sympy.solvers.ode.ode import odesimp >>> x , u2, C1= symbols('x,u2,C1') >>> f = Function('f') >>> eq = dsolve(x*f(x).diff(x) - f(x) - x*sin(f(x)/x), f(x), ... hint='1st_homogeneous_coeff_subs_indep_div_dep_Integral', ... simplify=False) >>> pprint(eq, wrap_line=False) x ---- f(x) / | | / 1 \ | -|u1 + -------| | | /1 \| | | sin|--|| | \ \u1// log(f(x)) = log(C1) + | ---------------- d(u1) | 2 | u1 | / >>> pprint(odesimp(eq, f(x), 1, {C1}, ... hint='1st_homogeneous_coeff_subs_indep_div_dep' ... )) #doctest: +SKIP x --------- = C1 /f(x)\ tan|----| \2*x / """ x = func.args[0] f = func.func C1 = get_numbered_constants(eq, num=1) constants = eq.free_symbols - ode.free_symbols # First, integrate if the hint allows it. eq = _handle_Integral(eq, func, hint) if hint.startswith("nth_linear_euler_eq_nonhomogeneous"): eq = simplify(eq) if not isinstance(eq, Equality): raise TypeError("eq should be an instance of Equality") # Second, clean up the arbitrary constants. # Right now, nth linear hints can put as many as 2*order constants in an # expression. If that number grows with another hint, the third argument # here should be raised accordingly, or constantsimp() rewritten to handle # an arbitrary number of constants. eq = constantsimp(eq, constants) # Lastly, now that we have cleaned up the expression, try solving for func. # When CRootOf is implemented in solve(), we will want to return a CRootOf # every time instead of an Equality. # Get the f(x) on the left if possible. if eq.rhs == func and not eq.lhs.has(func): eq = [Eq(eq.rhs, eq.lhs)] # make sure we are working with lists of solutions in simplified form. if eq.lhs == func and not eq.rhs.has(func): # The solution is already solved eq = [eq] else: # The solution is not solved, so try to solve it try: floats = any(i.is_Float for i in eq.atoms(Number)) eqsol = solve(eq, func, force=True, rational=False if floats else None) if not eqsol: raise NotImplementedError except (NotImplementedError, PolynomialError): eq = [eq] else: def _expand(expr): numer, denom = expr.as_numer_denom() if denom.is_Add: return expr else: return powsimp(expr.expand(), combine='exp', deep=True) # XXX: the rest of odesimp() expects each ``t`` to be in a # specific normal form: rational expression with numerator # expanded, but with combined exponential functions (at # least in this setup all tests pass). eq = [Eq(f(x), _expand(t)) for t in eqsol] # special simplification of the lhs. if hint.startswith("1st_homogeneous_coeff"): for j, eqi in enumerate(eq): newi = logcombine(eqi, force=True) if isinstance(newi.lhs, log) and newi.rhs == 0: newi = Eq(newi.lhs.args[0]/C1, C1) eq[j] = newi # We cleaned up the constants before solving to help the solve engine with # a simpler expression, but the solved expression could have introduced # things like -C1, so rerun constantsimp() one last time before returning. for i, eqi in enumerate(eq): eq[i] = constantsimp(eqi, constants) eq[i] = constant_renumber(eq[i], ode.free_symbols) # If there is only 1 solution, return it; # otherwise return the list of solutions. if len(eq) == 1: eq = eq[0] return eq def ode_sol_simplicity(sol, func, trysolving=True): r""" Returns an extended integer representing how simple a solution to an ODE is. The following things are considered, in order from most simple to least: - ``sol`` is solved for ``func``. - ``sol`` is not solved for ``func``, but can be if passed to solve (e.g., a solution returned by ``dsolve(ode, func, simplify=False``). - If ``sol`` is not solved for ``func``, then base the result on the length of ``sol``, as computed by ``len(str(sol))``. - If ``sol`` has any unevaluated :py:class:`~sympy.integrals.integrals.Integral`\s, this will automatically be considered less simple than any of the above. This function returns an integer such that if solution A is simpler than solution B by above metric, then ``ode_sol_simplicity(sola, func) < ode_sol_simplicity(solb, func)``. Currently, the following are the numbers returned, but if the heuristic is ever improved, this may change. Only the ordering is guaranteed. +----------------------------------------------+-------------------+ | Simplicity | Return | +==============================================+===================+ | ``sol`` solved for ``func`` | ``-2`` | +----------------------------------------------+-------------------+ | ``sol`` not solved for ``func`` but can be | ``-1`` | +----------------------------------------------+-------------------+ | ``sol`` is not solved nor solvable for | ``len(str(sol))`` | | ``func`` | | +----------------------------------------------+-------------------+ | ``sol`` contains an | ``oo`` | | :obj:`~sympy.integrals.integrals.Integral` | | +----------------------------------------------+-------------------+ ``oo`` here means the SymPy infinity, which should compare greater than any integer. If you already know :py:meth:`~sympy.solvers.solvers.solve` cannot solve ``sol``, you can use ``trysolving=False`` to skip that step, which is the only potentially slow step. For example, :py:meth:`~sympy.solvers.ode.dsolve` with the ``simplify=False`` flag should do this. If ``sol`` is a list of solutions, if the worst solution in the list returns ``oo`` it returns that, otherwise it returns ``len(str(sol))``, that is, the length of the string representation of the whole list. Examples ======== This function is designed to be passed to ``min`` as the key argument, such as ``min(listofsolutions, key=lambda i: ode_sol_simplicity(i, f(x)))``. >>> from sympy import symbols, Function, Eq, tan, Integral >>> from sympy.solvers.ode.ode import ode_sol_simplicity >>> x, C1, C2 = symbols('x, C1, C2') >>> f = Function('f') >>> ode_sol_simplicity(Eq(f(x), C1*x**2), f(x)) -2 >>> ode_sol_simplicity(Eq(x**2 + f(x), C1), f(x)) -1 >>> ode_sol_simplicity(Eq(f(x), C1*Integral(2*x, x)), f(x)) oo >>> eq1 = Eq(f(x)/tan(f(x)/(2*x)), C1) >>> eq2 = Eq(f(x)/tan(f(x)/(2*x) + f(x)), C2) >>> [ode_sol_simplicity(eq, f(x)) for eq in [eq1, eq2]] [28, 35] >>> min([eq1, eq2], key=lambda i: ode_sol_simplicity(i, f(x))) Eq(f(x)/tan(f(x)/(2*x)), C1) """ # TODO: if two solutions are solved for f(x), we still want to be # able to get the simpler of the two # See the docstring for the coercion rules. We check easier (faster) # things here first, to save time. if iterable(sol): # See if there are Integrals for i in sol: if ode_sol_simplicity(i, func, trysolving=trysolving) == oo: return oo return len(str(sol)) if sol.has(Integral): return oo # Next, try to solve for func. This code will change slightly when CRootOf # is implemented in solve(). Probably a CRootOf solution should fall # somewhere between a normal solution and an unsolvable expression. # First, see if they are already solved if sol.lhs == func and not sol.rhs.has(func) or \ sol.rhs == func and not sol.lhs.has(func): return -2 # We are not so lucky, try solving manually if trysolving: try: sols = solve(sol, func) if not sols: raise NotImplementedError except NotImplementedError: pass else: return -1 # Finally, a naive computation based on the length of the string version # of the expression. This may favor combined fractions because they # will not have duplicate denominators, and may slightly favor expressions # with fewer additions and subtractions, as those are separated by spaces # by the printer. # Additional ideas for simplicity heuristics are welcome, like maybe # checking if a equation has a larger domain, or if constantsimp has # introduced arbitrary constants numbered higher than the order of a # given ODE that sol is a solution of. return len(str(sol)) def _extract_funcs(eqs): from sympy.core.basic import preorder_traversal funcs = [] for eq in eqs: derivs = [node for node in preorder_traversal(eq) if isinstance(node, Derivative)] func = [] for d in derivs: func += list(d.atoms(AppliedUndef)) for func_ in func: funcs.append(func_) funcs = list(uniq(funcs)) return funcs def _get_constant_subexpressions(expr, Cs): Cs = set(Cs) Ces = [] def _recursive_walk(expr): expr_syms = expr.free_symbols if expr_syms and expr_syms.issubset(Cs): Ces.append(expr) else: if expr.func == exp: expr = expr.expand(mul=True) if expr.func in (Add, Mul): d = sift(expr.args, lambda i : i.free_symbols.issubset(Cs)) if len(d[True]) > 1: x = expr.func(*d[True]) if not x.is_number: Ces.append(x) elif isinstance(expr, Integral): if expr.free_symbols.issubset(Cs) and \ all(len(x) == 3 for x in expr.limits): Ces.append(expr) for i in expr.args: _recursive_walk(i) return _recursive_walk(expr) return Ces def __remove_linear_redundancies(expr, Cs): cnts = {i: expr.count(i) for i in Cs} Cs = [i for i in Cs if cnts[i] > 0] def _linear(expr): if isinstance(expr, Add): xs = [i for i in Cs if expr.count(i)==cnts[i] \ and 0 == expr.diff(i, 2)] d = {} for x in xs: y = expr.diff(x) if y not in d: d[y]=[] d[y].append(x) for y in d: if len(d[y]) > 1: d[y].sort(key=str) for x in d[y][1:]: expr = expr.subs(x, 0) return expr def _recursive_walk(expr): if len(expr.args) != 0: expr = expr.func(*[_recursive_walk(i) for i in expr.args]) expr = _linear(expr) return expr if isinstance(expr, Equality): lhs, rhs = [_recursive_walk(i) for i in expr.args] f = lambda i: isinstance(i, Number) or i in Cs if isinstance(lhs, Symbol) and lhs in Cs: rhs, lhs = lhs, rhs if lhs.func in (Add, Symbol) and rhs.func in (Add, Symbol): dlhs = sift([lhs] if isinstance(lhs, AtomicExpr) else lhs.args, f) drhs = sift([rhs] if isinstance(rhs, AtomicExpr) else rhs.args, f) for i in [True, False]: for hs in [dlhs, drhs]: if i not in hs: hs[i] = [0] # this calculation can be simplified lhs = Add(*dlhs[False]) - Add(*drhs[False]) rhs = Add(*drhs[True]) - Add(*dlhs[True]) elif lhs.func in (Mul, Symbol) and rhs.func in (Mul, Symbol): dlhs = sift([lhs] if isinstance(lhs, AtomicExpr) else lhs.args, f) if True in dlhs: if False not in dlhs: dlhs[False] = [1] lhs = Mul(*dlhs[False]) rhs = rhs/Mul(*dlhs[True]) return Eq(lhs, rhs) else: return _recursive_walk(expr) @vectorize(0) def constantsimp(expr, constants): r""" Simplifies an expression with arbitrary constants in it. This function is written specifically to work with :py:meth:`~sympy.solvers.ode.dsolve`, and is not intended for general use. Simplification is done by "absorbing" the arbitrary constants into other arbitrary constants, numbers, and symbols that they are not independent of. The symbols must all have the same name with numbers after it, for example, ``C1``, ``C2``, ``C3``. The ``symbolname`` here would be '``C``', the ``startnumber`` would be 1, and the ``endnumber`` would be 3. If the arbitrary constants are independent of the variable ``x``, then the independent symbol would be ``x``. There is no need to specify the dependent function, such as ``f(x)``, because it already has the independent symbol, ``x``, in it. Because terms are "absorbed" into arbitrary constants and because constants are renumbered after simplifying, the arbitrary constants in expr are not necessarily equal to the ones of the same name in the returned result. If two or more arbitrary constants are added, multiplied, or raised to the power of each other, they are first absorbed together into a single arbitrary constant. Then the new constant is combined into other terms if necessary. Absorption of constants is done with limited assistance: 1. terms of :py:class:`~sympy.core.add.Add`\s are collected to try join constants so `e^x (C_1 \cos(x) + C_2 \cos(x))` will simplify to `e^x C_1 \cos(x)`; 2. powers with exponents that are :py:class:`~sympy.core.add.Add`\s are expanded so `e^{C_1 + x}` will be simplified to `C_1 e^x`. Use :py:meth:`~sympy.solvers.ode.ode.constant_renumber` to renumber constants after simplification or else arbitrary numbers on constants may appear, e.g. `C_1 + C_3 x`. In rare cases, a single constant can be "simplified" into two constants. Every differential equation solution should have as many arbitrary constants as the order of the differential equation. The result here will be technically correct, but it may, for example, have `C_1` and `C_2` in an expression, when `C_1` is actually equal to `C_2`. Use your discretion in such situations, and also take advantage of the ability to use hints in :py:meth:`~sympy.solvers.ode.dsolve`. Examples ======== >>> from sympy import symbols >>> from sympy.solvers.ode.ode import constantsimp >>> C1, C2, C3, x, y = symbols('C1, C2, C3, x, y') >>> constantsimp(2*C1*x, {C1, C2, C3}) C1*x >>> constantsimp(C1 + 2 + x, {C1, C2, C3}) C1 + x >>> constantsimp(C1*C2 + 2 + C2 + C3*x, {C1, C2, C3}) C1 + C3*x """ # This function works recursively. The idea is that, for Mul, # Add, Pow, and Function, if the class has a constant in it, then # we can simplify it, which we do by recursing down and # simplifying up. Otherwise, we can skip that part of the # expression. Cs = constants orig_expr = expr constant_subexprs = _get_constant_subexpressions(expr, Cs) for xe in constant_subexprs: xes = list(xe.free_symbols) if not xes: continue if all([expr.count(c) == xe.count(c) for c in xes]): xes.sort(key=str) expr = expr.subs(xe, xes[0]) # try to perform common sub-expression elimination of constant terms try: commons, rexpr = cse(expr) commons.reverse() rexpr = rexpr[0] for s in commons: cs = list(s[1].atoms(Symbol)) if len(cs) == 1 and cs[0] in Cs and \ cs[0] not in rexpr.atoms(Symbol) and \ not any(cs[0] in ex for ex in commons if ex != s): rexpr = rexpr.subs(s[0], cs[0]) else: rexpr = rexpr.subs(*s) expr = rexpr except IndexError: pass expr = __remove_linear_redundancies(expr, Cs) def _conditional_term_factoring(expr): new_expr = terms_gcd(expr, clear=False, deep=True, expand=False) # we do not want to factor exponentials, so handle this separately if new_expr.is_Mul: infac = False asfac = False for m in new_expr.args: if isinstance(m, exp): asfac = True elif m.is_Add: infac = any(isinstance(fi, exp) for t in m.args for fi in Mul.make_args(t)) if asfac and infac: new_expr = expr break return new_expr expr = _conditional_term_factoring(expr) # call recursively if more simplification is possible if orig_expr != expr: return constantsimp(expr, Cs) return expr def constant_renumber(expr, variables=None, newconstants=None): r""" Renumber arbitrary constants in ``expr`` to use the symbol names as given in ``newconstants``. In the process, this reorders expression terms in a standard way. If ``newconstants`` is not provided then the new constant names will be ``C1``, ``C2`` etc. Otherwise ``newconstants`` should be an iterable giving the new symbols to use for the constants in order. The ``variables`` argument is a list of non-constant symbols. All other free symbols found in ``expr`` are assumed to be constants and will be renumbered. If ``variables`` is not given then any numbered symbol beginning with ``C`` (e.g. ``C1``) is assumed to be a constant. Symbols are renumbered based on ``.sort_key()``, so they should be numbered roughly in the order that they appear in the final, printed expression. Note that this ordering is based in part on hashes, so it can produce different results on different machines. The structure of this function is very similar to that of :py:meth:`~sympy.solvers.ode.constantsimp`. Examples ======== >>> from sympy import symbols >>> from sympy.solvers.ode.ode import constant_renumber >>> x, C1, C2, C3 = symbols('x,C1:4') >>> expr = C3 + C2*x + C1*x**2 >>> expr C1*x**2 + C2*x + C3 >>> constant_renumber(expr) C1 + C2*x + C3*x**2 The ``variables`` argument specifies which are constants so that the other symbols will not be renumbered: >>> constant_renumber(expr, [C1, x]) C1*x**2 + C2 + C3*x The ``newconstants`` argument is used to specify what symbols to use when replacing the constants: >>> constant_renumber(expr, [x], newconstants=symbols('E1:4')) E1 + E2*x + E3*x**2 """ # System of expressions if isinstance(expr, (set, list, tuple)): return type(expr)(constant_renumber(Tuple(*expr), variables=variables, newconstants=newconstants)) # Symbols in solution but not ODE are constants if variables is not None: variables = set(variables) free_symbols = expr.free_symbols constantsymbols = list(free_symbols - variables) # Any Cn is a constant... else: variables = set() isconstant = lambda s: s.startswith('C') and s[1:].isdigit() constantsymbols = [sym for sym in expr.free_symbols if isconstant(sym.name)] # Find new constants checking that they aren't already in the ODE if newconstants is None: iter_constants = numbered_symbols(start=1, prefix='C', exclude=variables) else: iter_constants = (sym for sym in newconstants if sym not in variables) constants_found = [] # make a mapping to send all constantsymbols to S.One and use # that to make sure that term ordering is not dependent on # the indexed value of C C_1 = [(ci, S.One) for ci in constantsymbols] sort_key=lambda arg: default_sort_key(arg.subs(C_1)) def _constant_renumber(expr): r""" We need to have an internal recursive function """ # For system of expressions if isinstance(expr, Tuple): renumbered = [_constant_renumber(e) for e in expr] return Tuple(*renumbered) if isinstance(expr, Equality): return Eq( _constant_renumber(expr.lhs), _constant_renumber(expr.rhs)) if type(expr) not in (Mul, Add, Pow) and not expr.is_Function and \ not expr.has(*constantsymbols): # Base case, as above. Hope there aren't constants inside # of some other class, because they won't be renumbered. return expr elif expr.is_Piecewise: return expr elif expr in constantsymbols: if expr not in constants_found: constants_found.append(expr) return expr elif expr.is_Function or expr.is_Pow: return expr.func( *[_constant_renumber(x) for x in expr.args]) else: sortedargs = list(expr.args) sortedargs.sort(key=sort_key) return expr.func(*[_constant_renumber(x) for x in sortedargs]) expr = _constant_renumber(expr) # Don't renumber symbols present in the ODE. constants_found = [c for c in constants_found if c not in variables] # Renumbering happens here subs_dict = {var: cons for var, cons in zip(constants_found, iter_constants)} expr = expr.subs(subs_dict, simultaneous=True) return expr def _handle_Integral(expr, func, hint): r""" Converts a solution with Integrals in it into an actual solution. For most hints, this simply runs ``expr.doit()``. """ if hint == "nth_linear_constant_coeff_homogeneous": sol = expr elif not hint.endswith("_Integral"): sol = expr.doit() else: sol = expr return sol # XXX: Should this function maybe go somewhere else? def homogeneous_order(eq, *symbols): r""" Returns the order `n` if `g` is homogeneous and ``None`` if it is not homogeneous. Determines if a function is homogeneous and if so of what order. A function `f(x, y, \cdots)` is homogeneous of order `n` if `f(t x, t y, \cdots) = t^n f(x, y, \cdots)`. If the function is of two variables, `F(x, y)`, then `f` being homogeneous of any order is equivalent to being able to rewrite `F(x, y)` as `G(x/y)` or `H(y/x)`. This fact is used to solve 1st order ordinary differential equations whose coefficients are homogeneous of the same order (see the docstrings of :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep` and :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep`). Symbols can be functions, but every argument of the function must be a symbol, and the arguments of the function that appear in the expression must match those given in the list of symbols. If a declared function appears with different arguments than given in the list of symbols, ``None`` is returned. Examples ======== >>> from sympy import Function, homogeneous_order, sqrt >>> from sympy.abc import x, y >>> f = Function('f') >>> homogeneous_order(f(x), f(x)) is None True >>> homogeneous_order(f(x,y), f(y, x), x, y) is None True >>> homogeneous_order(f(x), f(x), x) 1 >>> homogeneous_order(x**2*f(x)/sqrt(x**2+f(x)**2), x, f(x)) 2 >>> homogeneous_order(x**2+f(x), x, f(x)) is None True """ if not symbols: raise ValueError("homogeneous_order: no symbols were given.") symset = set(symbols) eq = sympify(eq) # The following are not supported if eq.has(Order, Derivative): return None # These are all constants if (eq.is_Number or eq.is_NumberSymbol or eq.is_number ): return S.Zero # Replace all functions with dummy variables dum = numbered_symbols(prefix='d', cls=Dummy) newsyms = set() for i in [j for j in symset if getattr(j, 'is_Function')]: iargs = set(i.args) if iargs.difference(symset): return None else: dummyvar = next(dum) eq = eq.subs(i, dummyvar) symset.remove(i) newsyms.add(dummyvar) symset.update(newsyms) if not eq.free_symbols & symset: return None # assuming order of a nested function can only be equal to zero if isinstance(eq, Function): return None if homogeneous_order( eq.args[0], *tuple(symset)) != 0 else S.Zero # make the replacement of x with x*t and see if t can be factored out t = Dummy('t', positive=True) # It is sufficient that t > 0 eqs = separatevars(eq.subs([(i, t*i) for i in symset]), [t], dict=True)[t] if eqs is S.One: return S.Zero # there was no term with only t i, d = eqs.as_independent(t, as_Add=False) b, e = d.as_base_exp() if b == t: return e def ode_2nd_power_series_ordinary(eq, func, order, match): r""" Gives a power series solution to a second order homogeneous differential equation with polynomial coefficients at an ordinary point. A homogeneous differential equation is of the form .. math :: P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) = 0 For simplicity it is assumed that `P(x)`, `Q(x)` and `R(x)` are polynomials, it is sufficient that `\frac{Q(x)}{P(x)}` and `\frac{R(x)}{P(x)}` exists at `x_{0}`. A recurrence relation is obtained by substituting `y` as `\sum_{n=0}^\infty a_{n}x^{n}`, in the differential equation, and equating the nth term. Using this relation various terms can be generated. Examples ======== >>> from sympy import dsolve, Function, pprint >>> from sympy.abc import x >>> f = Function("f") >>> eq = f(x).diff(x, 2) + f(x) >>> pprint(dsolve(eq, hint='2nd_power_series_ordinary')) / 4 2 \ / 2\ |x x | | x | / 6\ f(x) = C2*|-- - -- + 1| + C1*x*|1 - --| + O\x / \24 2 / \ 6 / References ========== - http://tutorial.math.lamar.edu/Classes/DE/SeriesSolutions.aspx - George E. Simmons, "Differential Equations with Applications and Historical Notes", p.p 176 - 184 """ x = func.args[0] f = func.func C0, C1 = get_numbered_constants(eq, num=2) n = Dummy("n", integer=True) s = Wild("s") k = Wild("k", exclude=[x]) x0 = match.get('x0') terms = match.get('terms', 5) p = match[match['a3']] q = match[match['b3']] r = match[match['c3']] seriesdict = {} recurr = Function("r") # Generating the recurrence relation which works this way: # for the second order term the summation begins at n = 2. The coefficients # p is multiplied with an*(n - 1)*(n - 2)*x**n-2 and a substitution is made such that # the exponent of x becomes n. # For example, if p is x, then the second degree recurrence term is # an*(n - 1)*(n - 2)*x**n-1, substituting (n - 1) as n, it transforms to # an+1*n*(n - 1)*x**n. # A similar process is done with the first order and zeroth order term. coefflist = [(recurr(n), r), (n*recurr(n), q), (n*(n - 1)*recurr(n), p)] for index, coeff in enumerate(coefflist): if coeff[1]: f2 = powsimp(expand((coeff[1]*(x - x0)**(n - index)).subs(x, x + x0))) if f2.is_Add: addargs = f2.args else: addargs = [f2] for arg in addargs: powm = arg.match(s*x**k) term = coeff[0]*powm[s] if not powm[k].is_Symbol: term = term.subs(n, n - powm[k].as_independent(n)[0]) startind = powm[k].subs(n, index) # Seeing if the startterm can be reduced further. # If it vanishes for n lesser than startind, it is # equal to summation from n. if startind: for i in reversed(range(startind)): if not term.subs(n, i): seriesdict[term] = i else: seriesdict[term] = i + 1 break else: seriesdict[term] = S.Zero # Stripping of terms so that the sum starts with the same number. teq = S.Zero suminit = seriesdict.values() rkeys = seriesdict.keys() req = Add(*rkeys) if any(suminit): maxval = max(suminit) for term in seriesdict: val = seriesdict[term] if val != maxval: for i in range(val, maxval): teq += term.subs(n, val) finaldict = {} if teq: fargs = teq.atoms(AppliedUndef) if len(fargs) == 1: finaldict[fargs.pop()] = 0 else: maxf = max(fargs, key = lambda x: x.args[0]) sol = solve(teq, maxf) if isinstance(sol, list): sol = sol[0] finaldict[maxf] = sol # Finding the recurrence relation in terms of the largest term. fargs = req.atoms(AppliedUndef) maxf = max(fargs, key = lambda x: x.args[0]) minf = min(fargs, key = lambda x: x.args[0]) if minf.args[0].is_Symbol: startiter = 0 else: startiter = -minf.args[0].as_independent(n)[0] lhs = maxf rhs = solve(req, maxf) if isinstance(rhs, list): rhs = rhs[0] # Checking how many values are already present tcounter = len([t for t in finaldict.values() if t]) for _ in range(tcounter, terms - 3): # Assuming c0 and c1 to be arbitrary check = rhs.subs(n, startiter) nlhs = lhs.subs(n, startiter) nrhs = check.subs(finaldict) finaldict[nlhs] = nrhs startiter += 1 # Post processing series = C0 + C1*(x - x0) for term in finaldict: if finaldict[term]: fact = term.args[0] series += (finaldict[term].subs([(recurr(0), C0), (recurr(1), C1)])*( x - x0)**fact) series = collect(expand_mul(series), [C0, C1]) + Order(x**terms) return Eq(f(x), series) def ode_2nd_power_series_regular(eq, func, order, match): r""" Gives a power series solution to a second order homogeneous differential equation with polynomial coefficients at a regular point. A second order homogeneous differential equation is of the form .. math :: P(x)\frac{d^2y}{dx^2} + Q(x)\frac{dy}{dx} + R(x) = 0 A point is said to regular singular at `x0` if `x - x0\frac{Q(x)}{P(x)}` and `(x - x0)^{2}\frac{R(x)}{P(x)}` are analytic at `x0`. For simplicity `P(x)`, `Q(x)` and `R(x)` are assumed to be polynomials. The algorithm for finding the power series solutions is: 1. Try expressing `(x - x0)P(x)` and `((x - x0)^{2})Q(x)` as power series solutions about x0. Find `p0` and `q0` which are the constants of the power series expansions. 2. Solve the indicial equation `f(m) = m(m - 1) + m*p0 + q0`, to obtain the roots `m1` and `m2` of the indicial equation. 3. If `m1 - m2` is a non integer there exists two series solutions. If `m1 = m2`, there exists only one solution. If `m1 - m2` is an integer, then the existence of one solution is confirmed. The other solution may or may not exist. The power series solution is of the form `x^{m}\sum_{n=0}^\infty a_{n}x^{n}`. The coefficients are determined by the following recurrence relation. `a_{n} = -\frac{\sum_{k=0}^{n-1} q_{n-k} + (m + k)p_{n-k}}{f(m + n)}`. For the case in which `m1 - m2` is an integer, it can be seen from the recurrence relation that for the lower root `m`, when `n` equals the difference of both the roots, the denominator becomes zero. So if the numerator is not equal to zero, a second series solution exists. Examples ======== >>> from sympy import dsolve, Function, pprint >>> from sympy.abc import x >>> f = Function("f") >>> eq = x*(f(x).diff(x, 2)) + 2*(f(x).diff(x)) + x*f(x) >>> pprint(dsolve(eq, hint='2nd_power_series_regular')) / 6 4 2 \ | x x x | / 4 2 \ C1*|- --- + -- - -- + 1| | x x | \ 720 24 2 / / 6\ f(x) = C2*|--- - -- + 1| + ------------------------ + O\x / \120 6 / x References ========== - George E. Simmons, "Differential Equations with Applications and Historical Notes", p.p 176 - 184 """ x = func.args[0] f = func.func C0, C1 = get_numbered_constants(eq, num=2) m = Dummy("m") # for solving the indicial equation x0 = match.get('x0') terms = match.get('terms', 5) p = match['p'] q = match['q'] # Generating the indicial equation indicial = [] for term in [p, q]: if not term.has(x): indicial.append(term) else: term = series(term, x=x, n=1, x0=x0) if isinstance(term, Order): indicial.append(S.Zero) else: for arg in term.args: if not arg.has(x): indicial.append(arg) break p0, q0 = indicial sollist = solve(m*(m - 1) + m*p0 + q0, m) if sollist and isinstance(sollist, list) and all( [sol.is_real for sol in sollist]): serdict1 = {} serdict2 = {} if len(sollist) == 1: # Only one series solution exists in this case. m1 = m2 = sollist.pop() if terms-m1-1 <= 0: return Eq(f(x), Order(terms)) serdict1 = _frobenius(terms-m1-1, m1, p0, q0, p, q, x0, x, C0) else: m1 = sollist[0] m2 = sollist[1] if m1 < m2: m1, m2 = m2, m1 # Irrespective of whether m1 - m2 is an integer or not, one # Frobenius series solution exists. serdict1 = _frobenius(terms-m1-1, m1, p0, q0, p, q, x0, x, C0) if not (m1 - m2).is_integer: # Second frobenius series solution exists. serdict2 = _frobenius(terms-m2-1, m2, p0, q0, p, q, x0, x, C1) else: # Check if second frobenius series solution exists. serdict2 = _frobenius(terms-m2-1, m2, p0, q0, p, q, x0, x, C1, check=m1) if serdict1: finalseries1 = C0 for key in serdict1: power = int(key.name[1:]) finalseries1 += serdict1[key]*(x - x0)**power finalseries1 = (x - x0)**m1*finalseries1 finalseries2 = S.Zero if serdict2: for key in serdict2: power = int(key.name[1:]) finalseries2 += serdict2[key]*(x - x0)**power finalseries2 += C1 finalseries2 = (x - x0)**m2*finalseries2 return Eq(f(x), collect(finalseries1 + finalseries2, [C0, C1]) + Order(x**terms)) def _frobenius(n, m, p0, q0, p, q, x0, x, c, check=None): r""" Returns a dict with keys as coefficients and values as their values in terms of C0 """ n = int(n) # In cases where m1 - m2 is not an integer m2 = check d = Dummy("d") numsyms = numbered_symbols("C", start=0) numsyms = [next(numsyms) for i in range(n + 1)] serlist = [] for ser in [p, q]: # Order term not present if ser.is_polynomial(x) and Poly(ser, x).degree() <= n: if x0: ser = ser.subs(x, x + x0) dict_ = Poly(ser, x).as_dict() # Order term present else: tseries = series(ser, x=x0, n=n+1) # Removing order dict_ = Poly(list(ordered(tseries.args))[: -1], x).as_dict() # Fill in with zeros, if coefficients are zero. for i in range(n + 1): if (i,) not in dict_: dict_[(i,)] = S.Zero serlist.append(dict_) pseries = serlist[0] qseries = serlist[1] indicial = d*(d - 1) + d*p0 + q0 frobdict = {} for i in range(1, n + 1): num = c*(m*pseries[(i,)] + qseries[(i,)]) for j in range(1, i): sym = Symbol("C" + str(j)) num += frobdict[sym]*((m + j)*pseries[(i - j,)] + qseries[(i - j,)]) # Checking for cases when m1 - m2 is an integer. If num equals zero # then a second Frobenius series solution cannot be found. If num is not zero # then set constant as zero and proceed. if m2 is not None and i == m2 - m: if num: return False else: frobdict[numsyms[i]] = S.Zero else: frobdict[numsyms[i]] = -num/(indicial.subs(d, m+i)) return frobdict def _remove_redundant_solutions(eq, solns, order, var): r""" Remove redundant solutions from the set of solutions. This function is needed because otherwise dsolve can return redundant solutions. As an example consider: eq = Eq((f(x).diff(x, 2))*f(x).diff(x), 0) There are two ways to find solutions to eq. The first is to solve f(x).diff(x, 2) = 0 leading to solution f(x)=C1 + C2*x. The second is to solve the equation f(x).diff(x) = 0 leading to the solution f(x) = C1. In this particular case we then see that the second solution is a special case of the first and we don't want to return it. This does not always happen. If we have eq = Eq((f(x)**2-4)*(f(x).diff(x)-4), 0) then we get the algebraic solution f(x) = [-2, 2] and the integral solution f(x) = x + C1 and in this case the two solutions are not equivalent wrt initial conditions so both should be returned. """ def is_special_case_of(soln1, soln2): return _is_special_case_of(soln1, soln2, eq, order, var) unique_solns = [] for soln1 in solns: for soln2 in unique_solns[:]: if is_special_case_of(soln1, soln2): break elif is_special_case_of(soln2, soln1): unique_solns.remove(soln2) else: unique_solns.append(soln1) return unique_solns def _is_special_case_of(soln1, soln2, eq, order, var): r""" True if soln1 is found to be a special case of soln2 wrt some value of the constants that appear in soln2. False otherwise. """ # The solutions returned by dsolve may be given explicitly or implicitly. # We will equate the sol1=(soln1.rhs - soln1.lhs), sol2=(soln2.rhs - soln2.lhs) # of the two solutions. # # Since this is supposed to hold for all x it also holds for derivatives. # For an order n ode we should be able to differentiate # each solution n times to get n+1 equations. # # We then try to solve those n+1 equations for the integrations constants # in sol2. If we can find a solution that doesn't depend on x then it # means that some value of the constants in sol1 is a special case of # sol2 corresponding to a particular choice of the integration constants. # In case the solution is in implicit form we subtract the sides soln1 = soln1.rhs - soln1.lhs soln2 = soln2.rhs - soln2.lhs # Work for the series solution if soln1.has(Order) and soln2.has(Order): if soln1.getO() == soln2.getO(): soln1 = soln1.removeO() soln2 = soln2.removeO() else: return False elif soln1.has(Order) or soln2.has(Order): return False constants1 = soln1.free_symbols.difference(eq.free_symbols) constants2 = soln2.free_symbols.difference(eq.free_symbols) constants1_new = get_numbered_constants(Tuple(soln1, soln2), len(constants1)) if len(constants1) == 1: constants1_new = {constants1_new} for c_old, c_new in zip(constants1, constants1_new): soln1 = soln1.subs(c_old, c_new) # n equations for sol1 = sol2, sol1'=sol2', ... lhs = soln1 rhs = soln2 eqns = [Eq(lhs, rhs)] for n in range(1, order): lhs = lhs.diff(var) rhs = rhs.diff(var) eq = Eq(lhs, rhs) eqns.append(eq) # BooleanTrue/False awkwardly show up for trivial equations if any(isinstance(eq, BooleanFalse) for eq in eqns): return False eqns = [eq for eq in eqns if not isinstance(eq, BooleanTrue)] try: constant_solns = solve(eqns, constants2) except NotImplementedError: return False # Sometimes returns a dict and sometimes a list of dicts if isinstance(constant_solns, dict): constant_solns = [constant_solns] # after solving the issue 17418, maybe we don't need the following checksol code. for constant_soln in constant_solns: for eq in eqns: eq=eq.rhs-eq.lhs if checksol(eq, constant_soln) is not True: return False # If any solution gives all constants as expressions that don't depend on # x then there exists constants for soln2 that give soln1 for constant_soln in constant_solns: if not any(c.has(var) for c in constant_soln.values()): return True return False def ode_1st_power_series(eq, func, order, match): r""" The power series solution is a method which gives the Taylor series expansion to the solution of a differential equation. For a first order differential equation `\frac{dy}{dx} = h(x, y)`, a power series solution exists at a point `x = x_{0}` if `h(x, y)` is analytic at `x_{0}`. The solution is given by .. math:: y(x) = y(x_{0}) + \sum_{n = 1}^{\infty} \frac{F_{n}(x_{0},b)(x - x_{0})^n}{n!}, where `y(x_{0}) = b` is the value of y at the initial value of `x_{0}`. To compute the values of the `F_{n}(x_{0},b)` the following algorithm is followed, until the required number of terms are generated. 1. `F_1 = h(x_{0}, b)` 2. `F_{n+1} = \frac{\partial F_{n}}{\partial x} + \frac{\partial F_{n}}{\partial y}F_{1}` Examples ======== >>> from sympy import Function, pprint, exp >>> from sympy.solvers.ode.ode import dsolve >>> from sympy.abc import x >>> f = Function('f') >>> eq = exp(x)*(f(x).diff(x)) - f(x) >>> pprint(dsolve(eq, hint='1st_power_series')) 3 4 5 C1*x C1*x C1*x / 6\ f(x) = C1 + C1*x - ----- + ----- + ----- + O\x / 6 24 60 References ========== - Travis W. Walker, Analytic power series technique for solving first-order differential equations, p.p 17, 18 """ x = func.args[0] y = match['y'] f = func.func h = -match[match['d']]/match[match['e']] point = match.get('f0') value = match.get('f0val') terms = match.get('terms') # First term F = h if not h: return Eq(f(x), value) # Initialization series = value if terms > 1: hc = h.subs({x: point, y: value}) if hc.has(oo) or hc.has(NaN) or hc.has(zoo): # Derivative does not exist, not analytic return Eq(f(x), oo) elif hc: series += hc*(x - point) for factcount in range(2, terms): Fnew = F.diff(x) + F.diff(y)*h Fnewc = Fnew.subs({x: point, y: value}) # Same logic as above if Fnewc.has(oo) or Fnewc.has(NaN) or Fnewc.has(-oo) or Fnewc.has(zoo): return Eq(f(x), oo) series += Fnewc*((x - point)**factcount)/factorial(factcount) F = Fnew series += Order(x**terms) return Eq(f(x), series) def checkinfsol(eq, infinitesimals, func=None, order=None): r""" This function is used to check if the given infinitesimals are the actual infinitesimals of the given first order differential equation. This method is specific to the Lie Group Solver of ODEs. As of now, it simply checks, by substituting the infinitesimals in the partial differential equation. .. math:: \frac{\partial \eta}{\partial x} + \left(\frac{\partial \eta}{\partial y} - \frac{\partial \xi}{\partial x}\right)*h - \frac{\partial \xi}{\partial y}*h^{2} - \xi\frac{\partial h}{\partial x} - \eta\frac{\partial h}{\partial y} = 0 where `\eta`, and `\xi` are the infinitesimals and `h(x,y) = \frac{dy}{dx}` The infinitesimals should be given in the form of a list of dicts ``[{xi(x, y): inf, eta(x, y): inf}]``, corresponding to the output of the function infinitesimals. It returns a list of values of the form ``[(True/False, sol)]`` where ``sol`` is the value obtained after substituting the infinitesimals in the PDE. If it is ``True``, then ``sol`` would be 0. """ if isinstance(eq, Equality): eq = eq.lhs - eq.rhs if not func: eq, func = _preprocess(eq) variables = func.args if len(variables) != 1: raise ValueError("ODE's have only one independent variable") else: x = variables[0] if not order: order = ode_order(eq, func) if order != 1: raise NotImplementedError("Lie groups solver has been implemented " "only for first order differential equations") else: df = func.diff(x) a = Wild('a', exclude = [df]) b = Wild('b', exclude = [df]) match = collect(expand(eq), df).match(a*df + b) if match: h = -simplify(match[b]/match[a]) else: try: sol = solve(eq, df) except NotImplementedError: raise NotImplementedError("Infinitesimals for the " "first order ODE could not be found") else: h = sol[0] # Find infinitesimals for one solution y = Dummy('y') h = h.subs(func, y) xi = Function('xi')(x, y) eta = Function('eta')(x, y) dxi = Function('xi')(x, func) deta = Function('eta')(x, func) pde = (eta.diff(x) + (eta.diff(y) - xi.diff(x))*h - (xi.diff(y))*h**2 - xi*(h.diff(x)) - eta*(h.diff(y))) soltup = [] for sol in infinitesimals: tsol = {xi: S(sol[dxi]).subs(func, y), eta: S(sol[deta]).subs(func, y)} sol = simplify(pde.subs(tsol).doit()) if sol: soltup.append((False, sol.subs(y, func))) else: soltup.append((True, 0)) return soltup def sysode_linear_2eq_order1(match_): x = match_['func'][0].func y = match_['func'][1].func func = match_['func'] fc = match_['func_coeff'] eq = match_['eq'] r = dict() t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] for i in range(2): eqs = 0 for terms in Add.make_args(eq[i]): eqs += terms/fc[i,func[i],1] eq[i] = eqs # for equations Eq(a1*diff(x(t),t), a*x(t) + b*y(t) + k1) # and Eq(a2*diff(x(t),t), c*x(t) + d*y(t) + k2) r['a'] = -fc[0,x(t),0]/fc[0,x(t),1] r['c'] = -fc[1,x(t),0]/fc[1,y(t),1] r['b'] = -fc[0,y(t),0]/fc[0,x(t),1] r['d'] = -fc[1,y(t),0]/fc[1,y(t),1] forcing = [S.Zero,S.Zero] for i in range(2): for j in Add.make_args(eq[i]): if not j.has(x(t), y(t)): forcing[i] += j if not (forcing[0].has(t) or forcing[1].has(t)): r['k1'] = forcing[0] r['k2'] = forcing[1] else: raise NotImplementedError("Only homogeneous problems are supported" + " (and constant inhomogeneity)") if match_['type_of_equation'] == 'type6': sol = _linear_2eq_order1_type6(x, y, t, r, eq) if match_['type_of_equation'] == 'type7': sol = _linear_2eq_order1_type7(x, y, t, r, eq) return sol def _linear_2eq_order1_type6(x, y, t, r, eq): r""" The equations of this type of ode are . .. math:: x' = f(t) x + g(t) y .. math:: y' = a [f(t) + a h(t)] x + a [g(t) - h(t)] y This is solved by first multiplying the first equation by `-a` and adding it to the second equation to obtain .. math:: y' - a x' = -a h(t) (y - a x) Setting `U = y - ax` and integrating the equation we arrive at .. math:: y - ax = C_1 e^{-a \int h(t) \,dt} and on substituting the value of y in first equation give rise to first order ODEs. After solving for `x`, we can obtain `y` by substituting the value of `x` in second equation. """ C1, C2, C3, C4 = get_numbered_constants(eq, num=4) p = 0 q = 0 p1 = cancel(r['c']/cancel(r['c']/r['d']).as_numer_denom()[0]) p2 = cancel(r['a']/cancel(r['a']/r['b']).as_numer_denom()[0]) for n, i in enumerate([p1, p2]): for j in Mul.make_args(collect_const(i)): if not j.has(t): q = j if q!=0 and n==0: if ((r['c']/j - r['a'])/(r['b'] - r['d']/j)) == j: p = 1 s = j break if q!=0 and n==1: if ((r['a']/j - r['c'])/(r['d'] - r['b']/j)) == j: p = 2 s = j break if p == 1: equ = diff(x(t),t) - r['a']*x(t) - r['b']*(s*x(t) + C1*exp(-s*Integral(r['b'] - r['d']/s, t))) hint1 = classify_ode(equ)[1] sol1 = dsolve(equ, hint=hint1+'_Integral').rhs sol2 = s*sol1 + C1*exp(-s*Integral(r['b'] - r['d']/s, t)) elif p ==2: equ = diff(y(t),t) - r['c']*y(t) - r['d']*s*y(t) + C1*exp(-s*Integral(r['d'] - r['b']/s, t)) hint1 = classify_ode(equ)[1] sol2 = dsolve(equ, hint=hint1+'_Integral').rhs sol1 = s*sol2 + C1*exp(-s*Integral(r['d'] - r['b']/s, t)) return [Eq(x(t), sol1), Eq(y(t), sol2)] def _linear_2eq_order1_type7(x, y, t, r, eq): r""" The equations of this type of ode are . .. math:: x' = f(t) x + g(t) y .. math:: y' = h(t) x + p(t) y Differentiating the first equation and substituting the value of `y` from second equation will give a second-order linear equation .. math:: g x'' - (fg + gp + g') x' + (fgp - g^{2} h + f g' - f' g) x = 0 This above equation can be easily integrated if following conditions are satisfied. 1. `fgp - g^{2} h + f g' - f' g = 0` 2. `fgp - g^{2} h + f g' - f' g = ag, fg + gp + g' = bg` If first condition is satisfied then it is solved by current dsolve solver and in second case it becomes a constant coefficient differential equation which is also solved by current solver. Otherwise if the above condition fails then, a particular solution is assumed as `x = x_0(t)` and `y = y_0(t)` Then the general solution is expressed as .. math:: x = C_1 x_0(t) + C_2 x_0(t) \int \frac{g(t) F(t) P(t)}{x_0^{2}(t)} \,dt .. math:: y = C_1 y_0(t) + C_2 [\frac{F(t) P(t)}{x_0(t)} + y_0(t) \int \frac{g(t) F(t) P(t)}{x_0^{2}(t)} \,dt] where C1 and C2 are arbitrary constants and .. math:: F(t) = e^{\int f(t) \,dt} , P(t) = e^{\int p(t) \,dt} """ C1, C2, C3, C4 = get_numbered_constants(eq, num=4) e1 = r['a']*r['b']*r['c'] - r['b']**2*r['c'] + r['a']*diff(r['b'],t) - diff(r['a'],t)*r['b'] e2 = r['a']*r['c']*r['d'] - r['b']*r['c']**2 + diff(r['c'],t)*r['d'] - r['c']*diff(r['d'],t) m1 = r['a']*r['b'] + r['b']*r['d'] + diff(r['b'],t) m2 = r['a']*r['c'] + r['c']*r['d'] + diff(r['c'],t) if e1 == 0: sol1 = dsolve(r['b']*diff(x(t),t,t) - m1*diff(x(t),t)).rhs sol2 = dsolve(diff(y(t),t) - r['c']*sol1 - r['d']*y(t)).rhs elif e2 == 0: sol2 = dsolve(r['c']*diff(y(t),t,t) - m2*diff(y(t),t)).rhs sol1 = dsolve(diff(x(t),t) - r['a']*x(t) - r['b']*sol2).rhs elif not (e1/r['b']).has(t) and not (m1/r['b']).has(t): sol1 = dsolve(diff(x(t),t,t) - (m1/r['b'])*diff(x(t),t) - (e1/r['b'])*x(t)).rhs sol2 = dsolve(diff(y(t),t) - r['c']*sol1 - r['d']*y(t)).rhs elif not (e2/r['c']).has(t) and not (m2/r['c']).has(t): sol2 = dsolve(diff(y(t),t,t) - (m2/r['c'])*diff(y(t),t) - (e2/r['c'])*y(t)).rhs sol1 = dsolve(diff(x(t),t) - r['a']*x(t) - r['b']*sol2).rhs else: x0 = Function('x0')(t) # x0 and y0 being particular solutions y0 = Function('y0')(t) F = exp(Integral(r['a'],t)) P = exp(Integral(r['d'],t)) sol1 = C1*x0 + C2*x0*Integral(r['b']*F*P/x0**2, t) sol2 = C1*y0 + C2*(F*P/x0 + y0*Integral(r['b']*F*P/x0**2, t)) return [Eq(x(t), sol1), Eq(y(t), sol2)] def sysode_nonlinear_2eq_order1(match_): func = match_['func'] eq = match_['eq'] fc = match_['func_coeff'] t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] if match_['type_of_equation'] == 'type5': sol = _nonlinear_2eq_order1_type5(func, t, eq) return sol x = func[0].func y = func[1].func for i in range(2): eqs = 0 for terms in Add.make_args(eq[i]): eqs += terms/fc[i,func[i],1] eq[i] = eqs if match_['type_of_equation'] == 'type1': sol = _nonlinear_2eq_order1_type1(x, y, t, eq) elif match_['type_of_equation'] == 'type2': sol = _nonlinear_2eq_order1_type2(x, y, t, eq) elif match_['type_of_equation'] == 'type3': sol = _nonlinear_2eq_order1_type3(x, y, t, eq) elif match_['type_of_equation'] == 'type4': sol = _nonlinear_2eq_order1_type4(x, y, t, eq) return sol def _nonlinear_2eq_order1_type1(x, y, t, eq): r""" Equations: .. math:: x' = x^n F(x,y) .. math:: y' = g(y) F(x,y) Solution: .. math:: x = \varphi(y), \int \frac{1}{g(y) F(\varphi(y),y)} \,dy = t + C_2 where if `n \neq 1` .. math:: \varphi = [C_1 + (1-n) \int \frac{1}{g(y)} \,dy]^{\frac{1}{1-n}} if `n = 1` .. math:: \varphi = C_1 e^{\int \frac{1}{g(y)} \,dy} where `C_1` and `C_2` are arbitrary constants. """ C1, C2 = get_numbered_constants(eq, num=2) n = Wild('n', exclude=[x(t),y(t)]) f = Wild('f') u, v = symbols('u, v') r = eq[0].match(diff(x(t),t) - x(t)**n*f) g = ((diff(y(t),t) - eq[1])/r[f]).subs(y(t),v) F = r[f].subs(x(t),u).subs(y(t),v) n = r[n] if n!=1: phi = (C1 + (1-n)*Integral(1/g, v))**(1/(1-n)) else: phi = C1*exp(Integral(1/g, v)) phi = phi.doit() sol2 = solve(Integral(1/(g*F.subs(u,phi)), v).doit() - t - C2, v) sol = [] for sols in sol2: sol.append(Eq(x(t),phi.subs(v, sols))) sol.append(Eq(y(t), sols)) return sol def _nonlinear_2eq_order1_type2(x, y, t, eq): r""" Equations: .. math:: x' = e^{\lambda x} F(x,y) .. math:: y' = g(y) F(x,y) Solution: .. math:: x = \varphi(y), \int \frac{1}{g(y) F(\varphi(y),y)} \,dy = t + C_2 where if `\lambda \neq 0` .. math:: \varphi = -\frac{1}{\lambda} log(C_1 - \lambda \int \frac{1}{g(y)} \,dy) if `\lambda = 0` .. math:: \varphi = C_1 + \int \frac{1}{g(y)} \,dy where `C_1` and `C_2` are arbitrary constants. """ C1, C2 = get_numbered_constants(eq, num=2) n = Wild('n', exclude=[x(t),y(t)]) f = Wild('f') u, v = symbols('u, v') r = eq[0].match(diff(x(t),t) - exp(n*x(t))*f) g = ((diff(y(t),t) - eq[1])/r[f]).subs(y(t),v) F = r[f].subs(x(t),u).subs(y(t),v) n = r[n] if n: phi = -1/n*log(C1 - n*Integral(1/g, v)) else: phi = C1 + Integral(1/g, v) phi = phi.doit() sol2 = solve(Integral(1/(g*F.subs(u,phi)), v).doit() - t - C2, v) sol = [] for sols in sol2: sol.append(Eq(x(t),phi.subs(v, sols))) sol.append(Eq(y(t), sols)) return sol def _nonlinear_2eq_order1_type3(x, y, t, eq): r""" Autonomous system of general form .. math:: x' = F(x,y) .. math:: y' = G(x,y) Assuming `y = y(x, C_1)` where `C_1` is an arbitrary constant is the general solution of the first-order equation .. math:: F(x,y) y'_x = G(x,y) Then the general solution of the original system of equations has the form .. math:: \int \frac{1}{F(x,y(x,C_1))} \,dx = t + C_1 """ C1, C2, C3, C4 = get_numbered_constants(eq, num=4) v = Function('v') u = Symbol('u') f = Wild('f') g = Wild('g') r1 = eq[0].match(diff(x(t),t) - f) r2 = eq[1].match(diff(y(t),t) - g) F = r1[f].subs(x(t), u).subs(y(t), v(u)) G = r2[g].subs(x(t), u).subs(y(t), v(u)) sol2r = dsolve(Eq(diff(v(u), u), G/F)) if isinstance(sol2r, Equality): sol2r = [sol2r] for sol2s in sol2r: sol1 = solve(Integral(1/F.subs(v(u), sol2s.rhs), u).doit() - t - C2, u) sol = [] for sols in sol1: sol.append(Eq(x(t), sols)) sol.append(Eq(y(t), (sol2s.rhs).subs(u, sols))) return sol def _nonlinear_2eq_order1_type4(x, y, t, eq): r""" Equation: .. math:: x' = f_1(x) g_1(y) \phi(x,y,t) .. math:: y' = f_2(x) g_2(y) \phi(x,y,t) First integral: .. math:: \int \frac{f_2(x)}{f_1(x)} \,dx - \int \frac{g_1(y)}{g_2(y)} \,dy = C where `C` is an arbitrary constant. On solving the first integral for `x` (resp., `y` ) and on substituting the resulting expression into either equation of the original solution, one arrives at a first-order equation for determining `y` (resp., `x` ). """ C1, C2 = get_numbered_constants(eq, num=2) u, v = symbols('u, v') U, V = symbols('U, V', cls=Function) f = Wild('f') g = Wild('g') f1 = Wild('f1', exclude=[v,t]) f2 = Wild('f2', exclude=[v,t]) g1 = Wild('g1', exclude=[u,t]) g2 = Wild('g2', exclude=[u,t]) r1 = eq[0].match(diff(x(t),t) - f) r2 = eq[1].match(diff(y(t),t) - g) num, den = ( (r1[f].subs(x(t),u).subs(y(t),v))/ (r2[g].subs(x(t),u).subs(y(t),v))).as_numer_denom() R1 = num.match(f1*g1) R2 = den.match(f2*g2) phi = (r1[f].subs(x(t),u).subs(y(t),v))/num F1 = R1[f1]; F2 = R2[f2] G1 = R1[g1]; G2 = R2[g2] sol1r = solve(Integral(F2/F1, u).doit() - Integral(G1/G2,v).doit() - C1, u) sol2r = solve(Integral(F2/F1, u).doit() - Integral(G1/G2,v).doit() - C1, v) sol = [] for sols in sol1r: sol.append(Eq(y(t), dsolve(diff(V(t),t) - F2.subs(u,sols).subs(v,V(t))*G2.subs(v,V(t))*phi.subs(u,sols).subs(v,V(t))).rhs)) for sols in sol2r: sol.append(Eq(x(t), dsolve(diff(U(t),t) - F1.subs(u,U(t))*G1.subs(v,sols).subs(u,U(t))*phi.subs(v,sols).subs(u,U(t))).rhs)) return set(sol) def _nonlinear_2eq_order1_type5(func, t, eq): r""" Clairaut system of ODEs .. math:: x = t x' + F(x',y') .. math:: y = t y' + G(x',y') The following are solutions of the system `(i)` straight lines: .. math:: x = C_1 t + F(C_1, C_2), y = C_2 t + G(C_1, C_2) where `C_1` and `C_2` are arbitrary constants; `(ii)` envelopes of the above lines; `(iii)` continuously differentiable lines made up from segments of the lines `(i)` and `(ii)`. """ C1, C2 = get_numbered_constants(eq, num=2) f = Wild('f') g = Wild('g') def check_type(x, y): r1 = eq[0].match(t*diff(x(t),t) - x(t) + f) r2 = eq[1].match(t*diff(y(t),t) - y(t) + g) if not (r1 and r2): r1 = eq[0].match(diff(x(t),t) - x(t)/t + f/t) r2 = eq[1].match(diff(y(t),t) - y(t)/t + g/t) if not (r1 and r2): r1 = (-eq[0]).match(t*diff(x(t),t) - x(t) + f) r2 = (-eq[1]).match(t*diff(y(t),t) - y(t) + g) if not (r1 and r2): r1 = (-eq[0]).match(diff(x(t),t) - x(t)/t + f/t) r2 = (-eq[1]).match(diff(y(t),t) - y(t)/t + g/t) return [r1, r2] for func_ in func: if isinstance(func_, list): x = func[0][0].func y = func[0][1].func [r1, r2] = check_type(x, y) if not (r1 and r2): [r1, r2] = check_type(y, x) x, y = y, x x1 = diff(x(t),t); y1 = diff(y(t),t) return {Eq(x(t), C1*t + r1[f].subs(x1,C1).subs(y1,C2)), Eq(y(t), C2*t + r2[g].subs(x1,C1).subs(y1,C2))} def sysode_nonlinear_3eq_order1(match_): x = match_['func'][0].func y = match_['func'][1].func z = match_['func'][2].func eq = match_['eq'] t = list(list(eq[0].atoms(Derivative))[0].atoms(Symbol))[0] if match_['type_of_equation'] == 'type1': sol = _nonlinear_3eq_order1_type1(x, y, z, t, eq) if match_['type_of_equation'] == 'type2': sol = _nonlinear_3eq_order1_type2(x, y, z, t, eq) if match_['type_of_equation'] == 'type3': sol = _nonlinear_3eq_order1_type3(x, y, z, t, eq) if match_['type_of_equation'] == 'type4': sol = _nonlinear_3eq_order1_type4(x, y, z, t, eq) if match_['type_of_equation'] == 'type5': sol = _nonlinear_3eq_order1_type5(x, y, z, t, eq) return sol def _nonlinear_3eq_order1_type1(x, y, z, t, eq): r""" Equations: .. math:: a x' = (b - c) y z, \enspace b y' = (c - a) z x, \enspace c z' = (a - b) x y First Integrals: .. math:: a x^{2} + b y^{2} + c z^{2} = C_1 .. math:: a^{2} x^{2} + b^{2} y^{2} + c^{2} z^{2} = C_2 where `C_1` and `C_2` are arbitrary constants. On solving the integrals for `y` and `z` and on substituting the resulting expressions into the first equation of the system, we arrives at a separable first-order equation on `x`. Similarly doing that for other two equations, we will arrive at first order equation on `y` and `z` too. References ========== -http://eqworld.ipmnet.ru/en/solutions/sysode/sode0401.pdf """ C1, C2 = get_numbered_constants(eq, num=2) u, v, w = symbols('u, v, w') p = Wild('p', exclude=[x(t), y(t), z(t), t]) q = Wild('q', exclude=[x(t), y(t), z(t), t]) s = Wild('s', exclude=[x(t), y(t), z(t), t]) r = (diff(x(t),t) - eq[0]).match(p*y(t)*z(t)) r.update((diff(y(t),t) - eq[1]).match(q*z(t)*x(t))) r.update((diff(z(t),t) - eq[2]).match(s*x(t)*y(t))) n1, d1 = r[p].as_numer_denom() n2, d2 = r[q].as_numer_denom() n3, d3 = r[s].as_numer_denom() val = solve([n1*u-d1*v+d1*w, d2*u+n2*v-d2*w, d3*u-d3*v-n3*w],[u,v]) vals = [val[v], val[u]] c = lcm(vals[0].as_numer_denom()[1], vals[1].as_numer_denom()[1]) b = vals[0].subs(w, c) a = vals[1].subs(w, c) y_x = sqrt(((c*C1-C2) - a*(c-a)*x(t)**2)/(b*(c-b))) z_x = sqrt(((b*C1-C2) - a*(b-a)*x(t)**2)/(c*(b-c))) z_y = sqrt(((a*C1-C2) - b*(a-b)*y(t)**2)/(c*(a-c))) x_y = sqrt(((c*C1-C2) - b*(c-b)*y(t)**2)/(a*(c-a))) x_z = sqrt(((b*C1-C2) - c*(b-c)*z(t)**2)/(a*(b-a))) y_z = sqrt(((a*C1-C2) - c*(a-c)*z(t)**2)/(b*(a-b))) sol1 = dsolve(a*diff(x(t),t) - (b-c)*y_x*z_x) sol2 = dsolve(b*diff(y(t),t) - (c-a)*z_y*x_y) sol3 = dsolve(c*diff(z(t),t) - (a-b)*x_z*y_z) return [sol1, sol2, sol3] def _nonlinear_3eq_order1_type2(x, y, z, t, eq): r""" Equations: .. math:: a x' = (b - c) y z f(x, y, z, t) .. math:: b y' = (c - a) z x f(x, y, z, t) .. math:: c z' = (a - b) x y f(x, y, z, t) First Integrals: .. math:: a x^{2} + b y^{2} + c z^{2} = C_1 .. math:: a^{2} x^{2} + b^{2} y^{2} + c^{2} z^{2} = C_2 where `C_1` and `C_2` are arbitrary constants. On solving the integrals for `y` and `z` and on substituting the resulting expressions into the first equation of the system, we arrives at a first-order differential equations on `x`. Similarly doing that for other two equations we will arrive at first order equation on `y` and `z`. References ========== -http://eqworld.ipmnet.ru/en/solutions/sysode/sode0402.pdf """ C1, C2 = get_numbered_constants(eq, num=2) u, v, w = symbols('u, v, w') p = Wild('p', exclude=[x(t), y(t), z(t), t]) q = Wild('q', exclude=[x(t), y(t), z(t), t]) s = Wild('s', exclude=[x(t), y(t), z(t), t]) f = Wild('f') r1 = (diff(x(t),t) - eq[0]).match(y(t)*z(t)*f) r = collect_const(r1[f]).match(p*f) r.update(((diff(y(t),t) - eq[1])/r[f]).match(q*z(t)*x(t))) r.update(((diff(z(t),t) - eq[2])/r[f]).match(s*x(t)*y(t))) n1, d1 = r[p].as_numer_denom() n2, d2 = r[q].as_numer_denom() n3, d3 = r[s].as_numer_denom() val = solve([n1*u-d1*v+d1*w, d2*u+n2*v-d2*w, -d3*u+d3*v+n3*w],[u,v]) vals = [val[v], val[u]] c = lcm(vals[0].as_numer_denom()[1], vals[1].as_numer_denom()[1]) a = vals[0].subs(w, c) b = vals[1].subs(w, c) y_x = sqrt(((c*C1-C2) - a*(c-a)*x(t)**2)/(b*(c-b))) z_x = sqrt(((b*C1-C2) - a*(b-a)*x(t)**2)/(c*(b-c))) z_y = sqrt(((a*C1-C2) - b*(a-b)*y(t)**2)/(c*(a-c))) x_y = sqrt(((c*C1-C2) - b*(c-b)*y(t)**2)/(a*(c-a))) x_z = sqrt(((b*C1-C2) - c*(b-c)*z(t)**2)/(a*(b-a))) y_z = sqrt(((a*C1-C2) - c*(a-c)*z(t)**2)/(b*(a-b))) sol1 = dsolve(a*diff(x(t),t) - (b-c)*y_x*z_x*r[f]) sol2 = dsolve(b*diff(y(t),t) - (c-a)*z_y*x_y*r[f]) sol3 = dsolve(c*diff(z(t),t) - (a-b)*x_z*y_z*r[f]) return [sol1, sol2, sol3] def _nonlinear_3eq_order1_type3(x, y, z, t, eq): r""" Equations: .. math:: x' = c F_2 - b F_3, \enspace y' = a F_3 - c F_1, \enspace z' = b F_1 - a F_2 where `F_n = F_n(x, y, z, t)`. 1. First Integral: .. math:: a x + b y + c z = C_1, where C is an arbitrary constant. 2. If we assume function `F_n` to be independent of `t`,i.e, `F_n` = `F_n (x, y, z)` Then, on eliminating `t` and `z` from the first two equation of the system, one arrives at the first-order equation .. math:: \frac{dy}{dx} = \frac{a F_3 (x, y, z) - c F_1 (x, y, z)}{c F_2 (x, y, z) - b F_3 (x, y, z)} where `z = \frac{1}{c} (C_1 - a x - b y)` References ========== -http://eqworld.ipmnet.ru/en/solutions/sysode/sode0404.pdf """ C1 = get_numbered_constants(eq, num=1) u, v, w = symbols('u, v, w') fu, fv, fw = symbols('u, v, w', cls=Function) p = Wild('p', exclude=[x(t), y(t), z(t), t]) q = Wild('q', exclude=[x(t), y(t), z(t), t]) s = Wild('s', exclude=[x(t), y(t), z(t), t]) F1, F2, F3 = symbols('F1, F2, F3', cls=Wild) r1 = (diff(x(t), t) - eq[0]).match(F2-F3) r = collect_const(r1[F2]).match(s*F2) r.update(collect_const(r1[F3]).match(q*F3)) if eq[1].has(r[F2]) and not eq[1].has(r[F3]): r[F2], r[F3] = r[F3], r[F2] r[s], r[q] = -r[q], -r[s] r.update((diff(y(t), t) - eq[1]).match(p*r[F3] - r[s]*F1)) a = r[p]; b = r[q]; c = r[s] F1 = r[F1].subs(x(t), u).subs(y(t),v).subs(z(t), w) F2 = r[F2].subs(x(t), u).subs(y(t),v).subs(z(t), w) F3 = r[F3].subs(x(t), u).subs(y(t),v).subs(z(t), w) z_xy = (C1-a*u-b*v)/c y_zx = (C1-a*u-c*w)/b x_yz = (C1-b*v-c*w)/a y_x = dsolve(diff(fv(u),u) - ((a*F3-c*F1)/(c*F2-b*F3)).subs(w,z_xy).subs(v,fv(u))).rhs z_x = dsolve(diff(fw(u),u) - ((b*F1-a*F2)/(c*F2-b*F3)).subs(v,y_zx).subs(w,fw(u))).rhs z_y = dsolve(diff(fw(v),v) - ((b*F1-a*F2)/(a*F3-c*F1)).subs(u,x_yz).subs(w,fw(v))).rhs x_y = dsolve(diff(fu(v),v) - ((c*F2-b*F3)/(a*F3-c*F1)).subs(w,z_xy).subs(u,fu(v))).rhs y_z = dsolve(diff(fv(w),w) - ((a*F3-c*F1)/(b*F1-a*F2)).subs(u,x_yz).subs(v,fv(w))).rhs x_z = dsolve(diff(fu(w),w) - ((c*F2-b*F3)/(b*F1-a*F2)).subs(v,y_zx).subs(u,fu(w))).rhs sol1 = dsolve(diff(fu(t),t) - (c*F2 - b*F3).subs(v,y_x).subs(w,z_x).subs(u,fu(t))).rhs sol2 = dsolve(diff(fv(t),t) - (a*F3 - c*F1).subs(u,x_y).subs(w,z_y).subs(v,fv(t))).rhs sol3 = dsolve(diff(fw(t),t) - (b*F1 - a*F2).subs(u,x_z).subs(v,y_z).subs(w,fw(t))).rhs return [sol1, sol2, sol3] def _nonlinear_3eq_order1_type4(x, y, z, t, eq): r""" Equations: .. math:: x' = c z F_2 - b y F_3, \enspace y' = a x F_3 - c z F_1, \enspace z' = b y F_1 - a x F_2 where `F_n = F_n (x, y, z, t)` 1. First integral: .. math:: a x^{2} + b y^{2} + c z^{2} = C_1 where `C` is an arbitrary constant. 2. Assuming the function `F_n` is independent of `t`: `F_n = F_n (x, y, z)`. Then on eliminating `t` and `z` from the first two equations of the system, one arrives at the first-order equation .. math:: \frac{dy}{dx} = \frac{a x F_3 (x, y, z) - c z F_1 (x, y, z)} {c z F_2 (x, y, z) - b y F_3 (x, y, z)} where `z = \pm \sqrt{\frac{1}{c} (C_1 - a x^{2} - b y^{2})}` References ========== -http://eqworld.ipmnet.ru/en/solutions/sysode/sode0405.pdf """ C1 = get_numbered_constants(eq, num=1) u, v, w = symbols('u, v, w') p = Wild('p', exclude=[x(t), y(t), z(t), t]) q = Wild('q', exclude=[x(t), y(t), z(t), t]) s = Wild('s', exclude=[x(t), y(t), z(t), t]) F1, F2, F3 = symbols('F1, F2, F3', cls=Wild) r1 = eq[0].match(diff(x(t),t) - z(t)*F2 + y(t)*F3) r = collect_const(r1[F2]).match(s*F2) r.update(collect_const(r1[F3]).match(q*F3)) if eq[1].has(r[F2]) and not eq[1].has(r[F3]): r[F2], r[F3] = r[F3], r[F2] r[s], r[q] = -r[q], -r[s] r.update((diff(y(t),t) - eq[1]).match(p*x(t)*r[F3] - r[s]*z(t)*F1)) a = r[p]; b = r[q]; c = r[s] F1 = r[F1].subs(x(t),u).subs(y(t),v).subs(z(t),w) F2 = r[F2].subs(x(t),u).subs(y(t),v).subs(z(t),w) F3 = r[F3].subs(x(t),u).subs(y(t),v).subs(z(t),w) x_yz = sqrt((C1 - b*v**2 - c*w**2)/a) y_zx = sqrt((C1 - c*w**2 - a*u**2)/b) z_xy = sqrt((C1 - a*u**2 - b*v**2)/c) y_x = dsolve(diff(v(u),u) - ((a*u*F3-c*w*F1)/(c*w*F2-b*v*F3)).subs(w,z_xy).subs(v,v(u))).rhs z_x = dsolve(diff(w(u),u) - ((b*v*F1-a*u*F2)/(c*w*F2-b*v*F3)).subs(v,y_zx).subs(w,w(u))).rhs z_y = dsolve(diff(w(v),v) - ((b*v*F1-a*u*F2)/(a*u*F3-c*w*F1)).subs(u,x_yz).subs(w,w(v))).rhs x_y = dsolve(diff(u(v),v) - ((c*w*F2-b*v*F3)/(a*u*F3-c*w*F1)).subs(w,z_xy).subs(u,u(v))).rhs y_z = dsolve(diff(v(w),w) - ((a*u*F3-c*w*F1)/(b*v*F1-a*u*F2)).subs(u,x_yz).subs(v,v(w))).rhs x_z = dsolve(diff(u(w),w) - ((c*w*F2-b*v*F3)/(b*v*F1-a*u*F2)).subs(v,y_zx).subs(u,u(w))).rhs sol1 = dsolve(diff(u(t),t) - (c*w*F2 - b*v*F3).subs(v,y_x).subs(w,z_x).subs(u,u(t))).rhs sol2 = dsolve(diff(v(t),t) - (a*u*F3 - c*w*F1).subs(u,x_y).subs(w,z_y).subs(v,v(t))).rhs sol3 = dsolve(diff(w(t),t) - (b*v*F1 - a*u*F2).subs(u,x_z).subs(v,y_z).subs(w,w(t))).rhs return [sol1, sol2, sol3] def _nonlinear_3eq_order1_type5(x, y, z, t, eq): r""" .. math:: x' = x (c F_2 - b F_3), \enspace y' = y (a F_3 - c F_1), \enspace z' = z (b F_1 - a F_2) where `F_n = F_n (x, y, z, t)` and are arbitrary functions. First Integral: .. math:: \left|x\right|^{a} \left|y\right|^{b} \left|z\right|^{c} = C_1 where `C` is an arbitrary constant. If the function `F_n` is independent of `t`, then, by eliminating `t` and `z` from the first two equations of the system, one arrives at a first-order equation. References ========== -http://eqworld.ipmnet.ru/en/solutions/sysode/sode0406.pdf """ C1 = get_numbered_constants(eq, num=1) u, v, w = symbols('u, v, w') fu, fv, fw = symbols('u, v, w', cls=Function) p = Wild('p', exclude=[x(t), y(t), z(t), t]) q = Wild('q', exclude=[x(t), y(t), z(t), t]) s = Wild('s', exclude=[x(t), y(t), z(t), t]) F1, F2, F3 = symbols('F1, F2, F3', cls=Wild) r1 = eq[0].match(diff(x(t), t) - x(t)*F2 + x(t)*F3) r = collect_const(r1[F2]).match(s*F2) r.update(collect_const(r1[F3]).match(q*F3)) if eq[1].has(r[F2]) and not eq[1].has(r[F3]): r[F2], r[F3] = r[F3], r[F2] r[s], r[q] = -r[q], -r[s] r.update((diff(y(t), t) - eq[1]).match(y(t)*(p*r[F3] - r[s]*F1))) a = r[p]; b = r[q]; c = r[s] F1 = r[F1].subs(x(t), u).subs(y(t), v).subs(z(t), w) F2 = r[F2].subs(x(t), u).subs(y(t), v).subs(z(t), w) F3 = r[F3].subs(x(t), u).subs(y(t), v).subs(z(t), w) x_yz = (C1*v**-b*w**-c)**-a y_zx = (C1*w**-c*u**-a)**-b z_xy = (C1*u**-a*v**-b)**-c y_x = dsolve(diff(fv(u), u) - ((v*(a*F3 - c*F1))/(u*(c*F2 - b*F3))).subs(w, z_xy).subs(v, fv(u))).rhs z_x = dsolve(diff(fw(u), u) - ((w*(b*F1 - a*F2))/(u*(c*F2 - b*F3))).subs(v, y_zx).subs(w, fw(u))).rhs z_y = dsolve(diff(fw(v), v) - ((w*(b*F1 - a*F2))/(v*(a*F3 - c*F1))).subs(u, x_yz).subs(w, fw(v))).rhs x_y = dsolve(diff(fu(v), v) - ((u*(c*F2 - b*F3))/(v*(a*F3 - c*F1))).subs(w, z_xy).subs(u, fu(v))).rhs y_z = dsolve(diff(fv(w), w) - ((v*(a*F3 - c*F1))/(w*(b*F1 - a*F2))).subs(u, x_yz).subs(v, fv(w))).rhs x_z = dsolve(diff(fu(w), w) - ((u*(c*F2 - b*F3))/(w*(b*F1 - a*F2))).subs(v, y_zx).subs(u, fu(w))).rhs sol1 = dsolve(diff(fu(t), t) - (u*(c*F2 - b*F3)).subs(v, y_x).subs(w, z_x).subs(u, fu(t))).rhs sol2 = dsolve(diff(fv(t), t) - (v*(a*F3 - c*F1)).subs(u, x_y).subs(w, z_y).subs(v, fv(t))).rhs sol3 = dsolve(diff(fw(t), t) - (w*(b*F1 - a*F2)).subs(u, x_z).subs(v, y_z).subs(w, fw(t))).rhs return [sol1, sol2, sol3] #This import is written at the bottom to avoid circular imports. from .single import SingleODEProblem, SingleODESolver, solver_map sympy-sympy-1.9/sympy/solvers/ode/riccati.py000066400000000000000000000737061412543434000213550ustar00rootroot00000000000000r""" This module contains :py:meth:`~sympy.solvers.ode.riccati.solve_riccati`, a function which gives all rational particular solutions to first order Riccati ODEs. A general first order Riccati ODE is given by - .. math:: y' = b_0(x) + b_1(x)w + b_2(x)w^2 where `b_0, b_1` and `b_2` can be arbitrary rational functions of `x` with `b_2 \ne 0`. When `b_2 = 0`, the equation is not a Riccati ODE anymore and becomes a Linear ODE. Similarly, when `b_0 = 0`, the equation is a Bernoulli ODE. The algorithm presented below can find rational solution(s) to all ODEs with `b_2 \ne 0` that have a rational solution, or prove that no rational solution exists for the equation. Background ========== A Riccati equation can be transformed to its normal form .. math:: y' + y^2 = a(x) using the transformation .. math:: y = -b_2(x) - \frac{b'_2(x)}{2 b_2(x)} - \frac{b_1(x)}{2} where `a(x)` is given by .. math:: a(x) = \frac{1}{4}\left(\frac{b_2'}{b_2} + b_1\right)^2 - \frac{1}{2}\left(\frac{b_2'}{b_2} + b_1\right)' - b_0 b_2 Thus, we can develop an algorithm to solve for the Riccati equation in its normal form, which would in turn give us the solution for the original Riccati equation. Algorithm ========= The algorithm implemented here is presented in the Ph.D thesis "Rational and Algebraic Solutions of First-Order Algebraic ODEs" by N. Thieu Vo. The entire thesis can be found here - https://www3.risc.jku.at/publications/download/risc_5387/PhDThesisThieu.pdf We have only implemented the Rational Riccati solver (Algorithm 11, Pg 78-82 in Thesis). Before we proceed towards the implementation of the algorithm, a few definitions to understand are - 1. Valuation of a Rational Function at `\infty`: The valuation of a rational function `p(x)` at `\infty` is equal to the difference between the degree of the denominator and the numerator of `p(x)`. NOTE: A general definition of valuation of a rational function at any value of `x` can be found in Pg 63 of the thesis, but is not of any interest for this algorithm. 2. Zeros and Poles of a Rational Function: Let `a(x) = \frac{S(x)}{T(x)}, T \ne 0` be a rational function of `x`. Then - a. The Zeros of `a(x)` are the roots of `S(x)`. b. The Poles of `a(x)` are the roots of `T(x)`. However, `\infty` can also be a pole of a(x). We say that `a(x)` has a pole at `\infty` if `a(\frac{1}{x})` has a pole at 0. Every pole is associated with an order that is equal to the multiplicity of its appearence as a root of `T(x)`. A pole is called a simple pole if it has an order 1. Similarly, a pole is called a multiple pole if it has an order `\ge` 2. Necessary Conditions ==================== For a Riccati equation in its normal form, .. math:: y' + y^2 = a(x) we can define a. A pole is called a movable pole if it is a pole of `y(x)` and is not a pole of `a(x)`. b. Similarly, a pole is called a non-movable pole if it is a pole of both `y(x)` and `a(x)`. Then, the algorithm states that a rational solution exists only if - a. Every pole of `a(x)` must be either a simple pole or a multiple pole of even order. b. The valuation of `a(x)` at `\infty` must be even or be `\ge` 2. This algorithm finds all possible rational solutions for the Riccati ODE. If no rational solutions are found, it means that no rational solutions exist. The algorithm works for Riccati ODEs where the coefficients are rational functions in the independent variable `x` with rational number coefficients i.e. in `Q(x)`. The coefficients in the rational function cannot be floats, irrational numbers, symbols or any other kind of expression. The reasons for this are - 1. When using symbols, different symbols could take the same value and this would affect the multiplicity of poles if symbols are present here. 2. An integer degree bound is required to calculate a polynomial solution to an auxiliary differential equation, which in turn gives the particular solution for the original ODE. If symbols/floats/irrational numbers are present, we cannot determine if the expression for the degree bound is an integer or not. Solution ======== With these definitions, we can state a general form for the solution of the equation. `y(x)` must have the form - .. math:: y(x) = \sum_{i=1}^{n} \sum_{j=1}^{r_i} \frac{c_{ij}}{(x - x_i)^j} + \sum_{i=1}^{m} \frac{1}{x - \chi_i} + \sum_{i=0}^{N} d_i x^i where `x_1, x_2, ..., x_n` are non-movable poles of `a(x)`, `\chi_1, \chi_2, ..., \chi_m` are movable poles of `a(x)`, and the values of `N, n, r_1, r_2, ..., r_n` can be determined from `a(x)`. The coefficient vectors `(d_0, d_1, ..., d_N)` and `(c_{i1}, c_{i2}, ..., c_{i r_i})` can be determined from `a(x)`. We will have 2 choices each of these vectors and part of the procedure is figuring out which of the 2 should be used to get the solution correctly. Implementation ============== In this implementatin, we use ``Poly`` to represent a rational function rather than using ``Expr`` since ``Poly`` is much faster. Since we cannot represent rational functions directly using ``Poly``, we instead represent a rational function with 2 ``Poly`` objects - one for its numerator and the other for its denominator. The code is written to match the steps given in the thesis (Pg 82) Step 0 : Match the equation - Find `b_0, b_1` and `b_2`. If `b_2 = 0` or no such functions exist, raise an error Step 1 : Transform the equation to its normal form as explained in the theory section. Step 2 : Initialize an empty set of solutions, ``sol``. Step 3 : If `a(x) = 0`, append `\frac{1}/{(x - C1)}` to ``sol``. Step 4 : If `a(x)` is a rational non-zero number, append `\pm \sqrt{a}` to ``sol``. Step 5 : Find the poles and their multiplicities of `a(x)`. Let the number of poles be `n`. Also find the valuation of `a(x)` at `\infty` using ``val_at_inf``. NOTE: Although the algorithm considers `\infty` as a pole, it is not mentioned if it a part of the set of finite poles. `\infty` is NOT a part of the set of finite poles. If a pole exists at `\infty`, we use its multiplicty to find the laurent series of `a(x)` about `\infty`. Step 6 : Find `n` c-vectors (one for each pole) and 1 d-vector using ``construct_c`` and ``construct_d``. Now, determine all the ``2**(n + 1)`` combinations of choosing between 2 choices for each of the `n` c-vectors and 1 d-vector. NOTE: The equation for `d_{-1}` in Case 4 (Pg 80) has a printinig mistake. The term `- d_N` must be replaced with `-N d_N`. The same has been explained in the code as well. For each of these above combinations, do Step 8 : Compute `m` in ``compute_m_ybar``. `m` is the degree bound of the polynomial solution we must find for the auxiliary equation. Step 9 : In ``compute_m_ybar``, compute ybar as well where ``ybar`` is one part of y(x) - .. math:: \overline{y}(x) = \sum_{i=1}^{n} \sum_{j=1}^{r_i} \frac{c_{ij}}{(x - x_i)^j} + \sum_{i=0}^{N} d_i x^i Step 10 : If `m` is a non-negative integer - Step 11: Find a polynomial solution of degree `m` for the auxiliary equation. There are 2 cases possible - a. `m` is a non-negative integer: We can solve for the coefficients in `p(x)` using Undetermined Coefficients. b. `m` is not a non-negative integer: In this case, we cannot find a polynomial solution to the auxiliary equation, and hence, we ignore this value of `m`. Step 12 : For each `p(x)` that exists, append `ybar + \frac{p'(x)}{p(x)}` to ``sol``. Step 13 : For each solution in ``sol``, apply an inverse transformation, so that the solutions of the original equation are found using the solutions of the equation in its normal form. """ from itertools import product from sympy.core import S from sympy.core.add import Add from sympy.core.numbers import oo, Float from sympy.core.function import count_ops from sympy.core.relational import Eq from sympy.core.symbol import symbols, Symbol, Dummy from sympy.functions import sqrt, exp from sympy.functions.elementary.complexes import sign from sympy.integrals.integrals import Integral from sympy.polys.domains import ZZ from sympy.polys.polytools import Poly from sympy.polys.polyroots import roots from sympy.solvers.solveset import linsolve def riccati_normal(w, x, b1, b2): """ Given a solution `w(x)` to the equation .. math:: w'(x) = b_0(x) + b_1(x)*w(x) + b_2(x)*w(x)^2 and rational function coefficients `b_1(x)` and `b_2(x)`, this function transforms the solution to give a solution `y(x)` for its corresponding normal Riccati ODE .. math:: y'(x) + y(x)^2 = a(x) using the transformation .. math:: y(x) = -b_2(x)*w(x) - b'_2(x)/(2*b_2(x)) - b_1(x)/2 """ return -b2*w - b2.diff(x)/(2*b2) - b1/2 def riccati_inverse_normal(y, x, b1, b2, bp=None): """ Inverse transforming the solution to the normal Riccati ODE to get the solution to the Riccati ODE. """ # bp is the expression which is independent of the solution # and hence, it need not be computed again if bp is None: bp = -b2.diff(x)/(2*b2**2) - b1/(2*b2) # w(x) = -y(x)/b2(x) - b2'(x)/(2*b2(x)^2) - b1(x)/(2*b2(x)) return -y/b2 + bp def riccati_reduced(eq, f, x): """ Convert a Riccati ODE into its corresponding normal Riccati ODE. """ match, funcs = match_riccati(eq, f, x) # If equation is not a Riccati ODE, exit if not match: return False # Using the rational functions, find the expression for a(x) b0, b1, b2 = funcs a = -b0*b2 + b1**2/4 - b1.diff(x)/2 + 3*b2.diff(x)**2/(4*b2**2) + b1*b2.diff(x)/(2*b2) - \ b2.diff(x, 2)/(2*b2) # Normal form of Riccati ODE is f'(x) + f(x)^2 = a(x) return f(x).diff(x) + f(x)**2 - a def linsolve_dict(eq, syms): """ Get the output of linsolve as a dict """ # Convert tuple type return value of linsolve # to a dictionary for ease of use sol = linsolve(eq, syms) if not sol: return {} return {k:v for k, v in zip(syms, list(sol)[0])} def match_riccati(eq, f, x): """ A function that matches and returns the coefficients if an equation is a Riccati ODE Parameters ========== eq: Equation to be matched f: Dependent variable x: Independent variable Returns ======= match: True if equation is a Riccati ODE, False otherwise funcs: [b0, b1, b2] if match is True, [] otherwise. Here, b0, b1 and b2 are rational functions which match the equation. """ # Group terms based on f(x) if isinstance(eq, Eq): eq = eq.lhs - eq.rhs eq = eq.expand().collect(f(x)) cf = eq.coeff(f(x).diff(x)) # There must be an f(x).diff(x) term. # eq must be an Add object since we are using the expanded # equation and it must have atleast 2 terms (b2 != 0) if cf != 0 and isinstance(eq, Add): # Divide all coefficients by the coefficient of f(x).diff(x) # and add the terms again to get the same equation eq = Add(*((x/cf).cancel() for x in eq.args)).collect(f(x)) # Match the equation with the pattern b1 = -eq.coeff(f(x)) b2 = -eq.coeff(f(x)**2) b0 = (f(x).diff(x) - b1*f(x) - b2*f(x)**2 - eq).expand() funcs = [b0, b1, b2] # Check if coefficients are not symbols and floats if any([len(x.atoms(Symbol)) > 1 or len(x.atoms(Float)) for x in [b0, b1, b2]]): return False, [] # If b_0(x) contains f(x), it is not a Riccati ODE if len(b0.atoms(f)) or not all([b2 != 0, b0.is_rational_function(x), \ b1.is_rational_function(x), b2.is_rational_function(x)]): return False, [] return True, funcs return False, [] def val_at_inf(num, den, x): # Valuation of a rational function at oo = deg(denom) - deg(numer) return den.degree(x) - num.degree(x) def check_necessary_conds(val_inf, muls): """ The necessary conditions for a rational solution to exist are as follows - i) Every pole of a(x) must be either a simple pole or a multiple pole of even order. ii) The valuation of a(x) at infinity must be even or be greater than or equal to 2. Here, a simple pole is a pole with multiplicity 1 and a multiple pole is a pole with multiplicity greater than 1. """ return (val_inf >= 2 or (val_inf <= 0 and val_inf%2 == 0)) and \ all([mul == 1 or (mul%2 == 0 and mul >= 2) for mul in muls]) def inverse_transform_poly(num, den, x): """ A function to make the substitution x -> 1/x in a rational function that is represented using Poly objects for numerator and denominator. """ # Declare for reuse one = Poly(1, x) xpoly = Poly(x, x) # Check if degree of numerator is same as denominator pwr = val_at_inf(num, den, x) if pwr >= 0: # Denominator has greater degree. Substituting x with # 1/x would make the extra power go to the numerator if num.expr != 0: num = num.transform(one, xpoly) * x**pwr den = den.transform(one, xpoly) else: # Numerator has greater degree. Substituting x with # 1/x would make the extra power go to the denominator num = num.transform(one, xpoly) den = den.transform(one, xpoly) * x**(-pwr) return num.cancel(den, include=True) def limit_at_inf(num, den, x): """ Find the limit of a rational function at oo """ # pwr = degree(num) - degree(den) pwr = -val_at_inf(num, den, x) # Numerator has a greater degree than denominator # Limit at infinity would depend on the sign of the # leading coefficients of numerator and denominator if pwr > 0: return oo*sign(num.LC()/den.LC()) # Degree of numerator is equal to that of denominator # Limit at infinity is just the ratio of leading coeffs elif pwr == 0: return num.LC()/den.LC() # Degree of numerator is less than that of denominator # Limit at infinity is just 0 else: return 0 def construct_c_case_1(num, den, x, pole): # Find the coefficient of 1/(x - pole)**2 in the # Laurent series expansion of a(x) about pole. num1, den1 = (num*Poly((x - pole)**2, x, extension=True)).cancel(den, include=True) r = (num1.subs(x, pole))/(den1.subs(x, pole)) # If multiplicity is 2, the coefficient to be added # in the c-vector is c = (1 +- sqrt(1 + 4*r))/2 if r != -S(1)/4: return [[(1 + sqrt(1 + 4*r))/2], [(1 - sqrt(1 + 4*r))/2]] return [[S(1)/2]] def construct_c_case_2(num, den, x, pole, mul): # Generate the coefficients using the recurrence # relation mentioned in (5.14) in the thesis (Pg 80) # r_i = mul/2 ri = mul//2 # Find the Laurent series coefficients about the pole ser = rational_laurent_series(num, den, x, pole, mul, 6) # Start with an empty memo to store the coefficients # This is for the plus case cplus = [0 for i in range(ri)] # Base Case cplus[ri-1] = sqrt(ser[2*ri]) # Iterate backwards to find all coefficients s = ri - 1 sm = 0 for s in range(ri-1, 0, -1): sm = 0 for j in range(s+1, ri): sm += cplus[j-1]*cplus[ri+s-j-1] if s!= 1: cplus[s-1] = (ser[ri+s] - sm)/(2*cplus[ri-1]) # Memo for the minus case cminus = [-x for x in cplus] # Find the 0th coefficient in the recurrence cplus[0] = (ser[ri+s] - sm - ri*cplus[ri-1])/(2*cplus[ri-1]) cminus[0] = (ser[ri+s] - sm - ri*cminus[ri-1])/(2*cminus[ri-1]) # Add both the plus and minus cases' coefficients if cplus != cminus: return [cplus, cminus] return cplus def construct_c_case_3(): # If multiplicity is 1, the coefficient to be added # in the c-vector is 1 (no choice) return [[1]] def construct_c(num, den, x, poles, muls): """ Helper function to calculate the coefficients in the c-vector for each pole. """ c = [] for pole, mul in zip(poles, muls): c.append([]) # Case 3 if mul == 1: # Add the coefficients from Case 3 c[-1].extend(construct_c_case_3()) # Case 1 elif mul == 2: # Add the coefficients from Case 1 c[-1].extend(construct_c_case_1(num, den, x, pole)) # Case 2 else: # Add the coefficients from Case 2 c[-1].extend(construct_c_case_2(num, den, x, pole, mul)) return c def construct_d_case_4(ser, N): # Initialize an empty vector dplus = [0 for i in range(N+2)] # d_N = sqrt(a_{2*N}) dplus[N] = sqrt(ser[2*N]) # Use the recurrence relations to find # the value of d_s for s in range(N-1, -2, -1): sm = 0 for j in range(s+1, N): sm += dplus[j]*dplus[N+s-j] if s != -1: dplus[s] = (ser[N+s] - sm)/(2*dplus[N]) # Coefficients for the case of d_N = -sqrt(a_{2*N}) dminus = [-x for x in dplus] # The third equation in Eq 5.15 of the thesis is WRONG! # d_N must be replaced with N*d_N in that equation. dplus[-1] = (ser[N+s] - N*dplus[N] - sm)/(2*dplus[N]) dminus[-1] = (ser[N+s] - N*dminus[N] - sm)/(2*dminus[N]) if dplus != dminus: return [dplus, dminus] return dplus def construct_d_case_5(ser): # List to store coefficients for plus case dplus = [0, 0] # d_0 = sqrt(a_0) dplus[0] = sqrt(ser[0]) # d_(-1) = a_(-1)/(2*d_0) dplus[-1] = ser[-1]/(2*dplus[0]) # Coefficients for the minus case are just the negative # of the coefficients for the positive case. dminus = [-x for x in dplus] if dplus != dminus: return [dplus, dminus] return dplus def construct_d_case_6(num, den, x): # s_oo = lim x->0 1/x**2 * a(1/x) which is equivalent to # s_oo = lim x->oo x**2 * a(x) s_inf = limit_at_inf(Poly(x**2, x)*num, den, x) # d_(-1) = (1 +- sqrt(1 + 4*s_oo))/2 if s_inf != -S(1)/4: return [[(1 + sqrt(1 + 4*s_inf))/2], [(1 - sqrt(1 + 4*s_inf))/2]] return [[S(1)/2]] def construct_d(num, den, x, val_inf): """ Helper function to calculate the coefficients in the d-vector based on the valuation of the function at oo. """ N = -val_inf//2 # Multiplicity of oo as a pole mul = -val_inf if val_inf < 0 else 0 ser = rational_laurent_series(num, den, x, oo, mul, 1) # Case 4 if val_inf < 0: d = construct_d_case_4(ser, N) # Case 5 elif val_inf == 0: d = construct_d_case_5(ser) # Case 6 else: d = construct_d_case_6(num, den, x) return d def rational_laurent_series(num, den, x, r, m, n): r""" The function computes the Laurent series coefficients of a rational function. Parameters ========== num: A Poly object that is the numerator of `f(x)`. den: A Poly object that is the denominator of `f(x)`. x: The variable of expansion of the series. r: The point of expansion of the series. m: Multiplicity of r if r is a pole of `f(x)`. Should be zero otherwise. n: Order of the term upto which the series is expanded. Returns ======= series: A dictionary that has power of the term as key and coefficient of that term as value. Below is a basic outline of how the Laurent series of a rational function `f(x)` about `x_0` is being calculated - 1. Substitute `x + x_0` in place of `x`. If `x_0` is a pole of `f(x)`, multiply the expression by `x^m` where `m` is the multiplicity of `x_0`. Denote the the resulting expression as g(x). We do this substitution so that we can now find the Laurent series of g(x) about `x = 0`. 2. We can then assume that the Laurent series of `g(x)` takes the following form - .. math:: g(x) = \frac{num(x)}{den(x)} = \sum_{m = 0}^{\infty} a_m x^m where `a_m` denotes the Laurent series coefficients. 3. Multiply the denominator to the RHS of the equation and form a recurrence relation for the coefficients `a_m`. """ one = Poly(1, x, extension=True) if r == oo: # Series at x = oo is equal to first transforming # the function from x -> 1/x and finding the # series at x = 0 num, den = inverse_transform_poly(num, den, x) r = S(0) if r: # For an expansion about a non-zero point, a # transformation from x -> x + r must be made num = num.transform(Poly(x + r, x, extension=True), one) den = den.transform(Poly(x + r, x, extension=True), one) # Remove the pole from the denominator if the series # expansion is about one of the poles num, den = (num*x**m).cancel(den, include=True) # Equate coefficients for the first terms (base case) maxdegree = 1 + max(num.degree(), den.degree()) syms = symbols(f'a:{maxdegree}', cls=Dummy) diff = num - den * Poly(syms[::-1], x) coeff_diffs = diff.all_coeffs()[::-1][:maxdegree] (coeffs, ) = linsolve(coeff_diffs, syms) # Use the recursion relation for the rest recursion = den.all_coeffs()[::-1] div, rec_rhs = recursion[0], recursion[1:] series = list(coeffs) while len(series) < n: next_coeff = Add(*(c*series[-1-n] for n, c in enumerate(rec_rhs))) / div series.append(-next_coeff) series = {m - i: val for i, val in enumerate(series)} return series def compute_m_ybar(x, poles, choice, N): """ Helper function to calculate - 1. m - The degree bound for the polynomial solution that must be found for the auxiliary differential equation. 2. ybar - Part of the solution which can be computed using the poles, c and d vectors. """ ybar = 0 m = Poly(choice[-1][-1], x, extension=True) # Calculate the first (nested) summation for ybar # as given in Step 9 of the Thesis (Pg 82) for i in range(len(poles)): for j in range(len(choice[i])): ybar += choice[i][j]/(x - poles[i])**(j+1) m -= Poly(choice[i][0], x, extension=True) # Calculate the second summation for ybar for i in range(N+1): ybar += choice[-1][i]*x**i return (m.expr, ybar) def solve_aux_eq(numa, dena, numy, deny, x, m): """ Helper function to find a polynomial solution of degree m for the auxiliary differential equation. """ # Assume that the solution is of the type # p(x) = C_0 + C_1*x + ... + C_{m-1}*x**(m-1) + x**m psyms = symbols(f'C0:{m}', cls=Dummy) K = ZZ[psyms] psol = Poly(K.gens, x, domain=K) + Poly(x**m, x, domain=K) # Eq (5.16) in Thesis - Pg 81 auxeq = (dena*(numy.diff(x)*deny - numy*deny.diff(x) + numy**2) - numa*deny**2)*psol if m >= 1: px = psol.diff(x) auxeq += px*(2*numy*deny*dena) if m >= 2: auxeq += px.diff(x)*(deny**2*dena) if m != 0: # m is a non-zero integer. Find the constant terms using undetermined coefficients return psol, linsolve_dict(auxeq.all_coeffs(), psyms), True else: # m == 0 . Check if 1 (x**0) is a solution to the auxiliary equation return S(1), auxeq, auxeq == 0 def remove_redundant_sols(sol1, sol2, x): """ Helper function to remove redundant solutions to the differential equation. """ # If y1 and y2 are redundant solutions, there is # some value of the arbitrary constant for which # they will be equal syms1 = sol1.atoms(Symbol, Dummy) syms2 = sol2.atoms(Symbol, Dummy) num1, den1 = [Poly(e, x, extension=True) for e in sol1.together().as_numer_denom()] num2, den2 = [Poly(e, x, extension=True) for e in sol2.together().as_numer_denom()] # Cross multiply e = num1*den2 - den1*num2 # Check if there are any constants syms = list(e.atoms(Symbol, Dummy)) if len(syms): # Find values of constants for which solutions are equal redn = linsolve(e.all_coeffs(), syms) if len(redn): # Return the general solution over a particular solution if len(syms1) > len(syms2): return sol2 # If both have constants, return the lesser complex solution elif len(syms1) == len(syms2): return sol1 if count_ops(syms1) >= count_ops(syms2) else sol2 else: return sol1 def get_gen_sol_from_part_sol(part_sols, a, x): """" Helper function which computes the general solution for a Riccati ODE from its particular solutions. There are 3 cases to find the general solution from the particular solutions for a Riccati ODE depending on the number of particular solution(s) we have - 1, 2 or 3. For more information, see Section 6 of "Methods of Solution of the Riccati Differential Equation" by D. R. Haaheim and F. M. Stein """ # If no particular solutions are found, a general # solution cannot be found if len(part_sols) == 0: return [] # In case of a single particular solution, the general # solution can be found by using the substitution # y = y1 + 1/z and solving a Bernoulli ODE to find z. elif len(part_sols) == 1: y1 = part_sols[0] i = exp(Integral(2*y1, x)) z = i * Integral(a/i, x) z = z.doit() if a == 0 or z == 0: return y1 return y1 + 1/z # In case of 2 particular solutions, the general solution # can be found by solving a separable equation. This is # the most common case, i.e. most Riccati ODEs have 2 # rational particular solutions. elif len(part_sols) == 2: y1, y2 = part_sols # One of them already has a constant if len(y1.atoms(Dummy)) + len(y2.atoms(Dummy)) > 0: u = exp(Integral(y2 - y1, x)).doit() # Introduce a constant else: C1 = Dummy('C1') u = C1*exp(Integral(y2 - y1, x)).doit() if u == 1: return y2 return (y2*u - y1)/(u - 1) # In case of 3 particular solutions, a closed form # of the general solution can be obtained directly else: y1, y2, y3 = part_sols[:3] C1 = Dummy('C1') return (C1 + 1)*y2*(y1 - y3)/(C1*y1 + y2 - (C1 + 1)*y3) def solve_riccati(fx, x, b0, b1, b2, gensol=False): """ The main function that gives particular/general solutions to Riccati ODEs that have atleast 1 rational particular solution. """ # Step 1 : Convert to Normal Form a = -b0*b2 + b1**2/4 - b1.diff(x)/2 + 3*b2.diff(x)**2/(4*b2**2) + b1*b2.diff(x)/(2*b2) - \ b2.diff(x, 2)/(2*b2) a_t = a.together() num, den = [Poly(e, x, extension=True) for e in a_t.as_numer_denom()] num, den = num.cancel(den, include=True) # Step 2 presol = [] # Step 3 : a(x) is 0 if num == 0: presol.append(1/(x + Dummy('C1'))) # Step 4 : a(x) is a non-zero constant elif x not in num.free_symbols.union(den.free_symbols): presol.extend([sqrt(a), -sqrt(a)]) # Step 5 : Find poles and valuation at infinity poles = roots(den, x) poles, muls = list(poles.keys()), list(poles.values()) val_inf = val_at_inf(num, den, x) if len(poles): # Check necessary conditions (outlined in the module docstring) if not check_necessary_conds(val_inf, muls): raise ValueError("Rational Solution doesn't exist") # Step 6 # Construct c-vectors for each singular point c = construct_c(num, den, x, poles, muls) # Construct d vectors for each singular point d = construct_d(num, den, x, val_inf) # Step 7 : Iterate over all possible combinations and return solutions # For each possible combination, generate an array of 0's and 1's # where 0 means pick 1st choice and 1 means pick the second choice. # NOTE: We could exit from the loop if we find 3 particular solutions, # but it is not implemented here as - # a. Finding 3 particular solutions is very rare. Most of the time, # only 2 particular solutions are found. # b. In case we exit after finding 3 particular solutions, it might # happen that 1 or 2 of them are redundant solutions. So, instead of # spending some more time in computing the particular solutions, # we will end up computing the general solution from a single # particular solution which is usually slower than computing the # general solution from 2 or 3 particular solutions. c.append(d) choices = product(*c) for choice in choices: m, ybar = compute_m_ybar(x, poles, choice, -val_inf//2) numy, deny = [Poly(e, x, extension=True) for e in ybar.together().as_numer_denom()] # Step 10 : Check if a valid solution exists. If yes, also check # if m is a non-negative integer if m.is_nonnegative == True and m.is_integer == True: # Step 11 : Find polynomial solutions of degree m for the auxiliary equation psol, coeffs, exists = solve_aux_eq(num, den, numy, deny, x, m) # Step 12 : If valid polynomial solution exists, append solution. if exists: # m == 0 case if psol == 1 and coeffs == 0: # p(x) = 1, so p'(x)/p(x) term need not be added presol.append(ybar) # m is a positive integer and there are valid coefficients elif len(coeffs): # Substitute the valid coefficients to get p(x) psol = psol.xreplace(coeffs) # y(x) = ybar(x) + p'(x)/p(x) presol.append(ybar + psol.diff(x)/psol) # Remove redundant solutions from the list of existing solutions remove = set() for i in range(len(presol)): for j in range(i+1, len(presol)): rem = remove_redundant_sols(presol[i], presol[j], x) if rem is not None: remove.add(rem) sols = [x for x in presol if x not in remove] # Step 15 : Inverse transform the solutions of the equation in normal form bp = -b2.diff(x)/(2*b2**2) - b1/(2*b2) # If general solution is required, compute it from the particular solutions if gensol: sols = [get_gen_sol_from_part_sol(sols, a, x)] # Inverse transform the particular solutions presol = [Eq(fx, riccati_inverse_normal(y, x, b1, b2, bp).cancel(extension=True)) for y in sols] return presol sympy-sympy-1.9/sympy/solvers/ode/single.py000066400000000000000000003271711412543434000212160ustar00rootroot00000000000000# # This is the module for ODE solver classes for single ODEs. # import typing if typing.TYPE_CHECKING: from typing import ClassVar from typing import Dict, Type, Iterator, List, Optional from .riccati import match_riccati, solve_riccati from sympy.core import Add, S, Pow, Rational from sympy.core.exprtools import factor_terms from sympy.core.expr import Expr from sympy.core.function import AppliedUndef, Derivative, diff, Function, expand, Subs, _mexpand from sympy.core.numbers import Float, zoo from sympy.core.relational import Equality, Eq from sympy.core.symbol import Symbol, Dummy, Wild from sympy.core.mul import Mul from sympy.functions import exp, tan, log, sqrt, besselj, bessely, cbrt, airyai, airybi from sympy.integrals import Integral from sympy.polys import Poly from sympy.polys.polytools import cancel, factor, degree from sympy.simplify import collect, simplify, separatevars, logcombine, posify from sympy.simplify.radsimp import fraction from sympy.utilities import numbered_symbols from sympy.solvers.solvers import solve from sympy.solvers.deutils import ode_order, _preprocess from sympy.polys.matrices.linsolve import _lin_eq2dict from sympy.polys.solvers import PolyNonlinearError from .hypergeometric import equivalence_hypergeometric, match_2nd_2F1_hypergeometric, \ get_sol_2F1_hypergeometric, match_2nd_hypergeometric from .nonhomogeneous import _get_euler_characteristic_eq_sols, _get_const_characteristic_eq_sols, \ _solve_undetermined_coefficients, _solve_variation_of_parameters, _test_term, _undetermined_coefficients_match, \ _get_simplified_sol from .lie_group import _ode_lie_group class ODEMatchError(NotImplementedError): """Raised if a SingleODESolver is asked to solve an ODE it does not match""" pass def cached_property(func): '''Decorator to cache property method''' attrname = '_' + func.__name__ def propfunc(self): val = getattr(self, attrname, None) if val is None: val = func(self) setattr(self, attrname, val) return val return property(propfunc) class SingleODEProblem: """Represents an ordinary differential equation (ODE) This class is used internally in the by dsolve and related functions/classes so that properties of an ODE can be computed efficiently. Examples ======== This class is used internally by dsolve. To instantiate an instance directly first define an ODE problem: >>> from sympy import Function, Symbol >>> x = Symbol('x') >>> f = Function('f') >>> eq = f(x).diff(x, 2) Now you can create a SingleODEProblem instance and query its properties: >>> from sympy.solvers.ode.single import SingleODEProblem >>> problem = SingleODEProblem(f(x).diff(x), f(x), x) >>> problem.eq Derivative(f(x), x) >>> problem.func f(x) >>> problem.sym x """ # Instance attributes: eq = None # type: Expr func = None # type: AppliedUndef sym = None # type: Symbol _order = None # type: int _eq_expanded = None # type: Expr _eq_preprocessed = None # type: Expr _eq_high_order_free = None def __init__(self, eq, func, sym, prep=True, **kwargs): assert isinstance(eq, Expr) assert isinstance(func, AppliedUndef) assert isinstance(sym, Symbol) assert isinstance(prep, bool) self.eq = eq self.func = func self.sym = sym self.prep = prep self.params = kwargs @cached_property def order(self) -> int: return ode_order(self.eq, self.func) @cached_property def eq_preprocessed(self) -> Expr: return self._get_eq_preprocessed() @cached_property def eq_high_order_free(self) -> Expr: a = Wild('a', exclude=[self.func]) c1 = Wild('c1', exclude=[self.sym]) # Precondition to try remove f(x) from highest order derivative reduced_eq = None if self.eq.is_Add: deriv_coef = self.eq.coeff(self.func.diff(self.sym, self.order)) if deriv_coef not in (1, 0): r = deriv_coef.match(a*self.func**c1) if r and r[c1]: den = self.func**r[c1] reduced_eq = Add(*[arg/den for arg in self.eq.args]) if not reduced_eq: reduced_eq = expand(self.eq) return reduced_eq @cached_property def eq_expanded(self) -> Expr: return expand(self.eq_preprocessed) def _get_eq_preprocessed(self) -> Expr: if self.prep: process_eq, process_func = _preprocess(self.eq, self.func) if process_func != self.func: raise ValueError else: process_eq = self.eq return process_eq def get_numbered_constants(self, num=1, start=1, prefix='C') -> List[Symbol]: """ Returns a list of constants that do not occur in eq already. """ ncs = self.iter_numbered_constants(start, prefix) Cs = [next(ncs) for i in range(num)] return Cs def iter_numbered_constants(self, start=1, prefix='C') -> Iterator[Symbol]: """ Returns an iterator of constants that do not occur in eq already. """ atom_set = self.eq.free_symbols func_set = self.eq.atoms(Function) if func_set: atom_set |= {Symbol(str(f.func)) for f in func_set} return numbered_symbols(start=start, prefix=prefix, exclude=atom_set) @cached_property def is_autonomous(self): u = Dummy('u') x = self.sym syms = self.eq.subs(self.func, u).free_symbols return x not in syms def get_linear_coefficients(self, eq, func, order): r""" Matches a differential equation to the linear form: .. math:: a_n(x) y^{(n)} + \cdots + a_1(x)y' + a_0(x) y + B(x) = 0 Returns a dict of order:coeff terms, where order is the order of the derivative on each term, and coeff is the coefficient of that derivative. The key ``-1`` holds the function `B(x)`. Returns ``None`` if the ODE is not linear. This function assumes that ``func`` has already been checked to be good. Examples ======== >>> from sympy import Function, cos, sin >>> from sympy.abc import x >>> from sympy.solvers.ode.single import SingleODEProblem >>> f = Function('f') >>> eq = f(x).diff(x, 3) + 2*f(x).diff(x) + \ ... x*f(x).diff(x, 2) + cos(x)*f(x).diff(x) + x - f(x) - \ ... sin(x) >>> obj = SingleODEProblem(eq, f(x), x) >>> obj.get_linear_coefficients(eq, f(x), 3) {-1: x - sin(x), 0: -1, 1: cos(x) + 2, 2: x, 3: 1} >>> eq = f(x).diff(x, 3) + 2*f(x).diff(x) + \ ... x*f(x).diff(x, 2) + cos(x)*f(x).diff(x) + x - f(x) - \ ... sin(f(x)) >>> obj = SingleODEProblem(eq, f(x), x) >>> obj.get_linear_coefficients(eq, f(x), 3) == None True """ f = func.func x = func.args[0] symset = {Derivative(f(x), x, i) for i in range(order+1)} try: rhs, lhs_terms = _lin_eq2dict(eq, symset) except PolyNonlinearError: return None if rhs.has(func) or any(c.has(func) for c in lhs_terms.values()): return None terms = {i: lhs_terms.get(f(x).diff(x, i), S.Zero) for i in range(order+1)} terms[-1] = rhs return terms # TODO: Add methods that can be used by many ODE solvers: # order # is_linear() # get_linear_coefficients() # eq_prepared (the ODE in prepared form) class SingleODESolver: """ Base class for Single ODE solvers. Subclasses should implement the _matches and _get_general_solution methods. This class is not intended to be instantiated directly but its subclasses are as part of dsolve. Examples ======== You can use a subclass of SingleODEProblem to solve a particular type of ODE. We first define a particular ODE problem: >>> from sympy import Function, Symbol >>> x = Symbol('x') >>> f = Function('f') >>> eq = f(x).diff(x, 2) Now we solve this problem using the NthAlgebraic solver which is a subclass of SingleODESolver: >>> from sympy.solvers.ode.single import NthAlgebraic, SingleODEProblem >>> problem = SingleODEProblem(eq, f(x), x) >>> solver = NthAlgebraic(problem) >>> solver.get_general_solution() [Eq(f(x), _C*x + _C)] The normal way to solve an ODE is to use dsolve (which would use NthAlgebraic and other solvers internally). When using dsolve a number of other things are done such as evaluating integrals, simplifying the solution and renumbering the constants: >>> from sympy import dsolve >>> dsolve(eq, hint='nth_algebraic') Eq(f(x), C1 + C2*x) """ # Subclasses should store the hint name (the argument to dsolve) in this # attribute hint = None # type: ClassVar[str] # Subclasses should define this to indicate if they support an _Integral # hint. has_integral = None # type: ClassVar[bool] # The ODE to be solved ode_problem = None # type: SingleODEProblem # Cache whether or not the equation has matched the method _matched = None # type: Optional[bool] # Subclasses should store in this attribute the list of order(s) of ODE # that subclass can solve or leave it to None if not specific to any order order = None # type: Optional[list] def __init__(self, ode_problem): self.ode_problem = ode_problem def matches(self) -> bool: if self.order is not None and self.ode_problem.order not in self.order: self._matched = False return self._matched if self._matched is None: self._matched = self._matches() return self._matched def get_general_solution(self, *, simplify: bool = True) -> List[Equality]: if not self.matches(): msg = "%s solver can not solve:\n%s" raise ODEMatchError(msg % (self.hint, self.ode_problem.eq)) return self._get_general_solution(simplify_flag=simplify) def _matches(self) -> bool: msg = "Subclasses of SingleODESolver should implement matches." raise NotImplementedError(msg) def _get_general_solution(self, *, simplify_flag: bool = True) -> List[Equality]: msg = "Subclasses of SingleODESolver should implement get_general_solution." raise NotImplementedError(msg) class SinglePatternODESolver(SingleODESolver): '''Superclass for ODE solvers based on pattern matching''' def wilds(self): prob = self.ode_problem f = prob.func.func x = prob.sym order = prob.order return self._wilds(f, x, order) def wilds_match(self): match = self._wilds_match return [match.get(w, S.Zero) for w in self.wilds()] def _matches(self): eq = self.ode_problem.eq_expanded f = self.ode_problem.func.func x = self.ode_problem.sym order = self.ode_problem.order df = f(x).diff(x, order) if order not in [1, 2]: return False pattern = self._equation(f(x), x, order) if not pattern.coeff(df).has(Wild): eq = expand(eq / eq.coeff(df)) eq = eq.collect([f(x).diff(x), f(x)], func = cancel) self._wilds_match = match = eq.match(pattern) if match is not None: return self._verify(f(x)) return False def _verify(self, fx) -> bool: return True def _wilds(self, f, x, order): msg = "Subclasses of SingleODESolver should implement _wilds" raise NotImplementedError(msg) def _equation(self, fx, x, order): msg = "Subclasses of SingleODESolver should implement _equation" raise NotImplementedError(msg) class NthAlgebraic(SingleODESolver): r""" Solves an `n`\th order ordinary differential equation using algebra and integrals. There is no general form for the kind of equation that this can solve. The the equation is solved algebraically treating differentiation as an invertible algebraic function. Examples ======== >>> from sympy import Function, dsolve, Eq >>> from sympy.abc import x >>> f = Function('f') >>> eq = Eq(f(x) * (f(x).diff(x)**2 - 1), 0) >>> dsolve(eq, f(x), hint='nth_algebraic') [Eq(f(x), 0), Eq(f(x), C1 - x), Eq(f(x), C1 + x)] Note that this solver can return algebraic solutions that do not have any integration constants (f(x) = 0 in the above example). """ hint = 'nth_algebraic' has_integral = True # nth_algebraic_Integral hint def _matches(self): r""" Matches any differential equation that nth_algebraic can solve. Uses `sympy.solve` but teaches it how to integrate derivatives. This involves calling `sympy.solve` and does most of the work of finding a solution (apart from evaluating the integrals). """ eq = self.ode_problem.eq func = self.ode_problem.func var = self.ode_problem.sym # Derivative that solve can handle: diffx = self._get_diffx(var) # Replace derivatives wrt the independent variable with diffx def replace(eq, var): def expand_diffx(*args): differand, diffs = args[0], args[1:] toreplace = differand for v, n in diffs: for _ in range(n): if v == var: toreplace = diffx(toreplace) else: toreplace = Derivative(toreplace, v) return toreplace return eq.replace(Derivative, expand_diffx) # Restore derivatives in solution afterwards def unreplace(eq, var): return eq.replace(diffx, lambda e: Derivative(e, var)) subs_eqn = replace(eq, var) try: # turn off simplification to protect Integrals that have # _t instead of fx in them and would otherwise factor # as t_*Integral(1, x) solns = solve(subs_eqn, func, simplify=False) except NotImplementedError: solns = [] solns = [simplify(unreplace(soln, var)) for soln in solns] solns = [Equality(func, soln) for soln in solns] self.solutions = solns return len(solns) != 0 def _get_general_solution(self, *, simplify_flag: bool = True): return self.solutions # This needs to produce an invertible function but the inverse depends # which variable we are integrating with respect to. Since the class can # be stored in cached results we need to ensure that we always get the # same class back for each particular integration variable so we store these # classes in a global dict: _diffx_stored = {} # type: Dict[Symbol, Type[Function]] @staticmethod def _get_diffx(var): diffcls = NthAlgebraic._diffx_stored.get(var, None) if diffcls is None: # A class that behaves like Derivative wrt var but is "invertible". class diffx(Function): def inverse(self): # don't use integrate here because fx has been replaced by _t # in the equation; integrals will not be correct while solve # is at work. return lambda expr: Integral(expr, var) + Dummy('C') diffcls = NthAlgebraic._diffx_stored.setdefault(var, diffx) return diffcls class FirstExact(SinglePatternODESolver): r""" Solves 1st order exact ordinary differential equations. A 1st order differential equation is called exact if it is the total differential of a function. That is, the differential equation .. math:: P(x, y) \,\partial{}x + Q(x, y) \,\partial{}y = 0 is exact if there is some function `F(x, y)` such that `P(x, y) = \partial{}F/\partial{}x` and `Q(x, y) = \partial{}F/\partial{}y`. It can be shown that a necessary and sufficient condition for a first order ODE to be exact is that `\partial{}P/\partial{}y = \partial{}Q/\partial{}x`. Then, the solution will be as given below:: >>> from sympy import Function, Eq, Integral, symbols, pprint >>> x, y, t, x0, y0, C1= symbols('x,y,t,x0,y0,C1') >>> P, Q, F= map(Function, ['P', 'Q', 'F']) >>> pprint(Eq(Eq(F(x, y), Integral(P(t, y), (t, x0, x)) + ... Integral(Q(x0, t), (t, y0, y))), C1)) x y / / | | F(x, y) = | P(t, y) dt + | Q(x0, t) dt = C1 | | / / x0 y0 Where the first partials of `P` and `Q` exist and are continuous in a simply connected region. A note: SymPy currently has no way to represent inert substitution on an expression, so the hint ``1st_exact_Integral`` will return an integral with `dy`. This is supposed to represent the function that you are solving for. Examples ======== >>> from sympy import Function, dsolve, cos, sin >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), ... f(x), hint='1st_exact') Eq(x*cos(f(x)) + f(x)**3/3, C1) References ========== - https://en.wikipedia.org/wiki/Exact_differential_equation - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 73 # indirect doctest """ hint = "1st_exact" has_integral = True order = [1] def _wilds(self, f, x, order): P = Wild('P', exclude=[f(x).diff(x)]) Q = Wild('Q', exclude=[f(x).diff(x)]) return P, Q def _equation(self, fx, x, order): P, Q = self.wilds() return P + Q*fx.diff(x) def _verify(self, fx) -> bool: P, Q = self.wilds() x = self.ode_problem.sym y = Dummy('y') m, n = self.wilds_match() m = m.subs(fx, y) n = n.subs(fx, y) numerator = cancel(m.diff(y) - n.diff(x)) if numerator.is_zero: # Is exact return True else: # The following few conditions try to convert a non-exact # differential equation into an exact one. # References: # 1. Differential equations with applications # and historical notes - George E. Simmons # 2. https://math.okstate.edu/people/binegar/2233-S99/2233-l12.pdf factor_n = cancel(numerator/n) factor_m = cancel(-numerator/m) if y not in factor_n.free_symbols: # If (dP/dy - dQ/dx) / Q = f(x) # then exp(integral(f(x))*equation becomes exact factor = factor_n integration_variable = x elif x not in factor_m.free_symbols: # If (dP/dy - dQ/dx) / -P = f(y) # then exp(integral(f(y))*equation becomes exact factor = factor_m integration_variable = y else: # Couldn't convert to exact return False factor = exp(Integral(factor, integration_variable)) m *= factor n *= factor self._wilds_match[P] = m.subs(y, fx) self._wilds_match[Q] = n.subs(y, fx) return True def _get_general_solution(self, *, simplify_flag: bool = True): m, n = self.wilds_match() fx = self.ode_problem.func x = self.ode_problem.sym (C1,) = self.ode_problem.get_numbered_constants(num=1) y = Dummy('y') m = m.subs(fx, y) n = n.subs(fx, y) gen_sol = Eq(Subs(Integral(m, x) + Integral(n - Integral(m, x).diff(y), y), y, fx), C1) return [gen_sol] class FirstLinear(SinglePatternODESolver): r""" Solves 1st order linear differential equations. These are differential equations of the form .. math:: dy/dx + P(x) y = Q(x)\text{.} These kinds of differential equations can be solved in a general way. The integrating factor `e^{\int P(x) \,dx}` will turn the equation into a separable equation. The general solution is:: >>> from sympy import Function, dsolve, Eq, pprint, diff, sin >>> from sympy.abc import x >>> f, P, Q = map(Function, ['f', 'P', 'Q']) >>> genform = Eq(f(x).diff(x) + P(x)*f(x), Q(x)) >>> pprint(genform) d P(x)*f(x) + --(f(x)) = Q(x) dx >>> pprint(dsolve(genform, f(x), hint='1st_linear_Integral')) / / \ | | | | | / | / | | | | | | | | P(x) dx | - | P(x) dx | | | | | | | / | / f(x) = |C1 + | Q(x)*e dx|*e | | | \ / / Examples ======== >>> f = Function('f') >>> pprint(dsolve(Eq(x*diff(f(x), x) - f(x), x**2*sin(x)), ... f(x), '1st_linear')) f(x) = x*(C1 - cos(x)) References ========== - https://en.wikipedia.org/wiki/Linear_differential_equation#First_order_equation - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 92 # indirect doctest """ hint = '1st_linear' has_integral = True order = [1] def _wilds(self, f, x, order): P = Wild('P', exclude=[f(x)]) Q = Wild('Q', exclude=[f(x), f(x).diff(x)]) return P, Q def _equation(self, fx, x, order): P, Q = self.wilds() return fx.diff(x) + P*fx - Q def _get_general_solution(self, *, simplify_flag: bool = True): P, Q = self.wilds_match() fx = self.ode_problem.func x = self.ode_problem.sym (C1,) = self.ode_problem.get_numbered_constants(num=1) gensol = Eq(fx, ((C1 + Integral(Q*exp(Integral(P, x)), x)) * exp(-Integral(P, x)))) return [gensol] class AlmostLinear(SinglePatternODESolver): r""" Solves an almost-linear differential equation. The general form of an almost linear differential equation is .. math:: a(x) g'(f(x)) f'(x) + b(x) g(f(x)) + c(x) Here `f(x)` is the function to be solved for (the dependent variable). The substitution `g(f(x)) = u(x)` leads to a linear differential equation for `u(x)` of the form `a(x) u' + b(x) u + c(x) = 0`. This can be solved for `u(x)` by the `first_linear` hint and then `f(x)` is found by solving `g(f(x)) = u(x)`. See Also ======== :obj:`sympy.solvers.ode.single.FirstLinear` Examples ======== >>> from sympy import Function, pprint, sin, cos >>> from sympy.solvers.ode import dsolve >>> from sympy.abc import x >>> f = Function('f') >>> d = f(x).diff(x) >>> eq = x*d + x*f(x) + 1 >>> dsolve(eq, f(x), hint='almost_linear') Eq(f(x), (C1 - Ei(x))*exp(-x)) >>> pprint(dsolve(eq, f(x), hint='almost_linear')) -x f(x) = (C1 - Ei(x))*e >>> example = cos(f(x))*f(x).diff(x) + sin(f(x)) + 1 >>> pprint(example) d sin(f(x)) + cos(f(x))*--(f(x)) + 1 dx >>> pprint(dsolve(example, f(x), hint='almost_linear')) / -x \ / -x \ [f(x) = pi - asin\C1*e - 1/, f(x) = asin\C1*e - 1/] References ========== - Joel Moses, "Symbolic Integration - The Stormy Decade", Communications of the ACM, Volume 14, Number 8, August 1971, pp. 558 """ hint = "almost_linear" has_integral = True order = [1] def _wilds(self, f, x, order): P = Wild('P', exclude=[f(x).diff(x)]) Q = Wild('Q', exclude=[f(x).diff(x)]) return P, Q def _equation(self, fx, x, order): P, Q = self.wilds() return P*fx.diff(x) + Q def _verify(self, fx): a, b = self.wilds_match() c, b = b.as_independent(fx) if b.is_Add else (S.Zero, b) # a, b and c are the function a(x), b(x) and c(x) respectively. # c(x) is obtained by separating out b as terms with and without fx i.e, l(y) # The following conditions checks if the given equation is an almost-linear differential equation using the fact that # a(x)*(l(y))' / l(y)' is independent of l(y) if b.diff(fx) != 0 and not simplify(b.diff(fx)/a).has(fx): self.ly = factor_terms(b).as_independent(fx, as_Add=False)[1] # Gives the term containing fx i.e., l(y) self.ax = a / self.ly.diff(fx) self.cx = -c # cx is taken as -c(x) to simplify expression in the solution integral self.bx = factor_terms(b) / self.ly return True return False def _get_general_solution(self, *, simplify_flag: bool = True): x = self.ode_problem.sym (C1,) = self.ode_problem.get_numbered_constants(num=1) gensol = Eq(self.ly, ((C1 + Integral((self.cx/self.ax)*exp(Integral(self.bx/self.ax, x)), x)) * exp(-Integral(self.bx/self.ax, x)))) return [gensol] class Bernoulli(SinglePatternODESolver): r""" Solves Bernoulli differential equations. These are equations of the form .. math:: dy/dx + P(x) y = Q(x) y^n\text{, }n \ne 1`\text{.} The substitution `w = 1/y^{1-n}` will transform an equation of this form into one that is linear (see the docstring of :obj:`~sympy.solvers.ode.single.FirstLinear`). The general solution is:: >>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x, n >>> f, P, Q = map(Function, ['f', 'P', 'Q']) >>> genform = Eq(f(x).diff(x) + P(x)*f(x), Q(x)*f(x)**n) >>> pprint(genform) d n P(x)*f(x) + --(f(x)) = Q(x)*f (x) dx >>> pprint(dsolve(genform, f(x), hint='Bernoulli_Integral'), num_columns=110) -1 ----- n - 1 // / / \ \ || | | | | || | / | / | / | || | | | | | | | || | (1 - n)* | P(x) dx | (1 - n)* | P(x) dx | (n - 1)* | P(x) dx| || | | | | | | | || | / | / | / | f(x) = ||C1 - n* | Q(x)*e dx + | Q(x)*e dx|*e | || | | | | \\ / / / / Note that the equation is separable when `n = 1` (see the docstring of :obj:`~sympy.solvers.ode.single.Separable`). >>> pprint(dsolve(Eq(f(x).diff(x) + P(x)*f(x), Q(x)*f(x)), f(x), ... hint='separable_Integral')) f(x) / | / | 1 | | - dy = C1 + | (-P(x) + Q(x)) dx | y | | / / Examples ======== >>> from sympy import Function, dsolve, Eq, pprint, log >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(Eq(x*f(x).diff(x) + f(x), log(x)*f(x)**2), ... f(x), hint='Bernoulli')) 1 f(x) = ----------------- C1*x + log(x) + 1 References ========== - https://en.wikipedia.org/wiki/Bernoulli_differential_equation - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 95 # indirect doctest """ hint = "Bernoulli" has_integral = True order = [1] def _wilds(self, f, x, order): P = Wild('P', exclude=[f(x)]) Q = Wild('Q', exclude=[f(x)]) n = Wild('n', exclude=[x, f(x), f(x).diff(x)]) return P, Q, n def _equation(self, fx, x, order): P, Q, n = self.wilds() return fx.diff(x) + P*fx - Q*fx**n def _get_general_solution(self, *, simplify_flag: bool = True): P, Q, n = self.wilds_match() fx = self.ode_problem.func x = self.ode_problem.sym (C1,) = self.ode_problem.get_numbered_constants(num=1) if n==1: gensol = Eq(log(fx), ( C1 + Integral((-P + Q), x) )) else: gensol = Eq(fx**(1-n), ( (C1 - (n - 1) * Integral(Q*exp(-n*Integral(P, x)) * exp(Integral(P, x)), x) ) * exp(-(1 - n)*Integral(P, x))) ) return [gensol] class Factorable(SingleODESolver): r""" Solves equations having a solvable factor. This function is used to solve the equation having factors. Factors may be of type algebraic or ode. It will try to solve each factor independently. Factors will be solved by calling dsolve. We will return the list of solutions. Examples ======== >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> eq = (f(x)**2-4)*(f(x).diff(x)+f(x)) >>> pprint(dsolve(eq, f(x))) -x [f(x) = 2, f(x) = -2, f(x) = C1*e ] """ hint = "factorable" has_integral = False def _matches(self): eq = self.ode_problem.eq f = self.ode_problem.func.func x = self.ode_problem.sym order =self.ode_problem.order df = f(x).diff(x) self.eqs = [] eq = eq.collect(f(x), func = cancel) eq = fraction(factor(eq))[0] factors = Mul.make_args(factor(eq)) roots = [fac.as_base_exp() for fac in factors if len(fac.args)!=0] if len(roots)>1 or roots[0][1]>1: for base, expo in roots: if base.has(f(x)): self.eqs.append(base) if len(self.eqs)>0: return True roots = solve(eq, df) if len(roots)>0: self.eqs = [(df - root) for root in roots] if len(self.eqs)==1: if order>1: return False if self.eqs[0].has(Float): return False return fraction(factor(self.eqs[0]))[0]-eq!=0 return True for i in factors: if i.has(f(x)): self.eqs.append(i) return len(self.eqs)>0 and len(factors)>1 def _get_general_solution(self, *, simplify_flag: bool = True): func = self.ode_problem.func.func x = self.ode_problem.sym eqns = self.eqs sols = [] for eq in eqns: try: sol = dsolve(eq, func(x)) except NotImplementedError: continue else: if isinstance(sol, list): sols.extend(sol) else: sols.append(sol) if sols == []: raise NotImplementedError("The given ODE " + str(eq) + " cannot be solved by" + " the factorable group method") return sols class RiccatiSpecial(SinglePatternODESolver): r""" The general Riccati equation has the form .. math:: dy/dx = f(x) y^2 + g(x) y + h(x)\text{.} While it does not have a general solution [1], the "special" form, `dy/dx = a y^2 - b x^c`, does have solutions in many cases [2]. This routine returns a solution for `a(dy/dx) = b y^2 + c y/x + d/x^2` that is obtained by using a suitable change of variables to reduce it to the special form and is valid when neither `a` nor `b` are zero and either `c` or `d` is zero. >>> from sympy.abc import x, a, b, c, d >>> from sympy.solvers.ode import dsolve, checkodesol >>> from sympy import pprint, Function >>> f = Function('f') >>> y = f(x) >>> genform = a*y.diff(x) - (b*y**2 + c*y/x + d/x**2) >>> sol = dsolve(genform, y, hint="Riccati_special_minus2") >>> pprint(sol, wrap_line=False) / / __________________ \\ | __________________ | / 2 || | / 2 | \/ 4*b*d - (a + c) *log(x)|| -|a + c - \/ 4*b*d - (a + c) *tan|C1 + ----------------------------|| \ \ 2*a // f(x) = ------------------------------------------------------------------------ 2*b*x >>> checkodesol(genform, sol, order=1)[0] True References ========== - http://www.maplesoft.com/support/help/Maple/view.aspx?path=odeadvisor/Riccati - http://eqworld.ipmnet.ru/en/solutions/ode/ode0106.pdf - http://eqworld.ipmnet.ru/en/solutions/ode/ode0123.pdf """ hint = "Riccati_special_minus2" has_integral = False order = [1] def _wilds(self, f, x, order): a = Wild('a', exclude=[x, f(x), f(x).diff(x), 0]) b = Wild('b', exclude=[x, f(x), f(x).diff(x), 0]) c = Wild('c', exclude=[x, f(x), f(x).diff(x)]) d = Wild('d', exclude=[x, f(x), f(x).diff(x)]) return a, b, c, d def _equation(self, fx, x, order): a, b, c, d = self.wilds() return a*fx.diff(x) + b*fx**2 + c*fx/x + d/x**2 def _get_general_solution(self, *, simplify_flag: bool = True): a, b, c, d = self.wilds_match() fx = self.ode_problem.func x = self.ode_problem.sym (C1,) = self.ode_problem.get_numbered_constants(num=1) mu = sqrt(4*d*b - (a - c)**2) gensol = Eq(fx, (a - c - mu*tan(mu/(2*a)*log(x) + C1))/(2*b*x)) return [gensol] class RationalRiccati(SinglePatternODESolver): r""" Gives general solutions to the first order Riccati differential equations that have atleast one rational particular solution. .. math :: y' = b_0(x) + b_1(x) y + b_2(x) y^2 where `b_0`, `b_1` and `b_2` are rational functions of `x` with `b_2 \ne 0` (`b_2 = 0` would make it a Bernoulli equation). Examples ======== >>> from sympy import Symbol, Function, dsolve, checkodesol >>> f = Function('f') >>> x = Symbol('x') >>> eq = -x**4*f(x)**2 + x**3*f(x).diff(x) + x**2*f(x) + 20 >>> sol = dsolve(eq, hint="1st_rational_riccati") >>> sol Eq(f(x), (4*C1 - 5*x**9 - 4)/(x**2*(C1 + x**9 - 1))) >>> checkodesol(eq, sol) (True, 0) References ========== - Riccati ODE: https://en.wikipedia.org/wiki/Riccati_equation - N. Thieu Vo - Rational and Algebraic Solutions of First-Order Algebraic ODEs: Algorithm 11, pp. 78 - https://www3.risc.jku.at/publications/download/risc_5387/PhDThesisThieu.pdf """ has_integral = False hint = "1st_rational_riccati" order = [1] def _wilds(self, f, x, order): b0 = Wild('b0', exclude=[f(x), f(x).diff(x)]) b1 = Wild('b1', exclude=[f(x), f(x).diff(x)]) b2 = Wild('b2', exclude=[f(x), f(x).diff(x)]) return (b0, b1, b2) def _equation(self, fx, x, order): b0, b1, b2 = self.wilds() return fx.diff(x) - b0 - b1*fx - b2*fx**2 def _matches(self): eq = self.ode_problem.eq_expanded f = self.ode_problem.func.func x = self.ode_problem.sym order = self.ode_problem.order if order != 1: return False match, funcs = match_riccati(eq, f, x) if not match: return False _b0, _b1, _b2 = funcs b0, b1, b2 = self.wilds() self._wilds_match = match = {b0: _b0, b1: _b1, b2: _b2} return True def _get_general_solution(self, *, simplify_flag: bool = True): # Match the equation b0, b1, b2 = self.wilds_match() fx = self.ode_problem.func x = self.ode_problem.sym return solve_riccati(fx, x, b0, b1, b2, gensol=True) class SecondNonlinearAutonomousConserved(SinglePatternODESolver): r""" Gives solution for the autonomous second order nonlinear differential equation of the form .. math :: f''(x) = g(f(x)) The solution for this differential equation can be computed by multiplying by `f'(x)` and integrating on both sides, converting it into a first order differential equation. Examples ======== >>> from sympy import Function, symbols, dsolve >>> f, g = symbols('f g', cls=Function) >>> x = symbols('x') >>> eq = f(x).diff(x, 2) - g(f(x)) >>> dsolve(eq, simplify=False) [Eq(Integral(1/sqrt(C1 + 2*Integral(g(_u), _u)), (_u, f(x))), C2 + x), Eq(Integral(1/sqrt(C1 + 2*Integral(g(_u), _u)), (_u, f(x))), C2 - x)] >>> from sympy import exp, log >>> eq = f(x).diff(x, 2) - exp(f(x)) + log(f(x)) >>> dsolve(eq, simplify=False) [Eq(Integral(1/sqrt(-2*_u*log(_u) + 2*_u + C1 + 2*exp(_u)), (_u, f(x))), C2 + x), Eq(Integral(1/sqrt(-2*_u*log(_u) + 2*_u + C1 + 2*exp(_u)), (_u, f(x))), C2 - x)] References ========== - http://eqworld.ipmnet.ru/en/solutions/ode/ode0301.pdf """ hint = "2nd_nonlinear_autonomous_conserved" has_integral = True order = [2] def _wilds(self, f, x, order): fy = Wild('fy', exclude=[0, f(x).diff(x), f(x).diff(x, 2)]) return (fy, ) def _equation(self, fx, x, order): fy = self.wilds()[0] return fx.diff(x, 2) + fy def _verify(self, fx): return self.ode_problem.is_autonomous def _get_general_solution(self, *, simplify_flag: bool = True): g = self.wilds_match()[0] fx = self.ode_problem.func x = self.ode_problem.sym u = Dummy('u') g = g.subs(fx, u) C1, C2 = self.ode_problem.get_numbered_constants(num=2) inside = -2*Integral(g, u) + C1 lhs = Integral(1/sqrt(inside), (u, fx)) return [Eq(lhs, C2 + x), Eq(lhs, C2 - x)] class Liouville(SinglePatternODESolver): r""" Solves 2nd order Liouville differential equations. The general form of a Liouville ODE is .. math:: \frac{d^2 y}{dx^2} + g(y) \left(\! \frac{dy}{dx}\!\right)^2 + h(x) \frac{dy}{dx}\text{.} The general solution is: >>> from sympy import Function, dsolve, Eq, pprint, diff >>> from sympy.abc import x >>> f, g, h = map(Function, ['f', 'g', 'h']) >>> genform = Eq(diff(f(x),x,x) + g(f(x))*diff(f(x),x)**2 + ... h(x)*diff(f(x),x), 0) >>> pprint(genform) 2 2 /d \ d d g(f(x))*|--(f(x))| + h(x)*--(f(x)) + ---(f(x)) = 0 \dx / dx 2 dx >>> pprint(dsolve(genform, f(x), hint='Liouville_Integral')) f(x) / / | | | / | / | | | | | - | h(x) dx | | g(y) dy | | | | | / | / C1 + C2* | e dx + | e dy = 0 | | / / Examples ======== >>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(diff(f(x), x, x) + diff(f(x), x)**2/f(x) + ... diff(f(x), x)/x, f(x), hint='Liouville')) ________________ ________________ [f(x) = -\/ C1 + C2*log(x) , f(x) = \/ C1 + C2*log(x) ] References ========== - Goldstein and Braun, "Advanced Methods for the Solution of Differential Equations", pp. 98 - http://www.maplesoft.com/support/help/Maple/view.aspx?path=odeadvisor/Liouville # indirect doctest """ hint = "Liouville" has_integral = True order = [2] def _wilds(self, f, x, order): d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) e = Wild('e', exclude=[f(x).diff(x)]) k = Wild('k', exclude=[f(x).diff(x)]) return d, e, k def _equation(self, fx, x, order): # Liouville ODE in the form # f(x).diff(x, 2) + g(f(x))*(f(x).diff(x))**2 + h(x)*f(x).diff(x) # See Goldstein and Braun, "Advanced Methods for the Solution of # Differential Equations", pg. 98 d, e, k = self.wilds() return d*fx.diff(x, 2) + e*fx.diff(x)**2 + k*fx.diff(x) def _verify(self, fx): d, e, k = self.wilds_match() self.y = Dummy('y') x = self.ode_problem.sym self.g = simplify(e/d).subs(fx, self.y) self.h = simplify(k/d).subs(fx, self.y) if self.y in self.h.free_symbols or x in self.g.free_symbols: return False return True def _get_general_solution(self, *, simplify_flag: bool = True): d, e, k = self.wilds_match() fx = self.ode_problem.func x = self.ode_problem.sym C1, C2 = self.ode_problem.get_numbered_constants(num=2) int = Integral(exp(Integral(self.g, self.y)), (self.y, None, fx)) gen_sol = Eq(int + C1*Integral(exp(-Integral(self.h, x)), x) + C2, 0) return [gen_sol] class Separable(SinglePatternODESolver): r""" Solves separable 1st order differential equations. This is any differential equation that can be written as `P(y) \tfrac{dy}{dx} = Q(x)`. The solution can then just be found by rearranging terms and integrating: `\int P(y) \,dy = \int Q(x) \,dx`. This hint uses :py:meth:`sympy.simplify.simplify.separatevars` as its back end, so if a separable equation is not caught by this solver, it is most likely the fault of that function. :py:meth:`~sympy.simplify.simplify.separatevars` is smart enough to do most expansion and factoring necessary to convert a separable equation `F(x, y)` into the proper form `P(x)\cdot{}Q(y)`. The general solution is:: >>> from sympy import Function, dsolve, Eq, pprint >>> from sympy.abc import x >>> a, b, c, d, f = map(Function, ['a', 'b', 'c', 'd', 'f']) >>> genform = Eq(a(x)*b(f(x))*f(x).diff(x), c(x)*d(f(x))) >>> pprint(genform) d a(x)*b(f(x))*--(f(x)) = c(x)*d(f(x)) dx >>> pprint(dsolve(genform, f(x), hint='separable_Integral')) f(x) / / | | | b(y) | c(x) | ---- dy = C1 + | ---- dx | d(y) | a(x) | | / / Examples ======== >>> from sympy import Function, dsolve, Eq >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(Eq(f(x)*f(x).diff(x) + x, 3*x*f(x)**2), f(x), ... hint='separable', simplify=False)) / 2 \ 2 log\3*f (x) - 1/ x ---------------- = C1 + -- 6 2 References ========== - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 52 # indirect doctest """ hint = "separable" has_integral = True order = [1] def _wilds(self, f, x, order): d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) e = Wild('e', exclude=[f(x).diff(x)]) return d, e def _equation(self, fx, x, order): d, e = self.wilds() return d + e*fx.diff(x) def _verify(self, fx): d, e = self.wilds_match() self.y = Dummy('y') x = self.ode_problem.sym d = separatevars(d.subs(fx, self.y)) e = separatevars(e.subs(fx, self.y)) # m1[coeff]*m1[x]*m1[y] + m2[coeff]*m2[x]*m2[y]*y' self.m1 = separatevars(d, dict=True, symbols=(x, self.y)) self.m2 = separatevars(e, dict=True, symbols=(x, self.y)) if self.m1 and self.m2: return True return False def _get_match_object(self): fx = self.ode_problem.func x = self.ode_problem.sym return self.m1, self.m2, x, fx def _get_general_solution(self, *, simplify_flag: bool = True): m1, m2, x, fx = self._get_match_object() (C1,) = self.ode_problem.get_numbered_constants(num=1) int = Integral(m2['coeff']*m2[self.y]/m1[self.y], (self.y, None, fx)) gen_sol = Eq(int, Integral(-m1['coeff']*m1[x]/ m2[x], x) + C1) return [gen_sol] class SeparableReduced(Separable): r""" Solves a differential equation that can be reduced to the separable form. The general form of this equation is .. math:: y' + (y/x) H(x^n y) = 0\text{}. This can be solved by substituting `u(y) = x^n y`. The equation then reduces to the separable form `\frac{u'}{u (\mathrm{power} - H(u))} - \frac{1}{x} = 0`. The general solution is: >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x, n >>> f, g = map(Function, ['f', 'g']) >>> genform = f(x).diff(x) + (f(x)/x)*g(x**n*f(x)) >>> pprint(genform) / n \ d f(x)*g\x *f(x)/ --(f(x)) + --------------- dx x >>> pprint(dsolve(genform, hint='separable_reduced')) n x *f(x) / | | 1 | ------------ dy = C1 + log(x) | y*(n - g(y)) | / See Also ======== :obj:`sympy.solvers.ode.single.Separable` Examples ======== >>> from sympy import Function, pprint >>> from sympy.solvers.ode.ode import dsolve >>> from sympy.abc import x >>> f = Function('f') >>> d = f(x).diff(x) >>> eq = (x - x**2*f(x))*d - f(x) >>> dsolve(eq, hint='separable_reduced') [Eq(f(x), (1 - sqrt(C1*x**2 + 1))/x), Eq(f(x), (sqrt(C1*x**2 + 1) + 1)/x)] >>> pprint(dsolve(eq, hint='separable_reduced')) ___________ ___________ / 2 / 2 1 - \/ C1*x + 1 \/ C1*x + 1 + 1 [f(x) = ------------------, f(x) = ------------------] x x References ========== - Joel Moses, "Symbolic Integration - The Stormy Decade", Communications of the ACM, Volume 14, Number 8, August 1971, pp. 558 """ hint = "separable_reduced" has_integral = True order = [1] def _degree(self, expr, x): # Made this function to calculate the degree of # x in an expression. If expr will be of form # x**p*y, (wheare p can be variables/rationals) then it # will return p. for val in expr: if val.has(x): if isinstance(val, Pow) and val.as_base_exp()[0] == x: return (val.as_base_exp()[1]) elif val == x: return (val.as_base_exp()[1]) else: return self._degree(val.args, x) return 0 def _powers(self, expr): # this function will return all the different relative power of x w.r.t f(x). # expr = x**p * f(x)**q then it will return {p/q}. pows = set() fx = self.ode_problem.func x = self.ode_problem.sym self.y = Dummy('y') if isinstance(expr, Add): exprs = expr.atoms(Add) elif isinstance(expr, Mul): exprs = expr.atoms(Mul) elif isinstance(expr, Pow): exprs = expr.atoms(Pow) else: exprs = {expr} for arg in exprs: if arg.has(x): _, u = arg.as_independent(x, fx) pow = self._degree((u.subs(fx, self.y), ), x)/self._degree((u.subs(fx, self.y), ), self.y) pows.add(pow) return pows def _verify(self, fx): num, den = self.wilds_match() x = self.ode_problem.sym factor = simplify(x/fx*num/den) # Try representing factor in terms of x^n*y # where n is lowest power of x in factor; # first remove terms like sqrt(2)*3 from factor.atoms(Mul) num, dem = factor.as_numer_denom() num = expand(num) dem = expand(dem) pows = self._powers(num) pows.update(self._powers(dem)) pows = list(pows) if(len(pows)==1) and pows[0]!=zoo: self.t = Dummy('t') self.r2 = {'t': self.t} num = num.subs(x**pows[0]*fx, self.t) dem = dem.subs(x**pows[0]*fx, self.t) test = num/dem free = test.free_symbols if len(free) == 1 and free.pop() == self.t: self.r2.update({'power' : pows[0], 'u' : test}) return True return False return False def _get_match_object(self): fx = self.ode_problem.func x = self.ode_problem.sym u = self.r2['u'].subs(self.r2['t'], self.y) ycoeff = 1/(self.y*(self.r2['power'] - u)) m1 = {self.y: 1, x: -1/x, 'coeff': 1} m2 = {self.y: ycoeff, x: 1, 'coeff': 1} return m1, m2, x, x**self.r2['power']*fx class HomogeneousCoeffSubsDepDivIndep(SinglePatternODESolver): r""" Solves a 1st order differential equation with homogeneous coefficients using the substitution `u_1 = \frac{\text{}}{\text{}}`. This is a differential equation .. math:: P(x, y) + Q(x, y) dy/dx = 0 such that `P` and `Q` are homogeneous and of the same order. A function `F(x, y)` is homogeneous of order `n` if `F(x t, y t) = t^n F(x, y)`. Equivalently, `F(x, y)` can be rewritten as `G(y/x)` or `H(x/y)`. See also the docstring of :py:meth:`~sympy.solvers.ode.homogeneous_order`. If the coefficients `P` and `Q` in the differential equation above are homogeneous functions of the same order, then it can be shown that the substitution `y = u_1 x` (i.e. `u_1 = y/x`) will turn the differential equation into an equation separable in the variables `x` and `u`. If `h(u_1)` is the function that results from making the substitution `u_1 = f(x)/x` on `P(x, f(x))` and `g(u_2)` is the function that results from the substitution on `Q(x, f(x))` in the differential equation `P(x, f(x)) + Q(x, f(x)) f'(x) = 0`, then the general solution is:: >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f, g, h = map(Function, ['f', 'g', 'h']) >>> genform = g(f(x)/x) + h(f(x)/x)*f(x).diff(x) >>> pprint(genform) /f(x)\ /f(x)\ d g|----| + h|----|*--(f(x)) \ x / \ x / dx >>> pprint(dsolve(genform, f(x), ... hint='1st_homogeneous_coeff_subs_dep_div_indep_Integral')) f(x) ---- x / | | -h(u1) log(x) = C1 + | ---------------- d(u1) | u1*h(u1) + g(u1) | / Where `u_1 h(u_1) + g(u_1) \ne 0` and `x \ne 0`. See also the docstrings of :obj:`~sympy.solvers.ode.single.HomogeneousCoeffBest` and :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep`. Examples ======== >>> from sympy import Function, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_subs_dep_div_indep', simplify=False)) / 3 \ |3*f(x) f (x)| log|------ + -----| | x 3 | \ x / log(x) = log(C1) - ------------------- 3 References ========== - https://en.wikipedia.org/wiki/Homogeneous_differential_equation - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 59 # indirect doctest """ hint = "1st_homogeneous_coeff_subs_dep_div_indep" has_integral = True order = [1] def _wilds(self, f, x, order): d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) e = Wild('e', exclude=[f(x).diff(x)]) return d, e def _equation(self, fx, x, order): d, e = self.wilds() return d + e*fx.diff(x) def _verify(self, fx): self.d, self.e = self.wilds_match() self.y = Dummy('y') x = self.ode_problem.sym self.d = separatevars(self.d.subs(fx, self.y)) self.e = separatevars(self.e.subs(fx, self.y)) ordera = homogeneous_order(self.d, x, self.y) orderb = homogeneous_order(self.e, x, self.y) if ordera == orderb and ordera is not None: self.u = Dummy('u') if simplify((self.d + self.u*self.e).subs({x: 1, self.y: self.u})) != 0: return True return False return False def _get_match_object(self): fx = self.ode_problem.func x = self.ode_problem.sym self.u1 = Dummy('u1') xarg = 0 yarg = 0 return [self.d, self.e, fx, x, self.u, self.u1, self.y, xarg, yarg] def _get_general_solution(self, *, simplify_flag: bool = True): d, e, fx, x, u, u1, y, xarg, yarg = self._get_match_object() (C1,) = self.ode_problem.get_numbered_constants(num=1) int = Integral( (-e/(d + u1*e)).subs({x: 1, y: u1}), (u1, None, fx/x)) sol = logcombine(Eq(log(x), int + log(C1)), force=True) gen_sol = sol.subs(fx, u).subs(((u, u - yarg), (x, x - xarg), (u, fx))) return [gen_sol] class HomogeneousCoeffSubsIndepDivDep(SinglePatternODESolver): r""" Solves a 1st order differential equation with homogeneous coefficients using the substitution `u_2 = \frac{\text{}}{\text{}}`. This is a differential equation .. math:: P(x, y) + Q(x, y) dy/dx = 0 such that `P` and `Q` are homogeneous and of the same order. A function `F(x, y)` is homogeneous of order `n` if `F(x t, y t) = t^n F(x, y)`. Equivalently, `F(x, y)` can be rewritten as `G(y/x)` or `H(x/y)`. See also the docstring of :py:meth:`~sympy.solvers.ode.homogeneous_order`. If the coefficients `P` and `Q` in the differential equation above are homogeneous functions of the same order, then it can be shown that the substitution `x = u_2 y` (i.e. `u_2 = x/y`) will turn the differential equation into an equation separable in the variables `y` and `u_2`. If `h(u_2)` is the function that results from making the substitution `u_2 = x/f(x)` on `P(x, f(x))` and `g(u_2)` is the function that results from the substitution on `Q(x, f(x))` in the differential equation `P(x, f(x)) + Q(x, f(x)) f'(x) = 0`, then the general solution is: >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f, g, h = map(Function, ['f', 'g', 'h']) >>> genform = g(x/f(x)) + h(x/f(x))*f(x).diff(x) >>> pprint(genform) / x \ / x \ d g|----| + h|----|*--(f(x)) \f(x)/ \f(x)/ dx >>> pprint(dsolve(genform, f(x), ... hint='1st_homogeneous_coeff_subs_indep_div_dep_Integral')) x ---- f(x) / | | -g(u1) | ---------------- d(u1) | u1*g(u1) + h(u1) | / f(x) = C1*e Where `u_1 g(u_1) + h(u_1) \ne 0` and `f(x) \ne 0`. See also the docstrings of :obj:`~sympy.solvers.ode.single.HomogeneousCoeffBest` and :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep`. Examples ======== >>> from sympy import Function, pprint, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_subs_indep_div_dep', ... simplify=False)) / 2 \ | 3*x | log|----- + 1| | 2 | \f (x) / log(f(x)) = log(C1) - -------------- 3 References ========== - https://en.wikipedia.org/wiki/Homogeneous_differential_equation - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 59 # indirect doctest """ hint = "1st_homogeneous_coeff_subs_indep_div_dep" has_integral = True order = [1] def _wilds(self, f, x, order): d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) e = Wild('e', exclude=[f(x).diff(x)]) return d, e def _equation(self, fx, x, order): d, e = self.wilds() return d + e*fx.diff(x) def _verify(self, fx): self.d, self.e = self.wilds_match() self.y = Dummy('y') x = self.ode_problem.sym self.d = separatevars(self.d.subs(fx, self.y)) self.e = separatevars(self.e.subs(fx, self.y)) ordera = homogeneous_order(self.d, x, self.y) orderb = homogeneous_order(self.e, x, self.y) if ordera == orderb and ordera is not None: self.u = Dummy('u') if simplify((self.e + self.u*self.d).subs({x: self.u, self.y: 1})) != 0: return True return False return False def _get_match_object(self): fx = self.ode_problem.func x = self.ode_problem.sym self.u1 = Dummy('u1') xarg = 0 yarg = 0 return [self.d, self.e, fx, x, self.u, self.u1, self.y, xarg, yarg] def _get_general_solution(self, *, simplify_flag: bool = True): d, e, fx, x, u, u1, y, xarg, yarg = self._get_match_object() (C1,) = self.ode_problem.get_numbered_constants(num=1) int = Integral(simplify((-d/(e + u1*d)).subs({x: u1, y: 1})), (u1, None, x/fx)) sol = logcombine(Eq(log(fx), int + log(C1)), force=True) gen_sol = sol.subs(fx, u).subs(((u, u - yarg), (x, x - xarg), (u, fx))) return [gen_sol] class HomogeneousCoeffBest(HomogeneousCoeffSubsIndepDivDep, HomogeneousCoeffSubsDepDivIndep): r""" Returns the best solution to an ODE from the two hints ``1st_homogeneous_coeff_subs_dep_div_indep`` and ``1st_homogeneous_coeff_subs_indep_div_dep``. This is as determined by :py:meth:`~sympy.solvers.ode.ode.ode_sol_simplicity`. See the :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep` and :obj:`~sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep` docstrings for more information on these hints. Note that there is no ``ode_1st_homogeneous_coeff_best_Integral`` hint. Examples ======== >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), f(x), ... hint='1st_homogeneous_coeff_best', simplify=False)) / 2 \ | 3*x | log|----- + 1| | 2 | \f (x) / log(f(x)) = log(C1) - -------------- 3 References ========== - https://en.wikipedia.org/wiki/Homogeneous_differential_equation - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 59 # indirect doctest """ hint = "1st_homogeneous_coeff_best" has_integral = False order = [1] def _verify(self, fx): if HomogeneousCoeffSubsIndepDivDep._verify(self, fx) and HomogeneousCoeffSubsDepDivIndep._verify(self, fx): return True return False def _get_general_solution(self, *, simplify_flag: bool = True): # There are two substitutions that solve the equation, u1=y/x and u2=x/y # # They produce different integrals, so try them both and see which # # one is easier sol1 = HomogeneousCoeffSubsIndepDivDep._get_general_solution(self) sol2 = HomogeneousCoeffSubsDepDivIndep._get_general_solution(self) fx = self.ode_problem.func if simplify_flag: sol1 = odesimp(self.ode_problem.eq, *sol1, fx, "1st_homogeneous_coeff_subs_indep_div_dep") sol2 = odesimp(self.ode_problem.eq, *sol2, fx, "1st_homogeneous_coeff_subs_dep_div_indep") return min([sol1, sol2], key=lambda x: ode_sol_simplicity(x, fx, trysolving=not simplify)) class LinearCoefficients(HomogeneousCoeffBest): r""" Solves a differential equation with linear coefficients. The general form of a differential equation with linear coefficients is .. math:: y' + F\left(\!\frac{a_1 x + b_1 y + c_1}{a_2 x + b_2 y + c_2}\!\right) = 0\text{,} where `a_1`, `b_1`, `c_1`, `a_2`, `b_2`, `c_2` are constants and `a_1 b_2 - a_2 b_1 \ne 0`. This can be solved by substituting: .. math:: x = x' + \frac{b_2 c_1 - b_1 c_2}{a_2 b_1 - a_1 b_2} y = y' + \frac{a_1 c_2 - a_2 c_1}{a_2 b_1 - a_1 b_2}\text{.} This substitution reduces the equation to a homogeneous differential equation. See Also ======== :obj:`sympy.solvers.ode.single.HomogeneousCoeffBest` :obj:`sympy.solvers.ode.single.HomogeneousCoeffSubsIndepDivDep` :obj:`sympy.solvers.ode.single.HomogeneousCoeffSubsDepDivIndep` Examples ======== >>> from sympy import Function, pprint >>> from sympy.solvers.ode.ode import dsolve >>> from sympy.abc import x >>> f = Function('f') >>> df = f(x).diff(x) >>> eq = (x + f(x) + 1)*df + (f(x) - 6*x + 1) >>> dsolve(eq, hint='linear_coefficients') [Eq(f(x), -x - sqrt(C1 + 7*x**2) - 1), Eq(f(x), -x + sqrt(C1 + 7*x**2) - 1)] >>> pprint(dsolve(eq, hint='linear_coefficients')) ___________ ___________ / 2 / 2 [f(x) = -x - \/ C1 + 7*x - 1, f(x) = -x + \/ C1 + 7*x - 1] References ========== - Joel Moses, "Symbolic Integration - The Stormy Decade", Communications of the ACM, Volume 14, Number 8, August 1971, pp. 558 """ hint = "linear_coefficients" has_integral = True order = [1] def _wilds(self, f, x, order): d = Wild('d', exclude=[f(x).diff(x), f(x).diff(x, 2)]) e = Wild('e', exclude=[f(x).diff(x)]) return d, e def _equation(self, fx, x, order): d, e = self.wilds() return d + e*fx.diff(x) def _verify(self, fx): self.d, self.e = self.wilds_match() a, b = self.wilds() F = self.d/self.e x = self.ode_problem.sym params = self._linear_coeff_match(F, fx) if params: self.xarg, self.yarg = params u = Dummy('u') t = Dummy('t') self.y = Dummy('y') # Dummy substitution for df and f(x). dummy_eq = self.ode_problem.eq.subs(((fx.diff(x), t), (fx, u))) reps = ((x, x + self.xarg), (u, u + self.yarg), (t, fx.diff(x)), (u, fx)) dummy_eq = simplify(dummy_eq.subs(reps)) # get the re-cast values for e and d r2 = collect(expand(dummy_eq), [fx.diff(x), fx]).match(a*fx.diff(x) + b) if r2: self.d, self.e = r2[b], r2[a] orderd = homogeneous_order(self.d, x, fx) ordere = homogeneous_order(self.e, x, fx) if orderd == ordere and orderd is not None: self.d = self.d.subs(fx, self.y) self.e = self.e.subs(fx, self.y) return True return False return False def _linear_coeff_match(self, expr, func): r""" Helper function to match hint ``linear_coefficients``. Matches the expression to the form `(a_1 x + b_1 f(x) + c_1)/(a_2 x + b_2 f(x) + c_2)` where the following conditions hold: 1. `a_1`, `b_1`, `c_1`, `a_2`, `b_2`, `c_2` are Rationals; 2. `c_1` or `c_2` are not equal to zero; 3. `a_2 b_1 - a_1 b_2` is not equal to zero. Return ``xarg``, ``yarg`` where 1. ``xarg`` = `(b_2 c_1 - b_1 c_2)/(a_2 b_1 - a_1 b_2)` 2. ``yarg`` = `(a_1 c_2 - a_2 c_1)/(a_2 b_1 - a_1 b_2)` Examples ======== >>> from sympy import Function >>> from sympy.abc import x >>> from sympy.solvers.ode.single import LinearCoefficients >>> from sympy.functions.elementary.trigonometric import sin >>> f = Function('f') >>> eq = (-25*f(x) - 8*x + 62)/(4*f(x) + 11*x - 11) >>> obj = LinearCoefficients(eq) >>> obj._linear_coeff_match(eq, f(x)) (1/9, 22/9) >>> eq = sin((-5*f(x) - 8*x + 6)/(4*f(x) + x - 1)) >>> obj = LinearCoefficients(eq) >>> obj._linear_coeff_match(eq, f(x)) (19/27, 2/27) >>> eq = sin(f(x)/x) >>> obj = LinearCoefficients(eq) >>> obj._linear_coeff_match(eq, f(x)) """ f = func.func x = func.args[0] def abc(eq): r''' Internal function of _linear_coeff_match that returns Rationals a, b, c if eq is a*x + b*f(x) + c, else None. ''' eq = _mexpand(eq) c = eq.as_independent(x, f(x), as_Add=True)[0] if not c.is_Rational: return a = eq.coeff(x) if not a.is_Rational: return b = eq.coeff(f(x)) if not b.is_Rational: return if eq == a*x + b*f(x) + c: return a, b, c def match(arg): r''' Internal function of _linear_coeff_match that returns Rationals a1, b1, c1, a2, b2, c2 and a2*b1 - a1*b2 of the expression (a1*x + b1*f(x) + c1)/(a2*x + b2*f(x) + c2) if one of c1 or c2 and a2*b1 - a1*b2 is non-zero, else None. ''' n, d = arg.together().as_numer_denom() m = abc(n) if m is not None: a1, b1, c1 = m m = abc(d) if m is not None: a2, b2, c2 = m d = a2*b1 - a1*b2 if (c1 or c2) and d: return a1, b1, c1, a2, b2, c2, d m = [fi.args[0] for fi in expr.atoms(Function) if fi.func != f and len(fi.args) == 1 and not fi.args[0].is_Function] or {expr} m1 = match(m.pop()) if m1 and all(match(mi) == m1 for mi in m): a1, b1, c1, a2, b2, c2, denom = m1 return (b2*c1 - b1*c2)/denom, (a1*c2 - a2*c1)/denom def _get_match_object(self): fx = self.ode_problem.func x = self.ode_problem.sym self.u1 = Dummy('u1') u = Dummy('u') return [self.d, self.e, fx, x, u, self.u1, self.y, self.xarg, self.yarg] class NthOrderReducible(SingleODESolver): r""" Solves ODEs that only involve derivatives of the dependent variable using a substitution of the form `f^n(x) = g(x)`. For example any second order ODE of the form `f''(x) = h(f'(x), x)` can be transformed into a pair of 1st order ODEs `g'(x) = h(g(x), x)` and `f'(x) = g(x)`. Usually the 1st order ODE for `g` is easier to solve. If that gives an explicit solution for `g` then `f` is found simply by integration. Examples ======== >>> from sympy import Function, dsolve, Eq >>> from sympy.abc import x >>> f = Function('f') >>> eq = Eq(x*f(x).diff(x)**2 + f(x).diff(x, 2), 0) >>> dsolve(eq, f(x), hint='nth_order_reducible') ... # doctest: +NORMALIZE_WHITESPACE Eq(f(x), C1 - sqrt(-1/C2)*log(-C2*sqrt(-1/C2) + x) + sqrt(-1/C2)*log(C2*sqrt(-1/C2) + x)) """ hint = "nth_order_reducible" has_integral = False def _matches(self): # Any ODE that can be solved with a substitution and # repeated integration e.g.: # `d^2/dx^2(y) + x*d/dx(y) = constant #f'(x) must be finite for this to work eq = self.ode_problem.eq_preprocessed func = self.ode_problem.func x = self.ode_problem.sym r""" Matches any differential equation that can be rewritten with a smaller order. Only derivatives of ``func`` alone, wrt a single variable, are considered, and only in them should ``func`` appear. """ # ODE only handles functions of 1 variable so this affirms that state assert len(func.args) == 1 vc = [d.variable_count[0] for d in eq.atoms(Derivative) if d.expr == func and len(d.variable_count) == 1] ords = [c for v, c in vc if v == x] if len(ords) < 2: return False self.smallest = min(ords) # make sure func does not appear outside of derivatives D = Dummy() if eq.subs(func.diff(x, self.smallest), D).has(func): return False return True def _get_general_solution(self, *, simplify_flag: bool = True): eq = self.ode_problem.eq f = self.ode_problem.func.func x = self.ode_problem.sym n = self.smallest # get a unique function name for g names = [a.name for a in eq.atoms(AppliedUndef)] while True: name = Dummy().name if name not in names: g = Function(name) break w = f(x).diff(x, n) geq = eq.subs(w, g(x)) gsol = dsolve(geq, g(x)) if not isinstance(gsol, list): gsol = [gsol] # Might be multiple solutions to the reduced ODE: fsol = [] for gsoli in gsol: fsoli = dsolve(gsoli.subs(g(x), w), f(x)) # or do integration n times fsol.append(fsoli) return fsol class SecondHypergeometric(SingleODESolver): r""" Solves 2nd order linear differential equations. It computes special function solutions which can be expressed using the 2F1, 1F1 or 0F1 hypergeometric functions. .. math:: y'' + A(x) y' + B(x) y = 0\text{,} where `A` and `B` are rational functions. These kinds of differential equations have solution of non-Liouvillian form. Given linear ODE can be obtained from 2F1 given by .. math:: (x^2 - x) y'' + ((a + b + 1) x - c) y' + b a y = 0\text{,} where {a, b, c} are arbitrary constants. Notes ===== The algorithm should find any solution of the form .. math:: y = P(x) _pF_q(..; ..;\frac{\alpha x^k + \beta}{\gamma x^k + \delta})\text{,} where pFq is any of 2F1, 1F1 or 0F1 and `P` is an "arbitrary function". Currently only the 2F1 case is implemented in SymPy but the other cases are described in the paper and could be implemented in future (contributions welcome!). Examples ======== >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> eq = (x*x - x)*f(x).diff(x,2) + (5*x - 1)*f(x).diff(x) + 4*f(x) >>> pprint(dsolve(eq, f(x), '2nd_hypergeometric')) _ / / 4 \\ |_ /-1, -1 | \ |C1 + C2*|log(x) + -----||* | | | x| \ \ x + 1// 2 1 \ 1 | / f(x) = -------------------------------------------- 3 (x - 1) References ========== - "Non-Liouvillian solutions for second order linear ODEs" by L. Chan, E.S. Cheb-Terrab """ hint = "2nd_hypergeometric" has_integral = True def _matches(self): eq = self.ode_problem.eq_preprocessed func = self.ode_problem.func r = match_2nd_hypergeometric(eq, func) self.match_object = None if r: A, B = r d = equivalence_hypergeometric(A, B, func) if d: if d['type'] == "2F1": self.match_object = match_2nd_2F1_hypergeometric(d['I0'], d['k'], d['sing_point'], func) if self.match_object is not None: self.match_object.update({'A':A, 'B':B}) # We can extend it for 1F1 and 0F1 type also. return self.match_object is not None def _get_general_solution(self, *, simplify_flag: bool = True): eq = self.ode_problem.eq func = self.ode_problem.func if self.match_object['type'] == "2F1": sol = get_sol_2F1_hypergeometric(eq, func, self.match_object) if sol is None: raise NotImplementedError("The given ODE " + str(eq) + " cannot be solved by" + " the hypergeometric method") return [sol] class NthLinearConstantCoeffHomogeneous(SingleODESolver): r""" Solves an `n`\th order linear homogeneous differential equation with constant coefficients. This is an equation of the form .. math:: a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = 0\text{.} These equations can be solved in a general manner, by taking the roots of the characteristic equation `a_n m^n + a_{n-1} m^{n-1} + \cdots + a_1 m + a_0 = 0`. The solution will then be the sum of `C_n x^i e^{r x}` terms, for each where `C_n` is an arbitrary constant, `r` is a root of the characteristic equation and `i` is one of each from 0 to the multiplicity of the root - 1 (for example, a root 3 of multiplicity 2 would create the terms `C_1 e^{3 x} + C_2 x e^{3 x}`). The exponential is usually expanded for complex roots using Euler's equation `e^{I x} = \cos(x) + I \sin(x)`. Complex roots always come in conjugate pairs in polynomials with real coefficients, so the two roots will be represented (after simplifying the constants) as `e^{a x} \left(C_1 \cos(b x) + C_2 \sin(b x)\right)`. If SymPy cannot find exact roots to the characteristic equation, a :py:class:`~sympy.polys.rootoftools.ComplexRootOf` instance will be return instead. >>> from sympy import Function, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(f(x).diff(x, 5) + 10*f(x).diff(x) - 2*f(x), f(x), ... hint='nth_linear_constant_coeff_homogeneous') ... # doctest: +NORMALIZE_WHITESPACE Eq(f(x), C5*exp(x*CRootOf(_x**5 + 10*_x - 2, 0)) + (C1*sin(x*im(CRootOf(_x**5 + 10*_x - 2, 1))) + C2*cos(x*im(CRootOf(_x**5 + 10*_x - 2, 1))))*exp(x*re(CRootOf(_x**5 + 10*_x - 2, 1))) + (C3*sin(x*im(CRootOf(_x**5 + 10*_x - 2, 3))) + C4*cos(x*im(CRootOf(_x**5 + 10*_x - 2, 3))))*exp(x*re(CRootOf(_x**5 + 10*_x - 2, 3)))) Note that because this method does not involve integration, there is no ``nth_linear_constant_coeff_homogeneous_Integral`` hint. Examples ======== >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x, 4) + 2*f(x).diff(x, 3) - ... 2*f(x).diff(x, 2) - 6*f(x).diff(x) + 5*f(x), f(x), ... hint='nth_linear_constant_coeff_homogeneous')) x -2*x f(x) = (C1 + C2*x)*e + (C3*sin(x) + C4*cos(x))*e References ========== - https://en.wikipedia.org/wiki/Linear_differential_equation section: Nonhomogeneous_equation_with_constant_coefficients - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 211 # indirect doctest """ hint = "nth_linear_constant_coeff_homogeneous" has_integral = False def _matches(self): eq = self.ode_problem.eq_high_order_free func = self.ode_problem.func order = self.ode_problem.order x = self.ode_problem.sym self.r = self.ode_problem.get_linear_coefficients(eq, func, order) if order and self.r and not any(self.r[i].has(x) for i in self.r if i >= 0): if not self.r[-1]: return True else: return False return False def _get_general_solution(self, *, simplify_flag: bool = True): fx = self.ode_problem.func order = self.ode_problem.order roots, collectterms = _get_const_characteristic_eq_sols(self.r, fx, order) # A generator of constants constants = self.ode_problem.get_numbered_constants(num=len(roots)) gsol = Add(*[i*j for (i, j) in zip(constants, roots)]) gsol = Eq(fx, gsol) if simplify_flag: gsol = _get_simplified_sol([gsol], fx, collectterms) return [gsol] class NthLinearConstantCoeffVariationOfParameters(SingleODESolver): r""" Solves an `n`\th order linear differential equation with constant coefficients using the method of variation of parameters. This method works on any differential equations of the form .. math:: f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = P(x)\text{.} This method works by assuming that the particular solution takes the form .. math:: \sum_{x=1}^{n} c_i(x) y_i(x)\text{,} where `y_i` is the `i`\th solution to the homogeneous equation. The solution is then solved using Wronskian's and Cramer's Rule. The particular solution is given by .. math:: \sum_{x=1}^n \left( \int \frac{W_i(x)}{W(x)} \,dx \right) y_i(x) \text{,} where `W(x)` is the Wronskian of the fundamental system (the system of `n` linearly independent solutions to the homogeneous equation), and `W_i(x)` is the Wronskian of the fundamental system with the `i`\th column replaced with `[0, 0, \cdots, 0, P(x)]`. This method is general enough to solve any `n`\th order inhomogeneous linear differential equation with constant coefficients, but sometimes SymPy cannot simplify the Wronskian well enough to integrate it. If this method hangs, try using the ``nth_linear_constant_coeff_variation_of_parameters_Integral`` hint and simplifying the integrals manually. Also, prefer using ``nth_linear_constant_coeff_undetermined_coefficients`` when it applies, because it doesn't use integration, making it faster and more reliable. Warning, using simplify=False with 'nth_linear_constant_coeff_variation_of_parameters' in :py:meth:`~sympy.solvers.ode.dsolve` may cause it to hang, because it will not attempt to simplify the Wronskian before integrating. It is recommended that you only use simplify=False with 'nth_linear_constant_coeff_variation_of_parameters_Integral' for this method, especially if the solution to the homogeneous equation has trigonometric functions in it. Examples ======== >>> from sympy import Function, dsolve, pprint, exp, log >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x, 3) - 3*f(x).diff(x, 2) + ... 3*f(x).diff(x) - f(x) - exp(x)*log(x), f(x), ... hint='nth_linear_constant_coeff_variation_of_parameters')) / / / x*log(x) 11*x\\\ x f(x) = |C1 + x*|C2 + x*|C3 + -------- - ----|||*e \ \ \ 6 36 /// References ========== - https://en.wikipedia.org/wiki/Variation_of_parameters - http://planetmath.org/VariationOfParameters - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 233 # indirect doctest """ hint = "nth_linear_constant_coeff_variation_of_parameters" has_integral = True def _matches(self): eq = self.ode_problem.eq_high_order_free func = self.ode_problem.func order = self.ode_problem.order x = self.ode_problem.sym self.r = self.ode_problem.get_linear_coefficients(eq, func, order) if order and self.r and not any(self.r[i].has(x) for i in self.r if i >= 0): if self.r[-1]: return True else: return False return False def _get_general_solution(self, *, simplify_flag: bool = True): eq = self.ode_problem.eq_high_order_free f = self.ode_problem.func.func x = self.ode_problem.sym order = self.ode_problem.order roots, collectterms = _get_const_characteristic_eq_sols(self.r, f(x), order) # A generator of constants constants = self.ode_problem.get_numbered_constants(num=len(roots)) homogen_sol = Add(*[i*j for (i, j) in zip(constants, roots)]) homogen_sol = Eq(f(x), homogen_sol) homogen_sol = _solve_variation_of_parameters(eq, f(x), roots, homogen_sol, order, self.r, simplify_flag) if simplify_flag: homogen_sol = _get_simplified_sol([homogen_sol], f(x), collectterms) return [homogen_sol] class NthLinearConstantCoeffUndeterminedCoefficients(SingleODESolver): r""" Solves an `n`\th order linear differential equation with constant coefficients using the method of undetermined coefficients. This method works on differential equations of the form .. math:: a_n f^{(n)}(x) + a_{n-1} f^{(n-1)}(x) + \cdots + a_1 f'(x) + a_0 f(x) = P(x)\text{,} where `P(x)` is a function that has a finite number of linearly independent derivatives. Functions that fit this requirement are finite sums functions of the form `a x^i e^{b x} \sin(c x + d)` or `a x^i e^{b x} \cos(c x + d)`, where `i` is a non-negative integer and `a`, `b`, `c`, and `d` are constants. For example any polynomial in `x`, functions like `x^2 e^{2 x}`, `x \sin(x)`, and `e^x \cos(x)` can all be used. Products of `\sin`'s and `\cos`'s have a finite number of derivatives, because they can be expanded into `\sin(a x)` and `\cos(b x)` terms. However, SymPy currently cannot do that expansion, so you will need to manually rewrite the expression in terms of the above to use this method. So, for example, you will need to manually convert `\sin^2(x)` into `(1 + \cos(2 x))/2` to properly apply the method of undetermined coefficients on it. This method works by creating a trial function from the expression and all of its linear independent derivatives and substituting them into the original ODE. The coefficients for each term will be a system of linear equations, which are be solved for and substituted, giving the solution. If any of the trial functions are linearly dependent on the solution to the homogeneous equation, they are multiplied by sufficient `x` to make them linearly independent. Examples ======== >>> from sympy import Function, dsolve, pprint, exp, cos >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x, 2) + 2*f(x).diff(x) + f(x) - ... 4*exp(-x)*x**2 + cos(2*x), f(x), ... hint='nth_linear_constant_coeff_undetermined_coefficients')) / / 3\\ | | x || -x 4*sin(2*x) 3*cos(2*x) f(x) = |C1 + x*|C2 + --||*e - ---------- + ---------- \ \ 3 // 25 25 References ========== - https://en.wikipedia.org/wiki/Method_of_undetermined_coefficients - M. Tenenbaum & H. Pollard, "Ordinary Differential Equations", Dover 1963, pp. 221 # indirect doctest """ hint = "nth_linear_constant_coeff_undetermined_coefficients" has_integral = False def _matches(self): eq = self.ode_problem.eq_high_order_free func = self.ode_problem.func order = self.ode_problem.order x = self.ode_problem.sym self.r = self.ode_problem.get_linear_coefficients(eq, func, order) does_match = False if order and self.r and not any(self.r[i].has(x) for i in self.r if i >= 0): if self.r[-1]: eq_homogeneous = Add(eq, -self.r[-1]) undetcoeff = _undetermined_coefficients_match(self.r[-1], x, func, eq_homogeneous) if undetcoeff['test']: self.trialset = undetcoeff['trialset'] does_match = True return does_match def _get_general_solution(self, *, simplify_flag: bool = True): eq = self.ode_problem.eq f = self.ode_problem.func.func x = self.ode_problem.sym order = self.ode_problem.order roots, collectterms = _get_const_characteristic_eq_sols(self.r, f(x), order) # A generator of constants constants = self.ode_problem.get_numbered_constants(num=len(roots)) homogen_sol = Add(*[i*j for (i, j) in zip(constants, roots)]) homogen_sol = Eq(f(x), homogen_sol) self.r.update({'list': roots, 'sol': homogen_sol, 'simpliy_flag': simplify_flag}) gsol = _solve_undetermined_coefficients(eq, f(x), order, self.r, self.trialset) if simplify_flag: gsol = _get_simplified_sol([gsol], f(x), collectterms) return [gsol] class NthLinearEulerEqHomogeneous(SingleODESolver): r""" Solves an `n`\th order linear homogeneous variable-coefficient Cauchy-Euler equidimensional ordinary differential equation. This is an equation with form `0 = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) \cdots`. These equations can be solved in a general manner, by substituting solutions of the form `f(x) = x^r`, and deriving a characteristic equation for `r`. When there are repeated roots, we include extra terms of the form `C_{r k} \ln^k(x) x^r`, where `C_{r k}` is an arbitrary integration constant, `r` is a root of the characteristic equation, and `k` ranges over the multiplicity of `r`. In the cases where the roots are complex, solutions of the form `C_1 x^a \sin(b \log(x)) + C_2 x^a \cos(b \log(x))` are returned, based on expansions with Euler's formula. The general solution is the sum of the terms found. If SymPy cannot find exact roots to the characteristic equation, a :py:obj:`~.ComplexRootOf` instance will be returned instead. >>> from sympy import Function, dsolve >>> from sympy.abc import x >>> f = Function('f') >>> dsolve(4*x**2*f(x).diff(x, 2) + f(x), f(x), ... hint='nth_linear_euler_eq_homogeneous') ... # doctest: +NORMALIZE_WHITESPACE Eq(f(x), sqrt(x)*(C1 + C2*log(x))) Note that because this method does not involve integration, there is no ``nth_linear_euler_eq_homogeneous_Integral`` hint. The following is for internal use: - ``returns = 'sol'`` returns the solution to the ODE. - ``returns = 'list'`` returns a list of linearly independent solutions, corresponding to the fundamental solution set, for use with non homogeneous solution methods like variation of parameters and undetermined coefficients. Note that, though the solutions should be linearly independent, this function does not explicitly check that. You can do ``assert simplify(wronskian(sollist)) != 0`` to check for linear independence. Also, ``assert len(sollist) == order`` will need to pass. - ``returns = 'both'``, return a dictionary ``{'sol': , 'list': }``. Examples ======== >>> from sympy import Function, dsolve, pprint >>> from sympy.abc import x >>> f = Function('f') >>> eq = f(x).diff(x, 2)*x**2 - 4*f(x).diff(x)*x + 6*f(x) >>> pprint(dsolve(eq, f(x), ... hint='nth_linear_euler_eq_homogeneous')) 2 f(x) = x *(C1 + C2*x) References ========== - https://en.wikipedia.org/wiki/Cauchy%E2%80%93Euler_equation - C. Bender & S. Orszag, "Advanced Mathematical Methods for Scientists and Engineers", Springer 1999, pp. 12 # indirect doctest """ hint = "nth_linear_euler_eq_homogeneous" has_integral = False def _matches(self): eq = self.ode_problem.eq_preprocessed f = self.ode_problem.func.func order = self.ode_problem.order x = self.ode_problem.sym match = self.ode_problem.get_linear_coefficients(eq, f(x), order) self.r = None does_match = False if order and match: coeff = match[order] factor = x**order / coeff self.r = {i: factor*match[i] for i in match} if self.r and not any(not _test_term(self.r[i], f(x), i) for i in self.r if i >= 0): if not self.r[-1]: does_match = True return does_match def _get_general_solution(self, *, simplify_flag: bool = True): fx = self.ode_problem.func eq = self.ode_problem.eq homogen_sol = _get_euler_characteristic_eq_sols(eq, fx, self.r)[0] return [homogen_sol] class NthLinearEulerEqNonhomogeneousVariationOfParameters(SingleODESolver): r""" Solves an `n`\th order linear non homogeneous Cauchy-Euler equidimensional ordinary differential equation using variation of parameters. This is an equation with form `g(x) = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) \cdots`. This method works by assuming that the particular solution takes the form .. math:: \sum_{x=1}^{n} c_i(x) y_i(x) {a_n} {x^n} \text{, } where `y_i` is the `i`\th solution to the homogeneous equation. The solution is then solved using Wronskian's and Cramer's Rule. The particular solution is given by multiplying eq given below with `a_n x^{n}` .. math:: \sum_{x=1}^n \left( \int \frac{W_i(x)}{W(x)} \, dx \right) y_i(x) \text{, } where `W(x)` is the Wronskian of the fundamental system (the system of `n` linearly independent solutions to the homogeneous equation), and `W_i(x)` is the Wronskian of the fundamental system with the `i`\th column replaced with `[0, 0, \cdots, 0, \frac{x^{- n}}{a_n} g{\left(x \right)}]`. This method is general enough to solve any `n`\th order inhomogeneous linear differential equation, but sometimes SymPy cannot simplify the Wronskian well enough to integrate it. If this method hangs, try using the ``nth_linear_constant_coeff_variation_of_parameters_Integral`` hint and simplifying the integrals manually. Also, prefer using ``nth_linear_constant_coeff_undetermined_coefficients`` when it applies, because it doesn't use integration, making it faster and more reliable. Warning, using simplify=False with 'nth_linear_constant_coeff_variation_of_parameters' in :py:meth:`~sympy.solvers.ode.dsolve` may cause it to hang, because it will not attempt to simplify the Wronskian before integrating. It is recommended that you only use simplify=False with 'nth_linear_constant_coeff_variation_of_parameters_Integral' for this method, especially if the solution to the homogeneous equation has trigonometric functions in it. Examples ======== >>> from sympy import Function, dsolve, Derivative >>> from sympy.abc import x >>> f = Function('f') >>> eq = x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - x**4 >>> dsolve(eq, f(x), ... hint='nth_linear_euler_eq_nonhomogeneous_variation_of_parameters').expand() Eq(f(x), C1*x + C2*x**2 + x**4/6) """ hint = "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters" has_integral = True def _matches(self): eq = self.ode_problem.eq_preprocessed f = self.ode_problem.func.func order = self.ode_problem.order x = self.ode_problem.sym match = self.ode_problem.get_linear_coefficients(eq, f(x), order) self.r = None does_match = False if order and match: coeff = match[order] factor = x**order / coeff self.r = {i: factor*match[i] for i in match} if self.r and not any(not _test_term(self.r[i], f(x), i) for i in self.r if i >= 0): if self.r[-1]: does_match = True return does_match def _get_general_solution(self, *, simplify_flag: bool = True): eq = self.ode_problem.eq f = self.ode_problem.func.func x = self.ode_problem.sym order = self.ode_problem.order homogen_sol, roots = _get_euler_characteristic_eq_sols(eq, f(x), self.r) self.r[-1] = self.r[-1]/self.r[order] sol = _solve_variation_of_parameters(eq, f(x), roots, homogen_sol, order, self.r, simplify_flag) return [Eq(f(x), homogen_sol.rhs + (sol.rhs - homogen_sol.rhs)*self.r[order])] class NthLinearEulerEqNonhomogeneousUndeterminedCoefficients(SingleODESolver): r""" Solves an `n`\th order linear non homogeneous Cauchy-Euler equidimensional ordinary differential equation using undetermined coefficients. This is an equation with form `g(x) = a_0 f(x) + a_1 x f'(x) + a_2 x^2 f''(x) \cdots`. These equations can be solved in a general manner, by substituting solutions of the form `x = exp(t)`, and deriving a characteristic equation of form `g(exp(t)) = b_0 f(t) + b_1 f'(t) + b_2 f''(t) \cdots` which can be then solved by nth_linear_constant_coeff_undetermined_coefficients if g(exp(t)) has finite number of linearly independent derivatives. Functions that fit this requirement are finite sums functions of the form `a x^i e^{b x} \sin(c x + d)` or `a x^i e^{b x} \cos(c x + d)`, where `i` is a non-negative integer and `a`, `b`, `c`, and `d` are constants. For example any polynomial in `x`, functions like `x^2 e^{2 x}`, `x \sin(x)`, and `e^x \cos(x)` can all be used. Products of `\sin`'s and `\cos`'s have a finite number of derivatives, because they can be expanded into `\sin(a x)` and `\cos(b x)` terms. However, SymPy currently cannot do that expansion, so you will need to manually rewrite the expression in terms of the above to use this method. So, for example, you will need to manually convert `\sin^2(x)` into `(1 + \cos(2 x))/2` to properly apply the method of undetermined coefficients on it. After replacement of x by exp(t), this method works by creating a trial function from the expression and all of its linear independent derivatives and substituting them into the original ODE. The coefficients for each term will be a system of linear equations, which are be solved for and substituted, giving the solution. If any of the trial functions are linearly dependent on the solution to the homogeneous equation, they are multiplied by sufficient `x` to make them linearly independent. Examples ======== >>> from sympy import dsolve, Function, Derivative, log >>> from sympy.abc import x >>> f = Function('f') >>> eq = x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - log(x) >>> dsolve(eq, f(x), ... hint='nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients').expand() Eq(f(x), C1*x + C2*x**2 + log(x)/2 + 3/4) """ hint = "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients" has_integral = False def _matches(self): eq = self.ode_problem.eq_high_order_free f = self.ode_problem.func.func order = self.ode_problem.order x = self.ode_problem.sym match = self.ode_problem.get_linear_coefficients(eq, f(x), order) self.r = None does_match = False if order and match: coeff = match[order] factor = x**order / coeff self.r = {i: factor*match[i] for i in match} if self.r and not any(not _test_term(self.r[i], f(x), i) for i in self.r if i >= 0): if self.r[-1]: e, re = posify(self.r[-1].subs(x, exp(x))) undetcoeff = _undetermined_coefficients_match(e.subs(re), x) if undetcoeff['test']: does_match = True return does_match def _get_general_solution(self, *, simplify_flag: bool = True): f = self.ode_problem.func.func x = self.ode_problem.sym chareq, eq, symbol = S.Zero, S.Zero, Dummy('x') for i in self.r.keys(): if i >= 0: chareq += (self.r[i]*diff(x**symbol, x, i)*x**-symbol).expand() for i in range(1, degree(Poly(chareq, symbol))+1): eq += chareq.coeff(symbol**i)*diff(f(x), x, i) if chareq.as_coeff_add(symbol)[0]: eq += chareq.as_coeff_add(symbol)[0]*f(x) e, re = posify(self.r[-1].subs(x, exp(x))) eq += e.subs(re) self.const_undet_instance = NthLinearConstantCoeffUndeterminedCoefficients(SingleODEProblem(eq, f(x), x)) sol = self.const_undet_instance.get_general_solution(simplify = simplify_flag)[0] sol = sol.subs(x, log(x)) sol = sol.subs(f(log(x)), f(x)).expand() return [sol] class SecondLinearBessel(SingleODESolver): r""" Gives solution of the Bessel differential equation .. math :: x^2 \frac{d^2y}{dx^2} + x \frac{dy}{dx} y(x) + (x^2-n^2) y(x) if `n` is integer then the solution is of the form ``Eq(f(x), C0 besselj(n,x) + C1 bessely(n,x))`` as both the solutions are linearly independent else if `n` is a fraction then the solution is of the form ``Eq(f(x), C0 besselj(n,x) + C1 besselj(-n,x))`` which can also transform into ``Eq(f(x), C0 besselj(n,x) + C1 bessely(n,x))``. Examples ======== >>> from sympy.abc import x >>> from sympy import Symbol >>> v = Symbol('v', positive=True) >>> from sympy.solvers.ode import dsolve >>> from sympy import Function >>> f = Function('f') >>> y = f(x) >>> genform = x**2*y.diff(x, 2) + x*y.diff(x) + (x**2 - v**2)*y >>> dsolve(genform) Eq(f(x), C1*besselj(v, x) + C2*bessely(v, x)) References ========== https://www.math24.net/bessel-differential-equation/ """ hint = "2nd_linear_bessel" has_integral = False def _matches(self): eq = self.ode_problem.eq_high_order_free f = self.ode_problem.func order = self.ode_problem.order x = self.ode_problem.sym df = f.diff(x) a = Wild('a', exclude=[f,df]) b = Wild('b', exclude=[x, f,df]) a4 = Wild('a4', exclude=[x,f,df]) b4 = Wild('b4', exclude=[x,f,df]) c4 = Wild('c4', exclude=[x,f,df]) d4 = Wild('d4', exclude=[x,f,df]) a3 = Wild('a3', exclude=[f, df, f.diff(x, 2)]) b3 = Wild('b3', exclude=[f, df, f.diff(x, 2)]) c3 = Wild('c3', exclude=[f, df, f.diff(x, 2)]) deq = a3*(f.diff(x, 2)) + b3*df + c3*f r = collect(eq, [f.diff(x, 2), df, f]).match(deq) if order == 2 and r: if not all([r[key].is_polynomial() for key in r]): n, d = eq.as_numer_denom() eq = expand(n) r = collect(eq, [f.diff(x, 2), df, f]).match(deq) if r and r[a3] != 0: # leading coeff of f(x).diff(x, 2) coeff = factor(r[a3]).match(a4*(x-b)**b4) if coeff: # if coeff[b4] = 0 means constant coefficient if coeff[b4] == 0: return False point = coeff[b] else: return False if point: r[a3] = simplify(r[a3].subs(x, x+point)) r[b3] = simplify(r[b3].subs(x, x+point)) r[c3] = simplify(r[c3].subs(x, x+point)) # making a3 in the form of x**2 r[a3] = cancel(r[a3]/(coeff[a4]*(x)**(-2+coeff[b4]))) r[b3] = cancel(r[b3]/(coeff[a4]*(x)**(-2+coeff[b4]))) r[c3] = cancel(r[c3]/(coeff[a4]*(x)**(-2+coeff[b4]))) # checking if b3 is of form c*(x-b) coeff1 = factor(r[b3]).match(a4*(x)) if coeff1 is None: return False # c3 maybe of very complex form so I am simply checking (a - b) form # if yes later I will match with the standerd form of bessel in a and b # a, b are wild variable defined above. _coeff2 = r[c3].match(a - b) if _coeff2 is None: return False # matching with standerd form for c3 coeff2 = factor(_coeff2[a]).match(c4**2*(x)**(2*a4)) if coeff2 is None: return False if _coeff2[b] == 0: coeff2[d4] = 0 else: coeff2[d4] = factor(_coeff2[b]).match(d4**2)[d4] self.rn = {'n':coeff2[d4], 'a4':coeff2[c4], 'd4':coeff2[a4]} self.rn['c4'] = coeff1[a4] self.rn['b4'] = point return True return False def _get_general_solution(self, *, simplify_flag: bool = True): f = self.ode_problem.func.func x = self.ode_problem.sym n = self.rn['n'] a4 = self.rn['a4'] c4 = self.rn['c4'] d4 = self.rn['d4'] b4 = self.rn['b4'] n = sqrt(n**2 + Rational(1, 4)*(c4 - 1)**2) (C1, C2) = self.ode_problem.get_numbered_constants(num=2) return [Eq(f(x), ((x**(Rational(1-c4,2)))*(C1*besselj(n/d4,a4*x**d4/d4) + C2*bessely(n/d4,a4*x**d4/d4))).subs(x, x-b4))] class SecondLinearAiry(SingleODESolver): r""" Gives solution of the Airy differential equation .. math :: \frac{d^2y}{dx^2} + (a + b x) y(x) = 0 in terms of Airy special functions airyai and airybi. Examples ======== >>> from sympy import dsolve, Function >>> from sympy.abc import x >>> f = Function("f") >>> eq = f(x).diff(x, 2) - x*f(x) >>> dsolve(eq) Eq(f(x), C1*airyai(x) + C2*airybi(x)) """ hint = "2nd_linear_airy" has_integral = False def _matches(self): eq = self.ode_problem.eq_high_order_free f = self.ode_problem.func order = self.ode_problem.order x = self.ode_problem.sym df = f.diff(x) a4 = Wild('a4', exclude=[x,f,df]) b4 = Wild('b4', exclude=[x,f,df]) match = self.ode_problem.get_linear_coefficients(eq, f, order) does_match = False if order == 2 and match and match[2] != 0: if match[1].is_zero: self.rn = cancel(match[0]/match[2]).match(a4+b4*x) if self.rn and self.rn[b4] != 0: self.rn = {'b':self.rn[a4],'m':self.rn[b4]} does_match = True return does_match def _get_general_solution(self, *, simplify_flag: bool = True): f = self.ode_problem.func.func x = self.ode_problem.sym (C1, C2) = self.ode_problem.get_numbered_constants(num=2) b = self.rn['b'] m = self.rn['m'] if m.is_positive: arg = - b/cbrt(m)**2 - cbrt(m)*x elif m.is_negative: arg = - b/cbrt(-m)**2 + cbrt(-m)*x else: arg = - b/cbrt(-m)**2 + cbrt(-m)*x return [Eq(f(x), C1*airyai(arg) + C2*airybi(arg))] class LieGroup(SingleODESolver): r""" This hint implements the Lie group method of solving first order differential equations. The aim is to convert the given differential equation from the given coordinate system into another coordinate system where it becomes invariant under the one-parameter Lie group of translations. The converted ODE can be easily solved by quadrature. It makes use of the :py:meth:`sympy.solvers.ode.infinitesimals` function which returns the infinitesimals of the transformation. The coordinates `r` and `s` can be found by solving the following Partial Differential Equations. .. math :: \xi\frac{\partial r}{\partial x} + \eta\frac{\partial r}{\partial y} = 0 .. math :: \xi\frac{\partial s}{\partial x} + \eta\frac{\partial s}{\partial y} = 1 The differential equation becomes separable in the new coordinate system .. math :: \frac{ds}{dr} = \frac{\frac{\partial s}{\partial x} + h(x, y)\frac{\partial s}{\partial y}}{ \frac{\partial r}{\partial x} + h(x, y)\frac{\partial r}{\partial y}} After finding the solution by integration, it is then converted back to the original coordinate system by substituting `r` and `s` in terms of `x` and `y` again. Examples ======== >>> from sympy import Function, dsolve, exp, pprint >>> from sympy.abc import x >>> f = Function('f') >>> pprint(dsolve(f(x).diff(x) + 2*x*f(x) - x*exp(-x**2), f(x), ... hint='lie_group')) / 2\ 2 | x | -x f(x) = |C1 + --|*e \ 2 / References ========== - Solving differential equations by Symmetry Groups, John Starrett, pp. 1 - pp. 14 """ hint = "lie_group" has_integral = False def _has_additional_params(self): return 'xi' in self.ode_problem.params and 'eta' in self.ode_problem.params def _matches(self): eq = self.ode_problem.eq f = self.ode_problem.func.func order = self.ode_problem.order x = self.ode_problem.sym df = f(x).diff(x) y = Dummy('y') d = Wild('d', exclude=[df, f(x).diff(x, 2)]) e = Wild('e', exclude=[df]) does_match = False if self._has_additional_params() and order == 1: xi = self.ode_problem.params['xi'] eta = self.ode_problem.params['eta'] self.r3 = {'xi': xi, 'eta': eta} r = collect(eq, df, exact=True).match(d + e * df) if r: r['d'] = d r['e'] = e r['y'] = y r[d] = r[d].subs(f(x), y) r[e] = r[e].subs(f(x), y) self.r3.update(r) does_match = True return does_match def _get_general_solution(self, *, simplify_flag: bool = True): eq = self.ode_problem.eq x = self.ode_problem.sym func = self.ode_problem.func order = self.ode_problem.order df = func.diff(x) try: eqsol = solve(eq, df) except NotImplementedError: eqsol = [] desols = [] for s in eqsol: sol = _ode_lie_group(s, func, order, match=self.r3) if sol: desols.extend(sol) if desols == []: raise NotImplementedError("The given ODE " + str(eq) + " cannot be solved by" + " the lie group method") return desols solver_map = { 'factorable': Factorable, 'nth_linear_constant_coeff_homogeneous': NthLinearConstantCoeffHomogeneous, 'nth_linear_euler_eq_homogeneous': NthLinearEulerEqHomogeneous, 'nth_linear_constant_coeff_undetermined_coefficients': NthLinearConstantCoeffUndeterminedCoefficients, 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients': NthLinearEulerEqNonhomogeneousUndeterminedCoefficients, 'separable': Separable, '1st_exact': FirstExact, '1st_linear': FirstLinear, 'Bernoulli': Bernoulli, 'Riccati_special_minus2': RiccatiSpecial, '1st_rational_riccati': RationalRiccati, '1st_homogeneous_coeff_best': HomogeneousCoeffBest, '1st_homogeneous_coeff_subs_indep_div_dep': HomogeneousCoeffSubsIndepDivDep, '1st_homogeneous_coeff_subs_dep_div_indep': HomogeneousCoeffSubsDepDivIndep, 'almost_linear': AlmostLinear, 'linear_coefficients': LinearCoefficients, 'separable_reduced': SeparableReduced, 'nth_linear_constant_coeff_variation_of_parameters': NthLinearConstantCoeffVariationOfParameters, 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters': NthLinearEulerEqNonhomogeneousVariationOfParameters, 'Liouville': Liouville, '2nd_linear_airy': SecondLinearAiry, '2nd_linear_bessel': SecondLinearBessel, '2nd_hypergeometric': SecondHypergeometric, 'nth_order_reducible': NthOrderReducible, '2nd_nonlinear_autonomous_conserved': SecondNonlinearAutonomousConserved, 'nth_algebraic': NthAlgebraic, 'lie_group': LieGroup, } # Avoid circular import: from .ode import dsolve, ode_sol_simplicity, odesimp, homogeneous_order sympy-sympy-1.9/sympy/solvers/ode/subscheck.py000066400000000000000000000374531412543434000217100ustar00rootroot00000000000000from sympy.core import S, Pow from sympy.core.compatibility import iterable, is_sequence from sympy.core.function import (Derivative, AppliedUndef, diff) from sympy.core.relational import Equality, Eq from sympy.core.symbol import Dummy from sympy.core.sympify import sympify from sympy.logic.boolalg import BooleanAtom from sympy.functions import exp from sympy.series import Order from sympy.simplify.simplify import simplify, posify, besselsimp from sympy.simplify.trigsimp import trigsimp from sympy.simplify.sqrtdenest import sqrtdenest from sympy.solvers import solve from sympy.solvers.deutils import _preprocess, ode_order def sub_func_doit(eq, func, new): r""" When replacing the func with something else, we usually want the derivative evaluated, so this function helps in making that happen. Examples ======== >>> from sympy import Derivative, symbols, Function >>> from sympy.solvers.ode.subscheck import sub_func_doit >>> x, z = symbols('x, z') >>> y = Function('y') >>> sub_func_doit(3*Derivative(y(x), x) - 1, y(x), x) 2 >>> sub_func_doit(x*Derivative(y(x), x) - y(x)**2 + y(x), y(x), ... 1/(x*(z + 1/x))) x*(-1/(x**2*(z + 1/x)) + 1/(x**3*(z + 1/x)**2)) + 1/(x*(z + 1/x)) ...- 1/(x**2*(z + 1/x)**2) """ reps= {func: new} for d in eq.atoms(Derivative): if d.expr == func: reps[d] = new.diff(*d.variable_count) else: reps[d] = d.xreplace({func: new}).doit(deep=False) return eq.xreplace(reps) def checkodesol(ode, sol, func=None, order='auto', solve_for_func=True): r""" Substitutes ``sol`` into ``ode`` and checks that the result is ``0``. This works when ``func`` is one function, like `f(x)` or a list of functions like `[f(x), g(x)]` when `ode` is a system of ODEs. ``sol`` can be a single solution or a list of solutions. Each solution may be an :py:class:`~sympy.core.relational.Equality` that the solution satisfies, e.g. ``Eq(f(x), C1), Eq(f(x) + C1, 0)``; or simply an :py:class:`~sympy.core.expr.Expr`, e.g. ``f(x) - C1``. In most cases it will not be necessary to explicitly identify the function, but if the function cannot be inferred from the original equation it can be supplied through the ``func`` argument. If a sequence of solutions is passed, the same sort of container will be used to return the result for each solution. It tries the following methods, in order, until it finds zero equivalence: 1. Substitute the solution for `f` in the original equation. This only works if ``ode`` is solved for `f`. It will attempt to solve it first unless ``solve_for_func == False``. 2. Take `n` derivatives of the solution, where `n` is the order of ``ode``, and check to see if that is equal to the solution. This only works on exact ODEs. 3. Take the 1st, 2nd, ..., `n`\th derivatives of the solution, each time solving for the derivative of `f` of that order (this will always be possible because `f` is a linear operator). Then back substitute each derivative into ``ode`` in reverse order. This function returns a tuple. The first item in the tuple is ``True`` if the substitution results in ``0``, and ``False`` otherwise. The second item in the tuple is what the substitution results in. It should always be ``0`` if the first item is ``True``. Sometimes this function will return ``False`` even when an expression is identically equal to ``0``. This happens when :py:meth:`~sympy.simplify.simplify.simplify` does not reduce the expression to ``0``. If an expression returned by this function vanishes identically, then ``sol`` really is a solution to the ``ode``. If this function seems to hang, it is probably because of a hard simplification. To use this function to test, test the first item of the tuple. Examples ======== >>> from sympy import (Eq, Function, checkodesol, symbols, ... Derivative, exp) >>> x, C1, C2 = symbols('x,C1,C2') >>> f, g = symbols('f g', cls=Function) >>> checkodesol(f(x).diff(x), Eq(f(x), C1)) (True, 0) >>> assert checkodesol(f(x).diff(x), C1)[0] >>> assert not checkodesol(f(x).diff(x), x)[0] >>> checkodesol(f(x).diff(x, 2), x**2) (False, 2) >>> eqs = [Eq(Derivative(f(x), x), f(x)), Eq(Derivative(g(x), x), g(x))] >>> sol = [Eq(f(x), C1*exp(x)), Eq(g(x), C2*exp(x))] >>> checkodesol(eqs, sol) (True, [0, 0]) """ if iterable(ode): return checksysodesol(ode, sol, func=func) if not isinstance(ode, Equality): ode = Eq(ode, 0) if func is None: try: _, func = _preprocess(ode.lhs) except ValueError: funcs = [s.atoms(AppliedUndef) for s in ( sol if is_sequence(sol, set) else [sol])] funcs = set().union(*funcs) if len(funcs) != 1: raise ValueError( 'must pass func arg to checkodesol for this case.') func = funcs.pop() if not isinstance(func, AppliedUndef) or len(func.args) != 1: raise ValueError( "func must be a function of one variable, not %s" % func) if is_sequence(sol, set): return type(sol)([checkodesol(ode, i, order=order, solve_for_func=solve_for_func) for i in sol]) if not isinstance(sol, Equality): sol = Eq(func, sol) elif sol.rhs == func: sol = sol.reversed if order == 'auto': order = ode_order(ode, func) solved = sol.lhs == func and not sol.rhs.has(func) if solve_for_func and not solved: rhs = solve(sol, func) if rhs: eqs = [Eq(func, t) for t in rhs] if len(rhs) == 1: eqs = eqs[0] return checkodesol(ode, eqs, order=order, solve_for_func=False) x = func.args[0] # Handle series solutions here if sol.has(Order): assert sol.lhs == func Oterm = sol.rhs.getO() solrhs = sol.rhs.removeO() Oexpr = Oterm.expr assert isinstance(Oexpr, Pow) sorder = Oexpr.exp assert Oterm == Order(x**sorder) odesubs = (ode.lhs-ode.rhs).subs(func, solrhs).doit().expand() neworder = Order(x**(sorder - order)) odesubs = odesubs + neworder assert odesubs.getO() == neworder residual = odesubs.removeO() return (residual == 0, residual) s = True testnum = 0 while s: if testnum == 0: # First pass, try substituting a solved solution directly into the # ODE. This has the highest chance of succeeding. ode_diff = ode.lhs - ode.rhs if sol.lhs == func: s = sub_func_doit(ode_diff, func, sol.rhs) s = besselsimp(s) else: testnum += 1 continue ss = simplify(s.rewrite(exp)) if ss: # with the new numer_denom in power.py, if we do a simple # expansion then testnum == 0 verifies all solutions. s = ss.expand(force=True) else: s = 0 testnum += 1 elif testnum == 1: # Second pass. If we cannot substitute f, try seeing if the nth # derivative is equal, this will only work for odes that are exact, # by definition. s = simplify( trigsimp(diff(sol.lhs, x, order) - diff(sol.rhs, x, order)) - trigsimp(ode.lhs) + trigsimp(ode.rhs)) # s2 = simplify( # diff(sol.lhs, x, order) - diff(sol.rhs, x, order) - \ # ode.lhs + ode.rhs) testnum += 1 elif testnum == 2: # Third pass. Try solving for df/dx and substituting that into the # ODE. Thanks to Chris Smith for suggesting this method. Many of # the comments below are his, too. # The method: # - Take each of 1..n derivatives of the solution. # - Solve each nth derivative for d^(n)f/dx^(n) # (the differential of that order) # - Back substitute into the ODE in decreasing order # (i.e., n, n-1, ...) # - Check the result for zero equivalence if sol.lhs == func and not sol.rhs.has(func): diffsols = {0: sol.rhs} elif sol.rhs == func and not sol.lhs.has(func): diffsols = {0: sol.lhs} else: diffsols = {} sol = sol.lhs - sol.rhs for i in range(1, order + 1): # Differentiation is a linear operator, so there should always # be 1 solution. Nonetheless, we test just to make sure. # We only need to solve once. After that, we automatically # have the solution to the differential in the order we want. if i == 1: ds = sol.diff(x) try: sdf = solve(ds, func.diff(x, i)) if not sdf: raise NotImplementedError except NotImplementedError: testnum += 1 break else: diffsols[i] = sdf[0] else: # This is what the solution says df/dx should be. diffsols[i] = diffsols[i - 1].diff(x) # Make sure the above didn't fail. if testnum > 2: continue else: # Substitute it into ODE to check for self consistency. lhs, rhs = ode.lhs, ode.rhs for i in range(order, -1, -1): if i == 0 and 0 not in diffsols: # We can only substitute f(x) if the solution was # solved for f(x). break lhs = sub_func_doit(lhs, func.diff(x, i), diffsols[i]) rhs = sub_func_doit(rhs, func.diff(x, i), diffsols[i]) ode_or_bool = Eq(lhs, rhs) ode_or_bool = simplify(ode_or_bool) if isinstance(ode_or_bool, (bool, BooleanAtom)): if ode_or_bool: lhs = rhs = S.Zero else: lhs = ode_or_bool.lhs rhs = ode_or_bool.rhs # No sense in overworking simplify -- just prove that the # numerator goes to zero num = trigsimp((lhs - rhs).as_numer_denom()[0]) # since solutions are obtained using force=True we test # using the same level of assumptions ## replace function with dummy so assumptions will work _func = Dummy('func') num = num.subs(func, _func) ## posify the expression num, reps = posify(num) s = simplify(num).xreplace(reps).xreplace({_func: func}) testnum += 1 else: break if not s: return (True, s) elif s is True: # The code above never was able to change s raise NotImplementedError("Unable to test if " + str(sol) + " is a solution to " + str(ode) + ".") else: return (False, s) def checksysodesol(eqs, sols, func=None): r""" Substitutes corresponding ``sols`` for each functions into each ``eqs`` and checks that the result of substitutions for each equation is ``0``. The equations and solutions passed can be any iterable. This only works when each ``sols`` have one function only, like `x(t)` or `y(t)`. For each function, ``sols`` can have a single solution or a list of solutions. In most cases it will not be necessary to explicitly identify the function, but if the function cannot be inferred from the original equation it can be supplied through the ``func`` argument. When a sequence of equations is passed, the same sequence is used to return the result for each equation with each function substituted with corresponding solutions. It tries the following method to find zero equivalence for each equation: Substitute the solutions for functions, like `x(t)` and `y(t)` into the original equations containing those functions. This function returns a tuple. The first item in the tuple is ``True`` if the substitution results for each equation is ``0``, and ``False`` otherwise. The second item in the tuple is what the substitution results in. Each element of the ``list`` should always be ``0`` corresponding to each equation if the first item is ``True``. Note that sometimes this function may return ``False``, but with an expression that is identically equal to ``0``, instead of returning ``True``. This is because :py:meth:`~sympy.simplify.simplify.simplify` cannot reduce the expression to ``0``. If an expression returned by each function vanishes identically, then ``sols`` really is a solution to ``eqs``. If this function seems to hang, it is probably because of a difficult simplification. Examples ======== >>> from sympy import Eq, diff, symbols, sin, cos, exp, sqrt, S, Function >>> from sympy.solvers.ode.subscheck import checksysodesol >>> C1, C2 = symbols('C1:3') >>> t = symbols('t') >>> x, y = symbols('x, y', cls=Function) >>> eq = (Eq(diff(x(t),t), x(t) + y(t) + 17), Eq(diff(y(t),t), -2*x(t) + y(t) + 12)) >>> sol = [Eq(x(t), (C1*sin(sqrt(2)*t) + C2*cos(sqrt(2)*t))*exp(t) - S(5)/3), ... Eq(y(t), (sqrt(2)*C1*cos(sqrt(2)*t) - sqrt(2)*C2*sin(sqrt(2)*t))*exp(t) - S(46)/3)] >>> checksysodesol(eq, sol) (True, [0, 0]) >>> eq = (Eq(diff(x(t),t),x(t)*y(t)**4), Eq(diff(y(t),t),y(t)**3)) >>> sol = [Eq(x(t), C1*exp(-1/(4*(C2 + t)))), Eq(y(t), -sqrt(2)*sqrt(-1/(C2 + t))/2), ... Eq(x(t), C1*exp(-1/(4*(C2 + t)))), Eq(y(t), sqrt(2)*sqrt(-1/(C2 + t))/2)] >>> checksysodesol(eq, sol) (True, [0, 0]) """ def _sympify(eq): return list(map(sympify, eq if iterable(eq) else [eq])) eqs = _sympify(eqs) for i in range(len(eqs)): if isinstance(eqs[i], Equality): eqs[i] = eqs[i].lhs - eqs[i].rhs if func is None: funcs = [] for eq in eqs: derivs = eq.atoms(Derivative) func = set().union(*[d.atoms(AppliedUndef) for d in derivs]) for func_ in func: funcs.append(func_) funcs = list(set(funcs)) if not all(isinstance(func, AppliedUndef) and len(func.args) == 1 for func in funcs)\ and len({func.args for func in funcs})!=1: raise ValueError("func must be a function of one variable, not %s" % func) for sol in sols: if len(sol.atoms(AppliedUndef)) != 1: raise ValueError("solutions should have one function only") if len(funcs) != len({sol.lhs for sol in sols}): raise ValueError("number of solutions provided does not match the number of equations") dictsol = dict() for sol in sols: func = list(sol.atoms(AppliedUndef))[0] if sol.rhs == func: sol = sol.reversed solved = sol.lhs == func and not sol.rhs.has(func) if not solved: rhs = solve(sol, func) if not rhs: raise NotImplementedError else: rhs = sol.rhs dictsol[func] = rhs checkeq = [] for eq in eqs: for func in funcs: eq = sub_func_doit(eq, func, dictsol[func]) ss = simplify(eq) if ss != 0: eq = ss.expand(force=True) if eq != 0: eq = sqrtdenest(eq).simplify() else: eq = 0 checkeq.append(eq) if len(set(checkeq)) == 1 and list(set(checkeq))[0] == 0: return (True, checkeq) else: return (False, checkeq) sympy-sympy-1.9/sympy/solvers/ode/systems.py000066400000000000000000002141721412543434000214400ustar00rootroot00000000000000from sympy.core import Add, Mul, S from sympy.core.containers import Tuple from sympy.core.compatibility import iterable from sympy.core.exprtools import factor_terms from sympy.core.numbers import I from sympy.core.relational import Eq, Equality from sympy.core.symbol import Dummy, Symbol from sympy.core.function import (expand_mul, expand, Derivative, AppliedUndef, Function, Subs) from sympy.functions import (exp, im, cos, sin, re, Piecewise, piecewise_fold, sqrt, log) from sympy.functions.combinatorial.factorials import factorial from sympy.matrices import zeros, Matrix, NonSquareMatrixError, MatrixBase, eye from sympy.polys import Poly, together from sympy.simplify import collect, radsimp, signsimp from sympy.simplify.powsimp import powdenest, powsimp from sympy.simplify.ratsimp import ratsimp from sympy.simplify.simplify import simplify from sympy.sets.sets import FiniteSet from sympy.solvers.deutils import ode_order from sympy.solvers.solveset import NonlinearError, solveset from sympy.utilities import default_sort_key from sympy.utilities.iterables import ordered from sympy.utilities.misc import filldedent from sympy.integrals.integrals import Integral, integrate def _get_func_order(eqs, funcs): return {func: max(ode_order(eq, func) for eq in eqs) for func in funcs} class ODEOrderError(ValueError): """Raised by linear_ode_to_matrix if the system has the wrong order""" pass class ODENonlinearError(NonlinearError): """Raised by linear_ode_to_matrix if the system is nonlinear""" pass def _simpsol(soleq): lhs = soleq.lhs sol = soleq.rhs sol = powsimp(sol) gens = list(sol.atoms(exp)) p = Poly(sol, *gens, expand=False) gens = [factor_terms(g) for g in gens] if not gens: gens = p.gens syms = [Symbol('C1'), Symbol('C2')] terms = [] for coeff, monom in zip(p.coeffs(), p.monoms()): coeff = piecewise_fold(coeff) if type(coeff) is Piecewise: coeff = Piecewise(*((ratsimp(coef).collect(syms), cond) for coef, cond in coeff.args)) else: coeff = ratsimp(coeff).collect(syms) monom = Mul(*(g ** i for g, i in zip(gens, monom))) terms.append(coeff * monom) return Eq(lhs, Add(*terms)) def _solsimp(e, t): no_t, has_t = powsimp(expand_mul(e)).as_independent(t) no_t = ratsimp(no_t) has_t = has_t.replace(exp, lambda a: exp(factor_terms(a))) return no_t + has_t def simpsol(sol, wrt1, wrt2, doit=True): """Simplify solutions from dsolve_system.""" # The parameter sol is the solution as returned by dsolve (list of Eq). # # The parameters wrt1 and wrt2 are lists of symbols to be collected for # with those in wrt1 being collected for first. This allows for collecting # on any factors involving the independent variable before collecting on # the integration constants or vice versa using e.g.: # # sol = simpsol(sol, [t], [C1, C2]) # t first, constants after # sol = simpsol(sol, [C1, C2], [t]) # constants first, t after # # If doit=True (default) then simpsol will begin by evaluating any # unevaluated integrals. Since many integrals will appear multiple times # in the solutions this is done intelligently by computing each integral # only once. # # The strategy is to first perform simple cancellation with factor_terms # and then multiply out all brackets with expand_mul. This gives an Add # with many terms. # # We split each term into two multiplicative factors dep and coeff where # all factors that involve wrt1 are in dep and any constant factors are in # coeff e.g. # sqrt(2)*C1*exp(t) -> ( exp(t) , sqrt(2)*C1 ) # # The dep factors are simplified using powsimp to combine expanded # exponential factors e.g. # exp(a*t)*exp(b*t) -> exp(t*(a+b)) # # We then collect coefficients for all terms having the same (simplified) # dep. The coefficients are then simplified using together and ratsimp and # lastly by recursively applying the same transformation to the # coefficients to collect on wrt2. # # Finally the result is recombined into an Add and signsimp is used to # normalise any minus signs. def simprhs(rhs, rep, wrt1, wrt2): """Simplify the rhs of an ODE solution""" if rep: rhs = rhs.subs(rep) rhs = factor_terms(rhs) rhs = simp_coeff_dep(rhs, wrt1, wrt2) rhs = signsimp(rhs) return rhs def simp_coeff_dep(expr, wrt1, wrt2=None): """Split rhs into terms, split terms into dep and coeff and collect on dep""" add_dep_terms = lambda e: e.is_Add and e.has(*wrt1) expandable = lambda e: e.is_Mul and any(map(add_dep_terms, e.args)) expand_func = lambda e: expand_mul(e, deep=False) expand_mul_mod = lambda e: e.replace(expandable, expand_func) terms = Add.make_args(expand_mul_mod(expr)) dc = {} for term in terms: coeff, dep = term.as_independent(*wrt1, as_Add=False) # Collect together the coefficients for terms that have the same # dependence on wrt1 (after dep is normalised using simpdep). dep = simpdep(dep, wrt1) # See if the dependence on t cancels out... if dep is not S.One: dep2 = factor_terms(dep) if not dep2.has(*wrt1): coeff *= dep2 dep = S.One if dep not in dc: dc[dep] = coeff else: dc[dep] += coeff # Apply the method recursively to the coefficients but this time # collecting on wrt2 rather than wrt2. termpairs = ((simpcoeff(c, wrt2), d) for d, c in dc.items()) if wrt2 is not None: termpairs = ((simp_coeff_dep(c, wrt2), d) for c, d in termpairs) return Add(*(c * d for c, d in termpairs)) def simpdep(term, wrt1): """Normalise factors involving t with powsimp and recombine exp""" def canonicalise(a): # Using factor_terms here isn't quite right because it leads to things # like exp(t*(1+t)) that we don't want. We do want to cancel factors # and pull out a common denominator but ideally the numerator would be # expressed as a standard form polynomial in t so we expand_mul # and collect afterwards. a = factor_terms(a) num, den = a.as_numer_denom() num = expand_mul(num) num = collect(num, wrt1) return num / den term = powsimp(term) rep = {e: exp(canonicalise(e.args[0])) for e in term.atoms(exp)} term = term.subs(rep) return term def simpcoeff(coeff, wrt2): """Bring to a common fraction and cancel with ratsimp""" coeff = together(coeff) if coeff.is_polynomial(): # Calling ratsimp can be expensive. The main reason is to simplify # sums of terms with irrational denominators so we limit ourselves # to the case where the expression is polynomial in any symbols. # Maybe there's a better approach... coeff = ratsimp(radsimp(coeff)) # collect on secondary variables first and any remaining symbols after if wrt2 is not None: syms = list(wrt2) + list(ordered(coeff.free_symbols - set(wrt2))) else: syms = list(ordered(coeff.free_symbols)) coeff = collect(coeff, syms) coeff = together(coeff) return coeff # There are often repeated integrals. Collect unique integrals and # evaluate each once and then substitute into the final result to replace # all occurrences in each of the solution equations. if doit: integrals = set().union(*(s.atoms(Integral) for s in sol)) rep = {i: factor_terms(i).doit() for i in integrals} else: rep = {} sol = [Eq(s.lhs, simprhs(s.rhs, rep, wrt1, wrt2)) for s in sol] return sol def linodesolve_type(A, t, b=None): r""" Helper function that determines the type of the system of ODEs for solving with :obj:`sympy.solvers.ode.systems.linodesolve()` Explanation =========== This function takes in the coefficient matrix and/or the non-homogeneous term and returns the type of the equation that can be solved by :obj:`sympy.solvers.ode.systems.linodesolve()`. If the system is constant coefficient homogeneous, then "type1" is returned If the system is constant coefficient non-homogeneous, then "type2" is returned If the system is non-constant coefficient homogeneous, then "type3" is returned If the system is non-constant coefficient non-homogeneous, then "type4" is returned If the system has a non-constant coefficient matrix which can be factorized into constant coefficient matrix, then "type5" or "type6" is returned for when the system is homogeneous or non-homogeneous respectively. Note that, if the system of ODEs is of "type3" or "type4", then along with the type, the commutative antiderivative of the coefficient matrix is also returned. If the system cannot be solved by :obj:`sympy.solvers.ode.systems.linodesolve()`, then NotImplementedError is raised. Parameters ========== A : Matrix Coefficient matrix of the system of ODEs b : Matrix or None Non-homogeneous term of the system. The default value is None. If this argument is None, then the system is assumed to be homogeneous. Examples ======== >>> from sympy import symbols, Matrix >>> from sympy.solvers.ode.systems import linodesolve_type >>> t = symbols("t") >>> A = Matrix([[1, 1], [2, 3]]) >>> b = Matrix([t, 1]) >>> linodesolve_type(A, t) {'antiderivative': None, 'type_of_equation': 'type1'} >>> linodesolve_type(A, t, b=b) {'antiderivative': None, 'type_of_equation': 'type2'} >>> A_t = Matrix([[1, t], [-t, 1]]) >>> linodesolve_type(A_t, t) {'antiderivative': Matrix([ [ t, t**2/2], [-t**2/2, t]]), 'type_of_equation': 'type3'} >>> linodesolve_type(A_t, t, b=b) {'antiderivative': Matrix([ [ t, t**2/2], [-t**2/2, t]]), 'type_of_equation': 'type4'} >>> A_non_commutative = Matrix([[1, t], [t, -1]]) >>> linodesolve_type(A_non_commutative, t) Traceback (most recent call last): ... NotImplementedError: The system doesn't have a commutative antiderivative, it can't be solved by linodesolve. Returns ======= Dict Raises ====== NotImplementedError When the coefficient matrix doesn't have a commutative antiderivative See Also ======== linodesolve: Function for which linodesolve_type gets the information """ match = {} is_non_constant = not _matrix_is_constant(A, t) is_non_homogeneous = not (b is None or b.is_zero_matrix) type = "type{}".format(int("{}{}".format(int(is_non_constant), int(is_non_homogeneous)), 2) + 1) B = None match.update({"type_of_equation": type, "antiderivative": B}) if is_non_constant: B, is_commuting = _is_commutative_anti_derivative(A, t) if not is_commuting: raise NotImplementedError(filldedent(''' The system doesn't have a commutative antiderivative, it can't be solved by linodesolve. ''')) match['antiderivative'] = B match.update(_first_order_type5_6_subs(A, t, b=b)) return match def _first_order_type5_6_subs(A, t, b=None): match = {} factor_terms = _factor_matrix(A, t) is_homogeneous = b is None or b.is_zero_matrix if factor_terms is not None: t_ = Symbol("{}_".format(t)) F_t = integrate(factor_terms[0], t) inverse = solveset(Eq(t_, F_t), t) # Note: A simple way to check if a function is invertible # or not. if isinstance(inverse, FiniteSet) and not inverse.has(Piecewise)\ and len(inverse) == 1: A = factor_terms[1] if not is_homogeneous: b = b / factor_terms[0] b = b.subs(t, list(inverse)[0]) type = "type{}".format(5 + (not is_homogeneous)) match.update({'func_coeff': A, 'tau': F_t, 't_': t_, 'type_of_equation': type, 'rhs': b}) return match def linear_ode_to_matrix(eqs, funcs, t, order): r""" Convert a linear system of ODEs to matrix form Explanation =========== Express a system of linear ordinary differential equations as a single matrix differential equation [1]. For example the system $x' = x + y + 1$ and $y' = x - y$ can be represented as .. math:: A_1 X' = A0 X + b where $A_1$ and $A_0$ are $2 \times 2$ matrices and $b$, $X$ and $X'$ are $2 \times 1$ matrices with $X = [x, y]^T$. Higher-order systems are represented with additional matrices e.g. a second-order system would look like .. math:: A_2 X'' = A_1 X' + A_0 X + b Examples ======== >>> from sympy import (Function, Symbol, Matrix, Eq) >>> from sympy.solvers.ode.systems import linear_ode_to_matrix >>> t = Symbol('t') >>> x = Function('x') >>> y = Function('y') We can create a system of linear ODEs like >>> eqs = [ ... Eq(x(t).diff(t), x(t) + y(t) + 1), ... Eq(y(t).diff(t), x(t) - y(t)), ... ] >>> funcs = [x(t), y(t)] >>> order = 1 # 1st order system Now ``linear_ode_to_matrix`` can represent this as a matrix differential equation. >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, t, order) >>> A1 Matrix([ [1, 0], [0, 1]]) >>> A0 Matrix([ [1, 1], [1, -1]]) >>> b Matrix([ [1], [0]]) The original equations can be recovered from these matrices: >>> eqs_mat = Matrix([eq.lhs - eq.rhs for eq in eqs]) >>> X = Matrix(funcs) >>> A1 * X.diff(t) - A0 * X - b == eqs_mat True If the system of equations has a maximum order greater than the order of the system specified, a ODEOrderError exception is raised. >>> eqs = [Eq(x(t).diff(t, 2), x(t).diff(t) + x(t)), Eq(y(t).diff(t), y(t) + x(t))] >>> linear_ode_to_matrix(eqs, funcs, t, 1) Traceback (most recent call last): ... ODEOrderError: Cannot represent system in 1-order form If the system of equations is nonlinear, then ODENonlinearError is raised. >>> eqs = [Eq(x(t).diff(t), x(t) + y(t)), Eq(y(t).diff(t), y(t)**2 + x(t))] >>> linear_ode_to_matrix(eqs, funcs, t, 1) Traceback (most recent call last): ... ODENonlinearError: The system of ODEs is nonlinear. Parameters ========== eqs : list of sympy expressions or equalities The equations as expressions (assumed equal to zero). funcs : list of applied functions The dependent variables of the system of ODEs. t : symbol The independent variable. order : int The order of the system of ODEs. Returns ======= The tuple ``(As, b)`` where ``As`` is a tuple of matrices and ``b`` is the the matrix representing the rhs of the matrix equation. Raises ====== ODEOrderError When the system of ODEs have an order greater than what was specified ODENonlinearError When the system of ODEs is nonlinear See Also ======== linear_eq_to_matrix: for systems of linear algebraic equations. References ========== .. [1] https://en.wikipedia.org/wiki/Matrix_differential_equation """ from sympy.solvers.solveset import linear_eq_to_matrix if any(ode_order(eq, func) > order for eq in eqs for func in funcs): msg = "Cannot represent system in {}-order form" raise ODEOrderError(msg.format(order)) As = [] for o in range(order, -1, -1): # Work from the highest derivative down funcs_deriv = [func.diff(t, o) for func in funcs] # linear_eq_to_matrix expects a proper symbol so substitute e.g. # Derivative(x(t), t) for a Dummy. rep = {func_deriv: Dummy() for func_deriv in funcs_deriv} eqs = [eq.subs(rep) for eq in eqs] syms = [rep[func_deriv] for func_deriv in funcs_deriv] # Ai is the matrix for X(t).diff(t, o) # eqs is minus the remainder of the equations. try: Ai, b = linear_eq_to_matrix(eqs, syms) except NonlinearError: raise ODENonlinearError("The system of ODEs is nonlinear.") Ai = Ai.applyfunc(expand_mul) As.append(Ai if o == order else -Ai) if o: eqs = [-eq for eq in b] else: rhs = b return As, rhs def matrix_exp(A, t): r""" Matrix exponential $\exp(A*t)$ for the matrix ``A`` and scalar ``t``. Explanation =========== This functions returns the $\exp(A*t)$ by doing a simple matrix multiplication: .. math:: \exp(A*t) = P * expJ * P^{-1} where $expJ$ is $\exp(J*t)$. $J$ is the Jordan normal form of $A$ and $P$ is matrix such that: .. math:: A = P * J * P^{-1} The matrix exponential $\exp(A*t)$ appears in the solution of linear differential equations. For example if $x$ is a vector and $A$ is a matrix then the initial value problem .. math:: \frac{dx(t)}{dt} = A \times x(t), x(0) = x0 has the unique solution .. math:: x(t) = \exp(A t) x0 Examples ======== >>> from sympy import Symbol, Matrix, pprint >>> from sympy.solvers.ode.systems import matrix_exp >>> t = Symbol('t') We will consider a 2x2 matrix for comupting the exponential >>> A = Matrix([[2, -5], [2, -4]]) >>> pprint(A) [2 -5] [ ] [2 -4] Now, exp(A*t) is given as follows: >>> pprint(matrix_exp(A, t)) [ -t -t -t ] [3*e *sin(t) + e *cos(t) -5*e *sin(t) ] [ ] [ -t -t -t ] [ 2*e *sin(t) - 3*e *sin(t) + e *cos(t)] Parameters ========== A : Matrix The matrix $A$ in the expression $\exp(A*t)$ t : Symbol The independent variable See Also ======== matrix_exp_jordan_form: For exponential of Jordan normal form References ========== .. [1] https://en.wikipedia.org/wiki/Jordan_normal_form .. [2] https://en.wikipedia.org/wiki/Matrix_exponential """ P, expJ = matrix_exp_jordan_form(A, t) return P * expJ * P.inv() def matrix_exp_jordan_form(A, t): r""" Matrix exponential $\exp(A*t)$ for the matrix *A* and scalar *t*. Explanation =========== Returns the Jordan form of the $\exp(A*t)$ along with the matrix $P$ such that: .. math:: \exp(A*t) = P * expJ * P^{-1} Examples ======== >>> from sympy import Matrix, Symbol >>> from sympy.solvers.ode.systems import matrix_exp, matrix_exp_jordan_form >>> t = Symbol('t') We will consider a 2x2 defective matrix. This shows that our method works even for defective matrices. >>> A = Matrix([[1, 1], [0, 1]]) It can be observed that this function gives us the Jordan normal form and the required invertible matrix P. >>> P, expJ = matrix_exp_jordan_form(A, t) Here, it is shown that P and expJ returned by this function is correct as they satisfy the formula: P * expJ * P_inverse = exp(A*t). >>> P * expJ * P.inv() == matrix_exp(A, t) True Parameters ========== A : Matrix The matrix $A$ in the expression $\exp(A*t)$ t : Symbol The independent variable References ========== .. [1] https://en.wikipedia.org/wiki/Defective_matrix .. [2] https://en.wikipedia.org/wiki/Jordan_matrix .. [3] https://en.wikipedia.org/wiki/Jordan_normal_form """ N, M = A.shape if N != M: raise ValueError('Needed square matrix but got shape (%s, %s)' % (N, M)) elif A.has(t): raise ValueError('Matrix A should not depend on t') def jordan_chains(A): '''Chains from Jordan normal form analogous to M.eigenvects(). Returns a dict with eignevalues as keys like: {e1: [[v111,v112,...], [v121, v122,...]], e2:...} where vijk is the kth vector in the jth chain for eigenvalue i. ''' P, blocks = A.jordan_cells() basis = [P[:,i] for i in range(P.shape[1])] n = 0 chains = {} for b in blocks: eigval = b[0, 0] size = b.shape[0] if eigval not in chains: chains[eigval] = [] chains[eigval].append(basis[n:n+size]) n += size return chains eigenchains = jordan_chains(A) # Needed for consistency across Python versions eigenchains_iter = sorted(eigenchains.items(), key=default_sort_key) isreal = not A.has(I) blocks = [] vectors = [] seen_conjugate = set() for e, chains in eigenchains_iter: for chain in chains: n = len(chain) if isreal and e != e.conjugate() and e.conjugate() in eigenchains: if e in seen_conjugate: continue seen_conjugate.add(e.conjugate()) exprt = exp(re(e) * t) imrt = im(e) * t imblock = Matrix([[cos(imrt), sin(imrt)], [-sin(imrt), cos(imrt)]]) expJblock2 = Matrix(n, n, lambda i,j: imblock * t**(j-i) / factorial(j-i) if j >= i else zeros(2, 2)) expJblock = Matrix(2*n, 2*n, lambda i,j: expJblock2[i//2,j//2][i%2,j%2]) blocks.append(exprt * expJblock) for i in range(n): vectors.append(re(chain[i])) vectors.append(im(chain[i])) else: vectors.extend(chain) fun = lambda i,j: t**(j-i)/factorial(j-i) if j >= i else 0 expJblock = Matrix(n, n, fun) blocks.append(exp(e * t) * expJblock) expJ = Matrix.diag(*blocks) P = Matrix(N, N, lambda i,j: vectors[j][i]) return P, expJ # Note: To add a docstring example with tau def linodesolve(A, t, b=None, B=None, type="auto", doit=False, tau=None): r""" System of n equations linear first-order differential equations Explanation =========== This solver solves the system of ODEs of the follwing form: .. math:: X'(t) = A(t) X(t) + b(t) Here, $A(t)$ is the coefficient matrix, $X(t)$ is the vector of n independent variables, $b(t)$ is the non-homogeneous term and $X'(t)$ is the derivative of $X(t)$ Depending on the properties of $A(t)$ and $b(t)$, this solver evaluates the solution differently. When $A(t)$ is constant coefficient matrix and $b(t)$ is zero vector i.e. system is homogeneous, the system is "type1". The solution is: .. math:: X(t) = \exp(A t) C Here, $C$ is a vector of constants and $A$ is the constant coefficient matrix. When $A(t)$ is constant coefficient matrix and $b(t)$ is non-zero i.e. system is non-homogeneous, the system is "type2". The solution is: .. math:: X(t) = e^{A t} ( \int e^{- A t} b \,dt + C) When $A(t)$ is coefficient matrix such that its commutative with its antiderivative $B(t)$ and $b(t)$ is a zero vector i.e. system is homogeneous, the system is "type3". The solution is: .. math:: X(t) = \exp(B(t)) C When $A(t)$ is commutative with its antiderivative $B(t)$ and $b(t)$ is non-zero i.e. system is non-homogeneous, the system is "type4". The solution is: .. math:: X(t) = e^{B(t)} ( \int e^{-B(t)} b(t) \,dt + C) When $A(t)$ is a coefficient matrix such that it can be factorized into a scalar and a constant coefficient matrix: .. math:: A(t) = f(t) * A Where $f(t)$ is a scalar expression in the independent variable $t$ and $A$ is a constant matrix, then we can do the following substitutions: .. math:: tau = \int f(t) dt, X(t) = Y(tau), b(t) = b(f^{-1}(tau)) Here, the substitution for the non-homogeneous term is done only when its non-zero. Using these substitutions, our original system becomes: .. math:: Y'(tau) = A * Y(tau) + b(tau)/f(tau) The above system can be easily solved using the solution for "type1" or "type2" depending on the homogeneity of the system. After we get the solution for $Y(tau)$, we substitute the solution for $tau$ as $t$ to get back $X(t)$ .. math:: X(t) = Y(tau) Systems of "type5" and "type6" have a commutative antiderivative but we use this solution because its faster to compute. The final solution is the general solution for all the four equations since a constant coefficient matrix is always commutative with its antidervative. An additional feature of this function is, if someone wants to substitute for value of the independent variable, they can pass the substitution `tau` and the solution will have the independent variable substituted with the passed expression(`tau`). Parameters ========== A : Matrix Coefficient matrix of the system of linear first order ODEs. t : Symbol Independent variable in the system of ODEs. b : Matrix or None Non-homogeneous term in the system of ODEs. If None is passed, a homogeneous system of ODEs is assumed. B : Matrix or None Antiderivative of the coefficient matrix. If the antiderivative is not passed and the solution requires the term, then the solver would compute it internally. type : String Type of the system of ODEs passed. Depending on the type, the solution is evaluated. The type values allowed and the corresponding system it solves are: "type1" for constant coefficient homogeneous "type2" for constant coefficient non-homogeneous, "type3" for non-constant coefficient homogeneous, "type4" for non-constant coefficient non-homogeneous, "type5" and "type6" for non-constant coefficient homogeneous and non-homogeneous systems respectively where the coefficient matrix can be factorized to a constant coefficient matrix. The default value is "auto" which will let the solver decide the correct type of the system passed. doit : Boolean Evaluate the solution if True, default value is False tau: Expression Used to substitute for the value of `t` after we get the solution of the system. Examples ======== To solve the system of ODEs using this function directly, several things must be done in the right order. Wrong inputs to the function will lead to incorrect results. >>> from sympy import symbols, Function, Eq >>> from sympy.solvers.ode.systems import canonical_odes, linear_ode_to_matrix, linodesolve, linodesolve_type >>> from sympy.solvers.ode.subscheck import checkodesol >>> f, g = symbols("f, g", cls=Function) >>> x, a = symbols("x, a") >>> funcs = [f(x), g(x)] >>> eqs = [Eq(f(x).diff(x) - f(x), a*g(x) + 1), Eq(g(x).diff(x) + g(x), a*f(x))] Here, it is important to note that before we derive the coefficient matrix, it is important to get the system of ODEs into the desired form. For that we will use :obj:`sympy.solvers.ode.systems.canonical_odes()`. >>> eqs = canonical_odes(eqs, funcs, x) >>> eqs [[Eq(Derivative(f(x), x), a*g(x) + f(x) + 1), Eq(Derivative(g(x), x), a*f(x) - g(x))]] Now, we will use :obj:`sympy.solvers.ode.systems.linear_ode_to_matrix()` to get the coefficient matrix and the non-homogeneous term if it is there. >>> eqs = eqs[0] >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1) >>> A = A0 We have the coefficient matrices and the non-homogeneous term ready. Now, we can use :obj:`sympy.solvers.ode.systems.linodesolve_type()` to get the information for the system of ODEs to finally pass it to the solver. >>> system_info = linodesolve_type(A, x, b=b) >>> sol_vector = linodesolve(A, x, b=b, B=system_info['antiderivative'], type=system_info['type_of_equation']) Now, we can prove if the solution is correct or not by using :obj:`sympy.solvers.ode.checkodesol()` >>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] >>> checkodesol(eqs, sol) (True, [0, 0]) We can also use the doit method to evaluate the solutions passed by the function. >>> sol_vector_evaluated = linodesolve(A, x, b=b, type="type2", doit=True) Now, we will look at a system of ODEs which is non-constant. >>> eqs = [Eq(f(x).diff(x), f(x) + x*g(x)), Eq(g(x).diff(x), -x*f(x) + g(x))] The system defined above is already in the desired form, so we don't have to convert it. >>> (A1, A0), b = linear_ode_to_matrix(eqs, funcs, x, 1) >>> A = A0 A user can also pass the commutative antiderivative required for type3 and type4 system of ODEs. Passing an incorrect one will lead to incorrect results. If the coefficient matrix is not commutative with its antiderivative, then :obj:`sympy.solvers.ode.systems.linodesolve_type()` raises a NotImplementedError. If it does have a commutative antiderivative, then the function just returns the information about the system. >>> system_info = linodesolve_type(A, x, b=b) Now, we can pass the antiderivative as an argument to get the solution. If the system information is not passed, then the solver will compute the required arguments internally. >>> sol_vector = linodesolve(A, x, b=b) Once again, we can verify the solution obtained. >>> sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] >>> checkodesol(eqs, sol) (True, [0, 0]) Returns ======= List Raises ====== ValueError This error is raised when the coefficient matrix, non-homogeneous term or the antiderivative, if passed, aren't a matrix or don't have correct dimensions NonSquareMatrixError When the coefficient matrix or its antiderivative, if passed isn't a square matrix NotImplementedError If the coefficient matrix doesn't have a commutative antiderivative See Also ======== linear_ode_to_matrix: Coefficient matrix computation function canonical_odes: System of ODEs representation change linodesolve_type: Getting information about systems of ODEs to pass in this solver """ if not isinstance(A, MatrixBase): raise ValueError(filldedent('''\ The coefficients of the system of ODEs should be of type Matrix ''')) if not A.is_square: raise NonSquareMatrixError(filldedent('''\ The coefficient matrix must be a square ''')) if b is not None: if not isinstance(b, MatrixBase): raise ValueError(filldedent('''\ The non-homogeneous terms of the system of ODEs should be of type Matrix ''')) if A.rows != b.rows: raise ValueError(filldedent('''\ The system of ODEs should have the same number of non-homogeneous terms and the number of equations ''')) if B is not None: if not isinstance(B, MatrixBase): raise ValueError(filldedent('''\ The antiderivative of coefficients of the system of ODEs should be of type Matrix ''')) if not B.is_square: raise NonSquareMatrixError(filldedent('''\ The antiderivative of the coefficient matrix must be a square ''')) if A.rows != B.rows: raise ValueError(filldedent('''\ The coefficient matrix and its antiderivative should have same dimensions ''')) if not any(type == "type{}".format(i) for i in range(1, 7)) and not type == "auto": raise ValueError(filldedent('''\ The input type should be a valid one ''')) n = A.rows # constants = numbered_symbols(prefix='C', cls=Dummy, start=const_idx+1) Cvect = Matrix(list(Dummy() for _ in range(n))) if any(type == typ for typ in ["type2", "type4", "type6"]) and b is None: b = zeros(n, 1) is_transformed = tau is not None passed_type = type if type == "auto": system_info = linodesolve_type(A, t, b=b) type = system_info["type_of_equation"] B = system_info["antiderivative"] if type == "type5" or type == "type6": is_transformed = True if passed_type != "auto": if tau is None: system_info = _first_order_type5_6_subs(A, t, b=b) if not system_info: raise ValueError(filldedent(''' The system passed isn't {}. '''.format(type))) tau = system_info['tau'] t = system_info['t_'] A = system_info['A'] b = system_info['b'] if type in ["type1", "type2", "type5", "type6"]: P, J = matrix_exp_jordan_form(A, t) P = simplify(P) if type == "type1" or type == "type5": sol_vector = P * (J * Cvect) else: sol_vector = P * J * ((J.inv() * P.inv() * b).applyfunc(lambda x: Integral(x, t)) + Cvect) else: if B is None: B, _ = _is_commutative_anti_derivative(A, t) if type == "type3": sol_vector = B.exp() * Cvect else: sol_vector = B.exp() * (((-B).exp() * b).applyfunc(lambda x: Integral(x, t)) + Cvect) if is_transformed: sol_vector = sol_vector.subs(t, tau) gens = sol_vector.atoms(exp) if type != "type1": sol_vector = [expand_mul(s) for s in sol_vector] sol_vector = [collect(s, ordered(gens), exact=True) for s in sol_vector] if doit: sol_vector = [s.doit() for s in sol_vector] return sol_vector def _matrix_is_constant(M, t): """Checks if the matrix M is independent of t or not.""" return all(coef.as_independent(t, as_Add=True)[1] == 0 for coef in M) def canonical_odes(eqs, funcs, t): r""" Function that solves for highest order derivatives in a system Explanation =========== This function inputs a system of ODEs and based on the system, the dependent variables and their highest order, returns the system in the following form: .. math:: X'(t) = A(t) X(t) + b(t) Here, $X(t)$ is the vector of dependent variables of lower order, $A(t)$ is the coefficient matrix, $b(t)$ is the non-homogeneous term and $X'(t)$ is the vector of dependent variables in their respective highest order. We use the term canonical form to imply the system of ODEs which is of the above form. If the system passed has a non-linear term with multiple solutions, then a list of systems is returned in its canonical form. Parameters ========== eqs : List List of the ODEs funcs : List List of dependent variables t : Symbol Independent variable Examples ======== >>> from sympy import symbols, Function, Eq, Derivative >>> from sympy.solvers.ode.systems import canonical_odes >>> f, g = symbols("f g", cls=Function) >>> x, y = symbols("x y") >>> funcs = [f(x), g(x)] >>> eqs = [Eq(f(x).diff(x) - 7*f(x), 12*g(x)), Eq(g(x).diff(x) + g(x), 20*f(x))] >>> canonical_eqs = canonical_odes(eqs, funcs, x) >>> canonical_eqs [[Eq(Derivative(f(x), x), 7*f(x) + 12*g(x)), Eq(Derivative(g(x), x), 20*f(x) - g(x))]] >>> system = [Eq(Derivative(f(x), x)**2 - 2*Derivative(f(x), x) + 1, 4), Eq(-y*f(x) + Derivative(g(x), x), 0)] >>> canonical_system = canonical_odes(system, funcs, x) >>> canonical_system [[Eq(Derivative(f(x), x), -1), Eq(Derivative(g(x), x), y*f(x))], [Eq(Derivative(f(x), x), 3), Eq(Derivative(g(x), x), y*f(x))]] Returns ======= List """ from sympy.solvers.solvers import solve order = _get_func_order(eqs, funcs) canon_eqs = solve(eqs, *[func.diff(t, order[func]) for func in funcs], dict=True) systems = [] for eq in canon_eqs: system = [Eq(func.diff(t, order[func]), eq[func.diff(t, order[func])]) for func in funcs] systems.append(system) return systems def _is_commutative_anti_derivative(A, t): r""" Helper function for determining if the Matrix passed is commutative with its antiderivative Explanation =========== This function checks if the Matrix $A$ passed is commutative with its antiderivative with respect to the independent variable $t$. .. math:: B(t) = \int A(t) dt The function outputs two values, first one being the antiderivative $B(t)$, second one being a boolean value, if True, then the matrix $A(t)$ passed is commutative with $B(t)$, else the matrix passed isn't commutative with $B(t)$. Parameters ========== A : Matrix The matrix which has to be checked t : Symbol Independent variable Examples ======== >>> from sympy import symbols, Matrix >>> from sympy.solvers.ode.systems import _is_commutative_anti_derivative >>> t = symbols("t") >>> A = Matrix([[1, t], [-t, 1]]) >>> B, is_commuting = _is_commutative_anti_derivative(A, t) >>> is_commuting True Returns ======= Matrix, Boolean """ B = integrate(A, t) is_commuting = (B*A - A*B).applyfunc(expand).applyfunc(factor_terms).is_zero_matrix is_commuting = False if is_commuting is None else is_commuting return B, is_commuting def _factor_matrix(A, t): term = None for element in A: temp_term = element.as_independent(t)[1] if temp_term.has(t): term = temp_term break if term is not None: A_factored = (A/term).applyfunc(ratsimp) can_factor = _matrix_is_constant(A_factored, t) term = (term, A_factored) if can_factor else None return term def _is_second_order_type2(A, t): term = _factor_matrix(A, t) is_type2 = False if term is not None: term = 1/term[0] is_type2 = term.is_polynomial() if is_type2: poly = Poly(term.expand(), t) monoms = poly.monoms() if monoms[0][0] == 4 or monoms[0][0] == 2: cs = _get_poly_coeffs(poly, 4) a, b, c, d, e = cs a1 = powdenest(sqrt(a), force=True) c1 = powdenest(sqrt(e), force=True) b1 = powdenest(sqrt(c - 2*a1*c1), force=True) is_type2 = (b == 2*a1*b1) and (d == 2*b1*c1) term = a1*t**2 + b1*t + c1 else: is_type2 = False return is_type2, term def _get_poly_coeffs(poly, order): cs = [0 for _ in range(order+1)] for c, m in zip(poly.coeffs(), poly.monoms()): cs[-1-m[0]] = c return cs def _match_second_order_type(A1, A0, t, b=None): r""" Works only for second order system in its canonical form. Type 0: Constant coefficient matrix, can be simply solved by introducing dummy variables. Type 1: When the substitution: $U = t*X' - X$ works for reducing the second order system to first order system. Type 2: When the system is of the form: $poly * X'' = A*X$ where $poly$ is square of a quadratic polynomial with respect to *t* and $A$ is a constant coefficient matrix. """ match = {"type_of_equation": "type0"} n = A1.shape[0] if _matrix_is_constant(A1, t) and _matrix_is_constant(A0, t): return match if (A1 + A0*t).applyfunc(expand_mul).is_zero_matrix: match.update({"type_of_equation": "type1", "A1": A1}) elif A1.is_zero_matrix and (b is None or b.is_zero_matrix): is_type2, term = _is_second_order_type2(A0, t) if is_type2: a, b, c = _get_poly_coeffs(Poly(term, t), 2) A = (A0*(term**2).expand()).applyfunc(ratsimp) + (b**2/4 - a*c)*eye(n, n) tau = integrate(1/term, t) t_ = Symbol("{}_".format(t)) match.update({"type_of_equation": "type2", "A0": A, "g(t)": sqrt(term), "tau": tau, "is_transformed": True, "t_": t_}) return match def _second_order_subs_type1(A, b, funcs, t): r""" For a linear, second order system of ODEs, a particular substitution. A system of the below form can be reduced to a linear first order system of ODEs: .. math:: X'' = A(t) * (t*X' - X) + b(t) By substituting: .. math:: U = t*X' - X To get the system: .. math:: U' = t*(A(t)*U + b(t)) Where $U$ is the vector of dependent variables, $X$ is the vector of dependent variables in `funcs` and $X'$ is the first order derivative of $X$ with respect to $t$. It may or may not reduce the system into linear first order system of ODEs. Then a check is made to determine if the system passed can be reduced or not, if this substitution works, then the system is reduced and its solved for the new substitution. After we get the solution for $U$: .. math:: U = a(t) We substitute and return the reduced system: .. math:: a(t) = t*X' - X Parameters ========== A: Matrix Coefficient matrix($A(t)*t$) of the second order system of this form. b: Matrix Non-homogeneous term($b(t)$) of the system of ODEs. funcs: List List of dependent variables t: Symbol Independent variable of the system of ODEs. Returns ======= List """ U = Matrix([t*func.diff(t) - func for func in funcs]) sol = linodesolve(A, t, t*b) reduced_eqs = [Eq(u, s) for s, u in zip(sol, U)] reduced_eqs = canonical_odes(reduced_eqs, funcs, t)[0] return reduced_eqs def _second_order_subs_type2(A, funcs, t_): r""" Returns a second order system based on the coefficient matrix passed. Explanation =========== This function returns a system of second order ODE of the following form: .. math:: X'' = A * X Here, $X$ is the vector of dependent variables, but a bit modified, $A$ is the coefficient matrix passed. Along with returning the second order system, this function also returns the new dependent variables with the new independent variable `t_` passed. Parameters ========== A: Matrix Coefficient matrix of the system funcs: List List of old dependent variables t_: Symbol New independent variable Returns ======= List, List """ func_names = [func.func.__name__ for func in funcs] new_funcs = [Function(Dummy("{}_".format(name)))(t_) for name in func_names] rhss = A * Matrix(new_funcs) new_eqs = [Eq(func.diff(t_, 2), rhs) for func, rhs in zip(new_funcs, rhss)] return new_eqs, new_funcs def _is_euler_system(As, t): return all(_matrix_is_constant((A*t**i).applyfunc(ratsimp), t) for i, A in enumerate(As)) def _classify_linear_system(eqs, funcs, t, is_canon=False): r""" Returns a dictionary with details of the eqs if the system passed is linear and can be classified by this function else returns None Explanation =========== This function takes the eqs, converts it into a form Ax = b where x is a vector of terms containing dependent variables and their derivatives till their maximum order. If it is possible to convert eqs into Ax = b, then all the equations in eqs are linear otherwise they are non-linear. To check if the equations are constant coefficient, we need to check if all the terms in A obtained above are constant or not. To check if the equations are homogeneous or not, we need to check if b is a zero matrix or not. Parameters ========== eqs: List List of ODEs funcs: List List of dependent variables t: Symbol Independent variable of the equations in eqs is_canon: Boolean If True, then this function won't try to get the system in canonical form. Default value is False Returns ======= match = { 'no_of_equation': len(eqs), 'eq': eqs, 'func': funcs, 'order': order, 'is_linear': is_linear, 'is_constant': is_constant, 'is_homogeneous': is_homogeneous, } Dict or list of Dicts or None Dict with values for keys: 1. no_of_equation: Number of equations 2. eq: The set of equations 3. func: List of dependent variables 4. order: A dictionary that gives the order of the dependent variable in eqs 5. is_linear: Boolean value indicating if the set of equations are linear or not. 6. is_constant: Boolean value indicating if the set of equations have constant coefficients or not. 7. is_homogeneous: Boolean value indicating if the set of equations are homogeneous or not. 8. commutative_antiderivative: Antiderivative of the coefficient matrix if the coefficient matrix is non-constant and commutative with its antiderivative. This key may or may not exist. 9. is_general: Boolean value indicating if the system of ODEs is solvable using one of the general case solvers or not. 10. rhs: rhs of the non-homogeneous system of ODEs in Matrix form. This key may or may not exist. 11. is_higher_order: True if the system passed has an order greater than 1. This key may or may not exist. 12. is_second_order: True if the system passed is a second order ODE. This key may or may not exist. This Dict is the answer returned if the eqs are linear and constant coefficient. Otherwise, None is returned. """ # Error for i == 0 can be added but isn't for now # Check for len(funcs) == len(eqs) if len(funcs) != len(eqs): raise ValueError("Number of functions given is not equal to the number of equations %s" % funcs) # ValueError when functions have more than one arguments for func in funcs: if len(func.args) != 1: raise ValueError("dsolve() and classify_sysode() work with " "functions of one variable only, not %s" % func) # Getting the func_dict and order using the helper # function order = _get_func_order(eqs, funcs) system_order = max(order[func] for func in funcs) is_higher_order = system_order > 1 is_second_order = system_order == 2 and all(order[func] == 2 for func in funcs) # Not adding the check if the len(func.args) for # every func in funcs is 1 # Linearity check try: canon_eqs = canonical_odes(eqs, funcs, t) if not is_canon else [eqs] if len(canon_eqs) == 1: As, b = linear_ode_to_matrix(canon_eqs[0], funcs, t, system_order) else: match = { 'is_implicit': True, 'canon_eqs': canon_eqs } return match # When the system of ODEs is non-linear, an ODENonlinearError is raised. # This function catches the error and None is returned. except ODENonlinearError: return None is_linear = True # Homogeneous check is_homogeneous = True if b.is_zero_matrix else False # Is general key is used to identify if the system of ODEs can be solved by # one of the general case solvers or not. match = { 'no_of_equation': len(eqs), 'eq': eqs, 'func': funcs, 'order': order, 'is_linear': is_linear, 'is_homogeneous': is_homogeneous, 'is_general': True } if not is_homogeneous: match['rhs'] = b is_constant = all(_matrix_is_constant(A_, t) for A_ in As) # The match['is_linear'] check will be added in the future when this # function becomes ready to deal with non-linear systems of ODEs if not is_higher_order: A = As[1] match['func_coeff'] = A # Constant coefficient check is_constant = _matrix_is_constant(A, t) match['is_constant'] = is_constant try: system_info = linodesolve_type(A, t, b=b) except NotImplementedError: return None match.update(system_info) antiderivative = match.pop("antiderivative") if not is_constant: match['commutative_antiderivative'] = antiderivative return match else: match['type_of_equation'] = "type0" if is_second_order: A1, A0 = As[1:] match_second_order = _match_second_order_type(A1, A0, t) match.update(match_second_order) match['is_second_order'] = True # If system is constant, then no need to check if its in euler # form or not. It will be easier and faster to directly proceed # to solve it. if match['type_of_equation'] == "type0" and not is_constant: is_euler = _is_euler_system(As, t) if is_euler: t_ = Symbol('{}_'.format(t)) match.update({'is_transformed': True, 'type_of_equation': 'type1', 't_': t_}) else: is_jordan = lambda M: M == Matrix.jordan_block(M.shape[0], M[0, 0]) terms = _factor_matrix(As[-1], t) if all(A.is_zero_matrix for A in As[1:-1]) and terms is not None and not is_jordan(terms[1]): P, J = terms[1].jordan_form() match.update({'type_of_equation': 'type2', 'J': J, 'f(t)': terms[0], 'P': P, 'is_transformed': True}) if match['type_of_equation'] != 'type0' and is_second_order: match.pop('is_second_order', None) match['is_higher_order'] = is_higher_order return match def _preprocess_eqs(eqs): processed_eqs = [] for eq in eqs: processed_eqs.append(eq if isinstance(eq, Equality) else Eq(eq, 0)) return processed_eqs def _eqs2dict(eqs, funcs): eqsorig = {} eqsmap = {} funcset = set(funcs) for eq in eqs: f1, = eq.lhs.atoms(AppliedUndef) f2s = (eq.rhs.atoms(AppliedUndef) - {f1}) & funcset eqsmap[f1] = f2s eqsorig[f1] = eq return eqsmap, eqsorig def _dict2graph(d): nodes = list(d) edges = [(f1, f2) for f1, f2s in d.items() for f2 in f2s] G = (nodes, edges) return G def _is_type1(scc, t): eqs, funcs = scc try: (A1, A0), b = linear_ode_to_matrix(eqs, funcs, t, 1) except (ODENonlinearError, ODEOrderError): return False if _matrix_is_constant(A0, t) and b.is_zero_matrix: return True return False def _combine_type1_subsystems(subsystem, funcs, t): indices = [i for i, sys in enumerate(zip(subsystem, funcs)) if _is_type1(sys, t)] remove = set() for ip, i in enumerate(indices): for j in indices[ip+1:]: if any(eq2.has(funcs[i]) for eq2 in subsystem[j]): subsystem[j] = subsystem[i] + subsystem[j] remove.add(i) subsystem = [sys for i, sys in enumerate(subsystem) if i not in remove] return subsystem def _component_division(eqs, funcs, t): from sympy.utilities.iterables import connected_components, strongly_connected_components # Assuming that each eq in eqs is in canonical form, # that is, [f(x).diff(x) = .., g(x).diff(x) = .., etc] # and that the system passed is in its first order eqsmap, eqsorig = _eqs2dict(eqs, funcs) subsystems = [] for cc in connected_components(_dict2graph(eqsmap)): eqsmap_c = {f: eqsmap[f] for f in cc} sccs = strongly_connected_components(_dict2graph(eqsmap_c)) subsystem = [[eqsorig[f] for f in scc] for scc in sccs] subsystem = _combine_type1_subsystems(subsystem, sccs, t) subsystems.append(subsystem) return subsystems # Returns: List of equations def _linear_ode_solver(match): t = match['t'] funcs = match['func'] rhs = match.get('rhs', None) tau = match.get('tau', None) t = match['t_'] if 't_' in match else t A = match['func_coeff'] # Note: To make B None when the matrix has constant # coefficient B = match.get('commutative_antiderivative', None) type = match['type_of_equation'] sol_vector = linodesolve(A, t, b=rhs, B=B, type=type, tau=tau) sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] return sol def _select_equations(eqs, funcs, key=lambda x: x): eq_dict = {e.lhs: e.rhs for e in eqs} return [Eq(f, eq_dict[key(f)]) for f in funcs] def _higher_order_ode_solver(match): eqs = match["eq"] funcs = match["func"] t = match["t"] sysorder = match['order'] type = match.get('type_of_equation', "type0") is_second_order = match.get('is_second_order', False) is_transformed = match.get('is_transformed', False) is_euler = is_transformed and type == "type1" is_higher_order_type2 = is_transformed and type == "type2" and 'P' in match if is_second_order: new_eqs, new_funcs = _second_order_to_first_order(eqs, funcs, t, A1=match.get("A1", None), A0=match.get("A0", None), b=match.get("rhs", None), type=type, t_=match.get("t_", None)) else: new_eqs, new_funcs = _higher_order_to_first_order(eqs, sysorder, t, funcs=funcs, type=type, J=match.get('J', None), f_t=match.get('f(t)', None), P=match.get('P', None), b=match.get('rhs', None)) if is_transformed: t = match.get('t_', t) if not is_higher_order_type2: new_eqs = _select_equations(new_eqs, [f.diff(t) for f in new_funcs]) sol = None # NotImplementedError may be raised when the system may be actually # solvable if it can be just divided into sub-systems try: if not is_higher_order_type2: sol = _strong_component_solver(new_eqs, new_funcs, t) except NotImplementedError: sol = None # Dividing the system only when it becomes essential if sol is None: try: sol = _component_solver(new_eqs, new_funcs, t) except NotImplementedError: sol = None if sol is None: return sol is_second_order_type2 = is_second_order and type == "type2" underscores = '__' if is_transformed else '_' sol = _select_equations(sol, funcs, key=lambda x: Function(Dummy('{}{}0'.format(x.func.__name__, underscores)))(t)) if match.get("is_transformed", False): if is_second_order_type2: g_t = match["g(t)"] tau = match["tau"] sol = [Eq(s.lhs, s.rhs.subs(t, tau) * g_t) for s in sol] elif is_euler: t = match['t'] tau = match['t_'] sol = [s.subs(tau, log(t)) for s in sol] elif is_higher_order_type2: P = match['P'] sol_vector = P * Matrix([s.rhs for s in sol]) sol = [Eq(f, s) for f, s in zip(funcs, sol_vector)] return sol # Returns: List of equations or None # If None is returned by this solver, then the system # of ODEs cannot be solved directly by dsolve_system. def _strong_component_solver(eqs, funcs, t): from sympy.solvers.ode.ode import dsolve, constant_renumber match = _classify_linear_system(eqs, funcs, t, is_canon=True) sol = None # Assuming that we can't get an implicit system # since we are already canonical equations from # dsolve_system if match: match['t'] = t if match.get('is_higher_order', False): sol = _higher_order_ode_solver(match) elif match.get('is_linear', False): sol = _linear_ode_solver(match) # Note: For now, only linear systems are handled by this function # hence, the match condition is added. This can be removed later. if sol is None and len(eqs) == 1: sol = dsolve(eqs[0], func=funcs[0]) variables = Tuple(eqs[0]).free_symbols new_constants = [Dummy() for _ in range(ode_order(eqs[0], funcs[0]))] sol = constant_renumber(sol, variables=variables, newconstants=new_constants) sol = [sol] # To add non-linear case here in future return sol def _get_funcs_from_canon(eqs): return [eq.lhs.args[0] for eq in eqs] # Returns: List of Equations(a solution) def _weak_component_solver(wcc, t): # We will divide the systems into sccs # only when the wcc cannot be solved as # a whole eqs = [] for scc in wcc: eqs += scc funcs = _get_funcs_from_canon(eqs) sol = _strong_component_solver(eqs, funcs, t) if sol: return sol sol = [] for j, scc in enumerate(wcc): eqs = scc funcs = _get_funcs_from_canon(eqs) # Substituting solutions for the dependent # variables solved in previous SCC, if any solved. comp_eqs = [eq.subs({s.lhs: s.rhs for s in sol}) for eq in eqs] scc_sol = _strong_component_solver(comp_eqs, funcs, t) if scc_sol is None: raise NotImplementedError(filldedent(''' The system of ODEs passed cannot be solved by dsolve_system. ''')) # scc_sol: List of equations # scc_sol is a solution sol += scc_sol return sol # Returns: List of Equations(a solution) def _component_solver(eqs, funcs, t): components = _component_division(eqs, funcs, t) sol = [] for wcc in components: # wcc_sol: List of Equations sol += _weak_component_solver(wcc, t) # sol: List of Equations return sol def _second_order_to_first_order(eqs, funcs, t, type="auto", A1=None, A0=None, b=None, t_=None): r""" Expects the system to be in second order and in canonical form Explanation =========== Reduces a second order system into a first order one depending on the type of second order system. 1. "type0": If this is passed, then the system will be reduced to first order by introducing dummy variables. 2. "type1": If this is passed, then a particular substitution will be used to reduce the the system into first order. 3. "type2": If this is passed, then the system will be transformed with new dependent variables and independent variables. This transformation is a part of solving the corresponding system of ODEs. `A1` and `A0` are the coefficient matrices from the system and it is assumed that the second order system has the form given below: .. math:: A2 * X'' = A1 * X' + A0 * X + b Here, $A2$ is the coefficient matrix for the vector $X''$ and $b$ is the non-homogeneous term. Default value for `b` is None but if `A1` and `A0` are passed and `b` isn't passed, then the system will be assumed homogeneous. """ is_a1 = A1 is None is_a0 = A0 is None if (type == "type1" and is_a1) or (type == "type2" and is_a0)\ or (type == "auto" and (is_a1 or is_a0)): (A2, A1, A0), b = linear_ode_to_matrix(eqs, funcs, t, 2) if not A2.is_Identity: raise ValueError(filldedent(''' The system must be in its canonical form. ''')) if type == "auto": match = _match_second_order_type(A1, A0, t) type = match["type_of_equation"] A1 = match.get("A1", None) A0 = match.get("A0", None) sys_order = {func: 2 for func in funcs} if type == "type1": if b is None: b = zeros(len(eqs)) eqs = _second_order_subs_type1(A1, b, funcs, t) sys_order = {func: 1 for func in funcs} if type == "type2": if t_ is None: t_ = Symbol("{}_".format(t)) t = t_ eqs, funcs = _second_order_subs_type2(A0, funcs, t_) sys_order = {func: 2 for func in funcs} return _higher_order_to_first_order(eqs, sys_order, t, funcs=funcs) def _higher_order_type2_to_sub_systems(J, f_t, funcs, t, max_order, b=None, P=None): # Note: To add a test for this ValueError if J is None or f_t is None or not _matrix_is_constant(J, t): raise ValueError(filldedent(''' Correctly input for args 'A' and 'f_t' for Linear, Higher Order, Type 2 ''')) if P is None and b is not None and not b.is_zero_matrix: raise ValueError(filldedent(''' Provide the keyword 'P' for matrix P in A = P * J * P-1. ''')) new_funcs = Matrix([Function(Dummy('{}__0'.format(f.func.__name__)))(t) for f in funcs]) new_eqs = new_funcs.diff(t, max_order) - f_t * J * new_funcs if b is not None and not b.is_zero_matrix: new_eqs -= P.inv() * b new_eqs = canonical_odes(new_eqs, new_funcs, t)[0] return new_eqs, new_funcs def _higher_order_to_first_order(eqs, sys_order, t, funcs=None, type="type0", **kwargs): if funcs is None: funcs = sys_order.keys() # Standard Cauchy Euler system if type == "type1": t_ = Symbol('{}_'.format(t)) new_funcs = [Function(Dummy('{}_'.format(f.func.__name__)))(t_) for f in funcs] max_order = max(sys_order[func] for func in funcs) subs_dict = {func: new_func for func, new_func in zip(funcs, new_funcs)} subs_dict[t] = exp(t_) free_function = Function(Dummy()) def _get_coeffs_from_subs_expression(expr): if isinstance(expr, Subs): free_symbol = expr.args[1][0] term = expr.args[0] return {ode_order(term, free_symbol): 1} if isinstance(expr, Mul): coeff = expr.args[0] order = list(_get_coeffs_from_subs_expression(expr.args[1]).keys())[0] return {order: coeff} if isinstance(expr, Add): coeffs = {} for arg in expr.args: if isinstance(arg, Mul): coeffs.update(_get_coeffs_from_subs_expression(arg)) else: order = list(_get_coeffs_from_subs_expression(arg).keys())[0] coeffs[order] = 1 return coeffs for o in range(1, max_order + 1): expr = free_function(log(t_)).diff(t_, o)*t_**o coeff_dict = _get_coeffs_from_subs_expression(expr) coeffs = [coeff_dict[order] if order in coeff_dict else 0 for order in range(o + 1)] expr_to_subs = sum(free_function(t_).diff(t_, i) * c for i, c in enumerate(coeffs)) / t**o subs_dict.update({f.diff(t, o): expr_to_subs.subs(free_function(t_), nf) for f, nf in zip(funcs, new_funcs)}) new_eqs = [eq.subs(subs_dict) for eq in eqs] new_sys_order = {nf: sys_order[f] for f, nf in zip(funcs, new_funcs)} new_eqs = canonical_odes(new_eqs, new_funcs, t_)[0] return _higher_order_to_first_order(new_eqs, new_sys_order, t_, funcs=new_funcs) # Systems of the form: X(n)(t) = f(t)*A*X + b # where X(n)(t) is the nth derivative of the vector of dependent variables # with respect to the independent variable and A is a constant matrix. if type == "type2": J = kwargs.get('J', None) f_t = kwargs.get('f_t', None) b = kwargs.get('b', None) P = kwargs.get('P', None) max_order = max(sys_order[func] for func in funcs) return _higher_order_type2_to_sub_systems(J, f_t, funcs, t, max_order, P=P, b=b) # Note: To be changed to this after doit option is disabled for default cases # new_sysorder = _get_func_order(new_eqs, new_funcs) # # return _higher_order_to_first_order(new_eqs, new_sysorder, t, funcs=new_funcs) new_funcs = [] for prev_func in funcs: func_name = prev_func.func.__name__ func = Function(Dummy('{}_0'.format(func_name)))(t) new_funcs.append(func) subs_dict = {prev_func: func} new_eqs = [] for i in range(1, sys_order[prev_func]): new_func = Function(Dummy('{}_{}'.format(func_name, i)))(t) subs_dict[prev_func.diff(t, i)] = new_func new_funcs.append(new_func) prev_f = subs_dict[prev_func.diff(t, i-1)] new_eq = Eq(prev_f.diff(t), new_func) new_eqs.append(new_eq) eqs = [eq.subs(subs_dict) for eq in eqs] + new_eqs return eqs, new_funcs def dsolve_system(eqs, funcs=None, t=None, ics=None, doit=False, simplify=True): r""" Solves any(supported) system of Ordinary Differential Equations Explanation =========== This function takes a system of ODEs as an input, determines if the it is solvable by this function, and returns the solution if found any. This function can handle: 1. Linear, First Order, Constant coefficient homogeneous system of ODEs 2. Linear, First Order, Constant coefficient non-homogeneous system of ODEs 3. Linear, First Order, non-constant coefficient homogeneous system of ODEs 4. Linear, First Order, non-constant coefficient non-homogeneous system of ODEs 5. Any implicit system which can be divided into system of ODEs which is of the above 4 forms 6. Any higher order linear system of ODEs that can be reduced to one of the 5 forms of systems described above. The types of systems described above aren't limited by the number of equations, i.e. this function can solve the above types irrespective of the number of equations in the system passed. But, the bigger the system, the more time it will take to solve the system. This function returns a list of solutions. Each solution is a list of equations where LHS is the dependent variable and RHS is an expression in terms of the independent variable. Among the non constant coefficient types, not all the systems are solvable by this function. Only those which have either a coefficient matrix with a commutative antiderivative or those systems which may be divided further so that the divided systems may have coefficient matrix with commutative antiderivative. Parameters ========== eqs : List system of ODEs to be solved funcs : List or None List of dependent variables that make up the system of ODEs t : Symbol or None Independent variable in the system of ODEs ics : Dict or None Set of initial boundary/conditions for the system of ODEs doit : Boolean Evaluate the solutions if True. Default value is True. Can be set to false if the integral evaluation takes too much time and/or isn't required. simplify: Boolean Simplify the solutions for the systems. Default value is True. Can be set to false if simplification takes too much time and/or isn't required. Examples ======== >>> from sympy import symbols, Eq, Function >>> from sympy.solvers.ode.systems import dsolve_system >>> f, g = symbols("f g", cls=Function) >>> x = symbols("x") >>> eqs = [Eq(f(x).diff(x), g(x)), Eq(g(x).diff(x), f(x))] >>> dsolve_system(eqs) [[Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), C1*exp(-x) + C2*exp(x))]] You can also pass the initial conditions for the system of ODEs: >>> dsolve_system(eqs, ics={f(0): 1, g(0): 0}) [[Eq(f(x), exp(x)/2 + exp(-x)/2), Eq(g(x), exp(x)/2 - exp(-x)/2)]] Optionally, you can pass the dependent variables and the independent variable for which the system is to be solved: >>> funcs = [f(x), g(x)] >>> dsolve_system(eqs, funcs=funcs, t=x) [[Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), C1*exp(-x) + C2*exp(x))]] Lets look at an implicit system of ODEs: >>> eqs = [Eq(f(x).diff(x)**2, g(x)**2), Eq(g(x).diff(x), g(x))] >>> dsolve_system(eqs) [[Eq(f(x), C1 - C2*exp(x)), Eq(g(x), C2*exp(x))], [Eq(f(x), C1 + C2*exp(x)), Eq(g(x), C2*exp(x))]] Returns ======= List of List of Equations Raises ====== NotImplementedError When the system of ODEs is not solvable by this function. ValueError When the parameters passed aren't in the required form. """ from sympy.solvers.ode.ode import solve_ics, _extract_funcs, constant_renumber if not iterable(eqs): raise ValueError(filldedent(''' List of equations should be passed. The input is not valid. ''')) eqs = _preprocess_eqs(eqs) if funcs is not None and not isinstance(funcs, list): raise ValueError(filldedent(''' Input to the funcs should be a list of functions. ''')) if funcs is None: funcs = _extract_funcs(eqs) if any(len(func.args) != 1 for func in funcs): raise ValueError(filldedent(''' dsolve_system can solve a system of ODEs with only one independent variable. ''')) if len(eqs) != len(funcs): raise ValueError(filldedent(''' Number of equations and number of functions don't match ''')) if t is not None and not isinstance(t, Symbol): raise ValueError(filldedent(''' The indepedent variable must be of type Symbol ''')) if t is None: t = list(list(eqs[0].atoms(Derivative))[0].atoms(Symbol))[0] sols = [] canon_eqs = canonical_odes(eqs, funcs, t) for canon_eq in canon_eqs: try: sol = _strong_component_solver(canon_eq, funcs, t) except NotImplementedError: sol = None if sol is None: sol = _component_solver(canon_eq, funcs, t) sols.append(sol) if sols: final_sols = [] variables = Tuple(*eqs).free_symbols for sol in sols: sol = _select_equations(sol, funcs) sol = constant_renumber(sol, variables=variables) if ics: constants = Tuple(*sol).free_symbols - variables solved_constants = solve_ics(sol, funcs, constants, ics) sol = [s.subs(solved_constants) for s in sol] if simplify: constants = Tuple(*sol).free_symbols - variables sol = simpsol(sol, [t], constants, doit=doit) final_sols.append(sol) sols = final_sols return sols sympy-sympy-1.9/sympy/solvers/ode/tests/000077500000000000000000000000001412543434000205125ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/ode/tests/__init__.py000066400000000000000000000000001412543434000226110ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/ode/tests/test_lie_group.py000066400000000000000000000117031412543434000241120ustar00rootroot00000000000000from sympy import (atan, Eq, exp, Function, log, Rational, sin, sqrt, Symbol, tan, symbols) from sympy.solvers.ode import (classify_ode, checkinfsol, dsolve, infinitesimals) from sympy.solvers.ode.subscheck import checkodesol from sympy.testing.pytest import XFAIL C1 = Symbol('C1') x, y = symbols("x y") f = Function('f') xi = Function('xi') eta = Function('eta') def test_heuristic1(): a, b, c, a4, a3, a2, a1, a0 = symbols("a b c a4 a3 a2 a1 a0") df = f(x).diff(x) eq = Eq(df, x**2*f(x)) eq1 = f(x).diff(x) + a*f(x) - c*exp(b*x) eq2 = f(x).diff(x) + 2*x*f(x) - x*exp(-x**2) eq3 = (1 + 2*x)*df + 2 - 4*exp(-f(x)) eq4 = f(x).diff(x) - (a4*x**4 + a3*x**3 + a2*x**2 + a1*x + a0)**Rational(-1, 2) eq5 = x**2*df - f(x) + x**2*exp(x - (1/x)) eqlist = [eq, eq1, eq2, eq3, eq4, eq5] i = infinitesimals(eq, hint='abaco1_simple') assert i == [{eta(x, f(x)): exp(x**3/3), xi(x, f(x)): 0}, {eta(x, f(x)): f(x), xi(x, f(x)): 0}, {eta(x, f(x)): 0, xi(x, f(x)): x**(-2)}] i1 = infinitesimals(eq1, hint='abaco1_simple') assert i1 == [{eta(x, f(x)): exp(-a*x), xi(x, f(x)): 0}] i2 = infinitesimals(eq2, hint='abaco1_simple') assert i2 == [{eta(x, f(x)): exp(-x**2), xi(x, f(x)): 0}] i3 = infinitesimals(eq3, hint='abaco1_simple') assert i3 == [{eta(x, f(x)): 0, xi(x, f(x)): 2*x + 1}, {eta(x, f(x)): 0, xi(x, f(x)): 1/(exp(f(x)) - 2)}] i4 = infinitesimals(eq4, hint='abaco1_simple') assert i4 == [{eta(x, f(x)): 1, xi(x, f(x)): 0}, {eta(x, f(x)): 0, xi(x, f(x)): sqrt(a0 + a1*x + a2*x**2 + a3*x**3 + a4*x**4)}] i5 = infinitesimals(eq5, hint='abaco1_simple') assert i5 == [{xi(x, f(x)): 0, eta(x, f(x)): exp(-1/x)}] ilist = [i, i1, i2, i3, i4, i5] for eq, i in (zip(eqlist, ilist)): check = checkinfsol(eq, i) assert check[0] # This ODE can be solved by the Lie Group method, when there are # better assumptions eq6 = df - (f(x)/x)*(x*log(x**2/f(x)) + 2) i = infinitesimals(eq6, hint='abaco1_product') assert i == [{eta(x, f(x)): f(x)*exp(-x), xi(x, f(x)): 0}] assert checkinfsol(eq6, i)[0] eq7 = x*(f(x).diff(x)) + 1 - f(x)**2 i = infinitesimals(eq7, hint='chi') assert checkinfsol(eq7, i)[0] def test_heuristic3(): a, b = symbols("a b") df = f(x).diff(x) eq = x**2*df + x*f(x) + f(x)**2 + x**2 i = infinitesimals(eq, hint='bivariate') assert i == [{eta(x, f(x)): f(x), xi(x, f(x)): x}] assert checkinfsol(eq, i)[0] eq = x**2*(-f(x)**2 + df)- a*x**2*f(x) + 2 - a*x i = infinitesimals(eq, hint='bivariate') assert checkinfsol(eq, i)[0] def test_heuristic_function_sum(): eq = f(x).diff(x) - (3*(1 + x**2/f(x)**2)*atan(f(x)/x) + (1 - 2*f(x))/x + (1 - 3*f(x))*(x/f(x)**2)) i = infinitesimals(eq, hint='function_sum') assert i == [{eta(x, f(x)): f(x)**(-2) + x**(-2), xi(x, f(x)): 0}] assert checkinfsol(eq, i)[0] def test_heuristic_abaco2_similar(): a, b = symbols("a b") F = Function('F') eq = f(x).diff(x) - F(a*x + b*f(x)) i = infinitesimals(eq, hint='abaco2_similar') assert i == [{eta(x, f(x)): -a/b, xi(x, f(x)): 1}] assert checkinfsol(eq, i)[0] eq = f(x).diff(x) - (f(x)**2 / (sin(f(x) - x) - x**2 + 2*x*f(x))) i = infinitesimals(eq, hint='abaco2_similar') assert i == [{eta(x, f(x)): f(x)**2, xi(x, f(x)): f(x)**2}] assert checkinfsol(eq, i)[0] def test_heuristic_abaco2_unique_unknown(): a, b = symbols("a b") F = Function('F') eq = f(x).diff(x) - x**(a - 1)*(f(x)**(1 - b))*F(x**a/a + f(x)**b/b) i = infinitesimals(eq, hint='abaco2_unique_unknown') assert i == [{eta(x, f(x)): -f(x)*f(x)**(-b), xi(x, f(x)): x*x**(-a)}] assert checkinfsol(eq, i)[0] eq = f(x).diff(x) + tan(F(x**2 + f(x)**2) + atan(x/f(x))) i = infinitesimals(eq, hint='abaco2_unique_unknown') assert i == [{eta(x, f(x)): x, xi(x, f(x)): -f(x)}] assert checkinfsol(eq, i)[0] eq = (x*f(x).diff(x) + f(x) + 2*x)**2 -4*x*f(x) -4*x**2 -4*a i = infinitesimals(eq, hint='abaco2_unique_unknown') assert checkinfsol(eq, i)[0] def test_heuristic_linear(): a, b, m, n = symbols("a b m n") eq = x**(n*(m + 1) - m)*(f(x).diff(x)) - a*f(x)**n -b*x**(n*(m + 1)) i = infinitesimals(eq, hint='linear') assert checkinfsol(eq, i)[0] @XFAIL def test_kamke(): a, b, alpha, c = symbols("a b alpha c") eq = x**2*(a*f(x)**2+(f(x).diff(x))) + b*x**alpha + c i = infinitesimals(eq, hint='sum_function') # XFAIL assert checkinfsol(eq, i)[0] def test_user_infinitesimals(): x = Symbol("x") # assuming x is real generates an error eq = x*(f(x).diff(x)) + 1 - f(x)**2 sol = Eq(f(x), (C1 + x**2)/(C1 - x**2)) infinitesimals = {'xi':sqrt(f(x) - 1)/sqrt(f(x) + 1), 'eta':0} assert dsolve(eq, hint='lie_group', **infinitesimals) == sol assert checkodesol(eq, sol) == (True, 0) @XFAIL def test_lie_group_issue15219(): eqn = exp(f(x).diff(x)-f(x)) assert 'lie_group' not in classify_ode(eqn, f(x)) sympy-sympy-1.9/sympy/solvers/ode/tests/test_ode.py000066400000000000000000001266001412543434000226770ustar00rootroot00000000000000from sympy import (acosh, cos, Derivative, diff, Eq, exp, Function, I, Integral, log, O, pi, Rational, S, sin, sqrt, Subs, Symbol, tan, symbols, Poly, re, im, atan2, collect) from sympy.solvers.ode import (classify_ode, homogeneous_order, dsolve) from sympy.solvers.ode.subscheck import checkodesol from sympy.solvers.ode.ode import (classify_sysode, constant_renumber, constantsimp, get_numbered_constants, solve_ics) from sympy.solvers.ode.nonhomogeneous import _undetermined_coefficients_match from sympy.solvers.ode.single import LinearCoefficients from sympy.solvers.deutils import ode_order from sympy.testing.pytest import XFAIL, raises, slow C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 = symbols('C0:11') u, x, y, z = symbols('u,x:z', real=True) f = Function('f') g = Function('g') h = Function('h') # Note: Examples which were specifically testing Single ODE solver are moved to test_single.py # and all the system of ode examples are moved to test_systems.py # Note: the tests below may fail (but still be correct) if ODE solver, # the integral engine, solve(), or even simplify() changes. Also, in # differently formatted solutions, the arbitrary constants might not be # equal. Using specific hints in tests can help to avoid this. # Tests of order higher than 1 should run the solutions through # constant_renumber because it will normalize it (constant_renumber causes # dsolve() to return different results on different machines) def test_get_numbered_constants(): with raises(ValueError): get_numbered_constants(None) def test_dsolve_all_hint(): eq = f(x).diff(x) output = dsolve(eq, hint='all') # Match the Dummy variables: sol1 = output['separable_Integral'] _y = sol1.lhs.args[1][0] sol1 = output['1st_homogeneous_coeff_subs_dep_div_indep_Integral'] _u1 = sol1.rhs.args[1].args[1][0] expected = {'Bernoulli_Integral': Eq(f(x), C1 + Integral(0, x)), '1st_homogeneous_coeff_best': Eq(f(x), C1), 'Bernoulli': Eq(f(x), C1), 'nth_algebraic': Eq(f(x), C1), 'nth_linear_euler_eq_homogeneous': Eq(f(x), C1), 'nth_linear_constant_coeff_homogeneous': Eq(f(x), C1), 'separable': Eq(f(x), C1), '1st_homogeneous_coeff_subs_indep_div_dep': Eq(f(x), C1), 'nth_algebraic_Integral': Eq(f(x), C1), '1st_linear': Eq(f(x), C1), '1st_linear_Integral': Eq(f(x), C1 + Integral(0, x)), '1st_exact': Eq(f(x), C1), '1st_exact_Integral': Eq(Subs(Integral(0, x) + Integral(1, _y), _y, f(x)), C1), 'lie_group': Eq(f(x), C1), '1st_homogeneous_coeff_subs_dep_div_indep': Eq(f(x), C1), '1st_homogeneous_coeff_subs_dep_div_indep_Integral': Eq(log(x), C1 + Integral(-1/_u1, (_u1, f(x)/x))), '1st_power_series': Eq(f(x), C1), 'separable_Integral': Eq(Integral(1, (_y, f(x))), C1 + Integral(0, x)), '1st_homogeneous_coeff_subs_indep_div_dep_Integral': Eq(f(x), C1), 'best': Eq(f(x), C1), 'best_hint': 'nth_algebraic', 'default': 'nth_algebraic', 'order': 1} assert output == expected assert dsolve(eq, hint='best') == Eq(f(x), C1) def test_dsolve_ics(): # Maybe this should just use one of the solutions instead of raising... with raises(NotImplementedError): dsolve(f(x).diff(x) - sqrt(f(x)), ics={f(1):1}) @slow def test_dsolve_options(): eq = x*f(x).diff(x) + f(x) a = dsolve(eq, hint='all') b = dsolve(eq, hint='all', simplify=False) c = dsolve(eq, hint='all_Integral') keys = ['1st_exact', '1st_exact_Integral', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_dep_div_indep', '1st_homogeneous_coeff_subs_dep_div_indep_Integral', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_linear', '1st_linear_Integral', 'Bernoulli', 'Bernoulli_Integral', 'almost_linear', 'almost_linear_Integral', 'best', 'best_hint', 'default', 'lie_group', 'nth_linear_euler_eq_homogeneous', 'order', 'separable', 'separable_Integral'] Integral_keys = ['1st_exact_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_linear_Integral', 'Bernoulli_Integral', 'almost_linear_Integral', 'best', 'best_hint', 'default', 'nth_linear_euler_eq_homogeneous', 'order', 'separable_Integral'] assert sorted(a.keys()) == keys assert a['order'] == ode_order(eq, f(x)) assert a['best'] == Eq(f(x), C1/x) assert dsolve(eq, hint='best') == Eq(f(x), C1/x) assert a['default'] == 'separable' assert a['best_hint'] == 'separable' assert not a['1st_exact'].has(Integral) assert not a['separable'].has(Integral) assert not a['1st_homogeneous_coeff_best'].has(Integral) assert not a['1st_homogeneous_coeff_subs_dep_div_indep'].has(Integral) assert not a['1st_homogeneous_coeff_subs_indep_div_dep'].has(Integral) assert not a['1st_linear'].has(Integral) assert a['1st_linear_Integral'].has(Integral) assert a['1st_exact_Integral'].has(Integral) assert a['1st_homogeneous_coeff_subs_dep_div_indep_Integral'].has(Integral) assert a['1st_homogeneous_coeff_subs_indep_div_dep_Integral'].has(Integral) assert a['separable_Integral'].has(Integral) assert sorted(b.keys()) == keys assert b['order'] == ode_order(eq, f(x)) assert b['best'] == Eq(f(x), C1/x) assert dsolve(eq, hint='best', simplify=False) == Eq(f(x), C1/x) assert b['default'] == 'separable' assert b['best_hint'] == '1st_linear' assert a['separable'] != b['separable'] assert a['1st_homogeneous_coeff_subs_dep_div_indep'] != \ b['1st_homogeneous_coeff_subs_dep_div_indep'] assert a['1st_homogeneous_coeff_subs_indep_div_dep'] != \ b['1st_homogeneous_coeff_subs_indep_div_dep'] assert not b['1st_exact'].has(Integral) assert not b['separable'].has(Integral) assert not b['1st_homogeneous_coeff_best'].has(Integral) assert not b['1st_homogeneous_coeff_subs_dep_div_indep'].has(Integral) assert not b['1st_homogeneous_coeff_subs_indep_div_dep'].has(Integral) assert not b['1st_linear'].has(Integral) assert b['1st_linear_Integral'].has(Integral) assert b['1st_exact_Integral'].has(Integral) assert b['1st_homogeneous_coeff_subs_dep_div_indep_Integral'].has(Integral) assert b['1st_homogeneous_coeff_subs_indep_div_dep_Integral'].has(Integral) assert b['separable_Integral'].has(Integral) assert sorted(c.keys()) == Integral_keys raises(ValueError, lambda: dsolve(eq, hint='notarealhint')) raises(ValueError, lambda: dsolve(eq, hint='Liouville')) assert dsolve(f(x).diff(x) - 1/f(x)**2, hint='all')['best'] == \ dsolve(f(x).diff(x) - 1/f(x)**2, hint='best') assert dsolve(f(x) + f(x).diff(x) + sin(x).diff(x) + 1, f(x), hint="1st_linear_Integral") == \ Eq(f(x), (C1 + Integral((-sin(x).diff(x) - 1)* exp(Integral(1, x)), x))*exp(-Integral(1, x))) def test_classify_ode(): assert classify_ode(f(x).diff(x, 2), f(x)) == \ ( 'nth_algebraic', 'nth_linear_constant_coeff_homogeneous', 'nth_linear_euler_eq_homogeneous', 'Liouville', '2nd_power_series_ordinary', 'nth_algebraic_Integral', 'Liouville_Integral', ) assert classify_ode(f(x), f(x)) == ('nth_algebraic', 'nth_algebraic_Integral') assert classify_ode(Eq(f(x).diff(x), 0), f(x)) == ( 'nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_homogeneous', 'nth_linear_euler_eq_homogeneous', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral') assert classify_ode(f(x).diff(x)**2, f(x)) == ('factorable', 'nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', '1st_power_series', 'lie_group', 'nth_linear_euler_eq_homogeneous', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral') # issue 4749: f(x) should be cleared from highest derivative before classifying a = classify_ode(Eq(f(x).diff(x) + f(x), x), f(x)) b = classify_ode(f(x).diff(x)*f(x) + f(x)*f(x) - x*f(x), f(x)) c = classify_ode(f(x).diff(x)/f(x) + f(x)/f(x) - x/f(x), f(x)) assert a == ('1st_exact', '1st_linear', 'Bernoulli', 'almost_linear', '1st_power_series', "lie_group", 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', 'almost_linear_Integral', 'nth_linear_constant_coeff_variation_of_parameters_Integral') assert b == ('factorable', '1st_linear', 'Bernoulli', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', '1st_linear_Integral', 'Bernoulli_Integral', 'nth_linear_constant_coeff_variation_of_parameters_Integral') assert c == ('1st_linear', 'Bernoulli', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', '1st_linear_Integral', 'Bernoulli_Integral', 'nth_linear_constant_coeff_variation_of_parameters_Integral') assert classify_ode( 2*x*f(x)*f(x).diff(x) + (1 + x)*f(x)**2 - exp(x), f(x) ) == ('1st_exact', 'Bernoulli', 'almost_linear', 'lie_group', '1st_exact_Integral', 'Bernoulli_Integral', 'almost_linear_Integral') assert 'Riccati_special_minus2' in \ classify_ode(2*f(x).diff(x) + f(x)**2 - f(x)/x + 3*x**(-2), f(x)) raises(ValueError, lambda: classify_ode(x + f(x, y).diff(x).diff( y), f(x, y))) # issue 5176 k = Symbol('k') assert classify_ode(f(x).diff(x)/(k*f(x) + k*x*f(x)) + 2*f(x)/(k*f(x) + k*x*f(x)) + x*f(x).diff(x)/(k*f(x) + k*x*f(x)) + z, f(x)) == \ ('separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_power_series', 'lie_group', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral') # preprocessing ans = ('nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral', 'nth_linear_constant_coeff_variation_of_parameters_Integral', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters_Integral') # w/o f(x) given assert classify_ode(diff(f(x) + x, x) + diff(f(x), x)) == ans # w/ f(x) and prep=True assert classify_ode(diff(f(x) + x, x) + diff(f(x), x), f(x), prep=True) == ans assert classify_ode(Eq(2*x**3*f(x).diff(x), 0), f(x)) == \ ('factorable', 'nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_power_series', 'lie_group', 'nth_linear_euler_eq_homogeneous', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral') assert classify_ode(Eq(2*f(x)**3*f(x).diff(x), 0), f(x)) == \ ('factorable', 'nth_algebraic', 'separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_power_series', 'lie_group', 'nth_algebraic_Integral', 'separable_Integral', '1st_exact_Integral', '1st_linear_Integral', 'Bernoulli_Integral') # test issue 13864 assert classify_ode(Eq(diff(f(x), x) - f(x)**x, 0), f(x)) == \ ('1st_power_series', 'lie_group') assert isinstance(classify_ode(Eq(f(x), 5), f(x), dict=True), dict) #This is for new behavior of classify_ode when called internally with default, It should # return the first hint which matches therefore, 'ordered_hints' key will not be there. assert sorted(classify_ode(Eq(f(x).diff(x), 0), f(x), dict=True).keys()) == \ ['default', 'nth_linear_constant_coeff_homogeneous', 'order'] a = classify_ode(2*x*f(x)*f(x).diff(x) + (1 + x)*f(x)**2 - exp(x), f(x), dict=True, hint='Bernoulli') assert sorted(a.keys()) == ['Bernoulli', 'Bernoulli_Integral', 'default', 'order', 'ordered_hints'] def test_classify_ode_ics(): # Dummy eq = f(x).diff(x, x) - f(x) # Not f(0) or f'(0) ics = {x: 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) ############################ # f(0) type (AppliedUndef) # ############################ # Wrong function ics = {g(0): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Contains x ics = {f(x): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Too many args ics = {f(0, 0): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # point contains f # XXX: Should be NotImplementedError ics = {f(0): f(1)} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Does not raise ics = {f(0): 1} classify_ode(eq, f(x), ics=ics) ##################### # f'(0) type (Subs) # ##################### # Wrong function ics = {g(x).diff(x).subs(x, 0): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Contains x ics = {f(y).diff(y).subs(y, x): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Wrong variable ics = {f(y).diff(y).subs(y, 0): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Too many args ics = {f(x, y).diff(x).subs(x, 0): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Derivative wrt wrong vars ics = {Derivative(f(x), x, y).subs(x, 0): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # point contains f # XXX: Should be NotImplementedError ics = {f(x).diff(x).subs(x, 0): f(0)} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Does not raise ics = {f(x).diff(x).subs(x, 0): 1} classify_ode(eq, f(x), ics=ics) ########################### # f'(y) type (Derivative) # ########################### # Wrong function ics = {g(x).diff(x).subs(x, y): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Contains x ics = {f(y).diff(y).subs(y, x): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Too many args ics = {f(x, y).diff(x).subs(x, y): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Derivative wrt wrong vars ics = {Derivative(f(x), x, z).subs(x, y): 1} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # point contains f # XXX: Should be NotImplementedError ics = {f(x).diff(x).subs(x, y): f(0)} raises(ValueError, lambda: classify_ode(eq, f(x), ics=ics)) # Does not raise ics = {f(x).diff(x).subs(x, y): 1} classify_ode(eq, f(x), ics=ics) def test_classify_sysode(): # Here x is assumed to be x(t) and y as y(t) for simplicity. # Similarly diff(x,t) and diff(y,y) is assumed to be x1 and y1 respectively. k, l, m, n = symbols('k, l, m, n', Integer=True) k1, k2, k3, l1, l2, l3, m1, m2, m3 = symbols('k1, k2, k3, l1, l2, l3, m1, m2, m3', Integer=True) P, Q, R, p, q, r = symbols('P, Q, R, p, q, r', cls=Function) P1, P2, P3, Q1, Q2, R1, R2 = symbols('P1, P2, P3, Q1, Q2, R1, R2', cls=Function) x, y, z = symbols('x, y, z', cls=Function) t = symbols('t') x1 = diff(x(t),t) ; y1 = diff(y(t),t) ; eq6 = (Eq(x1, exp(k*x(t))*P(x(t),y(t))), Eq(y1,r(y(t))*P(x(t),y(t)))) sol6 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): 0, (1, x(t), 1): 0, (0, x(t), 1): 1, (1, y(t), 0): 0, \ (1, x(t), 0): 0, (0, y(t), 1): 0, (0, y(t), 0): 0, (1, y(t), 1): 1}, 'type_of_equation': 'type2', 'func': \ [x(t), y(t)], 'is_linear': False, 'eq': [-P(x(t), y(t))*exp(k*x(t)) + Derivative(x(t), t), -P(x(t), \ y(t))*r(y(t)) + Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} assert classify_sysode(eq6) == sol6 eq7 = (Eq(x1, x(t)**2+y(t)/x(t)), Eq(y1, x(t)/y(t))) sol7 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): 0, (1, x(t), 1): 0, (0, x(t), 1): 1, (1, y(t), 0): 0, \ (1, x(t), 0): -1/y(t), (0, y(t), 1): 0, (0, y(t), 0): -1/x(t), (1, y(t), 1): 1}, 'type_of_equation': 'type3', \ 'func': [x(t), y(t)], 'is_linear': False, 'eq': [-x(t)**2 + Derivative(x(t), t) - y(t)/x(t), -x(t)/y(t) + \ Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} assert classify_sysode(eq7) == sol7 eq8 = (Eq(x1, P1(x(t))*Q1(y(t))*R(x(t),y(t),t)), Eq(y1, P1(x(t))*Q1(y(t))*R(x(t),y(t),t))) sol8 = {'func': [x(t), y(t)], 'is_linear': False, 'type_of_equation': 'type4', 'eq': \ [-P1(x(t))*Q1(y(t))*R(x(t), y(t), t) + Derivative(x(t), t), -P1(x(t))*Q1(y(t))*R(x(t), y(t), t) + \ Derivative(y(t), t)], 'func_coeff': {(0, y(t), 1): 0, (1, y(t), 1): 1, (1, x(t), 1): 0, (0, y(t), 0): 0, \ (1, x(t), 0): 0, (0, x(t), 0): 0, (1, y(t), 0): 0, (0, x(t), 1): 1}, 'order': {y(t): 1, x(t): 1}, 'no_of_equation': 2} assert classify_sysode(eq8) == sol8 eq11 = (Eq(x1,x(t)*y(t)**3), Eq(y1,y(t)**5)) sol11 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): -y(t)**3, (1, x(t), 1): 0, (0, x(t), 1): 1, \ (1, y(t), 0): 0, (1, x(t), 0): 0, (0, y(t), 1): 0, (0, y(t), 0): 0, (1, y(t), 1): 1}, 'type_of_equation': \ 'type1', 'func': [x(t), y(t)], 'is_linear': False, 'eq': [-x(t)*y(t)**3 + Derivative(x(t), t), \ -y(t)**5 + Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} assert classify_sysode(eq11) == sol11 eq13 = (Eq(x1,x(t)*y(t)*sin(t)**2), Eq(y1,y(t)**2*sin(t)**2)) sol13 = {'no_of_equation': 2, 'func_coeff': {(0, x(t), 0): -y(t)*sin(t)**2, (1, x(t), 1): 0, (0, x(t), 1): 1, \ (1, y(t), 0): 0, (1, x(t), 0): 0, (0, y(t), 1): 0, (0, y(t), 0): -x(t)*sin(t)**2, (1, y(t), 1): 1}, \ 'type_of_equation': 'type4', 'func': [x(t), y(t)], 'is_linear': False, 'eq': [-x(t)*y(t)*sin(t)**2 + \ Derivative(x(t), t), -y(t)**2*sin(t)**2 + Derivative(y(t), t)], 'order': {y(t): 1, x(t): 1}} assert classify_sysode(eq13) == sol13 def test_solve_ics(): # Basic tests that things work from dsolve. assert dsolve(f(x).diff(x) - 1/f(x), f(x), ics={f(1): 2}) == \ Eq(f(x), sqrt(2 * x + 2)) assert dsolve(f(x).diff(x) - f(x), f(x), ics={f(0): 1}) == Eq(f(x), exp(x)) assert dsolve(f(x).diff(x) - f(x), f(x), ics={f(x).diff(x).subs(x, 0): 1}) == Eq(f(x), exp(x)) assert dsolve(f(x).diff(x, x) + f(x), f(x), ics={f(0): 1, f(x).diff(x).subs(x, 0): 1}) == Eq(f(x), sin(x) + cos(x)) assert dsolve([f(x).diff(x) - f(x) + g(x), g(x).diff(x) - g(x) - f(x)], [f(x), g(x)], ics={f(0): 1, g(0): 0}) == [Eq(f(x), exp(x)*cos(x)), Eq(g(x), exp(x)*sin(x))] # Test cases where dsolve returns two solutions. eq = (x**2*f(x)**2 - x).diff(x) assert dsolve(eq, f(x), ics={f(1): 0}) == [Eq(f(x), -sqrt(x - 1)/x), Eq(f(x), sqrt(x - 1)/x)] assert dsolve(eq, f(x), ics={f(x).diff(x).subs(x, 1): 0}) == [Eq(f(x), -sqrt(x - S.Half)/x), Eq(f(x), sqrt(x - S.Half)/x)] eq = cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x) assert dsolve(eq, f(x), ics={f(0):1}, hint='1st_exact', simplify=False) == Eq(x*cos(f(x)) + f(x)**3/3, Rational(1, 3)) assert dsolve(eq, f(x), ics={f(0):1}, hint='1st_exact', simplify=True) == Eq(x*cos(f(x)) + f(x)**3/3, Rational(1, 3)) assert solve_ics([Eq(f(x), C1*exp(x))], [f(x)], [C1], {f(0): 1}) == {C1: 1} assert solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], {f(0): 1, f(pi/2): 1}) == {C1: 1, C2: 1} assert solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], {f(0): 1, f(x).diff(x).subs(x, 0): 1}) == {C1: 1, C2: 1} assert solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], {f(0): 1}) == \ {C2: 1} # Some more complicated tests Refer to PR #16098 assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(0):0, f(x).diff(x).subs(x, 1):0})) == \ {Eq(f(x), 0), Eq(f(x), x ** 3 / 6 - x / 2)} assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(0):0})) == \ {Eq(f(x), 0), Eq(f(x), C2*x + x**3/6)} K, r, f0 = symbols('K r f0') sol = Eq(f(x), K*f0*exp(r*x)/((-K + f0)*(f0*exp(r*x)/(-K + f0) - 1))) assert (dsolve(Eq(f(x).diff(x), r * f(x) * (1 - f(x) / K)), f(x), ics={f(0): f0})) == sol #Order dependent issues Refer to PR #16098 assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(x).diff(x).subs(x,0):0, f(0):0})) == \ {Eq(f(x), 0), Eq(f(x), x ** 3 / 6)} assert set(dsolve(f(x).diff(x)*(f(x).diff(x, 2)-x), ics={f(0):0, f(x).diff(x).subs(x,0):0})) == \ {Eq(f(x), 0), Eq(f(x), x ** 3 / 6)} # XXX: Ought to be ValueError raises(ValueError, lambda: solve_ics([Eq(f(x), C1*sin(x) + C2*cos(x))], [f(x)], [C1, C2], {f(0): 1, f(pi): 1})) # Degenerate case. f'(0) is identically 0. raises(ValueError, lambda: solve_ics([Eq(f(x), sqrt(C1 - x**2))], [f(x)], [C1], {f(x).diff(x).subs(x, 0): 0})) EI, q, L = symbols('EI q L') # eq = Eq(EI*diff(f(x), x, 4), q) sols = [Eq(f(x), C1 + C2*x + C3*x**2 + C4*x**3 + q*x**4/(24*EI))] funcs = [f(x)] constants = [C1, C2, C3, C4] # Test both cases, Derivative (the default from f(x).diff(x).subs(x, L)), # and Subs ics1 = {f(0): 0, f(x).diff(x).subs(x, 0): 0, f(L).diff(L, 2): 0, f(L).diff(L, 3): 0} ics2 = {f(0): 0, f(x).diff(x).subs(x, 0): 0, Subs(f(x).diff(x, 2), x, L): 0, Subs(f(x).diff(x, 3), x, L): 0} solved_constants1 = solve_ics(sols, funcs, constants, ics1) solved_constants2 = solve_ics(sols, funcs, constants, ics2) assert solved_constants1 == solved_constants2 == { C1: 0, C2: 0, C3: L**2*q/(4*EI), C4: -L*q/(6*EI)} def test_ode_order(): f = Function('f') g = Function('g') x = Symbol('x') assert ode_order(3*x*exp(f(x)), f(x)) == 0 assert ode_order(x*diff(f(x), x) + 3*x*f(x) - sin(x)/x, f(x)) == 1 assert ode_order(x**2*f(x).diff(x, x) + x*diff(f(x), x) - f(x), f(x)) == 2 assert ode_order(diff(x*exp(f(x)), x, x), f(x)) == 2 assert ode_order(diff(x*diff(x*exp(f(x)), x, x), x), f(x)) == 3 assert ode_order(diff(f(x), x, x), g(x)) == 0 assert ode_order(diff(f(x), x, x)*diff(g(x), x), f(x)) == 2 assert ode_order(diff(f(x), x, x)*diff(g(x), x), g(x)) == 1 assert ode_order(diff(x*diff(x*exp(f(x)), x, x), x), g(x)) == 0 # issue 5835: ode_order has to also work for unevaluated derivatives # (ie, without using doit()). assert ode_order(Derivative(x*f(x), x), f(x)) == 1 assert ode_order(x*sin(Derivative(x*f(x)**2, x, x)), f(x)) == 2 assert ode_order(Derivative(x*Derivative(x*exp(f(x)), x, x), x), g(x)) == 0 assert ode_order(Derivative(f(x), x, x), g(x)) == 0 assert ode_order(Derivative(x*exp(f(x)), x, x), f(x)) == 2 assert ode_order(Derivative(f(x), x, x)*Derivative(g(x), x), g(x)) == 1 assert ode_order(Derivative(x*Derivative(f(x), x, x), x), f(x)) == 3 assert ode_order( x*sin(Derivative(x*Derivative(f(x), x)**2, x, x)), f(x)) == 3 def test_homogeneous_order(): assert homogeneous_order(exp(y/x) + tan(y/x), x, y) == 0 assert homogeneous_order(x**2 + sin(x)*cos(y), x, y) is None assert homogeneous_order(x - y - x*sin(y/x), x, y) == 1 assert homogeneous_order((x*y + sqrt(x**4 + y**4) + x**2*(log(x) - log(y)))/ (pi*x**Rational(2, 3)*sqrt(y)**3), x, y) == Rational(-1, 6) assert homogeneous_order(y/x*cos(y/x) - x/y*sin(y/x) + cos(y/x), x, y) == 0 assert homogeneous_order(f(x), x, f(x)) == 1 assert homogeneous_order(f(x)**2, x, f(x)) == 2 assert homogeneous_order(x*y*z, x, y) == 2 assert homogeneous_order(x*y*z, x, y, z) == 3 assert homogeneous_order(x**2*f(x)/sqrt(x**2 + f(x)**2), f(x)) is None assert homogeneous_order(f(x, y)**2, x, f(x, y), y) == 2 assert homogeneous_order(f(x, y)**2, x, f(x), y) is None assert homogeneous_order(f(x, y)**2, x, f(x, y)) is None assert homogeneous_order(f(y, x)**2, x, y, f(x, y)) is None assert homogeneous_order(f(y), f(x), x) is None assert homogeneous_order(-f(x)/x + 1/sin(f(x)/ x), f(x), x) == 0 assert homogeneous_order(log(1/y) + log(x**2), x, y) is None assert homogeneous_order(log(1/y) + log(x), x, y) == 0 assert homogeneous_order(log(x/y), x, y) == 0 assert homogeneous_order(2*log(1/y) + 2*log(x), x, y) == 0 a = Symbol('a') assert homogeneous_order(a*log(1/y) + a*log(x), x, y) == 0 assert homogeneous_order(f(x).diff(x), x, y) is None assert homogeneous_order(-f(x).diff(x) + x, x, y) is None assert homogeneous_order(O(x), x, y) is None assert homogeneous_order(x + O(x**2), x, y) is None assert homogeneous_order(x**pi, x) == pi assert homogeneous_order(x**x, x) is None raises(ValueError, lambda: homogeneous_order(x*y)) @XFAIL def test_noncircularized_real_imaginary_parts(): # If this passes, lines numbered 3878-3882 (at the time of this commit) # of sympy/solvers/ode.py for nth_linear_constant_coeff_homogeneous # should be removed. y = sqrt(1+x) i, r = im(y), re(y) assert not (i.has(atan2) and r.has(atan2)) def test_collect_respecting_exponentials(): # If this test passes, lines 1306-1311 (at the time of this commit) # of sympy/solvers/ode.py should be removed. sol = 1 + exp(x/2) assert sol == collect( sol, exp(x/3)) def test_undetermined_coefficients_match(): assert _undetermined_coefficients_match(g(x), x) == {'test': False} assert _undetermined_coefficients_match(sin(2*x + sqrt(5)), x) == \ {'test': True, 'trialset': {cos(2*x + sqrt(5)), sin(2*x + sqrt(5))}} assert _undetermined_coefficients_match(sin(x)*cos(x), x) == \ {'test': False} s = {cos(x), x*cos(x), x**2*cos(x), x**2*sin(x), x*sin(x), sin(x)} assert _undetermined_coefficients_match(sin(x)*(x**2 + x + 1), x) == \ {'test': True, 'trialset': s} assert _undetermined_coefficients_match( sin(x)*x**2 + sin(x)*x + sin(x), x) == {'test': True, 'trialset': s} assert _undetermined_coefficients_match( exp(2*x)*sin(x)*(x**2 + x + 1), x ) == { 'test': True, 'trialset': {exp(2*x)*sin(x), x**2*exp(2*x)*sin(x), cos(x)*exp(2*x), x**2*cos(x)*exp(2*x), x*cos(x)*exp(2*x), x*exp(2*x)*sin(x)}} assert _undetermined_coefficients_match(1/sin(x), x) == {'test': False} assert _undetermined_coefficients_match(log(x), x) == {'test': False} assert _undetermined_coefficients_match(2**(x)*(x**2 + x + 1), x) == \ {'test': True, 'trialset': {2**x, x*2**x, x**2*2**x}} assert _undetermined_coefficients_match(x**y, x) == {'test': False} assert _undetermined_coefficients_match(exp(x)*exp(2*x + 1), x) == \ {'test': True, 'trialset': {exp(1 + 3*x)}} assert _undetermined_coefficients_match(sin(x)*(x**2 + x + 1), x) == \ {'test': True, 'trialset': {x*cos(x), x*sin(x), x**2*cos(x), x**2*sin(x), cos(x), sin(x)}} assert _undetermined_coefficients_match(sin(x)*(x + sin(x)), x) == \ {'test': False} assert _undetermined_coefficients_match(sin(x)*(x + sin(2*x)), x) == \ {'test': False} assert _undetermined_coefficients_match(sin(x)*tan(x), x) == \ {'test': False} assert _undetermined_coefficients_match( x**2*sin(x)*exp(x) + x*sin(x) + x, x ) == { 'test': True, 'trialset': {x**2*cos(x)*exp(x), x, cos(x), S.One, exp(x)*sin(x), sin(x), x*exp(x)*sin(x), x*cos(x), x*cos(x)*exp(x), x*sin(x), cos(x)*exp(x), x**2*exp(x)*sin(x)}} assert _undetermined_coefficients_match(4*x*sin(x - 2), x) == { 'trialset': {x*cos(x - 2), x*sin(x - 2), cos(x - 2), sin(x - 2)}, 'test': True, } assert _undetermined_coefficients_match(2**x*x, x) == \ {'test': True, 'trialset': {2**x, x*2**x}} assert _undetermined_coefficients_match(2**x*exp(2*x), x) == \ {'test': True, 'trialset': {2**x*exp(2*x)}} assert _undetermined_coefficients_match(exp(-x)/x, x) == \ {'test': False} # Below are from Ordinary Differential Equations, # Tenenbaum and Pollard, pg. 231 assert _undetermined_coefficients_match(S(4), x) == \ {'test': True, 'trialset': {S.One}} assert _undetermined_coefficients_match(12*exp(x), x) == \ {'test': True, 'trialset': {exp(x)}} assert _undetermined_coefficients_match(exp(I*x), x) == \ {'test': True, 'trialset': {exp(I*x)}} assert _undetermined_coefficients_match(sin(x), x) == \ {'test': True, 'trialset': {cos(x), sin(x)}} assert _undetermined_coefficients_match(cos(x), x) == \ {'test': True, 'trialset': {cos(x), sin(x)}} assert _undetermined_coefficients_match(8 + 6*exp(x) + 2*sin(x), x) == \ {'test': True, 'trialset': {S.One, cos(x), sin(x), exp(x)}} assert _undetermined_coefficients_match(x**2, x) == \ {'test': True, 'trialset': {S.One, x, x**2}} assert _undetermined_coefficients_match(9*x*exp(x) + exp(-x), x) == \ {'test': True, 'trialset': {x*exp(x), exp(x), exp(-x)}} assert _undetermined_coefficients_match(2*exp(2*x)*sin(x), x) == \ {'test': True, 'trialset': {exp(2*x)*sin(x), cos(x)*exp(2*x)}} assert _undetermined_coefficients_match(x - sin(x), x) == \ {'test': True, 'trialset': {S.One, x, cos(x), sin(x)}} assert _undetermined_coefficients_match(x**2 + 2*x, x) == \ {'test': True, 'trialset': {S.One, x, x**2}} assert _undetermined_coefficients_match(4*x*sin(x), x) == \ {'test': True, 'trialset': {x*cos(x), x*sin(x), cos(x), sin(x)}} assert _undetermined_coefficients_match(x*sin(2*x), x) == \ {'test': True, 'trialset': {x*cos(2*x), x*sin(2*x), cos(2*x), sin(2*x)}} assert _undetermined_coefficients_match(x**2*exp(-x), x) == \ {'test': True, 'trialset': {x*exp(-x), x**2*exp(-x), exp(-x)}} assert _undetermined_coefficients_match(2*exp(-x) - x**2*exp(-x), x) == \ {'test': True, 'trialset': {x*exp(-x), x**2*exp(-x), exp(-x)}} assert _undetermined_coefficients_match(exp(-2*x) + x**2, x) == \ {'test': True, 'trialset': {S.One, x, x**2, exp(-2*x)}} assert _undetermined_coefficients_match(x*exp(-x), x) == \ {'test': True, 'trialset': {x*exp(-x), exp(-x)}} assert _undetermined_coefficients_match(x + exp(2*x), x) == \ {'test': True, 'trialset': {S.One, x, exp(2*x)}} assert _undetermined_coefficients_match(sin(x) + exp(-x), x) == \ {'test': True, 'trialset': {cos(x), sin(x), exp(-x)}} assert _undetermined_coefficients_match(exp(x), x) == \ {'test': True, 'trialset': {exp(x)}} # converted from sin(x)**2 assert _undetermined_coefficients_match(S.Half - cos(2*x)/2, x) == \ {'test': True, 'trialset': {S.One, cos(2*x), sin(2*x)}} # converted from exp(2*x)*sin(x)**2 assert _undetermined_coefficients_match( exp(2*x)*(S.Half + cos(2*x)/2), x ) == { 'test': True, 'trialset': {exp(2*x)*sin(2*x), cos(2*x)*exp(2*x), exp(2*x)}} assert _undetermined_coefficients_match(2*x + sin(x) + cos(x), x) == \ {'test': True, 'trialset': {S.One, x, cos(x), sin(x)}} # converted from sin(2*x)*sin(x) assert _undetermined_coefficients_match(cos(x)/2 - cos(3*x)/2, x) == \ {'test': True, 'trialset': {cos(x), cos(3*x), sin(x), sin(3*x)}} assert _undetermined_coefficients_match(cos(x**2), x) == {'test': False} assert _undetermined_coefficients_match(2**(x**2), x) == {'test': False} def test_issue_4785(): from sympy.abc import A eq = x + A*(x + diff(f(x), x) + f(x)) + diff(f(x), x) + f(x) + 2 assert classify_ode(eq, f(x)) == ('1st_exact', '1st_linear', 'almost_linear', '1st_power_series', 'lie_group', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', '1st_exact_Integral', '1st_linear_Integral', 'almost_linear_Integral', 'nth_linear_constant_coeff_variation_of_parameters_Integral') # issue 4864 eq = (x**2 + f(x)**2)*f(x).diff(x) - 2*x*f(x) assert classify_ode(eq, f(x)) == ('1st_exact', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', '1st_power_series', 'lie_group', '1st_exact_Integral', '1st_homogeneous_coeff_subs_indep_div_dep_Integral', '1st_homogeneous_coeff_subs_dep_div_indep_Integral') def test_issue_4825(): raises(ValueError, lambda: dsolve(f(x, y).diff(x) - y*f(x, y), f(x))) assert classify_ode(f(x, y).diff(x) - y*f(x, y), f(x), dict=True) == \ {'order': 0, 'default': None, 'ordered_hints': ()} # See also issue 3793, test Z13. raises(ValueError, lambda: dsolve(f(x).diff(x), f(y))) assert classify_ode(f(x).diff(x), f(y), dict=True) == \ {'order': 0, 'default': None, 'ordered_hints': ()} def test_constant_renumber_order_issue_5308(): from sympy.utilities.iterables import variations assert constant_renumber(C1*x + C2*y) == \ constant_renumber(C1*y + C2*x) == \ C1*x + C2*y e = C1*(C2 + x)*(C3 + y) for a, b, c in variations([C1, C2, C3], 3): assert constant_renumber(a*(b + x)*(c + y)) == e def test_constant_renumber(): e1, e2, x, y = symbols("e1:3 x y") exprs = [e2*x, e1*x + e2*y] assert constant_renumber(exprs[0]) == e2*x assert constant_renumber(exprs[0], variables=[x]) == C1*x assert constant_renumber(exprs[0], variables=[x], newconstants=[C2]) == C2*x assert constant_renumber(exprs, variables=[x, y]) == [C1*x, C1*y + C2*x] assert constant_renumber(exprs, variables=[x, y], newconstants=symbols("C3:5")) == [C3*x, C3*y + C4*x] def test_issue_5770(): k = Symbol("k", real=True) t = Symbol('t') w = Function('w') sol = dsolve(w(t).diff(t, 6) - k**6*w(t), w(t)) assert len([s for s in sol.free_symbols if s.name.startswith('C')]) == 6 assert constantsimp((C1*cos(x) + C2*cos(x))*exp(x), {C1, C2}) == \ C1*cos(x)*exp(x) assert constantsimp(C1*cos(x) + C2*cos(x) + C3*sin(x), {C1, C2, C3}) == \ C1*cos(x) + C3*sin(x) assert constantsimp(exp(C1 + x), {C1}) == C1*exp(x) assert constantsimp(x + C1 + y, {C1, y}) == C1 + x assert constantsimp(x + C1 + Integral(x, (x, 1, 2)), {C1}) == C1 + x def test_issue_5112_5430(): assert homogeneous_order(-log(x) + acosh(x), x) is None assert homogeneous_order(y - log(x), x, y) is None def test_issue_5095(): f = Function('f') raises(ValueError, lambda: dsolve(f(x).diff(x)**2, f(x), 'fdsjf')) def test_homogeneous_function(): f = Function('f') eq1 = tan(x + f(x)) eq2 = sin((3*x)/(4*f(x))) eq3 = cos(x*f(x)*Rational(3, 4)) eq4 = log((3*x + 4*f(x))/(5*f(x) + 7*x)) eq5 = exp((2*x**2)/(3*f(x)**2)) eq6 = log((3*x + 4*f(x))/(5*f(x) + 7*x) + exp((2*x**2)/(3*f(x)**2))) eq7 = sin((3*x)/(5*f(x) + x**2)) assert homogeneous_order(eq1, x, f(x)) == None assert homogeneous_order(eq2, x, f(x)) == 0 assert homogeneous_order(eq3, x, f(x)) == None assert homogeneous_order(eq4, x, f(x)) == 0 assert homogeneous_order(eq5, x, f(x)) == 0 assert homogeneous_order(eq6, x, f(x)) == 0 assert homogeneous_order(eq7, x, f(x)) == None def test_linear_coeff_match(): n, d = z*(2*x + 3*f(x) + 5), z*(7*x + 9*f(x) + 11) rat = n/d eq1 = sin(rat) + cos(rat.expand()) obj1 = LinearCoefficients(eq1) eq2 = rat obj2 = LinearCoefficients(eq2) eq3 = log(sin(rat)) obj3 = LinearCoefficients(eq3) ans = (4, Rational(-13, 3)) assert obj1._linear_coeff_match(eq1, f(x)) == ans assert obj2._linear_coeff_match(eq2, f(x)) == ans assert obj3._linear_coeff_match(eq3, f(x)) == ans # no c eq4 = (3*x)/f(x) obj4 = LinearCoefficients(eq4) # not x and f(x) eq5 = (3*x + 2)/x obj5 = LinearCoefficients(eq5) # denom will be zero eq6 = (3*x + 2*f(x) + 1)/(3*x + 2*f(x) + 5) obj6 = LinearCoefficients(eq6) # not rational coefficient eq7 = (3*x + 2*f(x) + sqrt(2))/(3*x + 2*f(x) + 5) obj7 = LinearCoefficients(eq7) assert obj4._linear_coeff_match(eq4, f(x)) is None assert obj5._linear_coeff_match(eq5, f(x)) is None assert obj6._linear_coeff_match(eq6, f(x)) is None assert obj7._linear_coeff_match(eq7, f(x)) is None def test_constantsimp_take_problem(): c = exp(C1) + 2 assert len(Poly(constantsimp(exp(C1) + c + c*x, [C1])).gens) == 2 def test_series(): C1 = Symbol("C1") eq = f(x).diff(x) - f(x) sol = Eq(f(x), C1 + C1*x + C1*x**2/2 + C1*x**3/6 + C1*x**4/24 + C1*x**5/120 + O(x**6)) assert dsolve(eq, hint='1st_power_series') == sol assert checkodesol(eq, sol, order=1)[0] eq = f(x).diff(x) - x*f(x) sol = Eq(f(x), C1*x**4/8 + C1*x**2/2 + C1 + O(x**6)) assert dsolve(eq, hint='1st_power_series') == sol assert checkodesol(eq, sol, order=1)[0] eq = f(x).diff(x) - sin(x*f(x)) sol = Eq(f(x), (x - 2)**2*(1+ sin(4))*cos(4) + (x - 2)*sin(4) + 2 + O(x**3)) assert dsolve(eq, hint='1st_power_series', ics={f(2): 2}, n=3) == sol # FIXME: The solution here should be O((x-2)**3) so is incorrect #assert checkodesol(eq, sol, order=1)[0] @slow def test_2nd_power_series_ordinary(): C1, C2 = symbols("C1 C2") eq = f(x).diff(x, 2) - x*f(x) assert classify_ode(eq) == ('2nd_linear_airy', '2nd_power_series_ordinary') sol = Eq(f(x), C2*(x**3/6 + 1) + C1*x*(x**3/12 + 1) + O(x**6)) assert dsolve(eq, hint='2nd_power_series_ordinary') == sol assert checkodesol(eq, sol) == (True, 0) sol = Eq(f(x), C2*((x + 2)**4/6 + (x + 2)**3/6 - (x + 2)**2 + 1) + C1*(x + (x + 2)**4/12 - (x + 2)**3/3 + S(2)) + O(x**6)) assert dsolve(eq, hint='2nd_power_series_ordinary', x0=-2) == sol # FIXME: Solution should be O((x+2)**6) # assert checkodesol(eq, sol) == (True, 0) sol = Eq(f(x), C2*x + C1 + O(x**2)) assert dsolve(eq, hint='2nd_power_series_ordinary', n=2) == sol assert checkodesol(eq, sol) == (True, 0) eq = (1 + x**2)*(f(x).diff(x, 2)) + 2*x*(f(x).diff(x)) -2*f(x) assert classify_ode(eq) == ('2nd_hypergeometric', '2nd_hypergeometric_Integral', '2nd_power_series_ordinary') sol = Eq(f(x), C2*(-x**4/3 + x**2 + 1) + C1*x + O(x**6)) assert dsolve(eq, hint='2nd_power_series_ordinary') == sol assert checkodesol(eq, sol) == (True, 0) eq = f(x).diff(x, 2) + x*(f(x).diff(x)) + f(x) assert classify_ode(eq) == ('2nd_power_series_ordinary',) sol = Eq(f(x), C2*(x**4/8 - x**2/2 + 1) + C1*x*(-x**2/3 + 1) + O(x**6)) assert dsolve(eq) == sol # FIXME: checkodesol fails for this solution... # assert checkodesol(eq, sol) == (True, 0) eq = f(x).diff(x, 2) + f(x).diff(x) - x*f(x) assert classify_ode(eq) == ('2nd_power_series_ordinary',) sol = Eq(f(x), C2*(-x**4/24 + x**3/6 + 1) + C1*x*(x**3/24 + x**2/6 - x/2 + 1) + O(x**6)) assert dsolve(eq) == sol # FIXME: checkodesol fails for this solution... # assert checkodesol(eq, sol) == (True, 0) eq = f(x).diff(x, 2) + x*f(x) assert classify_ode(eq) == ('2nd_linear_airy', '2nd_power_series_ordinary') sol = Eq(f(x), C2*(x**6/180 - x**3/6 + 1) + C1*x*(-x**3/12 + 1) + O(x**7)) assert dsolve(eq, hint='2nd_power_series_ordinary', n=7) == sol assert checkodesol(eq, sol) == (True, 0) def test_2nd_power_series_regular(): C1, C2, a = symbols("C1 C2 a") eq = x**2*(f(x).diff(x, 2)) - 3*x*(f(x).diff(x)) + (4*x + 4)*f(x) sol = Eq(f(x), C1*x**2*(-16*x**3/9 + 4*x**2 - 4*x + 1) + O(x**6)) assert dsolve(eq, hint='2nd_power_series_regular') == sol assert checkodesol(eq, sol) == (True, 0) eq = 4*x**2*(f(x).diff(x, 2)) -8*x**2*(f(x).diff(x)) + (4*x**2 + 1)*f(x) sol = Eq(f(x), C1*sqrt(x)*(x**4/24 + x**3/6 + x**2/2 + x + 1) + O(x**6)) assert dsolve(eq, hint='2nd_power_series_regular') == sol assert checkodesol(eq, sol) == (True, 0) eq = x**2*(f(x).diff(x, 2)) - x**2*(f(x).diff(x)) + ( x**2 - 2)*f(x) sol = Eq(f(x), C1*(-x**6/720 - 3*x**5/80 - x**4/8 + x**2/2 + x/2 + 1)/x + C2*x**2*(-x**3/60 + x**2/20 + x/2 + 1) + O(x**6)) assert dsolve(eq) == sol assert checkodesol(eq, sol) == (True, 0) eq = x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 - Rational(1, 4))*f(x) sol = Eq(f(x), C1*(x**4/24 - x**2/2 + 1)/sqrt(x) + C2*sqrt(x)*(x**4/120 - x**2/6 + 1) + O(x**6)) assert dsolve(eq, hint='2nd_power_series_regular') == sol assert checkodesol(eq, sol) == (True, 0) eq = x*f(x).diff(x, 2) + f(x).diff(x) - a*x*f(x) sol = Eq(f(x), C1*(a**2*x**4/64 + a*x**2/4 + 1) + O(x**6)) assert dsolve(eq, f(x), hint="2nd_power_series_regular") == sol assert checkodesol(eq, sol) == (True, 0) eq = f(x).diff(x, 2) + ((1 - x)/x)*f(x).diff(x) + (a/x)*f(x) sol = Eq(f(x), C1*(-a*x**5*(a - 4)*(a - 3)*(a - 2)*(a - 1)/14400 + \ a*x**4*(a - 3)*(a - 2)*(a - 1)/576 - a*x**3*(a - 2)*(a - 1)/36 + \ a*x**2*(a - 1)/4 - a*x + 1) + O(x**6)) assert dsolve(eq, f(x), hint="2nd_power_series_regular") == sol assert checkodesol(eq, sol) == (True, 0) def test_issue_15056(): t = Symbol('t') C3 = Symbol('C3') assert get_numbered_constants(Symbol('C1') * Function('C2')(t)) == C3 def test_issue_15913(): eq = -C1/x - 2*x*f(x) - f(x) + Derivative(f(x), x) sol = C2*exp(x**2 + x) + exp(x**2 + x)*Integral(C1*exp(-x**2 - x)/x, x) assert checkodesol(eq, sol) == (True, 0) sol = C1 + C2*exp(-x*y) eq = Derivative(y*f(x), x) + f(x).diff(x, 2) assert checkodesol(eq, sol, f(x)) == (True, 0) def test_issue_16146(): raises(ValueError, lambda: dsolve([f(x).diff(x), g(x).diff(x)], [f(x), g(x), h(x)])) raises(ValueError, lambda: dsolve([f(x).diff(x), g(x).diff(x)], [f(x)])) def test_dsolve_remove_redundant_solutions(): eq = (f(x)-2)*f(x).diff(x) sol = Eq(f(x), C1) assert dsolve(eq) == sol eq = (f(x)-sin(x))*(f(x).diff(x, 2)) sol = {Eq(f(x), C1 + C2*x), Eq(f(x), sin(x))} assert set(dsolve(eq)) == sol eq = (f(x)**2-2*f(x)+1)*f(x).diff(x, 3) sol = Eq(f(x), C1 + C2*x + C3*x**2) assert dsolve(eq) == sol def test_issue_13060(): A, B = symbols("A B", cls=Function) t = Symbol("t") eq = [Eq(Derivative(A(t), t), A(t)*B(t)), Eq(Derivative(B(t), t), A(t)*B(t))] sol = dsolve(eq) assert checkodesol(eq, sol) == (True, [0, 0]) sympy-sympy-1.9/sympy/solvers/ode/tests/test_riccati.py000066400000000000000000000703021412543434000235430ustar00rootroot00000000000000from random import randint from sympy import (S, symbols, Function, Rational, Poly, Eq, ratsimp, checkodesol, sqrt, Dummy, oo, I, Mul, sin, exp, log, tanh) from sympy.testing.pytest import slow from sympy.solvers.ode.riccati import (riccati_normal, riccati_inverse_normal, riccati_reduced, match_riccati, inverse_transform_poly, limit_at_inf, check_necessary_conds, val_at_inf, construct_c_case_1, construct_c_case_2, construct_c_case_3, construct_d_case_4, construct_d_case_5, construct_d_case_6, rational_laurent_series, solve_riccati) f = Function('f') x = symbols('x') # These are the functions used to generate the tests # SHOULD NOT BE USED DIRECTLY IN TESTS def rand_rational(maxint): return Rational(randint(-maxint, maxint), randint(1, maxint)) def rand_poly(x, degree, maxint): return Poly([rand_rational(maxint) for _ in range(degree+1)], x) def rand_rational_function(x, degree, maxint): degnum = randint(1, degree) degden = randint(1, degree) num = rand_poly(x, degnum, maxint) den = rand_poly(x, degden, maxint) while den == Poly(0, x): den = rand_poly(x, degden, maxint) return num / den def find_riccati_ode(ratfunc, x, yf): y = ratfunc yp = y.diff(x) q1 = rand_rational_function(x, 1, 3) q2 = rand_rational_function(x, 1, 3) while q2 == 0: q2 = rand_rational_function(x, 1, 3) q0 = ratsimp(yp - q1*y - q2*y**2) eq = Eq(yf.diff(), q0 + q1*yf + q2*yf**2) sol = Eq(yf, y) assert checkodesol(eq, sol) == (True, 0) return eq, q0, q1, q2 # Testing functions start def test_riccati_transformation(): """ This function tests the transformation of the solution of a Riccati ODE to the solution of its corresponding normal Riccati ODE. Each test case 4 values - 1. w - The solution to be transformed 2. b1 - The coefficient of f(x) in the ODE. 3. b2 - The coefficient of f(x)**2 in the ODE. 4. y - The solution to the normal Riccati ODE. """ tests = [ ( x/(x - 1), (x**2 + 7)/3*x, x, -x**2/(x - 1) - x*(x**2/3 + S(7)/3)/2 - 1/(2*x) ), ( (2*x + 3)/(2*x + 2), (3 - 3*x)/(x + 1), 5*x, -5*x*(2*x + 3)/(2*x + 2) - (3 - 3*x)/(Mul(2, x + 1, evaluate=False)) - 1/(2*x) ), ( -1/(2*x**2 - 1), 0, (2 - x)/(4*x - 2), (2 - x)/((4*x - 2)*(2*x**2 - 1)) - (4*x - 2)*(Mul(-4, 2 - x, evaluate=False)/(4*x - \ 2)**2 - 1/(4*x - 2))/(Mul(2, 2 - x, evaluate=False)) ), ( x, (8*x - 12)/(12*x + 9), x**3/(6*x - 9), -x**4/(6*x - 9) - (8*x - 12)/(Mul(2, 12*x + 9, evaluate=False)) - (6*x - 9)*(-6*x**3/(6*x \ - 9)**2 + 3*x**2/(6*x - 9))/(2*x**3) )] for w, b1, b2, y in tests: assert y == riccati_normal(w, x, b1, b2) assert w == riccati_inverse_normal(y, x, b1, b2).cancel() # Test bp parameter in riccati_inverse_normal tests = [ ( (-2*x - 1)/(2*x**2 + 2*x - 2), -2/x, (-x - 1)/(4*x), 8*x**2*(1/(4*x) + (-x - 1)/(4*x**2))/(-x - 1)**2 + 4/(-x - 1), -2*x*(-1/(4*x) - (-x - 1)/(4*x**2))/(-x - 1) - (-2*x - 1)*(-x - 1)/(4*x*(2*x**2 + 2*x \ - 2)) + 1/x ), ( 3/(2*x**2), -2/x, (-x - 1)/(4*x), 8*x**2*(1/(4*x) + (-x - 1)/(4*x**2))/(-x - 1)**2 + 4/(-x - 1), -2*x*(-1/(4*x) - (-x - 1)/(4*x**2))/(-x - 1) + 1/x - Mul(3, -x - 1, evaluate=False)/(8*x**3) )] for w, b1, b2, bp, y in tests: assert y == riccati_normal(w, x, b1, b2) assert w == riccati_inverse_normal(y, x, b1, b2, bp).cancel() def test_riccati_reduced(): """ This function tests the transformation of a Riccati ODE to its normal Riccati ODE. Each test case 2 values - 1. eq - A Riccati ODE. 2. normal_eq - The normal Riccati ODE of eq. """ tests = [ ( f(x).diff(x) - x**2 - x*f(x) - x*f(x)**2, f(x).diff(x) + f(x)**2 + x**3 - x**2/4 - 3/(4*x**2) ), ( 6*x/(2*x + 9) + f(x).diff(x) - (x + 1)*f(x)**2/x, -3*x**2*(1/x + (-x - 1)/x**2)**2/(4*(-x - 1)**2) + Mul(6, \ -x - 1, evaluate=False)/(2*x + 9) + f(x)**2 + f(x).diff(x) \ - (-1 + (x + 1)/x)/(x*(-x - 1)) ), ( f(x)**2 + f(x).diff(x) - (x - 1)*f(x)/(-x - S(1)/2), -(2*x - 2)**2/(4*(2*x + 1)**2) + (2*x - 2)/(2*x + 1)**2 + \ f(x)**2 + f(x).diff(x) - 1/(2*x + 1) ), ( f(x).diff(x) - f(x)**2/x, f(x)**2 + f(x).diff(x) + 1/(4*x**2) ), ( -3*(-x**2 - x + 1)/(x**2 + 6*x + 1) + f(x).diff(x) + f(x)**2/x, f(x)**2 + f(x).diff(x) + (3*x**2/(x**2 + 6*x + 1) + 3*x/(x**2 \ + 6*x + 1) - 3/(x**2 + 6*x + 1))/x + 1/(4*x**2) ), ( 6*x/(2*x + 9) + f(x).diff(x) - (x + 1)*f(x)/x, False ), ( f(x)*f(x).diff(x) - 1/x + f(x)/3 + f(x)**2/(x**2 - 2), False )] for eq, normal_eq in tests: assert normal_eq == riccati_reduced(eq, f, x) def test_match_riccati(): """ This function tests if an ODE is Riccati or not. Each test case has 5 values - 1. eq - The Riccati ODE. 2. match - Boolean indicating if eq is a Riccati ODE. 3. b0 - 4. b1 - Coefficient of f(x) in eq. 5. b2 - Coefficient of f(x)**2 in eq. """ tests = [ # Test Rational Riccati ODEs ( f(x).diff(x) - (405*x**3 - 882*x**2 - 78*x + 92)/(243*x**4 \ - 945*x**3 + 846*x**2 + 180*x - 72) - 2 - f(x)**2/(3*x + 1) \ - (S(1)/3 - x)*f(x)/(S(1)/3 - 3*x/2), True, 45*x**3/(27*x**4 - 105*x**3 + 94*x**2 + 20*x - 8) - 98*x**2/ \ (27*x**4 - 105*x**3 + 94*x**2 + 20*x - 8) - 26*x/(81*x**4 - \ 315*x**3 + 282*x**2 + 60*x - 24) + 2 + 92/(243*x**4 - 945*x**3 \ + 846*x**2 + 180*x - 72), Mul(-1, 2 - 6*x, evaluate=False)/(9*x - 2), 1/(3*x + 1) ), ( f(x).diff(x) + 4*x/27 - (x/3 - 1)*f(x)**2 - (2*x/3 + \ 1)*f(x)/(3*x + 2) - S(10)/27 - (265*x**2 + 423*x + 162) \ /(324*x**3 + 216*x**2), True, -4*x/27 + S(10)/27 + 3/(6*x**3 + 4*x**2) + 47/(36*x**2 \ + 24*x) + 265/(324*x + 216), Mul(-1, -2*x - 3, evaluate=False)/(9*x + 6), x/3 - 1 ), ( f(x).diff(x) - (304*x**5 - 745*x**4 + 631*x**3 - 876*x**2 \ + 198*x - 108)/(36*x**6 - 216*x**5 + 477*x**4 - 567*x**3 + \ 360*x**2 - 108*x) - S(17)/9 - (x - S(3)/2)*f(x)/(x/2 - \ S(3)/2) - (x/3 - 3)*f(x)**2/(3*x), True, 304*x**4/(36*x**5 - 216*x**4 + 477*x**3 - 567*x**2 + 360*x - \ 108) - 745*x**3/(36*x**5 - 216*x**4 + 477*x**3 - 567*x**2 + \ 360*x - 108) + 631*x**2/(36*x**5 - 216*x**4 + 477*x**3 - 567* \ x**2 + 360*x - 108) - 292*x/(12*x**5 - 72*x**4 + 159*x**3 - \ 189*x**2 + 120*x - 36) + S(17)/9 - 12/(4*x**6 - 24*x**5 + \ 53*x**4 - 63*x**3 + 40*x**2 - 12*x) + 22/(4*x**5 - 24*x**4 \ + 53*x**3 - 63*x**2 + 40*x - 12), Mul(-1, 3 - 2*x, evaluate=False)/(x - 3), Mul(-1, 9 - x, evaluate=False)/(9*x) ), # Test Non-Rational Riccati ODEs ( f(x).diff(x) - x**(S(3)/2)/(x**(S(1)/2) - 2) + x**2*f(x) + \ x*f(x)**2/(x**(S(3)/4)), False, 0, 0, 0 ), ( f(x).diff(x) - sin(x**2) + exp(x)*f(x) + log(x)*f(x)**2, False, 0, 0, 0 ), ( f(x).diff(x) - tanh(x + sqrt(x)) + f(x) + x**4*f(x)**2, False, 0, 0, 0 ), # Test Non-Riccati ODEs ( (1 - x**2)*f(x).diff(x, 2) - 2*x*f(x).diff(x) + 20*f(x), False, 0, 0, 0 ), ( f(x).diff(x) - x**2 + x**3*f(x) + (x**2/(x + 1))*f(x)**3, False, 0, 0, 0 ), ( f(x).diff(x)*f(x)**2 + (x**2 - 1)/(x**3 + 1)*f(x) + 1/(2*x \ + 3) + f(x)**2, False, 0, 0, 0 )] for eq, res, b0, b1, b2 in tests: match, funcs = match_riccati(eq, f, x) assert match == res if res: assert [b0, b1, b2] == funcs def test_val_at_inf(): """ This function tests the valuation of rational function at oo. Each test case has 3 values - 1. num - Numerator of rational function. 2. den - Denominator of rational function. 3. val_inf - Valuation of rational function at oo """ tests = [ # degree(denom) > degree(numer) ( Poly(10*x**3 + 8*x**2 - 13*x + 6, x), Poly(-13*x**10 - x**9 + 5*x**8 + 7*x**7 + 10*x**6 + 6*x**5 - 7*x**4 + 11*x**3 - 8*x**2 + 5*x + 13, x), 7 ), ( Poly(1, x), Poly(-9*x**4 + 3*x**3 + 15*x**2 - 6*x - 14, x), 4 ), # degree(denom) == degree(numer) ( Poly(-6*x**3 - 8*x**2 + 8*x - 6, x), Poly(-5*x**3 + 12*x**2 - 6*x - 9, x), 0 ), # degree(denom) < degree(numer) ( Poly(12*x**8 - 12*x**7 - 11*x**6 + 8*x**5 + 3*x**4 - x**3 + x**2 - 11*x, x), Poly(-14*x**2 + x, x), -6 ), ( Poly(5*x**6 + 9*x**5 - 11*x**4 - 9*x**3 + x**2 - 4*x + 4, x), Poly(15*x**4 + 3*x**3 - 8*x**2 + 15*x + 12, x), -2 )] for num, den, val in tests: assert val_at_inf(num, den, x) == val def test_necessary_conds(): """ This function tests the necessary conditions for a Riccati ODE to have a rational particular solution. """ # Valuation at Infinity is an odd negative integer assert check_necessary_conds(-3, [1, 2, 4]) == False # Valuation at Infinity is a positive integer lesser than 2 assert check_necessary_conds(1, [1, 2, 4]) == False # Multiplicity of a pole is an odd integer greater than 1 assert check_necessary_conds(2, [3, 1, 6]) == False # All values are correct assert check_necessary_conds(-10, [1, 2, 8, 12]) == True def test_inverse_transform_poly(): """ This function tests the substitution x -> 1/x in rational functions represented using Poly. """ fns = [ (15*x**3 - 8*x**2 - 2*x - 6)/(18*x + 6), (180*x**5 + 40*x**4 + 80*x**3 + 30*x**2 - 60*x - 80)/(180*x**3 - 150*x**2 + 75*x + 12), (-15*x**5 - 36*x**4 + 75*x**3 - 60*x**2 - 80*x - 60)/(80*x**4 + 60*x**3 + 60*x**2 + 60*x - 80), (60*x**7 + 24*x**6 - 15*x**5 - 20*x**4 + 30*x**2 + 100*x - 60)/(240*x**2 - 20*x - 30), (30*x**6 - 12*x**5 + 15*x**4 - 15*x**2 + 10*x + 60)/(3*x**10 - 45*x**9 + 15*x**5 + 15*x**4 - 5*x**3 \ + 15*x**2 + 45*x - 15) ] for f in fns: num, den = [Poly(e, x) for e in f.as_numer_denom()] num, den = inverse_transform_poly(num, den, x) assert f.subs(x, 1/x).cancel() == num/den def test_limit_at_inf(): """ This function tests the limit at oo of a rational function. Each test case has 3 values - 1. num - Numerator of rational function. 2. den - Denominator of rational function. 3. limit_at_inf - Limit of rational function at oo """ tests = [ # deg(denom) > deg(numer) ( Poly(-12*x**2 + 20*x + 32, x), Poly(32*x**3 + 72*x**2 + 3*x - 32, x), 0 ), # deg(denom) < deg(numer) ( Poly(1260*x**4 - 1260*x**3 - 700*x**2 - 1260*x + 1400, x), Poly(6300*x**3 - 1575*x**2 + 756*x - 540, x), oo ), # deg(denom) < deg(numer), one of the leading coefficients is negative ( Poly(-735*x**8 - 1400*x**7 + 1680*x**6 - 315*x**5 - 600*x**4 + 840*x**3 - 525*x**2 \ + 630*x + 3780, x), Poly(1008*x**7 - 2940*x**6 - 84*x**5 + 2940*x**4 - 420*x**3 + 1512*x**2 + 105*x + 168, x), -oo ), # deg(denom) == deg(numer) ( Poly(105*x**7 - 960*x**6 + 60*x**5 + 60*x**4 - 80*x**3 + 45*x**2 + 120*x + 15, x), Poly(735*x**7 + 525*x**6 + 720*x**5 + 720*x**4 - 8400*x**3 - 2520*x**2 + 2800*x + 280, x), S(1)/7 ), ( Poly(288*x**4 - 450*x**3 + 280*x**2 - 900*x - 90, x), Poly(607*x**4 + 840*x**3 - 1050*x**2 + 420*x + 420, x), S(288)/607 )] for num, den, lim in tests: assert limit_at_inf(num, den, x) == lim def test_construct_c_case_1(): """ This function tests the Case 1 in the step to calculate coefficients of c-vectors. Each test case has 4 values - 1. num - Numerator of the rational function a(x). 2. den - Denominator of the rational function a(x). 3. pole - Pole of a(x) for which c-vector is being calculated. 4. c - The c-vector for the pole. """ tests = [ ( Poly(-3*x**3 + 3*x**2 + 4*x - 5, x, extension=True), Poly(4*x**8 + 16*x**7 + 9*x**5 + 12*x**4 + 6*x**3 + 12*x**2, x, extension=True), S(0), [[S(1)/2 + sqrt(6)*I/6], [S(1)/2 - sqrt(6)*I/6]] ), ( Poly(1200*x**3 + 1440*x**2 + 816*x + 560, x, extension=True), Poly(128*x**5 - 656*x**4 + 1264*x**3 - 1125*x**2 + 385*x + 49, x, extension=True), S(7)/4, [[S(1)/2 + sqrt(16367978)/634], [S(1)/2 - sqrt(16367978)/634]] ), ( Poly(4*x + 2, x, extension=True), Poly(18*x**4 + (2 - 18*sqrt(3))*x**3 + (14 - 11*sqrt(3))*x**2 + (4 - 6*sqrt(3))*x \ + 8*sqrt(3) + 16, x, domain='QQ'), (S(1) + sqrt(3))/2, [[S(1)/2 + sqrt(Mul(4, 2*sqrt(3) + 4, evaluate=False)/(19*sqrt(3) + 44) + 1)/2], \ [S(1)/2 - sqrt(Mul(4, 2*sqrt(3) + 4, evaluate=False)/(19*sqrt(3) + 44) + 1)/2]] )] for num, den, pole, c in tests: assert construct_c_case_1(num, den, x, pole) == c def test_construct_c_case_2(): """ This function tests the Case 2 in the step to calculate coefficients of c-vectors. Each test case has 5 values - 1. num - Numerator of the rational function a(x). 2. den - Denominator of the rational function a(x). 3. pole - Pole of a(x) for which c-vector is being calculated. 4. mul - The multiplicity of the pole. 5. c - The c-vector for the pole. """ tests = [ # Testing poles with multiplicity 2 ( Poly(1, x, extension=True), Poly((x - 1)**2*(x - 2), x, extension=True), 1, 2, [[-I*(-1 - I)/2], [I*(-1 + I)/2]] ), ( Poly(3*x**5 - 12*x**4 - 7*x**3 + 1, x, extension=True), Poly((3*x - 1)**2*(x + 2)**2, x, extension=True), S(1)/3, 2, [[-S(89)/98], [-S(9)/98]] ), # Testing poles with multiplicity 4 ( Poly(x**3 - x**2 + 4*x, x, extension=True), Poly((x - 2)**4*(x + 5)**2, x, extension=True), 2, 4, [[7*sqrt(3)*(S(60)/343 - 4*sqrt(3)/7)/12, 2*sqrt(3)/7], \ [-7*sqrt(3)*(S(60)/343 + 4*sqrt(3)/7)/12, -2*sqrt(3)/7]] ), ( Poly(3*x**5 + x**4 + 3, x, extension=True), Poly((4*x + 1)**4*(x + 2), x, extension=True), -S(1)/4, 4, [[128*sqrt(439)*(-sqrt(439)/128 - S(55)/14336)/439, sqrt(439)/256], \ [-128*sqrt(439)*(sqrt(439)/128 - S(55)/14336)/439, -sqrt(439)/256]] ), # Testing poles with multiplicity 6 ( Poly(x**3 + 2, x, extension=True), Poly((3*x - 1)**6*(x**2 + 1), x, extension=True), S(1)/3, 6, [[27*sqrt(66)*(-sqrt(66)/54 - S(131)/267300)/22, -2*sqrt(66)/1485, sqrt(66)/162], \ [-27*sqrt(66)*(sqrt(66)/54 - S(131)/267300)/22, 2*sqrt(66)/1485, -sqrt(66)/162]] ), ( Poly(x**2 + 12, x, extension=True), Poly((x - sqrt(2))**6, x, extension=True), sqrt(2), 6, [[sqrt(14)*(S(6)/7 - 3*sqrt(14))/28, sqrt(7)/7, sqrt(14)], \ [-sqrt(14)*(S(6)/7 + 3*sqrt(14))/28, -sqrt(7)/7, -sqrt(14)]] )] for num, den, pole, mul, c in tests: assert construct_c_case_2(num, den, x, pole, mul) == c def test_construct_c_case_3(): """ This function tests the Case 3 in the step to calculate coefficients of c-vectors. """ assert construct_c_case_3() == [[1]] def test_construct_d_case_4(): """ This function tests the Case 4 in the step to calculate coefficients of the d-vector. Each test case has 4 values - 1. num - Numerator of the rational function a(x). 2. den - Denominator of the rational function a(x). 3. mul - Multiplicity of oo as a pole. 4. d - The d-vector. """ tests = [ # Tests with multiplicity at oo = 2 ( Poly(-x**5 - 2*x**4 + 4*x**3 + 2*x + 5, x, extension=True), Poly(9*x**3 - 2*x**2 + 10*x - 2, x, extension=True), 2, [[10*I/27, I/3, -3*I*(S(158)/243 - I/3)/2], \ [-10*I/27, -I/3, 3*I*(S(158)/243 + I/3)/2]] ), ( Poly(-x**6 + 9*x**5 + 5*x**4 + 6*x**3 + 5*x**2 + 6*x + 7, x, extension=True), Poly(x**4 + 3*x**3 + 12*x**2 - x + 7, x, extension=True), 2, [[-6*I, I, -I*(17 - I)/2], [6*I, -I, I*(17 + I)/2]] ), # Tests with multiplicity at oo = 4 ( Poly(-2*x**6 - x**5 - x**4 - 2*x**3 - x**2 - 3*x - 3, x, extension=True), Poly(3*x**2 + 10*x + 7, x, extension=True), 4, [[269*sqrt(6)*I/288, -17*sqrt(6)*I/36, sqrt(6)*I/3, -sqrt(6)*I*(S(16969)/2592 \ - 2*sqrt(6)*I/3)/4], [-269*sqrt(6)*I/288, 17*sqrt(6)*I/36, -sqrt(6)*I/3, \ sqrt(6)*I*(S(16969)/2592 + 2*sqrt(6)*I/3)/4]] ), ( Poly(-3*x**5 - 3*x**4 - 3*x**3 - x**2 - 1, x, extension=True), Poly(12*x - 2, x, extension=True), 4, [[41*I/192, 7*I/24, I/2, -I*(-S(59)/6912 - I)], \ [-41*I/192, -7*I/24, -I/2, I*(-S(59)/6912 + I)]] ), # Tests with multiplicity at oo = 4 ( Poly(-x**7 - x**5 - x**4 - x**2 - x, x, extension=True), Poly(x + 2, x, extension=True), 6, [[-5*I/2, 2*I, -I, I, -I*(-9 - 3*I)/2], [5*I/2, -2*I, I, -I, I*(-9 + 3*I)/2]] ), ( Poly(-x**7 - x**6 - 2*x**5 - 2*x**4 - x**3 - x**2 + 2*x - 2, x, extension=True), Poly(2*x - 2, x, extension=True), 6, [[3*sqrt(2)*I/4, 3*sqrt(2)*I/4, sqrt(2)*I/2, sqrt(2)*I/2, -sqrt(2)*I*(-S(7)/8 - \ 3*sqrt(2)*I/2)/2], [-3*sqrt(2)*I/4, -3*sqrt(2)*I/4, -sqrt(2)*I/2, -sqrt(2)*I/2, \ sqrt(2)*I*(-S(7)/8 + 3*sqrt(2)*I/2)/2]] )] for num, den, mul, d in tests: ser = rational_laurent_series(num, den, x, oo, mul, 1) assert construct_d_case_4(ser, mul//2) == d def test_construct_d_case_5(): """ This function tests the Case 5 in the step to calculate coefficients of the d-vector. Each test case has 3 values - 1. num - Numerator of the rational function a(x). 2. den - Denominator of the rational function a(x). 3. d - The d-vector. """ tests = [ ( Poly(2*x**3 + x**2 + x - 2, x, extension=True), Poly(9*x**3 + 5*x**2 + 2*x - 1, x, extension=True), [[sqrt(2)/3, -sqrt(2)/108], [-sqrt(2)/3, sqrt(2)/108]] ), ( Poly(3*x**5 + x**4 - x**3 + x**2 - 2*x - 2, x, domain='ZZ'), Poly(9*x**5 + 7*x**4 + 3*x**3 + 2*x**2 + 5*x + 7, x, domain='ZZ'), [[sqrt(3)/3, -2*sqrt(3)/27], [-sqrt(3)/3, 2*sqrt(3)/27]] ), ( Poly(x**2 - x + 1, x, domain='ZZ'), Poly(3*x**2 + 7*x + 3, x, domain='ZZ'), [[sqrt(3)/3, -5*sqrt(3)/9], [-sqrt(3)/3, 5*sqrt(3)/9]] )] for num, den, d in tests: # Multiplicity of oo is 0 ser = rational_laurent_series(num, den, x, oo, 0, 1) assert construct_d_case_5(ser) == d def test_construct_d_case_6(): """ This function tests the Case 6 in the step to calculate coefficients of the d-vector. Each test case has 3 values - 1. num - Numerator of the rational function a(x). 2. den - Denominator of the rational function a(x). 3. d - The d-vector. """ tests = [ ( Poly(-2*x**2 - 5, x, domain='ZZ'), Poly(4*x**4 + 2*x**2 + 10*x + 2, x, domain='ZZ'), [[S(1)/2 + I/2], [S(1)/2 - I/2]] ), ( Poly(-2*x**3 - 4*x**2 - 2*x - 5, x, domain='ZZ'), Poly(x**6 - x**5 + 2*x**4 - 4*x**3 - 5*x**2 - 5*x + 9, x, domain='ZZ'), [[1], [0]] ), ( Poly(-5*x**3 + x**2 + 11*x + 12, x, domain='ZZ'), Poly(6*x**8 - 26*x**7 - 27*x**6 - 10*x**5 - 44*x**4 - 46*x**3 - 34*x**2 \ - 27*x - 42, x, domain='ZZ'), [[1], [0]] )] for num, den, d in tests: assert construct_d_case_6(num, den, x) == d def test_rational_laurent_series(): """ This function tests the computation of coefficients of Laurent series of a rational function. Each test case has 5 values - 1. num - Numerator of the rational function. 2. den - Denominator of the rational function. 3. x0 - Point about which Laurent series is to be calculated. 4. mul - Multiplicity of x0 if x0 is a pole of the rational function (0 otherwise). 5. n - Number of terms upto which the series is to be calcuated. """ tests = [ # Laurent series about simple pole (Multiplicity = 1) ( Poly(x**2 - 3*x + 9, x, extension=True), Poly(x**2 - x, x, extension=True), S(1), 1, 6, {1: 7, 0: -8, -1: 9, -2: -9, -3: 9, -4: -9} ), # Laurent series about multiple pole (Multiplicty > 1) ( Poly(64*x**3 - 1728*x + 1216, x, extension=True), Poly(64*x**4 - 80*x**3 - 831*x**2 + 1809*x - 972, x, extension=True), S(9)/8, 2, 3, {0: S(32177152)/46521675, 2: S(1019)/984, -1: S(11947565056)/28610830125, \ 1: S(209149)/75645} ), ( Poly(1, x, extension=True), Poly(x**5 + (-4*sqrt(2) - 1)*x**4 + (4*sqrt(2) + 12)*x**3 + (-12 - 8*sqrt(2))*x**2 \ + (4 + 8*sqrt(2))*x - 4, x, extension=True), sqrt(2), 4, 6, {4: 1 + sqrt(2), 3: -3 - 2*sqrt(2), 2: Mul(-1, -3 - 2*sqrt(2), evaluate=False)/(-1 \ + sqrt(2)), 1: (-3 - 2*sqrt(2))/(-1 + sqrt(2))**2, 0: Mul(-1, -3 - 2*sqrt(2), evaluate=False \ )/(-1 + sqrt(2))**3, -1: (-3 - 2*sqrt(2))/(-1 + sqrt(2))**4} ), # Laurent series about oo ( Poly(x**5 - 4*x**3 + 6*x**2 + 10*x - 13, x, extension=True), Poly(x**2 - 5, x, extension=True), oo, 3, 6, {3: 1, 2: 0, 1: 1, 0: 6, -1: 15, -2: 17} ), # Laurent series at x0 where x0 is not a pole of the function # Using multiplicity as 0 (as x0 will not be a pole) ( Poly(3*x**3 + 6*x**2 - 2*x + 5, x, extension=True), Poly(9*x**4 - x**3 - 3*x**2 + 4*x + 4, x, extension=True), S(2)/5, 0, 1, {0: S(3345)/3304, -1: S(399325)/2729104, -2: S(3926413375)/4508479808, \ -3: S(-5000852751875)/1862002160704, -4: S(-6683640101653125)/6152055138966016} ), ( Poly(-7*x**2 + 2*x - 4, x, extension=True), Poly(7*x**5 + 9*x**4 + 8*x**3 + 3*x**2 + 6*x + 9, x, extension=True), oo, 0, 6, {0: 0, -2: 0, -5: -S(71)/49, -1: 0, -3: -1, -4: S(11)/7} )] for num, den, x0, mul, n, ser in tests: assert ser == rational_laurent_series(num, den, x, x0, mul, n) def check_dummy_sol(eq, solse, dummy_sym): """ Helper function to check if actual solution matches expected solution if actual solution contains dummy symbols. """ if isinstance(eq, Eq): eq = eq.lhs - eq.rhs _, funcs = match_riccati(eq, f, x) sols = solve_riccati(f(x), x, *funcs) C1 = Dummy('C1') sols = [sol.subs(C1, dummy_sym) for sol in sols] assert all([x[0] for x in checkodesol(eq, sols)]) assert all([s1.dummy_eq(s2, dummy_sym) for s1, s2 in zip(sols, solse)]) def test_solve_riccati(): """ This function tests the computation of rational particular solutions for a Riccati ODE. Each test case has 2 values - 1. eq - Riccati ODE to be solved. 2. sol - Expected solution to the equation. Some examples have been taken from the paper - "Statistical Investigation of First-Order Algebraic ODEs and their Rational General Solutions" by Georg Grasegger, N. Thieu Vo, Franz Winkler https://www3.risc.jku.at/publications/download/risc_5197/RISCReport15-19.pdf """ C0 = Dummy('C0') # Type: 1st Order Rational Riccati, dy/dx = a + b*y + c*y**2, # a, b, c are rational functions of x tests = [ # a(x) is a constant ( Eq(f(x).diff(x) + f(x)**2 - 2, 0), [Eq(f(x), sqrt(2)), Eq(f(x), -sqrt(2))] ), # a(x) is a constant ( f(x)**2 + f(x).diff(x) + 4*f(x)/x + 2/x**2, [Eq(f(x), (-2*C0 - x)/(C0*x + x**2))] ), # a(x) is a constant ( 2*x**2*f(x).diff(x) - x*(4*f(x) + f(x).diff(x) - 4) + (f(x) - 1)*f(x), [Eq(f(x), (C0 + 2*x**2)/(C0 + x))] ), # Pole with multiplicity 1 ( Eq(f(x).diff(x), -f(x)**2 - 2/(x**3 - x**2)), [Eq(f(x), 1/(x**2 - x))] ), # One pole of multiplicity 2 ( x**2 - (2*x + 1/x)*f(x) + f(x)**2 + f(x).diff(x), [Eq(f(x), (C0*x + x**3 + 2*x)/(C0 + x**2)), Eq(f(x), x)] ), ( x**4*f(x).diff(x) + x**2 - x*(2*f(x)**2 + f(x).diff(x)) + f(x), [Eq(f(x), (C0*x**2 + x)/(C0 + x**2)), Eq(f(x), x**2)] ), # Multiple poles of multiplicity 2 ( -f(x)**2 + f(x).diff(x) + (15*x**2 - 20*x + 7)/((x - 1)**2*(2*x \ - 1)**2), [Eq(f(x), (9*C0*x - 6*C0 - 15*x**5 + 60*x**4 - 94*x**3 + 72*x**2 \ - 30*x + 6)/(6*C0*x**2 - 9*C0*x + 3*C0 + 6*x**6 - 29*x**5 + \ 57*x**4 - 58*x**3 + 30*x**2 - 6*x)), Eq(f(x), (3*x - 2)/(2*x**2 \ - 3*x + 1))] ), # Regression: Poles with even multiplicity > 2 fixed ( f(x)**2 + f(x).diff(x) - (4*x**6 - 8*x**5 + 12*x**4 + 4*x**3 + \ 7*x**2 - 20*x + 4)/(4*x**4), [Eq(f(x), (2*x**5 - 2*x**4 - x**3 + 4*x**2 + 3*x - 2)/(2*x**4 \ - 2*x**2))] ), # Regression: Poles with even multiplicity > 2 fixed ( Eq(f(x).diff(x), (-x**6 + 15*x**4 - 40*x**3 + 45*x**2 - 24*x + 4)/\ (x**12 - 12*x**11 + 66*x**10 - 220*x**9 + 495*x**8 - 792*x**7 + 924*x**6 - \ 792*x**5 + 495*x**4 - 220*x**3 + 66*x**2 - 12*x + 1) + f(x)**2 + f(x)), [Eq(f(x), 1/(x**6 - 6*x**5 + 15*x**4 - 20*x**3 + 15*x**2 - 6*x + 1))] ), # More than 2 poles with multiplicity 2 # Regression: Fixed mistake in necessary conditions ( Eq(f(x).diff(x), x*f(x) + 2*x + (3*x - 2)*f(x)**2/(4*x + 2) + \ (8*x**2 - 7*x + 26)/(16*x**3 - 24*x**2 + 8) - S(3)/2), [Eq(f(x), (1 - 4*x)/(2*x - 2))] ), # Regression: Fixed mistake in necessary conditions ( Eq(f(x).diff(x), (-12*x**2 - 48*x - 15)/(24*x**3 - 40*x**2 + 8*x + 8) \ + 3*f(x)**2/(6*x + 2)), [Eq(f(x), (2*x + 1)/(2*x - 2))] ), # Imaginary poles ( f(x).diff(x) + (3*x**2 + 1)*f(x)**2/x + (6*x**2 - x + 3)*f(x)/(x*(x \ - 1)) + (3*x**2 - 2*x + 2)/(x*(x - 1)**2), [Eq(f(x), (-C0 - x**3 + x**2 - 2*x)/(C0*x - C0 + x**4 - x**3 + x**2 \ - x)), Eq(f(x), -1/(x - 1))], ), # Imaginary coefficients in equation ( f(x).diff(x) - 2*I*(f(x)**2 + 1)/x, [Eq(f(x), (-I*C0 + I*x**4)/(C0 + x**4)), Eq(f(x), -I)] ), # Regression: linsolve returning empty solution # Large value of m (> 10) ( Eq(f(x).diff(x), x*f(x)/(S(3)/2 - 2*x) + (x/2 - S(1)/3)*f(x)**2/\ (2*x/3 - S(1)/2) - S(5)/4 + (281*x**2 - 1260*x + 756)/(16*x**3 - 12*x**2)), [Eq(f(x), (9 - x)/x), Eq(f(x), (40*x**14 + 28*x**13 + 420*x**12 + 2940*x**11 + \ 18480*x**10 + 103950*x**9 + 519750*x**8 + 2286900*x**7 + 8731800*x**6 + 28378350*\ x**5 + 76403250*x**4 + 163721250*x**3 + 261954000*x**2 + 278326125*x + 147349125)/\ ((24*x**14 + 140*x**13 + 840*x**12 + 4620*x**11 + 23100*x**10 + 103950*x**9 + \ 415800*x**8 + 1455300*x**7 + 4365900*x**6 + 10914750*x**5 + 21829500*x**4 + 32744250\ *x**3 + 32744250*x**2 + 16372125*x)))] ), # Regression: Fixed bug due to a typo in paper ( Eq(f(x).diff(x), 18*x**3 + 18*x**2 + (-x/2 - S(1)/2)*f(x)**2 + 6), [Eq(f(x), 6*x)] ), # Regression: Fixed bug due to a typo in paper ( Eq(f(x).diff(x), -3*x**3/4 + 15*x/2 + (x/3 - S(4)/3)*f(x)**2 \ + 9 + (1 - x)*f(x)/x + 3/x), [Eq(f(x), -3*x/2 - 3)] )] for eq, sol in tests: check_dummy_sol(eq, sol, C0) @slow def test_solve_riccati_slow(): """ This function tests the computation of rational particular solutions for a Riccati ODE. Each test case has 2 values - 1. eq - Riccati ODE to be solved. 2. sol - Expected solution to the equation. """ C0 = Dummy('C0') tests = [ # Very large values of m (989 and 991) ( Eq(f(x).diff(x), (1 - x)*f(x)/(x - 3) + (2 - 12*x)*f(x)**2/(2*x - 9) + \ (54924*x**3 - 405264*x**2 + 1084347*x - 1087533)/(8*x**4 - 132*x**3 + 810*x**2 - \ 2187*x + 2187) + 495), [Eq(f(x), (18*x + 6)/(2*x - 9))] )] for eq, sol in tests: check_dummy_sol(eq, sol, C0) sympy-sympy-1.9/sympy/solvers/ode/tests/test_single.py000066400000000000000000003013211412543434000234040ustar00rootroot00000000000000# # The main tests for the code in single.py are currently located in # sympy/solvers/tests/test_ode.py # r""" This File contains test functions for the individual hints used for solving ODEs. Examples of each solver will be returned by _get_examples_ode_sol_name_of_solver. Examples should have a key 'XFAIL' which stores the list of hints if they are expected to fail for that hint. Functions that are for internal use: 1) _ode_solver_test(ode_examples) - It takes a dictionary of examples returned by _get_examples method and tests them with their respective hints. 2) _test_particular_example(our_hint, example_name) - It tests the ODE example corresponding to the hint provided. 3) _test_all_hints(runxfail=False) - It is used to test all the examples with all the hints currently implemented. It calls _test_all_examples_for_one_hint() which outputs whether the given hint functions properly if it classifies the ODE example. If runxfail flag is set to True then it will only test the examples which are expected to fail. Everytime the ODE of a particular solver is added, _test_all_hints() is to be executed to find the possible failures of different solver hints. 4) _test_all_examples_for_one_hint(our_hint, all_examples) - It takes hint as argument and checks this hint against all the ODE examples and gives output as the number of ODEs matched, number of ODEs which were solved correctly, list of ODEs which gives incorrect solution and list of ODEs which raises exception. """ from sympy import (acos, acosh, asin, asinh, atan, cos, Derivative, Dummy, diff, cbrt, E, Eq, exp, hyper, I, im, Integral, integrate, LambertW, log, Mul, Ne, pi, Piecewise, Rational, re, rootof, S, sin, sinh, cosh, tan, tanh, sec, sqrt, symbols, Ei, erfi) from sympy.core import Function, Symbol from sympy.functions import airyai, airybi, besselj, bessely, lowergamma from sympy.integrals.risch import NonElementaryIntegral from sympy.solvers.ode import classify_ode, dsolve from sympy.solvers.ode.ode import allhints, _remove_redundant_solutions from sympy.solvers.ode.single import (FirstLinear, ODEMatchError, SingleODEProblem, SingleODESolver, NthOrderReducible) from sympy.solvers.ode.subscheck import checkodesol from sympy.testing.pytest import raises, slow, ON_TRAVIS import traceback x = Symbol('x') u = Symbol('u') _u = Dummy('u') y = Symbol('y') f = Function('f') g = Function('g') C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 = symbols('C1:11') hint_message = """\ Hint did not match the example {example}. The ODE is: {eq}. The expected hint was {our_hint}\ """ expected_sol_message = """\ Different solution found from dsolve for example {example}. The ODE is: {eq} The expected solution was {sol} What dsolve returned is: {dsolve_sol}\ """ checkodesol_msg = """\ solution found is not correct for example {example}. The ODE is: {eq}\ """ dsol_incorrect_msg = """\ solution returned by dsolve is incorrect when using {hint}. The ODE is: {eq} The expected solution was {sol} what dsolve returned is: {dsolve_sol} You can test this with: eq = {eq} sol = dsolve(eq, hint='{hint}') print(sol) print(checkodesol(eq, sol)) """ exception_msg = """\ dsolve raised exception : {e} when using {hint} for the example {example} You can test this with: from sympy.solvers.ode.tests.test_single import _test_an_example _test_an_example('{hint}', example_name = '{example}') The ODE is: {eq} \ """ check_hint_msg = """\ Tested hint was : {hint} Total of {matched} examples matched with this hint. Out of which {solve} gave correct results. Examples which gave incorrect results are {unsolve}. Examples which raised exceptions are {exceptions} \ """ def _add_example_keys(func): def inner(): solver=func() examples=[] for example in solver['examples']: temp={ 'eq': solver['examples'][example]['eq'], 'sol': solver['examples'][example]['sol'], 'XFAIL': solver['examples'][example].get('XFAIL', []), 'func': solver['examples'][example].get('func',solver['func']), 'example_name': example, 'slow': solver['examples'][example].get('slow', False), 'simplify_flag':solver['examples'][example].get('simplify_flag',True), 'checkodesol_XFAIL': solver['examples'][example].get('checkodesol_XFAIL', False), 'dsolve_too_slow':solver['examples'][example].get('dsolve_too_slow',False), 'checkodesol_too_slow':solver['examples'][example].get('checkodesol_too_slow',False), 'hint': solver['hint'] } examples.append(temp) return examples return inner() def _ode_solver_test(ode_examples, run_slow_test=False): for example in ode_examples: if ((not run_slow_test) and example['slow']) or (run_slow_test and (not example['slow'])): continue result = _test_particular_example(example['hint'], example, solver_flag=True) if result['xpass_msg'] != "": print(result['xpass_msg']) def _test_all_hints(runxfail=False): all_hints = list(allhints)+["default"] all_examples = _get_all_examples() for our_hint in all_hints: if our_hint.endswith('_Integral') or 'series' in our_hint: continue _test_all_examples_for_one_hint(our_hint, all_examples, runxfail) def _test_dummy_sol(expected_sol,dsolve_sol): if type(dsolve_sol)==list: return any(expected_sol.dummy_eq(sub_dsol) for sub_dsol in dsolve_sol) else: return expected_sol.dummy_eq(dsolve_sol) def _test_an_example(our_hint, example_name): all_examples = _get_all_examples() for example in all_examples: if example['example_name'] == example_name: _test_particular_example(our_hint, example) def _test_particular_example(our_hint, ode_example, solver_flag=False): eq = ode_example['eq'] expected_sol = ode_example['sol'] example = ode_example['example_name'] xfail = our_hint in ode_example['XFAIL'] func = ode_example['func'] result = {'msg': '', 'xpass_msg': ''} simplify_flag=ode_example['simplify_flag'] checkodesol_XFAIL = ode_example['checkodesol_XFAIL'] dsolve_too_slow = ode_example['dsolve_too_slow'] checkodesol_too_slow = ode_example['checkodesol_too_slow'] xpass = True if solver_flag: if our_hint not in classify_ode(eq, func): message = hint_message.format(example=example, eq=eq, our_hint=our_hint) raise AssertionError(message) if our_hint in classify_ode(eq, func): result['match_list'] = example try: if not (dsolve_too_slow): dsolve_sol = dsolve(eq, func, simplify=simplify_flag,hint=our_hint) else: if len(expected_sol)==1: dsolve_sol = expected_sol[0] else: dsolve_sol = expected_sol except Exception as e: dsolve_sol = [] result['exception_list'] = example if not solver_flag: traceback.print_exc() result['msg'] = exception_msg.format(e=str(e), hint=our_hint, example=example, eq=eq) if solver_flag and not xfail: print(result['msg']) raise xpass = False if solver_flag and dsolve_sol!=[]: expect_sol_check = False if type(dsolve_sol)==list: for sub_sol in expected_sol: if sub_sol.has(Dummy): expect_sol_check = not _test_dummy_sol(sub_sol, dsolve_sol) else: expect_sol_check = sub_sol not in dsolve_sol if expect_sol_check: break else: expect_sol_check = dsolve_sol not in expected_sol for sub_sol in expected_sol: if sub_sol.has(Dummy): expect_sol_check = not _test_dummy_sol(sub_sol, dsolve_sol) if expect_sol_check: message = expected_sol_message.format(example=example, eq=eq, sol=expected_sol, dsolve_sol=dsolve_sol) raise AssertionError(message) expected_checkodesol = [(True, 0) for i in range(len(expected_sol))] if len(expected_sol) == 1: expected_checkodesol = (True, 0) if not (checkodesol_too_slow and ON_TRAVIS): if not checkodesol_XFAIL: if checkodesol(eq, dsolve_sol, func, solve_for_func=False) != expected_checkodesol: result['unsolve_list'] = example xpass = False message = dsol_incorrect_msg.format(hint=our_hint, eq=eq, sol=expected_sol,dsolve_sol=dsolve_sol) if solver_flag: message = checkodesol_msg.format(example=example, eq=eq) raise AssertionError(message) else: result['msg'] = 'AssertionError: ' + message if xpass and xfail: result['xpass_msg'] = example + "is now passing for the hint" + our_hint return result def _test_all_examples_for_one_hint(our_hint, all_examples=[], runxfail=None): if all_examples == []: all_examples = _get_all_examples() match_list, unsolve_list, exception_list = [], [], [] for ode_example in all_examples: xfail = our_hint in ode_example['XFAIL'] if runxfail and not xfail: continue if xfail: continue result = _test_particular_example(our_hint, ode_example) match_list += result.get('match_list',[]) unsolve_list += result.get('unsolve_list',[]) exception_list += result.get('exception_list',[]) if runxfail is not None: msg = result['msg'] if msg!='': print(result['msg']) # print(result.get('xpass_msg','')) if runxfail is None: match_count = len(match_list) solved = len(match_list)-len(unsolve_list)-len(exception_list) msg = check_hint_msg.format(hint=our_hint, matched=match_count, solve=solved, unsolve=unsolve_list, exceptions=exception_list) print(msg) def test_SingleODESolver(): # Test that not implemented methods give NotImplementedError # Subclasses should override these methods. problem = SingleODEProblem(f(x).diff(x), f(x), x) solver = SingleODESolver(problem) raises(NotImplementedError, lambda: solver.matches()) raises(NotImplementedError, lambda: solver.get_general_solution()) raises(NotImplementedError, lambda: solver._matches()) raises(NotImplementedError, lambda: solver._get_general_solution()) # This ODE can not be solved by the FirstLinear solver. Here we test that # it does not match and the asking for a general solution gives # ODEMatchError problem = SingleODEProblem(f(x).diff(x) + f(x)*f(x), f(x), x) solver = FirstLinear(problem) raises(ODEMatchError, lambda: solver.get_general_solution()) solver = FirstLinear(problem) assert solver.matches() is False #These are just test for order of ODE problem = SingleODEProblem(f(x).diff(x) + f(x), f(x), x) assert problem.order == 1 problem = SingleODEProblem(f(x).diff(x,4) + f(x).diff(x,2) - f(x).diff(x,3), f(x), x) assert problem.order == 4 problem = SingleODEProblem(f(x).diff(x, 3) + f(x).diff(x, 2) - f(x)**2, f(x), x) assert problem.is_autonomous == True problem = SingleODEProblem(f(x).diff(x, 3) + x*f(x).diff(x, 2) - f(x)**2, f(x), x) assert problem.is_autonomous == False def test_linear_coefficients(): _ode_solver_test(_get_examples_ode_sol_linear_coefficients) @slow def test_1st_homogeneous_coeff_ode(): #These were marked as test_1st_homogeneous_coeff_corner_case eq1 = f(x).diff(x) - f(x)/x c1 = classify_ode(eq1, f(x)) eq2 = x*f(x).diff(x) - f(x) c2 = classify_ode(eq2, f(x)) sdi = "1st_homogeneous_coeff_subs_dep_div_indep" sid = "1st_homogeneous_coeff_subs_indep_div_dep" assert sid not in c1 and sdi not in c1 assert sid not in c2 and sdi not in c2 _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep) _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_best) @slow def test_slow_examples_1st_homogeneous_coeff_ode(): _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep, run_slow_test=True) _ode_solver_test(_get_examples_ode_sol_1st_homogeneous_coeff_best, run_slow_test=True) @slow def test_nth_linear_constant_coeff_homogeneous(): _ode_solver_test(_get_examples_ode_sol_nth_linear_constant_coeff_homogeneous) @slow def test_slow_examples_nth_linear_constant_coeff_homogeneous(): _ode_solver_test(_get_examples_ode_sol_nth_linear_constant_coeff_homogeneous, run_slow_test=True) def test_Airy_equation(): _ode_solver_test(_get_examples_ode_sol_2nd_linear_airy) @slow def test_lie_group(): _ode_solver_test(_get_examples_ode_sol_lie_group) @slow def test_separable_reduced(): df = f(x).diff(x) eq = (x / f(x))*df + tan(x**2*f(x) / (x**2*f(x) - 1)) assert classify_ode(eq) == ('separable_reduced', 'lie_group', 'separable_reduced_Integral') _ode_solver_test(_get_examples_ode_sol_separable_reduced) @slow def test_slow_examples_separable_reduced(): _ode_solver_test(_get_examples_ode_sol_separable_reduced, run_slow_test=True) @slow def test_2nd_2F1_hypergeometric(): _ode_solver_test(_get_examples_ode_sol_2nd_2F1_hypergeometric) def test_2nd_2F1_hypergeometric_integral(): eq = x*(x-1)*f(x).diff(x, 2) + (-1+ S(7)/2*x)*f(x).diff(x) + f(x) sol = Eq(f(x), (C1 + C2*Integral(exp(Integral((1 - x/2)/(x*(x - 1)), x))/(1 - x/2)**2, x))*exp(Integral(1/(x - 1), x)/4)*exp(-Integral(7/(x - 1), x)/4)*hyper((S(1)/2, -1), (1,), x)) assert sol == dsolve(eq, hint='2nd_hypergeometric_Integral') assert checkodesol(eq, sol) == (True, 0) @slow def test_2nd_nonlinear_autonomous_conserved(): _ode_solver_test(_get_examples_ode_sol_2nd_nonlinear_autonomous_conserved) def test_2nd_nonlinear_autonomous_conserved_integral(): eq = f(x).diff(x, 2) + asin(f(x)) actual = [Eq(Integral(1/sqrt(C1 - 2*Integral(asin(_u), _u)), (_u, f(x))), C2 + x), Eq(Integral(1/sqrt(C1 - 2*Integral(asin(_u), _u)), (_u, f(x))), C2 - x)] solved = dsolve(eq, hint='2nd_nonlinear_autonomous_conserved_Integral', simplify=False) for a,s in zip(actual, solved): assert a.dummy_eq(s) # checkodesol unable to simplify solutions with f(x) in an integral equation assert checkodesol(eq, [s.doit() for s in solved]) == [(True, 0), (True, 0)] def test_2nd_linear_bessel_equation(): _ode_solver_test(_get_examples_ode_sol_2nd_linear_bessel) @slow def test_nth_algebraic(): eqn = f(x) + f(x)*f(x).diff(x) solns = [Eq(f(x), exp(x)), Eq(f(x), C1*exp(C2*x))] solns_final = _remove_redundant_solutions(eqn, solns, 2, x) assert solns_final == [Eq(f(x), C1*exp(C2*x))] _ode_solver_test(_get_examples_ode_sol_nth_algebraic) @slow def test_slow_examples_nth_linear_constant_coeff_var_of_parameters(): _ode_solver_test(_get_examples_ode_sol_nth_linear_var_of_parameters, run_slow_test=True) def test_nth_linear_constant_coeff_var_of_parameters(): _ode_solver_test(_get_examples_ode_sol_nth_linear_var_of_parameters) @slow def test_nth_linear_constant_coeff_variation_of_parameters__integral(): # solve_variation_of_parameters shouldn't attempt to simplify the # Wronskian if simplify=False. If wronskian() ever gets good enough # to simplify the result itself, this test might fail. our_hint = 'nth_linear_constant_coeff_variation_of_parameters_Integral' eq = f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x) sol_simp = dsolve(eq, f(x), hint=our_hint, simplify=True) sol_nsimp = dsolve(eq, f(x), hint=our_hint, simplify=False) assert sol_simp != sol_nsimp assert checkodesol(eq, sol_simp, order=5, solve_for_func=False) == (True, 0) assert checkodesol(eq, sol_simp, order=5, solve_for_func=False) == (True, 0) @slow def test_slow_examples_1st_exact(): _ode_solver_test(_get_examples_ode_sol_1st_exact, run_slow_test=True) @slow def test_1st_exact(): _ode_solver_test(_get_examples_ode_sol_1st_exact) def test_1st_exact_integral(): eq = cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x) sol_1 = dsolve(eq, f(x), simplify=False, hint='1st_exact_Integral') assert checkodesol(eq, sol_1, order=1, solve_for_func=False) @slow def test_slow_examples_nth_order_reducible(): _ode_solver_test(_get_examples_ode_sol_nth_order_reducible, run_slow_test=True) @slow def test_slow_examples_nth_linear_constant_coeff_undetermined_coefficients(): _ode_solver_test(_get_examples_ode_sol_nth_linear_undetermined_coefficients, run_slow_test=True) @slow def test_slow_examples_separable(): _ode_solver_test(_get_examples_ode_sol_separable, run_slow_test=True) def test_nth_linear_constant_coeff_undetermined_coefficients(): #issue-https://github.com/sympy/sympy/issues/5787 # This test case is to show the classification of imaginary constants under # nth_linear_constant_coeff_undetermined_coefficients eq = Eq(diff(f(x), x), I*f(x) + S.Half - I) our_hint = 'nth_linear_constant_coeff_undetermined_coefficients' assert our_hint in classify_ode(eq) _ode_solver_test(_get_examples_ode_sol_nth_linear_undetermined_coefficients) def test_nth_order_reducible(): F = lambda eq: NthOrderReducible(SingleODEProblem(eq, f(x), x))._matches() D = Derivative assert F(D(y*f(x), x, y) + D(f(x), x)) == False assert F(D(y*f(y), y, y) + D(f(y), y)) == False assert F(f(x)*D(f(x), x) + D(f(x), x, 2))== False assert F(D(x*f(y), y, 2) + D(u*y*f(x), x, 3)) == False # no simplification by design assert F(D(f(y), y, 2) + D(f(y), y, 3) + D(f(x), x, 4)) == False assert F(D(f(x), x, 2) + D(f(x), x, 3)) == True _ode_solver_test(_get_examples_ode_sol_nth_order_reducible) @slow def test_separable(): _ode_solver_test(_get_examples_ode_sol_separable) @slow def test_factorable(): assert integrate(-asin(f(2*x)+pi), x) == -Integral(asin(pi + f(2*x)), x) _ode_solver_test(_get_examples_ode_sol_factorable) @slow def test_slow_examples_factorable(): _ode_solver_test(_get_examples_ode_sol_factorable, run_slow_test=True) def test_Riccati_special_minus2(): _ode_solver_test(_get_examples_ode_sol_riccati) @slow def test_1st_rational_riccati(): _ode_solver_test(_get_examples_ode_sol_1st_rational_riccati) def test_Bernoulli(): _ode_solver_test(_get_examples_ode_sol_bernoulli) def test_1st_linear(): _ode_solver_test(_get_examples_ode_sol_1st_linear) def test_almost_linear(): _ode_solver_test(_get_examples_ode_sol_almost_linear) def test_Liouville_ODE(): hint = 'Liouville' not_Liouville1 = classify_ode(diff(f(x), x)/x + f(x)*diff(f(x), x, x)/2 - diff(f(x), x)**2/2, f(x)) not_Liouville2 = classify_ode(diff(f(x), x)/x + diff(f(x), x, x)/2 - x*diff(f(x), x)**2/2, f(x)) assert hint not in not_Liouville1 assert hint not in not_Liouville2 assert hint + '_Integral' not in not_Liouville1 assert hint + '_Integral' not in not_Liouville2 _ode_solver_test(_get_examples_ode_sol_liouville) def test_nth_order_linear_euler_eq_homogeneous(): x, t, a, b, c = symbols('x t a b c') y = Function('y') our_hint = "nth_linear_euler_eq_homogeneous" eq = diff(f(t), t, 4)*t**4 - 13*diff(f(t), t, 2)*t**2 + 36*f(t) assert our_hint in classify_ode(eq) eq = a*y(t) + b*t*diff(y(t), t) + c*t**2*diff(y(t), t, 2) assert our_hint in classify_ode(eq) _ode_solver_test(_get_examples_ode_sol_euler_homogeneous) def test_nth_order_linear_euler_eq_nonhomogeneous_undetermined_coefficients(): x, t = symbols('x t') a, b, c, d = symbols('a b c d', integer=True) our_hint = "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients" eq = x**4*diff(f(x), x, 4) - 13*x**2*diff(f(x), x, 2) + 36*f(x) + x assert our_hint in classify_ode(eq, f(x)) eq = a*x**2*diff(f(x), x, 2) + b*x*diff(f(x), x) + c*f(x) + d*log(x) assert our_hint in classify_ode(eq, f(x)) _ode_solver_test(_get_examples_ode_sol_euler_undetermined_coeff) def test_nth_order_linear_euler_eq_nonhomogeneous_variation_of_parameters(): x, t = symbols('x, t') a, b, c, d = symbols('a, b, c, d', integer=True) our_hint = "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters" eq = Eq(x**2*diff(f(x),x,2) - 8*x*diff(f(x),x) + 12*f(x), x**2) assert our_hint in classify_ode(eq, f(x)) eq = Eq(a*x**3*diff(f(x),x,3) + b*x**2*diff(f(x),x,2) + c*x*diff(f(x),x) + d*f(x), x*log(x)) assert our_hint in classify_ode(eq, f(x)) _ode_solver_test(_get_examples_ode_sol_euler_var_para) @_add_example_keys def _get_examples_ode_sol_euler_homogeneous(): r1, r2, r3, r4, r5 = [rootof(x**5 - 14*x**4 + 71*x**3 - 154*x**2 + 120*x - 1, n) for n in range(5)] return { 'hint': "nth_linear_euler_eq_homogeneous", 'func': f(x), 'examples':{ 'euler_hom_01': { 'eq': Eq(-3*diff(f(x), x)*x + 2*x**2*diff(f(x), x, x), 0), 'sol': [Eq(f(x), C1 + C2*x**Rational(5, 2))], }, 'euler_hom_02': { 'eq': Eq(3*f(x) - 5*diff(f(x), x)*x + 2*x**2*diff(f(x), x, x), 0), 'sol': [Eq(f(x), C1*sqrt(x) + C2*x**3)] }, 'euler_hom_03': { 'eq': Eq(4*f(x) + 5*diff(f(x), x)*x + x**2*diff(f(x), x, x), 0), 'sol': [Eq(f(x), (C1 + C2*log(x))/x**2)] }, 'euler_hom_04': { 'eq': Eq(6*f(x) - 6*diff(f(x), x)*x + 1*x**2*diff(f(x), x, x) + x**3*diff(f(x), x, x, x), 0), 'sol': [Eq(f(x), C1/x**2 + C2*x + C3*x**3)] }, 'euler_hom_05': { 'eq': Eq(-125*f(x) + 61*diff(f(x), x)*x - 12*x**2*diff(f(x), x, x) + x**3*diff(f(x), x, x, x), 0), 'sol': [Eq(f(x), x**5*(C1 + C2*log(x) + C3*log(x)**2))] }, 'euler_hom_06': { 'eq': x**2*diff(f(x), x, 2) + x*diff(f(x), x) - 9*f(x), 'sol': [Eq(f(x), C1*x**-3 + C2*x**3)] }, 'euler_hom_07': { 'eq': sin(x)*x**2*f(x).diff(x, 2) + sin(x)*x*f(x).diff(x) + sin(x)*f(x), 'sol': [Eq(f(x), C1*sin(log(x)) + C2*cos(log(x)))], 'XFAIL': ['2nd_power_series_regular','nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients'] }, 'euler_hom_08': { 'eq': x**6 * f(x).diff(x, 6) - x*f(x).diff(x) + f(x), 'sol': [Eq(f(x), C1*x + C2*x**r1 + C3*x**r2 + C4*x**r3 + C5*x**r4 + C6*x**r5)], 'checkodesol_XFAIL':True }, #This example is from issue: https://github.com/sympy/sympy/issues/15237 #This example is from issue: # https://github.com/sympy/sympy/issues/15237 'euler_hom_09': { 'eq': Derivative(x*f(x), x, x, x), 'sol': [Eq(f(x), C1 + C2/x + C3*x)], }, } } @_add_example_keys def _get_examples_ode_sol_euler_undetermined_coeff(): return { 'hint': "nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients", 'func': f(x), 'examples':{ 'euler_undet_01': { 'eq': Eq(x**2*diff(f(x), x, x) + x*diff(f(x), x), 1), 'sol': [Eq(f(x), C1 + C2*log(x) + log(x)**2/2)] }, 'euler_undet_02': { 'eq': Eq(x**2*diff(f(x), x, x) - 2*x*diff(f(x), x) + 2*f(x), x**3), 'sol': [Eq(f(x), x*(C1 + C2*x + Rational(1, 2)*x**2))] }, 'euler_undet_03': { 'eq': Eq(x**2*diff(f(x), x, x) - x*diff(f(x), x) - 3*f(x), log(x)/x), 'sol': [Eq(f(x), (C1 + C2*x**4 - log(x)**2/8 - log(x)/16)/x)] }, 'euler_undet_04': { 'eq': Eq(x**2*diff(f(x), x, x) + 3*x*diff(f(x), x) - 8*f(x), log(x)**3 - log(x)), 'sol': [Eq(f(x), C1/x**4 + C2*x**2 - Rational(1,8)*log(x)**3 - Rational(3,32)*log(x)**2 - Rational(1,64)*log(x) - Rational(7, 256))] }, 'euler_undet_05': { 'eq': Eq(x**3*diff(f(x), x, x, x) - 3*x**2*diff(f(x), x, x) + 6*x*diff(f(x), x) - 6*f(x), log(x)), 'sol': [Eq(f(x), C1*x + C2*x**2 + C3*x**3 - Rational(1, 6)*log(x) - Rational(11, 36))] }, #Below examples were added for the issue: https://github.com/sympy/sympy/issues/5096 'euler_undet_06': { 'eq': 2*x**2*f(x).diff(x, 2) + f(x) + sqrt(2*x)*sin(log(2*x)/2), 'sol': [Eq(f(x), sqrt(x)*(C1*sin(log(x)/2) + C2*cos(log(x)/2) + sqrt(2)*log(x)*cos(log(2*x)/2)/2))] }, 'euler_undet_07': { 'eq': 2*x**2*f(x).diff(x, 2) + f(x) + sin(log(2*x)/2), 'sol': [Eq(f(x), C1*sqrt(x)*sin(log(x)/2) + C2*sqrt(x)*cos(log(x)/2) - 2*sin(log(2*x)/2)/5 - 4*cos(log(2*x)/2)/5)] }, } } @_add_example_keys def _get_examples_ode_sol_euler_var_para(): return { 'hint': "nth_linear_euler_eq_nonhomogeneous_variation_of_parameters", 'func': f(x), 'examples':{ 'euler_var_01': { 'eq': Eq(x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x), x**4), 'sol': [Eq(f(x), x*(C1 + C2*x + x**3/6))] }, 'euler_var_02': { 'eq': Eq(3*x**2*diff(f(x), x, x) + 6*x*diff(f(x), x) - 6*f(x), x**3*exp(x)), 'sol': [Eq(f(x), C1/x**2 + C2*x + x*exp(x)/3 - 4*exp(x)/3 + 8*exp(x)/(3*x) - 8*exp(x)/(3*x**2))] }, 'euler_var_03': { 'eq': Eq(x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x), x**4*exp(x)), 'sol': [Eq(f(x), x*(C1 + C2*x + x*exp(x) - 2*exp(x)))] }, 'euler_var_04': { 'eq': x**2*Derivative(f(x), x, x) - 2*x*Derivative(f(x), x) + 2*f(x) - log(x), 'sol': [Eq(f(x), C1*x + C2*x**2 + log(x)/2 + Rational(3, 4))] }, 'euler_var_05': { 'eq': -exp(x) + (x*Derivative(f(x), (x, 2)) + Derivative(f(x), x))/x, 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))] }, 'euler_var_06': { 'eq': x**2 * f(x).diff(x, 2) + x * f(x).diff(x) + 4 * f(x) - 1/x, 'sol': [Eq(f(x), C1*sin(2*log(x)) + C2*cos(2*log(x)) + 1/(5*x))] }, } } @_add_example_keys def _get_examples_ode_sol_bernoulli(): # Type: Bernoulli, f'(x) + p(x)*f(x) == q(x)*f(x)**n return { 'hint': "Bernoulli", 'func': f(x), 'examples':{ 'bernoulli_01': { 'eq': Eq(x*f(x).diff(x) + f(x) - f(x)**2, 0), 'sol': [Eq(f(x), 1/(C1*x + 1))], 'XFAIL': ['separable_reduced'] }, 'bernoulli_02': { 'eq': f(x).diff(x) - y*f(x), 'sol': [Eq(f(x), C1*exp(x*y))] }, 'bernoulli_03': { 'eq': f(x)*f(x).diff(x) - 1, 'sol': [Eq(f(x), -sqrt(C1 + 2*x)), Eq(f(x), sqrt(C1 + 2*x))] }, } } @_add_example_keys def _get_examples_ode_sol_riccati(): # Type: Riccati special alpha = -2, a*dy/dx + b*y**2 + c*y/x +d/x**2 return { 'hint': "Riccati_special_minus2", 'func': f(x), 'examples':{ 'riccati_01': { 'eq': 2*f(x).diff(x) + f(x)**2 - f(x)/x + 3*x**(-2), 'sol': [Eq(f(x), (-sqrt(3)*tan(C1 + sqrt(3)*log(x)/4) + 3)/(2*x))], }, }, } @_add_example_keys def _get_examples_ode_sol_1st_rational_riccati(): # Type: 1st Order Rational Riccati, dy/dx = a + b*y + c*y**2, # a, b, c are rational functions of x return { 'hint': "1st_rational_riccati", 'func': f(x), 'examples':{ # a(x) is a constant "rational_riccati_01": { "eq": Eq(f(x).diff(x) + f(x)**2 - 2, 0), "sol": [Eq(f(x), sqrt(2)*(-C1 - exp(2*sqrt(2)*x))/(C1 - exp(2*sqrt(2)*x)))] }, # a(x) is a constant "rational_riccati_02": { "eq": f(x)**2 + Derivative(f(x), x) + 4*f(x)/x + 2/x**2, "sol": [Eq(f(x), (-2*C1 - x)/(x*(C1 + x)))] }, # a(x) is a constant "rational_riccati_03": { "eq": 2*x**2*Derivative(f(x), x) - x*(4*f(x) + Derivative(f(x), x) - 4) + (f(x) - 1)*f(x), "sol": [Eq(f(x), (C1 + 2*x**2)/(C1 + x))] }, # Constant coefficients "rational_riccati_04": { "eq": f(x).diff(x) - 6 - 5*f(x) - f(x)**2, "sol": [Eq(f(x), (-2*C1 + 3*exp(x))/(C1 - exp(x)))] }, # One pole of multiplicity 2 "rational_riccati_05": { "eq": x**2 - (2*x + 1/x)*f(x) + f(x)**2 + Derivative(f(x), x), "sol": [Eq(f(x), x*(C1 + x**2 + 1)/(C1 + x**2 - 1))] }, # One pole of multiplicity 2 "rational_riccati_06": { "eq": x**4*Derivative(f(x), x) + x**2 - x*(2*f(x)**2 + Derivative(f(x), x)) + f(x), "sol": [Eq(f(x), x*(C1*x - x + 1)/(C1 + x**2 - 1))] }, # Multiple poles of multiplicity 2 "rational_riccati_07": { "eq": -f(x)**2 + Derivative(f(x), x) + (15*x**2 - 20*x + 7)/((x - 1)**2*(2*x \ - 1)**2), "sol": [Eq(f(x), (9*C1*x - 6*C1 - 15*x**5 + 60*x**4 - 94*x**3 + 72*x**2 - \ 33*x + 8)/(6*C1*x**2 - 9*C1*x + 3*C1 + 6*x**6 - 29*x**5 + 57*x**4 - \ 58*x**3 + 28*x**2 - 3*x - 1))] }, # Imaginary poles "rational_riccati_08": { "eq": Derivative(f(x), x) + (3*x**2 + 1)*f(x)**2/x + (6*x**2 - x + 3)*f(x)/(x*(x \ - 1)) + (3*x**2 - 2*x + 2)/(x*(x - 1)**2), "sol": [Eq(f(x), (-C1 - x**3 + x**2 - 2*x + 1)/(C1*x - C1 + x**4 - x**3 + x**2 - \ 2*x + 1))], }, # Imaginary coefficients in equation "rational_riccati_09": { "eq": Derivative(f(x), x) - 2*I*(f(x)**2 + 1)/x, "sol": [Eq(f(x), (-I*C1 + I*x**4 + I)/(C1 + x**4 - 1))] }, # Regression: linsolve returning empty solution # Large value of m (> 10) "rational_riccati_10": { "eq": Eq(Derivative(f(x), x), x*f(x)/(S(3)/2 - 2*x) + (x/2 - S(1)/3)*f(x)**2/\ (2*x/3 - S(1)/2) - S(5)/4 + (281*x**2 - 1260*x + 756)/(16*x**3 - 12*x**2)), "sol": [Eq(f(x), (40*C1*x**14 + 28*C1*x**13 + 420*C1*x**12 + 2940*C1*x**11 + \ 18480*C1*x**10 + 103950*C1*x**9 + 519750*C1*x**8 + 2286900*C1*x**7 + \ 8731800*C1*x**6 + 28378350*C1*x**5 + 76403250*C1*x**4 + 163721250*C1*x**3 \ + 261954000*C1*x**2 + 278326125*C1*x + 147349125*C1 + x*exp(2*x) - 9*exp(2*x) \ )/(x*(24*C1*x**13 + 140*C1*x**12 + 840*C1*x**11 + 4620*C1*x**10 + 23100*C1*x**9 \ + 103950*C1*x**8 + 415800*C1*x**7 + 1455300*C1*x**6 + 4365900*C1*x**5 + \ 10914750*C1*x**4 + 21829500*C1*x**3 + 32744250*C1*x**2 + 32744250*C1*x + \ 16372125*C1 - exp(2*x))))] } } } @_add_example_keys def _get_examples_ode_sol_1st_linear(): # Type: first order linear form f'(x)+p(x)f(x)=q(x) return { 'hint': "1st_linear", 'func': f(x), 'examples':{ 'linear_01': { 'eq': Eq(f(x).diff(x) + x*f(x), x**2), 'sol': [Eq(f(x), (C1 + x*exp(x**2/2)- sqrt(2)*sqrt(pi)*erfi(sqrt(2)*x/2)/2)*exp(-x**2/2))], }, }, } @_add_example_keys def _get_examples_ode_sol_factorable(): """ some hints are marked as xfail for examples because they missed additional algebraic solution which could be found by Factorable hint. Fact_01 raise exception for nth_linear_constant_coeff_undetermined_coefficients""" y = Dummy('y') a0,a1,a2,a3,a4 = symbols('a0, a1, a2, a3, a4') return { 'hint': "factorable", 'func': f(x), 'examples':{ 'fact_01': { 'eq': f(x) + f(x)*f(x).diff(x), 'sol': [Eq(f(x), 0), Eq(f(x), C1 - x)], 'XFAIL': ['separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', 'lie_group', 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters', 'nth_linear_constant_coeff_undetermined_coefficients'] }, 'fact_02': { 'eq': f(x)*(f(x).diff(x)+f(x)*x+2), 'sol': [Eq(f(x), (C1 - sqrt(2)*sqrt(pi)*erfi(sqrt(2)*x/2))*exp(-x**2/2)), Eq(f(x), 0)], 'XFAIL': ['Bernoulli', '1st_linear', 'lie_group'] }, 'fact_03': { 'eq': (f(x).diff(x)+f(x)*x**2)*(f(x).diff(x, 2) + x*f(x)), 'sol': [Eq(f(x), C1*airyai(-x) + C2*airybi(-x)),Eq(f(x), C1*exp(-x**3/3))] }, 'fact_04': { 'eq': (f(x).diff(x)+f(x)*x**2)*(f(x).diff(x, 2) + f(x)), 'sol': [Eq(f(x), C1*exp(-x**3/3)), Eq(f(x), C1*sin(x) + C2*cos(x))] }, 'fact_05': { 'eq': (f(x).diff(x)**2-1)*(f(x).diff(x)**2-4), 'sol': [Eq(f(x), C1 - x), Eq(f(x), C1 + x), Eq(f(x), C1 + 2*x), Eq(f(x), C1 - 2*x)] }, 'fact_06': { 'eq': (f(x).diff(x, 2)-exp(f(x)))*f(x).diff(x), 'sol': [ Eq(f(x), log(C1/(cos(C1*sqrt(-1/C1)*(C2 + x)) - 1))), Eq(f(x), log(C1/(cos(C1*sqrt(-1/C1)*(C2 - x)) - 1))), Eq(f(x), C1) ], 'slow': True, }, 'fact_07': { 'eq': (f(x).diff(x)**2-1)*(f(x)*f(x).diff(x)-1), 'sol': [Eq(f(x), C1 - x), Eq(f(x), -sqrt(C1 + 2*x)),Eq(f(x), sqrt(C1 + 2*x)), Eq(f(x), C1 + x)] }, 'fact_08': { 'eq': Derivative(f(x), x)**4 - 2*Derivative(f(x), x)**2 + 1, 'sol': [Eq(f(x), C1 - x), Eq(f(x), C1 + x)] }, 'fact_09': { 'eq': f(x)**2*Derivative(f(x), x)**6 - 2*f(x)**2*Derivative(f(x), x)**4 + f(x)**2*Derivative(f(x), x)**2 - 2*f(x)*Derivative(f(x), x)**5 + 4*f(x)*Derivative(f(x), x)**3 - 2*f(x)*Derivative(f(x), x) + Derivative(f(x), x)**4 - 2*Derivative(f(x), x)**2 + 1, 'sol': [ Eq(f(x), C1 - x), Eq(f(x), -sqrt(C1 + 2*x)), Eq(f(x), sqrt(C1 + 2*x)), Eq(f(x), C1 + x) ] }, 'fact_10': { 'eq': x**4*f(x)**2 + 2*x**4*f(x)*Derivative(f(x), (x, 2)) + x**4*Derivative(f(x), (x, 2))**2 + 2*x**3*f(x)*Derivative(f(x), x) + 2*x**3*Derivative(f(x), x)*Derivative(f(x), (x, 2)) - 7*x**2*f(x)**2 - 7*x**2*f(x)*Derivative(f(x), (x, 2)) + x**2*Derivative(f(x), x)**2 - 7*x*f(x)*Derivative(f(x), x) + 12*f(x)**2, 'sol': [ Eq(f(x), C1*besselj(2, x) + C2*bessely(2, x)), Eq(f(x), C1*besselj(sqrt(3), x) + C2*bessely(sqrt(3), x)) ], 'slow': True, }, 'fact_11': { 'eq': (f(x).diff(x, 2)-exp(f(x)))*(f(x).diff(x, 2)+exp(f(x))), 'sol': [ Eq(f(x), log(C1/(cos(C1*sqrt(-1/C1)*(C2 + x)) - 1))), Eq(f(x), log(C1/(cos(C1*sqrt(-1/C1)*(C2 - x)) - 1))), Eq(f(x), log(C1/(1 - cos(C1*sqrt(-1/C1)*(C2 + x))))), Eq(f(x), log(C1/(1 - cos(C1*sqrt(-1/C1)*(C2 - x))))) ], 'dsolve_too_slow': True, }, #Below examples were added for the issue: https://github.com/sympy/sympy/issues/15889 'fact_12': { 'eq': exp(f(x).diff(x))-f(x)**2, 'sol': [Eq(NonElementaryIntegral(1/log(y**2), (y, f(x))), C1 + x)], 'XFAIL': ['lie_group'] #It shows not implemented error for lie_group. }, 'fact_13': { 'eq': f(x).diff(x)**2 - f(x)**3, 'sol': [Eq(f(x), 4/(C1**2 - 2*C1*x + x**2))], 'XFAIL': ['lie_group'] #It shows not implemented error for lie_group. }, 'fact_14': { 'eq': f(x).diff(x)**2 - f(x), 'sol': [Eq(f(x), C1**2/4 - C1*x/2 + x**2/4)] }, 'fact_15': { 'eq': f(x).diff(x)**2 - f(x)**2, 'sol': [Eq(f(x), C1*exp(x)), Eq(f(x), C1*exp(-x))] }, 'fact_16': { 'eq': f(x).diff(x)**2 - f(x)**3, 'sol': [Eq(f(x), 4/(C1**2 - 2*C1*x + x**2))], }, # kamke ode 1.1 'fact_17': { 'eq': f(x).diff(x)-(a4*x**4 + a3*x**3 + a2*x**2 + a1*x + a0)**(-1/2), 'sol': [Eq(f(x), C1 + Integral(1/sqrt(a0 + a1*x + a2*x**2 + a3*x**3 + a4*x**4), x))], 'slow': True }, # This is from issue: https://github.com/sympy/sympy/issues/9446 'fact_18':{ 'eq': Eq(f(2 * x), sin(Derivative(f(x)))), 'sol': [Eq(f(x), C1 + Integral(pi - asin(f(2*x)), x)), Eq(f(x), C1 + Integral(asin(f(2*x)), x))], 'checkodesol_XFAIL':True }, # This is from issue: https://github.com/sympy/sympy/issues/7093 'fact_19': { 'eq': Derivative(f(x), x)**2 - x**3, 'sol': [Eq(f(x), C1 - 2*x**Rational(5,2)/5), Eq(f(x), C1 + 2*x**Rational(5,2)/5)], }, 'fact_20': { 'eq': x*f(x).diff(x, 2) - x*f(x), 'sol': [Eq(f(x), C1*exp(-x) + C2*exp(x))], }, } } @_add_example_keys def _get_examples_ode_sol_almost_linear(): from sympy import Ei A = Symbol('A', positive=True) f = Function('f') d = f(x).diff(x) return { 'hint': "almost_linear", 'func': f(x), 'examples':{ 'almost_lin_01': { 'eq': x**2*f(x)**2*d + f(x)**3 + 1, 'sol': [Eq(f(x), (C1*exp(3/x) - 1)**Rational(1, 3)), Eq(f(x), (-1 - sqrt(3)*I)*(C1*exp(3/x) - 1)**Rational(1, 3)/2), Eq(f(x), (-1 + sqrt(3)*I)*(C1*exp(3/x) - 1)**Rational(1, 3)/2)], }, 'almost_lin_02': { 'eq': x*f(x)*d + 2*x*f(x)**2 + 1, 'sol': [Eq(f(x), -sqrt((C1 - 2*Ei(4*x))*exp(-4*x))), Eq(f(x), sqrt((C1 - 2*Ei(4*x))*exp(-4*x)))] }, 'almost_lin_03': { 'eq': x*d + x*f(x) + 1, 'sol': [Eq(f(x), (C1 - Ei(x))*exp(-x))] }, 'almost_lin_04': { 'eq': x*exp(f(x))*d + exp(f(x)) + 3*x, 'sol': [Eq(f(x), log(C1/x - x*Rational(3, 2)))], }, 'almost_lin_05': { 'eq': x + A*(x + diff(f(x), x) + f(x)) + diff(f(x), x) + f(x) + 2, 'sol': [Eq(f(x), (C1 + Piecewise( (x, Eq(A + 1, 0)), ((-A*x + A - x - 1)*exp(x)/(A + 1), True)))*exp(-x))], }, } } @_add_example_keys def _get_examples_ode_sol_liouville(): n = Symbol('n') _y = Dummy('y') return { 'hint': "Liouville", 'func': f(x), 'examples':{ 'liouville_01': { 'eq': diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2, 'sol': [Eq(f(x), log(x/(C1 + C2*x)))], }, 'liouville_02': { 'eq': diff(x*exp(-f(x)), x, x), 'sol': [Eq(f(x), log(x/(C1 + C2*x)))] }, 'liouville_03': { 'eq': ((diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2)*exp(-f(x))/exp(f(x))).expand(), 'sol': [Eq(f(x), log(x/(C1 + C2*x)))] }, 'liouville_04': { 'eq': diff(f(x), x, x) + 1/f(x)*(diff(f(x), x))**2 + 1/x*diff(f(x), x), 'sol': [Eq(f(x), -sqrt(C1 + C2*log(x))), Eq(f(x), sqrt(C1 + C2*log(x)))], }, 'liouville_05': { 'eq': x*diff(f(x), x, x) + x/f(x)*diff(f(x), x)**2 + x*diff(f(x), x), 'sol': [Eq(f(x), -sqrt(C1 + C2*exp(-x))), Eq(f(x), sqrt(C1 + C2*exp(-x)))], }, 'liouville_06': { 'eq': Eq((x*exp(f(x))).diff(x, x), 0), 'sol': [Eq(f(x), log(C1 + C2/x))], }, 'liouville_07': { 'eq': (diff(f(x), x)/x + diff(f(x), x, x)/2 - diff(f(x), x)**2/2)*exp(-f(x))/exp(f(x)), 'sol': [Eq(f(x), log(x/(C1 + C2*x)))], }, 'liouville_08': { 'eq': x**2*diff(f(x),x) + (n*f(x) + f(x)**2)*diff(f(x),x)**2 + diff(f(x), (x, 2)), 'sol': [Eq(C1 + C2*lowergamma(Rational(1,3), x**3/3) + NonElementaryIntegral(exp(_y**3/3)*exp(_y**2*n/2), (_y, f(x))), 0)], }, } } @_add_example_keys def _get_examples_ode_sol_nth_algebraic(): M, m, r, t = symbols('M m r t') phi = Function('phi') k = Symbol('k') # This one needs a substitution f' = g. # 'algeb_12': { # 'eq': -exp(x) + (x*Derivative(f(x), (x, 2)) + Derivative(f(x), x))/x, # 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))], # }, return { 'hint': "nth_algebraic", 'func': f(x), 'examples':{ 'algeb_01': { 'eq': f(x) * f(x).diff(x) * f(x).diff(x, x) * (f(x) - 1) * (f(x).diff(x) - x), 'sol': [Eq(f(x), C1 + x**2/2), Eq(f(x), C1 + C2*x)] }, 'algeb_02': { 'eq': f(x) * f(x).diff(x) * f(x).diff(x, x) * (f(x) - 1), 'sol': [Eq(f(x), C1 + C2*x)] }, 'algeb_03': { 'eq': f(x) * f(x).diff(x) * f(x).diff(x, x), 'sol': [Eq(f(x), C1 + C2*x)] }, 'algeb_04': { 'eq': Eq(-M * phi(t).diff(t), Rational(3, 2) * m * r**2 * phi(t).diff(t) * phi(t).diff(t,t)), 'sol': [Eq(phi(t), C1), Eq(phi(t), C1 + C2*t - M*t**2/(3*m*r**2))], 'func': phi(t) }, 'algeb_05': { 'eq': (1 - sin(f(x))) * f(x).diff(x), 'sol': [Eq(f(x), C1)], 'XFAIL': ['separable'] #It raised exception. }, 'algeb_06': { 'eq': (diff(f(x)) - x)*(diff(f(x)) + x), 'sol': [Eq(f(x), C1 - x**2/2), Eq(f(x), C1 + x**2/2)] }, 'algeb_07': { 'eq': Eq(Derivative(f(x), x), Derivative(g(x), x)), 'sol': [Eq(f(x), C1 + g(x))], }, 'algeb_08': { 'eq': f(x).diff(x) - C1, #this example is from issue 15999 'sol': [Eq(f(x), C1*x + C2)], }, 'algeb_09': { 'eq': f(x)*f(x).diff(x), 'sol': [Eq(f(x), C1)], }, 'algeb_10': { 'eq': (diff(f(x)) - x)*(diff(f(x)) + x), 'sol': [Eq(f(x), C1 - x**2/2), Eq(f(x), C1 + x**2/2)], }, 'algeb_11': { 'eq': f(x) + f(x)*f(x).diff(x), 'sol': [Eq(f(x), 0), Eq(f(x), C1 - x)], 'XFAIL': ['separable', '1st_exact', '1st_linear', 'Bernoulli', '1st_homogeneous_coeff_best', '1st_homogeneous_coeff_subs_indep_div_dep', '1st_homogeneous_coeff_subs_dep_div_indep', 'lie_group', 'nth_linear_constant_coeff_undetermined_coefficients', 'nth_linear_euler_eq_nonhomogeneous_undetermined_coefficients', 'nth_linear_constant_coeff_variation_of_parameters', 'nth_linear_euler_eq_nonhomogeneous_variation_of_parameters'] #nth_linear_constant_coeff_undetermined_coefficients raises exception rest all of them misses a solution. }, 'algeb_12': { 'eq': Derivative(x*f(x), x, x, x), 'sol': [Eq(f(x), (C1 + C2*x + C3*x**2) / x)], 'XFAIL': ['nth_algebraic'] # It passes only when prep=False is set in dsolve. }, 'algeb_13': { 'eq': Eq(Derivative(x*Derivative(f(x), x), x)/x, exp(x)), 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))], 'XFAIL': ['nth_algebraic'] # It passes only when prep=False is set in dsolve. }, # These are simple tests from the old ode module example 14-18 'algeb_14': { 'eq': Eq(f(x).diff(x), 0), 'sol': [Eq(f(x), C1)], }, 'algeb_15': { 'eq': Eq(3*f(x).diff(x) - 5, 0), 'sol': [Eq(f(x), C1 + x*Rational(5, 3))], }, 'algeb_16': { 'eq': Eq(3*f(x).diff(x), 5), 'sol': [Eq(f(x), C1 + x*Rational(5, 3))], }, # Type: 2nd order, constant coefficients (two complex roots) 'algeb_17': { 'eq': Eq(3*f(x).diff(x) - 1, 0), 'sol': [Eq(f(x), C1 + x/3)], }, 'algeb_18': { 'eq': Eq(x*f(x).diff(x) - 1, 0), 'sol': [Eq(f(x), C1 + log(x))], }, # https://github.com/sympy/sympy/issues/6989 'algeb_19': { 'eq': f(x).diff(x) - x*exp(-k*x), 'sol': [Eq(f(x), C1 + Piecewise(((-k*x - 1)*exp(-k*x)/k**2, Ne(k**2, 0)),(x**2/2, True)))], }, 'algeb_20': { 'eq': -f(x).diff(x) + x*exp(-k*x), 'sol': [Eq(f(x), C1 + Piecewise(((-k*x - 1)*exp(-k*x)/k**2, Ne(k**2, 0)),(x**2/2, True)))], }, # https://github.com/sympy/sympy/issues/10867 'algeb_21': { 'eq': Eq(g(x).diff(x).diff(x), (x-2)**2 + (x-3)**3), 'sol': [Eq(g(x), C1 + C2*x + x**5/20 - 2*x**4/3 + 23*x**3/6 - 23*x**2/2)], 'func': g(x), }, # https://github.com/sympy/sympy/issues/13691 'algeb_22': { 'eq': f(x).diff(x) - C1*g(x).diff(x), 'sol': [Eq(f(x), C2 + C1*g(x))], 'func': f(x), }, # https://github.com/sympy/sympy/issues/4838 'algeb_23': { 'eq': f(x).diff(x) - 3*C1 - 3*x**2, 'sol': [Eq(f(x), C2 + 3*C1*x + x**3)], }, } } @_add_example_keys def _get_examples_ode_sol_nth_order_reducible(): return { 'hint': "nth_order_reducible", 'func': f(x), 'examples':{ 'reducible_01': { 'eq': Eq(x*Derivative(f(x), x)**2 + Derivative(f(x), x, 2), 0), 'sol': [Eq(f(x),C1 - sqrt(-1/C2)*log(-C2*sqrt(-1/C2) + x) + sqrt(-1/C2)*log(C2*sqrt(-1/C2) + x))], 'slow': True, }, 'reducible_02': { 'eq': -exp(x) + (x*Derivative(f(x), (x, 2)) + Derivative(f(x), x))/x, 'sol': [Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x))], 'slow': True, }, 'reducible_03': { 'eq': Eq(sqrt(2) * f(x).diff(x,x,x) + f(x).diff(x), 0), 'sol': [Eq(f(x), C1 + C2*sin(2**Rational(3, 4)*x/2) + C3*cos(2**Rational(3, 4)*x/2))], 'slow': True, }, 'reducible_04': { 'eq': f(x).diff(x, 2) + 2*f(x).diff(x), 'sol': [Eq(f(x), C1 + C2*exp(-2*x))], }, 'reducible_05': { 'eq': f(x).diff(x, 3) + f(x).diff(x, 2) - 6*f(x).diff(x), 'sol': [Eq(f(x), C1 + C2*exp(-3*x) + C3*exp(2*x))], 'slow': True, }, 'reducible_06': { 'eq': f(x).diff(x, 4) - f(x).diff(x, 3) - 4*f(x).diff(x, 2) + \ 4*f(x).diff(x), 'sol': [Eq(f(x), C1 + C2*exp(-2*x) + C3*exp(x) + C4*exp(2*x))], 'slow': True, }, 'reducible_07': { 'eq': f(x).diff(x, 4) + 3*f(x).diff(x, 3), 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + C4*exp(-3*x))], 'slow': True, }, 'reducible_08': { 'eq': f(x).diff(x, 4) - 2*f(x).diff(x, 2), 'sol': [Eq(f(x), C1 + C2*x + C3*exp(-sqrt(2)*x) + C4*exp(sqrt(2)*x))], 'slow': True, }, 'reducible_09': { 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2), 'sol': [Eq(f(x), C1 + C2*x + C3*sin(2*x) + C4*cos(2*x))], 'slow': True, }, 'reducible_10': { 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x), 'sol': [Eq(f(x), C1 + C2*x*sin(x) + C2*cos(x) - C3*x*cos(x) + C3*sin(x) + C4*sin(x) + C5*cos(x))], 'slow': True, }, 'reducible_11': { 'eq': f(x).diff(x, 2) - f(x).diff(x)**3, 'sol': [Eq(f(x), C1 - sqrt(2)*sqrt(-1/(C2 + x))*(C2 + x)), Eq(f(x), C1 + sqrt(2)*sqrt(-1/(C2 + x))*(C2 + x))], 'slow': True, }, # Needs to be a way to know how to combine derivatives in the expression 'reducible_12': { 'eq': Derivative(x*f(x), x, x, x) + Derivative(f(x), x, x, x), 'sol': [Eq(f(x), C1 + C3/Mul(2, (x**2 + 2*x + 1), evaluate=False) + x*(C2 + C3/Mul(2, (x**2 + 2*x + 1), evaluate=False)))], # 2-arg Mul! 'slow': True, }, } } @_add_example_keys def _get_examples_ode_sol_nth_linear_undetermined_coefficients(): # examples 3-27 below are from Ordinary Differential Equations, # Tenenbaum and Pollard, pg. 231 g = exp(-x) f2 = f(x).diff(x, 2) c = 3*f(x).diff(x, 3) + 5*f2 + f(x).diff(x) - f(x) - x t = symbols("t") u = symbols("u",cls=Function) R, L, C, E_0, alpha = symbols("R L C E_0 alpha",positive=True) omega = Symbol('omega') return { 'hint': "nth_linear_constant_coeff_undetermined_coefficients", 'func': f(x), 'examples':{ 'undet_01': { 'eq': c - x*g, 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x**2/24 - 3*x/32))*exp(-x) - 1)], 'slow': True, }, 'undet_02': { 'eq': c - g, 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x/8))*exp(-x) - 1)], 'slow': True, }, 'undet_03': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 4, 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2)], 'slow': True, }, 'undet_04': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 12*exp(x), 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2*exp(x))], 'slow': True, }, 'undet_05': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - exp(I*x), 'sol': [Eq(f(x), (S(3)/10 + I/10)*(C1*exp(-2*x) + C2*exp(-x) - I*exp(I*x)))], 'slow': True, }, 'undet_06': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - sin(x), 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + sin(x)/10 - 3*cos(x)/10)], 'slow': True, }, 'undet_07': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - cos(x), 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 3*sin(x)/10 + cos(x)/10)], 'slow': True, }, 'undet_08': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - (8 + 6*exp(x) + 2*sin(x)), 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + exp(x) + sin(x)/5 - 3*cos(x)/5 + 4)], 'slow': True, }, 'undet_09': { 'eq': f2 + f(x).diff(x) + f(x) - x**2, 'sol': [Eq(f(x), -2*x + x**2 + (C1*sin(x*sqrt(3)/2) + C2*cos(x*sqrt(3)/2))*exp(-x/2))], 'slow': True, }, 'undet_10': { 'eq': f2 - 2*f(x).diff(x) - 8*f(x) - 9*x*exp(x) - 10*exp(-x), 'sol': [Eq(f(x), -x*exp(x) - 2*exp(-x) + C1*exp(-2*x) + C2*exp(4*x))], 'slow': True, }, 'undet_11': { 'eq': f2 - 3*f(x).diff(x) - 2*exp(2*x)*sin(x), 'sol': [Eq(f(x), C1 + C2*exp(3*x) - 3*exp(2*x)*sin(x)/5 - exp(2*x)*cos(x)/5)], 'slow': True, }, 'undet_12': { 'eq': f(x).diff(x, 4) - 2*f2 + f(x) - x + sin(x), 'sol': [Eq(f(x), x - sin(x)/4 + (C1 + C2*x)*exp(-x) + (C3 + C4*x)*exp(x))], 'slow': True, }, 'undet_13': { 'eq': f2 + f(x).diff(x) - x**2 - 2*x, 'sol': [Eq(f(x), C1 + x**3/3 + C2*exp(-x))], 'slow': True, }, 'undet_14': { 'eq': f2 + f(x).diff(x) - x - sin(2*x), 'sol': [Eq(f(x), C1 - x - sin(2*x)/5 - cos(2*x)/10 + x**2/2 + C2*exp(-x))], 'slow': True, }, 'undet_15': { 'eq': f2 + f(x) - 4*x*sin(x), 'sol': [Eq(f(x), (C1 - x**2)*cos(x) + (C2 + x)*sin(x))], 'slow': True, }, 'undet_16': { 'eq': f2 + 4*f(x) - x*sin(2*x), 'sol': [Eq(f(x), (C1 - x**2/8)*cos(2*x) + (C2 + x/16)*sin(2*x))], 'slow': True, }, 'undet_17': { 'eq': f2 + 2*f(x).diff(x) + f(x) - x**2*exp(-x), 'sol': [Eq(f(x), (C1 + x*(C2 + x**3/12))*exp(-x))], 'slow': True, }, 'undet_18': { 'eq': f(x).diff(x, 3) + 3*f2 + 3*f(x).diff(x) + f(x) - 2*exp(-x) + \ x**2*exp(-x), 'sol': [Eq(f(x), (C1 + x*(C2 + x*(C3 - x**3/60 + x/3)))*exp(-x))], 'slow': True, }, 'undet_19': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - exp(-2*x) - x**2, 'sol': [Eq(f(x), C2*exp(-x) + x**2/2 - x*Rational(3,2) + (C1 - x)*exp(-2*x) + Rational(7,4))], 'slow': True, }, 'undet_20': { 'eq': f2 - 3*f(x).diff(x) + 2*f(x) - x*exp(-x), 'sol': [Eq(f(x), C1*exp(x) + C2*exp(2*x) + (6*x + 5)*exp(-x)/36)], 'slow': True, }, 'undet_21': { 'eq': f2 + f(x).diff(x) - 6*f(x) - x - exp(2*x), 'sol': [Eq(f(x), Rational(-1, 36) - x/6 + C2*exp(-3*x) + (C1 + x/5)*exp(2*x))], 'slow': True, }, 'undet_22': { 'eq': f2 + f(x) - sin(x) - exp(-x), 'sol': [Eq(f(x), C2*sin(x) + (C1 - x/2)*cos(x) + exp(-x)/2)], 'slow': True, }, 'undet_23': { 'eq': f(x).diff(x, 3) - 3*f2 + 3*f(x).diff(x) - f(x) - exp(x), 'sol': [Eq(f(x), (C1 + x*(C2 + x*(C3 + x/6)))*exp(x))], 'slow': True, }, 'undet_24': { 'eq': f2 + f(x) - S.Half - cos(2*x)/2, 'sol': [Eq(f(x), S.Half - cos(2*x)/6 + C1*sin(x) + C2*cos(x))], 'slow': True, }, 'undet_25': { 'eq': f(x).diff(x, 3) - f(x).diff(x) - exp(2*x)*(S.Half - cos(2*x)/2), 'sol': [Eq(f(x), C1 + C2*exp(-x) + C3*exp(x) + (-21*sin(2*x) + 27*cos(2*x) + 130)*exp(2*x)/1560)], 'slow': True, }, #Note: 'undet_26' is referred in 'undet_37' 'undet_26': { 'eq': (f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - sin(x) - cos(x)), 'sol': [Eq(f(x), C1 + x**2 + (C2 + x*(C3 - x/8))*sin(x) + (C4 + x*(C5 + x/8))*cos(x))], 'slow': True, }, 'undet_27': { 'eq': f2 + f(x) - cos(x)/2 + cos(3*x)/2, 'sol': [Eq(f(x), cos(3*x)/16 + C2*cos(x) + (C1 + x/4)*sin(x))], 'slow': True, }, 'undet_28': { 'eq': f(x).diff(x) - 1, 'sol': [Eq(f(x), C1 + x)], 'slow': True, }, # https://github.com/sympy/sympy/issues/19358 'undet_29': { 'eq': f2 + f(x).diff(x) + exp(x-C1), 'sol': [Eq(f(x), C2 + C3*exp(-x) - exp(-C1 + x)/2)], 'slow': True, }, # https://github.com/sympy/sympy/issues/18408 'undet_30': { 'eq': f(x).diff(x, 3) - f(x).diff(x) - sinh(x), 'sol': [Eq(f(x), C1 + C2*exp(-x) + C3*exp(x) + x*sinh(x)/2)], }, 'undet_31': { 'eq': f(x).diff(x, 2) - 49*f(x) - sinh(3*x), 'sol': [Eq(f(x), C1*exp(-7*x) + C2*exp(7*x) - sinh(3*x)/40)], }, 'undet_32': { 'eq': f(x).diff(x, 3) - f(x).diff(x) - sinh(x) - exp(x), 'sol': [Eq(f(x), C1 + C3*exp(-x) + x*sinh(x)/2 + (C2 + x/2)*exp(x))], }, # https://github.com/sympy/sympy/issues/5096 'undet_33': { 'eq': f(x).diff(x, x) + f(x) - x*sin(x - 2), 'sol': [Eq(f(x), C1*sin(x) + C2*cos(x) - x**2*cos(x - 2)/4 + x*sin(x - 2)/4)], }, 'undet_34': { 'eq': f(x).diff(x, 2) + f(x) - x**4*sin(x-1), 'sol': [ Eq(f(x), C1*sin(x) + C2*cos(x) - x**5*cos(x - 1)/10 + x**4*sin(x - 1)/4 + x**3*cos(x - 1)/2 - 3*x**2*sin(x - 1)/4 - 3*x*cos(x - 1)/4)], }, 'undet_35': { 'eq': f(x).diff(x, 2) - f(x) - exp(x - 1), 'sol': [Eq(f(x), C2*exp(-x) + (C1 + x*exp(-1)/2)*exp(x))], }, 'undet_36': { 'eq': f(x).diff(x, 2)+f(x)-(sin(x-2)+1), 'sol': [Eq(f(x), C1*sin(x) + C2*cos(x) - x*cos(x - 2)/2 + 1)], }, # Equivalent to example_name 'undet_26'. # This previously failed because the algorithm for undetermined coefficients # didn't know to multiply exp(I*x) by sufficient x because it is linearly # dependent on sin(x) and cos(x). 'undet_37': { 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x), 'sol': [Eq(f(x), C1 + x**2*(I*exp(I*x)/8 + 1) + (C2 + C3*x)*sin(x) + (C4 + C5*x)*cos(x))], }, # https://github.com/sympy/sympy/issues/12623 'undet_38': { 'eq': Eq( u(t).diff(t,t) + R /L*u(t).diff(t) + 1/(L*C)*u(t), alpha), 'sol': [Eq(u(t), C*L*alpha + C1*exp(t*(-R - sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)) + C2*exp(t*(-R + sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)))], 'func': u(t) }, 'undet_39': { 'eq': Eq( L*C*u(t).diff(t,t) + R*C*u(t).diff(t) + u(t), E_0*exp(I*omega*t) ), 'sol': [Eq(u(t), C1*exp(t*(-R - sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)) + C2*exp(t*(-R + sqrt(C*R**2 - 4*L)/sqrt(C))/(2*L)) - E_0*exp(I*omega*t)/(C*L*omega**2 - I*C*R*omega - 1))], 'func': u(t), }, # https://github.com/sympy/sympy/issues/6879 'undet_40': { 'eq': Eq(Derivative(f(x), x, 2) - 2*Derivative(f(x), x) + f(x), sin(x)), 'sol': [Eq(f(x), (C1 + C2*x)*exp(x) + cos(x)/2)], }, } } @_add_example_keys def _get_examples_ode_sol_separable(): # test_separable1-5 are from Ordinary Differential Equations, Tenenbaum and # Pollard, pg. 55 t,a = symbols('a,t') m = 96 g = 9.8 k = .2 f1 = g * m v = Function('v') return { 'hint': "separable", 'func': f(x), 'examples':{ 'separable_01': { 'eq': f(x).diff(x) - f(x), 'sol': [Eq(f(x), C1*exp(x))], }, 'separable_02': { 'eq': x*f(x).diff(x) - f(x), 'sol': [Eq(f(x), C1*x)], }, 'separable_03': { 'eq': f(x).diff(x) + sin(x), 'sol': [Eq(f(x), C1 + cos(x))], }, 'separable_04': { 'eq': f(x)**2 + 1 - (x**2 + 1)*f(x).diff(x), 'sol': [Eq(f(x), tan(C1 + atan(x)))], }, 'separable_05': { 'eq': f(x).diff(x)/tan(x) - f(x) - 2, 'sol': [Eq(f(x), C1/cos(x) - 2)], }, 'separable_06': { 'eq': f(x).diff(x) * (1 - sin(f(x))) - 1, 'sol': [Eq(-x + f(x) + cos(f(x)), C1)], }, 'separable_07': { 'eq': f(x)*x**2*f(x).diff(x) - f(x)**3 - 2*x**2*f(x).diff(x), 'sol': [ Eq(f(x), (-x + sqrt(x*(4*C1*x + x - 4)))/(C1*x - 1)/2), Eq(f(x), -((x + sqrt(x*(4*C1*x + x - 4)))/(C1*x - 1))/2) ], 'slow': True, }, 'separable_08': { 'eq': f(x)**2 - 1 - (2*f(x) + x*f(x))*f(x).diff(x), 'sol': [Eq(f(x), -sqrt(C1*x**2 + 4*C1*x + 4*C1 + 1)), Eq(f(x), sqrt(C1*x**2 + 4*C1*x + 4*C1 + 1))], 'slow': True, }, 'separable_09': { 'eq': x*log(x)*f(x).diff(x) + sqrt(1 + f(x)**2), 'sol': [Eq(f(x), sinh(C1 - log(log(x))))], #One more solution is f(x)=I 'slow': True, 'checkodesol_XFAIL': True, }, 'separable_10': { 'eq': exp(x + 1)*tan(f(x)) + cos(f(x))*f(x).diff(x), 'sol': [Eq(E*exp(x) + log(cos(f(x)) - 1)/2 - log(cos(f(x)) + 1)/2 + cos(f(x)), C1)], 'slow': True, }, 'separable_11': { 'eq': (x*cos(f(x)) + x**2*sin(f(x))*f(x).diff(x) - a**2*sin(f(x))*f(x).diff(x)), 'sol': [ Eq(f(x), -acos(C1*sqrt(-a**2 + x**2)) + 2*pi), Eq(f(x), acos(C1*sqrt(-a**2 + x**2))) ], 'slow': True, }, 'separable_12': { 'eq': f(x).diff(x) - f(x)*tan(x), 'sol': [Eq(f(x), C1/cos(x))], }, 'separable_13': { 'eq': (x - 1)*cos(f(x))*f(x).diff(x) - 2*x*sin(f(x)), 'sol': [ Eq(f(x), pi - asin(C1*(x**2 - 2*x + 1)*exp(2*x))), Eq(f(x), asin(C1*(x**2 - 2*x + 1)*exp(2*x))) ], }, 'separable_14': { 'eq': f(x).diff(x) - f(x)*log(f(x))/tan(x), 'sol': [Eq(f(x), exp(C1*sin(x)))], }, 'separable_15': { 'eq': x*f(x).diff(x) + (1 + f(x)**2)*atan(f(x)), 'sol': [Eq(f(x), tan(C1/x))], #Two more solutions are f(x)=0 and f(x)=I 'slow': True, 'checkodesol_XFAIL': True, }, 'separable_16': { 'eq': f(x).diff(x) + x*(f(x) + 1), 'sol': [Eq(f(x), -1 + C1*exp(-x**2/2))], }, 'separable_17': { 'eq': exp(f(x)**2)*(x**2 + 2*x + 1) + (x*f(x) + f(x))*f(x).diff(x), 'sol': [ Eq(f(x), -sqrt(log(1/(C1 + x**2 + 2*x)))), Eq(f(x), sqrt(log(1/(C1 + x**2 + 2*x)))) ], }, 'separable_18': { 'eq': f(x).diff(x) + f(x), 'sol': [Eq(f(x), C1*exp(-x))], }, 'separable_19': { 'eq': sin(x)*cos(2*f(x)) + cos(x)*sin(2*f(x))*f(x).diff(x), 'sol': [Eq(f(x), pi - acos(C1/cos(x)**2)/2), Eq(f(x), acos(C1/cos(x)**2)/2)], }, 'separable_20': { 'eq': (1 - x)*f(x).diff(x) - x*(f(x) + 1), 'sol': [Eq(f(x), (C1*exp(-x) - x + 1)/(x - 1))], }, 'separable_21': { 'eq': f(x)*diff(f(x), x) + x - 3*x*f(x)**2, 'sol': [Eq(f(x), -sqrt(3)*sqrt(C1*exp(3*x**2) + 1)/3), Eq(f(x), sqrt(3)*sqrt(C1*exp(3*x**2) + 1)/3)], }, 'separable_22': { 'eq': f(x).diff(x) - exp(x + f(x)), 'sol': [Eq(f(x), log(-1/(C1 + exp(x))))], 'XFAIL': ['lie_group'] #It shows 'NoneType' object is not subscriptable for lie_group. }, # https://github.com/sympy/sympy/issues/7081 'separable_23': { 'eq': x*(f(x).diff(x)) + 1 - f(x)**2, 'sol': [Eq(f(x), -1/(-C1 + x**2)*(C1 + x**2))], }, # https://github.com/sympy/sympy/issues/10379 'separable_24': { 'eq': f(t).diff(t)-(1-51.05*y*f(t)), 'sol': [Eq(f(t), (0.019588638589618023*exp(y*(C1 - 51.049999999999997*t)) + 0.019588638589618023)/y)], 'func': f(t), }, # https://github.com/sympy/sympy/issues/15999 'separable_25': { 'eq': f(x).diff(x) - C1*f(x), 'sol': [Eq(f(x), C2*exp(C1*x))], }, 'separable_26': { 'eq': f1 - k * (v(t) ** 2) - m * Derivative(v(t)), 'sol': [Eq(v(t), -68.585712797928991/tanh(C1 - 0.14288690166235204*t))], 'func': v(t), 'checkodesol_XFAIL': True, } } } @_add_example_keys def _get_examples_ode_sol_1st_exact(): # Type: Exact differential equation, p(x,f) + q(x,f)*f' == 0, # where dp/df == dq/dx ''' Example 7 is an exact equation that fails under the exact engine. It is caught by first order homogeneous albeit with a much contorted solution. The exact engine fails because of a poorly simplified integral of q(0,y)dy, where q is the function multiplying f'. The solutions should be Eq(sqrt(x**2+f(x)**2)**3+y**3, C1). The equation below is equivalent, but it is so complex that checkodesol fails, and takes a long time to do so. ''' return { 'hint': "1st_exact", 'func': f(x), 'examples':{ '1st_exact_01': { 'eq': sin(x)*cos(f(x)) + cos(x)*sin(f(x))*f(x).diff(x), 'sol': [Eq(f(x), -acos(C1/cos(x)) + 2*pi), Eq(f(x), acos(C1/cos(x)))], 'slow': True, }, '1st_exact_02': { 'eq': (2*x*f(x) + 1)/f(x) + (f(x) - x)/f(x)**2*f(x).diff(x), 'sol': [Eq(f(x), exp(C1 - x**2 + LambertW(-x*exp(-C1 + x**2))))], 'XFAIL': ['lie_group'], #It shows dsolve raises an exception: List index out of range for lie_group 'slow': True, 'checkodesol_XFAIL':True }, '1st_exact_03': { 'eq': 2*x + f(x)*cos(x) + (2*f(x) + sin(x) - sin(f(x)))*f(x).diff(x), 'sol': [Eq(f(x)*sin(x) + cos(f(x)) + x**2 + f(x)**2, C1)], 'XFAIL': ['lie_group'], #It goes into infinite loop for lie_group. 'slow': True, }, '1st_exact_04': { 'eq': cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), 'sol': [Eq(x*cos(f(x)) + f(x)**3/3, C1)], 'slow': True, }, '1st_exact_05': { 'eq': 2*x*f(x) + (x**2 + f(x)**2)*f(x).diff(x), 'sol': [Eq(x**2*f(x) + f(x)**3/3, C1)], 'slow': True, 'simplify_flag':False }, # This was from issue: https://github.com/sympy/sympy/issues/11290 '1st_exact_06': { 'eq': cos(f(x)) - (x*sin(f(x)) - f(x)**2)*f(x).diff(x), 'sol': [Eq(x*cos(f(x)) + f(x)**3/3, C1)], 'simplify_flag':False }, '1st_exact_07': { 'eq': x*sqrt(x**2 + f(x)**2) - (x**2*f(x)/(f(x) - sqrt(x**2 + f(x)**2)))*f(x).diff(x), 'sol': [Eq(log(x), C1 - 9*sqrt(1 + f(x)**2/x**2)*asinh(f(x)/x)/(-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2)) - 9*sqrt(1 + f(x)**2/x**2)* log(1 - sqrt(1 + f(x)**2/x**2)*f(x)/x + 2*f(x)**2/x**2)/ (-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2)) + 9*asinh(f(x)/x)*f(x)/(x*(-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2))) + 9*f(x)*log(1 - sqrt(1 + f(x)**2/x**2)*f(x)/x + 2*f(x)**2/x**2)/ (x*(-27*f(x)/x + 27*sqrt(1 + f(x)**2/x**2))))], 'slow': True, 'dsolve_too_slow':True }, # Type: a(x)f'(x)+b(x)*f(x)+c(x)=0 '1st_exact_08': { 'eq': Eq(x**2*f(x).diff(x) + 3*x*f(x) - sin(x)/x, 0), 'sol': [Eq(f(x), (C1 - cos(x))/x**3)], }, # these examples are from test_exact_enhancement '1st_exact_09': { 'eq': f(x)/x**2 + ((f(x)*x - 1)/x)*f(x).diff(x), 'sol': [Eq(f(x), (i*sqrt(C1*x**2 + 1) + 1)/x) for i in (-1, 1)], }, '1st_exact_10': { 'eq': (x*f(x) - 1) + f(x).diff(x)*(x**2 - x*f(x)), 'sol': [Eq(f(x), x - sqrt(C1 + x**2 - 2*log(x))), Eq(f(x), x + sqrt(C1 + x**2 - 2*log(x)))], }, '1st_exact_11': { 'eq': (x + 2)*sin(f(x)) + f(x).diff(x)*x*cos(f(x)), 'sol': [Eq(f(x), -asin(C1*exp(-x)/x**2) + pi), Eq(f(x), asin(C1*exp(-x)/x**2))], }, } } @_add_example_keys def _get_examples_ode_sol_nth_linear_var_of_parameters(): g = exp(-x) f2 = f(x).diff(x, 2) c = 3*f(x).diff(x, 3) + 5*f2 + f(x).diff(x) - f(x) - x return { 'hint': "nth_linear_constant_coeff_variation_of_parameters", 'func': f(x), 'examples':{ 'var_of_parameters_01': { 'eq': c - x*g, 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x**2/24 - 3*x/32))*exp(-x) - 1)], 'slow': True, }, 'var_of_parameters_02': { 'eq': c - g, 'sol': [Eq(f(x), C3*exp(x/3) - x + (C1 + x*(C2 - x/8))*exp(-x) - 1)], 'slow': True, }, 'var_of_parameters_03': { 'eq': f(x).diff(x) - 1, 'sol': [Eq(f(x), C1 + x)], 'slow': True, }, 'var_of_parameters_04': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 4, 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2)], 'slow': True, }, 'var_of_parameters_05': { 'eq': f2 + 3*f(x).diff(x) + 2*f(x) - 12*exp(x), 'sol': [Eq(f(x), C1*exp(-2*x) + C2*exp(-x) + 2*exp(x))], 'slow': True, }, 'var_of_parameters_06': { 'eq': f2 - 2*f(x).diff(x) - 8*f(x) - 9*x*exp(x) - 10*exp(-x), 'sol': [Eq(f(x), -x*exp(x) - 2*exp(-x) + C1*exp(-2*x) + C2*exp(4*x))], 'slow': True, }, 'var_of_parameters_07': { 'eq': f2 + 2*f(x).diff(x) + f(x) - x**2*exp(-x), 'sol': [Eq(f(x), (C1 + x*(C2 + x**3/12))*exp(-x))], 'slow': True, }, 'var_of_parameters_08': { 'eq': f2 - 3*f(x).diff(x) + 2*f(x) - x*exp(-x), 'sol': [Eq(f(x), C1*exp(x) + C2*exp(2*x) + (6*x + 5)*exp(-x)/36)], 'slow': True, }, 'var_of_parameters_09': { 'eq': f(x).diff(x, 3) - 3*f2 + 3*f(x).diff(x) - f(x) - exp(x), 'sol': [Eq(f(x), (C1 + x*(C2 + x*(C3 + x/6)))*exp(x))], 'slow': True, }, 'var_of_parameters_10': { 'eq': f2 + 2*f(x).diff(x) + f(x) - exp(-x)/x, 'sol': [Eq(f(x), (C1 + x*(C2 + log(x)))*exp(-x))], 'slow': True, }, 'var_of_parameters_11': { 'eq': f2 + f(x) - 1/sin(x)*1/cos(x), 'sol': [Eq(f(x), (C1 + log(sin(x) - 1)/2 - log(sin(x) + 1)/2 )*cos(x) + (C2 + log(cos(x) - 1)/2 - log(cos(x) + 1)/2)*sin(x))], 'slow': True, }, 'var_of_parameters_12': { 'eq': f(x).diff(x, 4) - 1/x, 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + x**3*(C4 + log(x)/6))], 'slow': True, }, # These were from issue: https://github.com/sympy/sympy/issues/15996 'var_of_parameters_13': { 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - 2*x - exp(I*x), 'sol': [Eq(f(x), C1 + x**2 + (C2 + x*(C3 - x/8 + 3*exp(I*x)/2 + 3*exp(-I*x)/2) + 5*exp(2*I*x)/16 + 2*I*exp(I*x) - 2*I*exp(-I*x))*sin(x) + (C4 + x*(C5 + I*x/8 + 3*I*exp(I*x)/2 - 3*I*exp(-I*x)/2) + 5*I*exp(2*I*x)/16 - 2*exp(I*x) - 2*exp(-I*x))*cos(x) - I*exp(I*x))], }, 'var_of_parameters_14': { 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x) - exp(I*x), 'sol': [Eq(f(x), C1 + (C2 + x*(C3 - x/8) + 5*exp(2*I*x)/16)*sin(x) + (C4 + x*(C5 + I*x/8) + 5*I*exp(2*I*x)/16)*cos(x) - I*exp(I*x))], }, # https://github.com/sympy/sympy/issues/14395 'var_of_parameters_15': { 'eq': Derivative(f(x), x, x) + 9*f(x) - sec(x), 'sol': [Eq(f(x), (C1 - x/3 + sin(2*x)/3)*sin(3*x) + (C2 + log(cos(x)) - 2*log(cos(x)**2)/3 + 2*cos(x)**2/3)*cos(3*x))], 'slow': True, }, } } @_add_example_keys def _get_examples_ode_sol_2nd_linear_bessel(): return { 'hint': "2nd_linear_bessel", 'func': f(x), 'examples':{ '2nd_lin_bessel_01': { 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 - 4)*f(x), 'sol': [Eq(f(x), C1*besselj(2, x) + C2*bessely(2, x))], }, '2nd_lin_bessel_02': { 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 +25)*f(x), 'sol': [Eq(f(x), C1*besselj(5*I, x) + C2*bessely(5*I, x))], }, '2nd_lin_bessel_03': { 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2)*f(x), 'sol': [Eq(f(x), C1*besselj(0, x) + C2*bessely(0, x))], }, '2nd_lin_bessel_04': { 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (81*x**2 -S(1)/9)*f(x), 'sol': [Eq(f(x), C1*besselj(S(1)/3, 9*x) + C2*bessely(S(1)/3, 9*x))], }, '2nd_lin_bessel_05': { 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**4 - 4)*f(x), 'sol': [Eq(f(x), C1*besselj(1, x**2/2) + C2*bessely(1, x**2/2))], }, '2nd_lin_bessel_06': { 'eq': x**2*(f(x).diff(x, 2)) + 2*x*(f(x).diff(x)) + (x**4 - 4)*f(x), 'sol': [Eq(f(x), (C1*besselj(sqrt(17)/4, x**2/2) + C2*bessely(sqrt(17)/4, x**2/2))/sqrt(x))], }, '2nd_lin_bessel_07': { 'eq': x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (x**2 - S(1)/4)*f(x), 'sol': [Eq(f(x), C1*besselj(S(1)/2, x) + C2*bessely(S(1)/2, x))], }, '2nd_lin_bessel_08': { 'eq': x**2*(f(x).diff(x, 2)) - 3*x*(f(x).diff(x)) + (4*x + 4)*f(x), 'sol': [Eq(f(x), x**2*(C1*besselj(0, 4*sqrt(x)) + C2*bessely(0, 4*sqrt(x))))], }, '2nd_lin_bessel_09': { 'eq': x*(f(x).diff(x, 2)) - f(x).diff(x) + 4*x**3*f(x), 'sol': [Eq(f(x), x*(C1*besselj(S(1)/2, x**2) + C2*bessely(S(1)/2, x**2)))], }, '2nd_lin_bessel_10': { 'eq': (x-2)**2*(f(x).diff(x, 2)) - (x-2)*f(x).diff(x) + 4*(x-2)**2*f(x), 'sol': [Eq(f(x), (x - 2)*(C1*besselj(1, 2*x - 4) + C2*bessely(1, 2*x - 4)))], }, # https://github.com/sympy/sympy/issues/4414 '2nd_lin_bessel_11': { 'eq': f(x).diff(x, x) + 2/x*f(x).diff(x) + f(x), 'sol': [Eq(f(x), (C1*besselj(S(1)/2, x) + C2*bessely(S(1)/2, x))/sqrt(x))], }, } } @_add_example_keys def _get_examples_ode_sol_2nd_2F1_hypergeometric(): return { 'hint': "2nd_hypergeometric", 'func': f(x), 'examples':{ '2nd_2F1_hyper_01': { 'eq': x*(x-1)*f(x).diff(x, 2) + (S(3)/2 -2*x)*f(x).diff(x) + 2*f(x), 'sol': [Eq(f(x), C1*x**(S(5)/2)*hyper((S(3)/2, S(1)/2), (S(7)/2,), x) + C2*hyper((-1, -2), (-S(3)/2,), x))], }, '2nd_2F1_hyper_02': { 'eq': x*(x-1)*f(x).diff(x, 2) + (S(7)/2*x)*f(x).diff(x) + f(x), 'sol': [Eq(f(x), (C1*(1 - x)**(S(5)/2)*hyper((S(1)/2, 2), (S(7)/2,), 1 - x) + C2*hyper((-S(1)/2, -2), (-S(3)/2,), 1 - x))/(x - 1)**(S(5)/2))], }, '2nd_2F1_hyper_03': { 'eq': x*(x-1)*f(x).diff(x, 2) + (S(3)+ S(7)/2*x)*f(x).diff(x) + f(x), 'sol': [Eq(f(x), (C1*(1 - x)**(S(11)/2)*hyper((S(1)/2, 2), (S(13)/2,), 1 - x) + C2*hyper((-S(7)/2, -5), (-S(9)/2,), 1 - x))/(x - 1)**(S(11)/2))], }, '2nd_2F1_hyper_04': { 'eq': -x**(S(5)/7)*(-416*x**(S(9)/7)/9 - 2385*x**(S(5)/7)/49 + S(298)*x/3)*f(x)/(196*(-x**(S(6)/7) + x)**2*(x**(S(6)/7) + x)**2) + Derivative(f(x), (x, 2)), 'sol': [Eq(f(x), x**(S(45)/98)*(C1*x**(S(4)/49)*hyper((S(1)/3, -S(1)/2), (S(9)/7,), x**(S(2)/7)) + C2*hyper((S(1)/21, -S(11)/14), (S(5)/7,), x**(S(2)/7)))/(x**(S(2)/7) - 1)**(S(19)/84))], 'checkodesol_XFAIL':True, }, } } @_add_example_keys def _get_examples_ode_sol_2nd_nonlinear_autonomous_conserved(): return { 'hint': "2nd_nonlinear_autonomous_conserved", 'func': f(x), 'examples': { '2nd_nonlinear_autonomous_conserved_01': { 'eq': f(x).diff(x, 2) + exp(f(x)) + log(f(x)), 'sol': [ Eq(Integral(1/sqrt(C1 - 2*_u*log(_u) + 2*_u - 2*exp(_u)), (_u, f(x))), C2 + x), Eq(Integral(1/sqrt(C1 - 2*_u*log(_u) + 2*_u - 2*exp(_u)), (_u, f(x))), C2 - x) ], 'simplify_flag': False, }, '2nd_nonlinear_autonomous_conserved_02': { 'eq': f(x).diff(x, 2) + cbrt(f(x)) + 1/f(x), 'sol': [ Eq(sqrt(2)*Integral(1/sqrt(2*C1 - 3*_u**Rational(4, 3) - 4*log(_u)), (_u, f(x))), C2 + x), Eq(sqrt(2)*Integral(1/sqrt(2*C1 - 3*_u**Rational(4, 3) - 4*log(_u)), (_u, f(x))), C2 - x) ], 'simplify_flag': False, }, '2nd_nonlinear_autonomous_conserved_03': { 'eq': f(x).diff(x, 2) + sin(f(x)), 'sol': [ Eq(Integral(1/sqrt(C1 + 2*cos(_u)), (_u, f(x))), C2 + x), Eq(Integral(1/sqrt(C1 + 2*cos(_u)), (_u, f(x))), C2 - x) ], 'simplify_flag': False, }, '2nd_nonlinear_autonomous_conserved_04': { 'eq': f(x).diff(x, 2) + cosh(f(x)), 'sol': [ Eq(Integral(1/sqrt(C1 - 2*sinh(_u)), (_u, f(x))), C2 + x), Eq(Integral(1/sqrt(C1 - 2*sinh(_u)), (_u, f(x))), C2 - x) ], 'simplify_flag': False, }, '2nd_nonlinear_autonomous_conserved_05': { 'eq': f(x).diff(x, 2) + asin(f(x)), 'sol': [ Eq(Integral(1/sqrt(C1 - 2*_u*asin(_u) - 2*sqrt(1 - _u**2)), (_u, f(x))), C2 + x), Eq(Integral(1/sqrt(C1 - 2*_u*asin(_u) - 2*sqrt(1 - _u**2)), (_u, f(x))), C2 - x) ], 'simplify_flag': False, 'XFAIL': ['2nd_nonlinear_autonomous_conserved_Integral'] } } } @_add_example_keys def _get_examples_ode_sol_separable_reduced(): df = f(x).diff(x) return { 'hint': "separable_reduced", 'func': f(x), 'examples':{ 'separable_reduced_01': { 'eq': x* df + f(x)* (1 / (x**2*f(x) - 1)), 'sol': [Eq(log(x**2*f(x))/3 + log(x**2*f(x) - Rational(3, 2))/6, C1 + log(x))], 'simplify_flag': False, 'XFAIL': ['lie_group'], #It hangs. }, #Note: 'separable_reduced_02' is referred in 'separable_reduced_11' 'separable_reduced_02': { 'eq': f(x).diff(x) + (f(x) / (x**4*f(x) - x)), 'sol': [Eq(log(x**3*f(x))/4 + log(x**3*f(x) - Rational(4,3))/12, C1 + log(x))], 'simplify_flag': False, 'checkodesol_XFAIL':True, #It hangs for this. }, 'separable_reduced_03': { 'eq': x*df + f(x)*(x**2*f(x)), 'sol': [Eq(log(x**2*f(x))/2 - log(x**2*f(x) - 2)/2, C1 + log(x))], 'simplify_flag': False, }, 'separable_reduced_04': { 'eq': Eq(f(x).diff(x) + f(x)/x * (1 + (x**(S(2)/3)*f(x))**2), 0), 'sol': [Eq(-3*log(x**(S(2)/3)*f(x)) + 3*log(3*x**(S(4)/3)*f(x)**2 + 1)/2, C1 + log(x))], 'simplify_flag': False, }, 'separable_reduced_05': { 'eq': Eq(f(x).diff(x) + f(x)/x * (1 + (x*f(x))**2), 0), 'sol': [Eq(f(x), -sqrt(2)*sqrt(1/(C1 + log(x)))/(2*x)),\ Eq(f(x), sqrt(2)*sqrt(1/(C1 + log(x)))/(2*x))], }, 'separable_reduced_06': { 'eq': Eq(f(x).diff(x) + (x**4*f(x)**2 + x**2*f(x))*f(x)/(x*(x**6*f(x)**3 + x**4*f(x)**2)), 0), 'sol': [Eq(f(x), C1 + 1/(2*x**2))], }, 'separable_reduced_07': { 'eq': Eq(f(x).diff(x) + (f(x)**2)*f(x)/(x), 0), 'sol': [ Eq(f(x), -sqrt(2)*sqrt(1/(C1 + log(x)))/2), Eq(f(x), sqrt(2)*sqrt(1/(C1 + log(x)))/2) ], }, 'separable_reduced_08': { 'eq': Eq(f(x).diff(x) + (f(x)+3)*f(x)/(x*(f(x)+2)), 0), 'sol': [Eq(-log(f(x) + 3)/3 - 2*log(f(x))/3, C1 + log(x))], 'simplify_flag': False, 'XFAIL': ['lie_group'], #It hangs. }, 'separable_reduced_09': { 'eq': Eq(f(x).diff(x) + (f(x)+3)*f(x)/x, 0), 'sol': [Eq(f(x), 3/(C1*x**3 - 1))], }, 'separable_reduced_10': { 'eq': Eq(f(x).diff(x) + (f(x)**2+f(x))*f(x)/(x), 0), 'sol': [Eq(- log(x) - log(f(x) + 1) + log(f(x)) + 1/f(x), C1)], 'XFAIL': ['lie_group'],#No algorithms are implemented to solve equation -C1 + x*(_y + 1)*exp(-1/_y)/_y }, # Equivalent to example_name 'separable_reduced_02'. Only difference is testing with simplify=True 'separable_reduced_11': { 'eq': f(x).diff(x) + (f(x) / (x**4*f(x) - x)), 'sol': [Eq(f(x), -sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 - sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 4/x**6 - 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3)), Eq(f(x), -sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 + sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 4/x**6 - 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3)), Eq(f(x), sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 - sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 4/x**6 + 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3)), Eq(f(x), sqrt(2)*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)/6 + sqrt(2)*sqrt(-3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 4/x**6 + 4*sqrt(2)/(x**9*sqrt(3*3**Rational(1,3)*(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) - 3*3**Rational(2,3)*exp(12*C1)/(sqrt((3*exp(12*C1) + x**(-12))*exp(24*C1)) - exp(12*C1)/x**6)**Rational(1,3) + 2/x**6)))/6 + 1/(3*x**3))], 'checkodesol_XFAIL':True, #It hangs for this. 'slow': True, }, #These were from issue: https://github.com/sympy/sympy/issues/6247 'separable_reduced_12': { 'eq': x**2*f(x)**2 + x*Derivative(f(x), x), 'sol': [Eq(f(x), 2*C1/(C1*x**2 - 1))], }, } } @_add_example_keys def _get_examples_ode_sol_lie_group(): a, b, c = symbols("a b c") return { 'hint': "lie_group", 'func': f(x), 'examples':{ #Example 1-4 and 19-20 were from issue: https://github.com/sympy/sympy/issues/17322 'lie_group_01': { 'eq': x*f(x).diff(x)*(f(x)+4) + (f(x)**2) -2*f(x)-2*x, 'sol': [], 'dsolve_too_slow': True, 'checkodesol_too_slow': True, }, 'lie_group_02': { 'eq': x*f(x).diff(x)*(f(x)+4) + (f(x)**2) -2*f(x)-2*x, 'sol': [], 'dsolve_too_slow': True, }, 'lie_group_03': { 'eq': Eq(x**7*Derivative(f(x), x) + 5*x**3*f(x)**2 - (2*x**2 + 2)*f(x)**3, 0), 'sol': [], 'dsolve_too_slow': True, }, 'lie_group_04': { 'eq': f(x).diff(x) - (f(x) - x*log(x))**2/x**2 + log(x), 'sol': [], 'XFAIL': ['lie_group'], }, 'lie_group_05': { 'eq': f(x).diff(x)**2, 'sol': [Eq(f(x), C1)], 'XFAIL': ['factorable'], #It raises Not Implemented error }, 'lie_group_06': { 'eq': Eq(f(x).diff(x), x**2*f(x)), 'sol': [Eq(f(x), C1*exp(x**3)**Rational(1, 3))], }, 'lie_group_07': { 'eq': f(x).diff(x) + a*f(x) - c*exp(b*x), 'sol': [Eq(f(x), Piecewise(((-C1*(a + b) + c*exp(x*(a + b)))*exp(-a*x)/(a + b),\ Ne(a, -b)), ((-C1 + c*x)*exp(-a*x), True)))], }, 'lie_group_08': { 'eq': f(x).diff(x) + 2*x*f(x) - x*exp(-x**2), 'sol': [Eq(f(x), (C1 + x**2/2)*exp(-x**2))], }, 'lie_group_09': { 'eq': (1 + 2*x)*(f(x).diff(x)) + 2 - 4*exp(-f(x)), 'sol': [Eq(f(x), log(C1/(2*x + 1) + 2))], }, 'lie_group_10': { 'eq': x**2*(f(x).diff(x)) - f(x) + x**2*exp(x - (1/x)), 'sol': [Eq(f(x), -((C1 + exp(x))*exp(-1/x)))], 'XFAIL': ['factorable'], #It raises Recursion Error (maixmum depth exceeded) }, 'lie_group_11': { 'eq': x**2*f(x)**2 + x*Derivative(f(x), x), 'sol': [Eq(f(x), 2/(C1 + x**2))], }, 'lie_group_12': { 'eq': diff(f(x),x) + 2*x*f(x) - x*exp(-x**2), 'sol': [Eq(f(x), exp(-x**2)*(C1 + x**2/2))], }, 'lie_group_13': { 'eq': diff(f(x),x) + f(x)*cos(x) - exp(2*x), 'sol': [Eq(f(x), exp(-sin(x))*(C1 + Integral(exp(2*x)*exp(sin(x)), x)))], }, 'lie_group_14': { 'eq': diff(f(x),x) + f(x)*cos(x) - sin(2*x)/2, 'sol': [Eq(f(x), C1*exp(-sin(x)) + sin(x) - 1)], }, 'lie_group_15': { 'eq': x*diff(f(x),x) + f(x) - x*sin(x), 'sol': [Eq(f(x), (C1 - x*cos(x) + sin(x))/x)], }, 'lie_group_16': { 'eq': x*diff(f(x),x) - f(x) - x/log(x), 'sol': [Eq(f(x), x*(C1 + log(log(x))))], }, 'lie_group_17': { 'eq': (f(x).diff(x)-f(x)) * (f(x).diff(x)+f(x)), 'sol': [Eq(f(x), C1*exp(x)), Eq(f(x), C1*exp(-x))], }, 'lie_group_18': { 'eq': f(x).diff(x) * (f(x).diff(x) - f(x)), 'sol': [Eq(f(x), C1*exp(x)), Eq(f(x), C1)], }, 'lie_group_19': { 'eq': (f(x).diff(x)-f(x)) * (f(x).diff(x)+f(x)), 'sol': [Eq(f(x), C1*exp(-x)), Eq(f(x), C1*exp(x))], }, 'lie_group_20': { 'eq': f(x).diff(x)*(f(x).diff(x)+f(x)), 'sol': [Eq(f(x), C1), Eq(f(x), C1*exp(-x))], }, } } @_add_example_keys def _get_examples_ode_sol_2nd_linear_airy(): return { 'hint': "2nd_linear_airy", 'func': f(x), 'examples':{ '2nd_lin_airy_01': { 'eq': f(x).diff(x, 2) - x*f(x), 'sol': [Eq(f(x), C1*airyai(x) + C2*airybi(x))], }, '2nd_lin_airy_02': { 'eq': f(x).diff(x, 2) + 2*x*f(x), 'sol': [Eq(f(x), C1*airyai(-2**(S(1)/3)*x) + C2*airybi(-2**(S(1)/3)*x))], }, } } @_add_example_keys def _get_examples_ode_sol_nth_linear_constant_coeff_homogeneous(): # From Exercise 20, in Ordinary Differential Equations, # Tenenbaum and Pollard, pg. 220 a = Symbol('a', positive=True) k = Symbol('k', real=True) r1, r2, r3, r4, r5 = [rootof(x**5 + 11*x - 2, n) for n in range(5)] r6, r7, r8, r9, r10 = [rootof(x**5 - 3*x + 1, n) for n in range(5)] r11, r12, r13, r14, r15 = [rootof(x**5 - 100*x**3 + 1000*x + 1, n) for n in range(5)] r16, r17, r18, r19, r20 = [rootof(x**5 - x**4 + 10, n) for n in range(5)] r21, r22, r23, r24, r25 = [rootof(x**5 - x + 1, n) for n in range(5)] E = exp(1) return { 'hint': "nth_linear_constant_coeff_homogeneous", 'func': f(x), 'examples':{ 'lin_const_coeff_hom_01': { 'eq': f(x).diff(x, 2) + 2*f(x).diff(x), 'sol': [Eq(f(x), C1 + C2*exp(-2*x))], }, 'lin_const_coeff_hom_02': { 'eq': f(x).diff(x, 2) - 3*f(x).diff(x) + 2*f(x), 'sol': [Eq(f(x), (C1 + C2*exp(x))*exp(x))], }, 'lin_const_coeff_hom_03': { 'eq': f(x).diff(x, 2) - f(x), 'sol': [Eq(f(x), C1*exp(-x) + C2*exp(x))], }, 'lin_const_coeff_hom_04': { 'eq': f(x).diff(x, 3) + f(x).diff(x, 2) - 6*f(x).diff(x), 'sol': [Eq(f(x), C1 + C2*exp(-3*x) + C3*exp(2*x))], 'slow': True, }, 'lin_const_coeff_hom_05': { 'eq': 6*f(x).diff(x, 2) - 11*f(x).diff(x) + 4*f(x), 'sol': [Eq(f(x), C1*exp(x/2) + C2*exp(x*Rational(4, 3)))], 'slow': True, }, 'lin_const_coeff_hom_06': { 'eq': Eq(f(x).diff(x, 2) + 2*f(x).diff(x) - f(x), 0), 'sol': [Eq(f(x), C1*exp(x*(-1 + sqrt(2))) + C2*exp(x*(-sqrt(2) - 1)))], 'slow': True, }, 'lin_const_coeff_hom_07': { 'eq': diff(f(x), x, 3) + diff(f(x), x, 2) - 10*diff(f(x), x) - 6*f(x), 'sol': [Eq(f(x), C1*exp(3*x) + C2*exp(x*(-2 - sqrt(2))) + C3*exp(x*(-2 + sqrt(2))))], 'slow': True, }, 'lin_const_coeff_hom_08': { 'eq': f(x).diff(x, 4) - f(x).diff(x, 3) - 4*f(x).diff(x, 2) + \ 4*f(x).diff(x), 'sol': [Eq(f(x), C1 + C2*exp(-2*x) + C3*exp(x) + C4*exp(2*x))], 'slow': True, }, 'lin_const_coeff_hom_09': { 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 3) + f(x).diff(x, 2) - \ 4*f(x).diff(x) - 2*f(x), 'sol': [Eq(f(x), C3*exp(-x) + C4*exp(x) + (C1*exp(-sqrt(2)*x) + C2*exp(sqrt(2)*x))*exp(-2*x))], 'slow': True, }, 'lin_const_coeff_hom_10': { 'eq': f(x).diff(x, 4) - a**2*f(x), 'sol': [Eq(f(x), C1*exp(-sqrt(a)*x) + C2*exp(sqrt(a)*x) + C3*sin(sqrt(a)*x) + C4*cos(sqrt(a)*x))], 'slow': True, }, 'lin_const_coeff_hom_11': { 'eq': f(x).diff(x, 2) - 2*k*f(x).diff(x) - 2*f(x), 'sol': [Eq(f(x), C1*exp(x*(k - sqrt(k**2 + 2))) + C2*exp(x*(k + sqrt(k**2 + 2))))], 'slow': True, }, 'lin_const_coeff_hom_12': { 'eq': f(x).diff(x, 2) + 4*k*f(x).diff(x) - 12*k**2*f(x), 'sol': [Eq(f(x), C1*exp(-6*k*x) + C2*exp(2*k*x))], 'slow': True, }, 'lin_const_coeff_hom_13': { 'eq': f(x).diff(x, 4), 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + C4*x**3)], 'slow': True, }, 'lin_const_coeff_hom_14': { 'eq': f(x).diff(x, 2) + 4*f(x).diff(x) + 4*f(x), 'sol': [Eq(f(x), (C1 + C2*x)*exp(-2*x))], 'slow': True, }, 'lin_const_coeff_hom_15': { 'eq': 3*f(x).diff(x, 3) + 5*f(x).diff(x, 2) + f(x).diff(x) - f(x), 'sol': [Eq(f(x), (C1 + C2*x)*exp(-x) + C3*exp(x/3))], 'slow': True, }, 'lin_const_coeff_hom_16': { 'eq': f(x).diff(x, 3) - 6*f(x).diff(x, 2) + 12*f(x).diff(x) - 8*f(x), 'sol': [Eq(f(x), (C1 + x*(C2 + C3*x))*exp(2*x))], 'slow': True, }, 'lin_const_coeff_hom_17': { 'eq': f(x).diff(x, 2) - 2*a*f(x).diff(x) + a**2*f(x), 'sol': [Eq(f(x), (C1 + C2*x)*exp(a*x))], 'slow': True, }, 'lin_const_coeff_hom_18': { 'eq': f(x).diff(x, 4) + 3*f(x).diff(x, 3), 'sol': [Eq(f(x), C1 + C2*x + C3*x**2 + C4*exp(-3*x))], 'slow': True, }, 'lin_const_coeff_hom_19': { 'eq': f(x).diff(x, 4) - 2*f(x).diff(x, 2), 'sol': [Eq(f(x), C1 + C2*x + C3*exp(-sqrt(2)*x) + C4*exp(sqrt(2)*x))], 'slow': True, }, 'lin_const_coeff_hom_20': { 'eq': f(x).diff(x, 4) + 2*f(x).diff(x, 3) - 11*f(x).diff(x, 2) - \ 12*f(x).diff(x) + 36*f(x), 'sol': [Eq(f(x), (C1 + C2*x)*exp(-3*x) + (C3 + C4*x)*exp(2*x))], 'slow': True, }, 'lin_const_coeff_hom_21': { 'eq': 36*f(x).diff(x, 4) - 37*f(x).diff(x, 2) + 4*f(x).diff(x) + 5*f(x), 'sol': [Eq(f(x), C1*exp(-x) + C2*exp(-x/3) + C3*exp(x/2) + C4*exp(x*Rational(5, 6)))], 'slow': True, }, 'lin_const_coeff_hom_22': { 'eq': f(x).diff(x, 4) - 8*f(x).diff(x, 2) + 16*f(x), 'sol': [Eq(f(x), (C1 + C2*x)*exp(-2*x) + (C3 + C4*x)*exp(2*x))], 'slow': True, }, 'lin_const_coeff_hom_23': { 'eq': f(x).diff(x, 2) - 2*f(x).diff(x) + 5*f(x), 'sol': [Eq(f(x), (C1*sin(2*x) + C2*cos(2*x))*exp(x))], 'slow': True, }, 'lin_const_coeff_hom_24': { 'eq': f(x).diff(x, 2) - f(x).diff(x) + f(x), 'sol': [Eq(f(x), (C1*sin(x*sqrt(3)/2) + C2*cos(x*sqrt(3)/2))*exp(x/2))], 'slow': True, }, 'lin_const_coeff_hom_25': { 'eq': f(x).diff(x, 4) + 5*f(x).diff(x, 2) + 6*f(x), 'sol': [Eq(f(x), C1*sin(sqrt(2)*x) + C2*sin(sqrt(3)*x) + C3*cos(sqrt(2)*x) + C4*cos(sqrt(3)*x))], 'slow': True, }, 'lin_const_coeff_hom_26': { 'eq': f(x).diff(x, 2) - 4*f(x).diff(x) + 20*f(x), 'sol': [Eq(f(x), (C1*sin(4*x) + C2*cos(4*x))*exp(2*x))], 'slow': True, }, 'lin_const_coeff_hom_27': { 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2) + 4*f(x), 'sol': [Eq(f(x), (C1 + C2*x)*sin(x*sqrt(2)) + (C3 + C4*x)*cos(x*sqrt(2)))], 'slow': True, }, 'lin_const_coeff_hom_28': { 'eq': f(x).diff(x, 3) + 8*f(x), 'sol': [Eq(f(x), (C1*sin(x*sqrt(3)) + C2*cos(x*sqrt(3)))*exp(x) + C3*exp(-2*x))], 'slow': True, }, 'lin_const_coeff_hom_29': { 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2), 'sol': [Eq(f(x), C1 + C2*x + C3*sin(2*x) + C4*cos(2*x))], 'slow': True, }, 'lin_const_coeff_hom_30': { 'eq': f(x).diff(x, 5) + 2*f(x).diff(x, 3) + f(x).diff(x), 'sol': [Eq(f(x), C1 + (C2 + C3*x)*sin(x) + (C4 + C5*x)*cos(x))], 'slow': True, }, 'lin_const_coeff_hom_31': { 'eq': f(x).diff(x, 4) + f(x).diff(x, 2) + f(x), 'sol': [Eq(f(x), (C1*sin(sqrt(3)*x/2) + C2*cos(sqrt(3)*x/2))*exp(-x/2) + (C3*sin(sqrt(3)*x/2) + C4*cos(sqrt(3)*x/2))*exp(x/2))], 'slow': True, }, 'lin_const_coeff_hom_32': { 'eq': f(x).diff(x, 4) + 4*f(x).diff(x, 2) + f(x), 'sol': [Eq(f(x), C1*sin(x*sqrt(-sqrt(3) + 2)) + C2*sin(x*sqrt(sqrt(3) + 2)) + C3*cos(x*sqrt(-sqrt(3) + 2)) + C4*cos(x*sqrt(sqrt(3) + 2)))], 'slow': True, }, # One real root, two complex conjugate pairs 'lin_const_coeff_hom_33': { 'eq': f(x).diff(x, 5) + 11*f(x).diff(x) - 2*f(x), 'sol': [Eq(f(x), C5*exp(r1*x) + exp(re(r2)*x) * (C1*sin(im(r2)*x) + C2*cos(im(r2)*x)) + exp(re(r4)*x) * (C3*sin(im(r4)*x) + C4*cos(im(r4)*x)))], 'checkodesol_XFAIL':True, #It Hangs }, # Three real roots, one complex conjugate pair 'lin_const_coeff_hom_34': { 'eq': f(x).diff(x,5) - 3*f(x).diff(x) + f(x), 'sol': [Eq(f(x), C3*exp(r6*x) + C4*exp(r7*x) + C5*exp(r8*x) + exp(re(r9)*x) * (C1*sin(im(r9)*x) + C2*cos(im(r9)*x)))], 'checkodesol_XFAIL':True, #It Hangs }, # Five distinct real roots 'lin_const_coeff_hom_35': { 'eq': f(x).diff(x,5) - 100*f(x).diff(x,3) + 1000*f(x).diff(x) + f(x), 'sol': [Eq(f(x), C1*exp(r11*x) + C2*exp(r12*x) + C3*exp(r13*x) + C4*exp(r14*x) + C5*exp(r15*x))], 'checkodesol_XFAIL':True, #It Hangs }, # Rational root and unsolvable quintic 'lin_const_coeff_hom_36': { 'eq': f(x).diff(x, 6) - 6*f(x).diff(x, 5) + 5*f(x).diff(x, 4) + 10*f(x).diff(x) - 50 * f(x), 'sol': [Eq(f(x), C5*exp(5*x) + C6*exp(x*r16) + exp(re(r17)*x) * (C1*sin(im(r17)*x) + C2*cos(im(r17)*x)) + exp(re(r19)*x) * (C3*sin(im(r19)*x) + C4*cos(im(r19)*x)))], 'checkodesol_XFAIL':True, #It Hangs }, # Five double roots (this is (x**5 - x + 1)**2) 'lin_const_coeff_hom_37': { 'eq': f(x).diff(x, 10) - 2*f(x).diff(x, 6) + 2*f(x).diff(x, 5) + f(x).diff(x, 2) - 2*f(x).diff(x, 1) + f(x), 'sol': [Eq(f(x), (C1 + C2*x)*exp(x*r21) + (-((C3 + C4*x)*sin(x*im(r22))) + (C5 + C6*x)*cos(x*im(r22)))*exp(x*re(r22)) + (-((C7 + C8*x)*sin(x*im(r24))) + (C10*x + C9)*cos(x*im(r24)))*exp(x*re(r24)))], 'checkodesol_XFAIL':True, #It Hangs }, 'lin_const_coeff_hom_38': { 'eq': Eq(sqrt(2) * f(x).diff(x,x,x) + f(x).diff(x), 0), 'sol': [Eq(f(x), C1 + C2*sin(2**Rational(3, 4)*x/2) + C3*cos(2**Rational(3, 4)*x/2))], }, 'lin_const_coeff_hom_39': { 'eq': Eq(E * f(x).diff(x,x,x) + f(x).diff(x), 0), 'sol': [Eq(f(x), C1 + C2*sin(x/sqrt(E)) + C3*cos(x/sqrt(E)))], }, 'lin_const_coeff_hom_40': { 'eq': Eq(pi * f(x).diff(x,x,x) + f(x).diff(x), 0), 'sol': [Eq(f(x), C1 + C2*sin(x/sqrt(pi)) + C3*cos(x/sqrt(pi)))], }, 'lin_const_coeff_hom_41': { 'eq': Eq(I * f(x).diff(x,x,x) + f(x).diff(x), 0), 'sol': [Eq(f(x), C1 + C2*exp(-sqrt(I)*x) + C3*exp(sqrt(I)*x))], }, 'lin_const_coeff_hom_42': { 'eq': f(x).diff(x, x) + y*f(x), 'sol': [Eq(f(x), C1*exp(-x*sqrt(-y)) + C2*exp(x*sqrt(-y)))], }, 'lin_const_coeff_hom_43': { 'eq': Eq(9*f(x).diff(x, x) + f(x), 0), 'sol': [Eq(f(x), C1*sin(x/3) + C2*cos(x/3))], }, 'lin_const_coeff_hom_44': { 'eq': Eq(9*f(x).diff(x, x), f(x)), 'sol': [Eq(f(x), C1*exp(-x/3) + C2*exp(x/3))], }, 'lin_const_coeff_hom_45': { 'eq': Eq(f(x).diff(x, x) - 3*diff(f(x), x) + 2*f(x), 0), 'sol': [Eq(f(x), (C1 + C2*exp(x))*exp(x))], }, 'lin_const_coeff_hom_46': { 'eq': Eq(f(x).diff(x, x) - 4*diff(f(x), x) + 4*f(x), 0), 'sol': [Eq(f(x), (C1 + C2*x)*exp(2*x))], }, # Type: 2nd order, constant coefficients (two real equal roots) 'lin_const_coeff_hom_47': { 'eq': Eq(f(x).diff(x, x) + 2*diff(f(x), x) + 3*f(x), 0), 'sol': [Eq(f(x), (C1*sin(x*sqrt(2)) + C2*cos(x*sqrt(2)))*exp(-x))], }, #These were from issue: https://github.com/sympy/sympy/issues/6247 'lin_const_coeff_hom_48': { 'eq': f(x).diff(x, x) + 4*f(x), 'sol': [Eq(f(x), C1*sin(2*x) + C2*cos(2*x))], }, } } @_add_example_keys def _get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep(): return { 'hint': "1st_homogeneous_coeff_subs_dep_div_indep", 'func': f(x), 'examples':{ 'dep_div_indep_01': { 'eq': f(x)/x*cos(f(x)/x) - (x/f(x)*sin(f(x)/x) + cos(f(x)/x))*f(x).diff(x), 'sol': [Eq(log(x), C1 - log(f(x)*sin(f(x)/x)/x))], 'slow': True }, #indep_div_dep actually has a simpler solution for example 2 but it runs too slow. 'dep_div_indep_02': { 'eq': x*f(x).diff(x) - f(x) - x*sin(f(x)/x), 'sol': [Eq(log(x), log(C1) + log(cos(f(x)/x) - 1)/2 - log(cos(f(x)/x) + 1)/2)], 'simplify_flag':False, }, 'dep_div_indep_03': { 'eq': x*exp(f(x)/x) - f(x)*sin(f(x)/x) + x*sin(f(x)/x)*f(x).diff(x), 'sol': [Eq(log(x), C1 + exp(-f(x)/x)*sin(f(x)/x)/2 + exp(-f(x)/x)*cos(f(x)/x)/2)], 'slow': True }, 'dep_div_indep_04': { 'eq': f(x).diff(x) - f(x)/x + 1/sin(f(x)/x), 'sol': [Eq(f(x), x*(-acos(C1 + log(x)) + 2*pi)), Eq(f(x), x*acos(C1 + log(x)))], 'slow': True }, # previous code was testing with these other solution: # example5_solb = Eq(f(x), log(log(C1/x)**(-x))) 'dep_div_indep_05': { 'eq': x*exp(f(x)/x) + f(x) - x*f(x).diff(x), 'sol': [Eq(f(x), log((1/(C1 - log(x)))**x))], 'checkodesol_XFAIL':True, #(because of **x?) }, } } @_add_example_keys def _get_examples_ode_sol_linear_coefficients(): return { 'hint': "linear_coefficients", 'func': f(x), 'examples':{ 'linear_coeff_01': { 'eq': f(x).diff(x) + (3 + 2*f(x))/(x + 3), 'sol': [Eq(f(x), C1/(x**2 + 6*x + 9) - Rational(3, 2))], }, } } @_add_example_keys def _get_examples_ode_sol_1st_homogeneous_coeff_best(): return { 'hint': "1st_homogeneous_coeff_best", 'func': f(x), 'examples':{ # previous code was testing this with other solution: # example1_solb = Eq(-f(x)/(1 + log(x/f(x))), C1) '1st_homogeneous_coeff_best_01': { 'eq': f(x) + (x*log(f(x)/x) - 2*x)*diff(f(x), x), 'sol': [Eq(f(x), -exp(C1)*LambertW(-x*exp(-C1 + 1)))], 'checkodesol_XFAIL':True, #(because of LambertW?) }, '1st_homogeneous_coeff_best_02': { 'eq': 2*f(x)*exp(x/f(x)) + f(x)*f(x).diff(x) - 2*x*exp(x/f(x))*f(x).diff(x), 'sol': [Eq(log(f(x)), C1 - 2*exp(x/f(x)))], }, # previous code was testing this with other solution: # example3_solb = Eq(log(C1*x*sqrt(1/x)*sqrt(f(x))) + x**2/(2*f(x)**2), 0) '1st_homogeneous_coeff_best_03': { 'eq': 2*x**2*f(x) + f(x)**3 + (x*f(x)**2 - 2*x**3)*f(x).diff(x), 'sol': [Eq(f(x), exp(2*C1 + LambertW(-2*x**4*exp(-4*C1))/2)/x)], 'checkodesol_XFAIL':True, #(because of LambertW?) }, '1st_homogeneous_coeff_best_04': { 'eq': (x + sqrt(f(x)**2 - x*f(x)))*f(x).diff(x) - f(x), 'sol': [Eq(log(f(x)), C1 - 2*sqrt(-x/f(x) + 1))], 'slow': True, }, '1st_homogeneous_coeff_best_05': { 'eq': x + f(x) - (x - f(x))*f(x).diff(x), 'sol': [Eq(log(x), C1 - log(sqrt(1 + f(x)**2/x**2)) + atan(f(x)/x))], }, '1st_homogeneous_coeff_best_06': { 'eq': x*f(x).diff(x) - f(x) - x*sin(f(x)/x), 'sol': [Eq(f(x), 2*x*atan(C1*x))], }, '1st_homogeneous_coeff_best_07': { 'eq': x**2 + f(x)**2 - 2*x*f(x)*f(x).diff(x), 'sol': [Eq(f(x), -sqrt(x*(C1 + x))), Eq(f(x), sqrt(x*(C1 + x)))], }, '1st_homogeneous_coeff_best_08': { 'eq': f(x)**2 + (x*sqrt(f(x)**2 - x**2) - x*f(x))*f(x).diff(x), 'sol': [Eq(log(x), C1 - log(f(x)/x) + acosh(f(x)/x))], }, } } def _get_all_examples(): all_examples = _get_examples_ode_sol_euler_homogeneous + \ _get_examples_ode_sol_euler_undetermined_coeff + \ _get_examples_ode_sol_euler_var_para + \ _get_examples_ode_sol_factorable + \ _get_examples_ode_sol_bernoulli + \ _get_examples_ode_sol_nth_algebraic + \ _get_examples_ode_sol_riccati + \ _get_examples_ode_sol_1st_linear + \ _get_examples_ode_sol_1st_exact + \ _get_examples_ode_sol_almost_linear + \ _get_examples_ode_sol_nth_order_reducible + \ _get_examples_ode_sol_nth_linear_undetermined_coefficients + \ _get_examples_ode_sol_liouville + \ _get_examples_ode_sol_separable + \ _get_examples_ode_sol_1st_rational_riccati + \ _get_examples_ode_sol_nth_linear_var_of_parameters + \ _get_examples_ode_sol_2nd_linear_bessel + \ _get_examples_ode_sol_2nd_2F1_hypergeometric + \ _get_examples_ode_sol_2nd_nonlinear_autonomous_conserved + \ _get_examples_ode_sol_separable_reduced + \ _get_examples_ode_sol_lie_group + \ _get_examples_ode_sol_2nd_linear_airy + \ _get_examples_ode_sol_nth_linear_constant_coeff_homogeneous +\ _get_examples_ode_sol_1st_homogeneous_coeff_best +\ _get_examples_ode_sol_1st_homogeneous_coeff_subs_dep_div_indep +\ _get_examples_ode_sol_linear_coefficients return all_examples sympy-sympy-1.9/sympy/solvers/ode/tests/test_subscheck.py000066400000000000000000000275261412543434000241110ustar00rootroot00000000000000from sympy import (cos, Derivative, diff, Eq, erf, erfi, exp, Function, I, Integral, log, pi, Rational, sin, sqrt, Symbol, symbols, Ei) from sympy.solvers.ode.subscheck import checkodesol, checksysodesol from sympy.functions import besselj, bessely from sympy.testing.pytest import raises, slow C0, C1, C2, C3, C4 = symbols('C0:5') u, x, y, z = symbols('u,x:z', real=True) f = Function('f') g = Function('g') h = Function('h') @slow def test_checkodesol(): # For the most part, checkodesol is well tested in the tests below. # These tests only handle cases not checked below. raises(ValueError, lambda: checkodesol(f(x, y).diff(x), Eq(f(x, y), x))) raises(ValueError, lambda: checkodesol(f(x).diff(x), Eq(f(x, y), x), f(x, y))) assert checkodesol(f(x).diff(x), Eq(f(x, y), x)) == \ (False, -f(x).diff(x) + f(x, y).diff(x) - 1) assert checkodesol(f(x).diff(x), Eq(f(x), x)) is not True assert checkodesol(f(x).diff(x), Eq(f(x), x)) == (False, 1) sol1 = Eq(f(x)**5 + 11*f(x) - 2*f(x) + x, 0) assert checkodesol(diff(sol1.lhs, x), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x)*exp(f(x)), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x, 2), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x, 2)*exp(f(x)), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x, 3), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x, 3)*exp(f(x)), sol1) == (True, 0) assert checkodesol(diff(sol1.lhs, x, 3), Eq(f(x), x*log(x))) == \ (False, 60*x**4*((log(x) + 1)**2 + log(x))*( log(x) + 1)*log(x)**2 - 5*x**4*log(x)**4 - 9) assert checkodesol(diff(exp(f(x)) + x, x)*x, Eq(exp(f(x)) + x, 0)) == \ (True, 0) assert checkodesol(diff(exp(f(x)) + x, x)*x, Eq(exp(f(x)) + x, 0), solve_for_func=False) == (True, 0) assert checkodesol(f(x).diff(x, 2), [Eq(f(x), C1 + C2*x), Eq(f(x), C2 + C1*x), Eq(f(x), C1*x + C2*x**2)]) == \ [(True, 0), (True, 0), (False, C2)] assert checkodesol(f(x).diff(x, 2), {Eq(f(x), C1 + C2*x), Eq(f(x), C2 + C1*x), Eq(f(x), C1*x + C2*x**2)}) == \ {(True, 0), (True, 0), (False, C2)} assert checkodesol(f(x).diff(x) - 1/f(x)/2, Eq(f(x)**2, x)) == \ [(True, 0), (True, 0)] assert checkodesol(f(x).diff(x) - f(x), Eq(C1*exp(x), f(x))) == (True, 0) # Based on test_1st_homogeneous_coeff_ode2_eq3sol. Make sure that # checkodesol tries back substituting f(x) when it can. eq3 = x*exp(f(x)/x) + f(x) - x*f(x).diff(x) sol3 = Eq(f(x), log(log(C1/x)**(-x))) assert not checkodesol(eq3, sol3)[1].has(f(x)) # This case was failing intermittently depending on hash-seed: eqn = Eq(Derivative(x*Derivative(f(x), x), x)/x, exp(x)) sol = Eq(f(x), C1 + C2*log(x) + exp(x) - Ei(x)) assert checkodesol(eqn, sol, order=2, solve_for_func=False)[0] eq = x**2*(f(x).diff(x, 2)) + x*(f(x).diff(x)) + (2*x**2 +25)*f(x) sol = Eq(f(x), C1*besselj(5*I, sqrt(2)*x) + C2*bessely(5*I, sqrt(2)*x)) assert checkodesol(eq, sol) == (True, 0) eqs = [Eq(f(x).diff(x), f(x) + g(x)), Eq(g(x).diff(x), f(x) + g(x))] sol = [Eq(f(x), -C1 + C2*exp(2*x)), Eq(g(x), C1 + C2*exp(2*x))] assert checkodesol(eqs, sol) == (True, [0, 0]) def test_checksysodesol(): x, y, z = symbols('x, y, z', cls=Function) t = Symbol('t') eq = (Eq(diff(x(t),t), 9*y(t)), Eq(diff(y(t),t), 12*x(t))) sol = [Eq(x(t), 9*C1*exp(-6*sqrt(3)*t) + 9*C2*exp(6*sqrt(3)*t)), \ Eq(y(t), -6*sqrt(3)*C1*exp(-6*sqrt(3)*t) + 6*sqrt(3)*C2*exp(6*sqrt(3)*t))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), 2*x(t) + 4*y(t)), Eq(diff(y(t),t), 12*x(t) + 41*y(t))) sol = [Eq(x(t), 4*C1*exp(t*(-sqrt(1713)/2 + Rational(43, 2))) + 4*C2*exp(t*(sqrt(1713)/2 + \ Rational(43, 2)))), Eq(y(t), C1*(-sqrt(1713)/2 + Rational(39, 2))*exp(t*(-sqrt(1713)/2 + \ Rational(43, 2))) + C2*(Rational(39, 2) + sqrt(1713)/2)*exp(t*(sqrt(1713)/2 + Rational(43, 2))))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), x(t) + y(t)), Eq(diff(y(t),t), -2*x(t) + 2*y(t))) sol = [Eq(x(t), (C1*sin(sqrt(7)*t/2) + C2*cos(sqrt(7)*t/2))*exp(t*Rational(3, 2))), \ Eq(y(t), ((C1/2 - sqrt(7)*C2/2)*sin(sqrt(7)*t/2) + (sqrt(7)*C1/2 + \ C2/2)*cos(sqrt(7)*t/2))*exp(t*Rational(3, 2)))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), x(t) + y(t) + 9), Eq(diff(y(t),t), 2*x(t) + 5*y(t) + 23)) sol = [Eq(x(t), C1*exp(t*(-sqrt(6) + 3)) + C2*exp(t*(sqrt(6) + 3)) - \ Rational(22, 3)), Eq(y(t), C1*(-sqrt(6) + 2)*exp(t*(-sqrt(6) + 3)) + C2*(2 + \ sqrt(6))*exp(t*(sqrt(6) + 3)) - Rational(5, 3))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), x(t) + y(t) + 81), Eq(diff(y(t),t), -2*x(t) + y(t) + 23)) sol = [Eq(x(t), (C1*sin(sqrt(2)*t) + C2*cos(sqrt(2)*t))*exp(t) - Rational(58, 3)), \ Eq(y(t), (sqrt(2)*C1*cos(sqrt(2)*t) - sqrt(2)*C2*sin(sqrt(2)*t))*exp(t) - Rational(185, 3))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), 5*t*x(t) + 2*y(t)), Eq(diff(y(t),t), 2*x(t) + 5*t*y(t))) sol = [Eq(x(t), (C1*exp(Integral(2, t).doit()) + C2*exp(-(Integral(2, t)).doit()))*\ exp((Integral(5*t, t)).doit())), Eq(y(t), (C1*exp((Integral(2, t)).doit()) - \ C2*exp(-(Integral(2, t)).doit()))*exp((Integral(5*t, t)).doit()))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + 5*t*y(t))) sol = [Eq(x(t), (C1*cos((Integral(t**2, t)).doit()) + C2*sin((Integral(t**2, t)).doit()))*\ exp((Integral(5*t, t)).doit())), Eq(y(t), (-C1*sin((Integral(t**2, t)).doit()) + \ C2*cos((Integral(t**2, t)).doit()))*exp((Integral(5*t, t)).doit()))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + (5*t+9*t**2)*y(t))) sol = [Eq(x(t), (C1*exp((-sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()) + \ C2*exp((sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()))*exp((Integral(5*t, t)).doit())), \ Eq(y(t), (C1*(-sqrt(77)/2 + Rational(9, 2))*exp((-sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()) + \ C2*(sqrt(77)/2 + Rational(9, 2))*exp((sqrt(77)/2 + Rational(9, 2))*(Integral(t**2, t)).doit()))*exp((Integral(5*t, t)).doit()))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t,t), 5*x(t) + 43*y(t)), Eq(diff(y(t),t,t), x(t) + 9*y(t))) root0 = -sqrt(-sqrt(47) + 7) root1 = sqrt(-sqrt(47) + 7) root2 = -sqrt(sqrt(47) + 7) root3 = sqrt(sqrt(47) + 7) sol = [Eq(x(t), 43*C1*exp(t*root0) + 43*C2*exp(t*root1) + 43*C3*exp(t*root2) + 43*C4*exp(t*root3)), \ Eq(y(t), C1*(root0**2 - 5)*exp(t*root0) + C2*(root1**2 - 5)*exp(t*root1) + \ C3*(root2**2 - 5)*exp(t*root2) + C4*(root3**2 - 5)*exp(t*root3))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t,t), 8*x(t)+3*y(t)+31), Eq(diff(y(t),t,t), 9*x(t)+7*y(t)+12)) root0 = -sqrt(-sqrt(109)/2 + Rational(15, 2)) root1 = sqrt(-sqrt(109)/2 + Rational(15, 2)) root2 = -sqrt(sqrt(109)/2 + Rational(15, 2)) root3 = sqrt(sqrt(109)/2 + Rational(15, 2)) sol = [Eq(x(t), 3*C1*exp(t*root0) + 3*C2*exp(t*root1) + 3*C3*exp(t*root2) + 3*C4*exp(t*root3) - Rational(181, 29)), \ Eq(y(t), C1*(root0**2 - 8)*exp(t*root0) + C2*(root1**2 - 8)*exp(t*root1) + \ C3*(root2**2 - 8)*exp(t*root2) + C4*(root3**2 - 8)*exp(t*root3) + Rational(183, 29))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t,t) - 9*diff(y(t),t) + 7*x(t),0), Eq(diff(y(t),t,t) + 9*diff(x(t),t) + 7*y(t),0)) sol = [Eq(x(t), C1*cos(t*(Rational(9, 2) + sqrt(109)/2)) + C2*sin(t*(Rational(9, 2) + sqrt(109)/2)) + \ C3*cos(t*(-sqrt(109)/2 + Rational(9, 2))) + C4*sin(t*(-sqrt(109)/2 + Rational(9, 2)))), Eq(y(t), -C1*sin(t*(Rational(9, 2) + sqrt(109)/2)) \ + C2*cos(t*(Rational(9, 2) + sqrt(109)/2)) - C3*sin(t*(-sqrt(109)/2 + Rational(9, 2))) + C4*cos(t*(-sqrt(109)/2 + Rational(9, 2))))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t,t), 9*t*diff(y(t),t)-9*y(t)), Eq(diff(y(t),t,t),7*t*diff(x(t),t)-7*x(t))) I1 = sqrt(6)*7**Rational(1, 4)*sqrt(pi)*erfi(sqrt(6)*7**Rational(1, 4)*t/2)/2 - exp(3*sqrt(7)*t**2/2)/t I2 = -sqrt(6)*7**Rational(1, 4)*sqrt(pi)*erf(sqrt(6)*7**Rational(1, 4)*t/2)/2 - exp(-3*sqrt(7)*t**2/2)/t sol = [Eq(x(t), C3*t + t*(9*C1*I1 + 9*C2*I2)), Eq(y(t), C4*t + t*(3*sqrt(7)*C1*I1 - 3*sqrt(7)*C2*I2))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), 21*x(t)), Eq(diff(y(t),t), 17*x(t)+3*y(t)), Eq(diff(z(t),t), 5*x(t)+7*y(t)+9*z(t))) sol = [Eq(x(t), C1*exp(21*t)), Eq(y(t), 17*C1*exp(21*t)/18 + C2*exp(3*t)), \ Eq(z(t), 209*C1*exp(21*t)/216 - 7*C2*exp(3*t)/6 + C3*exp(9*t))] assert checksysodesol(eq, sol) == (True, [0, 0, 0]) eq = (Eq(diff(x(t),t),3*y(t)-11*z(t)),Eq(diff(y(t),t),7*z(t)-3*x(t)),Eq(diff(z(t),t),11*x(t)-7*y(t))) sol = [Eq(x(t), 7*C0 + sqrt(179)*C1*cos(sqrt(179)*t) + (77*C1/3 + 130*C2/3)*sin(sqrt(179)*t)), \ Eq(y(t), 11*C0 + sqrt(179)*C2*cos(sqrt(179)*t) + (-58*C1/3 - 77*C2/3)*sin(sqrt(179)*t)), \ Eq(z(t), 3*C0 + sqrt(179)*(-7*C1/3 - 11*C2/3)*cos(sqrt(179)*t) + (11*C1 - 7*C2)*sin(sqrt(179)*t))] assert checksysodesol(eq, sol) == (True, [0, 0, 0]) eq = (Eq(3*diff(x(t),t),4*5*(y(t)-z(t))),Eq(4*diff(y(t),t),3*5*(z(t)-x(t))),Eq(5*diff(z(t),t),3*4*(x(t)-y(t)))) sol = [Eq(x(t), C0 + 5*sqrt(2)*C1*cos(5*sqrt(2)*t) + (12*C1/5 + 164*C2/15)*sin(5*sqrt(2)*t)), \ Eq(y(t), C0 + 5*sqrt(2)*C2*cos(5*sqrt(2)*t) + (-51*C1/10 - 12*C2/5)*sin(5*sqrt(2)*t)), \ Eq(z(t), C0 + 5*sqrt(2)*(-9*C1/25 - 16*C2/25)*cos(5*sqrt(2)*t) + (12*C1/5 - 12*C2/5)*sin(5*sqrt(2)*t))] assert checksysodesol(eq, sol) == (True, [0, 0, 0]) eq = (Eq(diff(x(t),t),4*x(t) - z(t)),Eq(diff(y(t),t),2*x(t)+2*y(t)-z(t)),Eq(diff(z(t),t),3*x(t)+y(t))) sol = [Eq(x(t), C1*exp(2*t) + C2*t*exp(2*t) + C2*exp(2*t) + C3*t**2*exp(2*t)/2 + C3*t*exp(2*t) + C3*exp(2*t)), \ Eq(y(t), C1*exp(2*t) + C2*t*exp(2*t) + C2*exp(2*t) + C3*t**2*exp(2*t)/2 + C3*t*exp(2*t)), \ Eq(z(t), 2*C1*exp(2*t) + 2*C2*t*exp(2*t) + C2*exp(2*t) + C3*t**2*exp(2*t) + C3*t*exp(2*t) + C3*exp(2*t))] assert checksysodesol(eq, sol) == (True, [0, 0, 0]) eq = (Eq(diff(x(t),t),4*x(t) - y(t) - 2*z(t)),Eq(diff(y(t),t),2*x(t) + y(t)- 2*z(t)),Eq(diff(z(t),t),5*x(t)-3*z(t))) sol = [Eq(x(t), C1*exp(2*t) + C2*(-sin(t) + 3*cos(t)) + C3*(3*sin(t) + cos(t))), \ Eq(y(t), C2*(-sin(t) + 3*cos(t)) + C3*(3*sin(t) + cos(t))), Eq(z(t), C1*exp(2*t) + 5*C2*cos(t) + 5*C3*sin(t))] assert checksysodesol(eq, sol) == (True, [0, 0, 0]) eq = (Eq(diff(x(t),t),x(t)*y(t)**3), Eq(diff(y(t),t),y(t)**5)) sol = [Eq(x(t), C1*exp((-1/(4*C2 + 4*t))**(Rational(-1, 4)))), Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), \ Eq(x(t), C1*exp(-1/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), \ Eq(x(t), C1*exp(-I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), \ Eq(x(t), C1*exp(I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(diff(x(t),t), exp(3*x(t))*y(t)**3),Eq(diff(y(t),t), y(t)**5)) sol = [Eq(x(t), -log(C1 - 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), \ Eq(x(t), -log(C1 + 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), \ Eq(x(t), -log(C1 + 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), \ Eq(x(t), -log(C1 - 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] assert checksysodesol(eq, sol) == (True, [0, 0]) eq = (Eq(x(t),t*diff(x(t),t)+diff(x(t),t)*diff(y(t),t)), Eq(y(t),t*diff(y(t),t)+diff(y(t),t)**2)) sol = {Eq(x(t), C1*C2 + C1*t), Eq(y(t), C2**2 + C2*t)} assert checksysodesol(eq, sol) == (True, [0, 0]) sympy-sympy-1.9/sympy/solvers/ode/tests/test_systems.py000066400000000000000000003757651412543434000236610ustar00rootroot00000000000000from sympy import (symbols, Symbol, sinh, diff, Function, Derivative, Matrix, Rational, S, I, Eq, sqrt, Mul, pi) from sympy.core.containers import Tuple from sympy.functions import exp, cos, sin, log, tan, Ci, Si, erf, erfi from sympy.matrices import dotprodsimp, NonSquareMatrixError from sympy.solvers.ode import dsolve from sympy.solvers.ode.ode import constant_renumber from sympy.solvers.ode.subscheck import checksysodesol from sympy.solvers.ode.systems import (_classify_linear_system, linear_ode_to_matrix, ODEOrderError, ODENonlinearError, _simpsol, _is_commutative_anti_derivative, linodesolve, canonical_odes, dsolve_system, _component_division, _eqs2dict, _dict2graph) from sympy.functions import airyai, airybi from sympy.integrals.integrals import Integral from sympy.simplify.ratsimp import ratsimp from sympy.testing.pytest import ON_TRAVIS, raises, slow, skip, XFAIL C0, C1, C2, C3, C4, C5, C6, C7, C8, C9, C10 = symbols('C0:11') x = symbols('x') f = Function('f') g = Function('g') h = Function('h') def test_linear_ode_to_matrix(): f, g, h = symbols("f, g, h", cls=Function) t = Symbol("t") funcs = [f(t), g(t), h(t)] f1 = f(t).diff(t) g1 = g(t).diff(t) h1 = h(t).diff(t) f2 = f(t).diff(t, 2) g2 = g(t).diff(t, 2) h2 = h(t).diff(t, 2) eqs_1 = [Eq(f1, g(t)), Eq(g1, f(t))] sol_1 = ([Matrix([[1, 0], [0, 1]]), Matrix([[ 0, 1], [1, 0]])], Matrix([[0],[0]])) assert linear_ode_to_matrix(eqs_1, funcs[:-1], t, 1) == sol_1 eqs_2 = [Eq(f1, f(t) + 2*g(t)), Eq(g1, h(t)), Eq(h1, g(t) + h(t) + f(t))] sol_2 = ([Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]]), Matrix([[1, 2, 0], [ 0, 0, 1], [1, 1, 1]])], Matrix([[0], [0], [0]])) assert linear_ode_to_matrix(eqs_2, funcs, t, 1) == sol_2 eqs_3 = [Eq(2*f1 + 3*h1, f(t) + g(t)), Eq(4*h1 + 5*g1, f(t) + h(t)), Eq(5*f1 + 4*g1, g(t) + h(t))] sol_3 = ([Matrix([[2, 0, 3], [0, 5, 4], [5, 4, 0]]), Matrix([[1, 1, 0], [1, 0, 1], [0, 1, 1]])], Matrix([[0], [0], [0]])) assert linear_ode_to_matrix(eqs_3, funcs, t, 1) == sol_3 eqs_4 = [Eq(f2 + h(t), f1 + g(t)), Eq(2*h2 + g2 + g1 + g(t), 0), Eq(3*h1, 4)] sol_4 = ([Matrix([[1, 0, 0], [0, 1, 2], [0, 0, 0]]), Matrix([[1, 0, 0], [0, -1, 0], [0, 0, -3]]), Matrix([[0, 1, -1], [0, -1, 0], [0, 0, 0]])], Matrix([[0], [0], [4]])) assert linear_ode_to_matrix(eqs_4, funcs, t, 2) == sol_4 eqs_5 = [Eq(f2, g(t)), Eq(f1 + g1, f(t))] raises(ODEOrderError, lambda: linear_ode_to_matrix(eqs_5, funcs[:-1], t, 1)) eqs_6 = [Eq(f1, f(t)**2), Eq(g1, f(t) + g(t))] raises(ODENonlinearError, lambda: linear_ode_to_matrix(eqs_6, funcs[:-1], t, 1)) def test__classify_linear_system(): x, y, z, w = symbols('x, y, z, w', cls=Function) t, k, l = symbols('t k l') x1 = diff(x(t), t) y1 = diff(y(t), t) z1 = diff(z(t), t) w1 = diff(w(t), t) x2 = diff(x(t), t, t) y2 = diff(y(t), t, t) funcs = [x(t), y(t)] funcs_2 = funcs + [z(t), w(t)] eqs_1 = (5 * x1 + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * t * x(t) + 3 * y(t) + t)) assert _classify_linear_system(eqs_1, funcs, t) is None eqs_2 = (5 * (x1**2) + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * t * x(t) + 3 * y(t) + t)) sol2 = {'is_implicit': True, 'canon_eqs': [[Eq(Derivative(x(t), t), -sqrt(-12*x(t)/5 + 6*y(t)/5)), Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)], [Eq(Derivative(x(t), t), sqrt(-12*x(t)/5 + 6*y(t)/5)), Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)]]} assert _classify_linear_system(eqs_2, funcs, t) == sol2 eqs_2_1 = [Eq(Derivative(x(t), t), -sqrt(-12*x(t)/5 + 6*y(t)/5)), Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)] assert _classify_linear_system(eqs_2_1, funcs, t) is None eqs_2_2 = [Eq(Derivative(x(t), t), sqrt(-12*x(t)/5 + 6*y(t)/5)), Eq(Derivative(y(t), t), 11*t*x(t)/2 - t/2 - 3*y(t)/2)] assert _classify_linear_system(eqs_2_2, funcs, t) is None eqs_3 = (5 * x1 + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * x(t) + 3 * y(t)), (5 * w1 + z(t)), (z1 + w(t))) answer_3 = {'no_of_equation': 4, 'eq': (12*x(t) - 6*y(t) + 5*Derivative(x(t), t), -11*x(t) + 3*y(t) + 2*Derivative(y(t), t), z(t) + 5*Derivative(w(t), t), w(t) + Derivative(z(t), t)), 'func': [x(t), y(t), z(t), w(t)], 'order': {x(t): 1, y(t): 1, z(t): 1, w(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [Rational(12, 5), Rational(-6, 5), 0, 0], [Rational(-11, 2), Rational(3, 2), 0, 0], [0, 0, 0, 1], [0, 0, Rational(1, 5), 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eqs_3, funcs_2, t) == answer_3 eqs_4 = (5 * x1 + 12 * x(t) - 6 * (y(t)), (2 * y1 - 11 * x(t) + 3 * y(t)), (z1 - w(t)), (w1 - z(t))) answer_4 = {'no_of_equation': 4, 'eq': (12 * x(t) - 6 * y(t) + 5 * Derivative(x(t), t), -11 * x(t) + 3 * y(t) + 2 * Derivative(y(t), t), -w(t) + Derivative(z(t), t), -z(t) + Derivative(w(t), t)), 'func': [x(t), y(t), z(t), w(t)], 'order': {x(t): 1, y(t): 1, z(t): 1, w(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [Rational(12, 5), Rational(-6, 5), 0, 0], [Rational(-11, 2), Rational(3, 2), 0, 0], [0, 0, 0, -1], [0, 0, -1, 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eqs_4, funcs_2, t) == answer_4 eqs_5 = (5*x1 + 12*x(t) - 6*(y(t)) + x2, (2*y1 - 11*x(t) + 3*y(t)), (z1 - w(t)), (w1 - z(t))) answer_5 = {'no_of_equation': 4, 'eq': (12*x(t) - 6*y(t) + 5*Derivative(x(t), t) + Derivative(x(t), (t, 2)), -11*x(t) + 3*y(t) + 2*Derivative(y(t), t), -w(t) + Derivative(z(t), t), -z(t) + Derivative(w(t), t)), 'func': [x(t), y(t), z(t), w(t)], 'order': {x(t): 2, y(t): 1, z(t): 1, w(t): 1}, 'is_linear': True, 'is_homogeneous': True, 'is_general': True, 'type_of_equation': 'type0', 'is_higher_order': True} assert _classify_linear_system(eqs_5, funcs_2, t) == answer_5 eqs_6 = (Eq(x1, 3*y(t) - 11*z(t)), Eq(y1, 7*z(t) - 3*x(t)), Eq(z1, 11*x(t) - 7*y(t))) answer_6 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 3*y(t) - 11*z(t)), Eq(Derivative(y(t), t), -3*x(t) + 7*z(t)), Eq(Derivative(z(t), t), 11*x(t) - 7*y(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [ 0, -3, 11], [ 3, 0, -7], [-11, 7, 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eqs_6, funcs_2[:-1], t) == answer_6 eqs_7 = (Eq(x1, y(t)), Eq(y1, x(t))) answer_7 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), y(t)), Eq(Derivative(y(t), t), x(t))), 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [ 0, -1], [-1, 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eqs_7, funcs, t) == answer_7 eqs_8 = (Eq(x1, 21*x(t)), Eq(y1, 17*x(t) + 3*y(t)), Eq(z1, 5*x(t) + 7*y(t) + 9*z(t))) answer_8 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 21*x(t)), Eq(Derivative(y(t), t), 17*x(t) + 3*y(t)), Eq(Derivative(z(t), t), 5*x(t) + 7*y(t) + 9*z(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [-21, 0, 0], [-17, -3, 0], [ -5, -7, -9]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eqs_8, funcs_2[:-1], t) == answer_8 eqs_9 = (Eq(x1, 4*x(t) + 5*y(t) + 2*z(t)), Eq(y1, x(t) + 13*y(t) + 9*z(t)), Eq(z1, 32*x(t) + 41*y(t) + 11*z(t))) answer_9 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 4*x(t) + 5*y(t) + 2*z(t)), Eq(Derivative(y(t), t), x(t) + 13*y(t) + 9*z(t)), Eq(Derivative(z(t), t), 32*x(t) + 41*y(t) + 11*z(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [ -4, -5, -2], [ -1, -13, -9], [-32, -41, -11]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eqs_9, funcs_2[:-1], t) == answer_9 eqs_10 = (Eq(3*x1, 4*5*(y(t) - z(t))), Eq(4*y1, 3*5*(z(t) - x(t))), Eq(5*z1, 3*4*(x(t) - y(t)))) answer_10 = {'no_of_equation': 3, 'eq': (Eq(3*Derivative(x(t), t), 20*y(t) - 20*z(t)), Eq(4*Derivative(y(t), t), -15*x(t) + 15*z(t)), Eq(5*Derivative(z(t), t), 12*x(t) - 12*y(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [ 0, Rational(-20, 3), Rational(20, 3)], [Rational(15, 4), 0, Rational(-15, 4)], [Rational(-12, 5), Rational(12, 5), 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eqs_10, funcs_2[:-1], t) == answer_10 eq11 = (Eq(x1, 3*y(t) - 11*z(t)), Eq(y1, 7*z(t) - 3*x(t)), Eq(z1, 11*x(t) - 7*y(t))) sol11 = {'no_of_equation': 3, 'eq': (Eq(Derivative(x(t), t), 3*y(t) - 11*z(t)), Eq(Derivative(y(t), t), -3*x(t) + 7*z(t)), Eq(Derivative(z(t), t), 11*x(t) - 7*y(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [ 0, -3, 11], [ 3, 0, -7], [-11, 7, 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eq11, funcs_2[:-1], t) == sol11 eq12 = (Eq(Derivative(x(t), t), y(t)), Eq(Derivative(y(t), t), x(t))) sol12 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), y(t)), Eq(Derivative(y(t), t), x(t))), 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [0, -1], [-1, 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eq12, [x(t), y(t)], t) == sol12 eq13 = (Eq(Derivative(x(t), t), 21*x(t)), Eq(Derivative(y(t), t), 17*x(t) + 3*y(t)), Eq(Derivative(z(t), t), 5*x(t) + 7*y(t) + 9*z(t))) sol13 = {'no_of_equation': 3, 'eq': ( Eq(Derivative(x(t), t), 21 * x(t)), Eq(Derivative(y(t), t), 17 * x(t) + 3 * y(t)), Eq(Derivative(z(t), t), 5 * x(t) + 7 * y(t) + 9 * z(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [-21, 0, 0], [-17, -3, 0], [-5, -7, -9]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eq13, [x(t), y(t), z(t)], t) == sol13 eq14 = ( Eq(Derivative(x(t), t), 4*x(t) + 5*y(t) + 2*z(t)), Eq(Derivative(y(t), t), x(t) + 13*y(t) + 9*z(t)), Eq(Derivative(z(t), t), 32*x(t) + 41*y(t) + 11*z(t))) sol14 = {'no_of_equation': 3, 'eq': ( Eq(Derivative(x(t), t), 4 * x(t) + 5 * y(t) + 2 * z(t)), Eq(Derivative(y(t), t), x(t) + 13 * y(t) + 9 * z(t)), Eq(Derivative(z(t), t), 32 * x(t) + 41 * y(t) + 11 * z(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [-4, -5, -2], [-1, -13, -9], [-32, -41, -11]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eq14, [x(t), y(t), z(t)], t) == sol14 eq15 = (Eq(3*Derivative(x(t), t), 20*y(t) - 20*z(t)), Eq(4*Derivative(y(t), t), -15*x(t) + 15*z(t)), Eq(5*Derivative(z(t), t), 12*x(t) - 12*y(t))) sol15 = {'no_of_equation': 3, 'eq': ( Eq(3 * Derivative(x(t), t), 20 * y(t) - 20 * z(t)), Eq(4 * Derivative(y(t), t), -15 * x(t) + 15 * z(t)), Eq(5 * Derivative(z(t), t), 12 * x(t) - 12 * y(t))), 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': True, 'func_coeff': -Matrix([ [0, Rational(-20, 3), Rational(20, 3)], [Rational(15, 4), 0, Rational(-15, 4)], [Rational(-12, 5), Rational(12, 5), 0]]), 'type_of_equation': 'type1', 'is_general': True} assert _classify_linear_system(eq15, [x(t), y(t), z(t)], t) == sol15 # Constant coefficient homogeneous ODEs eq1 = (Eq(diff(x(t), t), x(t) + y(t) + 9), Eq(diff(y(t), t), 2*x(t) + 5*y(t) + 23)) sol1 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), x(t) + y(t) + 9), Eq(Derivative(y(t), t), 2*x(t) + 5*y(t) + 23)), 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': True, 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([[-1, -1], [-2, -5]]), 'rhs': Matrix([[ 9], [23]]), 'type_of_equation': 'type2'} assert _classify_linear_system(eq1, funcs, t) == sol1 # Non constant coefficient homogeneous ODEs eq1 = (Eq(diff(x(t), t), 5*t*x(t) + 2*y(t)), Eq(diff(y(t), t), 2*x(t) + 5*t*y(t))) sol1 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), t), 5*t*x(t) + 2*y(t)), Eq(Derivative(y(t), t), 5*t*y(t) + 2*x(t))), 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': False, 'is_homogeneous': True, 'func_coeff': -Matrix([ [-5*t, -2], [ -2, -5*t]]), 'commutative_antiderivative': Matrix([ [5*t**2/2, 2*t], [ 2*t, 5*t**2/2]]), 'type_of_equation': 'type3', 'is_general': True} assert _classify_linear_system(eq1, funcs, t) == sol1 # Non constant coefficient non-homogeneous ODEs eq1 = [Eq(x1, x(t) + t*y(t) + t), Eq(y1, t*x(t) + y(t))] sol1 = {'no_of_equation': 2, 'eq': [Eq(Derivative(x(t), t), t*y(t) + t + x(t)), Eq(Derivative(y(t), t), t*x(t) + y(t))], 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_constant': False, 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-1, -t], [-t, -1]]), 'commutative_antiderivative': Matrix([ [ t, t**2/2], [t**2/2, t]]), 'rhs': Matrix([ [t], [0]]), 'type_of_equation': 'type4'} assert _classify_linear_system(eq1, funcs, t) == sol1 eq2 = [Eq(x1, t*x(t) + t*y(t) + t), Eq(y1, t*x(t) + t*y(t) + cos(t))] sol2 = {'no_of_equation': 2, 'eq': [Eq(Derivative(x(t), t), t*x(t) + t*y(t) + t), Eq(Derivative(y(t), t), t*x(t) + t*y(t) + cos(t))], 'func': [x(t), y(t)], 'order': {x(t): 1, y(t): 1}, 'is_linear': True, 'is_homogeneous': False, 'is_general': True, 'rhs': Matrix([ [ t], [cos(t)]]), 'func_coeff': Matrix([ [t, t], [t, t]]), 'is_constant': False, 'type_of_equation': 'type4', 'commutative_antiderivative': Matrix([ [t**2/2, t**2/2], [t**2/2, t**2/2]])} assert _classify_linear_system(eq2, funcs, t) == sol2 eq3 = [Eq(x1, t*(x(t) + y(t) + z(t) + 1)), Eq(y1, t*(x(t) + y(t) + z(t))), Eq(z1, t*(x(t) + y(t) + z(t)))] sol3 = {'no_of_equation': 3, 'eq': [Eq(Derivative(x(t), t), t*(x(t) + y(t) + z(t) + 1)), Eq(Derivative(y(t), t), t*(x(t) + y(t) + z(t))), Eq(Derivative(z(t), t), t*(x(t) + y(t) + z(t)))], 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': False, 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-t, -t, -t], [-t, -t, -t], [-t, -t, -t]]), 'commutative_antiderivative': Matrix([ [t**2/2, t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2]]), 'rhs': Matrix([ [t], [0], [0]]), 'type_of_equation': 'type4'} assert _classify_linear_system(eq3, funcs_2[:-1], t) == sol3 eq4 = [Eq(x1, x(t) + y(t) + t*z(t) + 1), Eq(y1, x(t) + t*y(t) + z(t) + 10), Eq(z1, t*x(t) + y(t) + z(t) + t)] sol4 = {'no_of_equation': 3, 'eq': [Eq(Derivative(x(t), t), t*z(t) + x(t) + y(t) + 1), Eq(Derivative(y(t), t), t*y(t) + x(t) + z(t) + 10), Eq(Derivative(z(t), t), t*x(t) + t + y(t) + z(t))], 'func': [x(t), y(t), z(t)], 'order': {x(t): 1, y(t): 1, z(t): 1}, 'is_linear': True, 'is_constant': False, 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-1, -1, -t], [-1, -t, -1], [-t, -1, -1]]), 'commutative_antiderivative': Matrix([ [ t, t, t**2/2], [ t, t**2/2, t], [t**2/2, t, t]]), 'rhs': Matrix([ [ 1], [10], [ t]]), 'type_of_equation': 'type4'} assert _classify_linear_system(eq4, funcs_2[:-1], t) == sol4 sum_terms = t*(x(t) + y(t) + z(t) + w(t)) eq5 = [Eq(x1, sum_terms), Eq(y1, sum_terms), Eq(z1, sum_terms + 1), Eq(w1, sum_terms)] sol5 = {'no_of_equation': 4, 'eq': [Eq(Derivative(x(t), t), t*(w(t) + x(t) + y(t) + z(t))), Eq(Derivative(y(t), t), t*(w(t) + x(t) + y(t) + z(t))), Eq(Derivative(z(t), t), t*(w(t) + x(t) + y(t) + z(t)) + 1), Eq(Derivative(w(t), t), t*(w(t) + x(t) + y(t) + z(t)))], 'func': [x(t), y(t), z(t), w(t)], 'order': {x(t): 1, y(t): 1, z(t): 1, w(t): 1}, 'is_linear': True, 'is_constant': False, 'is_homogeneous': False, 'is_general': True, 'func_coeff': -Matrix([ [-t, -t, -t, -t], [-t, -t, -t, -t], [-t, -t, -t, -t], [-t, -t, -t, -t]]), 'commutative_antiderivative': Matrix([ [t**2/2, t**2/2, t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2, t**2/2], [t**2/2, t**2/2, t**2/2, t**2/2]]), 'rhs': Matrix([ [0], [0], [1], [0]]), 'type_of_equation': 'type4'} assert _classify_linear_system(eq5, funcs_2, t) == sol5 # Second Order t_ = symbols("t_") eq1 = (Eq(9*x(t) + 7*y(t) + 4*Derivative(x(t), t) + Derivative(x(t), (t, 2)) + 3*Derivative(y(t), t), 11*exp(I*t)), Eq(3*x(t) + 12*y(t) + 5*Derivative(x(t), t) + 8*Derivative(y(t), t) + Derivative(y(t), (t, 2)), 2*exp(I*t))) sol1 = {'no_of_equation': 2, 'eq': (Eq(9*x(t) + 7*y(t) + 4*Derivative(x(t), t) + Derivative(x(t), (t, 2)) + 3*Derivative(y(t), t), 11*exp(I*t)), Eq(3*x(t) + 12*y(t) + 5*Derivative(x(t), t) + 8*Derivative(y(t), t) + Derivative(y(t), (t, 2)), 2*exp(I*t))), 'func': [x(t), y(t)], 'order': {x(t): 2, y(t): 2}, 'is_linear': True, 'is_homogeneous': False, 'is_general': True, 'rhs': Matrix([ [11*exp(I*t)], [ 2*exp(I*t)]]), 'type_of_equation': 'type0', 'is_second_order': True, 'is_higher_order': True} assert _classify_linear_system(eq1, funcs, t) == sol1 eq2 = (Eq((4*t**2 + 7*t + 1)**2*Derivative(x(t), (t, 2)), 5*x(t) + 35*y(t)), Eq((4*t**2 + 7*t + 1)**2*Derivative(y(t), (t, 2)), x(t) + 9*y(t))) sol2 = {'no_of_equation': 2, 'eq': (Eq((4*t**2 + 7*t + 1)**2*Derivative(x(t), (t, 2)), 5*x(t) + 35*y(t)), Eq((4*t**2 + 7*t + 1)**2*Derivative(y(t), (t, 2)), x(t) + 9*y(t))), 'func': [x(t), y(t)], 'order': {x(t): 2, y(t): 2}, 'is_linear': True, 'is_homogeneous': True, 'is_general': True, 'type_of_equation': 'type2', 'A0': Matrix([ [Rational(53, 4), 35], [ 1, Rational(69, 4)]]), 'g(t)': sqrt(4*t**2 + 7*t + 1), 'tau': sqrt(33)*log(t - sqrt(33)/8 + Rational(7, 8))/33 - sqrt(33)*log(t + sqrt(33)/8 + Rational(7, 8))/33, 'is_transformed': True, 't_': t_, 'is_second_order': True, 'is_higher_order': True} assert _classify_linear_system(eq2, funcs, t) == sol2 eq3 = ((t*Derivative(x(t), t) - x(t))*log(t) + (t*Derivative(y(t), t) - y(t))*exp(t) + Derivative(x(t), (t, 2)), t**2*(t*Derivative(x(t), t) - x(t)) + t*(t*Derivative(y(t), t) - y(t)) + Derivative(y(t), (t, 2))) sol3 = {'no_of_equation': 2, 'eq': ((t*Derivative(x(t), t) - x(t))*log(t) + (t*Derivative(y(t), t) - y(t))*exp(t) + Derivative(x(t), (t, 2)), t**2*(t*Derivative(x(t), t) - x(t)) + t*(t*Derivative(y(t), t) - y(t)) + Derivative(y(t), (t, 2))), 'func': [x(t), y(t)], 'order': {x(t): 2, y(t): 2}, 'is_linear': True, 'is_homogeneous': True, 'is_general': True, 'type_of_equation': 'type1', 'A1': Matrix([ [-t*log(t), -t*exp(t)], [ -t**3, -t**2]]), 'is_second_order': True, 'is_higher_order': True} assert _classify_linear_system(eq3, funcs, t) == sol3 eq4 = (Eq(x2, k*x(t) - l*y1), Eq(y2, l*x1 + k*y(t))) sol4 = {'no_of_equation': 2, 'eq': (Eq(Derivative(x(t), (t, 2)), k*x(t) - l*Derivative(y(t), t)), Eq(Derivative(y(t), (t, 2)), k*y(t) + l*Derivative(x(t), t))), 'func': [x(t), y(t)], 'order': {x(t): 2, y(t): 2}, 'is_linear': True, 'is_homogeneous': True, 'is_general': True, 'type_of_equation': 'type0', 'is_second_order': True, 'is_higher_order': True} assert _classify_linear_system(eq4, funcs, t) == sol4 # Multiple matchs f, g = symbols("f g", cls=Function) y, t_ = symbols("y t_") funcs = [f(t), g(t)] eq1 = [Eq(Derivative(f(t), t)**2 - 2*Derivative(f(t), t) + 1, 4), Eq(-y*f(t) + Derivative(g(t), t), 0)] sol1 = {'is_implicit': True, 'canon_eqs': [[Eq(Derivative(f(t), t), -1), Eq(Derivative(g(t), t), y*f(t))], [Eq(Derivative(f(t), t), 3), Eq(Derivative(g(t), t), y*f(t))]]} assert _classify_linear_system(eq1, funcs, t) == sol1 raises(ValueError, lambda: _classify_linear_system(eq1, funcs[:1], t)) eq2 = [Eq(Derivative(f(t), t), (2*f(t) + g(t) + 1)/t), Eq(Derivative(g(t), t), (f(t) + 2*g(t))/t)] sol2 = {'no_of_equation': 2, 'eq': [Eq(Derivative(f(t), t), (2*f(t) + g(t) + 1)/t), Eq(Derivative(g(t), t), (f(t) + 2*g(t))/t)], 'func': [f(t), g(t)], 'order': {f(t): 1, g(t): 1}, 'is_linear': True, 'is_homogeneous': False, 'is_general': True, 'rhs': Matrix([ [1], [0]]), 'func_coeff': Matrix([ [2, 1], [1, 2]]), 'is_constant': False, 'type_of_equation': 'type6', 't_': t_, 'tau': log(t), 'commutative_antiderivative': Matrix([ [2*log(t), log(t)], [ log(t), 2*log(t)]])} assert _classify_linear_system(eq2, funcs, t) == sol2 eq3 = [Eq(Derivative(f(t), t), (2*f(t) + g(t))/t), Eq(Derivative(g(t), t), (f(t) + 2*g(t))/t)] sol3 = {'no_of_equation': 2, 'eq': [Eq(Derivative(f(t), t), (2*f(t) + g(t))/t), Eq(Derivative(g(t), t), (f(t) + 2*g(t))/t)], 'func': [f(t), g(t)], 'order': {f(t): 1, g(t): 1}, 'is_linear': True, 'is_homogeneous': True, 'is_general': True, 'func_coeff': Matrix([ [2, 1], [1, 2]]), 'is_constant': False, 'type_of_equation': 'type5', 't_': t_, 'rhs': Matrix([ [0], [0]]), 'tau': log(t), 'commutative_antiderivative': Matrix([ [2*log(t), log(t)], [ log(t), 2*log(t)]])} assert _classify_linear_system(eq3, funcs, t) == sol3 def test_matrix_exp(): from sympy.matrices.dense import Matrix, eye, zeros from sympy.solvers.ode.systems import matrix_exp t = Symbol('t') for n in range(1, 6+1): assert matrix_exp(zeros(n), t) == eye(n) for n in range(1, 6+1): A = eye(n) expAt = exp(t) * eye(n) assert matrix_exp(A, t) == expAt for n in range(1, 6+1): A = Matrix(n, n, lambda i,j: i+1 if i==j else 0) expAt = Matrix(n, n, lambda i,j: exp((i+1)*t) if i==j else 0) assert matrix_exp(A, t) == expAt A = Matrix([[0, 1], [-1, 0]]) expAt = Matrix([[cos(t), sin(t)], [-sin(t), cos(t)]]) assert matrix_exp(A, t) == expAt A = Matrix([[2, -5], [2, -4]]) expAt = Matrix([ [3*exp(-t)*sin(t) + exp(-t)*cos(t), -5*exp(-t)*sin(t)], [2*exp(-t)*sin(t), -3*exp(-t)*sin(t) + exp(-t)*cos(t)] ]) assert matrix_exp(A, t) == expAt A = Matrix([[21, 17, 6], [-5, -1, -6], [4, 4, 16]]) # TO update this. # expAt = Matrix([ # [(8*t*exp(12*t) + 5*exp(12*t) - 1)*exp(4*t)/4, # (8*t*exp(12*t) + 5*exp(12*t) - 5)*exp(4*t)/4, # (exp(12*t) - 1)*exp(4*t)/2], # [(-8*t*exp(12*t) - exp(12*t) + 1)*exp(4*t)/4, # (-8*t*exp(12*t) - exp(12*t) + 5)*exp(4*t)/4, # (-exp(12*t) + 1)*exp(4*t)/2], # [4*t*exp(16*t), 4*t*exp(16*t), exp(16*t)]]) expAt = Matrix([ [2*t*exp(16*t) + 5*exp(16*t)/4 - exp(4*t)/4, 2*t*exp(16*t) + 5*exp(16*t)/4 - 5*exp(4*t)/4, exp(16*t)/2 - exp(4*t)/2], [ -2*t*exp(16*t) - exp(16*t)/4 + exp(4*t)/4, -2*t*exp(16*t) - exp(16*t)/4 + 5*exp(4*t)/4, -exp(16*t)/2 + exp(4*t)/2], [ 4*t*exp(16*t), 4*t*exp(16*t), exp(16*t)] ]) assert matrix_exp(A, t) == expAt A = Matrix([[1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 1, -S(1)/8], [0, 0, S(1)/2, S(1)/2]]) expAt = Matrix([ [exp(t), t*exp(t), 4*t*exp(3*t/4) + 8*t*exp(t) + 48*exp(3*t/4) - 48*exp(t), -2*t*exp(3*t/4) - 2*t*exp(t) - 16*exp(3*t/4) + 16*exp(t)], [0, exp(t), -t*exp(3*t/4) - 8*exp(3*t/4) + 8*exp(t), t*exp(3*t/4)/2 + 2*exp(3*t/4) - 2*exp(t)], [0, 0, t*exp(3*t/4)/4 + exp(3*t/4), -t*exp(3*t/4)/8], [0, 0, t*exp(3*t/4)/2, -t*exp(3*t/4)/4 + exp(3*t/4)] ]) assert matrix_exp(A, t) == expAt A = Matrix([ [ 0, 1, 0, 0], [-1, 0, 0, 0], [ 0, 0, 0, 1], [ 0, 0, -1, 0]]) expAt = Matrix([ [ cos(t), sin(t), 0, 0], [-sin(t), cos(t), 0, 0], [ 0, 0, cos(t), sin(t)], [ 0, 0, -sin(t), cos(t)]]) assert matrix_exp(A, t) == expAt A = Matrix([ [ 0, 1, 1, 0], [-1, 0, 0, 1], [ 0, 0, 0, 1], [ 0, 0, -1, 0]]) expAt = Matrix([ [ cos(t), sin(t), t*cos(t), t*sin(t)], [-sin(t), cos(t), -t*sin(t), t*cos(t)], [ 0, 0, cos(t), sin(t)], [ 0, 0, -sin(t), cos(t)]]) assert matrix_exp(A, t) == expAt # This case is unacceptably slow right now but should be solvable... #a, b, c, d, e, f = symbols('a b c d e f') #A = Matrix([ #[-a, b, c, d], #[ a, -b, e, 0], #[ 0, 0, -c - e - f, 0], #[ 0, 0, f, -d]]) A = Matrix([[0, I], [I, 0]]) expAt = Matrix([ [exp(I*t)/2 + exp(-I*t)/2, exp(I*t)/2 - exp(-I*t)/2], [exp(I*t)/2 - exp(-I*t)/2, exp(I*t)/2 + exp(-I*t)/2]]) assert matrix_exp(A, t) == expAt # Testing Errors M = Matrix([[1, 2, 3], [4, 5, 6], [7, 7, 7]]) M1 = Matrix([[t, 1], [1, 1]]) raises(ValueError, lambda: matrix_exp(M[:, :2], t)) raises(ValueError, lambda: matrix_exp(M[:2, :], t)) raises(ValueError, lambda: matrix_exp(M1, t)) raises(ValueError, lambda: matrix_exp(M1[:1, :1], t)) def test_canonical_odes(): f, g, h = symbols('f g h', cls=Function) x = symbols('x') funcs = [f(x), g(x), h(x)] eqs1 = [Eq(f(x).diff(x, x), f(x) + 2*g(x)), Eq(g(x) + 1, g(x).diff(x) + f(x))] sol1 = [[Eq(Derivative(f(x), (x, 2)), f(x) + 2*g(x)), Eq(Derivative(g(x), x), -f(x) + g(x) + 1)]] assert canonical_odes(eqs1, funcs[:2], x) == sol1 eqs2 = [Eq(f(x).diff(x), h(x).diff(x) + f(x)), Eq(g(x).diff(x)**2, f(x) + h(x)), Eq(h(x).diff(x), f(x))] sol2 = [[Eq(Derivative(f(x), x), 2*f(x)), Eq(Derivative(g(x), x), -sqrt(f(x) + h(x))), Eq(Derivative(h(x), x), f(x))], [Eq(Derivative(f(x), x), 2*f(x)), Eq(Derivative(g(x), x), sqrt(f(x) + h(x))), Eq(Derivative(h(x), x), f(x))]] assert canonical_odes(eqs2, funcs, x) == sol2 def test_sysode_linear_neq_order1_type1(): f, g, x, y, h = symbols('f g x y h', cls=Function) a, b, c, t = symbols('a b c t') eqs1 = [Eq(Derivative(x(t), t), x(t)), Eq(Derivative(y(t), t), y(t))] sol1 = [Eq(x(t), C1*exp(t)), Eq(y(t), C2*exp(t))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) eqs2 = [Eq(Derivative(x(t), t), 2*x(t)), Eq(Derivative(y(t), t), 3*y(t))] sol2 = [Eq(x(t), C1*exp(2*t)), Eq(y(t), C2*exp(3*t))] assert dsolve(eqs2) == sol2 assert checksysodesol(eqs2, sol2) == (True, [0, 0]) eqs3 = [Eq(Derivative(x(t), t), a*x(t)), Eq(Derivative(y(t), t), a*y(t))] sol3 = [Eq(x(t), C1*exp(a*t)), Eq(y(t), C2*exp(a*t))] assert dsolve(eqs3) == sol3 assert checksysodesol(eqs3, sol3) == (True, [0, 0]) # Regression test case for issue #15474 # https://github.com/sympy/sympy/issues/15474 eqs4 = [Eq(Derivative(x(t), t), a*x(t)), Eq(Derivative(y(t), t), b*y(t))] sol4 = [Eq(x(t), C1*exp(a*t)), Eq(y(t), C2*exp(b*t))] assert dsolve(eqs4) == sol4 assert checksysodesol(eqs4, sol4) == (True, [0, 0]) eqs5 = [Eq(Derivative(x(t), t), -y(t)), Eq(Derivative(y(t), t), x(t))] sol5 = [Eq(x(t), -C1*sin(t) - C2*cos(t)), Eq(y(t), C1*cos(t) - C2*sin(t))] assert dsolve(eqs5) == sol5 assert checksysodesol(eqs5, sol5) == (True, [0, 0]) eqs6 = [Eq(Derivative(x(t), t), -2*y(t)), Eq(Derivative(y(t), t), 2*x(t))] sol6 = [Eq(x(t), -C1*sin(2*t) - C2*cos(2*t)), Eq(y(t), C1*cos(2*t) - C2*sin(2*t))] assert dsolve(eqs6) == sol6 assert checksysodesol(eqs6, sol6) == (True, [0, 0]) eqs7 = [Eq(Derivative(x(t), t), I*y(t)), Eq(Derivative(y(t), t), I*x(t))] sol7 = [Eq(x(t), -C1*exp(-I*t) + C2*exp(I*t)), Eq(y(t), C1*exp(-I*t) + C2*exp(I*t))] assert dsolve(eqs7) == sol7 assert checksysodesol(eqs7, sol7) == (True, [0, 0]) eqs8 = [Eq(Derivative(x(t), t), -a*y(t)), Eq(Derivative(y(t), t), a*x(t))] sol8 = [Eq(x(t), -I*C1*exp(-I*a*t) + I*C2*exp(I*a*t)), Eq(y(t), C1*exp(-I*a*t) + C2*exp(I*a*t))] assert dsolve(eqs8) == sol8 assert checksysodesol(eqs8, sol8) == (True, [0, 0]) eqs9 = [Eq(Derivative(x(t), t), x(t) + y(t)), Eq(Derivative(y(t), t), x(t) - y(t))] sol9 = [Eq(x(t), C1*(1 - sqrt(2))*exp(-sqrt(2)*t) + C2*(1 + sqrt(2))*exp(sqrt(2)*t)), Eq(y(t), C1*exp(-sqrt(2)*t) + C2*exp(sqrt(2)*t))] assert dsolve(eqs9) == sol9 assert checksysodesol(eqs9, sol9) == (True, [0, 0]) eqs10 = [Eq(Derivative(x(t), t), x(t) + y(t)), Eq(Derivative(y(t), t), x(t) + y(t))] sol10 = [Eq(x(t), -C1 + C2*exp(2*t)), Eq(y(t), C1 + C2*exp(2*t))] assert dsolve(eqs10) == sol10 assert checksysodesol(eqs10, sol10) == (True, [0, 0]) eqs11 = [Eq(Derivative(x(t), t), 2*x(t) + y(t)), Eq(Derivative(y(t), t), -x(t) + 2*y(t))] sol11 = [Eq(x(t), C1*exp(2*t)*sin(t) + C2*exp(2*t)*cos(t)), Eq(y(t), C1*exp(2*t)*cos(t) - C2*exp(2*t)*sin(t))] assert dsolve(eqs11) == sol11 assert checksysodesol(eqs11, sol11) == (True, [0, 0]) eqs12 = [Eq(Derivative(x(t), t), x(t) + 2*y(t)), Eq(Derivative(y(t), t), 2*x(t) + y(t))] sol12 = [Eq(x(t), -C1*exp(-t) + C2*exp(3*t)), Eq(y(t), C1*exp(-t) + C2*exp(3*t))] assert dsolve(eqs12) == sol12 assert checksysodesol(eqs12, sol12) == (True, [0, 0]) eqs13 = [Eq(Derivative(x(t), t), 4*x(t) + y(t)), Eq(Derivative(y(t), t), -x(t) + 2*y(t))] sol13 = [Eq(x(t), C2*t*exp(3*t) + (C1 + C2)*exp(3*t)), Eq(y(t), -C1*exp(3*t) - C2*t*exp(3*t))] assert dsolve(eqs13) == sol13 assert checksysodesol(eqs13, sol13) == (True, [0, 0]) eqs14 = [Eq(Derivative(x(t), t), a*y(t)), Eq(Derivative(y(t), t), a*x(t))] sol14 = [Eq(x(t), -C1*exp(-a*t) + C2*exp(a*t)), Eq(y(t), C1*exp(-a*t) + C2*exp(a*t))] assert dsolve(eqs14) == sol14 assert checksysodesol(eqs14, sol14) == (True, [0, 0]) eqs15 = [Eq(Derivative(x(t), t), a*y(t)), Eq(Derivative(y(t), t), b*x(t))] sol15 = [Eq(x(t), -C1*a*exp(-t*sqrt(a*b))/sqrt(a*b) + C2*a*exp(t*sqrt(a*b))/sqrt(a*b)), Eq(y(t), C1*exp(-t*sqrt(a*b)) + C2*exp(t*sqrt(a*b)))] assert dsolve(eqs15) == sol15 assert checksysodesol(eqs15, sol15) == (True, [0, 0]) eqs16 = [Eq(Derivative(x(t), t), a*x(t) + b*y(t)), Eq(Derivative(y(t), t), c*x(t))] sol16 = [Eq(x(t), -2*C1*b*exp(t*(a + sqrt(a**2 + 4*b*c))/2)/(a - sqrt(a**2 + 4*b*c)) - 2*C2*b*exp(t*(a - sqrt(a**2 + 4*b*c))/2)/(a + sqrt(a**2 + 4*b*c))), Eq(y(t), C1*exp(t*(a + sqrt(a**2 + 4*b*c))/2) + C2*exp(t*(a - sqrt(a**2 + 4*b*c))/2))] assert dsolve(eqs16) == sol16 assert checksysodesol(eqs16, sol16) == (True, [0, 0]) # Regression test case for issue #18562 # https://github.com/sympy/sympy/issues/18562 eqs17 = [Eq(Derivative(x(t), t), a*y(t) + x(t)), Eq(Derivative(y(t), t), a*x(t) - y(t))] sol17 = [Eq(x(t), C1*a*exp(t*sqrt(a**2 + 1))/(sqrt(a**2 + 1) - 1) - C2*a*exp(-t*sqrt(a**2 + 1))/(sqrt(a**2 + 1) + 1)), Eq(y(t), C1*exp(t*sqrt(a**2 + 1)) + C2*exp(-t*sqrt(a**2 + 1)))] assert dsolve(eqs17) == sol17 assert checksysodesol(eqs17, sol17) == (True, [0, 0]) eqs18 = [Eq(Derivative(x(t), t), 0), Eq(Derivative(y(t), t), 0)] sol18 = [Eq(x(t), C1), Eq(y(t), C2)] assert dsolve(eqs18) == sol18 assert checksysodesol(eqs18, sol18) == (True, [0, 0]) eqs19 = [Eq(Derivative(x(t), t), 2*x(t) - y(t)), Eq(Derivative(y(t), t), x(t))] sol19 = [Eq(x(t), C2*t*exp(t) + (C1 + C2)*exp(t)), Eq(y(t), C1*exp(t) + C2*t*exp(t))] assert dsolve(eqs19) == sol19 assert checksysodesol(eqs19, sol19) == (True, [0, 0]) eqs20 = [Eq(Derivative(x(t), t), x(t)), Eq(Derivative(y(t), t), x(t) + y(t))] sol20 = [Eq(x(t), C1*exp(t)), Eq(y(t), C1*t*exp(t) + C2*exp(t))] assert dsolve(eqs20) == sol20 assert checksysodesol(eqs20, sol20) == (True, [0, 0]) eqs21 = [Eq(Derivative(x(t), t), 3*x(t)), Eq(Derivative(y(t), t), x(t) + y(t))] sol21 = [Eq(x(t), 2*C1*exp(3*t)), Eq(y(t), C1*exp(3*t) + C2*exp(t))] assert dsolve(eqs21) == sol21 assert checksysodesol(eqs21, sol21) == (True, [0, 0]) eqs22 = [Eq(Derivative(x(t), t), 3*x(t)), Eq(Derivative(y(t), t), y(t))] sol22 = [Eq(x(t), C1*exp(3*t)), Eq(y(t), C2*exp(t))] assert dsolve(eqs22) == sol22 assert checksysodesol(eqs22, sol22) == (True, [0, 0]) @slow def test_sysode_linear_neq_order1_type1_slow(): t = Symbol('t') Z0 = Function('Z0') Z1 = Function('Z1') Z2 = Function('Z2') Z3 = Function('Z3') k01, k10, k20, k21, k23, k30 = symbols('k01 k10 k20 k21 k23 k30') eqs1 = [Eq(Derivative(Z0(t), t), -k01*Z0(t) + k10*Z1(t) + k20*Z2(t) + k30*Z3(t)), Eq(Derivative(Z1(t), t), k01*Z0(t) - k10*Z1(t) + k21*Z2(t)), Eq(Derivative(Z2(t), t), (-k20 - k21 - k23)*Z2(t)), Eq(Derivative(Z3(t), t), k23*Z2(t) - k30*Z3(t))] sol1 = [Eq(Z0(t), C1*k10/k01 - C2*(k10 - k30)*exp(-k30*t)/(k01 + k10 - k30) - C3*(k10*(k20 + k21 - k30) - k20**2 - k20*(k21 + k23 - k30) + k23*k30)*exp(-t*(k20 + k21 + k23))/(k23*(-k01 - k10 + k20 + k21 + k23)) - C4*exp(-t*(k01 + k10))), Eq(Z1(t), C1 - C2*k01*exp(-k30*t)/(k01 + k10 - k30) + C3*(-k01*(k20 + k21 - k30) + k20*k21 + k21**2 + k21*(k23 - k30))*exp(-t*(k20 + k21 + k23))/(k23*(-k01 - k10 + k20 + k21 + k23)) + C4*exp(-t*(k01 + k10))), Eq(Z2(t), -C3*(k20 + k21 + k23 - k30)*exp(-t*(k20 + k21 + k23))/k23), Eq(Z3(t), C2*exp(-k30*t) + C3*exp(-t*(k20 + k21 + k23)))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0, 0, 0]) x, y, z, u, v, w = symbols('x y z u v w', cls=Function) k2, k3 = symbols('k2 k3') a_b, a_c = symbols('a_b a_c', real=True) eqs2 = [Eq(Derivative(z(t), t), k2*y(t)), Eq(Derivative(x(t), t), k3*y(t)), Eq(Derivative(y(t), t), (-k2 - k3)*y(t))] sol2 = [Eq(z(t), C1 - C2*k2*exp(-t*(k2 + k3))/(k2 + k3)), Eq(x(t), -C2*k3*exp(-t*(k2 + k3))/(k2 + k3) + C3), Eq(y(t), C2*exp(-t*(k2 + k3)))] assert dsolve(eqs2) == sol2 assert checksysodesol(eqs2, sol2) == (True, [0, 0, 0]) eqs3 = [4*u(t) - v(t) - 2*w(t) + Derivative(u(t), t), 2*u(t) + v(t) - 2*w(t) + Derivative(v(t), t), 5*u(t) + v(t) - 3*w(t) + Derivative(w(t), t)] sol3 = [Eq(u(t), C3*exp(-2*t) + (C1/2 + sqrt(3)*C2/6)*cos(sqrt(3)*t) + sin(sqrt(3)*t)*(sqrt(3)*C1/6 + C2*Rational(-1, 2))), Eq(v(t), (C1/2 + sqrt(3)*C2/6)*cos(sqrt(3)*t) + sin(sqrt(3)*t)*(sqrt(3)*C1/6 + C2*Rational(-1, 2))), Eq(w(t), C1*cos(sqrt(3)*t) - C2*sin(sqrt(3)*t) + C3*exp(-2*t))] assert dsolve(eqs3) == sol3 assert checksysodesol(eqs3, sol3) == (True, [0, 0, 0]) eqs4 = [Eq(Derivative(x(t), t), w(t)*Rational(-2, 9) + 2*x(t) + y(t) + z(t)*Rational(-8, 9)), Eq(Derivative(y(t), t), w(t)*Rational(4, 9) + 2*y(t) + z(t)*Rational(16, 9)), Eq(Derivative(z(t), t), w(t)*Rational(-2, 9) + z(t)*Rational(37, 9)), Eq(Derivative(w(t), t), w(t)*Rational(44, 9) + z(t)*Rational(-4, 9))] sol4 = [Eq(x(t), C1*exp(2*t) + C2*t*exp(2*t)), Eq(y(t), C2*exp(2*t) + 2*C3*exp(4*t)), Eq(z(t), 2*C3*exp(4*t) + C4*exp(5*t)*Rational(-1, 4)), Eq(w(t), C3*exp(4*t) + C4*exp(5*t))] assert dsolve(eqs4) == sol4 assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0, 0]) # Regression test case for issue #15574 # https://github.com/sympy/sympy/issues/15574 eq5 = [Eq(x(t).diff(t), x(t)), Eq(y(t).diff(t), y(t)), Eq(z(t).diff(t), z(t)), Eq(w(t).diff(t), w(t))] sol5 = [Eq(x(t), C1*exp(t)), Eq(y(t), C2*exp(t)), Eq(z(t), C3*exp(t)), Eq(w(t), C4*exp(t))] assert dsolve(eq5) == sol5 assert checksysodesol(eq5, sol5) == (True, [0, 0, 0, 0]) eqs6 = [Eq(Derivative(x(t), t), x(t) + y(t)), Eq(Derivative(y(t), t), y(t) + z(t)), Eq(Derivative(z(t), t), w(t)*Rational(-1, 8) + z(t)), Eq(Derivative(w(t), t), w(t)/2 + z(t)/2)] sol6 = [Eq(x(t), C1*exp(t) + C2*t*exp(t) + 4*C4*t*exp(t*Rational(3, 4)) + (4*C3 + 48*C4)*exp(t*Rational(3, 4))), Eq(y(t), C2*exp(t) - C4*t*exp(t*Rational(3, 4)) - (C3 + 8*C4)*exp(t*Rational(3, 4))), Eq(z(t), C4*t*exp(t*Rational(3, 4))/4 + (C3/4 + C4)*exp(t*Rational(3, 4))), Eq(w(t), C3*exp(t*Rational(3, 4))/2 + C4*t*exp(t*Rational(3, 4))/2)] assert dsolve(eqs6) == sol6 assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0, 0]) # Regression test case for issue #15574 # https://github.com/sympy/sympy/issues/15574 eq7 = [Eq(Derivative(x(t), t), x(t)), Eq(Derivative(y(t), t), y(t)), Eq(Derivative(z(t), t), z(t)), Eq(Derivative(w(t), t), w(t)), Eq(Derivative(u(t), t), u(t))] sol7 = [Eq(x(t), C1*exp(t)), Eq(y(t), C2*exp(t)), Eq(z(t), C3*exp(t)), Eq(w(t), C4*exp(t)), Eq(u(t), C5*exp(t))] assert dsolve(eq7) == sol7 assert checksysodesol(eq7, sol7) == (True, [0, 0, 0, 0, 0]) eqs8 = [Eq(Derivative(x(t), t), 2*x(t) + y(t)), Eq(Derivative(y(t), t), 2*y(t)), Eq(Derivative(z(t), t), 4*z(t)), Eq(Derivative(w(t), t), u(t) + 5*w(t)), Eq(Derivative(u(t), t), 5*u(t))] sol8 = [Eq(x(t), C1*exp(2*t) + C2*t*exp(2*t)), Eq(y(t), C2*exp(2*t)), Eq(z(t), C3*exp(4*t)), Eq(w(t), C4*exp(5*t) + C5*t*exp(5*t)), Eq(u(t), C5*exp(5*t))] assert dsolve(eqs8) == sol8 assert checksysodesol(eqs8, sol8) == (True, [0, 0, 0, 0, 0]) # Regression test case for issue #15574 # https://github.com/sympy/sympy/issues/15574 eq9 = [Eq(Derivative(x(t), t), x(t)), Eq(Derivative(y(t), t), y(t)), Eq(Derivative(z(t), t), z(t))] sol9 = [Eq(x(t), C1*exp(t)), Eq(y(t), C2*exp(t)), Eq(z(t), C3*exp(t))] assert dsolve(eq9) == sol9 assert checksysodesol(eq9, sol9) == (True, [0, 0, 0]) # Regression test case for issue #15407 # https://github.com/sympy/sympy/issues/15407 eqs10 = [Eq(Derivative(x(t), t), (-a_b - a_c)*x(t)), Eq(Derivative(y(t), t), a_b*y(t)), Eq(Derivative(z(t), t), a_c*x(t))] sol10 = [Eq(x(t), -C1*(a_b + a_c)*exp(-t*(a_b + a_c))/a_c), Eq(y(t), C2*exp(a_b*t)), Eq(z(t), C1*exp(-t*(a_b + a_c)) + C3)] assert dsolve(eqs10) == sol10 assert checksysodesol(eqs10, sol10) == (True, [0, 0, 0]) # Regression test case for issue #14312 # https://github.com/sympy/sympy/issues/14312 eqs11 = [Eq(Derivative(x(t), t), k3*y(t)), Eq(Derivative(y(t), t), (-k2 - k3)*y(t)), Eq(Derivative(z(t), t), k2*y(t))] sol11 = [Eq(x(t), C1 + C2*k3*exp(-t*(k2 + k3))/k2), Eq(y(t), -C2*(k2 + k3)*exp(-t*(k2 + k3))/k2), Eq(z(t), C2*exp(-t*(k2 + k3)) + C3)] assert dsolve(eqs11) == sol11 assert checksysodesol(eqs11, sol11) == (True, [0, 0, 0]) # Regression test case for issue #14312 # https://github.com/sympy/sympy/issues/14312 eqs12 = [Eq(Derivative(z(t), t), k2*y(t)), Eq(Derivative(x(t), t), k3*y(t)), Eq(Derivative(y(t), t), (-k2 - k3)*y(t))] sol12 = [Eq(z(t), C1 - C2*k2*exp(-t*(k2 + k3))/(k2 + k3)), Eq(x(t), -C2*k3*exp(-t*(k2 + k3))/(k2 + k3) + C3), Eq(y(t), C2*exp(-t*(k2 + k3)))] assert dsolve(eqs12) == sol12 assert checksysodesol(eqs12, sol12) == (True, [0, 0, 0]) f, g, h = symbols('f, g, h', cls=Function) a, b, c = symbols('a, b, c') # Regression test case for issue #15474 # https://github.com/sympy/sympy/issues/15474 eqs13 = [Eq(Derivative(f(t), t), 2*f(t) + g(t)), Eq(Derivative(g(t), t), a*f(t))] sol13 = [Eq(f(t), C1*exp(t*(sqrt(a + 1) + 1))/(sqrt(a + 1) - 1) - C2*exp(-t*(sqrt(a + 1) - 1))/(sqrt(a + 1) + 1)), Eq(g(t), C1*exp(t*(sqrt(a + 1) + 1)) + C2*exp(-t*(sqrt(a + 1) - 1)))] assert dsolve(eqs13) == sol13 assert checksysodesol(eqs13, sol13) == (True, [0, 0]) eqs14 = [Eq(Derivative(f(t), t), 2*g(t) - 3*h(t)), Eq(Derivative(g(t), t), -2*f(t) + 4*h(t)), Eq(Derivative(h(t), t), 3*f(t) - 4*g(t))] sol14 = [Eq(f(t), 2*C1 - sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(3, 25) + C3*Rational(-8, 25)) - cos(sqrt(29)*t)*(C2*Rational(8, 25) + sqrt(29)*C3*Rational(3, 25))), Eq(g(t), C1*Rational(3, 2) + sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(4, 25) + C3*Rational(6, 25)) - cos(sqrt(29)*t)*(C2*Rational(6, 25) + sqrt(29)*C3*Rational(-4, 25))), Eq(h(t), C1 + C2*cos(sqrt(29)*t) - C3*sin(sqrt(29)*t))] assert dsolve(eqs14) == sol14 assert checksysodesol(eqs14, sol14) == (True, [0, 0, 0]) eqs15 = [Eq(2*Derivative(f(t), t), 12*g(t) - 12*h(t)), Eq(3*Derivative(g(t), t), -8*f(t) + 8*h(t)), Eq(4*Derivative(h(t), t), 6*f(t) - 6*g(t))] sol15 = [Eq(f(t), C1 - sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(6, 13) + C3*Rational(-16, 13)) - cos(sqrt(29)*t)*(C2*Rational(16, 13) + sqrt(29)*C3*Rational(6, 13))), Eq(g(t), C1 + sin(sqrt(29)*t)*(sqrt(29)*C2*Rational(8, 39) + C3*Rational(16, 13)) - cos(sqrt(29)*t)*(C2*Rational(16, 13) + sqrt(29)*C3*Rational(-8, 39))), Eq(h(t), C1 + C2*cos(sqrt(29)*t) - C3*sin(sqrt(29)*t))] assert dsolve(eqs15) == sol15 assert checksysodesol(eqs15, sol15) == (True, [0, 0, 0]) eq16 = (Eq(diff(x(t), t), 21*x(t)), Eq(diff(y(t), t), 17*x(t) + 3*y(t)), Eq(diff(z(t), t), 5*x(t) + 7*y(t) + 9*z(t))) sol16 = [Eq(x(t), 216*C1*exp(21*t)/209), Eq(y(t), 204*C1*exp(21*t)/209 - 6*C2*exp(3*t)/7), Eq(z(t), C1*exp(21*t) + C2*exp(3*t) + C3*exp(9*t))] assert dsolve(eq16) == sol16 assert checksysodesol(eq16, sol16) == (True, [0, 0, 0]) eqs17 = [Eq(Derivative(x(t), t), 3*y(t) - 11*z(t)), Eq(Derivative(y(t), t), -3*x(t) + 7*z(t)), Eq(Derivative(z(t), t), 11*x(t) - 7*y(t))] sol17 = [Eq(x(t), C1*Rational(7, 3) - sin(sqrt(179)*t)*(sqrt(179)*C2*Rational(11, 170) + C3*Rational(-21, 170)) - cos(sqrt(179)*t)*(C2*Rational(21, 170) + sqrt(179)*C3*Rational(11, 170))), Eq(y(t), C1*Rational(11, 3) + sin(sqrt(179)*t)*(sqrt(179)*C2*Rational(7, 170) + C3*Rational(33, 170)) - cos(sqrt(179)*t)*(C2*Rational(33, 170) + sqrt(179)*C3*Rational(-7, 170))), Eq(z(t), C1 + C2*cos(sqrt(179)*t) - C3*sin(sqrt(179)*t))] assert dsolve(eqs17) == sol17 assert checksysodesol(eqs17, sol17) == (True, [0, 0, 0]) eqs18 = [Eq(3*Derivative(x(t), t), 20*y(t) - 20*z(t)), Eq(4*Derivative(y(t), t), -15*x(t) + 15*z(t)), Eq(5*Derivative(z(t), t), 12*x(t) - 12*y(t))] sol18 = [Eq(x(t), C1 - sin(5*sqrt(2)*t)*(sqrt(2)*C2*Rational(4, 3) - C3) - cos(5*sqrt(2)*t)*(C2 + sqrt(2)*C3*Rational(4, 3))), Eq(y(t), C1 + sin(5*sqrt(2)*t)*(sqrt(2)*C2*Rational(3, 4) + C3) - cos(5*sqrt(2)*t)*(C2 + sqrt(2)*C3*Rational(-3, 4))), Eq(z(t), C1 + C2*cos(5*sqrt(2)*t) - C3*sin(5*sqrt(2)*t))] assert dsolve(eqs18) == sol18 assert checksysodesol(eqs18, sol18) == (True, [0, 0, 0]) eqs19 = [Eq(Derivative(x(t), t), 4*x(t) - z(t)), Eq(Derivative(y(t), t), 2*x(t) + 2*y(t) - z(t)), Eq(Derivative(z(t), t), 3*x(t) + y(t))] sol19 = [Eq(x(t), C2*t**2*exp(2*t)/2 + t*(2*C2 + C3)*exp(2*t) + (C1 + C2 + 2*C3)*exp(2*t)), Eq(y(t), C2*t**2*exp(2*t)/2 + t*(2*C2 + C3)*exp(2*t) + (C1 + 2*C3)*exp(2*t)), Eq(z(t), C2*t**2*exp(2*t) + t*(3*C2 + 2*C3)*exp(2*t) + (2*C1 + 3*C3)*exp(2*t))] assert dsolve(eqs19) == sol19 assert checksysodesol(eqs19, sol19) == (True, [0, 0, 0]) eqs20 = [Eq(Derivative(x(t), t), 4*x(t) - y(t) - 2*z(t)), Eq(Derivative(y(t), t), 2*x(t) + y(t) - 2*z(t)), Eq(Derivative(z(t), t), 5*x(t) - 3*z(t))] sol20 = [Eq(x(t), C1*exp(2*t) - sin(t)*(C2*Rational(3, 5) + C3/5) - cos(t)*(C2/5 + C3*Rational(-3, 5))), Eq(y(t), -sin(t)*(C2*Rational(3, 5) + C3/5) - cos(t)*(C2/5 + C3*Rational(-3, 5))), Eq(z(t), C1*exp(2*t) - C2*sin(t) + C3*cos(t))] assert dsolve(eqs20) == sol20 assert checksysodesol(eqs20, sol20) == (True, [0, 0, 0]) eq21 = (Eq(diff(x(t), t), 9*y(t)), Eq(diff(y(t), t), 12*x(t))) sol21 = [Eq(x(t), -sqrt(3)*C1*exp(-6*sqrt(3)*t)/2 + sqrt(3)*C2*exp(6*sqrt(3)*t)/2), Eq(y(t), C1*exp(-6*sqrt(3)*t) + C2*exp(6*sqrt(3)*t))] assert dsolve(eq21) == sol21 assert checksysodesol(eq21, sol21) == (True, [0, 0]) eqs22 = [Eq(Derivative(x(t), t), 2*x(t) + 4*y(t)), Eq(Derivative(y(t), t), 12*x(t) + 41*y(t))] sol22 = [Eq(x(t), C1*(39 - sqrt(1713))*exp(t*(sqrt(1713) + 43)/2)*Rational(-1, 24) + C2*(39 + sqrt(1713))*exp(t*(43 - sqrt(1713))/2)*Rational(-1, 24)), Eq(y(t), C1*exp(t*(sqrt(1713) + 43)/2) + C2*exp(t*(43 - sqrt(1713))/2))] assert dsolve(eqs22) == sol22 assert checksysodesol(eqs22, sol22) == (True, [0, 0]) eqs23 = [Eq(Derivative(x(t), t), x(t) + y(t)), Eq(Derivative(y(t), t), -2*x(t) + 2*y(t))] sol23 = [Eq(x(t), (C1/4 + sqrt(7)*C2/4)*cos(sqrt(7)*t/2)*exp(t*Rational(3, 2)) + sin(sqrt(7)*t/2)*(sqrt(7)*C1/4 + C2*Rational(-1, 4))*exp(t*Rational(3, 2))), Eq(y(t), C1*cos(sqrt(7)*t/2)*exp(t*Rational(3, 2)) - C2*sin(sqrt(7)*t/2)*exp(t*Rational(3, 2)))] assert dsolve(eqs23) == sol23 assert checksysodesol(eqs23, sol23) == (True, [0, 0]) # Regression test case for issue #15474 # https://github.com/sympy/sympy/issues/15474 a = Symbol("a", real=True) eq24 = [x(t).diff(t) - a*y(t), y(t).diff(t) + a*x(t)] sol24 = [Eq(x(t), C1*sin(a*t) + C2*cos(a*t)), Eq(y(t), C1*cos(a*t) - C2*sin(a*t))] assert dsolve(eq24) == sol24 assert checksysodesol(eq24, sol24) == (True, [0, 0]) # Regression test case for issue #19150 # https://github.com/sympy/sympy/issues/19150 eqs25 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), (f(t) - 2*g(t) + x(t))/(b*c)), Eq(Derivative(x(t), t), (g(t) - 2*x(t) + y(t))/(b*c)), Eq(Derivative(y(t), t), (h(t) + x(t) - 2*y(t))/(b*c)), Eq(Derivative(h(t), t), 0)] sol25 = [Eq(f(t), -3*C1 + 4*C2), Eq(g(t), -2*C1 + 3*C2 - C3*exp(-2*t/(b*c)) + C4*exp(-t*(sqrt(2) + 2)/(b*c)) + C5*exp(-t*(2 - sqrt(2))/(b*c))), Eq(x(t), -C1 + 2*C2 - sqrt(2)*C4*exp(-t*(sqrt(2) + 2)/(b*c)) + sqrt(2)*C5*exp(-t*(2 - sqrt(2))/(b*c))), Eq(y(t), C2 + C3*exp(-2*t/(b*c)) + C4*exp(-t*(sqrt(2) + 2)/(b*c)) + C5*exp(-t*(2 - sqrt(2))/(b*c))), Eq(h(t), C1)] assert dsolve(eqs25) == sol25 assert checksysodesol(eqs25, sol25) == (True, [0, 0, 0, 0, 0]) eq26 = [Eq(Derivative(f(t), t), 2*f(t)), Eq(Derivative(g(t), t), 3*f(t) + 7*g(t))] sol26 = [Eq(f(t), -5*C1*exp(2*t)/3), Eq(g(t), C1*exp(2*t) + C2*exp(7*t))] assert dsolve(eq26) == sol26 assert checksysodesol(eq26, sol26) == (True, [0, 0]) eq27 = [Eq(Derivative(f(t), t), -9*I*f(t) - 4*g(t)), Eq(Derivative(g(t), t), -4*I*g(t))] sol27 = [Eq(f(t), 4*I*C1*exp(-4*I*t)/5 + C2*exp(-9*I*t)), Eq(g(t), C1*exp(-4*I*t))] assert dsolve(eq27) == sol27 assert checksysodesol(eq27, sol27) == (True, [0, 0]) eq28 = [Eq(Derivative(f(t), t), -9*I*f(t)), Eq(Derivative(g(t), t), -4*I*g(t))] sol28 = [Eq(f(t), C1*exp(-9*I*t)), Eq(g(t), C2*exp(-4*I*t))] assert dsolve(eq28) == sol28 assert checksysodesol(eq28, sol28) == (True, [0, 0]) eq29 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), 0)] sol29 = [Eq(f(t), C1), Eq(g(t), C2)] assert dsolve(eq29) == sol29 assert checksysodesol(eq29, sol29) == (True, [0, 0]) eq30 = [Eq(Derivative(f(t), t), f(t)), Eq(Derivative(g(t), t), 0)] sol30 = [Eq(f(t), C1*exp(t)), Eq(g(t), C2)] assert dsolve(eq30) == sol30 assert checksysodesol(eq30, sol30) == (True, [0, 0]) eq31 = [Eq(Derivative(f(t), t), g(t)), Eq(Derivative(g(t), t), 0)] sol31 = [Eq(f(t), C1 + C2*t), Eq(g(t), C2)] assert dsolve(eq31) == sol31 assert checksysodesol(eq31, sol31) == (True, [0, 0]) eq32 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), f(t))] sol32 = [Eq(f(t), C1), Eq(g(t), C1*t + C2)] assert dsolve(eq32) == sol32 assert checksysodesol(eq32, sol32) == (True, [0, 0]) eq33 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), g(t))] sol33 = [Eq(f(t), C1), Eq(g(t), C2*exp(t))] assert dsolve(eq33) == sol33 assert checksysodesol(eq33, sol33) == (True, [0, 0]) eq34 = [Eq(Derivative(f(t), t), f(t)), Eq(Derivative(g(t), t), I*g(t))] sol34 = [Eq(f(t), C1*exp(t)), Eq(g(t), C2*exp(I*t))] assert dsolve(eq34) == sol34 assert checksysodesol(eq34, sol34) == (True, [0, 0]) eq35 = [Eq(Derivative(f(t), t), I*f(t)), Eq(Derivative(g(t), t), -I*g(t))] sol35 = [Eq(f(t), C1*exp(I*t)), Eq(g(t), C2*exp(-I*t))] assert dsolve(eq35) == sol35 assert checksysodesol(eq35, sol35) == (True, [0, 0]) eq36 = [Eq(Derivative(f(t), t), I*g(t)), Eq(Derivative(g(t), t), 0)] sol36 = [Eq(f(t), I*C1 + I*C2*t), Eq(g(t), C2)] assert dsolve(eq36) == sol36 assert checksysodesol(eq36, sol36) == (True, [0, 0]) eq37 = [Eq(Derivative(f(t), t), I*g(t)), Eq(Derivative(g(t), t), I*f(t))] sol37 = [Eq(f(t), -C1*exp(-I*t) + C2*exp(I*t)), Eq(g(t), C1*exp(-I*t) + C2*exp(I*t))] assert dsolve(eq37) == sol37 assert checksysodesol(eq37, sol37) == (True, [0, 0]) # Multiple systems eq1 = [Eq(Derivative(f(t), t)**2, g(t)**2), Eq(-f(t) + Derivative(g(t), t), 0)] sol1 = [[Eq(f(t), -C1*sin(t) - C2*cos(t)), Eq(g(t), C1*cos(t) - C2*sin(t))], [Eq(f(t), -C1*exp(-t) + C2*exp(t)), Eq(g(t), C1*exp(-t) + C2*exp(t))]] assert dsolve(eq1) == sol1 for sol in sol1: assert checksysodesol(eq1, sol) == (True, [0, 0]) def test_sysode_linear_neq_order1_type2(): f, g, h, k = symbols('f g h k', cls=Function) x, t, a, b, c, d, y = symbols('x t a b c d y') k1, k2 = symbols('k1 k2') eqs1 = [Eq(Derivative(f(x), x), f(x) + g(x) + 5), Eq(Derivative(g(x), x), -f(x) - g(x) + 7)] sol1 = [Eq(f(x), C1 + C2 + 6*x**2 + x*(C2 + 5)), Eq(g(x), -C1 - 6*x**2 - x*(C2 - 7))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) eqs2 = [Eq(Derivative(f(x), x), f(x) + g(x) + 5), Eq(Derivative(g(x), x), f(x) + g(x) + 7)] sol2 = [Eq(f(x), -C1 + C2*exp(2*x) - x - 3), Eq(g(x), C1 + C2*exp(2*x) + x - 3)] assert dsolve(eqs2) == sol2 assert checksysodesol(eqs2, sol2) == (True, [0, 0]) eqs3 = [Eq(Derivative(f(x), x), f(x) + 5), Eq(Derivative(g(x), x), f(x) + 7)] sol3 = [Eq(f(x), C1*exp(x) - 5), Eq(g(x), C1*exp(x) + C2 + 2*x - 5)] assert dsolve(eqs3) == sol3 assert checksysodesol(eqs3, sol3) == (True, [0, 0]) eqs4 = [Eq(Derivative(f(x), x), f(x) + exp(x)), Eq(Derivative(g(x), x), x*exp(x) + f(x) + g(x))] sol4 = [Eq(f(x), C1*exp(x) + x*exp(x)), Eq(g(x), C1*x*exp(x) + C2*exp(x) + x**2*exp(x))] assert dsolve(eqs4) == sol4 assert checksysodesol(eqs4, sol4) == (True, [0, 0]) eqs5 = [Eq(Derivative(f(x), x), 5*x + f(x) + g(x)), Eq(Derivative(g(x), x), f(x) - g(x))] sol5 = [Eq(f(x), C1*(1 + sqrt(2))*exp(sqrt(2)*x) + C2*(1 - sqrt(2))*exp(-sqrt(2)*x) + x*Rational(-5, 2) + Rational(-5, 2)), Eq(g(x), C1*exp(sqrt(2)*x) + C2*exp(-sqrt(2)*x) + x*Rational(-5, 2))] assert dsolve(eqs5) == sol5 assert checksysodesol(eqs5, sol5) == (True, [0, 0]) eqs6 = [Eq(Derivative(f(x), x), -9*f(x) - 4*g(x)), Eq(Derivative(g(x), x), -4*g(x)), Eq(Derivative(h(x), x), h(x) + exp(x))] sol6 = [Eq(f(x), C1*exp(-4*x)*Rational(-4, 5) + C2*exp(-9*x)), Eq(g(x), C1*exp(-4*x)), Eq(h(x), C3*exp(x) + x*exp(x))] assert dsolve(eqs6) == sol6 assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0]) # Regression test case for issue #8859 # https://github.com/sympy/sympy/issues/8859 eqs7 = [Eq(Derivative(f(t), t), 3*t + f(t)), Eq(Derivative(g(t), t), g(t))] sol7 = [Eq(f(t), C1*exp(t) - 3*t - 3), Eq(g(t), C2*exp(t))] assert dsolve(eqs7) == sol7 assert checksysodesol(eqs7, sol7) == (True, [0, 0]) # Regression test case for issue #8567 # https://github.com/sympy/sympy/issues/8567 eqs8 = [Eq(Derivative(f(t), t), f(t) + 2*g(t)), Eq(Derivative(g(t), t), -2*f(t) + g(t) + 2*exp(t))] sol8 = [Eq(f(t), C1*exp(t)*sin(2*t) + C2*exp(t)*cos(2*t) + exp(t)*cos(2*t)**2 + 2*exp(t)*sin(2*t)*tan(t)/(tan(t)**2 + 1)), Eq(g(t), C1*exp(t)*cos(2*t) - C2*exp(t)*sin(2*t) - exp(t)*sin(2*t)*cos(2*t) + 2*exp(t)*cos(2*t)*tan(t)/(tan(t)**2 + 1))] assert dsolve(eqs8) == sol8 assert checksysodesol(eqs8, sol8) == (True, [0, 0]) # Regression test case for issue #19150 # https://github.com/sympy/sympy/issues/19150 eqs9 = [Eq(Derivative(f(t), t), (c - 2*f(t) + g(t))/(a*b)), Eq(Derivative(g(t), t), (f(t) - 2*g(t) + h(t))/(a*b)), Eq(Derivative(h(t), t), (d + g(t) - 2*h(t))/(a*b))] sol9 = [Eq(f(t), -C1*exp(-2*t/(a*b)) + C2*exp(-t*(sqrt(2) + 2)/(a*b)) + C3*exp(-t*(2 - sqrt(2))/(a*b)) + Mul(Rational(1, 4), 3*c + d, evaluate=False)), Eq(g(t), -sqrt(2)*C2*exp(-t*(sqrt(2) + 2)/(a*b)) + sqrt(2)*C3*exp(-t*(2 - sqrt(2))/(a*b)) + Mul(Rational(1, 2), c + d, evaluate=False)), Eq(h(t), C1*exp(-2*t/(a*b)) + C2*exp(-t*(sqrt(2) + 2)/(a*b)) + C3*exp(-t*(2 - sqrt(2))/(a*b)) + Mul(Rational(1, 4), c + 3*d, evaluate=False))] assert dsolve(eqs9) == sol9 assert checksysodesol(eqs9, sol9) == (True, [0, 0, 0]) # Regression test case for issue #16635 # https://github.com/sympy/sympy/issues/16635 eqs10 = [Eq(Derivative(f(t), t), 15*t + f(t) - g(t) - 10), Eq(Derivative(g(t), t), -15*t + f(t) - g(t) - 5)] sol10 = [Eq(f(t), C1 + C2 + 5*t**3 + 5*t**2 + t*(C2 - 10)), Eq(g(t), C1 + 5*t**3 - 10*t**2 + t*(C2 - 5))] assert dsolve(eqs10) == sol10 assert checksysodesol(eqs10, sol10) == (True, [0, 0]) # Multiple solutions eqs11 = [Eq(Derivative(f(t), t)**2 - 2*Derivative(f(t), t) + 1, 4), Eq(-y*f(t) + Derivative(g(t), t), 0)] sol11 = [[Eq(f(t), C1 - t), Eq(g(t), C1*t*y + C2*y + t**2*y*Rational(-1, 2))], [Eq(f(t), C1 + 3*t), Eq(g(t), C1*t*y + C2*y + t**2*y*Rational(3, 2))]] assert dsolve(eqs11) == sol11 for s11 in sol11: assert checksysodesol(eqs11, s11) == (True, [0, 0]) # test case for issue #19831 # https://github.com/sympy/sympy/issues/19831 n = symbols('n', positive=True) x0 = symbols('x_0') t0 = symbols('t_0') x_0 = symbols('x_0') t_0 = symbols('t_0') t = symbols('t') x = Function('x') y = Function('y') T = symbols('T') eqs12 = [Eq(Derivative(y(t), t), x(t)), Eq(Derivative(x(t), t), n*(y(t) + 1))] sol12 = [Eq(y(t), C1*exp(sqrt(n)*t)*n**Rational(-1, 2) - C2*exp(-sqrt(n)*t)*n**Rational(-1, 2) - 1), Eq(x(t), C1*exp(sqrt(n)*t) + C2*exp(-sqrt(n)*t))] assert dsolve(eqs12) == sol12 assert checksysodesol(eqs12, sol12) == (True, [0, 0]) sol12b = [ Eq(y(t), (T*exp(-sqrt(n)*t_0)/2 + exp(-sqrt(n)*t_0)/2 + x_0*exp(-sqrt(n)*t_0)/(2*sqrt(n)))*exp(sqrt(n)*t) + (T*exp(sqrt(n)*t_0)/2 + exp(sqrt(n)*t_0)/2 - x_0*exp(sqrt(n)*t_0)/(2*sqrt(n)))*exp(-sqrt(n)*t) - 1), Eq(x(t), (T*sqrt(n)*exp(-sqrt(n)*t_0)/2 + sqrt(n)*exp(-sqrt(n)*t_0)/2 + x_0*exp(-sqrt(n)*t_0)/2)*exp(sqrt(n)*t) - (T*sqrt(n)*exp(sqrt(n)*t_0)/2 + sqrt(n)*exp(sqrt(n)*t_0)/2 - x_0*exp(sqrt(n)*t_0)/2)*exp(-sqrt(n)*t)) ] assert dsolve(eqs12, ics={y(t0): T, x(t0): x0}) == sol12b assert checksysodesol(eqs12, sol12b) == (True, [0, 0]) #Test cases added for the issue 19763 #https://github.com/sympy/sympy/issues/19763 eq13 = [Eq(Derivative(f(t), t), f(t) + g(t) + 9), Eq(Derivative(g(t), t), 2*f(t) + 5*g(t) + 23)] sol13 = [Eq(f(t), -C1*(2 + sqrt(6))*exp(t*(3 - sqrt(6)))/2 - C2*(2 - sqrt(6))*exp(t*(sqrt(6) + 3))/2 - Rational(22,3)), Eq(g(t), C1*exp(t*(3 - sqrt(6))) + C2*exp(t*(sqrt(6) + 3)) - Rational(5,3))] assert dsolve(eq13) == sol13 assert checksysodesol(eq13, sol13) == (True, [0, 0]) eq14 = [Eq(Derivative(f(t), t), f(t) + g(t) + 81), Eq(Derivative(g(t), t), -2*f(t) + g(t) + 23)] sol14 = [Eq(f(t), sqrt(2)*C1*exp(t)*sin(sqrt(2)*t)/2 + sqrt(2)*C2*exp(t)*cos(sqrt(2)*t)/2 + sqrt(2)*exp(t)*sin(sqrt(2)*t)*Integral(-23*exp(-t)*sin(sqrt(2)*t)**2/cos(sqrt(2)*t) + 81*sqrt(2)*exp(-t)*sin(sqrt(2)*t) + 23*exp(-t)/cos(sqrt(2)*t), t)/2 + 185*sqrt(2)*sin(sqrt(2)*t)*cos(sqrt(2)*t)/6 - 58*cos(sqrt(2)*t)**2/3), Eq(g(t), C1*exp(t)*cos(sqrt(2)*t) - C2*exp(t)*sin(sqrt(2)*t) + exp(t)*cos(sqrt(2)*t)*Integral(-23*exp(-t)*sin(sqrt(2)*t)**2/cos(sqrt(2)*t) + 81*sqrt(2)*exp(-t)*sin(sqrt(2)*t) + 23*exp(-t)/cos(sqrt(2)*t), t) - 185*sin(sqrt(2)*t)**2/3 + 58*sqrt(2)*sin(sqrt(2)*t)*cos(sqrt(2)*t)/3)] assert dsolve(eq14) == sol14 assert checksysodesol(eq14 , sol14) == (True , [0,0]) eq15 = [Eq(Derivative(f(t), t), f(t) + 2*g(t) + k1), Eq(Derivative(g(t), t), 3*f(t) + 4*g(t) + k2)] sol15 = [Eq(f(t), -C1*(3 - sqrt(33))*exp(t*(5 + sqrt(33))/2)/6 - C2*(3 + sqrt(33))*exp(t*(5 - sqrt(33))/2)/6 + 2*k1 - k2), Eq(g(t), C1*exp(t*(5 + sqrt(33))/2) + C2*exp(t*(5 - sqrt(33))/2) - Mul(Rational(1,2) , 3*k1 - k2 , evaluate = False))] assert dsolve(eq15) == sol15 assert checksysodesol(eq15 , sol15) == (True , [0,0]) eq16 = [Eq(Derivative(f(t), t), k1), Eq(Derivative(g(t), t), k2)] sol16 = [Eq(f(t), C1 + k1*t), Eq(g(t), C2 + k2*t)] assert dsolve(eq16) == sol16 assert checksysodesol(eq16 , sol16) == (True , [0,0]) eq17 = [Eq(Derivative(f(t), t), 0), Eq(Derivative(g(t), t), c*f(t) + k2)] sol17 = [Eq(f(t), C1), Eq(g(t), C2*c + t*(C1*c + k2))] assert dsolve(eq17) == sol17 assert checksysodesol(eq17 , sol17) == (True , [0,0]) eq18 = [Eq(Derivative(f(t), t), k1), Eq(Derivative(g(t), t), f(t) + k2)] sol18 = [Eq(f(t), C1 + k1*t), Eq(g(t), C2 + k1*t**2/2 + t*(C1 + k2))] assert dsolve(eq18) == sol18 assert checksysodesol(eq18 , sol18) == (True , [0,0]) eq19 = [Eq(Derivative(f(t), t), k1), Eq(Derivative(g(t), t), f(t) + 2*g(t) + k2)] sol19 = [Eq(f(t), -2*C1 + k1*t), Eq(g(t), C1 + C2*exp(2*t) - k1*t/2 - Mul(Rational(1,4), k1 + 2*k2 , evaluate = False))] assert dsolve(eq19) == sol19 assert checksysodesol(eq19 , sol19) == (True , [0,0]) eq20 = [Eq(diff(f(t), t), f(t) + k1), Eq(diff(g(t), t), k2)] sol20 = [Eq(f(t), C1*exp(t) - k1), Eq(g(t), C2 + k2*t)] assert dsolve(eq20) == sol20 assert checksysodesol(eq20 , sol20) == (True , [0,0]) eq21 = [Eq(diff(f(t), t), g(t) + k1), Eq(diff(g(t), t), 0)] sol21 = [Eq(f(t), C1 + t*(C2 + k1)), Eq(g(t), C2)] assert dsolve(eq21) == sol21 assert checksysodesol(eq21 , sol21) == (True , [0,0]) eq22 = [Eq(Derivative(f(t), t), f(t) + 2*g(t) + k1), Eq(Derivative(g(t), t), k2)] sol22 = [Eq(f(t), -2*C1 + C2*exp(t) - k1 - 2*k2*t - 2*k2), Eq(g(t), C1 + k2*t)] assert dsolve(eq22) == sol22 assert checksysodesol(eq22 , sol22) == (True , [0,0]) eq23 = [Eq(Derivative(f(t), t), g(t) + k1), Eq(Derivative(g(t), t), 2*g(t) + k2)] sol23 = [Eq(f(t), C1 + C2*exp(2*t)/2 - k2/4 + t*(2*k1 - k2)/2), Eq(g(t), C2*exp(2*t) - k2/2)] assert dsolve(eq23) == sol23 assert checksysodesol(eq23 , sol23) == (True , [0,0]) eq24 = [Eq(Derivative(f(t), t), f(t) + k1), Eq(Derivative(g(t), t), 2*f(t) + k2)] sol24 = [Eq(f(t), C1*exp(t)/2 - k1), Eq(g(t), C1*exp(t) + C2 - 2*k1 - t*(2*k1 - k2))] assert dsolve(eq24) == sol24 assert checksysodesol(eq24 , sol24) == (True , [0,0]) eq25 = [Eq(Derivative(f(t), t), f(t) + 2*g(t) + k1), Eq(Derivative(g(t), t), 3*f(t) + 6*g(t) + k2)] sol25 = [Eq(f(t), -2*C1 + C2*exp(7*t)/3 + 2*t*(3*k1 - k2)/7 - Mul(Rational(1,49), k1 + 2*k2 , evaluate = False)), Eq(g(t), C1 + C2*exp(7*t) - t*(3*k1 - k2)/7 - Mul(Rational(3,49), k1 + 2*k2 , evaluate = False))] assert dsolve(eq25) == sol25 assert checksysodesol(eq25 , sol25) == (True , [0,0]) eq26 = [Eq(Derivative(f(t), t), 2*f(t) - g(t) + k1), Eq(Derivative(g(t), t), 4*f(t) - 2*g(t) + 2*k1)] sol26 = [Eq(f(t), C1 + 2*C2 + t*(2*C1 + k1)), Eq(g(t), 4*C2 + t*(4*C1 + 2*k1))] assert dsolve(eq26) == sol26 assert checksysodesol(eq26 , sol26) == (True , [0,0]) def test_sysode_linear_neq_order1_type3(): f, g, h, k, x0 , y0 = symbols('f g h k x0 y0', cls=Function) x, t, a = symbols('x t a') r = symbols('r', real=True) eqs1 = [Eq(Derivative(f(r), r), r*g(r) + f(r)), Eq(Derivative(g(r), r), -r*f(r) + g(r))] sol1 = [Eq(f(r), C1*exp(r)*sin(r**2/2) + C2*exp(r)*cos(r**2/2)), Eq(g(r), C1*exp(r)*cos(r**2/2) - C2*exp(r)*sin(r**2/2))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) eqs2 = [Eq(Derivative(f(x), x), x**2*g(x) + x*f(x)), Eq(Derivative(g(x), x), 2*x**2*f(x) + (3*x**2 + x)*g(x))] sol2 = [Eq(f(x), (sqrt(17)*C1/17 + C2*(17 - 3*sqrt(17))/34)*exp(x**3*(3 + sqrt(17))/6 + x**2/2) - exp(x**3*(3 - sqrt(17))/6 + x**2/2)*(sqrt(17)*C1/17 + C2*(3*sqrt(17) + 17)*Rational(-1, 34))), Eq(g(x), exp(x**3*(3 - sqrt(17))/6 + x**2/2)*(C1*(17 - 3*sqrt(17))/34 + sqrt(17)*C2*Rational(-2, 17)) + exp(x**3*(3 + sqrt(17))/6 + x**2/2)*(C1*(3*sqrt(17) + 17)/34 + sqrt(17)*C2*Rational(2, 17)))] assert dsolve(eqs2) == sol2 assert checksysodesol(eqs2, sol2) == (True, [0, 0]) eqs3 = [Eq(f(x).diff(x), x*f(x) + g(x)), Eq(g(x).diff(x), -f(x) + x*g(x))] sol3 = [Eq(f(x), (C1/2 + I*C2/2)*exp(x**2/2 - I*x) + exp(x**2/2 + I*x)*(C1/2 + I*C2*Rational(-1, 2))), Eq(g(x), (I*C1/2 + C2/2)*exp(x**2/2 + I*x) - exp(x**2/2 - I*x)*(I*C1/2 + C2*Rational(-1, 2)))] assert dsolve(eqs3) == sol3 assert checksysodesol(eqs3, sol3) == (True, [0, 0]) eqs4 = [Eq(f(x).diff(x), x*(f(x) + g(x) + h(x))), Eq(g(x).diff(x), x*(f(x) + g(x) + h(x))), Eq(h(x).diff(x), x*(f(x) + g(x) + h(x)))] sol4 = [Eq(f(x), -C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2)), Eq(g(x), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2)), Eq(h(x), -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2))] assert dsolve(eqs4) == sol4 assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0]) eqs5 = [Eq(f(x).diff(x), x**2*(f(x) + g(x) + h(x))), Eq(g(x).diff(x), x**2*(f(x) + g(x) + h(x))), Eq(h(x).diff(x), x**2*(f(x) + g(x) + h(x)))] sol5 = [Eq(f(x), -C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + C3/3)*exp(x**3)), Eq(g(x), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(x**3)), Eq(h(x), -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(x**3))] assert dsolve(eqs5) == sol5 assert checksysodesol(eqs5, sol5) == (True, [0, 0, 0]) eqs6 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x) + k(x))), Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x) + k(x))), Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x) + k(x))), Eq(Derivative(k(x), x), x*(f(x) + g(x) + h(x) + k(x)))] sol6 = [Eq(f(x), -C1/4 - C2/4 - C3/4 + 3*C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2)), Eq(g(x), 3*C1/4 - C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2)), Eq(h(x), -C1/4 + 3*C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2)), Eq(k(x), -C1/4 - C2/4 + 3*C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2))] assert dsolve(eqs6) == sol6 assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0, 0]) y = symbols("y", real=True) eqs7 = [Eq(Derivative(f(y), y), y*f(y) + g(y)), Eq(Derivative(g(y), y), y*g(y) - f(y))] sol7 = [Eq(f(y), C1*exp(y**2/2)*sin(y) + C2*exp(y**2/2)*cos(y)), Eq(g(y), C1*exp(y**2/2)*cos(y) - C2*exp(y**2/2)*sin(y))] assert dsolve(eqs7) == sol7 assert checksysodesol(eqs7, sol7) == (True, [0, 0]) #Test cases added for the issue 19763 #https://github.com/sympy/sympy/issues/19763 eqs8 = [Eq(Derivative(f(t), t), 5*t*f(t) + 2*h(t)), Eq(Derivative(h(t), t), 2*f(t) + 5*t*h(t))] sol8 = [Eq(f(t), Mul(-1, (C1/2 - C2/2), evaluate = False)*exp(5*t**2/2 - 2*t) + (C1/2 + C2/2)*exp(5*t**2/2 + 2*t)), Eq(h(t), (C1/2 - C2/2)*exp(5*t**2/2 - 2*t) + (C1/2 + C2/2)*exp(5*t**2/2 + 2*t))] assert dsolve(eqs8) == sol8 assert checksysodesol(eqs8, sol8) == (True, [0, 0]) eqs9 = [Eq(diff(f(t), t), 5*t*f(t) + t**2*g(t)), Eq(diff(g(t), t), -t**2*f(t) + 5*t*g(t))] sol9 = [Eq(f(t), (C1/2 - I*C2/2)*exp(I*t**3/3 + 5*t**2/2) + (C1/2 + I*C2/2)*exp(-I*t**3/3 + 5*t**2/2)), Eq(g(t), Mul(-1, (I*C1/2 - C2/2) , evaluate = False)*exp(-I*t**3/3 + 5*t**2/2) + (I*C1/2 + C2/2)*exp(I*t**3/3 + 5*t**2/2))] assert dsolve(eqs9) == sol9 assert checksysodesol(eqs9 , sol9) == (True , [0,0]) eqs10 = [Eq(diff(f(t), t), t**2*g(t) + 5*t*f(t)), Eq(diff(g(t), t), -t**2*f(t) + (9*t**2 + 5*t)*g(t))] sol10 = [Eq(f(t), (C1*(77 - 9*sqrt(77))/154 + sqrt(77)*C2/77)*exp(t**3*(sqrt(77) + 9)/6 + 5*t**2/2) + (C1*(77 + 9*sqrt(77))/154 - sqrt(77)*C2/77)*exp(t**3*(9 - sqrt(77))/6 + 5*t**2/2)), Eq(g(t), (sqrt(77)*C1/77 + C2*(77 - 9*sqrt(77))/154)*exp(t**3*(9 - sqrt(77))/6 + 5*t**2/2) - (sqrt(77)*C1/77 - C2*(77 + 9*sqrt(77))/154)*exp(t**3*(sqrt(77) + 9)/6 + 5*t**2/2))] assert dsolve(eqs10) == sol10 assert checksysodesol(eqs10 , sol10) == (True , [0,0]) eqs11 = [Eq(diff(f(t), t), 5*t*f(t) + t**2*g(t)), Eq(diff(g(t), t), (1-t**2)*f(t) + (5*t + 9*t**2)*g(t))] sol11 = [Eq(f(t), C1*x0(t) + C2*x0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t)), Eq(g(t), C1*y0(t) + C2*(y0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t) + exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)))] assert dsolve(eqs11) == sol11 @slow def test_sysode_linear_neq_order1_type4(): f, g, h, k = symbols('f g h k', cls=Function) x, t, a = symbols('x t a') r = symbols('r', real=True) eqs1 = [Eq(diff(f(r), r), f(r) + r*g(r) + r**2), Eq(diff(g(r), r), -r*f(r) + g(r) + r)] sol1 = [Eq(f(r), C1*exp(r)*sin(r**2/2) + C2*exp(r)*cos(r**2/2) + exp(r)*sin(r**2/2)*Integral(r**2*exp(-r)*sin(r**2/2) + r*exp(-r)*cos(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r**2*exp(-r)*cos(r**2/2) - r*exp(-r)*sin(r**2/2), r)), Eq(g(r), C1*exp(r)*cos(r**2/2) - C2*exp(r)*sin(r**2/2) - exp(r)*sin(r**2/2)*Integral(r**2*exp(-r)*cos(r**2/2) - r*exp(-r)*sin(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r**2*exp(-r)*sin(r**2/2) + r*exp(-r)*cos(r**2/2), r))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) eqs2 = [Eq(diff(f(r), r), f(r) + r*g(r) + r), Eq(diff(g(r), r), -r*f(r) + g(r) + log(r))] sol2 = [Eq(f(r), C1*exp(r)*sin(r**2/2) + C2*exp(r)*cos(r**2/2) + exp(r)*sin(r**2/2)*Integral(r*exp(-r)*sin(r**2/2) + exp(-r)*log(r)*cos(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r*exp(-r)*cos(r**2/2) - exp(-r)*log(r)*sin( r**2/2), r)), Eq(g(r), C1*exp(r)*cos(r**2/2) - C2*exp(r)*sin(r**2/2) - exp(r)*sin(r**2/2)*Integral(r*exp(-r)*cos(r**2/2) - exp(-r)*log(r)*sin(r**2/2), r) + exp(r)*cos(r**2/2)*Integral(r*exp(-r)*sin(r**2/2) + exp(-r)*log(r)*cos( r**2/2), r))] # XXX: dsolve hangs for this in integration assert dsolve_system(eqs2, simplify=False, doit=False) == [sol2] assert checksysodesol(eqs2, sol2) == (True, [0, 0]) eqs3 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x)) + x), Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x)) + x), Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x)) + 1)] sol3 = [Eq(f(x), C1*Rational(-1, 3) + C2*Rational(-1, 3) + C3*Rational(2, 3) + x**2/6 + x*Rational(-1, 3) + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + sqrt(6)*sqrt(pi)*erf(sqrt(6)*x/2)*exp(x**2*Rational(3, 2))/18 + Rational(-2, 9)), Eq(g(x), C1*Rational(2, 3) + C2*Rational(-1, 3) + C3*Rational(-1, 3) + x**2/6 + x*Rational(-1, 3) + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + sqrt(6)*sqrt(pi)*erf(sqrt(6)*x/2)*exp(x**2*Rational(3, 2))/18 + Rational(-2, 9)), Eq(h(x), C1*Rational(-1, 3) + C2*Rational(2, 3) + C3*Rational(-1, 3) + x**2*Rational(-1, 3) + x*Rational(2, 3) + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + sqrt(6)*sqrt(pi)*erf(sqrt(6)*x/2)*exp(x**2*Rational(3, 2))/18 + Rational(-2, 9))] assert dsolve(eqs3) == sol3 assert checksysodesol(eqs3, sol3) == (True, [0, 0, 0]) eqs4 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x)) + sin(x)), Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x)) + sin(x)), Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x)) + sin(x))] sol4 = [Eq(f(x), C1*Rational(-1, 3) + C2*Rational(-1, 3) + C3*Rational(2, 3) + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + Integral(sin(x)*exp(x**2*Rational(-3, 2)), x)*exp(x**2*Rational(3, 2))), Eq(g(x), C1*Rational(2, 3) + C2*Rational(-1, 3) + C3*Rational(-1, 3) + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + Integral(sin(x)*exp(x**2*Rational(-3, 2)), x)*exp(x**2*Rational(3, 2))), Eq(h(x), C1*Rational(-1, 3) + C2*Rational(2, 3) + C3*Rational(-1, 3) + (C1/3 + C2/3 + C3/3)*exp(x**2*Rational(3, 2)) + Integral(sin(x)*exp(x**2*Rational(-3, 2)), x)*exp(x**2*Rational(3, 2)))] assert dsolve(eqs4) == sol4 assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0]) eqs5 = [Eq(Derivative(f(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1)), Eq(Derivative(g(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1)), Eq(Derivative(h(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1)), Eq(Derivative(k(x), x), x*(f(x) + g(x) + h(x) + k(x) + 1))] sol5 = [Eq(f(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(3, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4)), Eq(g(x), C1*Rational(3, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4)), Eq(h(x), C1*Rational(-1, 4) + C2*Rational(3, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4)), Eq(k(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(3, 4) + C4*Rational(-1, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(2*x**2) + Rational(-1, 4))] assert dsolve(eqs5) == sol5 assert checksysodesol(eqs5, sol5) == (True, [0, 0, 0, 0]) eqs6 = [Eq(Derivative(f(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1)), Eq(Derivative(g(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1)), Eq(Derivative(h(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1)), Eq(Derivative(k(x), x), x**2*(f(x) + g(x) + h(x) + k(x) + 1))] sol6 = [Eq(f(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(3, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4)), Eq(g(x), C1*Rational(3, 4) + C2*Rational(-1, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4)), Eq(h(x), C1*Rational(-1, 4) + C2*Rational(3, 4) + C3*Rational(-1, 4) + C4*Rational(-1, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4)), Eq(k(x), C1*Rational(-1, 4) + C2*Rational(-1, 4) + C3*Rational(3, 4) + C4*Rational(-1, 4) + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x**3*Rational(4, 3)) + Rational(-1, 4))] assert dsolve(eqs6) == sol6 assert checksysodesol(eqs6, sol6) == (True, [0, 0, 0, 0]) eqs7 = [Eq(Derivative(f(x), x), (f(x) + g(x) + h(x))*log(x) + sin(x)), Eq(Derivative(g(x), x), (f(x) + g(x) + h(x))*log(x) + sin(x)), Eq(Derivative(h(x), x), (f(x) + g(x) + h(x))*log(x) + sin(x))] sol7 = [Eq(f(x), -C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + C3/3)*exp(x*(3*log(x) - 3)) + exp(x*(3*log(x) - 3))*Integral(exp(3*x)*exp(-3*x*log(x))*sin(x), x)), Eq(g(x), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(x*(3*log(x) - 3)) + exp(x*(3*log(x) - 3))*Integral(exp(3*x)*exp(-3*x*log(x))*sin(x), x)), Eq(h(x), -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(x*(3*log(x) - 3)) + exp(x*(3*log(x) - 3))*Integral(exp(3*x)*exp(-3*x*log(x))*sin(x), x))] with dotprodsimp(True): assert dsolve(eqs7, simplify=False, doit=False) == sol7 assert checksysodesol(eqs7, sol7) == (True, [0, 0, 0]) eqs8 = [Eq(Derivative(f(x), x), (f(x) + g(x) + h(x) + k(x))*log(x) + sin(x)), Eq(Derivative(g(x), x), (f(x) + g(x) + h(x) + k(x))*log(x) + sin(x)), Eq(Derivative(h(x), x), (f(x) + g(x) + h(x) + k(x))*log(x) + sin(x)), Eq(Derivative(k(x), x), (f(x) + g(x) + h(x) + k(x))*log(x) + sin(x))] sol8 = [Eq(f(x), -C1/4 - C2/4 - C3/4 + 3*C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x)), Eq(g(x), 3*C1/4 - C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x)), Eq(h(x), -C1/4 + 3*C2/4 - C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x)), Eq(k(x), -C1/4 - C2/4 + 3*C3/4 - C4/4 + (C1/4 + C2/4 + C3/4 + C4/4)*exp(x*(4*log(x) - 4)) + exp(x*(4*log(x) - 4))*Integral(exp(4*x)*exp(-4*x*log(x))*sin(x), x))] with dotprodsimp(True): assert dsolve(eqs8) == sol8 assert checksysodesol(eqs8, sol8) == (True, [0, 0, 0, 0]) def test_sysode_linear_neq_order1_type5_type6(): f, g = symbols("f g", cls=Function) x, x_ = symbols("x x_") # Type 5 eqs1 = [Eq(Derivative(f(x), x), (2*f(x) + g(x))/x), Eq(Derivative(g(x), x), (f(x) + 2*g(x))/x)] sol1 = [Eq(f(x), -C1*x + C2*x**3), Eq(g(x), C1*x + C2*x**3)] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) # Type 6 eqs2 = [Eq(Derivative(f(x), x), (2*f(x) + g(x) + 1)/x), Eq(Derivative(g(x), x), (x + f(x) + 2*g(x))/x)] sol2 = [Eq(f(x), C2*x**3 - x*(C1 + Rational(1, 4)) + x*log(x)*Rational(-1, 2) + Rational(-2, 3)), Eq(g(x), C2*x**3 + x*log(x)/2 + x*(C1 + Rational(-1, 4)) + Rational(1, 3))] assert dsolve(eqs2) == sol2 assert checksysodesol(eqs2, sol2) == (True, [0, 0]) def test_higher_order_to_first_order(): f, g = symbols('f g', cls=Function) x = symbols('x') eqs1 = [Eq(Derivative(f(x), (x, 2)), 2*f(x) + g(x)), Eq(Derivative(g(x), (x, 2)), -f(x))] sol1 = [Eq(f(x), -C2*x*exp(-x) + C3*x*exp(x) - (C1 - C2)*exp(-x) + (C3 + C4)*exp(x)), Eq(g(x), C2*x*exp(-x) - C3*x*exp(x) + (C1 + C2)*exp(-x) + (C3 - C4)*exp(x))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) eqs2 = [Eq(f(x).diff(x, 2), 0), Eq(g(x).diff(x, 2), f(x))] sol2 = [Eq(f(x), C1 + C2*x), Eq(g(x), C1*x**2/2 + C2*x**3/6 + C3 + C4*x)] assert dsolve(eqs2) == sol2 assert checksysodesol(eqs2, sol2) == (True, [0, 0]) eqs3 = [Eq(Derivative(f(x), (x, 2)), 2*f(x)), Eq(Derivative(g(x), (x, 2)), -f(x) + 2*g(x))] sol3 = [Eq(f(x), 4*C1*exp(-sqrt(2)*x) + 4*C2*exp(sqrt(2)*x)), Eq(g(x), sqrt(2)*C1*x*exp(-sqrt(2)*x) - sqrt(2)*C2*x*exp(sqrt(2)*x) + (C1 + sqrt(2)*C4)*exp(-sqrt(2)*x) + (C2 - sqrt(2)*C3)*exp(sqrt(2)*x))] assert dsolve(eqs3) == sol3 assert checksysodesol(eqs3, sol3) == (True, [0, 0]) eqs4 = [Eq(Derivative(f(x), (x, 2)), 2*f(x) + g(x)), Eq(Derivative(g(x), (x, 2)), 2*g(x))] sol4 = [Eq(f(x), C1*x*exp(sqrt(2)*x)/4 + C3*x*exp(-sqrt(2)*x)/4 + (C2/4 + sqrt(2)*C3/8)*exp(-sqrt(2)*x) - exp(sqrt(2)*x)*(sqrt(2)*C1/8 + C4*Rational(-1, 4))), Eq(g(x), sqrt(2)*C1*exp(sqrt(2)*x)/2 + sqrt(2)*C3*exp(-sqrt(2)*x)*Rational(-1, 2))] assert dsolve(eqs4) == sol4 assert checksysodesol(eqs4, sol4) == (True, [0, 0]) eqs5 = [Eq(f(x).diff(x, 2), f(x)), Eq(g(x).diff(x, 2), f(x))] sol5 = [Eq(f(x), -C1*exp(-x) + C2*exp(x)), Eq(g(x), -C1*exp(-x) + C2*exp(x) + C3 + C4*x)] assert dsolve(eqs5) == sol5 assert checksysodesol(eqs5, sol5) == (True, [0, 0]) eqs6 = [Eq(Derivative(f(x), (x, 2)), f(x) + g(x)), Eq(Derivative(g(x), (x, 2)), -f(x) - g(x))] sol6 = [Eq(f(x), C1 + C2*x**2/2 + C2 + C4*x**3/6 + x*(C3 + C4)), Eq(g(x), -C1 + C2*x**2*Rational(-1, 2) - C3*x + C4*x**3*Rational(-1, 6))] assert dsolve(eqs6) == sol6 assert checksysodesol(eqs6, sol6) == (True, [0, 0]) eqs7 = [Eq(Derivative(f(x), (x, 2)), f(x) + g(x) + 1), Eq(Derivative(g(x), (x, 2)), f(x) + g(x) + 1)] sol7 = [Eq(f(x), -C1 - C2*x + sqrt(2)*C3*exp(sqrt(2)*x)/2 + sqrt(2)*C4*exp(-sqrt(2)*x)*Rational(-1, 2) + Rational(-1, 2)), Eq(g(x), C1 + C2*x + sqrt(2)*C3*exp(sqrt(2)*x)/2 + sqrt(2)*C4*exp(-sqrt(2)*x)*Rational(-1, 2) + Rational(-1, 2))] assert dsolve(eqs7) == sol7 assert checksysodesol(eqs7, sol7) == (True, [0, 0]) eqs8 = [Eq(Derivative(f(x), (x, 2)), f(x) + g(x) + 1), Eq(Derivative(g(x), (x, 2)), -f(x) - g(x) + 1)] sol8 = [Eq(f(x), C1 + C2 + C4*x**3/6 + x**4/12 + x**2*(C2/2 + Rational(1, 2)) + x*(C3 + C4)), Eq(g(x), -C1 - C3*x + C4*x**3*Rational(-1, 6) + x**4*Rational(-1, 12) - x**2*(C2/2 + Rational(-1, 2)))] assert dsolve(eqs8) == sol8 assert checksysodesol(eqs8, sol8) == (True, [0, 0]) x, y = symbols('x, y', cls=Function) t, l = symbols('t, l') eqs10 = [Eq(Derivative(x(t), (t, 2)), 5*x(t) + 43*y(t)), Eq(Derivative(y(t), (t, 2)), x(t) + 9*y(t))] sol10 = [Eq(x(t), C1*(61 - 9*sqrt(47))*sqrt(sqrt(47) + 7)*exp(-t*sqrt(sqrt(47) + 7))/2 + C2*sqrt(7 - sqrt(47))*(61 + 9*sqrt(47))*exp(-t*sqrt(7 - sqrt(47)))/2 + C3*(61 - 9*sqrt(47))*sqrt(sqrt(47) + 7)*exp(t*sqrt(sqrt(47) + 7))*Rational(-1, 2) + C4*sqrt(7 - sqrt(47))*(61 + 9*sqrt(47))*exp(t*sqrt(7 - sqrt(47)))*Rational(-1, 2)), Eq(y(t), C1*(7 - sqrt(47))*sqrt(sqrt(47) + 7)*exp(-t*sqrt(sqrt(47) + 7))*Rational(-1, 2) + C2*sqrt(7 - sqrt(47))*(sqrt(47) + 7)*exp(-t*sqrt(7 - sqrt(47)))*Rational(-1, 2) + C3*(7 - sqrt(47))*sqrt(sqrt(47) + 7)*exp(t*sqrt(sqrt(47) + 7))/2 + C4*sqrt(7 - sqrt(47))*(sqrt(47) + 7)*exp(t*sqrt(7 - sqrt(47)))/2)] assert dsolve(eqs10) == sol10 assert checksysodesol(eqs10, sol10) == (True, [0, 0]) eqs11 = [Eq(7*x(t) + Derivative(x(t), (t, 2)) - 9*Derivative(y(t), t), 0), Eq(7*y(t) + 9*Derivative(x(t), t) + Derivative(y(t), (t, 2)), 0)] sol11 = [Eq(y(t), C1*(9 - sqrt(109))*sin(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)/14 + C2*(9 - sqrt(109))*cos(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)*Rational(-1, 14) + C3*(9 + sqrt(109))*sin(sqrt(2)*t*sqrt(95 - 9*sqrt(109))/2)/14 + C4*(9 + sqrt(109))*cos(sqrt(2)*t*sqrt(95 - 9*sqrt(109))/2)*Rational(-1, 14)), Eq(x(t), C1*(9 - sqrt(109))*cos(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)*Rational(-1, 14) + C2*(9 - sqrt(109))*sin(sqrt(2)*t*sqrt(9*sqrt(109) + 95)/2)*Rational(-1, 14) + C3*(9 + sqrt(109))*cos(sqrt(2)*t*sqrt(95 - 9*sqrt(109))/2)/14 + C4*(9 + sqrt(109))*sin(sqrt(2)*t*sqrt(95 - 9*sqrt(109))/2)/14)] assert dsolve(eqs11) == sol11 assert checksysodesol(eqs11, sol11) == (True, [0, 0]) # Euler Systems # Note: To add examples of euler systems solver with non-homogeneous term. eqs13 = [Eq(Derivative(f(t), (t, 2)), Derivative(f(t), t)/t + f(t)/t**2 + g(t)/t**2), Eq(Derivative(g(t), (t, 2)), g(t)/t**2)] sol13 = [Eq(f(t), C1*(sqrt(5) + 3)*Rational(-1, 2)*t**(Rational(1, 2) + sqrt(5)*Rational(-1, 2)) + C2*t**(Rational(1, 2) + sqrt(5)/2)*(3 - sqrt(5))*Rational(-1, 2) - C3*t**(1 - sqrt(2))*(1 + sqrt(2)) - C4*t**(1 + sqrt(2))*(1 - sqrt(2))), Eq(g(t), C1*(1 + sqrt(5))*Rational(-1, 2)*t**(Rational(1, 2) + sqrt(5)*Rational(-1, 2)) + C2*t**(Rational(1, 2) + sqrt(5)/2)*(1 - sqrt(5))*Rational(-1, 2))] assert dsolve(eqs13) == sol13 assert checksysodesol(eqs13, sol13) == (True, [0, 0]) # Solving systems using dsolve separately eqs14 = [Eq(Derivative(f(t), (t, 2)), t*f(t)), Eq(Derivative(g(t), (t, 2)), t*g(t))] sol14 = [Eq(f(t), C1*airyai(t) + C2*airybi(t)), Eq(g(t), C3*airyai(t) + C4*airybi(t))] assert dsolve(eqs14) == sol14 assert checksysodesol(eqs14, sol14) == (True, [0, 0]) eqs15 = [Eq(Derivative(x(t), (t, 2)), t*(4*Derivative(x(t), t) + 8*Derivative(y(t), t))), Eq(Derivative(y(t), (t, 2)), t*(12*Derivative(x(t), t) - 6*Derivative(y(t), t)))] sol15 = [Eq(x(t), C1 - erf(sqrt(6)*t)*(sqrt(6)*sqrt(pi)*C2/33 + sqrt(6)*sqrt(pi)*C3*Rational(-1, 44)) + erfi(sqrt(5)*t)*(sqrt(5)*sqrt(pi)*C2*Rational(2, 55) + sqrt(5)*sqrt(pi)*C3*Rational(4, 55))), Eq(y(t), C4 + erf(sqrt(6)*t)*(sqrt(6)*sqrt(pi)*C2*Rational(2, 33) + sqrt(6)*sqrt(pi)*C3*Rational(-1, 22)) + erfi(sqrt(5)*t)*(sqrt(5)*sqrt(pi)*C2*Rational(3, 110) + sqrt(5)*sqrt(pi)*C3*Rational(3, 55)))] assert dsolve(eqs15) == sol15 assert checksysodesol(eqs15, sol15) == (True, [0, 0]) @slow def test_higher_order_to_first_order_9(): f, g = symbols('f g', cls=Function) x = symbols('x') eqs9 = [f(x) + g(x) - 2*exp(I*x) + 2*Derivative(f(x), x) + Derivative(f(x), (x, 2)), f(x) + g(x) - 2*exp(I*x) + 2*Derivative(g(x), x) + Derivative(g(x), (x, 2))] sol9 = [Eq(f(x), -C1 + C2*exp(-2*x)/2 + (C3/2 + C4/2)*exp(-x)*sin(x) + (2 + I)*exp(I*x)*sin(x)**2*Rational(-1, 5) + (1 - 2*I)*exp(I*x)*sin(x)*cos(x)*Rational(2, 5) + (4 - 3*I)*exp(I*x)*cos(x)**2/5 + exp(-x)*sin(x)*Integral(-exp(x)*exp(I*x)*sin(x)**2/cos(x) + exp(x)*exp(I*x)*sin(x) + exp(x)*exp(I*x)/cos(x), x) - exp(-x)*cos(x)*Integral(-exp(x)*exp(I*x)*sin(x)**2/cos(x) + exp(x)*exp(I*x)*sin(x) + exp(x)*exp(I*x)/cos(x), x) - exp(-x)*cos(x)*(C3/2 + C4*Rational(-1, 2))), Eq(g(x), C1 + C2*exp(-2*x)*Rational(-1, 2) + (C3/2 + C4/2)*exp(-x)*sin(x) + (2 + I)*exp(I*x)*sin(x)**2*Rational(-1, 5) + (1 - 2*I)*exp(I*x)*sin(x)*cos(x)*Rational(2, 5) + (4 - 3*I)*exp(I*x)*cos(x)**2/5 + exp(-x)*sin(x)*Integral(-exp(x)*exp(I*x)*sin(x)**2/cos(x) + exp(x)*exp(I*x)*sin(x) + exp(x)*exp(I*x)/cos(x), x) - exp(-x)*cos(x)*Integral(-exp(x)*exp(I*x)*sin(x)**2/cos(x) + exp(x)*exp(I*x)*sin(x) + exp(x)*exp(I*x)/cos(x), x) - exp(-x)*cos(x)*(C3/2 + C4*Rational(-1, 2)))] assert dsolve(eqs9) == sol9 assert checksysodesol(eqs9, sol9) == (True, [0, 0]) def test_higher_order_to_first_order_12(): f, g = symbols('f g', cls=Function) x = symbols('x') x, y = symbols('x, y', cls=Function) t, l = symbols('t, l') eqs12 = [Eq(4*x(t) + Derivative(x(t), (t, 2)) + 8*Derivative(y(t), t), 0), Eq(4*y(t) - 8*Derivative(x(t), t) + Derivative(y(t), (t, 2)), 0)] sol12 = [Eq(y(t), C1*(2 - sqrt(5))*sin(2*t*sqrt(4*sqrt(5) + 9))*Rational(-1, 2) + C2*(2 - sqrt(5))*cos(2*t*sqrt(4*sqrt(5) + 9))/2 + C3*(2 + sqrt(5))*sin(2*t*sqrt(9 - 4*sqrt(5)))*Rational(-1, 2) + C4*(2 + sqrt(5))*cos(2*t*sqrt(9 - 4*sqrt(5)))/2), Eq(x(t), C1*(2 - sqrt(5))*cos(2*t*sqrt(4*sqrt(5) + 9))*Rational(-1, 2) + C2*(2 - sqrt(5))*sin(2*t*sqrt(4*sqrt(5) + 9))*Rational(-1, 2) + C3*(2 + sqrt(5))*cos(2*t*sqrt(9 - 4*sqrt(5)))/2 + C4*(2 + sqrt(5))*sin(2*t*sqrt(9 - 4*sqrt(5)))/2)] assert dsolve(eqs12) == sol12 assert checksysodesol(eqs12, sol12) == (True, [0, 0]) def test_second_order_to_first_order_2(): f, g = symbols("f g", cls=Function) x, t, x_, t_, d, a, m = symbols("x t x_ t_ d a m") eqs2 = [Eq(f(x).diff(x, 2), 2*(x*g(x).diff(x) - g(x))), Eq(g(x).diff(x, 2),-2*(x*f(x).diff(x) - f(x)))] sol2 = [Eq(f(x), C1*x + x*Integral(C2*exp(-x_)*exp(I*exp(2*x_))/2 + C2*exp(-x_)*exp(-I*exp(2*x_))/2 - I*C3*exp(-x_)*exp(I*exp(2*x_))/2 + I*C3*exp(-x_)*exp(-I*exp(2*x_))/2, (x_, log(x)))), Eq(g(x), C4*x + x*Integral(I*C2*exp(-x_)*exp(I*exp(2*x_))/2 - I*C2*exp(-x_)*exp(-I*exp(2*x_))/2 + C3*exp(-x_)*exp(I*exp(2*x_))/2 + C3*exp(-x_)*exp(-I*exp(2*x_))/2, (x_, log(x))))] # XXX: dsolve hangs for this in integration assert dsolve_system(eqs2, simplify=False, doit=False) == [sol2] assert checksysodesol(eqs2, sol2) == (True, [0, 0]) eqs3 = (Eq(diff(f(t),t,t), 9*t*diff(g(t),t)-9*g(t)), Eq(diff(g(t),t,t),7*t*diff(f(t),t)-7*f(t))) sol3 = [Eq(f(t), C1*t + t*Integral(C2*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/2 + C2*exp(-t_)* exp(-3*sqrt(7)*exp(2*t_)/2)/2 + 3*sqrt(7)*C3*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/14 - 3*sqrt(7)*C3*exp(-t_)*exp(-3*sqrt(7)*exp(2*t_)/2)/14, (t_, log(t)))), Eq(g(t), C4*t + t*Integral(sqrt(7)*C2*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/6 - sqrt(7)*C2*exp(-t_)* exp(-3*sqrt(7)*exp(2*t_)/2)/6 + C3*exp(-t_)*exp(3*sqrt(7)*exp(2*t_)/2)/2 + C3*exp(-t_)*exp(-3*sqrt(7)* exp(2*t_)/2)/2, (t_, log(t))))] # XXX: dsolve hangs for this in integration assert dsolve_system(eqs3, simplify=False, doit=False) == [sol3] assert checksysodesol(eqs3, sol3) == (True, [0, 0]) # Regression Test case for sympy#19238 # https://github.com/sympy/sympy/issues/19238 # Note: When the doit method is removed, these particular types of systems # can be divided first so that we have lesser number of big matrices. eqs5 = [Eq(Derivative(g(t), (t, 2)), a*m), Eq(Derivative(f(t), (t, 2)), 0)] sol5 = [Eq(g(t), C1 + C2*t + a*m*t**2/2), Eq(f(t), C3 + C4*t)] assert dsolve(eqs5) == sol5 assert checksysodesol(eqs5, sol5) == (True, [0, 0]) # Type 2 eqs6 = [Eq(Derivative(f(t), (t, 2)), f(t)/t**4), Eq(Derivative(g(t), (t, 2)), d*g(t)/t**4)] sol6 = [Eq(f(t), C1*sqrt(t**2)*exp(-1/t) - C2*sqrt(t**2)*exp(1/t)), Eq(g(t), C3*sqrt(t**2)*exp(-sqrt(d)/t)*d**Rational(-1, 2) - C4*sqrt(t**2)*exp(sqrt(d)/t)*d**Rational(-1, 2))] assert dsolve(eqs6) == sol6 assert checksysodesol(eqs6, sol6) == (True, [0, 0]) @slow def test_second_order_to_first_order_slow1(): f, g = symbols("f g", cls=Function) x, t, x_, t_, d, a, m = symbols("x t x_ t_ d a m") # Type 1 eqs1 = [Eq(f(x).diff(x, 2), 2/x *(x*g(x).diff(x) - g(x))), Eq(g(x).diff(x, 2),-2/x *(x*f(x).diff(x) - f(x)))] sol1 = [Eq(f(x), C1*x + 2*C2*x*Ci(2*x) - C2*sin(2*x) - 2*C3*x*Si(2*x) - C3*cos(2*x)), Eq(g(x), -2*C2*x*Si(2*x) - C2*cos(2*x) - 2*C3*x*Ci(2*x) + C3*sin(2*x) + C4*x)] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) def test_second_order_to_first_order_slow4(): f, g = symbols("f g", cls=Function) x, t, x_, t_, d, a, m = symbols("x t x_ t_ d a m") eqs4 = [Eq(Derivative(f(t), (t, 2)), t*sin(t)*Derivative(g(t), t) - g(t)*sin(t)), Eq(Derivative(g(t), (t, 2)), t*sin(t)*Derivative(f(t), t) - f(t)*sin(t))] sol4 = [Eq(f(t), C1*t + t*Integral(C2*exp(-t_)*exp(exp(t_)*cos(exp(t_)))*exp(-sin(exp(t_)))/2 + C2*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2 - C3*exp(-t_)*exp(exp(t_)*cos(exp(t_)))* exp(-sin(exp(t_)))/2 + C3*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2, (t_, log(t)))), Eq(g(t), C4*t + t*Integral(-C2*exp(-t_)*exp(exp(t_)*cos(exp(t_)))*exp(-sin(exp(t_)))/2 + C2*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2 + C3*exp(-t_)*exp(exp(t_)*cos(exp(t_)))* exp(-sin(exp(t_)))/2 + C3*exp(-t_)*exp(-exp(t_)*cos(exp(t_)))*exp(sin(exp(t_)))/2, (t_, log(t))))] # XXX: dsolve hangs for this in integration assert dsolve_system(eqs4, simplify=False, doit=False) == [sol4] assert checksysodesol(eqs4, sol4) == (True, [0, 0]) def test_component_division(): f, g, h, k = symbols('f g h k', cls=Function) x = symbols("x") funcs = [f(x), g(x), h(x), k(x)] eqs1 = [Eq(Derivative(f(x), x), 2*f(x)), Eq(Derivative(g(x), x), f(x)), Eq(Derivative(h(x), x), h(x)), Eq(Derivative(k(x), x), h(x)**4 + k(x))] sol1 = [Eq(f(x), 2*C1*exp(2*x)), Eq(g(x), C1*exp(2*x) + C2), Eq(h(x), C3*exp(x)), Eq(k(x), C3**4*exp(4*x)/3 + C4*exp(x))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0, 0, 0]) components1 = {((Eq(Derivative(f(x), x), 2*f(x)),), (Eq(Derivative(g(x), x), f(x)),)), ((Eq(Derivative(h(x), x), h(x)),), (Eq(Derivative(k(x), x), h(x)**4 + k(x)),))} eqsdict1 = ({f(x): set(), g(x): {f(x)}, h(x): set(), k(x): {h(x)}}, {f(x): Eq(Derivative(f(x), x), 2*f(x)), g(x): Eq(Derivative(g(x), x), f(x)), h(x): Eq(Derivative(h(x), x), h(x)), k(x): Eq(Derivative(k(x), x), h(x)**4 + k(x))}) graph1 = [{f(x), g(x), h(x), k(x)}, {(g(x), f(x)), (k(x), h(x))}] assert {tuple(tuple(scc) for scc in wcc) for wcc in _component_division(eqs1, funcs, x)} == components1 assert _eqs2dict(eqs1, funcs) == eqsdict1 assert [set(element) for element in _dict2graph(eqsdict1[0])] == graph1 eqs2 = [Eq(Derivative(f(x), x), 2*f(x)), Eq(Derivative(g(x), x), f(x)), Eq(Derivative(h(x), x), h(x)), Eq(Derivative(k(x), x), f(x)**4 + k(x))] sol2 = [Eq(f(x), C1*exp(2*x)), Eq(g(x), C1*exp(2*x)/2 + C2), Eq(h(x), C3*exp(x)), Eq(k(x), C1**4*exp(8*x)/7 + C4*exp(x))] assert dsolve(eqs2) == sol2 assert checksysodesol(eqs2, sol2) == (True, [0, 0, 0, 0]) components2 = {frozenset([(Eq(Derivative(f(x), x), 2*f(x)),), (Eq(Derivative(g(x), x), f(x)),), (Eq(Derivative(k(x), x), f(x)**4 + k(x)),)]), frozenset([(Eq(Derivative(h(x), x), h(x)),)])} eqsdict2 = ({f(x): set(), g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, {f(x): Eq(Derivative(f(x), x), 2*f(x)), g(x): Eq(Derivative(g(x), x), f(x)), h(x): Eq(Derivative(h(x), x), h(x)), k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) graph2 = [{f(x), g(x), h(x), k(x)}, {(g(x), f(x)), (k(x), f(x))}] assert {frozenset(tuple(scc) for scc in wcc) for wcc in _component_division(eqs2, funcs, x)} == components2 assert _eqs2dict(eqs2, funcs) == eqsdict2 assert [set(element) for element in _dict2graph(eqsdict2[0])] == graph2 eqs3 = [Eq(Derivative(f(x), x), 2*f(x)), Eq(Derivative(g(x), x), x + f(x)), Eq(Derivative(h(x), x), h(x)), Eq(Derivative(k(x), x), f(x)**4 + k(x))] sol3 = [Eq(f(x), C1*exp(2*x)), Eq(g(x), C1*exp(2*x)/2 + C2 + x**2/2), Eq(h(x), C3*exp(x)), Eq(k(x), C1**4*exp(8*x)/7 + C4*exp(x))] assert dsolve(eqs3) == sol3 assert checksysodesol(eqs3, sol3) == (True, [0, 0, 0, 0]) components3 = {frozenset([(Eq(Derivative(f(x), x), 2*f(x)),), (Eq(Derivative(g(x), x), x + f(x)),), (Eq(Derivative(k(x), x), f(x)**4 + k(x)),)]), frozenset([(Eq(Derivative(h(x), x), h(x)),),])} eqsdict3 = ({f(x): set(), g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, {f(x): Eq(Derivative(f(x), x), 2*f(x)), g(x): Eq(Derivative(g(x), x), x + f(x)), h(x): Eq(Derivative(h(x), x), h(x)), k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) graph3 = [{f(x), g(x), h(x), k(x)}, {(g(x), f(x)), (k(x), f(x))}] assert {frozenset(tuple(scc) for scc in wcc) for wcc in _component_division(eqs3, funcs, x)} == components3 assert _eqs2dict(eqs3, funcs) == eqsdict3 assert [set(l) for l in _dict2graph(eqsdict3[0])] == graph3 # Note: To be uncommented when the default option to call dsolve first for # single ODE system can be rearranged. This can be done after the doit # option in dsolve is made False by default. eqs4 = [Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), Eq(Derivative(g(x), x), f(x) + x*g(x) + x), Eq(Derivative(h(x), x), h(x)), Eq(Derivative(k(x), x), f(x)**4 + k(x))] sol4 = [Eq(f(x), (C1/2 - sqrt(2)*C2/2 - sqrt(2)*Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 +\ sqrt(2)*x)/2, x)/2 + Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 +\ sqrt(2)*x)/2, x)/2)*exp(x**2/2 - sqrt(2)*x) + (C1/2 + sqrt(2)*C2/2 + sqrt(2)*Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2)*exp(x**2/2 + sqrt(2)*x)), Eq(g(x), (-sqrt(2)*C1/4 + C2/2 + Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 -\ sqrt(2)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/4)*exp(x**2/2 - sqrt(2)*x) + (sqrt(2)*C1/4 + C2/2 + Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + sqrt(2)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/4)*exp(x**2/2 + sqrt(2)*x)), Eq(h(x), C3*exp(x)), Eq(k(x), C4*exp(x) + exp(x)*Integral((C1*exp(x**2/2 - sqrt(2)*x)/2 + C1*exp(x**2/2 + sqrt(2)*x)/2 - sqrt(2)*C2*exp(x**2/2 - sqrt(2)*x)/2 + sqrt(2)*C2*exp(x**2/2 + sqrt(2)*x)/2 - sqrt(2)*exp(x**2/2 - sqrt(2)*x)*Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + exp(x**2/2 - sqrt(2)*x)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + sqrt(2)*exp(x**2/2 + sqrt(2)*x)*Integral(x*exp(-x**2/2 - sqrt(2)*x)/2 + x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2 + exp(x**2/2 + sqrt(2)*x)*Integral(sqrt(2)*x*exp(-x**2/2 - sqrt(2)*x)/2 - sqrt(2)*x*exp(-x**2/2 + sqrt(2)*x)/2, x)/2)**4*exp(-x), x))] components4 = {(frozenset([Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), Eq(Derivative(g(x), x), x*g(x) + x + f(x))]), frozenset([Eq(Derivative(k(x), x), f(x)**4 + k(x)),])), (frozenset([Eq(Derivative(h(x), x), h(x)),]),)} eqsdict4 = ({f(x): {g(x)}, g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, {f(x): Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), g(x): Eq(Derivative(g(x), x), x*g(x) + x + f(x)), h(x): Eq(Derivative(h(x), x), h(x)), k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) graph4 = [{f(x), g(x), h(x), k(x)}, {(f(x), g(x)), (g(x), f(x)), (k(x), f(x))}] assert {tuple(frozenset(scc) for scc in wcc) for wcc in _component_division(eqs4, funcs, x)} == components4 assert _eqs2dict(eqs4, funcs) == eqsdict4 assert [set(element) for element in _dict2graph(eqsdict4[0])] == graph4 # XXX: dsolve hangs in integration here: assert dsolve_system(eqs4, simplify=False, doit=False) == [sol4] assert checksysodesol(eqs4, sol4) == (True, [0, 0, 0, 0]) eqs5 = [Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), Eq(Derivative(g(x), x), x*g(x) + f(x)), Eq(Derivative(h(x), x), h(x)), Eq(Derivative(k(x), x), f(x)**4 + k(x))] sol5 = [Eq(f(x), (C1/2 - sqrt(2)*C2/2)*exp(x**2/2 - sqrt(2)*x) + (C1/2 + sqrt(2)*C2/2)*exp(x**2/2 + sqrt(2)*x)), Eq(g(x), (-sqrt(2)*C1/4 + C2/2)*exp(x**2/2 - sqrt(2)*x) + (sqrt(2)*C1/4 + C2/2)*exp(x**2/2 + sqrt(2)*x)), Eq(h(x), C3*exp(x)), Eq(k(x), C4*exp(x) + exp(x)*Integral((C1*exp(x**2/2 - sqrt(2)*x)/2 + C1*exp(x**2/2 + sqrt(2)*x)/2 - sqrt(2)*C2*exp(x**2/2 - sqrt(2)*x)/2 + sqrt(2)*C2*exp(x**2/2 + sqrt(2)*x)/2)**4*exp(-x), x))] components5 = {(frozenset([Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), Eq(Derivative(g(x), x), x*g(x) + f(x))]), frozenset([Eq(Derivative(k(x), x), f(x)**4 + k(x)),])), (frozenset([Eq(Derivative(h(x), x), h(x)),]),)} eqsdict5 = ({f(x): {g(x)}, g(x): {f(x)}, h(x): set(), k(x): {f(x)}}, {f(x): Eq(Derivative(f(x), x), x*f(x) + 2*g(x)), g(x): Eq(Derivative(g(x), x), x*g(x) + f(x)), h(x): Eq(Derivative(h(x), x), h(x)), k(x): Eq(Derivative(k(x), x), f(x)**4 + k(x))}) graph5 = [{f(x), g(x), h(x), k(x)}, {(f(x), g(x)), (g(x), f(x)), (k(x), f(x))}] assert {tuple(frozenset(scc) for scc in wcc) for wcc in _component_division(eqs5, funcs, x)} == components5 assert _eqs2dict(eqs5, funcs) == eqsdict5 assert [set(element) for element in _dict2graph(eqsdict5[0])] == graph5 # XXX: dsolve hangs in integration here: assert dsolve_system(eqs5, simplify=False, doit=False) == [sol5] assert checksysodesol(eqs5, sol5) == (True, [0, 0, 0, 0]) def test_linodesolve(): t, x, a = symbols("t x a") f, g, h = symbols("f g h", cls=Function) # Testing the Errors raises(ValueError, lambda: linodesolve(1, t)) raises(ValueError, lambda: linodesolve(a, t)) A1 = Matrix([[1, 2], [2, 4], [4, 6]]) raises(NonSquareMatrixError, lambda: linodesolve(A1, t)) A2 = Matrix([[1, 2, 1], [3, 1, 2]]) raises(NonSquareMatrixError, lambda: linodesolve(A2, t)) # Testing auto functionality func = [f(t), g(t)] eq = [Eq(f(t).diff(t) + g(t).diff(t), g(t)), Eq(g(t).diff(t), f(t))] ceq = canonical_odes(eq, func, t) (A1, A0), b = linear_ode_to_matrix(ceq[0], func, t, 1) A = A0 sol = [C1*(-Rational(1, 2) + sqrt(5)/2)*exp(t*(-Rational(1, 2) + sqrt(5)/2)) + C2*(-sqrt(5)/2 - Rational(1, 2))* exp(t*(-sqrt(5)/2 - Rational(1, 2))), C1*exp(t*(-Rational(1, 2) + sqrt(5)/2)) + C2*exp(t*(-sqrt(5)/2 - Rational(1, 2)))] assert constant_renumber(linodesolve(A, t), variables=Tuple(*eq).free_symbols) == sol # Testing the Errors raises(ValueError, lambda: linodesolve(1, t, b=Matrix([t+1]))) raises(ValueError, lambda: linodesolve(a, t, b=Matrix([log(t) + sin(t)]))) raises(ValueError, lambda: linodesolve(Matrix([7]), t, b=t**2)) raises(ValueError, lambda: linodesolve(Matrix([a+10]), t, b=log(t)*cos(t))) raises(ValueError, lambda: linodesolve(7, t, b=t**2)) raises(ValueError, lambda: linodesolve(a, t, b=log(t) + sin(t))) A1 = Matrix([[1, 2], [2, 4], [4, 6]]) b1 = Matrix([t, 1, t**2]) raises(NonSquareMatrixError, lambda: linodesolve(A1, t, b=b1)) A2 = Matrix([[1, 2, 1], [3, 1, 2]]) b2 = Matrix([t, t**2]) raises(NonSquareMatrixError, lambda: linodesolve(A2, t, b=b2)) raises(ValueError, lambda: linodesolve(A1[:2, :], t, b=b1)) raises(ValueError, lambda: linodesolve(A1[:2, :], t, b=b1[:1])) # DOIT check A1 = Matrix([[1, -1], [1, -1]]) b1 = Matrix([15*t - 10, -15*t - 5]) sol1 = [C1 + C2*t + C2 - 10*t**3 + 10*t**2 + t*(15*t**2 - 5*t) - 10*t, C1 + C2*t - 10*t**3 - 5*t**2 + t*(15*t**2 - 5*t) - 5*t] assert constant_renumber(linodesolve(A1, t, b=b1, type="type2", doit=True), variables=[t]) == sol1 # Testing auto functionality func = [f(t), g(t)] eq = [Eq(f(t).diff(t) + g(t).diff(t), g(t) + t), Eq(g(t).diff(t), f(t))] ceq = canonical_odes(eq, func, t) (A1, A0), b = linear_ode_to_matrix(ceq[0], func, t, 1) A = A0 sol = [-C1*exp(-t/2 + sqrt(5)*t/2)/2 + sqrt(5)*C1*exp(-t/2 + sqrt(5)*t/2)/2 - sqrt(5)*C2*exp(-sqrt(5)*t/2 - t/2)/2 - C2*exp(-sqrt(5)*t/2 - t/2)/2 - exp(-t/2 + sqrt(5)*t/2)*Integral(t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)) - sqrt(5)*t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)), t)/2 + sqrt(5)*exp(-t/2 + sqrt(5)*t/2)*Integral(t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)) - sqrt(5)*t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)), t)/2 - sqrt(5)*exp(-sqrt(5)*t/2 - t/2)*Integral(-sqrt(5)*t*exp(t/2 + sqrt(5)*t/2)/5, t)/2 - exp(-sqrt(5)*t/2 - t/2)*Integral(-sqrt(5)*t*exp(t/2 + sqrt(5)*t/2)/5, t)/2, C1*exp(-t/2 + sqrt(5)*t/2) + C2*exp(-sqrt(5)*t/2 - t/2) + exp(-t/2 + sqrt(5)*t/2)*Integral(t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)) - sqrt(5)*t*exp(-sqrt(5)*t/2 + t/2)/(-5 + sqrt(5)), t) + exp(-sqrt(5)*t/2 - t/2)*Integral(-sqrt(5)*t*exp(t/2 + sqrt(5)*t/2)/5, t)] assert constant_renumber(linodesolve(A, t, b=b), variables=[t]) == sol # non-homogeneous term assumed to be 0 sol1 = [-C1*exp(-t/2 + sqrt(5)*t/2)/2 + sqrt(5)*C1*exp(-t/2 + sqrt(5)*t/2)/2 - sqrt(5)*C2*exp(-sqrt(5)*t/2 - t/2)/2 - C2*exp(-sqrt(5)*t/2 - t/2)/2 - exp(-t/2 + sqrt(5)*t/2)*Integral(0, t)/2 + sqrt(5)*exp(-t/2 + sqrt(5)*t/2)*Integral(0, t)/2 - sqrt(5)*exp(-sqrt(5)*t/2 - t/2)*Integral(0, t)/2 - exp(-sqrt(5)*t/2 - t/2)*Integral(0, t)/2, C1*exp(-t/2 + sqrt(5)*t/2) + C2*exp(-sqrt(5)*t/2 - t/2) + exp(-t/2 + sqrt(5)*t/2)*Integral(0, t) + exp(-sqrt(5)*t/2 - t/2)*Integral(0, t)] assert constant_renumber(linodesolve(A, t, type="type2"), variables=[t]) == sol1 # Testing the Errors raises(ValueError, lambda: linodesolve(t+10, t)) raises(ValueError, lambda: linodesolve(a*t, t)) A1 = Matrix([[1, t], [-t, 1]]) B1, _ = _is_commutative_anti_derivative(A1, t) raises(NonSquareMatrixError, lambda: linodesolve(A1[:, :1], t, B=B1)) raises(ValueError, lambda: linodesolve(A1, t, B=1)) A2 = Matrix([[t, t, t], [t, t, t], [t, t, t]]) B2, _ = _is_commutative_anti_derivative(A2, t) raises(NonSquareMatrixError, lambda: linodesolve(A2, t, B=B2[:2, :])) raises(ValueError, lambda: linodesolve(A2, t, B=2)) raises(ValueError, lambda: linodesolve(A2, t, B=B2, type="type31")) raises(ValueError, lambda: linodesolve(A1, t, B=B2)) raises(ValueError, lambda: linodesolve(A2, t, B=B1)) # Testing auto functionality func = [f(t), g(t)] eq = [Eq(f(t).diff(t), f(t) + t*g(t)), Eq(g(t).diff(t), -t*f(t) + g(t))] ceq = canonical_odes(eq, func, t) (A1, A0), b = linear_ode_to_matrix(ceq[0], func, t, 1) A = A0 sol = [(C1/2 - I*C2/2)*exp(I*t**2/2 + t) + (C1/2 + I*C2/2)*exp(-I*t**2/2 + t), (-I*C1/2 + C2/2)*exp(-I*t**2/2 + t) + (I*C1/2 + C2/2)*exp(I*t**2/2 + t)] assert constant_renumber(linodesolve(A, t), variables=Tuple(*eq).free_symbols) == sol assert constant_renumber(linodesolve(A, t, type="type3"), variables=Tuple(*eq).free_symbols) == sol A1 = Matrix([[t, 1], [t, -1]]) raises(NotImplementedError, lambda: linodesolve(A1, t)) # Testing the Errors raises(ValueError, lambda: linodesolve(t+10, t, b=Matrix([t+1]))) raises(ValueError, lambda: linodesolve(a*t, t, b=Matrix([log(t) + sin(t)]))) raises(ValueError, lambda: linodesolve(Matrix([7*t]), t, b=t**2)) raises(ValueError, lambda: linodesolve(Matrix([a + 10*log(t)]), t, b=log(t)*cos(t))) raises(ValueError, lambda: linodesolve(7*t, t, b=t**2)) raises(ValueError, lambda: linodesolve(a*t**2, t, b=log(t) + sin(t))) A1 = Matrix([[1, t], [-t, 1]]) b1 = Matrix([t, t ** 2]) B1, _ = _is_commutative_anti_derivative(A1, t) raises(NonSquareMatrixError, lambda: linodesolve(A1[:, :1], t, b=b1)) A2 = Matrix([[t, t, t], [t, t, t], [t, t, t]]) b2 = Matrix([t, 1, t**2]) B2, _ = _is_commutative_anti_derivative(A2, t) raises(NonSquareMatrixError, lambda: linodesolve(A2[:2, :], t, b=b2)) raises(ValueError, lambda: linodesolve(A1, t, b=b2)) raises(ValueError, lambda: linodesolve(A2, t, b=b1)) raises(ValueError, lambda: linodesolve(A1, t, b=b1, B=B2)) raises(ValueError, lambda: linodesolve(A2, t, b=b2, B=B1)) # Testing auto functionality func = [f(x), g(x), h(x)] eq = [Eq(f(x).diff(x), x*(f(x) + g(x) + h(x)) + x), Eq(g(x).diff(x), x*(f(x) + g(x) + h(x)) + x), Eq(h(x).diff(x), x*(f(x) + g(x) + h(x)) + 1)] ceq = canonical_odes(eq, func, x) (A1, A0), b = linear_ode_to_matrix(ceq[0], func, x, 1) A = A0 _x1 = exp(-3*x**2/2) _x2 = exp(3*x**2/2) _x3 = Integral(2*_x1*x/3 + _x1/3 + x/3 - Rational(1, 3), x) _x4 = 2*_x2*_x3/3 _x5 = Integral(2*_x1*x/3 + _x1/3 - 2*x/3 + Rational(2, 3), x) sol = [ C1*_x2/3 - C1/3 + C2*_x2/3 - C2/3 + C3*_x2/3 + 2*C3/3 + _x2*_x5/3 + _x3/3 + _x4 - _x5/3, C1*_x2/3 + 2*C1/3 + C2*_x2/3 - C2/3 + C3*_x2/3 - C3/3 + _x2*_x5/3 + _x3/3 + _x4 - _x5/3, C1*_x2/3 - C1/3 + C2*_x2/3 + 2*C2/3 + C3*_x2/3 - C3/3 + _x2*_x5/3 - 2*_x3/3 + _x4 + 2*_x5/3, ] assert constant_renumber(linodesolve(A, x, b=b), variables=Tuple(*eq).free_symbols) == sol assert constant_renumber(linodesolve(A, x, b=b, type="type4"), variables=Tuple(*eq).free_symbols) == sol A1 = Matrix([[t, 1], [t, -1]]) raises(NotImplementedError, lambda: linodesolve(A1, t, b=b1)) # non-homogeneous term not passed sol1 = [-C1/3 - C2/3 + 2*C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2), 2*C1/3 - C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2), -C1/3 + 2*C2/3 - C3/3 + (C1/3 + C2/3 + C3/3)*exp(3*x**2/2)] assert constant_renumber(linodesolve(A, x, type="type4", doit=True), variables=Tuple(*eq).free_symbols) == sol1 @slow def test_linear_3eq_order1_type4_slow(): x, y, z = symbols('x, y, z', cls=Function) t = Symbol('t') f = t ** 3 + log(t) g = t ** 2 + sin(t) eq1 = (Eq(diff(x(t), t), (4 * f + g) * x(t) - f * y(t) - 2 * f * z(t)), Eq(diff(y(t), t), 2 * f * x(t) + (f + g) * y(t) - 2 * f * z(t)), Eq(diff(z(t), t), 5 * f * x(t) + f * y( t) + (-3 * f + g) * z(t))) with dotprodsimp(True): dsolve(eq1) @slow def test_linear_neq_order1_type2_slow1(): i, r1, c1, r2, c2, t = symbols('i, r1, c1, r2, c2, t') x1 = Function('x1') x2 = Function('x2') eq1 = r1*c1*Derivative(x1(t), t) + x1(t) - x2(t) - r1*i eq2 = r2*c1*Derivative(x1(t), t) + r2*c2*Derivative(x2(t), t) + x2(t) - r2*i eq = [eq1, eq2] # XXX: Solution is too complicated [sol] = dsolve_system(eq, simplify=False, doit=False) assert checksysodesol(eq, sol) == (True, [0, 0]) # Regression test case for issue #9204 # https://github.com/sympy/sympy/issues/9204 @slow def test_linear_new_order1_type2_de_lorentz_slow_check(): if ON_TRAVIS: skip("Too slow for travis.") m = Symbol("m", real=True) q = Symbol("q", real=True) t = Symbol("t", real=True) e1, e2, e3 = symbols("e1:4", real=True) b1, b2, b3 = symbols("b1:4", real=True) v1, v2, v3 = symbols("v1:4", cls=Function, real=True) eqs = [ -e1*q + m*Derivative(v1(t), t) - q*(-b2*v3(t) + b3*v2(t)), -e2*q + m*Derivative(v2(t), t) - q*(b1*v3(t) - b3*v1(t)), -e3*q + m*Derivative(v3(t), t) - q*(-b1*v2(t) + b2*v1(t)) ] sol = dsolve(eqs) assert checksysodesol(eqs, sol) == (True, [0, 0, 0]) # Regression test case for issue #14001 # https://github.com/sympy/sympy/issues/14001 @slow def test_linear_neq_order1_type2_slow_check(): RC, t, C, Vs, L, R1, V0, I0 = symbols("RC t C Vs L R1 V0 I0") V = Function("V") I = Function("I") system = [Eq(V(t).diff(t), -1/RC*V(t) + I(t)/C), Eq(I(t).diff(t), -R1/L*I(t) - 1/L*V(t) + Vs/L)] [sol] = dsolve_system(system, simplify=False, doit=False) assert checksysodesol(system, sol) == (True, [0, 0]) def _linear_3eq_order1_type4_long(): x, y, z = symbols('x, y, z', cls=Function) t = Symbol('t') f = t ** 3 + log(t) g = t ** 2 + sin(t) eq1 = (Eq(diff(x(t), t), (4*f + g)*x(t) - f*y(t) - 2*f*z(t)), Eq(diff(y(t), t), 2*f*x(t) + (f + g)*y(t) - 2*f*z(t)), Eq(diff(z(t), t), 5*f*x(t) + f*y( t) + (-3*f + g)*z(t))) dsolve_sol = dsolve(eq1) dsolve_sol1 = [_simpsol(sol) for sol in dsolve_sol] x_1 = sqrt(-t**6 - 8*t**3*log(t) + 8*t**3 - 16*log(t)**2 + 32*log(t) - 16) x_2 = sqrt(3) x_3 = 8324372644*C1*x_1*x_2 + 4162186322*C2*x_1*x_2 - 8324372644*C3*x_1*x_2 x_4 = 1 / (1903457163*t**3 + 3825881643*x_1*x_2 + 7613828652*log(t) - 7613828652) x_5 = exp(t**3/3 + t*x_1*x_2/4 - cos(t)) x_6 = exp(t**3/3 - t*x_1*x_2/4 - cos(t)) x_7 = exp(t**4/2 + t**3/3 + 2*t*log(t) - 2*t - cos(t)) x_8 = 91238*C1*x_1*x_2 + 91238*C2*x_1*x_2 - 91238*C3*x_1*x_2 x_9 = 1 / (66049*t**3 - 50629*x_1*x_2 + 264196*log(t) - 264196) x_10 = 50629 * C1 / 25189 + 37909*C2/25189 - 50629*C3/25189 - x_3*x_4 x_11 = -50629*C1/25189 - 12720*C2/25189 + 50629*C3/25189 + x_3*x_4 sol = [Eq(x(t), x_10*x_5 + x_11*x_6 + x_7*(C1 - C2)), Eq(y(t), x_10*x_5 + x_11*x_6), Eq(z(t), x_5*( -424*C1/257 - 167*C2/257 + 424*C3/257 - x_8*x_9) + x_6*(167*C1/257 + 424*C2/257 - 167*C3/257 + x_8*x_9) + x_7*(C1 - C2))] assert dsolve_sol1 == sol assert checksysodesol(eq1, dsolve_sol1) == (True, [0, 0, 0]) @slow def test_neq_order1_type4_slow_check1(): f, g = symbols("f g", cls=Function) x = symbols("x") eqs = [Eq(diff(f(x), x), x*f(x) + x**2*g(x) + x), Eq(diff(g(x), x), 2*x**2*f(x) + (x + 3*x**2)*g(x) + 1)] sol = dsolve(eqs) assert checksysodesol(eqs, sol) == (True, [0, 0]) @slow def test_neq_order1_type4_slow_check2(): f, g, h = symbols("f, g, h", cls=Function) x = Symbol("x") eqs = [ Eq(Derivative(f(x), x), x*h(x) + f(x) + g(x) + 1), Eq(Derivative(g(x), x), x*g(x) + f(x) + h(x) + 10), Eq(Derivative(h(x), x), x*f(x) + x + g(x) + h(x)) ] with dotprodsimp(True): sol = dsolve(eqs) assert checksysodesol(eqs, sol) == (True, [0, 0, 0]) def _neq_order1_type4_slow3(): f, g = symbols("f g", cls=Function) x = symbols("x") eqs = [ Eq(Derivative(f(x), x), x*f(x) + g(x) + sin(x)), Eq(Derivative(g(x), x), x**2 + x*g(x) - f(x)) ] sol = [ Eq(f(x), (C1/2 - I*C2/2 - I*Integral(x**2*exp(-x**2/2 - I*x)/2 + x**2*exp(-x**2/2 + I*x)/2 + I*exp(-x**2/2 - I*x)*sin(x)/2 - I*exp(-x**2/2 + I*x)*sin(x)/2, x)/2 + Integral(-I*x**2*exp(-x**2/2 - I*x)/2 + I*x**2*exp(-x**2/2 + I*x)/2 + exp(-x**2/2 - I*x)*sin(x)/2 + exp(-x**2/2 + I*x)*sin(x)/2, x)/2)*exp(x**2/2 + I*x) + (C1/2 + I*C2/2 + I*Integral(x**2*exp(-x**2/2 - I*x)/2 + x**2*exp(-x**2/2 + I*x)/2 + I*exp(-x**2/2 - I*x)*sin(x)/2 - I*exp(-x**2/2 + I*x)*sin(x)/2, x)/2 + Integral(-I*x**2*exp(-x**2/2 - I*x)/2 + I*x**2*exp(-x**2/2 + I*x)/2 + exp(-x**2/2 - I*x)*sin(x)/2 + exp(-x**2/2 + I*x)*sin(x)/2, x)/2)*exp(x**2/2 - I*x)), Eq(g(x), (-I*C1/2 + C2/2 + Integral(x**2*exp(-x**2/2 - I*x)/2 + x**2*exp(-x**2/2 + I*x)/2 + I*exp(-x**2/2 - I*x)*sin(x)/2 - I*exp(-x**2/2 + I*x)*sin(x)/2, x)/2 - I*Integral(-I*x**2*exp(-x**2/2 - I*x)/2 + I*x**2*exp(-x**2/2 + I*x)/2 + exp(-x**2/2 - I*x)*sin(x)/2 + exp(-x**2/2 + I*x)*sin(x)/2, x)/2)*exp(x**2/2 - I*x) + (I*C1/2 + C2/2 + Integral(x**2*exp(-x**2/2 - I*x)/2 + x**2*exp(-x**2/2 + I*x)/2 + I*exp(-x**2/2 - I*x)*sin(x)/2 - I*exp(-x**2/2 + I*x)*sin(x)/2, x)/2 + I*Integral(-I*x**2*exp(-x**2/2 - I*x)/2 + I*x**2*exp(-x**2/2 + I*x)/2 + exp(-x**2/2 - I*x)*sin(x)/2 + exp(-x**2/2 + I*x)*sin(x)/2, x)/2)*exp(x**2/2 + I*x)) ] return eqs, sol def test_neq_order1_type4_slow3(): eqs, sol = _neq_order1_type4_slow3() assert dsolve_system(eqs, simplify=False, doit=False) == [sol] # XXX: dsolve gives an error in integration: # assert dsolve(eqs) == sol # https://github.com/sympy/sympy/issues/20155 @slow def test_neq_order1_type4_slow_check3(): eqs, sol = _neq_order1_type4_slow3() assert checksysodesol(eqs, sol) == (True, [0, 0]) @XFAIL @slow def test_linear_3eq_order1_type4_long_dsolve_slow_xfail(): if ON_TRAVIS: skip("Too slow for travis.") eq, sol = _linear_3eq_order1_type4_long() dsolve_sol = dsolve(eq) dsolve_sol1 = [_simpsol(sol) for sol in dsolve_sol] assert dsolve_sol1 == sol @slow def test_linear_3eq_order1_type4_long_dsolve_dotprodsimp(): if ON_TRAVIS: skip("Too slow for travis.") eq, sol = _linear_3eq_order1_type4_long() # XXX: Only works with dotprodsimp see # test_linear_3eq_order1_type4_long_dsolve_slow_xfail which is too slow with dotprodsimp(True): dsolve_sol = dsolve(eq) dsolve_sol1 = [_simpsol(sol) for sol in dsolve_sol] assert dsolve_sol1 == sol @slow def test_linear_3eq_order1_type4_long_check(): if ON_TRAVIS: skip("Too slow for travis.") eq, sol = _linear_3eq_order1_type4_long() assert checksysodesol(eq, sol) == (True, [0, 0, 0]) def test_dsolve_system(): f, g = symbols("f g", cls=Function) x = symbols("x") eqs = [Eq(f(x).diff(x), f(x) + g(x)), Eq(g(x).diff(x), f(x) + g(x))] funcs = [f(x), g(x)] sol = [[Eq(f(x), -C1 + C2*exp(2*x)), Eq(g(x), C1 + C2*exp(2*x))]] assert dsolve_system(eqs, funcs=funcs, t=x, doit=True) == sol raises(ValueError, lambda: dsolve_system(1)) raises(ValueError, lambda: dsolve_system(eqs, 1)) raises(ValueError, lambda: dsolve_system(eqs, funcs, 1)) raises(ValueError, lambda: dsolve_system(eqs, funcs[:1], x)) eq = (Eq(f(x).diff(x), 12 * f(x) - 6 * g(x)), Eq(g(x).diff(x) ** 2, 11 * f(x) + 3 * g(x))) raises(NotImplementedError, lambda: dsolve_system(eq) == ([], [])) raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)]) == ([], [])) raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)], t=x) == ([], [])) raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)], t=x, ics={f(0): 1, g(0): 1}) == ([], [])) raises(NotImplementedError, lambda: dsolve_system(eq, t=x, ics={f(0): 1, g(0): 1}) == ([], [])) raises(NotImplementedError, lambda: dsolve_system(eq, ics={f(0): 1, g(0): 1}) == ([], [])) raises(NotImplementedError, lambda: dsolve_system(eq, funcs=[f(x), g(x)], ics={f(0): 1, g(0): 1}) == ([], [])) def test_dsolve(): f, g = symbols('f g', cls=Function) x, y = symbols('x y') eqs = [f(x).diff(x) - x, f(x).diff(x) + x] with raises(ValueError): dsolve(eqs) eqs = [f(x, y).diff(x)] with raises(ValueError): dsolve(eqs) eqs = [f(x, y).diff(x)+g(x).diff(x), g(x).diff(x)] with raises(ValueError): dsolve(eqs) @slow def test_higher_order1_slow1(): x, y = symbols("x y", cls=Function) t = symbols("t") eq = [ Eq(diff(x(t),t,t), (log(t)+t**2)*diff(x(t),t)+(log(t)+t**2)*3*diff(y(t),t)), Eq(diff(y(t),t,t), (log(t)+t**2)*2*diff(x(t),t)+(log(t)+t**2)*9*diff(y(t),t)) ] sol, = dsolve_system(eq, simplify=False, doit=False) # The solution is too long to write out explicitly and checkodesol is too # slow so we test for particular values of t: for e in eq: res = (e.lhs - e.rhs).subs({sol[0].lhs:sol[0].rhs, sol[1].lhs:sol[1].rhs}) res = res.subs({d: d.doit(deep=False) for d in res.atoms(Derivative)}) assert ratsimp(res.subs(t, 1)) == 0 def test_second_order_type2_slow1(): x, y, z = symbols('x, y, z', cls=Function) t, l = symbols('t, l') eqs1 = [Eq(Derivative(x(t), (t, 2)), t*(2*x(t) + y(t))), Eq(Derivative(y(t), (t, 2)), t*(-x(t) + 2*y(t)))] sol1 = [Eq(x(t), I*C1*airyai(t*(2 - I)**(S(1)/3)) + I*C2*airybi(t*(2 - I)**(S(1)/3)) - I*C3*airyai(t*(2 + I)**(S(1)/3)) - I*C4*airybi(t*(2 + I)**(S(1)/3))), Eq(y(t), C1*airyai(t*(2 - I)**(S(1)/3)) + C2*airybi(t*(2 - I)**(S(1)/3)) + C3*airyai(t*(2 + I)**(S(1)/3)) + C4*airybi(t*(2 + I)**(S(1)/3)))] assert dsolve(eqs1) == sol1 assert checksysodesol(eqs1, sol1) == (True, [0, 0]) @slow @XFAIL def test_nonlinear_3eq_order1_type1(): if ON_TRAVIS: skip("Too slow for travis.") a, b, c = symbols('a b c') eqs = [ a * f(x).diff(x) - (b - c) * g(x) * h(x), b * g(x).diff(x) - (c - a) * h(x) * f(x), c * h(x).diff(x) - (a - b) * f(x) * g(x), ] assert dsolve(eqs) # NotImplementedError @XFAIL def test_nonlinear_3eq_order1_type4(): eqs = [ Eq(f(x).diff(x), (2*h(x)*g(x) - 3*g(x)*h(x))), Eq(g(x).diff(x), (4*f(x)*h(x) - 2*h(x)*f(x))), Eq(h(x).diff(x), (3*g(x)*f(x) - 4*f(x)*g(x))), ] dsolve(eqs) # KeyError when matching # sol = ? # assert dsolve_sol == sol # assert checksysodesol(eqs, dsolve_sol) == (True, [0, 0, 0]) @slow @XFAIL def test_nonlinear_3eq_order1_type3(): if ON_TRAVIS: skip("Too slow for travis.") eqs = [ Eq(f(x).diff(x), (2*f(x)**2 - 3 )), Eq(g(x).diff(x), (4 - 2*h(x) )), Eq(h(x).diff(x), (3*h(x) - 4*f(x)**2)), ] dsolve(eqs) # Not sure if this finishes... # sol = ? # assert dsolve_sol == sol # assert checksysodesol(eqs, dsolve_sol) == (True, [0, 0, 0]) @XFAIL def test_nonlinear_3eq_order1_type5(): eqs = [ Eq(f(x).diff(x), f(x)*(2*f(x) - 3*g(x))), Eq(g(x).diff(x), g(x)*(4*g(x) - 2*h(x))), Eq(h(x).diff(x), h(x)*(3*h(x) - 4*f(x))), ] dsolve(eqs) # KeyError # sol = ? # assert dsolve_sol == sol # assert checksysodesol(eqs, dsolve_sol) == (True, [0, 0, 0]) def test_linear_2eq_order1(): x, y, z = symbols('x, y, z', cls=Function) k, l, m, n = symbols('k, l, m, n', Integer=True) t = Symbol('t') x0, y0 = symbols('x0, y0', cls=Function) eq1 = (Eq(diff(x(t),t), x(t) + y(t) + 9), Eq(diff(y(t),t), 2*x(t) + 5*y(t) + 23)) sol1 = [Eq(x(t), C1*exp(t*(sqrt(6) + 3)) + C2*exp(t*(-sqrt(6) + 3)) - Rational(22, 3)), \ Eq(y(t), C1*(2 + sqrt(6))*exp(t*(sqrt(6) + 3)) + C2*(-sqrt(6) + 2)*exp(t*(-sqrt(6) + 3)) - Rational(5, 3))] assert checksysodesol(eq1, sol1) == (True, [0, 0]) eq2 = (Eq(diff(x(t),t), x(t) + y(t) + 81), Eq(diff(y(t),t), -2*x(t) + y(t) + 23)) sol2 = [Eq(x(t), (C1*cos(sqrt(2)*t) + C2*sin(sqrt(2)*t))*exp(t) - Rational(58, 3)), \ Eq(y(t), (-sqrt(2)*C1*sin(sqrt(2)*t) + sqrt(2)*C2*cos(sqrt(2)*t))*exp(t) - Rational(185, 3))] assert checksysodesol(eq2, sol2) == (True, [0, 0]) eq3 = (Eq(diff(x(t),t), 5*t*x(t) + 2*y(t)), Eq(diff(y(t),t), 2*x(t) + 5*t*y(t))) sol3 = [Eq(x(t), (C1*exp(2*t) + C2*exp(-2*t))*exp(Rational(5, 2)*t**2)), \ Eq(y(t), (C1*exp(2*t) - C2*exp(-2*t))*exp(Rational(5, 2)*t**2))] assert checksysodesol(eq3, sol3) == (True, [0, 0]) eq4 = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + 5*t*y(t))) sol4 = [Eq(x(t), (C1*cos((t**3)/3) + C2*sin((t**3)/3))*exp(Rational(5, 2)*t**2)), \ Eq(y(t), (-C1*sin((t**3)/3) + C2*cos((t**3)/3))*exp(Rational(5, 2)*t**2))] assert checksysodesol(eq4, sol4) == (True, [0, 0]) eq5 = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), -t**2*x(t) + (5*t+9*t**2)*y(t))) sol5 = [Eq(x(t), (C1*exp((sqrt(77)/2 + Rational(9, 2))*(t**3)/3) + \ C2*exp((-sqrt(77)/2 + Rational(9, 2))*(t**3)/3))*exp(Rational(5, 2)*t**2)), \ Eq(y(t), (C1*(sqrt(77)/2 + Rational(9, 2))*exp((sqrt(77)/2 + Rational(9, 2))*(t**3)/3) + \ C2*(-sqrt(77)/2 + Rational(9, 2))*exp((-sqrt(77)/2 + Rational(9, 2))*(t**3)/3))*exp(Rational(5, 2)*t**2))] assert checksysodesol(eq5, sol5) == (True, [0, 0]) eq6 = (Eq(diff(x(t),t), 5*t*x(t) + t**2*y(t)), Eq(diff(y(t),t), (1-t**2)*x(t) + (5*t+9*t**2)*y(t))) sol6 = [Eq(x(t), C1*x0(t) + C2*x0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t)), \ Eq(y(t), C1*y0(t) + C2*(y0(t)*Integral(t**2*exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)**2, t) + \ exp(Integral(5*t, t))*exp(Integral(9*t**2 + 5*t, t))/x0(t)))] s = dsolve(eq6) assert s == sol6 # too complicated to test with subs and simplify # assert checksysodesol(eq10, sol10) == (True, [0, 0]) # this one fails def test_nonlinear_2eq_order1(): x, y, z = symbols('x, y, z', cls=Function) t = Symbol('t') eq1 = (Eq(diff(x(t),t),x(t)*y(t)**3), Eq(diff(y(t),t),y(t)**5)) sol1 = [ Eq(x(t), C1*exp((-1/(4*C2 + 4*t))**(Rational(-1, 4)))), Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), C1*exp(-1/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), C1*exp(-I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), C1*exp(I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] assert dsolve(eq1) == sol1 assert checksysodesol(eq1, sol1) == (True, [0, 0]) eq2 = (Eq(diff(x(t),t), exp(3*x(t))*y(t)**3),Eq(diff(y(t),t), y(t)**5)) sol2 = [ Eq(x(t), -log(C1 - 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), -log(C1 + 3/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), -log(C1 + 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), -log(C1 - 3*I/(-1/(4*C2 + 4*t))**Rational(1, 4))/3), Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] assert dsolve(eq2) == sol2 assert checksysodesol(eq2, sol2) == (True, [0, 0]) eq3 = (Eq(diff(x(t),t), y(t)*x(t)), Eq(diff(y(t),t), x(t)**3)) tt = Rational(2, 3) sol3 = [ Eq(x(t), 6**tt/(6*(-sinh(sqrt(C1)*(C2 + t)/2)/sqrt(C1))**tt)), Eq(y(t), sqrt(C1 + C1/sinh(sqrt(C1)*(C2 + t)/2)**2)/3)] assert dsolve(eq3) == sol3 # FIXME: assert checksysodesol(eq3, sol3) == (True, [0, 0]) eq4 = (Eq(diff(x(t),t),x(t)*y(t)*sin(t)**2), Eq(diff(y(t),t),y(t)**2*sin(t)**2)) sol4 = {Eq(x(t), -2*exp(C1)/(C2*exp(C1) + t - sin(2*t)/2)), Eq(y(t), -2/(C1 + t - sin(2*t)/2))} assert dsolve(eq4) == sol4 # FIXME: assert checksysodesol(eq4, sol4) == (True, [0, 0]) eq5 = (Eq(x(t),t*diff(x(t),t)+diff(x(t),t)*diff(y(t),t)), Eq(y(t),t*diff(y(t),t)+diff(y(t),t)**2)) sol5 = {Eq(x(t), C1*C2 + C1*t), Eq(y(t), C2**2 + C2*t)} assert dsolve(eq5) == sol5 assert checksysodesol(eq5, sol5) == (True, [0, 0]) eq6 = (Eq(diff(x(t),t),x(t)**2*y(t)**3), Eq(diff(y(t),t),y(t)**5)) sol6 = [ Eq(x(t), 1/(C1 - 1/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), -(-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), 1/(C1 + (-1/(4*C2 + 4*t))**(Rational(-1, 4)))), Eq(y(t), (-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), 1/(C1 + I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), -I*(-1/(4*C2 + 4*t))**Rational(1, 4)), Eq(x(t), 1/(C1 - I/(-1/(4*C2 + 4*t))**Rational(1, 4))), Eq(y(t), I*(-1/(4*C2 + 4*t))**Rational(1, 4))] assert dsolve(eq6) == sol6 assert checksysodesol(eq6, sol6) == (True, [0, 0]) @slow def test_nonlinear_3eq_order1(): x, y, z = symbols('x, y, z', cls=Function) t, u = symbols('t u') eq1 = (4*diff(x(t),t) + 2*y(t)*z(t), 3*diff(y(t),t) - z(t)*x(t), 5*diff(z(t),t) - x(t)*y(t)) sol1 = [Eq(4*Integral(1/(sqrt(-4*u**2 - 3*C1 + C2)*sqrt(-4*u**2 + 5*C1 - C2)), (u, x(t))), C3 - sqrt(15)*t/15), Eq(3*Integral(1/(sqrt(-6*u**2 - C1 + 5*C2)*sqrt(3*u**2 + C1 - 4*C2)), (u, y(t))), C3 + sqrt(5)*t/10), Eq(5*Integral(1/(sqrt(-10*u**2 - 3*C1 + C2)* sqrt(5*u**2 + 4*C1 - C2)), (u, z(t))), C3 + sqrt(3)*t/6)] assert [i.dummy_eq(j) for i, j in zip(dsolve(eq1), sol1)] # FIXME: assert checksysodesol(eq1, sol1) == (True, [0, 0, 0]) eq2 = (4*diff(x(t),t) + 2*y(t)*z(t)*sin(t), 3*diff(y(t),t) - z(t)*x(t)*sin(t), 5*diff(z(t),t) - x(t)*y(t)*sin(t)) sol2 = [Eq(3*Integral(1/(sqrt(-6*u**2 - C1 + 5*C2)*sqrt(3*u**2 + C1 - 4*C2)), (u, x(t))), C3 + sqrt(5)*cos(t)/10), Eq(4*Integral(1/(sqrt(-4*u**2 - 3*C1 + C2)*sqrt(-4*u**2 + 5*C1 - C2)), (u, y(t))), C3 - sqrt(15)*cos(t)/15), Eq(5*Integral(1/(sqrt(-10*u**2 - 3*C1 + C2)* sqrt(5*u**2 + 4*C1 - C2)), (u, z(t))), C3 + sqrt(3)*cos(t)/6)] assert [i.dummy_eq(j) for i, j in zip(dsolve(eq2), sol2)] # FIXME: assert checksysodesol(eq2, sol2) == (True, [0, 0, 0]) def test_C1_function_9239(): t = Symbol('t') C1 = Function('C1') C2 = Function('C2') C3 = Symbol('C3') C4 = Symbol('C4') eq = (Eq(diff(C1(t), t), 9*C2(t)), Eq(diff(C2(t), t), 12*C1(t))) sol = [Eq(C1(t), 9*C3*exp(6*sqrt(3)*t) + 9*C4*exp(-6*sqrt(3)*t)), Eq(C2(t), 6*sqrt(3)*C3*exp(6*sqrt(3)*t) - 6*sqrt(3)*C4*exp(-6*sqrt(3)*t))] assert checksysodesol(eq, sol) == (True, [0, 0]) def test_dsolve_linsystem_symbol(): eps = Symbol('epsilon', positive=True) eq1 = (Eq(diff(f(x), x), -eps*g(x)), Eq(diff(g(x), x), eps*f(x))) sol1 = [Eq(f(x), -C1*eps*cos(eps*x) - C2*eps*sin(eps*x)), Eq(g(x), -C1*eps*sin(eps*x) + C2*eps*cos(eps*x))] assert checksysodesol(eq1, sol1) == (True, [0, 0]) sympy-sympy-1.9/sympy/solvers/pde.py000066400000000000000000001060551412543434000177320ustar00rootroot00000000000000""" This module contains pdsolve() and different helper functions that it uses. It is heavily inspired by the ode module and hence the basic infrastructure remains the same. **Functions in this module** These are the user functions in this module: - pdsolve() - Solves PDE's - classify_pde() - Classifies PDEs into possible hints for dsolve(). - pde_separate() - Separate variables in partial differential equation either by additive or multiplicative separation approach. These are the helper functions in this module: - pde_separate_add() - Helper function for searching additive separable solutions. - pde_separate_mul() - Helper function for searching multiplicative separable solutions. **Currently implemented solver methods** The following methods are implemented for solving partial differential equations. See the docstrings of the various pde_hint() functions for more information on each (run help(pde)): - 1st order linear homogeneous partial differential equations with constant coefficients. - 1st order linear general partial differential equations with constant coefficients. - 1st order linear partial differential equations with variable coefficients. """ from functools import reduce from itertools import combinations_with_replacement from sympy.simplify import simplify # type: ignore from sympy.core import Add, S from sympy.core.compatibility import is_sequence from sympy.core.function import Function, expand, AppliedUndef, Subs from sympy.core.relational import Equality, Eq from sympy.core.symbol import Symbol, Wild, symbols from sympy.functions import exp from sympy.integrals.integrals import Integral from sympy.utilities.iterables import has_dups from sympy.utilities.misc import filldedent from sympy.solvers.deutils import _preprocess, ode_order, _desolve from sympy.solvers.solvers import solve from sympy.simplify.radsimp import collect import operator allhints = ( "1st_linear_constant_coeff_homogeneous", "1st_linear_constant_coeff", "1st_linear_constant_coeff_Integral", "1st_linear_variable_coeff" ) def pdsolve(eq, func=None, hint='default', dict=False, solvefun=None, **kwargs): """ Solves any (supported) kind of partial differential equation. **Usage** pdsolve(eq, f(x,y), hint) -> Solve partial differential equation eq for function f(x,y), using method hint. **Details** ``eq`` can be any supported partial differential equation (see the pde docstring for supported methods). This can either be an Equality, or an expression, which is assumed to be equal to 0. ``f(x,y)`` is a function of two variables whose derivatives in that variable make up the partial differential equation. In many cases it is not necessary to provide this; it will be autodetected (and an error raised if it couldn't be detected). ``hint`` is the solving method that you want pdsolve to use. Use classify_pde(eq, f(x,y)) to get all of the possible hints for a PDE. The default hint, 'default', will use whatever hint is returned first by classify_pde(). See Hints below for more options that you can use for hint. ``solvefun`` is the convention used for arbitrary functions returned by the PDE solver. If not set by the user, it is set by default to be F. **Hints** Aside from the various solving methods, there are also some meta-hints that you can pass to pdsolve(): "default": This uses whatever hint is returned first by classify_pde(). This is the default argument to pdsolve(). "all": To make pdsolve apply all relevant classification hints, use pdsolve(PDE, func, hint="all"). This will return a dictionary of hint:solution terms. If a hint causes pdsolve to raise the NotImplementedError, value of that hint's key will be the exception object raised. The dictionary will also include some special keys: - order: The order of the PDE. See also ode_order() in deutils.py - default: The solution that would be returned by default. This is the one produced by the hint that appears first in the tuple returned by classify_pde(). "all_Integral": This is the same as "all", except if a hint also has a corresponding "_Integral" hint, it only returns the "_Integral" hint. This is useful if "all" causes pdsolve() to hang because of a difficult or impossible integral. This meta-hint will also be much faster than "all", because integrate() is an expensive routine. See also the classify_pde() docstring for more info on hints, and the pde docstring for a list of all supported hints. **Tips** - You can declare the derivative of an unknown function this way: >>> from sympy import Function, Derivative >>> from sympy.abc import x, y # x and y are the independent variables >>> f = Function("f")(x, y) # f is a function of x and y >>> # fx will be the partial derivative of f with respect to x >>> fx = Derivative(f, x) >>> # fy will be the partial derivative of f with respect to y >>> fy = Derivative(f, y) - See test_pde.py for many tests, which serves also as a set of examples for how to use pdsolve(). - pdsolve always returns an Equality class (except for the case when the hint is "all" or "all_Integral"). Note that it is not possible to get an explicit solution for f(x, y) as in the case of ODE's - Do help(pde.pde_hintname) to get help more information on a specific hint Examples ======== >>> from sympy.solvers.pde import pdsolve >>> from sympy import Function, Eq >>> from sympy.abc import x, y >>> f = Function('f') >>> u = f(x, y) >>> ux = u.diff(x) >>> uy = u.diff(y) >>> eq = Eq(1 + (2*(ux/u)) + (3*(uy/u)), 0) >>> pdsolve(eq) Eq(f(x, y), F(3*x - 2*y)*exp(-2*x/13 - 3*y/13)) """ if not solvefun: solvefun = Function('F') # See the docstring of _desolve for more details. hints = _desolve(eq, func=func, hint=hint, simplify=True, type='pde', **kwargs) eq = hints.pop('eq', False) all_ = hints.pop('all', False) if all_: # TODO : 'best' hint should be implemented when adequate # number of hints are added. pdedict = {} failed_hints = {} gethints = classify_pde(eq, dict=True) pdedict.update({'order': gethints['order'], 'default': gethints['default']}) for hint in hints: try: rv = _helper_simplify(eq, hint, hints[hint]['func'], hints[hint]['order'], hints[hint][hint], solvefun) except NotImplementedError as detail: failed_hints[hint] = detail else: pdedict[hint] = rv pdedict.update(failed_hints) return pdedict else: return _helper_simplify(eq, hints['hint'], hints['func'], hints['order'], hints[hints['hint']], solvefun) def _helper_simplify(eq, hint, func, order, match, solvefun): """Helper function of pdsolve that calls the respective pde functions to solve for the partial differential equations. This minimizes the computation in calling _desolve multiple times. """ if hint.endswith("_Integral"): solvefunc = globals()[ "pde_" + hint[:-len("_Integral")]] else: solvefunc = globals()["pde_" + hint] return _handle_Integral(solvefunc(eq, func, order, match, solvefun), func, order, hint) def _handle_Integral(expr, func, order, hint): r""" Converts a solution with integrals in it into an actual solution. Simplifies the integral mainly using doit() """ if hint.endswith("_Integral"): return expr elif hint == "1st_linear_constant_coeff": return simplify(expr.doit()) else: return expr def classify_pde(eq, func=None, dict=False, *, prep=True, **kwargs): """ Returns a tuple of possible pdsolve() classifications for a PDE. The tuple is ordered so that first item is the classification that pdsolve() uses to solve the PDE by default. In general, classifications near the beginning of the list will produce better solutions faster than those near the end, though there are always exceptions. To make pdsolve use a different classification, use pdsolve(PDE, func, hint=). See also the pdsolve() docstring for different meta-hints you can use. If ``dict`` is true, classify_pde() will return a dictionary of hint:match expression terms. This is intended for internal use by pdsolve(). Note that because dictionaries are ordered arbitrarily, this will most likely not be in the same order as the tuple. You can get help on different hints by doing help(pde.pde_hintname), where hintname is the name of the hint without "_Integral". See sympy.pde.allhints or the sympy.pde docstring for a list of all supported hints that can be returned from classify_pde. Examples ======== >>> from sympy.solvers.pde import classify_pde >>> from sympy import Function, Eq >>> from sympy.abc import x, y >>> f = Function('f') >>> u = f(x, y) >>> ux = u.diff(x) >>> uy = u.diff(y) >>> eq = Eq(1 + (2*(ux/u)) + (3*(uy/u)), 0) >>> classify_pde(eq) ('1st_linear_constant_coeff_homogeneous',) """ if func and len(func.args) != 2: raise NotImplementedError("Right now only partial " "differential equations of two variables are supported") if prep or func is None: prep, func_ = _preprocess(eq, func) if func is None: func = func_ if isinstance(eq, Equality): if eq.rhs != 0: return classify_pde(eq.lhs - eq.rhs, func) eq = eq.lhs f = func.func x = func.args[0] y = func.args[1] fx = f(x,y).diff(x) fy = f(x,y).diff(y) # TODO : For now pde.py uses support offered by the ode_order function # to find the order with respect to a multi-variable function. An # improvement could be to classify the order of the PDE on the basis of # individual variables. order = ode_order(eq, f(x,y)) # hint:matchdict or hint:(tuple of matchdicts) # Also will contain "default": and "order":order items. matching_hints = {'order': order} if not order: if dict: matching_hints["default"] = None return matching_hints else: return () eq = expand(eq) a = Wild('a', exclude = [f(x,y)]) b = Wild('b', exclude = [f(x,y), fx, fy, x, y]) c = Wild('c', exclude = [f(x,y), fx, fy, x, y]) d = Wild('d', exclude = [f(x,y), fx, fy, x, y]) e = Wild('e', exclude = [f(x,y), fx, fy]) n = Wild('n', exclude = [x, y]) # Try removing the smallest power of f(x,y) # from the highest partial derivatives of f(x,y) reduced_eq = None if eq.is_Add: var = set(combinations_with_replacement((x,y), order)) dummyvar = var.copy() power = None for i in var: coeff = eq.coeff(f(x,y).diff(*i)) if coeff != 1: match = coeff.match(a*f(x,y)**n) if match and match[a]: power = match[n] dummyvar.remove(i) break dummyvar.remove(i) for i in dummyvar: coeff = eq.coeff(f(x,y).diff(*i)) if coeff != 1: match = coeff.match(a*f(x,y)**n) if match and match[a] and match[n] < power: power = match[n] if power: den = f(x,y)**power reduced_eq = Add(*[arg/den for arg in eq.args]) if not reduced_eq: reduced_eq = eq if order == 1: reduced_eq = collect(reduced_eq, f(x, y)) r = reduced_eq.match(b*fx + c*fy + d*f(x,y) + e) if r: if not r[e]: ## Linear first-order homogeneous partial-differential ## equation with constant coefficients r.update({'b': b, 'c': c, 'd': d}) matching_hints["1st_linear_constant_coeff_homogeneous"] = r else: if r[b]**2 + r[c]**2 != 0: ## Linear first-order general partial-differential ## equation with constant coefficients r.update({'b': b, 'c': c, 'd': d, 'e': e}) matching_hints["1st_linear_constant_coeff"] = r matching_hints[ "1st_linear_constant_coeff_Integral"] = r else: b = Wild('b', exclude=[f(x, y), fx, fy]) c = Wild('c', exclude=[f(x, y), fx, fy]) d = Wild('d', exclude=[f(x, y), fx, fy]) r = reduced_eq.match(b*fx + c*fy + d*f(x,y) + e) if r: r.update({'b': b, 'c': c, 'd': d, 'e': e}) matching_hints["1st_linear_variable_coeff"] = r # Order keys based on allhints. retlist = [] for i in allhints: if i in matching_hints: retlist.append(i) if dict: # Dictionaries are ordered arbitrarily, so make note of which # hint would come first for pdsolve(). Use an ordered dict in Py 3. matching_hints["default"] = None matching_hints["ordered_hints"] = tuple(retlist) for i in allhints: if i in matching_hints: matching_hints["default"] = i break return matching_hints else: return tuple(retlist) def checkpdesol(pde, sol, func=None, solve_for_func=True): """ Checks if the given solution satisfies the partial differential equation. pde is the partial differential equation which can be given in the form of an equation or an expression. sol is the solution for which the pde is to be checked. This can also be given in an equation or an expression form. If the function is not provided, the helper function _preprocess from deutils is used to identify the function. If a sequence of solutions is passed, the same sort of container will be used to return the result for each solution. The following methods are currently being implemented to check if the solution satisfies the PDE: 1. Directly substitute the solution in the PDE and check. If the solution hasn't been solved for f, then it will solve for f provided solve_for_func hasn't been set to False. If the solution satisfies the PDE, then a tuple (True, 0) is returned. Otherwise a tuple (False, expr) where expr is the value obtained after substituting the solution in the PDE. However if a known solution returns False, it may be due to the inability of doit() to simplify it to zero. Examples ======== >>> from sympy import Function, symbols >>> from sympy.solvers.pde import checkpdesol, pdsolve >>> x, y = symbols('x y') >>> f = Function('f') >>> eq = 2*f(x,y) + 3*f(x,y).diff(x) + 4*f(x,y).diff(y) >>> sol = pdsolve(eq) >>> assert checkpdesol(eq, sol)[0] >>> eq = x*f(x,y) + f(x,y).diff(x) >>> checkpdesol(eq, sol) (False, (x*F(4*x - 3*y) - 6*F(4*x - 3*y)/25 + 4*Subs(Derivative(F(_xi_1), _xi_1), _xi_1, 4*x - 3*y))*exp(-6*x/25 - 8*y/25)) """ # Converting the pde into an equation if not isinstance(pde, Equality): pde = Eq(pde, 0) # If no function is given, try finding the function present. if func is None: try: _, func = _preprocess(pde.lhs) except ValueError: funcs = [s.atoms(AppliedUndef) for s in ( sol if is_sequence(sol, set) else [sol])] funcs = set().union(funcs) if len(funcs) != 1: raise ValueError( 'must pass func arg to checkpdesol for this case.') func = funcs.pop() # If the given solution is in the form of a list or a set # then return a list or set of tuples. if is_sequence(sol, set): return type(sol)([checkpdesol( pde, i, func=func, solve_for_func=solve_for_func) for i in sol]) # Convert solution into an equation if not isinstance(sol, Equality): sol = Eq(func, sol) elif sol.rhs == func: sol = sol.reversed # Try solving for the function solved = sol.lhs == func and not sol.rhs.has(func) if solve_for_func and not solved: solved = solve(sol, func) if solved: if len(solved) == 1: return checkpdesol(pde, Eq(func, solved[0]), func=func, solve_for_func=False) else: return checkpdesol(pde, [Eq(func, t) for t in solved], func=func, solve_for_func=False) # try direct substitution of the solution into the PDE and simplify if sol.lhs == func: pde = pde.lhs - pde.rhs s = simplify(pde.subs(func, sol.rhs).doit()) return s is S.Zero, s raise NotImplementedError(filldedent(''' Unable to test if %s is a solution to %s.''' % (sol, pde))) def pde_1st_linear_constant_coeff_homogeneous(eq, func, order, match, solvefun): r""" Solves a first order linear homogeneous partial differential equation with constant coefficients. The general form of this partial differential equation is .. math:: a \frac{\partial f(x,y)}{\partial x} + b \frac{\partial f(x,y)}{\partial y} + c f(x,y) = 0 where `a`, `b` and `c` are constants. The general solution is of the form: .. math:: f(x, y) = F(- a y + b x ) e^{- \frac{c (a x + b y)}{a^2 + b^2}} and can be found in SymPy with ``pdsolve``:: >>> from sympy.solvers import pdsolve >>> from sympy.abc import x, y, a, b, c >>> from sympy import Function, pprint >>> f = Function('f') >>> u = f(x,y) >>> ux = u.diff(x) >>> uy = u.diff(y) >>> genform = a*ux + b*uy + c*u >>> pprint(genform) d d a*--(f(x, y)) + b*--(f(x, y)) + c*f(x, y) dx dy >>> pprint(pdsolve(genform)) -c*(a*x + b*y) --------------- 2 2 a + b f(x, y) = F(-a*y + b*x)*e Examples ======== >>> from sympy import pdsolve >>> from sympy import Function, pprint >>> from sympy.abc import x,y >>> f = Function('f') >>> pdsolve(f(x,y) + f(x,y).diff(x) + f(x,y).diff(y)) Eq(f(x, y), F(x - y)*exp(-x/2 - y/2)) >>> pprint(pdsolve(f(x,y) + f(x,y).diff(x) + f(x,y).diff(y))) x y - - - - 2 2 f(x, y) = F(x - y)*e References ========== - Viktor Grigoryan, "Partial Differential Equations" Math 124A - Fall 2010, pp.7 """ # TODO : For now homogeneous first order linear PDE's having # two variables are implemented. Once there is support for # solving systems of ODE's, this can be extended to n variables. f = func.func x = func.args[0] y = func.args[1] b = match[match['b']] c = match[match['c']] d = match[match['d']] return Eq(f(x,y), exp(-S(d)/(b**2 + c**2)*(b*x + c*y))*solvefun(c*x - b*y)) def pde_1st_linear_constant_coeff(eq, func, order, match, solvefun): r""" Solves a first order linear partial differential equation with constant coefficients. The general form of this partial differential equation is .. math:: a \frac{\partial f(x,y)}{\partial x} + b \frac{\partial f(x,y)}{\partial y} + c f(x,y) = G(x,y) where `a`, `b` and `c` are constants and `G(x, y)` can be an arbitrary function in `x` and `y`. The general solution of the PDE is: .. math:: f(x, y) = \left. \left[F(\eta) + \frac{1}{a^2 + b^2} \int\limits^{a x + b y} G\left(\frac{a \xi + b \eta}{a^2 + b^2}, \frac{- a \eta + b \xi}{a^2 + b^2} \right) e^{\frac{c \xi}{a^2 + b^2}}\, d\xi\right] e^{- \frac{c \xi}{a^2 + b^2}} \right|_{\substack{\eta=- a y + b x\\ \xi=a x + b y }}\, , where `F(\eta)` is an arbitrary single-valued function. The solution can be found in SymPy with ``pdsolve``:: >>> from sympy.solvers import pdsolve >>> from sympy.abc import x, y, a, b, c >>> from sympy import Function, pprint >>> f = Function('f') >>> G = Function('G') >>> u = f(x,y) >>> ux = u.diff(x) >>> uy = u.diff(y) >>> genform = a*ux + b*uy + c*u - G(x,y) >>> pprint(genform) d d a*--(f(x, y)) + b*--(f(x, y)) + c*f(x, y) - G(x, y) dx dy >>> pprint(pdsolve(genform, hint='1st_linear_constant_coeff_Integral')) // a*x + b*y \ || / | || | | || | c*xi | || | ------- | || | 2 2 | || | /a*xi + b*eta -a*eta + b*xi\ a + b | || | G|------------, -------------|*e d(xi)| || | | 2 2 2 2 | | || | \ a + b a + b / | || | | || / | || | f(x, y) = ||F(eta) + -------------------------------------------------------|* || 2 2 | \\ a + b / \| || || || || || || || || -c*xi || -------|| 2 2|| a + b || e || || /|eta=-a*y + b*x, xi=a*x + b*y Examples ======== >>> from sympy.solvers.pde import pdsolve >>> from sympy import Function, pprint, exp >>> from sympy.abc import x,y >>> f = Function('f') >>> eq = -2*f(x,y).diff(x) + 4*f(x,y).diff(y) + 5*f(x,y) - exp(x + 3*y) >>> pdsolve(eq) Eq(f(x, y), (F(4*x + 2*y) + exp(x/2 + 4*y)/15)*exp(x/2 - y)) References ========== - Viktor Grigoryan, "Partial Differential Equations" Math 124A - Fall 2010, pp.7 """ # TODO : For now homogeneous first order linear PDE's having # two variables are implemented. Once there is support for # solving systems of ODE's, this can be extended to n variables. xi, eta = symbols("xi eta") f = func.func x = func.args[0] y = func.args[1] b = match[match['b']] c = match[match['c']] d = match[match['d']] e = -match[match['e']] expterm = exp(-S(d)/(b**2 + c**2)*xi) functerm = solvefun(eta) solvedict = solve((b*x + c*y - xi, c*x - b*y - eta), x, y) # Integral should remain as it is in terms of xi, # doit() should be done in _handle_Integral. genterm = (1/S(b**2 + c**2))*Integral( (1/expterm*e).subs(solvedict), (xi, b*x + c*y)) return Eq(f(x,y), Subs(expterm*(functerm + genterm), (eta, xi), (c*x - b*y, b*x + c*y))) def pde_1st_linear_variable_coeff(eq, func, order, match, solvefun): r""" Solves a first order linear partial differential equation with variable coefficients. The general form of this partial differential equation is .. math:: a(x, y) \frac{\partial f(x, y)}{\partial x} + b(x, y) \frac{\partial f(x, y)}{\partial y} + c(x, y) f(x, y) = G(x, y) where `a(x, y)`, `b(x, y)`, `c(x, y)` and `G(x, y)` are arbitrary functions in `x` and `y`. This PDE is converted into an ODE by making the following transformation: 1. `\xi` as `x` 2. `\eta` as the constant in the solution to the differential equation `\frac{dy}{dx} = -\frac{b}{a}` Making the previous substitutions reduces it to the linear ODE .. math:: a(\xi, \eta)\frac{du}{d\xi} + c(\xi, \eta)u - G(\xi, \eta) = 0 which can be solved using ``dsolve``. >>> from sympy.abc import x, y >>> from sympy import Function, pprint >>> a, b, c, G, f= [Function(i) for i in ['a', 'b', 'c', 'G', 'f']] >>> u = f(x,y) >>> ux = u.diff(x) >>> uy = u.diff(y) >>> genform = a(x, y)*u + b(x, y)*ux + c(x, y)*uy - G(x,y) >>> pprint(genform) d d -G(x, y) + a(x, y)*f(x, y) + b(x, y)*--(f(x, y)) + c(x, y)*--(f(x, y)) dx dy Examples ======== >>> from sympy.solvers.pde import pdsolve >>> from sympy import Function, pprint >>> from sympy.abc import x,y >>> f = Function('f') >>> eq = x*(u.diff(x)) - y*(u.diff(y)) + y**2*u - y**2 >>> pdsolve(eq) Eq(f(x, y), F(x*y)*exp(y**2/2) + 1) References ========== - Viktor Grigoryan, "Partial Differential Equations" Math 124A - Fall 2010, pp.7 """ from sympy.integrals.integrals import integrate from sympy.solvers.ode import dsolve xi, eta = symbols("xi eta") f = func.func x = func.args[0] y = func.args[1] b = match[match['b']] c = match[match['c']] d = match[match['d']] e = -match[match['e']] if not d: # To deal with cases like b*ux = e or c*uy = e if not (b and c): if c: try: tsol = integrate(e/c, y) except NotImplementedError: raise NotImplementedError("Unable to find a solution" " due to inability of integrate") else: return Eq(f(x,y), solvefun(x) + tsol) if b: try: tsol = integrate(e/b, x) except NotImplementedError: raise NotImplementedError("Unable to find a solution" " due to inability of integrate") else: return Eq(f(x,y), solvefun(y) + tsol) if not c: # To deal with cases when c is 0, a simpler method is used. # The PDE reduces to b*(u.diff(x)) + d*u = e, which is a linear ODE in x plode = f(x).diff(x)*b + d*f(x) - e sol = dsolve(plode, f(x)) syms = sol.free_symbols - plode.free_symbols - {x, y} rhs = _simplify_variable_coeff(sol.rhs, syms, solvefun, y) return Eq(f(x, y), rhs) if not b: # To deal with cases when b is 0, a simpler method is used. # The PDE reduces to c*(u.diff(y)) + d*u = e, which is a linear ODE in y plode = f(y).diff(y)*c + d*f(y) - e sol = dsolve(plode, f(y)) syms = sol.free_symbols - plode.free_symbols - {x, y} rhs = _simplify_variable_coeff(sol.rhs, syms, solvefun, x) return Eq(f(x, y), rhs) dummy = Function('d') h = (c/b).subs(y, dummy(x)) sol = dsolve(dummy(x).diff(x) - h, dummy(x)) if isinstance(sol, list): sol = sol[0] solsym = sol.free_symbols - h.free_symbols - {x, y} if len(solsym) == 1: solsym = solsym.pop() etat = (solve(sol, solsym)[0]).subs(dummy(x), y) ysub = solve(eta - etat, y)[0] deq = (b*(f(x).diff(x)) + d*f(x) - e).subs(y, ysub) final = (dsolve(deq, f(x), hint='1st_linear')).rhs if isinstance(final, list): final = final[0] finsyms = final.free_symbols - deq.free_symbols - {x, y} rhs = _simplify_variable_coeff(final, finsyms, solvefun, etat) return Eq(f(x, y), rhs) else: raise NotImplementedError("Cannot solve the partial differential equation due" " to inability of constantsimp") def _simplify_variable_coeff(sol, syms, func, funcarg): r""" Helper function to replace constants by functions in 1st_linear_variable_coeff """ eta = Symbol("eta") if len(syms) == 1: sym = syms.pop() final = sol.subs(sym, func(funcarg)) else: for key, sym in enumerate(syms): final = sol.subs(sym, func(funcarg)) return simplify(final.subs(eta, funcarg)) def pde_separate(eq, fun, sep, strategy='mul'): """Separate variables in partial differential equation either by additive or multiplicative separation approach. It tries to rewrite an equation so that one of the specified variables occurs on a different side of the equation than the others. :param eq: Partial differential equation :param fun: Original function F(x, y, z) :param sep: List of separated functions [X(x), u(y, z)] :param strategy: Separation strategy. You can choose between additive separation ('add') and multiplicative separation ('mul') which is default. Examples ======== >>> from sympy import E, Eq, Function, pde_separate, Derivative as D >>> from sympy.abc import x, t >>> u, X, T = map(Function, 'uXT') >>> eq = Eq(D(u(x, t), x), E**(u(x, t))*D(u(x, t), t)) >>> pde_separate(eq, u(x, t), [X(x), T(t)], strategy='add') [exp(-X(x))*Derivative(X(x), x), exp(T(t))*Derivative(T(t), t)] >>> eq = Eq(D(u(x, t), x, 2), D(u(x, t), t, 2)) >>> pde_separate(eq, u(x, t), [X(x), T(t)], strategy='mul') [Derivative(X(x), (x, 2))/X(x), Derivative(T(t), (t, 2))/T(t)] See Also ======== pde_separate_add, pde_separate_mul """ do_add = False if strategy == 'add': do_add = True elif strategy == 'mul': do_add = False else: raise ValueError('Unknown strategy: %s' % strategy) if isinstance(eq, Equality): if eq.rhs != 0: return pde_separate(Eq(eq.lhs - eq.rhs, 0), fun, sep, strategy) else: return pde_separate(Eq(eq, 0), fun, sep, strategy) if eq.rhs != 0: raise ValueError("Value should be 0") # Handle arguments orig_args = list(fun.args) subs_args = [] for s in sep: for j in range(0, len(s.args)): subs_args.append(s.args[j]) if do_add: functions = reduce(operator.add, sep) else: functions = reduce(operator.mul, sep) # Check whether variables match if len(subs_args) != len(orig_args): raise ValueError("Variable counts do not match") # Check for duplicate arguments like [X(x), u(x, y)] if has_dups(subs_args): raise ValueError("Duplicate substitution arguments detected") # Check whether the variables match if set(orig_args) != set(subs_args): raise ValueError("Arguments do not match") # Substitute original function with separated... result = eq.lhs.subs(fun, functions).doit() # Divide by terms when doing multiplicative separation if not do_add: eq = 0 for i in result.args: eq += i/functions result = eq svar = subs_args[0] dvar = subs_args[1:] return _separate(result, svar, dvar) def pde_separate_add(eq, fun, sep): """ Helper function for searching additive separable solutions. Consider an equation of two independent variables x, y and a dependent variable w, we look for the product of two functions depending on different arguments: `w(x, y, z) = X(x) + y(y, z)` Examples ======== >>> from sympy import E, Eq, Function, pde_separate_add, Derivative as D >>> from sympy.abc import x, t >>> u, X, T = map(Function, 'uXT') >>> eq = Eq(D(u(x, t), x), E**(u(x, t))*D(u(x, t), t)) >>> pde_separate_add(eq, u(x, t), [X(x), T(t)]) [exp(-X(x))*Derivative(X(x), x), exp(T(t))*Derivative(T(t), t)] """ return pde_separate(eq, fun, sep, strategy='add') def pde_separate_mul(eq, fun, sep): """ Helper function for searching multiplicative separable solutions. Consider an equation of two independent variables x, y and a dependent variable w, we look for the product of two functions depending on different arguments: `w(x, y, z) = X(x)*u(y, z)` Examples ======== >>> from sympy import Function, Eq, pde_separate_mul, Derivative as D >>> from sympy.abc import x, y >>> u, X, Y = map(Function, 'uXY') >>> eq = Eq(D(u(x, y), x, 2), D(u(x, y), y, 2)) >>> pde_separate_mul(eq, u(x, y), [X(x), Y(y)]) [Derivative(X(x), (x, 2))/X(x), Derivative(Y(y), (y, 2))/Y(y)] """ return pde_separate(eq, fun, sep, strategy='mul') def _separate(eq, dep, others): """Separate expression into two parts based on dependencies of variables.""" # FIRST PASS # Extract derivatives depending our separable variable... terms = set() for term in eq.args: if term.is_Mul: for i in term.args: if i.is_Derivative and not i.has(*others): terms.add(term) continue elif term.is_Derivative and not term.has(*others): terms.add(term) # Find the factor that we need to divide by div = set() for term in terms: ext, sep = term.expand().as_independent(dep) # Failed? if sep.has(*others): return None div.add(ext) # FIXME: Find lcm() of all the divisors and divide with it, instead of # current hack :( # https://github.com/sympy/sympy/issues/4597 if len(div) > 0: final = 0 for term in eq.args: eqn = 0 for i in div: eqn += term / i final += simplify(eqn) eq = final # SECOND PASS - separate the derivatives div = set() lhs = rhs = 0 for term in eq.args: # Check, whether we have already term with independent variable... if not term.has(*others): lhs += term continue # ...otherwise, try to separate temp, sep = term.expand().as_independent(dep) # Failed? if sep.has(*others): return None # Extract the divisors div.add(sep) rhs -= term.expand() # Do the division fulldiv = reduce(operator.add, div) lhs = simplify(lhs/fulldiv).expand() rhs = simplify(rhs/fulldiv).expand() # ...and check whether we were successful :) if lhs.has(*others) or rhs.has(dep): return None return [lhs, rhs] sympy-sympy-1.9/sympy/solvers/polysys.py000066400000000000000000000260211412543434000206760ustar00rootroot00000000000000"""Solvers of systems of polynomial equations. """ from sympy.core import S from sympy.polys import Poly, groebner, roots from sympy.polys.polytools import parallel_poly_from_expr from sympy.polys.polyerrors import (ComputationFailed, PolificationFailed, CoercionFailed) from sympy.simplify import rcollect from sympy.utilities import default_sort_key, postfixes from sympy.utilities.misc import filldedent class SolveFailed(Exception): """Raised when solver's conditions weren't met. """ def solve_poly_system(seq, *gens, **args): """ Solve a system of polynomial equations. Parameters ========== seq: a list/tuple/set Listing all the equations that are needed to be solved gens: generators generators of the equations in seq for which we want the solutions args: Keyword arguments Special options for solving the equations Returns ======= List[Tuple] A List of tuples. Solutions for symbols that satisfy the equations listed in seq Examples ======== >>> from sympy import solve_poly_system >>> from sympy.abc import x, y >>> solve_poly_system([x*y - 2*y, 2*y**2 - x**2], x, y) [(0, 0), (2, -sqrt(2)), (2, sqrt(2))] """ try: polys, opt = parallel_poly_from_expr(seq, *gens, **args) except PolificationFailed as exc: raise ComputationFailed('solve_poly_system', len(seq), exc) if len(polys) == len(opt.gens) == 2: f, g = polys if all(i <= 2 for i in f.degree_list() + g.degree_list()): try: return solve_biquadratic(f, g, opt) except SolveFailed: pass return solve_generic(polys, opt) def solve_biquadratic(f, g, opt): """Solve a system of two bivariate quadratic polynomial equations. Parameters ========== f: a single Expr or Poly First equation g: a single Expr or Poly Second Equation opt: an Options object For specifying keyword arguments and generators Returns ======= List[Tuple] A List of tuples. Solutions for symbols that satisfy the equations listed in seq. Examples ======== >>> from sympy.polys import Options, Poly >>> from sympy.abc import x, y >>> from sympy.solvers.polysys import solve_biquadratic >>> NewOption = Options((x, y), {'domain': 'ZZ'}) >>> a = Poly(y**2 - 4 + x, y, x, domain='ZZ') >>> b = Poly(y*2 + 3*x - 7, y, x, domain='ZZ') >>> solve_biquadratic(a, b, NewOption) [(1/3, 3), (41/27, 11/9)] >>> a = Poly(y + x**2 - 3, y, x, domain='ZZ') >>> b = Poly(-y + x - 4, y, x, domain='ZZ') >>> solve_biquadratic(a, b, NewOption) [(7/2 - sqrt(29)/2, -sqrt(29)/2 - 1/2), (sqrt(29)/2 + 7/2, -1/2 + \ sqrt(29)/2)] """ G = groebner([f, g]) if len(G) == 1 and G[0].is_ground: return None if len(G) != 2: raise SolveFailed x, y = opt.gens p, q = G if not p.gcd(q).is_ground: # not 0-dimensional raise SolveFailed p = Poly(p, x, expand=False) p_roots = [rcollect(expr, y) for expr in roots(p).keys()] q = q.ltrim(-1) q_roots = list(roots(q).keys()) solutions = [] for q_root in q_roots: for p_root in p_roots: solution = (p_root.subs(y, q_root), q_root) solutions.append(solution) return sorted(solutions, key=default_sort_key) def solve_generic(polys, opt): """ Solve a generic system of polynomial equations. Returns all possible solutions over C[x_1, x_2, ..., x_m] of a set F = { f_1, f_2, ..., f_n } of polynomial equations, using Groebner basis approach. For now only zero-dimensional systems are supported, which means F can have at most a finite number of solutions. The algorithm works by the fact that, supposing G is the basis of F with respect to an elimination order (here lexicographic order is used), G and F generate the same ideal, they have the same set of solutions. By the elimination property, if G is a reduced, zero-dimensional Groebner basis, then there exists an univariate polynomial in G (in its last variable). This can be solved by computing its roots. Substituting all computed roots for the last (eliminated) variable in other elements of G, new polynomial system is generated. Applying the above procedure recursively, a finite number of solutions can be found. The ability of finding all solutions by this procedure depends on the root finding algorithms. If no solutions were found, it means only that roots() failed, but the system is solvable. To overcome this difficulty use numerical algorithms instead. Parameters ========== polys: a list/tuple/set Listing all the polynomial equations that are needed to be solved opt: an Options object For specifying keyword arguments and generators Returns ======= List[Tuple] A List of tuples. Solutions for symbols that satisfy the equations listed in seq References ========== .. [Buchberger01] B. Buchberger, Groebner Bases: A Short Introduction for Systems Theorists, In: R. Moreno-Diaz, B. Buchberger, J.L. Freire, Proceedings of EUROCAST'01, February, 2001 .. [Cox97] D. Cox, J. Little, D. O'Shea, Ideals, Varieties and Algorithms, Springer, Second Edition, 1997, pp. 112 Examples ======== >>> from sympy.polys import Poly, Options >>> from sympy.solvers.polysys import solve_generic >>> from sympy.abc import x, y >>> NewOption = Options((x, y), {'domain': 'ZZ'}) >>> a = Poly(x - y + 5, x, y, domain='ZZ') >>> b = Poly(x + y - 3, x, y, domain='ZZ') >>> solve_generic([a, b], NewOption) [(-1, 4)] >>> a = Poly(x - 2*y + 5, x, y, domain='ZZ') >>> b = Poly(2*x - y - 3, x, y, domain='ZZ') >>> solve_generic([a, b], NewOption) [(11/3, 13/3)] >>> a = Poly(x**2 + y, x, y, domain='ZZ') >>> b = Poly(x + y*4, x, y, domain='ZZ') >>> solve_generic([a, b], NewOption) [(0, 0), (1/4, -1/16)] """ def _is_univariate(f): """Returns True if 'f' is univariate in its last variable. """ for monom in f.monoms(): if any(monom[:-1]): return False return True def _subs_root(f, gen, zero): """Replace generator with a root so that the result is nice. """ p = f.as_expr({gen: zero}) if f.degree(gen) >= 2: p = p.expand(deep=False) return p def _solve_reduced_system(system, gens, entry=False): """Recursively solves reduced polynomial systems. """ if len(system) == len(gens) == 1: zeros = list(roots(system[0], gens[-1]).keys()) return [(zero,) for zero in zeros] basis = groebner(system, gens, polys=True) if len(basis) == 1 and basis[0].is_ground: if not entry: return [] else: return None univariate = list(filter(_is_univariate, basis)) if len(univariate) == 1: f = univariate.pop() else: raise NotImplementedError(filldedent(''' only zero-dimensional systems supported (finite number of solutions) ''')) gens = f.gens gen = gens[-1] zeros = list(roots(f.ltrim(gen)).keys()) if not zeros: return [] if len(basis) == 1: return [(zero,) for zero in zeros] solutions = [] for zero in zeros: new_system = [] new_gens = gens[:-1] for b in basis[:-1]: eq = _subs_root(b, gen, zero) if eq is not S.Zero: new_system.append(eq) for solution in _solve_reduced_system(new_system, new_gens): solutions.append(solution + (zero,)) if solutions and len(solutions[0]) != len(gens): raise NotImplementedError(filldedent(''' only zero-dimensional systems supported (finite number of solutions) ''')) return solutions try: result = _solve_reduced_system(polys, opt.gens, entry=True) except CoercionFailed: raise NotImplementedError if result is not None: return sorted(result, key=default_sort_key) else: return None def solve_triangulated(polys, *gens, **args): """ Solve a polynomial system using Gianni-Kalkbrenner algorithm. The algorithm proceeds by computing one Groebner basis in the ground domain and then by iteratively computing polynomial factorizations in appropriately constructed algebraic extensions of the ground domain. Parameters ========== polys: a list/tuple/set Listing all the equations that are needed to be solved gens: generators generators of the equations in polys for which we want the solutions args: Keyword arguments Special options for solving the equations Returns ======= List[Tuple] A List of tuples. Solutions for symbols that satisfy the equations listed in polys Examples ======== >>> from sympy.solvers.polysys import solve_triangulated >>> from sympy.abc import x, y, z >>> F = [x**2 + y + z - 1, x + y**2 + z - 1, x + y + z**2 - 1] >>> solve_triangulated(F, x, y, z) [(0, 0, 1), (0, 1, 0), (1, 0, 0)] References ========== 1. Patrizia Gianni, Teo Mora, Algebraic Solution of System of Polynomial Equations using Groebner Bases, AAECC-5 on Applied Algebra, Algebraic Algorithms and Error-Correcting Codes, LNCS 356 247--257, 1989 """ G = groebner(polys, gens, polys=True) G = list(reversed(G)) domain = args.get('domain') if domain is not None: for i, g in enumerate(G): G[i] = g.set_domain(domain) f, G = G[0].ltrim(-1), G[1:] dom = f.get_domain() zeros = f.ground_roots() solutions = set() for zero in zeros: solutions.add(((zero,), dom)) var_seq = reversed(gens[:-1]) vars_seq = postfixes(gens[1:]) for var, vars in zip(var_seq, vars_seq): _solutions = set() for values, dom in solutions: H, mapping = [], list(zip(vars, values)) for g in G: _vars = (var,) + vars if g.has_only_gens(*_vars) and g.degree(var) != 0: h = g.ltrim(var).eval(dict(mapping)) if g.degree(var) == h.degree(): H.append(h) p = min(H, key=lambda h: h.degree()) zeros = p.ground_roots() for zero in zeros: if not zero.is_Rational: dom_zero = dom.algebraic_field(zero) else: dom_zero = dom _solutions.add(((zero,) + values, dom_zero)) solutions = _solutions solutions = list(solutions) for i, (solution, _) in enumerate(solutions): solutions[i] = solution return sorted(solutions, key=default_sort_key) sympy-sympy-1.9/sympy/solvers/recurr.py000066400000000000000000000604641412543434000204670ustar00rootroot00000000000000r""" This module is intended for solving recurrences or, in other words, difference equations. Currently supported are linear, inhomogeneous equations with polynomial or rational coefficients. The solutions are obtained among polynomials, rational functions, hypergeometric terms, or combinations of hypergeometric term which are pairwise dissimilar. ``rsolve_X`` functions were meant as a low level interface for ``rsolve`` which would use Mathematica's syntax. Given a recurrence relation: .. math:: a_{k}(n) y(n+k) + a_{k-1}(n) y(n+k-1) + ... + a_{0}(n) y(n) = f(n) where `k > 0` and `a_{i}(n)` are polynomials in `n`. To use ``rsolve_X`` we need to put all coefficients in to a list ``L`` of `k+1` elements the following way: ``L = [a_{0}(n), ..., a_{k-1}(n), a_{k}(n)]`` where ``L[i]``, for `i=0, \ldots, k`, maps to `a_{i}(n) y(n+i)` (`y(n+i)` is implicit). For example if we would like to compute `m`-th Bernoulli polynomial up to a constant (example was taken from rsolve_poly docstring), then we would use `b(n+1) - b(n) = m n^{m-1}` recurrence, which has solution `b(n) = B_m + C`. Then ``L = [-1, 1]`` and `f(n) = m n^(m-1)` and finally for `m=4`: >>> from sympy import Symbol, bernoulli, rsolve_poly >>> n = Symbol('n', integer=True) >>> rsolve_poly([-1, 1], 4*n**3, n) C0 + n**4 - 2*n**3 + n**2 >>> bernoulli(4, n) n**4 - 2*n**3 + n**2 - 1/30 For the sake of completeness, `f(n)` can be: [1] a polynomial -> rsolve_poly [2] a rational function -> rsolve_ratio [3] a hypergeometric function -> rsolve_hyper """ from collections import defaultdict from sympy.core.singleton import S from sympy.core.numbers import Rational, I from sympy.core.symbol import Symbol, Wild, Dummy from sympy.core.relational import Equality from sympy.core.add import Add from sympy.core.mul import Mul from sympy.core import sympify from sympy.simplify import simplify, hypersimp, hypersimilar # type: ignore from sympy.solvers import solve, solve_undetermined_coeffs from sympy.polys import Poly, quo, gcd, lcm, roots, resultant from sympy.functions import binomial, factorial, FallingFactorial, RisingFactorial from sympy.matrices import Matrix, casoratian from sympy.concrete import product from sympy.core.compatibility import default_sort_key from sympy.utilities.iterables import numbered_symbols def rsolve_poly(coeffs, f, n, shift=0, **hints): r""" Given linear recurrence operator `\operatorname{L}` of order `k` with polynomial coefficients and inhomogeneous equation `\operatorname{L} y = f`, where `f` is a polynomial, we seek for all polynomial solutions over field `K` of characteristic zero. The algorithm performs two basic steps: (1) Compute degree `N` of the general polynomial solution. (2) Find all polynomials of degree `N` or less of `\operatorname{L} y = f`. There are two methods for computing the polynomial solutions. If the degree bound is relatively small, i.e. it's smaller than or equal to the order of the recurrence, then naive method of undetermined coefficients is being used. This gives system of algebraic equations with `N+1` unknowns. In the other case, the algorithm performs transformation of the initial equation to an equivalent one, for which the system of algebraic equations has only `r` indeterminates. This method is quite sophisticated (in comparison with the naive one) and was invented together by Abramov, Bronstein and Petkovsek. It is possible to generalize the algorithm implemented here to the case of linear q-difference and differential equations. Lets say that we would like to compute `m`-th Bernoulli polynomial up to a constant. For this we can use `b(n+1) - b(n) = m n^{m-1}` recurrence, which has solution `b(n) = B_m + C`. For example: >>> from sympy import Symbol, rsolve_poly >>> n = Symbol('n', integer=True) >>> rsolve_poly([-1, 1], 4*n**3, n) C0 + n**4 - 2*n**3 + n**2 References ========== .. [1] S. A. Abramov, M. Bronstein and M. Petkovsek, On polynomial solutions of linear operator equations, in: T. Levelt, ed., Proc. ISSAC '95, ACM Press, New York, 1995, 290-296. .. [2] M. Petkovsek, Hypergeometric solutions of linear recurrences with polynomial coefficients, J. Symbolic Computation, 14 (1992), 243-264. .. [3] M. Petkovsek, H. S. Wilf, D. Zeilberger, A = B, 1996. """ f = sympify(f) if not f.is_polynomial(n): return None homogeneous = f.is_zero r = len(coeffs) - 1 coeffs = [Poly(coeff, n) for coeff in coeffs] polys = [Poly(0, n)]*(r + 1) terms = [(S.Zero, S.NegativeInfinity)]*(r + 1) for i in range(r + 1): for j in range(i, r + 1): polys[i] += coeffs[j]*(binomial(j, i).as_poly(n)) if not polys[i].is_zero: (exp,), coeff = polys[i].LT() terms[i] = (coeff, exp) d = b = terms[0][1] for i in range(1, r + 1): if terms[i][1] > d: d = terms[i][1] if terms[i][1] - i > b: b = terms[i][1] - i d, b = int(d), int(b) x = Dummy('x') degree_poly = S.Zero for i in range(r + 1): if terms[i][1] - i == b: degree_poly += terms[i][0]*FallingFactorial(x, i) nni_roots = list(roots(degree_poly, x, filter='Z', predicate=lambda r: r >= 0).keys()) if nni_roots: N = [max(nni_roots)] else: N = [] if homogeneous: N += [-b - 1] else: N += [f.as_poly(n).degree() - b, -b - 1] N = int(max(N)) if N < 0: if homogeneous: if hints.get('symbols', False): return (S.Zero, []) else: return S.Zero else: return None if N <= r: C = [] y = E = S.Zero for i in range(N + 1): C.append(Symbol('C' + str(i + shift))) y += C[i] * n**i for i in range(r + 1): E += coeffs[i].as_expr()*y.subs(n, n + i) solutions = solve_undetermined_coeffs(E - f, C, n) if solutions is not None: C = [c for c in C if (c not in solutions)] result = y.subs(solutions) else: return None # TBD else: A = r U = N + A + b + 1 nni_roots = list(roots(polys[r], filter='Z', predicate=lambda r: r >= 0).keys()) if nni_roots != []: a = max(nni_roots) + 1 else: a = S.Zero def _zero_vector(k): return [S.Zero] * k def _one_vector(k): return [S.One] * k def _delta(p, k): B = S.One D = p.subs(n, a + k) for i in range(1, k + 1): B *= Rational(i - k - 1, i) D += B * p.subs(n, a + k - i) return D alpha = {} for i in range(-A, d + 1): I = _one_vector(d + 1) for k in range(1, d + 1): I[k] = I[k - 1] * (x + i - k + 1)/k alpha[i] = S.Zero for j in range(A + 1): for k in range(d + 1): B = binomial(k, i + j) D = _delta(polys[j].as_expr(), k) alpha[i] += I[k]*B*D V = Matrix(U, A, lambda i, j: int(i == j)) if homogeneous: for i in range(A, U): v = _zero_vector(A) for k in range(1, A + b + 1): if i - k < 0: break B = alpha[k - A].subs(x, i - k) for j in range(A): v[j] += B * V[i - k, j] denom = alpha[-A].subs(x, i) for j in range(A): V[i, j] = -v[j] / denom else: G = _zero_vector(U) for i in range(A, U): v = _zero_vector(A) g = S.Zero for k in range(1, A + b + 1): if i - k < 0: break B = alpha[k - A].subs(x, i - k) for j in range(A): v[j] += B * V[i - k, j] g += B * G[i - k] denom = alpha[-A].subs(x, i) for j in range(A): V[i, j] = -v[j] / denom G[i] = (_delta(f, i - A) - g) / denom P, Q = _one_vector(U), _zero_vector(A) for i in range(1, U): P[i] = (P[i - 1] * (n - a - i + 1)/i).expand() for i in range(A): Q[i] = Add(*[(v*p).expand() for v, p in zip(V[:, i], P)]) if not homogeneous: h = Add(*[(g*p).expand() for g, p in zip(G, P)]) C = [Symbol('C' + str(i + shift)) for i in range(A)] g = lambda i: Add(*[c*_delta(q, i) for c, q in zip(C, Q)]) if homogeneous: E = [g(i) for i in range(N + 1, U)] else: E = [g(i) + _delta(h, i) for i in range(N + 1, U)] if E != []: solutions = solve(E, *C) if not solutions: if homogeneous: if hints.get('symbols', False): return (S.Zero, []) else: return S.Zero else: return None else: solutions = {} if homogeneous: result = S.Zero else: result = h for c, q in list(zip(C, Q)): if c in solutions: s = solutions[c]*q C.remove(c) else: s = c*q result += s.expand() if hints.get('symbols', False): return (result, C) else: return result def rsolve_ratio(coeffs, f, n, **hints): r""" Given linear recurrence operator `\operatorname{L}` of order `k` with polynomial coefficients and inhomogeneous equation `\operatorname{L} y = f`, where `f` is a polynomial, we seek for all rational solutions over field `K` of characteristic zero. This procedure accepts only polynomials, however if you are interested in solving recurrence with rational coefficients then use ``rsolve`` which will pre-process the given equation and run this procedure with polynomial arguments. The algorithm performs two basic steps: (1) Compute polynomial `v(n)` which can be used as universal denominator of any rational solution of equation `\operatorname{L} y = f`. (2) Construct new linear difference equation by substitution `y(n) = u(n)/v(n)` and solve it for `u(n)` finding all its polynomial solutions. Return ``None`` if none were found. Algorithm implemented here is a revised version of the original Abramov's algorithm, developed in 1989. The new approach is much simpler to implement and has better overall efficiency. This method can be easily adapted to q-difference equations case. Besides finding rational solutions alone, this functions is an important part of Hyper algorithm were it is used to find particular solution of inhomogeneous part of a recurrence. Examples ======== >>> from sympy.abc import x >>> from sympy.solvers.recurr import rsolve_ratio >>> rsolve_ratio([-2*x**3 + x**2 + 2*x - 1, 2*x**3 + x**2 - 6*x, ... - 2*x**3 - 11*x**2 - 18*x - 9, 2*x**3 + 13*x**2 + 22*x + 8], 0, x) C2*(2*x - 3)/(2*(x**2 - 1)) References ========== .. [1] S. A. Abramov, Rational solutions of linear difference and q-difference equations with polynomial coefficients, in: T. Levelt, ed., Proc. ISSAC '95, ACM Press, New York, 1995, 285-289 See Also ======== rsolve_hyper """ f = sympify(f) if not f.is_polynomial(n): return None coeffs = list(map(sympify, coeffs)) r = len(coeffs) - 1 A, B = coeffs[r], coeffs[0] A = A.subs(n, n - r).expand() h = Dummy('h') res = resultant(A, B.subs(n, n + h), n) if not res.is_polynomial(h): p, q = res.as_numer_denom() res = quo(p, q, h) nni_roots = list(roots(res, h, filter='Z', predicate=lambda r: r >= 0).keys()) if not nni_roots: return rsolve_poly(coeffs, f, n, **hints) else: C, numers = S.One, [S.Zero]*(r + 1) for i in range(int(max(nni_roots)), -1, -1): d = gcd(A, B.subs(n, n + i), n) A = quo(A, d, n) B = quo(B, d.subs(n, n - i), n) C *= Mul(*[d.subs(n, n - j) for j in range(i + 1)]) denoms = [C.subs(n, n + i) for i in range(r + 1)] for i in range(r + 1): g = gcd(coeffs[i], denoms[i], n) numers[i] = quo(coeffs[i], g, n) denoms[i] = quo(denoms[i], g, n) for i in range(r + 1): numers[i] *= Mul(*(denoms[:i] + denoms[i + 1:])) result = rsolve_poly(numers, f * Mul(*denoms), n, **hints) if result is not None: if hints.get('symbols', False): return (simplify(result[0] / C), result[1]) else: return simplify(result / C) else: return None def rsolve_hyper(coeffs, f, n, **hints): r""" Given linear recurrence operator `\operatorname{L}` of order `k` with polynomial coefficients and inhomogeneous equation `\operatorname{L} y = f` we seek for all hypergeometric solutions over field `K` of characteristic zero. The inhomogeneous part can be either hypergeometric or a sum of a fixed number of pairwise dissimilar hypergeometric terms. The algorithm performs three basic steps: (1) Group together similar hypergeometric terms in the inhomogeneous part of `\operatorname{L} y = f`, and find particular solution using Abramov's algorithm. (2) Compute generating set of `\operatorname{L}` and find basis in it, so that all solutions are linearly independent. (3) Form final solution with the number of arbitrary constants equal to dimension of basis of `\operatorname{L}`. Term `a(n)` is hypergeometric if it is annihilated by first order linear difference equations with polynomial coefficients or, in simpler words, if consecutive term ratio is a rational function. The output of this procedure is a linear combination of fixed number of hypergeometric terms. However the underlying method can generate larger class of solutions - D'Alembertian terms. Note also that this method not only computes the kernel of the inhomogeneous equation, but also reduces in to a basis so that solutions generated by this procedure are linearly independent Examples ======== >>> from sympy.solvers import rsolve_hyper >>> from sympy.abc import x >>> rsolve_hyper([-1, -1, 1], 0, x) C0*(1/2 - sqrt(5)/2)**x + C1*(1/2 + sqrt(5)/2)**x >>> rsolve_hyper([-1, 1], 1 + x, x) C0 + x*(x + 1)/2 References ========== .. [1] M. Petkovsek, Hypergeometric solutions of linear recurrences with polynomial coefficients, J. Symbolic Computation, 14 (1992), 243-264. .. [2] M. Petkovsek, H. S. Wilf, D. Zeilberger, A = B, 1996. """ coeffs = list(map(sympify, coeffs)) f = sympify(f) r, kernel, symbols = len(coeffs) - 1, [], set() if not f.is_zero: if f.is_Add: similar = {} for g in f.expand().args: if not g.is_hypergeometric(n): return None for h in similar.keys(): if hypersimilar(g, h, n): similar[h] += g break else: similar[g] = S.Zero inhomogeneous = [] for g, h in similar.items(): inhomogeneous.append(g + h) elif f.is_hypergeometric(n): inhomogeneous = [f] else: return None for i, g in enumerate(inhomogeneous): coeff, polys = S.One, coeffs[:] denoms = [S.One]*(r + 1) s = hypersimp(g, n) for j in range(1, r + 1): coeff *= s.subs(n, n + j - 1) p, q = coeff.as_numer_denom() polys[j] *= p denoms[j] = q for j in range(r + 1): polys[j] *= Mul(*(denoms[:j] + denoms[j + 1:])) R = rsolve_poly(polys, Mul(*denoms), n) if not (R is None or R is S.Zero): inhomogeneous[i] *= R else: return None result = Add(*inhomogeneous) else: result = S.Zero Z = Dummy('Z') p, q = coeffs[0], coeffs[r].subs(n, n - r + 1) p_factors = [z for z in roots(p, n).keys()] q_factors = [z for z in roots(q, n).keys()] factors = [(S.One, S.One)] for p in p_factors: for q in q_factors: if p.is_integer and q.is_integer and p <= q: continue else: factors += [(n - p, n - q)] p = [(n - p, S.One) for p in p_factors] q = [(S.One, n - q) for q in q_factors] factors = p + factors + q for A, B in factors: polys, degrees = [], [] D = A*B.subs(n, n + r - 1) for i in range(r + 1): a = Mul(*[A.subs(n, n + j) for j in range(i)]) b = Mul(*[B.subs(n, n + j) for j in range(i, r)]) poly = quo(coeffs[i]*a*b, D, n) polys.append(poly.as_poly(n)) if not poly.is_zero: degrees.append(polys[i].degree()) if degrees: d, poly = max(degrees), S.Zero else: return None for i in range(r + 1): coeff = polys[i].nth(d) if coeff is not S.Zero: poly += coeff * Z**i for z in roots(poly, Z).keys(): if z.is_zero: continue recurr_coeffs = [polys[i].as_expr()*z**i for i in range(r + 1)] if d == 0 and 0 != Add(*[recurr_coeffs[j]*j for j in range(1, r + 1)]): # faster inline check (than calling rsolve_poly) for a # constant solution to a constant coefficient recurrence. C = Symbol("C" + str(len(symbols))) s = [C] else: C, s = rsolve_poly(recurr_coeffs, 0, n, len(symbols), symbols=True) if C is not None and C is not S.Zero: symbols |= set(s) ratio = z * A * C.subs(n, n + 1) / B / C ratio = simplify(ratio) # If there is a nonnegative root in the denominator of the ratio, # this indicates that the term y(n_root) is zero, and one should # start the product with the term y(n_root + 1). n0 = 0 for n_root in roots(ratio.as_numer_denom()[1], n).keys(): if n_root.has(I): return None elif (n0 < (n_root + 1)) == True: n0 = n_root + 1 K = product(ratio, (n, n0, n - 1)) if K.has(factorial, FallingFactorial, RisingFactorial): K = simplify(K) if casoratian(kernel + [K], n, zero=False) != 0: kernel.append(K) kernel.sort(key=default_sort_key) sk = list(zip(numbered_symbols('C'), kernel)) if sk: for C, ker in sk: result += C * ker else: return None if hints.get('symbols', False): # XXX: This returns the symbols in a non-deterministic order symbols |= {s for s, k in sk} return (result, list(symbols)) else: return result def rsolve(f, y, init=None): r""" Solve univariate recurrence with rational coefficients. Given `k`-th order linear recurrence `\operatorname{L} y = f`, or equivalently: .. math:: a_{k}(n) y(n+k) + a_{k-1}(n) y(n+k-1) + \cdots + a_{0}(n) y(n) = f(n) where `a_{i}(n)`, for `i=0, \ldots, k`, are polynomials or rational functions in `n`, and `f` is a hypergeometric function or a sum of a fixed number of pairwise dissimilar hypergeometric terms in `n`, finds all solutions or returns ``None``, if none were found. Initial conditions can be given as a dictionary in two forms: (1) ``{ n_0 : v_0, n_1 : v_1, ..., n_m : v_m}`` (2) ``{y(n_0) : v_0, y(n_1) : v_1, ..., y(n_m) : v_m}`` or as a list ``L`` of values: ``L = [v_0, v_1, ..., v_m]`` where ``L[i] = v_i``, for `i=0, \ldots, m`, maps to `y(n_i)`. Examples ======== Lets consider the following recurrence: .. math:: (n - 1) y(n + 2) - (n^2 + 3 n - 2) y(n + 1) + 2 n (n + 1) y(n) = 0 >>> from sympy import Function, rsolve >>> from sympy.abc import n >>> y = Function('y') >>> f = (n - 1)*y(n + 2) - (n**2 + 3*n - 2)*y(n + 1) + 2*n*(n + 1)*y(n) >>> rsolve(f, y(n)) 2**n*C0 + C1*factorial(n) >>> rsolve(f, y(n), {y(0):0, y(1):3}) 3*2**n - 3*factorial(n) See Also ======== rsolve_poly, rsolve_ratio, rsolve_hyper """ if isinstance(f, Equality): f = f.lhs - f.rhs n = y.args[0] k = Wild('k', exclude=(n,)) # Preprocess user input to allow things like # y(n) + a*(y(n + 1) + y(n - 1))/2 f = f.expand().collect(y.func(Wild('m', integer=True))) h_part = defaultdict(list) i_part = [] for g in Add.make_args(f): coeff, dep = g.as_coeff_mul(y.func) if not dep: i_part.append(coeff) continue for h in dep: if h.is_Function and h.func == y.func: result = h.args[0].match(n + k) if result is not None: h_part[int(result[k])].append(coeff) continue raise ValueError( "'%s(%s + k)' expected, got '%s'" % (y.func, n, h)) for k in h_part: h_part[k] = Add(*h_part[k]) h_part.default_factory = lambda: 0 i_part = Add(*i_part) for k, coeff in h_part.items(): h_part[k] = simplify(coeff) common = S.One if not i_part.is_zero and not i_part.is_hypergeometric(n) and \ not (i_part.is_Add and all(map(lambda x: x.is_hypergeometric(n), i_part.expand().args))): raise ValueError("The independent term should be a sum of hypergeometric functions, got '%s'" % i_part) for coeff in h_part.values(): if coeff.is_rational_function(n): if not coeff.is_polynomial(n): common = lcm(common, coeff.as_numer_denom()[1], n) else: raise ValueError( "Polynomial or rational function expected, got '%s'" % coeff) i_numer, i_denom = i_part.as_numer_denom() if i_denom.is_polynomial(n): common = lcm(common, i_denom, n) if common is not S.One: for k, coeff in h_part.items(): numer, denom = coeff.as_numer_denom() h_part[k] = numer*quo(common, denom, n) i_part = i_numer*quo(common, i_denom, n) K_min = min(h_part.keys()) if K_min < 0: K = abs(K_min) H_part = defaultdict(lambda: S.Zero) i_part = i_part.subs(n, n + K).expand() common = common.subs(n, n + K).expand() for k, coeff in h_part.items(): H_part[k + K] = coeff.subs(n, n + K).expand() else: H_part = h_part K_max = max(H_part.keys()) coeffs = [H_part[i] for i in range(K_max + 1)] result = rsolve_hyper(coeffs, -i_part, n, symbols=True) if result is None: return None solution, symbols = result if init == {} or init == []: init = None if symbols and init is not None: if isinstance(init, list): init = {i: init[i] for i in range(len(init))} equations = [] for k, v in init.items(): try: i = int(k) except TypeError: if k.is_Function and k.func == y.func: i = int(k.args[0]) else: raise ValueError("Integer or term expected, got '%s'" % k) eq = solution.subs(n, i) - v if eq.has(S.NaN): eq = solution.limit(n, i) - v equations.append(eq) result = solve(equations, *symbols) if not result: return None else: solution = solution.subs(result) return solution sympy-sympy-1.9/sympy/solvers/solvers.py000066400000000000000000003766341412543434000206730ustar00rootroot00000000000000""" This module contain solvers for all kinds of equations: - algebraic or transcendental, use solve() - recurrence, use rsolve() - differential, use dsolve() - nonlinear (numerically), use nsolve() (you will need a good starting point) """ from sympy import divisors, binomial, expand_func from sympy.core.assumptions import check_assumptions from sympy.core.compatibility import (iterable, is_sequence, ordered, default_sort_key) from sympy.core.sympify import sympify from sympy.core import (S, Add, Symbol, Equality, Dummy, Expr, Mul, Pow, Unequality) from sympy.core.exprtools import factor_terms from sympy.core.function import (expand_mul, expand_log, Derivative, AppliedUndef, UndefinedFunction, nfloat, Function, expand_power_exp, _mexpand, expand) from sympy.integrals.integrals import Integral from sympy.core.numbers import ilcm, Float, Rational from sympy.core.relational import Relational from sympy.core.logic import fuzzy_not from sympy.core.power import integer_log from sympy.logic.boolalg import And, Or, BooleanAtom from sympy.core.basic import preorder_traversal from sympy.functions import (log, exp, LambertW, cos, sin, tan, acos, asin, atan, Abs, re, im, arg, sqrt, atan2) from sympy.functions.elementary.trigonometric import (TrigonometricFunction, HyperbolicFunction) from sympy.simplify import (simplify, collect, powsimp, posify, # type: ignore powdenest, nsimplify, denom, logcombine, sqrtdenest, fraction, separatevars) from sympy.simplify.sqrtdenest import sqrt_depth from sympy.simplify.fu import TR1, TR2i from sympy.matrices.common import NonInvertibleMatrixError from sympy.matrices import Matrix, zeros from sympy.polys import roots, cancel, factor, Poly from sympy.polys.polyerrors import GeneratorsNeeded, PolynomialError from sympy.polys.solvers import sympy_eqs_to_ring, solve_lin_sys from sympy.functions.elementary.piecewise import piecewise_fold, Piecewise from sympy.utilities.lambdify import lambdify from sympy.utilities.misc import filldedent from sympy.utilities.iterables import (cartes, connected_components, generate_bell, uniq) from sympy.utilities.decorator import conserve_mpmath_dps from mpmath import findroot from sympy.solvers.polysys import solve_poly_system from sympy.solvers.inequalities import reduce_inequalities from types import GeneratorType from collections import defaultdict import warnings def recast_to_symbols(eqs, symbols): """ Return (e, s, d) where e and s are versions of *eqs* and *symbols* in which any non-Symbol objects in *symbols* have been replaced with generic Dummy symbols and d is a dictionary that can be used to restore the original expressions. Examples ======== >>> from sympy.solvers.solvers import recast_to_symbols >>> from sympy import symbols, Function >>> x, y = symbols('x y') >>> fx = Function('f')(x) >>> eqs, syms = [fx + 1, x, y], [fx, y] >>> e, s, d = recast_to_symbols(eqs, syms); (e, s, d) ([_X0 + 1, x, y], [_X0, y], {_X0: f(x)}) The original equations and symbols can be restored using d: >>> assert [i.xreplace(d) for i in eqs] == eqs >>> assert [d.get(i, i) for i in s] == syms """ if not iterable(eqs) and iterable(symbols): raise ValueError('Both eqs and symbols must be iterable') new_symbols = list(symbols) swap_sym = {} for i, s in enumerate(symbols): if not isinstance(s, Symbol) and s not in swap_sym: swap_sym[s] = Dummy('X%d' % i) new_symbols[i] = swap_sym[s] new_f = [] for i in eqs: isubs = getattr(i, 'subs', None) if isubs is not None: new_f.append(isubs(swap_sym)) else: new_f.append(i) swap_sym = {v: k for k, v in swap_sym.items()} return new_f, new_symbols, swap_sym def _ispow(e): """Return True if e is a Pow or is exp.""" return isinstance(e, Expr) and (e.is_Pow or isinstance(e, exp)) def _simple_dens(f, symbols): # when checking if a denominator is zero, we can just check the # base of powers with nonzero exponents since if the base is zero # the power will be zero, too. To keep it simple and fast, we # limit simplification to exponents that are Numbers dens = set() for d in denoms(f, symbols): if d.is_Pow and d.exp.is_Number: if d.exp.is_zero: continue # foo**0 is never 0 d = d.base dens.add(d) return dens def denoms(eq, *symbols): """ Return (recursively) set of all denominators that appear in *eq* that contain any symbol in *symbols*; if *symbols* are not provided then all denominators will be returned. Examples ======== >>> from sympy.solvers.solvers import denoms >>> from sympy.abc import x, y, z >>> denoms(x/y) {y} >>> denoms(x/(y*z)) {y, z} >>> denoms(3/x + y/z) {x, z} >>> denoms(x/2 + y/z) {2, z} If *symbols* are provided then only denominators containing those symbols will be returned: >>> denoms(1/x + 1/y + 1/z, y, z) {y, z} """ pot = preorder_traversal(eq) dens = set() for p in pot: # Here p might be Tuple or Relational # Expr subtrees (e.g. lhs and rhs) will be traversed after by pot if not isinstance(p, Expr): continue den = denom(p) if den is S.One: continue for d in Mul.make_args(den): dens.add(d) if not symbols: return dens elif len(symbols) == 1: if iterable(symbols[0]): symbols = symbols[0] rv = [] for d in dens: free = d.free_symbols if any(s in free for s in symbols): rv.append(d) return set(rv) def checksol(f, symbol, sol=None, **flags): """ Checks whether sol is a solution of equation f == 0. Explanation =========== Input can be either a single symbol and corresponding value or a dictionary of symbols and values. When given as a dictionary and flag ``simplify=True``, the values in the dictionary will be simplified. *f* can be a single equation or an iterable of equations. A solution must satisfy all equations in *f* to be considered valid; if a solution does not satisfy any equation, False is returned; if one or more checks are inconclusive (and none are False) then None is returned. Examples ======== >>> from sympy import symbols >>> from sympy.solvers import checksol >>> x, y = symbols('x,y') >>> checksol(x**4 - 1, x, 1) True >>> checksol(x**4 - 1, x, 0) False >>> checksol(x**2 + y**2 - 5**2, {x: 3, y: 4}) True To check if an expression is zero using ``checksol()``, pass it as *f* and send an empty dictionary for *symbol*: >>> checksol(x**2 + x - x*(x + 1), {}) True None is returned if ``checksol()`` could not conclude. flags: 'numerical=True (default)' do a fast numerical check if ``f`` has only one symbol. 'minimal=True (default is False)' a very fast, minimal testing. 'warn=True (default is False)' show a warning if checksol() could not conclude. 'simplify=True (default)' simplify solution before substituting into function and simplify the function before trying specific simplifications 'force=True (default is False)' make positive all symbols without assumptions regarding sign. """ from sympy.physics.units import Unit minimal = flags.get('minimal', False) if sol is not None: sol = {symbol: sol} elif isinstance(symbol, dict): sol = symbol else: msg = 'Expecting (sym, val) or ({sym: val}, None) but got (%s, %s)' raise ValueError(msg % (symbol, sol)) if iterable(f): if not f: raise ValueError('no functions to check') rv = True for fi in f: check = checksol(fi, sol, **flags) if check: continue if check is False: return False rv = None # don't return, wait to see if there's a False return rv if isinstance(f, Poly): f = f.as_expr() elif isinstance(f, (Equality, Unequality)): if f.rhs in (S.true, S.false): f = f.reversed B, E = f.args if isinstance(B, BooleanAtom): f = f.subs(sol) if not f.is_Boolean: return else: f = f.rewrite(Add, evaluate=False) if isinstance(f, BooleanAtom): return bool(f) elif not f.is_Relational and not f: return True if sol and not f.free_symbols & set(sol.keys()): # if f(y) == 0, x=3 does not set f(y) to zero...nor does it not return None illegal = {S.NaN, S.ComplexInfinity, S.Infinity, S.NegativeInfinity} if any(sympify(v).atoms() & illegal for k, v in sol.items()): return False was = f attempt = -1 numerical = flags.get('numerical', True) while 1: attempt += 1 if attempt == 0: val = f.subs(sol) if isinstance(val, Mul): val = val.as_independent(Unit)[0] if val.atoms() & illegal: return False elif attempt == 1: if not val.is_number: if not val.is_constant(*list(sol.keys()), simplify=not minimal): return False # there are free symbols -- simple expansion might work _, val = val.as_content_primitive() val = _mexpand(val.as_numer_denom()[0], recursive=True) elif attempt == 2: if minimal: return if flags.get('simplify', True): for k in sol: sol[k] = simplify(sol[k]) # start over without the failed expanded form, possibly # with a simplified solution val = simplify(f.subs(sol)) if flags.get('force', True): val, reps = posify(val) # expansion may work now, so try again and check exval = _mexpand(val, recursive=True) if exval.is_number: # we can decide now val = exval else: # if there are no radicals and no functions then this can't be # zero anymore -- can it? pot = preorder_traversal(expand_mul(val)) seen = set() saw_pow_func = False for p in pot: if p in seen: continue seen.add(p) if p.is_Pow and not p.exp.is_Integer: saw_pow_func = True elif p.is_Function: saw_pow_func = True elif isinstance(p, UndefinedFunction): saw_pow_func = True if saw_pow_func: break if saw_pow_func is False: return False if flags.get('force', True): # don't do a zero check with the positive assumptions in place val = val.subs(reps) nz = fuzzy_not(val.is_zero) if nz is not None: # issue 5673: nz may be True even when False # so these are just hacks to keep a false positive # from being returned # HACK 1: LambertW (issue 5673) if val.is_number and val.has(LambertW): # don't eval this to verify solution since if we got here, # numerical must be False return None # add other HACKs here if necessary, otherwise we assume # the nz value is correct return not nz break if val == was: continue elif val.is_Rational: return val == 0 if numerical and val.is_number: return (abs(val.n(18).n(12, chop=True)) < 1e-9) is S.true was = val if flags.get('warn', False): warnings.warn("\n\tWarning: could not verify solution %s." % sol) # returns None if it can't conclude # TODO: improve solution testing def solve(f, *symbols, **flags): r""" Algebraically solves equations and systems of equations. Explanation =========== Currently supported: - polynomial - transcendental - piecewise combinations of the above - systems of linear and polynomial equations - systems containing relational expressions Examples ======== The output varies according to the input and can be seen by example: >>> from sympy import solve, Poly, Eq, Function, exp >>> from sympy.abc import x, y, z, a, b >>> f = Function('f') Boolean or univariate Relational: >>> solve(x < 3) (-oo < x) & (x < 3) To always get a list of solution mappings, use flag dict=True: >>> solve(x - 3, dict=True) [{x: 3}] >>> sol = solve([x - 3, y - 1], dict=True) >>> sol [{x: 3, y: 1}] >>> sol[0][x] 3 >>> sol[0][y] 1 To get a list of *symbols* and set of solution(s) use flag set=True: >>> solve([x**2 - 3, y - 1], set=True) ([x, y], {(-sqrt(3), 1), (sqrt(3), 1)}) Single expression and single symbol that is in the expression: >>> solve(x - y, x) [y] >>> solve(x - 3, x) [3] >>> solve(Eq(x, 3), x) [3] >>> solve(Poly(x - 3), x) [3] >>> solve(x**2 - y**2, x, set=True) ([x], {(-y,), (y,)}) >>> solve(x**4 - 1, x, set=True) ([x], {(-1,), (1,), (-I,), (I,)}) Single expression with no symbol that is in the expression: >>> solve(3, x) [] >>> solve(x - 3, y) [] Single expression with no symbol given. In this case, all free *symbols* will be selected as potential *symbols* to solve for. If the equation is univariate then a list of solutions is returned; otherwise - as is the case when *symbols* are given as an iterable of length greater than 1 - a list of mappings will be returned: >>> solve(x - 3) [3] >>> solve(x**2 - y**2) [{x: -y}, {x: y}] >>> solve(z**2*x**2 - z**2*y**2) [{x: -y}, {x: y}, {z: 0}] >>> solve(z**2*x - z**2*y**2) [{x: y**2}, {z: 0}] When an object other than a Symbol is given as a symbol, it is isolated algebraically and an implicit solution may be obtained. This is mostly provided as a convenience to save you from replacing the object with a Symbol and solving for that Symbol. It will only work if the specified object can be replaced with a Symbol using the subs method: >>> solve(f(x) - x, f(x)) [x] >>> solve(f(x).diff(x) - f(x) - x, f(x).diff(x)) [x + f(x)] >>> solve(f(x).diff(x) - f(x) - x, f(x)) [-x + Derivative(f(x), x)] >>> solve(x + exp(x)**2, exp(x), set=True) ([exp(x)], {(-sqrt(-x),), (sqrt(-x),)}) >>> from sympy import Indexed, IndexedBase, Tuple, sqrt >>> A = IndexedBase('A') >>> eqs = Tuple(A[1] + A[2] - 3, A[1] - A[2] + 1) >>> solve(eqs, eqs.atoms(Indexed)) {A[1]: 1, A[2]: 2} * To solve for a symbol implicitly, use implicit=True: >>> solve(x + exp(x), x) [-LambertW(1)] >>> solve(x + exp(x), x, implicit=True) [-exp(x)] * It is possible to solve for anything that can be targeted with subs: >>> solve(x + 2 + sqrt(3), x + 2) [-sqrt(3)] >>> solve((x + 2 + sqrt(3), x + 4 + y), y, x + 2) {y: -2 + sqrt(3), x + 2: -sqrt(3)} * Nothing heroic is done in this implicit solving so you may end up with a symbol still in the solution: >>> eqs = (x*y + 3*y + sqrt(3), x + 4 + y) >>> solve(eqs, y, x + 2) {y: -sqrt(3)/(x + 3), x + 2: -2*x/(x + 3) - 6/(x + 3) + sqrt(3)/(x + 3)} >>> solve(eqs, y*x, x) {x: -y - 4, x*y: -3*y - sqrt(3)} * If you attempt to solve for a number remember that the number you have obtained does not necessarily mean that the value is equivalent to the expression obtained: >>> solve(sqrt(2) - 1, 1) [sqrt(2)] >>> solve(x - y + 1, 1) # /!\ -1 is targeted, too [x/(y - 1)] >>> [_.subs(z, -1) for _ in solve((x - y + 1).subs(-1, z), 1)] [-x + y] * To solve for a function within a derivative, use ``dsolve``. Single expression and more than one symbol: * When there is a linear solution: >>> solve(x - y**2, x, y) [(y**2, y)] >>> solve(x**2 - y, x, y) [(x, x**2)] >>> solve(x**2 - y, x, y, dict=True) [{y: x**2}] * When undetermined coefficients are identified: * That are linear: >>> solve((a + b)*x - b + 2, a, b) {a: -2, b: 2} * That are nonlinear: >>> solve((a + b)*x - b**2 + 2, a, b, set=True) ([a, b], {(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))}) * If there is no linear solution, then the first successful attempt for a nonlinear solution will be returned: >>> solve(x**2 - y**2, x, y, dict=True) [{x: -y}, {x: y}] >>> solve(x**2 - y**2/exp(x), x, y, dict=True) [{x: 2*LambertW(-y/2)}, {x: 2*LambertW(y/2)}] >>> solve(x**2 - y**2/exp(x), y, x) [(-x*sqrt(exp(x)), x), (x*sqrt(exp(x)), x)] Iterable of one or more of the above: * Involving relationals or bools: >>> solve([x < 3, x - 2]) Eq(x, 2) >>> solve([x > 3, x - 2]) False * When the system is linear: * With a solution: >>> solve([x - 3], x) {x: 3} >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y) {x: -3, y: 1} >>> solve((x + 5*y - 2, -3*x + 6*y - 15), x, y, z) {x: -3, y: 1} >>> solve((x + 5*y - 2, -3*x + 6*y - z), z, x, y) {x: 2 - 5*y, z: 21*y - 6} * Without a solution: >>> solve([x + 3, x - 3]) [] * When the system is not linear: >>> solve([x**2 + y -2, y**2 - 4], x, y, set=True) ([x, y], {(-2, -2), (0, 2), (2, -2)}) * If no *symbols* are given, all free *symbols* will be selected and a list of mappings returned: >>> solve([x - 2, x**2 + y]) [{x: 2, y: -4}] >>> solve([x - 2, x**2 + f(x)], {f(x), x}) [{x: 2, f(x): -4}] * If any equation does not depend on the symbol(s) given, it will be eliminated from the equation set and an answer may be given implicitly in terms of variables that were not of interest: >>> solve([x - y, y - 3], x) {x: y} **Additional Examples** ``solve()`` with check=True (default) will run through the symbol tags to elimate unwanted solutions. If no assumptions are included, all possible solutions will be returned: >>> from sympy import Symbol, solve >>> x = Symbol("x") >>> solve(x**2 - 1) [-1, 1] By using the positive tag, only one solution will be returned: >>> pos = Symbol("pos", positive=True) >>> solve(pos**2 - 1) [1] Assumptions are not checked when ``solve()`` input involves relationals or bools. When the solutions are checked, those that make any denominator zero are automatically excluded. If you do not want to exclude such solutions, then use the check=False option: >>> from sympy import sin, limit >>> solve(sin(x)/x) # 0 is excluded [pi] If check=False, then a solution to the numerator being zero is found: x = 0. In this case, this is a spurious solution since $\sin(x)/x$ has the well known limit (without dicontinuity) of 1 at x = 0: >>> solve(sin(x)/x, check=False) [0, pi] In the following case, however, the limit exists and is equal to the value of x = 0 that is excluded when check=True: >>> eq = x**2*(1/x - z**2/x) >>> solve(eq, x) [] >>> solve(eq, x, check=False) [0] >>> limit(eq, x, 0, '-') 0 >>> limit(eq, x, 0, '+') 0 **Disabling High-Order Explicit Solutions** When solving polynomial expressions, you might not want explicit solutions (which can be quite long). If the expression is univariate, ``CRootOf`` instances will be returned instead: >>> solve(x**3 - x + 1) [-1/((-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)) - (-1/2 - sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3, -(-1/2 + sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)/3 - 1/((-1/2 + sqrt(3)*I/2)*(3*sqrt(69)/2 + 27/2)**(1/3)), -(3*sqrt(69)/2 + 27/2)**(1/3)/3 - 1/(3*sqrt(69)/2 + 27/2)**(1/3)] >>> solve(x**3 - x + 1, cubics=False) [CRootOf(x**3 - x + 1, 0), CRootOf(x**3 - x + 1, 1), CRootOf(x**3 - x + 1, 2)] If the expression is multivariate, no solution might be returned: >>> solve(x**3 - x + a, x, cubics=False) [] Sometimes solutions will be obtained even when a flag is False because the expression could be factored. In the following example, the equation can be factored as the product of a linear and a quadratic factor so explicit solutions (which did not require solving a cubic expression) are obtained: >>> eq = x**3 + 3*x**2 + x - 1 >>> solve(eq, cubics=False) [-1, -1 + sqrt(2), -sqrt(2) - 1] **Solving Equations Involving Radicals** Because of SymPy's use of the principle root, some solutions to radical equations will be missed unless check=False: >>> from sympy import root >>> eq = root(x**3 - 3*x**2, 3) + 1 - x >>> solve(eq) [] >>> solve(eq, check=False) [1/3] In the above example, there is only a single solution to the equation. Other expressions will yield spurious roots which must be checked manually; roots which give a negative argument to odd-powered radicals will also need special checking: >>> from sympy import real_root, S >>> eq = root(x, 3) - root(x, 5) + S(1)/7 >>> solve(eq) # this gives 2 solutions but misses a 3rd [CRootOf(7*x**5 - 7*x**3 + 1, 1)**15, CRootOf(7*x**5 - 7*x**3 + 1, 2)**15] >>> sol = solve(eq, check=False) >>> [abs(eq.subs(x,i).n(2)) for i in sol] [0.48, 0.e-110, 0.e-110, 0.052, 0.052] The first solution is negative so ``real_root`` must be used to see that it satisfies the expression: >>> abs(real_root(eq.subs(x, sol[0])).n(2)) 0.e-110 If the roots of the equation are not real then more care will be necessary to find the roots, especially for higher order equations. Consider the following expression: >>> expr = root(x, 3) - root(x, 5) We will construct a known value for this expression at x = 3 by selecting the 1-th root for each radical: >>> expr1 = root(x, 3, 1) - root(x, 5, 1) >>> v = expr1.subs(x, -3) The ``solve`` function is unable to find any exact roots to this equation: >>> eq = Eq(expr, v); eq1 = Eq(expr1, v) >>> solve(eq, check=False), solve(eq1, check=False) ([], []) The function ``unrad``, however, can be used to get a form of the equation for which numerical roots can be found: >>> from sympy.solvers.solvers import unrad >>> from sympy import nroots >>> e, (p, cov) = unrad(eq) >>> pvals = nroots(e) >>> inversion = solve(cov, x)[0] >>> xvals = [inversion.subs(p, i) for i in pvals] Although ``eq`` or ``eq1`` could have been used to find ``xvals``, the solution can only be verified with ``expr1``: >>> z = expr - v >>> [xi.n(chop=1e-9) for xi in xvals if abs(z.subs(x, xi).n()) < 1e-9] [] >>> z1 = expr1 - v >>> [xi.n(chop=1e-9) for xi in xvals if abs(z1.subs(x, xi).n()) < 1e-9] [-3.0] Parameters ========== f : - a single Expr or Poly that must be zero - an Equality - a Relational expression - a Boolean - iterable of one or more of the above symbols : (object(s) to solve for) specified as - none given (other non-numeric objects will be used) - single symbol - denested list of symbols (e.g., ``solve(f, x, y)``) - ordered iterable of symbols (e.g., ``solve(f, [x, y])``) flags : dict=True (default is False) Return list (perhaps empty) of solution mappings. set=True (default is False) Return list of symbols and set of tuple(s) of solution(s). exclude=[] (default) Do not try to solve for any of the free symbols in exclude; if expressions are given, the free symbols in them will be extracted automatically. check=True (default) If False, do not do any testing of solutions. This can be useful if you want to include solutions that make any denominator zero. numerical=True (default) Do a fast numerical check if *f* has only one symbol. minimal=True (default is False) A very fast, minimal testing. warn=True (default is False) Show a warning if ``checksol()`` could not conclude. simplify=True (default) Simplify all but polynomials of order 3 or greater before returning them and (if check is not False) use the general simplify function on the solutions and the expression obtained when they are substituted into the function which should be zero. force=True (default is False) Make positive all symbols without assumptions regarding sign. rational=True (default) Recast Floats as Rational; if this option is not used, the system containing Floats may fail to solve because of issues with polys. If rational=None, Floats will be recast as rationals but the answer will be recast as Floats. If the flag is False then nothing will be done to the Floats. manual=True (default is False) Do not use the polys/matrix method to solve a system of equations, solve them one at a time as you might "manually." implicit=True (default is False) Allows ``solve`` to return a solution for a pattern in terms of other functions that contain that pattern; this is only needed if the pattern is inside of some invertible function like cos, exp, ect. particular=True (default is False) Instructs ``solve`` to try to find a particular solution to a linear system with as many zeros as possible; this is very expensive. quick=True (default is False) When using particular=True, use a fast heuristic to find a solution with many zeros (instead of using the very slow method guaranteed to find the largest number of zeros possible). cubics=True (default) Return explicit solutions when cubic expressions are encountered. quartics=True (default) Return explicit solutions when quartic expressions are encountered. quintics=True (default) Return explicit solutions (if possible) when quintic expressions are encountered. See Also ======== rsolve: For solving recurrence relationships dsolve: For solving differential equations """ # keeping track of how f was passed since if it is a list # a dictionary of results will be returned. ########################################################################### def _sympified_list(w): return list(map(sympify, w if iterable(w) else [w])) bare_f = not iterable(f) ordered_symbols = (symbols and symbols[0] and (isinstance(symbols[0], Symbol) or is_sequence(symbols[0], include=GeneratorType) ) ) f, symbols = (_sympified_list(w) for w in [f, symbols]) if isinstance(f, list): f = [s for s in f if s is not S.true and s is not True] implicit = flags.get('implicit', False) # preprocess symbol(s) ########################################################################### if not symbols: # get symbols from equations symbols = set().union(*[fi.free_symbols for fi in f]) if len(symbols) < len(f): for fi in f: pot = preorder_traversal(fi) for p in pot: if isinstance(p, AppliedUndef): flags['dict'] = True # better show symbols symbols.add(p) pot.skip() # don't go any deeper symbols = list(symbols) ordered_symbols = False elif len(symbols) == 1 and iterable(symbols[0]): symbols = symbols[0] # remove symbols the user is not interested in exclude = flags.pop('exclude', set()) if exclude: if isinstance(exclude, Expr): exclude = [exclude] exclude = set().union(*[e.free_symbols for e in sympify(exclude)]) symbols = [s for s in symbols if s not in exclude] # preprocess equation(s) ########################################################################### for i, fi in enumerate(f): if isinstance(fi, (Equality, Unequality)): if 'ImmutableDenseMatrix' in [type(a).__name__ for a in fi.args]: fi = fi.lhs - fi.rhs else: L, R = fi.args if isinstance(R, BooleanAtom): L, R = R, L if isinstance(L, BooleanAtom): if isinstance(fi, Unequality): L = ~L if R.is_Relational: fi = ~R if L is S.false else R elif R.is_Symbol: return L elif R.is_Boolean and (~R).is_Symbol: return ~L else: raise NotImplementedError(filldedent(''' Unanticipated argument of Eq when other arg is True or False. ''')) else: fi = fi.rewrite(Add, evaluate=False) f[i] = fi if fi.is_Relational: return reduce_inequalities(f, symbols=symbols) if isinstance(fi, Poly): f[i] = fi.as_expr() # rewrite hyperbolics in terms of exp f[i] = f[i].replace(lambda w: isinstance(w, HyperbolicFunction) and \ (len(w.free_symbols & set(symbols)) > 0), lambda w: w.rewrite(exp)) # if we have a Matrix, we need to iterate over its elements again if f[i].is_Matrix: bare_f = False f.extend(list(f[i])) f[i] = S.Zero # if we can split it into real and imaginary parts then do so freei = f[i].free_symbols if freei and all(s.is_extended_real or s.is_imaginary for s in freei): fr, fi = f[i].as_real_imag() # accept as long as new re, im, arg or atan2 are not introduced had = f[i].atoms(re, im, arg, atan2) if fr and fi and fr != fi and not any( i.atoms(re, im, arg, atan2) - had for i in (fr, fi)): if bare_f: bare_f = False f[i: i + 1] = [fr, fi] # real/imag handling ----------------------------- if any(isinstance(fi, (bool, BooleanAtom)) for fi in f): if flags.get('set', False): return [], set() return [] for i, fi in enumerate(f): # Abs while True: was = fi fi = fi.replace(Abs, lambda arg: separatevars(Abs(arg)).rewrite(Piecewise) if arg.has(*symbols) else Abs(arg)) if was == fi: break for e in fi.find(Abs): if e.has(*symbols): raise NotImplementedError('solving %s when the argument ' 'is not real or imaginary.' % e) # arg fi = fi.replace(arg, lambda a: arg(a).rewrite(atan2).rewrite(atan)) # save changes f[i] = fi # see if re(s) or im(s) appear freim = [fi for fi in f if fi.has(re, im)] if freim: irf = [] for s in symbols: if s.is_real or s.is_imaginary: continue # neither re(x) nor im(x) will appear # if re(s) or im(s) appear, the auxiliary equation must be present if any(fi.has(re(s), im(s)) for fi in freim): irf.append((s, re(s) + S.ImaginaryUnit*im(s))) if irf: for s, rhs in irf: for i, fi in enumerate(f): f[i] = fi.xreplace({s: rhs}) f.append(s - rhs) symbols.extend([re(s), im(s)]) if bare_f: bare_f = False flags['dict'] = True # end of real/imag handling ----------------------------- symbols = list(uniq(symbols)) if not ordered_symbols: # we do this to make the results returned canonical in case f # contains a system of nonlinear equations; all other cases should # be unambiguous symbols = sorted(symbols, key=default_sort_key) # we can solve for non-symbol entities by replacing them with Dummy symbols f, symbols, swap_sym = recast_to_symbols(f, symbols) # this is needed in the next two events symset = set(symbols) # get rid of equations that have no symbols of interest; we don't # try to solve them because the user didn't ask and they might be # hard to solve; this means that solutions may be given in terms # of the eliminated equations e.g. solve((x-y, y-3), x) -> {x: y} newf = [] for fi in f: # let the solver handle equations that.. # - have no symbols but are expressions # - have symbols of interest # - have no symbols of interest but are constant # but when an expression is not constant and has no symbols of # interest, it can't change what we obtain for a solution from # the remaining equations so we don't include it; and if it's # zero it can be removed and if it's not zero, there is no # solution for the equation set as a whole # # The reason for doing this filtering is to allow an answer # to be obtained to queries like solve((x - y, y), x); without # this mod the return value is [] ok = False if fi.free_symbols & symset: ok = True else: if fi.is_number: if fi.is_Number: if fi.is_zero: continue return [] ok = True else: if fi.is_constant(): ok = True if ok: newf.append(fi) if not newf: return [] f = newf del newf # mask off any Object that we aren't going to invert: Derivative, # Integral, etc... so that solving for anything that they contain will # give an implicit solution seen = set() non_inverts = set() for fi in f: pot = preorder_traversal(fi) for p in pot: if not isinstance(p, Expr) or isinstance(p, Piecewise): pass elif (isinstance(p, bool) or not p.args or p in symset or p.is_Add or p.is_Mul or p.is_Pow and not implicit or p.is_Function and not implicit) and p.func not in (re, im): continue elif not p in seen: seen.add(p) if p.free_symbols & symset: non_inverts.add(p) else: continue pot.skip() del seen non_inverts = dict(list(zip(non_inverts, [Dummy() for _ in non_inverts]))) f = [fi.subs(non_inverts) for fi in f] # Both xreplace and subs are needed below: xreplace to force substitution # inside Derivative, subs to handle non-straightforward substitutions non_inverts = [(v, k.xreplace(swap_sym).subs(swap_sym)) for k, v in non_inverts.items()] # rationalize Floats floats = False if flags.get('rational', True) is not False: for i, fi in enumerate(f): if fi.has(Float): floats = True f[i] = nsimplify(fi, rational=True) # capture any denominators before rewriting since # they may disappear after the rewrite, e.g. issue 14779 flags['_denominators'] = _simple_dens(f[0], symbols) # Any embedded piecewise functions need to be brought out to the # top level so that the appropriate strategy gets selected. # However, this is necessary only if one of the piecewise # functions depends on one of the symbols we are solving for. def _has_piecewise(e): if e.is_Piecewise: return e.has(*symbols) return any([_has_piecewise(a) for a in e.args]) for i, fi in enumerate(f): if _has_piecewise(fi): f[i] = piecewise_fold(fi) # # try to get a solution ########################################################################### if bare_f: solution = _solve(f[0], *symbols, **flags) else: solution = _solve_system(f, symbols, **flags) # # postprocessing ########################################################################### # Restore masked-off objects if non_inverts: def _do_dict(solution): return {k: v.subs(non_inverts) for k, v in solution.items()} for i in range(1): if isinstance(solution, dict): solution = _do_dict(solution) break elif solution and isinstance(solution, list): if isinstance(solution[0], dict): solution = [_do_dict(s) for s in solution] break elif isinstance(solution[0], tuple): solution = [tuple([v.subs(non_inverts) for v in s]) for s in solution] break else: solution = [v.subs(non_inverts) for v in solution] break elif not solution: break else: raise NotImplementedError(filldedent(''' no handling of %s was implemented''' % solution)) # Restore original "symbols" if a dictionary is returned. # This is not necessary for # - the single univariate equation case # since the symbol will have been removed from the solution; # - the nonlinear poly_system since that only supports zero-dimensional # systems and those results come back as a list # # ** unless there were Derivatives with the symbols, but those were handled # above. if swap_sym: symbols = [swap_sym.get(k, k) for k in symbols] if isinstance(solution, dict): solution = {swap_sym.get(k, k): v.subs(swap_sym) for k, v in solution.items()} elif solution and isinstance(solution, list) and isinstance(solution[0], dict): for i, sol in enumerate(solution): solution[i] = {swap_sym.get(k, k): v.subs(swap_sym) for k, v in sol.items()} # undo the dictionary solutions returned when the system was only partially # solved with poly-system if all symbols are present if ( not flags.get('dict', False) and solution and ordered_symbols and not isinstance(solution, dict) and all(isinstance(sol, dict) for sol in solution) ): solution = [tuple([r.get(s, s) for s in symbols]) for r in solution] # Get assumptions about symbols, to filter solutions. # Note that if assumptions about a solution can't be verified, it is still # returned. check = flags.get('check', True) # restore floats if floats and solution and flags.get('rational', None) is None: solution = nfloat(solution, exponent=False) if check and solution: # assumption checking warn = flags.get('warn', False) got_None = [] # solutions for which one or more symbols gave None no_False = [] # solutions for which no symbols gave False if isinstance(solution, tuple): # this has already been checked and is in as_set form return solution elif isinstance(solution, list): if isinstance(solution[0], tuple): for sol in solution: for symb, val in zip(symbols, sol): test = check_assumptions(val, **symb.assumptions0) if test is False: break if test is None: got_None.append(sol) else: no_False.append(sol) elif isinstance(solution[0], dict): for sol in solution: a_None = False for symb, val in sol.items(): test = check_assumptions(val, **symb.assumptions0) if test: continue if test is False: break a_None = True else: no_False.append(sol) if a_None: got_None.append(sol) else: # list of expressions for sol in solution: test = check_assumptions(sol, **symbols[0].assumptions0) if test is False: continue no_False.append(sol) if test is None: got_None.append(sol) elif isinstance(solution, dict): a_None = False for symb, val in solution.items(): test = check_assumptions(val, **symb.assumptions0) if test: continue if test is False: no_False = None break a_None = True else: no_False = solution if a_None: got_None.append(solution) elif isinstance(solution, (Relational, And, Or)): if len(symbols) != 1: raise ValueError("Length should be 1") if warn and symbols[0].assumptions0: warnings.warn(filldedent(""" \tWarning: assumptions about variable '%s' are not handled currently.""" % symbols[0])) # TODO: check also variable assumptions for inequalities else: raise TypeError('Unrecognized solution') # improve the checker solution = no_False if warn and got_None: warnings.warn(filldedent(""" \tWarning: assumptions concerning following solution(s) can't be checked:""" + '\n\t' + ', '.join(str(s) for s in got_None))) # # done ########################################################################### as_dict = flags.get('dict', False) as_set = flags.get('set', False) if not as_set and isinstance(solution, list): # Make sure that a list of solutions is ordered in a canonical way. solution.sort(key=default_sort_key) if not as_dict and not as_set: return solution or [] # return a list of mappings or [] if not solution: solution = [] else: if isinstance(solution, dict): solution = [solution] elif iterable(solution[0]): solution = [dict(list(zip(symbols, s))) for s in solution] elif isinstance(solution[0], dict): pass else: if len(symbols) != 1: raise ValueError("Length should be 1") solution = [{symbols[0]: s} for s in solution] if as_dict: return solution assert as_set if not solution: return [], set() k = list(ordered(solution[0].keys())) return k, {tuple([s[ki] for ki in k]) for s in solution} def _solve(f, *symbols, **flags): """ Return a checked solution for *f* in terms of one or more of the symbols. A list should be returned except for the case when a linear undetermined-coefficients equation is encountered (in which case a dictionary is returned). If no method is implemented to solve the equation, a NotImplementedError will be raised. In the case that conversion of an expression to a Poly gives None a ValueError will be raised. """ not_impl_msg = "No algorithms are implemented to solve equation %s" if len(symbols) != 1: soln = None free = f.free_symbols ex = free - set(symbols) if len(ex) != 1: ind, dep = f.as_independent(*symbols) ex = ind.free_symbols & dep.free_symbols if len(ex) == 1: ex = ex.pop() try: # soln may come back as dict, list of dicts or tuples, or # tuple of symbol list and set of solution tuples soln = solve_undetermined_coeffs(f, symbols, ex, **flags) except NotImplementedError: pass if soln: if flags.get('simplify', True): if isinstance(soln, dict): for k in soln: soln[k] = simplify(soln[k]) elif isinstance(soln, list): if isinstance(soln[0], dict): for d in soln: for k in d: d[k] = simplify(d[k]) elif isinstance(soln[0], tuple): soln = [tuple(simplify(i) for i in j) for j in soln] else: raise TypeError('unrecognized args in list') elif isinstance(soln, tuple): sym, sols = soln soln = sym, {tuple(simplify(i) for i in j) for j in sols} else: raise TypeError('unrecognized solution type') return soln # find first successful solution failed = [] got_s = set() result = [] for s in symbols: xi, v = solve_linear(f, symbols=[s]) if xi == s: # no need to check but we should simplify if desired if flags.get('simplify', True): v = simplify(v) vfree = v.free_symbols if got_s and any([ss in vfree for ss in got_s]): # sol depends on previously solved symbols: discard it continue got_s.add(xi) result.append({xi: v}) elif xi: # there might be a non-linear solution if xi is not 0 failed.append(s) if not failed: return result for s in failed: try: soln = _solve(f, s, **flags) for sol in soln: if got_s and any([ss in sol.free_symbols for ss in got_s]): # sol depends on previously solved symbols: discard it continue got_s.add(s) result.append({s: sol}) except NotImplementedError: continue if got_s: return result else: raise NotImplementedError(not_impl_msg % f) symbol = symbols[0] #expand binomials only if it has the unknown symbol f = f.replace(lambda e: isinstance(e, binomial) and e.has(symbol), lambda e: expand_func(e)) # /!\ capture this flag then set it to False so that no checking in # recursive calls will be done; only the final answer is checked flags['check'] = checkdens = check = flags.pop('check', True) # build up solutions if f is a Mul if f.is_Mul: result = set() for m in f.args: if m in {S.NegativeInfinity, S.ComplexInfinity, S.Infinity}: result = set() break soln = _solve(m, symbol, **flags) result.update(set(soln)) result = list(result) if check: # all solutions have been checked but now we must # check that the solutions do not set denominators # in any factor to zero dens = flags.get('_denominators', _simple_dens(f, symbols)) result = [s for s in result if all(not checksol(den, {symbol: s}, **flags) for den in dens)] # set flags for quick exit at end; solutions for each # factor were already checked and simplified check = False flags['simplify'] = False elif f.is_Piecewise: result = set() for i, (expr, cond) in enumerate(f.args): if expr.is_zero: raise NotImplementedError( 'solve cannot represent interval solutions') candidates = _solve(expr, symbol, **flags) # the explicit condition for this expr is the current cond # and none of the previous conditions args = [~c for _, c in f.args[:i]] + [cond] cond = And(*args) for candidate in candidates: if candidate in result: # an unconditional value was already there continue try: v = cond.subs(symbol, candidate) _eval_simplify = getattr(v, '_eval_simplify', None) if _eval_simplify is not None: # unconditionally take the simpification of v v = _eval_simplify(ratio=2, measure=lambda x: 1) except TypeError: # incompatible type with condition(s) continue if v == False: continue if v == True: result.add(candidate) else: result.add(Piecewise( (candidate, v), (S.NaN, True))) # set flags for quick exit at end; solutions for each # piece were already checked and simplified check = False flags['simplify'] = False else: # first see if it really depends on symbol and whether there # is only a linear solution f_num, sol = solve_linear(f, symbols=symbols) if f_num.is_zero or sol is S.NaN: return [] elif f_num.is_Symbol: # no need to check but simplify if desired if flags.get('simplify', True): sol = simplify(sol) return [sol] poly = None # check for a single Add generator if not f_num.is_Add: add_args = [i for i in f_num.atoms(Add) if symbol in i.free_symbols] if len(add_args) == 1: gen = add_args[0] spart = gen.as_independent(symbol)[1].as_base_exp()[0] if spart == symbol: try: poly = Poly(f_num, spart) except PolynomialError: pass result = False # no solution was obtained msg = '' # there is no failure message # Poly is generally robust enough to convert anything to # a polynomial and tell us the different generators that it # contains, so we will inspect the generators identified by # polys to figure out what to do. # try to identify a single generator that will allow us to solve this # as a polynomial, followed (perhaps) by a change of variables if the # generator is not a symbol try: if poly is None: poly = Poly(f_num) if poly is None: raise ValueError('could not convert %s to Poly' % f_num) except GeneratorsNeeded: simplified_f = simplify(f_num) if simplified_f != f_num: return _solve(simplified_f, symbol, **flags) raise ValueError('expression appears to be a constant') gens = [g for g in poly.gens if g.has(symbol)] def _as_base_q(x): """Return (b**e, q) for x = b**(p*e/q) where p/q is the leading Rational of the exponent of x, e.g. exp(-2*x/3) -> (exp(x), 3) """ b, e = x.as_base_exp() if e.is_Rational: return b, e.q if not e.is_Mul: return x, 1 c, ee = e.as_coeff_Mul() if c.is_Rational and c is not S.One: # c could be a Float return b**ee, c.q return x, 1 if len(gens) > 1: # If there is more than one generator, it could be that the # generators have the same base but different powers, e.g. # >>> Poly(exp(x) + 1/exp(x)) # Poly(exp(-x) + exp(x), exp(-x), exp(x), domain='ZZ') # # If unrad was not disabled then there should be no rational # exponents appearing as in # >>> Poly(sqrt(x) + sqrt(sqrt(x))) # Poly(sqrt(x) + x**(1/4), sqrt(x), x**(1/4), domain='ZZ') bases, qs = list(zip(*[_as_base_q(g) for g in gens])) bases = set(bases) if len(bases) > 1 or not all(q == 1 for q in qs): funcs = {b for b in bases if b.is_Function} trig = {_ for _ in funcs if isinstance(_, TrigonometricFunction)} other = funcs - trig if not other and len(funcs.intersection(trig)) > 1: newf = None if f_num.is_Add and len(f_num.args) == 2: # check for sin(x)**p = cos(x)**p _args = f_num.args t = a, b = [i.atoms(Function).intersection( trig) for i in _args] if all(len(i) == 1 for i in t): a, b = [i.pop() for i in t] if isinstance(a, cos): a, b = b, a _args = _args[::-1] if isinstance(a, sin) and isinstance(b, cos ) and a.args[0] == b.args[0]: # sin(x) + cos(x) = 0 -> tan(x) + 1 = 0 newf, _d = (TR2i(_args[0]/_args[1]) + 1 ).as_numer_denom() if not _d.is_Number: newf = None if newf is None: newf = TR1(f_num).rewrite(tan) if newf != f_num: # don't check the rewritten form --check # solutions in the un-rewritten form below flags['check'] = False result = _solve(newf, symbol, **flags) flags['check'] = check # just a simple case - see if replacement of single function # clears all symbol-dependent functions, e.g. # log(x) - log(log(x) - 1) - 3 can be solved even though it has # two generators. if result is False and funcs: funcs = list(ordered(funcs)) # put shallowest function first f1 = funcs[0] t = Dummy('t') # perform the substitution ftry = f_num.subs(f1, t) # if no Functions left, we can proceed with usual solve if not ftry.has(symbol): cv_sols = _solve(ftry, t, **flags) cv_inv = _solve(t - f1, symbol, **flags)[0] sols = list() for sol in cv_sols: sols.append(cv_inv.subs(t, sol)) result = list(ordered(sols)) if result is False: msg = 'multiple generators %s' % gens else: # e.g. case where gens are exp(x), exp(-x) u = bases.pop() t = Dummy('t') inv = _solve(u - t, symbol, **flags) if isinstance(u, (Pow, exp)): # this will be resolved by factor in _tsolve but we might # as well try a simple expansion here to get things in # order so something like the following will work now without # having to factor: # # >>> eq = (exp(I*(-x-2))+exp(I*(x+2))) # >>> eq.subs(exp(x),y) # fails # exp(I*(-x - 2)) + exp(I*(x + 2)) # >>> eq.expand().subs(exp(x),y) # works # y**I*exp(2*I) + y**(-I)*exp(-2*I) def _expand(p): b, e = p.as_base_exp() e = expand_mul(e) return expand_power_exp(b**e) ftry = f_num.replace( lambda w: w.is_Pow or isinstance(w, exp), _expand).subs(u, t) if not ftry.has(symbol): soln = _solve(ftry, t, **flags) sols = list() for sol in soln: for i in inv: sols.append(i.subs(t, sol)) result = list(ordered(sols)) elif len(gens) == 1: # There is only one generator that we are interested in, but # there may have been more than one generator identified by # polys (e.g. for symbols other than the one we are interested # in) so recast the poly in terms of our generator of interest. # Also use composite=True with f_num since Poly won't update # poly as documented in issue 8810. poly = Poly(f_num, gens[0], composite=True) # if we aren't on the tsolve-pass, use roots if not flags.pop('tsolve', False): soln = None deg = poly.degree() flags['tsolve'] = True solvers = {k: flags.get(k, True) for k in ('cubics', 'quartics', 'quintics')} soln = roots(poly, **solvers) if sum(soln.values()) < deg: # e.g. roots(32*x**5 + 400*x**4 + 2032*x**3 + # 5000*x**2 + 6250*x + 3189) -> {} # so all_roots is used and RootOf instances are # returned *unless* the system is multivariate # or high-order EX domain. try: soln = poly.all_roots() except NotImplementedError: if not flags.get('incomplete', True): raise NotImplementedError( filldedent(''' Neither high-order multivariate polynomials nor sorting of EX-domain polynomials is supported. If you want to see any results, pass keyword incomplete=True to solve; to see numerical values of roots for univariate expressions, use nroots. ''')) else: pass else: soln = list(soln.keys()) if soln is not None: u = poly.gen if u != symbol: try: t = Dummy('t') iv = _solve(u - t, symbol, **flags) soln = list(ordered({i.subs(t, s) for i in iv for s in soln})) except NotImplementedError: # perhaps _tsolve can handle f_num soln = None else: check = False # only dens need to be checked if soln is not None: if len(soln) > 2: # if the flag wasn't set then unset it since high-order # results are quite long. Perhaps one could base this # decision on a certain critical length of the # roots. In addition, wester test M2 has an expression # whose roots can be shown to be real with the # unsimplified form of the solution whereas only one of # the simplified forms appears to be real. flags['simplify'] = flags.get('simplify', False) result = soln # fallback if above fails # ----------------------- if result is False: # try unrad if flags.pop('_unrad', True): try: u = unrad(f_num, symbol) except (ValueError, NotImplementedError): u = False if u: eq, cov = u if cov: isym, ieq = cov inv = _solve(ieq, symbol, **flags)[0] rv = {inv.subs(isym, xi) for xi in _solve(eq, isym, **flags)} else: try: rv = set(_solve(eq, symbol, **flags)) except NotImplementedError: rv = None if rv is not None: result = list(ordered(rv)) # if the flag wasn't set then unset it since unrad results # can be quite long or of very high order flags['simplify'] = flags.get('simplify', False) else: pass # for coverage # try _tsolve if result is False: flags.pop('tsolve', None) # allow tsolve to be used on next pass try: soln = _tsolve(f_num, symbol, **flags) if soln is not None: result = soln except PolynomialError: pass # ----------- end of fallback ---------------------------- if result is False: raise NotImplementedError('\n'.join([msg, not_impl_msg % f])) if flags.get('simplify', True): result = list(map(simplify, result)) # we just simplified the solution so we now set the flag to # False so the simplification doesn't happen again in checksol() flags['simplify'] = False if checkdens: # reject any result that makes any denom. affirmatively 0; # if in doubt, keep it dens = _simple_dens(f, symbols) result = [s for s in result if all(not checksol(d, {symbol: s}, **flags) for d in dens)] if check: # keep only results if the check is not False result = [r for r in result if checksol(f_num, {symbol: r}, **flags) is not False] return result def _solve_system(exprs, symbols, **flags): if not exprs: return [] if flags.pop('_split', True): # Split the system into connected components V = exprs symsset = set(symbols) exprsyms = {e: e.free_symbols & symsset for e in exprs} E = [] sym_indices = {sym: i for i, sym in enumerate(symbols)} for n, e1 in enumerate(exprs): for e2 in exprs[:n]: # Equations are connected if they share a symbol if exprsyms[e1] & exprsyms[e2]: E.append((e1, e2)) G = V, E subexprs = connected_components(G) if len(subexprs) > 1: subsols = [] for subexpr in subexprs: subsyms = set() for e in subexpr: subsyms |= exprsyms[e] subsyms = list(sorted(subsyms, key = lambda x: sym_indices[x])) flags['_split'] = False # skip split step subsol = _solve_system(subexpr, subsyms, **flags) if not isinstance(subsol, list): subsol = [subsol] subsols.append(subsol) # Full solution is cartesion product of subsystems sols = [] for soldicts in cartes(*subsols): sols.append(dict(item for sd in soldicts for item in sd.items())) # Return a list with one dict as just the dict if len(sols) == 1: return sols[0] return sols polys = [] dens = set() failed = [] result = False linear = False manual = flags.get('manual', False) checkdens = check = flags.get('check', True) for j, g in enumerate(exprs): dens.update(_simple_dens(g, symbols)) i, d = _invert(g, *symbols) g = d - i g = g.as_numer_denom()[0] if manual: failed.append(g) continue poly = g.as_poly(*symbols, extension=True) if poly is not None: polys.append(poly) else: failed.append(g) if not polys: solved_syms = [] else: if all(p.is_linear for p in polys): n, m = len(polys), len(symbols) matrix = zeros(n, m + 1) for i, poly in enumerate(polys): for monom, coeff in poly.terms(): try: j = monom.index(1) matrix[i, j] = coeff except ValueError: matrix[i, m] = -coeff # returns a dictionary ({symbols: values}) or None if flags.pop('particular', False): result = minsolve_linear_system(matrix, *symbols, **flags) else: result = solve_linear_system(matrix, *symbols, **flags) if failed: if result: solved_syms = list(result.keys()) else: solved_syms = [] else: linear = True else: if len(symbols) > len(polys): from sympy.utilities.iterables import subsets free = set().union(*[p.free_symbols for p in polys]) free = list(ordered(free.intersection(symbols))) got_s = set() result = [] for syms in subsets(free, len(polys)): try: # returns [] or list of tuples of solutions for syms res = solve_poly_system(polys, *syms) if res: for r in res: skip = False for r1 in r: if got_s and any([ss in r1.free_symbols for ss in got_s]): # sol depends on previously # solved symbols: discard it skip = True if not skip: got_s.update(syms) result.extend([dict(list(zip(syms, r)))]) except NotImplementedError: pass if got_s: solved_syms = list(got_s) else: raise NotImplementedError('no valid subset found') else: try: result = solve_poly_system(polys, *symbols) if result: solved_syms = symbols # we don't know here if the symbols provided # were given or not, so let solve resolve that. # A list of dictionaries is going to always be # returned from here. result = [dict(list(zip(solved_syms, r))) for r in result] except NotImplementedError: failed.extend([g.as_expr() for g in polys]) solved_syms = [] result = None if result: if isinstance(result, dict): result = [result] else: result = [{}] if failed: # For each failed equation, see if we can solve for one of the # remaining symbols from that equation. If so, we update the # solution set and continue with the next failed equation, # repeating until we are done or we get an equation that can't # be solved. def _ok_syms(e, sort=False): rv = (e.free_symbols - solved_syms) & legal # Solve first for symbols that have lower degree in the equation. # Ideally we want to solve firstly for symbols that appear linearly # with rational coefficients e.g. if e = x*y + z then we should # solve for z first. def key(sym): ep = e.as_poly(sym) if ep is None: complexity = (S.Infinity, S.Infinity, S.Infinity) else: coeff_syms = ep.LC().free_symbols complexity = (ep.degree(), len(coeff_syms & rv), len(coeff_syms)) return complexity + (default_sort_key(sym),) if sort: rv = sorted(rv, key=key) return rv solved_syms = set(solved_syms) # set of symbols we have solved for legal = set(symbols) # what we are interested in # sort so equation with the fewest potential symbols is first u = Dummy() # used in solution checking for eq in ordered(failed, lambda _: len(_ok_syms(_))): newresult = [] bad_results = [] got_s = set() hit = False for r in result: # update eq with everything that is known so far eq2 = eq.subs(r) # if check is True then we see if it satisfies this # equation, otherwise we just accept it if check and r: b = checksol(u, u, eq2, minimal=True) if b is not None: # this solution is sufficient to know whether # it is valid or not so we either accept or # reject it, then continue if b: newresult.append(r) else: bad_results.append(r) continue # search for a symbol amongst those available that # can be solved for ok_syms = _ok_syms(eq2, sort=True) if not ok_syms: if r: newresult.append(r) break # skip as it's independent of desired symbols for s in ok_syms: try: soln = _solve(eq2, s, **flags) except NotImplementedError: continue # put each solution in r and append the now-expanded # result in the new result list; use copy since the # solution for s in being added in-place for sol in soln: if got_s and any([ss in sol.free_symbols for ss in got_s]): # sol depends on previously solved symbols: discard it continue rnew = r.copy() for k, v in r.items(): rnew[k] = v.subs(s, sol) # and add this new solution rnew[s] = sol # check that it is independent of previous solutions iset = set(rnew.items()) for i in newresult: if len(i) < len(iset) and not set(i.items()) - iset: # this is a superset of a known solution that # is smaller break else: # keep it newresult.append(rnew) hit = True got_s.add(s) if not hit: raise NotImplementedError('could not solve %s' % eq2) else: result = newresult for b in bad_results: if b in result: result.remove(b) default_simplify = bool(failed) # rely on system-solvers to simplify if flags.get('simplify', default_simplify): for r in result: for k in r: r[k] = simplify(r[k]) flags['simplify'] = False # don't need to do so in checksol now if checkdens: result = [r for r in result if not any(checksol(d, r, **flags) for d in dens)] if check and not linear: result = [r for r in result if not any(checksol(e, r, **flags) is False for e in exprs)] result = [r for r in result if r] if linear and result: result = result[0] return result def solve_linear(lhs, rhs=0, symbols=[], exclude=[]): r""" Return a tuple derived from ``f = lhs - rhs`` that is one of the following: ``(0, 1)``, ``(0, 0)``, ``(symbol, solution)``, ``(n, d)``. Explanation =========== ``(0, 1)`` meaning that ``f`` is independent of the symbols in *symbols* that are not in *exclude*. ``(0, 0)`` meaning that there is no solution to the equation amongst the symbols given. If the first element of the tuple is not zero, then the function is guaranteed to be dependent on a symbol in *symbols*. ``(symbol, solution)`` where symbol appears linearly in the numerator of ``f``, is in *symbols* (if given), and is not in *exclude* (if given). No simplification is done to ``f`` other than a ``mul=True`` expansion, so the solution will correspond strictly to a unique solution. ``(n, d)`` where ``n`` and ``d`` are the numerator and denominator of ``f`` when the numerator was not linear in any symbol of interest; ``n`` will never be a symbol unless a solution for that symbol was found (in which case the second element is the solution, not the denominator). Examples ======== >>> from sympy.core.power import Pow >>> from sympy.polys.polytools import cancel ``f`` is independent of the symbols in *symbols* that are not in *exclude*: >>> from sympy.solvers.solvers import solve_linear >>> from sympy.abc import x, y, z >>> from sympy import cos, sin >>> eq = y*cos(x)**2 + y*sin(x)**2 - y # = y*(1 - 1) = 0 >>> solve_linear(eq) (0, 1) >>> eq = cos(x)**2 + sin(x)**2 # = 1 >>> solve_linear(eq) (0, 1) >>> solve_linear(x, exclude=[x]) (0, 1) The variable ``x`` appears as a linear variable in each of the following: >>> solve_linear(x + y**2) (x, -y**2) >>> solve_linear(1/x - y**2) (x, y**(-2)) When not linear in ``x`` or ``y`` then the numerator and denominator are returned: >>> solve_linear(x**2/y**2 - 3) (x**2 - 3*y**2, y**2) If the numerator of the expression is a symbol, then ``(0, 0)`` is returned if the solution for that symbol would have set any denominator to 0: >>> eq = 1/(1/x - 2) >>> eq.as_numer_denom() (x, 1 - 2*x) >>> solve_linear(eq) (0, 0) But automatic rewriting may cause a symbol in the denominator to appear in the numerator so a solution will be returned: >>> (1/x)**-1 x >>> solve_linear((1/x)**-1) (x, 0) Use an unevaluated expression to avoid this: >>> solve_linear(Pow(1/x, -1, evaluate=False)) (0, 0) If ``x`` is allowed to cancel in the following expression, then it appears to be linear in ``x``, but this sort of cancellation is not done by ``solve_linear`` so the solution will always satisfy the original expression without causing a division by zero error. >>> eq = x**2*(1/x - z**2/x) >>> solve_linear(cancel(eq)) (x, 0) >>> solve_linear(eq) (x**2*(1 - z**2), x) A list of symbols for which a solution is desired may be given: >>> solve_linear(x + y + z, symbols=[y]) (y, -x - z) A list of symbols to ignore may also be given: >>> solve_linear(x + y + z, exclude=[x]) (y, -x - z) (A solution for ``y`` is obtained because it is the first variable from the canonically sorted list of symbols that had a linear solution.) """ if isinstance(lhs, Equality): if rhs: raise ValueError(filldedent(''' If lhs is an Equality, rhs must be 0 but was %s''' % rhs)) rhs = lhs.rhs lhs = lhs.lhs dens = None eq = lhs - rhs n, d = eq.as_numer_denom() if not n: return S.Zero, S.One free = n.free_symbols if not symbols: symbols = free else: bad = [s for s in symbols if not s.is_Symbol] if bad: if len(bad) == 1: bad = bad[0] if len(symbols) == 1: eg = 'solve(%s, %s)' % (eq, symbols[0]) else: eg = 'solve(%s, *%s)' % (eq, list(symbols)) raise ValueError(filldedent(''' solve_linear only handles symbols, not %s. To isolate non-symbols use solve, e.g. >>> %s <<<. ''' % (bad, eg))) symbols = free.intersection(symbols) symbols = symbols.difference(exclude) if not symbols: return S.Zero, S.One # derivatives are easy to do but tricky to analyze to see if they # are going to disallow a linear solution, so for simplicity we # just evaluate the ones that have the symbols of interest derivs = defaultdict(list) for der in n.atoms(Derivative): csym = der.free_symbols & symbols for c in csym: derivs[c].append(der) all_zero = True for xi in sorted(symbols, key=default_sort_key): # canonical order # if there are derivatives in this var, calculate them now if isinstance(derivs[xi], list): derivs[xi] = {der: der.doit() for der in derivs[xi]} newn = n.subs(derivs[xi]) dnewn_dxi = newn.diff(xi) # dnewn_dxi can be nonzero if it survives differentation by any # of its free symbols free = dnewn_dxi.free_symbols if dnewn_dxi and (not free or any(dnewn_dxi.diff(s) for s in free) or free == symbols): all_zero = False if dnewn_dxi is S.NaN: break if xi not in dnewn_dxi.free_symbols: vi = -1/dnewn_dxi*(newn.subs(xi, 0)) if dens is None: dens = _simple_dens(eq, symbols) if not any(checksol(di, {xi: vi}, minimal=True) is True for di in dens): # simplify any trivial integral irep = [(i, i.doit()) for i in vi.atoms(Integral) if i.function.is_number] # do a slight bit of simplification vi = expand_mul(vi.subs(irep)) return xi, vi if all_zero: return S.Zero, S.One if n.is_Symbol: # no solution for this symbol was found return S.Zero, S.Zero return n, d def minsolve_linear_system(system, *symbols, **flags): r""" Find a particular solution to a linear system. Explanation =========== In particular, try to find a solution with the minimal possible number of non-zero variables using a naive algorithm with exponential complexity. If ``quick=True``, a heuristic is used. """ quick = flags.get('quick', False) # Check if there are any non-zero solutions at all s0 = solve_linear_system(system, *symbols, **flags) if not s0 or all(v == 0 for v in s0.values()): return s0 if quick: # We just solve the system and try to heuristically find a nice # solution. s = solve_linear_system(system, *symbols) def update(determined, solution): delete = [] for k, v in solution.items(): solution[k] = v.subs(determined) if not solution[k].free_symbols: delete.append(k) determined[k] = solution[k] for k in delete: del solution[k] determined = {} update(determined, s) while s: # NOTE sort by default_sort_key to get deterministic result k = max((k for k in s.values()), key=lambda x: (len(x.free_symbols), default_sort_key(x))) x = max(k.free_symbols, key=default_sort_key) if len(k.free_symbols) != 1: determined[x] = S.Zero else: val = solve(k)[0] if val == 0 and all(v.subs(x, val) == 0 for v in s.values()): determined[x] = S.One else: determined[x] = val update(determined, s) return determined else: # We try to select n variables which we want to be non-zero. # All others will be assumed zero. We try to solve the modified system. # If there is a non-trivial solution, just set the free variables to # one. If we do this for increasing n, trying all combinations of # variables, we will find an optimal solution. # We speed up slightly by starting at one less than the number of # variables the quick method manages. from itertools import combinations from sympy.utilities.misc import debug N = len(symbols) bestsol = minsolve_linear_system(system, *symbols, quick=True) n0 = len([x for x in bestsol.values() if x != 0]) for n in range(n0 - 1, 1, -1): debug('minsolve: %s' % n) thissol = None for nonzeros in combinations(list(range(N)), n): subm = Matrix([system.col(i).T for i in nonzeros] + [system.col(-1).T]).T s = solve_linear_system(subm, *[symbols[i] for i in nonzeros]) if s and not all(v == 0 for v in s.values()): subs = [(symbols[v], S.One) for v in nonzeros] for k, v in s.items(): s[k] = v.subs(subs) for sym in symbols: if sym not in s: if symbols.index(sym) in nonzeros: s[sym] = S.One else: s[sym] = S.Zero thissol = s break if thissol is None: break bestsol = thissol return bestsol def solve_linear_system(system, *symbols, **flags): r""" Solve system of $N$ linear equations with $M$ variables, which means both under- and overdetermined systems are supported. Explanation =========== The possible number of solutions is zero, one, or infinite. Respectively, this procedure will return None or a dictionary with solutions. In the case of underdetermined systems, all arbitrary parameters are skipped. This may cause a situation in which an empty dictionary is returned. In that case, all symbols can be assigned arbitrary values. Input to this function is a $N\times M + 1$ matrix, which means it has to be in augmented form. If you prefer to enter $N$ equations and $M$ unknowns then use ``solve(Neqs, *Msymbols)`` instead. Note: a local copy of the matrix is made by this routine so the matrix that is passed will not be modified. The algorithm used here is fraction-free Gaussian elimination, which results, after elimination, in an upper-triangular matrix. Then solutions are found using back-substitution. This approach is more efficient and compact than the Gauss-Jordan method. Examples ======== >>> from sympy import Matrix, solve_linear_system >>> from sympy.abc import x, y Solve the following system:: x + 4 y == 2 -2 x + y == 14 >>> system = Matrix(( (1, 4, 2), (-2, 1, 14))) >>> solve_linear_system(system, x, y) {x: -6, y: 2} A degenerate system returns an empty dictionary: >>> system = Matrix(( (0,0,0), (0,0,0) )) >>> solve_linear_system(system, x, y) {} """ assert system.shape[1] == len(symbols) + 1 # This is just a wrapper for solve_lin_sys eqs = list(system * Matrix(symbols + (-1,))) eqs, ring = sympy_eqs_to_ring(eqs, symbols) sol = solve_lin_sys(eqs, ring, _raw=False) if sol is not None: sol = {sym:val for sym, val in sol.items() if sym != val} return sol def solve_undetermined_coeffs(equ, coeffs, sym, **flags): r""" Solve equation of a type $p(x; a_1, \ldots, a_k) = q(x)$ where both $p$ and $q$ are univariate polynomials that depend on $k$ parameters. Explanation =========== The result of this function is a dictionary with symbolic values of those parameters with respect to coefficients in $q$. This function accepts both equations class instances and ordinary SymPy expressions. Specification of parameters and variables is obligatory for efficiency and simplicity reasons. Examples ======== >>> from sympy import Eq >>> from sympy.abc import a, b, c, x >>> from sympy.solvers import solve_undetermined_coeffs >>> solve_undetermined_coeffs(Eq(2*a*x + a+b, x), [a, b], x) {a: 1/2, b: -1/2} >>> solve_undetermined_coeffs(Eq(a*c*x + a+b, x), [a, b], x) {a: 1/c, b: -1/c} """ if isinstance(equ, Equality): # got equation, so move all the # terms to the left hand side equ = equ.lhs - equ.rhs equ = cancel(equ).as_numer_denom()[0] system = list(collect(equ.expand(), sym, evaluate=False).values()) if not any(equ.has(sym) for equ in system): # consecutive powers in the input expressions have # been successfully collected, so solve remaining # system using Gaussian elimination algorithm return solve(system, *coeffs, **flags) else: return None # no solutions def solve_linear_system_LU(matrix, syms): """ Solves the augmented matrix system using ``LUsolve`` and returns a dictionary in which solutions are keyed to the symbols of *syms* as ordered. Explanation =========== The matrix must be invertible. Examples ======== >>> from sympy import Matrix >>> from sympy.abc import x, y, z >>> from sympy.solvers.solvers import solve_linear_system_LU >>> solve_linear_system_LU(Matrix([ ... [1, 2, 0, 1], ... [3, 2, 2, 1], ... [2, 0, 0, 1]]), [x, y, z]) {x: 1/2, y: 1/4, z: -1/2} See Also ======== LUsolve """ if matrix.rows != matrix.cols - 1: raise ValueError("Rows should be equal to columns - 1") A = matrix[:matrix.rows, :matrix.rows] b = matrix[:, matrix.cols - 1:] soln = A.LUsolve(b) solutions = {} for i in range(soln.rows): solutions[syms[i]] = soln[i, 0] return solutions def det_perm(M): """ Return the determinant of *M* by using permutations to select factors. Explanation =========== For sizes larger than 8 the number of permutations becomes prohibitively large, or if there are no symbols in the matrix, it is better to use the standard determinant routines (e.g., ``M.det()``.) See Also ======== det_minor det_quick """ args = [] s = True n = M.rows list_ = M.flat() for perm in generate_bell(n): fac = [] idx = 0 for j in perm: fac.append(list_[idx + j]) idx += n term = Mul(*fac) # disaster with unevaluated Mul -- takes forever for n=7 args.append(term if s else -term) s = not s return Add(*args) def det_minor(M): """ Return the ``det(M)`` computed from minors without introducing new nesting in products. See Also ======== det_perm det_quick """ n = M.rows if n == 2: return M[0, 0]*M[1, 1] - M[1, 0]*M[0, 1] else: return sum([(1, -1)[i % 2]*Add(*[M[0, i]*d for d in Add.make_args(det_minor(M.minor_submatrix(0, i)))]) if M[0, i] else S.Zero for i in range(n)]) def det_quick(M, method=None): """ Return ``det(M)`` assuming that either there are lots of zeros or the size of the matrix is small. If this assumption is not met, then the normal Matrix.det function will be used with method = ``method``. See Also ======== det_minor det_perm """ if any(i.has(Symbol) for i in M): if M.rows < 8 and all(i.has(Symbol) for i in M): return det_perm(M) return det_minor(M) else: return M.det(method=method) if method else M.det() def inv_quick(M): """Return the inverse of ``M``, assuming that either there are lots of zeros or the size of the matrix is small. """ from sympy.matrices import zeros if not all(i.is_Number for i in M): if not any(i.is_Number for i in M): det = lambda _: det_perm(_) else: det = lambda _: det_minor(_) else: return M.inv() n = M.rows d = det(M) if d == S.Zero: raise NonInvertibleMatrixError("Matrix det == 0; not invertible") ret = zeros(n) s1 = -1 for i in range(n): s = s1 = -s1 for j in range(n): di = det(M.minor_submatrix(i, j)) ret[j, i] = s*di/d s = -s return ret # these are functions that have multiple inverse values per period multi_inverses = { sin: lambda x: (asin(x), S.Pi - asin(x)), cos: lambda x: (acos(x), 2*S.Pi - acos(x)), } def _tsolve(eq, sym, **flags): """ Helper for ``_solve`` that solves a transcendental equation with respect to the given symbol. Various equations containing powers and logarithms, can be solved. There is currently no guarantee that all solutions will be returned or that a real solution will be favored over a complex one. Either a list of potential solutions will be returned or None will be returned (in the case that no method was known to get a solution for the equation). All other errors (like the inability to cast an expression as a Poly) are unhandled. Examples ======== >>> from sympy import log >>> from sympy.solvers.solvers import _tsolve as tsolve >>> from sympy.abc import x >>> tsolve(3**(2*x + 5) - 4, x) [-5/2 + log(2)/log(3), (-5*log(3)/2 + log(2) + I*pi)/log(3)] >>> tsolve(log(x) + 2*x, x) [LambertW(2)/2] """ if 'tsolve_saw' not in flags: flags['tsolve_saw'] = [] if eq in flags['tsolve_saw']: return None else: flags['tsolve_saw'].append(eq) rhs, lhs = _invert(eq, sym) if lhs == sym: return [rhs] try: if lhs.is_Add: # it's time to try factoring; powdenest is used # to try get powers in standard form for better factoring f = factor(powdenest(lhs - rhs)) if f.is_Mul: return _solve(f, sym, **flags) if rhs: f = logcombine(lhs, force=flags.get('force', True)) if f.count(log) != lhs.count(log): if isinstance(f, log): return _solve(f.args[0] - exp(rhs), sym, **flags) return _tsolve(f - rhs, sym, **flags) elif lhs.is_Pow: if lhs.exp.is_Integer: if lhs - rhs != eq: return _solve(lhs - rhs, sym, **flags) if sym not in lhs.exp.free_symbols: return _solve(lhs.base - rhs**(1/lhs.exp), sym, **flags) # _tsolve calls this with Dummy before passing the actual number in. if any(t.is_Dummy for t in rhs.free_symbols): raise NotImplementedError # _tsolve will call here again... # a ** g(x) == 0 if not rhs: # f(x)**g(x) only has solutions where f(x) == 0 and g(x) != 0 at # the same place sol_base = _solve(lhs.base, sym, **flags) return [s for s in sol_base if lhs.exp.subs(sym, s) != 0] # a ** g(x) == b if not lhs.base.has(sym): if lhs.base == 0: return _solve(lhs.exp, sym, **flags) if rhs != 0 else [] # Gets most solutions... if lhs.base == rhs.as_base_exp()[0]: # handles case when bases are equal sol = _solve(lhs.exp - rhs.as_base_exp()[1], sym, **flags) else: # handles cases when bases are not equal and exp # may or may not be equal sol = _solve(exp(log(lhs.base)*lhs.exp)-exp(log(rhs)), sym, **flags) # Check for duplicate solutions def equal(expr1, expr2): _ = Dummy() eq = checksol(expr1 - _, _, expr2) if eq is None: if nsimplify(expr1) != nsimplify(expr2): return False # they might be coincidentally the same # so check more rigorously eq = expr1.equals(expr2) return eq # Guess a rational exponent e_rat = nsimplify(log(abs(rhs))/log(abs(lhs.base))) e_rat = simplify(posify(e_rat)[0]) n, d = fraction(e_rat) if expand(lhs.base**n - rhs**d) == 0: sol = [s for s in sol if not equal(lhs.exp.subs(sym, s), e_rat)] sol.extend(_solve(lhs.exp - e_rat, sym, **flags)) return list(ordered(set(sol))) # f(x) ** g(x) == c else: sol = [] logform = lhs.exp*log(lhs.base) - log(rhs) if logform != lhs - rhs: try: sol.extend(_solve(logform, sym, **flags)) except NotImplementedError: pass # Collect possible solutions and check with substitution later. check = [] if rhs == 1: # f(x) ** g(x) = 1 -- g(x)=0 or f(x)=+-1 check.extend(_solve(lhs.exp, sym, **flags)) check.extend(_solve(lhs.base - 1, sym, **flags)) check.extend(_solve(lhs.base + 1, sym, **flags)) elif rhs.is_Rational: for d in (i for i in divisors(abs(rhs.p)) if i != 1): e, t = integer_log(rhs.p, d) if not t: continue # rhs.p != d**b for s in divisors(abs(rhs.q)): if s**e== rhs.q: r = Rational(d, s) check.extend(_solve(lhs.base - r, sym, **flags)) check.extend(_solve(lhs.base + r, sym, **flags)) check.extend(_solve(lhs.exp - e, sym, **flags)) elif rhs.is_irrational: b_l, e_l = lhs.base.as_base_exp() n, d = (e_l*lhs.exp).as_numer_denom() b, e = sqrtdenest(rhs).as_base_exp() check = [sqrtdenest(i) for i in (_solve(lhs.base - b, sym, **flags))] check.extend([sqrtdenest(i) for i in (_solve(lhs.exp - e, sym, **flags))]) if e_l*d != 1: check.extend(_solve(b_l**n - rhs**(e_l*d), sym, **flags)) for s in check: ok = checksol(eq, sym, s) if ok is None: ok = eq.subs(sym, s).equals(0) if ok: sol.append(s) return list(ordered(set(sol))) elif lhs.is_Function and len(lhs.args) == 1: if lhs.func in multi_inverses: # sin(x) = 1/3 -> x - asin(1/3) & x - (pi - asin(1/3)) soln = [] for i in multi_inverses[lhs.func](rhs): soln.extend(_solve(lhs.args[0] - i, sym, **flags)) return list(ordered(soln)) elif lhs.func == LambertW: return _solve(lhs.args[0] - rhs*exp(rhs), sym, **flags) rewrite = lhs.rewrite(exp) if rewrite != lhs: return _solve(rewrite - rhs, sym, **flags) except NotImplementedError: pass # maybe it is a lambert pattern if flags.pop('bivariate', True): # lambert forms may need some help being recognized, e.g. changing # 2**(3*x) + x**3*log(2)**3 + 3*x**2*log(2)**2 + 3*x*log(2) + 1 # to 2**(3*x) + (x*log(2) + 1)**3 g = _filtered_gens(eq.as_poly(), sym) up_or_log = set() for gi in g: if isinstance(gi, exp) or (gi.is_Pow and gi.base == S.Exp1) or isinstance(gi, log): up_or_log.add(gi) elif gi.is_Pow: gisimp = powdenest(expand_power_exp(gi)) if gisimp.is_Pow and sym in gisimp.exp.free_symbols: up_or_log.add(gi) eq_down = expand_log(expand_power_exp(eq)).subs( dict(list(zip(up_or_log, [0]*len(up_or_log))))) eq = expand_power_exp(factor(eq_down, deep=True) + (eq - eq_down)) rhs, lhs = _invert(eq, sym) if lhs.has(sym): try: poly = lhs.as_poly() g = _filtered_gens(poly, sym) _eq = lhs - rhs sols = _solve_lambert(_eq, sym, g) # use a simplified form if it satisfies eq # and has fewer operations for n, s in enumerate(sols): ns = nsimplify(s) if ns != s and ns.count_ops() <= s.count_ops(): ok = checksol(_eq, sym, ns) if ok is None: ok = _eq.subs(sym, ns).equals(0) if ok: sols[n] = ns return sols except NotImplementedError: # maybe it's a convoluted function if len(g) == 2: try: gpu = bivariate_type(lhs - rhs, *g) if gpu is None: raise NotImplementedError g, p, u = gpu flags['bivariate'] = False inversion = _tsolve(g - u, sym, **flags) if inversion: sol = _solve(p, u, **flags) return list(ordered({i.subs(u, s) for i in inversion for s in sol})) except NotImplementedError: pass else: pass if flags.pop('force', True): flags['force'] = False pos, reps = posify(lhs - rhs) if rhs == S.ComplexInfinity: return [] for u, s in reps.items(): if s == sym: break else: u = sym if pos.has(u): try: soln = _solve(pos, u, **flags) return list(ordered([s.subs(reps) for s in soln])) except NotImplementedError: pass else: pass # here for coverage return # here for coverage # TODO: option for calculating J numerically @conserve_mpmath_dps def nsolve(*args, dict=False, **kwargs): r""" Solve a nonlinear equation system numerically: ``nsolve(f, [args,] x0, modules=['mpmath'], **kwargs)``. Explanation =========== ``f`` is a vector function of symbolic expressions representing the system. *args* are the variables. If there is only one variable, this argument can be omitted. ``x0`` is a starting vector close to a solution. Use the modules keyword to specify which modules should be used to evaluate the function and the Jacobian matrix. Make sure to use a module that supports matrices. For more information on the syntax, please see the docstring of ``lambdify``. If the keyword arguments contain ``dict=True`` (default is False) ``nsolve`` will return a list (perhaps empty) of solution mappings. This might be especially useful if you want to use ``nsolve`` as a fallback to solve since using the dict argument for both methods produces return values of consistent type structure. Please note: to keep this consistent with ``solve``, the solution will be returned in a list even though ``nsolve`` (currently at least) only finds one solution at a time. Overdetermined systems are supported. Examples ======== >>> from sympy import Symbol, nsolve >>> import mpmath >>> mpmath.mp.dps = 15 >>> x1 = Symbol('x1') >>> x2 = Symbol('x2') >>> f1 = 3 * x1**2 - 2 * x2**2 - 1 >>> f2 = x1**2 - 2 * x1 + x2**2 + 2 * x2 - 8 >>> print(nsolve((f1, f2), (x1, x2), (-1, 1))) Matrix([[-1.19287309935246], [1.27844411169911]]) For one-dimensional functions the syntax is simplified: >>> from sympy import sin, nsolve >>> from sympy.abc import x >>> nsolve(sin(x), x, 2) 3.14159265358979 >>> nsolve(sin(x), 2) 3.14159265358979 To solve with higher precision than the default, use the prec argument: >>> from sympy import cos >>> nsolve(cos(x) - x, 1) 0.739085133215161 >>> nsolve(cos(x) - x, 1, prec=50) 0.73908513321516064165531208767387340401341175890076 >>> cos(_) 0.73908513321516064165531208767387340401341175890076 To solve for complex roots of real functions, a nonreal initial point must be specified: >>> from sympy import I >>> nsolve(x**2 + 2, I) 1.4142135623731*I ``mpmath.findroot`` is used and you can find their more extensive documentation, especially concerning keyword parameters and available solvers. Note, however, that functions which are very steep near the root, the verification of the solution may fail. In this case you should use the flag ``verify=False`` and independently verify the solution. >>> from sympy import cos, cosh >>> f = cos(x)*cosh(x) - 1 >>> nsolve(f, 3.14*100) Traceback (most recent call last): ... ValueError: Could not find root within given tolerance. (1.39267e+230 > 2.1684e-19) >>> ans = nsolve(f, 3.14*100, verify=False); ans 312.588469032184 >>> f.subs(x, ans).n(2) 2.1e+121 >>> (f/f.diff(x)).subs(x, ans).n(2) 7.4e-15 One might safely skip the verification if bounds of the root are known and a bisection method is used: >>> bounds = lambda i: (3.14*i, 3.14*(i + 1)) >>> nsolve(f, bounds(100), solver='bisect', verify=False) 315.730061685774 Alternatively, a function may be better behaved when the denominator is ignored. Since this is not always the case, however, the decision of what function to use is left to the discretion of the user. >>> eq = x**2/(1 - x)/(1 - 2*x)**2 - 100 >>> nsolve(eq, 0.46) Traceback (most recent call last): ... ValueError: Could not find root within given tolerance. (10000 > 2.1684e-19) Try another starting point or tweak arguments. >>> nsolve(eq.as_numer_denom()[0], 0.46) 0.46792545969349058 """ # there are several other SymPy functions that use method= so # guard against that here if 'method' in kwargs: raise ValueError(filldedent(''' Keyword "method" should not be used in this context. When using some mpmath solvers directly, the keyword "method" is used, but when using nsolve (and findroot) the keyword to use is "solver".''')) if 'prec' in kwargs: prec = kwargs.pop('prec') import mpmath mpmath.mp.dps = prec else: prec = None # keyword argument to return result as a dictionary as_dict = dict from builtins import dict # to unhide the builtin # interpret arguments if len(args) == 3: f = args[0] fargs = args[1] x0 = args[2] if iterable(fargs) and iterable(x0): if len(x0) != len(fargs): raise TypeError('nsolve expected exactly %i guess vectors, got %i' % (len(fargs), len(x0))) elif len(args) == 2: f = args[0] fargs = None x0 = args[1] if iterable(f): raise TypeError('nsolve expected 3 arguments, got 2') elif len(args) < 2: raise TypeError('nsolve expected at least 2 arguments, got %i' % len(args)) else: raise TypeError('nsolve expected at most 3 arguments, got %i' % len(args)) modules = kwargs.get('modules', ['mpmath']) if iterable(f): f = list(f) for i, fi in enumerate(f): if isinstance(fi, Equality): f[i] = fi.lhs - fi.rhs f = Matrix(f).T if iterable(x0): x0 = list(x0) if not isinstance(f, Matrix): # assume it's a sympy expression if isinstance(f, Equality): f = f.lhs - f.rhs syms = f.free_symbols if fargs is None: fargs = syms.copy().pop() if not (len(syms) == 1 and (fargs in syms or fargs[0] in syms)): raise ValueError(filldedent(''' expected a one-dimensional and numerical function''')) # the function is much better behaved if there is no denominator # but sending the numerator is left to the user since sometimes # the function is better behaved when the denominator is present # e.g., issue 11768 f = lambdify(fargs, f, modules) x = sympify(findroot(f, x0, **kwargs)) if as_dict: return [{fargs: x}] return x if len(fargs) > f.cols: raise NotImplementedError(filldedent(''' need at least as many equations as variables''')) verbose = kwargs.get('verbose', False) if verbose: print('f(x):') print(f) # derive Jacobian J = f.jacobian(fargs) if verbose: print('J(x):') print(J) # create functions f = lambdify(fargs, f.T, modules) J = lambdify(fargs, J, modules) # solve the system numerically x = findroot(f, x0, J=J, **kwargs) if as_dict: return [dict(zip(fargs, [sympify(xi) for xi in x]))] return Matrix(x) def _invert(eq, *symbols, **kwargs): """ Return tuple (i, d) where ``i`` is independent of *symbols* and ``d`` contains symbols. Explanation =========== ``i`` and ``d`` are obtained after recursively using algebraic inversion until an uninvertible ``d`` remains. If there are no free symbols then ``d`` will be zero. Some (but not necessarily all) solutions to the expression ``i - d`` will be related to the solutions of the original expression. Examples ======== >>> from sympy.solvers.solvers import _invert as invert >>> from sympy import sqrt, cos >>> from sympy.abc import x, y >>> invert(x - 3) (3, x) >>> invert(3) (3, 0) >>> invert(2*cos(x) - 1) (1/2, cos(x)) >>> invert(sqrt(x) - 3) (3, sqrt(x)) >>> invert(sqrt(x) + y, x) (-y, sqrt(x)) >>> invert(sqrt(x) + y, y) (-sqrt(x), y) >>> invert(sqrt(x) + y, x, y) (0, sqrt(x) + y) If there is more than one symbol in a power's base and the exponent is not an Integer, then the principal root will be used for the inversion: >>> invert(sqrt(x + y) - 2) (4, x + y) >>> invert(sqrt(x + y) - 2) (4, x + y) If the exponent is an Integer, setting ``integer_power`` to True will force the principal root to be selected: >>> invert(x**2 - 4, integer_power=True) (2, x) """ eq = sympify(eq) if eq.args: # make sure we are working with flat eq eq = eq.func(*eq.args) free = eq.free_symbols if not symbols: symbols = free if not free & set(symbols): return eq, S.Zero dointpow = bool(kwargs.get('integer_power', False)) lhs = eq rhs = S.Zero while True: was = lhs while True: indep, dep = lhs.as_independent(*symbols) # dep + indep == rhs if lhs.is_Add: # this indicates we have done it all if indep.is_zero: break lhs = dep rhs -= indep # dep * indep == rhs else: # this indicates we have done it all if indep is S.One: break lhs = dep rhs /= indep # collect like-terms in symbols if lhs.is_Add: terms = {} for a in lhs.args: i, d = a.as_independent(*symbols) terms.setdefault(d, []).append(i) if any(len(v) > 1 for v in terms.values()): args = [] for d, i in terms.items(): if len(i) > 1: args.append(Add(*i)*d) else: args.append(i[0]*d) lhs = Add(*args) # if it's a two-term Add with rhs = 0 and two powers we can get the # dependent terms together, e.g. 3*f(x) + 2*g(x) -> f(x)/g(x) = -2/3 if lhs.is_Add and not rhs and len(lhs.args) == 2 and \ not lhs.is_polynomial(*symbols): a, b = ordered(lhs.args) ai, ad = a.as_independent(*symbols) bi, bd = b.as_independent(*symbols) if any(_ispow(i) for i in (ad, bd)): a_base, a_exp = ad.as_base_exp() b_base, b_exp = bd.as_base_exp() if a_base == b_base: # a = -b lhs = powsimp(powdenest(ad/bd)) rhs = -bi/ai else: rat = ad/bd _lhs = powsimp(ad/bd) if _lhs != rat: lhs = _lhs rhs = -bi/ai elif ai == -bi: if isinstance(ad, Function) and ad.func == bd.func: if len(ad.args) == len(bd.args) == 1: lhs = ad.args[0] - bd.args[0] elif len(ad.args) == len(bd.args): # should be able to solve # f(x, y) - f(2 - x, 0) == 0 -> x == 1 raise NotImplementedError( 'equal function with more than 1 argument') else: raise ValueError( 'function with different numbers of args') elif lhs.is_Mul and any(_ispow(a) for a in lhs.args): lhs = powsimp(powdenest(lhs)) if lhs.is_Function: if hasattr(lhs, 'inverse') and lhs.inverse() is not None and len(lhs.args) == 1: # -1 # f(x) = g -> x = f (g) # # /!\ inverse should not be defined if there are multiple values # for the function -- these are handled in _tsolve # rhs = lhs.inverse()(rhs) lhs = lhs.args[0] elif isinstance(lhs, atan2): y, x = lhs.args lhs = 2*atan(y/(sqrt(x**2 + y**2) + x)) elif lhs.func == rhs.func: if len(lhs.args) == len(rhs.args) == 1: lhs = lhs.args[0] rhs = rhs.args[0] elif len(lhs.args) == len(rhs.args): # should be able to solve # f(x, y) == f(2, 3) -> x == 2 # f(x, x + y) == f(2, 3) -> x == 2 raise NotImplementedError( 'equal function with more than 1 argument') else: raise ValueError( 'function with different numbers of args') if rhs and lhs.is_Pow and lhs.exp.is_Integer and lhs.exp < 0: lhs = 1/lhs rhs = 1/rhs # base**a = b -> base = b**(1/a) if # a is an Integer and dointpow=True (this gives real branch of root) # a is not an Integer and the equation is multivariate and the # base has more than 1 symbol in it # The rationale for this is that right now the multi-system solvers # doesn't try to resolve generators to see, for example, if the whole # system is written in terms of sqrt(x + y) so it will just fail, so we # do that step here. if lhs.is_Pow and ( lhs.exp.is_Integer and dointpow or not lhs.exp.is_Integer and len(symbols) > 1 and len(lhs.base.free_symbols & set(symbols)) > 1): rhs = rhs**(1/lhs.exp) lhs = lhs.base if lhs == was: break return rhs, lhs def unrad(eq, *syms, **flags): """ Remove radicals with symbolic arguments and return (eq, cov), None, or raise an error. Explanation =========== None is returned if there are no radicals to remove. NotImplementedError is raised if there are radicals and they cannot be removed or if the relationship between the original symbols and the change of variable needed to rewrite the system as a polynomial cannot be solved. Otherwise the tuple, ``(eq, cov)``, is returned where: *eq*, ``cov`` *eq* is an equation without radicals (in the symbol(s) of interest) whose solutions are a superset of the solutions to the original expression. *eq* might be rewritten in terms of a new variable; the relationship to the original variables is given by ``cov`` which is a list containing ``v`` and ``v**p - b`` where ``p`` is the power needed to clear the radical and ``b`` is the radical now expressed as a polynomial in the symbols of interest. For example, for sqrt(2 - x) the tuple would be ``(c, c**2 - 2 + x)``. The solutions of *eq* will contain solutions to the original equation (if there are any). *syms* An iterable of symbols which, if provided, will limit the focus of radical removal: only radicals with one or more of the symbols of interest will be cleared. All free symbols are used if *syms* is not set. *flags* are used internally for communication during recursive calls. Two options are also recognized: ``take``, when defined, is interpreted as a single-argument function that returns True if a given Pow should be handled. Radicals can be removed from an expression if: * All bases of the radicals are the same; a change of variables is done in this case. * If all radicals appear in one term of the expression. * There are only four terms with sqrt() factors or there are less than four terms having sqrt() factors. * There are only two terms with radicals. Examples ======== >>> from sympy.solvers.solvers import unrad >>> from sympy.abc import x >>> from sympy import sqrt, Rational, root >>> unrad(sqrt(x)*x**Rational(1, 3) + 2) (x**5 - 64, []) >>> unrad(sqrt(x) + root(x + 1, 3)) (-x**3 + x**2 + 2*x + 1, []) >>> eq = sqrt(x) + root(x, 3) - 2 >>> unrad(eq) (_p**3 + _p**2 - 2, [_p, _p**6 - x]) """ from sympy import Equality as Eq uflags = dict(check=False, simplify=False) def _cov(p, e): if cov: # XXX - uncovered oldp, olde = cov if Poly(e, p).degree(p) in (1, 2): cov[:] = [p, olde.subs(oldp, _solve(e, p, **uflags)[0])] else: raise NotImplementedError else: cov[:] = [p, e] def _canonical(eq, cov): if cov: # change symbol to vanilla so no solutions are eliminated p, e = cov rep = {p: Dummy(p.name)} eq = eq.xreplace(rep) cov = [p.xreplace(rep), e.xreplace(rep)] # remove constants and powers of factors since these don't change # the location of the root; XXX should factor or factor_terms be used? eq = factor_terms(_mexpand(eq.as_numer_denom()[0], recursive=True), clear=True) if eq.is_Mul: args = [] for f in eq.args: if f.is_number: continue if f.is_Pow: args.append(f.base) else: args.append(f) eq = Mul(*args) # leave as Mul for more efficient solving # make the sign canonical margs = list(Mul.make_args(eq)) changed = False for i, m in enumerate(margs): if m.could_extract_minus_sign(): margs[i] = -m changed = True if changed: eq = Mul(*margs, evaluate=False) return eq, cov def _Q(pow): # return leading Rational of denominator of Pow's exponent c = pow.as_base_exp()[1].as_coeff_Mul()[0] if not c.is_Rational: return S.One return c.q # define the _take method that will determine whether a term is of interest def _take(d): # return True if coefficient of any factor's exponent's den is not 1 for pow in Mul.make_args(d): if not pow.is_Pow: continue if _Q(pow) == 1: continue if pow.free_symbols & syms: return True return False _take = flags.setdefault('_take', _take) if isinstance(eq, Eq): eq = eq.lhs - eq.rhs # XXX legacy Eq as Eqn support elif not isinstance(eq, Expr): return cov, nwas, rpt = [flags.setdefault(k, v) for k, v in sorted(dict(cov=[], n=None, rpt=0).items())] # preconditioning eq = powdenest(factor_terms(eq, radical=True, clear=True)) eq = eq.as_numer_denom()[0] eq = _mexpand(eq, recursive=True) if eq.is_number: return # see if there are radicals in symbols of interest syms = set(syms) or eq.free_symbols # _take uses this poly = eq.as_poly() gens = [g for g in poly.gens if _take(g)] if not gens: return # recast poly in terms of eigen-gens poly = eq.as_poly(*gens) # - an exponent has a symbol of interest (don't handle) if any(g.exp.has(*syms) for g in gens): return def _rads_bases_lcm(poly): # if all the bases are the same or all the radicals are in one # term, `lcm` will be the lcm of the denominators of the # exponents of the radicals lcm = 1 rads = set() bases = set() for g in poly.gens: q = _Q(g) if q != 1: rads.add(g) lcm = ilcm(lcm, q) bases.add(g.base) return rads, bases, lcm rads, bases, lcm = _rads_bases_lcm(poly) covsym = Dummy('p', nonnegative=True) # only keep in syms symbols that actually appear in radicals; # and update gens newsyms = set() for r in rads: newsyms.update(syms & r.free_symbols) if newsyms != syms: syms = newsyms # get terms together that have common generators drad = dict(list(zip(rads, list(range(len(rads)))))) rterms = {(): []} args = Add.make_args(poly.as_expr()) for t in args: if _take(t): common = set(t.as_poly().gens).intersection(rads) key = tuple(sorted([drad[i] for i in common])) else: key = () rterms.setdefault(key, []).append(t) others = Add(*rterms.pop(())) rterms = [Add(*rterms[k]) for k in rterms.keys()] # the output will depend on the order terms are processed, so # make it canonical quickly rterms = list(reversed(list(ordered(rterms)))) ok = False # we don't have a solution yet depth = sqrt_depth(eq) if len(rterms) == 1 and not (rterms[0].is_Add and lcm > 2): eq = rterms[0]**lcm - ((-others)**lcm) ok = True else: if len(rterms) == 1 and rterms[0].is_Add: rterms = list(rterms[0].args) if len(bases) == 1: b = bases.pop() if len(syms) > 1: x = b.free_symbols else: x = syms x = list(ordered(x))[0] try: inv = _solve(covsym**lcm - b, x, **uflags) if not inv: raise NotImplementedError eq = poly.as_expr().subs(b, covsym**lcm).subs(x, inv[0]) _cov(covsym, covsym**lcm - b) return _canonical(eq, cov) except NotImplementedError: pass if len(rterms) == 2: if not others: eq = rterms[0]**lcm - (-rterms[1])**lcm ok = True elif not log(lcm, 2).is_Integer: # the lcm-is-power-of-two case is handled below r0, r1 = rterms if flags.get('_reverse', False): r1, r0 = r0, r1 i0 = _rads0, _bases0, lcm0 = _rads_bases_lcm(r0.as_poly()) i1 = _rads1, _bases1, lcm1 = _rads_bases_lcm(r1.as_poly()) for reverse in range(2): if reverse: i0, i1 = i1, i0 r0, r1 = r1, r0 _rads1, _, lcm1 = i1 _rads1 = Mul(*_rads1) t1 = _rads1**lcm1 c = covsym**lcm1 - t1 for x in syms: try: sol = _solve(c, x, **uflags) if not sol: raise NotImplementedError neweq = r0.subs(x, sol[0]) + covsym*r1/_rads1 + \ others tmp = unrad(neweq, covsym) if tmp: eq, newcov = tmp if newcov: newp, newc = newcov _cov(newp, c.subs(covsym, _solve(newc, covsym, **uflags)[0])) else: _cov(covsym, c) else: eq = neweq _cov(covsym, c) ok = True break except NotImplementedError: if reverse: raise NotImplementedError( 'no successful change of variable found') else: pass if ok: break elif len(rterms) == 3: # two cube roots and another with order less than 5 # (so an analytical solution can be found) or a base # that matches one of the cube root bases info = [_rads_bases_lcm(i.as_poly()) for i in rterms] RAD = 0 BASES = 1 LCM = 2 if info[0][LCM] != 3: info.append(info.pop(0)) rterms.append(rterms.pop(0)) elif info[1][LCM] != 3: info.append(info.pop(1)) rterms.append(rterms.pop(1)) if info[0][LCM] == info[1][LCM] == 3: if info[1][BASES] != info[2][BASES]: info[0], info[1] = info[1], info[0] rterms[0], rterms[1] = rterms[1], rterms[0] if info[1][BASES] == info[2][BASES]: eq = rterms[0]**3 + (rterms[1] + rterms[2] + others)**3 ok = True elif info[2][LCM] < 5: # a*root(A, 3) + b*root(B, 3) + others = c a, b, c, d, A, B = [Dummy(i) for i in 'abcdAB'] # zz represents the unraded expression into which the # specifics for this case are substituted zz = (c - d)*(A**3*a**9 + 3*A**2*B*a**6*b**3 - 3*A**2*a**6*c**3 + 9*A**2*a**6*c**2*d - 9*A**2*a**6*c*d**2 + 3*A**2*a**6*d**3 + 3*A*B**2*a**3*b**6 + 21*A*B*a**3*b**3*c**3 - 63*A*B*a**3*b**3*c**2*d + 63*A*B*a**3*b**3*c*d**2 - 21*A*B*a**3*b**3*d**3 + 3*A*a**3*c**6 - 18*A*a**3*c**5*d + 45*A*a**3*c**4*d**2 - 60*A*a**3*c**3*d**3 + 45*A*a**3*c**2*d**4 - 18*A*a**3*c*d**5 + 3*A*a**3*d**6 + B**3*b**9 - 3*B**2*b**6*c**3 + 9*B**2*b**6*c**2*d - 9*B**2*b**6*c*d**2 + 3*B**2*b**6*d**3 + 3*B*b**3*c**6 - 18*B*b**3*c**5*d + 45*B*b**3*c**4*d**2 - 60*B*b**3*c**3*d**3 + 45*B*b**3*c**2*d**4 - 18*B*b**3*c*d**5 + 3*B*b**3*d**6 - c**9 + 9*c**8*d - 36*c**7*d**2 + 84*c**6*d**3 - 126*c**5*d**4 + 126*c**4*d**5 - 84*c**3*d**6 + 36*c**2*d**7 - 9*c*d**8 + d**9) def _t(i): b = Mul(*info[i][RAD]) return cancel(rterms[i]/b), Mul(*info[i][BASES]) aa, AA = _t(0) bb, BB = _t(1) cc = -rterms[2] dd = others eq = zz.xreplace(dict(zip( (a, A, b, B, c, d), (aa, AA, bb, BB, cc, dd)))) ok = True # handle power-of-2 cases if not ok: if log(lcm, 2).is_Integer and (not others and len(rterms) == 4 or len(rterms) < 4): def _norm2(a, b): return a**2 + b**2 + 2*a*b if len(rterms) == 4: # (r0+r1)**2 - (r2+r3)**2 r0, r1, r2, r3 = rterms eq = _norm2(r0, r1) - _norm2(r2, r3) ok = True elif len(rterms) == 3: # (r1+r2)**2 - (r0+others)**2 r0, r1, r2 = rterms eq = _norm2(r1, r2) - _norm2(r0, others) ok = True elif len(rterms) == 2: # r0**2 - (r1+others)**2 r0, r1 = rterms eq = r0**2 - _norm2(r1, others) ok = True new_depth = sqrt_depth(eq) if ok else depth rpt += 1 # XXX how many repeats with others unchanging is enough? if not ok or ( nwas is not None and len(rterms) == nwas and new_depth is not None and new_depth == depth and rpt > 3): raise NotImplementedError('Cannot remove all radicals') flags.update(dict(cov=cov, n=len(rterms), rpt=rpt)) neq = unrad(eq, *syms, **flags) if neq: eq, cov = neq eq, cov = _canonical(eq, cov) return eq, cov from sympy.solvers.bivariate import ( bivariate_type, _solve_lambert, _filtered_gens) sympy-sympy-1.9/sympy/solvers/solveset.py000066400000000000000000004020761412543434000210300ustar00rootroot00000000000000""" This module contains functions to: - solve a single equation for a single variable, in any domain either real or complex. - solve a single transcendental equation for a single variable in any domain either real or complex. (currently supports solving in real domain only) - solve a system of linear equations with N variables and M equations. - solve a system of Non Linear Equations with N variables and M equations """ from sympy.core.sympify import sympify from sympy.core import (S, Pow, Dummy, pi, Expr, Wild, Mul, Equality, Add) from sympy.core.containers import Tuple from sympy.core.numbers import I, Number, Rational, oo from sympy.core.function import (Lambda, expand_complex, AppliedUndef, expand_log) from sympy.core.mod import Mod from sympy.core.numbers import igcd from sympy.core.relational import Eq, Ne, Relational from sympy.core.symbol import Symbol, _uniquely_named_symbol from sympy.core.sympify import _sympify from sympy.simplify.simplify import simplify, fraction, trigsimp from sympy.simplify import powdenest, logcombine from sympy.functions import (log, Abs, tan, cot, sin, cos, sec, csc, exp, acos, asin, acsc, asec, arg, piecewise_fold, Piecewise) from sympy.functions.elementary.trigonometric import (TrigonometricFunction, HyperbolicFunction) from sympy.functions.elementary.miscellaneous import real_root from sympy.logic.boolalg import And from sympy.sets import (FiniteSet, EmptySet, imageset, Interval, Intersection, Union, ConditionSet, ImageSet, Complement, Contains) from sympy.sets.sets import Set, ProductSet from sympy.matrices import Matrix, MatrixBase from sympy.ntheory import totient from sympy.ntheory.factor_ import divisors from sympy.ntheory.residue_ntheory import discrete_log, nthroot_mod from sympy.polys import (roots, Poly, degree, together, PolynomialError, RootOf, factor, lcm, gcd) from sympy.polys.polyerrors import CoercionFailed from sympy.polys.polytools import invert from sympy.polys.solvers import (sympy_eqs_to_ring, solve_lin_sys, PolyNonlinearError) from sympy.polys.matrices.linsolve import _linsolve from sympy.solvers.solvers import (checksol, denoms, unrad, _simple_dens, recast_to_symbols) from sympy.solvers.polysys import solve_poly_system from sympy.solvers.inequalities import solve_univariate_inequality from sympy.utilities import filldedent from sympy.utilities.iterables import numbered_symbols, has_dups from sympy.calculus.util import periodicity, continuous_domain from sympy.core.compatibility import ordered, default_sort_key, is_sequence from types import GeneratorType from collections import defaultdict class NonlinearError(ValueError): """Raised when unexpectedly encountering nonlinear equations""" pass _rc = Dummy("R", real=True), Dummy("C", complex=True) def _masked(f, *atoms): """Return ``f``, with all objects given by ``atoms`` replaced with Dummy symbols, ``d``, and the list of replacements, ``(d, e)``, where ``e`` is an object of type given by ``atoms`` in which any other instances of atoms have been recursively replaced with Dummy symbols, too. The tuples are ordered so that if they are applied in sequence, the origin ``f`` will be restored. Examples ======== >>> from sympy import cos >>> from sympy.abc import x >>> from sympy.solvers.solveset import _masked >>> f = cos(cos(x) + 1) >>> f, reps = _masked(cos(1 + cos(x)), cos) >>> f _a1 >>> reps [(_a1, cos(_a0 + 1)), (_a0, cos(x))] >>> for d, e in reps: ... f = f.xreplace({d: e}) >>> f cos(cos(x) + 1) """ sym = numbered_symbols('a', cls=Dummy, real=True) mask = [] for a in ordered(f.atoms(*atoms)): for i in mask: a = a.replace(*i) mask.append((a, next(sym))) for i, (o, n) in enumerate(mask): f = f.replace(o, n) mask[i] = (n, o) mask = list(reversed(mask)) return f, mask def _invert(f_x, y, x, domain=S.Complexes): r""" Reduce the complex valued equation ``f(x) = y`` to a set of equations ``{g(x) = h_1(y), g(x) = h_2(y), ..., g(x) = h_n(y) }`` where ``g(x)`` is a simpler function than ``f(x)``. The return value is a tuple ``(g(x), set_h)``, where ``g(x)`` is a function of ``x`` and ``set_h`` is the set of function ``{h_1(y), h_2(y), ..., h_n(y)}``. Here, ``y`` is not necessarily a symbol. The ``set_h`` contains the functions, along with the information about the domain in which they are valid, through set operations. For instance, if ``y = Abs(x) - n`` is inverted in the real domain, then ``set_h`` is not simply `{-n, n}` as the nature of `n` is unknown; rather, it is: `Intersection([0, oo) {n}) U Intersection((-oo, 0], {-n})` By default, the complex domain is used which means that inverting even seemingly simple functions like ``exp(x)`` will give very different results from those obtained in the real domain. (In the case of ``exp(x)``, the inversion via ``log`` is multi-valued in the complex domain, having infinitely many branches.) If you are working with real values only (or you are not sure which function to use) you should probably set the domain to ``S.Reals`` (or use `invert\_real` which does that automatically). Examples ======== >>> from sympy.solvers.solveset import invert_complex, invert_real >>> from sympy.abc import x, y >>> from sympy import exp When does exp(x) == y? >>> invert_complex(exp(x), y, x) (x, ImageSet(Lambda(_n, I*(2*_n*pi + arg(y)) + log(Abs(y))), Integers)) >>> invert_real(exp(x), y, x) (x, Intersection({log(y)}, Reals)) When does exp(x) == 1? >>> invert_complex(exp(x), 1, x) (x, ImageSet(Lambda(_n, 2*_n*I*pi), Integers)) >>> invert_real(exp(x), 1, x) (x, {0}) See Also ======== invert_real, invert_complex """ x = sympify(x) if not x.is_Symbol: raise ValueError("x must be a symbol") f_x = sympify(f_x) if x not in f_x.free_symbols: raise ValueError("Inverse of constant function doesn't exist") y = sympify(y) if x in y.free_symbols: raise ValueError("y should be independent of x ") if domain.is_subset(S.Reals): x1, s = _invert_real(f_x, FiniteSet(y), x) else: x1, s = _invert_complex(f_x, FiniteSet(y), x) if not isinstance(s, FiniteSet) or x1 != x: return x1, s # Avoid adding gratuitous intersections with S.Complexes. Actual # conditions should be handled by the respective inverters. if domain is S.Complexes: return x1, s else: return x1, s.intersection(domain) invert_complex = _invert def invert_real(f_x, y, x, domain=S.Reals): """ Inverts a real-valued function. Same as _invert, but sets the domain to ``S.Reals`` before inverting. """ return _invert(f_x, y, x, domain) def _invert_real(f, g_ys, symbol): """Helper function for _invert.""" if f == symbol: return (f, g_ys) n = Dummy('n', real=True) if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1): return _invert_real(f.exp, imageset(Lambda(n, log(n)), g_ys), symbol) if hasattr(f, 'inverse') and f.inverse() is not None and not isinstance(f, ( TrigonometricFunction, HyperbolicFunction, )): if len(f.args) > 1: raise ValueError("Only functions with one argument are supported.") return _invert_real(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) if isinstance(f, Abs): return _invert_abs(f.args[0], g_ys, symbol) if f.is_Add: # f = g + h g, h = f.as_independent(symbol) if g is not S.Zero: return _invert_real(h, imageset(Lambda(n, n - g), g_ys), symbol) if f.is_Mul: # f = g*h g, h = f.as_independent(symbol) if g is not S.One: return _invert_real(h, imageset(Lambda(n, n/g), g_ys), symbol) if f.is_Pow: base, expo = f.args base_has_sym = base.has(symbol) expo_has_sym = expo.has(symbol) if not expo_has_sym: if expo.is_rational: num, den = expo.as_numer_denom() if den % 2 == 0 and num % 2 == 1 and den.is_zero is False: root = Lambda(n, real_root(n, expo)) g_ys_pos = g_ys & Interval(0, oo) res = imageset(root, g_ys_pos) base_positive = solveset(base >= 0, symbol, S.Reals) _inv, _set = _invert_real(base, res, symbol) return (_inv, _set.intersect(base_positive)) if den % 2 == 1: root = Lambda(n, real_root(n, expo)) res = imageset(root, g_ys) if num % 2 == 0: neg_res = imageset(Lambda(n, -n), res) return _invert_real(base, res + neg_res, symbol) if num % 2 == 1: return _invert_real(base, res, symbol) elif expo.is_irrational: root = Lambda(n, real_root(n, expo)) g_ys_pos = g_ys & Interval(0, oo) res = imageset(root, g_ys_pos) return _invert_real(base, res, symbol) else: # indeterminate exponent, e.g. Float or parity of # num, den of rational could not be determined pass # use default return if not base_has_sym: rhs = g_ys.args[0] if base.is_positive: return _invert_real(expo, imageset(Lambda(n, log(n, base, evaluate=False)), g_ys), symbol) elif base.is_negative: from sympy.core.power import integer_log s, b = integer_log(rhs, base) if b: return _invert_real(expo, FiniteSet(s), symbol) else: return _invert_real(expo, S.EmptySet, symbol) elif base.is_zero: one = Eq(rhs, 1) if one == S.true: # special case: 0**x - 1 return _invert_real(expo, FiniteSet(0), symbol) elif one == S.false: return _invert_real(expo, S.EmptySet, symbol) if isinstance(f, TrigonometricFunction): if isinstance(g_ys, FiniteSet): def inv(trig): if isinstance(f, (sin, csc)): F = asin if isinstance(f, sin) else acsc return (lambda a: n*pi + (-1)**n*F(a),) if isinstance(f, (cos, sec)): F = acos if isinstance(f, cos) else asec return ( lambda a: 2*n*pi + F(a), lambda a: 2*n*pi - F(a),) if isinstance(f, (tan, cot)): return (lambda a: n*pi + f.inverse()(a),) n = Dummy('n', integer=True) invs = S.EmptySet for L in inv(f): invs += Union(*[imageset(Lambda(n, L(g)), S.Integers) for g in g_ys]) return _invert_real(f.args[0], invs, symbol) return (f, g_ys) def _invert_complex(f, g_ys, symbol): """Helper function for _invert.""" if f == symbol: return (f, g_ys) n = Dummy('n') if f.is_Add: # f = g + h g, h = f.as_independent(symbol) if g is not S.Zero: return _invert_complex(h, imageset(Lambda(n, n - g), g_ys), symbol) if f.is_Mul: # f = g*h g, h = f.as_independent(symbol) if g is not S.One: if g in {S.NegativeInfinity, S.ComplexInfinity, S.Infinity}: return (h, S.EmptySet) return _invert_complex(h, imageset(Lambda(n, n/g), g_ys), symbol) if f.is_Pow: base, expo = f.args # special case: g**r = 0 # Could be improved like `_invert_real` to handle more general cases. if expo.is_Rational and g_ys == FiniteSet(0): if expo.is_positive: return _invert_complex(base, g_ys, symbol) if hasattr(f, 'inverse') and f.inverse() is not None and \ not isinstance(f, TrigonometricFunction) and \ not isinstance(f, HyperbolicFunction) and \ not isinstance(f, exp): if len(f.args) > 1: raise ValueError("Only functions with one argument are supported.") return _invert_complex(f.args[0], imageset(Lambda(n, f.inverse()(n)), g_ys), symbol) if isinstance(f, exp) or (f.is_Pow and f.base == S.Exp1): if isinstance(g_ys, ImageSet): # can solve upto `(d*exp(exp(...(exp(a*x + b))...) + c)` format. # Further can be improved to `(d*exp(exp(...(exp(a*x**n + b*x**(n-1) + ... + f))...) + c)`. g_ys_expr = g_ys.lamda.expr g_ys_vars = g_ys.lamda.variables k = Dummy('k{}'.format(len(g_ys_vars))) g_ys_vars_1 = (k,) + g_ys_vars exp_invs = Union(*[imageset(Lambda((g_ys_vars_1,), (I*(2*k*pi + arg(g_ys_expr)) + log(Abs(g_ys_expr)))), S.Integers**(len(g_ys_vars_1)))]) elif isinstance(g_ys, FiniteSet): exp_invs = Union(*[imageset(Lambda(n, I*(2*n*pi + arg(g_y)) + log(Abs(g_y))), S.Integers) for g_y in g_ys if g_y != 0]) return _invert_complex(f.exp, exp_invs, symbol) return (f, g_ys) def _invert_abs(f, g_ys, symbol): """Helper function for inverting absolute value functions. Returns the complete result of inverting an absolute value function along with the conditions which must also be satisfied. If it is certain that all these conditions are met, a `FiniteSet` of all possible solutions is returned. If any condition cannot be satisfied, an `EmptySet` is returned. Otherwise, a `ConditionSet` of the solutions, with all the required conditions specified, is returned. """ if not g_ys.is_FiniteSet: # this could be used for FiniteSet, but the # results are more compact if they aren't, e.g. # ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n}) vs # Union(Intersection(Interval(0, oo), {n}), Intersection(Interval(-oo, 0), {-n})) # for the solution of abs(x) - n pos = Intersection(g_ys, Interval(0, S.Infinity)) parg = _invert_real(f, pos, symbol) narg = _invert_real(-f, pos, symbol) if parg[0] != narg[0]: raise NotImplementedError return parg[0], Union(narg[1], parg[1]) # check conditions: all these must be true. If any are unknown # then return them as conditions which must be satisfied unknown = [] for a in g_ys.args: ok = a.is_nonnegative if a.is_Number else a.is_positive if ok is None: unknown.append(a) elif not ok: return symbol, S.EmptySet if unknown: conditions = And(*[Contains(i, Interval(0, oo)) for i in unknown]) else: conditions = True n = Dummy('n', real=True) # this is slightly different than above: instead of solving # +/-f on positive values, here we solve for f on +/- g_ys g_x, values = _invert_real(f, Union( imageset(Lambda(n, n), g_ys), imageset(Lambda(n, -n), g_ys)), symbol) return g_x, ConditionSet(g_x, conditions, values) def domain_check(f, symbol, p): """Returns False if point p is infinite or any subexpression of f is infinite or becomes so after replacing symbol with p. If none of these conditions is met then True will be returned. Examples ======== >>> from sympy import Mul, oo >>> from sympy.abc import x >>> from sympy.solvers.solveset import domain_check >>> g = 1/(1 + (1/(x + 1))**2) >>> domain_check(g, x, -1) False >>> domain_check(x**2, x, 0) True >>> domain_check(1/x, x, oo) False * The function relies on the assumption that the original form of the equation has not been changed by automatic simplification. >>> domain_check(x/x, x, 0) # x/x is automatically simplified to 1 True * To deal with automatic evaluations use evaluate=False: >>> domain_check(Mul(x, 1/x, evaluate=False), x, 0) False """ f, p = sympify(f), sympify(p) if p.is_infinite: return False return _domain_check(f, symbol, p) def _domain_check(f, symbol, p): # helper for domain check if f.is_Atom and f.is_finite: return True elif f.subs(symbol, p).is_infinite: return False elif isinstance(f, Piecewise): # Check the cases of the Piecewise in turn. There might be invalid # expressions in later cases that don't apply e.g. # solveset(Piecewise((0, Eq(x, 0)), (1/x, True)), x) for expr, cond in f.args: condsubs = cond.subs(symbol, p) if condsubs is S.false: continue elif condsubs is S.true: return _domain_check(expr, symbol, p) else: # We don't know which case of the Piecewise holds. On this # basis we cannot decide whether any solution is in or out of # the domain. Ideally this function would allow returning a # symbolic condition for the validity of the solution that # could be handled in the calling code. In the mean time we'll # give this particular solution the benefit of the doubt and # let it pass. return True else: # TODO : We should not blindly recurse through all args of arbitrary expressions like this return all([_domain_check(g, symbol, p) for g in f.args]) def _is_finite_with_finite_vars(f, domain=S.Complexes): """ Return True if the given expression is finite. For symbols that don't assign a value for `complex` and/or `real`, the domain will be used to assign a value; symbols that don't assign a value for `finite` will be made finite. All other assumptions are left unmodified. """ def assumptions(s): A = s.assumptions0 A.setdefault('finite', A.get('finite', True)) if domain.is_subset(S.Reals): # if this gets set it will make complex=True, too A.setdefault('real', True) else: # don't change 'real' because being complex implies # nothing about being real A.setdefault('complex', True) return A reps = {s: Dummy(**assumptions(s)) for s in f.free_symbols} return f.xreplace(reps).is_finite def _is_function_class_equation(func_class, f, symbol): """ Tests whether the equation is an equation of the given function class. The given equation belongs to the given function class if it is comprised of functions of the function class which are multiplied by or added to expressions independent of the symbol. In addition, the arguments of all such functions must be linear in the symbol as well. Examples ======== >>> from sympy.solvers.solveset import _is_function_class_equation >>> from sympy import tan, sin, tanh, sinh, exp >>> from sympy.abc import x >>> from sympy.functions.elementary.trigonometric import (TrigonometricFunction, ... HyperbolicFunction) >>> _is_function_class_equation(TrigonometricFunction, exp(x) + tan(x), x) False >>> _is_function_class_equation(TrigonometricFunction, tan(x) + sin(x), x) True >>> _is_function_class_equation(TrigonometricFunction, tan(x**2), x) False >>> _is_function_class_equation(TrigonometricFunction, tan(x + 2), x) True >>> _is_function_class_equation(HyperbolicFunction, tanh(x) + sinh(x), x) True """ if f.is_Mul or f.is_Add: return all(_is_function_class_equation(func_class, arg, symbol) for arg in f.args) if f.is_Pow: if not f.exp.has(symbol): return _is_function_class_equation(func_class, f.base, symbol) else: return False if not f.has(symbol): return True if isinstance(f, func_class): try: g = Poly(f.args[0], symbol) return g.degree() <= 1 except PolynomialError: return False else: return False def _solve_as_rational(f, symbol, domain): """ solve rational functions""" from sympy.core.function import _mexpand f = together(_mexpand(f, recursive=True), deep=True) g, h = fraction(f) if not h.has(symbol): try: return _solve_as_poly(g, symbol, domain) except NotImplementedError: # The polynomial formed from g could end up having # coefficients in a ring over which finding roots # isn't implemented yet, e.g. ZZ[a] for some symbol a return ConditionSet(symbol, Eq(f, 0), domain) except CoercionFailed: # contained oo, zoo or nan return S.EmptySet else: valid_solns = _solveset(g, symbol, domain) invalid_solns = _solveset(h, symbol, domain) return valid_solns - invalid_solns class _SolveTrig1Error(Exception): """Raised when _solve_trig1 heuristics do not apply""" def _solve_trig(f, symbol, domain): """Function to call other helpers to solve trigonometric equations """ sol = None try: sol = _solve_trig1(f, symbol, domain) except _SolveTrig1Error: try: sol = _solve_trig2(f, symbol, domain) except ValueError: raise NotImplementedError(filldedent(''' Solution to this kind of trigonometric equations is yet to be implemented''')) return sol def _solve_trig1(f, symbol, domain): """Primary solver for trigonometric and hyperbolic equations Returns either the solution set as a ConditionSet (auto-evaluated to a union of ImageSets if no variables besides 'symbol' are involved) or raises _SolveTrig1Error if f == 0 can't be solved. Notes ===== Algorithm: 1. Do a change of variable x -> mu*x in arguments to trigonometric and hyperbolic functions, in order to reduce them to small integers. (This step is crucial to keep the degrees of the polynomials of step 4 low.) 2. Rewrite trigonometric/hyperbolic functions as exponentials. 3. Proceed to a 2nd change of variable, replacing exp(I*x) or exp(x) by y. 4. Solve the resulting rational equation. 5. Use invert_complex or invert_real to return to the original variable. 6. If the coefficients of 'symbol' were symbolic in nature, add the necessary consistency conditions in a ConditionSet. """ # Prepare change of variable x = Dummy('x') if _is_function_class_equation(HyperbolicFunction, f, symbol): cov = exp(x) inverter = invert_real if domain.is_subset(S.Reals) else invert_complex else: cov = exp(I*x) inverter = invert_complex f = trigsimp(f) f_original = f trig_functions = f.atoms(TrigonometricFunction, HyperbolicFunction) trig_arguments = [e.args[0] for e in trig_functions] # trigsimp may have reduced the equation to an expression # that is independent of 'symbol' (e.g. cos**2+sin**2) if not any(a.has(symbol) for a in trig_arguments): return solveset(f_original, symbol, domain) denominators = [] numerators = [] for ar in trig_arguments: try: poly_ar = Poly(ar, symbol) except PolynomialError: raise _SolveTrig1Error("trig argument is not a polynomial") if poly_ar.degree() > 1: # degree >1 still bad raise _SolveTrig1Error("degree of variable must not exceed one") if poly_ar.degree() == 0: # degree 0, don't care continue c = poly_ar.all_coeffs()[0] # got the coefficient of 'symbol' numerators.append(fraction(c)[0]) denominators.append(fraction(c)[1]) mu = lcm(denominators)/gcd(numerators) f = f.subs(symbol, mu*x) f = f.rewrite(exp) f = together(f) g, h = fraction(f) y = Dummy('y') g, h = g.expand(), h.expand() g, h = g.subs(cov, y), h.subs(cov, y) if g.has(x) or h.has(x): raise _SolveTrig1Error("change of variable not possible") solns = solveset_complex(g, y) - solveset_complex(h, y) if isinstance(solns, ConditionSet): raise _SolveTrig1Error("polynomial has ConditionSet solution") if isinstance(solns, FiniteSet): if any(isinstance(s, RootOf) for s in solns): raise _SolveTrig1Error("polynomial results in RootOf object") # revert the change of variable cov = cov.subs(x, symbol/mu) result = Union(*[inverter(cov, s, symbol)[1] for s in solns]) # In case of symbolic coefficients, the solution set is only valid # if numerator and denominator of mu are non-zero. if mu.has(Symbol): syms = (mu).atoms(Symbol) munum, muden = fraction(mu) condnum = munum.as_independent(*syms, as_Add=False)[1] condden = muden.as_independent(*syms, as_Add=False)[1] cond = And(Ne(condnum, 0), Ne(condden, 0)) else: cond = True # Actual conditions are returned as part of the ConditionSet. Adding an # intersection with C would only complicate some solution sets due to # current limitations of intersection code. (e.g. #19154) if domain is S.Complexes: # This is a slight abuse of ConditionSet. Ideally this should # be some kind of "PiecewiseSet". (See #19507 discussion) return ConditionSet(symbol, cond, result) else: return ConditionSet(symbol, cond, Intersection(result, domain)) elif solns is S.EmptySet: return S.EmptySet else: raise _SolveTrig1Error("polynomial solutions must form FiniteSet") def _solve_trig2(f, symbol, domain): """Secondary helper to solve trigonometric equations, called when first helper fails """ from sympy import ilcm, expand_trig, degree f = trigsimp(f) f_original = f trig_functions = f.atoms(sin, cos, tan, sec, cot, csc) trig_arguments = [e.args[0] for e in trig_functions] denominators = [] numerators = [] # todo: This solver can be extended to hyperbolics if the # analogous change of variable to tanh (instead of tan) # is used. if not trig_functions: return ConditionSet(symbol, Eq(f_original, 0), domain) # todo: The pre-processing below (extraction of numerators, denominators, # gcd, lcm, mu, etc.) should be updated to the enhanced version in # _solve_trig1. (See #19507) for ar in trig_arguments: try: poly_ar = Poly(ar, symbol) except PolynomialError: raise ValueError("give up, we can't solve if this is not a polynomial in x") if poly_ar.degree() > 1: # degree >1 still bad raise ValueError("degree of variable inside polynomial should not exceed one") if poly_ar.degree() == 0: # degree 0, don't care continue c = poly_ar.all_coeffs()[0] # got the coefficient of 'symbol' try: numerators.append(Rational(c).p) denominators.append(Rational(c).q) except TypeError: return ConditionSet(symbol, Eq(f_original, 0), domain) x = Dummy('x') # ilcm() and igcd() require more than one argument if len(numerators) > 1: mu = Rational(2)*ilcm(*denominators)/igcd(*numerators) else: assert len(numerators) == 1 mu = Rational(2)*denominators[0]/numerators[0] f = f.subs(symbol, mu*x) f = f.rewrite(tan) f = expand_trig(f) f = together(f) g, h = fraction(f) y = Dummy('y') g, h = g.expand(), h.expand() g, h = g.subs(tan(x), y), h.subs(tan(x), y) if g.has(x) or h.has(x): return ConditionSet(symbol, Eq(f_original, 0), domain) solns = solveset(g, y, S.Reals) - solveset(h, y, S.Reals) if isinstance(solns, FiniteSet): result = Union(*[invert_real(tan(symbol/mu), s, symbol)[1] for s in solns]) dsol = invert_real(tan(symbol/mu), oo, symbol)[1] if degree(h) > degree(g): # If degree(denom)>degree(num) then there result = Union(result, dsol) # would be another sol at Lim(denom-->oo) return Intersection(result, domain) elif solns is S.EmptySet: return S.EmptySet else: return ConditionSet(symbol, Eq(f_original, 0), S.Reals) def _solve_as_poly(f, symbol, domain=S.Complexes): """ Solve the equation using polynomial techniques if it already is a polynomial equation or, with a change of variables, can be made so. """ result = None if f.is_polynomial(symbol): solns = roots(f, symbol, cubics=True, quartics=True, quintics=True, domain='EX') num_roots = sum(solns.values()) if degree(f, symbol) <= num_roots: result = FiniteSet(*solns.keys()) else: poly = Poly(f, symbol) solns = poly.all_roots() if poly.degree() <= len(solns): result = FiniteSet(*solns) else: result = ConditionSet(symbol, Eq(f, 0), domain) else: poly = Poly(f) if poly is None: result = ConditionSet(symbol, Eq(f, 0), domain) gens = [g for g in poly.gens if g.has(symbol)] if len(gens) == 1: poly = Poly(poly, gens[0]) gen = poly.gen deg = poly.degree() poly = Poly(poly.as_expr(), poly.gen, composite=True) poly_solns = FiniteSet(*roots(poly, cubics=True, quartics=True, quintics=True).keys()) if len(poly_solns) < deg: result = ConditionSet(symbol, Eq(f, 0), domain) if gen != symbol: y = Dummy('y') inverter = invert_real if domain.is_subset(S.Reals) else invert_complex lhs, rhs_s = inverter(gen, y, symbol) if lhs == symbol: result = Union(*[rhs_s.subs(y, s) for s in poly_solns]) else: result = ConditionSet(symbol, Eq(f, 0), domain) else: result = ConditionSet(symbol, Eq(f, 0), domain) if result is not None: if isinstance(result, FiniteSet): # this is to simplify solutions like -sqrt(-I) to sqrt(2)/2 # - sqrt(2)*I/2. We are not expanding for solution with symbols # or undefined functions because that makes the solution more complicated. # For example, expand_complex(a) returns re(a) + I*im(a) if all([s.atoms(Symbol, AppliedUndef) == set() and not isinstance(s, RootOf) for s in result]): s = Dummy('s') result = imageset(Lambda(s, expand_complex(s)), result) if isinstance(result, FiniteSet) and domain != S.Complexes: # Avoid adding gratuitous intersections with S.Complexes. Actual # conditions should be handled elsewhere. result = result.intersection(domain) return result else: return ConditionSet(symbol, Eq(f, 0), domain) def _solve_radical(f, unradf, symbol, solveset_solver): """ Helper function to solve equations with radicals """ res = unradf eq, cov = res if res else (f, []) if not cov: result = solveset_solver(eq, symbol) - \ Union(*[solveset_solver(g, symbol) for g in denoms(f, symbol)]) else: y, yeq = cov if not solveset_solver(y - I, y): yreal = Dummy('yreal', real=True) yeq = yeq.xreplace({y: yreal}) eq = eq.xreplace({y: yreal}) y = yreal g_y_s = solveset_solver(yeq, symbol) f_y_sols = solveset_solver(eq, y) result = Union(*[imageset(Lambda(y, g_y), f_y_sols) for g_y in g_y_s]) if not isinstance(result, FiniteSet): solution_set = result else: f_set = [] # solutions for FiniteSet c_set = [] # solutions for ConditionSet for s in result: if checksol(f, symbol, s): f_set.append(s) else: c_set.append(s) solution_set = FiniteSet(*f_set) + ConditionSet(symbol, Eq(f, 0), FiniteSet(*c_set)) return solution_set def _solve_abs(f, symbol, domain): """ Helper function to solve equation involving absolute value function """ if not domain.is_subset(S.Reals): raise ValueError(filldedent(''' Absolute values cannot be inverted in the complex domain.''')) p, q, r = Wild('p'), Wild('q'), Wild('r') pattern_match = f.match(p*Abs(q) + r) or {} f_p, f_q, f_r = [pattern_match.get(i, S.Zero) for i in (p, q, r)] if not (f_p.is_zero or f_q.is_zero): domain = continuous_domain(f_q, symbol, domain) q_pos_cond = solve_univariate_inequality(f_q >= 0, symbol, relational=False, domain=domain, continuous=True) q_neg_cond = q_pos_cond.complement(domain) sols_q_pos = solveset_real(f_p*f_q + f_r, symbol).intersect(q_pos_cond) sols_q_neg = solveset_real(f_p*(-f_q) + f_r, symbol).intersect(q_neg_cond) return Union(sols_q_pos, sols_q_neg) else: return ConditionSet(symbol, Eq(f, 0), domain) def solve_decomposition(f, symbol, domain): """ Function to solve equations via the principle of "Decomposition and Rewriting". Examples ======== >>> from sympy import exp, sin, Symbol, pprint, S >>> from sympy.solvers.solveset import solve_decomposition as sd >>> x = Symbol('x') >>> f1 = exp(2*x) - 3*exp(x) + 2 >>> sd(f1, x, S.Reals) {0, log(2)} >>> f2 = sin(x)**2 + 2*sin(x) + 1 >>> pprint(sd(f2, x, S.Reals), use_unicode=False) 3*pi {2*n*pi + ---- | n in Integers} 2 >>> f3 = sin(x + 2) >>> pprint(sd(f3, x, S.Reals), use_unicode=False) {2*n*pi - 2 | n in Integers} U {2*n*pi - 2 + pi | n in Integers} """ from sympy.solvers.decompogen import decompogen from sympy.calculus.util import function_range # decompose the given function g_s = decompogen(f, symbol) # `y_s` represents the set of values for which the function `g` is to be # solved. # `solutions` represent the solutions of the equations `g = y_s` or # `g = 0` depending on the type of `y_s`. # As we are interested in solving the equation: f = 0 y_s = FiniteSet(0) for g in g_s: frange = function_range(g, symbol, domain) y_s = Intersection(frange, y_s) result = S.EmptySet if isinstance(y_s, FiniteSet): for y in y_s: solutions = solveset(Eq(g, y), symbol, domain) if not isinstance(solutions, ConditionSet): result += solutions else: if isinstance(y_s, ImageSet): iter_iset = (y_s,) elif isinstance(y_s, Union): iter_iset = y_s.args elif y_s is EmptySet: # y_s is not in the range of g in g_s, so no solution exists #in the given domain return EmptySet for iset in iter_iset: new_solutions = solveset(Eq(iset.lamda.expr, g), symbol, domain) dummy_var = tuple(iset.lamda.expr.free_symbols)[0] (base_set,) = iset.base_sets if isinstance(new_solutions, FiniteSet): new_exprs = new_solutions elif isinstance(new_solutions, Intersection): if isinstance(new_solutions.args[1], FiniteSet): new_exprs = new_solutions.args[1] for new_expr in new_exprs: result += ImageSet(Lambda(dummy_var, new_expr), base_set) if result is S.EmptySet: return ConditionSet(symbol, Eq(f, 0), domain) y_s = result return y_s def _solveset(f, symbol, domain, _check=False): """Helper for solveset to return a result from an expression that has already been sympify'ed and is known to contain the given symbol.""" # _check controls whether the answer is checked or not from sympy.simplify.simplify import signsimp from sympy.logic.boolalg import BooleanTrue if isinstance(f, BooleanTrue): return domain orig_f = f if f.is_Mul: coeff, f = f.as_independent(symbol, as_Add=False) if coeff in {S.ComplexInfinity, S.NegativeInfinity, S.Infinity}: f = together(orig_f) elif f.is_Add: a, h = f.as_independent(symbol) m, h = h.as_independent(symbol, as_Add=False) if m not in {S.ComplexInfinity, S.Zero, S.Infinity, S.NegativeInfinity}: f = a/m + h # XXX condition `m != 0` should be added to soln # assign the solvers to use solver = lambda f, x, domain=domain: _solveset(f, x, domain) inverter = lambda f, rhs, symbol: _invert(f, rhs, symbol, domain) result = EmptySet if f.expand().is_zero: return domain elif not f.has(symbol): return EmptySet elif f.is_Mul and all(_is_finite_with_finite_vars(m, domain) for m in f.args): # if f(x) and g(x) are both finite we can say that the solution of # f(x)*g(x) == 0 is same as Union(f(x) == 0, g(x) == 0) is not true in # general. g(x) can grow to infinitely large for the values where # f(x) == 0. To be sure that we are not silently allowing any # wrong solutions we are using this technique only if both f and g are # finite for a finite input. result = Union(*[solver(m, symbol) for m in f.args]) elif _is_function_class_equation(TrigonometricFunction, f, symbol) or \ _is_function_class_equation(HyperbolicFunction, f, symbol): result = _solve_trig(f, symbol, domain) elif isinstance(f, arg): a = f.args[0] result = solveset_real(a > 0, symbol) elif f.is_Piecewise: expr_set_pairs = f.as_expr_set_pairs(domain) for (expr, in_set) in expr_set_pairs: if in_set.is_Relational: in_set = in_set.as_set() solns = solver(expr, symbol, in_set) result += solns elif isinstance(f, Eq): result = solver(Add(f.lhs, - f.rhs, evaluate=False), symbol, domain) elif f.is_Relational: try: result = solve_univariate_inequality( f, symbol, domain=domain, relational=False) except NotImplementedError: result = ConditionSet(symbol, f, domain) return result elif _is_modular(f, symbol): result = _solve_modular(f, symbol, domain) else: lhs, rhs_s = inverter(f, 0, symbol) if lhs == symbol: # do some very minimal simplification since # repeated inversion may have left the result # in a state that other solvers (e.g. poly) # would have simplified; this is done here # rather than in the inverter since here it # is only done once whereas there it would # be repeated for each step of the inversion if isinstance(rhs_s, FiniteSet): rhs_s = FiniteSet(*[Mul(* signsimp(i).as_content_primitive()) for i in rhs_s]) result = rhs_s elif isinstance(rhs_s, FiniteSet): for equation in [lhs - rhs for rhs in rhs_s]: if equation == f: u = unrad(f, symbol) if u: result += _solve_radical(equation, u, symbol, solver) elif equation.has(Abs): result += _solve_abs(f, symbol, domain) else: result_rational = _solve_as_rational(equation, symbol, domain) if not isinstance(result_rational, ConditionSet): result += result_rational else: # may be a transcendental type equation t_result = _transolve(equation, symbol, domain) if isinstance(t_result, ConditionSet): # might need factoring; this is expensive so we # have delayed until now. To avoid recursion # errors look for a non-trivial factoring into # a product of symbol dependent terms; I think # that something that factors as a Pow would # have already been recognized by now. factored = equation.factor() if factored.is_Mul and equation != factored: _, dep = factored.as_independent(symbol) if not dep.is_Add: # non-trivial factoring of equation # but use form with constants # in case they need special handling t_result = solver(factored, symbol) result += t_result else: result += solver(equation, symbol) elif rhs_s is not S.EmptySet: result = ConditionSet(symbol, Eq(f, 0), domain) if isinstance(result, ConditionSet): if isinstance(f, Expr): num, den = f.as_numer_denom() else: num, den = f, S.One if den.has(symbol): _result = _solveset(num, symbol, domain) if not isinstance(_result, ConditionSet): singularities = _solveset(den, symbol, domain) result = _result - singularities if _check: if isinstance(result, ConditionSet): # it wasn't solved or has enumerated all conditions # -- leave it alone return result # whittle away all but the symbol-containing core # to use this for testing if isinstance(orig_f, Expr): fx = orig_f.as_independent(symbol, as_Add=True)[1] fx = fx.as_independent(symbol, as_Add=False)[1] else: fx = orig_f if isinstance(result, FiniteSet): # check the result for invalid solutions result = FiniteSet(*[s for s in result if isinstance(s, RootOf) or domain_check(fx, symbol, s)]) return result def _is_modular(f, symbol): """ Helper function to check below mentioned types of modular equations. ``A - Mod(B, C) = 0`` A -> This can or cannot be a function of symbol. B -> This is surely a function of symbol. C -> It is an integer. Parameters ========== f : Expr The equation to be checked. symbol : Symbol The concerned variable for which the equation is to be checked. Examples ======== >>> from sympy import symbols, exp, Mod >>> from sympy.solvers.solveset import _is_modular as check >>> x, y = symbols('x y') >>> check(Mod(x, 3) - 1, x) True >>> check(Mod(x, 3) - 1, y) False >>> check(Mod(x, 3)**2 - 5, x) False >>> check(Mod(x, 3)**2 - y, x) False >>> check(exp(Mod(x, 3)) - 1, x) False >>> check(Mod(3, y) - 1, y) False """ if not f.has(Mod): return False # extract modterms from f. modterms = list(f.atoms(Mod)) return (len(modterms) == 1 and # only one Mod should be present modterms[0].args[0].has(symbol) and # B-> function of symbol modterms[0].args[1].is_integer and # C-> to be an integer. any(isinstance(term, Mod) for term in list(_term_factors(f))) # free from other funcs ) def _invert_modular(modterm, rhs, n, symbol): """ Helper function to invert modular equation. ``Mod(a, m) - rhs = 0`` Generally it is inverted as (a, ImageSet(Lambda(n, m*n + rhs), S.Integers)). More simplified form will be returned if possible. If it is not invertible then (modterm, rhs) is returned. The following cases arise while inverting equation ``Mod(a, m) - rhs = 0``: 1. If a is symbol then m*n + rhs is the required solution. 2. If a is an instance of ``Add`` then we try to find two symbol independent parts of a and the symbol independent part gets tranferred to the other side and again the ``_invert_modular`` is called on the symbol dependent part. 3. If a is an instance of ``Mul`` then same as we done in ``Add`` we separate out the symbol dependent and symbol independent parts and transfer the symbol independent part to the rhs with the help of invert and again the ``_invert_modular`` is called on the symbol dependent part. 4. If a is an instance of ``Pow`` then two cases arise as following: - If a is of type (symbol_indep)**(symbol_dep) then the remainder is evaluated with the help of discrete_log function and then the least period is being found out with the help of totient function. period*n + remainder is the required solution in this case. For reference: (https://en.wikipedia.org/wiki/Euler's_theorem) - If a is of type (symbol_dep)**(symbol_indep) then we try to find all primitive solutions list with the help of nthroot_mod function. m*n + rem is the general solution where rem belongs to solutions list from nthroot_mod function. Parameters ========== modterm, rhs : Expr The modular equation to be inverted, ``modterm - rhs = 0`` symbol : Symbol The variable in the equation to be inverted. n : Dummy Dummy variable for output g_n. Returns ======= A tuple (f_x, g_n) is being returned where f_x is modular independent function of symbol and g_n being set of values f_x can have. Examples ======== >>> from sympy import symbols, exp, Mod, Dummy, S >>> from sympy.solvers.solveset import _invert_modular as invert_modular >>> x, y = symbols('x y') >>> n = Dummy('n') >>> invert_modular(Mod(exp(x), 7), S(5), n, x) (Mod(exp(x), 7), 5) >>> invert_modular(Mod(x, 7), S(5), n, x) (x, ImageSet(Lambda(_n, 7*_n + 5), Integers)) >>> invert_modular(Mod(3*x + 8, 7), S(5), n, x) (x, ImageSet(Lambda(_n, 7*_n + 6), Integers)) >>> invert_modular(Mod(x**4, 7), S(5), n, x) (x, EmptySet) >>> invert_modular(Mod(2**(x**2 + x + 1), 7), S(2), n, x) (x**2 + x + 1, ImageSet(Lambda(_n, 3*_n + 1), Naturals0)) """ a, m = modterm.args if rhs.is_real is False or any(term.is_real is False for term in list(_term_factors(a))): # Check for complex arguments return modterm, rhs if abs(rhs) >= abs(m): # if rhs has value greater than value of m. return symbol, EmptySet if a == symbol: return symbol, ImageSet(Lambda(n, m*n + rhs), S.Integers) if a.is_Add: # g + h = a g, h = a.as_independent(symbol) if g is not S.Zero: x_indep_term = rhs - Mod(g, m) return _invert_modular(Mod(h, m), Mod(x_indep_term, m), n, symbol) if a.is_Mul: # g*h = a g, h = a.as_independent(symbol) if g is not S.One: x_indep_term = rhs*invert(g, m) return _invert_modular(Mod(h, m), Mod(x_indep_term, m), n, symbol) if a.is_Pow: # base**expo = a base, expo = a.args if expo.has(symbol) and not base.has(symbol): # remainder -> solution independent of n of equation. # m, rhs are made coprime by dividing igcd(m, rhs) try: remainder = discrete_log(m / igcd(m, rhs), rhs, a.base) except ValueError: # log does not exist return modterm, rhs # period -> coefficient of n in the solution and also referred as # the least period of expo in which it is repeats itself. # (a**(totient(m)) - 1) divides m. Here is link of theorem: # (https://en.wikipedia.org/wiki/Euler's_theorem) period = totient(m) for p in divisors(period): # there might a lesser period exist than totient(m). if pow(a.base, p, m / igcd(m, a.base)) == 1: period = p break # recursion is not applied here since _invert_modular is currently # not smart enough to handle infinite rhs as here expo has infinite # rhs = ImageSet(Lambda(n, period*n + remainder), S.Naturals0). return expo, ImageSet(Lambda(n, period*n + remainder), S.Naturals0) elif base.has(symbol) and not expo.has(symbol): try: remainder_list = nthroot_mod(rhs, expo, m, all_roots=True) if remainder_list == []: return symbol, EmptySet except (ValueError, NotImplementedError): return modterm, rhs g_n = EmptySet for rem in remainder_list: g_n += ImageSet(Lambda(n, m*n + rem), S.Integers) return base, g_n return modterm, rhs def _solve_modular(f, symbol, domain): r""" Helper function for solving modular equations of type ``A - Mod(B, C) = 0``, where A can or cannot be a function of symbol, B is surely a function of symbol and C is an integer. Currently ``_solve_modular`` is only able to solve cases where A is not a function of symbol. Parameters ========== f : Expr The modular equation to be solved, ``f = 0`` symbol : Symbol The variable in the equation to be solved. domain : Set A set over which the equation is solved. It has to be a subset of Integers. Returns ======= A set of integer solutions satisfying the given modular equation. A ``ConditionSet`` if the equation is unsolvable. Examples ======== >>> from sympy.solvers.solveset import _solve_modular as solve_modulo >>> from sympy import S, Symbol, sin, Intersection, Interval >>> from sympy.core.mod import Mod >>> x = Symbol('x') >>> solve_modulo(Mod(5*x - 8, 7) - 3, x, S.Integers) ImageSet(Lambda(_n, 7*_n + 5), Integers) >>> solve_modulo(Mod(5*x - 8, 7) - 3, x, S.Reals) # domain should be subset of integers. ConditionSet(x, Eq(Mod(5*x + 6, 7) - 3, 0), Reals) >>> solve_modulo(-7 + Mod(x, 5), x, S.Integers) EmptySet >>> solve_modulo(Mod(12**x, 21) - 18, x, S.Integers) ImageSet(Lambda(_n, 6*_n + 2), Naturals0) >>> solve_modulo(Mod(sin(x), 7) - 3, x, S.Integers) # not solvable ConditionSet(x, Eq(Mod(sin(x), 7) - 3, 0), Integers) >>> solve_modulo(3 - Mod(x, 5), x, Intersection(S.Integers, Interval(0, 100))) Intersection(ImageSet(Lambda(_n, 5*_n + 3), Integers), Range(0, 101, 1)) """ # extract modterm and g_y from f unsolved_result = ConditionSet(symbol, Eq(f, 0), domain) modterm = list(f.atoms(Mod))[0] rhs = -S.One*(f.subs(modterm, S.Zero)) if f.as_coefficients_dict()[modterm].is_negative: # checks if coefficient of modterm is negative in main equation. rhs *= -S.One if not domain.is_subset(S.Integers): return unsolved_result if rhs.has(symbol): # TODO Case: A-> function of symbol, can be extended here # in future. return unsolved_result n = Dummy('n', integer=True) f_x, g_n = _invert_modular(modterm, rhs, n, symbol) if f_x == modterm and g_n == rhs: return unsolved_result if f_x == symbol: if domain is not S.Integers: return domain.intersect(g_n) return g_n if isinstance(g_n, ImageSet): lamda_expr = g_n.lamda.expr lamda_vars = g_n.lamda.variables base_sets = g_n.base_sets sol_set = _solveset(f_x - lamda_expr, symbol, S.Integers) if isinstance(sol_set, FiniteSet): tmp_sol = EmptySet for sol in sol_set: tmp_sol += ImageSet(Lambda(lamda_vars, sol), *base_sets) sol_set = tmp_sol else: sol_set = ImageSet(Lambda(lamda_vars, sol_set), *base_sets) return domain.intersect(sol_set) return unsolved_result def _term_factors(f): """ Iterator to get the factors of all terms present in the given equation. Parameters ========== f : Expr Equation that needs to be addressed Returns ======= Factors of all terms present in the equation. Examples ======== >>> from sympy import symbols >>> from sympy.solvers.solveset import _term_factors >>> x = symbols('x') >>> list(_term_factors(-2 - x**2 + x*(x + 1))) [-2, -1, x**2, x, x + 1] """ for add_arg in Add.make_args(f): yield from Mul.make_args(add_arg) def _solve_exponential(lhs, rhs, symbol, domain): r""" Helper function for solving (supported) exponential equations. Exponential equations are the sum of (currently) at most two terms with one or both of them having a power with a symbol-dependent exponent. For example .. math:: 5^{2x + 3} - 5^{3x - 1} .. math:: 4^{5 - 9x} - e^{2 - x} Parameters ========== lhs, rhs : Expr The exponential equation to be solved, `lhs = rhs` symbol : Symbol The variable in which the equation is solved domain : Set A set over which the equation is solved. Returns ======= A set of solutions satisfying the given equation. A ``ConditionSet`` if the equation is unsolvable or if the assumptions are not properly defined, in that case a different style of ``ConditionSet`` is returned having the solution(s) of the equation with the desired assumptions. Examples ======== >>> from sympy.solvers.solveset import _solve_exponential as solve_expo >>> from sympy import symbols, S >>> x = symbols('x', real=True) >>> a, b = symbols('a b') >>> solve_expo(2**x + 3**x - 5**x, 0, x, S.Reals) # not solvable ConditionSet(x, Eq(2**x + 3**x - 5**x, 0), Reals) >>> solve_expo(a**x - b**x, 0, x, S.Reals) # solvable but incorrect assumptions ConditionSet(x, (a > 0) & (b > 0), {0}) >>> solve_expo(3**(2*x) - 2**(x + 3), 0, x, S.Reals) {-3*log(2)/(-2*log(3) + log(2))} >>> solve_expo(2**x - 4**x, 0, x, S.Reals) {0} * Proof of correctness of the method The logarithm function is the inverse of the exponential function. The defining relation between exponentiation and logarithm is: .. math:: {\log_b x} = y \enspace if \enspace b^y = x Therefore if we are given an equation with exponent terms, we can convert every term to its corresponding logarithmic form. This is achieved by taking logarithms and expanding the equation using logarithmic identities so that it can easily be handled by ``solveset``. For example: .. math:: 3^{2x} = 2^{x + 3} Taking log both sides will reduce the equation to .. math:: (2x)\log(3) = (x + 3)\log(2) This form can be easily handed by ``solveset``. """ unsolved_result = ConditionSet(symbol, Eq(lhs - rhs, 0), domain) newlhs = powdenest(lhs) if lhs != newlhs: # it may also be advantageous to factor the new expr neweq = factor(newlhs - rhs) if neweq != (lhs - rhs): return _solveset(neweq, symbol, domain) # try again with _solveset if not (isinstance(lhs, Add) and len(lhs.args) == 2): # solving for the sum of more than two powers is possible # but not yet implemented return unsolved_result if rhs != 0: return unsolved_result a, b = list(ordered(lhs.args)) a_term = a.as_independent(symbol)[1] b_term = b.as_independent(symbol)[1] a_base, a_exp = a_term.as_base_exp() b_base, b_exp = b_term.as_base_exp() from sympy.functions.elementary.complexes import im if domain.is_subset(S.Reals): conditions = And( a_base > 0, b_base > 0, Eq(im(a_exp), 0), Eq(im(b_exp), 0)) else: conditions = And( Ne(a_base, 0), Ne(b_base, 0)) L, R = map(lambda i: expand_log(log(i), force=True), (a, -b)) solutions = _solveset(L - R, symbol, domain) return ConditionSet(symbol, conditions, solutions) def _is_exponential(f, symbol): r""" Return ``True`` if one or more terms contain ``symbol`` only in exponents, else ``False``. Parameters ========== f : Expr The equation to be checked symbol : Symbol The variable in which the equation is checked Examples ======== >>> from sympy import symbols, cos, exp >>> from sympy.solvers.solveset import _is_exponential as check >>> x, y = symbols('x y') >>> check(y, y) False >>> check(x**y - 1, y) True >>> check(x**y*2**y - 1, y) True >>> check(exp(x + 3) + 3**x, x) True >>> check(cos(2**x), x) False * Philosophy behind the helper The function extracts each term of the equation and checks if it is of exponential form w.r.t ``symbol``. """ rv = False for expr_arg in _term_factors(f): if symbol not in expr_arg.free_symbols: continue if (isinstance(expr_arg, Pow) and symbol not in expr_arg.base.free_symbols or isinstance(expr_arg, exp)): rv = True # symbol in exponent else: return False # dependent on symbol in non-exponential way return rv def _solve_logarithm(lhs, rhs, symbol, domain): r""" Helper to solve logarithmic equations which are reducible to a single instance of `\log`. Logarithmic equations are (currently) the equations that contains `\log` terms which can be reduced to a single `\log` term or a constant using various logarithmic identities. For example: .. math:: \log(x) + \log(x - 4) can be reduced to: .. math:: \log(x(x - 4)) Parameters ========== lhs, rhs : Expr The logarithmic equation to be solved, `lhs = rhs` symbol : Symbol The variable in which the equation is solved domain : Set A set over which the equation is solved. Returns ======= A set of solutions satisfying the given equation. A ``ConditionSet`` if the equation is unsolvable. Examples ======== >>> from sympy import symbols, log, S >>> from sympy.solvers.solveset import _solve_logarithm as solve_log >>> x = symbols('x') >>> f = log(x - 3) + log(x + 3) >>> solve_log(f, 0, x, S.Reals) {-sqrt(10), sqrt(10)} * Proof of correctness A logarithm is another way to write exponent and is defined by .. math:: {\log_b x} = y \enspace if \enspace b^y = x When one side of the equation contains a single logarithm, the equation can be solved by rewriting the equation as an equivalent exponential equation as defined above. But if one side contains more than one logarithm, we need to use the properties of logarithm to condense it into a single logarithm. Take for example .. math:: \log(2x) - 15 = 0 contains single logarithm, therefore we can directly rewrite it to exponential form as .. math:: x = \frac{e^{15}}{2} But if the equation has more than one logarithm as .. math:: \log(x - 3) + \log(x + 3) = 0 we use logarithmic identities to convert it into a reduced form Using, .. math:: \log(a) + \log(b) = \log(ab) the equation becomes, .. math:: \log((x - 3)(x + 3)) This equation contains one logarithm and can be solved by rewriting to exponents. """ new_lhs = logcombine(lhs, force=True) new_f = new_lhs - rhs return _solveset(new_f, symbol, domain) def _is_logarithmic(f, symbol): r""" Return ``True`` if the equation is in the form `a\log(f(x)) + b\log(g(x)) + ... + c` else ``False``. Parameters ========== f : Expr The equation to be checked symbol : Symbol The variable in which the equation is checked Returns ======= ``True`` if the equation is logarithmic otherwise ``False``. Examples ======== >>> from sympy import symbols, tan, log >>> from sympy.solvers.solveset import _is_logarithmic as check >>> x, y = symbols('x y') >>> check(log(x + 2) - log(x + 3), x) True >>> check(tan(log(2*x)), x) False >>> check(x*log(x), x) False >>> check(x + log(x), x) False >>> check(y + log(x), x) True * Philosophy behind the helper The function extracts each term and checks whether it is logarithmic w.r.t ``symbol``. """ rv = False for term in Add.make_args(f): saw_log = False for term_arg in Mul.make_args(term): if symbol not in term_arg.free_symbols: continue if isinstance(term_arg, log): if saw_log: return False # more than one log in term saw_log = True else: return False # dependent on symbol in non-log way if saw_log: rv = True return rv def _is_lambert(f, symbol): r""" If this returns ``False`` then the Lambert solver (``_solve_lambert``) will not be called. Explanation =========== Quick check for cases that the Lambert solver might be able to handle. 1. Equations containing more than two operands and `symbol`s involving any of `Pow`, `exp`, `HyperbolicFunction`,`TrigonometricFunction`, `log` terms. 2. In `Pow`, `exp` the exponent should have `symbol` whereas for `HyperbolicFunction`,`TrigonometricFunction`, `log` should contain `symbol`. 3. For `HyperbolicFunction`,`TrigonometricFunction` the number of trigonometric functions in equation should be less than number of symbols. (since `A*cos(x) + B*sin(x) - c` is not the Lambert type). Some forms of lambert equations are: 1. X**X = C 2. X*(B*log(X) + D)**A = C 3. A*log(B*X + A) + d*X = C 4. (B*X + A)*exp(d*X + g) = C 5. g*exp(B*X + h) - B*X = C 6. A*D**(E*X + g) - B*X = C 7. A*cos(X) + B*sin(X) - D*X = C 8. A*cosh(X) + B*sinh(X) - D*X = C Where X is any variable, A, B, C, D, E are any constants, g, h are linear functions or log terms. Parameters ========== f : Expr The equation to be checked symbol : Symbol The variable in which the equation is checked Returns ======= If this returns ``False`` then the Lambert solver (``_solve_lambert``) will not be called. Examples ======== >>> from sympy.solvers.solveset import _is_lambert >>> from sympy import symbols, cosh, sinh, log >>> x = symbols('x') >>> _is_lambert(3*log(x) - x*log(3), x) True >>> _is_lambert(log(log(x - 3)) + log(x-3), x) True >>> _is_lambert(cosh(x) - sinh(x), x) False >>> _is_lambert((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1), x) True See Also ======== _solve_lambert """ term_factors = list(_term_factors(f.expand())) # total number of symbols in equation no_of_symbols = len([arg for arg in term_factors if arg.has(symbol)]) # total number of trigonometric terms in equation no_of_trig = len([arg for arg in term_factors \ if arg.has(HyperbolicFunction, TrigonometricFunction)]) if f.is_Add and no_of_symbols >= 2: # `log`, `HyperbolicFunction`, `TrigonometricFunction` should have symbols # and no_of_trig < no_of_symbols lambert_funcs = (log, HyperbolicFunction, TrigonometricFunction) if any(isinstance(arg, lambert_funcs)\ for arg in term_factors if arg.has(symbol)): if no_of_trig < no_of_symbols: return True # here, `Pow`, `exp` exponent should have symbols elif any(isinstance(arg, (Pow, exp)) \ for arg in term_factors if (arg.as_base_exp()[1]).has(symbol)): return True return False def _transolve(f, symbol, domain): r""" Function to solve transcendental equations. It is a helper to ``solveset`` and should be used internally. ``_transolve`` currently supports the following class of equations: - Exponential equations - Logarithmic equations Parameters ========== f : Any transcendental equation that needs to be solved. This needs to be an expression, which is assumed to be equal to ``0``. symbol : The variable for which the equation is solved. This needs to be of class ``Symbol``. domain : A set over which the equation is solved. This needs to be of class ``Set``. Returns ======= Set A set of values for ``symbol`` for which ``f`` is equal to zero. An ``EmptySet`` is returned if ``f`` does not have solutions in respective domain. A ``ConditionSet`` is returned as unsolved object if algorithms to evaluate complete solution are not yet implemented. How to use ``_transolve`` ========================= ``_transolve`` should not be used as an independent function, because it assumes that the equation (``f``) and the ``symbol`` comes from ``solveset`` and might have undergone a few modification(s). To use ``_transolve`` as an independent function the equation (``f``) and the ``symbol`` should be passed as they would have been by ``solveset``. Examples ======== >>> from sympy.solvers.solveset import _transolve as transolve >>> from sympy.solvers.solvers import _tsolve as tsolve >>> from sympy import symbols, S, pprint >>> x = symbols('x', real=True) # assumption added >>> transolve(5**(x - 3) - 3**(2*x + 1), x, S.Reals) {-(log(3) + 3*log(5))/(-log(5) + 2*log(3))} How ``_transolve`` works ======================== ``_transolve`` uses two types of helper functions to solve equations of a particular class: Identifying helpers: To determine whether a given equation belongs to a certain class of equation or not. Returns either ``True`` or ``False``. Solving helpers: Once an equation is identified, a corresponding helper either solves the equation or returns a form of the equation that ``solveset`` might better be able to handle. * Philosophy behind the module The purpose of ``_transolve`` is to take equations which are not already polynomial in their generator(s) and to either recast them as such through a valid transformation or to solve them outright. A pair of helper functions for each class of supported transcendental functions are employed for this purpose. One identifies the transcendental form of an equation and the other either solves it or recasts it into a tractable form that can be solved by ``solveset``. For example, an equation in the form `ab^{f(x)} - cd^{g(x)} = 0` can be transformed to `\log(a) + f(x)\log(b) - \log(c) - g(x)\log(d) = 0` (under certain assumptions) and this can be solved with ``solveset`` if `f(x)` and `g(x)` are in polynomial form. How ``_transolve`` is better than ``_tsolve`` ============================================= 1) Better output ``_transolve`` provides expressions in a more simplified form. Consider a simple exponential equation >>> f = 3**(2*x) - 2**(x + 3) >>> pprint(transolve(f, x, S.Reals), use_unicode=False) -3*log(2) {------------------} -2*log(3) + log(2) >>> pprint(tsolve(f, x), use_unicode=False) / 3 \ | --------| | log(2/9)| [-log\2 /] 2) Extensible The API of ``_transolve`` is designed such that it is easily extensible, i.e. the code that solves a given class of equations is encapsulated in a helper and not mixed in with the code of ``_transolve`` itself. 3) Modular ``_transolve`` is designed to be modular i.e, for every class of equation a separate helper for identification and solving is implemented. This makes it easy to change or modify any of the method implemented directly in the helpers without interfering with the actual structure of the API. 4) Faster Computation Solving equation via ``_transolve`` is much faster as compared to ``_tsolve``. In ``solve``, attempts are made computing every possibility to get the solutions. This series of attempts makes solving a bit slow. In ``_transolve``, computation begins only after a particular type of equation is identified. How to add new class of equations ================================= Adding a new class of equation solver is a three-step procedure: - Identify the type of the equations Determine the type of the class of equations to which they belong: it could be of ``Add``, ``Pow``, etc. types. Separate internal functions are used for each type. Write identification and solving helpers and use them from within the routine for the given type of equation (after adding it, if necessary). Something like: .. code-block:: python def add_type(lhs, rhs, x): .... if _is_exponential(lhs, x): new_eq = _solve_exponential(lhs, rhs, x) .... rhs, lhs = eq.as_independent(x) if lhs.is_Add: result = add_type(lhs, rhs, x) - Define the identification helper. - Define the solving helper. Apart from this, a few other things needs to be taken care while adding an equation solver: - Naming conventions: Name of the identification helper should be as ``_is_class`` where class will be the name or abbreviation of the class of equation. The solving helper will be named as ``_solve_class``. For example: for exponential equations it becomes ``_is_exponential`` and ``_solve_expo``. - The identifying helpers should take two input parameters, the equation to be checked and the variable for which a solution is being sought, while solving helpers would require an additional domain parameter. - Be sure to consider corner cases. - Add tests for each helper. - Add a docstring to your helper that describes the method implemented. The documentation of the helpers should identify: - the purpose of the helper, - the method used to identify and solve the equation, - a proof of correctness - the return values of the helpers """ def add_type(lhs, rhs, symbol, domain): """ Helper for ``_transolve`` to handle equations of ``Add`` type, i.e. equations taking the form as ``a*f(x) + b*g(x) + .... = c``. For example: 4**x + 8**x = 0 """ result = ConditionSet(symbol, Eq(lhs - rhs, 0), domain) # check if it is exponential type equation if _is_exponential(lhs, symbol): result = _solve_exponential(lhs, rhs, symbol, domain) # check if it is logarithmic type equation elif _is_logarithmic(lhs, symbol): result = _solve_logarithm(lhs, rhs, symbol, domain) return result result = ConditionSet(symbol, Eq(f, 0), domain) # invert_complex handles the call to the desired inverter based # on the domain specified. lhs, rhs_s = invert_complex(f, 0, symbol, domain) if isinstance(rhs_s, FiniteSet): assert (len(rhs_s.args)) == 1 rhs = rhs_s.args[0] if lhs.is_Add: result = add_type(lhs, rhs, symbol, domain) else: result = rhs_s return result def solveset(f, symbol=None, domain=S.Complexes): r"""Solves a given inequality or equation with set as output Parameters ========== f : Expr or a relational. The target equation or inequality symbol : Symbol The variable for which the equation is solved domain : Set The domain over which the equation is solved Returns ======= Set A set of values for `symbol` for which `f` is True or is equal to zero. An `EmptySet` is returned if `f` is False or nonzero. A `ConditionSet` is returned as unsolved object if algorithms to evaluate complete solution are not yet implemented. `solveset` claims to be complete in the solution set that it returns. Raises ====== NotImplementedError The algorithms to solve inequalities in complex domain are not yet implemented. ValueError The input is not valid. RuntimeError It is a bug, please report to the github issue tracker. Notes ===== Python interprets 0 and 1 as False and True, respectively, but in this function they refer to solutions of an expression. So 0 and 1 return the Domain and EmptySet, respectively, while True and False return the opposite (as they are assumed to be solutions of relational expressions). See Also ======== solveset_real: solver for real domain solveset_complex: solver for complex domain Examples ======== >>> from sympy import exp, sin, Symbol, pprint, S, Eq >>> from sympy.solvers.solveset import solveset, solveset_real * The default domain is complex. Not specifying a domain will lead to the solving of the equation in the complex domain (and this is not affected by the assumptions on the symbol): >>> x = Symbol('x') >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers} >>> x = Symbol('x', real=True) >>> pprint(solveset(exp(x) - 1, x), use_unicode=False) {2*n*I*pi | n in Integers} * If you want to use `solveset` to solve the equation in the real domain, provide a real domain. (Using ``solveset_real`` does this automatically.) >>> R = S.Reals >>> x = Symbol('x') >>> solveset(exp(x) - 1, x, R) {0} >>> solveset_real(exp(x) - 1, x) {0} The solution is unaffected by assumptions on the symbol: >>> p = Symbol('p', positive=True) >>> pprint(solveset(p**2 - 4)) {-2, 2} When a conditionSet is returned, symbols with assumptions that would alter the set are replaced with more generic symbols: >>> i = Symbol('i', imaginary=True) >>> solveset(Eq(i**2 + i*sin(i), 1), i, domain=S.Reals) ConditionSet(_R, Eq(_R**2 + _R*sin(_R) - 1, 0), Reals) * Inequalities can be solved over the real domain only. Use of a complex domain leads to a NotImplementedError. >>> solveset(exp(x) > 1, x, R) Interval.open(0, oo) """ f = sympify(f) symbol = sympify(symbol) if f is S.true: return domain if f is S.false: return S.EmptySet if not isinstance(f, (Expr, Relational, Number)): raise ValueError("%s is not a valid SymPy expression" % f) if not isinstance(symbol, (Expr, Relational)) and symbol is not None: raise ValueError("%s is not a valid SymPy symbol" % (symbol,)) if not isinstance(domain, Set): raise ValueError("%s is not a valid domain" %(domain)) free_symbols = f.free_symbols if f.has(Piecewise): f = piecewise_fold(f) if symbol is None and not free_symbols: b = Eq(f, 0) if b is S.true: return domain elif b is S.false: return S.EmptySet else: raise NotImplementedError(filldedent(''' relationship between value and 0 is unknown: %s''' % b)) if symbol is None: if len(free_symbols) == 1: symbol = free_symbols.pop() elif free_symbols: raise ValueError(filldedent(''' The independent variable must be specified for a multivariate equation.''')) elif not isinstance(symbol, Symbol): f, s, swap = recast_to_symbols([f], [symbol]) # the xreplace will be needed if a ConditionSet is returned return solveset(f[0], s[0], domain).xreplace(swap) # solveset should ignore assumptions on symbols if symbol not in _rc: x = _rc[0] if domain.is_subset(S.Reals) else _rc[1] rv = solveset(f.xreplace({symbol: x}), x, domain) # try to use the original symbol if possible try: _rv = rv.xreplace({x: symbol}) except TypeError: _rv = rv if rv.dummy_eq(_rv): rv = _rv return rv # Abs has its own handling method which avoids the # rewriting property that the first piece of abs(x) # is for x >= 0 and the 2nd piece for x < 0 -- solutions # can look better if the 2nd condition is x <= 0. Since # the solution is a set, duplication of results is not # an issue, e.g. {y, -y} when y is 0 will be {0} f, mask = _masked(f, Abs) f = f.rewrite(Piecewise) # everything that's not an Abs for d, e in mask: # everything *in* an Abs e = e.func(e.args[0].rewrite(Piecewise)) f = f.xreplace({d: e}) f = piecewise_fold(f) return _solveset(f, symbol, domain, _check=True) def solveset_real(f, symbol): return solveset(f, symbol, S.Reals) def solveset_complex(f, symbol): return solveset(f, symbol, S.Complexes) def _solveset_multi(eqs, syms, domains): '''Basic implementation of a multivariate solveset. For internal use (not ready for public consumption)''' rep = {} for sym, dom in zip(syms, domains): if dom is S.Reals: rep[sym] = Symbol(sym.name, real=True) eqs = [eq.subs(rep) for eq in eqs] syms = [sym.subs(rep) for sym in syms] syms = tuple(syms) if len(eqs) == 0: return ProductSet(*domains) if len(syms) == 1: sym = syms[0] domain = domains[0] solsets = [solveset(eq, sym, domain) for eq in eqs] solset = Intersection(*solsets) return ImageSet(Lambda((sym,), (sym,)), solset).doit() eqs = sorted(eqs, key=lambda eq: len(eq.free_symbols & set(syms))) for n in range(len(eqs)): sols = [] all_handled = True for sym in syms: if sym not in eqs[n].free_symbols: continue sol = solveset(eqs[n], sym, domains[syms.index(sym)]) if isinstance(sol, FiniteSet): i = syms.index(sym) symsp = syms[:i] + syms[i+1:] domainsp = domains[:i] + domains[i+1:] eqsp = eqs[:n] + eqs[n+1:] for s in sol: eqsp_sub = [eq.subs(sym, s) for eq in eqsp] sol_others = _solveset_multi(eqsp_sub, symsp, domainsp) fun = Lambda((symsp,), symsp[:i] + (s,) + symsp[i:]) sols.append(ImageSet(fun, sol_others).doit()) else: all_handled = False if all_handled: return Union(*sols) def solvify(f, symbol, domain): """Solves an equation using solveset and returns the solution in accordance with the `solve` output API. Returns ======= We classify the output based on the type of solution returned by `solveset`. Solution | Output ---------------------------------------- FiniteSet | list ImageSet, | list (if `f` is periodic) Union | Union | list (with FiniteSet) EmptySet | empty list Others | None Raises ====== NotImplementedError A ConditionSet is the input. Examples ======== >>> from sympy.solvers.solveset import solvify >>> from sympy.abc import x >>> from sympy import S, tan, sin, exp >>> solvify(x**2 - 9, x, S.Reals) [-3, 3] >>> solvify(sin(x) - 1, x, S.Reals) [pi/2] >>> solvify(tan(x), x, S.Reals) [0] >>> solvify(exp(x) - 1, x, S.Complexes) >>> solvify(exp(x) - 1, x, S.Reals) [0] """ solution_set = solveset(f, symbol, domain) result = None if solution_set is S.EmptySet: result = [] elif isinstance(solution_set, ConditionSet): raise NotImplementedError('solveset is unable to solve this equation.') elif isinstance(solution_set, FiniteSet): result = list(solution_set) else: period = periodicity(f, symbol) if period is not None: solutions = S.EmptySet iter_solutions = () if isinstance(solution_set, ImageSet): iter_solutions = (solution_set,) elif isinstance(solution_set, Union): if all(isinstance(i, ImageSet) for i in solution_set.args): iter_solutions = solution_set.args for solution in iter_solutions: solutions += solution.intersect(Interval(0, period, False, True)) if isinstance(solutions, FiniteSet): result = list(solutions) else: solution = solution_set.intersect(domain) if isinstance(solution, Union): # concerned about only FiniteSet with Union but not about ImageSet # if required could be extend if any(isinstance(i, FiniteSet) for i in solution.args): result = [sol for soln in solution.args \ for sol in soln.args if isinstance(soln,FiniteSet)] else: return None elif isinstance(solution, FiniteSet): result += solution return result ############################################################################### ################################ LINSOLVE ##################################### ############################################################################### def linear_coeffs(eq, *syms, **_kw): """Return a list whose elements are the coefficients of the corresponding symbols in the sum of terms in ``eq``. The additive constant is returned as the last element of the list. Raises ====== NonlinearError The equation contains a nonlinear term Examples ======== >>> from sympy.solvers.solveset import linear_coeffs >>> from sympy.abc import x, y, z >>> linear_coeffs(3*x + 2*y - 1, x, y) [3, 2, -1] It is not necessary to expand the expression: >>> linear_coeffs(x + y*(z*(x*3 + 2) + 3), x) [3*y*z + 1, y*(2*z + 3)] But if there are nonlinear or cross terms -- even if they would cancel after simplification -- an error is raised so the situation does not pass silently past the caller's attention: >>> eq = 1/x*(x - 1) + 1/x >>> linear_coeffs(eq.expand(), x) [0, 1] >>> linear_coeffs(eq, x) Traceback (most recent call last): ... NonlinearError: nonlinear term encountered: 1/x >>> linear_coeffs(x*(y + 1) - x*y, x, y) Traceback (most recent call last): ... NonlinearError: nonlinear term encountered: x*(y + 1) """ d = defaultdict(list) eq = _sympify(eq) symset = set(syms) has = eq.free_symbols & symset if not has: return [S.Zero]*len(syms) + [eq] c, terms = eq.as_coeff_add(*has) d[0].extend(Add.make_args(c)) for t in terms: m, f = t.as_coeff_mul(*has) if len(f) != 1: break f = f[0] if f in symset: d[f].append(m) elif f.is_Add: d1 = linear_coeffs(f, *has, **{'dict': True}) d[0].append(m*d1.pop(0)) for xf, vf in d1.items(): d[xf].append(m*vf) else: break else: for k, v in d.items(): d[k] = Add(*v) if not _kw: return [d.get(s, S.Zero) for s in syms] + [d[0]] return d # default is still list but this won't matter raise NonlinearError('nonlinear term encountered: %s' % t) def linear_eq_to_matrix(equations, *symbols): r""" Converts a given System of Equations into Matrix form. Here `equations` must be a linear system of equations in `symbols`. Element M[i, j] corresponds to the coefficient of the jth symbol in the ith equation. The Matrix form corresponds to the augmented matrix form. For example: .. math:: 4x + 2y + 3z = 1 .. math:: 3x + y + z = -6 .. math:: 2x + 4y + 9z = 2 This system would return `A` & `b` as given below: :: [ 4 2 3 ] [ 1 ] A = [ 3 1 1 ] b = [-6 ] [ 2 4 9 ] [ 2 ] The only simplification performed is to convert `Eq(a, b) -> a - b`. Raises ====== NonlinearError The equations contain a nonlinear term. ValueError The symbols are not given or are not unique. Examples ======== >>> from sympy import linear_eq_to_matrix, symbols >>> c, x, y, z = symbols('c, x, y, z') The coefficients (numerical or symbolic) of the symbols will be returned as matrices: >>> eqns = [c*x + z - 1 - c, y + z, x - y] >>> A, b = linear_eq_to_matrix(eqns, [x, y, z]) >>> A Matrix([ [c, 0, 1], [0, 1, 1], [1, -1, 0]]) >>> b Matrix([ [c + 1], [ 0], [ 0]]) This routine does not simplify expressions and will raise an error if nonlinearity is encountered: >>> eqns = [ ... (x**2 - 3*x)/(x - 3) - 3, ... y**2 - 3*y - y*(y - 4) + x - 4] >>> linear_eq_to_matrix(eqns, [x, y]) Traceback (most recent call last): ... NonlinearError: The term (x**2 - 3*x)/(x - 3) is nonlinear in {x, y} Simplifying these equations will discard the removable singularity in the first, reveal the linear structure of the second: >>> [e.simplify() for e in eqns] [x - 3, x + y - 4] Any such simplification needed to eliminate nonlinear terms must be done before calling this routine. """ if not symbols: raise ValueError(filldedent(''' Symbols must be given, for which coefficients are to be found. ''')) if hasattr(symbols[0], '__iter__'): symbols = symbols[0] for i in symbols: if not isinstance(i, Symbol): raise ValueError(filldedent(''' Expecting a Symbol but got %s ''' % i)) if has_dups(symbols): raise ValueError('Symbols must be unique') equations = sympify(equations) if isinstance(equations, MatrixBase): equations = list(equations) elif isinstance(equations, (Expr, Eq)): equations = [equations] elif not is_sequence(equations): raise ValueError(filldedent(''' Equation(s) must be given as a sequence, Expr, Eq or Matrix. ''')) A, b = [], [] for i, f in enumerate(equations): if isinstance(f, Equality): f = f.rewrite(Add, evaluate=False) coeff_list = linear_coeffs(f, *symbols) b.append(-coeff_list.pop()) A.append(coeff_list) A, b = map(Matrix, (A, b)) return A, b def linsolve(system, *symbols): r""" Solve system of N linear equations with M variables; both underdetermined and overdetermined systems are supported. The possible number of solutions is zero, one or infinite. Zero solutions throws a ValueError, whereas infinite solutions are represented parametrically in terms of the given symbols. For unique solution a FiniteSet of ordered tuples is returned. All Standard input formats are supported: For the given set of Equations, the respective input types are given below: .. math:: 3x + 2y - z = 1 .. math:: 2x - 2y + 4z = -2 .. math:: 2x - y + 2z = 0 * Augmented Matrix Form, `system` given below: :: [3 2 -1 1] system = [2 -2 4 -2] [2 -1 2 0] * List Of Equations Form `system = [3x + 2y - z - 1, 2x - 2y + 4z + 2, 2x - y + 2z]` * Input A & b Matrix Form (from Ax = b) are given as below: :: [3 2 -1 ] [ 1 ] A = [2 -2 4 ] b = [ -2 ] [2 -1 2 ] [ 0 ] `system = (A, b)` Symbols can always be passed but are actually only needed when 1) a system of equations is being passed and 2) the system is passed as an underdetermined matrix and one wants to control the name of the free variables in the result. An error is raised if no symbols are used for case 1, but if no symbols are provided for case 2, internally generated symbols will be provided. When providing symbols for case 2, there should be at least as many symbols are there are columns in matrix A. The algorithm used here is Gauss-Jordan elimination, which results, after elimination, in a row echelon form matrix. Returns ======= A FiniteSet containing an ordered tuple of values for the unknowns for which the `system` has a solution. (Wrapping the tuple in FiniteSet is used to maintain a consistent output format throughout solveset.) Returns EmptySet, if the linear system is inconsistent. Raises ====== ValueError The input is not valid. The symbols are not given. Examples ======== >>> from sympy import Matrix, linsolve, symbols >>> x, y, z = symbols("x, y, z") >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 10]]) >>> b = Matrix([3, 6, 9]) >>> A Matrix([ [1, 2, 3], [4, 5, 6], [7, 8, 10]]) >>> b Matrix([ [3], [6], [9]]) >>> linsolve((A, b), [x, y, z]) {(-1, 2, 0)} * Parametric Solution: In case the system is underdetermined, the function will return a parametric solution in terms of the given symbols. Those that are free will be returned unchanged. e.g. in the system below, `z` is returned as the solution for variable z; it can take on any value. >>> A = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) >>> b = Matrix([3, 6, 9]) >>> linsolve((A, b), x, y, z) {(z - 1, 2 - 2*z, z)} If no symbols are given, internally generated symbols will be used. The `tau0` in the 3rd position indicates (as before) that the 3rd variable -- whatever it's named -- can take on any value: >>> linsolve((A, b)) {(tau0 - 1, 2 - 2*tau0, tau0)} * List of Equations as input >>> Eqns = [3*x + 2*y - z - 1, 2*x - 2*y + 4*z + 2, - x + y/2 - z] >>> linsolve(Eqns, x, y, z) {(1, -2, -2)} * Augmented Matrix as input >>> aug = Matrix([[2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]]) >>> aug Matrix([ [2, 1, 3, 1], [2, 6, 8, 3], [6, 8, 18, 5]]) >>> linsolve(aug, x, y, z) {(3/10, 2/5, 0)} * Solve for symbolic coefficients >>> a, b, c, d, e, f = symbols('a, b, c, d, e, f') >>> eqns = [a*x + b*y - c, d*x + e*y - f] >>> linsolve(eqns, x, y) {((-b*f + c*e)/(a*e - b*d), (a*f - c*d)/(a*e - b*d))} * A degenerate system returns solution as set of given symbols. >>> system = Matrix(([0, 0, 0], [0, 0, 0], [0, 0, 0])) >>> linsolve(system, x, y) {(x, y)} * For an empty system linsolve returns empty set >>> linsolve([], x) EmptySet * An error is raised if, after expansion, any nonlinearity is detected: >>> linsolve([x*(1/x - 1), (y - 1)**2 - y**2 + 1], x, y) {(1, 1)} >>> linsolve([x**2 - 1], x) Traceback (most recent call last): ... NonlinearError: nonlinear term encountered: x**2 """ if not system: return S.EmptySet # If second argument is an iterable if symbols and hasattr(symbols[0], '__iter__'): symbols = symbols[0] sym_gen = isinstance(symbols, GeneratorType) b = None # if we don't get b the input was bad # unpack system if hasattr(system, '__iter__'): # 1). (A, b) if len(system) == 2 and isinstance(system[0], MatrixBase): A, b = system # 2). (eq1, eq2, ...) if not isinstance(system[0], MatrixBase): if sym_gen or not symbols: raise ValueError(filldedent(''' When passing a system of equations, the explicit symbols for which a solution is being sought must be given as a sequence, too. ''')) # # Pass to the sparse solver implemented in polys. It is important # that we do not attempt to convert the equations to a matrix # because that would be very inefficient for large sparse systems # of equations. # eqs = system eqs = [sympify(eq) for eq in eqs] try: sol = _linsolve(eqs, symbols) except PolyNonlinearError as exc: # e.g. cos(x) contains an element of the set of generators raise NonlinearError(str(exc)) if sol is None: return S.EmptySet sol = FiniteSet(Tuple(*(sol.get(sym, sym) for sym in symbols))) return sol elif isinstance(system, MatrixBase) and not ( symbols and not isinstance(symbols, GeneratorType) and isinstance(symbols[0], MatrixBase)): # 3). A augmented with b A, b = system[:, :-1], system[:, -1:] if b is None: raise ValueError("Invalid arguments") if sym_gen: symbols = [next(symbols) for i in range(A.cols)] if any(set(symbols) & (A.free_symbols | b.free_symbols)): raise ValueError(filldedent(''' At least one of the symbols provided already appears in the system to be solved. One way to avoid this is to use Dummy symbols in the generator, e.g. numbered_symbols('%s', cls=Dummy) ''' % symbols[0].name.rstrip('1234567890'))) if not symbols: symbols = [Dummy() for _ in range(A.cols)] name = _uniquely_named_symbol('tau', (A, b), compare=lambda i: str(i).rstrip('1234567890')).name gen = numbered_symbols(name) else: gen = None # This is just a wrapper for solve_lin_sys eqs = [] rows = A.tolist() for rowi, bi in zip(rows, b): terms = [elem * sym for elem, sym in zip(rowi, symbols) if elem] terms.append(-bi) eqs.append(Add(*terms)) eqs, ring = sympy_eqs_to_ring(eqs, symbols) sol = solve_lin_sys(eqs, ring, _raw=False) if sol is None: return S.EmptySet #sol = {sym:val for sym, val in sol.items() if sym != val} sol = FiniteSet(Tuple(*(sol.get(sym, sym) for sym in symbols))) if gen is not None: solsym = sol.free_symbols rep = {sym: next(gen) for sym in symbols if sym in solsym} sol = sol.subs(rep) return sol ############################################################################## # ------------------------------nonlinsolve ---------------------------------# ############################################################################## def _return_conditionset(eqs, symbols): # return conditionset eqs = (Eq(lhs, 0) for lhs in eqs) condition_set = ConditionSet( Tuple(*symbols), And(*eqs), S.Complexes**len(symbols)) return condition_set def substitution(system, symbols, result=[{}], known_symbols=[], exclude=[], all_symbols=None): r""" Solves the `system` using substitution method. It is used in `nonlinsolve`. This will be called from `nonlinsolve` when any equation(s) is non polynomial equation. Parameters ========== system : list of equations The target system of equations symbols : list of symbols to be solved. The variable(s) for which the system is solved known_symbols : list of solved symbols Values are known for these variable(s) result : An empty list or list of dict If No symbol values is known then empty list otherwise symbol as keys and corresponding value in dict. exclude : Set of expression. Mostly denominator expression(s) of the equations of the system. Final solution should not satisfy these expressions. all_symbols : known_symbols + symbols(unsolved). Returns ======= A FiniteSet of ordered tuple of values of `all_symbols` for which the `system` has solution. Order of values in the tuple is same as symbols present in the parameter `all_symbols`. If parameter `all_symbols` is None then same as symbols present in the parameter `symbols`. Please note that general FiniteSet is unordered, the solution returned here is not simply a FiniteSet of solutions, rather it is a FiniteSet of ordered tuple, i.e. the first & only argument to FiniteSet is a tuple of solutions, which is ordered, & hence the returned solution is ordered. Also note that solution could also have been returned as an ordered tuple, FiniteSet is just a wrapper `{}` around the tuple. It has no other significance except for the fact it is just used to maintain a consistent output format throughout the solveset. Raises ====== ValueError The input is not valid. The symbols are not given. AttributeError The input symbols are not `Symbol` type. Examples ======== >>> from sympy.core.symbol import symbols >>> x, y = symbols('x, y', real=True) >>> from sympy.solvers.solveset import substitution >>> substitution([x + y], [x], [{y: 1}], [y], set([]), [x, y]) {(-1, 1)} * when you want soln should not satisfy eq `x + 1 = 0` >>> substitution([x + y], [x], [{y: 1}], [y], set([x + 1]), [y, x]) EmptySet >>> substitution([x + y], [x], [{y: 1}], [y], set([x - 1]), [y, x]) {(1, -1)} >>> substitution([x + y - 1, y - x**2 + 5], [x, y]) {(-3, 4), (2, -1)} * Returns both real and complex solution >>> x, y, z = symbols('x, y, z') >>> from sympy import exp, sin >>> substitution([exp(x) - sin(y), y**2 - 4], [x, y]) {(ImageSet(Lambda(_n, I*(2*_n*pi + pi) + log(sin(2))), Integers), -2), (ImageSet(Lambda(_n, 2*_n*I*pi + log(sin(2))), Integers), 2)} >>> eqs = [z**2 + exp(2*x) - sin(y), -3 + exp(-y)] >>> substitution(eqs, [y, z]) {(-log(3), -sqrt(-exp(2*x) - sin(log(3)))), (-log(3), sqrt(-exp(2*x) - sin(log(3)))), (ImageSet(Lambda(_n, 2*_n*I*pi - log(3)), Integers), ImageSet(Lambda(_n, -sqrt(-exp(2*x) + sin(2*_n*I*pi - log(3)))), Integers)), (ImageSet(Lambda(_n, 2*_n*I*pi - log(3)), Integers), ImageSet(Lambda(_n, sqrt(-exp(2*x) + sin(2*_n*I*pi - log(3)))), Integers))} """ from sympy.core.compatibility import is_sequence if not system: return S.EmptySet if not symbols: msg = ('Symbols must be given, for which solution of the ' 'system is to be found.') raise ValueError(filldedent(msg)) if not is_sequence(symbols): msg = ('symbols should be given as a sequence, e.g. a list.' 'Not type %s: %s') raise TypeError(filldedent(msg % (type(symbols), symbols))) if not getattr(symbols[0], 'is_Symbol', False): msg = ('Iterable of symbols must be given as ' 'second argument, not type %s: %s') raise ValueError(filldedent(msg % (type(symbols[0]), symbols[0]))) # By default `all_symbols` will be same as `symbols` if all_symbols is None: all_symbols = symbols old_result = result # storing complements and intersection for particular symbol complements = {} intersections = {} # when total_solveset_call equals total_conditionset # it means that solveset failed to solve all eqs. total_conditionset = -1 total_solveset_call = -1 def _unsolved_syms(eq, sort=False): """Returns the unsolved symbol present in the equation `eq`. """ free = eq.free_symbols unsolved = (free - set(known_symbols)) & set(all_symbols) if sort: unsolved = list(unsolved) unsolved.sort(key=default_sort_key) return unsolved # end of _unsolved_syms() # sort such that equation with the fewest potential symbols is first. # means eq with less number of variable first in the list. eqs_in_better_order = list( ordered(system, lambda _: len(_unsolved_syms(_)))) def add_intersection_complement(result, intersection_dict, complement_dict): # If solveset has returned some intersection/complement # for any symbol, it will be added in the final solution. final_result = [] for res in result: res_copy = res for key_res, value_res in res.items(): intersect_set, complement_set = None, None for key_sym, value_sym in intersection_dict.items(): if key_sym == key_res: intersect_set = value_sym for key_sym, value_sym in complement_dict.items(): if key_sym == key_res: complement_set = value_sym if intersect_set or complement_set: new_value = FiniteSet(value_res) if intersect_set and intersect_set != S.Complexes: new_value = Intersection(new_value, intersect_set) if complement_set: new_value = Complement(new_value, complement_set) if new_value is S.EmptySet: res_copy = None break elif new_value.is_FiniteSet and len(new_value) == 1: res_copy[key_res] = set(new_value).pop() else: res_copy[key_res] = new_value if res_copy is not None: final_result.append(res_copy) return final_result # end of def add_intersection_complement() def _extract_main_soln(sym, sol, soln_imageset): """Separate the Complements, Intersections, ImageSet lambda expr and its base_set. This function returns the unmasks sol from different classes of sets and also returns the appended ImageSet elements in a soln_imageset (dict: where key as unmasked element and value as ImageSet). """ # if there is union, then need to check # Complement, Intersection, Imageset. # Order should not be changed. if isinstance(sol, ConditionSet): # extracts any solution in ConditionSet sol = sol.base_set if isinstance(sol, Complement): # extract solution and complement complements[sym] = sol.args[1] sol = sol.args[0] # complement will be added at the end # using `add_intersection_complement` method # if there is union of Imageset or other in soln. # no testcase is written for this if block if isinstance(sol, Union): sol_args = sol.args sol = S.EmptySet # We need in sequence so append finteset elements # and then imageset or other. for sol_arg2 in sol_args: if isinstance(sol_arg2, FiniteSet): sol += sol_arg2 else: # ImageSet, Intersection, complement then # append them directly sol += FiniteSet(sol_arg2) if isinstance(sol, Intersection): # Interval/Set will be at 0th index always if sol.args[0] not in (S.Reals, S.Complexes): # Sometimes solveset returns soln with intersection # S.Reals or S.Complexes. We don't consider that # intersection. intersections[sym] = sol.args[0] sol = sol.args[1] # after intersection and complement Imageset should # be checked. if isinstance(sol, ImageSet): soln_imagest = sol expr2 = sol.lamda.expr sol = FiniteSet(expr2) soln_imageset[expr2] = soln_imagest if not isinstance(sol, FiniteSet): sol = FiniteSet(sol) return sol, soln_imageset # end of def _extract_main_soln() # helper function for _append_new_soln def _check_exclude(rnew, imgset_yes): rnew_ = rnew if imgset_yes: # replace all dummy variables (Imageset lambda variables) # with zero before `checksol`. Considering fundamental soln # for `checksol`. rnew_copy = rnew.copy() dummy_n = imgset_yes[0] for key_res, value_res in rnew_copy.items(): rnew_copy[key_res] = value_res.subs(dummy_n, 0) rnew_ = rnew_copy # satisfy_exclude == true if it satisfies the expr of `exclude` list. try: # something like : `Mod(-log(3), 2*I*pi)` can't be # simplified right now, so `checksol` returns `TypeError`. # when this issue is fixed this try block should be # removed. Mod(-log(3), 2*I*pi) == -log(3) satisfy_exclude = any( checksol(d, rnew_) for d in exclude) except TypeError: satisfy_exclude = None return satisfy_exclude # end of def _check_exclude() # helper function for _append_new_soln def _restore_imgset(rnew, original_imageset, newresult): restore_sym = set(rnew.keys()) & \ set(original_imageset.keys()) for key_sym in restore_sym: img = original_imageset[key_sym] rnew[key_sym] = img if rnew not in newresult: newresult.append(rnew) # end of def _restore_imgset() def _append_eq(eq, result, res, delete_soln, n=None): u = Dummy('u') if n: eq = eq.subs(n, 0) satisfy = eq if eq in (True, False) else checksol(u, u, eq, minimal=True) if satisfy is False: delete_soln = True res = {} else: result.append(res) return result, res, delete_soln def _append_new_soln(rnew, sym, sol, imgset_yes, soln_imageset, original_imageset, newresult, eq=None): """If `rnew` (A dict ) contains valid soln append it to `newresult` list. `imgset_yes` is (base, dummy_var) if there was imageset in previously calculated result(otherwise empty tuple). `original_imageset` is dict of imageset expr and imageset from this result. `soln_imageset` dict of imageset expr and imageset of new soln. """ satisfy_exclude = _check_exclude(rnew, imgset_yes) delete_soln = False # soln should not satisfy expr present in `exclude` list. if not satisfy_exclude: local_n = None # if it is imageset if imgset_yes: local_n = imgset_yes[0] base = imgset_yes[1] if sym and sol: # when `sym` and `sol` is `None` means no new # soln. In that case we will append rnew directly after # substituting original imagesets in rnew values if present # (second last line of this function using _restore_imgset) dummy_list = list(sol.atoms(Dummy)) # use one dummy `n` which is in # previous imageset local_n_list = [ local_n for i in range( 0, len(dummy_list))] dummy_zip = zip(dummy_list, local_n_list) lam = Lambda(local_n, sol.subs(dummy_zip)) rnew[sym] = ImageSet(lam, base) if eq is not None: newresult, rnew, delete_soln = _append_eq( eq, newresult, rnew, delete_soln, local_n) elif eq is not None: newresult, rnew, delete_soln = _append_eq( eq, newresult, rnew, delete_soln) elif sol in soln_imageset.keys(): rnew[sym] = soln_imageset[sol] # restore original imageset _restore_imgset(rnew, original_imageset, newresult) else: newresult.append(rnew) elif satisfy_exclude: delete_soln = True rnew = {} _restore_imgset(rnew, original_imageset, newresult) return newresult, delete_soln # end of def _append_new_soln() def _new_order_result(result, eq): # separate first, second priority. `res` that makes `eq` value equals # to zero, should be used first then other result(second priority). # If it is not done then we may miss some soln. first_priority = [] second_priority = [] for res in result: if not any(isinstance(val, ImageSet) for val in res.values()): if eq.subs(res) == 0: first_priority.append(res) else: second_priority.append(res) if first_priority or second_priority: return first_priority + second_priority return result def _solve_using_known_values(result, solver): """Solves the system using already known solution (result contains the dict ). solver is `solveset_complex` or `solveset_real`. """ # stores imageset . soln_imageset = {} total_solvest_call = 0 total_conditionst = 0 # sort such that equation with the fewest potential symbols is first. # means eq with less variable first for index, eq in enumerate(eqs_in_better_order): newresult = [] original_imageset = {} # if imageset expr is used to solve other symbol imgset_yes = False result = _new_order_result(result, eq) for res in result: got_symbol = set() # symbols solved in one iteration # find the imageset and use its expr. for key_res, value_res in res.items(): if isinstance(value_res, ImageSet): res[key_res] = value_res.lamda.expr original_imageset[key_res] = value_res dummy_n = value_res.lamda.expr.atoms(Dummy).pop() (base,) = value_res.base_sets imgset_yes = (dummy_n, base) # update eq with everything that is known so far eq2 = eq.subs(res).expand() unsolved_syms = _unsolved_syms(eq2, sort=True) if not unsolved_syms: if res: newresult, delete_res = _append_new_soln( res, None, None, imgset_yes, soln_imageset, original_imageset, newresult, eq2) if delete_res: # `delete_res` is true, means substituting `res` in # eq2 doesn't return `zero` or deleting the `res` # (a soln) since it staisfies expr of `exclude` # list. result.remove(res) continue # skip as it's independent of desired symbols depen1, depen2 = (eq2.rewrite(Add)).as_independent(*unsolved_syms) if (depen1.has(Abs) or depen2.has(Abs)) and solver == solveset_complex: # Absolute values cannot be inverted in the # complex domain continue soln_imageset = {} for sym in unsolved_syms: not_solvable = False try: soln = solver(eq2, sym) total_solvest_call += 1 soln_new = S.EmptySet if isinstance(soln, Complement): # separate solution and complement complements[sym] = soln.args[1] soln = soln.args[0] # complement will be added at the end if isinstance(soln, Intersection): # Interval will be at 0th index always if soln.args[0] != Interval(-oo, oo): # sometimes solveset returns soln # with intersection S.Reals, to confirm that # soln is in domain=S.Reals intersections[sym] = soln.args[0] soln_new += soln.args[1] soln = soln_new if soln_new else soln if index > 0 and solver == solveset_real: # one symbol's real soln , another symbol may have # corresponding complex soln. if not isinstance(soln, (ImageSet, ConditionSet)): soln += solveset_complex(eq2, sym) except NotImplementedError: # If sovleset is not able to solve equation `eq2`. Next # time we may get soln using next equation `eq2` continue if isinstance(soln, ConditionSet): if soln.base_set in (S.Reals, S.Complexes): soln = S.EmptySet # don't do `continue` we may get soln # in terms of other symbol(s) not_solvable = True total_conditionst += 1 else: soln = soln.base_set if soln is not S.EmptySet: soln, soln_imageset = _extract_main_soln( sym, soln, soln_imageset) for sol in soln: # sol is not a `Union` since we checked it # before this loop sol, soln_imageset = _extract_main_soln( sym, sol, soln_imageset) sol = set(sol).pop() free = sol.free_symbols if got_symbol and any([ ss in free for ss in got_symbol ]): # sol depends on previously solved symbols # then continue continue rnew = res.copy() # put each solution in res and append the new result # in the new result list (solution for symbol `s`) # along with old results. for k, v in res.items(): if isinstance(v, Expr): # if any unsolved symbol is present # Then subs known value rnew[k] = v.subs(sym, sol) # and add this new solution if sol in soln_imageset.keys(): # replace all lambda variables with 0. imgst = soln_imageset[sol] rnew[sym] = imgst.lamda( *[0 for i in range(0, len( imgst.lamda.variables))]) else: rnew[sym] = sol newresult, delete_res = _append_new_soln( rnew, sym, sol, imgset_yes, soln_imageset, original_imageset, newresult) if delete_res: # deleting the `res` (a soln) since it staisfies # eq of `exclude` list result.remove(res) # solution got for sym if not not_solvable: got_symbol.add(sym) # next time use this new soln if newresult: result = newresult return result, total_solvest_call, total_conditionst # end def _solve_using_know_values() new_result_real, solve_call1, cnd_call1 = _solve_using_known_values( old_result, solveset_real) new_result_complex, solve_call2, cnd_call2 = _solve_using_known_values( old_result, solveset_complex) # If total_solveset_call is equal to total_conditionset # then solveset failed to solve all of the equations. # In this case we return a ConditionSet here. total_conditionset += (cnd_call1 + cnd_call2) total_solveset_call += (solve_call1 + solve_call2) if total_conditionset == total_solveset_call and total_solveset_call != -1: return _return_conditionset(eqs_in_better_order, all_symbols) # don't keep duplicate solutions filtered_complex = [] for i in list(new_result_complex): for j in list(new_result_real): if i.keys() != j.keys(): continue if all(a.dummy_eq(b) for a, b in zip(i.values(), j.values()) \ if type(a) != int or type(b) != int): break else: filtered_complex.append(i) # overall result result = new_result_real + filtered_complex result_all_variables = [] result_infinite = [] for res in result: if not res: # means {None : None} continue # If length < len(all_symbols) means infinite soln. # Some or all the soln is dependent on 1 symbol. # eg. {x: y+2} then final soln {x: y+2, y: y} if len(res) < len(all_symbols): solved_symbols = res.keys() unsolved = list(filter( lambda x: x not in solved_symbols, all_symbols)) for unsolved_sym in unsolved: res[unsolved_sym] = unsolved_sym result_infinite.append(res) if res not in result_all_variables: result_all_variables.append(res) if result_infinite: # we have general soln # eg : [{x: -1, y : 1}, {x : -y , y: y}] then # return [{x : -y, y : y}] result_all_variables = result_infinite if intersections or complements: result_all_variables = add_intersection_complement( result_all_variables, intersections, complements) # convert to ordered tuple result = S.EmptySet for r in result_all_variables: temp = [r[symb] for symb in all_symbols] result += FiniteSet(tuple(temp)) return result # end of def substitution() def _solveset_work(system, symbols): soln = solveset(system[0], symbols[0]) if isinstance(soln, FiniteSet): _soln = FiniteSet(*[tuple((s,)) for s in soln]) return _soln else: return FiniteSet(tuple(FiniteSet(soln))) def _handle_positive_dimensional(polys, symbols, denominators): from sympy.polys.polytools import groebner # substitution method where new system is groebner basis of the system _symbols = list(symbols) _symbols.sort(key=default_sort_key) basis = groebner(polys, _symbols, polys=True) new_system = [] for poly_eq in basis: new_system.append(poly_eq.as_expr()) result = [{}] result = substitution( new_system, symbols, result, [], denominators) return result # end of def _handle_positive_dimensional() def _handle_zero_dimensional(polys, symbols, system): # solve 0 dimensional poly system using `solve_poly_system` result = solve_poly_system(polys, *symbols) # May be some extra soln is added because # we used `unrad` in `_separate_poly_nonpoly`, so # need to check and remove if it is not a soln. result_update = S.EmptySet for res in result: dict_sym_value = dict(list(zip(symbols, res))) if all(checksol(eq, dict_sym_value) for eq in system): result_update += FiniteSet(res) return result_update # end of def _handle_zero_dimensional() def _separate_poly_nonpoly(system, symbols): polys = [] polys_expr = [] nonpolys = [] denominators = set() poly = None for eq in system: # Store denom expression if it contains symbol denominators.update(_simple_dens(eq, symbols)) # try to remove sqrt and rational power without_radicals = unrad(simplify(eq), *symbols) if without_radicals: eq_unrad, cov = without_radicals if not cov: eq = eq_unrad if isinstance(eq, Expr): eq = eq.as_numer_denom()[0] poly = eq.as_poly(*symbols, extension=True) elif simplify(eq).is_number: continue if poly is not None: polys.append(poly) polys_expr.append(poly.as_expr()) else: nonpolys.append(eq) return polys, polys_expr, nonpolys, denominators # end of def _separate_poly_nonpoly() def nonlinsolve(system, *symbols): r""" Solve system of N nonlinear equations with M variables, which means both under and overdetermined systems are supported. Positive dimensional system is also supported (A system with infinitely many solutions is said to be positive-dimensional). In Positive dimensional system solution will be dependent on at least one symbol. Returns both real solution and complex solution(If system have). The possible number of solutions is zero, one or infinite. Parameters ========== system : list of equations The target system of equations symbols : list of Symbols symbols should be given as a sequence eg. list Returns ======= A FiniteSet of ordered tuple of values of `symbols` for which the `system` has solution. Order of values in the tuple is same as symbols present in the parameter `symbols`. Please note that general FiniteSet is unordered, the solution returned here is not simply a FiniteSet of solutions, rather it is a FiniteSet of ordered tuple, i.e. the first & only argument to FiniteSet is a tuple of solutions, which is ordered, & hence the returned solution is ordered. Also note that solution could also have been returned as an ordered tuple, FiniteSet is just a wrapper `{}` around the tuple. It has no other significance except for the fact it is just used to maintain a consistent output format throughout the solveset. For the given set of Equations, the respective input types are given below: .. math:: x*y - 1 = 0 .. math:: 4*x**2 + y**2 - 5 = 0 `system = [x*y - 1, 4*x**2 + y**2 - 5]` `symbols = [x, y]` Raises ====== ValueError The input is not valid. The symbols are not given. AttributeError The input symbols are not `Symbol` type. Examples ======== >>> from sympy.core.symbol import symbols >>> from sympy.solvers.solveset import nonlinsolve >>> x, y, z = symbols('x, y, z', real=True) >>> nonlinsolve([x*y - 1, 4*x**2 + y**2 - 5], [x, y]) {(-1, -1), (-1/2, -2), (1/2, 2), (1, 1)} 1. Positive dimensional system and complements: >>> from sympy import pprint >>> from sympy.polys.polytools import is_zero_dimensional >>> a, b, c, d = symbols('a, b, c, d', extended_real=True) >>> eq1 = a + b + c + d >>> eq2 = a*b + b*c + c*d + d*a >>> eq3 = a*b*c + b*c*d + c*d*a + d*a*b >>> eq4 = a*b*c*d - 1 >>> system = [eq1, eq2, eq3, eq4] >>> is_zero_dimensional(system) False >>> pprint(nonlinsolve(system, [a, b, c, d]), use_unicode=False) -1 1 1 -1 {(---, -d, -, {d} \ {0}), (-, -d, ---, {d} \ {0})} d d d d >>> nonlinsolve([(x+y)**2 - 4, x + y - 2], [x, y]) {(2 - y, y)} 2. If some of the equations are non-polynomial then `nonlinsolve` will call the `substitution` function and return real and complex solutions, if present. >>> from sympy import exp, sin >>> nonlinsolve([exp(x) - sin(y), y**2 - 4], [x, y]) {(ImageSet(Lambda(_n, I*(2*_n*pi + pi) + log(sin(2))), Integers), -2), (ImageSet(Lambda(_n, 2*_n*I*pi + log(sin(2))), Integers), 2)} 3. If system is non-linear polynomial and zero-dimensional then it returns both solution (real and complex solutions, if present) using `solve_poly_system`: >>> from sympy import sqrt >>> nonlinsolve([x**2 - 2*y**2 -2, x*y - 2], [x, y]) {(-2, -1), (2, 1), (-sqrt(2)*I, sqrt(2)*I), (sqrt(2)*I, -sqrt(2)*I)} 4. `nonlinsolve` can solve some linear (zero or positive dimensional) system (because it uses the `groebner` function to get the groebner basis and then uses the `substitution` function basis as the new `system`). But it is not recommended to solve linear system using `nonlinsolve`, because `linsolve` is better for general linear systems. >>> nonlinsolve([x + 2*y -z - 3, x - y - 4*z + 9 , y + z - 4], [x, y, z]) {(3*z - 5, 4 - z, z)} 5. System having polynomial equations and only real solution is solved using `solve_poly_system`: >>> e1 = sqrt(x**2 + y**2) - 10 >>> e2 = sqrt(y**2 + (-x + 10)**2) - 3 >>> nonlinsolve((e1, e2), (x, y)) {(191/20, -3*sqrt(391)/20), (191/20, 3*sqrt(391)/20)} >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [x, y]) {(1, 2), (1 - sqrt(5), 2 + sqrt(5)), (1 + sqrt(5), 2 - sqrt(5))} >>> nonlinsolve([x**2 + 2/y - 2, x + y - 3], [y, x]) {(2, 1), (2 - sqrt(5), 1 + sqrt(5)), (2 + sqrt(5), 1 - sqrt(5))} 6. It is better to use symbols instead of Trigonometric Function or Function (e.g. replace `sin(x)` with symbol, replace `f(x)` with symbol and so on. Get soln from `nonlinsolve` and then using `solveset` get the value of `x`) How nonlinsolve is better than old solver `_solve_system` : =========================================================== 1. A positive dimensional system solver : nonlinsolve can return solution for positive dimensional system. It finds the Groebner Basis of the positive dimensional system(calling it as basis) then we can start solving equation(having least number of variable first in the basis) using solveset and substituting that solved solutions into other equation(of basis) to get solution in terms of minimum variables. Here the important thing is how we are substituting the known values and in which equations. 2. Real and Complex both solutions : nonlinsolve returns both real and complex solution. If all the equations in the system are polynomial then using `solve_poly_system` both real and complex solution is returned. If all the equations in the system are not polynomial equation then goes to `substitution` method with this polynomial and non polynomial equation(s), to solve for unsolved variables. Here to solve for particular variable solveset_real and solveset_complex is used. For both real and complex solution function `_solve_using_know_values` is used inside `substitution` function.(`substitution` function will be called when there is any non polynomial equation(s) is present). When solution is valid then add its general solution in the final result. 3. Complement and Intersection will be added if any : nonlinsolve maintains dict for complements and Intersections. If solveset find complements or/and Intersection with any Interval or set during the execution of `substitution` function ,then complement or/and Intersection for that variable is added before returning final solution. """ from sympy.polys.polytools import is_zero_dimensional if not system: return S.EmptySet if not symbols: msg = ('Symbols must be given, for which solution of the ' 'system is to be found.') raise ValueError(filldedent(msg)) if hasattr(symbols[0], '__iter__'): symbols = symbols[0] if not is_sequence(symbols) or not symbols: msg = ('Symbols must be given, for which solution of the ' 'system is to be found.') raise IndexError(filldedent(msg)) system, symbols, swap = recast_to_symbols(system, symbols) if swap: soln = nonlinsolve(system, symbols) return FiniteSet(*[tuple(i.xreplace(swap) for i in s) for s in soln]) if len(system) == 1 and len(symbols) == 1: return _solveset_work(system, symbols) # main code of def nonlinsolve() starts from here polys, polys_expr, nonpolys, denominators = _separate_poly_nonpoly( system, symbols) if len(symbols) == len(polys): # If all the equations in the system are poly if is_zero_dimensional(polys, symbols): # finite number of soln (Zero dimensional system) try: return _handle_zero_dimensional(polys, symbols, system) except NotImplementedError: # Right now it doesn't fail for any polynomial system of # equation. If `solve_poly_system` fails then `substitution` # method will handle it. result = substitution( polys_expr, symbols, exclude=denominators) return result # positive dimensional system res = _handle_positive_dimensional(polys, symbols, denominators) if res is EmptySet and any(not p.domain.is_Exact for p in polys): raise NotImplementedError("Equation not in exact domain. Try converting to rational") else: return res else: # If all the equations are not polynomial. # Use `substitution` method for the system result = substitution( polys_expr + nonpolys, symbols, exclude=denominators) return result sympy-sympy-1.9/sympy/solvers/tests/000077500000000000000000000000001412543434000177435ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/tests/__init__.py000066400000000000000000000000001412543434000220420ustar00rootroot00000000000000sympy-sympy-1.9/sympy/solvers/tests/test_constantsimp.py000066400000000000000000000201741412543434000241020ustar00rootroot00000000000000""" If the arbitrary constant class from issue 4435 is ever implemented, this should serve as a set of test cases. """ from sympy import (acos, cos, cosh, Eq, exp, Function, I, Integral, log, Pow, S, sin, sinh, sqrt, Symbol) from sympy.solvers.ode.ode import constantsimp, constant_renumber from sympy.testing.pytest import XFAIL x = Symbol('x') y = Symbol('y') z = Symbol('z') u2 = Symbol('u2') _a = Symbol('_a') C1 = Symbol('C1') C2 = Symbol('C2') C3 = Symbol('C3') f = Function('f') def test_constant_mul(): # We want C1 (Constant) below to absorb the y's, but not the x's assert constant_renumber(constantsimp(y*C1, [C1])) == C1*y assert constant_renumber(constantsimp(C1*y, [C1])) == C1*y assert constant_renumber(constantsimp(x*C1, [C1])) == x*C1 assert constant_renumber(constantsimp(C1*x, [C1])) == x*C1 assert constant_renumber(constantsimp(2*C1, [C1])) == C1 assert constant_renumber(constantsimp(C1*2, [C1])) == C1 assert constant_renumber(constantsimp(y*C1*x, [C1, y])) == C1*x assert constant_renumber(constantsimp(x*y*C1, [C1, y])) == x*C1 assert constant_renumber(constantsimp(y*x*C1, [C1, y])) == x*C1 assert constant_renumber(constantsimp(C1*x*y, [C1, y])) == C1*x assert constant_renumber(constantsimp(x*C1*y, [C1, y])) == x*C1 assert constant_renumber(constantsimp(C1*y*(y + 1), [C1])) == C1*y*(y+1) assert constant_renumber(constantsimp(y*C1*(y + 1), [C1])) == C1*y*(y+1) assert constant_renumber(constantsimp(x*(y*C1), [C1])) == x*y*C1 assert constant_renumber(constantsimp(x*(C1*y), [C1])) == x*y*C1 assert constant_renumber(constantsimp(C1*(x*y), [C1, y])) == C1*x assert constant_renumber(constantsimp((x*y)*C1, [C1, y])) == x*C1 assert constant_renumber(constantsimp((y*x)*C1, [C1, y])) == x*C1 assert constant_renumber(constantsimp(y*(y + 1)*C1, [C1, y])) == C1 assert constant_renumber(constantsimp((C1*x)*y, [C1, y])) == C1*x assert constant_renumber(constantsimp(y*(x*C1), [C1, y])) == x*C1 assert constant_renumber(constantsimp((x*C1)*y, [C1, y])) == x*C1 assert constant_renumber(constantsimp(C1*x*y*x*y*2, [C1, y])) == C1*x**2 assert constant_renumber(constantsimp(C1*x*y*z, [C1, y, z])) == C1*x assert constant_renumber(constantsimp(C1*x*y**2*sin(z), [C1, y, z])) == C1*x assert constant_renumber(constantsimp(C1*C1, [C1])) == C1 assert constant_renumber(constantsimp(C1*C2, [C1, C2])) == C1 assert constant_renumber(constantsimp(C2*C2, [C1, C2])) == C1 assert constant_renumber(constantsimp(C1*C1*C2, [C1, C2])) == C1 assert constant_renumber(constantsimp(C1*x*2**x, [C1])) == C1*x*2**x def test_constant_add(): assert constant_renumber(constantsimp(C1 + C1, [C1])) == C1 assert constant_renumber(constantsimp(C1 + 2, [C1])) == C1 assert constant_renumber(constantsimp(2 + C1, [C1])) == C1 assert constant_renumber(constantsimp(C1 + y, [C1, y])) == C1 assert constant_renumber(constantsimp(C1 + x, [C1])) == C1 + x assert constant_renumber(constantsimp(C1 + C1, [C1])) == C1 assert constant_renumber(constantsimp(C1 + C2, [C1, C2])) == C1 assert constant_renumber(constantsimp(C2 + C1, [C1, C2])) == C1 assert constant_renumber(constantsimp(C1 + C2 + C1, [C1, C2])) == C1 def test_constant_power_as_base(): assert constant_renumber(constantsimp(C1**C1, [C1])) == C1 assert constant_renumber(constantsimp(Pow(C1, C1), [C1])) == C1 assert constant_renumber(constantsimp(C1**C1, [C1])) == C1 assert constant_renumber(constantsimp(C1**C2, [C1, C2])) == C1 assert constant_renumber(constantsimp(C2**C1, [C1, C2])) == C1 assert constant_renumber(constantsimp(C2**C2, [C1, C2])) == C1 assert constant_renumber(constantsimp(C1**y, [C1, y])) == C1 assert constant_renumber(constantsimp(C1**x, [C1])) == C1**x assert constant_renumber(constantsimp(C1**2, [C1])) == C1 assert constant_renumber( constantsimp(C1**(x*y), [C1])) == C1**(x*y) def test_constant_power_as_exp(): assert constant_renumber(constantsimp(x**C1, [C1])) == x**C1 assert constant_renumber(constantsimp(y**C1, [C1, y])) == C1 assert constant_renumber(constantsimp(x**y**C1, [C1, y])) == x**C1 assert constant_renumber( constantsimp((x**y)**C1, [C1])) == (x**y)**C1 assert constant_renumber( constantsimp(x**(y**C1), [C1, y])) == x**C1 assert constant_renumber(constantsimp(x**C1**y, [C1, y])) == x**C1 assert constant_renumber( constantsimp(x**(C1**y), [C1, y])) == x**C1 assert constant_renumber( constantsimp((x**C1)**y, [C1])) == (x**C1)**y assert constant_renumber(constantsimp(2**C1, [C1])) == C1 assert constant_renumber(constantsimp(S(2)**C1, [C1])) == C1 assert constant_renumber(constantsimp(exp(C1), [C1])) == C1 assert constant_renumber( constantsimp(exp(C1 + x), [C1])) == C1*exp(x) assert constant_renumber(constantsimp(Pow(2, C1), [C1])) == C1 def test_constant_function(): assert constant_renumber(constantsimp(sin(C1), [C1])) == C1 assert constant_renumber(constantsimp(f(C1), [C1])) == C1 assert constant_renumber(constantsimp(f(C1, C1), [C1])) == C1 assert constant_renumber(constantsimp(f(C1, C2), [C1, C2])) == C1 assert constant_renumber(constantsimp(f(C2, C1), [C1, C2])) == C1 assert constant_renumber(constantsimp(f(C2, C2), [C1, C2])) == C1 assert constant_renumber( constantsimp(f(C1, x), [C1])) == f(C1, x) assert constant_renumber(constantsimp(f(C1, y), [C1, y])) == C1 assert constant_renumber(constantsimp(f(y, C1), [C1, y])) == C1 assert constant_renumber(constantsimp(f(C1, y, C2), [C1, C2, y])) == C1 def test_constant_function_multiple(): # The rules to not renumber in this case would be too complicated, and # dsolve is not likely to ever encounter anything remotely like this. assert constant_renumber( constantsimp(f(C1, C1, x), [C1])) == f(C1, C1, x) def test_constant_multiple(): assert constant_renumber(constantsimp(C1*2 + 2, [C1])) == C1 assert constant_renumber(constantsimp(x*2/C1, [C1])) == C1*x assert constant_renumber(constantsimp(C1**2*2 + 2, [C1])) == C1 assert constant_renumber( constantsimp(sin(2*C1) + x + sqrt(2), [C1])) == C1 + x assert constant_renumber(constantsimp(2*C1 + C2, [C1, C2])) == C1 def test_constant_repeated(): assert C1 + C1*x == constant_renumber( C1 + C1*x) def test_ode_solutions(): # only a few examples here, the rest will be tested in the actual dsolve tests assert constant_renumber(constantsimp(C1*exp(2*x) + exp(x)*(C2 + C3), [C1, C2, C3])) == \ constant_renumber(C1*exp(x) + C2*exp(2*x)) assert constant_renumber( constantsimp(Eq(f(x), I*C1*sinh(x/3) + C2*cosh(x/3)), [C1, C2]) ) == constant_renumber(Eq(f(x), C1*sinh(x/3) + C2*cosh(x/3))) assert constant_renumber(constantsimp(Eq(f(x), acos((-C1)/cos(x))), [C1])) == \ Eq(f(x), acos(C1/cos(x))) assert constant_renumber( constantsimp(Eq(log(f(x)/C1) + 2*exp(x/f(x)), 0), [C1]) ) == Eq(log(C1*f(x)) + 2*exp(x/f(x)), 0) assert constant_renumber(constantsimp(Eq(log(x*sqrt(2)*sqrt(1/x)*sqrt(f(x)) /C1) + x**2/(2*f(x)**2), 0), [C1])) == \ Eq(log(C1*sqrt(x)*sqrt(f(x))) + x**2/(2*f(x)**2), 0) assert constant_renumber(constantsimp(Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(x/C1) - cos(f(x)/x)*exp(-f(x)/x)/2, 0), [C1])) == \ Eq(-exp(-f(x)/x)*sin(f(x)/x)/2 + log(C1*x) - cos(f(x)/x)* exp(-f(x)/x)/2, 0) assert constant_renumber(constantsimp(Eq(-Integral(-1/(sqrt(1 - u2**2)*u2), (u2, _a, x/f(x))) + log(f(x)/C1), 0), [C1])) == \ Eq(-Integral(-1/(u2*sqrt(1 - u2**2)), (u2, _a, x/f(x))) + log(C1*f(x)), 0) assert [constantsimp(i, [C1]) for i in [Eq(f(x), sqrt(-C1*x + x**2)), Eq(f(x), -sqrt(-C1*x + x**2))]] == \ [Eq(f(x), sqrt(x*(C1 + x))), Eq(f(x), -sqrt(x*(C1 + x)))] @XFAIL def test_nonlocal_simplification(): assert constantsimp(C1 + C2+x*C2, [C1, C2]) == C1 + C2*x def test_constant_Eq(): # C1 on the rhs is well-tested, but the lhs is only tested here assert constantsimp(Eq(C1, 3 + f(x)*x), [C1]) == Eq(x*f(x), C1) assert constantsimp(Eq(C1, 3 * f(x)*x), [C1]) == Eq(f(x)*x, C1) sympy-sympy-1.9/sympy/solvers/tests/test_decompogen.py000066400000000000000000000046211412543434000234770ustar00rootroot00000000000000from sympy.solvers.decompogen import decompogen, compogen from sympy import sin, cos, sqrt, Abs, exp, symbols from sympy.testing.pytest import XFAIL, raises x, y = symbols('x y') def test_decompogen(): assert decompogen(sin(cos(x)), x) == [sin(x), cos(x)] assert decompogen(sin(x)**2 + sin(x) + 1, x) == [x**2 + x + 1, sin(x)] assert decompogen(sqrt(6*x**2 - 5), x) == [sqrt(x), 6*x**2 - 5] assert decompogen(sin(sqrt(cos(x**2 + 1))), x) == [sin(x), sqrt(x), cos(x), x**2 + 1] assert decompogen(Abs(cos(x)**2 + 3*cos(x) - 4), x) == [Abs(x), x**2 + 3*x - 4, cos(x)] assert decompogen(sin(x)**2 + sin(x) - sqrt(3)/2, x) == [x**2 + x - sqrt(3)/2, sin(x)] assert decompogen(Abs(cos(y)**2 + 3*cos(x) - 4), x) == [Abs(x), 3*x + cos(y)**2 - 4, cos(x)] assert decompogen(x, y) == [x] assert decompogen(1, x) == [1] raises(TypeError, lambda: decompogen(x < 5, x)) def test_decompogen_poly(): assert decompogen(x**4 + 2*x**2 + 1, x) == [x**2 + 2*x + 1, x**2] assert decompogen(x**4 + 2*x**3 - x - 1, x) == [x**2 - x - 1, x**2 + x] @XFAIL def test_decompogen_fails(): A = lambda x: x**2 + 2*x + 3 B = lambda x: 4*x**2 + 5*x + 6 assert decompogen(A(x*exp(x)), x) == [x**2 + 2*x + 3, x*exp(x)] assert decompogen(A(B(x)), x) == [x**2 + 2*x + 3, 4*x**2 + 5*x + 6] assert decompogen(A(1/x + 1/x**2), x) == [x**2 + 2*x + 3, 1/x + 1/x**2] assert decompogen(A(1/x + 2/(x + 1)), x) == [x**2 + 2*x + 3, 1/x + 2/(x + 1)] def test_compogen(): assert compogen([sin(x), cos(x)], x) == sin(cos(x)) assert compogen([x**2 + x + 1, sin(x)], x) == sin(x)**2 + sin(x) + 1 assert compogen([sqrt(x), 6*x**2 - 5], x) == sqrt(6*x**2 - 5) assert compogen([sin(x), sqrt(x), cos(x), x**2 + 1], x) == sin(sqrt( cos(x**2 + 1))) assert compogen([Abs(x), x**2 + 3*x - 4, cos(x)], x) == Abs(cos(x)**2 + 3*cos(x) - 4) assert compogen([x**2 + x - sqrt(3)/2, sin(x)], x) == (sin(x)**2 + sin(x) - sqrt(3)/2) assert compogen([Abs(x), 3*x + cos(y)**2 - 4, cos(x)], x) == \ Abs(3*cos(x) + cos(y)**2 - 4) assert compogen([x**2 + 2*x + 1, x**2], x) == x**4 + 2*x**2 + 1 # the result is in unsimplified form assert compogen([x**2 - x - 1, x**2 + x], x) == -x**2 - x + (x**2 + x)**2 - 1 sympy-sympy-1.9/sympy/solvers/tests/test_inequalities.py000066400000000000000000000473151412543434000240620ustar00rootroot00000000000000"""Tests for tools for solving inequalities and systems of inequalities. """ from sympy import (And, Eq, FiniteSet, Ge, Gt, Interval, Le, Lt, Ne, oo, I, Or, S, sin, cos, tan, sqrt, Symbol, Union, Integral, Sum, Function, Poly, PurePoly, pi, root, log, exp, Dummy, Abs, Piecewise, Rational) from sympy.solvers.inequalities import (reduce_inequalities, solve_poly_inequality as psolve, reduce_rational_inequalities, solve_univariate_inequality as isolve, reduce_abs_inequality, _solve_inequality) from sympy.polys.rootoftools import rootof from sympy.solvers.solvers import solve from sympy.solvers.solveset import solveset from sympy.abc import x, y from sympy.core.mod import Mod from sympy.testing.pytest import raises, XFAIL inf = oo.evalf() def test_solve_poly_inequality(): assert psolve(Poly(0, x), '==') == [S.Reals] assert psolve(Poly(1, x), '==') == [S.EmptySet] assert psolve(PurePoly(x + 1, x), ">") == [Interval(-1, oo, True, False)] def test_reduce_poly_inequalities_real_interval(): assert reduce_rational_inequalities( [[Eq(x**2, 0)]], x, relational=False) == FiniteSet(0) assert reduce_rational_inequalities( [[Le(x**2, 0)]], x, relational=False) == FiniteSet(0) assert reduce_rational_inequalities( [[Lt(x**2, 0)]], x, relational=False) == S.EmptySet assert reduce_rational_inequalities( [[Ge(x**2, 0)]], x, relational=False) == \ S.Reals if x.is_real else Interval(-oo, oo) assert reduce_rational_inequalities( [[Gt(x**2, 0)]], x, relational=False) == \ FiniteSet(0).complement(S.Reals) assert reduce_rational_inequalities( [[Ne(x**2, 0)]], x, relational=False) == \ FiniteSet(0).complement(S.Reals) assert reduce_rational_inequalities( [[Eq(x**2, 1)]], x, relational=False) == FiniteSet(-1, 1) assert reduce_rational_inequalities( [[Le(x**2, 1)]], x, relational=False) == Interval(-1, 1) assert reduce_rational_inequalities( [[Lt(x**2, 1)]], x, relational=False) == Interval(-1, 1, True, True) assert reduce_rational_inequalities( [[Ge(x**2, 1)]], x, relational=False) == \ Union(Interval(-oo, -1), Interval(1, oo)) assert reduce_rational_inequalities( [[Gt(x**2, 1)]], x, relational=False) == \ Interval(-1, 1).complement(S.Reals) assert reduce_rational_inequalities( [[Ne(x**2, 1)]], x, relational=False) == \ FiniteSet(-1, 1).complement(S.Reals) assert reduce_rational_inequalities([[Eq( x**2, 1.0)]], x, relational=False) == FiniteSet(-1.0, 1.0).evalf() assert reduce_rational_inequalities( [[Le(x**2, 1.0)]], x, relational=False) == Interval(-1.0, 1.0) assert reduce_rational_inequalities([[Lt( x**2, 1.0)]], x, relational=False) == Interval(-1.0, 1.0, True, True) assert reduce_rational_inequalities( [[Ge(x**2, 1.0)]], x, relational=False) == \ Union(Interval(-inf, -1.0), Interval(1.0, inf)) assert reduce_rational_inequalities( [[Gt(x**2, 1.0)]], x, relational=False) == \ Union(Interval(-inf, -1.0, right_open=True), Interval(1.0, inf, left_open=True)) assert reduce_rational_inequalities([[Ne( x**2, 1.0)]], x, relational=False) == \ FiniteSet(-1.0, 1.0).complement(S.Reals) s = sqrt(2) assert reduce_rational_inequalities([[Lt( x**2 - 1, 0), Gt(x**2 - 1, 0)]], x, relational=False) == S.EmptySet assert reduce_rational_inequalities([[Le(x**2 - 1, 0), Ge( x**2 - 1, 0)]], x, relational=False) == FiniteSet(-1, 1) assert reduce_rational_inequalities( [[Le(x**2 - 2, 0), Ge(x**2 - 1, 0)]], x, relational=False ) == Union(Interval(-s, -1, False, False), Interval(1, s, False, False)) assert reduce_rational_inequalities( [[Le(x**2 - 2, 0), Gt(x**2 - 1, 0)]], x, relational=False ) == Union(Interval(-s, -1, False, True), Interval(1, s, True, False)) assert reduce_rational_inequalities( [[Lt(x**2 - 2, 0), Ge(x**2 - 1, 0)]], x, relational=False ) == Union(Interval(-s, -1, True, False), Interval(1, s, False, True)) assert reduce_rational_inequalities( [[Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)]], x, relational=False ) == Union(Interval(-s, -1, True, True), Interval(1, s, True, True)) assert reduce_rational_inequalities( [[Lt(x**2 - 2, 0), Ne(x**2 - 1, 0)]], x, relational=False ) == Union(Interval(-s, -1, True, True), Interval(-1, 1, True, True), Interval(1, s, True, True)) assert reduce_rational_inequalities([[Lt(x**2, -1.)]], x) is S.false def test_reduce_poly_inequalities_complex_relational(): assert reduce_rational_inequalities( [[Eq(x**2, 0)]], x, relational=True) == Eq(x, 0) assert reduce_rational_inequalities( [[Le(x**2, 0)]], x, relational=True) == Eq(x, 0) assert reduce_rational_inequalities( [[Lt(x**2, 0)]], x, relational=True) == False assert reduce_rational_inequalities( [[Ge(x**2, 0)]], x, relational=True) == And(Lt(-oo, x), Lt(x, oo)) assert reduce_rational_inequalities( [[Gt(x**2, 0)]], x, relational=True) == \ And(Gt(x, -oo), Lt(x, oo), Ne(x, 0)) assert reduce_rational_inequalities( [[Ne(x**2, 0)]], x, relational=True) == \ And(Gt(x, -oo), Lt(x, oo), Ne(x, 0)) for one in (S.One, S(1.0)): inf = one*oo assert reduce_rational_inequalities( [[Eq(x**2, one)]], x, relational=True) == \ Or(Eq(x, -one), Eq(x, one)) assert reduce_rational_inequalities( [[Le(x**2, one)]], x, relational=True) == \ And(And(Le(-one, x), Le(x, one))) assert reduce_rational_inequalities( [[Lt(x**2, one)]], x, relational=True) == \ And(And(Lt(-one, x), Lt(x, one))) assert reduce_rational_inequalities( [[Ge(x**2, one)]], x, relational=True) == \ And(Or(And(Le(one, x), Lt(x, inf)), And(Le(x, -one), Lt(-inf, x)))) assert reduce_rational_inequalities( [[Gt(x**2, one)]], x, relational=True) == \ And(Or(And(Lt(-inf, x), Lt(x, -one)), And(Lt(one, x), Lt(x, inf)))) assert reduce_rational_inequalities( [[Ne(x**2, one)]], x, relational=True) == \ Or(And(Lt(-inf, x), Lt(x, -one)), And(Lt(-one, x), Lt(x, one)), And(Lt(one, x), Lt(x, inf))) def test_reduce_rational_inequalities_real_relational(): assert reduce_rational_inequalities([], x) == False assert reduce_rational_inequalities( [[(x**2 + 3*x + 2)/(x**2 - 16) >= 0]], x, relational=False) == \ Union(Interval.open(-oo, -4), Interval(-2, -1), Interval.open(4, oo)) assert reduce_rational_inequalities( [[((-2*x - 10)*(3 - x))/((x**2 + 5)*(x - 2)**2) < 0]], x, relational=False) == \ Union(Interval.open(-5, 2), Interval.open(2, 3)) assert reduce_rational_inequalities([[(x + 1)/(x - 5) <= 0]], x, relational=False) == \ Interval.Ropen(-1, 5) assert reduce_rational_inequalities([[(x**2 + 4*x + 3)/(x - 1) > 0]], x, relational=False) == \ Union(Interval.open(-3, -1), Interval.open(1, oo)) assert reduce_rational_inequalities([[(x**2 - 16)/(x - 1)**2 < 0]], x, relational=False) == \ Union(Interval.open(-4, 1), Interval.open(1, 4)) assert reduce_rational_inequalities([[(3*x + 1)/(x + 4) >= 1]], x, relational=False) == \ Union(Interval.open(-oo, -4), Interval.Ropen(Rational(3, 2), oo)) assert reduce_rational_inequalities([[(x - 8)/x <= 3 - x]], x, relational=False) == \ Union(Interval.Lopen(-oo, -2), Interval.Lopen(0, 4)) # issue sympy/sympy#10237 assert reduce_rational_inequalities( [[x < oo, x >= 0, -oo < x]], x, relational=False) == Interval(0, oo) def test_reduce_abs_inequalities(): e = abs(x - 5) < 3 ans = And(Lt(2, x), Lt(x, 8)) assert reduce_inequalities(e) == ans assert reduce_inequalities(e, x) == ans assert reduce_inequalities(abs(x - 5)) == Eq(x, 5) assert reduce_inequalities( abs(2*x + 3) >= 8) == Or(And(Le(Rational(5, 2), x), Lt(x, oo)), And(Le(x, Rational(-11, 2)), Lt(-oo, x))) assert reduce_inequalities(abs(x - 4) + abs( 3*x - 5) < 7) == And(Lt(S.Half, x), Lt(x, 4)) assert reduce_inequalities(abs(x - 4) + abs(3*abs(x) - 5) < 7) == \ Or(And(S(-2) < x, x < -1), And(S.Half < x, x < 4)) nr = Symbol('nr', extended_real=False) raises(TypeError, lambda: reduce_inequalities(abs(nr - 5) < 3)) assert reduce_inequalities(x < 3, symbols=[x, nr]) == And(-oo < x, x < 3) def test_reduce_inequalities_general(): assert reduce_inequalities(Ge(sqrt(2)*x, 1)) == And(sqrt(2)/2 <= x, x < oo) assert reduce_inequalities(x + 1 > 0) == And(S.NegativeOne < x, x < oo) def test_reduce_inequalities_boolean(): assert reduce_inequalities( [Eq(x**2, 0), True]) == Eq(x, 0) assert reduce_inequalities([Eq(x**2, 0), False]) == False assert reduce_inequalities(x**2 >= 0) is S.true # issue 10196 def test_reduce_inequalities_multivariate(): assert reduce_inequalities([Ge(x**2, 1), Ge(y**2, 1)]) == And( Or(And(Le(S.One, x), Lt(x, oo)), And(Le(x, -1), Lt(-oo, x))), Or(And(Le(S.One, y), Lt(y, oo)), And(Le(y, -1), Lt(-oo, y)))) def test_reduce_inequalities_errors(): raises(NotImplementedError, lambda: reduce_inequalities(Ge(sin(x) + x, 1))) raises(NotImplementedError, lambda: reduce_inequalities(Ge(x**2*y + y, 1))) def test__solve_inequalities(): assert reduce_inequalities(x + y < 1, symbols=[x]) == (x < 1 - y) assert reduce_inequalities(x + y >= 1, symbols=[x]) == (x < oo) & (x >= -y + 1) assert reduce_inequalities(Eq(0, x - y), symbols=[x]) == Eq(x, y) assert reduce_inequalities(Ne(0, x - y), symbols=[x]) == Ne(x, y) def test_issue_6343(): eq = -3*x**2/2 - x*Rational(45, 4) + Rational(33, 2) > 0 assert reduce_inequalities(eq) == \ And(x < Rational(-15, 4) + sqrt(401)/4, -sqrt(401)/4 - Rational(15, 4) < x) def test_issue_8235(): assert reduce_inequalities(x**2 - 1 < 0) == \ And(S.NegativeOne < x, x < 1) assert reduce_inequalities(x**2 - 1 <= 0) == \ And(S.NegativeOne <= x, x <= 1) assert reduce_inequalities(x**2 - 1 > 0) == \ Or(And(-oo < x, x < -1), And(x < oo, S.One < x)) assert reduce_inequalities(x**2 - 1 >= 0) == \ Or(And(-oo < x, x <= -1), And(S.One <= x, x < oo)) eq = x**8 + x - 9 # we want CRootOf solns here sol = solve(eq >= 0) tru = Or(And(rootof(eq, 1) <= x, x < oo), And(-oo < x, x <= rootof(eq, 0))) assert sol == tru # recast vanilla as real assert solve(sqrt((-x + 1)**2) < 1) == And(S.Zero < x, x < 2) def test_issue_5526(): assert reduce_inequalities(0 <= x + Integral(y**2, (y, 1, 3)) - 1, [x]) == \ (x >= -Integral(y**2, (y, 1, 3)) + 1) f = Function('f') e = Sum(f(x), (x, 1, 3)) assert reduce_inequalities(0 <= x + e + y**2, [x]) == \ (x >= -y**2 - Sum(f(x), (x, 1, 3))) def test_solve_univariate_inequality(): assert isolve(x**2 >= 4, x, relational=False) == Union(Interval(-oo, -2), Interval(2, oo)) assert isolve(x**2 >= 4, x) == Or(And(Le(2, x), Lt(x, oo)), And(Le(x, -2), Lt(-oo, x))) assert isolve((x - 1)*(x - 2)*(x - 3) >= 0, x, relational=False) == \ Union(Interval(1, 2), Interval(3, oo)) assert isolve((x - 1)*(x - 2)*(x - 3) >= 0, x) == \ Or(And(Le(1, x), Le(x, 2)), And(Le(3, x), Lt(x, oo))) assert isolve((x - 1)*(x - 2)*(x - 4) < 0, x, domain = FiniteSet(0, 3)) == \ Or(Eq(x, 0), Eq(x, 3)) # issue 2785: assert isolve(x**3 - 2*x - 1 > 0, x, relational=False) == \ Union(Interval(-1, -sqrt(5)/2 + S.Half, True, True), Interval(S.Half + sqrt(5)/2, oo, True, True)) # issue 2794: assert isolve(x**3 - x**2 + x - 1 > 0, x, relational=False) == \ Interval(1, oo, True) #issue 13105 assert isolve((x + I)*(x + 2*I) < 0, x) == Eq(x, 0) assert isolve(((x - 1)*(x - 2) + I)*((x - 1)*(x - 2) + 2*I) < 0, x) == Or(Eq(x, 1), Eq(x, 2)) assert isolve((((x - 1)*(x - 2) + I)*((x - 1)*(x - 2) + 2*I))/(x - 2) > 0, x) == Eq(x, 1) raises (ValueError, lambda: isolve((x**2 - 3*x*I + 2)/x < 0, x)) # numerical testing in valid() is needed assert isolve(x**7 - x - 2 > 0, x) == \ And(rootof(x**7 - x - 2, 0) < x, x < oo) # handle numerator and denominator; although these would be handled as # rational inequalities, these test confirm that the right thing is done # when the domain is EX (e.g. when 2 is replaced with sqrt(2)) assert isolve(1/(x - 2) > 0, x) == And(S(2) < x, x < oo) den = ((x - 1)*(x - 2)).expand() assert isolve((x - 1)/den <= 0, x) == \ (x > -oo) & (x < 2) & Ne(x, 1) n = Dummy('n') raises(NotImplementedError, lambda: isolve(Abs(x) <= n, x, relational=False)) c1 = Dummy("c1", positive=True) raises(NotImplementedError, lambda: isolve(n/c1 < 0, c1)) n = Dummy('n', negative=True) assert isolve(n/c1 > -2, c1) == (-n/2 < c1) assert isolve(n/c1 < 0, c1) == True assert isolve(n/c1 > 0, c1) == False zero = cos(1)**2 + sin(1)**2 - 1 raises(NotImplementedError, lambda: isolve(x**2 < zero, x)) raises(NotImplementedError, lambda: isolve( x**2 < zero*I, x)) raises(NotImplementedError, lambda: isolve(1/(x - y) < 2, x)) raises(NotImplementedError, lambda: isolve(1/(x - y) < 0, x)) raises(TypeError, lambda: isolve(x - I < 0, x)) zero = x**2 + x - x*(x + 1) assert isolve(zero < 0, x, relational=False) is S.EmptySet assert isolve(zero <= 0, x, relational=False) is S.Reals # make sure iter_solutions gets a default value raises(NotImplementedError, lambda: isolve( Eq(cos(x)**2 + sin(x)**2, 1), x)) def test_trig_inequalities(): # all the inequalities are solved in a periodic interval. assert isolve(sin(x) < S.Half, x, relational=False) == \ Union(Interval(0, pi/6, False, True), Interval.open(pi*Rational(5, 6), 2*pi)) assert isolve(sin(x) > S.Half, x, relational=False) == \ Interval(pi/6, pi*Rational(5, 6), True, True) assert isolve(cos(x) < S.Zero, x, relational=False) == \ Interval(pi/2, pi*Rational(3, 2), True, True) assert isolve(cos(x) >= S.Zero, x, relational=False) == \ Union(Interval(0, pi/2), Interval.Ropen(pi*Rational(3, 2), 2*pi)) assert isolve(tan(x) < S.One, x, relational=False) == \ Union(Interval.Ropen(0, pi/4), Interval.open(pi/2, pi)) assert isolve(sin(x) <= S.Zero, x, relational=False) == \ Union(FiniteSet(S.Zero), Interval.Ropen(pi, 2*pi)) assert isolve(sin(x) <= S.One, x, relational=False) == S.Reals assert isolve(cos(x) < S(-2), x, relational=False) == S.EmptySet assert isolve(sin(x) >= S.NegativeOne, x, relational=False) == S.Reals assert isolve(cos(x) > S.One, x, relational=False) == S.EmptySet def test_issue_9954(): assert isolve(x**2 >= 0, x, relational=False) == S.Reals assert isolve(x**2 >= 0, x, relational=True) == S.Reals.as_relational(x) assert isolve(x**2 < 0, x, relational=False) == S.EmptySet assert isolve(x**2 < 0, x, relational=True) == S.EmptySet.as_relational(x) @XFAIL def test_slow_general_univariate(): r = rootof(x**5 - x**2 + 1, 0) assert solve(sqrt(x) + 1/root(x, 3) > 1) == \ Or(And(0 < x, x < r**6), And(r**6 < x, x < oo)) def test_issue_8545(): eq = 1 - x - abs(1 - x) ans = And(Lt(1, x), Lt(x, oo)) assert reduce_abs_inequality(eq, '<', x) == ans eq = 1 - x - sqrt((1 - x)**2) assert reduce_inequalities(eq < 0) == ans def test_issue_8974(): assert isolve(-oo < x, x) == And(-oo < x, x < oo) assert isolve(oo > x, x) == And(-oo < x, x < oo) def test_issue_10198(): assert reduce_inequalities( -1 + 1/abs(1/x - 1) < 0) == (x > -oo) & (x < 1/2) & Ne(x, 0) assert reduce_inequalities(abs(1/sqrt(x)) - 1, x) == Eq(x, 1) assert reduce_abs_inequality(-3 + 1/abs(1 - 1/x), '<', x) == \ Or(And(-oo < x, x < 0), And(S.Zero < x, x < Rational(3, 4)), And(Rational(3, 2) < x, x < oo)) raises(ValueError,lambda: reduce_abs_inequality(-3 + 1/abs( 1 - 1/sqrt(x)), '<', x)) def test_issue_10047(): # issue 10047: this must remain an inequality, not True, since if x # is not real the inequality is invalid # assert solve(sin(x) < 2) == (x <= oo) # with PR 16956, (x <= oo) autoevaluates when x is extended_real # which is assumed in the current implementation of inequality solvers assert solve(sin(x) < 2) == True assert solveset(sin(x) < 2, domain=S.Reals) == S.Reals def test_issue_10268(): assert solve(log(x) < 1000) == And(S.Zero < x, x < exp(1000)) @XFAIL def test_isolve_Sets(): n = Dummy('n') assert isolve(Abs(x) <= n, x, relational=False) == \ Piecewise((S.EmptySet, n < 0), (Interval(-n, n), True)) def test_integer_domain_relational_isolve(): dom = FiniteSet(0, 3) x = Symbol('x',zero=False) assert isolve((x - 1)*(x - 2)*(x - 4) < 0, x, domain=dom) == Eq(x, 3) x = Symbol('x') assert isolve(x + 2 < 0, x, domain=S.Integers) == \ (x <= -3) & (x > -oo) & Eq(Mod(x, 1), 0) assert isolve(2 * x + 3 > 0, x, domain=S.Integers) == \ (x >= -1) & (x < oo) & Eq(Mod(x, 1), 0) assert isolve((x ** 2 + 3 * x - 2) < 0, x, domain=S.Integers) == \ (x >= -3) & (x <= 0) & Eq(Mod(x, 1), 0) assert isolve((x ** 2 + 3 * x - 2) > 0, x, domain=S.Integers) == \ ((x >= 1) & (x < oo) & Eq(Mod(x, 1), 0)) | ( (x <= -4) & (x > -oo) & Eq(Mod(x, 1), 0)) def test_issue_10671_12466(): assert solveset(sin(y), y, Interval(0, pi)) == FiniteSet(0, pi) i = Interval(1, 10) assert solveset((1/x).diff(x) < 0, x, i) == i assert solveset((log(x - 6)/x) <= 0, x, S.Reals) == \ Interval.Lopen(6, 7) def test__solve_inequality(): for op in (Gt, Lt, Le, Ge, Eq, Ne): assert _solve_inequality(op(x, 1), x).lhs == x assert _solve_inequality(op(S.One, x), x).lhs == x # don't get tricked by symbol on right: solve it assert _solve_inequality(Eq(2*x - 1, x), x) == Eq(x, 1) ie = Eq(S.One, y) assert _solve_inequality(ie, x) == ie for fx in (x**2, exp(x), sin(x) + cos(x), x*(1 + x)): for c in (0, 1): e = 2*fx - c > 0 assert _solve_inequality(e, x, linear=True) == ( fx > c/S(2)) assert _solve_inequality(2*x**2 + 2*x - 1 < 0, x, linear=True) == ( x*(x + 1) < S.Half) assert _solve_inequality(Eq(x*y, 1), x) == Eq(x*y, 1) nz = Symbol('nz', nonzero=True) assert _solve_inequality(Eq(x*nz, 1), x) == Eq(x, 1/nz) assert _solve_inequality(x*nz < 1, x) == (x*nz < 1) a = Symbol('a', positive=True) assert _solve_inequality(a/x > 1, x) == (S.Zero < x) & (x < a) assert _solve_inequality(a/x > 1, x, linear=True) == (1/x > 1/a) # make sure to include conditions under which solution is valid e = Eq(1 - x, x*(1/x - 1)) assert _solve_inequality(e, x) == Ne(x, 0) assert _solve_inequality(x < x*(1/x - 1), x) == (x < S.Half) & Ne(x, 0) def test__pt(): from sympy.solvers.inequalities import _pt assert _pt(-oo, oo) == 0 assert _pt(S.One, S(3)) == 2 assert _pt(S.One, oo) == _pt(oo, S.One) == 2 assert _pt(S.One, -oo) == _pt(-oo, S.One) == S.Half assert _pt(S.NegativeOne, oo) == _pt(oo, S.NegativeOne) == Rational(-1, 2) assert _pt(S.NegativeOne, -oo) == _pt(-oo, S.NegativeOne) == -2 assert _pt(x, oo) == _pt(oo, x) == x + 1 assert _pt(x, -oo) == _pt(-oo, x) == x - 1 raises(ValueError, lambda: _pt(Dummy('i', infinite=True), S.One)) sympy-sympy-1.9/sympy/solvers/tests/test_numeric.py000066400000000000000000000104541412543434000230220ustar00rootroot00000000000000from sympy import (Eq, Matrix, pi, sin, sqrt, Symbol, Integral, Piecewise, symbols, Float, I, Rational) from mpmath import mnorm, mpf from sympy.solvers import nsolve from sympy.utilities.lambdify import lambdify from sympy.testing.pytest import raises, XFAIL from sympy.utilities.decorator import conserve_mpmath_dps @XFAIL def test_nsolve_fail(): x = symbols('x') # Sometimes it is better to use the numerator (issue 4829) # but sometimes it is not (issue 11768) so leave this to # the discretion of the user ans = nsolve(x**2/(1 - x)/(1 - 2*x)**2 - 100, x, 0) assert ans > 0.46 and ans < 0.47 def test_nsolve_denominator(): x = symbols('x') # Test that nsolve uses the full expression (numerator and denominator). ans = nsolve((x**2 + 3*x + 2)/(x + 2), -2.1) # The root -2 was divided out, so make sure we don't find it. assert ans == -1.0 def test_nsolve(): # onedimensional x = Symbol('x') assert nsolve(sin(x), 2) - pi.evalf() < 1e-15 assert nsolve(Eq(2*x, 2), x, -10) == nsolve(2*x - 2, -10) # Testing checks on number of inputs raises(TypeError, lambda: nsolve(Eq(2*x, 2))) raises(TypeError, lambda: nsolve(Eq(2*x, 2), x, 1, 2)) # multidimensional x1 = Symbol('x1') x2 = Symbol('x2') f1 = 3 * x1**2 - 2 * x2**2 - 1 f2 = x1**2 - 2 * x1 + x2**2 + 2 * x2 - 8 f = Matrix((f1, f2)).T F = lambdify((x1, x2), f.T, modules='mpmath') for x0 in [(-1, 1), (1, -2), (4, 4), (-4, -4)]: x = nsolve(f, (x1, x2), x0, tol=1.e-8) assert mnorm(F(*x), 1) <= 1.e-10 # The Chinese mathematician Zhu Shijie was the very first to solve this # nonlinear system 700 years ago (z was added to make it 3-dimensional) x = Symbol('x') y = Symbol('y') z = Symbol('z') f1 = -x + 2*y f2 = (x**2 + x*(y**2 - 2) - 4*y) / (x + 4) f3 = sqrt(x**2 + y**2)*z f = Matrix((f1, f2, f3)).T F = lambdify((x, y, z), f.T, modules='mpmath') def getroot(x0): root = nsolve(f, (x, y, z), x0) assert mnorm(F(*root), 1) <= 1.e-8 return root assert list(map(round, getroot((1, 1, 1)))) == [2.0, 1.0, 0.0] assert nsolve([Eq( f1, 0), Eq(f2, 0), Eq(f3, 0)], [x, y, z], (1, 1, 1)) # just see that it works a = Symbol('a') assert abs(nsolve(1/(0.001 + a)**3 - 6/(0.9 - a)**3, a, 0.3) - mpf('0.31883011387318591')) < 1e-15 def test_issue_6408(): x = Symbol('x') assert nsolve(Piecewise((x, x < 1), (x**2, True)), x, 2) == 0.0 def test_issue_6408_integral(): x, y = symbols('x y') assert nsolve(Integral(x*y, (x, 0, 5)), y, 2) == 0.0 @conserve_mpmath_dps def test_increased_dps(): # Issue 8564 import mpmath mpmath.mp.dps = 128 x = Symbol('x') e1 = x**2 - pi q = nsolve(e1, x, 3.0) assert abs(sqrt(pi).evalf(128) - q) < 1e-128 def test_nsolve_precision(): x, y = symbols('x y') sol = nsolve(x**2 - pi, x, 3, prec=128) assert abs(sqrt(pi).evalf(128) - sol) < 1e-128 assert isinstance(sol, Float) sols = nsolve((y**2 - x, x**2 - pi), (x, y), (3, 3), prec=128) assert isinstance(sols, Matrix) assert sols.shape == (2, 1) assert abs(sqrt(pi).evalf(128) - sols[0]) < 1e-128 assert abs(sqrt(sqrt(pi)).evalf(128) - sols[1]) < 1e-128 assert all(isinstance(i, Float) for i in sols) def test_nsolve_complex(): x, y = symbols('x y') assert nsolve(x**2 + 2, 1j) == sqrt(2.)*I assert nsolve(x**2 + 2, I) == sqrt(2.)*I assert nsolve([x**2 + 2, y**2 + 2], [x, y], [I, I]) == Matrix([sqrt(2.)*I, sqrt(2.)*I]) assert nsolve([x**2 + 2, y**2 + 2], [x, y], [I, I]) == Matrix([sqrt(2.)*I, sqrt(2.)*I]) def test_nsolve_dict_kwarg(): x, y = symbols('x y') # one variable assert nsolve(x**2 - 2, 1, dict = True) == \ [{x: sqrt(2.)}] # one variable with complex solution assert nsolve(x**2 + 2, I, dict = True) == \ [{x: sqrt(2.)*I}] # two variables assert nsolve([x**2 + y**2 - 5, x**2 - y**2 + 1], [x, y], [1, 1], dict = True) == \ [{x: sqrt(2.), y: sqrt(3.)}] def test_nsolve_rational(): x = symbols('x') assert nsolve(x - Rational(1, 3), 0, prec=100) == Rational(1, 3).evalf(100) def test_issue_14950(): x = Matrix(symbols('t s')) x0 = Matrix([17, 23]) eqn = x + x0 assert nsolve(eqn, x, x0) == -x0 assert nsolve(eqn.T, x.T, x0.T) == -x0 sympy-sympy-1.9/sympy/solvers/tests/test_pde.py000066400000000000000000000215411412543434000221270ustar00rootroot00000000000000from sympy import (Derivative as D, Eq, exp, sin, Function, Symbol, symbols, cos, log) from sympy.core import S from sympy.solvers.pde import (pde_separate, pde_separate_add, pde_separate_mul, pdsolve, classify_pde, checkpdesol) from sympy.testing.pytest import raises a, b, c, x, y = symbols('a b c x y') def test_pde_separate_add(): x, y, z, t = symbols("x,y,z,t") F, T, X, Y, Z, u = map(Function, 'FTXYZu') eq = Eq(D(u(x, t), x), D(u(x, t), t)*exp(u(x, t))) res = pde_separate_add(eq, u(x, t), [X(x), T(t)]) assert res == [D(X(x), x)*exp(-X(x)), D(T(t), t)*exp(T(t))] def test_pde_separate(): x, y, z, t = symbols("x,y,z,t") F, T, X, Y, Z, u = map(Function, 'FTXYZu') eq = Eq(D(u(x, t), x), D(u(x, t), t)*exp(u(x, t))) raises(ValueError, lambda: pde_separate(eq, u(x, t), [X(x), T(t)], 'div')) def test_pde_separate_mul(): x, y, z, t = symbols("x,y,z,t") c = Symbol("C", real=True) Phi = Function('Phi') F, R, T, X, Y, Z, u = map(Function, 'FRTXYZu') r, theta, z = symbols('r,theta,z') # Something simple :) eq = Eq(D(F(x, y, z), x) + D(F(x, y, z), y) + D(F(x, y, z), z), 0) # Duplicate arguments in functions raises( ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(x), u(z, z)])) # Wrong number of arguments raises(ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(x), Y(y)])) # Wrong variables: [x, y] -> [x, z] raises( ValueError, lambda: pde_separate_mul(eq, F(x, y, z), [X(t), Y(x, y)])) assert pde_separate_mul(eq, F(x, y, z), [Y(y), u(x, z)]) == \ [D(Y(y), y)/Y(y), -D(u(x, z), x)/u(x, z) - D(u(x, z), z)/u(x, z)] assert pde_separate_mul(eq, F(x, y, z), [X(x), Y(y), Z(z)]) == \ [D(X(x), x)/X(x), -D(Z(z), z)/Z(z) - D(Y(y), y)/Y(y)] # wave equation wave = Eq(D(u(x, t), t, t), c**2*D(u(x, t), x, x)) res = pde_separate_mul(wave, u(x, t), [X(x), T(t)]) assert res == [D(X(x), x, x)/X(x), D(T(t), t, t)/(c**2*T(t))] # Laplace equation in cylindrical coords eq = Eq(1/r * D(Phi(r, theta, z), r) + D(Phi(r, theta, z), r, 2) + 1/r**2 * D(Phi(r, theta, z), theta, 2) + D(Phi(r, theta, z), z, 2), 0) # Separate z res = pde_separate_mul(eq, Phi(r, theta, z), [Z(z), u(theta, r)]) assert res == [D(Z(z), z, z)/Z(z), -D(u(theta, r), r, r)/u(theta, r) - D(u(theta, r), r)/(r*u(theta, r)) - D(u(theta, r), theta, theta)/(r**2*u(theta, r))] # Lets use the result to create a new equation... eq = Eq(res[1], c) # ...and separate theta... res = pde_separate_mul(eq, u(theta, r), [T(theta), R(r)]) assert res == [D(T(theta), theta, theta)/T(theta), -r*D(R(r), r)/R(r) - r**2*D(R(r), r, r)/R(r) - c*r**2] # ...or r... res = pde_separate_mul(eq, u(theta, r), [R(r), T(theta)]) assert res == [r*D(R(r), r)/R(r) + r**2*D(R(r), r, r)/R(r) + c*r**2, -D(T(theta), theta, theta)/T(theta)] def test_issue_11726(): x, t = symbols("x t") f = symbols("f", cls=Function) X, T = symbols("X T", cls=Function) u = f(x, t) eq = u.diff(x, 2) - u.diff(t, 2) res = pde_separate(eq, u, [T(x), X(t)]) assert res == [D(T(x), x, x)/T(x),D(X(t), t, t)/X(t)] def test_pde_classify(): # When more number of hints are added, add tests for classifying here. f = Function('f') eq1 = a*f(x,y) + b*f(x,y).diff(x) + c*f(x,y).diff(y) eq2 = 3*f(x,y) + 2*f(x,y).diff(x) + f(x,y).diff(y) eq3 = a*f(x,y) + b*f(x,y).diff(x) + 2*f(x,y).diff(y) eq4 = x*f(x,y) + f(x,y).diff(x) + 3*f(x,y).diff(y) eq5 = x**2*f(x,y) + x*f(x,y).diff(x) + x*y*f(x,y).diff(y) eq6 = y*x**2*f(x,y) + y*f(x,y).diff(x) + f(x,y).diff(y) for eq in [eq1, eq2, eq3]: assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) for eq in [eq4, eq5, eq6]: assert classify_pde(eq) == ('1st_linear_variable_coeff',) def test_checkpdesol(): f, F = map(Function, ['f', 'F']) eq1 = a*f(x,y) + b*f(x,y).diff(x) + c*f(x,y).diff(y) eq2 = 3*f(x,y) + 2*f(x,y).diff(x) + f(x,y).diff(y) eq3 = a*f(x,y) + b*f(x,y).diff(x) + 2*f(x,y).diff(y) for eq in [eq1, eq2, eq3]: assert checkpdesol(eq, pdsolve(eq))[0] eq4 = x*f(x,y) + f(x,y).diff(x) + 3*f(x,y).diff(y) eq5 = 2*f(x,y) + 1*f(x,y).diff(x) + 3*f(x,y).diff(y) eq6 = f(x,y) + 1*f(x,y).diff(x) + 3*f(x,y).diff(y) assert checkpdesol(eq4, [pdsolve(eq5), pdsolve(eq6)]) == [ (False, (x - 2)*F(3*x - y)*exp(-x/S(5) - 3*y/S(5))), (False, (x - 1)*F(3*x - y)*exp(-x/S(10) - 3*y/S(10)))] for eq in [eq4, eq5, eq6]: assert checkpdesol(eq, pdsolve(eq))[0] sol = pdsolve(eq4) sol4 = Eq(sol.lhs - sol.rhs, 0) raises(NotImplementedError, lambda: checkpdesol(eq4, sol4, solve_for_func=False)) def test_solvefun(): f, F, G, H = map(Function, ['f', 'F', 'G', 'H']) eq1 = f(x,y) + f(x,y).diff(x) + f(x,y).diff(y) assert pdsolve(eq1) == Eq(f(x, y), F(x - y)*exp(-x/2 - y/2)) assert pdsolve(eq1, solvefun=G) == Eq(f(x, y), G(x - y)*exp(-x/2 - y/2)) assert pdsolve(eq1, solvefun=H) == Eq(f(x, y), H(x - y)*exp(-x/2 - y/2)) def test_pde_1st_linear_constant_coeff_homogeneous(): f, F = map(Function, ['f', 'F']) u = f(x, y) eq = 2*u + u.diff(x) + u.diff(y) assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) sol = pdsolve(eq) assert sol == Eq(u, F(x - y)*exp(-x - y)) assert checkpdesol(eq, sol)[0] eq = 4 + (3*u.diff(x)/u) + (2*u.diff(y)/u) assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) sol = pdsolve(eq) assert sol == Eq(u, F(2*x - 3*y)*exp(-S(12)*x/13 - S(8)*y/13)) assert checkpdesol(eq, sol)[0] eq = u + (6*u.diff(x)) + (7*u.diff(y)) assert classify_pde(eq) == ('1st_linear_constant_coeff_homogeneous',) sol = pdsolve(eq) assert sol == Eq(u, F(7*x - 6*y)*exp(-6*x/S(85) - 7*y/S(85))) assert checkpdesol(eq, sol)[0] eq = a*u + b*u.diff(x) + c*u.diff(y) sol = pdsolve(eq) assert checkpdesol(eq, sol)[0] def test_pde_1st_linear_constant_coeff(): f, F = map(Function, ['f', 'F']) u = f(x,y) eq = -2*u.diff(x) + 4*u.diff(y) + 5*u - exp(x + 3*y) sol = pdsolve(eq) assert sol == Eq(f(x,y), (F(4*x + 2*y) + exp(x/S(2) + 4*y)/S(15))*exp(x/S(2) - y)) assert classify_pde(eq) == ('1st_linear_constant_coeff', '1st_linear_constant_coeff_Integral') assert checkpdesol(eq, sol)[0] eq = (u.diff(x)/u) + (u.diff(y)/u) + 1 - (exp(x + y)/u) sol = pdsolve(eq) assert sol == Eq(f(x, y), F(x - y)*exp(-x/2 - y/2) + exp(x + y)/S(3)) assert classify_pde(eq) == ('1st_linear_constant_coeff', '1st_linear_constant_coeff_Integral') assert checkpdesol(eq, sol)[0] eq = 2*u + -u.diff(x) + 3*u.diff(y) + sin(x) sol = pdsolve(eq) assert sol == Eq(f(x, y), F(3*x + y)*exp(x/S(5) - 3*y/S(5)) - 2*sin(x)/S(5) - cos(x)/S(5)) assert classify_pde(eq) == ('1st_linear_constant_coeff', '1st_linear_constant_coeff_Integral') assert checkpdesol(eq, sol)[0] eq = u + u.diff(x) + u.diff(y) + x*y sol = pdsolve(eq) assert sol == Eq(f(x, y), -x*y + x + y + F(x - y)*exp(-x/S(2) - y/S(2)) - 2) assert classify_pde(eq) == ('1st_linear_constant_coeff', '1st_linear_constant_coeff_Integral') assert checkpdesol(eq, sol)[0] eq = u + u.diff(x) + u.diff(y) + log(x) assert classify_pde(eq) == ('1st_linear_constant_coeff', '1st_linear_constant_coeff_Integral') def test_pdsolve_all(): f, F = map(Function, ['f', 'F']) u = f(x,y) eq = u + u.diff(x) + u.diff(y) + x**2*y sol = pdsolve(eq, hint = 'all') keys = ['1st_linear_constant_coeff', '1st_linear_constant_coeff_Integral', 'default', 'order'] assert sorted(sol.keys()) == keys assert sol['order'] == 1 assert sol['default'] == '1st_linear_constant_coeff' assert sol['1st_linear_constant_coeff'] == Eq(f(x, y), -x**2*y + x**2 + 2*x*y - 4*x - 2*y + F(x - y)*exp(-x/S(2) - y/S(2)) + 6) def test_pdsolve_variable_coeff(): f, F = map(Function, ['f', 'F']) u = f(x, y) eq = x*(u.diff(x)) - y*(u.diff(y)) + y**2*u - y**2 sol = pdsolve(eq, hint="1st_linear_variable_coeff") assert sol == Eq(u, F(x*y)*exp(y**2/2) + 1) assert checkpdesol(eq, sol)[0] eq = x**2*u + x*u.diff(x) + x*y*u.diff(y) sol = pdsolve(eq, hint='1st_linear_variable_coeff') assert sol == Eq(u, F(y*exp(-x))*exp(-x**2/2)) assert checkpdesol(eq, sol)[0] eq = y*x**2*u + y*u.diff(x) + u.diff(y) sol = pdsolve(eq, hint='1st_linear_variable_coeff') assert sol == Eq(u, F(-2*x + y**2)*exp(-x**3/3)) assert checkpdesol(eq, sol)[0] eq = exp(x)**2*(u.diff(x)) + y sol = pdsolve(eq, hint='1st_linear_variable_coeff') assert sol == Eq(u, y*exp(-2*x)/2 + F(y)) assert checkpdesol(eq, sol)[0] eq = exp(2*x)*(u.diff(y)) + y*u - u sol = pdsolve(eq, hint='1st_linear_variable_coeff') assert sol == Eq(u, exp((-y**2 + 2*y + 2*F(x))*exp(-2*x)/2)) sympy-sympy-1.9/sympy/solvers/tests/test_polysys.py000066400000000000000000000113671412543434000231060ustar00rootroot00000000000000"""Tests for solvers of systems of polynomial equations. """ from sympy import (flatten, I, Integer, Poly, QQ, Rational, S, sqrt, solve, symbols) from sympy.abc import x, y, z from sympy.polys import PolynomialError from sympy.solvers.polysys import (solve_poly_system, solve_triangulated, solve_biquadratic, SolveFailed) from sympy.polys.polytools import parallel_poly_from_expr from sympy.testing.pytest import raises def test_solve_poly_system(): assert solve_poly_system([x - 1], x) == [(S.One,)] assert solve_poly_system([y - x, y - x - 1], x, y) is None assert solve_poly_system([y - x**2, y + x**2], x, y) == [(S.Zero, S.Zero)] assert solve_poly_system([2*x - 3, y*Rational(3, 2) - 2*x, z - 5*y], x, y, z) == \ [(Rational(3, 2), Integer(2), Integer(10))] assert solve_poly_system([x*y - 2*y, 2*y**2 - x**2], x, y) == \ [(0, 0), (2, -sqrt(2)), (2, sqrt(2))] assert solve_poly_system([y - x**2, y + x**2 + 1], x, y) == \ [(-I*sqrt(S.Half), Rational(-1, 2)), (I*sqrt(S.Half), Rational(-1, 2))] f_1 = x**2 + y + z - 1 f_2 = x + y**2 + z - 1 f_3 = x + y + z**2 - 1 a, b = sqrt(2) - 1, -sqrt(2) - 1 assert solve_poly_system([f_1, f_2, f_3], x, y, z) == \ [(0, 0, 1), (0, 1, 0), (1, 0, 0), (a, a, a), (b, b, b)] solution = [(1, -1), (1, 1)] assert solve_poly_system([Poly(x**2 - y**2), Poly(x - 1)]) == solution assert solve_poly_system([x**2 - y**2, x - 1], x, y) == solution assert solve_poly_system([x**2 - y**2, x - 1]) == solution assert solve_poly_system( [x + x*y - 3, y + x*y - 4], x, y) == [(-3, -2), (1, 2)] raises(NotImplementedError, lambda: solve_poly_system([x**3 - y**3], x, y)) raises(NotImplementedError, lambda: solve_poly_system( [z, -2*x*y**2 + x + y**2*z, y**2*(-z - 4) + 2])) raises(PolynomialError, lambda: solve_poly_system([1/x], x)) def test_solve_biquadratic(): x0, y0, x1, y1, r = symbols('x0 y0 x1 y1 r') f_1 = (x - 1)**2 + (y - 1)**2 - r**2 f_2 = (x - 2)**2 + (y - 2)**2 - r**2 s = sqrt(2*r**2 - 1) a = (3 - s)/2 b = (3 + s)/2 assert solve_poly_system([f_1, f_2], x, y) == [(a, b), (b, a)] f_1 = (x - 1)**2 + (y - 2)**2 - r**2 f_2 = (x - 1)**2 + (y - 1)**2 - r**2 assert solve_poly_system([f_1, f_2], x, y) == \ [(1 - sqrt((2*r - 1)*(2*r + 1))/2, Rational(3, 2)), (1 + sqrt((2*r - 1)*(2*r + 1))/2, Rational(3, 2))] query = lambda expr: expr.is_Pow and expr.exp is S.Half f_1 = (x - 1 )**2 + (y - 2)**2 - r**2 f_2 = (x - x1)**2 + (y - 1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(r.count(query) == 1 for r in flatten(result)) f_1 = (x - x0)**2 + (y - y0)**2 - r**2 f_2 = (x - x1)**2 + (y - y1)**2 - r**2 result = solve_poly_system([f_1, f_2], x, y) assert len(result) == 2 and all(len(r) == 2 for r in result) assert all(len(r.find(query)) == 1 for r in flatten(result)) s1 = (x*y - y, x**2 - x) assert solve(s1) == [{x: 1}, {x: 0, y: 0}] s2 = (x*y - x, y**2 - y) assert solve(s2) == [{y: 1}, {x: 0, y: 0}] gens = (x, y) for seq in (s1, s2): (f, g), opt = parallel_poly_from_expr(seq, *gens) raises(SolveFailed, lambda: solve_biquadratic(f, g, opt)) seq = (x**2 + y**2 - 2, y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == [ (-1, -1), (-1, 1), (1, -1), (1, 1)] ans = [(0, -1), (0, 1)] seq = (x**2 + y**2 - 1, y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == ans seq = (x**2 + y**2 - 1, x**2 - x + y**2 - 1) (f, g), opt = parallel_poly_from_expr(seq, *gens) assert solve_biquadratic(f, g, opt) == ans def test_solve_triangulated(): f_1 = x**2 + y + z - 1 f_2 = x + y**2 + z - 1 f_3 = x + y + z**2 - 1 a, b = sqrt(2) - 1, -sqrt(2) - 1 assert solve_triangulated([f_1, f_2, f_3], x, y, z) == \ [(0, 0, 1), (0, 1, 0), (1, 0, 0)] dom = QQ.algebraic_field(sqrt(2)) assert solve_triangulated([f_1, f_2, f_3], x, y, z, domain=dom) == \ [(0, 0, 1), (0, 1, 0), (1, 0, 0), (a, a, a), (b, b, b)] def test_solve_issue_3686(): roots = solve_poly_system([((x - 5)**2/250000 + (y - Rational(5, 10))**2/250000) - 1, x], x, y) assert roots == [(0, S.Half - 15*sqrt(1111)), (0, S.Half + 15*sqrt(1111))] roots = solve_poly_system([((x - 5)**2/250000 + (y - 5.0/10)**2/250000) - 1, x], x, y) # TODO: does this really have to be so complicated?! assert len(roots) == 2 assert roots[0][0] == 0 assert roots[0][1].epsilon_eq(-499.474999374969, 1e12) assert roots[1][0] == 0 assert roots[1][1].epsilon_eq(500.474999374969, 1e12) sympy-sympy-1.9/sympy/solvers/tests/test_recurr.py000066400000000000000000000216751412543434000226710ustar00rootroot00000000000000from sympy import Eq, factor, factorial, Function, Lambda, rf, S, sqrt, symbols, I, \ expand, binomial, Rational, Symbol, cos, sin, Abs from sympy.solvers.recurr import rsolve, rsolve_hyper, rsolve_poly, rsolve_ratio from sympy.testing.pytest import raises, slow from sympy.abc import a, b y = Function('y') n, k = symbols('n,k', integer=True) C0, C1, C2 = symbols('C0,C1,C2') def test_rsolve_poly(): assert rsolve_poly([-1, -1, 1], 0, n) == 0 assert rsolve_poly([-1, -1, 1], 1, n) == -1 assert rsolve_poly([-1, n + 1], n, n) == 1 assert rsolve_poly([-1, 1], n, n) == C0 + (n**2 - n)/2 assert rsolve_poly([-n - 1, n], 1, n) == C1*n - 1 assert rsolve_poly([-4*n - 2, 1], 4*n + 1, n) == -1 assert rsolve_poly([-1, 1], n**5 + n**3, n) == \ C0 - n**3 / 2 - n**5 / 2 + n**2 / 6 + n**6 / 6 + 2*n**4 / 3 def test_rsolve_ratio(): solution = rsolve_ratio([-2*n**3 + n**2 + 2*n - 1, 2*n**3 + n**2 - 6*n, -2*n**3 - 11*n**2 - 18*n - 9, 2*n**3 + 13*n**2 + 22*n + 8], 0, n) assert solution in [ C1*((-2*n + 3)/(n**2 - 1))/3, (S.Half)*(C1*(-3 + 2*n)/(-1 + n**2)), (S.Half)*(C1*( 3 - 2*n)/( 1 - n**2)), (S.Half)*(C2*(-3 + 2*n)/(-1 + n**2)), (S.Half)*(C2*( 3 - 2*n)/( 1 - n**2)), ] def test_rsolve_hyper(): assert rsolve_hyper([-1, -1, 1], 0, n) in [ C0*(S.Half - S.Half*sqrt(5))**n + C1*(S.Half + S.Half*sqrt(5))**n, C1*(S.Half - S.Half*sqrt(5))**n + C0*(S.Half + S.Half*sqrt(5))**n, ] assert rsolve_hyper([n**2 - 2, -2*n - 1, 1], 0, n) in [ C0*rf(sqrt(2), n) + C1*rf(-sqrt(2), n), C1*rf(sqrt(2), n) + C0*rf(-sqrt(2), n), ] assert rsolve_hyper([n**2 - k, -2*n - 1, 1], 0, n) in [ C0*rf(sqrt(k), n) + C1*rf(-sqrt(k), n), C1*rf(sqrt(k), n) + C0*rf(-sqrt(k), n), ] assert rsolve_hyper( [2*n*(n + 1), -n**2 - 3*n + 2, n - 1], 0, n) == C1*factorial(n) + C0*2**n assert rsolve_hyper( [n + 2, -(2*n + 3)*(17*n**2 + 51*n + 39), n + 1], 0, n) == None assert rsolve_hyper([-n - 1, -1, 1], 0, n) == None assert rsolve_hyper([-1, 1], n, n).expand() == C0 + n**2/2 - n/2 assert rsolve_hyper([-1, 1], 1 + n, n).expand() == C0 + n**2/2 + n/2 assert rsolve_hyper([-1, 1], 3*(n + n**2), n).expand() == C0 + n**3 - n assert rsolve_hyper([-a, 1],0,n).expand() == C0*a**n assert rsolve_hyper([-a, 0, 1], 0, n).expand() == (-1)**n*C1*a**(n/2) + C0*a**(n/2) assert rsolve_hyper([1, 1, 1], 0, n).expand() == \ C0*(Rational(-1, 2) - sqrt(3)*I/2)**n + C1*(Rational(-1, 2) + sqrt(3)*I/2)**n assert rsolve_hyper([1, -2*n/a - 2/a, 1], 0, n) is None def recurrence_term(c, f): """Compute RHS of recurrence in f(n) with coefficients in c.""" return sum(c[i]*f.subs(n, n + i) for i in range(len(c))) def test_rsolve_bulk(): """Some bulk-generated tests.""" funcs = [ n, n + 1, n**2, n**3, n**4, n + n**2, 27*n + 52*n**2 - 3* n**3 + 12*n**4 - 52*n**5 ] coeffs = [ [-2, 1], [-2, -1, 1], [-1, 1, 1, -1, 1], [-n, 1], [n**2 - n + 12, 1] ] for p in funcs: # compute difference for c in coeffs: q = recurrence_term(c, p) if p.is_polynomial(n): assert rsolve_poly(c, q, n) == p # See issue 3956: #if p.is_hypergeometric(n): # assert rsolve_hyper(c, q, n) == p def test_rsolve(): f = y(n + 2) - y(n + 1) - y(n) h = sqrt(5)*(S.Half + S.Half*sqrt(5))**n \ - sqrt(5)*(S.Half - S.Half*sqrt(5))**n assert rsolve(f, y(n)) in [ C0*(S.Half - S.Half*sqrt(5))**n + C1*(S.Half + S.Half*sqrt(5))**n, C1*(S.Half - S.Half*sqrt(5))**n + C0*(S.Half + S.Half*sqrt(5))**n, ] assert rsolve(f, y(n), [0, 5]) == h assert rsolve(f, y(n), {0: 0, 1: 5}) == h assert rsolve(f, y(n), {y(0): 0, y(1): 5}) == h assert rsolve(y(n) - y(n - 1) - y(n - 2), y(n), [0, 5]) == h assert rsolve(Eq(y(n), y(n - 1) + y(n - 2)), y(n), [0, 5]) == h assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 f = (n - 1)*y(n + 2) - (n**2 + 3*n - 2)*y(n + 1) + 2*n*(n + 1)*y(n) g = C1*factorial(n) + C0*2**n h = -3*factorial(n) + 3*2**n assert rsolve(f, y(n)) == g assert rsolve(f, y(n), []) == g assert rsolve(f, y(n), {}) == g assert rsolve(f, y(n), [0, 3]) == h assert rsolve(f, y(n), {0: 0, 1: 3}) == h assert rsolve(f, y(n), {y(0): 0, y(1): 3}) == h assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 f = y(n) - y(n - 1) - 2 assert rsolve(f, y(n), {y(0): 0}) == 2*n assert rsolve(f, y(n), {y(0): 1}) == 2*n + 1 assert rsolve(f, y(n), {y(0): 0, y(1): 1}) is None assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 f = 3*y(n - 1) - y(n) - 1 assert rsolve(f, y(n), {y(0): 0}) == -3**n/2 + S.Half assert rsolve(f, y(n), {y(0): 1}) == 3**n/2 + S.Half assert rsolve(f, y(n), {y(0): 2}) == 3*3**n/2 + S.Half assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 f = y(n) - 1/n*y(n - 1) assert rsolve(f, y(n)) == C0/factorial(n) assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 f = y(n) - 1/n*y(n - 1) - 1 assert rsolve(f, y(n)) is None f = 2*y(n - 1) + (1 - n)*y(n)/n assert rsolve(f, y(n), {y(1): 1}) == 2**(n - 1)*n assert rsolve(f, y(n), {y(1): 2}) == 2**(n - 1)*n*2 assert rsolve(f, y(n), {y(1): 3}) == 2**(n - 1)*n*3 assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 f = (n - 1)*(n - 2)*y(n + 2) - (n + 1)*(n + 2)*y(n) assert rsolve(f, y(n), {y(3): 6, y(4): 24}) == n*(n - 1)*(n - 2) assert rsolve( f, y(n), {y(3): 6, y(4): -24}) == -n*(n - 1)*(n - 2)*(-1)**(n) assert f.subs(y, Lambda(k, rsolve(f, y(n)).subs(n, k))).simplify() == 0 assert rsolve(Eq(y(n + 1), a*y(n)), y(n), {y(1): a}).simplify() == a**n assert rsolve(y(n) - a*y(n-2),y(n), \ {y(1): sqrt(a)*(a + b), y(2): a*(a - b)}).simplify() == \ a**(n/2)*(-(-1)**n*b + a) f = (-16*n**2 + 32*n - 12)*y(n - 1) + (4*n**2 - 12*n + 9)*y(n) yn = rsolve(f, y(n), {y(1): binomial(2*n + 1, 3)}) sol = 2**(2*n)*n*(2*n - 1)**2*(2*n + 1)/12 assert factor(expand(yn, func=True)) == sol assert (rsolve(y(n) + a*(y(n + 1) + y(n - 1))/2, y(n)) - (C0*((sqrt(-a**2 + 1) - 1)/a)**n + C1*((-sqrt(-a**2 + 1) - 1)/a)**n)).simplify() == 0 assert rsolve((k + 1)*y(k), y(k)) is None assert (rsolve((k + 1)*y(k) + (k + 3)*y(k + 1) + (k + 5)*y(k + 2), y(k)) is None) assert rsolve(y(n) + y(n + 1) + 2**n + 3**n, y(n)) == (-1)**n*C0 - 2**n/3 - 3**n/4 def test_rsolve_raises(): x = Function('x') raises(ValueError, lambda: rsolve(y(n) - y(k + 1), y(n))) raises(ValueError, lambda: rsolve(y(n) - y(n + 1), x(n))) raises(ValueError, lambda: rsolve(y(n) - x(n + 1), y(n))) raises(ValueError, lambda: rsolve(y(n) - sqrt(n)*y(n + 1), y(n))) raises(ValueError, lambda: rsolve(y(n) - y(n + 1), y(n), {x(0): 0})) raises(ValueError, lambda: rsolve(y(n) + y(n + 1) + 2**n + cos(n), y(n))) def test_issue_6844(): f = y(n + 2) - y(n + 1) + y(n)/4 assert rsolve(f, y(n)) == 2**(-n)*(C0 + C1*n) assert rsolve(f, y(n), {y(0): 0, y(1): 1}) == 2*2**(-n)*n def test_issue_18751(): r = Symbol('r', real=True, positive=True) theta = Symbol('theta', real=True) f = y(n) - 2 * r * cos(theta) * y(n - 1) + r**2 * y(n - 2) assert rsolve(f, y(n)) == \ C0*(r*(cos(theta) - I*Abs(sin(theta))))**n + C1*(r*(cos(theta) + I*Abs(sin(theta))))**n def test_constant_naming(): #issue 8697 assert rsolve(y(n+3) - y(n+2) - y(n+1) + y(n), y(n)) == (-1)**n*C0+C1+C2*n assert rsolve(y(n+3)+3*y(n+2)+3*y(n+1)+y(n), y(n)).expand() == C0*(-1)**n + (-1)**n*C1*n + (-1)**n*C2*n**2 assert rsolve(y(n) - 2*y(n - 3) + 5*y(n - 2) - 4*y(n - 1),y(n),[1,3,8]) == 3*2**n - n - 2 #issue 19630 assert rsolve(y(n+3) - 3*y(n+1) + 2*y(n), y(n), {y(1):0, y(2):8, y(3):-2}) == (-2)**n + 2*n @slow def test_issue_15751(): f = y(n) + 21*y(n + 1) - 273*y(n + 2) - 1092*y(n + 3) + 1820*y(n + 4) + 1092*y(n + 5) - 273*y(n + 6) - 21*y(n + 7) + y(n + 8) assert rsolve(f, y(n)) is not None def test_issue_17990(): f = -10*y(n) + 4*y(n + 1) + 6*y(n + 2) + 46*y(n + 3) sol = rsolve(f, y(n)) expected = C0*((86*18**(S(1)/3)/69 + (-12 + (-1 + sqrt(3)*I)*(290412 + 3036*sqrt(9165))**(S(1)/3))*(1 - sqrt(3)*I)*(24201 + 253*sqrt(9165))** (S(1)/3)/276)/((1 - sqrt(3)*I)*(24201 + 253*sqrt(9165))**(S(1)/3)) )**n + C1*((86*18**(S(1)/3)/69 + (-12 + (-1 - sqrt(3)*I)*(290412 + 3036 *sqrt(9165))**(S(1)/3))*(1 + sqrt(3)*I)*(24201 + 253*sqrt(9165))** (S(1)/3)/276)/((1 + sqrt(3)*I)*(24201 + 253*sqrt(9165))**(S(1)/3)) )**n + C2*(-43*18**(S(1)/3)/(69*(24201 + 253*sqrt(9165))**(S(1)/3)) - S(1)/23 + (290412 + 3036*sqrt(9165))**(S(1)/3)/138)**n assert sol == expected e = sol.subs({C0: 1, C1: 1, C2: 1, n: 1}).evalf() assert abs(e + 0.130434782608696) < 1e-13 sympy-sympy-1.9/sympy/solvers/tests/test_solvers.py000066400000000000000000002700641412543434000230620ustar00rootroot00000000000000from sympy import ( Abs, And, Derivative, Dummy, Eq, Float, Function, Gt, I, Integral, LambertW, Lt, Matrix, Or, Poly, Q, Rational, S, Symbol, Ne, Wild, acos, asin, atan, atanh, binomial, cos, cosh, diff, erf, erfinv, erfc, erfcinv, exp, im, log, pi, re, sec, sin, sinh, solve, solve_linear, sqrt, sstr, symbols, sympify, tan, tanh, root, atan2, arg, Mul, SparseMatrix, ask, Tuple, nsolve, oo, E, cbrt, denom, Add, Piecewise, GoldenRatio, TribonacciConstant) from sympy.core.function import nfloat from sympy.solvers import solve_linear_system, solve_linear_system_LU, \ solve_undetermined_coeffs from sympy.solvers.bivariate import _filtered_gens, _solve_lambert, _lambert from sympy.solvers.solvers import _invert, unrad, checksol, posify, _ispow, \ det_quick, det_perm, det_minor, _simple_dens, denoms from sympy.physics.units import cm from sympy.polys.rootoftools import CRootOf from sympy.testing.pytest import slow, XFAIL, SKIP, raises from sympy.testing.randtest import verify_numerically as tn from sympy.abc import a, b, c, d, e, k, h, p, x, y, z, t, q, m, R def NS(e, n=15, **options): return sstr(sympify(e).evalf(n, **options), full_prec=True) def test_swap_back(): f, g = map(Function, 'fg') fx, gx = f(x), g(x) assert solve([fx + y - 2, fx - gx - 5], fx, y, gx) == \ {fx: gx + 5, y: -gx - 3} assert solve(fx + gx*x - 2, [fx, gx], dict=True)[0] == {fx: 2, gx: 0} assert solve(fx + gx**2*x - y, [fx, gx], dict=True) == [{fx: y - gx**2*x}] assert solve([f(1) - 2, x + 2], dict=True) == [{x: -2, f(1): 2}] def guess_solve_strategy(eq, symbol): try: solve(eq, symbol) return True except (TypeError, NotImplementedError): return False def test_guess_poly(): # polynomial equations assert guess_solve_strategy( S(4), x ) # == GS_POLY assert guess_solve_strategy( x, x ) # == GS_POLY assert guess_solve_strategy( x + a, x ) # == GS_POLY assert guess_solve_strategy( 2*x, x ) # == GS_POLY assert guess_solve_strategy( x + sqrt(2), x) # == GS_POLY assert guess_solve_strategy( x + 2**Rational(1, 4), x) # == GS_POLY assert guess_solve_strategy( x**2 + 1, x ) # == GS_POLY assert guess_solve_strategy( x**2 - 1, x ) # == GS_POLY assert guess_solve_strategy( x*y + y, x ) # == GS_POLY assert guess_solve_strategy( x*exp(y) + y, x) # == GS_POLY assert guess_solve_strategy( (x - y**3)/(y**2*sqrt(1 - y**2)), x) # == GS_POLY def test_guess_poly_cv(): # polynomial equations via a change of variable assert guess_solve_strategy( sqrt(x) + 1, x ) # == GS_POLY_CV_1 assert guess_solve_strategy( x**Rational(1, 3) + sqrt(x) + 1, x ) # == GS_POLY_CV_1 assert guess_solve_strategy( 4*x*(1 - sqrt(x)), x ) # == GS_POLY_CV_1 # polynomial equation multiplying both sides by x**n assert guess_solve_strategy( x + 1/x + y, x ) # == GS_POLY_CV_2 def test_guess_rational_cv(): # rational functions assert guess_solve_strategy( (x + 1)/(x**2 + 2), x) # == GS_RATIONAL assert guess_solve_strategy( (x - y**3)/(y**2*sqrt(1 - y**2)), y) # == GS_RATIONAL_CV_1 # rational functions via the change of variable y -> x**n assert guess_solve_strategy( (sqrt(x) + 1)/(x**Rational(1, 3) + sqrt(x) + 1), x ) \ #== GS_RATIONAL_CV_1 def test_guess_transcendental(): #transcendental functions assert guess_solve_strategy( exp(x) + 1, x ) # == GS_TRANSCENDENTAL assert guess_solve_strategy( 2*cos(x) - y, x ) # == GS_TRANSCENDENTAL assert guess_solve_strategy( exp(x) + exp(-x) - y, x ) # == GS_TRANSCENDENTAL assert guess_solve_strategy(3**x - 10, x) # == GS_TRANSCENDENTAL assert guess_solve_strategy(-3**x + 10, x) # == GS_TRANSCENDENTAL assert guess_solve_strategy(a*x**b - y, x) # == GS_TRANSCENDENTAL def test_solve_args(): # equation container, issue 5113 ans = {x: -3, y: 1} eqs = (x + 5*y - 2, -3*x + 6*y - 15) assert all(solve(container(eqs), x, y) == ans for container in (tuple, list, set, frozenset)) assert solve(Tuple(*eqs), x, y) == ans # implicit symbol to solve for assert set(solve(x**2 - 4)) == {S(2), -S(2)} assert solve([x + y - 3, x - y - 5]) == {x: 4, y: -1} assert solve(x - exp(x), x, implicit=True) == [exp(x)] # no symbol to solve for assert solve(42) == solve(42, x) == [] assert solve([1, 2]) == [] # duplicate symbols removed assert solve((x - 3, y + 2), x, y, x) == {x: 3, y: -2} # unordered symbols # only 1 assert solve(y - 3, {y}) == [3] # more than 1 assert solve(y - 3, {x, y}) == [{y: 3}] # multiple symbols: take the first linear solution+ # - return as tuple with values for all requested symbols assert solve(x + y - 3, [x, y]) == [(3 - y, y)] # - unless dict is True assert solve(x + y - 3, [x, y], dict=True) == [{x: 3 - y}] # - or no symbols are given assert solve(x + y - 3) == [{x: 3 - y}] # multiple symbols might represent an undetermined coefficients system assert solve(a + b*x - 2, [a, b]) == {a: 2, b: 0} args = (a + b)*x - b**2 + 2, a, b assert solve(*args) == \ [(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))] assert solve(*args, set=True) == \ ([a, b], {(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))}) assert solve(*args, dict=True) == \ [{b: sqrt(2), a: -sqrt(2)}, {b: -sqrt(2), a: sqrt(2)}] eq = a*x**2 + b*x + c - ((x - h)**2 + 4*p*k)/4/p flags = dict(dict=True) assert solve(eq, [h, p, k], exclude=[a, b, c], **flags) == \ [{k: c - b**2/(4*a), h: -b/(2*a), p: 1/(4*a)}] flags.update(dict(simplify=False)) assert solve(eq, [h, p, k], exclude=[a, b, c], **flags) == \ [{k: (4*a*c - b**2)/(4*a), h: -b/(2*a), p: 1/(4*a)}] # failing undetermined system assert solve(a*x + b**2/(x + 4) - 3*x - 4/x, a, b, dict=True) == \ [{a: (-b**2*x + 3*x**3 + 12*x**2 + 4*x + 16)/(x**2*(x + 4))}] # failed single equation assert solve(1/(1/x - y + exp(y))) == [] raises( NotImplementedError, lambda: solve(exp(x) + sin(x) + exp(y) + sin(y))) # failed system # -- when no symbols given, 1 fails assert solve([y, exp(x) + x]) == {x: -LambertW(1), y: 0} # both fail assert solve( (exp(x) - x, exp(y) - y)) == {x: -LambertW(-1), y: -LambertW(-1)} # -- when symbols given solve([y, exp(x) + x], x, y) == [(-LambertW(1), 0)] # symbol is a number assert solve(x**2 - pi, pi) == [x**2] # no equations assert solve([], [x]) == [] # overdetermined system # - nonlinear assert solve([(x + y)**2 - 4, x + y - 2]) == [{x: -y + 2}] # - linear assert solve((x + y - 2, 2*x + 2*y - 4)) == {x: -y + 2} # When one or more args are Boolean assert solve(Eq(x**2, 0.0)) == [0] # issue 19048 assert solve([True, Eq(x, 0)], [x], dict=True) == [{x: 0}] assert solve([Eq(x, x), Eq(x, 0), Eq(x, x+1)], [x], dict=True) == [] assert not solve([Eq(x, x+1), x < 2], x) assert solve([Eq(x, 0), x+1<2]) == Eq(x, 0) assert solve([Eq(x, x), Eq(x, x+1)], x) == [] assert solve(True, x) == [] assert solve([x - 1, False], [x], set=True) == ([], set()) def test_solve_polynomial1(): assert solve(3*x - 2, x) == [Rational(2, 3)] assert solve(Eq(3*x, 2), x) == [Rational(2, 3)] assert set(solve(x**2 - 1, x)) == {-S.One, S.One} assert set(solve(Eq(x**2, 1), x)) == {-S.One, S.One} assert solve(x - y**3, x) == [y**3] rx = root(x, 3) assert solve(x - y**3, y) == [ rx, -rx/2 - sqrt(3)*I*rx/2, -rx/2 + sqrt(3)*I*rx/2] a11, a12, a21, a22, b1, b2 = symbols('a11,a12,a21,a22,b1,b2') assert solve([a11*x + a12*y - b1, a21*x + a22*y - b2], x, y) == \ { x: (a22*b1 - a12*b2)/(a11*a22 - a12*a21), y: (a11*b2 - a21*b1)/(a11*a22 - a12*a21), } solution = {y: S.Zero, x: S.Zero} assert solve((x - y, x + y), x, y ) == solution assert solve((x - y, x + y), (x, y)) == solution assert solve((x - y, x + y), [x, y]) == solution assert set(solve(x**3 - 15*x - 4, x)) == { -2 + 3**S.Half, S(4), -2 - 3**S.Half } assert set(solve((x**2 - 1)**2 - a, x)) == \ {sqrt(1 + sqrt(a)), -sqrt(1 + sqrt(a)), sqrt(1 - sqrt(a)), -sqrt(1 - sqrt(a))} def test_solve_polynomial2(): assert solve(4, x) == [] def test_solve_polynomial_cv_1a(): """ Test for solving on equations that can be converted to a polynomial equation using the change of variable y -> x**Rational(p, q) """ assert solve( sqrt(x) - 1, x) == [1] assert solve( sqrt(x) - 2, x) == [4] assert solve( x**Rational(1, 4) - 2, x) == [16] assert solve( x**Rational(1, 3) - 3, x) == [27] assert solve(sqrt(x) + x**Rational(1, 3) + x**Rational(1, 4), x) == [0] def test_solve_polynomial_cv_1b(): assert set(solve(4*x*(1 - a*sqrt(x)), x)) == {S.Zero, 1/a**2} assert set(solve(x*(root(x, 3) - 3), x)) == {S.Zero, S(27)} def test_solve_polynomial_cv_2(): """ Test for solving on equations that can be converted to a polynomial equation multiplying both sides of the equation by x**m """ assert solve(x + 1/x - 1, x) in \ [[ S.Half + I*sqrt(3)/2, S.Half - I*sqrt(3)/2], [ S.Half - I*sqrt(3)/2, S.Half + I*sqrt(3)/2]] def test_quintics_1(): f = x**5 - 110*x**3 - 55*x**2 + 2310*x + 979 s = solve(f, check=False) for r in s: res = f.subs(x, r.n()).n() assert tn(res, 0) f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 s = solve(f) for r in s: assert r.func == CRootOf # if one uses solve to get the roots of a polynomial that has a CRootOf # solution, make sure that the use of nfloat during the solve process # doesn't fail. Note: if you want numerical solutions to a polynomial # it is *much* faster to use nroots to get them than to solve the # equation only to get RootOf solutions which are then numerically # evaluated. So for eq = x**5 + 3*x + 7 do Poly(eq).nroots() rather # than [i.n() for i in solve(eq)] to get the numerical roots of eq. assert nfloat(solve(x**5 + 3*x**3 + 7)[0], exponent=False) == \ CRootOf(x**5 + 3*x**3 + 7, 0).n() def test_quintics_2(): f = x**5 + 15*x + 12 s = solve(f, check=False) for r in s: res = f.subs(x, r.n()).n() assert tn(res, 0) f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 s = solve(f) for r in s: assert r.func == CRootOf assert solve(x**5 - 6*x**3 - 6*x**2 + x - 6) == [ CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 0), CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 1), CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 2), CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 3), CRootOf(x**5 - 6*x**3 - 6*x**2 + x - 6, 4)] def test_quintics_3(): y = x**5 + x**3 - 2**Rational(1, 3) assert solve(y) == solve(-y) == [] def test_highorder_poly(): # just testing that the uniq generator is unpacked sol = solve(x**6 - 2*x + 2) assert all(isinstance(i, CRootOf) for i in sol) and len(sol) == 6 def test_solve_rational(): """Test solve for rational functions""" assert solve( ( x - y**3 )/( (y**2)*sqrt(1 - y**2) ), x) == [y**3] def test_solve_nonlinear(): assert solve(x**2 - y**2, x, y, dict=True) == [{x: -y}, {x: y}] assert solve(x**2 - y**2/exp(x), y, x, dict=True) == [{y: -x*sqrt(exp(x))}, {y: x*sqrt(exp(x))}] def test_issue_8666(): x = symbols('x') assert solve(Eq(x**2 - 1/(x**2 - 4), 4 - 1/(x**2 - 4)), x) == [] assert solve(Eq(x + 1/x, 1/x), x) == [] def test_issue_7228(): assert solve(4**(2*(x**2) + 2*x) - 8, x) == [Rational(-3, 2), S.Half] def test_issue_7190(): assert solve(log(x-3) + log(x+3), x) == [sqrt(10)] def test_issue_21004(): x = symbols('x') f = x/sqrt(x**2+1) f_diff = f.diff(x) assert solve(f_diff, x) == [] def test_linear_system(): x, y, z, t, n = symbols('x, y, z, t, n') assert solve([x - 1, x - y, x - 2*y, y - 1], [x, y]) == [] assert solve([x - 1, x - y, x - 2*y, x - 1], [x, y]) == [] assert solve([x - 1, x - 1, x - y, x - 2*y], [x, y]) == [] assert solve([x + 5*y - 2, -3*x + 6*y - 15], x, y) == {x: -3, y: 1} M = Matrix([[0, 0, n*(n + 1), (n + 1)**2, 0], [n + 1, n + 1, -2*n - 1, -(n + 1), 0], [-1, 0, 1, 0, 0]]) assert solve_linear_system(M, x, y, z, t) == \ {x: t*(-n-1)/n, z: t*(-n-1)/n, y: 0} assert solve([x + y + z + t, -z - t], x, y, z, t) == {x: -y, z: -t} @XFAIL def test_linear_system_xfail(): # https://github.com/sympy/sympy/issues/6420 M = Matrix([[0, 15.0, 10.0, 700.0], [1, 1, 1, 100.0], [0, 10.0, 5.0, 200.0], [-5.0, 0, 0, 0 ]]) assert solve_linear_system(M, x, y, z) == {x: 0, y: -60.0, z: 160.0} def test_linear_system_function(): a = Function('a') assert solve([a(0, 0) + a(0, 1) + a(1, 0) + a(1, 1), -a(1, 0) - a(1, 1)], a(0, 0), a(0, 1), a(1, 0), a(1, 1)) == {a(1, 0): -a(1, 1), a(0, 0): -a(0, 1)} def test_linear_system_symbols_doesnt_hang_1(): def _mk_eqs(wy): # Equations for fitting a wy*2 - 1 degree polynomial between two points, # at end points derivatives are known up to order: wy - 1 order = 2*wy - 1 x, x0, x1 = symbols('x, x0, x1', real=True) y0s = symbols('y0_:{}'.format(wy), real=True) y1s = symbols('y1_:{}'.format(wy), real=True) c = symbols('c_:{}'.format(order+1), real=True) expr = sum([coeff*x**o for o, coeff in enumerate(c)]) eqs = [] for i in range(wy): eqs.append(expr.diff(x, i).subs({x: x0}) - y0s[i]) eqs.append(expr.diff(x, i).subs({x: x1}) - y1s[i]) return eqs, c # # The purpose of this test is just to see that these calls don't hang. The # expressions returned are complicated so are not included here. Testing # their correctness takes longer than solving the system. # for n in range(1, 7+1): eqs, c = _mk_eqs(n) solve(eqs, c) def test_linear_system_symbols_doesnt_hang_2(): M = Matrix([ [66, 24, 39, 50, 88, 40, 37, 96, 16, 65, 31, 11, 37, 72, 16, 19, 55, 37, 28, 76], [10, 93, 34, 98, 59, 44, 67, 74, 74, 94, 71, 61, 60, 23, 6, 2, 57, 8, 29, 78], [19, 91, 57, 13, 64, 65, 24, 53, 77, 34, 85, 58, 87, 39, 39, 7, 36, 67, 91, 3], [74, 70, 15, 53, 68, 43, 86, 83, 81, 72, 25, 46, 67, 17, 59, 25, 78, 39, 63, 6], [69, 40, 67, 21, 67, 40, 17, 13, 93, 44, 46, 89, 62, 31, 30, 38, 18, 20, 12, 81], [50, 22, 74, 76, 34, 45, 19, 76, 28, 28, 11, 99, 97, 82, 8, 46, 99, 57, 68, 35], [58, 18, 45, 88, 10, 64, 9, 34, 90, 82, 17, 41, 43, 81, 45, 83, 22, 88, 24, 39], [42, 21, 70, 68, 6, 33, 64, 81, 83, 15, 86, 75, 86, 17, 77, 34, 62, 72, 20, 24], [ 7, 8, 2, 72, 71, 52, 96, 5, 32, 51, 31, 36, 79, 88, 25, 77, 29, 26, 33, 13], [19, 31, 30, 85, 81, 39, 63, 28, 19, 12, 16, 49, 37, 66, 38, 13, 3, 71, 61, 51], [29, 82, 80, 49, 26, 85, 1, 37, 2, 74, 54, 82, 26, 47, 54, 9, 35, 0, 99, 40], [15, 49, 82, 91, 93, 57, 45, 25, 45, 97, 15, 98, 48, 52, 66, 24, 62, 54, 97, 37], [62, 23, 73, 53, 52, 86, 28, 38, 0, 74, 92, 38, 97, 70, 71, 29, 26, 90, 67, 45], [ 2, 32, 23, 24, 71, 37, 25, 71, 5, 41, 97, 65, 93, 13, 65, 45, 25, 88, 69, 50], [40, 56, 1, 29, 79, 98, 79, 62, 37, 28, 45, 47, 3, 1, 32, 74, 98, 35, 84, 32], [33, 15, 87, 79, 65, 9, 14, 63, 24, 19, 46, 28, 74, 20, 29, 96, 84, 91, 93, 1], [97, 18, 12, 52, 1, 2, 50, 14, 52, 76, 19, 82, 41, 73, 51, 79, 13, 3, 82, 96], [40, 28, 52, 10, 10, 71, 56, 78, 82, 5, 29, 48, 1, 26, 16, 18, 50, 76, 86, 52], [38, 89, 83, 43, 29, 52, 90, 77, 57, 0, 67, 20, 81, 88, 48, 96, 88, 58, 14, 3]]) syms = x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,x10,x11,x12,x13,x14,x15,x16,x17,x18 = symbols('x:19') sol = { x0: -S(1967374186044955317099186851240896179)/3166636564687820453598895768302256588, x1: -S(84268280268757263347292368432053826)/791659141171955113399723942075564147, x2: -S(229962957341664730974463872411844965)/1583318282343910226799447884151128294, x3: S(990156781744251750886760432229180537)/6333273129375640907197791536604513176, x4: -S(2169830351210066092046760299593096265)/18999819388126922721593374609813539528, x5: S(4680868883477577389628494526618745355)/9499909694063461360796687304906769764, x6: -S(1590820774344371990683178396480879213)/3166636564687820453598895768302256588, x7: -S(54104723404825537735226491634383072)/339282489073695048599881689460956063, x8: S(3182076494196560075964847771774733847)/6333273129375640907197791536604513176, x9: -S(10870817431029210431989147852497539675)/18999819388126922721593374609813539528, x10: -S(13118019242576506476316318268573312603)/18999819388126922721593374609813539528, x11: -S(5173852969886775824855781403820641259)/4749954847031730680398343652453384882, x12: S(4261112042731942783763341580651820563)/4749954847031730680398343652453384882, x13: -S(821833082694661608993818117038209051)/6333273129375640907197791536604513176, x14: S(906881575107250690508618713632090559)/904753304196520129599684505229216168, x15: -S(732162528717458388995329317371283987)/6333273129375640907197791536604513176, x16: S(4524215476705983545537087360959896817)/9499909694063461360796687304906769764, x17: -S(3898571347562055611881270844646055217)/6333273129375640907197791536604513176, x18: S(7513502486176995632751685137907442269)/18999819388126922721593374609813539528 } eqs = list(M * Matrix(syms + (1,))) assert solve(eqs, syms) == sol y = Symbol('y') eqs = list(y * M * Matrix(syms + (1,))) assert solve(eqs, syms) == sol def test_linear_systemLU(): n = Symbol('n') M = Matrix([[1, 2, 0, 1], [1, 3, 2*n, 1], [4, -1, n**2, 1]]) assert solve_linear_system_LU(M, [x, y, z]) == {z: -3/(n**2 + 18*n), x: 1 - 12*n/(n**2 + 18*n), y: 6*n/(n**2 + 18*n)} # Note: multiple solutions exist for some of these equations, so the tests # should be expected to break if the implementation of the solver changes # in such a way that a different branch is chosen @slow def test_solve_transcendental(): from sympy.abc import a, b assert solve(exp(x) - 3, x) == [log(3)] assert set(solve((a*x + b)*(exp(x) - 3), x)) == {-b/a, log(3)} assert solve(cos(x) - y, x) == [-acos(y) + 2*pi, acos(y)] assert solve(2*cos(x) - y, x) == [-acos(y/2) + 2*pi, acos(y/2)] assert solve(Eq(cos(x), sin(x)), x) == [pi/4] assert set(solve(exp(x) + exp(-x) - y, x)) in [{ log(y/2 - sqrt(y**2 - 4)/2), log(y/2 + sqrt(y**2 - 4)/2), }, { log(y - sqrt(y**2 - 4)) - log(2), log(y + sqrt(y**2 - 4)) - log(2)}, { log(y/2 - sqrt((y - 2)*(y + 2))/2), log(y/2 + sqrt((y - 2)*(y + 2))/2)}] assert solve(exp(x) - 3, x) == [log(3)] assert solve(Eq(exp(x), 3), x) == [log(3)] assert solve(log(x) - 3, x) == [exp(3)] assert solve(sqrt(3*x) - 4, x) == [Rational(16, 3)] assert solve(3**(x + 2), x) == [] assert solve(3**(2 - x), x) == [] assert solve(x + 2**x, x) == [-LambertW(log(2))/log(2)] assert solve(2*x + 5 + log(3*x - 2), x) == \ [Rational(2, 3) + LambertW(2*exp(Rational(-19, 3))/3)/2] assert solve(3*x + log(4*x), x) == [LambertW(Rational(3, 4))/3] assert set(solve((2*x + 8)*(8 + exp(x)), x)) == {S(-4), log(8) + pi*I} eq = 2*exp(3*x + 4) - 3 ans = solve(eq, x) # this generated a failure in flatten assert len(ans) == 3 and all(eq.subs(x, a).n(chop=True) == 0 for a in ans) assert solve(2*log(3*x + 4) - 3, x) == [(exp(Rational(3, 2)) - 4)/3] assert solve(exp(x) + 1, x) == [pi*I] eq = 2*(3*x + 4)**5 - 6*7**(3*x + 9) result = solve(eq, x) ans = [(log(2401) + 5*LambertW((-1 + sqrt(5) + sqrt(2)*I*sqrt(sqrt(5) + \ 5))*log(7**(7*3**Rational(1, 5)/20))* -1))/(-3*log(7)), \ (log(2401) + 5*LambertW((1 + sqrt(5) - sqrt(2)*I*sqrt(5 - \ sqrt(5)))*log(7**(7*3**Rational(1, 5)/20))))/(-3*log(7)), \ (log(2401) + 5*LambertW((1 + sqrt(5) + sqrt(2)*I*sqrt(5 - \ sqrt(5)))*log(7**(7*3**Rational(1, 5)/20))))/(-3*log(7)), \ (log(2401) + 5*LambertW((-sqrt(5) + 1 + sqrt(2)*I*sqrt(sqrt(5) + \ 5))*log(7**(7*3**Rational(1, 5)/20))))/(-3*log(7)), \ (log(2401) + 5*LambertW(-log(7**(7*3**Rational(1, 5)/5))))/(-3*log(7))] assert result == ans # it works if expanded, too assert solve(eq.expand(), x) == result assert solve(z*cos(x) - y, x) == [-acos(y/z) + 2*pi, acos(y/z)] assert solve(z*cos(2*x) - y, x) == [-acos(y/z)/2 + pi, acos(y/z)/2] assert solve(z*cos(sin(x)) - y, x) == [ pi - asin(acos(y/z)), asin(acos(y/z) - 2*pi) + pi, -asin(acos(y/z) - 2*pi), asin(acos(y/z))] assert solve(z*cos(x), x) == [pi/2, pi*Rational(3, 2)] # issue 4508 assert solve(y - b*x/(a + x), x) in [[-a*y/(y - b)], [a*y/(b - y)]] assert solve(y - b*exp(a/x), x) == [a/log(y/b)] # issue 4507 assert solve(y - b/(1 + a*x), x) in [[(b - y)/(a*y)], [-((y - b)/(a*y))]] # issue 4506 assert solve(y - a*x**b, x) == [(y/a)**(1/b)] # issue 4505 assert solve(z**x - y, x) == [log(y)/log(z)] # issue 4504 assert solve(2**x - 10, x) == [1 + log(5)/log(2)] # issue 6744 assert solve(x*y) == [{x: 0}, {y: 0}] assert solve([x*y]) == [{x: 0}, {y: 0}] assert solve(x**y - 1) == [{x: 1}, {y: 0}] assert solve([x**y - 1]) == [{x: 1}, {y: 0}] assert solve(x*y*(x**2 - y**2)) == [{x: 0}, {x: -y}, {x: y}, {y: 0}] assert solve([x*y*(x**2 - y**2)]) == [{x: 0}, {x: -y}, {x: y}, {y: 0}] # issue 4739 assert solve(exp(log(5)*x) - 2**x, x) == [0] # issue 14791 assert solve(exp(log(5)*x) - exp(log(2)*x), x) == [0] f = Function('f') assert solve(y*f(log(5)*x) - y*f(log(2)*x), x) == [0] assert solve(f(x) - f(0), x) == [0] assert solve(f(x) - f(2 - x), x) == [1] raises(NotImplementedError, lambda: solve(f(x, y) - f(1, 2), x)) raises(NotImplementedError, lambda: solve(f(x, y) - f(2 - x, 2), x)) raises(ValueError, lambda: solve(f(x, y) - f(1 - x), x)) raises(ValueError, lambda: solve(f(x, y) - f(1), x)) # misc # make sure that the right variables is picked up in tsolve # shouldn't generate a GeneratorsNeeded error in _tsolve when the NaN is generated # for eq_down. Actual answers, as determined numerically are approx. +/- 0.83 raises(NotImplementedError, lambda: solve(sinh(x)*sinh(sinh(x)) + cosh(x)*cosh(sinh(x)) - 3)) # watch out for recursive loop in tsolve raises(NotImplementedError, lambda: solve((x + 2)**y*x - 3, x)) # issue 7245 assert solve(sin(sqrt(x))) == [0, pi**2] # issue 7602 a, b = symbols('a, b', real=True, negative=False) assert str(solve(Eq(a, 0.5 - cos(pi*b)/2), b)) == \ '[2.0 - 0.318309886183791*acos(1.0 - 2.0*a), 0.318309886183791*acos(1.0 - 2.0*a)]' # issue 15325 assert solve(y**(1/x) - z, x) == [log(y)/log(z)] def test_solve_for_functions_derivatives(): t = Symbol('t') x = Function('x')(t) y = Function('y')(t) a11, a12, a21, a22, b1, b2 = symbols('a11,a12,a21,a22,b1,b2') soln = solve([a11*x + a12*y - b1, a21*x + a22*y - b2], x, y) assert soln == { x: (a22*b1 - a12*b2)/(a11*a22 - a12*a21), y: (a11*b2 - a21*b1)/(a11*a22 - a12*a21), } assert solve(x - 1, x) == [1] assert solve(3*x - 2, x) == [Rational(2, 3)] soln = solve([a11*x.diff(t) + a12*y.diff(t) - b1, a21*x.diff(t) + a22*y.diff(t) - b2], x.diff(t), y.diff(t)) assert soln == { y.diff(t): (a11*b2 - a21*b1)/(a11*a22 - a12*a21), x.diff(t): (a22*b1 - a12*b2)/(a11*a22 - a12*a21) } assert solve(x.diff(t) - 1, x.diff(t)) == [1] assert solve(3*x.diff(t) - 2, x.diff(t)) == [Rational(2, 3)] eqns = {3*x - 1, 2*y - 4} assert solve(eqns, {x, y}) == { x: Rational(1, 3), y: 2 } x = Symbol('x') f = Function('f') F = x**2 + f(x)**2 - 4*x - 1 assert solve(F.diff(x), diff(f(x), x)) == [(-x + 2)/f(x)] # Mixed cased with a Symbol and a Function x = Symbol('x') y = Function('y')(t) soln = solve([a11*x + a12*y.diff(t) - b1, a21*x + a22*y.diff(t) - b2], x, y.diff(t)) assert soln == { y.diff(t): (a11*b2 - a21*b1)/(a11*a22 - a12*a21), x: (a22*b1 - a12*b2)/(a11*a22 - a12*a21) } # issue 13263 x = Symbol('x') f = Function('f') soln = solve([f(x).diff(x) + f(x).diff(x, 2) - 1, f(x).diff(x) - f(x).diff(x, 2)], f(x).diff(x), f(x).diff(x, 2)) assert soln == { f(x).diff(x, 2): 1/2, f(x).diff(x): 1/2 } soln = solve([f(x).diff(x, 2) + f(x).diff(x, 3) - 1, 1 - f(x).diff(x, 2) - f(x).diff(x, 3), 1 - f(x).diff(x,3)], f(x).diff(x, 2), f(x).diff(x, 3)) assert soln == { f(x).diff(x, 2): 0, f(x).diff(x, 3): 1 } def test_issue_3725(): f = Function('f') F = x**2 + f(x)**2 - 4*x - 1 e = F.diff(x) assert solve(e, f(x).diff(x)) in [[(2 - x)/f(x)], [-((x - 2)/f(x))]] def test_issue_3870(): a, b, c, d = symbols('a b c d') A = Matrix(2, 2, [a, b, c, d]) B = Matrix(2, 2, [0, 2, -3, 0]) C = Matrix(2, 2, [1, 2, 3, 4]) assert solve(A*B - C, [a, b, c, d]) == {a: 1, b: Rational(-1, 3), c: 2, d: -1} assert solve([A*B - C], [a, b, c, d]) == {a: 1, b: Rational(-1, 3), c: 2, d: -1} assert solve(Eq(A*B, C), [a, b, c, d]) == {a: 1, b: Rational(-1, 3), c: 2, d: -1} assert solve([A*B - B*A], [a, b, c, d]) == {a: d, b: Rational(-2, 3)*c} assert solve([A*C - C*A], [a, b, c, d]) == {a: d - c, b: Rational(2, 3)*c} assert solve([A*B - B*A, A*C - C*A], [a, b, c, d]) == {a: d, b: 0, c: 0} assert solve([Eq(A*B, B*A)], [a, b, c, d]) == {a: d, b: Rational(-2, 3)*c} assert solve([Eq(A*C, C*A)], [a, b, c, d]) == {a: d - c, b: Rational(2, 3)*c} assert solve([Eq(A*B, B*A), Eq(A*C, C*A)], [a, b, c, d]) == {a: d, b: 0, c: 0} def test_solve_linear(): w = Wild('w') assert solve_linear(x, x) == (0, 1) assert solve_linear(x, exclude=[x]) == (0, 1) assert solve_linear(x, symbols=[w]) == (0, 1) assert solve_linear(x, y - 2*x) in [(x, y/3), (y, 3*x)] assert solve_linear(x, y - 2*x, exclude=[x]) == (y, 3*x) assert solve_linear(3*x - y, 0) in [(x, y/3), (y, 3*x)] assert solve_linear(3*x - y, 0, [x]) == (x, y/3) assert solve_linear(3*x - y, 0, [y]) == (y, 3*x) assert solve_linear(x**2/y, 1) == (y, x**2) assert solve_linear(w, x) in [(w, x), (x, w)] assert solve_linear(cos(x)**2 + sin(x)**2 + 2 + y) == \ (y, -2 - cos(x)**2 - sin(x)**2) assert solve_linear(cos(x)**2 + sin(x)**2 + 2 + y, symbols=[x]) == (0, 1) assert solve_linear(Eq(x, 3)) == (x, 3) assert solve_linear(1/(1/x - 2)) == (0, 0) assert solve_linear((x + 1)*exp(-x), symbols=[x]) == (x, -1) assert solve_linear((x + 1)*exp(x), symbols=[x]) == ((x + 1)*exp(x), 1) assert solve_linear(x*exp(-x**2), symbols=[x]) == (x, 0) assert solve_linear(0**x - 1) == (0**x - 1, 1) assert solve_linear(1 + 1/(x - 1)) == (x, 0) eq = y*cos(x)**2 + y*sin(x)**2 - y # = y*(1 - 1) = 0 assert solve_linear(eq) == (0, 1) eq = cos(x)**2 + sin(x)**2 # = 1 assert solve_linear(eq) == (0, 1) raises(ValueError, lambda: solve_linear(Eq(x, 3), 3)) def test_solve_undetermined_coeffs(): assert solve_undetermined_coeffs(a*x**2 + b*x**2 + b*x + 2*c*x + c + 1, [a, b, c], x) == \ {a: -2, b: 2, c: -1} # Test that rational functions work assert solve_undetermined_coeffs(a/x + b/(x + 1) - (2*x + 1)/(x**2 + x), [a, b], x) == \ {a: 1, b: 1} # Test cancellation in rational functions assert solve_undetermined_coeffs(((c + 1)*a*x**2 + (c + 1)*b*x**2 + (c + 1)*b*x + (c + 1)*2*c*x + (c + 1)**2)/(c + 1), [a, b, c], x) == \ {a: -2, b: 2, c: -1} def test_solve_inequalities(): x = Symbol('x') sol = And(S.Zero < x, x < oo) assert solve(x + 1 > 1) == sol assert solve([x + 1 > 1]) == sol assert solve([x + 1 > 1], x) == sol assert solve([x + 1 > 1], [x]) == sol system = [Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)] assert solve(system) == \ And(Or(And(Lt(-sqrt(2), x), Lt(x, -1)), And(Lt(1, x), Lt(x, sqrt(2)))), Eq(0, 0)) x = Symbol('x', real=True) system = [Lt(x**2 - 2, 0), Gt(x**2 - 1, 0)] assert solve(system) == \ Or(And(Lt(-sqrt(2), x), Lt(x, -1)), And(Lt(1, x), Lt(x, sqrt(2)))) # issues 6627, 3448 assert solve((x - 3)/(x - 2) < 0, x) == And(Lt(2, x), Lt(x, 3)) assert solve(x/(x + 1) > 1, x) == And(Lt(-oo, x), Lt(x, -1)) assert solve(sin(x) > S.Half) == And(pi/6 < x, x < pi*Rational(5, 6)) assert solve(Eq(False, x < 1)) == (S.One <= x) & (x < oo) assert solve(Eq(True, x < 1)) == (-oo < x) & (x < 1) assert solve(Eq(x < 1, False)) == (S.One <= x) & (x < oo) assert solve(Eq(x < 1, True)) == (-oo < x) & (x < 1) assert solve(Eq(False, x)) == False assert solve(Eq(0, x)) == [0] assert solve(Eq(True, x)) == True assert solve(Eq(1, x)) == [1] assert solve(Eq(False, ~x)) == True assert solve(Eq(True, ~x)) == False assert solve(Ne(True, x)) == False assert solve(Ne(1, x)) == (x > -oo) & (x < oo) & Ne(x, 1) def test_issue_4793(): assert solve(1/x) == [] assert solve(x*(1 - 5/x)) == [5] assert solve(x + sqrt(x) - 2) == [1] assert solve(-(1 + x)/(2 + x)**2 + 1/(2 + x)) == [] assert solve(-x**2 - 2*x + (x + 1)**2 - 1) == [] assert solve((x/(x + 1) + 3)**(-2)) == [] assert solve(x/sqrt(x**2 + 1), x) == [0] assert solve(exp(x) - y, x) == [log(y)] assert solve(exp(x)) == [] assert solve(x**2 + x + sin(y)**2 + cos(y)**2 - 1, x) in [[0, -1], [-1, 0]] eq = 4*3**(5*x + 2) - 7 ans = solve(eq, x) assert len(ans) == 5 and all(eq.subs(x, a).n(chop=True) == 0 for a in ans) assert solve(log(x**2) - y**2/exp(x), x, y, set=True) == ( [x, y], {(x, sqrt(exp(x) * log(x ** 2))), (x, -sqrt(exp(x) * log(x ** 2)))}) assert solve(x**2*z**2 - z**2*y**2) == [{x: -y}, {x: y}, {z: 0}] assert solve((x - 1)/(1 + 1/(x - 1))) == [] assert solve(x**(y*z) - x, x) == [1] raises(NotImplementedError, lambda: solve(log(x) - exp(x), x)) raises(NotImplementedError, lambda: solve(2**x - exp(x) - 3)) def test_PR1964(): # issue 5171 assert solve(sqrt(x)) == solve(sqrt(x**3)) == [0] assert solve(sqrt(x - 1)) == [1] # issue 4462 a = Symbol('a') assert solve(-3*a/sqrt(x), x) == [] # issue 4486 assert solve(2*x/(x + 2) - 1, x) == [2] # issue 4496 assert set(solve((x**2/(7 - x)).diff(x))) == {S.Zero, S(14)} # issue 4695 f = Function('f') assert solve((3 - 5*x/f(x))*f(x), f(x)) == [x*Rational(5, 3)] # issue 4497 assert solve(1/root(5 + x, 5) - 9, x) == [Rational(-295244, 59049)] assert solve(sqrt(x) + sqrt(sqrt(x)) - 4) == [(Rational(-1, 2) + sqrt(17)/2)**4] assert set(solve(Poly(sqrt(exp(x)) + sqrt(exp(-x)) - 4))) in \ [ {log((-sqrt(3) + 2)**2), log((sqrt(3) + 2)**2)}, {2*log(-sqrt(3) + 2), 2*log(sqrt(3) + 2)}, {log(-4*sqrt(3) + 7), log(4*sqrt(3) + 7)}, ] assert set(solve(Poly(exp(x) + exp(-x) - 4))) == \ {log(-sqrt(3) + 2), log(sqrt(3) + 2)} assert set(solve(x**y + x**(2*y) - 1, x)) == \ {(Rational(-1, 2) + sqrt(5)/2)**(1/y), (Rational(-1, 2) - sqrt(5)/2)**(1/y)} assert solve(exp(x/y)*exp(-z/y) - 2, y) == [(x - z)/log(2)] assert solve( x**z*y**z - 2, z) in [[log(2)/(log(x) + log(y))], [log(2)/(log(x*y))]] # if you do inversion too soon then multiple roots (as for the following) # will be missed, e.g. if exp(3*x) = exp(3) -> 3*x = 3 E = S.Exp1 assert solve(exp(3*x) - exp(3), x) in [ [1, log(E*(Rational(-1, 2) - sqrt(3)*I/2)), log(E*(Rational(-1, 2) + sqrt(3)*I/2))], [1, log(-E/2 - sqrt(3)*E*I/2), log(-E/2 + sqrt(3)*E*I/2)], ] # coverage test p = Symbol('p', positive=True) assert solve((1/p + 1)**(p + 1)) == [] def test_issue_5197(): x = Symbol('x', real=True) assert solve(x**2 + 1, x) == [] n = Symbol('n', integer=True, positive=True) assert solve((n - 1)*(n + 2)*(2*n - 1), n) == [1] x = Symbol('x', positive=True) y = Symbol('y') assert solve([x + 5*y - 2, -3*x + 6*y - 15], x, y) == [] # not {x: -3, y: 1} b/c x is positive # The solution following should not contain (-sqrt(2), sqrt(2)) assert solve((x + y)*n - y**2 + 2, x, y) == [(sqrt(2), -sqrt(2))] y = Symbol('y', positive=True) # The solution following should not contain {y: -x*exp(x/2)} assert solve(x**2 - y**2/exp(x), y, x, dict=True) == [{y: x*exp(x/2)}] x, y, z = symbols('x y z', positive=True) assert solve(z**2*x**2 - z**2*y**2/exp(x), y, x, z, dict=True) == [{y: x*exp(x/2)}] def test_checking(): assert set( solve(x*(x - y/x), x, check=False)) == {sqrt(y), S.Zero, -sqrt(y)} assert set(solve(x*(x - y/x), x, check=True)) == {sqrt(y), -sqrt(y)} # {x: 0, y: 4} sets denominator to 0 in the following so system should return None assert solve((1/(1/x + 2), 1/(y - 3) - 1)) == [] # 0 sets denominator of 1/x to zero so None is returned assert solve(1/(1/x + 2)) == [] def test_issue_4671_4463_4467(): assert solve(sqrt(x**2 - 1) - 2) in ([sqrt(5), -sqrt(5)], [-sqrt(5), sqrt(5)]) assert solve((2**exp(y**2/x) + 2)/(x**2 + 15), y) == [ -sqrt(x*log(1 + I*pi/log(2))), sqrt(x*log(1 + I*pi/log(2)))] C1, C2 = symbols('C1 C2') f = Function('f') assert solve(C1 + C2/x**2 - exp(-f(x)), f(x)) == [log(x**2/(C1*x**2 + C2))] a = Symbol('a') E = S.Exp1 assert solve(1 - log(a + 4*x**2), x) in ( [-sqrt(-a + E)/2, sqrt(-a + E)/2], [sqrt(-a + E)/2, -sqrt(-a + E)/2] ) assert solve(log(a**(-3) - x**2)/a, x) in ( [-sqrt(-1 + a**(-3)), sqrt(-1 + a**(-3))], [sqrt(-1 + a**(-3)), -sqrt(-1 + a**(-3))],) assert solve(1 - log(a + 4*x**2), x) in ( [-sqrt(-a + E)/2, sqrt(-a + E)/2], [sqrt(-a + E)/2, -sqrt(-a + E)/2],) assert solve((a**2 + 1)*(sin(a*x) + cos(a*x)), x) == [-pi/(4*a)] assert solve(3 - (sinh(a*x) + cosh(a*x)), x) == [log(3)/a] assert set(solve(3 - (sinh(a*x) + cosh(a*x)**2), x)) == \ {log(-2 + sqrt(5))/a, log(-sqrt(2) + 1)/a, log(-sqrt(5) - 2)/a, log(1 + sqrt(2))/a} assert solve(atan(x) - 1) == [tan(1)] def test_issue_5132(): r, t = symbols('r,t') assert set(solve([r - x**2 - y**2, tan(t) - y/x], [x, y])) == \ {( -sqrt(r*cos(t)**2), -1*sqrt(r*cos(t)**2)*tan(t)), (sqrt(r*cos(t)**2), sqrt(r*cos(t)**2)*tan(t))} assert solve([exp(x) - sin(y), 1/y - 3], [x, y]) == \ [(log(sin(Rational(1, 3))), Rational(1, 3))] assert solve([exp(x) - sin(y), 1/exp(y) - 3], [x, y]) == \ [(log(-sin(log(3))), -log(3))] assert set(solve([exp(x) - sin(y), y**2 - 4], [x, y])) == \ {(log(-sin(2)), -S(2)), (log(sin(2)), S(2))} eqs = [exp(x)**2 - sin(y) + z**2, 1/exp(y) - 3] assert solve(eqs, set=True) == \ ([y, z], { (-log(3), sqrt(-exp(2*x) - sin(log(3)))), (-log(3), -sqrt(-exp(2*x) - sin(log(3))))}) assert solve(eqs, x, z, set=True) == ( [x, z], {(x, sqrt(-exp(2*x) + sin(y))), (x, -sqrt(-exp(2*x) + sin(y)))}) assert set(solve(eqs, x, y)) == \ { (log(-sqrt(-z**2 - sin(log(3)))), -log(3)), (log(-z**2 - sin(log(3)))/2, -log(3))} assert set(solve(eqs, y, z)) == \ { (-log(3), -sqrt(-exp(2*x) - sin(log(3)))), (-log(3), sqrt(-exp(2*x) - sin(log(3))))} eqs = [exp(x)**2 - sin(y) + z, 1/exp(y) - 3] assert solve(eqs, set=True) == ([y, z], { (-log(3), -exp(2*x) - sin(log(3)))}) assert solve(eqs, x, z, set=True) == ( [x, z], {(x, -exp(2*x) + sin(y))}) assert set(solve(eqs, x, y)) == { (log(-sqrt(-z - sin(log(3)))), -log(3)), (log(-z - sin(log(3)))/2, -log(3))} assert solve(eqs, z, y) == \ [(-exp(2*x) - sin(log(3)), -log(3))] assert solve((sqrt(x**2 + y**2) - sqrt(10), x + y - 4), set=True) == ( [x, y], {(S.One, S(3)), (S(3), S.One)}) assert set(solve((sqrt(x**2 + y**2) - sqrt(10), x + y - 4), x, y)) == \ {(S.One, S(3)), (S(3), S.One)} def test_issue_5335(): lam, a0, conc = symbols('lam a0 conc') a = 0.005 b = 0.743436700916726 eqs = [lam + 2*y - a0*(1 - x/2)*x - a*x/2*x, a0*(1 - x/2)*x - 1*y - b*y, x + y - conc] sym = [x, y, a0] # there are 4 solutions obtained manually but only two are valid assert len(solve(eqs, sym, manual=True, minimal=True)) == 2 assert len(solve(eqs, sym)) == 2 # cf below with rational=False @SKIP("Hangs") def _test_issue_5335_float(): # gives ZeroDivisionError: polynomial division lam, a0, conc = symbols('lam a0 conc') a = 0.005 b = 0.743436700916726 eqs = [lam + 2*y - a0*(1 - x/2)*x - a*x/2*x, a0*(1 - x/2)*x - 1*y - b*y, x + y - conc] sym = [x, y, a0] assert len(solve(eqs, sym, rational=False)) == 2 def test_issue_5767(): assert set(solve([x**2 + y + 4], [x])) == \ {(-sqrt(-y - 4),), (sqrt(-y - 4),)} def test_polysys(): assert set(solve([x**2 + 2/y - 2, x + y - 3], [x, y])) == \ {(S.One, S(2)), (1 + sqrt(5), 2 - sqrt(5)), (1 - sqrt(5), 2 + sqrt(5))} assert solve([x**2 + y - 2, x**2 + y]) == [] # the ordering should be whatever the user requested assert solve([x**2 + y - 3, x - y - 4], (x, y)) != solve([x**2 + y - 3, x - y - 4], (y, x)) @slow def test_unrad1(): raises(NotImplementedError, lambda: unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) + 3)) raises(NotImplementedError, lambda: unrad(sqrt(x) + (x + 1)**Rational(1, 3) + 2*sqrt(y))) s = symbols('s', cls=Dummy) # checkers to deal with possibility of answer coming # back with a sign change (cf issue 5203) def check(rv, ans): assert bool(rv[1]) == bool(ans[1]) if ans[1]: return s_check(rv, ans) e = rv[0].expand() a = ans[0].expand() return e in [a, -a] and rv[1] == ans[1] def s_check(rv, ans): # get the dummy rv = list(rv) d = rv[0].atoms(Dummy) reps = list(zip(d, [s]*len(d))) # replace s with this dummy rv = (rv[0].subs(reps).expand(), [rv[1][0].subs(reps), rv[1][1].subs(reps)]) ans = (ans[0].subs(reps).expand(), [ans[1][0].subs(reps), ans[1][1].subs(reps)]) return str(rv[0]) in [str(ans[0]), str(-ans[0])] and \ str(rv[1]) == str(ans[1]) assert unrad(1) is None assert check(unrad(sqrt(x)), (x, [])) assert check(unrad(sqrt(x) + 1), (x - 1, [])) assert check(unrad(sqrt(x) + root(x, 3) + 2), (s**3 + s**2 + 2, [s, s**6 - x])) assert check(unrad(sqrt(x)*root(x, 3) + 2), (x**5 - 64, [])) assert check(unrad(sqrt(x) + (x + 1)**Rational(1, 3)), (x**3 - (x + 1)**2, [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(2*x)), (-2*sqrt(2)*x - 2*x + 1, [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + 2), (16*x - 9, [])) assert check(unrad(sqrt(x) + sqrt(x + 1) + sqrt(1 - x)), (5*x**2 - 4*x, [])) assert check(unrad(a*sqrt(x) + b*sqrt(x) + c*sqrt(y) + d*sqrt(y)), ((a*sqrt(x) + b*sqrt(x))**2 - (c*sqrt(y) + d*sqrt(y))**2, [])) assert check(unrad(sqrt(x) + sqrt(1 - x)), (2*x - 1, [])) assert check(unrad(sqrt(x) + sqrt(1 - x) - 3), (x**2 - x + 16, [])) assert check(unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x)), (5*x**2 - 2*x + 1, [])) assert unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - 3) in [ (25*x**4 + 376*x**3 + 1256*x**2 - 2272*x + 784, []), (25*x**8 - 476*x**6 + 2534*x**4 - 1468*x**2 + 169, [])] assert unrad(sqrt(x) + sqrt(1 - x) + sqrt(2 + x) - sqrt(1 - 2*x)) == \ (41*x**4 + 40*x**3 + 232*x**2 - 160*x + 16, []) # orig root at 0.487 assert check(unrad(sqrt(x) + sqrt(x + 1)), (S.One, [])) eq = sqrt(x) + sqrt(x + 1) + sqrt(1 - sqrt(x)) assert check(unrad(eq), (16*x**2 - 9*x, [])) assert set(solve(eq, check=False)) == {S.Zero, Rational(9, 16)} assert solve(eq) == [] # but this one really does have those solutions assert set(solve(sqrt(x) - sqrt(x + 1) + sqrt(1 - sqrt(x)))) == \ {S.Zero, Rational(9, 16)} assert check(unrad(sqrt(x) + root(x + 1, 3) + 2*sqrt(y), y), (S('2*sqrt(x)*(x + 1)**(1/3) + x - 4*y + (x + 1)**(2/3)'), [])) assert check(unrad(sqrt(x/(1 - x)) + (x + 1)**Rational(1, 3)), (x**5 - x**4 - x**3 + 2*x**2 + x - 1, [])) assert check(unrad(sqrt(x/(1 - x)) + 2*sqrt(y), y), (4*x*y + x - 4*y, [])) assert check(unrad(sqrt(x)*sqrt(1 - x) + 2, x), (x**2 - x + 4, [])) # http://tutorial.math.lamar.edu/ # Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a assert solve(Eq(x, sqrt(x + 6))) == [3] assert solve(Eq(x + sqrt(x - 4), 4)) == [4] assert solve(Eq(1, x + sqrt(2*x - 3))) == [] assert set(solve(Eq(sqrt(5*x + 6) - 2, x))) == {-S.One, S(2)} assert set(solve(Eq(sqrt(2*x - 1) - sqrt(x - 4), 2))) == {S(5), S(13)} assert solve(Eq(sqrt(x + 7) + 2, sqrt(3 - x))) == [-6] # http://www.purplemath.com/modules/solverad.htm assert solve((2*x - 5)**Rational(1, 3) - 3) == [16] assert set(solve(x + 1 - root(x**4 + 4*x**3 - x, 4))) == \ {Rational(-1, 2), Rational(-1, 3)} assert set(solve(sqrt(2*x**2 - 7) - (3 - x))) == {-S(8), S(2)} assert solve(sqrt(2*x + 9) - sqrt(x + 1) - sqrt(x + 4)) == [0] assert solve(sqrt(x + 4) + sqrt(2*x - 1) - 3*sqrt(x - 1)) == [5] assert solve(sqrt(x)*sqrt(x - 7) - 12) == [16] assert solve(sqrt(x - 3) + sqrt(x) - 3) == [4] assert solve(sqrt(9*x**2 + 4) - (3*x + 2)) == [0] assert solve(sqrt(x) - 2 - 5) == [49] assert solve(sqrt(x - 3) - sqrt(x) - 3) == [] assert solve(sqrt(x - 1) - x + 7) == [10] assert solve(sqrt(x - 2) - 5) == [27] assert solve(sqrt(17*x - sqrt(x**2 - 5)) - 7) == [3] assert solve(sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x))) == [] # don't posify the expression in unrad and do use _mexpand z = sqrt(2*x + 1)/sqrt(x) - sqrt(2 + 1/x) p = posify(z)[0] assert solve(p) == [] assert solve(z) == [] assert solve(z + 6*I) == [Rational(-1, 11)] assert solve(p + 6*I) == [] # issue 8622 assert unrad(root(x + 1, 5) - root(x, 3)) == ( -(x**5 - x**3 - 3*x**2 - 3*x - 1), []) # issue #8679 assert check(unrad(x + root(x, 3) + root(x, 3)**2 + sqrt(y), x), (s**3 + s**2 + s + sqrt(y), [s, s**3 - x])) # for coverage assert check(unrad(sqrt(x) + root(x, 3) + y), (s**3 + s**2 + y, [s, s**6 - x])) assert solve(sqrt(x) + root(x, 3) - 2) == [1] raises(NotImplementedError, lambda: solve(sqrt(x) + root(x, 3) + root(x + 1, 5) - 2)) # fails through a different code path raises(NotImplementedError, lambda: solve(-sqrt(2) + cosh(x)/x)) # unrad some assert solve(sqrt(x + root(x, 3))+root(x - y, 5), y) == [ x + (x**Rational(1, 3) + x)**Rational(5, 2)] assert check(unrad(sqrt(x) - root(x + 1, 3)*sqrt(x + 2) + 2), (s**10 + 8*s**8 + 24*s**6 - 12*s**5 - 22*s**4 - 160*s**3 - 212*s**2 - 192*s - 56, [s, s**2 - x])) e = root(x + 1, 3) + root(x, 3) assert unrad(e) == (2*x + 1, []) eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) assert check(unrad(eq), (15625*x**4 + 173000*x**3 + 355600*x**2 - 817920*x + 331776, [])) assert check(unrad(root(x, 4) + root(x, 4)**3 - 1), (s**3 + s - 1, [s, s**4 - x])) assert check(unrad(root(x, 2) + root(x, 2)**3 - 1), (x**3 + 2*x**2 + x - 1, [])) assert unrad(x**0.5) is None assert check(unrad(t + root(x + y, 5) + root(x + y, 5)**3), (s**3 + s + t, [s, s**5 - x - y])) assert check(unrad(x + root(x + y, 5) + root(x + y, 5)**3, y), (s**3 + s + x, [s, s**5 - x - y])) assert check(unrad(x + root(x + y, 5) + root(x + y, 5)**3, x), (s**5 + s**3 + s - y, [s, s**5 - x - y])) assert check(unrad(root(x - 1, 3) + root(x + 1, 5) + root(2, 5)), (s**5 + 5*2**Rational(1, 5)*s**4 + s**3 + 10*2**Rational(2, 5)*s**3 + 10*2**Rational(3, 5)*s**2 + 5*2**Rational(4, 5)*s + 4, [s, s**3 - x + 1])) raises(NotImplementedError, lambda: unrad((root(x, 2) + root(x, 3) + root(x, 4)).subs(x, x**5 - x + 1))) # the simplify flag should be reset to False for unrad results; # if it's not then this next test will take a long time assert solve(root(x, 3) + root(x, 5) - 2) == [1] eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) assert check(unrad(eq), ((5*x - 4)*(3125*x**3 + 37100*x**2 + 100800*x - 82944), [])) ans = S(''' [4/5, -1484/375 + 172564/(140625*(114*sqrt(12657)/78125 + 12459439/52734375)**(1/3)) + 4*(114*sqrt(12657)/78125 + 12459439/52734375)**(1/3)]''') assert solve(eq) == ans # duplicate radical handling assert check(unrad(sqrt(x + root(x + 1, 3)) - root(x + 1, 3) - 2), (s**3 - s**2 - 3*s - 5, [s, s**3 - x - 1])) # cov post-processing e = root(x**2 + 1, 3) - root(x**2 - 1, 5) - 2 assert check(unrad(e), (s**5 - 10*s**4 + 39*s**3 - 80*s**2 + 80*s - 30, [s, s**3 - x**2 - 1])) e = sqrt(x + root(x + 1, 2)) - root(x + 1, 3) - 2 assert check(unrad(e), (s**6 - 2*s**5 - 7*s**4 - 3*s**3 + 26*s**2 + 40*s + 25, [s, s**3 - x - 1])) assert check(unrad(e, _reverse=True), (s**6 - 14*s**5 + 73*s**4 - 187*s**3 + 276*s**2 - 228*s + 89, [s, s**2 - x - sqrt(x + 1)])) # this one needs r0, r1 reversal to work assert check(unrad(sqrt(x + sqrt(root(x, 3) - 1)) - root(x, 6) - 2), (s**12 - 2*s**8 - 8*s**7 - 8*s**6 + s**4 + 8*s**3 + 23*s**2 + 32*s + 17, [s, s**6 - x])) # why does this pass assert unrad(root(cosh(x), 3)/x*root(x + 1, 5) - 1) == ( -(x**15 - x**3*cosh(x)**5 - 3*x**2*cosh(x)**5 - 3*x*cosh(x)**5 - cosh(x)**5), []) # and this fail? #assert unrad(sqrt(cosh(x)/x) + root(x + 1, 3)*sqrt(x) - 1) == ( # -s**6 + 6*s**5 - 15*s**4 + 20*s**3 - 15*s**2 + 6*s + x**5 + # 2*x**4 + x**3 - 1, [s, s**2 - cosh(x)/x]) # watch for symbols in exponents assert unrad(S('(x+y)**(2*y/3) + (x+y)**(1/3) + 1')) is None assert check(unrad(S('(x+y)**(2*y/3) + (x+y)**(1/3) + 1'), x), (s**(2*y) + s + 1, [s, s**3 - x - y])) # should _Q be so lenient? assert unrad(x**(S.Half/y) + y, x) == (x**(1/y) - y**2, []) # This tests two things: that if full unrad is attempted and fails # the solution should still be found; also it tests that the use of # composite assert len(solve(sqrt(y)*x + x**3 - 1, x)) == 3 assert len(solve(-512*y**3 + 1344*(x + 2)**Rational(1, 3)*y**2 - 1176*(x + 2)**Rational(2, 3)*y - 169*x + 686, y, _unrad=False)) == 3 # watch out for when the cov doesn't involve the symbol of interest eq = S('-x + (7*y/8 - (27*x/2 + 27*sqrt(x**2)/2)**(1/3)/3)**3 - 1') assert solve(eq, y) == [ 2**(S(2)/3)*(27*x + 27*sqrt(x**2))**(S(1)/3)*S(4)/21 + (512*x/343 + S(512)/343)**(S(1)/3)*(-S(1)/2 - sqrt(3)*I/2), 2**(S(2)/3)*(27*x + 27*sqrt(x**2))**(S(1)/3)*S(4)/21 + (512*x/343 + S(512)/343)**(S(1)/3)*(-S(1)/2 + sqrt(3)*I/2), 2**(S(2)/3)*(27*x + 27*sqrt(x**2))**(S(1)/3)*S(4)/21 + (512*x/343 + S(512)/343)**(S(1)/3)] eq = root(x + 1, 3) - (root(x, 3) + root(x, 5)) assert check(unrad(eq), (3*s**13 + 3*s**11 + s**9 - 1, [s, s**15 - x])) assert check(unrad(eq - 2), (3*s**13 + 3*s**11 + 6*s**10 + s**9 + 12*s**8 + 6*s**6 + 12*s**5 + 12*s**3 + 7, [s, s**15 - x])) assert check(unrad(root(x, 3) - root(x + 1, 4)/2 + root(x + 2, 3)), (s*(4096*s**9 + 960*s**8 + 48*s**7 - s**6 - 1728), [s, s**4 - x - 1])) # orig expr has two real roots: -1, -.389 assert check(unrad(root(x, 3) + root(x + 1, 4) - root(x + 2, 3)/2), (343*s**13 + 2904*s**12 + 1344*s**11 + 512*s**10 - 1323*s**9 - 3024*s**8 - 1728*s**7 + 1701*s**5 + 216*s**4 - 729*s, [s, s**4 - x - 1])) # orig expr has one real root: -0.048 assert check(unrad(root(x, 3)/2 - root(x + 1, 4) + root(x + 2, 3)), (729*s**13 - 216*s**12 + 1728*s**11 - 512*s**10 + 1701*s**9 - 3024*s**8 + 1344*s**7 + 1323*s**5 - 2904*s**4 + 343*s, [s, s**4 - x - 1])) # orig expr has 2 real roots: -0.91, -0.15 assert check(unrad(root(x, 3)/2 - root(x + 1, 4) + root(x + 2, 3) - 2), (729*s**13 + 1242*s**12 + 18496*s**10 + 129701*s**9 + 388602*s**8 + 453312*s**7 - 612864*s**6 - 3337173*s**5 - 6332418*s**4 - 7134912*s**3 - 5064768*s**2 - 2111913*s - 398034, [s, s**4 - x - 1])) # orig expr has 1 real root: 19.53 ans = solve(sqrt(x) + sqrt(x + 1) - sqrt(1 - x) - sqrt(2 + x)) assert len(ans) == 1 and NS(ans[0])[:4] == '0.73' # the fence optimization problem # https://github.com/sympy/sympy/issues/4793#issuecomment-36994519 F = Symbol('F') eq = F - (2*x + 2*y + sqrt(x**2 + y**2)) ans = F*Rational(2, 7) - sqrt(2)*F/14 X = solve(eq, x, check=False) for xi in reversed(X): # reverse since currently, ans is the 2nd one Y = solve((x*y).subs(x, xi).diff(y), y, simplify=False, check=False) if any((a - ans).expand().is_zero for a in Y): break else: assert None # no answer was found assert solve(sqrt(x + 1) + root(x, 3) - 2) == S(''' [(-11/(9*(47/54 + sqrt(93)/6)**(1/3)) + 1/3 + (47/54 + sqrt(93)/6)**(1/3))**3]''') assert solve(sqrt(sqrt(x + 1)) + x**Rational(1, 3) - 2) == S(''' [(-sqrt(-2*(-1/16 + sqrt(6913)/16)**(1/3) + 6/(-1/16 + sqrt(6913)/16)**(1/3) + 17/2 + 121/(4*sqrt(-6/(-1/16 + sqrt(6913)/16)**(1/3) + 2*(-1/16 + sqrt(6913)/16)**(1/3) + 17/4)))/2 + sqrt(-6/(-1/16 + sqrt(6913)/16)**(1/3) + 2*(-1/16 + sqrt(6913)/16)**(1/3) + 17/4)/2 + 9/4)**3]''') assert solve(sqrt(x) + root(sqrt(x) + 1, 3) - 2) == S(''' [(-(81/2 + 3*sqrt(741)/2)**(1/3)/3 + (81/2 + 3*sqrt(741)/2)**(-1/3) + 2)**2]''') eq = S(''' -x + (1/2 - sqrt(3)*I/2)*(3*x**3/2 - x*(3*x**2 - 34)/2 + sqrt((-3*x**3 + x*(3*x**2 - 34) + 90)**2/4 - 39304/27) - 45)**(1/3) + 34/(3*(1/2 - sqrt(3)*I/2)*(3*x**3/2 - x*(3*x**2 - 34)/2 + sqrt((-3*x**3 + x*(3*x**2 - 34) + 90)**2/4 - 39304/27) - 45)**(1/3))''') assert check(unrad(eq), (s*-(-s**6 + sqrt(3)*s**6*I - 153*2**Rational(2, 3)*3**Rational(1, 3)*s**4 + 51*12**Rational(1, 3)*s**4 - 102*2**Rational(2, 3)*3**Rational(5, 6)*s**4*I - 1620*s**3 + 1620*sqrt(3)*s**3*I + 13872*18**Rational(1, 3)*s**2 - 471648 + 471648*sqrt(3)*I), [s, s**3 - 306*x - sqrt(3)*sqrt(31212*x**2 - 165240*x + 61484) + 810])) assert solve(eq) == [] # not other code errors eq = root(x, 3) - root(y, 3) + root(x, 5) assert check(unrad(eq), (s**15 + 3*s**13 + 3*s**11 + s**9 - y, [s, s**15 - x])) eq = root(x, 3) + root(y, 3) + root(x*y, 4) assert check(unrad(eq), (s*y*(-s**12 - 3*s**11*y - 3*s**10*y**2 - s**9*y**3 - 3*s**8*y**2 + 21*s**7*y**3 - 3*s**6*y**4 - 3*s**4*y**4 - 3*s**3*y**5 - y**6), [s, s**4 - x*y])) raises(NotImplementedError, lambda: unrad(root(x, 3) + root(y, 3) + root(x*y, 5))) # Test unrad with an Equality eq = Eq(-x**(S(1)/5) + x**(S(1)/3), -3**(S(1)/3) - (-1)**(S(3)/5)*3**(S(1)/5)) assert check(unrad(eq), (-s**5 + s**3 - 3**(S(1)/3) - (-1)**(S(3)/5)*3**(S(1)/5), [s, s**15 - x])) # make sure buried radicals are exposed s = sqrt(x) - 1 assert unrad(s**2 - s**3) == (x**3 - 6*x**2 + 9*x - 4, []) # make sure numerators which are already polynomial are rejected assert unrad((x/(x + 1) + 3)**(-2), x) is None @slow def test_unrad_slow(): # this has roots with multiplicity > 1; there should be no # repeats in roots obtained, however eq = (sqrt(1 + sqrt(1 - 4*x**2)) - x*(1 + sqrt(1 + 2*sqrt(1 - 4*x**2)))) assert solve(eq) == [S.Half] @XFAIL def test_unrad_fail(): # this only works if we check real_root(eq.subs(x, Rational(1, 3))) # but checksol doesn't work like that assert solve(root(x**3 - 3*x**2, 3) + 1 - x) == [Rational(1, 3)] assert solve(root(x + 1, 3) + root(x**2 - 2, 5) + 1) == [ -1, -1 + CRootOf(x**5 + x**4 + 5*x**3 + 8*x**2 + 10*x + 5, 0)**3] def test_checksol(): x, y, r, t = symbols('x, y, r, t') eq = r - x**2 - y**2 dict_var_soln = {y: - sqrt(r) / sqrt(tan(t)**2 + 1), x: -sqrt(r)*tan(t)/sqrt(tan(t)**2 + 1)} assert checksol(eq, dict_var_soln) == True assert checksol(Eq(x, False), {x: False}) is True assert checksol(Ne(x, False), {x: False}) is False assert checksol(Eq(x < 1, True), {x: 0}) is True assert checksol(Eq(x < 1, True), {x: 1}) is False assert checksol(Eq(x < 1, False), {x: 1}) is True assert checksol(Eq(x < 1, False), {x: 0}) is False assert checksol(Eq(x + 1, x**2 + 1), {x: 1}) is True assert checksol([x - 1, x**2 - 1], x, 1) is True assert checksol([x - 1, x**2 - 2], x, 1) is False assert checksol(Poly(x**2 - 1), x, 1) is True raises(ValueError, lambda: checksol(x, 1)) raises(ValueError, lambda: checksol([], x, 1)) def test__invert(): assert _invert(x - 2) == (2, x) assert _invert(2) == (2, 0) assert _invert(exp(1/x) - 3, x) == (1/log(3), x) assert _invert(exp(1/x + a/x) - 3, x) == ((a + 1)/log(3), x) assert _invert(a, x) == (a, 0) def test_issue_4463(): assert solve(-a*x + 2*x*log(x), x) == [exp(a/2)] assert solve(x**x) == [] assert solve(x**x - 2) == [exp(LambertW(log(2)))] assert solve(((x - 3)*(x - 2))**((x - 3)*(x - 4))) == [2] @slow def test_issue_5114_solvers(): a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r = symbols('a:r') # there is no 'a' in the equation set but this is how the # problem was originally posed syms = a, b, c, f, h, k, n eqs = [b + r/d - c/d, c*(1/d + 1/e + 1/g) - f/g - r/d, f*(1/g + 1/i + 1/j) - c/g - h/i, h*(1/i + 1/l + 1/m) - f/i - k/m, k*(1/m + 1/o + 1/p) - h/m - n/p, n*(1/p + 1/q) - k/p] assert len(solve(eqs, syms, manual=True, check=False, simplify=False)) == 1 def test_issue_5849(): # # XXX: This system does not have a solution for most values of the # parameters. Generally solve returns the empty set for systems that are # generically inconsistent. # I1, I2, I3, I4, I5, I6 = symbols('I1:7') dI1, dI4, dQ2, dQ4, Q2, Q4 = symbols('dI1,dI4,dQ2,dQ4,Q2,Q4') e = ( I1 - I2 - I3, I3 - I4 - I5, I4 + I5 - I6, -I1 + I2 + I6, -2*I1 - 2*I3 - 2*I5 - 3*I6 - dI1/2 + 12, -I4 + dQ4, -I2 + dQ2, 2*I3 + 2*I5 + 3*I6 - Q2, I4 - 2*I5 + 2*Q4 + dI4 ) ans = [{ I1: I2 + I3, dI1: -4*I2 - 8*I3 - 4*I5 - 6*I6 + 24, I4: I3 - I5, dQ4: I3 - I5, Q4: -I3/2 + 3*I5/2 - dI4/2, dQ2: I2, Q2: 2*I3 + 2*I5 + 3*I6}] v = I1, I4, Q2, Q4, dI1, dI4, dQ2, dQ4 assert solve(e, *v, manual=True, check=False, dict=True) == ans assert solve(e, *v, manual=True, check=False) == ans[0] assert solve(e, *v, manual=True) == [] assert solve(e, *v) == [] # the matrix solver (tested below) doesn't like this because it produces # a zero row in the matrix. Is this related to issue 4551? assert [ei.subs( ans[0]) for ei in e] == [0, 0, I3 - I6, -I3 + I6, 0, 0, 0, 0, 0] def test_issue_5849_matrix(): '''Same as test_issue_5849 but solved with the matrix solver. A solution only exists if I3 == I6 which is not generically true, but `solve` does not return conditions under which the solution is valid, only a solution that is canonical and consistent with the input. ''' # a simple example with the same issue # assert solve([x+y+z, x+y], [x, y]) == {x: y} # the longer example I1, I2, I3, I4, I5, I6 = symbols('I1:7') dI1, dI4, dQ2, dQ4, Q2, Q4 = symbols('dI1,dI4,dQ2,dQ4,Q2,Q4') e = ( I1 - I2 - I3, I3 - I4 - I5, I4 + I5 - I6, -I1 + I2 + I6, -2*I1 - 2*I3 - 2*I5 - 3*I6 - dI1/2 + 12, -I4 + dQ4, -I2 + dQ2, 2*I3 + 2*I5 + 3*I6 - Q2, I4 - 2*I5 + 2*Q4 + dI4 ) assert solve(e, I1, I4, Q2, Q4, dI1, dI4, dQ2, dQ4) == [] def test_issue_21882(): a, b, c, d, f, g, k = unknowns = symbols('a, b, c, d, f, g, k') equations = [ -k*a + b + 5*f/6 + 2*c/9 + 5*d/6 + 4*a/3, -k*f + 4*f/3 + d/2, -k*d + f/6 + d, 13*b/18 + 13*c/18 + 13*a/18, -k*c + b/2 + 20*c/9 + a, -k*b + b + c/18 + a/6, 5*b/3 + c/3 + a, 2*b/3 + 2*c + 4*a/3, -g, ] answer = [ {a: 0, f: 0, b: 0, d: 0, c: 0, g: 0}, {a: 0, f: -d, b: 0, k: S(5)/6, c: 0, g: 0}, {a: -2*c, f: 0, b: c, d: 0, k: S(13)/18, g: 0}, ] assert solve(equations, unknowns, dict=True) == answer def test_issue_5901(): f, g, h = map(Function, 'fgh') a = Symbol('a') D = Derivative(f(x), x) G = Derivative(g(a), a) assert solve(f(x) + f(x).diff(x), f(x)) == \ [-D] assert solve(f(x) - 3, f(x)) == \ [3] assert solve(f(x) - 3*f(x).diff(x), f(x)) == \ [3*D] assert solve([f(x) - 3*f(x).diff(x)], f(x)) == \ {f(x): 3*D} assert solve([f(x) - 3*f(x).diff(x), f(x)**2 - y + 4], f(x), y) == \ [{f(x): 3*D, y: 9*D**2 + 4}] assert solve(-f(a)**2*g(a)**2 + f(a)**2*h(a)**2 + g(a).diff(a), h(a), g(a), set=True) == \ ([g(a)], { (-sqrt(h(a)**2*f(a)**2 + G)/f(a),), (sqrt(h(a)**2*f(a)**2+ G)/f(a),)}) args = [f(x).diff(x, 2)*(f(x) + g(x)) - g(x)**2 + 2, f(x), g(x)] assert set(solve(*args)) == \ {(-sqrt(2), sqrt(2)), (sqrt(2), -sqrt(2))} eqs = [f(x)**2 + g(x) - 2*f(x).diff(x), g(x)**2 - 4] assert solve(eqs, f(x), g(x), set=True) == \ ([f(x), g(x)], { (-sqrt(2*D - 2), S(2)), (sqrt(2*D - 2), S(2)), (-sqrt(2*D + 2), -S(2)), (sqrt(2*D + 2), -S(2))}) # the underlying problem was in solve_linear that was not masking off # anything but a Mul or Add; it now raises an error if it gets anything # but a symbol and solve handles the substitutions necessary so solve_linear # won't make this error raises( ValueError, lambda: solve_linear(f(x) + f(x).diff(x), symbols=[f(x)])) assert solve_linear(f(x) + f(x).diff(x), symbols=[x]) == \ (f(x) + Derivative(f(x), x), 1) assert solve_linear(f(x) + Integral(x, (x, y)), symbols=[x]) == \ (f(x) + Integral(x, (x, y)), 1) assert solve_linear(f(x) + Integral(x, (x, y)) + x, symbols=[x]) == \ (x + f(x) + Integral(x, (x, y)), 1) assert solve_linear(f(y) + Integral(x, (x, y)) + x, symbols=[x]) == \ (x, -f(y) - Integral(x, (x, y))) assert solve_linear(x - f(x)/a + (f(x) - 1)/a, symbols=[x]) == \ (x, 1/a) assert solve_linear(x + Derivative(2*x, x)) == \ (x, -2) assert solve_linear(x + Integral(x, y), symbols=[x]) == \ (x, 0) assert solve_linear(x + Integral(x, y) - 2, symbols=[x]) == \ (x, 2/(y + 1)) assert set(solve(x + exp(x)**2, exp(x))) == \ {-sqrt(-x), sqrt(-x)} assert solve(x + exp(x), x, implicit=True) == \ [-exp(x)] assert solve(cos(x) - sin(x), x, implicit=True) == [] assert solve(x - sin(x), x, implicit=True) == \ [sin(x)] assert solve(x**2 + x - 3, x, implicit=True) == \ [-x**2 + 3] assert solve(x**2 + x - 3, x**2, implicit=True) == \ [-x + 3] def test_issue_5912(): assert set(solve(x**2 - x - 0.1, rational=True)) == \ {S.Half + sqrt(35)/10, -sqrt(35)/10 + S.Half} ans = solve(x**2 - x - 0.1, rational=False) assert len(ans) == 2 and all(a.is_Number for a in ans) ans = solve(x**2 - x - 0.1) assert len(ans) == 2 and all(a.is_Number for a in ans) def test_float_handling(): def test(e1, e2): return len(e1.atoms(Float)) == len(e2.atoms(Float)) assert solve(x - 0.5, rational=True)[0].is_Rational assert solve(x - 0.5, rational=False)[0].is_Float assert solve(x - S.Half, rational=False)[0].is_Rational assert solve(x - 0.5, rational=None)[0].is_Float assert solve(x - S.Half, rational=None)[0].is_Rational assert test(nfloat(1 + 2*x), 1.0 + 2.0*x) for contain in [list, tuple, set]: ans = nfloat(contain([1 + 2*x])) assert type(ans) is contain and test(list(ans)[0], 1.0 + 2.0*x) k, v = list(nfloat({2*x: [1 + 2*x]}).items())[0] assert test(k, 2*x) and test(v[0], 1.0 + 2.0*x) assert test(nfloat(cos(2*x)), cos(2.0*x)) assert test(nfloat(3*x**2), 3.0*x**2) assert test(nfloat(3*x**2, exponent=True), 3.0*x**2.0) assert test(nfloat(exp(2*x)), exp(2.0*x)) assert test(nfloat(x/3), x/3.0) assert test(nfloat(x**4 + 2*x + cos(Rational(1, 3)) + 1), x**4 + 2.0*x + 1.94495694631474) # don't call nfloat if there is no solution tot = 100 + c + z + t assert solve(((.7 + c)/tot - .6, (.2 + z)/tot - .3, t/tot - .1)) == [] def test_check_assumptions(): x = symbols('x', positive=True) assert solve(x**2 - 1) == [1] def test_issue_6056(): assert solve(tanh(x + 3)*tanh(x - 3) - 1) == [] assert solve(tanh(x - 1)*tanh(x + 1) + 1) == \ [I*pi*Rational(-3, 4), -I*pi/4, I*pi/4, I*pi*Rational(3, 4)] assert solve((tanh(x + 3)*tanh(x - 3) + 1)**2) == \ [I*pi*Rational(-3, 4), -I*pi/4, I*pi/4, I*pi*Rational(3, 4)] def test_issue_5673(): eq = -x + exp(exp(LambertW(log(x)))*LambertW(log(x))) assert checksol(eq, x, 2) is True assert checksol(eq, x, 2, numerical=False) is None def test_exclude(): R, C, Ri, Vout, V1, Vminus, Vplus, s = \ symbols('R, C, Ri, Vout, V1, Vminus, Vplus, s') Rf = symbols('Rf', positive=True) # to eliminate Rf = 0 soln eqs = [C*V1*s + Vplus*(-2*C*s - 1/R), Vminus*(-1/Ri - 1/Rf) + Vout/Rf, C*Vplus*s + V1*(-C*s - 1/R) + Vout/R, -Vminus + Vplus] assert solve(eqs, exclude=s*C*R) == [ { Rf: Ri*(C*R*s + 1)**2/(C*R*s), Vminus: Vplus, V1: 2*Vplus + Vplus/(C*R*s), Vout: C*R*Vplus*s + 3*Vplus + Vplus/(C*R*s)}, { Vplus: 0, Vminus: 0, V1: 0, Vout: 0}, ] # TODO: Investigate why currently solution [0] is preferred over [1]. assert solve(eqs, exclude=[Vplus, s, C]) in [[{ Vminus: Vplus, V1: Vout/2 + Vplus/2 + sqrt((Vout - 5*Vplus)*(Vout - Vplus))/2, R: (Vout - 3*Vplus - sqrt(Vout**2 - 6*Vout*Vplus + 5*Vplus**2))/(2*C*Vplus*s), Rf: Ri*(Vout - Vplus)/Vplus, }, { Vminus: Vplus, V1: Vout/2 + Vplus/2 - sqrt((Vout - 5*Vplus)*(Vout - Vplus))/2, R: (Vout - 3*Vplus + sqrt(Vout**2 - 6*Vout*Vplus + 5*Vplus**2))/(2*C*Vplus*s), Rf: Ri*(Vout - Vplus)/Vplus, }], [{ Vminus: Vplus, Vout: (V1**2 - V1*Vplus - Vplus**2)/(V1 - 2*Vplus), Rf: Ri*(V1 - Vplus)**2/(Vplus*(V1 - 2*Vplus)), R: Vplus/(C*s*(V1 - 2*Vplus)), }]] def test_high_order_roots(): s = x**5 + 4*x**3 + 3*x**2 + Rational(7, 4) assert set(solve(s)) == set(Poly(s*4, domain='ZZ').all_roots()) def test_minsolve_linear_system(): def count(dic): return len([x for x in dic.values() if x == 0]) assert count(solve([x + y + z, y + z + a + t], particular=True, quick=True)) \ == 3 assert count(solve([x + y + z, y + z + a + t], particular=True, quick=False)) \ == 3 assert count(solve([x + y + z, y + z + a], particular=True, quick=True)) == 1 assert count(solve([x + y + z, y + z + a], particular=True, quick=False)) == 2 def test_real_roots(): # cf. issue 6650 x = Symbol('x', real=True) assert len(solve(x**5 + x**3 + 1)) == 1 def test_issue_6528(): eqs = [ 327600995*x**2 - 37869137*x + 1809975124*y**2 - 9998905626, 895613949*x**2 - 273830224*x*y + 530506983*y**2 - 10000000000] # two expressions encountered are > 1400 ops long so if this hangs # it is likely because simplification is being done assert len(solve(eqs, y, x, check=False)) == 4 def test_overdetermined(): x = symbols('x', real=True) eqs = [Abs(4*x - 7) - 5, Abs(3 - 8*x) - 1] assert solve(eqs, x) == [(S.Half,)] assert solve(eqs, x, manual=True) == [(S.Half,)] assert solve(eqs, x, manual=True, check=False) == [(S.Half,), (S(3),)] def test_issue_6605(): x = symbols('x') assert solve(4**(x/2) - 2**(x/3)) == [0, 3*I*pi/log(2)] # while the first one passed, this one failed x = symbols('x', real=True) assert solve(5**(x/2) - 2**(x/3)) == [0] b = sqrt(6)*sqrt(log(2))/sqrt(log(5)) assert solve(5**(x/2) - 2**(3/x)) == [-b, b] def test__ispow(): assert _ispow(x**2) assert not _ispow(x) assert not _ispow(True) def test_issue_6644(): eq = -sqrt((m - q)**2 + (-m/(2*q) + S.Half)**2) + sqrt((-m**2/2 - sqrt( 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2 + (m**2/2 - m - sqrt( 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2) sol = solve(eq, q, simplify=False, check=False) assert len(sol) == 5 def test_issue_6752(): assert solve([a**2 + a, a - b], [a, b]) == [(-1, -1), (0, 0)] assert solve([a**2 + a*c, a - b], [a, b]) == [(0, 0), (-c, -c)] def test_issue_6792(): assert solve(x*(x - 1)**2*(x + 1)*(x**6 - x + 1)) == [ -1, 0, 1, CRootOf(x**6 - x + 1, 0), CRootOf(x**6 - x + 1, 1), CRootOf(x**6 - x + 1, 2), CRootOf(x**6 - x + 1, 3), CRootOf(x**6 - x + 1, 4), CRootOf(x**6 - x + 1, 5)] def test_issues_6819_6820_6821_6248_8692(): # issue 6821 x, y = symbols('x y', real=True) assert solve(abs(x + 3) - 2*abs(x - 3)) == [1, 9] assert solve([abs(x) - 2, arg(x) - pi], x) == [(-2,)] assert set(solve(abs(x - 7) - 8)) == {-S.One, S(15)} # issue 8692 assert solve(Eq(Abs(x + 1) + Abs(x**2 - 7), 9), x) == [ Rational(-1, 2) + sqrt(61)/2, -sqrt(69)/2 + S.Half] # issue 7145 assert solve(2*abs(x) - abs(x - 1)) == [-1, Rational(1, 3)] x = symbols('x') assert solve([re(x) - 1, im(x) - 2], x) == [ {re(x): 1, x: 1 + 2*I, im(x): 2}] # check for 'dict' handling of solution eq = sqrt(re(x)**2 + im(x)**2) - 3 assert solve(eq) == solve(eq, x) i = symbols('i', imaginary=True) assert solve(abs(i) - 3) == [-3*I, 3*I] raises(NotImplementedError, lambda: solve(abs(x) - 3)) w = symbols('w', integer=True) assert solve(2*x**w - 4*y**w, w) == solve((x/y)**w - 2, w) x, y = symbols('x y', real=True) assert solve(x + y*I + 3) == {y: 0, x: -3} # issue 2642 assert solve(x*(1 + I)) == [0] x, y = symbols('x y', imaginary=True) assert solve(x + y*I + 3 + 2*I) == {x: -2*I, y: 3*I} x = symbols('x', real=True) assert solve(x + y + 3 + 2*I) == {x: -3, y: -2*I} # issue 6248 f = Function('f') assert solve(f(x + 1) - f(2*x - 1)) == [2] assert solve(log(x + 1) - log(2*x - 1)) == [2] x = symbols('x') assert solve(2**x + 4**x) == [I*pi/log(2)] def test_issue_14607(): # issue 14607 s, tau_c, tau_1, tau_2, phi, K = symbols( 's, tau_c, tau_1, tau_2, phi, K') target = (s**2*tau_1*tau_2 + s*tau_1 + s*tau_2 + 1)/(K*s*(-phi + tau_c)) K_C, tau_I, tau_D = symbols('K_C, tau_I, tau_D', positive=True, nonzero=True) PID = K_C*(1 + 1/(tau_I*s) + tau_D*s) eq = (target - PID).together() eq *= denom(eq).simplify() eq = Poly(eq, s) c = eq.coeffs() vars = [K_C, tau_I, tau_D] s = solve(c, vars, dict=True) assert len(s) == 1 knownsolution = {K_C: -(tau_1 + tau_2)/(K*(phi - tau_c)), tau_I: tau_1 + tau_2, tau_D: tau_1*tau_2/(tau_1 + tau_2)} for var in vars: assert s[0][var].simplify() == knownsolution[var].simplify() def test_lambert_multivariate(): from sympy.abc import x, y assert _filtered_gens(Poly(x + 1/x + exp(x) + y), x) == {x, exp(x)} assert _lambert(x, x) == [] assert solve((x**2 - 2*x + 1).subs(x, log(x) + 3*x)) == [LambertW(3*S.Exp1)/3] assert solve((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1)) == \ [LambertW(3*exp(-sqrt(2)))/3, LambertW(3*exp(sqrt(2)))/3] assert solve((x**2 - 2*x - 2).subs(x, log(x) + 3*x)) == \ [LambertW(3*exp(1 - sqrt(3)))/3, LambertW(3*exp(1 + sqrt(3)))/3] eq = (x*exp(x) - 3).subs(x, x*exp(x)) assert solve(eq) == [LambertW(3*exp(-LambertW(3)))] # coverage test raises(NotImplementedError, lambda: solve(x - sin(x)*log(y - x), x)) ans = [3, -3*LambertW(-log(3)/3)/log(3)] # 3 and 2.478... assert solve(x**3 - 3**x, x) == ans assert set(solve(3*log(x) - x*log(3))) == set(ans) assert solve(LambertW(2*x) - y, x) == [y*exp(y)/2] @XFAIL def test_other_lambert(): assert solve(3*sin(x) - x*sin(3), x) == [3] assert set(solve(x**a - a**x), x) == { a, -a*LambertW(-log(a)/a)/log(a)} @slow def test_lambert_bivariate(): # tests passing current implementation assert solve((x**2 + x)*exp(x**2 + x) - 1) == [ Rational(-1, 2) + sqrt(1 + 4*LambertW(1))/2, Rational(-1, 2) - sqrt(1 + 4*LambertW(1))/2] assert solve((x**2 + x)*exp((x**2 + x)*2) - 1) == [ Rational(-1, 2) + sqrt(1 + 2*LambertW(2))/2, Rational(-1, 2) - sqrt(1 + 2*LambertW(2))/2] assert solve(a/x + exp(x/2), x) == [2*LambertW(-a/2)] assert solve((a/x + exp(x/2)).diff(x), x) == \ [4*LambertW(-sqrt(2)*sqrt(a)/4), 4*LambertW(sqrt(2)*sqrt(a)/4)] assert solve((1/x + exp(x/2)).diff(x), x) == \ [4*LambertW(-sqrt(2)/4), 4*LambertW(sqrt(2)/4), # nsimplifies as 2*2**(141/299)*3**(206/299)*5**(205/299)*7**(37/299)/21 4*LambertW(-sqrt(2)/4, -1)] assert solve(x*log(x) + 3*x + 1, x) == \ [exp(-3 + LambertW(-exp(3)))] assert solve(-x**2 + 2**x, x) == [2, 4, -2*LambertW(log(2)/2)/log(2)] assert solve(x**2 - 2**x, x) == [2, 4, -2*LambertW(log(2)/2)/log(2)] ans = solve(3*x + 5 + 2**(-5*x + 3), x) assert len(ans) == 1 and ans[0].expand() == \ Rational(-5, 3) + LambertW(-10240*root(2, 3)*log(2)/3)/(5*log(2)) assert solve(5*x - 1 + 3*exp(2 - 7*x), x) == \ [Rational(1, 5) + LambertW(-21*exp(Rational(3, 5))/5)/7] assert solve((log(x) + x).subs(x, x**2 + 1)) == [ -I*sqrt(-LambertW(1) + 1), sqrt(-1 + LambertW(1))] # check collection ax = a**(3*x + 5) ans = solve(3*log(ax) + b*log(ax) + ax, x) x0 = 1/log(a) x1 = sqrt(3)*I x2 = b + 3 x3 = x2*LambertW(1/x2)/a**5 x4 = x3**Rational(1, 3)/2 assert ans == [ x0*log(x4*(x1 - 1)), x0*log(-x4*(x1 + 1)), x0*log(x3)/3] x1 = LambertW(Rational(1, 3)) x2 = a**(-5) x3 = 3**Rational(1, 3) x4 = 3**Rational(5, 6)*I x5 = x1**Rational(1, 3)*x2**Rational(1, 3)/2 ans = solve(3*log(ax) + ax, x) assert ans == [ x0*log(3*x1*x2)/3, x0*log(x5*(-x3 + x4)), x0*log(-x5*(x3 + x4))] # coverage p = symbols('p', positive=True) eq = 4*2**(2*p + 3) - 2*p - 3 assert _solve_lambert(eq, p, _filtered_gens(Poly(eq), p)) == [ Rational(-3, 2) - LambertW(-4*log(2))/(2*log(2))] assert set(solve(3**cos(x) - cos(x)**3)) == { acos(3), acos(-3*LambertW(-log(3)/3)/log(3))} # should give only one solution after using `uniq` assert solve(2*log(x) - 2*log(z) + log(z + log(x) + log(z)), x) == [ exp(-z + LambertW(2*z**4*exp(2*z))/2)/z] # cases when p != S.One # issue 4271 ans = solve((a/x + exp(x/2)).diff(x, 2), x) x0 = (-a)**Rational(1, 3) x1 = sqrt(3)*I x2 = x0/6 assert ans == [ 6*LambertW(x0/3), 6*LambertW(x2*(x1 - 1)), 6*LambertW(-x2*(x1 + 1))] assert solve((1/x + exp(x/2)).diff(x, 2), x) == \ [6*LambertW(Rational(-1, 3)), 6*LambertW(Rational(1, 6) - sqrt(3)*I/6), \ 6*LambertW(Rational(1, 6) + sqrt(3)*I/6), 6*LambertW(Rational(-1, 3), -1)] assert solve(x**2 - y**2/exp(x), x, y, dict=True) == \ [{x: 2*LambertW(-y/2)}, {x: 2*LambertW(y/2)}] # this is slow but not exceedingly slow assert solve((x**3)**(x/2) + pi/2, x) == [ exp(LambertW(-2*log(2)/3 + 2*log(pi)/3 + I*pi*Rational(2, 3)))] def test_rewrite_trig(): assert solve(sin(x) + tan(x)) == [0, -pi, pi, 2*pi] assert solve(sin(x) + sec(x)) == [ -2*atan(Rational(-1, 2) + sqrt(2)*sqrt(1 - sqrt(3)*I)/2 + sqrt(3)*I/2), 2*atan(S.Half - sqrt(2)*sqrt(1 + sqrt(3)*I)/2 + sqrt(3)*I/2), 2*atan(S.Half + sqrt(2)*sqrt(1 + sqrt(3)*I)/2 + sqrt(3)*I/2), 2*atan(S.Half - sqrt(3)*I/2 + sqrt(2)*sqrt(1 - sqrt(3)*I)/2)] assert solve(sinh(x) + tanh(x)) == [0, I*pi] # issue 6157 assert solve(2*sin(x) - cos(x), x) == [atan(S.Half)] @XFAIL def test_rewrite_trigh(): # if this import passes then the test below should also pass from sympy import sech assert solve(sinh(x) + sech(x)) == [ 2*atanh(Rational(-1, 2) + sqrt(5)/2 - sqrt(-2*sqrt(5) + 2)/2), 2*atanh(Rational(-1, 2) + sqrt(5)/2 + sqrt(-2*sqrt(5) + 2)/2), 2*atanh(-sqrt(5)/2 - S.Half + sqrt(2 + 2*sqrt(5))/2), 2*atanh(-sqrt(2 + 2*sqrt(5))/2 - sqrt(5)/2 - S.Half)] def test_uselogcombine(): eq = z - log(x) + log(y/(x*(-1 + y**2/x**2))) assert solve(eq, x, force=True) == [-sqrt(y*(y - exp(z))), sqrt(y*(y - exp(z)))] assert solve(log(x + 3) + log(1 + 3/x) - 3) in [ [-3 + sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 + exp(3)/2, -sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 - 3 + exp(3)/2], [-3 + sqrt(-36 + (-exp(3) + 6)**2)/2 + exp(3)/2, -3 - sqrt(-36 + (-exp(3) + 6)**2)/2 + exp(3)/2], ] assert solve(log(exp(2*x) + 1) + log(-tanh(x) + 1) - log(2)) == [] def test_atan2(): assert solve(atan2(x, 2) - pi/3, x) == [2*sqrt(3)] def test_errorinverses(): assert solve(erf(x) - y, x) == [erfinv(y)] assert solve(erfinv(x) - y, x) == [erf(y)] assert solve(erfc(x) - y, x) == [erfcinv(y)] assert solve(erfcinv(x) - y, x) == [erfc(y)] def test_issue_2725(): R = Symbol('R') eq = sqrt(2)*R*sqrt(1/(R + 1)) + (R + 1)*(sqrt(2)*sqrt(1/(R + 1)) - 1) sol = solve(eq, R, set=True)[1] assert sol == {(Rational(5, 3) + (Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3) + 40/(9*((Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3))),), (Rational(5, 3) + 40/(9*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)) + (Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3),)} def test_issue_5114_6611(): # See that it doesn't hang; this solves in about 2 seconds. # Also check that the solution is relatively small. # Note: the system in issue 6611 solves in about 5 seconds and has # an op-count of 138336 (with simplify=False). b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r = symbols('b:r') eqs = Matrix([ [b - c/d + r/d], [c*(1/g + 1/e + 1/d) - f/g - r/d], [-c/g + f*(1/j + 1/i + 1/g) - h/i], [-f/i + h*(1/m + 1/l + 1/i) - k/m], [-h/m + k*(1/p + 1/o + 1/m) - n/p], [-k/p + n*(1/q + 1/p)]]) v = Matrix([f, h, k, n, b, c]) ans = solve(list(eqs), list(v), simplify=False) # If time is taken to simplify then then 2617 below becomes # 1168 and the time is about 50 seconds instead of 2. assert sum([s.count_ops() for s in ans.values()]) <= 3270 def test_det_quick(): m = Matrix(3, 3, symbols('a:9')) assert m.det() == det_quick(m) # calls det_perm m[0, 0] = 1 assert m.det() == det_quick(m) # calls det_minor m = Matrix(3, 3, list(range(9))) assert m.det() == det_quick(m) # defaults to .det() # make sure they work with Sparse s = SparseMatrix(2, 2, (1, 2, 1, 4)) assert det_perm(s) == det_minor(s) == s.det() def test_real_imag_splitting(): a, b = symbols('a b', real=True) assert solve(sqrt(a**2 + b**2) - 3, a) == \ [-sqrt(-b**2 + 9), sqrt(-b**2 + 9)] a, b = symbols('a b', imaginary=True) assert solve(sqrt(a**2 + b**2) - 3, a) == [] def test_issue_7110(): y = -2*x**3 + 4*x**2 - 2*x + 5 assert any(ask(Q.real(i)) for i in solve(y)) def test_units(): assert solve(1/x - 1/(2*cm)) == [2*cm] def test_issue_7547(): A, B, V = symbols('A,B,V') eq1 = Eq(630.26*(V - 39.0)*V*(V + 39) - A + B, 0) eq2 = Eq(B, 1.36*10**8*(V - 39)) eq3 = Eq(A, 5.75*10**5*V*(V + 39.0)) sol = Matrix(nsolve(Tuple(eq1, eq2, eq3), [A, B, V], (0, 0, 0))) assert str(sol) == str(Matrix( [['4442890172.68209'], ['4289299466.1432'], ['70.5389666628177']])) def test_issue_7895(): r = symbols('r', real=True) assert solve(sqrt(r) - 2) == [4] def test_issue_2777(): # the equations represent two circles x, y = symbols('x y', real=True) e1, e2 = sqrt(x**2 + y**2) - 10, sqrt(y**2 + (-x + 10)**2) - 3 a, b = Rational(191, 20), 3*sqrt(391)/20 ans = [(a, -b), (a, b)] assert solve((e1, e2), (x, y)) == ans assert solve((e1, e2/(x - a)), (x, y)) == [] # make the 2nd circle's radius be -3 e2 += 6 assert solve((e1, e2), (x, y)) == [] assert solve((e1, e2), (x, y), check=False) == ans def test_issue_7322(): number = 5.62527e-35 assert solve(x - number, x)[0] == number def test_nsolve(): raises(ValueError, lambda: nsolve(x, (-1, 1), method='bisect')) raises(TypeError, lambda: nsolve((x - y + 3,x + y,z - y),(x,y,z),(-50,50))) raises(TypeError, lambda: nsolve((x + y, x - y), (0, 1))) @slow def test_high_order_multivariate(): assert len(solve(a*x**3 - x + 1, x)) == 3 assert len(solve(a*x**4 - x + 1, x)) == 4 assert solve(a*x**5 - x + 1, x) == [] # incomplete solution allowed raises(NotImplementedError, lambda: solve(a*x**5 - x + 1, x, incomplete=False)) # result checking must always consider the denominator and CRootOf # must be checked, too d = x**5 - x + 1 assert solve(d*(1 + 1/d)) == [CRootOf(d + 1, i) for i in range(5)] d = x - 1 assert solve(d*(2 + 1/d)) == [S.Half] def test_base_0_exp_0(): assert solve(0**x - 1) == [0] assert solve(0**(x - 2) - 1) == [2] assert solve(S('x*(1/x**0 - x)', evaluate=False)) == \ [0, 1] def test__simple_dens(): assert _simple_dens(1/x**0, [x]) == set() assert _simple_dens(1/x**y, [x]) == {x**y} assert _simple_dens(1/root(x, 3), [x]) == {x} def test_issue_8755(): # This tests two things: that if full unrad is attempted and fails # the solution should still be found; also it tests the use of # keyword `composite`. assert len(solve(sqrt(y)*x + x**3 - 1, x)) == 3 assert len(solve(-512*y**3 + 1344*(x + 2)**Rational(1, 3)*y**2 - 1176*(x + 2)**Rational(2, 3)*y - 169*x + 686, y, _unrad=False)) == 3 @slow def test_issue_8828(): x1 = 0 y1 = -620 r1 = 920 x2 = 126 y2 = 276 x3 = 51 y3 = 205 r3 = 104 v = x, y, z f1 = (x - x1)**2 + (y - y1)**2 - (r1 - z)**2 f2 = (x2 - x)**2 + (y2 - y)**2 - z**2 f3 = (x - x3)**2 + (y - y3)**2 - (r3 - z)**2 F = f1,f2,f3 g1 = sqrt((x - x1)**2 + (y - y1)**2) + z - r1 g2 = f2 g3 = sqrt((x - x3)**2 + (y - y3)**2) + z - r3 G = g1,g2,g3 A = solve(F, v) B = solve(G, v) C = solve(G, v, manual=True) p, q, r = [{tuple(i.evalf(2) for i in j) for j in R} for R in [A, B, C]] assert p == q == r @slow def test_issue_2840_8155(): assert solve(sin(3*x) + sin(6*x)) == [ 0, pi*Rational(-5, 3), pi*Rational(-4, 3), -pi, pi*Rational(-2, 3), pi*Rational(-4, 9), -pi/3, pi*Rational(-2, 9), pi*Rational(2, 9), pi/3, pi*Rational(4, 9), pi*Rational(2, 3), pi, pi*Rational(4, 3), pi*Rational(14, 9), pi*Rational(5, 3), pi*Rational(16, 9), 2*pi, -2*I*log(-(-1)**Rational(1, 9)), -2*I*log(-(-1)**Rational(2, 9)), -2*I*log(-sin(pi/18) - I*cos(pi/18)), -2*I*log(-sin(pi/18) + I*cos(pi/18)), -2*I*log(sin(pi/18) - I*cos(pi/18)), -2*I*log(sin(pi/18) + I*cos(pi/18))] assert solve(2*sin(x) - 2*sin(2*x)) == [ 0, pi*Rational(-5, 3), -pi, -pi/3, pi/3, pi, pi*Rational(5, 3)] def test_issue_9567(): assert solve(1 + 1/(x - 1)) == [0] def test_issue_11538(): assert solve(x + E) == [-E] assert solve(x**2 + E) == [-I*sqrt(E), I*sqrt(E)] assert solve(x**3 + 2*E) == [ -cbrt(2 * E), cbrt(2)*cbrt(E)/2 - cbrt(2)*sqrt(3)*I*cbrt(E)/2, cbrt(2)*cbrt(E)/2 + cbrt(2)*sqrt(3)*I*cbrt(E)/2] assert solve([x + 4, y + E], x, y) == {x: -4, y: -E} assert solve([x**2 + 4, y + E], x, y) == [ (-2*I, -E), (2*I, -E)] e1 = x - y**3 + 4 e2 = x + y + 4 + 4 * E assert len(solve([e1, e2], x, y)) == 3 @slow def test_issue_12114(): a, b, c, d, e, f, g = symbols('a,b,c,d,e,f,g') terms = [1 + a*b + d*e, 1 + a*c + d*f, 1 + b*c + e*f, g - a**2 - d**2, g - b**2 - e**2, g - c**2 - f**2] s = solve(terms, [a, b, c, d, e, f, g], dict=True) assert s == [{a: -sqrt(-f**2 - 1), b: -sqrt(-f**2 - 1), c: -sqrt(-f**2 - 1), d: f, e: f, g: -1}, {a: sqrt(-f**2 - 1), b: sqrt(-f**2 - 1), c: sqrt(-f**2 - 1), d: f, e: f, g: -1}, {a: -sqrt(3)*f/2 - sqrt(-f**2 + 2)/2, b: sqrt(3)*f/2 - sqrt(-f**2 + 2)/2, c: sqrt(-f**2 + 2), d: -f/2 + sqrt(-3*f**2 + 6)/2, e: -f/2 - sqrt(3)*sqrt(-f**2 + 2)/2, g: 2}, {a: -sqrt(3)*f/2 + sqrt(-f**2 + 2)/2, b: sqrt(3)*f/2 + sqrt(-f**2 + 2)/2, c: -sqrt(-f**2 + 2), d: -f/2 - sqrt(-3*f**2 + 6)/2, e: -f/2 + sqrt(3)*sqrt(-f**2 + 2)/2, g: 2}, {a: sqrt(3)*f/2 - sqrt(-f**2 + 2)/2, b: -sqrt(3)*f/2 - sqrt(-f**2 + 2)/2, c: sqrt(-f**2 + 2), d: -f/2 - sqrt(-3*f**2 + 6)/2, e: -f/2 + sqrt(3)*sqrt(-f**2 + 2)/2, g: 2}, {a: sqrt(3)*f/2 + sqrt(-f**2 + 2)/2, b: -sqrt(3)*f/2 + sqrt(-f**2 + 2)/2, c: -sqrt(-f**2 + 2), d: -f/2 + sqrt(-3*f**2 + 6)/2, e: -f/2 - sqrt(3)*sqrt(-f**2 + 2)/2, g: 2}] def test_inf(): assert solve(1 - oo*x) == [] assert solve(oo*x, x) == [] assert solve(oo*x - oo, x) == [] def test_issue_12448(): f = Function('f') fun = [f(i) for i in range(15)] sym = symbols('x:15') reps = dict(zip(fun, sym)) (x, y, z), c = sym[:3], sym[3:] ssym = solve([c[4*i]*x + c[4*i + 1]*y + c[4*i + 2]*z + c[4*i + 3] for i in range(3)], (x, y, z)) (x, y, z), c = fun[:3], fun[3:] sfun = solve([c[4*i]*x + c[4*i + 1]*y + c[4*i + 2]*z + c[4*i + 3] for i in range(3)], (x, y, z)) assert sfun[fun[0]].xreplace(reps).count_ops() == \ ssym[sym[0]].count_ops() def test_denoms(): assert denoms(x/2 + 1/y) == {2, y} assert denoms(x/2 + 1/y, y) == {y} assert denoms(x/2 + 1/y, [y]) == {y} assert denoms(1/x + 1/y + 1/z, [x, y]) == {x, y} assert denoms(1/x + 1/y + 1/z, x, y) == {x, y} assert denoms(1/x + 1/y + 1/z, {x, y}) == {x, y} def test_issue_12476(): x0, x1, x2, x3, x4, x5 = symbols('x0 x1 x2 x3 x4 x5') eqns = [x0**2 - x0, x0*x1 - x1, x0*x2 - x2, x0*x3 - x3, x0*x4 - x4, x0*x5 - x5, x0*x1 - x1, -x0/3 + x1**2 - 2*x2/3, x1*x2 - x1/3 - x2/3 - x3/3, x1*x3 - x2/3 - x3/3 - x4/3, x1*x4 - 2*x3/3 - x5/3, x1*x5 - x4, x0*x2 - x2, x1*x2 - x1/3 - x2/3 - x3/3, -x0/6 - x1/6 + x2**2 - x2/6 - x3/3 - x4/6, -x1/6 + x2*x3 - x2/3 - x3/6 - x4/6 - x5/6, x2*x4 - x2/3 - x3/3 - x4/3, x2*x5 - x3, x0*x3 - x3, x1*x3 - x2/3 - x3/3 - x4/3, -x1/6 + x2*x3 - x2/3 - x3/6 - x4/6 - x5/6, -x0/6 - x1/6 - x2/6 + x3**2 - x3/3 - x4/6, -x1/3 - x2/3 + x3*x4 - x3/3, -x2 + x3*x5, x0*x4 - x4, x1*x4 - 2*x3/3 - x5/3, x2*x4 - x2/3 - x3/3 - x4/3, -x1/3 - x2/3 + x3*x4 - x3/3, -x0/3 - 2*x2/3 + x4**2, -x1 + x4*x5, x0*x5 - x5, x1*x5 - x4, x2*x5 - x3, -x2 + x3*x5, -x1 + x4*x5, -x0 + x5**2, x0 - 1] sols = [{x0: 1, x3: Rational(1, 6), x2: Rational(1, 6), x4: Rational(-2, 3), x1: Rational(-2, 3), x5: 1}, {x0: 1, x3: S.Half, x2: Rational(-1, 2), x4: 0, x1: 0, x5: -1}, {x0: 1, x3: Rational(-1, 3), x2: Rational(-1, 3), x4: Rational(1, 3), x1: Rational(1, 3), x5: 1}, {x0: 1, x3: 1, x2: 1, x4: 1, x1: 1, x5: 1}, {x0: 1, x3: Rational(-1, 3), x2: Rational(1, 3), x4: sqrt(5)/3, x1: -sqrt(5)/3, x5: -1}, {x0: 1, x3: Rational(-1, 3), x2: Rational(1, 3), x4: -sqrt(5)/3, x1: sqrt(5)/3, x5: -1}] assert solve(eqns) == sols def test_issue_13849(): t = symbols('t') assert solve((t*(sqrt(5) + sqrt(2)) - sqrt(2), t), t) == [] def test_issue_14860(): from sympy.physics.units import newton, kilo assert solve(8*kilo*newton + x + y, x) == [-8000*newton - y] def test_issue_14721(): k, h, a, b = symbols(':4') assert solve([ -1 + (-k + 1)**2/b**2 + (-h - 1)**2/a**2, -1 + (-k + 1)**2/b**2 + (-h + 1)**2/a**2, h, k + 2], h, k, a, b) == [ (0, -2, -b*sqrt(1/(b**2 - 9)), b), (0, -2, b*sqrt(1/(b**2 - 9)), b)] assert solve([ h, h/a + 1/b**2 - 2, -h/2 + 1/b**2 - 2], a, h, b) == [ (a, 0, -sqrt(2)/2), (a, 0, sqrt(2)/2)] assert solve((a + b**2 - 1, a + b**2 - 2)) == [] def test_issue_14779(): x = symbols('x', real=True) assert solve(sqrt(x**4 - 130*x**2 + 1089) + sqrt(x**4 - 130*x**2 + 3969) - 96*Abs(x)/x,x) == [sqrt(130)] def test_issue_15307(): assert solve((y - 2, Mul(x + 3,x - 2, evaluate=False))) == \ [{x: -3, y: 2}, {x: 2, y: 2}] assert solve((y - 2, Mul(3, x - 2, evaluate=False))) == \ {x: 2, y: 2} assert solve((y - 2, Add(x + 4, x - 2, evaluate=False))) == \ {x: -1, y: 2} eq1 = Eq(12513*x + 2*y - 219093, -5726*x - y) eq2 = Eq(-2*x + 8, 2*x - 40) assert solve([eq1, eq2]) == {x:12, y:75} def test_issue_15415(): assert solve(x - 3, x) == [3] assert solve([x - 3], x) == {x:3} assert solve(Eq(y + 3*x**2/2, y + 3*x), y) == [] assert solve([Eq(y + 3*x**2/2, y + 3*x)], y) == [] assert solve([Eq(y + 3*x**2/2, y + 3*x), Eq(x, 1)], y) == [] @slow def test_issue_15731(): # f(x)**g(x)=c assert solve(Eq((x**2 - 7*x + 11)**(x**2 - 13*x + 42), 1)) == [2, 3, 4, 5, 6, 7] assert solve((x)**(x + 4) - 4) == [-2] assert solve((-x)**(-x + 4) - 4) == [2] assert solve((x**2 - 6)**(x**2 - 2) - 4) == [-2, 2] assert solve((x**2 - 2*x - 1)**(x**2 - 3) - 1/(1 - 2*sqrt(2))) == [sqrt(2)] assert solve(x**(x + S.Half) - 4*sqrt(2)) == [S(2)] assert solve((x**2 + 1)**x - 25) == [2] assert solve(x**(2/x) - 2) == [2, 4] assert solve((x/2)**(2/x) - sqrt(2)) == [4, 8] assert solve(x**(x + S.Half) - Rational(9, 4)) == [Rational(3, 2)] # a**g(x)=c assert solve((-sqrt(sqrt(2)))**x - 2) == [4, log(2)/(log(2**Rational(1, 4)) + I*pi)] assert solve((sqrt(2))**x - sqrt(sqrt(2))) == [S.Half] assert solve((-sqrt(2))**x + 2*(sqrt(2))) == [3, (3*log(2)**2 + 4*pi**2 - 4*I*pi*log(2))/(log(2)**2 + 4*pi**2)] assert solve((sqrt(2))**x - 2*(sqrt(2))) == [3] assert solve(I**x + 1) == [2] assert solve((1 + I)**x - 2*I) == [2] assert solve((sqrt(2) + sqrt(3))**x - (2*sqrt(6) + 5)**Rational(1, 3)) == [Rational(2, 3)] # bases of both sides are equal b = Symbol('b') assert solve(b**x - b**2, x) == [2] assert solve(b**x - 1/b, x) == [-1] assert solve(b**x - b, x) == [1] b = Symbol('b', positive=True) assert solve(b**x - b**2, x) == [2] assert solve(b**x - 1/b, x) == [-1] def test_issue_10933(): assert solve(x**4 + y*(x + 0.1), x) # doesn't fail assert solve(I*x**4 + x**3 + x**2 + 1.) # doesn't fail def test_Abs_handling(): x = symbols('x', real=True) assert solve(abs(x/y), x) == [0] def test_issue_7982(): x = Symbol('x') # Test that no exception happens assert solve([2*x**2 + 5*x + 20 <= 0, x >= 1.5], x) is S.false # From #8040 assert solve([x**3 - 8.08*x**2 - 56.48*x/5 - 106 >= 0, x - 1 <= 0], [x]) is S.false def test_issue_14645(): x, y = symbols('x y') assert solve([x*y - x - y, x*y - x - y], [x, y]) == [(y/(y - 1), y)] def test_issue_12024(): x, y = symbols('x y') assert solve(Piecewise((0.0, x < 0.1), (x, x >= 0.1)) - y) == \ [{y: Piecewise((0.0, x < 0.1), (x, True))}] def test_issue_17452(): assert solve((7**x)**x + pi, x) == [-sqrt(log(pi) + I*pi)/sqrt(log(7)), sqrt(log(pi) + I*pi)/sqrt(log(7))] assert solve(x**(x/11) + pi/11, x) == [exp(LambertW(-11*log(11) + 11*log(pi) + 11*I*pi))] def test_issue_17799(): assert solve(-erf(x**(S(1)/3))**pi + I, x) == [] def test_issue_17650(): x = Symbol('x', real=True) assert solve(abs(abs(x**2 - 1) - x) - x) == [1, -1 + sqrt(2), 1 + sqrt(2)] def test_issue_17882(): eq = -8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)) assert unrad(eq) is None def test_issue_17949(): assert solve(exp(+x+x**2), x) == [] assert solve(exp(-x+x**2), x) == [] assert solve(exp(+x-x**2), x) == [] assert solve(exp(-x-x**2), x) == [] def test_issue_10993(): assert solve(Eq(binomial(x, 2), 3)) == [-2, 3] assert solve(Eq(pow(x, 2) + binomial(x, 3), x)) == [-4, 0, 1] assert solve(Eq(binomial(x, 2), 0)) == [0, 1] assert solve(a+binomial(x, 3), a) == [-binomial(x, 3)] assert solve(x-binomial(a, 3) + binomial(y, 2) + sin(a), x) == [-sin(a) + binomial(a, 3) - binomial(y, 2)] assert solve((x+1)-binomial(x+1, 3), x) == [-2, -1, 3] def test_issue_11553(): eq1 = x + y + 1 eq2 = x + GoldenRatio assert solve([eq1, eq2], x, y) == {x: -GoldenRatio, y: -1 + GoldenRatio} eq3 = x + 2 + TribonacciConstant assert solve([eq1, eq3], x, y) == {x: -2 - TribonacciConstant, y: 1 + TribonacciConstant} def test_issue_19113_19102(): t = S(1)/3 solve(cos(x)**5-sin(x)**5) assert solve(4*cos(x)**3 - 2*sin(x)**3) == [ atan(2**(t)), -atan(2**(t)*(1 - sqrt(3)*I)/2), -atan(2**(t)*(1 + sqrt(3)*I)/2)] h = S.Half assert solve(cos(x)**2 + sin(x)) == [ 2*atan(-h + sqrt(5)/2 + sqrt(2)*sqrt(1 - sqrt(5))/2), -2*atan(h + sqrt(5)/2 + sqrt(2)*sqrt(1 + sqrt(5))/2), -2*atan(-sqrt(5)/2 + h + sqrt(2)*sqrt(1 - sqrt(5))/2), -2*atan(-sqrt(2)*sqrt(1 + sqrt(5))/2 + h + sqrt(5)/2)] assert solve(3*cos(x) - sin(x)) == [atan(3)] def test_issue_19509(): a = S(3)/4 b = S(5)/8 c = sqrt(5)/8 d = sqrt(5)/4 assert solve(1/(x -1)**5 - 1) == [2, -d + a - sqrt(-b + c), -d + a + sqrt(-b + c), d + a - sqrt(-b - c), d + a + sqrt(-b - c)] def test_issue_20747(): THT, HT, DBH, dib, c0, c1, c2, c3, c4 = symbols('THT HT DBH dib c0 c1 c2 c3 c4') f = DBH*c3 + THT*c4 + c2 rhs = 1 - ((HT - 1)/(THT - 1))**c1*(1 - exp(c0/f)) eq = dib - DBH*(c0 - f*log(rhs)) term = ((1 - exp((DBH*c0 - dib)/(DBH*(DBH*c3 + THT*c4 + c2)))) / (1 - exp(c0/(DBH*c3 + THT*c4 + c2)))) sol = [THT*term**(1/c1) - term**(1/c1) + 1] assert solve(eq, HT) == sol def test_issue_20902(): f = (t / ((1 + t) ** 2)) assert solve(f.subs({t: 3 * x + 2}).diff(x) > 0, x) == (S(-1) < x) & (x < S(-1)/3) assert solve(f.subs({t: 3 * x + 3}).diff(x) > 0, x) == (S(-4)/3 < x) & (x < S(-2)/3) assert solve(f.subs({t: 3 * x + 4}).diff(x) > 0, x) == (S(-5)/3 < x) & (x < S(-1)) assert solve(f.subs({t: 3 * x + 2}).diff(x) > 0, x) == (S(-1) < x) & (x < S(-1)/3) def test_issue_21034(): a = symbols('a', real=True) system = [x - cosh(cos(4)), y - sinh(cos(a)), z - tanh(x)] assert solve(system, x, y, z) == {x: cosh(cos(4)), z: tanh(cosh(cos(4))), y: sinh(cos(a))} #Constants inside hyperbolic functions should not be rewritten in terms of exp newsystem = [(exp(x) - exp(-x)) - tanh(x)*(exp(x) + exp(-x)) + x - 5] assert solve(newsystem, x) == {x: 5} #If the variable of interest is present in hyperbolic function, only then # it shouuld be rewritten in terms of exp and solved further def test_issue_4886(): z = a*sqrt(R**2*a**2 + R**2*b**2 - c**2)/(a**2 + b**2) t = b*c/(a**2 + b**2) sol = [((b*(t - z) - c)/(-a), t - z), ((b*(t + z) - c)/(-a), t + z)] assert solve([x**2 + y**2 - R**2, a*x + b*y - c], x, y) == sol def test_issue_6819(): a, b, c, d = symbols('a b c d', positive=True) assert solve(a*b**x - c*d**x, x) == [log(c/a)/log(b/d)] def test_issue_21852(): solution = [21 - 21*sqrt(2)/2] assert solve(2*x + sqrt(2*x**2) - 21) == solution def test_issue_21942(): eq = -d + (a*c**(1 - e) + b**(1 - e)*(1 - a))**(1/(1 - e)) sol = solve(eq, c, simplify=False, check=False) assert sol == [(b/b**e - b/(a*b**e) + d**(1 - e)/a)**(1/(1 - e))] sympy-sympy-1.9/sympy/solvers/tests/test_solveset.py000066400000000000000000003455131412543434000232330ustar00rootroot00000000000000from sympy.core.containers import Tuple from sympy.core.compatibility import ordered from sympy.core.function import (Function, Lambda, nfloat, diff) from sympy.core.mod import Mod from sympy.core.numbers import (E, I, Rational, oo, pi, Integer) from sympy.core.relational import (Eq, Gt, Ne, Ge) from sympy.core.singleton import S from sympy.core.symbol import (Dummy, Symbol, symbols) from sympy.functions.elementary.complexes import (Abs, arg, im, re, sign) from sympy.functions.elementary.exponential import (LambertW, exp, log) from sympy.functions.elementary.hyperbolic import (HyperbolicFunction, sinh, tanh, cosh, sech, coth) from sympy.functions.elementary.miscellaneous import sqrt, Min, Max from sympy.functions.elementary.piecewise import Piecewise from sympy.functions.elementary.trigonometric import ( TrigonometricFunction, acos, acot, acsc, asec, asin, atan, atan2, cos, cot, csc, sec, sin, tan) from sympy.functions.special.error_functions import (erf, erfc, erfcinv, erfinv) from sympy.logic.boolalg import And from sympy.matrices.dense import MutableDenseMatrix as Matrix from sympy.matrices.immutable import ImmutableDenseMatrix from sympy.polys.polytools import Poly from sympy.polys.rootoftools import CRootOf from sympy.sets.contains import Contains from sympy.sets.conditionset import ConditionSet from sympy.sets.fancysets import ImageSet, Range from sympy.sets.sets import (Complement, EmptySet, FiniteSet, Intersection, Interval, Union, imageset, ProductSet) from sympy.simplify import simplify from sympy.tensor.indexed import Indexed from sympy.utilities.iterables import numbered_symbols from sympy.testing.pytest import (XFAIL, raises, skip, slow, SKIP, _both_exp_pow) from sympy.testing.randtest import verify_numerically as tn from sympy.physics.units import cm from sympy.solvers import solve from sympy.solvers.solveset import ( solveset_real, domain_check, solveset_complex, linear_eq_to_matrix, linsolve, _is_function_class_equation, invert_real, invert_complex, solveset, solve_decomposition, substitution, nonlinsolve, solvify, _is_finite_with_finite_vars, _transolve, _is_exponential, _solve_exponential, _is_logarithmic, _is_lambert, _solve_logarithm, _term_factors, _is_modular, NonlinearError) from sympy.abc import (a, b, c, d, e, f, g, h, i, j, k, l, m, n, q, r, t, w, x, y, z) def dumeq(i, j): if type(i) in (list, tuple): return all(dumeq(i, j) for i, j in zip(i, j)) return i == j or i.dummy_eq(j) @_both_exp_pow def test_invert_real(): x = Symbol('x', real=True) def ireal(x, s=S.Reals): return Intersection(s, x) # issue 14223 assert invert_real(x, 0, x, Interval(1, 2)) == (x, S.EmptySet) assert invert_real(exp(x), z, x) == (x, ireal(FiniteSet(log(z)))) y = Symbol('y', positive=True) n = Symbol('n', real=True) assert invert_real(x + 3, y, x) == (x, FiniteSet(y - 3)) assert invert_real(x*3, y, x) == (x, FiniteSet(y / 3)) assert invert_real(exp(x), y, x) == (x, FiniteSet(log(y))) assert invert_real(exp(3*x), y, x) == (x, FiniteSet(log(y) / 3)) assert invert_real(exp(x + 3), y, x) == (x, FiniteSet(log(y) - 3)) assert invert_real(exp(x) + 3, y, x) == (x, ireal(FiniteSet(log(y - 3)))) assert invert_real(exp(x)*3, y, x) == (x, FiniteSet(log(y / 3))) assert invert_real(log(x), y, x) == (x, FiniteSet(exp(y))) assert invert_real(log(3*x), y, x) == (x, FiniteSet(exp(y) / 3)) assert invert_real(log(x + 3), y, x) == (x, FiniteSet(exp(y) - 3)) assert invert_real(Abs(x), y, x) == (x, FiniteSet(y, -y)) assert invert_real(2**x, y, x) == (x, FiniteSet(log(y)/log(2))) assert invert_real(2**exp(x), y, x) == (x, ireal(FiniteSet(log(log(y)/log(2))))) assert invert_real(x**2, y, x) == (x, FiniteSet(sqrt(y), -sqrt(y))) assert invert_real(x**S.Half, y, x) == (x, FiniteSet(y**2)) raises(ValueError, lambda: invert_real(x, x, x)) # issue 21236 assert invert_real(x**pi, y, x) == (x, FiniteSet(y**(1/pi))) assert invert_real(x**pi, -E, x) == (x, EmptySet()) assert invert_real(x**Rational(3/2), 1000, x) == (x, FiniteSet(100)) assert invert_real(x**1.0, 1, x) == (x**1.0, FiniteSet(1)) raises(ValueError, lambda: invert_real(S.One, y, x)) assert invert_real(x**31 + x, y, x) == (x**31 + x, FiniteSet(y)) lhs = x**31 + x base_values = FiniteSet(y - 1, -y - 1) assert invert_real(Abs(x**31 + x + 1), y, x) == (lhs, base_values) assert dumeq(invert_real(sin(x), y, x), (x, imageset(Lambda(n, n*pi + (-1)**n*asin(y)), S.Integers))) assert dumeq(invert_real(sin(exp(x)), y, x), (x, imageset(Lambda(n, log((-1)**n*asin(y) + n*pi)), S.Integers))) assert dumeq(invert_real(csc(x), y, x), (x, imageset(Lambda(n, n*pi + (-1)**n*acsc(y)), S.Integers))) assert dumeq(invert_real(csc(exp(x)), y, x), (x, imageset(Lambda(n, log((-1)**n*acsc(y) + n*pi)), S.Integers))) assert dumeq(invert_real(cos(x), y, x), (x, Union(imageset(Lambda(n, 2*n*pi + acos(y)), S.Integers), \ imageset(Lambda(n, 2*n*pi - acos(y)), S.Integers)))) assert dumeq(invert_real(cos(exp(x)), y, x), (x, Union(imageset(Lambda(n, log(2*n*pi + acos(y))), S.Integers), \ imageset(Lambda(n, log(2*n*pi - acos(y))), S.Integers)))) assert dumeq(invert_real(sec(x), y, x), (x, Union(imageset(Lambda(n, 2*n*pi + asec(y)), S.Integers), \ imageset(Lambda(n, 2*n*pi - asec(y)), S.Integers)))) assert dumeq(invert_real(sec(exp(x)), y, x), (x, Union(imageset(Lambda(n, log(2*n*pi + asec(y))), S.Integers), \ imageset(Lambda(n, log(2*n*pi - asec(y))), S.Integers)))) assert dumeq(invert_real(tan(x), y, x), (x, imageset(Lambda(n, n*pi + atan(y)), S.Integers))) assert dumeq(invert_real(tan(exp(x)), y, x), (x, imageset(Lambda(n, log(n*pi + atan(y))), S.Integers))) assert dumeq(invert_real(cot(x), y, x), (x, imageset(Lambda(n, n*pi + acot(y)), S.Integers))) assert dumeq(invert_real(cot(exp(x)), y, x), (x, imageset(Lambda(n, log(n*pi + acot(y))), S.Integers))) assert dumeq(invert_real(tan(tan(x)), y, x), (tan(x), imageset(Lambda(n, n*pi + atan(y)), S.Integers))) x = Symbol('x', positive=True) assert invert_real(x**pi, y, x) == (x, FiniteSet(y**(1/pi))) def test_invert_complex(): assert invert_complex(x + 3, y, x) == (x, FiniteSet(y - 3)) assert invert_complex(x*3, y, x) == (x, FiniteSet(y / 3)) assert invert_complex((x - 1)**3, 0, x) == (x, FiniteSet(1)) assert dumeq(invert_complex(exp(x), y, x), (x, imageset(Lambda(n, I*(2*pi*n + arg(y)) + log(Abs(y))), S.Integers))) assert invert_complex(log(x), y, x) == (x, FiniteSet(exp(y))) raises(ValueError, lambda: invert_real(1, y, x)) raises(ValueError, lambda: invert_complex(x, x, x)) raises(ValueError, lambda: invert_complex(x, x, 1)) # https://github.com/skirpichev/omg/issues/16 assert invert_complex(sinh(x), 0, x) != (x, FiniteSet(0)) def test_domain_check(): assert domain_check(1/(1 + (1/(x+1))**2), x, -1) is False assert domain_check(x**2, x, 0) is True assert domain_check(x, x, oo) is False assert domain_check(0, x, oo) is False def test_issue_11536(): assert solveset(0**x - 100, x, S.Reals) == S.EmptySet assert solveset(0**x - 1, x, S.Reals) == FiniteSet(0) def test_issue_17479(): from sympy.solvers.solveset import nonlinsolve f = (x**2 + y**2)**2 + (x**2 + z**2)**2 - 2*(2*x**2 + y**2 + z**2) fx = f.diff(x) fy = f.diff(y) fz = f.diff(z) sol = nonlinsolve([fx, fy, fz], [x, y, z]) assert len(sol) >= 4 and len(sol) <= 20 # nonlinsolve has been giving a varying number of solutions # (originally 18, then 20, now 19) due to various internal changes. # Unfortunately not all the solutions are actually valid and some are # redundant. Since the original issue was that an exception was raised, # this first test only checks that nonlinsolve returns a "plausible" # solution set. The next test checks the result for correctness. @XFAIL def test_issue_18449(): x, y, z = symbols("x, y, z") f = (x**2 + y**2)**2 + (x**2 + z**2)**2 - 2*(2*x**2 + y**2 + z**2) fx = diff(f, x) fy = diff(f, y) fz = diff(f, z) sol = nonlinsolve([fx, fy, fz], [x, y, z]) for (xs, ys, zs) in sol: d = {x: xs, y: ys, z: zs} assert tuple(_.subs(d).simplify() for _ in (fx, fy, fz)) == (0, 0, 0) # After simplification and removal of duplicate elements, there should # only be 4 parametric solutions left: # simplifiedsolutions = FiniteSet((sqrt(1 - z**2), z, z), # (-sqrt(1 - z**2), z, z), # (sqrt(1 - z**2), -z, z), # (-sqrt(1 - z**2), -z, z)) # TODO: Is the above solution set definitely complete? def test_issue_21047(): f = (2 - x)**2 + (sqrt(x - 1) - 1)**6 assert(solveset(f, x, S.Reals)) == FiniteSet(2) f = (sqrt(x)-1)**2 + (sqrt(x)+1)**2 -2*x**2 + sqrt(2) assert solveset(f, x, S.Reals) == FiniteSet( S.Half - sqrt(2*sqrt(2) + 5)/2, S.Half + sqrt(2*sqrt(2) + 5)/2) def test_is_function_class_equation(): from sympy.abc import x, a assert _is_function_class_equation(TrigonometricFunction, tan(x), x) is True assert _is_function_class_equation(TrigonometricFunction, tan(x) - 1, x) is True assert _is_function_class_equation(TrigonometricFunction, tan(x) + sin(x), x) is True assert _is_function_class_equation(TrigonometricFunction, tan(x) + sin(x) - a, x) is True assert _is_function_class_equation(TrigonometricFunction, sin(x)*tan(x) + sin(x), x) is True assert _is_function_class_equation(TrigonometricFunction, sin(x)*tan(x + a) + sin(x), x) is True assert _is_function_class_equation(TrigonometricFunction, sin(x)*tan(x*a) + sin(x), x) is True assert _is_function_class_equation(TrigonometricFunction, a*tan(x) - 1, x) is True assert _is_function_class_equation(TrigonometricFunction, tan(x)**2 + sin(x) - 1, x) is True assert _is_function_class_equation(TrigonometricFunction, tan(x) + x, x) is False assert _is_function_class_equation(TrigonometricFunction, tan(x**2), x) is False assert _is_function_class_equation(TrigonometricFunction, tan(x**2) + sin(x), x) is False assert _is_function_class_equation(TrigonometricFunction, tan(x)**sin(x), x) is False assert _is_function_class_equation(TrigonometricFunction, tan(sin(x)) + sin(x), x) is False assert _is_function_class_equation(HyperbolicFunction, tanh(x), x) is True assert _is_function_class_equation(HyperbolicFunction, tanh(x) - 1, x) is True assert _is_function_class_equation(HyperbolicFunction, tanh(x) + sinh(x), x) is True assert _is_function_class_equation(HyperbolicFunction, tanh(x) + sinh(x) - a, x) is True assert _is_function_class_equation(HyperbolicFunction, sinh(x)*tanh(x) + sinh(x), x) is True assert _is_function_class_equation(HyperbolicFunction, sinh(x)*tanh(x + a) + sinh(x), x) is True assert _is_function_class_equation(HyperbolicFunction, sinh(x)*tanh(x*a) + sinh(x), x) is True assert _is_function_class_equation(HyperbolicFunction, a*tanh(x) - 1, x) is True assert _is_function_class_equation(HyperbolicFunction, tanh(x)**2 + sinh(x) - 1, x) is True assert _is_function_class_equation(HyperbolicFunction, tanh(x) + x, x) is False assert _is_function_class_equation(HyperbolicFunction, tanh(x**2), x) is False assert _is_function_class_equation(HyperbolicFunction, tanh(x**2) + sinh(x), x) is False assert _is_function_class_equation(HyperbolicFunction, tanh(x)**sinh(x), x) is False assert _is_function_class_equation(HyperbolicFunction, tanh(sinh(x)) + sinh(x), x) is False def test_garbage_input(): raises(ValueError, lambda: solveset_real([y], y)) x = Symbol('x', real=True) assert solveset_real(x, 1) == S.EmptySet assert solveset_real(x - 1, 1) == FiniteSet(x) assert solveset_real(x, pi) == S.EmptySet assert solveset_real(x, x**2) == S.EmptySet raises(ValueError, lambda: solveset_complex([x], x)) assert solveset_complex(x, pi) == S.EmptySet raises(ValueError, lambda: solveset((x, y), x)) raises(ValueError, lambda: solveset(x + 1, S.Reals)) raises(ValueError, lambda: solveset(x + 1, x, 2)) def test_solve_mul(): assert solveset_real((a*x + b)*(exp(x) - 3), x) == \ Union({log(3)}, Intersection({-b/a}, S.Reals)) anz = Symbol('anz', nonzero=True) bb = Symbol('bb', real=True) assert solveset_real((anz*x + bb)*(exp(x) - 3), x) == \ FiniteSet(-bb/anz, log(3)) assert solveset_real((2*x + 8)*(8 + exp(x)), x) == FiniteSet(S(-4)) assert solveset_real(x/log(x), x) == EmptySet() def test_solve_invert(): assert solveset_real(exp(x) - 3, x) == FiniteSet(log(3)) assert solveset_real(log(x) - 3, x) == FiniteSet(exp(3)) assert solveset_real(3**(x + 2), x) == FiniteSet() assert solveset_real(3**(2 - x), x) == FiniteSet() assert solveset_real(y - b*exp(a/x), x) == Intersection( S.Reals, FiniteSet(a/log(y/b))) # issue 4504 assert solveset_real(2**x - 10, x) == FiniteSet(1 + log(5)/log(2)) def test_errorinverses(): assert solveset_real(erf(x) - S.Half, x) == \ FiniteSet(erfinv(S.Half)) assert solveset_real(erfinv(x) - 2, x) == \ FiniteSet(erf(2)) assert solveset_real(erfc(x) - S.One, x) == \ FiniteSet(erfcinv(S.One)) assert solveset_real(erfcinv(x) - 2, x) == FiniteSet(erfc(2)) def test_solve_polynomial(): x = Symbol('x', real=True) y = Symbol('y', real=True) assert solveset_real(3*x - 2, x) == FiniteSet(Rational(2, 3)) assert solveset_real(x**2 - 1, x) == FiniteSet(-S.One, S.One) assert solveset_real(x - y**3, x) == FiniteSet(y ** 3) a11, a12, a21, a22, b1, b2 = symbols('a11, a12, a21, a22, b1, b2') assert solveset_real(x**3 - 15*x - 4, x) == FiniteSet( -2 + 3 ** S.Half, S(4), -2 - 3 ** S.Half) assert solveset_real(sqrt(x) - 1, x) == FiniteSet(1) assert solveset_real(sqrt(x) - 2, x) == FiniteSet(4) assert solveset_real(x**Rational(1, 4) - 2, x) == FiniteSet(16) assert solveset_real(x**Rational(1, 3) - 3, x) == FiniteSet(27) assert len(solveset_real(x**5 + x**3 + 1, x)) == 1 assert len(solveset_real(-2*x**3 + 4*x**2 - 2*x + 6, x)) > 0 assert solveset_real(x**6 + x**4 + I, x) is S.EmptySet def test_return_root_of(): f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 s = list(solveset_complex(f, x)) for root in s: assert root.func == CRootOf # if one uses solve to get the roots of a polynomial that has a CRootOf # solution, make sure that the use of nfloat during the solve process # doesn't fail. Note: if you want numerical solutions to a polynomial # it is *much* faster to use nroots to get them than to solve the # equation only to get CRootOf solutions which are then numerically # evaluated. So for eq = x**5 + 3*x + 7 do Poly(eq).nroots() rather # than [i.n() for i in solve(eq)] to get the numerical roots of eq. assert nfloat(list(solveset_complex(x**5 + 3*x**3 + 7, x))[0], exponent=False) == CRootOf(x**5 + 3*x**3 + 7, 0).n() sol = list(solveset_complex(x**6 - 2*x + 2, x)) assert all(isinstance(i, CRootOf) for i in sol) and len(sol) == 6 f = x**5 - 15*x**3 - 5*x**2 + 10*x + 20 s = list(solveset_complex(f, x)) for root in s: assert root.func == CRootOf s = x**5 + 4*x**3 + 3*x**2 + Rational(7, 4) assert solveset_complex(s, x) == \ FiniteSet(*Poly(s*4, domain='ZZ').all_roots()) # Refer issue #7876 eq = x*(x - 1)**2*(x + 1)*(x**6 - x + 1) assert solveset_complex(eq, x) == \ FiniteSet(-1, 0, 1, CRootOf(x**6 - x + 1, 0), CRootOf(x**6 - x + 1, 1), CRootOf(x**6 - x + 1, 2), CRootOf(x**6 - x + 1, 3), CRootOf(x**6 - x + 1, 4), CRootOf(x**6 - x + 1, 5)) def test_solveset_sqrt_1(): assert solveset_real(sqrt(5*x + 6) - 2 - x, x) == \ FiniteSet(-S.One, S(2)) assert solveset_real(sqrt(x - 1) - x + 7, x) == FiniteSet(10) assert solveset_real(sqrt(x - 2) - 5, x) == FiniteSet(27) assert solveset_real(sqrt(x) - 2 - 5, x) == FiniteSet(49) assert solveset_real(sqrt(x**3), x) == FiniteSet(0) assert solveset_real(sqrt(x - 1), x) == FiniteSet(1) def test_solveset_sqrt_2(): x = Symbol('x', real=True) y = Symbol('y', real=True) # http://tutorial.math.lamar.edu/Classes/Alg/SolveRadicalEqns.aspx#Solve_Rad_Ex2_a assert solveset_real(sqrt(2*x - 1) - sqrt(x - 4) - 2, x) == \ FiniteSet(S(5), S(13)) assert solveset_real(sqrt(x + 7) + 2 - sqrt(3 - x), x) == \ FiniteSet(-6) # http://www.purplemath.com/modules/solverad.htm assert solveset_real(sqrt(17*x - sqrt(x**2 - 5)) - 7, x) == \ FiniteSet(3) eq = x + 1 - (x**4 + 4*x**3 - x)**Rational(1, 4) assert solveset_real(eq, x) == FiniteSet(Rational(-1, 2), Rational(-1, 3)) eq = sqrt(2*x + 9) - sqrt(x + 1) - sqrt(x + 4) assert solveset_real(eq, x) == FiniteSet(0) eq = sqrt(x + 4) + sqrt(2*x - 1) - 3*sqrt(x - 1) assert solveset_real(eq, x) == FiniteSet(5) eq = sqrt(x)*sqrt(x - 7) - 12 assert solveset_real(eq, x) == FiniteSet(16) eq = sqrt(x - 3) + sqrt(x) - 3 assert solveset_real(eq, x) == FiniteSet(4) eq = sqrt(2*x**2 - 7) - (3 - x) assert solveset_real(eq, x) == FiniteSet(-S(8), S(2)) # others eq = sqrt(9*x**2 + 4) - (3*x + 2) assert solveset_real(eq, x) == FiniteSet(0) assert solveset_real(sqrt(x - 3) - sqrt(x) - 3, x) == FiniteSet() eq = (2*x - 5)**Rational(1, 3) - 3 assert solveset_real(eq, x) == FiniteSet(16) assert solveset_real(sqrt(x) + sqrt(sqrt(x)) - 4, x) == \ FiniteSet((Rational(-1, 2) + sqrt(17)/2)**4) eq = sqrt(x) - sqrt(x - 1) + sqrt(sqrt(x)) assert solveset_real(eq, x) == FiniteSet() eq = (x - 4)**2 + (sqrt(x) - 2)**4 assert solveset_real(eq, x) == FiniteSet(-4, 4) eq = (sqrt(x) + sqrt(x + 1) + sqrt(1 - x) - 6*sqrt(5)/5) ans = solveset_real(eq, x) ra = S('''-1484/375 - 4*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3) - 172564/(140625*(-1/2 + sqrt(3)*I/2)*(-12459439/52734375 + 114*sqrt(12657)/78125)**(1/3))''') rb = Rational(4, 5) assert all(abs(eq.subs(x, i).n()) < 1e-10 for i in (ra, rb)) and \ len(ans) == 2 and \ {i.n(chop=True) for i in ans} == \ {i.n(chop=True) for i in (ra, rb)} assert solveset_real(sqrt(x) + x**Rational(1, 3) + x**Rational(1, 4), x) == FiniteSet(0) assert solveset_real(x/sqrt(x**2 + 1), x) == FiniteSet(0) eq = (x - y**3)/((y**2)*sqrt(1 - y**2)) assert solveset_real(eq, x) == FiniteSet(y**3) # issue 4497 assert solveset_real(1/(5 + x)**Rational(1, 5) - 9, x) == \ FiniteSet(Rational(-295244, 59049)) @XFAIL def test_solve_sqrt_fail(): # this only works if we check real_root(eq.subs(x, Rational(1, 3))) # but checksol doesn't work like that eq = (x**3 - 3*x**2)**Rational(1, 3) + 1 - x assert solveset_real(eq, x) == FiniteSet(Rational(1, 3)) @slow def test_solve_sqrt_3(): R = Symbol('R') eq = sqrt(2)*R*sqrt(1/(R + 1)) + (R + 1)*(sqrt(2)*sqrt(1/(R + 1)) - 1) sol = solveset_complex(eq, R) fset = [Rational(5, 3) + 4*sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3, -sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3 + 40*re(1/((Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9 + sqrt(30)*sin(atan(3*sqrt(111)/251)/3)/3 + Rational(5, 3) + I*(-sqrt(30)*cos(atan(3*sqrt(111)/251)/3)/3 - sqrt(10)*sin(atan(3*sqrt(111)/251)/3)/3 + 40*im(1/((Rational(-1, 2) - sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9)] cset = [40*re(1/((Rational(-1, 2) + sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9 - sqrt(10)*cos(atan(3*sqrt(111)/251)/3)/3 - sqrt(30)*sin(atan(3*sqrt(111)/251)/3)/3 + Rational(5, 3) + I*(40*im(1/((Rational(-1, 2) + sqrt(3)*I/2)*(Rational(251, 27) + sqrt(111)*I/9)**Rational(1, 3)))/9 - sqrt(10)*sin(atan(3*sqrt(111)/251)/3)/3 + sqrt(30)*cos(atan(3*sqrt(111)/251)/3)/3)] assert sol._args[0] == FiniteSet(*fset) assert sol._args[1] == ConditionSet( R, Eq(sqrt(2)*R*sqrt(1/(R + 1)) + (R + 1)*(sqrt(2)*sqrt(1/(R + 1)) - 1), 0), FiniteSet(*cset)) # the number of real roots will depend on the value of m: for m=1 there are 4 # and for m=-1 there are none. eq = -sqrt((m - q)**2 + (-m/(2*q) + S.Half)**2) + sqrt((-m**2/2 - sqrt( 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2 + (m**2/2 - m - sqrt( 4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2) unsolved_object = ConditionSet(q, Eq(sqrt((m - q)**2 + (-m/(2*q) + S.Half)**2) - sqrt((-m**2/2 - sqrt(4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2 + (m**2/2 - m - sqrt(4*m**4 - 4*m**2 + 8*m + 1)/4 - Rational(1, 4))**2), 0), S.Reals) assert solveset_real(eq, q) == unsolved_object def test_solve_polynomial_symbolic_param(): assert solveset_complex((x**2 - 1)**2 - a, x) == \ FiniteSet(sqrt(1 + sqrt(a)), -sqrt(1 + sqrt(a)), sqrt(1 - sqrt(a)), -sqrt(1 - sqrt(a))) # issue 4507 assert solveset_complex(y - b/(1 + a*x), x) == \ FiniteSet((b/y - 1)/a) - FiniteSet(-1/a) # issue 4508 assert solveset_complex(y - b*x/(a + x), x) == \ FiniteSet(-a*y/(y - b)) - FiniteSet(-a) def test_solve_rational(): assert solveset_real(1/x + 1, x) == FiniteSet(-S.One) assert solveset_real(1/exp(x) - 1, x) == FiniteSet(0) assert solveset_real(x*(1 - 5/x), x) == FiniteSet(5) assert solveset_real(2*x/(x + 2) - 1, x) == FiniteSet(2) assert solveset_real((x**2/(7 - x)).diff(x), x) == \ FiniteSet(S.Zero, S(14)) def test_solveset_real_gen_is_pow(): assert solveset_real(sqrt(1) + 1, x) == EmptySet() def test_no_sol(): assert solveset(1 - oo*x) == EmptySet() assert solveset(oo*x, x) == EmptySet() assert solveset(oo*x - oo, x) == EmptySet() assert solveset_real(4, x) == EmptySet() assert solveset_real(exp(x), x) == EmptySet() assert solveset_real(x**2 + 1, x) == EmptySet() assert solveset_real(-3*a/sqrt(x), x) == EmptySet() assert solveset_real(1/x, x) == EmptySet() assert solveset_real(-(1 + x)/(2 + x)**2 + 1/(2 + x), x) == \ EmptySet() def test_sol_zero_real(): assert solveset_real(0, x) == S.Reals assert solveset(0, x, Interval(1, 2)) == Interval(1, 2) assert solveset_real(-x**2 - 2*x + (x + 1)**2 - 1, x) == S.Reals def test_no_sol_rational_extragenous(): assert solveset_real((x/(x + 1) + 3)**(-2), x) == EmptySet() assert solveset_real((x - 1)/(1 + 1/(x - 1)), x) == EmptySet() def test_solve_polynomial_cv_1a(): """ Test for solving on equations that can be converted to a polynomial equation using the change of variable y -> x**Rational(p, q) """ assert solveset_real(sqrt(x) - 1, x) == FiniteSet(1) assert solveset_real(sqrt(x) - 2, x) == FiniteSet(4) assert solveset_real(x**Rational(1, 4) - 2, x) == FiniteSet(16) assert solveset_real(x**Rational(1, 3) - 3, x) == FiniteSet(27) assert solveset_real(x*(x**(S.One / 3) - 3), x) == \ FiniteSet(S.Zero, S(27)) def test_solveset_real_rational(): """Test solveset_real for rational functions""" x = Symbol('x', real=True) y = Symbol('y', real=True) assert solveset_real((x - y**3) / ((y**2)*sqrt(1 - y**2)), x) \ == FiniteSet(y**3) # issue 4486 assert solveset_real(2*x/(x + 2) - 1, x) == FiniteSet(2) def test_solveset_real_log(): assert solveset_real(log((x-1)*(x+1)), x) == \ FiniteSet(sqrt(2), -sqrt(2)) def test_poly_gens(): assert solveset_real(4**(2*(x**2) + 2*x) - 8, x) == \ FiniteSet(Rational(-3, 2), S.Half) def test_solve_abs(): n = Dummy('n') raises(ValueError, lambda: solveset(Abs(x) - 1, x)) assert solveset(Abs(x) - n, x, S.Reals).dummy_eq( ConditionSet(x, Contains(n, Interval(0, oo)), {-n, n})) assert solveset_real(Abs(x) - 2, x) == FiniteSet(-2, 2) assert solveset_real(Abs(x) + 2, x) is S.EmptySet assert solveset_real(Abs(x + 3) - 2*Abs(x - 3), x) == \ FiniteSet(1, 9) assert solveset_real(2*Abs(x) - Abs(x - 1), x) == \ FiniteSet(-1, Rational(1, 3)) sol = ConditionSet( x, And( Contains(b, Interval(0, oo)), Contains(a + b, Interval(0, oo)), Contains(a - b, Interval(0, oo))), FiniteSet(-a - b - 3, -a + b - 3, a - b - 3, a + b - 3)) eq = Abs(Abs(x + 3) - a) - b assert invert_real(eq, 0, x)[1] == sol reps = {a: 3, b: 1} eqab = eq.subs(reps) for si in sol.subs(reps): assert not eqab.subs(x, si) assert dumeq(solveset(Eq(sin(Abs(x)), 1), x, domain=S.Reals), Union( Intersection(Interval(0, oo), ImageSet(Lambda(n, (-1)**n*pi/2 + n*pi), S.Integers)), Intersection(Interval(-oo, 0), ImageSet(Lambda(n, n*pi - (-1)**(-n)*pi/2), S.Integers)))) def test_issue_9824(): assert dumeq(solveset(sin(x)**2 - 2*sin(x) + 1, x), ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers)) assert dumeq(solveset(cos(x)**2 - 2*cos(x) + 1, x), ImageSet(Lambda(n, 2*n*pi), S.Integers)) def test_issue_9565(): assert solveset_real(Abs((x - 1)/(x - 5)) <= Rational(1, 3), x) == Interval(-1, 2) def test_issue_10069(): eq = abs(1/(x - 1)) - 1 > 0 assert solveset_real(eq, x) == Union( Interval.open(0, 1), Interval.open(1, 2)) def test_real_imag_splitting(): a, b = symbols('a b', real=True) assert solveset_real(sqrt(a**2 - b**2) - 3, a) == \ FiniteSet(-sqrt(b**2 + 9), sqrt(b**2 + 9)) assert solveset_real(sqrt(a**2 + b**2) - 3, a) != \ S.EmptySet def test_units(): assert solveset_real(1/x - 1/(2*cm), x) == FiniteSet(2*cm) def test_solve_only_exp_1(): y = Symbol('y', positive=True) assert solveset_real(exp(x) - y, x) == FiniteSet(log(y)) assert solveset_real(exp(x) + exp(-x) - 4, x) == \ FiniteSet(log(-sqrt(3) + 2), log(sqrt(3) + 2)) assert solveset_real(exp(x) + exp(-x) - y, x) != S.EmptySet def test_atan2(): # The .inverse() method on atan2 works only if x.is_real is True and the # second argument is a real constant assert solveset_real(atan2(x, 2) - pi/3, x) == FiniteSet(2*sqrt(3)) def test_piecewise_solveset(): eq = Piecewise((x - 2, Gt(x, 2)), (2 - x, True)) - 3 assert set(solveset_real(eq, x)) == set(FiniteSet(-1, 5)) absxm3 = Piecewise( (x - 3, 0 <= x - 3), (3 - x, 0 > x - 3)) y = Symbol('y', positive=True) assert solveset_real(absxm3 - y, x) == FiniteSet(-y + 3, y + 3) f = Piecewise(((x - 2)**2, x >= 0), (0, True)) assert solveset(f, x, domain=S.Reals) == Union(FiniteSet(2), Interval(-oo, 0, True, True)) assert solveset( Piecewise((x + 1, x > 0), (I, True)) - I, x, S.Reals ) == Interval(-oo, 0) assert solveset(Piecewise((x - 1, Ne(x, I)), (x, True)), x) == FiniteSet(1) # issue 19718 g = Piecewise((1, x > 10), (0, True)) assert solveset(g > 0, x, S.Reals) == Interval.open(10, oo) from sympy.logic.boolalg import BooleanTrue f = BooleanTrue() assert solveset(f, x, domain=Interval(-3, 10)) == Interval(-3, 10) # issue 20552 f = Piecewise((0, Eq(x, 0)), (x**2/Abs(x), True)) g = Piecewise((0, Eq(x, pi)), ((x - pi)/sin(x), True)) assert solveset(f, x, domain=S.Reals) == FiniteSet(0) assert solveset(g) == FiniteSet(pi) def test_solveset_complex_polynomial(): assert solveset_complex(a*x**2 + b*x + c, x) == \ FiniteSet(-b/(2*a) - sqrt(-4*a*c + b**2)/(2*a), -b/(2*a) + sqrt(-4*a*c + b**2)/(2*a)) assert solveset_complex(x - y**3, y) == FiniteSet( (-x**Rational(1, 3))/2 + I*sqrt(3)*x**Rational(1, 3)/2, x**Rational(1, 3), (-x**Rational(1, 3))/2 - I*sqrt(3)*x**Rational(1, 3)/2) assert solveset_complex(x + 1/x - 1, x) == \ FiniteSet(S.Half + I*sqrt(3)/2, S.Half - I*sqrt(3)/2) def test_sol_zero_complex(): assert solveset_complex(0, x) == S.Complexes def test_solveset_complex_rational(): assert solveset_complex((x - 1)*(x - I)/(x - 3), x) == \ FiniteSet(1, I) assert solveset_complex((x - y**3)/((y**2)*sqrt(1 - y**2)), x) == \ FiniteSet(y**3) assert solveset_complex(-x**2 - I, x) == \ FiniteSet(-sqrt(2)/2 + sqrt(2)*I/2, sqrt(2)/2 - sqrt(2)*I/2) def test_solve_quintics(): skip("This test is too slow") f = x**5 - 110*x**3 - 55*x**2 + 2310*x + 979 s = solveset_complex(f, x) for root in s: res = f.subs(x, root.n()).n() assert tn(res, 0) f = x**5 + 15*x + 12 s = solveset_complex(f, x) for root in s: res = f.subs(x, root.n()).n() assert tn(res, 0) def test_solveset_complex_exp(): from sympy.abc import x, n assert dumeq(solveset_complex(exp(x) - 1, x), imageset(Lambda(n, I*2*n*pi), S.Integers)) assert dumeq(solveset_complex(exp(x) - I, x), imageset(Lambda(n, I*(2*n*pi + pi/2)), S.Integers)) assert solveset_complex(1/exp(x), x) == S.EmptySet assert dumeq(solveset_complex(sinh(x).rewrite(exp), x), imageset(Lambda(n, n*pi*I), S.Integers)) def test_solveset_real_exp(): from sympy.abc import x, y assert solveset(Eq((-2)**x, 4), x, S.Reals) == FiniteSet(2) assert solveset(Eq(-2**x, 4), x, S.Reals) == S.EmptySet assert solveset(Eq((-3)**x, 27), x, S.Reals) == S.EmptySet assert solveset(Eq((-5)**(x+1), 625), x, S.Reals) == FiniteSet(3) assert solveset(Eq(2**(x-3), -16), x, S.Reals) == S.EmptySet assert solveset(Eq((-3)**(x - 3), -3**39), x, S.Reals) == FiniteSet(42) assert solveset(Eq(2**x, y), x, S.Reals) == Intersection(S.Reals, FiniteSet(log(y)/log(2))) assert invert_real((-2)**(2*x) - 16, 0, x) == (x, FiniteSet(2)) def test_solve_complex_log(): assert solveset_complex(log(x), x) == FiniteSet(1) assert solveset_complex(1 - log(a + 4*x**2), x) == \ FiniteSet(-sqrt(-a + E)/2, sqrt(-a + E)/2) def test_solve_complex_sqrt(): assert solveset_complex(sqrt(5*x + 6) - 2 - x, x) == \ FiniteSet(-S.One, S(2)) assert solveset_complex(sqrt(5*x + 6) - (2 + 2*I) - x, x) == \ FiniteSet(-S(2), 3 - 4*I) assert solveset_complex(4*x*(1 - a * sqrt(x)), x) == \ FiniteSet(S.Zero, 1 / a ** 2) def test_solveset_complex_tan(): s = solveset_complex(tan(x).rewrite(exp), x) assert dumeq(s, imageset(Lambda(n, pi*n), S.Integers) - \ imageset(Lambda(n, pi*n + pi/2), S.Integers)) @_both_exp_pow def test_solve_trig(): from sympy.abc import n assert dumeq(solveset_real(sin(x), x), Union(imageset(Lambda(n, 2*pi*n), S.Integers), imageset(Lambda(n, 2*pi*n + pi), S.Integers))) assert dumeq(solveset_real(sin(x) - 1, x), imageset(Lambda(n, 2*pi*n + pi/2), S.Integers)) assert dumeq(solveset_real(cos(x), x), Union(imageset(Lambda(n, 2*pi*n + pi/2), S.Integers), imageset(Lambda(n, 2*pi*n + pi*Rational(3, 2)), S.Integers))) assert dumeq(solveset_real(sin(x) + cos(x), x), Union(imageset(Lambda(n, 2*n*pi + pi*Rational(3, 4)), S.Integers), imageset(Lambda(n, 2*n*pi + pi*Rational(7, 4)), S.Integers))) assert solveset_real(sin(x)**2 + cos(x)**2, x) == S.EmptySet assert dumeq(solveset_complex(cos(x) - S.Half, x), Union(imageset(Lambda(n, 2*n*pi + pi*Rational(5, 3)), S.Integers), imageset(Lambda(n, 2*n*pi + pi/3), S.Integers))) assert dumeq(solveset(sin(y + a) - sin(y), a, domain=S.Reals), Union(ImageSet(Lambda(n, 2*n*pi), S.Integers), Intersection(ImageSet(Lambda(n, -I*(I*( 2*n*pi + arg(-exp(-2*I*y))) + 2*im(y))), S.Integers), S.Reals))) assert dumeq(solveset_real(sin(2*x)*cos(x) + cos(2*x)*sin(x)-1, x), ImageSet(Lambda(n, n*pi*Rational(2, 3) + pi/6), S.Integers)) assert dumeq(solveset_real(2*tan(x)*sin(x) + 1, x), Union( ImageSet(Lambda(n, 2*n*pi + atan(sqrt(2)*sqrt(-1 + sqrt(17))/ (1 - sqrt(17))) + pi), S.Integers), ImageSet(Lambda(n, 2*n*pi - atan(sqrt(2)*sqrt(-1 + sqrt(17))/ (1 - sqrt(17))) + pi), S.Integers))) assert dumeq(solveset_real(cos(2*x)*cos(4*x) - 1, x), ImageSet(Lambda(n, n*pi), S.Integers)) assert dumeq(solveset(sin(x/10) + Rational(3, 4)), Union( ImageSet(Lambda(n, 20*n*pi + 10*atan(3*sqrt(7)/7) + 10*pi), S.Integers), ImageSet(Lambda(n, 20*n*pi - 10*atan(3*sqrt(7)/7) + 20*pi), S.Integers))) assert dumeq(solveset(cos(x/15) + cos(x/5)), Union( ImageSet(Lambda(n, 30*n*pi + 15*pi/2), S.Integers), ImageSet(Lambda(n, 30*n*pi + 45*pi/2), S.Integers), ImageSet(Lambda(n, 30*n*pi + 75*pi/4), S.Integers), ImageSet(Lambda(n, 30*n*pi + 45*pi/4), S.Integers), ImageSet(Lambda(n, 30*n*pi + 105*pi/4), S.Integers), ImageSet(Lambda(n, 30*n*pi + 15*pi/4), S.Integers))) assert dumeq(solveset(sec(sqrt(2)*x/3) + 5), Union( ImageSet(Lambda(n, 3*sqrt(2)*(2*n*pi - pi + atan(2*sqrt(6)))/2), S.Integers), ImageSet(Lambda(n, 3*sqrt(2)*(2*n*pi - atan(2*sqrt(6)) + pi)/2), S.Integers))) assert dumeq(simplify(solveset(tan(pi*x) - cot(pi/2*x))), Union( ImageSet(Lambda(n, 4*n + 1), S.Integers), ImageSet(Lambda(n, 4*n + 3), S.Integers), ImageSet(Lambda(n, 4*n + Rational(7, 3)), S.Integers), ImageSet(Lambda(n, 4*n + Rational(5, 3)), S.Integers), ImageSet(Lambda(n, 4*n + Rational(11, 3)), S.Integers), ImageSet(Lambda(n, 4*n + Rational(1, 3)), S.Integers))) assert dumeq(solveset(cos(9*x)), Union( ImageSet(Lambda(n, 2*n*pi/9 + pi/18), S.Integers), ImageSet(Lambda(n, 2*n*pi/9 + pi/6), S.Integers))) assert dumeq(solveset(sin(8*x) + cot(12*x), x, S.Reals), Union( ImageSet(Lambda(n, n*pi/2 + pi/8), S.Integers), ImageSet(Lambda(n, n*pi/2 + 3*pi/8), S.Integers), ImageSet(Lambda(n, n*pi/2 + 5*pi/16), S.Integers), ImageSet(Lambda(n, n*pi/2 + 3*pi/16), S.Integers), ImageSet(Lambda(n, n*pi/2 + 7*pi/16), S.Integers), ImageSet(Lambda(n, n*pi/2 + pi/16), S.Integers))) # This is the only remaining solveset test that actually ends up being solved # by _solve_trig2(). All others are handled by the improved _solve_trig1. assert dumeq(solveset_real(2*cos(x)*cos(2*x) - 1, x), Union(ImageSet(Lambda(n, 2*n*pi + 2*atan(sqrt(-2*2**Rational(1, 3)*(67 + 9*sqrt(57))**Rational(2, 3) + 8*2**Rational(2, 3) + 11*(67 + 9*sqrt(57))**Rational(1, 3))/(3*(67 + 9*sqrt(57))**Rational(1, 6)))), S.Integers), ImageSet(Lambda(n, 2*n*pi - 2*atan(sqrt(-2*2**Rational(1, 3)*(67 + 9*sqrt(57))**Rational(2, 3) + 8*2**Rational(2, 3) + 11*(67 + 9*sqrt(57))**Rational(1, 3))/(3*(67 + 9*sqrt(57))**Rational(1, 6))) + 2*pi), S.Integers))) # issue #16870 assert dumeq(simplify(solveset(sin(x/180*pi) - S.Half, x, S.Reals)), Union( ImageSet(Lambda(n, 360*n + 150), S.Integers), ImageSet(Lambda(n, 360*n + 30), S.Integers))) def test_solve_hyperbolic(): # actual solver: _solve_trig1 n = Dummy('n') assert solveset(sinh(x) + cosh(x), x) == S.EmptySet assert solveset(sinh(x) + cos(x), x) == ConditionSet(x, Eq(cos(x) + sinh(x), 0), S.Complexes) assert solveset_real(sinh(x) + sech(x), x) == FiniteSet( log(sqrt(sqrt(5) - 2))) assert solveset_real(3*cosh(2*x) - 5, x) == FiniteSet( -log(3)/2, log(3)/2) assert solveset_real(sinh(x - 3) - 2, x) == FiniteSet( log((2 + sqrt(5))*exp(3))) assert solveset_real(cosh(2*x) + 2*sinh(x) - 5, x) == FiniteSet( log(-2 + sqrt(5)), log(1 + sqrt(2))) assert solveset_real((coth(x) + sinh(2*x))/cosh(x) - 3, x) == FiniteSet( log(S.Half + sqrt(5)/2), log(1 + sqrt(2))) assert solveset_real(cosh(x)*sinh(x) - 2, x) == FiniteSet( log(4 + sqrt(17))/2) assert solveset_real(sinh(x) + tanh(x) - 1, x) == FiniteSet( log(sqrt(2)/2 + sqrt(-S(1)/2 + sqrt(2)))) assert dumeq(solveset_complex(sinh(x) - I/2, x), Union( ImageSet(Lambda(n, I*(2*n*pi + 5*pi/6)), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi/6)), S.Integers))) assert dumeq(solveset_complex(sinh(x) + sech(x), x), Union( ImageSet(Lambda(n, 2*n*I*pi + log(sqrt(-2 + sqrt(5)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi/2) + log(sqrt(2 + sqrt(5)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi) + log(sqrt(-2 + sqrt(5)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi - pi/2) + log(sqrt(2 + sqrt(5)))), S.Integers))) assert dumeq(solveset(sinh(x/10) + Rational(3, 4)), Union( ImageSet(Lambda(n, 10*I*(2*n*pi + pi) + 10*log(2)), S.Integers), ImageSet(Lambda(n, 20*n*I*pi - 10*log(2)), S.Integers))) assert dumeq(solveset(cosh(x/15) + cosh(x/5)), Union( ImageSet(Lambda(n, 15*I*(2*n*pi + pi/2)), S.Integers), ImageSet(Lambda(n, 15*I*(2*n*pi - pi/2)), S.Integers), ImageSet(Lambda(n, 15*I*(2*n*pi - 3*pi/4)), S.Integers), ImageSet(Lambda(n, 15*I*(2*n*pi + 3*pi/4)), S.Integers), ImageSet(Lambda(n, 15*I*(2*n*pi - pi/4)), S.Integers), ImageSet(Lambda(n, 15*I*(2*n*pi + pi/4)), S.Integers))) assert dumeq(solveset(sech(sqrt(2)*x/3) + 5), Union( ImageSet(Lambda(n, 3*sqrt(2)*I*(2*n*pi - pi + atan(2*sqrt(6)))/2), S.Integers), ImageSet(Lambda(n, 3*sqrt(2)*I*(2*n*pi - atan(2*sqrt(6)) + pi)/2), S.Integers))) assert dumeq(solveset(tanh(pi*x) - coth(pi/2*x)), Union( ImageSet(Lambda(n, 2*I*(2*n*pi + pi/2)/pi), S.Integers), ImageSet(Lambda(n, 2*I*(2*n*pi - pi/2)/pi), S.Integers))) assert dumeq(solveset(cosh(9*x)), Union( ImageSet(Lambda(n, I*(2*n*pi + pi/2)/9), S.Integers), ImageSet(Lambda(n, I*(2*n*pi - pi/2)/9), S.Integers))) # issues #9606 / #9531: assert solveset(sinh(x), x, S.Reals) == FiniteSet(0) assert dumeq(solveset(sinh(x), x, S.Complexes), Union( ImageSet(Lambda(n, I*(2*n*pi + pi)), S.Integers), ImageSet(Lambda(n, 2*n*I*pi), S.Integers))) # issues #11218 / #18427 assert dumeq(solveset(sin(pi*x), x, S.Reals), Union( ImageSet(Lambda(n, (2*n*pi + pi)/pi), S.Integers), ImageSet(Lambda(n, 2*n), S.Integers))) assert dumeq(solveset(sin(pi*x), x), Union( ImageSet(Lambda(n, (2*n*pi + pi)/pi), S.Integers), ImageSet(Lambda(n, 2*n), S.Integers))) # issue #17543 assert dumeq(simplify(solveset(I*cot(8*x - 8*E), x)), Union( ImageSet(Lambda(n, n*pi/4 - 13*pi/16 + E), S.Integers), ImageSet(Lambda(n, n*pi/4 - 11*pi/16 + E), S.Integers))) # issues #18490 / #19489 assert solveset(cosh(x) + cosh(3*x) - cosh(5*x), x, S.Reals ).dummy_eq(ConditionSet(x, Eq(cosh(x) + cosh(3*x) - cosh(5*x), 0), S.Reals)) assert solveset(sinh(8*x) + coth(12*x)).dummy_eq( ConditionSet(x, Eq(sinh(8*x) + coth(12*x), 0), S.Complexes)) def test_solve_trig_hyp_symbolic(): # actual solver: _solve_trig1 assert dumeq(solveset(sin(a*x), x), ConditionSet(x, Ne(a, 0), Union( ImageSet(Lambda(n, (2*n*pi + pi)/a), S.Integers), ImageSet(Lambda(n, 2*n*pi/a), S.Integers)))) assert dumeq(solveset(cosh(x/a), x), ConditionSet(x, Ne(a, 0), Union( ImageSet(Lambda(n, I*a*(2*n*pi + pi/2)), S.Integers), ImageSet(Lambda(n, I*a*(2*n*pi - pi/2)), S.Integers)))) assert dumeq(solveset(sin(2*sqrt(3)/3*a**2/(b*pi)*x) + cos(4*sqrt(3)/3*a**2/(b*pi)*x), x), ConditionSet(x, Ne(b, 0) & Ne(a**2, 0), Union( ImageSet(Lambda(n, sqrt(3)*pi*b*(2*n*pi + pi/2)/(2*a**2)), S.Integers), ImageSet(Lambda(n, sqrt(3)*pi*b*(2*n*pi - 5*pi/6)/(2*a**2)), S.Integers), ImageSet(Lambda(n, sqrt(3)*pi*b*(2*n*pi - pi/6)/(2*a**2)), S.Integers)))) assert dumeq(simplify(solveset(cot((1 + I)*x) - cot((3 + 3*I)*x), x)), Union( ImageSet(Lambda(n, pi*(1 - I)*(4*n + 1)/4), S.Integers), ImageSet(Lambda(n, pi*(1 - I)*(4*n - 1)/4), S.Integers))) assert dumeq(solveset(cosh((a**2 + 1)*x) - 3, x), ConditionSet(x, Ne(a**2 + 1, 0), Union( ImageSet(Lambda(n, (2*n*I*pi + log(3 - 2*sqrt(2)))/(a**2 + 1)), S.Integers), ImageSet(Lambda(n, (2*n*I*pi + log(2*sqrt(2) + 3))/(a**2 + 1)), S.Integers)))) ar = Symbol('ar', real=True) assert solveset(cosh((ar**2 + 1)*x) - 2, x, S.Reals) == FiniteSet( log(sqrt(3) + 2)/(ar**2 + 1), log(2 - sqrt(3))/(ar**2 + 1)) def test_issue_9616(): assert dumeq(solveset(sinh(x) + tanh(x) - 1, x), Union( ImageSet(Lambda(n, 2*n*I*pi + log(sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi - atan(sqrt(2)*sqrt(S.Half + sqrt(2))) + pi) + log(sqrt(1 + sqrt(2)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi) + log(-sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi - pi + atan(sqrt(2)*sqrt(S.Half + sqrt(2)))) + log(sqrt(1 + sqrt(2)))), S.Integers))) f1 = (sinh(x)).rewrite(exp) f2 = (tanh(x)).rewrite(exp) assert dumeq(solveset(f1 + f2 - 1, x), Union( Complement(ImageSet( Lambda(n, I*(2*n*pi + pi) + log(-sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)), Complement(ImageSet(Lambda(n, I*(2*n*pi - pi + atan(sqrt(2)*sqrt(S.Half + sqrt(2)))) + log(sqrt(1 + sqrt(2)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)), Complement(ImageSet(Lambda(n, I*(2*n*pi - atan(sqrt(2)*sqrt(S.Half + sqrt(2))) + pi) + log(sqrt(1 + sqrt(2)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)), Complement( ImageSet(Lambda(n, 2*n*I*pi + log(sqrt(2)/2 + sqrt(-S.Half + sqrt(2)))), S.Integers), ImageSet(Lambda(n, I*(2*n*pi + pi)/2), S.Integers)))) def test_solve_invalid_sol(): assert 0 not in solveset_real(sin(x)/x, x) assert 0 not in solveset_complex((exp(x) - 1)/x, x) @XFAIL def test_solve_trig_simplified(): from sympy.abc import n assert dumeq(solveset_real(sin(x), x), imageset(Lambda(n, n*pi), S.Integers)) assert dumeq(solveset_real(cos(x), x), imageset(Lambda(n, n*pi + pi/2), S.Integers)) assert dumeq(solveset_real(cos(x) + sin(x), x), imageset(Lambda(n, n*pi - pi/4), S.Integers)) @XFAIL def test_solve_lambert(): assert solveset_real(x*exp(x) - 1, x) == FiniteSet(LambertW(1)) assert solveset_real(exp(x) + x, x) == FiniteSet(-LambertW(1)) assert solveset_real(x + 2**x, x) == \ FiniteSet(-LambertW(log(2))/log(2)) # issue 4739 ans = solveset_real(3*x + 5 + 2**(-5*x + 3), x) assert ans == FiniteSet(Rational(-5, 3) + LambertW(-10240*2**Rational(1, 3)*log(2)/3)/(5*log(2))) eq = 2*(3*x + 4)**5 - 6*7**(3*x + 9) result = solveset_real(eq, x) ans = FiniteSet((log(2401) + 5*LambertW(-log(7**(7*3**Rational(1, 5)/5))))/(3*log(7))/-1) assert result == ans assert solveset_real(eq.expand(), x) == result assert solveset_real(5*x - 1 + 3*exp(2 - 7*x), x) == \ FiniteSet(Rational(1, 5) + LambertW(-21*exp(Rational(3, 5))/5)/7) assert solveset_real(2*x + 5 + log(3*x - 2), x) == \ FiniteSet(Rational(2, 3) + LambertW(2*exp(Rational(-19, 3))/3)/2) assert solveset_real(3*x + log(4*x), x) == \ FiniteSet(LambertW(Rational(3, 4))/3) assert solveset_real(x**x - 2) == FiniteSet(exp(LambertW(log(2)))) a = Symbol('a') assert solveset_real(-a*x + 2*x*log(x), x) == FiniteSet(exp(a/2)) a = Symbol('a', real=True) assert solveset_real(a/x + exp(x/2), x) == \ FiniteSet(2*LambertW(-a/2)) assert solveset_real((a/x + exp(x/2)).diff(x), x) == \ FiniteSet(4*LambertW(sqrt(2)*sqrt(a)/4)) # coverage test assert solveset_real(tanh(x + 3)*tanh(x - 3) - 1, x) == EmptySet() assert solveset_real((x**2 - 2*x + 1).subs(x, log(x) + 3*x), x) == \ FiniteSet(LambertW(3*S.Exp1)/3) assert solveset_real((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1), x) == \ FiniteSet(LambertW(3*exp(-sqrt(2)))/3, LambertW(3*exp(sqrt(2)))/3) assert solveset_real((x**2 - 2*x - 2).subs(x, log(x) + 3*x), x) == \ FiniteSet(LambertW(3*exp(1 + sqrt(3)))/3, LambertW(3*exp(-sqrt(3) + 1))/3) assert solveset_real(x*log(x) + 3*x + 1, x) == \ FiniteSet(exp(-3 + LambertW(-exp(3)))) eq = (x*exp(x) - 3).subs(x, x*exp(x)) assert solveset_real(eq, x) == \ FiniteSet(LambertW(3*exp(-LambertW(3)))) assert solveset_real(3*log(a**(3*x + 5)) + a**(3*x + 5), x) == \ FiniteSet(-((log(a**5) + LambertW(Rational(1, 3)))/(3*log(a)))) p = symbols('p', positive=True) assert solveset_real(3*log(p**(3*x + 5)) + p**(3*x + 5), x) == \ FiniteSet( log((-3**Rational(1, 3) - 3**Rational(5, 6)*I)*LambertW(Rational(1, 3))**Rational(1, 3)/(2*p**Rational(5, 3)))/log(p), log((-3**Rational(1, 3) + 3**Rational(5, 6)*I)*LambertW(Rational(1, 3))**Rational(1, 3)/(2*p**Rational(5, 3)))/log(p), log((3*LambertW(Rational(1, 3))/p**5)**(1/(3*log(p)))),) # checked numerically # check collection b = Symbol('b') eq = 3*log(a**(3*x + 5)) + b*log(a**(3*x + 5)) + a**(3*x + 5) assert solveset_real(eq, x) == FiniteSet( -((log(a**5) + LambertW(1/(b + 3)))/(3*log(a)))) # issue 4271 assert solveset_real((a/x + exp(x/2)).diff(x, 2), x) == FiniteSet( 6*LambertW((-1)**Rational(1, 3)*a**Rational(1, 3)/3)) assert solveset_real(x**3 - 3**x, x) == \ FiniteSet(-3/log(3)*LambertW(-log(3)/3)) assert solveset_real(3**cos(x) - cos(x)**3) == FiniteSet( acos(-3*LambertW(-log(3)/3)/log(3))) assert solveset_real(x**2 - 2**x, x) == \ solveset_real(-x**2 + 2**x, x) assert solveset_real(3*log(x) - x*log(3)) == FiniteSet( -3*LambertW(-log(3)/3)/log(3), -3*LambertW(-log(3)/3, -1)/log(3)) assert solveset_real(LambertW(2*x) - y) == FiniteSet( y*exp(y)/2) @XFAIL def test_other_lambert(): a = Rational(6, 5) assert solveset_real(x**a - a**x, x) == FiniteSet( a, -a*LambertW(-log(a)/a)/log(a)) @_both_exp_pow def test_solveset(): f = Function('f') raises(ValueError, lambda: solveset(x + y)) assert solveset(x, 1) == S.EmptySet assert solveset(f(1)**2 + y + 1, f(1) ) == FiniteSet(-sqrt(-y - 1), sqrt(-y - 1)) assert solveset(f(1)**2 - 1, f(1), S.Reals) == FiniteSet(-1, 1) assert solveset(f(1)**2 + 1, f(1)) == FiniteSet(-I, I) assert solveset(x - 1, 1) == FiniteSet(x) assert solveset(sin(x) - cos(x), sin(x)) == FiniteSet(cos(x)) assert solveset(0, domain=S.Reals) == S.Reals assert solveset(1) == S.EmptySet assert solveset(True, domain=S.Reals) == S.Reals # issue 10197 assert solveset(False, domain=S.Reals) == S.EmptySet assert solveset(exp(x) - 1, domain=S.Reals) == FiniteSet(0) assert solveset(exp(x) - 1, x, S.Reals) == FiniteSet(0) assert solveset(Eq(exp(x), 1), x, S.Reals) == FiniteSet(0) assert solveset(exp(x) - 1, exp(x), S.Reals) == FiniteSet(1) A = Indexed('A', x) assert solveset(A - 1, A, S.Reals) == FiniteSet(1) assert solveset(x - 1 >= 0, x, S.Reals) == Interval(1, oo) assert solveset(exp(x) - 1 >= 0, x, S.Reals) == Interval(0, oo) assert dumeq(solveset(exp(x) - 1, x), imageset(Lambda(n, 2*I*pi*n), S.Integers)) assert dumeq(solveset(Eq(exp(x), 1), x), imageset(Lambda(n, 2*I*pi*n), S.Integers)) # issue 13825 assert solveset(x**2 + f(0) + 1, x) == {-sqrt(-f(0) - 1), sqrt(-f(0) - 1)} # issue 19977 assert solveset(atan(log(x)) > 0, x, domain=Interval.open(0, oo)) == Interval.open(1, oo) @_both_exp_pow def test_multi_exp(): k1, k2, k3 = symbols('k1, k2, k3') assert dumeq(solveset(exp(exp(x)) - 5, x),\ imageset(Lambda(((k1, n),), I*(2*k1*pi + arg(2*n*I*pi + log(5))) + log(Abs(2*n*I*pi + log(5)))),\ ProductSet(S.Integers, S.Integers))) assert dumeq(solveset((d*exp(exp(a*x + b)) + c), x),\ imageset(Lambda(x, (-b + x)/a), ImageSet(Lambda(((k1, n),), \ I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d))))), \ ProductSet(S.Integers, S.Integers)))) assert dumeq(solveset((d*exp(exp(exp(a*x + b))) + c), x),\ imageset(Lambda(x, (-b + x)/a), ImageSet(Lambda(((k2, k1, n),), \ I*(2*k2*pi + arg(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + \ log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))) + log(Abs(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + \ log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d))))))), \ ProductSet(S.Integers, S.Integers, S.Integers)))) assert dumeq(solveset((d*exp(exp(exp(exp(a*x + b)))) + c), x),\ ImageSet(Lambda(x, (-b + x)/a), ImageSet(Lambda(((k3, k2, k1, n),), \ I*(2*k3*pi + arg(I*(2*k2*pi + arg(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + \ log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))) + log(Abs(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + \ log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))))) + log(Abs(I*(2*k2*pi + \ arg(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))))) + \ log(Abs(I*(2*k1*pi + arg(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d)))) + log(Abs(I*(2*n*pi + arg(-c/d)) + log(Abs(c/d))))))))), \ ProductSet(S.Integers, S.Integers, S.Integers, S.Integers)))) def test__solveset_multi(): from sympy.solvers.solveset import _solveset_multi from sympy import Reals # Basic univariate case: from sympy.abc import x assert _solveset_multi([x**2-1], [x], [S.Reals]) == FiniteSet((1,), (-1,)) # Linear systems of two equations from sympy.abc import x, y assert _solveset_multi([x+y, x+1], [x, y], [Reals, Reals]) == FiniteSet((-1, 1)) assert _solveset_multi([x+y, x+1], [y, x], [Reals, Reals]) == FiniteSet((1, -1)) assert _solveset_multi([x+y, x-y-1], [x, y], [Reals, Reals]) == FiniteSet((S(1)/2, -S(1)/2)) assert _solveset_multi([x-1, y-2], [x, y], [Reals, Reals]) == FiniteSet((1, 2)) # assert dumeq(_solveset_multi([x+y], [x, y], [Reals, Reals]), ImageSet(Lambda(x, (x, -x)), Reals)) assert dumeq(_solveset_multi([x+y], [x, y], [Reals, Reals]), Union( ImageSet(Lambda(((x,),), (x, -x)), ProductSet(Reals)), ImageSet(Lambda(((y,),), (-y, y)), ProductSet(Reals)))) assert _solveset_multi([x+y, x+y+1], [x, y], [Reals, Reals]) == S.EmptySet assert _solveset_multi([x+y, x-y, x-1], [x, y], [Reals, Reals]) == S.EmptySet assert _solveset_multi([x+y, x-y, x-1], [y, x], [Reals, Reals]) == S.EmptySet # Systems of three equations: from sympy.abc import x, y, z assert _solveset_multi([x+y+z-1, x+y-z-2, x-y-z-3], [x, y, z], [Reals, Reals, Reals]) == FiniteSet((2, -S.Half, -S.Half)) # Nonlinear systems: from sympy.abc import r, theta, z, x, y assert _solveset_multi([x**2+y**2-2, x+y], [x, y], [Reals, Reals]) == FiniteSet((-1, 1), (1, -1)) assert _solveset_multi([x**2-1, y], [x, y], [Reals, Reals]) == FiniteSet((1, 0), (-1, 0)) #assert _solveset_multi([x**2-y**2], [x, y], [Reals, Reals]) == Union( # ImageSet(Lambda(x, (x, -x)), Reals), ImageSet(Lambda(x, (x, x)), Reals)) assert dumeq(_solveset_multi([x**2-y**2], [x, y], [Reals, Reals]), Union( ImageSet(Lambda(((x,),), (x, -Abs(x))), ProductSet(Reals)), ImageSet(Lambda(((x,),), (x, Abs(x))), ProductSet(Reals)), ImageSet(Lambda(((y,),), (-Abs(y), y)), ProductSet(Reals)), ImageSet(Lambda(((y,),), (Abs(y), y)), ProductSet(Reals)))) assert _solveset_multi([r*cos(theta)-1, r*sin(theta)], [theta, r], [Interval(0, pi), Interval(-1, 1)]) == FiniteSet((0, 1), (pi, -1)) assert _solveset_multi([r*cos(theta)-1, r*sin(theta)], [r, theta], [Interval(0, 1), Interval(0, pi)]) == FiniteSet((1, 0)) #assert _solveset_multi([r*cos(theta)-r, r*sin(theta)], [r, theta], # [Interval(0, 1), Interval(0, pi)]) == ? assert dumeq(_solveset_multi([r*cos(theta)-r, r*sin(theta)], [r, theta], [Interval(0, 1), Interval(0, pi)]), Union( ImageSet(Lambda(((r,),), (r, 0)), ImageSet(Lambda(r, (r,)), Interval(0, 1))), ImageSet(Lambda(((theta,),), (0, theta)), ImageSet(Lambda(theta, (theta,)), Interval(0, pi))))) def test_conditionset(): assert solveset(Eq(sin(x)**2 + cos(x)**2, 1), x, domain=S.Reals ) is S.Reals assert solveset(Eq(x**2 + x*sin(x), 1), x, domain=S.Reals ).dummy_eq(ConditionSet(x, Eq(x**2 + x*sin(x) - 1, 0), S.Reals)) assert dumeq(solveset(Eq(-I*(exp(I*x) - exp(-I*x))/2, 1), x ), imageset(Lambda(n, 2*n*pi + pi/2), S.Integers)) assert solveset(x + sin(x) > 1, x, domain=S.Reals ).dummy_eq(ConditionSet(x, x + sin(x) > 1, S.Reals)) assert solveset(Eq(sin(Abs(x)), x), x, domain=S.Reals ).dummy_eq(ConditionSet(x, Eq(-x + sin(Abs(x)), 0), S.Reals)) assert solveset(y**x-z, x, S.Reals ).dummy_eq(ConditionSet(x, Eq(y**x - z, 0), S.Reals)) @XFAIL def test_conditionset_equality(): ''' Checking equality of different representations of ConditionSet''' assert solveset(Eq(tan(x), y), x) == ConditionSet(x, Eq(tan(x), y), S.Complexes) def test_solveset_domain(): assert solveset(x**2 - x - 6, x, Interval(0, oo)) == FiniteSet(3) assert solveset(x**2 - 1, x, Interval(0, oo)) == FiniteSet(1) assert solveset(x**4 - 16, x, Interval(0, 10)) == FiniteSet(2) def test_improve_coverage(): solution = solveset(exp(x) + sin(x), x, S.Reals) unsolved_object = ConditionSet(x, Eq(exp(x) + sin(x), 0), S.Reals) assert solution.dummy_eq(unsolved_object) def test_issue_9522(): expr1 = Eq(1/(x**2 - 4) + x, 1/(x**2 - 4) + 2) expr2 = Eq(1/x + x, 1/x) assert solveset(expr1, x, S.Reals) == EmptySet() assert solveset(expr2, x, S.Reals) == EmptySet() def test_solvify(): assert solvify(x**2 + 10, x, S.Reals) == [] assert solvify(x**3 + 1, x, S.Complexes) == [-1, S.Half - sqrt(3)*I/2, S.Half + sqrt(3)*I/2] assert solvify(log(x), x, S.Reals) == [1] assert solvify(cos(x), x, S.Reals) == [pi/2, pi*Rational(3, 2)] assert solvify(sin(x) + 1, x, S.Reals) == [pi*Rational(3, 2)] raises(NotImplementedError, lambda: solvify(sin(exp(x)), x, S.Complexes)) def test_solvify_piecewise(): p1 = Piecewise((0, x < -1), (x**2, x <= 1), (log(x), True)) p2 = Piecewise((0, x < -10), (x**2 + 5*x - 6, x >= -9)) p3 = Piecewise((0, Eq(x, 0)), (x**2/Abs(x), True)) p4 = Piecewise((0, Eq(x, pi)), ((x - pi)/sin(x), True)) # issue 21079 assert solvify(p1, x, S.Reals) == [0] assert solvify(p2, x, S.Reals) == [-6, 1] assert solvify(p3, x, S.Reals) == [0] assert solvify(p4, x, S.Reals) == [pi] def test_abs_invert_solvify(): x = Symbol('x',positive=True) assert solvify(sin(Abs(x)), x, S.Reals) == [0, pi] x = Symbol('x') assert solvify(sin(Abs(x)), x, S.Reals) is None def test_linear_eq_to_matrix(): eqns1 = [2*x + y - 2*z - 3, x - y - z, x + y + 3*z - 12] eqns2 = [Eq(3*x + 2*y - z, 1), Eq(2*x - 2*y + 4*z, -2), -2*x + y - 2*z] A, B = linear_eq_to_matrix(eqns1, x, y, z) assert A == Matrix([[2, 1, -2], [1, -1, -1], [1, 1, 3]]) assert B == Matrix([[3], [0], [12]]) A, B = linear_eq_to_matrix(eqns2, x, y, z) assert A == Matrix([[3, 2, -1], [2, -2, 4], [-2, 1, -2]]) assert B == Matrix([[1], [-2], [0]]) # Pure symbolic coefficients eqns3 = [a*b*x + b*y + c*z - d, e*x + d*x + f*y + g*z - h, i*x + j*y + k*z - l] A, B = linear_eq_to_matrix(eqns3, x, y, z) assert A == Matrix([[a*b, b, c], [d + e, f, g], [i, j, k]]) assert B == Matrix([[d], [h], [l]]) # raise ValueError if # 1) no symbols are given raises(ValueError, lambda: linear_eq_to_matrix(eqns3)) # 2) there are duplicates raises(ValueError, lambda: linear_eq_to_matrix(eqns3, [x, x, y])) # 3) there are non-symbols raises(ValueError, lambda: linear_eq_to_matrix(eqns3, [x, 1/a, y])) # 4) a nonlinear term is detected in the original expression raises(NonlinearError, lambda: linear_eq_to_matrix(Eq(1/x + x, 1/x), [x])) assert linear_eq_to_matrix(1, x) == (Matrix([[0]]), Matrix([[-1]])) # issue 15195 assert linear_eq_to_matrix(x + y*(z*(3*x + 2) + 3), x) == ( Matrix([[3*y*z + 1]]), Matrix([[-y*(2*z + 3)]])) assert linear_eq_to_matrix(Matrix( [[a*x + b*y - 7], [5*x + 6*y - c]]), x, y) == ( Matrix([[a, b], [5, 6]]), Matrix([[7], [c]])) # issue 15312 assert linear_eq_to_matrix(Eq(x + 2, 1), x) == ( Matrix([[1]]), Matrix([[-1]])) def test_issue_16577(): assert linear_eq_to_matrix(Eq(a*(2*x + 3*y) + 4*y, 5), x, y) == ( Matrix([[2*a, 3*a + 4]]), Matrix([[5]])) def test_linsolve(): x1, x2, x3, x4 = symbols('x1, x2, x3, x4') # Test for different input forms M = Matrix([[1, 2, 1, 1, 7], [1, 2, 2, -1, 12], [2, 4, 0, 6, 4]]) system1 = A, B = M[:, :-1], M[:, -1] Eqns = [x1 + 2*x2 + x3 + x4 - 7, x1 + 2*x2 + 2*x3 - x4 - 12, 2*x1 + 4*x2 + 6*x4 - 4] sol = FiniteSet((-2*x2 - 3*x4 + 2, x2, 2*x4 + 5, x4)) assert linsolve(Eqns, (x1, x2, x3, x4)) == sol assert linsolve(Eqns, *(x1, x2, x3, x4)) == sol assert linsolve(system1, (x1, x2, x3, x4)) == sol assert linsolve(system1, *(x1, x2, x3, x4)) == sol # issue 9667 - symbols can be Dummy symbols x1, x2, x3, x4 = symbols('x:4', cls=Dummy) assert linsolve(system1, x1, x2, x3, x4) == FiniteSet( (-2*x2 - 3*x4 + 2, x2, 2*x4 + 5, x4)) # raise ValueError for garbage value raises(ValueError, lambda: linsolve(Eqns)) raises(ValueError, lambda: linsolve(x1)) raises(ValueError, lambda: linsolve(x1, x2)) raises(ValueError, lambda: linsolve((A,), x1, x2)) raises(ValueError, lambda: linsolve(A, B, x1, x2)) #raise ValueError if equations are non-linear in given variables raises(NonlinearError, lambda: linsolve([x + y - 1, x ** 2 + y - 3], [x, y])) raises(NonlinearError, lambda: linsolve([cos(x) + y, x + y], [x, y])) assert linsolve([x + z - 1, x ** 2 + y - 3], [z, y]) == {(-x + 1, -x**2 + 3)} # Fully symbolic test A = Matrix([[a, b], [c, d]]) B = Matrix([[e], [g]]) system2 = (A, B) sol = FiniteSet(((-b*g + d*e)/(a*d - b*c), (a*g - c*e)/(a*d - b*c))) assert linsolve(system2, [x, y]) == sol # No solution A = Matrix([[1, 2, 3], [2, 4, 6], [3, 6, 9]]) B = Matrix([0, 0, 1]) assert linsolve((A, B), (x, y, z)) == EmptySet() # Issue #10056 A, B, J1, J2 = symbols('A B J1 J2') Augmatrix = Matrix([ [2*I*J1, 2*I*J2, -2/J1], [-2*I*J2, -2*I*J1, 2/J2], [0, 2, 2*I/(J1*J2)], [2, 0, 0], ]) assert linsolve(Augmatrix, A, B) == FiniteSet((0, I/(J1*J2))) # Issue #10121 - Assignment of free variables Augmatrix = Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0]]) assert linsolve(Augmatrix, a, b, c, d, e) == FiniteSet((a, 0, c, 0, e)) #raises(IndexError, lambda: linsolve(Augmatrix, a, b, c)) x0, x1, x2, _x0 = symbols('tau0 tau1 tau2 _tau0') assert linsolve(Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, _x0]]) ) == FiniteSet((x0, 0, x1, _x0, x2)) x0, x1, x2, _x0 = symbols('tau00 tau01 tau02 tau0') assert linsolve(Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, _x0]]) ) == FiniteSet((x0, 0, x1, _x0, x2)) x0, x1, x2, _x0 = symbols('tau00 tau01 tau02 tau1') assert linsolve(Matrix([[0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, _x0]]) ) == FiniteSet((x0, 0, x1, _x0, x2)) # symbols can be given as generators x0, x2, x4 = symbols('x0, x2, x4') assert linsolve(Augmatrix, numbered_symbols('x') ) == FiniteSet((x0, 0, x2, 0, x4)) Augmatrix[-1, -1] = x0 # use Dummy to avoid clash; the names may clash but the symbols # will not Augmatrix[-1, -1] = symbols('_x0') assert len(linsolve( Augmatrix, numbered_symbols('x', cls=Dummy)).free_symbols) == 4 # Issue #12604 f = Function('f') assert linsolve([f(x) - 5], f(x)) == FiniteSet((5,)) # Issue #14860 from sympy.physics.units import meter, newton, kilo kN = kilo*newton Eqns = [8*kN + x + y, 28*kN*meter + 3*x*meter] assert linsolve(Eqns, x, y) == { (kilo*newton*Rational(-28, 3), kN*Rational(4, 3))} # linsolve fully expands expressions, so removable singularities # and other nonlinearity does not raise an error assert linsolve([Eq(x, x + y)], [x, y]) == {(x, 0)} assert linsolve([Eq(1/x, 1/x + y)], [x, y]) == {(x, 0)} assert linsolve([Eq(y/x, y/x + y)], [x, y]) == {(x, 0)} assert linsolve([Eq(x*(x + 1), x**2 + y)], [x, y]) == {(y, y)} # corner cases # # XXX: The case below should give the same as for [0] # assert linsolve([], [x]) == {(x,)} assert linsolve([], [x]) == EmptySet() assert linsolve([0], [x]) == {(x,)} assert linsolve([x], [x, y]) == {(0, y)} assert linsolve([x, 0], [x, y]) == {(0, y)} def test_linsolve_large_sparse(): # # This is mainly a performance test # def _mk_eqs_sol(n): xs = symbols('x:{}'.format(n)) ys = symbols('y:{}'.format(n)) syms = xs + ys eqs = [] sol = (-S.Half,) * n + (S.Half,) * n for xi, yi in zip(xs, ys): eqs.extend([xi + yi, xi - yi + 1]) return eqs, syms, FiniteSet(sol) n = 500 eqs, syms, sol = _mk_eqs_sol(n) assert linsolve(eqs, syms) == sol def test_linsolve_immutable(): A = ImmutableDenseMatrix([[1, 1, 2], [0, 1, 2], [0, 0, 1]]) B = ImmutableDenseMatrix([2, 1, -1]) assert linsolve([A, B], (x, y, z)) == FiniteSet((1, 3, -1)) A = ImmutableDenseMatrix([[1, 1, 7], [1, -1, 3]]) assert linsolve(A) == FiniteSet((5, 2)) def test_solve_decomposition(): n = Dummy('n') f1 = exp(3*x) - 6*exp(2*x) + 11*exp(x) - 6 f2 = sin(x)**2 - 2*sin(x) + 1 f3 = sin(x)**2 - sin(x) f4 = sin(x + 1) f5 = exp(x + 2) - 1 f6 = 1/log(x) f7 = 1/x s1 = ImageSet(Lambda(n, 2*n*pi), S.Integers) s2 = ImageSet(Lambda(n, 2*n*pi + pi), S.Integers) s3 = ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers) s4 = ImageSet(Lambda(n, 2*n*pi - 1), S.Integers) s5 = ImageSet(Lambda(n, 2*n*pi - 1 + pi), S.Integers) assert solve_decomposition(f1, x, S.Reals) == FiniteSet(0, log(2), log(3)) assert dumeq(solve_decomposition(f2, x, S.Reals), s3) assert dumeq(solve_decomposition(f3, x, S.Reals), Union(s1, s2, s3)) assert dumeq(solve_decomposition(f4, x, S.Reals), Union(s4, s5)) assert solve_decomposition(f5, x, S.Reals) == FiniteSet(-2) assert solve_decomposition(f6, x, S.Reals) == S.EmptySet assert solve_decomposition(f7, x, S.Reals) == S.EmptySet assert solve_decomposition(x, x, Interval(1, 2)) == S.EmptySet # nonlinsolve testcases def test_nonlinsolve_basic(): assert nonlinsolve([],[]) == S.EmptySet assert nonlinsolve([],[x, y]) == S.EmptySet system = [x, y - x - 5] assert nonlinsolve([x],[x, y]) == FiniteSet((0, y)) assert nonlinsolve(system, [y]) == FiniteSet((x + 5,)) soln = (ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers),) assert dumeq(nonlinsolve([sin(x) - 1], [x]), FiniteSet(tuple(soln))) assert nonlinsolve([x**2 - 1], [x]) == FiniteSet((-1,), (1,)) soln = FiniteSet((y, y)) assert nonlinsolve([x - y, 0], x, y) == soln assert nonlinsolve([0, x - y], x, y) == soln assert nonlinsolve([x - y, x - y], x, y) == soln assert nonlinsolve([x, 0], x, y) == FiniteSet((0, y)) f = Function('f') assert nonlinsolve([f(x), 0], f(x), y) == FiniteSet((0, y)) assert nonlinsolve([f(x), 0], f(x), f(y)) == FiniteSet((0, f(y))) A = Indexed('A', x) assert nonlinsolve([A, 0], A, y) == FiniteSet((0, y)) assert nonlinsolve([x**2 -1], [sin(x)]) == FiniteSet((S.EmptySet,)) assert nonlinsolve([x**2 -1], sin(x)) == FiniteSet((S.EmptySet,)) assert nonlinsolve([x**2 -1], 1) == FiniteSet((x**2,)) assert nonlinsolve([x**2 -1], x + y) == FiniteSet((S.EmptySet,)) assert nonlinsolve([Eq(1, x + y), Eq(1, -x + y - 1), Eq(1, -x + y - 1)], x, y) == FiniteSet( (-S.Half, 3*S.Half)) def test_nonlinsolve_abs(): soln = FiniteSet((y, y), (-y, y)) assert nonlinsolve([Abs(x) - y], x, y) == soln def test_raise_exception_nonlinsolve(): raises(IndexError, lambda: nonlinsolve([x**2 -1], [])) raises(ValueError, lambda: nonlinsolve([x**2 -1])) raises(NotImplementedError, lambda: nonlinsolve([(x+y)**2 - 9, x**2 - y**2 - 0.75], (x, y))) def test_trig_system(): # TODO: add more simple testcases when solveset returns # simplified soln for Trig eq assert nonlinsolve([sin(x) - 1, cos(x) -1 ], x) == S.EmptySet soln1 = (ImageSet(Lambda(n, 2*n*pi + pi/2), S.Integers),) soln = FiniteSet(soln1) assert dumeq(nonlinsolve([sin(x) - 1, cos(x)], x), soln) @XFAIL def test_trig_system_fail(): # fails because solveset trig solver is not much smart. sys = [x + y - pi/2, sin(x) + sin(y) - 1] # solveset returns conditionset for sin(x) + sin(y) - 1 soln_1 = (ImageSet(Lambda(n, n*pi + pi/2), S.Integers), ImageSet(Lambda(n, n*pi), S.Integers)) soln_1 = FiniteSet(soln_1) soln_2 = (ImageSet(Lambda(n, n*pi), S.Integers), ImageSet(Lambda(n, n*pi+ pi/2), S.Integers)) soln_2 = FiniteSet(soln_2) soln = soln_1 + soln_2 assert dumeq(nonlinsolve(sys, [x, y]), soln) # Add more cases from here # http://www.vitutor.com/geometry/trigonometry/equations_systems.html#uno sys = [sin(x) + sin(y) - (sqrt(3)+1)/2, sin(x) - sin(y) - (sqrt(3) - 1)/2] soln_x = Union(ImageSet(Lambda(n, 2*n*pi + pi/3), S.Integers), ImageSet(Lambda(n, 2*n*pi + pi*Rational(2, 3)), S.Integers)) soln_y = Union(ImageSet(Lambda(n, 2*n*pi + pi/6), S.Integers), ImageSet(Lambda(n, 2*n*pi + pi*Rational(5, 6)), S.Integers)) assert dumeq(nonlinsolve(sys, [x, y]), FiniteSet((soln_x, soln_y))) def test_nonlinsolve_positive_dimensional(): x, y, z, a, b, c, d = symbols('x, y, z, a, b, c, d', extended_real=True) assert nonlinsolve([x*y, x*y - x], [x, y]) == FiniteSet((0, y)) system = [a**2 + a*c, a - b] assert nonlinsolve(system, [a, b]) == FiniteSet((0, 0), (-c, -c)) # here (a= 0, b = 0) is independent soln so both is printed. # if symbols = [a, b, c] then only {a : -c ,b : -c} eq1 = a + b + c + d eq2 = a*b + b*c + c*d + d*a eq3 = a*b*c + b*c*d + c*d*a + d*a*b eq4 = a*b*c*d - 1 system = [eq1, eq2, eq3, eq4] sol1 = (-1/d, -d, 1/d, FiniteSet(d) - FiniteSet(0)) sol2 = (1/d, -d, -1/d, FiniteSet(d) - FiniteSet(0)) soln = FiniteSet(sol1, sol2) assert nonlinsolve(system, [a, b, c, d]) == soln def test_nonlinsolve_polysys(): x, y, z = symbols('x, y, z', real=True) assert nonlinsolve([x**2 + y - 2, x**2 + y], [x, y]) == S.EmptySet s = (-y + 2, y) assert nonlinsolve([(x + y)**2 - 4, x + y - 2], [x, y]) == FiniteSet(s) system = [x**2 - y**2] soln_real = FiniteSet((-y, y), (y, y)) soln_complex = FiniteSet((-Abs(y), y), (Abs(y), y)) soln =soln_real + soln_complex assert nonlinsolve(system, [x, y]) == soln system = [x**2 - y**2] soln_real= FiniteSet((y, -y), (y, y)) soln_complex = FiniteSet((y, -Abs(y)), (y, Abs(y))) soln = soln_real + soln_complex assert nonlinsolve(system, [y, x]) == soln system = [x**2 + y - 3, x - y - 4] assert nonlinsolve(system, (x, y)) != nonlinsolve(system, (y, x)) def test_nonlinsolve_using_substitution(): x, y, z, n = symbols('x, y, z, n', real = True) system = [(x + y)*n - y**2 + 2] s_x = (n*y - y**2 + 2)/n soln = (-s_x, y) assert nonlinsolve(system, [x, y]) == FiniteSet(soln) system = [z**2*x**2 - z**2*y**2/exp(x)] soln_real_1 = (y, x, 0) soln_real_2 = (-exp(x/2)*Abs(x), x, z) soln_real_3 = (exp(x/2)*Abs(x), x, z) soln_complex_1 = (-x*exp(x/2), x, z) soln_complex_2 = (x*exp(x/2), x, z) syms = [y, x, z] soln = FiniteSet(soln_real_1, soln_complex_1, soln_complex_2,\ soln_real_2, soln_real_3) assert nonlinsolve(system,syms) == soln def test_nonlinsolve_complex(): n = Dummy('n') assert dumeq(nonlinsolve([exp(x) - sin(y), 1/y - 3], [x, y]), { (ImageSet(Lambda(n, 2*n*I*pi + log(sin(Rational(1, 3)))), S.Integers), Rational(1, 3))}) system = [exp(x) - sin(y), 1/exp(y) - 3] assert dumeq(nonlinsolve(system, [x, y]), { (ImageSet(Lambda(n, I*(2*n*pi + pi) + log(sin(log(3)))), S.Integers), -log(3)), (ImageSet(Lambda(n, I*(2*n*pi + arg(sin(2*n*I*pi - log(3)))) + log(Abs(sin(2*n*I*pi - log(3))))), S.Integers), ImageSet(Lambda(n, 2*n*I*pi - log(3)), S.Integers))}) system = [exp(x) - sin(y), y**2 - 4] assert dumeq(nonlinsolve(system, [x, y]), { (ImageSet(Lambda(n, I*(2*n*pi + pi) + log(sin(2))), S.Integers), -2), (ImageSet(Lambda(n, 2*n*I*pi + log(sin(2))), S.Integers), 2)}) @XFAIL def test_solve_nonlinear_trans(): # After the transcendental equation solver these will work x, y, z = symbols('x, y, z', real=True) soln1 = FiniteSet((2*LambertW(y/2), y)) soln2 = FiniteSet((-x*sqrt(exp(x)), y), (x*sqrt(exp(x)), y)) soln3 = FiniteSet((x*exp(x/2), x)) soln4 = FiniteSet(2*LambertW(y/2), y) assert nonlinsolve([x**2 - y**2/exp(x)], [x, y]) == soln1 assert nonlinsolve([x**2 - y**2/exp(x)], [y, x]) == soln2 assert nonlinsolve([x**2 - y**2/exp(x)], [y, x]) == soln3 assert nonlinsolve([x**2 - y**2/exp(x)], [x, y]) == soln4 def test_issue_19050(): # test_issue_19050 --> TypeError removed assert dumeq(nonlinsolve([x + y, sin(y)], [x, y]), FiniteSet((ImageSet(Lambda(n, -2*n*pi), S.Integers), ImageSet(Lambda(n, 2*n*pi), S.Integers)),\ (ImageSet(Lambda(n, -2*n*pi - pi), S.Integers), ImageSet(Lambda(n, 2*n*pi + pi), S.Integers)))) assert dumeq(nonlinsolve([x + y, sin(y) + cos(y)], [x, y]), FiniteSet((ImageSet(Lambda(n, -2*n*pi - 3*pi/4), S.Integers), ImageSet(Lambda(n, 2*n*pi + 3*pi/4), S.Integers)), \ (ImageSet(Lambda(n, -2*n*pi - 7*pi/4), S.Integers), ImageSet(Lambda(n, 2*n*pi + 7*pi/4), S.Integers)))) def test_issue_16618(): # AttributeError is removed ! eqn = [sin(x)*sin(y), cos(x)*cos(y) - 1] ans = FiniteSet((x, 2*n*pi), (2*n*pi, y), (x, 2*n*pi + pi), (2*n*pi + pi, y)) sol = nonlinsolve(eqn, [x, y]) for i0, j0 in zip(ordered(sol), ordered(ans)): assert len(i0) == len(j0) == 2 assert all(a.dummy_eq(b) for a, b in zip(i0, j0)) assert len(sol) == len(ans) def test_issue_17566(): assert nonlinsolve([32*(2**x)/2**(-y) - 4**y, 27*(3**x) - 1/3**y], x, y) ==\ FiniteSet((-log(81)/log(3), 1)) def test_issue_19587(): n,m = symbols('n m') assert nonlinsolve([32*2**m*2**n - 4**n, 27*3**m - 3**(-n)], m, n) ==\ FiniteSet((-log(81)/log(3), 1)) def test_issue_5132_1(): system = [sqrt(x**2 + y**2) - sqrt(10), x + y - 4] assert nonlinsolve(system, [x, y]) == FiniteSet((1, 3), (3, 1)) n = Dummy('n') eqs = [exp(x)**2 - sin(y) + z**2, 1/exp(y) - 3] s_real_y = -log(3) s_real_z = sqrt(-exp(2*x) - sin(log(3))) soln_real = FiniteSet((s_real_y, s_real_z), (s_real_y, -s_real_z)) lam = Lambda(n, 2*n*I*pi + -log(3)) s_complex_y = ImageSet(lam, S.Integers) lam = Lambda(n, sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) s_complex_z_1 = ImageSet(lam, S.Integers) lam = Lambda(n, -sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) s_complex_z_2 = ImageSet(lam, S.Integers) soln_complex = FiniteSet( (s_complex_y, s_complex_z_1), (s_complex_y, s_complex_z_2) ) soln = soln_real + soln_complex assert dumeq(nonlinsolve(eqs, [y, z]), soln) def test_issue_5132_2(): x, y = symbols('x, y', real=True) eqs = [exp(x)**2 - sin(y) + z**2, 1/exp(y) - 3] n = Dummy('n') soln_real = (log(-z**2 + sin(y))/2, z) lam = Lambda( n, I*(2*n*pi + arg(-z**2 + sin(y)))/2 + log(Abs(z**2 - sin(y)))/2) img = ImageSet(lam, S.Integers) # not sure about the complex soln. But it looks correct. soln_complex = (img, z) soln = FiniteSet(soln_real, soln_complex) assert dumeq(nonlinsolve(eqs, [x, z]), soln) system = [r - x**2 - y**2, tan(t) - y/x] s_x = sqrt(r/(tan(t)**2 + 1)) s_y = sqrt(r/(tan(t)**2 + 1))*tan(t) soln = FiniteSet((s_x, s_y), (-s_x, -s_y)) assert nonlinsolve(system, [x, y]) == soln def test_issue_6752(): a,b,c,d = symbols('a, b, c, d', real=True) assert nonlinsolve([a**2 + a, a - b], [a, b]) == {(-1, -1), (0, 0)} @SKIP("slow") def test_issue_5114_solveset(): # slow testcase from sympy.abc import d, e, f, g, h, i, j, k, l, o, p, q, r # there is no 'a' in the equation set but this is how the # problem was originally posed syms = [a, b, c, f, h, k, n] eqs = [b + r/d - c/d, c*(1/d + 1/e + 1/g) - f/g - r/d, f*(1/g + 1/i + 1/j) - c/g - h/i, h*(1/i + 1/l + 1/m) - f/i - k/m, k*(1/m + 1/o + 1/p) - h/m - n/p, n*(1/p + 1/q) - k/p] assert len(nonlinsolve(eqs, syms)) == 1 @SKIP("Hangs") def _test_issue_5335(): # Not able to check zero dimensional system. # is_zero_dimensional Hangs lam, a0, conc = symbols('lam a0 conc') eqs = [lam + 2*y - a0*(1 - x/2)*x - 0.005*x/2*x, a0*(1 - x/2)*x - 1*y - 0.743436700916726*y, x + y - conc] sym = [x, y, a0] # there are 4 solutions but only two are valid assert len(nonlinsolve(eqs, sym)) == 2 # float eqs = [lam + 2*y - a0*(1 - x/2)*x - 0.005*x/2*x, a0*(1 - x/2)*x - 1*y - 0.743436700916726*y, x + y - conc] sym = [x, y, a0] assert len(nonlinsolve(eqs, sym)) == 2 def test_issue_2777(): # the equations represent two circles x, y = symbols('x y', real=True) e1, e2 = sqrt(x**2 + y**2) - 10, sqrt(y**2 + (-x + 10)**2) - 3 a, b = Rational(191, 20), 3*sqrt(391)/20 ans = {(a, -b), (a, b)} assert nonlinsolve((e1, e2), (x, y)) == ans assert nonlinsolve((e1, e2/(x - a)), (x, y)) == S.EmptySet # make the 2nd circle's radius be -3 e2 += 6 assert nonlinsolve((e1, e2), (x, y)) == S.EmptySet def test_issue_8828(): x1 = 0 y1 = -620 r1 = 920 x2 = 126 y2 = 276 x3 = 51 y3 = 205 r3 = 104 v = [x, y, z] f1 = (x - x1)**2 + (y - y1)**2 - (r1 - z)**2 f2 = (x2 - x)**2 + (y2 - y)**2 - z**2 f3 = (x - x3)**2 + (y - y3)**2 - (r3 - z)**2 F = [f1, f2, f3] g1 = sqrt((x - x1)**2 + (y - y1)**2) + z - r1 g2 = f2 g3 = sqrt((x - x3)**2 + (y - y3)**2) + z - r3 G = [g1, g2, g3] # both soln same A = nonlinsolve(F, v) B = nonlinsolve(G, v) assert A == B def test_nonlinsolve_conditionset(): # when solveset failed to solve all the eq # return conditionset f = Function('f') f1 = f(x) - pi/2 f2 = f(y) - pi*Rational(3, 2) intermediate_system = Eq(2*f(x) - pi, 0) & Eq(2*f(y) - 3*pi, 0) symbols = Tuple(x, y) soln = ConditionSet( symbols, intermediate_system, S.Complexes**2) assert nonlinsolve([f1, f2], [x, y]) == soln def test_substitution_basic(): assert substitution([], [x, y]) == S.EmptySet assert substitution([], []) == S.EmptySet system = [2*x**2 + 3*y**2 - 30, 3*x**2 - 2*y**2 - 19] soln = FiniteSet((-3, -2), (-3, 2), (3, -2), (3, 2)) assert substitution(system, [x, y]) == soln soln = FiniteSet((-1, 1)) assert substitution([x + y], [x], [{y: 1}], [y], set(), [x, y]) == soln assert substitution( [x + y], [x], [{y: 1}], [y], {x + 1}, [y, x]) == S.EmptySet def test_issue_5132_substitution(): x, y, z, r, t = symbols('x, y, z, r, t', real=True) system = [r - x**2 - y**2, tan(t) - y/x] s_x_1 = Complement(FiniteSet(-sqrt(r/(tan(t)**2 + 1))), FiniteSet(0)) s_x_2 = Complement(FiniteSet(sqrt(r/(tan(t)**2 + 1))), FiniteSet(0)) s_y = sqrt(r/(tan(t)**2 + 1))*tan(t) soln = FiniteSet((s_x_2, s_y)) + FiniteSet((s_x_1, -s_y)) assert substitution(system, [x, y]) == soln n = Dummy('n') eqs = [exp(x)**2 - sin(y) + z**2, 1/exp(y) - 3] s_real_y = -log(3) s_real_z = sqrt(-exp(2*x) - sin(log(3))) soln_real = FiniteSet((s_real_y, s_real_z), (s_real_y, -s_real_z)) lam = Lambda(n, 2*n*I*pi + -log(3)) s_complex_y = ImageSet(lam, S.Integers) lam = Lambda(n, sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) s_complex_z_1 = ImageSet(lam, S.Integers) lam = Lambda(n, -sqrt(-exp(2*x) + sin(2*n*I*pi + -log(3)))) s_complex_z_2 = ImageSet(lam, S.Integers) soln_complex = FiniteSet( (s_complex_y, s_complex_z_1), (s_complex_y, s_complex_z_2)) soln = soln_real + soln_complex assert dumeq(substitution(eqs, [y, z]), soln) def test_raises_substitution(): raises(ValueError, lambda: substitution([x**2 -1], [])) raises(TypeError, lambda: substitution([x**2 -1])) raises(ValueError, lambda: substitution([x**2 -1], [sin(x)])) raises(TypeError, lambda: substitution([x**2 -1], x)) raises(TypeError, lambda: substitution([x**2 -1], 1)) def test_issue_21022(): from sympy.core.sympify import sympify eqs = [ 'k-16', 'p-8', 'y*y+z*z-x*x', 'd - x + p', 'd*d+k*k-y*y', 'z*z-p*p-k*k', 'abc-efg', ] efg = Symbol('efg') eqs = [sympify(x) for x in eqs] syb = list(ordered(set.union(*[x.free_symbols for x in eqs]))) res = nonlinsolve(eqs, syb) ans = FiniteSet( (efg, sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16), efg, 16, 8, 8 + sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16), sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16, -8*sqrt(5)), (efg, sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16), efg, 16, 8, 8 + sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16), sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16, 8*sqrt(5)), (efg, -sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16), efg, 16, 8, -sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16) + 8, sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16, -8*sqrt(5)), (efg, -sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16), efg, 16, 8, -sqrt(-16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16)*sqrt(16 + sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16) + 8, sqrt(640 - 128*sqrt(5))*sqrt(128*sqrt(5) + 640)/16, 8*sqrt(5)) ) assert len(res) == len(ans) == 4 assert res == ans for result in res.args: assert len(result) == 8 def test_issue_17933(): eq1 = x*sin(45) - y*cos(q) eq2 = x*cos(45) - y*sin(q) eq3 = 9*x*sin(45)/10 + y*cos(q) eq4 = 9*x*cos(45)/10 + y*sin(z) - z assert nonlinsolve([eq1, eq2, eq3, eq4], x, y, z, q) ==\ FiniteSet((0, 0, 0, q)) def test_issue_14565(): # removed redundancy assert dumeq(nonlinsolve([k + m, k + m*exp(-2*pi*k)], [k, m]) , FiniteSet((-n*I, ImageSet(Lambda(n, n*I), S.Integers)))) # end of tests for nonlinsolve def test_issue_9556(): b = Symbol('b', positive=True) assert solveset(Abs(x) + 1, x, S.Reals) == EmptySet() assert solveset(Abs(x) + b, x, S.Reals) == EmptySet() assert solveset(Eq(b, -1), b, S.Reals) == EmptySet() def test_issue_9611(): assert solveset(Eq(x - x + a, a), x, S.Reals) == S.Reals assert solveset(Eq(y - y + a, a), y) == S.Complexes def test_issue_9557(): assert solveset(x**2 + a, x, S.Reals) == Intersection(S.Reals, FiniteSet(-sqrt(-a), sqrt(-a))) def test_issue_9778(): x = Symbol('x', real=True) y = Symbol('y', real=True) assert solveset(x**3 + 1, x, S.Reals) == FiniteSet(-1) assert solveset(x**Rational(3, 5) + 1, x, S.Reals) == S.EmptySet assert solveset(x**3 + y, x, S.Reals) == \ FiniteSet(-Abs(y)**Rational(1, 3)*sign(y)) def test_issue_10214(): assert solveset(x**Rational(3, 2) + 4, x, S.Reals) == S.EmptySet assert solveset(x**(Rational(-3, 2)) + 4, x, S.Reals) == S.EmptySet ans = FiniteSet(-2**Rational(2, 3)) assert solveset(x**(S(3)) + 4, x, S.Reals) == ans assert (x**(S(3)) + 4).subs(x,list(ans)[0]) == 0 # substituting ans and verifying the result. assert (x**(S(3)) + 4).subs(x,-(-2)**Rational(2, 3)) == 0 def test_issue_9849(): assert solveset(Abs(sin(x)) + 1, x, S.Reals) == S.EmptySet def test_issue_9953(): assert linsolve([ ], x) == S.EmptySet def test_issue_9913(): assert solveset(2*x + 1/(x - 10)**2, x, S.Reals) == \ FiniteSet(-(3*sqrt(24081)/4 + Rational(4027, 4))**Rational(1, 3)/3 - 100/ (3*(3*sqrt(24081)/4 + Rational(4027, 4))**Rational(1, 3)) + Rational(20, 3)) def test_issue_10397(): assert solveset(sqrt(x), x, S.Complexes) == FiniteSet(0) def test_issue_14987(): raises(ValueError, lambda: linear_eq_to_matrix( [x**2], x)) raises(ValueError, lambda: linear_eq_to_matrix( [x*(-3/x + 1) + 2*y - a], [x, y])) raises(ValueError, lambda: linear_eq_to_matrix( [(x**2 - 3*x)/(x - 3) - 3], x)) raises(ValueError, lambda: linear_eq_to_matrix( [(x + 1)**3 - x**3 - 3*x**2 + 7], x)) raises(ValueError, lambda: linear_eq_to_matrix( [x*(1/x + 1) + y], [x, y])) raises(ValueError, lambda: linear_eq_to_matrix( [(x + 1)*y], [x, y])) raises(ValueError, lambda: linear_eq_to_matrix( [Eq(1/x, 1/x + y)], [x, y])) raises(ValueError, lambda: linear_eq_to_matrix( [Eq(y/x, y/x + y)], [x, y])) raises(ValueError, lambda: linear_eq_to_matrix( [Eq(x*(x + 1), x**2 + y)], [x, y])) def test_simplification(): eq = x + (a - b)/(-2*a + 2*b) assert solveset(eq, x) == FiniteSet(S.Half) assert solveset(eq, x, S.Reals) == Intersection({-((a - b)/(-2*a + 2*b))}, S.Reals) # So that ap - bn is not zero: ap = Symbol('ap', positive=True) bn = Symbol('bn', negative=True) eq = x + (ap - bn)/(-2*ap + 2*bn) assert solveset(eq, x) == FiniteSet(S.Half) assert solveset(eq, x, S.Reals) == FiniteSet(S.Half) def test_integer_domain_relational(): eq1 = 2*x + 3 > 0 eq2 = x**2 + 3*x - 2 >= 0 eq3 = x + 1/x > -2 + 1/x eq4 = x + sqrt(x**2 - 5) > 0 eq = x + 1/x > -2 + 1/x eq5 = eq.subs(x,log(x)) eq6 = log(x)/x <= 0 eq7 = log(x)/x < 0 eq8 = x/(x-3) < 3 eq9 = x/(x**2-3) < 3 assert solveset(eq1, x, S.Integers) == Range(-1, oo, 1) assert solveset(eq2, x, S.Integers) == Union(Range(-oo, -3, 1), Range(1, oo, 1)) assert solveset(eq3, x, S.Integers) == Union(Range(-1, 0, 1), Range(1, oo, 1)) assert solveset(eq4, x, S.Integers) == Range(3, oo, 1) assert solveset(eq5, x, S.Integers) == Range(2, oo, 1) assert solveset(eq6, x, S.Integers) == Range(1, 2, 1) assert solveset(eq7, x, S.Integers) == S.EmptySet assert solveset(eq8, x, domain=Range(0,5)) == Range(0, 3, 1) assert solveset(eq9, x, domain=Range(0,5)) == Union(Range(0, 2, 1), Range(2, 5, 1)) # test_issue_19794 assert solveset(x + 2 < 0, x, S.Integers) == Range(-oo, -2, 1) def test_issue_10555(): f = Function('f') g = Function('g') assert solveset(f(x) - pi/2, x, S.Reals).dummy_eq( ConditionSet(x, Eq(f(x) - pi/2, 0), S.Reals)) assert solveset(f(g(x)) - pi/2, g(x), S.Reals).dummy_eq( ConditionSet(g(x), Eq(f(g(x)) - pi/2, 0), S.Reals)) def test_issue_8715(): eq = x + 1/x > -2 + 1/x assert solveset(eq, x, S.Reals) == \ (Interval.open(-2, oo) - FiniteSet(0)) assert solveset(eq.subs(x,log(x)), x, S.Reals) == \ Interval.open(exp(-2), oo) - FiniteSet(1) def test_issue_11174(): eq = z**2 + exp(2*x) - sin(y) soln = Intersection(S.Reals, FiniteSet(log(-z**2 + sin(y))/2)) assert solveset(eq, x, S.Reals) == soln eq = sqrt(r)*Abs(tan(t))/sqrt(tan(t)**2 + 1) + x*tan(t) s = -sqrt(r)*Abs(tan(t))/(sqrt(tan(t)**2 + 1)*tan(t)) soln = Intersection(S.Reals, FiniteSet(s)) assert solveset(eq, x, S.Reals) == soln def test_issue_11534(): # eq and eq2 should give the same solution as a Complement x = Symbol('x', real=True) y = Symbol('y', real=True) eq = -y + x/sqrt(-x**2 + 1) eq2 = -y**2 + x**2/(-x**2 + 1) soln = Complement(FiniteSet(-y/sqrt(y**2 + 1), y/sqrt(y**2 + 1)), FiniteSet(-1, 1)) assert solveset(eq, x, S.Reals) == soln assert solveset(eq2, x, S.Reals) == soln def test_issue_10477(): assert solveset((x**2 + 4*x - 3)/x < 2, x, S.Reals) == \ Union(Interval.open(-oo, -3), Interval.open(0, 1)) def test_issue_10671(): assert solveset(sin(y), y, Interval(0, pi)) == FiniteSet(0, pi) i = Interval(1, 10) assert solveset((1/x).diff(x) < 0, x, i) == i def test_issue_11064(): eq = x + sqrt(x**2 - 5) assert solveset(eq > 0, x, S.Reals) == \ Interval(sqrt(5), oo) assert solveset(eq < 0, x, S.Reals) == \ Interval(-oo, -sqrt(5)) assert solveset(eq > sqrt(5), x, S.Reals) == \ Interval.Lopen(sqrt(5), oo) def test_issue_12478(): eq = sqrt(x - 2) + 2 soln = solveset_real(eq, x) assert soln is S.EmptySet assert solveset(eq < 0, x, S.Reals) is S.EmptySet assert solveset(eq > 0, x, S.Reals) == Interval(2, oo) def test_issue_12429(): eq = solveset(log(x)/x <= 0, x, S.Reals) sol = Interval.Lopen(0, 1) assert eq == sol def test_solveset_arg(): assert solveset(arg(x), x, S.Reals) == Interval.open(0, oo) assert solveset(arg(4*x -3), x) == Interval.open(Rational(3, 4), oo) def test__is_finite_with_finite_vars(): f = _is_finite_with_finite_vars # issue 12482 assert all(f(1/x) is None for x in ( Dummy(), Dummy(real=True), Dummy(complex=True))) assert f(1/Dummy(real=False)) is True # b/c it's finite but not 0 def test_issue_13550(): assert solveset(x**2 - 2*x - 15, symbol = x, domain = Interval(-oo, 0)) == FiniteSet(-3) def test_issue_13849(): assert nonlinsolve((t*(sqrt(5) + sqrt(2)) - sqrt(2), t), t) == EmptySet() def test_issue_14223(): assert solveset((Abs(x + Min(x, 2)) - 2).rewrite(Piecewise), x, S.Reals) == FiniteSet(-1, 1) assert solveset((Abs(x + Min(x, 2)) - 2).rewrite(Piecewise), x, Interval(0, 2)) == FiniteSet(1) def test_issue_10158(): dom = S.Reals assert solveset(x*Max(x, 15) - 10, x, dom) == FiniteSet(Rational(2, 3)) assert solveset(x*Min(x, 15) - 10, x, dom) == FiniteSet(-sqrt(10), sqrt(10)) assert solveset(Max(Abs(x - 3) - 1, x + 2) - 3, x, dom) == FiniteSet(-1, 1) assert solveset(Abs(x - 1) - Abs(y), x, dom) == FiniteSet(-Abs(y) + 1, Abs(y) + 1) assert solveset(Abs(x + 4*Abs(x + 1)), x, dom) == FiniteSet(Rational(-4, 3), Rational(-4, 5)) assert solveset(2*Abs(x + Abs(x + Max(3, x))) - 2, x, S.Reals) == FiniteSet(-1, -2) dom = S.Complexes raises(ValueError, lambda: solveset(x*Max(x, 15) - 10, x, dom)) raises(ValueError, lambda: solveset(x*Min(x, 15) - 10, x, dom)) raises(ValueError, lambda: solveset(Max(Abs(x - 3) - 1, x + 2) - 3, x, dom)) raises(ValueError, lambda: solveset(Abs(x - 1) - Abs(y), x, dom)) raises(ValueError, lambda: solveset(Abs(x + 4*Abs(x + 1)), x, dom)) def test_issue_14300(): f = 1 - exp(-18000000*x) - y a1 = FiniteSet(-log(-y + 1)/18000000) assert solveset(f, x, S.Reals) == \ Intersection(S.Reals, a1) assert dumeq(solveset(f, x), ImageSet(Lambda(n, -I*(2*n*pi + arg(-y + 1))/18000000 - log(Abs(y - 1))/18000000), S.Integers)) def test_issue_14454(): number = CRootOf(x**4 + x - 1, 2) raises(ValueError, lambda: invert_real(number, 0, x, S.Reals)) assert invert_real(x**2, number, x, S.Reals) # no error def test_issue_17882(): assert solveset(-8*x**2/(9*(x**2 - 1)**(S(4)/3)) + 4/(3*(x**2 - 1)**(S(1)/3)), x, S.Complexes) == \ FiniteSet(sqrt(3), -sqrt(3)) def test_term_factors(): assert list(_term_factors(3**x - 2)) == [-2, 3**x] expr = 4**(x + 1) + 4**(x + 2) + 4**(x - 1) - 3**(x + 2) - 3**(x + 3) assert set(_term_factors(expr)) == { 3**(x + 2), 4**(x + 2), 3**(x + 3), 4**(x - 1), -1, 4**(x + 1)} #################### tests for transolve and its helpers ############### def test_transolve(): assert _transolve(3**x, x, S.Reals) == S.EmptySet assert _transolve(3**x - 9**(x + 5), x, S.Reals) == FiniteSet(-10) def test_issue_21276(): eq = (2*x*(y - z) - y*erf(y - z) - y + z*erf(y - z) + z)**2 assert solveset(eq.expand(), y) == FiniteSet(z, z + erfinv(2*x - 1)) # exponential tests def test_exponential_real(): from sympy.abc import x, y, z e1 = 3**(2*x) - 2**(x + 3) e2 = 4**(5 - 9*x) - 8**(2 - x) e3 = 2**x + 4**x e4 = exp(log(5)*x) - 2**x e5 = exp(x/y)*exp(-z/y) - 2 e6 = 5**(x/2) - 2**(x/3) e7 = 4**(x + 1) + 4**(x + 2) + 4**(x - 1) - 3**(x + 2) - 3**(x + 3) e8 = -9*exp(-2*x + 5) + 4*exp(3*x + 1) e9 = 2**x + 4**x + 8**x - 84 e10 = 29*2**(x + 1)*615**(x) - 123*2726**(x) assert solveset(e1, x, S.Reals) == FiniteSet( -3*log(2)/(-2*log(3) + log(2))) assert solveset(e2, x, S.Reals) == FiniteSet(Rational(4, 15)) assert solveset(e3, x, S.Reals) == S.EmptySet assert solveset(e4, x, S.Reals) == FiniteSet(0) assert solveset(e5, x, S.Reals) == Intersection( S.Reals, FiniteSet(y*log(2*exp(z/y)))) assert solveset(e6, x, S.Reals) == FiniteSet(0) assert solveset(e7, x, S.Reals) == FiniteSet(2) assert solveset(e8, x, S.Reals) == FiniteSet(-2*log(2)/5 + 2*log(3)/5 + Rational(4, 5)) assert solveset(e9, x, S.Reals) == FiniteSet(2) assert solveset(e10,x, S.Reals) == FiniteSet((-log(29) - log(2) + log(123))/(-log(2726) + log(2) + log(615))) assert solveset_real(-9*exp(-2*x + 5) + 2**(x + 1), x) == FiniteSet( -((-5 - 2*log(3) + log(2))/(log(2) + 2))) assert solveset_real(4**(x/2) - 2**(x/3), x) == FiniteSet(0) b = sqrt(6)*sqrt(log(2))/sqrt(log(5)) assert solveset_real(5**(x/2) - 2**(3/x), x) == FiniteSet(-b, b) # coverage test C1, C2 = symbols('C1 C2') f = Function('f') assert solveset_real(C1 + C2/x**2 - exp(-f(x)), f(x)) == Intersection( S.Reals, FiniteSet(-log(C1 + C2/x**2))) y = symbols('y', positive=True) assert solveset_real(x**2 - y**2/exp(x), y) == Intersection( S.Reals, FiniteSet(-sqrt(x**2*exp(x)), sqrt(x**2*exp(x)))) p = Symbol('p', positive=True) assert solveset_real((1/p + 1)**(p + 1), p).dummy_eq( ConditionSet(x, Eq((1 + 1/x)**(x + 1), 0), S.Reals)) @XFAIL def test_exponential_complex(): from sympy.abc import x from sympy import Dummy n = Dummy('n') assert dumeq(solveset_complex(2**x + 4**x, x),imageset( Lambda(n, I*(2*n*pi + pi)/log(2)), S.Integers)) assert solveset_complex(x**z*y**z - 2, z) == FiniteSet( log(2)/(log(x) + log(y))) assert dumeq(solveset_complex(4**(x/2) - 2**(x/3), x), imageset( Lambda(n, 3*n*I*pi/log(2)), S.Integers)) assert dumeq(solveset(2**x + 32, x), imageset( Lambda(n, (I*(2*n*pi + pi) + 5*log(2))/log(2)), S.Integers)) eq = (2**exp(y**2/x) + 2)/(x**2 + 15) a = sqrt(x)*sqrt(-log(log(2)) + log(log(2) + 2*n*I*pi)) assert solveset_complex(eq, y) == FiniteSet(-a, a) union1 = imageset(Lambda(n, I*(2*n*pi - pi*Rational(2, 3))/log(2)), S.Integers) union2 = imageset(Lambda(n, I*(2*n*pi + pi*Rational(2, 3))/log(2)), S.Integers) assert dumeq(solveset(2**x + 4**x + 8**x, x), Union(union1, union2)) eq = 4**(x + 1) + 4**(x + 2) + 4**(x - 1) - 3**(x + 2) - 3**(x + 3) res = solveset(eq, x) num = 2*n*I*pi - 4*log(2) + 2*log(3) den = -2*log(2) + log(3) ans = imageset(Lambda(n, num/den), S.Integers) assert dumeq(res, ans) def test_expo_conditionset(): f1 = (exp(x) + 1)**x - 2 f2 = (x + 2)**y*x - 3 f3 = 2**x - exp(x) - 3 f4 = log(x) - exp(x) f5 = 2**x + 3**x - 5**x assert solveset(f1, x, S.Reals).dummy_eq(ConditionSet( x, Eq((exp(x) + 1)**x - 2, 0), S.Reals)) assert solveset(f2, x, S.Reals).dummy_eq(ConditionSet( x, Eq(x*(x + 2)**y - 3, 0), S.Reals)) assert solveset(f3, x, S.Reals).dummy_eq(ConditionSet( x, Eq(2**x - exp(x) - 3, 0), S.Reals)) assert solveset(f4, x, S.Reals).dummy_eq(ConditionSet( x, Eq(-exp(x) + log(x), 0), S.Reals)) assert solveset(f5, x, S.Reals).dummy_eq(ConditionSet( x, Eq(2**x + 3**x - 5**x, 0), S.Reals)) def test_exponential_symbols(): x, y, z = symbols('x y z', positive=True) xr, zr = symbols('xr, zr', real=True) assert solveset(z**x - y, x, S.Reals) == Intersection( S.Reals, FiniteSet(log(y)/log(z))) f1 = 2*x**w - 4*y**w f2 = (x/y)**w - 2 sol1 = Intersection({log(2)/(log(x) - log(y))}, S.Reals) sol2 = Intersection({log(2)/log(x/y)}, S.Reals) assert solveset(f1, w, S.Reals) == sol1, solveset(f1, w, S.Reals) assert solveset(f2, w, S.Reals) == sol2, solveset(f2, w, S.Reals) assert solveset(x**x, x, Interval.Lopen(0,oo)).dummy_eq( ConditionSet(w, Eq(w**w, 0), Interval.open(0, oo))) assert solveset(x**y - 1, y, S.Reals) == FiniteSet(0) assert solveset(exp(x/y)*exp(-z/y) - 2, y, S.Reals) == \ Complement(ConditionSet(y, Eq(im(x)/y, 0) & Eq(im(z)/y, 0), \ Complement(Intersection(FiniteSet((x - z)/log(2)), S.Reals), FiniteSet(0))), FiniteSet(0)) assert solveset(exp(xr/y)*exp(-zr/y) - 2, y, S.Reals) == \ Complement(FiniteSet((xr - zr)/log(2)), FiniteSet(0)) assert solveset(a**x - b**x, x).dummy_eq(ConditionSet( w, Ne(a, 0) & Ne(b, 0), FiniteSet(0))) def test_ignore_assumptions(): # make sure assumptions are ignored xpos = symbols('x', positive=True) x = symbols('x') assert solveset_complex(xpos**2 - 4, xpos ) == solveset_complex(x**2 - 4, x) @XFAIL def test_issue_10864(): assert solveset(x**(y*z) - x, x, S.Reals) == FiniteSet(1) @XFAIL def test_solve_only_exp_2(): assert solveset_real(sqrt(exp(x)) + sqrt(exp(-x)) - 4, x) == \ FiniteSet(2*log(-sqrt(3) + 2), 2*log(sqrt(3) + 2)) def test_is_exponential(): assert _is_exponential(y, x) is False assert _is_exponential(3**x - 2, x) is True assert _is_exponential(5**x - 7**(2 - x), x) is True assert _is_exponential(sin(2**x) - 4*x, x) is False assert _is_exponential(x**y - z, y) is True assert _is_exponential(x**y - z, x) is False assert _is_exponential(2**x + 4**x - 1, x) is True assert _is_exponential(x**(y*z) - x, x) is False assert _is_exponential(x**(2*x) - 3**x, x) is False assert _is_exponential(x**y - y*z, y) is False assert _is_exponential(x**y - x*z, y) is True def test_solve_exponential(): assert _solve_exponential(3**(2*x) - 2**(x + 3), 0, x, S.Reals) == \ FiniteSet(-3*log(2)/(-2*log(3) + log(2))) assert _solve_exponential(2**y + 4**y, 1, y, S.Reals) == \ FiniteSet(log(Rational(-1, 2) + sqrt(5)/2)/log(2)) assert _solve_exponential(2**y + 4**y, 0, y, S.Reals) == \ S.EmptySet assert _solve_exponential(2**x + 3**x - 5**x, 0, x, S.Reals) == \ ConditionSet(x, Eq(2**x + 3**x - 5**x, 0), S.Reals) # end of exponential tests # logarithmic tests def test_logarithmic(): assert solveset_real(log(x - 3) + log(x + 3), x) == FiniteSet( -sqrt(10), sqrt(10)) assert solveset_real(log(x + 1) - log(2*x - 1), x) == FiniteSet(2) assert solveset_real(log(x + 3) + log(1 + 3/x) - 3, x) == FiniteSet( -3 + sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 + exp(3)/2, -sqrt(-12 + exp(3))*exp(Rational(3, 2))/2 - 3 + exp(3)/2) eq = z - log(x) + log(y/(x*(-1 + y**2/x**2))) assert solveset_real(eq, x) == \ Intersection(S.Reals, FiniteSet(-sqrt(y**2 - y*exp(z)), sqrt(y**2 - y*exp(z)))) - \ Intersection(S.Reals, FiniteSet(-sqrt(y**2), sqrt(y**2))) assert solveset_real( log(3*x) - log(-x + 1) - log(4*x + 1), x) == FiniteSet(Rational(-1, 2), S.Half) assert solveset(log(x**y) - y*log(x), x, S.Reals) == S.Reals @XFAIL def test_uselogcombine_2(): eq = log(exp(2*x) + 1) + log(-tanh(x) + 1) - log(2) assert solveset_real(eq, x) == EmptySet() eq = log(8*x) - log(sqrt(x) + 1) - 2 assert solveset_real(eq, x) == EmptySet() def test_is_logarithmic(): assert _is_logarithmic(y, x) is False assert _is_logarithmic(log(x), x) is True assert _is_logarithmic(log(x) - 3, x) is True assert _is_logarithmic(log(x)*log(y), x) is True assert _is_logarithmic(log(x)**2, x) is False assert _is_logarithmic(log(x - 3) + log(x + 3), x) is True assert _is_logarithmic(log(x**y) - y*log(x), x) is True assert _is_logarithmic(sin(log(x)), x) is False assert _is_logarithmic(x + y, x) is False assert _is_logarithmic(log(3*x) - log(1 - x) + 4, x) is True assert _is_logarithmic(log(x) + log(y) + x, x) is False assert _is_logarithmic(log(log(x - 3)) + log(x - 3), x) is True assert _is_logarithmic(log(log(3) + x) + log(x), x) is True assert _is_logarithmic(log(x)*(y + 3) + log(x), y) is False def test_solve_logarithm(): y = Symbol('y') assert _solve_logarithm(log(x**y) - y*log(x), 0, x, S.Reals) == S.Reals y = Symbol('y', positive=True) assert _solve_logarithm(log(x)*log(y), 0, x, S.Reals) == FiniteSet(1) # end of logarithmic tests # lambert tests def test_is_lambert(): a, b, c = symbols('a,b,c') assert _is_lambert(x**2, x) is False assert _is_lambert(a**x**2+b*x+c, x) is True assert _is_lambert(E**2, x) is False assert _is_lambert(x*E**2, x) is False assert _is_lambert(3*log(x) - x*log(3), x) is True assert _is_lambert(log(log(x - 3)) + log(x-3), x) is True assert _is_lambert(5*x - 1 + 3*exp(2 - 7*x), x) is True assert _is_lambert((a/x + exp(x/2)).diff(x, 2), x) is True assert _is_lambert((x**2 - 2*x + 1).subs(x, (log(x) + 3*x)**2 - 1), x) is True assert _is_lambert(x*sinh(x) - 1, x) is True assert _is_lambert(x*cos(x) - 5, x) is True assert _is_lambert(tanh(x) - 5*x, x) is True assert _is_lambert(cosh(x) - sinh(x), x) is False # end of lambert tests def test_linear_coeffs(): from sympy.solvers.solveset import linear_coeffs assert linear_coeffs(0, x) == [0, 0] assert all(i is S.Zero for i in linear_coeffs(0, x)) assert linear_coeffs(x + 2*y + 3, x, y) == [1, 2, 3] assert linear_coeffs(x + 2*y + 3, y, x) == [2, 1, 3] assert linear_coeffs(x + 2*x**2 + 3, x, x**2) == [1, 2, 3] raises(ValueError, lambda: linear_coeffs(x + 2*x**2 + x**3, x, x**2)) raises(ValueError, lambda: linear_coeffs(1/x*(x - 1) + 1/x, x)) assert linear_coeffs(a*(x + y), x, y) == [a, a, 0] assert linear_coeffs(1.0, x, y) == [0, 0, 1.0] # modular tests def test_is_modular(): assert _is_modular(y, x) is False assert _is_modular(Mod(x, 3) - 1, x) is True assert _is_modular(Mod(x**3 - 3*x**2 - x + 1, 3) - 1, x) is True assert _is_modular(Mod(exp(x + y), 3) - 2, x) is True assert _is_modular(Mod(exp(x + y), 3) - log(x), x) is True assert _is_modular(Mod(x, 3) - 1, y) is False assert _is_modular(Mod(x, 3)**2 - 5, x) is False assert _is_modular(Mod(x, 3)**2 - y, x) is False assert _is_modular(exp(Mod(x, 3)) - 1, x) is False assert _is_modular(Mod(3, y) - 1, y) is False def test_invert_modular(): n = Dummy('n', integer=True) from sympy.solvers.solveset import _invert_modular as invert_modular # non invertible cases assert invert_modular(Mod(sin(x), 7), S(5), n, x) == (Mod(sin(x), 7), 5) assert invert_modular(Mod(exp(x), 7), S(5), n, x) == (Mod(exp(x), 7), 5) assert invert_modular(Mod(log(x), 7), S(5), n, x) == (Mod(log(x), 7), 5) # a is symbol assert dumeq(invert_modular(Mod(x, 7), S(5), n, x), (x, ImageSet(Lambda(n, 7*n + 5), S.Integers))) # a.is_Add assert dumeq(invert_modular(Mod(x + 8, 7), S(5), n, x), (x, ImageSet(Lambda(n, 7*n + 4), S.Integers))) assert invert_modular(Mod(x**2 + x, 7), S(5), n, x) == \ (Mod(x**2 + x, 7), 5) # a.is_Mul assert dumeq(invert_modular(Mod(3*x, 7), S(5), n, x), (x, ImageSet(Lambda(n, 7*n + 4), S.Integers))) assert invert_modular(Mod((x + 1)*(x + 2), 7), S(5), n, x) == \ (Mod((x + 1)*(x + 2), 7), 5) # a.is_Pow assert invert_modular(Mod(x**4, 7), S(5), n, x) == \ (x, EmptySet()) assert dumeq(invert_modular(Mod(3**x, 4), S(3), n, x), (x, ImageSet(Lambda(n, 2*n + 1), S.Naturals0))) assert dumeq(invert_modular(Mod(2**(x**2 + x + 1), 7), S(2), n, x), (x**2 + x + 1, ImageSet(Lambda(n, 3*n + 1), S.Naturals0))) assert invert_modular(Mod(sin(x)**4, 7), S(5), n, x) == (x, EmptySet()) def test_solve_modular(): n = Dummy('n', integer=True) # if rhs has symbol (need to be implemented in future). assert solveset(Mod(x, 4) - x, x, S.Integers ).dummy_eq( ConditionSet(x, Eq(-x + Mod(x, 4), 0), S.Integers)) # when _invert_modular fails to invert assert solveset(3 - Mod(sin(x), 7), x, S.Integers ).dummy_eq( ConditionSet(x, Eq(Mod(sin(x), 7) - 3, 0), S.Integers)) assert solveset(3 - Mod(log(x), 7), x, S.Integers ).dummy_eq( ConditionSet(x, Eq(Mod(log(x), 7) - 3, 0), S.Integers)) assert solveset(3 - Mod(exp(x), 7), x, S.Integers ).dummy_eq(ConditionSet(x, Eq(Mod(exp(x), 7) - 3, 0), S.Integers)) # EmptySet solution definitely assert solveset(7 - Mod(x, 5), x, S.Integers) == EmptySet() assert solveset(5 - Mod(x, 5), x, S.Integers) == EmptySet() # Negative m assert dumeq(solveset(2 + Mod(x, -3), x, S.Integers), ImageSet(Lambda(n, -3*n - 2), S.Integers)) assert solveset(4 + Mod(x, -3), x, S.Integers) == EmptySet() # linear expression in Mod assert dumeq(solveset(3 - Mod(x, 5), x, S.Integers), ImageSet(Lambda(n, 5*n + 3), S.Integers)) assert dumeq(solveset(3 - Mod(5*x - 8, 7), x, S.Integers), ImageSet(Lambda(n, 7*n + 5), S.Integers)) assert dumeq(solveset(3 - Mod(5*x, 7), x, S.Integers), ImageSet(Lambda(n, 7*n + 2), S.Integers)) # higher degree expression in Mod assert dumeq(solveset(Mod(x**2, 160) - 9, x, S.Integers), Union(ImageSet(Lambda(n, 160*n + 3), S.Integers), ImageSet(Lambda(n, 160*n + 13), S.Integers), ImageSet(Lambda(n, 160*n + 67), S.Integers), ImageSet(Lambda(n, 160*n + 77), S.Integers), ImageSet(Lambda(n, 160*n + 83), S.Integers), ImageSet(Lambda(n, 160*n + 93), S.Integers), ImageSet(Lambda(n, 160*n + 147), S.Integers), ImageSet(Lambda(n, 160*n + 157), S.Integers))) assert solveset(3 - Mod(x**4, 7), x, S.Integers) == EmptySet() assert dumeq(solveset(Mod(x**4, 17) - 13, x, S.Integers), Union(ImageSet(Lambda(n, 17*n + 3), S.Integers), ImageSet(Lambda(n, 17*n + 5), S.Integers), ImageSet(Lambda(n, 17*n + 12), S.Integers), ImageSet(Lambda(n, 17*n + 14), S.Integers))) # a.is_Pow tests assert dumeq(solveset(Mod(7**x, 41) - 15, x, S.Integers), ImageSet(Lambda(n, 40*n + 3), S.Naturals0)) assert dumeq(solveset(Mod(12**x, 21) - 18, x, S.Integers), ImageSet(Lambda(n, 6*n + 2), S.Naturals0)) assert dumeq(solveset(Mod(3**x, 4) - 3, x, S.Integers), ImageSet(Lambda(n, 2*n + 1), S.Naturals0)) assert dumeq(solveset(Mod(2**x, 7) - 2 , x, S.Integers), ImageSet(Lambda(n, 3*n + 1), S.Naturals0)) assert dumeq(solveset(Mod(3**(3**x), 4) - 3, x, S.Integers), Intersection(ImageSet(Lambda(n, Intersection({log(2*n + 1)/log(3)}, S.Integers)), S.Naturals0), S.Integers)) # Implemented for m without primitive root assert solveset(Mod(x**3, 7) - 2, x, S.Integers) == EmptySet() assert dumeq(solveset(Mod(x**3, 8) - 1, x, S.Integers), ImageSet(Lambda(n, 8*n + 1), S.Integers)) assert dumeq(solveset(Mod(x**4, 9) - 4, x, S.Integers), Union(ImageSet(Lambda(n, 9*n + 4), S.Integers), ImageSet(Lambda(n, 9*n + 5), S.Integers))) # domain intersection assert dumeq(solveset(3 - Mod(5*x - 8, 7), x, S.Naturals0), Intersection(ImageSet(Lambda(n, 7*n + 5), S.Integers), S.Naturals0)) # Complex args assert solveset(Mod(x, 3) - I, x, S.Integers) == \ EmptySet() assert solveset(Mod(I*x, 3) - 2, x, S.Integers ).dummy_eq( ConditionSet(x, Eq(Mod(I*x, 3) - 2, 0), S.Integers)) assert solveset(Mod(I + x, 3) - 2, x, S.Integers ).dummy_eq( ConditionSet(x, Eq(Mod(x + I, 3) - 2, 0), S.Integers)) # issue 17373 (https://github.com/sympy/sympy/issues/17373) assert dumeq(solveset(Mod(x**4, 14) - 11, x, S.Integers), Union(ImageSet(Lambda(n, 14*n + 3), S.Integers), ImageSet(Lambda(n, 14*n + 11), S.Integers))) assert dumeq(solveset(Mod(x**31, 74) - 43, x, S.Integers), ImageSet(Lambda(n, 74*n + 31), S.Integers)) # issue 13178 n = symbols('n', integer=True) a = 742938285 b = 1898888478 m = 2**31 - 1 c = 20170816 assert dumeq(solveset(c - Mod(a**n*b, m), n, S.Integers), ImageSet(Lambda(n, 2147483646*n + 100), S.Naturals0)) assert dumeq(solveset(c - Mod(a**n*b, m), n, S.Naturals0), Intersection(ImageSet(Lambda(n, 2147483646*n + 100), S.Naturals0), S.Naturals0)) assert dumeq(solveset(c - Mod(a**(2*n)*b, m), n, S.Integers), Intersection(ImageSet(Lambda(n, 1073741823*n + 50), S.Naturals0), S.Integers)) assert solveset(c - Mod(a**(2*n + 7)*b, m), n, S.Integers) == EmptySet() assert dumeq(solveset(c - Mod(a**(n - 4)*b, m), n, S.Integers), Intersection(ImageSet(Lambda(n, 2147483646*n + 104), S.Naturals0), S.Integers)) # end of modular tests def test_issue_17276(): assert nonlinsolve([Eq(x, 5**(S(1)/5)), Eq(x*y, 25*sqrt(5))], x, y) == \ FiniteSet((5**(S(1)/5), 25*5**(S(3)/10))) def test_issue_10426(): x = Dummy('x') a = Symbol('a') n = Dummy('n') assert (solveset(sin(x + a) - sin(x), a)).dummy_eq(Dummy('x')) == (Union( ImageSet(Lambda(n, 2*n*pi), S.Integers), Intersection(S.Complexes, ImageSet(Lambda(n, -I*(I*(2*n*pi + arg(-exp(-2*I*x))) + 2*im(x))), S.Integers)))).dummy_eq(Dummy('x,n')) def test_issue_18208(): vars = symbols('x0:16') + symbols('y0:12') x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15,\ y0, y1, y2, y3, y4, y5, y6, y7, y8, y9, y10, y11 = vars eqs = [x0 + x1 + x2 + x3 - 51, x0 + x1 + x4 + x5 - 46, x2 + x3 + x6 + x7 - 39, x0 + x3 + x4 + x7 - 50, x1 + x2 + x5 + x6 - 35, x4 + x5 + x6 + x7 - 34, x4 + x5 + x8 + x9 - 46, x10 + x11 + x6 + x7 - 23, x11 + x4 + x7 + x8 - 25, x10 + x5 + x6 + x9 - 44, x10 + x11 + x8 + x9 - 35, x12 + x13 + x8 + x9 - 35, x10 + x11 + x14 + x15 - 29, x11 + x12 + x15 + x8 - 35, x10 + x13 + x14 + x9 - 29, x12 + x13 + x14 + x15 - 29, y0 + y1 + y2 + y3 - 55, y0 + y1 + y4 + y5 - 53, y2 + y3 + y6 + y7 - 56, y0 + y3 + y4 + y7 - 57, y1 + y2 + y5 + y6 - 52, y4 + y5 + y6 + y7 - 54, y4 + y5 + y8 + y9 - 48, y10 + y11 + y6 + y7 - 60, y11 + y4 + y7 + y8 - 51, y10 + y5 + y6 + y9 - 57, y10 + y11 + y8 + y9 - 54, x10 - 2, x11 - 5, x12 - 1, x13 - 6, x14 - 1, x15 - 21, y0 - 12, y1 - 20] expected = [38 - x3, x3 - 10, 23 - x3, x3, 12 - x7, x7 + 6, 16 - x7, x7, 8, 20, 2, 5, 1, 6, 1, 21, 12, 20, -y11 + y9 + 2, y11 - y9 + 21, -y11 - y7 + y9 + 24, y11 + y7 - y9 - 3, 33 - y7, y7, 27 - y9, y9, 27 - y11, y11] A, b = linear_eq_to_matrix(eqs, vars) # solve solve_expected = {v:eq for v, eq in zip(vars, expected) if v != eq} assert solve(eqs, vars) == solve_expected # linsolve linsolve_expected = FiniteSet(Tuple(*expected)) assert linsolve(eqs, vars) == linsolve_expected assert linsolve((A, b), vars) == linsolve_expected # gauss_jordan_solve gj_solve, new_vars = A.gauss_jordan_solve(b) gj_solve = [i for i in gj_solve] tau0, tau1, tau2, tau3, tau4 = symbols([str(v) for v in new_vars]) gj_expected = linsolve_expected.subs(zip([x3, x7, y7, y9, y11], new_vars)) assert FiniteSet(Tuple(*gj_solve)) == gj_expected # nonlinsolve # The solution set of nonlinsolve is currently equivalent to linsolve and is # also correct. However, we would prefer to use the same symbols as parameters # for the solution to the underdetermined system in all cases if possible. # We want a solution that is not just equivalent but also given in the same form. # This test may be changed should nonlinsolve be modified in this way. nonlinsolve_expected = FiniteSet((38 - x3, x3 - 10, 23 - x3, x3, 12 - x7, x7 + 6, 16 - x7, x7, 8, 20, 2, 5, 1, 6, 1, 21, 12, 20, -y5 + y7 - 1, y5 - y7 + 24, 21 - y5, y5, 33 - y7, y7, 27 - y9, y9, -y5 + y7 - y9 + 24, y5 - y7 + y9 + 3)) assert nonlinsolve(eqs, vars) == nonlinsolve_expected @XFAIL def test_substitution_with_infeasible_solution(): a00, a01, a10, a11, l0, l1, l2, l3, m0, m1, m2, m3, m4, m5, m6, m7, c00, c01, c10, c11, p00, p01, p10, p11 = symbols( 'a00, a01, a10, a11, l0, l1, l2, l3, m0, m1, m2, m3, m4, m5, m6, m7, c00, c01, c10, c11, p00, p01, p10, p11' ) solvefor = [p00, p01, p10, p11, c00, c01, c10, c11, m0, m1, m3, l0, l1, l2, l3] system = [ -l0 * c00 - l1 * c01 + m0 + c00 + c01, -l0 * c10 - l1 * c11 + m1, -l2 * c00 - l3 * c01 + c00 + c01, -l2 * c10 - l3 * c11 + m3, -l0 * p00 - l2 * p10 + p00 + p10, -l1 * p00 - l3 * p10 + p00 + p10, -l0 * p01 - l2 * p11, -l1 * p01 - l3 * p11, -a00 + c00 * p00 + c10 * p01, -a01 + c01 * p00 + c11 * p01, -a10 + c00 * p10 + c10 * p11, -a11 + c01 * p10 + c11 * p11, -m0 * p00, -m1 * p01, -m2 * p10, -m3 * p11, -m4 * c00, -m5 * c01, -m6 * c10, -m7 * c11, m2, m4, m5, m6, m7 ] sol = FiniteSet( (0, Complement(FiniteSet(p01), FiniteSet(0)), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, l2, l3), (p00, Complement(FiniteSet(p01), FiniteSet(0)), 0, p11, 0, 0, 0, 0, 0, 0, 0, 1, 1, -p01/p11, -p01/p11), (0, Complement(FiniteSet(p01), FiniteSet(0)), 0, p11, 0, 0, 0, 0, 0, 0, 0, 1, -l3*p11/p01, -p01/p11, l3), (0, Complement(FiniteSet(p01), FiniteSet(0)), 0, p11, 0, 0, 0, 0, 0, 0, 0, -l2*p11/p01, -l3*p11/p01, l2, l3), ) assert sol != nonlinsolve(system, solvefor) def test_issue_20097(): assert solveset(1/sqrt(x)) == EmptySet() def test_issue_15350(): assert solveset(diff(sqrt(1/x+x))) == FiniteSet(-1, 1) def test_issue_18359(): c1 = Piecewise((0, x < 0), (Min(1, x)/2 - Min(2, x)/2 + Min(3, x)/2, True)) c2 = Piecewise((Piecewise((0, x < 0), (Min(1, x)/2 - Min(2, x)/2 + Min(3, x)/2, True)), x >= 0), (0, True)) correct_result = Interval(1, 2) result1 = solveset(c1 - Rational(1, 2), x, Interval(0, 3)) result2 = solveset(c2 - Rational(1, 2), x, Interval(0, 3)) assert result1 == correct_result assert result2 == correct_result def test_issue_17604(): lhs = -2**(3*x/11)*exp(x/11) + pi**(x/11) assert _is_exponential(lhs, x) assert _solve_exponential(lhs, 0, x, S.Complexes) == FiniteSet(0) def test_issue_17580(): assert solveset(1/(1 - x**3)**2, x, S.Reals) == EmptySet() def test_issue_17566_actual(): sys = [2**x + 2**y - 3, 4**x + 9**y - 5] # Not clear this is the correct result, but at least no recursion error assert nonlinsolve(sys, x, y) == FiniteSet((log(3 - 2**y)/log(2), y)) def test_issue_17565(): eq = Ge(2*(x - 2)**2/(3*(x + 1)**(Integer(1)/3)) + 2*(x - 2)*(x + 1)**(Integer(2)/3), 0) res = Union(Interval.Lopen(-1, -Rational(1, 4)), Interval(2, oo)) assert solveset(eq, x, S.Reals) == res def test_issue_15024(): function = (x + 5)/sqrt(-x**2 - 10*x) assert solveset(function, x, S.Reals) == FiniteSet(Integer(-5)) def test_issue_16877(): assert dumeq(nonlinsolve([x - 1, sin(y)], x, y), FiniteSet((FiniteSet(1), ImageSet(Lambda(n, 2*n*pi), S.Integers)), (FiniteSet(1), ImageSet(Lambda(n, 2*n*pi + pi), S.Integers)))) # Even better if (FiniteSet(1), ImageSet(Lambda(n, n*pi), S.Integers)) is obtained def test_issue_16876(): assert dumeq(nonlinsolve([sin(x), 2*x - 4*y], x, y), FiniteSet((ImageSet(Lambda(n, 2*n*pi), S.Integers), ImageSet(Lambda(n, n*pi), S.Integers)), (ImageSet(Lambda(n, 2*n*pi + pi), S.Integers), ImageSet(Lambda(n, n*pi + pi/2), S.Integers)))) # Even better if (ImageSet(Lambda(n, n*pi), S.Integers), # ImageSet(Lambda(n, n*pi/2), S.Integers)) is obtained def test_issue_21236(): x, z = symbols("x z") y = symbols('y', rational=True) assert solveset(x**y - z, x, S.Reals) == ConditionSet(x, Eq(x**y - z, 0), S.Reals) e1, e2 = symbols('e1 e2', even=True) y = e1/e2 # don't know if num or den will be odd and the other even assert solveset(x**y - z, x, S.Reals) == ConditionSet(x, Eq(x**y - z, 0), S.Reals) def test_issue_21908(): assert nonlinsolve([(x**2 + 2*x - y**2)*exp(x), -2*y*exp(x)], x, y ) == {(-2, 0), (0, 0)} def test_issue_22058(): sol = solveset(-sqrt(t)*x**2 + 2*x + sqrt(t), x, S.Reals) # doesn't fail (and following numerical check) assert sol.xreplace({t: 1}) == {1 - sqrt(2), 1 + sqrt(2)}, sol.xreplace({t: 1}) sympy-sympy-1.9/sympy/stats/000077500000000000000000000000001412543434000162425ustar00rootroot00000000000000sympy-sympy-1.9/sympy/stats/__init__.py000066400000000000000000000204061412543434000203550ustar00rootroot00000000000000""" SymPy statistics module Introduces a random variable type into the SymPy language. Random variables may be declared using prebuilt functions such as Normal, Exponential, Coin, Die, etc... or built with functions like FiniteRV. Queries on random expressions can be made using the functions ========================= ============================= Expression Meaning ------------------------- ----------------------------- ``P(condition)`` Probability ``E(expression)`` Expected value ``H(expression)`` Entropy ``variance(expression)`` Variance ``density(expression)`` Probability Density Function ``sample(expression)`` Produce a realization ``where(condition)`` Where the condition is true ========================= ============================= Examples ======== >>> from sympy.stats import P, E, variance, Die, Normal >>> from sympy import Eq, simplify >>> X, Y = Die('X', 6), Die('Y', 6) # Define two six sided dice >>> Z = Normal('Z', 0, 1) # Declare a Normal random variable with mean 0, std 1 >>> P(X>3) # Probability X is greater than 3 1/2 >>> E(X+Y) # Expectation of the sum of two dice 7 >>> variance(X+Y) # Variance of the sum of two dice 35/6 >>> simplify(P(Z>1)) # Probability of Z being greater than 1 1/2 - erf(sqrt(2)/2)/2 One could also create custom distribution and define custom random variables as follows: 1. If you want to create a Continuous Random Variable: >>> from sympy.stats import ContinuousRV, P, E >>> from sympy import exp, Symbol, Interval, oo >>> x = Symbol('x') >>> pdf = exp(-x) # pdf of the Continuous Distribution >>> Z = ContinuousRV(x, pdf, set=Interval(0, oo)) >>> E(Z) 1 >>> P(Z > 5) exp(-5) 1.1 To create an instance of Continuous Distribution: >>> from sympy.stats import ContinuousDistributionHandmade >>> from sympy import Lambda >>> dist = ContinuousDistributionHandmade(Lambda(x, pdf), set=Interval(0, oo)) >>> dist.pdf(x) exp(-x) 2. If you want to create a Discrete Random Variable: >>> from sympy.stats import DiscreteRV, P, E >>> from sympy import Symbol, S >>> p = S(1)/2 >>> x = Symbol('x', integer=True, positive=True) >>> pdf = p*(1 - p)**(x - 1) >>> D = DiscreteRV(x, pdf, set=S.Naturals) >>> E(D) 2 >>> P(D > 3) 1/8 2.1 To create an instance of Discrete Distribution: >>> from sympy.stats import DiscreteDistributionHandmade >>> from sympy import Lambda >>> dist = DiscreteDistributionHandmade(Lambda(x, pdf), set=S.Naturals) >>> dist.pdf(x) 2**(1 - x)/2 3. If you want to create a Finite Random Variable: >>> from sympy.stats import FiniteRV, P, E >>> from sympy import Rational >>> pmf = {1: Rational(1, 3), 2: Rational(1, 6), 3: Rational(1, 4), 4: Rational(1, 4)} >>> X = FiniteRV('X', pmf) >>> E(X) 29/12 >>> P(X > 3) 1/4 3.1 To create an instance of Finite Distribution: >>> from sympy.stats import FiniteDistributionHandmade >>> dist = FiniteDistributionHandmade(pmf) >>> dist.pmf(x) Lambda(x, Piecewise((1/3, Eq(x, 1)), (1/6, Eq(x, 2)), (1/4, Eq(x, 3) | Eq(x, 4)), (0, True))) """ __all__ = [ 'P', 'E', 'H', 'density', 'where', 'given', 'sample', 'cdf','median', 'characteristic_function', 'pspace', 'sample_iter', 'variance', 'std', 'skewness', 'kurtosis', 'covariance', 'dependent', 'entropy', 'independent', 'random_symbols', 'correlation', 'factorial_moment', 'moment', 'cmoment', 'sampling_density', 'moment_generating_function', 'smoment', 'quantile', 'coskewness', 'sample_stochastic_process', 'FiniteRV', 'DiscreteUniform', 'Die', 'Bernoulli', 'Coin', 'Binomial', 'BetaBinomial', 'Hypergeometric', 'Rademacher', 'IdealSoliton', 'RobustSoliton', 'FiniteDistributionHandmade', 'ContinuousRV', 'Arcsin', 'Benini', 'Beta', 'BetaNoncentral', 'BetaPrime', 'BoundedPareto', 'Cauchy', 'Chi', 'ChiNoncentral', 'ChiSquared', 'Dagum', 'Erlang', 'ExGaussian', 'Exponential', 'ExponentialPower', 'FDistribution', 'FisherZ', 'Frechet', 'Gamma', 'GammaInverse', 'Gompertz', 'Gumbel', 'Kumaraswamy', 'Laplace', 'Levy', 'Logistic','LogCauchy', 'LogLogistic', 'LogitNormal', 'LogNormal', 'Lomax', 'Moyal', 'Maxwell', 'Nakagami', 'Normal', 'GaussianInverse', 'Pareto', 'PowerFunction', 'QuadraticU', 'RaisedCosine', 'Rayleigh','Reciprocal', 'StudentT', 'ShiftedGompertz', 'Trapezoidal', 'Triangular', 'Uniform', 'UniformSum', 'VonMises', 'Wald', 'Weibull', 'WignerSemicircle', 'ContinuousDistributionHandmade', 'FlorySchulz', 'Geometric','Hermite', 'Logarithmic', 'NegativeBinomial', 'Poisson', 'Skellam', 'YuleSimon', 'Zeta', 'DiscreteRV', 'DiscreteDistributionHandmade', 'JointRV', 'Dirichlet', 'GeneralizedMultivariateLogGamma', 'GeneralizedMultivariateLogGammaOmega', 'Multinomial', 'MultivariateBeta', 'MultivariateEwens', 'MultivariateT', 'NegativeMultinomial', 'NormalGamma', 'MultivariateNormal', 'MultivariateLaplace', 'marginal_distribution', 'StochasticProcess', 'DiscreteTimeStochasticProcess', 'DiscreteMarkovChain', 'TransitionMatrixOf', 'StochasticStateSpaceOf', 'GeneratorMatrixOf', 'ContinuousMarkovChain', 'BernoulliProcess', 'PoissonProcess', 'WienerProcess', 'GammaProcess', 'CircularEnsemble', 'CircularUnitaryEnsemble', 'CircularOrthogonalEnsemble', 'CircularSymplecticEnsemble', 'GaussianEnsemble', 'GaussianUnitaryEnsemble', 'GaussianOrthogonalEnsemble', 'GaussianSymplecticEnsemble', 'joint_eigen_distribution', 'JointEigenDistribution', 'level_spacing_distribution', 'MatrixGamma', 'Wishart', 'MatrixNormal', 'MatrixStudentT', 'Probability', 'Expectation', 'Variance', 'Covariance', 'Moment', 'CentralMoment', 'ExpectationMatrix', 'VarianceMatrix', 'CrossCovarianceMatrix' ] from .rv_interface import (P, E, H, density, where, given, sample, cdf, median, characteristic_function, pspace, sample_iter, variance, std, skewness, kurtosis, covariance, dependent, entropy, independent, random_symbols, correlation, factorial_moment, moment, cmoment, sampling_density, moment_generating_function, smoment, quantile, coskewness, sample_stochastic_process) from .frv_types import (FiniteRV, DiscreteUniform, Die, Bernoulli, Coin, Binomial, BetaBinomial, Hypergeometric, Rademacher, FiniteDistributionHandmade, IdealSoliton, RobustSoliton) from .crv_types import (ContinuousRV, Arcsin, Benini, Beta, BetaNoncentral, BetaPrime, BoundedPareto, Cauchy, Chi, ChiNoncentral, ChiSquared, Dagum, Erlang, ExGaussian, Exponential, ExponentialPower, FDistribution, FisherZ, Frechet, Gamma, GammaInverse, Gompertz, Gumbel, Kumaraswamy, Laplace, Levy, Logistic,LogCauchy ,LogLogistic, LogitNormal, LogNormal, Lomax, Maxwell, Moyal, Nakagami, Normal, GaussianInverse, Pareto, QuadraticU, RaisedCosine, Rayleigh, Reciprocal, StudentT, PowerFunction, ShiftedGompertz, Trapezoidal, Triangular, Uniform, UniformSum, VonMises, Wald, Weibull, WignerSemicircle, ContinuousDistributionHandmade) from .drv_types import (FlorySchulz, Geometric, Hermite, Logarithmic, NegativeBinomial, Poisson, Skellam, YuleSimon, Zeta, DiscreteRV, DiscreteDistributionHandmade) from .joint_rv_types import (JointRV, Dirichlet, GeneralizedMultivariateLogGamma, GeneralizedMultivariateLogGammaOmega, Multinomial, MultivariateBeta, MultivariateEwens, MultivariateT, NegativeMultinomial, NormalGamma, MultivariateNormal, MultivariateLaplace, marginal_distribution) from .stochastic_process_types import (StochasticProcess, DiscreteTimeStochasticProcess, DiscreteMarkovChain, TransitionMatrixOf, StochasticStateSpaceOf, GeneratorMatrixOf, ContinuousMarkovChain, BernoulliProcess, PoissonProcess, WienerProcess, GammaProcess) from .random_matrix_models import (CircularEnsemble, CircularUnitaryEnsemble, CircularOrthogonalEnsemble, CircularSymplecticEnsemble, GaussianEnsemble, GaussianUnitaryEnsemble, GaussianOrthogonalEnsemble, GaussianSymplecticEnsemble, joint_eigen_distribution, JointEigenDistribution, level_spacing_distribution) from .matrix_distributions import MatrixGamma, Wishart, MatrixNormal, MatrixStudentT from .symbolic_probability import (Probability, Expectation, Variance, Covariance, Moment, CentralMoment) from .symbolic_multivariate_probability import (ExpectationMatrix, VarianceMatrix, CrossCovarianceMatrix) sympy-sympy-1.9/sympy/stats/compound_rv.py000066400000000000000000000172121412543434000211520ustar00rootroot00000000000000from sympy import Basic, Sum, Dummy, Lambda, Integral from sympy.stats.rv import (NamedArgsMixin, random_symbols, _symbol_converter, PSpace, RandomSymbol, is_random, Distribution) from sympy.stats.crv import ContinuousDistribution, SingleContinuousPSpace from sympy.stats.drv import DiscreteDistribution, SingleDiscretePSpace from sympy.stats.frv import SingleFiniteDistribution, SingleFinitePSpace from sympy.stats.crv_types import ContinuousDistributionHandmade from sympy.stats.drv_types import DiscreteDistributionHandmade from sympy.stats.frv_types import FiniteDistributionHandmade class CompoundPSpace(PSpace): """ A temporary Probability Space for the Compound Distribution. After Marginalization, this returns the corresponding Probability Space of the parent distribution. """ def __new__(cls, s, distribution): s = _symbol_converter(s) if isinstance(distribution, ContinuousDistribution): return SingleContinuousPSpace(s, distribution) if isinstance(distribution, DiscreteDistribution): return SingleDiscretePSpace(s, distribution) if isinstance(distribution, SingleFiniteDistribution): return SingleFinitePSpace(s, distribution) if not isinstance(distribution, CompoundDistribution): raise ValueError("%s should be an isinstance of " "CompoundDistribution"%(distribution)) return Basic.__new__(cls, s, distribution) @property def value(self): return RandomSymbol(self.symbol, self) @property def symbol(self): return self.args[0] @property def is_Continuous(self): return self.distribution.is_Continuous @property def is_Finite(self): return self.distribution.is_Finite @property def is_Discrete(self): return self.distribution.is_Discrete @property def distribution(self): return self.args[1] @property def pdf(self): return self.distribution.pdf(self.symbol) @property def set(self): return self.distribution.set @property def domain(self): return self._get_newpspace().domain def _get_newpspace(self, evaluate=False): x = Dummy('x') parent_dist = self.distribution.args[0] func = Lambda(x, self.distribution.pdf(x, evaluate)) new_pspace = self._transform_pspace(self.symbol, parent_dist, func) if new_pspace is not None: return new_pspace message = ("Compound Distribution for %s is not implemeted yet" % str(parent_dist)) raise NotImplementedError(message) def _transform_pspace(self, sym, dist, pdf): """ This function returns the new pspace of the distribution using handmade Distributions and their corresponding pspace. """ pdf = Lambda(sym, pdf(sym)) _set = dist.set if isinstance(dist, ContinuousDistribution): return SingleContinuousPSpace(sym, ContinuousDistributionHandmade(pdf, _set)) elif isinstance(dist, DiscreteDistribution): return SingleDiscretePSpace(sym, DiscreteDistributionHandmade(pdf, _set)) elif isinstance(dist, SingleFiniteDistribution): dens = {k: pdf(k) for k in _set} return SingleFinitePSpace(sym, FiniteDistributionHandmade(dens)) def compute_density(self, expr, *, compound_evaluate=True, **kwargs): new_pspace = self._get_newpspace(compound_evaluate) expr = expr.subs({self.value: new_pspace.value}) return new_pspace.compute_density(expr, **kwargs) def compute_cdf(self, expr, *, compound_evaluate=True, **kwargs): new_pspace = self._get_newpspace(compound_evaluate) expr = expr.subs({self.value: new_pspace.value}) return new_pspace.compute_cdf(expr, **kwargs) def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): new_pspace = self._get_newpspace(evaluate) expr = expr.subs({self.value: new_pspace.value}) if rvs: rvs = rvs.subs({self.value: new_pspace.value}) if isinstance(new_pspace, SingleFinitePSpace): return new_pspace.compute_expectation(expr, rvs, **kwargs) return new_pspace.compute_expectation(expr, rvs, evaluate, **kwargs) def probability(self, condition, *, compound_evaluate=True, **kwargs): new_pspace = self._get_newpspace(compound_evaluate) condition = condition.subs({self.value: new_pspace.value}) return new_pspace.probability(condition) def conditional_space(self, condition, *, compound_evaluate=True, **kwargs): new_pspace = self._get_newpspace(compound_evaluate) condition = condition.subs({self.value: new_pspace.value}) return new_pspace.conditional_space(condition) class CompoundDistribution(Distribution, NamedArgsMixin): """ Class for Compound Distributions. Parameters ========== dist : Distribution Distribution must contain a random parameter Examples ======== >>> from sympy.stats.compound_rv import CompoundDistribution >>> from sympy.stats.crv_types import NormalDistribution >>> from sympy.stats import Normal >>> from sympy.abc import x >>> X = Normal('X', 2, 4) >>> N = NormalDistribution(X, 4) >>> C = CompoundDistribution(N) >>> C.set Interval(-oo, oo) >>> C.pdf(x, evaluate=True).simplify() exp(-x**2/64 + x/16 - 1/16)/(8*sqrt(pi)) References ========== .. [1] https://en.wikipedia.org/wiki/Compound_probability_distribution """ def __new__(cls, dist): if not isinstance(dist, (ContinuousDistribution, SingleFiniteDistribution, DiscreteDistribution)): message = "Compound Distribution for %s is not implemeted yet" % str(dist) raise NotImplementedError(message) if not cls._compound_check(dist): return dist return Basic.__new__(cls, dist) @property def set(self): return self.args[0].set @property def is_Continuous(self): return isinstance(self.args[0], ContinuousDistribution) @property def is_Finite(self): return isinstance(self.args[0], SingleFiniteDistribution) @property def is_Discrete(self): return isinstance(self.args[0], DiscreteDistribution) def pdf(self, x, evaluate=False): dist = self.args[0] randoms = [rv for rv in dist.args if is_random(rv)] if isinstance(dist, SingleFiniteDistribution): y = Dummy('y', integer=True, negative=False) expr = dist.pmf(y) else: y = Dummy('y') expr = dist.pdf(y) for rv in randoms: expr = self._marginalise(expr, rv, evaluate) return Lambda(y, expr)(x) def _marginalise(self, expr, rv, evaluate): if isinstance(rv.pspace.distribution, SingleFiniteDistribution): rv_dens = rv.pspace.distribution.pmf(rv) else: rv_dens = rv.pspace.distribution.pdf(rv) rv_dom = rv.pspace.domain.set if rv.pspace.is_Discrete or rv.pspace.is_Finite: expr = Sum(expr*rv_dens, (rv, rv_dom._inf, rv_dom._sup)) else: expr = Integral(expr*rv_dens, (rv, rv_dom._inf, rv_dom._sup)) if evaluate: return expr.doit() return expr @classmethod def _compound_check(self, dist): """ Checks if the given distribution contains random parameters. """ randoms = [] for arg in dist.args: randoms.extend(random_symbols(arg)) if len(randoms) == 0: return False return True sympy-sympy-1.9/sympy/stats/crv.py000066400000000000000000000500411412543434000174060ustar00rootroot00000000000000""" Continuous Random Variables Module See Also ======== sympy.stats.crv_types sympy.stats.rv sympy.stats.frv """ from sympy import (Interval, Intersection, symbols, sympify, Dummy, nan, Integral, And, Or, Piecewise, cacheit, integrate, oo, Lambda, Basic, S, exp, I, FiniteSet, Ne, Eq, Union, poly, series, factorial) from sympy.core.function import PoleError from sympy.functions.special.delta_functions import DiracDelta from sympy.polys.polyerrors import PolynomialError from sympy.solvers.solveset import solveset from sympy.solvers.inequalities import reduce_rational_inequalities from sympy.core.sympify import _sympify from sympy.stats.rv import (RandomDomain, SingleDomain, ConditionalDomain, is_random, ProductDomain, PSpace, SinglePSpace, random_symbols, NamedArgsMixin, Distribution) class ContinuousDomain(RandomDomain): """ A domain with continuous support Represented using symbols and Intervals. """ is_Continuous = True def as_boolean(self): raise NotImplementedError("Not Implemented for generic Domains") class SingleContinuousDomain(ContinuousDomain, SingleDomain): """ A univariate domain with continuous support Represented using a single symbol and interval. """ def compute_expectation(self, expr, variables=None, **kwargs): if variables is None: variables = self.symbols if not variables: return expr if frozenset(variables) != frozenset(self.symbols): raise ValueError("Values should be equal") # assumes only intervals return Integral(expr, (self.symbol, self.set), **kwargs) def as_boolean(self): return self.set.as_relational(self.symbol) class ProductContinuousDomain(ProductDomain, ContinuousDomain): """ A collection of independent domains with continuous support """ def compute_expectation(self, expr, variables=None, **kwargs): if variables is None: variables = self.symbols for domain in self.domains: domain_vars = frozenset(variables) & frozenset(domain.symbols) if domain_vars: expr = domain.compute_expectation(expr, domain_vars, **kwargs) return expr def as_boolean(self): return And(*[domain.as_boolean() for domain in self.domains]) class ConditionalContinuousDomain(ContinuousDomain, ConditionalDomain): """ A domain with continuous support that has been further restricted by a condition such as $x > 3$. """ def compute_expectation(self, expr, variables=None, **kwargs): if variables is None: variables = self.symbols if not variables: return expr # Extract the full integral fullintgrl = self.fulldomain.compute_expectation(expr, variables) # separate into integrand and limits integrand, limits = fullintgrl.function, list(fullintgrl.limits) conditions = [self.condition] while conditions: cond = conditions.pop() if cond.is_Boolean: if isinstance(cond, And): conditions.extend(cond.args) elif isinstance(cond, Or): raise NotImplementedError("Or not implemented here") elif cond.is_Relational: if cond.is_Equality: # Add the appropriate Delta to the integrand integrand *= DiracDelta(cond.lhs - cond.rhs) else: symbols = cond.free_symbols & set(self.symbols) if len(symbols) != 1: # Can't handle x > y raise NotImplementedError( "Multivariate Inequalities not yet implemented") # Can handle x > 0 symbol = symbols.pop() # Find the limit with x, such as (x, -oo, oo) for i, limit in enumerate(limits): if limit[0] == symbol: # Make condition into an Interval like [0, oo] cintvl = reduce_rational_inequalities_wrap( cond, symbol) # Make limit into an Interval like [-oo, oo] lintvl = Interval(limit[1], limit[2]) # Intersect them to get [0, oo] intvl = cintvl.intersect(lintvl) # Put back into limits list limits[i] = (symbol, intvl.left, intvl.right) else: raise TypeError( "Condition %s is not a relational or Boolean" % cond) return Integral(integrand, *limits, **kwargs) def as_boolean(self): return And(self.fulldomain.as_boolean(), self.condition) @property def set(self): if len(self.symbols) == 1: return (self.fulldomain.set & reduce_rational_inequalities_wrap( self.condition, tuple(self.symbols)[0])) else: raise NotImplementedError( "Set of Conditional Domain not Implemented") class ContinuousDistribution(Distribution): def __call__(self, *args): return self.pdf(*args) class SingleContinuousDistribution(ContinuousDistribution, NamedArgsMixin): """ Continuous distribution of a single variable. Explanation =========== Serves as superclass for Normal/Exponential/UniformDistribution etc.... Represented by parameters for each of the specific classes. E.g NormalDistribution is represented by a mean and standard deviation. Provides methods for pdf, cdf, and sampling. See Also ======== sympy.stats.crv_types.* """ set = Interval(-oo, oo) def __new__(cls, *args): args = list(map(sympify, args)) return Basic.__new__(cls, *args) @staticmethod def check(*args): pass @cacheit def compute_cdf(self, **kwargs): """ Compute the CDF from the PDF. Returns a Lambda. """ x, z = symbols('x, z', real=True, cls=Dummy) left_bound = self.set.start # CDF is integral of PDF from left bound to z pdf = self.pdf(x) cdf = integrate(pdf.doit(), (x, left_bound, z), **kwargs) # CDF Ensure that CDF left of left_bound is zero cdf = Piecewise((cdf, z >= left_bound), (0, True)) return Lambda(z, cdf) def _cdf(self, x): return None def cdf(self, x, **kwargs): """ Cumulative density function """ if len(kwargs) == 0: cdf = self._cdf(x) if cdf is not None: return cdf return self.compute_cdf(**kwargs)(x) @cacheit def compute_characteristic_function(self, **kwargs): """ Compute the characteristic function from the PDF. Returns a Lambda. """ x, t = symbols('x, t', real=True, cls=Dummy) pdf = self.pdf(x) cf = integrate(exp(I*t*x)*pdf, (x, self.set)) return Lambda(t, cf) def _characteristic_function(self, t): return None def characteristic_function(self, t, **kwargs): """ Characteristic function """ if len(kwargs) == 0: cf = self._characteristic_function(t) if cf is not None: return cf return self.compute_characteristic_function(**kwargs)(t) @cacheit def compute_moment_generating_function(self, **kwargs): """ Compute the moment generating function from the PDF. Returns a Lambda. """ x, t = symbols('x, t', real=True, cls=Dummy) pdf = self.pdf(x) mgf = integrate(exp(t * x) * pdf, (x, self.set)) return Lambda(t, mgf) def _moment_generating_function(self, t): return None def moment_generating_function(self, t, **kwargs): """ Moment generating function """ if not kwargs: mgf = self._moment_generating_function(t) if mgf is not None: return mgf return self.compute_moment_generating_function(**kwargs)(t) def expectation(self, expr, var, evaluate=True, **kwargs): """ Expectation of expression over distribution """ if evaluate: try: p = poly(expr, var) if p.is_zero: return S.Zero t = Dummy('t', real=True) mgf = self._moment_generating_function(t) if mgf is None: return integrate(expr * self.pdf(var), (var, self.set), **kwargs) deg = p.degree() taylor = poly(series(mgf, t, 0, deg + 1).removeO(), t) result = 0 for k in range(deg+1): result += p.coeff_monomial(var ** k) * taylor.coeff_monomial(t ** k) * factorial(k) return result except PolynomialError: return integrate(expr * self.pdf(var), (var, self.set), **kwargs) else: return Integral(expr * self.pdf(var), (var, self.set), **kwargs) @cacheit def compute_quantile(self, **kwargs): """ Compute the Quantile from the PDF. Returns a Lambda. """ x, p = symbols('x, p', real=True, cls=Dummy) left_bound = self.set.start pdf = self.pdf(x) cdf = integrate(pdf, (x, left_bound, x), **kwargs) quantile = solveset(cdf - p, x, self.set) return Lambda(p, Piecewise((quantile, (p >= 0) & (p <= 1) ), (nan, True))) def _quantile(self, x): return None def quantile(self, x, **kwargs): """ Cumulative density function """ if len(kwargs) == 0: quantile = self._quantile(x) if quantile is not None: return quantile return self.compute_quantile(**kwargs)(x) class ContinuousPSpace(PSpace): """ Continuous Probability Space Represents the likelihood of an event space defined over a continuum. Represented with a ContinuousDomain and a PDF (Lambda-Like) """ is_Continuous = True is_real = True @property def pdf(self): return self.density(*self.domain.symbols) def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): if rvs is None: rvs = self.values else: rvs = frozenset(rvs) expr = expr.xreplace({rv: rv.symbol for rv in rvs}) domain_symbols = frozenset(rv.symbol for rv in rvs) return self.domain.compute_expectation(self.pdf * expr, domain_symbols, **kwargs) def compute_density(self, expr, **kwargs): # Common case Density(X) where X in self.values if expr in self.values: # Marginalize all other random symbols out of the density randomsymbols = tuple(set(self.values) - frozenset([expr])) symbols = tuple(rs.symbol for rs in randomsymbols) pdf = self.domain.compute_expectation(self.pdf, symbols, **kwargs) return Lambda(expr.symbol, pdf) z = Dummy('z', real=True) return Lambda(z, self.compute_expectation(DiracDelta(expr - z), **kwargs)) @cacheit def compute_cdf(self, expr, **kwargs): if not self.domain.set.is_Interval: raise ValueError( "CDF not well defined on multivariate expressions") d = self.compute_density(expr, **kwargs) x, z = symbols('x, z', real=True, cls=Dummy) left_bound = self.domain.set.start # CDF is integral of PDF from left bound to z cdf = integrate(d(x), (x, left_bound, z), **kwargs) # CDF Ensure that CDF left of left_bound is zero cdf = Piecewise((cdf, z >= left_bound), (0, True)) return Lambda(z, cdf) @cacheit def compute_characteristic_function(self, expr, **kwargs): if not self.domain.set.is_Interval: raise NotImplementedError("Characteristic function of multivariate expressions not implemented") d = self.compute_density(expr, **kwargs) x, t = symbols('x, t', real=True, cls=Dummy) cf = integrate(exp(I*t*x)*d(x), (x, -oo, oo), **kwargs) return Lambda(t, cf) @cacheit def compute_moment_generating_function(self, expr, **kwargs): if not self.domain.set.is_Interval: raise NotImplementedError("Moment generating function of multivariate expressions not implemented") d = self.compute_density(expr, **kwargs) x, t = symbols('x, t', real=True, cls=Dummy) mgf = integrate(exp(t * x) * d(x), (x, -oo, oo), **kwargs) return Lambda(t, mgf) @cacheit def compute_quantile(self, expr, **kwargs): if not self.domain.set.is_Interval: raise ValueError( "Quantile not well defined on multivariate expressions") d = self.compute_cdf(expr, **kwargs) x = Dummy('x', real=True) p = Dummy('p', positive=True) quantile = solveset(d(x) - p, x, self.set) return Lambda(p, quantile) def probability(self, condition, **kwargs): z = Dummy('z', real=True) cond_inv = False if isinstance(condition, Ne): condition = Eq(condition.args[0], condition.args[1]) cond_inv = True # Univariate case can be handled by where try: domain = self.where(condition) rv = [rv for rv in self.values if rv.symbol == domain.symbol][0] # Integrate out all other random variables pdf = self.compute_density(rv, **kwargs) # return S.Zero if `domain` is empty set if domain.set is S.EmptySet or isinstance(domain.set, FiniteSet): return S.Zero if not cond_inv else S.One if isinstance(domain.set, Union): return sum( Integral(pdf(z), (z, subset), **kwargs) for subset in domain.set.args if isinstance(subset, Interval)) # Integrate out the last variable over the special domain return Integral(pdf(z), (z, domain.set), **kwargs) # Other cases can be turned into univariate case # by computing a density handled by density computation except NotImplementedError: from sympy.stats.rv import density expr = condition.lhs - condition.rhs if not is_random(expr): dens = self.density comp = condition.rhs else: dens = density(expr, **kwargs) comp = 0 if not isinstance(dens, ContinuousDistribution): from sympy.stats.crv_types import ContinuousDistributionHandmade dens = ContinuousDistributionHandmade(dens, set=self.domain.set) # Turn problem into univariate case space = SingleContinuousPSpace(z, dens) result = space.probability(condition.__class__(space.value, comp)) return result if not cond_inv else S.One - result def where(self, condition): rvs = frozenset(random_symbols(condition)) if not (len(rvs) == 1 and rvs.issubset(self.values)): raise NotImplementedError( "Multiple continuous random variables not supported") rv = tuple(rvs)[0] interval = reduce_rational_inequalities_wrap(condition, rv) interval = interval.intersect(self.domain.set) return SingleContinuousDomain(rv.symbol, interval) def conditional_space(self, condition, normalize=True, **kwargs): condition = condition.xreplace({rv: rv.symbol for rv in self.values}) domain = ConditionalContinuousDomain(self.domain, condition) if normalize: # create a clone of the variable to # make sure that variables in nested integrals are different # from the variables outside the integral # this makes sure that they are evaluated separately # and in the correct order replacement = {rv: Dummy(str(rv)) for rv in self.symbols} norm = domain.compute_expectation(self.pdf, **kwargs) pdf = self.pdf / norm.xreplace(replacement) # XXX: Converting set to tuple. The order matters to Lambda though # so we shouldn't be starting with a set here... density = Lambda(tuple(domain.symbols), pdf) return ContinuousPSpace(domain, density) class SingleContinuousPSpace(ContinuousPSpace, SinglePSpace): """ A continuous probability space over a single univariate variable. These consist of a Symbol and a SingleContinuousDistribution This class is normally accessed through the various random variable functions, Normal, Exponential, Uniform, etc.... """ @property def set(self): return self.distribution.set @property def domain(self): return SingleContinuousDomain(sympify(self.symbol), self.set) def sample(self, size=(), library='scipy', seed=None): """ Internal sample method. Returns dictionary mapping RandomSymbol to realization value. """ return {self.value: self.distribution.sample(size, library=library, seed=seed)} def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): rvs = rvs or (self.value,) if self.value not in rvs: return expr expr = _sympify(expr) expr = expr.xreplace({rv: rv.symbol for rv in rvs}) x = self.value.symbol try: return self.distribution.expectation(expr, x, evaluate=evaluate, **kwargs) except PoleError: return Integral(expr * self.pdf, (x, self.set), **kwargs) def compute_cdf(self, expr, **kwargs): if expr == self.value: z = Dummy("z", real=True) return Lambda(z, self.distribution.cdf(z, **kwargs)) else: return ContinuousPSpace.compute_cdf(self, expr, **kwargs) def compute_characteristic_function(self, expr, **kwargs): if expr == self.value: t = Dummy("t", real=True) return Lambda(t, self.distribution.characteristic_function(t, **kwargs)) else: return ContinuousPSpace.compute_characteristic_function(self, expr, **kwargs) def compute_moment_generating_function(self, expr, **kwargs): if expr == self.value: t = Dummy("t", real=True) return Lambda(t, self.distribution.moment_generating_function(t, **kwargs)) else: return ContinuousPSpace.compute_moment_generating_function(self, expr, **kwargs) def compute_density(self, expr, **kwargs): # https://en.wikipedia.org/wiki/Random_variable#Functions_of_random_variables if expr == self.value: return self.density y = Dummy('y', real=True) gs = solveset(expr - y, self.value, S.Reals) if isinstance(gs, Intersection) and S.Reals in gs.args: gs = list(gs.args[1]) if not gs: raise ValueError("Can not solve %s for %s"%(expr, self.value)) fx = self.compute_density(self.value) fy = sum(fx(g) * abs(g.diff(y)) for g in gs) return Lambda(y, fy) def compute_quantile(self, expr, **kwargs): if expr == self.value: p = Dummy("p", real=True) return Lambda(p, self.distribution.quantile(p, **kwargs)) else: return ContinuousPSpace.compute_quantile(self, expr, **kwargs) def _reduce_inequalities(conditions, var, **kwargs): try: return reduce_rational_inequalities(conditions, var, **kwargs) except PolynomialError: raise ValueError("Reduction of condition failed %s\n" % conditions[0]) def reduce_rational_inequalities_wrap(condition, var): if condition.is_Relational: return _reduce_inequalities([[condition]], var, relational=False) if isinstance(condition, Or): return Union(*[_reduce_inequalities([[arg]], var, relational=False) for arg in condition.args]) if isinstance(condition, And): intervals = [_reduce_inequalities([[arg]], var, relational=False) for arg in condition.args] I = intervals[0] for i in intervals: I = I.intersect(i) return I sympy-sympy-1.9/sympy/stats/crv_types.py000066400000000000000000003504561412543434000206470ustar00rootroot00000000000000""" Continuous Random Variables - Prebuilt variables Contains ======== Arcsin Benini Beta BetaNoncentral BetaPrime BoundedPareto Cauchy Chi ChiNoncentral ChiSquared Dagum Erlang ExGaussian Exponential ExponentialPower FDistribution FisherZ Frechet Gamma GammaInverse Gumbel Gompertz Kumaraswamy Laplace Levy LogCauchy Logistic LogLogistic LogitNormal LogNormal Lomax Maxwell Moyal Nakagami Normal Pareto PowerFunction QuadraticU RaisedCosine Rayleigh Reciprocal ShiftedGompertz StudentT Trapezoidal Triangular Uniform UniformSum VonMises Wald Weibull WignerSemicircle """ from sympy import beta as beta_fn from sympy import cos, sin, tan, atan, exp, besseli, besselj, besselk from sympy import (log, sqrt, pi, S, Dummy, Interval, sympify, gamma, sign, Piecewise, And, Eq, binomial, factorial, Sum, floor, Abs, Lambda, Basic, lowergamma, erf, erfc, erfi, erfinv, I, asin, hyper, uppergamma, sinh, Ne, expint, Rational, integrate) from sympy.matrices import MatrixBase from sympy.stats.crv import SingleContinuousPSpace, SingleContinuousDistribution from sympy.stats.rv import _value_check, is_random oo = S.Infinity __all__ = ['ContinuousRV', 'Arcsin', 'Benini', 'Beta', 'BetaNoncentral', 'BetaPrime', 'BoundedPareto', 'Cauchy', 'Chi', 'ChiNoncentral', 'ChiSquared', 'Dagum', 'Erlang', 'ExGaussian', 'Exponential', 'ExponentialPower', 'FDistribution', 'FisherZ', 'Frechet', 'Gamma', 'GammaInverse', 'Gompertz', 'Gumbel', 'Kumaraswamy', 'Laplace', 'Levy', 'LogCauchy', 'Logistic', 'LogLogistic', 'LogitNormal', 'LogNormal', 'Lomax', 'Maxwell', 'Moyal', 'Nakagami', 'Normal', 'GaussianInverse', 'Pareto', 'PowerFunction', 'QuadraticU', 'RaisedCosine', 'Rayleigh', 'Reciprocal', 'StudentT', 'ShiftedGompertz', 'Trapezoidal', 'Triangular', 'Uniform', 'UniformSum', 'VonMises', 'Wald', 'Weibull', 'WignerSemicircle', ] @is_random.register(MatrixBase) def _(x): return any([is_random(i) for i in x]) def rv(symbol, cls, args, **kwargs): args = list(map(sympify, args)) dist = cls(*args) if kwargs.pop('check', True): dist.check(*args) pspace = SingleContinuousPSpace(symbol, dist) if any(is_random(arg) for arg in args): from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution pspace = CompoundPSpace(symbol, CompoundDistribution(dist)) return pspace.value class ContinuousDistributionHandmade(SingleContinuousDistribution): _argnames = ('pdf',) def __new__(cls, pdf, set=Interval(-oo, oo)): return Basic.__new__(cls, pdf, set) @property def set(self): return self.args[1] @staticmethod def check(pdf, set): x = Dummy('x') val = integrate(pdf(x), (x, set)) _value_check(Eq(val, 1) != S.false, "The pdf on the given set is incorrect.") def ContinuousRV(symbol, density, set=Interval(-oo, oo), **kwargs): """ Create a Continuous Random Variable given the following: Parameters ========== symbol : Symbol Represents name of the random variable. density : Expression containing symbol Represents probability density function. set : set/Interval Represents the region where the pdf is valid, by default is real line. check : bool If True, it will check whether the given density integrates to 1 over the given set. If False, it will not perform this check. Default is False. Returns ======= RandomSymbol Many common continuous random variable types are already implemented. This function should be necessary only very rarely. Examples ======== >>> from sympy import Symbol, sqrt, exp, pi >>> from sympy.stats import ContinuousRV, P, E >>> x = Symbol("x") >>> pdf = sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) # Normal distribution >>> X = ContinuousRV(x, pdf) >>> E(X) 0 >>> P(X>0) 1/2 """ pdf = Piecewise((density, set.as_relational(symbol)), (0, True)) pdf = Lambda(symbol, pdf) # have a default of False while `rv` should have a default of True kwargs['check'] = kwargs.pop('check', False) return rv(symbol.name, ContinuousDistributionHandmade, (pdf, set), **kwargs) ######################################## # Continuous Probability Distributions # ######################################## #------------------------------------------------------------------------------- # Arcsin distribution ---------------------------------------------------------- class ArcsinDistribution(SingleContinuousDistribution): _argnames = ('a', 'b') @property def set(self): return Interval(self.a, self.b) def pdf(self, x): a, b = self.a, self.b return 1/(pi*sqrt((x - a)*(b - x))) def _cdf(self, x): a, b = self.a, self.b return Piecewise( (S.Zero, x < a), (2*asin(sqrt((x - a)/(b - a)))/pi, x <= b), (S.One, True)) def Arcsin(name, a=0, b=1): r""" Create a Continuous Random Variable with an arcsin distribution. The density of the arcsin distribution is given by .. math:: f(x) := \frac{1}{\pi\sqrt{(x-a)(b-x)}} with :math:`x \in (a,b)`. It must hold that :math:`-\infty < a < b < \infty`. Parameters ========== a : Real number, the left interval boundary b : Real number, the right interval boundary Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Arcsin, density, cdf >>> from sympy import Symbol >>> a = Symbol("a", real=True) >>> b = Symbol("b", real=True) >>> z = Symbol("z") >>> X = Arcsin("x", a, b) >>> density(X)(z) 1/(pi*sqrt((-a + z)*(b - z))) >>> cdf(X)(z) Piecewise((0, a > z), (2*asin(sqrt((-a + z)/(-a + b)))/pi, b >= z), (1, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Arcsine_distribution """ return rv(name, ArcsinDistribution, (a, b)) #------------------------------------------------------------------------------- # Benini distribution ---------------------------------------------------------- class BeniniDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'beta', 'sigma') @staticmethod def check(alpha, beta, sigma): _value_check(alpha > 0, "Shape parameter Alpha must be positive.") _value_check(beta > 0, "Shape parameter Beta must be positive.") _value_check(sigma > 0, "Scale parameter Sigma must be positive.") @property def set(self): return Interval(self.sigma, oo) def pdf(self, x): alpha, beta, sigma = self.alpha, self.beta, self.sigma return (exp(-alpha*log(x/sigma) - beta*log(x/sigma)**2) *(alpha/x + 2*beta*log(x/sigma)/x)) def _moment_generating_function(self, t): raise NotImplementedError('The moment generating function of the ' 'Benini distribution does not exist.') def Benini(name, alpha, beta, sigma): r""" Create a Continuous Random Variable with a Benini distribution. The density of the Benini distribution is given by .. math:: f(x) := e^{-\alpha\log{\frac{x}{\sigma}} -\beta\log^2\left[{\frac{x}{\sigma}}\right]} \left(\frac{\alpha}{x}+\frac{2\beta\log{\frac{x}{\sigma}}}{x}\right) This is a heavy-tailed distribution and is also known as the log-Rayleigh distribution. Parameters ========== alpha : Real number, `\alpha > 0`, a shape beta : Real number, `\beta > 0`, a shape sigma : Real number, `\sigma > 0`, a scale Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Benini, density, cdf >>> from sympy import Symbol, pprint >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) >>> sigma = Symbol("sigma", positive=True) >>> z = Symbol("z") >>> X = Benini("x", alpha, beta, sigma) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) / / z \\ / z \ 2/ z \ | 2*beta*log|-----|| - alpha*log|-----| - beta*log |-----| |alpha \sigma/| \sigma/ \sigma/ |----- + -----------------|*e \ z z / >>> cdf(X)(z) Piecewise((1 - exp(-alpha*log(z/sigma) - beta*log(z/sigma)**2), sigma <= z), (0, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Benini_distribution .. [2] http://reference.wolfram.com/legacy/v8/ref/BeniniDistribution.html """ return rv(name, BeniniDistribution, (alpha, beta, sigma)) #------------------------------------------------------------------------------- # Beta distribution ------------------------------------------------------------ class BetaDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'beta') set = Interval(0, 1) @staticmethod def check(alpha, beta): _value_check(alpha > 0, "Shape parameter Alpha must be positive.") _value_check(beta > 0, "Shape parameter Beta must be positive.") def pdf(self, x): alpha, beta = self.alpha, self.beta return x**(alpha - 1) * (1 - x)**(beta - 1) / beta_fn(alpha, beta) def _characteristic_function(self, t): return hyper((self.alpha,), (self.alpha + self.beta,), I*t) def _moment_generating_function(self, t): return hyper((self.alpha,), (self.alpha + self.beta,), t) def Beta(name, alpha, beta): r""" Create a Continuous Random Variable with a Beta distribution. The density of the Beta distribution is given by .. math:: f(x) := \frac{x^{\alpha-1}(1-x)^{\beta-1}} {\mathrm{B}(\alpha,\beta)} with :math:`x \in [0,1]`. Parameters ========== alpha : Real number, `\alpha > 0`, a shape beta : Real number, `\beta > 0`, a shape Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Beta, density, E, variance >>> from sympy import Symbol, simplify, pprint, factor >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) >>> z = Symbol("z") >>> X = Beta("x", alpha, beta) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) alpha - 1 beta - 1 z *(1 - z) -------------------------- B(alpha, beta) >>> simplify(E(X)) alpha/(alpha + beta) >>> factor(simplify(variance(X))) alpha*beta/((alpha + beta)**2*(alpha + beta + 1)) References ========== .. [1] https://en.wikipedia.org/wiki/Beta_distribution .. [2] http://mathworld.wolfram.com/BetaDistribution.html """ return rv(name, BetaDistribution, (alpha, beta)) #------------------------------------------------------------------------------- # Noncentral Beta distribution ------------------------------------------------------------ class BetaNoncentralDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'beta', 'lamda') set = Interval(0, 1) @staticmethod def check(alpha, beta, lamda): _value_check(alpha > 0, "Shape parameter Alpha must be positive.") _value_check(beta > 0, "Shape parameter Beta must be positive.") _value_check(lamda >= 0, "Noncentrality parameter Lambda must be positive") def pdf(self, x): alpha, beta, lamda = self.alpha, self.beta, self.lamda k = Dummy("k") return Sum(exp(-lamda / 2) * (lamda / 2)**k * x**(alpha + k - 1) *( 1 - x)**(beta - 1) / (factorial(k) * beta_fn(alpha + k, beta)), (k, 0, oo)) def BetaNoncentral(name, alpha, beta, lamda): r""" Create a Continuous Random Variable with a Type I Noncentral Beta distribution. The density of the Noncentral Beta distribution is given by .. math:: f(x) := \sum_{k=0}^\infty e^{-\lambda/2}\frac{(\lambda/2)^k}{k!} \frac{x^{\alpha+k-1}(1-x)^{\beta-1}}{\mathrm{B}(\alpha+k,\beta)} with :math:`x \in [0,1]`. Parameters ========== alpha : Real number, `\alpha > 0`, a shape beta : Real number, `\beta > 0`, a shape lamda: Real number, `\lambda >= 0`, noncentrality parameter Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import BetaNoncentral, density, cdf >>> from sympy import Symbol, pprint >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) >>> lamda = Symbol("lamda", nonnegative=True) >>> z = Symbol("z") >>> X = BetaNoncentral("x", alpha, beta, lamda) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) oo _____ \ ` \ -lamda \ k ------- \ k + alpha - 1 /lamda\ beta - 1 2 ) z *|-----| *(1 - z) *e / \ 2 / / ------------------------------------------------ / B(k + alpha, beta)*k! /____, k = 0 Compute cdf with specific 'x', 'alpha', 'beta' and 'lamda' values as follows : >>> cdf(BetaNoncentral("x", 1, 1, 1), evaluate=False)(2).doit() 2*exp(1/2) The argument evaluate=False prevents an attempt at evaluation of the sum for general x, before the argument 2 is passed. References ========== .. [1] https://en.wikipedia.org/wiki/Noncentral_beta_distribution .. [2] https://reference.wolfram.com/language/ref/NoncentralBetaDistribution.html """ return rv(name, BetaNoncentralDistribution, (alpha, beta, lamda)) #------------------------------------------------------------------------------- # Beta prime distribution ------------------------------------------------------ class BetaPrimeDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'beta') @staticmethod def check(alpha, beta): _value_check(alpha > 0, "Shape parameter Alpha must be positive.") _value_check(beta > 0, "Shape parameter Beta must be positive.") set = Interval(0, oo) def pdf(self, x): alpha, beta = self.alpha, self.beta return x**(alpha - 1)*(1 + x)**(-alpha - beta)/beta_fn(alpha, beta) def BetaPrime(name, alpha, beta): r""" Create a continuous random variable with a Beta prime distribution. The density of the Beta prime distribution is given by .. math:: f(x) := \frac{x^{\alpha-1} (1+x)^{-\alpha -\beta}}{B(\alpha,\beta)} with :math:`x > 0`. Parameters ========== alpha : Real number, `\alpha > 0`, a shape beta : Real number, `\beta > 0`, a shape Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import BetaPrime, density >>> from sympy import Symbol, pprint >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) >>> z = Symbol("z") >>> X = BetaPrime("x", alpha, beta) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) alpha - 1 -alpha - beta z *(z + 1) ------------------------------- B(alpha, beta) References ========== .. [1] https://en.wikipedia.org/wiki/Beta_prime_distribution .. [2] http://mathworld.wolfram.com/BetaPrimeDistribution.html """ return rv(name, BetaPrimeDistribution, (alpha, beta)) #------------------------------------------------------------------------------- # Bounded Pareto Distribution -------------------------------------------------- class BoundedParetoDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'left', 'right') @property def set(self): return Interval(self.left , self.right) @staticmethod def check(alpha, left, right): _value_check (alpha.is_positive, "Shape must be positive.") _value_check (left.is_positive, "Left value should be positive.") _value_check (right > left, "Right should be greater than left.") def pdf(self, x): alpha, left, right = self.alpha, self.left, self.right num = alpha * (left**alpha) * x**(- alpha -1) den = 1 - (left/right)**alpha return num/den def BoundedPareto(name, alpha, left, right): r""" Create a continuous random variable with a Bounded Pareto distribution. The density of the Bounded Pareto distribution is given by .. math:: f(x) := \frac{\alpha L^{\alpha}x^{-\alpha-1}}{1-(\frac{L}{H})^{\alpha}} Parameters ========== alpha : Real Number, `alpha > 0` Shape parameter left : Real Number, `left > 0` Location parameter right : Real Number, `right > left` Location parameter Examples ======== >>> from sympy.stats import BoundedPareto, density, cdf, E >>> from sympy import symbols >>> L, H = symbols('L, H', positive=True) >>> X = BoundedPareto('X', 2, L, H) >>> x = symbols('x') >>> density(X)(x) 2*L**2/(x**3*(1 - L**2/H**2)) >>> cdf(X)(x) Piecewise((-H**2*L**2/(x**2*(H**2 - L**2)) + H**2/(H**2 - L**2), L <= x), (0, True)) >>> E(X).simplify() 2*H*L/(H + L) Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Pareto_distribution#Bounded_Pareto_distribution """ return rv (name, BoundedParetoDistribution, (alpha, left, right)) # ------------------------------------------------------------------------------ # Cauchy distribution ---------------------------------------------------------- class CauchyDistribution(SingleContinuousDistribution): _argnames = ('x0', 'gamma') @staticmethod def check(x0, gamma): _value_check(gamma > 0, "Scale parameter Gamma must be positive.") _value_check(x0.is_real, "Location parameter must be real.") def pdf(self, x): return 1/(pi*self.gamma*(1 + ((x - self.x0)/self.gamma)**2)) def _cdf(self, x): x0, gamma = self.x0, self.gamma return (1/pi)*atan((x - x0)/gamma) + S.Half def _characteristic_function(self, t): return exp(self.x0 * I * t - self.gamma * Abs(t)) def _moment_generating_function(self, t): raise NotImplementedError("The moment generating function for the " "Cauchy distribution does not exist.") def _quantile(self, p): return self.x0 + self.gamma*tan(pi*(p - S.Half)) def Cauchy(name, x0, gamma): r""" Create a continuous random variable with a Cauchy distribution. The density of the Cauchy distribution is given by .. math:: f(x) := \frac{1}{\pi \gamma [1 + {(\frac{x-x_0}{\gamma})}^2]} Parameters ========== x0 : Real number, the location gamma : Real number, `\gamma > 0`, a scale Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Cauchy, density >>> from sympy import Symbol >>> x0 = Symbol("x0") >>> gamma = Symbol("gamma", positive=True) >>> z = Symbol("z") >>> X = Cauchy("x", x0, gamma) >>> density(X)(z) 1/(pi*gamma*(1 + (-x0 + z)**2/gamma**2)) References ========== .. [1] https://en.wikipedia.org/wiki/Cauchy_distribution .. [2] http://mathworld.wolfram.com/CauchyDistribution.html """ return rv(name, CauchyDistribution, (x0, gamma)) #------------------------------------------------------------------------------- # Chi distribution ------------------------------------------------------------- class ChiDistribution(SingleContinuousDistribution): _argnames = ('k',) @staticmethod def check(k): _value_check(k > 0, "Number of degrees of freedom (k) must be positive.") _value_check(k.is_integer, "Number of degrees of freedom (k) must be an integer.") set = Interval(0, oo) def pdf(self, x): return 2**(1 - self.k/2)*x**(self.k - 1)*exp(-x**2/2)/gamma(self.k/2) def _characteristic_function(self, t): k = self.k part_1 = hyper((k/2,), (S.Half,), -t**2/2) part_2 = I*t*sqrt(2)*gamma((k+1)/2)/gamma(k/2) part_3 = hyper(((k+1)/2,), (Rational(3, 2),), -t**2/2) return part_1 + part_2*part_3 def _moment_generating_function(self, t): k = self.k part_1 = hyper((k / 2,), (S.Half,), t ** 2 / 2) part_2 = t * sqrt(2) * gamma((k + 1) / 2) / gamma(k / 2) part_3 = hyper(((k + 1) / 2,), (S(3) / 2,), t ** 2 / 2) return part_1 + part_2 * part_3 def Chi(name, k): r""" Create a continuous random variable with a Chi distribution. The density of the Chi distribution is given by .. math:: f(x) := \frac{2^{1-k/2}x^{k-1}e^{-x^2/2}}{\Gamma(k/2)} with :math:`x \geq 0`. Parameters ========== k : Positive integer, The number of degrees of freedom Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Chi, density, E >>> from sympy import Symbol, simplify >>> k = Symbol("k", integer=True) >>> z = Symbol("z") >>> X = Chi("x", k) >>> density(X)(z) 2**(1 - k/2)*z**(k - 1)*exp(-z**2/2)/gamma(k/2) >>> simplify(E(X)) sqrt(2)*gamma(k/2 + 1/2)/gamma(k/2) References ========== .. [1] https://en.wikipedia.org/wiki/Chi_distribution .. [2] http://mathworld.wolfram.com/ChiDistribution.html """ return rv(name, ChiDistribution, (k,)) #------------------------------------------------------------------------------- # Non-central Chi distribution ------------------------------------------------- class ChiNoncentralDistribution(SingleContinuousDistribution): _argnames = ('k', 'l') @staticmethod def check(k, l): _value_check(k > 0, "Number of degrees of freedom (k) must be positive.") _value_check(k.is_integer, "Number of degrees of freedom (k) must be an integer.") _value_check(l > 0, "Shift parameter Lambda must be positive.") set = Interval(0, oo) def pdf(self, x): k, l = self.k, self.l return exp(-(x**2+l**2)/2)*x**k*l / (l*x)**(k/2) * besseli(k/2-1, l*x) def ChiNoncentral(name, k, l): r""" Create a continuous random variable with a non-central Chi distribution. Explanation =========== The density of the non-central Chi distribution is given by .. math:: f(x) := \frac{e^{-(x^2+\lambda^2)/2} x^k\lambda} {(\lambda x)^{k/2}} I_{k/2-1}(\lambda x) with `x \geq 0`. Here, `I_\nu (x)` is the :ref:`modified Bessel function of the first kind `. Parameters ========== k : A positive Integer, $k > 0$ The number of degrees of freedom. lambda : Real number, `\lambda > 0` Shift parameter. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import ChiNoncentral, density >>> from sympy import Symbol >>> k = Symbol("k", integer=True) >>> l = Symbol("l") >>> z = Symbol("z") >>> X = ChiNoncentral("x", k, l) >>> density(X)(z) l*z**k*exp(-l**2/2 - z**2/2)*besseli(k/2 - 1, l*z)/(l*z)**(k/2) References ========== .. [1] https://en.wikipedia.org/wiki/Noncentral_chi_distribution """ return rv(name, ChiNoncentralDistribution, (k, l)) #------------------------------------------------------------------------------- # Chi squared distribution ----------------------------------------------------- class ChiSquaredDistribution(SingleContinuousDistribution): _argnames = ('k',) @staticmethod def check(k): _value_check(k > 0, "Number of degrees of freedom (k) must be positive.") _value_check(k.is_integer, "Number of degrees of freedom (k) must be an integer.") set = Interval(0, oo) def pdf(self, x): k = self.k return 1/(2**(k/2)*gamma(k/2))*x**(k/2 - 1)*exp(-x/2) def _cdf(self, x): k = self.k return Piecewise( (S.One/gamma(k/2)*lowergamma(k/2, x/2), x >= 0), (0, True) ) def _characteristic_function(self, t): return (1 - 2*I*t)**(-self.k/2) def _moment_generating_function(self, t): return (1 - 2*t)**(-self.k/2) def ChiSquared(name, k): r""" Create a continuous random variable with a Chi-squared distribution. Explanation =========== The density of the Chi-squared distribution is given by .. math:: f(x) := \frac{1}{2^{\frac{k}{2}}\Gamma\left(\frac{k}{2}\right)} x^{\frac{k}{2}-1} e^{-\frac{x}{2}} with :math:`x \geq 0`. Parameters ========== k : Positive integer The number of degrees of freedom. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import ChiSquared, density, E, variance, moment >>> from sympy import Symbol >>> k = Symbol("k", integer=True, positive=True) >>> z = Symbol("z") >>> X = ChiSquared("x", k) >>> density(X)(z) z**(k/2 - 1)*exp(-z/2)/(2**(k/2)*gamma(k/2)) >>> E(X) k >>> variance(X) 2*k >>> moment(X, 3) k**3 + 6*k**2 + 8*k References ========== .. [1] https://en.wikipedia.org/wiki/Chi_squared_distribution .. [2] http://mathworld.wolfram.com/Chi-SquaredDistribution.html """ return rv(name, ChiSquaredDistribution, (k, )) #------------------------------------------------------------------------------- # Dagum distribution ----------------------------------------------------------- class DagumDistribution(SingleContinuousDistribution): _argnames = ('p', 'a', 'b') set = Interval(0, oo) @staticmethod def check(p, a, b): _value_check(p > 0, "Shape parameter p must be positive.") _value_check(a > 0, "Shape parameter a must be positive.") _value_check(b > 0, "Scale parameter b must be positive.") def pdf(self, x): p, a, b = self.p, self.a, self.b return a*p/x*((x/b)**(a*p)/(((x/b)**a + 1)**(p + 1))) def _cdf(self, x): p, a, b = self.p, self.a, self.b return Piecewise(((S.One + (S(x)/b)**-a)**-p, x>=0), (S.Zero, True)) def Dagum(name, p, a, b): r""" Create a continuous random variable with a Dagum distribution. Explanation =========== The density of the Dagum distribution is given by .. math:: f(x) := \frac{a p}{x} \left( \frac{\left(\tfrac{x}{b}\right)^{a p}} {\left(\left(\tfrac{x}{b}\right)^a + 1 \right)^{p+1}} \right) with :math:`x > 0`. Parameters ========== p : Real number ``p > 0``, a shape. a : Real number ``a > 0``, a shape. b : Real number ``b > 0``, a scale. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Dagum, density, cdf >>> from sympy import Symbol >>> p = Symbol("p", positive=True) >>> a = Symbol("a", positive=True) >>> b = Symbol("b", positive=True) >>> z = Symbol("z") >>> X = Dagum("x", p, a, b) >>> density(X)(z) a*p*(z/b)**(a*p)*((z/b)**a + 1)**(-p - 1)/z >>> cdf(X)(z) Piecewise(((1 + (z/b)**(-a))**(-p), z >= 0), (0, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Dagum_distribution """ return rv(name, DagumDistribution, (p, a, b)) #------------------------------------------------------------------------------- # Erlang distribution ---------------------------------------------------------- def Erlang(name, k, l): r""" Create a continuous random variable with an Erlang distribution. Explanation =========== The density of the Erlang distribution is given by .. math:: f(x) := \frac{\lambda^k x^{k-1} e^{-\lambda x}}{(k-1)!} with :math:`x \in [0,\infty]`. Parameters ========== k : Positive integer l : Real number, `\lambda > 0`, the rate Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Erlang, density, cdf, E, variance >>> from sympy import Symbol, simplify, pprint >>> k = Symbol("k", integer=True, positive=True) >>> l = Symbol("l", positive=True) >>> z = Symbol("z") >>> X = Erlang("x", k, l) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) k k - 1 -l*z l *z *e --------------- Gamma(k) >>> C = cdf(X)(z) >>> pprint(C, use_unicode=False) /lowergamma(k, l*z) |------------------ for z > 0 < Gamma(k) | \ 0 otherwise >>> E(X) k/l >>> simplify(variance(X)) k/l**2 References ========== .. [1] https://en.wikipedia.org/wiki/Erlang_distribution .. [2] http://mathworld.wolfram.com/ErlangDistribution.html """ return rv(name, GammaDistribution, (k, S.One/l)) # ------------------------------------------------------------------------------- # ExGaussian distribution ----------------------------------------------------- class ExGaussianDistribution(SingleContinuousDistribution): _argnames = ('mean', 'std', 'rate') set = Interval(-oo, oo) @staticmethod def check(mean, std, rate): _value_check( std > 0, "Standard deviation of ExGaussian must be positive.") _value_check(rate > 0, "Rate of ExGaussian must be positive.") def pdf(self, x): mean, std, rate = self.mean, self.std, self.rate term1 = rate/2 term2 = exp(rate * (2 * mean + rate * std**2 - 2*x)/2) term3 = erfc((mean + rate*std**2 - x)/(sqrt(2)*std)) return term1*term2*term3 def _cdf(self, x): from sympy.stats import cdf mean, std, rate = self.mean, self.std, self.rate u = rate*(x - mean) v = rate*std GaussianCDF1 = cdf(Normal('x', 0, v))(u) GaussianCDF2 = cdf(Normal('x', v**2, v))(u) return GaussianCDF1 - exp(-u + (v**2/2) + log(GaussianCDF2)) def _characteristic_function(self, t): mean, std, rate = self.mean, self.std, self.rate term1 = (1 - I*t/rate)**(-1) term2 = exp(I*mean*t - std**2*t**2/2) return term1 * term2 def _moment_generating_function(self, t): mean, std, rate = self.mean, self.std, self.rate term1 = (1 - t/rate)**(-1) term2 = exp(mean*t + std**2*t**2/2) return term1*term2 def ExGaussian(name, mean, std, rate): r""" Create a continuous random variable with an Exponentially modified Gaussian (EMG) distribution. Explanation =========== The density of the exponentially modified Gaussian distribution is given by .. math:: f(x) := \frac{\lambda}{2}e^{\frac{\lambda}{2}(2\mu+\lambda\sigma^2-2x)} \text{erfc}(\frac{\mu + \lambda\sigma^2 - x}{\sqrt{2}\sigma}) with $x > 0$. Note that the expected value is `1/\lambda`. Parameters ========== mu : A Real number, the mean of Gaussian component std: A positive Real number, :math: `\sigma^2 > 0` the variance of Gaussian component lambda: A positive Real number, :math: `\lambda > 0` the rate of Exponential component Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import ExGaussian, density, cdf, E >>> from sympy.stats import variance, skewness >>> from sympy import Symbol, pprint, simplify >>> mean = Symbol("mu") >>> std = Symbol("sigma", positive=True) >>> rate = Symbol("lamda", positive=True) >>> z = Symbol("z") >>> X = ExGaussian("x", mean, std, rate) >>> pprint(density(X)(z), use_unicode=False) / 2 \ lamda*\lamda*sigma + 2*mu - 2*z/ --------------------------------- / ___ / 2 \\ 2 |\/ 2 *\lamda*sigma + mu - z/| lamda*e *erfc|-----------------------------| \ 2*sigma / ---------------------------------------------------------------------------- 2 >>> cdf(X)(z) -(erf(sqrt(2)*(-lamda**2*sigma**2 + lamda*(-mu + z))/(2*lamda*sigma))/2 + 1/2)*exp(lamda**2*sigma**2/2 - lamda*(-mu + z)) + erf(sqrt(2)*(-mu + z)/(2*sigma))/2 + 1/2 >>> E(X) (lamda*mu + 1)/lamda >>> simplify(variance(X)) sigma**2 + lamda**(-2) >>> simplify(skewness(X)) 2/(lamda**2*sigma**2 + 1)**(3/2) References ========== .. [1] https://en.wikipedia.org/wiki/Exponentially_modified_Gaussian_distribution """ return rv(name, ExGaussianDistribution, (mean, std, rate)) #------------------------------------------------------------------------------- # Exponential distribution ----------------------------------------------------- class ExponentialDistribution(SingleContinuousDistribution): _argnames = ('rate',) set = Interval(0, oo) @staticmethod def check(rate): _value_check(rate > 0, "Rate must be positive.") def pdf(self, x): return self.rate * exp(-self.rate*x) def _cdf(self, x): return Piecewise( (S.One - exp(-self.rate*x), x >= 0), (0, True), ) def _characteristic_function(self, t): rate = self.rate return rate / (rate - I*t) def _moment_generating_function(self, t): rate = self.rate return rate / (rate - t) def _quantile(self, p): return -log(1-p)/self.rate def Exponential(name, rate): r""" Create a continuous random variable with an Exponential distribution. Explanation =========== The density of the exponential distribution is given by .. math:: f(x) := \lambda \exp(-\lambda x) with $x > 0$. Note that the expected value is `1/\lambda`. Parameters ========== rate : A positive Real number, `\lambda > 0`, the rate (or inverse scale/inverse mean) Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Exponential, density, cdf, E >>> from sympy.stats import variance, std, skewness, quantile >>> from sympy import Symbol >>> l = Symbol("lambda", positive=True) >>> z = Symbol("z") >>> p = Symbol("p") >>> X = Exponential("x", l) >>> density(X)(z) lambda*exp(-lambda*z) >>> cdf(X)(z) Piecewise((1 - exp(-lambda*z), z >= 0), (0, True)) >>> quantile(X)(p) -log(1 - p)/lambda >>> E(X) 1/lambda >>> variance(X) lambda**(-2) >>> skewness(X) 2 >>> X = Exponential('x', 10) >>> density(X)(z) 10*exp(-10*z) >>> E(X) 1/10 >>> std(X) 1/10 References ========== .. [1] https://en.wikipedia.org/wiki/Exponential_distribution .. [2] http://mathworld.wolfram.com/ExponentialDistribution.html """ return rv(name, ExponentialDistribution, (rate, )) # ------------------------------------------------------------------------------- # Exponential Power distribution ----------------------------------------------------- class ExponentialPowerDistribution(SingleContinuousDistribution): _argnames = ('mu', 'alpha', 'beta') set = Interval(-oo, oo) @staticmethod def check(mu, alpha, beta): _value_check(alpha > 0, "Scale parameter alpha must be positive.") _value_check(beta > 0, "Shape parameter beta must be positive.") def pdf(self, x): mu, alpha, beta = self.mu, self.alpha, self.beta num = beta*exp(-(Abs(x - mu)/alpha)**beta) den = 2*alpha*gamma(1/beta) return num/den def _cdf(self, x): mu, alpha, beta = self.mu, self.alpha, self.beta num = lowergamma(1/beta, (Abs(x - mu) / alpha)**beta) den = 2*gamma(1/beta) return sign(x - mu)*num/den + S.Half def ExponentialPower(name, mu, alpha, beta): r""" Create a Continuous Random Variable with Exponential Power distribution. This distribution is known also as Generalized Normal distribution version 1. Explanation =========== The density of the Exponential Power distribution is given by .. math:: f(x) := \frac{\beta}{2\alpha\Gamma(\frac{1}{\beta})} e^{{-(\frac{|x - \mu|}{\alpha})^{\beta}}} with :math:`x \in [ - \infty, \infty ]`. Parameters ========== mu : Real number A location. alpha : Real number,``alpha > 0`` A scale. beta : Real number, ``beta > 0`` A shape. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import ExponentialPower, density, cdf >>> from sympy import Symbol, pprint >>> z = Symbol("z") >>> mu = Symbol("mu") >>> alpha = Symbol("alpha", positive=True) >>> beta = Symbol("beta", positive=True) >>> X = ExponentialPower("x", mu, alpha, beta) >>> pprint(density(X)(z), use_unicode=False) beta /|mu - z|\ -|--------| \ alpha / beta*e --------------------- / 1 \ 2*alpha*Gamma|----| \beta/ >>> cdf(X)(z) 1/2 + lowergamma(1/beta, (Abs(mu - z)/alpha)**beta)*sign(-mu + z)/(2*gamma(1/beta)) References ========== .. [1] https://reference.wolfram.com/language/ref/ExponentialPowerDistribution.html .. [2] https://en.wikipedia.org/wiki/Generalized_normal_distribution#Version_1 """ return rv(name, ExponentialPowerDistribution, (mu, alpha, beta)) #------------------------------------------------------------------------------- # F distribution --------------------------------------------------------------- class FDistributionDistribution(SingleContinuousDistribution): _argnames = ('d1', 'd2') set = Interval(0, oo) @staticmethod def check(d1, d2): _value_check((d1 > 0, d1.is_integer), "Degrees of freedom d1 must be positive integer.") _value_check((d2 > 0, d2.is_integer), "Degrees of freedom d2 must be positive integer.") def pdf(self, x): d1, d2 = self.d1, self.d2 return (sqrt((d1*x)**d1*d2**d2 / (d1*x+d2)**(d1+d2)) / (x * beta_fn(d1/2, d2/2))) def _moment_generating_function(self, t): raise NotImplementedError('The moment generating function for the ' 'F-distribution does not exist.') def FDistribution(name, d1, d2): r""" Create a continuous random variable with a F distribution. Explanation =========== The density of the F distribution is given by .. math:: f(x) := \frac{\sqrt{\frac{(d_1 x)^{d_1} d_2^{d_2}} {(d_1 x + d_2)^{d_1 + d_2}}}} {x \mathrm{B} \left(\frac{d_1}{2}, \frac{d_2}{2}\right)} with :math:`x > 0`. Parameters ========== d1 : `d_1 > 0`, where d_1 is the degrees of freedom (n_1 - 1) d2 : `d_2 > 0`, where d_2 is the degrees of freedom (n_2 - 1) Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import FDistribution, density >>> from sympy import Symbol, pprint >>> d1 = Symbol("d1", positive=True) >>> d2 = Symbol("d2", positive=True) >>> z = Symbol("z") >>> X = FDistribution("x", d1, d2) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) d2 -- ______________________________ 2 / d1 -d1 - d2 d2 *\/ (d1*z) *(d1*z + d2) -------------------------------------- /d1 d2\ z*B|--, --| \2 2 / References ========== .. [1] https://en.wikipedia.org/wiki/F-distribution .. [2] http://mathworld.wolfram.com/F-Distribution.html """ return rv(name, FDistributionDistribution, (d1, d2)) #------------------------------------------------------------------------------- # Fisher Z distribution -------------------------------------------------------- class FisherZDistribution(SingleContinuousDistribution): _argnames = ('d1', 'd2') set = Interval(-oo, oo) @staticmethod def check(d1, d2): _value_check(d1 > 0, "Degree of freedom d1 must be positive.") _value_check(d2 > 0, "Degree of freedom d2 must be positive.") def pdf(self, x): d1, d2 = self.d1, self.d2 return (2*d1**(d1/2)*d2**(d2/2) / beta_fn(d1/2, d2/2) * exp(d1*x) / (d1*exp(2*x)+d2)**((d1+d2)/2)) def FisherZ(name, d1, d2): r""" Create a Continuous Random Variable with an Fisher's Z distribution. Explanation =========== The density of the Fisher's Z distribution is given by .. math:: f(x) := \frac{2d_1^{d_1/2} d_2^{d_2/2}} {\mathrm{B}(d_1/2, d_2/2)} \frac{e^{d_1z}}{\left(d_1e^{2z}+d_2\right)^{\left(d_1+d_2\right)/2}} .. TODO - What is the difference between these degrees of freedom? Parameters ========== d1 : ``d_1 > 0`` Degree of freedom. d2 : ``d_2 > 0`` Degree of freedom. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import FisherZ, density >>> from sympy import Symbol, pprint >>> d1 = Symbol("d1", positive=True) >>> d2 = Symbol("d2", positive=True) >>> z = Symbol("z") >>> X = FisherZ("x", d1, d2) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) d1 d2 d1 d2 - -- - -- -- -- 2 2 2 2 / 2*z \ d1*z 2*d1 *d2 *\d1*e + d2/ *e ----------------------------------------- /d1 d2\ B|--, --| \2 2 / References ========== .. [1] https://en.wikipedia.org/wiki/Fisher%27s_z-distribution .. [2] http://mathworld.wolfram.com/Fishersz-Distribution.html """ return rv(name, FisherZDistribution, (d1, d2)) #------------------------------------------------------------------------------- # Frechet distribution --------------------------------------------------------- class FrechetDistribution(SingleContinuousDistribution): _argnames = ('a', 's', 'm') set = Interval(0, oo) @staticmethod def check(a, s, m): _value_check(a > 0, "Shape parameter alpha must be positive.") _value_check(s > 0, "Scale parameter s must be positive.") def __new__(cls, a, s=1, m=0): a, s, m = list(map(sympify, (a, s, m))) return Basic.__new__(cls, a, s, m) def pdf(self, x): a, s, m = self.a, self.s, self.m return a/s * ((x-m)/s)**(-1-a) * exp(-((x-m)/s)**(-a)) def _cdf(self, x): a, s, m = self.a, self.s, self.m return Piecewise((exp(-((x-m)/s)**(-a)), x >= m), (S.Zero, True)) def Frechet(name, a, s=1, m=0): r""" Create a continuous random variable with a Frechet distribution. Explanation =========== The density of the Frechet distribution is given by .. math:: f(x) := \frac{\alpha}{s} \left(\frac{x-m}{s}\right)^{-1-\alpha} e^{-(\frac{x-m}{s})^{-\alpha}} with :math:`x \geq m`. Parameters ========== a : Real number, :math:`a \in \left(0, \infty\right)` the shape s : Real number, :math:`s \in \left(0, \infty\right)` the scale m : Real number, :math:`m \in \left(-\infty, \infty\right)` the minimum Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Frechet, density, cdf >>> from sympy import Symbol >>> a = Symbol("a", positive=True) >>> s = Symbol("s", positive=True) >>> m = Symbol("m", real=True) >>> z = Symbol("z") >>> X = Frechet("x", a, s, m) >>> density(X)(z) a*((-m + z)/s)**(-a - 1)*exp(-1/((-m + z)/s)**a)/s >>> cdf(X)(z) Piecewise((exp(-1/((-m + z)/s)**a), m <= z), (0, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Fr%C3%A9chet_distribution """ return rv(name, FrechetDistribution, (a, s, m)) #------------------------------------------------------------------------------- # Gamma distribution ----------------------------------------------------------- class GammaDistribution(SingleContinuousDistribution): _argnames = ('k', 'theta') set = Interval(0, oo) @staticmethod def check(k, theta): _value_check(k > 0, "k must be positive") _value_check(theta > 0, "Theta must be positive") def pdf(self, x): k, theta = self.k, self.theta return x**(k - 1) * exp(-x/theta) / (gamma(k)*theta**k) def _cdf(self, x): k, theta = self.k, self.theta return Piecewise( (lowergamma(k, S(x)/theta)/gamma(k), x > 0), (S.Zero, True)) def _characteristic_function(self, t): return (1 - self.theta*I*t)**(-self.k) def _moment_generating_function(self, t): return (1- self.theta*t)**(-self.k) def Gamma(name, k, theta): r""" Create a continuous random variable with a Gamma distribution. Explanation =========== The density of the Gamma distribution is given by .. math:: f(x) := \frac{1}{\Gamma(k) \theta^k} x^{k - 1} e^{-\frac{x}{\theta}} with :math:`x \in [0,1]`. Parameters ========== k : Real number, ``k > 0``, a shape theta : Real number, `\theta > 0`, a scale Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Gamma, density, cdf, E, variance >>> from sympy import Symbol, pprint, simplify >>> k = Symbol("k", positive=True) >>> theta = Symbol("theta", positive=True) >>> z = Symbol("z") >>> X = Gamma("x", k, theta) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) -z ----- -k k - 1 theta theta *z *e --------------------- Gamma(k) >>> C = cdf(X, meijerg=True)(z) >>> pprint(C, use_unicode=False) / / z \ |k*lowergamma|k, -----| | \ theta/ <---------------------- for z >= 0 | Gamma(k + 1) | \ 0 otherwise >>> E(X) k*theta >>> V = simplify(variance(X)) >>> pprint(V, use_unicode=False) 2 k*theta References ========== .. [1] https://en.wikipedia.org/wiki/Gamma_distribution .. [2] http://mathworld.wolfram.com/GammaDistribution.html """ return rv(name, GammaDistribution, (k, theta)) #------------------------------------------------------------------------------- # Inverse Gamma distribution --------------------------------------------------- class GammaInverseDistribution(SingleContinuousDistribution): _argnames = ('a', 'b') set = Interval(0, oo) @staticmethod def check(a, b): _value_check(a > 0, "alpha must be positive") _value_check(b > 0, "beta must be positive") def pdf(self, x): a, b = self.a, self.b return b**a/gamma(a) * x**(-a-1) * exp(-b/x) def _cdf(self, x): a, b = self.a, self.b return Piecewise((uppergamma(a,b/x)/gamma(a), x > 0), (S.Zero, True)) def _characteristic_function(self, t): a, b = self.a, self.b return 2 * (-I*b*t)**(a/2) * besselk(a, sqrt(-4*I*b*t)) / gamma(a) def _moment_generating_function(self, t): raise NotImplementedError('The moment generating function for the ' 'gamma inverse distribution does not exist.') def GammaInverse(name, a, b): r""" Create a continuous random variable with an inverse Gamma distribution. Explanation =========== The density of the inverse Gamma distribution is given by .. math:: f(x) := \frac{\beta^\alpha}{\Gamma(\alpha)} x^{-\alpha - 1} \exp\left(\frac{-\beta}{x}\right) with :math:`x > 0`. Parameters ========== a : Real number, `a > 0` a shape b : Real number, `b > 0` a scale Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import GammaInverse, density, cdf >>> from sympy import Symbol, pprint >>> a = Symbol("a", positive=True) >>> b = Symbol("b", positive=True) >>> z = Symbol("z") >>> X = GammaInverse("x", a, b) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) -b --- a -a - 1 z b *z *e --------------- Gamma(a) >>> cdf(X)(z) Piecewise((uppergamma(a, b/z)/gamma(a), z > 0), (0, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Inverse-gamma_distribution """ return rv(name, GammaInverseDistribution, (a, b)) #------------------------------------------------------------------------------- # Gumbel distribution (Maximum and Minimum) -------------------------------------------------------- class GumbelDistribution(SingleContinuousDistribution): _argnames = ('beta', 'mu', 'minimum') set = Interval(-oo, oo) @staticmethod def check(beta, mu, minimum): _value_check(beta > 0, "Scale parameter beta must be positive.") def pdf(self, x): beta, mu = self.beta, self.mu z = (x - mu)/beta f_max = (1/beta)*exp(-z - exp(-z)) f_min = (1/beta)*exp(z - exp(z)) return Piecewise((f_min, self.minimum), (f_max, not self.minimum)) def _cdf(self, x): beta, mu = self.beta, self.mu z = (x - mu)/beta F_max = exp(-exp(-z)) F_min = 1 - exp(-exp(z)) return Piecewise((F_min, self.minimum), (F_max, not self.minimum)) def _characteristic_function(self, t): cf_max = gamma(1 - I*self.beta*t) * exp(I*self.mu*t) cf_min = gamma(1 + I*self.beta*t) * exp(I*self.mu*t) return Piecewise((cf_min, self.minimum), (cf_max, not self.minimum)) def _moment_generating_function(self, t): mgf_max = gamma(1 - self.beta*t) * exp(self.mu*t) mgf_min = gamma(1 + self.beta*t) * exp(self.mu*t) return Piecewise((mgf_min, self.minimum), (mgf_max, not self.minimum)) def Gumbel(name, beta, mu, minimum=False): r""" Create a Continuous Random Variable with Gumbel distribution. Explanation =========== The density of the Gumbel distribution is given by For Maximum .. math:: f(x) := \dfrac{1}{\beta} \exp \left( -\dfrac{x-\mu}{\beta} - \exp \left( -\dfrac{x - \mu}{\beta} \right) \right) with :math:`x \in [ - \infty, \infty ]`. For Minimum .. math:: f(x) := \frac{e^{- e^{\frac{- \mu + x}{\beta}} + \frac{- \mu + x}{\beta}}}{\beta} with :math:`x \in [ - \infty, \infty ]`. Parameters ========== mu : Real number, 'mu' is a location beta : Real number, 'beta > 0' is a scale minimum : Boolean, by default, False, set to True for enabling minimum distribution Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Gumbel, density, cdf >>> from sympy import Symbol >>> x = Symbol("x") >>> mu = Symbol("mu") >>> beta = Symbol("beta", positive=True) >>> X = Gumbel("x", beta, mu) >>> density(X)(x) exp(-exp(-(-mu + x)/beta) - (-mu + x)/beta)/beta >>> cdf(X)(x) exp(-exp(-(-mu + x)/beta)) References ========== .. [1] http://mathworld.wolfram.com/GumbelDistribution.html .. [2] https://en.wikipedia.org/wiki/Gumbel_distribution .. [3] http://www.mathwave.com/help/easyfit/html/analyses/distributions/gumbel_max.html .. [4] http://www.mathwave.com/help/easyfit/html/analyses/distributions/gumbel_min.html """ return rv(name, GumbelDistribution, (beta, mu, minimum)) #------------------------------------------------------------------------------- # Gompertz distribution -------------------------------------------------------- class GompertzDistribution(SingleContinuousDistribution): _argnames = ('b', 'eta') set = Interval(0, oo) @staticmethod def check(b, eta): _value_check(b > 0, "b must be positive") _value_check(eta > 0, "eta must be positive") def pdf(self, x): eta, b = self.eta, self.b return b*eta*exp(b*x)*exp(eta)*exp(-eta*exp(b*x)) def _cdf(self, x): eta, b = self.eta, self.b return 1 - exp(eta)*exp(-eta*exp(b*x)) def _moment_generating_function(self, t): eta, b = self.eta, self.b return eta * exp(eta) * expint(t/b, eta) def Gompertz(name, b, eta): r""" Create a Continuous Random Variable with Gompertz distribution. Explanation =========== The density of the Gompertz distribution is given by .. math:: f(x) := b \eta e^{b x} e^{\eta} \exp \left(-\eta e^{bx} \right) with :math: 'x \in [0, \inf)'. Parameters ========== b: Real number, 'b > 0' a scale eta: Real number, 'eta > 0' a shape Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Gompertz, density >>> from sympy import Symbol >>> b = Symbol("b", positive=True) >>> eta = Symbol("eta", positive=True) >>> z = Symbol("z") >>> X = Gompertz("x", b, eta) >>> density(X)(z) b*eta*exp(eta)*exp(b*z)*exp(-eta*exp(b*z)) References ========== .. [1] https://en.wikipedia.org/wiki/Gompertz_distribution """ return rv(name, GompertzDistribution, (b, eta)) #------------------------------------------------------------------------------- # Kumaraswamy distribution ----------------------------------------------------- class KumaraswamyDistribution(SingleContinuousDistribution): _argnames = ('a', 'b') set = Interval(0, oo) @staticmethod def check(a, b): _value_check(a > 0, "a must be positive") _value_check(b > 0, "b must be positive") def pdf(self, x): a, b = self.a, self.b return a * b * x**(a-1) * (1-x**a)**(b-1) def _cdf(self, x): a, b = self.a, self.b return Piecewise( (S.Zero, x < S.Zero), (1 - (1 - x**a)**b, x <= S.One), (S.One, True)) def Kumaraswamy(name, a, b): r""" Create a Continuous Random Variable with a Kumaraswamy distribution. Explanation =========== The density of the Kumaraswamy distribution is given by .. math:: f(x) := a b x^{a-1} (1-x^a)^{b-1} with :math:`x \in [0,1]`. Parameters ========== a : Real number, ``a > 0`` a shape b : Real number, ``b > 0`` a shape Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Kumaraswamy, density, cdf >>> from sympy import Symbol, pprint >>> a = Symbol("a", positive=True) >>> b = Symbol("b", positive=True) >>> z = Symbol("z") >>> X = Kumaraswamy("x", a, b) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) b - 1 a - 1 / a\ a*b*z *\1 - z / >>> cdf(X)(z) Piecewise((0, z < 0), (1 - (1 - z**a)**b, z <= 1), (1, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Kumaraswamy_distribution """ return rv(name, KumaraswamyDistribution, (a, b)) #------------------------------------------------------------------------------- # Laplace distribution --------------------------------------------------------- class LaplaceDistribution(SingleContinuousDistribution): _argnames = ('mu', 'b') set = Interval(-oo, oo) @staticmethod def check(mu, b): _value_check(b > 0, "Scale parameter b must be positive.") _value_check(mu.is_real, "Location parameter mu should be real") def pdf(self, x): mu, b = self.mu, self.b return 1/(2*b)*exp(-Abs(x - mu)/b) def _cdf(self, x): mu, b = self.mu, self.b return Piecewise( (S.Half*exp((x - mu)/b), x < mu), (S.One - S.Half*exp(-(x - mu)/b), x >= mu) ) def _characteristic_function(self, t): return exp(self.mu*I*t) / (1 + self.b**2*t**2) def _moment_generating_function(self, t): return exp(self.mu*t) / (1 - self.b**2*t**2) def Laplace(name, mu, b): r""" Create a continuous random variable with a Laplace distribution. Explanation =========== The density of the Laplace distribution is given by .. math:: f(x) := \frac{1}{2 b} \exp \left(-\frac{|x-\mu|}b \right) Parameters ========== mu : Real number or a list/matrix, the location (mean) or the location vector b : Real number or a positive definite matrix, representing a scale or the covariance matrix. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Laplace, density, cdf >>> from sympy import Symbol, pprint >>> mu = Symbol("mu") >>> b = Symbol("b", positive=True) >>> z = Symbol("z") >>> X = Laplace("x", mu, b) >>> density(X)(z) exp(-Abs(mu - z)/b)/(2*b) >>> cdf(X)(z) Piecewise((exp((-mu + z)/b)/2, mu > z), (1 - exp((mu - z)/b)/2, True)) >>> L = Laplace('L', [1, 2], [[1, 0], [0, 1]]) >>> pprint(density(L)(1, 2), use_unicode=False) 5 / ____\ e *besselk\0, \/ 35 / --------------------- pi References ========== .. [1] https://en.wikipedia.org/wiki/Laplace_distribution .. [2] http://mathworld.wolfram.com/LaplaceDistribution.html """ if isinstance(mu, (list, MatrixBase)) and\ isinstance(b, (list, MatrixBase)): from sympy.stats.joint_rv_types import MultivariateLaplace return MultivariateLaplace(name, mu, b) return rv(name, LaplaceDistribution, (mu, b)) #------------------------------------------------------------------------------- # Levy distribution --------------------------------------------------------- class LevyDistribution(SingleContinuousDistribution): _argnames = ('mu', 'c') @property def set(self): return Interval(self.mu, oo) @staticmethod def check(mu, c): _value_check(c > 0, "c (scale parameter) must be positive") _value_check(mu.is_real, "mu (location paramater) must be real") def pdf(self, x): mu, c = self.mu, self.c return sqrt(c/(2*pi))*exp(-c/(2*(x - mu)))/((x - mu)**(S.One + S.Half)) def _cdf(self, x): mu, c = self.mu, self.c return erfc(sqrt(c/(2*(x - mu)))) def _characteristic_function(self, t): mu, c = self.mu, self.c return exp(I * mu * t - sqrt(-2 * I * c * t)) def _moment_generating_function(self, t): raise NotImplementedError('The moment generating function of Levy distribution does not exist.') def Levy(name, mu, c): r""" Create a continuous random variable with a Levy distribution. The density of the Levy distribution is given by .. math:: f(x) := \sqrt(\frac{c}{2 \pi}) \frac{\exp -\frac{c}{2 (x - \mu)}}{(x - \mu)^{3/2}} Parameters ========== mu : Real number The location parameter. c : Real number, ``c > 0`` A scale parameter. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Levy, density, cdf >>> from sympy import Symbol >>> mu = Symbol("mu", real=True) >>> c = Symbol("c", positive=True) >>> z = Symbol("z") >>> X = Levy("x", mu, c) >>> density(X)(z) sqrt(2)*sqrt(c)*exp(-c/(-2*mu + 2*z))/(2*sqrt(pi)*(-mu + z)**(3/2)) >>> cdf(X)(z) erfc(sqrt(c)*sqrt(1/(-2*mu + 2*z))) References ========== .. [1] https://en.wikipedia.org/wiki/L%C3%A9vy_distribution .. [2] http://mathworld.wolfram.com/LevyDistribution.html """ return rv(name, LevyDistribution, (mu, c)) #------------------------------------------------------------------------------- # Log-Cauchy distribution -------------------------------------------------------- class LogCauchyDistribution(SingleContinuousDistribution): _argnames = ('mu', 'sigma') set = Interval.open(0, oo) @staticmethod def check(mu, sigma): _value_check((sigma > 0) != False, "Scale parameter Gamma must be positive.") _value_check(mu.is_real != False, "Location parameter must be real.") def pdf(self, x): mu, sigma = self.mu, self.sigma return 1/(x*pi)*(sigma/((log(x) - mu)**2 + sigma**2)) def _cdf(self, x): mu, sigma = self.mu, self.sigma return (1/pi)*atan((log(x) - mu)/sigma) + S.Half def _characteristic_function(self, t): raise NotImplementedError("The characteristic function for the " "Log-Cauchy distribution does not exist.") def _moment_generating_function(self, t): raise NotImplementedError("The moment generating function for the " "Log-Cauchy distribution does not exist.") def LogCauchy(name, mu, sigma): r""" Create a continuous random variable with a Log-Cauchy distribution. The density of the Log-Cauchy distribution is given by .. math:: f(x) := \frac{1}{\pi x} \frac{\sigma}{(log(x)-\mu^2) + \sigma^2} Parameters ========== mu : Real number, the location sigma : Real number, `\sigma > 0`, a scale Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import LogCauchy, density, cdf >>> from sympy import Symbol, S >>> mu = 2 >>> sigma = S.One / 5 >>> z = Symbol("z") >>> X = LogCauchy("x", mu, sigma) >>> density(X)(z) 1/(5*pi*z*((log(z) - 2)**2 + 1/25)) >>> cdf(X)(z) atan(5*log(z) - 10)/pi + 1/2 References ========== .. [1] https://en.wikipedia.org/wiki/Log-Cauchy_distribution """ return rv(name, LogCauchyDistribution, (mu, sigma)) #------------------------------------------------------------------------------- # Logistic distribution -------------------------------------------------------- class LogisticDistribution(SingleContinuousDistribution): _argnames = ('mu', 's') set = Interval(-oo, oo) @staticmethod def check(mu, s): _value_check(s > 0, "Scale parameter s must be positive.") def pdf(self, x): mu, s = self.mu, self.s return exp(-(x - mu)/s)/(s*(1 + exp(-(x - mu)/s))**2) def _cdf(self, x): mu, s = self.mu, self.s return S.One/(1 + exp(-(x - mu)/s)) def _characteristic_function(self, t): return Piecewise((exp(I*t*self.mu) * pi*self.s*t / sinh(pi*self.s*t), Ne(t, 0)), (S.One, True)) def _moment_generating_function(self, t): return exp(self.mu*t) * beta_fn(1 - self.s*t, 1 + self.s*t) def _quantile(self, p): return self.mu - self.s*log(-S.One + S.One/p) def Logistic(name, mu, s): r""" Create a continuous random variable with a logistic distribution. Explanation =========== The density of the logistic distribution is given by .. math:: f(x) := \frac{e^{-(x-\mu)/s}} {s\left(1+e^{-(x-\mu)/s}\right)^2} Parameters ========== mu : Real number, the location (mean) s : Real number, `s > 0` a scale Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Logistic, density, cdf >>> from sympy import Symbol >>> mu = Symbol("mu", real=True) >>> s = Symbol("s", positive=True) >>> z = Symbol("z") >>> X = Logistic("x", mu, s) >>> density(X)(z) exp((mu - z)/s)/(s*(exp((mu - z)/s) + 1)**2) >>> cdf(X)(z) 1/(exp((mu - z)/s) + 1) References ========== .. [1] https://en.wikipedia.org/wiki/Logistic_distribution .. [2] http://mathworld.wolfram.com/LogisticDistribution.html """ return rv(name, LogisticDistribution, (mu, s)) #------------------------------------------------------------------------------- # Log-logistic distribution -------------------------------------------------------- class LogLogisticDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'beta') set = Interval(0, oo) @staticmethod def check(alpha, beta): _value_check(alpha > 0, "Scale parameter Alpha must be positive.") _value_check(beta > 0, "Shape parameter Beta must be positive.") def pdf(self, x): a, b = self.alpha, self.beta return ((b/a)*(x/a)**(b - 1))/(1 + (x/a)**b)**2 def _cdf(self, x): a, b = self.alpha, self.beta return 1/(1 + (x/a)**(-b)) def _quantile(self, p): a, b = self.alpha, self.beta return a*((p/(1 - p))**(1/b)) def expectation(self, expr, var, **kwargs): a, b = self.args return Piecewise((S.NaN, b <= 1), (pi*a/(b*sin(pi/b)), True)) def LogLogistic(name, alpha, beta): r""" Create a continuous random variable with a log-logistic distribution. The distribution is unimodal when ``beta > 1``. Explanation =========== The density of the log-logistic distribution is given by .. math:: f(x) := \frac{(\frac{\beta}{\alpha})(\frac{x}{\alpha})^{\beta - 1}} {(1 + (\frac{x}{\alpha})^{\beta})^2} Parameters ========== alpha : Real number, `\alpha > 0`, scale parameter and median of distribution beta : Real number, `\beta > 0` a shape parameter Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import LogLogistic, density, cdf, quantile >>> from sympy import Symbol, pprint >>> alpha = Symbol("alpha", real=True, positive=True) >>> beta = Symbol("beta", real=True, positive=True) >>> p = Symbol("p") >>> z = Symbol("z", positive=True) >>> X = LogLogistic("x", alpha, beta) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) beta - 1 / z \ beta*|-----| \alpha/ ------------------------ 2 / beta \ |/ z \ | alpha*||-----| + 1| \\alpha/ / >>> cdf(X)(z) 1/(1 + (z/alpha)**(-beta)) >>> quantile(X)(p) alpha*(p/(1 - p))**(1/beta) References ========== .. [1] https://en.wikipedia.org/wiki/Log-logistic_distribution """ return rv(name, LogLogisticDistribution, (alpha, beta)) #------------------------------------------------------------------------------- #Logit-Normal distribution------------------------------------------------------ class LogitNormalDistribution(SingleContinuousDistribution): _argnames = ('mu', 's') set = Interval.open(0, 1) @staticmethod def check(mu, s): _value_check((s ** 2).is_real is not False and s ** 2 > 0, "Squared scale parameter s must be positive.") _value_check(mu.is_real is not False, "Location parameter must be real") def _logit(self, x): return log(x / (1 - x)) def pdf(self, x): mu, s = self.mu, self.s return exp(-(self._logit(x) - mu)**2/(2*s**2))*(S.One/sqrt(2*pi*(s**2)))*(1/(x*(1 - x))) def _cdf(self, x): mu, s = self.mu, self.s return (S.One/2)*(1 + erf((self._logit(x) - mu)/(sqrt(2*s**2)))) def LogitNormal(name, mu, s): r""" Create a continuous random variable with a Logit-Normal distribution. The density of the logistic distribution is given by .. math:: f(x) := \frac{1}{s \sqrt{2 \pi}} \frac{1}{x(1 - x)} e^{- \frac{(logit(x) - \mu)^2}{s^2}} where logit(x) = \log(\frac{x}{1 - x}) Parameters ========== mu : Real number, the location (mean) s : Real number, `s > 0` a scale Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import LogitNormal, density, cdf >>> from sympy import Symbol,pprint >>> mu = Symbol("mu", real=True) >>> s = Symbol("s", positive=True) >>> z = Symbol("z") >>> X = LogitNormal("x",mu,s) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) 2 / / z \\ -|-mu + log|-----|| \ \1 - z// --------------------- 2 ___ 2*s \/ 2 *e ---------------------------- ____ 2*\/ pi *s*z*(1 - z) >>> density(X)(z) sqrt(2)*exp(-(-mu + log(z/(1 - z)))**2/(2*s**2))/(2*sqrt(pi)*s*z*(1 - z)) >>> cdf(X)(z) erf(sqrt(2)*(-mu + log(z/(1 - z)))/(2*s))/2 + 1/2 References ========== .. [1] https://en.wikipedia.org/wiki/Logit-normal_distribution """ return rv(name, LogitNormalDistribution, (mu, s)) #------------------------------------------------------------------------------- # Log Normal distribution ------------------------------------------------------ class LogNormalDistribution(SingleContinuousDistribution): _argnames = ('mean', 'std') set = Interval(0, oo) @staticmethod def check(mean, std): _value_check(std > 0, "Parameter std must be positive.") def pdf(self, x): mean, std = self.mean, self.std return exp(-(log(x) - mean)**2 / (2*std**2)) / (x*sqrt(2*pi)*std) def _cdf(self, x): mean, std = self.mean, self.std return Piecewise( (S.Half + S.Half*erf((log(x) - mean)/sqrt(2)/std), x > 0), (S.Zero, True) ) def _moment_generating_function(self, t): raise NotImplementedError('Moment generating function of the log-normal distribution is not defined.') def LogNormal(name, mean, std): r""" Create a continuous random variable with a log-normal distribution. Explanation =========== The density of the log-normal distribution is given by .. math:: f(x) := \frac{1}{x\sqrt{2\pi\sigma^2}} e^{-\frac{\left(\ln x-\mu\right)^2}{2\sigma^2}} with :math:`x \geq 0`. Parameters ========== mu : Real number The log-scale. sigma : Real number A shape. ($\sigma^2 > 0$) Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import LogNormal, density >>> from sympy import Symbol, pprint >>> mu = Symbol("mu", real=True) >>> sigma = Symbol("sigma", positive=True) >>> z = Symbol("z") >>> X = LogNormal("x", mu, sigma) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) 2 -(-mu + log(z)) ----------------- 2 ___ 2*sigma \/ 2 *e ------------------------ ____ 2*\/ pi *sigma*z >>> X = LogNormal('x', 0, 1) # Mean 0, standard deviation 1 >>> density(X)(z) sqrt(2)*exp(-log(z)**2/2)/(2*sqrt(pi)*z) References ========== .. [1] https://en.wikipedia.org/wiki/Lognormal .. [2] http://mathworld.wolfram.com/LogNormalDistribution.html """ return rv(name, LogNormalDistribution, (mean, std)) #------------------------------------------------------------------------------- # Lomax Distribution ----------------------------------------------------------- class LomaxDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'lamda',) set = Interval(0, oo) @staticmethod def check(alpha, lamda): _value_check(alpha.is_real, "Shape parameter should be real.") _value_check(lamda.is_real, "Scale parameter should be real.") _value_check(alpha.is_positive, "Shape parameter should be positive.") _value_check(lamda.is_positive, "Scale parameter should be positive.") def pdf(self, x): lamba, alpha = self.lamda, self.alpha return (alpha/lamba) * (S.One + x/lamba)**(-alpha-1) def Lomax(name, alpha, lamda): r""" Create a continuous random variable with a Lomax distribution. Explanation =========== The density of the Lomax distribution is given by .. math:: f(x) := \frac{\alpha}{\lambda}\left[1+\frac{x}{\lambda}\right]^{-(\alpha+1)} Parameters ========== alpha : Real Number, `alpha > 0` Shape parameter lamda : Real Number, `lamda > 0` Scale parameter Examples ======== >>> from sympy.stats import Lomax, density, cdf, E >>> from sympy import symbols >>> a, l = symbols('a, l', positive=True) >>> X = Lomax('X', a, l) >>> x = symbols('x') >>> density(X)(x) a*(1 + x/l)**(-a - 1)/l >>> cdf(X)(x) Piecewise((1 - 1/(1 + x/l)**a, x >= 0), (0, True)) >>> a = 2 >>> X = Lomax('X', a, l) >>> E(X) l Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Lomax_distribution """ return rv(name, LomaxDistribution, (alpha, lamda)) #------------------------------------------------------------------------------- # Maxwell distribution --------------------------------------------------------- class MaxwellDistribution(SingleContinuousDistribution): _argnames = ('a',) set = Interval(0, oo) @staticmethod def check(a): _value_check(a > 0, "Parameter a must be positive.") def pdf(self, x): a = self.a return sqrt(2/pi)*x**2*exp(-x**2/(2*a**2))/a**3 def _cdf(self, x): a = self.a return erf(sqrt(2)*x/(2*a)) - sqrt(2)*x*exp(-x**2/(2*a**2))/(sqrt(pi)*a) def Maxwell(name, a): r""" Create a continuous random variable with a Maxwell distribution. Explanation =========== The density of the Maxwell distribution is given by .. math:: f(x) := \sqrt{\frac{2}{\pi}} \frac{x^2 e^{-x^2/(2a^2)}}{a^3} with :math:`x \geq 0`. .. TODO - what does the parameter mean? Parameters ========== a : Real number, `a > 0` Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Maxwell, density, E, variance >>> from sympy import Symbol, simplify >>> a = Symbol("a", positive=True) >>> z = Symbol("z") >>> X = Maxwell("x", a) >>> density(X)(z) sqrt(2)*z**2*exp(-z**2/(2*a**2))/(sqrt(pi)*a**3) >>> E(X) 2*sqrt(2)*a/sqrt(pi) >>> simplify(variance(X)) a**2*(-8 + 3*pi)/pi References ========== .. [1] https://en.wikipedia.org/wiki/Maxwell_distribution .. [2] http://mathworld.wolfram.com/MaxwellDistribution.html """ return rv(name, MaxwellDistribution, (a, )) #------------------------------------------------------------------------------- # Moyal Distribution ----------------------------------------------------------- class MoyalDistribution(SingleContinuousDistribution): _argnames = ('mu', 'sigma') @staticmethod def check(mu, sigma): _value_check(mu.is_real, "Location parameter must be real.") _value_check(sigma.is_real and sigma > 0, "Scale parameter must be real\ and positive.") def pdf(self, x): mu, sigma = self.mu, self.sigma num = exp(-(exp(-(x - mu)/sigma) + (x - mu)/(sigma))/2) den = (sqrt(2*pi) * sigma) return num/den def _characteristic_function(self, t): mu, sigma = self.mu, self.sigma term1 = exp(I*t*mu) term2 = (2**(-I*sigma*t) * gamma(Rational(1, 2) - I*t*sigma)) return (term1 * term2)/sqrt(pi) def _moment_generating_function(self, t): mu, sigma = self.mu, self.sigma term1 = exp(t*mu) term2 = (2**(-1*sigma*t) * gamma(Rational(1, 2) - t*sigma)) return (term1 * term2)/sqrt(pi) def Moyal(name, mu, sigma): r""" Create a continuous random variable with a Moyal distribution. Explanation =========== The density of the Moyal distribution is given by .. math:: f(x) := \frac{\exp-\frac{1}{2}\exp-\frac{x-\mu}{\sigma}-\frac{x-\mu}{2\sigma}}{\sqrt{2\pi}\sigma} with :math:`x \in \mathbb{R}`. Parameters ========== mu : Real number Location parameter sigma : Real positive number Scale parameter Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Moyal, density, cdf >>> from sympy import Symbol, simplify >>> mu = Symbol("mu", real=True) >>> sigma = Symbol("sigma", positive=True, real=True) >>> z = Symbol("z") >>> X = Moyal("x", mu, sigma) >>> density(X)(z) sqrt(2)*exp(-exp((mu - z)/sigma)/2 - (-mu + z)/(2*sigma))/(2*sqrt(pi)*sigma) >>> simplify(cdf(X)(z)) 1 - erf(sqrt(2)*exp((mu - z)/(2*sigma))/2) References ========== .. [1] https://reference.wolfram.com/language/ref/MoyalDistribution.html .. [2] http://www.stat.rice.edu/~dobelman/textfiles/DistributionsHandbook.pdf """ return rv(name, MoyalDistribution, (mu, sigma)) #------------------------------------------------------------------------------- # Nakagami distribution -------------------------------------------------------- class NakagamiDistribution(SingleContinuousDistribution): _argnames = ('mu', 'omega') set = Interval(0, oo) @staticmethod def check(mu, omega): _value_check(mu >= S.Half, "Shape parameter mu must be greater than equal to 1/2.") _value_check(omega > 0, "Spread parameter omega must be positive.") def pdf(self, x): mu, omega = self.mu, self.omega return 2*mu**mu/(gamma(mu)*omega**mu)*x**(2*mu - 1)*exp(-mu/omega*x**2) def _cdf(self, x): mu, omega = self.mu, self.omega return Piecewise( (lowergamma(mu, (mu/omega)*x**2)/gamma(mu), x > 0), (S.Zero, True)) def Nakagami(name, mu, omega): r""" Create a continuous random variable with a Nakagami distribution. Explanation =========== The density of the Nakagami distribution is given by .. math:: f(x) := \frac{2\mu^\mu}{\Gamma(\mu)\omega^\mu} x^{2\mu-1} \exp\left(-\frac{\mu}{\omega}x^2 \right) with :math:`x > 0`. Parameters ========== mu : Real number, `\mu \geq \frac{1}{2}` a shape omega : Real number, `\omega > 0`, the spread Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Nakagami, density, E, variance, cdf >>> from sympy import Symbol, simplify, pprint >>> mu = Symbol("mu", positive=True) >>> omega = Symbol("omega", positive=True) >>> z = Symbol("z") >>> X = Nakagami("x", mu, omega) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) 2 -mu*z ------- mu -mu 2*mu - 1 omega 2*mu *omega *z *e ---------------------------------- Gamma(mu) >>> simplify(E(X)) sqrt(mu)*sqrt(omega)*gamma(mu + 1/2)/gamma(mu + 1) >>> V = simplify(variance(X)) >>> pprint(V, use_unicode=False) 2 omega*Gamma (mu + 1/2) omega - ----------------------- Gamma(mu)*Gamma(mu + 1) >>> cdf(X)(z) Piecewise((lowergamma(mu, mu*z**2/omega)/gamma(mu), z > 0), (0, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Nakagami_distribution """ return rv(name, NakagamiDistribution, (mu, omega)) #------------------------------------------------------------------------------- # Normal distribution ---------------------------------------------------------- class NormalDistribution(SingleContinuousDistribution): _argnames = ('mean', 'std') @staticmethod def check(mean, std): _value_check(std > 0, "Standard deviation must be positive") def pdf(self, x): return exp(-(x - self.mean)**2 / (2*self.std**2)) / (sqrt(2*pi)*self.std) def _cdf(self, x): mean, std = self.mean, self.std return erf(sqrt(2)*(-mean + x)/(2*std))/2 + S.Half def _characteristic_function(self, t): mean, std = self.mean, self.std return exp(I*mean*t - std**2*t**2/2) def _moment_generating_function(self, t): mean, std = self.mean, self.std return exp(mean*t + std**2*t**2/2) def _quantile(self, p): mean, std = self.mean, self.std return mean + std*sqrt(2)*erfinv(2*p - 1) def Normal(name, mean, std): r""" Create a continuous random variable with a Normal distribution. Explanation =========== The density of the Normal distribution is given by .. math:: f(x) := \frac{1}{\sigma\sqrt{2\pi}} e^{ -\frac{(x-\mu)^2}{2\sigma^2} } Parameters ========== mu : Real number or a list representing the mean or the mean vector sigma : Real number or a positive definite square matrix, :math:`\sigma^2 > 0` the variance Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Normal, density, E, std, cdf, skewness, quantile, marginal_distribution >>> from sympy import Symbol, simplify, pprint >>> mu = Symbol("mu") >>> sigma = Symbol("sigma", positive=True) >>> z = Symbol("z") >>> y = Symbol("y") >>> p = Symbol("p") >>> X = Normal("x", mu, sigma) >>> density(X)(z) sqrt(2)*exp(-(-mu + z)**2/(2*sigma**2))/(2*sqrt(pi)*sigma) >>> C = simplify(cdf(X))(z) # it needs a little more help... >>> pprint(C, use_unicode=False) / ___ \ |\/ 2 *(-mu + z)| erf|---------------| \ 2*sigma / 1 -------------------- + - 2 2 >>> quantile(X)(p) mu + sqrt(2)*sigma*erfinv(2*p - 1) >>> simplify(skewness(X)) 0 >>> X = Normal("x", 0, 1) # Mean 0, standard deviation 1 >>> density(X)(z) sqrt(2)*exp(-z**2/2)/(2*sqrt(pi)) >>> E(2*X + 1) 1 >>> simplify(std(2*X + 1)) 2 >>> m = Normal('X', [1, 2], [[2, 1], [1, 2]]) >>> pprint(density(m)(y, z), use_unicode=False) 2 2 y y*z z - -- + --- - -- + z - 1 ___ 3 3 3 \/ 3 *e ------------------------------ 6*pi >>> marginal_distribution(m, m[0])(1) 1/(2*sqrt(pi)) References ========== .. [1] https://en.wikipedia.org/wiki/Normal_distribution .. [2] http://mathworld.wolfram.com/NormalDistributionFunction.html """ if isinstance(mean, list) or getattr(mean, 'is_Matrix', False) and\ isinstance(std, list) or getattr(std, 'is_Matrix', False): from sympy.stats.joint_rv_types import MultivariateNormal return MultivariateNormal(name, mean, std) return rv(name, NormalDistribution, (mean, std)) #------------------------------------------------------------------------------- # Inverse Gaussian distribution ---------------------------------------------------------- class GaussianInverseDistribution(SingleContinuousDistribution): _argnames = ('mean', 'shape') @property def set(self): return Interval(0, oo) @staticmethod def check(mean, shape): _value_check(shape > 0, "Shape parameter must be positive") _value_check(mean > 0, "Mean must be positive") def pdf(self, x): mu, s = self.mean, self.shape return exp(-s*(x - mu)**2 / (2*x*mu**2)) * sqrt(s/(2*pi*x**3)) def _cdf(self, x): from sympy.stats import cdf mu, s = self.mean, self.shape stdNormalcdf = cdf(Normal('x', 0, 1)) first_term = stdNormalcdf(sqrt(s/x) * ((x/mu) - S.One)) second_term = exp(2*s/mu) * stdNormalcdf(-sqrt(s/x)*(x/mu + S.One)) return first_term + second_term def _characteristic_function(self, t): mu, s = self.mean, self.shape return exp((s/mu)*(1 - sqrt(1 - (2*mu**2*I*t)/s))) def _moment_generating_function(self, t): mu, s = self.mean, self.shape return exp((s/mu)*(1 - sqrt(1 - (2*mu**2*t)/s))) def GaussianInverse(name, mean, shape): r""" Create a continuous random variable with an Inverse Gaussian distribution. Inverse Gaussian distribution is also known as Wald distribution. Explanation =========== The density of the Inverse Gaussian distribution is given by .. math:: f(x) := \sqrt{\frac{\lambda}{2\pi x^3}} e^{-\frac{\lambda(x-\mu)^2}{2x\mu^2}} Parameters ========== mu : Positive number representing the mean. lambda : Positive number representing the shape parameter. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import GaussianInverse, density, E, std, skewness >>> from sympy import Symbol, pprint >>> mu = Symbol("mu", positive=True) >>> lamda = Symbol("lambda", positive=True) >>> z = Symbol("z", positive=True) >>> X = GaussianInverse("x", mu, lamda) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) 2 -lambda*(-mu + z) ------------------- 2 ___ ________ 2*mu *z \/ 2 *\/ lambda *e ------------------------------------- ____ 3/2 2*\/ pi *z >>> E(X) mu >>> std(X).expand() mu**(3/2)/sqrt(lambda) >>> skewness(X).expand() 3*sqrt(mu)/sqrt(lambda) References ========== .. [1] https://en.wikipedia.org/wiki/Inverse_Gaussian_distribution .. [2] http://mathworld.wolfram.com/InverseGaussianDistribution.html """ return rv(name, GaussianInverseDistribution, (mean, shape)) Wald = GaussianInverse #------------------------------------------------------------------------------- # Pareto distribution ---------------------------------------------------------- class ParetoDistribution(SingleContinuousDistribution): _argnames = ('xm', 'alpha') @property def set(self): return Interval(self.xm, oo) @staticmethod def check(xm, alpha): _value_check(xm > 0, "Xm must be positive") _value_check(alpha > 0, "Alpha must be positive") def pdf(self, x): xm, alpha = self.xm, self.alpha return alpha * xm**alpha / x**(alpha + 1) def _cdf(self, x): xm, alpha = self.xm, self.alpha return Piecewise( (S.One - xm**alpha/x**alpha, x>=xm), (0, True), ) def _moment_generating_function(self, t): xm, alpha = self.xm, self.alpha return alpha * (-xm*t)**alpha * uppergamma(-alpha, -xm*t) def _characteristic_function(self, t): xm, alpha = self.xm, self.alpha return alpha * (-I * xm * t) ** alpha * uppergamma(-alpha, -I * xm * t) def Pareto(name, xm, alpha): r""" Create a continuous random variable with the Pareto distribution. Explanation =========== The density of the Pareto distribution is given by .. math:: f(x) := \frac{\alpha\,x_m^\alpha}{x^{\alpha+1}} with :math:`x \in [x_m,\infty]`. Parameters ========== xm : Real number, `x_m > 0`, a scale alpha : Real number, `\alpha > 0`, a shape Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Pareto, density >>> from sympy import Symbol >>> xm = Symbol("xm", positive=True) >>> beta = Symbol("beta", positive=True) >>> z = Symbol("z") >>> X = Pareto("x", xm, beta) >>> density(X)(z) beta*xm**beta*z**(-beta - 1) References ========== .. [1] https://en.wikipedia.org/wiki/Pareto_distribution .. [2] http://mathworld.wolfram.com/ParetoDistribution.html """ return rv(name, ParetoDistribution, (xm, alpha)) #------------------------------------------------------------------------------- # PowerFunction distribution --------------------------------------------------- class PowerFunctionDistribution(SingleContinuousDistribution): _argnames=('alpha','a','b') @property def set(self): return Interval(self.a, self.b) @staticmethod def check(alpha, a, b): _value_check(a.is_real, "Continuous Boundary parameter should be real.") _value_check(b.is_real, "Continuous Boundary parameter should be real.") _value_check(a < b, " 'a' the left Boundary must be smaller than 'b' the right Boundary." ) _value_check(alpha.is_positive, "Continuous Shape parameter should be positive.") def pdf(self, x): alpha, a, b = self.alpha, self.a, self.b num = alpha*(x - a)**(alpha - 1) den = (b - a)**alpha return num/den def PowerFunction(name, alpha, a, b): r""" Creates a continuous random variable with a Power Function Distribution. Explanation =========== The density of PowerFunction distribution is given by .. math:: f(x) := \frac{{\alpha}(x - a)^{\alpha - 1}}{(b - a)^{\alpha}} with :math:`x \in [a,b]`. Parameters ========== alpha: Positive number, `0 < alpha` the shape paramater a : Real number, :math:`-\infty < a` the left boundary b : Real number, :math:`a < b < \infty` the right boundary Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import PowerFunction, density, cdf, E, variance >>> from sympy import Symbol >>> alpha = Symbol("alpha", positive=True) >>> a = Symbol("a", real=True) >>> b = Symbol("b", real=True) >>> z = Symbol("z") >>> X = PowerFunction("X", 2, a, b) >>> density(X)(z) (-2*a + 2*z)/(-a + b)**2 >>> cdf(X)(z) Piecewise((a**2/(a**2 - 2*a*b + b**2) - 2*a*z/(a**2 - 2*a*b + b**2) + z**2/(a**2 - 2*a*b + b**2), a <= z), (0, True)) >>> alpha = 2 >>> a = 0 >>> b = 1 >>> Y = PowerFunction("Y", alpha, a, b) >>> E(Y) 2/3 >>> variance(Y) 1/18 References ========== .. [1] http://www.mathwave.com/help/easyfit/html/analyses/distributions/power_func.html """ return rv(name, PowerFunctionDistribution, (alpha, a, b)) #------------------------------------------------------------------------------- # QuadraticU distribution ------------------------------------------------------ class QuadraticUDistribution(SingleContinuousDistribution): _argnames = ('a', 'b') @property def set(self): return Interval(self.a, self.b) @staticmethod def check(a, b): _value_check(b > a, "Parameter b must be in range (%s, oo)."%(a)) def pdf(self, x): a, b = self.a, self.b alpha = 12 / (b-a)**3 beta = (a+b) / 2 return Piecewise( (alpha * (x-beta)**2, And(a<=x, x<=b)), (S.Zero, True)) def _moment_generating_function(self, t): a, b = self.a, self.b return -3 * (exp(a*t) * (4 + (a**2 + 2*a*(-2 + b) + b**2) * t) \ - exp(b*t) * (4 + (-4*b + (a + b)**2) * t)) / ((a-b)**3 * t**2) def _characteristic_function(self, t): a, b = self.a, self.b return -3*I*(exp(I*a*t*exp(I*b*t)) * (4*I - (-4*b + (a+b)**2)*t)) \ / ((a-b)**3 * t**2) def QuadraticU(name, a, b): r""" Create a Continuous Random Variable with a U-quadratic distribution. Explanation =========== The density of the U-quadratic distribution is given by .. math:: f(x) := \alpha (x-\beta)^2 with :math:`x \in [a,b]`. Parameters ========== a : Real number b : Real number, :math:`a < b` Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import QuadraticU, density >>> from sympy import Symbol, pprint >>> a = Symbol("a", real=True) >>> b = Symbol("b", real=True) >>> z = Symbol("z") >>> X = QuadraticU("x", a, b) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) / 2 | / a b \ |12*|- - - - + z| | \ 2 2 / <----------------- for And(b >= z, a <= z) | 3 | (-a + b) | \ 0 otherwise References ========== .. [1] https://en.wikipedia.org/wiki/U-quadratic_distribution """ return rv(name, QuadraticUDistribution, (a, b)) #------------------------------------------------------------------------------- # RaisedCosine distribution ---------------------------------------------------- class RaisedCosineDistribution(SingleContinuousDistribution): _argnames = ('mu', 's') @property def set(self): return Interval(self.mu - self.s, self.mu + self.s) @staticmethod def check(mu, s): _value_check(s > 0, "s must be positive") def pdf(self, x): mu, s = self.mu, self.s return Piecewise( ((1+cos(pi*(x-mu)/s)) / (2*s), And(mu-s<=x, x<=mu+s)), (S.Zero, True)) def _characteristic_function(self, t): mu, s = self.mu, self.s return Piecewise((exp(-I*pi*mu/s)/2, Eq(t, -pi/s)), (exp(I*pi*mu/s)/2, Eq(t, pi/s)), (pi**2*sin(s*t)*exp(I*mu*t) / (s*t*(pi**2 - s**2*t**2)), True)) def _moment_generating_function(self, t): mu, s = self.mu, self.s return pi**2 * sinh(s*t) * exp(mu*t) / (s*t*(pi**2 + s**2*t**2)) def RaisedCosine(name, mu, s): r""" Create a Continuous Random Variable with a raised cosine distribution. Explanation =========== The density of the raised cosine distribution is given by .. math:: f(x) := \frac{1}{2s}\left(1+\cos\left(\frac{x-\mu}{s}\pi\right)\right) with :math:`x \in [\mu-s,\mu+s]`. Parameters ========== mu : Real number s : Real number, `s > 0` Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import RaisedCosine, density >>> from sympy import Symbol, pprint >>> mu = Symbol("mu", real=True) >>> s = Symbol("s", positive=True) >>> z = Symbol("z") >>> X = RaisedCosine("x", mu, s) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) / /pi*(-mu + z)\ |cos|------------| + 1 | \ s / <--------------------- for And(z >= mu - s, z <= mu + s) | 2*s | \ 0 otherwise References ========== .. [1] https://en.wikipedia.org/wiki/Raised_cosine_distribution """ return rv(name, RaisedCosineDistribution, (mu, s)) #------------------------------------------------------------------------------- # Rayleigh distribution -------------------------------------------------------- class RayleighDistribution(SingleContinuousDistribution): _argnames = ('sigma',) set = Interval(0, oo) @staticmethod def check(sigma): _value_check(sigma > 0, "Scale parameter sigma must be positive.") def pdf(self, x): sigma = self.sigma return x/sigma**2*exp(-x**2/(2*sigma**2)) def _cdf(self, x): sigma = self.sigma return 1 - exp(-(x**2/(2*sigma**2))) def _characteristic_function(self, t): sigma = self.sigma return 1 - sigma*t*exp(-sigma**2*t**2/2) * sqrt(pi/2) * (erfi(sigma*t/sqrt(2)) - I) def _moment_generating_function(self, t): sigma = self.sigma return 1 + sigma*t*exp(sigma**2*t**2/2) * sqrt(pi/2) * (erf(sigma*t/sqrt(2)) + 1) def Rayleigh(name, sigma): r""" Create a continuous random variable with a Rayleigh distribution. Explanation =========== The density of the Rayleigh distribution is given by .. math :: f(x) := \frac{x}{\sigma^2} e^{-x^2/2\sigma^2} with :math:`x > 0`. Parameters ========== sigma : Real number, `\sigma > 0` Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Rayleigh, density, E, variance >>> from sympy import Symbol >>> sigma = Symbol("sigma", positive=True) >>> z = Symbol("z") >>> X = Rayleigh("x", sigma) >>> density(X)(z) z*exp(-z**2/(2*sigma**2))/sigma**2 >>> E(X) sqrt(2)*sqrt(pi)*sigma/2 >>> variance(X) -pi*sigma**2/2 + 2*sigma**2 References ========== .. [1] https://en.wikipedia.org/wiki/Rayleigh_distribution .. [2] http://mathworld.wolfram.com/RayleighDistribution.html """ return rv(name, RayleighDistribution, (sigma, )) #------------------------------------------------------------------------------- # Reciprocal distribution -------------------------------------------------------- class ReciprocalDistribution(SingleContinuousDistribution): _argnames = ('a', 'b') @property def set(self): return Interval(self.a, self.b) @staticmethod def check(a, b): _value_check(a > 0, "Parameter > 0. a = %s"%a) _value_check((a < b), "Parameter b must be in range (%s, +oo]. b = %s"%(a, b)) def pdf(self, x): a, b = self.a, self.b return 1/(x*(log(b) - log(a))) def Reciprocal(name, a, b): r"""Creates a continuous random variable with a reciprocal distribution. Parameters ========== a : Real number, :math:`0 < a` b : Real number, :math:`a < b` Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Reciprocal, density, cdf >>> from sympy import symbols >>> a, b, x = symbols('a, b, x', positive=True) >>> R = Reciprocal('R', a, b) >>> density(R)(x) 1/(x*(-log(a) + log(b))) >>> cdf(R)(x) Piecewise((log(a)/(log(a) - log(b)) - log(x)/(log(a) - log(b)), a <= x), (0, True)) Reference ========= .. [1] https://en.wikipedia.org/wiki/Reciprocal_distribution """ return rv(name, ReciprocalDistribution, (a, b)) #------------------------------------------------------------------------------- # Shifted Gompertz distribution ------------------------------------------------ class ShiftedGompertzDistribution(SingleContinuousDistribution): _argnames = ('b', 'eta') set = Interval(0, oo) @staticmethod def check(b, eta): _value_check(b > 0, "b must be positive") _value_check(eta > 0, "eta must be positive") def pdf(self, x): b, eta = self.b, self.eta return b*exp(-b*x)*exp(-eta*exp(-b*x))*(1+eta*(1-exp(-b*x))) def ShiftedGompertz(name, b, eta): r""" Create a continuous random variable with a Shifted Gompertz distribution. Explanation =========== The density of the Shifted Gompertz distribution is given by .. math:: f(x) := b e^{-b x} e^{-\eta \exp(-b x)} \left[1 + \eta(1 - e^(-bx)) \right] with :math: 'x \in [0, \inf)'. Parameters ========== b: Real number, 'b > 0' a scale eta: Real number, 'eta > 0' a shape Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import ShiftedGompertz, density >>> from sympy import Symbol >>> b = Symbol("b", positive=True) >>> eta = Symbol("eta", positive=True) >>> x = Symbol("x") >>> X = ShiftedGompertz("x", b, eta) >>> density(X)(x) b*(eta*(1 - exp(-b*x)) + 1)*exp(-b*x)*exp(-eta*exp(-b*x)) References ========== .. [1] https://en.wikipedia.org/wiki/Shifted_Gompertz_distribution """ return rv(name, ShiftedGompertzDistribution, (b, eta)) #------------------------------------------------------------------------------- # StudentT distribution -------------------------------------------------------- class StudentTDistribution(SingleContinuousDistribution): _argnames = ('nu',) set = Interval(-oo, oo) @staticmethod def check(nu): _value_check(nu > 0, "Degrees of freedom nu must be positive.") def pdf(self, x): nu = self.nu return 1/(sqrt(nu)*beta_fn(S.Half, nu/2))*(1 + x**2/nu)**(-(nu + 1)/2) def _cdf(self, x): nu = self.nu return S.Half + x*gamma((nu+1)/2)*hyper((S.Half, (nu+1)/2), (Rational(3, 2),), -x**2/nu)/(sqrt(pi*nu)*gamma(nu/2)) def _moment_generating_function(self, t): raise NotImplementedError('The moment generating function for the Student-T distribution is undefined.') def StudentT(name, nu): r""" Create a continuous random variable with a student's t distribution. Explanation =========== The density of the student's t distribution is given by .. math:: f(x) := \frac{\Gamma \left(\frac{\nu+1}{2} \right)} {\sqrt{\nu\pi}\Gamma \left(\frac{\nu}{2} \right)} \left(1+\frac{x^2}{\nu} \right)^{-\frac{\nu+1}{2}} Parameters ========== nu : Real number, `\nu > 0`, the degrees of freedom Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import StudentT, density, cdf >>> from sympy import Symbol, pprint >>> nu = Symbol("nu", positive=True) >>> z = Symbol("z") >>> X = StudentT("x", nu) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) nu 1 - -- - - 2 2 / 2\ | z | |1 + --| \ nu/ ----------------- ____ / nu\ \/ nu *B|1/2, --| \ 2 / >>> cdf(X)(z) 1/2 + z*gamma(nu/2 + 1/2)*hyper((1/2, nu/2 + 1/2), (3/2,), -z**2/nu)/(sqrt(pi)*sqrt(nu)*gamma(nu/2)) References ========== .. [1] https://en.wikipedia.org/wiki/Student_t-distribution .. [2] http://mathworld.wolfram.com/Studentst-Distribution.html """ return rv(name, StudentTDistribution, (nu, )) #------------------------------------------------------------------------------- # Trapezoidal distribution ------------------------------------------------------ class TrapezoidalDistribution(SingleContinuousDistribution): _argnames = ('a', 'b', 'c', 'd') @property def set(self): return Interval(self.a, self.d) @staticmethod def check(a, b, c, d): _value_check(a < d, "Lower bound parameter a < %s. a = %s"%(d, a)) _value_check((a <= b, b < c), "Level start parameter b must be in range [%s, %s). b = %s"%(a, c, b)) _value_check((b < c, c <= d), "Level end parameter c must be in range (%s, %s]. c = %s"%(b, d, c)) _value_check(d >= c, "Upper bound parameter d > %s. d = %s"%(c, d)) def pdf(self, x): a, b, c, d = self.a, self.b, self.c, self.d return Piecewise( (2*(x-a) / ((b-a)*(d+c-a-b)), And(a <= x, x < b)), (2 / (d+c-a-b), And(b <= x, x < c)), (2*(d-x) / ((d-c)*(d+c-a-b)), And(c <= x, x <= d)), (S.Zero, True)) def Trapezoidal(name, a, b, c, d): r""" Create a continuous random variable with a trapezoidal distribution. Explanation =========== The density of the trapezoidal distribution is given by .. math:: f(x) := \begin{cases} 0 & \mathrm{for\ } x < a, \\ \frac{2(x-a)}{(b-a)(d+c-a-b)} & \mathrm{for\ } a \le x < b, \\ \frac{2}{d+c-a-b} & \mathrm{for\ } b \le x < c, \\ \frac{2(d-x)}{(d-c)(d+c-a-b)} & \mathrm{for\ } c \le x < d, \\ 0 & \mathrm{for\ } d < x. \end{cases} Parameters ========== a : Real number, :math:`a < d` b : Real number, :math:`a <= b < c` c : Real number, :math:`b < c <= d` d : Real number Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Trapezoidal, density >>> from sympy import Symbol, pprint >>> a = Symbol("a") >>> b = Symbol("b") >>> c = Symbol("c") >>> d = Symbol("d") >>> z = Symbol("z") >>> X = Trapezoidal("x", a,b,c,d) >>> pprint(density(X)(z), use_unicode=False) / -2*a + 2*z |------------------------- for And(a <= z, b > z) |(-a + b)*(-a - b + c + d) | | 2 | -------------- for And(b <= z, c > z) < -a - b + c + d | | 2*d - 2*z |------------------------- for And(d >= z, c <= z) |(-c + d)*(-a - b + c + d) | \ 0 otherwise References ========== .. [1] https://en.wikipedia.org/wiki/Trapezoidal_distribution """ return rv(name, TrapezoidalDistribution, (a, b, c, d)) #------------------------------------------------------------------------------- # Triangular distribution ------------------------------------------------------ class TriangularDistribution(SingleContinuousDistribution): _argnames = ('a', 'b', 'c') @property def set(self): return Interval(self.a, self.b) @staticmethod def check(a, b, c): _value_check(b > a, "Parameter b > %s. b = %s"%(a, b)) _value_check((a <= c, c <= b), "Parameter c must be in range [%s, %s]. c = %s"%(a, b, c)) def pdf(self, x): a, b, c = self.a, self.b, self.c return Piecewise( (2*(x - a)/((b - a)*(c - a)), And(a <= x, x < c)), (2/(b - a), Eq(x, c)), (2*(b - x)/((b - a)*(b - c)), And(c < x, x <= b)), (S.Zero, True)) def _characteristic_function(self, t): a, b, c = self.a, self.b, self.c return -2 *((b-c) * exp(I*a*t) - (b-a) * exp(I*c*t) + (c-a) * exp(I*b*t)) / ((b-a)*(c-a)*(b-c)*t**2) def _moment_generating_function(self, t): a, b, c = self.a, self.b, self.c return 2 * ((b - c) * exp(a * t) - (b - a) * exp(c * t) + (c - a) * exp(b * t)) / ( (b - a) * (c - a) * (b - c) * t ** 2) def Triangular(name, a, b, c): r""" Create a continuous random variable with a triangular distribution. Explanation =========== The density of the triangular distribution is given by .. math:: f(x) := \begin{cases} 0 & \mathrm{for\ } x < a, \\ \frac{2(x-a)}{(b-a)(c-a)} & \mathrm{for\ } a \le x < c, \\ \frac{2}{b-a} & \mathrm{for\ } x = c, \\ \frac{2(b-x)}{(b-a)(b-c)} & \mathrm{for\ } c < x \le b, \\ 0 & \mathrm{for\ } b < x. \end{cases} Parameters ========== a : Real number, :math:`a \in \left(-\infty, \infty\right)` b : Real number, :math:`a < b` c : Real number, :math:`a \leq c \leq b` Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Triangular, density >>> from sympy import Symbol, pprint >>> a = Symbol("a") >>> b = Symbol("b") >>> c = Symbol("c") >>> z = Symbol("z") >>> X = Triangular("x", a,b,c) >>> pprint(density(X)(z), use_unicode=False) / -2*a + 2*z |----------------- for And(a <= z, c > z) |(-a + b)*(-a + c) | | 2 | ------ for c = z < -a + b | | 2*b - 2*z |---------------- for And(b >= z, c < z) |(-a + b)*(b - c) | \ 0 otherwise References ========== .. [1] https://en.wikipedia.org/wiki/Triangular_distribution .. [2] http://mathworld.wolfram.com/TriangularDistribution.html """ return rv(name, TriangularDistribution, (a, b, c)) #------------------------------------------------------------------------------- # Uniform distribution --------------------------------------------------------- class UniformDistribution(SingleContinuousDistribution): _argnames = ('left', 'right') @property def set(self): return Interval(self.left, self.right) @staticmethod def check(left, right): _value_check(left < right, "Lower limit should be less than Upper limit.") def pdf(self, x): left, right = self.left, self.right return Piecewise( (S.One/(right - left), And(left <= x, x <= right)), (S.Zero, True) ) def _cdf(self, x): left, right = self.left, self.right return Piecewise( (S.Zero, x < left), ((x - left)/(right - left), x <= right), (S.One, True) ) def _characteristic_function(self, t): left, right = self.left, self.right return Piecewise(((exp(I*t*right) - exp(I*t*left)) / (I*t*(right - left)), Ne(t, 0)), (S.One, True)) def _moment_generating_function(self, t): left, right = self.left, self.right return Piecewise(((exp(t*right) - exp(t*left)) / (t * (right - left)), Ne(t, 0)), (S.One, True)) def expectation(self, expr, var, **kwargs): from sympy import Max, Min kwargs['evaluate'] = True result = SingleContinuousDistribution.expectation(self, expr, var, **kwargs) result = result.subs({Max(self.left, self.right): self.right, Min(self.left, self.right): self.left}) return result def Uniform(name, left, right): r""" Create a continuous random variable with a uniform distribution. Explanation =========== The density of the uniform distribution is given by .. math:: f(x) := \begin{cases} \frac{1}{b - a} & \text{for } x \in [a,b] \\ 0 & \text{otherwise} \end{cases} with :math:`x \in [a,b]`. Parameters ========== a : Real number, :math:`-\infty < a` the left boundary b : Real number, :math:`a < b < \infty` the right boundary Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Uniform, density, cdf, E, variance >>> from sympy import Symbol, simplify >>> a = Symbol("a", negative=True) >>> b = Symbol("b", positive=True) >>> z = Symbol("z") >>> X = Uniform("x", a, b) >>> density(X)(z) Piecewise((1/(-a + b), (b >= z) & (a <= z)), (0, True)) >>> cdf(X)(z) Piecewise((0, a > z), ((-a + z)/(-a + b), b >= z), (1, True)) >>> E(X) a/2 + b/2 >>> simplify(variance(X)) a**2/12 - a*b/6 + b**2/12 References ========== .. [1] https://en.wikipedia.org/wiki/Uniform_distribution_%28continuous%29 .. [2] http://mathworld.wolfram.com/UniformDistribution.html """ return rv(name, UniformDistribution, (left, right)) #------------------------------------------------------------------------------- # UniformSum distribution ------------------------------------------------------ class UniformSumDistribution(SingleContinuousDistribution): _argnames = ('n',) @property def set(self): return Interval(0, self.n) @staticmethod def check(n): _value_check((n > 0, n.is_integer), "Parameter n must be positive integer.") def pdf(self, x): n = self.n k = Dummy("k") return 1/factorial( n - 1)*Sum((-1)**k*binomial(n, k)*(x - k)**(n - 1), (k, 0, floor(x))) def _cdf(self, x): n = self.n k = Dummy("k") return Piecewise((S.Zero, x < 0), (1/factorial(n)*Sum((-1)**k*binomial(n, k)*(x - k)**(n), (k, 0, floor(x))), x <= n), (S.One, True)) def _characteristic_function(self, t): return ((exp(I*t) - 1) / (I*t))**self.n def _moment_generating_function(self, t): return ((exp(t) - 1) / t)**self.n def UniformSum(name, n): r""" Create a continuous random variable with an Irwin-Hall distribution. Explanation =========== The probability distribution function depends on a single parameter $n$ which is an integer. The density of the Irwin-Hall distribution is given by .. math :: f(x) := \frac{1}{(n-1)!}\sum_{k=0}^{\left\lfloor x\right\rfloor}(-1)^k \binom{n}{k}(x-k)^{n-1} Parameters ========== n : A positive Integer, `n > 0` Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import UniformSum, density, cdf >>> from sympy import Symbol, pprint >>> n = Symbol("n", integer=True) >>> z = Symbol("z") >>> X = UniformSum("x", n) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) floor(z) ___ \ ` \ k n - 1 /n\ ) (-1) *(-k + z) *| | / \k/ /__, k = 0 -------------------------------- (n - 1)! >>> cdf(X)(z) Piecewise((0, z < 0), (Sum((-1)**_k*(-_k + z)**n*binomial(n, _k), (_k, 0, floor(z)))/factorial(n), n >= z), (1, True)) Compute cdf with specific 'x' and 'n' values as follows : >>> cdf(UniformSum("x", 5), evaluate=False)(2).doit() 9/40 The argument evaluate=False prevents an attempt at evaluation of the sum for general n, before the argument 2 is passed. References ========== .. [1] https://en.wikipedia.org/wiki/Uniform_sum_distribution .. [2] http://mathworld.wolfram.com/UniformSumDistribution.html """ return rv(name, UniformSumDistribution, (n, )) #------------------------------------------------------------------------------- # VonMises distribution -------------------------------------------------------- class VonMisesDistribution(SingleContinuousDistribution): _argnames = ('mu', 'k') set = Interval(0, 2*pi) @staticmethod def check(mu, k): _value_check(k > 0, "k must be positive") def pdf(self, x): mu, k = self.mu, self.k return exp(k*cos(x-mu)) / (2*pi*besseli(0, k)) def VonMises(name, mu, k): r""" Create a Continuous Random Variable with a von Mises distribution. Explanation =========== The density of the von Mises distribution is given by .. math:: f(x) := \frac{e^{\kappa\cos(x-\mu)}}{2\pi I_0(\kappa)} with :math:`x \in [0,2\pi]`. Parameters ========== mu : Real number Measure of location. k : Real number Measure of concentration. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import VonMises, density >>> from sympy import Symbol, pprint >>> mu = Symbol("mu") >>> k = Symbol("k", positive=True) >>> z = Symbol("z") >>> X = VonMises("x", mu, k) >>> D = density(X)(z) >>> pprint(D, use_unicode=False) k*cos(mu - z) e ------------------ 2*pi*besseli(0, k) References ========== .. [1] https://en.wikipedia.org/wiki/Von_Mises_distribution .. [2] http://mathworld.wolfram.com/vonMisesDistribution.html """ return rv(name, VonMisesDistribution, (mu, k)) #------------------------------------------------------------------------------- # Weibull distribution --------------------------------------------------------- class WeibullDistribution(SingleContinuousDistribution): _argnames = ('alpha', 'beta') set = Interval(0, oo) @staticmethod def check(alpha, beta): _value_check(alpha > 0, "Alpha must be positive") _value_check(beta > 0, "Beta must be positive") def pdf(self, x): alpha, beta = self.alpha, self.beta return beta * (x/alpha)**(beta - 1) * exp(-(x/alpha)**beta) / alpha def Weibull(name, alpha, beta): r""" Create a continuous random variable with a Weibull distribution. Explanation =========== The density of the Weibull distribution is given by .. math:: f(x) := \begin{cases} \frac{k}{\lambda}\left(\frac{x}{\lambda}\right)^{k-1} e^{-(x/\lambda)^{k}} & x\geq0\\ 0 & x<0 \end{cases} Parameters ========== lambda : Real number, :math:`\lambda > 0` a scale k : Real number, ``k > 0`` a shape Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Weibull, density, E, variance >>> from sympy import Symbol, simplify >>> l = Symbol("lambda", positive=True) >>> k = Symbol("k", positive=True) >>> z = Symbol("z") >>> X = Weibull("x", l, k) >>> density(X)(z) k*(z/lambda)**(k - 1)*exp(-(z/lambda)**k)/lambda >>> simplify(E(X)) lambda*gamma(1 + 1/k) >>> simplify(variance(X)) lambda**2*(-gamma(1 + 1/k)**2 + gamma(1 + 2/k)) References ========== .. [1] https://en.wikipedia.org/wiki/Weibull_distribution .. [2] http://mathworld.wolfram.com/WeibullDistribution.html """ return rv(name, WeibullDistribution, (alpha, beta)) #------------------------------------------------------------------------------- # Wigner semicircle distribution ----------------------------------------------- class WignerSemicircleDistribution(SingleContinuousDistribution): _argnames = ('R',) @property def set(self): return Interval(-self.R, self.R) @staticmethod def check(R): _value_check(R > 0, "Radius R must be positive.") def pdf(self, x): R = self.R return 2/(pi*R**2)*sqrt(R**2 - x**2) def _characteristic_function(self, t): return Piecewise((2 * besselj(1, self.R*t) / (self.R*t), Ne(t, 0)), (S.One, True)) def _moment_generating_function(self, t): return Piecewise((2 * besseli(1, self.R*t) / (self.R*t), Ne(t, 0)), (S.One, True)) def WignerSemicircle(name, R): r""" Create a continuous random variable with a Wigner semicircle distribution. Explanation =========== The density of the Wigner semicircle distribution is given by .. math:: f(x) := \frac2{\pi R^2}\,\sqrt{R^2-x^2} with :math:`x \in [-R,R]`. Parameters ========== R : Real number, `R > 0`, the radius Returns ======= A `RandomSymbol`. Examples ======== >>> from sympy.stats import WignerSemicircle, density, E >>> from sympy import Symbol >>> R = Symbol("R", positive=True) >>> z = Symbol("z") >>> X = WignerSemicircle("x", R) >>> density(X)(z) 2*sqrt(R**2 - z**2)/(pi*R**2) >>> E(X) 0 References ========== .. [1] https://en.wikipedia.org/wiki/Wigner_semicircle_distribution .. [2] http://mathworld.wolfram.com/WignersSemicircleLaw.html """ return rv(name, WignerSemicircleDistribution, (R,)) sympy-sympy-1.9/sympy/stats/drv.py000066400000000000000000000263241412543434000174160ustar00rootroot00000000000000from sympy import (Basic, sympify, symbols, Dummy, Lambda, summation, Piecewise, S, cacheit, Sum, exp, I, Ne, Eq, poly, series, factorial, And, floor) from sympy.polys.polyerrors import PolynomialError from sympy.stats.crv import reduce_rational_inequalities_wrap from sympy.stats.rv import (NamedArgsMixin, SinglePSpace, SingleDomain, random_symbols, PSpace, ConditionalDomain, RandomDomain, ProductDomain, Distribution) from sympy.stats.symbolic_probability import Probability from sympy.sets.fancysets import Range, FiniteSet from sympy.sets.sets import Union from sympy.sets.contains import Contains from sympy.utilities import filldedent from sympy.core.sympify import _sympify class DiscreteDistribution(Distribution): def __call__(self, *args): return self.pdf(*args) class SingleDiscreteDistribution(DiscreteDistribution, NamedArgsMixin): """ Discrete distribution of a single variable. Serves as superclass for PoissonDistribution etc.... Provides methods for pdf, cdf, and sampling See Also: sympy.stats.crv_types.* """ set = S.Integers def __new__(cls, *args): args = list(map(sympify, args)) return Basic.__new__(cls, *args) @staticmethod def check(*args): pass @cacheit def compute_cdf(self, **kwargs): """ Compute the CDF from the PDF. Returns a Lambda. """ x = symbols('x', integer=True, cls=Dummy) z = symbols('z', real=True, cls=Dummy) left_bound = self.set.inf # CDF is integral of PDF from left bound to z pdf = self.pdf(x) cdf = summation(pdf, (x, left_bound, floor(z)), **kwargs) # CDF Ensure that CDF left of left_bound is zero cdf = Piecewise((cdf, z >= left_bound), (0, True)) return Lambda(z, cdf) def _cdf(self, x): return None def cdf(self, x, **kwargs): """ Cumulative density function """ if not kwargs: cdf = self._cdf(x) if cdf is not None: return cdf return self.compute_cdf(**kwargs)(x) @cacheit def compute_characteristic_function(self, **kwargs): """ Compute the characteristic function from the PDF. Returns a Lambda. """ x, t = symbols('x, t', real=True, cls=Dummy) pdf = self.pdf(x) cf = summation(exp(I*t*x)*pdf, (x, self.set.inf, self.set.sup)) return Lambda(t, cf) def _characteristic_function(self, t): return None def characteristic_function(self, t, **kwargs): """ Characteristic function """ if not kwargs: cf = self._characteristic_function(t) if cf is not None: return cf return self.compute_characteristic_function(**kwargs)(t) @cacheit def compute_moment_generating_function(self, **kwargs): t = Dummy('t', real=True) x = Dummy('x', integer=True) pdf = self.pdf(x) mgf = summation(exp(t*x)*pdf, (x, self.set.inf, self.set.sup)) return Lambda(t, mgf) def _moment_generating_function(self, t): return None def moment_generating_function(self, t, **kwargs): if not kwargs: mgf = self._moment_generating_function(t) if mgf is not None: return mgf return self.compute_moment_generating_function(**kwargs)(t) @cacheit def compute_quantile(self, **kwargs): """ Compute the Quantile from the PDF. Returns a Lambda. """ x = Dummy('x', integer=True) p = Dummy('p', real=True) left_bound = self.set.inf pdf = self.pdf(x) cdf = summation(pdf, (x, left_bound, x), **kwargs) set = ((x, p <= cdf), ) return Lambda(p, Piecewise(*set)) def _quantile(self, x): return None def quantile(self, x, **kwargs): """ Cumulative density function """ if not kwargs: quantile = self._quantile(x) if quantile is not None: return quantile return self.compute_quantile(**kwargs)(x) def expectation(self, expr, var, evaluate=True, **kwargs): """ Expectation of expression over distribution """ # TODO: support discrete sets with non integer stepsizes if evaluate: try: p = poly(expr, var) t = Dummy('t', real=True) mgf = self.moment_generating_function(t) deg = p.degree() taylor = poly(series(mgf, t, 0, deg + 1).removeO(), t) result = 0 for k in range(deg+1): result += p.coeff_monomial(var ** k) * taylor.coeff_monomial(t ** k) * factorial(k) return result except PolynomialError: return summation(expr * self.pdf(var), (var, self.set.inf, self.set.sup), **kwargs) else: return Sum(expr * self.pdf(var), (var, self.set.inf, self.set.sup), **kwargs) def __call__(self, *args): return self.pdf(*args) class DiscreteDomain(RandomDomain): """ A domain with discrete support with step size one. Represented using symbols and Range. """ is_Discrete = True class SingleDiscreteDomain(DiscreteDomain, SingleDomain): def as_boolean(self): return Contains(self.symbol, self.set) class ConditionalDiscreteDomain(DiscreteDomain, ConditionalDomain): """ Domain with discrete support of step size one, that is restricted by some condition. """ @property def set(self): rv = self.symbols if len(self.symbols) > 1: raise NotImplementedError(filldedent(''' Multivariate conditional domains are not yet implemented.''')) rv = list(rv)[0] return reduce_rational_inequalities_wrap(self.condition, rv).intersect(self.fulldomain.set) class DiscretePSpace(PSpace): is_real = True is_Discrete = True @property def pdf(self): return self.density(*self.symbols) def where(self, condition): rvs = random_symbols(condition) assert all(r.symbol in self.symbols for r in rvs) if len(rvs) > 1: raise NotImplementedError(filldedent('''Multivariate discrete random variables are not yet supported.''')) conditional_domain = reduce_rational_inequalities_wrap(condition, rvs[0]) conditional_domain = conditional_domain.intersect(self.domain.set) return SingleDiscreteDomain(rvs[0].symbol, conditional_domain) def probability(self, condition): complement = isinstance(condition, Ne) if complement: condition = Eq(condition.args[0], condition.args[1]) try: _domain = self.where(condition).set if condition == False or _domain is S.EmptySet: return S.Zero if condition == True or _domain == self.domain.set: return S.One prob = self.eval_prob(_domain) except NotImplementedError: from sympy.stats.rv import density expr = condition.lhs - condition.rhs dens = density(expr) if not isinstance(dens, DiscreteDistribution): from sympy.stats.drv_types import DiscreteDistributionHandmade dens = DiscreteDistributionHandmade(dens) z = Dummy('z', real=True) space = SingleDiscretePSpace(z, dens) prob = space.probability(condition.__class__(space.value, 0)) if prob is None: prob = Probability(condition) return prob if not complement else S.One - prob def eval_prob(self, _domain): sym = list(self.symbols)[0] if isinstance(_domain, Range): n = symbols('n', integer=True) inf, sup, step = (r for r in _domain.args) summand = ((self.pdf).replace( sym, n*step)) rv = summation(summand, (n, inf/step, (sup)/step - 1)).doit() return rv elif isinstance(_domain, FiniteSet): pdf = Lambda(sym, self.pdf) rv = sum(pdf(x) for x in _domain) return rv elif isinstance(_domain, Union): rv = sum(self.eval_prob(x) for x in _domain.args) return rv def conditional_space(self, condition): # XXX: Converting from set to tuple. The order matters to Lambda # though so we should be starting with a set... density = Lambda(tuple(self.symbols), self.pdf/self.probability(condition)) condition = condition.xreplace({rv: rv.symbol for rv in self.values}) domain = ConditionalDiscreteDomain(self.domain, condition) return DiscretePSpace(domain, density) class ProductDiscreteDomain(ProductDomain, DiscreteDomain): def as_boolean(self): return And(*[domain.as_boolean for domain in self.domains]) class SingleDiscretePSpace(DiscretePSpace, SinglePSpace): """ Discrete probability space over a single univariate variable """ is_real = True @property def set(self): return self.distribution.set @property def domain(self): return SingleDiscreteDomain(self.symbol, self.set) def sample(self, size=(), library='scipy', seed=None): """ Internal sample method. Returns dictionary mapping RandomSymbol to realization value. """ return {self.value: self.distribution.sample(size, library=library, seed=seed)} def compute_expectation(self, expr, rvs=None, evaluate=True, **kwargs): rvs = rvs or (self.value,) if self.value not in rvs: return expr expr = _sympify(expr) expr = expr.xreplace({rv: rv.symbol for rv in rvs}) x = self.value.symbol try: return self.distribution.expectation(expr, x, evaluate=evaluate, **kwargs) except NotImplementedError: return Sum(expr * self.pdf, (x, self.set.inf, self.set.sup), **kwargs) def compute_cdf(self, expr, **kwargs): if expr == self.value: x = Dummy("x", real=True) return Lambda(x, self.distribution.cdf(x, **kwargs)) else: raise NotImplementedError() def compute_density(self, expr, **kwargs): if expr == self.value: return self.distribution raise NotImplementedError() def compute_characteristic_function(self, expr, **kwargs): if expr == self.value: t = Dummy("t", real=True) return Lambda(t, self.distribution.characteristic_function(t, **kwargs)) else: raise NotImplementedError() def compute_moment_generating_function(self, expr, **kwargs): if expr == self.value: t = Dummy("t", real=True) return Lambda(t, self.distribution.moment_generating_function(t, **kwargs)) else: raise NotImplementedError() def compute_quantile(self, expr, **kwargs): if expr == self.value: p = Dummy("p", real=True) return Lambda(p, self.distribution.quantile(p, **kwargs)) else: raise NotImplementedError() sympy-sympy-1.9/sympy/stats/drv_types.py000066400000000000000000000443301412543434000206370ustar00rootroot00000000000000""" Contains ======== FlorySchulz Geometric Hermite Logarithmic NegativeBinomial Poisson Skellam YuleSimon Zeta """ from sympy import (Basic, factorial, exp, S, sympify, I, zeta, polylog, log, beta, hyper, binomial, Piecewise, floor, besseli, sqrt, Sum, Dummy, Lambda, Eq) from sympy.stats.drv import SingleDiscreteDistribution, SingleDiscretePSpace from sympy.stats.rv import _value_check, is_random __all__ = ['FlorySchulz', 'Geometric', 'Hermite', 'Logarithmic', 'NegativeBinomial', 'Poisson', 'Skellam', 'YuleSimon', 'Zeta' ] def rv(symbol, cls, *args, **kwargs): args = list(map(sympify, args)) dist = cls(*args) if kwargs.pop('check', True): dist.check(*args) pspace = SingleDiscretePSpace(symbol, dist) if any(is_random(arg) for arg in args): from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution pspace = CompoundPSpace(symbol, CompoundDistribution(dist)) return pspace.value class DiscreteDistributionHandmade(SingleDiscreteDistribution): _argnames = ('pdf',) def __new__(cls, pdf, set=S.Integers): return Basic.__new__(cls, pdf, set) @property def set(self): return self.args[1] @staticmethod def check(pdf, set): x = Dummy('x') val = Sum(pdf(x), (x, set._inf, set._sup)).doit() _value_check(Eq(val, 1) != S.false, "The pdf is incorrect on the given set.") def DiscreteRV(symbol, density, set=S.Integers, **kwargs): """ Create a Discrete Random Variable given the following: Parameters ========== symbol : Symbol Represents name of the random variable. density : Expression containing symbol Represents probability density function. set : set Represents the region where the pdf is valid, by default is real line. check : bool If True, it will check whether the given density integrates to 1 over the given set. If False, it will not perform this check. Default is False. Examples ======== >>> from sympy.stats import DiscreteRV, P, E >>> from sympy import Rational, Symbol >>> x = Symbol('x') >>> n = 10 >>> density = Rational(1, 10) >>> X = DiscreteRV(x, density, set=set(range(n))) >>> E(X) 9/2 >>> P(X>3) 3/5 Returns ======= RandomSymbol """ set = sympify(set) pdf = Piecewise((density, set.as_relational(symbol)), (0, True)) pdf = Lambda(symbol, pdf) # have a default of False while `rv` should have a default of True kwargs['check'] = kwargs.pop('check', False) return rv(symbol.name, DiscreteDistributionHandmade, pdf, set, **kwargs) #------------------------------------------------------------------------------- # Flory-Schulz distribution ------------------------------------------------------------ class FlorySchulzDistribution(SingleDiscreteDistribution): _argnames = ('a',) set = S.Naturals @staticmethod def check(a): _value_check((0 < a, a < 1), "a must be between 0 and 1") def pdf(self, k): a = self.a return (a**2 * k * (1 - a)**(k - 1)) def _characteristic_function(self, t): a = self.a return a**2*exp(I*t)/((1 + (a - 1)*exp(I*t))**2) def _moment_generating_function(self, t): a = self.a return a**2*exp(t)/((1 + (a - 1)*exp(t))**2) def FlorySchulz(name, a): r""" Create a discrete random variable with a FlorySchulz distribution. The density of the FlorySchulz distribution is given by .. math:: f(k) := (a^2) k (1 - a)^{k-1} Parameters ========== a A real number between 0 and 1 Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, E, variance, FlorySchulz >>> from sympy import Symbol, S >>> a = S.One / 5 >>> z = Symbol("z") >>> X = FlorySchulz("x", a) >>> density(X)(z) (4/5)**(z - 1)*z/25 >>> E(X) 9 >>> variance(X) 40 References ========== https://en.wikipedia.org/wiki/Flory%E2%80%93Schulz_distribution """ return rv(name, FlorySchulzDistribution, a) #------------------------------------------------------------------------------- # Geometric distribution ------------------------------------------------------------ class GeometricDistribution(SingleDiscreteDistribution): _argnames = ('p',) set = S.Naturals @staticmethod def check(p): _value_check((0 < p, p <= 1), "p must be between 0 and 1") def pdf(self, k): return (1 - self.p)**(k - 1) * self.p def _characteristic_function(self, t): p = self.p return p * exp(I*t) / (1 - (1 - p)*exp(I*t)) def _moment_generating_function(self, t): p = self.p return p * exp(t) / (1 - (1 - p) * exp(t)) def Geometric(name, p): r""" Create a discrete random variable with a Geometric distribution. Explanation =========== The density of the Geometric distribution is given by .. math:: f(k) := p (1 - p)^{k - 1} Parameters ========== p: A probability between 0 and 1 Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Geometric, density, E, variance >>> from sympy import Symbol, S >>> p = S.One / 5 >>> z = Symbol("z") >>> X = Geometric("x", p) >>> density(X)(z) (4/5)**(z - 1)/5 >>> E(X) 5 >>> variance(X) 20 References ========== .. [1] https://en.wikipedia.org/wiki/Geometric_distribution .. [2] http://mathworld.wolfram.com/GeometricDistribution.html """ return rv(name, GeometricDistribution, p) #------------------------------------------------------------------------------- # Hermite distribution --------------------------------------------------------- class HermiteDistribution(SingleDiscreteDistribution): _argnames = ('a1', 'a2') set = S.Naturals0 @staticmethod def check(a1, a2): _value_check(a1.is_nonnegative, 'Parameter a1 must be >= 0.') _value_check(a2.is_nonnegative, 'Parameter a2 must be >= 0.') def pdf(self, k): a1, a2 = self.a1, self.a2 term1 = exp(-(a1 + a2)) j = Dummy("j", integer=True) num = a1**(k - 2*j) * a2**j den = factorial(k - 2*j) * factorial(j) return term1 * Sum(num/den, (j, 0, k//2)).doit() def _moment_generating_function(self, t): a1, a2 = self.a1, self.a2 term1 = a1 * (exp(t) - 1) term2 = a2 * (exp(2*t) - 1) return exp(term1 + term2) def _characteristic_function(self, t): a1, a2 = self.a1, self.a2 term1 = a1 * (exp(I*t) - 1) term2 = a2 * (exp(2*I*t) - 1) return exp(term1 + term2) def Hermite(name, a1, a2): r""" Create a discrete random variable with a Hermite distribution. Explanation =========== The density of the Hermite distribution is given by .. math:: f(x):= e^{-a_1 -a_2}\sum_{j=0}^{\left \lfloor x/2 \right \rfloor} \frac{a_{1}^{x-2j}a_{2}^{j}}{(x-2j)!j!} Parameters ========== a1: A Positive number greater than equal to 0. a2: A Positive number greater than equal to 0. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Hermite, density, E, variance >>> from sympy import Symbol >>> a1 = Symbol("a1", positive=True) >>> a2 = Symbol("a2", positive=True) >>> x = Symbol("x") >>> H = Hermite("H", a1=5, a2=4) >>> density(H)(2) 33*exp(-9)/2 >>> E(H) 13 >>> variance(H) 21 References ========== .. [1] https://en.wikipedia.org/wiki/Hermite_distribution """ return rv(name, HermiteDistribution, a1, a2) #------------------------------------------------------------------------------- # Logarithmic distribution ------------------------------------------------------------ class LogarithmicDistribution(SingleDiscreteDistribution): _argnames = ('p',) set = S.Naturals @staticmethod def check(p): _value_check((p > 0, p < 1), "p should be between 0 and 1") def pdf(self, k): p = self.p return (-1) * p**k / (k * log(1 - p)) def _characteristic_function(self, t): p = self.p return log(1 - p * exp(I*t)) / log(1 - p) def _moment_generating_function(self, t): p = self.p return log(1 - p * exp(t)) / log(1 - p) def Logarithmic(name, p): r""" Create a discrete random variable with a Logarithmic distribution. Explanation =========== The density of the Logarithmic distribution is given by .. math:: f(k) := \frac{-p^k}{k \ln{(1 - p)}} Parameters ========== p: A value between 0 and 1 Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Logarithmic, density, E, variance >>> from sympy import Symbol, S >>> p = S.One / 5 >>> z = Symbol("z") >>> X = Logarithmic("x", p) >>> density(X)(z) -1/(5**z*z*log(4/5)) >>> E(X) -1/(-4*log(5) + 8*log(2)) >>> variance(X) -1/((-4*log(5) + 8*log(2))*(-2*log(5) + 4*log(2))) + 1/(-64*log(2)*log(5) + 64*log(2)**2 + 16*log(5)**2) - 10/(-32*log(5) + 64*log(2)) References ========== .. [1] https://en.wikipedia.org/wiki/Logarithmic_distribution .. [2] http://mathworld.wolfram.com/LogarithmicDistribution.html """ return rv(name, LogarithmicDistribution, p) #------------------------------------------------------------------------------- # Negative binomial distribution ------------------------------------------------------------ class NegativeBinomialDistribution(SingleDiscreteDistribution): _argnames = ('r', 'p') set = S.Naturals0 @staticmethod def check(r, p): _value_check(r > 0, 'r should be positive') _value_check((p > 0, p < 1), 'p should be between 0 and 1') def pdf(self, k): r = self.r p = self.p return binomial(k + r - 1, k) * (1 - p)**r * p**k def _characteristic_function(self, t): r = self.r p = self.p return ((1 - p) / (1 - p * exp(I*t)))**r def _moment_generating_function(self, t): r = self.r p = self.p return ((1 - p) / (1 - p * exp(t)))**r def NegativeBinomial(name, r, p): r""" Create a discrete random variable with a Negative Binomial distribution. Explanation =========== The density of the Negative Binomial distribution is given by .. math:: f(k) := \binom{k + r - 1}{k} (1 - p)^r p^k Parameters ========== r: A positive value p: A value between 0 and 1 Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import NegativeBinomial, density, E, variance >>> from sympy import Symbol, S >>> r = 5 >>> p = S.One / 5 >>> z = Symbol("z") >>> X = NegativeBinomial("x", r, p) >>> density(X)(z) 1024*binomial(z + 4, z)/(3125*5**z) >>> E(X) 5/4 >>> variance(X) 25/16 References ========== .. [1] https://en.wikipedia.org/wiki/Negative_binomial_distribution .. [2] http://mathworld.wolfram.com/NegativeBinomialDistribution.html """ return rv(name, NegativeBinomialDistribution, r, p) #------------------------------------------------------------------------------- # Poisson distribution ------------------------------------------------------------ class PoissonDistribution(SingleDiscreteDistribution): _argnames = ('lamda',) set = S.Naturals0 @staticmethod def check(lamda): _value_check(lamda > 0, "Lambda must be positive") def pdf(self, k): return self.lamda**k / factorial(k) * exp(-self.lamda) def _characteristic_function(self, t): return exp(self.lamda * (exp(I*t) - 1)) def _moment_generating_function(self, t): return exp(self.lamda * (exp(t) - 1)) def Poisson(name, lamda): r""" Create a discrete random variable with a Poisson distribution. Explanation =========== The density of the Poisson distribution is given by .. math:: f(k) := \frac{\lambda^{k} e^{- \lambda}}{k!} Parameters ========== lamda: Positive number, a rate Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Poisson, density, E, variance >>> from sympy import Symbol, simplify >>> rate = Symbol("lambda", positive=True) >>> z = Symbol("z") >>> X = Poisson("x", rate) >>> density(X)(z) lambda**z*exp(-lambda)/factorial(z) >>> E(X) lambda >>> simplify(variance(X)) lambda References ========== .. [1] https://en.wikipedia.org/wiki/Poisson_distribution .. [2] http://mathworld.wolfram.com/PoissonDistribution.html """ return rv(name, PoissonDistribution, lamda) # ----------------------------------------------------------------------------- # Skellam distribution -------------------------------------------------------- class SkellamDistribution(SingleDiscreteDistribution): _argnames = ('mu1', 'mu2') set = S.Integers @staticmethod def check(mu1, mu2): _value_check(mu1 >= 0, 'Parameter mu1 must be >= 0') _value_check(mu2 >= 0, 'Parameter mu2 must be >= 0') def pdf(self, k): (mu1, mu2) = (self.mu1, self.mu2) term1 = exp(-(mu1 + mu2)) * (mu1 / mu2) ** (k / 2) term2 = besseli(k, 2 * sqrt(mu1 * mu2)) return term1 * term2 def _cdf(self, x): raise NotImplementedError( "Skellam doesn't have closed form for the CDF.") def _characteristic_function(self, t): (mu1, mu2) = (self.mu1, self.mu2) return exp(-(mu1 + mu2) + mu1 * exp(I * t) + mu2 * exp(-I * t)) def _moment_generating_function(self, t): (mu1, mu2) = (self.mu1, self.mu2) return exp(-(mu1 + mu2) + mu1 * exp(t) + mu2 * exp(-t)) def Skellam(name, mu1, mu2): r""" Create a discrete random variable with a Skellam distribution. Explanation =========== The Skellam is the distribution of the difference N1 - N2 of two statistically independent random variables N1 and N2 each Poisson-distributed with respective expected values mu1 and mu2. The density of the Skellam distribution is given by .. math:: f(k) := e^{-(\mu_1+\mu_2)}(\frac{\mu_1}{\mu_2})^{k/2}I_k(2\sqrt{\mu_1\mu_2}) Parameters ========== mu1: A non-negative value mu2: A non-negative value Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Skellam, density, E, variance >>> from sympy import Symbol, pprint >>> z = Symbol("z", integer=True) >>> mu1 = Symbol("mu1", positive=True) >>> mu2 = Symbol("mu2", positive=True) >>> X = Skellam("x", mu1, mu2) >>> pprint(density(X)(z), use_unicode=False) z - 2 /mu1\ -mu1 - mu2 / _____ _____\ |---| *e *besseli\z, 2*\/ mu1 *\/ mu2 / \mu2/ >>> E(X) mu1 - mu2 >>> variance(X).expand() mu1 + mu2 References ========== .. [1] https://en.wikipedia.org/wiki/Skellam_distribution """ return rv(name, SkellamDistribution, mu1, mu2) #------------------------------------------------------------------------------- # Yule-Simon distribution ------------------------------------------------------------ class YuleSimonDistribution(SingleDiscreteDistribution): _argnames = ('rho',) set = S.Naturals @staticmethod def check(rho): _value_check(rho > 0, 'rho should be positive') def pdf(self, k): rho = self.rho return rho * beta(k, rho + 1) def _cdf(self, x): return Piecewise((1 - floor(x) * beta(floor(x), self.rho + 1), x >= 1), (0, True)) def _characteristic_function(self, t): rho = self.rho return rho * hyper((1, 1), (rho + 2,), exp(I*t)) * exp(I*t) / (rho + 1) def _moment_generating_function(self, t): rho = self.rho return rho * hyper((1, 1), (rho + 2,), exp(t)) * exp(t) / (rho + 1) def YuleSimon(name, rho): r""" Create a discrete random variable with a Yule-Simon distribution. Explanation =========== The density of the Yule-Simon distribution is given by .. math:: f(k) := \rho B(k, \rho + 1) Parameters ========== rho: A positive value Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import YuleSimon, density, E, variance >>> from sympy import Symbol, simplify >>> p = 5 >>> z = Symbol("z") >>> X = YuleSimon("x", p) >>> density(X)(z) 5*beta(z, 6) >>> simplify(E(X)) 5/4 >>> simplify(variance(X)) 25/48 References ========== .. [1] https://en.wikipedia.org/wiki/Yule%E2%80%93Simon_distribution """ return rv(name, YuleSimonDistribution, rho) #------------------------------------------------------------------------------- # Zeta distribution ------------------------------------------------------------ class ZetaDistribution(SingleDiscreteDistribution): _argnames = ('s',) set = S.Naturals @staticmethod def check(s): _value_check(s > 1, 's should be greater than 1') def pdf(self, k): s = self.s return 1 / (k**s * zeta(s)) def _characteristic_function(self, t): return polylog(self.s, exp(I*t)) / zeta(self.s) def _moment_generating_function(self, t): return polylog(self.s, exp(t)) / zeta(self.s) def Zeta(name, s): r""" Create a discrete random variable with a Zeta distribution. Explanation =========== The density of the Zeta distribution is given by .. math:: f(k) := \frac{1}{k^s \zeta{(s)}} Parameters ========== s: A value greater than 1 Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import Zeta, density, E, variance >>> from sympy import Symbol >>> s = 5 >>> z = Symbol("z") >>> X = Zeta("x", s) >>> density(X)(z) 1/(z**5*zeta(5)) >>> E(X) pi**4/(90*zeta(5)) >>> variance(X) -pi**8/(8100*zeta(5)**2) + zeta(3)/zeta(5) References ========== .. [1] https://en.wikipedia.org/wiki/Zeta_distribution """ return rv(name, ZetaDistribution, s) sympy-sympy-1.9/sympy/stats/error_prop.py000066400000000000000000000060421412543434000210070ustar00rootroot00000000000000"""Tools for arithmetic error propagation.""" from itertools import repeat, combinations from sympy import S, Symbol, Add, Mul, simplify, Pow, exp from sympy.stats.symbolic_probability import RandomSymbol, Variance, Covariance from sympy.stats.rv import is_random _arg0_or_var = lambda var: var.args[0] if len(var.args) > 0 else var def variance_prop(expr, consts=(), include_covar=False): r"""Symbolically propagates variance (`\sigma^2`) for expressions. This is computed as as seen in [1]_. Parameters ========== expr : Expr A sympy expression to compute the variance for. consts : sequence of Symbols, optional Represents symbols that are known constants in the expr, and thus have zero variance. All symbols not in consts are assumed to be variant. include_covar : bool, optional Flag for whether or not to include covariances, default=False. Returns ======= var_expr : Expr An expression for the total variance of the expr. The variance for the original symbols (e.g. x) are represented via instance of the Variance symbol (e.g. Variance(x)). Examples ======== >>> from sympy import symbols, exp >>> from sympy.stats.error_prop import variance_prop >>> x, y = symbols('x y') >>> variance_prop(x + y) Variance(x) + Variance(y) >>> variance_prop(x * y) x**2*Variance(y) + y**2*Variance(x) >>> variance_prop(exp(2*x)) 4*exp(4*x)*Variance(x) References ========== .. [1] https://en.wikipedia.org/wiki/Propagation_of_uncertainty """ args = expr.args if len(args) == 0: if expr in consts: return S.Zero elif is_random(expr): return Variance(expr).doit() elif isinstance(expr, Symbol): return Variance(RandomSymbol(expr)).doit() else: return S.Zero nargs = len(args) var_args = list(map(variance_prop, args, repeat(consts, nargs), repeat(include_covar, nargs))) if isinstance(expr, Add): var_expr = Add(*var_args) if include_covar: terms = [2 * Covariance(_arg0_or_var(x), _arg0_or_var(y)).expand() \ for x, y in combinations(var_args, 2)] var_expr += Add(*terms) elif isinstance(expr, Mul): terms = [v/a**2 for a, v in zip(args, var_args)] var_expr = simplify(expr**2 * Add(*terms)) if include_covar: terms = [2*Covariance(_arg0_or_var(x), _arg0_or_var(y)).expand()/(a*b) \ for (a, b), (x, y) in zip(combinations(args, 2), combinations(var_args, 2))] var_expr += Add(*terms) elif isinstance(expr, Pow): b = args[1] v = var_args[0] * (expr * b / args[0])**2 var_expr = simplify(v) elif isinstance(expr, exp): var_expr = simplify(var_args[0] * expr**2) else: # unknown how to proceed, return variance of whole expr. var_expr = Variance(expr) return var_expr sympy-sympy-1.9/sympy/stats/frv.py000066400000000000000000000401231412543434000174110ustar00rootroot00000000000000""" Finite Discrete Random Variables Module See Also ======== sympy.stats.frv_types sympy.stats.rv sympy.stats.crv """ from itertools import product from sympy import (Basic, Symbol, cacheit, sympify, Mul, And, Or, Piecewise, Eq, Lambda, exp, I, Dummy, nan, Sum, Intersection, S) from sympy.core.containers import Dict from sympy.core.logic import Logic from sympy.core.relational import Relational from sympy.core.sympify import _sympify from sympy.sets.sets import FiniteSet from sympy.stats.rv import (RandomDomain, ProductDomain, ConditionalDomain, PSpace, IndependentProductPSpace, SinglePSpace, random_symbols, sumsets, rv_subs, NamedArgsMixin, Density, Distribution) class FiniteDensity(dict): """ A domain with Finite Density. """ def __call__(self, item): """ Make instance of a class callable. If item belongs to current instance of a class, return it. Otherwise, return 0. """ item = sympify(item) if item in self: return self[item] else: return 0 @property def dict(self): """ Return item as dictionary. """ return dict(self) class FiniteDomain(RandomDomain): """ A domain with discrete finite support Represented using a FiniteSet. """ is_Finite = True @property def symbols(self): return FiniteSet(sym for sym, val in self.elements) @property def elements(self): return self.args[0] @property def dict(self): return FiniteSet(*[Dict(dict(el)) for el in self.elements]) def __contains__(self, other): return other in self.elements def __iter__(self): return self.elements.__iter__() def as_boolean(self): return Or(*[And(*[Eq(sym, val) for sym, val in item]) for item in self]) class SingleFiniteDomain(FiniteDomain): """ A FiniteDomain over a single symbol/set Example: The possibilities of a *single* die roll. """ def __new__(cls, symbol, set): if not isinstance(set, FiniteSet) and \ not isinstance(set, Intersection): set = FiniteSet(*set) return Basic.__new__(cls, symbol, set) @property def symbol(self): return self.args[0] @property def symbols(self): return FiniteSet(self.symbol) @property def set(self): return self.args[1] @property def elements(self): return FiniteSet(*[frozenset(((self.symbol, elem), )) for elem in self.set]) def __iter__(self): return (frozenset(((self.symbol, elem),)) for elem in self.set) def __contains__(self, other): sym, val = tuple(other)[0] return sym == self.symbol and val in self.set class ProductFiniteDomain(ProductDomain, FiniteDomain): """ A Finite domain consisting of several other FiniteDomains Example: The possibilities of the rolls of three independent dice """ def __iter__(self): proditer = product(*self.domains) return (sumsets(items) for items in proditer) @property def elements(self): return FiniteSet(*self) class ConditionalFiniteDomain(ConditionalDomain, ProductFiniteDomain): """ A FiniteDomain that has been restricted by a condition Example: The possibilities of a die roll under the condition that the roll is even. """ def __new__(cls, domain, condition): """ Create a new instance of ConditionalFiniteDomain class """ if condition is True: return domain cond = rv_subs(condition) return Basic.__new__(cls, domain, cond) def _test(self, elem): """ Test the value. If value is boolean, return it. If value is equality relational (two objects are equal), return it with left-hand side being equal to right-hand side. Otherwise, raise ValueError exception. """ val = self.condition.xreplace(dict(elem)) if val in [True, False]: return val elif val.is_Equality: return val.lhs == val.rhs raise ValueError("Undecidable if %s" % str(val)) def __contains__(self, other): return other in self.fulldomain and self._test(other) def __iter__(self): return (elem for elem in self.fulldomain if self._test(elem)) @property def set(self): if isinstance(self.fulldomain, SingleFiniteDomain): return FiniteSet(*[elem for elem in self.fulldomain.set if frozenset(((self.fulldomain.symbol, elem),)) in self]) else: raise NotImplementedError( "Not implemented on multi-dimensional conditional domain") def as_boolean(self): return FiniteDomain.as_boolean(self) class SingleFiniteDistribution(Distribution, NamedArgsMixin): def __new__(cls, *args): args = list(map(sympify, args)) return Basic.__new__(cls, *args) @staticmethod def check(*args): pass @property # type: ignore @cacheit def dict(self): if self.is_symbolic: return Density(self) return {k: self.pmf(k) for k in self.set} def pmf(self, *args): # to be overridden by specific distribution raise NotImplementedError() @property def set(self): # to be overridden by specific distribution raise NotImplementedError() values = property(lambda self: self.dict.values) items = property(lambda self: self.dict.items) is_symbolic = property(lambda self: False) __iter__ = property(lambda self: self.dict.__iter__) __getitem__ = property(lambda self: self.dict.__getitem__) def __call__(self, *args): return self.pmf(*args) def __contains__(self, other): return other in self.set #============================================= #========= Probability Space =============== #============================================= class FinitePSpace(PSpace): """ A Finite Probability Space Represents the probabilities of a finite number of events. """ is_Finite = True def __new__(cls, domain, density): density = {sympify(key): sympify(val) for key, val in density.items()} public_density = Dict(density) obj = PSpace.__new__(cls, domain, public_density) obj._density = density return obj def prob_of(self, elem): elem = sympify(elem) density = self._density if isinstance(list(density.keys())[0], FiniteSet): return density.get(elem, S.Zero) return density.get(tuple(elem)[0][1], S.Zero) def where(self, condition): assert all(r.symbol in self.symbols for r in random_symbols(condition)) return ConditionalFiniteDomain(self.domain, condition) def compute_density(self, expr): expr = rv_subs(expr, self.values) d = FiniteDensity() for elem in self.domain: val = expr.xreplace(dict(elem)) prob = self.prob_of(elem) d[val] = d.get(val, S.Zero) + prob return d @cacheit def compute_cdf(self, expr): d = self.compute_density(expr) cum_prob = S.Zero cdf = [] for key in sorted(d): prob = d[key] cum_prob += prob cdf.append((key, cum_prob)) return dict(cdf) @cacheit def sorted_cdf(self, expr, python_float=False): cdf = self.compute_cdf(expr) items = list(cdf.items()) sorted_items = sorted(items, key=lambda val_cumprob: val_cumprob[1]) if python_float: sorted_items = [(v, float(cum_prob)) for v, cum_prob in sorted_items] return sorted_items @cacheit def compute_characteristic_function(self, expr): d = self.compute_density(expr) t = Dummy('t', real=True) return Lambda(t, sum(exp(I*k*t)*v for k,v in d.items())) @cacheit def compute_moment_generating_function(self, expr): d = self.compute_density(expr) t = Dummy('t', real=True) return Lambda(t, sum(exp(k*t)*v for k,v in d.items())) def compute_expectation(self, expr, rvs=None, **kwargs): rvs = rvs or self.values expr = rv_subs(expr, rvs) probs = [self.prob_of(elem) for elem in self.domain] if isinstance(expr, (Logic, Relational)): parse_domain = [tuple(elem)[0][1] for elem in self.domain] bools = [expr.xreplace(dict(elem)) for elem in self.domain] else: parse_domain = [expr.xreplace(dict(elem)) for elem in self.domain] bools = [True for elem in self.domain] return sum([Piecewise((prob * elem, blv), (S.Zero, True)) for prob, elem, blv in zip(probs, parse_domain, bools)]) def compute_quantile(self, expr): cdf = self.compute_cdf(expr) p = Dummy('p', real=True) set = ((nan, (p < 0) | (p > 1)),) for key, value in cdf.items(): set = set + ((key, p <= value), ) return Lambda(p, Piecewise(*set)) def probability(self, condition): cond_symbols = frozenset(rs.symbol for rs in random_symbols(condition)) cond = rv_subs(condition) if not cond_symbols.issubset(self.symbols): raise ValueError("Cannot compare foreign random symbols, %s" %(str(cond_symbols - self.symbols))) if isinstance(condition, Relational) and \ (not cond.free_symbols.issubset(self.domain.free_symbols)): rv = condition.lhs if isinstance(condition.rhs, Symbol) else condition.rhs return sum(Piecewise( (self.prob_of(elem), condition.subs(rv, list(elem)[0][1])), (S.Zero, True)) for elem in self.domain) return sympify(sum(self.prob_of(elem) for elem in self.where(condition))) def conditional_space(self, condition): domain = self.where(condition) prob = self.probability(condition) density = {key: val / prob for key, val in self._density.items() if domain._test(key)} return FinitePSpace(domain, density) def sample(self, size=(), library='scipy', seed=None): """ Internal sample method Returns dictionary mapping RandomSymbol to realization value. """ return {self.value: self.distribution.sample(size, library, seed)} class SingleFinitePSpace(SinglePSpace, FinitePSpace): """ A single finite probability space Represents the probabilities of a set of random events that can be attributed to a single variable/symbol. This class is implemented by many of the standard FiniteRV types such as Die, Bernoulli, Coin, etc.... """ @property def domain(self): return SingleFiniteDomain(self.symbol, self.distribution.set) @property def _is_symbolic(self): """ Helper property to check if the distribution of the random variable is having symbolic dimension. """ return self.distribution.is_symbolic @property def distribution(self): return self.args[1] def pmf(self, expr): return self.distribution.pmf(expr) @property # type: ignore @cacheit def _density(self): return {FiniteSet((self.symbol, val)): prob for val, prob in self.distribution.dict.items()} @cacheit def compute_characteristic_function(self, expr): if self._is_symbolic: d = self.compute_density(expr) t = Dummy('t', real=True) ki = Dummy('ki') return Lambda(t, Sum(d(ki)*exp(I*ki*t), (ki, self.args[1].low, self.args[1].high))) expr = rv_subs(expr, self.values) return FinitePSpace(self.domain, self.distribution).compute_characteristic_function(expr) @cacheit def compute_moment_generating_function(self, expr): if self._is_symbolic: d = self.compute_density(expr) t = Dummy('t', real=True) ki = Dummy('ki') return Lambda(t, Sum(d(ki)*exp(ki*t), (ki, self.args[1].low, self.args[1].high))) expr = rv_subs(expr, self.values) return FinitePSpace(self.domain, self.distribution).compute_moment_generating_function(expr) def compute_quantile(self, expr): if self._is_symbolic: raise NotImplementedError("Computing quantile for random variables " "with symbolic dimension because the bounds of searching the required " "value is undetermined.") expr = rv_subs(expr, self.values) return FinitePSpace(self.domain, self.distribution).compute_quantile(expr) def compute_density(self, expr): if self._is_symbolic: rv = list(random_symbols(expr))[0] k = Dummy('k', integer=True) cond = True if not isinstance(expr, (Relational, Logic)) \ else expr.subs(rv, k) return Lambda(k, Piecewise((self.pmf(k), And(k >= self.args[1].low, k <= self.args[1].high, cond)), (S.Zero, True))) expr = rv_subs(expr, self.values) return FinitePSpace(self.domain, self.distribution).compute_density(expr) def compute_cdf(self, expr): if self._is_symbolic: d = self.compute_density(expr) k = Dummy('k') ki = Dummy('ki') return Lambda(k, Sum(d(ki), (ki, self.args[1].low, k))) expr = rv_subs(expr, self.values) return FinitePSpace(self.domain, self.distribution).compute_cdf(expr) def compute_expectation(self, expr, rvs=None, **kwargs): if self._is_symbolic: rv = random_symbols(expr)[0] k = Dummy('k', integer=True) expr = expr.subs(rv, k) cond = True if not isinstance(expr, (Relational, Logic)) \ else expr func = self.pmf(k) * k if cond != True else self.pmf(k) * expr return Sum(Piecewise((func, cond), (S.Zero, True)), (k, self.distribution.low, self.distribution.high)).doit() expr = _sympify(expr) expr = rv_subs(expr, rvs) return FinitePSpace(self.domain, self.distribution).compute_expectation(expr, rvs, **kwargs) def probability(self, condition): if self._is_symbolic: #TODO: Implement the mechanism for handling queries for symbolic sized distributions. raise NotImplementedError("Currently, probability queries are not " "supported for random variables with symbolic sized distributions.") condition = rv_subs(condition) return FinitePSpace(self.domain, self.distribution).probability(condition) def conditional_space(self, condition): """ This method is used for transferring the computation to probability method because conditional space of random variables with symbolic dimensions is currently not possible. """ if self._is_symbolic: self domain = self.where(condition) prob = self.probability(condition) density = {key: val / prob for key, val in self._density.items() if domain._test(key)} return FinitePSpace(domain, density) class ProductFinitePSpace(IndependentProductPSpace, FinitePSpace): """ A collection of several independent finite probability spaces """ @property def domain(self): return ProductFiniteDomain(*[space.domain for space in self.spaces]) @property # type: ignore @cacheit def _density(self): proditer = product(*[iter(space._density.items()) for space in self.spaces]) d = {} for items in proditer: elems, probs = list(zip(*items)) elem = sumsets(elems) prob = Mul(*probs) d[elem] = d.get(elem, S.Zero) + prob return Dict(d) @property # type: ignore @cacheit def density(self): return Dict(self._density) def probability(self, condition): return FinitePSpace.probability(self, condition) def compute_density(self, expr): return FinitePSpace.compute_density(self, expr) sympy-sympy-1.9/sympy/stats/frv_types.py000066400000000000000000000543711412543434000206470ustar00rootroot00000000000000""" Finite Discrete Random Variables - Prebuilt variable types Contains ======== FiniteRV DiscreteUniform Die Bernoulli Coin Binomial BetaBinomial Hypergeometric Rademacher IdealSoliton RobustSoliton """ from sympy import (S, sympify, Rational, binomial, cacheit, Integer, Dummy, Eq, Intersection, Interval, log, Range, Symbol, Lambda, Piecewise, Or, Gt, Lt, Ge, Le, Contains) from sympy import beta as beta_fn from sympy.stats.frv import (SingleFiniteDistribution, SingleFinitePSpace) from sympy.stats.rv import _value_check, Density, is_random __all__ = ['FiniteRV', 'DiscreteUniform', 'Die', 'Bernoulli', 'Coin', 'Binomial', 'BetaBinomial', 'Hypergeometric', 'Rademacher', 'IdealSoliton', 'RobustSoliton', ] def rv(name, cls, *args, **kwargs): args = list(map(sympify, args)) dist = cls(*args) if kwargs.pop('check', True): dist.check(*args) pspace = SingleFinitePSpace(name, dist) if any(is_random(arg) for arg in args): from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution pspace = CompoundPSpace(name, CompoundDistribution(dist)) return pspace.value class FiniteDistributionHandmade(SingleFiniteDistribution): @property def dict(self): return self.args[0] def pmf(self, x): x = Symbol('x') return Lambda(x, Piecewise(*( [(v, Eq(k, x)) for k, v in self.dict.items()] + [(S.Zero, True)]))) @property def set(self): return set(self.dict.keys()) @staticmethod def check(density): for p in density.values(): _value_check((p >= 0, p <= 1), "Probability at a point must be between 0 and 1.") val = sum(density.values()) _value_check(Eq(val, 1) != S.false, "Total Probability must be 1.") def FiniteRV(name, density, **kwargs): r""" Create a Finite Random Variable given a dict representing the density. Parameters ========== name : Symbol Represents name of the random variable. density: A dict Dictionary conatining the pdf of finite distribution check : bool If True, it will check whether the given density integrates to 1 over the given set. If False, it will not perform this check. Default is False. Examples ======== >>> from sympy.stats import FiniteRV, P, E >>> density = {0: .1, 1: .2, 2: .3, 3: .4} >>> X = FiniteRV('X', density) >>> E(X) 2.00000000000000 >>> P(X >= 2) 0.700000000000000 Returns ======= RandomSymbol """ # have a default of False while `rv` should have a default of True kwargs['check'] = kwargs.pop('check', False) return rv(name, FiniteDistributionHandmade, density, **kwargs) class DiscreteUniformDistribution(SingleFiniteDistribution): @staticmethod def check(*args): # not using _value_check since there is a # suggestion for the user if len(set(args)) != len(args): from sympy.utilities.iterables import multiset from sympy.utilities.misc import filldedent weights = multiset(args) n = Integer(len(args)) for k in weights: weights[k] /= n raise ValueError(filldedent(""" Repeated args detected but set expected. For a distribution having different weights for each item use the following:""") + ( '\nS("FiniteRV(%s, %s)")' % ("'X'", weights))) @property def p(self): return Rational(1, len(self.args)) @property # type: ignore @cacheit def dict(self): return {k: self.p for k in self.set} @property def set(self): return set(self.args) def pmf(self, x): if x in self.args: return self.p else: return S.Zero def DiscreteUniform(name, items): r""" Create a Finite Random Variable representing a uniform distribution over the input set. Parameters ========== items: list/tuple Items over which Uniform distribution is to be made Examples ======== >>> from sympy.stats import DiscreteUniform, density >>> from sympy import symbols >>> X = DiscreteUniform('X', symbols('a b c')) # equally likely over a, b, c >>> density(X).dict {a: 1/3, b: 1/3, c: 1/3} >>> Y = DiscreteUniform('Y', list(range(5))) # distribution over a range >>> density(Y).dict {0: 1/5, 1: 1/5, 2: 1/5, 3: 1/5, 4: 1/5} Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Discrete_uniform_distribution .. [2] http://mathworld.wolfram.com/DiscreteUniformDistribution.html """ return rv(name, DiscreteUniformDistribution, *items) class DieDistribution(SingleFiniteDistribution): _argnames = ('sides',) @staticmethod def check(sides): _value_check((sides.is_positive, sides.is_integer), "number of sides must be a positive integer.") @property def is_symbolic(self): return not self.sides.is_number @property def high(self): return self.sides @property def low(self): return S.One @property def set(self): if self.is_symbolic: return Intersection(S.Naturals0, Interval(0, self.sides)) return set(map(Integer, list(range(1, self.sides + 1)))) def pmf(self, x): x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number' or 'Symbol' or , " "'RandomSymbol' not %s" % (type(x))) cond = Ge(x, 1) & Le(x, self.sides) & Contains(x, S.Integers) return Piecewise((S.One/self.sides, cond), (S.Zero, True)) def Die(name, sides=6): r""" Create a Finite Random Variable representing a fair die. Parameters ========== sides: Integer Represents the number of sides of the Die, by default is 6 Examples ======== >>> from sympy.stats import Die, density >>> from sympy import Symbol >>> D6 = Die('D6', 6) # Six sided Die >>> density(D6).dict {1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6} >>> D4 = Die('D4', 4) # Four sided Die >>> density(D4).dict {1: 1/4, 2: 1/4, 3: 1/4, 4: 1/4} >>> n = Symbol('n', positive=True, integer=True) >>> Dn = Die('Dn', n) # n sided Die >>> density(Dn).dict Density(DieDistribution(n)) >>> density(Dn).dict.subs(n, 4).doit() {1: 1/4, 2: 1/4, 3: 1/4, 4: 1/4} Returns ======= RandomSymbol """ return rv(name, DieDistribution, sides) class BernoulliDistribution(SingleFiniteDistribution): _argnames = ('p', 'succ', 'fail') @staticmethod def check(p, succ, fail): _value_check((p >= 0, p <= 1), "p should be in range [0, 1].") @property def set(self): return {self.succ, self.fail} def pmf(self, x): if isinstance(self.succ, Symbol) and isinstance(self.fail, Symbol): return Piecewise((self.p, x == self.succ), (1 - self.p, x == self.fail), (S.Zero, True)) return Piecewise((self.p, Eq(x, self.succ)), (1 - self.p, Eq(x, self.fail)), (S.Zero, True)) def Bernoulli(name, p, succ=1, fail=0): r""" Create a Finite Random Variable representing a Bernoulli process. Parameters ========== p : Rational number between 0 and 1 Represents probability of success succ : Integer/symbol/string Represents event of success fail : Integer/symbol/string Represents event of failure Examples ======== >>> from sympy.stats import Bernoulli, density >>> from sympy import S >>> X = Bernoulli('X', S(3)/4) # 1-0 Bernoulli variable, probability = 3/4 >>> density(X).dict {0: 1/4, 1: 3/4} >>> X = Bernoulli('X', S.Half, 'Heads', 'Tails') # A fair coin toss >>> density(X).dict {Heads: 1/2, Tails: 1/2} Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Bernoulli_distribution .. [2] http://mathworld.wolfram.com/BernoulliDistribution.html """ return rv(name, BernoulliDistribution, p, succ, fail) def Coin(name, p=S.Half): r""" Create a Finite Random Variable representing a Coin toss. Parameters ========== p : Rational Numeber between 0 and 1 Represents probability of getting "Heads", by default is Half Examples ======== >>> from sympy.stats import Coin, density >>> from sympy import Rational >>> C = Coin('C') # A fair coin toss >>> density(C).dict {H: 1/2, T: 1/2} >>> C2 = Coin('C2', Rational(3, 5)) # An unfair coin >>> density(C2).dict {H: 3/5, T: 2/5} Returns ======= RandomSymbol See Also ======== sympy.stats.Binomial References ========== .. [1] https://en.wikipedia.org/wiki/Coin_flipping """ return rv(name, BernoulliDistribution, p, 'H', 'T') class BinomialDistribution(SingleFiniteDistribution): _argnames = ('n', 'p', 'succ', 'fail') @staticmethod def check(n, p, succ, fail): _value_check((n.is_integer, n.is_nonnegative), "'n' must be nonnegative integer.") _value_check((p <= 1, p >= 0), "p should be in range [0, 1].") @property def high(self): return self.n @property def low(self): return S.Zero @property def is_symbolic(self): return not self.n.is_number @property def set(self): if self.is_symbolic: return Intersection(S.Naturals0, Interval(0, self.n)) return set(self.dict.keys()) def pmf(self, x): n, p = self.n, self.p x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number' or 'Symbol' or , " "'RandomSymbol' not %s" % (type(x))) cond = Ge(x, 0) & Le(x, n) & Contains(x, S.Integers) return Piecewise((binomial(n, x) * p**x * (1 - p)**(n - x), cond), (S.Zero, True)) @property # type: ignore @cacheit def dict(self): if self.is_symbolic: return Density(self) return {k*self.succ + (self.n-k)*self.fail: self.pmf(k) for k in range(0, self.n + 1)} def Binomial(name, n, p, succ=1, fail=0): r""" Create a Finite Random Variable representing a binomial distribution. Parameters ========== n : Positive Integer Represents number of trials p : Rational Number between 0 and 1 Represents probability of success succ : Integer/symbol/string Represents event of success, by default is 1 fail : Integer/symbol/string Represents event of failure, by default is 0 Examples ======== >>> from sympy.stats import Binomial, density >>> from sympy import S, Symbol >>> X = Binomial('X', 4, S.Half) # Four "coin flips" >>> density(X).dict {0: 1/16, 1: 1/4, 2: 3/8, 3: 1/4, 4: 1/16} >>> n = Symbol('n', positive=True, integer=True) >>> p = Symbol('p', positive=True) >>> X = Binomial('X', n, S.Half) # n "coin flips" >>> density(X).dict Density(BinomialDistribution(n, 1/2, 1, 0)) >>> density(X).dict.subs(n, 4).doit() {0: 1/16, 1: 1/4, 2: 3/8, 3: 1/4, 4: 1/16} Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Binomial_distribution .. [2] http://mathworld.wolfram.com/BinomialDistribution.html """ return rv(name, BinomialDistribution, n, p, succ, fail) #------------------------------------------------------------------------------- # Beta-binomial distribution ---------------------------------------------------------- class BetaBinomialDistribution(SingleFiniteDistribution): _argnames = ('n', 'alpha', 'beta') @staticmethod def check(n, alpha, beta): _value_check((n.is_integer, n.is_nonnegative), "'n' must be nonnegative integer. n = %s." % str(n)) _value_check((alpha > 0), "'alpha' must be: alpha > 0 . alpha = %s" % str(alpha)) _value_check((beta > 0), "'beta' must be: beta > 0 . beta = %s" % str(beta)) @property def high(self): return self.n @property def low(self): return S.Zero @property def is_symbolic(self): return not self.n.is_number @property def set(self): if self.is_symbolic: return Intersection(S.Naturals0, Interval(0, self.n)) return set(map(Integer, list(range(0, self.n + 1)))) def pmf(self, k): n, a, b = self.n, self.alpha, self.beta return binomial(n, k) * beta_fn(k + a, n - k + b) / beta_fn(a, b) def BetaBinomial(name, n, alpha, beta): r""" Create a Finite Random Variable representing a Beta-binomial distribution. Parameters ========== n : Positive Integer Represents number of trials alpha : Real positive number beta : Real positive number Examples ======== >>> from sympy.stats import BetaBinomial, density >>> X = BetaBinomial('X', 2, 1, 1) >>> density(X).dict {0: 1/3, 1: 2*beta(2, 2), 2: 1/3} Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Beta-binomial_distribution .. [2] http://mathworld.wolfram.com/BetaBinomialDistribution.html """ return rv(name, BetaBinomialDistribution, n, alpha, beta) class HypergeometricDistribution(SingleFiniteDistribution): _argnames = ('N', 'm', 'n') @staticmethod def check(n, N, m): _value_check((N.is_integer, N.is_nonnegative), "'N' must be nonnegative integer. N = %s." % str(n)) _value_check((n.is_integer, n.is_nonnegative), "'n' must be nonnegative integer. n = %s." % str(n)) _value_check((m.is_integer, m.is_nonnegative), "'m' must be nonnegative integer. m = %s." % str(n)) @property def is_symbolic(self): return any(not x.is_number for x in (self.N, self.m, self.n)) @property def high(self): return Piecewise((self.n, Lt(self.n, self.m) != False), (self.m, True)) @property def low(self): return Piecewise((0, Gt(0, self.n + self.m - self.N) != False), (self.n + self.m - self.N, True)) @property def set(self): N, m, n = self.N, self.m, self.n if self.is_symbolic: return Intersection(S.Naturals0, Interval(self.low, self.high)) return {i for i in range(max(0, n + m - N), min(n, m) + 1)} def pmf(self, k): N, m, n = self.N, self.m, self.n return S(binomial(m, k) * binomial(N - m, n - k))/binomial(N, n) def Hypergeometric(name, N, m, n): r""" Create a Finite Random Variable representing a hypergeometric distribution. Parameters ========== N : Positive Integer Represents finite population of size N. m : Positive Integer Represents number of trials with required feature. n : Positive Integer Represents numbers of draws. Examples ======== >>> from sympy.stats import Hypergeometric, density >>> X = Hypergeometric('X', 10, 5, 3) # 10 marbles, 5 white (success), 3 draws >>> density(X).dict {0: 1/12, 1: 5/12, 2: 5/12, 3: 1/12} Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Hypergeometric_distribution .. [2] http://mathworld.wolfram.com/HypergeometricDistribution.html """ return rv(name, HypergeometricDistribution, N, m, n) class RademacherDistribution(SingleFiniteDistribution): @property def set(self): return {-1, 1} @property def pmf(self): k = Dummy('k') return Lambda(k, Piecewise((S.Half, Or(Eq(k, -1), Eq(k, 1))), (S.Zero, True))) def Rademacher(name): r""" Create a Finite Random Variable representing a Rademacher distribution. Examples ======== >>> from sympy.stats import Rademacher, density >>> X = Rademacher('X') >>> density(X).dict {-1: 1/2, 1: 1/2} Returns ======= RandomSymbol See Also ======== sympy.stats.Bernoulli References ========== .. [1] https://en.wikipedia.org/wiki/Rademacher_distribution """ return rv(name, RademacherDistribution) class IdealSolitonDistribution(SingleFiniteDistribution): _argnames = ('k',) @staticmethod def check(k): _value_check(k.is_integer and k.is_positive, "'k' must be a positive integer.") @property def low(self): return S.One @property def high(self): return self.k @property def set(self): return set(list(Range(1, self.k+1))) @property @cacheit def dict(self): if self.k.is_Symbol: return Density(self) d = {1: Rational(1, self.k)} d.update(dict((i, Rational(1, i*(i - 1))) for i in range(2, self.k + 1))) return d def pmf(self, x): x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number' or 'Symbol' or , " "'RandomSymbol' not %s" % (type(x))) cond1 = Eq(x, 1) & x.is_integer cond2 = Ge(x, 1) & Le(x, self.k) & x.is_integer return Piecewise((1/self.k, cond1), (1/(x*(x - 1)), cond2), (S.Zero, True)) def IdealSoliton(name, k): r""" Create a Finite Random Variable of Ideal Soliton Distribution Parameters ========== k : Positive Integer Represents the number of input symbols in an LT (Luby Transform) code. Examples ======== >>> from sympy.stats import IdealSoliton, density, P, E >>> sol = IdealSoliton('sol', 5) >>> density(sol).dict {1: 1/5, 2: 1/2, 3: 1/6, 4: 1/12, 5: 1/20} >>> density(sol).set {1, 2, 3, 4, 5} >>> from sympy import Symbol >>> k = Symbol('k', positive=True, integer=True) >>> sol = IdealSoliton('sol', k) >>> density(sol).dict Density(IdealSolitonDistribution(k)) >>> density(sol).dict.subs(k, 10).doit() {1: 1/10, 2: 1/2, 3: 1/6, 4: 1/12, 5: 1/20, 6: 1/30, 7: 1/42, 8: 1/56, 9: 1/72, 10: 1/90} >>> E(sol.subs(k, 10)) 7381/2520 >>> P(sol.subs(k, 4) > 2) 1/4 Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Soliton_distribution#Ideal_distribution .. [2] http://pages.cs.wisc.edu/~suman/courses/740/papers/luby02lt.pdf """ return rv(name, IdealSolitonDistribution, k) class RobustSolitonDistribution(SingleFiniteDistribution): _argnames= ('k', 'delta', 'c') @staticmethod def check(k, delta, c): _value_check(k.is_integer and k.is_positive, "'k' must be a positive integer") _value_check(Gt(delta, 0) and Le(delta, 1), "'delta' must be a real number in the interval (0,1)") _value_check(c.is_positive, "'c' must be a positive real number.") @property def R(self): return self.c * log(self.k/self.delta) * self.k**0.5 @property def Z(self): z = 0 for i in Range(1, round(self.k/self.R)): z += (1/i) z += log(self.R/self.delta) return 1 + z * self.R/self.k @property def low(self): return S.One @property def high(self): return self.k @property def set(self): return set(list(Range(1, self.k+1))) @property def is_symbolic(self): return not all([self.k.is_number, self.c.is_number, self.delta.is_number]) def pmf(self, x): x = sympify(x) if not (x.is_number or x.is_Symbol or is_random(x)): raise ValueError("'x' expected as an argument of type 'number' or 'Symbol' or , " "'RandomSymbol' not %s" % (type(x))) cond1 = Eq(x, 1) & x.is_integer cond2 = Ge(x, 1) & Le(x, self.k) & x.is_integer rho = Piecewise((Rational(1, self.k), cond1), (Rational(1, x*(x-1)), cond2), (S.Zero, True)) cond1 = Ge(x, 1) & Le(x, round(self.k/self.R)-1) cond2 = Eq(x, round(self.k/self.R)) tau = Piecewise((self.R/(self.k * x), cond1), (self.R * log(self.R/self.delta)/self.k, cond2), (S.Zero, True)) return (rho + tau)/self.Z def RobustSoliton(name, k, delta, c): r''' Create a Finite Random Variable of Robust Soliton Distribution Parameters ========== k : Positive Integer Represents the number of input symbols in an LT (Luby Transform) code. delta : Positive Rational Number Represents the failure probability. Must be in the interval (0,1). c : Positive Rational Number Constant of proportionality. Values close to 1 are recommended Examples ======== >>> from sympy.stats import RobustSoliton, density, P, E >>> robSol = RobustSoliton('robSol', 5, 0.5, 0.01) >>> density(robSol).dict {1: 0.204253668152708, 2: 0.490631107897393, 3: 0.165210624506162, 4: 0.0834387731899302, 5: 0.0505633404760675} >>> density(robSol).set {1, 2, 3, 4, 5} >>> from sympy import Symbol >>> k = Symbol('k', positive=True, integer=True) >>> c = Symbol('c', positive=True) >>> robSol = RobustSoliton('robSol', k, 0.5, c) >>> density(robSol).dict Density(RobustSolitonDistribution(k, 0.5, c)) >>> density(robSol).dict.subs(k, 10).subs(c, 0.03).doit() {1: 0.116641095387194, 2: 0.467045731687165, 3: 0.159984123349381, 4: 0.0821431680681869, 5: 0.0505765646770100, 6: 0.0345781523420719, 7: 0.0253132820710503, 8: 0.0194459129233227, 9: 0.0154831166726115, 10: 0.0126733075238887} >>> E(robSol.subs(k, 10).subs(c, 0.05)) 2.91358846104106 >>> P(robSol.subs(k, 4).subs(c, 0.1) > 2) 0.243650614389834 Returns ======= RandomSymbol References ========== .. [1] https://en.wikipedia.org/wiki/Soliton_distribution#Robust_distribution .. [2] http://www.inference.org.uk/mackay/itprnn/ps/588.596.pdf .. [3] http://pages.cs.wisc.edu/~suman/courses/740/papers/luby02lt.pdf ''' return rv(name, RobustSolitonDistribution, k, delta, c) sympy-sympy-1.9/sympy/stats/joint_rv.py000066400000000000000000000365151412543434000204600ustar00rootroot00000000000000""" Joint Random Variables Module See Also ======== sympy.stats.rv sympy.stats.frv sympy.stats.crv sympy.stats.drv """ from sympy import (Basic, Lambda, sympify, Indexed, Symbol, ProductSet, S, Dummy, prod) from sympy.concrete.products import Product from sympy.concrete.summations import Sum, summation from sympy.core.compatibility import iterable from sympy.core.containers import Tuple from sympy.integrals.integrals import Integral, integrate from sympy.matrices import ImmutableMatrix, matrix2numpy, list2numpy from sympy.stats.crv import SingleContinuousDistribution, SingleContinuousPSpace from sympy.stats.drv import SingleDiscreteDistribution, SingleDiscretePSpace from sympy.stats.rv import (ProductPSpace, NamedArgsMixin, Distribution, ProductDomain, RandomSymbol, random_symbols, SingleDomain, _symbol_converter) from sympy.utilities.misc import filldedent from sympy.external import import_module # __all__ = ['marginal_distribution'] class JointPSpace(ProductPSpace): """ Represents a joint probability space. Represented using symbols for each component and a distribution. """ def __new__(cls, sym, dist): if isinstance(dist, SingleContinuousDistribution): return SingleContinuousPSpace(sym, dist) if isinstance(dist, SingleDiscreteDistribution): return SingleDiscretePSpace(sym, dist) sym = _symbol_converter(sym) return Basic.__new__(cls, sym, dist) @property def set(self): return self.domain.set @property def symbol(self): return self.args[0] @property def distribution(self): return self.args[1] @property def value(self): return JointRandomSymbol(self.symbol, self) @property def component_count(self): _set = self.distribution.set if isinstance(_set, ProductSet): return S(len(_set.args)) elif isinstance(_set, Product): return _set.limits[0][-1] return S.One @property def pdf(self): sym = [Indexed(self.symbol, i) for i in range(self.component_count)] return self.distribution(*sym) @property def domain(self): rvs = random_symbols(self.distribution) if not rvs: return SingleDomain(self.symbol, self.distribution.set) return ProductDomain(*[rv.pspace.domain for rv in rvs]) def component_domain(self, index): return self.set.args[index] def marginal_distribution(self, *indices): count = self.component_count if count.atoms(Symbol): raise ValueError("Marginal distributions cannot be computed " "for symbolic dimensions. It is a work under progress.") orig = [Indexed(self.symbol, i) for i in range(count)] all_syms = [Symbol(str(i)) for i in orig] replace_dict = dict(zip(all_syms, orig)) sym = tuple(Symbol(str(Indexed(self.symbol, i))) for i in indices) limits = list([i,] for i in all_syms if i not in sym) index = 0 for i in range(count): if i not in indices: limits[index].append(self.distribution.set.args[i]) limits[index] = tuple(limits[index]) index += 1 if self.distribution.is_Continuous: f = Lambda(sym, integrate(self.distribution(*all_syms), *limits)) elif self.distribution.is_Discrete: f = Lambda(sym, summation(self.distribution(*all_syms), *limits)) return f.xreplace(replace_dict) def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): syms = tuple(self.value[i] for i in range(self.component_count)) rvs = rvs or syms if not any([i in rvs for i in syms]): return expr expr = expr*self.pdf for rv in rvs: if isinstance(rv, Indexed): expr = expr.xreplace({rv: Indexed(str(rv.base), rv.args[1])}) elif isinstance(rv, RandomSymbol): expr = expr.xreplace({rv: rv.symbol}) if self.value in random_symbols(expr): raise NotImplementedError(filldedent(''' Expectations of expression with unindexed joint random symbols cannot be calculated yet.''')) limits = tuple((Indexed(str(rv.base),rv.args[1]), self.distribution.set.args[rv.args[1]]) for rv in syms) return Integral(expr, *limits) def where(self, condition): raise NotImplementedError() def compute_density(self, expr): raise NotImplementedError() def sample(self, size=(), library='scipy', seed=None): """ Internal sample method Returns dictionary mapping RandomSymbol to realization value. """ return {RandomSymbol(self.symbol, self): self.distribution.sample(size, library=library, seed=seed)} def probability(self, condition): raise NotImplementedError() class SampleJointScipy: """Returns the sample from scipy of the given distribution""" def __new__(cls, dist, size, seed=None): return cls._sample_scipy(dist, size, seed) @classmethod def _sample_scipy(cls, dist, size, seed): """Sample from SciPy.""" import numpy if seed is None or isinstance(seed, int): rand_state = numpy.random.default_rng(seed=seed) else: rand_state = seed from scipy import stats as scipy_stats scipy_rv_map = { 'MultivariateNormalDistribution': lambda dist, size: scipy_stats.multivariate_normal.rvs( mean=matrix2numpy(dist.mu).flatten(), cov=matrix2numpy(dist.sigma), size=size, random_state=rand_state), 'MultivariateBetaDistribution': lambda dist, size: scipy_stats.dirichlet.rvs( alpha=list2numpy(dist.alpha, float).flatten(), size=size, random_state=rand_state), 'MultinomialDistribution': lambda dist, size: scipy_stats.multinomial.rvs( n=int(dist.n), p=list2numpy(dist.p, float).flatten(), size=size, random_state=rand_state) } sample_shape = { 'MultivariateNormalDistribution': lambda dist: matrix2numpy(dist.mu).flatten().shape, 'MultivariateBetaDistribution': lambda dist: list2numpy(dist.alpha).flatten().shape, 'MultinomialDistribution': lambda dist: list2numpy(dist.p).flatten().shape } dist_list = scipy_rv_map.keys() if dist.__class__.__name__ not in dist_list: return None samples = scipy_rv_map[dist.__class__.__name__](dist, size) return samples.reshape(size + sample_shape[dist.__class__.__name__](dist)) class SampleJointNumpy: """Returns the sample from numpy of the given distribution""" def __new__(cls, dist, size, seed=None): return cls._sample_numpy(dist, size, seed) @classmethod def _sample_numpy(cls, dist, size, seed): """Sample from NumPy.""" import numpy if seed is None or isinstance(seed, int): rand_state = numpy.random.default_rng(seed=seed) else: rand_state = seed numpy_rv_map = { 'MultivariateNormalDistribution': lambda dist, size: rand_state.multivariate_normal( mean=matrix2numpy(dist.mu, float).flatten(), cov=matrix2numpy(dist.sigma, float), size=size), 'MultivariateBetaDistribution': lambda dist, size: rand_state.dirichlet( alpha=list2numpy(dist.alpha, float).flatten(), size=size), 'MultinomialDistribution': lambda dist, size: rand_state.multinomial( n=int(dist.n), pvals=list2numpy(dist.p, float).flatten(), size=size) } sample_shape = { 'MultivariateNormalDistribution': lambda dist: matrix2numpy(dist.mu).flatten().shape, 'MultivariateBetaDistribution': lambda dist: list2numpy(dist.alpha).flatten().shape, 'MultinomialDistribution': lambda dist: list2numpy(dist.p).flatten().shape } dist_list = numpy_rv_map.keys() if dist.__class__.__name__ not in dist_list: return None samples = numpy_rv_map[dist.__class__.__name__](dist, prod(size)) return samples.reshape(size + sample_shape[dist.__class__.__name__](dist)) class SampleJointPymc: """Returns the sample from pymc3 of the given distribution""" def __new__(cls, dist, size, seed=None): return cls._sample_pymc3(dist, size, seed) @classmethod def _sample_pymc3(cls, dist, size, seed): """Sample from PyMC3.""" import pymc3 pymc3_rv_map = { 'MultivariateNormalDistribution': lambda dist: pymc3.MvNormal('X', mu=matrix2numpy(dist.mu, float).flatten(), cov=matrix2numpy(dist.sigma, float), shape=(1, dist.mu.shape[0])), 'MultivariateBetaDistribution': lambda dist: pymc3.Dirichlet('X', a=list2numpy(dist.alpha, float).flatten()), 'MultinomialDistribution': lambda dist: pymc3.Multinomial('X', n=int(dist.n), p=list2numpy(dist.p, float).flatten(), shape=(1, len(dist.p))) } sample_shape = { 'MultivariateNormalDistribution': lambda dist: matrix2numpy(dist.mu).flatten().shape, 'MultivariateBetaDistribution': lambda dist: list2numpy(dist.alpha).flatten().shape, 'MultinomialDistribution': lambda dist: list2numpy(dist.p).flatten().shape } dist_list = pymc3_rv_map.keys() if dist.__class__.__name__ not in dist_list: return None import logging logging.getLogger("pymc3").setLevel(logging.ERROR) with pymc3.Model(): pymc3_rv_map[dist.__class__.__name__](dist) samples = pymc3.sample(draws=prod(size), chains=1, progressbar=False, random_seed=seed, return_inferencedata=False, compute_convergence_checks=False)[:]['X'] return samples.reshape(size + sample_shape[dist.__class__.__name__](dist)) _get_sample_class_jrv = { 'scipy': SampleJointScipy, 'pymc3': SampleJointPymc, 'numpy': SampleJointNumpy } class JointDistribution(Distribution, NamedArgsMixin): """ Represented by the random variables part of the joint distribution. Contains methods for PDF, CDF, sampling, marginal densities, etc. """ _argnames = ('pdf', ) def __new__(cls, *args): args = list(map(sympify, args)) for i in range(len(args)): if isinstance(args[i], list): args[i] = ImmutableMatrix(args[i]) return Basic.__new__(cls, *args) @property def domain(self): return ProductDomain(self.symbols) @property def pdf(self): return self.density.args[1] def cdf(self, other): if not isinstance(other, dict): raise ValueError("%s should be of type dict, got %s"%(other, type(other))) rvs = other.keys() _set = self.domain.set.sets expr = self.pdf(tuple(i.args[0] for i in self.symbols)) for i in range(len(other)): if rvs[i].is_Continuous: density = Integral(expr, (rvs[i], _set[i].inf, other[rvs[i]])) elif rvs[i].is_Discrete: density = Sum(expr, (rvs[i], _set[i].inf, other[rvs[i]])) return density def sample(self, size=(), library='scipy', seed=None): """ A random realization from the distribution """ libraries = ['scipy', 'numpy', 'pymc3'] if library not in libraries: raise NotImplementedError("Sampling from %s is not supported yet." % str(library)) if not import_module(library): raise ValueError("Failed to import %s" % library) samps = _get_sample_class_jrv[library](self, size, seed=seed) if samps is not None: return samps raise NotImplementedError( "Sampling for %s is not currently implemented from %s" % (self.__class__.__name__, library) ) def __call__(self, *args): return self.pdf(*args) class JointRandomSymbol(RandomSymbol): """ Representation of random symbols with joint probability distributions to allow indexing." """ def __getitem__(self, key): if isinstance(self.pspace, JointPSpace): if (self.pspace.component_count <= key) == True: raise ValueError("Index keys for %s can only up to %s." % (self.name, self.pspace.component_count - 1)) return Indexed(self, key) class MarginalDistribution(Distribution): """ Represents the marginal distribution of a joint probability space. Initialised using a probability distribution and random variables(or their indexed components) which should be a part of the resultant distribution. """ def __new__(cls, dist, *rvs): if len(rvs) == 1 and iterable(rvs[0]): rvs = tuple(rvs[0]) if not all([isinstance(rv, (Indexed, RandomSymbol))] for rv in rvs): raise ValueError(filldedent('''Marginal distribution can be intitialised only in terms of random variables or indexed random variables''')) rvs = Tuple.fromiter(rv for rv in rvs) if not isinstance(dist, JointDistribution) and len(random_symbols(dist)) == 0: return dist return Basic.__new__(cls, dist, rvs) def check(self): pass @property def set(self): rvs = [i for i in self.args[1] if isinstance(i, RandomSymbol)] return ProductSet(*[rv.pspace.set for rv in rvs]) @property def symbols(self): rvs = self.args[1] return {rv.pspace.symbol for rv in rvs} def pdf(self, *x): expr, rvs = self.args[0], self.args[1] marginalise_out = [i for i in random_symbols(expr) if i not in rvs] if isinstance(expr, JointDistribution): count = len(expr.domain.args) x = Dummy('x', real=True, finite=True) syms = tuple(Indexed(x, i) for i in count) expr = expr.pdf(syms) else: syms = tuple(rv.pspace.symbol if isinstance(rv, RandomSymbol) else rv.args[0] for rv in rvs) return Lambda(syms, self.compute_pdf(expr, marginalise_out))(*x) def compute_pdf(self, expr, rvs): for rv in rvs: lpdf = 1 if isinstance(rv, RandomSymbol): lpdf = rv.pspace.pdf expr = self.marginalise_out(expr*lpdf, rv) return expr def marginalise_out(self, expr, rv): from sympy.concrete.summations import Sum if isinstance(rv, RandomSymbol): dom = rv.pspace.set elif isinstance(rv, Indexed): dom = rv.base.component_domain( rv.pspace.component_domain(rv.args[1])) expr = expr.xreplace({rv: rv.pspace.symbol}) if rv.pspace.is_Continuous: #TODO: Modify to support integration #for all kinds of sets. expr = Integral(expr, (rv.pspace.symbol, dom)) elif rv.pspace.is_Discrete: #incorporate this into `Sum`/`summation` if dom in (S.Integers, S.Naturals, S.Naturals0): dom = (dom.inf, dom.sup) expr = Sum(expr, (rv.pspace.symbol, dom)) return expr def __call__(self, *args): return self.pdf(*args) sympy-sympy-1.9/sympy/stats/joint_rv_types.py000066400000000000000000000720211412543434000216740ustar00rootroot00000000000000from sympy import (sympify, S, pi, sqrt, exp, Lambda, Indexed, besselk, gamma, Interval, Range, factorial, Mul, Integer, Add, rf, Eq, Piecewise, ones, Symbol, Pow, Rational, Sum, Intersection, Matrix, symbols, Product, IndexedBase) from sympy.matrices import ImmutableMatrix, MatrixSymbol from sympy.matrices.expressions.determinant import det from sympy.matrices.expressions.matexpr import MatrixElement from sympy.stats.joint_rv import JointDistribution, JointPSpace, MarginalDistribution from sympy.stats.rv import _value_check, random_symbols __all__ = ['JointRV', 'MultivariateNormal', 'MultivariateLaplace', 'Dirichlet', 'GeneralizedMultivariateLogGamma', 'GeneralizedMultivariateLogGammaOmega', 'Multinomial', 'MultivariateBeta', 'MultivariateEwens', 'MultivariateT', 'NegativeMultinomial', 'NormalGamma' ] def multivariate_rv(cls, sym, *args): args = list(map(sympify, args)) dist = cls(*args) args = dist.args dist.check(*args) return JointPSpace(sym, dist).value def marginal_distribution(rv, *indices): """ Marginal distribution function of a joint random variable. Parameters ========== rv: A random variable with a joint probability distribution. indices: component indices or the indexed random symbol for whom the joint distribution is to be calculated Returns ======= A Lambda expression in `sym`. Examples ======== >>> from sympy.stats import MultivariateNormal, marginal_distribution >>> m = MultivariateNormal('X', [1, 2], [[2, 1], [1, 2]]) >>> marginal_distribution(m, m[0])(1) 1/(2*sqrt(pi)) """ indices = list(indices) for i in range(len(indices)): if isinstance(indices[i], Indexed): indices[i] = indices[i].args[1] prob_space = rv.pspace if not indices: raise ValueError( "At least one component for marginal density is needed.") if hasattr(prob_space.distribution, '_marginal_distribution'): return prob_space.distribution._marginal_distribution(indices, rv.symbol) return prob_space.marginal_distribution(*indices) class JointDistributionHandmade(JointDistribution): _argnames = ('pdf',) is_Continuous = True @property def set(self): return self.args[1] def JointRV(symbol, pdf, _set=None): """ Create a Joint Random Variable where each of its component is conitinuous, given the following: -- a symbol -- a PDF in terms of indexed symbols of the symbol given as the first argument NOTE: As of now, the set for each component for a `JointRV` is equal to the set of all integers, which can not be changed. Examples ======== >>> from sympy import exp, pi, Indexed, S >>> from sympy.stats import density, JointRV >>> x1, x2 = (Indexed('x', i) for i in (1, 2)) >>> pdf = exp(-x1**2/2 + x1 - x2**2/2 - S(1)/2)/(2*pi) >>> N1 = JointRV('x', pdf) #Multivariate Normal distribution >>> density(N1)(1, 2) exp(-2)/(2*pi) Returns ======= RandomSymbol """ #TODO: Add support for sets provided by the user symbol = sympify(symbol) syms = list(i for i in pdf.free_symbols if isinstance(i, Indexed) and i.base == IndexedBase(symbol)) syms = tuple(sorted(syms, key = lambda index: index.args[1])) _set = S.Reals**len(syms) pdf = Lambda(syms, pdf) dist = JointDistributionHandmade(pdf, _set) jrv = JointPSpace(symbol, dist).value rvs = random_symbols(pdf) if len(rvs) != 0: dist = MarginalDistribution(dist, (jrv,)) return JointPSpace(symbol, dist).value return jrv #------------------------------------------------------------------------------- # Multivariate Normal distribution --------------------------------------------- class MultivariateNormalDistribution(JointDistribution): _argnames = ('mu', 'sigma') is_Continuous=True @property def set(self): k = self.mu.shape[0] return S.Reals**k @staticmethod def check(mu, sigma): _value_check(mu.shape[0] == sigma.shape[0], "Size of the mean vector and covariance matrix are incorrect.") #check if covariance matrix is positive semi definite or not. if not isinstance(sigma, MatrixSymbol): _value_check(sigma.is_positive_semidefinite, "The covariance matrix must be positive semi definite. ") def pdf(self, *args): mu, sigma = self.mu, self.sigma k = mu.shape[0] if len(args) == 1 and args[0].is_Matrix: args = args[0] else: args = ImmutableMatrix(args) x = args - mu density = S.One/sqrt((2*pi)**(k)*det(sigma))*exp( Rational(-1, 2)*x.transpose()*(sigma.inv()*x)) return MatrixElement(density, 0, 0) def _marginal_distribution(self, indices, sym): sym = ImmutableMatrix([Indexed(sym, i) for i in indices]) _mu, _sigma = self.mu, self.sigma k = self.mu.shape[0] for i in range(k): if i not in indices: _mu = _mu.row_del(i) _sigma = _sigma.col_del(i) _sigma = _sigma.row_del(i) return Lambda(tuple(sym), S.One/sqrt((2*pi)**(len(_mu))*det(_sigma))*exp( Rational(-1, 2)*(_mu - sym).transpose()*(_sigma.inv()*\ (_mu - sym)))[0]) def MultivariateNormal(name, mu, sigma): """ Creates a continuous random variable with Multivariate Normal Distribution. The density of the multivariate normal distribution can be found at [1]. Parameters ========== mu : List representing the mean or the mean vector sigma : Positive semidefinite square matrix Represents covariance Matrix If `sigma` is noninvertible then only sampling is supported currently Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import MultivariateNormal, density, marginal_distribution >>> from sympy import symbols, MatrixSymbol >>> X = MultivariateNormal('X', [3, 4], [[2, 1], [1, 2]]) >>> y, z = symbols('y z') >>> density(X)(y, z) sqrt(3)*exp(-y**2/3 + y*z/3 + 2*y/3 - z**2/3 + 5*z/3 - 13/3)/(6*pi) >>> density(X)(1, 2) sqrt(3)*exp(-4/3)/(6*pi) >>> marginal_distribution(X, X[1])(y) exp(-(y - 4)**2/4)/(2*sqrt(pi)) >>> marginal_distribution(X, X[0])(y) exp(-(y - 3)**2/4)/(2*sqrt(pi)) The example below shows that it is also possible to use symbolic parameters to define the MultivariateNormal class. >>> n = symbols('n', natural=True) >>> Sg = MatrixSymbol('Sg', n, n) >>> mu = MatrixSymbol('mu', n, 1) >>> obs = MatrixSymbol('obs', n, 1) >>> X = MultivariateNormal('X', mu, Sg) The density of a multivariate normal can be calculated using a matrix argument, as shown below. >>> density(X)(obs) (exp(((1/2)*mu.T - (1/2)*obs.T)*Sg**(-1)*(-mu + obs))/sqrt((2*pi)**n*Determinant(Sg)))[0, 0] References ========== .. [1] https://en.wikipedia.org/wiki/Multivariate_normal_distribution """ return multivariate_rv(MultivariateNormalDistribution, name, mu, sigma) #------------------------------------------------------------------------------- # Multivariate Laplace distribution -------------------------------------------- class MultivariateLaplaceDistribution(JointDistribution): _argnames = ('mu', 'sigma') is_Continuous=True @property def set(self): k = self.mu.shape[0] return S.Reals**k @staticmethod def check(mu, sigma): _value_check(mu.shape[0] == sigma.shape[0], "Size of the mean vector and covariance matrix are incorrect.") # check if covariance matrix is positive definite or not. if not isinstance(sigma, MatrixSymbol): _value_check(sigma.is_positive_definite, "The covariance matrix must be positive definite. ") def pdf(self, *args): mu, sigma = self.mu, self.sigma mu_T = mu.transpose() k = S(mu.shape[0]) sigma_inv = sigma.inv() args = ImmutableMatrix(args) args_T = args.transpose() x = (mu_T*sigma_inv*mu)[0] y = (args_T*sigma_inv*args)[0] v = 1 - k/2 return S(2)/((2*pi)**(S(k)/2)*sqrt(det(sigma)))\ *(y/(2 + x))**(S(v)/2)*besselk(v, sqrt((2 + x)*(y)))\ *exp((args_T*sigma_inv*mu)[0]) def MultivariateLaplace(name, mu, sigma): """ Creates a continuous random variable with Multivariate Laplace Distribution. The density of the multivariate Laplace distribution can be found at [1]. Parameters ========== mu : List representing the mean or the mean vector sigma : Positive definite square matrix Represents covariance Matrix Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import MultivariateLaplace, density >>> from sympy import symbols >>> y, z = symbols('y z') >>> X = MultivariateLaplace('X', [2, 4], [[3, 1], [1, 3]]) >>> density(X)(y, z) sqrt(2)*exp(y/4 + 5*z/4)*besselk(0, sqrt(15*y*(3*y/8 - z/8)/2 + 15*z*(-y/8 + 3*z/8)/2))/(4*pi) >>> density(X)(1, 2) sqrt(2)*exp(11/4)*besselk(0, sqrt(165)/4)/(4*pi) References ========== .. [1] https://en.wikipedia.org/wiki/Multivariate_Laplace_distribution """ return multivariate_rv(MultivariateLaplaceDistribution, name, mu, sigma) #------------------------------------------------------------------------------- # Multivariate StudentT distribution ------------------------------------------- class MultivariateTDistribution(JointDistribution): _argnames = ('mu', 'shape_mat', 'dof') is_Continuous=True @property def set(self): k = self.mu.shape[0] return S.Reals**k @staticmethod def check(mu, sigma, v): _value_check(mu.shape[0] == sigma.shape[0], "Size of the location vector and shape matrix are incorrect.") # check if covariance matrix is positive definite or not. if not isinstance(sigma, MatrixSymbol): _value_check(sigma.is_positive_definite, "The shape matrix must be positive definite. ") def pdf(self, *args): mu, sigma = self.mu, self.shape_mat v = S(self.dof) k = S(mu.shape[0]) sigma_inv = sigma.inv() args = ImmutableMatrix(args) x = args - mu return gamma((k + v)/2)/(gamma(v/2)*(v*pi)**(k/2)*sqrt(det(sigma)))\ *(1 + 1/v*(x.transpose()*sigma_inv*x)[0])**((-v - k)/2) def MultivariateT(syms, mu, sigma, v): """ Creates a joint random variable with multivariate T-distribution. Parameters ========== syms: A symbol/str For identifying the random variable. mu: A list/matrix Representing the location vector sigma: The shape matrix for the distribution Examples ======== >>> from sympy.stats import density, MultivariateT >>> from sympy import Symbol >>> x = Symbol("x") >>> X = MultivariateT("x", [1, 1], [[1, 0], [0, 1]], 2) >>> density(X)(1, 2) 2/(9*pi) Returns ======= RandomSymbol """ return multivariate_rv(MultivariateTDistribution, syms, mu, sigma, v) #------------------------------------------------------------------------------- # Multivariate Normal Gamma distribution --------------------------------------- class NormalGammaDistribution(JointDistribution): _argnames = ('mu', 'lamda', 'alpha', 'beta') is_Continuous=True @staticmethod def check(mu, lamda, alpha, beta): _value_check(mu.is_real, "Location must be real.") _value_check(lamda > 0, "Lambda must be positive") _value_check(alpha > 0, "alpha must be positive") _value_check(beta > 0, "beta must be positive") @property def set(self): return S.Reals*Interval(0, S.Infinity) def pdf(self, x, tau): beta, alpha, lamda = self.beta, self.alpha, self.lamda mu = self.mu return beta**alpha*sqrt(lamda)/(gamma(alpha)*sqrt(2*pi))*\ tau**(alpha - S.Half)*exp(-1*beta*tau)*\ exp(-1*(lamda*tau*(x - mu)**2)/S(2)) def _marginal_distribution(self, indices, *sym): if len(indices) == 2: return self.pdf(*sym) if indices[0] == 0: #For marginal over `x`, return non-standardized Student-T's #distribution x = sym[0] v, mu, sigma = self.alpha - S.Half, self.mu, \ S(self.beta)/(self.lamda * self.alpha) return Lambda(sym, gamma((v + 1)/2)/(gamma(v/2)*sqrt(pi*v)*sigma)*\ (1 + 1/v*((x - mu)/sigma)**2)**((-v -1)/2)) #For marginal over `tau`, return Gamma distribution as per construction from sympy.stats.crv_types import GammaDistribution return Lambda(sym, GammaDistribution(self.alpha, self.beta)(sym[0])) def NormalGamma(sym, mu, lamda, alpha, beta): """ Creates a bivariate joint random variable with multivariate Normal gamma distribution. Parameters ========== sym: A symbol/str For identifying the random variable. mu: A real number The mean of the normal distribution lamda: A positive integer Parameter of joint distribution alpha: A positive integer Parameter of joint distribution beta: A positive integer Parameter of joint distribution Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, NormalGamma >>> from sympy import symbols >>> X = NormalGamma('x', 0, 1, 2, 3) >>> y, z = symbols('y z') >>> density(X)(y, z) 9*sqrt(2)*z**(3/2)*exp(-3*z)*exp(-y**2*z/2)/(2*sqrt(pi)) References ========== .. [1] https://en.wikipedia.org/wiki/Normal-gamma_distribution """ return multivariate_rv(NormalGammaDistribution, sym, mu, lamda, alpha, beta) #------------------------------------------------------------------------------- # Multivariate Beta/Dirichlet distribution ------------------------------------- class MultivariateBetaDistribution(JointDistribution): _argnames = ('alpha',) is_Continuous = True @staticmethod def check(alpha): _value_check(len(alpha) >= 2, "At least two categories should be passed.") for a_k in alpha: _value_check((a_k > 0) != False, "Each concentration parameter" " should be positive.") @property def set(self): k = len(self.alpha) return Interval(0, 1)**k def pdf(self, *syms): alpha = self.alpha B = Mul.fromiter(map(gamma, alpha))/gamma(Add(*alpha)) return Mul.fromiter(sym**(a_k - 1) for a_k, sym in zip(alpha, syms))/B def MultivariateBeta(syms, *alpha): """ Creates a continuous random variable with Dirichlet/Multivariate Beta Distribution. The density of the dirichlet distribution can be found at [1]. Parameters ========== alpha: Positive real numbers Signifies concentration numbers. Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, MultivariateBeta, marginal_distribution >>> from sympy import Symbol >>> a1 = Symbol('a1', positive=True) >>> a2 = Symbol('a2', positive=True) >>> B = MultivariateBeta('B', [a1, a2]) >>> C = MultivariateBeta('C', a1, a2) >>> x = Symbol('x') >>> y = Symbol('y') >>> density(B)(x, y) x**(a1 - 1)*y**(a2 - 1)*gamma(a1 + a2)/(gamma(a1)*gamma(a2)) >>> marginal_distribution(C, C[0])(x) x**(a1 - 1)*gamma(a1 + a2)/(a2*gamma(a1)*gamma(a2)) References ========== .. [1] https://en.wikipedia.org/wiki/Dirichlet_distribution .. [2] http://mathworld.wolfram.com/DirichletDistribution.html """ if not isinstance(alpha[0], list): alpha = (list(alpha),) return multivariate_rv(MultivariateBetaDistribution, syms, alpha[0]) Dirichlet = MultivariateBeta #------------------------------------------------------------------------------- # Multivariate Ewens distribution ---------------------------------------------- class MultivariateEwensDistribution(JointDistribution): _argnames = ('n', 'theta') is_Discrete = True is_Continuous = False @staticmethod def check(n, theta): _value_check((n > 0), "sample size should be positive integer.") _value_check(theta.is_positive, "mutation rate should be positive.") @property def set(self): if not isinstance(self.n, Integer): i = Symbol('i', integer=True, positive=True) return Product(Intersection(S.Naturals0, Interval(0, self.n//i)), (i, 1, self.n)) prod_set = Range(0, self.n + 1) for i in range(2, self.n + 1): prod_set *= Range(0, self.n//i + 1) return prod_set.flatten() def pdf(self, *syms): n, theta = self.n, self.theta condi = isinstance(self.n, Integer) if not (isinstance(syms[0], IndexedBase) or condi): raise ValueError("Please use IndexedBase object for syms as " "the dimension is symbolic") term_1 = factorial(n)/rf(theta, n) if condi: term_2 = Mul.fromiter(theta**syms[j]/((j+1)**syms[j]*factorial(syms[j])) for j in range(n)) cond = Eq(sum([(k + 1)*syms[k] for k in range(n)]), n) return Piecewise((term_1 * term_2, cond), (0, True)) syms = syms[0] j, k = symbols('j, k', positive=True, integer=True) term_2 = Product(theta**syms[j]/((j+1)**syms[j]*factorial(syms[j])), (j, 0, n - 1)) cond = Eq(Sum((k + 1)*syms[k], (k, 0, n - 1)), n) return Piecewise((term_1 * term_2, cond), (0, True)) def MultivariateEwens(syms, n, theta): """ Creates a discrete random variable with Multivariate Ewens Distribution. The density of the said distribution can be found at [1]. Parameters ========== n: Positive integer Size of the sample or the integer whose partitions are considered theta: Positive real number Denotes Mutation rate Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, marginal_distribution, MultivariateEwens >>> from sympy import Symbol >>> a1 = Symbol('a1', positive=True) >>> a2 = Symbol('a2', positive=True) >>> ed = MultivariateEwens('E', 2, 1) >>> density(ed)(a1, a2) Piecewise((1/(2**a2*factorial(a1)*factorial(a2)), Eq(a1 + 2*a2, 2)), (0, True)) >>> marginal_distribution(ed, ed[0])(a1) Piecewise((1/factorial(a1), Eq(a1, 2)), (0, True)) References ========== .. [1] https://en.wikipedia.org/wiki/Ewens%27s_sampling_formula .. [2] http://www.stat.rutgers.edu/home/hcrane/Papers/STS529.pdf """ return multivariate_rv(MultivariateEwensDistribution, syms, n, theta) #------------------------------------------------------------------------------- # Generalized Multivariate Log Gamma distribution ------------------------------ class GeneralizedMultivariateLogGammaDistribution(JointDistribution): _argnames = ('delta', 'v', 'lamda', 'mu') is_Continuous=True def check(self, delta, v, l, mu): _value_check((delta >= 0, delta <= 1), "delta must be in range [0, 1].") _value_check((v > 0), "v must be positive") for lk in l: _value_check((lk > 0), "lamda must be a positive vector.") for muk in mu: _value_check((muk > 0), "mu must be a positive vector.") _value_check(len(l) > 1,"the distribution should have at least" " two random variables.") @property def set(self): return S.Reals**len(self.lamda) def pdf(self, *y): from sympy.functions.special.gamma_functions import gamma d, v, l, mu = self.delta, self.v, self.lamda, self.mu n = Symbol('n', negative=False, integer=True) k = len(l) sterm1 = Pow((1 - d), n)/\ ((gamma(v + n)**(k - 1))*gamma(v)*gamma(n + 1)) sterm2 = Mul.fromiter(mui*li**(-v - n) for mui, li in zip(mu, l)) term1 = sterm1 * sterm2 sterm3 = (v + n) * sum([mui * yi for mui, yi in zip(mu, y)]) sterm4 = sum([exp(mui * yi)/li for (mui, yi, li) in zip(mu, y, l)]) term2 = exp(sterm3 - sterm4) return Pow(d, v) * Sum(term1 * term2, (n, 0, S.Infinity)) def GeneralizedMultivariateLogGamma(syms, delta, v, lamda, mu): """ Creates a joint random variable with generalized multivariate log gamma distribution. The joint pdf can be found at [1]. Parameters ========== syms: list/tuple/set of symbols for identifying each component delta: A constant in range [0, 1] v: Positive real number lamda: List of positive real numbers mu: List of positive real numbers Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density >>> from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGamma >>> from sympy import symbols, S >>> v = 1 >>> l, mu = [1, 1, 1], [1, 1, 1] >>> d = S.Half >>> y = symbols('y_1:4', positive=True) >>> Gd = GeneralizedMultivariateLogGamma('G', d, v, l, mu) >>> density(Gd)(y[0], y[1], y[2]) Sum(exp((n + 1)*(y_1 + y_2 + y_3) - exp(y_1) - exp(y_2) - exp(y_3))/(2**n*gamma(n + 1)**3), (n, 0, oo))/2 References ========== .. [1] https://en.wikipedia.org/wiki/Generalized_multivariate_log-gamma_distribution .. [2] https://www.researchgate.net/publication/234137346_On_a_multivariate_log-gamma_distribution_and_the_use_of_the_distribution_in_the_Bayesian_analysis Note ==== If the GeneralizedMultivariateLogGamma is too long to type use, `from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGamma as GMVLG` If you want to pass the matrix omega instead of the constant delta, then use, GeneralizedMultivariateLogGammaOmega. """ return multivariate_rv(GeneralizedMultivariateLogGammaDistribution, syms, delta, v, lamda, mu) def GeneralizedMultivariateLogGammaOmega(syms, omega, v, lamda, mu): """ Extends GeneralizedMultivariateLogGamma. Parameters ========== syms: list/tuple/set of symbols For identifying each component omega: A square matrix Every element of square matrix must be absolute value of square root of correlation coefficient v: Positive real number lamda: List of positive real numbers mu: List of positive real numbers Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density >>> from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGammaOmega >>> from sympy import Matrix, symbols, S >>> omega = Matrix([[1, S.Half, S.Half], [S.Half, 1, S.Half], [S.Half, S.Half, 1]]) >>> v = 1 >>> l, mu = [1, 1, 1], [1, 1, 1] >>> G = GeneralizedMultivariateLogGammaOmega('G', omega, v, l, mu) >>> y = symbols('y_1:4', positive=True) >>> density(G)(y[0], y[1], y[2]) sqrt(2)*Sum((1 - sqrt(2)/2)**n*exp((n + 1)*(y_1 + y_2 + y_3) - exp(y_1) - exp(y_2) - exp(y_3))/gamma(n + 1)**3, (n, 0, oo))/2 References ========== .. [1] https://en.wikipedia.org/wiki/Generalized_multivariate_log-gamma_distribution .. [2] https://www.researchgate.net/publication/234137346_On_a_multivariate_log-gamma_distribution_and_the_use_of_the_distribution_in_the_Bayesian_analysis Notes ===== If the GeneralizedMultivariateLogGammaOmega is too long to type use, `from sympy.stats.joint_rv_types import GeneralizedMultivariateLogGammaOmega as GMVLGO` """ _value_check((omega.is_square, isinstance(omega, Matrix)), "omega must be a" " square matrix") for val in omega.values(): _value_check((val >= 0, val <= 1), "all values in matrix must be between 0 and 1(both inclusive).") _value_check(omega.diagonal().equals(ones(1, omega.shape[0])), "all the elements of diagonal should be 1.") _value_check((omega.shape[0] == len(lamda), len(lamda) == len(mu)), "lamda, mu should be of same length and omega should " " be of shape (length of lamda, length of mu)") _value_check(len(lamda) > 1,"the distribution should have at least" " two random variables.") delta = Pow(Rational(omega.det()), Rational(1, len(lamda) - 1)) return GeneralizedMultivariateLogGamma(syms, delta, v, lamda, mu) #------------------------------------------------------------------------------- # Multinomial distribution ----------------------------------------------------- class MultinomialDistribution(JointDistribution): _argnames = ('n', 'p') is_Continuous=False is_Discrete = True @staticmethod def check(n, p): _value_check(n > 0, "number of trials must be a positive integer") for p_k in p: _value_check((p_k >= 0, p_k <= 1), "probability must be in range [0, 1]") _value_check(Eq(sum(p), 1), "probabilities must sum to 1") @property def set(self): return Intersection(S.Naturals0, Interval(0, self.n))**len(self.p) def pdf(self, *x): n, p = self.n, self.p term_1 = factorial(n)/Mul.fromiter(factorial(x_k) for x_k in x) term_2 = Mul.fromiter(p_k**x_k for p_k, x_k in zip(p, x)) return Piecewise((term_1 * term_2, Eq(sum(x), n)), (0, True)) def Multinomial(syms, n, *p): """ Creates a discrete random variable with Multinomial Distribution. The density of the said distribution can be found at [1]. Parameters ========== n: Positive integer Represents number of trials p: List of event probabilites Must be in the range of [0, 1] Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, Multinomial, marginal_distribution >>> from sympy import symbols >>> x1, x2, x3 = symbols('x1, x2, x3', nonnegative=True, integer=True) >>> p1, p2, p3 = symbols('p1, p2, p3', positive=True) >>> M = Multinomial('M', 3, p1, p2, p3) >>> density(M)(x1, x2, x3) Piecewise((6*p1**x1*p2**x2*p3**x3/(factorial(x1)*factorial(x2)*factorial(x3)), Eq(x1 + x2 + x3, 3)), (0, True)) >>> marginal_distribution(M, M[0])(x1).subs(x1, 1) 3*p1*p2**2 + 6*p1*p2*p3 + 3*p1*p3**2 References ========== .. [1] https://en.wikipedia.org/wiki/Multinomial_distribution .. [2] http://mathworld.wolfram.com/MultinomialDistribution.html """ if not isinstance(p[0], list): p = (list(p), ) return multivariate_rv(MultinomialDistribution, syms, n, p[0]) #------------------------------------------------------------------------------- # Negative Multinomial Distribution -------------------------------------------- class NegativeMultinomialDistribution(JointDistribution): _argnames = ('k0', 'p') is_Continuous=False is_Discrete = True @staticmethod def check(k0, p): _value_check(k0 > 0, "number of failures must be a positive integer") for p_k in p: _value_check((p_k >= 0, p_k <= 1), "probability must be in range [0, 1].") _value_check(sum(p) <= 1, "success probabilities must not be greater than 1.") @property def set(self): return Range(0, S.Infinity)**len(self.p) def pdf(self, *k): k0, p = self.k0, self.p term_1 = (gamma(k0 + sum(k))*(1 - sum(p))**k0)/gamma(k0) term_2 = Mul.fromiter(pi**ki/factorial(ki) for pi, ki in zip(p, k)) return term_1 * term_2 def NegativeMultinomial(syms, k0, *p): """ Creates a discrete random variable with Negative Multinomial Distribution. The density of the said distribution can be found at [1]. Parameters ========== k0: positive integer Represents number of failures before the experiment is stopped p: List of event probabilites Must be in the range of [0, 1] Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, NegativeMultinomial, marginal_distribution >>> from sympy import symbols >>> x1, x2, x3 = symbols('x1, x2, x3', nonnegative=True, integer=True) >>> p1, p2, p3 = symbols('p1, p2, p3', positive=True) >>> N = NegativeMultinomial('M', 3, p1, p2, p3) >>> N_c = NegativeMultinomial('M', 3, 0.1, 0.1, 0.1) >>> density(N)(x1, x2, x3) p1**x1*p2**x2*p3**x3*(-p1 - p2 - p3 + 1)**3*gamma(x1 + x2 + x3 + 3)/(2*factorial(x1)*factorial(x2)*factorial(x3)) >>> marginal_distribution(N_c, N_c[0])(1).evalf().round(2) 0.25 References ========== .. [1] https://en.wikipedia.org/wiki/Negative_multinomial_distribution .. [2] http://mathworld.wolfram.com/NegativeBinomialDistribution.html """ if not isinstance(p[0], list): p = (list(p), ) return multivariate_rv(NegativeMultinomialDistribution, syms, k0, p[0]) sympy-sympy-1.9/sympy/stats/matrix_distributions.py000066400000000000000000000521021412543434000231020ustar00rootroot00000000000000from sympy import S, Basic, exp, multigamma, pi, prod from sympy.core.sympify import sympify, _sympify from sympy.matrices import (ImmutableMatrix, Inverse, Trace, Determinant, MatrixSymbol, MatrixBase, Transpose, MatrixSet, matrix2numpy) from sympy.stats.rv import (_value_check, RandomMatrixSymbol, NamedArgsMixin, PSpace, _symbol_converter, MatrixDomain, Distribution) from sympy.external import import_module ################################################################################ #------------------------Matrix Probability Space------------------------------# ################################################################################ class MatrixPSpace(PSpace): """ Represents probability space for Matrix Distributions. """ def __new__(cls, sym, distribution, dim_n, dim_m): sym = _symbol_converter(sym) dim_n, dim_m = _sympify(dim_n), _sympify(dim_m) if not (dim_n.is_integer and dim_m.is_integer): raise ValueError("Dimensions should be integers") return Basic.__new__(cls, sym, distribution, dim_n, dim_m) distribution = property(lambda self: self.args[1]) symbol = property(lambda self: self.args[0]) @property def domain(self): return MatrixDomain(self.symbol, self.distribution.set) @property def value(self): return RandomMatrixSymbol(self.symbol, self.args[2], self.args[3], self) @property def values(self): return {self.value} def compute_density(self, expr, *args): rms = expr.atoms(RandomMatrixSymbol) if len(rms) > 1 or (not isinstance(expr, RandomMatrixSymbol)): raise NotImplementedError("Currently, no algorithm has been " "implemented to handle general expressions containing " "multiple matrix distributions.") return self.distribution.pdf(expr) def sample(self, size=(), library='scipy', seed=None): """ Internal sample method Returns dictionary mapping RandomMatrixSymbol to realization value. """ return {self.value: self.distribution.sample(size, library=library, seed=seed)} def rv(symbol, cls, args): args = list(map(sympify, args)) dist = cls(*args) dist.check(*args) dim = dist.dimension pspace = MatrixPSpace(symbol, dist, dim[0], dim[1]) return pspace.value class SampleMatrixScipy: """Returns the sample from scipy of the given distribution""" def __new__(cls, dist, size, seed=None): return cls._sample_scipy(dist, size, seed) @classmethod def _sample_scipy(cls, dist, size, seed): """Sample from SciPy.""" from scipy import stats as scipy_stats import numpy scipy_rv_map = { 'WishartDistribution': lambda dist, size, rand_state: scipy_stats.wishart.rvs( df=int(dist.n), scale=matrix2numpy(dist.scale_matrix, float), size=size), 'MatrixNormalDistribution': lambda dist, size, rand_state: scipy_stats.matrix_normal.rvs( mean=matrix2numpy(dist.location_matrix, float), rowcov=matrix2numpy(dist.scale_matrix_1, float), colcov=matrix2numpy(dist.scale_matrix_2, float), size=size, random_state=rand_state) } sample_shape = { 'WishartDistribution': lambda dist: dist.scale_matrix.shape, 'MatrixNormalDistribution' : lambda dist: dist.location_matrix.shape } dist_list = scipy_rv_map.keys() if dist.__class__.__name__ not in dist_list: return None if seed is None or isinstance(seed, int): rand_state = numpy.random.default_rng(seed=seed) else: rand_state = seed samp = scipy_rv_map[dist.__class__.__name__](dist, prod(size), rand_state) return samp.reshape(size + sample_shape[dist.__class__.__name__](dist)) class SampleMatrixNumpy: """Returns the sample from numpy of the given distribution""" ### TODO: Add tests after adding matrix distributions in numpy_rv_map def __new__(cls, dist, size, seed=None): return cls._sample_numpy(dist, size, seed) @classmethod def _sample_numpy(cls, dist, size, seed): """Sample from NumPy.""" numpy_rv_map = { } sample_shape = { } dist_list = numpy_rv_map.keys() if dist.__class__.__name__ not in dist_list: return None import numpy if seed is None or isinstance(seed, int): rand_state = numpy.random.default_rng(seed=seed) else: rand_state = seed samp = numpy_rv_map[dist.__class__.__name__](dist, prod(size), rand_state) return samp.reshape(size + sample_shape[dist.__class__.__name__](dist)) class SampleMatrixPymc: """Returns the sample from pymc3 of the given distribution""" def __new__(cls, dist, size, seed=None): return cls._sample_pymc3(dist, size, seed) @classmethod def _sample_pymc3(cls, dist, size, seed): """Sample from PyMC3.""" import pymc3 pymc3_rv_map = { 'MatrixNormalDistribution': lambda dist: pymc3.MatrixNormal('X', mu=matrix2numpy(dist.location_matrix, float), rowcov=matrix2numpy(dist.scale_matrix_1, float), colcov=matrix2numpy(dist.scale_matrix_2, float), shape=dist.location_matrix.shape), 'WishartDistribution': lambda dist: pymc3.WishartBartlett('X', nu=int(dist.n), S=matrix2numpy(dist.scale_matrix, float)) } sample_shape = { 'WishartDistribution': lambda dist: dist.scale_matrix.shape, 'MatrixNormalDistribution' : lambda dist: dist.location_matrix.shape } dist_list = pymc3_rv_map.keys() if dist.__class__.__name__ not in dist_list: return None import logging logging.getLogger("pymc3").setLevel(logging.ERROR) with pymc3.Model(): pymc3_rv_map[dist.__class__.__name__](dist) samps = pymc3.sample(draws=prod(size), chains=1, progressbar=False, random_seed=seed, return_inferencedata=False, compute_convergence_checks=False)['X'] return samps.reshape(size + sample_shape[dist.__class__.__name__](dist)) _get_sample_class_matrixrv = { 'scipy': SampleMatrixScipy, 'pymc3': SampleMatrixPymc, 'numpy': SampleMatrixNumpy } ################################################################################ #-------------------------Matrix Distribution----------------------------------# ################################################################################ class MatrixDistribution(Distribution, NamedArgsMixin): """ Abstract class for Matrix Distribution. """ def __new__(cls, *args): args = list(map(sympify, args)) return Basic.__new__(cls, *args) @staticmethod def check(*args): pass def __call__(self, expr): if isinstance(expr, list): expr = ImmutableMatrix(expr) return self.pdf(expr) def sample(self, size=(), library='scipy', seed=None): """ Internal sample method Returns dictionary mapping RandomSymbol to realization value. """ libraries = ['scipy', 'numpy', 'pymc3'] if library not in libraries: raise NotImplementedError("Sampling from %s is not supported yet." % str(library)) if not import_module(library): raise ValueError("Failed to import %s" % library) samps = _get_sample_class_matrixrv[library](self, size, seed) if samps is not None: return samps raise NotImplementedError( "Sampling for %s is not currently implemented from %s" % (self.__class__.__name__, library) ) ################################################################################ #------------------------Matrix Distribution Types-----------------------------# ################################################################################ #------------------------------------------------------------------------------- # Matrix Gamma distribution ---------------------------------------------------- class MatrixGammaDistribution(MatrixDistribution): _argnames = ('alpha', 'beta', 'scale_matrix') @staticmethod def check(alpha, beta, scale_matrix): if not isinstance(scale_matrix , MatrixSymbol): _value_check(scale_matrix.is_positive_definite, "The shape " "matrix must be positive definite.") _value_check(scale_matrix.is_square, "Should " "be square matrix") _value_check(alpha.is_positive, "Shape parameter should be positive.") _value_check(beta.is_positive, "Scale parameter should be positive.") @property def set(self): k = self.scale_matrix.shape[0] return MatrixSet(k, k, S.Reals) @property def dimension(self): return self.scale_matrix.shape def pdf(self, x): alpha , beta , scale_matrix = self.alpha, self.beta, self.scale_matrix p = scale_matrix.shape[0] if isinstance(x, list): x = ImmutableMatrix(x) if not isinstance(x, (MatrixBase, MatrixSymbol)): raise ValueError("%s should be an isinstance of Matrix " "or MatrixSymbol" % str(x)) sigma_inv_x = - Inverse(scale_matrix)*x / beta term1 = exp(Trace(sigma_inv_x))/((beta**(p*alpha)) * multigamma(alpha, p)) term2 = (Determinant(scale_matrix))**(-alpha) term3 = (Determinant(x))**(alpha - S(p + 1)/2) return term1 * term2 * term3 def MatrixGamma(symbol, alpha, beta, scale_matrix): """ Creates a random variable with Matrix Gamma Distribution. The density of the said distribution can be found at [1]. Parameters ========== alpha: Positive Real number Shape Parameter beta: Positive Real number Scale Parameter scale_matrix: Positive definite real square matrix Scale Matrix Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, MatrixGamma >>> from sympy import MatrixSymbol, symbols >>> a, b = symbols('a b', positive=True) >>> M = MatrixGamma('M', a, b, [[2, 1], [1, 2]]) >>> X = MatrixSymbol('X', 2, 2) >>> density(M)(X).doit() exp(Trace(Matrix([ [-2/3, 1/3], [ 1/3, -2/3]])*X)/b)*Determinant(X)**(a - 3/2)/(3**a*sqrt(pi)*b**(2*a)*gamma(a)*gamma(a - 1/2)) >>> density(M)([[1, 0], [0, 1]]).doit() exp(-4/(3*b))/(3**a*sqrt(pi)*b**(2*a)*gamma(a)*gamma(a - 1/2)) References ========== .. [1] https://en.wikipedia.org/wiki/Matrix_gamma_distribution """ if isinstance(scale_matrix, list): scale_matrix = ImmutableMatrix(scale_matrix) return rv(symbol, MatrixGammaDistribution, (alpha, beta, scale_matrix)) #------------------------------------------------------------------------------- # Wishart Distribution --------------------------------------------------------- class WishartDistribution(MatrixDistribution): _argnames = ('n', 'scale_matrix') @staticmethod def check(n, scale_matrix): if not isinstance(scale_matrix , MatrixSymbol): _value_check(scale_matrix.is_positive_definite, "The shape " "matrix must be positive definite.") _value_check(scale_matrix.is_square, "Should " "be square matrix") _value_check(n.is_positive, "Shape parameter should be positive.") @property def set(self): k = self.scale_matrix.shape[0] return MatrixSet(k, k, S.Reals) @property def dimension(self): return self.scale_matrix.shape def pdf(self, x): n, scale_matrix = self.n, self.scale_matrix p = scale_matrix.shape[0] if isinstance(x, list): x = ImmutableMatrix(x) if not isinstance(x, (MatrixBase, MatrixSymbol)): raise ValueError("%s should be an isinstance of Matrix " "or MatrixSymbol" % str(x)) sigma_inv_x = - Inverse(scale_matrix)*x / S(2) term1 = exp(Trace(sigma_inv_x))/((2**(p*n/S(2))) * multigamma(n/S(2), p)) term2 = (Determinant(scale_matrix))**(-n/S(2)) term3 = (Determinant(x))**(S(n - p - 1)/2) return term1 * term2 * term3 def Wishart(symbol, n, scale_matrix): """ Creates a random variable with Wishart Distribution. The density of the said distribution can be found at [1]. Parameters ========== n: Positive Real number Represents degrees of freedom scale_matrix: Positive definite real square matrix Scale Matrix Returns ======= RandomSymbol Examples ======== >>> from sympy.stats import density, Wishart >>> from sympy import MatrixSymbol, symbols >>> n = symbols('n', positive=True) >>> W = Wishart('W', n, [[2, 1], [1, 2]]) >>> X = MatrixSymbol('X', 2, 2) >>> density(W)(X).doit() exp(Trace(Matrix([ [-1/3, 1/6], [ 1/6, -1/3]])*X))*Determinant(X)**(n/2 - 3/2)/(2**n*3**(n/2)*sqrt(pi)*gamma(n/2)*gamma(n/2 - 1/2)) >>> density(W)([[1, 0], [0, 1]]).doit() exp(-2/3)/(2**n*3**(n/2)*sqrt(pi)*gamma(n/2)*gamma(n/2 - 1/2)) References ========== .. [1] https://en.wikipedia.org/wiki/Wishart_distribution """ if isinstance(scale_matrix, list): scale_matrix = ImmutableMatrix(scale_matrix) return rv(symbol, WishartDistribution, (n, scale_matrix)) #------------------------------------------------------------------------------- # Matrix Normal distribution --------------------------------------------------- class MatrixNormalDistribution(MatrixDistribution): _argnames = ('location_matrix', 'scale_matrix_1', 'scale_matrix_2') @staticmethod def check(location_matrix, scale_matrix_1, scale_matrix_2): if not isinstance(scale_matrix_1 , MatrixSymbol): _value_check(scale_matrix_1.is_positive_definite, "The shape " "matrix must be positive definite.") if not isinstance(scale_matrix_2 , MatrixSymbol): _value_check(scale_matrix_2.is_positive_definite, "The shape " "matrix must be positive definite.") _value_check(scale_matrix_1.is_square, "Scale matrix 1 should be " "be square matrix") _value_check(scale_matrix_2.is_square, "Scale matrix 2 should be " "be square matrix") n = location_matrix.shape[0] p = location_matrix.shape[1] _value_check(scale_matrix_1.shape[0] == n, "Scale matrix 1 should be" " of shape %s x %s"% (str(n), str(n))) _value_check(scale_matrix_2.shape[0] == p, "Scale matrix 2 should be" " of shape %s x %s"% (str(p), str(p))) @property def set(self): n, p = self.location_matrix.shape return MatrixSet(n, p, S.Reals) @property def dimension(self): return self.location_matrix.shape def pdf(self, x): M , U , V = self.location_matrix, self.scale_matrix_1, self.scale_matrix_2 n, p = M.shape if isinstance(x, list): x = ImmutableMatrix(x) if not isinstance(x, (MatrixBase, MatrixSymbol)): raise ValueError("%s should be an isinstance of Matrix " "or MatrixSymbol" % str(x)) term1 = Inverse(V)*Transpose(x - M)*Inverse(U)*(x - M) num = exp(-Trace(term1)/S(2)) den = (2*pi)**(S(n*p)/2) * Determinant(U)**S(p)/2 * Determinant(V)**S(n)/2 return num/den def MatrixNormal(symbol, location_matrix, scale_matrix_1, scale_matrix_2): """ Creates a random variable with Matrix Normal Distribution. The density of the said distribution can be found at [1]. Parameters ========== location_matrix: Real ``n x p`` matrix Represents degrees of freedom scale_matrix_1: Positive definite matrix Scale Matrix of shape ``n x n`` scale_matrix_2: Positive definite matrix Scale Matrix of shape ``p x p`` Returns ======= RandomSymbol Examples ======== >>> from sympy import MatrixSymbol >>> from sympy.stats import density, MatrixNormal >>> M = MatrixNormal('M', [[1, 2]], [1], [[1, 0], [0, 1]]) >>> X = MatrixSymbol('X', 1, 2) >>> density(M)(X).doit() 2*exp(-Trace((Matrix([ [-1], [-2]]) + X.T)*(Matrix([[-1, -2]]) + X))/2)/pi >>> density(M)([[3, 4]]).doit() 2*exp(-4)/pi References ========== .. [1] https://en.wikipedia.org/wiki/Matrix_normal_distribution """ if isinstance(location_matrix, list): location_matrix = ImmutableMatrix(location_matrix) if isinstance(scale_matrix_1, list): scale_matrix_1 = ImmutableMatrix(scale_matrix_1) if isinstance(scale_matrix_2, list): scale_matrix_2 = ImmutableMatrix(scale_matrix_2) args = (location_matrix, scale_matrix_1, scale_matrix_2) return rv(symbol, MatrixNormalDistribution, args) #------------------------------------------------------------------------------- # Matrix Student's T distribution --------------------------------------------------- class MatrixStudentTDistribution(MatrixDistribution): _argnames = ('nu', 'location_matrix', 'scale_matrix_1', 'scale_matrix_2') @staticmethod def check(nu, location_matrix, scale_matrix_1, scale_matrix_2): if not isinstance(scale_matrix_1, MatrixSymbol): _value_check(scale_matrix_1.is_positive_definite != False, "The shape " "matrix must be positive definite.") if not isinstance(scale_matrix_2, MatrixSymbol): _value_check(scale_matrix_2.is_positive_definite != False, "The shape " "matrix must be positive definite.") _value_check(scale_matrix_1.is_square != False, "Scale matrix 1 should be " "be square matrix") _value_check(scale_matrix_2.is_square != False, "Scale matrix 2 should be " "be square matrix") n = location_matrix.shape[0] p = location_matrix.shape[1] _value_check(scale_matrix_1.shape[0] == p, "Scale matrix 1 should be" " of shape %s x %s" % (str(p), str(p))) _value_check(scale_matrix_2.shape[0] == n, "Scale matrix 2 should be" " of shape %s x %s" % (str(n), str(n))) _value_check(nu.is_positive != False, "Degrees of freedom must be positive") @property def set(self): n, p = self.location_matrix.shape return MatrixSet(n, p, S.Reals) @property def dimension(self): return self.location_matrix.shape def pdf(self, x): from sympy import eye if isinstance(x, list): x = ImmutableMatrix(x) if not isinstance(x, (MatrixBase, MatrixSymbol)): raise ValueError("%s should be an isinstance of Matrix " "or MatrixSymbol" % str(x)) nu, M, Omega, Sigma = self.nu, self.location_matrix, self.scale_matrix_1, self.scale_matrix_2 n, p = M.shape K = multigamma((nu + n + p - 1)/2, p) * Determinant(Omega)**(-n/2) * Determinant(Sigma)**(-p/2) \ / ((pi)**(n*p/2) * multigamma((nu + p - 1)/2, p)) return K * (Determinant(eye(n) + Inverse(Sigma)*(x - M)*Inverse(Omega)*Transpose(x - M))) \ **(-(nu + n + p -1)/2) def MatrixStudentT(symbol, nu, location_matrix, scale_matrix_1, scale_matrix_2): """ Creates a random variable with Matrix Gamma Distribution. The density of the said distribution can be found at [1]. Parameters ========== nu: Positive Real number degrees of freedom location_matrix: Positive definite real square matrix Location Matrix of shape ``n x p`` scale_matrix_1: Positive definite real square matrix Scale Matrix of shape ``p x p`` scale_matrix_2: Positive definite real square matrix Scale Matrix of shape ``n x n`` Returns ======= RandomSymbol Examples ======== >>> from sympy import MatrixSymbol,symbols >>> from sympy.stats import density, MatrixStudentT >>> v = symbols('v',positive=True) >>> M = MatrixStudentT('M', v, [[1, 2]], [[1, 0], [0, 1]], [1]) >>> X = MatrixSymbol('X', 1, 2) >>> density(M)(X) gamma(v/2 + 1)*Determinant((Matrix([[-1, -2]]) + X)*(Matrix([ [-1], [-2]]) + X.T) + Matrix([[1]]))**(-v/2 - 1)/(pi**1.0*gamma(v/2)*Determinant(Matrix([[1]]))**1.0*Determinant(Matrix([ [1, 0], [0, 1]]))**0.5) References ========== .. [1] https://en.wikipedia.org/wiki/Matrix_t-distribution """ if isinstance(location_matrix, list): location_matrix = ImmutableMatrix(location_matrix) if isinstance(scale_matrix_1, list): scale_matrix_1 = ImmutableMatrix(scale_matrix_1) if isinstance(scale_matrix_2, list): scale_matrix_2 = ImmutableMatrix(scale_matrix_2) args = (nu, location_matrix, scale_matrix_1, scale_matrix_2) return rv(symbol, MatrixStudentTDistribution, args) sympy-sympy-1.9/sympy/stats/random_matrix.py000066400000000000000000000015271412543434000214650ustar00rootroot00000000000000from sympy import Basic from sympy.stats.rv import PSpace, _symbol_converter, RandomMatrixSymbol class RandomMatrixPSpace(PSpace): """ Represents probability space for random matrices. It contains the mechanics for handling the API calls for random matrices. """ def __new__(cls, sym, model=None): sym = _symbol_converter(sym) return Basic.__new__(cls, sym, model) model = property(lambda self: self.args[1]) def compute_density(self, expr, *args): rms = expr.atoms(RandomMatrixSymbol) if len(rms) > 2 or (not isinstance(expr, RandomMatrixSymbol)): raise NotImplementedError("Currently, no algorithm has been " "implemented to handle general expressions containing " "multiple random matrices.") return self.model.density(expr) sympy-sympy-1.9/sympy/stats/random_matrix_models.py000066400000000000000000000347561412543434000230420ustar00rootroot00000000000000from sympy import (Basic, exp, pi, Lambda, Trace, S, MatrixSymbol, Integral, gamma, Product, Dummy, Sum, Abs, IndexedBase, I) from sympy.core.sympify import _sympify from sympy.stats.rv import _symbol_converter, Density, RandomMatrixSymbol, is_random from sympy.stats.joint_rv_types import JointDistributionHandmade from sympy.stats.random_matrix import RandomMatrixPSpace from sympy.tensor.array import ArrayComprehension __all__ = [ 'CircularEnsemble', 'CircularUnitaryEnsemble', 'CircularOrthogonalEnsemble', 'CircularSymplecticEnsemble', 'GaussianEnsemble', 'GaussianUnitaryEnsemble', 'GaussianOrthogonalEnsemble', 'GaussianSymplecticEnsemble', 'joint_eigen_distribution', 'JointEigenDistribution', 'level_spacing_distribution' ] @is_random.register(RandomMatrixSymbol) def _(x): return True class RandomMatrixEnsembleModel(Basic): """ Base class for random matrix ensembles. It acts as an umbrella and contains the methods common to all the ensembles defined in sympy.stats.random_matrix_models. """ def __new__(cls, sym, dim=None): sym, dim = _symbol_converter(sym), _sympify(dim) if dim.is_integer == False: raise ValueError("Dimension of the random matrices must be " "integers, received %s instead."%(dim)) return Basic.__new__(cls, sym, dim) symbol = property(lambda self: self.args[0]) dimension = property(lambda self: self.args[1]) def density(self, expr): return Density(expr) def __call__(self, expr): return self.density(expr) class GaussianEnsembleModel(RandomMatrixEnsembleModel): """ Abstract class for Gaussian ensembles. Contains the properties common to all the gaussian ensembles. References ========== .. [1] https://en.wikipedia.org/wiki/Random_matrix#Gaussian_ensembles .. [2] https://arxiv.org/pdf/1712.07903.pdf """ def _compute_normalization_constant(self, beta, n): """ Helper function for computing normalization constant for joint probability density of eigen values of Gaussian ensembles. References ========== .. [1] https://en.wikipedia.org/wiki/Selberg_integral#Mehta's_integral """ n = S(n) prod_term = lambda j: gamma(1 + beta*S(j)/2)/gamma(S.One + beta/S(2)) j = Dummy('j', integer=True, positive=True) term1 = Product(prod_term(j), (j, 1, n)).doit() term2 = (2/(beta*n))**(beta*n*(n - 1)/4 + n/2) term3 = (2*pi)**(n/2) return term1 * term2 * term3 def _compute_joint_eigen_distribution(self, beta): """ Helper function for computing the joint probability distribution of eigen values of the random matrix. """ n = self.dimension Zbn = self._compute_normalization_constant(beta, n) l = IndexedBase('l') i = Dummy('i', integer=True, positive=True) j = Dummy('j', integer=True, positive=True) k = Dummy('k', integer=True, positive=True) term1 = exp((-S(n)/2) * Sum(l[k]**2, (k, 1, n)).doit()) sub_term = Lambda(i, Product(Abs(l[j] - l[i])**beta, (j, i + 1, n))) term2 = Product(sub_term(i).doit(), (i, 1, n - 1)).doit() syms = ArrayComprehension(l[k], (k, 1, n)).doit() return Lambda(tuple(syms), (term1 * term2)/Zbn) class GaussianUnitaryEnsembleModel(GaussianEnsembleModel): @property def normalization_constant(self): n = self.dimension return 2**(S(n)/2) * pi**(S(n**2)/2) def density(self, expr): n, ZGUE = self.dimension, self.normalization_constant h_pspace = RandomMatrixPSpace('P', model=self) H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) return Lambda(H, exp(-S(n)/2 * Trace(H**2))/ZGUE)(expr) def joint_eigen_distribution(self): return self._compute_joint_eigen_distribution(S(2)) def level_spacing_distribution(self): s = Dummy('s') f = (32/pi**2)*(s**2)*exp((-4/pi)*s**2) return Lambda(s, f) class GaussianOrthogonalEnsembleModel(GaussianEnsembleModel): @property def normalization_constant(self): n = self.dimension _H = MatrixSymbol('_H', n, n) return Integral(exp(-S(n)/4 * Trace(_H**2))) def density(self, expr): n, ZGOE = self.dimension, self.normalization_constant h_pspace = RandomMatrixPSpace('P', model=self) H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) return Lambda(H, exp(-S(n)/4 * Trace(H**2))/ZGOE)(expr) def joint_eigen_distribution(self): return self._compute_joint_eigen_distribution(S.One) def level_spacing_distribution(self): s = Dummy('s') f = (pi/2)*s*exp((-pi/4)*s**2) return Lambda(s, f) class GaussianSymplecticEnsembleModel(GaussianEnsembleModel): @property def normalization_constant(self): n = self.dimension _H = MatrixSymbol('_H', n, n) return Integral(exp(-S(n) * Trace(_H**2))) def density(self, expr): n, ZGSE = self.dimension, self.normalization_constant h_pspace = RandomMatrixPSpace('P', model=self) H = RandomMatrixSymbol('H', n, n, pspace=h_pspace) return Lambda(H, exp(-S(n) * Trace(H**2))/ZGSE)(expr) def joint_eigen_distribution(self): return self._compute_joint_eigen_distribution(S(4)) def level_spacing_distribution(self): s = Dummy('s') f = ((S(2)**18)/((S(3)**6)*(pi**3)))*(s**4)*exp((-64/(9*pi))*s**2) return Lambda(s, f) def GaussianEnsemble(sym, dim): sym, dim = _symbol_converter(sym), _sympify(dim) model = GaussianEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) def GaussianUnitaryEnsemble(sym, dim): """ Represents Gaussian Unitary Ensembles. Examples ======== >>> from sympy.stats import GaussianUnitaryEnsemble as GUE, density >>> from sympy import MatrixSymbol >>> G = GUE('U', 2) >>> X = MatrixSymbol('X', 2, 2) >>> density(G)(X) exp(-Trace(X**2))/(2*pi**2) """ sym, dim = _symbol_converter(sym), _sympify(dim) model = GaussianUnitaryEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) def GaussianOrthogonalEnsemble(sym, dim): """ Represents Gaussian Orthogonal Ensembles. Examples ======== >>> from sympy.stats import GaussianOrthogonalEnsemble as GOE, density >>> from sympy import MatrixSymbol >>> G = GOE('U', 2) >>> X = MatrixSymbol('X', 2, 2) >>> density(G)(X) exp(-Trace(X**2)/2)/Integral(exp(-Trace(_H**2)/2), _H) """ sym, dim = _symbol_converter(sym), _sympify(dim) model = GaussianOrthogonalEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) def GaussianSymplecticEnsemble(sym, dim): """ Represents Gaussian Symplectic Ensembles. Examples ======== >>> from sympy.stats import GaussianSymplecticEnsemble as GSE, density >>> from sympy import MatrixSymbol >>> G = GSE('U', 2) >>> X = MatrixSymbol('X', 2, 2) >>> density(G)(X) exp(-2*Trace(X**2))/Integral(exp(-2*Trace(_H**2)), _H) """ sym, dim = _symbol_converter(sym), _sympify(dim) model = GaussianSymplecticEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) class CircularEnsembleModel(RandomMatrixEnsembleModel): """ Abstract class for Circular ensembles. Contains the properties and methods common to all the circular ensembles. References ========== .. [1] https://en.wikipedia.org/wiki/Circular_ensemble """ def density(self, expr): # TODO : Add support for Lie groups(as extensions of sympy.diffgeom) # and define measures on them raise NotImplementedError("Support for Haar measure hasn't been " "implemented yet, therefore the density of " "%s cannot be computed."%(self)) def _compute_joint_eigen_distribution(self, beta): """ Helper function to compute the joint distribution of phases of the complex eigen values of matrices belonging to any circular ensembles. """ n = self.dimension Zbn = ((2*pi)**n)*(gamma(beta*n/2 + 1)/S(gamma(beta/2 + 1))**n) t = IndexedBase('t') i, j, k = (Dummy('i', integer=True), Dummy('j', integer=True), Dummy('k', integer=True)) syms = ArrayComprehension(t[i], (i, 1, n)).doit() f = Product(Product(Abs(exp(I*t[k]) - exp(I*t[j]))**beta, (j, k + 1, n)).doit(), (k, 1, n - 1)).doit() return Lambda(tuple(syms), f/Zbn) class CircularUnitaryEnsembleModel(CircularEnsembleModel): def joint_eigen_distribution(self): return self._compute_joint_eigen_distribution(S(2)) class CircularOrthogonalEnsembleModel(CircularEnsembleModel): def joint_eigen_distribution(self): return self._compute_joint_eigen_distribution(S.One) class CircularSymplecticEnsembleModel(CircularEnsembleModel): def joint_eigen_distribution(self): return self._compute_joint_eigen_distribution(S(4)) def CircularEnsemble(sym, dim): sym, dim = _symbol_converter(sym), _sympify(dim) model = CircularEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) def CircularUnitaryEnsemble(sym, dim): """ Represents Cicular Unitary Ensembles. Examples ======== >>> from sympy.stats import CircularUnitaryEnsemble as CUE >>> from sympy.stats import joint_eigen_distribution >>> C = CUE('U', 1) >>> joint_eigen_distribution(C) Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k]))**2, (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) Note ==== As can be seen above in the example, density of CiruclarUnitaryEnsemble is not evaluated becuase the exact definition is based on haar measure of unitary group which is not unique. """ sym, dim = _symbol_converter(sym), _sympify(dim) model = CircularUnitaryEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) def CircularOrthogonalEnsemble(sym, dim): """ Represents Cicular Orthogonal Ensembles. Examples ======== >>> from sympy.stats import CircularOrthogonalEnsemble as COE >>> from sympy.stats import joint_eigen_distribution >>> C = COE('O', 1) >>> joint_eigen_distribution(C) Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k])), (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) Note ==== As can be seen above in the example, density of CiruclarOrthogonalEnsemble is not evaluated becuase the exact definition is based on haar measure of unitary group which is not unique. """ sym, dim = _symbol_converter(sym), _sympify(dim) model = CircularOrthogonalEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) def CircularSymplecticEnsemble(sym, dim): """ Represents Cicular Symplectic Ensembles. Examples ======== >>> from sympy.stats import CircularSymplecticEnsemble as CSE >>> from sympy.stats import joint_eigen_distribution >>> C = CSE('S', 1) >>> joint_eigen_distribution(C) Lambda(t[1], Product(Abs(exp(I*t[_j]) - exp(I*t[_k]))**4, (_j, _k + 1, 1), (_k, 1, 0))/(2*pi)) Note ==== As can be seen above in the example, density of CiruclarSymplecticEnsemble is not evaluated becuase the exact definition is based on haar measure of unitary group which is not unique. """ sym, dim = _symbol_converter(sym), _sympify(dim) model = CircularSymplecticEnsembleModel(sym, dim) rmp = RandomMatrixPSpace(sym, model=model) return RandomMatrixSymbol(sym, dim, dim, pspace=rmp) def joint_eigen_distribution(mat): """ For obtaining joint probability distribution of eigen values of random matrix. Parameters ========== mat: RandomMatrixSymbol The matrix symbol whose eigen values are to be considered. Returns ======= Lambda Examples ======== >>> from sympy.stats import GaussianUnitaryEnsemble as GUE >>> from sympy.stats import joint_eigen_distribution >>> U = GUE('U', 2) >>> joint_eigen_distribution(U) Lambda((l[1], l[2]), exp(-l[1]**2 - l[2]**2)*Product(Abs(l[_i] - l[_j])**2, (_j, _i + 1, 2), (_i, 1, 1))/pi) """ if not isinstance(mat, RandomMatrixSymbol): raise ValueError("%s is not of type, RandomMatrixSymbol."%(mat)) return mat.pspace.model.joint_eigen_distribution() def JointEigenDistribution(mat): """ Creates joint distribution of eigen values of matrices with random expressions. Parameters ========== mat: Matrix The matrix under consideration. Returns ======= JointDistributionHandmade Examples ======== >>> from sympy.stats import Normal, JointEigenDistribution >>> from sympy import Matrix >>> A = [[Normal('A00', 0, 1), Normal('A01', 0, 1)], ... [Normal('A10', 0, 1), Normal('A11', 0, 1)]] >>> JointEigenDistribution(Matrix(A)) JointDistributionHandmade(-sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 + A00/2 + A11/2, sqrt(A00**2 - 2*A00*A11 + 4*A01*A10 + A11**2)/2 + A00/2 + A11/2) """ eigenvals = mat.eigenvals(multiple=True) if any(not is_random(eigenval) for eigenval in set(eigenvals)): raise ValueError("Eigen values don't have any random expression, " "joint distribution cannot be generated.") return JointDistributionHandmade(*eigenvals) def level_spacing_distribution(mat): """ For obtaining distribution of level spacings. Parameters ========== mat: RandomMatrixSymbol The random matrix symbol whose eigen values are to be considered for finding the level spacings. Returns ======= Lambda Examples ======== >>> from sympy.stats import GaussianUnitaryEnsemble as GUE >>> from sympy.stats import level_spacing_distribution >>> U = GUE('U', 2) >>> level_spacing_distribution(U) Lambda(_s, 32*_s**2*exp(-4*_s**2/pi)/pi**2) References ========== .. [1] https://en.wikipedia.org/wiki/Random_matrix#Distribution_of_level_spacings """ return mat.pspace.model.level_spacing_distribution() sympy-sympy-1.9/sympy/stats/rv.py000066400000000000000000001506661412543434000172610ustar00rootroot00000000000000""" Main Random Variables Module Defines abstract random variable type. Contains interfaces for probability space object (PSpace) as well as standard operators, P, E, sample, density, where, quantile See Also ======== sympy.stats.crv sympy.stats.frv sympy.stats.rv_interface """ from functools import singledispatch from typing import Tuple as tTuple from sympy import (Basic, S, Expr, Symbol, Tuple, And, Add, Eq, lambdify, Or, Equality, Lambda, sympify, Dummy, Ne, KroneckerDelta, DiracDelta, Mul, Indexed, MatrixSymbol, Function, prod) from sympy.core.relational import Relational from sympy.core.sympify import _sympify from sympy.sets.sets import FiniteSet, ProductSet, Intersection from sympy.solvers.solveset import solveset from sympy.external import import_module from sympy.utilities.misc import filldedent from sympy.utilities.decorator import doctest_depends_on from sympy.utilities.exceptions import SymPyDeprecationWarning import warnings x = Symbol('x') @singledispatch def is_random(x): return False @is_random.register(Basic) def _(x): atoms = x.free_symbols return any([is_random(i) for i in atoms]) class RandomDomain(Basic): """ Represents a set of variables and the values which they can take. See Also ======== sympy.stats.crv.ContinuousDomain sympy.stats.frv.FiniteDomain """ is_ProductDomain = False is_Finite = False is_Continuous = False is_Discrete = False def __new__(cls, symbols, *args): symbols = FiniteSet(*symbols) return Basic.__new__(cls, symbols, *args) @property def symbols(self): return self.args[0] @property def set(self): return self.args[1] def __contains__(self, other): raise NotImplementedError() def compute_expectation(self, expr): raise NotImplementedError() class SingleDomain(RandomDomain): """ A single variable and its domain. See Also ======== sympy.stats.crv.SingleContinuousDomain sympy.stats.frv.SingleFiniteDomain """ def __new__(cls, symbol, set): assert symbol.is_Symbol return Basic.__new__(cls, symbol, set) @property def symbol(self): return self.args[0] @property def symbols(self): return FiniteSet(self.symbol) def __contains__(self, other): if len(other) != 1: return False sym, val = tuple(other)[0] return self.symbol == sym and val in self.set class MatrixDomain(RandomDomain): """ A Random Matrix variable and its domain. """ def __new__(cls, symbol, set): symbol, set = _symbol_converter(symbol), _sympify(set) return Basic.__new__(cls, symbol, set) @property def symbol(self): return self.args[0] @property def symbols(self): return FiniteSet(self.symbol) class ConditionalDomain(RandomDomain): """ A RandomDomain with an attached condition. See Also ======== sympy.stats.crv.ConditionalContinuousDomain sympy.stats.frv.ConditionalFiniteDomain """ def __new__(cls, fulldomain, condition): condition = condition.xreplace({rs: rs.symbol for rs in random_symbols(condition)}) return Basic.__new__(cls, fulldomain, condition) @property def symbols(self): return self.fulldomain.symbols @property def fulldomain(self): return self.args[0] @property def condition(self): return self.args[1] @property def set(self): raise NotImplementedError("Set of Conditional Domain not Implemented") def as_boolean(self): return And(self.fulldomain.as_boolean(), self.condition) class PSpace(Basic): """ A Probability Space. Explanation =========== Probability Spaces encode processes that equal different values probabilistically. These underly Random Symbols which occur in SymPy expressions and contain the mechanics to evaluate statistical statements. See Also ======== sympy.stats.crv.ContinuousPSpace sympy.stats.frv.FinitePSpace """ is_Finite = None # type: bool is_Continuous = None # type: bool is_Discrete = None # type: bool is_real = None # type: bool @property def domain(self): return self.args[0] @property def density(self): return self.args[1] @property def values(self): return frozenset(RandomSymbol(sym, self) for sym in self.symbols) @property def symbols(self): return self.domain.symbols def where(self, condition): raise NotImplementedError() def compute_density(self, expr): raise NotImplementedError() def sample(self, size=(), library='scipy', seed=None): raise NotImplementedError() def probability(self, condition): raise NotImplementedError() def compute_expectation(self, expr): raise NotImplementedError() class SinglePSpace(PSpace): """ Represents the probabilities of a set of random events that can be attributed to a single variable/symbol. """ def __new__(cls, s, distribution): s = _symbol_converter(s) return Basic.__new__(cls, s, distribution) @property def value(self): return RandomSymbol(self.symbol, self) @property def symbol(self): return self.args[0] @property def distribution(self): return self.args[1] @property def pdf(self): return self.distribution.pdf(self.symbol) class RandomSymbol(Expr): """ Random Symbols represent ProbabilitySpaces in SymPy Expressions. In principle they can take on any value that their symbol can take on within the associated PSpace with probability determined by the PSpace Density. Explanation =========== Random Symbols contain pspace and symbol properties. The pspace property points to the represented Probability Space The symbol is a standard SymPy Symbol that is used in that probability space for example in defining a density. You can form normal SymPy expressions using RandomSymbols and operate on those expressions with the Functions E - Expectation of a random expression P - Probability of a condition density - Probability Density of an expression given - A new random expression (with new random symbols) given a condition An object of the RandomSymbol type should almost never be created by the user. They tend to be created instead by the PSpace class's value method. Traditionally a user doesn't even do this but instead calls one of the convenience functions Normal, Exponential, Coin, Die, FiniteRV, etc.... """ def __new__(cls, symbol, pspace=None): from sympy.stats.joint_rv import JointRandomSymbol if pspace is None: # Allow single arg, representing pspace == PSpace() pspace = PSpace() symbol = _symbol_converter(symbol) if not isinstance(pspace, PSpace): raise TypeError("pspace variable should be of type PSpace") if cls == JointRandomSymbol and isinstance(pspace, SinglePSpace): cls = RandomSymbol return Basic.__new__(cls, symbol, pspace) is_finite = True is_symbol = True is_Atom = True _diff_wrt = True pspace = property(lambda self: self.args[1]) symbol = property(lambda self: self.args[0]) name = property(lambda self: self.symbol.name) def _eval_is_positive(self): return self.symbol.is_positive def _eval_is_integer(self): return self.symbol.is_integer def _eval_is_real(self): return self.symbol.is_real or self.pspace.is_real @property def is_commutative(self): return self.symbol.is_commutative @property def free_symbols(self): return {self} class RandomIndexedSymbol(RandomSymbol): def __new__(cls, idx_obj, pspace=None): if pspace is None: # Allow single arg, representing pspace == PSpace() pspace = PSpace() if not isinstance(idx_obj, (Indexed, Function)): raise TypeError("An Function or Indexed object is expected not %s"%(idx_obj)) return Basic.__new__(cls, idx_obj, pspace) symbol = property(lambda self: self.args[0]) name = property(lambda self: str(self.args[0])) @property def key(self): if isinstance(self.symbol, Indexed): return self.symbol.args[1] elif isinstance(self.symbol, Function): return self.symbol.args[0] @property def free_symbols(self): if self.key.free_symbols: free_syms = self.key.free_symbols free_syms.add(self) return free_syms return {self} @property def pspace(self): return self.args[1] class RandomMatrixSymbol(RandomSymbol, MatrixSymbol): # type: ignore def __new__(cls, symbol, n, m, pspace=None): n, m = _sympify(n), _sympify(m) symbol = _symbol_converter(symbol) if pspace is None: # Allow single arg, representing pspace == PSpace() pspace = PSpace() return Basic.__new__(cls, symbol, n, m, pspace) symbol = property(lambda self: self.args[0]) pspace = property(lambda self: self.args[3]) class ProductPSpace(PSpace): """ Abstract class for representing probability spaces with multiple random variables. See Also ======== sympy.stats.rv.IndependentProductPSpace sympy.stats.joint_rv.JointPSpace """ pass class IndependentProductPSpace(ProductPSpace): """ A probability space resulting from the merger of two independent probability spaces. Often created using the function, pspace. """ def __new__(cls, *spaces): rs_space_dict = {} for space in spaces: for value in space.values: rs_space_dict[value] = space symbols = FiniteSet(*[val.symbol for val in rs_space_dict.keys()]) # Overlapping symbols from sympy.stats.joint_rv import MarginalDistribution from sympy.stats.compound_rv import CompoundDistribution if len(symbols) < sum(len(space.symbols) for space in spaces if not isinstance(space.distribution, ( CompoundDistribution, MarginalDistribution))): raise ValueError("Overlapping Random Variables") if all(space.is_Finite for space in spaces): from sympy.stats.frv import ProductFinitePSpace cls = ProductFinitePSpace obj = Basic.__new__(cls, *FiniteSet(*spaces)) return obj @property def pdf(self): p = Mul(*[space.pdf for space in self.spaces]) return p.subs({rv: rv.symbol for rv in self.values}) @property def rs_space_dict(self): d = {} for space in self.spaces: for value in space.values: d[value] = space return d @property def symbols(self): return FiniteSet(*[val.symbol for val in self.rs_space_dict.keys()]) @property def spaces(self): return FiniteSet(*self.args) @property def values(self): return sumsets(space.values for space in self.spaces) def compute_expectation(self, expr, rvs=None, evaluate=False, **kwargs): rvs = rvs or self.values rvs = frozenset(rvs) for space in self.spaces: expr = space.compute_expectation(expr, rvs & space.values, evaluate=False, **kwargs) if evaluate and hasattr(expr, 'doit'): return expr.doit(**kwargs) return expr @property def domain(self): return ProductDomain(*[space.domain for space in self.spaces]) @property def density(self): raise NotImplementedError("Density not available for ProductSpaces") def sample(self, size=(), library='scipy', seed=None): return {k: v for space in self.spaces for k, v in space.sample(size=size, library=library, seed=seed).items()} def probability(self, condition, **kwargs): cond_inv = False if isinstance(condition, Ne): condition = Eq(condition.args[0], condition.args[1]) cond_inv = True elif isinstance(condition, And): # they are independent return Mul(*[self.probability(arg) for arg in condition.args]) elif isinstance(condition, Or): # they are independent return Add(*[self.probability(arg) for arg in condition.args]) expr = condition.lhs - condition.rhs rvs = random_symbols(expr) dens = self.compute_density(expr) if any([pspace(rv).is_Continuous for rv in rvs]): from sympy.stats.crv import SingleContinuousPSpace from sympy.stats.crv_types import ContinuousDistributionHandmade if expr in self.values: # Marginalize all other random symbols out of the density randomsymbols = tuple(set(self.values) - frozenset([expr])) symbols = tuple(rs.symbol for rs in randomsymbols) pdf = self.domain.integrate(self.pdf, symbols, **kwargs) return Lambda(expr.symbol, pdf) dens = ContinuousDistributionHandmade(dens) z = Dummy('z', real=True) space = SingleContinuousPSpace(z, dens) result = space.probability(condition.__class__(space.value, 0)) else: from sympy.stats.drv import SingleDiscretePSpace from sympy.stats.drv_types import DiscreteDistributionHandmade dens = DiscreteDistributionHandmade(dens) z = Dummy('z', integer=True) space = SingleDiscretePSpace(z, dens) result = space.probability(condition.__class__(space.value, 0)) return result if not cond_inv else S.One - result def compute_density(self, expr, **kwargs): rvs = random_symbols(expr) if any(pspace(rv).is_Continuous for rv in rvs): z = Dummy('z', real=True) expr = self.compute_expectation(DiracDelta(expr - z), **kwargs) else: z = Dummy('z', integer=True) expr = self.compute_expectation(KroneckerDelta(expr, z), **kwargs) return Lambda(z, expr) def compute_cdf(self, expr, **kwargs): raise ValueError("CDF not well defined on multivariate expressions") def conditional_space(self, condition, normalize=True, **kwargs): rvs = random_symbols(condition) condition = condition.xreplace({rv: rv.symbol for rv in self.values}) if any([pspace(rv).is_Continuous for rv in rvs]): from sympy.stats.crv import (ConditionalContinuousDomain, ContinuousPSpace) space = ContinuousPSpace domain = ConditionalContinuousDomain(self.domain, condition) elif any([pspace(rv).is_Discrete for rv in rvs]): from sympy.stats.drv import (ConditionalDiscreteDomain, DiscretePSpace) space = DiscretePSpace domain = ConditionalDiscreteDomain(self.domain, condition) elif all([pspace(rv).is_Finite for rv in rvs]): from sympy.stats.frv import FinitePSpace return FinitePSpace.conditional_space(self, condition) if normalize: replacement = {rv: Dummy(str(rv)) for rv in self.symbols} norm = domain.compute_expectation(self.pdf, **kwargs) pdf = self.pdf / norm.xreplace(replacement) # XXX: Converting symbols from set to tuple. The order matters to # Lambda though so we shouldn't be starting with a set here... density = Lambda(tuple(domain.symbols), pdf) return space(domain, density) class ProductDomain(RandomDomain): """ A domain resulting from the merger of two independent domains. See Also ======== sympy.stats.crv.ProductContinuousDomain sympy.stats.frv.ProductFiniteDomain """ is_ProductDomain = True def __new__(cls, *domains): # Flatten any product of products domains2 = [] for domain in domains: if not domain.is_ProductDomain: domains2.append(domain) else: domains2.extend(domain.domains) domains2 = FiniteSet(*domains2) if all(domain.is_Finite for domain in domains2): from sympy.stats.frv import ProductFiniteDomain cls = ProductFiniteDomain if all(domain.is_Continuous for domain in domains2): from sympy.stats.crv import ProductContinuousDomain cls = ProductContinuousDomain if all(domain.is_Discrete for domain in domains2): from sympy.stats.drv import ProductDiscreteDomain cls = ProductDiscreteDomain return Basic.__new__(cls, *domains2) @property def sym_domain_dict(self): return {symbol: domain for domain in self.domains for symbol in domain.symbols} @property def symbols(self): return FiniteSet(*[sym for domain in self.domains for sym in domain.symbols]) @property def domains(self): return self.args @property def set(self): return ProductSet(*(domain.set for domain in self.domains)) def __contains__(self, other): # Split event into each subdomain for domain in self.domains: # Collect the parts of this event which associate to this domain elem = frozenset([item for item in other if sympify(domain.symbols.contains(item[0])) is S.true]) # Test this sub-event if elem not in domain: return False # All subevents passed return True def as_boolean(self): return And(*[domain.as_boolean() for domain in self.domains]) def random_symbols(expr): """ Returns all RandomSymbols within a SymPy Expression. """ atoms = getattr(expr, 'atoms', None) if atoms is not None: comp = lambda rv: rv.symbol.name l = list(atoms(RandomSymbol)) return sorted(l, key=comp) else: return [] def pspace(expr): """ Returns the underlying Probability Space of a random expression. For internal use. Examples ======== >>> from sympy.stats import pspace, Normal >>> X = Normal('X', 0, 1) >>> pspace(2*X + 1) == X.pspace True """ expr = sympify(expr) if isinstance(expr, RandomSymbol) and expr.pspace is not None: return expr.pspace if expr.has(RandomMatrixSymbol): rm = list(expr.atoms(RandomMatrixSymbol))[0] return rm.pspace rvs = random_symbols(expr) if not rvs: raise ValueError("Expression containing Random Variable expected, not %s" % (expr)) # If only one space present if all(rv.pspace == rvs[0].pspace for rv in rvs): return rvs[0].pspace from sympy.stats.compound_rv import CompoundPSpace from sympy.stats.stochastic_process import StochasticPSpace for rv in rvs: if isinstance(rv.pspace, (CompoundPSpace, StochasticPSpace)): return rv.pspace # Otherwise make a product space return IndependentProductPSpace(*[rv.pspace for rv in rvs]) def sumsets(sets): """ Union of sets """ return frozenset().union(*sets) def rs_swap(a, b): """ Build a dictionary to swap RandomSymbols based on their underlying symbol. i.e. if ``X = ('x', pspace1)`` and ``Y = ('x', pspace2)`` then ``X`` and ``Y`` match and the key, value pair ``{X:Y}`` will appear in the result Inputs: collections a and b of random variables which share common symbols Output: dict mapping RVs in a to RVs in b """ d = {} for rsa in a: d[rsa] = [rsb for rsb in b if rsa.symbol == rsb.symbol][0] return d def given(expr, condition=None, **kwargs): r""" Conditional Random Expression. Explanation =========== From a random expression and a condition on that expression creates a new probability space from the condition and returns the same expression on that conditional probability space. Examples ======== >>> from sympy.stats import given, density, Die >>> X = Die('X', 6) >>> Y = given(X, X > 3) >>> density(Y).dict {4: 1/3, 5: 1/3, 6: 1/3} Following convention, if the condition is a random symbol then that symbol is considered fixed. >>> from sympy.stats import Normal >>> from sympy import pprint >>> from sympy.abc import z >>> X = Normal('X', 0, 1) >>> Y = Normal('Y', 0, 1) >>> pprint(density(X + Y, Y)(z), use_unicode=False) 2 -(-Y + z) ----------- ___ 2 \/ 2 *e ------------------ ____ 2*\/ pi """ if not is_random(condition) or pspace_independent(expr, condition): return expr if isinstance(condition, RandomSymbol): condition = Eq(condition, condition.symbol) condsymbols = random_symbols(condition) if (isinstance(condition, Equality) and len(condsymbols) == 1 and not isinstance(pspace(expr).domain, ConditionalDomain)): rv = tuple(condsymbols)[0] results = solveset(condition, rv) if isinstance(results, Intersection) and S.Reals in results.args: results = list(results.args[1]) sums = 0 for res in results: temp = expr.subs(rv, res) if temp == True: return True if temp != False: # XXX: This seems nonsensical but preserves existing behaviour # after the change that Relational is no longer a subclass of # Expr. Here expr is sometimes Relational and sometimes Expr # but we are trying to add them with +=. This needs to be # fixed somehow. if sums == 0 and isinstance(expr, Relational): sums = expr.subs(rv, res) else: sums += expr.subs(rv, res) if sums == 0: return False return sums # Get full probability space of both the expression and the condition fullspace = pspace(Tuple(expr, condition)) # Build new space given the condition space = fullspace.conditional_space(condition, **kwargs) # Dictionary to swap out RandomSymbols in expr with new RandomSymbols # That point to the new conditional space swapdict = rs_swap(fullspace.values, space.values) # Swap random variables in the expression expr = expr.xreplace(swapdict) return expr def expectation(expr, condition=None, numsamples=None, evaluate=True, **kwargs): """ Returns the expected value of a random expression. Parameters ========== expr : Expr containing RandomSymbols The expression of which you want to compute the expectation value given : Expr containing RandomSymbols A conditional expression. E(X, X>0) is expectation of X given X > 0 numsamples : int Enables sampling and approximates the expectation with this many samples evalf : Bool (defaults to True) If sampling return a number rather than a complex expression evaluate : Bool (defaults to True) In case of continuous systems return unevaluated integral Examples ======== >>> from sympy.stats import E, Die >>> X = Die('X', 6) >>> E(X) 7/2 >>> E(2*X + 1) 8 >>> E(X, X > 3) # Expectation of X given that it is above 3 5 """ if not is_random(expr): # expr isn't random? return expr kwargs['numsamples'] = numsamples from sympy.stats.symbolic_probability import Expectation if evaluate: return Expectation(expr, condition).doit(**kwargs) return Expectation(expr, condition) def probability(condition, given_condition=None, numsamples=None, evaluate=True, **kwargs): """ Probability that a condition is true, optionally given a second condition. Parameters ========== condition : Combination of Relationals containing RandomSymbols The condition of which you want to compute the probability given_condition : Combination of Relationals containing RandomSymbols A conditional expression. P(X > 1, X > 0) is expectation of X > 1 given X > 0 numsamples : int Enables sampling and approximates the probability with this many samples evaluate : Bool (defaults to True) In case of continuous systems return unevaluated integral Examples ======== >>> from sympy.stats import P, Die >>> from sympy import Eq >>> X, Y = Die('X', 6), Die('Y', 6) >>> P(X > 3) 1/2 >>> P(Eq(X, 5), X > 2) # Probability that X == 5 given that X > 2 1/4 >>> P(X > Y) 5/12 """ kwargs['numsamples'] = numsamples from sympy.stats.symbolic_probability import Probability if evaluate: return Probability(condition, given_condition).doit(**kwargs) ### TODO: Remove the user warnings in the future releases message = ("Since version 1.7, using `evaluate=False` returns `Probability` " "object. If you want unevaluated Integral/Sum use " "`P(condition, given_condition, evaluate=False).rewrite(Integral)`") warnings.warn(filldedent(message)) return Probability(condition, given_condition) class Density(Basic): expr = property(lambda self: self.args[0]) @property def condition(self): if len(self.args) > 1: return self.args[1] else: return None def doit(self, evaluate=True, **kwargs): from sympy.stats.random_matrix import RandomMatrixPSpace from sympy.stats.joint_rv import JointPSpace from sympy.stats.matrix_distributions import MatrixPSpace from sympy.stats.compound_rv import CompoundPSpace from sympy.stats.frv import SingleFiniteDistribution expr, condition = self.expr, self.condition if isinstance(expr, SingleFiniteDistribution): return expr.dict if condition is not None: # Recompute on new conditional expr expr = given(expr, condition, **kwargs) if not random_symbols(expr): return Lambda(x, DiracDelta(x - expr)) if isinstance(expr, RandomSymbol): if isinstance(expr.pspace, (SinglePSpace, JointPSpace, MatrixPSpace)) and \ hasattr(expr.pspace, 'distribution'): return expr.pspace.distribution elif isinstance(expr.pspace, RandomMatrixPSpace): return expr.pspace.model if isinstance(pspace(expr), CompoundPSpace): kwargs['compound_evaluate'] = evaluate result = pspace(expr).compute_density(expr, **kwargs) if evaluate and hasattr(result, 'doit'): return result.doit() else: return result def density(expr, condition=None, evaluate=True, numsamples=None, **kwargs): """ Probability density of a random expression, optionally given a second condition. Explanation =========== This density will take on different forms for different types of probability spaces. Discrete variables produce Dicts. Continuous variables produce Lambdas. Parameters ========== expr : Expr containing RandomSymbols The expression of which you want to compute the density value condition : Relational containing RandomSymbols A conditional expression. density(X > 1, X > 0) is density of X > 1 given X > 0 numsamples : int Enables sampling and approximates the density with this many samples Examples ======== >>> from sympy.stats import density, Die, Normal >>> from sympy import Symbol >>> x = Symbol('x') >>> D = Die('D', 6) >>> X = Normal(x, 0, 1) >>> density(D).dict {1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6} >>> density(2*D).dict {2: 1/6, 4: 1/6, 6: 1/6, 8: 1/6, 10: 1/6, 12: 1/6} >>> density(X)(x) sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) """ if numsamples: return sampling_density(expr, condition, numsamples=numsamples, **kwargs) return Density(expr, condition).doit(evaluate=evaluate, **kwargs) def cdf(expr, condition=None, evaluate=True, **kwargs): """ Cumulative Distribution Function of a random expression. optionally given a second condition. Explanation =========== This density will take on different forms for different types of probability spaces. Discrete variables produce Dicts. Continuous variables produce Lambdas. Examples ======== >>> from sympy.stats import density, Die, Normal, cdf >>> D = Die('D', 6) >>> X = Normal('X', 0, 1) >>> density(D).dict {1: 1/6, 2: 1/6, 3: 1/6, 4: 1/6, 5: 1/6, 6: 1/6} >>> cdf(D) {1: 1/6, 2: 1/3, 3: 1/2, 4: 2/3, 5: 5/6, 6: 1} >>> cdf(3*D, D > 2) {9: 1/4, 12: 1/2, 15: 3/4, 18: 1} >>> cdf(X) Lambda(_z, erf(sqrt(2)*_z/2)/2 + 1/2) """ if condition is not None: # If there is a condition # Recompute on new conditional expr return cdf(given(expr, condition, **kwargs), **kwargs) # Otherwise pass work off to the ProbabilitySpace result = pspace(expr).compute_cdf(expr, **kwargs) if evaluate and hasattr(result, 'doit'): return result.doit() else: return result def characteristic_function(expr, condition=None, evaluate=True, **kwargs): """ Characteristic function of a random expression, optionally given a second condition. Returns a Lambda. Examples ======== >>> from sympy.stats import Normal, DiscreteUniform, Poisson, characteristic_function >>> X = Normal('X', 0, 1) >>> characteristic_function(X) Lambda(_t, exp(-_t**2/2)) >>> Y = DiscreteUniform('Y', [1, 2, 7]) >>> characteristic_function(Y) Lambda(_t, exp(7*_t*I)/3 + exp(2*_t*I)/3 + exp(_t*I)/3) >>> Z = Poisson('Z', 2) >>> characteristic_function(Z) Lambda(_t, exp(2*exp(_t*I) - 2)) """ if condition is not None: return characteristic_function(given(expr, condition, **kwargs), **kwargs) result = pspace(expr).compute_characteristic_function(expr, **kwargs) if evaluate and hasattr(result, 'doit'): return result.doit() else: return result def moment_generating_function(expr, condition=None, evaluate=True, **kwargs): if condition is not None: return moment_generating_function(given(expr, condition, **kwargs), **kwargs) result = pspace(expr).compute_moment_generating_function(expr, **kwargs) if evaluate and hasattr(result, 'doit'): return result.doit() else: return result def where(condition, given_condition=None, **kwargs): """ Returns the domain where a condition is True. Examples ======== >>> from sympy.stats import where, Die, Normal >>> from sympy import And >>> D1, D2 = Die('a', 6), Die('b', 6) >>> a, b = D1.symbol, D2.symbol >>> X = Normal('x', 0, 1) >>> where(X**2<1) Domain: (-1 < x) & (x < 1) >>> where(X**2<1).set Interval.open(-1, 1) >>> where(And(D1<=D2 , D2<3)) Domain: (Eq(a, 1) & Eq(b, 1)) | (Eq(a, 1) & Eq(b, 2)) | (Eq(a, 2) & Eq(b, 2)) """ if given_condition is not None: # If there is a condition # Recompute on new conditional expr return where(given(condition, given_condition, **kwargs), **kwargs) # Otherwise pass work off to the ProbabilitySpace return pspace(condition).where(condition, **kwargs) @doctest_depends_on(modules=('scipy',)) def sample(expr, condition=None, size=(), library='scipy', numsamples=1, seed=None, **kwargs): """ A realization of the random expression. Parameters ========== expr : Expression of random variables Expression from which sample is extracted condition : Expr containing RandomSymbols A conditional expression size : int, tuple Represents size of each sample in numsamples library : str - 'scipy' : Sample using scipy - 'numpy' : Sample using numpy - 'pymc3' : Sample using PyMC3 Choose any of the available options to sample from as string, by default is 'scipy' numsamples : int Number of samples, each with size as ``size``. The ``numsamples`` parameter is deprecated and is only provided for compatibility with v1.8. Use a list comprehension or an additional dimension in ``size`` instead. seed : An object to be used as seed by the given external library for sampling `expr`. Following is the list of possible types of object for the supported libraries, - 'scipy': int, numpy.random.RandomState, numpy.random.Generator - 'numpy': int, numpy.random.RandomState, numpy.random.Generator - 'pymc3': int Optional, by default None, in which case seed settings related to the given library will be used. No modifications to environment's global seed settings are done by this argument. Returns ======= sample: float/list/numpy.ndarray one sample or a collection of samples of the random expression. - sample(X) returns float/numpy.float64/numpy.int64 object. - sample(X, size=int/tuple) returns numpy.ndarray object. Examples ======== >>> from sympy.stats import Die, sample, Normal, Geometric >>> X, Y, Z = Die('X', 6), Die('Y', 6), Die('Z', 6) # Finite Random Variable >>> die_roll = sample(X + Y + Z) >>> die_roll # doctest: +SKIP 3 >>> N = Normal('N', 3, 4) # Continuous Random Variable >>> samp = sample(N) >>> samp in N.pspace.domain.set True >>> samp = sample(N, N>0) >>> samp > 0 True >>> samp_list = sample(N, size=4) >>> [sam in N.pspace.domain.set for sam in samp_list] [True, True, True, True] >>> sample(N, size = (2,3)) # doctest: +SKIP array([[5.42519758, 6.40207856, 4.94991743], [1.85819627, 6.83403519, 1.9412172 ]]) >>> G = Geometric('G', 0.5) # Discrete Random Variable >>> samp_list = sample(G, size=3) >>> samp_list # doctest: +SKIP [1, 3, 2] >>> [sam in G.pspace.domain.set for sam in samp_list] [True, True, True] >>> MN = Normal("MN", [3, 4], [[2, 1], [1, 2]]) # Joint Random Variable >>> samp_list = sample(MN, size=4) >>> samp_list # doctest: +SKIP [array([2.85768055, 3.38954165]), array([4.11163337, 4.3176591 ]), array([0.79115232, 1.63232916]), array([4.01747268, 3.96716083])] >>> [tuple(sam) in MN.pspace.domain.set for sam in samp_list] [True, True, True, True] .. versionchanged:: 1.7.0 sample used to return an iterator containing the samples instead of value. .. versionchanged:: 1.9.0 sample returns values or array of values instead of an iterator and numsamples is deprecated. """ iterator = sample_iter(expr, condition, size=size, library=library, numsamples=numsamples, seed=seed) if numsamples != 1: SymPyDeprecationWarning( feature="numsamples parameter", issue=21723, deprecated_since_version="1.9", useinstead="a list comprehension or an additional dimension in ``size``").warn() return [next(iterator) for i in range(numsamples)] return next(iterator) def quantile(expr, evaluate=True, **kwargs): r""" Return the :math:`p^{th}` order quantile of a probability distribution. Explanation =========== Quantile is defined as the value at which the probability of the random variable is less than or equal to the given probability. ..math:: Q(p) = inf{x \in (-\infty, \infty) such that p <= F(x)} Examples ======== >>> from sympy.stats import quantile, Die, Exponential >>> from sympy import Symbol, pprint >>> p = Symbol("p") >>> l = Symbol("lambda", positive=True) >>> X = Exponential("x", l) >>> quantile(X)(p) -log(1 - p)/lambda >>> D = Die("d", 6) >>> pprint(quantile(D)(p), use_unicode=False) /nan for Or(p > 1, p < 0) | | 1 for p <= 1/6 | | 2 for p <= 1/3 | < 3 for p <= 1/2 | | 4 for p <= 2/3 | | 5 for p <= 5/6 | \ 6 for p <= 1 """ result = pspace(expr).compute_quantile(expr, **kwargs) if evaluate and hasattr(result, 'doit'): return result.doit() else: return result def sample_iter(expr, condition=None, size=(), library='scipy', numsamples=S.Infinity, seed=None, **kwargs): """ Returns an iterator of realizations from the expression given a condition. Parameters ========== expr: Expr Random expression to be realized condition: Expr, optional A conditional expression size : int, tuple Represents size of each sample in numsamples numsamples: integer, optional Length of the iterator (defaults to infinity) seed : An object to be used as seed by the given external library for sampling `expr`. Following is the list of possible types of object for the supported libraries, - 'scipy': int, numpy.random.RandomState, numpy.random.Generator - 'numpy': int, numpy.random.RandomState, numpy.random.Generator - 'pymc3': int Optional, by default None, in which case seed settings related to the given library will be used. No modifications to environment's global seed settings are done by this argument. Examples ======== >>> from sympy.stats import Normal, sample_iter >>> X = Normal('X', 0, 1) >>> expr = X*X + 3 >>> iterator = sample_iter(expr, numsamples=3) # doctest: +SKIP >>> list(iterator) # doctest: +SKIP [12, 4, 7] Returns ======= sample_iter: iterator object iterator object containing the sample/samples of given expr See Also ======== sample sampling_P sampling_E """ from sympy.stats.joint_rv import JointRandomSymbol if not import_module(library): raise ValueError("Failed to import %s" % library) if condition is not None: ps = pspace(Tuple(expr, condition)) else: ps = pspace(expr) rvs = list(ps.values) if isinstance(expr, JointRandomSymbol): expr = expr.subs({expr: RandomSymbol(expr.symbol, expr.pspace)}) else: sub = {} for arg in expr.args: if isinstance(arg, JointRandomSymbol): sub[arg] = RandomSymbol(arg.symbol, arg.pspace) expr = expr.subs(sub) def fn_subs(*args): return expr.subs({rv: arg for rv, arg in zip(rvs, args)}) def given_fn_subs(*args): if condition is not None: return condition.subs({rv: arg for rv, arg in zip(rvs, args)}) return False if library == 'pymc3': # Currently unable to lambdify in pymc3 # TODO : Remove 'pymc3' when lambdify accepts 'pymc3' as module fn = lambdify(rvs, expr, **kwargs) else: fn = lambdify(rvs, expr, modules=library, **kwargs) if condition is not None: given_fn = lambdify(rvs, condition, **kwargs) def return_generator_infinite(): count = 0 _size = (1,)+((size,) if isinstance(size, int) else size) while count < numsamples: d = ps.sample(size=_size, library=library, seed=seed) # a dictionary that maps RVs to values args = [d[rv][0] for rv in rvs] if condition is not None: # Check that these values satisfy the condition # TODO: Replace the try-except block with only given_fn(*args) # once lambdify works with unevaluated SymPy objects. try: gd = given_fn(*args) except (NameError, TypeError): gd = given_fn_subs(*args) if gd != True and gd != False: raise ValueError( "Conditions must not contain free symbols") if not gd: # If the values don't satisfy then try again continue yield fn(*args) count += 1 def return_generator_finite(): faulty = True while faulty: d = ps.sample(size=(numsamples,) + ((size,) if isinstance(size, int) else size), library=library, seed=seed) # a dictionary that maps RVs to values faulty = False count = 0 while count < numsamples and not faulty: args = [d[rv][count] for rv in rvs] if condition is not None: # Check that these values satisfy the condition # TODO: Replace the try-except block with only given_fn(*args) # once lambdify works with unevaluated SymPy objects. try: gd = given_fn(*args) except (NameError, TypeError): gd = given_fn_subs(*args) if gd != True and gd != False: raise ValueError( "Conditions must not contain free symbols") if not gd: # If the values don't satisfy then try again faulty = True count += 1 count = 0 while count < numsamples: args = [d[rv][count] for rv in rvs] # TODO: Replace the try-except block with only fn(*args) # once lambdify works with unevaluated SymPy objects. try: yield fn(*args) except (NameError, TypeError): yield fn_subs(*args) count += 1 if numsamples is S.Infinity: return return_generator_infinite() return return_generator_finite() def sample_iter_lambdify(expr, condition=None, size=(), numsamples=S.Infinity, seed=None, **kwargs): return sample_iter(expr, condition=condition, size=size, numsamples=numsamples, seed=seed, **kwargs) def sample_iter_subs(expr, condition=None, size=(), numsamples=S.Infinity, seed=None, **kwargs): return sample_iter(expr, condition=condition, size=size, numsamples=numsamples, seed=seed, **kwargs) def sampling_P(condition, given_condition=None, library='scipy', numsamples=1, evalf=True, seed=None, **kwargs): """ Sampling version of P. See Also ======== P sampling_E sampling_density """ count_true = 0 count_false = 0 samples = sample_iter(condition, given_condition, library=library, numsamples=numsamples, seed=seed, **kwargs) for sample in samples: if sample: count_true += 1 else: count_false += 1 result = S(count_true) / numsamples if evalf: return result.evalf() else: return result def sampling_E(expr, given_condition=None, library='scipy', numsamples=1, evalf=True, seed=None, **kwargs): """ Sampling version of E. See Also ======== P sampling_P sampling_density """ samples = list(sample_iter(expr, given_condition, library=library, numsamples=numsamples, seed=seed, **kwargs)) result = Add(*[samp for samp in samples]) / numsamples if evalf: return result.evalf() else: return result def sampling_density(expr, given_condition=None, library='scipy', numsamples=1, seed=None, **kwargs): """ Sampling version of density. See Also ======== density sampling_P sampling_E """ results = {} for result in sample_iter(expr, given_condition, library=library, numsamples=numsamples, seed=seed, **kwargs): results[result] = results.get(result, 0) + 1 return results def dependent(a, b): """ Dependence of two random expressions. Two expressions are independent if knowledge of one does not change computations on the other. Examples ======== >>> from sympy.stats import Normal, dependent, given >>> from sympy import Tuple, Eq >>> X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) >>> dependent(X, Y) False >>> dependent(2*X + Y, -Y) True >>> X, Y = given(Tuple(X, Y), Eq(X + Y, 3)) >>> dependent(X, Y) True See Also ======== independent """ if pspace_independent(a, b): return False z = Symbol('z', real=True) # Dependent if density is unchanged when one is given information about # the other return (density(a, Eq(b, z)) != density(a) or density(b, Eq(a, z)) != density(b)) def independent(a, b): """ Independence of two random expressions. Two expressions are independent if knowledge of one does not change computations on the other. Examples ======== >>> from sympy.stats import Normal, independent, given >>> from sympy import Tuple, Eq >>> X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) >>> independent(X, Y) True >>> independent(2*X + Y, -Y) False >>> X, Y = given(Tuple(X, Y), Eq(X + Y, 3)) >>> independent(X, Y) False See Also ======== dependent """ return not dependent(a, b) def pspace_independent(a, b): """ Tests for independence between a and b by checking if their PSpaces have overlapping symbols. This is a sufficient but not necessary condition for independence and is intended to be used internally. Notes ===== pspace_independent(a, b) implies independent(a, b) independent(a, b) does not imply pspace_independent(a, b) """ a_symbols = set(pspace(b).symbols) b_symbols = set(pspace(a).symbols) if len(set(random_symbols(a)).intersection(random_symbols(b))) != 0: return False if len(a_symbols.intersection(b_symbols)) == 0: return True return None def rv_subs(expr, symbols=None): """ Given a random expression replace all random variables with their symbols. If symbols keyword is given restrict the swap to only the symbols listed. """ if symbols is None: symbols = random_symbols(expr) if not symbols: return expr swapdict = {rv: rv.symbol for rv in symbols} return expr.subs(swapdict) class NamedArgsMixin: _argnames = () # type: tTuple[str, ...] def __getattr__(self, attr): try: return self.args[self._argnames.index(attr)] except ValueError: raise AttributeError("'%s' object has no attribute '%s'" % ( type(self).__name__, attr)) class Distribution(Basic): def sample(self, size=(), library='scipy', seed=None): """ A random realization from the distribution """ module = import_module(library) if library in {'scipy', 'numpy', 'pymc3'} and module is None: raise ValueError("Failed to import %s" % library) if library == 'scipy': # scipy does not require map as it can handle using custom distributions. # However, we will still use a map where we can. # TODO: do this for drv.py and frv.py if necessary. # TODO: add more distributions here if there are more # See links below referring to sections beginning with "A common parametrization..." # I will remove all these comments if everything is ok. from sympy.stats.sampling.sample_scipy import do_sample_scipy import numpy if seed is None or isinstance(seed, int): rand_state = numpy.random.default_rng(seed=seed) else: rand_state = seed samps = do_sample_scipy(self, size, rand_state) elif library == 'numpy': from sympy.stats.sampling.sample_numpy import do_sample_numpy import numpy if seed is None or isinstance(seed, int): rand_state = numpy.random.default_rng(seed=seed) else: rand_state = seed _size = None if size == () else size samps = do_sample_numpy(self, _size, rand_state) elif library == 'pymc3': from sympy.stats.sampling.sample_pymc3 import do_sample_pymc3 import logging logging.getLogger("pymc3").setLevel(logging.ERROR) import pymc3 with pymc3.Model(): if do_sample_pymc3(self): samps = pymc3.sample(draws=prod(size), chains=1, compute_convergence_checks=False, progressbar=False, random_seed=seed, return_inferencedata=False)[:]['X'] samps = samps.reshape(size) else: samps = None else: raise NotImplementedError("Sampling from %s is not supported yet." % str(library)) if samps is not None: return samps raise NotImplementedError( "Sampling for %s is not currently implemented from %s" % (self, library)) def _value_check(condition, message): """ Raise a ValueError with message if condition is False, else return True if all conditions were True, else False. Examples ======== >>> from sympy.stats.rv import _value_check >>> from sympy.abc import a, b, c >>> from sympy import And, Dummy >>> _value_check(2 < 3, '') True Here, the condition is not False, but it doesn't evaluate to True so False is returned (but no error is raised). So checking if the return value is True or False will tell you if all conditions were evaluated. >>> _value_check(a < b, '') False In this case the condition is False so an error is raised: >>> r = Dummy(real=True) >>> _value_check(r < r - 1, 'condition is not true') Traceback (most recent call last): ... ValueError: condition is not true If no condition of many conditions must be False, they can be checked by passing them as an iterable: >>> _value_check((a < 0, b < 0, c < 0), '') False The iterable can be a generator, too: >>> _value_check((i < 0 for i in (a, b, c)), '') False The following are equivalent to the above but do not pass an iterable: >>> all(_value_check(i < 0, '') for i in (a, b, c)) False >>> _value_check(And(a < 0, b < 0, c < 0), '') False """ from sympy.core.compatibility import iterable from sympy.core.logic import fuzzy_and if not iterable(condition): condition = [condition] truth = fuzzy_and(condition) if truth == False: raise ValueError(message) return truth == True def _symbol_converter(sym): """ Casts the parameter to Symbol if it is 'str' otherwise no operation is performed on it. Parameters ========== sym The parameter to be converted. Returns ======= Symbol the parameter converted to Symbol. Raises ====== TypeError If the parameter is not an instance of both str and Symbol. Examples ======== >>> from sympy import Symbol >>> from sympy.stats.rv import _symbol_converter >>> s = _symbol_converter('s') >>> isinstance(s, Symbol) True >>> _symbol_converter(1) Traceback (most recent call last): ... TypeError: 1 is neither a Symbol nor a string >>> r = Symbol('r') >>> isinstance(r, Symbol) True """ if isinstance(sym, str): sym = Symbol(sym) if not isinstance(sym, Symbol): raise TypeError("%s is neither a Symbol nor a string"%(sym)) return sym def sample_stochastic_process(process): """ This function is used to sample from stochastic process. Parameters ========== process: StochasticProcess Process used to extract the samples. It must be an instance of StochasticProcess Examples ======== >>> from sympy.stats import sample_stochastic_process, DiscreteMarkovChain >>> from sympy import Matrix >>> T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) >>> next(sample_stochastic_process(Y)) in Y.state_space # doctest: +SKIP True >>> next(sample_stochastic_process(Y)) # doctest: +SKIP 0 >>> next(sample_stochastic_process(Y)) # doctest: +SKIP 2 Returns ======= sample: iterator object iterator object containing the sample of given process """ from sympy.stats.stochastic_process_types import StochasticProcess if not isinstance(process, StochasticProcess): raise ValueError("Process must be an instance of Stochastic Process") return process.sample() sympy-sympy-1.9/sympy/stats/rv_interface.py000066400000000000000000000325741412543434000212760ustar00rootroot00000000000000from sympy.sets import FiniteSet from sympy import (sqrt, log, exp, FallingFactorial, Rational, Eq, Dummy, piecewise_fold, solveset, Integral) from .rv import (probability, expectation, density, where, given, pspace, cdf, PSpace, characteristic_function, sample, sample_iter, random_symbols, independent, dependent, sampling_density, moment_generating_function, quantile, is_random, sample_stochastic_process) __all__ = ['P', 'E', 'H', 'density', 'where', 'given', 'sample', 'cdf', 'characteristic_function', 'pspace', 'sample_iter', 'variance', 'std', 'skewness', 'kurtosis', 'covariance', 'dependent', 'entropy', 'median', 'independent', 'random_symbols', 'correlation', 'factorial_moment', 'moment', 'cmoment', 'sampling_density', 'moment_generating_function', 'smoment', 'quantile', 'sample_stochastic_process'] def moment(X, n, c=0, condition=None, *, evaluate=True, **kwargs): """ Return the nth moment of a random expression about c. .. math:: moment(X, c, n) = E((X-c)^{n}) Default value of c is 0. Examples ======== >>> from sympy.stats import Die, moment, E >>> X = Die('X', 6) >>> moment(X, 1, 6) -5/2 >>> moment(X, 2) 91/6 >>> moment(X, 1) == E(X) True """ from sympy.stats.symbolic_probability import Moment if evaluate: return Moment(X, n, c, condition).doit() return Moment(X, n, c, condition).rewrite(Integral) def variance(X, condition=None, **kwargs): """ Variance of a random expression. .. math:: variance(X) = E((X-E(X))^{2}) Examples ======== >>> from sympy.stats import Die, Bernoulli, variance >>> from sympy import simplify, Symbol >>> X = Die('X', 6) >>> p = Symbol('p') >>> B = Bernoulli('B', p, 1, 0) >>> variance(2*X) 35/3 >>> simplify(variance(B)) p*(1 - p) """ if is_random(X) and pspace(X) == PSpace(): from sympy.stats.symbolic_probability import Variance return Variance(X, condition) return cmoment(X, 2, condition, **kwargs) def standard_deviation(X, condition=None, **kwargs): r""" Standard Deviation of a random expression .. math:: std(X) = \sqrt(E((X-E(X))^{2})) Examples ======== >>> from sympy.stats import Bernoulli, std >>> from sympy import Symbol, simplify >>> p = Symbol('p') >>> B = Bernoulli('B', p, 1, 0) >>> simplify(std(B)) sqrt(p*(1 - p)) """ return sqrt(variance(X, condition, **kwargs)) std = standard_deviation def entropy(expr, condition=None, **kwargs): """ Calculuates entropy of a probability distribution. Parameters ========== expression : the random expression whose entropy is to be calculated condition : optional, to specify conditions on random expression b: base of the logarithm, optional By default, it is taken as Euler's number Returns ======= result : Entropy of the expression, a constant Examples ======== >>> from sympy.stats import Normal, Die, entropy >>> X = Normal('X', 0, 1) >>> entropy(X) log(2)/2 + 1/2 + log(pi)/2 >>> D = Die('D', 4) >>> entropy(D) log(4) References ========== .. [1] https://en.wikipedia.org/wiki/Entropy_(information_theory) .. [2] https://www.crmarsh.com/static/pdf/Charles_Marsh_Continuous_Entropy.pdf .. [3] http://www.math.uconn.edu/~kconrad/blurbs/analysis/entropypost.pdf """ pdf = density(expr, condition, **kwargs) base = kwargs.get('b', exp(1)) if isinstance(pdf, dict): return sum([-prob*log(prob, base) for prob in pdf.values()]) return expectation(-log(pdf(expr), base)) def covariance(X, Y, condition=None, **kwargs): """ Covariance of two random expressions. Explanation =========== The expectation that the two variables will rise and fall together .. math:: covariance(X,Y) = E((X-E(X)) (Y-E(Y))) Examples ======== >>> from sympy.stats import Exponential, covariance >>> from sympy import Symbol >>> rate = Symbol('lambda', positive=True, real=True, finite=True) >>> X = Exponential('X', rate) >>> Y = Exponential('Y', rate) >>> covariance(X, X) lambda**(-2) >>> covariance(X, Y) 0 >>> covariance(X, Y + rate*X) 1/lambda """ if (is_random(X) and pspace(X) == PSpace()) or (is_random(Y) and pspace(Y) == PSpace()): from sympy.stats.symbolic_probability import Covariance return Covariance(X, Y, condition) return expectation( (X - expectation(X, condition, **kwargs)) * (Y - expectation(Y, condition, **kwargs)), condition, **kwargs) def correlation(X, Y, condition=None, **kwargs): r""" Correlation of two random expressions, also known as correlation coefficient or Pearson's correlation. Explanation =========== The normalized expectation that the two variables will rise and fall together .. math:: correlation(X,Y) = E((X-E(X))(Y-E(Y)) / (\sigma_x \sigma_y)) Examples ======== >>> from sympy.stats import Exponential, correlation >>> from sympy import Symbol >>> rate = Symbol('lambda', positive=True, real=True, finite=True) >>> X = Exponential('X', rate) >>> Y = Exponential('Y', rate) >>> correlation(X, X) 1 >>> correlation(X, Y) 0 >>> correlation(X, Y + rate*X) 1/sqrt(1 + lambda**(-2)) """ return covariance(X, Y, condition, **kwargs)/(std(X, condition, **kwargs) * std(Y, condition, **kwargs)) def cmoment(X, n, condition=None, *, evaluate=True, **kwargs): """ Return the nth central moment of a random expression about its mean. .. math:: cmoment(X, n) = E((X - E(X))^{n}) Examples ======== >>> from sympy.stats import Die, cmoment, variance >>> X = Die('X', 6) >>> cmoment(X, 3) 0 >>> cmoment(X, 2) 35/12 >>> cmoment(X, 2) == variance(X) True """ from sympy.stats.symbolic_probability import CentralMoment if evaluate: return CentralMoment(X, n, condition).doit() return CentralMoment(X, n, condition).rewrite(Integral) def smoment(X, n, condition=None, **kwargs): r""" Return the nth Standardized moment of a random expression. .. math:: smoment(X, n) = E(((X - \mu)/\sigma_X)^{n}) Examples ======== >>> from sympy.stats import skewness, Exponential, smoment >>> from sympy import Symbol >>> rate = Symbol('lambda', positive=True, real=True, finite=True) >>> Y = Exponential('Y', rate) >>> smoment(Y, 4) 9 >>> smoment(Y, 4) == smoment(3*Y, 4) True >>> smoment(Y, 3) == skewness(Y) True """ sigma = std(X, condition, **kwargs) return (1/sigma)**n*cmoment(X, n, condition, **kwargs) def skewness(X, condition=None, **kwargs): r""" Measure of the asymmetry of the probability distribution. Explanation =========== Positive skew indicates that most of the values lie to the right of the mean. .. math:: skewness(X) = E(((X - E(X))/\sigma_X)^{3}) Parameters ========== condition : Expr containing RandomSymbols A conditional expression. skewness(X, X>0) is skewness of X given X > 0 Examples ======== >>> from sympy.stats import skewness, Exponential, Normal >>> from sympy import Symbol >>> X = Normal('X', 0, 1) >>> skewness(X) 0 >>> skewness(X, X > 0) # find skewness given X > 0 (-sqrt(2)/sqrt(pi) + 4*sqrt(2)/pi**(3/2))/(1 - 2/pi)**(3/2) >>> rate = Symbol('lambda', positive=True, real=True, finite=True) >>> Y = Exponential('Y', rate) >>> skewness(Y) 2 """ return smoment(X, 3, condition=condition, **kwargs) def kurtosis(X, condition=None, **kwargs): r""" Characterizes the tails/outliers of a probability distribution. Explanation =========== Kurtosis of any univariate normal distribution is 3. Kurtosis less than 3 means that the distribution produces fewer and less extreme outliers than the normal distribution. .. math:: kurtosis(X) = E(((X - E(X))/\sigma_X)^{4}) Parameters ========== condition : Expr containing RandomSymbols A conditional expression. kurtosis(X, X>0) is kurtosis of X given X > 0 Examples ======== >>> from sympy.stats import kurtosis, Exponential, Normal >>> from sympy import Symbol >>> X = Normal('X', 0, 1) >>> kurtosis(X) 3 >>> kurtosis(X, X > 0) # find kurtosis given X > 0 (-4/pi - 12/pi**2 + 3)/(1 - 2/pi)**2 >>> rate = Symbol('lamda', positive=True, real=True, finite=True) >>> Y = Exponential('Y', rate) >>> kurtosis(Y) 9 References ========== .. [1] https://en.wikipedia.org/wiki/Kurtosis .. [2] http://mathworld.wolfram.com/Kurtosis.html """ return smoment(X, 4, condition=condition, **kwargs) def factorial_moment(X, n, condition=None, **kwargs): """ The factorial moment is a mathematical quantity defined as the expectation or average of the falling factorial of a random variable. .. math:: factorial-moment(X, n) = E(X(X - 1)(X - 2)...(X - n + 1)) Parameters ========== n: A natural number, n-th factorial moment. condition : Expr containing RandomSymbols A conditional expression. Examples ======== >>> from sympy.stats import factorial_moment, Poisson, Binomial >>> from sympy import Symbol, S >>> lamda = Symbol('lamda') >>> X = Poisson('X', lamda) >>> factorial_moment(X, 2) lamda**2 >>> Y = Binomial('Y', 2, S.Half) >>> factorial_moment(Y, 2) 1/2 >>> factorial_moment(Y, 2, Y > 1) # find factorial moment for Y > 1 2 References ========== .. [1] https://en.wikipedia.org/wiki/Factorial_moment .. [2] http://mathworld.wolfram.com/FactorialMoment.html """ return expectation(FallingFactorial(X, n), condition=condition, **kwargs) def median(X, evaluate=True, **kwargs): r""" Calculuates the median of the probability distribution. Explanation =========== Mathematically, median of Probability distribution is defined as all those values of `m` for which the following condition is satisfied .. math:: P(X\leq m) \geq \frac{1}{2} \text{ and} \text{ } P(X\geq m)\geq \frac{1}{2} Parameters ========== X: The random expression whose median is to be calculated. Returns ======= The FiniteSet or an Interval which contains the median of the random expression. Examples ======== >>> from sympy.stats import Normal, Die, median >>> N = Normal('N', 3, 1) >>> median(N) {3} >>> D = Die('D') >>> median(D) {3, 4} References ========== .. [1] https://en.wikipedia.org/wiki/Median#Probability_distributions """ if not is_random(X): return X from sympy.stats.crv import ContinuousPSpace from sympy.stats.drv import DiscretePSpace from sympy.stats.frv import FinitePSpace if isinstance(pspace(X), FinitePSpace): cdf = pspace(X).compute_cdf(X) result = [] for key, value in cdf.items(): if value>= Rational(1, 2) and (1 - value) + \ pspace(X).probability(Eq(X, key)) >= Rational(1, 2): result.append(key) return FiniteSet(*result) if isinstance(pspace(X), ContinuousPSpace) or isinstance(pspace(X), DiscretePSpace): cdf = pspace(X).compute_cdf(X) x = Dummy('x') result = solveset(piecewise_fold(cdf(x) - Rational(1, 2)), x, pspace(X).set) return result raise NotImplementedError("The median of %s is not implemeted."%str(pspace(X))) def coskewness(X, Y, Z, condition=None, **kwargs): r""" Calculates the co-skewness of three random variables. Explanation =========== Mathematically Coskewness is defined as .. math:: coskewness(X,Y,Z)=\frac{E[(X-E[X]) * (Y-E[Y]) * (Z-E[Z])]} {\sigma_{X}\sigma_{Y}\sigma_{Z}} Parameters ========== X : RandomSymbol Random Variable used to calculate coskewness Y : RandomSymbol Random Variable used to calculate coskewness Z : RandomSymbol Random Variable used to calculate coskewness condition : Expr containing RandomSymbols A conditional expression Examples ======== >>> from sympy.stats import coskewness, Exponential, skewness >>> from sympy import symbols >>> p = symbols('p', positive=True) >>> X = Exponential('X', p) >>> Y = Exponential('Y', 2*p) >>> coskewness(X, Y, Y) 0 >>> coskewness(X, Y + X, Y + 2*X) 16*sqrt(85)/85 >>> coskewness(X + 2*Y, Y + X, Y + 2*X, X > 3) 9*sqrt(170)/85 >>> coskewness(Y, Y, Y) == skewness(Y) True >>> coskewness(X, Y + p*X, Y + 2*p*X) 4/(sqrt(1 + 1/(4*p**2))*sqrt(4 + 1/(4*p**2))) Returns ======= coskewness : The coskewness of the three random variables References ========== .. [1] https://en.wikipedia.org/wiki/Coskewness """ num = expectation((X - expectation(X, condition, **kwargs)) \ * (Y - expectation(Y, condition, **kwargs)) \ * (Z - expectation(Z, condition, **kwargs)), condition, **kwargs) den = std(X, condition, **kwargs) * std(Y, condition, **kwargs) \ * std(Z, condition, **kwargs) return num/den P = probability E = expectation H = entropy sympy-sympy-1.9/sympy/stats/sampling/000077500000000000000000000000001412543434000200545ustar00rootroot00000000000000sympy-sympy-1.9/sympy/stats/sampling/__init__.py000066400000000000000000000000001412543434000221530ustar00rootroot00000000000000sympy-sympy-1.9/sympy/stats/sampling/sample_numpy.py000066400000000000000000000051311412543434000231370ustar00rootroot00000000000000from functools import singledispatch from sympy.external import import_module from sympy.stats.crv_types import BetaDistribution, ChiSquaredDistribution, ExponentialDistribution, GammaDistribution, \ LogNormalDistribution, NormalDistribution, ParetoDistribution, UniformDistribution from sympy.stats.drv_types import GeometricDistribution, PoissonDistribution, ZetaDistribution from sympy.stats.frv_types import BinomialDistribution numpy = import_module('numpy') @singledispatch def do_sample_numpy(dist, size, rand_state): return None # CRV: @do_sample_numpy.register(BetaDistribution) def _(dist: BetaDistribution, size, rand_state): return rand_state.beta(a=float(dist.alpha), b=float(dist.beta), size=size) @do_sample_numpy.register(ChiSquaredDistribution) def _(dist: ChiSquaredDistribution, size, rand_state): return rand_state.chisquare(df=float(dist.k), size=size) @do_sample_numpy.register(ExponentialDistribution) def _(dist: ExponentialDistribution, size, rand_state): return rand_state.exponential(1 / float(dist.rate), size=size) @do_sample_numpy.register(GammaDistribution) def _(dist: GammaDistribution, size, rand_state): return rand_state.gamma(float(dist.k), float(dist.theta), size=size) @do_sample_numpy.register(LogNormalDistribution) def _(dist: LogNormalDistribution, size, rand_state): return rand_state.lognormal(float(dist.mean), float(dist.std), size=size) @do_sample_numpy.register(NormalDistribution) def _(dist: NormalDistribution, size, rand_state): return rand_state.normal(float(dist.mean), float(dist.std), size=size) @do_sample_numpy.register(ParetoDistribution) def _(dist: ParetoDistribution, size, rand_state): return (numpy.random.pareto(a=float(dist.alpha), size=size) + 1) * float(dist.xm) @do_sample_numpy.register(UniformDistribution) def _(dist: UniformDistribution, size, rand_state): return rand_state.uniform(low=float(dist.left), high=float(dist.right), size=size) # DRV: @do_sample_numpy.register(GeometricDistribution) def _(dist: GeometricDistribution, size, rand_state): return rand_state.geometric(p=float(dist.p), size=size) @do_sample_numpy.register(PoissonDistribution) def _(dist: PoissonDistribution, size, rand_state): return rand_state.poisson(lam=float(dist.lamda), size=size) @do_sample_numpy.register(ZetaDistribution) def _(dist: ZetaDistribution, size, rand_state): return rand_state.zipf(a=float(dist.s), size=size) # FRV: @do_sample_numpy.register(BinomialDistribution) def _(dist: BinomialDistribution, size, rand_state): return rand_state.binomial(n=int(dist.n), p=float(dist.p), size=size) sympy-sympy-1.9/sympy/stats/sampling/sample_pymc3.py000066400000000000000000000056471412543434000230360ustar00rootroot00000000000000from functools import singledispatch from sympy.external import import_module from sympy.stats.crv_types import BetaDistribution, CauchyDistribution, ChiSquaredDistribution, ExponentialDistribution, \ GammaDistribution, LogNormalDistribution, NormalDistribution, ParetoDistribution, UniformDistribution, \ GaussianInverseDistribution from sympy.stats.drv_types import PoissonDistribution, GeometricDistribution, NegativeBinomialDistribution from sympy.stats.frv_types import BinomialDistribution, BernoulliDistribution pymc3 = import_module('pymc3') @singledispatch def do_sample_pymc3(dist): return None # CRV: @do_sample_pymc3.register(BetaDistribution) def _(dist: BetaDistribution): return pymc3.Beta('X', alpha=float(dist.alpha), beta=float(dist.beta)) @do_sample_pymc3.register(CauchyDistribution) def _(dist: CauchyDistribution): return pymc3.Cauchy('X', alpha=float(dist.x0), beta=float(dist.gamma)) @do_sample_pymc3.register(ChiSquaredDistribution) def _(dist: ChiSquaredDistribution): return pymc3.ChiSquared('X', nu=float(dist.k)) @do_sample_pymc3.register(ExponentialDistribution) def _(dist: ExponentialDistribution): return pymc3.Exponential('X', lam=float(dist.rate)) @do_sample_pymc3.register(GammaDistribution) def _(dist: GammaDistribution): return pymc3.Gamma('X', alpha=float(dist.k), beta=1 / float(dist.theta)) @do_sample_pymc3.register(LogNormalDistribution) def _(dist: LogNormalDistribution): return pymc3.Lognormal('X', mu=float(dist.mean), sigma=float(dist.std)) @do_sample_pymc3.register(NormalDistribution) def _(dist: NormalDistribution): return pymc3.Normal('X', float(dist.mean), float(dist.std)) @do_sample_pymc3.register(GaussianInverseDistribution) def _(dist: GaussianInverseDistribution): return pymc3.Wald('X', mu=float(dist.mean), lam=float(dist.shape)) @do_sample_pymc3.register(ParetoDistribution) def _(dist: ParetoDistribution): return pymc3.Pareto('X', alpha=float(dist.alpha), m=float(dist.xm)) @do_sample_pymc3.register(UniformDistribution) def _(dist: UniformDistribution): return pymc3.Uniform('X', lower=float(dist.left), upper=float(dist.right)) # DRV: @do_sample_pymc3.register(GeometricDistribution) def _(dist: GeometricDistribution): return pymc3.Geometric('X', p=float(dist.p)) @do_sample_pymc3.register(NegativeBinomialDistribution) def _(dist: NegativeBinomialDistribution): return pymc3.NegativeBinomial('X', mu=float((dist.p * dist.r) / (1 - dist.p)), alpha=float(dist.r)) @do_sample_pymc3.register(PoissonDistribution) def _(dist: PoissonDistribution): return pymc3.Poisson('X', mu=float(dist.lamda)) # FRV: @do_sample_pymc3.register(BernoulliDistribution) def _(dist: BernoulliDistribution): return pymc3.Bernoulli('X', p=float(dist.p)) @do_sample_pymc3.register(BinomialDistribution) def _(dist: BinomialDistribution): return pymc3.Binomial('X', n=int(dist.n), p=float(dist.p)) sympy-sympy-1.9/sympy/stats/sampling/sample_scipy.py000066400000000000000000000141751412543434000231260ustar00rootroot00000000000000from functools import singledispatch from sympy import Dummy, lambdify, exp from sympy.external import import_module from sympy.stats import DiscreteDistributionHandmade from sympy.stats.crv import SingleContinuousDistribution from sympy.stats.crv_types import ChiSquaredDistribution, ExponentialDistribution, GammaDistribution, \ LogNormalDistribution, NormalDistribution, ParetoDistribution, UniformDistribution, BetaDistribution, \ StudentTDistribution, CauchyDistribution from sympy.stats.drv_types import GeometricDistribution, LogarithmicDistribution, NegativeBinomialDistribution, \ PoissonDistribution, SkellamDistribution, YuleSimonDistribution, ZetaDistribution from sympy.stats.frv import SingleFiniteDistribution scipy = import_module("scipy") if scipy is not None: import scipy.stats @singledispatch def do_sample_scipy(dist, size, seed): return None # CRV @do_sample_scipy.register(SingleContinuousDistribution) def _(dist: SingleContinuousDistribution, size, seed): # if we don't need to make a handmade pdf, we won't import scipy.stats z = Dummy('z') handmade_pdf = lambdify(z, dist.pdf(z), ['numpy', 'scipy']) class scipy_pdf(scipy.stats.rv_continuous): def _pdf(dist, x): return handmade_pdf(x) scipy_rv = scipy_pdf(a=float(dist.set._inf), b=float(dist.set._sup), name='scipy_pdf') return scipy_rv.rvs(size=size, random_state=seed) @do_sample_scipy.register(ChiSquaredDistribution) def _(dist: ChiSquaredDistribution, size, seed): # same parametrisation return scipy.stats.chi2.rvs(df=float(dist.k), size=size, random_state=seed) @do_sample_scipy.register(ExponentialDistribution) def _(dist: ExponentialDistribution, size, seed): # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.expon.html#scipy.stats.expon return scipy.stats.expon.rvs(scale=1 / float(dist.rate), size=size, random_state=seed) @do_sample_scipy.register(GammaDistribution) def _(dist: GammaDistribution, size, seed): # https://stackoverflow.com/questions/42150965/how-to-plot-gamma-distribution-with-alpha-and-beta-parameters-in-python return scipy.stats.gamma.rvs(a=float(dist.k), scale=float(dist.theta), size=size, random_state=seed) @do_sample_scipy.register(LogNormalDistribution) def _(dist: LogNormalDistribution, size, seed): # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.lognorm.html return scipy.stats.lognorm.rvs(scale=float(exp(dist.mean)), s=float(dist.std), size=size, random_state=seed) @do_sample_scipy.register(NormalDistribution) def _(dist: NormalDistribution, size, seed): return scipy.stats.norm.rvs(loc=float(dist.mean), scale=float(dist.std), size=size, random_state=seed) @do_sample_scipy.register(ParetoDistribution) def _(dist: ParetoDistribution, size, seed): # https://stackoverflow.com/questions/42260519/defining-pareto-distribution-in-python-scipy return scipy.stats.pareto.rvs(b=float(dist.alpha), scale=float(dist.xm), size=size, random_state=seed) @do_sample_scipy.register(StudentTDistribution) def _(dist: StudentTDistribution, size, seed): return scipy.stats.t.rvs(df=float(dist.nu), size=size, random_state=seed) @do_sample_scipy.register(UniformDistribution) def _(dist: UniformDistribution, size, seed): # https://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.uniform.html return scipy.stats.uniform.rvs(loc=float(dist.left), scale=float(dist.right - dist.left), size=size, random_state=seed) @do_sample_scipy.register(BetaDistribution) def _(dist: BetaDistribution, size, seed): # same parametrisation return scipy.stats.beta.rvs(a=float(dist.alpha), b=float(dist.beta), size=size, random_state=seed) @do_sample_scipy.register(CauchyDistribution) def _(dist: CauchyDistribution, size, seed): return scipy.stats.cauchy.rvs(loc=float(dist.x0), scale=float(dist.gamma), size=size, random_state=seed) # DRV: @do_sample_scipy.register(DiscreteDistributionHandmade) def _(dist: DiscreteDistributionHandmade, size, seed): from scipy.stats import rv_discrete from sympy import lambdify z = Dummy('z') handmade_pmf = lambdify(z, dist.pdf(z), ['numpy', 'scipy']) class scipy_pmf(rv_discrete): def _pmf(dist, x): return handmade_pmf(x) scipy_rv = scipy_pmf(a=float(dist.set._inf), b=float(dist.set._sup), name='scipy_pmf') return scipy_rv.rvs(size=size, random_state=seed) @do_sample_scipy.register(GeometricDistribution) def _(dist: GeometricDistribution, size, seed): return scipy.stats.geom.rvs(p=float(dist.p), size=size, random_state=seed) @do_sample_scipy.register(LogarithmicDistribution) def _(dist: LogarithmicDistribution, size, seed): return scipy.stats.logser.rvs(p=float(dist.p), size=size, random_state=seed) @do_sample_scipy.register(NegativeBinomialDistribution) def _(dist: NegativeBinomialDistribution, size, seed): return scipy.stats.nbinom.rvs(n=float(dist.r), p=float(dist.p), size=size, random_state=seed) @do_sample_scipy.register(PoissonDistribution) def _(dist: PoissonDistribution, size, seed): return scipy.stats.poisson.rvs(mu=float(dist.lamda), size=size, random_state=seed) @do_sample_scipy.register(SkellamDistribution) def _(dist: SkellamDistribution, size, seed): return scipy.stats.skellam.rvs(mu1=float(dist.mu1), mu2=float(dist.mu2), size=size, random_state=seed) @do_sample_scipy.register(YuleSimonDistribution) def _(dist: YuleSimonDistribution, size, seed): return scipy.stats.yulesimon.rvs(alpha=float(dist.rho), size=size, random_state=seed) @do_sample_scipy.register(ZetaDistribution) def _(dist: ZetaDistribution, size, seed): return scipy.stats.zipf.rvs(a=float(dist.s), size=size, random_state=seed) # FRV: @do_sample_scipy.register(SingleFiniteDistribution) def _(dist: SingleFiniteDistribution, size, seed): # scipy can handle with custom distributions from scipy.stats import rv_discrete density_ = dist.dict x, y = [], [] for k, v in density_.items(): x.append(int(k)) y.append(float(v)) scipy_rv = rv_discrete(name='scipy_rv', values=(x, y)) return scipy_rv.rvs(size=size, random_state=seed) sympy-sympy-1.9/sympy/stats/sampling/tests/000077500000000000000000000000001412543434000212165ustar00rootroot00000000000000sympy-sympy-1.9/sympy/stats/sampling/tests/__init__.py000066400000000000000000000000001412543434000233150ustar00rootroot00000000000000sympy-sympy-1.9/sympy/stats/sampling/tests/test_sample_continuous_rv.py000066400000000000000000000123441412543434000271110ustar00rootroot00000000000000from sympy import exp, Interval, oo, Symbol from sympy.external import import_module from sympy.stats import Beta, Chi, Normal, Gamma, Exponential, LogNormal, Pareto, ChiSquared, Uniform, sample, \ BetaPrime, Cauchy, GammaInverse, GaussianInverse, StudentT, Weibull, density, ContinuousRV from sympy.testing.pytest import skip, raises def test_sample_numpy(): distribs_numpy = [ Beta("B", 1, 1), Normal("N", 0, 1), Gamma("G", 2, 7), Exponential("E", 2), LogNormal("LN", 0, 1), Pareto("P", 1, 1), ChiSquared("CS", 2), Uniform("U", 0, 1) ] size = 3 numpy = import_module('numpy') if not numpy: skip('Numpy is not installed. Abort tests for _sample_numpy.') else: for X in distribs_numpy: samps = sample(X, size=size, library='numpy') for sam in samps: assert sam in X.pspace.domain.set raises(NotImplementedError, lambda: sample(Chi("C", 1), library='numpy')) raises(NotImplementedError, lambda: Chi("C", 1).pspace.distribution.sample(library='tensorflow')) def test_sample_scipy(): distribs_scipy = [ Beta("B", 1, 1), BetaPrime("BP", 1, 1), Cauchy("C", 1, 1), Chi("C", 1), Normal("N", 0, 1), Gamma("G", 2, 7), GammaInverse("GI", 1, 1), GaussianInverse("GUI", 1, 1), Exponential("E", 2), LogNormal("LN", 0, 1), Pareto("P", 1, 1), StudentT("S", 2), ChiSquared("CS", 2), Uniform("U", 0, 1) ] size = 3 scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests for _sample_scipy.') else: for X in distribs_scipy: samps = sample(X, size=size, library='scipy') samps2 = sample(X, size=(2, 2), library='scipy') for sam in samps: assert sam in X.pspace.domain.set for i in range(2): for j in range(2): assert samps2[i][j] in X.pspace.domain.set def test_sample_pymc3(): distribs_pymc3 = [ Beta("B", 1, 1), Cauchy("C", 1, 1), Normal("N", 0, 1), Gamma("G", 2, 7), GaussianInverse("GI", 1, 1), Exponential("E", 2), LogNormal("LN", 0, 1), Pareto("P", 1, 1), ChiSquared("CS", 2), Uniform("U", 0, 1) ] size = 3 pymc3 = import_module('pymc3') if not pymc3: skip('PyMC3 is not installed. Abort tests for _sample_pymc3.') else: for X in distribs_pymc3: samps = sample(X, size=size, library='pymc3') for sam in samps: assert sam in X.pspace.domain.set raises(NotImplementedError, lambda: sample(Chi("C", 1), library='pymc3')) def test_sampling_gamma_inverse(): scipy = import_module('scipy') if not scipy: skip('Scipy not installed. Abort tests for sampling of gamma inverse.') X = GammaInverse("x", 1, 1) assert sample(X) in X.pspace.domain.set def test_lognormal_sampling(): # Right now, only density function and sampling works scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests') for i in range(3): X = LogNormal('x', i, 1) assert sample(X) in X.pspace.domain.set size = 5 samps = sample(X, size=size) for samp in samps: assert samp in X.pspace.domain.set def test_sampling_gaussian_inverse(): scipy = import_module('scipy') if not scipy: skip('Scipy not installed. Abort tests for sampling of Gaussian inverse.') X = GaussianInverse("x", 1, 1) assert sample(X, library='scipy') in X.pspace.domain.set def test_prefab_sampling(): scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests') N = Normal('X', 0, 1) L = LogNormal('L', 0, 1) E = Exponential('Ex', 1) P = Pareto('P', 1, 3) W = Weibull('W', 1, 1) U = Uniform('U', 0, 1) B = Beta('B', 2, 5) G = Gamma('G', 1, 3) variables = [N, L, E, P, W, U, B, G] niter = 10 size = 5 for var in variables: for _ in range(niter): assert sample(var) in var.pspace.domain.set samps = sample(var, size=size) for samp in samps: assert samp in var.pspace.domain.set def test_sample_continuous(): z = Symbol('z') Z = ContinuousRV(z, exp(-z), set=Interval(0, oo)) assert density(Z)(-1) == 0 scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests') assert sample(Z) in Z.pspace.domain.set sym, val = list(Z.pspace.sample().items())[0] assert sym == Z and val in Interval(0, oo) libraries = ['scipy', 'numpy', 'pymc3'] for lib in libraries: try: imported_lib = import_module(lib) if imported_lib: s0, s1, s2 = [], [], [] s0 = sample(Z, size=10, library=lib, seed=0) s1 = sample(Z, size=10, library=lib, seed=0) s2 = sample(Z, size=10, library=lib, seed=1) assert all(s0 == s1) assert all(s1 != s2) except NotImplementedError: continue sympy-sympy-1.9/sympy/stats/sampling/tests/test_sample_discrete_rv.py000066400000000000000000000063261412543434000265100ustar00rootroot00000000000000from sympy import S, Symbol from sympy.external import import_module from sympy.stats import Geometric, Poisson, Zeta, sample, Skellam, DiscreteRV, Logarithmic, NegativeBinomial, YuleSimon from sympy.testing.pytest import skip, raises, slow def test_sample_numpy(): distribs_numpy = [ Geometric('G', 0.5), Poisson('P', 1), Zeta('Z', 2) ] size = 3 numpy = import_module('numpy') if not numpy: skip('Numpy is not installed. Abort tests for _sample_numpy.') else: for X in distribs_numpy: samps = sample(X, size=size, library='numpy') for sam in samps: assert sam in X.pspace.domain.set raises(NotImplementedError, lambda: sample(Skellam('S', 1, 1), library='numpy')) raises(NotImplementedError, lambda: Skellam('S', 1, 1).pspace.distribution.sample(library='tensorflow')) def test_sample_scipy(): p = S(2)/3 x = Symbol('x', integer=True, positive=True) pdf = p*(1 - p)**(x - 1) # pdf of Geometric Distribution distribs_scipy = [ DiscreteRV(x, pdf, set=S.Naturals), Geometric('G', 0.5), Logarithmic('L', 0.5), NegativeBinomial('N', 5, 0.4), Poisson('P', 1), Skellam('S', 1, 1), YuleSimon('Y', 1), Zeta('Z', 2) ] size = 3 scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests for _sample_scipy.') else: for X in distribs_scipy: samps = sample(X, size=size, library='scipy') samps2 = sample(X, size=(2, 2), library='scipy') for sam in samps: assert sam in X.pspace.domain.set for i in range(2): for j in range(2): assert samps2[i][j] in X.pspace.domain.set def test_sample_pymc3(): distribs_pymc3 = [ Geometric('G', 0.5), Poisson('P', 1), NegativeBinomial('N', 5, 0.4) ] size = 3 pymc3 = import_module('pymc3') if not pymc3: skip('PyMC3 is not installed. Abort tests for _sample_pymc3.') else: for X in distribs_pymc3: samps = sample(X, size=size, library='pymc3') for sam in samps: assert sam in X.pspace.domain.set raises(NotImplementedError, lambda: sample(Skellam('S', 1, 1), library='pymc3')) @slow def test_sample_discrete(): X = Geometric('X', S.Half) scipy = import_module('scipy') if not scipy: skip('Scipy not installed. Abort tests') assert sample(X) in X.pspace.domain.set samps = sample(X, size=2) # This takes long time if ran without scipy for samp in samps: assert samp in X.pspace.domain.set libraries = ['scipy', 'numpy', 'pymc3'] for lib in libraries: try: imported_lib = import_module(lib) if imported_lib: s0, s1, s2 = [], [], [] s0 = sample(X, size=10, library=lib, seed=0) s1 = sample(X, size=10, library=lib, seed=0) s2 = sample(X, size=10, library=lib, seed=1) assert all(s0 == s1) assert not all(s1 == s2) except NotImplementedError: continue sympy-sympy-1.9/sympy/stats/sampling/tests/test_sample_finite_rv.py000066400000000000000000000056561412543434000261710ustar00rootroot00000000000000from sympy import S, Rational from sympy.external import import_module from sympy.stats import Binomial, sample, Die, FiniteRV, DiscreteUniform, Bernoulli, BetaBinomial, Hypergeometric, \ Rademacher from sympy.testing.pytest import skip, raises def test_given_sample(): X = Die('X', 6) scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests') assert sample(X, X > 5) == 6 def test_sample_numpy(): distribs_numpy = [ Binomial("B", 5, 0.4), ] size = 3 numpy = import_module('numpy') if not numpy: skip('Numpy is not installed. Abort tests for _sample_numpy.') else: for X in distribs_numpy: samps = sample(X, size=size, library='numpy') for sam in samps: assert sam in X.pspace.domain.set raises(NotImplementedError, lambda: sample(Die("D"), library='numpy')) raises(NotImplementedError, lambda: Die("D").pspace.sample(library='tensorflow')) def test_sample_scipy(): distribs_scipy = [ FiniteRV('F', {1: S.Half, 2: Rational(1, 4), 3: Rational(1, 4)}), DiscreteUniform("Y", list(range(5))), Die("D"), Bernoulli("Be", 0.3), Binomial("Bi", 5, 0.4), BetaBinomial("Bb", 2, 1, 1), Hypergeometric("H", 1, 1, 1), Rademacher("R") ] size = 3 scipy = import_module('scipy') if not scipy: skip('Scipy not installed. Abort tests for _sample_scipy.') else: for X in distribs_scipy: samps = sample(X, size=size) samps2 = sample(X, size=(2, 2)) for sam in samps: assert sam in X.pspace.domain.set for i in range(2): for j in range(2): assert samps2[i][j] in X.pspace.domain.set def test_sample_pymc3(): distribs_pymc3 = [ Bernoulli('B', 0.2), Binomial('N', 5, 0.4) ] size = 3 pymc3 = import_module('pymc3') if not pymc3: skip('PyMC3 is not installed. Abort tests for _sample_pymc3.') else: for X in distribs_pymc3: samps = sample(X, size=size, library='pymc3') for sam in samps: assert sam in X.pspace.domain.set raises(NotImplementedError, lambda: (sample(Die("D"), library='pymc3'))) def test_sample_seed(): F = FiniteRV('F', {1: S.Half, 2: Rational(1, 4), 3: Rational(1, 4)}) size = 10 libraries = ['scipy', 'numpy', 'pymc3'] for lib in libraries: try: imported_lib = import_module(lib) if imported_lib: s0 = sample(F, size=size, library=lib, seed=0) s1 = sample(F, size=size, library=lib, seed=0) s2 = sample(F, size=size, library=lib, seed=1) assert all(s0 == s1) assert not all(s1 == s2) except NotImplementedError: continue sympy-sympy-1.9/sympy/stats/stochastic_process.py000066400000000000000000000043751412543434000225270ustar00rootroot00000000000000from sympy import Basic from sympy.stats.joint_rv import ProductPSpace from sympy.stats.rv import ProductDomain, _symbol_converter, Distribution class StochasticPSpace(ProductPSpace): """ Represents probability space of stochastic processes and their random variables. Contains mechanics to do computations for queries of stochastic processes. Explanation =========== Initialized by symbol, the specific process and distribution(optional) if the random indexed symbols of the process follows any specific distribution, like, in Bernoulli Process, each random indexed symbol follows Bernoulli distribution. For processes with memory, this parameter should not be passed. """ def __new__(cls, sym, process, distribution=None): sym = _symbol_converter(sym) from sympy.stats.stochastic_process_types import StochasticProcess if not isinstance(process, StochasticProcess): raise TypeError("`process` must be an instance of StochasticProcess.") if distribution is None: distribution = Distribution() return Basic.__new__(cls, sym, process, distribution) @property def process(self): """ The associated stochastic process. """ return self.args[1] @property def domain(self): return ProductDomain(self.process.index_set, self.process.state_space) @property def symbol(self): return self.args[0] @property def distribution(self): return self.args[2] def probability(self, condition, given_condition=None, evaluate=True, **kwargs): """ Transfers the task of handling queries to the specific stochastic process because every process has their own logic of handling such queries. """ return self.process.probability(condition, given_condition, evaluate, **kwargs) def compute_expectation(self, expr, condition=None, evaluate=True, **kwargs): """ Transfers the task of handling queries to the specific stochastic process because every process has their own logic of handling such queries. """ return self.process.expectation(expr, condition, evaluate, **kwargs) sympy-sympy-1.9/sympy/stats/stochastic_process_types.py000066400000000000000000002525361412543434000237570ustar00rootroot00000000000000from __future__ import print_function, division import random import itertools from typing import Sequence as tSequence, Union as tUnion, List as tList, Tuple as tTuple from sympy import (Matrix, MatrixSymbol, S, Indexed, Basic, Tuple, Range, Set, And, Eq, FiniteSet, ImmutableMatrix, Integer, igcd, Lambda, Mul, Dummy, IndexedBase, Add, Interval, oo, linsolve, eye, Or, Not, Intersection, factorial, Contains, Union, Expr, Function, exp, cacheit, sqrt, pi, gamma, Ge, Piecewise, Symbol, NonSquareMatrixError, EmptySet, ceiling, MatrixBase, ConditionSet, ones, zeros, Identity, Rational, Lt, Gt, Le, Ne, BlockMatrix, Sum) from sympy.core.relational import Relational from sympy.logic.boolalg import Boolean from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.iterables import strongly_connected_components from sympy.stats.joint_rv import JointDistribution from sympy.stats.joint_rv_types import JointDistributionHandmade from sympy.stats.rv import (RandomIndexedSymbol, random_symbols, RandomSymbol, _symbol_converter, _value_check, pspace, given, dependent, is_random, sample_iter, Distribution, Density) from sympy.stats.stochastic_process import StochasticPSpace from sympy.stats.symbolic_probability import Probability, Expectation from sympy.stats.frv_types import Bernoulli, BernoulliDistribution, FiniteRV from sympy.stats.drv_types import Poisson, PoissonDistribution from sympy.stats.crv_types import Normal, NormalDistribution, Gamma, GammaDistribution from sympy.core.sympify import _sympify, sympify __all__ = [ 'StochasticProcess', 'DiscreteTimeStochasticProcess', 'DiscreteMarkovChain', 'TransitionMatrixOf', 'StochasticStateSpaceOf', 'GeneratorMatrixOf', 'ContinuousMarkovChain', 'BernoulliProcess', 'PoissonProcess', 'WienerProcess', 'GammaProcess' ] @is_random.register(Indexed) def _(x): return is_random(x.base) @is_random.register(RandomIndexedSymbol) # type: ignore def _(x): return True def _set_converter(itr): """ Helper function for converting list/tuple/set to Set. If parameter is not an instance of list/tuple/set then no operation is performed. Returns ======= Set The argument converted to Set. Raises ====== TypeError If the argument is not an instance of list/tuple/set. """ if isinstance(itr, (list, tuple, set)): itr = FiniteSet(*itr) if not isinstance(itr, Set): raise TypeError("%s is not an instance of list/tuple/set."%(itr)) return itr def _state_converter(itr: tSequence) -> tUnion[Tuple, Range]: """ Helper function for converting list/tuple/set/Range/Tuple/FiniteSet to tuple/Range. """ if isinstance(itr, (Tuple, set, FiniteSet)): itr = Tuple(*(sympify(i) if isinstance(i, str) else i for i in itr)) elif isinstance(itr, (list, tuple)): # check if states are unique if len(set(itr)) != len(itr): raise ValueError('The state space must have unique elements.') itr = Tuple(*(sympify(i) if isinstance(i, str) else i for i in itr)) elif isinstance(itr, Range): # the only ordered set in sympy I know of # try to convert to tuple try: itr = Tuple(*(sympify(i) if isinstance(i, str) else i for i in itr)) except (TypeError, ValueError): pass else: raise TypeError("%s is not an instance of list/tuple/set/Range/Tuple/FiniteSet." % (itr)) return itr def _sym_sympify(arg): """ Converts an arbitrary expression to a type that can be used inside SymPy. As generally strings are unwise to use in the expressions, it returns the Symbol of argument if the string type argument is passed. Parameters ========= arg: The parameter to be converted to be used in Sympy. Returns ======= The converted parameter. """ if isinstance(arg, str): return Symbol(arg) else: return _sympify(arg) def _matrix_checks(matrix): if not isinstance(matrix, (Matrix, MatrixSymbol, ImmutableMatrix)): raise TypeError("Transition probabilities either should " "be a Matrix or a MatrixSymbol.") if matrix.shape[0] != matrix.shape[1]: raise NonSquareMatrixError("%s is not a square matrix"%(matrix)) if isinstance(matrix, Matrix): matrix = ImmutableMatrix(matrix.tolist()) return matrix class StochasticProcess(Basic): """ Base class for all the stochastic processes whether discrete or continuous. Parameters ========== sym: Symbol or str state_space: Set The state space of the stochastic process, by default S.Reals. For discrete sets it is zero indexed. See Also ======== DiscreteTimeStochasticProcess """ index_set = S.Reals def __new__(cls, sym, state_space=S.Reals, **kwargs): sym = _symbol_converter(sym) state_space = _set_converter(state_space) return Basic.__new__(cls, sym, state_space) @property def symbol(self): return self.args[0] @property def state_space(self) -> tUnion[FiniteSet, Range]: if not isinstance(self.args[1], (FiniteSet, Range)): return FiniteSet(*self.args[1]) return self.args[1] def _deprecation_warn_distribution(self): SymPyDeprecationWarning( feature="Calling distribution with RandomIndexedSymbol", useinstead="distribution with just timestamp as argument", issue=20078, deprecated_since_version="1.7.1" ).warn() def distribution(self, key=None): if key is None: self._deprecation_warn_distribution() return Distribution() def density(self, x): return Density() def __call__(self, time): """ Overridden in ContinuousTimeStochasticProcess. """ raise NotImplementedError("Use [] for indexing discrete time stochastic process.") def __getitem__(self, time): """ Overridden in DiscreteTimeStochasticProcess. """ raise NotImplementedError("Use () for indexing continuous time stochastic process.") def probability(self, condition): raise NotImplementedError() def joint_distribution(self, *args): """ Computes the joint distribution of the random indexed variables. Parameters ========== args: iterable The finite list of random indexed variables/the key of a stochastic process whose joint distribution has to be computed. Returns ======= JointDistribution The joint distribution of the list of random indexed variables. An unevaluated object is returned if it is not possible to compute the joint distribution. Raises ====== ValueError: When the arguments passed are not of type RandomIndexSymbol or Number. """ args = list(args) for i, arg in enumerate(args): if S(arg).is_Number: if self.index_set.is_subset(S.Integers): args[i] = self.__getitem__(arg) else: args[i] = self.__call__(arg) elif not isinstance(arg, RandomIndexedSymbol): raise ValueError("Expected a RandomIndexedSymbol or " "key not %s"%(type(arg))) if args[0].pspace.distribution == Distribution(): return JointDistribution(*args) density = Lambda(tuple(args), expr=Mul.fromiter(arg.pspace.process.density(arg) for arg in args)) return JointDistributionHandmade(density) def expectation(self, condition, given_condition): raise NotImplementedError("Abstract method for expectation queries.") def sample(self): raise NotImplementedError("Abstract method for sampling queries.") class DiscreteTimeStochasticProcess(StochasticProcess): """ Base class for all discrete stochastic processes. """ def __getitem__(self, time): """ For indexing discrete time stochastic processes. Returns ======= RandomIndexedSymbol """ time = sympify(time) if not time.is_symbol and time not in self.index_set: raise IndexError("%s is not in the index set of %s"%(time, self.symbol)) idx_obj = Indexed(self.symbol, time) pspace_obj = StochasticPSpace(self.symbol, self, self.distribution(time)) return RandomIndexedSymbol(idx_obj, pspace_obj) class ContinuousTimeStochasticProcess(StochasticProcess): """ Base class for all continuous time stochastic process. """ def __call__(self, time): """ For indexing continuous time stochastic processes. Returns ======= RandomIndexedSymbol """ time = sympify(time) if not time.is_symbol and time not in self.index_set: raise IndexError("%s is not in the index set of %s"%(time, self.symbol)) func_obj = Function(self.symbol)(time) pspace_obj = StochasticPSpace(self.symbol, self, self.distribution(time)) return RandomIndexedSymbol(func_obj, pspace_obj) class TransitionMatrixOf(Boolean): """ Assumes that the matrix is the transition matrix of the process. """ def __new__(cls, process, matrix): if not isinstance(process, DiscreteMarkovChain): raise ValueError("Currently only DiscreteMarkovChain " "support TransitionMatrixOf.") matrix = _matrix_checks(matrix) return Basic.__new__(cls, process, matrix) process = property(lambda self: self.args[0]) matrix = property(lambda self: self.args[1]) class GeneratorMatrixOf(TransitionMatrixOf): """ Assumes that the matrix is the generator matrix of the process. """ def __new__(cls, process, matrix): if not isinstance(process, ContinuousMarkovChain): raise ValueError("Currently only ContinuousMarkovChain " "support GeneratorMatrixOf.") matrix = _matrix_checks(matrix) return Basic.__new__(cls, process, matrix) class StochasticStateSpaceOf(Boolean): def __new__(cls, process, state_space): if not isinstance(process, (DiscreteMarkovChain, ContinuousMarkovChain)): raise ValueError("Currently only DiscreteMarkovChain and ContinuousMarkovChain " "support StochasticStateSpaceOf.") state_space = _state_converter(state_space) if isinstance(state_space, Range): ss_size = ceiling((state_space.stop - state_space.start) / state_space.step) else: ss_size = len(state_space) state_index = Range(ss_size) return Basic.__new__(cls, process, state_index) process = property(lambda self: self.args[0]) state_index = property(lambda self: self.args[1]) class MarkovProcess(StochasticProcess): """ Contains methods that handle queries common to Markov processes. """ @property def number_of_states(self) -> tUnion[Integer, Symbol]: """ The number of states in the Markov Chain. """ return _sympify(self.args[2].shape[0]) @property def _state_index(self) -> Range: """ Returns state index as Range. """ return self.args[1] @classmethod def _sanity_checks(cls, state_space, trans_probs): # Try to never have None as state_space or trans_probs. # This helps a lot if we get it done at the start. if (state_space is None) and (trans_probs is None): _n = Dummy('n', integer=True, nonnegative=True) state_space = _state_converter(Range(_n)) trans_probs = _matrix_checks(MatrixSymbol('_T', _n, _n)) elif state_space is None: trans_probs = _matrix_checks(trans_probs) state_space = _state_converter(Range(trans_probs.shape[0])) elif trans_probs is None: state_space = _state_converter(state_space) if isinstance(state_space, Range): _n = ceiling((state_space.stop - state_space.start) / state_space.step) else: _n = len(state_space) trans_probs = MatrixSymbol('_T', _n, _n) else: state_space = _state_converter(state_space) trans_probs = _matrix_checks(trans_probs) # Range object doesn't want to give a symbolic size # so we do it ourselves. if isinstance(state_space, Range): ss_size = ceiling((state_space.stop - state_space.start) / state_space.step) else: ss_size = len(state_space) if ss_size != trans_probs.shape[0]: raise ValueError('The size of the state space and the number of ' 'rows of the transition matrix must be the same.') return state_space, trans_probs def _extract_information(self, given_condition): """ Helper function to extract information, like, transition matrix/generator matrix, state space, etc. """ if isinstance(self, DiscreteMarkovChain): trans_probs = self.transition_probabilities state_index = self._state_index elif isinstance(self, ContinuousMarkovChain): trans_probs = self.generator_matrix state_index = self._state_index if isinstance(given_condition, And): gcs = given_condition.args given_condition = S.true for gc in gcs: if isinstance(gc, TransitionMatrixOf): trans_probs = gc.matrix if isinstance(gc, StochasticStateSpaceOf): state_index = gc.state_index if isinstance(gc, Relational): given_condition = given_condition & gc if isinstance(given_condition, TransitionMatrixOf): trans_probs = given_condition.matrix given_condition = S.true if isinstance(given_condition, StochasticStateSpaceOf): state_index = given_condition.state_index given_condition = S.true return trans_probs, state_index, given_condition def _check_trans_probs(self, trans_probs, row_sum=1): """ Helper function for checking the validity of transition probabilities. """ if not isinstance(trans_probs, MatrixSymbol): rows = trans_probs.tolist() for row in rows: if (sum(row) - row_sum) != 0: raise ValueError("Values in a row must sum to %s. " "If you are using Float or floats then please use Rational."%(row_sum)) def _work_out_state_index(self, state_index, given_condition, trans_probs): """ Helper function to extract state space if there is a random symbol in the given condition. """ # if given condition is None, then there is no need to work out # state_space from random variables if given_condition != None: rand_var = list(given_condition.atoms(RandomSymbol) - given_condition.atoms(RandomIndexedSymbol)) if len(rand_var) == 1: state_index = rand_var[0].pspace.set # `not None` is `True`. So the old test fails for symbolic sizes. # Need to build the statement differently. sym_cond = not isinstance(self.number_of_states, (int, Integer)) cond1 = not sym_cond and len(state_index) != trans_probs.shape[0] if cond1: raise ValueError("state space is not compatible with the transition probabilities.") if not isinstance(trans_probs.shape[0], Symbol): state_index = FiniteSet(*[i for i in range(trans_probs.shape[0])]) return state_index @cacheit def _preprocess(self, given_condition, evaluate): """ Helper function for pre-processing the information. """ is_insufficient = False if not evaluate: # avoid pre-processing if the result is not to be evaluated return (True, None, None, None) # extracting transition matrix and state space trans_probs, state_index, given_condition = self._extract_information(given_condition) # given_condition does not have sufficient information # for computations if trans_probs is None or \ given_condition is None: is_insufficient = True else: # checking transition probabilities if isinstance(self, DiscreteMarkovChain): self._check_trans_probs(trans_probs, row_sum=1) elif isinstance(self, ContinuousMarkovChain): self._check_trans_probs(trans_probs, row_sum=0) # working out state space state_index = self._work_out_state_index(state_index, given_condition, trans_probs) return is_insufficient, trans_probs, state_index, given_condition def replace_with_index(self, condition): if isinstance(condition, Relational): lhs, rhs = condition.lhs, condition.rhs if not isinstance(lhs, RandomIndexedSymbol): lhs, rhs = rhs, lhs condition = type(condition)(self.index_of.get(lhs, lhs), self.index_of.get(rhs, rhs)) return condition def probability(self, condition, given_condition=None, evaluate=True, **kwargs): """ Handles probability queries for Markov process. Parameters ========== condition: Relational given_condition: Relational/And Returns ======= Probability If the information is not sufficient. Expr In all other cases. Note ==== Any information passed at the time of query overrides any information passed at the time of object creation like transition probabilities, state space. Pass the transition matrix using TransitionMatrixOf, generator matrix using GeneratorMatrixOf and state space using StochasticStateSpaceOf in given_condition using & or And. """ check, mat, state_index, new_given_condition = \ self._preprocess(given_condition, evaluate) rv = list(condition.atoms(RandomIndexedSymbol)) symbolic = False for sym in rv: if sym.key.is_symbol: symbolic = True break if check: return Probability(condition, new_given_condition) if isinstance(self, ContinuousMarkovChain): trans_probs = self.transition_probabilities(mat) elif isinstance(self, DiscreteMarkovChain): trans_probs = mat condition = self.replace_with_index(condition) given_condition = self.replace_with_index(given_condition) new_given_condition = self.replace_with_index(new_given_condition) if isinstance(condition, Relational): if isinstance(new_given_condition, And): gcs = new_given_condition.args else: gcs = (new_given_condition, ) min_key_rv = list(new_given_condition.atoms(RandomIndexedSymbol)) if len(min_key_rv): min_key_rv = min_key_rv[0] for r in rv: if min_key_rv.key.is_symbol or r.key.is_symbol: continue if min_key_rv.key > r.key: return Probability(condition) else: min_key_rv = None return Probability(condition) if symbolic: return self._symbolic_probability(condition, new_given_condition, rv, min_key_rv) if len(rv) > 1: rv[0] = condition.lhs rv[1] = condition.rhs if rv[0].key < rv[1].key: rv[0], rv[1] = rv[1], rv[0] if isinstance(condition, Gt): condition = Lt(condition.lhs, condition.rhs) elif isinstance(condition, Lt): condition = Gt(condition.lhs, condition.rhs) elif isinstance(condition, Ge): condition = Le(condition.lhs, condition.rhs) elif isinstance(condition, Le): condition = Ge(condition.lhs, condition.rhs) s = Rational(0, 1) n = len(self.state_space) if isinstance(condition, Eq) or isinstance(condition, Ne): for i in range(0, n): s += self.probability(Eq(rv[0], i), Eq(rv[1], i)) * self.probability(Eq(rv[1], i), new_given_condition) return s if isinstance(condition, Eq) else 1 - s else: upper = 0 greater = False if isinstance(condition, Ge) or isinstance(condition, Lt): upper = 1 if isinstance(condition, Gt) or isinstance(condition, Ge): greater = True for i in range(0, n): if i <= n//2: for j in range(0, i + upper): s += self.probability(Eq(rv[0], i), Eq(rv[1], j)) * self.probability(Eq(rv[1], j), new_given_condition) else: s += self.probability(Eq(rv[0], i), new_given_condition) for j in range(i + upper, n): s -= self.probability(Eq(rv[0], i), Eq(rv[1], j)) * self.probability(Eq(rv[1], j), new_given_condition) return s if greater else 1 - s rv = rv[0] states = condition.as_set() prob, gstate = dict(), None for gc in gcs: if gc.has(min_key_rv): if gc.has(Probability): p, gp = (gc.rhs, gc.lhs) if isinstance(gc.lhs, Probability) \ else (gc.lhs, gc.rhs) gr = gp.args[0] gset = Intersection(gr.as_set(), state_index) gstate = list(gset)[0] prob[gset] = p else: _, gstate = (gc.lhs.key, gc.rhs) if isinstance(gc.lhs, RandomIndexedSymbol) \ else (gc.rhs.key, gc.lhs) if any((k not in self.index_set) for k in (rv.key, min_key_rv.key)): raise IndexError("The timestamps of the process are not in it's index set.") states = Intersection(states, state_index) if not isinstance(self.number_of_states, Symbol) else states for state in Union(states, FiniteSet(gstate)): if not isinstance(state, (int, Integer)) or Ge(state, mat.shape[0]) is True: raise IndexError("No information is available for (%s, %s) in " "transition probabilities of shape, (%s, %s). " "State space is zero indexed." %(gstate, state, mat.shape[0], mat.shape[1])) if prob: gstates = Union(*prob.keys()) if len(gstates) == 1: gstate = list(gstates)[0] gprob = list(prob.values())[0] prob[gstates] = gprob elif len(gstates) == len(state_index) - 1: gstate = list(state_index - gstates)[0] gprob = S.One - sum(prob.values()) prob[state_index - gstates] = gprob else: raise ValueError("Conflicting information.") else: gprob = S.One if min_key_rv == rv: return sum([prob[FiniteSet(state)] for state in states]) if isinstance(self, ContinuousMarkovChain): return gprob * sum([trans_probs(rv.key - min_key_rv.key).__getitem__((gstate, state)) for state in states]) if isinstance(self, DiscreteMarkovChain): return gprob * sum([(trans_probs**(rv.key - min_key_rv.key)).__getitem__((gstate, state)) for state in states]) if isinstance(condition, Not): expr = condition.args[0] return S.One - self.probability(expr, given_condition, evaluate, **kwargs) if isinstance(condition, And): compute_later, state2cond, conds = [], dict(), condition.args for expr in conds: if isinstance(expr, Relational): ris = list(expr.atoms(RandomIndexedSymbol))[0] if state2cond.get(ris, None) is None: state2cond[ris] = S.true state2cond[ris] &= expr else: compute_later.append(expr) ris = [] for ri in state2cond: ris.append(ri) cset = Intersection(state2cond[ri].as_set(), state_index) if len(cset) == 0: return S.Zero state2cond[ri] = cset.as_relational(ri) sorted_ris = sorted(ris, key=lambda ri: ri.key) prod = self.probability(state2cond[sorted_ris[0]], given_condition, evaluate, **kwargs) for i in range(1, len(sorted_ris)): ri, prev_ri = sorted_ris[i], sorted_ris[i-1] if not isinstance(state2cond[ri], Eq): raise ValueError("The process is in multiple states at %s, unable to determine the probability."%(ri)) mat_of = TransitionMatrixOf(self, mat) if isinstance(self, DiscreteMarkovChain) else GeneratorMatrixOf(self, mat) prod *= self.probability(state2cond[ri], state2cond[prev_ri] & mat_of & StochasticStateSpaceOf(self, state_index), evaluate, **kwargs) for expr in compute_later: prod *= self.probability(expr, given_condition, evaluate, **kwargs) return prod if isinstance(condition, Or): return sum([self.probability(expr, given_condition, evaluate, **kwargs) for expr in condition.args]) raise NotImplementedError("Mechanism for handling (%s, %s) queries hasn't been " "implemented yet."%(condition, given_condition)) def _symbolic_probability(self, condition, new_given_condition, rv, min_key_rv): #Function to calculate probability for queries with symbols if isinstance(condition, Relational): curr_state = new_given_condition.rhs if isinstance(new_given_condition.lhs, RandomIndexedSymbol) \ else new_given_condition.lhs next_state = condition.rhs if isinstance(condition.lhs, RandomIndexedSymbol) \ else condition.lhs if isinstance(condition, Eq) or isinstance(condition, Ne): if isinstance(self, DiscreteMarkovChain): P = self.transition_probabilities**(rv[0].key - min_key_rv.key) else: P = exp(self.generator_matrix*(rv[0].key - min_key_rv.key)) prob = P[curr_state, next_state] if isinstance(condition, Eq) else 1 - P[curr_state, next_state] return Piecewise((prob, rv[0].key > min_key_rv.key), (Probability(condition), True)) else: upper = 1 greater = False if isinstance(condition, Ge) or isinstance(condition, Lt): upper = 0 if isinstance(condition, Gt) or isinstance(condition, Ge): greater = True k = Dummy('k') condition = Eq(condition.lhs, k) if isinstance(condition.lhs, RandomIndexedSymbol)\ else Eq(condition.rhs, k) total = Sum(self.probability(condition, new_given_condition), (k, next_state + upper, self.state_space._sup)) return Piecewise((total, rv[0].key > min_key_rv.key), (Probability(condition), True)) if greater\ else Piecewise((1 - total, rv[0].key > min_key_rv.key), (Probability(condition), True)) else: return Probability(condition, new_given_condition) def expectation(self, expr, condition=None, evaluate=True, **kwargs): """ Handles expectation queries for markov process. Parameters ========== expr: RandomIndexedSymbol, Relational, Logic Condition for which expectation has to be computed. Must contain a RandomIndexedSymbol of the process. condition: Relational, Logic The given conditions under which computations should be done. Returns ======= Expectation Unevaluated object if computations cannot be done due to insufficient information. Expr In all other cases when the computations are successful. Note ==== Any information passed at the time of query overrides any information passed at the time of object creation like transition probabilities, state space. Pass the transition matrix using TransitionMatrixOf, generator matrix using GeneratorMatrixOf and state space using StochasticStateSpaceOf in given_condition using & or And. """ check, mat, state_index, condition = \ self._preprocess(condition, evaluate) if check: return Expectation(expr, condition) rvs = random_symbols(expr) if isinstance(expr, Expr) and isinstance(condition, Eq) \ and len(rvs) == 1: # handle queries similar to E(f(X[i]), Eq(X[i-m], )) condition=self.replace_with_index(condition) state_index=self.replace_with_index(state_index) rv = list(rvs)[0] lhsg, rhsg = condition.lhs, condition.rhs if not isinstance(lhsg, RandomIndexedSymbol): lhsg, rhsg = (rhsg, lhsg) if rhsg not in state_index: raise ValueError("%s state is not in the state space."%(rhsg)) if rv.key < lhsg.key: raise ValueError("Incorrect given condition is given, expectation " "time %s < time %s"%(rv.key, rv.key)) mat_of = TransitionMatrixOf(self, mat) if isinstance(self, DiscreteMarkovChain) else GeneratorMatrixOf(self, mat) cond = condition & mat_of & \ StochasticStateSpaceOf(self, state_index) func = lambda s: self.probability(Eq(rv, s), cond) * expr.subs(rv, self._state_index[s]) return sum([func(s) for s in state_index]) raise NotImplementedError("Mechanism for handling (%s, %s) queries hasn't been " "implemented yet."%(expr, condition)) class DiscreteMarkovChain(DiscreteTimeStochasticProcess, MarkovProcess): """ Represents a finite discrete time-homogeneous Markov chain. This type of Markov Chain can be uniquely characterised by its (ordered) state space and its one-step transition probability matrix. Parameters ========== sym: The name given to the Markov Chain state_space: Optional, by default, Range(n) trans_probs: Optional, by default, MatrixSymbol('_T', n, n) Examples ======== >>> from sympy.stats import DiscreteMarkovChain, TransitionMatrixOf, P, E >>> from sympy import Matrix, MatrixSymbol, Eq, symbols >>> T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) >>> YS = DiscreteMarkovChain("Y") >>> Y.state_space {0, 1, 2} >>> Y.transition_probabilities Matrix([ [0.5, 0.2, 0.3], [0.2, 0.5, 0.3], [0.2, 0.3, 0.5]]) >>> TS = MatrixSymbol('T', 3, 3) >>> P(Eq(YS[3], 2), Eq(YS[1], 1) & TransitionMatrixOf(YS, TS)) T[0, 2]*T[1, 0] + T[1, 1]*T[1, 2] + T[1, 2]*T[2, 2] >>> P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) 0.36 Probabilities will be calculated based on indexes rather than state names. For example, with the Sunny-Cloudy-Rainy model with string state names: >>> from sympy.core.symbol import Str >>> Y = DiscreteMarkovChain("Y", [Str('Sunny'), Str('Cloudy'), Str('Rainy')], T) >>> P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) 0.36 This gives the same answer as the ``[0, 1, 2]`` state space. Currently, there is no support for state names within probability and expectation statements. Here is a work-around using ``Str``: >>> P(Eq(Str('Rainy'), Y[3]), Eq(Y[1], Str('Cloudy'))).round(2) 0.36 Symbol state names can also be used: >>> sunny, cloudy, rainy = symbols('Sunny, Cloudy, Rainy') >>> Y = DiscreteMarkovChain("Y", [sunny, cloudy, rainy], T) >>> P(Eq(Y[3], rainy), Eq(Y[1], cloudy)).round(2) 0.36 Expectations will be calculated as follows: >>> E(Y[3], Eq(Y[1], cloudy)) 0.38*Cloudy + 0.36*Rainy + 0.26*Sunny Probability of expressions with multiple RandomIndexedSymbols can also be calculated provided there is only 1 RandomIndexedSymbol in the given condition. It is always better to use Rational instead of floating point numbers for the probabilities in the transition matrix to avoid errors. >>> from sympy import Gt, Le, Rational >>> T = Matrix([[Rational(5, 10), Rational(3, 10), Rational(2, 10)], [Rational(2, 10), Rational(7, 10), Rational(1, 10)], [Rational(3, 10), Rational(3, 10), Rational(4, 10)]]) >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) >>> P(Eq(Y[3], Y[1]), Eq(Y[0], 0)).round(3) 0.409 >>> P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) 0.36 >>> P(Le(Y[15], Y[10]), Eq(Y[8], 2)).round(7) 0.6963328 Symbolic probability queries are also supported >>> from sympy import symbols, Matrix, Rational, Eq, Gt >>> from sympy.stats import P, DiscreteMarkovChain >>> a, b, c, d = symbols('a b c d') >>> T = Matrix([[Rational(1, 10), Rational(4, 10), Rational(5, 10)], [Rational(3, 10), Rational(4, 10), Rational(3, 10)], [Rational(7, 10), Rational(2, 10), Rational(1, 10)]]) >>> Y = DiscreteMarkovChain("Y", [0, 1, 2], T) >>> query = P(Eq(Y[a], b), Eq(Y[c], d)) >>> query.subs({a:10 ,b:2, c:5, d:1}).round(4) 0.3096 >>> P(Eq(Y[10], 2), Eq(Y[5], 1)).evalf().round(4) 0.3096 >>> query_gt = P(Gt(Y[a], b), Eq(Y[c], d)) >>> query_gt.subs({a:21, b:0, c:5, d:0}).evalf().round(5) 0.64705 >>> P(Gt(Y[21], 0), Eq(Y[5], 0)).round(5) 0.64705 There is limited support for arbitrarily sized states: >>> n = symbols('n', nonnegative=True, integer=True) >>> T = MatrixSymbol('T', n, n) >>> Y = DiscreteMarkovChain("Y", trans_probs=T) >>> Y.state_space Range(0, n, 1) >>> query = P(Eq(Y[a], b), Eq(Y[c], d)) >>> query.subs({a:10, b:2, c:5, d:1}) (T**5)[1, 2] References ========== .. [1] https://en.wikipedia.org/wiki/Markov_chain#Discrete-time_Markov_chain .. [2] https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf """ index_set = S.Naturals0 def __new__(cls, sym, state_space=None, trans_probs=None): # type: (Basic, tUnion[str, Symbol], tSequence, tUnion[MatrixBase, MatrixSymbol]) -> DiscreteMarkovChain sym = _symbol_converter(sym) state_space, trans_probs = MarkovProcess._sanity_checks(state_space, trans_probs) obj = Basic.__new__(cls, sym, state_space, trans_probs) indices = dict() if isinstance(obj.number_of_states, Integer): for index, state in enumerate(obj._state_index): indices[state] = index obj.index_of = indices return obj @property def transition_probabilities(self) -> tUnion[MatrixBase, MatrixSymbol]: """ Transition probabilities of discrete Markov chain, either an instance of Matrix or MatrixSymbol. """ return self.args[2] def communication_classes(self) -> tList[tTuple[tList[Basic], Boolean, Integer]]: """ Returns the list of communication classes that partition the states of the markov chain. A communication class is defined to be a set of states such that every state in that set is reachable from every other state in that set. Due to its properties this forms a class in the mathematical sense. Communication classes are also known as recurrence classes. Returns ======= classes The ``classes`` are a list of tuples. Each tuple represents a single communication class with its properties. The first element in the tuple is the list of states in the class, the second element is whether the class is recurrent and the third element is the period of the communication class. Examples ======== >>> from sympy.stats import DiscreteMarkovChain >>> from sympy import Matrix >>> T = Matrix([[0, 1, 0], ... [1, 0, 0], ... [1, 0, 0]]) >>> X = DiscreteMarkovChain('X', [1, 2, 3], T) >>> classes = X.communication_classes() >>> for states, is_recurrent, period in classes: ... states, is_recurrent, period ([1, 2], True, 2) ([3], False, 1) From this we can see that states ``1`` and ``2`` communicate, are recurrent and have a period of 2. We can also see state ``3`` is transient with a period of 1. Notes ===== The algorithm used is of order ``O(n**2)`` where ``n`` is the number of states in the markov chain. It uses Tarjan's algorithm to find the classes themselves and then it uses a breadth-first search algorithm to find each class's periodicity. Most of the algorithm's components approach ``O(n)`` as the matrix becomes more and more sparse. References ========== .. [1] http://www.columbia.edu/~ww2040/4701Sum07/4701-06-Notes-MCII.pdf .. [2] http://cecas.clemson.edu/~shierd/Shier/markov.pdf .. [3] https://ujcontent.uj.ac.za/vital/access/services/Download/uj:7506/CONTENT1 .. [4] https://www.mathworks.com/help/econ/dtmc.classify.html """ n = self.number_of_states T = self.transition_probabilities if isinstance(T, MatrixSymbol): raise NotImplementedError("Cannot perform the operation with a symbolic matrix.") # begin Tarjan's algorithm V = Range(n) # don't use state names. Rather use state # indexes since we use them for matrix # indexing here and later onward E = [(i, j) for i in V for j in V if T[i, j] != 0] classes = strongly_connected_components((V, E)) # end Tarjan's algorithm recurrence = [] periods = [] for class_ in classes: # begin recurrent check (similar to self._check_trans_probs()) submatrix = T[class_, class_] # get the submatrix with those states is_recurrent = S.true rows = submatrix.tolist() for row in rows: if (sum(row) - 1) != 0: is_recurrent = S.false break recurrence.append(is_recurrent) # end recurrent check # begin breadth-first search non_tree_edge_values = set() visited = {class_[0]} newly_visited = {class_[0]} level = {class_[0]: 0} current_level = 0 done = False # imitate a do-while loop while not done: # runs at most len(class_) times done = len(visited) == len(class_) current_level += 1 # this loop and the while loop above run a combined len(class_) number of times. # so this triple nested loop runs through each of the n states once. for i in newly_visited: # the loop below runs len(class_) number of times # complexity is around about O(n * avg(len(class_))) newly_visited = {j for j in class_ if T[i, j] != 0} new_tree_edges = newly_visited.difference(visited) for j in new_tree_edges: level[j] = current_level new_non_tree_edges = newly_visited.intersection(visited) new_non_tree_edge_values = {level[i]-level[j]+1 for j in new_non_tree_edges} non_tree_edge_values = non_tree_edge_values.union(new_non_tree_edge_values) visited = visited.union(new_tree_edges) # igcd needs at least 2 arguments positive_ntev = {val_e for val_e in non_tree_edge_values if val_e > 0} if len(positive_ntev) == 0: periods.append(len(class_)) elif len(positive_ntev) == 1: periods.append(positive_ntev.pop()) else: periods.append(igcd(*positive_ntev)) # end breadth-first search # convert back to the user's state names classes = [[self._state_index[i] for i in class_] for class_ in classes] return sympify(list(zip(classes, recurrence, periods))) def fundamental_matrix(self): """ Each entry fundamental matrix can be interpreted as the expected number of times the chains is in state j if it started in state i. References ========== .. [1] https://lips.cs.princeton.edu/the-fundamental-matrix-of-a-finite-markov-chain/ """ _, _, _, Q = self.decompose() if Q.shape[0] > 0: # if non-ergodic I = eye(Q.shape[0]) if (I - Q).det() == 0: raise ValueError("The fundamental matrix doesn't exist.") return (I - Q).inv().as_immutable() else: # if ergodic P = self.transition_probabilities I = eye(P.shape[0]) w = self.fixed_row_vector() W = Matrix([list(w) for i in range(0, P.shape[0])]) if (I - P + W).det() == 0: raise ValueError("The fundamental matrix doesn't exist.") return (I - P + W).inv().as_immutable() def absorbing_probabilities(self): """ Computes the absorbing probabilities, i.e., the ij-th entry of the matrix denotes the probability of Markov chain being absorbed in state j starting from state i. """ _, _, R, _ = self.decompose() N = self.fundamental_matrix() if R is None or N is None: return None return N*R def absorbing_probabilites(self): SymPyDeprecationWarning( feature="absorbing_probabilites", useinstead="absorbing_probabilities", issue=20042, deprecated_since_version="1.7" ).warn() return self.absorbing_probabilities() def is_regular(self): tuples = self.communication_classes() if len(tuples) == 0: return S.false # not defined for a 0x0 matrix classes, _, periods = list(zip(*tuples)) return And(len(classes) == 1, periods[0] == 1) def is_ergodic(self): tuples = self.communication_classes() if len(tuples) == 0: return S.false # not defined for a 0x0 matrix classes, _, _ = list(zip(*tuples)) return S(len(classes) == 1) def is_absorbing_state(self, state): trans_probs = self.transition_probabilities if isinstance(trans_probs, ImmutableMatrix) and \ state < trans_probs.shape[0]: return S(trans_probs[state, state]) is S.One def is_absorbing_chain(self): states, A, B, C = self.decompose() r = A.shape[0] return And(r > 0, A == Identity(r).as_explicit()) def stationary_distribution(self, condition_set=False) -> tUnion[ImmutableMatrix, ConditionSet, Lambda]: """ The stationary distribution is any row vector, p, that solves p = pP, is row stochastic and each element in p must be nonnegative. That means in matrix form: :math:`(P-I)^T p^T = 0` and :math:`(1, ..., 1) p = 1` where ``P`` is the one-step transition matrix. All time-homogeneous Markov Chains with a finite state space have at least one stationary distribution. In addition, if a finite time-homogeneous Markov Chain is irreducible, the stationary distribution is unique. Parameters ========== condition_set : bool If the chain has a symbolic size or transition matrix, it will return a ``Lambda`` if ``False`` and return a ``ConditionSet`` if ``True``. Examples ======== >>> from sympy.stats import DiscreteMarkovChain >>> from sympy import Matrix, S An irreducible Markov Chain >>> T = Matrix([[S(1)/2, S(1)/2, 0], ... [S(4)/5, S(1)/5, 0], ... [1, 0, 0]]) >>> X = DiscreteMarkovChain('X', trans_probs=T) >>> X.stationary_distribution() Matrix([[8/13, 5/13, 0]]) A reducible Markov Chain >>> T = Matrix([[S(1)/2, S(1)/2, 0], ... [S(4)/5, S(1)/5, 0], ... [0, 0, 1]]) >>> X = DiscreteMarkovChain('X', trans_probs=T) >>> X.stationary_distribution() Matrix([[8/13 - 8*tau0/13, 5/13 - 5*tau0/13, tau0]]) >>> Y = DiscreteMarkovChain('Y') >>> Y.stationary_distribution() Lambda((wm, _T), Eq(wm*_T, wm)) >>> Y.stationary_distribution(condition_set=True) ConditionSet(wm, Eq(wm*_T, wm)) References ========== .. [1] https://www.probabilitycourse.com/chapter11/11_2_6_stationary_and_limiting_distributions.php .. [2] https://galton.uchicago.edu/~yibi/teaching/stat317/2014/Lectures/Lecture4_6up.pdf See Also ======== sympy.stats.DiscreteMarkovChain.limiting_distribution """ trans_probs = self.transition_probabilities n = self.number_of_states if n == 0: return ImmutableMatrix(Matrix([[]])) # symbolic matrix version if isinstance(trans_probs, MatrixSymbol): wm = MatrixSymbol('wm', 1, n) if condition_set: return ConditionSet(wm, Eq(wm * trans_probs, wm)) else: return Lambda((wm, trans_probs), Eq(wm * trans_probs, wm)) # numeric matrix version a = Matrix(trans_probs - Identity(n)).T a[0, 0:n] = ones(1, n) b = zeros(n, 1) b[0, 0] = 1 soln = list(linsolve((a, b)))[0] return ImmutableMatrix([[sol for sol in soln]]) def fixed_row_vector(self): """ A wrapper for ``stationary_distribution()``. """ return self.stationary_distribution() @property def limiting_distribution(self): """ The fixed row vector is the limiting distribution of a discrete Markov chain. """ return self.fixed_row_vector() def decompose(self) -> tTuple[tList[Basic], ImmutableMatrix, ImmutableMatrix, ImmutableMatrix]: """ Decomposes the transition matrix into submatrices with special properties. The transition matrix can be decomposed into 4 submatrices: - A - the submatrix from recurrent states to recurrent states. - B - the submatrix from transient to recurrent states. - C - the submatrix from transient to transient states. - O - the submatrix of zeros for recurrent to transient states. Returns ======= states, A, B, C ``states`` - a list of state names with the first being the recurrent states and the last being the transient states in the order of the row names of A and then the row names of C. ``A`` - the submatrix from recurrent states to recurrent states. ``B`` - the submatrix from transient to recurrent states. ``C`` - the submatrix from transient to transient states. Examples ======== >>> from sympy.stats import DiscreteMarkovChain >>> from sympy import Matrix, S One can decompose this chain for example: >>> T = Matrix([[S(1)/2, S(1)/2, 0, 0, 0], ... [S(2)/5, S(1)/5, S(2)/5, 0, 0], ... [0, 0, 1, 0, 0], ... [0, 0, S(1)/2, S(1)/2, 0], ... [S(1)/2, 0, 0, 0, S(1)/2]]) >>> X = DiscreteMarkovChain('X', trans_probs=T) >>> states, A, B, C = X.decompose() >>> states [2, 0, 1, 3, 4] >>> A # recurrent to recurrent Matrix([[1]]) >>> B # transient to recurrent Matrix([ [ 0], [2/5], [1/2], [ 0]]) >>> C # transient to transient Matrix([ [1/2, 1/2, 0, 0], [2/5, 1/5, 0, 0], [ 0, 0, 1/2, 0], [1/2, 0, 0, 1/2]]) This means that state 2 is the only absorbing state (since A is a 1x1 matrix). B is a 4x1 matrix since the 4 remaining transient states all merge into reccurent state 2. And C is the 4x4 matrix that shows how the transient states 0, 1, 3, 4 all interact. See Also ======== sympy.stats.DiscreteMarkovChain.communication_classes sympy.stats.DiscreteMarkovChain.canonical_form References ========== .. [1] https://en.wikipedia.org/wiki/Absorbing_Markov_chain .. [2] http://people.brandeis.edu/~igusa/Math56aS08/Math56a_S08_notes015.pdf """ trans_probs = self.transition_probabilities classes = self.communication_classes() r_states = [] t_states = [] for states, recurrent, period in classes: if recurrent: r_states += states else: t_states += states states = r_states + t_states indexes = [self.index_of[state] for state in states] A = Matrix(len(r_states), len(r_states), lambda i, j: trans_probs[indexes[i], indexes[j]]) B = Matrix(len(t_states), len(r_states), lambda i, j: trans_probs[indexes[len(r_states) + i], indexes[j]]) C = Matrix(len(t_states), len(t_states), lambda i, j: trans_probs[indexes[len(r_states) + i], indexes[len(r_states) + j]]) return states, A.as_immutable(), B.as_immutable(), C.as_immutable() def canonical_form(self) -> tTuple[tList[Basic], ImmutableMatrix]: """ Reorders the one-step transition matrix so that recurrent states appear first and transient states appear last. Other representations include inserting transient states first and recurrent states last. Returns ======= states, P_new ``states`` is the list that describes the order of the new states in the matrix so that the ith element in ``states`` is the state of the ith row of A. ``P_new`` is the new transition matrix in canonical form. Examples ======== >>> from sympy.stats import DiscreteMarkovChain >>> from sympy import Matrix, S You can convert your chain into canonical form: >>> T = Matrix([[S(1)/2, S(1)/2, 0, 0, 0], ... [S(2)/5, S(1)/5, S(2)/5, 0, 0], ... [0, 0, 1, 0, 0], ... [0, 0, S(1)/2, S(1)/2, 0], ... [S(1)/2, 0, 0, 0, S(1)/2]]) >>> X = DiscreteMarkovChain('X', list(range(1, 6)), trans_probs=T) >>> states, new_matrix = X.canonical_form() >>> states [3, 1, 2, 4, 5] >>> new_matrix Matrix([ [ 1, 0, 0, 0, 0], [ 0, 1/2, 1/2, 0, 0], [2/5, 2/5, 1/5, 0, 0], [1/2, 0, 0, 1/2, 0], [ 0, 1/2, 0, 0, 1/2]]) The new states are [3, 1, 2, 4, 5] and you can create a new chain with this and its canonical form will remain the same (since it is already in canonical form). >>> X = DiscreteMarkovChain('X', states, new_matrix) >>> states, new_matrix = X.canonical_form() >>> states [3, 1, 2, 4, 5] >>> new_matrix Matrix([ [ 1, 0, 0, 0, 0], [ 0, 1/2, 1/2, 0, 0], [2/5, 2/5, 1/5, 0, 0], [1/2, 0, 0, 1/2, 0], [ 0, 1/2, 0, 0, 1/2]]) This is not limited to absorbing chains: >>> T = Matrix([[0, 5, 5, 0, 0], ... [0, 0, 0, 10, 0], ... [5, 0, 5, 0, 0], ... [0, 10, 0, 0, 0], ... [0, 3, 0, 3, 4]])/10 >>> X = DiscreteMarkovChain('X', trans_probs=T) >>> states, new_matrix = X.canonical_form() >>> states [1, 3, 0, 2, 4] >>> new_matrix Matrix([ [ 0, 1, 0, 0, 0], [ 1, 0, 0, 0, 0], [ 1/2, 0, 0, 1/2, 0], [ 0, 0, 1/2, 1/2, 0], [3/10, 3/10, 0, 0, 2/5]]) See Also ======== sympy.stats.DiscreteMarkovChain.communication_classes sympy.stats.DiscreteMarkovChain.decompose References ========== .. [1] https://onlinelibrary.wiley.com/doi/pdf/10.1002/9780470316887.app1 .. [2] http://www.columbia.edu/~ww2040/6711F12/lect1023big.pdf """ states, A, B, C = self.decompose() O = zeros(A.shape[0], C.shape[1]) return states, BlockMatrix([[A, O], [B, C]]).as_explicit() def sample(self): """ Returns ======= sample: iterator object iterator object containing the sample """ if not isinstance(self.transition_probabilities, (Matrix, ImmutableMatrix)): raise ValueError("Transition Matrix must be provided for sampling") Tlist = self.transition_probabilities.tolist() samps = [random.choice(list(self.state_space))] yield samps[0] time = 1 densities = {} for state in self.state_space: states = list(self.state_space) densities[state] = {states[i]: Tlist[state][i] for i in range(len(states))} while time < S.Infinity: samps.append((next(sample_iter(FiniteRV("_", densities[samps[time - 1]]))))) yield samps[time] time += 1 class ContinuousMarkovChain(ContinuousTimeStochasticProcess, MarkovProcess): """ Represents continuous time Markov chain. Parameters ========== sym: Symbol/str state_space: Set Optional, by default, S.Reals gen_mat: Matrix/ImmutableMatrix/MatrixSymbol Optional, by default, None Examples ======== >>> from sympy.stats import ContinuousMarkovChain, P >>> from sympy import Matrix, S, Eq, Gt >>> G = Matrix([[-S(1), S(1)], [S(1), -S(1)]]) >>> C = ContinuousMarkovChain('C', state_space=[0, 1], gen_mat=G) >>> C.limiting_distribution() Matrix([[1/2, 1/2]]) >>> C.state_space {0, 1} >>> C.generator_matrix Matrix([ [-1, 1], [ 1, -1]]) Probability queries are supported >>> P(Eq(C(1.96), 0), Eq(C(0.78), 1)).round(5) 0.45279 >>> P(Gt(C(1.7), 0), Eq(C(0.82), 1)).round(5) 0.58602 Probability of expressions with multiple RandomIndexedSymbols can also be calculated provided there is only 1 RandomIndexedSymbol in the given condition. It is always better to use Rational instead of floating point numbers for the probabilities in the generator matrix to avoid errors. >>> from sympy import Gt, Le, Rational >>> G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]]) >>> C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G) >>> P(Eq(C(3.92), C(1.75)), Eq(C(0.46), 0)).round(5) 0.37933 >>> P(Gt(C(3.92), C(1.75)), Eq(C(0.46), 0)).round(5) 0.34211 >>> P(Le(C(1.57), C(3.14)), Eq(C(1.22), 1)).round(4) 0.7143 Symbolic probability queries are also supported >>> from sympy import S, symbols, Matrix, Rational, Eq, Gt >>> from sympy.stats import P, ContinuousMarkovChain >>> a,b,c,d = symbols('a b c d') >>> G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]]) >>> C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G) >>> query = P(Eq(C(a), b), Eq(C(c), d)) >>> query.subs({a:3.65 ,b:2, c:1.78, d:1}).evalf().round(10) 0.4002723175 >>> P(Eq(C(3.65), 2), Eq(C(1.78), 1)).round(10) 0.4002723175 >>> query_gt = P(Gt(C(a), b), Eq(C(c), d)) >>> query_gt.subs({a:43.2 ,b:0, c:3.29, d:2}).evalf().round(10) 0.6832579186 >>> P(Gt(C(43.2), 0), Eq(C(3.29), 2)).round(10) 0.6832579186 References ========== .. [1] https://en.wikipedia.org/wiki/Markov_chain#Continuous-time_Markov_chain .. [2] http://u.math.biu.ac.il/~amirgi/CTMCnotes.pdf """ index_set = S.Reals def __new__(cls, sym, state_space=None, gen_mat=None): sym = _symbol_converter(sym) state_space, gen_mat = MarkovProcess._sanity_checks(state_space, gen_mat) obj = Basic.__new__(cls, sym, state_space, gen_mat) indices = dict() if isinstance(obj.number_of_states, Integer): for index, state in enumerate(obj.state_space): indices[state] = index obj.index_of = indices return obj @property def generator_matrix(self): return self.args[2] @cacheit def transition_probabilities(self, gen_mat=None): t = Dummy('t') if isinstance(gen_mat, (Matrix, ImmutableMatrix)) and \ gen_mat.is_diagonalizable(): # for faster computation use diagonalized generator matrix Q, D = gen_mat.diagonalize() return Lambda(t, Q*exp(t*D)*Q.inv()) if gen_mat != None: return Lambda(t, exp(t*gen_mat)) def limiting_distribution(self): gen_mat = self.generator_matrix if gen_mat is None: return None if isinstance(gen_mat, MatrixSymbol): wm = MatrixSymbol('wm', 1, gen_mat.shape[0]) return Lambda((wm, gen_mat), Eq(wm*gen_mat, wm)) w = IndexedBase('w') wi = [w[i] for i in range(gen_mat.shape[0])] wm = Matrix([wi]) eqs = (wm*gen_mat).tolist()[0] eqs.append(sum(wi) - 1) soln = list(linsolve(eqs, wi))[0] return ImmutableMatrix([[sol for sol in soln]]) class BernoulliProcess(DiscreteTimeStochasticProcess): """ The Bernoulli process consists of repeated independent Bernoulli process trials with the same parameter `p`. It's assumed that the probability `p` applies to every trial and that the outcomes of each trial are independent of all the rest. Therefore Bernoulli Processs is Discrete State and Discrete Time Stochastic Process. Parameters ========== sym: Symbol/str success: Integer/str The event which is considered to be success, by default is 1. failure: Integer/str The event which is considered to be failure, by default is 0. p: Real Number between 0 and 1 Represents the probability of getting success. Examples ======== >>> from sympy.stats import BernoulliProcess, P, E >>> from sympy import Eq, Gt >>> B = BernoulliProcess("B", p=0.7, success=1, failure=0) >>> B.state_space {0, 1} >>> (B.p).round(2) 0.70 >>> B.success 1 >>> B.failure 0 >>> X = B[1] + B[2] + B[3] >>> P(Eq(X, 0)).round(2) 0.03 >>> P(Eq(X, 2)).round(2) 0.44 >>> P(Eq(X, 4)).round(2) 0 >>> P(Gt(X, 1)).round(2) 0.78 >>> P(Eq(B[1], 0) & Eq(B[2], 1) & Eq(B[3], 0) & Eq(B[4], 1)).round(2) 0.04 >>> B.joint_distribution(B[1], B[2]) JointDistributionHandmade(Lambda((B[1], B[2]), Piecewise((0.7, Eq(B[1], 1)), (0.3, Eq(B[1], 0)), (0, True))*Piecewise((0.7, Eq(B[2], 1)), (0.3, Eq(B[2], 0)), (0, True)))) >>> E(2*B[1] + B[2]).round(2) 2.10 >>> P(B[1] < 1).round(2) 0.30 References ========== .. [1] https://en.wikipedia.org/wiki/Bernoulli_process .. [2] https://mathcs.clarku.edu/~djoyce/ma217/bernoulli.pdf """ index_set = S.Naturals0 def __new__(cls, sym, p, success=1, failure=0): _value_check(p >= 0 and p <= 1, 'Value of p must be between 0 and 1.') sym = _symbol_converter(sym) p = _sympify(p) success = _sym_sympify(success) failure = _sym_sympify(failure) return Basic.__new__(cls, sym, p, success, failure) @property def symbol(self): return self.args[0] @property def p(self): return self.args[1] @property def success(self): return self.args[2] @property def failure(self): return self.args[3] @property def state_space(self): return _set_converter([self.success, self.failure]) def distribution(self, key=None): if key is None: self._deprecation_warn_distribution() return BernoulliDistribution(self.p) return BernoulliDistribution(self.p, self.success, self.failure) def simple_rv(self, rv): return Bernoulli(rv.name, p=self.p, succ=self.success, fail=self.failure) def expectation(self, expr, condition=None, evaluate=True, **kwargs): """ Computes expectation. Parameters ========== expr: RandomIndexedSymbol, Relational, Logic Condition for which expectation has to be computed. Must contain a RandomIndexedSymbol of the process. condition: Relational, Logic The given conditions under which computations should be done. Returns ======= Expectation of the RandomIndexedSymbol. """ return _SubstituteRV._expectation(expr, condition, evaluate, **kwargs) def probability(self, condition, given_condition=None, evaluate=True, **kwargs): """ Computes probability. Parameters ========== condition: Relational Condition for which probability has to be computed. Must contain a RandomIndexedSymbol of the process. given_condition: Relational/And The given conditions under which computations should be done. Returns ======= Probability of the condition. """ return _SubstituteRV._probability(condition, given_condition, evaluate, **kwargs) def density(self, x): return Piecewise((self.p, Eq(x, self.success)), (1 - self.p, Eq(x, self.failure)), (S.Zero, True)) class _SubstituteRV: """ Internal class to handle the queries of expectation and probability by substitution. """ @staticmethod def _rvindexed_subs(expr, condition=None): """ Substitutes the RandomIndexedSymbol with the RandomSymbol with same name, distribution and probability as RandomIndexedSymbol. Parameters ========== expr: RandomIndexedSymbol, Relational, Logic Condition for which expectation has to be computed. Must contain a RandomIndexedSymbol of the process. condition: Relational, Logic The given conditions under which computations should be done. """ rvs_expr = random_symbols(expr) if len(rvs_expr) != 0: swapdict_expr = {} for rv in rvs_expr: if isinstance(rv, RandomIndexedSymbol): newrv = rv.pspace.process.simple_rv(rv) # substitute with equivalent simple rv swapdict_expr[rv] = newrv expr = expr.subs(swapdict_expr) rvs_cond = random_symbols(condition) if len(rvs_cond)!=0: swapdict_cond = {} for rv in rvs_cond: if isinstance(rv, RandomIndexedSymbol): newrv = rv.pspace.process.simple_rv(rv) swapdict_cond[rv] = newrv condition = condition.subs(swapdict_cond) return expr, condition @classmethod def _expectation(self, expr, condition=None, evaluate=True, **kwargs): """ Internal method for computing expectation of indexed RV. Parameters ========== expr: RandomIndexedSymbol, Relational, Logic Condition for which expectation has to be computed. Must contain a RandomIndexedSymbol of the process. condition: Relational, Logic The given conditions under which computations should be done. Returns ======= Expectation of the RandomIndexedSymbol. """ new_expr, new_condition = self._rvindexed_subs(expr, condition) if not is_random(new_expr): return new_expr new_pspace = pspace(new_expr) if new_condition is not None: new_expr = given(new_expr, new_condition) if new_expr.is_Add: # As E is Linear return Add(*[new_pspace.compute_expectation( expr=arg, evaluate=evaluate, **kwargs) for arg in new_expr.args]) return new_pspace.compute_expectation( new_expr, evaluate=evaluate, **kwargs) @classmethod def _probability(self, condition, given_condition=None, evaluate=True, **kwargs): """ Internal method for computing probability of indexed RV Parameters ========== condition: Relational Condition for which probability has to be computed. Must contain a RandomIndexedSymbol of the process. given_condition: Relational/And The given conditions under which computations should be done. Returns ======= Probability of the condition. """ new_condition, new_givencondition = self._rvindexed_subs(condition, given_condition) if isinstance(new_givencondition, RandomSymbol): condrv = random_symbols(new_condition) if len(condrv) == 1 and condrv[0] == new_givencondition: return BernoulliDistribution(self._probability(new_condition), 0, 1) if any([dependent(rv, new_givencondition) for rv in condrv]): return Probability(new_condition, new_givencondition) else: return self._probability(new_condition) if new_givencondition is not None and \ not isinstance(new_givencondition, (Relational, Boolean)): raise ValueError("%s is not a relational or combination of relationals" % (new_givencondition)) if new_givencondition == False or new_condition == False: return S.Zero if new_condition == True: return S.One if not isinstance(new_condition, (Relational, Boolean)): raise ValueError("%s is not a relational or combination of relationals" % (new_condition)) if new_givencondition is not None: # If there is a condition # Recompute on new conditional expr return self._probability(given(new_condition, new_givencondition, **kwargs), **kwargs) result = pspace(new_condition).probability(new_condition, **kwargs) if evaluate and hasattr(result, 'doit'): return result.doit() else: return result def get_timerv_swaps(expr, condition): """ Finds the appropriate interval for each time stamp in expr by parsing the given condition and returns intervals for each timestamp and dictionary that maps variable time-stamped Random Indexed Symbol to its corresponding Random Indexed variable with fixed time stamp. Parameters ========== expr: Sympy Expression Expression containing Random Indexed Symbols with variable time stamps condition: Relational/Boolean Expression Expression containing time bounds of variable time stamps in expr Examples ======== >>> from sympy.stats.stochastic_process_types import get_timerv_swaps, PoissonProcess >>> from sympy import symbols, Contains, Interval >>> x, t, d = symbols('x t d', positive=True) >>> X = PoissonProcess("X", 3) >>> get_timerv_swaps(x*X(t), Contains(t, Interval.Lopen(0, 1))) ([Interval.Lopen(0, 1)], {X(t): X(1)}) >>> get_timerv_swaps((X(t)**2 + X(d)**2), Contains(t, Interval.Lopen(0, 1)) ... & Contains(d, Interval.Ropen(1, 4))) # doctest: +SKIP ([Interval.Ropen(1, 4), Interval.Lopen(0, 1)], {X(d): X(3), X(t): X(1)}) Returns ======= intervals: list List of Intervals/FiniteSet on which each time stamp is defined rv_swap: dict Dictionary mapping variable time Random Indexed Symbol to constant time Random Indexed Variable """ if not isinstance(condition, (Relational, Boolean)): raise ValueError("%s is not a relational or combination of relationals" % (condition)) expr_syms = list(expr.atoms(RandomIndexedSymbol)) if isinstance(condition, (And, Or)): given_cond_args = condition.args else: # single condition given_cond_args = (condition, ) rv_swap = {} intervals = [] for expr_sym in expr_syms: for arg in given_cond_args: if arg.has(expr_sym.key) and isinstance(expr_sym.key, Symbol): intv = _set_converter(arg.args[1]) diff_key = intv._sup - intv._inf if diff_key == oo: raise ValueError("%s should have finite bounds" % str(expr_sym.name)) elif diff_key == S.Zero: # has singleton set diff_key = intv._sup rv_swap[expr_sym] = expr_sym.subs({expr_sym.key: diff_key}) intervals.append(intv) return intervals, rv_swap class CountingProcess(ContinuousTimeStochasticProcess): """ This class handles the common methods of the Counting Processes such as Poisson, Wiener and Gamma Processes """ index_set = _set_converter(Interval(0, oo)) @property def symbol(self): return self.args[0] def expectation(self, expr, condition=None, evaluate=True, **kwargs): """ Computes expectation Parameters ========== expr: RandomIndexedSymbol, Relational, Logic Condition for which expectation has to be computed. Must contain a RandomIndexedSymbol of the process. condition: Relational, Boolean The given conditions under which computations should be done, i.e, the intervals on which each variable time stamp in expr is defined Returns ======= Expectation of the given expr """ if condition is not None: intervals, rv_swap = get_timerv_swaps(expr, condition) # they are independent when they have non-overlapping intervals if len(intervals) == 1 or all(Intersection(*intv_comb) == EmptySet for intv_comb in itertools.combinations(intervals, 2)): if expr.is_Add: return Add.fromiter(self.expectation(arg, condition) for arg in expr.args) expr = expr.subs(rv_swap) else: return Expectation(expr, condition) return _SubstituteRV._expectation(expr, evaluate=evaluate, **kwargs) def _solve_argwith_tworvs(self, arg): if arg.args[0].key >= arg.args[1].key or isinstance(arg, Eq): diff_key = abs(arg.args[0].key - arg.args[1].key) rv = arg.args[0] arg = arg.__class__(rv.pspace.process(diff_key), 0) else: diff_key = arg.args[1].key - arg.args[0].key rv = arg.args[1] arg = arg.__class__(rv.pspace.process(diff_key), 0) return arg def _solve_numerical(self, condition, given_condition=None): if isinstance(condition, And): args_list = list(condition.args) else: args_list = [condition] if given_condition is not None: if isinstance(given_condition, And): args_list.extend(list(given_condition.args)) else: args_list.extend([given_condition]) # sort the args based on timestamp to get the independent increments in # each segment using all the condition args as well as given_condition args args_list = sorted(args_list, key=lambda x: x.args[0].key) result = [] cond_args = list(condition.args) if isinstance(condition, And) else [condition] if args_list[0] in cond_args and not (is_random(args_list[0].args[0]) and is_random(args_list[0].args[1])): result.append(_SubstituteRV._probability(args_list[0])) if is_random(args_list[0].args[0]) and is_random(args_list[0].args[1]): arg = self._solve_argwith_tworvs(args_list[0]) result.append(_SubstituteRV._probability(arg)) for i in range(len(args_list) - 1): curr, nex = args_list[i], args_list[i + 1] diff_key = nex.args[0].key - curr.args[0].key working_set = curr.args[0].pspace.process.state_space if curr.args[1] > nex.args[1]: #impossible condition so return 0 result.append(0) break if isinstance(curr, Eq): working_set = Intersection(working_set, Interval.Lopen(curr.args[1], oo)) else: working_set = Intersection(working_set, curr.as_set()) if isinstance(nex, Eq): working_set = Intersection(working_set, Interval(-oo, nex.args[1])) else: working_set = Intersection(working_set, nex.as_set()) if working_set == EmptySet: rv = Eq(curr.args[0].pspace.process(diff_key), 0) result.append(_SubstituteRV._probability(rv)) else: if working_set.is_finite_set: if isinstance(curr, Eq) and isinstance(nex, Eq): rv = Eq(curr.args[0].pspace.process(diff_key), len(working_set)) result.append(_SubstituteRV._probability(rv)) elif isinstance(curr, Eq) ^ isinstance(nex, Eq): result.append(Add.fromiter(_SubstituteRV._probability(Eq( curr.args[0].pspace.process(diff_key), x)) for x in range(len(working_set)))) else: n = len(working_set) result.append(Add.fromiter((n - x)*_SubstituteRV._probability(Eq( curr.args[0].pspace.process(diff_key), x)) for x in range(n))) else: result.append(_SubstituteRV._probability( curr.args[0].pspace.process(diff_key) <= working_set._sup - working_set._inf)) return Mul.fromiter(result) def probability(self, condition, given_condition=None, evaluate=True, **kwargs): """ Computes probability. Parameters ========== condition: Relational Condition for which probability has to be computed. Must contain a RandomIndexedSymbol of the process. given_condition: Relational, Boolean The given conditions under which computations should be done, i.e, the intervals on which each variable time stamp in expr is defined Returns ======= Probability of the condition """ check_numeric = True if isinstance(condition, (And, Or)): cond_args = condition.args else: cond_args = (condition, ) # check that condition args are numeric or not if not all(arg.args[0].key.is_number for arg in cond_args): check_numeric = False if given_condition is not None: check_given_numeric = True if isinstance(given_condition, (And, Or)): given_cond_args = given_condition.args else: given_cond_args = (given_condition, ) # check that given condition args are numeric or not if given_condition.has(Contains): check_given_numeric = False # Handle numerical queries if check_numeric and check_given_numeric: res = [] if isinstance(condition, Or): res.append(Add.fromiter(self._solve_numerical(arg, given_condition) for arg in condition.args)) if isinstance(given_condition, Or): res.append(Add.fromiter(self._solve_numerical(condition, arg) for arg in given_condition.args)) if res: return Add.fromiter(res) return self._solve_numerical(condition, given_condition) # No numeric queries, go by Contains?... then check that all the # given condition are in form of `Contains` if not all(arg.has(Contains) for arg in given_cond_args): raise ValueError("If given condition is passed with `Contains`, then " "please pass the evaluated condition with its corresponding information " "in terms of intervals of each time stamp to be passed in given condition.") intervals, rv_swap = get_timerv_swaps(condition, given_condition) # they are independent when they have non-overlapping intervals if len(intervals) == 1 or all(Intersection(*intv_comb) == EmptySet for intv_comb in itertools.combinations(intervals, 2)): if isinstance(condition, And): return Mul.fromiter(self.probability(arg, given_condition) for arg in condition.args) elif isinstance(condition, Or): return Add.fromiter(self.probability(arg, given_condition) for arg in condition.args) condition = condition.subs(rv_swap) else: return Probability(condition, given_condition) if check_numeric: return self._solve_numerical(condition) return _SubstituteRV._probability(condition, evaluate=evaluate, **kwargs) class PoissonProcess(CountingProcess): """ The Poisson process is a counting process. It is usually used in scenarios where we are counting the occurrences of certain events that appear to happen at a certain rate, but completely at random. Parameters ========== sym: Symbol/str lamda: Positive number Rate of the process, ``lamda > 0`` Examples ======== >>> from sympy.stats import PoissonProcess, P, E >>> from sympy import symbols, Eq, Ne, Contains, Interval >>> X = PoissonProcess("X", lamda=3) >>> X.state_space Naturals0 >>> X.lamda 3 >>> t1, t2 = symbols('t1 t2', positive=True) >>> P(X(t1) < 4) (9*t1**3/2 + 9*t1**2/2 + 3*t1 + 1)*exp(-3*t1) >>> P(Eq(X(t1), 2) | Ne(X(t1), 4), Contains(t1, Interval.Ropen(2, 4))) 1 - 36*exp(-6) >>> P(Eq(X(t1), 2) & Eq(X(t2), 3), Contains(t1, Interval.Lopen(0, 2)) ... & Contains(t2, Interval.Lopen(2, 4))) 648*exp(-12) >>> E(X(t1)) 3*t1 >>> E(X(t1)**2 + 2*X(t2), Contains(t1, Interval.Lopen(0, 1)) ... & Contains(t2, Interval.Lopen(1, 2))) 18 >>> P(X(3) < 1, Eq(X(1), 0)) exp(-6) >>> P(Eq(X(4), 3), Eq(X(2), 3)) exp(-6) >>> P(X(2) <= 3, X(1) > 1) 5*exp(-3) Merging two Poisson Processes >>> Y = PoissonProcess("Y", lamda=4) >>> Z = X + Y >>> Z.lamda 7 Splitting a Poisson Process into two independent Poisson Processes >>> N, M = Z.split(l1=2, l2=5) >>> N.lamda, M.lamda (2, 5) References ========== .. [1] https://www.probabilitycourse.com/chapter11/11_0_0_intro.php .. [2] https://en.wikipedia.org/wiki/Poisson_point_process """ def __new__(cls, sym, lamda): _value_check(lamda > 0, 'lamda should be a positive number.') sym = _symbol_converter(sym) lamda = _sympify(lamda) return Basic.__new__(cls, sym, lamda) @property def lamda(self): return self.args[1] @property def state_space(self): return S.Naturals0 def distribution(self, key): if isinstance(key, RandomIndexedSymbol): self._deprecation_warn_distribution() return PoissonDistribution(self.lamda*key.key) return PoissonDistribution(self.lamda*key) def density(self, x): return (self.lamda*x.key)**x / factorial(x) * exp(-(self.lamda*x.key)) def simple_rv(self, rv): return Poisson(rv.name, lamda=self.lamda*rv.key) def __add__(self, other): if not isinstance(other, PoissonProcess): raise ValueError("Only instances of Poisson Process can be merged") return PoissonProcess(Dummy(self.symbol.name + other.symbol.name), self.lamda + other.lamda) def split(self, l1, l2): if _sympify(l1 + l2) != self.lamda: raise ValueError("Sum of l1 and l2 should be %s" % str(self.lamda)) return PoissonProcess(Dummy("l1"), l1), PoissonProcess(Dummy("l2"), l2) class WienerProcess(CountingProcess): """ The Wiener process is a real valued continuous-time stochastic process. In physics it is used to study Brownian motion and therefore also known as Brownian Motion. Parameters ========== sym: Symbol/str Examples ======== >>> from sympy.stats import WienerProcess, P, E >>> from sympy import symbols, Contains, Interval >>> X = WienerProcess("X") >>> X.state_space Reals >>> t1, t2 = symbols('t1 t2', positive=True) >>> P(X(t1) < 7).simplify() erf(7*sqrt(2)/(2*sqrt(t1)))/2 + 1/2 >>> P((X(t1) > 2) | (X(t1) < 4), Contains(t1, Interval.Ropen(2, 4))).simplify() -erf(1)/2 + erf(2)/2 + 1 >>> E(X(t1)) 0 >>> E(X(t1) + 2*X(t2), Contains(t1, Interval.Lopen(0, 1)) ... & Contains(t2, Interval.Lopen(1, 2))) 0 References ========== .. [1] https://www.probabilitycourse.com/chapter11/11_4_0_brownian_motion_wiener_process.php .. [2] https://en.wikipedia.org/wiki/Wiener_process """ def __new__(cls, sym): sym = _symbol_converter(sym) return Basic.__new__(cls, sym) @property def state_space(self): return S.Reals def distribution(self, key): if isinstance(key, RandomIndexedSymbol): self._deprecation_warn_distribution() return NormalDistribution(0, sqrt(key.key)) return NormalDistribution(0, sqrt(key)) def density(self, x): return exp(-x**2/(2*x.key)) / (sqrt(2*pi)*sqrt(x.key)) def simple_rv(self, rv): return Normal(rv.name, 0, sqrt(rv.key)) class GammaProcess(CountingProcess): """ A Gamma process is a random process with independent gamma distributed increments. It is a pure-jump increasing Levy process. Parameters ========== sym: Symbol/str lamda: Positive number Jump size of the process, ``lamda > 0`` gamma: Positive number Rate of jump arrivals, ``gamma > 0`` Examples ======== >>> from sympy.stats import GammaProcess, E, P, variance >>> from sympy import symbols, Contains, Interval, Not >>> t, d, x, l, g = symbols('t d x l g', positive=True) >>> X = GammaProcess("X", l, g) >>> E(X(t)) g*t/l >>> variance(X(t)).simplify() g*t/l**2 >>> X = GammaProcess('X', 1, 2) >>> P(X(t) < 1).simplify() lowergamma(2*t, 1)/gamma(2*t) >>> P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & ... Contains(d, Interval.Lopen(7, 8))).simplify() -4*exp(-3) + 472*exp(-8)/3 + 1 >>> E(X(2) + x*E(X(5))) 10*x + 4 References ========== .. [1] https://en.wikipedia.org/wiki/Gamma_process """ def __new__(cls, sym, lamda, gamma): _value_check(lamda > 0, 'lamda should be a positive number') _value_check(gamma > 0, 'gamma should be a positive number') sym = _symbol_converter(sym) gamma = _sympify(gamma) lamda = _sympify(lamda) return Basic.__new__(cls, sym, lamda, gamma) @property def lamda(self): return self.args[1] @property def gamma(self): return self.args[2] @property def state_space(self): return _set_converter(Interval(0, oo)) def distribution(self, key): if isinstance(key, RandomIndexedSymbol): self._deprecation_warn_distribution() return GammaDistribution(self.gamma*key.key, 1/self.lamda) return GammaDistribution(self.gamma*key, 1/self.lamda) def density(self, x): k = self.gamma*x.key theta = 1/self.lamda return x**(k - 1) * exp(-x/theta) / (gamma(k)*theta**k) def simple_rv(self, rv): return Gamma(rv.name, self.gamma*rv.key, 1/self.lamda) sympy-sympy-1.9/sympy/stats/symbolic_multivariate_probability.py000066400000000000000000000237031412543434000256300ustar00rootroot00000000000000import itertools from sympy import (MatrixExpr, Expr, ShapeError, ZeroMatrix, Add, Mul, MatMul, S, expand as _expand) from sympy.stats.rv import RandomSymbol, is_random from sympy.core.sympify import _sympify from sympy.stats.symbolic_probability import Variance, Covariance, Expectation class ExpectationMatrix(Expectation, MatrixExpr): """ Expectation of a random matrix expression. Examples ======== >>> from sympy.stats import ExpectationMatrix, Normal >>> from sympy.stats.rv import RandomMatrixSymbol >>> from sympy import symbols, MatrixSymbol, Matrix >>> k = symbols("k") >>> A, B = MatrixSymbol("A", k, k), MatrixSymbol("B", k, k) >>> X, Y = RandomMatrixSymbol("X", k, 1), RandomMatrixSymbol("Y", k, 1) >>> ExpectationMatrix(X) ExpectationMatrix(X) >>> ExpectationMatrix(A*X).shape (k, 1) To expand the expectation in its expression, use ``expand()``: >>> ExpectationMatrix(A*X + B*Y).expand() A*ExpectationMatrix(X) + B*ExpectationMatrix(Y) >>> ExpectationMatrix((X + Y)*(X - Y).T).expand() ExpectationMatrix(X*X.T) - ExpectationMatrix(X*Y.T) + ExpectationMatrix(Y*X.T) - ExpectationMatrix(Y*Y.T) To evaluate the ``ExpectationMatrix``, use ``doit()``: >>> N11, N12 = Normal('N11', 11, 1), Normal('N12', 12, 1) >>> N21, N22 = Normal('N21', 21, 1), Normal('N22', 22, 1) >>> M11, M12 = Normal('M11', 1, 1), Normal('M12', 2, 1) >>> M21, M22 = Normal('M21', 3, 1), Normal('M22', 4, 1) >>> x1 = Matrix([[N11, N12], [N21, N22]]) >>> x2 = Matrix([[M11, M12], [M21, M22]]) >>> ExpectationMatrix(x1 + x2).doit() Matrix([ [12, 14], [24, 26]]) """ def __new__(cls, expr, condition=None): expr = _sympify(expr) if condition is None: if not is_random(expr): return expr obj = Expr.__new__(cls, expr) else: condition = _sympify(condition) obj = Expr.__new__(cls, expr, condition) obj._shape = expr.shape obj._condition = condition return obj @property def shape(self): return self._shape def expand(self, **hints): expr = self.args[0] condition = self._condition if not is_random(expr): return expr if isinstance(expr, Add): return Add.fromiter(Expectation(a, condition=condition).expand() for a in expr.args) expand_expr = _expand(expr) if isinstance(expand_expr, Add): return Add.fromiter(Expectation(a, condition=condition).expand() for a in expand_expr.args) elif isinstance(expr, (Mul, MatMul)): rv = [] nonrv = [] postnon = [] for a in expr.args: if is_random(a): if rv: rv.extend(postnon) else: nonrv.extend(postnon) postnon = [] rv.append(a) elif a.is_Matrix: postnon.append(a) else: nonrv.append(a) # In order to avoid infinite-looping (MatMul may call .doit() again), # do not rebuild if len(nonrv) == 0: return self return Mul.fromiter(nonrv)*Expectation(Mul.fromiter(rv), condition=condition)*Mul.fromiter(postnon) return self class VarianceMatrix(Variance, MatrixExpr): """ Variance of a random matrix probability expression. Also known as Covariance matrix, auto-covariance matrix, dispersion matrix, or variance-covariance matrix. Examples ======== >>> from sympy.stats import VarianceMatrix >>> from sympy.stats.rv import RandomMatrixSymbol >>> from sympy import symbols, MatrixSymbol >>> k = symbols("k") >>> A, B = MatrixSymbol("A", k, k), MatrixSymbol("B", k, k) >>> X, Y = RandomMatrixSymbol("X", k, 1), RandomMatrixSymbol("Y", k, 1) >>> VarianceMatrix(X) VarianceMatrix(X) >>> VarianceMatrix(X).shape (k, k) To expand the variance in its expression, use ``expand()``: >>> VarianceMatrix(A*X).expand() A*VarianceMatrix(X)*A.T >>> VarianceMatrix(A*X + B*Y).expand() 2*A*CrossCovarianceMatrix(X, Y)*B.T + A*VarianceMatrix(X)*A.T + B*VarianceMatrix(Y)*B.T """ def __new__(cls, arg, condition=None): arg = _sympify(arg) if 1 not in arg.shape: raise ShapeError("Expression is not a vector") shape = (arg.shape[0], arg.shape[0]) if arg.shape[1] == 1 else (arg.shape[1], arg.shape[1]) if condition: obj = Expr.__new__(cls, arg, condition) else: obj = Expr.__new__(cls, arg) obj._shape = shape obj._condition = condition return obj @property def shape(self): return self._shape def expand(self, **hints): arg = self.args[0] condition = self._condition if not is_random(arg): return ZeroMatrix(*self.shape) if isinstance(arg, RandomSymbol): return self elif isinstance(arg, Add): rv = [] for a in arg.args: if is_random(a): rv.append(a) variances = Add(*map(lambda xv: Variance(xv, condition).expand(), rv)) map_to_covar = lambda x: 2*Covariance(*x, condition=condition).expand() covariances = Add(*map(map_to_covar, itertools.combinations(rv, 2))) return variances + covariances elif isinstance(arg, (Mul, MatMul)): nonrv = [] rv = [] for a in arg.args: if is_random(a): rv.append(a) else: nonrv.append(a) if len(rv) == 0: return ZeroMatrix(*self.shape) # Avoid possible infinite loops with MatMul: if len(nonrv) == 0: return self # Variance of many multiple matrix products is not implemented: if len(rv) > 1: return self return Mul.fromiter(nonrv)*Variance(Mul.fromiter(rv), condition)*(Mul.fromiter(nonrv)).transpose() # this expression contains a RandomSymbol somehow: return self class CrossCovarianceMatrix(Covariance, MatrixExpr): """ Covariance of a random matrix probability expression. Examples ======== >>> from sympy.stats import CrossCovarianceMatrix >>> from sympy.stats.rv import RandomMatrixSymbol >>> from sympy import symbols, MatrixSymbol >>> k = symbols("k") >>> A, B = MatrixSymbol("A", k, k), MatrixSymbol("B", k, k) >>> C, D = MatrixSymbol("C", k, k), MatrixSymbol("D", k, k) >>> X, Y = RandomMatrixSymbol("X", k, 1), RandomMatrixSymbol("Y", k, 1) >>> Z, W = RandomMatrixSymbol("Z", k, 1), RandomMatrixSymbol("W", k, 1) >>> CrossCovarianceMatrix(X, Y) CrossCovarianceMatrix(X, Y) >>> CrossCovarianceMatrix(X, Y).shape (k, k) To expand the covariance in its expression, use ``expand()``: >>> CrossCovarianceMatrix(X + Y, Z).expand() CrossCovarianceMatrix(X, Z) + CrossCovarianceMatrix(Y, Z) >>> CrossCovarianceMatrix(A*X , Y).expand() A*CrossCovarianceMatrix(X, Y) >>> CrossCovarianceMatrix(A*X, B.T*Y).expand() A*CrossCovarianceMatrix(X, Y)*B >>> CrossCovarianceMatrix(A*X + B*Y, C.T*Z + D.T*W).expand() A*CrossCovarianceMatrix(X, W)*D + A*CrossCovarianceMatrix(X, Z)*C + B*CrossCovarianceMatrix(Y, W)*D + B*CrossCovarianceMatrix(Y, Z)*C """ def __new__(cls, arg1, arg2, condition=None): arg1 = _sympify(arg1) arg2 = _sympify(arg2) if (1 not in arg1.shape) or (1 not in arg2.shape) or (arg1.shape[1] != arg2.shape[1]): raise ShapeError("Expression is not a vector") shape = (arg1.shape[0], arg2.shape[0]) if arg1.shape[1] == 1 and arg2.shape[1] == 1 \ else (1, 1) if condition: obj = Expr.__new__(cls, arg1, arg2, condition) else: obj = Expr.__new__(cls, arg1, arg2) obj._shape = shape obj._condition = condition return obj @property def shape(self): return self._shape def expand(self, **hints): arg1 = self.args[0] arg2 = self.args[1] condition = self._condition if arg1 == arg2: return VarianceMatrix(arg1, condition).expand() if not is_random(arg1) or not is_random(arg2): return ZeroMatrix(*self.shape) if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): return CrossCovarianceMatrix(arg1, arg2, condition) coeff_rv_list1 = self._expand_single_argument(arg1.expand()) coeff_rv_list2 = self._expand_single_argument(arg2.expand()) addends = [a*CrossCovarianceMatrix(r1, r2, condition=condition)*b.transpose() for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2] return Add.fromiter(addends) @classmethod def _expand_single_argument(cls, expr): # return (coefficient, random_symbol) pairs: if isinstance(expr, RandomSymbol): return [(S.One, expr)] elif isinstance(expr, Add): outval = [] for a in expr.args: if isinstance(a, (Mul, MatMul)): outval.append(cls._get_mul_nonrv_rv_tuple(a)) elif is_random(a): outval.append((S.One, a)) return outval elif isinstance(expr, (Mul, MatMul)): return [cls._get_mul_nonrv_rv_tuple(expr)] elif is_random(expr): return [(S.One, expr)] @classmethod def _get_mul_nonrv_rv_tuple(cls, m): rv = [] nonrv = [] for a in m.args: if is_random(a): rv.append(a) else: nonrv.append(a) return (Mul.fromiter(nonrv), Mul.fromiter(rv)) sympy-sympy-1.9/sympy/stats/symbolic_probability.py000066400000000000000000000544021412543434000230420ustar00rootroot00000000000000import itertools from sympy import (Expr, Add, Mul, S, Integral, Eq, Sum, Symbol, expand as _expand, Not) from sympy.core.compatibility import default_sort_key from sympy.core.parameters import global_parameters from sympy.core.sympify import _sympify from sympy.core.relational import Relational from sympy.logic.boolalg import Boolean from sympy.stats import variance, covariance from sympy.stats.rv import (RandomSymbol, pspace, dependent, given, sampling_E, RandomIndexedSymbol, is_random, PSpace, sampling_P, random_symbols) __all__ = ['Probability', 'Expectation', 'Variance', 'Covariance'] @is_random.register(Expr) def _(x): atoms = x.free_symbols if len(atoms) == 1 and next(iter(atoms)) == x: return False return any([is_random(i) for i in atoms]) @is_random.register(RandomSymbol) # type: ignore def _(x): return True class Probability(Expr): """ Symbolic expression for the probability. Examples ======== >>> from sympy.stats import Probability, Normal >>> from sympy import Integral >>> X = Normal("X", 0, 1) >>> prob = Probability(X > 1) >>> prob Probability(X > 1) Integral representation: >>> prob.rewrite(Integral) Integral(sqrt(2)*exp(-_z**2/2)/(2*sqrt(pi)), (_z, 1, oo)) Evaluation of the integral: >>> prob.evaluate_integral() sqrt(2)*(-sqrt(2)*sqrt(pi)*erf(sqrt(2)/2) + sqrt(2)*sqrt(pi))/(4*sqrt(pi)) """ def __new__(cls, prob, condition=None, **kwargs): prob = _sympify(prob) if condition is None: obj = Expr.__new__(cls, prob) else: condition = _sympify(condition) obj = Expr.__new__(cls, prob, condition) obj._condition = condition return obj def doit(self, **hints): condition = self.args[0] given_condition = self._condition numsamples = hints.get('numsamples', False) for_rewrite = not hints.get('for_rewrite', False) if isinstance(condition, Not): return S.One - self.func(condition.args[0], given_condition, evaluate=for_rewrite).doit(**hints) if condition.has(RandomIndexedSymbol): return pspace(condition).probability(condition, given_condition, evaluate=for_rewrite) if isinstance(given_condition, RandomSymbol): condrv = random_symbols(condition) if len(condrv) == 1 and condrv[0] == given_condition: from sympy.stats.frv_types import BernoulliDistribution return BernoulliDistribution(self.func(condition).doit(**hints), 0, 1) if any([dependent(rv, given_condition) for rv in condrv]): return Probability(condition, given_condition) else: return Probability(condition).doit() if given_condition is not None and \ not isinstance(given_condition, (Relational, Boolean)): raise ValueError("%s is not a relational or combination of relationals" % (given_condition)) if given_condition == False or condition is S.false: return S.Zero if not isinstance(condition, (Relational, Boolean)): raise ValueError("%s is not a relational or combination of relationals" % (condition)) if condition is S.true: return S.One if numsamples: return sampling_P(condition, given_condition, numsamples=numsamples) if given_condition is not None: # If there is a condition # Recompute on new conditional expr return Probability(given(condition, given_condition)).doit() # Otherwise pass work off to the ProbabilitySpace if pspace(condition) == PSpace(): return Probability(condition, given_condition) result = pspace(condition).probability(condition) if hasattr(result, 'doit') and for_rewrite: return result.doit() else: return result def _eval_rewrite_as_Integral(self, arg, condition=None, **kwargs): return self.func(arg, condition=condition).doit(for_rewrite=True) _eval_rewrite_as_Sum = _eval_rewrite_as_Integral def evaluate_integral(self): return self.rewrite(Integral).doit() class Expectation(Expr): """ Symbolic expression for the expectation. Examples ======== >>> from sympy.stats import Expectation, Normal, Probability, Poisson >>> from sympy import symbols, Integral, Sum >>> mu = symbols("mu") >>> sigma = symbols("sigma", positive=True) >>> X = Normal("X", mu, sigma) >>> Expectation(X) Expectation(X) >>> Expectation(X).evaluate_integral().simplify() mu To get the integral expression of the expectation: >>> Expectation(X).rewrite(Integral) Integral(sqrt(2)*X*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) The same integral expression, in more abstract terms: >>> Expectation(X).rewrite(Probability) Integral(x*Probability(Eq(X, x)), (x, -oo, oo)) To get the Summation expression of the expectation for discrete random variables: >>> lamda = symbols('lamda', positive=True) >>> Z = Poisson('Z', lamda) >>> Expectation(Z).rewrite(Sum) Sum(Z*lamda**Z*exp(-lamda)/factorial(Z), (Z, 0, oo)) This class is aware of some properties of the expectation: >>> from sympy.abc import a >>> Expectation(a*X) Expectation(a*X) >>> Y = Normal("Y", 1, 2) >>> Expectation(X + Y) Expectation(X + Y) To expand the ``Expectation`` into its expression, use ``expand()``: >>> Expectation(X + Y).expand() Expectation(X) + Expectation(Y) >>> Expectation(a*X + Y).expand() a*Expectation(X) + Expectation(Y) >>> Expectation(a*X + Y) Expectation(a*X + Y) >>> Expectation((X + Y)*(X - Y)).expand() Expectation(X**2) - Expectation(Y**2) To evaluate the ``Expectation``, use ``doit()``: >>> Expectation(X + Y).doit() mu + 1 >>> Expectation(X + Expectation(Y + Expectation(2*X))).doit() 3*mu + 1 To prevent evaluating nested ``Expectation``, use ``doit(deep=False)`` >>> Expectation(X + Expectation(Y)).doit(deep=False) mu + Expectation(Expectation(Y)) >>> Expectation(X + Expectation(Y + Expectation(2*X))).doit(deep=False) mu + Expectation(Expectation(Y + Expectation(2*X))) """ def __new__(cls, expr, condition=None, **kwargs): expr = _sympify(expr) if expr.is_Matrix: from sympy.stats.symbolic_multivariate_probability import ExpectationMatrix return ExpectationMatrix(expr, condition) if condition is None: if not is_random(expr): return expr obj = Expr.__new__(cls, expr) else: condition = _sympify(condition) obj = Expr.__new__(cls, expr, condition) obj._condition = condition return obj def expand(self, **hints): expr = self.args[0] condition = self._condition if not is_random(expr): return expr if isinstance(expr, Add): return Add.fromiter(Expectation(a, condition=condition).expand() for a in expr.args) expand_expr = _expand(expr) if isinstance(expand_expr, Add): return Add.fromiter(Expectation(a, condition=condition).expand() for a in expand_expr.args) elif isinstance(expr, Mul): rv = [] nonrv = [] for a in expr.args: if is_random(a): rv.append(a) else: nonrv.append(a) return Mul.fromiter(nonrv)*Expectation(Mul.fromiter(rv), condition=condition) return self def doit(self, **hints): deep = hints.get('deep', True) condition = self._condition expr = self.args[0] numsamples = hints.get('numsamples', False) for_rewrite = not hints.get('for_rewrite', False) if deep: expr = expr.doit(**hints) if not is_random(expr) or isinstance(expr, Expectation): # expr isn't random? return expr if numsamples: # Computing by monte carlo sampling? evalf = hints.get('evalf', True) return sampling_E(expr, condition, numsamples=numsamples, evalf=evalf) if expr.has(RandomIndexedSymbol): return pspace(expr).compute_expectation(expr, condition) # Create new expr and recompute E if condition is not None: # If there is a condition return self.func(given(expr, condition)).doit(**hints) # A few known statements for efficiency if expr.is_Add: # We know that E is Linear return Add(*[self.func(arg, condition).doit(**hints) if not isinstance(arg, Expectation) else self.func(arg, condition) for arg in expr.args]) if expr.is_Mul: if expr.atoms(Expectation): return expr if pspace(expr) == PSpace(): return self.func(expr) # Otherwise case is simple, pass work off to the ProbabilitySpace result = pspace(expr).compute_expectation(expr, evaluate=for_rewrite) if hasattr(result, 'doit') and for_rewrite: return result.doit(**hints) else: return result def _eval_rewrite_as_Probability(self, arg, condition=None, **kwargs): rvs = arg.atoms(RandomSymbol) if len(rvs) > 1: raise NotImplementedError() if len(rvs) == 0: return arg rv = rvs.pop() if rv.pspace is None: raise ValueError("Probability space not known") symbol = rv.symbol if symbol.name[0].isupper(): symbol = Symbol(symbol.name.lower()) else : symbol = Symbol(symbol.name + "_1") if rv.pspace.is_Continuous: return Integral(arg.replace(rv, symbol)*Probability(Eq(rv, symbol), condition), (symbol, rv.pspace.domain.set.inf, rv.pspace.domain.set.sup)) else: if rv.pspace.is_Finite: raise NotImplementedError else: return Sum(arg.replace(rv, symbol)*Probability(Eq(rv, symbol), condition), (symbol, rv.pspace.domain.set.inf, rv.pspace.set.sup)) def _eval_rewrite_as_Integral(self, arg, condition=None, **kwargs): return self.func(arg, condition=condition).doit(deep=False, for_rewrite=True) _eval_rewrite_as_Sum = _eval_rewrite_as_Integral # For discrete this will be Sum def evaluate_integral(self): return self.rewrite(Integral).doit() evaluate_sum = evaluate_integral class Variance(Expr): """ Symbolic expression for the variance. Examples ======== >>> from sympy import symbols, Integral >>> from sympy.stats import Normal, Expectation, Variance, Probability >>> mu = symbols("mu", positive=True) >>> sigma = symbols("sigma", positive=True) >>> X = Normal("X", mu, sigma) >>> Variance(X) Variance(X) >>> Variance(X).evaluate_integral() sigma**2 Integral representation of the underlying calculations: >>> Variance(X).rewrite(Integral) Integral(sqrt(2)*(X - Integral(sqrt(2)*X*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)))**2*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) Integral representation, without expanding the PDF: >>> Variance(X).rewrite(Probability) -Integral(x*Probability(Eq(X, x)), (x, -oo, oo))**2 + Integral(x**2*Probability(Eq(X, x)), (x, -oo, oo)) Rewrite the variance in terms of the expectation >>> Variance(X).rewrite(Expectation) -Expectation(X)**2 + Expectation(X**2) Some transformations based on the properties of the variance may happen: >>> from sympy.abc import a >>> Y = Normal("Y", 0, 1) >>> Variance(a*X) Variance(a*X) To expand the variance in its expression, use ``expand()``: >>> Variance(a*X).expand() a**2*Variance(X) >>> Variance(X + Y) Variance(X + Y) >>> Variance(X + Y).expand() 2*Covariance(X, Y) + Variance(X) + Variance(Y) """ def __new__(cls, arg, condition=None, **kwargs): arg = _sympify(arg) if arg.is_Matrix: from sympy.stats.symbolic_multivariate_probability import VarianceMatrix return VarianceMatrix(arg, condition) if condition is None: obj = Expr.__new__(cls, arg) else: condition = _sympify(condition) obj = Expr.__new__(cls, arg, condition) obj._condition = condition return obj def expand(self, **hints): arg = self.args[0] condition = self._condition if not is_random(arg): return S.Zero if isinstance(arg, RandomSymbol): return self elif isinstance(arg, Add): rv = [] for a in arg.args: if is_random(a): rv.append(a) variances = Add(*map(lambda xv: Variance(xv, condition).expand(), rv)) map_to_covar = lambda x: 2*Covariance(*x, condition=condition).expand() covariances = Add(*map(map_to_covar, itertools.combinations(rv, 2))) return variances + covariances elif isinstance(arg, Mul): nonrv = [] rv = [] for a in arg.args: if is_random(a): rv.append(a) else: nonrv.append(a**2) if len(rv) == 0: return S.Zero return Mul.fromiter(nonrv)*Variance(Mul.fromiter(rv), condition) # this expression contains a RandomSymbol somehow: return self def _eval_rewrite_as_Expectation(self, arg, condition=None, **kwargs): e1 = Expectation(arg**2, condition) e2 = Expectation(arg, condition)**2 return e1 - e2 def _eval_rewrite_as_Probability(self, arg, condition=None, **kwargs): return self.rewrite(Expectation).rewrite(Probability) def _eval_rewrite_as_Integral(self, arg, condition=None, **kwargs): return variance(self.args[0], self._condition, evaluate=False) _eval_rewrite_as_Sum = _eval_rewrite_as_Integral def evaluate_integral(self): return self.rewrite(Integral).doit() class Covariance(Expr): """ Symbolic expression for the covariance. Examples ======== >>> from sympy.stats import Covariance >>> from sympy.stats import Normal >>> X = Normal("X", 3, 2) >>> Y = Normal("Y", 0, 1) >>> Z = Normal("Z", 0, 1) >>> W = Normal("W", 0, 1) >>> cexpr = Covariance(X, Y) >>> cexpr Covariance(X, Y) Evaluate the covariance, `X` and `Y` are independent, therefore zero is the result: >>> cexpr.evaluate_integral() 0 Rewrite the covariance expression in terms of expectations: >>> from sympy.stats import Expectation >>> cexpr.rewrite(Expectation) Expectation(X*Y) - Expectation(X)*Expectation(Y) In order to expand the argument, use ``expand()``: >>> from sympy.abc import a, b, c, d >>> Covariance(a*X + b*Y, c*Z + d*W) Covariance(a*X + b*Y, c*Z + d*W) >>> Covariance(a*X + b*Y, c*Z + d*W).expand() a*c*Covariance(X, Z) + a*d*Covariance(W, X) + b*c*Covariance(Y, Z) + b*d*Covariance(W, Y) This class is aware of some properties of the covariance: >>> Covariance(X, X).expand() Variance(X) >>> Covariance(a*X, b*Y).expand() a*b*Covariance(X, Y) """ def __new__(cls, arg1, arg2, condition=None, **kwargs): arg1 = _sympify(arg1) arg2 = _sympify(arg2) if arg1.is_Matrix or arg2.is_Matrix: from sympy.stats.symbolic_multivariate_probability import CrossCovarianceMatrix return CrossCovarianceMatrix(arg1, arg2, condition) if kwargs.pop('evaluate', global_parameters.evaluate): arg1, arg2 = sorted([arg1, arg2], key=default_sort_key) if condition is None: obj = Expr.__new__(cls, arg1, arg2) else: condition = _sympify(condition) obj = Expr.__new__(cls, arg1, arg2, condition) obj._condition = condition return obj def expand(self, **hints): arg1 = self.args[0] arg2 = self.args[1] condition = self._condition if arg1 == arg2: return Variance(arg1, condition).expand() if not is_random(arg1): return S.Zero if not is_random(arg2): return S.Zero arg1, arg2 = sorted([arg1, arg2], key=default_sort_key) if isinstance(arg1, RandomSymbol) and isinstance(arg2, RandomSymbol): return Covariance(arg1, arg2, condition) coeff_rv_list1 = self._expand_single_argument(arg1.expand()) coeff_rv_list2 = self._expand_single_argument(arg2.expand()) addends = [a*b*Covariance(*sorted([r1, r2], key=default_sort_key), condition=condition) for (a, r1) in coeff_rv_list1 for (b, r2) in coeff_rv_list2] return Add.fromiter(addends) @classmethod def _expand_single_argument(cls, expr): # return (coefficient, random_symbol) pairs: if isinstance(expr, RandomSymbol): return [(S.One, expr)] elif isinstance(expr, Add): outval = [] for a in expr.args: if isinstance(a, Mul): outval.append(cls._get_mul_nonrv_rv_tuple(a)) elif is_random(a): outval.append((S.One, a)) return outval elif isinstance(expr, Mul): return [cls._get_mul_nonrv_rv_tuple(expr)] elif is_random(expr): return [(S.One, expr)] @classmethod def _get_mul_nonrv_rv_tuple(cls, m): rv = [] nonrv = [] for a in m.args: if is_random(a): rv.append(a) else: nonrv.append(a) return (Mul.fromiter(nonrv), Mul.fromiter(rv)) def _eval_rewrite_as_Expectation(self, arg1, arg2, condition=None, **kwargs): e1 = Expectation(arg1*arg2, condition) e2 = Expectation(arg1, condition)*Expectation(arg2, condition) return e1 - e2 def _eval_rewrite_as_Probability(self, arg1, arg2, condition=None, **kwargs): return self.rewrite(Expectation).rewrite(Probability) def _eval_rewrite_as_Integral(self, arg1, arg2, condition=None, **kwargs): return covariance(self.args[0], self.args[1], self._condition, evaluate=False) _eval_rewrite_as_Sum = _eval_rewrite_as_Integral def evaluate_integral(self): return self.rewrite(Integral).doit() class Moment(Expr): """ Symbolic class for Moment Examples ======== >>> from sympy import Symbol, Integral >>> from sympy.stats import Normal, Expectation, Probability, Moment >>> mu = Symbol('mu', real=True) >>> sigma = Symbol('sigma', real=True, positive=True) >>> X = Normal('X', mu, sigma) >>> M = Moment(X, 3, 1) To evaluate the result of Moment use `doit`: >>> M.doit() mu**3 - 3*mu**2 + 3*mu*sigma**2 + 3*mu - 3*sigma**2 - 1 Rewrite the Moment expression in terms of Expectation: >>> M.rewrite(Expectation) Expectation((X - 1)**3) Rewrite the Moment expression in terms of Probability: >>> M.rewrite(Probability) Integral((x - 1)**3*Probability(Eq(X, x)), (x, -oo, oo)) Rewrite the Moment expression in terms of Integral: >>> M.rewrite(Integral) Integral(sqrt(2)*(X - 1)**3*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) """ def __new__(cls, X, n, c=0, condition=None, **kwargs): X = _sympify(X) n = _sympify(n) c = _sympify(c) if condition is not None: condition = _sympify(condition) return super().__new__(cls, X, n, c, condition) else: return super().__new__(cls, X, n, c) def doit(self, **hints): return self.rewrite(Expectation).doit(**hints) def _eval_rewrite_as_Expectation(self, X, n, c=0, condition=None, **kwargs): return Expectation((X - c)**n, condition) def _eval_rewrite_as_Probability(self, X, n, c=0, condition=None, **kwargs): return self.rewrite(Expectation).rewrite(Probability) def _eval_rewrite_as_Integral(self, X, n, c=0, condition=None, **kwargs): return self.rewrite(Expectation).rewrite(Integral) class CentralMoment(Expr): """ Symbolic class Central Moment Examples ======== >>> from sympy import Symbol, Integral >>> from sympy.stats import Normal, Expectation, Probability, CentralMoment >>> mu = Symbol('mu', real=True) >>> sigma = Symbol('sigma', real=True, positive=True) >>> X = Normal('X', mu, sigma) >>> CM = CentralMoment(X, 4) To evaluate the result of CentralMoment use `doit`: >>> CM.doit().simplify() 3*sigma**4 Rewrite the CentralMoment expression in terms of Expectation: >>> CM.rewrite(Expectation) Expectation((X - Expectation(X))**4) Rewrite the CentralMoment expression in terms of Probability: >>> CM.rewrite(Probability) Integral((x - Integral(x*Probability(True), (x, -oo, oo)))**4*Probability(Eq(X, x)), (x, -oo, oo)) Rewrite the CentralMoment expression in terms of Integral: >>> CM.rewrite(Integral) Integral(sqrt(2)*(X - Integral(sqrt(2)*X*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)))**4*exp(-(X - mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (X, -oo, oo)) """ def __new__(cls, X, n, condition=None, **kwargs): X = _sympify(X) n = _sympify(n) if condition is not None: condition = _sympify(condition) return super().__new__(cls, X, n, condition) else: return super().__new__(cls, X, n) def doit(self, **hints): return self.rewrite(Expectation).doit(**hints) def _eval_rewrite_as_Expectation(self, X, n, condition=None, **kwargs): mu = Expectation(X, condition, **kwargs) return Moment(X, n, mu, condition, **kwargs).rewrite(Expectation) def _eval_rewrite_as_Probability(self, X, n, condition=None, **kwargs): return self.rewrite(Expectation).rewrite(Probability) def _eval_rewrite_as_Integral(self, X, n, condition=None, **kwargs): return self.rewrite(Expectation).rewrite(Integral) sympy-sympy-1.9/sympy/stats/tests/000077500000000000000000000000001412543434000174045ustar00rootroot00000000000000sympy-sympy-1.9/sympy/stats/tests/__init__.py000066400000000000000000000000001412543434000215030ustar00rootroot00000000000000sympy-sympy-1.9/sympy/stats/tests/test_compound_rv.py000066400000000000000000000126071412543434000233560ustar00rootroot00000000000000from sympy import (symbols, S, erf, sqrt, pi, exp, gamma, Interval, oo, beta, Eq, Piecewise, Integral, Abs, arg, Dummy, Sum, factorial) from sympy.stats import (Normal, P, E, density, Gamma, Poisson, Rayleigh, variance, Bernoulli, Beta, Uniform, cdf) from sympy.stats.compound_rv import CompoundDistribution, CompoundPSpace from sympy.stats.crv_types import NormalDistribution from sympy.stats.drv_types import PoissonDistribution from sympy.stats.frv_types import BernoulliDistribution from sympy.testing.pytest import raises, ignore_warnings from sympy.stats.joint_rv_types import MultivariateNormalDistribution x = symbols('x') def test_normal_CompoundDist(): X = Normal('X', 1, 2) Y = Normal('X', X, 4) assert density(Y)(x).simplify() == sqrt(10)*exp(-x**2/40 + x/20 - S(1)/40)/(20*sqrt(pi)) assert E(Y) == 1 # it is always equal to mean of X assert P(Y > 1) == S(1)/2 # as 1 is the mean assert P(Y > 5).simplify() == S(1)/2 - erf(sqrt(10)/5)/2 assert variance(Y) == variance(X) + 4**2 # 2**2 + 4**2 # https://math.stackexchange.com/questions/1484451/ # (Contains proof of E and variance computation) def test_poisson_CompoundDist(): k, t, y = symbols('k t y', positive=True, real=True) G = Gamma('G', k, t) D = Poisson('P', G) assert density(D)(y).simplify() == t**y*(t + 1)**(-k - y)*gamma(k + y)/(gamma(k)*gamma(y + 1)) # https://en.wikipedia.org/wiki/Negative_binomial_distribution#Gamma%E2%80%93Poisson_mixture assert E(D).simplify() == k*t # mean of NegativeBinomialDistribution def test_bernoulli_CompoundDist(): X = Beta('X', 1, 2) Y = Bernoulli('Y', X) assert density(Y).dict == {0: S(2)/3, 1: S(1)/3} assert E(Y) == P(Eq(Y, 1)) == S(1)/3 assert variance(Y) == S(2)/9 assert cdf(Y) == {0: S(2)/3, 1: 1} # test issue 8128 a = Bernoulli('a', S(1)/2) b = Bernoulli('b', a) assert density(b).dict == {0: S(1)/2, 1: S(1)/2} assert P(b > 0.5) == S(1)/2 X = Uniform('X', 0, 1) Y = Bernoulli('Y', X) assert E(Y) == S(1)/2 assert P(Eq(Y, 1)) == E(Y) def test_unevaluated_CompoundDist(): # these tests need to be removed once they work with evaluation as they are currently not # evaluated completely in sympy. R = Rayleigh('R', 4) X = Normal('X', 3, R) _k = Dummy('k') exprd = Piecewise((exp(S(3)/4 - x/4)/8, 2*Abs(arg(x - 3)) <= pi/2), (sqrt(2)*Integral(exp(-(_k**4 + 16*(x - 3)**2)/(32*_k**2)), (_k, 0, oo))/(32*sqrt(pi)), True)) assert (density(X)(x).simplify()).dummy_eq(exprd.simplify()) expre = Integral(_k*Integral(sqrt(2)*exp(-_k**2/32)*exp(-(_k - 3)**2/(2*_k**2) )/(32*sqrt(pi)), (_k, 0, oo)), (_k, -oo, oo)) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert E(X, evaluate=False).rewrite(Integral).dummy_eq(expre) X = Poisson('X', 1) Y = Poisson('Y', X) Z = Poisson('Z', Y) exprd = exp(-1)*Sum(exp(-Y)*Y**x*Sum(exp(-X)*X**Y/(factorial(X)*factorial(Y) ), (X, 0, oo)), (Y, 0, oo))/factorial(x) assert density(Z)(x).simplify() == exprd N = Normal('N', 1, 2) M = Normal('M', 3, 4) D = Normal('D', M, N) exprd = Integral(sqrt(2)*exp(-(_k - 1)**2/8)*Integral(exp(-(-_k + x )**2/(2*_k**2))*exp(-(_k - 3)**2/32)/(8*pi*_k) , (_k, -oo, oo))/(4*sqrt(pi)), (_k, -oo, oo)) assert density(D, evaluate=False)(x).dummy_eq(exprd) def test_Compound_Distribution(): X = Normal('X', 2, 4) N = NormalDistribution(X, 4) C = CompoundDistribution(N) assert C.is_Continuous assert C.set == Interval(-oo, oo) assert C.pdf(x, evaluate=True).simplify() == exp(-x**2/64 + x/16 - S(1)/16)/(8*sqrt(pi)) assert not isinstance(CompoundDistribution(NormalDistribution(2, 3)), CompoundDistribution) M = MultivariateNormalDistribution([1, 2], [[2, 1], [1, 2]]) raises(NotImplementedError, lambda: CompoundDistribution(M)) X = Beta('X', 2, 4) B = BernoulliDistribution(X, 1, 0) C = CompoundDistribution(B) assert C.is_Finite assert C.set == {0, 1} y = symbols('y', negative=False, integer=True) assert C.pdf(y, evaluate=True) == Piecewise((S(1)/(30*beta(2, 4)), Eq(y, 0)), (S(1)/(60*beta(2, 4)), Eq(y, 1)), (0, True)) k, t, z = symbols('k t z', positive=True, real=True) G = Gamma('G', k, t) X = PoissonDistribution(G) C = CompoundDistribution(X) assert C.is_Discrete assert C.set == S.Naturals0 assert C.pdf(z, evaluate=True).simplify() == t**z*(t + 1)**(-k - z)*gamma(k \ + z)/(gamma(k)*gamma(z + 1)) def test_compound_pspace(): X = Normal('X', 2, 4) Y = Normal('Y', 3, 6) assert not isinstance(Y.pspace, CompoundPSpace) N = NormalDistribution(1, 2) D = PoissonDistribution(3) B = BernoulliDistribution(0.2, 1, 0) pspace1 = CompoundPSpace('N', N) pspace2 = CompoundPSpace('D', D) pspace3 = CompoundPSpace('B', B) assert not isinstance(pspace1, CompoundPSpace) assert not isinstance(pspace2, CompoundPSpace) assert not isinstance(pspace3, CompoundPSpace) M = MultivariateNormalDistribution([1, 2], [[2, 1], [1, 2]]) raises(ValueError, lambda: CompoundPSpace('M', M)) Y = Normal('Y', X, 6) assert isinstance(Y.pspace, CompoundPSpace) assert Y.pspace.distribution == CompoundDistribution(NormalDistribution(X, 6)) assert Y.pspace.domain.set == Interval(-oo, oo) sympy-sympy-1.9/sympy/stats/tests/test_continuous_rv.py000066400000000000000000001527521412543434000237460ustar00rootroot00000000000000from sympy import E as e from sympy import (Symbol, Abs, exp, expint, S, pi, simplify, Interval, erf, erfc, Ne, EulerGamma, Eq, log, lowergamma, uppergamma, symbols, sqrt, And, gamma, beta, Piecewise, Integral, sin, cos, tan, atan, sinh, cosh, besseli, floor, expand_func, Rational, I, re, Lambda, asin, im, lambdify, hyper, diff, Or, Mul, sign, Dummy, Sum, factorial, binomial, erfi, besselj, besselk) from sympy.functions.special.error_functions import erfinv from sympy.functions.special.hyper import meijerg from sympy.sets.sets import FiniteSet, Complement, Intersection from sympy.stats import (P, E, where, density, variance, covariance, skewness, kurtosis, median, given, pspace, cdf, characteristic_function, moment_generating_function, ContinuousRV, Arcsin, Benini, Beta, BetaNoncentral, BetaPrime, Cauchy, Chi, ChiSquared, ChiNoncentral, Dagum, Erlang, ExGaussian, Exponential, ExponentialPower, FDistribution, FisherZ, Frechet, Gamma, GammaInverse, Gompertz, Gumbel, Kumaraswamy, Laplace, Levy, Logistic, LogCauchy, LogLogistic, LogitNormal, LogNormal, Maxwell, Moyal, Nakagami, Normal, GaussianInverse, Pareto, PowerFunction, QuadraticU, RaisedCosine, Rayleigh, Reciprocal, ShiftedGompertz, StudentT, Trapezoidal, Triangular, Uniform, UniformSum, VonMises, Weibull, coskewness, WignerSemicircle, Wald, correlation, moment, cmoment, smoment, quantile, Lomax, BoundedPareto) from sympy.stats.crv_types import NormalDistribution, ExponentialDistribution, ContinuousDistributionHandmade from sympy.stats.joint_rv_types import MultivariateLaplaceDistribution, MultivariateNormalDistribution from sympy.stats.crv import SingleContinuousPSpace, SingleContinuousDomain from sympy.stats.compound_rv import CompoundPSpace from sympy.stats.symbolic_probability import Probability from sympy.testing.pytest import raises, XFAIL, slow, ignore_warnings from sympy.testing.randtest import verify_numerically as tn oo = S.Infinity x, y, z = map(Symbol, 'xyz') def test_single_normal(): mu = Symbol('mu', real=True) sigma = Symbol('sigma', positive=True) X = Normal('x', 0, 1) Y = X*sigma + mu assert E(Y) == mu assert variance(Y) == sigma**2 pdf = density(Y) x = Symbol('x', real=True) assert (pdf(x) == 2**S.Half*exp(-(x - mu)**2/(2*sigma**2))/(2*pi**S.Half*sigma)) assert P(X**2 < 1) == erf(2**S.Half/2) ans = quantile(Y)(x) assert ans == Complement(Intersection(FiniteSet( sqrt(2)*sigma*(sqrt(2)*mu/(2*sigma)+ erfinv(2*x - 1))), Interval(-oo, oo)), FiniteSet(mu)) assert E(X, Eq(X, mu)) == mu assert median(X) == FiniteSet(0) # issue 8248 assert X.pspace.compute_expectation(1).doit() == 1 def test_conditional_1d(): X = Normal('x', 0, 1) Y = given(X, X >= 0) z = Symbol('z') assert density(Y)(z) == 2 * density(X)(z) assert Y.pspace.domain.set == Interval(0, oo) assert E(Y) == sqrt(2) / sqrt(pi) assert E(X**2) == E(Y**2) def test_ContinuousDomain(): X = Normal('x', 0, 1) assert where(X**2 <= 1).set == Interval(-1, 1) assert where(X**2 <= 1).symbol == X.symbol where(And(X**2 <= 1, X >= 0)).set == Interval(0, 1) raises(ValueError, lambda: where(sin(X) > 1)) Y = given(X, X >= 0) assert Y.pspace.domain.set == Interval(0, oo) @slow def test_multiple_normal(): X, Y = Normal('x', 0, 1), Normal('y', 0, 1) p = Symbol("p", positive=True) assert E(X + Y) == 0 assert variance(X + Y) == 2 assert variance(X + X) == 4 assert covariance(X, Y) == 0 assert covariance(2*X + Y, -X) == -2*variance(X) assert skewness(X) == 0 assert skewness(X + Y) == 0 assert kurtosis(X) == 3 assert kurtosis(X+Y) == 3 assert correlation(X, Y) == 0 assert correlation(X, X + Y) == correlation(X, X - Y) assert moment(X, 2) == 1 assert cmoment(X, 3) == 0 assert moment(X + Y, 4) == 12 assert cmoment(X, 2) == variance(X) assert smoment(X*X, 2) == 1 assert smoment(X + Y, 3) == skewness(X + Y) assert smoment(X + Y, 4) == kurtosis(X + Y) assert E(X, Eq(X + Y, 0)) == 0 assert variance(X, Eq(X + Y, 0)) == S.Half assert quantile(X)(p) == sqrt(2)*erfinv(2*p - S.One) def test_symbolic(): mu1, mu2 = symbols('mu1 mu2', real=True) s1, s2 = symbols('sigma1 sigma2', positive=True) rate = Symbol('lambda', positive=True) X = Normal('x', mu1, s1) Y = Normal('y', mu2, s2) Z = Exponential('z', rate) a, b, c = symbols('a b c', real=True) assert E(X) == mu1 assert E(X + Y) == mu1 + mu2 assert E(a*X + b) == a*E(X) + b assert variance(X) == s1**2 assert variance(X + a*Y + b) == variance(X) + a**2*variance(Y) assert E(Z) == 1/rate assert E(a*Z + b) == a*E(Z) + b assert E(X + a*Z + b) == mu1 + a/rate + b assert median(X) == FiniteSet(mu1) def test_cdf(): X = Normal('x', 0, 1) d = cdf(X) assert P(X < 1) == d(1).rewrite(erfc) assert d(0) == S.Half d = cdf(X, X > 0) # given X>0 assert d(0) == 0 Y = Exponential('y', 10) d = cdf(Y) assert d(-5) == 0 assert P(Y > 3) == 1 - d(3) raises(ValueError, lambda: cdf(X + Y)) Z = Exponential('z', 1) f = cdf(Z) assert f(z) == Piecewise((1 - exp(-z), z >= 0), (0, True)) def test_characteristic_function(): X = Uniform('x', 0, 1) cf = characteristic_function(X) assert cf(1) == -I*(-1 + exp(I)) Y = Normal('y', 1, 1) cf = characteristic_function(Y) assert cf(0) == 1 assert cf(1) == exp(I - S.Half) Z = Exponential('z', 5) cf = characteristic_function(Z) assert cf(0) == 1 assert cf(1).expand() == Rational(25, 26) + I*Rational(5, 26) X = GaussianInverse('x', 1, 1) cf = characteristic_function(X) assert cf(0) == 1 assert cf(1) == exp(1 - sqrt(1 - 2*I)) X = ExGaussian('x', 0, 1, 1) cf = characteristic_function(X) assert cf(0) == 1 assert cf(1) == (1 + I)*exp(Rational(-1, 2))/2 L = Levy('x', 0, 1) cf = characteristic_function(L) assert cf(0) == 1 assert cf(1) == exp(-sqrt(2)*sqrt(-I)) def test_moment_generating_function(): t = symbols('t', positive=True) # Symbolic tests a, b, c = symbols('a b c') mgf = moment_generating_function(Beta('x', a, b))(t) assert mgf == hyper((a,), (a + b,), t) mgf = moment_generating_function(Chi('x', a))(t) assert mgf == sqrt(2)*t*gamma(a/2 + S.Half)*\ hyper((a/2 + S.Half,), (Rational(3, 2),), t**2/2)/gamma(a/2) +\ hyper((a/2,), (S.Half,), t**2/2) mgf = moment_generating_function(ChiSquared('x', a))(t) assert mgf == (1 - 2*t)**(-a/2) mgf = moment_generating_function(Erlang('x', a, b))(t) assert mgf == (1 - t/b)**(-a) mgf = moment_generating_function(ExGaussian("x", a, b, c))(t) assert mgf == exp(a*t + b**2*t**2/2)/(1 - t/c) mgf = moment_generating_function(Exponential('x', a))(t) assert mgf == a/(a - t) mgf = moment_generating_function(Gamma('x', a, b))(t) assert mgf == (-b*t + 1)**(-a) mgf = moment_generating_function(Gumbel('x', a, b))(t) assert mgf == exp(b*t)*gamma(-a*t + 1) mgf = moment_generating_function(Gompertz('x', a, b))(t) assert mgf == b*exp(b)*expint(t/a, b) mgf = moment_generating_function(Laplace('x', a, b))(t) assert mgf == exp(a*t)/(-b**2*t**2 + 1) mgf = moment_generating_function(Logistic('x', a, b))(t) assert mgf == exp(a*t)*beta(-b*t + 1, b*t + 1) mgf = moment_generating_function(Normal('x', a, b))(t) assert mgf == exp(a*t + b**2*t**2/2) mgf = moment_generating_function(Pareto('x', a, b))(t) assert mgf == b*(-a*t)**b*uppergamma(-b, -a*t) mgf = moment_generating_function(QuadraticU('x', a, b))(t) assert str(mgf) == ("(3*(t*(-4*b + (a + b)**2) + 4)*exp(b*t) - " "3*(t*(a**2 + 2*a*(b - 2) + b**2) + 4)*exp(a*t))/(t**2*(a - b)**3)") mgf = moment_generating_function(RaisedCosine('x', a, b))(t) assert mgf == pi**2*exp(a*t)*sinh(b*t)/(b*t*(b**2*t**2 + pi**2)) mgf = moment_generating_function(Rayleigh('x', a))(t) assert mgf == sqrt(2)*sqrt(pi)*a*t*(erf(sqrt(2)*a*t/2) + 1)\ *exp(a**2*t**2/2)/2 + 1 mgf = moment_generating_function(Triangular('x', a, b, c))(t) assert str(mgf) == ("(-2*(-a + b)*exp(c*t) + 2*(-a + c)*exp(b*t) + " "2*(b - c)*exp(a*t))/(t**2*(-a + b)*(-a + c)*(b - c))") mgf = moment_generating_function(Uniform('x', a, b))(t) assert mgf == (-exp(a*t) + exp(b*t))/(t*(-a + b)) mgf = moment_generating_function(UniformSum('x', a))(t) assert mgf == ((exp(t) - 1)/t)**a mgf = moment_generating_function(WignerSemicircle('x', a))(t) assert mgf == 2*besseli(1, a*t)/(a*t) # Numeric tests mgf = moment_generating_function(Beta('x', 1, 1))(t) assert mgf.diff(t).subs(t, 1) == hyper((2,), (3,), 1)/2 mgf = moment_generating_function(Chi('x', 1))(t) assert mgf.diff(t).subs(t, 1) == sqrt(2)*hyper((1,), (Rational(3, 2),), S.Half )/sqrt(pi) + hyper((Rational(3, 2),), (Rational(3, 2),), S.Half) + 2*sqrt(2)*hyper((2,), (Rational(5, 2),), S.Half)/(3*sqrt(pi)) mgf = moment_generating_function(ChiSquared('x', 1))(t) assert mgf.diff(t).subs(t, 1) == I mgf = moment_generating_function(Erlang('x', 1, 1))(t) assert mgf.diff(t).subs(t, 0) == 1 mgf = moment_generating_function(ExGaussian("x", 0, 1, 1))(t) assert mgf.diff(t).subs(t, 2) == -exp(2) mgf = moment_generating_function(Exponential('x', 1))(t) assert mgf.diff(t).subs(t, 0) == 1 mgf = moment_generating_function(Gamma('x', 1, 1))(t) assert mgf.diff(t).subs(t, 0) == 1 mgf = moment_generating_function(Gumbel('x', 1, 1))(t) assert mgf.diff(t).subs(t, 0) == EulerGamma + 1 mgf = moment_generating_function(Gompertz('x', 1, 1))(t) assert mgf.diff(t).subs(t, 1) == -e*meijerg(((), (1, 1)), ((0, 0, 0), ()), 1) mgf = moment_generating_function(Laplace('x', 1, 1))(t) assert mgf.diff(t).subs(t, 0) == 1 mgf = moment_generating_function(Logistic('x', 1, 1))(t) assert mgf.diff(t).subs(t, 0) == beta(1, 1) mgf = moment_generating_function(Normal('x', 0, 1))(t) assert mgf.diff(t).subs(t, 1) == exp(S.Half) mgf = moment_generating_function(Pareto('x', 1, 1))(t) assert mgf.diff(t).subs(t, 0) == expint(1, 0) mgf = moment_generating_function(QuadraticU('x', 1, 2))(t) assert mgf.diff(t).subs(t, 1) == -12*e - 3*exp(2) mgf = moment_generating_function(RaisedCosine('x', 1, 1))(t) assert mgf.diff(t).subs(t, 1) == -2*e*pi**2*sinh(1)/\ (1 + pi**2)**2 + e*pi**2*cosh(1)/(1 + pi**2) mgf = moment_generating_function(Rayleigh('x', 1))(t) assert mgf.diff(t).subs(t, 0) == sqrt(2)*sqrt(pi)/2 mgf = moment_generating_function(Triangular('x', 1, 3, 2))(t) assert mgf.diff(t).subs(t, 1) == -e + exp(3) mgf = moment_generating_function(Uniform('x', 0, 1))(t) assert mgf.diff(t).subs(t, 1) == 1 mgf = moment_generating_function(UniformSum('x', 1))(t) assert mgf.diff(t).subs(t, 1) == 1 mgf = moment_generating_function(WignerSemicircle('x', 1))(t) assert mgf.diff(t).subs(t, 1) == -2*besseli(1, 1) + besseli(2, 1) +\ besseli(0, 1) def test_ContinuousRV(): pdf = sqrt(2)*exp(-x**2/2)/(2*sqrt(pi)) # Normal distribution # X and Y should be equivalent X = ContinuousRV(x, pdf, check=True) Y = Normal('y', 0, 1) assert variance(X) == variance(Y) assert P(X > 0) == P(Y > 0) Z = ContinuousRV(z, exp(-z), set=Interval(0, oo)) assert Z.pspace.domain.set == Interval(0, oo) assert E(Z) == 1 assert P(Z > 5) == exp(-5) raises(ValueError, lambda: ContinuousRV(z, exp(-z), set=Interval(0, 10), check=True)) # the correct pdf for Gamma(k, theta) but the integral in `check` # integrates to something equivalent to 1 and not to 1 exactly _x, k, theta = symbols("x k theta", positive=True) pdf = 1/(gamma(k)*theta**k)*_x**(k-1)*exp(-_x/theta) X = ContinuousRV(_x, pdf, set=Interval(0, oo)) Y = Gamma('y', k, theta) assert (E(X) - E(Y)).simplify() == 0 assert (variance(X) - variance(Y)).simplify() == 0 def test_arcsin(): a = Symbol("a", real=True) b = Symbol("b", real=True) X = Arcsin('x', a, b) assert density(X)(x) == 1/(pi*sqrt((-x + b)*(x - a))) assert cdf(X)(x) == Piecewise((0, a > x), (2*asin(sqrt((-a + x)/(-a + b)))/pi, b >= x), (1, True)) assert pspace(X).domain.set == Interval(a, b) def test_benini(): alpha = Symbol("alpha", positive=True) beta = Symbol("beta", positive=True) sigma = Symbol("sigma", positive=True) X = Benini('x', alpha, beta, sigma) assert density(X)(x) == ((alpha/x + 2*beta*log(x/sigma)/x) *exp(-alpha*log(x/sigma) - beta*log(x/sigma)**2)) assert pspace(X).domain.set == Interval(sigma, oo) raises(NotImplementedError, lambda: moment_generating_function(X)) alpha = Symbol("alpha", nonpositive=True) raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) beta = Symbol("beta", nonpositive=True) raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) alpha = Symbol("alpha", positive=True) raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) beta = Symbol("beta", positive=True) sigma = Symbol("sigma", nonpositive=True) raises(ValueError, lambda: Benini('x', alpha, beta, sigma)) def test_beta(): a, b = symbols('alpha beta', positive=True) B = Beta('x', a, b) assert pspace(B).domain.set == Interval(0, 1) assert characteristic_function(B)(x) == hyper((a,), (a + b,), I*x) assert density(B)(x) == x**(a - 1)*(1 - x)**(b - 1)/beta(a, b) assert simplify(E(B)) == a / (a + b) assert simplify(variance(B)) == a*b / (a**3 + 3*a**2*b + a**2 + 3*a*b**2 + 2*a*b + b**3 + b**2) # Full symbolic solution is too much, test with numeric version a, b = 1, 2 B = Beta('x', a, b) assert expand_func(E(B)) == a / S(a + b) assert expand_func(variance(B)) == (a*b) / S((a + b)**2 * (a + b + 1)) assert median(B) == FiniteSet(1 - 1/sqrt(2)) def test_beta_noncentral(): a, b = symbols('a b', positive=True) c = Symbol('c', nonnegative=True) _k = Dummy('k') X = BetaNoncentral('x', a, b, c) assert pspace(X).domain.set == Interval(0, 1) dens = density(X) z = Symbol('z') res = Sum( z**(_k + a - 1)*(c/2)**_k*(1 - z)**(b - 1)*exp(-c/2)/ (beta(_k + a, b)*factorial(_k)), (_k, 0, oo)) assert dens(z).dummy_eq(res) # BetaCentral should not raise if the assumptions # on the symbols can not be determined a, b, c = symbols('a b c') assert BetaNoncentral('x', a, b, c) a = Symbol('a', positive=False, real=True) raises(ValueError, lambda: BetaNoncentral('x', a, b, c)) a = Symbol('a', positive=True) b = Symbol('b', positive=False, real=True) raises(ValueError, lambda: BetaNoncentral('x', a, b, c)) a = Symbol('a', positive=True) b = Symbol('b', positive=True) c = Symbol('c', nonnegative=False, real=True) raises(ValueError, lambda: BetaNoncentral('x', a, b, c)) def test_betaprime(): alpha = Symbol("alpha", positive=True) betap = Symbol("beta", positive=True) X = BetaPrime('x', alpha, betap) assert density(X)(x) == x**(alpha - 1)*(x + 1)**(-alpha - betap)/beta(alpha, betap) alpha = Symbol("alpha", nonpositive=True) raises(ValueError, lambda: BetaPrime('x', alpha, betap)) alpha = Symbol("alpha", positive=True) betap = Symbol("beta", nonpositive=True) raises(ValueError, lambda: BetaPrime('x', alpha, betap)) X = BetaPrime('x', 1, 1) assert median(X) == FiniteSet(1) def test_BoundedPareto(): L, H = symbols('L, H', negative=True) raises(ValueError, lambda: BoundedPareto('X', 1, L, H)) L, H = symbols('L, H', real=False) raises(ValueError, lambda: BoundedPareto('X', 1, L, H)) L, H = symbols('L, H', positive=True) raises(ValueError, lambda: BoundedPareto('X', -1, L, H)) X = BoundedPareto('X', 2, L, H) assert X.pspace.domain.set == Interval(L, H) assert density(X)(x) == 2*L**2/(x**3*(1 - L**2/H**2)) assert cdf(X)(x) == Piecewise((-H**2*L**2/(x**2*(H**2 - L**2)) \ + H**2/(H**2 - L**2), L <= x), (0, True)) assert E(X).simplify() == 2*H*L/(H + L) X = BoundedPareto('X', 1, 2, 4) assert E(X).simplify() == log(16) assert median(X) == FiniteSet(Rational(8, 3)) assert variance(X).simplify() == 8 - 16*log(2)**2 def test_cauchy(): x0 = Symbol("x0", real=True) gamma = Symbol("gamma", positive=True) p = Symbol("p", positive=True) X = Cauchy('x', x0, gamma) # Tests the characteristic function assert characteristic_function(X)(x) == exp(-gamma*Abs(x) + I*x*x0) raises(NotImplementedError, lambda: moment_generating_function(X)) assert density(X)(x) == 1/(pi*gamma*(1 + (x - x0)**2/gamma**2)) assert diff(cdf(X)(x), x) == density(X)(x) assert quantile(X)(p) == gamma*tan(pi*(p - S.Half)) + x0 x1 = Symbol("x1", real=False) raises(ValueError, lambda: Cauchy('x', x1, gamma)) gamma = Symbol("gamma", nonpositive=True) raises(ValueError, lambda: Cauchy('x', x0, gamma)) assert median(X) == FiniteSet(x0) def test_chi(): from sympy import I k = Symbol("k", integer=True) X = Chi('x', k) assert density(X)(x) == 2**(-k/2 + 1)*x**(k - 1)*exp(-x**2/2)/gamma(k/2) # Tests the characteristic function assert characteristic_function(X)(x) == sqrt(2)*I*x*gamma(k/2 + S(1)/2)*hyper((k/2 + S(1)/2,), (S(3)/2,), -x**2/2)/gamma(k/2) + hyper((k/2,), (S(1)/2,), -x**2/2) # Tests the moment generating function assert moment_generating_function(X)(x) == sqrt(2)*x*gamma(k/2 + S(1)/2)*hyper((k/2 + S(1)/2,), (S(3)/2,), x**2/2)/gamma(k/2) + hyper((k/2,), (S(1)/2,), x**2/2) k = Symbol("k", integer=True, positive=False) raises(ValueError, lambda: Chi('x', k)) k = Symbol("k", integer=False, positive=True) raises(ValueError, lambda: Chi('x', k)) def test_chi_noncentral(): k = Symbol("k", integer=True) l = Symbol("l") X = ChiNoncentral("x", k, l) assert density(X)(x) == (x**k*l*(x*l)**(-k/2)* exp(-x**2/2 - l**2/2)*besseli(k/2 - 1, x*l)) k = Symbol("k", integer=True, positive=False) raises(ValueError, lambda: ChiNoncentral('x', k, l)) k = Symbol("k", integer=True, positive=True) l = Symbol("l", nonpositive=True) raises(ValueError, lambda: ChiNoncentral('x', k, l)) k = Symbol("k", integer=False) l = Symbol("l", positive=True) raises(ValueError, lambda: ChiNoncentral('x', k, l)) def test_chi_squared(): k = Symbol("k", integer=True) X = ChiSquared('x', k) # Tests the characteristic function assert characteristic_function(X)(x) == ((-2*I*x + 1)**(-k/2)) assert density(X)(x) == 2**(-k/2)*x**(k/2 - 1)*exp(-x/2)/gamma(k/2) assert cdf(X)(x) == Piecewise((lowergamma(k/2, x/2)/gamma(k/2), x >= 0), (0, True)) assert E(X) == k assert variance(X) == 2*k X = ChiSquared('x', 15) assert cdf(X)(3) == -14873*sqrt(6)*exp(Rational(-3, 2))/(5005*sqrt(pi)) + erf(sqrt(6)/2) k = Symbol("k", integer=True, positive=False) raises(ValueError, lambda: ChiSquared('x', k)) k = Symbol("k", integer=False, positive=True) raises(ValueError, lambda: ChiSquared('x', k)) def test_dagum(): p = Symbol("p", positive=True) b = Symbol("b", positive=True) a = Symbol("a", positive=True) X = Dagum('x', p, a, b) assert density(X)(x) == a*p*(x/b)**(a*p)*((x/b)**a + 1)**(-p - 1)/x assert cdf(X)(x) == Piecewise(((1 + (x/b)**(-a))**(-p), x >= 0), (0, True)) p = Symbol("p", nonpositive=True) raises(ValueError, lambda: Dagum('x', p, a, b)) p = Symbol("p", positive=True) b = Symbol("b", nonpositive=True) raises(ValueError, lambda: Dagum('x', p, a, b)) b = Symbol("b", positive=True) a = Symbol("a", nonpositive=True) raises(ValueError, lambda: Dagum('x', p, a, b)) X = Dagum('x', 1 , 1, 1) assert median(X) == FiniteSet(1) def test_erlang(): k = Symbol("k", integer=True, positive=True) l = Symbol("l", positive=True) X = Erlang("x", k, l) assert density(X)(x) == x**(k - 1)*l**k*exp(-x*l)/gamma(k) assert cdf(X)(x) == Piecewise((lowergamma(k, l*x)/gamma(k), x > 0), (0, True)) def test_exgaussian(): m, z = symbols("m, z") s, l = symbols("s, l", positive=True) X = ExGaussian("x", m, s, l) assert density(X)(z) == l*exp(l*(l*s**2 + 2*m - 2*z)/2) *\ erfc(sqrt(2)*(l*s**2 + m - z)/(2*s))/2 # Note: actual_output simplifies to expected_output. # Ideally cdf(X)(z) would return expected_output # expected_output = (erf(sqrt(2)*(l*s**2 + m - z)/(2*s)) - 1)*exp(l*(l*s**2 + 2*m - 2*z)/2)/2 - erf(sqrt(2)*(m - z)/(2*s))/2 + S.Half u = l*(z - m) v = l*s GaussianCDF1 = cdf(Normal('x', 0, v))(u) GaussianCDF2 = cdf(Normal('x', v**2, v))(u) actual_output = GaussianCDF1 - exp(-u + (v**2/2) + log(GaussianCDF2)) assert cdf(X)(z) == actual_output # assert simplify(actual_output) == expected_output assert variance(X).expand() == s**2 + l**(-2) assert skewness(X).expand() == 2/(l**3*s**2*sqrt(s**2 + l**(-2)) + l * sqrt(s**2 + l**(-2))) def test_exponential(): rate = Symbol('lambda', positive=True) X = Exponential('x', rate) p = Symbol("p", positive=True, real=True, finite=True) assert E(X) == 1/rate assert variance(X) == 1/rate**2 assert skewness(X) == 2 assert skewness(X) == smoment(X, 3) assert kurtosis(X) == 9 assert kurtosis(X) == smoment(X, 4) assert smoment(2*X, 4) == smoment(X, 4) assert moment(X, 3) == 3*2*1/rate**3 assert P(X > 0) is S.One assert P(X > 1) == exp(-rate) assert P(X > 10) == exp(-10*rate) assert quantile(X)(p) == -log(1-p)/rate assert where(X <= 1).set == Interval(0, 1) Y = Exponential('y', 1) assert median(Y) == FiniteSet(log(2)) #Test issue 9970 z = Dummy('z') assert P(X > z) == exp(-z*rate) assert P(X < z) == 0 #Test issue 10076 (Distribution with interval(0,oo)) x = Symbol('x') _z = Dummy('_z') b = SingleContinuousPSpace(x, ExponentialDistribution(2)) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed expected1 = Integral(2*exp(-2*_z), (_z, 3, oo)) assert b.probability(x > 3, evaluate=False).rewrite(Integral).dummy_eq(expected1) expected2 = Integral(2*exp(-2*_z), (_z, 0, 4)) assert b.probability(x < 4, evaluate=False).rewrite(Integral).dummy_eq(expected2) Y = Exponential('y', 2*rate) assert coskewness(X, X, X) == skewness(X) assert coskewness(X, Y + rate*X, Y + 2*rate*X) == \ 4/(sqrt(1 + 1/(4*rate**2))*sqrt(4 + 1/(4*rate**2))) assert coskewness(X + 2*Y, Y + X, Y + 2*X, X > 3) == \ sqrt(170)*Rational(9, 85) def test_exponential_power(): mu = Symbol('mu') z = Symbol('z') alpha = Symbol('alpha', positive=True) beta = Symbol('beta', positive=True) X = ExponentialPower('x', mu, alpha, beta) assert density(X)(z) == beta*exp(-(Abs(mu - z)/alpha) ** beta)/(2*alpha*gamma(1/beta)) assert cdf(X)(z) == S.Half + lowergamma(1/beta, (Abs(mu - z)/alpha)**beta)*sign(-mu + z)/\ (2*gamma(1/beta)) def test_f_distribution(): d1 = Symbol("d1", positive=True) d2 = Symbol("d2", positive=True) X = FDistribution("x", d1, d2) assert density(X)(x) == (d2**(d2/2)*sqrt((d1*x)**d1*(d1*x + d2)**(-d1 - d2)) /(x*beta(d1/2, d2/2))) raises(NotImplementedError, lambda: moment_generating_function(X)) d1 = Symbol("d1", nonpositive=True) raises(ValueError, lambda: FDistribution('x', d1, d1)) d1 = Symbol("d1", positive=True, integer=False) raises(ValueError, lambda: FDistribution('x', d1, d1)) d1 = Symbol("d1", positive=True) d2 = Symbol("d2", nonpositive=True) raises(ValueError, lambda: FDistribution('x', d1, d2)) d2 = Symbol("d2", positive=True, integer=False) raises(ValueError, lambda: FDistribution('x', d1, d2)) def test_fisher_z(): d1 = Symbol("d1", positive=True) d2 = Symbol("d2", positive=True) X = FisherZ("x", d1, d2) assert density(X)(x) == (2*d1**(d1/2)*d2**(d2/2)*(d1*exp(2*x) + d2) **(-d1/2 - d2/2)*exp(d1*x)/beta(d1/2, d2/2)) def test_frechet(): a = Symbol("a", positive=True) s = Symbol("s", positive=True) m = Symbol("m", real=True) X = Frechet("x", a, s=s, m=m) assert density(X)(x) == a*((x - m)/s)**(-a - 1)*exp(-((x - m)/s)**(-a))/s assert cdf(X)(x) == Piecewise((exp(-((-m + x)/s)**(-a)), m <= x), (0, True)) @slow def test_gamma(): k = Symbol("k", positive=True) theta = Symbol("theta", positive=True) X = Gamma('x', k, theta) # Tests characteristic function assert characteristic_function(X)(x) == ((-I*theta*x + 1)**(-k)) assert density(X)(x) == x**(k - 1)*theta**(-k)*exp(-x/theta)/gamma(k) assert cdf(X, meijerg=True)(z) == Piecewise( (-k*lowergamma(k, 0)/gamma(k + 1) + k*lowergamma(k, z/theta)/gamma(k + 1), z >= 0), (0, True)) # assert simplify(variance(X)) == k*theta**2 # handled numerically below assert E(X) == moment(X, 1) k, theta = symbols('k theta', positive=True) X = Gamma('x', k, theta) assert E(X) == k*theta assert variance(X) == k*theta**2 assert skewness(X).expand() == 2/sqrt(k) assert kurtosis(X).expand() == 3 + 6/k Y = Gamma('y', 2*k, 3*theta) assert coskewness(X, theta*X + Y, k*X + Y).simplify() == \ 2*531441**(-k)*sqrt(k)*theta*(3*3**(12*k) - 2*531441**k) \ /(sqrt(k**2 + 18)*sqrt(theta**2 + 18)) def test_gamma_inverse(): a = Symbol("a", positive=True) b = Symbol("b", positive=True) X = GammaInverse("x", a, b) assert density(X)(x) == x**(-a - 1)*b**a*exp(-b/x)/gamma(a) assert cdf(X)(x) == Piecewise((uppergamma(a, b/x)/gamma(a), x > 0), (0, True)) assert characteristic_function(X)(x) == 2 * (-I*b*x)**(a/2) \ * besselk(a, 2*sqrt(b)*sqrt(-I*x))/gamma(a) raises(NotImplementedError, lambda: moment_generating_function(X)) def test_gompertz(): b = Symbol("b", positive=True) eta = Symbol("eta", positive=True) X = Gompertz("x", b, eta) assert density(X)(x) == b*eta*exp(eta)*exp(b*x)*exp(-eta*exp(b*x)) assert cdf(X)(x) == 1 - exp(eta)*exp(-eta*exp(b*x)) assert diff(cdf(X)(x), x) == density(X)(x) def test_gumbel(): beta = Symbol("beta", positive=True) mu = Symbol("mu") x = Symbol("x") y = Symbol("y") X = Gumbel("x", beta, mu) Y = Gumbel("y", beta, mu, minimum=True) assert density(X)(x).expand() == \ exp(mu/beta)*exp(-x/beta)*exp(-exp(mu/beta)*exp(-x/beta))/beta assert density(Y)(y).expand() == \ exp(-mu/beta)*exp(y/beta)*exp(-exp(-mu/beta)*exp(y/beta))/beta assert cdf(X)(x).expand() == \ exp(-exp(mu/beta)*exp(-x/beta)) assert characteristic_function(X)(x) == exp(I*mu*x)*gamma(-I*beta*x + 1) def test_kumaraswamy(): a = Symbol("a", positive=True) b = Symbol("b", positive=True) X = Kumaraswamy("x", a, b) assert density(X)(x) == x**(a - 1)*a*b*(-x**a + 1)**(b - 1) assert cdf(X)(x) == Piecewise((0, x < 0), (-(-x**a + 1)**b + 1, x <= 1), (1, True)) def test_laplace(): mu = Symbol("mu") b = Symbol("b", positive=True) X = Laplace('x', mu, b) #Tests characteristic_function assert characteristic_function(X)(x) == (exp(I*mu*x)/(b**2*x**2 + 1)) assert density(X)(x) == exp(-Abs(x - mu)/b)/(2*b) assert cdf(X)(x) == Piecewise((exp((-mu + x)/b)/2, mu > x), (-exp((mu - x)/b)/2 + 1, True)) X = Laplace('x', [1, 2], [[1, 0], [0, 1]]) assert isinstance(pspace(X).distribution, MultivariateLaplaceDistribution) def test_levy(): mu = Symbol("mu", real=True) c = Symbol("c", positive=True) X = Levy('x', mu, c) assert X.pspace.domain.set == Interval(mu, oo) assert density(X)(x) == sqrt(c/(2*pi))*exp(-c/(2*(x - mu)))/((x - mu)**(S.One + S.Half)) assert cdf(X)(x) == erfc(sqrt(c/(2*(x - mu)))) raises(NotImplementedError, lambda: moment_generating_function(X)) mu = Symbol("mu", real=False) raises(ValueError, lambda: Levy('x',mu,c)) c = Symbol("c", nonpositive=True) raises(ValueError, lambda: Levy('x',mu,c)) mu = Symbol("mu", real=True) raises(ValueError, lambda: Levy('x',mu,c)) def test_logcauchy(): mu = Symbol("mu" , positive=True) sigma = Symbol("sigma" , positive=True) X = LogCauchy("x", mu, sigma) assert density(X)(x) == sigma/(x*pi*(sigma**2 + (-mu + log(x))**2)) assert cdf(X)(x) == atan((log(x) - mu)/sigma)/pi + S.Half def test_logistic(): mu = Symbol("mu", real=True) s = Symbol("s", positive=True) p = Symbol("p", positive=True) X = Logistic('x', mu, s) #Tests characteristics_function assert characteristic_function(X)(x) == \ (Piecewise((pi*s*x*exp(I*mu*x)/sinh(pi*s*x), Ne(x, 0)), (1, True))) assert density(X)(x) == exp((-x + mu)/s)/(s*(exp((-x + mu)/s) + 1)**2) assert cdf(X)(x) == 1/(exp((mu - x)/s) + 1) assert quantile(X)(p) == mu - s*log(-S.One + 1/p) def test_loglogistic(): a, b = symbols('a b') assert LogLogistic('x', a, b) a = Symbol('a', negative=True) b = Symbol('b', positive=True) raises(ValueError, lambda: LogLogistic('x', a, b)) a = Symbol('a', positive=True) b = Symbol('b', negative=True) raises(ValueError, lambda: LogLogistic('x', a, b)) a, b, z, p = symbols('a b z p', positive=True) X = LogLogistic('x', a, b) assert density(X)(z) == b*(z/a)**(b - 1)/(a*((z/a)**b + 1)**2) assert cdf(X)(z) == 1/(1 + (z/a)**(-b)) assert quantile(X)(p) == a*(p/(1 - p))**(1/b) # Expectation assert E(X) == Piecewise((S.NaN, b <= 1), (pi*a/(b*sin(pi/b)), True)) b = symbols('b', prime=True) # b > 1 X = LogLogistic('x', a, b) assert E(X) == pi*a/(b*sin(pi/b)) X = LogLogistic('x', 1, 2) assert median(X) == FiniteSet(1) def test_logitnormal(): mu = Symbol('mu', real=True) s = Symbol('s', positive=True) X = LogitNormal('x', mu, s) x = Symbol('x') assert density(X)(x) == sqrt(2)*exp(-(-mu + log(x/(1 - x)))**2/(2*s**2))/(2*sqrt(pi)*s*x*(1 - x)) assert cdf(X)(x) == erf(sqrt(2)*(-mu + log(x/(1 - x)))/(2*s))/2 + S(1)/2 def test_lognormal(): mean = Symbol('mu', real=True) std = Symbol('sigma', positive=True) X = LogNormal('x', mean, std) # The sympy integrator can't do this too well #assert E(X) == exp(mean+std**2/2) #assert variance(X) == (exp(std**2)-1) * exp(2*mean + std**2) # The sympy integrator can't do this too well #assert E(X) == raises(NotImplementedError, lambda: moment_generating_function(X)) mu = Symbol("mu", real=True) sigma = Symbol("sigma", positive=True) X = LogNormal('x', mu, sigma) assert density(X)(x) == (sqrt(2)*exp(-(-mu + log(x))**2 /(2*sigma**2))/(2*x*sqrt(pi)*sigma)) # Tests cdf assert cdf(X)(x) == Piecewise( (erf(sqrt(2)*(-mu + log(x))/(2*sigma))/2 + S(1)/2, x > 0), (0, True)) X = LogNormal('x', 0, 1) # Mean 0, standard deviation 1 assert density(X)(x) == sqrt(2)*exp(-log(x)**2/2)/(2*x*sqrt(pi)) def test_Lomax(): a, l = symbols('a, l', negative=True) raises(ValueError, lambda: Lomax('X', a , l)) a, l = symbols('a, l', real=False) raises(ValueError, lambda: Lomax('X', a , l)) a, l = symbols('a, l', positive=True) X = Lomax('X', a, l) assert X.pspace.domain.set == Interval(0, oo) assert density(X)(x) == a*(1 + x/l)**(-a - 1)/l assert cdf(X)(x) == Piecewise((1 - (1 + x/l)**(-a), x >= 0), (0, True)) a = 3 X = Lomax('X', a, l) assert E(X) == l/2 assert median(X) == FiniteSet(l*(-1 + 2**Rational(1, 3))) assert variance(X) == 3*l**2/4 def test_maxwell(): a = Symbol("a", positive=True) X = Maxwell('x', a) assert density(X)(x) == (sqrt(2)*x**2*exp(-x**2/(2*a**2))/ (sqrt(pi)*a**3)) assert E(X) == 2*sqrt(2)*a/sqrt(pi) assert variance(X) == -8*a**2/pi + 3*a**2 assert cdf(X)(x) == erf(sqrt(2)*x/(2*a)) - sqrt(2)*x*exp(-x**2/(2*a**2))/(sqrt(pi)*a) assert diff(cdf(X)(x), x) == density(X)(x) def test_Moyal(): mu = Symbol('mu',real=False) sigma = Symbol('sigma', real=True, positive=True) raises(ValueError, lambda: Moyal('M',mu, sigma)) mu = Symbol('mu', real=True) sigma = Symbol('sigma', real=True, negative=True) raises(ValueError, lambda: Moyal('M',mu, sigma)) sigma = Symbol('sigma', real=True, positive=True) M = Moyal('M', mu, sigma) assert density(M)(z) == sqrt(2)*exp(-exp((mu - z)/sigma)/2 - (-mu + z)/(2*sigma))/(2*sqrt(pi)*sigma) assert cdf(M)(z).simplify() == 1 - erf(sqrt(2)*exp((mu - z)/(2*sigma))/2) assert characteristic_function(M)(z) == 2**(-I*sigma*z)*exp(I*mu*z) \ *gamma(-I*sigma*z + Rational(1, 2))/sqrt(pi) assert E(M) == mu + EulerGamma*sigma + sigma*log(2) assert moment_generating_function(M)(z) == 2**(-sigma*z)*exp(mu*z) \ *gamma(-sigma*z + Rational(1, 2))/sqrt(pi) def test_nakagami(): mu = Symbol("mu", positive=True) omega = Symbol("omega", positive=True) X = Nakagami('x', mu, omega) assert density(X)(x) == (2*x**(2*mu - 1)*mu**mu*omega**(-mu) *exp(-x**2*mu/omega)/gamma(mu)) assert simplify(E(X)) == (sqrt(mu)*sqrt(omega) *gamma(mu + S.Half)/gamma(mu + 1)) assert simplify(variance(X)) == ( omega - omega*gamma(mu + S.Half)**2/(gamma(mu)*gamma(mu + 1))) assert cdf(X)(x) == Piecewise( (lowergamma(mu, mu*x**2/omega)/gamma(mu), x > 0), (0, True)) X = Nakagami('x',1 ,1) assert median(X) == FiniteSet(sqrt(log(2))) def test_gaussian_inverse(): # test for symbolic parameters a, b = symbols('a b') assert GaussianInverse('x', a, b) # Inverse Gaussian distribution is also known as Wald distribution # `GaussianInverse` can also be referred by the name `Wald` a, b, z = symbols('a b z') X = Wald('x', a, b) assert density(X)(z) == sqrt(2)*sqrt(b/z**3)*exp(-b*(-a + z)**2/(2*a**2*z))/(2*sqrt(pi)) a, b = symbols('a b', positive=True) z = Symbol('z', positive=True) X = GaussianInverse('x', a, b) assert density(X)(z) == sqrt(2)*sqrt(b)*sqrt(z**(-3))*exp(-b*(-a + z)**2/(2*a**2*z))/(2*sqrt(pi)) assert E(X) == a assert variance(X).expand() == a**3/b assert cdf(X)(z) == (S.Half - erf(sqrt(2)*sqrt(b)*(1 + z/a)/(2*sqrt(z)))/2)*exp(2*b/a) +\ erf(sqrt(2)*sqrt(b)*(-1 + z/a)/(2*sqrt(z)))/2 + S.Half a = symbols('a', nonpositive=True) raises(ValueError, lambda: GaussianInverse('x', a, b)) a = symbols('a', positive=True) b = symbols('b', nonpositive=True) raises(ValueError, lambda: GaussianInverse('x', a, b)) def test_pareto(): xm, beta = symbols('xm beta', positive=True) alpha = beta + 5 X = Pareto('x', xm, alpha) dens = density(X) #Tests cdf function assert cdf(X)(x) == \ Piecewise((-x**(-beta - 5)*xm**(beta + 5) + 1, x >= xm), (0, True)) #Tests characteristic_function assert characteristic_function(X)(x) == \ ((-I*x*xm)**(beta + 5)*(beta + 5)*uppergamma(-beta - 5, -I*x*xm)) assert dens(x) == x**(-(alpha + 1))*xm**(alpha)*(alpha) assert simplify(E(X)) == alpha*xm/(alpha-1) # computation of taylor series for MGF still too slow #assert simplify(variance(X)) == xm**2*alpha / ((alpha-1)**2*(alpha-2)) def test_pareto_numeric(): xm, beta = 3, 2 alpha = beta + 5 X = Pareto('x', xm, alpha) assert E(X) == alpha*xm/S(alpha - 1) assert variance(X) == xm**2*alpha / S((alpha - 1)**2*(alpha - 2)) assert median(X) == FiniteSet(3*2**Rational(1, 7)) # Skewness tests too slow. Try shortcutting function? def test_PowerFunction(): alpha = Symbol("alpha", nonpositive=True) a, b = symbols('a, b', real=True) raises (ValueError, lambda: PowerFunction('x', alpha, a, b)) a, b = symbols('a, b', real=False) raises (ValueError, lambda: PowerFunction('x', alpha, a, b)) alpha = Symbol("alpha", positive=True) a, b = symbols('a, b', real=True) raises (ValueError, lambda: PowerFunction('x', alpha, 5, 2)) X = PowerFunction('X', 2, a, b) assert density(X)(z) == (-2*a + 2*z)/(-a + b)**2 assert cdf(X)(z) == Piecewise((a**2/(a**2 - 2*a*b + b**2) - 2*a*z/(a**2 - 2*a*b + b**2) + z**2/(a**2 - 2*a*b + b**2), a <= z), (0, True)) X = PowerFunction('X', 2, 0, 1) assert density(X)(z) == 2*z assert cdf(X)(z) == Piecewise((z**2, z >= 0), (0,True)) assert E(X) == Rational(2,3) assert P(X < 0) == 0 assert P(X < 1) == 1 assert median(X) == FiniteSet(1/sqrt(2)) def test_raised_cosine(): mu = Symbol("mu", real=True) s = Symbol("s", positive=True) X = RaisedCosine("x", mu, s) assert pspace(X).domain.set == Interval(mu - s, mu + s) #Tests characteristics_function assert characteristic_function(X)(x) == \ Piecewise((exp(-I*pi*mu/s)/2, Eq(x, -pi/s)), (exp(I*pi*mu/s)/2, Eq(x, pi/s)), (pi**2*exp(I*mu*x)*sin(s*x)/(s*x*(-s**2*x**2 + pi**2)), True)) assert density(X)(x) == (Piecewise(((cos(pi*(x - mu)/s) + 1)/(2*s), And(x <= mu + s, mu - s <= x)), (0, True))) def test_rayleigh(): sigma = Symbol("sigma", positive=True) X = Rayleigh('x', sigma) #Tests characteristic_function assert characteristic_function(X)(x) == (-sqrt(2)*sqrt(pi)*sigma*x*(erfi(sqrt(2)*sigma*x/2) - I)*exp(-sigma**2*x**2/2)/2 + 1) assert density(X)(x) == x*exp(-x**2/(2*sigma**2))/sigma**2 assert E(X) == sqrt(2)*sqrt(pi)*sigma/2 assert variance(X) == -pi*sigma**2/2 + 2*sigma**2 assert cdf(X)(x) == 1 - exp(-x**2/(2*sigma**2)) assert diff(cdf(X)(x), x) == density(X)(x) def test_reciprocal(): a = Symbol("a", real=True) b = Symbol("b", real=True) X = Reciprocal('x', a, b) assert density(X)(x) == 1/(x*(-log(a) + log(b))) assert cdf(X)(x) == Piecewise((log(a)/(log(a) - log(b)) - log(x)/(log(a) - log(b)), a <= x), (0, True)) X = Reciprocal('x', 5, 30) assert E(X) == 25/(log(30) - log(5)) assert P(X < 4) == S.Zero assert P(X < 20) == log(20) / (log(30) - log(5)) - log(5) / (log(30) - log(5)) assert cdf(X)(10) == log(10) / (log(30) - log(5)) - log(5) / (log(30) - log(5)) a = symbols('a', nonpositive=True) raises(ValueError, lambda: Reciprocal('x', a, b)) a = symbols('a', positive=True) b = symbols('b', positive=True) raises(ValueError, lambda: Reciprocal('x', a + b, a)) def test_shiftedgompertz(): b = Symbol("b", positive=True) eta = Symbol("eta", positive=True) X = ShiftedGompertz("x", b, eta) assert density(X)(x) == b*(eta*(1 - exp(-b*x)) + 1)*exp(-b*x)*exp(-eta*exp(-b*x)) def test_studentt(): nu = Symbol("nu", positive=True) X = StudentT('x', nu) assert density(X)(x) == (1 + x**2/nu)**(-nu/2 - S.Half)/(sqrt(nu)*beta(S.Half, nu/2)) assert cdf(X)(x) == S.Half + x*gamma(nu/2 + S.Half)*hyper((S.Half, nu/2 + S.Half), (Rational(3, 2),), -x**2/nu)/(sqrt(pi)*sqrt(nu)*gamma(nu/2)) raises(NotImplementedError, lambda: moment_generating_function(X)) def test_trapezoidal(): a = Symbol("a", real=True) b = Symbol("b", real=True) c = Symbol("c", real=True) d = Symbol("d", real=True) X = Trapezoidal('x', a, b, c, d) assert density(X)(x) == Piecewise(((-2*a + 2*x)/((-a + b)*(-a - b + c + d)), (a <= x) & (x < b)), (2/(-a - b + c + d), (b <= x) & (x < c)), ((2*d - 2*x)/((-c + d)*(-a - b + c + d)), (c <= x) & (x <= d)), (0, True)) X = Trapezoidal('x', 0, 1, 2, 3) assert E(X) == Rational(3, 2) assert variance(X) == Rational(5, 12) assert P(X < 2) == Rational(3, 4) assert median(X) == FiniteSet(Rational(3, 2)) def test_triangular(): a = Symbol("a") b = Symbol("b") c = Symbol("c") X = Triangular('x', a, b, c) assert pspace(X).domain.set == Interval(a, b) assert str(density(X)(x)) == ("Piecewise(((-2*a + 2*x)/((-a + b)*(-a + c)), (a <= x) & (c > x)), " "(2/(-a + b), Eq(c, x)), ((2*b - 2*x)/((-a + b)*(b - c)), (b >= x) & (c < x)), (0, True))") #Tests moment_generating_function assert moment_generating_function(X)(x).expand() == \ ((-2*(-a + b)*exp(c*x) + 2*(-a + c)*exp(b*x) + 2*(b - c)*exp(a*x))/(x**2*(-a + b)*(-a + c)*(b - c))).expand() assert str(characteristic_function(X)(x)) == \ '(2*(-a + b)*exp(I*c*x) - 2*(-a + c)*exp(I*b*x) - 2*(b - c)*exp(I*a*x))/(x**2*(-a + b)*(-a + c)*(b - c))' def test_quadratic_u(): a = Symbol("a", real=True) b = Symbol("b", real=True) X = QuadraticU("x", a, b) Y = QuadraticU("x", 1, 2) assert pspace(X).domain.set == Interval(a, b) # Tests _moment_generating_function assert moment_generating_function(Y)(1) == -15*exp(2) + 27*exp(1) assert moment_generating_function(Y)(2) == -9*exp(4)/2 + 21*exp(2)/2 assert characteristic_function(Y)(1) == 3*I*(-1 + 4*I)*exp(I*exp(2*I)) assert density(X)(x) == (Piecewise((12*(x - a/2 - b/2)**2/(-a + b)**3, And(x <= b, a <= x)), (0, True))) def test_uniform(): l = Symbol('l', real=True) w = Symbol('w', positive=True) X = Uniform('x', l, l + w) assert E(X) == l + w/2 assert variance(X).expand() == w**2/12 # With numbers all is well X = Uniform('x', 3, 5) assert P(X < 3) == 0 and P(X > 5) == 0 assert P(X < 4) == P(X > 4) == S.Half assert median(X) == FiniteSet(4) z = Symbol('z') p = density(X)(z) assert p.subs(z, 3.7) == S.Half assert p.subs(z, -1) == 0 assert p.subs(z, 6) == 0 c = cdf(X) assert c(2) == 0 and c(3) == 0 assert c(Rational(7, 2)) == Rational(1, 4) assert c(5) == 1 and c(6) == 1 @XFAIL def test_uniform_P(): """ This stopped working because SingleContinuousPSpace.compute_density no longer calls integrate on a DiracDelta but rather just solves directly. integrate used to call UniformDistribution.expectation which special-cased subsed out the Min and Max terms that Uniform produces I decided to regress on this class for general cleanliness (and I suspect speed) of the algorithm. """ l = Symbol('l', real=True) w = Symbol('w', positive=True) X = Uniform('x', l, l + w) assert P(X < l) == 0 and P(X > l + w) == 0 def test_uniformsum(): n = Symbol("n", integer=True) _k = Dummy("k") x = Symbol("x") X = UniformSum('x', n) res = Sum((-1)**_k*(-_k + x)**(n - 1)*binomial(n, _k), (_k, 0, floor(x)))/factorial(n - 1) assert density(X)(x).dummy_eq(res) #Tests set functions assert X.pspace.domain.set == Interval(0, n) #Tests the characteristic_function assert characteristic_function(X)(x) == (-I*(exp(I*x) - 1)/x)**n #Tests the moment_generating_function assert moment_generating_function(X)(x) == ((exp(x) - 1)/x)**n def test_von_mises(): mu = Symbol("mu") k = Symbol("k", positive=True) X = VonMises("x", mu, k) assert density(X)(x) == exp(k*cos(x - mu))/(2*pi*besseli(0, k)) def test_weibull(): a, b = symbols('a b', positive=True) # FIXME: simplify(E(X)) seems to hang without extended_positive=True # On a Linux machine this had a rapid memory leak... # a, b = symbols('a b', positive=True) X = Weibull('x', a, b) assert E(X).expand() == a * gamma(1 + 1/b) assert variance(X).expand() == (a**2 * gamma(1 + 2/b) - E(X)**2).expand() assert simplify(skewness(X)) == (2*gamma(1 + 1/b)**3 - 3*gamma(1 + 1/b)*gamma(1 + 2/b) + gamma(1 + 3/b))/(-gamma(1 + 1/b)**2 + gamma(1 + 2/b))**Rational(3, 2) assert simplify(kurtosis(X)) == (-3*gamma(1 + 1/b)**4 +\ 6*gamma(1 + 1/b)**2*gamma(1 + 2/b) - 4*gamma(1 + 1/b)*gamma(1 + 3/b) + gamma(1 + 4/b))/(gamma(1 + 1/b)**2 - gamma(1 + 2/b))**2 def test_weibull_numeric(): # Test for integers and rationals a = 1 bvals = [S.Half, 1, Rational(3, 2), 5] for b in bvals: X = Weibull('x', a, b) assert simplify(E(X)) == expand_func(a * gamma(1 + 1/S(b))) assert simplify(variance(X)) == simplify( a**2 * gamma(1 + 2/S(b)) - E(X)**2) # Not testing Skew... it's slow with int/frac values > 3/2 def test_wignersemicircle(): R = Symbol("R", positive=True) X = WignerSemicircle('x', R) assert pspace(X).domain.set == Interval(-R, R) assert density(X)(x) == 2*sqrt(-x**2 + R**2)/(pi*R**2) assert E(X) == 0 #Tests ChiNoncentralDistribution assert characteristic_function(X)(x) == \ Piecewise((2*besselj(1, R*x)/(R*x), Ne(x, 0)), (1, True)) def test_input_value_assertions(): a, b = symbols('a b') p, q = symbols('p q', positive=True) m, n = symbols('m n', positive=False, real=True) raises(ValueError, lambda: Normal('x', 3, 0)) raises(ValueError, lambda: Normal('x', m, n)) Normal('X', a, p) # No error raised raises(ValueError, lambda: Exponential('x', m)) Exponential('Ex', p) # No error raised for fn in [Pareto, Weibull, Beta, Gamma]: raises(ValueError, lambda: fn('x', m, p)) raises(ValueError, lambda: fn('x', p, n)) fn('x', p, q) # No error raised def test_unevaluated(): X = Normal('x', 0, 1) k = Dummy('k') expr1 = Integral(sqrt(2)*k*exp(-k**2/2)/(2*sqrt(pi)), (k, -oo, oo)) expr2 = Integral(sqrt(2)*exp(-k**2/2)/(2*sqrt(pi)), (k, 0, oo)) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert E(X, evaluate=False).rewrite(Integral).dummy_eq(expr1) assert E(X + 1, evaluate=False).rewrite(Integral).dummy_eq(expr1 + 1) assert P(X > 0, evaluate=False).rewrite(Integral).dummy_eq(expr2) assert P(X > 0, X**2 < 1) == S.Half def test_probability_unevaluated(): T = Normal('T', 30, 3) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert type(P(T > 33, evaluate=False)) == Probability def test_density_unevaluated(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 2) assert isinstance(density(X+Y, evaluate=False)(z), Integral) def test_NormalDistribution(): nd = NormalDistribution(0, 1) x = Symbol('x') assert nd.cdf(x) == erf(sqrt(2)*x/2)/2 + S.Half assert nd.expectation(1, x) == 1 assert nd.expectation(x, x) == 0 assert nd.expectation(x**2, x) == 1 #Test issue 10076 a = SingleContinuousPSpace(x, NormalDistribution(2, 4)) _z = Dummy('_z') expected1 = Integral(sqrt(2)*exp(-(_z - 2)**2/32)/(8*sqrt(pi)),(_z, -oo, 1)) assert a.probability(x < 1, evaluate=False).dummy_eq(expected1) is True expected2 = Integral(sqrt(2)*exp(-(_z - 2)**2/32)/(8*sqrt(pi)),(_z, 1, oo)) assert a.probability(x > 1, evaluate=False).dummy_eq(expected2) is True b = SingleContinuousPSpace(x, NormalDistribution(1, 9)) expected3 = Integral(sqrt(2)*exp(-(_z - 1)**2/162)/(18*sqrt(pi)),(_z, 6, oo)) assert b.probability(x > 6, evaluate=False).dummy_eq(expected3) is True expected4 = Integral(sqrt(2)*exp(-(_z - 1)**2/162)/(18*sqrt(pi)),(_z, -oo, 6)) assert b.probability(x < 6, evaluate=False).dummy_eq(expected4) is True def test_random_parameters(): mu = Normal('mu', 2, 3) meas = Normal('T', mu, 1) assert density(meas, evaluate=False)(z) assert isinstance(pspace(meas), CompoundPSpace) X = Normal('x', [1, 2], [[1, 0], [0, 1]]) assert isinstance(pspace(X).distribution, MultivariateNormalDistribution) assert density(meas)(z).simplify() == sqrt(5)*exp(-z**2/20 + z/5 - S(1)/5)/(10*sqrt(pi)) def test_random_parameters_given(): mu = Normal('mu', 2, 3) meas = Normal('T', mu, 1) assert given(meas, Eq(mu, 5)) == Normal('T', 5, 1) def test_conjugate_priors(): mu = Normal('mu', 2, 3) x = Normal('x', mu, 1) assert isinstance(simplify(density(mu, Eq(x, y), evaluate=False)(z)), Mul) def test_difficult_univariate(): """ Since using solve in place of deltaintegrate we're able to perform substantially more complex density computations on single continuous random variables """ x = Normal('x', 0, 1) assert density(x**3) assert density(exp(x**2)) assert density(log(x)) def test_issue_10003(): X = Exponential('x', 3) G = Gamma('g', 1, 2) assert P(X < -1) is S.Zero assert P(G < -1) is S.Zero @slow def test_precomputed_cdf(): x = symbols("x", real=True) mu = symbols("mu", real=True) sigma, xm, alpha = symbols("sigma xm alpha", positive=True) n = symbols("n", integer=True, positive=True) distribs = [ Normal("X", mu, sigma), Pareto("P", xm, alpha), ChiSquared("C", n), Exponential("E", sigma), # LogNormal("L", mu, sigma), ] for X in distribs: compdiff = cdf(X)(x) - simplify(X.pspace.density.compute_cdf()(x)) compdiff = simplify(compdiff.rewrite(erfc)) assert compdiff == 0 @slow def test_precomputed_characteristic_functions(): import mpmath def test_cf(dist, support_lower_limit, support_upper_limit): pdf = density(dist) t = Symbol('t') # first function is the hardcoded CF of the distribution cf1 = lambdify([t], characteristic_function(dist)(t), 'mpmath') # second function is the Fourier transform of the density function f = lambdify([x, t], pdf(x)*exp(I*x*t), 'mpmath') cf2 = lambda t: mpmath.quad(lambda x: f(x, t), [support_lower_limit, support_upper_limit], maxdegree=10) # compare the two functions at various points for test_point in [2, 5, 8, 11]: n1 = cf1(test_point) n2 = cf2(test_point) assert abs(re(n1) - re(n2)) < 1e-12 assert abs(im(n1) - im(n2)) < 1e-12 test_cf(Beta('b', 1, 2), 0, 1) test_cf(Chi('c', 3), 0, mpmath.inf) test_cf(ChiSquared('c', 2), 0, mpmath.inf) test_cf(Exponential('e', 6), 0, mpmath.inf) test_cf(Logistic('l', 1, 2), -mpmath.inf, mpmath.inf) test_cf(Normal('n', -1, 5), -mpmath.inf, mpmath.inf) test_cf(RaisedCosine('r', 3, 1), 2, 4) test_cf(Rayleigh('r', 0.5), 0, mpmath.inf) test_cf(Uniform('u', -1, 1), -1, 1) test_cf(WignerSemicircle('w', 3), -3, 3) def test_long_precomputed_cdf(): x = symbols("x", real=True) distribs = [ Arcsin("A", -5, 9), Dagum("D", 4, 10, 3), Erlang("E", 14, 5), Frechet("F", 2, 6, -3), Gamma("G", 2, 7), GammaInverse("GI", 3, 5), Kumaraswamy("K", 6, 8), Laplace("LA", -5, 4), Logistic("L", -6, 7), Nakagami("N", 2, 7), StudentT("S", 4) ] for distr in distribs: for _ in range(5): assert tn(diff(cdf(distr)(x), x), density(distr)(x), x, a=0, b=0, c=1, d=0) US = UniformSum("US", 5) pdf01 = density(US)(x).subs(floor(x), 0).doit() # pdf on (0, 1) cdf01 = cdf(US, evaluate=False)(x).subs(floor(x), 0).doit() # cdf on (0, 1) assert tn(diff(cdf01, x), pdf01, x, a=0, b=0, c=1, d=0) def test_issue_13324(): X = Uniform('X', 0, 1) assert E(X, X > S.Half) == Rational(3, 4) assert E(X, X > 0) == S.Half def test_issue_20756(): X = Uniform('X', -1, +1) Y = Uniform('Y', -1, +1) assert E(X * Y) == S.Zero assert E(X * ((Y + 1) - 1)) == S.Zero assert E(Y * (X*(X + 1) - X*X)) == S.Zero def test_FiniteSet_prob(): E = Exponential('E', 3) N = Normal('N', 5, 7) assert P(Eq(E, 1)) is S.Zero assert P(Eq(N, 2)) is S.Zero assert P(Eq(N, x)) is S.Zero def test_prob_neq(): E = Exponential('E', 4) X = ChiSquared('X', 4) assert P(Ne(E, 2)) == 1 assert P(Ne(X, 4)) == 1 assert P(Ne(X, 4)) == 1 assert P(Ne(X, 5)) == 1 assert P(Ne(E, x)) == 1 def test_union(): N = Normal('N', 3, 2) assert simplify(P(N**2 - N > 2)) == \ -erf(sqrt(2))/2 - erfc(sqrt(2)/4)/2 + Rational(3, 2) assert simplify(P(N**2 - 4 > 0)) == \ -erf(5*sqrt(2)/4)/2 - erfc(sqrt(2)/4)/2 + Rational(3, 2) def test_Or(): N = Normal('N', 0, 1) assert simplify(P(Or(N > 2, N < 1))) == \ -erf(sqrt(2))/2 - erfc(sqrt(2)/2)/2 + Rational(3, 2) assert P(Or(N < 0, N < 1)) == P(N < 1) assert P(Or(N > 0, N < 0)) == 1 def test_conditional_eq(): E = Exponential('E', 1) assert P(Eq(E, 1), Eq(E, 1)) == 1 assert P(Eq(E, 1), Eq(E, 2)) == 0 assert P(E > 1, Eq(E, 2)) == 1 assert P(E < 1, Eq(E, 2)) == 0 def test_ContinuousDistributionHandmade(): x = Symbol('x') z = Dummy('z') dens = Lambda(x, Piecewise((S.Half, (0<=x)&(x<1)), (0, (x>=1)&(x<2)), (S.Half, (x>=2)&(x<3)), (0, True))) dens = ContinuousDistributionHandmade(dens, set=Interval(0, 3)) space = SingleContinuousPSpace(z, dens) assert dens.pdf == Lambda(x, Piecewise((1/2, (x >= 0) & (x < 1)), (0, (x >= 1) & (x < 2)), (1/2, (x >= 2) & (x < 3)), (0, True))) assert median(space.value) == Interval(1, 2) assert E(space.value) == Rational(3, 2) assert variance(space.value) == Rational(13, 12) def test_issue_16318(): # test compute_expectation function of the SingleContinuousDomain N = SingleContinuousDomain(x, Interval(0, 1)) raises(ValueError, lambda: SingleContinuousDomain.compute_expectation(N, x+1, {x, y})) sympy-sympy-1.9/sympy/stats/tests/test_discrete_rv.py000066400000000000000000000256701412543434000233400ustar00rootroot00000000000000from sympy import (S, Symbol, Sum, I, lambdify, re, im, log, simplify, sqrt, zeta, pi, besseli, Dummy, oo, Piecewise, Rational, beta, floor, FiniteSet) from sympy.core.relational import Eq, Ne from sympy.functions.elementary.exponential import exp from sympy.logic.boolalg import Or from sympy.sets.fancysets import Range from sympy.stats import (P, E, variance, density, characteristic_function, where, moment_generating_function, skewness, cdf, kurtosis, coskewness) from sympy.stats.drv_types import (PoissonDistribution, GeometricDistribution, FlorySchulz, Poisson, Geometric, Hermite, Logarithmic, NegativeBinomial, Skellam, YuleSimon, Zeta, DiscreteRV) from sympy.testing.pytest import slow, nocache_fail, raises, ignore_warnings from sympy.stats.symbolic_probability import Expectation x = Symbol('x') def test_PoissonDistribution(): l = 3 p = PoissonDistribution(l) assert abs(p.cdf(10).evalf() - 1) < .001 assert abs(p.cdf(10.4).evalf() - 1) < .001 assert p.expectation(x, x) == l assert p.expectation(x**2, x) - p.expectation(x, x)**2 == l def test_Poisson(): l = 3 x = Poisson('x', l) assert E(x) == l assert variance(x) == l assert density(x) == PoissonDistribution(l) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert isinstance(E(x, evaluate=False), Expectation) assert isinstance(E(2*x, evaluate=False), Expectation) # issue 8248 assert x.pspace.compute_expectation(1) == 1 def test_FlorySchulz(): a = Symbol("a") z = Symbol("z") x = FlorySchulz('x' , a) assert E(x) == (2 - a)/a assert (variance(x) - 2*(1 - a)/a**2).simplify() == S(0) assert density(x)(z) == a**2*z*(1 - a)**(z - 1) @slow def test_GeometricDistribution(): p = S.One / 5 d = GeometricDistribution(p) assert d.expectation(x, x) == 1/p assert d.expectation(x**2, x) - d.expectation(x, x)**2 == (1-p)/p**2 assert abs(d.cdf(20000).evalf() - 1) < .001 assert abs(d.cdf(20000.8).evalf() - 1) < .001 G = Geometric('G', p=S(1)/4) assert cdf(G)(S(7)/2) == P(G <= S(7)/2) X = Geometric('X', Rational(1, 5)) Y = Geometric('Y', Rational(3, 10)) assert coskewness(X, X + Y, X + 2*Y).simplify() == sqrt(230)*Rational(81, 1150) def test_Hermite(): a1 = Symbol("a1", positive=True) a2 = Symbol("a2", negative=True) raises(ValueError, lambda: Hermite("H", a1, a2)) a1 = Symbol("a1", negative=True) a2 = Symbol("a2", positive=True) raises(ValueError, lambda: Hermite("H", a1, a2)) a1 = Symbol("a1", positive=True) x = Symbol("x") H = Hermite("H", a1, a2) assert moment_generating_function(H)(x) == exp(a1*(exp(x) - 1) + a2*(exp(2*x) - 1)) assert characteristic_function(H)(x) == exp(a1*(exp(I*x) - 1) + a2*(exp(2*I*x) - 1)) assert E(H) == a1 + 2*a2 H = Hermite("H", a1=5, a2=4) assert density(H)(2) == 33*exp(-9)/2 assert E(H) == 13 assert variance(H) == 21 assert kurtosis(H) == Rational(464,147) assert skewness(H) == 37*sqrt(21)/441 def test_Logarithmic(): p = S.Half x = Logarithmic('x', p) assert E(x) == -p / ((1 - p) * log(1 - p)) assert variance(x) == -1/log(2)**2 + 2/log(2) assert E(2*x**2 + 3*x + 4) == 4 + 7 / log(2) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert isinstance(E(x, evaluate=False), Expectation) @nocache_fail def test_negative_binomial(): r = 5 p = S.One / 3 x = NegativeBinomial('x', r, p) assert E(x) == p*r / (1-p) # This hangs when run with the cache disabled: assert variance(x) == p*r / (1-p)**2 assert E(x**5 + 2*x + 3) == Rational(9207, 4) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert isinstance(E(x, evaluate=False), Expectation) def test_skellam(): mu1 = Symbol('mu1') mu2 = Symbol('mu2') z = Symbol('z') X = Skellam('x', mu1, mu2) assert density(X)(z) == (mu1/mu2)**(z/2) * \ exp(-mu1 - mu2)*besseli(z, 2*sqrt(mu1*mu2)) assert skewness(X).expand() == mu1/(mu1*sqrt(mu1 + mu2) + mu2 * sqrt(mu1 + mu2)) - mu2/(mu1*sqrt(mu1 + mu2) + mu2*sqrt(mu1 + mu2)) assert variance(X).expand() == mu1 + mu2 assert E(X) == mu1 - mu2 assert characteristic_function(X)(z) == exp( mu1*exp(I*z) - mu1 - mu2 + mu2*exp(-I*z)) assert moment_generating_function(X)(z) == exp( mu1*exp(z) - mu1 - mu2 + mu2*exp(-z)) def test_yule_simon(): from sympy import S rho = S(3) x = YuleSimon('x', rho) assert simplify(E(x)) == rho / (rho - 1) assert simplify(variance(x)) == rho**2 / ((rho - 1)**2 * (rho - 2)) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert isinstance(E(x, evaluate=False), Expectation) # To test the cdf function assert cdf(x)(x) == Piecewise((-beta(floor(x), 4)*floor(x) + 1, x >= 1), (0, True)) def test_zeta(): s = S(5) x = Zeta('x', s) assert E(x) == zeta(s-1) / zeta(s) assert simplify(variance(x)) == ( zeta(s) * zeta(s-2) - zeta(s-1)**2) / zeta(s)**2 def test_discrete_probability(): X = Geometric('X', Rational(1, 5)) Y = Poisson('Y', 4) G = Geometric('e', x) assert P(Eq(X, 3)) == Rational(16, 125) assert P(X < 3) == Rational(9, 25) assert P(X > 3) == Rational(64, 125) assert P(X >= 3) == Rational(16, 25) assert P(X <= 3) == Rational(61, 125) assert P(Ne(X, 3)) == Rational(109, 125) assert P(Eq(Y, 3)) == 32*exp(-4)/3 assert P(Y < 3) == 13*exp(-4) assert P(Y > 3).equals(32*(Rational(-71, 32) + 3*exp(4)/32)*exp(-4)/3) assert P(Y >= 3).equals(32*(Rational(-39, 32) + 3*exp(4)/32)*exp(-4)/3) assert P(Y <= 3) == 71*exp(-4)/3 assert P(Ne(Y, 3)).equals( 13*exp(-4) + 32*(Rational(-71, 32) + 3*exp(4)/32)*exp(-4)/3) assert P(X < S.Infinity) is S.One assert P(X > S.Infinity) is S.Zero assert P(G < 3) == x*(2-x) assert P(Eq(G, 3)) == x*(-x + 1)**2 def test_DiscreteRV(): p = S(1)/2 x = Symbol('x', integer=True, positive=True) pdf = p*(1 - p)**(x - 1) # pdf of Geometric Distribution D = DiscreteRV(x, pdf, set=S.Naturals, check=True) assert E(D) == E(Geometric('G', S(1)/2)) == 2 assert P(D > 3) == S(1)/8 assert D.pspace.domain.set == S.Naturals raises(ValueError, lambda: DiscreteRV(x, x, FiniteSet(*range(4)), check=True)) # purposeful invalid pmf but it should not raise since check=False # see test_drv_types.test_ContinuousRV for explanation X = DiscreteRV(x, 1/x, S.Naturals) assert P(X < 2) == 1 assert E(X) == oo def test_precomputed_characteristic_functions(): import mpmath def test_cf(dist, support_lower_limit, support_upper_limit): pdf = density(dist) t = S('t') x = S('x') # first function is the hardcoded CF of the distribution cf1 = lambdify([t], characteristic_function(dist)(t), 'mpmath') # second function is the Fourier transform of the density function f = lambdify([x, t], pdf(x)*exp(I*x*t), 'mpmath') cf2 = lambda t: mpmath.nsum(lambda x: f(x, t), [ support_lower_limit, support_upper_limit], maxdegree=10) # compare the two functions at various points for test_point in [2, 5, 8, 11]: n1 = cf1(test_point) n2 = cf2(test_point) assert abs(re(n1) - re(n2)) < 1e-12 assert abs(im(n1) - im(n2)) < 1e-12 test_cf(Geometric('g', Rational(1, 3)), 1, mpmath.inf) test_cf(Logarithmic('l', Rational(1, 5)), 1, mpmath.inf) test_cf(NegativeBinomial('n', 5, Rational(1, 7)), 0, mpmath.inf) test_cf(Poisson('p', 5), 0, mpmath.inf) test_cf(YuleSimon('y', 5), 1, mpmath.inf) test_cf(Zeta('z', 5), 1, mpmath.inf) def test_moment_generating_functions(): t = S('t') geometric_mgf = moment_generating_function(Geometric('g', S.Half))(t) assert geometric_mgf.diff(t).subs(t, 0) == 2 logarithmic_mgf = moment_generating_function(Logarithmic('l', S.Half))(t) assert logarithmic_mgf.diff(t).subs(t, 0) == 1/log(2) negative_binomial_mgf = moment_generating_function( NegativeBinomial('n', 5, Rational(1, 3)))(t) assert negative_binomial_mgf.diff(t).subs(t, 0) == Rational(5, 2) poisson_mgf = moment_generating_function(Poisson('p', 5))(t) assert poisson_mgf.diff(t).subs(t, 0) == 5 skellam_mgf = moment_generating_function(Skellam('s', 1, 1))(t) assert skellam_mgf.diff(t).subs( t, 2) == (-exp(-2) + exp(2))*exp(-2 + exp(-2) + exp(2)) yule_simon_mgf = moment_generating_function(YuleSimon('y', 3))(t) assert simplify(yule_simon_mgf.diff(t).subs(t, 0)) == Rational(3, 2) zeta_mgf = moment_generating_function(Zeta('z', 5))(t) assert zeta_mgf.diff(t).subs(t, 0) == pi**4/(90*zeta(5)) def test_Or(): X = Geometric('X', S.Half) P(Or(X < 3, X > 4)) == Rational(13, 16) P(Or(X > 2, X > 1)) == P(X > 1) P(Or(X >= 3, X < 3)) == 1 def test_where(): X = Geometric('X', Rational(1, 5)) Y = Poisson('Y', 4) assert where(X**2 > 4).set == Range(3, S.Infinity, 1) assert where(X**2 >= 4).set == Range(2, S.Infinity, 1) assert where(Y**2 < 9).set == Range(0, 3, 1) assert where(Y**2 <= 9).set == Range(0, 4, 1) def test_conditional(): X = Geometric('X', Rational(2, 3)) Y = Poisson('Y', 3) assert P(X > 2, X > 3) == 1 assert P(X > 3, X > 2) == Rational(1, 3) assert P(Y > 2, Y < 2) == 0 assert P(Eq(Y, 3), Y >= 0) == 9*exp(-3)/2 assert P(Eq(Y, 3), Eq(Y, 2)) == 0 assert P(X < 2, Eq(X, 2)) == 0 assert P(X > 2, Eq(X, 3)) == 1 def test_product_spaces(): X1 = Geometric('X1', S.Half) X2 = Geometric('X2', Rational(1, 3)) #assert str(P(X1 + X2 < 3, evaluate=False)) == """Sum(Piecewise((2**(X2 - n - 2)*(2/3)**(X2 - 1)/6, """\ # + """(-X2 + n + 3 >= 1) & (-X2 + n + 3 < oo)), (0, True)), (X2, 1, oo), (n, -oo, -1))""" n = Dummy('n') with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert P(X1 + X2 < 3, evaluate=False).rewrite(Sum).dummy_eq(Sum(Piecewise((2**(-n)/4, n + 2 >= 1), (0, True)), (n, -oo, -1))/3) #assert str(P(X1 + X2 > 3)) == """Sum(Piecewise((2**(X2 - n - 2)*(2/3)**(X2 - 1)/6, """ +\ # """(-X2 + n + 3 >= 1) & (-X2 + n + 3 < oo)), (0, True)), (X2, 1, oo), (n, 1, oo))""" assert P(X1 + X2 > 3).dummy_eq(Sum(Piecewise((2**(X2 - n - 2)*(Rational(2, 3))**(X2 - 1)/6, -X2 + n + 3 >= 1), (0, True)), (X2, 1, oo), (n, 1, oo))) # assert str(P(Eq(X1 + X2, 3))) == """Sum(Piecewise((2**(X2 - 2)*(2/3)**(X2 - 1)/6, """ +\ # """X2 <= 2), (0, True)), (X2, 1, oo))""" assert P(Eq(X1 + X2, 3)) == Rational(1, 12) sympy-sympy-1.9/sympy/stats/tests/test_error_prop.py000066400000000000000000000034601412543434000232110ustar00rootroot00000000000000from sympy import symbols, exp, Function from sympy.stats.error_prop import variance_prop from sympy.stats.symbolic_probability import (RandomSymbol, Variance, Covariance) def test_variance_prop(): x, y, z = symbols('x y z') phi, t = consts = symbols('phi t') a = RandomSymbol(x) var_x = Variance(a) var_y = Variance(RandomSymbol(y)) var_z = Variance(RandomSymbol(z)) f = Function('f')(x) cases = { x + y: var_x + var_y, a + y: var_x + var_y, x + y + z: var_x + var_y + var_z, 2*x: 4*var_x, x*y: var_x*y**2 + var_y*x**2, 1/x: var_x/x**4, x/y: (var_x*y**2 + var_y*x**2)/y**4, exp(x): var_x*exp(2*x), exp(2*x): 4*var_x*exp(4*x), exp(-x*t): t**2*var_x*exp(-2*t*x), f: Variance(f), } for inp, out in cases.items(): obs = variance_prop(inp, consts=consts) assert out == obs def test_variance_prop_with_covar(): x, y, z = symbols('x y z') phi, t = consts = symbols('phi t') a = RandomSymbol(x) var_x = Variance(a) b = RandomSymbol(y) var_y = Variance(b) c = RandomSymbol(z) var_z = Variance(c) covar_x_y = Covariance(a, b) covar_x_z = Covariance(a, c) covar_y_z = Covariance(b, c) cases = { x + y: var_x + var_y + 2*covar_x_y, a + y: var_x + var_y + 2*covar_x_y, x + y + z: var_x + var_y + var_z + \ 2*covar_x_y + 2*covar_x_z + 2*covar_y_z, 2*x: 4*var_x, x*y: var_x*y**2 + var_y*x**2 + 2*covar_x_y/(x*y), 1/x: var_x/x**4, exp(x): var_x*exp(2*x), exp(2*x): 4*var_x*exp(4*x), exp(-x*t): t**2*var_x*exp(-2*t*x), } for inp, out in cases.items(): obs = variance_prop(inp, consts=consts, include_covar=True) assert out == obs sympy-sympy-1.9/sympy/stats/tests/test_finite_rv.py000066400000000000000000000464201412543434000230100ustar00rootroot00000000000000from sympy import (FiniteSet, S, Symbol, sqrt, nan, beta, Rational, symbols, simplify, Eq, cos, And, Tuple, Or, Dict, sympify, binomial, cancel, exp, I, Piecewise, Sum, Dummy, harmonic, Function) from sympy.matrices import Matrix from sympy.stats import (DiscreteUniform, Die, Bernoulli, Coin, Binomial, BetaBinomial, Hypergeometric, Rademacher, IdealSoliton, RobustSoliton, P, E, variance, covariance, skewness, density, where, FiniteRV, pspace, cdf, correlation, moment, cmoment, smoment, characteristic_function, moment_generating_function, quantile, kurtosis, median, coskewness) from sympy.stats.frv_types import DieDistribution, BinomialDistribution, \ HypergeometricDistribution from sympy.stats.rv import Density from sympy.testing.pytest import raises def BayesTest(A, B): assert P(A, B) == P(And(A, B)) / P(B) assert P(A, B) == P(B, A) * P(A) / P(B) def test_discreteuniform(): # Symbolic a, b, c, t = symbols('a b c t') X = DiscreteUniform('X', [a, b, c]) assert E(X) == (a + b + c)/3 assert simplify(variance(X) - ((a**2 + b**2 + c**2)/3 - (a/3 + b/3 + c/3)**2)) == 0 assert P(Eq(X, a)) == P(Eq(X, b)) == P(Eq(X, c)) == S('1/3') Y = DiscreteUniform('Y', range(-5, 5)) # Numeric assert E(Y) == S('-1/2') assert variance(Y) == S('33/4') assert median(Y) == FiniteSet(-1, 0) for x in range(-5, 5): assert P(Eq(Y, x)) == S('1/10') assert P(Y <= x) == S(x + 6)/10 assert P(Y >= x) == S(5 - x)/10 assert dict(density(Die('D', 6)).items()) == \ dict(density(DiscreteUniform('U', range(1, 7))).items()) assert characteristic_function(X)(t) == exp(I*a*t)/3 + exp(I*b*t)/3 + exp(I*c*t)/3 assert moment_generating_function(X)(t) == exp(a*t)/3 + exp(b*t)/3 + exp(c*t)/3 # issue 18611 raises(ValueError, lambda: DiscreteUniform('Z', [a, a, a, b, b, c])) def test_dice(): # TODO: Make iid method! X, Y, Z = Die('X', 6), Die('Y', 6), Die('Z', 6) a, b, t, p = symbols('a b t p') assert E(X) == 3 + S.Half assert variance(X) == Rational(35, 12) assert E(X + Y) == 7 assert E(X + X) == 7 assert E(a*X + b) == a*E(X) + b assert variance(X + Y) == variance(X) + variance(Y) == cmoment(X + Y, 2) assert variance(X + X) == 4 * variance(X) == cmoment(X + X, 2) assert cmoment(X, 0) == 1 assert cmoment(4*X, 3) == 64*cmoment(X, 3) assert covariance(X, Y) is S.Zero assert covariance(X, X + Y) == variance(X) assert density(Eq(cos(X*S.Pi), 1))[True] == S.Half assert correlation(X, Y) == 0 assert correlation(X, Y) == correlation(Y, X) assert smoment(X + Y, 3) == skewness(X + Y) assert smoment(X + Y, 4) == kurtosis(X + Y) assert smoment(X, 0) == 1 assert P(X > 3) == S.Half assert P(2*X > 6) == S.Half assert P(X > Y) == Rational(5, 12) assert P(Eq(X, Y)) == P(Eq(X, 1)) assert E(X, X > 3) == 5 == moment(X, 1, 0, X > 3) assert E(X, Y > 3) == E(X) == moment(X, 1, 0, Y > 3) assert E(X + Y, Eq(X, Y)) == E(2*X) assert moment(X, 0) == 1 assert moment(5*X, 2) == 25*moment(X, 2) assert quantile(X)(p) == Piecewise((nan, (p > 1) | (p < 0)),\ (S.One, p <= Rational(1, 6)), (S(2), p <= Rational(1, 3)), (S(3), p <= S.Half),\ (S(4), p <= Rational(2, 3)), (S(5), p <= Rational(5, 6)), (S(6), p <= 1)) assert P(X > 3, X > 3) is S.One assert P(X > Y, Eq(Y, 6)) is S.Zero assert P(Eq(X + Y, 12)) == Rational(1, 36) assert P(Eq(X + Y, 12), Eq(X, 6)) == Rational(1, 6) assert density(X + Y) == density(Y + Z) != density(X + X) d = density(2*X + Y**Z) assert d[S(22)] == Rational(1, 108) and d[S(4100)] == Rational(1, 216) and S(3130) not in d assert pspace(X).domain.as_boolean() == Or( *[Eq(X.symbol, i) for i in [1, 2, 3, 4, 5, 6]]) assert where(X > 3).set == FiniteSet(4, 5, 6) assert characteristic_function(X)(t) == exp(6*I*t)/6 + exp(5*I*t)/6 + exp(4*I*t)/6 + exp(3*I*t)/6 + exp(2*I*t)/6 + exp(I*t)/6 assert moment_generating_function(X)(t) == exp(6*t)/6 + exp(5*t)/6 + exp(4*t)/6 + exp(3*t)/6 + exp(2*t)/6 + exp(t)/6 assert median(X) == FiniteSet(3, 4) D = Die('D', 7) assert median(D) == FiniteSet(4) # Bayes test for die BayesTest(X > 3, X + Y < 5) BayesTest(Eq(X - Y, Z), Z > Y) BayesTest(X > 3, X > 2) # arg test for die raises(ValueError, lambda: Die('X', -1)) # issue 8105: negative sides. raises(ValueError, lambda: Die('X', 0)) raises(ValueError, lambda: Die('X', 1.5)) # issue 8103: non integer sides. # symbolic test for die n, k = symbols('n, k', positive=True) D = Die('D', n) dens = density(D).dict assert dens == Density(DieDistribution(n)) assert set(dens.subs(n, 4).doit().keys()) == {1, 2, 3, 4} assert set(dens.subs(n, 4).doit().values()) == {Rational(1, 4)} k = Dummy('k', integer=True) assert E(D).dummy_eq( Sum(Piecewise((k/n, k <= n), (0, True)), (k, 1, n))) assert variance(D).subs(n, 6).doit() == Rational(35, 12) ki = Dummy('ki') cumuf = cdf(D)(k) assert cumuf.dummy_eq( Sum(Piecewise((1/n, (ki >= 1) & (ki <= n)), (0, True)), (ki, 1, k))) assert cumuf.subs({n: 6, k: 2}).doit() == Rational(1, 3) t = Dummy('t') cf = characteristic_function(D)(t) assert cf.dummy_eq( Sum(Piecewise((exp(ki*I*t)/n, (ki >= 1) & (ki <= n)), (0, True)), (ki, 1, n))) assert cf.subs(n, 3).doit() == exp(3*I*t)/3 + exp(2*I*t)/3 + exp(I*t)/3 mgf = moment_generating_function(D)(t) assert mgf.dummy_eq( Sum(Piecewise((exp(ki*t)/n, (ki >= 1) & (ki <= n)), (0, True)), (ki, 1, n))) assert mgf.subs(n, 3).doit() == exp(3*t)/3 + exp(2*t)/3 + exp(t)/3 def test_given(): X = Die('X', 6) assert density(X, X > 5) == {S(6): S.One} assert where(X > 2, X > 5).as_boolean() == Eq(X.symbol, 6) def test_domains(): X, Y = Die('x', 6), Die('y', 6) x, y = X.symbol, Y.symbol # Domains d = where(X > Y) assert d.condition == (x > y) d = where(And(X > Y, Y > 3)) assert d.as_boolean() == Or(And(Eq(x, 5), Eq(y, 4)), And(Eq(x, 6), Eq(y, 5)), And(Eq(x, 6), Eq(y, 4))) assert len(d.elements) == 3 assert len(pspace(X + Y).domain.elements) == 36 Z = Die('x', 4) raises(ValueError, lambda: P(X > Z)) # Two domains with same internal symbol assert pspace(X + Y).domain.set == FiniteSet(1, 2, 3, 4, 5, 6)**2 assert where(X > 3).set == FiniteSet(4, 5, 6) assert X.pspace.domain.dict == FiniteSet( *[Dict({X.symbol: i}) for i in range(1, 7)]) assert where(X > Y).dict == FiniteSet(*[Dict({X.symbol: i, Y.symbol: j}) for i in range(1, 7) for j in range(1, 7) if i > j]) def test_bernoulli(): p, a, b, t = symbols('p a b t') X = Bernoulli('B', p, a, b) assert E(X) == a*p + b*(-p + 1) assert density(X)[a] == p assert density(X)[b] == 1 - p assert characteristic_function(X)(t) == p * exp(I * a * t) + (-p + 1) * exp(I * b * t) assert moment_generating_function(X)(t) == p * exp(a * t) + (-p + 1) * exp(b * t) X = Bernoulli('B', p, 1, 0) z = Symbol("z") assert E(X) == p assert simplify(variance(X)) == p*(1 - p) assert E(a*X + b) == a*E(X) + b assert simplify(variance(a*X + b)) == simplify(a**2 * variance(X)) assert quantile(X)(z) == Piecewise((nan, (z > 1) | (z < 0)), (0, z <= 1 - p), (1, z <= 1)) Y = Bernoulli('Y', Rational(1, 2)) assert median(Y) == FiniteSet(0, 1) Z = Bernoulli('Z', Rational(2, 3)) assert median(Z) == FiniteSet(1) raises(ValueError, lambda: Bernoulli('B', 1.5)) raises(ValueError, lambda: Bernoulli('B', -0.5)) #issue 8248 assert X.pspace.compute_expectation(1) == 1 p = Rational(1, 5) X = Binomial('X', 5, p) Y = Binomial('Y', 7, 2*p) Z = Binomial('Z', 9, 3*p) assert coskewness(Y + Z, X + Y, X + Z).simplify() == 0 assert coskewness(Y + 2*X + Z, X + 2*Y + Z, X + 2*Z + Y).simplify() == \ sqrt(1529)*Rational(12, 16819) assert coskewness(Y + 2*X + Z, X + 2*Y + Z, X + 2*Z + Y, X < 2).simplify() \ == -sqrt(357451121)*Rational(2812, 4646864573) def test_cdf(): D = Die('D', 6) o = S.One assert cdf( D) == sympify({1: o/6, 2: o/3, 3: o/2, 4: 2*o/3, 5: 5*o/6, 6: o}) def test_coins(): C, D = Coin('C'), Coin('D') H, T = symbols('H, T') assert P(Eq(C, D)) == S.Half assert density(Tuple(C, D)) == {(H, H): Rational(1, 4), (H, T): Rational(1, 4), (T, H): Rational(1, 4), (T, T): Rational(1, 4)} assert dict(density(C).items()) == {H: S.Half, T: S.Half} F = Coin('F', Rational(1, 10)) assert P(Eq(F, H)) == Rational(1, 10) d = pspace(C).domain assert d.as_boolean() == Or(Eq(C.symbol, H), Eq(C.symbol, T)) raises(ValueError, lambda: P(C > D)) # Can't intelligently compare H to T def test_binomial_verify_parameters(): raises(ValueError, lambda: Binomial('b', .2, .5)) raises(ValueError, lambda: Binomial('b', 3, 1.5)) def test_binomial_numeric(): nvals = range(5) pvals = [0, Rational(1, 4), S.Half, Rational(3, 4), 1] for n in nvals: for p in pvals: X = Binomial('X', n, p) assert E(X) == n*p assert variance(X) == n*p*(1 - p) if n > 0 and 0 < p < 1: assert skewness(X) == (1 - 2*p)/sqrt(n*p*(1 - p)) assert kurtosis(X) == 3 + (1 - 6*p*(1 - p))/(n*p*(1 - p)) for k in range(n + 1): assert P(Eq(X, k)) == binomial(n, k)*p**k*(1 - p)**(n - k) def test_binomial_quantile(): X = Binomial('X', 50, S.Half) assert quantile(X)(0.95) == S(31) assert median(X) == FiniteSet(25) X = Binomial('X', 5, S.Half) p = Symbol("p", positive=True) assert quantile(X)(p) == Piecewise((nan, p > S.One), (S.Zero, p <= Rational(1, 32)),\ (S.One, p <= Rational(3, 16)), (S(2), p <= S.Half), (S(3), p <= Rational(13, 16)),\ (S(4), p <= Rational(31, 32)), (S(5), p <= S.One)) assert median(X) == FiniteSet(2, 3) def test_binomial_symbolic(): n = 2 p = symbols('p', positive=True) X = Binomial('X', n, p) t = Symbol('t') assert simplify(E(X)) == n*p == simplify(moment(X, 1)) assert simplify(variance(X)) == n*p*(1 - p) == simplify(cmoment(X, 2)) assert cancel(skewness(X) - (1 - 2*p)/sqrt(n*p*(1 - p))) == 0 assert cancel((kurtosis(X)) - (3 + (1 - 6*p*(1 - p))/(n*p*(1 - p)))) == 0 assert characteristic_function(X)(t) == p ** 2 * exp(2 * I * t) + 2 * p * (-p + 1) * exp(I * t) + (-p + 1) ** 2 assert moment_generating_function(X)(t) == p ** 2 * exp(2 * t) + 2 * p * (-p + 1) * exp(t) + (-p + 1) ** 2 # Test ability to change success/failure winnings H, T = symbols('H T') Y = Binomial('Y', n, p, succ=H, fail=T) assert simplify(E(Y) - (n*(H*p + T*(1 - p)))) == 0 # test symbolic dimensions n = symbols('n') B = Binomial('B', n, p) raises(NotImplementedError, lambda: P(B > 2)) assert density(B).dict == Density(BinomialDistribution(n, p, 1, 0)) assert set(density(B).dict.subs(n, 4).doit().keys()) == \ {S.Zero, S.One, S(2), S(3), S(4)} assert set(density(B).dict.subs(n, 4).doit().values()) == \ {(1 - p)**4, 4*p*(1 - p)**3, 6*p**2*(1 - p)**2, 4*p**3*(1 - p), p**4} k = Dummy('k', integer=True) assert E(B > 2).dummy_eq( Sum(Piecewise((k*p**k*(1 - p)**(-k + n)*binomial(n, k), (k >= 0) & (k <= n) & (k > 2)), (0, True)), (k, 0, n))) def test_beta_binomial(): # verify parameters raises(ValueError, lambda: BetaBinomial('b', .2, 1, 2)) raises(ValueError, lambda: BetaBinomial('b', 2, -1, 2)) raises(ValueError, lambda: BetaBinomial('b', 2, 1, -2)) assert BetaBinomial('b', 2, 1, 1) # test numeric values nvals = range(1,5) alphavals = [Rational(1, 4), S.Half, Rational(3, 4), 1, 10] betavals = [Rational(1, 4), S.Half, Rational(3, 4), 1, 10] for n in nvals: for a in alphavals: for b in betavals: X = BetaBinomial('X', n, a, b) assert E(X) == moment(X, 1) assert variance(X) == cmoment(X, 2) # test symbolic n, a, b = symbols('a b n') assert BetaBinomial('x', n, a, b) n = 2 # Because we're using for loops, can't do symbolic n a, b = symbols('a b', positive=True) X = BetaBinomial('X', n, a, b) t = Symbol('t') assert E(X).expand() == moment(X, 1).expand() assert variance(X).expand() == cmoment(X, 2).expand() assert skewness(X) == smoment(X, 3) assert characteristic_function(X)(t) == exp(2*I*t)*beta(a + 2, b)/beta(a, b) +\ 2*exp(I*t)*beta(a + 1, b + 1)/beta(a, b) + beta(a, b + 2)/beta(a, b) assert moment_generating_function(X)(t) == exp(2*t)*beta(a + 2, b)/beta(a, b) +\ 2*exp(t)*beta(a + 1, b + 1)/beta(a, b) + beta(a, b + 2)/beta(a, b) def test_hypergeometric_numeric(): for N in range(1, 5): for m in range(0, N + 1): for n in range(1, N + 1): X = Hypergeometric('X', N, m, n) N, m, n = map(sympify, (N, m, n)) assert sum(density(X).values()) == 1 assert E(X) == n * m / N if N > 1: assert variance(X) == n*(m/N)*(N - m)/N*(N - n)/(N - 1) # Only test for skewness when defined if N > 2 and 0 < m < N and n < N: assert skewness(X) == simplify((N - 2*m)*sqrt(N - 1)*(N - 2*n) / (sqrt(n*m*(N - m)*(N - n))*(N - 2))) def test_hypergeometric_symbolic(): N, m, n = symbols('N, m, n') H = Hypergeometric('H', N, m, n) dens = density(H).dict expec = E(H > 2) assert dens == Density(HypergeometricDistribution(N, m, n)) assert dens.subs(N, 5).doit() == Density(HypergeometricDistribution(5, m, n)) assert set(dens.subs({N: 3, m: 2, n: 1}).doit().keys()) == {S.Zero, S.One} assert set(dens.subs({N: 3, m: 2, n: 1}).doit().values()) == {Rational(1, 3), Rational(2, 3)} k = Dummy('k', integer=True) assert expec.dummy_eq( Sum(Piecewise((k*binomial(m, k)*binomial(N - m, -k + n) /binomial(N, n), k > 2), (0, True)), (k, 0, n))) def test_rademacher(): X = Rademacher('X') t = Symbol('t') assert E(X) == 0 assert variance(X) == 1 assert density(X)[-1] == S.Half assert density(X)[1] == S.Half assert characteristic_function(X)(t) == exp(I*t)/2 + exp(-I*t)/2 assert moment_generating_function(X)(t) == exp(t) / 2 + exp(-t) / 2 def test_ideal_soliton(): raises(ValueError, lambda : IdealSoliton('sol', -12)) raises(ValueError, lambda : IdealSoliton('sol', 13.2)) raises(ValueError, lambda : IdealSoliton('sol', 0)) f = Function('f') raises(ValueError, lambda : density(IdealSoliton('sol', 10)).pmf(f)) k = Symbol('k', integer=True, positive=True) x = Symbol('x', integer=True, positive=True) t = Symbol('t') sol = IdealSoliton('sol', k) assert density(sol).low == S.One assert density(sol).high == k assert density(sol).dict == Density(density(sol)) assert density(sol).pmf(x) == Piecewise((1/k, Eq(x, 1)), (1/(x*(x - 1)), k >= x), (0, True)) k_vals = [5, 20, 50, 100, 1000] for i in k_vals: assert E(sol.subs(k, i)) == harmonic(i) == moment(sol.subs(k, i), 1) assert variance(sol.subs(k, i)) == (i - 1) + harmonic(i) - harmonic(i)**2 == cmoment(sol.subs(k, i),2) assert skewness(sol.subs(k, i)) == smoment(sol.subs(k, i), 3) assert kurtosis(sol.subs(k, i)) == smoment(sol.subs(k, i), 4) assert exp(I*t)/10 + Sum(exp(I*t*x)/(x*x - x), (x, 2, k)).subs(k, 10).doit() == characteristic_function(sol.subs(k, 10))(t) assert exp(t)/10 + Sum(exp(t*x)/(x*x - x), (x, 2, k)).subs(k, 10).doit() == moment_generating_function(sol.subs(k, 10))(t) def test_robust_soliton(): raises(ValueError, lambda : RobustSoliton('robSol', -12, 0.1, 0.02)) raises(ValueError, lambda : RobustSoliton('robSol', 13, 1.89, 0.1)) raises(ValueError, lambda : RobustSoliton('robSol', 15, 0.6, -2.31)) f = Function('f') raises(ValueError, lambda : density(RobustSoliton('robSol', 15, 0.6, 0.1)).pmf(f)) k = Symbol('k', integer=True, positive=True) delta = Symbol('delta', positive=True) c = Symbol('c', positive=True) robSol = RobustSoliton('robSol', k, delta, c) assert density(robSol).low == 1 assert density(robSol).high == k k_vals = [10, 20, 50] delta_vals = [0.2, 0.4, 0.6] c_vals = [0.01, 0.03, 0.05] for x in k_vals: for y in delta_vals: for z in c_vals: assert E(robSol.subs({k: x, delta: y, c: z})) == moment(robSol.subs({k: x, delta: y, c: z}), 1) assert variance(robSol.subs({k: x, delta: y, c: z})) == cmoment(robSol.subs({k: x, delta: y, c: z}), 2) assert skewness(robSol.subs({k: x, delta: y, c: z})) == smoment(robSol.subs({k: x, delta: y, c: z}), 3) assert kurtosis(robSol.subs({k: x, delta: y, c: z})) == smoment(robSol.subs({k: x, delta: y, c: z}), 4) def test_FiniteRV(): F = FiniteRV('F', {1: S.Half, 2: Rational(1, 4), 3: Rational(1, 4)}, check=True) p = Symbol("p", positive=True) assert dict(density(F).items()) == {S.One: S.Half, S(2): Rational(1, 4), S(3): Rational(1, 4)} assert P(F >= 2) == S.Half assert quantile(F)(p) == Piecewise((nan, p > S.One), (S.One, p <= S.Half),\ (S(2), p <= Rational(3, 4)),(S(3), True)) assert pspace(F).domain.as_boolean() == Or( *[Eq(F.symbol, i) for i in [1, 2, 3]]) assert F.pspace.domain.set == FiniteSet(1, 2, 3) raises(ValueError, lambda: FiniteRV('F', {1: S.Half, 2: S.Half, 3: S.Half}, check=True)) raises(ValueError, lambda: FiniteRV('F', {1: S.Half, 2: Rational(-1, 2), 3: S.One}, check=True)) raises(ValueError, lambda: FiniteRV('F', {1: S.One, 2: Rational(3, 2), 3: S.Zero,\ 4: Rational(-1, 2), 5: Rational(-3, 4), 6: Rational(-1, 4)}, check=True)) # purposeful invalid pmf but it should not raise since check=False # see test_drv_types.test_ContinuousRV for explanation X = FiniteRV('X', {1: 1, 2: 2}) assert E(X) == 5 assert P(X <= 2) + P(X > 2) != 1 def test_density_call(): from sympy.abc import p x = Bernoulli('x', p) d = density(x) assert d(0) == 1 - p assert d(S.Zero) == 1 - p assert d(5) == 0 assert 0 in d assert 5 not in d assert d(S.Zero) == d[S.Zero] def test_DieDistribution(): from sympy.abc import x X = DieDistribution(6) assert X.pmf(S.Half) is S.Zero assert X.pmf(x).subs({x: 1}).doit() == Rational(1, 6) assert X.pmf(x).subs({x: 7}).doit() == 0 assert X.pmf(x).subs({x: -1}).doit() == 0 assert X.pmf(x).subs({x: Rational(1, 3)}).doit() == 0 raises(ValueError, lambda: X.pmf(Matrix([0, 0]))) raises(ValueError, lambda: X.pmf(x**2 - 1)) def test_FinitePSpace(): X = Die('X', 6) space = pspace(X) assert space.density == DieDistribution(6) def test_symbolic_conditions(): B = Bernoulli('B', Rational(1, 4)) D = Die('D', 4) b, n = symbols('b, n') Y = P(Eq(B, b)) Z = E(D > n) assert Y == \ Piecewise((Rational(1, 4), Eq(b, 1)), (0, True)) + \ Piecewise((Rational(3, 4), Eq(b, 0)), (0, True)) assert Z == \ Piecewise((Rational(1, 4), n < 1), (0, True)) + Piecewise((S.Half, n < 2), (0, True)) + \ Piecewise((Rational(3, 4), n < 3), (0, True)) + Piecewise((S.One, n < 4), (0, True)) sympy-sympy-1.9/sympy/stats/tests/test_joint_rv.py000066400000000000000000000406621412543434000226570ustar00rootroot00000000000000from sympy import (symbols, pi, oo, S, exp, sqrt, besselk, Indexed, Sum, simplify, Rational, factorial, gamma, Piecewise, Eq, Product, Interval, IndexedBase, RisingFactorial, polar_lift, ProductSet, Range, eye, Determinant) from sympy.core.numbers import comp from sympy.integrals.integrals import integrate from sympy.matrices import Matrix, MatrixSymbol from sympy.matrices.expressions.matexpr import MatrixElement from sympy.stats import density, median, marginal_distribution, Normal, Laplace, E, sample from sympy.stats.joint_rv_types import (JointRV, MultivariateNormalDistribution, JointDistributionHandmade, MultivariateT, NormalGamma, GeneralizedMultivariateLogGammaOmega as GMVLGO, MultivariateBeta, GeneralizedMultivariateLogGamma as GMVLG, MultivariateEwens, Multinomial, NegativeMultinomial, MultivariateNormal, MultivariateLaplace) from sympy.testing.pytest import raises, XFAIL, skip from sympy.external import import_module x, y, z, a, b = symbols('x y z a b') def test_Normal(): m = Normal('A', [1, 2], [[1, 0], [0, 1]]) A = MultivariateNormal('A', [1, 2], [[1, 0], [0, 1]]) assert m == A assert density(m)(1, 2) == 1/(2*pi) assert m.pspace.distribution.set == ProductSet(S.Reals, S.Reals) raises (ValueError, lambda:m[2]) n = Normal('B', [1, 2, 3], [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) p = Normal('C', Matrix([1, 2]), Matrix([[1, 0], [0, 1]])) assert density(m)(x, y) == density(p)(x, y) assert marginal_distribution(n, 0, 1)(1, 2) == 1/(2*pi) raises(ValueError, lambda: marginal_distribution(m)) assert integrate(density(m)(x, y), (x, -oo, oo), (y, -oo, oo)).evalf() == 1 N = Normal('N', [1, 2], [[x, 0], [0, y]]) assert density(N)(0, 0) == exp(-((4*x + y)/(2*x*y)))/(2*pi*sqrt(x*y)) raises (ValueError, lambda: Normal('M', [1, 2], [[1, 1], [1, -1]])) # symbolic n = symbols('n', natural=True) mu = MatrixSymbol('mu', n, 1) sigma = MatrixSymbol('sigma', n, n) X = Normal('X', mu, sigma) assert density(X) == MultivariateNormalDistribution(mu, sigma) raises (NotImplementedError, lambda: median(m)) # Below tests should work after issue #17267 is resolved # assert E(X) == mu # assert variance(X) == sigma # test symbolic multivariate normal densities n = 3 Sg = MatrixSymbol('Sg', n, n) mu = MatrixSymbol('mu', n, 1) obs = MatrixSymbol('obs', n, 1) X = MultivariateNormal('X', mu, Sg) density_X = density(X) eval_a = density_X(obs).subs({Sg: eye(3), mu: Matrix([0, 0, 0]), obs: Matrix([0, 0, 0])}).doit() eval_b = density_X(0, 0, 0).subs({Sg: eye(3), mu: Matrix([0, 0, 0])}).doit() assert eval_a == sqrt(2)/(4*pi**Rational(3/2)) assert eval_b == sqrt(2)/(4*pi**Rational(3/2)) n = symbols('n', natural=True) Sg = MatrixSymbol('Sg', n, n) mu = MatrixSymbol('mu', n, 1) obs = MatrixSymbol('obs', n, 1) X = MultivariateNormal('X', mu, Sg) density_X_at_obs = density(X)(obs) expected_density = MatrixElement( exp((S(1)/2) * (mu.T - obs.T) * Sg**(-1) * (-mu + obs)) / \ sqrt((2*pi)**n * Determinant(Sg)), 0, 0) assert density_X_at_obs == expected_density def test_MultivariateTDist(): t1 = MultivariateT('T', [0, 0], [[1, 0], [0, 1]], 2) assert(density(t1))(1, 1) == 1/(8*pi) assert t1.pspace.distribution.set == ProductSet(S.Reals, S.Reals) assert integrate(density(t1)(x, y), (x, -oo, oo), \ (y, -oo, oo)).evalf() == 1 raises(ValueError, lambda: MultivariateT('T', [1, 2], [[1, 1], [1, -1]], 1)) t2 = MultivariateT('t2', [1, 2], [[x, 0], [0, y]], 1) assert density(t2)(1, 2) == 1/(2*pi*sqrt(x*y)) def test_multivariate_laplace(): raises(ValueError, lambda: Laplace('T', [1, 2], [[1, 2], [2, 1]])) L = Laplace('L', [1, 0], [[1, 0], [0, 1]]) L2 = MultivariateLaplace('L2', [1, 0], [[1, 0], [0, 1]]) assert density(L)(2, 3) == exp(2)*besselk(0, sqrt(39))/pi L1 = Laplace('L1', [1, 2], [[x, 0], [0, y]]) assert density(L1)(0, 1) == \ exp(2/y)*besselk(0, sqrt((2 + 4/y + 1/x)/y))/(pi*sqrt(x*y)) assert L.pspace.distribution.set == ProductSet(S.Reals, S.Reals) assert L.pspace.distribution == L2.pspace.distribution def test_NormalGamma(): ng = NormalGamma('G', 1, 2, 3, 4) assert density(ng)(1, 1) == 32*exp(-4)/sqrt(pi) assert ng.pspace.distribution.set == ProductSet(S.Reals, Interval(0, oo)) raises(ValueError, lambda:NormalGamma('G', 1, 2, 3, -1)) assert marginal_distribution(ng, 0)(1) == \ 3*sqrt(10)*gamma(Rational(7, 4))/(10*sqrt(pi)*gamma(Rational(5, 4))) assert marginal_distribution(ng, y)(1) == exp(Rational(-1, 4))/128 assert marginal_distribution(ng,[0,1])(x) == x**2*exp(-x/4)/128 def test_GeneralizedMultivariateLogGammaDistribution(): h = S.Half omega = Matrix([[1, h, h, h], [h, 1, h, h], [h, h, 1, h], [h, h, h, 1]]) v, l, mu = (4, [1, 2, 3, 4], [1, 2, 3, 4]) y_1, y_2, y_3, y_4 = symbols('y_1:5', real=True) delta = symbols('d', positive=True) G = GMVLGO('G', omega, v, l, mu) Gd = GMVLG('Gd', delta, v, l, mu) dend = ("d**4*Sum(4*24**(-n - 4)*(1 - d)**n*exp((n + 4)*(y_1 + 2*y_2 + 3*y_3 " "+ 4*y_4) - exp(y_1) - exp(2*y_2)/2 - exp(3*y_3)/3 - exp(4*y_4)/4)/" "(gamma(n + 1)*gamma(n + 4)**3), (n, 0, oo))") assert str(density(Gd)(y_1, y_2, y_3, y_4)) == dend den = ("5*2**(2/3)*5**(1/3)*Sum(4*24**(-n - 4)*(-2**(2/3)*5**(1/3)/4 + 1)**n*" "exp((n + 4)*(y_1 + 2*y_2 + 3*y_3 + 4*y_4) - exp(y_1) - exp(2*y_2)/2 - " "exp(3*y_3)/3 - exp(4*y_4)/4)/(gamma(n + 1)*gamma(n + 4)**3), (n, 0, oo))/64") assert str(density(G)(y_1, y_2, y_3, y_4)) == den marg = ("5*2**(2/3)*5**(1/3)*exp(4*y_1)*exp(-exp(y_1))*Integral(exp(-exp(4*G[3])" "/4)*exp(16*G[3])*Integral(exp(-exp(3*G[2])/3)*exp(12*G[2])*Integral(exp(" "-exp(2*G[1])/2)*exp(8*G[1])*Sum((-1/4)**n*(-4 + 2**(2/3)*5**(1/3" "))**n*exp(n*y_1)*exp(2*n*G[1])*exp(3*n*G[2])*exp(4*n*G[3])/(24**n*gamma(n + 1)" "*gamma(n + 4)**3), (n, 0, oo)), (G[1], -oo, oo)), (G[2], -oo, oo)), (G[3]" ", -oo, oo))/5308416") assert str(marginal_distribution(G, G[0])(y_1)) == marg omega_f1 = Matrix([[1, h, h]]) omega_f2 = Matrix([[1, h, h, h], [h, 1, 2, h], [h, h, 1, h], [h, h, h, 1]]) omega_f3 = Matrix([[6, h, h, h], [h, 1, 2, h], [h, h, 1, h], [h, h, h, 1]]) v_f = symbols("v_f", positive=False, real=True) l_f = [1, 2, v_f, 4] m_f = [v_f, 2, 3, 4] omega_f4 = Matrix([[1, h, h, h, h], [h, 1, h, h, h], [h, h, 1, h, h], [h, h, h, 1, h], [h, h, h, h, 1]]) l_f1 = [1, 2, 3, 4, 5] omega_f5 = Matrix([[1]]) mu_f5 = l_f5 = [1] raises(ValueError, lambda: GMVLGO('G', omega_f1, v, l, mu)) raises(ValueError, lambda: GMVLGO('G', omega_f2, v, l, mu)) raises(ValueError, lambda: GMVLGO('G', omega_f3, v, l, mu)) raises(ValueError, lambda: GMVLGO('G', omega, v_f, l, mu)) raises(ValueError, lambda: GMVLGO('G', omega, v, l_f, mu)) raises(ValueError, lambda: GMVLGO('G', omega, v, l, m_f)) raises(ValueError, lambda: GMVLGO('G', omega_f4, v, l, mu)) raises(ValueError, lambda: GMVLGO('G', omega, v, l_f1, mu)) raises(ValueError, lambda: GMVLGO('G', omega_f5, v, l_f5, mu_f5)) raises(ValueError, lambda: GMVLG('G', Rational(3, 2), v, l, mu)) def test_MultivariateBeta(): a1, a2 = symbols('a1, a2', positive=True) a1_f, a2_f = symbols('a1, a2', positive=False, real=True) mb = MultivariateBeta('B', [a1, a2]) mb_c = MultivariateBeta('C', a1, a2) assert density(mb)(1, 2) == S(2)**(a2 - 1)*gamma(a1 + a2)/\ (gamma(a1)*gamma(a2)) assert marginal_distribution(mb_c, 0)(3) == S(3)**(a1 - 1)*gamma(a1 + a2)/\ (a2*gamma(a1)*gamma(a2)) raises(ValueError, lambda: MultivariateBeta('b1', [a1_f, a2])) raises(ValueError, lambda: MultivariateBeta('b2', [a1, a2_f])) raises(ValueError, lambda: MultivariateBeta('b3', [0, 0])) raises(ValueError, lambda: MultivariateBeta('b4', [a1_f, a2_f])) assert mb.pspace.distribution.set == ProductSet(Interval(0, 1), Interval(0, 1)) def test_MultivariateEwens(): n, theta, i = symbols('n theta i', positive=True) # tests for integer dimensions theta_f = symbols('t_f', negative=True) a = symbols('a_1:4', positive = True, integer = True) ed = MultivariateEwens('E', 3, theta) assert density(ed)(a[0], a[1], a[2]) == Piecewise((6*2**(-a[1])*3**(-a[2])* theta**a[0]*theta**a[1]*theta**a[2]/ (theta*(theta + 1)*(theta + 2)* factorial(a[0])*factorial(a[1])* factorial(a[2])), Eq(a[0] + 2*a[1] + 3*a[2], 3)), (0, True)) assert marginal_distribution(ed, ed[1])(a[1]) == Piecewise((6*2**(-a[1])* theta**a[1]/((theta + 1)* (theta + 2)*factorial(a[1])), Eq(2*a[1] + 1, 3)), (0, True)) raises(ValueError, lambda: MultivariateEwens('e1', 5, theta_f)) assert ed.pspace.distribution.set == ProductSet(Range(0, 4, 1), Range(0, 2, 1), Range(0, 2, 1)) # tests for symbolic dimensions eds = MultivariateEwens('E', n, theta) a = IndexedBase('a') j, k = symbols('j, k') den = Piecewise((factorial(n)*Product(theta**a[j]*(j + 1)**(-a[j])/ factorial(a[j]), (j, 0, n - 1))/RisingFactorial(theta, n), Eq(n, Sum((k + 1)*a[k], (k, 0, n - 1)))), (0, True)) assert density(eds)(a).dummy_eq(den) def test_Multinomial(): n, x1, x2, x3, x4 = symbols('n, x1, x2, x3, x4', nonnegative=True, integer=True) p1, p2, p3, p4 = symbols('p1, p2, p3, p4', positive=True) p1_f, n_f = symbols('p1_f, n_f', negative=True) M = Multinomial('M', n, [p1, p2, p3, p4]) C = Multinomial('C', 3, p1, p2, p3) f = factorial assert density(M)(x1, x2, x3, x4) == Piecewise((p1**x1*p2**x2*p3**x3*p4**x4* f(n)/(f(x1)*f(x2)*f(x3)*f(x4)), Eq(n, x1 + x2 + x3 + x4)), (0, True)) assert marginal_distribution(C, C[0])(x1).subs(x1, 1) ==\ 3*p1*p2**2 +\ 6*p1*p2*p3 +\ 3*p1*p3**2 raises(ValueError, lambda: Multinomial('b1', 5, [p1, p2, p3, p1_f])) raises(ValueError, lambda: Multinomial('b2', n_f, [p1, p2, p3, p4])) raises(ValueError, lambda: Multinomial('b3', n, 0.5, 0.4, 0.3, 0.1)) def test_NegativeMultinomial(): k0, x1, x2, x3, x4 = symbols('k0, x1, x2, x3, x4', nonnegative=True, integer=True) p1, p2, p3, p4 = symbols('p1, p2, p3, p4', positive=True) p1_f = symbols('p1_f', negative=True) N = NegativeMultinomial('N', 4, [p1, p2, p3, p4]) C = NegativeMultinomial('C', 4, 0.1, 0.2, 0.3) g = gamma f = factorial assert simplify(density(N)(x1, x2, x3, x4) - p1**x1*p2**x2*p3**x3*p4**x4*(-p1 - p2 - p3 - p4 + 1)**4*g(x1 + x2 + x3 + x4 + 4)/(6*f(x1)*f(x2)*f(x3)*f(x4))) is S.Zero assert comp(marginal_distribution(C, C[0])(1).evalf(), 0.33, .01) raises(ValueError, lambda: NegativeMultinomial('b1', 5, [p1, p2, p3, p1_f])) raises(ValueError, lambda: NegativeMultinomial('b2', k0, 0.5, 0.4, 0.3, 0.4)) assert N.pspace.distribution.set == ProductSet(Range(0, oo, 1), Range(0, oo, 1), Range(0, oo, 1), Range(0, oo, 1)) def test_JointPSpace_marginal_distribution(): T = MultivariateT('T', [0, 0], [[1, 0], [0, 1]], 2) assert marginal_distribution(T, T[1])(x) == sqrt(2)*(x**2 + 2)/( 8*polar_lift(x**2/2 + 1)**Rational(5, 2)) assert integrate(marginal_distribution(T, 1)(x), (x, -oo, oo)) == 1 t = MultivariateT('T', [0, 0, 0], [[1, 0, 0], [0, 1, 0], [0, 0, 1]], 3) assert comp(marginal_distribution(t, 0)(1).evalf(), 0.2, .01) def test_JointRV(): x1, x2 = (Indexed('x', i) for i in (1, 2)) pdf = exp(-x1**2/2 + x1 - x2**2/2 - S.Half)/(2*pi) X = JointRV('x', pdf) assert density(X)(1, 2) == exp(-2)/(2*pi) assert isinstance(X.pspace.distribution, JointDistributionHandmade) assert marginal_distribution(X, 0)(2) == sqrt(2)*exp(Rational(-1, 2))/(2*sqrt(pi)) def test_expectation(): m = Normal('A', [x, y], [[1, 0], [0, 1]]) assert simplify(E(m[1])) == y @XFAIL def test_joint_vector_expectation(): m = Normal('A', [x, y], [[1, 0], [0, 1]]) assert E(m) == (x, y) def test_sample_numpy(): distribs_numpy = [ MultivariateNormal("M", [3, 4], [[2, 1], [1, 2]]), MultivariateBeta("B", [0.4, 5, 15, 50, 203]), Multinomial("N", 50, [0.3, 0.2, 0.1, 0.25, 0.15]) ] size = 3 numpy = import_module('numpy') if not numpy: skip('Numpy is not installed. Abort tests for _sample_numpy.') else: for X in distribs_numpy: samps = sample(X, size=size, library='numpy') for sam in samps: assert tuple(sam) in X.pspace.distribution.set N_c = NegativeMultinomial('N', 3, 0.1, 0.1, 0.1) raises(NotImplementedError, lambda: sample(N_c, library='numpy')) def test_sample_scipy(): distribs_scipy = [ MultivariateNormal("M", [0, 0], [[0.1, 0.025], [0.025, 0.1]]), MultivariateBeta("B", [0.4, 5, 15]), Multinomial("N", 8, [0.3, 0.2, 0.1, 0.4]) ] size = 3 scipy = import_module('scipy') if not scipy: skip('Scipy not installed. Abort tests for _sample_scipy.') else: for X in distribs_scipy: samps = sample(X, size=size) samps2 = sample(X, size=(2, 2)) for sam in samps: assert tuple(sam) in X.pspace.distribution.set for i in range(2): for j in range(2): assert tuple(samps2[i][j]) in X.pspace.distribution.set N_c = NegativeMultinomial('N', 3, 0.1, 0.1, 0.1) raises(NotImplementedError, lambda: sample(N_c)) def test_sample_pymc3(): distribs_pymc3 = [ MultivariateNormal("M", [5, 2], [[1, 0], [0, 1]]), MultivariateBeta("B", [0.4, 5, 15]), Multinomial("N", 4, [0.3, 0.2, 0.1, 0.4]) ] size = 3 pymc3 = import_module('pymc3') if not pymc3: skip('PyMC3 is not installed. Abort tests for _sample_pymc3.') else: for X in distribs_pymc3: samps = sample(X, size=size, library='pymc3') for sam in samps: assert tuple(sam.flatten()) in X.pspace.distribution.set N_c = NegativeMultinomial('N', 3, 0.1, 0.1, 0.1) raises(NotImplementedError, lambda: sample(N_c, library='pymc3')) def test_sample_seed(): x1, x2 = (Indexed('x', i) for i in (1, 2)) pdf = exp(-x1**2/2 + x1 - x2**2/2 - S.Half)/(2*pi) X = JointRV('x', pdf) libraries = ['scipy', 'numpy', 'pymc3'] for lib in libraries: try: imported_lib = import_module(lib) if imported_lib: s0, s1, s2 = [], [], [] s0 = sample(X, size=10, library=lib, seed=0) s1 = sample(X, size=10, library=lib, seed=0) s2 = sample(X, size=10, library=lib, seed=1) assert all(s0 == s1) assert all(s1 != s2) except NotImplementedError: continue def test_issue_21057(): m = Normal("x", [0, 0], [[0, 0], [0, 0]]) n = MultivariateNormal("x", [0, 0], [[0, 0], [0, 0]]) p = Normal("x", [0, 0], [[0, 0], [0, 1]]) assert m == n libraries = ['scipy', 'numpy', 'pymc3'] for library in libraries: try: imported_lib = import_module(library) if imported_lib: s1 = sample(m, size=8) s2 = sample(n, size=8) s3 = sample(p, size=8) assert tuple(s1.flatten()) == tuple(s2.flatten()) for s in s3: assert tuple(s.flatten()) in p.pspace.distribution.set except NotImplementedError: continue sympy-sympy-1.9/sympy/stats/tests/test_matrix_distributions.py000066400000000000000000000206021412543434000253030ustar00rootroot00000000000000from sympy import exp, S, sqrt, pi, symbols, Product, gamma, Dummy from sympy.matrices import Determinant, Matrix, Trace, MatrixSymbol, MatrixSet from sympy.stats import density, sample from sympy.stats.matrix_distributions import (MatrixGammaDistribution, MatrixGamma, MatrixPSpace, Wishart, MatrixNormal, MatrixStudentT) from sympy.testing.pytest import raises, skip from sympy.external import import_module def test_MatrixPSpace(): M = MatrixGammaDistribution(1, 2, [[2, 1], [1, 2]]) MP = MatrixPSpace('M', M, 2, 2) assert MP.distribution == M raises(ValueError, lambda: MatrixPSpace('M', M, 1.2, 2)) def test_MatrixGamma(): M = MatrixGamma('M', 1, 2, [[1, 0], [0, 1]]) assert M.pspace.distribution.set == MatrixSet(2, 2, S.Reals) assert isinstance(density(M), MatrixGammaDistribution) X = MatrixSymbol('X', 2, 2) num = exp(Trace(Matrix([[-S(1)/2, 0], [0, -S(1)/2]])*X)) assert density(M)(X).doit() == num/(4*pi*sqrt(Determinant(X))) assert density(M)([[2, 1], [1, 2]]).doit() == sqrt(3)*exp(-2)/(12*pi) X = MatrixSymbol('X', 1, 2) Y = MatrixSymbol('Y', 1, 2) assert density(M)([X, Y]).doit() == exp(-X[0, 0]/2 - Y[0, 1]/2)/(4*pi*sqrt( X[0, 0]*Y[0, 1] - X[0, 1]*Y[0, 0])) # symbolic a, b = symbols('a b', positive=True) d = symbols('d', positive=True, integer=True) Y = MatrixSymbol('Y', d, d) Z = MatrixSymbol('Z', 2, 2) SM = MatrixSymbol('SM', d, d) M2 = MatrixGamma('M2', a, b, SM) M3 = MatrixGamma('M3', 2, 3, [[2, 1], [1, 2]]) k = Dummy('k') exprd = pi**(-d*(d - 1)/4)*b**(-a*d)*exp(Trace((-1/b)*SM**(-1)*Y) )*Determinant(SM)**(-a)*Determinant(Y)**(a - d/2 - S(1)/2)/Product( gamma(-k/2 + a + S(1)/2), (k, 1, d)) assert density(M2)(Y).dummy_eq(exprd) raises(NotImplementedError, lambda: density(M3 + M)(Z)) raises(ValueError, lambda: density(M)(1)) raises(ValueError, lambda: MatrixGamma('M', -1, 2, [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixGamma('M', -1, -2, [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixGamma('M', -1, 2, [[1, 0], [2, 1]])) raises(ValueError, lambda: MatrixGamma('M', -1, 2, [[1, 0], [0]])) def test_Wishart(): W = Wishart('W', 5, [[1, 0], [0, 1]]) assert W.pspace.distribution.set == MatrixSet(2, 2, S.Reals) X = MatrixSymbol('X', 2, 2) term1 = exp(Trace(Matrix([[-S(1)/2, 0], [0, -S(1)/2]])*X)) assert density(W)(X).doit() == term1 * Determinant(X)/(24*pi) assert density(W)([[2, 1], [1, 2]]).doit() == exp(-2)/(8*pi) n = symbols('n', positive=True) d = symbols('d', positive=True, integer=True) Y = MatrixSymbol('Y', d, d) SM = MatrixSymbol('SM', d, d) W = Wishart('W', n, SM) k = Dummy('k') exprd = 2**(-d*n/2)*pi**(-d*(d - 1)/4)*exp(Trace(-(S(1)/2)*SM**(-1)*Y) )*Determinant(SM)**(-n/2)*Determinant(Y)**( -d/2 + n/2 - S(1)/2)/Product(gamma(-k/2 + n/2 + S(1)/2), (k, 1, d)) assert density(W)(Y).dummy_eq(exprd) raises(ValueError, lambda: density(W)(1)) raises(ValueError, lambda: Wishart('W', -1, [[1, 0], [0, 1]])) raises(ValueError, lambda: Wishart('W', -1, [[1, 0], [2, 1]])) raises(ValueError, lambda: Wishart('W', 2, [[1, 0], [0]])) def test_MatrixNormal(): M = MatrixNormal('M', [[5, 6]], [4], [[2, 1], [1, 2]]) assert M.pspace.distribution.set == MatrixSet(1, 2, S.Reals) X = MatrixSymbol('X', 1, 2) term1 = exp(-Trace(Matrix([[ S(2)/3, -S(1)/3], [-S(1)/3, S(2)/3]])*( Matrix([[-5], [-6]]) + X.T)*Matrix([[1/4]])*(Matrix([[-5, -6]]) + X))/2) assert density(M)(X).doit() == term1/(24*pi) assert density(M)([[7, 8]]).doit() == exp(-S(1)/3)/(24*pi) d, n = symbols('d n', positive=True, integer=True) SM2 = MatrixSymbol('SM2', d, d) SM1 = MatrixSymbol('SM1', n, n) LM = MatrixSymbol('LM', n, d) Y = MatrixSymbol('Y', n, d) M = MatrixNormal('M', LM, SM1, SM2) exprd = 4*(2*pi)**(-d*n/2)*exp(-Trace(SM2**(-1)*(-LM.T + Y.T)*SM1**(-1)*(-LM + Y) )/2)*Determinant(SM1)**(-d)*Determinant(SM2)**(-n) assert density(M)(Y).doit() == exprd raises(ValueError, lambda: density(M)(1)) raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [0, 1]], [[1, 0], [2, 1]])) raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [2, 1]], [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [0, 1]], [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [2]], [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixNormal('M', [1, 2], [[1, 0], [2, 1]], [[1, 0], [0]])) raises(ValueError, lambda: MatrixNormal('M', [[1, 2]], [[1, 0], [0, 1]], [[1, 0]])) raises(ValueError, lambda: MatrixNormal('M', [[1, 2]], [1], [[1, 0]])) def test_MatrixStudentT(): M = MatrixStudentT('M', 2, [[5, 6]], [[2, 1], [1, 2]], [4]) assert M.pspace.distribution.set == MatrixSet(1, 2, S.Reals) X = MatrixSymbol('X', 1, 2) D = pi ** (-1.0) * Determinant(Matrix([[4]])) ** (-1.0) * Determinant(Matrix([[2, 1], [1, 2]])) \ ** (-0.5) / Determinant(Matrix([[S(1) / 4]]) * (Matrix([[-5, -6]]) + X) * Matrix([[S(2) / 3, -S(1) / 3], [-S(1) / 3, S(2) / 3]]) * ( Matrix([[-5], [-6]]) + X.T) + Matrix([[1]])) ** 2 assert density(M)(X) == D v = symbols('v', positive=True) n, p = 1, 2 Omega = MatrixSymbol('Omega', p, p) Sigma = MatrixSymbol('Sigma', n, n) Location = MatrixSymbol('Location', n, p) Y = MatrixSymbol('Y', n, p) M = MatrixStudentT('M', v, Location, Omega, Sigma) exprd = gamma(v/2 + 1)*Determinant(Matrix([[1]]) + Sigma**(-1)*(-Location + Y)*Omega**(-1)*(-Location.T + Y.T))**(-v/2 - 1) / \ (pi*gamma(v/2)*sqrt(Determinant(Omega))*Determinant(Sigma)) assert density(M)(Y) == exprd raises(ValueError, lambda: density(M)(1)) raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [0, 1]], [[1, 0], [2, 1]])) raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [2, 1]], [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [0, 1]], [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [2]], [[1, 0], [0, 1]])) raises(ValueError, lambda: MatrixStudentT('M', 1, [1, 2], [[1, 0], [2, 1]], [[1], [2]])) raises(ValueError, lambda: MatrixStudentT('M', 1, [[1, 2]], [[1, 0], [0, 1]], [[1, 0]])) raises(ValueError, lambda: MatrixStudentT('M', 1, [[1, 2]], [1], [[1, 0]])) raises(ValueError, lambda: MatrixStudentT('M', -1, [1, 2], [[1, 0], [0, 1]], [4])) def test_sample_scipy(): distribs_scipy = [ MatrixNormal('M', [[5, 6]], [4], [[2, 1], [1, 2]]), Wishart('W', 5, [[1, 0], [0, 1]]) ] size = 5 scipy = import_module('scipy') if not scipy: skip('Scipy not installed. Abort tests for _sample_scipy.') else: for X in distribs_scipy: samps = sample(X, size=size) for sam in samps: assert Matrix(sam) in X.pspace.distribution.set M = MatrixGamma('M', 1, 2, [[1, 0], [0, 1]]) raises(NotImplementedError, lambda: sample(M, size=3)) def test_sample_pymc3(): distribs_pymc3 = [ MatrixNormal('M', [[5, 6], [3, 4]], [[1, 0], [0, 1]], [[2, 1], [1, 2]]), Wishart('W', 7, [[2, 1], [1, 2]]) ] size = 3 pymc3 = import_module('pymc3') if not pymc3: skip('PyMC3 is not installed. Abort tests for _sample_pymc3.') else: for X in distribs_pymc3: samps = sample(X, size=size, library='pymc3') for sam in samps: assert Matrix(sam) in X.pspace.distribution.set M = MatrixGamma('M', 1, 2, [[1, 0], [0, 1]]) raises(NotImplementedError, lambda: sample(M, size=3)) def test_sample_seed(): X = MatrixNormal('M', [[5, 6], [3, 4]], [[1, 0], [0, 1]], [[2, 1], [1, 2]]) libraries = ['scipy', 'numpy', 'pymc3'] for lib in libraries: try: imported_lib = import_module(lib) if imported_lib: s0, s1, s2 = [], [], [] s0 = sample(X, size=10, library=lib, seed=0) s1 = sample(X, size=10, library=lib, seed=0) s2 = sample(X, size=10, library=lib, seed=1) for i in range(10): assert (s0[i] == s1[i]).all() assert (s1[i] != s2[i]).all() except NotImplementedError: continue sympy-sympy-1.9/sympy/stats/tests/test_mix.py000066400000000000000000000065311412543434000216170ustar00rootroot00000000000000from sympy import (Symbol, Eq, Ne, simplify, sqrt, exp, pi, symbols, Piecewise, factorial, gamma, IndexedBase, Add, Pow, Mul, Indexed, Integer, Integral, DiracDelta, Dummy, Sum, oo) from sympy.functions.elementary.piecewise import ExprCondPair from sympy.stats import (Poisson, Beta, Exponential, P, Multinomial, MultivariateBeta) from sympy.stats.crv_types import Normal from sympy.stats.drv_types import PoissonDistribution from sympy.stats.compound_rv import CompoundPSpace, CompoundDistribution from sympy.stats.joint_rv import MarginalDistribution from sympy.stats.rv import pspace, density from sympy.testing.pytest import ignore_warnings def test_density(): x = Symbol('x') l = Symbol('l', positive=True) rate = Beta(l, 2, 3) X = Poisson(x, rate) assert isinstance(pspace(X), CompoundPSpace) assert density(X, Eq(rate, rate.symbol)) == PoissonDistribution(l) N1 = Normal('N1', 0, 1) N2 = Normal('N2', N1, 2) assert density(N2)(0).doit() == sqrt(10)/(10*sqrt(pi)) assert simplify(density(N2, Eq(N1, 1))(x)) == \ sqrt(2)*exp(-(x - 1)**2/8)/(4*sqrt(pi)) assert simplify(density(N2)(x)) == sqrt(10)*exp(-x**2/10)/(10*sqrt(pi)) def test_MarginalDistribution(): a1, p1, p2 = symbols('a1 p1 p2', positive=True) C = Multinomial('C', 2, p1, p2) B = MultivariateBeta('B', a1, C[0]) MGR = MarginalDistribution(B, (C[0],)) mgrc = Mul(Symbol('B'), Piecewise(ExprCondPair(Mul(Integer(2), Pow(Symbol('p1', positive=True), Indexed(IndexedBase(Symbol('C')), Integer(0))), Pow(Symbol('p2', positive=True), Indexed(IndexedBase(Symbol('C')), Integer(1))), Pow(factorial(Indexed(IndexedBase(Symbol('C')), Integer(0))), Integer(-1)), Pow(factorial(Indexed(IndexedBase(Symbol('C')), Integer(1))), Integer(-1))), Eq(Add(Indexed(IndexedBase(Symbol('C')), Integer(0)), Indexed(IndexedBase(Symbol('C')), Integer(1))), Integer(2))), ExprCondPair(Integer(0), True)), Pow(gamma(Symbol('a1', positive=True)), Integer(-1)), gamma(Add(Symbol('a1', positive=True), Indexed(IndexedBase(Symbol('C')), Integer(0)))), Pow(gamma(Indexed(IndexedBase(Symbol('C')), Integer(0))), Integer(-1)), Pow(Indexed(IndexedBase(Symbol('B')), Integer(0)), Add(Symbol('a1', positive=True), Integer(-1))), Pow(Indexed(IndexedBase(Symbol('B')), Integer(1)), Add(Indexed(IndexedBase(Symbol('C')), Integer(0)), Integer(-1)))) assert MGR(C) == mgrc def test_compound_distribution(): Y = Poisson('Y', 1) Z = Poisson('Z', Y) assert isinstance(pspace(Z), CompoundPSpace) assert isinstance(pspace(Z).distribution, CompoundDistribution) assert Z.pspace.distribution.pdf(1).doit() == exp(-2)*exp(exp(-1)) def test_mix_expression(): Y, E = Poisson('Y', 1), Exponential('E', 1) k = Dummy('k') expr1 = Integral(Sum(exp(-1)*Integral(exp(-k)*DiracDelta(k - 2), (k, 0, oo) )/factorial(k), (k, 0, oo)), (k, -oo, 0)) expr2 = Integral(Sum(exp(-1)*Integral(exp(-k)*DiracDelta(k - 2), (k, 0, oo) )/factorial(k), (k, 0, oo)), (k, 0, oo)) assert P(Eq(Y + E, 1)) == 0 assert P(Ne(Y + E, 2)) == 1 with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert P(E + Y < 2, evaluate=False).rewrite(Integral).dummy_eq(expr1) assert P(E + Y > 2, evaluate=False).rewrite(Integral).dummy_eq(expr2) sympy-sympy-1.9/sympy/stats/tests/test_random_matrix.py000066400000000000000000000123751412543434000236710ustar00rootroot00000000000000from sympy import (sqrt, exp, Trace, pi, S, Integral, MatrixSymbol, Lambda, Dummy, Product, Abs, IndexedBase, Matrix, I, Rational) from sympy.stats import (GaussianUnitaryEnsemble as GUE, density, GaussianOrthogonalEnsemble as GOE, GaussianSymplecticEnsemble as GSE, joint_eigen_distribution, CircularUnitaryEnsemble as CUE, CircularOrthogonalEnsemble as COE, CircularSymplecticEnsemble as CSE, JointEigenDistribution, level_spacing_distribution, Normal, Beta) from sympy.stats.joint_rv_types import JointDistributionHandmade from sympy.stats.rv import RandomMatrixSymbol from sympy.stats.random_matrix_models import GaussianEnsemble, RandomMatrixPSpace from sympy.testing.pytest import raises def test_GaussianEnsemble(): G = GaussianEnsemble('G', 3) assert density(G) == G.pspace.model raises(ValueError, lambda: GaussianEnsemble('G', 3.5)) def test_GaussianUnitaryEnsemble(): H = RandomMatrixSymbol('H', 3, 3) G = GUE('U', 3) assert density(G)(H) == sqrt(2)*exp(-3*Trace(H**2)/2)/(4*pi**Rational(9, 2)) i, j = (Dummy('i', integer=True, positive=True), Dummy('j', integer=True, positive=True)) l = IndexedBase('l') assert joint_eigen_distribution(G).dummy_eq( Lambda((l[1], l[2], l[3]), 27*sqrt(6)*exp(-3*(l[1]**2)/2 - 3*(l[2]**2)/2 - 3*(l[3]**2)/2)* Product(Abs(l[i] - l[j])**2, (j, i + 1, 3), (i, 1, 2))/(16*pi**Rational(3, 2)))) s = Dummy('s') assert level_spacing_distribution(G).dummy_eq(Lambda(s, 32*s**2*exp(-4*s**2/pi)/pi**2)) def test_GaussianOrthogonalEnsemble(): H = RandomMatrixSymbol('H', 3, 3) _H = MatrixSymbol('_H', 3, 3) G = GOE('O', 3) assert density(G)(H) == exp(-3*Trace(H**2)/4)/Integral(exp(-3*Trace(_H**2)/4), _H) i, j = (Dummy('i', integer=True, positive=True), Dummy('j', integer=True, positive=True)) l = IndexedBase('l') assert joint_eigen_distribution(G).dummy_eq( Lambda((l[1], l[2], l[3]), 9*sqrt(2)*exp(-3*l[1]**2/2 - 3*l[2]**2/2 - 3*l[3]**2/2)* Product(Abs(l[i] - l[j]), (j, i + 1, 3), (i, 1, 2))/(32*pi))) s = Dummy('s') assert level_spacing_distribution(G).dummy_eq(Lambda(s, s*pi*exp(-s**2*pi/4)/2)) def test_GaussianSymplecticEnsemble(): H = RandomMatrixSymbol('H', 3, 3) _H = MatrixSymbol('_H', 3, 3) G = GSE('O', 3) assert density(G)(H) == exp(-3*Trace(H**2))/Integral(exp(-3*Trace(_H**2)), _H) i, j = (Dummy('i', integer=True, positive=True), Dummy('j', integer=True, positive=True)) l = IndexedBase('l') assert joint_eigen_distribution(G).dummy_eq( Lambda((l[1], l[2], l[3]), 162*sqrt(3)*exp(-3*l[1]**2/2 - 3*l[2]**2/2 - 3*l[3]**2/2)* Product(Abs(l[i] - l[j])**4, (j, i + 1, 3), (i, 1, 2))/(5*pi**Rational(3, 2)))) s = Dummy('s') assert level_spacing_distribution(G).dummy_eq(Lambda(s, S(262144)*s**4*exp(-64*s**2/(9*pi))/(729*pi**3))) def test_CircularUnitaryEnsemble(): CU = CUE('U', 3) j, k = (Dummy('j', integer=True, positive=True), Dummy('k', integer=True, positive=True)) t = IndexedBase('t') assert joint_eigen_distribution(CU).dummy_eq( Lambda((t[1], t[2], t[3]), Product(Abs(exp(I*t[j]) - exp(I*t[k]))**2, (j, k + 1, 3), (k, 1, 2))/(48*pi**3)) ) def test_CircularOrthogonalEnsemble(): CO = COE('U', 3) j, k = (Dummy('j', integer=True, positive=True), Dummy('k', integer=True, positive=True)) t = IndexedBase('t') assert joint_eigen_distribution(CO).dummy_eq( Lambda((t[1], t[2], t[3]), Product(Abs(exp(I*t[j]) - exp(I*t[k])), (j, k + 1, 3), (k, 1, 2))/(48*pi**2)) ) def test_CircularSymplecticEnsemble(): CS = CSE('U', 3) j, k = (Dummy('j', integer=True, positive=True), Dummy('k', integer=True, positive=True)) t = IndexedBase('t') assert joint_eigen_distribution(CS).dummy_eq( Lambda((t[1], t[2], t[3]), Product(Abs(exp(I*t[j]) - exp(I*t[k]))**4, (j, k + 1, 3), (k, 1, 2))/(720*pi**3)) ) def test_JointEigenDistribution(): A = Matrix([[Normal('A00', 0, 1), Normal('A01', 1, 1)], [Beta('A10', 1, 1), Beta('A11', 1, 1)]]) JointEigenDistribution(A) == \ JointDistributionHandmade(-sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] + A[1, 1]**2)/2 + A[0, 0]/2 + A[1, 1]/2, sqrt(A[0, 0]**2 - 2*A[0, 0]*A[1, 1] + 4*A[0, 1]*A[1, 0] + A[1, 1]**2)/2 + A[0, 0]/2 + A[1, 1]/2) raises(ValueError, lambda: JointEigenDistribution(Matrix([[1, 0], [2, 1]]))) def test_issue_19841(): G1 = GUE('U', 2) G2 = G1.xreplace({2: 2}) assert G1.args == G2.args X = MatrixSymbol('X', 2, 2) G = GSE('U', 2) h_pspace = RandomMatrixPSpace('P', model=density(G)) H = RandomMatrixSymbol('H', 2, 2, pspace=h_pspace) H2 = RandomMatrixSymbol('H', 2, 2, pspace=None) assert H.doit() == H assert (2*H).xreplace({H: X}) == 2*X assert (2*H).xreplace({H2: X}) == 2*H assert (2*H2).xreplace({H: X}) == 2*H2 assert (2*H2).xreplace({H2: X}) == 2*X sympy-sympy-1.9/sympy/stats/tests/test_rv.py000066400000000000000000000277411412543434000214570ustar00rootroot00000000000000from sympy import (S, Symbol, Interval, binomial, nan, exp, Or, symbols, Eq, cos, And, Tuple, integrate, oo, sin, Sum, Basic, Indexed, DiracDelta, Lambda, log, pi, FallingFactorial, Rational, Matrix) from sympy.stats import (Die, Normal, Exponential, FiniteRV, P, E, H, variance, density, given, independent, dependent, where, pspace, GaussianUnitaryEnsemble, random_symbols, sample, Geometric, factorial_moment, Binomial, Hypergeometric, DiscreteUniform, Poisson, characteristic_function, moment_generating_function, BernoulliProcess, Variance, Expectation, Probability, Covariance, covariance, cmoment, moment, median) from sympy.stats.rv import (IndependentProductPSpace, rs_swap, Density, NamedArgsMixin, RandomSymbol, sample_iter, PSpace, is_random, RandomIndexedSymbol, RandomMatrixSymbol) from sympy.testing.pytest import raises, skip, XFAIL from sympy.external import import_module from sympy.core.numbers import comp from sympy.stats.frv_types import BernoulliDistribution from sympy.core.symbol import Dummy from sympy.functions.elementary.piecewise import Piecewise def test_where(): X, Y = Die('X'), Die('Y') Z = Normal('Z', 0, 1) assert where(Z**2 <= 1).set == Interval(-1, 1) assert where(Z**2 <= 1).as_boolean() == Interval(-1, 1).as_relational(Z.symbol) assert where(And(X > Y, Y > 4)).as_boolean() == And( Eq(X.symbol, 6), Eq(Y.symbol, 5)) assert len(where(X < 3).set) == 2 assert 1 in where(X < 3).set X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) assert where(And(X**2 <= 1, X >= 0)).set == Interval(0, 1) XX = given(X, And(X**2 <= 1, X >= 0)) assert XX.pspace.domain.set == Interval(0, 1) assert XX.pspace.domain.as_boolean() == \ And(0 <= X.symbol, X.symbol**2 <= 1, -oo < X.symbol, X.symbol < oo) with raises(TypeError): XX = given(X, X + 3) def test_random_symbols(): X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) assert set(random_symbols(2*X + 1)) == {X} assert set(random_symbols(2*X + Y)) == {X, Y} assert set(random_symbols(2*X + Y.symbol)) == {X} assert set(random_symbols(2)) == set() def test_characteristic_function(): # Imports I from sympy from sympy import I X = Normal('X',0,1) Y = DiscreteUniform('Y', [1,2,7]) Z = Poisson('Z', 2) t = symbols('_t') P = Lambda(t, exp(-t**2/2)) Q = Lambda(t, exp(7*t*I)/3 + exp(2*t*I)/3 + exp(t*I)/3) R = Lambda(t, exp(2 * exp(t*I) - 2)) assert characteristic_function(X).dummy_eq(P) assert characteristic_function(Y).dummy_eq(Q) assert characteristic_function(Z).dummy_eq(R) def test_moment_generating_function(): X = Normal('X',0,1) Y = DiscreteUniform('Y', [1,2,7]) Z = Poisson('Z', 2) t = symbols('_t') P = Lambda(t, exp(t**2/2)) Q = Lambda(t, (exp(7*t)/3 + exp(2*t)/3 + exp(t)/3)) R = Lambda(t, exp(2 * exp(t) - 2)) assert moment_generating_function(X).dummy_eq(P) assert moment_generating_function(Y).dummy_eq(Q) assert moment_generating_function(Z).dummy_eq(R) def test_sample_iter(): X = Normal('X',0,1) Y = DiscreteUniform('Y', [1, 2, 7]) Z = Poisson('Z', 2) scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests') expr = X**2 + 3 iterator = sample_iter(expr) expr2 = Y**2 + 5*Y + 4 iterator2 = sample_iter(expr2) expr3 = Z**3 + 4 iterator3 = sample_iter(expr3) def is_iterator(obj): if ( hasattr(obj, '__iter__') and (hasattr(obj, 'next') or hasattr(obj, '__next__')) and callable(obj.__iter__) and obj.__iter__() is obj ): return True else: return False assert is_iterator(iterator) assert is_iterator(iterator2) assert is_iterator(iterator3) def test_pspace(): X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) x = Symbol('x') raises(ValueError, lambda: pspace(5 + 3)) raises(ValueError, lambda: pspace(x < 1)) assert pspace(X) == X.pspace assert pspace(2*X + 1) == X.pspace assert pspace(2*X + Y) == IndependentProductPSpace(Y.pspace, X.pspace) def test_rs_swap(): X = Normal('x', 0, 1) Y = Exponential('y', 1) XX = Normal('x', 0, 2) YY = Normal('y', 0, 3) expr = 2*X + Y assert expr.subs(rs_swap((X, Y), (YY, XX))) == 2*XX + YY def test_RandomSymbol(): X = Normal('x', 0, 1) Y = Normal('x', 0, 2) assert X.symbol == Y.symbol assert X != Y assert X.name == X.symbol.name X = Normal('lambda', 0, 1) # make sure we can use protected terms X = Normal('Lambda', 0, 1) # make sure we can use SymPy terms def test_RandomSymbol_diff(): X = Normal('x', 0, 1) assert (2*X).diff(X) def test_random_symbol_no_pspace(): x = RandomSymbol(Symbol('x')) assert x.pspace == PSpace() def test_overlap(): X = Normal('x', 0, 1) Y = Normal('x', 0, 2) raises(ValueError, lambda: P(X > Y)) def test_IndependentProductPSpace(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 1) px = X.pspace py = Y.pspace assert pspace(X + Y) == IndependentProductPSpace(px, py) assert pspace(X + Y) == IndependentProductPSpace(py, px) def test_E(): assert E(5) == 5 def test_H(): X = Normal('X', 0, 1) D = Die('D', sides = 4) G = Geometric('G', 0.5) assert H(X, X > 0) == -log(2)/2 + S.Half + log(pi)/2 assert H(D, D > 2) == log(2) assert comp(H(G).evalf().round(2), 1.39) def test_Sample(): X = Die('X', 6) Y = Normal('Y', 0, 1) z = Symbol('z', integer=True) scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests') assert sample(X) in [1, 2, 3, 4, 5, 6] assert isinstance(sample(X + Y), float) assert P(X + Y > 0, Y < 0, numsamples=10).is_number assert E(X + Y, numsamples=10).is_number assert E(X**2 + Y, numsamples=10).is_number assert E((X + Y)**2, numsamples=10).is_number assert variance(X + Y, numsamples=10).is_number raises(TypeError, lambda: P(Y > z, numsamples=5)) assert P(sin(Y) <= 1, numsamples=10) == 1 assert P(sin(Y) <= 1, cos(Y) < 1, numsamples=10) == 1 assert all(i in range(1, 7) for i in density(X, numsamples=10)) assert all(i in range(4, 7) for i in density(X, X>3, numsamples=10)) numpy = import_module('numpy') if not numpy: skip('Numpy is not installed. Abort tests') #Test Issue #21563: Output of sample must be a float or array assert isinstance(sample(X), numpy.int64) assert isinstance(sample(Y), numpy.float64) assert isinstance(sample(X, size=2), numpy.ndarray) @XFAIL def test_samplingE(): scipy = import_module('scipy') if not scipy: skip('Scipy is not installed. Abort tests') Y = Normal('Y', 0, 1) z = Symbol('z', integer=True) assert E(Sum(1/z**Y, (z, 1, oo)), Y > 2, numsamples=3).is_number def test_given(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 1) A = given(X, True) B = given(X, Y > 2) assert X == A == B def test_factorial_moment(): X = Poisson('X', 2) Y = Binomial('Y', 2, S.Half) Z = Hypergeometric('Z', 4, 2, 2) assert factorial_moment(X, 2) == 4 assert factorial_moment(Y, 2) == S.Half assert factorial_moment(Z, 2) == Rational(1, 3) x, y, z, l = symbols('x y z l') Y = Binomial('Y', 2, y) Z = Hypergeometric('Z', 10, 2, 3) assert factorial_moment(Y, l) == y**2*FallingFactorial( 2, l) + 2*y*(1 - y)*FallingFactorial(1, l) + (1 - y)**2*\ FallingFactorial(0, l) assert factorial_moment(Z, l) == 7*FallingFactorial(0, l)/\ 15 + 7*FallingFactorial(1, l)/15 + FallingFactorial(2, l)/15 def test_dependence(): X, Y = Die('X'), Die('Y') assert independent(X, 2*Y) assert not dependent(X, 2*Y) X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) assert independent(X, Y) assert dependent(X, 2*X) # Create a dependency XX, YY = given(Tuple(X, Y), Eq(X + Y, 3)) assert dependent(XX, YY) def test_dependent_finite(): X, Y = Die('X'), Die('Y') # Dependence testing requires symbolic conditions which currently break # finite random variables assert dependent(X, Y + X) XX, YY = given(Tuple(X, Y), X + Y > 5) # Create a dependency assert dependent(XX, YY) def test_normality(): X, Y = Normal('X', 0, 1), Normal('Y', 0, 1) x = Symbol('x', real=True, finite=True) z = Symbol('z', real=True, finite=True) dens = density(X - Y, Eq(X + Y, z)) assert integrate(dens(x), (x, -oo, oo)) == 1 def test_Density(): X = Die('X', 6) d = Density(X) assert d.doit() == density(X) def test_NamedArgsMixin(): class Foo(Basic, NamedArgsMixin): _argnames = 'foo', 'bar' a = Foo(1, 2) assert a.foo == 1 assert a.bar == 2 raises(AttributeError, lambda: a.baz) class Bar(Basic, NamedArgsMixin): pass raises(AttributeError, lambda: Bar(1, 2).foo) def test_density_constant(): assert density(3)(2) == 0 assert density(3)(3) == DiracDelta(0) def test_cmoment_constant(): assert variance(3) == 0 assert cmoment(3, 3) == 0 assert cmoment(3, 4) == 0 x = Symbol('x') assert variance(x) == 0 assert cmoment(x, 15) == 0 assert cmoment(x, 0) == 1 def test_moment_constant(): assert moment(3, 0) == 1 assert moment(3, 1) == 3 assert moment(3, 2) == 9 x = Symbol('x') assert moment(x, 2) == x**2 def test_median_constant(): assert median(3) == 3 x = Symbol('x') assert median(x) == x def test_real(): x = Normal('x', 0, 1) assert x.is_real def test_issue_10052(): X = Exponential('X', 3) assert P(X < oo) == 1 assert P(X > oo) == 0 assert P(X < 2, X > oo) == 0 assert P(X < oo, X > oo) == 0 assert P(X < oo, X > 2) == 1 assert P(X < 3, X == 2) == 0 raises(ValueError, lambda: P(1)) raises(ValueError, lambda: P(X < 1, 2)) def test_issue_11934(): density = {0: .5, 1: .5} X = FiniteRV('X', density) assert E(X) == 0.5 assert P( X>= 2) == 0 def test_issue_8129(): X = Exponential('X', 4) assert P(X >= X) == 1 assert P(X > X) == 0 assert P(X > X+1) == 0 def test_issue_12237(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 1) U = P(X > 0, X) V = P(Y < 0, X) W = P(X + Y > 0, X) assert W == P(X + Y > 0, X) assert U == BernoulliDistribution(S.Half, S.Zero, S.One) assert V == S.Half def test_is_random(): X = Normal('X', 0, 1) Y = Normal('Y', 0, 1) a, b = symbols('a, b') G = GaussianUnitaryEnsemble('U', 2) B = BernoulliProcess('B', 0.9) assert not is_random(a) assert not is_random(a + b) assert not is_random(a * b) assert not is_random(Matrix([a**2, b**2])) assert is_random(X) assert is_random(X**2 + Y) assert is_random(Y + b**2) assert is_random(Y > 5) assert is_random(B[3] < 1) assert is_random(G) assert is_random(X * Y * B[1]) assert is_random(Matrix([[X, B[2]], [G, Y]])) assert is_random(Eq(X, 4)) def test_issue_12283(): x = symbols('x') X = RandomSymbol(x) Y = RandomSymbol('Y') Z = RandomMatrixSymbol('Z', 2, 1) W = RandomMatrixSymbol('W', 2, 1) RI = RandomIndexedSymbol(Indexed('RI', 3)) assert pspace(Z) == PSpace() assert pspace(RI) == PSpace() assert pspace(X) == PSpace() assert E(X) == Expectation(X) assert P(Y > 3) == Probability(Y > 3) assert variance(X) == Variance(X) assert variance(RI) == Variance(RI) assert covariance(X, Y) == Covariance(X, Y) assert covariance(W, Z) == Covariance(W, Z) def test_issue_6810(): X = Die('X', 6) Y = Normal('Y', 0, 1) assert P(Eq(X, 2)) == S(1)/6 assert P(Eq(Y, 0)) == 0 assert P(Or(X > 2, X < 3)) == 1 assert P(And(X > 3, X > 2)) == S(1)/2 def test_issue_20286(): n, p = symbols('n p') B = Binomial('B', n, p) k = Dummy('k', integer = True) eq = Sum(Piecewise((-p**k*(1 - p)**(-k + n)*log(p**k*(1 - p)**(-k + n)*binomial(n, k))*binomial(n, k), (k >= 0) & (k <= n)), (nan, True)), (k, 0, n)) assert eq.dummy_eq(H(B)) sympy-sympy-1.9/sympy/stats/tests/test_stochastic_process.py000066400000000000000000001124641412543434000247270ustar00rootroot00000000000000from sympy import (S, symbols, FiniteSet, Eq, Matrix, MatrixSymbol, Float, And, ImmutableMatrix, Ne, Lt, Le, Gt, Ge, exp, Not, Rational, Lambda, erf, Piecewise, factorial, Interval, oo, Contains, sqrt, pi, ceiling, gamma, lowergamma, Sum, Range, Tuple, ImmutableDenseMatrix, Symbol) from sympy.stats import (DiscreteMarkovChain, P, TransitionMatrixOf, E, StochasticStateSpaceOf, variance, ContinuousMarkovChain, BernoulliProcess, PoissonProcess, WienerProcess, GammaProcess, sample_stochastic_process) from sympy.stats.joint_rv import JointDistribution from sympy.stats.joint_rv_types import JointDistributionHandmade from sympy.stats.rv import RandomIndexedSymbol from sympy.stats.symbolic_probability import Probability, Expectation from sympy.testing.pytest import raises, skip, ignore_warnings from sympy.external import import_module from sympy.stats.frv_types import BernoulliDistribution from sympy.stats.drv_types import PoissonDistribution from sympy.stats.crv_types import NormalDistribution, GammaDistribution from sympy.core.symbol import Str def test_DiscreteMarkovChain(): # pass only the name X = DiscreteMarkovChain("X") assert isinstance(X.state_space, Range) assert X.index_set == S.Naturals0 assert isinstance(X.transition_probabilities, MatrixSymbol) t = symbols('t', positive=True, integer=True) assert isinstance(X[t], RandomIndexedSymbol) assert E(X[0]) == Expectation(X[0]) raises(TypeError, lambda: DiscreteMarkovChain(1)) raises(NotImplementedError, lambda: X(t)) raises(NotImplementedError, lambda: X.communication_classes()) raises(NotImplementedError, lambda: X.canonical_form()) raises(NotImplementedError, lambda: X.decompose()) nz = Symbol('n', integer=True) TZ = MatrixSymbol('M', nz, nz) SZ = Range(nz) YZ = DiscreteMarkovChain('Y', SZ, TZ) assert P(Eq(YZ[2], 1), Eq(YZ[1], 0)) == TZ[0, 1] raises(ValueError, lambda: sample_stochastic_process(t)) raises(ValueError, lambda: next(sample_stochastic_process(X))) # pass name and state_space # any hashable object should be a valid state # states should be valid as a tuple/set/list/Tuple/Range sym, rainy, cloudy, sunny = symbols('a Rainy Cloudy Sunny', real=True) state_spaces = [(1, 2, 3), [Str('Hello'), sym, DiscreteMarkovChain], Tuple(1, exp(sym), Str('World'), sympify=False), Range(-1, 5, 2), [rainy, cloudy, sunny]] chains = [DiscreteMarkovChain("Y", state_space) for state_space in state_spaces] for i, Y in enumerate(chains): assert isinstance(Y.transition_probabilities, MatrixSymbol) assert Y.state_space == state_spaces[i] or Y.state_space == FiniteSet(*state_spaces[i]) assert Y.number_of_states == 3 with ignore_warnings(UserWarning): # TODO: Restore tests once warnings are removed assert P(Eq(Y[2], 1), Eq(Y[0], 2), evaluate=False) == Probability(Eq(Y[2], 1), Eq(Y[0], 2)) assert E(Y[0]) == Expectation(Y[0]) raises(ValueError, lambda: next(sample_stochastic_process(Y))) raises(TypeError, lambda: DiscreteMarkovChain("Y", dict((1, 1)))) Y = DiscreteMarkovChain("Y", Range(1, t, 2)) assert Y.number_of_states == ceiling((t-1)/2) # pass name and transition_probabilities chains = [DiscreteMarkovChain("Y", trans_probs=Matrix([[]])), DiscreteMarkovChain("Y", trans_probs=Matrix([[0, 1], [1, 0]])), DiscreteMarkovChain("Y", trans_probs=Matrix([[pi, 1-pi], [sym, 1-sym]]))] for Z in chains: assert Z.number_of_states == Z.transition_probabilities.shape[0] assert isinstance(Z.transition_probabilities, ImmutableDenseMatrix) # pass name, state_space and transition_probabilities T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) TS = MatrixSymbol('T', 3, 3) Y = DiscreteMarkovChain("Y", [0, 1, 2], T) YS = DiscreteMarkovChain("Y", ['One', 'Two', 3], TS) assert Y.joint_distribution(1, Y[2], 3) == JointDistribution(Y[1], Y[2], Y[3]) raises(ValueError, lambda: Y.joint_distribution(Y[1].symbol, Y[2].symbol)) assert P(Eq(Y[3], 2), Eq(Y[1], 1)).round(2) == Float(0.36, 2) assert (P(Eq(YS[3], 2), Eq(YS[1], 1)) - (TS[0, 2]*TS[1, 0] + TS[1, 1]*TS[1, 2] + TS[1, 2]*TS[2, 2])).simplify() == 0 assert P(Eq(YS[1], 1), Eq(YS[2], 2)) == Probability(Eq(YS[1], 1)) assert P(Eq(YS[3], 3), Eq(YS[1], 1)) == TS[0, 2]*TS[1, 0] + TS[1, 1]*TS[1, 2] + TS[1, 2]*TS[2, 2] TO = Matrix([[0.25, 0.75, 0],[0, 0.25, 0.75],[0.75, 0, 0.25]]) assert P(Eq(Y[3], 2), Eq(Y[1], 1) & TransitionMatrixOf(Y, TO)).round(3) == Float(0.375, 3) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert E(Y[3], evaluate=False) == Expectation(Y[3]) assert E(Y[3], Eq(Y[2], 1)).round(2) == Float(1.1, 3) TSO = MatrixSymbol('T', 4, 4) raises(ValueError, lambda: str(P(Eq(YS[3], 2), Eq(YS[1], 1) & TransitionMatrixOf(YS, TSO)))) raises(TypeError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], symbols('M'))) raises(ValueError, lambda: DiscreteMarkovChain("Z", [0, 1, 2], MatrixSymbol('T', 3, 4))) raises(ValueError, lambda: E(Y[3], Eq(Y[2], 6))) raises(ValueError, lambda: E(Y[2], Eq(Y[3], 1))) # extended tests for probability queries TO1 = Matrix([[Rational(1, 4), Rational(3, 4), 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)],[0, Rational(1, 4), Rational(3, 4)]]) assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), Eq(Probability(Eq(Y[0], 0)), Rational(1, 4)) & TransitionMatrixOf(Y, TO1)) == Rational(1, 16) assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), TransitionMatrixOf(Y, TO1)) == \ Probability(Eq(Y[0], 0))/4 assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) & StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4) assert P(Lt(X[1], 2) & Gt(X[1], 0), Eq(X[0], 2) & StochasticStateSpaceOf(X, [None, 'None', 1]) & TransitionMatrixOf(X, TO1)) == Rational(1, 4) assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) & StochasticStateSpaceOf(X, [0, 1, 2]) & TransitionMatrixOf(X, TO1)) is S.Zero assert P(Ne(X[1], 2) & Ne(X[1], 1), Eq(X[0], 2) & StochasticStateSpaceOf(X, [None, 'None', 1]) & TransitionMatrixOf(X, TO1)) is S.Zero assert P(And(Eq(Y[2], 1), Eq(Y[1], 1), Eq(Y[0], 0)), Eq(Y[1], 1)) == 0.1*Probability(Eq(Y[0], 0)) # testing properties of Markov chain TO2 = Matrix([[S.One, 0, 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)],[0, Rational(1, 4), Rational(3, 4)]]) TO3 = Matrix([[Rational(1, 4), Rational(3, 4), 0],[Rational(1, 3), Rational(1, 3), Rational(1, 3)], [0, Rational(1, 4), Rational(3, 4)]]) Y2 = DiscreteMarkovChain('Y', trans_probs=TO2) Y3 = DiscreteMarkovChain('Y', trans_probs=TO3) assert Y3.fundamental_matrix() == ImmutableMatrix([[176, 81, -132], [36, 141, -52], [-44, -39, 208]])/125 assert Y2.is_absorbing_chain() == True assert Y3.is_absorbing_chain() == False assert Y2.canonical_form() == ([0, 1, 2], TO2) assert Y3.canonical_form() == ([0, 1, 2], TO3) assert Y2.decompose() == ([0, 1, 2], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3]) assert Y3.decompose() == ([0, 1, 2], TO3, Matrix(0, 3, []), Matrix(0, 0, [])) TO4 = Matrix([[Rational(1, 5), Rational(2, 5), Rational(2, 5)], [Rational(1, 10), S.Half, Rational(2, 5)], [Rational(3, 5), Rational(3, 10), Rational(1, 10)]]) Y4 = DiscreteMarkovChain('Y', trans_probs=TO4) w = ImmutableMatrix([[Rational(11, 39), Rational(16, 39), Rational(4, 13)]]) assert Y4.limiting_distribution == w assert Y4.is_regular() == True assert Y4.is_ergodic() == True TS1 = MatrixSymbol('T', 3, 3) Y5 = DiscreteMarkovChain('Y', trans_probs=TS1) assert Y5.limiting_distribution(w, TO4).doit() == True assert Y5.stationary_distribution(condition_set=True).subs(TS1, TO4).contains(w).doit() == S.true TO6 = Matrix([[S.One, 0, 0, 0, 0],[S.Half, 0, S.Half, 0, 0],[0, S.Half, 0, S.Half, 0], [0, 0, S.Half, 0, S.Half], [0, 0, 0, 0, 1]]) Y6 = DiscreteMarkovChain('Y', trans_probs=TO6) assert Y6.fundamental_matrix() == ImmutableMatrix([[Rational(3, 2), S.One, S.Half], [S.One, S(2), S.One], [S.Half, S.One, Rational(3, 2)]]) assert Y6.absorbing_probabilities() == ImmutableMatrix([[Rational(3, 4), Rational(1, 4)], [S.Half, S.Half], [Rational(1, 4), Rational(3, 4)]]) TO7 = Matrix([[Rational(1, 2), Rational(1, 4), Rational(1, 4)], [Rational(1, 2), 0, Rational(1, 2)], [Rational(1, 4), Rational(1, 4), Rational(1, 2)]]) Y7 = DiscreteMarkovChain('Y', trans_probs=TO7) assert Y7.is_absorbing_chain() == False assert Y7.fundamental_matrix() == ImmutableDenseMatrix([[Rational(86, 75), Rational(1, 25), Rational(-14, 75)], [Rational(2, 25), Rational(21, 25), Rational(2, 25)], [Rational(-14, 75), Rational(1, 25), Rational(86, 75)]]) # test for zero-sized matrix functionality X = DiscreteMarkovChain('X', trans_probs=Matrix([[]])) assert X.number_of_states == 0 assert X.stationary_distribution() == Matrix([[]]) assert X.communication_classes() == [] assert X.canonical_form() == ([], Matrix([[]])) assert X.decompose() == ([], Matrix([[]]), Matrix([[]]), Matrix([[]])) assert X.is_regular() == False assert X.is_ergodic() == False # test communication_class # see https://drive.google.com/drive/folders/1HbxLlwwn2b3U8Lj7eb_ASIUb5vYaNIjg?usp=sharing # tutorial 2.pdf TO7 = Matrix([[0, 5, 5, 0, 0], [0, 0, 0, 10, 0], [5, 0, 5, 0, 0], [0, 10, 0, 0, 0], [0, 3, 0, 3, 4]])/10 Y7 = DiscreteMarkovChain('Y', trans_probs=TO7) tuples = Y7.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([1, 3], [0, 2], [4]) assert recurrence == (True, False, False) assert periods == (2, 1, 1) TO8 = Matrix([[0, 0, 0, 10, 0, 0], [5, 0, 5, 0, 0, 0], [0, 4, 0, 0, 0, 6], [10, 0, 0, 0, 0, 0], [0, 10, 0, 0, 0, 0], [0, 0, 0, 5, 5, 0]])/10 Y8 = DiscreteMarkovChain('Y', trans_probs=TO8) tuples = Y8.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([0, 3], [1, 2, 5, 4]) assert recurrence == (True, False) assert periods == (2, 2) TO9 = Matrix([[2, 0, 0, 3, 0, 0, 3, 2, 0, 0], [0, 10, 0, 0, 0, 0, 0, 0, 0, 0], [0, 2, 2, 0, 0, 0, 0, 0, 3, 3], [0, 0, 0, 3, 0, 0, 6, 1, 0, 0], [0, 0, 0, 0, 5, 5, 0, 0, 0, 0], [0, 0, 0, 0, 0, 10, 0, 0, 0, 0], [4, 0, 0, 5, 0, 0, 1, 0, 0, 0], [2, 0, 0, 4, 0, 0, 2, 2, 0, 0], [3, 0, 1, 0, 0, 0, 0, 0, 4, 2], [0, 0, 4, 0, 0, 0, 0, 0, 3, 3]])/10 Y9 = DiscreteMarkovChain('Y', trans_probs=TO9) tuples = Y9.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([0, 3, 6, 7], [1], [2, 8, 9], [5], [4]) assert recurrence == (True, True, False, True, False) assert periods == (1, 1, 1, 1, 1) # test canonical form # see https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf # example 11.13 T = Matrix([[1, 0, 0, 0, 0], [S(1) / 2, 0, S(1) / 2, 0, 0], [0, S(1) / 2, 0, S(1) / 2, 0], [0, 0, S(1) / 2, 0, S(1) / 2], [0, 0, 0, 0, S(1)]]) DW = DiscreteMarkovChain('DW', [0, 1, 2, 3, 4], T) states, A, B, C = DW.decompose() assert states == [0, 4, 1, 2, 3] assert A == Matrix([[1, 0], [0, 1]]) assert B == Matrix([[S(1)/2, 0], [0, 0], [0, S(1)/2]]) assert C == Matrix([[0, S(1)/2, 0], [S(1)/2, 0, S(1)/2], [0, S(1)/2, 0]]) states, new_matrix = DW.canonical_form() assert states == [0, 4, 1, 2, 3] assert new_matrix == Matrix([[1, 0, 0, 0, 0], [0, 1, 0, 0, 0], [S(1)/2, 0, 0, S(1)/2, 0], [0, 0, S(1)/2, 0, S(1)/2], [0, S(1)/2, 0, S(1)/2, 0]]) # test regular and ergodic # https://www.dartmouth.edu/~chance/teaching_aids/books_articles/probability_book/Chapter11.pdf T = Matrix([[0, 4, 0, 0, 0], [1, 0, 3, 0, 0], [0, 2, 0, 2, 0], [0, 0, 3, 0, 1], [0, 0, 0, 4, 0]])/4 X = DiscreteMarkovChain('X', trans_probs=T) assert not X.is_regular() assert X.is_ergodic() T = Matrix([[0, 1], [1, 0]]) X = DiscreteMarkovChain('X', trans_probs=T) assert not X.is_regular() assert X.is_ergodic() # http://www.math.wisc.edu/~valko/courses/331/MC2.pdf T = Matrix([[2, 1, 1], [2, 0, 2], [1, 1, 2]])/4 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_regular() assert X.is_ergodic() # https://docs.ufpr.br/~lucambio/CE222/1S2014/Kemeny-Snell1976.pdf T = Matrix([[1, 1], [1, 1]])/2 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_regular() assert X.is_ergodic() # test is_absorbing_chain T = Matrix([[0, 1, 0], [1, 0, 0], [0, 0, 1]]) X = DiscreteMarkovChain('X', trans_probs=T) assert not X.is_absorbing_chain() # https://en.wikipedia.org/wiki/Absorbing_Markov_chain T = Matrix([[1, 1, 0, 0], [0, 1, 1, 0], [1, 0, 0, 1], [0, 0, 0, 2]])/2 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_absorbing_chain() T = Matrix([[2, 0, 0, 0, 0], [1, 0, 1, 0, 0], [0, 1, 0, 1, 0], [0, 0, 1, 0, 1], [0, 0, 0, 0, 2]])/2 X = DiscreteMarkovChain('X', trans_probs=T) assert X.is_absorbing_chain() # test custom state space Y10 = DiscreteMarkovChain('Y', [1, 2, 3], TO2) tuples = Y10.communication_classes() classes, recurrence, periods = list(zip(*tuples)) assert classes == ([1], [2, 3]) assert recurrence == (True, False) assert periods == (1, 1) assert Y10.canonical_form() == ([1, 2, 3], TO2) assert Y10.decompose() == ([1, 2, 3], TO2[0:1, 0:1], TO2[1:3, 0:1], TO2[1:3, 1:3]) # testing miscellaneous queries T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)], [Rational(1, 3), 0, Rational(2, 3)], [S.Half, S.Half, 0]]) X = DiscreteMarkovChain('X', [0, 1, 2], T) assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0), Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12) assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3) assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3) assert E(X[1]**2, Eq(X[0], 1)) == Rational(8, 3) assert variance(X[1], Eq(X[0], 1)) == Rational(8, 9) raises(ValueError, lambda: E(X[1], Eq(X[2], 1))) raises(ValueError, lambda: DiscreteMarkovChain('X', [0, 1], T)) # testing miscellaneous queries with different state space X = DiscreteMarkovChain('X', ['A', 'B', 'C'], T) assert P(Eq(X[1], 2) & Eq(X[2], 1) & Eq(X[3], 0), Eq(P(Eq(X[1], 0)), Rational(1, 4)) & Eq(P(Eq(X[1], 1)), Rational(1, 4))) == Rational(1, 12) assert P(Eq(X[2], 1) | Eq(X[2], 2), Eq(X[1], 1)) == Rational(2, 3) assert P(Eq(X[2], 1) & Eq(X[2], 2), Eq(X[1], 1)) is S.Zero assert P(Ne(X[2], 2), Eq(X[1], 1)) == Rational(1, 3) a = X.state_space.args[0] c = X.state_space.args[2] assert (E(X[1] ** 2, Eq(X[0], 1)) - (a**2/3 + 2*c**2/3)).simplify() == 0 assert (variance(X[1], Eq(X[0], 1)) - (2*(-a/3 + c/3)**2/3 + (2*a/3 - 2*c/3)**2/3)).simplify() == 0 raises(ValueError, lambda: E(X[1], Eq(X[2], 1))) #testing queries with multiple RandomIndexedSymbols T = Matrix([[Rational(5, 10), Rational(3, 10), Rational(2, 10)], [Rational(2, 10), Rational(7, 10), Rational(1, 10)], [Rational(3, 10), Rational(3, 10), Rational(4, 10)]]) Y = DiscreteMarkovChain("Y", [0, 1, 2], T) assert P(Eq(Y[7], Y[5]), Eq(Y[2], 0)).round(5) == Float(0.44428, 5) assert P(Gt(Y[3], Y[1]), Eq(Y[0], 0)).round(2) == Float(0.36, 2) assert P(Le(Y[5], Y[10]), Eq(Y[4], 2)).round(6) == Float(0.583120, 6) assert Float(P(Eq(Y[10], Y[5]), Eq(Y[4], 1)), 14) == Float(1 - P(Ne(Y[10], Y[5]), Eq(Y[4], 1)), 14) assert Float(P(Gt(Y[8], Y[9]), Eq(Y[3], 2)), 14) == Float(1 - P(Le(Y[8], Y[9]), Eq(Y[3], 2)), 14) assert Float(P(Lt(Y[1], Y[4]), Eq(Y[0], 0)), 14) == Float(1 - P(Ge(Y[1], Y[4]), Eq(Y[0], 0)), 14) assert P(Eq(Y[5], Y[10]), Eq(Y[2], 1)) == P(Eq(Y[10], Y[5]), Eq(Y[2], 1)) assert P(Gt(Y[1], Y[2]), Eq(Y[0], 1)) == P(Lt(Y[2], Y[1]), Eq(Y[0], 1)) assert P(Ge(Y[7], Y[6]), Eq(Y[4], 1)) == P(Le(Y[6], Y[7]), Eq(Y[4], 1)) #test symbolic queries a, b, c, d = symbols('a b c d') T = Matrix([[Rational(1, 10), Rational(4, 10), Rational(5, 10)], [Rational(3, 10), Rational(4, 10), Rational(3, 10)], [Rational(7, 10), Rational(2, 10), Rational(1, 10)]]) Y = DiscreteMarkovChain("Y", [0, 1, 2], T) query = P(Eq(Y[a], b), Eq(Y[c], d)) assert query.subs({a:10, b:2, c:5, d:1}).evalf().round(4) == P(Eq(Y[10], 2), Eq(Y[5], 1)).round(4) assert query.subs({a:15, b:0, c:10, d:1}).evalf().round(4) == P(Eq(Y[15], 0), Eq(Y[10], 1)).round(4) query_gt = P(Gt(Y[a], b), Eq(Y[c], d)) query_le = P(Le(Y[a], b), Eq(Y[c], d)) assert query_gt.subs({a:5, b:2, c:1, d:0}).evalf() + query_le.subs({a:5, b:2, c:1, d:0}).evalf() == 1 query_ge = P(Ge(Y[a], b), Eq(Y[c], d)) query_lt = P(Lt(Y[a], b), Eq(Y[c], d)) assert query_ge.subs({a:4, b:1, c:0, d:2}).evalf() + query_lt.subs({a:4, b:1, c:0, d:2}).evalf() == 1 #test issue 20078 assert (2*Y[1] + 3*Y[1]).simplify() == 5*Y[1] assert (2*Y[1] - 3*Y[1]).simplify() == -Y[1] assert (2*(0.25*Y[1])).simplify() == 0.5*Y[1] assert ((2*Y[1]) * (0.25*Y[1])).simplify() == 0.5*Y[1]**2 assert (Y[1]**2 + Y[1]**3).simplify() == (Y[1] + 1)*Y[1]**2 def test_sample_stochastic_process(): if not import_module('scipy'): skip('SciPy Not installed. Skip sampling tests') import random random.seed(0) numpy = import_module('numpy') if numpy: numpy.random.seed(0) # scipy uses numpy to sample so to set its seed T = Matrix([[0.5, 0.2, 0.3],[0.2, 0.5, 0.3],[0.2, 0.3, 0.5]]) Y = DiscreteMarkovChain("Y", [0, 1, 2], T) for samps in range(10): assert next(sample_stochastic_process(Y)) in Y.state_space Z = DiscreteMarkovChain("Z", ['1', 1, 0], T) for samps in range(10): assert next(sample_stochastic_process(Z)) in Z.state_space T = Matrix([[S.Half, Rational(1, 4), Rational(1, 4)], [Rational(1, 3), 0, Rational(2, 3)], [S.Half, S.Half, 0]]) X = DiscreteMarkovChain('X', [0, 1, 2], T) for samps in range(10): assert next(sample_stochastic_process(X)) in X.state_space W = DiscreteMarkovChain('W', [1, pi, oo], T) for samps in range(10): assert next(sample_stochastic_process(W)) in W.state_space def test_ContinuousMarkovChain(): T1 = Matrix([[S(-2), S(2), S.Zero], [S.Zero, S.NegativeOne, S.One], [Rational(3, 2), Rational(3, 2), S(-3)]]) C1 = ContinuousMarkovChain('C', [0, 1, 2], T1) assert C1.limiting_distribution() == ImmutableMatrix([[Rational(3, 19), Rational(12, 19), Rational(4, 19)]]) T2 = Matrix([[-S.One, S.One, S.Zero], [S.One, -S.One, S.Zero], [S.Zero, S.One, -S.One]]) C2 = ContinuousMarkovChain('C', [0, 1, 2], T2) A, t = C2.generator_matrix, symbols('t', positive=True) assert C2.transition_probabilities(A)(t) == Matrix([[S.Half + exp(-2*t)/2, S.Half - exp(-2*t)/2, 0], [S.Half - exp(-2*t)/2, S.Half + exp(-2*t)/2, 0], [S.Half - exp(-t) + exp(-2*t)/2, S.Half - exp(-2*t)/2, exp(-t)]]) with ignore_warnings(UserWarning): ### TODO: Restore tests once warnings are removed assert P(Eq(C2(1), 1), Eq(C2(0), 1), evaluate=False) == Probability(Eq(C2(1), 1), Eq(C2(0), 1)) assert P(Eq(C2(1), 1), Eq(C2(0), 1)) == exp(-2)/2 + S.Half assert P(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 1), Eq(P(Eq(C2(1), 0)), S.Half)) == (Rational(1, 4) - exp(-2)/4)*(exp(-2)/2 + S.Half) assert P(Not(Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)) | (Eq(C2(1), 0) & Eq(C2(2), 1) & Eq(C2(3), 2)), Eq(P(Eq(C2(1), 0)), Rational(1, 4)) & Eq(P(Eq(C2(1), 1)), Rational(1, 4))) is S.One assert E(C2(Rational(3, 2)), Eq(C2(0), 2)) == -exp(-3)/2 + 2*exp(Rational(-3, 2)) + S.Half assert variance(C2(Rational(3, 2)), Eq(C2(0), 1)) == ((S.Half - exp(-3)/2)**2*(exp(-3)/2 + S.Half) + (Rational(-1, 2) - exp(-3)/2)**2*(S.Half - exp(-3)/2)) raises(KeyError, lambda: P(Eq(C2(1), 0), Eq(P(Eq(C2(1), 1)), S.Half))) assert P(Eq(C2(1), 0), Eq(P(Eq(C2(5), 1)), S.Half)) == Probability(Eq(C2(1), 0)) TS1 = MatrixSymbol('G', 3, 3) CS1 = ContinuousMarkovChain('C', [0, 1, 2], TS1) A = CS1.generator_matrix assert CS1.transition_probabilities(A)(t) == exp(t*A) C3 = ContinuousMarkovChain('C', [Symbol('0'), Symbol('1'), Symbol('2')], T2) assert P(Eq(C3(1), 1), Eq(C3(0), 1)) == exp(-2)/2 + S.Half assert P(Eq(C3(1), Symbol('1')), Eq(C3(0), Symbol('1'))) == exp(-2)/2 + S.Half #test probability queries G = Matrix([[-S(1), Rational(1, 10), Rational(9, 10)], [Rational(2, 5), -S(1), Rational(3, 5)], [Rational(1, 2), Rational(1, 2), -S(1)]]) C = ContinuousMarkovChain('C', state_space=[0, 1, 2], gen_mat=G) assert P(Eq(C(7.385), C(3.19)), Eq(C(0.862), 0)).round(5) == Float(0.35469, 5) assert P(Gt(C(98.715), C(19.807)), Eq(C(11.314), 2)).round(5) == Float(0.32452, 5) assert P(Le(C(5.9), C(10.112)), Eq(C(4), 1)).round(6) == Float(0.675214, 6) assert Float(P(Eq(C(7.32), C(2.91)), Eq(C(2.63), 1)), 14) == Float(1 - P(Ne(C(7.32), C(2.91)), Eq(C(2.63), 1)), 14) assert Float(P(Gt(C(3.36), C(1.101)), Eq(C(0.8), 2)), 14) == Float(1 - P(Le(C(3.36), C(1.101)), Eq(C(0.8), 2)), 14) assert Float(P(Lt(C(4.9), C(2.79)), Eq(C(1.61), 0)), 14) == Float(1 - P(Ge(C(4.9), C(2.79)), Eq(C(1.61), 0)), 14) assert P(Eq(C(5.243), C(10.912)), Eq(C(2.174), 1)) == P(Eq(C(10.912), C(5.243)), Eq(C(2.174), 1)) assert P(Gt(C(2.344), C(9.9)), Eq(C(1.102), 1)) == P(Lt(C(9.9), C(2.344)), Eq(C(1.102), 1)) assert P(Ge(C(7.87), C(1.008)), Eq(C(0.153), 1)) == P(Le(C(1.008), C(7.87)), Eq(C(0.153), 1)) #test symbolic queries a, b, c, d = symbols('a b c d') query = P(Eq(C(a), b), Eq(C(c), d)) assert query.subs({a:3.65, b:2, c:1.78, d:1}).evalf().round(10) == P(Eq(C(3.65), 2), Eq(C(1.78), 1)).round(10) query_gt = P(Gt(C(a), b), Eq(C(c), d)) query_le = P(Le(C(a), b), Eq(C(c), d)) assert query_gt.subs({a:13.2, b:0, c:3.29, d:2}).evalf() + query_le.subs({a:13.2, b:0, c:3.29, d:2}).evalf() == 1 query_ge = P(Ge(C(a), b), Eq(C(c), d)) query_lt = P(Lt(C(a), b), Eq(C(c), d)) assert query_ge.subs({a:7.43, b:1, c:1.45, d:0}).evalf() + query_lt.subs({a:7.43, b:1, c:1.45, d:0}).evalf() == 1 #test issue 20078 assert (2*C(1) + 3*C(1)).simplify() == 5*C(1) assert (2*C(1) - 3*C(1)).simplify() == -C(1) assert (2*(0.25*C(1))).simplify() == 0.5*C(1) assert (2*C(1) * 0.25*C(1)).simplify() == 0.5*C(1)**2 assert (C(1)**2 + C(1)**3).simplify() == (C(1) + 1)*C(1)**2 def test_BernoulliProcess(): B = BernoulliProcess("B", p=0.6, success=1, failure=0) assert B.state_space == FiniteSet(0, 1) assert B.index_set == S.Naturals0 assert B.success == 1 assert B.failure == 0 X = BernoulliProcess("X", p=Rational(1,3), success='H', failure='T') assert X.state_space == FiniteSet('H', 'T') H, T = symbols("H,T") assert E(X[1]+X[2]*X[3]) == H**2/9 + 4*H*T/9 + H/3 + 4*T**2/9 + 2*T/3 t, x = symbols('t, x', positive=True, integer=True) assert isinstance(B[t], RandomIndexedSymbol) raises(ValueError, lambda: BernoulliProcess("X", p=1.1, success=1, failure=0)) raises(NotImplementedError, lambda: B(t)) raises(IndexError, lambda: B[-3]) assert B.joint_distribution(B[3], B[9]) == JointDistributionHandmade(Lambda((B[3], B[9]), Piecewise((0.6, Eq(B[3], 1)), (0.4, Eq(B[3], 0)), (0, True)) *Piecewise((0.6, Eq(B[9], 1)), (0.4, Eq(B[9], 0)), (0, True)))) assert B.joint_distribution(2, B[4]) == JointDistributionHandmade(Lambda((B[2], B[4]), Piecewise((0.6, Eq(B[2], 1)), (0.4, Eq(B[2], 0)), (0, True)) *Piecewise((0.6, Eq(B[4], 1)), (0.4, Eq(B[4], 0)), (0, True)))) # Test for the sum distribution of Bernoulli Process RVs Y = B[1] + B[2] + B[3] assert P(Eq(Y, 0)).round(2) == Float(0.06, 1) assert P(Eq(Y, 2)).round(2) == Float(0.43, 2) assert P(Eq(Y, 4)).round(2) == 0 assert P(Gt(Y, 1)).round(2) == Float(0.65, 2) # Test for independency of each Random Indexed variable assert P(Eq(B[1], 0) & Eq(B[2], 1) & Eq(B[3], 0) & Eq(B[4], 1)).round(2) == Float(0.06, 1) assert E(2 * B[1] + B[2]).round(2) == Float(1.80, 3) assert E(2 * B[1] + B[2] + 5).round(2) == Float(6.80, 3) assert E(B[2] * B[4] + B[10]).round(2) == Float(0.96, 2) assert E(B[2] > 0, Eq(B[1],1) & Eq(B[2],1)).round(2) == Float(0.60,2) assert E(B[1]) == 0.6 assert P(B[1] > 0).round(2) == Float(0.60, 2) assert P(B[1] < 1).round(2) == Float(0.40, 2) assert P(B[1] > 0, B[2] <= 1).round(2) == Float(0.60, 2) assert P(B[12] * B[5] > 0).round(2) == Float(0.36, 2) assert P(B[12] * B[5] > 0, B[4] < 1).round(2) == Float(0.36, 2) assert P(Eq(B[2], 1), B[2] > 0) == 1 assert P(Eq(B[5], 3)) == 0 assert P(Eq(B[1], 1), B[1] < 0) == 0 assert P(B[2] > 0, Eq(B[2], 1)) == 1 assert P(B[2] < 0, Eq(B[2], 1)) == 0 assert P(B[2] > 0, B[2]==7) == 0 assert P(B[5] > 0, B[5]) == BernoulliDistribution(0.6, 0, 1) raises(ValueError, lambda: P(3)) raises(ValueError, lambda: P(B[3] > 0, 3)) # test issue 19456 expr = Sum(B[t], (t, 0, 4)) expr2 = Sum(B[t], (t, 1, 3)) expr3 = Sum(B[t]**2, (t, 1, 3)) assert expr.doit() == B[0] + B[1] + B[2] + B[3] + B[4] assert expr2.doit() == Y assert expr3.doit() == B[1]**2 + B[2]**2 + B[3]**2 assert B[2*t].free_symbols == {B[2*t], t} assert B[4].free_symbols == {B[4]} assert B[x*t].free_symbols == {B[x*t], x, t} #test issue 20078 assert (2*B[t] + 3*B[t]).simplify() == 5*B[t] assert (2*B[t] - 3*B[t]).simplify() == -B[t] assert (2*(0.25*B[t])).simplify() == 0.5*B[t] assert (2*B[t] * 0.25*B[t]).simplify() == 0.5*B[t]**2 assert (B[t]**2 + B[t]**3).simplify() == (B[t] + 1)*B[t]**2 def test_PoissonProcess(): X = PoissonProcess("X", 3) assert X.state_space == S.Naturals0 assert X.index_set == Interval(0, oo) assert X.lamda == 3 t, d, x, y = symbols('t d x y', positive=True) assert isinstance(X(t), RandomIndexedSymbol) assert X.distribution(t) == PoissonDistribution(3*t) raises(ValueError, lambda: PoissonProcess("X", -1)) raises(NotImplementedError, lambda: X[t]) raises(IndexError, lambda: X(-5)) assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade(Lambda((X(2), X(3)), 6**X(2)*9**X(3)*exp(-15)/(factorial(X(2))*factorial(X(3))))) assert X.joint_distribution(4, 6) == JointDistributionHandmade(Lambda((X(4), X(6)), 12**X(4)*18**X(6)*exp(-30)/(factorial(X(4))*factorial(X(6))))) assert P(X(t) < 1) == exp(-3*t) assert P(Eq(X(t), 0), Contains(t, Interval.Lopen(3, 5))) == exp(-6) # exp(-2*lamda) res = P(Eq(X(t), 1), Contains(t, Interval.Lopen(3, 4))) assert res == 3*exp(-3) # Equivalent to P(Eq(X(t), 1))**4 because of non-overlapping intervals assert P(Eq(X(t), 1) & Eq(X(d), 1) & Eq(X(x), 1) & Eq(X(y), 1), Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(x, Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))) == res**4 # Return Probability because of overlapping intervals assert P(Eq(X(t), 2) & Eq(X(d), 3), Contains(t, Interval.Lopen(0, 2)) & Contains(d, Interval.Ropen(2, 4))) == \ Probability(Eq(X(d), 3) & Eq(X(t), 2), Contains(t, Interval.Lopen(0, 2)) & Contains(d, Interval.Ropen(2, 4))) raises(ValueError, lambda: P(Eq(X(t), 2) & Eq(X(d), 3), Contains(t, Interval.Lopen(0, 4)) & Contains(d, Interval.Lopen(3, oo)))) # no bound on d assert P(Eq(X(3), 2)) == 81*exp(-9)/2 assert P(Eq(X(t), 2), Contains(t, Interval.Lopen(0, 5))) == 225*exp(-15)/2 # Check that probability works correctly by adding it to 1 res1 = P(X(t) <= 3, Contains(t, Interval.Lopen(0, 5))) res2 = P(X(t) > 3, Contains(t, Interval.Lopen(0, 5))) assert res1 == 691*exp(-15) assert (res1 + res2).simplify() == 1 # Check Not and Or assert P(Not(Eq(X(t), 2) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & \ Contains(d, Interval.Lopen(7, 8))).simplify() == -18*exp(-6) + 234*exp(-9) + 1 assert P(Eq(X(t), 2) | Ne(X(t), 4), Contains(t, Interval.Ropen(2, 4))) == 1 - 36*exp(-6) raises(ValueError, lambda: P(X(t) > 2, X(t) + X(d))) assert E(X(t)) == 3*t # property of the distribution at a given timestamp assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == 75 assert E(X(t)**2, Contains(t, Interval.Lopen(0, 1))) == 12 assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Ropen(1, 2))) == \ Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2), Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Ropen(1, 2))) # Value Error because of infinite time bound raises(ValueError, lambda: E(X(t)**3, Contains(t, Interval.Lopen(1, oo)))) # Equivalent to E(X(t)**2) - E(X(d)**2) == E(X(1)**2) - E(X(1)**2) == 0 assert E((X(t) + X(d))*(X(t) - X(d)), Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2))) == 0 assert E(X(2) + x*E(X(5))) == 15*x + 6 assert E(x*X(1) + y) == 3*x + y assert P(Eq(X(1), 2) & Eq(X(t), 3), Contains(t, Interval.Lopen(1, 2))) == 81*exp(-6)/4 Y = PoissonProcess("Y", 6) Z = X + Y assert Z.lamda == X.lamda + Y.lamda == 9 raises(ValueError, lambda: X + 5) # should be added be only PoissonProcess instance N, M = Z.split(4, 5) assert N.lamda == 4 assert M.lamda == 5 raises(ValueError, lambda: Z.split(3, 2)) # 2+3 != 9 raises(ValueError, lambda :P(Eq(X(t), 0), Contains(t, Interval.Lopen(1, 3)) & Eq(X(1), 0))) # check if it handles queries with two random variables in one args res1 = P(Eq(N(3), N(5))) assert res1 == P(Eq(N(t), 0), Contains(t, Interval(3, 5))) res2 = P(N(3) > N(1)) assert res2 == P((N(t) > 0), Contains(t, Interval(1, 3))) assert P(N(3) < N(1)) == 0 # condition is not possible res3 = P(N(3) <= N(1)) # holds only for Eq(N(3), N(1)) assert res3 == P(Eq(N(t), 0), Contains(t, Interval(1, 3))) # tests from https://www.probabilitycourse.com/chapter11/11_1_2_basic_concepts_of_the_poisson_process.php X = PoissonProcess('X', 10) # 11.1 assert P(Eq(X(S(1)/3), 3) & Eq(X(1), 10)) == exp(-10)*Rational(8000000000, 11160261) assert P(Eq(X(1), 1), Eq(X(S(1)/3), 3)) == 0 assert P(Eq(X(1), 10), Eq(X(S(1)/3), 3)) == P(Eq(X(S(2)/3), 7)) X = PoissonProcess('X', 2) # 11.2 assert P(X(S(1)/2) < 1) == exp(-1) assert P(X(3) < 1, Eq(X(1), 0)) == exp(-4) assert P(Eq(X(4), 3), Eq(X(2), 3)) == exp(-4) X = PoissonProcess('X', 3) assert P(Eq(X(2), 5) & Eq(X(1), 2)) == Rational(81, 4)*exp(-6) # check few properties assert P(X(2) <= 3, X(1)>=1) == 3*P(Eq(X(1), 0)) + 2*P(Eq(X(1), 1)) + P(Eq(X(1), 2)) assert P(X(2) <= 3, X(1) > 1) == 2*P(Eq(X(1), 0)) + 1*P(Eq(X(1), 1)) assert P(Eq(X(2), 5) & Eq(X(1), 2)) == P(Eq(X(1), 3))*P(Eq(X(1), 2)) assert P(Eq(X(3), 4), Eq(X(1), 3)) == P(Eq(X(2), 1)) #test issue 20078 assert (2*X(t) + 3*X(t)).simplify() == 5*X(t) assert (2*X(t) - 3*X(t)).simplify() == -X(t) assert (2*(0.25*X(t))).simplify() == 0.5*X(t) assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2 assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2 def test_WienerProcess(): X = WienerProcess("X") assert X.state_space == S.Reals assert X.index_set == Interval(0, oo) t, d, x, y = symbols('t d x y', positive=True) assert isinstance(X(t), RandomIndexedSymbol) assert X.distribution(t) == NormalDistribution(0, sqrt(t)) raises(ValueError, lambda: PoissonProcess("X", -1)) raises(NotImplementedError, lambda: X[t]) raises(IndexError, lambda: X(-2)) assert X.joint_distribution(X(2), X(3)) == JointDistributionHandmade( Lambda((X(2), X(3)), sqrt(6)*exp(-X(2)**2/4)*exp(-X(3)**2/6)/(12*pi))) assert X.joint_distribution(4, 6) == JointDistributionHandmade( Lambda((X(4), X(6)), sqrt(6)*exp(-X(4)**2/8)*exp(-X(6)**2/12)/(24*pi))) assert P(X(t) < 3).simplify() == erf(3*sqrt(2)/(2*sqrt(t)))/2 + S(1)/2 assert P(X(t) > 2, Contains(t, Interval.Lopen(3, 7))).simplify() == S(1)/2 -\ erf(sqrt(2)/2)/2 # Equivalent to P(X(1)>1)**4 assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1), Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(x, Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() ==\ (1 - erf(sqrt(2)/2))*(1 - erf(sqrt(2)))*(1 - erf(3*sqrt(2)/2))*(1 - erf(2*sqrt(2)))/16 # Contains an overlapping interval so, return Probability assert P((X(t)< 2) & (X(d)> 3), Contains(t, Interval.Lopen(0, 2)) & Contains(d, Interval.Ropen(2, 4))) == Probability((X(d) > 3) & (X(t) < 2), Contains(d, Interval.Ropen(2, 4)) & Contains(t, Interval.Lopen(0, 2))) assert str(P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & Contains(d, Interval.Lopen(7, 8))).simplify()) == \ '-(1 - erf(3*sqrt(2)/2))*(2 - erfc(5/2))/4 + 1' # Distribution has mean 0 at each timestamp assert E(X(t)) == 0 assert E(x*(X(t) + X(d))*(X(t)**2+X(d)**2), Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Ropen(1, 2))) == Expectation(x*(X(d) + X(t))*(X(d)**2 + X(t)**2), Contains(d, Interval.Ropen(1, 2)) & Contains(t, Interval.Lopen(0, 1))) assert E(X(t) + x*E(X(3))) == 0 #test issue 20078 assert (2*X(t) + 3*X(t)).simplify() == 5*X(t) assert (2*X(t) - 3*X(t)).simplify() == -X(t) assert (2*(0.25*X(t))).simplify() == 0.5*X(t) assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2 assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2 def test_GammaProcess_symbolic(): t, d, x, y, g, l = symbols('t d x y g l', positive=True) X = GammaProcess("X", l, g) raises(NotImplementedError, lambda: X[t]) raises(IndexError, lambda: X(-1)) assert isinstance(X(t), RandomIndexedSymbol) assert X.state_space == Interval(0, oo) assert X.distribution(t) == GammaDistribution(g*t, 1/l) assert X.joint_distribution(5, X(3)) == JointDistributionHandmade(Lambda( (X(5), X(3)), l**(8*g)*exp(-l*X(3))*exp(-l*X(5))*X(3)**(3*g - 1)*X(5)**(5*g - 1)/(gamma(3*g)*gamma(5*g)))) # property of the gamma process at any given timestamp assert E(X(t)) == g*t/l assert variance(X(t)).simplify() == g*t/l**2 # Equivalent to E(2*X(1)) + E(X(1)**2) + E(X(1)**3), where E(X(1)) == g/l assert E(X(t)**2 + X(d)*2 + X(y)**3, Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(y, Interval.Ropen(3, 4))) == \ 2*g/l + (g**2 + g)/l**2 + (g**3 + 3*g**2 + 2*g)/l**3 assert P(X(t) > 3, Contains(t, Interval.Lopen(3, 4))).simplify() == \ 1 - lowergamma(g, 3*l)/gamma(g) # equivalent to P(X(1)>3) #test issue 20078 assert (2*X(t) + 3*X(t)).simplify() == 5*X(t) assert (2*X(t) - 3*X(t)).simplify() == -X(t) assert (2*(0.25*X(t))).simplify() == 0.5*X(t) assert (2*X(t) * 0.25*X(t)).simplify() == 0.5*X(t)**2 assert (X(t)**2 + X(t)**3).simplify() == (X(t) + 1)*X(t)**2 def test_GammaProcess_numeric(): t, d, x, y = symbols('t d x y', positive=True) X = GammaProcess("X", 1, 2) assert X.state_space == Interval(0, oo) assert X.index_set == Interval(0, oo) assert X.lamda == 1 assert X.gamma == 2 raises(ValueError, lambda: GammaProcess("X", -1, 2)) raises(ValueError, lambda: GammaProcess("X", 0, -2)) raises(ValueError, lambda: GammaProcess("X", -1, -2)) # all are independent because of non-overlapping intervals assert P((X(t) > 4) & (X(d) > 3) & (X(x) > 2) & (X(y) > 1), Contains(t, Interval.Lopen(0, 1)) & Contains(d, Interval.Lopen(1, 2)) & Contains(x, Interval.Lopen(2, 3)) & Contains(y, Interval.Lopen(3, 4))).simplify() == \ 120*exp(-10) # Check working with Not and Or assert P(Not((X(t) < 5) & (X(d) > 3)), Contains(t, Interval.Ropen(2, 4)) & Contains(d, Interval.Lopen(7, 8))).simplify() == -4*exp(-3) + 472*exp(-8)/3 + 1 assert P((X(t) > 2) | (X(t) < 4), Contains(t, Interval.Ropen(1, 4))).simplify() == \ -643*exp(-4)/15 + 109*exp(-2)/15 + 1 assert E(X(t)) == 2*t # E(X(t)) == gamma*t/l assert E(X(2) + x*E(X(5))) == 10*x + 4 sympy-sympy-1.9/sympy/stats/tests/test_symbolic_multivariate.py000066400000000000000000000124711412543434000254310ustar00rootroot00000000000000from sympy.stats import Expectation, Normal, Variance, Covariance from sympy.testing.pytest import raises from sympy import symbols, MatrixSymbol, Matrix, ZeroMatrix, ShapeError from sympy.stats.rv import RandomMatrixSymbol from sympy.stats.symbolic_multivariate_probability import (ExpectationMatrix, VarianceMatrix, CrossCovarianceMatrix) j, k = symbols("j,k") A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) D = MatrixSymbol("D", k, k) a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) A2 = MatrixSymbol("A2", 2, 2) B2 = MatrixSymbol("B2", 2, 2) X = RandomMatrixSymbol("X", k, 1) Y = RandomMatrixSymbol("Y", k, 1) Z = RandomMatrixSymbol("Z", k, 1) W = RandomMatrixSymbol("W", k, 1) R = RandomMatrixSymbol("R", k, k) X2 = RandomMatrixSymbol("X2", 2, 1) normal = Normal("normal", 0, 1) m1 = Matrix([ [1, j*Normal("normal2", 2, 1)], [normal, 0] ]) def test_multivariate_expectation(): expr = Expectation(a) assert expr == Expectation(a) == ExpectationMatrix(a) assert expr.expand() == a expr = Expectation(X) assert expr == Expectation(X) == ExpectationMatrix(X) assert expr.shape == (k, 1) assert expr.rows == k assert expr.cols == 1 assert isinstance(expr, ExpectationMatrix) expr = Expectation(A*X + b) assert expr == ExpectationMatrix(A*X + b) assert expr.expand() == A*ExpectationMatrix(X) + b assert isinstance(expr, ExpectationMatrix) assert expr.shape == (k, 1) expr = Expectation(m1*X2) assert expr.expand() == expr expr = Expectation(A2*m1*B2*X2) assert expr.args[0].args == (A2, m1, B2, X2) assert expr.expand() == A2*ExpectationMatrix(m1*B2*X2) expr = Expectation((X + Y)*(X - Y).T) assert expr.expand() == ExpectationMatrix(X*X.T) - ExpectationMatrix(X*Y.T) +\ ExpectationMatrix(Y*X.T) - ExpectationMatrix(Y*Y.T) expr = Expectation(A*X + B*Y) assert expr.expand() == A*ExpectationMatrix(X) + B*ExpectationMatrix(Y) assert Expectation(m1).doit() == Matrix([[1, 2*j], [0, 0]]) x1 = Matrix([ [Normal('N11', 11, 1), Normal('N12', 12, 1)], [Normal('N21', 21, 1), Normal('N22', 22, 1)] ]) x2 = Matrix([ [Normal('M11', 1, 1), Normal('M12', 2, 1)], [Normal('M21', 3, 1), Normal('M22', 4, 1)] ]) assert Expectation(Expectation(x1 + x2)).doit(deep=False) == ExpectationMatrix(x1 + x2) assert Expectation(Expectation(x1 + x2)).doit() == Matrix([[12, 14], [24, 26]]) def test_multivariate_variance(): raises(ShapeError, lambda: Variance(A)) expr = Variance(a) # type: VarianceMatrix assert expr == Variance(a) == VarianceMatrix(a) assert expr.expand() == ZeroMatrix(k, k) expr = Variance(a.T) assert expr == Variance(a.T) == VarianceMatrix(a.T) assert expr.expand() == ZeroMatrix(k, k) expr = Variance(X) assert expr == Variance(X) == VarianceMatrix(X) assert expr.shape == (k, k) assert expr.rows == k assert expr.cols == k assert isinstance(expr, VarianceMatrix) expr = Variance(A*X) assert expr == VarianceMatrix(A*X) assert expr.expand() == A*VarianceMatrix(X)*A.T assert isinstance(expr, VarianceMatrix) assert expr.shape == (k, k) expr = Variance(A*B*X) assert expr.expand() == A*B*VarianceMatrix(X)*B.T*A.T expr = Variance(m1*X2) assert expr.expand() == expr expr = Variance(A2*m1*B2*X2) assert expr.args[0].args == (A2, m1, B2, X2) assert expr.expand() == expr expr = Variance(A*X + B*Y) assert expr.expand() == 2*A*CrossCovarianceMatrix(X, Y)*B.T +\ A*VarianceMatrix(X)*A.T + B*VarianceMatrix(Y)*B.T def test_multivariate_crosscovariance(): raises(ShapeError, lambda: Covariance(X, Y.T)) raises(ShapeError, lambda: Covariance(X, A)) expr = Covariance(a.T, b.T) assert expr.shape == (1, 1) assert expr.expand() == ZeroMatrix(1, 1) expr = Covariance(a, b) assert expr == Covariance(a, b) == CrossCovarianceMatrix(a, b) assert expr.expand() == ZeroMatrix(k, k) assert expr.shape == (k, k) assert expr.rows == k assert expr.cols == k assert isinstance(expr, CrossCovarianceMatrix) expr = Covariance(A*X + a, b) assert expr.expand() == ZeroMatrix(k, k) expr = Covariance(X, Y) assert isinstance(expr, CrossCovarianceMatrix) assert expr.expand() == expr expr = Covariance(X, X) assert isinstance(expr, CrossCovarianceMatrix) assert expr.expand() == VarianceMatrix(X) expr = Covariance(X + Y, Z) assert isinstance(expr, CrossCovarianceMatrix) assert expr.expand() == CrossCovarianceMatrix(X, Z) + CrossCovarianceMatrix(Y, Z) expr = Covariance(A*X , Y) assert isinstance(expr, CrossCovarianceMatrix) assert expr.expand() == A*CrossCovarianceMatrix(X, Y) expr = Covariance(X , B*Y) assert isinstance(expr, CrossCovarianceMatrix) assert expr.expand() == CrossCovarianceMatrix(X, Y)*B.T expr = Covariance(A*X + a, B.T*Y + b) assert isinstance(expr, CrossCovarianceMatrix) assert expr.expand() == A*CrossCovarianceMatrix(X, Y)*B expr = Covariance(A*X + B*Y + a, C.T*Z + D.T*W + b) assert isinstance(expr, CrossCovarianceMatrix) assert expr.expand() == A*CrossCovarianceMatrix(X, W)*D + A*CrossCovarianceMatrix(X, Z)*C \ + B*CrossCovarianceMatrix(Y, W)*D + B*CrossCovarianceMatrix(Y, Z)*C sympy-sympy-1.9/sympy/stats/tests/test_symbolic_probability.py000066400000000000000000000215771412543434000252520ustar00rootroot00000000000000from sympy import symbols, Mul, sin, Integral, oo, Eq, Sum, sqrt, exp, pi, Dummy from sympy.core.expr import unchanged from sympy.stats import (Normal, Poisson, variance, Covariance, Variance, Probability, Expectation, Moment, CentralMoment) from sympy.stats.rv import probability, expectation def test_literal_probability(): X = Normal('X', 2, 3) Y = Normal('Y', 3, 4) Z = Poisson('Z', 4) W = Poisson('W', 3) x = symbols('x', real=True) y, w, z = symbols('y, w, z') assert Probability(X > 0).evaluate_integral() == probability(X > 0) assert Probability(X > x).evaluate_integral() == probability(X > x) assert Probability(X > 0).rewrite(Integral).doit() == probability(X > 0) assert Probability(X > x).rewrite(Integral).doit() == probability(X > x) assert Expectation(X).evaluate_integral() == expectation(X) assert Expectation(X).rewrite(Integral).doit() == expectation(X) assert Expectation(X**2).evaluate_integral() == expectation(X**2) assert Expectation(x*X).args == (x*X,) assert Expectation(x*X).expand() == x*Expectation(X) assert Expectation(2*X + 3*Y + z*X*Y).expand() == 2*Expectation(X) + 3*Expectation(Y) + z*Expectation(X*Y) assert Expectation(2*X + 3*Y + z*X*Y).args == (2*X + 3*Y + z*X*Y,) assert Expectation(sin(X)) == Expectation(sin(X)).expand() assert Expectation(2*x*sin(X)*Y + y*X**2 + z*X*Y).expand() == 2*x*Expectation(sin(X)*Y) \ + y*Expectation(X**2) + z*Expectation(X*Y) assert Expectation(X + Y).expand() == Expectation(X) + Expectation(Y) assert Expectation((X + Y)*(X - Y)).expand() == Expectation(X**2) - Expectation(Y**2) assert Expectation((X + Y)*(X - Y)).expand().doit() == -12 assert Expectation(X + Y, evaluate=True).doit() == 5 assert Expectation(X + Expectation(Y)).doit() == 5 assert Expectation(X + Expectation(Y)).doit(deep=False) == 2 + Expectation(Expectation(Y)) assert Expectation(X + Expectation(Y + Expectation(2*X))).doit(deep=False) == 2 \ + Expectation(Expectation(Y + Expectation(2*X))) assert Expectation(X + Expectation(Y + Expectation(2*X))).doit() == 9 assert Expectation(Expectation(2*X)).doit() == 4 assert Expectation(Expectation(2*X)).doit(deep=False) == Expectation(2*X) assert Expectation(4*Expectation(2*X)).doit(deep=False) == 4*Expectation(2*X) assert Expectation((X + Y)**3).expand() == 3*Expectation(X*Y**2) +\ 3*Expectation(X**2*Y) + Expectation(X**3) + Expectation(Y**3) assert Expectation((X - Y)**3).expand() == 3*Expectation(X*Y**2) -\ 3*Expectation(X**2*Y) + Expectation(X**3) - Expectation(Y**3) assert Expectation((X - Y)**2).expand() == -2*Expectation(X*Y) +\ Expectation(X**2) + Expectation(Y**2) assert Variance(w).args == (w,) assert Variance(w).expand() == 0 assert Variance(X).evaluate_integral() == Variance(X).rewrite(Integral).doit() == variance(X) assert Variance(X + z).args == (X + z,) assert Variance(X + z).expand() == Variance(X) assert Variance(X*Y).args == (Mul(X, Y),) assert type(Variance(X*Y)) == Variance assert Variance(z*X).expand() == z**2*Variance(X) assert Variance(X + Y).expand() == Variance(X) + Variance(Y) + 2*Covariance(X, Y) assert Variance(X + Y + Z + W).expand() == (Variance(X) + Variance(Y) + Variance(Z) + Variance(W) + 2 * Covariance(X, Y) + 2 * Covariance(X, Z) + 2 * Covariance(X, W) + 2 * Covariance(Y, Z) + 2 * Covariance(Y, W) + 2 * Covariance(W, Z)) assert Variance(X**2).evaluate_integral() == variance(X**2) assert unchanged(Variance, X**2) assert Variance(x*X**2).expand() == x**2*Variance(X**2) assert Variance(sin(X)).args == (sin(X),) assert Variance(sin(X)).expand() == Variance(sin(X)) assert Variance(x*sin(X)).expand() == x**2*Variance(sin(X)) assert Covariance(w, z).args == (w, z) assert Covariance(w, z).expand() == 0 assert Covariance(X, w).expand() == 0 assert Covariance(w, X).expand() == 0 assert Covariance(X, Y).args == (X, Y) assert type(Covariance(X, Y)) == Covariance assert Covariance(z*X + 3, Y).expand() == z*Covariance(X, Y) assert Covariance(X, X).args == (X, X) assert Covariance(X, X).expand() == Variance(X) assert Covariance(z*X + 3, w*Y + 4).expand() == w*z*Covariance(X,Y) assert Covariance(X, Y) == Covariance(Y, X) assert Covariance(X + Y, Z + W).expand() == Covariance(W, X) + Covariance(W, Y) + Covariance(X, Z) + Covariance(Y, Z) assert Covariance(x*X + y*Y, z*Z + w*W).expand() == (x*w*Covariance(W, X) + w*y*Covariance(W, Y) + x*z*Covariance(X, Z) + y*z*Covariance(Y, Z)) assert Covariance(x*X**2 + y*sin(Y), z*Y*Z**2 + w*W).expand() == (w*x*Covariance(W, X**2) + w*y*Covariance(sin(Y), W) + x*z*Covariance(Y*Z**2, X**2) + y*z*Covariance(Y*Z**2, sin(Y))) assert Covariance(X, X**2).expand() == Covariance(X, X**2) assert Covariance(X, sin(X)).expand() == Covariance(sin(X), X) assert Covariance(X**2, sin(X)*Y).expand() == Covariance(sin(X)*Y, X**2) assert Covariance(w, X).evaluate_integral() == 0 def test_probability_rewrite(): X = Normal('X', 2, 3) Y = Normal('Y', 3, 4) Z = Poisson('Z', 4) W = Poisson('W', 3) x, y, w, z = symbols('x, y, w, z') assert Variance(w).rewrite(Expectation) == 0 assert Variance(X).rewrite(Expectation) == Expectation(X ** 2) - Expectation(X) ** 2 assert Variance(X, condition=Y).rewrite(Expectation) == Expectation(X ** 2, Y) - Expectation(X, Y) ** 2 assert Variance(X, Y) != Expectation(X**2) - Expectation(X)**2 assert Variance(X + z).rewrite(Expectation) == Expectation((X + z) ** 2) - Expectation(X + z) ** 2 assert Variance(X * Y).rewrite(Expectation) == Expectation(X ** 2 * Y ** 2) - Expectation(X * Y) ** 2 assert Covariance(w, X).rewrite(Expectation) == -w*Expectation(X) + Expectation(w*X) assert Covariance(X, Y).rewrite(Expectation) == Expectation(X*Y) - Expectation(X)*Expectation(Y) assert Covariance(X, Y, condition=W).rewrite(Expectation) == Expectation(X * Y, W) - Expectation(X, W) * Expectation(Y, W) w, x, z = symbols("W, x, z") px = Probability(Eq(X, x)) pz = Probability(Eq(Z, z)) assert Expectation(X).rewrite(Probability) == Integral(x*px, (x, -oo, oo)) assert Expectation(Z).rewrite(Probability) == Sum(z*pz, (z, 0, oo)) assert Variance(X).rewrite(Probability) == Integral(x**2*px, (x, -oo, oo)) - Integral(x*px, (x, -oo, oo))**2 assert Variance(Z).rewrite(Probability) == Sum(z**2*pz, (z, 0, oo)) - Sum(z*pz, (z, 0, oo))**2 assert Covariance(w, X).rewrite(Probability) == \ -w*Integral(x*Probability(Eq(X, x)), (x, -oo, oo)) + Integral(w*x*Probability(Eq(X, x)), (x, -oo, oo)) # To test rewrite as sum function assert Variance(X).rewrite(Sum) == Variance(X).rewrite(Integral) assert Expectation(X).rewrite(Sum) == Expectation(X).rewrite(Integral) assert Covariance(w, X).rewrite(Sum) == 0 assert Covariance(w, X).rewrite(Integral) == 0 assert Variance(X, condition=Y).rewrite(Probability) == Integral(x**2*Probability(Eq(X, x), Y), (x, -oo, oo)) - \ Integral(x*Probability(Eq(X, x), Y), (x, -oo, oo))**2 def test_symbolic_Moment(): mu = symbols('mu', real=True) sigma = symbols('sigma', real=True, positive=True) x = symbols('x') X = Normal('X', mu, sigma) M = Moment(X, 4, 2) assert M.rewrite(Expectation) == Expectation((X - 2)**4) assert M.rewrite(Probability) == Integral((x - 2)**4*Probability(Eq(X, x)), (x, -oo, oo)) k = Dummy('k') expri = Integral(sqrt(2)*(k - 2)**4*exp(-(k - \ mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (k, -oo, oo)) assert M.rewrite(Integral).dummy_eq(expri) assert M.doit() == (mu**4 - 8*mu**3 + 6*mu**2*sigma**2 + \ 24*mu**2 - 24*mu*sigma**2 - 32*mu + 3*sigma**4 + 24*sigma**2 + 16) M = Moment(2, 5) assert M.doit() == 2**5 def test_symbolic_CentralMoment(): mu = symbols('mu', real=True) sigma = symbols('sigma', real=True, positive=True) x = symbols('x') X = Normal('X', mu, sigma) CM = CentralMoment(X, 6) assert CM.rewrite(Expectation) == Expectation((X - Expectation(X))**6) assert CM.rewrite(Probability) == Integral((x - Integral(x*Probability(True), (x, -oo, oo)))**6*Probability(Eq(X, x)), (x, -oo, oo)) k = Dummy('k') expri = Integral(sqrt(2)*(k - Integral(sqrt(2)*k*exp(-(k - \ mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (k, -oo, oo)))**6*exp(-(k - \ mu)**2/(2*sigma**2))/(2*sqrt(pi)*sigma), (k, -oo, oo)) assert CM.rewrite(Integral).dummy_eq(expri) assert CM.doit().simplify() == 15*sigma**6 CM = Moment(5, 5) assert CM.doit() == 5**5 sympy-sympy-1.9/sympy/strategies/000077500000000000000000000000001412543434000172565ustar00rootroot00000000000000sympy-sympy-1.9/sympy/strategies/__init__.py000066400000000000000000000025751412543434000214000ustar00rootroot00000000000000""" Rewrite Rules DISCLAIMER: This module is experimental. The interface is subject to change. A rule is a function that transforms one expression into another Rule :: Expr -> Expr A strategy is a function that says how a rule should be applied to a syntax tree. In general strategies take rules and produce a new rule Strategy :: [Rules], Other-stuff -> Rule This allows developers to separate a mathematical transformation from the algorithmic details of applying that transformation. The goal is to separate the work of mathematical programming from algorithmic programming. Submodules strategies.rl - some fundamental rules strategies.core - generic non-SymPy specific strategies strategies.traverse - strategies that traverse a SymPy tree strategies.tools - some conglomerate strategies that do depend on SymPy """ from . import rl from . import traverse from .rl import rm_id, unpack, flatten, sort, glom, distribute, rebuild from .util import new from .core import (condition, debug, chain, null_safe, do_one, exhaust, minimize, tryit) from .tools import canon, typed from . import branch __all__ = [ 'rl', 'traverse', 'rm_id', 'unpack', 'flatten', 'sort', 'glom', 'distribute', 'rebuild', 'new', 'condition', 'debug', 'chain', 'null_safe', 'do_one', 'exhaust', 'minimize', 'tryit', 'canon', 'typed', 'branch', ] sympy-sympy-1.9/sympy/strategies/branch/000077500000000000000000000000001412543434000205135ustar00rootroot00000000000000sympy-sympy-1.9/sympy/strategies/branch/__init__.py000066400000000000000000000005431412543434000226260ustar00rootroot00000000000000from . import traverse from .core import (condition, debug, multiplex, exhaust, notempty, chain, onaction, sfilter, yieldify, do_one, identity) from .tools import canon __all__ = [ 'traverse', 'condition', 'debug', 'multiplex', 'exhaust', 'notempty', 'chain', 'onaction', 'sfilter', 'yieldify', 'do_one', 'identity', 'canon', ] sympy-sympy-1.9/sympy/strategies/branch/core.py000066400000000000000000000052741412543434000220250ustar00rootroot00000000000000""" Generic SymPy-Independent Strategies """ def identity(x): yield x def exhaust(brule): """ Apply a branching rule repeatedly until it has no effect """ def exhaust_brl(expr): seen = {expr} for nexpr in brule(expr): if nexpr not in seen: seen.add(nexpr) yield from exhaust_brl(nexpr) if seen == {expr}: yield expr return exhaust_brl def onaction(brule, fn): def onaction_brl(expr): for result in brule(expr): if result != expr: fn(brule, expr, result) yield result return onaction_brl def debug(brule, file=None): """ Print the input and output expressions at each rule application """ if not file: from sys import stdout file = stdout def write(brl, expr, result): file.write("Rule: %s\n" % brl.__name__) file.write("In: %s\nOut: %s\n\n" % (expr, result)) return onaction(brule, write) def multiplex(*brules): """ Multiplex many branching rules into one """ def multiplex_brl(expr): seen = set() for brl in brules: for nexpr in brl(expr): if nexpr not in seen: seen.add(nexpr) yield nexpr return multiplex_brl def condition(cond, brule): """ Only apply branching rule if condition is true """ def conditioned_brl(expr): if cond(expr): yield from brule(expr) else: pass return conditioned_brl def sfilter(pred, brule): """ Yield only those results which satisfy the predicate """ def filtered_brl(expr): yield from filter(pred, brule(expr)) return filtered_brl def notempty(brule): def notempty_brl(expr): yielded = False for nexpr in brule(expr): yielded = True yield nexpr if not yielded: yield expr return notempty_brl def do_one(*brules): """ Execute one of the branching rules """ def do_one_brl(expr): yielded = False for brl in brules: for nexpr in brl(expr): yielded = True yield nexpr if yielded: return return do_one_brl def chain(*brules): """ Compose a sequence of brules so that they apply to the expr sequentially """ def chain_brl(expr): if not brules: yield expr return head, tail = brules[0], brules[1:] for nexpr in head(expr): yield from chain(*tail)(nexpr) return chain_brl def yieldify(rl): """ Turn a rule into a branching rule """ def brl(expr): yield rl(expr) return brl sympy-sympy-1.9/sympy/strategies/branch/tests/000077500000000000000000000000001412543434000216555ustar00rootroot00000000000000sympy-sympy-1.9/sympy/strategies/branch/tests/__init__.py000066400000000000000000000000001412543434000237540ustar00rootroot00000000000000sympy-sympy-1.9/sympy/strategies/branch/tests/test_core.py000066400000000000000000000043171412543434000242230ustar00rootroot00000000000000from sympy.strategies.branch.core import (exhaust, debug, multiplex, condition, notempty, chain, onaction, sfilter, yieldify, do_one, identity) def posdec(x): if x > 0: yield x-1 else: yield x def branch5(x): if 0 < x < 5: yield x-1 elif 5 < x < 10: yield x+1 elif x == 5: yield x+1 yield x-1 else: yield x even = lambda x: x%2 == 0 def inc(x): yield x + 1 def one_to_n(n): yield from range(n) def test_exhaust(): brl = exhaust(branch5) assert set(brl(3)) == {0} assert set(brl(7)) == {10} assert set(brl(5)) == {0, 10} def test_debug(): from io import StringIO file = StringIO() rl = debug(posdec, file) list(rl(5)) log = file.getvalue() file.close() assert posdec.__name__ in log assert '5' in log assert '4' in log def test_multiplex(): brl = multiplex(posdec, branch5) assert set(brl(3)) == {2} assert set(brl(7)) == {6, 8} assert set(brl(5)) == {4, 6} def test_condition(): brl = condition(even, branch5) assert set(brl(4)) == set(branch5(4)) assert set(brl(5)) == set() def test_sfilter(): brl = sfilter(even, one_to_n) assert set(brl(10)) == {0, 2, 4, 6, 8} def test_notempty(): def ident_if_even(x): if even(x): yield x brl = notempty(ident_if_even) assert set(brl(4)) == {4} assert set(brl(5)) == {5} def test_chain(): assert list(chain()(2)) == [2] # identity assert list(chain(inc, inc)(2)) == [4] assert list(chain(branch5, inc)(4)) == [4] assert set(chain(branch5, inc)(5)) == {5, 7} assert list(chain(inc, branch5)(5)) == [7] def test_onaction(): L = [] def record(fn, input, output): L.append((input, output)) list(onaction(inc, record)(2)) assert L == [(2, 3)] list(onaction(identity, record)(2)) assert L == [(2, 3)] def test_yieldify(): inc = lambda x: x + 1 yinc = yieldify(inc) assert list(yinc(3)) == [4] def test_do_one(): def bad(expr): raise ValueError() yield False assert list(do_one(inc)(3)) == [4] assert list(do_one(inc, bad)(3)) == [4] assert list(do_one(inc, posdec)(3)) == [4] sympy-sympy-1.9/sympy/strategies/branch/tests/test_tools.py000066400000000000000000000014121412543434000244240ustar00rootroot00000000000000from sympy.strategies.branch.tools import canon from sympy import Basic def posdec(x): if isinstance(x, int) and x > 0: yield x-1 else: yield x def branch5(x): if isinstance(x, int): if 0 < x < 5: yield x-1 elif 5 < x < 10: yield x+1 elif x == 5: yield x+1 yield x-1 else: yield x def test_zero_ints(): expr = Basic(2, Basic(5, 3), 8) expected = {Basic(0, Basic(0, 0), 0)} brl = canon(posdec) assert set(brl(expr)) == expected def test_split5(): expr = Basic(2, Basic(5, 3), 8) expected = {Basic(0, Basic(0, 0), 10), Basic(0, Basic(10, 0), 10)} brl = canon(branch5) assert set(brl(expr)) == expected sympy-sympy-1.9/sympy/strategies/branch/tests/test_traverse.py000066400000000000000000000021671412543434000251270ustar00rootroot00000000000000from sympy import Basic from sympy.strategies.branch.traverse import top_down, sall from sympy.strategies.branch.core import do_one, identity def inc(x): if isinstance(x, int): yield x + 1 def test_top_down_easy(): expr = Basic(1, 2) expected = Basic(2, 3) brl = top_down(inc) assert set(brl(expr)) == {expected} def test_top_down_big_tree(): expr = Basic(1, Basic(2), Basic(3, Basic(4), 5)) expected = Basic(2, Basic(3), Basic(4, Basic(5), 6)) brl = top_down(inc) assert set(brl(expr)) == {expected} def test_top_down_harder_function(): def split5(x): if x == 5: yield x - 1 yield x + 1 expr = Basic(Basic(5, 6), 1) expected = {Basic(Basic(4, 6), 1), Basic(Basic(6, 6), 1)} brl = top_down(split5) assert set(brl(expr)) == expected def test_sall(): expr = Basic(1, 2) expected = Basic(2, 3) brl = sall(inc) assert list(brl(expr)) == [expected] expr = Basic(1, 2, Basic(3, 4)) expected = Basic(2, 3, Basic(3, 4)) brl = sall(do_one(inc, identity)) assert list(brl(expr)) == [expected] sympy-sympy-1.9/sympy/strategies/branch/tools.py000066400000000000000000000005441412543434000222300ustar00rootroot00000000000000from .core import exhaust, multiplex from .traverse import top_down def canon(*rules): """ Strategy for canonicalization Apply each branching rule in a top-down fashion through the tree. Multiplex through all branching rule traversals Keep doing this until there is no change. """ return exhaust(multiplex(*map(top_down, rules))) sympy-sympy-1.9/sympy/strategies/branch/traverse.py000066400000000000000000000014361412543434000227240ustar00rootroot00000000000000""" Branching Strategies to Traverse a Tree """ from itertools import product from sympy.strategies.util import basic_fns from .core import chain, identity, do_one def top_down(brule, fns=basic_fns): """ Apply a rule down a tree running it on the top nodes first """ return chain(do_one(brule, identity), lambda expr: sall(top_down(brule, fns), fns)(expr)) def sall(brule, fns=basic_fns): """ Strategic all - apply rule to args """ op, new, children, leaf = map(fns.get, ('op', 'new', 'children', 'leaf')) def all_rl(expr): if leaf(expr): yield expr else: myop = op(expr) argss = product(*map(brule, children(expr))) for args in argss: yield new(myop, *args) return all_rl sympy-sympy-1.9/sympy/strategies/core.py000066400000000000000000000055751412543434000205740ustar00rootroot00000000000000""" Generic SymPy-Independent Strategies """ identity = lambda x: x def exhaust(rule): """ Apply a rule repeatedly until it has no effect """ def exhaustive_rl(expr): new, old = rule(expr), expr while new != old: new, old = rule(new), new return new return exhaustive_rl def memoize(rule): """ Memoized version of a rule """ cache = {} def memoized_rl(expr): if expr in cache: return cache[expr] else: result = rule(expr) cache[expr] = result return result return memoized_rl def condition(cond, rule): """ Only apply rule if condition is true """ def conditioned_rl(expr): if cond(expr): return rule(expr) else: return expr return conditioned_rl def chain(*rules): """ Compose a sequence of rules so that they apply to the expr sequentially """ def chain_rl(expr): for rule in rules: expr = rule(expr) return expr return chain_rl def debug(rule, file=None): """ Print out before and after expressions each time rule is used """ if file is None: from sys import stdout file = stdout def debug_rl(*args, **kwargs): expr = args[0] result = rule(*args, **kwargs) if result != expr: file.write("Rule: %s\n" % rule.__name__) file.write("In: %s\nOut: %s\n\n"%(expr, result)) return result return debug_rl def null_safe(rule): """ Return original expr if rule returns None """ def null_safe_rl(expr): result = rule(expr) if result is None: return expr else: return result return null_safe_rl def tryit(rule, exception): """ Return original expr if rule raises exception """ def try_rl(expr): try: return rule(expr) except exception: return expr return try_rl def do_one(*rules): """ Try each of the rules until one works. Then stop. """ def do_one_rl(expr): for rl in rules: result = rl(expr) if result != expr: return result return expr return do_one_rl def switch(key, ruledict): """ Select a rule based on the result of key called on the function """ def switch_rl(expr): rl = ruledict.get(key(expr), identity) return rl(expr) return switch_rl def minimize(*rules, objective=identity): """ Select result of rules that minimizes objective >>> from sympy.strategies import minimize >>> inc = lambda x: x + 1 >>> dec = lambda x: x - 1 >>> rl = minimize(inc, dec) >>> rl(4) 3 >>> rl = minimize(inc, dec, objective=lambda x: -x) # maximize >>> rl(4) 5 """ def minrule(expr): return min([rule(expr) for rule in rules], key=objective) return minrule sympy-sympy-1.9/sympy/strategies/rl.py000066400000000000000000000104071412543434000202470ustar00rootroot00000000000000""" Generic Rules for SymPy This file assumes knowledge of Basic and little else. """ from sympy.utilities.iterables import sift from .util import new # Functions that create rules def rm_id(isid, new=new): """ Create a rule to remove identities. isid - fn :: x -> Bool --- whether or not this element is an identity. Examples ======== >>> from sympy.strategies import rm_id >>> from sympy import Basic >>> remove_zeros = rm_id(lambda x: x==0) >>> remove_zeros(Basic(1, 0, 2)) Basic(1, 2) >>> remove_zeros(Basic(0, 0)) # If only identites then we keep one Basic(0) See Also: unpack """ def ident_remove(expr): """ Remove identities """ ids = list(map(isid, expr.args)) if sum(ids) == 0: # No identities. Common case return expr elif sum(ids) != len(ids): # there is at least one non-identity return new(expr.__class__, *[arg for arg, x in zip(expr.args, ids) if not x]) else: return new(expr.__class__, expr.args[0]) return ident_remove def glom(key, count, combine): """ Create a rule to conglomerate identical args. Examples ======== >>> from sympy.strategies import glom >>> from sympy import Add >>> from sympy.abc import x >>> key = lambda x: x.as_coeff_Mul()[1] >>> count = lambda x: x.as_coeff_Mul()[0] >>> combine = lambda cnt, arg: cnt * arg >>> rl = glom(key, count, combine) >>> rl(Add(x, -x, 3*x, 2, 3, evaluate=False)) 3*x + 5 Wait, how are key, count and combine supposed to work? >>> key(2*x) x >>> count(2*x) 2 >>> combine(2, x) 2*x """ def conglomerate(expr): """ Conglomerate together identical args x + x -> 2x """ groups = sift(expr.args, key) counts = {k: sum(map(count, args)) for k, args in groups.items()} newargs = [combine(cnt, mat) for mat, cnt in counts.items()] if set(newargs) != set(expr.args): return new(type(expr), *newargs) else: return expr return conglomerate def sort(key, new=new): """ Create a rule to sort by a key function. Examples ======== >>> from sympy.strategies import sort >>> from sympy import Basic >>> sort_rl = sort(str) >>> sort_rl(Basic(3, 1, 2)) Basic(1, 2, 3) """ def sort_rl(expr): return new(expr.__class__, *sorted(expr.args, key=key)) return sort_rl def distribute(A, B): """ Turns an A containing Bs into a B of As where A, B are container types >>> from sympy.strategies import distribute >>> from sympy import Add, Mul, symbols >>> x, y = symbols('x,y') >>> dist = distribute(Mul, Add) >>> expr = Mul(2, x+y, evaluate=False) >>> expr 2*(x + y) >>> dist(expr) 2*x + 2*y """ def distribute_rl(expr): for i, arg in enumerate(expr.args): if isinstance(arg, B): first, b, tail = expr.args[:i], expr.args[i], expr.args[i+1:] return B(*[A(*(first + (arg,) + tail)) for arg in b.args]) return expr return distribute_rl def subs(a, b): """ Replace expressions exactly """ def subs_rl(expr): if expr == a: return b else: return expr return subs_rl # Functions that are rules def unpack(expr): """ Rule to unpack singleton args >>> from sympy.strategies import unpack >>> from sympy import Basic >>> unpack(Basic(2)) 2 """ if len(expr.args) == 1: return expr.args[0] else: return expr def flatten(expr, new=new): """ Flatten T(a, b, T(c, d), T2(e)) to T(a, b, c, d, T2(e)) """ cls = expr.__class__ args = [] for arg in expr.args: if arg.__class__ == cls: args.extend(arg.args) else: args.append(arg) return new(expr.__class__, *args) def rebuild(expr): """ Rebuild a SymPy tree. Explanation =========== This function recursively calls constructors in the expression tree. This forces canonicalization and removes ugliness introduced by the use of Basic.__new__ """ if expr.is_Atom: return expr else: return expr.func(*list(map(rebuild, expr.args))) sympy-sympy-1.9/sympy/strategies/tests/000077500000000000000000000000001412543434000204205ustar00rootroot00000000000000sympy-sympy-1.9/sympy/strategies/tests/__init__.py000066400000000000000000000000001412543434000225170ustar00rootroot00000000000000sympy-sympy-1.9/sympy/strategies/tests/test_core.py000066400000000000000000000035121412543434000227620ustar00rootroot00000000000000from sympy import S from sympy.strategies.core import (null_safe, exhaust, memoize, condition, chain, tryit, do_one, debug, switch, minimize) def test_null_safe(): def rl(expr): if expr == 1: return 2 safe_rl = null_safe(rl) assert rl(1) == safe_rl(1) assert rl(3) == None assert safe_rl(3) == 3 def posdec(x): if x > 0: return x-1 else: return x def test_exhaust(): sink = exhaust(posdec) assert sink(5) == 0 assert sink(10) == 0 def test_memoize(): rl = memoize(posdec) assert rl(5) == posdec(5) assert rl(5) == posdec(5) assert rl(-2) == posdec(-2) def test_condition(): rl = condition(lambda x: x%2 == 0, posdec) assert rl(5) == 5 assert rl(4) == 3 def test_chain(): rl = chain(posdec, posdec) assert rl(5) == 3 assert rl(1) == 0 def test_tryit(): def rl(expr): assert False safe_rl = tryit(rl, AssertionError) assert safe_rl(S(1)) == 1 def test_do_one(): rl = do_one(posdec, posdec) assert rl(5) == 4 rl1 = lambda x: 2 if x == 1 else x rl2 = lambda x: 3 if x == 2 else x rule = do_one(rl1, rl2) assert rule(1) == 2 assert rule(rule(1)) == 3 def test_debug(): from io import StringIO file = StringIO() rl = debug(posdec, file) rl(5) log = file.getvalue() file.close() assert posdec.__name__ in log assert '5' in log assert '4' in log def test_switch(): inc = lambda x: x + 1 dec = lambda x: x - 1 key = lambda x: x % 3 rl = switch(key, {0: inc, 1: dec}) assert rl(3) == 4 assert rl(4) == 3 assert rl(5) == 5 def test_minimize(): inc = lambda x: x + 1 dec = lambda x: x - 1 rl = minimize(inc, dec) assert rl(4) == 3 rl = minimize(inc, dec, objective=lambda x: -x) assert rl(4) == 5 sympy-sympy-1.9/sympy/strategies/tests/test_rl.py000066400000000000000000000033141412543434000224470ustar00rootroot00000000000000from sympy import S from sympy.strategies.rl import (rm_id, glom, flatten, unpack, sort, distribute, subs, rebuild) from sympy import Basic def test_rm_id(): rmzeros = rm_id(lambda x: x == 0) assert rmzeros(Basic(0, 1)) == Basic(1) assert rmzeros(Basic(0, 0)) == Basic(0) assert rmzeros(Basic(2, 1)) == Basic(2, 1) def test_glom(): from sympy import Add from sympy.abc import x key = lambda x: x.as_coeff_Mul()[1] count = lambda x: x.as_coeff_Mul()[0] newargs = lambda cnt, arg: cnt * arg rl = glom(key, count, newargs) result = rl(Add(x, -x, 3*x, 2, 3, evaluate=False)) expected = Add(3*x, 5) assert set(result.args) == set(expected.args) def test_flatten(): assert flatten(Basic(1, 2, Basic(3, 4))) == Basic(1, 2, 3, 4) def test_unpack(): assert unpack(Basic(2)) == 2 assert unpack(Basic(2, 3)) == Basic(2, 3) def test_sort(): assert sort(str)(Basic(3,1,2)) == Basic(1,2,3) def test_distribute(): class T1(Basic): pass class T2(Basic): pass distribute_t12 = distribute(T1, T2) assert distribute_t12(T1(1, 2, T2(3, 4), 5)) == \ T2(T1(1, 2, 3, 5), T1(1, 2, 4, 5)) assert distribute_t12(T1(1, 2, 3)) == T1(1, 2, 3) def test_distribute_add_mul(): from sympy import Add, Mul, symbols x, y = symbols('x, y') expr = Mul(2, Add(x, y), evaluate=False) expected = Add(Mul(2, x), Mul(2, y)) distribute_mul = distribute(Mul, Add) assert distribute_mul(expr) == expected def test_subs(): rl = subs(1, 2) assert rl(1) == 2 assert rl(3) == 3 def test_rebuild(): from sympy import Add expr = Basic.__new__(Add, S(1), S(2)) assert rebuild(expr) == 3 sympy-sympy-1.9/sympy/strategies/tests/test_strat.py000066400000000000000000000000001412543434000231540ustar00rootroot00000000000000sympy-sympy-1.9/sympy/strategies/tests/test_tools.py000066400000000000000000000014061412543434000231720ustar00rootroot00000000000000from sympy.strategies.tools import subs, typed from sympy.strategies.rl import rm_id from sympy import Basic def test_subs(): from sympy import symbols a,b,c,d,e,f = symbols('a,b,c,d,e,f') mapping = {a: d, d: a, Basic(e): Basic(f)} expr = Basic(a, Basic(b, c), Basic(d, Basic(e))) result = Basic(d, Basic(b, c), Basic(a, Basic(f))) assert subs(mapping)(expr) == result def test_subs_empty(): assert subs({})(Basic(1, 2)) == Basic(1, 2) def test_typed(): class A(Basic): pass class B(Basic): pass rmzeros = rm_id(lambda x: x == 0) rmones = rm_id(lambda x: x == 1) remove_something = typed({A: rmzeros, B: rmones}) assert remove_something(A(0, 1)) == A(1) assert remove_something(B(0, 1)) == B(0) sympy-sympy-1.9/sympy/strategies/tests/test_traverse.py000066400000000000000000000033301412543434000236630ustar00rootroot00000000000000from sympy.strategies.traverse import (top_down, bottom_up, sall, top_down_once, bottom_up_once, basic_fns) from sympy.strategies.rl import rebuild from sympy.strategies.util import expr_fns from sympy import Add, Basic, Symbol, S from sympy.abc import x, y, z def zero_symbols(expression): return S.Zero if isinstance(expression, Symbol) else expression def test_sall(): zero_onelevel = sall(zero_symbols) assert zero_onelevel(Basic(x, y, Basic(x, z))) == Basic(0, 0, Basic(x, z)) def test_bottom_up(): _test_global_traversal(bottom_up) _test_stop_on_non_basics(bottom_up) def test_top_down(): _test_global_traversal(top_down) _test_stop_on_non_basics(top_down) def _test_global_traversal(trav): zero_all_symbols = trav(zero_symbols) assert zero_all_symbols(Basic(x, y, Basic(x, z))) == \ Basic(0, 0, Basic(0, 0)) def _test_stop_on_non_basics(trav): def add_one_if_can(expr): try: return expr + 1 except TypeError: return expr expr = Basic(1, 'a', Basic(2, 'b')) expected = Basic(2, 'a', Basic(3, 'b')) rl = trav(add_one_if_can) assert rl(expr) == expected class Basic2(Basic): pass rl = lambda x: Basic2(*x.args) if isinstance(x, Basic) else x def test_top_down_once(): top_rl = top_down_once(rl) assert top_rl(Basic(1, 2, Basic(3, 4))) == Basic2(1, 2, Basic(3, 4)) def test_bottom_up_once(): bottom_rl = bottom_up_once(rl) assert bottom_rl(Basic(1, 2, Basic(3, 4))) == Basic(1, 2, Basic2(3, 4)) def test_expr_fns(): expr = x + y**3 e = bottom_up(lambda v: v + 1, expr_fns)(expr) b = bottom_up(lambda v: Basic.__new__(Add, v, S(1)), basic_fns)(expr) assert rebuild(b) == e sympy-sympy-1.9/sympy/strategies/tests/test_tree.py000066400000000000000000000047771412543434000230070ustar00rootroot00000000000000from sympy.strategies.tree import treeapply, greedy, allresults, brute from functools import partial, reduce def test_treeapply(): tree = ([3, 3], [4, 1], 2) assert treeapply(tree, {list: min, tuple: max}) == 3 add = lambda *args: sum(args) mul = lambda *args: reduce(lambda a, b: a*b, args, 1) assert treeapply(tree, {list: add, tuple: mul}) == 60 def test_treeapply_leaf(): assert treeapply(3, {}, leaf=lambda x: x**2) == 9 tree = ([3, 3], [4, 1], 2) treep1 = ([4, 4], [5, 2], 3) assert treeapply(tree, {list: min, tuple: max}, leaf=lambda x: x+1) == \ treeapply(treep1, {list: min, tuple: max}) def test_treeapply_strategies(): from sympy.strategies import chain, minimize join = {list: chain, tuple: minimize} inc = lambda x: x + 1 dec = lambda x: x - 1 double = lambda x: 2*x assert treeapply(inc, join) == inc assert treeapply((inc, dec), join)(5) == minimize(inc, dec)(5) assert treeapply([inc, dec], join)(5) == chain(inc, dec)(5) tree = (inc, [dec, double]) # either inc or dec-then-double assert treeapply(tree, join)(5) == 6 assert treeapply(tree, join)(1) == 0 maximize = partial(minimize, objective=lambda x: -x) join = {list: chain, tuple: maximize} fn = treeapply(tree, join) assert fn(4) == 6 # highest value comes from the dec then double assert fn(1) == 2 # highest value comes from the inc def test_greedy(): inc = lambda x: x + 1 dec = lambda x: x - 1 double = lambda x: 2*x tree = [inc, (dec, double)] # either inc or dec-then-double fn = greedy(tree, objective=lambda x: -x) assert fn(4) == 6 # highest value comes from the dec then double assert fn(1) == 2 # highest value comes from the inc tree = [inc, dec, [inc, dec, [(inc, inc), (dec, dec)]]] lowest = greedy(tree) assert lowest(10) == 8 highest = greedy(tree, objective=lambda x: -x) assert highest(10) == 12 def test_allresults(): inc = lambda x: x+1 dec = lambda x: x-1 double = lambda x: x*2 # square = lambda x: x**2 assert set(allresults(inc)(3)) == {inc(3)} assert set(allresults([inc, dec])(3)) == {2, 4} assert set(allresults((inc, dec))(3)) == {3} assert set(allresults([inc, (dec, double)])(4)) == {5, 6} def test_brute(): inc = lambda x: x+1 dec = lambda x: x-1 square = lambda x: x**2 tree = ([inc, dec], square) fn = brute(tree, lambda x: -x) assert fn(2) == (2 + 1)**2 assert fn(-2) == (-2 - 1)**2 assert brute(inc)(1) == 2 sympy-sympy-1.9/sympy/strategies/tools.py000066400000000000000000000024561412543434000207770ustar00rootroot00000000000000from . import rl from .core import do_one, exhaust, switch from .traverse import top_down def subs(d, **kwargs): """ Full simultaneous exact substitution. Examples ======== >>> from sympy.strategies.tools import subs >>> from sympy import Basic >>> mapping = {1: 4, 4: 1, Basic(5): Basic(6, 7)} >>> expr = Basic(1, Basic(2, 3), Basic(4, Basic(5))) >>> subs(mapping)(expr) Basic(4, Basic(2, 3), Basic(1, Basic(6, 7))) """ if d: return top_down(do_one(*map(rl.subs, *zip(*d.items()))), **kwargs) else: return lambda x: x def canon(*rules, **kwargs): """ Strategy for canonicalization. Explanation =========== Apply each rule in a bottom_up fashion through the tree. Do each one in turn. Keep doing this until there is no change. """ return exhaust(top_down(exhaust(do_one(*rules)), **kwargs)) def typed(ruletypes): """ Apply rules based on the expression type inputs: ruletypes -- a dict mapping {Type: rule} Examples ======== >>> from sympy.strategies import rm_id, typed >>> from sympy import Add, Mul >>> rm_zeros = rm_id(lambda x: x==0) >>> rm_ones = rm_id(lambda x: x==1) >>> remove_idents = typed({Add: rm_zeros, Mul: rm_ones}) """ return switch(type, ruletypes) sympy-sympy-1.9/sympy/strategies/traverse.py000066400000000000000000000022371412543434000214670ustar00rootroot00000000000000"""Strategies to Traverse a Tree.""" from sympy.strategies.util import basic_fns from sympy.strategies.core import chain, do_one def top_down(rule, fns=basic_fns): """Apply a rule down a tree running it on the top nodes first.""" return chain(rule, lambda expr: sall(top_down(rule, fns), fns)(expr)) def bottom_up(rule, fns=basic_fns): """Apply a rule down a tree running it on the bottom nodes first.""" return chain(lambda expr: sall(bottom_up(rule, fns), fns)(expr), rule) def top_down_once(rule, fns=basic_fns): """Apply a rule down a tree - stop on success.""" return do_one(rule, lambda expr: sall(top_down(rule, fns), fns)(expr)) def bottom_up_once(rule, fns=basic_fns): """Apply a rule up a tree - stop on success.""" return do_one(lambda expr: sall(bottom_up(rule, fns), fns)(expr), rule) def sall(rule, fns=basic_fns): """Strategic all - apply rule to args.""" op, new, children, leaf = map(fns.get, ('op', 'new', 'children', 'leaf')) def all_rl(expr): if leaf(expr): return expr else: args = map(rule, children(expr)) return new(op(expr), *args) return all_rl sympy-sympy-1.9/sympy/strategies/tree.py000066400000000000000000000072431412543434000205750ustar00rootroot00000000000000from functools import partial from sympy.strategies import chain, minimize import sympy.strategies.branch as branch from sympy.strategies.branch import yieldify identity = lambda x: x def treeapply(tree, join, leaf=identity): """ Apply functions onto recursive containers (tree). Explanation =========== join - a dictionary mapping container types to functions e.g. ``{list: minimize, tuple: chain}`` Keys are containers/iterables. Values are functions [a] -> a. Examples ======== >>> from sympy.strategies.tree import treeapply >>> tree = [(3, 2), (4, 1)] >>> treeapply(tree, {list: max, tuple: min}) 2 >>> add = lambda *args: sum(args) >>> def mul(*args): ... total = 1 ... for arg in args: ... total *= arg ... return total >>> treeapply(tree, {list: mul, tuple: add}) 25 """ for typ in join: if isinstance(tree, typ): return join[typ](*map(partial(treeapply, join=join, leaf=leaf), tree)) return leaf(tree) def greedy(tree, objective=identity, **kwargs): """ Execute a strategic tree. Select alternatives greedily Trees ----- Nodes in a tree can be either function - a leaf list - a selection among operations tuple - a sequence of chained operations Textual examples ---------------- Text: Run f, then run g, e.g. ``lambda x: g(f(x))`` Code: ``(f, g)`` Text: Run either f or g, whichever minimizes the objective Code: ``[f, g]`` Textx: Run either f or g, whichever is better, then run h Code: ``([f, g], h)`` Text: Either expand then simplify or try factor then foosimp. Finally print Code: ``([(expand, simplify), (factor, foosimp)], print)`` Objective --------- "Better" is determined by the objective keyword. This function makes choices to minimize the objective. It defaults to the identity. Examples ======== >>> from sympy.strategies.tree import greedy >>> inc = lambda x: x + 1 >>> dec = lambda x: x - 1 >>> double = lambda x: 2*x >>> tree = [inc, (dec, double)] # either inc or dec-then-double >>> fn = greedy(tree) >>> fn(4) # lowest value comes from the inc 5 >>> fn(1) # lowest value comes from dec then double 0 This function selects between options in a tuple. The result is chosen that minimizes the objective function. >>> fn = greedy(tree, objective=lambda x: -x) # maximize >>> fn(4) # highest value comes from the dec then double 6 >>> fn(1) # highest value comes from the inc 2 Greediness ---------- This is a greedy algorithm. In the example: ([a, b], c) # do either a or b, then do c the choice between running ``a`` or ``b`` is made without foresight to c """ optimize = partial(minimize, objective=objective) return treeapply(tree, {list: optimize, tuple: chain}, **kwargs) def allresults(tree, leaf=yieldify): """ Execute a strategic tree. Return all possibilities. Returns a lazy iterator of all possible results Exhaustiveness -------------- This is an exhaustive algorithm. In the example ([a, b], [c, d]) All of the results from (a, c), (b, c), (a, d), (b, d) are returned. This can lead to combinatorial blowup. See sympy.strategies.greedy for details on input """ return treeapply(tree, {list: branch.multiplex, tuple: branch.chain}, leaf=leaf) def brute(tree, objective=identity, **kwargs): return lambda expr: min(tuple(allresults(tree, **kwargs)(expr)), key=objective) sympy-sympy-1.9/sympy/strategies/util.py000066400000000000000000000005341412543434000206070ustar00rootroot00000000000000from sympy import Basic new = Basic.__new__ def assoc(d, k, v): d = d.copy() d[k] = v return d basic_fns = {'op': type, 'new': Basic.__new__, 'leaf': lambda x: not isinstance(x, Basic) or x.is_Atom, 'children': lambda x: x.args} expr_fns = assoc(basic_fns, 'new', lambda op, *args: op(*args)) sympy-sympy-1.9/sympy/tensor/000077500000000000000000000000001412543434000164165ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/__init__.py000066400000000000000000000015461412543434000205350ustar00rootroot00000000000000"""A module to manipulate symbolic objects with indices including tensors """ from .indexed import IndexedBase, Idx, Indexed from .index_methods import get_contraction_structure, get_indices from .functions import shape from .array import (MutableDenseNDimArray, ImmutableDenseNDimArray, MutableSparseNDimArray, ImmutableSparseNDimArray, NDimArray, tensorproduct, tensorcontraction, tensordiagonal, derive_by_array, permutedims, Array, DenseNDimArray, SparseNDimArray,) __all__ = [ 'IndexedBase', 'Idx', 'Indexed', 'get_contraction_structure', 'get_indices', 'shape', 'MutableDenseNDimArray', 'ImmutableDenseNDimArray', 'MutableSparseNDimArray', 'ImmutableSparseNDimArray', 'NDimArray', 'tensorproduct', 'tensorcontraction', 'tensordiagonal', 'derive_by_array', 'permutedims', 'Array', 'DenseNDimArray', 'SparseNDimArray', ] sympy-sympy-1.9/sympy/tensor/array/000077500000000000000000000000001412543434000175345ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/array/__init__.py000066400000000000000000000162031412543434000216470ustar00rootroot00000000000000r""" N-dim array module for SymPy. Four classes are provided to handle N-dim arrays, given by the combinations dense/sparse (i.e. whether to store all elements or only the non-zero ones in memory) and mutable/immutable (immutable classes are SymPy objects, but cannot change after they have been created). Examples ======== The following examples show the usage of ``Array``. This is an abbreviation for ``ImmutableDenseNDimArray``, that is an immutable and dense N-dim array, the other classes are analogous. For mutable classes it is also possible to change element values after the object has been constructed. Array construction can detect the shape of nested lists and tuples: >>> from sympy import Array >>> a1 = Array([[1, 2], [3, 4], [5, 6]]) >>> a1 [[1, 2], [3, 4], [5, 6]] >>> a1.shape (3, 2) >>> a1.rank() 2 >>> from sympy.abc import x, y, z >>> a2 = Array([[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]]) >>> a2 [[[x, y], [z, x*z]], [[1, x*y], [1/x, x/y]]] >>> a2.shape (2, 2, 2) >>> a2.rank() 3 Otherwise one could pass a 1-dim array followed by a shape tuple: >>> m1 = Array(range(12), (3, 4)) >>> m1 [[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]] >>> m2 = Array(range(12), (3, 2, 2)) >>> m2 [[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]] >>> m2[1,1,1] 7 >>> m2.reshape(4, 3) [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] Slice support: >>> m2[:, 1, 1] [3, 7, 11] Elementwise derivative: >>> from sympy.abc import x, y, z >>> m3 = Array([x**3, x*y, z]) >>> m3.diff(x) [3*x**2, y, 0] >>> m3.diff(z) [0, 0, 1] Multiplication with other SymPy expressions is applied elementwisely: >>> (1+x)*m3 [x**3*(x + 1), x*y*(x + 1), z*(x + 1)] To apply a function to each element of the N-dim array, use ``applyfunc``: >>> m3.applyfunc(lambda x: x/2) [x**3/2, x*y/2, z/2] N-dim arrays can be converted to nested lists by the ``tolist()`` method: >>> m2.tolist() [[[0, 1], [2, 3]], [[4, 5], [6, 7]], [[8, 9], [10, 11]]] >>> isinstance(m2.tolist(), list) True If the rank is 2, it is possible to convert them to matrices with ``tomatrix()``: >>> m1.tomatrix() Matrix([ [0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]) Products and contractions ------------------------- Tensor product between arrays `A_{i_1,\ldots,i_n}` and `B_{j_1,\ldots,j_m}` creates the combined array `P = A \otimes B` defined as `P_{i_1,\ldots,i_n,j_1,\ldots,j_m} := A_{i_1,\ldots,i_n}\cdot B_{j_1,\ldots,j_m}.` It is available through ``tensorproduct(...)``: >>> from sympy import Array, tensorproduct >>> from sympy.abc import x,y,z,t >>> A = Array([x, y, z, t]) >>> B = Array([1, 2, 3, 4]) >>> tensorproduct(A, B) [[x, 2*x, 3*x, 4*x], [y, 2*y, 3*y, 4*y], [z, 2*z, 3*z, 4*z], [t, 2*t, 3*t, 4*t]] Tensor product between a rank-1 array and a matrix creates a rank-3 array: >>> from sympy import eye >>> p1 = tensorproduct(A, eye(4)) >>> p1 [[[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]], [[y, 0, 0, 0], [0, y, 0, 0], [0, 0, y, 0], [0, 0, 0, y]], [[z, 0, 0, 0], [0, z, 0, 0], [0, 0, z, 0], [0, 0, 0, z]], [[t, 0, 0, 0], [0, t, 0, 0], [0, 0, t, 0], [0, 0, 0, t]]] Now, to get back `A_0 \otimes \mathbf{1}` one can access `p_{0,m,n}` by slicing: >>> p1[0,:,:] [[x, 0, 0, 0], [0, x, 0, 0], [0, 0, x, 0], [0, 0, 0, x]] Tensor contraction sums over the specified axes, for example contracting positions `a` and `b` means `A_{i_1,\ldots,i_a,\ldots,i_b,\ldots,i_n} \implies \sum_k A_{i_1,\ldots,k,\ldots,k,\ldots,i_n}` Remember that Python indexing is zero starting, to contract the a-th and b-th axes it is therefore necessary to specify `a-1` and `b-1` >>> from sympy import tensorcontraction >>> C = Array([[x, y], [z, t]]) The matrix trace is equivalent to the contraction of a rank-2 array: `A_{m,n} \implies \sum_k A_{k,k}` >>> tensorcontraction(C, (0, 1)) t + x Matrix product is equivalent to a tensor product of two rank-2 arrays, followed by a contraction of the 2nd and 3rd axes (in Python indexing axes number 1, 2). `A_{m,n}\cdot B_{i,j} \implies \sum_k A_{m, k}\cdot B_{k, j}` >>> D = Array([[2, 1], [0, -1]]) >>> tensorcontraction(tensorproduct(C, D), (1, 2)) [[2*x, x - y], [2*z, -t + z]] One may verify that the matrix product is equivalent: >>> from sympy import Matrix >>> Matrix([[x, y], [z, t]])*Matrix([[2, 1], [0, -1]]) Matrix([ [2*x, x - y], [2*z, -t + z]]) or equivalently >>> C.tomatrix()*D.tomatrix() Matrix([ [2*x, x - y], [2*z, -t + z]]) Diagonal operator ----------------- The ``tensordiagonal`` function acts in a similar manner as ``tensorcontraction``, but the joined indices are not summed over, for example diagonalizing positions `a` and `b` means `A_{i_1,\ldots,i_a,\ldots,i_b,\ldots,i_n} \implies A_{i_1,\ldots,k,\ldots,k,\ldots,i_n} \implies \tilde{A}_{i_1,\ldots,i_{a-1},i_{a+1},\ldots,i_{b-1},i_{b+1},\ldots,i_n,k}` where `\tilde{A}` is the array equivalent to the diagonal of `A` at positions `a` and `b` moved to the last index slot. Compare the difference between contraction and diagonal operators: >>> from sympy import tensordiagonal >>> from sympy.abc import a, b, c, d >>> m = Matrix([[a, b], [c, d]]) >>> tensorcontraction(m, [0, 1]) a + d >>> tensordiagonal(m, [0, 1]) [a, d] In short, no summation occurs with ``tensordiagonal``. Derivatives by array -------------------- The usual derivative operation may be extended to support derivation with respect to arrays, provided that all elements in the that array are symbols or expressions suitable for derivations. The definition of a derivative by an array is as follows: given the array `A_{i_1, \ldots, i_N}` and the array `X_{j_1, \ldots, j_M}` the derivative of arrays will return a new array `B` defined by `B_{j_1,\ldots,j_M,i_1,\ldots,i_N} := \frac{\partial A_{i_1,\ldots,i_N}}{\partial X_{j_1,\ldots,j_M}}` The function ``derive_by_array`` performs such an operation: >>> from sympy import derive_by_array >>> from sympy.abc import x, y, z, t >>> from sympy import sin, exp With scalars, it behaves exactly as the ordinary derivative: >>> derive_by_array(sin(x*y), x) y*cos(x*y) Scalar derived by an array basis: >>> derive_by_array(sin(x*y), [x, y, z]) [y*cos(x*y), x*cos(x*y), 0] Deriving array by an array basis: `B^{nm} := \frac{\partial A^m}{\partial x^n}` >>> basis = [x, y, z] >>> ax = derive_by_array([exp(x), sin(y*z), t], basis) >>> ax [[exp(x), 0, 0], [0, z*cos(y*z), 0], [0, y*cos(y*z), 0]] Contraction of the resulting array: `\sum_m \frac{\partial A^m}{\partial x^m}` >>> tensorcontraction(ax, (0, 1)) z*cos(y*z) + exp(x) """ from .dense_ndim_array import MutableDenseNDimArray, ImmutableDenseNDimArray, DenseNDimArray from .sparse_ndim_array import MutableSparseNDimArray, ImmutableSparseNDimArray, SparseNDimArray from .ndim_array import NDimArray, ArrayKind from .arrayop import tensorproduct, tensorcontraction, tensordiagonal, derive_by_array, permutedims from .array_comprehension import ArrayComprehension, ArrayComprehensionMap Array = ImmutableDenseNDimArray __all__ = [ 'MutableDenseNDimArray', 'ImmutableDenseNDimArray', 'DenseNDimArray', 'MutableSparseNDimArray', 'ImmutableSparseNDimArray', 'SparseNDimArray', 'NDimArray', 'ArrayKind', 'tensorproduct', 'tensorcontraction', 'tensordiagonal', 'derive_by_array', 'permutedims', 'ArrayComprehension', 'ArrayComprehensionMap', 'Array', ] sympy-sympy-1.9/sympy/tensor/array/array_comprehension.py000066400000000000000000000271351412543434000241650ustar00rootroot00000000000000import functools, itertools from sympy.core.sympify import sympify from sympy.core.expr import Expr from sympy.core import Basic from sympy.tensor.array import ImmutableDenseNDimArray from sympy import Symbol from sympy.core.numbers import Integer class ArrayComprehension(Basic): """ Generate a list comprehension. Explanation =========== If there is a symbolic dimension, for example, say [i for i in range(1, N)] where N is a Symbol, then the expression will not be expanded to an array. Otherwise, calling the doit() function will launch the expansion. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j, k = symbols('i j k') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.doit() [[11, 12, 13], [21, 22, 23], [31, 32, 33], [41, 42, 43]] >>> b = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, k)) >>> b.doit() ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, k)) """ def __new__(cls, function, *symbols, **assumptions): if any(len(l) != 3 or None for l in symbols): raise ValueError('ArrayComprehension requires values lower and upper bound' ' for the expression') arglist = [sympify(function)] arglist.extend(cls._check_limits_validity(function, symbols)) obj = Basic.__new__(cls, *arglist, **assumptions) obj._limits = obj._args[1:] obj._shape = cls._calculate_shape_from_limits(obj._limits) obj._rank = len(obj._shape) obj._loop_size = cls._calculate_loop_size(obj._shape) return obj @property def function(self): """The function applied across limits. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j = symbols('i j') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.function 10*i + j """ return self._args[0] @property def limits(self): """ The list of limits that will be applied while expanding the array. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j = symbols('i j') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.limits ((i, 1, 4), (j, 1, 3)) """ return self._limits @property def free_symbols(self): """ The set of the free_symbols in the array. Variables appeared in the bounds are supposed to be excluded from the free symbol set. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j, k = symbols('i j k') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.free_symbols set() >>> b = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, k+3)) >>> b.free_symbols {k} """ expr_free_sym = self.function.free_symbols for var, inf, sup in self._limits: expr_free_sym.discard(var) curr_free_syms = inf.free_symbols.union(sup.free_symbols) expr_free_sym = expr_free_sym.union(curr_free_syms) return expr_free_sym @property def variables(self): """The tuples of the variables in the limits. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j, k = symbols('i j k') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.variables [i, j] """ return [l[0] for l in self._limits] @property def bound_symbols(self): """The list of dummy variables. Note ==== Note that all variables are dummy variables since a limit without lower bound or upper bound is not accepted. """ return [l[0] for l in self._limits if len(l) != 1] @property def shape(self): """ The shape of the expanded array, which may have symbols. Note ==== Both the lower and the upper bounds are included while calculating the shape. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j, k = symbols('i j k') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.shape (4, 3) >>> b = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, k+3)) >>> b.shape (4, k + 3) """ return self._shape @property def is_shape_numeric(self): """ Test if the array is shape-numeric which means there is no symbolic dimension. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j, k = symbols('i j k') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.is_shape_numeric True >>> b = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, k+3)) >>> b.is_shape_numeric False """ for _, inf, sup in self._limits: if Basic(inf, sup).atoms(Symbol): return False return True def rank(self): """The rank of the expanded array. Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j, k = symbols('i j k') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.rank() 2 """ return self._rank def __len__(self): """ The length of the expanded array which means the number of elements in the array. Raises ====== ValueError : When the length of the array is symbolic Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j = symbols('i j') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> len(a) 12 """ if self._loop_size.free_symbols: raise ValueError('Symbolic length is not supported') return self._loop_size @classmethod def _check_limits_validity(cls, function, limits): limits = sympify(limits) for var, inf, sup in limits: if any((not isinstance(i, Expr)) or i.atoms(Symbol, Integer) != i.atoms() for i in [inf, sup]): raise TypeError('Bounds should be an Expression(combination of Integer and Symbol)') if (inf > sup) == True: raise ValueError('Lower bound should be inferior to upper bound') if var in inf.free_symbols or var in sup.free_symbols: raise ValueError('Variable should not be part of its bounds') return limits @classmethod def _calculate_shape_from_limits(cls, limits): return tuple([sup - inf + 1 for _, inf, sup in limits]) @classmethod def _calculate_loop_size(cls, shape): if not shape: return 0 loop_size = 1 for l in shape: loop_size = loop_size * l return loop_size def doit(self): if not self.is_shape_numeric: return self return self._expand_array() def _expand_array(self): res = [] for values in itertools.product(*[range(inf, sup+1) for var, inf, sup in self._limits]): res.append(self._get_element(values)) return ImmutableDenseNDimArray(res, self.shape) def _get_element(self, values): temp = self.function for var, val in zip(self.variables, values): temp = temp.subs(var, val) return temp def tolist(self): """Transform the expanded array to a list. Raises ====== ValueError : When there is a symbolic dimension Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j = symbols('i j') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.tolist() [[11, 12, 13], [21, 22, 23], [31, 32, 33], [41, 42, 43]] """ if self.is_shape_numeric: return self._expand_array().tolist() raise ValueError("A symbolic array cannot be expanded to a list") def tomatrix(self): """Transform the expanded array to a matrix. Raises ====== ValueError : When there is a symbolic dimension ValueError : When the rank of the expanded array is not equal to 2 Examples ======== >>> from sympy.tensor.array import ArrayComprehension >>> from sympy import symbols >>> i, j = symbols('i j') >>> a = ArrayComprehension(10*i + j, (i, 1, 4), (j, 1, 3)) >>> a.tomatrix() Matrix([ [11, 12, 13], [21, 22, 23], [31, 32, 33], [41, 42, 43]]) """ from sympy.matrices import Matrix if not self.is_shape_numeric: raise ValueError("A symbolic array cannot be expanded to a matrix") if self._rank != 2: raise ValueError('Dimensions must be of size of 2') return Matrix(self._expand_array().tomatrix()) def isLambda(v): LAMBDA = lambda: 0 return isinstance(v, type(LAMBDA)) and v.__name__ == LAMBDA.__name__ class ArrayComprehensionMap(ArrayComprehension): ''' A subclass of ArrayComprehension dedicated to map external function lambda. Notes ===== Only the lambda function is considered. At most one argument in lambda function is accepted in order to avoid ambiguity in value assignment. Examples ======== >>> from sympy.tensor.array import ArrayComprehensionMap >>> from sympy import symbols >>> i, j, k = symbols('i j k') >>> a = ArrayComprehensionMap(lambda: 1, (i, 1, 4)) >>> a.doit() [1, 1, 1, 1] >>> b = ArrayComprehensionMap(lambda a: a+1, (j, 1, 4)) >>> b.doit() [2, 3, 4, 5] ''' def __new__(cls, function, *symbols, **assumptions): if any(len(l) != 3 or None for l in symbols): raise ValueError('ArrayComprehension requires values lower and upper bound' ' for the expression') if not isLambda(function): raise ValueError('Data type not supported') arglist = cls._check_limits_validity(function, symbols) obj = Basic.__new__(cls, *arglist, **assumptions) obj._limits = obj._args obj._shape = cls._calculate_shape_from_limits(obj._limits) obj._rank = len(obj._shape) obj._loop_size = cls._calculate_loop_size(obj._shape) obj._lambda = function return obj @property def func(self): class _(ArrayComprehensionMap): def __new__(cls, *args, **kwargs): return ArrayComprehensionMap(self._lambda, *args, **kwargs) return _ def _get_element(self, values): temp = self._lambda if self._lambda.__code__.co_argcount == 0: temp = temp() elif self._lambda.__code__.co_argcount == 1: temp = temp(functools.reduce(lambda a, b: a*b, values)) return temp sympy-sympy-1.9/sympy/tensor/array/array_derivatives.py000066400000000000000000000112141412543434000236300ustar00rootroot00000000000000from typing import Optional from sympy import Derivative, Integer, Expr from sympy.matrices.common import MatrixCommon from .ndim_array import NDimArray from .arrayop import derive_by_array from sympy import MatrixExpr from sympy import ZeroMatrix from sympy.matrices.expressions.matexpr import _matrix_derivative class ArrayDerivative(Derivative): is_scalar = False def __new__(cls, expr, *variables, **kwargs): obj = super().__new__(cls, expr, *variables, **kwargs) if isinstance(obj, ArrayDerivative): obj._shape = obj._get_shape() return obj def _get_shape(self): shape = () for v, count in self.variable_count: if hasattr(v, "shape"): for i in range(count): shape += v.shape if hasattr(self.expr, "shape"): shape += self.expr.shape return shape @property def shape(self): return self._shape @classmethod def _get_zero_with_shape_like(cls, expr): if isinstance(expr, (MatrixCommon, NDimArray)): return expr.zeros(*expr.shape) elif isinstance(expr, MatrixExpr): return ZeroMatrix(*expr.shape) else: raise RuntimeError("Unable to determine shape of array-derivative.") @staticmethod def _call_derive_scalar_by_matrix(expr, v): # type: (Expr, MatrixCommon) -> Expr return v.applyfunc(lambda x: expr.diff(x)) @staticmethod def _call_derive_scalar_by_matexpr(expr, v): # type: (Expr, MatrixExpr) -> Expr if expr.has(v): return _matrix_derivative(expr, v) else: return ZeroMatrix(*v.shape) @staticmethod def _call_derive_scalar_by_array(expr, v): # type: (Expr, NDimArray) -> Expr return v.applyfunc(lambda x: expr.diff(x)) @staticmethod def _call_derive_matrix_by_scalar(expr, v): # type: (MatrixCommon, Expr) -> Expr return _matrix_derivative(expr, v) @staticmethod def _call_derive_matexpr_by_scalar(expr, v): # type: (MatrixExpr, Expr) -> Expr return expr._eval_derivative(v) @staticmethod def _call_derive_array_by_scalar(expr, v): # type: (NDimArray, Expr) -> Expr return expr.applyfunc(lambda x: x.diff(v)) @staticmethod def _call_derive_default(expr, v): # type: (Expr, Expr) -> Optional[Expr] if expr.has(v): return _matrix_derivative(expr, v) else: return None @classmethod def _dispatch_eval_derivative_n_times(cls, expr, v, count): # Evaluate the derivative `n` times. If # `_eval_derivative_n_times` is not overridden by the current # object, the default in `Basic` will call a loop over # `_eval_derivative`: if not isinstance(count, (int, Integer)) or ((count <= 0) == True): return None # TODO: this could be done with multiple-dispatching: if expr.is_scalar: if isinstance(v, MatrixCommon): result = cls._call_derive_scalar_by_matrix(expr, v) elif isinstance(v, MatrixExpr): result = cls._call_derive_scalar_by_matexpr(expr, v) elif isinstance(v, NDimArray): result = cls._call_derive_scalar_by_array(expr, v) elif v.is_scalar: # scalar by scalar has a special return super()._dispatch_eval_derivative_n_times(expr, v, count) else: return None elif v.is_scalar: if isinstance(expr, MatrixCommon): result = cls._call_derive_matrix_by_scalar(expr, v) elif isinstance(expr, MatrixExpr): result = cls._call_derive_matexpr_by_scalar(expr, v) elif isinstance(expr, NDimArray): result = cls._call_derive_array_by_scalar(expr, v) else: return None else: # Both `expr` and `v` are some array/matrix type: if isinstance(expr, MatrixCommon) or isinstance(expr, MatrixCommon): result = derive_by_array(expr, v) elif isinstance(expr, MatrixExpr) and isinstance(v, MatrixExpr): result = cls._call_derive_default(expr, v) elif isinstance(expr, MatrixExpr) or isinstance(v, MatrixExpr): # if one expression is a symbolic matrix expression while the other isn't, don't evaluate: return None else: result = derive_by_array(expr, v) if result is None: return None if count == 1: return result else: return cls._dispatch_eval_derivative_n_times(result, v, count - 1) sympy-sympy-1.9/sympy/tensor/array/arrayop.py000066400000000000000000000376461412543434000216030ustar00rootroot00000000000000import itertools from collections.abc import Iterable from sympy import S, Tuple, diff, Basic from sympy.core.sympify import _sympify from sympy.tensor.array.ndim_array import NDimArray from sympy.tensor.array.dense_ndim_array import DenseNDimArray, ImmutableDenseNDimArray from sympy.tensor.array.sparse_ndim_array import SparseNDimArray def _arrayfy(a): from sympy.matrices import MatrixBase if isinstance(a, NDimArray): return a if isinstance(a, (MatrixBase, list, tuple, Tuple)): return ImmutableDenseNDimArray(a) return a def tensorproduct(*args): """ Tensor product among scalars or array-like objects. Examples ======== >>> from sympy.tensor.array import tensorproduct, Array >>> from sympy.abc import x, y, z, t >>> A = Array([[1, 2], [3, 4]]) >>> B = Array([x, y]) >>> tensorproduct(A, B) [[[x, y], [2*x, 2*y]], [[3*x, 3*y], [4*x, 4*y]]] >>> tensorproduct(A, x) [[x, 2*x], [3*x, 4*x]] >>> tensorproduct(A, B, B) [[[[x**2, x*y], [x*y, y**2]], [[2*x**2, 2*x*y], [2*x*y, 2*y**2]]], [[[3*x**2, 3*x*y], [3*x*y, 3*y**2]], [[4*x**2, 4*x*y], [4*x*y, 4*y**2]]]] Applying this function on two matrices will result in a rank 4 array. >>> from sympy import Matrix, eye >>> m = Matrix([[x, y], [z, t]]) >>> p = tensorproduct(eye(3), m) >>> p [[[[x, y], [z, t]], [[0, 0], [0, 0]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[x, y], [z, t]], [[0, 0], [0, 0]]], [[[0, 0], [0, 0]], [[0, 0], [0, 0]], [[x, y], [z, t]]]] """ from sympy.tensor.array import SparseNDimArray, ImmutableSparseNDimArray if len(args) == 0: return S.One if len(args) == 1: return _arrayfy(args[0]) from sympy.tensor.array.expressions.array_expressions import _CodegenArrayAbstract from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct from sympy.tensor.array.expressions.array_expressions import _ArrayExpr from sympy import MatrixSymbol if any(isinstance(arg, (_ArrayExpr, _CodegenArrayAbstract, MatrixSymbol)) for arg in args): return ArrayTensorProduct(*args) if len(args) > 2: return tensorproduct(tensorproduct(args[0], args[1]), *args[2:]) # length of args is 2: a, b = map(_arrayfy, args) if not isinstance(a, NDimArray) or not isinstance(b, NDimArray): return a*b if isinstance(a, SparseNDimArray) and isinstance(b, SparseNDimArray): lp = len(b) new_array = {k1*lp + k2: v1*v2 for k1, v1 in a._sparse_array.items() for k2, v2 in b._sparse_array.items()} return ImmutableSparseNDimArray(new_array, a.shape + b.shape) product_list = [i*j for i in Flatten(a) for j in Flatten(b)] return ImmutableDenseNDimArray(product_list, a.shape + b.shape) def _util_contraction_diagonal(array, *contraction_or_diagonal_axes): array = _arrayfy(array) # Verify contraction_axes: taken_dims = set() for axes_group in contraction_or_diagonal_axes: if not isinstance(axes_group, Iterable): raise ValueError("collections of contraction/diagonal axes expected") dim = array.shape[axes_group[0]] for d in axes_group: if d in taken_dims: raise ValueError("dimension specified more than once") if dim != array.shape[d]: raise ValueError("cannot contract or diagonalize between axes of different dimension") taken_dims.add(d) rank = array.rank() remaining_shape = [dim for i, dim in enumerate(array.shape) if i not in taken_dims] cum_shape = [0]*rank _cumul = 1 for i in range(rank): cum_shape[rank - i - 1] = _cumul _cumul *= int(array.shape[rank - i - 1]) # DEFINITION: by absolute position it is meant the position along the one # dimensional array containing all the tensor components. # Possible future work on this module: move computation of absolute # positions to a class method. # Determine absolute positions of the uncontracted indices: remaining_indices = [[cum_shape[i]*j for j in range(array.shape[i])] for i in range(rank) if i not in taken_dims] # Determine absolute positions of the contracted indices: summed_deltas = [] for axes_group in contraction_or_diagonal_axes: lidx = [] for js in range(array.shape[axes_group[0]]): lidx.append(sum([cum_shape[ig] * js for ig in axes_group])) summed_deltas.append(lidx) return array, remaining_indices, remaining_shape, summed_deltas def tensorcontraction(array, *contraction_axes): """ Contraction of an array-like object on the specified axes. Examples ======== >>> from sympy import Array, tensorcontraction >>> from sympy import Matrix, eye >>> tensorcontraction(eye(3), (0, 1)) 3 >>> A = Array(range(18), (3, 2, 3)) >>> A [[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]], [[12, 13, 14], [15, 16, 17]]] >>> tensorcontraction(A, (0, 2)) [21, 30] Matrix multiplication may be emulated with a proper combination of ``tensorcontraction`` and ``tensorproduct`` >>> from sympy import tensorproduct >>> from sympy.abc import a,b,c,d,e,f,g,h >>> m1 = Matrix([[a, b], [c, d]]) >>> m2 = Matrix([[e, f], [g, h]]) >>> p = tensorproduct(m1, m2) >>> p [[[[a*e, a*f], [a*g, a*h]], [[b*e, b*f], [b*g, b*h]]], [[[c*e, c*f], [c*g, c*h]], [[d*e, d*f], [d*g, d*h]]]] >>> tensorcontraction(p, (1, 2)) [[a*e + b*g, a*f + b*h], [c*e + d*g, c*f + d*h]] >>> m1*m2 Matrix([ [a*e + b*g, a*f + b*h], [c*e + d*g, c*f + d*h]]) """ from sympy.tensor.array.expressions.array_expressions import ArrayContraction from sympy.tensor.array.expressions.array_expressions import _CodegenArrayAbstract from sympy.tensor.array.expressions.array_expressions import _ArrayExpr from sympy import MatrixSymbol if isinstance(array, (_ArrayExpr, _CodegenArrayAbstract, MatrixSymbol)): return ArrayContraction(array, *contraction_axes) array, remaining_indices, remaining_shape, summed_deltas = _util_contraction_diagonal(array, *contraction_axes) # Compute the contracted array: # # 1. external for loops on all uncontracted indices. # Uncontracted indices are determined by the combinatorial product of # the absolute positions of the remaining indices. # 2. internal loop on all contracted indices. # It sums the values of the absolute contracted index and the absolute # uncontracted index for the external loop. contracted_array = [] for icontrib in itertools.product(*remaining_indices): index_base_position = sum(icontrib) isum = S.Zero for sum_to_index in itertools.product(*summed_deltas): idx = array._get_tuple_index(index_base_position + sum(sum_to_index)) isum += array[idx] contracted_array.append(isum) if len(remaining_indices) == 0: assert len(contracted_array) == 1 return contracted_array[0] return type(array)(contracted_array, remaining_shape) def tensordiagonal(array, *diagonal_axes): """ Diagonalization of an array-like object on the specified axes. This is equivalent to multiplying the expression by Kronecker deltas uniting the axes. The diagonal indices are put at the end of the axes. Examples ======== ``tensordiagonal`` acting on a 2-dimensional array by axes 0 and 1 is equivalent to the diagonal of the matrix: >>> from sympy import Array, tensordiagonal >>> from sympy import Matrix, eye >>> tensordiagonal(eye(3), (0, 1)) [1, 1, 1] >>> from sympy.abc import a,b,c,d >>> m1 = Matrix([[a, b], [c, d]]) >>> tensordiagonal(m1, [0, 1]) [a, d] In case of higher dimensional arrays, the diagonalized out dimensions are appended removed and appended as a single dimension at the end: >>> A = Array(range(18), (3, 2, 3)) >>> A [[[0, 1, 2], [3, 4, 5]], [[6, 7, 8], [9, 10, 11]], [[12, 13, 14], [15, 16, 17]]] >>> tensordiagonal(A, (0, 2)) [[0, 7, 14], [3, 10, 17]] >>> from sympy import permutedims >>> tensordiagonal(A, (0, 2)) == permutedims(Array([A[0, :, 0], A[1, :, 1], A[2, :, 2]]), [1, 0]) True """ if any([len(i) <= 1 for i in diagonal_axes]): raise ValueError("need at least two axes to diagonalize") from sympy.tensor.array.expressions.array_expressions import _ArrayExpr from sympy.tensor.array.expressions.array_expressions import _CodegenArrayAbstract from sympy.tensor.array.expressions.array_expressions import ArrayDiagonal from sympy import MatrixSymbol if isinstance(array, (_ArrayExpr, _CodegenArrayAbstract, MatrixSymbol)): return ArrayDiagonal(array, *diagonal_axes) array, remaining_indices, remaining_shape, diagonal_deltas = _util_contraction_diagonal(array, *diagonal_axes) # Compute the diagonalized array: # # 1. external for loops on all undiagonalized indices. # Undiagonalized indices are determined by the combinatorial product of # the absolute positions of the remaining indices. # 2. internal loop on all diagonal indices. # It appends the values of the absolute diagonalized index and the absolute # undiagonalized index for the external loop. diagonalized_array = [] diagonal_shape = [len(i) for i in diagonal_deltas] for icontrib in itertools.product(*remaining_indices): index_base_position = sum(icontrib) isum = [] for sum_to_index in itertools.product(*diagonal_deltas): idx = array._get_tuple_index(index_base_position + sum(sum_to_index)) isum.append(array[idx]) isum = type(array)(isum).reshape(*diagonal_shape) diagonalized_array.append(isum) return type(array)(diagonalized_array, remaining_shape + diagonal_shape) def derive_by_array(expr, dx): r""" Derivative by arrays. Supports both arrays and scalars. Explanation =========== Given the array `A_{i_1, \ldots, i_N}` and the array `X_{j_1, \ldots, j_M}` this function will return a new array `B` defined by `B_{j_1,\ldots,j_M,i_1,\ldots,i_N} := \frac{\partial A_{i_1,\ldots,i_N}}{\partial X_{j_1,\ldots,j_M}}` Examples ======== >>> from sympy import derive_by_array >>> from sympy.abc import x, y, z, t >>> from sympy import cos >>> derive_by_array(cos(x*t), x) -t*sin(t*x) >>> derive_by_array(cos(x*t), [x, y, z, t]) [-t*sin(t*x), 0, 0, -x*sin(t*x)] >>> derive_by_array([x, y**2*z], [[x, y], [z, t]]) [[[1, 0], [0, 2*y*z]], [[0, y**2], [0, 0]]] """ from sympy.matrices import MatrixBase from sympy.tensor.array import SparseNDimArray array_types = (Iterable, MatrixBase, NDimArray) if isinstance(dx, array_types): dx = ImmutableDenseNDimArray(dx) for i in dx: if not i._diff_wrt: raise ValueError("cannot derive by this array") if isinstance(expr, array_types): if isinstance(expr, NDimArray): expr = expr.as_immutable() else: expr = ImmutableDenseNDimArray(expr) if isinstance(dx, array_types): if isinstance(expr, SparseNDimArray): lp = len(expr) new_array = {k + i*lp: v for i, x in enumerate(Flatten(dx)) for k, v in expr.diff(x)._sparse_array.items()} else: new_array = [[y.diff(x) for y in Flatten(expr)] for x in Flatten(dx)] return type(expr)(new_array, dx.shape + expr.shape) else: return expr.diff(dx) else: expr = _sympify(expr) if isinstance(dx, array_types): return ImmutableDenseNDimArray([expr.diff(i) for i in Flatten(dx)], dx.shape) else: dx = _sympify(dx) return diff(expr, dx) def permutedims(expr, perm): """ Permutes the indices of an array. Parameter specifies the permutation of the indices. Examples ======== >>> from sympy.abc import x, y, z, t >>> from sympy import sin >>> from sympy import Array, permutedims >>> a = Array([[x, y, z], [t, sin(x), 0]]) >>> a [[x, y, z], [t, sin(x), 0]] >>> permutedims(a, (1, 0)) [[x, t], [y, sin(x)], [z, 0]] If the array is of second order, ``transpose`` can be used: >>> from sympy import transpose >>> transpose(a) [[x, t], [y, sin(x)], [z, 0]] Examples on higher dimensions: >>> b = Array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) >>> permutedims(b, (2, 1, 0)) [[[1, 5], [3, 7]], [[2, 6], [4, 8]]] >>> permutedims(b, (1, 2, 0)) [[[1, 5], [2, 6]], [[3, 7], [4, 8]]] ``Permutation`` objects are also allowed: >>> from sympy.combinatorics import Permutation >>> permutedims(b, Permutation([1, 2, 0])) [[[1, 5], [2, 6]], [[3, 7], [4, 8]]] """ from sympy.tensor.array import SparseNDimArray from sympy.tensor.array.expressions.array_expressions import _ArrayExpr from sympy.tensor.array.expressions.array_expressions import _CodegenArrayAbstract from sympy.tensor.array.expressions.array_expressions import PermuteDims from sympy import MatrixSymbol if isinstance(expr, (_ArrayExpr, _CodegenArrayAbstract, MatrixSymbol)): return PermuteDims(expr, perm) if not isinstance(expr, NDimArray): expr = ImmutableDenseNDimArray(expr) from sympy.combinatorics import Permutation if not isinstance(perm, Permutation): perm = Permutation(list(perm)) if perm.size != expr.rank(): raise ValueError("wrong permutation size") # Get the inverse permutation: iperm = ~perm new_shape = perm(expr.shape) if isinstance(expr, SparseNDimArray): return type(expr)({tuple(perm(expr._get_tuple_index(k))): v for k, v in expr._sparse_array.items()}, new_shape) indices_span = perm([range(i) for i in expr.shape]) new_array = [None]*len(expr) for i, idx in enumerate(itertools.product(*indices_span)): t = iperm(idx) new_array[i] = expr[t] return type(expr)(new_array, new_shape) class Flatten(Basic): ''' Flatten an iterable object to a list in a lazy-evaluation way. Notes ===== This class is an iterator with which the memory cost can be economised. Optimisation has been considered to ameliorate the performance for some specific data types like DenseNDimArray and SparseNDimArray. Examples ======== >>> from sympy.tensor.array.arrayop import Flatten >>> from sympy.tensor.array import Array >>> A = Array(range(6)).reshape(2, 3) >>> Flatten(A) Flatten([[0, 1, 2], [3, 4, 5]]) >>> [i for i in Flatten(A)] [0, 1, 2, 3, 4, 5] ''' def __init__(self, iterable): from sympy.matrices.matrices import MatrixBase from sympy.tensor.array import NDimArray if not isinstance(iterable, (Iterable, MatrixBase)): raise NotImplementedError("Data type not yet supported") if isinstance(iterable, list): iterable = NDimArray(iterable) self._iter = iterable self._idx = 0 def __iter__(self): return self def __next__(self): from sympy.matrices.matrices import MatrixBase if len(self._iter) > self._idx: if isinstance(self._iter, DenseNDimArray): result = self._iter._array[self._idx] elif isinstance(self._iter, SparseNDimArray): if self._idx in self._iter._sparse_array: result = self._iter._sparse_array[self._idx] else: result = 0 elif isinstance(self._iter, MatrixBase): result = self._iter[self._idx] elif hasattr(self._iter, '__next__'): result = next(self._iter) else: result = self._iter[self._idx] else: raise StopIteration self._idx += 1 return result def next(self): return self.__next__() sympy-sympy-1.9/sympy/tensor/array/dense_ndim_array.py000066400000000000000000000140531412543434000234140ustar00rootroot00000000000000import functools from sympy import Basic, Tuple, S from sympy.core.sympify import _sympify from sympy.tensor.array.mutable_ndim_array import MutableNDimArray from sympy.tensor.array.ndim_array import NDimArray, ImmutableNDimArray from sympy.simplify.simplify import simplify class DenseNDimArray(NDimArray): def __new__(self, *args, **kwargs): return ImmutableDenseNDimArray(*args, **kwargs) def __getitem__(self, index): """ Allows to get items from N-dim array. Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray([0, 1, 2, 3], (2, 2)) >>> a [[0, 1], [2, 3]] >>> a[0, 0] 0 >>> a[1, 1] 3 >>> a[0] [0, 1] >>> a[1] [2, 3] Symbolic index: >>> from sympy.abc import i, j >>> a[i, j] [[0, 1], [2, 3]][i, j] Replace `i` and `j` to get element `(1, 1)`: >>> a[i, j].subs({i: 1, j: 1}) 3 """ syindex = self._check_symbolic_index(index) if syindex is not None: return syindex index = self._check_index_for_getitem(index) if isinstance(index, tuple) and any([isinstance(i, slice) for i in index]): sl_factors, eindices = self._get_slice_data_for_array_access(index) array = [self._array[self._parse_index(i)] for i in eindices] nshape = [len(el) for i, el in enumerate(sl_factors) if isinstance(index[i], slice)] return type(self)(array, nshape) else: index = self._parse_index(index) return self._array[index] @classmethod def zeros(cls, *shape): list_length = functools.reduce(lambda x, y: x*y, shape, S.One) return cls._new(([0]*list_length,), shape) def tomatrix(self): """ Converts MutableDenseNDimArray to Matrix. Can convert only 2-dim array, else will raise error. Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray([1 for i in range(9)], (3, 3)) >>> b = a.tomatrix() >>> b Matrix([ [1, 1, 1], [1, 1, 1], [1, 1, 1]]) """ from sympy.matrices import Matrix if self.rank() != 2: raise ValueError('Dimensions must be of size of 2') return Matrix(self.shape[0], self.shape[1], self._array) def reshape(self, *newshape): """ Returns MutableDenseNDimArray instance with new shape. Elements number must be suitable to new shape. The only argument of method sets new shape. Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray([1, 2, 3, 4, 5, 6], (2, 3)) >>> a.shape (2, 3) >>> a [[1, 2, 3], [4, 5, 6]] >>> b = a.reshape(3, 2) >>> b.shape (3, 2) >>> b [[1, 2], [3, 4], [5, 6]] """ new_total_size = functools.reduce(lambda x,y: x*y, newshape) if new_total_size != self._loop_size: raise ValueError("Invalid reshape parameters " + newshape) # there is no `.func` as this class does not subtype `Basic`: return type(self)(self._array, newshape) class ImmutableDenseNDimArray(DenseNDimArray, ImmutableNDimArray): """ """ def __new__(cls, iterable, shape=None, **kwargs): return cls._new(iterable, shape, **kwargs) @classmethod def _new(cls, iterable, shape, **kwargs): from sympy.utilities.iterables import flatten shape, flat_list = cls._handle_ndarray_creation_inputs(iterable, shape, **kwargs) shape = Tuple(*map(_sympify, shape)) cls._check_special_bounds(flat_list, shape) flat_list = flatten(flat_list) flat_list = Tuple(*flat_list) self = Basic.__new__(cls, flat_list, shape, **kwargs) self._shape = shape self._array = list(flat_list) self._rank = len(shape) self._loop_size = functools.reduce(lambda x,y: x*y, shape, 1) return self def __setitem__(self, index, value): raise TypeError('immutable N-dim array') def as_mutable(self): return MutableDenseNDimArray(self) def _eval_simplify(self, **kwargs): return self.applyfunc(simplify) class MutableDenseNDimArray(DenseNDimArray, MutableNDimArray): def __new__(cls, iterable=None, shape=None, **kwargs): return cls._new(iterable, shape, **kwargs) @classmethod def _new(cls, iterable, shape, **kwargs): from sympy.utilities.iterables import flatten shape, flat_list = cls._handle_ndarray_creation_inputs(iterable, shape, **kwargs) flat_list = flatten(flat_list) self = object.__new__(cls) self._shape = shape self._array = list(flat_list) self._rank = len(shape) self._loop_size = functools.reduce(lambda x,y: x*y, shape) if shape else len(flat_list) return self def __setitem__(self, index, value): """Allows to set items to MutableDenseNDimArray. Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(2, 2) >>> a[0,0] = 1 >>> a[1,1] = 1 >>> a [[1, 0], [0, 1]] """ if isinstance(index, tuple) and any([isinstance(i, slice) for i in index]): value, eindices, slice_offsets = self._get_slice_data_for_array_assignment(index, value) for i in eindices: other_i = [ind - j for ind, j in zip(i, slice_offsets) if j is not None] self._array[self._parse_index(i)] = value[other_i] else: index = self._parse_index(index) self._setter_iterable_check(value) value = _sympify(value) self._array[index] = value def as_immutable(self): return ImmutableDenseNDimArray(self) @property def free_symbols(self): return {i for j in self._array for i in j.free_symbols} sympy-sympy-1.9/sympy/tensor/array/expressions/000077500000000000000000000000001412543434000221165ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/array/expressions/__init__.py000066400000000000000000000000001412543434000242150ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/array/expressions/array_expressions.py000066400000000000000000001650121412543434000262550ustar00rootroot00000000000000import operator from functools import reduce import itertools from itertools import accumulate from typing import Optional, List, Dict from sympy import Expr, ImmutableDenseNDimArray, S, Symbol, Integer, ZeroMatrix, Basic, tensorproduct, Add, permutedims, \ Tuple, tensordiagonal, Lambda, Dummy, Function, MatrixExpr, NDimArray, Indexed, IndexedBase, default_sort_key, \ tensorcontraction, diagonalize_vector, Mul from sympy.matrices.expressions.matexpr import MatrixElement from sympy.tensor.array.expressions.utils import _apply_recursively_over_nested_lists, _sort_contraction_indices, \ _get_mapping_from_subranks, _build_push_indices_up_func_transformation, _get_contraction_links, \ _build_push_indices_down_func_transformation from sympy.combinatorics import Permutation from sympy.combinatorics.permutations import _af_invert from sympy.core.sympify import _sympify class _ArrayExpr(Expr): pass class ArraySymbol(_ArrayExpr): """ Symbol representing an array expression """ def __new__(cls, symbol, *shape): if isinstance(symbol, str): symbol = Symbol(symbol) # symbol = _sympify(symbol) shape = map(_sympify, shape) obj = Expr.__new__(cls, symbol, *shape) return obj @property def name(self): return self._args[0] @property def shape(self): return self._args[1:] def __getitem__(self, item): return ArrayElement(self, item) def as_explicit(self): if any(not isinstance(i, (int, Integer)) for i in self.shape): raise ValueError("cannot express explicit array with symbolic shape") data = [self[i] for i in itertools.product(*[range(j) for j in self.shape])] return ImmutableDenseNDimArray(data).reshape(*self.shape) class ArrayElement(_ArrayExpr): """ An element of an array. """ def __new__(cls, name, indices): if isinstance(name, str): name = Symbol(name) name = _sympify(name) indices = _sympify(indices) if hasattr(name, "shape"): if any([(i >= s) == True for i, s in zip(indices, name.shape)]): raise ValueError("shape is out of bounds") if any([(i < 0) == True for i in indices]): raise ValueError("shape contains negative values") obj = Expr.__new__(cls, name, indices) return obj @property def name(self): return self._args[0] @property def indices(self): return self._args[1] class ZeroArray(_ArrayExpr): """ Symbolic array of zeros. Equivalent to ``ZeroMatrix`` for matrices. """ def __new__(cls, *shape): if len(shape) == 0: return S.Zero shape = map(_sympify, shape) obj = Expr.__new__(cls, *shape) return obj @property def shape(self): return self._args def as_explicit(self): if any(not i.is_Integer for i in self.shape): raise ValueError("Cannot return explicit form for symbolic shape.") return ImmutableDenseNDimArray.zeros(*self.shape) class OneArray(_ArrayExpr): """ Symbolic array of ones. """ def __new__(cls, *shape): if len(shape) == 0: return S.One shape = map(_sympify, shape) obj = Expr.__new__(cls, *shape) return obj @property def shape(self): return self._args def as_explicit(self): if any(not i.is_Integer for i in self.shape): raise ValueError("Cannot return explicit form for symbolic shape.") return ImmutableDenseNDimArray([S.One for i in range(reduce(operator.mul, self.shape))]).reshape(*self.shape) class _CodegenArrayAbstract(Basic): @property def subranks(self): """ Returns the ranks of the objects in the uppermost tensor product inside the current object. In case no tensor products are contained, return the atomic ranks. Examples ======== >>> from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayContraction >>> from sympy import MatrixSymbol >>> M = MatrixSymbol("M", 3, 3) >>> N = MatrixSymbol("N", 3, 3) >>> P = MatrixSymbol("P", 3, 3) Important: do not confuse the rank of the matrix with the rank of an array. >>> tp = ArrayTensorProduct(M, N, P) >>> tp.subranks [2, 2, 2] >>> co = ArrayContraction(tp, (1, 2), (3, 4)) >>> co.subranks [2, 2, 2] """ return self._subranks[:] def subrank(self): """ The sum of ``subranks``. """ return sum(self.subranks) @property def shape(self): return self._shape class ArrayTensorProduct(_CodegenArrayAbstract): r""" Class to represent the tensor product of array-like objects. """ def __new__(cls, *args): args = [_sympify(arg) for arg in args] args = cls._flatten(args) ranks = [get_rank(arg) for arg in args] # Check if there are nested permutation and lift them up: permutation_cycles = [] for i, arg in enumerate(args): if not isinstance(arg, PermuteDims): continue permutation_cycles.extend([[k + sum(ranks[:i]) for k in j] for j in arg.permutation.cyclic_form]) args[i] = arg.expr if permutation_cycles: return PermuteDims(ArrayTensorProduct(*args), Permutation(sum(ranks)-1)*Permutation(permutation_cycles)) if len(args) == 1: return args[0] # If any object is a ZeroArray, return a ZeroArray: if any(isinstance(arg, (ZeroArray, ZeroMatrix)) for arg in args): shapes = reduce(operator.add, [get_shape(i) for i in args], ()) return ZeroArray(*shapes) # If there are contraction objects inside, transform the whole # expression into `ArrayContraction`: contractions = {i: arg for i, arg in enumerate(args) if isinstance(arg, ArrayContraction)} if contractions: ranks = [_get_subrank(arg) if isinstance(arg, ArrayContraction) else get_rank(arg) for arg in args] cumulative_ranks = list(accumulate([0] + ranks))[:-1] tp = cls(*[arg.expr if isinstance(arg, ArrayContraction) else arg for arg in args]) contraction_indices = [tuple(cumulative_ranks[i] + k for k in j) for i, arg in contractions.items() for j in arg.contraction_indices] return ArrayContraction(tp, *contraction_indices) diagonals = {i: arg for i, arg in enumerate(args) if isinstance(arg, ArrayDiagonal)} if diagonals: permutation = [] last_perm = [] ranks = [get_rank(arg) for arg in args] cumulative_ranks = list(accumulate([0] + ranks))[:-1] for i, arg in enumerate(args): if isinstance(arg, ArrayDiagonal): i1 = get_rank(arg) - len(arg.diagonal_indices) i2 = len(arg.diagonal_indices) permutation.extend([cumulative_ranks[i] + j for j in range(i1)]) last_perm.extend([cumulative_ranks[i] + j for j in range(i1, i1 + i2)]) else: permutation.extend([cumulative_ranks[i] + j for j in range(get_rank(arg))]) permutation.extend(last_perm) tp = cls(*[arg.expr if isinstance(arg, ArrayDiagonal) else arg for arg in args]) ranks2 = [_get_subrank(arg) if isinstance(arg, ArrayDiagonal) else get_rank(arg) for arg in args] cumulative_ranks2 = list(accumulate([0] + ranks2))[:-1] diagonal_indices = [tuple(cumulative_ranks2[i] + k for k in j) for i, arg in diagonals.items() for j in arg.diagonal_indices] return PermuteDims(ArrayDiagonal(tp, *diagonal_indices), permutation) obj = Basic.__new__(cls, *args) obj._subranks = ranks shapes = [get_shape(i) for i in args] if any(i is None for i in shapes): obj._shape = None else: obj._shape = tuple(j for i in shapes for j in i) return obj @classmethod def _flatten(cls, args): args = [i for arg in args for i in (arg.args if isinstance(arg, cls) else [arg])] return args def as_explicit(self): return tensorproduct(*[arg.as_explicit() if hasattr(arg, "as_explicit") else arg for arg in self.args]) class ArrayAdd(_CodegenArrayAbstract): r""" Class for elementwise array additions. """ def __new__(cls, *args): args = [_sympify(arg) for arg in args] ranks = [get_rank(arg) for arg in args] ranks = list(set(ranks)) if len(ranks) != 1: raise ValueError("summing arrays of different ranks") shapes = [arg.shape for arg in args] if len({i for i in shapes if i is not None}) > 1: raise ValueError("mismatching shapes in addition") # Flatten: args = cls._flatten_args(args) args = [arg for arg in args if not isinstance(arg, (ZeroArray, ZeroMatrix))] if len(args) == 0: if any(i for i in shapes if i is None): raise NotImplementedError("cannot handle addition of ZeroMatrix/ZeroArray and undefined shape object") return ZeroArray(*shapes[0]) elif len(args) == 1: return args[0] obj = Basic.__new__(cls, *args) obj._subranks = ranks if any(i is None for i in shapes): obj._shape = None else: obj._shape = shapes[0] return obj @classmethod def _flatten_args(cls, args): new_args = [] for arg in args: if isinstance(arg, ArrayAdd): new_args.extend(arg.args) else: new_args.append(arg) return new_args def as_explicit(self): return Add.fromiter([arg.as_explicit() for arg in self.args]) class PermuteDims(_CodegenArrayAbstract): r""" Class to represent permutation of axes of arrays. Examples ======== >>> from sympy.tensor.array.expressions.array_expressions import PermuteDims >>> from sympy import MatrixSymbol >>> M = MatrixSymbol("M", 3, 3) >>> cg = PermuteDims(M, [1, 0]) The object ``cg`` represents the transposition of ``M``, as the permutation ``[1, 0]`` will act on its indices by switching them: `M_{ij} \Rightarrow M_{ji}` This is evident when transforming back to matrix form: >>> from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix >>> convert_array_to_matrix(cg) M.T >>> N = MatrixSymbol("N", 3, 2) >>> cg = PermuteDims(N, [1, 0]) >>> cg.shape (2, 3) Permutations of tensor products are simplified in order to achieve a standard form: >>> from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct >>> M = MatrixSymbol("M", 4, 5) >>> tp = ArrayTensorProduct(M, N) >>> tp.shape (4, 5, 3, 2) >>> perm1 = PermuteDims(tp, [2, 3, 1, 0]) The args ``(M, N)`` have been sorted and the permutation has been simplified, the expression is equivalent: >>> perm1.expr.args (N, M) >>> perm1.shape (3, 2, 5, 4) >>> perm1.permutation (2 3) The permutation in its array form has been simplified from ``[2, 3, 1, 0]`` to ``[0, 1, 3, 2]``, as the arguments of the tensor product `M` and `N` have been switched: >>> perm1.permutation.array_form [0, 1, 3, 2] We can nest a second permutation: >>> perm2 = PermuteDims(perm1, [1, 0, 2, 3]) >>> perm2.shape (2, 3, 5, 4) >>> perm2.permutation.array_form [1, 0, 3, 2] """ def __new__(cls, expr, permutation, nest_permutation=True): from sympy.combinatorics import Permutation expr = _sympify(expr) permutation = Permutation(permutation) permutation_size = permutation.size expr_rank = get_rank(expr) if permutation_size != expr_rank: raise ValueError("Permutation size must be the length of the shape of expr") if isinstance(expr, PermuteDims): subexpr = expr.expr subperm = expr.permutation permutation = permutation * subperm expr = subexpr if isinstance(expr, ArrayContraction): expr, permutation = cls._handle_nested_contraction(expr, permutation) if isinstance(expr, ArrayTensorProduct): expr, permutation = cls._sort_components(expr, permutation) if isinstance(expr, (ZeroArray, ZeroMatrix)): return ZeroArray(*[expr.shape[i] for i in permutation.array_form]) plist = permutation.array_form if plist == sorted(plist): return expr obj = Basic.__new__(cls, expr, permutation) obj._subranks = [get_rank(expr)] shape = expr.shape if shape is None: obj._shape = None else: obj._shape = tuple(shape[permutation(i)] for i in range(len(shape))) return obj @property def expr(self): return self.args[0] @property def permutation(self): return self.args[1] @classmethod def _sort_components(cls, expr, permutation): # Get the permutation in its image-form: perm_image_form = _af_invert(permutation.array_form) args = list(expr.args) # Starting index global position for every arg: cumul = list(accumulate([0] + expr.subranks)) # Split `perm_image_form` into a list of list corresponding to the indices # of every argument: perm_image_form_in_components = [perm_image_form[cumul[i]:cumul[i+1]] for i in range(len(args))] # Create an index, target-position-key array: ps = [(i, sorted(comp)) for i, comp in enumerate(perm_image_form_in_components)] # Sort the array according to the target-position-key: # In this way, we define a canonical way to sort the arguments according # to the permutation. ps.sort(key=lambda x: x[1]) # Read the inverse-permutation (i.e. image-form) of the args: perm_args_image_form = [i[0] for i in ps] # Apply the args-permutation to the `args`: args_sorted = [args[i] for i in perm_args_image_form] # Apply the args-permutation to the array-form of the permutation of the axes (of `expr`): perm_image_form_sorted_args = [perm_image_form_in_components[i] for i in perm_args_image_form] new_permutation = Permutation(_af_invert([j for i in perm_image_form_sorted_args for j in i])) return ArrayTensorProduct(*args_sorted), new_permutation @classmethod def _handle_nested_contraction(cls, expr, permutation): if not isinstance(expr, ArrayContraction): return expr, permutation if not isinstance(expr.expr, ArrayTensorProduct): return expr, permutation args = expr.expr.args subranks = [get_rank(arg) for arg in expr.expr.args] contraction_indices = expr.contraction_indices contraction_indices_flat = [j for i in contraction_indices for j in i] cumul = list(accumulate([0] + subranks)) # Spread the permutation in its array form across the args in the corresponding # tensor-product arguments with free indices: permutation_array_blocks_up = [] image_form = _af_invert(permutation.array_form) counter = 0 for i, e in enumerate(subranks): current = [] for j in range(cumul[i], cumul[i+1]): if j in contraction_indices_flat: continue current.append(image_form[counter]) counter += 1 permutation_array_blocks_up.append(current) # Get the map of axis repositioning for every argument of tensor-product: index_blocks = [[j for j in range(cumul[i], cumul[i+1])] for i, e in enumerate(expr.subranks)] index_blocks_up = expr._push_indices_up(expr.contraction_indices, index_blocks) inverse_permutation = permutation**(-1) index_blocks_up_permuted = [[inverse_permutation(j) for j in i if j is not None] for i in index_blocks_up] # Sorting key is a list of tuple, first element is the index of `args`, second element of # the tuple is the sorting key to sort `args` of the tensor product: sorting_keys = list(enumerate(index_blocks_up_permuted)) sorting_keys.sort(key=lambda x: x[1]) # Now we can get the permutation acting on the args in its image-form: new_perm_image_form = [i[0] for i in sorting_keys] # Apply the args-level permutation to various elements: new_index_blocks = [index_blocks[i] for i in new_perm_image_form] new_index_perm_array_form = _af_invert([j for i in new_index_blocks for j in i]) new_args = [args[i] for i in new_perm_image_form] new_contraction_indices = [tuple(new_index_perm_array_form[j] for j in i) for i in contraction_indices] new_expr = ArrayContraction(ArrayTensorProduct(*new_args), *new_contraction_indices) new_permutation = Permutation(_af_invert([j for i in [permutation_array_blocks_up[k] for k in new_perm_image_form] for j in i])) return new_expr, new_permutation @classmethod def _check_permutation_mapping(cls, expr, permutation): subranks = expr.subranks index2arg = [i for i, arg in enumerate(expr.args) for j in range(expr.subranks[i])] permuted_indices = [permutation(i) for i in range(expr.subrank())] new_args = list(expr.args) arg_candidate_index = index2arg[permuted_indices[0]] current_indices = [] new_permutation = [] inserted_arg_cand_indices = set([]) for i, idx in enumerate(permuted_indices): if index2arg[idx] != arg_candidate_index: new_permutation.extend(current_indices) current_indices = [] arg_candidate_index = index2arg[idx] current_indices.append(idx) arg_candidate_rank = subranks[arg_candidate_index] if len(current_indices) == arg_candidate_rank: new_permutation.extend(sorted(current_indices)) local_current_indices = [j - min(current_indices) for j in current_indices] i1 = index2arg[i] new_args[i1] = PermuteDims(new_args[i1], Permutation(local_current_indices)) inserted_arg_cand_indices.add(arg_candidate_index) current_indices = [] new_permutation.extend(current_indices) # TODO: swap args positions in order to simplify the expression: # TODO: this should be in a function args_positions = list(range(len(new_args))) # Get possible shifts: maps = {} cumulative_subranks = [0] + list(accumulate(subranks)) for i in range(0, len(subranks)): s = set([index2arg[new_permutation[j]] for j in range(cumulative_subranks[i], cumulative_subranks[i+1])]) if len(s) != 1: continue elem = next(iter(s)) if i != elem: maps[i] = elem # Find cycles in the map: lines = [] current_line = [] while maps: if len(current_line) == 0: k, v = maps.popitem() current_line.append(k) else: k = current_line[-1] if k not in maps: current_line = [] continue v = maps.pop(k) if v in current_line: lines.append(current_line) current_line = [] continue current_line.append(v) for line in lines: for i, e in enumerate(line): args_positions[line[(i + 1) % len(line)]] = e # TODO: function in order to permute the args: permutation_blocks = [[new_permutation[cumulative_subranks[i] + j] for j in range(e)] for i, e in enumerate(subranks)] new_args = [new_args[i] for i in args_positions] new_permutation_blocks = [permutation_blocks[i] for i in args_positions] new_permutation2 = [j for i in new_permutation_blocks for j in i] return ArrayTensorProduct(*new_args), Permutation(new_permutation2) # **(-1) @classmethod def _check_if_there_are_closed_cycles(cls, expr, permutation): args = list(expr.args) subranks = expr.subranks cyclic_form = permutation.cyclic_form cumulative_subranks = [0] + list(accumulate(subranks)) cyclic_min = [min(i) for i in cyclic_form] cyclic_max = [max(i) for i in cyclic_form] cyclic_keep = [] for i, cycle in enumerate(cyclic_form): flag = True for j in range(0, len(cumulative_subranks) - 1): if cyclic_min[i] >= cumulative_subranks[j] and cyclic_max[i] < cumulative_subranks[j+1]: # Found a sinkable cycle. args[j] = PermuteDims(args[j], Permutation([[k - cumulative_subranks[j] for k in cyclic_form[i]]])) flag = False break if flag: cyclic_keep.append(cyclic_form[i]) return ArrayTensorProduct(*args), Permutation(cyclic_keep, size=permutation.size) def nest_permutation(self): r""" DEPRECATED. """ ret = self._nest_permutation(self.expr, self.permutation) if ret is None: return self return ret @classmethod def _nest_permutation(cls, expr, permutation): if isinstance(expr, ArrayTensorProduct): return PermuteDims(*cls._check_if_there_are_closed_cycles(expr, permutation)) elif isinstance(expr, ArrayContraction): # Invert tree hierarchy: put the contraction above. cycles = permutation.cyclic_form newcycles = ArrayContraction._convert_outer_indices_to_inner_indices(expr, *cycles) newpermutation = Permutation(newcycles) new_contr_indices = [tuple(newpermutation(j) for j in i) for i in expr.contraction_indices] return ArrayContraction(PermuteDims(expr.expr, newpermutation), *new_contr_indices) elif isinstance(expr, ArrayAdd): return ArrayAdd(*[PermuteDims(arg, permutation) for arg in expr.args]) return None def as_explicit(self): return permutedims(self.expr.as_explicit(), self.permutation) class ArrayDiagonal(_CodegenArrayAbstract): r""" Class to represent the diagonal operator. Explanation =========== In a 2-dimensional array it returns the diagonal, this looks like the operation: `A_{ij} \rightarrow A_{ii}` The diagonal over axes 1 and 2 (the second and third) of the tensor product of two 2-dimensional arrays `A \otimes B` is `\Big[ A_{ab} B_{cd} \Big]_{abcd} \rightarrow \Big[ A_{ai} B_{id} \Big]_{adi}` In this last example the array expression has been reduced from 4-dimensional to 3-dimensional. Notice that no contraction has occurred, rather there is a new index `i` for the diagonal, contraction would have reduced the array to 2 dimensions. Notice that the diagonalized out dimensions are added as new dimensions at the end of the indices. """ def __new__(cls, expr, *diagonal_indices): expr = _sympify(expr) diagonal_indices = [Tuple(*sorted(i)) for i in diagonal_indices] if isinstance(expr, ArrayAdd): return ArrayAdd(*[ArrayDiagonal(arg, *diagonal_indices) for arg in expr.args]) if isinstance(expr, ArrayDiagonal): return cls._flatten(expr, *diagonal_indices) if isinstance(expr, PermuteDims): return cls._handle_nested_permutedims_in_diag(expr, *diagonal_indices) shape = get_shape(expr) if shape is not None: cls._validate(expr, *diagonal_indices) # Get new shape: positions, shape = cls._get_positions_shape(shape, diagonal_indices) else: positions = None if len(diagonal_indices) == 0: return expr if isinstance(expr, (ZeroArray, ZeroMatrix)): return ZeroArray(*shape) obj = Basic.__new__(cls, expr, *diagonal_indices) obj._positions = positions obj._subranks = _get_subranks(expr) obj._shape = shape return obj @staticmethod def _validate(expr, *diagonal_indices): # Check that no diagonalization happens on indices with mismatched # dimensions: shape = get_shape(expr) for i in diagonal_indices: if len({shape[j] for j in i}) != 1: raise ValueError("diagonalizing indices of different dimensions") if len(i) <= 1: raise ValueError("need at least two axes to diagonalize") @staticmethod def _remove_trivial_dimensions(shape, *diagonal_indices): return [tuple(j for j in i) for i in diagonal_indices if shape[i[0]] != 1] @property def expr(self): return self.args[0] @property def diagonal_indices(self): return self.args[1:] @staticmethod def _flatten(expr, *outer_diagonal_indices): inner_diagonal_indices = expr.diagonal_indices all_inner = [j for i in inner_diagonal_indices for j in i] all_inner.sort() # TODO: add API for total rank and cumulative rank: total_rank = _get_subrank(expr) inner_rank = len(all_inner) outer_rank = total_rank - inner_rank shifts = [0 for i in range(outer_rank)] counter = 0 pointer = 0 for i in range(outer_rank): while pointer < inner_rank and counter >= all_inner[pointer]: counter += 1 pointer += 1 shifts[i] += pointer counter += 1 outer_diagonal_indices = tuple(tuple(shifts[j] + j for j in i) for i in outer_diagonal_indices) diagonal_indices = inner_diagonal_indices + outer_diagonal_indices return ArrayDiagonal(expr.expr, *diagonal_indices) @classmethod def _handle_nested_permutedims_in_diag(cls, expr: PermuteDims, *diagonal_indices): back_diagonal_indices = [[expr.permutation(j) for j in i] for i in diagonal_indices] nondiag = [i for i in range(get_rank(expr)) if not any(i in j for j in diagonal_indices)] back_nondiag = [expr.permutation(i) for i in nondiag] remap = {e: i for i, e in enumerate(sorted(back_nondiag))} new_permutation1 = [remap[i] for i in back_nondiag] shift = len(new_permutation1) diag_block_perm = [i + shift for i in range(len(back_diagonal_indices))] new_permutation = new_permutation1 + diag_block_perm return PermuteDims( ArrayDiagonal( expr.expr, *back_diagonal_indices ), new_permutation ) def _push_indices_down_nonstatic(self, indices): transform = lambda x: self._positions[x] if x < len(self._positions) else None return _apply_recursively_over_nested_lists(transform, indices) def _push_indices_up_nonstatic(self, indices): def transform(x): for i, e in enumerate(self._positions): if (isinstance(e, int) and x == e) or (isinstance(e, tuple) and x in e): return i return _apply_recursively_over_nested_lists(transform, indices) @classmethod def _push_indices_down(cls, diagonal_indices, indices, rank): positions, shape = cls._get_positions_shape(range(rank), diagonal_indices) transform = lambda x: positions[x] if x < len(positions) else None return _apply_recursively_over_nested_lists(transform, indices) @classmethod def _push_indices_up(cls, diagonal_indices, indices, rank): positions, shape = cls._get_positions_shape(range(rank), diagonal_indices) def transform(x): for i, e in enumerate(positions): if (isinstance(e, int) and x == e) or (isinstance(e, (tuple, Tuple)) and (x in e)): return i return _apply_recursively_over_nested_lists(transform, indices) @classmethod def _get_positions_shape(cls, shape, diagonal_indices): data1 = tuple((i, shp) for i, shp in enumerate(shape) if not any(i in j for j in diagonal_indices)) pos1, shp1 = zip(*data1) if data1 else ((), ()) data2 = tuple((i, shape[i[0]]) for i in diagonal_indices) pos2, shp2 = zip(*data2) if data2 else ((), ()) positions = pos1 + pos2 shape = shp1 + shp2 return positions, shape def as_explicit(self): return tensordiagonal(self.expr.as_explicit(), *self.diagonal_indices) class ArrayElementwiseApplyFunc(_CodegenArrayAbstract): def __new__(cls, function, element): if not isinstance(function, Lambda): d = Dummy('d') function = Lambda(d, function(d)) obj = _CodegenArrayAbstract.__new__(cls, function, element) obj._subranks = _get_subranks(element) return obj @property def function(self): return self.args[0] @property def expr(self): return self.args[1] @property def shape(self): return self.expr.shape def _get_function_fdiff(self): d = Dummy("d") function = self.function(d) fdiff = function.diff(d) if isinstance(fdiff, Function): fdiff = type(fdiff) else: fdiff = Lambda(d, fdiff) return fdiff class ArrayContraction(_CodegenArrayAbstract): r""" This class is meant to represent contractions of arrays in a form easily processable by the code printers. """ def __new__(cls, expr, *contraction_indices, **kwargs): contraction_indices = _sort_contraction_indices(contraction_indices) expr = _sympify(expr) if len(contraction_indices) == 0: return expr if isinstance(expr, ArrayContraction): return cls._flatten(expr, *contraction_indices) if isinstance(expr, (ZeroArray, ZeroMatrix)): contraction_indices_flat = [j for i in contraction_indices for j in i] shape = [e for i, e in enumerate(expr.shape) if i not in contraction_indices_flat] return ZeroArray(*shape) if isinstance(expr, PermuteDims): return cls._handle_nested_permute_dims(expr, *contraction_indices) if isinstance(expr, ArrayTensorProduct): expr, contraction_indices = cls._sort_fully_contracted_args(expr, contraction_indices) expr, contraction_indices = cls._lower_contraction_to_addends(expr, contraction_indices) if len(contraction_indices) == 0: return expr if isinstance(expr, ArrayDiagonal): return cls._handle_nested_diagonal(expr, *contraction_indices) if isinstance(expr, ArrayAdd): return ArrayAdd(*[ArrayContraction(i, *contraction_indices) for i in expr.args]) obj = Basic.__new__(cls, expr, *contraction_indices) obj._subranks = _get_subranks(expr) obj._mapping = _get_mapping_from_subranks(obj._subranks) free_indices_to_position = {i: i for i in range(sum(obj._subranks)) if all([i not in cind for cind in contraction_indices])} obj._free_indices_to_position = free_indices_to_position shape = expr.shape cls._validate(expr, *contraction_indices) if shape: shape = tuple(shp for i, shp in enumerate(shape) if not any(i in j for j in contraction_indices)) obj._shape = shape return obj def __mul__(self, other): if other == 1: return self else: raise NotImplementedError("Product of N-dim arrays is not uniquely defined. Use another method.") def __rmul__(self, other): if other == 1: return self else: raise NotImplementedError("Product of N-dim arrays is not uniquely defined. Use another method.") @staticmethod def _validate(expr, *contraction_indices): shape = expr.shape if shape is None: return # Check that no contraction happens when the shape is mismatched: for i in contraction_indices: if len({shape[j] for j in i if shape[j] != -1}) != 1: raise ValueError("contracting indices of different dimensions") @classmethod def _push_indices_down(cls, contraction_indices, indices): flattened_contraction_indices = [j for i in contraction_indices for j in i] flattened_contraction_indices.sort() transform = _build_push_indices_down_func_transformation(flattened_contraction_indices) return _apply_recursively_over_nested_lists(transform, indices) @classmethod def _push_indices_up(cls, contraction_indices, indices): flattened_contraction_indices = [j for i in contraction_indices for j in i] flattened_contraction_indices.sort() transform = _build_push_indices_up_func_transformation(flattened_contraction_indices) return _apply_recursively_over_nested_lists(transform, indices) @classmethod def _lower_contraction_to_addends(cls, expr, contraction_indices): if isinstance(expr, ArrayAdd): raise NotImplementedError() if not isinstance(expr, ArrayTensorProduct): return expr, contraction_indices subranks = expr.subranks cumranks = list(accumulate([0] + subranks)) contraction_indices_remaining = [] contraction_indices_args = [[] for i in expr.args] backshift = set([]) for i, contraction_group in enumerate(contraction_indices): for j in range(len(expr.args)): if not isinstance(expr.args[j], ArrayAdd): continue if all(cumranks[j] <= k < cumranks[j+1] for k in contraction_group): contraction_indices_args[j].append([k - cumranks[j] for k in contraction_group]) backshift.update(contraction_group) break else: contraction_indices_remaining.append(contraction_group) if len(contraction_indices_remaining) == len(contraction_indices): return expr, contraction_indices total_rank = get_rank(expr) shifts = list(accumulate([1 if i in backshift else 0 for i in range(total_rank)])) contraction_indices_remaining = [Tuple.fromiter(j - shifts[j] for j in i) for i in contraction_indices_remaining] ret = ArrayTensorProduct(*[ ArrayContraction(arg, *contr) for arg, contr in zip(expr.args, contraction_indices_args) ]) return ret, contraction_indices_remaining def split_multiple_contractions(self): """ Recognize multiple contractions and attempt at rewriting them as paired-contractions. This allows some contractions involving more than two indices to be rewritten as multiple contractions involving two indices, thus allowing the expression to be rewritten as a matrix multiplication line. Examples: * `A_ij b_j0 C_jk` ===> `A*DiagMatrix(b)*C` Care for: - matrix being diagonalized (i.e. `A_ii`) - vectors being diagonalized (i.e. `a_i0`) Multiple contractions can be split into matrix multiplications if not more than two arguments are non-diagonals or non-vectors. Vectors get diagonalized while diagonal matrices remain diagonal. The non-diagonal matrices can be at the beginning or at the end of the final matrix multiplication line. """ from sympy import ask, Q editor = _EditArrayContraction(self) contraction_indices = self.contraction_indices if isinstance(self.expr, ArrayTensorProduct): args = list(self.expr.args) else: args = [self.expr] # TODO: unify API, best location in ArrayTensorProduct subranks = [get_rank(i) for i in args] # TODO: unify API mapping = _get_mapping_from_subranks(subranks) reverse_mapping = {v: k for k, v in mapping.items()} for indl, links in enumerate(contraction_indices): if len(links) <= 2: continue positions = editor.get_mapping_for_index(indl) # Also consider the case of diagonal matrices being contracted: current_dimension = self.expr.shape[links[0]] not_vectors: Tuple[_ArgE, int] = [] vectors: Tuple[_ArgE, int] = [] for arg_ind, rel_ind in positions: mat = args[arg_ind] other_arg_pos = 1-rel_ind other_arg_abs = reverse_mapping[arg_ind, other_arg_pos] arg = editor.args_with_ind[arg_ind] if (((1 not in mat.shape) and (not ask(Q.diagonal(mat)))) or ((current_dimension == 1) is True and mat.shape != (1, 1)) or any([other_arg_abs in l for li, l in enumerate(contraction_indices) if li != indl]) ): not_vectors.append((arg, rel_ind)) else: vectors.append((arg, rel_ind)) if len(not_vectors) > 2: # If more than two arguments in the multiple contraction are # non-vectors and non-diagonal matrices, we cannot find a way # to split this contraction into a matrix multiplication line: continue # Three cases to handle: # - zero non-vectors # - one non-vector # - two non-vectors for v, rel_ind in vectors: v.element = diagonalize_vector(v.element) vectors_to_loop = not_vectors[:1] + vectors + not_vectors[1:] first_not_vector, rel_ind = vectors_to_loop[0] new_index = first_not_vector.indices[rel_ind] for v, rel_ind in vectors_to_loop[1:-1]: v.indices[rel_ind] = new_index new_index = editor.get_new_contraction_index() assert v.indices.index(None) == 1 - rel_ind v.indices[v.indices.index(None)] = new_index last_vec, rel_ind = vectors_to_loop[-1] last_vec.indices[rel_ind] = new_index return editor.to_array_contraction() def flatten_contraction_of_diagonal(self): if not isinstance(self.expr, ArrayDiagonal): return self contraction_down = self.expr._push_indices_down(self.expr.diagonal_indices, self.contraction_indices) new_contraction_indices = [] diagonal_indices = self.expr.diagonal_indices[:] for i in contraction_down: contraction_group = list(i) for j in i: diagonal_with = [k for k in diagonal_indices if j in k] contraction_group.extend([l for k in diagonal_with for l in k]) diagonal_indices = [k for k in diagonal_indices if k not in diagonal_with] new_contraction_indices.append(sorted(set(contraction_group))) new_contraction_indices = ArrayDiagonal._push_indices_up(diagonal_indices, new_contraction_indices) return ArrayContraction( ArrayDiagonal( self.expr.expr, *diagonal_indices ), *new_contraction_indices ) @staticmethod def _get_free_indices_to_position_map(free_indices, contraction_indices): free_indices_to_position = {} flattened_contraction_indices = [j for i in contraction_indices for j in i] counter = 0 for ind in free_indices: while counter in flattened_contraction_indices: counter += 1 free_indices_to_position[ind] = counter counter += 1 return free_indices_to_position @staticmethod def _get_index_shifts(expr): """ Get the mapping of indices at the positions before the contraction occurs. Examples ======== >>> from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct >>> from sympy.tensor.array.expressions.array_expressions import ArrayContraction >>> from sympy import MatrixSymbol >>> M = MatrixSymbol("M", 3, 3) >>> N = MatrixSymbol("N", 3, 3) >>> cg = ArrayContraction(ArrayTensorProduct(M, N), [1, 2]) >>> cg._get_index_shifts(cg) [0, 2] Indeed, ``cg`` after the contraction has two dimensions, 0 and 1. They need to be shifted by 0 and 2 to get the corresponding positions before the contraction (that is, 0 and 3). """ inner_contraction_indices = expr.contraction_indices all_inner = [j for i in inner_contraction_indices for j in i] all_inner.sort() # TODO: add API for total rank and cumulative rank: total_rank = _get_subrank(expr) inner_rank = len(all_inner) outer_rank = total_rank - inner_rank shifts = [0 for i in range(outer_rank)] counter = 0 pointer = 0 for i in range(outer_rank): while pointer < inner_rank and counter >= all_inner[pointer]: counter += 1 pointer += 1 shifts[i] += pointer counter += 1 return shifts @staticmethod def _convert_outer_indices_to_inner_indices(expr, *outer_contraction_indices): shifts = ArrayContraction._get_index_shifts(expr) outer_contraction_indices = tuple(tuple(shifts[j] + j for j in i) for i in outer_contraction_indices) return outer_contraction_indices @staticmethod def _flatten(expr, *outer_contraction_indices): inner_contraction_indices = expr.contraction_indices outer_contraction_indices = ArrayContraction._convert_outer_indices_to_inner_indices(expr, *outer_contraction_indices) contraction_indices = inner_contraction_indices + outer_contraction_indices return ArrayContraction(expr.expr, *contraction_indices) @classmethod def _handle_nested_permute_dims(cls, expr, *contraction_indices): permutation = expr.permutation plist = permutation.array_form new_contraction_indices = [tuple(permutation(j) for j in i) for i in contraction_indices] new_plist = [i for i in plist if all(i not in j for j in new_contraction_indices)] new_plist = cls._push_indices_up(new_contraction_indices, new_plist) return PermuteDims( ArrayContraction(expr.expr, *new_contraction_indices), Permutation(new_plist) ) @classmethod def _handle_nested_diagonal(cls, expr: 'ArrayDiagonal', *contraction_indices): diagonal_indices = list(expr.diagonal_indices) down_contraction_indices = expr._push_indices_down(expr.diagonal_indices, contraction_indices, get_rank(expr.expr)) # Flatten diagonally contracted indices: down_contraction_indices = [[k for j in i for k in (j if isinstance(j, (tuple, Tuple)) else [j])] for i in down_contraction_indices] new_contraction_indices = [] for contr_indgrp in down_contraction_indices: ind = contr_indgrp[:] for j, diag_indgrp in enumerate(diagonal_indices): if diag_indgrp is None: continue if any(i in diag_indgrp for i in contr_indgrp): ind.extend(diag_indgrp) diagonal_indices[j] = None new_contraction_indices.append(sorted(set(ind))) new_diagonal_indices_down = [i for i in diagonal_indices if i is not None] new_diagonal_indices = ArrayContraction._push_indices_up(new_contraction_indices, new_diagonal_indices_down) return ArrayDiagonal( ArrayContraction(expr.expr, *new_contraction_indices), *new_diagonal_indices ) @classmethod def _sort_fully_contracted_args(cls, expr, contraction_indices): if expr.shape is None: return expr, contraction_indices cumul = list(accumulate([0] + expr.subranks)) index_blocks = [list(range(cumul[i], cumul[i+1])) for i in range(len(expr.args))] contraction_indices_flat = {j for i in contraction_indices for j in i} fully_contracted = [all(j in contraction_indices_flat for j in range(cumul[i], cumul[i+1])) for i, arg in enumerate(expr.args)] new_pos = sorted(range(len(expr.args)), key=lambda x: (0, default_sort_key(expr.args[x])) if fully_contracted[x] else (1,)) new_args = [expr.args[i] for i in new_pos] new_index_blocks_flat = [j for i in new_pos for j in index_blocks[i]] index_permutation_array_form = _af_invert(new_index_blocks_flat) new_contraction_indices = [tuple(index_permutation_array_form[j] for j in i) for i in contraction_indices] new_contraction_indices = _sort_contraction_indices(new_contraction_indices) return ArrayTensorProduct(*new_args), new_contraction_indices def _get_contraction_tuples(self): r""" Return tuples containing the argument index and position within the argument of the index position. Examples ======== >>> from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct >>> from sympy import MatrixSymbol >>> from sympy.abc import N >>> from sympy.tensor.array.expressions.array_expressions import ArrayContraction >>> A = MatrixSymbol("A", N, N) >>> B = MatrixSymbol("B", N, N) >>> cg = ArrayContraction(ArrayTensorProduct(A, B), (1, 2)) >>> cg._get_contraction_tuples() [[(0, 1), (1, 0)]] Notes ===== Here the contraction pair `(1, 2)` meaning that the 2nd and 3rd indices of the tensor product `A\otimes B` are contracted, has been transformed into `(0, 1)` and `(1, 0)`, identifying the same indices in a different notation. `(0, 1)` is the second index (1) of the first argument (i.e. 0 or `A`). `(1, 0)` is the first index (i.e. 0) of the second argument (i.e. 1 or `B`). """ mapping = self._mapping return [[mapping[j] for j in i] for i in self.contraction_indices] @staticmethod def _contraction_tuples_to_contraction_indices(expr, contraction_tuples): # TODO: check that `expr` has `.subranks`: ranks = expr.subranks cumulative_ranks = [0] + list(accumulate(ranks)) return [tuple(cumulative_ranks[j]+k for j, k in i) for i in contraction_tuples] @property def free_indices(self): return self._free_indices[:] @property def free_indices_to_position(self): return dict(self._free_indices_to_position) @property def expr(self): return self.args[0] @property def contraction_indices(self): return self.args[1:] def _contraction_indices_to_components(self): expr = self.expr if not isinstance(expr, ArrayTensorProduct): raise NotImplementedError("only for contractions of tensor products") ranks = expr.subranks mapping = {} counter = 0 for i, rank in enumerate(ranks): for j in range(rank): mapping[counter] = (i, j) counter += 1 return mapping def sort_args_by_name(self): """ Sort arguments in the tensor product so that their order is lexicographical. Examples ======== >>> from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array >>> from sympy import MatrixSymbol >>> from sympy.abc import N >>> A = MatrixSymbol("A", N, N) >>> B = MatrixSymbol("B", N, N) >>> C = MatrixSymbol("C", N, N) >>> D = MatrixSymbol("D", N, N) >>> cg = convert_matrix_to_array(C*D*A*B) >>> cg ArrayContraction(ArrayTensorProduct(A, D, C, B), (0, 3), (1, 6), (2, 5)) >>> cg.sort_args_by_name() ArrayContraction(ArrayTensorProduct(A, D, B, C), (0, 3), (1, 4), (2, 7)) """ expr = self.expr if not isinstance(expr, ArrayTensorProduct): return self args = expr.args sorted_data = sorted(enumerate(args), key=lambda x: default_sort_key(x[1])) pos_sorted, args_sorted = zip(*sorted_data) reordering_map = {i: pos_sorted.index(i) for i, arg in enumerate(args)} contraction_tuples = self._get_contraction_tuples() contraction_tuples = [[(reordering_map[j], k) for j, k in i] for i in contraction_tuples] c_tp = ArrayTensorProduct(*args_sorted) new_contr_indices = self._contraction_tuples_to_contraction_indices( c_tp, contraction_tuples ) return ArrayContraction(c_tp, *new_contr_indices) def _get_contraction_links(self): r""" Returns a dictionary of links between arguments in the tensor product being contracted. See the example for an explanation of the values. Examples ======== >>> from sympy import MatrixSymbol >>> from sympy.abc import N >>> from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array >>> A = MatrixSymbol("A", N, N) >>> B = MatrixSymbol("B", N, N) >>> C = MatrixSymbol("C", N, N) >>> D = MatrixSymbol("D", N, N) Matrix multiplications are pairwise contractions between neighboring matrices: `A_{ij} B_{jk} C_{kl} D_{lm}` >>> cg = convert_matrix_to_array(A*B*C*D) >>> cg ArrayContraction(ArrayTensorProduct(B, C, A, D), (0, 5), (1, 2), (3, 6)) >>> cg._get_contraction_links() {0: {0: (2, 1), 1: (1, 0)}, 1: {0: (0, 1), 1: (3, 0)}, 2: {1: (0, 0)}, 3: {0: (1, 1)}} This dictionary is interpreted as follows: argument in position 0 (i.e. matrix `A`) has its second index (i.e. 1) contracted to `(1, 0)`, that is argument in position 1 (matrix `B`) on the first index slot of `B`, this is the contraction provided by the index `j` from `A`. The argument in position 1 (that is, matrix `B`) has two contractions, the ones provided by the indices `j` and `k`, respectively the first and second indices (0 and 1 in the sub-dict). The link `(0, 1)` and `(2, 0)` respectively. `(0, 1)` is the index slot 1 (the 2nd) of argument in position 0 (that is, `A_{\ldot j}`), and so on. """ args, dlinks = _get_contraction_links([self], self.subranks, *self.contraction_indices) return dlinks def as_explicit(self): return tensorcontraction(self.expr.as_explicit(), *self.contraction_indices) class _ArgE: """ The ``_ArgE`` object contains references to the array expression (``.element``) and a list containing the information about index contractions (``.indices``). Index contractions are numbered and contracted indices show the number of the contraction. Uncontracted indices have ``None`` value. For example: ``_ArgE(M, [None, 3])`` This object means that expression ``M`` is part of an array contraction and has two indices, the first is not contracted (value ``None``), the second index is contracted to the 4th (i.e. number ``3``) group of the array contraction object. """ def __init__(self, element, indices: Optional[List[Optional[int]]] = None): self.element = element if indices is None: self.indices: List[Optional[int]] = [None for i in range(get_rank(element))] else: self.indices: List[Optional[int]] = indices def __str__(self): return "_ArgE(%s, %s)" % (self.element, self.indices) __repr__ = __str__ class _IndPos: """ Index position, requiring two integers in the constructor: - arg: the position of the argument in the tensor product, - rel: the relative position of the index inside the argument. """ def __init__(self, arg: int, rel: int): self.arg = arg self.rel = rel def __str__(self): return "_IndPos(%i, %i)" % (self.arg, self.rel) __repr__ = __str__ def __iter__(self): yield from [self.arg, self.rel] class _EditArrayContraction: """ Utility class to help manipulate array contraction objects. This class takes as input an ``ArrayContraction`` object and turns it into an editable object. The field ``args_with_ind`` of this class is a list of ``_ArgE`` objects which can be used to easily edit the contraction structure of the expression. Once editing is finished, the ``ArrayContraction`` object may be recreated by calling the ``.to_array_contraction()`` method. """ def __init__(self, array_contraction: Optional[ArrayContraction]): if array_contraction is None: self.args_with_ind: List[_ArgE] = [] self.number_of_contraction_indices: int = 0 self._track_permutation: Optional[List[int]] = None return expr = array_contraction.expr if isinstance(expr, ArrayTensorProduct): args = list(expr.args) else: args = [expr] args_with_ind: List[_ArgE] = [_ArgE(arg) for arg in args] mapping = _get_mapping_from_subranks(array_contraction.subranks) for i, contraction_tuple in enumerate(array_contraction.contraction_indices): for j in contraction_tuple: arg_pos, rel_pos = mapping[j] args_with_ind[arg_pos].indices[rel_pos] = i self.args_with_ind: List[_ArgE] = args_with_ind self.number_of_contraction_indices: int = len(array_contraction.contraction_indices) self._track_permutation: Optional[List[int]] = None def insert_after(self, arg: _ArgE, new_arg: _ArgE): pos = self.args_with_ind.index(arg) self.args_with_ind.insert(pos + 1, new_arg) def get_new_contraction_index(self): self.number_of_contraction_indices += 1 return self.number_of_contraction_indices - 1 def refresh_indices(self): updates: Dict[int, int] = {} for arg_with_ind in self.args_with_ind: updates.update({i: -1 for i in arg_with_ind.indices if i is not None}) for i, e in enumerate(sorted(updates)): updates[e] = i self.number_of_contraction_indices: int = len(updates) for arg_with_ind in self.args_with_ind: arg_with_ind.indices = [updates.get(i, None) for i in arg_with_ind.indices] def merge_scalars(self): scalars = [] for arg_with_ind in self.args_with_ind: if len(arg_with_ind.indices) == 0: scalars.append(arg_with_ind) for i in scalars: self.args_with_ind.remove(i) scalar = Mul.fromiter([i.element for i in scalars]) if len(self.args_with_ind) == 0: self.args_with_ind.append(_ArgE(scalar)) else: from sympy.tensor.array.expressions.conv_array_to_matrix import _a2m_tensor_product self.args_with_ind[0].element = _a2m_tensor_product(scalar, self.args_with_ind[0].element) def to_array_contraction(self): self.merge_scalars() self.refresh_indices() args = [arg.element for arg in self.args_with_ind] contraction_indices = self.get_contraction_indices() expr = ArrayContraction(ArrayTensorProduct(*args), *contraction_indices) if self._track_permutation is not None: permutation = _af_invert([j for i in self._track_permutation for j in i]) expr = PermuteDims(expr, permutation) return expr def get_contraction_indices(self) -> List[List[int]]: contraction_indices: List[List[int]] = [[] for i in range(self.number_of_contraction_indices)] current_position: int = 0 for i, arg_with_ind in enumerate(self.args_with_ind): for j in arg_with_ind.indices: if j is not None: contraction_indices[j].append(current_position) current_position += 1 return contraction_indices def get_mapping_for_index(self, ind) -> List[_IndPos]: if ind >= self.number_of_contraction_indices: raise ValueError("index value exceeding the index range") positions: List[_IndPos] = [] for i, arg_with_ind in enumerate(self.args_with_ind): for j, arg_ind in enumerate(arg_with_ind.indices): if ind == arg_ind: positions.append(_IndPos(i, j)) return positions def get_contraction_indices_to_ind_rel_pos(self) -> List[List[_IndPos]]: contraction_indices: List[List[_IndPos]] = [[] for i in range(self.number_of_contraction_indices)] for i, arg_with_ind in enumerate(self.args_with_ind): for j, ind in enumerate(arg_with_ind.indices): if ind is not None: contraction_indices[ind].append(_IndPos(i, j)) return contraction_indices def count_args_with_index(self, index: int) -> int: """ Count the number of arguments that have the given index. """ counter: int = 0 for arg_with_ind in self.args_with_ind: if index in arg_with_ind.indices: counter += 1 return counter def track_permutation_start(self): self._track_permutation = [] counter: int = 0 for arg_with_ind in self.args_with_ind: perm = [] for i in arg_with_ind.indices: if i is not None: continue perm.append(counter) counter += 1 self._track_permutation.append(perm) def track_permutation_merge(self, destination: _ArgE, from_element: _ArgE): index_destination = self.args_with_ind.index(destination) index_element = self.args_with_ind.index(from_element) self._track_permutation[index_destination].extend(self._track_permutation[index_element]) self._track_permutation.pop(index_element) def get_rank(expr): if isinstance(expr, (MatrixExpr, MatrixElement)): return 2 if isinstance(expr, _CodegenArrayAbstract): return len(expr.shape) if isinstance(expr, NDimArray): return expr.rank() if isinstance(expr, Indexed): return expr.rank if isinstance(expr, IndexedBase): shape = expr.shape if shape is None: return -1 else: return len(shape) if hasattr(expr, "shape"): return len(expr.shape) return 0 def _get_subrank(expr): if isinstance(expr, _CodegenArrayAbstract): return expr.subrank() return get_rank(expr) def _get_subranks(expr): if isinstance(expr, _CodegenArrayAbstract): return expr.subranks else: return [get_rank(expr)] def get_shape(expr): if hasattr(expr, "shape"): return expr.shape return () def nest_permutation(expr): if isinstance(expr, PermuteDims): return expr.nest_permutation() else: return expr sympy-sympy-1.9/sympy/tensor/array/expressions/arrayexpr_derivatives.py000066400000000000000000000125361412543434000271210ustar00rootroot00000000000000import operator from functools import reduce, singledispatch from sympy import Expr, Transpose, Identity, MatrixSymbol, S, Inverse, MatrixExpr, HadamardProduct from sympy.combinatorics.permutations import _af_invert from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction from sympy.tensor.array.expressions.array_expressions import ZeroArray, ArraySymbol, ArrayTensorProduct, \ ArrayAdd, PermuteDims, ArrayDiagonal, ArrayElementwiseApplyFunc, get_rank, \ get_shape, ArrayContraction from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array @singledispatch def array_derive(expr, x): raise NotImplementedError(f"not implemented for type {type(expr)}") @array_derive.register(Expr) def _(expr: Expr, x: Expr): return ZeroArray(*x.shape) @array_derive.register(ArrayTensorProduct) def _(expr: ArrayTensorProduct, x: Expr): args = expr.args addend_list = [] for i, arg in enumerate(expr.args): darg = array_derive(arg, x) if darg == 0: continue args_prev = args[:i] args_succ = args[i+1:] shape_prev = reduce(operator.add, map(get_shape, args_prev), ()) shape_succ = reduce(operator.add, map(get_shape, args_succ), ()) addend = ArrayTensorProduct(*args_prev, darg, *args_succ) tot1 = len(get_shape(x)) tot2 = tot1 + len(shape_prev) tot3 = tot2 + len(get_shape(arg)) tot4 = tot3 + len(shape_succ) perm = [i for i in range(tot1, tot2)] + \ [i for i in range(tot1)] + [i for i in range(tot2, tot3)] + \ [i for i in range(tot3, tot4)] addend = PermuteDims(addend, _af_invert(perm)) addend_list.append(addend) if len(addend_list) == 1: return addend_list[0] elif len(addend_list) == 0: return S.Zero else: return ArrayAdd(*addend_list) @array_derive.register(ArraySymbol) def _(expr: ArraySymbol, x: Expr): if expr == x: return PermuteDims( ArrayTensorProduct.fromiter(Identity(i) for i in expr.shape), [2*i for i in range(len(expr.shape))] + [2*i+1 for i in range(len(expr.shape))] ) return ZeroArray(*(x.shape + expr.shape)) @array_derive.register(MatrixSymbol) def _(expr: MatrixSymbol, x: Expr): m, n = expr.shape if expr == x: return PermuteDims( ArrayTensorProduct(Identity(m), Identity(n)), [0, 2, 1, 3] ) return ZeroArray(*(x.shape + expr.shape)) @array_derive.register(Identity) def _(expr: Identity, x: Expr): return ZeroArray(*(x.shape + expr.shape)) @array_derive.register(Transpose) def _(expr: Transpose, x: Expr): # D(A.T, A) ==> (m,n,i,j) ==> D(A_ji, A_mn) = d_mj d_ni # D(B.T, A) ==> (m,n,i,j) ==> D(B_ji, A_mn) fd = array_derive(expr.arg, x) return PermuteDims(fd, [0, 1, 3, 2]) @array_derive.register(Inverse) def _(expr: Inverse, x: Expr): mat = expr.I dexpr = array_derive(mat, x) tp = ArrayTensorProduct(-expr, dexpr, expr) mp = ArrayContraction(tp, (1, 4), (5, 6)) pp = PermuteDims(mp, [1, 2, 0, 3]) return pp @array_derive.register(ElementwiseApplyFunction) def _(expr: ElementwiseApplyFunction, x: Expr): assert get_rank(expr) == 2 assert get_rank(x) == 2 fdiff = expr._get_function_fdiff() dexpr = array_derive(expr.expr, x) tp = ArrayTensorProduct( ElementwiseApplyFunction(fdiff, expr.expr), dexpr ) td = ArrayDiagonal( tp, (0, 4), (1, 5) ) return td @array_derive.register(ArrayElementwiseApplyFunc) def _(expr: ArrayElementwiseApplyFunc, x: Expr): fdiff = expr._get_function_fdiff() subexpr = expr.expr dsubexpr = array_derive(subexpr, x) tp = ArrayTensorProduct( dsubexpr, ArrayElementwiseApplyFunc(fdiff, subexpr) ) b = get_rank(x) c = get_rank(expr) diag_indices = [(b + i, b + c + i) for i in range(c)] return ArrayDiagonal(tp, *diag_indices) @array_derive.register(MatrixExpr) def _(expr: MatrixExpr, x: Expr): cg = convert_matrix_to_array(expr) return array_derive(cg, x) @array_derive.register(HadamardProduct) def _(expr: HadamardProduct, x: Expr): raise NotImplementedError() @array_derive.register(ArrayContraction) def _(expr: ArrayContraction, x: Expr): fd = array_derive(expr.expr, x) rank_x = len(get_shape(x)) contraction_indices = expr.contraction_indices new_contraction_indices = [tuple(j + rank_x for j in i) for i in contraction_indices] return ArrayContraction(fd, *new_contraction_indices) @array_derive.register(ArrayDiagonal) def _(expr: ArrayDiagonal, x: Expr): dsubexpr = array_derive(expr.expr, x) rank_x = len(get_shape(x)) diag_indices = [[j + rank_x for j in i] for i in expr.diagonal_indices] return ArrayDiagonal(dsubexpr, *diag_indices) @array_derive.register(ArrayAdd) def _(expr: ArrayAdd, x: Expr): return ArrayAdd(*[array_derive(arg, x) for arg in expr.args]) @array_derive.register(PermuteDims) def _(expr: PermuteDims, x: Expr): de = array_derive(expr.expr, x) perm = [0, 1] + [i + 2 for i in expr.permutation.array_form] return PermuteDims(de, perm) def matrix_derive(expr, x): from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix ce = convert_matrix_to_array(expr) dce = array_derive(ce, x) return convert_array_to_matrix(dce).doit() sympy-sympy-1.9/sympy/tensor/array/expressions/conv_array_to_matrix.py000066400000000000000000000703261412543434000267310ustar00rootroot00000000000000import itertools from collections import defaultdict, Counter from typing import Tuple, Union, FrozenSet, Dict, List, Optional from functools import singledispatch from itertools import accumulate from sympy import Trace, MatrixExpr, Transpose, DiagMatrix, Mul, ZeroMatrix, hadamard_product, S from sympy.combinatorics.permutations import _af_invert, Permutation from sympy.matrices.common import MatrixCommon from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction from sympy.tensor.array.expressions.array_expressions import PermuteDims, ArrayDiagonal, \ ArrayTensorProduct, OneArray, get_rank, _get_subrank, ZeroArray, ArrayContraction, \ ArrayAdd, _CodegenArrayAbstract, get_shape, ArrayElementwiseApplyFunc, _ArrayExpr, _EditArrayContraction, _ArgE from sympy.tensor.array.expressions.utils import _get_mapping_from_subranks def _get_candidate_for_matmul_from_contraction(scan_indices: List[Optional[int]], remaining_args: List[_ArgE]) -> Tuple[Optional[_ArgE], bool, int]: scan_indices = [i for i in scan_indices if i is not None] if len(scan_indices) == 0: return None, False, -1 transpose: bool = False candidate: Optional[_ArgE] = None candidate_index: int = -1 for arg_with_ind2 in remaining_args: if not isinstance(arg_with_ind2.element, MatrixExpr): continue for index in scan_indices: if candidate_index != -1 and candidate_index != index: # A candidate index has already been selected, check # repetitions only for that index: continue if index in arg_with_ind2.indices: if set(arg_with_ind2.indices) == {index}: # Index repeated twice in arg_with_ind2 candidate = None break if candidate is None: candidate = arg_with_ind2 candidate_index = index transpose = (index == arg_with_ind2.indices[1]) else: # Index repeated more than twice, break candidate = None break return candidate, transpose, candidate_index def _insert_candidate_into_editor(editor: _EditArrayContraction, arg_with_ind: _ArgE, candidate: _ArgE, transpose1: bool, transpose2: bool): other = candidate.element other_index: int if transpose2: other = Transpose(other) other_index = candidate.indices[0] else: other_index = candidate.indices[1] new_element = (Transpose(arg_with_ind.element) if transpose1 else arg_with_ind.element) * other editor.args_with_ind.remove(candidate) new_arge = _ArgE(new_element) return new_arge, other_index def _support_function_tp1_recognize(contraction_indices, args): if len(contraction_indices) == 0: return _a2m_tensor_product(*args) ac = ArrayContraction(ArrayTensorProduct(*args), *contraction_indices) editor = _EditArrayContraction(ac) editor.track_permutation_start() while True: flag_stop: bool = True for i, arg_with_ind in enumerate(editor.args_with_ind): if not isinstance(arg_with_ind.element, MatrixExpr): continue first_index = arg_with_ind.indices[0] second_index = arg_with_ind.indices[1] first_frequency = editor.count_args_with_index(first_index) second_frequency = editor.count_args_with_index(second_index) if first_index is not None and first_frequency == 1 and first_index == second_index: flag_stop = False arg_with_ind.element = Trace(arg_with_ind.element)._normalize() arg_with_ind.indices = [] break scan_indices = [] if first_frequency == 2: scan_indices.append(first_index) if second_frequency == 2: scan_indices.append(second_index) candidate, transpose, found_index = _get_candidate_for_matmul_from_contraction(scan_indices, editor.args_with_ind[i+1:]) if candidate is not None: flag_stop = False editor.track_permutation_merge(arg_with_ind, candidate) transpose1 = found_index == first_index new_arge, other_index = _insert_candidate_into_editor(editor, arg_with_ind, candidate, transpose1, transpose) if found_index == first_index: new_arge.indices = [second_index, other_index] else: new_arge.indices = [first_index, other_index] set_indices = set(new_arge.indices) if len(set_indices) == 1 and set_indices != {None}: # This is a trace: new_arge.element = Trace(new_arge.element)._normalize() new_arge.indices = [] editor.args_with_ind[i] = new_arge # TODO: is this break necessary? break if flag_stop: break editor.refresh_indices() return editor.to_array_contraction() @singledispatch def _array2matrix(expr): return expr @_array2matrix.register(ZeroArray) def _(expr: ZeroArray): if get_rank(expr) == 2: return ZeroMatrix(*expr.shape) else: return expr @_array2matrix.register(ArrayTensorProduct) def _(expr: ArrayTensorProduct): return _a2m_tensor_product(*[_array2matrix(arg) for arg in expr.args]) @_array2matrix.register(ArrayContraction) def _(expr: ArrayContraction): expr = expr.flatten_contraction_of_diagonal() expr = expr.split_multiple_contractions() expr = identify_hadamard_products(expr) if not isinstance(expr, ArrayContraction): return _array2matrix(expr) subexpr = expr.expr contraction_indices: Tuple[Tuple[int]] = expr.contraction_indices if isinstance(subexpr, ArrayTensorProduct): newexpr = ArrayContraction(_array2matrix(subexpr), *contraction_indices) contraction_indices = newexpr.contraction_indices if any(i > 2 for i in newexpr.subranks): addends = ArrayAdd(*[_a2m_tensor_product(*j) for j in itertools.product(*[i.args if isinstance(i, ArrayAdd) else [i] for i in expr.expr.args])]) newexpr = ArrayContraction(addends, *contraction_indices) if isinstance(newexpr, ArrayAdd): ret = _array2matrix(newexpr) return ret assert isinstance(newexpr, ArrayContraction) ret = _support_function_tp1_recognize(contraction_indices, list(newexpr.expr.args)) return ret elif not isinstance(subexpr, _CodegenArrayAbstract): ret = _array2matrix(subexpr) if isinstance(ret, MatrixExpr): assert expr.contraction_indices == ((0, 1),) return _a2m_trace(ret) else: return ArrayContraction(ret, *expr.contraction_indices) @_array2matrix.register(ArrayDiagonal) def _(expr: ArrayDiagonal): pexpr = ArrayDiagonal(_array2matrix(expr.expr), *expr.diagonal_indices) pexpr = identify_hadamard_products(pexpr) if isinstance(pexpr, ArrayDiagonal): pexpr = _array_diag2contr_diagmatrix(pexpr) if expr == pexpr: return expr return _array2matrix(pexpr) @_array2matrix.register(PermuteDims) def _(expr: PermuteDims): if expr.permutation.array_form == [1, 0]: return _a2m_transpose(_array2matrix(expr.expr)) elif isinstance(expr.expr, ArrayTensorProduct): ranks = expr.expr.subranks inv_permutation = expr.permutation**(-1) newrange = [inv_permutation(i) for i in range(sum(ranks))] newpos = [] counter = 0 for rank in ranks: newpos.append(newrange[counter:counter+rank]) counter += rank newargs = [] newperm = [] scalars = [] for pos, arg in zip(newpos, expr.expr.args): if len(pos) == 0: scalars.append(_array2matrix(arg)) elif pos == sorted(pos): newargs.append((_array2matrix(arg), pos[0])) newperm.extend(pos) elif len(pos) == 2: newargs.append((_a2m_transpose(_array2matrix(arg)), pos[0])) newperm.extend(reversed(pos)) else: raise NotImplementedError() newargs = [i[0] for i in newargs] return PermuteDims(_a2m_tensor_product(*scalars, *newargs), _af_invert(newperm)) elif isinstance(expr.expr, ArrayContraction): mat_mul_lines = _array2matrix(expr.expr) if not isinstance(mat_mul_lines, ArrayTensorProduct): flat_cyclic_form = [j for i in expr.permutation.cyclic_form for j in i] expr_shape = get_shape(expr) if all(expr_shape[i] == 1 for i in flat_cyclic_form): return mat_mul_lines return mat_mul_lines # TODO: this assumes that all arguments are matrices, it may not be the case: permutation = Permutation(2*len(mat_mul_lines.args)-1)*expr.permutation permuted = [permutation(i) for i in range(2*len(mat_mul_lines.args))] args_array = [None for i in mat_mul_lines.args] for i in range(len(mat_mul_lines.args)): p1 = permuted[2*i] p2 = permuted[2*i+1] if p1 // 2 != p2 // 2: return PermuteDims(mat_mul_lines, permutation) pos = p1 // 2 if p1 > p2: args_array[i] = _a2m_transpose(mat_mul_lines.args[pos]) else: args_array[i] = mat_mul_lines.args[pos] return _a2m_tensor_product(*args_array) else: return expr @_array2matrix.register(ArrayAdd) def _(expr: ArrayAdd): addends = [_array2matrix(arg) for arg in expr.args] return _a2m_add(*addends) @_array2matrix.register(ArrayElementwiseApplyFunc) def _(expr: ArrayElementwiseApplyFunc): subexpr = _array2matrix(expr.expr) if isinstance(subexpr, MatrixExpr): return ElementwiseApplyFunction(expr.function, subexpr) else: return ArrayElementwiseApplyFunc(expr.function, subexpr) @singledispatch def _remove_trivial_dims(expr): return expr, [] @_remove_trivial_dims.register(ArrayTensorProduct) def _(expr: ArrayTensorProduct): # Recognize expressions like [x, y] with shape (k, 1, k, 1) as `x*y.T`. # The matrix expression has to be equivalent to the tensor product of the # matrices, with trivial dimensions (i.e. dim=1) dropped. # That is, add contractions over trivial dimensions: removed = [] newargs = [] cumul = list(accumulate([0] + [get_rank(arg) for arg in expr.args])) pending = None prev_i = None for i, arg in enumerate(expr.args): current_range = list(range(cumul[i], cumul[i+1])) if isinstance(arg, OneArray): removed.extend(current_range) continue if not isinstance(arg, (MatrixExpr, MatrixCommon)): rarg, rem = _remove_trivial_dims(arg) removed.extend(rem) newargs.append(rarg) continue elif getattr(arg, "is_Identity", False): if arg.shape == (1, 1): # Ignore identity matrices of shape (1, 1) - they are equivalent to scalar 1. removed.extend(current_range) continue k = arg.shape[0] if pending == k: # OK, there is already removed.extend(current_range) continue elif pending is None: newargs.append(arg) pending = k prev_i = i else: pending = k prev_i = i newargs.append(arg) elif arg.shape == (1, 1): arg, _ = _remove_trivial_dims(arg) # Matrix is equivalent to scalar: if len(newargs) == 0: newargs.append(arg) elif 1 in get_shape(newargs[-1]): if newargs[-1].shape[1] == 1: newargs[-1] = newargs[-1]*arg else: newargs[-1] = arg*newargs[-1] removed.extend(current_range) else: newargs.append(arg) elif 1 in arg.shape: k = [i for i in arg.shape if i != 1][0] if pending is None: pending = k prev_i = i newargs.append(arg) elif pending == k: prev = newargs[-1] if prev.is_Identity: removed.extend([cumul[prev_i], cumul[prev_i]+1]) newargs[-1] = arg prev_i = i continue if prev.shape[0] == 1: d1 = cumul[prev_i] prev = _a2m_transpose(prev) else: d1 = cumul[prev_i] + 1 if arg.shape[1] == 1: d2 = cumul[i] + 1 arg = _a2m_transpose(arg) else: d2 = cumul[i] newargs[-1] = prev*arg pending = None removed.extend([d1, d2]) else: newargs.append(arg) pending = k prev_i = i else: newargs.append(arg) pending = None return _a2m_tensor_product(*newargs), sorted(removed) @_remove_trivial_dims.register(ArrayAdd) def _(expr: ArrayAdd): rec = [_remove_trivial_dims(arg) for arg in expr.args] newargs, removed = zip(*rec) if len(set(map(tuple, removed))) != 1: return expr, [] return _a2m_add(*newargs), removed[0] @_remove_trivial_dims.register(PermuteDims) def _(expr: PermuteDims): subexpr, subremoved = _remove_trivial_dims(expr.expr) p = expr.permutation.array_form pinv = _af_invert(expr.permutation.array_form) shift = list(accumulate([1 if i in subremoved else 0 for i in range(len(p))])) premoved = [pinv[i] for i in subremoved] p2 = [e - shift[e] for i, e in enumerate(p) if e not in subremoved] # TODO: check if subremoved should be permuted as well... newexpr = PermuteDims(subexpr, p2) if newexpr != expr: newexpr = _array2matrix(newexpr) return newexpr, sorted(premoved) @_remove_trivial_dims.register(ArrayContraction) def _(expr: ArrayContraction): newexpr, removed = _remove_trivial_dims(expr.expr) shifts = list(accumulate([1 if i in removed else 0 for i in range(get_rank(expr.expr))])) new_contraction_indices = [tuple(j for j in i if j not in removed) for i in expr.contraction_indices] # Remove possible empty tuples "()": new_contraction_indices = [i for i in new_contraction_indices if len(i) > 0] contraction_indices_flat = [j for i in expr.contraction_indices for j in i] removed = [i for i in removed if i not in contraction_indices_flat] new_contraction_indices = [tuple(j - shifts[j] for j in i) for i in new_contraction_indices] # Shift removed: removed = ArrayContraction._push_indices_up(expr.contraction_indices, removed) return ArrayContraction(newexpr, *new_contraction_indices), list(removed) @_remove_trivial_dims.register(ArrayDiagonal) def _(expr: ArrayDiagonal): newexpr, removed = _remove_trivial_dims(expr.expr) shifts = list(accumulate([0] + [1 if i in removed else 0 for i in range(get_rank(expr.expr))])) new_diag_indices = [tuple(j for j in i if j not in removed) for i in expr.diagonal_indices] new_diag_indices = [tuple(j - shifts[j] for j in i) for i in new_diag_indices] rank = get_rank(expr.expr) removed = ArrayDiagonal._push_indices_up(expr.diagonal_indices, removed, rank) removed = sorted({i for i in removed}) # If there are single axes to diagonalize remaining, it means that their # corresponding dimension has been removed, they no longer need diagonalization: new_diag_indices = [i for i in new_diag_indices if len(i) > 1] return ArrayDiagonal(newexpr, *new_diag_indices), removed @_remove_trivial_dims.register(ElementwiseApplyFunction) def _(expr: ElementwiseApplyFunction): subexpr, removed = _remove_trivial_dims(expr.expr) if subexpr.shape == (1, 1): # TODO: move this to ElementwiseApplyFunction return expr.function(subexpr), removed + [0, 1] return ElementwiseApplyFunction(expr.function, subexpr) @_remove_trivial_dims.register(ArrayElementwiseApplyFunc) def _(expr: ArrayElementwiseApplyFunc): subexpr, removed = _remove_trivial_dims(expr.expr) return ArrayElementwiseApplyFunc(expr.function, subexpr), removed def convert_array_to_matrix(expr): r""" Recognize matrix expressions in codegen objects. If more than one matrix multiplication line have been detected, return a list with the matrix expressions. Examples ======== >>> from sympy.tensor.array.expressions.conv_indexed_to_array import convert_indexed_to_array >>> from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct >>> from sympy import MatrixSymbol, Sum >>> from sympy.abc import i, j, k, l, N >>> from sympy.tensor.array.expressions.array_expressions import ArrayContraction >>> from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array >>> from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix >>> A = MatrixSymbol("A", N, N) >>> B = MatrixSymbol("B", N, N) >>> C = MatrixSymbol("C", N, N) >>> D = MatrixSymbol("D", N, N) >>> expr = Sum(A[i, j]*B[j, k], (j, 0, N-1)) >>> cg = convert_indexed_to_array(expr) >>> convert_array_to_matrix(cg) A*B >>> cg = convert_indexed_to_array(expr, first_indices=[k]) >>> convert_array_to_matrix(cg) B.T*A.T Transposition is detected: >>> expr = Sum(A[j, i]*B[j, k], (j, 0, N-1)) >>> cg = convert_indexed_to_array(expr) >>> convert_array_to_matrix(cg) A.T*B >>> cg = convert_indexed_to_array(expr, first_indices=[k]) >>> convert_array_to_matrix(cg) B.T*A Detect the trace: >>> expr = Sum(A[i, i], (i, 0, N-1)) >>> cg = convert_indexed_to_array(expr) >>> convert_array_to_matrix(cg) Trace(A) Recognize some more complex traces: >>> expr = Sum(A[i, j]*B[j, i], (i, 0, N-1), (j, 0, N-1)) >>> cg = convert_indexed_to_array(expr) >>> convert_array_to_matrix(cg) Trace(A*B) More complicated expressions: >>> expr = Sum(A[i, j]*B[k, j]*A[l, k], (j, 0, N-1), (k, 0, N-1)) >>> cg = convert_indexed_to_array(expr) >>> convert_array_to_matrix(cg) A*B.T*A.T Expressions constructed from matrix expressions do not contain literal indices, the positions of free indices are returned instead: >>> expr = A*B >>> cg = convert_matrix_to_array(expr) >>> convert_array_to_matrix(cg) A*B If more than one line of matrix multiplications is detected, return separate matrix multiplication factors embedded in a tensor product object: >>> cg = ArrayContraction(ArrayTensorProduct(A, B, C, D), (1, 2), (5, 6)) >>> convert_array_to_matrix(cg) ArrayTensorProduct(A*B, C*D) The two lines have free indices at axes 0, 3 and 4, 7, respectively. """ rec = _array2matrix(expr) rec, removed = _remove_trivial_dims(rec) return rec def _array_diag2contr_diagmatrix(expr: ArrayDiagonal): if isinstance(expr.expr, ArrayTensorProduct): args = list(expr.expr.args) diag_indices = list(expr.diagonal_indices) mapping = _get_mapping_from_subranks([_get_subrank(arg) for arg in args]) tuple_links = [[mapping[j] for j in i] for i in diag_indices] contr_indices = [] total_rank = get_rank(expr) replaced = [False for arg in args] for i, (abs_pos, rel_pos) in enumerate(zip(diag_indices, tuple_links)): if len(abs_pos) != 2: continue (pos1_outer, pos1_inner), (pos2_outer, pos2_inner) = rel_pos arg1 = args[pos1_outer] arg2 = args[pos2_outer] if get_rank(arg1) != 2 or get_rank(arg2) != 2: if replaced[pos1_outer]: diag_indices[i] = None if replaced[pos2_outer]: diag_indices[i] = None continue pos1_in2 = 1 - pos1_inner pos2_in2 = 1 - pos2_inner if arg1.shape[pos1_in2] == 1: darg1 = DiagMatrix(arg1) args.append(darg1) contr_indices.append(((pos2_outer, pos2_inner), (len(args)-1, pos1_inner))) total_rank += 1 diag_indices[i] = None args[pos1_outer] = OneArray(arg1.shape[pos1_in2]) replaced[pos1_outer] = True elif arg2.shape[pos2_in2] == 1: darg2 = DiagMatrix(arg2) args.append(darg2) contr_indices.append(((pos1_outer, pos1_inner), (len(args)-1, pos2_inner))) total_rank += 1 diag_indices[i] = None args[pos2_outer] = OneArray(arg2.shape[pos2_in2]) replaced[pos2_outer] = True diag_indices_new = [i for i in diag_indices if i is not None] cumul = list(accumulate([0] + [get_rank(arg) for arg in args])) contr_indices2 = [tuple(cumul[a] + b for a, b in i) for i in contr_indices] tc = ArrayContraction( ArrayTensorProduct(*args), *contr_indices2 ) td = ArrayDiagonal(tc, *diag_indices_new) return td return expr def _a2m_mul(*args): if all(not isinstance(i, _CodegenArrayAbstract) for i in args): from sympy import MatMul return MatMul(*args).doit() else: return ArrayContraction( ArrayTensorProduct(*args), *[(2*i-1, 2*i) for i in range(1, len(args))] ) def _a2m_tensor_product(*args): scalars = [] arrays = [] for arg in args: if isinstance(arg, (MatrixExpr, _ArrayExpr, _CodegenArrayAbstract)): arrays.append(arg) else: scalars.append(arg) scalar = Mul.fromiter(scalars) if len(arrays) == 0: return scalar if scalar != 1: if isinstance(arrays[0], _CodegenArrayAbstract): arrays = [scalar] + arrays else: arrays[0] *= scalar return ArrayTensorProduct(*arrays) def _a2m_add(*args): if all(not isinstance(i, _CodegenArrayAbstract) for i in args): from sympy import MatAdd return MatAdd(*args).doit() else: return ArrayAdd(*args) def _a2m_trace(arg): if isinstance(arg, _CodegenArrayAbstract): return ArrayContraction(arg, (0, 1)) else: from sympy import Trace return Trace(arg) def _a2m_transpose(arg): if isinstance(arg, _CodegenArrayAbstract): return PermuteDims(arg, [1, 0]) else: from sympy import Transpose return Transpose(arg).doit() def identify_hadamard_products(expr: Union[ArrayContraction, ArrayDiagonal]): mapping = _get_mapping_from_subranks(expr.subranks) editor: _EditArrayContraction if isinstance(expr, ArrayContraction): editor = _EditArrayContraction(expr) elif isinstance(expr, ArrayDiagonal): if isinstance(expr.expr, ArrayContraction): editor = _EditArrayContraction(expr.expr) diagonalized = ArrayContraction._push_indices_down(expr.expr.contraction_indices, expr.diagonal_indices) elif isinstance(expr.expr, ArrayTensorProduct): editor = _EditArrayContraction(None) editor.args_with_ind = [_ArgE(arg) for i, arg in enumerate(expr.expr.args)] diagonalized = expr.diagonal_indices else: return expr # Trick: add diagonalized indices as negative indices into the editor object: for i, e in enumerate(diagonalized): for j in e: arg_pos, rel_pos = mapping[j] editor.args_with_ind[arg_pos].indices[rel_pos] = -1 - i map_contr_to_args: Dict[FrozenSet, List[_ArgE]] = defaultdict(list) map_ind_to_inds = defaultdict(int) for arg_with_ind in editor.args_with_ind: for ind in arg_with_ind.indices: map_ind_to_inds[ind] += 1 if None in arg_with_ind.indices: continue map_contr_to_args[frozenset(arg_with_ind.indices)].append(arg_with_ind) k: FrozenSet[int] v: List[_ArgE] for k, v in map_contr_to_args.items(): make_trace: bool = False if len(k) == 1 and next(iter(k)) >= 0 and sum([next(iter(k)) in i for i in map_contr_to_args]) == 1: # This is a trace: the arguments are fully contracted with only one # index, and the index isn't used anywhere else: make_trace = True first_element = S.One elif len(k) != 2: # Hadamard product only defined for matrices: continue if len(v) == 1: # Hadamard product with a single argument makes no sense: continue for ind in k: if map_ind_to_inds[ind] <= 2: # There is no other contraction, skip: continue def check_transpose(x): x = [i if i >= 0 else -1-i for i in x] return x == sorted(x) # Check if expression is a trace: if all([map_ind_to_inds[j] == len(v) and j >= 0 for j in k]) and all([j >= 0 for j in k]): # This is a trace make_trace = True first_element = v[0].element if not check_transpose(v[0].indices): first_element = first_element.T hadamard_factors = v[1:] else: hadamard_factors = v # This is a Hadamard product: hp = hadamard_product(*[i.element if check_transpose(i.indices) else Transpose(i.element) for i in hadamard_factors]) hp_indices = v[0].indices if not check_transpose(hadamard_factors[0].indices): hp_indices = list(reversed(hp_indices)) if make_trace: hp = Trace(first_element*hp.T)._normalize() hp_indices = [] editor.insert_after(v[0], _ArgE(hp, hp_indices)) for i in v: editor.args_with_ind.remove(i) # Count the ranks of the arguments: counter = 0 # Create a collector for the new diagonal indices: diag_indices = defaultdict(list) count_index_freq = Counter() for arg_with_ind in editor.args_with_ind: count_index_freq.update(Counter(arg_with_ind.indices)) free_index_count = count_index_freq[None] # Construct the inverse permutation: inv_perm1 = [] inv_perm2 = [] # Keep track of which diagonal indices have already been processed: done = set([]) # Counter for the diagonal indices: counter4 = 0 for arg_with_ind in editor.args_with_ind: # If some diagonalization axes have been removed, they should be # permuted in order to keep the permutation. # Add permutation here counter2 = 0 # counter for the indices for i in arg_with_ind.indices: if i is None: inv_perm1.append(counter4) counter2 += 1 counter4 += 1 continue if i >= 0: continue # Reconstruct the diagonal indices: diag_indices[-1 - i].append(counter + counter2) if count_index_freq[i] == 1 and i not in done: inv_perm1.append(free_index_count - 1 - i) done.add(i) elif i not in done: inv_perm2.append(free_index_count - 1 - i) done.add(i) counter2 += 1 # Remove negative indices to restore a proper editor object: arg_with_ind.indices = [i if i is not None and i >= 0 else None for i in arg_with_ind.indices] counter += len([i for i in arg_with_ind.indices if i is None or i < 0]) inverse_permutation = inv_perm1 + inv_perm2 permutation = _af_invert(inverse_permutation) if isinstance(expr, ArrayContraction): return editor.to_array_contraction() else: # Get the diagonal indices after the detection of HadamardProduct in the expression: diag_indices_filtered = [tuple(v) for v in diag_indices.values() if len(v) > 1] expr1 = editor.to_array_contraction() expr2 = ArrayDiagonal(expr1, *diag_indices_filtered) expr3 = PermuteDims(expr2, permutation) return expr3 sympy-sympy-1.9/sympy/tensor/array/expressions/conv_indexed_to_array.py000066400000000000000000000160211412543434000270350ustar00rootroot00000000000000from collections import defaultdict from sympy import Sum, Mul, KroneckerDelta, Indexed, IndexedBase, Add from sympy.combinatorics import Permutation from sympy.matrices.expressions.matexpr import MatrixElement from sympy.tensor.array.expressions.array_expressions import PermuteDims, ArrayDiagonal, \ ArrayContraction, ArrayTensorProduct, ArrayAdd from sympy.tensor.array.expressions.utils import _get_argindex, _get_diagonal_indices def convert_indexed_to_array(expr, first_indices=None): r""" Parse indexed expression into a form useful for code generation. Examples ======== >>> from sympy.tensor.array.expressions.conv_indexed_to_array import convert_indexed_to_array >>> from sympy import MatrixSymbol, Sum, symbols >>> i, j, k, d = symbols("i j k d") >>> M = MatrixSymbol("M", d, d) >>> N = MatrixSymbol("N", d, d) Recognize the trace in summation form: >>> expr = Sum(M[i, i], (i, 0, d-1)) >>> convert_indexed_to_array(expr) ArrayContraction(M, (0, 1)) Recognize the extraction of the diagonal by using the same index `i` on both axes of the matrix: >>> expr = M[i, i] >>> convert_indexed_to_array(expr) ArrayDiagonal(M, (0, 1)) This function can help perform the transformation expressed in two different mathematical notations as: `\sum_{j=0}^{N-1} A_{i,j} B_{j,k} \Longrightarrow \mathbf{A}\cdot \mathbf{B}` Recognize the matrix multiplication in summation form: >>> expr = Sum(M[i, j]*N[j, k], (j, 0, d-1)) >>> convert_indexed_to_array(expr) ArrayContraction(ArrayTensorProduct(M, N), (1, 2)) Specify that ``k`` has to be the starting index: >>> convert_indexed_to_array(expr, first_indices=[k]) ArrayContraction(ArrayTensorProduct(N, M), (0, 3)) """ result, indices = _convert_indexed_to_array(expr) if not first_indices: return result for i in first_indices: if i not in indices: first_indices.remove(i) first_indices.extend([i for i in indices if i not in first_indices]) permutation = [first_indices.index(i) for i in indices] return PermuteDims(result, permutation) def _convert_indexed_to_array(expr): if isinstance(expr, Sum): function = expr.function summation_indices = expr.variables subexpr, subindices = _convert_indexed_to_array(function) # Check dimensional consistency: shape = subexpr.shape if shape: for ind, istart, iend in expr.limits: i = _get_argindex(subindices, ind) if istart != 0 or iend+1 != shape[i]: raise ValueError("summation index and array dimension mismatch: %s" % ind) contraction_indices = [] subindices = list(subindices) if isinstance(subexpr, ArrayDiagonal): diagonal_indices = list(subexpr.diagonal_indices) dindices = subindices[-len(diagonal_indices):] subindices = subindices[:-len(diagonal_indices)] for index in summation_indices: if index in dindices: position = dindices.index(index) contraction_indices.append(diagonal_indices[position]) diagonal_indices[position] = None diagonal_indices = [i for i in diagonal_indices if i is not None] for i, ind in enumerate(subindices): if ind in summation_indices: pass if diagonal_indices: subexpr = ArrayDiagonal(subexpr.expr, *diagonal_indices) else: subexpr = subexpr.expr axes_contraction = defaultdict(list) for i, ind in enumerate(subindices): if ind in summation_indices: axes_contraction[ind].append(i) subindices[i] = None for k, v in axes_contraction.items(): contraction_indices.append(tuple(v)) free_indices = [i for i in subindices if i is not None] indices_ret = list(free_indices) indices_ret.sort(key=lambda x: free_indices.index(x)) return ArrayContraction( subexpr, *contraction_indices, free_indices=free_indices ), tuple(indices_ret) if isinstance(expr, Mul): args, indices = zip(*[_convert_indexed_to_array(arg) for arg in expr.args]) # Check if there are KroneckerDelta objects: kronecker_delta_repl = {} for arg in args: if not isinstance(arg, KroneckerDelta): continue # Diagonalize two indices: i, j = arg.indices kindices = set(arg.indices) if i in kronecker_delta_repl: kindices.update(kronecker_delta_repl[i]) if j in kronecker_delta_repl: kindices.update(kronecker_delta_repl[j]) kindices = frozenset(kindices) for index in kindices: kronecker_delta_repl[index] = kindices # Remove KroneckerDelta objects, their relations should be handled by # ArrayDiagonal: newargs = [] newindices = [] for arg, loc_indices in zip(args, indices): if isinstance(arg, KroneckerDelta): continue newargs.append(arg) newindices.append(loc_indices) flattened_indices = [kronecker_delta_repl.get(j, j) for i in newindices for j in i] diagonal_indices, ret_indices = _get_diagonal_indices(flattened_indices) tp = ArrayTensorProduct(*newargs) if diagonal_indices: return (ArrayDiagonal(tp, *diagonal_indices), ret_indices) else: return tp, ret_indices if isinstance(expr, MatrixElement): indices = expr.args[1:] diagonal_indices, ret_indices = _get_diagonal_indices(indices) if diagonal_indices: return (ArrayDiagonal(expr.args[0], *diagonal_indices), ret_indices) else: return expr.args[0], ret_indices if isinstance(expr, Indexed): indices = expr.indices diagonal_indices, ret_indices = _get_diagonal_indices(indices) if diagonal_indices: return (ArrayDiagonal(expr.base, *diagonal_indices), ret_indices) else: return expr.args[0], ret_indices if isinstance(expr, IndexedBase): raise NotImplementedError if isinstance(expr, KroneckerDelta): return expr, expr.indices if isinstance(expr, Add): args, indices = zip(*[_convert_indexed_to_array(arg) for arg in expr.args]) args = list(args) # Check if all indices are compatible. Otherwise expand the dimensions: index0set = set(indices[0]) index0 = indices[0] for i in range(1, len(args)): if set(indices[i]) != index0set: raise NotImplementedError("indices must be the same") permutation = Permutation([index0.index(j) for j in indices[i]]) # Perform index permutations: args[i] = PermuteDims(args[i], permutation) return ArrayAdd(*args), index0 return expr, () sympy-sympy-1.9/sympy/tensor/array/expressions/conv_matrix_to_array.py000066400000000000000000000057741412543434000267360ustar00rootroot00000000000000from sympy import Mul, Basic, MatMul, MatAdd, Transpose, Trace, Pow, \ MatPow, symbols, Dummy, Lambda, HadamardProduct, HadamardPower, S from sympy.matrices.expressions.matexpr import MatrixExpr from sympy.tensor.array.expressions.array_expressions import ArrayDiagonal, ArrayTensorProduct, \ PermuteDims, ArrayAdd, ArrayContraction, ArrayElementwiseApplyFunc def convert_matrix_to_array(expr: MatrixExpr) -> Basic: if isinstance(expr, MatMul): args_nonmat = [] args = [] for arg in expr.args: if isinstance(arg, MatrixExpr): args.append(arg) else: args_nonmat.append(convert_matrix_to_array(arg)) contractions = [(2*i+1, 2*i+2) for i in range(len(args)-1)] scalar = ArrayTensorProduct.fromiter(args_nonmat) if args_nonmat else S.One if scalar == 1: tprod = ArrayTensorProduct( *[convert_matrix_to_array(arg) for arg in args]) else: tprod = ArrayTensorProduct( scalar, *[convert_matrix_to_array(arg) for arg in args]) return ArrayContraction( tprod, *contractions ) elif isinstance(expr, MatAdd): return ArrayAdd( *[convert_matrix_to_array(arg) for arg in expr.args] ) elif isinstance(expr, Transpose): return PermuteDims( convert_matrix_to_array(expr.args[0]), [1, 0] ) elif isinstance(expr, Trace): inner_expr = convert_matrix_to_array(expr.arg) return ArrayContraction(inner_expr, (0, len(inner_expr.shape) - 1)) elif isinstance(expr, Mul): return ArrayTensorProduct.fromiter(convert_matrix_to_array(i) for i in expr.args) elif isinstance(expr, Pow): base = convert_matrix_to_array(expr.base) if (expr.exp > 0) == True: return ArrayTensorProduct.fromiter(base for i in range(expr.exp)) else: return expr elif isinstance(expr, MatPow): base = convert_matrix_to_array(expr.base) if expr.exp.is_Integer != True: b = symbols("b", cls=Dummy) return ArrayElementwiseApplyFunc(Lambda(b, b**expr.exp), convert_matrix_to_array(base)) elif (expr.exp > 0) == True: return convert_matrix_to_array(MatMul.fromiter(base for i in range(expr.exp))) else: return expr elif isinstance(expr, HadamardProduct): tp = ArrayTensorProduct.fromiter([convert_matrix_to_array(arg) for arg in expr.args]) diag = [[2*i for i in range(len(expr.args))], [2*i+1 for i in range(len(expr.args))]] return ArrayDiagonal(tp, *diag) elif isinstance(expr, HadamardPower): base, exp = expr.args if exp.is_Integer and exp > 0: return convert_matrix_to_array(HadamardProduct.fromiter(base for i in range(exp))) else: raise NotImplementedError("conversion of Hadamard symbolic power is currently not supported") else: return expr sympy-sympy-1.9/sympy/tensor/array/expressions/tests/000077500000000000000000000000001412543434000232605ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/array/expressions/tests/__init__.py000066400000000000000000000000001412543434000253570ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/array/expressions/tests/test_array_expressions.py000066400000000000000000000507631412543434000304640ustar00rootroot00000000000000import random from sympy import symbols, ImmutableDenseNDimArray, tensorproduct, tensorcontraction, permutedims, MatrixSymbol, \ ZeroMatrix, sin, cos, DiagMatrix from sympy.combinatorics import Permutation from sympy.tensor.array.expressions.array_expressions import ZeroArray, OneArray, ArraySymbol, ArrayElement, \ PermuteDims, ArrayContraction, ArrayTensorProduct, ArrayDiagonal, \ ArrayAdd, nest_permutation, ArrayElementwiseApplyFunc, _EditArrayContraction, _ArgE from sympy.testing.pytest import raises i, j, k, l, m, n = symbols("i j k l m n") M = ArraySymbol("M", k, k) N = ArraySymbol("N", k, k) P = ArraySymbol("P", k, k) Q = ArraySymbol("Q", k, k) A = ArraySymbol("A", k, k) B = ArraySymbol("B", k, k) C = ArraySymbol("C", k, k) D = ArraySymbol("D", k, k) X = ArraySymbol("X", k, k) Y = ArraySymbol("Y", k, k) a = ArraySymbol("a", k, 1) b = ArraySymbol("b", k, 1) c = ArraySymbol("c", k, 1) d = ArraySymbol("d", k, 1) def test_array_symbol_and_element(): A = ArraySymbol("A", 2) A0 = ArrayElement(A, (0,)) A1 = ArrayElement(A, (1,)) assert A.as_explicit() == ImmutableDenseNDimArray([A0, A1]) A2 = tensorproduct(A, A) assert A2.shape == (2, 2) # TODO: not yet supported: # assert A2.as_explicit() == Array([[A[0]*A[0], A[1]*A[0]], [A[0]*A[1], A[1]*A[1]]]) A3 = tensorcontraction(A2, (0, 1)) assert A3.shape == () # TODO: not yet supported: # assert A3.as_explicit() == Array([]) A = ArraySymbol("A", 2, 3, 4) Ae = A.as_explicit() assert Ae == ImmutableDenseNDimArray( [[[ArrayElement(A, (i, j, k)) for k in range(4)] for j in range(3)] for i in range(2)]) p = permutedims(A, Permutation(0, 2, 1)) assert isinstance(p, PermuteDims) def test_zero_array(): assert ZeroArray() == 0 assert ZeroArray().is_Integer za = ZeroArray(3, 2, 4) assert za.shape == (3, 2, 4) za_e = za.as_explicit() assert za_e.shape == (3, 2, 4) m, n, k = symbols("m n k") za = ZeroArray(m, n, k, 2) assert za.shape == (m, n, k, 2) raises(ValueError, lambda: za.as_explicit()) def test_one_array(): assert OneArray() == 1 assert OneArray().is_Integer oa = OneArray(3, 2, 4) assert oa.shape == (3, 2, 4) oa_e = oa.as_explicit() assert oa_e.shape == (3, 2, 4) m, n, k = symbols("m n k") oa = OneArray(m, n, k, 2) assert oa.shape == (m, n, k, 2) raises(ValueError, lambda: oa.as_explicit()) def test_arrayexpr_contraction_construction(): cg = ArrayContraction(A) assert cg == A cg = ArrayContraction(ArrayTensorProduct(A, B), (1, 0)) assert cg == ArrayContraction(ArrayTensorProduct(A, B), (0, 1)) cg = ArrayContraction(ArrayTensorProduct(M, N), (0, 1)) indtup = cg._get_contraction_tuples() assert indtup == [[(0, 0), (0, 1)]] assert cg._contraction_tuples_to_contraction_indices(cg.expr, indtup) == [(0, 1)] cg = ArrayContraction(ArrayTensorProduct(M, N), (1, 2)) indtup = cg._get_contraction_tuples() assert indtup == [[(0, 1), (1, 0)]] assert cg._contraction_tuples_to_contraction_indices(cg.expr, indtup) == [(1, 2)] cg = ArrayContraction(ArrayTensorProduct(M, M, N), (1, 4), (2, 5)) indtup = cg._get_contraction_tuples() assert indtup == [[(0, 0), (1, 1)], [(0, 1), (2, 0)]] assert cg._contraction_tuples_to_contraction_indices(cg.expr, indtup) == [(0, 3), (1, 4)] def test_arrayexpr_array_flatten(): # Flatten nested ArrayTensorProduct objects: expr1 = ArrayTensorProduct(M, N) expr2 = ArrayTensorProduct(P, Q) expr = ArrayTensorProduct(expr1, expr2) assert expr == ArrayTensorProduct(M, N, P, Q) assert expr.args == (M, N, P, Q) # Flatten mixed ArrayTensorProduct and ArrayContraction objects: cg1 = ArrayContraction(expr1, (1, 2)) cg2 = ArrayContraction(expr2, (0, 3)) expr = ArrayTensorProduct(cg1, cg2) assert expr == ArrayContraction(ArrayTensorProduct(M, N, P, Q), (1, 2), (4, 7)) expr = ArrayTensorProduct(M, cg1) assert expr == ArrayContraction(ArrayTensorProduct(M, M, N), (3, 4)) # Flatten nested ArrayContraction objects: cgnested = ArrayContraction(cg1, (0, 1)) assert cgnested == ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2)) cgnested = ArrayContraction(ArrayTensorProduct(cg1, cg2), (0, 3)) assert cgnested == ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 6), (1, 2), (4, 7)) cg3 = ArrayContraction(ArrayTensorProduct(M, N, P, Q), (1, 3), (2, 4)) cgnested = ArrayContraction(cg3, (0, 1)) assert cgnested == ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 5), (1, 3), (2, 4)) cgnested = ArrayContraction(cg3, (0, 3), (1, 2)) assert cgnested == ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 7), (1, 3), (2, 4), (5, 6)) cg4 = ArrayContraction(ArrayTensorProduct(M, N, P, Q), (1, 5), (3, 7)) cgnested = ArrayContraction(cg4, (0, 1)) assert cgnested == ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 2), (1, 5), (3, 7)) cgnested = ArrayContraction(cg4, (0, 1), (2, 3)) assert cgnested == ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 2), (1, 5), (3, 7), (4, 6)) cg = ArrayDiagonal(cg4) assert cg == cg4 assert isinstance(cg, type(cg4)) # Flatten nested ArrayDiagonal objects: cg1 = ArrayDiagonal(expr1, (1, 2)) cg2 = ArrayDiagonal(expr2, (0, 3)) cg3 = ArrayDiagonal(ArrayTensorProduct(M, N, P, Q), (1, 3), (2, 4)) cg4 = ArrayDiagonal(ArrayTensorProduct(M, N, P, Q), (1, 5), (3, 7)) cgnested = ArrayDiagonal(cg1, (0, 1)) assert cgnested == ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2), (0, 3)) cgnested = ArrayDiagonal(cg3, (1, 2)) assert cgnested == ArrayDiagonal(ArrayTensorProduct(M, N, P, Q), (1, 3), (2, 4), (5, 6)) cgnested = ArrayDiagonal(cg4, (1, 2)) assert cgnested == ArrayDiagonal(ArrayTensorProduct(M, N, P, Q), (1, 5), (3, 7), (2, 4)) cg = ArrayAdd(M, N) cg2 = ArrayAdd(cg, P) assert isinstance(cg2, ArrayAdd) assert cg2.args == (M, N, P) assert cg2.shape == (k, k) expr = ArrayTensorProduct(ArrayDiagonal(X, (0, 1)), ArrayDiagonal(A, (0, 1))) assert expr == ArrayDiagonal(ArrayTensorProduct(X, A), (0, 1), (2, 3)) expr1 = ArrayDiagonal(ArrayTensorProduct(X, A), (1, 2)) expr2 = ArrayTensorProduct(expr1, a) assert expr2 == PermuteDims(ArrayDiagonal(ArrayTensorProduct(X, A, a), (1, 2)), [0, 1, 3, 4, 2]) expr1 = ArrayContraction(ArrayTensorProduct(X, A), (1, 2)) expr2 = ArrayTensorProduct(expr1, a) assert isinstance(expr2, ArrayContraction) assert isinstance(expr2.expr, ArrayTensorProduct) def test_arrayexpr_array_diagonal(): cg = ArrayDiagonal(M, (1, 0)) assert cg == ArrayDiagonal(M, (0, 1)) cg = ArrayDiagonal(ArrayTensorProduct(M, N, P), (4, 1), (2, 0)) assert cg == ArrayDiagonal(ArrayTensorProduct(M, N, P), (1, 4), (0, 2)) def test_arrayexpr_array_shape(): expr = ArrayTensorProduct(M, N, P, Q) assert expr.shape == (k, k, k, k, k, k, k, k) Z = MatrixSymbol("Z", m, n) expr = ArrayTensorProduct(M, Z) assert expr.shape == (k, k, m, n) expr2 = ArrayContraction(expr, (0, 1)) assert expr2.shape == (m, n) expr2 = ArrayDiagonal(expr, (0, 1)) assert expr2.shape == (m, n, k) exprp = PermuteDims(expr, [2, 1, 3, 0]) assert exprp.shape == (m, k, n, k) expr3 = ArrayTensorProduct(N, Z) expr2 = ArrayAdd(expr, expr3) assert expr2.shape == (k, k, m, n) # Contraction along axes with discordant dimensions: raises(ValueError, lambda: ArrayContraction(expr, (1, 2))) # Also diagonal needs the same dimensions: raises(ValueError, lambda: ArrayDiagonal(expr, (1, 2))) # Diagonal requires at least to axes to compute the diagonal: raises(ValueError, lambda: ArrayDiagonal(expr, (1,))) def test_arrayexpr_permutedims_sink(): cg = PermuteDims(ArrayTensorProduct(M, N), [0, 1, 3, 2], nest_permutation=False) sunk = nest_permutation(cg) assert sunk == ArrayTensorProduct(M, PermuteDims(N, [1, 0])) cg = PermuteDims(ArrayTensorProduct(M, N), [1, 0, 3, 2], nest_permutation=False) sunk = nest_permutation(cg) assert sunk == ArrayTensorProduct(PermuteDims(M, [1, 0]), PermuteDims(N, [1, 0])) cg = PermuteDims(ArrayTensorProduct(M, N), [3, 2, 1, 0], nest_permutation=False) sunk = nest_permutation(cg) assert sunk == ArrayTensorProduct(PermuteDims(N, [1, 0]), PermuteDims(M, [1, 0])) cg = PermuteDims(ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), [1, 0], nest_permutation=False) sunk = nest_permutation(cg) assert sunk == ArrayContraction(PermuteDims(ArrayTensorProduct(M, N), [[0, 3]]), (1, 2)) cg = PermuteDims(ArrayTensorProduct(M, N), [1, 0, 3, 2], nest_permutation=False) sunk = nest_permutation(cg) assert sunk == ArrayTensorProduct(PermuteDims(M, [1, 0]), PermuteDims(N, [1, 0])) cg = PermuteDims(ArrayContraction(ArrayTensorProduct(M, N, P), (1, 2), (3, 4)), [1, 0], nest_permutation=False) sunk = nest_permutation(cg) assert sunk == ArrayContraction(PermuteDims(ArrayTensorProduct(M, N, P), [[0, 5]]), (1, 2), (3, 4)) def test_arrayexpr_push_indices_up_and_down(): indices = list(range(12)) contr_diag_indices = [(0, 6), (2, 8)] assert ArrayContraction._push_indices_down(contr_diag_indices, indices) == (1, 3, 4, 5, 7, 9, 10, 11, 12, 13, 14, 15) assert ArrayContraction._push_indices_up(contr_diag_indices, indices) == (None, 0, None, 1, 2, 3, None, 4, None, 5, 6, 7) assert ArrayDiagonal._push_indices_down(contr_diag_indices, indices, 10) == (1, 3, 4, 5, 7, 9, (0, 6), (2, 8), None, None, None, None) assert ArrayDiagonal._push_indices_up(contr_diag_indices, indices, 10) == (6, 0, 7, 1, 2, 3, 6, 4, 7, 5, None, None) contr_diag_indices = [(1, 2), (7, 8)] assert ArrayContraction._push_indices_down(contr_diag_indices, indices) == (0, 3, 4, 5, 6, 9, 10, 11, 12, 13, 14, 15) assert ArrayContraction._push_indices_up(contr_diag_indices, indices) == (0, None, None, 1, 2, 3, 4, None, None, 5, 6, 7) assert ArrayDiagonal._push_indices_down(contr_diag_indices, indices, 10) == (0, 3, 4, 5, 6, 9, (1, 2), (7, 8), None, None, None, None) assert ArrayDiagonal._push_indices_up(contr_diag_indices, indices, 10) == (0, 6, 6, 1, 2, 3, 4, 7, 7, 5, None, None) def test_arrayexpr_split_multiple_contractions(): a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) X = MatrixSymbol("X", k, k) cg = ArrayContraction(ArrayTensorProduct(A.T, a, b, b.T, (A*X*b).applyfunc(cos)), (1, 2, 8), (5, 6, 9)) assert cg.split_multiple_contractions().dummy_eq(ArrayContraction(ArrayTensorProduct(DiagMatrix(a), (A*X*b).applyfunc(cos), A.T, b, b.T), (0, 2), (1, 5), (3, 7, 8))) # assert recognize_matrix_expression(cg) # Check no overlap of lines: cg = ArrayContraction(ArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8), (3, 7)) assert cg.split_multiple_contractions() == cg cg = ArrayContraction(ArrayTensorProduct(a, b, A), (0, 2, 4), (1, 3)) assert cg.split_multiple_contractions() == cg def test_arrayexpr_nested_permutations(): cg = PermuteDims(PermuteDims(M, (1, 0)), (1, 0)) assert cg == M times = 3 plist1 = [list(range(6)) for i in range(times)] plist2 = [list(range(6)) for i in range(times)] for i in range(times): random.shuffle(plist1[i]) random.shuffle(plist2[i]) plist1.append([2, 5, 4, 1, 0, 3]) plist2.append([3, 5, 0, 4, 1, 2]) plist1.append([2, 5, 4, 0, 3, 1]) plist2.append([3, 0, 5, 1, 2, 4]) plist1.append([5, 4, 2, 0, 3, 1]) plist2.append([4, 5, 0, 2, 3, 1]) Me = M.subs(k, 3).as_explicit() Ne = N.subs(k, 3).as_explicit() Pe = P.subs(k, 3).as_explicit() cge = tensorproduct(Me, Ne, Pe) for permutation_array1, permutation_array2 in zip(plist1, plist2): p1 = Permutation(permutation_array1) p2 = Permutation(permutation_array2) cg = PermuteDims( PermuteDims( ArrayTensorProduct(M, N, P), p1), p2 ) result = PermuteDims( ArrayTensorProduct(M, N, P), p2*p1 ) assert cg == result # Check that `permutedims` behaves the same way with explicit-component arrays: result1 = permutedims(permutedims(cge, p1), p2) result2 = permutedims(cge, p2*p1) assert result1 == result2 def test_arrayexpr_contraction_permutation_mix(): Me = M.subs(k, 3).as_explicit() Ne = N.subs(k, 3).as_explicit() cg1 = ArrayContraction(PermuteDims(ArrayTensorProduct(M, N), Permutation([0, 2, 1, 3])), (2, 3)) cg2 = ArrayContraction(ArrayTensorProduct(M, N), (1, 3)) assert cg1 == cg2 cge1 = tensorcontraction(permutedims(tensorproduct(Me, Ne), Permutation([0, 2, 1, 3])), (2, 3)) cge2 = tensorcontraction(tensorproduct(Me, Ne), (1, 3)) assert cge1 == cge2 cg1 = PermuteDims(ArrayTensorProduct(M, N), Permutation([0, 1, 3, 2])) cg2 = ArrayTensorProduct(M, PermuteDims(N, Permutation([1, 0]))) assert cg1 == cg2 cg1 = ArrayContraction( PermuteDims( ArrayTensorProduct(M, N, P, Q), Permutation([0, 2, 3, 1, 4, 5, 7, 6])), (1, 2), (3, 5) ) cg2 = ArrayContraction( ArrayTensorProduct(M, N, P, PermuteDims(Q, Permutation([1, 0]))), (1, 5), (2, 3) ) assert cg1 == cg2 cg1 = ArrayContraction( PermuteDims( ArrayTensorProduct(M, N, P, Q), Permutation([1, 0, 4, 6, 2, 7, 5, 3])), (0, 1), (2, 6), (3, 7) ) cg2 = PermuteDims( ArrayContraction( ArrayTensorProduct(M, P, Q, N), (0, 1), (2, 3), (4, 7)), [1, 0] ) assert cg1 == cg2 cg1 = ArrayContraction( PermuteDims( ArrayTensorProduct(M, N, P, Q), Permutation([1, 0, 4, 6, 7, 2, 5, 3])), (0, 1), (2, 6), (3, 7) ) cg2 = PermuteDims( ArrayContraction( ArrayTensorProduct(PermuteDims(M, [1, 0]), N, P, Q), (0, 1), (3, 6), (4, 5) ), Permutation([1, 0]) ) assert cg1 == cg2 def test_arrayexpr_permute_tensor_product(): cg1 = PermuteDims(ArrayTensorProduct(M, N, P, Q), Permutation([2, 3, 1, 0, 5, 4, 6, 7])) cg2 = ArrayTensorProduct(N, PermuteDims(M, [1, 0]), PermuteDims(P, [1, 0]), Q) assert cg1 == cg2 # TODO: reverse operation starting with `PermuteDims` and getting down to `bb`... cg1 = PermuteDims(ArrayTensorProduct(M, N, P, Q), Permutation([2, 3, 4, 5, 0, 1, 6, 7])) cg2 = ArrayTensorProduct(N, P, M, Q) assert cg1 == cg2 cg1 = PermuteDims(ArrayTensorProduct(M, N, P, Q), Permutation([2, 3, 4, 6, 5, 7, 0, 1])) assert cg1.expr == ArrayTensorProduct(N, P, Q, M) assert cg1.permutation == Permutation([0, 1, 2, 4, 3, 5, 6, 7]) cg1 = ArrayContraction( PermuteDims( ArrayTensorProduct(N, Q, Q, M), [2, 1, 5, 4, 0, 3, 6, 7]), [1, 2, 6]) cg2 = PermuteDims(ArrayContraction(ArrayTensorProduct(Q, Q, N, M), (3, 5, 6)), [0, 2, 3, 1, 4]) assert cg1 == cg2 cg1 = ArrayContraction( ArrayContraction( ArrayContraction( ArrayContraction( PermuteDims( ArrayTensorProduct(N, Q, Q, M), [2, 1, 5, 4, 0, 3, 6, 7]), [1, 2, 6]), [1, 3, 4]), [1]), [0]) cg2 = ArrayContraction(ArrayTensorProduct(M, N, Q, Q), (0, 3, 5), (1, 4, 7), (2,), (6,)) assert cg1 == cg2 def test_arrayexpr_normalize_diagonal_permutedims(): tp = ArrayTensorProduct(M, Q, N, P) expr = ArrayDiagonal( PermuteDims(tp, [0, 1, 2, 4, 7, 6, 3, 5]), (2, 4, 5), (6, 7), (0, 3)) result = ArrayDiagonal(tp, (2, 6, 7), (3, 5), (0, 4)) assert expr == result tp = ArrayTensorProduct(M, N, P, Q) expr = ArrayDiagonal(PermuteDims(tp, [0, 5, 2, 4, 1, 6, 3, 7]), (1, 2, 6), (3, 4)) result = ArrayDiagonal(ArrayTensorProduct(M, P, N, Q), (3, 4, 5), (1, 2)) assert expr == result def test_arrayexpr_normalize_diagonal_contraction(): tp = ArrayTensorProduct(M, N, P, Q) expr = ArrayContraction(ArrayDiagonal(tp, (1, 3, 4)), (0, 3)) result = ArrayDiagonal(ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 6)), (0, 2, 3)) assert expr == result expr = ArrayContraction(ArrayDiagonal(tp, (0, 1, 2, 3, 7)), (1, 2, 3)) result = ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 1, 2, 3, 5, 6, 7)) assert expr == result expr = ArrayContraction(ArrayDiagonal(tp, (0, 2, 6, 7)), (1, 2, 3)) result = ArrayDiagonal(ArrayContraction(tp, (3, 4, 5)), (0, 2, 3, 4)) assert expr == result td = ArrayDiagonal(ArrayTensorProduct(M, N, P, Q), (0, 3)) expr = ArrayContraction(td, (2, 1), (0, 4, 6, 5, 3)) result = ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 1, 3, 5, 6, 7), (2, 4)) assert expr == result def test_arrayexpr_array_wrong_permutation_size(): cg = ArrayTensorProduct(M, N) raises(ValueError, lambda: PermuteDims(cg, [1, 0])) raises(ValueError, lambda: PermuteDims(cg, [1, 0, 2, 3, 5, 4])) def test_arrayexpr_nested_array_elementwise_add(): cg = ArrayContraction(ArrayAdd( ArrayTensorProduct(M, N), ArrayTensorProduct(N, M) ), (1, 2)) result = ArrayAdd( ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), ArrayContraction(ArrayTensorProduct(N, M), (1, 2)) ) assert cg == result cg = ArrayDiagonal(ArrayAdd( ArrayTensorProduct(M, N), ArrayTensorProduct(N, M) ), (1, 2)) result = ArrayAdd( ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2)), ArrayDiagonal(ArrayTensorProduct(N, M), (1, 2)) ) assert cg == result def test_arrayexpr_array_expr_zero_array(): za1 = ZeroArray(k, l, m, n) zm1 = ZeroMatrix(m, n) za2 = ZeroArray(k, m, m, n) zm2 = ZeroMatrix(m, m) zm3 = ZeroMatrix(k, k) assert ArrayTensorProduct(M, N, za1) == ZeroArray(k, k, k, k, k, l, m, n) assert ArrayTensorProduct(M, N, zm1) == ZeroArray(k, k, k, k, m, n) assert ArrayContraction(za1, (3,)) == ZeroArray(k, l, m) assert ArrayContraction(zm1, (1,)) == ZeroArray(m) assert ArrayContraction(za2, (1, 2)) == ZeroArray(k, n) assert ArrayContraction(zm2, (0, 1)) == 0 assert ArrayDiagonal(za2, (1, 2)) == ZeroArray(k, n, m) assert ArrayDiagonal(zm2, (0, 1)) == ZeroArray(m) assert PermuteDims(za1, [2, 1, 3, 0]) == ZeroArray(m, l, n, k) assert PermuteDims(zm1, [1, 0]) == ZeroArray(n, m) assert ArrayAdd(za1) == za1 assert ArrayAdd(zm1) == ZeroArray(m, n) tp1 = ArrayTensorProduct(MatrixSymbol("A", k, l), MatrixSymbol("B", m, n)) assert ArrayAdd(tp1, za1) == tp1 tp2 = ArrayTensorProduct(MatrixSymbol("C", k, l), MatrixSymbol("D", m, n)) assert ArrayAdd(tp1, za1, tp2) == ArrayAdd(tp1, tp2) assert ArrayAdd(M, zm3) == M assert ArrayAdd(M, N, zm3) == ArrayAdd(M, N) def test_arrayexpr_array_expr_applyfunc(): A = ArraySymbol("A", 3, k, 2) aaf = ArrayElementwiseApplyFunc(sin, A) assert aaf.shape == (3, k, 2) def test_edit_array_contraction(): cg = ArrayContraction(ArrayTensorProduct(A, B, C, D), (1, 2, 5)) ecg = _EditArrayContraction(cg) assert ecg.to_array_contraction() == cg ecg.args_with_ind[1], ecg.args_with_ind[2] = ecg.args_with_ind[2], ecg.args_with_ind[1] assert ecg.to_array_contraction() == ArrayContraction(ArrayTensorProduct(A, C, B, D), (1, 3, 4)) ci = ecg.get_new_contraction_index() new_arg = _ArgE(X) new_arg.indices = [ci, ci] ecg.args_with_ind.insert(2, new_arg) assert ecg.to_array_contraction() == ArrayContraction(ArrayTensorProduct(A, C, X, B, D), (1, 3, 6), (4, 5)) assert ecg.get_contraction_indices() == [[1, 3, 6], [4, 5]] assert [[tuple(j) for j in i] for i in ecg.get_contraction_indices_to_ind_rel_pos()] == [[(0, 1), (1, 1), (3, 0)], [(2, 0), (2, 1)]] assert [list(i) for i in ecg.get_mapping_for_index(0)] == [[0, 1], [1, 1], [3, 0]] assert [list(i) for i in ecg.get_mapping_for_index(1)] == [[2, 0], [2, 1]] raises(ValueError, lambda: ecg.get_mapping_for_index(2)) ecg.args_with_ind.pop(1) assert ecg.to_array_contraction() == ArrayContraction(ArrayTensorProduct(A, X, B, D), (1, 4), (2, 3)) ecg.args_with_ind[0].indices[1] = ecg.args_with_ind[1].indices[0] ecg.args_with_ind[1].indices[1] = ecg.args_with_ind[2].indices[0] assert ecg.to_array_contraction() == ArrayContraction(ArrayTensorProduct(A, X, B, D), (1, 2), (3, 4)) ecg.insert_after(ecg.args_with_ind[1], _ArgE(C)) assert ecg.to_array_contraction() == ArrayContraction(ArrayTensorProduct(A, X, C, B, D), (1, 2), (3, 6)) sympy-sympy-1.9/sympy/tensor/array/expressions/tests/test_arrayexpr_derivatives.py000066400000000000000000000041231412543434000313130ustar00rootroot00000000000000from sympy import MatrixSymbol, symbols, Identity, sin, cos from sympy.matrices.expressions.applyfunc import ElementwiseApplyFunction from sympy.tensor.array.expressions.array_expressions import ArraySymbol, ArrayTensorProduct, \ PermuteDims, ArrayDiagonal, ArrayElementwiseApplyFunc, ArrayContraction from sympy.tensor.array.expressions.arrayexpr_derivatives import array_derive k = symbols("k") I = Identity(k) X = MatrixSymbol("X", k, k) x = MatrixSymbol("x", k, 1) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) D = MatrixSymbol("D", k, k) A1 = ArraySymbol("A", 3, 2, k) def test_arrayexpr_derivatives1(): res = array_derive(X, X) assert res == PermuteDims(ArrayTensorProduct(I, I), [0, 2, 1, 3]) cg = ArrayTensorProduct(A, X, B) res = array_derive(cg, X) assert res == PermuteDims( ArrayTensorProduct(I, A, I, B), [0, 4, 2, 3, 1, 5, 6, 7]) cg = ArrayContraction(X, (0, 1)) res = array_derive(cg, X) assert res == ArrayContraction(ArrayTensorProduct(I, I), (1, 3)) cg = ArrayDiagonal(X, (0, 1)) res = array_derive(cg, X) assert res == ArrayDiagonal(ArrayTensorProduct(I, I), (1, 3)) cg = ElementwiseApplyFunction(sin, X) res = array_derive(cg, X) assert res.dummy_eq(ArrayDiagonal( ArrayTensorProduct( ElementwiseApplyFunction(cos, X), I, I ), (0, 3), (1, 5))) cg = ArrayElementwiseApplyFunc(sin, X) res = array_derive(cg, X) assert res.dummy_eq(ArrayDiagonal( ArrayTensorProduct( I, I, ArrayElementwiseApplyFunc(cos, X) ), (1, 4), (3, 5))) res = array_derive(A1, A1) assert res == PermuteDims( ArrayTensorProduct(Identity(3), Identity(2), Identity(k)), [0, 2, 4, 1, 3, 5] ) cg = ArrayElementwiseApplyFunc(sin, A1) res = array_derive(cg, A1) assert res.dummy_eq(ArrayDiagonal( ArrayTensorProduct( Identity(3), Identity(2), Identity(k), ArrayElementwiseApplyFunc(cos, A1) ), (1, 6), (3, 7), (5, 8) )) sympy-sympy-1.9/sympy/tensor/array/expressions/tests/test_as_explicit.py000066400000000000000000000043131412543434000271760ustar00rootroot00000000000000from sympy import ImmutableDenseNDimArray, tensorproduct, MatrixSymbol, tensorcontraction, tensordiagonal, permutedims, \ Symbol from sympy.tensor.array.expressions.array_expressions import ZeroArray, OneArray, ArraySymbol, \ ArrayTensorProduct, PermuteDims, ArrayDiagonal, ArrayContraction from sympy.testing.pytest import raises def test_array_as_explicit_call(): assert ZeroArray(3, 2, 4).as_explicit() == ImmutableDenseNDimArray.zeros(3, 2, 4) assert OneArray(3, 2, 4).as_explicit() == ImmutableDenseNDimArray([1 for i in range(3*2*4)]).reshape(3, 2, 4) k = Symbol("k") X = ArraySymbol("X", k, 3, 2) raises(ValueError, lambda: X.as_explicit()) raises(ValueError, lambda: ZeroArray(k, 2, 3).as_explicit()) raises(ValueError, lambda: OneArray(2, k, 2).as_explicit()) A = ArraySymbol("A", 3, 3) B = ArraySymbol("B", 3, 3) texpr = tensorproduct(A, B) assert isinstance(texpr, ArrayTensorProduct) assert texpr.as_explicit() == tensorproduct(A.as_explicit(), B.as_explicit()) texpr = tensorcontraction(A, (0, 1)) assert isinstance(texpr, ArrayContraction) assert texpr.as_explicit() == A[0, 0] + A[1, 1] + A[2, 2] texpr = tensordiagonal(A, (0, 1)) assert isinstance(texpr, ArrayDiagonal) assert texpr.as_explicit() == ImmutableDenseNDimArray([A[0, 0], A[1, 1], A[2, 2]]) texpr = permutedims(A, [1, 0]) assert isinstance(texpr, PermuteDims) assert texpr.as_explicit() == permutedims(A.as_explicit(), [1, 0]) def test_array_as_explicit_matrix_symbol(): A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) texpr = tensorproduct(A, B) assert isinstance(texpr, ArrayTensorProduct) assert texpr.as_explicit() == tensorproduct(A.as_explicit(), B.as_explicit()) texpr = tensorcontraction(A, (0, 1)) assert isinstance(texpr, ArrayContraction) assert texpr.as_explicit() == A[0, 0] + A[1, 1] + A[2, 2] texpr = tensordiagonal(A, (0, 1)) assert isinstance(texpr, ArrayDiagonal) assert texpr.as_explicit() == ImmutableDenseNDimArray([A[0, 0], A[1, 1], A[2, 2]]) texpr = permutedims(A, [1, 0]) assert isinstance(texpr, PermuteDims) assert texpr.as_explicit() == permutedims(A.as_explicit(), [1, 0]) sympy-sympy-1.9/sympy/tensor/array/expressions/tests/test_convert_array_to_matrix.py000066400000000000000000000511501412543434000316370ustar00rootroot00000000000000from sympy import ( symbols, Identity, cos, ZeroMatrix, OneMatrix, sqrt, HadamardProduct) from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array from sympy.tensor.array.expressions.conv_array_to_matrix import _support_function_tp1_recognize, \ _array_diag2contr_diagmatrix, convert_array_to_matrix, _remove_trivial_dims, _array2matrix from sympy import MatrixSymbol from sympy.combinatorics import Permutation from sympy.matrices.expressions.diagonal import DiagMatrix from sympy.matrices import Trace, MatMul, Transpose from sympy.tensor.array.expressions.array_expressions import ZeroArray, OneArray, \ ArrayTensorProduct, ArrayAdd, PermuteDims, ArrayDiagonal, \ ArrayContraction from sympy.testing.pytest import raises i, j, k, l, m, n = symbols("i j k l m n") I = Identity(k) I1 = Identity(1) M = MatrixSymbol("M", k, k) N = MatrixSymbol("N", k, k) P = MatrixSymbol("P", k, k) Q = MatrixSymbol("Q", k, k) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) D = MatrixSymbol("D", k, k) X = MatrixSymbol("X", k, k) Y = MatrixSymbol("Y", k, k) a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) c = MatrixSymbol("c", k, 1) d = MatrixSymbol("d", k, 1) x = MatrixSymbol("x", k, 1) def test_arrayexpr_convert_array_to_matrix(): cg = ArrayContraction(ArrayTensorProduct(M), (0, 1)) assert convert_array_to_matrix(cg) == Trace(M) cg = ArrayContraction(ArrayTensorProduct(M, N), (0, 1), (2, 3)) assert convert_array_to_matrix(cg) == Trace(M) * Trace(N) cg = ArrayContraction(ArrayTensorProduct(M, N), (0, 3), (1, 2)) assert convert_array_to_matrix(cg) == Trace(M * N) cg = ArrayContraction(ArrayTensorProduct(M, N), (0, 2), (1, 3)) assert convert_array_to_matrix(cg) == Trace(M * N.T) cg = convert_matrix_to_array(M * N * P) assert convert_array_to_matrix(cg) == M * N * P cg = convert_matrix_to_array(M * N.T * P) assert convert_array_to_matrix(cg) == M * N.T * P cg = ArrayContraction(ArrayTensorProduct(M,N,P,Q), (1, 2), (5, 6)) assert convert_array_to_matrix(cg) == ArrayTensorProduct(M * N, P * Q) cg = ArrayContraction(ArrayTensorProduct(-2, M, N), (1, 2)) assert convert_array_to_matrix(cg) == -2 * M * N a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) c = MatrixSymbol("c", k, 1) cg = PermuteDims( ArrayContraction( ArrayTensorProduct( a, ArrayAdd( ArrayTensorProduct(b, c), ArrayTensorProduct(c, b), ) ), (2, 4)), [0, 1, 3, 2]) assert convert_array_to_matrix(cg) == a * (b.T * c + c.T * b) za = ZeroArray(m, n) assert convert_array_to_matrix(za) == ZeroMatrix(m, n) cg = ArrayTensorProduct(3, M) assert convert_array_to_matrix(cg) == 3 * M # Partial conversion to matrix multiplication: expr = ArrayContraction(ArrayTensorProduct(M, N, P, Q), (0, 2), (1, 4, 6)) assert convert_array_to_matrix(expr) == ArrayContraction(ArrayTensorProduct(M.T*N, P, Q), (0, 2, 4)) # TODO: not yet supported: # cg = ArrayDiagonal(ArrayTensorProduct(M, N, P), (0, 2, 4), (1, 3, 5)) # assert recognize_matrix_expression(cg) == HadamardProduct(M, N, P) # cg = ArrayDiagonal(ArrayTensorProduct(M, N, P), (0, 3, 4), (1, 2, 5)) # assert recognize_matrix_expression(cg) == HadamardProduct(M, N.T, P) x = MatrixSymbol("x", k, 1) cg = PermuteDims( ArrayContraction(ArrayTensorProduct(OneArray(1), x, OneArray(1), DiagMatrix(Identity(1))), (0, 5)), Permutation(1, 2, 3)) assert convert_array_to_matrix(cg) == x expr = ArrayAdd(M, PermuteDims(M, [1, 0])) assert convert_array_to_matrix(expr) == M + Transpose(M) def test_arrayexpr_convert_array_to_matrix2(): cg = ArrayContraction(ArrayTensorProduct(M, N), (1, 3)) assert convert_array_to_matrix(cg) == M * N.T cg = PermuteDims(ArrayTensorProduct(M, N), Permutation([0, 1, 3, 2])) assert convert_array_to_matrix(cg) == ArrayTensorProduct(M, N.T) cg = ArrayTensorProduct(M, PermuteDims(N, Permutation([1, 0]))) assert convert_array_to_matrix(cg) == ArrayTensorProduct(M, N.T) cg = ArrayContraction( PermuteDims( ArrayTensorProduct(M, N, P, Q), Permutation([0, 2, 3, 1, 4, 5, 7, 6])), (1, 2), (3, 5) ) assert convert_array_to_matrix(cg) == ArrayTensorProduct(M * P.T * Trace(N), Q.T) cg = ArrayContraction( ArrayTensorProduct(M, N, P, PermuteDims(Q, Permutation([1, 0]))), (1, 5), (2, 3) ) assert convert_array_to_matrix(cg) == ArrayTensorProduct(M * P.T * Trace(N), Q.T) cg = ArrayTensorProduct(M, PermuteDims(N, [1, 0])) assert convert_array_to_matrix(cg) == ArrayTensorProduct(M, N.T) cg = ArrayTensorProduct(PermuteDims(M, [1, 0]), PermuteDims(N, [1, 0])) assert convert_array_to_matrix(cg) == ArrayTensorProduct(M.T, N.T) cg = ArrayTensorProduct(PermuteDims(N, [1, 0]), PermuteDims(M, [1, 0])) assert convert_array_to_matrix(cg) == ArrayTensorProduct(N.T, M.T) def test_arrayexpr_convert_array_to_diagonalized_vector(): # Check matrix recognition over trivial dimensions: cg = ArrayTensorProduct(a, b) assert convert_array_to_matrix(cg) == a * b.T cg = ArrayTensorProduct(I1, a, b) assert convert_array_to_matrix(cg) == a * b.T # Recognize trace inside a tensor product: cg = ArrayContraction(ArrayTensorProduct(A, B, C), (0, 3), (1, 2)) assert convert_array_to_matrix(cg) == Trace(A * B) * C # Transform diagonal operator to contraction: cg = ArrayDiagonal(ArrayTensorProduct(A, a), (1, 2)) assert _array_diag2contr_diagmatrix(cg) == ArrayContraction(ArrayTensorProduct(A, OneArray(1), DiagMatrix(a)), (1, 3)) assert convert_array_to_matrix(cg) == A * DiagMatrix(a) cg = ArrayDiagonal(ArrayTensorProduct(a, b), (0, 2)) assert _array_diag2contr_diagmatrix(cg) == PermuteDims( ArrayContraction(ArrayTensorProduct(DiagMatrix(a), OneArray(1), b), (0, 3)), [1, 2, 0] ) assert convert_array_to_matrix(cg) == b.T * DiagMatrix(a) cg = ArrayDiagonal(ArrayTensorProduct(A, a), (0, 2)) assert _array_diag2contr_diagmatrix(cg) == ArrayContraction(ArrayTensorProduct(A, OneArray(1), DiagMatrix(a)), (0, 3)) assert convert_array_to_matrix(cg) == A.T * DiagMatrix(a) cg = ArrayDiagonal(ArrayTensorProduct(I, x, I1), (0, 2), (3, 5)) assert _array_diag2contr_diagmatrix(cg) == ArrayContraction(ArrayTensorProduct(I, OneArray(1), I1, DiagMatrix(x)), (0, 5)) assert convert_array_to_matrix(cg) == DiagMatrix(x) cg = ArrayDiagonal(ArrayTensorProduct(I, x, A, B), (1, 2), (5, 6)) assert _array_diag2contr_diagmatrix(cg) == ArrayDiagonal(ArrayContraction(ArrayTensorProduct(I, OneArray(1), A, B, DiagMatrix(x)), (1, 7)), (5, 6)) # TODO: not yet working # assert convert_array_to_matrix(cg) cg = ArrayDiagonal(ArrayTensorProduct(x, I1), (1, 2)) assert isinstance(cg, ArrayDiagonal) assert cg.diagonal_indices == ((1, 2),) assert convert_array_to_matrix(cg) == x cg = ArrayDiagonal(ArrayTensorProduct(x, I), (0, 2)) assert _array_diag2contr_diagmatrix(cg) == ArrayContraction(ArrayTensorProduct(OneArray(1), I, DiagMatrix(x)), (1, 3)) assert convert_array_to_matrix(cg).doit() == DiagMatrix(x) raises(ValueError, lambda: ArrayDiagonal(x, (1,))) # Ignore identity matrices with contractions: cg = ArrayContraction(ArrayTensorProduct(I, A, I, I), (0, 2), (1, 3), (5, 7)) assert cg.split_multiple_contractions() == cg assert convert_array_to_matrix(cg) == Trace(A) * I cg = ArrayContraction(ArrayTensorProduct(Trace(A) * I, I, I), (1, 5), (3, 4)) assert cg.split_multiple_contractions() == cg assert convert_array_to_matrix(cg).doit() == Trace(A) * I # Add DiagMatrix when required: cg = ArrayContraction(ArrayTensorProduct(A, a), (1, 2)) assert cg.split_multiple_contractions() == cg assert convert_array_to_matrix(cg) == A * a cg = ArrayContraction(ArrayTensorProduct(A, a, B), (1, 2, 4)) assert cg.split_multiple_contractions() == ArrayContraction(ArrayTensorProduct(A, DiagMatrix(a), B), (1, 2), (3, 4)) assert convert_array_to_matrix(cg) == A * DiagMatrix(a) * B cg = ArrayContraction(ArrayTensorProduct(A, a, B), (0, 2, 4)) assert cg.split_multiple_contractions() == ArrayContraction(ArrayTensorProduct(A, DiagMatrix(a), B), (0, 2), (3, 4)) assert convert_array_to_matrix(cg) == A.T * DiagMatrix(a) * B cg = ArrayContraction(ArrayTensorProduct(A, a, b, a.T, B), (0, 2, 4, 7, 9)) assert cg.split_multiple_contractions() == ArrayContraction(ArrayTensorProduct(A, DiagMatrix(a), DiagMatrix(b), DiagMatrix(a), B), (0, 2), (3, 4), (5, 7), (6, 9)) assert convert_array_to_matrix(cg).doit() == A.T * DiagMatrix(a) * DiagMatrix(b) * DiagMatrix(a) * B.T cg = ArrayContraction(ArrayTensorProduct(I1, I1, I1), (1, 2, 4)) assert cg.split_multiple_contractions() == ArrayContraction(ArrayTensorProduct(I1, I1, I1), (1, 2), (3, 4)) assert convert_array_to_matrix(cg).doit() == Identity(1) cg = ArrayContraction(ArrayTensorProduct(I, I, I, I, A), (1, 2, 8), (5, 6, 9)) assert convert_array_to_matrix(cg.split_multiple_contractions()).doit() == A cg = ArrayContraction(ArrayTensorProduct(A, a, C, a, B), (1, 2, 4), (5, 6, 8)) expected = ArrayContraction(ArrayTensorProduct(DiagMatrix(a), DiagMatrix(a), C, A, B), (0, 4), (1, 7), (2, 5), (3, 8)) assert cg.split_multiple_contractions() == expected assert convert_array_to_matrix(cg) == A * DiagMatrix(a) * C * DiagMatrix(a) * B cg = ArrayContraction(ArrayTensorProduct(a, I1, b, I1, (a.T*b).applyfunc(cos)), (1, 2, 8), (5, 6, 9)) assert cg.split_multiple_contractions().dummy_eq(ArrayContraction(ArrayTensorProduct((a.T * b).applyfunc(cos), I1, I1, a, b), (0, 2), (1, 4), (3, 7), (5, 9))) assert convert_array_to_matrix(cg).doit().dummy_eq(MatMul(a, (a.T * b).applyfunc(cos), b.T)) def test_arrayexpr_convert_array_contraction_tp_additions(): a = ArrayAdd( ArrayTensorProduct(M, N), ArrayTensorProduct(N, M) ) tp = ArrayTensorProduct(P, a, Q) expr = ArrayContraction(tp, (3, 4)) expected = ArrayTensorProduct( P, ArrayAdd( ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), ArrayContraction(ArrayTensorProduct(N, M), (1, 2)), ), Q ) assert expr == expected assert convert_array_to_matrix(expr) == ArrayTensorProduct(P, M * N + N * M, Q) expr = ArrayContraction(tp, (1, 2), (3, 4), (5, 6)) result = ArrayContraction( ArrayTensorProduct( P, ArrayAdd( ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), ArrayContraction(ArrayTensorProduct(N, M), (1, 2)), ), Q ), (1, 2), (3, 4)) assert expr == result assert convert_array_to_matrix(expr) == P * (M * N + N * M) * Q def test_arrayexpr_convert_array_to_implicit_matmul(): # Trivial dimensions are suppressed, so the result can be expressed in matrix form: cg = ArrayTensorProduct(a, b) assert convert_array_to_matrix(cg) == a * b.T cg = ArrayTensorProduct(a, I, b) assert convert_array_to_matrix(cg) == a * b.T cg = ArrayContraction(ArrayTensorProduct(I, I), (1, 2)) assert convert_array_to_matrix(cg) == I cg = PermuteDims(ArrayTensorProduct(I, Identity(1)), [0, 2, 1, 3]) assert convert_array_to_matrix(cg) == I def test_arrayexpr_convert_array_to_matrix_remove_trivial_dims(): # Tensor Product: assert _remove_trivial_dims(ArrayTensorProduct(a, b)) == (a * b.T, [1, 3]) assert _remove_trivial_dims(ArrayTensorProduct(a.T, b)) == (a * b.T, [0, 3]) assert _remove_trivial_dims(ArrayTensorProduct(a, b.T)) == (a * b.T, [1, 2]) assert _remove_trivial_dims(ArrayTensorProduct(a.T, b.T)) == (a * b.T, [0, 2]) assert _remove_trivial_dims(ArrayTensorProduct(I, a.T, b.T)) == (a * b.T, [0, 1, 2, 4]) assert _remove_trivial_dims(ArrayTensorProduct(a.T, I, b.T)) == (a * b.T, [0, 2, 3, 4]) assert _remove_trivial_dims(ArrayTensorProduct(a, I)) == (a, [2, 3]) assert _remove_trivial_dims(ArrayTensorProduct(I, a)) == (a, [0, 1]) assert _remove_trivial_dims(ArrayTensorProduct(a.T, b.T, c, d)) == ( ArrayTensorProduct(a * b.T, c * d.T), [0, 2, 5, 7]) assert _remove_trivial_dims(ArrayTensorProduct(a.T, I, b.T, c, d, I)) == ( ArrayTensorProduct(a * b.T, c * d.T, I), [0, 2, 3, 4, 7, 9]) # Addition: cg = ArrayAdd(ArrayTensorProduct(a, b), ArrayTensorProduct(c, d)) assert _remove_trivial_dims(cg) == (a * b.T + c * d.T, [1, 3]) # Permute Dims: cg = PermuteDims(ArrayTensorProduct(a, b), Permutation(3)(1, 2)) assert _remove_trivial_dims(cg) == (a * b.T, [2, 3]) cg = PermuteDims(ArrayTensorProduct(a, I, b), Permutation(5)(1, 2, 3, 4)) assert _remove_trivial_dims(cg) == (a * b.T, [1, 2, 4, 5]) cg = PermuteDims(ArrayTensorProduct(I, b, a), Permutation(5)(1, 2, 4, 5, 3)) assert _remove_trivial_dims(cg) == (b * a.T, [0, 3, 4, 5]) # Diagonal: cg = ArrayDiagonal(ArrayTensorProduct(M, a), (1, 2)) assert _remove_trivial_dims(cg) == (cg, []) # Contraction: cg = ArrayContraction(ArrayTensorProduct(M, a), (1, 2)) assert _remove_trivial_dims(cg) == (cg, []) # A few more cases to test the removal and shift of nested removed axes # with array contractions and array diagonals: tp = ArrayTensorProduct( OneMatrix(1, 1), M, x, OneMatrix(1, 1), Identity(1), ) expr = ArrayContraction(tp, (1, 8)) rexpr, removed = _remove_trivial_dims(expr) assert removed == [0, 5, 6, 7] expr = ArrayContraction(tp, (1, 8), (3, 4)) rexpr, removed = _remove_trivial_dims(expr) assert removed == [0, 3, 4, 5] expr = ArrayDiagonal(tp, (1, 8)) rexpr, removed = _remove_trivial_dims(expr) assert removed == [0, 5, 6, 7, 8] expr = ArrayDiagonal(tp, (1, 8), (3, 4)) rexpr, removed = _remove_trivial_dims(expr) assert removed == [0, 3, 4, 5, 6] cg = ArrayDiagonal(ArrayTensorProduct(PermuteDims(ArrayTensorProduct(x, I1), Permutation(1, 2, 3)), (x.T*x).applyfunc(sqrt)), (2, 4), (3, 5)) rexpr, removed = _remove_trivial_dims(cg) assert removed == [1, 2, 3] def test_arrayexpr_convert_array_to_matrix_diag2contraction_diagmatrix(): cg = ArrayDiagonal(ArrayTensorProduct(M, a), (1, 2)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == ArrayContraction(ArrayTensorProduct(M, OneArray(1), DiagMatrix(a)), (1, 3)) raises(ValueError, lambda: ArrayDiagonal(ArrayTensorProduct(a, M), (1, 2))) cg = ArrayDiagonal(ArrayTensorProduct(a.T, M), (1, 2)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == ArrayContraction(ArrayTensorProduct(OneArray(1), M, DiagMatrix(a.T)), (1, 4)) cg = ArrayDiagonal(ArrayTensorProduct(a.T, M, N, b.T), (1, 2), (4, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == ArrayContraction( ArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a.T), DiagMatrix(b.T)), (1, 7), (3, 9)) cg = ArrayDiagonal(ArrayTensorProduct(a, M, N, b.T), (0, 2), (4, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == ArrayContraction( ArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a), DiagMatrix(b.T)), (1, 6), (3, 9)) cg = ArrayDiagonal(ArrayTensorProduct(a, M, N, b.T), (0, 4), (3, 7)) res = _array_diag2contr_diagmatrix(cg) assert res.shape == cg.shape assert res == ArrayContraction( ArrayTensorProduct(OneArray(1), M, N, OneArray(1), DiagMatrix(a), DiagMatrix(b.T)), (3, 6), (2, 9)) I1 = Identity(1) x = MatrixSymbol("x", k, 1) A = MatrixSymbol("A", k, k) cg = ArrayDiagonal(ArrayTensorProduct(x, A.T, I1), (0, 2)) assert _array_diag2contr_diagmatrix(cg).shape == cg.shape assert _array2matrix(cg).shape == cg.shape def test_arrayexpr_convert_array_to_matrix_support_function(): assert _support_function_tp1_recognize([], [2 * k]) == 2 * k assert _support_function_tp1_recognize([(1, 2)], [A, 2 * k, B, 3]) == 6 * k * A * B assert _support_function_tp1_recognize([(0, 3), (1, 2)], [A, B]) == Trace(A * B) assert _support_function_tp1_recognize([(1, 2)], [A, B]) == A * B assert _support_function_tp1_recognize([(0, 2)], [A, B]) == A.T * B assert _support_function_tp1_recognize([(1, 3)], [A, B]) == A * B.T assert _support_function_tp1_recognize([(0, 3)], [A, B]) == A.T * B.T assert _support_function_tp1_recognize([(1, 2), (5, 6)], [A, B, C, D]) == ArrayTensorProduct(A * B, C * D) assert _support_function_tp1_recognize([(1, 4), (3, 6)], [A, B, C, D]) == PermuteDims( ArrayTensorProduct(A * C, B * D), [0, 2, 1, 3]) assert _support_function_tp1_recognize([(0, 3), (1, 4)], [A, B, C]) == B * A * C assert _support_function_tp1_recognize([(9, 10), (1, 2), (5, 6), (3, 4), (7, 8)], [X, Y, A, B, C, D]) == X * Y * A * B * C * D assert _support_function_tp1_recognize([(9, 10), (1, 2), (5, 6), (3, 4)], [X, Y, A, B, C, D]) == ArrayTensorProduct(X * Y * A * B, C * D) assert _support_function_tp1_recognize([(1, 7), (3, 8), (4, 11)], [X, Y, A, B, C, D]) == PermuteDims( ArrayTensorProduct(X * B.T, Y * C, A.T * D.T), [0, 2, 4, 1, 3, 5] ) assert _support_function_tp1_recognize([(0, 1), (3, 6), (5, 8)], [X, A, B, C, D]) == PermuteDims( ArrayTensorProduct(Trace(X) * A * C, B * D), [0, 2, 1, 3]) assert _support_function_tp1_recognize([(1, 2), (3, 4), (5, 6), (7, 8)], [A, A, B, C, D]) == A ** 2 * B * C * D assert _support_function_tp1_recognize([(1, 2), (3, 4), (5, 6), (7, 8)], [X, A, B, C, D]) == X * A * B * C * D assert _support_function_tp1_recognize([(1, 6), (3, 8), (5, 10)], [X, Y, A, B, C, D]) == PermuteDims( ArrayTensorProduct(X * B, Y * C, A * D), [0, 2, 4, 1, 3, 5] ) assert _support_function_tp1_recognize([(1, 4), (3, 6)], [A, B, C, D]) == PermuteDims( ArrayTensorProduct(A * C, B * D), [0, 2, 1, 3]) assert _support_function_tp1_recognize([(0, 4), (1, 7), (2, 5), (3, 8)], [X, A, B, C, D]) == C*X.T*B*A*D assert _support_function_tp1_recognize([(0, 4), (1, 7), (2, 5), (3, 8)], [X, A, B, C, D]) == C*X.T*B*A*D def test_convert_array_to_hadamard_products(): expr = HadamardProduct(M, N) cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert ret == expr expr = HadamardProduct(M, N)*P cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert ret == expr expr = Q*HadamardProduct(M, N)*P cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert ret == expr expr = Q*HadamardProduct(M, N.T)*P cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert ret == expr expr = HadamardProduct(M, N)*HadamardProduct(Q, P) cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert expr == ret expr = P.T*HadamardProduct(M, N)*HadamardProduct(Q, P) cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert expr == ret # ArrayDiagonal should be converted cg = ArrayDiagonal(ArrayTensorProduct(M, N, Q), (1, 3), (0, 2, 4)) ret = convert_array_to_matrix(cg) expected = PermuteDims(ArrayDiagonal(ArrayTensorProduct(HadamardProduct(M.T, N.T), Q), (1, 2)), [1, 0, 2]) assert expected == ret # Special case that should return the same expression: cg = ArrayDiagonal(ArrayTensorProduct(HadamardProduct(M, N), Q), (0, 2)) ret = convert_array_to_matrix(cg) assert ret == cg # Hadamard products with traces: expr = Trace(HadamardProduct(M, N)) cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert ret == Trace(HadamardProduct(M.T, N.T)) expr = Trace(A*HadamardProduct(M, N)) cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert ret == Trace(HadamardProduct(M, N)*A) expr = Trace(HadamardProduct(A, M)*N) cg = convert_matrix_to_array(expr) ret = convert_array_to_matrix(cg) assert ret == Trace(HadamardProduct(M.T, N)*A) # These should not be converted into Hadamard products: cg = ArrayDiagonal(ArrayTensorProduct(M, N), (0, 1, 2, 3)) ret = convert_array_to_matrix(cg) assert ret == cg cg = ArrayDiagonal(ArrayTensorProduct(A), (0, 1)) ret = convert_array_to_matrix(cg) assert ret == cg sympy-sympy-1.9/sympy/tensor/array/expressions/tests/test_convert_index_to_array.py000066400000000000000000000136531412543434000314500ustar00rootroot00000000000000from sympy import Sum, MatrixSymbol, Identity, symbols, IndexedBase, KroneckerDelta from sympy.combinatorics import Permutation from sympy.tensor.array.expressions.array_expressions import ArrayContraction, ArrayTensorProduct, \ ArrayDiagonal, ArrayAdd, PermuteDims from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix from sympy.tensor.array.expressions.conv_indexed_to_array import convert_indexed_to_array, _convert_indexed_to_array from sympy.testing.pytest import raises A, B = symbols("A B", cls=IndexedBase) i, j, k, l, m, n = symbols("i j k l m n") I = Identity(k) M = MatrixSymbol("M", k, k) N = MatrixSymbol("N", k, k) P = MatrixSymbol("P", k, k) Q = MatrixSymbol("Q", k, k) a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) c = MatrixSymbol("c", k, 1) d = MatrixSymbol("d", k, 1) def test_arrayexpr_convert_index_to_array_support_function(): expr = M[i, j] assert _convert_indexed_to_array(expr) == (M, (i, j)) expr = M[i, j]*N[k, l] assert _convert_indexed_to_array(expr) == (ArrayTensorProduct(M, N), (i, j, k, l)) expr = M[i, j]*N[j, k] assert _convert_indexed_to_array(expr) == (ArrayDiagonal(ArrayTensorProduct(M, N), (1, 2)), (i, k, j)) expr = Sum(M[i, j]*N[j, k], (j, 0, k-1)) assert _convert_indexed_to_array(expr) == (ArrayContraction(ArrayTensorProduct(M, N), (1, 2)), (i, k)) expr = M[i, j] + N[i, j] assert _convert_indexed_to_array(expr) == (ArrayAdd(M, N), (i, j)) expr = M[i, j] + N[j, i] assert _convert_indexed_to_array(expr) == (ArrayAdd(M, PermuteDims(N, Permutation([1, 0]))), (i, j)) expr = M[i, j] + M[j, i] assert _convert_indexed_to_array(expr) == (ArrayAdd(M, PermuteDims(M, Permutation([1, 0]))), (i, j)) expr = (M*N*P)[i, j] assert _convert_indexed_to_array(expr) == (ArrayContraction(ArrayTensorProduct(M, N, P), (1, 2), (3, 4)), (i, j)) expr = expr.function # Disregard summation in previous expression ret1, ret2 = _convert_indexed_to_array(expr) assert ret1 == ArrayDiagonal(ArrayTensorProduct(M, N, P), (1, 2), (3, 4)) assert str(ret2) == "(i, j, _i_1, _i_2)" expr = KroneckerDelta(i, j)*M[i, k] assert _convert_indexed_to_array(expr) == (M, ({i, j}, k)) expr = KroneckerDelta(i, j)*KroneckerDelta(j, k)*M[i, l] assert _convert_indexed_to_array(expr) == (M, ({i, j, k}, l)) expr = KroneckerDelta(j, k)*(M[i, j]*N[k, l] + N[i, j]*M[k, l]) assert _convert_indexed_to_array(expr) == (ArrayDiagonal(ArrayAdd( ArrayTensorProduct(M, N), PermuteDims(ArrayTensorProduct(M, N), Permutation(0, 2)(1, 3)) ), (1, 2)), (i, l, frozenset({j, k}))) expr = KroneckerDelta(j, m)*KroneckerDelta(m, k)*(M[i, j]*N[k, l] + N[i, j]*M[k, l]) assert _convert_indexed_to_array(expr) == (ArrayDiagonal(ArrayAdd( ArrayTensorProduct(M, N), PermuteDims(ArrayTensorProduct(M, N), Permutation(0, 2)(1, 3)) ), (1, 2)), (i, l, frozenset({j, m, k}))) expr = KroneckerDelta(i, j)*KroneckerDelta(j, k)*KroneckerDelta(k,m)*M[i, 0]*KroneckerDelta(m, n) assert _convert_indexed_to_array(expr) == (M, ({i, j, k, m, n}, 0)) expr = M[i, i] assert _convert_indexed_to_array(expr) == (ArrayDiagonal(M, (0, 1)), (i,)) def test_arrayexpr_convert_indexed_to_array_expression(): s = Sum(A[i]*B[i], (i, 0, 3)) cg = convert_indexed_to_array(s) assert cg == ArrayContraction(ArrayTensorProduct(A, B), (0, 1)) expr = M*N result = ArrayContraction(ArrayTensorProduct(M, N), (1, 2)) elem = expr[i, j] assert convert_indexed_to_array(elem) == result expr = M*N*M elem = expr[i, j] result = ArrayContraction(ArrayTensorProduct(M, M, N), (1, 4), (2, 5)) cg = convert_indexed_to_array(elem) assert cg == result cg = convert_indexed_to_array((M * N * P)[i, j]) assert cg == ArrayContraction(ArrayTensorProduct(M, N, P), (1, 2), (3, 4)) cg = convert_indexed_to_array((M * N.T * P)[i, j]) assert cg == ArrayContraction(ArrayTensorProduct(M, N, P), (1, 3), (2, 4)) expr = -2*M*N elem = expr[i, j] cg = convert_indexed_to_array(elem) assert cg == ArrayContraction(ArrayTensorProduct(-2, M, N), (1, 2)) def test_arrayexpr_convert_indexed_to_array_and_back_to_matrix(): expr = a.T*b elem = expr[0, 0] cg = convert_indexed_to_array(elem) assert cg == ArrayContraction(ArrayTensorProduct(a, b), (0, 2)) expr = M[i,j] + N[i,j] p1, p2 = _convert_indexed_to_array(expr) assert convert_array_to_matrix(p1) == M + N expr = M[i,j] + N[j,i] p1, p2 = _convert_indexed_to_array(expr) assert convert_array_to_matrix(p1) == M + N.T expr = M[i,j]*N[k,l] + N[i,j]*M[k,l] p1, p2 = _convert_indexed_to_array(expr) assert convert_array_to_matrix(p1) == ArrayAdd( ArrayTensorProduct(M, N), ArrayTensorProduct(N, M)) expr = (M*N*P)[i, j] p1, p2 = _convert_indexed_to_array(expr) assert convert_array_to_matrix(p1) == M * N * P expr = Sum(M[i,j]*(N*P)[j,m], (j, 0, k-1)) p1, p2 = _convert_indexed_to_array(expr) assert convert_array_to_matrix(p1) == M * N * P expr = Sum((P[j, m] + P[m, j])*(M[i,j]*N[m,n] + N[i,j]*M[m,n]), (j, 0, k-1), (m, 0, k-1)) p1, p2 = _convert_indexed_to_array(expr) assert convert_array_to_matrix(p1) == M * P * N + M * P.T * N + N * P * M + N * P.T * M def test_arrayexpr_convert_indexed_to_array_out_of_bounds(): expr = Sum(M[i, i], (i, 0, 4)) raises(ValueError, lambda: convert_indexed_to_array(expr)) expr = Sum(M[i, i], (i, 0, k)) raises(ValueError, lambda: convert_indexed_to_array(expr)) expr = Sum(M[i, i], (i, 1, k-1)) raises(ValueError, lambda: convert_indexed_to_array(expr)) expr = Sum(M[i, j]*N[j,m], (j, 0, 4)) raises(ValueError, lambda: convert_indexed_to_array(expr)) expr = Sum(M[i, j]*N[j,m], (j, 0, k)) raises(ValueError, lambda: convert_indexed_to_array(expr)) expr = Sum(M[i, j]*N[j,m], (j, 1, k-1)) raises(ValueError, lambda: convert_indexed_to_array(expr)) sympy-sympy-1.9/sympy/tensor/array/expressions/tests/test_convert_matrix_to_array.py000066400000000000000000000070131412543434000316360ustar00rootroot00000000000000from sympy import MatrixSymbol, Transpose, Inverse, Trace, HadamardProduct, HadamardPower, MatPow, symbols, Identity from sympy.tensor.array.expressions.array_expressions import ArrayTensorProduct, ArrayContraction, \ PermuteDims, ArrayDiagonal from sympy.tensor.array.expressions.conv_array_to_matrix import convert_array_to_matrix from sympy.tensor.array.expressions.conv_matrix_to_array import convert_matrix_to_array i, j, k, l, m, n = symbols("i j k l m n") I = Identity(k) M = MatrixSymbol("M", k, k) N = MatrixSymbol("N", k, k) P = MatrixSymbol("P", k, k) Q = MatrixSymbol("Q", k, k) A = MatrixSymbol("A", k, k) B = MatrixSymbol("B", k, k) C = MatrixSymbol("C", k, k) D = MatrixSymbol("D", k, k) X = MatrixSymbol("X", k, k) Y = MatrixSymbol("Y", k, k) a = MatrixSymbol("a", k, 1) b = MatrixSymbol("b", k, 1) c = MatrixSymbol("c", k, 1) d = MatrixSymbol("d", k, 1) def test_arrayexpr_convert_matrix_to_array(): expr = M*N result = ArrayContraction(ArrayTensorProduct(M, N), (1, 2)) assert convert_matrix_to_array(expr) == result expr = M*N*M result = ArrayContraction(ArrayTensorProduct(M, N, M), (1, 2), (3, 4)) assert convert_matrix_to_array(expr) == result expr = Transpose(M) assert convert_matrix_to_array(expr) == PermuteDims(M, [1, 0]) expr = M*Transpose(N) assert convert_matrix_to_array(expr) == ArrayContraction(ArrayTensorProduct(M, PermuteDims(N, [1, 0])), (1, 2)) expr = 3*M*N res = convert_matrix_to_array(expr) rexpr = convert_array_to_matrix(res) assert expr == rexpr expr = 3*M + N*M.T*M + 4*k*N res = convert_matrix_to_array(expr) rexpr = convert_array_to_matrix(res) assert expr == rexpr expr = Inverse(M)*N rexpr = convert_array_to_matrix(convert_matrix_to_array(expr)) assert expr == rexpr expr = M**2 rexpr = convert_array_to_matrix(convert_matrix_to_array(expr)) assert expr == rexpr expr = M*(2*N + 3*M) res = convert_matrix_to_array(expr) rexpr = convert_array_to_matrix(res) assert expr == rexpr expr = Trace(M) result = ArrayContraction(M, (0, 1)) assert convert_matrix_to_array(expr) == result expr = 3*Trace(M) result = ArrayContraction(ArrayTensorProduct(3, M), (0, 1)) assert convert_matrix_to_array(expr) == result expr = 3*Trace(Trace(M) * M) result = ArrayContraction(ArrayTensorProduct(3, M, M), (0, 1), (2, 3)) assert convert_matrix_to_array(expr) == result expr = 3*Trace(M)**2 result = ArrayContraction(ArrayTensorProduct(3, M, M), (0, 1), (2, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardProduct(M, N) result = ArrayDiagonal(ArrayTensorProduct(M, N), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardProduct(M*N, N*M) result = ArrayDiagonal(ArrayContraction(ArrayTensorProduct(M, N, N, M), (1, 2), (5, 6)), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardPower(M, 2) result = ArrayDiagonal(ArrayTensorProduct(M, M), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = HadamardPower(M*N, 2) result = ArrayDiagonal(ArrayContraction(ArrayTensorProduct(M, N, M, N), (1, 2), (5, 6)), (0, 2), (1, 3)) assert convert_matrix_to_array(expr) == result expr = M**2 assert isinstance(expr, MatPow) assert convert_matrix_to_array(expr) == ArrayContraction(ArrayTensorProduct(M, M), (1, 2)) expr = a.T*b cg = convert_matrix_to_array(expr) assert cg == ArrayContraction(ArrayTensorProduct(a, b), (0, 2)) sympy-sympy-1.9/sympy/tensor/array/expressions/utils.py000066400000000000000000000067601412543434000236410ustar00rootroot00000000000000import bisect from collections import defaultdict from sympy import Tuple, Integer def _get_mapping_from_subranks(subranks): mapping = {} counter = 0 for i, rank in enumerate(subranks): for j in range(rank): mapping[counter] = (i, j) counter += 1 return mapping def _get_contraction_links(args, subranks, *contraction_indices): mapping = _get_mapping_from_subranks(subranks) contraction_tuples = [[mapping[j] for j in i] for i in contraction_indices] dlinks = defaultdict(dict) for links in contraction_tuples: if len(links) == 2: (arg1, pos1), (arg2, pos2) = links dlinks[arg1][pos1] = (arg2, pos2) dlinks[arg2][pos2] = (arg1, pos1) continue return args, dict(dlinks) def _sort_contraction_indices(pairing_indices): pairing_indices = [Tuple(*sorted(i)) for i in pairing_indices] pairing_indices.sort(key=lambda x: min(x)) return pairing_indices def _get_diagonal_indices(flattened_indices): axes_contraction = defaultdict(list) for i, ind in enumerate(flattened_indices): if isinstance(ind, (int, Integer)): # If the indices is a number, there can be no diagonal operation: continue axes_contraction[ind].append(i) axes_contraction = {k: v for k, v in axes_contraction.items() if len(v) > 1} # Put the diagonalized indices at the end: ret_indices = [i for i in flattened_indices if i not in axes_contraction] diag_indices = list(axes_contraction) diag_indices.sort(key=lambda x: flattened_indices.index(x)) diagonal_indices = [tuple(axes_contraction[i]) for i in diag_indices] ret_indices += diag_indices ret_indices = tuple(ret_indices) return diagonal_indices, ret_indices def _get_argindex(subindices, ind): for i, sind in enumerate(subindices): if ind == sind: return i if isinstance(sind, (set, frozenset)) and ind in sind: return i raise IndexError("%s not found in %s" % (ind, subindices)) def _apply_recursively_over_nested_lists(func, arr): if isinstance(arr, (tuple, list, Tuple)): return tuple(_apply_recursively_over_nested_lists(func, i) for i in arr) elif isinstance(arr, Tuple): return Tuple.fromiter(_apply_recursively_over_nested_lists(func, i) for i in arr) else: return func(arr) def _build_push_indices_up_func_transformation(flattened_contraction_indices): shifts = {0: 0} i = 0 cumulative = 0 while i < len(flattened_contraction_indices): j = 1 while i+j < len(flattened_contraction_indices): if flattened_contraction_indices[i] + j != flattened_contraction_indices[i+j]: break j += 1 cumulative += j shifts[flattened_contraction_indices[i]] = cumulative i += j shift_keys = sorted(shifts.keys()) def func(idx): return shifts[shift_keys[bisect.bisect_right(shift_keys, idx)-1]] def transform(j): if j in flattened_contraction_indices: return None else: return j - func(j) return transform def _build_push_indices_down_func_transformation(flattened_contraction_indices): N = flattened_contraction_indices[-1]+2 shifts = [i for i in range(N) if i not in flattened_contraction_indices] def transform(j): if j < len(shifts): return shifts[j] else: return j + shifts[-1] - len(shifts) + 1 return transform sympy-sympy-1.9/sympy/tensor/array/mutable_ndim_array.py000066400000000000000000000004251412543434000237450ustar00rootroot00000000000000from sympy.tensor.array.ndim_array import NDimArray class MutableNDimArray(NDimArray): def as_immutable(self): raise NotImplementedError("abstract method") def as_mutable(self): return self def _sympy_(self): return self.as_immutable() sympy-sympy-1.9/sympy/tensor/array/ndim_array.py000066400000000000000000000444751412543434000222510ustar00rootroot00000000000000from sympy import Basic from sympy import S from sympy.core.expr import Expr from sympy.core.numbers import Integer from sympy.core.sympify import sympify from sympy.core.kind import Kind, NumberKind, UndefinedKind from sympy.core.compatibility import SYMPY_INTS from sympy.printing.defaults import Printable import itertools from collections.abc import Iterable class ArrayKind(Kind): """ Kind for N-dimensional array in SymPy. This kind represents the multidimensional array that algebraic operations are defined. Basic class for this kind is ``NDimArray``, but any expression representing the array can have this. Parameters ========== element_kind : Kind Kind of the element. Default is :obj:NumberKind ``, which means that the array contains only numbers. Examples ======== Any instance of array class has ``ArrayKind``. >>> from sympy import NDimArray >>> NDimArray([1,2,3]).kind ArrayKind(NumberKind) Although expressions representing an array may be not instance of array class, it will have ``ArrayKind`` as well. >>> from sympy import Integral >>> from sympy.tensor.array import NDimArray >>> from sympy.abc import x >>> intA = Integral(NDimArray([1,2,3]), x) >>> isinstance(intA, NDimArray) False >>> intA.kind ArrayKind(NumberKind) Use ``isinstance()`` to check for ``ArrayKind` without specifying the element kind. Use ``is`` with specifying the element kind. >>> from sympy.tensor.array import ArrayKind >>> from sympy.core.kind import NumberKind >>> boolA = NDimArray([True, False]) >>> isinstance(boolA.kind, ArrayKind) True >>> boolA.kind is ArrayKind(NumberKind) False See Also ======== shape : Function to return the shape of objects with ``MatrixKind``. """ def __new__(cls, element_kind=NumberKind): obj = super().__new__(cls, element_kind) obj.element_kind = element_kind return obj def __repr__(self): return "ArrayKind(%s)" % self.element_kind class NDimArray(Printable): """ Examples ======== Create an N-dim array of zeros: >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(2, 3, 4) >>> a [[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]] Create an N-dim array from a list; >>> a = MutableDenseNDimArray([[2, 3], [4, 5]]) >>> a [[2, 3], [4, 5]] >>> b = MutableDenseNDimArray([[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]]) >>> b [[[1, 2], [3, 4], [5, 6]], [[7, 8], [9, 10], [11, 12]]] Create an N-dim array from a flat list with dimension shape: >>> a = MutableDenseNDimArray([1, 2, 3, 4, 5, 6], (2, 3)) >>> a [[1, 2, 3], [4, 5, 6]] Create an N-dim array from a matrix: >>> from sympy import Matrix >>> a = Matrix([[1,2],[3,4]]) >>> a Matrix([ [1, 2], [3, 4]]) >>> b = MutableDenseNDimArray(a) >>> b [[1, 2], [3, 4]] Arithmetic operations on N-dim arrays >>> a = MutableDenseNDimArray([1, 1, 1, 1], (2, 2)) >>> b = MutableDenseNDimArray([4, 4, 4, 4], (2, 2)) >>> c = a + b >>> c [[5, 5], [5, 5]] >>> a - b [[-3, -3], [-3, -3]] """ _diff_wrt = True is_scalar = False def __new__(cls, iterable, shape=None, **kwargs): from sympy.tensor.array import ImmutableDenseNDimArray return ImmutableDenseNDimArray(iterable, shape, **kwargs) @property def kind(self): elem_kinds = set(e.kind for e in self._array) if len(elem_kinds) == 1: elemkind, = elem_kinds else: elemkind = UndefinedKind return ArrayKind(elemkind) def _parse_index(self, index): if isinstance(index, (SYMPY_INTS, Integer)): raise ValueError("Only a tuple index is accepted") if self._loop_size == 0: raise ValueError("Index not valide with an empty array") if len(index) != self._rank: raise ValueError('Wrong number of array axes') real_index = 0 # check if input index can exist in current indexing for i in range(self._rank): if (index[i] >= self.shape[i]) or (index[i] < -self.shape[i]): raise ValueError('Index ' + str(index) + ' out of border') if index[i] < 0: real_index += 1 real_index = real_index*self.shape[i] + index[i] return real_index def _get_tuple_index(self, integer_index): index = [] for i, sh in enumerate(reversed(self.shape)): index.append(integer_index % sh) integer_index //= sh index.reverse() return tuple(index) def _check_symbolic_index(self, index): # Check if any index is symbolic: tuple_index = (index if isinstance(index, tuple) else (index,)) if any([(isinstance(i, Expr) and (not i.is_number)) for i in tuple_index]): for i, nth_dim in zip(tuple_index, self.shape): if ((i < 0) == True) or ((i >= nth_dim) == True): raise ValueError("index out of range") from sympy.tensor import Indexed return Indexed(self, *tuple_index) return None def _setter_iterable_check(self, value): from sympy.matrices.matrices import MatrixBase if isinstance(value, (Iterable, MatrixBase, NDimArray)): raise NotImplementedError @classmethod def _scan_iterable_shape(cls, iterable): def f(pointer): if not isinstance(pointer, Iterable): return [pointer], () result = [] elems, shapes = zip(*[f(i) for i in pointer]) if len(set(shapes)) != 1: raise ValueError("could not determine shape unambiguously") for i in elems: result.extend(i) return result, (len(shapes),)+shapes[0] return f(iterable) @classmethod def _handle_ndarray_creation_inputs(cls, iterable=None, shape=None, **kwargs): from sympy.matrices.matrices import MatrixBase from sympy.tensor.array import SparseNDimArray from sympy import Dict, Tuple if shape is None: if iterable is None: shape = () iterable = () # Construction of a sparse array from a sparse array elif isinstance(iterable, SparseNDimArray): return iterable._shape, iterable._sparse_array # Construct N-dim array from another N-dim array: elif isinstance(iterable, NDimArray): shape = iterable.shape # Construct N-dim array from an iterable (numpy arrays included): elif isinstance(iterable, Iterable): iterable, shape = cls._scan_iterable_shape(iterable) # Construct N-dim array from a Matrix: elif isinstance(iterable, MatrixBase): shape = iterable.shape else: shape = () iterable = (iterable,) if isinstance(iterable, (Dict, dict)) and shape is not None: new_dict = iterable.copy() for k, v in new_dict.items(): if isinstance(k, (tuple, Tuple)): new_key = 0 for i, idx in enumerate(k): new_key = new_key * shape[i] + idx iterable[new_key] = iterable[k] del iterable[k] if isinstance(shape, (SYMPY_INTS, Integer)): shape = (shape,) if any([not isinstance(dim, (SYMPY_INTS, Integer)) for dim in shape]): raise TypeError("Shape should contain integers only.") return tuple(shape), iterable def __len__(self): """Overload common function len(). Returns number of elements in array. Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(3, 3) >>> a [[0, 0, 0], [0, 0, 0], [0, 0, 0]] >>> len(a) 9 """ return self._loop_size @property def shape(self): """ Returns array shape (dimension). Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(3, 3) >>> a.shape (3, 3) """ return self._shape def rank(self): """ Returns rank of array. Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(3,4,5,6,3) >>> a.rank() 5 """ return self._rank def diff(self, *args, **kwargs): """ Calculate the derivative of each element in the array. Examples ======== >>> from sympy import ImmutableDenseNDimArray >>> from sympy.abc import x, y >>> M = ImmutableDenseNDimArray([[x, y], [1, x*y]]) >>> M.diff(x) [[1, 0], [0, y]] """ from sympy.tensor.array.array_derivatives import ArrayDerivative kwargs.setdefault('evaluate', True) return ArrayDerivative(self.as_immutable(), *args, **kwargs) def _eval_derivative(self, base): # Types are (base: scalar, self: array) return self.applyfunc(lambda x: base.diff(x)) def _eval_derivative_n_times(self, s, n): return Basic._eval_derivative_n_times(self, s, n) def applyfunc(self, f): """Apply a function to each element of the N-dim array. Examples ======== >>> from sympy import ImmutableDenseNDimArray >>> m = ImmutableDenseNDimArray([i*2+j for i in range(2) for j in range(2)], (2, 2)) >>> m [[0, 1], [2, 3]] >>> m.applyfunc(lambda i: 2*i) [[0, 2], [4, 6]] """ from sympy.tensor.array import SparseNDimArray from sympy.tensor.array.arrayop import Flatten if isinstance(self, SparseNDimArray) and f(S.Zero) == 0: return type(self)({k: f(v) for k, v in self._sparse_array.items() if f(v) != 0}, self.shape) return type(self)(map(f, Flatten(self)), self.shape) def _sympystr(self, printer): def f(sh, shape_left, i, j): if len(shape_left) == 1: return "["+", ".join([printer._print(self[self._get_tuple_index(e)]) for e in range(i, j)])+"]" sh //= shape_left[0] return "[" + ", ".join([f(sh, shape_left[1:], i+e*sh, i+(e+1)*sh) for e in range(shape_left[0])]) + "]" # + "\n"*len(shape_left) if self.rank() == 0: return printer._print(self[()]) return f(self._loop_size, self.shape, 0, self._loop_size) def tolist(self): """ Converting MutableDenseNDimArray to one-dim list Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray([1, 2, 3, 4], (2, 2)) >>> a [[1, 2], [3, 4]] >>> b = a.tolist() >>> b [[1, 2], [3, 4]] """ def f(sh, shape_left, i, j): if len(shape_left) == 1: return [self[self._get_tuple_index(e)] for e in range(i, j)] result = [] sh //= shape_left[0] for e in range(shape_left[0]): result.append(f(sh, shape_left[1:], i+e*sh, i+(e+1)*sh)) return result return f(self._loop_size, self.shape, 0, self._loop_size) def __add__(self, other): from sympy.tensor.array.arrayop import Flatten if not isinstance(other, NDimArray): return NotImplemented if self.shape != other.shape: raise ValueError("array shape mismatch") result_list = [i+j for i,j in zip(Flatten(self), Flatten(other))] return type(self)(result_list, self.shape) def __sub__(self, other): from sympy.tensor.array.arrayop import Flatten if not isinstance(other, NDimArray): return NotImplemented if self.shape != other.shape: raise ValueError("array shape mismatch") result_list = [i-j for i,j in zip(Flatten(self), Flatten(other))] return type(self)(result_list, self.shape) def __mul__(self, other): from sympy.matrices.matrices import MatrixBase from sympy.tensor.array import SparseNDimArray from sympy.tensor.array.arrayop import Flatten if isinstance(other, (Iterable, NDimArray, MatrixBase)): raise ValueError("scalar expected, use tensorproduct(...) for tensorial product") other = sympify(other) if isinstance(self, SparseNDimArray): if other.is_zero: return type(self)({}, self.shape) return type(self)({k: other*v for (k, v) in self._sparse_array.items()}, self.shape) result_list = [i*other for i in Flatten(self)] return type(self)(result_list, self.shape) def __rmul__(self, other): from sympy.matrices.matrices import MatrixBase from sympy.tensor.array import SparseNDimArray from sympy.tensor.array.arrayop import Flatten if isinstance(other, (Iterable, NDimArray, MatrixBase)): raise ValueError("scalar expected, use tensorproduct(...) for tensorial product") other = sympify(other) if isinstance(self, SparseNDimArray): if other.is_zero: return type(self)({}, self.shape) return type(self)({k: other*v for (k, v) in self._sparse_array.items()}, self.shape) result_list = [other*i for i in Flatten(self)] return type(self)(result_list, self.shape) def __truediv__(self, other): from sympy.matrices.matrices import MatrixBase from sympy.tensor.array import SparseNDimArray from sympy.tensor.array.arrayop import Flatten if isinstance(other, (Iterable, NDimArray, MatrixBase)): raise ValueError("scalar expected") other = sympify(other) if isinstance(self, SparseNDimArray) and other != S.Zero: return type(self)({k: v/other for (k, v) in self._sparse_array.items()}, self.shape) result_list = [i/other for i in Flatten(self)] return type(self)(result_list, self.shape) def __rtruediv__(self, other): raise NotImplementedError('unsupported operation on NDimArray') def __neg__(self): from sympy.tensor.array import SparseNDimArray from sympy.tensor.array.arrayop import Flatten if isinstance(self, SparseNDimArray): return type(self)({k: -v for (k, v) in self._sparse_array.items()}, self.shape) result_list = [-i for i in Flatten(self)] return type(self)(result_list, self.shape) def __iter__(self): def iterator(): if self._shape: for i in range(self._shape[0]): yield self[i] else: yield self[()] return iterator() def __eq__(self, other): """ NDimArray instances can be compared to each other. Instances equal if they have same shape and data. Examples ======== >>> from sympy import MutableDenseNDimArray >>> a = MutableDenseNDimArray.zeros(2, 3) >>> b = MutableDenseNDimArray.zeros(2, 3) >>> a == b True >>> c = a.reshape(3, 2) >>> c == b False >>> a[0,0] = 1 >>> b[0,0] = 2 >>> a == b False """ from sympy.tensor.array import SparseNDimArray if not isinstance(other, NDimArray): return False if not self.shape == other.shape: return False if isinstance(self, SparseNDimArray) and isinstance(other, SparseNDimArray): return dict(self._sparse_array) == dict(other._sparse_array) return list(self) == list(other) def __ne__(self, other): return not self == other def _eval_transpose(self): if self.rank() != 2: raise ValueError("array rank not 2") from .arrayop import permutedims return permutedims(self, (1, 0)) def transpose(self): return self._eval_transpose() def _eval_conjugate(self): from sympy.tensor.array.arrayop import Flatten return self.func([i.conjugate() for i in Flatten(self)], self.shape) def conjugate(self): return self._eval_conjugate() def _eval_adjoint(self): return self.transpose().conjugate() def adjoint(self): return self._eval_adjoint() def _slice_expand(self, s, dim): if not isinstance(s, slice): return (s,) start, stop, step = s.indices(dim) return [start + i*step for i in range((stop-start)//step)] def _get_slice_data_for_array_access(self, index): sl_factors = [self._slice_expand(i, dim) for (i, dim) in zip(index, self.shape)] eindices = itertools.product(*sl_factors) return sl_factors, eindices def _get_slice_data_for_array_assignment(self, index, value): if not isinstance(value, NDimArray): value = type(self)(value) sl_factors, eindices = self._get_slice_data_for_array_access(index) slice_offsets = [min(i) if isinstance(i, list) else None for i in sl_factors] # TODO: add checks for dimensions for `value`? return value, eindices, slice_offsets @classmethod def _check_special_bounds(cls, flat_list, shape): if shape == () and len(flat_list) != 1: raise ValueError("arrays without shape need one scalar value") if shape == (0,) and len(flat_list) > 0: raise ValueError("if array shape is (0,) there cannot be elements") def _check_index_for_getitem(self, index): if isinstance(index, (SYMPY_INTS, Integer, slice)): index = (index, ) if len(index) < self.rank(): index = tuple([i for i in index] + \ [slice(None) for i in range(len(index), self.rank())]) if len(index) > self.rank(): raise ValueError('Dimension of index greater than rank of array') return index class ImmutableNDimArray(NDimArray, Basic): _op_priority = 11.0 def __hash__(self): return Basic.__hash__(self) def as_immutable(self): return self def as_mutable(self): raise NotImplementedError("abstract method") sympy-sympy-1.9/sympy/tensor/array/sparse_ndim_array.py000066400000000000000000000143321412543434000236130ustar00rootroot00000000000000from sympy import S, Dict, Basic, Tuple from sympy.core.sympify import _sympify from sympy.tensor.array.mutable_ndim_array import MutableNDimArray from sympy.tensor.array.ndim_array import NDimArray, ImmutableNDimArray import functools class SparseNDimArray(NDimArray): def __new__(self, *args, **kwargs): return ImmutableSparseNDimArray(*args, **kwargs) def __getitem__(self, index): """ Get an element from a sparse N-dim array. Examples ======== >>> from sympy import MutableSparseNDimArray >>> a = MutableSparseNDimArray(range(4), (2, 2)) >>> a [[0, 1], [2, 3]] >>> a[0, 0] 0 >>> a[1, 1] 3 >>> a[0] [0, 1] >>> a[1] [2, 3] Symbolic indexing: >>> from sympy.abc import i, j >>> a[i, j] [[0, 1], [2, 3]][i, j] Replace `i` and `j` to get element `(0, 0)`: >>> a[i, j].subs({i: 0, j: 0}) 0 """ syindex = self._check_symbolic_index(index) if syindex is not None: return syindex index = self._check_index_for_getitem(index) # `index` is a tuple with one or more slices: if isinstance(index, tuple) and any([isinstance(i, slice) for i in index]): sl_factors, eindices = self._get_slice_data_for_array_access(index) array = [self._sparse_array.get(self._parse_index(i), S.Zero) for i in eindices] nshape = [len(el) for i, el in enumerate(sl_factors) if isinstance(index[i], slice)] return type(self)(array, nshape) else: index = self._parse_index(index) return self._sparse_array.get(index, S.Zero) @classmethod def zeros(cls, *shape): """ Return a sparse N-dim array of zeros. """ return cls({}, shape) def tomatrix(self): """ Converts MutableDenseNDimArray to Matrix. Can convert only 2-dim array, else will raise error. Examples ======== >>> from sympy import MutableSparseNDimArray >>> a = MutableSparseNDimArray([1 for i in range(9)], (3, 3)) >>> b = a.tomatrix() >>> b Matrix([ [1, 1, 1], [1, 1, 1], [1, 1, 1]]) """ from sympy.matrices import SparseMatrix if self.rank() != 2: raise ValueError('Dimensions must be of size of 2') mat_sparse = {} for key, value in self._sparse_array.items(): mat_sparse[self._get_tuple_index(key)] = value return SparseMatrix(self.shape[0], self.shape[1], mat_sparse) def reshape(self, *newshape): new_total_size = functools.reduce(lambda x,y: x*y, newshape) if new_total_size != self._loop_size: raise ValueError("Invalid reshape parameters " + newshape) return type(self)(self._sparse_array, newshape) class ImmutableSparseNDimArray(SparseNDimArray, ImmutableNDimArray): def __new__(cls, iterable=None, shape=None, **kwargs): from sympy.utilities.iterables import flatten shape, flat_list = cls._handle_ndarray_creation_inputs(iterable, shape, **kwargs) shape = Tuple(*map(_sympify, shape)) cls._check_special_bounds(flat_list, shape) loop_size = functools.reduce(lambda x,y: x*y, shape) if shape else len(flat_list) # Sparse array: if isinstance(flat_list, (dict, Dict)): sparse_array = Dict(flat_list) else: sparse_array = {} for i, el in enumerate(flatten(flat_list)): if el != 0: sparse_array[i] = _sympify(el) sparse_array = Dict(sparse_array) self = Basic.__new__(cls, sparse_array, shape, **kwargs) self._shape = shape self._rank = len(shape) self._loop_size = loop_size self._sparse_array = sparse_array return self def __setitem__(self, index, value): raise TypeError("immutable N-dim array") def as_mutable(self): return MutableSparseNDimArray(self) class MutableSparseNDimArray(MutableNDimArray, SparseNDimArray): def __new__(cls, iterable=None, shape=None, **kwargs): from sympy.utilities.iterables import flatten shape, flat_list = cls._handle_ndarray_creation_inputs(iterable, shape, **kwargs) self = object.__new__(cls) self._shape = shape self._rank = len(shape) self._loop_size = functools.reduce(lambda x,y: x*y, shape) if shape else len(flat_list) # Sparse array: if isinstance(flat_list, (dict, Dict)): self._sparse_array = dict(flat_list) return self self._sparse_array = {} for i, el in enumerate(flatten(flat_list)): if el != 0: self._sparse_array[i] = _sympify(el) return self def __setitem__(self, index, value): """Allows to set items to MutableDenseNDimArray. Examples ======== >>> from sympy import MutableSparseNDimArray >>> a = MutableSparseNDimArray.zeros(2, 2) >>> a[0, 0] = 1 >>> a[1, 1] = 1 >>> a [[1, 0], [0, 1]] """ if isinstance(index, tuple) and any([isinstance(i, slice) for i in index]): value, eindices, slice_offsets = self._get_slice_data_for_array_assignment(index, value) for i in eindices: other_i = [ind - j for ind, j in zip(i, slice_offsets) if j is not None] other_value = value[other_i] complete_index = self._parse_index(i) if other_value != 0: self._sparse_array[complete_index] = other_value elif complete_index in self._sparse_array: self._sparse_array.pop(complete_index) else: index = self._parse_index(index) value = _sympify(value) if value == 0 and index in self._sparse_array: self._sparse_array.pop(index) else: self._sparse_array[index] = value def as_immutable(self): return ImmutableSparseNDimArray(self) @property def free_symbols(self): return {i for j in self._sparse_array.values() for i in j.free_symbols} sympy-sympy-1.9/sympy/tensor/array/tests/000077500000000000000000000000001412543434000206765ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/array/tests/__init__.py000066400000000000000000000000001412543434000227750ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/array/tests/test_array_comprehension.py000066400000000000000000000107641412543434000263660ustar00rootroot00000000000000from sympy.tensor.array.array_comprehension import ArrayComprehension, ArrayComprehensionMap from sympy.tensor.array import ImmutableDenseNDimArray from sympy.abc import i, j, k, l from sympy.testing.pytest import raises, warns_deprecated_sympy from sympy.matrices import Matrix def test_array_comprehension(): a = ArrayComprehension(i*j, (i, 1, 3), (j, 2, 4)) b = ArrayComprehension(i, (i, 1, j+1)) c = ArrayComprehension(i+j+k+l, (i, 1, 2), (j, 1, 3), (k, 1, 4), (l, 1, 5)) d = ArrayComprehension(k, (i, 1, 5)) e = ArrayComprehension(i, (j, k+1, k+5)) assert a.doit().tolist() == [[2, 3, 4], [4, 6, 8], [6, 9, 12]] assert a.shape == (3, 3) assert a.is_shape_numeric == True assert a.tolist() == [[2, 3, 4], [4, 6, 8], [6, 9, 12]] assert a.tomatrix() == Matrix([ [2, 3, 4], [4, 6, 8], [6, 9, 12]]) assert len(a) == 9 assert isinstance(b.doit(), ArrayComprehension) assert isinstance(a.doit(), ImmutableDenseNDimArray) assert b.subs(j, 3) == ArrayComprehension(i, (i, 1, 4)) assert b.free_symbols == {j} assert b.shape == (j + 1,) assert b.rank() == 1 assert b.is_shape_numeric == False assert c.free_symbols == set() assert c.function == i + j + k + l assert c.limits == ((i, 1, 2), (j, 1, 3), (k, 1, 4), (l, 1, 5)) assert c.doit().tolist() == [[[[4, 5, 6, 7, 8], [5, 6, 7, 8, 9], [6, 7, 8, 9, 10], [7, 8, 9, 10, 11]], [[5, 6, 7, 8, 9], [6, 7, 8, 9, 10], [7, 8, 9, 10, 11], [8, 9, 10, 11, 12]], [[6, 7, 8, 9, 10], [7, 8, 9, 10, 11], [8, 9, 10, 11, 12], [9, 10, 11, 12, 13]]], [[[5, 6, 7, 8, 9], [6, 7, 8, 9, 10], [7, 8, 9, 10, 11], [8, 9, 10, 11, 12]], [[6, 7, 8, 9, 10], [7, 8, 9, 10, 11], [8, 9, 10, 11, 12], [9, 10, 11, 12, 13]], [[7, 8, 9, 10, 11], [8, 9, 10, 11, 12], [9, 10, 11, 12, 13], [10, 11, 12, 13, 14]]]] assert c.free_symbols == set() assert c.variables == [i, j, k, l] assert c.bound_symbols == [i, j, k, l] assert d.doit().tolist() == [k, k, k, k, k] assert len(e) == 5 raises(TypeError, lambda: ArrayComprehension(i*j, (i, 1, 3), (j, 2, [1, 3, 2]))) raises(ValueError, lambda: ArrayComprehension(i*j, (i, 1, 3), (j, 2, 1))) raises(ValueError, lambda: ArrayComprehension(i*j, (i, 1, 3), (j, 2, j+1))) raises(ValueError, lambda: len(ArrayComprehension(i*j, (i, 1, 3), (j, 2, j+4)))) raises(TypeError, lambda: ArrayComprehension(i*j, (i, 0, i + 1.5), (j, 0, 2))) raises(ValueError, lambda: b.tolist()) raises(ValueError, lambda: b.tomatrix()) raises(ValueError, lambda: c.tomatrix()) def test_arraycomprehensionmap(): a = ArrayComprehensionMap(lambda i: i+1, (i, 1, 5)) assert a.doit().tolist() == [2, 3, 4, 5, 6] assert a.shape == (5,) assert a.is_shape_numeric assert a.tolist() == [2, 3, 4, 5, 6] assert len(a) == 5 assert isinstance(a.doit(), ImmutableDenseNDimArray) expr = ArrayComprehensionMap(lambda i: i+1, (i, 1, k)) assert expr.doit() == expr assert expr.subs(k, 4) == ArrayComprehensionMap(lambda i: i+1, (i, 1, 4)) assert expr.subs(k, 4).doit() == ImmutableDenseNDimArray([2, 3, 4, 5]) b = ArrayComprehensionMap(lambda i: i+1, (i, 1, 2), (i, 1, 3), (i, 1, 4), (i, 1, 5)) assert b.doit().tolist() == [[[[2, 3, 4, 5, 6], [3, 5, 7, 9, 11], [4, 7, 10, 13, 16], [5, 9, 13, 17, 21]], [[3, 5, 7, 9, 11], [5, 9, 13, 17, 21], [7, 13, 19, 25, 31], [9, 17, 25, 33, 41]], [[4, 7, 10, 13, 16], [7, 13, 19, 25, 31], [10, 19, 28, 37, 46], [13, 25, 37, 49, 61]]], [[[3, 5, 7, 9, 11], [5, 9, 13, 17, 21], [7, 13, 19, 25, 31], [9, 17, 25, 33, 41]], [[5, 9, 13, 17, 21], [9, 17, 25, 33, 41], [13, 25, 37, 49, 61], [17, 33, 49, 65, 81]], [[7, 13, 19, 25, 31], [13, 25, 37, 49, 61], [19, 37, 55, 73, 91], [25, 49, 73, 97, 121]]]] # tests about lambda expression assert ArrayComprehensionMap(lambda: 3, (i, 1, 5)).doit().tolist() == [3, 3, 3, 3, 3] assert ArrayComprehensionMap(lambda i: i+1, (i, 1, 5)).doit().tolist() == [2, 3, 4, 5, 6] raises(ValueError, lambda: ArrayComprehensionMap(i*j, (i, 1, 3), (j, 2, 4))) with warns_deprecated_sympy(): a = ArrayComprehensionMap(lambda i, j: i+j, (i, 1, 5)) raises(ValueError, lambda: a.doit()) sympy-sympy-1.9/sympy/tensor/array/tests/test_array_derivatives.py000066400000000000000000000027061412543434000260370ustar00rootroot00000000000000from sympy import Matrix, symbols, MatrixSymbol, NDimArray from sympy.matrices.common import MatrixCommon from sympy.tensor.array.array_derivatives import ArrayDerivative x, y, z, t = symbols("x y z t") m = Matrix([[x, y], [z, t]]) M = MatrixSymbol("M", 3, 2) N = MatrixSymbol("N", 4, 3) def test_array_derivative_construction(): d = ArrayDerivative(x, m, evaluate=False) assert d.shape == (2, 2) expr = d.doit() assert isinstance(expr, MatrixCommon) assert expr.shape == (2, 2) d = ArrayDerivative(m, m, evaluate=False) assert d.shape == (2, 2, 2, 2) expr = d.doit() assert isinstance(expr, NDimArray) assert expr.shape == (2, 2, 2, 2) d = ArrayDerivative(m, x, evaluate=False) assert d.shape == (2, 2) expr = d.doit() assert isinstance(expr, MatrixCommon) assert expr.shape == (2, 2) d = ArrayDerivative(M, N, evaluate=False) assert d.shape == (4, 3, 3, 2) expr = d.doit() assert isinstance(expr, ArrayDerivative) assert expr.shape == (4, 3, 3, 2) d = ArrayDerivative(M, (N, 2), evaluate=False) assert d.shape == (4, 3, 4, 3, 3, 2) expr = d.doit() assert isinstance(expr, ArrayDerivative) assert expr.shape == (4, 3, 4, 3, 3, 2) d = ArrayDerivative(M.as_explicit(), (N.as_explicit(), 2), evaluate=False) assert d.doit().shape == (4, 3, 4, 3, 3, 2) expr = d.doit() assert isinstance(expr, ArrayDerivative) assert expr.shape == (4, 3, 4, 3, 3, 2) sympy-sympy-1.9/sympy/tensor/array/tests/test_arrayop.py000066400000000000000000000573051412543434000237760ustar00rootroot00000000000000import random from sympy.combinatorics import Permutation from sympy.combinatorics.permutations import _af_invert from sympy.testing.pytest import raises from sympy import symbols, sin, exp, log, cos, transpose, adjoint, conjugate, diff from sympy.tensor.array import Array, ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableSparseNDimArray from sympy.tensor.array.arrayop import tensorproduct, tensorcontraction, derive_by_array, permutedims, Flatten, \ tensordiagonal def test_import_NDimArray(): from sympy.tensor.array import NDimArray del NDimArray def test_tensorproduct(): x,y,z,t = symbols('x y z t') from sympy.abc import a,b,c,d assert tensorproduct() == 1 assert tensorproduct([x]) == Array([x]) assert tensorproduct([x], [y]) == Array([[x*y]]) assert tensorproduct([x], [y], [z]) == Array([[[x*y*z]]]) assert tensorproduct([x], [y], [z], [t]) == Array([[[[x*y*z*t]]]]) assert tensorproduct(x) == x assert tensorproduct(x, y) == x*y assert tensorproduct(x, y, z) == x*y*z assert tensorproduct(x, y, z, t) == x*y*z*t for ArrayType in [ImmutableDenseNDimArray, ImmutableSparseNDimArray]: A = ArrayType([x, y]) B = ArrayType([1, 2, 3]) C = ArrayType([a, b, c, d]) assert tensorproduct(A, B, C) == ArrayType([[[a*x, b*x, c*x, d*x], [2*a*x, 2*b*x, 2*c*x, 2*d*x], [3*a*x, 3*b*x, 3*c*x, 3*d*x]], [[a*y, b*y, c*y, d*y], [2*a*y, 2*b*y, 2*c*y, 2*d*y], [3*a*y, 3*b*y, 3*c*y, 3*d*y]]]) assert tensorproduct([x, y], [1, 2, 3]) == tensorproduct(A, B) assert tensorproduct(A, 2) == ArrayType([2*x, 2*y]) assert tensorproduct(A, [2]) == ArrayType([[2*x], [2*y]]) assert tensorproduct([2], A) == ArrayType([[2*x, 2*y]]) assert tensorproduct(a, A) == ArrayType([a*x, a*y]) assert tensorproduct(a, A, B) == ArrayType([[a*x, 2*a*x, 3*a*x], [a*y, 2*a*y, 3*a*y]]) assert tensorproduct(A, B, a) == ArrayType([[a*x, 2*a*x, 3*a*x], [a*y, 2*a*y, 3*a*y]]) assert tensorproduct(B, a, A) == ArrayType([[a*x, a*y], [2*a*x, 2*a*y], [3*a*x, 3*a*y]]) # tests for large scale sparse array for SparseArrayType in [ImmutableSparseNDimArray, MutableSparseNDimArray]: a = SparseArrayType({1:2, 3:4},(1000, 2000)) b = SparseArrayType({1:2, 3:4},(1000, 2000)) assert tensorproduct(a, b) == ImmutableSparseNDimArray({2000001: 4, 2000003: 8, 6000001: 8, 6000003: 16}, (1000, 2000, 1000, 2000)) def test_tensorcontraction(): from sympy.abc import a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x B = Array(range(18), (2, 3, 3)) assert tensorcontraction(B, (1, 2)) == Array([12, 39]) C1 = Array([a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x], (2, 3, 2, 2)) assert tensorcontraction(C1, (0, 2)) == Array([[a + o, b + p], [e + s, f + t], [i + w, j + x]]) assert tensorcontraction(C1, (0, 2, 3)) == Array([a + p, e + t, i + x]) assert tensorcontraction(C1, (2, 3)) == Array([[a + d, e + h, i + l], [m + p, q + t, u + x]]) def test_derivative_by_array(): from sympy.abc import i, j, t, x, y, z bexpr = x*y**2*exp(z)*log(t) sexpr = sin(bexpr) cexpr = cos(bexpr) a = Array([sexpr]) assert derive_by_array(sexpr, t) == x*y**2*exp(z)*cos(x*y**2*exp(z)*log(t))/t assert derive_by_array(sexpr, [x, y, z]) == Array([bexpr/x*cexpr, 2*y*bexpr/y**2*cexpr, bexpr*cexpr]) assert derive_by_array(a, [x, y, z]) == Array([[bexpr/x*cexpr], [2*y*bexpr/y**2*cexpr], [bexpr*cexpr]]) assert derive_by_array(sexpr, [[x, y], [z, t]]) == Array([[bexpr/x*cexpr, 2*y*bexpr/y**2*cexpr], [bexpr*cexpr, bexpr/log(t)/t*cexpr]]) assert derive_by_array(a, [[x, y], [z, t]]) == Array([[[bexpr/x*cexpr], [2*y*bexpr/y**2*cexpr]], [[bexpr*cexpr], [bexpr/log(t)/t*cexpr]]]) assert derive_by_array([[x, y], [z, t]], [x, y]) == Array([[[1, 0], [0, 0]], [[0, 1], [0, 0]]]) assert derive_by_array([[x, y], [z, t]], [[x, y], [z, t]]) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]]) assert diff(sexpr, t) == x*y**2*exp(z)*cos(x*y**2*exp(z)*log(t))/t assert diff(sexpr, Array([x, y, z])) == Array([bexpr/x*cexpr, 2*y*bexpr/y**2*cexpr, bexpr*cexpr]) assert diff(a, Array([x, y, z])) == Array([[bexpr/x*cexpr], [2*y*bexpr/y**2*cexpr], [bexpr*cexpr]]) assert diff(sexpr, Array([[x, y], [z, t]])) == Array([[bexpr/x*cexpr, 2*y*bexpr/y**2*cexpr], [bexpr*cexpr, bexpr/log(t)/t*cexpr]]) assert diff(a, Array([[x, y], [z, t]])) == Array([[[bexpr/x*cexpr], [2*y*bexpr/y**2*cexpr]], [[bexpr*cexpr], [bexpr/log(t)/t*cexpr]]]) assert diff(Array([[x, y], [z, t]]), Array([x, y])) == Array([[[1, 0], [0, 0]], [[0, 1], [0, 0]]]) assert diff(Array([[x, y], [z, t]]), Array([[x, y], [z, t]])) == Array([[[[1, 0], [0, 0]], [[0, 1], [0, 0]]], [[[0, 0], [1, 0]], [[0, 0], [0, 1]]]]) # test for large scale sparse array for SparseArrayType in [ImmutableSparseNDimArray, MutableSparseNDimArray]: b = MutableSparseNDimArray({0:i, 1:j}, (10000, 20000)) assert derive_by_array(b, i) == ImmutableSparseNDimArray({0: 1}, (10000, 20000)) assert derive_by_array(b, (i, j)) == ImmutableSparseNDimArray({0: 1, 200000001: 1}, (2, 10000, 20000)) #https://github.com/sympy/sympy/issues/20655 U = Array([x, y, z]) E = 2 assert derive_by_array(E, U) == ImmutableDenseNDimArray([0, 0, 0]) def test_issue_emerged_while_discussing_10972(): ua = Array([-1,0]) Fa = Array([[0, 1], [-1, 0]]) po = tensorproduct(Fa, ua, Fa, ua) assert tensorcontraction(po, (1, 2), (4, 5)) == Array([[0, 0], [0, 1]]) sa = symbols('a0:144') po = Array(sa, [2, 2, 3, 3, 2, 2]) assert tensorcontraction(po, (0, 1), (2, 3), (4, 5)) == sa[0] + sa[108] + sa[111] + sa[124] + sa[127] + sa[140] + sa[143] + sa[16] + sa[19] + sa[3] + sa[32] + sa[35] assert tensorcontraction(po, (0, 1, 4, 5), (2, 3)) == sa[0] + sa[111] + sa[127] + sa[143] + sa[16] + sa[32] assert tensorcontraction(po, (0, 1), (4, 5)) == Array([[sa[0] + sa[108] + sa[111] + sa[3], sa[112] + sa[115] + sa[4] + sa[7], sa[11] + sa[116] + sa[119] + sa[8]], [sa[12] + sa[120] + sa[123] + sa[15], sa[124] + sa[127] + sa[16] + sa[19], sa[128] + sa[131] + sa[20] + sa[23]], [sa[132] + sa[135] + sa[24] + sa[27], sa[136] + sa[139] + sa[28] + sa[31], sa[140] + sa[143] + sa[32] + sa[35]]]) assert tensorcontraction(po, (0, 1), (2, 3)) == Array([[sa[0] + sa[108] + sa[124] + sa[140] + sa[16] + sa[32], sa[1] + sa[109] + sa[125] + sa[141] + sa[17] + sa[33]], [sa[110] + sa[126] + sa[142] + sa[18] + sa[2] + sa[34], sa[111] + sa[127] + sa[143] + sa[19] + sa[3] + sa[35]]]) def test_array_permutedims(): sa = symbols('a0:144') for ArrayType in [ImmutableDenseNDimArray, ImmutableSparseNDimArray]: m1 = ArrayType(sa[:6], (2, 3)) assert permutedims(m1, (1, 0)) == transpose(m1) assert m1.tomatrix().T == permutedims(m1, (1, 0)).tomatrix() assert m1.tomatrix().T == transpose(m1).tomatrix() assert m1.tomatrix().C == conjugate(m1).tomatrix() assert m1.tomatrix().H == adjoint(m1).tomatrix() assert m1.tomatrix().T == m1.transpose().tomatrix() assert m1.tomatrix().C == m1.conjugate().tomatrix() assert m1.tomatrix().H == m1.adjoint().tomatrix() raises(ValueError, lambda: permutedims(m1, (0,))) raises(ValueError, lambda: permutedims(m1, (0, 0))) raises(ValueError, lambda: permutedims(m1, (1, 2, 0))) # Some tests with random arrays: dims = 6 shape = [random.randint(1,5) for i in range(dims)] elems = [random.random() for i in range(tensorproduct(*shape))] ra = ArrayType(elems, shape) perm = list(range(dims)) # Randomize the permutation: random.shuffle(perm) # Test inverse permutation: assert permutedims(permutedims(ra, perm), _af_invert(perm)) == ra # Test that permuted shape corresponds to action by `Permutation`: assert permutedims(ra, perm).shape == tuple(Permutation(perm)(shape)) z = ArrayType.zeros(4,5,6,7) assert permutedims(z, (2, 3, 1, 0)).shape == (6, 7, 5, 4) assert permutedims(z, [2, 3, 1, 0]).shape == (6, 7, 5, 4) assert permutedims(z, Permutation([2, 3, 1, 0])).shape == (6, 7, 5, 4) po = ArrayType(sa, [2, 2, 3, 3, 2, 2]) raises(ValueError, lambda: permutedims(po, (1, 1))) raises(ValueError, lambda: po.transpose()) raises(ValueError, lambda: po.adjoint()) assert permutedims(po, reversed(range(po.rank()))) == ArrayType( [[[[[[sa[0], sa[72]], [sa[36], sa[108]]], [[sa[12], sa[84]], [sa[48], sa[120]]], [[sa[24], sa[96]], [sa[60], sa[132]]]], [[[sa[4], sa[76]], [sa[40], sa[112]]], [[sa[16], sa[88]], [sa[52], sa[124]]], [[sa[28], sa[100]], [sa[64], sa[136]]]], [[[sa[8], sa[80]], [sa[44], sa[116]]], [[sa[20], sa[92]], [sa[56], sa[128]]], [[sa[32], sa[104]], [sa[68], sa[140]]]]], [[[[sa[2], sa[74]], [sa[38], sa[110]]], [[sa[14], sa[86]], [sa[50], sa[122]]], [[sa[26], sa[98]], [sa[62], sa[134]]]], [[[sa[6], sa[78]], [sa[42], sa[114]]], [[sa[18], sa[90]], [sa[54], sa[126]]], [[sa[30], sa[102]], [sa[66], sa[138]]]], [[[sa[10], sa[82]], [sa[46], sa[118]]], [[sa[22], sa[94]], [sa[58], sa[130]]], [[sa[34], sa[106]], [sa[70], sa[142]]]]]], [[[[[sa[1], sa[73]], [sa[37], sa[109]]], [[sa[13], sa[85]], [sa[49], sa[121]]], [[sa[25], sa[97]], [sa[61], sa[133]]]], [[[sa[5], sa[77]], [sa[41], sa[113]]], [[sa[17], sa[89]], [sa[53], sa[125]]], [[sa[29], sa[101]], [sa[65], sa[137]]]], [[[sa[9], sa[81]], [sa[45], sa[117]]], [[sa[21], sa[93]], [sa[57], sa[129]]], [[sa[33], sa[105]], [sa[69], sa[141]]]]], [[[[sa[3], sa[75]], [sa[39], sa[111]]], [[sa[15], sa[87]], [sa[51], sa[123]]], [[sa[27], sa[99]], [sa[63], sa[135]]]], [[[sa[7], sa[79]], [sa[43], sa[115]]], [[sa[19], sa[91]], [sa[55], sa[127]]], [[sa[31], sa[103]], [sa[67], sa[139]]]], [[[sa[11], sa[83]], [sa[47], sa[119]]], [[sa[23], sa[95]], [sa[59], sa[131]]], [[sa[35], sa[107]], [sa[71], sa[143]]]]]]]) assert permutedims(po, (1, 0, 2, 3, 4, 5)) == ArrayType( [[[[[[sa[0], sa[1]], [sa[2], sa[3]]], [[sa[4], sa[5]], [sa[6], sa[7]]], [[sa[8], sa[9]], [sa[10], sa[11]]]], [[[sa[12], sa[13]], [sa[14], sa[15]]], [[sa[16], sa[17]], [sa[18], sa[19]]], [[sa[20], sa[21]], [sa[22], sa[23]]]], [[[sa[24], sa[25]], [sa[26], sa[27]]], [[sa[28], sa[29]], [sa[30], sa[31]]], [[sa[32], sa[33]], [sa[34], sa[35]]]]], [[[[sa[72], sa[73]], [sa[74], sa[75]]], [[sa[76], sa[77]], [sa[78], sa[79]]], [[sa[80], sa[81]], [sa[82], sa[83]]]], [[[sa[84], sa[85]], [sa[86], sa[87]]], [[sa[88], sa[89]], [sa[90], sa[91]]], [[sa[92], sa[93]], [sa[94], sa[95]]]], [[[sa[96], sa[97]], [sa[98], sa[99]]], [[sa[100], sa[101]], [sa[102], sa[103]]], [[sa[104], sa[105]], [sa[106], sa[107]]]]]], [[[[[sa[36], sa[37]], [sa[38], sa[39]]], [[sa[40], sa[41]], [sa[42], sa[43]]], [[sa[44], sa[45]], [sa[46], sa[47]]]], [[[sa[48], sa[49]], [sa[50], sa[51]]], [[sa[52], sa[53]], [sa[54], sa[55]]], [[sa[56], sa[57]], [sa[58], sa[59]]]], [[[sa[60], sa[61]], [sa[62], sa[63]]], [[sa[64], sa[65]], [sa[66], sa[67]]], [[sa[68], sa[69]], [sa[70], sa[71]]]]], [ [[[sa[108], sa[109]], [sa[110], sa[111]]], [[sa[112], sa[113]], [sa[114], sa[115]]], [[sa[116], sa[117]], [sa[118], sa[119]]]], [[[sa[120], sa[121]], [sa[122], sa[123]]], [[sa[124], sa[125]], [sa[126], sa[127]]], [[sa[128], sa[129]], [sa[130], sa[131]]]], [[[sa[132], sa[133]], [sa[134], sa[135]]], [[sa[136], sa[137]], [sa[138], sa[139]]], [[sa[140], sa[141]], [sa[142], sa[143]]]]]]]) assert permutedims(po, (0, 2, 1, 4, 3, 5)) == ArrayType( [[[[[[sa[0], sa[1]], [sa[4], sa[5]], [sa[8], sa[9]]], [[sa[2], sa[3]], [sa[6], sa[7]], [sa[10], sa[11]]]], [[[sa[36], sa[37]], [sa[40], sa[41]], [sa[44], sa[45]]], [[sa[38], sa[39]], [sa[42], sa[43]], [sa[46], sa[47]]]]], [[[[sa[12], sa[13]], [sa[16], sa[17]], [sa[20], sa[21]]], [[sa[14], sa[15]], [sa[18], sa[19]], [sa[22], sa[23]]]], [[[sa[48], sa[49]], [sa[52], sa[53]], [sa[56], sa[57]]], [[sa[50], sa[51]], [sa[54], sa[55]], [sa[58], sa[59]]]]], [[[[sa[24], sa[25]], [sa[28], sa[29]], [sa[32], sa[33]]], [[sa[26], sa[27]], [sa[30], sa[31]], [sa[34], sa[35]]]], [[[sa[60], sa[61]], [sa[64], sa[65]], [sa[68], sa[69]]], [[sa[62], sa[63]], [sa[66], sa[67]], [sa[70], sa[71]]]]]], [[[[[sa[72], sa[73]], [sa[76], sa[77]], [sa[80], sa[81]]], [[sa[74], sa[75]], [sa[78], sa[79]], [sa[82], sa[83]]]], [[[sa[108], sa[109]], [sa[112], sa[113]], [sa[116], sa[117]]], [[sa[110], sa[111]], [sa[114], sa[115]], [sa[118], sa[119]]]]], [[[[sa[84], sa[85]], [sa[88], sa[89]], [sa[92], sa[93]]], [[sa[86], sa[87]], [sa[90], sa[91]], [sa[94], sa[95]]]], [[[sa[120], sa[121]], [sa[124], sa[125]], [sa[128], sa[129]]], [[sa[122], sa[123]], [sa[126], sa[127]], [sa[130], sa[131]]]]], [[[[sa[96], sa[97]], [sa[100], sa[101]], [sa[104], sa[105]]], [[sa[98], sa[99]], [sa[102], sa[103]], [sa[106], sa[107]]]], [[[sa[132], sa[133]], [sa[136], sa[137]], [sa[140], sa[141]]], [[sa[134], sa[135]], [sa[138], sa[139]], [sa[142], sa[143]]]]]]]) po2 = po.reshape(4, 9, 2, 2) assert po2 == ArrayType([[[[sa[0], sa[1]], [sa[2], sa[3]]], [[sa[4], sa[5]], [sa[6], sa[7]]], [[sa[8], sa[9]], [sa[10], sa[11]]], [[sa[12], sa[13]], [sa[14], sa[15]]], [[sa[16], sa[17]], [sa[18], sa[19]]], [[sa[20], sa[21]], [sa[22], sa[23]]], [[sa[24], sa[25]], [sa[26], sa[27]]], [[sa[28], sa[29]], [sa[30], sa[31]]], [[sa[32], sa[33]], [sa[34], sa[35]]]], [[[sa[36], sa[37]], [sa[38], sa[39]]], [[sa[40], sa[41]], [sa[42], sa[43]]], [[sa[44], sa[45]], [sa[46], sa[47]]], [[sa[48], sa[49]], [sa[50], sa[51]]], [[sa[52], sa[53]], [sa[54], sa[55]]], [[sa[56], sa[57]], [sa[58], sa[59]]], [[sa[60], sa[61]], [sa[62], sa[63]]], [[sa[64], sa[65]], [sa[66], sa[67]]], [[sa[68], sa[69]], [sa[70], sa[71]]]], [[[sa[72], sa[73]], [sa[74], sa[75]]], [[sa[76], sa[77]], [sa[78], sa[79]]], [[sa[80], sa[81]], [sa[82], sa[83]]], [[sa[84], sa[85]], [sa[86], sa[87]]], [[sa[88], sa[89]], [sa[90], sa[91]]], [[sa[92], sa[93]], [sa[94], sa[95]]], [[sa[96], sa[97]], [sa[98], sa[99]]], [[sa[100], sa[101]], [sa[102], sa[103]]], [[sa[104], sa[105]], [sa[106], sa[107]]]], [[[sa[108], sa[109]], [sa[110], sa[111]]], [[sa[112], sa[113]], [sa[114], sa[115]]], [[sa[116], sa[117]], [sa[118], sa[119]]], [[sa[120], sa[121]], [sa[122], sa[123]]], [[sa[124], sa[125]], [sa[126], sa[127]]], [[sa[128], sa[129]], [sa[130], sa[131]]], [[sa[132], sa[133]], [sa[134], sa[135]]], [[sa[136], sa[137]], [sa[138], sa[139]]], [[sa[140], sa[141]], [sa[142], sa[143]]]]]) assert permutedims(po2, (3, 2, 0, 1)) == ArrayType([[[[sa[0], sa[4], sa[8], sa[12], sa[16], sa[20], sa[24], sa[28], sa[32]], [sa[36], sa[40], sa[44], sa[48], sa[52], sa[56], sa[60], sa[64], sa[68]], [sa[72], sa[76], sa[80], sa[84], sa[88], sa[92], sa[96], sa[100], sa[104]], [sa[108], sa[112], sa[116], sa[120], sa[124], sa[128], sa[132], sa[136], sa[140]]], [[sa[2], sa[6], sa[10], sa[14], sa[18], sa[22], sa[26], sa[30], sa[34]], [sa[38], sa[42], sa[46], sa[50], sa[54], sa[58], sa[62], sa[66], sa[70]], [sa[74], sa[78], sa[82], sa[86], sa[90], sa[94], sa[98], sa[102], sa[106]], [sa[110], sa[114], sa[118], sa[122], sa[126], sa[130], sa[134], sa[138], sa[142]]]], [[[sa[1], sa[5], sa[9], sa[13], sa[17], sa[21], sa[25], sa[29], sa[33]], [sa[37], sa[41], sa[45], sa[49], sa[53], sa[57], sa[61], sa[65], sa[69]], [sa[73], sa[77], sa[81], sa[85], sa[89], sa[93], sa[97], sa[101], sa[105]], [sa[109], sa[113], sa[117], sa[121], sa[125], sa[129], sa[133], sa[137], sa[141]]], [[sa[3], sa[7], sa[11], sa[15], sa[19], sa[23], sa[27], sa[31], sa[35]], [sa[39], sa[43], sa[47], sa[51], sa[55], sa[59], sa[63], sa[67], sa[71]], [sa[75], sa[79], sa[83], sa[87], sa[91], sa[95], sa[99], sa[103], sa[107]], [sa[111], sa[115], sa[119], sa[123], sa[127], sa[131], sa[135], sa[139], sa[143]]]]]) # test for large scale sparse array for SparseArrayType in [ImmutableSparseNDimArray, MutableSparseNDimArray]: A = SparseArrayType({1:1, 10000:2}, (10000, 20000, 10000)) assert permutedims(A, (0, 1, 2)) == A assert permutedims(A, (1, 0, 2)) == SparseArrayType({1: 1, 100000000: 2}, (20000, 10000, 10000)) B = SparseArrayType({1:1, 20000:2}, (10000, 20000)) assert B.transpose() == SparseArrayType({10000: 1, 1: 2}, (20000, 10000)) def test_flatten(): from sympy import Matrix for ArrayType in [ImmutableDenseNDimArray, ImmutableSparseNDimArray, Matrix]: A = ArrayType(range(24)).reshape(4, 6) assert [i for i in Flatten(A)] == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23] for i, v in enumerate(Flatten(A)): i == v def test_tensordiagonal(): from sympy import eye expr = Array(range(9)).reshape(3, 3) raises(ValueError, lambda: tensordiagonal(expr, [0], [1])) assert tensordiagonal(eye(3), [0, 1]) == Array([1, 1, 1]) assert tensordiagonal(expr, [0, 1]) == Array([0, 4, 8]) x, y, z = symbols("x y z") expr2 = tensorproduct([x, y, z], expr) assert tensordiagonal(expr2, [1, 2]) == Array([[0, 4*x, 8*x], [0, 4*y, 8*y], [0, 4*z, 8*z]]) assert tensordiagonal(expr2, [0, 1]) == Array([[0, 3*y, 6*z], [x, 4*y, 7*z], [2*x, 5*y, 8*z]]) assert tensordiagonal(expr2, [0, 1, 2]) == Array([0, 4*y, 8*z]) # assert tensordiagonal(expr2, [0]) == permutedims(expr2, [1, 2, 0]) # assert tensordiagonal(expr2, [1]) == permutedims(expr2, [0, 2, 1]) # assert tensordiagonal(expr2, [2]) == expr2 # assert tensordiagonal(expr2, [1], [2]) == expr2 # assert tensordiagonal(expr2, [0], [1]) == permutedims(expr2, [2, 0, 1]) a, b, c, X, Y, Z = symbols("a b c X Y Z") expr3 = tensorproduct([x, y, z], [1, 2, 3], [a, b, c], [X, Y, Z]) assert tensordiagonal(expr3, [0, 1, 2, 3]) == Array([x*a*X, 2*y*b*Y, 3*z*c*Z]) assert tensordiagonal(expr3, [0, 1], [2, 3]) == tensorproduct([x, 2*y, 3*z], [a*X, b*Y, c*Z]) # assert tensordiagonal(expr3, [0], [1, 2], [3]) == tensorproduct([x, y, z], [a, 2*b, 3*c], [X, Y, Z]) assert tensordiagonal(tensordiagonal(expr3, [2, 3]), [0, 1]) == tensorproduct([a*X, b*Y, c*Z], [x, 2*y, 3*z]) raises(ValueError, lambda: tensordiagonal([[1, 2, 3], [4, 5, 6]], [0, 1])) raises(ValueError, lambda: tensordiagonal(expr3.reshape(3, 3, 9), [1, 2])) sympy-sympy-1.9/sympy/tensor/array/tests/test_immutable_ndim_array.py000066400000000000000000000363621412543434000265050ustar00rootroot00000000000000from copy import copy from sympy.tensor.array.dense_ndim_array import ImmutableDenseNDimArray from sympy import Symbol, Rational, SparseMatrix, Dict, diff, symbols, Indexed, IndexedBase, S from sympy.matrices import Matrix from sympy.tensor.array.sparse_ndim_array import ImmutableSparseNDimArray from sympy.testing.pytest import raises def test_ndim_array_initiation(): arr_with_no_elements = ImmutableDenseNDimArray([], shape=(0,)) assert len(arr_with_no_elements) == 0 assert arr_with_no_elements.rank() == 1 raises(ValueError, lambda: ImmutableDenseNDimArray([0], shape=(0,))) raises(ValueError, lambda: ImmutableDenseNDimArray([1, 2, 3], shape=(0,))) raises(ValueError, lambda: ImmutableDenseNDimArray([], shape=())) raises(ValueError, lambda: ImmutableSparseNDimArray([0], shape=(0,))) raises(ValueError, lambda: ImmutableSparseNDimArray([1, 2, 3], shape=(0,))) raises(ValueError, lambda: ImmutableSparseNDimArray([], shape=())) arr_with_one_element = ImmutableDenseNDimArray([23]) assert len(arr_with_one_element) == 1 assert arr_with_one_element[0] == 23 assert arr_with_one_element[:] == ImmutableDenseNDimArray([23]) assert arr_with_one_element.rank() == 1 arr_with_symbol_element = ImmutableDenseNDimArray([Symbol('x')]) assert len(arr_with_symbol_element) == 1 assert arr_with_symbol_element[0] == Symbol('x') assert arr_with_symbol_element[:] == ImmutableDenseNDimArray([Symbol('x')]) assert arr_with_symbol_element.rank() == 1 number5 = 5 vector = ImmutableDenseNDimArray.zeros(number5) assert len(vector) == number5 assert vector.shape == (number5,) assert vector.rank() == 1 vector = ImmutableSparseNDimArray.zeros(number5) assert len(vector) == number5 assert vector.shape == (number5,) assert vector._sparse_array == Dict() assert vector.rank() == 1 n_dim_array = ImmutableDenseNDimArray(range(3**4), (3, 3, 3, 3,)) assert len(n_dim_array) == 3 * 3 * 3 * 3 assert n_dim_array.shape == (3, 3, 3, 3) assert n_dim_array.rank() == 4 array_shape = (3, 3, 3, 3) sparse_array = ImmutableSparseNDimArray.zeros(*array_shape) assert len(sparse_array._sparse_array) == 0 assert len(sparse_array) == 3 * 3 * 3 * 3 assert n_dim_array.shape == array_shape assert n_dim_array.rank() == 4 one_dim_array = ImmutableDenseNDimArray([2, 3, 1]) assert len(one_dim_array) == 3 assert one_dim_array.shape == (3,) assert one_dim_array.rank() == 1 assert one_dim_array.tolist() == [2, 3, 1] shape = (3, 3) array_with_many_args = ImmutableSparseNDimArray.zeros(*shape) assert len(array_with_many_args) == 3 * 3 assert array_with_many_args.shape == shape assert array_with_many_args[0, 0] == 0 assert array_with_many_args.rank() == 2 shape = (int(3), int(3)) array_with_long_shape = ImmutableSparseNDimArray.zeros(*shape) assert len(array_with_long_shape) == 3 * 3 assert array_with_long_shape.shape == shape assert array_with_long_shape[int(0), int(0)] == 0 assert array_with_long_shape.rank() == 2 vector_with_long_shape = ImmutableDenseNDimArray(range(5), int(5)) assert len(vector_with_long_shape) == 5 assert vector_with_long_shape.shape == (int(5),) assert vector_with_long_shape.rank() == 1 raises(ValueError, lambda: vector_with_long_shape[int(5)]) from sympy.abc import x for ArrayType in [ImmutableDenseNDimArray, ImmutableSparseNDimArray]: rank_zero_array = ArrayType(x) assert len(rank_zero_array) == 1 assert rank_zero_array.shape == () assert rank_zero_array.rank() == 0 assert rank_zero_array[()] == x raises(ValueError, lambda: rank_zero_array[0]) def test_reshape(): array = ImmutableDenseNDimArray(range(50), 50) assert array.shape == (50,) assert array.rank() == 1 array = array.reshape(5, 5, 2) assert array.shape == (5, 5, 2) assert array.rank() == 3 assert len(array) == 50 def test_getitem(): for ArrayType in [ImmutableDenseNDimArray, ImmutableSparseNDimArray]: array = ArrayType(range(24)).reshape(2, 3, 4) assert array.tolist() == [[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]] assert array[0] == ArrayType([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]) assert array[0, 0] == ArrayType([0, 1, 2, 3]) value = 0 for i in range(2): for j in range(3): for k in range(4): assert array[i, j, k] == value value += 1 raises(ValueError, lambda: array[3, 4, 5]) raises(ValueError, lambda: array[3, 4, 5, 6]) raises(ValueError, lambda: array[3, 4, 5, 3:4]) def test_iterator(): array = ImmutableDenseNDimArray(range(4), (2, 2)) array[0] == ImmutableDenseNDimArray([0, 1]) array[1] == ImmutableDenseNDimArray([2, 3]) array = array.reshape(4) j = 0 for i in array: assert i == j j += 1 def test_sparse(): sparse_array = ImmutableSparseNDimArray([0, 0, 0, 1], (2, 2)) assert len(sparse_array) == 2 * 2 # dictionary where all data is, only non-zero entries are actually stored: assert len(sparse_array._sparse_array) == 1 assert sparse_array.tolist() == [[0, 0], [0, 1]] for i, j in zip(sparse_array, [[0, 0], [0, 1]]): assert i == ImmutableSparseNDimArray(j) def sparse_assignment(): sparse_array[0, 0] = 123 assert len(sparse_array._sparse_array) == 1 raises(TypeError, sparse_assignment) assert len(sparse_array._sparse_array) == 1 assert sparse_array[0, 0] == 0 assert sparse_array/0 == ImmutableSparseNDimArray([[S.NaN, S.NaN], [S.NaN, S.ComplexInfinity]], (2, 2)) # test for large scale sparse array # equality test assert ImmutableSparseNDimArray.zeros(100000, 200000) == ImmutableSparseNDimArray.zeros(100000, 200000) # __mul__ and __rmul__ a = ImmutableSparseNDimArray({200001: 1}, (100000, 200000)) assert a * 3 == ImmutableSparseNDimArray({200001: 3}, (100000, 200000)) assert 3 * a == ImmutableSparseNDimArray({200001: 3}, (100000, 200000)) assert a * 0 == ImmutableSparseNDimArray({}, (100000, 200000)) assert 0 * a == ImmutableSparseNDimArray({}, (100000, 200000)) # __truediv__ assert a/3 == ImmutableSparseNDimArray({200001: Rational(1, 3)}, (100000, 200000)) # __neg__ assert -a == ImmutableSparseNDimArray({200001: -1}, (100000, 200000)) def test_calculation(): a = ImmutableDenseNDimArray([1]*9, (3, 3)) b = ImmutableDenseNDimArray([9]*9, (3, 3)) c = a + b for i in c: assert i == ImmutableDenseNDimArray([10, 10, 10]) assert c == ImmutableDenseNDimArray([10]*9, (3, 3)) assert c == ImmutableSparseNDimArray([10]*9, (3, 3)) c = b - a for i in c: assert i == ImmutableDenseNDimArray([8, 8, 8]) assert c == ImmutableDenseNDimArray([8]*9, (3, 3)) assert c == ImmutableSparseNDimArray([8]*9, (3, 3)) def test_ndim_array_converting(): dense_array = ImmutableDenseNDimArray([1, 2, 3, 4], (2, 2)) alist = dense_array.tolist() alist == [[1, 2], [3, 4]] matrix = dense_array.tomatrix() assert (isinstance(matrix, Matrix)) for i in range(len(dense_array)): assert dense_array[dense_array._get_tuple_index(i)] == matrix[i] assert matrix.shape == dense_array.shape assert ImmutableDenseNDimArray(matrix) == dense_array assert ImmutableDenseNDimArray(matrix.as_immutable()) == dense_array assert ImmutableDenseNDimArray(matrix.as_mutable()) == dense_array sparse_array = ImmutableSparseNDimArray([1, 2, 3, 4], (2, 2)) alist = sparse_array.tolist() assert alist == [[1, 2], [3, 4]] matrix = sparse_array.tomatrix() assert(isinstance(matrix, SparseMatrix)) for i in range(len(sparse_array)): assert sparse_array[sparse_array._get_tuple_index(i)] == matrix[i] assert matrix.shape == sparse_array.shape assert ImmutableSparseNDimArray(matrix) == sparse_array assert ImmutableSparseNDimArray(matrix.as_immutable()) == sparse_array assert ImmutableSparseNDimArray(matrix.as_mutable()) == sparse_array def test_converting_functions(): arr_list = [1, 2, 3, 4] arr_matrix = Matrix(((1, 2), (3, 4))) # list arr_ndim_array = ImmutableDenseNDimArray(arr_list, (2, 2)) assert (isinstance(arr_ndim_array, ImmutableDenseNDimArray)) assert arr_matrix.tolist() == arr_ndim_array.tolist() # Matrix arr_ndim_array = ImmutableDenseNDimArray(arr_matrix) assert (isinstance(arr_ndim_array, ImmutableDenseNDimArray)) assert arr_matrix.tolist() == arr_ndim_array.tolist() assert arr_matrix.shape == arr_ndim_array.shape def test_equality(): first_list = [1, 2, 3, 4] second_list = [1, 2, 3, 4] third_list = [4, 3, 2, 1] assert first_list == second_list assert first_list != third_list first_ndim_array = ImmutableDenseNDimArray(first_list, (2, 2)) second_ndim_array = ImmutableDenseNDimArray(second_list, (2, 2)) fourth_ndim_array = ImmutableDenseNDimArray(first_list, (2, 2)) assert first_ndim_array == second_ndim_array def assignment_attempt(a): a[0, 0] = 0 raises(TypeError, lambda: assignment_attempt(second_ndim_array)) assert first_ndim_array == second_ndim_array assert first_ndim_array == fourth_ndim_array def test_arithmetic(): a = ImmutableDenseNDimArray([3 for i in range(9)], (3, 3)) b = ImmutableDenseNDimArray([7 for i in range(9)], (3, 3)) c1 = a + b c2 = b + a assert c1 == c2 d1 = a - b d2 = b - a assert d1 == d2 * (-1) e1 = a * 5 e2 = 5 * a e3 = copy(a) e3 *= 5 assert e1 == e2 == e3 f1 = a / 5 f2 = copy(a) f2 /= 5 assert f1 == f2 assert f1[0, 0] == f1[0, 1] == f1[0, 2] == f1[1, 0] == f1[1, 1] == \ f1[1, 2] == f1[2, 0] == f1[2, 1] == f1[2, 2] == Rational(3, 5) assert type(a) == type(b) == type(c1) == type(c2) == type(d1) == type(d2) \ == type(e1) == type(e2) == type(e3) == type(f1) z0 = -a assert z0 == ImmutableDenseNDimArray([-3 for i in range(9)], (3, 3)) def test_higher_dimenions(): m3 = ImmutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert m3.tolist() == [[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]] assert m3._get_tuple_index(0) == (0, 0, 0) assert m3._get_tuple_index(1) == (0, 0, 1) assert m3._get_tuple_index(4) == (0, 1, 0) assert m3._get_tuple_index(12) == (1, 0, 0) assert str(m3) == '[[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]]' m3_rebuilt = ImmutableDenseNDimArray([[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]]) assert m3 == m3_rebuilt m3_other = ImmutableDenseNDimArray([[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]], (2, 3, 4)) assert m3 == m3_other def test_rebuild_immutable_arrays(): sparr = ImmutableSparseNDimArray(range(10, 34), (2, 3, 4)) densarr = ImmutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert sparr == sparr.func(*sparr.args) assert densarr == densarr.func(*densarr.args) def test_slices(): md = ImmutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert md[:] == ImmutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert md[:, :, 0].tomatrix() == Matrix([[10, 14, 18], [22, 26, 30]]) assert md[0, 1:2, :].tomatrix() == Matrix([[14, 15, 16, 17]]) assert md[0, 1:3, :].tomatrix() == Matrix([[14, 15, 16, 17], [18, 19, 20, 21]]) assert md[:, :, :] == md sd = ImmutableSparseNDimArray(range(10, 34), (2, 3, 4)) assert sd == ImmutableSparseNDimArray(md) assert sd[:] == ImmutableSparseNDimArray(range(10, 34), (2, 3, 4)) assert sd[:, :, 0].tomatrix() == Matrix([[10, 14, 18], [22, 26, 30]]) assert sd[0, 1:2, :].tomatrix() == Matrix([[14, 15, 16, 17]]) assert sd[0, 1:3, :].tomatrix() == Matrix([[14, 15, 16, 17], [18, 19, 20, 21]]) assert sd[:, :, :] == sd def test_diff_and_applyfunc(): from sympy.abc import x, y, z md = ImmutableDenseNDimArray([[x, y], [x*z, x*y*z]]) assert md.diff(x) == ImmutableDenseNDimArray([[1, 0], [z, y*z]]) assert diff(md, x) == ImmutableDenseNDimArray([[1, 0], [z, y*z]]) sd = ImmutableSparseNDimArray(md) assert sd == ImmutableSparseNDimArray([x, y, x*z, x*y*z], (2, 2)) assert sd.diff(x) == ImmutableSparseNDimArray([[1, 0], [z, y*z]]) assert diff(sd, x) == ImmutableSparseNDimArray([[1, 0], [z, y*z]]) mdn = md.applyfunc(lambda x: x*3) assert mdn == ImmutableDenseNDimArray([[3*x, 3*y], [3*x*z, 3*x*y*z]]) assert md != mdn sdn = sd.applyfunc(lambda x: x/2) assert sdn == ImmutableSparseNDimArray([[x/2, y/2], [x*z/2, x*y*z/2]]) assert sd != sdn sdp = sd.applyfunc(lambda x: x+1) assert sdp == ImmutableSparseNDimArray([[x + 1, y + 1], [x*z + 1, x*y*z + 1]]) assert sd != sdp def test_op_priority(): from sympy.abc import x md = ImmutableDenseNDimArray([1, 2, 3]) e1 = (1+x)*md e2 = md*(1+x) assert e1 == ImmutableDenseNDimArray([1+x, 2+2*x, 3+3*x]) assert e1 == e2 sd = ImmutableSparseNDimArray([1, 2, 3]) e3 = (1+x)*sd e4 = sd*(1+x) assert e3 == ImmutableDenseNDimArray([1+x, 2+2*x, 3+3*x]) assert e3 == e4 def test_symbolic_indexing(): x, y, z, w = symbols("x y z w") M = ImmutableDenseNDimArray([[x, y], [z, w]]) i, j = symbols("i, j") Mij = M[i, j] assert isinstance(Mij, Indexed) Ms = ImmutableSparseNDimArray([[2, 3*x], [4, 5]]) msij = Ms[i, j] assert isinstance(msij, Indexed) for oi, oj in [(0, 0), (0, 1), (1, 0), (1, 1)]: assert Mij.subs({i: oi, j: oj}) == M[oi, oj] assert msij.subs({i: oi, j: oj}) == Ms[oi, oj] A = IndexedBase("A", (0, 2)) assert A[0, 0].subs(A, M) == x assert A[i, j].subs(A, M) == M[i, j] assert M[i, j].subs(M, A) == A[i, j] assert isinstance(M[3 * i - 2, j], Indexed) assert M[3 * i - 2, j].subs({i: 1, j: 0}) == M[1, 0] assert isinstance(M[i, 0], Indexed) assert M[i, 0].subs(i, 0) == M[0, 0] assert M[0, i].subs(i, 1) == M[0, 1] assert M[i, j].diff(x) == ImmutableDenseNDimArray([[1, 0], [0, 0]])[i, j] assert Ms[i, j].diff(x) == ImmutableSparseNDimArray([[0, 3], [0, 0]])[i, j] Mo = ImmutableDenseNDimArray([1, 2, 3]) assert Mo[i].subs(i, 1) == 2 Mos = ImmutableSparseNDimArray([1, 2, 3]) assert Mos[i].subs(i, 1) == 2 raises(ValueError, lambda: M[i, 2]) raises(ValueError, lambda: M[i, -1]) raises(ValueError, lambda: M[2, i]) raises(ValueError, lambda: M[-1, i]) raises(ValueError, lambda: Ms[i, 2]) raises(ValueError, lambda: Ms[i, -1]) raises(ValueError, lambda: Ms[2, i]) raises(ValueError, lambda: Ms[-1, i]) def test_issue_12665(): # Testing Python 3 hash of immutable arrays: arr = ImmutableDenseNDimArray([1, 2, 3]) # This should NOT raise an exception: hash(arr) def test_zeros_without_shape(): arr = ImmutableDenseNDimArray.zeros() assert arr == ImmutableDenseNDimArray(0) def test_issue_21870(): a0 = ImmutableDenseNDimArray(0) assert a0.rank() == 0 a1 = ImmutableDenseNDimArray(a0) assert a1.rank() == 0 sympy-sympy-1.9/sympy/tensor/array/tests/test_mutable_ndim_array.py000066400000000000000000000311301412543434000261430ustar00rootroot00000000000000from copy import copy from sympy.tensor.array.dense_ndim_array import MutableDenseNDimArray from sympy import Symbol, Rational, SparseMatrix, diff, sympify, S from sympy.matrices import Matrix from sympy.tensor.array.sparse_ndim_array import MutableSparseNDimArray from sympy.testing.pytest import raises def test_ndim_array_initiation(): arr_with_one_element = MutableDenseNDimArray([23]) assert len(arr_with_one_element) == 1 assert arr_with_one_element[0] == 23 assert arr_with_one_element.rank() == 1 raises(ValueError, lambda: arr_with_one_element[1]) arr_with_symbol_element = MutableDenseNDimArray([Symbol('x')]) assert len(arr_with_symbol_element) == 1 assert arr_with_symbol_element[0] == Symbol('x') assert arr_with_symbol_element.rank() == 1 number5 = 5 vector = MutableDenseNDimArray.zeros(number5) assert len(vector) == number5 assert vector.shape == (number5,) assert vector.rank() == 1 raises(ValueError, lambda: arr_with_one_element[5]) vector = MutableSparseNDimArray.zeros(number5) assert len(vector) == number5 assert vector.shape == (number5,) assert vector._sparse_array == {} assert vector.rank() == 1 n_dim_array = MutableDenseNDimArray(range(3**4), (3, 3, 3, 3,)) assert len(n_dim_array) == 3 * 3 * 3 * 3 assert n_dim_array.shape == (3, 3, 3, 3) assert n_dim_array.rank() == 4 raises(ValueError, lambda: n_dim_array[0, 0, 0, 3]) raises(ValueError, lambda: n_dim_array[3, 0, 0, 0]) raises(ValueError, lambda: n_dim_array[3**4]) array_shape = (3, 3, 3, 3) sparse_array = MutableSparseNDimArray.zeros(*array_shape) assert len(sparse_array._sparse_array) == 0 assert len(sparse_array) == 3 * 3 * 3 * 3 assert n_dim_array.shape == array_shape assert n_dim_array.rank() == 4 one_dim_array = MutableDenseNDimArray([2, 3, 1]) assert len(one_dim_array) == 3 assert one_dim_array.shape == (3,) assert one_dim_array.rank() == 1 assert one_dim_array.tolist() == [2, 3, 1] shape = (3, 3) array_with_many_args = MutableSparseNDimArray.zeros(*shape) assert len(array_with_many_args) == 3 * 3 assert array_with_many_args.shape == shape assert array_with_many_args[0, 0] == 0 assert array_with_many_args.rank() == 2 shape = (int(3), int(3)) array_with_long_shape = MutableSparseNDimArray.zeros(*shape) assert len(array_with_long_shape) == 3 * 3 assert array_with_long_shape.shape == shape assert array_with_long_shape[int(0), int(0)] == 0 assert array_with_long_shape.rank() == 2 vector_with_long_shape = MutableDenseNDimArray(range(5), int(5)) assert len(vector_with_long_shape) == 5 assert vector_with_long_shape.shape == (int(5),) assert vector_with_long_shape.rank() == 1 raises(ValueError, lambda: vector_with_long_shape[int(5)]) from sympy.abc import x for ArrayType in [MutableDenseNDimArray, MutableSparseNDimArray]: rank_zero_array = ArrayType(x) assert len(rank_zero_array) == 1 assert rank_zero_array.shape == () assert rank_zero_array.rank() == 0 assert rank_zero_array[()] == x raises(ValueError, lambda: rank_zero_array[0]) def test_sympify(): from sympy.abc import x, y, z, t arr = MutableDenseNDimArray([[x, y], [1, z*t]]) arr_other = sympify(arr) assert arr_other.shape == (2, 2) assert arr_other == arr def test_reshape(): array = MutableDenseNDimArray(range(50), 50) assert array.shape == (50,) assert array.rank() == 1 array = array.reshape(5, 5, 2) assert array.shape == (5, 5, 2) assert array.rank() == 3 assert len(array) == 50 def test_iterator(): array = MutableDenseNDimArray(range(4), (2, 2)) array[0] == MutableDenseNDimArray([0, 1]) array[1] == MutableDenseNDimArray([2, 3]) array = array.reshape(4) j = 0 for i in array: assert i == j j += 1 def test_getitem(): for ArrayType in [MutableDenseNDimArray, MutableSparseNDimArray]: array = ArrayType(range(24)).reshape(2, 3, 4) assert array.tolist() == [[[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]], [[12, 13, 14, 15], [16, 17, 18, 19], [20, 21, 22, 23]]] assert array[0] == ArrayType([[0, 1, 2, 3], [4, 5, 6, 7], [8, 9, 10, 11]]) assert array[0, 0] == ArrayType([0, 1, 2, 3]) value = 0 for i in range(2): for j in range(3): for k in range(4): assert array[i, j, k] == value value += 1 raises(ValueError, lambda: array[3, 4, 5]) raises(ValueError, lambda: array[3, 4, 5, 6]) raises(ValueError, lambda: array[3, 4, 5, 3:4]) def test_sparse(): sparse_array = MutableSparseNDimArray([0, 0, 0, 1], (2, 2)) assert len(sparse_array) == 2 * 2 # dictionary where all data is, only non-zero entries are actually stored: assert len(sparse_array._sparse_array) == 1 assert sparse_array.tolist() == [[0, 0], [0, 1]] for i, j in zip(sparse_array, [[0, 0], [0, 1]]): assert i == MutableSparseNDimArray(j) sparse_array[0, 0] = 123 assert len(sparse_array._sparse_array) == 2 assert sparse_array[0, 0] == 123 assert sparse_array/0 == MutableSparseNDimArray([[S.ComplexInfinity, S.NaN], [S.NaN, S.ComplexInfinity]], (2, 2)) # when element in sparse array become zero it will disappear from # dictionary sparse_array[0, 0] = 0 assert len(sparse_array._sparse_array) == 1 sparse_array[1, 1] = 0 assert len(sparse_array._sparse_array) == 0 assert sparse_array[0, 0] == 0 # test for large scale sparse array # equality test a = MutableSparseNDimArray.zeros(100000, 200000) b = MutableSparseNDimArray.zeros(100000, 200000) assert a == b a[1, 1] = 1 b[1, 1] = 2 assert a != b # __mul__ and __rmul__ assert a * 3 == MutableSparseNDimArray({200001: 3}, (100000, 200000)) assert 3 * a == MutableSparseNDimArray({200001: 3}, (100000, 200000)) assert a * 0 == MutableSparseNDimArray({}, (100000, 200000)) assert 0 * a == MutableSparseNDimArray({}, (100000, 200000)) # __truediv__ assert a/3 == MutableSparseNDimArray({200001: Rational(1, 3)}, (100000, 200000)) # __neg__ assert -a == MutableSparseNDimArray({200001: -1}, (100000, 200000)) def test_calculation(): a = MutableDenseNDimArray([1]*9, (3, 3)) b = MutableDenseNDimArray([9]*9, (3, 3)) c = a + b for i in c: assert i == MutableDenseNDimArray([10, 10, 10]) assert c == MutableDenseNDimArray([10]*9, (3, 3)) assert c == MutableSparseNDimArray([10]*9, (3, 3)) c = b - a for i in c: assert i == MutableSparseNDimArray([8, 8, 8]) assert c == MutableDenseNDimArray([8]*9, (3, 3)) assert c == MutableSparseNDimArray([8]*9, (3, 3)) def test_ndim_array_converting(): dense_array = MutableDenseNDimArray([1, 2, 3, 4], (2, 2)) alist = dense_array.tolist() alist == [[1, 2], [3, 4]] matrix = dense_array.tomatrix() assert (isinstance(matrix, Matrix)) for i in range(len(dense_array)): assert dense_array[dense_array._get_tuple_index(i)] == matrix[i] assert matrix.shape == dense_array.shape assert MutableDenseNDimArray(matrix) == dense_array assert MutableDenseNDimArray(matrix.as_immutable()) == dense_array assert MutableDenseNDimArray(matrix.as_mutable()) == dense_array sparse_array = MutableSparseNDimArray([1, 2, 3, 4], (2, 2)) alist = sparse_array.tolist() assert alist == [[1, 2], [3, 4]] matrix = sparse_array.tomatrix() assert(isinstance(matrix, SparseMatrix)) for i in range(len(sparse_array)): assert sparse_array[sparse_array._get_tuple_index(i)] == matrix[i] assert matrix.shape == sparse_array.shape assert MutableSparseNDimArray(matrix) == sparse_array assert MutableSparseNDimArray(matrix.as_immutable()) == sparse_array assert MutableSparseNDimArray(matrix.as_mutable()) == sparse_array def test_converting_functions(): arr_list = [1, 2, 3, 4] arr_matrix = Matrix(((1, 2), (3, 4))) # list arr_ndim_array = MutableDenseNDimArray(arr_list, (2, 2)) assert (isinstance(arr_ndim_array, MutableDenseNDimArray)) assert arr_matrix.tolist() == arr_ndim_array.tolist() # Matrix arr_ndim_array = MutableDenseNDimArray(arr_matrix) assert (isinstance(arr_ndim_array, MutableDenseNDimArray)) assert arr_matrix.tolist() == arr_ndim_array.tolist() assert arr_matrix.shape == arr_ndim_array.shape def test_equality(): first_list = [1, 2, 3, 4] second_list = [1, 2, 3, 4] third_list = [4, 3, 2, 1] assert first_list == second_list assert first_list != third_list first_ndim_array = MutableDenseNDimArray(first_list, (2, 2)) second_ndim_array = MutableDenseNDimArray(second_list, (2, 2)) third_ndim_array = MutableDenseNDimArray(third_list, (2, 2)) fourth_ndim_array = MutableDenseNDimArray(first_list, (2, 2)) assert first_ndim_array == second_ndim_array second_ndim_array[0, 0] = 0 assert first_ndim_array != second_ndim_array assert first_ndim_array != third_ndim_array assert first_ndim_array == fourth_ndim_array def test_arithmetic(): a = MutableDenseNDimArray([3 for i in range(9)], (3, 3)) b = MutableDenseNDimArray([7 for i in range(9)], (3, 3)) c1 = a + b c2 = b + a assert c1 == c2 d1 = a - b d2 = b - a assert d1 == d2 * (-1) e1 = a * 5 e2 = 5 * a e3 = copy(a) e3 *= 5 assert e1 == e2 == e3 f1 = a / 5 f2 = copy(a) f2 /= 5 assert f1 == f2 assert f1[0, 0] == f1[0, 1] == f1[0, 2] == f1[1, 0] == f1[1, 1] == \ f1[1, 2] == f1[2, 0] == f1[2, 1] == f1[2, 2] == Rational(3, 5) assert type(a) == type(b) == type(c1) == type(c2) == type(d1) == type(d2) \ == type(e1) == type(e2) == type(e3) == type(f1) z0 = -a assert z0 == MutableDenseNDimArray([-3 for i in range(9)], (3, 3)) def test_higher_dimenions(): m3 = MutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert m3.tolist() == [[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]] assert m3._get_tuple_index(0) == (0, 0, 0) assert m3._get_tuple_index(1) == (0, 0, 1) assert m3._get_tuple_index(4) == (0, 1, 0) assert m3._get_tuple_index(12) == (1, 0, 0) assert str(m3) == '[[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]]' m3_rebuilt = MutableDenseNDimArray([[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]]) assert m3 == m3_rebuilt m3_other = MutableDenseNDimArray([[[10, 11, 12, 13], [14, 15, 16, 17], [18, 19, 20, 21]], [[22, 23, 24, 25], [26, 27, 28, 29], [30, 31, 32, 33]]], (2, 3, 4)) assert m3 == m3_other def test_slices(): md = MutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert md[:] == MutableDenseNDimArray(range(10, 34), (2, 3, 4)) assert md[:, :, 0].tomatrix() == Matrix([[10, 14, 18], [22, 26, 30]]) assert md[0, 1:2, :].tomatrix() == Matrix([[14, 15, 16, 17]]) assert md[0, 1:3, :].tomatrix() == Matrix([[14, 15, 16, 17], [18, 19, 20, 21]]) assert md[:, :, :] == md sd = MutableSparseNDimArray(range(10, 34), (2, 3, 4)) assert sd == MutableSparseNDimArray(md) assert sd[:] == MutableSparseNDimArray(range(10, 34), (2, 3, 4)) assert sd[:, :, 0].tomatrix() == Matrix([[10, 14, 18], [22, 26, 30]]) assert sd[0, 1:2, :].tomatrix() == Matrix([[14, 15, 16, 17]]) assert sd[0, 1:3, :].tomatrix() == Matrix([[14, 15, 16, 17], [18, 19, 20, 21]]) assert sd[:, :, :] == sd def test_slices_assign(): a = MutableDenseNDimArray(range(12), shape=(4, 3)) b = MutableSparseNDimArray(range(12), shape=(4, 3)) for i in [a, b]: assert i.tolist() == [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] i[0, :] = [2, 2, 2] assert i.tolist() == [[2, 2, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]] i[0, 1:] = [8, 8] assert i.tolist() == [[2, 8, 8], [3, 4, 5], [6, 7, 8], [9, 10, 11]] i[1:3, 1] = [20, 44] assert i.tolist() == [[2, 8, 8], [3, 20, 5], [6, 44, 8], [9, 10, 11]] def test_diff(): from sympy.abc import x, y, z md = MutableDenseNDimArray([[x, y], [x*z, x*y*z]]) assert md.diff(x) == MutableDenseNDimArray([[1, 0], [z, y*z]]) assert diff(md, x) == MutableDenseNDimArray([[1, 0], [z, y*z]]) sd = MutableSparseNDimArray(md) assert sd == MutableSparseNDimArray([x, y, x*z, x*y*z], (2, 2)) assert sd.diff(x) == MutableSparseNDimArray([[1, 0], [z, y*z]]) assert diff(sd, x) == MutableSparseNDimArray([[1, 0], [z, y*z]]) sympy-sympy-1.9/sympy/tensor/array/tests/test_ndim_array.py000066400000000000000000000030721412543434000244360ustar00rootroot00000000000000from sympy.testing.pytest import raises from sympy import ( Array, ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableDenseNDimArray, MutableSparseNDimArray, sin, cos, simplify, Matrix ) from sympy.abc import x, y array_types = [ ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableDenseNDimArray, MutableSparseNDimArray ] def test_array_negative_indices(): for ArrayType in array_types: test_array = ArrayType([[1, 2, 3, 4, 5], [6, 7, 8, 9, 10]]) assert test_array[:, -1] == Array([5, 10]) assert test_array[:, -2] == Array([4, 9]) assert test_array[:, -3] == Array([3, 8]) assert test_array[:, -4] == Array([2, 7]) assert test_array[:, -5] == Array([1, 6]) assert test_array[:, 0] == Array([1, 6]) assert test_array[:, 1] == Array([2, 7]) assert test_array[:, 2] == Array([3, 8]) assert test_array[:, 3] == Array([4, 9]) assert test_array[:, 4] == Array([5, 10]) raises(ValueError, lambda: test_array[:, -6]) raises(ValueError, lambda: test_array[-3, :]) assert test_array[-1, -1] == 10 def test_issue_18361(): A = Array([sin(2 * x) - 2 * sin(x) * cos(x)]) B = Array([sin(x)**2 + cos(x)**2, 0]) C = Array([(x + x**2)/(x*sin(y)**2 + x*cos(y)**2), 2*sin(x)*cos(x)]) assert simplify(A) == Array([0]) assert simplify(B) == Array([1, 0]) assert simplify(C) == Array([x + 1, sin(2*x)]) def test_issue_20222(): A = Array([[1, 2], [3, 4]]) B = Matrix([[1,2],[3,4]]) raises(TypeError, lambda: A - B) sympy-sympy-1.9/sympy/tensor/array/tests/test_ndim_array_conversions.py000066400000000000000000000012101412543434000270560ustar00rootroot00000000000000from sympy.tensor.array import (ImmutableDenseNDimArray, ImmutableSparseNDimArray, MutableDenseNDimArray, MutableSparseNDimArray) from sympy.abc import x, y, z def test_NDim_array_conv(): MD = MutableDenseNDimArray([x, y, z]) MS = MutableSparseNDimArray([x, y, z]) ID = ImmutableDenseNDimArray([x, y, z]) IS = ImmutableSparseNDimArray([x, y, z]) assert MD.as_immutable() == ID assert MD.as_mutable() == MD assert MS.as_immutable() == IS assert MS.as_mutable() == MS assert ID.as_immutable() == ID assert ID.as_mutable() == MD assert IS.as_immutable() == IS assert IS.as_mutable() == MS sympy-sympy-1.9/sympy/tensor/functions.py000066400000000000000000000075631412543434000210130ustar00rootroot00000000000000from collections.abc import Iterable from functools import singledispatch from sympy import Expr, S, Mul, sympify from sympy.core.parameters import global_parameters class TensorProduct(Expr): """ Generic class for tensor products. """ is_number = False def __new__(cls, *args, **kwargs): from sympy.tensor.array import NDimArray, tensorproduct, Array from sympy import MatrixBase, MatrixExpr from sympy.strategies import flatten args = [sympify(arg) for arg in args] evaluate = kwargs.get("evaluate", global_parameters.evaluate) if not evaluate: obj = Expr.__new__(cls, *args) return obj arrays = [] other = [] scalar = S.One for arg in args: if isinstance(arg, (Iterable, MatrixBase, NDimArray)): arrays.append(Array(arg)) elif isinstance(arg, (MatrixExpr,)): other.append(arg) else: scalar *= arg coeff = scalar*tensorproduct(*arrays) if len(other) == 0: return coeff if coeff != 1: newargs = [coeff] + other else: newargs = other obj = Expr.__new__(cls, *newargs, **kwargs) return flatten(obj) def rank(self): return len(self.shape) def _get_args_shapes(self): from sympy import Array return [i.shape if hasattr(i, "shape") else Array(i).shape for i in self.args] @property def shape(self): shape_list = self._get_args_shapes() return sum(shape_list, ()) def __getitem__(self, index): index = iter(index) return Mul.fromiter( arg.__getitem__(tuple(next(index) for i in shp)) for arg, shp in zip(self.args, self._get_args_shapes()) ) @singledispatch def shape(expr): """ Return the shape of the *expr* as a tuple. *expr* should represent suitable object such as matrix or array. Parameters ========== expr : SymPy object having ``MatrixKind`` or ``ArrayKind``. Raises ====== NoShapeError : Raised when object with wrong kind is passed. Examples ======== This function returns the shape of any object representing matrix or array. >>> from sympy import shape, Array, Matrix, Integral >>> from sympy.abc import x >>> A = Array([1, 2]) >>> shape(A) (2,) >>> shape(Integral(A, x)) (2,) >>> M = Matrix([1, 2]) >>> shape(M) (2, 1) >>> shape(Integral(M, x)) (2, 1) You can support new type by dispatching. >>> from sympy import Expr >>> class NewExpr(Expr): ... pass >>> @shape.register(NewExpr) ... def _(expr): ... return shape(expr.args[0]) >>> shape(NewExpr(M)) (2, 1) If unsuitable expression is passed, ``NoShapeError()`` will be raised. >>> shape(Integral(x, x)) Traceback (most recent call last): ... sympy.tensor.functions.NoShapeError: shape() called on non-array object: Integral(x, x) Notes ===== Array-like classes (such as ``Matrix`` or ``NDimArray``) has ``shape`` property which returns its shape, but it cannot be used for non-array classes containing array. This function returns the shape of any registered object representing array. """ if hasattr(expr, "shape"): return expr.shape raise NoShapeError( "%s does not have shape, or its type is not registered to shape()." % expr) class NoShapeError(Exception): """ Raised when ``shape()`` is called on non-array object. This error can be imported from ``sympy.tensor.functions``. Examples ======== >>> from sympy import shape >>> from sympy.abc import x >>> shape(x) Traceback (most recent call last): ... sympy.tensor.functions.NoShapeError: shape() called on non-array object: x """ pass sympy-sympy-1.9/sympy/tensor/index_methods.py000066400000000000000000000361131412543434000216260ustar00rootroot00000000000000"""Module with functions operating on IndexedBase, Indexed and Idx objects - Check shape conformance - Determine indices in resulting expression etc. Methods in this module could be implemented by calling methods on Expr objects instead. When things stabilize this could be a useful refactoring. """ from functools import reduce from sympy.core.function import Function from sympy.functions import exp, Piecewise from sympy.tensor.indexed import Idx, Indexed from sympy.utilities import sift from collections import OrderedDict class IndexConformanceException(Exception): pass def _unique_and_repeated(inds): """ Returns the unique and repeated indices. Also note, from the examples given below that the order of indices is maintained as given in the input. Examples ======== >>> from sympy.tensor.index_methods import _unique_and_repeated >>> _unique_and_repeated([2, 3, 1, 3, 0, 4, 0]) ([2, 1, 4], [3, 0]) """ uniq = OrderedDict() for i in inds: if i in uniq: uniq[i] = 0 else: uniq[i] = 1 return sift(uniq, lambda x: uniq[x], binary=True) def _remove_repeated(inds): """ Removes repeated objects from sequences Returns a set of the unique objects and a tuple of all that have been removed. Examples ======== >>> from sympy.tensor.index_methods import _remove_repeated >>> l1 = [1, 2, 3, 2] >>> _remove_repeated(l1) ({1, 3}, (2,)) """ u, r = _unique_and_repeated(inds) return set(u), tuple(r) def _get_indices_Mul(expr, return_dummies=False): """Determine the outer indices of a Mul object. Examples ======== >>> from sympy.tensor.index_methods import _get_indices_Mul >>> from sympy.tensor.indexed import IndexedBase, Idx >>> i, j, k = map(Idx, ['i', 'j', 'k']) >>> x = IndexedBase('x') >>> y = IndexedBase('y') >>> _get_indices_Mul(x[i, k]*y[j, k]) ({i, j}, {}) >>> _get_indices_Mul(x[i, k]*y[j, k], return_dummies=True) ({i, j}, {}, (k,)) """ inds = list(map(get_indices, expr.args)) inds, syms = list(zip(*inds)) inds = list(map(list, inds)) inds = list(reduce(lambda x, y: x + y, inds)) inds, dummies = _remove_repeated(inds) symmetry = {} for s in syms: for pair in s: if pair in symmetry: symmetry[pair] *= s[pair] else: symmetry[pair] = s[pair] if return_dummies: return inds, symmetry, dummies else: return inds, symmetry def _get_indices_Pow(expr): """Determine outer indices of a power or an exponential. A power is considered a universal function, so that the indices of a Pow is just the collection of indices present in the expression. This may be viewed as a bit inconsistent in the special case: x[i]**2 = x[i]*x[i] (1) The above expression could have been interpreted as the contraction of x[i] with itself, but we choose instead to interpret it as a function lambda y: y**2 applied to each element of x (a universal function in numpy terms). In order to allow an interpretation of (1) as a contraction, we need contravariant and covariant Idx subclasses. (FIXME: this is not yet implemented) Expressions in the base or exponent are subject to contraction as usual, but an index that is present in the exponent, will not be considered contractable with its own base. Note however, that indices in the same exponent can be contracted with each other. Examples ======== >>> from sympy.tensor.index_methods import _get_indices_Pow >>> from sympy import Pow, exp, IndexedBase, Idx >>> A = IndexedBase('A') >>> x = IndexedBase('x') >>> i, j, k = map(Idx, ['i', 'j', 'k']) >>> _get_indices_Pow(exp(A[i, j]*x[j])) ({i}, {}) >>> _get_indices_Pow(Pow(x[i], x[i])) ({i}, {}) >>> _get_indices_Pow(Pow(A[i, j]*x[j], x[i])) ({i}, {}) """ base, exp = expr.as_base_exp() binds, bsyms = get_indices(base) einds, esyms = get_indices(exp) inds = binds | einds # FIXME: symmetries from power needs to check special cases, else nothing symmetries = {} return inds, symmetries def _get_indices_Add(expr): """Determine outer indices of an Add object. In a sum, each term must have the same set of outer indices. A valid expression could be x(i)*y(j) - x(j)*y(i) But we do not allow expressions like: x(i)*y(j) - z(j)*z(j) FIXME: Add support for Numpy broadcasting Examples ======== >>> from sympy.tensor.index_methods import _get_indices_Add >>> from sympy.tensor.indexed import IndexedBase, Idx >>> i, j, k = map(Idx, ['i', 'j', 'k']) >>> x = IndexedBase('x') >>> y = IndexedBase('y') >>> _get_indices_Add(x[i] + x[k]*y[i, k]) ({i}, {}) """ inds = list(map(get_indices, expr.args)) inds, syms = list(zip(*inds)) # allow broadcast of scalars non_scalars = [x for x in inds if x != set()] if not non_scalars: return set(), {} if not all([x == non_scalars[0] for x in non_scalars[1:]]): raise IndexConformanceException("Indices are not consistent: %s" % expr) if not reduce(lambda x, y: x != y or y, syms): symmetries = syms[0] else: # FIXME: search for symmetries symmetries = {} return non_scalars[0], symmetries def get_indices(expr): """Determine the outer indices of expression ``expr`` By *outer* we mean indices that are not summation indices. Returns a set and a dict. The set contains outer indices and the dict contains information about index symmetries. Examples ======== >>> from sympy.tensor.index_methods import get_indices >>> from sympy import symbols >>> from sympy.tensor import IndexedBase >>> x, y, A = map(IndexedBase, ['x', 'y', 'A']) >>> i, j, a, z = symbols('i j a z', integer=True) The indices of the total expression is determined, Repeated indices imply a summation, for instance the trace of a matrix A: >>> get_indices(A[i, i]) (set(), {}) In the case of many terms, the terms are required to have identical outer indices. Else an IndexConformanceException is raised. >>> get_indices(x[i] + A[i, j]*y[j]) ({i}, {}) :Exceptions: An IndexConformanceException means that the terms ar not compatible, e.g. >>> get_indices(x[i] + y[j]) #doctest: +SKIP (...) IndexConformanceException: Indices are not consistent: x(i) + y(j) .. warning:: The concept of *outer* indices applies recursively, starting on the deepest level. This implies that dummies inside parenthesis are assumed to be summed first, so that the following expression is handled gracefully: >>> get_indices((x[i] + A[i, j]*y[j])*x[j]) ({i, j}, {}) This is correct and may appear convenient, but you need to be careful with this as SymPy will happily .expand() the product, if requested. The resulting expression would mix the outer ``j`` with the dummies inside the parenthesis, which makes it a different expression. To be on the safe side, it is best to avoid such ambiguities by using unique indices for all contractions that should be held separate. """ # We call ourself recursively to determine indices of sub expressions. # break recursion if isinstance(expr, Indexed): c = expr.indices inds, dummies = _remove_repeated(c) return inds, {} elif expr is None: return set(), {} elif isinstance(expr, Idx): return {expr}, {} elif expr.is_Atom: return set(), {} # recurse via specialized functions else: if expr.is_Mul: return _get_indices_Mul(expr) elif expr.is_Add: return _get_indices_Add(expr) elif expr.is_Pow or isinstance(expr, exp): return _get_indices_Pow(expr) elif isinstance(expr, Piecewise): # FIXME: No support for Piecewise yet return set(), {} elif isinstance(expr, Function): # Support ufunc like behaviour by returning indices from arguments. # Functions do not interpret repeated indices across argumnts # as summation ind0 = set() for arg in expr.args: ind, sym = get_indices(arg) ind0 |= ind return ind0, sym # this test is expensive, so it should be at the end elif not expr.has(Indexed): return set(), {} raise NotImplementedError( "FIXME: No specialized handling of type %s" % type(expr)) def get_contraction_structure(expr): """Determine dummy indices of ``expr`` and describe its structure By *dummy* we mean indices that are summation indices. The structure of the expression is determined and described as follows: 1) A conforming summation of Indexed objects is described with a dict where the keys are summation indices and the corresponding values are sets containing all terms for which the summation applies. All Add objects in the SymPy expression tree are described like this. 2) For all nodes in the SymPy expression tree that are *not* of type Add, the following applies: If a node discovers contractions in one of its arguments, the node itself will be stored as a key in the dict. For that key, the corresponding value is a list of dicts, each of which is the result of a recursive call to get_contraction_structure(). The list contains only dicts for the non-trivial deeper contractions, omitting dicts with None as the one and only key. .. Note:: The presence of expressions among the dictionary keys indicates multiple levels of index contractions. A nested dict displays nested contractions and may itself contain dicts from a deeper level. In practical calculations the summation in the deepest nested level must be calculated first so that the outer expression can access the resulting indexed object. Examples ======== >>> from sympy.tensor.index_methods import get_contraction_structure >>> from sympy import default_sort_key >>> from sympy.tensor import IndexedBase, Idx >>> x, y, A = map(IndexedBase, ['x', 'y', 'A']) >>> i, j, k, l = map(Idx, ['i', 'j', 'k', 'l']) >>> get_contraction_structure(x[i]*y[i] + A[j, j]) {(i,): {x[i]*y[i]}, (j,): {A[j, j]}} >>> get_contraction_structure(x[i]*y[j]) {None: {x[i]*y[j]}} A multiplication of contracted factors results in nested dicts representing the internal contractions. >>> d = get_contraction_structure(x[i, i]*y[j, j]) >>> sorted(d.keys(), key=default_sort_key) [None, x[i, i]*y[j, j]] In this case, the product has no contractions: >>> d[None] {x[i, i]*y[j, j]} Factors are contracted "first": >>> sorted(d[x[i, i]*y[j, j]], key=default_sort_key) [{(i,): {x[i, i]}}, {(j,): {y[j, j]}}] A parenthesized Add object is also returned as a nested dictionary. The term containing the parenthesis is a Mul with a contraction among the arguments, so it will be found as a key in the result. It stores the dictionary resulting from a recursive call on the Add expression. >>> d = get_contraction_structure(x[i]*(y[i] + A[i, j]*x[j])) >>> sorted(d.keys(), key=default_sort_key) [(A[i, j]*x[j] + y[i])*x[i], (i,)] >>> d[(i,)] {(A[i, j]*x[j] + y[i])*x[i]} >>> d[x[i]*(A[i, j]*x[j] + y[i])] [{None: {y[i]}, (j,): {A[i, j]*x[j]}}] Powers with contractions in either base or exponent will also be found as keys in the dictionary, mapping to a list of results from recursive calls: >>> d = get_contraction_structure(A[j, j]**A[i, i]) >>> d[None] {A[j, j]**A[i, i]} >>> nested_contractions = d[A[j, j]**A[i, i]] >>> nested_contractions[0] {(j,): {A[j, j]}} >>> nested_contractions[1] {(i,): {A[i, i]}} The description of the contraction structure may appear complicated when represented with a string in the above examples, but it is easy to iterate over: >>> from sympy import Expr >>> for key in d: ... if isinstance(key, Expr): ... continue ... for term in d[key]: ... if term in d: ... # treat deepest contraction first ... pass ... # treat outermost contactions here """ # We call ourself recursively to inspect sub expressions. if isinstance(expr, Indexed): junk, key = _remove_repeated(expr.indices) return {key or None: {expr}} elif expr.is_Atom: return {None: {expr}} elif expr.is_Mul: junk, junk, key = _get_indices_Mul(expr, return_dummies=True) result = {key or None: {expr}} # recurse on every factor nested = [] for fac in expr.args: facd = get_contraction_structure(fac) if not (None in facd and len(facd) == 1): nested.append(facd) if nested: result[expr] = nested return result elif expr.is_Pow or isinstance(expr, exp): # recurse in base and exp separately. If either has internal # contractions we must include ourselves as a key in the returned dict b, e = expr.as_base_exp() dbase = get_contraction_structure(b) dexp = get_contraction_structure(e) dicts = [] for d in dbase, dexp: if not (None in d and len(d) == 1): dicts.append(d) result = {None: {expr}} if dicts: result[expr] = dicts return result elif expr.is_Add: # Note: we just collect all terms with identical summation indices, We # do nothing to identify equivalent terms here, as this would require # substitutions or pattern matching in expressions of unknown # complexity. result = {} for term in expr.args: # recurse on every term d = get_contraction_structure(term) for key in d: if key in result: result[key] |= d[key] else: result[key] = d[key] return result elif isinstance(expr, Piecewise): # FIXME: No support for Piecewise yet return {None: expr} elif isinstance(expr, Function): # Collect non-trivial contraction structures in each argument # We do not report repeated indices in separate arguments as a # contraction deeplist = [] for arg in expr.args: deep = get_contraction_structure(arg) if not (None in deep and len(deep) == 1): deeplist.append(deep) d = {None: {expr}} if deeplist: d[expr] = deeplist return d # this test is expensive, so it should be at the end elif not expr.has(Indexed): return {None: {expr}} raise NotImplementedError( "FIXME: No specialized handling of type %s" % type(expr)) sympy-sympy-1.9/sympy/tensor/indexed.py000066400000000000000000000577661412543434000204350ustar00rootroot00000000000000r"""Module that defines indexed objects The classes ``IndexedBase``, ``Indexed``, and ``Idx`` represent a matrix element ``M[i, j]`` as in the following diagram:: 1) The Indexed class represents the entire indexed object. | ___|___ ' ' M[i, j] / \__\______ | | | | | 2) The Idx class represents indices; each Idx can | optionally contain information about its range. | 3) IndexedBase represents the 'stem' of an indexed object, here `M`. The stem used by itself is usually taken to represent the entire array. There can be any number of indices on an Indexed object. No transformation properties are implemented in these Base objects, but implicit contraction of repeated indices is supported. Note that the support for complicated (i.e. non-atomic) integer expressions as indices is limited. (This should be improved in future releases.) Examples ======== To express the above matrix element example you would write: >>> from sympy import symbols, IndexedBase, Idx >>> M = IndexedBase('M') >>> i, j = symbols('i j', cls=Idx) >>> M[i, j] M[i, j] Repeated indices in a product implies a summation, so to express a matrix-vector product in terms of Indexed objects: >>> x = IndexedBase('x') >>> M[i, j]*x[j] M[i, j]*x[j] If the indexed objects will be converted to component based arrays, e.g. with the code printers or the autowrap framework, you also need to provide (symbolic or numerical) dimensions. This can be done by passing an optional shape parameter to IndexedBase upon construction: >>> dim1, dim2 = symbols('dim1 dim2', integer=True) >>> A = IndexedBase('A', shape=(dim1, 2*dim1, dim2)) >>> A.shape (dim1, 2*dim1, dim2) >>> A[i, j, 3].shape (dim1, 2*dim1, dim2) If an IndexedBase object has no shape information, it is assumed that the array is as large as the ranges of its indices: >>> n, m = symbols('n m', integer=True) >>> i = Idx('i', m) >>> j = Idx('j', n) >>> M[i, j].shape (m, n) >>> M[i, j].ranges [(0, m - 1), (0, n - 1)] The above can be compared with the following: >>> A[i, 2, j].shape (dim1, 2*dim1, dim2) >>> A[i, 2, j].ranges [(0, m - 1), None, (0, n - 1)] To analyze the structure of indexed expressions, you can use the methods get_indices() and get_contraction_structure(): >>> from sympy.tensor import get_indices, get_contraction_structure >>> get_indices(A[i, j, j]) ({i}, {}) >>> get_contraction_structure(A[i, j, j]) {(j,): {A[i, j, j]}} See the appropriate docstrings for a detailed explanation of the output. """ # TODO: (some ideas for improvement) # # o test and guarantee numpy compatibility # - implement full support for broadcasting # - strided arrays # # o more functions to analyze indexed expressions # - identify standard constructs, e.g matrix-vector product in a subexpression # # o functions to generate component based arrays (numpy and sympy.Matrix) # - generate a single array directly from Indexed # - convert simple sub-expressions # # o sophisticated indexing (possibly in subclasses to preserve simplicity) # - Idx with range smaller than dimension of Indexed # - Idx with stepsize != 1 # - Idx with step determined by function call from collections.abc import Iterable from sympy import Number from sympy.core.assumptions import StdFactKB from sympy.core import Expr, Tuple, sympify, S from sympy.core.symbol import _filter_assumptions, Symbol from sympy.core.compatibility import (is_sequence, NotIterable) from sympy.core.logic import fuzzy_bool, fuzzy_not from sympy.core.sympify import _sympify from sympy.functions.special.tensor_functions import KroneckerDelta from sympy.multipledispatch import dispatch class IndexException(Exception): pass class Indexed(Expr): """Represents a mathematical object with indices. >>> from sympy import Indexed, IndexedBase, Idx, symbols >>> i, j = symbols('i j', cls=Idx) >>> Indexed('A', i, j) A[i, j] It is recommended that ``Indexed`` objects be created by indexing ``IndexedBase``: ``IndexedBase('A')[i, j]`` instead of ``Indexed(IndexedBase('A'), i, j)``. >>> A = IndexedBase('A') >>> a_ij = A[i, j] # Prefer this, >>> b_ij = Indexed(A, i, j) # over this. >>> a_ij == b_ij True """ is_commutative = True is_Indexed = True is_symbol = True is_Atom = True def __new__(cls, base, *args, **kw_args): from sympy.utilities.misc import filldedent from sympy.tensor.array.ndim_array import NDimArray from sympy.matrices.matrices import MatrixBase if not args: raise IndexException("Indexed needs at least one index.") if isinstance(base, (str, Symbol)): base = IndexedBase(base) elif not hasattr(base, '__getitem__') and not isinstance(base, IndexedBase): raise TypeError(filldedent(""" The base can only be replaced with a string, Symbol, IndexedBase or an object with a method for getting items (i.e. an object with a `__getitem__` method). """)) args = list(map(sympify, args)) if isinstance(base, (NDimArray, Iterable, Tuple, MatrixBase)) and all([i.is_number for i in args]): if len(args) == 1: return base[args[0]] else: return base[args] obj = Expr.__new__(cls, base, *args, **kw_args) try: IndexedBase._set_assumptions(obj, base.assumptions0) except AttributeError: IndexedBase._set_assumptions(obj, {}) return obj def _hashable_content(self): return super()._hashable_content() + tuple(sorted(self.assumptions0.items())) @property def name(self): return str(self) @property def _diff_wrt(self): """Allow derivatives with respect to an ``Indexed`` object.""" return True def _eval_derivative(self, wrt): from sympy.tensor.array.ndim_array import NDimArray if isinstance(wrt, Indexed) and wrt.base == self.base: if len(self.indices) != len(wrt.indices): msg = "Different # of indices: d({!s})/d({!s})".format(self, wrt) raise IndexException(msg) result = S.One for index1, index2 in zip(self.indices, wrt.indices): result *= KroneckerDelta(index1, index2) return result elif isinstance(self.base, NDimArray): from sympy.tensor.array import derive_by_array return Indexed(derive_by_array(self.base, wrt), *self.args[1:]) else: if Tuple(self.indices).has(wrt): return S.NaN return S.Zero @property def assumptions0(self): return {k: v for k, v in self._assumptions.items() if v is not None} @property def base(self): """Returns the ``IndexedBase`` of the ``Indexed`` object. Examples ======== >>> from sympy import Indexed, IndexedBase, Idx, symbols >>> i, j = symbols('i j', cls=Idx) >>> Indexed('A', i, j).base A >>> B = IndexedBase('B') >>> B == B[i, j].base True """ return self.args[0] @property def indices(self): """ Returns the indices of the ``Indexed`` object. Examples ======== >>> from sympy import Indexed, Idx, symbols >>> i, j = symbols('i j', cls=Idx) >>> Indexed('A', i, j).indices (i, j) """ return self.args[1:] @property def rank(self): """ Returns the rank of the ``Indexed`` object. Examples ======== >>> from sympy import Indexed, Idx, symbols >>> i, j, k, l, m = symbols('i:m', cls=Idx) >>> Indexed('A', i, j).rank 2 >>> q = Indexed('A', i, j, k, l, m) >>> q.rank 5 >>> q.rank == len(q.indices) True """ return len(self.args) - 1 @property def shape(self): """Returns a list with dimensions of each index. Dimensions is a property of the array, not of the indices. Still, if the ``IndexedBase`` does not define a shape attribute, it is assumed that the ranges of the indices correspond to the shape of the array. >>> from sympy import IndexedBase, Idx, symbols >>> n, m = symbols('n m', integer=True) >>> i = Idx('i', m) >>> j = Idx('j', m) >>> A = IndexedBase('A', shape=(n, n)) >>> B = IndexedBase('B') >>> A[i, j].shape (n, n) >>> B[i, j].shape (m, m) """ from sympy.utilities.misc import filldedent if self.base.shape: return self.base.shape sizes = [] for i in self.indices: upper = getattr(i, 'upper', None) lower = getattr(i, 'lower', None) if None in (upper, lower): raise IndexException(filldedent(""" Range is not defined for all indices in: %s""" % self)) try: size = upper - lower + 1 except TypeError: raise IndexException(filldedent(""" Shape cannot be inferred from Idx with undefined range: %s""" % self)) sizes.append(size) return Tuple(*sizes) @property def ranges(self): """Returns a list of tuples with lower and upper range of each index. If an index does not define the data members upper and lower, the corresponding slot in the list contains ``None`` instead of a tuple. Examples ======== >>> from sympy import Indexed,Idx, symbols >>> Indexed('A', Idx('i', 2), Idx('j', 4), Idx('k', 8)).ranges [(0, 1), (0, 3), (0, 7)] >>> Indexed('A', Idx('i', 3), Idx('j', 3), Idx('k', 3)).ranges [(0, 2), (0, 2), (0, 2)] >>> x, y, z = symbols('x y z', integer=True) >>> Indexed('A', x, y, z).ranges [None, None, None] """ ranges = [] for i in self.indices: sentinel = object() upper = getattr(i, 'upper', sentinel) lower = getattr(i, 'lower', sentinel) if sentinel not in (upper, lower): ranges.append(Tuple(lower, upper)) else: ranges.append(None) return ranges def _sympystr(self, p): indices = list(map(p.doprint, self.indices)) return "%s[%s]" % (p.doprint(self.base), ", ".join(indices)) @property def free_symbols(self): base_free_symbols = self.base.free_symbols indices_free_symbols = { fs for i in self.indices for fs in i.free_symbols} if base_free_symbols: return {self} | base_free_symbols | indices_free_symbols else: return indices_free_symbols @property def expr_free_symbols(self): from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning(feature="expr_free_symbols method", issue=21494, deprecated_since_version="1.9").warn() return {self} class IndexedBase(Expr, NotIterable): """Represent the base or stem of an indexed object The IndexedBase class represent an array that contains elements. The main purpose of this class is to allow the convenient creation of objects of the Indexed class. The __getitem__ method of IndexedBase returns an instance of Indexed. Alone, without indices, the IndexedBase class can be used as a notation for e.g. matrix equations, resembling what you could do with the Symbol class. But, the IndexedBase class adds functionality that is not available for Symbol instances: - An IndexedBase object can optionally store shape information. This can be used in to check array conformance and conditions for numpy broadcasting. (TODO) - An IndexedBase object implements syntactic sugar that allows easy symbolic representation of array operations, using implicit summation of repeated indices. - The IndexedBase object symbolizes a mathematical structure equivalent to arrays, and is recognized as such for code generation and automatic compilation and wrapping. >>> from sympy.tensor import IndexedBase, Idx >>> from sympy import symbols >>> A = IndexedBase('A'); A A >>> type(A) When an IndexedBase object receives indices, it returns an array with named axes, represented by an Indexed object: >>> i, j = symbols('i j', integer=True) >>> A[i, j, 2] A[i, j, 2] >>> type(A[i, j, 2]) The IndexedBase constructor takes an optional shape argument. If given, it overrides any shape information in the indices. (But not the index ranges!) >>> m, n, o, p = symbols('m n o p', integer=True) >>> i = Idx('i', m) >>> j = Idx('j', n) >>> A[i, j].shape (m, n) >>> B = IndexedBase('B', shape=(o, p)) >>> B[i, j].shape (o, p) Assumptions can be specified with keyword arguments the same way as for Symbol: >>> A_real = IndexedBase('A', real=True) >>> A_real.is_real True >>> A != A_real True Assumptions can also be inherited if a Symbol is used to initialize the IndexedBase: >>> I = symbols('I', integer=True) >>> C_inherit = IndexedBase(I) >>> C_explicit = IndexedBase('I', integer=True) >>> C_inherit == C_explicit True """ is_commutative = True is_symbol = True is_Atom = True @staticmethod def _set_assumptions(obj, assumptions): """Set assumptions on obj, making sure to apply consistent values.""" tmp_asm_copy = assumptions.copy() is_commutative = fuzzy_bool(assumptions.get('commutative', True)) assumptions['commutative'] = is_commutative obj._assumptions = StdFactKB(assumptions) obj._assumptions._generator = tmp_asm_copy # Issue #8873 def __new__(cls, label, shape=None, *, offset=S.Zero, strides=None, **kw_args): from sympy import MatrixBase, NDimArray assumptions, kw_args = _filter_assumptions(kw_args) if isinstance(label, str): label = Symbol(label, **assumptions) elif isinstance(label, Symbol): assumptions = label._merge(assumptions) elif isinstance(label, (MatrixBase, NDimArray)): return label elif isinstance(label, Iterable): return _sympify(label) else: label = _sympify(label) if is_sequence(shape): shape = Tuple(*shape) elif shape is not None: shape = Tuple(shape) if shape is not None: obj = Expr.__new__(cls, label, shape) else: obj = Expr.__new__(cls, label) obj._shape = shape obj._offset = offset obj._strides = strides obj._name = str(label) IndexedBase._set_assumptions(obj, assumptions) return obj @property def name(self): return self._name def _hashable_content(self): return super()._hashable_content() + tuple(sorted(self.assumptions0.items())) @property def assumptions0(self): return {k: v for k, v in self._assumptions.items() if v is not None} def __getitem__(self, indices, **kw_args): if is_sequence(indices): # Special case needed because M[*my_tuple] is a syntax error. if self.shape and len(self.shape) != len(indices): raise IndexException("Rank mismatch.") return Indexed(self, *indices, **kw_args) else: if self.shape and len(self.shape) != 1: raise IndexException("Rank mismatch.") return Indexed(self, indices, **kw_args) @property def shape(self): """Returns the shape of the ``IndexedBase`` object. Examples ======== >>> from sympy import IndexedBase, Idx >>> from sympy.abc import x, y >>> IndexedBase('A', shape=(x, y)).shape (x, y) Note: If the shape of the ``IndexedBase`` is specified, it will override any shape information given by the indices. >>> A = IndexedBase('A', shape=(x, y)) >>> B = IndexedBase('B') >>> i = Idx('i', 2) >>> j = Idx('j', 1) >>> A[i, j].shape (x, y) >>> B[i, j].shape (2, 1) """ return self._shape @property def strides(self): """Returns the strided scheme for the ``IndexedBase`` object. Normally this is a tuple denoting the number of steps to take in the respective dimension when traversing an array. For code generation purposes strides='C' and strides='F' can also be used. strides='C' would mean that code printer would unroll in row-major order and 'F' means unroll in column major order. """ return self._strides @property def offset(self): """Returns the offset for the ``IndexedBase`` object. This is the value added to the resulting index when the 2D Indexed object is unrolled to a 1D form. Used in code generation. Examples ========== >>> from sympy.printing import ccode >>> from sympy.tensor import IndexedBase, Idx >>> from sympy import symbols >>> l, m, n, o = symbols('l m n o', integer=True) >>> A = IndexedBase('A', strides=(l, m, n), offset=o) >>> i, j, k = map(Idx, 'ijk') >>> ccode(A[i, j, k]) 'A[l*i + m*j + n*k + o]' """ return self._offset @property def label(self): """Returns the label of the ``IndexedBase`` object. Examples ======== >>> from sympy import IndexedBase >>> from sympy.abc import x, y >>> IndexedBase('A', shape=(x, y)).label A """ return self.args[0] def _sympystr(self, p): return p.doprint(self.label) class Idx(Expr): """Represents an integer index as an ``Integer`` or integer expression. There are a number of ways to create an ``Idx`` object. The constructor takes two arguments: ``label`` An integer or a symbol that labels the index. ``range`` Optionally you can specify a range as either * ``Symbol`` or integer: This is interpreted as a dimension. Lower and upper bounds are set to ``0`` and ``range - 1``, respectively. * ``tuple``: The two elements are interpreted as the lower and upper bounds of the range, respectively. Note: bounds of the range are assumed to be either integer or infinite (oo and -oo are allowed to specify an unbounded range). If ``n`` is given as a bound, then ``n.is_integer`` must not return false. For convenience, if the label is given as a string it is automatically converted to an integer symbol. (Note: this conversion is not done for range or dimension arguments.) Examples ======== >>> from sympy import Idx, symbols, oo >>> n, i, L, U = symbols('n i L U', integer=True) If a string is given for the label an integer ``Symbol`` is created and the bounds are both ``None``: >>> idx = Idx('qwerty'); idx qwerty >>> idx.lower, idx.upper (None, None) Both upper and lower bounds can be specified: >>> idx = Idx(i, (L, U)); idx i >>> idx.lower, idx.upper (L, U) When only a single bound is given it is interpreted as the dimension and the lower bound defaults to 0: >>> idx = Idx(i, n); idx.lower, idx.upper (0, n - 1) >>> idx = Idx(i, 4); idx.lower, idx.upper (0, 3) >>> idx = Idx(i, oo); idx.lower, idx.upper (0, oo) """ is_integer = True is_finite = True is_real = True is_symbol = True is_Atom = True _diff_wrt = True def __new__(cls, label, range=None, **kw_args): from sympy.utilities.misc import filldedent if isinstance(label, str): label = Symbol(label, integer=True) label, range = list(map(sympify, (label, range))) if label.is_Number: if not label.is_integer: raise TypeError("Index is not an integer number.") return label if not label.is_integer: raise TypeError("Idx object requires an integer label.") elif is_sequence(range): if len(range) != 2: raise ValueError(filldedent(""" Idx range tuple must have length 2, but got %s""" % len(range))) for bound in range: if (bound.is_integer is False and bound is not S.Infinity and bound is not S.NegativeInfinity): raise TypeError("Idx object requires integer bounds.") args = label, Tuple(*range) elif isinstance(range, Expr): if range is not S.Infinity and fuzzy_not(range.is_integer): raise TypeError("Idx object requires an integer dimension.") args = label, Tuple(0, range - 1) elif range: raise TypeError(filldedent(""" The range must be an ordered iterable or integer SymPy expression.""")) else: args = label, obj = Expr.__new__(cls, *args, **kw_args) obj._assumptions["finite"] = True obj._assumptions["real"] = True return obj @property def label(self): """Returns the label (Integer or integer expression) of the Idx object. Examples ======== >>> from sympy import Idx, Symbol >>> x = Symbol('x', integer=True) >>> Idx(x).label x >>> j = Symbol('j', integer=True) >>> Idx(j).label j >>> Idx(j + 1).label j + 1 """ return self.args[0] @property def lower(self): """Returns the lower bound of the ``Idx``. Examples ======== >>> from sympy import Idx >>> Idx('j', 2).lower 0 >>> Idx('j', 5).lower 0 >>> Idx('j').lower is None True """ try: return self.args[1][0] except IndexError: return @property def upper(self): """Returns the upper bound of the ``Idx``. Examples ======== >>> from sympy import Idx >>> Idx('j', 2).upper 1 >>> Idx('j', 5).upper 4 >>> Idx('j').upper is None True """ try: return self.args[1][1] except IndexError: return def _sympystr(self, p): return p.doprint(self.label) @property def name(self): return self.label.name if self.label.is_Symbol else str(self.label) @property def free_symbols(self): return {self} @dispatch(Idx, Idx) def _eval_is_ge(lhs, rhs): # noqa:F811 other_upper = rhs if rhs.upper is None else rhs.upper other_lower = rhs if rhs.lower is None else rhs.lower if lhs.lower is not None and (lhs.lower >= other_upper) == True: return True if lhs.upper is not None and (lhs.upper < other_lower) == True: return False return None @dispatch(Idx, Number) # type:ignore def _eval_is_ge(lhs, rhs): # noqa:F811 other_upper = rhs other_lower = rhs if lhs.lower is not None and (lhs.lower >= other_upper) == True: return True if lhs.upper is not None and (lhs.upper < other_lower) == True: return False return None @dispatch(Number, Idx) # type:ignore def _eval_is_ge(lhs, rhs): # noqa:F811 other_upper = lhs other_lower = lhs if rhs.upper is not None and (rhs.upper <= other_lower) == True: return True if rhs.lower is not None and (rhs.lower > other_upper) == True: return False return None sympy-sympy-1.9/sympy/tensor/tensor.py000066400000000000000000004331121412543434000203060ustar00rootroot00000000000000""" This module defines tensors with abstract index notation. The abstract index notation has been first formalized by Penrose. Tensor indices are formal objects, with a tensor type; there is no notion of index range, it is only possible to assign the dimension, used to trace the Kronecker delta; the dimension can be a Symbol. The Einstein summation convention is used. The covariant indices are indicated with a minus sign in front of the index. For instance the tensor ``t = p(a)*A(b,c)*q(-c)`` has the index ``c`` contracted. A tensor expression ``t`` can be called; called with its indices in sorted order it is equal to itself: in the above example ``t(a, b) == t``; one can call ``t`` with different indices; ``t(c, d) == p(c)*A(d,a)*q(-a)``. The contracted indices are dummy indices, internally they have no name, the indices being represented by a graph-like structure. Tensors are put in canonical form using ``canon_bp``, which uses the Butler-Portugal algorithm for canonicalization using the monoterm symmetries of the tensors. If there is a (anti)symmetric metric, the indices can be raised and lowered when the tensor is put in canonical form. """ from typing import Any, Dict as tDict, List, Set from functools import reduce from abc import abstractmethod, ABCMeta from collections import defaultdict import operator import itertools from sympy import Rational, prod, Integer, default_sort_key from sympy.combinatorics import Permutation from sympy.combinatorics.tensor_can import get_symmetric_group_sgs, \ bsgs_direct_product, canonicalize, riemann_bsgs from sympy.core import Basic, Expr, sympify, Add, Mul, S from sympy.core.assumptions import ManagedProperties from sympy.core.compatibility import SYMPY_INTS from sympy.core.containers import Tuple, Dict from sympy.core.decorators import deprecated from sympy.core.symbol import Symbol, symbols from sympy.core.sympify import CantSympify, _sympify from sympy.core.operations import AssocOp from sympy.matrices import eye from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.utilities.decorator import memoize_property import warnings @deprecated(useinstead=".replace_with_arrays", issue=15276, deprecated_since_version="1.4") def deprecate_data(): pass @deprecated(useinstead=".substitute_indices()", issue=17515, deprecated_since_version="1.5") def deprecate_fun_eval(): pass @deprecated(useinstead="tensor_heads()", issue=17108, deprecated_since_version="1.5") def deprecate_TensorType(): pass class _IndexStructure(CantSympify): """ This class handles the indices (free and dummy ones). It contains the algorithms to manage the dummy indices replacements and contractions of free indices under multiplications of tensor expressions, as well as stuff related to canonicalization sorting, getting the permutation of the expression and so on. It also includes tools to get the ``TensorIndex`` objects corresponding to the given index structure. """ def __init__(self, free, dum, index_types, indices, canon_bp=False): self.free = free self.dum = dum self.index_types = index_types self.indices = indices self._ext_rank = len(self.free) + 2*len(self.dum) self.dum.sort(key=lambda x: x[0]) @staticmethod def from_indices(*indices): """ Create a new ``_IndexStructure`` object from a list of ``indices``. Explanation =========== ``indices`` ``TensorIndex`` objects, the indices. Contractions are detected upon construction. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, _IndexStructure >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> m0, m1, m2, m3 = tensor_indices('m0,m1,m2,m3', Lorentz) >>> _IndexStructure.from_indices(m0, m1, -m1, m3) _IndexStructure([(m0, 0), (m3, 3)], [(1, 2)], [Lorentz, Lorentz, Lorentz, Lorentz]) """ free, dum = _IndexStructure._free_dum_from_indices(*indices) index_types = [i.tensor_index_type for i in indices] indices = _IndexStructure._replace_dummy_names(indices, free, dum) return _IndexStructure(free, dum, index_types, indices) @staticmethod def from_components_free_dum(components, free, dum): index_types = [] for component in components: index_types.extend(component.index_types) indices = _IndexStructure.generate_indices_from_free_dum_index_types(free, dum, index_types) return _IndexStructure(free, dum, index_types, indices) @staticmethod def _free_dum_from_indices(*indices): """ Convert ``indices`` into ``free``, ``dum`` for single component tensor. Explanation =========== ``free`` list of tuples ``(index, pos, 0)``, where ``pos`` is the position of index in the list of indices formed by the component tensors ``dum`` list of tuples ``(pos_contr, pos_cov, 0, 0)`` Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, \ _IndexStructure >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> m0, m1, m2, m3 = tensor_indices('m0,m1,m2,m3', Lorentz) >>> _IndexStructure._free_dum_from_indices(m0, m1, -m1, m3) ([(m0, 0), (m3, 3)], [(1, 2)]) """ n = len(indices) if n == 1: return [(indices[0], 0)], [] # find the positions of the free indices and of the dummy indices free = [True]*len(indices) index_dict = {} dum = [] for i, index in enumerate(indices): name = index.name typ = index.tensor_index_type contr = index.is_up if (name, typ) in index_dict: # found a pair of dummy indices is_contr, pos = index_dict[(name, typ)] # check consistency and update free if is_contr: if contr: raise ValueError('two equal contravariant indices in slots %d and %d' %(pos, i)) else: free[pos] = False free[i] = False else: if contr: free[pos] = False free[i] = False else: raise ValueError('two equal covariant indices in slots %d and %d' %(pos, i)) if contr: dum.append((i, pos)) else: dum.append((pos, i)) else: index_dict[(name, typ)] = index.is_up, i free = [(index, i) for i, index in enumerate(indices) if free[i]] free.sort() return free, dum def get_indices(self): """ Get a list of indices, creating new tensor indices to complete dummy indices. """ return self.indices[:] @staticmethod def generate_indices_from_free_dum_index_types(free, dum, index_types): indices = [None]*(len(free)+2*len(dum)) for idx, pos in free: indices[pos] = idx generate_dummy_name = _IndexStructure._get_generator_for_dummy_indices(free) for pos1, pos2 in dum: typ1 = index_types[pos1] indname = generate_dummy_name(typ1) indices[pos1] = TensorIndex(indname, typ1, True) indices[pos2] = TensorIndex(indname, typ1, False) return _IndexStructure._replace_dummy_names(indices, free, dum) @staticmethod def _get_generator_for_dummy_indices(free): cdt = defaultdict(int) # if the free indices have names with dummy_name, start with an # index higher than those for the dummy indices # to avoid name collisions for indx, ipos in free: if indx.name.split('_')[0] == indx.tensor_index_type.dummy_name: cdt[indx.tensor_index_type] = max(cdt[indx.tensor_index_type], int(indx.name.split('_')[1]) + 1) def dummy_name_gen(tensor_index_type): nd = str(cdt[tensor_index_type]) cdt[tensor_index_type] += 1 return tensor_index_type.dummy_name + '_' + nd return dummy_name_gen @staticmethod def _replace_dummy_names(indices, free, dum): dum.sort(key=lambda x: x[0]) new_indices = [ind for ind in indices] assert len(indices) == len(free) + 2*len(dum) generate_dummy_name = _IndexStructure._get_generator_for_dummy_indices(free) for ipos1, ipos2 in dum: typ1 = new_indices[ipos1].tensor_index_type indname = generate_dummy_name(typ1) new_indices[ipos1] = TensorIndex(indname, typ1, True) new_indices[ipos2] = TensorIndex(indname, typ1, False) return new_indices def get_free_indices(self): # type: () -> List[TensorIndex] """ Get a list of free indices. """ # get sorted indices according to their position: free = sorted(self.free, key=lambda x: x[1]) return [i[0] for i in free] def __str__(self): return "_IndexStructure({}, {}, {})".format(self.free, self.dum, self.index_types) def __repr__(self): return self.__str__() def _get_sorted_free_indices_for_canon(self): sorted_free = self.free[:] sorted_free.sort(key=lambda x: x[0]) return sorted_free def _get_sorted_dum_indices_for_canon(self): return sorted(self.dum, key=lambda x: x[0]) def _get_lexicographically_sorted_index_types(self): permutation = self.indices_canon_args()[0] index_types = [None]*self._ext_rank for i, it in enumerate(self.index_types): index_types[permutation(i)] = it return index_types def _get_lexicographically_sorted_indices(self): permutation = self.indices_canon_args()[0] indices = [None]*self._ext_rank for i, it in enumerate(self.indices): indices[permutation(i)] = it return indices def perm2tensor(self, g, is_canon_bp=False): """ Returns a ``_IndexStructure`` instance corresponding to the permutation ``g``. Explanation =========== ``g`` permutation corresponding to the tensor in the representation used in canonicalization ``is_canon_bp`` if True, then ``g`` is the permutation corresponding to the canonical form of the tensor """ sorted_free = [i[0] for i in self._get_sorted_free_indices_for_canon()] lex_index_types = self._get_lexicographically_sorted_index_types() lex_indices = self._get_lexicographically_sorted_indices() nfree = len(sorted_free) rank = self._ext_rank dum = [[None]*2 for i in range((rank - nfree)//2)] free = [] index_types = [None]*rank indices = [None]*rank for i in range(rank): gi = g[i] index_types[i] = lex_index_types[gi] indices[i] = lex_indices[gi] if gi < nfree: ind = sorted_free[gi] assert index_types[i] == sorted_free[gi].tensor_index_type free.append((ind, i)) else: j = gi - nfree idum, cov = divmod(j, 2) if cov: dum[idum][1] = i else: dum[idum][0] = i dum = [tuple(x) for x in dum] return _IndexStructure(free, dum, index_types, indices) def indices_canon_args(self): """ Returns ``(g, dummies, msym, v)``, the entries of ``canonicalize`` See ``canonicalize`` in ``tensor_can.py`` in combinatorics module. """ # to be called after sorted_components from sympy.combinatorics.permutations import _af_new n = self._ext_rank g = [None]*n + [n, n+1] # Converts the symmetry of the metric into msym from .canonicalize() # method in the combinatorics module def metric_symmetry_to_msym(metric): if metric is None: return None sym = metric.symmetry if sym == TensorSymmetry.fully_symmetric(2): return 0 if sym == TensorSymmetry.fully_symmetric(-2): return 1 return None # ordered indices: first the free indices, ordered by types # then the dummy indices, ordered by types and contravariant before # covariant # g[position in tensor] = position in ordered indices for i, (indx, ipos) in enumerate(self._get_sorted_free_indices_for_canon()): g[ipos] = i pos = len(self.free) j = len(self.free) dummies = [] prev = None a = [] msym = [] for ipos1, ipos2 in self._get_sorted_dum_indices_for_canon(): g[ipos1] = j g[ipos2] = j + 1 j += 2 typ = self.index_types[ipos1] if typ != prev: if a: dummies.append(a) a = [pos, pos + 1] prev = typ msym.append(metric_symmetry_to_msym(typ.metric)) else: a.extend([pos, pos + 1]) pos += 2 if a: dummies.append(a) return _af_new(g), dummies, msym def components_canon_args(components): numtyp = [] prev = None for t in components: if t == prev: numtyp[-1][1] += 1 else: prev = t numtyp.append([prev, 1]) v = [] for h, n in numtyp: if h.comm == 0 or h.comm == 1: comm = h.comm else: comm = TensorManager.get_comm(h.comm, h.comm) v.append((h.symmetry.base, h.symmetry.generators, n, comm)) return v class _TensorDataLazyEvaluator(CantSympify): """ EXPERIMENTAL: do not rely on this class, it may change without deprecation warnings in future versions of SymPy. Explanation =========== This object contains the logic to associate components data to a tensor expression. Components data are set via the ``.data`` property of tensor expressions, is stored inside this class as a mapping between the tensor expression and the ``ndarray``. Computations are executed lazily: whereas the tensor expressions can have contractions, tensor products, and additions, components data are not computed until they are accessed by reading the ``.data`` property associated to the tensor expression. """ _substitutions_dict = dict() # type: tDict[Any, Any] _substitutions_dict_tensmul = dict() # type: tDict[Any, Any] def __getitem__(self, key): dat = self._get(key) if dat is None: return None from .array import NDimArray if not isinstance(dat, NDimArray): return dat if dat.rank() == 0: return dat[()] elif dat.rank() == 1 and len(dat) == 1: return dat[0] return dat def _get(self, key): """ Retrieve ``data`` associated with ``key``. Explanation =========== This algorithm looks into ``self._substitutions_dict`` for all ``TensorHead`` in the ``TensExpr`` (or just ``TensorHead`` if key is a TensorHead instance). It reconstructs the components data that the tensor expression should have by performing on components data the operations that correspond to the abstract tensor operations applied. Metric tensor is handled in a different manner: it is pre-computed in ``self._substitutions_dict_tensmul``. """ if key in self._substitutions_dict: return self._substitutions_dict[key] if isinstance(key, TensorHead): return None if isinstance(key, Tensor): # special case to handle metrics. Metric tensors cannot be # constructed through contraction by the metric, their # components show if they are a matrix or its inverse. signature = tuple([i.is_up for i in key.get_indices()]) srch = (key.component,) + signature if srch in self._substitutions_dict_tensmul: return self._substitutions_dict_tensmul[srch] array_list = [self.data_from_tensor(key)] return self.data_contract_dum(array_list, key.dum, key.ext_rank) if isinstance(key, TensMul): tensmul_args = key.args if len(tensmul_args) == 1 and len(tensmul_args[0].components) == 1: # special case to handle metrics. Metric tensors cannot be # constructed through contraction by the metric, their # components show if they are a matrix or its inverse. signature = tuple([i.is_up for i in tensmul_args[0].get_indices()]) srch = (tensmul_args[0].components[0],) + signature if srch in self._substitutions_dict_tensmul: return self._substitutions_dict_tensmul[srch] #data_list = [self.data_from_tensor(i) for i in tensmul_args if isinstance(i, TensExpr)] data_list = [self.data_from_tensor(i) if isinstance(i, Tensor) else i.data for i in tensmul_args if isinstance(i, TensExpr)] coeff = prod([i for i in tensmul_args if not isinstance(i, TensExpr)]) if all([i is None for i in data_list]): return None if any([i is None for i in data_list]): raise ValueError("Mixing tensors with associated components "\ "data with tensors without components data") data_result = self.data_contract_dum(data_list, key.dum, key.ext_rank) return coeff*data_result if isinstance(key, TensAdd): data_list = [] free_args_list = [] for arg in key.args: if isinstance(arg, TensExpr): data_list.append(arg.data) free_args_list.append([x[0] for x in arg.free]) else: data_list.append(arg) free_args_list.append([]) if all([i is None for i in data_list]): return None if any([i is None for i in data_list]): raise ValueError("Mixing tensors with associated components "\ "data with tensors without components data") sum_list = [] from .array import permutedims for data, free_args in zip(data_list, free_args_list): if len(free_args) < 2: sum_list.append(data) else: free_args_pos = {y: x for x, y in enumerate(free_args)} axes = [free_args_pos[arg] for arg in key.free_args] sum_list.append(permutedims(data, axes)) return reduce(lambda x, y: x+y, sum_list) return None @staticmethod def data_contract_dum(ndarray_list, dum, ext_rank): from .array import tensorproduct, tensorcontraction, MutableDenseNDimArray arrays = list(map(MutableDenseNDimArray, ndarray_list)) prodarr = tensorproduct(*arrays) return tensorcontraction(prodarr, *dum) def data_tensorhead_from_tensmul(self, data, tensmul, tensorhead): """ This method is used when assigning components data to a ``TensMul`` object, it converts components data to a fully contravariant ndarray, which is then stored according to the ``TensorHead`` key. """ if data is None: return None return self._correct_signature_from_indices( data, tensmul.get_indices(), tensmul.free, tensmul.dum, True) def data_from_tensor(self, tensor): """ This method corrects the components data to the right signature (covariant/contravariant) using the metric associated with each ``TensorIndexType``. """ tensorhead = tensor.component if tensorhead.data is None: return None return self._correct_signature_from_indices( tensorhead.data, tensor.get_indices(), tensor.free, tensor.dum) def _assign_data_to_tensor_expr(self, key, data): if isinstance(key, TensAdd): raise ValueError('cannot assign data to TensAdd') # here it is assumed that `key` is a `TensMul` instance. if len(key.components) != 1: raise ValueError('cannot assign data to TensMul with multiple components') tensorhead = key.components[0] newdata = self.data_tensorhead_from_tensmul(data, key, tensorhead) return tensorhead, newdata def _check_permutations_on_data(self, tens, data): from .array import permutedims from .array.arrayop import Flatten if isinstance(tens, TensorHead): rank = tens.rank generators = tens.symmetry.generators elif isinstance(tens, Tensor): rank = tens.rank generators = tens.components[0].symmetry.generators elif isinstance(tens, TensorIndexType): rank = tens.metric.rank generators = tens.metric.symmetry.generators # Every generator is a permutation, check that by permuting the array # by that permutation, the array will be the same, except for a # possible sign change if the permutation admits it. for gener in generators: sign_change = +1 if (gener(rank) == rank) else -1 data_swapped = data last_data = data permute_axes = list(map(gener, list(range(rank)))) # the order of a permutation is the number of times to get the # identity by applying that permutation. for i in range(gener.order()-1): data_swapped = permutedims(data_swapped, permute_axes) # if any value in the difference array is non-zero, raise an error: if any(Flatten(last_data - sign_change*data_swapped)): raise ValueError("Component data symmetry structure error") last_data = data_swapped def __setitem__(self, key, value): """ Set the components data of a tensor object/expression. Explanation =========== Components data are transformed to the all-contravariant form and stored with the corresponding ``TensorHead`` object. If a ``TensorHead`` object cannot be uniquely identified, it will raise an error. """ data = _TensorDataLazyEvaluator.parse_data(value) self._check_permutations_on_data(key, data) # TensorHead and TensorIndexType can be assigned data directly, while # TensMul must first convert data to a fully contravariant form, and # assign it to its corresponding TensorHead single component. if not isinstance(key, (TensorHead, TensorIndexType)): key, data = self._assign_data_to_tensor_expr(key, data) if isinstance(key, TensorHead): for dim, indextype in zip(data.shape, key.index_types): if indextype.data is None: raise ValueError("index type {} has no components data"\ " associated (needed to raise/lower index)".format(indextype)) if not indextype.dim.is_number: continue if dim != indextype.dim: raise ValueError("wrong dimension of ndarray") self._substitutions_dict[key] = data def __delitem__(self, key): del self._substitutions_dict[key] def __contains__(self, key): return key in self._substitutions_dict def add_metric_data(self, metric, data): """ Assign data to the ``metric`` tensor. The metric tensor behaves in an anomalous way when raising and lowering indices. Explanation =========== A fully covariant metric is the inverse transpose of the fully contravariant metric (it is meant matrix inverse). If the metric is symmetric, the transpose is not necessary and mixed covariant/contravariant metrics are Kronecker deltas. """ # hard assignment, data should not be added to `TensorHead` for metric: # the problem with `TensorHead` is that the metric is anomalous, i.e. # raising and lowering the index means considering the metric or its # inverse, this is not the case for other tensors. self._substitutions_dict_tensmul[metric, True, True] = data inverse_transpose = self.inverse_transpose_matrix(data) # in symmetric spaces, the transpose is the same as the original matrix, # the full covariant metric tensor is the inverse transpose, so this # code will be able to handle non-symmetric metrics. self._substitutions_dict_tensmul[metric, False, False] = inverse_transpose # now mixed cases, these are identical to the unit matrix if the metric # is symmetric. m = data.tomatrix() invt = inverse_transpose.tomatrix() self._substitutions_dict_tensmul[metric, True, False] = m * invt self._substitutions_dict_tensmul[metric, False, True] = invt * m @staticmethod def _flip_index_by_metric(data, metric, pos): from .array import tensorproduct, tensorcontraction mdim = metric.rank() ddim = data.rank() if pos == 0: data = tensorcontraction( tensorproduct( metric, data ), (1, mdim+pos) ) else: data = tensorcontraction( tensorproduct( data, metric ), (pos, ddim) ) return data @staticmethod def inverse_matrix(ndarray): m = ndarray.tomatrix().inv() return _TensorDataLazyEvaluator.parse_data(m) @staticmethod def inverse_transpose_matrix(ndarray): m = ndarray.tomatrix().inv().T return _TensorDataLazyEvaluator.parse_data(m) @staticmethod def _correct_signature_from_indices(data, indices, free, dum, inverse=False): """ Utility function to correct the values inside the components data ndarray according to whether indices are covariant or contravariant. It uses the metric matrix to lower values of covariant indices. """ # change the ndarray values according covariantness/contravariantness of the indices # use the metric for i, indx in enumerate(indices): if not indx.is_up and not inverse: data = _TensorDataLazyEvaluator._flip_index_by_metric(data, indx.tensor_index_type.data, i) elif not indx.is_up and inverse: data = _TensorDataLazyEvaluator._flip_index_by_metric( data, _TensorDataLazyEvaluator.inverse_matrix(indx.tensor_index_type.data), i ) return data @staticmethod def _sort_data_axes(old, new): from .array import permutedims new_data = old.data.copy() old_free = [i[0] for i in old.free] new_free = [i[0] for i in new.free] for i in range(len(new_free)): for j in range(i, len(old_free)): if old_free[j] == new_free[i]: old_free[i], old_free[j] = old_free[j], old_free[i] new_data = permutedims(new_data, (i, j)) break return new_data @staticmethod def add_rearrange_tensmul_parts(new_tensmul, old_tensmul): def sorted_compo(): return _TensorDataLazyEvaluator._sort_data_axes(old_tensmul, new_tensmul) _TensorDataLazyEvaluator._substitutions_dict[new_tensmul] = sorted_compo() @staticmethod def parse_data(data): """ Transform ``data`` to array. The parameter ``data`` may contain data in various formats, e.g. nested lists, sympy ``Matrix``, and so on. Examples ======== >>> from sympy.tensor.tensor import _TensorDataLazyEvaluator >>> _TensorDataLazyEvaluator.parse_data([1, 3, -6, 12]) [1, 3, -6, 12] >>> _TensorDataLazyEvaluator.parse_data([[1, 2], [4, 7]]) [[1, 2], [4, 7]] """ from .array import MutableDenseNDimArray if not isinstance(data, MutableDenseNDimArray): if len(data) == 2 and hasattr(data[0], '__call__'): data = MutableDenseNDimArray(data[0], data[1]) else: data = MutableDenseNDimArray(data) return data _tensor_data_substitution_dict = _TensorDataLazyEvaluator() class _TensorManager: """ Class to manage tensor properties. Notes ===== Tensors belong to tensor commutation groups; each group has a label ``comm``; there are predefined labels: ``0`` tensors commuting with any other tensor ``1`` tensors anticommuting among themselves ``2`` tensors not commuting, apart with those with ``comm=0`` Other groups can be defined using ``set_comm``; tensors in those groups commute with those with ``comm=0``; by default they do not commute with any other group. """ def __init__(self): self._comm_init() def _comm_init(self): self._comm = [{} for i in range(3)] for i in range(3): self._comm[0][i] = 0 self._comm[i][0] = 0 self._comm[1][1] = 1 self._comm[2][1] = None self._comm[1][2] = None self._comm_symbols2i = {0:0, 1:1, 2:2} self._comm_i2symbol = {0:0, 1:1, 2:2} @property def comm(self): return self._comm def comm_symbols2i(self, i): """ Get the commutation group number corresponding to ``i``. ``i`` can be a symbol or a number or a string. If ``i`` is not already defined its commutation group number is set. """ if i not in self._comm_symbols2i: n = len(self._comm) self._comm.append({}) self._comm[n][0] = 0 self._comm[0][n] = 0 self._comm_symbols2i[i] = n self._comm_i2symbol[n] = i return n return self._comm_symbols2i[i] def comm_i2symbol(self, i): """ Returns the symbol corresponding to the commutation group number. """ return self._comm_i2symbol[i] def set_comm(self, i, j, c): """ Set the commutation parameter ``c`` for commutation groups ``i, j``. Parameters ========== i, j : symbols representing commutation groups c : group commutation number Notes ===== ``i, j`` can be symbols, strings or numbers, apart from ``0, 1`` and ``2`` which are reserved respectively for commuting, anticommuting tensors and tensors not commuting with any other group apart with the commuting tensors. For the remaining cases, use this method to set the commutation rules; by default ``c=None``. The group commutation number ``c`` is assigned in correspondence to the group commutation symbols; it can be 0 commuting 1 anticommuting None no commutation property Examples ======== ``G`` and ``GH`` do not commute with themselves and commute with each other; A is commuting. >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorManager, TensorSymmetry >>> Lorentz = TensorIndexType('Lorentz') >>> i0,i1,i2,i3,i4 = tensor_indices('i0:5', Lorentz) >>> A = TensorHead('A', [Lorentz]) >>> G = TensorHead('G', [Lorentz], TensorSymmetry.no_symmetry(1), 'Gcomm') >>> GH = TensorHead('GH', [Lorentz], TensorSymmetry.no_symmetry(1), 'GHcomm') >>> TensorManager.set_comm('Gcomm', 'GHcomm', 0) >>> (GH(i1)*G(i0)).canon_bp() G(i0)*GH(i1) >>> (G(i1)*G(i0)).canon_bp() G(i1)*G(i0) >>> (G(i1)*A(i0)).canon_bp() A(i0)*G(i1) """ if c not in (0, 1, None): raise ValueError('`c` can assume only the values 0, 1 or None') if i not in self._comm_symbols2i: n = len(self._comm) self._comm.append({}) self._comm[n][0] = 0 self._comm[0][n] = 0 self._comm_symbols2i[i] = n self._comm_i2symbol[n] = i if j not in self._comm_symbols2i: n = len(self._comm) self._comm.append({}) self._comm[0][n] = 0 self._comm[n][0] = 0 self._comm_symbols2i[j] = n self._comm_i2symbol[n] = j ni = self._comm_symbols2i[i] nj = self._comm_symbols2i[j] self._comm[ni][nj] = c self._comm[nj][ni] = c def set_comms(self, *args): """ Set the commutation group numbers ``c`` for symbols ``i, j``. Parameters ========== args : sequence of ``(i, j, c)`` """ for i, j, c in args: self.set_comm(i, j, c) def get_comm(self, i, j): """ Return the commutation parameter for commutation group numbers ``i, j`` see ``_TensorManager.set_comm`` """ return self._comm[i].get(j, 0 if i == 0 or j == 0 else None) def clear(self): """ Clear the TensorManager. """ self._comm_init() TensorManager = _TensorManager() class TensorIndexType(Basic): """ A TensorIndexType is characterized by its name and its metric. Parameters ========== name : name of the tensor type dummy_name : name of the head of dummy indices dim : dimension, it can be a symbol or an integer or ``None`` eps_dim : dimension of the epsilon tensor metric_symmetry : integer that denotes metric symmetry or ``None`` for no metirc metric_name : string with the name of the metric tensor Attributes ========== ``metric`` : the metric tensor ``delta`` : ``Kronecker delta`` ``epsilon`` : the ``Levi-Civita epsilon`` tensor ``data`` : (deprecated) a property to add ``ndarray`` values, to work in a specified basis. Notes ===== The possible values of the ``metric_symmetry`` parameter are: ``1`` : metric tensor is fully symmetric ``0`` : metric tensor possesses no index symmetry ``-1`` : metric tensor is fully antisymmetric ``None``: there is no metric tensor (metric equals to ``None``) The metric is assumed to be symmetric by default. It can also be set to a custom tensor by the ``.set_metric()`` method. If there is a metric the metric is used to raise and lower indices. In the case of non-symmetric metric, the following raising and lowering conventions will be adopted: ``psi(a) = g(a, b)*psi(-b); chi(-a) = chi(b)*g(-b, -a)`` From these it is easy to find: ``g(-a, b) = delta(-a, b)`` where ``delta(-a, b) = delta(b, -a)`` is the ``Kronecker delta`` (see ``TensorIndex`` for the conventions on indices). For antisymmetric metrics there is also the following equality: ``g(a, -b) = -delta(a, -b)`` If there is no metric it is not possible to raise or lower indices; e.g. the index of the defining representation of ``SU(N)`` is 'covariant' and the conjugate representation is 'contravariant'; for ``N > 2`` they are linearly independent. ``eps_dim`` is by default equal to ``dim``, if the latter is an integer; else it can be assigned (for use in naive dimensional regularization); if ``eps_dim`` is not an integer ``epsilon`` is ``None``. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> Lorentz.metric metric(Lorentz,Lorentz) """ def __new__(cls, name, dummy_name=None, dim=None, eps_dim=None, metric_symmetry=1, metric_name='metric', **kwargs): if 'dummy_fmt' in kwargs: SymPyDeprecationWarning(useinstead="dummy_name", feature="dummy_fmt", issue=17517, deprecated_since_version="1.5").warn() dummy_name = kwargs.get('dummy_fmt') if isinstance(name, str): name = Symbol(name) if dummy_name is None: dummy_name = str(name)[0] if isinstance(dummy_name, str): dummy_name = Symbol(dummy_name) if dim is None: dim = Symbol("dim_" + dummy_name.name) else: dim = sympify(dim) if eps_dim is None: eps_dim = dim else: eps_dim = sympify(eps_dim) metric_symmetry = sympify(metric_symmetry) if isinstance(metric_name, str): metric_name = Symbol(metric_name) if 'metric' in kwargs: SymPyDeprecationWarning(useinstead="metric_symmetry or .set_metric()", feature="metric argument", issue=17517, deprecated_since_version="1.5").warn() metric = kwargs.get('metric') if metric is not None: if metric in (True, False, 0, 1): metric_name = 'metric' #metric_antisym = metric else: metric_name = metric.name #metric_antisym = metric.antisym if metric: metric_symmetry = -1 else: metric_symmetry = 1 obj = Basic.__new__(cls, name, dummy_name, dim, eps_dim, metric_symmetry, metric_name) obj._autogenerated = [] return obj @property def name(self): return self.args[0].name @property def dummy_name(self): return self.args[1].name @property def dim(self): return self.args[2] @property def eps_dim(self): return self.args[3] @memoize_property def metric(self): metric_symmetry = self.args[4] metric_name = self.args[5] if metric_symmetry is None: return None if metric_symmetry == 0: symmetry = TensorSymmetry.no_symmetry(2) elif metric_symmetry == 1: symmetry = TensorSymmetry.fully_symmetric(2) elif metric_symmetry == -1: symmetry = TensorSymmetry.fully_symmetric(-2) return TensorHead(metric_name, [self]*2, symmetry) @memoize_property def delta(self): return TensorHead('KD', [self]*2, TensorSymmetry.fully_symmetric(2)) @memoize_property def epsilon(self): if not isinstance(self.eps_dim, (SYMPY_INTS, Integer)): return None symmetry = TensorSymmetry.fully_symmetric(-self.eps_dim) return TensorHead('Eps', [self]*self.eps_dim, symmetry) def set_metric(self, tensor): self._metric = tensor def __lt__(self, other): return self.name < other.name def __str__(self): return self.name __repr__ = __str__ # Everything below this line is deprecated @property def data(self): deprecate_data() return _tensor_data_substitution_dict[self] @data.setter def data(self, data): deprecate_data() # This assignment is a bit controversial, should metric components be assigned # to the metric only or also to the TensorIndexType object? The advantage here # is the ability to assign a 1D array and transform it to a 2D diagonal array. from .array import MutableDenseNDimArray data = _TensorDataLazyEvaluator.parse_data(data) if data.rank() > 2: raise ValueError("data have to be of rank 1 (diagonal metric) or 2.") if data.rank() == 1: if self.dim.is_number: nda_dim = data.shape[0] if nda_dim != self.dim: raise ValueError("Dimension mismatch") dim = data.shape[0] newndarray = MutableDenseNDimArray.zeros(dim, dim) for i, val in enumerate(data): newndarray[i, i] = val data = newndarray dim1, dim2 = data.shape if dim1 != dim2: raise ValueError("Non-square matrix tensor.") if self.dim.is_number: if self.dim != dim1: raise ValueError("Dimension mismatch") _tensor_data_substitution_dict[self] = data _tensor_data_substitution_dict.add_metric_data(self.metric, data) delta = self.get_kronecker_delta() i1 = TensorIndex('i1', self) i2 = TensorIndex('i2', self) delta(i1, -i2).data = _TensorDataLazyEvaluator.parse_data(eye(dim1)) @data.deleter def data(self): deprecate_data() if self in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self] if self.metric in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self.metric] @deprecated(useinstead=".delta", issue=17517, deprecated_since_version="1.5") def get_kronecker_delta(self): sym2 = TensorSymmetry(get_symmetric_group_sgs(2)) delta = TensorHead('KD', [self]*2, sym2) return delta @deprecated(useinstead=".delta", issue=17517, deprecated_since_version="1.5") def get_epsilon(self): if not isinstance(self._eps_dim, (SYMPY_INTS, Integer)): return None sym = TensorSymmetry(get_symmetric_group_sgs(self._eps_dim, 1)) epsilon = TensorHead('Eps', [self]*self._eps_dim, sym) return epsilon def _components_data_full_destroy(self): """ EXPERIMENTAL: do not rely on this API method. This destroys components data associated to the ``TensorIndexType``, if any, specifically: * metric tensor data * Kronecker tensor data """ if self in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self] def delete_tensmul_data(key): if key in _tensor_data_substitution_dict._substitutions_dict_tensmul: del _tensor_data_substitution_dict._substitutions_dict_tensmul[key] # delete metric data: delete_tensmul_data((self.metric, True, True)) delete_tensmul_data((self.metric, True, False)) delete_tensmul_data((self.metric, False, True)) delete_tensmul_data((self.metric, False, False)) # delete delta tensor data: delta = self.get_kronecker_delta() if delta in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[delta] class TensorIndex(Basic): """ Represents a tensor index Parameters ========== name : name of the index, or ``True`` if you want it to be automatically assigned tensor_index_type : ``TensorIndexType`` of the index is_up : flag for contravariant index (is_up=True by default) Attributes ========== ``name`` ``tensor_index_type`` ``is_up`` Notes ===== Tensor indices are contracted with the Einstein summation convention. An index can be in contravariant or in covariant form; in the latter case it is represented prepending a ``-`` to the index name. Adding ``-`` to a covariant (is_up=False) index makes it contravariant. Dummy indices have a name with head given by ``tensor_inde_type.dummy_name`` with underscore and a number. Similar to ``symbols`` multiple contravariant indices can be created at once using ``tensor_indices(s, typ)``, where ``s`` is a string of names. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, TensorIndex, TensorHead, tensor_indices >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> mu = TensorIndex('mu', Lorentz, is_up=False) >>> nu, rho = tensor_indices('nu, rho', Lorentz) >>> A = TensorHead('A', [Lorentz, Lorentz]) >>> A(mu, nu) A(-mu, nu) >>> A(-mu, -rho) A(mu, -rho) >>> A(mu, -mu) A(-L_0, L_0) """ def __new__(cls, name, tensor_index_type, is_up=True): if isinstance(name, str): name_symbol = Symbol(name) elif isinstance(name, Symbol): name_symbol = name elif name is True: name = "_i{}".format(len(tensor_index_type._autogenerated)) name_symbol = Symbol(name) tensor_index_type._autogenerated.append(name_symbol) else: raise ValueError("invalid name") is_up = sympify(is_up) return Basic.__new__(cls, name_symbol, tensor_index_type, is_up) @property def name(self): return self.args[0].name @property def tensor_index_type(self): return self.args[1] @property def is_up(self): return self.args[2] def _print(self): s = self.name if not self.is_up: s = '-%s' % s return s def __lt__(self, other): return ((self.tensor_index_type, self.name) < (other.tensor_index_type, other.name)) def __neg__(self): t1 = TensorIndex(self.name, self.tensor_index_type, (not self.is_up)) return t1 def tensor_indices(s, typ): """ Returns list of tensor indices given their names and their types. Parameters ========== s : string of comma separated names of indices typ : ``TensorIndexType`` of the indices Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz) """ if isinstance(s, str): a = [x.name for x in symbols(s, seq=True)] else: raise ValueError('expecting a string') tilist = [TensorIndex(i, typ) for i in a] if len(tilist) == 1: return tilist[0] return tilist class TensorSymmetry(Basic): """ Monoterm symmetry of a tensor (i.e. any symmetric or anti-symmetric index permutation). For the relevant terminology see ``tensor_can.py`` section of the combinatorics module. Parameters ========== bsgs : tuple ``(base, sgs)`` BSGS of the symmetry of the tensor Attributes ========== ``base`` : base of the BSGS ``generators`` : generators of the BSGS ``rank`` : rank of the tensor Notes ===== A tensor can have an arbitrary monoterm symmetry provided by its BSGS. Multiterm symmetries, like the cyclic symmetry of the Riemann tensor (i.e., Bianchi identity), are not covered. See combinatorics module for information on how to generate BSGS for a general index permutation group. Simple symmetries can be generated using built-in methods. See Also ======== sympy.combinatorics.tensor_can.get_symmetric_group_sgs Examples ======== Define a symmetric tensor of rank 2 >>> from sympy.tensor.tensor import TensorIndexType, TensorSymmetry, get_symmetric_group_sgs, TensorHead >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> sym = TensorSymmetry(get_symmetric_group_sgs(2)) >>> T = TensorHead('T', [Lorentz]*2, sym) Note, that the same can also be done using built-in TensorSymmetry methods >>> sym2 = TensorSymmetry.fully_symmetric(2) >>> sym == sym2 True """ def __new__(cls, *args, **kw_args): if len(args) == 1: base, generators = args[0] elif len(args) == 2: base, generators = args else: raise TypeError("bsgs required, either two separate parameters or one tuple") if not isinstance(base, Tuple): base = Tuple(*base) if not isinstance(generators, Tuple): generators = Tuple(*generators) return Basic.__new__(cls, base, generators, **kw_args) @property def base(self): return self.args[0] @property def generators(self): return self.args[1] @property def rank(self): return self.generators[0].size - 2 @classmethod def fully_symmetric(cls, rank): """ Returns a fully symmetric (antisymmetric if ``rank``<0) TensorSymmetry object for ``abs(rank)`` indices. """ if rank > 0: bsgs = get_symmetric_group_sgs(rank, False) elif rank < 0: bsgs = get_symmetric_group_sgs(-rank, True) elif rank == 0: bsgs = ([], [Permutation(1)]) return TensorSymmetry(bsgs) @classmethod def direct_product(cls, *args): """ Returns a TensorSymmetry object that is being a direct product of fully (anti-)symmetric index permutation groups. Notes ===== Some examples for different values of ``(*args)``: ``(1)`` vector, equivalent to ``TensorSymmetry.fully_symmetric(1)`` ``(2)`` tensor with 2 symmetric indices, equivalent to ``.fully_symmetric(2)`` ``(-2)`` tensor with 2 antisymmetric indices, equivalent to ``.fully_symmetric(-2)`` ``(2, -2)`` tensor with the first 2 indices commuting and the last 2 anticommuting ``(1, 1, 1)`` tensor with 3 indices without any symmetry """ base, sgs = [], [Permutation(1)] for arg in args: if arg > 0: bsgs2 = get_symmetric_group_sgs(arg, False) elif arg < 0: bsgs2 = get_symmetric_group_sgs(-arg, True) else: continue base, sgs = bsgs_direct_product(base, sgs, *bsgs2) return TensorSymmetry(base, sgs) @classmethod def riemann(cls): """ Returns a monotorem symmetry of the Riemann tensor """ return TensorSymmetry(riemann_bsgs) @classmethod def no_symmetry(cls, rank): """ TensorSymmetry object for ``rank`` indices with no symmetry """ return TensorSymmetry([], [Permutation(rank+1)]) @deprecated(useinstead="TensorSymmetry class constructor and methods", issue=17108, deprecated_since_version="1.5") def tensorsymmetry(*args): """ Returns a ``TensorSymmetry`` object. This method is deprecated, use ``TensorSymmetry.direct_product()`` or ``.riemann()`` instead. Explanation =========== One can represent a tensor with any monoterm slot symmetry group using a BSGS. ``args`` can be a BSGS ``args[0]`` base ``args[1]`` sgs Usually tensors are in (direct products of) representations of the symmetric group; ``args`` can be a list of lists representing the shapes of Young tableaux Notes ===== For instance: ``[[1]]`` vector ``[[1]*n]`` symmetric tensor of rank ``n`` ``[[n]]`` antisymmetric tensor of rank ``n`` ``[[2, 2]]`` monoterm slot symmetry of the Riemann tensor ``[[1],[1]]`` vector*vector ``[[2],[1],[1]`` (antisymmetric tensor)*vector*vector Notice that with the shape ``[2, 2]`` we associate only the monoterm symmetries of the Riemann tensor; this is an abuse of notation, since the shape ``[2, 2]`` corresponds usually to the irreducible representation characterized by the monoterm symmetries and by the cyclic symmetry. """ from sympy.combinatorics import Permutation def tableau2bsgs(a): if len(a) == 1: # antisymmetric vector n = a[0] bsgs = get_symmetric_group_sgs(n, 1) else: if all(x == 1 for x in a): # symmetric vector n = len(a) bsgs = get_symmetric_group_sgs(n) elif a == [2, 2]: bsgs = riemann_bsgs else: raise NotImplementedError return bsgs if not args: return TensorSymmetry(Tuple(), Tuple(Permutation(1))) if len(args) == 2 and isinstance(args[1][0], Permutation): return TensorSymmetry(args) base, sgs = tableau2bsgs(args[0]) for a in args[1:]: basex, sgsx = tableau2bsgs(a) base, sgs = bsgs_direct_product(base, sgs, basex, sgsx) return TensorSymmetry(Tuple(base, sgs)) class TensorType(Basic): """ Class of tensor types. Deprecated, use tensor_heads() instead. Parameters ========== index_types : list of ``TensorIndexType`` of the tensor indices symmetry : ``TensorSymmetry`` of the tensor Attributes ========== ``index_types`` ``symmetry`` ``types`` : list of ``TensorIndexType`` without repetitions """ is_commutative = False def __new__(cls, index_types, symmetry, **kw_args): deprecate_TensorType() assert symmetry.rank == len(index_types) obj = Basic.__new__(cls, Tuple(*index_types), symmetry, **kw_args) return obj @property def index_types(self): return self.args[0] @property def symmetry(self): return self.args[1] @property def types(self): return sorted(set(self.index_types), key=lambda x: x.name) def __str__(self): return 'TensorType(%s)' % ([str(x) for x in self.index_types]) def __call__(self, s, comm=0): """ Return a TensorHead object or a list of TensorHead objects. Parameters ========== s : name or string of names. comm : Commutation group. see ``_TensorManager.set_comm`` """ if isinstance(s, str): names = [x.name for x in symbols(s, seq=True)] else: raise ValueError('expecting a string') if len(names) == 1: return TensorHead(names[0], self.index_types, self.symmetry, comm) else: return [TensorHead(name, self.index_types, self.symmetry, comm) for name in names] @deprecated(useinstead="TensorHead class constructor or tensor_heads()", issue=17108, deprecated_since_version="1.5") def tensorhead(name, typ, sym=None, comm=0): """ Function generating tensorhead(s). This method is deprecated, use TensorHead constructor or tensor_heads() instead. Parameters ========== name : name or sequence of names (as in ``symbols``) typ : index types sym : same as ``*args`` in ``tensorsymmetry`` comm : commutation group number see ``_TensorManager.set_comm`` """ if sym is None: sym = [[1] for i in range(len(typ))] sym = tensorsymmetry(*sym) return TensorHead(name, typ, sym, comm) class TensorHead(Basic): """ Tensor head of the tensor. Parameters ========== name : name of the tensor index_types : list of TensorIndexType symmetry : TensorSymmetry of the tensor comm : commutation group number Attributes ========== ``name`` ``index_types`` ``rank`` : total number of indices ``symmetry`` ``comm`` : commutation group Notes ===== Similar to ``symbols`` multiple TensorHeads can be created using ``tensorhead(s, typ, sym=None, comm=0)`` function, where ``s`` is the string of names and ``sym`` is the monoterm tensor symmetry (see ``tensorsymmetry``). A ``TensorHead`` belongs to a commutation group, defined by a symbol on number ``comm`` (see ``_TensorManager.set_comm``); tensors in a commutation group have the same commutation properties; by default ``comm`` is ``0``, the group of the commuting tensors. Examples ======== Define a fully antisymmetric tensor of rank 2: >>> from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorSymmetry >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> asym2 = TensorSymmetry.fully_symmetric(-2) >>> A = TensorHead('A', [Lorentz, Lorentz], asym2) Examples with ndarray values, the components data assigned to the ``TensorHead`` object are assumed to be in a fully-contravariant representation. In case it is necessary to assign components data which represents the values of a non-fully covariant tensor, see the other examples. >>> from sympy.tensor.tensor import tensor_indices >>> from sympy import diag >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> i0, i1 = tensor_indices('i0:2', Lorentz) Specify a replacement dictionary to keep track of the arrays to use for replacements in the tensorial expression. The ``TensorIndexType`` is associated to the metric used for contractions (in fully covariant form): >>> repl = {Lorentz: diag(1, -1, -1, -1)} Let's see some examples of working with components with the electromagnetic tensor: >>> from sympy import symbols >>> Ex, Ey, Ez, Bx, By, Bz = symbols('E_x E_y E_z B_x B_y B_z') >>> c = symbols('c', positive=True) Let's define `F`, an antisymmetric tensor: >>> F = TensorHead('F', [Lorentz, Lorentz], asym2) Let's update the dictionary to contain the matrix to use in the replacements: >>> repl.update({F(-i0, -i1): [ ... [0, Ex/c, Ey/c, Ez/c], ... [-Ex/c, 0, -Bz, By], ... [-Ey/c, Bz, 0, -Bx], ... [-Ez/c, -By, Bx, 0]]}) Now it is possible to retrieve the contravariant form of the Electromagnetic tensor: >>> F(i0, i1).replace_with_arrays(repl, [i0, i1]) [[0, -E_x/c, -E_y/c, -E_z/c], [E_x/c, 0, -B_z, B_y], [E_y/c, B_z, 0, -B_x], [E_z/c, -B_y, B_x, 0]] and the mixed contravariant-covariant form: >>> F(i0, -i1).replace_with_arrays(repl, [i0, -i1]) [[0, E_x/c, E_y/c, E_z/c], [E_x/c, 0, B_z, -B_y], [E_y/c, -B_z, 0, B_x], [E_z/c, B_y, -B_x, 0]] Energy-momentum of a particle may be represented as: >>> from sympy import symbols >>> P = TensorHead('P', [Lorentz], TensorSymmetry.no_symmetry(1)) >>> E, px, py, pz = symbols('E p_x p_y p_z', positive=True) >>> repl.update({P(i0): [E, px, py, pz]}) The contravariant and covariant components are, respectively: >>> P(i0).replace_with_arrays(repl, [i0]) [E, p_x, p_y, p_z] >>> P(-i0).replace_with_arrays(repl, [-i0]) [E, -p_x, -p_y, -p_z] The contraction of a 1-index tensor by itself: >>> expr = P(i0)*P(-i0) >>> expr.replace_with_arrays(repl, []) E**2 - p_x**2 - p_y**2 - p_z**2 """ is_commutative = False def __new__(cls, name, index_types, symmetry=None, comm=0): if isinstance(name, str): name_symbol = Symbol(name) elif isinstance(name, Symbol): name_symbol = name else: raise ValueError("invalid name") if symmetry is None: symmetry = TensorSymmetry.no_symmetry(len(index_types)) else: assert symmetry.rank == len(index_types) obj = Basic.__new__(cls, name_symbol, Tuple(*index_types), symmetry) obj.comm = TensorManager.comm_symbols2i(comm) return obj @property def name(self): return self.args[0].name @property def index_types(self): return list(self.args[1]) @property def symmetry(self): return self.args[2] @property def rank(self): return len(self.index_types) def __lt__(self, other): return (self.name, self.index_types) < (other.name, other.index_types) def commutes_with(self, other): """ Returns ``0`` if ``self`` and ``other`` commute, ``1`` if they anticommute. Returns ``None`` if ``self`` and ``other`` neither commute nor anticommute. """ r = TensorManager.get_comm(self.comm, other.comm) return r def _print(self): return '%s(%s)' %(self.name, ','.join([str(x) for x in self.index_types])) def __call__(self, *indices, **kw_args): """ Returns a tensor with indices. Explanation =========== There is a special behavior in case of indices denoted by ``True``, they are considered auto-matrix indices, their slots are automatically filled, and confer to the tensor the behavior of a matrix or vector upon multiplication with another tensor containing auto-matrix indices of the same ``TensorIndexType``. This means indices get summed over the same way as in matrix multiplication. For matrix behavior, define two auto-matrix indices, for vector behavior define just one. Indices can also be strings, in which case the attribute ``index_types`` is used to convert them to proper ``TensorIndex``. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorSymmetry, TensorHead >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> a, b = tensor_indices('a,b', Lorentz) >>> A = TensorHead('A', [Lorentz]*2, TensorSymmetry.no_symmetry(2)) >>> t = A(a, -b) >>> t A(a, -b) """ updated_indices = [] for idx, typ in zip(indices, self.index_types): if isinstance(idx, str): idx = idx.strip().replace(" ", "") if idx.startswith('-'): updated_indices.append(TensorIndex(idx[1:], typ, is_up=False)) else: updated_indices.append(TensorIndex(idx, typ)) else: updated_indices.append(idx) updated_indices += indices[len(updated_indices):] tensor = Tensor(self, updated_indices, **kw_args) return tensor.doit() # Everything below this line is deprecated def __pow__(self, other): with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=SymPyDeprecationWarning) if self.data is None: raise ValueError("No power on abstract tensors.") deprecate_data() from .array import tensorproduct, tensorcontraction metrics = [_.data for _ in self.index_types] marray = self.data marraydim = marray.rank() for metric in metrics: marray = tensorproduct(marray, metric, marray) marray = tensorcontraction(marray, (0, marraydim), (marraydim+1, marraydim+2)) return marray ** (other * S.Half) @property def data(self): deprecate_data() return _tensor_data_substitution_dict[self] @data.setter def data(self, data): deprecate_data() _tensor_data_substitution_dict[self] = data @data.deleter def data(self): deprecate_data() if self in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self] def __iter__(self): deprecate_data() return self.data.__iter__() def _components_data_full_destroy(self): """ EXPERIMENTAL: do not rely on this API method. Destroy components data associated to the ``TensorHead`` object, this checks for attached components data, and destroys components data too. """ # do not garbage collect Kronecker tensor (it should be done by # ``TensorIndexType`` garbage collection) deprecate_data() if self.name == "KD": return # the data attached to a tensor must be deleted only by the TensorHead # destructor. If the TensorHead is deleted, it means that there are no # more instances of that tensor anywhere. if self in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self] def tensor_heads(s, index_types, symmetry=None, comm=0): """ Returns a sequence of TensorHeads from a string `s` """ if isinstance(s, str): names = [x.name for x in symbols(s, seq=True)] else: raise ValueError('expecting a string') thlist = [TensorHead(name, index_types, symmetry, comm) for name in names] if len(thlist) == 1: return thlist[0] return thlist class _TensorMetaclass(ManagedProperties, ABCMeta): pass class TensExpr(Expr, metaclass=_TensorMetaclass): """ Abstract base class for tensor expressions Notes ===== A tensor expression is an expression formed by tensors; currently the sums of tensors are distributed. A ``TensExpr`` can be a ``TensAdd`` or a ``TensMul``. ``TensMul`` objects are formed by products of component tensors, and include a coefficient, which is a SymPy expression. In the internal representation contracted indices are represented by ``(ipos1, ipos2, icomp1, icomp2)``, where ``icomp1`` is the position of the component tensor with contravariant index, ``ipos1`` is the slot which the index occupies in that component tensor. Contracted indices are therefore nameless in the internal representation. """ _op_priority = 12.0 is_commutative = False def __neg__(self): return self*S.NegativeOne def __abs__(self): raise NotImplementedError def __add__(self, other): return TensAdd(self, other).doit() def __radd__(self, other): return TensAdd(other, self).doit() def __sub__(self, other): return TensAdd(self, -other).doit() def __rsub__(self, other): return TensAdd(other, -self).doit() def __mul__(self, other): """ Multiply two tensors using Einstein summation convention. Explanation =========== If the two tensors have an index in common, one contravariant and the other covariant, in their product the indices are summed Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> g = Lorentz.metric >>> p, q = tensor_heads('p,q', [Lorentz]) >>> t1 = p(m0) >>> t2 = q(-m0) >>> t1*t2 p(L_0)*q(-L_0) """ return TensMul(self, other).doit() def __rmul__(self, other): return TensMul(other, self).doit() def __truediv__(self, other): other = _sympify(other) if isinstance(other, TensExpr): raise ValueError('cannot divide by a tensor') return TensMul(self, S.One/other).doit() def __rtruediv__(self, other): raise ValueError('cannot divide by a tensor') def __pow__(self, other): with warnings.catch_warnings(): warnings.filterwarnings("ignore", category=SymPyDeprecationWarning) if self.data is None: raise ValueError("No power without ndarray data.") deprecate_data() from .array import tensorproduct, tensorcontraction free = self.free marray = self.data mdim = marray.rank() for metric in free: marray = tensorcontraction( tensorproduct( marray, metric[0].tensor_index_type.data, marray), (0, mdim), (mdim+1, mdim+2) ) return marray ** (other * S.Half) def __rpow__(self, other): raise NotImplementedError @property @abstractmethod def nocoeff(self): raise NotImplementedError("abstract method") @property @abstractmethod def coeff(self): raise NotImplementedError("abstract method") @abstractmethod def get_indices(self): raise NotImplementedError("abstract method") @abstractmethod def get_free_indices(self): # type: () -> List[TensorIndex] raise NotImplementedError("abstract method") @abstractmethod def _replace_indices(self, repl): # type: (tDict[TensorIndex, TensorIndex]) -> TensExpr raise NotImplementedError("abstract method") def fun_eval(self, *index_tuples): deprecate_fun_eval() return self.substitute_indices(*index_tuples) def get_matrix(self): """ DEPRECATED: do not use. Returns ndarray components data as a matrix, if components data are available and ndarray dimension does not exceed 2. """ from sympy import Matrix deprecate_data() if 0 < self.rank <= 2: rows = self.data.shape[0] columns = self.data.shape[1] if self.rank == 2 else 1 if self.rank == 2: mat_list = [] * rows for i in range(rows): mat_list.append([]) for j in range(columns): mat_list[i].append(self[i, j]) else: mat_list = [None] * rows for i in range(rows): mat_list[i] = self[i] return Matrix(mat_list) else: raise NotImplementedError( "missing multidimensional reduction to matrix.") @staticmethod def _get_indices_permutation(indices1, indices2): return [indices1.index(i) for i in indices2] def expand(self, **hints): return _expand(self, **hints).doit() def _expand(self, **kwargs): return self def _get_free_indices_set(self): indset = set() for arg in self.args: if isinstance(arg, TensExpr): indset.update(arg._get_free_indices_set()) return indset def _get_dummy_indices_set(self): indset = set() for arg in self.args: if isinstance(arg, TensExpr): indset.update(arg._get_dummy_indices_set()) return indset def _get_indices_set(self): indset = set() for arg in self.args: if isinstance(arg, TensExpr): indset.update(arg._get_indices_set()) return indset @property def _iterate_dummy_indices(self): dummy_set = self._get_dummy_indices_set() def recursor(expr, pos): if isinstance(expr, TensorIndex): if expr in dummy_set: yield (expr, pos) elif isinstance(expr, (Tuple, TensExpr)): for p, arg in enumerate(expr.args): yield from recursor(arg, pos+(p,)) return recursor(self, ()) @property def _iterate_free_indices(self): free_set = self._get_free_indices_set() def recursor(expr, pos): if isinstance(expr, TensorIndex): if expr in free_set: yield (expr, pos) elif isinstance(expr, (Tuple, TensExpr)): for p, arg in enumerate(expr.args): yield from recursor(arg, pos+(p,)) return recursor(self, ()) @property def _iterate_indices(self): def recursor(expr, pos): if isinstance(expr, TensorIndex): yield (expr, pos) elif isinstance(expr, (Tuple, TensExpr)): for p, arg in enumerate(expr.args): yield from recursor(arg, pos+(p,)) return recursor(self, ()) @staticmethod def _contract_and_permute_with_metric(metric, array, pos, dim): # TODO: add possibility of metric after (spinors) from .array import tensorcontraction, tensorproduct, permutedims array = tensorcontraction(tensorproduct(metric, array), (1, 2+pos)) permu = list(range(dim)) permu[0], permu[pos] = permu[pos], permu[0] return permutedims(array, permu) @staticmethod def _match_indices_with_other_tensor(array, free_ind1, free_ind2, replacement_dict): from .array import permutedims index_types1 = [i.tensor_index_type for i in free_ind1] # Check if variance of indices needs to be fixed: pos2up = [] pos2down = [] free2remaining = free_ind2[:] for pos1, index1 in enumerate(free_ind1): if index1 in free2remaining: pos2 = free2remaining.index(index1) free2remaining[pos2] = None continue if -index1 in free2remaining: pos2 = free2remaining.index(-index1) free2remaining[pos2] = None free_ind2[pos2] = index1 if index1.is_up: pos2up.append(pos2) else: pos2down.append(pos2) else: index2 = free2remaining[pos1] if index2 is None: raise ValueError("incompatible indices: %s and %s" % (free_ind1, free_ind2)) free2remaining[pos1] = None free_ind2[pos1] = index1 if index1.is_up ^ index2.is_up: if index1.is_up: pos2up.append(pos1) else: pos2down.append(pos1) if len(set(free_ind1) & set(free_ind2)) < len(free_ind1): raise ValueError("incompatible indices: %s and %s" % (free_ind1, free_ind2)) # Raise indices: for pos in pos2up: index_type_pos = index_types1[pos] # type: TensorIndexType if index_type_pos not in replacement_dict: raise ValueError("No metric provided to lower index") metric = replacement_dict[index_type_pos] metric_inverse = _TensorDataLazyEvaluator.inverse_matrix(metric) array = TensExpr._contract_and_permute_with_metric(metric_inverse, array, pos, len(free_ind1)) # Lower indices: for pos in pos2down: index_type_pos = index_types1[pos] # type: TensorIndexType if index_type_pos not in replacement_dict: raise ValueError("No metric provided to lower index") metric = replacement_dict[index_type_pos] array = TensExpr._contract_and_permute_with_metric(metric, array, pos, len(free_ind1)) if free_ind1: permutation = TensExpr._get_indices_permutation(free_ind2, free_ind1) array = permutedims(array, permutation) if hasattr(array, "rank") and array.rank() == 0: array = array[()] return free_ind2, array def replace_with_arrays(self, replacement_dict, indices=None): """ Replace the tensorial expressions with arrays. The final array will correspond to the N-dimensional array with indices arranged according to ``indices``. Parameters ========== replacement_dict dictionary containing the replacement rules for tensors. indices the index order with respect to which the array is read. The original index order will be used if no value is passed. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices >>> from sympy.tensor.tensor import TensorHead >>> from sympy import symbols, diag >>> L = TensorIndexType("L") >>> i, j = tensor_indices("i j", L) >>> A = TensorHead("A", [L]) >>> A(i).replace_with_arrays({A(i): [1, 2]}, [i]) [1, 2] Since 'indices' is optional, we can also call replace_with_arrays by this way if no specific index order is needed: >>> A(i).replace_with_arrays({A(i): [1, 2]}) [1, 2] >>> expr = A(i)*A(j) >>> expr.replace_with_arrays({A(i): [1, 2]}) [[1, 2], [2, 4]] For contractions, specify the metric of the ``TensorIndexType``, which in this case is ``L``, in its covariant form: >>> expr = A(i)*A(-i) >>> expr.replace_with_arrays({A(i): [1, 2], L: diag(1, -1)}) -3 Symmetrization of an array: >>> H = TensorHead("H", [L, L]) >>> a, b, c, d = symbols("a b c d") >>> expr = H(i, j)/2 + H(j, i)/2 >>> expr.replace_with_arrays({H(i, j): [[a, b], [c, d]]}) [[a, b/2 + c/2], [b/2 + c/2, d]] Anti-symmetrization of an array: >>> expr = H(i, j)/2 - H(j, i)/2 >>> repl = {H(i, j): [[a, b], [c, d]]} >>> expr.replace_with_arrays(repl) [[0, b/2 - c/2], [-b/2 + c/2, 0]] The same expression can be read as the transpose by inverting ``i`` and ``j``: >>> expr.replace_with_arrays(repl, [j, i]) [[0, -b/2 + c/2], [b/2 - c/2, 0]] """ from .array import Array indices = indices or [] replacement_dict = {tensor: Array(array) for tensor, array in replacement_dict.items()} # Check dimensions of replaced arrays: for tensor, array in replacement_dict.items(): if isinstance(tensor, TensorIndexType): expected_shape = [tensor.dim for i in range(2)] else: expected_shape = [index_type.dim for index_type in tensor.index_types] if len(expected_shape) != array.rank() or (not all([dim1 == dim2 if dim1.is_number else True for dim1, dim2 in zip(expected_shape, array.shape)])): raise ValueError("shapes for tensor %s expected to be %s, "\ "replacement array shape is %s" % (tensor, expected_shape, array.shape)) ret_indices, array = self._extract_data(replacement_dict) last_indices, array = self._match_indices_with_other_tensor(array, indices, ret_indices, replacement_dict) return array def _check_add_Sum(self, expr, index_symbols): from sympy import Sum indices = self.get_indices() dum = self.dum sum_indices = [ (index_symbols[i], 0, indices[i].tensor_index_type.dim-1) for i, j in dum] if sum_indices: expr = Sum(expr, *sum_indices) return expr def _expand_partial_derivative(self): # simply delegate the _expand_partial_derivative() to # its arguments to expand a possibly found PartialDerivative return self.func(*[ a._expand_partial_derivative() if isinstance(a, TensExpr) else a for a in self.args]) class TensAdd(TensExpr, AssocOp): """ Sum of tensors. Parameters ========== free_args : list of the free indices Attributes ========== ``args`` : tuple of addends ``rank`` : rank of the tensor ``free_args`` : list of the free indices in sorted order Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_heads, tensor_indices >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> a, b = tensor_indices('a,b', Lorentz) >>> p, q = tensor_heads('p,q', [Lorentz]) >>> t = p(a) + q(a); t p(a) + q(a) Examples with components data added to the tensor expression: >>> from sympy import symbols, diag >>> x, y, z, t = symbols("x y z t") >>> repl = {} >>> repl[Lorentz] = diag(1, -1, -1, -1) >>> repl[p(a)] = [1, 2, 3, 4] >>> repl[q(a)] = [x, y, z, t] The following are: 2**2 - 3**2 - 2**2 - 7**2 ==> -58 >>> expr = p(a) + q(a) >>> expr.replace_with_arrays(repl, [a]) [x + 1, y + 2, z + 3, t + 4] """ def __new__(cls, *args, **kw_args): args = [_sympify(x) for x in args if x] args = TensAdd._tensAdd_flatten(args) args.sort(key=default_sort_key) if not args: return S.Zero if len(args) == 1: return args[0] return Basic.__new__(cls, *args, **kw_args) @property def coeff(self): return S.One @property def nocoeff(self): return self def get_free_indices(self): # type: () -> List[TensorIndex] return self.free_indices def _replace_indices(self, repl): # type: (tDict[TensorIndex, TensorIndex]) -> TensExpr newargs = [arg._replace_indices(repl) if isinstance(arg, TensExpr) else arg for arg in self.args] return self.func(*newargs) @memoize_property def rank(self): if isinstance(self.args[0], TensExpr): return self.args[0].rank else: return 0 @memoize_property def free_args(self): if isinstance(self.args[0], TensExpr): return self.args[0].free_args else: return [] @memoize_property def free_indices(self): if isinstance(self.args[0], TensExpr): return self.args[0].get_free_indices() else: return set() def doit(self, **kwargs): deep = kwargs.get('deep', True) if deep: args = [arg.doit(**kwargs) for arg in self.args] else: args = self.args if not args: return S.Zero if len(args) == 1 and not isinstance(args[0], TensExpr): return args[0] # now check that all addends have the same indices: TensAdd._tensAdd_check(args) # if TensAdd has only 1 element in its `args`: if len(args) == 1: # and isinstance(args[0], TensMul): return args[0] # Remove zeros: args = [x for x in args if x] # if there are no more args (i.e. have cancelled out), # just return zero: if not args: return S.Zero if len(args) == 1: return args[0] # Collect terms appearing more than once, differing by their coefficients: args = TensAdd._tensAdd_collect_terms(args) # collect canonicalized terms def sort_key(t): if not isinstance(t, TensExpr): return [], [], [] if hasattr(t, "_index_structure") and hasattr(t, "components"): x = get_index_structure(t) return t.components, x.free, x.dum return [], [], [] args.sort(key=sort_key) if not args: return S.Zero # it there is only a component tensor return it if len(args) == 1: return args[0] obj = self.func(*args) return obj @staticmethod def _tensAdd_flatten(args): # flatten TensAdd, coerce terms which are not tensors to tensors a = [] for x in args: if isinstance(x, (Add, TensAdd)): a.extend(list(x.args)) else: a.append(x) args = [x for x in a if x.coeff] return args @staticmethod def _tensAdd_check(args): # check that all addends have the same free indices def get_indices_set(x): # type: (Expr) -> Set[TensorIndex] if isinstance(x, TensExpr): return set(x.get_free_indices()) return set() indices0 = get_indices_set(args[0]) # type: Set[TensorIndex] list_indices = [get_indices_set(arg) for arg in args[1:]] # type: List[Set[TensorIndex]] if not all(x == indices0 for x in list_indices): raise ValueError('all tensors must have the same indices') @staticmethod def _tensAdd_collect_terms(args): # collect TensMul terms differing at most by their coefficient terms_dict = defaultdict(list) scalars = S.Zero if isinstance(args[0], TensExpr): free_indices = set(args[0].get_free_indices()) else: free_indices = set() for arg in args: if not isinstance(arg, TensExpr): if free_indices != set(): raise ValueError("wrong valence") scalars += arg continue if free_indices != set(arg.get_free_indices()): raise ValueError("wrong valence") # TODO: what is the part which is not a coeff? # needs an implementation similar to .as_coeff_Mul() terms_dict[arg.nocoeff].append(arg.coeff) new_args = [TensMul(Add(*coeff), t).doit() for t, coeff in terms_dict.items() if Add(*coeff) != 0] if isinstance(scalars, Add): new_args = list(scalars.args) + new_args elif scalars != 0: new_args = [scalars] + new_args return new_args def get_indices(self): indices = [] for arg in self.args: indices.extend([i for i in get_indices(arg) if i not in indices]) return indices def _expand(self, **hints): return TensAdd(*[_expand(i, **hints) for i in self.args]) def __call__(self, *indices): deprecate_fun_eval() free_args = self.free_args indices = list(indices) if [x.tensor_index_type for x in indices] != [x.tensor_index_type for x in free_args]: raise ValueError('incompatible types') if indices == free_args: return self index_tuples = list(zip(free_args, indices)) a = [x.func(*x.substitute_indices(*index_tuples).args) for x in self.args] res = TensAdd(*a).doit() return res def canon_bp(self): """ Canonicalize using the Butler-Portugal algorithm for canonicalization under monoterm symmetries. """ expr = self.expand() args = [canon_bp(x) for x in expr.args] res = TensAdd(*args).doit() return res def equals(self, other): other = _sympify(other) if isinstance(other, TensMul) and other.coeff == 0: return all(x.coeff == 0 for x in self.args) if isinstance(other, TensExpr): if self.rank != other.rank: return False if isinstance(other, TensAdd): if set(self.args) != set(other.args): return False else: return True t = self - other if not isinstance(t, TensExpr): return t == 0 else: if isinstance(t, TensMul): return t.coeff == 0 else: return all(x.coeff == 0 for x in t.args) def __getitem__(self, item): deprecate_data() return self.data[item] def contract_delta(self, delta): args = [x.contract_delta(delta) for x in self.args] t = TensAdd(*args).doit() return canon_bp(t) def contract_metric(self, g): """ Raise or lower indices with the metric ``g``. Parameters ========== g : metric contract_all : if True, eliminate all ``g`` which are contracted Notes ===== see the ``TensorIndexType`` docstring for the contraction conventions """ args = [contract_metric(x, g) for x in self.args] t = TensAdd(*args).doit() return canon_bp(t) def substitute_indices(self, *index_tuples): new_args = [] for arg in self.args: if isinstance(arg, TensExpr): arg = arg.substitute_indices(*index_tuples) new_args.append(arg) return TensAdd(*new_args).doit() def _print(self): a = [] args = self.args for x in args: a.append(str(x)) s = ' + '.join(a) s = s.replace('+ -', '- ') return s def _extract_data(self, replacement_dict): from sympy.tensor.array import Array, permutedims args_indices, arrays = zip(*[ arg._extract_data(replacement_dict) if isinstance(arg, TensExpr) else ([], arg) for arg in self.args ]) arrays = [Array(i) for i in arrays] ref_indices = args_indices[0] for i in range(1, len(args_indices)): indices = args_indices[i] array = arrays[i] permutation = TensMul._get_indices_permutation(indices, ref_indices) arrays[i] = permutedims(array, permutation) return ref_indices, sum(arrays, Array.zeros(*array.shape)) @property def data(self): deprecate_data() return _tensor_data_substitution_dict[self.expand()] @data.setter def data(self, data): deprecate_data() _tensor_data_substitution_dict[self] = data @data.deleter def data(self): deprecate_data() if self in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self] def __iter__(self): deprecate_data() if not self.data: raise ValueError("No iteration on abstract tensors") return self.data.flatten().__iter__() def _eval_rewrite_as_Indexed(self, *args): return Add.fromiter(args) def _eval_partial_derivative(self, s): # Evaluation like Add list_addends = [] for a in self.args: if isinstance(a, TensExpr): list_addends.append(a._eval_partial_derivative(s)) # do not call diff if s is no symbol elif s._diff_wrt: list_addends.append(a._eval_derivative(s)) return self.func(*list_addends) class Tensor(TensExpr): """ Base tensor class, i.e. this represents a tensor, the single unit to be put into an expression. Explanation =========== This object is usually created from a ``TensorHead``, by attaching indices to it. Indices preceded by a minus sign are considered contravariant, otherwise covariant. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead >>> Lorentz = TensorIndexType("Lorentz", dummy_name="L") >>> mu, nu = tensor_indices('mu nu', Lorentz) >>> A = TensorHead("A", [Lorentz, Lorentz]) >>> A(mu, -nu) A(mu, -nu) >>> A(mu, -mu) A(L_0, -L_0) It is also possible to use symbols instead of inidices (appropriate indices are then generated automatically). >>> from sympy import Symbol >>> x = Symbol('x') >>> A(x, mu) A(x, mu) >>> A(x, -x) A(L_0, -L_0) """ is_commutative = False _index_structure = None # type: _IndexStructure def __new__(cls, tensor_head, indices, *, is_canon_bp=False, **kw_args): indices = cls._parse_indices(tensor_head, indices) obj = Basic.__new__(cls, tensor_head, Tuple(*indices), **kw_args) obj._index_structure = _IndexStructure.from_indices(*indices) obj._free = obj._index_structure.free[:] obj._dum = obj._index_structure.dum[:] obj._ext_rank = obj._index_structure._ext_rank obj._coeff = S.One obj._nocoeff = obj obj._component = tensor_head obj._components = [tensor_head] if tensor_head.rank != len(indices): raise ValueError("wrong number of indices") obj.is_canon_bp = is_canon_bp obj._index_map = Tensor._build_index_map(indices, obj._index_structure) return obj @property def free(self): return self._free @property def dum(self): return self._dum @property def ext_rank(self): return self._ext_rank @property def coeff(self): return self._coeff @property def nocoeff(self): return self._nocoeff @property def component(self): return self._component @property def components(self): return self._components @property def head(self): return self.args[0] @property def indices(self): return self.args[1] @property def free_indices(self): return set(self._index_structure.get_free_indices()) @property def index_types(self): return self.head.index_types @property def rank(self): return len(self.free_indices) @staticmethod def _build_index_map(indices, index_structure): index_map = {} for idx in indices: index_map[idx] = (indices.index(idx),) return index_map def doit(self, **kwargs): args, indices, free, dum = TensMul._tensMul_contract_indices([self]) return args[0] @staticmethod def _parse_indices(tensor_head, indices): if not isinstance(indices, (tuple, list, Tuple)): raise TypeError("indices should be an array, got %s" % type(indices)) indices = list(indices) for i, index in enumerate(indices): if isinstance(index, Symbol): indices[i] = TensorIndex(index, tensor_head.index_types[i], True) elif isinstance(index, Mul): c, e = index.as_coeff_Mul() if c == -1 and isinstance(e, Symbol): indices[i] = TensorIndex(e, tensor_head.index_types[i], False) else: raise ValueError("index not understood: %s" % index) elif not isinstance(index, TensorIndex): raise TypeError("wrong type for index: %s is %s" % (index, type(index))) return indices def _set_new_index_structure(self, im, is_canon_bp=False): indices = im.get_indices() return self._set_indices(*indices, is_canon_bp=is_canon_bp) def _set_indices(self, *indices, is_canon_bp=False, **kw_args): if len(indices) != self.ext_rank: raise ValueError("indices length mismatch") return self.func(self.args[0], indices, is_canon_bp=is_canon_bp).doit() def _get_free_indices_set(self): return {i[0] for i in self._index_structure.free} def _get_dummy_indices_set(self): dummy_pos = set(itertools.chain(*self._index_structure.dum)) return {idx for i, idx in enumerate(self.args[1]) if i in dummy_pos} def _get_indices_set(self): return set(self.args[1].args) @property def free_in_args(self): return [(ind, pos, 0) for ind, pos in self.free] @property def dum_in_args(self): return [(p1, p2, 0, 0) for p1, p2 in self.dum] @property def free_args(self): return sorted([x[0] for x in self.free]) def commutes_with(self, other): """ :param other: :return: 0 commute 1 anticommute None neither commute nor anticommute """ if not isinstance(other, TensExpr): return 0 elif isinstance(other, Tensor): return self.component.commutes_with(other.component) return NotImplementedError def perm2tensor(self, g, is_canon_bp=False): """ Returns the tensor corresponding to the permutation ``g``. For further details, see the method in ``TIDS`` with the same name. """ return perm2tensor(self, g, is_canon_bp) def canon_bp(self): if self.is_canon_bp: return self expr = self.expand() g, dummies, msym = expr._index_structure.indices_canon_args() v = components_canon_args([expr.component]) can = canonicalize(g, dummies, msym, *v) if can == 0: return S.Zero tensor = self.perm2tensor(can, True) return tensor def split(self): return [self] def _expand(self, **kwargs): return self def sorted_components(self): return self def get_indices(self): # type: () -> List[TensorIndex] """ Get a list of indices, corresponding to those of the tensor. """ return list(self.args[1]) def get_free_indices(self): # type: () -> List[TensorIndex] """ Get a list of free indices, corresponding to those of the tensor. """ return self._index_structure.get_free_indices() def _replace_indices(self, repl): # type: (tDict[TensorIndex, TensorIndex]) -> Tensor # TODO: this could be optimized by only swapping the indices # instead of visiting the whole expression tree: return self.xreplace(repl) def as_base_exp(self): return self, S.One def substitute_indices(self, *index_tuples): """ Return a tensor with free indices substituted according to ``index_tuples``. ``index_types`` list of tuples ``(old_index, new_index)``. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads, TensorSymmetry >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) >>> A, B = tensor_heads('A,B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) >>> t = A(i, k)*B(-k, -j); t A(i, L_0)*B(-L_0, -j) >>> t.substitute_indices((i, k),(-j, l)) A(k, L_0)*B(-L_0, l) """ indices = [] for index in self.indices: for ind_old, ind_new in index_tuples: if (index.name == ind_old.name and index.tensor_index_type == ind_old.tensor_index_type): if index.is_up == ind_old.is_up: indices.append(ind_new) else: indices.append(-ind_new) break else: indices.append(index) return self.head(*indices) def __call__(self, *indices): deprecate_fun_eval() free_args = self.free_args indices = list(indices) if [x.tensor_index_type for x in indices] != [x.tensor_index_type for x in free_args]: raise ValueError('incompatible types') if indices == free_args: return self t = self.substitute_indices(*list(zip(free_args, indices))) # object is rebuilt in order to make sure that all contracted indices # get recognized as dummies, but only if there are contracted indices. if len({i if i.is_up else -i for i in indices}) != len(indices): return t.func(*t.args) return t # TODO: put this into TensExpr? def __iter__(self): deprecate_data() return self.data.__iter__() # TODO: put this into TensExpr? def __getitem__(self, item): deprecate_data() return self.data[item] def _extract_data(self, replacement_dict): from .array import Array for k, v in replacement_dict.items(): if isinstance(k, Tensor) and k.args[0] == self.args[0]: other = k array = v break else: raise ValueError("%s not found in %s" % (self, replacement_dict)) # TODO: inefficient, this should be done at root level only: replacement_dict = {k: Array(v) for k, v in replacement_dict.items()} array = Array(array) dum1 = self.dum dum2 = other.dum if len(dum2) > 0: for pair in dum2: # allow `dum2` if the contained values are also in `dum1`. if pair not in dum1: raise NotImplementedError("%s with contractions is not implemented" % other) # Remove elements in `dum2` from `dum1`: dum1 = [pair for pair in dum1 if pair not in dum2] if len(dum1) > 0: indices1 = self.get_indices() indices2 = other.get_indices() repl = {} for p1, p2 in dum1: repl[indices2[p2]] = -indices2[p1] for pos in (p1, p2): if indices1[pos].is_up ^ indices2[pos].is_up: metric = replacement_dict[indices1[pos].tensor_index_type] if indices1[pos].is_up: metric = _TensorDataLazyEvaluator.inverse_matrix(metric) array = self._contract_and_permute_with_metric(metric, array, pos, len(indices2)) other = other.xreplace(repl).doit() array = _TensorDataLazyEvaluator.data_contract_dum([array], dum1, len(indices2)) free_ind1 = self.get_free_indices() free_ind2 = other.get_free_indices() return self._match_indices_with_other_tensor(array, free_ind1, free_ind2, replacement_dict) @property def data(self): deprecate_data() return _tensor_data_substitution_dict[self] @data.setter def data(self, data): deprecate_data() # TODO: check data compatibility with properties of tensor. _tensor_data_substitution_dict[self] = data @data.deleter def data(self): deprecate_data() if self in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self] if self.metric in _tensor_data_substitution_dict: del _tensor_data_substitution_dict[self.metric] def _print(self): indices = [str(ind) for ind in self.indices] component = self.component if component.rank > 0: return ('%s(%s)' % (component.name, ', '.join(indices))) else: return ('%s' % component.name) def equals(self, other): if other == 0: return self.coeff == 0 other = _sympify(other) if not isinstance(other, TensExpr): assert not self.components return S.One == other def _get_compar_comp(self): t = self.canon_bp() r = (t.coeff, tuple(t.components), \ tuple(sorted(t.free)), tuple(sorted(t.dum))) return r return _get_compar_comp(self) == _get_compar_comp(other) def contract_metric(self, g): # if metric is not the same, ignore this step: if self.component != g: return self # in case there are free components, do not perform anything: if len(self.free) != 0: return self #antisym = g.index_types[0].metric_antisym if g.symmetry == TensorSymmetry.fully_symmetric(-2): antisym = 1 elif g.symmetry == TensorSymmetry.fully_symmetric(2): antisym = 0 elif g.symmetry == TensorSymmetry.no_symmetry(2): antisym = None else: raise NotImplementedError sign = S.One typ = g.index_types[0] if not antisym: # g(i, -i) sign = sign*typ.dim else: # g(i, -i) sign = sign*typ.dim dp0, dp1 = self.dum[0] if dp0 < dp1: # g(i, -i) = -D with antisymmetric metric sign = -sign return sign def contract_delta(self, metric): return self.contract_metric(metric) def _eval_rewrite_as_Indexed(self, tens, indices): from sympy import Indexed # TODO: replace .args[0] with .name: index_symbols = [i.args[0] for i in self.get_indices()] expr = Indexed(tens.args[0], *index_symbols) return self._check_add_Sum(expr, index_symbols) def _eval_partial_derivative(self, s): # type: (Tensor) -> Expr if not isinstance(s, Tensor): return S.Zero else: # @a_i/@a_k = delta_i^k # @a_i/@a^k = g_ij delta^j_k # @a^i/@a^k = delta^i_k # @a^i/@a_k = g^ij delta_j^k # TODO: if there is no metric present, the derivative should be zero? if self.head != s.head: return S.Zero # if heads are the same, provide delta and/or metric products # for every free index pair in the appropriate tensor # assumed that the free indices are in proper order # A contravariante index in the derivative becomes covariant # after performing the derivative and vice versa kronecker_delta_list = [1] # not guarantee a correct index order for (count, (iself, iother)) in enumerate(zip(self.get_free_indices(), s.get_free_indices())): if iself.tensor_index_type != iother.tensor_index_type: raise ValueError("index types not compatible") else: tensor_index_type = iself.tensor_index_type tensor_metric = tensor_index_type.metric dummy = TensorIndex("d_" + str(count), tensor_index_type, is_up=iself.is_up) if iself.is_up == iother.is_up: kroneckerdelta = tensor_index_type.delta(iself, -iother) else: kroneckerdelta = ( TensMul(tensor_metric(iself, dummy), tensor_index_type.delta(-dummy, -iother)) ) kronecker_delta_list.append(kroneckerdelta) return TensMul.fromiter(kronecker_delta_list).doit() # doit necessary to rename dummy indices accordingly class TensMul(TensExpr, AssocOp): """ Product of tensors. Parameters ========== coeff : SymPy coefficient of the tensor args Attributes ========== ``components`` : list of ``TensorHead`` of the component tensors ``types`` : list of nonrepeated ``TensorIndexType`` ``free`` : list of ``(ind, ipos, icomp)``, see Notes ``dum`` : list of ``(ipos1, ipos2, icomp1, icomp2)``, see Notes ``ext_rank`` : rank of the tensor counting the dummy indices ``rank`` : rank of the tensor ``coeff`` : SymPy coefficient of the tensor ``free_args`` : list of the free indices in sorted order ``is_canon_bp`` : ``True`` if the tensor in in canonical form Notes ===== ``args[0]`` list of ``TensorHead`` of the component tensors. ``args[1]`` list of ``(ind, ipos, icomp)`` where ``ind`` is a free index, ``ipos`` is the slot position of ``ind`` in the ``icomp``-th component tensor. ``args[2]`` list of tuples representing dummy indices. ``(ipos1, ipos2, icomp1, icomp2)`` indicates that the contravariant dummy index is the ``ipos1``-th slot position in the ``icomp1``-th component tensor; the corresponding covariant index is in the ``ipos2`` slot position in the ``icomp2``-th component tensor. """ identity = S.One _index_structure = None # type: _IndexStructure def __new__(cls, *args, **kw_args): is_canon_bp = kw_args.get('is_canon_bp', False) args = list(map(_sympify, args)) # Flatten: args = [i for arg in args for i in (arg.args if isinstance(arg, (TensMul, Mul)) else [arg])] args, indices, free, dum = TensMul._tensMul_contract_indices(args, replace_indices=False) # Data for indices: index_types = [i.tensor_index_type for i in indices] index_structure = _IndexStructure(free, dum, index_types, indices, canon_bp=is_canon_bp) obj = TensExpr.__new__(cls, *args) obj._indices = indices obj._index_types = index_types[:] obj._index_structure = index_structure obj._free = index_structure.free[:] obj._dum = index_structure.dum[:] obj._free_indices = {x[0] for x in obj.free} obj._rank = len(obj.free) obj._ext_rank = len(obj._index_structure.free) + 2*len(obj._index_structure.dum) obj._coeff = S.One obj._is_canon_bp = is_canon_bp return obj index_types = property(lambda self: self._index_types) free = property(lambda self: self._free) dum = property(lambda self: self._dum) free_indices = property(lambda self: self._free_indices) rank = property(lambda self: self._rank) ext_rank = property(lambda self: self._ext_rank) @staticmethod def _indices_to_free_dum(args_indices): free2pos1 = {} free2pos2 = {} dummy_data = [] indices = [] # Notation for positions (to better understand the code): # `pos1`: position in the `args`. # `pos2`: position in the indices. # Example: # A(i, j)*B(k, m, n)*C(p) # `pos1` of `n` is 1 because it's in `B` (second `args` of TensMul). # `pos2` of `n` is 4 because it's the fifth overall index. # Counter for the index position wrt the whole expression: pos2 = 0 for pos1, arg_indices in enumerate(args_indices): for index_pos, index in enumerate(arg_indices): if not isinstance(index, TensorIndex): raise TypeError("expected TensorIndex") if -index in free2pos1: # Dummy index detected: other_pos1 = free2pos1.pop(-index) other_pos2 = free2pos2.pop(-index) if index.is_up: dummy_data.append((index, pos1, other_pos1, pos2, other_pos2)) else: dummy_data.append((-index, other_pos1, pos1, other_pos2, pos2)) indices.append(index) elif index in free2pos1: raise ValueError("Repeated index: %s" % index) else: free2pos1[index] = pos1 free2pos2[index] = pos2 indices.append(index) pos2 += 1 free = [(i, p) for (i, p) in free2pos2.items()] free_names = [i.name for i in free2pos2.keys()] dummy_data.sort(key=lambda x: x[3]) return indices, free, free_names, dummy_data @staticmethod def _dummy_data_to_dum(dummy_data): return [(p2a, p2b) for (i, p1a, p1b, p2a, p2b) in dummy_data] @staticmethod def _tensMul_contract_indices(args, replace_indices=True): replacements = [{} for _ in args] #_index_order = all([_has_index_order(arg) for arg in args]) args_indices = [get_indices(arg) for arg in args] indices, free, free_names, dummy_data = TensMul._indices_to_free_dum(args_indices) cdt = defaultdict(int) def dummy_name_gen(tensor_index_type): nd = str(cdt[tensor_index_type]) cdt[tensor_index_type] += 1 return tensor_index_type.dummy_name + '_' + nd if replace_indices: for old_index, pos1cov, pos1contra, pos2cov, pos2contra in dummy_data: index_type = old_index.tensor_index_type while True: dummy_name = dummy_name_gen(index_type) if dummy_name not in free_names: break dummy = TensorIndex(dummy_name, index_type, True) replacements[pos1cov][old_index] = dummy replacements[pos1contra][-old_index] = -dummy indices[pos2cov] = dummy indices[pos2contra] = -dummy args = [ arg._replace_indices(repl) if isinstance(arg, TensExpr) else arg for arg, repl in zip(args, replacements)] dum = TensMul._dummy_data_to_dum(dummy_data) return args, indices, free, dum @staticmethod def _get_components_from_args(args): """ Get a list of ``Tensor`` objects having the same ``TIDS`` if multiplied by one another. """ components = [] for arg in args: if not isinstance(arg, TensExpr): continue if isinstance(arg, TensAdd): continue components.extend(arg.components) return components @staticmethod def _rebuild_tensors_list(args, index_structure): indices = index_structure.get_indices() #tensors = [None for i in components] # pre-allocate list ind_pos = 0 for i, arg in enumerate(args): if not isinstance(arg, TensExpr): continue prev_pos = ind_pos ind_pos += arg.ext_rank args[i] = Tensor(arg.component, indices[prev_pos:ind_pos]) def doit(self, **kwargs): is_canon_bp = self._is_canon_bp deep = kwargs.get('deep', True) if deep: args = [arg.doit(**kwargs) for arg in self.args] else: args = self.args args = [arg for arg in args if arg != self.identity] # Extract non-tensor coefficients: coeff = reduce(lambda a, b: a*b, [arg for arg in args if not isinstance(arg, TensExpr)], S.One) args = [arg for arg in args if isinstance(arg, TensExpr)] if len(args) == 0: return coeff if coeff != self.identity: args = [coeff] + args if coeff == 0: return S.Zero if len(args) == 1: return args[0] args, indices, free, dum = TensMul._tensMul_contract_indices(args) # Data for indices: index_types = [i.tensor_index_type for i in indices] index_structure = _IndexStructure(free, dum, index_types, indices, canon_bp=is_canon_bp) obj = self.func(*args) obj._index_types = index_types obj._index_structure = index_structure obj._ext_rank = len(obj._index_structure.free) + 2*len(obj._index_structure.dum) obj._coeff = coeff obj._is_canon_bp = is_canon_bp return obj # TODO: this method should be private # TODO: should this method be renamed _from_components_free_dum ? @staticmethod def from_data(coeff, components, free, dum, **kw_args): return TensMul(coeff, *TensMul._get_tensors_from_components_free_dum(components, free, dum), **kw_args).doit() @staticmethod def _get_tensors_from_components_free_dum(components, free, dum): """ Get a list of ``Tensor`` objects by distributing ``free`` and ``dum`` indices on the ``components``. """ index_structure = _IndexStructure.from_components_free_dum(components, free, dum) indices = index_structure.get_indices() tensors = [None for i in components] # pre-allocate list # distribute indices on components to build a list of tensors: ind_pos = 0 for i, component in enumerate(components): prev_pos = ind_pos ind_pos += component.rank tensors[i] = Tensor(component, indices[prev_pos:ind_pos]) return tensors def _get_free_indices_set(self): return {i[0] for i in self.free} def _get_dummy_indices_set(self): dummy_pos = set(itertools.chain(*self.dum)) return {idx for i, idx in enumerate(self._index_structure.get_indices()) if i in dummy_pos} def _get_position_offset_for_indices(self): arg_offset = [None for i in range(self.ext_rank)] counter = 0 for i, arg in enumerate(self.args): if not isinstance(arg, TensExpr): continue for j in range(arg.ext_rank): arg_offset[j + counter] = counter counter += arg.ext_rank return arg_offset @property def free_args(self): return sorted([x[0] for x in self.free]) @property def components(self): return self._get_components_from_args(self.args) @property def free_in_args(self): arg_offset = self._get_position_offset_for_indices() argpos = self._get_indices_to_args_pos() return [(ind, pos-arg_offset[pos], argpos[pos]) for (ind, pos) in self.free] @property def coeff(self): # return Mul.fromiter([c for c in self.args if not isinstance(c, TensExpr)]) return self._coeff @property def nocoeff(self): return self.func(*[t for t in self.args if isinstance(t, TensExpr)]).doit() @property def dum_in_args(self): arg_offset = self._get_position_offset_for_indices() argpos = self._get_indices_to_args_pos() return [(p1-arg_offset[p1], p2-arg_offset[p2], argpos[p1], argpos[p2]) for p1, p2 in self.dum] def equals(self, other): if other == 0: return self.coeff == 0 other = _sympify(other) if not isinstance(other, TensExpr): assert not self.components return self.coeff == other return self.canon_bp() == other.canon_bp() def get_indices(self): """ Returns the list of indices of the tensor. Explanation =========== The indices are listed in the order in which they appear in the component tensors. The dummy indices are given a name which does not collide with the names of the free indices. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> g = Lorentz.metric >>> p, q = tensor_heads('p,q', [Lorentz]) >>> t = p(m1)*g(m0,m2) >>> t.get_indices() [m1, m0, m2] >>> t2 = p(m1)*g(-m1, m2) >>> t2.get_indices() [L_0, -L_0, m2] """ return self._indices def get_free_indices(self): # type: () -> List[TensorIndex] """ Returns the list of free indices of the tensor. Explanation =========== The indices are listed in the order in which they appear in the component tensors. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> g = Lorentz.metric >>> p, q = tensor_heads('p,q', [Lorentz]) >>> t = p(m1)*g(m0,m2) >>> t.get_free_indices() [m1, m0, m2] >>> t2 = p(m1)*g(-m1, m2) >>> t2.get_free_indices() [m2] """ return self._index_structure.get_free_indices() def _replace_indices(self, repl): # type: (tDict[TensorIndex, TensorIndex]) -> TensExpr return self.func(*[arg._replace_indices(repl) if isinstance(arg, TensExpr) else arg for arg in self.args]) def split(self): """ Returns a list of tensors, whose product is ``self``. Explanation =========== Dummy indices contracted among different tensor components become free indices with the same name as the one used to represent the dummy indices. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads, TensorSymmetry >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> a, b, c, d = tensor_indices('a,b,c,d', Lorentz) >>> A, B = tensor_heads('A,B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) >>> t = A(a,b)*B(-b,c) >>> t A(a, L_0)*B(-L_0, c) >>> t.split() [A(a, L_0), B(-L_0, c)] """ if self.args == (): return [self] splitp = [] res = 1 for arg in self.args: if isinstance(arg, Tensor): splitp.append(res*arg) res = 1 else: res *= arg return splitp def _expand(self, **hints): # TODO: temporary solution, in the future this should be linked to # `Expr.expand`. args = [_expand(arg, **hints) for arg in self.args] args1 = [arg.args if isinstance(arg, (Add, TensAdd)) else (arg,) for arg in args] return TensAdd(*[ TensMul(*i) for i in itertools.product(*args1)] ) def __neg__(self): return TensMul(S.NegativeOne, self, is_canon_bp=self._is_canon_bp).doit() def __getitem__(self, item): deprecate_data() return self.data[item] def _get_args_for_traditional_printer(self): args = list(self.args) if (self.coeff < 0) == True: # expressions like "-A(a)" sign = "-" if self.coeff == S.NegativeOne: args = args[1:] else: args[0] = -args[0] else: sign = "" return sign, args def _sort_args_for_sorted_components(self): """ Returns the ``args`` sorted according to the components commutation properties. Explanation =========== The sorting is done taking into account the commutation group of the component tensors. """ cv = [arg for arg in self.args if isinstance(arg, TensExpr)] sign = 1 n = len(cv) - 1 for i in range(n): for j in range(n, i, -1): c = cv[j-1].commutes_with(cv[j]) # if `c` is `None`, it does neither commute nor anticommute, skip: if c not in [0, 1]: continue typ1 = sorted(set(cv[j-1].component.index_types), key=lambda x: x.name) typ2 = sorted(set(cv[j].component.index_types), key=lambda x: x.name) if (typ1, cv[j-1].component.name) > (typ2, cv[j].component.name): cv[j-1], cv[j] = cv[j], cv[j-1] # if `c` is 1, the anticommute, so change sign: if c: sign = -sign coeff = sign * self.coeff if coeff != 1: return [coeff] + cv return cv def sorted_components(self): """ Returns a tensor product with sorted components. """ return TensMul(*self._sort_args_for_sorted_components()).doit() def perm2tensor(self, g, is_canon_bp=False): """ Returns the tensor corresponding to the permutation ``g`` For further details, see the method in ``TIDS`` with the same name. """ return perm2tensor(self, g, is_canon_bp=is_canon_bp) def canon_bp(self): """ Canonicalize using the Butler-Portugal algorithm for canonicalization under monoterm symmetries. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, TensorSymmetry >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(-2)) >>> t = A(m0,-m1)*A(m1,-m0) >>> t.canon_bp() -A(L_0, L_1)*A(-L_0, -L_1) >>> t = A(m0,-m1)*A(m1,-m2)*A(m2,-m0) >>> t.canon_bp() 0 """ if self._is_canon_bp: return self expr = self.expand() if isinstance(expr, TensAdd): return expr.canon_bp() if not expr.components: return expr t = expr.sorted_components() g, dummies, msym = t._index_structure.indices_canon_args() v = components_canon_args(t.components) can = canonicalize(g, dummies, msym, *v) if can == 0: return S.Zero tmul = t.perm2tensor(can, True) return tmul def contract_delta(self, delta): t = self.contract_metric(delta) return t def _get_indices_to_args_pos(self): """ Get a dict mapping the index position to TensMul's argument number. """ pos_map = dict() pos_counter = 0 for arg_i, arg in enumerate(self.args): if not isinstance(arg, TensExpr): continue assert isinstance(arg, Tensor) for i in range(arg.ext_rank): pos_map[pos_counter] = arg_i pos_counter += 1 return pos_map def contract_metric(self, g): """ Raise or lower indices with the metric ``g``. Parameters ========== g : metric Notes ===== See the ``TensorIndexType`` docstring for the contraction conventions. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, tensor_heads >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> m0, m1, m2 = tensor_indices('m0,m1,m2', Lorentz) >>> g = Lorentz.metric >>> p, q = tensor_heads('p,q', [Lorentz]) >>> t = p(m0)*q(m1)*g(-m0, -m1) >>> t.canon_bp() metric(L_0, L_1)*p(-L_0)*q(-L_1) >>> t.contract_metric(g).canon_bp() p(L_0)*q(-L_0) """ expr = self.expand() if self != expr: expr = expr.canon_bp() return expr.contract_metric(g) pos_map = self._get_indices_to_args_pos() args = list(self.args) #antisym = g.index_types[0].metric_antisym if g.symmetry == TensorSymmetry.fully_symmetric(-2): antisym = 1 elif g.symmetry == TensorSymmetry.fully_symmetric(2): antisym = 0 elif g.symmetry == TensorSymmetry.no_symmetry(2): antisym = None else: raise NotImplementedError # list of positions of the metric ``g`` inside ``args`` gpos = [i for i, x in enumerate(self.args) if isinstance(x, Tensor) and x.component == g] if not gpos: return self # Sign is either 1 or -1, to correct the sign after metric contraction # (for spinor indices). sign = 1 dum = self.dum[:] free = self.free[:] elim = set() for gposx in gpos: if gposx in elim: continue free1 = [x for x in free if pos_map[x[1]] == gposx] dum1 = [x for x in dum if pos_map[x[0]] == gposx or pos_map[x[1]] == gposx] if not dum1: continue elim.add(gposx) # subs with the multiplication neutral element, that is, remove it: args[gposx] = 1 if len(dum1) == 2: if not antisym: dum10, dum11 = dum1 if pos_map[dum10[1]] == gposx: # the index with pos p0 contravariant p0 = dum10[0] else: # the index with pos p0 is covariant p0 = dum10[1] if pos_map[dum11[1]] == gposx: # the index with pos p1 is contravariant p1 = dum11[0] else: # the index with pos p1 is covariant p1 = dum11[1] dum.append((p0, p1)) else: dum10, dum11 = dum1 # change the sign to bring the indices of the metric to contravariant # form; change the sign if dum10 has the metric index in position 0 if pos_map[dum10[1]] == gposx: # the index with pos p0 is contravariant p0 = dum10[0] if dum10[1] == 1: sign = -sign else: # the index with pos p0 is covariant p0 = dum10[1] if dum10[0] == 0: sign = -sign if pos_map[dum11[1]] == gposx: # the index with pos p1 is contravariant p1 = dum11[0] sign = -sign else: # the index with pos p1 is covariant p1 = dum11[1] dum.append((p0, p1)) elif len(dum1) == 1: if not antisym: dp0, dp1 = dum1[0] if pos_map[dp0] == pos_map[dp1]: # g(i, -i) typ = g.index_types[0] sign = sign*typ.dim else: # g(i0, i1)*p(-i1) if pos_map[dp0] == gposx: p1 = dp1 else: p1 = dp0 ind, p = free1[0] free.append((ind, p1)) else: dp0, dp1 = dum1[0] if pos_map[dp0] == pos_map[dp1]: # g(i, -i) typ = g.index_types[0] sign = sign*typ.dim if dp0 < dp1: # g(i, -i) = -D with antisymmetric metric sign = -sign else: # g(i0, i1)*p(-i1) if pos_map[dp0] == gposx: p1 = dp1 if dp0 == 0: sign = -sign else: p1 = dp0 ind, p = free1[0] free.append((ind, p1)) dum = [x for x in dum if x not in dum1] free = [x for x in free if x not in free1] # shift positions: shift = 0 shifts = [0]*len(args) for i in range(len(args)): if i in elim: shift += 2 continue shifts[i] = shift free = [(ind, p - shifts[pos_map[p]]) for (ind, p) in free if pos_map[p] not in elim] dum = [(p0 - shifts[pos_map[p0]], p1 - shifts[pos_map[p1]]) for i, (p0, p1) in enumerate(dum) if pos_map[p0] not in elim and pos_map[p1] not in elim] res = sign*TensMul(*args).doit() if not isinstance(res, TensExpr): return res im = _IndexStructure.from_components_free_dum(res.components, free, dum) return res._set_new_index_structure(im) def _set_new_index_structure(self, im, is_canon_bp=False): indices = im.get_indices() return self._set_indices(*indices, is_canon_bp=is_canon_bp) def _set_indices(self, *indices, is_canon_bp=False, **kw_args): if len(indices) != self.ext_rank: raise ValueError("indices length mismatch") args = list(self.args)[:] pos = 0 for i, arg in enumerate(args): if not isinstance(arg, TensExpr): continue assert isinstance(arg, Tensor) ext_rank = arg.ext_rank args[i] = arg._set_indices(*indices[pos:pos+ext_rank]) pos += ext_rank return TensMul(*args, is_canon_bp=is_canon_bp).doit() @staticmethod def _index_replacement_for_contract_metric(args, free, dum): for arg in args: if not isinstance(arg, TensExpr): continue assert isinstance(arg, Tensor) def substitute_indices(self, *index_tuples): new_args = [] for arg in self.args: if isinstance(arg, TensExpr): arg = arg.substitute_indices(*index_tuples) new_args.append(arg) return TensMul(*new_args).doit() def __call__(self, *indices): deprecate_fun_eval() free_args = self.free_args indices = list(indices) if [x.tensor_index_type for x in indices] != [x.tensor_index_type for x in free_args]: raise ValueError('incompatible types') if indices == free_args: return self t = self.substitute_indices(*list(zip(free_args, indices))) # object is rebuilt in order to make sure that all contracted indices # get recognized as dummies, but only if there are contracted indices. if len({i if i.is_up else -i for i in indices}) != len(indices): return t.func(*t.args) return t def _extract_data(self, replacement_dict): args_indices, arrays = zip(*[arg._extract_data(replacement_dict) for arg in self.args if isinstance(arg, TensExpr)]) coeff = reduce(operator.mul, [a for a in self.args if not isinstance(a, TensExpr)], S.One) indices, free, free_names, dummy_data = TensMul._indices_to_free_dum(args_indices) dum = TensMul._dummy_data_to_dum(dummy_data) ext_rank = self.ext_rank free.sort(key=lambda x: x[1]) free_indices = [i[0] for i in free] return free_indices, coeff*_TensorDataLazyEvaluator.data_contract_dum(arrays, dum, ext_rank) @property def data(self): deprecate_data() dat = _tensor_data_substitution_dict[self.expand()] return dat @data.setter def data(self, data): deprecate_data() raise ValueError("Not possible to set component data to a tensor expression") @data.deleter def data(self): deprecate_data() raise ValueError("Not possible to delete component data to a tensor expression") def __iter__(self): deprecate_data() if self.data is None: raise ValueError("No iteration on abstract tensors") return self.data.__iter__() def _eval_rewrite_as_Indexed(self, *args): from sympy import Sum index_symbols = [i.args[0] for i in self.get_indices()] args = [arg.args[0] if isinstance(arg, Sum) else arg for arg in args] expr = Mul.fromiter(args) return self._check_add_Sum(expr, index_symbols) def _eval_partial_derivative(self, s): # Evaluation like Mul terms = [] for i, arg in enumerate(self.args): # checking whether some tensor instance is differentiated # or some other thing is necessary, but ugly if isinstance(arg, TensExpr): d = arg._eval_partial_derivative(s) else: # do not call diff is s is no symbol if s._diff_wrt: d = arg._eval_derivative(s) else: d = S.Zero if d: terms.append(TensMul.fromiter(self.args[:i] + (d,) + self.args[i + 1:])) return TensAdd.fromiter(terms) class TensorElement(TensExpr): """ Tensor with evaluated components. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, TensorHead, TensorSymmetry >>> from sympy import symbols >>> L = TensorIndexType("L") >>> i, j, k = symbols("i j k") >>> A = TensorHead("A", [L, L], TensorSymmetry.fully_symmetric(2)) >>> A(i, j).get_free_indices() [i, j] If we want to set component ``i`` to a specific value, use the ``TensorElement`` class: >>> from sympy.tensor.tensor import TensorElement >>> te = TensorElement(A(i, j), {i: 2}) As index ``i`` has been accessed (``{i: 2}`` is the evaluation of its 3rd element), the free indices will only contain ``j``: >>> te.get_free_indices() [j] """ def __new__(cls, expr, index_map): if not isinstance(expr, Tensor): # remap if not isinstance(expr, TensExpr): raise TypeError("%s is not a tensor expression" % expr) return expr.func(*[TensorElement(arg, index_map) for arg in expr.args]) expr_free_indices = expr.get_free_indices() name_translation = {i.args[0]: i for i in expr_free_indices} index_map = {name_translation.get(index, index): value for index, value in index_map.items()} index_map = {index: value for index, value in index_map.items() if index in expr_free_indices} if len(index_map) == 0: return expr free_indices = [i for i in expr_free_indices if i not in index_map.keys()] index_map = Dict(index_map) obj = TensExpr.__new__(cls, expr, index_map) obj._free_indices = free_indices return obj @property def free(self): return [(index, i) for i, index in enumerate(self.get_free_indices())] @property def dum(self): # TODO: inherit dummies from expr return [] @property def expr(self): return self._args[0] @property def index_map(self): return self._args[1] @property def coeff(self): return S.One @property def nocoeff(self): return self def get_free_indices(self): return self._free_indices def _replace_indices(self, repl): # type: (tDict[TensorIndex, TensorIndex]) -> TensExpr # TODO: can be improved: return self.xreplace(repl) def get_indices(self): return self.get_free_indices() def _extract_data(self, replacement_dict): ret_indices, array = self.expr._extract_data(replacement_dict) index_map = self.index_map slice_tuple = tuple(index_map.get(i, slice(None)) for i in ret_indices) ret_indices = [i for i in ret_indices if i not in index_map] array = array.__getitem__(slice_tuple) return ret_indices, array def canon_bp(p): """ Butler-Portugal canonicalization. See ``tensor_can.py`` from the combinatorics module for the details. """ if isinstance(p, TensExpr): return p.canon_bp() return p def tensor_mul(*a): """ product of tensors """ if not a: return TensMul.from_data(S.One, [], [], []) t = a[0] for tx in a[1:]: t = t*tx return t def riemann_cyclic_replace(t_r): """ replace Riemann tensor with an equivalent expression ``R(m,n,p,q) -> 2/3*R(m,n,p,q) - 1/3*R(m,q,n,p) + 1/3*R(m,p,n,q)`` """ free = sorted(t_r.free, key=lambda x: x[1]) m, n, p, q = [x[0] for x in free] t0 = t_r*Rational(2, 3) t1 = -t_r.substitute_indices((m,m),(n,q),(p,n),(q,p))*Rational(1, 3) t2 = t_r.substitute_indices((m,m),(n,p),(p,n),(q,q))*Rational(1, 3) t3 = t0 + t1 + t2 return t3 def riemann_cyclic(t2): """ Replace each Riemann tensor with an equivalent expression satisfying the cyclic identity. This trick is discussed in the reference guide to Cadabra. Examples ======== >>> from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorHead, riemann_cyclic, TensorSymmetry >>> Lorentz = TensorIndexType('Lorentz', dummy_name='L') >>> i, j, k, l = tensor_indices('i,j,k,l', Lorentz) >>> R = TensorHead('R', [Lorentz]*4, TensorSymmetry.riemann()) >>> t = R(i,j,k,l)*(R(-i,-j,-k,-l) - 2*R(-i,-k,-j,-l)) >>> riemann_cyclic(t) 0 """ t2 = t2.expand() if isinstance(t2, (TensMul, Tensor)): args = [t2] else: args = t2.args a1 = [x.split() for x in args] a2 = [[riemann_cyclic_replace(tx) for tx in y] for y in a1] a3 = [tensor_mul(*v) for v in a2] t3 = TensAdd(*a3).doit() if not t3: return t3 else: return canon_bp(t3) def get_lines(ex, index_type): """ Returns ``(lines, traces, rest)`` for an index type, where ``lines`` is the list of list of positions of a matrix line, ``traces`` is the list of list of traced matrix lines, ``rest`` is the rest of the elements ot the tensor. """ def _join_lines(a): i = 0 while i < len(a): x = a[i] xend = x[-1] xstart = x[0] hit = True while hit: hit = False for j in range(i + 1, len(a)): if j >= len(a): break if a[j][0] == xend: hit = True x.extend(a[j][1:]) xend = x[-1] a.pop(j) continue if a[j][0] == xstart: hit = True a[i] = reversed(a[j][1:]) + x x = a[i] xstart = a[i][0] a.pop(j) continue if a[j][-1] == xend: hit = True x.extend(reversed(a[j][:-1])) xend = x[-1] a.pop(j) continue if a[j][-1] == xstart: hit = True a[i] = a[j][:-1] + x x = a[i] xstart = x[0] a.pop(j) continue i += 1 return a arguments = ex.args dt = {} for c in ex.args: if not isinstance(c, TensExpr): continue if c in dt: continue index_types = c.index_types a = [] for i in range(len(index_types)): if index_types[i] is index_type: a.append(i) if len(a) > 2: raise ValueError('at most two indices of type %s allowed' % index_type) if len(a) == 2: dt[c] = a #dum = ex.dum lines = [] traces = [] traces1 = [] #indices_to_args_pos = ex._get_indices_to_args_pos() # TODO: add a dum_to_components_map ? for p0, p1, c0, c1 in ex.dum_in_args: if arguments[c0] not in dt: continue if c0 == c1: traces.append([c0]) continue ta0 = dt[arguments[c0]] ta1 = dt[arguments[c1]] if p0 not in ta0: continue if ta0.index(p0) == ta1.index(p1): # case gamma(i,s0,-s1) in c0, gamma(j,-s0,s2) in c1; # to deal with this case one could add to the position # a flag for transposition; # one could write [(c0, False), (c1, True)] raise NotImplementedError # if p0 == ta0[1] then G in pos c0 is mult on the right by G in c1 # if p0 == ta0[0] then G in pos c1 is mult on the right by G in c0 ta0 = dt[arguments[c0]] b0, b1 = (c0, c1) if p0 == ta0[1] else (c1, c0) lines1 = lines[:] for line in lines: if line[-1] == b0: if line[0] == b1: n = line.index(min(line)) traces1.append(line) traces.append(line[n:] + line[:n]) else: line.append(b1) break elif line[0] == b1: line.insert(0, b0) break else: lines1.append([b0, b1]) lines = [x for x in lines1 if x not in traces1] lines = _join_lines(lines) rest = [] for line in lines: for y in line: rest.append(y) for line in traces: for y in line: rest.append(y) rest = [x for x in range(len(arguments)) if x not in rest] return lines, traces, rest def get_free_indices(t): if not isinstance(t, TensExpr): return () return t.get_free_indices() def get_indices(t): if not isinstance(t, TensExpr): return () return t.get_indices() def get_index_structure(t): if isinstance(t, TensExpr): return t._index_structure return _IndexStructure([], [], [], []) def get_coeff(t): if isinstance(t, Tensor): return S.One if isinstance(t, TensMul): return t.coeff if isinstance(t, TensExpr): raise ValueError("no coefficient associated to this tensor expression") return t def contract_metric(t, g): if isinstance(t, TensExpr): return t.contract_metric(g) return t def perm2tensor(t, g, is_canon_bp=False): """ Returns the tensor corresponding to the permutation ``g`` For further details, see the method in ``TIDS`` with the same name. """ if not isinstance(t, TensExpr): return t elif isinstance(t, (Tensor, TensMul)): nim = get_index_structure(t).perm2tensor(g, is_canon_bp=is_canon_bp) res = t._set_new_index_structure(nim, is_canon_bp=is_canon_bp) if g[-1] != len(g) - 1: return -res return res raise NotImplementedError() def substitute_indices(t, *index_tuples): if not isinstance(t, TensExpr): return t return t.substitute_indices(*index_tuples) def _expand(expr, **kwargs): if isinstance(expr, TensExpr): return expr._expand(**kwargs) else: return expr.expand(**kwargs) sympy-sympy-1.9/sympy/tensor/tests/000077500000000000000000000000001412543434000175605ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/tests/__init__.py000066400000000000000000000000001412543434000216570ustar00rootroot00000000000000sympy-sympy-1.9/sympy/tensor/tests/test_functions.py000066400000000000000000000026311412543434000232030ustar00rootroot00000000000000from sympy.tensor.functions import TensorProduct from sympy import MatrixSymbol, Matrix, Array from sympy.abc import x, y, z from sympy.abc import i, j, k, l A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 3, 3) C = MatrixSymbol("C", 3, 3) def test_TensorProduct_construction(): assert TensorProduct(3, 4) == 12 assert isinstance(TensorProduct(A, A), TensorProduct) expr = TensorProduct(TensorProduct(x, y), z) assert expr == x*y*z expr = TensorProduct(TensorProduct(A, B), C) assert expr == TensorProduct(A, B, C) expr = TensorProduct(Matrix.eye(2), [[0, -1], [1, 0]]) assert expr == Array([ [ [[0, -1], [1, 0]], [[0, 0], [0, 0]] ], [ [[0, 0], [0, 0]], [[0, -1], [1, 0]] ] ]) def test_TensorProduct_shape(): expr = TensorProduct(3, 4, evaluate=False) assert expr.shape == () assert expr.rank() == 0 expr = TensorProduct([1, 2], [x, y], evaluate=False) assert expr.shape == (2, 2) assert expr.rank() == 2 expr = TensorProduct(expr, expr, evaluate=False) assert expr.shape == (2, 2, 2, 2) assert expr.rank() == 4 expr = TensorProduct(Matrix.eye(2), [[0, -1], [1, 0]], evaluate=False) assert expr.shape == (2, 2, 2, 2) assert expr.rank() == 4 def test_TensorProduct_getitem(): expr = TensorProduct(A, B) assert expr[i, j, k, l] == A[i, j]*B[k, l] sympy-sympy-1.9/sympy/tensor/tests/test_index_methods.py000066400000000000000000000156611412543434000240340ustar00rootroot00000000000000from sympy.core import symbols, S, Pow, Function from sympy.functions import exp from sympy.testing.pytest import raises from sympy.tensor.indexed import Idx, IndexedBase from sympy.tensor.index_methods import IndexConformanceException from sympy import get_contraction_structure, get_indices def test_trivial_indices(): x, y = symbols('x y') assert get_indices(x) == (set(), {}) assert get_indices(x*y) == (set(), {}) assert get_indices(x + y) == (set(), {}) assert get_indices(x**y) == (set(), {}) def test_get_indices_Indexed(): x = IndexedBase('x') i, j = Idx('i'), Idx('j') assert get_indices(x[i, j]) == ({i, j}, {}) assert get_indices(x[j, i]) == ({j, i}, {}) def test_get_indices_Idx(): f = Function('f') i, j = Idx('i'), Idx('j') assert get_indices(f(i)*j) == ({i, j}, {}) assert get_indices(f(j, i)) == ({j, i}, {}) assert get_indices(f(i)*i) == (set(), {}) def test_get_indices_mul(): x = IndexedBase('x') y = IndexedBase('y') i, j = Idx('i'), Idx('j') assert get_indices(x[j]*y[i]) == ({i, j}, {}) assert get_indices(x[i]*y[j]) == ({i, j}, {}) def test_get_indices_exceptions(): x = IndexedBase('x') y = IndexedBase('y') i, j = Idx('i'), Idx('j') raises(IndexConformanceException, lambda: get_indices(x[i] + y[j])) def test_scalar_broadcast(): x = IndexedBase('x') y = IndexedBase('y') i, j = Idx('i'), Idx('j') assert get_indices(x[i] + y[i, i]) == ({i}, {}) assert get_indices(x[i] + y[j, j]) == ({i}, {}) def test_get_indices_add(): x = IndexedBase('x') y = IndexedBase('y') A = IndexedBase('A') i, j, k = Idx('i'), Idx('j'), Idx('k') assert get_indices(x[i] + 2*y[i]) == ({i}, {}) assert get_indices(y[i] + 2*A[i, j]*x[j]) == ({i}, {}) assert get_indices(y[i] + 2*(x[i] + A[i, j]*x[j])) == ({i}, {}) assert get_indices(y[i] + x[i]*(A[j, j] + 1)) == ({i}, {}) assert get_indices( y[i] + x[i]*x[j]*(y[j] + A[j, k]*x[k])) == ({i}, {}) def test_get_indices_Pow(): x = IndexedBase('x') y = IndexedBase('y') A = IndexedBase('A') i, j, k = Idx('i'), Idx('j'), Idx('k') assert get_indices(Pow(x[i], y[j])) == ({i, j}, {}) assert get_indices(Pow(x[i, k], y[j, k])) == ({i, j, k}, {}) assert get_indices(Pow(A[i, k], y[k] + A[k, j]*x[j])) == ({i, k}, {}) assert get_indices(Pow(2, x[i])) == get_indices(exp(x[i])) # test of a design decision, this may change: assert get_indices(Pow(x[i], 2)) == ({i}, {}) def test_get_contraction_structure_basic(): x = IndexedBase('x') y = IndexedBase('y') i, j = Idx('i'), Idx('j') assert get_contraction_structure(x[i]*y[j]) == {None: {x[i]*y[j]}} assert get_contraction_structure(x[i] + y[j]) == {None: {x[i], y[j]}} assert get_contraction_structure(x[i]*y[i]) == {(i,): {x[i]*y[i]}} assert get_contraction_structure( 1 + x[i]*y[i]) == {None: {S.One}, (i,): {x[i]*y[i]}} assert get_contraction_structure(x[i]**y[i]) == {None: {x[i]**y[i]}} def test_get_contraction_structure_complex(): x = IndexedBase('x') y = IndexedBase('y') A = IndexedBase('A') i, j, k = Idx('i'), Idx('j'), Idx('k') expr1 = y[i] + A[i, j]*x[j] d1 = {None: {y[i]}, (j,): {A[i, j]*x[j]}} assert get_contraction_structure(expr1) == d1 expr2 = expr1*A[k, i] + x[k] d2 = {None: {x[k]}, (i,): {expr1*A[k, i]}, expr1*A[k, i]: [d1]} assert get_contraction_structure(expr2) == d2 def test_contraction_structure_simple_Pow(): x = IndexedBase('x') y = IndexedBase('y') i, j, k = Idx('i'), Idx('j'), Idx('k') ii_jj = x[i, i]**y[j, j] assert get_contraction_structure(ii_jj) == { None: {ii_jj}, ii_jj: [ {(i,): {x[i, i]}}, {(j,): {y[j, j]}} ] } ii_jk = x[i, i]**y[j, k] assert get_contraction_structure(ii_jk) == { None: {x[i, i]**y[j, k]}, x[i, i]**y[j, k]: [ {(i,): {x[i, i]}} ] } def test_contraction_structure_Mul_and_Pow(): x = IndexedBase('x') y = IndexedBase('y') i, j, k = Idx('i'), Idx('j'), Idx('k') i_ji = x[i]**(y[j]*x[i]) assert get_contraction_structure(i_ji) == {None: {i_ji}} ij_i = (x[i]*y[j])**(y[i]) assert get_contraction_structure(ij_i) == {None: {ij_i}} j_ij_i = x[j]*(x[i]*y[j])**(y[i]) assert get_contraction_structure(j_ij_i) == {(j,): {j_ij_i}} j_i_ji = x[j]*x[i]**(y[j]*x[i]) assert get_contraction_structure(j_i_ji) == {(j,): {j_i_ji}} ij_exp_kki = x[i]*y[j]*exp(y[i]*y[k, k]) result = get_contraction_structure(ij_exp_kki) expected = { (i,): {ij_exp_kki}, ij_exp_kki: [{ None: {exp(y[i]*y[k, k])}, exp(y[i]*y[k, k]): [{ None: {y[i]*y[k, k]}, y[i]*y[k, k]: [{(k,): {y[k, k]}}] }]} ] } assert result == expected def test_contraction_structure_Add_in_Pow(): x = IndexedBase('x') y = IndexedBase('y') i, j, k = Idx('i'), Idx('j'), Idx('k') s_ii_jj_s = (1 + x[i, i])**(1 + y[j, j]) expected = { None: {s_ii_jj_s}, s_ii_jj_s: [ {None: {S.One}, (i,): {x[i, i]}}, {None: {S.One}, (j,): {y[j, j]}} ] } result = get_contraction_structure(s_ii_jj_s) assert result == expected s_ii_jk_s = (1 + x[i, i]) ** (1 + y[j, k]) expected_2 = { None: {(x[i, i] + 1)**(y[j, k] + 1)}, s_ii_jk_s: [ {None: {S.One}, (i,): {x[i, i]}} ] } result_2 = get_contraction_structure(s_ii_jk_s) assert result_2 == expected_2 def test_contraction_structure_Pow_in_Pow(): x = IndexedBase('x') y = IndexedBase('y') z = IndexedBase('z') i, j, k = Idx('i'), Idx('j'), Idx('k') ii_jj_kk = x[i, i]**y[j, j]**z[k, k] expected = { None: {ii_jj_kk}, ii_jj_kk: [ {(i,): {x[i, i]}}, { None: {y[j, j]**z[k, k]}, y[j, j]**z[k, k]: [ {(j,): {y[j, j]}}, {(k,): {z[k, k]}} ] } ] } assert get_contraction_structure(ii_jj_kk) == expected def test_ufunc_support(): f = Function('f') g = Function('g') x = IndexedBase('x') y = IndexedBase('y') i, j = Idx('i'), Idx('j') a = symbols('a') assert get_indices(f(x[i])) == ({i}, {}) assert get_indices(f(x[i], y[j])) == ({i, j}, {}) assert get_indices(f(y[i])*g(x[i])) == (set(), {}) assert get_indices(f(a, x[i])) == ({i}, {}) assert get_indices(f(a, y[i], x[j])*g(x[i])) == ({j}, {}) assert get_indices(g(f(x[i]))) == ({i}, {}) assert get_contraction_structure(f(x[i])) == {None: {f(x[i])}} assert get_contraction_structure( f(y[i])*g(x[i])) == {(i,): {f(y[i])*g(x[i])}} assert get_contraction_structure( f(y[i])*g(f(x[i]))) == {(i,): {f(y[i])*g(f(x[i]))}} assert get_contraction_structure( f(x[j], y[i])*g(x[i])) == {(i,): {f(x[j], y[i])*g(x[i])}} sympy-sympy-1.9/sympy/tensor/tests/test_indexed.py000066400000000000000000000367171412543434000226270ustar00rootroot00000000000000from sympy.core import symbols, Symbol, Tuple, oo, Dummy from sympy.core.compatibility import iterable from sympy.tensor.indexed import IndexException from sympy.testing.pytest import raises, XFAIL # import test: from sympy import (IndexedBase, Idx, Indexed, S, sin, cos, exp, log, Sum, Order, LessThan, StrictGreaterThan, GreaterThan, StrictLessThan, Range, Subs, Function, KroneckerDelta, Derivative) def test_Idx_construction(): i, a, b = symbols('i a b', integer=True) assert Idx(i) != Idx(i, 1) assert Idx(i, a) == Idx(i, (0, a - 1)) assert Idx(i, oo) == Idx(i, (0, oo)) x = symbols('x', integer=False) raises(TypeError, lambda: Idx(x)) raises(TypeError, lambda: Idx(0.5)) raises(TypeError, lambda: Idx(i, x)) raises(TypeError, lambda: Idx(i, 0.5)) raises(TypeError, lambda: Idx(i, (x, 5))) raises(TypeError, lambda: Idx(i, (2, x))) raises(TypeError, lambda: Idx(i, (2, 3.5))) def test_Idx_properties(): i, a, b = symbols('i a b', integer=True) assert Idx(i).is_integer assert Idx(i).name == 'i' assert Idx(i + 2).name == 'i + 2' assert Idx('foo').name == 'foo' def test_Idx_bounds(): i, a, b = symbols('i a b', integer=True) assert Idx(i).lower is None assert Idx(i).upper is None assert Idx(i, a).lower == 0 assert Idx(i, a).upper == a - 1 assert Idx(i, 5).lower == 0 assert Idx(i, 5).upper == 4 assert Idx(i, oo).lower == 0 assert Idx(i, oo).upper is oo assert Idx(i, (a, b)).lower == a assert Idx(i, (a, b)).upper == b assert Idx(i, (1, 5)).lower == 1 assert Idx(i, (1, 5)).upper == 5 assert Idx(i, (-oo, oo)).lower is -oo assert Idx(i, (-oo, oo)).upper is oo def test_Idx_fixed_bounds(): i, a, b, x = symbols('i a b x', integer=True) assert Idx(x).lower is None assert Idx(x).upper is None assert Idx(x, a).lower == 0 assert Idx(x, a).upper == a - 1 assert Idx(x, 5).lower == 0 assert Idx(x, 5).upper == 4 assert Idx(x, oo).lower == 0 assert Idx(x, oo).upper is oo assert Idx(x, (a, b)).lower == a assert Idx(x, (a, b)).upper == b assert Idx(x, (1, 5)).lower == 1 assert Idx(x, (1, 5)).upper == 5 assert Idx(x, (-oo, oo)).lower is -oo assert Idx(x, (-oo, oo)).upper is oo def test_Idx_inequalities(): i14 = Idx("i14", (1, 4)) i79 = Idx("i79", (7, 9)) i46 = Idx("i46", (4, 6)) i35 = Idx("i35", (3, 5)) assert i14 <= 5 assert i14 < 5 assert not (i14 >= 5) assert not (i14 > 5) assert 5 >= i14 assert 5 > i14 assert not (5 <= i14) assert not (5 < i14) assert LessThan(i14, 5) assert StrictLessThan(i14, 5) assert not GreaterThan(i14, 5) assert not StrictGreaterThan(i14, 5) assert i14 <= 4 assert isinstance(i14 < 4, StrictLessThan) assert isinstance(i14 >= 4, GreaterThan) assert not (i14 > 4) assert isinstance(i14 <= 1, LessThan) assert not (i14 < 1) assert i14 >= 1 assert isinstance(i14 > 1, StrictGreaterThan) assert not (i14 <= 0) assert not (i14 < 0) assert i14 >= 0 assert i14 > 0 from sympy.abc import x assert isinstance(i14 < x, StrictLessThan) assert isinstance(i14 > x, StrictGreaterThan) assert isinstance(i14 <= x, LessThan) assert isinstance(i14 >= x, GreaterThan) assert i14 < i79 assert i14 <= i79 assert not (i14 > i79) assert not (i14 >= i79) assert i14 <= i46 assert isinstance(i14 < i46, StrictLessThan) assert isinstance(i14 >= i46, GreaterThan) assert not (i14 > i46) assert isinstance(i14 < i35, StrictLessThan) assert isinstance(i14 > i35, StrictGreaterThan) assert isinstance(i14 <= i35, LessThan) assert isinstance(i14 >= i35, GreaterThan) iNone1 = Idx("iNone1") iNone2 = Idx("iNone2") assert isinstance(iNone1 < iNone2, StrictLessThan) assert isinstance(iNone1 > iNone2, StrictGreaterThan) assert isinstance(iNone1 <= iNone2, LessThan) assert isinstance(iNone1 >= iNone2, GreaterThan) @XFAIL def test_Idx_inequalities_current_fails(): i14 = Idx("i14", (1, 4)) assert S(5) >= i14 assert S(5) > i14 assert not (S(5) <= i14) assert not (S(5) < i14) def test_Idx_func_args(): i, a, b = symbols('i a b', integer=True) ii = Idx(i) assert ii.func(*ii.args) == ii ii = Idx(i, a) assert ii.func(*ii.args) == ii ii = Idx(i, (a, b)) assert ii.func(*ii.args) == ii def test_Idx_subs(): i, a, b = symbols('i a b', integer=True) assert Idx(i, a).subs(a, b) == Idx(i, b) assert Idx(i, a).subs(i, b) == Idx(b, a) assert Idx(i).subs(i, 2) == Idx(2) assert Idx(i, a).subs(a, 2) == Idx(i, 2) assert Idx(i, (a, b)).subs(i, 2) == Idx(2, (a, b)) def test_IndexedBase_sugar(): i, j = symbols('i j', integer=True) a = symbols('a') A1 = Indexed(a, i, j) A2 = IndexedBase(a) assert A1 == A2[i, j] assert A1 == A2[(i, j)] assert A1 == A2[[i, j]] assert A1 == A2[Tuple(i, j)] assert all(a.is_Integer for a in A2[1, 0].args[1:]) def test_IndexedBase_subs(): i = symbols('i', integer=True) a, b = symbols('a b') A = IndexedBase(a) B = IndexedBase(b) assert A[i] == B[i].subs(b, a) C = {1: 2} assert C[1] == A[1].subs(A, C) def test_IndexedBase_shape(): i, j, m, n = symbols('i j m n', integer=True) a = IndexedBase('a', shape=(m, m)) b = IndexedBase('a', shape=(m, n)) assert b.shape == Tuple(m, n) assert a[i, j] != b[i, j] assert a[i, j] == b[i, j].subs(n, m) assert b.func(*b.args) == b assert b[i, j].func(*b[i, j].args) == b[i, j] raises(IndexException, lambda: b[i]) raises(IndexException, lambda: b[i, i, j]) F = IndexedBase("F", shape=m) assert F.shape == Tuple(m) assert F[i].subs(i, j) == F[j] raises(IndexException, lambda: F[i, j]) def test_IndexedBase_assumptions(): i = Symbol('i', integer=True) a = Symbol('a') A = IndexedBase(a, positive=True) for c in (A, A[i]): assert c.is_real assert c.is_complex assert not c.is_imaginary assert c.is_nonnegative assert c.is_nonzero assert c.is_commutative assert log(exp(c)) == c assert A != IndexedBase(a) assert A == IndexedBase(a, positive=True, real=True) assert A[i] != Indexed(a, i) def test_IndexedBase_assumptions_inheritance(): I = Symbol('I', integer=True) I_inherit = IndexedBase(I) I_explicit = IndexedBase('I', integer=True) assert I_inherit.is_integer assert I_explicit.is_integer assert I_inherit.label.is_integer assert I_explicit.label.is_integer assert I_inherit == I_explicit def test_issue_17652(): """Regression test issue #17652. IndexedBase.label should not upcast subclasses of Symbol """ class SubClass(Symbol): pass x = SubClass('X') assert type(x) == SubClass base = IndexedBase(x) assert type(x) == SubClass assert type(base.label) == SubClass def test_Indexed_constructor(): i, j = symbols('i j', integer=True) A = Indexed('A', i, j) assert A == Indexed(Symbol('A'), i, j) assert A == Indexed(IndexedBase('A'), i, j) raises(TypeError, lambda: Indexed(A, i, j)) raises(IndexException, lambda: Indexed("A")) assert A.free_symbols == {A, A.base.label, i, j} def test_Indexed_func_args(): i, j = symbols('i j', integer=True) a = symbols('a') A = Indexed(a, i, j) assert A == A.func(*A.args) def test_Indexed_subs(): i, j, k = symbols('i j k', integer=True) a, b = symbols('a b') A = IndexedBase(a) B = IndexedBase(b) assert A[i, j] == B[i, j].subs(b, a) assert A[i, j] == A[i, k].subs(k, j) def test_Indexed_properties(): i, j = symbols('i j', integer=True) A = Indexed('A', i, j) assert A.name == 'A[i, j]' assert A.rank == 2 assert A.indices == (i, j) assert A.base == IndexedBase('A') assert A.ranges == [None, None] raises(IndexException, lambda: A.shape) n, m = symbols('n m', integer=True) assert Indexed('A', Idx( i, m), Idx(j, n)).ranges == [Tuple(0, m - 1), Tuple(0, n - 1)] assert Indexed('A', Idx(i, m), Idx(j, n)).shape == Tuple(m, n) raises(IndexException, lambda: Indexed("A", Idx(i, m), Idx(j)).shape) def test_Indexed_shape_precedence(): i, j = symbols('i j', integer=True) o, p = symbols('o p', integer=True) n, m = symbols('n m', integer=True) a = IndexedBase('a', shape=(o, p)) assert a.shape == Tuple(o, p) assert Indexed( a, Idx(i, m), Idx(j, n)).ranges == [Tuple(0, m - 1), Tuple(0, n - 1)] assert Indexed(a, Idx(i, m), Idx(j, n)).shape == Tuple(o, p) assert Indexed( a, Idx(i, m), Idx(j)).ranges == [Tuple(0, m - 1), Tuple(None, None)] assert Indexed(a, Idx(i, m), Idx(j)).shape == Tuple(o, p) def test_complex_indices(): i, j = symbols('i j', integer=True) A = Indexed('A', i, i + j) assert A.rank == 2 assert A.indices == (i, i + j) def test_not_interable(): i, j = symbols('i j', integer=True) A = Indexed('A', i, i + j) assert not iterable(A) def test_Indexed_coeff(): N = Symbol('N', integer=True) len_y = N i = Idx('i', len_y-1) y = IndexedBase('y', shape=(len_y,)) a = (1/y[i+1]*y[i]).coeff(y[i]) b = (y[i]/y[i+1]).coeff(y[i]) assert a == b def test_differentiation(): from sympy.functions.special.tensor_functions import KroneckerDelta i, j, k, l = symbols('i j k l', cls=Idx) a = symbols('a') m, n = symbols("m, n", integer=True, finite=True) assert m.is_real h, L = symbols('h L', cls=IndexedBase) hi, hj = h[i], h[j] expr = hi assert expr.diff(hj) == KroneckerDelta(i, j) assert expr.diff(hi) == KroneckerDelta(i, i) expr = S(2) * hi assert expr.diff(hj) == S(2) * KroneckerDelta(i, j) assert expr.diff(hi) == S(2) * KroneckerDelta(i, i) assert expr.diff(a) is S.Zero assert Sum(expr, (i, -oo, oo)).diff(hj) == Sum(2*KroneckerDelta(i, j), (i, -oo, oo)) assert Sum(expr.diff(hj), (i, -oo, oo)) == Sum(2*KroneckerDelta(i, j), (i, -oo, oo)) assert Sum(expr, (i, -oo, oo)).diff(hj).doit() == 2 assert Sum(expr.diff(hi), (i, -oo, oo)).doit() == Sum(2, (i, -oo, oo)).doit() assert Sum(expr, (i, -oo, oo)).diff(hi).doit() is oo expr = a * hj * hj / S(2) assert expr.diff(hi) == a * h[j] * KroneckerDelta(i, j) assert expr.diff(a) == hj * hj / S(2) assert expr.diff(a, 2) is S.Zero assert Sum(expr, (i, -oo, oo)).diff(hi) == Sum(a*KroneckerDelta(i, j)*h[j], (i, -oo, oo)) assert Sum(expr.diff(hi), (i, -oo, oo)) == Sum(a*KroneckerDelta(i, j)*h[j], (i, -oo, oo)) assert Sum(expr, (i, -oo, oo)).diff(hi).doit() == a*h[j] assert Sum(expr, (j, -oo, oo)).diff(hi) == Sum(a*KroneckerDelta(i, j)*h[j], (j, -oo, oo)) assert Sum(expr.diff(hi), (j, -oo, oo)) == Sum(a*KroneckerDelta(i, j)*h[j], (j, -oo, oo)) assert Sum(expr, (j, -oo, oo)).diff(hi).doit() == a*h[i] expr = a * sin(hj * hj) assert expr.diff(hi) == 2*a*cos(hj * hj) * hj * KroneckerDelta(i, j) assert expr.diff(hj) == 2*a*cos(hj * hj) * hj expr = a * L[i, j] * h[j] assert expr.diff(hi) == a*L[i, j]*KroneckerDelta(i, j) assert expr.diff(hj) == a*L[i, j] assert expr.diff(L[i, j]) == a*h[j] assert expr.diff(L[k, l]) == a*KroneckerDelta(i, k)*KroneckerDelta(j, l)*h[j] assert expr.diff(L[i, l]) == a*KroneckerDelta(j, l)*h[j] assert Sum(expr, (j, -oo, oo)).diff(L[k, l]) == Sum(a * KroneckerDelta(i, k) * KroneckerDelta(j, l) * h[j], (j, -oo, oo)) assert Sum(expr, (j, -oo, oo)).diff(L[k, l]).doit() == a * KroneckerDelta(i, k) * h[l] assert h[m].diff(h[m]) == 1 assert h[m].diff(h[n]) == KroneckerDelta(m, n) assert Sum(a*h[m], (m, -oo, oo)).diff(h[n]) == Sum(a*KroneckerDelta(m, n), (m, -oo, oo)) assert Sum(a*h[m], (m, -oo, oo)).diff(h[n]).doit() == a assert Sum(a*h[m], (n, -oo, oo)).diff(h[n]) == Sum(a*KroneckerDelta(m, n), (n, -oo, oo)) assert Sum(a*h[m], (m, -oo, oo)).diff(h[m]).doit() == oo*a def test_indexed_series(): A = IndexedBase("A") i = symbols("i", integer=True) assert sin(A[i]).series(A[i]) == A[i] - A[i]**3/6 + A[i]**5/120 + Order(A[i]**6, A[i]) def test_indexed_is_constant(): A = IndexedBase("A") i, j, k = symbols("i,j,k") assert not A[i].is_constant() assert A[i].is_constant(j) assert not A[1+2*i, k].is_constant() assert not A[1+2*i, k].is_constant(i) assert A[1+2*i, k].is_constant(j) assert not A[1+2*i, k].is_constant(k) def test_issue_12533(): d = IndexedBase('d') assert IndexedBase(range(5)) == Range(0, 5, 1) assert d[0].subs(Symbol("d"), range(5)) == 0 assert d[0].subs(d, range(5)) == 0 assert d[1].subs(d, range(5)) == 1 assert Indexed(Range(5), 2) == 2 def test_issue_12780(): n = symbols("n") i = Idx("i", (0, n)) raises(TypeError, lambda: i.subs(n, 1.5)) def test_issue_18604(): m = symbols("m") assert Idx("i", m).name == 'i' assert Idx("i", m).lower == 0 assert Idx("i", m).upper == m - 1 m = symbols("m", real=False) raises(TypeError, lambda: Idx("i", m)) def test_Subs_with_Indexed(): A = IndexedBase("A") i, j, k = symbols("i,j,k") x, y, z = symbols("x,y,z") f = Function("f") assert Subs(A[i], A[i], A[j]).diff(A[j]) == 1 assert Subs(A[i], A[i], x).diff(A[i]) == 0 assert Subs(A[i], A[i], x).diff(A[j]) == 0 assert Subs(A[i], A[i], x).diff(x) == 1 assert Subs(A[i], A[i], x).diff(y) == 0 assert Subs(A[i], A[i], A[j]).diff(A[k]) == KroneckerDelta(j, k) assert Subs(x, x, A[i]).diff(A[j]) == KroneckerDelta(i, j) assert Subs(f(A[i]), A[i], x).diff(A[j]) == 0 assert Subs(f(A[i]), A[i], A[k]).diff(A[j]) == Derivative(f(A[k]), A[k])*KroneckerDelta(j, k) assert Subs(x, x, A[i]**2).diff(A[j]) == 2*KroneckerDelta(i, j)*A[i] assert Subs(A[i], A[i], A[j]**2).diff(A[k]) == 2*KroneckerDelta(j, k)*A[j] assert Subs(A[i]*x, x, A[i]).diff(A[i]) == 2*A[i] assert Subs(A[i]*x, x, A[i]).diff(A[j]) == 2*A[i]*KroneckerDelta(i, j) assert Subs(A[i]*x, x, A[j]).diff(A[i]) == A[j] + A[i]*KroneckerDelta(i, j) assert Subs(A[i]*x, x, A[j]).diff(A[j]) == A[i] + A[j]*KroneckerDelta(i, j) assert Subs(A[i]*x, x, A[i]).diff(A[k]) == 2*A[i]*KroneckerDelta(i, k) assert Subs(A[i]*x, x, A[j]).diff(A[k]) == KroneckerDelta(i, k)*A[j] + KroneckerDelta(j, k)*A[i] assert Subs(A[i]*x, A[i], x).diff(A[i]) == 0 assert Subs(A[i]*x, A[i], x).diff(A[j]) == 0 assert Subs(A[i]*x, A[j], x).diff(A[i]) == x assert Subs(A[i]*x, A[j], x).diff(A[j]) == x*KroneckerDelta(i, j) assert Subs(A[i]*x, A[i], x).diff(A[k]) == 0 assert Subs(A[i]*x, A[j], x).diff(A[k]) == x*KroneckerDelta(i, k) def test_complicated_derivative_with_Indexed(): x, y = symbols("x,y", cls=IndexedBase) sigma = symbols("sigma") i, j, k = symbols("i,j,k") m0,m1,m2,m3,m4,m5 = symbols("m0:6") f = Function("f") expr = f((x[i] - y[i])**2/sigma) _xi_1 = symbols("xi_1", cls=Dummy) assert expr.diff(x[m0]).dummy_eq( (x[i] - y[i])*KroneckerDelta(i, m0)*\ 2*Subs( Derivative(f(_xi_1), _xi_1), (_xi_1,), ((x[i] - y[i])**2/sigma,) )/sigma ) assert expr.diff(x[m0]).diff(x[m1]).dummy_eq( 2*KroneckerDelta(i, m0)*\ KroneckerDelta(i, m1)*Subs( Derivative(f(_xi_1), _xi_1), (_xi_1,), ((x[i] - y[i])**2/sigma,) )/sigma + \ 4*(x[i] - y[i])**2*KroneckerDelta(i, m0)*KroneckerDelta(i, m1)*\ Subs( Derivative(f(_xi_1), _xi_1, _xi_1), (_xi_1,), ((x[i] - y[i])**2/sigma,) )/sigma**2 ) sympy-sympy-1.9/sympy/tensor/tests/test_tensor.py000066400000000000000000002125221412543434000225070ustar00rootroot00000000000000from functools import wraps from sympy import Matrix, eye, Integer, expand, Indexed, Sum from sympy.combinatorics import Permutation from sympy.core import S, Rational, Symbol, Basic, Add from sympy.core.containers import Tuple from sympy.core.symbol import symbols from sympy.functions.elementary.miscellaneous import sqrt from sympy.tensor.array import Array from sympy.tensor.tensor import TensorIndexType, tensor_indices, TensorSymmetry, \ get_symmetric_group_sgs, TensorIndex, tensor_mul, TensAdd, \ riemann_cyclic_replace, riemann_cyclic, TensMul, tensor_heads, \ TensorManager, TensExpr, TensorHead, canon_bp, \ tensorhead, tensorsymmetry, TensorType, substitute_indices from sympy.testing.pytest import raises, XFAIL, warns_deprecated_sympy, ignore_warnings from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.matrices import diag def filter_warnings_decorator(f): @wraps(f) def wrapper(): with ignore_warnings(SymPyDeprecationWarning): f() return wrapper def _is_equal(arg1, arg2): if isinstance(arg1, TensExpr): return arg1.equals(arg2) elif isinstance(arg2, TensExpr): return arg2.equals(arg1) return arg1 == arg2 #################### Tests from tensor_can.py ####################### def test_canonicalize_no_slot_sym(): # A_d0 * B^d0; T_c = A^d0*B_d0 Lorentz = TensorIndexType('Lorentz', dummy_name='L') a, b, d0, d1 = tensor_indices('a,b,d0,d1', Lorentz) A, B = tensor_heads('A,B', [Lorentz], TensorSymmetry.no_symmetry(1)) t = A(-d0)*B(d0) tc = t.canon_bp() assert str(tc) == 'A(L_0)*B(-L_0)' # A^a * B^b; T_c = T t = A(a)*B(b) tc = t.canon_bp() assert tc == t # B^b * A^a t1 = B(b)*A(a) tc = t1.canon_bp() assert str(tc) == 'A(a)*B(b)' # A symmetric # A^{b}_{d0}*A^{d0, a}; T_c = A^{a d0}*A{b}_{d0} A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) t = A(b, -d0)*A(d0, a) tc = t.canon_bp() assert str(tc) == 'A(a, L_0)*A(b, -L_0)' # A^{d1}_{d0}*B^d0*C_d1 # T_c = A^{d0 d1}*B_d0*C_d1 B, C = tensor_heads('B,C', [Lorentz], TensorSymmetry.no_symmetry(1)) t = A(d1, -d0)*B(d0)*C(-d1) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1)*B(-L_0)*C(-L_1)' # A without symmetry # A^{d1}_{d0}*B^d0*C_d1 ord=[d0,-d0,d1,-d1]; g = [2,1,0,3,4,5] # T_c = A^{d0 d1}*B_d1*C_d0; can = [0,2,3,1,4,5] A = TensorHead('A', [Lorentz]*2, TensorSymmetry.no_symmetry(2)) t = A(d1, -d0)*B(d0)*C(-d1) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1)*B(-L_1)*C(-L_0)' # A, B without symmetry # A^{d1}_{d0}*B_{d1}^{d0} # T_c = A^{d0 d1}*B_{d0 d1} B = TensorHead('B', [Lorentz]*2, TensorSymmetry.no_symmetry(2)) t = A(d1, -d0)*B(-d1, d0) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1)*B(-L_0, -L_1)' # A_{d0}^{d1}*B_{d1}^{d0} # T_c = A^{d0 d1}*B_{d1 d0} t = A(-d0, d1)*B(-d1, d0) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1)*B(-L_1, -L_0)' # A, B, C without symmetry # A^{d1 d0}*B_{a d0}*C_{d1 b} # T_c=A^{d0 d1}*B_{a d1}*C_{d0 b} C = TensorHead('C', [Lorentz]*2, TensorSymmetry.no_symmetry(2)) t = A(d1, d0)*B(-a, -d0)*C(-d1, -b) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1)*B(-a, -L_1)*C(-L_0, -b)' # A symmetric, B and C without symmetry # A^{d1 d0}*B_{a d0}*C_{d1 b} # T_c = A^{d0 d1}*B_{a d0}*C_{d1 b} A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) t = A(d1, d0)*B(-a, -d0)*C(-d1, -b) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1)*B(-a, -L_0)*C(-L_1, -b)' # A and C symmetric, B without symmetry # A^{d1 d0}*B_{a d0}*C_{d1 b} ord=[a,b,d0,-d0,d1,-d1] # T_c = A^{d0 d1}*B_{a d0}*C_{b d1} C = TensorHead('C', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) t = A(d1, d0)*B(-a, -d0)*C(-d1, -b) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1)*B(-a, -L_0)*C(-b, -L_1)' def test_canonicalize_no_dummies(): Lorentz = TensorIndexType('Lorentz', dummy_name='L') a, b, c, d = tensor_indices('a, b, c, d', Lorentz) # A commuting # A^c A^b A^a # T_c = A^a A^b A^c A = TensorHead('A', [Lorentz], TensorSymmetry.no_symmetry(1)) t = A(c)*A(b)*A(a) tc = t.canon_bp() assert str(tc) == 'A(a)*A(b)*A(c)' # A anticommuting # A^c A^b A^a # T_c = -A^a A^b A^c A = TensorHead('A', [Lorentz], TensorSymmetry.no_symmetry(1), 1) t = A(c)*A(b)*A(a) tc = t.canon_bp() assert str(tc) == '-A(a)*A(b)*A(c)' # A commuting and symmetric # A^{b,d}*A^{c,a} # T_c = A^{a c}*A^{b d} A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) t = A(b, d)*A(c, a) tc = t.canon_bp() assert str(tc) == 'A(a, c)*A(b, d)' # A anticommuting and symmetric # A^{b,d}*A^{c,a} # T_c = -A^{a c}*A^{b d} A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(2), 1) t = A(b, d)*A(c, a) tc = t.canon_bp() assert str(tc) == '-A(a, c)*A(b, d)' # A^{c,a}*A^{b,d} # T_c = A^{a c}*A^{b d} t = A(c, a)*A(b, d) tc = t.canon_bp() assert str(tc) == 'A(a, c)*A(b, d)' def test_tensorhead_construction_without_symmetry(): L = TensorIndexType('Lorentz') A1 = TensorHead('A', [L, L]) A2 = TensorHead('A', [L, L], TensorSymmetry.no_symmetry(2)) assert A1 == A2 A3 = TensorHead('A', [L, L], TensorSymmetry.fully_symmetric(2)) # Symmetric assert A1 != A3 def test_no_metric_symmetry(): # no metric symmetry; A no symmetry # A^d1_d0 * A^d0_d1 # T_c = A^d0_d1 * A^d1_d0 Lorentz = TensorIndexType('Lorentz', dummy_name='L', metric_symmetry=0) d0, d1, d2, d3 = tensor_indices('d:4', Lorentz) A = TensorHead('A', [Lorentz]*2, TensorSymmetry.no_symmetry(2)) t = A(d1, -d0)*A(d0, -d1) tc = t.canon_bp() assert str(tc) == 'A(L_0, -L_1)*A(L_1, -L_0)' # A^d1_d2 * A^d0_d3 * A^d2_d1 * A^d3_d0 # T_c = A^d0_d1 * A^d1_d0 * A^d2_d3 * A^d3_d2 t = A(d1, -d2)*A(d0, -d3)*A(d2, -d1)*A(d3, -d0) tc = t.canon_bp() assert str(tc) == 'A(L_0, -L_1)*A(L_1, -L_0)*A(L_2, -L_3)*A(L_3, -L_2)' # A^d0_d2 * A^d1_d3 * A^d3_d0 * A^d2_d1 # T_c = A^d0_d1 * A^d1_d2 * A^d2_d3 * A^d3_d0 t = A(d0, -d1)*A(d1, -d2)*A(d2, -d3)*A(d3, -d0) tc = t.canon_bp() assert str(tc) == 'A(L_0, -L_1)*A(L_1, -L_2)*A(L_2, -L_3)*A(L_3, -L_0)' def test_canonicalize1(): Lorentz = TensorIndexType('Lorentz', dummy_name='L') a, a0, a1, a2, a3, b, d0, d1, d2, d3 = \ tensor_indices('a,a0,a1,a2,a3,b,d0,d1,d2,d3', Lorentz) # A_d0*A^d0; ord = [d0,-d0] # T_c = A^d0*A_d0 A = TensorHead('A', [Lorentz], TensorSymmetry.no_symmetry(1)) t = A(-d0)*A(d0) tc = t.canon_bp() assert str(tc) == 'A(L_0)*A(-L_0)' # A commuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0 # T_c = A^d0*A_d0*A^d1*A_d1*A^d2*A_d2 t = A(-d0)*A(-d1)*A(-d2)*A(d2)*A(d1)*A(d0) tc = t.canon_bp() assert str(tc) == 'A(L_0)*A(-L_0)*A(L_1)*A(-L_1)*A(L_2)*A(-L_2)' # A anticommuting # A_d0*A_d1*A_d2*A^d2*A^d1*A^d0 # T_c 0 A = TensorHead('A', [Lorentz], TensorSymmetry.no_symmetry(1), 1) t = A(-d0)*A(-d1)*A(-d2)*A(d2)*A(d1)*A(d0) tc = t.canon_bp() assert tc == 0 # A commuting symmetric # A^{d0 b}*A^a_d1*A^d1_d0 # T_c = A^{a d0}*A^{b d1}*A_{d0 d1} A = TensorHead('A', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) t = A(d0, b)*A(a, -d1)*A(d1, -d0) tc = t.canon_bp() assert str(tc) == 'A(a, L_0)*A(b, L_1)*A(-L_0, -L_1)' # A, B commuting symmetric # A^{d0 b}*A^d1_d0*B^a_d1 # T_c = A^{b d0}*A_d0^d1*B^a_d1 B = TensorHead('B', [Lorentz]*2, TensorSymmetry.fully_symmetric(2)) t = A(d0, b)*A(d1, -d0)*B(a, -d1) tc = t.canon_bp() assert str(tc) == 'A(b, L_0)*A(-L_0, L_1)*B(a, -L_1)' # A commuting symmetric # A^{d1 d0 b}*A^{a}_{d1 d0}; ord=[a,b, d0,-d0,d1,-d1] # T_c = A^{a d0 d1}*A^{b}_{d0 d1} A = TensorHead('A', [Lorentz]*3, TensorSymmetry.fully_symmetric(3)) t = A(d1, d0, b)*A(a, -d1, -d0) tc = t.canon_bp() assert str(tc) == 'A(a, L_0, L_1)*A(b, -L_0, -L_1)' # A^{d3 d0 d2}*A^a0_{d1 d2}*A^d1_d3^a1*A^{a2 a3}_d0 # T_c = A^{a0 d0 d1}*A^a1_d0^d2*A^{a2 a3 d3}*A_{d1 d2 d3} t = A(d3, d0, d2)*A(a0, -d1, -d2)*A(d1, -d3, a1)*A(a2, a3, -d0) tc = t.canon_bp() assert str(tc) == 'A(a0, L_0, L_1)*A(a1, -L_0, L_2)*A(a2, a3, L_3)*A(-L_1, -L_2, -L_3)' # A commuting symmetric, B antisymmetric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # in this esxample and in the next three, # renaming dummy indices and using symmetry of A, # T = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 # can = 0 A = TensorHead('A', [Lorentz]*3, TensorSymmetry.fully_symmetric(3)) B = TensorHead('B', [Lorentz]*2, TensorSymmetry.fully_symmetric(-2)) t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) tc = t.canon_bp() assert tc == 0 # A anticommuting symmetric, B antisymmetric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} A = TensorHead('A', [Lorentz]*3, TensorSymmetry.fully_symmetric(3), 1) B = TensorHead('B', [Lorentz]*2, TensorSymmetry.fully_symmetric(-2)) t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) tc = t.canon_bp() assert str(tc) == 'A(L_0, L_1, L_2)*A(-L_0, -L_1, L_3)*B(-L_2, -L_3)' # A anticommuting symmetric, B antisymmetric commuting, antisymmetric metric # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = -A^{d0 d1 d2} * A_{d0 d1}^d3 * B_{d2 d3} Spinor = TensorIndexType('Spinor', dummy_name='S', metric_symmetry=-1) a, a0, a1, a2, a3, b, d0, d1, d2, d3 = \ tensor_indices('a,a0,a1,a2,a3,b,d0,d1,d2,d3', Spinor) A = TensorHead('A', [Spinor]*3, TensorSymmetry.fully_symmetric(3), 1) B = TensorHead('B', [Spinor]*2, TensorSymmetry.fully_symmetric(-2)) t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) tc = t.canon_bp() assert str(tc) == '-A(S_0, S_1, S_2)*A(-S_0, -S_1, S_3)*B(-S_2, -S_3)' # A anticommuting symmetric, B antisymmetric anticommuting, # no metric symmetry # A^{d0 d1 d2} * A_{d2 d3 d1} * B_d0^d3 # T_c = A^{d0 d1 d2} * A_{d0 d1 d3} * B_d2^d3 Mat = TensorIndexType('Mat', metric_symmetry=0, dummy_name='M') a, a0, a1, a2, a3, b, d0, d1, d2, d3 = \ tensor_indices('a,a0,a1,a2,a3,b,d0,d1,d2,d3', Mat) A = TensorHead('A', [Mat]*3, TensorSymmetry.fully_symmetric(3), 1) B = TensorHead('B', [Mat]*2, TensorSymmetry.fully_symmetric(-2)) t = A(d0, d1, d2)*A(-d2, -d3, -d1)*B(-d0, d3) tc = t.canon_bp() assert str(tc) == 'A(M_0, M_1, M_2)*A(-M_0, -M_1, -M_3)*B(-M_2, M_3)' # Gamma anticommuting # Gamma_{mu nu} * gamma^rho * Gamma^{nu mu alpha} # T_c = -Gamma^{mu nu} * gamma^rho * Gamma_{alpha mu nu} alpha, beta, gamma, mu, nu, rho = \ tensor_indices('alpha,beta,gamma,mu,nu,rho', Lorentz) Gamma = TensorHead('Gamma', [Lorentz], TensorSymmetry.fully_symmetric(1), 2) Gamma2 = TensorHead('Gamma', [Lorentz]*2, TensorSymmetry.fully_symmetric(-2), 2) Gamma3 = TensorHead('Gamma', [Lorentz]*3, TensorSymmetry.fully_symmetric(-3), 2) t = Gamma2(-mu, -nu)*Gamma(rho)*Gamma3(nu, mu, alpha) tc = t.canon_bp() assert str(tc) == '-Gamma(L_0, L_1)*Gamma(rho)*Gamma(alpha, -L_0, -L_1)' # Gamma_{mu nu} * Gamma^{gamma beta} * gamma_rho * Gamma^{nu mu alpha} # T_c = Gamma^{mu nu} * Gamma^{beta gamma} * gamma_rho * Gamma^alpha_{mu nu} t = Gamma2(mu, nu)*Gamma2(beta, gamma)*Gamma(-rho)*Gamma3(alpha, -mu, -nu) tc = t.canon_bp() assert str(tc) == 'Gamma(L_0, L_1)*Gamma(beta, gamma)*Gamma(-rho)*Gamma(alpha, -L_0, -L_1)' # f^a_{b,c} antisymmetric in b,c; A_mu^a no symmetry # f^c_{d a} * f_{c e b} * A_mu^d * A_nu^a * A^{nu e} * A^{mu b} # g = [8,11,5, 9,13,7, 1,10, 3,4, 2,12, 0,6, 14,15] # T_c = -f^{a b c} * f_a^{d e} * A^mu_b * A_{mu d} * A^nu_c * A_{nu e} Flavor = TensorIndexType('Flavor', dummy_name='F') a, b, c, d, e, ff = tensor_indices('a,b,c,d,e,f', Flavor) mu, nu = tensor_indices('mu,nu', Lorentz) f = TensorHead('f', [Flavor]*3, TensorSymmetry.direct_product(1, -2)) A = TensorHead('A', [Lorentz, Flavor], TensorSymmetry.no_symmetry(2)) t = f(c, -d, -a)*f(-c, -e, -b)*A(-mu, d)*A(-nu, a)*A(nu, e)*A(mu, b) tc = t.canon_bp() assert str(tc) == '-f(F_0, F_1, F_2)*f(-F_0, F_3, F_4)*A(L_0, -F_1)*A(-L_0, -F_3)*A(L_1, -F_2)*A(-L_1, -F_4)' def test_bug_correction_tensor_indices(): # to make sure that tensor_indices does not return a list if creating # only one index: A = TensorIndexType("A") i = tensor_indices('i', A) assert not isinstance(i, (tuple, list)) assert isinstance(i, TensorIndex) def test_riemann_invariants(): Lorentz = TensorIndexType('Lorentz', dummy_name='L') d0, d1, d2, d3, d4, d5, d6, d7, d8, d9, d10, d11 = \ tensor_indices('d0:12', Lorentz) # R^{d0 d1}_{d1 d0}; ord = [d0,-d0,d1,-d1] # T_c = -R^{d0 d1}_{d0 d1} R = TensorHead('R', [Lorentz]*4, TensorSymmetry.riemann()) t = R(d0, d1, -d1, -d0) tc = t.canon_bp() assert str(tc) == '-R(L_0, L_1, -L_0, -L_1)' # R_d11^d1_d0^d5 * R^{d6 d4 d0}_d5 * R_{d7 d2 d8 d9} * # R_{d10 d3 d6 d4} * R^{d2 d7 d11}_d1 * R^{d8 d9 d3 d10} # can = [0,2,4,6, 1,3,8,10, 5,7,12,14, 9,11,16,18, 13,15,20,22, # 17,19,21>> from sympy.tensor.tensor import TensorIndexType, TensorHead >>> from sympy.tensor.toperators import PartialDerivative >>> from sympy import symbols >>> L = TensorIndexType("L") >>> A = TensorHead("A", [L]) >>> i, j = symbols("i j") >>> expr = PartialDerivative(A(i), A(j)) >>> expr PartialDerivative(A(i), A(j)) The ``PartialDerivative`` object behaves like a tensorial expression: >>> expr.get_indices() [i, -j] Indices can be contracted: >>> expr = PartialDerivative(A(i), A(i)) >>> expr PartialDerivative(A(L_0), A(L_0)) >>> expr.get_indices() [L_0, -L_0] """ def __new__(cls, expr, *variables): # Flatten: if isinstance(expr, PartialDerivative): variables = expr.variables + variables expr = expr.expr args, indices, free, dum = cls._contract_indices_for_derivative( S(expr), variables) obj = TensExpr.__new__(cls, *args) obj._indices = indices obj._free = free obj._dum = dum return obj @property def coeff(self): return S.One @property def nocoeff(self): return self @classmethod def _contract_indices_for_derivative(cls, expr, variables): variables_opposite_valence = [] for i in variables: if isinstance(i, Tensor): i_free_indices = i.get_free_indices() variables_opposite_valence.append( i.xreplace({k: -k for k in i_free_indices})) elif isinstance(i, Symbol): variables_opposite_valence.append(i) args, indices, free, dum = TensMul._tensMul_contract_indices( [expr] + variables_opposite_valence, replace_indices=True) for i in range(1, len(args)): args_i = args[i] if isinstance(args_i, Tensor): i_indices = args[i].get_free_indices() args[i] = args[i].xreplace({k: -k for k in i_indices}) return args, indices, free, dum def doit(self): args, indices, free, dum = self._contract_indices_for_derivative(self.expr, self.variables) obj = self.func(*args) obj._indices = indices obj._free = free obj._dum = dum return obj def _expand_partial_derivative(self): args, indices, free, dum = self._contract_indices_for_derivative(self.expr, self.variables) obj = self.func(*args) obj._indices = indices obj._free = free obj._dum = dum result = obj if not args[0].free_symbols: return S.Zero elif isinstance(obj.expr, TensAdd): # take care of sums of multi PDs result = obj.expr.func(*[ self.func(a, *obj.variables)._expand_partial_derivative() for a in result.expr.args]) elif isinstance(obj.expr, TensMul): # take care of products of multi PDs if len(obj.variables) == 1: # derivative with respect to single variable terms = [] mulargs = list(obj.expr.args) for ind in range(len(mulargs)): if not isinstance(sympify(mulargs[ind]), Number): # a number coefficient is not considered for # expansion of PartialDerivative d = self.func(mulargs[ind], *obj.variables)._expand_partial_derivative() terms.append(TensMul(*(mulargs[:ind] + [d] + mulargs[(ind + 1):]))) result = TensAdd.fromiter(terms) else: # derivative with respect to multiple variables # decompose: # partial(expr, (u, v)) # = partial(partial(expr, u).doit(), v).doit() result = obj.expr # init with expr for v in obj.variables: result = self.func(result, v)._expand_partial_derivative() # then throw PD on it return result def _perform_derivative(self): result = self.expr for v in self.variables: if isinstance(result, TensExpr): result = result._eval_partial_derivative(v) else: if v._diff_wrt: result = result._eval_derivative(v) else: result = S.Zero return result def get_indices(self): return self._indices def get_free_indices(self): free = sorted(self._free, key=lambda x: x[1]) return [i[0] for i in free] def _replace_indices(self, repl): expr = self.expr.xreplace(repl) mirrored = {-k: -v for k, v in repl.items()} variables = [i.xreplace(mirrored) for i in self.variables] return self.func(expr, *variables) @property def expr(self): return self.args[0] @property def variables(self): return self.args[1:] def _extract_data(self, replacement_dict): from .array import derive_by_array, tensorcontraction indices, array = self.expr._extract_data(replacement_dict) for variable in self.variables: var_indices, var_array = variable._extract_data(replacement_dict) var_indices = [-i for i in var_indices] coeff_array, var_array = zip(*[i.as_coeff_Mul() for i in var_array]) array = derive_by_array(array, var_array) array = array.as_mutable() # type: MutableDenseNDimArray varindex = var_indices[0] # type: TensorIndex # Remove coefficients of base vector: coeff_index = [0] + [slice(None) for i in range(len(indices))] for i, coeff in enumerate(coeff_array): coeff_index[0] = i array[tuple(coeff_index)] /= coeff if -varindex in indices: pos = indices.index(-varindex) array = tensorcontraction(array, (0, pos+1)) indices.pop(pos) else: indices.append(varindex) return indices, array sympy-sympy-1.9/sympy/testing/000077500000000000000000000000001412543434000165615ustar00rootroot00000000000000sympy-sympy-1.9/sympy/testing/__init__.py000066400000000000000000000002131412543434000206660ustar00rootroot00000000000000"""This module contains code for running the tests in SymPy. """ from .runtests import test, doctest __all__ = [ 'test', 'doctest', ] sympy-sympy-1.9/sympy/testing/benchmarking.py000066400000000000000000000140621412543434000215660ustar00rootroot00000000000000"""benchmarking through py.test""" import py from py.__.test.item import Item from py.__.test.terminal.terminal import TerminalSession from math import ceil as _ceil, floor as _floor, log10 import timeit from inspect import getsource # from IPython.Magic.magic_timeit units = ["s", "ms", "us", "ns"] scaling = [1, 1e3, 1e6, 1e9] unitn = {s: i for i, s in enumerate(units)} precision = 3 # like py.test Directory but scan for 'bench_.py' class Directory(py.test.collect.Directory): def filefilter(self, path): b = path.purebasename ext = path.ext return b.startswith('bench_') and ext == '.py' # like py.test Module but scane for 'bench_' and 'timeit_' class Module(py.test.collect.Module): def funcnamefilter(self, name): return name.startswith('bench_') or name.startswith('timeit_') # Function level benchmarking driver class Timer(timeit.Timer): def __init__(self, stmt, setup='pass', timer=timeit.default_timer, globals=globals()): # copy of timeit.Timer.__init__ # similarity index 95% self.timer = timer stmt = timeit.reindent(stmt, 8) setup = timeit.reindent(setup, 4) src = timeit.template % {'stmt': stmt, 'setup': setup} self.src = src # Save for traceback display code = compile(src, timeit.dummy_src_name, "exec") ns = {} #exec(code, globals(), ns) -- original timeit code exec(code, globals, ns) # -- we use caller-provided globals instead self.inner = ns["inner"] class Function(py.__.test.item.Function): def __init__(self, *args, **kw): super().__init__(*args, **kw) self.benchtime = None self.benchtitle = None def execute(self, target, *args): # get func source without first 'def func(...):' line src = getsource(target) src = '\n'.join( src.splitlines()[1:] ) # extract benchmark title if target.func_doc is not None: self.benchtitle = target.func_doc else: self.benchtitle = src.splitlines()[0].strip() # XXX we ignore args timer = Timer(src, globals=target.func_globals) if self.name.startswith('timeit_'): # from IPython.Magic.magic_timeit repeat = 3 number = 1 for i in range(1, 10): t = timer.timeit(number) if t >= 0.2: number *= (0.2 / t) number = int(_ceil(number)) break if t <= 0.02: # we are not close enough to that 0.2s number *= 10 else: # since we are very close to be > 0.2s we'd better adjust number # so that timing time is not too high number *= (0.2 / t) number = int(_ceil(number)) break self.benchtime = min(timer.repeat(repeat, number)) / number # 'bench_' else: self.benchtime = timer.timeit(1) class BenchSession(TerminalSession): def header(self, colitems): super().header(colitems) def footer(self, colitems): super().footer(colitems) self.out.write('\n') self.print_bench_results() def print_bench_results(self): self.out.write('==============================\n') self.out.write(' *** BENCHMARKING RESULTS *** \n') self.out.write('==============================\n') self.out.write('\n') # benchname, time, benchtitle results = [] for item, outcome in self._memo: if isinstance(item, Item): best = item.benchtime if best is None: # skipped or failed benchmarks tstr = '---' else: # from IPython.Magic.magic_timeit if best > 0.0: order = min(-int(_floor(log10(best)) // 3), 3) else: order = 3 tstr = "%.*g %s" % ( precision, best * scaling[order], units[order]) results.append( [item.name, tstr, item.benchtitle] ) # dot/unit align second column # FIXME simpler? this is crappy -- shame on me... wm = [0]*len(units) we = [0]*len(units) for s in results: tstr = s[1] n, u = tstr.split() # unit n un = unitn[u] try: m, e = n.split('.') except ValueError: m, e = n, '' wm[un] = max(len(m), wm[un]) we[un] = max(len(e), we[un]) for s in results: tstr = s[1] n, u = tstr.split() un = unitn[u] try: m, e = n.split('.') except ValueError: m, e = n, '' m = m.rjust(wm[un]) e = e.ljust(we[un]) if e.strip(): n = '.'.join((m, e)) else: n = ' '.join((m, e)) # let's put the number into the right place txt = '' for i in range(len(units)): if i == un: txt += n else: txt += ' '*(wm[i] + we[i] + 1) s[1] = '%s %s' % (txt, u) # align all columns besides the last one for i in range(2): w = max(len(s[i]) for s in results) for s in results: s[i] = s[i].ljust(w) # show results for s in results: self.out.write('%s | %s | %s\n' % tuple(s)) def main(args=None): # hook our Directory/Module/Function as defaults from py.__.test import defaultconftest defaultconftest.Directory = Directory defaultconftest.Module = Module defaultconftest.Function = Function # hook BenchSession as py.test session config = py.test.config config._getsessionclass = lambda: BenchSession py.test.cmdline.main(args) sympy-sympy-1.9/sympy/testing/matrices.py000066400000000000000000000003301412543434000207360ustar00rootroot00000000000000def allclose(A, B, rtol=1e-05, atol=1e-08): if len(A) != len(B): return False for x, y in zip(A, B): if abs(x-y) > atol + rtol * max(abs(x), abs(y)): return False return True sympy-sympy-1.9/sympy/testing/pytest.py000066400000000000000000000227631412543434000204750ustar00rootroot00000000000000"""py.test hacks to support XFAIL/XPASS""" import sys import functools import os import contextlib import warnings from sympy.utilities.exceptions import SymPyDeprecationWarning ON_TRAVIS = os.getenv('TRAVIS_BUILD_NUMBER', None) try: import pytest USE_PYTEST = getattr(sys, '_running_pytest', False) except ImportError: USE_PYTEST = False if USE_PYTEST: raises = pytest.raises warns = pytest.warns skip = pytest.skip XFAIL = pytest.mark.xfail SKIP = pytest.mark.skip slow = pytest.mark.slow nocache_fail = pytest.mark.nocache_fail from _pytest.outcomes import Failed else: # Not using pytest so define the things that would have been imported from # there. # _pytest._code.code.ExceptionInfo class ExceptionInfo: def __init__(self, value): self.value = value def __repr__(self): return "".format(self.value) def raises(expectedException, code=None): """ Tests that ``code`` raises the exception ``expectedException``. ``code`` may be a callable, such as a lambda expression or function name. If ``code`` is not given or None, ``raises`` will return a context manager for use in ``with`` statements; the code to execute then comes from the scope of the ``with``. ``raises()`` does nothing if the callable raises the expected exception, otherwise it raises an AssertionError. Examples ======== >>> from sympy.testing.pytest import raises >>> raises(ZeroDivisionError, lambda: 1/0) >>> raises(ZeroDivisionError, lambda: 1/2) Traceback (most recent call last): ... Failed: DID NOT RAISE >>> with raises(ZeroDivisionError): ... n = 1/0 >>> with raises(ZeroDivisionError): ... n = 1/2 Traceback (most recent call last): ... Failed: DID NOT RAISE Note that you cannot test multiple statements via ``with raises``: >>> with raises(ZeroDivisionError): ... n = 1/0 # will execute and raise, aborting the ``with`` ... n = 9999/0 # never executed This is just what ``with`` is supposed to do: abort the contained statement sequence at the first exception and let the context manager deal with the exception. To test multiple statements, you'll need a separate ``with`` for each: >>> with raises(ZeroDivisionError): ... n = 1/0 # will execute and raise >>> with raises(ZeroDivisionError): ... n = 9999/0 # will also execute and raise """ if code is None: return RaisesContext(expectedException) elif callable(code): try: code() except expectedException as e: return ExceptionInfo(e) raise Failed("DID NOT RAISE") elif isinstance(code, str): raise TypeError( '\'raises(xxx, "code")\' has been phased out; ' 'change \'raises(xxx, "expression")\' ' 'to \'raises(xxx, lambda: expression)\', ' '\'raises(xxx, "statement")\' ' 'to \'with raises(xxx): statement\'') else: raise TypeError( 'raises() expects a callable for the 2nd argument.') class RaisesContext: def __init__(self, expectedException): self.expectedException = expectedException def __enter__(self): return None def __exit__(self, exc_type, exc_value, traceback): if exc_type is None: raise Failed("DID NOT RAISE") return issubclass(exc_type, self.expectedException) class XFail(Exception): pass class XPass(Exception): pass class Skipped(Exception): pass class Failed(Exception): # type: ignore pass def XFAIL(func): def wrapper(): try: func() except Exception as e: message = str(e) if message != "Timeout": raise XFail(func.__name__) else: raise Skipped("Timeout") raise XPass(func.__name__) wrapper = functools.update_wrapper(wrapper, func) return wrapper def skip(str): raise Skipped(str) def SKIP(reason): """Similar to ``skip()``, but this is a decorator. """ def wrapper(func): def func_wrapper(): raise Skipped(reason) func_wrapper = functools.update_wrapper(func_wrapper, func) return func_wrapper return wrapper def slow(func): func._slow = True def func_wrapper(): func() func_wrapper = functools.update_wrapper(func_wrapper, func) func_wrapper.__wrapped__ = func return func_wrapper def nocache_fail(func): "Dummy decorator for marking tests that fail when cache is disabled" return func @contextlib.contextmanager def warns(warningcls, *, match=''): '''Like raises but tests that warnings are emitted. >>> from sympy.testing.pytest import warns >>> import warnings >>> with warns(UserWarning): ... warnings.warn('deprecated', UserWarning) >>> with warns(UserWarning): ... pass Traceback (most recent call last): ... Failed: DID NOT WARN. No warnings of type UserWarning\ was emitted. The list of emitted warnings is: []. ''' # Absorbs all warnings in warnrec with warnings.catch_warnings(record=True) as warnrec: # Hide all warnings but make sure that our warning is emitted warnings.simplefilter("ignore") warnings.filterwarnings("always", match, warningcls) # Now run the test yield # Raise if expected warning not found if not any(issubclass(w.category, warningcls) for w in warnrec): msg = ('Failed: DID NOT WARN.' ' No warnings of type %s was emitted.' ' The list of emitted warnings is: %s.' ) % (warningcls, [w.message for w in warnrec]) raise Failed(msg) def _both_exp_pow(func): """ Decorator used to run the test twice: the first time `e^x` is represented as ``Pow(E, x)``, the second time as ``exp(x)`` (exponential object is not a power). This is a temporary trick helping to manage the elimination of the class ``exp`` in favor of a replacement by ``Pow(E, ...)``. """ from sympy.core.parameters import _exp_is_pow def func_wrap(): with _exp_is_pow(True): func() with _exp_is_pow(False): func() wrapper = functools.update_wrapper(func_wrap, func) return wrapper @contextlib.contextmanager def warns_deprecated_sympy(): '''Shorthand for ``warns(SymPyDeprecationWarning)`` This is the recommended way to test that ``SymPyDeprecationWarning`` is emitted for deprecated features in SymPy. To test for other warnings use ``warns``. To suppress warnings without asserting that they are emitted use ``ignore_warnings``. >>> from sympy.testing.pytest import warns_deprecated_sympy >>> from sympy.utilities.exceptions import SymPyDeprecationWarning >>> with warns_deprecated_sympy(): ... SymPyDeprecationWarning("Don't use", feature="old thing", ... deprecated_since_version="1.0", issue=123).warn() >>> with warns_deprecated_sympy(): ... pass Traceback (most recent call last): ... Failed: DID NOT WARN. No warnings of type \ SymPyDeprecationWarning was emitted. The list of emitted warnings is: []. ''' with warns(SymPyDeprecationWarning): yield @contextlib.contextmanager def ignore_warnings(warningcls): '''Context manager to suppress warnings during tests. This function is useful for suppressing warnings during tests. The warns function should be used to assert that a warning is raised. The ignore_warnings function is useful in situation when the warning is not guaranteed to be raised (e.g. on importing a module) or if the warning comes from third-party code. When the warning is coming (reliably) from SymPy the warns function should be preferred to ignore_warnings. >>> from sympy.testing.pytest import ignore_warnings >>> import warnings Here's a warning: >>> with warnings.catch_warnings(): # reset warnings in doctest ... warnings.simplefilter('error') ... warnings.warn('deprecated', UserWarning) Traceback (most recent call last): ... UserWarning: deprecated Let's suppress it with ignore_warnings: >>> with warnings.catch_warnings(): # reset warnings in doctest ... warnings.simplefilter('error') ... with ignore_warnings(UserWarning): ... warnings.warn('deprecated', UserWarning) (No warning emitted) ''' # Absorbs all warnings in warnrec with warnings.catch_warnings(record=True) as warnrec: # Make sure our warning doesn't get filtered warnings.simplefilter("always", warningcls) # Now run the test yield # Reissue any warnings that we aren't testing for for w in warnrec: if not issubclass(w.category, warningcls): warnings.warn_explicit(w.message, w.category, w.filename, w.lineno) sympy-sympy-1.9/sympy/testing/quality_unicode.py000066400000000000000000000113171412543434000223340ustar00rootroot00000000000000import re import fnmatch # XXX Python 2 unicode import test. # May remove after deprecating python 2.7. message_unicode_A = \ "File contains a unicode character : %s, line %s. " \ "But with no encoding header. " \ "See https://www.python.org/dev/peps/pep-0263/ " \ "and add '# coding=utf-8'" message_unicode_B = \ "File contains a unicode character : %s, line %s. " \ "But not in the whitelist. " \ "Add the file to the whitelist in " + __file__ message_unicode_C = \ "File contains a unicode character : %s, line %s. " \ "And is in the whitelist, but without the encoding header. " \ "See https://www.python.org/dev/peps/pep-0263/ " \ "and add '# coding=utf-8'." message_unicode_D = \ "File does not contain a unicode character : %s." \ "but is in the whitelist. " \ "Remove the file from the whitelist in " + __file__ message_unicode_E = \ "File does not contain a unicode character : %s." \ "but contains the header '# coding=utf-8' or equivalent." \ "Remove the header." encoding_header_re = re.compile( r'^[ \t\f]*#.*?coding[:=][ \t]*([-_.a-zA-Z0-9]+)') # Whitelist pattern for files which can have unicode. unicode_whitelist = [ # Author names can include non-ASCII characters r'*/bin/authors_update.py', # These files have functions and test functions for unicode input and # output. r'*/sympy/testing/tests/test_code_quality.py', r'*/sympy/physics/vector/tests/test_printing.py', r'*/physics/quantum/tests/test_printing.py', r'*/sympy/vector/tests/test_printing.py', r'*/sympy/parsing/tests/test_sympy_parser.py', r'*/sympy/printing/pretty/tests/test_pretty.py', r'*/sympy/printing/tests/test_conventions.py', r'*/sympy/printing/tests/test_preview.py', r'*/liealgebras/type_g.py', r'*/liealgebras/weyl_group.py', r'*/liealgebras/tests/test_type_G.py', # wigner.py and polarization.py have unicode doctests. These probably # don't need to be there but some of the examples that are there are # pretty ugly without use_unicode (matrices need to be wrapped across # multiple lines etc) r'*/sympy/physics/wigner.py', r'*/sympy/physics/optics/polarization.py', # joint.py uses some unicode for variable names in the docstrings r'*/sympy/physics/mechanics/joint.py', ] unicode_strict_whitelist = [ r'*/sympy/parsing/latex/_antlr/__init__.py', ] def _test_this_file_encoding( fname, test_file, unicode_whitelist=unicode_whitelist, unicode_strict_whitelist=unicode_strict_whitelist): """Test helper function for python 2 importability test This test checks whether the file has # coding=utf-8 or # -*- coding: utf-8 -*- line if there is a unicode character in the code The test may have to operate on filewise manner, so it had moved to a separate process. May remove after deprecating python 2.7. """ has_coding_utf8 = False has_unicode = False is_in_whitelist = False is_in_strict_whitelist = False for patt in unicode_whitelist: if fnmatch.fnmatch(fname, patt): is_in_whitelist = True break for patt in unicode_strict_whitelist: if fnmatch.fnmatch(fname, patt): is_in_strict_whitelist = True is_in_whitelist = True break if is_in_whitelist: for idx, line in enumerate(test_file): if idx in (0, 1): match = encoding_header_re.match(line) if match and match.group(1).lower() == 'utf-8': has_coding_utf8 = True try: line.encode(encoding='ascii') except (UnicodeEncodeError, UnicodeDecodeError): has_unicode = True if has_coding_utf8 is False: assert False, \ message_unicode_C % (fname, idx + 1) if not has_unicode and not is_in_strict_whitelist: assert False, message_unicode_D % fname else: for idx, line in enumerate(test_file): if idx in (0, 1): match = encoding_header_re.match(line) if match and match.group(1).lower() == 'utf-8': has_coding_utf8 = True try: line.encode(encoding='ascii') except (UnicodeEncodeError, UnicodeDecodeError): has_unicode = True if has_coding_utf8: assert False, \ message_unicode_B % (fname, idx + 1) else: assert False, \ message_unicode_A % (fname, idx + 1) if not has_unicode and has_coding_utf8: assert False, \ message_unicode_E % fname sympy-sympy-1.9/sympy/testing/randtest.py000066400000000000000000000123071412543434000207620ustar00rootroot00000000000000""" Helpers for randomized testing """ from random import uniform, Random, randrange, randint from sympy.core.compatibility import is_sequence, as_int from sympy.core.containers import Tuple from sympy.core.numbers import comp, I from sympy.core.symbol import Symbol from sympy.simplify.simplify import nsimplify def random_complex_number(a=2, b=-1, c=3, d=1, rational=False, tolerance=None): """ Return a random complex number. To reduce chance of hitting branch cuts or anything, we guarantee b <= Im z <= d, a <= Re z <= c When rational is True, a rational approximation to a random number is obtained within specified tolerance, if any. """ A, B = uniform(a, c), uniform(b, d) if not rational: return A + I*B return (nsimplify(A, rational=True, tolerance=tolerance) + I*nsimplify(B, rational=True, tolerance=tolerance)) def verify_numerically(f, g, z=None, tol=1.0e-6, a=2, b=-1, c=3, d=1): """ Test numerically that f and g agree when evaluated in the argument z. If z is None, all symbols will be tested. This routine does not test whether there are Floats present with precision higher than 15 digits so if there are, your results may not be what you expect due to round- off errors. Examples ======== >>> from sympy import sin, cos >>> from sympy.abc import x >>> from sympy.testing.randtest import verify_numerically as tn >>> tn(sin(x)**2 + cos(x)**2, 1, x) True """ f, g, z = Tuple(f, g, z) z = [z] if isinstance(z, Symbol) else (f.free_symbols | g.free_symbols) reps = list(zip(z, [random_complex_number(a, b, c, d) for _ in z])) z1 = f.subs(reps).n() z2 = g.subs(reps).n() return comp(z1, z2, tol) def test_derivative_numerically(f, z, tol=1.0e-6, a=2, b=-1, c=3, d=1): """ Test numerically that the symbolically computed derivative of f with respect to z is correct. This routine does not test whether there are Floats present with precision higher than 15 digits so if there are, your results may not be what you expect due to round-off errors. Examples ======== >>> from sympy import sin >>> from sympy.abc import x >>> from sympy.testing.randtest import test_derivative_numerically as td >>> td(sin(x), x) True """ from sympy.core.function import Derivative z0 = random_complex_number(a, b, c, d) f1 = f.diff(z).subs(z, z0) f2 = Derivative(f, z).doit_numerically(z0) return comp(f1.n(), f2.n(), tol) def _randrange(seed=None): """Return a randrange generator. ``seed`` can be o None - return randomly seeded generator o int - return a generator seeded with the int o list - the values to be returned will be taken from the list in the order given; the provided list is not modified. Examples ======== >>> from sympy.testing.randtest import _randrange >>> rr = _randrange() >>> rr(1000) # doctest: +SKIP 999 >>> rr = _randrange(3) >>> rr(1000) # doctest: +SKIP 238 >>> rr = _randrange([0, 5, 1, 3, 4]) >>> rr(3), rr(3) (0, 1) """ if seed is None: return randrange elif isinstance(seed, int): return Random(seed).randrange elif is_sequence(seed): seed = list(seed) # make a copy seed.reverse() def give(a, b=None, seq=seed): if b is None: a, b = 0, a a, b = as_int(a), as_int(b) w = b - a if w < 1: raise ValueError('_randrange got empty range') try: x = seq.pop() except IndexError: raise ValueError('_randrange sequence was too short') if a <= x < b: return x else: return give(a, b, seq) return give else: raise ValueError('_randrange got an unexpected seed') def _randint(seed=None): """Return a randint generator. ``seed`` can be o None - return randomly seeded generator o int - return a generator seeded with the int o list - the values to be returned will be taken from the list in the order given; the provided list is not modified. Examples ======== >>> from sympy.testing.randtest import _randint >>> ri = _randint() >>> ri(1, 1000) # doctest: +SKIP 999 >>> ri = _randint(3) >>> ri(1, 1000) # doctest: +SKIP 238 >>> ri = _randint([0, 5, 1, 2, 4]) >>> ri(1, 3), ri(1, 3) (1, 2) """ if seed is None: return randint elif isinstance(seed, int): return Random(seed).randint elif is_sequence(seed): seed = list(seed) # make a copy seed.reverse() def give(a, b, seq=seed): a, b = as_int(a), as_int(b) w = b - a if w < 0: raise ValueError('_randint got empty range') try: x = seq.pop() except IndexError: raise ValueError('_randint sequence was too short') if a <= x <= b: return x else: return give(a, b, seq) return give else: raise ValueError('_randint got an unexpected seed') sympy-sympy-1.9/sympy/testing/runtests.py000066400000000000000000002546131412543434000210350ustar00rootroot00000000000000""" This is our testing framework. Goals: * it should be compatible with py.test and operate very similarly (or identically) * doesn't require any external dependencies * preferably all the functionality should be in this file only * no magic, just import the test file and execute the test functions, that's it * portable """ from __future__ import print_function, division import os import sys import platform import inspect import traceback import pdb import re import linecache import time from fnmatch import fnmatch from timeit import default_timer as clock import doctest as pdoctest # avoid clashing with our doctest() function from doctest import DocTestFinder, DocTestRunner import random import subprocess import shutil import signal import stat import tempfile import warnings from contextlib import contextmanager from sympy.core.cache import clear_cache from sympy.core.compatibility import (PY3, unwrap) from sympy.external import import_module IS_WINDOWS = (os.name == 'nt') ON_TRAVIS = os.getenv('TRAVIS_BUILD_NUMBER', None) # emperically generated list of the proportion of time spent running # an even split of tests. This should periodically be regenerated. # A list of [.6, .1, .3] would mean that if the tests are evenly split # into '1/3', '2/3', '3/3', the first split would take 60% of the time, # the second 10% and the third 30%. These lists are normalized to sum # to 1, so [60, 10, 30] has the same behavior as [6, 1, 3] or [.6, .1, .3]. # # This list can be generated with the code: # from time import time # import sympy # import os # os.environ["TRAVIS_BUILD_NUMBER"] = '2' # Mock travis to get more correct densities # delays, num_splits = [], 30 # for i in range(1, num_splits + 1): # tic = time() # sympy.test(split='{}/{}'.format(i, num_splits), time_balance=False) # Add slow=True for slow tests # delays.append(time() - tic) # tot = sum(delays) # print([round(x / tot, 4) for x in delays]) SPLIT_DENSITY = [ 0.0059, 0.0027, 0.0068, 0.0011, 0.0006, 0.0058, 0.0047, 0.0046, 0.004, 0.0257, 0.0017, 0.0026, 0.004, 0.0032, 0.0016, 0.0015, 0.0004, 0.0011, 0.0016, 0.0014, 0.0077, 0.0137, 0.0217, 0.0074, 0.0043, 0.0067, 0.0236, 0.0004, 0.1189, 0.0142, 0.0234, 0.0003, 0.0003, 0.0047, 0.0006, 0.0013, 0.0004, 0.0008, 0.0007, 0.0006, 0.0139, 0.0013, 0.0007, 0.0051, 0.002, 0.0004, 0.0005, 0.0213, 0.0048, 0.0016, 0.0012, 0.0014, 0.0024, 0.0015, 0.0004, 0.0005, 0.0007, 0.011, 0.0062, 0.0015, 0.0021, 0.0049, 0.0006, 0.0006, 0.0011, 0.0006, 0.0019, 0.003, 0.0044, 0.0054, 0.0057, 0.0049, 0.0016, 0.0006, 0.0009, 0.0006, 0.0012, 0.0006, 0.0149, 0.0532, 0.0076, 0.0041, 0.0024, 0.0135, 0.0081, 0.2209, 0.0459, 0.0438, 0.0488, 0.0137, 0.002, 0.0003, 0.0008, 0.0039, 0.0024, 0.0005, 0.0004, 0.003, 0.056, 0.0026] SPLIT_DENSITY_SLOW = [0.0086, 0.0004, 0.0568, 0.0003, 0.0032, 0.0005, 0.0004, 0.0013, 0.0016, 0.0648, 0.0198, 0.1285, 0.098, 0.0005, 0.0064, 0.0003, 0.0004, 0.0026, 0.0007, 0.0051, 0.0089, 0.0024, 0.0033, 0.0057, 0.0005, 0.0003, 0.001, 0.0045, 0.0091, 0.0006, 0.0005, 0.0321, 0.0059, 0.1105, 0.216, 0.1489, 0.0004, 0.0003, 0.0006, 0.0483] class Skipped(Exception): pass class TimeOutError(Exception): pass class DependencyError(Exception): pass # add more flags ?? future_flags = division.compiler_flag def _indent(s, indent=4): """ Add the given number of space characters to the beginning of every non-blank line in ``s``, and return the result. If the string ``s`` is Unicode, it is encoded using the stdout encoding and the ``backslashreplace`` error handler. """ # This regexp matches the start of non-blank lines: return re.sub('(?m)^(?!$)', indent*' ', s) pdoctest._indent = _indent # type: ignore # override reporter to maintain windows and python3 def _report_failure(self, out, test, example, got): """ Report that the given example failed. """ s = self._checker.output_difference(example, got, self.optionflags) s = s.encode('raw_unicode_escape').decode('utf8', 'ignore') out(self._failure_header(test, example) + s) if PY3 and IS_WINDOWS: DocTestRunner.report_failure = _report_failure # type: ignore def convert_to_native_paths(lst): """ Converts a list of '/' separated paths into a list of native (os.sep separated) paths and converts to lowercase if the system is case insensitive. """ newlst = [] for i, rv in enumerate(lst): rv = os.path.join(*rv.split("/")) # on windows the slash after the colon is dropped if sys.platform == "win32": pos = rv.find(':') if pos != -1: if rv[pos + 1] != '\\': rv = rv[:pos + 1] + '\\' + rv[pos + 1:] newlst.append(os.path.normcase(rv)) return newlst def get_sympy_dir(): """ Returns the root sympy directory and set the global value indicating whether the system is case sensitive or not. """ this_file = os.path.abspath(__file__) sympy_dir = os.path.join(os.path.dirname(this_file), "..", "..") sympy_dir = os.path.normpath(sympy_dir) return os.path.normcase(sympy_dir) def setup_pprint(): from sympy import pprint_use_unicode, init_printing import sympy.interactive.printing as interactive_printing # force pprint to be in ascii mode in doctests use_unicode_prev = pprint_use_unicode(False) # hook our nice, hash-stable strprinter init_printing(pretty_print=False) # Prevent init_printing() in doctests from affecting other doctests interactive_printing.NO_GLOBAL = True return use_unicode_prev @contextmanager def raise_on_deprecated(): """Context manager to make DeprecationWarning raise an error This is to catch SymPyDeprecationWarning from library code while running tests and doctests. It is important to use this context manager around each individual test/doctest in case some tests modify the warning filters. """ with warnings.catch_warnings(): warnings.filterwarnings('error', '.*', DeprecationWarning, module='sympy.*') yield def run_in_subprocess_with_hash_randomization( function, function_args=(), function_kwargs=None, command=sys.executable, module='sympy.testing.runtests', force=False): """ Run a function in a Python subprocess with hash randomization enabled. If hash randomization is not supported by the version of Python given, it returns False. Otherwise, it returns the exit value of the command. The function is passed to sys.exit(), so the return value of the function will be the return value. The environment variable PYTHONHASHSEED is used to seed Python's hash randomization. If it is set, this function will return False, because starting a new subprocess is unnecessary in that case. If it is not set, one is set at random, and the tests are run. Note that if this environment variable is set when Python starts, hash randomization is automatically enabled. To force a subprocess to be created even if PYTHONHASHSEED is set, pass ``force=True``. This flag will not force a subprocess in Python versions that do not support hash randomization (see below), because those versions of Python do not support the ``-R`` flag. ``function`` should be a string name of a function that is importable from the module ``module``, like "_test". The default for ``module`` is "sympy.testing.runtests". ``function_args`` and ``function_kwargs`` should be a repr-able tuple and dict, respectively. The default Python command is sys.executable, which is the currently running Python command. This function is necessary because the seed for hash randomization must be set by the environment variable before Python starts. Hence, in order to use a predetermined seed for tests, we must start Python in a separate subprocess. Hash randomization was added in the minor Python versions 2.6.8, 2.7.3, 3.1.5, and 3.2.3, and is enabled by default in all Python versions after and including 3.3.0. Examples ======== >>> from sympy.testing.runtests import ( ... run_in_subprocess_with_hash_randomization) >>> # run the core tests in verbose mode >>> run_in_subprocess_with_hash_randomization("_test", ... function_args=("core",), ... function_kwargs={'verbose': True}) # doctest: +SKIP # Will return 0 if sys.executable supports hash randomization and tests # pass, 1 if they fail, and False if it does not support hash # randomization. """ cwd = get_sympy_dir() # Note, we must return False everywhere, not None, as subprocess.call will # sometimes return None. # First check if the Python version supports hash randomization # If it doesn't have this support, it won't recognize the -R flag p = subprocess.Popen([command, "-RV"], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, cwd=cwd) p.communicate() if p.returncode != 0: return False hash_seed = os.getenv("PYTHONHASHSEED") if not hash_seed: os.environ["PYTHONHASHSEED"] = str(random.randrange(2**32)) else: if not force: return False function_kwargs = function_kwargs or {} # Now run the command commandstring = ("import sys; from %s import %s;sys.exit(%s(*%s, **%s))" % (module, function, function, repr(function_args), repr(function_kwargs))) try: p = subprocess.Popen([command, "-R", "-c", commandstring], cwd=cwd) p.communicate() except KeyboardInterrupt: p.wait() finally: # Put the environment variable back, so that it reads correctly for # the current Python process. if hash_seed is None: del os.environ["PYTHONHASHSEED"] else: os.environ["PYTHONHASHSEED"] = hash_seed return p.returncode def run_all_tests(test_args=(), test_kwargs=None, doctest_args=(), doctest_kwargs=None, examples_args=(), examples_kwargs=None): """ Run all tests. Right now, this runs the regular tests (bin/test), the doctests (bin/doctest), and the examples (examples/all.py). This is what ``setup.py test`` uses. You can pass arguments and keyword arguments to the test functions that support them (for now, test, doctest, and the examples). See the docstrings of those functions for a description of the available options. For example, to run the solvers tests with colors turned off: >>> from sympy.testing.runtests import run_all_tests >>> run_all_tests(test_args=("solvers",), ... test_kwargs={"colors:False"}) # doctest: +SKIP """ tests_successful = True test_kwargs = test_kwargs or {} doctest_kwargs = doctest_kwargs or {} examples_kwargs = examples_kwargs or {'quiet': True} try: # Regular tests if not test(*test_args, **test_kwargs): # some regular test fails, so set the tests_successful # flag to false and continue running the doctests tests_successful = False # Doctests print() if not doctest(*doctest_args, **doctest_kwargs): tests_successful = False # Examples print() sys.path.append("examples") # examples/all.py from all import run_examples # type: ignore if not run_examples(*examples_args, **examples_kwargs): tests_successful = False if tests_successful: return else: # Return nonzero exit code sys.exit(1) except KeyboardInterrupt: print() print("DO *NOT* COMMIT!") sys.exit(1) def test(*paths, subprocess=True, rerun=0, **kwargs): """ Run tests in the specified test_*.py files. Tests in a particular test_*.py file are run if any of the given strings in ``paths`` matches a part of the test file's path. If ``paths=[]``, tests in all test_*.py files are run. Notes: - If sort=False, tests are run in random order (not default). - Paths can be entered in native system format or in unix, forward-slash format. - Files that are on the blacklist can be tested by providing their path; they are only excluded if no paths are given. **Explanation of test results** ====== =============================================================== Output Meaning ====== =============================================================== . passed F failed X XPassed (expected to fail but passed) f XFAILed (expected to fail and indeed failed) s skipped w slow T timeout (e.g., when ``--timeout`` is used) K KeyboardInterrupt (when running the slow tests with ``--slow``, you can interrupt one of them without killing the test runner) ====== =============================================================== Colors have no additional meaning and are used just to facilitate interpreting the output. Examples ======== >>> import sympy Run all tests: >>> sympy.test() # doctest: +SKIP Run one file: >>> sympy.test("sympy/core/tests/test_basic.py") # doctest: +SKIP >>> sympy.test("_basic") # doctest: +SKIP Run all tests in sympy/functions/ and some particular file: >>> sympy.test("sympy/core/tests/test_basic.py", ... "sympy/functions") # doctest: +SKIP Run all tests in sympy/core and sympy/utilities: >>> sympy.test("/core", "/util") # doctest: +SKIP Run specific test from a file: >>> sympy.test("sympy/core/tests/test_basic.py", ... kw="test_equality") # doctest: +SKIP Run specific test from any file: >>> sympy.test(kw="subs") # doctest: +SKIP Run the tests with verbose mode on: >>> sympy.test(verbose=True) # doctest: +SKIP Don't sort the test output: >>> sympy.test(sort=False) # doctest: +SKIP Turn on post-mortem pdb: >>> sympy.test(pdb=True) # doctest: +SKIP Turn off colors: >>> sympy.test(colors=False) # doctest: +SKIP Force colors, even when the output is not to a terminal (this is useful, e.g., if you are piping to ``less -r`` and you still want colors) >>> sympy.test(force_colors=False) # doctest: +SKIP The traceback verboseness can be set to "short" or "no" (default is "short") >>> sympy.test(tb='no') # doctest: +SKIP The ``split`` option can be passed to split the test run into parts. The split currently only splits the test files, though this may change in the future. ``split`` should be a string of the form 'a/b', which will run part ``a`` of ``b``. For instance, to run the first half of the test suite: >>> sympy.test(split='1/2') # doctest: +SKIP The ``time_balance`` option can be passed in conjunction with ``split``. If ``time_balance=True`` (the default for ``sympy.test``), sympy will attempt to split the tests such that each split takes equal time. This heuristic for balancing is based on pre-recorded test data. >>> sympy.test(split='1/2', time_balance=True) # doctest: +SKIP You can disable running the tests in a separate subprocess using ``subprocess=False``. This is done to support seeding hash randomization, which is enabled by default in the Python versions where it is supported. If subprocess=False, hash randomization is enabled/disabled according to whether it has been enabled or not in the calling Python process. However, even if it is enabled, the seed cannot be printed unless it is called from a new Python process. Hash randomization was added in the minor Python versions 2.6.8, 2.7.3, 3.1.5, and 3.2.3, and is enabled by default in all Python versions after and including 3.3.0. If hash randomization is not supported ``subprocess=False`` is used automatically. >>> sympy.test(subprocess=False) # doctest: +SKIP To set the hash randomization seed, set the environment variable ``PYTHONHASHSEED`` before running the tests. This can be done from within Python using >>> import os >>> os.environ['PYTHONHASHSEED'] = '42' # doctest: +SKIP Or from the command line using $ PYTHONHASHSEED=42 ./bin/test If the seed is not set, a random seed will be chosen. Note that to reproduce the same hash values, you must use both the same seed as well as the same architecture (32-bit vs. 64-bit). """ # count up from 0, do not print 0 print_counter = lambda i : (print("rerun %d" % (rerun-i)) if rerun-i else None) if subprocess: # loop backwards so last i is 0 for i in range(rerun, -1, -1): print_counter(i) ret = run_in_subprocess_with_hash_randomization("_test", function_args=paths, function_kwargs=kwargs) if ret is False: break val = not bool(ret) # exit on the first failure or if done if not val or i == 0: return val # rerun even if hash randomization is not supported for i in range(rerun, -1, -1): print_counter(i) val = not bool(_test(*paths, **kwargs)) if not val or i == 0: return val def _test(*paths, verbose=False, tb="short", kw=None, pdb=False, colors=True, force_colors=False, sort=True, seed=None, timeout=False, fail_on_timeout=False, slow=False, enhance_asserts=False, split=None, time_balance=True, blacklist=('sympy/integrals/rubi/rubi_tests/tests',), fast_threshold=None, slow_threshold=None): """ Internal function that actually runs the tests. All keyword arguments from ``test()`` are passed to this function except for ``subprocess``. Returns 0 if tests passed and 1 if they failed. See the docstring of ``test()`` for more information. """ kw = kw or () # ensure that kw is a tuple if isinstance(kw, str): kw = (kw,) post_mortem = pdb if seed is None: seed = random.randrange(100000000) if ON_TRAVIS and timeout is False: # Travis times out if no activity is seen for 10 minutes. timeout = 595 fail_on_timeout = True if ON_TRAVIS: # pyglet does not work on Travis blacklist = list(blacklist) + ['sympy/plotting/pygletplot/tests'] blacklist = convert_to_native_paths(blacklist) r = PyTestReporter(verbose=verbose, tb=tb, colors=colors, force_colors=force_colors, split=split) t = SymPyTests(r, kw, post_mortem, seed, fast_threshold=fast_threshold, slow_threshold=slow_threshold) test_files = t.get_test_files('sympy') not_blacklisted = [f for f in test_files if not any(b in f for b in blacklist)] if len(paths) == 0: matched = not_blacklisted else: paths = convert_to_native_paths(paths) matched = [] for f in not_blacklisted: basename = os.path.basename(f) for p in paths: if p in f or fnmatch(basename, p): matched.append(f) break density = None if time_balance: if slow: density = SPLIT_DENSITY_SLOW else: density = SPLIT_DENSITY if split: matched = split_list(matched, split, density=density) t._testfiles.extend(matched) return int(not t.test(sort=sort, timeout=timeout, slow=slow, enhance_asserts=enhance_asserts, fail_on_timeout=fail_on_timeout)) def doctest(*paths, subprocess=True, rerun=0, **kwargs): r""" Runs doctests in all \*.py files in the sympy directory which match any of the given strings in ``paths`` or all tests if paths=[]. Notes: - Paths can be entered in native system format or in unix, forward-slash format. - Files that are on the blacklist can be tested by providing their path; they are only excluded if no paths are given. Examples ======== >>> import sympy Run all tests: >>> sympy.doctest() # doctest: +SKIP Run one file: >>> sympy.doctest("sympy/core/basic.py") # doctest: +SKIP >>> sympy.doctest("polynomial.rst") # doctest: +SKIP Run all tests in sympy/functions/ and some particular file: >>> sympy.doctest("/functions", "basic.py") # doctest: +SKIP Run any file having polynomial in its name, doc/src/modules/polynomial.rst, sympy/functions/special/polynomials.py, and sympy/polys/polynomial.py: >>> sympy.doctest("polynomial") # doctest: +SKIP The ``split`` option can be passed to split the test run into parts. The split currently only splits the test files, though this may change in the future. ``split`` should be a string of the form 'a/b', which will run part ``a`` of ``b``. Note that the regular doctests and the Sphinx doctests are split independently. For instance, to run the first half of the test suite: >>> sympy.doctest(split='1/2') # doctest: +SKIP The ``subprocess`` and ``verbose`` options are the same as with the function ``test()``. See the docstring of that function for more information. """ # count up from 0, do not print 0 print_counter = lambda i : (print("rerun %d" % (rerun-i)) if rerun-i else None) if subprocess: # loop backwards so last i is 0 for i in range(rerun, -1, -1): print_counter(i) ret = run_in_subprocess_with_hash_randomization("_doctest", function_args=paths, function_kwargs=kwargs) if ret is False: break val = not bool(ret) # exit on the first failure or if done if not val or i == 0: return val # rerun even if hash randomization is not supported for i in range(rerun, -1, -1): print_counter(i) val = not bool(_doctest(*paths, **kwargs)) if not val or i == 0: return val def _get_doctest_blacklist(): '''Get the default blacklist for the doctests''' blacklist = [] blacklist.extend([ "doc/src/modules/plotting.rst", # generates live plots "doc/src/modules/physics/mechanics/autolev_parser.rst", "sympy/galgebra.py", # no longer part of SymPy "sympy/this.py", # prints text "sympy/physics/gaussopt.py", # raises deprecation warning "sympy/matrices/densearith.py", # raises deprecation warning "sympy/matrices/densesolve.py", # raises deprecation warning "sympy/matrices/densetools.py", # raises deprecation warning "sympy/printing/ccode.py", # backwards compatibility shim, importing it breaks the codegen doctests "sympy/printing/fcode.py", # backwards compatibility shim, importing it breaks the codegen doctests "sympy/printing/cxxcode.py", # backwards compatibility shim, importing it breaks the codegen doctests "sympy/parsing/autolev/_antlr/autolevlexer.py", # generated code "sympy/parsing/autolev/_antlr/autolevparser.py", # generated code "sympy/parsing/autolev/_antlr/autolevlistener.py", # generated code "sympy/parsing/latex/_antlr/latexlexer.py", # generated code "sympy/parsing/latex/_antlr/latexparser.py", # generated code "sympy/integrals/rubi/rubi.py", "sympy/plotting/pygletplot/__init__.py", # crashes on some systems "sympy/plotting/pygletplot/plot.py", # crashes on some systems ]) # autolev parser tests num = 12 for i in range (1, num+1): blacklist.append("sympy/parsing/autolev/test-examples/ruletest" + str(i) + ".py") blacklist.extend(["sympy/parsing/autolev/test-examples/pydy-example-repo/mass_spring_damper.py", "sympy/parsing/autolev/test-examples/pydy-example-repo/chaos_pendulum.py", "sympy/parsing/autolev/test-examples/pydy-example-repo/double_pendulum.py", "sympy/parsing/autolev/test-examples/pydy-example-repo/non_min_pendulum.py"]) if import_module('numpy') is None: blacklist.extend([ "sympy/plotting/experimental_lambdify.py", "sympy/plotting/plot_implicit.py", "examples/advanced/autowrap_integrators.py", "examples/advanced/autowrap_ufuncify.py", "examples/intermediate/sample.py", "examples/intermediate/mplot2d.py", "examples/intermediate/mplot3d.py", "doc/src/modules/numeric-computation.rst" ]) else: if import_module('matplotlib') is None: blacklist.extend([ "examples/intermediate/mplot2d.py", "examples/intermediate/mplot3d.py" ]) else: # Use a non-windowed backend, so that the tests work on Travis import matplotlib matplotlib.use('Agg') if ON_TRAVIS or import_module('pyglet') is None: blacklist.extend(["sympy/plotting/pygletplot"]) if import_module('aesara') is None: blacklist.extend([ "sympy/printing/aesaracode.py", "doc/src/modules/numeric-computation.rst", ]) if import_module('cupy') is None: blacklist.extend([ "doc/src/modules/numeric-computation.rst", ]) if import_module('antlr4') is None: blacklist.extend([ "sympy/parsing/autolev/__init__.py", "sympy/parsing/latex/_parse_latex_antlr.py", ]) if import_module('lfortran') is None: #throws ImportError when lfortran not installed blacklist.extend([ "sympy/parsing/sym_expr.py", ]) # disabled because of doctest failures in asmeurer's bot blacklist.extend([ "sympy/utilities/autowrap.py", "examples/advanced/autowrap_integrators.py", "examples/advanced/autowrap_ufuncify.py" ]) # blacklist these modules until issue 4840 is resolved blacklist.extend([ "sympy/conftest.py", # Python 2.7 issues "sympy/testing/benchmarking.py", ]) # These are deprecated stubs to be removed: blacklist.extend([ "sympy/utilities/benchmarking.py", "sympy/utilities/tmpfiles.py", "sympy/utilities/pytest.py", "sympy/utilities/runtests.py", "sympy/utilities/quality_unicode.py", "sympy/utilities/randtest.py", ]) blacklist = convert_to_native_paths(blacklist) return blacklist def _doctest(*paths, **kwargs): """ Internal function that actually runs the doctests. All keyword arguments from ``doctest()`` are passed to this function except for ``subprocess``. Returns 0 if tests passed and 1 if they failed. See the docstrings of ``doctest()`` and ``test()`` for more information. """ from sympy import pprint_use_unicode normal = kwargs.get("normal", False) verbose = kwargs.get("verbose", False) colors = kwargs.get("colors", True) force_colors = kwargs.get("force_colors", False) blacklist = kwargs.get("blacklist", []) split = kwargs.get('split', None) blacklist.extend(_get_doctest_blacklist()) # Use a non-windowed backend, so that the tests work on Travis if import_module('matplotlib') is not None: import matplotlib matplotlib.use('Agg') # Disable warnings for external modules import sympy.external sympy.external.importtools.WARN_OLD_VERSION = False sympy.external.importtools.WARN_NOT_INSTALLED = False # Disable showing up of plots from sympy.plotting.plot import unset_show unset_show() r = PyTestReporter(verbose, split=split, colors=colors,\ force_colors=force_colors) t = SymPyDocTests(r, normal) test_files = t.get_test_files('sympy') test_files.extend(t.get_test_files('examples', init_only=False)) not_blacklisted = [f for f in test_files if not any(b in f for b in blacklist)] if len(paths) == 0: matched = not_blacklisted else: # take only what was requested...but not blacklisted items # and allow for partial match anywhere or fnmatch of name paths = convert_to_native_paths(paths) matched = [] for f in not_blacklisted: basename = os.path.basename(f) for p in paths: if p in f or fnmatch(basename, p): matched.append(f) break if split: matched = split_list(matched, split) t._testfiles.extend(matched) # run the tests and record the result for this *py portion of the tests if t._testfiles: failed = not t.test() else: failed = False # N.B. # -------------------------------------------------------------------- # Here we test *.rst files at or below doc/src. Code from these must # be self supporting in terms of imports since there is no importing # of necessary modules by doctest.testfile. If you try to pass *.py # files through this they might fail because they will lack the needed # imports and smarter parsing that can be done with source code. # test_files = t.get_test_files('doc/src', '*.rst', init_only=False) test_files.sort() not_blacklisted = [f for f in test_files if not any(b in f for b in blacklist)] if len(paths) == 0: matched = not_blacklisted else: # Take only what was requested as long as it's not on the blacklist. # Paths were already made native in *py tests so don't repeat here. # There's no chance of having a *py file slip through since we # only have *rst files in test_files. matched = [] for f in not_blacklisted: basename = os.path.basename(f) for p in paths: if p in f or fnmatch(basename, p): matched.append(f) break if split: matched = split_list(matched, split) first_report = True for rst_file in matched: if not os.path.isfile(rst_file): continue old_displayhook = sys.displayhook try: use_unicode_prev = setup_pprint() out = sympytestfile( rst_file, module_relative=False, encoding='utf-8', optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE | pdoctest.IGNORE_EXCEPTION_DETAIL) finally: # make sure we return to the original displayhook in case some # doctest has changed that sys.displayhook = old_displayhook # The NO_GLOBAL flag overrides the no_global flag to init_printing # if True import sympy.interactive.printing as interactive_printing interactive_printing.NO_GLOBAL = False pprint_use_unicode(use_unicode_prev) rstfailed, tested = out if tested: failed = rstfailed or failed if first_report: first_report = False msg = 'rst doctests start' if not t._testfiles: r.start(msg=msg) else: r.write_center(msg) print() # use as the id, everything past the first 'sympy' file_id = rst_file[rst_file.find('sympy') + len('sympy') + 1:] print(file_id, end=" ") # get at least the name out so it is know who is being tested wid = r.terminal_width - len(file_id) - 1 # update width test_file = '[%s]' % (tested) report = '[%s]' % (rstfailed or 'OK') print(''.join( [test_file, ' '*(wid - len(test_file) - len(report)), report]) ) # the doctests for *py will have printed this message already if there was # a failure, so now only print it if there was intervening reporting by # testing the *rst as evidenced by first_report no longer being True. if not first_report and failed: print() print("DO *NOT* COMMIT!") return int(failed) sp = re.compile(r'([0-9]+)/([1-9][0-9]*)') def split_list(l, split, density=None): """ Splits a list into part a of b split should be a string of the form 'a/b'. For instance, '1/3' would give the split one of three. If the length of the list is not divisible by the number of splits, the last split will have more items. `density` may be specified as a list. If specified, tests will be balanced so that each split has as equal-as-possible amount of mass according to `density`. >>> from sympy.testing.runtests import split_list >>> a = list(range(10)) >>> split_list(a, '1/3') [0, 1, 2] >>> split_list(a, '2/3') [3, 4, 5] >>> split_list(a, '3/3') [6, 7, 8, 9] """ m = sp.match(split) if not m: raise ValueError("split must be a string of the form a/b where a and b are ints") i, t = map(int, m.groups()) if not density: return l[(i - 1)*len(l)//t : i*len(l)//t] # normalize density tot = sum(density) density = [x / tot for x in density] def density_inv(x): """Interpolate the inverse to the cumulative distribution function given by density""" if x <= 0: return 0 if x >= sum(density): return 1 # find the first time the cumulative sum surpasses x # and linearly interpolate cumm = 0 for i, d in enumerate(density): cumm += d if cumm >= x: break frac = (d - (cumm - x)) / d return (i + frac) / len(density) lower_frac = density_inv((i - 1) / t) higher_frac = density_inv(i / t) return l[int(lower_frac*len(l)) : int(higher_frac*len(l))] from collections import namedtuple SymPyTestResults = namedtuple('SymPyTestResults', 'failed attempted') def sympytestfile(filename, module_relative=True, name=None, package=None, globs=None, verbose=None, report=True, optionflags=0, extraglobs=None, raise_on_error=False, parser=pdoctest.DocTestParser(), encoding=None): """ Test examples in the given file. Return (#failures, #tests). Optional keyword arg ``module_relative`` specifies how filenames should be interpreted: - If ``module_relative`` is True (the default), then ``filename`` specifies a module-relative path. By default, this path is relative to the calling module's directory; but if the ``package`` argument is specified, then it is relative to that package. To ensure os-independence, ``filename`` should use "/" characters to separate path segments, and should not be an absolute path (i.e., it may not begin with "/"). - If ``module_relative`` is False, then ``filename`` specifies an os-specific path. The path may be absolute or relative (to the current working directory). Optional keyword arg ``name`` gives the name of the test; by default use the file's basename. Optional keyword argument ``package`` is a Python package or the name of a Python package whose directory should be used as the base directory for a module relative filename. If no package is specified, then the calling module's directory is used as the base directory for module relative filenames. It is an error to specify ``package`` if ``module_relative`` is False. Optional keyword arg ``globs`` gives a dict to be used as the globals when executing examples; by default, use {}. A copy of this dict is actually used for each docstring, so that each docstring's examples start with a clean slate. Optional keyword arg ``extraglobs`` gives a dictionary that should be merged into the globals that are used to execute examples. By default, no extra globals are used. Optional keyword arg ``verbose`` prints lots of stuff if true, prints only failures if false; by default, it's true iff "-v" is in sys.argv. Optional keyword arg ``report`` prints a summary at the end when true, else prints nothing at the end. In verbose mode, the summary is detailed, else very brief (in fact, empty if all tests passed). Optional keyword arg ``optionflags`` or's together module constants, and defaults to 0. Possible values (see the docs for details): - DONT_ACCEPT_TRUE_FOR_1 - DONT_ACCEPT_BLANKLINE - NORMALIZE_WHITESPACE - ELLIPSIS - SKIP - IGNORE_EXCEPTION_DETAIL - REPORT_UDIFF - REPORT_CDIFF - REPORT_NDIFF - REPORT_ONLY_FIRST_FAILURE Optional keyword arg ``raise_on_error`` raises an exception on the first unexpected exception or failure. This allows failures to be post-mortem debugged. Optional keyword arg ``parser`` specifies a DocTestParser (or subclass) that should be used to extract tests from the files. Optional keyword arg ``encoding`` specifies an encoding that should be used to convert the file to unicode. Advanced tomfoolery: testmod runs methods of a local instance of class doctest.Tester, then merges the results into (or creates) global Tester instance doctest.master. Methods of doctest.master can be called directly too, if you want to do something unusual. Passing report=0 to testmod is especially useful then, to delay displaying a summary. Invoke doctest.master.summarize(verbose) when you're done fiddling. """ if package and not module_relative: raise ValueError("Package may only be specified for module-" "relative paths.") # Relativize the path if not PY3: text, filename = pdoctest._load_testfile( filename, package, module_relative) if encoding is not None: text = text.decode(encoding) else: text, filename = pdoctest._load_testfile( filename, package, module_relative, encoding) # If no name was given, then use the file's name. if name is None: name = os.path.basename(filename) # Assemble the globals. if globs is None: globs = {} else: globs = globs.copy() if extraglobs is not None: globs.update(extraglobs) if '__name__' not in globs: globs['__name__'] = '__main__' if raise_on_error: runner = pdoctest.DebugRunner(verbose=verbose, optionflags=optionflags) else: runner = SymPyDocTestRunner(verbose=verbose, optionflags=optionflags) runner._checker = SymPyOutputChecker() # Read the file, convert it to a test, and run it. test = parser.get_doctest(text, globs, name, filename, 0) runner.run(test, compileflags=future_flags) if report: runner.summarize() if pdoctest.master is None: pdoctest.master = runner else: pdoctest.master.merge(runner) return SymPyTestResults(runner.failures, runner.tries) class SymPyTests: def __init__(self, reporter, kw="", post_mortem=False, seed=None, fast_threshold=None, slow_threshold=None): self._post_mortem = post_mortem self._kw = kw self._count = 0 self._root_dir = get_sympy_dir() self._reporter = reporter self._reporter.root_dir(self._root_dir) self._testfiles = [] self._seed = seed if seed is not None else random.random() # Defaults in seconds, from human / UX design limits # http://www.nngroup.com/articles/response-times-3-important-limits/ # # These defaults are *NOT* set in stone as we are measuring different # things, so others feel free to come up with a better yardstick :) if fast_threshold: self._fast_threshold = float(fast_threshold) else: self._fast_threshold = 8 if slow_threshold: self._slow_threshold = float(slow_threshold) else: self._slow_threshold = 10 def test(self, sort=False, timeout=False, slow=False, enhance_asserts=False, fail_on_timeout=False): """ Runs the tests returning True if all tests pass, otherwise False. If sort=False run tests in random order. """ if sort: self._testfiles.sort() elif slow: pass else: random.seed(self._seed) random.shuffle(self._testfiles) self._reporter.start(self._seed) for f in self._testfiles: try: self.test_file(f, sort, timeout, slow, enhance_asserts, fail_on_timeout) except KeyboardInterrupt: print(" interrupted by user") self._reporter.finish() raise return self._reporter.finish() def _enhance_asserts(self, source): from ast import (NodeTransformer, Compare, Name, Store, Load, Tuple, Assign, BinOp, Str, Mod, Assert, parse, fix_missing_locations) ops = {"Eq": '==', "NotEq": '!=', "Lt": '<', "LtE": '<=', "Gt": '>', "GtE": '>=', "Is": 'is', "IsNot": 'is not', "In": 'in', "NotIn": 'not in'} class Transform(NodeTransformer): def visit_Assert(self, stmt): if isinstance(stmt.test, Compare): compare = stmt.test values = [compare.left] + compare.comparators names = [ "_%s" % i for i, _ in enumerate(values) ] names_store = [ Name(n, Store()) for n in names ] names_load = [ Name(n, Load()) for n in names ] target = Tuple(names_store, Store()) value = Tuple(values, Load()) assign = Assign([target], value) new_compare = Compare(names_load[0], compare.ops, names_load[1:]) msg_format = "\n%s " + "\n%s ".join([ ops[op.__class__.__name__] for op in compare.ops ]) + "\n%s" msg = BinOp(Str(msg_format), Mod(), Tuple(names_load, Load())) test = Assert(new_compare, msg, lineno=stmt.lineno, col_offset=stmt.col_offset) return [assign, test] else: return stmt tree = parse(source) new_tree = Transform().visit(tree) return fix_missing_locations(new_tree) def test_file(self, filename, sort=True, timeout=False, slow=False, enhance_asserts=False, fail_on_timeout=False): reporter = self._reporter funcs = [] try: gl = {'__file__': filename} try: if PY3: open_file = lambda: open(filename, encoding="utf8") else: open_file = lambda: open(filename) with open_file() as f: source = f.read() if self._kw: for l in source.splitlines(): if l.lstrip().startswith('def '): if any(l.find(k) != -1 for k in self._kw): break else: return if enhance_asserts: try: source = self._enhance_asserts(source) except ImportError: pass code = compile(source, filename, "exec", flags=0, dont_inherit=True) exec(code, gl) except (SystemExit, KeyboardInterrupt): raise except ImportError: reporter.import_error(filename, sys.exc_info()) return except Exception: reporter.test_exception(sys.exc_info()) clear_cache() self._count += 1 random.seed(self._seed) disabled = gl.get("disabled", False) if not disabled: # we need to filter only those functions that begin with 'test_' # We have to be careful about decorated functions. As long as # the decorator uses functools.wraps, we can detect it. funcs = [] for f in gl: if (f.startswith("test_") and (inspect.isfunction(gl[f]) or inspect.ismethod(gl[f]))): func = gl[f] # Handle multiple decorators while hasattr(func, '__wrapped__'): func = func.__wrapped__ if inspect.getsourcefile(func) == filename: funcs.append(gl[f]) if slow: funcs = [f for f in funcs if getattr(f, '_slow', False)] # Sorting of XFAILed functions isn't fixed yet :-( funcs.sort(key=lambda x: inspect.getsourcelines(x)[1]) i = 0 while i < len(funcs): if inspect.isgeneratorfunction(funcs[i]): # some tests can be generators, that return the actual # test functions. We unpack it below: f = funcs.pop(i) for fg in f(): func = fg[0] args = fg[1:] fgw = lambda: func(*args) funcs.insert(i, fgw) i += 1 else: i += 1 # drop functions that are not selected with the keyword expression: funcs = [x for x in funcs if self.matches(x)] if not funcs: return except Exception: reporter.entering_filename(filename, len(funcs)) raise reporter.entering_filename(filename, len(funcs)) if not sort: random.shuffle(funcs) for f in funcs: start = time.time() reporter.entering_test(f) try: if getattr(f, '_slow', False) and not slow: raise Skipped("Slow") with raise_on_deprecated(): if timeout: self._timeout(f, timeout, fail_on_timeout) else: random.seed(self._seed) f() except KeyboardInterrupt: if getattr(f, '_slow', False): reporter.test_skip("KeyboardInterrupt") else: raise except Exception: if timeout: signal.alarm(0) # Disable the alarm. It could not be handled before. t, v, tr = sys.exc_info() if t is AssertionError: reporter.test_fail((t, v, tr)) if self._post_mortem: pdb.post_mortem(tr) elif t.__name__ == "Skipped": reporter.test_skip(v) elif t.__name__ == "XFail": reporter.test_xfail() elif t.__name__ == "XPass": reporter.test_xpass(v) else: reporter.test_exception((t, v, tr)) if self._post_mortem: pdb.post_mortem(tr) else: reporter.test_pass() taken = time.time() - start if taken > self._slow_threshold: filename = os.path.relpath(filename, reporter._root_dir) reporter.slow_test_functions.append( (filename + "::" + f.__name__, taken)) if getattr(f, '_slow', False) and slow: if taken < self._fast_threshold: filename = os.path.relpath(filename, reporter._root_dir) reporter.fast_test_functions.append( (filename + "::" + f.__name__, taken)) reporter.leaving_filename() def _timeout(self, function, timeout, fail_on_timeout): def callback(x, y): signal.alarm(0) if fail_on_timeout: raise TimeOutError("Timed out after %d seconds" % timeout) else: raise Skipped("Timeout") signal.signal(signal.SIGALRM, callback) signal.alarm(timeout) # Set an alarm with a given timeout function() signal.alarm(0) # Disable the alarm def matches(self, x): """ Does the keyword expression self._kw match "x"? Returns True/False. Always returns True if self._kw is "". """ if not self._kw: return True for kw in self._kw: if x.__name__.find(kw) != -1: return True return False def get_test_files(self, dir, pat='test_*.py'): """ Returns the list of test_*.py (default) files at or below directory ``dir`` relative to the sympy home directory. """ dir = os.path.join(self._root_dir, convert_to_native_paths([dir])[0]) g = [] for path, folders, files in os.walk(dir): g.extend([os.path.join(path, f) for f in files if fnmatch(f, pat)]) return sorted([os.path.normcase(gi) for gi in g]) class SymPyDocTests: def __init__(self, reporter, normal): self._count = 0 self._root_dir = get_sympy_dir() self._reporter = reporter self._reporter.root_dir(self._root_dir) self._normal = normal self._testfiles = [] def test(self): """ Runs the tests and returns True if all tests pass, otherwise False. """ self._reporter.start() for f in self._testfiles: try: self.test_file(f) except KeyboardInterrupt: print(" interrupted by user") self._reporter.finish() raise return self._reporter.finish() def test_file(self, filename): clear_cache() from io import StringIO import sympy.interactive.printing as interactive_printing from sympy import pprint_use_unicode rel_name = filename[len(self._root_dir) + 1:] dirname, file = os.path.split(filename) module = rel_name.replace(os.sep, '.')[:-3] if rel_name.startswith("examples"): # Examples files do not have __init__.py files, # So we have to temporarily extend sys.path to import them sys.path.insert(0, dirname) module = file[:-3] # remove ".py" try: module = pdoctest._normalize_module(module) tests = SymPyDocTestFinder().find(module) except (SystemExit, KeyboardInterrupt): raise except ImportError: self._reporter.import_error(filename, sys.exc_info()) return finally: if rel_name.startswith("examples"): del sys.path[0] tests = [test for test in tests if len(test.examples) > 0] # By default tests are sorted by alphabetical order by function name. # We sort by line number so one can edit the file sequentially from # bottom to top. However, if there are decorated functions, their line # numbers will be too large and for now one must just search for these # by text and function name. tests.sort(key=lambda x: -x.lineno) if not tests: return self._reporter.entering_filename(filename, len(tests)) for test in tests: assert len(test.examples) != 0 if self._reporter._verbose: self._reporter.write("\n{} ".format(test.name)) # check if there are external dependencies which need to be met if '_doctest_depends_on' in test.globs: try: self._check_dependencies(**test.globs['_doctest_depends_on']) except DependencyError as e: self._reporter.test_skip(v=str(e)) continue runner = SymPyDocTestRunner(optionflags=pdoctest.ELLIPSIS | pdoctest.NORMALIZE_WHITESPACE | pdoctest.IGNORE_EXCEPTION_DETAIL) runner._checker = SymPyOutputChecker() old = sys.stdout new = StringIO() sys.stdout = new # If the testing is normal, the doctests get importing magic to # provide the global namespace. If not normal (the default) then # then must run on their own; all imports must be explicit within # a function's docstring. Once imported that import will be # available to the rest of the tests in a given function's # docstring (unless clear_globs=True below). if not self._normal: test.globs = {} # if this is uncommented then all the test would get is what # comes by default with a "from sympy import *" #exec('from sympy import *') in test.globs test.globs['print_function'] = print_function old_displayhook = sys.displayhook use_unicode_prev = setup_pprint() try: f, t = runner.run(test, compileflags=future_flags, out=new.write, clear_globs=False) except KeyboardInterrupt: raise finally: sys.stdout = old if f > 0: self._reporter.doctest_fail(test.name, new.getvalue()) else: self._reporter.test_pass() sys.displayhook = old_displayhook interactive_printing.NO_GLOBAL = False pprint_use_unicode(use_unicode_prev) self._reporter.leaving_filename() def get_test_files(self, dir, pat='*.py', init_only=True): r""" Returns the list of \*.py files (default) from which docstrings will be tested which are at or below directory ``dir``. By default, only those that have an __init__.py in their parent directory and do not start with ``test_`` will be included. """ def importable(x): """ Checks if given pathname x is an importable module by checking for __init__.py file. Returns True/False. Currently we only test if the __init__.py file exists in the directory with the file "x" (in theory we should also test all the parent dirs). """ init_py = os.path.join(os.path.dirname(x), "__init__.py") return os.path.exists(init_py) dir = os.path.join(self._root_dir, convert_to_native_paths([dir])[0]) g = [] for path, folders, files in os.walk(dir): g.extend([os.path.join(path, f) for f in files if not f.startswith('test_') and fnmatch(f, pat)]) if init_only: # skip files that are not importable (i.e. missing __init__.py) g = [x for x in g if importable(x)] return [os.path.normcase(gi) for gi in g] def _check_dependencies(self, executables=(), modules=(), disable_viewers=(), python_version=(3, 5)): """ Checks if the dependencies for the test are installed. Raises ``DependencyError`` it at least one dependency is not installed. """ for executable in executables: if not shutil.which(executable): raise DependencyError("Could not find %s" % executable) for module in modules: if module == 'matplotlib': matplotlib = import_module( 'matplotlib', import_kwargs={'fromlist': ['pyplot', 'cm', 'collections']}, min_module_version='1.0.0', catch=(RuntimeError,)) if matplotlib is None: raise DependencyError("Could not import matplotlib") else: if not import_module(module): raise DependencyError("Could not import %s" % module) if disable_viewers: tempdir = tempfile.mkdtemp() os.environ['PATH'] = '%s:%s' % (tempdir, os.environ['PATH']) vw = ('#!/usr/bin/env {}\n' 'import sys\n' 'if len(sys.argv) <= 1:\n' ' exit("wrong number of args")\n').format( 'python3' if PY3 else 'python') for viewer in disable_viewers: with open(os.path.join(tempdir, viewer), 'w') as fh: fh.write(vw) # make the file executable os.chmod(os.path.join(tempdir, viewer), stat.S_IREAD | stat.S_IWRITE | stat.S_IXUSR) if python_version: if sys.version_info < python_version: raise DependencyError("Requires Python >= " + '.'.join(map(str, python_version))) if 'pyglet' in modules: # monkey-patch pyglet s.t. it does not open a window during # doctesting import pyglet class DummyWindow: def __init__(self, *args, **kwargs): self.has_exit = True self.width = 600 self.height = 400 def set_vsync(self, x): pass def switch_to(self): pass def push_handlers(self, x): pass def close(self): pass pyglet.window.Window = DummyWindow class SymPyDocTestFinder(DocTestFinder): """ A class used to extract the DocTests that are relevant to a given object, from its docstring and the docstrings of its contained objects. Doctests can currently be extracted from the following object types: modules, functions, classes, methods, staticmethods, classmethods, and properties. Modified from doctest's version to look harder for code that appears comes from a different module. For example, the @vectorize decorator makes it look like functions come from multidimensional.py even though their code exists elsewhere. """ def _find(self, tests, obj, name, module, source_lines, globs, seen): """ Find tests for the given object and any contained objects, and add them to ``tests``. """ if self._verbose: print('Finding tests in %s' % name) # If we've already processed this object, then ignore it. if id(obj) in seen: return seen[id(obj)] = 1 # Make sure we don't run doctests for classes outside of sympy, such # as in numpy or scipy. if inspect.isclass(obj): if obj.__module__.split('.')[0] != 'sympy': return # Find a test for this object, and add it to the list of tests. test = self._get_test(obj, name, module, globs, source_lines) if test is not None: tests.append(test) if not self._recurse: return # Look for tests in a module's contained objects. if inspect.ismodule(obj): for rawname, val in obj.__dict__.items(): # Recurse to functions & classes. if inspect.isfunction(val) or inspect.isclass(val): # Make sure we don't run doctests functions or classes # from different modules if val.__module__ != module.__name__: continue assert self._from_module(module, val), \ "%s is not in module %s (rawname %s)" % (val, module, rawname) try: valname = '%s.%s' % (name, rawname) self._find(tests, val, valname, module, source_lines, globs, seen) except KeyboardInterrupt: raise # Look for tests in a module's __test__ dictionary. for valname, val in getattr(obj, '__test__', {}).items(): if not isinstance(valname, str): raise ValueError("SymPyDocTestFinder.find: __test__ keys " "must be strings: %r" % (type(valname),)) if not (inspect.isfunction(val) or inspect.isclass(val) or inspect.ismethod(val) or inspect.ismodule(val) or isinstance(val, str)): raise ValueError("SymPyDocTestFinder.find: __test__ values " "must be strings, functions, methods, " "classes, or modules: %r" % (type(val),)) valname = '%s.__test__.%s' % (name, valname) self._find(tests, val, valname, module, source_lines, globs, seen) # Look for tests in a class's contained objects. if inspect.isclass(obj): for valname, val in obj.__dict__.items(): # Special handling for staticmethod/classmethod. if isinstance(val, staticmethod): val = getattr(obj, valname) if isinstance(val, classmethod): val = getattr(obj, valname).__func__ # Recurse to methods, properties, and nested classes. if ((inspect.isfunction(unwrap(val)) or inspect.isclass(val) or isinstance(val, property)) and self._from_module(module, val)): # Make sure we don't run doctests functions or classes # from different modules if isinstance(val, property): if hasattr(val.fget, '__module__'): if val.fget.__module__ != module.__name__: continue else: if val.__module__ != module.__name__: continue assert self._from_module(module, val), \ "%s is not in module %s (valname %s)" % ( val, module, valname) valname = '%s.%s' % (name, valname) self._find(tests, val, valname, module, source_lines, globs, seen) def _get_test(self, obj, name, module, globs, source_lines): """ Return a DocTest for the given object, if it defines a docstring; otherwise, return None. """ lineno = None # Extract the object's docstring. If it doesn't have one, # then return None (no test for this object). if isinstance(obj, str): # obj is a string in the case for objects in the polys package. # Note that source_lines is a binary string (compiled polys # modules), which can't be handled by _find_lineno so determine # the line number here. docstring = obj matches = re.findall(r"line \d+", name) assert len(matches) == 1, \ "string '%s' does not contain lineno " % name # NOTE: this is not the exact linenumber but its better than no # lineno ;) lineno = int(matches[0][5:]) else: try: if obj.__doc__ is None: docstring = '' else: docstring = obj.__doc__ if not isinstance(docstring, str): docstring = str(docstring) except (TypeError, AttributeError): docstring = '' # Don't bother if the docstring is empty. if self._exclude_empty and not docstring: return None # check that properties have a docstring because _find_lineno # assumes it if isinstance(obj, property): if obj.fget.__doc__ is None: return None # Find the docstring's location in the file. if lineno is None: obj = unwrap(obj) # handling of properties is not implemented in _find_lineno so do # it here if hasattr(obj, 'func_closure') and obj.func_closure is not None: tobj = obj.func_closure[0].cell_contents elif isinstance(obj, property): tobj = obj.fget else: tobj = obj lineno = self._find_lineno(tobj, source_lines) if lineno is None: return None # Return a DocTest for this object. if module is None: filename = None else: filename = getattr(module, '__file__', module.__name__) if filename[-4:] in (".pyc", ".pyo"): filename = filename[:-1] globs['_doctest_depends_on'] = getattr(obj, '_doctest_depends_on', {}) return self._parser.get_doctest(docstring, globs, name, filename, lineno) class SymPyDocTestRunner(DocTestRunner): """ A class used to run DocTest test cases, and accumulate statistics. The ``run`` method is used to process a single DocTest case. It returns a tuple ``(f, t)``, where ``t`` is the number of test cases tried, and ``f`` is the number of test cases that failed. Modified from the doctest version to not reset the sys.displayhook (see issue 5140). See the docstring of the original DocTestRunner for more information. """ def run(self, test, compileflags=None, out=None, clear_globs=True): """ Run the examples in ``test``, and display the results using the writer function ``out``. The examples are run in the namespace ``test.globs``. If ``clear_globs`` is true (the default), then this namespace will be cleared after the test runs, to help with garbage collection. If you would like to examine the namespace after the test completes, then use ``clear_globs=False``. ``compileflags`` gives the set of flags that should be used by the Python compiler when running the examples. If not specified, then it will default to the set of future-import flags that apply to ``globs``. The output of each example is checked using ``SymPyDocTestRunner.check_output``, and the results are formatted by the ``SymPyDocTestRunner.report_*`` methods. """ self.test = test if compileflags is None: compileflags = pdoctest._extract_future_flags(test.globs) save_stdout = sys.stdout if out is None: out = save_stdout.write sys.stdout = self._fakeout # Patch pdb.set_trace to restore sys.stdout during interactive # debugging (so it's not still redirected to self._fakeout). # Note that the interactive output will go to *our* # save_stdout, even if that's not the real sys.stdout; this # allows us to write test cases for the set_trace behavior. save_set_trace = pdb.set_trace self.debugger = pdoctest._OutputRedirectingPdb(save_stdout) self.debugger.reset() pdb.set_trace = self.debugger.set_trace # Patch linecache.getlines, so we can see the example's source # when we're inside the debugger. self.save_linecache_getlines = pdoctest.linecache.getlines linecache.getlines = self.__patched_linecache_getlines # Fail for deprecation warnings with raise_on_deprecated(): try: test.globs['print_function'] = print_function return self.__run(test, compileflags, out) finally: sys.stdout = save_stdout pdb.set_trace = save_set_trace linecache.getlines = self.save_linecache_getlines if clear_globs: test.globs.clear() # We have to override the name mangled methods. monkeypatched_methods = [ 'patched_linecache_getlines', 'run', 'record_outcome' ] for method in monkeypatched_methods: oldname = '_DocTestRunner__' + method newname = '_SymPyDocTestRunner__' + method setattr(SymPyDocTestRunner, newname, getattr(DocTestRunner, oldname)) class SymPyOutputChecker(pdoctest.OutputChecker): """ Compared to the OutputChecker from the stdlib our OutputChecker class supports numerical comparison of floats occurring in the output of the doctest examples """ def __init__(self): # NOTE OutputChecker is an old-style class with no __init__ method, # so we can't call the base class version of __init__ here got_floats = r'(\d+\.\d*|\.\d+)' # floats in the 'want' string may contain ellipses want_floats = got_floats + r'(\.{3})?' front_sep = r'\s|\+|\-|\*|,' back_sep = front_sep + r'|j|e' fbeg = r'^%s(?=%s|$)' % (got_floats, back_sep) fmidend = r'(?<=%s)%s(?=%s|$)' % (front_sep, got_floats, back_sep) self.num_got_rgx = re.compile(r'(%s|%s)' %(fbeg, fmidend)) fbeg = r'^%s(?=%s|$)' % (want_floats, back_sep) fmidend = r'(?<=%s)%s(?=%s|$)' % (front_sep, want_floats, back_sep) self.num_want_rgx = re.compile(r'(%s|%s)' %(fbeg, fmidend)) def check_output(self, want, got, optionflags): """ Return True iff the actual output from an example (`got`) matches the expected output (`want`). These strings are always considered to match if they are identical; but depending on what option flags the test runner is using, several non-exact match types are also possible. See the documentation for `TestRunner` for more information about option flags. """ # Handle the common case first, for efficiency: # if they're string-identical, always return true. if got == want: return True # TODO parse integers as well ? # Parse floats and compare them. If some of the parsed floats contain # ellipses, skip the comparison. matches = self.num_got_rgx.finditer(got) numbers_got = [match.group(1) for match in matches] # list of strs matches = self.num_want_rgx.finditer(want) numbers_want = [match.group(1) for match in matches] # list of strs if len(numbers_got) != len(numbers_want): return False if len(numbers_got) > 0: nw_ = [] for ng, nw in zip(numbers_got, numbers_want): if '...' in nw: nw_.append(ng) continue else: nw_.append(nw) if abs(float(ng)-float(nw)) > 1e-5: return False got = self.num_got_rgx.sub(r'%s', got) got = got % tuple(nw_) # can be used as a special sequence to signify a # blank line, unless the DONT_ACCEPT_BLANKLINE flag is used. if not (optionflags & pdoctest.DONT_ACCEPT_BLANKLINE): # Replace in want with a blank line. want = re.sub(r'(?m)^%s\s*?$' % re.escape(pdoctest.BLANKLINE_MARKER), '', want) # If a line in got contains only spaces, then remove the # spaces. got = re.sub(r'(?m)^\s*?$', '', got) if got == want: return True # This flag causes doctest to ignore any differences in the # contents of whitespace strings. Note that this can be used # in conjunction with the ELLIPSIS flag. if optionflags & pdoctest.NORMALIZE_WHITESPACE: got = ' '.join(got.split()) want = ' '.join(want.split()) if got == want: return True # The ELLIPSIS flag says to let the sequence "..." in `want` # match any substring in `got`. if optionflags & pdoctest.ELLIPSIS: if pdoctest._ellipsis_match(want, got): return True # We didn't find any match; return false. return False class Reporter: """ Parent class for all reporters. """ pass class PyTestReporter(Reporter): """ Py.test like reporter. Should produce output identical to py.test. """ def __init__(self, verbose=False, tb="short", colors=True, force_colors=False, split=None): self._verbose = verbose self._tb_style = tb self._colors = colors self._force_colors = force_colors self._xfailed = 0 self._xpassed = [] self._failed = [] self._failed_doctest = [] self._passed = 0 self._skipped = 0 self._exceptions = [] self._terminal_width = None self._default_width = 80 self._split = split self._active_file = '' self._active_f = None # TODO: Should these be protected? self.slow_test_functions = [] self.fast_test_functions = [] # this tracks the x-position of the cursor (useful for positioning # things on the screen), without the need for any readline library: self._write_pos = 0 self._line_wrap = False def root_dir(self, dir): self._root_dir = dir @property def terminal_width(self): if self._terminal_width is not None: return self._terminal_width def findout_terminal_width(): if sys.platform == "win32": # Windows support is based on: # # http://code.activestate.com/recipes/ # 440694-determine-size-of-console-window-on-windows/ from ctypes import windll, create_string_buffer h = windll.kernel32.GetStdHandle(-12) csbi = create_string_buffer(22) res = windll.kernel32.GetConsoleScreenBufferInfo(h, csbi) if res: import struct (_, _, _, _, _, left, _, right, _, _, _) = \ struct.unpack("hhhhHhhhhhh", csbi.raw) return right - left else: return self._default_width if hasattr(sys.stdout, 'isatty') and not sys.stdout.isatty(): return self._default_width # leave PIPEs alone try: process = subprocess.Popen(['stty', '-a'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout = process.stdout.read() if PY3: stdout = stdout.decode("utf-8") except OSError: pass else: # We support the following output formats from stty: # # 1) Linux -> columns 80 # 2) OS X -> 80 columns # 3) Solaris -> columns = 80 re_linux = r"columns\s+(?P\d+);" re_osx = r"(?P\d+)\s*columns;" re_solaris = r"columns\s+=\s+(?P\d+);" for regex in (re_linux, re_osx, re_solaris): match = re.search(regex, stdout) if match is not None: columns = match.group('columns') try: width = int(columns) except ValueError: pass if width != 0: return width return self._default_width width = findout_terminal_width() self._terminal_width = width return width def write(self, text, color="", align="left", width=None, force_colors=False): """ Prints a text on the screen. It uses sys.stdout.write(), so no readline library is necessary. Parameters ========== color : choose from the colors below, "" means default color align : "left"/"right", "left" is a normal print, "right" is aligned on the right-hand side of the screen, filled with spaces if necessary width : the screen width """ color_templates = ( ("Black", "0;30"), ("Red", "0;31"), ("Green", "0;32"), ("Brown", "0;33"), ("Blue", "0;34"), ("Purple", "0;35"), ("Cyan", "0;36"), ("LightGray", "0;37"), ("DarkGray", "1;30"), ("LightRed", "1;31"), ("LightGreen", "1;32"), ("Yellow", "1;33"), ("LightBlue", "1;34"), ("LightPurple", "1;35"), ("LightCyan", "1;36"), ("White", "1;37"), ) colors = {} for name, value in color_templates: colors[name] = value c_normal = '\033[0m' c_color = '\033[%sm' if width is None: width = self.terminal_width if align == "right": if self._write_pos + len(text) > width: # we don't fit on the current line, create a new line self.write("\n") self.write(" "*(width - self._write_pos - len(text))) if not self._force_colors and hasattr(sys.stdout, 'isatty') and not \ sys.stdout.isatty(): # the stdout is not a terminal, this for example happens if the # output is piped to less, e.g. "bin/test | less". In this case, # the terminal control sequences would be printed verbatim, so # don't use any colors. color = "" elif sys.platform == "win32": # Windows consoles don't support ANSI escape sequences color = "" elif not self._colors: color = "" if self._line_wrap: if text[0] != "\n": sys.stdout.write("\n") # Avoid UnicodeEncodeError when printing out test failures if PY3 and IS_WINDOWS: text = text.encode('raw_unicode_escape').decode('utf8', 'ignore') elif PY3 and not sys.stdout.encoding.lower().startswith('utf'): text = text.encode(sys.stdout.encoding, 'backslashreplace' ).decode(sys.stdout.encoding) if color == "": sys.stdout.write(text) else: sys.stdout.write("%s%s%s" % (c_color % colors[color], text, c_normal)) sys.stdout.flush() l = text.rfind("\n") if l == -1: self._write_pos += len(text) else: self._write_pos = len(text) - l - 1 self._line_wrap = self._write_pos >= width self._write_pos %= width def write_center(self, text, delim="="): width = self.terminal_width if text != "": text = " %s " % text idx = (width - len(text)) // 2 t = delim*idx + text + delim*(width - idx - len(text)) self.write(t + "\n") def write_exception(self, e, val, tb): # remove the first item, as that is always runtests.py tb = tb.tb_next t = traceback.format_exception(e, val, tb) self.write("".join(t)) def start(self, seed=None, msg="test process starts"): self.write_center(msg) executable = sys.executable v = tuple(sys.version_info) python_version = "%s.%s.%s-%s-%s" % v implementation = platform.python_implementation() if implementation == 'PyPy': implementation += " %s.%s.%s-%s-%s" % sys.pypy_version_info self.write("executable: %s (%s) [%s]\n" % (executable, python_version, implementation)) from sympy.utilities.misc import ARCH self.write("architecture: %s\n" % ARCH) from sympy.core.cache import USE_CACHE self.write("cache: %s\n" % USE_CACHE) from sympy.external.gmpy import GROUND_TYPES, HAS_GMPY version = '' if GROUND_TYPES =='gmpy': if HAS_GMPY == 1: import gmpy elif HAS_GMPY == 2: import gmpy2 as gmpy version = gmpy.version() self.write("ground types: %s %s\n" % (GROUND_TYPES, version)) numpy = import_module('numpy') self.write("numpy: %s\n" % (None if not numpy else numpy.__version__)) if seed is not None: self.write("random seed: %d\n" % seed) from sympy.utilities.misc import HASH_RANDOMIZATION self.write("hash randomization: ") hash_seed = os.getenv("PYTHONHASHSEED") or '0' if HASH_RANDOMIZATION and (hash_seed == "random" or int(hash_seed)): self.write("on (PYTHONHASHSEED=%s)\n" % hash_seed) else: self.write("off\n") if self._split: self.write("split: %s\n" % self._split) self.write('\n') self._t_start = clock() def finish(self): self._t_end = clock() self.write("\n") global text, linelen text = "tests finished: %d passed, " % self._passed linelen = len(text) def add_text(mytext): global text, linelen """Break new text if too long.""" if linelen + len(mytext) > self.terminal_width: text += '\n' linelen = 0 text += mytext linelen += len(mytext) if len(self._failed) > 0: add_text("%d failed, " % len(self._failed)) if len(self._failed_doctest) > 0: add_text("%d failed, " % len(self._failed_doctest)) if self._skipped > 0: add_text("%d skipped, " % self._skipped) if self._xfailed > 0: add_text("%d expected to fail, " % self._xfailed) if len(self._xpassed) > 0: add_text("%d expected to fail but passed, " % len(self._xpassed)) if len(self._exceptions) > 0: add_text("%d exceptions, " % len(self._exceptions)) add_text("in %.2f seconds" % (self._t_end - self._t_start)) if self.slow_test_functions: self.write_center('slowest tests', '_') sorted_slow = sorted(self.slow_test_functions, key=lambda r: r[1]) for slow_func_name, taken in sorted_slow: print('%s - Took %.3f seconds' % (slow_func_name, taken)) if self.fast_test_functions: self.write_center('unexpectedly fast tests', '_') sorted_fast = sorted(self.fast_test_functions, key=lambda r: r[1]) for fast_func_name, taken in sorted_fast: print('%s - Took %.3f seconds' % (fast_func_name, taken)) if len(self._xpassed) > 0: self.write_center("xpassed tests", "_") for e in self._xpassed: self.write("%s: %s\n" % (e[0], e[1])) self.write("\n") if self._tb_style != "no" and len(self._exceptions) > 0: for e in self._exceptions: filename, f, (t, val, tb) = e self.write_center("", "_") if f is None: s = "%s" % filename else: s = "%s:%s" % (filename, f.__name__) self.write_center(s, "_") self.write_exception(t, val, tb) self.write("\n") if self._tb_style != "no" and len(self._failed) > 0: for e in self._failed: filename, f, (t, val, tb) = e self.write_center("", "_") self.write_center("%s:%s" % (filename, f.__name__), "_") self.write_exception(t, val, tb) self.write("\n") if self._tb_style != "no" and len(self._failed_doctest) > 0: for e in self._failed_doctest: filename, msg = e self.write_center("", "_") self.write_center("%s" % filename, "_") self.write(msg) self.write("\n") self.write_center(text) ok = len(self._failed) == 0 and len(self._exceptions) == 0 and \ len(self._failed_doctest) == 0 if not ok: self.write("DO *NOT* COMMIT!\n") return ok def entering_filename(self, filename, n): rel_name = filename[len(self._root_dir) + 1:] self._active_file = rel_name self._active_file_error = False self.write(rel_name) self.write("[%d] " % n) def leaving_filename(self): self.write(" ") if self._active_file_error: self.write("[FAIL]", "Red", align="right") else: self.write("[OK]", "Green", align="right") self.write("\n") if self._verbose: self.write("\n") def entering_test(self, f): self._active_f = f if self._verbose: self.write("\n" + f.__name__ + " ") def test_xfail(self): self._xfailed += 1 self.write("f", "Green") def test_xpass(self, v): message = str(v) self._xpassed.append((self._active_file, message)) self.write("X", "Green") def test_fail(self, exc_info): self._failed.append((self._active_file, self._active_f, exc_info)) self.write("F", "Red") self._active_file_error = True def doctest_fail(self, name, error_msg): # the first line contains "******", remove it: error_msg = "\n".join(error_msg.split("\n")[1:]) self._failed_doctest.append((name, error_msg)) self.write("F", "Red") self._active_file_error = True def test_pass(self, char="."): self._passed += 1 if self._verbose: self.write("ok", "Green") else: self.write(char, "Green") def test_skip(self, v=None): char = "s" self._skipped += 1 if v is not None: message = str(v) if message == "KeyboardInterrupt": char = "K" elif message == "Timeout": char = "T" elif message == "Slow": char = "w" if self._verbose: if v is not None: self.write(message + ' ', "Blue") else: self.write(" - ", "Blue") self.write(char, "Blue") def test_exception(self, exc_info): self._exceptions.append((self._active_file, self._active_f, exc_info)) if exc_info[0] is TimeOutError: self.write("T", "Red") else: self.write("E", "Red") self._active_file_error = True def import_error(self, filename, exc_info): self._exceptions.append((filename, None, exc_info)) rel_name = filename[len(self._root_dir) + 1:] self.write(rel_name) self.write("[?] Failed to import", "Red") self.write(" ") self.write("[FAIL]", "Red", align="right") self.write("\n") sympy-sympy-1.9/sympy/testing/tests/000077500000000000000000000000001412543434000177235ustar00rootroot00000000000000sympy-sympy-1.9/sympy/testing/tests/__init__.py000066400000000000000000000000001412543434000220220ustar00rootroot00000000000000sympy-sympy-1.9/sympy/testing/tests/diagnose_imports.py000077500000000000000000000227331412543434000236550ustar00rootroot00000000000000#!/usr/bin/env python """ Import diagnostics. Run bin/diagnose_imports.py --help for details. """ from typing import Dict if __name__ == "__main__": import sys import inspect import builtins import optparse from os.path import abspath, dirname, join, normpath this_file = abspath(__file__) sympy_dir = join(dirname(this_file), '..', '..', '..') sympy_dir = normpath(sympy_dir) sys.path.insert(0, sympy_dir) option_parser = optparse.OptionParser( usage= "Usage: %prog option [options]\n" "\n" "Import analysis for imports between SymPy modules.") option_group = optparse.OptionGroup( option_parser, 'Analysis options', 'Options that define what to do. Exactly one of these must be given.') option_group.add_option( '--problems', help= 'Print all import problems, that is: ' 'If an import pulls in a package instead of a module ' '(e.g. sympy.core instead of sympy.core.add); ' # see ##PACKAGE## 'if it imports a symbol that is already present; ' # see ##DUPLICATE## 'if it imports a symbol ' 'from somewhere other than the defining module.', # see ##ORIGIN## action='count') option_group.add_option( '--origins', help= 'For each imported symbol in each module, ' 'print the module that defined it. ' '(This is useful for import refactoring.)', action='count') option_parser.add_option_group(option_group) option_group = optparse.OptionGroup( option_parser, 'Sort options', 'These options define the sort order for output lines. ' 'At most one of these options is allowed. ' 'Unsorted output will reflect the order in which imports happened.') option_group.add_option( '--by-importer', help='Sort output lines by name of importing module.', action='count') option_group.add_option( '--by-origin', help='Sort output lines by name of imported module.', action='count') option_parser.add_option_group(option_group) (options, args) = option_parser.parse_args() if args: option_parser.error( 'Unexpected arguments %s (try %s --help)' % (args, sys.argv[0])) if options.problems > 1: option_parser.error('--problems must not be given more than once.') if options.origins > 1: option_parser.error('--origins must not be given more than once.') if options.by_importer > 1: option_parser.error('--by-importer must not be given more than once.') if options.by_origin > 1: option_parser.error('--by-origin must not be given more than once.') options.problems = options.problems == 1 options.origins = options.origins == 1 options.by_importer = options.by_importer == 1 options.by_origin = options.by_origin == 1 if not options.problems and not options.origins: option_parser.error( 'At least one of --problems and --origins is required') if options.problems and options.origins: option_parser.error( 'At most one of --problems and --origins is allowed') if options.by_importer and options.by_origin: option_parser.error( 'At most one of --by-importer and --by-origin is allowed') options.by_process = not options.by_importer and not options.by_origin builtin_import = builtins.__import__ class Definition: """Information about a symbol's definition.""" def __init__(self, name, value, definer): self.name = name self.value = value self.definer = definer def __hash__(self): return hash(self.name) def __eq__(self, other): return self.name == other.name and self.value == other.value def __ne__(self, other): return not (self == other) def __repr__(self): return 'Definition(%s, ..., %s)' % ( repr(self.name), repr(self.definer)) # Maps each function/variable to name of module to define it symbol_definers = {} # type: Dict[Definition, str] def in_module(a, b): """Is a the same module as or a submodule of b?""" return a == b or a != None and b != None and a.startswith(b + '.') def relevant(module): """Is module relevant for import checking? Only imports between relevant modules will be checked.""" return in_module(module, 'sympy') sorted_messages = [] def msg(msg, *args): global options, sorted_messages if options.by_process: print(msg % args) else: sorted_messages.append(msg % args) def tracking_import(module, globals=globals(), locals=[], fromlist=None, level=-1): """__import__ wrapper - does not change imports at all, but tracks them. Default order is implemented by doing output directly. All other orders are implemented by collecting output information into a sorted list that will be emitted after all imports are processed. Indirect imports can only occur after the requested symbol has been imported directly (because the indirect import would not have a module to pick the symbol up from). So this code detects indirect imports by checking whether the symbol in question was already imported. Keeps the semantics of __import__ unchanged.""" global options, symbol_definers caller_frame = inspect.getframeinfo(sys._getframe(1)) importer_filename = caller_frame.filename importer_module = globals['__name__'] if importer_filename == caller_frame.filename: importer_reference = '%s line %s' % ( importer_filename, str(caller_frame.lineno)) else: importer_reference = importer_filename result = builtin_import(module, globals, locals, fromlist, level) importee_module = result.__name__ # We're only interested if importer and importee are in SymPy if relevant(importer_module) and relevant(importee_module): for symbol in result.__dict__.iterkeys(): definition = Definition( symbol, result.__dict__[symbol], importer_module) if not definition in symbol_definers: symbol_definers[definition] = importee_module if hasattr(result, '__path__'): ##PACKAGE## # The existence of __path__ is documented in the tutorial on modules. # Python 3.3 documents this in http://docs.python.org/3.3/reference/import.html if options.by_origin: msg('Error: %s (a package) is imported by %s', module, importer_reference) else: msg('Error: %s contains package import %s', importer_reference, module) if fromlist != None: symbol_list = fromlist if '*' in symbol_list: if (importer_filename.endswith('__init__.py') or importer_filename.endswith('__init__.pyc') or importer_filename.endswith('__init__.pyo')): # We do not check starred imports inside __init__ # That's the normal "please copy over its imports to my namespace" symbol_list = [] else: symbol_list = result.__dict__.iterkeys() for symbol in symbol_list: if not symbol in result.__dict__: if options.by_origin: msg('Error: %s.%s is not defined (yet), but %s tries to import it', importee_module, symbol, importer_reference) else: msg('Error: %s tries to import %s.%s, which did not define it (yet)', importer_reference, importee_module, symbol) else: definition = Definition( symbol, result.__dict__[symbol], importer_module) symbol_definer = symbol_definers[definition] if symbol_definer == importee_module: ##DUPLICATE## if options.by_origin: msg('Error: %s.%s is imported again into %s', importee_module, symbol, importer_reference) else: msg('Error: %s imports %s.%s again', importer_reference, importee_module, symbol) else: ##ORIGIN## if options.by_origin: msg('Error: %s.%s is imported by %s, which should import %s.%s instead', importee_module, symbol, importer_reference, symbol_definer, symbol) else: msg('Error: %s imports %s.%s but should import %s.%s instead', importer_reference, importee_module, symbol, symbol_definer, symbol) return result builtins.__import__ = tracking_import __import__('sympy') sorted_messages.sort() for message in sorted_messages: print(message) sympy-sympy-1.9/sympy/testing/tests/test_code_quality.py000066400000000000000000000442371412543434000240300ustar00rootroot00000000000000# coding=utf-8 from os import walk, sep, pardir from os.path import split, join, abspath, exists, isfile from glob import glob import re import random import ast from sympy.testing.pytest import raises from sympy.testing.quality_unicode import _test_this_file_encoding # System path separator (usually slash or backslash) to be # used with excluded files, e.g. # exclude = set([ # "%(sep)smpmath%(sep)s" % sepd, # ]) sepd = {"sep": sep} # path and sympy_path SYMPY_PATH = abspath(join(split(__file__)[0], pardir, pardir)) # go to sympy/ assert exists(SYMPY_PATH) TOP_PATH = abspath(join(SYMPY_PATH, pardir)) BIN_PATH = join(TOP_PATH, "bin") EXAMPLES_PATH = join(TOP_PATH, "examples") # Error messages message_space = "File contains trailing whitespace: %s, line %s." message_implicit = "File contains an implicit import: %s, line %s." message_tabs = "File contains tabs instead of spaces: %s, line %s." message_carriage = "File contains carriage returns at end of line: %s, line %s" message_str_raise = "File contains string exception: %s, line %s" message_gen_raise = "File contains generic exception: %s, line %s" message_old_raise = "File contains old-style raise statement: %s, line %s, \"%s\"" message_eof = "File does not end with a newline: %s, line %s" message_multi_eof = "File ends with more than 1 newline: %s, line %s" message_test_suite_def = "Function should start with 'test_' or '_': %s, line %s" message_duplicate_test = "This is a duplicate test function: %s, line %s" message_self_assignments = "File contains assignments to self/cls: %s, line %s." message_func_is = "File contains '.func is': %s, line %s." implicit_test_re = re.compile(r'^\s*(>>> )?(\.\.\. )?from .* import .*\*') str_raise_re = re.compile( r'^\s*(>>> )?(\.\.\. )?raise(\s+(\'|\")|\s*(\(\s*)+(\'|\"))') gen_raise_re = re.compile( r'^\s*(>>> )?(\.\.\. )?raise(\s+Exception|\s*(\(\s*)+Exception)') old_raise_re = re.compile(r'^\s*(>>> )?(\.\.\. )?raise((\s*\(\s*)|\s+)\w+\s*,') test_suite_def_re = re.compile(r'^def\s+(?!(_|test))[^(]*\(\s*\)\s*:$') test_ok_def_re = re.compile(r'^def\s+test_.*:$') test_file_re = re.compile(r'.*[/\\]test_.*\.py$') func_is_re = re.compile(r'\.\s*func\s+is') def tab_in_leading(s): """Returns True if there are tabs in the leading whitespace of a line, including the whitespace of docstring code samples.""" n = len(s) - len(s.lstrip()) if not s[n:n + 3] in ['...', '>>>']: check = s[:n] else: smore = s[n + 3:] check = s[:n] + smore[:len(smore) - len(smore.lstrip())] return not (check.expandtabs() == check) def find_self_assignments(s): """Returns a list of "bad" assignments: if there are instances of assigning to the first argument of the class method (except for staticmethod's). """ t = [n for n in ast.parse(s).body if isinstance(n, ast.ClassDef)] bad = [] for c in t: for n in c.body: if not isinstance(n, ast.FunctionDef): continue if any(d.id == 'staticmethod' for d in n.decorator_list if isinstance(d, ast.Name)): continue if n.name == '__new__': continue if not n.args.args: continue first_arg = n.args.args[0].arg for m in ast.walk(n): if isinstance(m, ast.Assign): for a in m.targets: if isinstance(a, ast.Name) and a.id == first_arg: bad.append(m) elif (isinstance(a, ast.Tuple) and any(q.id == first_arg for q in a.elts if isinstance(q, ast.Name))): bad.append(m) return bad def check_directory_tree(base_path, file_check, exclusions=set(), pattern="*.py"): """ Checks all files in the directory tree (with base_path as starting point) with the file_check function provided, skipping files that contain any of the strings in the set provided by exclusions. """ if not base_path: return for root, dirs, files in walk(base_path): check_files(glob(join(root, pattern)), file_check, exclusions) def check_files(files, file_check, exclusions=set(), pattern=None): """ Checks all files with the file_check function provided, skipping files that contain any of the strings in the set provided by exclusions. """ if not files: return for fname in files: if not exists(fname) or not isfile(fname): continue if any(ex in fname for ex in exclusions): continue if pattern is None or re.match(pattern, fname): file_check(fname) def test_files(): """ This test tests all files in sympy and checks that: o no lines contains a trailing whitespace o no lines end with \r\n o no line uses tabs instead of spaces o that the file ends with a single newline o there are no general or string exceptions o there are no old style raise statements o name of arg-less test suite functions start with _ or test_ o no duplicate function names that start with test_ o no assignments to self variable in class methods o no lines contain ".func is" except in the test suite """ def test(fname): with open(fname, encoding="utf8") as test_file: test_this_file(fname, test_file) with open(fname, encoding='utf8') as test_file: _test_this_file_encoding(fname, test_file) def test_this_file(fname, test_file): line = None # to flag the case where there were no lines in file tests = 0 test_set = set() for idx, line in enumerate(test_file): if test_file_re.match(fname): if test_suite_def_re.match(line): assert False, message_test_suite_def % (fname, idx + 1) if test_ok_def_re.match(line): tests += 1 test_set.add(line[3:].split('(')[0].strip()) if len(test_set) != tests: assert False, message_duplicate_test % (fname, idx + 1) if line.endswith(" \n") or line.endswith("\t\n"): assert False, message_space % (fname, idx + 1) if line.endswith("\r\n"): assert False, message_carriage % (fname, idx + 1) if tab_in_leading(line): assert False, message_tabs % (fname, idx + 1) if str_raise_re.search(line): assert False, message_str_raise % (fname, idx + 1) if gen_raise_re.search(line): assert False, message_gen_raise % (fname, idx + 1) if (implicit_test_re.search(line) and not list(filter(lambda ex: ex in fname, import_exclude))): assert False, message_implicit % (fname, idx + 1) if func_is_re.search(line) and not test_file_re.search(fname): assert False, message_func_is % (fname, idx + 1) result = old_raise_re.search(line) if result is not None: assert False, message_old_raise % ( fname, idx + 1, result.group(2)) if line is not None: if line == '\n' and idx > 0: assert False, message_multi_eof % (fname, idx + 1) elif not line.endswith('\n'): # eof newline check assert False, message_eof % (fname, idx + 1) # Files to test at top level top_level_files = [join(TOP_PATH, file) for file in [ "isympy.py", "build.py", "setup.py", "setupegg.py", ]] # Files to exclude from all tests exclude = { "%(sep)ssympy%(sep)sparsing%(sep)sautolev%(sep)s_antlr%(sep)sautolevparser.py" % sepd, "%(sep)ssympy%(sep)sparsing%(sep)sautolev%(sep)s_antlr%(sep)sautolevlexer.py" % sepd, "%(sep)ssympy%(sep)sparsing%(sep)sautolev%(sep)s_antlr%(sep)sautolevlistener.py" % sepd, "%(sep)ssympy%(sep)sparsing%(sep)slatex%(sep)s_antlr%(sep)slatexparser.py" % sepd, "%(sep)ssympy%(sep)sparsing%(sep)slatex%(sep)s_antlr%(sep)slatexlexer.py" % sepd, } # Files to exclude from the implicit import test import_exclude = { # glob imports are allowed in top-level __init__.py: "%(sep)ssympy%(sep)s__init__.py" % sepd, # these __init__.py should be fixed: # XXX: not really, they use useful import pattern (DRY) "%(sep)svector%(sep)s__init__.py" % sepd, "%(sep)smechanics%(sep)s__init__.py" % sepd, "%(sep)squantum%(sep)s__init__.py" % sepd, "%(sep)spolys%(sep)s__init__.py" % sepd, "%(sep)spolys%(sep)sdomains%(sep)s__init__.py" % sepd, # interactive sympy executes ``from sympy import *``: "%(sep)sinteractive%(sep)ssession.py" % sepd, # isympy.py executes ``from sympy import *``: "%(sep)sisympy.py" % sepd, # these two are import timing tests: "%(sep)sbin%(sep)ssympy_time.py" % sepd, "%(sep)sbin%(sep)ssympy_time_cache.py" % sepd, # Taken from Python stdlib: "%(sep)sparsing%(sep)ssympy_tokenize.py" % sepd, # this one should be fixed: "%(sep)splotting%(sep)spygletplot%(sep)s" % sepd, # False positive in the docstring "%(sep)sbin%(sep)stest_external_imports.py" % sepd, "%(sep)sbin%(sep)stest_submodule_imports.py" % sepd, # These are deprecated stubs that can be removed at some point: "%(sep)sutilities%(sep)sruntests.py" % sepd, "%(sep)sutilities%(sep)spytest.py" % sepd, "%(sep)sutilities%(sep)srandtest.py" % sepd, "%(sep)sutilities%(sep)stmpfiles.py" % sepd, "%(sep)sutilities%(sep)squality_unicode.py" % sepd, "%(sep)sutilities%(sep)sbenchmarking.py" % sepd, } check_files(top_level_files, test) check_directory_tree(BIN_PATH, test, {"~", ".pyc", ".sh"}, "*") check_directory_tree(SYMPY_PATH, test, exclude) check_directory_tree(EXAMPLES_PATH, test, exclude) def _with_space(c): # return c with a random amount of leading space return random.randint(0, 10)*' ' + c def test_raise_statement_regular_expression(): candidates_ok = [ "some text # raise Exception, 'text'", "raise ValueError('text') # raise Exception, 'text'", "raise ValueError('text')", "raise ValueError", "raise ValueError('text')", "raise ValueError('text') #,", # Talking about an exception in a docstring ''''"""This function will raise ValueError, except when it doesn't"""''', "raise (ValueError('text')", ] str_candidates_fail = [ "raise 'exception'", "raise 'Exception'", 'raise "exception"', 'raise "Exception"', "raise 'ValueError'", ] gen_candidates_fail = [ "raise Exception('text') # raise Exception, 'text'", "raise Exception('text')", "raise Exception", "raise Exception('text')", "raise Exception('text') #,", "raise Exception, 'text'", "raise Exception, 'text' # raise Exception('text')", "raise Exception, 'text' # raise Exception, 'text'", ">>> raise Exception, 'text'", ">>> raise Exception, 'text' # raise Exception('text')", ">>> raise Exception, 'text' # raise Exception, 'text'", ] old_candidates_fail = [ "raise Exception, 'text'", "raise Exception, 'text' # raise Exception('text')", "raise Exception, 'text' # raise Exception, 'text'", ">>> raise Exception, 'text'", ">>> raise Exception, 'text' # raise Exception('text')", ">>> raise Exception, 'text' # raise Exception, 'text'", "raise ValueError, 'text'", "raise ValueError, 'text' # raise Exception('text')", "raise ValueError, 'text' # raise Exception, 'text'", ">>> raise ValueError, 'text'", ">>> raise ValueError, 'text' # raise Exception('text')", ">>> raise ValueError, 'text' # raise Exception, 'text'", "raise(ValueError,", "raise (ValueError,", "raise( ValueError,", "raise ( ValueError,", "raise(ValueError ,", "raise (ValueError ,", "raise( ValueError ,", "raise ( ValueError ,", ] for c in candidates_ok: assert str_raise_re.search(_with_space(c)) is None, c assert gen_raise_re.search(_with_space(c)) is None, c assert old_raise_re.search(_with_space(c)) is None, c for c in str_candidates_fail: assert str_raise_re.search(_with_space(c)) is not None, c for c in gen_candidates_fail: assert gen_raise_re.search(_with_space(c)) is not None, c for c in old_candidates_fail: assert old_raise_re.search(_with_space(c)) is not None, c def test_implicit_imports_regular_expression(): candidates_ok = [ "from sympy import something", ">>> from sympy import something", "from sympy.somewhere import something", ">>> from sympy.somewhere import something", "import sympy", ">>> import sympy", "import sympy.something.something", "... import sympy", "... import sympy.something.something", "... from sympy import something", "... from sympy.somewhere import something", ">> from sympy import *", # To allow 'fake' docstrings "# from sympy import *", "some text # from sympy import *", ] candidates_fail = [ "from sympy import *", ">>> from sympy import *", "from sympy.somewhere import *", ">>> from sympy.somewhere import *", "... from sympy import *", "... from sympy.somewhere import *", ] for c in candidates_ok: assert implicit_test_re.search(_with_space(c)) is None, c for c in candidates_fail: assert implicit_test_re.search(_with_space(c)) is not None, c def test_test_suite_defs(): candidates_ok = [ " def foo():\n", "def foo(arg):\n", "def _foo():\n", "def test_foo():\n", ] candidates_fail = [ "def foo():\n", "def foo() :\n", "def foo( ):\n", "def foo():\n", ] for c in candidates_ok: assert test_suite_def_re.search(c) is None, c for c in candidates_fail: assert test_suite_def_re.search(c) is not None, c def test_test_duplicate_defs(): candidates_ok = [ "def foo():\ndef foo():\n", "def test():\ndef test_():\n", "def test_():\ndef test__():\n", ] candidates_fail = [ "def test_():\ndef test_ ():\n", "def test_1():\ndef test_1():\n", ] ok = (None, 'check') def check(file): tests = 0 test_set = set() for idx, line in enumerate(file.splitlines()): if test_ok_def_re.match(line): tests += 1 test_set.add(line[3:].split('(')[0].strip()) if len(test_set) != tests: return False, message_duplicate_test % ('check', idx + 1) return None, 'check' for c in candidates_ok: assert check(c) == ok for c in candidates_fail: assert check(c) != ok def test_find_self_assignments(): candidates_ok = [ "class A(object):\n def foo(self, arg): arg = self\n", "class A(object):\n def foo(self, arg): self.prop = arg\n", "class A(object):\n def foo(self, arg): obj, obj2 = arg, self\n", "class A(object):\n @classmethod\n def bar(cls, arg): arg = cls\n", "class A(object):\n def foo(var, arg): arg = var\n", ] candidates_fail = [ "class A(object):\n def foo(self, arg): self = arg\n", "class A(object):\n def foo(self, arg): obj, self = arg, arg\n", "class A(object):\n def foo(self, arg):\n if arg: self = arg", "class A(object):\n @classmethod\n def foo(cls, arg): cls = arg\n", "class A(object):\n def foo(var, arg): var = arg\n", ] for c in candidates_ok: assert find_self_assignments(c) == [] for c in candidates_fail: assert find_self_assignments(c) != [] def test_test_unicode_encoding(): unicode_whitelist = ['foo'] unicode_strict_whitelist = ['bar'] fname = 'abc' test_file = ['α'] raises(AssertionError, lambda: _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist)) fname = 'abc' test_file = ['# coding=utf-8', 'α'] raises(AssertionError, lambda: _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist)) fname = 'abc' test_file = ['# coding=utf-8', 'abc'] raises(AssertionError, lambda: _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist)) fname = 'abc' test_file = ['abc'] _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist) fname = 'foo' test_file = ['α'] raises(AssertionError, lambda: _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist)) fname = 'foo' test_file = ['# coding=utf-8', 'α'] _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist) fname = 'foo' test_file = ['# coding=utf-8', 'abc'] raises(AssertionError, lambda: _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist)) fname = 'foo' test_file = ['abc'] raises(AssertionError, lambda: _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist)) fname = 'bar' test_file = ['α'] raises(AssertionError, lambda: _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist)) fname = 'bar' test_file = ['# coding=utf-8', 'α'] _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist) fname = 'bar' test_file = ['# coding=utf-8', 'abc'] _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist) fname = 'bar' test_file = ['abc'] _test_this_file_encoding( fname, test_file, unicode_whitelist, unicode_strict_whitelist) sympy-sympy-1.9/sympy/testing/tests/test_module_imports.py000066400000000000000000000026631412543434000244050ustar00rootroot00000000000000""" Checks that SymPy does not contain indirect imports. An indirect import is importing a symbol from a module that itself imported the symbol from elsewhere. Such a constellation makes it harder to diagnose inter-module dependencies and import order problems, and is therefore strongly discouraged. (Indirect imports from end-user code is fine and in fact a best practice.) Implementation note: Forcing Python into actually unloading already-imported submodules is a tricky and partly undocumented process. To avoid these issues, the actual diagnostic code is in bin/diagnose_imports, which is run as a separate, pristine Python process. """ import subprocess import sys from os.path import abspath, dirname, join, normpath import inspect from sympy.testing.pytest import XFAIL @XFAIL def test_module_imports_are_direct(): my_filename = abspath(inspect.getfile(inspect.currentframe())) my_dirname = dirname(my_filename) diagnose_imports_filename = join(my_dirname, 'diagnose_imports.py') diagnose_imports_filename = normpath(diagnose_imports_filename) process = subprocess.Popen( [ sys.executable, normpath(diagnose_imports_filename), '--problems', '--by-importer' ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, bufsize=-1) output, _ = process.communicate() assert output == '', "There are import problems:\n" + output.decode() sympy-sympy-1.9/sympy/testing/tests/test_pytest.py000066400000000000000000000171111412543434000226650ustar00rootroot00000000000000import warnings from sympy.testing.pytest import (raises, warns, ignore_warnings, warns_deprecated_sympy, Failed) from sympy.utilities.exceptions import SymPyDeprecationWarning # Test callables def test_expected_exception_is_silent_callable(): def f(): raise ValueError() raises(ValueError, f) # Under pytest raises will raise Failed rather than AssertionError def test_lack_of_exception_triggers_AssertionError_callable(): try: raises(Exception, lambda: 1 + 1) assert False except Failed as e: assert "DID NOT RAISE" in str(e) def test_unexpected_exception_is_passed_through_callable(): def f(): raise ValueError("some error message") try: raises(TypeError, f) assert False except ValueError as e: assert str(e) == "some error message" # Test with statement def test_expected_exception_is_silent_with(): with raises(ValueError): raise ValueError() def test_lack_of_exception_triggers_AssertionError_with(): try: with raises(Exception): 1 + 1 assert False except Failed as e: assert "DID NOT RAISE" in str(e) def test_unexpected_exception_is_passed_through_with(): try: with raises(TypeError): raise ValueError("some error message") assert False except ValueError as e: assert str(e) == "some error message" # Now we can use raises() instead of try/catch # to test that a specific exception class is raised def test_second_argument_should_be_callable_or_string(): raises(TypeError, lambda: raises("irrelevant", 42)) def test_warns_catches_warning(): with warnings.catch_warnings(record=True) as w: with warns(UserWarning): warnings.warn('this is the warning message') assert len(w) == 0 def test_warns_raises_without_warning(): with raises(Failed): with warns(UserWarning): pass def test_warns_hides_other_warnings(): # This isn't ideal but it's what pytest's warns does: with warnings.catch_warnings(record=True) as w: with warns(UserWarning): warnings.warn('this is the warning message', UserWarning) warnings.warn('this is the other message', RuntimeWarning) assert len(w) == 0 def test_warns_continues_after_warning(): with warnings.catch_warnings(record=True) as w: finished = False with warns(UserWarning): warnings.warn('this is the warning message') finished = True assert finished assert len(w) == 0 def test_warns_many_warnings(): # This isn't ideal but it's what pytest's warns does: with warnings.catch_warnings(record=True) as w: finished = False with warns(UserWarning): warnings.warn('this is the warning message', UserWarning) warnings.warn('this is the other message', RuntimeWarning) warnings.warn('this is the warning message', UserWarning) warnings.warn('this is the other message', RuntimeWarning) warnings.warn('this is the other message', RuntimeWarning) finished = True assert finished assert len(w) == 0 def test_warns_match_matching(): with warnings.catch_warnings(record=True) as w: with warns(UserWarning, match='this is the warning message'): warnings.warn('this is the warning message', UserWarning) assert len(w) == 0 def test_warns_match_non_matching(): with warnings.catch_warnings(record=True) as w: with raises(Failed): with warns(UserWarning, match='this is the warning message'): warnings.warn('this is not the expected warning message', UserWarning) assert len(w) == 0 def _warn_sympy_deprecation(): SymPyDeprecationWarning( feature="foo", useinstead="bar", issue=1, deprecated_since_version="0.0.0").warn() def test_warns_deprecated_sympy_catches_warning(): with warnings.catch_warnings(record=True) as w: with warns_deprecated_sympy(): _warn_sympy_deprecation() assert len(w) == 0 def test_warns_deprecated_sympy_raises_without_warning(): with raises(Failed): with warns_deprecated_sympy(): pass def test_warns_deprecated_sympy_hides_other_warnings(): # This isn't ideal but it's what pytest's deprecated_call does: with warnings.catch_warnings(record=True) as w: with warns_deprecated_sympy(): _warn_sympy_deprecation() warnings.warn('this is the other message', RuntimeWarning) assert len(w) == 0 def test_warns_deprecated_sympy_continues_after_warning(): with warnings.catch_warnings(record=True) as w: finished = False with warns_deprecated_sympy(): _warn_sympy_deprecation() finished = True assert finished assert len(w) == 0 def test_warns_deprecated_sympy_many_warnings(): # This isn't ideal but it's what pytest's warns_deprecated_sympy does: with warnings.catch_warnings(record=True) as w: finished = False with warns_deprecated_sympy(): _warn_sympy_deprecation() warnings.warn('this is the other message', RuntimeWarning) _warn_sympy_deprecation() warnings.warn('this is the other message', RuntimeWarning) warnings.warn('this is the other message', RuntimeWarning) finished = True assert finished assert len(w) == 0 def test_ignore_ignores_warning(): with warnings.catch_warnings(record=True) as w: with ignore_warnings(UserWarning): warnings.warn('this is the warning message') assert len(w) == 0 def test_ignore_does_not_raise_without_warning(): with warnings.catch_warnings(record=True) as w: with ignore_warnings(UserWarning): pass assert len(w) == 0 def test_ignore_allows_other_warnings(): with warnings.catch_warnings(record=True) as w: # This is needed when pytest is run as -Werror # the setting is reverted at the end of the catch_Warnings block. warnings.simplefilter("always") with ignore_warnings(UserWarning): warnings.warn('this is the warning message', UserWarning) warnings.warn('this is the other message', RuntimeWarning) assert len(w) == 1 assert isinstance(w[0].message, RuntimeWarning) assert str(w[0].message) == 'this is the other message' def test_ignore_continues_after_warning(): with warnings.catch_warnings(record=True) as w: finished = False with ignore_warnings(UserWarning): warnings.warn('this is the warning message') finished = True assert finished assert len(w) == 0 def test_ignore_many_warnings(): with warnings.catch_warnings(record=True) as w: # This is needed when pytest is run as -Werror # the setting is reverted at the end of the catch_Warnings block. warnings.simplefilter("always") with ignore_warnings(UserWarning): warnings.warn('this is the warning message', UserWarning) warnings.warn('this is the other message', RuntimeWarning) warnings.warn('this is the warning message', UserWarning) warnings.warn('this is the other message', RuntimeWarning) warnings.warn('this is the other message', RuntimeWarning) assert len(w) == 3 for wi in w: assert isinstance(wi.message, RuntimeWarning) assert str(wi.message) == 'this is the other message' sympy-sympy-1.9/sympy/testing/tmpfiles.py000066400000000000000000000020221412543434000207520ustar00rootroot00000000000000""" This module adds context manager for temporary files generated by the tests. """ import shutil import os class TmpFileManager: """ A class to track record of every temporary files created by the tests. """ tmp_files = set('') tmp_folders = set('') @classmethod def tmp_file(cls, name=''): cls.tmp_files.add(name) return name @classmethod def tmp_folder(cls, name=''): cls.tmp_folders.add(name) return name @classmethod def cleanup(cls): while cls.tmp_files: file = cls.tmp_files.pop() if os.path.isfile(file): os.remove(file) while cls.tmp_folders: folder = cls.tmp_folders.pop() shutil.rmtree(folder) def cleanup_tmp_files(test_func): """ A decorator to help test codes remove temporary files after the tests. """ def wrapper_function(): try: test_func() finally: TmpFileManager.cleanup() return wrapper_function sympy-sympy-1.9/sympy/this.py000066400000000000000000000010461412543434000164260ustar00rootroot00000000000000""" The Zen of SymPy. """ s = """The Zen of SymPy Unevaluated is better than evaluated. The user interface matters. Printing matters. Pure Python can be fast enough. If it's too slow, it's (probably) your fault. Documentation matters. Correctness is more important than speed. Push it in now and improve upon it later. Coverage by testing matters. Smart tests are better than random tests. But random tests sometimes find what your smartest test missed. The Python way is probably the right way. Community is more important than code.""" print(s) sympy-sympy-1.9/sympy/unify/000077500000000000000000000000001412543434000162365ustar00rootroot00000000000000sympy-sympy-1.9/sympy/unify/__init__.py000066400000000000000000000004451412543434000203520ustar00rootroot00000000000000""" Unification in SymPy See sympy.unify.core docstring for algorithmic details See http://matthewrocklin.com/blog/work/2012/11/01/Unification/ for discussion """ from .usympy import unify, rebuild from .rewrite import rewriterule __all__ = [ 'unify', 'rebuild', 'rewriterule', ] sympy-sympy-1.9/sympy/unify/core.py000066400000000000000000000155751412543434000175550ustar00rootroot00000000000000""" Generic Unification algorithm for expression trees with lists of children This implementation is a direct translation of Artificial Intelligence: A Modern Approach by Stuart Russel and Peter Norvig Second edition, section 9.2, page 276 It is modified in the following ways: 1. We allow associative and commutative Compound expressions. This results in combinatorial blowup. 2. We explore the tree lazily. 3. We provide generic interfaces to symbolic algebra libraries in Python. A more traditional version can be found here http://aima.cs.berkeley.edu/python/logic.html """ from sympy.utilities.iterables import kbins class Compound: """ A little class to represent an interior node in the tree This is analogous to SymPy.Basic for non-Atoms """ def __init__(self, op, args): self.op = op self.args = args def __eq__(self, other): return (type(self) == type(other) and self.op == other.op and self.args == other.args) def __hash__(self): return hash((type(self), self.op, self.args)) def __str__(self): return "%s[%s]" % (str(self.op), ', '.join(map(str, self.args))) class Variable: """ A Wild token """ def __init__(self, arg): self.arg = arg def __eq__(self, other): return type(self) == type(other) and self.arg == other.arg def __hash__(self): return hash((type(self), self.arg)) def __str__(self): return "Variable(%s)" % str(self.arg) class CondVariable: """ A wild token that matches conditionally. arg - a wild token. valid - an additional constraining function on a match. """ def __init__(self, arg, valid): self.arg = arg self.valid = valid def __eq__(self, other): return (type(self) == type(other) and self.arg == other.arg and self.valid == other.valid) def __hash__(self): return hash((type(self), self.arg, self.valid)) def __str__(self): return "CondVariable(%s)" % str(self.arg) def unify(x, y, s=None, **fns): """ Unify two expressions. Parameters ========== x, y - expression trees containing leaves, Compounds and Variables. s - a mapping of variables to subtrees. Returns ======= lazy sequence of mappings {Variable: subtree} Examples ======== >>> from sympy.unify.core import unify, Compound, Variable >>> expr = Compound("Add", ("x", "y")) >>> pattern = Compound("Add", ("x", Variable("a"))) >>> next(unify(expr, pattern, {})) {Variable(a): 'y'} """ s = s or {} if x == y: yield s elif isinstance(x, (Variable, CondVariable)): yield from unify_var(x, y, s, **fns) elif isinstance(y, (Variable, CondVariable)): yield from unify_var(y, x, s, **fns) elif isinstance(x, Compound) and isinstance(y, Compound): is_commutative = fns.get('is_commutative', lambda x: False) is_associative = fns.get('is_associative', lambda x: False) for sop in unify(x.op, y.op, s, **fns): if is_associative(x) and is_associative(y): a, b = (x, y) if len(x.args) < len(y.args) else (y, x) if is_commutative(x) and is_commutative(y): combs = allcombinations(a.args, b.args, 'commutative') else: combs = allcombinations(a.args, b.args, 'associative') for aaargs, bbargs in combs: aa = [unpack(Compound(a.op, arg)) for arg in aaargs] bb = [unpack(Compound(b.op, arg)) for arg in bbargs] yield from unify(aa, bb, sop, **fns) elif len(x.args) == len(y.args): yield from unify(x.args, y.args, sop, **fns) elif is_args(x) and is_args(y) and len(x) == len(y): if len(x) == 0: yield s else: for shead in unify(x[0], y[0], s, **fns): yield from unify(x[1:], y[1:], shead, **fns) def unify_var(var, x, s, **fns): if var in s: yield from unify(s[var], x, s, **fns) elif occur_check(var, x): pass elif isinstance(var, CondVariable) and var.valid(x): yield assoc(s, var, x) elif isinstance(var, Variable): yield assoc(s, var, x) def occur_check(var, x): """ var occurs in subtree owned by x? """ if var == x: return True elif isinstance(x, Compound): return occur_check(var, x.args) elif is_args(x): if any(occur_check(var, xi) for xi in x): return True return False def assoc(d, key, val): """ Return copy of d with key associated to val """ d = d.copy() d[key] = val return d def is_args(x): """ Is x a traditional iterable? """ return type(x) in (tuple, list, set) def unpack(x): if isinstance(x, Compound) and len(x.args) == 1: return x.args[0] else: return x def allcombinations(A, B, ordered): """ Restructure A and B to have the same number of elements. Parameters ========== ordered must be either 'commutative' or 'associative'. A and B can be rearranged so that the larger of the two lists is reorganized into smaller sublists. Examples ======== >>> from sympy.unify.core import allcombinations >>> for x in allcombinations((1, 2, 3), (5, 6), 'associative'): print(x) (((1,), (2, 3)), ((5,), (6,))) (((1, 2), (3,)), ((5,), (6,))) >>> for x in allcombinations((1, 2, 3), (5, 6), 'commutative'): print(x) (((1,), (2, 3)), ((5,), (6,))) (((1, 2), (3,)), ((5,), (6,))) (((1,), (3, 2)), ((5,), (6,))) (((1, 3), (2,)), ((5,), (6,))) (((2,), (1, 3)), ((5,), (6,))) (((2, 1), (3,)), ((5,), (6,))) (((2,), (3, 1)), ((5,), (6,))) (((2, 3), (1,)), ((5,), (6,))) (((3,), (1, 2)), ((5,), (6,))) (((3, 1), (2,)), ((5,), (6,))) (((3,), (2, 1)), ((5,), (6,))) (((3, 2), (1,)), ((5,), (6,))) """ if ordered == "commutative": ordered = 11 if ordered == "associative": ordered = None sm, bg = (A, B) if len(A) < len(B) else (B, A) for part in kbins(list(range(len(bg))), len(sm), ordered=ordered): if bg == B: yield tuple((a,) for a in A), partition(B, part) else: yield partition(A, part), tuple((b,) for b in B) def partition(it, part): """ Partition a tuple/list into pieces defined by indices. Examples ======== >>> from sympy.unify.core import partition >>> partition((10, 20, 30, 40), [[0, 1, 2], [3]]) ((10, 20, 30), (40,)) """ return type(it)([index(it, ind) for ind in part]) def index(it, ind): """ Fancy indexing into an indexable iterable (tuple, list). Examples ======== >>> from sympy.unify.core import index >>> index([10, 20, 30], (1, 2, 0)) [20, 30, 10] """ return type(it)([it[i] for i in ind]) sympy-sympy-1.9/sympy/unify/rewrite.py000066400000000000000000000034061412543434000202740ustar00rootroot00000000000000""" Functions to support rewriting of SymPy expressions """ from sympy import Expr from sympy.assumptions import ask from sympy.strategies.tools import subs from sympy.unify.usympy import rebuild, unify def rewriterule(source, target, variables=(), condition=None, assume=None): """ Rewrite rule. Transform expressions that match source into expressions that match target treating all ``variables`` as wilds. Examples ======== >>> from sympy.abc import w, x, y, z >>> from sympy.unify.rewrite import rewriterule >>> from sympy.utilities import default_sort_key >>> rl = rewriterule(x + y, x**y, [x, y]) >>> sorted(rl(z + 3), key=default_sort_key) [3**z, z**3] Use ``condition`` to specify additional requirements. Inputs are taken in the same order as is found in variables. >>> rl = rewriterule(x + y, x**y, [x, y], lambda x, y: x.is_integer) >>> list(rl(z + 3)) [3**z] Use ``assume`` to specify additional requirements using new assumptions. >>> from sympy.assumptions import Q >>> rl = rewriterule(x + y, x**y, [x, y], assume=Q.integer(x)) >>> list(rl(z + 3)) [3**z] Assumptions for the local context are provided at rule runtime >>> list(rl(w + z, Q.integer(z))) [z**w] """ def rewrite_rl(expr, assumptions=True): for match in unify(source, expr, {}, variables=variables): if (condition and not condition(*[match.get(var, var) for var in variables])): continue if (assume and not ask(assume.xreplace(match), assumptions)): continue expr2 = subs(match)(target) if isinstance(expr2, Expr): expr2 = rebuild(expr2) yield expr2 return rewrite_rl sympy-sympy-1.9/sympy/unify/tests/000077500000000000000000000000001412543434000174005ustar00rootroot00000000000000sympy-sympy-1.9/sympy/unify/tests/__init__.py000066400000000000000000000000001412543434000214770ustar00rootroot00000000000000sympy-sympy-1.9/sympy/unify/tests/test_rewrite.py000066400000000000000000000034621412543434000224770ustar00rootroot00000000000000from sympy.unify.rewrite import rewriterule from sympy import sin, Basic, Symbol, S from sympy.abc import x, y from sympy.strategies.rl import rebuild from sympy.assumptions import Q p, q = Symbol('p'), Symbol('q') def test_simple(): rl = rewriterule(Basic(p, 1), Basic(p, 2), variables=(p,)) assert list(rl(Basic(3, 1))) == [Basic(3, 2)] p1 = p**2 p2 = p**3 rl = rewriterule(p1, p2, variables=(p,)) expr = x**2 assert list(rl(expr)) == [x**3] def test_simple_variables(): rl = rewriterule(Basic(x, 1), Basic(x, 2), variables=(x,)) assert list(rl(Basic(3, 1))) == [Basic(3, 2)] rl = rewriterule(x**2, x**3, variables=(x,)) assert list(rl(y**2)) == [y**3] def test_moderate(): p1 = p**2 + q**3 p2 = (p*q)**4 rl = rewriterule(p1, p2, (p, q)) expr = x**2 + y**3 assert list(rl(expr)) == [(x*y)**4] def test_sincos(): p1 = sin(p)**2 + sin(p)**2 p2 = 1 rl = rewriterule(p1, p2, (p, q)) assert list(rl(sin(x)**2 + sin(x)**2)) == [1] assert list(rl(sin(y)**2 + sin(y)**2)) == [1] def test_Exprs_ok(): rl = rewriterule(p+q, q+p, (p, q)) next(rl(x+y)).is_commutative str(next(rl(x+y))) def test_condition_simple(): rl = rewriterule(x, x+1, [x], lambda x: x < 10) assert not list(rl(S(15))) assert rebuild(next(rl(S(5)))) == 6 def test_condition_multiple(): rl = rewriterule(x + y, x**y, [x,y], lambda x, y: x.is_integer) a = Symbol('a') b = Symbol('b', integer=True) expr = a + b assert list(rl(expr)) == [b**a] c = Symbol('c', integer=True) d = Symbol('d', integer=True) assert set(rl(c + d)) == {c**d, d**c} def test_assumptions(): rl = rewriterule(x + y, x**y, [x, y], assume=Q.integer(x)) a, b = map(Symbol, 'ab') expr = a + b assert list(rl(expr, Q.integer(b))) == [b**a] sympy-sympy-1.9/sympy/unify/tests/test_sympy.py000066400000000000000000000126711412543434000222010ustar00rootroot00000000000000from sympy import Add, Basic, symbols, Symbol, And, S from sympy.core.symbol import Str from sympy.unify.core import Compound, Variable from sympy.unify.usympy import (deconstruct, construct, unify, is_associative, is_commutative) from sympy.abc import x, y, z, n def test_deconstruct(): expr = Basic(1, 2, 3) expected = Compound(Basic, (1, 2, 3)) assert deconstruct(expr) == expected assert deconstruct(1) == 1 assert deconstruct(x) == x assert deconstruct(x, variables=(x,)) == Variable(x) assert deconstruct(Add(1, x, evaluate=False)) == Compound(Add, (1, x)) assert deconstruct(Add(1, x, evaluate=False), variables=(x,)) == \ Compound(Add, (1, Variable(x))) def test_construct(): expr = Compound(Basic, (1, 2, 3)) expected = Basic(1, 2, 3) assert construct(expr) == expected def test_nested(): expr = Basic(1, Basic(2), 3) cmpd = Compound(Basic, (1, Compound(Basic, (2,)), 3)) assert deconstruct(expr) == cmpd assert construct(cmpd) == expr def test_unify(): expr = Basic(1, 2, 3) a, b, c = map(Symbol, 'abc') pattern = Basic(a, b, c) assert list(unify(expr, pattern, {}, (a, b, c))) == [{a: 1, b: 2, c: 3}] assert list(unify(expr, pattern, variables=(a, b, c))) == \ [{a: 1, b: 2, c: 3}] def test_unify_variables(): assert list(unify(Basic(1, 2), Basic(1, x), {}, variables=(x,))) == [{x: 2}] def test_s_input(): expr = Basic(1, 2) a, b = map(Symbol, 'ab') pattern = Basic(a, b) assert list(unify(expr, pattern, {}, (a, b))) == [{a: 1, b: 2}] assert list(unify(expr, pattern, {a: 5}, (a, b))) == [] def iterdicteq(a, b): a = tuple(a) b = tuple(b) return len(a) == len(b) and all(x in b for x in a) def test_unify_commutative(): expr = Add(1, 2, 3, evaluate=False) a, b, c = map(Symbol, 'abc') pattern = Add(a, b, c, evaluate=False) result = tuple(unify(expr, pattern, {}, (a, b, c))) expected = ({a: 1, b: 2, c: 3}, {a: 1, b: 3, c: 2}, {a: 2, b: 1, c: 3}, {a: 2, b: 3, c: 1}, {a: 3, b: 1, c: 2}, {a: 3, b: 2, c: 1}) assert iterdicteq(result, expected) def test_unify_iter(): expr = Add(1, 2, 3, evaluate=False) a, b, c = map(Symbol, 'abc') pattern = Add(a, c, evaluate=False) assert is_associative(deconstruct(pattern)) assert is_commutative(deconstruct(pattern)) result = list(unify(expr, pattern, {}, (a, c))) expected = [{a: 1, c: Add(2, 3, evaluate=False)}, {a: 1, c: Add(3, 2, evaluate=False)}, {a: 2, c: Add(1, 3, evaluate=False)}, {a: 2, c: Add(3, 1, evaluate=False)}, {a: 3, c: Add(1, 2, evaluate=False)}, {a: 3, c: Add(2, 1, evaluate=False)}, {a: Add(1, 2, evaluate=False), c: 3}, {a: Add(2, 1, evaluate=False), c: 3}, {a: Add(1, 3, evaluate=False), c: 2}, {a: Add(3, 1, evaluate=False), c: 2}, {a: Add(2, 3, evaluate=False), c: 1}, {a: Add(3, 2, evaluate=False), c: 1}] assert iterdicteq(result, expected) def test_hard_match(): from sympy import sin, cos expr = sin(x) + cos(x)**2 p, q = map(Symbol, 'pq') pattern = sin(p) + cos(p)**2 assert list(unify(expr, pattern, {}, (p, q))) == [{p: x}] def test_matrix(): from sympy import MatrixSymbol X = MatrixSymbol('X', n, n) Y = MatrixSymbol('Y', 2, 2) Z = MatrixSymbol('Z', 2, 3) assert list(unify(X, Y, {}, variables=[n, Str('X')])) == [{Str('X'): Str('Y'), n: 2}] assert list(unify(X, Z, {}, variables=[n, Str('X')])) == [] def test_non_frankenAdds(): # the is_commutative property used to fail because of Basic.__new__ # This caused is_commutative and str calls to fail expr = x+y*2 rebuilt = construct(deconstruct(expr)) # Ensure that we can run these commands without causing an error str(rebuilt) rebuilt.is_commutative def test_FiniteSet_commutivity(): from sympy import FiniteSet a, b, c, x, y = symbols('a,b,c,x,y') s = FiniteSet(a, b, c) t = FiniteSet(x, y) variables = (x, y) assert {x: FiniteSet(a, c), y: b} in tuple(unify(s, t, variables=variables)) def test_FiniteSet_complex(): from sympy import FiniteSet a, b, c, x, y, z = symbols('a,b,c,x,y,z') expr = FiniteSet(Basic(S(1), x), y, Basic(x, z)) pattern = FiniteSet(a, Basic(x, b)) variables = a, b expected = tuple([{b: 1, a: FiniteSet(y, Basic(x, z))}, {b: z, a: FiniteSet(y, Basic(S(1), x))}]) assert iterdicteq(unify(expr, pattern, variables=variables), expected) def test_and(): variables = x, y expected = tuple([{x: z > 0, y: n < 3}]) assert iterdicteq(unify((z>0) & (n<3), And(x, y), variables=variables), expected) def test_Union(): from sympy import Interval assert list(unify(Interval(0, 1) + Interval(10, 11), Interval(0, 1) + Interval(12, 13), variables=(Interval(12, 13),))) def test_is_commutative(): assert is_commutative(deconstruct(x+y)) assert is_commutative(deconstruct(x*y)) assert not is_commutative(deconstruct(x**y)) def test_commutative_in_commutative(): from sympy.abc import a,b,c,d from sympy import sin, cos eq = sin(3)*sin(4)*sin(5) + 4*cos(3)*cos(4) pat = a*cos(b)*cos(c) + d*sin(b)*sin(c) assert next(unify(eq, pat, variables=(a,b,c,d))) sympy-sympy-1.9/sympy/unify/tests/test_unify.py000066400000000000000000000057151412543434000221530ustar00rootroot00000000000000from sympy.unify.core import Compound, Variable, CondVariable, allcombinations from sympy.unify import core a,b,c = 'abc' w,x,y,z = map(Variable, 'wxyz') C = Compound def is_associative(x): return isinstance(x, Compound) and (x.op in ('Add', 'Mul', 'CAdd', 'CMul')) def is_commutative(x): return isinstance(x, Compound) and (x.op in ('CAdd', 'CMul')) def unify(a, b, s={}): return core.unify(a, b, s=s, is_associative=is_associative, is_commutative=is_commutative) def test_basic(): assert list(unify(a, x, {})) == [{x: a}] assert list(unify(a, x, {x: 10})) == [] assert list(unify(1, x, {})) == [{x: 1}] assert list(unify(a, a, {})) == [{}] assert list(unify((w, x), (y, z), {})) == [{w: y, x: z}] assert list(unify(x, (a, b), {})) == [{x: (a, b)}] assert list(unify((a, b), (x, x), {})) == [] assert list(unify((y, z), (x, x), {}))!= [] assert list(unify((a, (b, c)), (a, (x, y)), {})) == [{x: b, y: c}] def test_ops(): assert list(unify(C('Add', (a,b,c)), C('Add', (a,x,y)), {})) == \ [{x:b, y:c}] assert list(unify(C('Add', (C('Mul', (1,2)), b,c)), C('Add', (x,y,c)), {})) == \ [{x: C('Mul', (1,2)), y:b}] def test_associative(): c1 = C('Add', (1,2,3)) c2 = C('Add', (x,y)) assert tuple(unify(c1, c2, {})) == ({x: 1, y: C('Add', (2, 3))}, {x: C('Add', (1, 2)), y: 3}) def test_commutative(): c1 = C('CAdd', (1,2,3)) c2 = C('CAdd', (x,y)) result = list(unify(c1, c2, {})) assert {x: 1, y: C('CAdd', (2, 3))} in result assert ({x: 2, y: C('CAdd', (1, 3))} in result or {x: 2, y: C('CAdd', (3, 1))} in result) def _test_combinations_assoc(): assert set(allcombinations((1,2,3), (a,b), True)) == \ {(((1, 2), (3,)), (a, b)), (((1,), (2, 3)), (a, b))} def _test_combinations_comm(): assert set(allcombinations((1,2,3), (a,b), None)) == \ {(((1,), (2, 3)), ('a', 'b')), (((2,), (3, 1)), ('a', 'b')), (((3,), (1, 2)), ('a', 'b')), (((1, 2), (3,)), ('a', 'b')), (((2, 3), (1,)), ('a', 'b')), (((3, 1), (2,)), ('a', 'b'))} def test_allcombinations(): assert set(allcombinations((1,2), (1,2), 'commutative')) ==\ {(((1,),(2,)), ((1,),(2,))), (((1,),(2,)), ((2,),(1,)))} def test_commutativity(): c1 = Compound('CAdd', (a, b)) c2 = Compound('CAdd', (x, y)) assert is_commutative(c1) and is_commutative(c2) assert len(list(unify(c1, c2, {}))) == 2 def test_CondVariable(): expr = C('CAdd', (1, 2)) x = Variable('x') y = CondVariable('y', lambda a: a % 2 == 0) z = CondVariable('z', lambda a: a > 3) pattern = C('CAdd', (x, y)) assert list(unify(expr, pattern, {})) == \ [{x: 1, y: 2}] z = CondVariable('z', lambda a: a > 3) pattern = C('CAdd', (z, y)) assert list(unify(expr, pattern, {})) == [] def test_defaultdict(): assert next(unify(Variable('x'), 'foo')) == {Variable('x'): 'foo'} sympy-sympy-1.9/sympy/unify/usympy.py000066400000000000000000000075601412543434000201660ustar00rootroot00000000000000""" SymPy interface to Unification engine See sympy.unify for module level docstring See sympy.unify.core for algorithmic docstring """ from sympy.core import Basic, Add, Mul, Pow from sympy.core.operations import AssocOp, LatticeOp from sympy.matrices import MatAdd, MatMul, MatrixExpr from sympy.sets.sets import Union, Intersection, FiniteSet from sympy.unify.core import Compound, Variable, CondVariable from sympy.unify import core basic_new_legal = [MatrixExpr] eval_false_legal = [AssocOp, Pow, FiniteSet] illegal = [LatticeOp] def sympy_associative(op): assoc_ops = (AssocOp, MatAdd, MatMul, Union, Intersection, FiniteSet) return any(issubclass(op, aop) for aop in assoc_ops) def sympy_commutative(op): comm_ops = (Add, MatAdd, Union, Intersection, FiniteSet) return any(issubclass(op, cop) for cop in comm_ops) def is_associative(x): return isinstance(x, Compound) and sympy_associative(x.op) def is_commutative(x): if not isinstance(x, Compound): return False if sympy_commutative(x.op): return True if issubclass(x.op, Mul): return all(construct(arg).is_commutative for arg in x.args) def mk_matchtype(typ): def matchtype(x): return (isinstance(x, typ) or isinstance(x, Compound) and issubclass(x.op, typ)) return matchtype def deconstruct(s, variables=()): """ Turn a SymPy object into a Compound """ if s in variables: return Variable(s) if isinstance(s, (Variable, CondVariable)): return s if not isinstance(s, Basic) or s.is_Atom: return s return Compound(s.__class__, tuple(deconstruct(arg, variables) for arg in s.args)) def construct(t): """ Turn a Compound into a SymPy object """ if isinstance(t, (Variable, CondVariable)): return t.arg if not isinstance(t, Compound): return t if any(issubclass(t.op, cls) for cls in eval_false_legal): return t.op(*map(construct, t.args), evaluate=False) elif any(issubclass(t.op, cls) for cls in basic_new_legal): return Basic.__new__(t.op, *map(construct, t.args)) else: return t.op(*map(construct, t.args)) def rebuild(s): """ Rebuild a SymPy expression. This removes harm caused by Expr-Rules interactions. """ return construct(deconstruct(s)) def unify(x, y, s=None, variables=(), **kwargs): """ Structural unification of two expressions/patterns. Examples ======== >>> from sympy.unify.usympy import unify >>> from sympy import Basic >>> from sympy.abc import x, y, z, p, q >>> next(unify(Basic(1, 2), Basic(1, x), variables=[x])) {x: 2} >>> expr = 2*x + y + z >>> pattern = 2*p + q >>> next(unify(expr, pattern, {}, variables=(p, q))) {p: x, q: y + z} Unification supports commutative and associative matching >>> expr = x + y + z >>> pattern = p + q >>> len(list(unify(expr, pattern, {}, variables=(p, q)))) 12 Symbols not indicated to be variables are treated as literal, else they are wild-like and match anything in a sub-expression. >>> expr = x*y*z + 3 >>> pattern = x*y + 3 >>> next(unify(expr, pattern, {}, variables=[x, y])) {x: y, y: x*z} The x and y of the pattern above were in a Mul and matched factors in the Mul of expr. Here, a single symbol matches an entire term: >>> expr = x*y + 3 >>> pattern = p + 3 >>> next(unify(expr, pattern, {}, variables=[p])) {p: x*y} """ decons = lambda x: deconstruct(x, variables) s = s or {} s = {decons(k): decons(v) for k, v in s.items()} ds = core.unify(decons(x), decons(y), s, is_associative=is_associative, is_commutative=is_commutative, **kwargs) for d in ds: yield {construct(k): construct(v) for k, v in d.items()} sympy-sympy-1.9/sympy/utilities/000077500000000000000000000000001412543434000171175ustar00rootroot00000000000000sympy-sympy-1.9/sympy/utilities/__init__.py000066400000000000000000000020251412543434000212270ustar00rootroot00000000000000"""This module contains some general purpose utilities that are used across SymPy. """ from .iterables import (flatten, group, take, subsets, variations, numbered_symbols, cartes, capture, dict_merge, postorder_traversal, interactive_traversal, prefixes, postfixes, sift, topological_sort, unflatten, has_dups, has_variety, reshape, default_sort_key, ordered, rotations) from .misc import filldedent from .lambdify import lambdify from .source import source from .decorator import threaded, xthreaded, public, memoize_property from .timeutils import timed __all__ = [ 'flatten', 'group', 'take', 'subsets', 'variations', 'numbered_symbols', 'cartes', 'capture', 'dict_merge', 'postorder_traversal', 'interactive_traversal', 'prefixes', 'postfixes', 'sift', 'topological_sort', 'unflatten', 'has_dups', 'has_variety', 'reshape', 'default_sort_key', 'ordered', 'rotations', 'filldedent', 'lambdify', 'source', 'threaded', 'xthreaded', 'public', 'memoize_property', 'timed', ] sympy-sympy-1.9/sympy/utilities/_compilation/000077500000000000000000000000001412543434000215745ustar00rootroot00000000000000sympy-sympy-1.9/sympy/utilities/_compilation/__init__.py000066400000000000000000000013571412543434000237130ustar00rootroot00000000000000""" This sub-module is private, i.e. external code should not depend on it. These functions are used by tests run as part of continuous integration. Once the implementation is mature (it should support the major platforms: Windows, OS X & Linux) it may become official API which may be relied upon by downstream libraries. Until then API may break without prior notice. TODO: - (optionally) clean up after tempfile.mkdtemp() - cross-platform testing - caching of compiler choice and intermediate files """ from .compilation import compile_link_import_strings, compile_run_strings from .availability import has_fortran, has_c, has_cxx __all__ = [ 'compile_link_import_strings', 'compile_run_strings', 'has_fortran', 'has_c', 'has_cxx', ] sympy-sympy-1.9/sympy/utilities/_compilation/availability.py000066400000000000000000000055041412543434000246240ustar00rootroot00000000000000import os from .compilation import compile_run_strings from .util import CompilerNotFoundError def has_fortran(): if not hasattr(has_fortran, 'result'): try: (stdout, stderr), info = compile_run_strings( [('main.f90', ( 'program foo\n' 'print *, "hello world"\n' 'end program' ))], clean=True ) except CompilerNotFoundError: has_fortran.result = False if os.environ.get('SYMPY_STRICT_COMPILER_CHECKS', '0') == '1': raise else: if info['exit_status'] != os.EX_OK or 'hello world' not in stdout: if os.environ.get('SYMPY_STRICT_COMPILER_CHECKS', '0') == '1': raise ValueError("Failed to compile test program:\n%s\n%s\n" % (stdout, stderr)) has_fortran.result = False else: has_fortran.result = True return has_fortran.result def has_c(): if not hasattr(has_c, 'result'): try: (stdout, stderr), info = compile_run_strings( [('main.c', ( '#include \n' 'int main(){\n' 'printf("hello world\\n");\n' 'return 0;\n' '}' ))], clean=True ) except CompilerNotFoundError: has_c.result = False if os.environ.get('SYMPY_STRICT_COMPILER_CHECKS', '0') == '1': raise else: if info['exit_status'] != os.EX_OK or 'hello world' not in stdout: if os.environ.get('SYMPY_STRICT_COMPILER_CHECKS', '0') == '1': raise ValueError("Failed to compile test program:\n%s\n%s\n" % (stdout, stderr)) has_c.result = False else: has_c.result = True return has_c.result def has_cxx(): if not hasattr(has_cxx, 'result'): try: (stdout, stderr), info = compile_run_strings( [('main.cxx', ( '#include \n' 'int main(){\n' 'std::cout << "hello world" << std::endl;\n' '}' ))], clean=True ) except CompilerNotFoundError: has_cxx.result = False if os.environ.get('SYMPY_STRICT_COMPILER_CHECKS', '0') == '1': raise else: if info['exit_status'] != os.EX_OK or 'hello world' not in stdout: if os.environ.get('SYMPY_STRICT_COMPILER_CHECKS', '0') == '1': raise ValueError("Failed to compile test program:\n%s\n%s\n" % (stdout, stderr)) has_cxx.result = False else: has_cxx.result = True return has_cxx.result sympy-sympy-1.9/sympy/utilities/_compilation/compilation.py000066400000000000000000000500131412543434000244630ustar00rootroot00000000000000import glob import os import shutil import subprocess import sys import tempfile import warnings from distutils.errors import CompileError from distutils.sysconfig import get_config_var, get_config_vars from .runners import ( CCompilerRunner, CppCompilerRunner, FortranCompilerRunner ) from .util import ( get_abspath, make_dirs, copy, Glob, ArbitraryDepthGlob, glob_at_depth, import_module_from_file, pyx_is_cplus, sha256_of_string, sha256_of_file ) sharedext = get_config_var('EXT_SUFFIX') if os.name == 'posix': objext = '.o' elif os.name == 'nt': objext = '.obj' else: warnings.warn("Unknown os.name: {}".format(os.name)) objext = '.o' def compile_sources(files, Runner=None, destdir=None, cwd=None, keep_dir_struct=False, per_file_kwargs=None, **kwargs): """ Compile source code files to object files. Parameters ========== files : iterable of str Paths to source files, if ``cwd`` is given, the paths are taken as relative. Runner: CompilerRunner subclass (optional) Could be e.g. ``FortranCompilerRunner``. Will be inferred from filename extensions if missing. destdir: str Output directory, if cwd is given, the path is taken as relative. cwd: str Working directory. Specify to have compiler run in other directory. also used as root of relative paths. keep_dir_struct: bool Reproduce directory structure in `destdir`. default: ``False`` per_file_kwargs: dict Dict mapping instances in ``files`` to keyword arguments. \\*\\*kwargs: dict Default keyword arguments to pass to ``Runner``. """ _per_file_kwargs = {} if per_file_kwargs is not None: for k, v in per_file_kwargs.items(): if isinstance(k, Glob): for path in glob.glob(k.pathname): _per_file_kwargs[path] = v elif isinstance(k, ArbitraryDepthGlob): for path in glob_at_depth(k.filename, cwd): _per_file_kwargs[path] = v else: _per_file_kwargs[k] = v # Set up destination directory destdir = destdir or '.' if not os.path.isdir(destdir): if os.path.exists(destdir): raise OSError("{} is not a directory".format(destdir)) else: make_dirs(destdir) if cwd is None: cwd = '.' for f in files: copy(f, destdir, only_update=True, dest_is_dir=True) # Compile files and return list of paths to the objects dstpaths = [] for f in files: if keep_dir_struct: name, ext = os.path.splitext(f) else: name, ext = os.path.splitext(os.path.basename(f)) file_kwargs = kwargs.copy() file_kwargs.update(_per_file_kwargs.get(f, {})) dstpaths.append(src2obj(f, Runner, cwd=cwd, **file_kwargs)) return dstpaths def get_mixed_fort_c_linker(vendor=None, cplus=False, cwd=None): vendor = vendor or os.environ.get('SYMPY_COMPILER_VENDOR', 'gnu') if vendor.lower() == 'intel': if cplus: return (FortranCompilerRunner, {'flags': ['-nofor_main', '-cxxlib']}, vendor) else: return (FortranCompilerRunner, {'flags': ['-nofor_main']}, vendor) elif vendor.lower() == 'gnu' or 'llvm': if cplus: return (CppCompilerRunner, {'lib_options': ['fortran']}, vendor) else: return (FortranCompilerRunner, {}, vendor) else: raise ValueError("No vendor found.") def link(obj_files, out_file=None, shared=False, Runner=None, cwd=None, cplus=False, fort=False, **kwargs): """ Link object files. Parameters ========== obj_files: iterable of str Paths to object files. out_file: str (optional) Path to executable/shared library, if ``None`` it will be deduced from the last item in obj_files. shared: bool Generate a shared library? Runner: CompilerRunner subclass (optional) If not given the ``cplus`` and ``fort`` flags will be inspected (fallback is the C compiler). cwd: str Path to the root of relative paths and working directory for compiler. cplus: bool C++ objects? default: ``False``. fort: bool Fortran objects? default: ``False``. \\*\\*kwargs: dict Keyword arguments passed to ``Runner``. Returns ======= The absolute path to the generated shared object / executable. """ if out_file is None: out_file, ext = os.path.splitext(os.path.basename(obj_files[-1])) if shared: out_file += sharedext if not Runner: if fort: Runner, extra_kwargs, vendor = \ get_mixed_fort_c_linker( vendor=kwargs.get('vendor', None), cplus=cplus, cwd=cwd, ) for k, v in extra_kwargs.items(): if k in kwargs: kwargs[k].expand(v) else: kwargs[k] = v else: if cplus: Runner = CppCompilerRunner else: Runner = CCompilerRunner flags = kwargs.pop('flags', []) if shared: if '-shared' not in flags: flags.append('-shared') run_linker = kwargs.pop('run_linker', True) if not run_linker: raise ValueError("run_linker was set to False (nonsensical).") out_file = get_abspath(out_file, cwd=cwd) runner = Runner(obj_files, out_file, flags, cwd=cwd, **kwargs) runner.run() return out_file def link_py_so(obj_files, so_file=None, cwd=None, libraries=None, cplus=False, fort=False, **kwargs): """ Link python extension module (shared object) for importing Parameters ========== obj_files: iterable of str Paths to object files to be linked. so_file: str Name (path) of shared object file to create. If not specified it will have the basname of the last object file in `obj_files` but with the extension '.so' (Unix). cwd: path string Root of relative paths and working directory of linker. libraries: iterable of strings Libraries to link against, e.g. ['m']. cplus: bool Any C++ objects? default: ``False``. fort: bool Any Fortran objects? default: ``False``. kwargs**: dict Keyword arguments passed to ``link(...)``. Returns ======= Absolute path to the generate shared object. """ libraries = libraries or [] include_dirs = kwargs.pop('include_dirs', []) library_dirs = kwargs.pop('library_dirs', []) # from distutils/command/build_ext.py: if sys.platform == "win32": warnings.warn("Windows not yet supported.") elif sys.platform == 'darwin': # Don't use the default code below pass elif sys.platform[:3] == 'aix': # Don't use the default code below pass else: from distutils import sysconfig if sysconfig.get_config_var('Py_ENABLE_SHARED'): cfgDict = get_config_vars() kwargs['linkline'] = kwargs.get('linkline', []) + [cfgDict['PY_LDFLAGS']] # PY_LDFLAGS or just LDFLAGS? library_dirs += [cfgDict['LIBDIR']] for opt in cfgDict['BLDLIBRARY'].split(): if opt.startswith('-l'): libraries += [opt[2:]] else: pass flags = kwargs.pop('flags', []) needed_flags = ('-pthread',) for flag in needed_flags: if flag not in flags: flags.append(flag) return link(obj_files, shared=True, flags=flags, cwd=cwd, cplus=cplus, fort=fort, include_dirs=include_dirs, libraries=libraries, library_dirs=library_dirs, **kwargs) def simple_cythonize(src, destdir=None, cwd=None, **cy_kwargs): """ Generates a C file from a Cython source file. Parameters ========== src: str Path to Cython source. destdir: str (optional) Path to output directory (default: '.'). cwd: path string (optional) Root of relative paths (default: '.'). **cy_kwargs: Second argument passed to cy_compile. Generates a .cpp file if ``cplus=True`` in ``cy_kwargs``, else a .c file. """ from Cython.Compiler.Main import ( default_options, CompilationOptions ) from Cython.Compiler.Main import compile as cy_compile assert src.lower().endswith('.pyx') or src.lower().endswith('.py') cwd = cwd or '.' destdir = destdir or '.' ext = '.cpp' if cy_kwargs.get('cplus', False) else '.c' c_name = os.path.splitext(os.path.basename(src))[0] + ext dstfile = os.path.join(destdir, c_name) if cwd: ori_dir = os.getcwd() else: ori_dir = '.' os.chdir(cwd) try: cy_options = CompilationOptions(default_options) cy_options.__dict__.update(cy_kwargs) cy_result = cy_compile([src], cy_options) if cy_result.num_errors > 0: raise ValueError("Cython compilation failed.") if os.path.abspath(os.path.dirname(src)) != os.path.abspath(destdir): if os.path.exists(dstfile): os.unlink(dstfile) shutil.move(os.path.join(os.path.dirname(src), c_name), destdir) finally: os.chdir(ori_dir) return dstfile extension_mapping = { '.c': (CCompilerRunner, None), '.cpp': (CppCompilerRunner, None), '.cxx': (CppCompilerRunner, None), '.f': (FortranCompilerRunner, None), '.for': (FortranCompilerRunner, None), '.ftn': (FortranCompilerRunner, None), '.f90': (FortranCompilerRunner, None), # ifort only knows about .f90 '.f95': (FortranCompilerRunner, 'f95'), '.f03': (FortranCompilerRunner, 'f2003'), '.f08': (FortranCompilerRunner, 'f2008'), } def src2obj(srcpath, Runner=None, objpath=None, cwd=None, inc_py=False, **kwargs): """ Compiles a source code file to an object file. Files ending with '.pyx' assumed to be cython files and are dispatched to pyx2obj. Parameters ========== srcpath: str Path to source file. Runner: CompilerRunner subclass (optional) If ``None``: deduced from extension of srcpath. objpath : str (optional) Path to generated object. If ``None``: deduced from ``srcpath``. cwd: str (optional) Working directory and root of relative paths. If ``None``: current dir. inc_py: bool Add Python include path to kwarg "include_dirs". Default: False \\*\\*kwargs: dict keyword arguments passed to Runner or pyx2obj """ name, ext = os.path.splitext(os.path.basename(srcpath)) if objpath is None: if os.path.isabs(srcpath): objpath = '.' else: objpath = os.path.dirname(srcpath) objpath = objpath or '.' # avoid objpath == '' if os.path.isdir(objpath): objpath = os.path.join(objpath, name + objext) include_dirs = kwargs.pop('include_dirs', []) if inc_py: from distutils.sysconfig import get_python_inc py_inc_dir = get_python_inc() if py_inc_dir not in include_dirs: include_dirs.append(py_inc_dir) if ext.lower() == '.pyx': return pyx2obj(srcpath, objpath=objpath, include_dirs=include_dirs, cwd=cwd, **kwargs) if Runner is None: Runner, std = extension_mapping[ext.lower()] if 'std' not in kwargs: kwargs['std'] = std flags = kwargs.pop('flags', []) needed_flags = ('-fPIC',) for flag in needed_flags: if flag not in flags: flags.append(flag) # src2obj implies not running the linker... run_linker = kwargs.pop('run_linker', False) if run_linker: raise CompileError("src2obj called with run_linker=True") runner = Runner([srcpath], objpath, include_dirs=include_dirs, run_linker=run_linker, cwd=cwd, flags=flags, **kwargs) runner.run() return objpath def pyx2obj(pyxpath, objpath=None, destdir=None, cwd=None, include_dirs=None, cy_kwargs=None, cplus=None, **kwargs): """ Convenience function If cwd is specified, pyxpath and dst are taken to be relative If only_update is set to `True` the modification time is checked and compilation is only run if the source is newer than the destination Parameters ========== pyxpath: str Path to Cython source file. objpath: str (optional) Path to object file to generate. destdir: str (optional) Directory to put generated C file. When ``None``: directory of ``objpath``. cwd: str (optional) Working directory and root of relative paths. include_dirs: iterable of path strings (optional) Passed onto src2obj and via cy_kwargs['include_path'] to simple_cythonize. cy_kwargs: dict (optional) Keyword arguments passed onto `simple_cythonize` cplus: bool (optional) Indicate whether C++ is used. default: auto-detect using ``.util.pyx_is_cplus``. compile_kwargs: dict keyword arguments passed onto src2obj Returns ======= Absolute path of generated object file. """ assert pyxpath.endswith('.pyx') cwd = cwd or '.' objpath = objpath or '.' destdir = destdir or os.path.dirname(objpath) abs_objpath = get_abspath(objpath, cwd=cwd) if os.path.isdir(abs_objpath): pyx_fname = os.path.basename(pyxpath) name, ext = os.path.splitext(pyx_fname) objpath = os.path.join(objpath, name + objext) cy_kwargs = cy_kwargs or {} cy_kwargs['output_dir'] = cwd if cplus is None: cplus = pyx_is_cplus(pyxpath) cy_kwargs['cplus'] = cplus interm_c_file = simple_cythonize(pyxpath, destdir=destdir, cwd=cwd, **cy_kwargs) include_dirs = include_dirs or [] flags = kwargs.pop('flags', []) needed_flags = ('-fwrapv', '-pthread', '-fPIC') for flag in needed_flags: if flag not in flags: flags.append(flag) options = kwargs.pop('options', []) if kwargs.pop('strict_aliasing', False): raise CompileError("Cython requires strict aliasing to be disabled.") # Let's be explicit about standard if cplus: std = kwargs.pop('std', 'c++98') else: std = kwargs.pop('std', 'c99') return src2obj(interm_c_file, objpath=objpath, cwd=cwd, include_dirs=include_dirs, flags=flags, std=std, options=options, inc_py=True, strict_aliasing=False, **kwargs) def _any_X(srcs, cls): for src in srcs: name, ext = os.path.splitext(src) key = ext.lower() if key in extension_mapping: if extension_mapping[key][0] == cls: return True return False def any_fortran_src(srcs): return _any_X(srcs, FortranCompilerRunner) def any_cplus_src(srcs): return _any_X(srcs, CppCompilerRunner) def compile_link_import_py_ext(sources, extname=None, build_dir='.', compile_kwargs=None, link_kwargs=None): """ Compiles sources to a shared object (python extension) and imports it Sources in ``sources`` which is imported. If shared object is newer than the sources, they are not recompiled but instead it is imported. Parameters ========== sources : string List of paths to sources. extname : string Name of extension (default: ``None``). If ``None``: taken from the last file in ``sources`` without extension. build_dir: str Path to directory in which objects files etc. are generated. compile_kwargs: dict keyword arguments passed to ``compile_sources`` link_kwargs: dict keyword arguments passed to ``link_py_so`` Returns ======= The imported module from of the python extension. """ if extname is None: extname = os.path.splitext(os.path.basename(sources[-1]))[0] compile_kwargs = compile_kwargs or {} link_kwargs = link_kwargs or {} try: mod = import_module_from_file(os.path.join(build_dir, extname), sources) except ImportError: objs = compile_sources(list(map(get_abspath, sources)), destdir=build_dir, cwd=build_dir, **compile_kwargs) so = link_py_so(objs, cwd=build_dir, fort=any_fortran_src(sources), cplus=any_cplus_src(sources), **link_kwargs) mod = import_module_from_file(so) return mod def _write_sources_to_build_dir(sources, build_dir): build_dir = build_dir or tempfile.mkdtemp() if not os.path.isdir(build_dir): raise OSError("Non-existent directory: ", build_dir) source_files = [] for name, src in sources: dest = os.path.join(build_dir, name) differs = True sha256_in_mem = sha256_of_string(src.encode('utf-8')).hexdigest() if os.path.exists(dest): if os.path.exists(dest + '.sha256'): sha256_on_disk = open(dest + '.sha256').read() else: sha256_on_disk = sha256_of_file(dest).hexdigest() differs = sha256_on_disk != sha256_in_mem if differs: with open(dest, 'wt') as fh: fh.write(src) open(dest + '.sha256', 'wt').write(sha256_in_mem) source_files.append(dest) return source_files, build_dir def compile_link_import_strings(sources, build_dir=None, **kwargs): """ Compiles, links and imports extension module from source. Parameters ========== sources : iterable of name/source pair tuples build_dir : string (default: None) Path. ``None`` implies use a temporary directory. **kwargs: Keyword arguments passed onto `compile_link_import_py_ext`. Returns ======= mod : module The compiled and imported extension module. info : dict Containing ``build_dir`` as 'build_dir'. """ source_files, build_dir = _write_sources_to_build_dir(sources, build_dir) mod = compile_link_import_py_ext(source_files, build_dir=build_dir, **kwargs) info = dict(build_dir=build_dir) return mod, info def compile_run_strings(sources, build_dir=None, clean=False, compile_kwargs=None, link_kwargs=None): """ Compiles, links and runs a program built from sources. Parameters ========== sources : iterable of name/source pair tuples build_dir : string (default: None) Path. ``None`` implies use a temporary directory. clean : bool Whether to remove build_dir after use. This will only have an effect if ``build_dir`` is ``None`` (which creates a temporary directory). Passing ``clean == True`` and ``build_dir != None`` raises a ``ValueError``. This will also set ``build_dir`` in returned info dictionary to ``None``. compile_kwargs: dict Keyword arguments passed onto ``compile_sources`` link_kwargs: dict Keyword arguments passed onto ``link`` Returns ======= (stdout, stderr): pair of strings info: dict Containing exit status as 'exit_status' and ``build_dir`` as 'build_dir' """ if clean and build_dir is not None: raise ValueError("Automatic removal of build_dir is only available for temporary directory.") try: source_files, build_dir = _write_sources_to_build_dir(sources, build_dir) objs = compile_sources(list(map(get_abspath, source_files)), destdir=build_dir, cwd=build_dir, **(compile_kwargs or {})) prog = link(objs, cwd=build_dir, fort=any_fortran_src(source_files), cplus=any_cplus_src(source_files), **(link_kwargs or {})) p = subprocess.Popen([prog], stdout=subprocess.PIPE, stderr=subprocess.PIPE) exit_status = p.wait() stdout, stderr = [txt.decode('utf-8') for txt in p.communicate()] finally: if clean and os.path.isdir(build_dir): shutil.rmtree(build_dir) build_dir = None info = dict(exit_status=exit_status, build_dir=build_dir) return (stdout, stderr), info sympy-sympy-1.9/sympy/utilities/_compilation/runners.py000066400000000000000000000215351412543434000236500ustar00rootroot00000000000000from typing import Callable, Dict, Optional, Tuple, Union from collections import OrderedDict from distutils.errors import CompileError import os import re import subprocess from .util import ( find_binary_of_command, unique_list ) class CompilerRunner: """ CompilerRunner base class. Parameters ========== sources : list of str Paths to sources. out : str flags : iterable of str Compiler flags. run_linker : bool compiler_name_exe : (str, str) tuple Tuple of compiler name & command to call. cwd : str Path of root of relative paths. include_dirs : list of str Include directories. libraries : list of str Libraries to link against. library_dirs : list of str Paths to search for shared libraries. std : str Standard string, e.g. ``'c++11'``, ``'c99'``, ``'f2003'``. define: iterable of strings macros to define undef : iterable of strings macros to undefine preferred_vendor : string name of preferred vendor e.g. 'gnu' or 'intel' Methods ======= run(): Invoke compilation as a subprocess. """ # Subclass to vendor/binary dict compiler_dict = None # type: Dict[str, str] # Standards should be a tuple of supported standards # (first one will be the default) standards = None # type: Tuple[Union[None, str], ...] # Subclass to dict of binary/formater-callback std_formater = None # type: Dict[str, Callable[[Optional[str]], str]] # subclass to be e.g. {'gcc': 'gnu', ...} compiler_name_vendor_mapping = None # type: Dict[str, str] def __init__(self, sources, out, flags=None, run_linker=True, compiler=None, cwd='.', include_dirs=None, libraries=None, library_dirs=None, std=None, define=None, undef=None, strict_aliasing=None, preferred_vendor=None, linkline=None, **kwargs): if isinstance(sources, str): raise ValueError("Expected argument sources to be a list of strings.") self.sources = list(sources) self.out = out self.flags = flags or [] self.cwd = cwd if compiler: self.compiler_name, self.compiler_binary = compiler else: # Find a compiler if preferred_vendor is None: preferred_vendor = os.environ.get('SYMPY_COMPILER_VENDOR', None) self.compiler_name, self.compiler_binary, self.compiler_vendor = self.find_compiler(preferred_vendor) if self.compiler_binary is None: raise ValueError("No compiler found (searched: {})".format(', '.join(self.compiler_dict.values()))) self.define = define or [] self.undef = undef or [] self.include_dirs = include_dirs or [] self.libraries = libraries or [] self.library_dirs = library_dirs or [] self.std = std or self.standards[0] self.run_linker = run_linker if self.run_linker: # both gnu and intel compilers use '-c' for disabling linker self.flags = list(filter(lambda x: x != '-c', self.flags)) else: if '-c' not in self.flags: self.flags.append('-c') if self.std: self.flags.append(self.std_formater[ self.compiler_name](self.std)) self.linkline = linkline or [] if strict_aliasing is not None: nsa_re = re.compile("no-strict-aliasing$") sa_re = re.compile("strict-aliasing$") if strict_aliasing is True: if any(map(nsa_re.match, flags)): raise CompileError("Strict aliasing cannot be both enforced and disabled") elif any(map(sa_re.match, flags)): pass # already enforced else: flags.append('-fstrict-aliasing') elif strict_aliasing is False: if any(map(nsa_re.match, flags)): pass # already disabled else: if any(map(sa_re.match, flags)): raise CompileError("Strict aliasing cannot be both enforced and disabled") else: flags.append('-fno-strict-aliasing') else: msg = "Expected argument strict_aliasing to be True/False, got {}" raise ValueError(msg.format(strict_aliasing)) @classmethod def find_compiler(cls, preferred_vendor=None): """ Identify a suitable C/fortran/other compiler. """ candidates = list(cls.compiler_dict.keys()) if preferred_vendor: if preferred_vendor in candidates: candidates = [preferred_vendor]+candidates else: raise ValueError("Unknown vendor {}".format(preferred_vendor)) name, path = find_binary_of_command([cls.compiler_dict[x] for x in candidates]) return name, path, cls.compiler_name_vendor_mapping[name] def cmd(self): """ List of arguments (str) to be passed to e.g. ``subprocess.Popen``. """ cmd = ( [self.compiler_binary] + self.flags + ['-U'+x for x in self.undef] + ['-D'+x for x in self.define] + ['-I'+x for x in self.include_dirs] + self.sources ) if self.run_linker: cmd += (['-L'+x for x in self.library_dirs] + ['-l'+x for x in self.libraries] + self.linkline) counted = [] for envvar in re.findall(r'\$\{(\w+)\}', ' '.join(cmd)): if os.getenv(envvar) is None: if envvar not in counted: counted.append(envvar) msg = "Environment variable '{}' undefined.".format(envvar) raise CompileError(msg) return cmd def run(self): self.flags = unique_list(self.flags) # Append output flag and name to tail of flags self.flags.extend(['-o', self.out]) env = os.environ.copy() env['PWD'] = self.cwd # NOTE: intel compilers seems to need shell=True p = subprocess.Popen(' '.join(self.cmd()), shell=True, cwd=self.cwd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env) comm = p.communicate() try: self.cmd_outerr = comm[0].decode('utf-8') except UnicodeDecodeError: self.cmd_outerr = comm[0].decode('iso-8859-1') # win32 self.cmd_returncode = p.returncode # Error handling if self.cmd_returncode != 0: msg = "Error executing '{}' in {} (exited status {}):\n {}\n".format( ' '.join(self.cmd()), self.cwd, str(self.cmd_returncode), self.cmd_outerr ) raise CompileError(msg) return self.cmd_outerr, self.cmd_returncode class CCompilerRunner(CompilerRunner): compiler_dict = OrderedDict([ ('gnu', 'gcc'), ('intel', 'icc'), ('llvm', 'clang'), ]) standards = ('c89', 'c90', 'c99', 'c11') # First is default std_formater = { 'gcc': '-std={}'.format, 'icc': '-std={}'.format, 'clang': '-std={}'.format, } compiler_name_vendor_mapping = { 'gcc': 'gnu', 'icc': 'intel', 'clang': 'llvm' } def _mk_flag_filter(cmplr_name): # helper for class initialization not_welcome = {'g++': ("Wimplicit-interface",)} # "Wstrict-prototypes",)} if cmplr_name in not_welcome: def fltr(x): for nw in not_welcome[cmplr_name]: if nw in x: return False return True else: def fltr(x): return True return fltr class CppCompilerRunner(CompilerRunner): compiler_dict = OrderedDict([ ('gnu', 'g++'), ('intel', 'icpc'), ('llvm', 'clang++'), ]) # First is the default, c++0x == c++11 standards = ('c++98', 'c++0x') std_formater = { 'g++': '-std={}'.format, 'icpc': '-std={}'.format, 'clang++': '-std={}'.format, } compiler_name_vendor_mapping = { 'g++': 'gnu', 'icpc': 'intel', 'clang++': 'llvm' } class FortranCompilerRunner(CompilerRunner): standards = (None, 'f77', 'f95', 'f2003', 'f2008') std_formater = { 'gfortran': lambda x: '-std=gnu' if x is None else '-std=legacy' if x == 'f77' else '-std={}'.format(x), 'ifort': lambda x: '-stand f08' if x is None else '-stand f{}'.format(x[-2:]), # f2008 => f08 } compiler_dict = OrderedDict([ ('gnu', 'gfortran'), ('intel', 'ifort'), ]) compiler_name_vendor_mapping = { 'gfortran': 'gnu', 'ifort': 'intel', } sympy-sympy-1.9/sympy/utilities/_compilation/tests/000077500000000000000000000000001412543434000227365ustar00rootroot00000000000000sympy-sympy-1.9/sympy/utilities/_compilation/tests/__init__.py000066400000000000000000000000001412543434000250350ustar00rootroot00000000000000sympy-sympy-1.9/sympy/utilities/_compilation/tests/test_compilation.py000066400000000000000000000033051412543434000266660ustar00rootroot00000000000000import shutil from sympy.external import import_module from sympy.testing.pytest import skip from sympy.utilities._compilation.compilation import compile_link_import_strings numpy = import_module('numpy') cython = import_module('cython') _sources1 = [ ('sigmoid.c', r""" #include void sigmoid(int n, const double * const restrict in, double * const restrict out, double lim){ for (int i=0; i 0: if not os.path.exists(parent): make_dirs(parent) if not os.path.exists(path): os.mkdir(path, 0o777) else: assert os.path.isdir(path) def copy(src, dst, only_update=False, copystat=True, cwd=None, dest_is_dir=False, create_dest_dirs=False): """ Variation of ``shutil.copy`` with extra options. Parameters ========== src : str Path to source file. dst : str Path to destination. only_update : bool Only copy if source is newer than destination (returns None if it was newer), default: ``False``. copystat : bool See ``shutil.copystat``. default: ``True``. cwd : str Path to working directory (root of relative paths). dest_is_dir : bool Ensures that dst is treated as a directory. default: ``False`` create_dest_dirs : bool Creates directories if needed. Returns ======= Path to the copied file. """ if cwd: # Handle working directory if not os.path.isabs(src): src = os.path.join(cwd, src) if not os.path.isabs(dst): dst = os.path.join(cwd, dst) if not os.path.exists(src): # Make sure source file extists raise FileNotFoundError("Source: `{}` does not exist".format(src)) # We accept both (re)naming destination file _or_ # passing a (possible non-existent) destination directory if dest_is_dir: if not dst[-1] == '/': dst = dst+'/' else: if os.path.exists(dst) and os.path.isdir(dst): dest_is_dir = True if dest_is_dir: dest_dir = dst dest_fname = os.path.basename(src) dst = os.path.join(dest_dir, dest_fname) else: dest_dir = os.path.dirname(dst) if not os.path.exists(dest_dir): if create_dest_dirs: make_dirs(dest_dir) else: raise FileNotFoundError("You must create directory first.") if only_update: # This function is not defined: # XXX: This branch is clearly not tested! if not missing_or_other_newer(dst, src): # noqa return if os.path.islink(dst): dst = os.path.abspath(os.path.realpath(dst), cwd=cwd) shutil.copy(src, dst) if copystat: shutil.copystat(src, dst) return dst Glob = namedtuple('Glob', 'pathname') ArbitraryDepthGlob = namedtuple('ArbitraryDepthGlob', 'filename') def glob_at_depth(filename_glob, cwd=None): if cwd is not None: cwd = '.' globbed = [] for root, dirs, filenames in os.walk(cwd): for fn in filenames: # This is not tested: if fnmatch.fnmatch(fn, filename_glob): globbed.append(os.path.join(root, fn)) return globbed def sha256_of_file(path, nblocks=128): """ Computes the SHA256 hash of a file. Parameters ========== path : string Path to file to compute hash of. nblocks : int Number of blocks to read per iteration. Returns ======= hashlib sha256 hash object. Use ``.digest()`` or ``.hexdigest()`` on returned object to get binary or hex encoded string. """ sh = sha256() with open(path, 'rb') as f: for chunk in iter(lambda: f.read(nblocks*sh.block_size), b''): sh.update(chunk) return sh def sha256_of_string(string): """ Computes the SHA256 hash of a string. """ sh = sha256() sh.update(string) return sh def pyx_is_cplus(path): """ Inspect a Cython source file (.pyx) and look for comment line like: # distutils: language = c++ Returns True if such a file is present in the file, else False. """ for line in open(path): if line.startswith('#') and '=' in line: splitted = line.split('=') if len(splitted) != 2: continue lhs, rhs = splitted if lhs.strip().split()[-1].lower() == 'language' and \ rhs.strip().split()[0].lower() == 'c++': return True return False def import_module_from_file(filename, only_if_newer_than=None): """ Imports python extension (from shared object file) Provide a list of paths in `only_if_newer_than` to check timestamps of dependencies. import_ raises an ImportError if any is newer. Word of warning: The OS may cache shared objects which makes reimporting same path of an shared object file very problematic. It will not detect the new time stamp, nor new checksum, but will instead silently use old module. Use unique names for this reason. Parameters ========== filename : str Path to shared object. only_if_newer_than : iterable of strings Paths to dependencies of the shared object. Raises ====== ``ImportError`` if any of the files specified in ``only_if_newer_than`` are newer than the file given by filename. """ path, name = os.path.split(filename) name, ext = os.path.splitext(name) name = name.split('.')[0] if sys.version_info[0] == 2: from imp import find_module, load_module fobj, filename, data = find_module(name, [path]) if only_if_newer_than: for dep in only_if_newer_than: if os.path.getmtime(filename) < os.path.getmtime(dep): raise ImportError("{} is newer than {}".format(dep, filename)) mod = load_module(name, fobj, filename, data) else: import importlib.util spec = importlib.util.spec_from_file_location(name, filename) if spec is None: raise ImportError("Failed to import: '%s'" % filename) mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) return mod def find_binary_of_command(candidates): """ Finds binary first matching name among candidates. Calls `find_executable` from distuils for provided candidates and returns first hit. Parameters ========== candidates : iterable of str Names of candidate commands Raises ====== CompilerNotFoundError if no candidates match. """ from distutils.spawn import find_executable for c in candidates: binary_path = find_executable(c) if c and binary_path: return c, binary_path raise CompilerNotFoundError('No binary located for candidates: {}'.format(candidates)) def unique_list(l): """ Uniquify a list (skip duplicate items). """ result = [] for x in l: if x not in result: result.append(x) return result sympy-sympy-1.9/sympy/utilities/autowrap.py000066400000000000000000001205151412543434000213370ustar00rootroot00000000000000"""Module for compiling codegen output, and wrap the binary for use in python. .. note:: To use the autowrap module it must first be imported >>> from sympy.utilities.autowrap import autowrap This module provides a common interface for different external backends, such as f2py, fwrap, Cython, SWIG(?) etc. (Currently only f2py and Cython are implemented) The goal is to provide access to compiled binaries of acceptable performance with a one-button user interface, e.g., >>> from sympy.abc import x,y >>> expr = (x - y)**25 >>> flat = expr.expand() >>> binary_callable = autowrap(flat) >>> binary_callable(2, 3) -1.0 Although a SymPy user might primarily be interested in working with mathematical expressions and not in the details of wrapping tools needed to evaluate such expressions efficiently in numerical form, the user cannot do so without some understanding of the limits in the target language. For example, the expanded expression contains large coefficients which result in loss of precision when computing the expression: >>> binary_callable(3, 2) 0.0 >>> binary_callable(4, 5), binary_callable(5, 4) (-22925376.0, 25165824.0) Wrapping the unexpanded expression gives the expected behavior: >>> e = autowrap(expr) >>> e(4, 5), e(5, 4) (-1.0, 1.0) The callable returned from autowrap() is a binary python function, not a SymPy object. If it is desired to use the compiled function in symbolic expressions, it is better to use binary_function() which returns a SymPy Function object. The binary callable is attached as the _imp_ attribute and invoked when a numerical evaluation is requested with evalf(), or with lambdify(). >>> from sympy.utilities.autowrap import binary_function >>> f = binary_function('f', expr) >>> 2*f(x, y) + y y + 2*f(x, y) >>> (2*f(x, y) + y).evalf(2, subs={x: 1, y:2}) 0.e-110 When is this useful? 1) For computations on large arrays, Python iterations may be too slow, and depending on the mathematical expression, it may be difficult to exploit the advanced index operations provided by NumPy. 2) For *really* long expressions that will be called repeatedly, the compiled binary should be significantly faster than SymPy's .evalf() 3) If you are generating code with the codegen utility in order to use it in another project, the automatic python wrappers let you test the binaries immediately from within SymPy. 4) To create customized ufuncs for use with numpy arrays. See *ufuncify*. When is this module NOT the best approach? 1) If you are really concerned about speed or memory optimizations, you will probably get better results by working directly with the wrapper tools and the low level code. However, the files generated by this utility may provide a useful starting point and reference code. Temporary files will be left intact if you supply the keyword tempdir="path/to/files/". 2) If the array computation can be handled easily by numpy, and you don't need the binaries for another project. """ import sys import os import shutil import tempfile from subprocess import STDOUT, CalledProcessError, check_output from string import Template from warnings import warn from sympy.core.cache import cacheit from sympy.core.compatibility import iterable from sympy.core.function import Lambda from sympy.core.relational import Eq from sympy.core.symbol import Dummy, Symbol from sympy.tensor.indexed import Idx, IndexedBase from sympy.utilities.codegen import (make_routine, get_code_generator, OutputArgument, InOutArgument, InputArgument, CodeGenArgumentListError, Result, ResultBase, C99CodeGen) from sympy.utilities.lambdify import implemented_function from sympy.utilities.decorator import doctest_depends_on _doctest_depends_on = {'exe': ('f2py', 'gfortran', 'gcc'), 'modules': ('numpy',)} class CodeWrapError(Exception): pass class CodeWrapper: """Base Class for code wrappers""" _filename = "wrapped_code" _module_basename = "wrapper_module" _module_counter = 0 @property def filename(self): return "%s_%s" % (self._filename, CodeWrapper._module_counter) @property def module_name(self): return "%s_%s" % (self._module_basename, CodeWrapper._module_counter) def __init__(self, generator, filepath=None, flags=[], verbose=False): """ generator -- the code generator to use """ self.generator = generator self.filepath = filepath self.flags = flags self.quiet = not verbose @property def include_header(self): return bool(self.filepath) @property def include_empty(self): return bool(self.filepath) def _generate_code(self, main_routine, routines): routines.append(main_routine) self.generator.write( routines, self.filename, True, self.include_header, self.include_empty) def wrap_code(self, routine, helpers=None): helpers = helpers or [] if self.filepath: workdir = os.path.abspath(self.filepath) else: workdir = tempfile.mkdtemp("_sympy_compile") if not os.access(workdir, os.F_OK): os.mkdir(workdir) oldwork = os.getcwd() os.chdir(workdir) try: sys.path.append(workdir) self._generate_code(routine, helpers) self._prepare_files(routine) self._process_files(routine) mod = __import__(self.module_name) finally: sys.path.remove(workdir) CodeWrapper._module_counter += 1 os.chdir(oldwork) if not self.filepath: try: shutil.rmtree(workdir) except OSError: # Could be some issues on Windows pass return self._get_wrapped_function(mod, routine.name) def _process_files(self, routine): command = self.command command.extend(self.flags) try: retoutput = check_output(command, stderr=STDOUT) except CalledProcessError as e: raise CodeWrapError( "Error while executing command: %s. Command output is:\n%s" % ( " ".join(command), e.output.decode('utf-8'))) if not self.quiet: print(retoutput) class DummyWrapper(CodeWrapper): """Class used for testing independent of backends """ template = """# dummy module for testing of SymPy def %(name)s(): return "%(expr)s" %(name)s.args = "%(args)s" %(name)s.returns = "%(retvals)s" """ def _prepare_files(self, routine): return def _generate_code(self, routine, helpers): with open('%s.py' % self.module_name, 'w') as f: printed = ", ".join( [str(res.expr) for res in routine.result_variables]) # convert OutputArguments to return value like f2py args = filter(lambda x: not isinstance( x, OutputArgument), routine.arguments) retvals = [] for val in routine.result_variables: if isinstance(val, Result): retvals.append('nameless') else: retvals.append(val.result_var) print(DummyWrapper.template % { 'name': routine.name, 'expr': printed, 'args': ", ".join([str(a.name) for a in args]), 'retvals': ", ".join([str(val) for val in retvals]) }, end="", file=f) def _process_files(self, routine): return @classmethod def _get_wrapped_function(cls, mod, name): return getattr(mod, name) class CythonCodeWrapper(CodeWrapper): """Wrapper that uses Cython""" setup_template = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {cythonize_options} {np_import} ext_mods = [Extension( {ext_args}, include_dirs={include_dirs}, library_dirs={library_dirs}, libraries={libraries}, extra_compile_args={extra_compile_args}, extra_link_args={extra_link_args} )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ pyx_imports = ( "import numpy as np\n" "cimport numpy as np\n\n") pyx_header = ( "cdef extern from '{header_file}.h':\n" " {prototype}\n\n") pyx_func = ( "def {name}_c({arg_string}):\n" "\n" "{declarations}" "{body}") std_compile_flag = '-std=c99' def __init__(self, *args, **kwargs): """Instantiates a Cython code wrapper. The following optional parameters get passed to ``distutils.Extension`` for building the Python extension module. Read its documentation to learn more. Parameters ========== include_dirs : [list of strings] A list of directories to search for C/C++ header files (in Unix form for portability). library_dirs : [list of strings] A list of directories to search for C/C++ libraries at link time. libraries : [list of strings] A list of library names (not filenames or paths) to link against. extra_compile_args : [list of strings] Any extra platform- and compiler-specific information to use when compiling the source files in 'sources'. For platforms and compilers where "command line" makes sense, this is typically a list of command-line arguments, but for other platforms it could be anything. Note that the attribute ``std_compile_flag`` will be appended to this list. extra_link_args : [list of strings] Any extra platform- and compiler-specific information to use when linking object files together to create the extension (or to create a new static Python interpreter). Similar interpretation as for 'extra_compile_args'. cythonize_options : [dictionary] Keyword arguments passed on to cythonize. """ self._include_dirs = kwargs.pop('include_dirs', []) self._library_dirs = kwargs.pop('library_dirs', []) self._libraries = kwargs.pop('libraries', []) self._extra_compile_args = kwargs.pop('extra_compile_args', []) self._extra_compile_args.append(self.std_compile_flag) self._extra_link_args = kwargs.pop('extra_link_args', []) self._cythonize_options = kwargs.pop('cythonize_options', {}) self._need_numpy = False super().__init__(*args, **kwargs) @property def command(self): command = [sys.executable, "setup.py", "build_ext", "--inplace"] return command def _prepare_files(self, routine, build_dir=os.curdir): # NOTE : build_dir is used for testing purposes. pyxfilename = self.module_name + '.pyx' codefilename = "%s.%s" % (self.filename, self.generator.code_extension) # pyx with open(os.path.join(build_dir, pyxfilename), 'w') as f: self.dump_pyx([routine], f, self.filename) # setup.py ext_args = [repr(self.module_name), repr([pyxfilename, codefilename])] if self._need_numpy: np_import = 'import numpy as np\n' self._include_dirs.append('np.get_include()') else: np_import = '' with open(os.path.join(build_dir, 'setup.py'), 'w') as f: includes = str(self._include_dirs).replace("'np.get_include()'", 'np.get_include()') f.write(self.setup_template.format( ext_args=", ".join(ext_args), np_import=np_import, include_dirs=includes, library_dirs=self._library_dirs, libraries=self._libraries, extra_compile_args=self._extra_compile_args, extra_link_args=self._extra_link_args, cythonize_options=self._cythonize_options )) @classmethod def _get_wrapped_function(cls, mod, name): return getattr(mod, name + '_c') def dump_pyx(self, routines, f, prefix): """Write a Cython file with python wrappers This file contains all the definitions of the routines in c code and refers to the header file. Arguments --------- routines List of Routine instances f File-like object to write the file to prefix The filename prefix, used to refer to the proper header file. Only the basename of the prefix is used. """ headers = [] functions = [] for routine in routines: prototype = self.generator.get_prototype(routine) # C Function Header Import headers.append(self.pyx_header.format(header_file=prefix, prototype=prototype)) # Partition the C function arguments into categories py_rets, py_args, py_loc, py_inf = self._partition_args(routine.arguments) # Function prototype name = routine.name arg_string = ", ".join(self._prototype_arg(arg) for arg in py_args) # Local Declarations local_decs = [] for arg, val in py_inf.items(): proto = self._prototype_arg(arg) mat, ind = [self._string_var(v) for v in val] local_decs.append(" cdef {} = {}.shape[{}]".format(proto, mat, ind)) local_decs.extend([" cdef {}".format(self._declare_arg(a)) for a in py_loc]) declarations = "\n".join(local_decs) if declarations: declarations = declarations + "\n" # Function Body args_c = ", ".join([self._call_arg(a) for a in routine.arguments]) rets = ", ".join([self._string_var(r.name) for r in py_rets]) if routine.results: body = ' return %s(%s)' % (routine.name, args_c) if rets: body = body + ', ' + rets else: body = ' %s(%s)\n' % (routine.name, args_c) body = body + ' return ' + rets functions.append(self.pyx_func.format(name=name, arg_string=arg_string, declarations=declarations, body=body)) # Write text to file if self._need_numpy: # Only import numpy if required f.write(self.pyx_imports) f.write('\n'.join(headers)) f.write('\n'.join(functions)) def _partition_args(self, args): """Group function arguments into categories.""" py_args = [] py_returns = [] py_locals = [] py_inferred = {} for arg in args: if isinstance(arg, OutputArgument): py_returns.append(arg) py_locals.append(arg) elif isinstance(arg, InOutArgument): py_returns.append(arg) py_args.append(arg) else: py_args.append(arg) # Find arguments that are array dimensions. These can be inferred # locally in the Cython code. if isinstance(arg, (InputArgument, InOutArgument)) and arg.dimensions: dims = [d[1] + 1 for d in arg.dimensions] sym_dims = [(i, d) for (i, d) in enumerate(dims) if isinstance(d, Symbol)] for (i, d) in sym_dims: py_inferred[d] = (arg.name, i) for arg in args: if arg.name in py_inferred: py_inferred[arg] = py_inferred.pop(arg.name) # Filter inferred arguments from py_args py_args = [a for a in py_args if a not in py_inferred] return py_returns, py_args, py_locals, py_inferred def _prototype_arg(self, arg): mat_dec = "np.ndarray[{mtype}, ndim={ndim}] {name}" np_types = {'double': 'np.double_t', 'int': 'np.int_t'} t = arg.get_datatype('c') if arg.dimensions: self._need_numpy = True ndim = len(arg.dimensions) mtype = np_types[t] return mat_dec.format(mtype=mtype, ndim=ndim, name=self._string_var(arg.name)) else: return "%s %s" % (t, self._string_var(arg.name)) def _declare_arg(self, arg): proto = self._prototype_arg(arg) if arg.dimensions: shape = '(' + ','.join(self._string_var(i[1] + 1) for i in arg.dimensions) + ')' return proto + " = np.empty({shape})".format(shape=shape) else: return proto + " = 0" def _call_arg(self, arg): if arg.dimensions: t = arg.get_datatype('c') return "<{}*> {}.data".format(t, self._string_var(arg.name)) elif isinstance(arg, ResultBase): return "&{}".format(self._string_var(arg.name)) else: return self._string_var(arg.name) def _string_var(self, var): printer = self.generator.printer.doprint return printer(var) class F2PyCodeWrapper(CodeWrapper): """Wrapper that uses f2py""" def __init__(self, *args, **kwargs): ext_keys = ['include_dirs', 'library_dirs', 'libraries', 'extra_compile_args', 'extra_link_args'] msg = ('The compilation option kwarg {} is not supported with the f2py ' 'backend.') for k in ext_keys: if k in kwargs.keys(): warn(msg.format(k)) kwargs.pop(k, None) super().__init__(*args, **kwargs) @property def command(self): filename = self.filename + '.' + self.generator.code_extension args = ['-c', '-m', self.module_name, filename] command = [sys.executable, "-c", "import numpy.f2py as f2py2e;f2py2e.main()"]+args return command def _prepare_files(self, routine): pass @classmethod def _get_wrapped_function(cls, mod, name): return getattr(mod, name) # Here we define a lookup of backends -> tuples of languages. For now, each # tuple is of length 1, but if a backend supports more than one language, # the most preferable language is listed first. _lang_lookup = {'CYTHON': ('C99', 'C89', 'C'), 'F2PY': ('F95',), 'NUMPY': ('C99', 'C89', 'C'), 'DUMMY': ('F95',)} # Dummy here just for testing def _infer_language(backend): """For a given backend, return the top choice of language""" langs = _lang_lookup.get(backend.upper(), False) if not langs: raise ValueError("Unrecognized backend: " + backend) return langs[0] def _validate_backend_language(backend, language): """Throws error if backend and language are incompatible""" langs = _lang_lookup.get(backend.upper(), False) if not langs: raise ValueError("Unrecognized backend: " + backend) if language.upper() not in langs: raise ValueError(("Backend {} and language {} are " "incompatible").format(backend, language)) @cacheit @doctest_depends_on(exe=('f2py', 'gfortran'), modules=('numpy',)) def autowrap(expr, language=None, backend='f2py', tempdir=None, args=None, flags=None, verbose=False, helpers=None, code_gen=None, **kwargs): """Generates python callable binaries based on the math expression. Parameters ========== expr The SymPy expression that should be wrapped as a binary routine. language : string, optional If supplied, (options: 'C' or 'F95'), specifies the language of the generated code. If ``None`` [default], the language is inferred based upon the specified backend. backend : string, optional Backend used to wrap the generated code. Either 'f2py' [default], or 'cython'. tempdir : string, optional Path to directory for temporary files. If this argument is supplied, the generated code and the wrapper input files are left intact in the specified path. args : iterable, optional An ordered iterable of symbols. Specifies the argument sequence for the function. flags : iterable, optional Additional option flags that will be passed to the backend. verbose : bool, optional If True, autowrap will not mute the command line backends. This can be helpful for debugging. helpers : 3-tuple or iterable of 3-tuples, optional Used to define auxiliary expressions needed for the main expr. If the main expression needs to call a specialized function it should be passed in via ``helpers``. Autowrap will then make sure that the compiled main expression can link to the helper routine. Items should be 3-tuples with (, , ). It is mandatory to supply an argument sequence to helper routines. code_gen : CodeGen instance An instance of a CodeGen subclass. Overrides ``language``. include_dirs : [string] A list of directories to search for C/C++ header files (in Unix form for portability). library_dirs : [string] A list of directories to search for C/C++ libraries at link time. libraries : [string] A list of library names (not filenames or paths) to link against. extra_compile_args : [string] Any extra platform- and compiler-specific information to use when compiling the source files in 'sources'. For platforms and compilers where "command line" makes sense, this is typically a list of command-line arguments, but for other platforms it could be anything. extra_link_args : [string] Any extra platform- and compiler-specific information to use when linking object files together to create the extension (or to create a new static Python interpreter). Similar interpretation as for 'extra_compile_args'. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.utilities.autowrap import autowrap >>> expr = ((x - y + z)**(13)).expand() >>> binary_func = autowrap(expr) >>> binary_func(1, 4, 2) -1.0 """ if language: if not isinstance(language, type): _validate_backend_language(backend, language) else: language = _infer_language(backend) # two cases 1) helpers is an iterable of 3-tuples and 2) helpers is a # 3-tuple if iterable(helpers) and len(helpers) != 0 and iterable(helpers[0]): helpers = helpers if helpers else () else: helpers = [helpers] if helpers else () args = list(args) if iterable(args, exclude=set) else args if code_gen is None: code_gen = get_code_generator(language, "autowrap") CodeWrapperClass = { 'F2PY': F2PyCodeWrapper, 'CYTHON': CythonCodeWrapper, 'DUMMY': DummyWrapper }[backend.upper()] code_wrapper = CodeWrapperClass(code_gen, tempdir, flags if flags else (), verbose, **kwargs) helps = [] for name_h, expr_h, args_h in helpers: helps.append(code_gen.routine(name_h, expr_h, args_h)) for name_h, expr_h, args_h in helpers: if expr.has(expr_h): name_h = binary_function(name_h, expr_h, backend='dummy') expr = expr.subs(expr_h, name_h(*args_h)) try: routine = code_gen.routine('autofunc', expr, args) except CodeGenArgumentListError as e: # if all missing arguments are for pure output, we simply attach them # at the end and try again, because the wrappers will silently convert # them to return values anyway. new_args = [] for missing in e.missing_args: if not isinstance(missing, OutputArgument): raise new_args.append(missing.name) routine = code_gen.routine('autofunc', expr, args + new_args) return code_wrapper.wrap_code(routine, helpers=helps) @doctest_depends_on(exe=('f2py', 'gfortran'), modules=('numpy',)) def binary_function(symfunc, expr, **kwargs): """Returns a sympy function with expr as binary implementation This is a convenience function that automates the steps needed to autowrap the SymPy expression and attaching it to a Function object with implemented_function(). Parameters ========== symfunc : sympy Function The function to bind the callable to. expr : sympy Expression The expression used to generate the function. kwargs : dict Any kwargs accepted by autowrap. Examples ======== >>> from sympy.abc import x, y >>> from sympy.utilities.autowrap import binary_function >>> expr = ((x - y)**(25)).expand() >>> f = binary_function('f', expr) >>> type(f) >>> 2*f(x, y) 2*f(x, y) >>> f(x, y).evalf(2, subs={x: 1, y: 2}) -1.0 """ binary = autowrap(expr, **kwargs) return implemented_function(symfunc, binary) ################################################################# # UFUNCIFY # ################################################################# _ufunc_top = Template("""\ #include "Python.h" #include "math.h" #include "numpy/ndarraytypes.h" #include "numpy/ufuncobject.h" #include "numpy/halffloat.h" #include ${include_file} static PyMethodDef ${module}Methods[] = { {NULL, NULL, 0, NULL} };""") _ufunc_outcalls = Template("*((double *)out${outnum}) = ${funcname}(${call_args});") _ufunc_body = Template("""\ static void ${funcname}_ufunc(char **args, npy_intp *dimensions, npy_intp* steps, void* data) { npy_intp i; npy_intp n = dimensions[0]; ${declare_args} ${declare_steps} for (i = 0; i < n; i++) { ${outcalls} ${step_increments} } } PyUFuncGenericFunction ${funcname}_funcs[1] = {&${funcname}_ufunc}; static char ${funcname}_types[${n_types}] = ${types} static void *${funcname}_data[1] = {NULL};""") _ufunc_bottom = Template("""\ #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "${module}", NULL, -1, ${module}Methods, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_${module}(void) { PyObject *m, *d; ${function_creation} m = PyModule_Create(&moduledef); if (!m) { return NULL; } import_array(); import_umath(); d = PyModule_GetDict(m); ${ufunc_init} return m; } #else PyMODINIT_FUNC init${module}(void) { PyObject *m, *d; ${function_creation} m = Py_InitModule("${module}", ${module}Methods); if (m == NULL) { return; } import_array(); import_umath(); d = PyModule_GetDict(m); ${ufunc_init} } #endif\ """) _ufunc_init_form = Template("""\ ufunc${ind} = PyUFunc_FromFuncAndData(${funcname}_funcs, ${funcname}_data, ${funcname}_types, 1, ${n_in}, ${n_out}, PyUFunc_None, "${module}", ${docstring}, 0); PyDict_SetItemString(d, "${funcname}", ufunc${ind}); Py_DECREF(ufunc${ind});""") _ufunc_setup = Template("""\ def configuration(parent_package='', top_path=None): import numpy from numpy.distutils.misc_util import Configuration config = Configuration('', parent_package, top_path) config.add_extension('${module}', sources=['${module}.c', '${filename}.c']) return config if __name__ == "__main__": from numpy.distutils.core import setup setup(configuration=configuration)""") class UfuncifyCodeWrapper(CodeWrapper): """Wrapper for Ufuncify""" def __init__(self, *args, **kwargs): ext_keys = ['include_dirs', 'library_dirs', 'libraries', 'extra_compile_args', 'extra_link_args'] msg = ('The compilation option kwarg {} is not supported with the numpy' ' backend.') for k in ext_keys: if k in kwargs.keys(): warn(msg.format(k)) kwargs.pop(k, None) super().__init__(*args, **kwargs) @property def command(self): command = [sys.executable, "setup.py", "build_ext", "--inplace"] return command def wrap_code(self, routines, helpers=None): # This routine overrides CodeWrapper because we can't assume funcname == routines[0].name # Therefore we have to break the CodeWrapper private API. # There isn't an obvious way to extend multi-expr support to # the other autowrap backends, so we limit this change to ufuncify. helpers = helpers if helpers is not None else [] # We just need a consistent name funcname = 'wrapped_' + str(id(routines) + id(helpers)) workdir = self.filepath or tempfile.mkdtemp("_sympy_compile") if not os.access(workdir, os.F_OK): os.mkdir(workdir) oldwork = os.getcwd() os.chdir(workdir) try: sys.path.append(workdir) self._generate_code(routines, helpers) self._prepare_files(routines, funcname) self._process_files(routines) mod = __import__(self.module_name) finally: sys.path.remove(workdir) CodeWrapper._module_counter += 1 os.chdir(oldwork) if not self.filepath: try: shutil.rmtree(workdir) except OSError: # Could be some issues on Windows pass return self._get_wrapped_function(mod, funcname) def _generate_code(self, main_routines, helper_routines): all_routines = main_routines + helper_routines self.generator.write( all_routines, self.filename, True, self.include_header, self.include_empty) def _prepare_files(self, routines, funcname): # C codefilename = self.module_name + '.c' with open(codefilename, 'w') as f: self.dump_c(routines, f, self.filename, funcname=funcname) # setup.py with open('setup.py', 'w') as f: self.dump_setup(f) @classmethod def _get_wrapped_function(cls, mod, name): return getattr(mod, name) def dump_setup(self, f): setup = _ufunc_setup.substitute(module=self.module_name, filename=self.filename) f.write(setup) def dump_c(self, routines, f, prefix, funcname=None): """Write a C file with python wrappers This file contains all the definitions of the routines in c code. Arguments --------- routines List of Routine instances f File-like object to write the file to prefix The filename prefix, used to name the imported module. funcname Name of the main function to be returned. """ if funcname is None: if len(routines) == 1: funcname = routines[0].name else: msg = 'funcname must be specified for multiple output routines' raise ValueError(msg) functions = [] function_creation = [] ufunc_init = [] module = self.module_name include_file = "\"{}.h\"".format(prefix) top = _ufunc_top.substitute(include_file=include_file, module=module) name = funcname # Partition the C function arguments into categories # Here we assume all routines accept the same arguments r_index = 0 py_in, _ = self._partition_args(routines[0].arguments) n_in = len(py_in) n_out = len(routines) # Declare Args form = "char *{0}{1} = args[{2}];" arg_decs = [form.format('in', i, i) for i in range(n_in)] arg_decs.extend([form.format('out', i, i+n_in) for i in range(n_out)]) declare_args = '\n '.join(arg_decs) # Declare Steps form = "npy_intp {0}{1}_step = steps[{2}];" step_decs = [form.format('in', i, i) for i in range(n_in)] step_decs.extend([form.format('out', i, i+n_in) for i in range(n_out)]) declare_steps = '\n '.join(step_decs) # Call Args form = "*(double *)in{0}" call_args = ', '.join([form.format(a) for a in range(n_in)]) # Step Increments form = "{0}{1} += {0}{1}_step;" step_incs = [form.format('in', i) for i in range(n_in)] step_incs.extend([form.format('out', i, i) for i in range(n_out)]) step_increments = '\n '.join(step_incs) # Types n_types = n_in + n_out types = "{" + ', '.join(["NPY_DOUBLE"]*n_types) + "};" # Docstring docstring = '"Created in SymPy with Ufuncify"' # Function Creation function_creation.append("PyObject *ufunc{};".format(r_index)) # Ufunc initialization init_form = _ufunc_init_form.substitute(module=module, funcname=name, docstring=docstring, n_in=n_in, n_out=n_out, ind=r_index) ufunc_init.append(init_form) outcalls = [_ufunc_outcalls.substitute( outnum=i, call_args=call_args, funcname=routines[i].name) for i in range(n_out)] body = _ufunc_body.substitute(module=module, funcname=name, declare_args=declare_args, declare_steps=declare_steps, call_args=call_args, step_increments=step_increments, n_types=n_types, types=types, outcalls='\n '.join(outcalls)) functions.append(body) body = '\n\n'.join(functions) ufunc_init = '\n '.join(ufunc_init) function_creation = '\n '.join(function_creation) bottom = _ufunc_bottom.substitute(module=module, ufunc_init=ufunc_init, function_creation=function_creation) text = [top, body, bottom] f.write('\n\n'.join(text)) def _partition_args(self, args): """Group function arguments into categories.""" py_in = [] py_out = [] for arg in args: if isinstance(arg, OutputArgument): py_out.append(arg) elif isinstance(arg, InOutArgument): raise ValueError("Ufuncify doesn't support InOutArguments") else: py_in.append(arg) return py_in, py_out @cacheit @doctest_depends_on(exe=('f2py', 'gfortran', 'gcc'), modules=('numpy',)) def ufuncify(args, expr, language=None, backend='numpy', tempdir=None, flags=None, verbose=False, helpers=None, **kwargs): """Generates a binary function that supports broadcasting on numpy arrays. Parameters ========== args : iterable Either a Symbol or an iterable of symbols. Specifies the argument sequence for the function. expr A SymPy expression that defines the element wise operation. language : string, optional If supplied, (options: 'C' or 'F95'), specifies the language of the generated code. If ``None`` [default], the language is inferred based upon the specified backend. backend : string, optional Backend used to wrap the generated code. Either 'numpy' [default], 'cython', or 'f2py'. tempdir : string, optional Path to directory for temporary files. If this argument is supplied, the generated code and the wrapper input files are left intact in the specified path. flags : iterable, optional Additional option flags that will be passed to the backend. verbose : bool, optional If True, autowrap will not mute the command line backends. This can be helpful for debugging. helpers : iterable, optional Used to define auxiliary expressions needed for the main expr. If the main expression needs to call a specialized function it should be put in the ``helpers`` iterable. Autowrap will then make sure that the compiled main expression can link to the helper routine. Items should be tuples with (, , ). It is mandatory to supply an argument sequence to helper routines. kwargs : dict These kwargs will be passed to autowrap if the `f2py` or `cython` backend is used and ignored if the `numpy` backend is used. Notes ===== The default backend ('numpy') will create actual instances of ``numpy.ufunc``. These support ndimensional broadcasting, and implicit type conversion. Use of the other backends will result in a "ufunc-like" function, which requires equal length 1-dimensional arrays for all arguments, and will not perform any type conversions. References ========== .. [1] http://docs.scipy.org/doc/numpy/reference/ufuncs.html Examples ======== >>> from sympy.utilities.autowrap import ufuncify >>> from sympy.abc import x, y >>> import numpy as np >>> f = ufuncify((x, y), y + x**2) >>> type(f) >>> f([1, 2, 3], 2) array([ 3., 6., 11.]) >>> f(np.arange(5), 3) array([ 3., 4., 7., 12., 19.]) For the 'f2py' and 'cython' backends, inputs are required to be equal length 1-dimensional arrays. The 'f2py' backend will perform type conversion, but the Cython backend will error if the inputs are not of the expected type. >>> f_fortran = ufuncify((x, y), y + x**2, backend='f2py') >>> f_fortran(1, 2) array([ 3.]) >>> f_fortran(np.array([1, 2, 3]), np.array([1.0, 2.0, 3.0])) array([ 2., 6., 12.]) >>> f_cython = ufuncify((x, y), y + x**2, backend='Cython') >>> f_cython(1, 2) # doctest: +ELLIPSIS Traceback (most recent call last): ... TypeError: Argument '_x' has incorrect type (expected numpy.ndarray, got int) >>> f_cython(np.array([1.0]), np.array([2.0])) array([ 3.]) """ if isinstance(args, Symbol): args = (args,) else: args = tuple(args) if language: _validate_backend_language(backend, language) else: language = _infer_language(backend) helpers = helpers if helpers else () flags = flags if flags else () if backend.upper() == 'NUMPY': # maxargs is set by numpy compile-time constant NPY_MAXARGS # If a future version of numpy modifies or removes this restriction # this variable should be changed or removed maxargs = 32 helps = [] for name, expr, args in helpers: helps.append(make_routine(name, expr, args)) code_wrapper = UfuncifyCodeWrapper(C99CodeGen("ufuncify"), tempdir, flags, verbose) if not isinstance(expr, (list, tuple)): expr = [expr] if len(expr) == 0: raise ValueError('Expression iterable has zero length') if len(expr) + len(args) > maxargs: msg = ('Cannot create ufunc with more than {0} total arguments: ' 'got {1} in, {2} out') raise ValueError(msg.format(maxargs, len(args), len(expr))) routines = [make_routine('autofunc{}'.format(idx), exprx, args) for idx, exprx in enumerate(expr)] return code_wrapper.wrap_code(routines, helpers=helps) else: # Dummies are used for all added expressions to prevent name clashes # within the original expression. y = IndexedBase(Dummy('y')) m = Dummy('m', integer=True) i = Idx(Dummy('i', integer=True), m) f_dummy = Dummy('f') f = implemented_function('%s_%d' % (f_dummy.name, f_dummy.dummy_index), Lambda(args, expr)) # For each of the args create an indexed version. indexed_args = [IndexedBase(Dummy(str(a))) for a in args] # Order the arguments (out, args, dim) args = [y] + indexed_args + [m] args_with_indices = [a[i] for a in indexed_args] return autowrap(Eq(y[i], f(*args_with_indices)), language, backend, tempdir, args, flags, verbose, helpers, **kwargs) sympy-sympy-1.9/sympy/utilities/benchmarking.py000066400000000000000000000004701412543434000221220ustar00rootroot00000000000000from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="Import sympy.utilities.benchmarking", useinstead="Import from sympy.testing.benchmarking", issue=18095, deprecated_since_version="1.6").warn() from sympy.testing.benchmarking import * # noqa:F401 sympy-sympy-1.9/sympy/utilities/codegen.py000066400000000000000000002370711412543434000211070ustar00rootroot00000000000000""" module for generating C, C++, Fortran77, Fortran90, Julia, Rust and Octave/Matlab routines that evaluate sympy expressions. This module is work in progress. Only the milestones with a '+' character in the list below have been completed. --- How is sympy.utilities.codegen different from sympy.printing.ccode? --- We considered the idea to extend the printing routines for sympy functions in such a way that it prints complete compilable code, but this leads to a few unsurmountable issues that can only be tackled with dedicated code generator: - For C, one needs both a code and a header file, while the printing routines generate just one string. This code generator can be extended to support .pyf files for f2py. - SymPy functions are not concerned with programming-technical issues, such as input, output and input-output arguments. Other examples are contiguous or non-contiguous arrays, including headers of other libraries such as gsl or others. - It is highly interesting to evaluate several sympy functions in one C routine, eventually sharing common intermediate results with the help of the cse routine. This is more than just printing. - From the programming perspective, expressions with constants should be evaluated in the code generator as much as possible. This is different for printing. --- Basic assumptions --- * A generic Routine data structure describes the routine that must be translated into C/Fortran/... code. This data structure covers all features present in one or more of the supported languages. * Descendants from the CodeGen class transform multiple Routine instances into compilable code. Each derived class translates into a specific language. * In many cases, one wants a simple workflow. The friendly functions in the last part are a simple api on top of the Routine/CodeGen stuff. They are easier to use, but are less powerful. --- Milestones --- + First working version with scalar input arguments, generating C code, tests + Friendly functions that are easier to use than the rigorous Routine/CodeGen workflow. + Integer and Real numbers as input and output + Output arguments + InputOutput arguments + Sort input/output arguments properly + Contiguous array arguments (numpy matrices) + Also generate .pyf code for f2py (in autowrap module) + Isolate constants and evaluate them beforehand in double precision + Fortran 90 + Octave/Matlab - Common Subexpression Elimination - User defined comments in the generated code - Optional extra include lines for libraries/objects that can eval special functions - Test other C compilers and libraries: gcc, tcc, libtcc, gcc+gsl, ... - Contiguous array arguments (sympy matrices) - Non-contiguous array arguments (sympy matrices) - ccode must raise an error when it encounters something that can not be translated into c. ccode(integrate(sin(x)/x, x)) does not make sense. - Complex numbers as input and output - A default complex datatype - Include extra information in the header: date, user, hostname, sha1 hash, ... - Fortran 77 - C++ - Python - Julia - Rust - ... """ import os import textwrap from io import StringIO from sympy import __version__ as sympy_version from sympy.core import Symbol, S, Tuple, Equality, Function, Basic from sympy.core.compatibility import is_sequence from sympy.printing.c import c_code_printers from sympy.printing.codeprinter import AssignmentError from sympy.printing.fortran import FCodePrinter from sympy.printing.julia import JuliaCodePrinter from sympy.printing.octave import OctaveCodePrinter from sympy.printing.rust import RustCodePrinter from sympy.tensor import Idx, Indexed, IndexedBase from sympy.matrices import (MatrixSymbol, ImmutableMatrix, MatrixBase, MatrixExpr, MatrixSlice) __all__ = [ # description of routines "Routine", "DataType", "default_datatypes", "get_default_datatype", "Argument", "InputArgument", "OutputArgument", "Result", # routines -> code "CodeGen", "CCodeGen", "FCodeGen", "JuliaCodeGen", "OctaveCodeGen", "RustCodeGen", # friendly functions "codegen", "make_routine", ] # # Description of routines # class Routine: """Generic description of evaluation routine for set of expressions. A CodeGen class can translate instances of this class into code in a particular language. The routine specification covers all the features present in these languages. The CodeGen part must raise an exception when certain features are not present in the target language. For example, multiple return values are possible in Python, but not in C or Fortran. Another example: Fortran and Python support complex numbers, while C does not. """ def __init__(self, name, arguments, results, local_vars, global_vars): """Initialize a Routine instance. Parameters ========== name : string Name of the routine. arguments : list of Arguments These are things that appear in arguments of a routine, often appearing on the right-hand side of a function call. These are commonly InputArguments but in some languages, they can also be OutputArguments or InOutArguments (e.g., pass-by-reference in C code). results : list of Results These are the return values of the routine, often appearing on the left-hand side of a function call. The difference between Results and OutputArguments and when you should use each is language-specific. local_vars : list of Results These are variables that will be defined at the beginning of the function. global_vars : list of Symbols Variables which will not be passed into the function. """ # extract all input symbols and all symbols appearing in an expression input_symbols = set() symbols = set() for arg in arguments: if isinstance(arg, OutputArgument): symbols.update(arg.expr.free_symbols - arg.expr.atoms(Indexed)) elif isinstance(arg, InputArgument): input_symbols.add(arg.name) elif isinstance(arg, InOutArgument): input_symbols.add(arg.name) symbols.update(arg.expr.free_symbols - arg.expr.atoms(Indexed)) else: raise ValueError("Unknown Routine argument: %s" % arg) for r in results: if not isinstance(r, Result): raise ValueError("Unknown Routine result: %s" % r) symbols.update(r.expr.free_symbols - r.expr.atoms(Indexed)) local_symbols = set() for r in local_vars: if isinstance(r, Result): symbols.update(r.expr.free_symbols - r.expr.atoms(Indexed)) local_symbols.add(r.name) else: local_symbols.add(r) symbols = {s.label if isinstance(s, Idx) else s for s in symbols} # Check that all symbols in the expressions are covered by # InputArguments/InOutArguments---subset because user could # specify additional (unused) InputArguments or local_vars. notcovered = symbols.difference( input_symbols.union(local_symbols).union(global_vars)) if notcovered != set(): raise ValueError("Symbols needed for output are not in input " + ", ".join([str(x) for x in notcovered])) self.name = name self.arguments = arguments self.results = results self.local_vars = local_vars self.global_vars = global_vars def __str__(self): return self.__class__.__name__ + "({name!r}, {arguments}, {results}, {local_vars}, {global_vars})".format(**self.__dict__) __repr__ = __str__ @property def variables(self): """Returns a set of all variables possibly used in the routine. For routines with unnamed return values, the dummies that may or may not be used will be included in the set. """ v = set(self.local_vars) for arg in self.arguments: v.add(arg.name) for res in self.results: v.add(res.result_var) return v @property def result_variables(self): """Returns a list of OutputArgument, InOutArgument and Result. If return values are present, they are at the end ot the list. """ args = [arg for arg in self.arguments if isinstance( arg, (OutputArgument, InOutArgument))] args.extend(self.results) return args class DataType: """Holds strings for a certain datatype in different languages.""" def __init__(self, cname, fname, pyname, jlname, octname, rsname): self.cname = cname self.fname = fname self.pyname = pyname self.jlname = jlname self.octname = octname self.rsname = rsname default_datatypes = { "int": DataType("int", "INTEGER*4", "int", "", "", "i32"), "float": DataType("double", "REAL*8", "float", "", "", "f64"), "complex": DataType("double", "COMPLEX*16", "complex", "", "", "float") #FIXME: # complex is only supported in fortran, python, julia, and octave. # So to not break c or rust code generation, we stick with double or # float, respecitvely (but actually should raise an exception for # explicitly complex variables (x.is_complex==True)) } COMPLEX_ALLOWED = False def get_default_datatype(expr, complex_allowed=None): """Derives an appropriate datatype based on the expression.""" if complex_allowed is None: complex_allowed = COMPLEX_ALLOWED if complex_allowed: final_dtype = "complex" else: final_dtype = "float" if expr.is_integer: return default_datatypes["int"] elif expr.is_real: return default_datatypes["float"] elif isinstance(expr, MatrixBase): #check all entries dt = "int" for element in expr: if dt == "int" and not element.is_integer: dt = "float" if dt == "float" and not element.is_real: return default_datatypes[final_dtype] return default_datatypes[dt] else: return default_datatypes[final_dtype] class Variable: """Represents a typed variable.""" def __init__(self, name, datatype=None, dimensions=None, precision=None): """Return a new variable. Parameters ========== name : Symbol or MatrixSymbol datatype : optional When not given, the data type will be guessed based on the assumptions on the symbol argument. dimension : sequence containing tupes, optional If present, the argument is interpreted as an array, where this sequence of tuples specifies (lower, upper) bounds for each index of the array. precision : int, optional Controls the precision of floating point constants. """ if not isinstance(name, (Symbol, MatrixSymbol)): raise TypeError("The first argument must be a sympy symbol.") if datatype is None: datatype = get_default_datatype(name) elif not isinstance(datatype, DataType): raise TypeError("The (optional) `datatype' argument must be an " "instance of the DataType class.") if dimensions and not isinstance(dimensions, (tuple, list)): raise TypeError( "The dimension argument must be a sequence of tuples") self._name = name self._datatype = { 'C': datatype.cname, 'FORTRAN': datatype.fname, 'JULIA': datatype.jlname, 'OCTAVE': datatype.octname, 'PYTHON': datatype.pyname, 'RUST': datatype.rsname, } self.dimensions = dimensions self.precision = precision def __str__(self): return "%s(%r)" % (self.__class__.__name__, self.name) __repr__ = __str__ @property def name(self): return self._name def get_datatype(self, language): """Returns the datatype string for the requested language. Examples ======== >>> from sympy import Symbol >>> from sympy.utilities.codegen import Variable >>> x = Variable(Symbol('x')) >>> x.get_datatype('c') 'double' >>> x.get_datatype('fortran') 'REAL*8' """ try: return self._datatype[language.upper()] except KeyError: raise CodeGenError("Has datatypes for languages: %s" % ", ".join(self._datatype)) class Argument(Variable): """An abstract Argument data structure: a name and a data type. This structure is refined in the descendants below. """ pass class InputArgument(Argument): pass class ResultBase: """Base class for all "outgoing" information from a routine. Objects of this class stores a sympy expression, and a sympy object representing a result variable that will be used in the generated code only if necessary. """ def __init__(self, expr, result_var): self.expr = expr self.result_var = result_var def __str__(self): return "%s(%r, %r)" % (self.__class__.__name__, self.expr, self.result_var) __repr__ = __str__ class OutputArgument(Argument, ResultBase): """OutputArgument are always initialized in the routine.""" def __init__(self, name, result_var, expr, datatype=None, dimensions=None, precision=None): """Return a new variable. Parameters ========== name : Symbol, MatrixSymbol The name of this variable. When used for code generation, this might appear, for example, in the prototype of function in the argument list. result_var : Symbol, Indexed Something that can be used to assign a value to this variable. Typically the same as `name` but for Indexed this should be e.g., "y[i]" whereas `name` should be the Symbol "y". expr : object The expression that should be output, typically a SymPy expression. datatype : optional When not given, the data type will be guessed based on the assumptions on the symbol argument. dimension : sequence containing tupes, optional If present, the argument is interpreted as an array, where this sequence of tuples specifies (lower, upper) bounds for each index of the array. precision : int, optional Controls the precision of floating point constants. """ Argument.__init__(self, name, datatype, dimensions, precision) ResultBase.__init__(self, expr, result_var) def __str__(self): return "%s(%r, %r, %r)" % (self.__class__.__name__, self.name, self.result_var, self.expr) __repr__ = __str__ class InOutArgument(Argument, ResultBase): """InOutArgument are never initialized in the routine.""" def __init__(self, name, result_var, expr, datatype=None, dimensions=None, precision=None): if not datatype: datatype = get_default_datatype(expr) Argument.__init__(self, name, datatype, dimensions, precision) ResultBase.__init__(self, expr, result_var) __init__.__doc__ = OutputArgument.__init__.__doc__ def __str__(self): return "%s(%r, %r, %r)" % (self.__class__.__name__, self.name, self.expr, self.result_var) __repr__ = __str__ class Result(Variable, ResultBase): """An expression for a return value. The name result is used to avoid conflicts with the reserved word "return" in the python language. It is also shorter than ReturnValue. These may or may not need a name in the destination (e.g., "return(x*y)" might return a value without ever naming it). """ def __init__(self, expr, name=None, result_var=None, datatype=None, dimensions=None, precision=None): """Initialize a return value. Parameters ========== expr : SymPy expression name : Symbol, MatrixSymbol, optional The name of this return variable. When used for code generation, this might appear, for example, in the prototype of function in a list of return values. A dummy name is generated if omitted. result_var : Symbol, Indexed, optional Something that can be used to assign a value to this variable. Typically the same as `name` but for Indexed this should be e.g., "y[i]" whereas `name` should be the Symbol "y". Defaults to `name` if omitted. datatype : optional When not given, the data type will be guessed based on the assumptions on the expr argument. dimension : sequence containing tupes, optional If present, this variable is interpreted as an array, where this sequence of tuples specifies (lower, upper) bounds for each index of the array. precision : int, optional Controls the precision of floating point constants. """ # Basic because it is the base class for all types of expressions if not isinstance(expr, (Basic, MatrixBase)): raise TypeError("The first argument must be a sympy expression.") if name is None: name = 'result_%d' % abs(hash(expr)) if datatype is None: #try to infer data type from the expression datatype = get_default_datatype(expr) if isinstance(name, str): if isinstance(expr, (MatrixBase, MatrixExpr)): name = MatrixSymbol(name, *expr.shape) else: name = Symbol(name) if result_var is None: result_var = name Variable.__init__(self, name, datatype=datatype, dimensions=dimensions, precision=precision) ResultBase.__init__(self, expr, result_var) def __str__(self): return "%s(%r, %r, %r)" % (self.__class__.__name__, self.expr, self.name, self.result_var) __repr__ = __str__ # # Transformation of routine objects into code # class CodeGen: """Abstract class for the code generators.""" printer = None # will be set to an instance of a CodePrinter subclass def _indent_code(self, codelines): return self.printer.indent_code(codelines) def _printer_method_with_settings(self, method, settings=None, *args, **kwargs): settings = settings or {} ori = {k: self.printer._settings[k] for k in settings} for k, v in settings.items(): self.printer._settings[k] = v result = getattr(self.printer, method)(*args, **kwargs) for k, v in ori.items(): self.printer._settings[k] = v return result def _get_symbol(self, s): """Returns the symbol as fcode prints it.""" if self.printer._settings['human']: expr_str = self.printer.doprint(s) else: constants, not_supported, expr_str = self.printer.doprint(s) if constants or not_supported: raise ValueError("Failed to print %s" % str(s)) return expr_str.strip() def __init__(self, project="project", cse=False): """Initialize a code generator. Derived classes will offer more options that affect the generated code. """ self.project = project self.cse = cse def routine(self, name, expr, argument_sequence=None, global_vars=None): """Creates an Routine object that is appropriate for this language. This implementation is appropriate for at least C/Fortran. Subclasses can override this if necessary. Here, we assume at most one return value (the l-value) which must be scalar. Additional outputs are OutputArguments (e.g., pointers on right-hand-side or pass-by-reference). Matrices are always returned via OutputArguments. If ``argument_sequence`` is None, arguments will be ordered alphabetically, but with all InputArguments first, and then OutputArgument and InOutArguments. """ if self.cse: from sympy.simplify.cse_main import cse if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): if not expr: raise ValueError("No expression given") for e in expr: if not e.is_Equality: raise CodeGenError("Lists of expressions must all be Equalities. {} is not.".format(e)) # create a list of right hand sides and simplify them rhs = [e.rhs for e in expr] common, simplified = cse(rhs) # pack the simplified expressions back up with their left hand sides expr = [Equality(e.lhs, rhs) for e, rhs in zip(expr, simplified)] else: if isinstance(expr, Equality): common, simplified = cse(expr.rhs) #, ignore=in_out_args) expr = Equality(expr.lhs, simplified[0]) else: common, simplified = cse(expr) expr = simplified local_vars = [Result(b,a) for a,b in common] local_symbols = {a for a,_ in common} local_expressions = Tuple(*[b for _,b in common]) else: local_expressions = Tuple() if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): if not expr: raise ValueError("No expression given") expressions = Tuple(*expr) else: expressions = Tuple(expr) if self.cse: if {i.label for i in expressions.atoms(Idx)} != set(): raise CodeGenError("CSE and Indexed expressions do not play well together yet") else: # local variables for indexed expressions local_vars = {i.label for i in expressions.atoms(Idx)} local_symbols = local_vars # global variables global_vars = set() if global_vars is None else set(global_vars) # symbols that should be arguments symbols = (expressions.free_symbols | local_expressions.free_symbols) - local_symbols - global_vars new_symbols = set() new_symbols.update(symbols) for symbol in symbols: if isinstance(symbol, Idx): new_symbols.remove(symbol) new_symbols.update(symbol.args[1].free_symbols) if isinstance(symbol, Indexed): new_symbols.remove(symbol) symbols = new_symbols # Decide whether to use output argument or return value return_val = [] output_args = [] for expr in expressions: if isinstance(expr, Equality): out_arg = expr.lhs expr = expr.rhs if isinstance(out_arg, Indexed): dims = tuple([ (S.Zero, dim - 1) for dim in out_arg.shape]) symbol = out_arg.base.label elif isinstance(out_arg, Symbol): dims = [] symbol = out_arg elif isinstance(out_arg, MatrixSymbol): dims = tuple([ (S.Zero, dim - 1) for dim in out_arg.shape]) symbol = out_arg else: raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " "can define output arguments.") if expr.has(symbol): output_args.append( InOutArgument(symbol, out_arg, expr, dimensions=dims)) else: output_args.append( OutputArgument(symbol, out_arg, expr, dimensions=dims)) # remove duplicate arguments when they are not local variables if symbol not in local_vars: # avoid duplicate arguments symbols.remove(symbol) elif isinstance(expr, (ImmutableMatrix, MatrixSlice)): # Create a "dummy" MatrixSymbol to use as the Output arg out_arg = MatrixSymbol('out_%s' % abs(hash(expr)), *expr.shape) dims = tuple([(S.Zero, dim - 1) for dim in out_arg.shape]) output_args.append( OutputArgument(out_arg, out_arg, expr, dimensions=dims)) else: return_val.append(Result(expr)) arg_list = [] # setup input argument list # helper to get dimensions for data for array-like args def dimensions(s): return [(S.Zero, dim - 1) for dim in s.shape] array_symbols = {} for array in expressions.atoms(Indexed) | local_expressions.atoms(Indexed): array_symbols[array.base.label] = array for array in expressions.atoms(MatrixSymbol) | local_expressions.atoms(MatrixSymbol): array_symbols[array] = array for symbol in sorted(symbols, key=str): if symbol in array_symbols: array = array_symbols[symbol] metadata = {'dimensions': dimensions(array)} else: metadata = {} arg_list.append(InputArgument(symbol, **metadata)) output_args.sort(key=lambda x: str(x.name)) arg_list.extend(output_args) if argument_sequence is not None: # if the user has supplied IndexedBase instances, we'll accept that new_sequence = [] for arg in argument_sequence: if isinstance(arg, IndexedBase): new_sequence.append(arg.label) else: new_sequence.append(arg) argument_sequence = new_sequence missing = [x for x in arg_list if x.name not in argument_sequence] if missing: msg = "Argument list didn't specify: {0} " msg = msg.format(", ".join([str(m.name) for m in missing])) raise CodeGenArgumentListError(msg, missing) # create redundant arguments to produce the requested sequence name_arg_dict = {x.name: x for x in arg_list} new_args = [] for symbol in argument_sequence: try: new_args.append(name_arg_dict[symbol]) except KeyError: if isinstance(symbol, (IndexedBase, MatrixSymbol)): metadata = {'dimensions': dimensions(symbol)} else: metadata = {} new_args.append(InputArgument(symbol, **metadata)) arg_list = new_args return Routine(name, arg_list, return_val, local_vars, global_vars) def write(self, routines, prefix, to_files=False, header=True, empty=True): """Writes all the source code files for the given routines. The generated source is returned as a list of (filename, contents) tuples, or is written to files (see below). Each filename consists of the given prefix, appended with an appropriate extension. Parameters ========== routines : list A list of Routine instances to be written prefix : string The prefix for the output files to_files : bool, optional When True, the output is written to files. Otherwise, a list of (filename, contents) tuples is returned. [default: False] header : bool, optional When True, a header comment is included on top of each source file. [default: True] empty : bool, optional When True, empty lines are included to structure the source files. [default: True] """ if to_files: for dump_fn in self.dump_fns: filename = "%s.%s" % (prefix, dump_fn.extension) with open(filename, "w") as f: dump_fn(self, routines, f, prefix, header, empty) else: result = [] for dump_fn in self.dump_fns: filename = "%s.%s" % (prefix, dump_fn.extension) contents = StringIO() dump_fn(self, routines, contents, prefix, header, empty) result.append((filename, contents.getvalue())) return result def dump_code(self, routines, f, prefix, header=True, empty=True): """Write the code by calling language specific methods. The generated file contains all the definitions of the routines in low-level code and refers to the header file if appropriate. Parameters ========== routines : list A list of Routine instances. f : file-like Where to write the file. prefix : string The filename prefix, used to refer to the proper header file. Only the basename of the prefix is used. header : bool, optional When True, a header comment is included on top of each source file. [default : True] empty : bool, optional When True, empty lines are included to structure the source files. [default : True] """ code_lines = self._preprocessor_statements(prefix) for routine in routines: if empty: code_lines.append("\n") code_lines.extend(self._get_routine_opening(routine)) code_lines.extend(self._declare_arguments(routine)) code_lines.extend(self._declare_globals(routine)) code_lines.extend(self._declare_locals(routine)) if empty: code_lines.append("\n") code_lines.extend(self._call_printer(routine)) if empty: code_lines.append("\n") code_lines.extend(self._get_routine_ending(routine)) code_lines = self._indent_code(''.join(code_lines)) if header: code_lines = ''.join(self._get_header() + [code_lines]) if code_lines: f.write(code_lines) class CodeGenError(Exception): pass class CodeGenArgumentListError(Exception): @property def missing_args(self): return self.args[1] header_comment = """Code generated with sympy %(version)s See http://www.sympy.org/ for more information. This file is part of '%(project)s' """ class CCodeGen(CodeGen): """Generator for C code. The .write() method inherited from CodeGen will output a code file and an interface file, .c and .h respectively. """ code_extension = "c" interface_extension = "h" standard = 'c99' def __init__(self, project="project", printer=None, preprocessor_statements=None, cse=False): super().__init__(project=project, cse=cse) self.printer = printer or c_code_printers[self.standard.lower()]() self.preprocessor_statements = preprocessor_statements if preprocessor_statements is None: self.preprocessor_statements = ['#include '] def _get_header(self): """Writes a common header for the generated files.""" code_lines = [] code_lines.append("/" + "*"*78 + '\n') tmp = header_comment % {"version": sympy_version, "project": self.project} for line in tmp.splitlines(): code_lines.append(" *%s*\n" % line.center(76)) code_lines.append(" " + "*"*78 + "/\n") return code_lines def get_prototype(self, routine): """Returns a string for the function prototype of the routine. If the routine has multiple result objects, an CodeGenError is raised. See: https://en.wikipedia.org/wiki/Function_prototype """ if len(routine.results) > 1: raise CodeGenError("C only supports a single or no return value.") elif len(routine.results) == 1: ctype = routine.results[0].get_datatype('C') else: ctype = "void" type_args = [] for arg in routine.arguments: name = self.printer.doprint(arg.name) if arg.dimensions or isinstance(arg, ResultBase): type_args.append((arg.get_datatype('C'), "*%s" % name)) else: type_args.append((arg.get_datatype('C'), name)) arguments = ", ".join([ "%s %s" % t for t in type_args]) return "%s %s(%s)" % (ctype, routine.name, arguments) def _preprocessor_statements(self, prefix): code_lines = [] code_lines.append('#include "{}.h"'.format(os.path.basename(prefix))) code_lines.extend(self.preprocessor_statements) code_lines = ['{}\n'.format(l) for l in code_lines] return code_lines def _get_routine_opening(self, routine): prototype = self.get_prototype(routine) return ["%s {\n" % prototype] def _declare_arguments(self, routine): # arguments are declared in prototype return [] def _declare_globals(self, routine): # global variables are not explicitly declared within C functions return [] def _declare_locals(self, routine): # Compose a list of symbols to be dereferenced in the function # body. These are the arguments that were passed by a reference # pointer, excluding arrays. dereference = [] for arg in routine.arguments: if isinstance(arg, ResultBase) and not arg.dimensions: dereference.append(arg.name) code_lines = [] for result in routine.local_vars: # local variables that are simple symbols such as those used as indices into # for loops are defined declared elsewhere. if not isinstance(result, Result): continue if result.name != result.result_var: raise CodeGen("Result variable and name should match: {}".format(result)) assign_to = result.name t = result.get_datatype('c') if isinstance(result.expr, (MatrixBase, MatrixExpr)): dims = result.expr.shape code_lines.append("{} {}[{}];\n".format(t, str(assign_to), dims[0]*dims[1])) prefix = "" else: prefix = "const {} ".format(t) constants, not_c, c_expr = self._printer_method_with_settings( 'doprint', dict(human=False, dereference=dereference), result.expr, assign_to=assign_to) for name, value in sorted(constants, key=str): code_lines.append("double const %s = %s;\n" % (name, value)) code_lines.append("{}{}\n".format(prefix, c_expr)) return code_lines def _call_printer(self, routine): code_lines = [] # Compose a list of symbols to be dereferenced in the function # body. These are the arguments that were passed by a reference # pointer, excluding arrays. dereference = [] for arg in routine.arguments: if isinstance(arg, ResultBase) and not arg.dimensions: dereference.append(arg.name) return_val = None for result in routine.result_variables: if isinstance(result, Result): assign_to = routine.name + "_result" t = result.get_datatype('c') code_lines.append("{} {};\n".format(t, str(assign_to))) return_val = assign_to else: assign_to = result.result_var try: constants, not_c, c_expr = self._printer_method_with_settings( 'doprint', dict(human=False, dereference=dereference), result.expr, assign_to=assign_to) except AssignmentError: assign_to = result.result_var code_lines.append( "%s %s;\n" % (result.get_datatype('c'), str(assign_to))) constants, not_c, c_expr = self._printer_method_with_settings( 'doprint', dict(human=False, dereference=dereference), result.expr, assign_to=assign_to) for name, value in sorted(constants, key=str): code_lines.append("double const %s = %s;\n" % (name, value)) code_lines.append("%s\n" % c_expr) if return_val: code_lines.append(" return %s;\n" % return_val) return code_lines def _get_routine_ending(self, routine): return ["}\n"] def dump_c(self, routines, f, prefix, header=True, empty=True): self.dump_code(routines, f, prefix, header, empty) dump_c.extension = code_extension # type: ignore dump_c.__doc__ = CodeGen.dump_code.__doc__ def dump_h(self, routines, f, prefix, header=True, empty=True): """Writes the C header file. This file contains all the function declarations. Parameters ========== routines : list A list of Routine instances. f : file-like Where to write the file. prefix : string The filename prefix, used to construct the include guards. Only the basename of the prefix is used. header : bool, optional When True, a header comment is included on top of each source file. [default : True] empty : bool, optional When True, empty lines are included to structure the source files. [default : True] """ if header: print(''.join(self._get_header()), file=f) guard_name = "%s__%s__H" % (self.project.replace( " ", "_").upper(), prefix.replace("/", "_").upper()) # include guards if empty: print(file=f) print("#ifndef %s" % guard_name, file=f) print("#define %s" % guard_name, file=f) if empty: print(file=f) # declaration of the function prototypes for routine in routines: prototype = self.get_prototype(routine) print("%s;" % prototype, file=f) # end if include guards if empty: print(file=f) print("#endif", file=f) if empty: print(file=f) dump_h.extension = interface_extension # type: ignore # This list of dump functions is used by CodeGen.write to know which dump # functions it has to call. dump_fns = [dump_c, dump_h] class C89CodeGen(CCodeGen): standard = 'C89' class C99CodeGen(CCodeGen): standard = 'C99' class FCodeGen(CodeGen): """Generator for Fortran 95 code The .write() method inherited from CodeGen will output a code file and an interface file, .f90 and .h respectively. """ code_extension = "f90" interface_extension = "h" def __init__(self, project='project', printer=None): super().__init__(project) self.printer = printer or FCodePrinter() def _get_header(self): """Writes a common header for the generated files.""" code_lines = [] code_lines.append("!" + "*"*78 + '\n') tmp = header_comment % {"version": sympy_version, "project": self.project} for line in tmp.splitlines(): code_lines.append("!*%s*\n" % line.center(76)) code_lines.append("!" + "*"*78 + '\n') return code_lines def _preprocessor_statements(self, prefix): return [] def _get_routine_opening(self, routine): """Returns the opening statements of the fortran routine.""" code_list = [] if len(routine.results) > 1: raise CodeGenError( "Fortran only supports a single or no return value.") elif len(routine.results) == 1: result = routine.results[0] code_list.append(result.get_datatype('fortran')) code_list.append("function") else: code_list.append("subroutine") args = ", ".join("%s" % self._get_symbol(arg.name) for arg in routine.arguments) call_sig = "{}({})\n".format(routine.name, args) # Fortran 95 requires all lines be less than 132 characters, so wrap # this line before appending. call_sig = ' &\n'.join(textwrap.wrap(call_sig, width=60, break_long_words=False)) + '\n' code_list.append(call_sig) code_list = [' '.join(code_list)] code_list.append('implicit none\n') return code_list def _declare_arguments(self, routine): # argument type declarations code_list = [] array_list = [] scalar_list = [] for arg in routine.arguments: if isinstance(arg, InputArgument): typeinfo = "%s, intent(in)" % arg.get_datatype('fortran') elif isinstance(arg, InOutArgument): typeinfo = "%s, intent(inout)" % arg.get_datatype('fortran') elif isinstance(arg, OutputArgument): typeinfo = "%s, intent(out)" % arg.get_datatype('fortran') else: raise CodeGenError("Unknown Argument type: %s" % type(arg)) fprint = self._get_symbol if arg.dimensions: # fortran arrays start at 1 dimstr = ", ".join(["%s:%s" % ( fprint(dim[0] + 1), fprint(dim[1] + 1)) for dim in arg.dimensions]) typeinfo += ", dimension(%s)" % dimstr array_list.append("%s :: %s\n" % (typeinfo, fprint(arg.name))) else: scalar_list.append("%s :: %s\n" % (typeinfo, fprint(arg.name))) # scalars first, because they can be used in array declarations code_list.extend(scalar_list) code_list.extend(array_list) return code_list def _declare_globals(self, routine): # Global variables not explicitly declared within Fortran 90 functions. # Note: a future F77 mode may need to generate "common" blocks. return [] def _declare_locals(self, routine): code_list = [] for var in sorted(routine.local_vars, key=str): typeinfo = get_default_datatype(var) code_list.append("%s :: %s\n" % ( typeinfo.fname, self._get_symbol(var))) return code_list def _get_routine_ending(self, routine): """Returns the closing statements of the fortran routine.""" if len(routine.results) == 1: return ["end function\n"] else: return ["end subroutine\n"] def get_interface(self, routine): """Returns a string for the function interface. The routine should have a single result object, which can be None. If the routine has multiple result objects, a CodeGenError is raised. See: https://en.wikipedia.org/wiki/Function_prototype """ prototype = [ "interface\n" ] prototype.extend(self._get_routine_opening(routine)) prototype.extend(self._declare_arguments(routine)) prototype.extend(self._get_routine_ending(routine)) prototype.append("end interface\n") return "".join(prototype) def _call_printer(self, routine): declarations = [] code_lines = [] for result in routine.result_variables: if isinstance(result, Result): assign_to = routine.name elif isinstance(result, (OutputArgument, InOutArgument)): assign_to = result.result_var constants, not_fortran, f_expr = self._printer_method_with_settings( 'doprint', dict(human=False, source_format='free', standard=95), result.expr, assign_to=assign_to) for obj, v in sorted(constants, key=str): t = get_default_datatype(obj) declarations.append( "%s, parameter :: %s = %s\n" % (t.fname, obj, v)) for obj in sorted(not_fortran, key=str): t = get_default_datatype(obj) if isinstance(obj, Function): name = obj.func else: name = obj declarations.append("%s :: %s\n" % (t.fname, name)) code_lines.append("%s\n" % f_expr) return declarations + code_lines def _indent_code(self, codelines): return self._printer_method_with_settings( 'indent_code', dict(human=False, source_format='free'), codelines) def dump_f95(self, routines, f, prefix, header=True, empty=True): # check that symbols are unique with ignorecase for r in routines: lowercase = {str(x).lower() for x in r.variables} orig_case = {str(x) for x in r.variables} if len(lowercase) < len(orig_case): raise CodeGenError("Fortran ignores case. Got symbols: %s" % (", ".join([str(var) for var in r.variables]))) self.dump_code(routines, f, prefix, header, empty) dump_f95.extension = code_extension # type: ignore dump_f95.__doc__ = CodeGen.dump_code.__doc__ def dump_h(self, routines, f, prefix, header=True, empty=True): """Writes the interface to a header file. This file contains all the function declarations. Parameters ========== routines : list A list of Routine instances. f : file-like Where to write the file. prefix : string The filename prefix. header : bool, optional When True, a header comment is included on top of each source file. [default : True] empty : bool, optional When True, empty lines are included to structure the source files. [default : True] """ if header: print(''.join(self._get_header()), file=f) if empty: print(file=f) # declaration of the function prototypes for routine in routines: prototype = self.get_interface(routine) f.write(prototype) if empty: print(file=f) dump_h.extension = interface_extension # type: ignore # This list of dump functions is used by CodeGen.write to know which dump # functions it has to call. dump_fns = [dump_f95, dump_h] class JuliaCodeGen(CodeGen): """Generator for Julia code. The .write() method inherited from CodeGen will output a code file .jl. """ code_extension = "jl" def __init__(self, project='project', printer=None): super().__init__(project) self.printer = printer or JuliaCodePrinter() def routine(self, name, expr, argument_sequence, global_vars): """Specialized Routine creation for Julia.""" if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): if not expr: raise ValueError("No expression given") expressions = Tuple(*expr) else: expressions = Tuple(expr) # local variables local_vars = {i.label for i in expressions.atoms(Idx)} # global variables global_vars = set() if global_vars is None else set(global_vars) # symbols that should be arguments old_symbols = expressions.free_symbols - local_vars - global_vars symbols = set() for s in old_symbols: if isinstance(s, Idx): symbols.update(s.args[1].free_symbols) elif not isinstance(s, Indexed): symbols.add(s) # Julia supports multiple return values return_vals = [] output_args = [] for (i, expr) in enumerate(expressions): if isinstance(expr, Equality): out_arg = expr.lhs expr = expr.rhs symbol = out_arg if isinstance(out_arg, Indexed): dims = tuple([ (S.One, dim) for dim in out_arg.shape]) symbol = out_arg.base.label output_args.append(InOutArgument(symbol, out_arg, expr, dimensions=dims)) if not isinstance(out_arg, (Indexed, Symbol, MatrixSymbol)): raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " "can define output arguments.") return_vals.append(Result(expr, name=symbol, result_var=out_arg)) if not expr.has(symbol): # this is a pure output: remove from the symbols list, so # it doesn't become an input. symbols.remove(symbol) else: # we have no name for this output return_vals.append(Result(expr, name='out%d' % (i+1))) # setup input argument list output_args.sort(key=lambda x: str(x.name)) arg_list = list(output_args) array_symbols = {} for array in expressions.atoms(Indexed): array_symbols[array.base.label] = array for array in expressions.atoms(MatrixSymbol): array_symbols[array] = array for symbol in sorted(symbols, key=str): arg_list.append(InputArgument(symbol)) if argument_sequence is not None: # if the user has supplied IndexedBase instances, we'll accept that new_sequence = [] for arg in argument_sequence: if isinstance(arg, IndexedBase): new_sequence.append(arg.label) else: new_sequence.append(arg) argument_sequence = new_sequence missing = [x for x in arg_list if x.name not in argument_sequence] if missing: msg = "Argument list didn't specify: {0} " msg = msg.format(", ".join([str(m.name) for m in missing])) raise CodeGenArgumentListError(msg, missing) # create redundant arguments to produce the requested sequence name_arg_dict = {x.name: x for x in arg_list} new_args = [] for symbol in argument_sequence: try: new_args.append(name_arg_dict[symbol]) except KeyError: new_args.append(InputArgument(symbol)) arg_list = new_args return Routine(name, arg_list, return_vals, local_vars, global_vars) def _get_header(self): """Writes a common header for the generated files.""" code_lines = [] tmp = header_comment % {"version": sympy_version, "project": self.project} for line in tmp.splitlines(): if line == '': code_lines.append("#\n") else: code_lines.append("# %s\n" % line) return code_lines def _preprocessor_statements(self, prefix): return [] def _get_routine_opening(self, routine): """Returns the opening statements of the routine.""" code_list = [] code_list.append("function ") # Inputs args = [] for i, arg in enumerate(routine.arguments): if isinstance(arg, OutputArgument): raise CodeGenError("Julia: invalid argument of type %s" % str(type(arg))) if isinstance(arg, (InputArgument, InOutArgument)): args.append("%s" % self._get_symbol(arg.name)) args = ", ".join(args) code_list.append("%s(%s)\n" % (routine.name, args)) code_list = [ "".join(code_list) ] return code_list def _declare_arguments(self, routine): return [] def _declare_globals(self, routine): return [] def _declare_locals(self, routine): return [] def _get_routine_ending(self, routine): outs = [] for result in routine.results: if isinstance(result, Result): # Note: name not result_var; want `y` not `y[i]` for Indexed s = self._get_symbol(result.name) else: raise CodeGenError("unexpected object in Routine results") outs.append(s) return ["return " + ", ".join(outs) + "\nend\n"] def _call_printer(self, routine): declarations = [] code_lines = [] for i, result in enumerate(routine.results): if isinstance(result, Result): assign_to = result.result_var else: raise CodeGenError("unexpected object in Routine results") constants, not_supported, jl_expr = self._printer_method_with_settings( 'doprint', dict(human=False), result.expr, assign_to=assign_to) for obj, v in sorted(constants, key=str): declarations.append( "%s = %s\n" % (obj, v)) for obj in sorted(not_supported, key=str): if isinstance(obj, Function): name = obj.func else: name = obj declarations.append( "# unsupported: %s\n" % (name)) code_lines.append("%s\n" % (jl_expr)) return declarations + code_lines def _indent_code(self, codelines): # Note that indenting seems to happen twice, first # statement-by-statement by JuliaPrinter then again here. p = JuliaCodePrinter({'human': False}) return p.indent_code(codelines) def dump_jl(self, routines, f, prefix, header=True, empty=True): self.dump_code(routines, f, prefix, header, empty) dump_jl.extension = code_extension # type: ignore dump_jl.__doc__ = CodeGen.dump_code.__doc__ # This list of dump functions is used by CodeGen.write to know which dump # functions it has to call. dump_fns = [dump_jl] class OctaveCodeGen(CodeGen): """Generator for Octave code. The .write() method inherited from CodeGen will output a code file .m. Octave .m files usually contain one function. That function name should match the filename (``prefix``). If you pass multiple ``name_expr`` pairs, the latter ones are presumed to be private functions accessed by the primary function. You should only pass inputs to ``argument_sequence``: outputs are ordered according to their order in ``name_expr``. """ code_extension = "m" def __init__(self, project='project', printer=None): super().__init__(project) self.printer = printer or OctaveCodePrinter() def routine(self, name, expr, argument_sequence, global_vars): """Specialized Routine creation for Octave.""" # FIXME: this is probably general enough for other high-level # languages, perhaps its the C/Fortran one that is specialized! if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): if not expr: raise ValueError("No expression given") expressions = Tuple(*expr) else: expressions = Tuple(expr) # local variables local_vars = {i.label for i in expressions.atoms(Idx)} # global variables global_vars = set() if global_vars is None else set(global_vars) # symbols that should be arguments old_symbols = expressions.free_symbols - local_vars - global_vars symbols = set() for s in old_symbols: if isinstance(s, Idx): symbols.update(s.args[1].free_symbols) elif not isinstance(s, Indexed): symbols.add(s) # Octave supports multiple return values return_vals = [] for (i, expr) in enumerate(expressions): if isinstance(expr, Equality): out_arg = expr.lhs expr = expr.rhs symbol = out_arg if isinstance(out_arg, Indexed): symbol = out_arg.base.label if not isinstance(out_arg, (Indexed, Symbol, MatrixSymbol)): raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " "can define output arguments.") return_vals.append(Result(expr, name=symbol, result_var=out_arg)) if not expr.has(symbol): # this is a pure output: remove from the symbols list, so # it doesn't become an input. symbols.remove(symbol) else: # we have no name for this output return_vals.append(Result(expr, name='out%d' % (i+1))) # setup input argument list arg_list = [] array_symbols = {} for array in expressions.atoms(Indexed): array_symbols[array.base.label] = array for array in expressions.atoms(MatrixSymbol): array_symbols[array] = array for symbol in sorted(symbols, key=str): arg_list.append(InputArgument(symbol)) if argument_sequence is not None: # if the user has supplied IndexedBase instances, we'll accept that new_sequence = [] for arg in argument_sequence: if isinstance(arg, IndexedBase): new_sequence.append(arg.label) else: new_sequence.append(arg) argument_sequence = new_sequence missing = [x for x in arg_list if x.name not in argument_sequence] if missing: msg = "Argument list didn't specify: {0} " msg = msg.format(", ".join([str(m.name) for m in missing])) raise CodeGenArgumentListError(msg, missing) # create redundant arguments to produce the requested sequence name_arg_dict = {x.name: x for x in arg_list} new_args = [] for symbol in argument_sequence: try: new_args.append(name_arg_dict[symbol]) except KeyError: new_args.append(InputArgument(symbol)) arg_list = new_args return Routine(name, arg_list, return_vals, local_vars, global_vars) def _get_header(self): """Writes a common header for the generated files.""" code_lines = [] tmp = header_comment % {"version": sympy_version, "project": self.project} for line in tmp.splitlines(): if line == '': code_lines.append("%\n") else: code_lines.append("%% %s\n" % line) return code_lines def _preprocessor_statements(self, prefix): return [] def _get_routine_opening(self, routine): """Returns the opening statements of the routine.""" code_list = [] code_list.append("function ") # Outputs outs = [] for i, result in enumerate(routine.results): if isinstance(result, Result): # Note: name not result_var; want `y` not `y(i)` for Indexed s = self._get_symbol(result.name) else: raise CodeGenError("unexpected object in Routine results") outs.append(s) if len(outs) > 1: code_list.append("[" + (", ".join(outs)) + "]") else: code_list.append("".join(outs)) code_list.append(" = ") # Inputs args = [] for i, arg in enumerate(routine.arguments): if isinstance(arg, (OutputArgument, InOutArgument)): raise CodeGenError("Octave: invalid argument of type %s" % str(type(arg))) if isinstance(arg, InputArgument): args.append("%s" % self._get_symbol(arg.name)) args = ", ".join(args) code_list.append("%s(%s)\n" % (routine.name, args)) code_list = [ "".join(code_list) ] return code_list def _declare_arguments(self, routine): return [] def _declare_globals(self, routine): if not routine.global_vars: return [] s = " ".join(sorted([self._get_symbol(g) for g in routine.global_vars])) return ["global " + s + "\n"] def _declare_locals(self, routine): return [] def _get_routine_ending(self, routine): return ["end\n"] def _call_printer(self, routine): declarations = [] code_lines = [] for i, result in enumerate(routine.results): if isinstance(result, Result): assign_to = result.result_var else: raise CodeGenError("unexpected object in Routine results") constants, not_supported, oct_expr = self._printer_method_with_settings( 'doprint', dict(human=False), result.expr, assign_to=assign_to) for obj, v in sorted(constants, key=str): declarations.append( " %s = %s; %% constant\n" % (obj, v)) for obj in sorted(not_supported, key=str): if isinstance(obj, Function): name = obj.func else: name = obj declarations.append( " %% unsupported: %s\n" % (name)) code_lines.append("%s\n" % (oct_expr)) return declarations + code_lines def _indent_code(self, codelines): return self._printer_method_with_settings( 'indent_code', dict(human=False), codelines) def dump_m(self, routines, f, prefix, header=True, empty=True, inline=True): # Note used to call self.dump_code() but we need more control for header code_lines = self._preprocessor_statements(prefix) for i, routine in enumerate(routines): if i > 0: if empty: code_lines.append("\n") code_lines.extend(self._get_routine_opening(routine)) if i == 0: if routine.name != prefix: raise ValueError('Octave function name should match prefix') if header: code_lines.append("%" + prefix.upper() + " Autogenerated by sympy\n") code_lines.append(''.join(self._get_header())) code_lines.extend(self._declare_arguments(routine)) code_lines.extend(self._declare_globals(routine)) code_lines.extend(self._declare_locals(routine)) if empty: code_lines.append("\n") code_lines.extend(self._call_printer(routine)) if empty: code_lines.append("\n") code_lines.extend(self._get_routine_ending(routine)) code_lines = self._indent_code(''.join(code_lines)) if code_lines: f.write(code_lines) dump_m.extension = code_extension # type: ignore dump_m.__doc__ = CodeGen.dump_code.__doc__ # This list of dump functions is used by CodeGen.write to know which dump # functions it has to call. dump_fns = [dump_m] class RustCodeGen(CodeGen): """Generator for Rust code. The .write() method inherited from CodeGen will output a code file .rs """ code_extension = "rs" def __init__(self, project="project", printer=None): super().__init__(project=project) self.printer = printer or RustCodePrinter() def routine(self, name, expr, argument_sequence, global_vars): """Specialized Routine creation for Rust.""" if is_sequence(expr) and not isinstance(expr, (MatrixBase, MatrixExpr)): if not expr: raise ValueError("No expression given") expressions = Tuple(*expr) else: expressions = Tuple(expr) # local variables local_vars = {i.label for i in expressions.atoms(Idx)} # global variables global_vars = set() if global_vars is None else set(global_vars) # symbols that should be arguments symbols = expressions.free_symbols - local_vars - global_vars - expressions.atoms(Indexed) # Rust supports multiple return values return_vals = [] output_args = [] for (i, expr) in enumerate(expressions): if isinstance(expr, Equality): out_arg = expr.lhs expr = expr.rhs symbol = out_arg if isinstance(out_arg, Indexed): dims = tuple([ (S.One, dim) for dim in out_arg.shape]) symbol = out_arg.base.label output_args.append(InOutArgument(symbol, out_arg, expr, dimensions=dims)) if not isinstance(out_arg, (Indexed, Symbol, MatrixSymbol)): raise CodeGenError("Only Indexed, Symbol, or MatrixSymbol " "can define output arguments.") return_vals.append(Result(expr, name=symbol, result_var=out_arg)) if not expr.has(symbol): # this is a pure output: remove from the symbols list, so # it doesn't become an input. symbols.remove(symbol) else: # we have no name for this output return_vals.append(Result(expr, name='out%d' % (i+1))) # setup input argument list output_args.sort(key=lambda x: str(x.name)) arg_list = list(output_args) array_symbols = {} for array in expressions.atoms(Indexed): array_symbols[array.base.label] = array for array in expressions.atoms(MatrixSymbol): array_symbols[array] = array for symbol in sorted(symbols, key=str): arg_list.append(InputArgument(symbol)) if argument_sequence is not None: # if the user has supplied IndexedBase instances, we'll accept that new_sequence = [] for arg in argument_sequence: if isinstance(arg, IndexedBase): new_sequence.append(arg.label) else: new_sequence.append(arg) argument_sequence = new_sequence missing = [x for x in arg_list if x.name not in argument_sequence] if missing: msg = "Argument list didn't specify: {0} " msg = msg.format(", ".join([str(m.name) for m in missing])) raise CodeGenArgumentListError(msg, missing) # create redundant arguments to produce the requested sequence name_arg_dict = {x.name: x for x in arg_list} new_args = [] for symbol in argument_sequence: try: new_args.append(name_arg_dict[symbol]) except KeyError: new_args.append(InputArgument(symbol)) arg_list = new_args return Routine(name, arg_list, return_vals, local_vars, global_vars) def _get_header(self): """Writes a common header for the generated files.""" code_lines = [] code_lines.append("/*\n") tmp = header_comment % {"version": sympy_version, "project": self.project} for line in tmp.splitlines(): code_lines.append((" *%s" % line.center(76)).rstrip() + "\n") code_lines.append(" */\n") return code_lines def get_prototype(self, routine): """Returns a string for the function prototype of the routine. If the routine has multiple result objects, an CodeGenError is raised. See: https://en.wikipedia.org/wiki/Function_prototype """ results = [i.get_datatype('Rust') for i in routine.results] if len(results) == 1: rstype = " -> " + results[0] elif len(routine.results) > 1: rstype = " -> (" + ", ".join(results) + ")" else: rstype = "" type_args = [] for arg in routine.arguments: name = self.printer.doprint(arg.name) if arg.dimensions or isinstance(arg, ResultBase): type_args.append(("*%s" % name, arg.get_datatype('Rust'))) else: type_args.append((name, arg.get_datatype('Rust'))) arguments = ", ".join([ "%s: %s" % t for t in type_args]) return "fn %s(%s)%s" % (routine.name, arguments, rstype) def _preprocessor_statements(self, prefix): code_lines = [] # code_lines.append("use std::f64::consts::*;\n") return code_lines def _get_routine_opening(self, routine): prototype = self.get_prototype(routine) return ["%s {\n" % prototype] def _declare_arguments(self, routine): # arguments are declared in prototype return [] def _declare_globals(self, routine): # global variables are not explicitly declared within C functions return [] def _declare_locals(self, routine): # loop variables are declared in loop statement return [] def _call_printer(self, routine): code_lines = [] declarations = [] returns = [] # Compose a list of symbols to be dereferenced in the function # body. These are the arguments that were passed by a reference # pointer, excluding arrays. dereference = [] for arg in routine.arguments: if isinstance(arg, ResultBase) and not arg.dimensions: dereference.append(arg.name) for i, result in enumerate(routine.results): if isinstance(result, Result): assign_to = result.result_var returns.append(str(result.result_var)) else: raise CodeGenError("unexpected object in Routine results") constants, not_supported, rs_expr = self._printer_method_with_settings( 'doprint', dict(human=False), result.expr, assign_to=assign_to) for name, value in sorted(constants, key=str): declarations.append("const %s: f64 = %s;\n" % (name, value)) for obj in sorted(not_supported, key=str): if isinstance(obj, Function): name = obj.func else: name = obj declarations.append("// unsupported: %s\n" % (name)) code_lines.append("let %s\n" % rs_expr); if len(returns) > 1: returns = ['(' + ', '.join(returns) + ')'] returns.append('\n') return declarations + code_lines + returns def _get_routine_ending(self, routine): return ["}\n"] def dump_rs(self, routines, f, prefix, header=True, empty=True): self.dump_code(routines, f, prefix, header, empty) dump_rs.extension = code_extension # type: ignore dump_rs.__doc__ = CodeGen.dump_code.__doc__ # This list of dump functions is used by CodeGen.write to know which dump # functions it has to call. dump_fns = [dump_rs] def get_code_generator(language, project=None, standard=None, printer = None): if language == 'C': if standard is None: pass elif standard.lower() == 'c89': language = 'C89' elif standard.lower() == 'c99': language = 'C99' CodeGenClass = {"C": CCodeGen, "C89": C89CodeGen, "C99": C99CodeGen, "F95": FCodeGen, "JULIA": JuliaCodeGen, "OCTAVE": OctaveCodeGen, "RUST": RustCodeGen}.get(language.upper()) if CodeGenClass is None: raise ValueError("Language '%s' is not supported." % language) return CodeGenClass(project, printer) # # Friendly functions # def codegen(name_expr, language=None, prefix=None, project="project", to_files=False, header=True, empty=True, argument_sequence=None, global_vars=None, standard=None, code_gen=None, printer = None): """Generate source code for expressions in a given language. Parameters ========== name_expr : tuple, or list of tuples A single (name, expression) tuple or a list of (name, expression) tuples. Each tuple corresponds to a routine. If the expression is an equality (an instance of class Equality) the left hand side is considered an output argument. If expression is an iterable, then the routine will have multiple outputs. language : string, A string that indicates the source code language. This is case insensitive. Currently, 'C', 'F95' and 'Octave' are supported. 'Octave' generates code compatible with both Octave and Matlab. prefix : string, optional A prefix for the names of the files that contain the source code. Language-dependent suffixes will be appended. If omitted, the name of the first name_expr tuple is used. project : string, optional A project name, used for making unique preprocessor instructions. [default: "project"] to_files : bool, optional When True, the code will be written to one or more files with the given prefix, otherwise strings with the names and contents of these files are returned. [default: False] header : bool, optional When True, a header is written on top of each source file. [default: True] empty : bool, optional When True, empty lines are used to structure the code. [default: True] argument_sequence : iterable, optional Sequence of arguments for the routine in a preferred order. A CodeGenError is raised if required arguments are missing. Redundant arguments are used without warning. If omitted, arguments will be ordered alphabetically, but with all input arguments first, and then output or in-out arguments. global_vars : iterable, optional Sequence of global variables used by the routine. Variables listed here will not show up as function arguments. standard : string code_gen : CodeGen instance An instance of a CodeGen subclass. Overrides ``language``. Examples ======== >>> from sympy.utilities.codegen import codegen >>> from sympy.abc import x, y, z >>> [(c_name, c_code), (h_name, c_header)] = codegen( ... ("f", x+y*z), "C89", "test", header=False, empty=False) >>> print(c_name) test.c >>> print(c_code) #include "test.h" #include double f(double x, double y, double z) { double f_result; f_result = x + y*z; return f_result; } >>> print(h_name) test.h >>> print(c_header) #ifndef PROJECT__TEST__H #define PROJECT__TEST__H double f(double x, double y, double z); #endif Another example using Equality objects to give named outputs. Here the filename (prefix) is taken from the first (name, expr) pair. >>> from sympy.abc import f, g >>> from sympy import Eq >>> [(c_name, c_code), (h_name, c_header)] = codegen( ... [("myfcn", x + y), ("fcn2", [Eq(f, 2*x), Eq(g, y)])], ... "C99", header=False, empty=False) >>> print(c_name) myfcn.c >>> print(c_code) #include "myfcn.h" #include double myfcn(double x, double y) { double myfcn_result; myfcn_result = x + y; return myfcn_result; } void fcn2(double x, double y, double *f, double *g) { (*f) = 2*x; (*g) = y; } If the generated function(s) will be part of a larger project where various global variables have been defined, the 'global_vars' option can be used to remove the specified variables from the function signature >>> from sympy.utilities.codegen import codegen >>> from sympy.abc import x, y, z >>> [(f_name, f_code), header] = codegen( ... ("f", x+y*z), "F95", header=False, empty=False, ... argument_sequence=(x, y), global_vars=(z,)) >>> print(f_code) REAL*8 function f(x, y) implicit none REAL*8, intent(in) :: x REAL*8, intent(in) :: y f = x + y*z end function """ # Initialize the code generator. if language is None: if code_gen is None: raise ValueError("Need either language or code_gen") else: if code_gen is not None: raise ValueError("You cannot specify both language and code_gen.") code_gen = get_code_generator(language, project, standard, printer) if isinstance(name_expr[0], str): # single tuple is given, turn it into a singleton list with a tuple. name_expr = [name_expr] if prefix is None: prefix = name_expr[0][0] # Construct Routines appropriate for this code_gen from (name, expr) pairs. routines = [] for name, expr in name_expr: routines.append(code_gen.routine(name, expr, argument_sequence, global_vars)) # Write the code. return code_gen.write(routines, prefix, to_files, header, empty) def make_routine(name, expr, argument_sequence=None, global_vars=None, language="F95"): """A factory that makes an appropriate Routine from an expression. Parameters ========== name : string The name of this routine in the generated code. expr : expression or list/tuple of expressions A SymPy expression that the Routine instance will represent. If given a list or tuple of expressions, the routine will be considered to have multiple return values and/or output arguments. argument_sequence : list or tuple, optional List arguments for the routine in a preferred order. If omitted, the results are language dependent, for example, alphabetical order or in the same order as the given expressions. global_vars : iterable, optional Sequence of global variables used by the routine. Variables listed here will not show up as function arguments. language : string, optional Specify a target language. The Routine itself should be language-agnostic but the precise way one is created, error checking, etc depend on the language. [default: "F95"]. A decision about whether to use output arguments or return values is made depending on both the language and the particular mathematical expressions. For an expression of type Equality, the left hand side is typically made into an OutputArgument (or perhaps an InOutArgument if appropriate). Otherwise, typically, the calculated expression is made a return values of the routine. Examples ======== >>> from sympy.utilities.codegen import make_routine >>> from sympy.abc import x, y, f, g >>> from sympy import Eq >>> r = make_routine('test', [Eq(f, 2*x), Eq(g, x + y)]) >>> [arg.result_var for arg in r.results] [] >>> [arg.name for arg in r.arguments] [x, y, f, g] >>> [arg.name for arg in r.result_variables] [f, g] >>> r.local_vars set() Another more complicated example with a mixture of specified and automatically-assigned names. Also has Matrix output. >>> from sympy import Matrix >>> r = make_routine('fcn', [x*y, Eq(f, 1), Eq(g, x + g), Matrix([[x, 2]])]) >>> [arg.result_var for arg in r.results] # doctest: +SKIP [result_5397460570204848505] >>> [arg.expr for arg in r.results] [x*y] >>> [arg.name for arg in r.arguments] # doctest: +SKIP [x, y, f, g, out_8598435338387848786] We can examine the various arguments more closely: >>> from sympy.utilities.codegen import (InputArgument, OutputArgument, ... InOutArgument) >>> [a.name for a in r.arguments if isinstance(a, InputArgument)] [x, y] >>> [a.name for a in r.arguments if isinstance(a, OutputArgument)] # doctest: +SKIP [f, out_8598435338387848786] >>> [a.expr for a in r.arguments if isinstance(a, OutputArgument)] [1, Matrix([[x, 2]])] >>> [a.name for a in r.arguments if isinstance(a, InOutArgument)] [g] >>> [a.expr for a in r.arguments if isinstance(a, InOutArgument)] [g + x] """ # initialize a new code generator code_gen = get_code_generator(language) return code_gen.routine(name, expr, argument_sequence, global_vars) sympy-sympy-1.9/sympy/utilities/decorator.py000066400000000000000000000160371412543434000214620ustar00rootroot00000000000000"""Useful utility decorators. """ import sys import types import inspect from sympy.core.decorators import wraps from sympy.core.compatibility import iterable from sympy.testing.runtests import DependencyError, SymPyDocTests, PyTestReporter def threaded_factory(func, use_add): """A factory for ``threaded`` decorators. """ from sympy.core import sympify from sympy.matrices import MatrixBase @wraps(func) def threaded_func(expr, *args, **kwargs): if isinstance(expr, MatrixBase): return expr.applyfunc(lambda f: func(f, *args, **kwargs)) elif iterable(expr): try: return expr.__class__([func(f, *args, **kwargs) for f in expr]) except TypeError: return expr else: expr = sympify(expr) if use_add and expr.is_Add: return expr.__class__(*[ func(f, *args, **kwargs) for f in expr.args ]) elif expr.is_Relational: return expr.__class__(func(expr.lhs, *args, **kwargs), func(expr.rhs, *args, **kwargs)) else: return func(expr, *args, **kwargs) return threaded_func def threaded(func): """Apply ``func`` to sub--elements of an object, including :class:`~.Add`. This decorator is intended to make it uniformly possible to apply a function to all elements of composite objects, e.g. matrices, lists, tuples and other iterable containers, or just expressions. This version of :func:`threaded` decorator allows threading over elements of :class:`~.Add` class. If this behavior is not desirable use :func:`xthreaded` decorator. Functions using this decorator must have the following signature:: @threaded def function(expr, *args, **kwargs): """ return threaded_factory(func, True) def xthreaded(func): """Apply ``func`` to sub--elements of an object, excluding :class:`~.Add`. This decorator is intended to make it uniformly possible to apply a function to all elements of composite objects, e.g. matrices, lists, tuples and other iterable containers, or just expressions. This version of :func:`threaded` decorator disallows threading over elements of :class:`~.Add` class. If this behavior is not desirable use :func:`threaded` decorator. Functions using this decorator must have the following signature:: @xthreaded def function(expr, *args, **kwargs): """ return threaded_factory(func, False) def conserve_mpmath_dps(func): """After the function finishes, resets the value of mpmath.mp.dps to the value it had before the function was run.""" import functools import mpmath def func_wrapper(*args, **kwargs): dps = mpmath.mp.dps try: return func(*args, **kwargs) finally: mpmath.mp.dps = dps func_wrapper = functools.update_wrapper(func_wrapper, func) return func_wrapper class no_attrs_in_subclass: """Don't 'inherit' certain attributes from a base class >>> from sympy.utilities.decorator import no_attrs_in_subclass >>> class A(object): ... x = 'test' >>> A.x = no_attrs_in_subclass(A, A.x) >>> class B(A): ... pass >>> hasattr(A, 'x') True >>> hasattr(B, 'x') False """ def __init__(self, cls, f): self.cls = cls self.f = f def __get__(self, instance, owner=None): if owner == self.cls: if hasattr(self.f, '__get__'): return self.f.__get__(instance, owner) return self.f raise AttributeError def doctest_depends_on(exe=None, modules=None, disable_viewers=None, python_version=None): """ Adds metadata about the dependencies which need to be met for doctesting the docstrings of the decorated objects. exe should be a list of executables modules should be a list of modules disable_viewers should be a list of viewers for preview() to disable python_version should be the minimum Python version required, as a tuple (like (3, 0)) """ dependencies = {} if exe is not None: dependencies['executables'] = exe if modules is not None: dependencies['modules'] = modules if disable_viewers is not None: dependencies['disable_viewers'] = disable_viewers if python_version is not None: dependencies['python_version'] = python_version def skiptests(): r = PyTestReporter() t = SymPyDocTests(r, None) try: t._check_dependencies(**dependencies) except DependencyError: return True # Skip doctests else: return False # Run doctests def depends_on_deco(fn): fn._doctest_depends_on = dependencies fn.__doctest_skip__ = skiptests if inspect.isclass(fn): fn._doctest_depdends_on = no_attrs_in_subclass( fn, fn._doctest_depends_on) fn.__doctest_skip__ = no_attrs_in_subclass( fn, fn.__doctest_skip__) return fn return depends_on_deco def public(obj): """ Append ``obj``'s name to global ``__all__`` variable (call site). By using this decorator on functions or classes you achieve the same goal as by filling ``__all__`` variables manually, you just don't have to repeat yourself (object's name). You also know if object is public at definition site, not at some random location (where ``__all__`` was set). Note that in multiple decorator setup (in almost all cases) ``@public`` decorator must be applied before any other decorators, because it relies on the pointer to object's global namespace. If you apply other decorators first, ``@public`` may end up modifying the wrong namespace. Examples ======== >>> from sympy.utilities.decorator import public >>> __all__ # noqa: F821 Traceback (most recent call last): ... NameError: name '__all__' is not defined >>> @public ... def some_function(): ... pass >>> __all__ # noqa: F821 ['some_function'] """ if isinstance(obj, types.FunctionType): ns = obj.__globals__ name = obj.__name__ elif isinstance(obj, (type(type), type)): ns = sys.modules[obj.__module__].__dict__ name = obj.__name__ else: raise TypeError("expected a function or a class, got %s" % obj) if "__all__" not in ns: ns["__all__"] = [name] else: ns["__all__"].append(name) return obj def memoize_property(propfunc): """Property decorator that caches the value of potentially expensive `propfunc` after the first evaluation. The cached value is stored in the corresponding property name with an attached underscore.""" attrname = '_' + propfunc.__name__ sentinel = object() @wraps(propfunc) def accessor(self): val = getattr(self, attrname, sentinel) if val is sentinel: val = propfunc(self) setattr(self, attrname, val) return val return property(accessor) sympy-sympy-1.9/sympy/utilities/enumerative.py000066400000000000000000001247711412543434000220310ustar00rootroot00000000000000""" Algorithms and classes to support enumerative combinatorics. Currently just multiset partitions, but more could be added. Terminology (following Knuth, algorithm 7.1.2.5M TAOCP) *multiset* aaabbcccc has a *partition* aaabc | bccc The submultisets, aaabc and bccc of the partition are called *parts*, or sometimes *vectors*. (Knuth notes that multiset partitions can be thought of as partitions of vectors of integers, where the ith element of the vector gives the multiplicity of element i.) The values a, b and c are *components* of the multiset. These correspond to elements of a set, but in a multiset can be present with a multiplicity greater than 1. The algorithm deserves some explanation. Think of the part aaabc from the multiset above. If we impose an ordering on the components of the multiset, we can represent a part with a vector, in which the value of the first element of the vector corresponds to the multiplicity of the first component in that part. Thus, aaabc can be represented by the vector [3, 1, 1]. We can also define an ordering on parts, based on the lexicographic ordering of the vector (leftmost vector element, i.e., the element with the smallest component number, is the most significant), so that [3, 1, 1] > [3, 1, 0] and [3, 1, 1] > [2, 1, 4]. The ordering on parts can be extended to an ordering on partitions: First, sort the parts in each partition, left-to-right in decreasing order. Then partition A is greater than partition B if A's leftmost/greatest part is greater than B's leftmost part. If the leftmost parts are equal, compare the second parts, and so on. In this ordering, the greatest partition of a given multiset has only one part. The least partition is the one in which the components are spread out, one per part. The enumeration algorithms in this file yield the partitions of the argument multiset in decreasing order. The main data structure is a stack of parts, corresponding to the current partition. An important invariant is that the parts on the stack are themselves in decreasing order. This data structure is decremented to find the next smaller partition. Most often, decrementing the partition will only involve adjustments to the smallest parts at the top of the stack, much as adjacent integers *usually* differ only in their last few digits. Knuth's algorithm uses two main operations on parts: Decrement - change the part so that it is smaller in the (vector) lexicographic order, but reduced by the smallest amount possible. For example, if the multiset has vector [5, 3, 1], and the bottom/greatest part is [4, 2, 1], this part would decrement to [4, 2, 0], while [4, 0, 0] would decrement to [3, 3, 1]. A singleton part is never decremented -- [1, 0, 0] is not decremented to [0, 3, 1]. Instead, the decrement operator needs to fail for this case. In Knuth's pseudocode, the decrement operator is step m5. Spread unallocated multiplicity - Once a part has been decremented, it cannot be the rightmost part in the partition. There is some multiplicity that has not been allocated, and new parts must be created above it in the stack to use up this multiplicity. To maintain the invariant that the parts on the stack are in decreasing order, these new parts must be less than or equal to the decremented part. For example, if the multiset is [5, 3, 1], and its most significant part has just been decremented to [5, 3, 0], the spread operation will add a new part so that the stack becomes [[5, 3, 0], [0, 0, 1]]. If the most significant part (for the same multiset) has been decremented to [2, 0, 0] the stack becomes [[2, 0, 0], [2, 0, 0], [1, 3, 1]]. In the pseudocode, the spread operation for one part is step m2. The complete spread operation is a loop of steps m2 and m3. In order to facilitate the spread operation, Knuth stores, for each component of each part, not just the multiplicity of that component in the part, but also the total multiplicity available for this component in this part or any lesser part above it on the stack. One added twist is that Knuth does not represent the part vectors as arrays. Instead, he uses a sparse representation, in which a component of a part is represented as a component number (c), plus the multiplicity of the component in that part (v) as well as the total multiplicity available for that component (u). This saves time that would be spent skipping over zeros. """ class PartComponent: """Internal class used in support of the multiset partitions enumerators and the associated visitor functions. Represents one component of one part of the current partition. A stack of these, plus an auxiliary frame array, f, represents a partition of the multiset. Knuth's pseudocode makes c, u, and v separate arrays. """ __slots__ = ('c', 'u', 'v') def __init__(self): self.c = 0 # Component number self.u = 0 # The as yet unpartitioned amount in component c # *before* it is allocated by this triple self.v = 0 # Amount of c component in the current part # (v<=u). An invariant of the representation is # that the next higher triple for this component # (if there is one) will have a value of u-v in # its u attribute. def __repr__(self): "for debug/algorithm animation purposes" return 'c:%d u:%d v:%d' % (self.c, self.u, self.v) def __eq__(self, other): """Define value oriented equality, which is useful for testers""" return (isinstance(other, self.__class__) and self.c == other.c and self.u == other.u and self.v == other.v) def __ne__(self, other): """Defined for consistency with __eq__""" return not self == other # This function tries to be a faithful implementation of algorithm # 7.1.2.5M in Volume 4A, Combinatoral Algorithms, Part 1, of The Art # of Computer Programming, by Donald Knuth. This includes using # (mostly) the same variable names, etc. This makes for rather # low-level Python. # Changes from Knuth's pseudocode include # - use PartComponent struct/object instead of 3 arrays # - make the function a generator # - map (with some difficulty) the GOTOs to Python control structures. # - Knuth uses 1-based numbering for components, this code is 0-based # - renamed variable l to lpart. # - flag variable x takes on values True/False instead of 1/0 # def multiset_partitions_taocp(multiplicities): """Enumerates partitions of a multiset. Parameters ========== multiplicities list of integer multiplicities of the components of the multiset. Yields ====== state Internal data structure which encodes a particular partition. This output is then usually processed by a visitor function which combines the information from this data structure with the components themselves to produce an actual partition. Unless they wish to create their own visitor function, users will have little need to look inside this data structure. But, for reference, it is a 3-element list with components: f is a frame array, which is used to divide pstack into parts. lpart points to the base of the topmost part. pstack is an array of PartComponent objects. The ``state`` output offers a peek into the internal data structures of the enumeration function. The client should treat this as read-only; any modification of the data structure will cause unpredictable (and almost certainly incorrect) results. Also, the components of ``state`` are modified in place at each iteration. Hence, the visitor must be called at each loop iteration. Accumulating the ``state`` instances and processing them later will not work. Examples ======== >>> from sympy.utilities.enumerative import list_visitor >>> from sympy.utilities.enumerative import multiset_partitions_taocp >>> # variables components and multiplicities represent the multiset 'abb' >>> components = 'ab' >>> multiplicities = [1, 2] >>> states = multiset_partitions_taocp(multiplicities) >>> list(list_visitor(state, components) for state in states) [[['a', 'b', 'b']], [['a', 'b'], ['b']], [['a'], ['b', 'b']], [['a'], ['b'], ['b']]] See Also ======== sympy.utilities.iterables.multiset_partitions: Takes a multiset as input and directly yields multiset partitions. It dispatches to a number of functions, including this one, for implementation. Most users will find it more convenient to use than multiset_partitions_taocp. """ # Important variables. # m is the number of components, i.e., number of distinct elements m = len(multiplicities) # n is the cardinality, total number of elements whether or not distinct n = sum(multiplicities) # The main data structure, f segments pstack into parts. See # list_visitor() for example code indicating how this internal # state corresponds to a partition. # Note: allocation of space for stack is conservative. Knuth's # exercise 7.2.1.5.68 gives some indication of how to tighten this # bound, but this is not implemented. pstack = [PartComponent() for i in range(n * m + 1)] f = [0] * (n + 1) # Step M1 in Knuth (Initialize) # Initial state - entire multiset in one part. for j in range(m): ps = pstack[j] ps.c = j ps.u = multiplicities[j] ps.v = multiplicities[j] # Other variables f[0] = 0 a = 0 lpart = 0 f[1] = m b = m # in general, current stack frame is from a to b - 1 while True: while True: # Step M2 (Subtract v from u) j = a k = b x = False while j < b: pstack[k].u = pstack[j].u - pstack[j].v if pstack[k].u == 0: x = True elif not x: pstack[k].c = pstack[j].c pstack[k].v = min(pstack[j].v, pstack[k].u) x = pstack[k].u < pstack[j].v k = k + 1 else: # x is True pstack[k].c = pstack[j].c pstack[k].v = pstack[k].u k = k + 1 j = j + 1 # Note: x is True iff v has changed # Step M3 (Push if nonzero.) if k > b: a = b b = k lpart = lpart + 1 f[lpart + 1] = b # Return to M2 else: break # Continue to M4 # M4 Visit a partition state = [f, lpart, pstack] yield state # M5 (Decrease v) while True: j = b-1 while (pstack[j].v == 0): j = j - 1 if j == a and pstack[j].v == 1: # M6 (Backtrack) if lpart == 0: return lpart = lpart - 1 b = a a = f[lpart] # Return to M5 else: pstack[j].v = pstack[j].v - 1 for k in range(j + 1, b): pstack[k].v = pstack[k].u break # GOTO M2 # --------------- Visitor functions for multiset partitions --------------- # A visitor takes the partition state generated by # multiset_partitions_taocp or other enumerator, and produces useful # output (such as the actual partition). def factoring_visitor(state, primes): """Use with multiset_partitions_taocp to enumerate the ways a number can be expressed as a product of factors. For this usage, the exponents of the prime factors of a number are arguments to the partition enumerator, while the corresponding prime factors are input here. Examples ======== To enumerate the factorings of a number we can think of the elements of the partition as being the prime factors and the multiplicities as being their exponents. >>> from sympy.utilities.enumerative import factoring_visitor >>> from sympy.utilities.enumerative import multiset_partitions_taocp >>> from sympy import factorint >>> primes, multiplicities = zip(*factorint(24).items()) >>> primes (2, 3) >>> multiplicities (3, 1) >>> states = multiset_partitions_taocp(multiplicities) >>> list(factoring_visitor(state, primes) for state in states) [[24], [8, 3], [12, 2], [4, 6], [4, 2, 3], [6, 2, 2], [2, 2, 2, 3]] """ f, lpart, pstack = state factoring = [] for i in range(lpart + 1): factor = 1 for ps in pstack[f[i]: f[i + 1]]: if ps.v > 0: factor *= primes[ps.c] ** ps.v factoring.append(factor) return factoring def list_visitor(state, components): """Return a list of lists to represent the partition. Examples ======== >>> from sympy.utilities.enumerative import list_visitor >>> from sympy.utilities.enumerative import multiset_partitions_taocp >>> states = multiset_partitions_taocp([1, 2, 1]) >>> s = next(states) >>> list_visitor(s, 'abc') # for multiset 'a b b c' [['a', 'b', 'b', 'c']] >>> s = next(states) >>> list_visitor(s, [1, 2, 3]) # for multiset '1 2 2 3 [[1, 2, 2], [3]] """ f, lpart, pstack = state partition = [] for i in range(lpart+1): part = [] for ps in pstack[f[i]:f[i+1]]: if ps.v > 0: part.extend([components[ps.c]] * ps.v) partition.append(part) return partition class MultisetPartitionTraverser(): """ Has methods to ``enumerate`` and ``count`` the partitions of a multiset. This implements a refactored and extended version of Knuth's algorithm 7.1.2.5M [AOCP]_." The enumeration methods of this class are generators and return data structures which can be interpreted by the same visitor functions used for the output of ``multiset_partitions_taocp``. Examples ======== >>> from sympy.utilities.enumerative import MultisetPartitionTraverser >>> m = MultisetPartitionTraverser() >>> m.count_partitions([4,4,4,2]) 127750 >>> m.count_partitions([3,3,3]) 686 See Also ======== multiset_partitions_taocp sympy.utilities.iterables.multiset_partitions References ========== .. [AOCP] Algorithm 7.1.2.5M in Volume 4A, Combinatoral Algorithms, Part 1, of The Art of Computer Programming, by Donald Knuth. .. [Factorisatio] On a Problem of Oppenheim concerning "Factorisatio Numerorum" E. R. Canfield, Paul Erdos, Carl Pomerance, JOURNAL OF NUMBER THEORY, Vol. 17, No. 1. August 1983. See section 7 for a description of an algorithm similar to Knuth's. .. [Yorgey] Generating Multiset Partitions, Brent Yorgey, The Monad.Reader, Issue 8, September 2007. """ def __init__(self): self.debug = False # TRACING variables. These are useful for gathering # statistics on the algorithm itself, but have no particular # benefit to a user of the code. self.k1 = 0 self.k2 = 0 self.p1 = 0 def db_trace(self, msg): """Useful for understanding/debugging the algorithms. Not generally activated in end-user code.""" if self.debug: # XXX: animation_visitor is undefined... Clearly this does not # work and was not tested. Previous code in comments below. raise RuntimeError #letters = 'abcdefghijklmnopqrstuvwxyz' #state = [self.f, self.lpart, self.pstack] #print("DBG:", msg, # ["".join(part) for part in list_visitor(state, letters)], # animation_visitor(state)) # # Helper methods for enumeration # def _initialize_enumeration(self, multiplicities): """Allocates and initializes the partition stack. This is called from the enumeration/counting routines, so there is no need to call it separately.""" num_components = len(multiplicities) # cardinality is the total number of elements, whether or not distinct cardinality = sum(multiplicities) # pstack is the partition stack, which is segmented by # f into parts. self.pstack = [PartComponent() for i in range(num_components * cardinality + 1)] self.f = [0] * (cardinality + 1) # Initial state - entire multiset in one part. for j in range(num_components): ps = self.pstack[j] ps.c = j ps.u = multiplicities[j] ps.v = multiplicities[j] self.f[0] = 0 self.f[1] = num_components self.lpart = 0 # The decrement_part() method corresponds to step M5 in Knuth's # algorithm. This is the base version for enum_all(). Modified # versions of this method are needed if we want to restrict # sizes of the partitions produced. def decrement_part(self, part): """Decrements part (a subrange of pstack), if possible, returning True iff the part was successfully decremented. If you think of the v values in the part as a multi-digit integer (least significant digit on the right) this is basically decrementing that integer, but with the extra constraint that the leftmost digit cannot be decremented to 0. Parameters ========== part The part, represented as a list of PartComponent objects, which is to be decremented. """ plen = len(part) for j in range(plen - 1, -1, -1): if j == 0 and part[j].v > 1 or j > 0 and part[j].v > 0: # found val to decrement part[j].v -= 1 # Reset trailing parts back to maximum for k in range(j + 1, plen): part[k].v = part[k].u return True return False # Version to allow number of parts to be bounded from above. # Corresponds to (a modified) step M5. def decrement_part_small(self, part, ub): """Decrements part (a subrange of pstack), if possible, returning True iff the part was successfully decremented. Parameters ========== part part to be decremented (topmost part on the stack) ub the maximum number of parts allowed in a partition returned by the calling traversal. Notes ===== The goal of this modification of the ordinary decrement method is to fail (meaning that the subtree rooted at this part is to be skipped) when it can be proved that this part can only have child partitions which are larger than allowed by ``ub``. If a decision is made to fail, it must be accurate, otherwise the enumeration will miss some partitions. But, it is OK not to capture all the possible failures -- if a part is passed that shouldn't be, the resulting too-large partitions are filtered by the enumeration one level up. However, as is usual in constrained enumerations, failing early is advantageous. The tests used by this method catch the most common cases, although this implementation is by no means the last word on this problem. The tests include: 1) ``lpart`` must be less than ``ub`` by at least 2. This is because once a part has been decremented, the partition will gain at least one child in the spread step. 2) If the leading component of the part is about to be decremented, check for how many parts will be added in order to use up the unallocated multiplicity in that leading component, and fail if this number is greater than allowed by ``ub``. (See code for the exact expression.) This test is given in the answer to Knuth's problem 7.2.1.5.69. 3) If there is *exactly* enough room to expand the leading component by the above test, check the next component (if it exists) once decrementing has finished. If this has ``v == 0``, this next component will push the expansion over the limit by 1, so fail. """ if self.lpart >= ub - 1: self.p1 += 1 # increment to keep track of usefulness of tests return False plen = len(part) for j in range(plen - 1, -1, -1): # Knuth's mod, (answer to problem 7.2.1.5.69) if j == 0 and (part[0].v - 1)*(ub - self.lpart) < part[0].u: self.k1 += 1 return False if j == 0 and part[j].v > 1 or j > 0 and part[j].v > 0: # found val to decrement part[j].v -= 1 # Reset trailing parts back to maximum for k in range(j + 1, plen): part[k].v = part[k].u # Have now decremented part, but are we doomed to # failure when it is expanded? Check one oddball case # that turns out to be surprisingly common - exactly # enough room to expand the leading component, but no # room for the second component, which has v=0. if (plen > 1 and part[1].v == 0 and (part[0].u - part[0].v) == ((ub - self.lpart - 1) * part[0].v)): self.k2 += 1 self.db_trace("Decrement fails test 3") return False return True return False def decrement_part_large(self, part, amt, lb): """Decrements part, while respecting size constraint. A part can have no children which are of sufficient size (as indicated by ``lb``) unless that part has sufficient unallocated multiplicity. When enforcing the size constraint, this method will decrement the part (if necessary) by an amount needed to ensure sufficient unallocated multiplicity. Returns True iff the part was successfully decremented. Parameters ========== part part to be decremented (topmost part on the stack) amt Can only take values 0 or 1. A value of 1 means that the part must be decremented, and then the size constraint is enforced. A value of 0 means just to enforce the ``lb`` size constraint. lb The partitions produced by the calling enumeration must have more parts than this value. """ if amt == 1: # In this case we always need to increment, *before* # enforcing the "sufficient unallocated multiplicity" # constraint. Easiest for this is just to call the # regular decrement method. if not self.decrement_part(part): return False # Next, perform any needed additional decrementing to respect # "sufficient unallocated multiplicity" (or fail if this is # not possible). min_unalloc = lb - self.lpart if min_unalloc <= 0: return True total_mult = sum(pc.u for pc in part) total_alloc = sum(pc.v for pc in part) if total_mult <= min_unalloc: return False deficit = min_unalloc - (total_mult - total_alloc) if deficit <= 0: return True for i in range(len(part) - 1, -1, -1): if i == 0: if part[0].v > deficit: part[0].v -= deficit return True else: return False # This shouldn't happen, due to above check else: if part[i].v >= deficit: part[i].v -= deficit return True else: deficit -= part[i].v part[i].v = 0 def decrement_part_range(self, part, lb, ub): """Decrements part (a subrange of pstack), if possible, returning True iff the part was successfully decremented. Parameters ========== part part to be decremented (topmost part on the stack) ub the maximum number of parts allowed in a partition returned by the calling traversal. lb The partitions produced by the calling enumeration must have more parts than this value. Notes ===== Combines the constraints of _small and _large decrement methods. If returns success, part has been decremented at least once, but perhaps by quite a bit more if needed to meet the lb constraint. """ # Constraint in the range case is just enforcing both the # constraints from _small and _large cases. Note the 0 as the # second argument to the _large call -- this is the signal to # decrement only as needed to for constraint enforcement. The # short circuiting and left-to-right order of the 'and' # operator is important for this to work correctly. return self.decrement_part_small(part, ub) and \ self.decrement_part_large(part, 0, lb) def spread_part_multiplicity(self): """Returns True if a new part has been created, and adjusts pstack, f and lpart as needed. Notes ===== Spreads unallocated multiplicity from the current top part into a new part created above the current on the stack. This new part is constrained to be less than or equal to the old in terms of the part ordering. This call does nothing (and returns False) if the current top part has no unallocated multiplicity. """ j = self.f[self.lpart] # base of current top part k = self.f[self.lpart + 1] # ub of current; potential base of next base = k # save for later comparison changed = False # Set to true when the new part (so far) is # strictly less than (as opposed to less than # or equal) to the old. for j in range(self.f[self.lpart], self.f[self.lpart + 1]): self.pstack[k].u = self.pstack[j].u - self.pstack[j].v if self.pstack[k].u == 0: changed = True else: self.pstack[k].c = self.pstack[j].c if changed: # Put all available multiplicity in this part self.pstack[k].v = self.pstack[k].u else: # Still maintaining ordering constraint if self.pstack[k].u < self.pstack[j].v: self.pstack[k].v = self.pstack[k].u changed = True else: self.pstack[k].v = self.pstack[j].v k = k + 1 if k > base: # Adjust for the new part on stack self.lpart = self.lpart + 1 self.f[self.lpart + 1] = k return True return False def top_part(self): """Return current top part on the stack, as a slice of pstack. """ return self.pstack[self.f[self.lpart]:self.f[self.lpart + 1]] # Same interface and functionality as multiset_partitions_taocp(), # but some might find this refactored version easier to follow. def enum_all(self, multiplicities): """Enumerate the partitions of a multiset. Examples ======== >>> from sympy.utilities.enumerative import list_visitor >>> from sympy.utilities.enumerative import MultisetPartitionTraverser >>> m = MultisetPartitionTraverser() >>> states = m.enum_all([2,2]) >>> list(list_visitor(state, 'ab') for state in states) [[['a', 'a', 'b', 'b']], [['a', 'a', 'b'], ['b']], [['a', 'a'], ['b', 'b']], [['a', 'a'], ['b'], ['b']], [['a', 'b', 'b'], ['a']], [['a', 'b'], ['a', 'b']], [['a', 'b'], ['a'], ['b']], [['a'], ['a'], ['b', 'b']], [['a'], ['a'], ['b'], ['b']]] See Also ======== multiset_partitions_taocp(): which provides the same result as this method, but is about twice as fast. Hence, enum_all is primarily useful for testing. Also see the function for a discussion of states and visitors. """ self._initialize_enumeration(multiplicities) while True: while self.spread_part_multiplicity(): pass # M4 Visit a partition state = [self.f, self.lpart, self.pstack] yield state # M5 (Decrease v) while not self.decrement_part(self.top_part()): # M6 (Backtrack) if self.lpart == 0: return self.lpart -= 1 def enum_small(self, multiplicities, ub): """Enumerate multiset partitions with no more than ``ub`` parts. Equivalent to enum_range(multiplicities, 0, ub) Parameters ========== multiplicities list of multiplicities of the components of the multiset. ub Maximum number of parts Examples ======== >>> from sympy.utilities.enumerative import list_visitor >>> from sympy.utilities.enumerative import MultisetPartitionTraverser >>> m = MultisetPartitionTraverser() >>> states = m.enum_small([2,2], 2) >>> list(list_visitor(state, 'ab') for state in states) [[['a', 'a', 'b', 'b']], [['a', 'a', 'b'], ['b']], [['a', 'a'], ['b', 'b']], [['a', 'b', 'b'], ['a']], [['a', 'b'], ['a', 'b']]] The implementation is based, in part, on the answer given to exercise 69, in Knuth [AOCP]_. See Also ======== enum_all, enum_large, enum_range """ # Keep track of iterations which do not yield a partition. # Clearly, we would like to keep this number small. self.discarded = 0 if ub <= 0: return self._initialize_enumeration(multiplicities) while True: good_partition = True while self.spread_part_multiplicity(): self.db_trace("spread 1") if self.lpart >= ub: self.discarded += 1 good_partition = False self.db_trace(" Discarding") self.lpart = ub - 2 break # M4 Visit a partition if good_partition: state = [self.f, self.lpart, self.pstack] yield state # M5 (Decrease v) while not self.decrement_part_small(self.top_part(), ub): self.db_trace("Failed decrement, going to backtrack") # M6 (Backtrack) if self.lpart == 0: return self.lpart -= 1 self.db_trace("Backtracked to") self.db_trace("decrement ok, about to expand") def enum_large(self, multiplicities, lb): """Enumerate the partitions of a multiset with lb < num(parts) Equivalent to enum_range(multiplicities, lb, sum(multiplicities)) Parameters ========== multiplicities list of multiplicities of the components of the multiset. lb Number of parts in the partition must be greater than this lower bound. Examples ======== >>> from sympy.utilities.enumerative import list_visitor >>> from sympy.utilities.enumerative import MultisetPartitionTraverser >>> m = MultisetPartitionTraverser() >>> states = m.enum_large([2,2], 2) >>> list(list_visitor(state, 'ab') for state in states) [[['a', 'a'], ['b'], ['b']], [['a', 'b'], ['a'], ['b']], [['a'], ['a'], ['b', 'b']], [['a'], ['a'], ['b'], ['b']]] See Also ======== enum_all, enum_small, enum_range """ self.discarded = 0 if lb >= sum(multiplicities): return self._initialize_enumeration(multiplicities) self.decrement_part_large(self.top_part(), 0, lb) while True: good_partition = True while self.spread_part_multiplicity(): if not self.decrement_part_large(self.top_part(), 0, lb): # Failure here should be rare/impossible self.discarded += 1 good_partition = False break # M4 Visit a partition if good_partition: state = [self.f, self.lpart, self.pstack] yield state # M5 (Decrease v) while not self.decrement_part_large(self.top_part(), 1, lb): # M6 (Backtrack) if self.lpart == 0: return self.lpart -= 1 def enum_range(self, multiplicities, lb, ub): """Enumerate the partitions of a multiset with ``lb < num(parts) <= ub``. In particular, if partitions with exactly ``k`` parts are desired, call with ``(multiplicities, k - 1, k)``. This method generalizes enum_all, enum_small, and enum_large. Examples ======== >>> from sympy.utilities.enumerative import list_visitor >>> from sympy.utilities.enumerative import MultisetPartitionTraverser >>> m = MultisetPartitionTraverser() >>> states = m.enum_range([2,2], 1, 2) >>> list(list_visitor(state, 'ab') for state in states) [[['a', 'a', 'b'], ['b']], [['a', 'a'], ['b', 'b']], [['a', 'b', 'b'], ['a']], [['a', 'b'], ['a', 'b']]] """ # combine the constraints of the _large and _small # enumerations. self.discarded = 0 if ub <= 0 or lb >= sum(multiplicities): return self._initialize_enumeration(multiplicities) self.decrement_part_large(self.top_part(), 0, lb) while True: good_partition = True while self.spread_part_multiplicity(): self.db_trace("spread 1") if not self.decrement_part_large(self.top_part(), 0, lb): # Failure here - possible in range case? self.db_trace(" Discarding (large cons)") self.discarded += 1 good_partition = False break elif self.lpart >= ub: self.discarded += 1 good_partition = False self.db_trace(" Discarding small cons") self.lpart = ub - 2 break # M4 Visit a partition if good_partition: state = [self.f, self.lpart, self.pstack] yield state # M5 (Decrease v) while not self.decrement_part_range(self.top_part(), lb, ub): self.db_trace("Failed decrement, going to backtrack") # M6 (Backtrack) if self.lpart == 0: return self.lpart -= 1 self.db_trace("Backtracked to") self.db_trace("decrement ok, about to expand") def count_partitions_slow(self, multiplicities): """Returns the number of partitions of a multiset whose elements have the multiplicities given in ``multiplicities``. Primarily for comparison purposes. It follows the same path as enumerate, and counts, rather than generates, the partitions. See Also ======== count_partitions Has the same calling interface, but is much faster. """ # number of partitions so far in the enumeration self.pcount = 0 self._initialize_enumeration(multiplicities) while True: while self.spread_part_multiplicity(): pass # M4 Visit (count) a partition self.pcount += 1 # M5 (Decrease v) while not self.decrement_part(self.top_part()): # M6 (Backtrack) if self.lpart == 0: return self.pcount self.lpart -= 1 def count_partitions(self, multiplicities): """Returns the number of partitions of a multiset whose components have the multiplicities given in ``multiplicities``. For larger counts, this method is much faster than calling one of the enumerators and counting the result. Uses dynamic programming to cut down on the number of nodes actually explored. The dictionary used in order to accelerate the counting process is stored in the ``MultisetPartitionTraverser`` object and persists across calls. If the user does not expect to call ``count_partitions`` for any additional multisets, the object should be cleared to save memory. On the other hand, the cache built up from one count run can significantly speed up subsequent calls to ``count_partitions``, so it may be advantageous not to clear the object. Examples ======== >>> from sympy.utilities.enumerative import MultisetPartitionTraverser >>> m = MultisetPartitionTraverser() >>> m.count_partitions([9,8,2]) 288716 >>> m.count_partitions([2,2]) 9 >>> del m Notes ===== If one looks at the workings of Knuth's algorithm M [AOCP]_, it can be viewed as a traversal of a binary tree of parts. A part has (up to) two children, the left child resulting from the spread operation, and the right child from the decrement operation. The ordinary enumeration of multiset partitions is an in-order traversal of this tree, and with the partitions corresponding to paths from the root to the leaves. The mapping from paths to partitions is a little complicated, since the partition would contain only those parts which are leaves or the parents of a spread link, not those which are parents of a decrement link. For counting purposes, it is sufficient to count leaves, and this can be done with a recursive in-order traversal. The number of leaves of a subtree rooted at a particular part is a function only of that part itself, so memoizing has the potential to speed up the counting dramatically. This method follows a computational approach which is similar to the hypothetical memoized recursive function, but with two differences: 1) This method is iterative, borrowing its structure from the other enumerations and maintaining an explicit stack of parts which are in the process of being counted. (There may be multisets which can be counted reasonably quickly by this implementation, but which would overflow the default Python recursion limit with a recursive implementation.) 2) Instead of using the part data structure directly, a more compact key is constructed. This saves space, but more importantly coalesces some parts which would remain separate with physical keys. Unlike the enumeration functions, there is currently no _range version of count_partitions. If someone wants to stretch their brain, it should be possible to construct one by memoizing with a histogram of counts rather than a single count, and combining the histograms. """ # number of partitions so far in the enumeration self.pcount = 0 # dp_stack is list of lists of (part_key, start_count) pairs self.dp_stack = [] # dp_map is map part_key-> count, where count represents the # number of multiset which are descendants of a part with this # key, **or any of its decrements** # Thus, when we find a part in the map, we add its count # value to the running total, cut off the enumeration, and # backtrack if not hasattr(self, 'dp_map'): self.dp_map = {} self._initialize_enumeration(multiplicities) pkey = part_key(self.top_part()) self.dp_stack.append([(pkey, 0), ]) while True: while self.spread_part_multiplicity(): pkey = part_key(self.top_part()) if pkey in self.dp_map: # Already have a cached value for the count of the # subtree rooted at this part. Add it to the # running counter, and break out of the spread # loop. The -1 below is to compensate for the # leaf that this code path would otherwise find, # and which gets incremented for below. self.pcount += (self.dp_map[pkey] - 1) self.lpart -= 1 break else: self.dp_stack.append([(pkey, self.pcount), ]) # M4 count a leaf partition self.pcount += 1 # M5 (Decrease v) while not self.decrement_part(self.top_part()): # M6 (Backtrack) for key, oldcount in self.dp_stack.pop(): self.dp_map[key] = self.pcount - oldcount if self.lpart == 0: return self.pcount self.lpart -= 1 # At this point have successfully decremented the part on # the stack and it does not appear in the cache. It needs # to be added to the list at the top of dp_stack pkey = part_key(self.top_part()) self.dp_stack[-1].append((pkey, self.pcount),) def part_key(part): """Helper for MultisetPartitionTraverser.count_partitions that creates a key for ``part``, that only includes information which can affect the count for that part. (Any irrelevant information just reduces the effectiveness of dynamic programming.) Notes ===== This member function is a candidate for future exploration. There are likely symmetries that can be exploited to coalesce some ``part_key`` values, and thereby save space and improve performance. """ # The component number is irrelevant for counting partitions, so # leave it out of the memo key. rval = [] for ps in part: rval.append(ps.u) rval.append(ps.v) return tuple(rval) sympy-sympy-1.9/sympy/utilities/exceptions.py000066400000000000000000000157731412543434000216670ustar00rootroot00000000000000""" General SymPy exceptions and warnings. """ import warnings from sympy.utilities.misc import filldedent class SymPyDeprecationWarning(DeprecationWarning): r"""A warning for deprecated features of SymPy. This class is expected to be used with the warnings.warn function (note that one has to explicitly turn on deprecation warnings): >>> import warnings >>> from sympy.utilities.exceptions import SymPyDeprecationWarning >>> warnings.simplefilter( ... "always", SymPyDeprecationWarning) >>> warnings.warn( ... SymPyDeprecationWarning(feature="Old deprecated thing", ... issue=1065, deprecated_since_version="1.0")) #doctest:+SKIP __main__:3: SymPyDeprecationWarning: Old deprecated thing has been deprecated since SymPy 1.0. See https://github.com/sympy/sympy/issues/1065 for more info. >>> SymPyDeprecationWarning(feature="Old deprecated thing", ... issue=1065, deprecated_since_version="1.1").warn() #doctest:+SKIP __main__:1: SymPyDeprecationWarning: Old deprecated thing has been deprecated since SymPy 1.1. See https://github.com/sympy/sympy/issues/1065 for more info. Three arguments to this class are required: ``feature``, ``issue`` and ``deprecated_since_version``. The ``issue`` flag should be an integer referencing for a "Deprecation Removal" issue in the SymPy issue tracker. See https://github.com/sympy/sympy/wiki/Deprecating-policy. >>> SymPyDeprecationWarning( ... feature="Old feature", ... useinstead="new feature", ... issue=5241, ... deprecated_since_version="1.1") Old feature has been deprecated since SymPy 1.1. Use new feature instead. See https://github.com/sympy/sympy/issues/5241 for more info. Every formal deprecation should have an associated issue in the GitHub issue tracker. All such issues should have the DeprecationRemoval tag. Additionally, each formal deprecation should mark the first release for which it was deprecated. Use the ``deprecated_since_version`` flag for this. >>> SymPyDeprecationWarning( ... feature="Old feature", ... useinstead="new feature", ... deprecated_since_version="0.7.2", ... issue=1065) Old feature has been deprecated since SymPy 0.7.2. Use new feature instead. See https://github.com/sympy/sympy/issues/1065 for more info. To provide additional information, create an instance of this class in this way: >>> SymPyDeprecationWarning( ... feature="Such and such", ... last_supported_version="1.2.3", ... useinstead="this other feature", ... issue=1065, ... deprecated_since_version="1.1") Such and such has been deprecated since SymPy 1.1. It will be last supported in SymPy version 1.2.3. Use this other feature instead. See https://github.com/sympy/sympy/issues/1065 for more info. Note that the text in ``feature`` begins a sentence, so if it begins with a plain English word, the first letter of that word should be capitalized. Either (or both) of the arguments ``last_supported_version`` and ``useinstead`` can be omitted. In this case the corresponding sentence will not be shown: >>> SymPyDeprecationWarning(feature="Such and such", ... useinstead="this other feature", issue=1065, ... deprecated_since_version="1.1") Such and such has been deprecated since SymPy 1.1. Use this other feature instead. See https://github.com/sympy/sympy/issues/1065 for more info. You can still provide the argument value. If it is a string, it will be appended to the end of the message: >>> SymPyDeprecationWarning( ... feature="Such and such", ... useinstead="this other feature", ... value="Contact the developers for further information.", ... issue=1065, ... deprecated_since_version="1.1") Such and such has been deprecated since SymPy 1.1. Use this other feature instead. See https://github.com/sympy/sympy/issues/1065 for more info. Contact the developers for further information. If, however, the argument value does not hold a string, a string representation of the object will be appended to the message: >>> SymPyDeprecationWarning( ... feature="Such and such", ... useinstead="this other feature", ... value=[1,2,3], ... issue=1065, ... deprecated_since_version="1.1") Such and such has been deprecated since SymPy 1.1. Use this other feature instead. See https://github.com/sympy/sympy/issues/1065 for more info. ([1, 2, 3]) Note that it may be necessary to go back through all the deprecations before a release to make sure that the version number is correct. So just use what you believe will be the next release number (this usually means bumping the minor number by one). To mark a function as deprecated, you can use the decorator @deprecated. See Also ======== sympy.core.decorators.deprecated """ def __init__(self, value=None, feature=None, last_supported_version=None, useinstead=None, issue=None, deprecated_since_version=None): self.args = (value, feature, last_supported_version, useinstead, issue, deprecated_since_version) self.fullMessage = "" if not feature: raise ValueError("feature is required argument of SymPyDeprecationWarning") if not deprecated_since_version: raise ValueError("deprecated_since_version is a required argument of SymPyDeprecationWarning") self.fullMessage = "%s has been deprecated since SymPy %s. " % \ (feature, deprecated_since_version) if last_supported_version: self.fullMessage += ("It will be last supported in SymPy " "version %s. ") % last_supported_version if useinstead: self.fullMessage += "Use %s instead. " % useinstead if not issue: raise ValueError("""\ The issue argument of SymPyDeprecationWarning is required. This should be a separate issue with the "Deprecation Removal" label. See https://github.com/sympy/sympy/wiki/Deprecating-policy.\ """) self.fullMessage += ("See " "https://github.com/sympy/sympy/issues/%d for more " "info. ") % issue if value: if not isinstance(value, str): value = "(%s)" % repr(value) value = " " + value else: value = "" self.fullMessage += value def __str__(self): return '\n%s\n' % filldedent(self.fullMessage) def warn(self, stacklevel=2): # the next line is what the user would see after the error is printed # if stacklevel was set to 1. If you are writing a wrapper around this, # increase the stacklevel accordingly. warnings.warn(self, stacklevel=stacklevel) # Python by default hides DeprecationWarnings, which we do not want. warnings.simplefilter("once", SymPyDeprecationWarning) sympy-sympy-1.9/sympy/utilities/iterables.py000066400000000000000000002262671412543434000214620ustar00rootroot00000000000000from collections import defaultdict, OrderedDict from itertools import ( combinations, combinations_with_replacement, permutations, product, product as cartes ) import random from operator import gt from sympy.core import Basic # this is the logical location of these functions from sympy.core.compatibility import (as_int, is_sequence, iterable, ordered) from sympy.core.compatibility import default_sort_key # noqa: F401 import sympy from sympy.utilities.enumerative import ( multiset_partitions_taocp, list_visitor, MultisetPartitionTraverser) def is_palindromic(s, i=0, j=None): """return True if the sequence is the same from left to right as it is from right to left in the whole sequence (default) or in the Python slice ``s[i: j]``; else False. Examples ======== >>> from sympy.utilities.iterables import is_palindromic >>> is_palindromic([1, 0, 1]) True >>> is_palindromic('abcbb') False >>> is_palindromic('abcbb', 1) False Normal Python slicing is performed in place so there is no need to create a slice of the sequence for testing: >>> is_palindromic('abcbb', 1, -1) True >>> is_palindromic('abcbb', -4, -1) True See Also ======== sympy.ntheory.digits.is_palindromic: tests integers """ i, j, _ = slice(i, j).indices(len(s)) m = (j - i)//2 # if length is odd, middle element will be ignored return all(s[i + k] == s[j - 1 - k] for k in range(m)) def flatten(iterable, levels=None, cls=None): """ Recursively denest iterable containers. >>> from sympy.utilities.iterables import flatten >>> flatten([1, 2, 3]) [1, 2, 3] >>> flatten([1, 2, [3]]) [1, 2, 3] >>> flatten([1, [2, 3], [4, 5]]) [1, 2, 3, 4, 5] >>> flatten([1.0, 2, (1, None)]) [1.0, 2, 1, None] If you want to denest only a specified number of levels of nested containers, then set ``levels`` flag to the desired number of levels:: >>> ls = [[(-2, -1), (1, 2)], [(0, 0)]] >>> flatten(ls, levels=1) [(-2, -1), (1, 2), (0, 0)] If cls argument is specified, it will only flatten instances of that class, for example: >>> from sympy.core import Basic >>> class MyOp(Basic): ... pass ... >>> flatten([MyOp(1, MyOp(2, 3))], cls=MyOp) [1, 2, 3] adapted from https://kogs-www.informatik.uni-hamburg.de/~meine/python_tricks """ from sympy.tensor.array import NDimArray if levels is not None: if not levels: return iterable elif levels > 0: levels -= 1 else: raise ValueError( "expected non-negative number of levels, got %s" % levels) if cls is None: reducible = lambda x: is_sequence(x, set) else: reducible = lambda x: isinstance(x, cls) result = [] for el in iterable: if reducible(el): if hasattr(el, 'args') and not isinstance(el, NDimArray): el = el.args result.extend(flatten(el, levels=levels, cls=cls)) else: result.append(el) return result def unflatten(iter, n=2): """Group ``iter`` into tuples of length ``n``. Raise an error if the length of ``iter`` is not a multiple of ``n``. """ if n < 1 or len(iter) % n: raise ValueError('iter length is not a multiple of %i' % n) return list(zip(*(iter[i::n] for i in range(n)))) def reshape(seq, how): """Reshape the sequence according to the template in ``how``. Examples ======== >>> from sympy.utilities import reshape >>> seq = list(range(1, 9)) >>> reshape(seq, [4]) # lists of 4 [[1, 2, 3, 4], [5, 6, 7, 8]] >>> reshape(seq, (4,)) # tuples of 4 [(1, 2, 3, 4), (5, 6, 7, 8)] >>> reshape(seq, (2, 2)) # tuples of 4 [(1, 2, 3, 4), (5, 6, 7, 8)] >>> reshape(seq, (2, [2])) # (i, i, [i, i]) [(1, 2, [3, 4]), (5, 6, [7, 8])] >>> reshape(seq, ((2,), [2])) # etc.... [((1, 2), [3, 4]), ((5, 6), [7, 8])] >>> reshape(seq, (1, [2], 1)) [(1, [2, 3], 4), (5, [6, 7], 8)] >>> reshape(tuple(seq), ([[1], 1, (2,)],)) (([[1], 2, (3, 4)],), ([[5], 6, (7, 8)],)) >>> reshape(tuple(seq), ([1], 1, (2,))) (([1], 2, (3, 4)), ([5], 6, (7, 8))) >>> reshape(list(range(12)), [2, [3], {2}, (1, (3,), 1)]) [[0, 1, [2, 3, 4], {5, 6}, (7, (8, 9, 10), 11)]] """ m = sum(flatten(how)) n, rem = divmod(len(seq), m) if m < 0 or rem: raise ValueError('template must sum to positive number ' 'that divides the length of the sequence') i = 0 container = type(how) rv = [None]*n for k in range(len(rv)): rv[k] = [] for hi in how: if type(hi) is int: rv[k].extend(seq[i: i + hi]) i += hi else: n = sum(flatten(hi)) hi_type = type(hi) rv[k].append(hi_type(reshape(seq[i: i + n], hi)[0])) i += n rv[k] = container(rv[k]) return type(seq)(rv) def group(seq, multiple=True): """ Splits a sequence into a list of lists of equal, adjacent elements. Examples ======== >>> from sympy.utilities.iterables import group >>> group([1, 1, 1, 2, 2, 3]) [[1, 1, 1], [2, 2], [3]] >>> group([1, 1, 1, 2, 2, 3], multiple=False) [(1, 3), (2, 2), (3, 1)] >>> group([1, 1, 3, 2, 2, 1], multiple=False) [(1, 2), (3, 1), (2, 2), (1, 1)] See Also ======== multiset """ if not seq: return [] current, groups = [seq[0]], [] for elem in seq[1:]: if elem == current[-1]: current.append(elem) else: groups.append(current) current = [elem] groups.append(current) if multiple: return groups for i, current in enumerate(groups): groups[i] = (current[0], len(current)) return groups def _iproduct2(iterable1, iterable2): '''Cartesian product of two possibly infinite iterables''' it1 = iter(iterable1) it2 = iter(iterable2) elems1 = [] elems2 = [] sentinel = object() def append(it, elems): e = next(it, sentinel) if e is not sentinel: elems.append(e) n = 0 append(it1, elems1) append(it2, elems2) while n <= len(elems1) + len(elems2): for m in range(n-len(elems1)+1, len(elems2)): yield (elems1[n-m], elems2[m]) n += 1 append(it1, elems1) append(it2, elems2) def iproduct(*iterables): ''' Cartesian product of iterables. Generator of the cartesian product of iterables. This is analogous to itertools.product except that it works with infinite iterables and will yield any item from the infinite product eventually. Examples ======== >>> from sympy.utilities.iterables import iproduct >>> sorted(iproduct([1,2], [3,4])) [(1, 3), (1, 4), (2, 3), (2, 4)] With an infinite iterator: >>> from sympy import S >>> (3,) in iproduct(S.Integers) True >>> (3, 4) in iproduct(S.Integers, S.Integers) True .. seealso:: `itertools.product `_ ''' if len(iterables) == 0: yield () return elif len(iterables) == 1: for e in iterables[0]: yield (e,) elif len(iterables) == 2: yield from _iproduct2(*iterables) else: first, others = iterables[0], iterables[1:] for ef, eo in _iproduct2(first, iproduct(*others)): yield (ef,) + eo def multiset(seq): """Return the hashable sequence in multiset form with values being the multiplicity of the item in the sequence. Examples ======== >>> from sympy.utilities.iterables import multiset >>> multiset('mississippi') {'i': 4, 'm': 1, 'p': 2, 's': 4} See Also ======== group """ rv = defaultdict(int) for s in seq: rv[s] += 1 return dict(rv) def postorder_traversal(node, keys=None): """ Do a postorder traversal of a tree. This generator recursively yields nodes that it has visited in a postorder fashion. That is, it descends through the tree depth-first to yield all of a node's children's postorder traversal before yielding the node itself. Parameters ========== node : sympy expression The expression to traverse. keys : (default None) sort key(s) The key(s) used to sort args of Basic objects. When None, args of Basic objects are processed in arbitrary order. If key is defined, it will be passed along to ordered() as the only key(s) to use to sort the arguments; if ``key`` is simply True then the default keys of ``ordered`` will be used (node count and default_sort_key). Yields ====== subtree : sympy expression All of the subtrees in the tree. Examples ======== >>> from sympy.utilities.iterables import postorder_traversal >>> from sympy.abc import w, x, y, z The nodes are returned in the order that they are encountered unless key is given; simply passing key=True will guarantee that the traversal is unique. >>> list(postorder_traversal(w + (x + y)*z)) # doctest: +SKIP [z, y, x, x + y, z*(x + y), w, w + z*(x + y)] >>> list(postorder_traversal(w + (x + y)*z, keys=True)) [w, z, x, y, x + y, z*(x + y), w + z*(x + y)] """ if isinstance(node, Basic): args = node.args if keys: if keys != True: args = ordered(args, keys, default=False) else: args = ordered(args) for arg in args: yield from postorder_traversal(arg, keys) elif iterable(node): for item in node: yield from postorder_traversal(item, keys) yield node def interactive_traversal(expr): """Traverse a tree asking a user which branch to choose. """ from sympy.printing import pprint RED, BRED = '\033[0;31m', '\033[1;31m' GREEN, BGREEN = '\033[0;32m', '\033[1;32m' YELLOW, BYELLOW = '\033[0;33m', '\033[1;33m' # noqa BLUE, BBLUE = '\033[0;34m', '\033[1;34m' # noqa MAGENTA, BMAGENTA = '\033[0;35m', '\033[1;35m'# noqa CYAN, BCYAN = '\033[0;36m', '\033[1;36m' # noqa END = '\033[0m' def cprint(*args): print("".join(map(str, args)) + END) def _interactive_traversal(expr, stage): if stage > 0: print() cprint("Current expression (stage ", BYELLOW, stage, END, "):") print(BCYAN) pprint(expr) print(END) if isinstance(expr, Basic): if expr.is_Add: args = expr.as_ordered_terms() elif expr.is_Mul: args = expr.as_ordered_factors() else: args = expr.args elif hasattr(expr, "__iter__"): args = list(expr) else: return expr n_args = len(args) if not n_args: return expr for i, arg in enumerate(args): cprint(GREEN, "[", BGREEN, i, GREEN, "] ", BLUE, type(arg), END) pprint(arg) print() if n_args == 1: choices = '0' else: choices = '0-%d' % (n_args - 1) try: choice = input("Your choice [%s,f,l,r,d,?]: " % choices) except EOFError: result = expr print() else: if choice == '?': cprint(RED, "%s - select subexpression with the given index" % choices) cprint(RED, "f - select the first subexpression") cprint(RED, "l - select the last subexpression") cprint(RED, "r - select a random subexpression") cprint(RED, "d - done\n") result = _interactive_traversal(expr, stage) elif choice in ['d', '']: result = expr elif choice == 'f': result = _interactive_traversal(args[0], stage + 1) elif choice == 'l': result = _interactive_traversal(args[-1], stage + 1) elif choice == 'r': result = _interactive_traversal(random.choice(args), stage + 1) else: try: choice = int(choice) except ValueError: cprint(BRED, "Choice must be a number in %s range\n" % choices) result = _interactive_traversal(expr, stage) else: if choice < 0 or choice >= n_args: cprint(BRED, "Choice must be in %s range\n" % choices) result = _interactive_traversal(expr, stage) else: result = _interactive_traversal(args[choice], stage + 1) return result return _interactive_traversal(expr, 0) def ibin(n, bits=None, str=False): """Return a list of length ``bits`` corresponding to the binary value of ``n`` with small bits to the right (last). If bits is omitted, the length will be the number required to represent ``n``. If the bits are desired in reversed order, use the ``[::-1]`` slice of the returned list. If a sequence of all bits-length lists starting from ``[0, 0,..., 0]`` through ``[1, 1, ..., 1]`` are desired, pass a non-integer for bits, e.g. ``'all'``. If the bit *string* is desired pass ``str=True``. Examples ======== >>> from sympy.utilities.iterables import ibin >>> ibin(2) [1, 0] >>> ibin(2, 4) [0, 0, 1, 0] If all lists corresponding to 0 to 2**n - 1, pass a non-integer for bits: >>> bits = 2 >>> for i in ibin(2, 'all'): ... print(i) (0, 0) (0, 1) (1, 0) (1, 1) If a bit string is desired of a given length, use str=True: >>> n = 123 >>> bits = 10 >>> ibin(n, bits, str=True) '0001111011' >>> ibin(n, bits, str=True)[::-1] # small bits left '1101111000' >>> list(ibin(3, 'all', str=True)) ['000', '001', '010', '011', '100', '101', '110', '111'] """ if n < 0: raise ValueError("negative numbers are not allowed") n = as_int(n) if bits is None: bits = 0 else: try: bits = as_int(bits) except ValueError: bits = -1 else: if n.bit_length() > bits: raise ValueError( "`bits` must be >= {}".format(n.bit_length())) if not str: if bits >= 0: return [1 if i == "1" else 0 for i in bin(n)[2:].rjust(bits, "0")] else: return variations(list(range(2)), n, repetition=True) else: if bits >= 0: return bin(n)[2:].rjust(bits, "0") else: return (bin(i)[2:].rjust(n, "0") for i in range(2**n)) def variations(seq, n, repetition=False): r"""Returns a generator of the n-sized variations of ``seq`` (size N). ``repetition`` controls whether items in ``seq`` can appear more than once; Examples ======== ``variations(seq, n)`` will return `\frac{N!}{(N - n)!}` permutations without repetition of ``seq``'s elements: >>> from sympy.utilities.iterables import variations >>> list(variations([1, 2], 2)) [(1, 2), (2, 1)] ``variations(seq, n, True)`` will return the `N^n` permutations obtained by allowing repetition of elements: >>> list(variations([1, 2], 2, repetition=True)) [(1, 1), (1, 2), (2, 1), (2, 2)] If you ask for more items than are in the set you get the empty set unless you allow repetitions: >>> list(variations([0, 1], 3, repetition=False)) [] >>> list(variations([0, 1], 3, repetition=True))[:4] [(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1)] .. seealso:: `itertools.permutations `_, `itertools.product `_ """ if not repetition: seq = tuple(seq) if len(seq) < n: return yield from permutations(seq, n) else: if n == 0: yield () else: yield from product(seq, repeat=n) def subsets(seq, k=None, repetition=False): r"""Generates all `k`-subsets (combinations) from an `n`-element set, ``seq``. A `k`-subset of an `n`-element set is any subset of length exactly `k`. The number of `k`-subsets of an `n`-element set is given by ``binomial(n, k)``, whereas there are `2^n` subsets all together. If `k` is ``None`` then all `2^n` subsets will be returned from shortest to longest. Examples ======== >>> from sympy.utilities.iterables import subsets ``subsets(seq, k)`` will return the `\frac{n!}{k!(n - k)!}` `k`-subsets (combinations) without repetition, i.e. once an item has been removed, it can no longer be "taken": >>> list(subsets([1, 2], 2)) [(1, 2)] >>> list(subsets([1, 2])) [(), (1,), (2,), (1, 2)] >>> list(subsets([1, 2, 3], 2)) [(1, 2), (1, 3), (2, 3)] ``subsets(seq, k, repetition=True)`` will return the `\frac{(n - 1 + k)!}{k!(n - 1)!}` combinations *with* repetition: >>> list(subsets([1, 2], 2, repetition=True)) [(1, 1), (1, 2), (2, 2)] If you ask for more items than are in the set you get the empty set unless you allow repetitions: >>> list(subsets([0, 1], 3, repetition=False)) [] >>> list(subsets([0, 1], 3, repetition=True)) [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)] """ if k is None: for k in range(len(seq) + 1): yield from subsets(seq, k, repetition) else: if not repetition: yield from combinations(seq, k) else: yield from combinations_with_replacement(seq, k) def filter_symbols(iterator, exclude): """ Only yield elements from `iterator` that do not occur in `exclude`. Parameters ========== iterator : iterable iterator to take elements from exclude : iterable elements to exclude Returns ======= iterator : iterator filtered iterator """ exclude = set(exclude) for s in iterator: if s not in exclude: yield s def numbered_symbols(prefix='x', cls=None, start=0, exclude=[], *args, **assumptions): """ Generate an infinite stream of Symbols consisting of a prefix and increasing subscripts provided that they do not occur in ``exclude``. Parameters ========== prefix : str, optional The prefix to use. By default, this function will generate symbols of the form "x0", "x1", etc. cls : class, optional The class to use. By default, it uses ``Symbol``, but you can also use ``Wild`` or ``Dummy``. start : int, optional The start number. By default, it is 0. Returns ======= sym : Symbol The subscripted symbols. """ exclude = set(exclude or []) if cls is None: # We can't just make the default cls=Symbol because it isn't # imported yet. from sympy import Symbol cls = Symbol while True: name = '%s%s' % (prefix, start) s = cls(name, *args, **assumptions) if s not in exclude: yield s start += 1 def capture(func): """Return the printed output of func(). ``func`` should be a function without arguments that produces output with print statements. >>> from sympy.utilities.iterables import capture >>> from sympy import pprint >>> from sympy.abc import x >>> def foo(): ... print('hello world!') ... >>> 'hello' in capture(foo) # foo, not foo() True >>> capture(lambda: pprint(2/x)) '2\\n-\\nx\\n' """ from io import StringIO import sys stdout = sys.stdout sys.stdout = file = StringIO() try: func() finally: sys.stdout = stdout return file.getvalue() def sift(seq, keyfunc, binary=False): """ Sift the sequence, ``seq`` according to ``keyfunc``. Returns ======= When ``binary`` is ``False`` (default), the output is a dictionary where elements of ``seq`` are stored in a list keyed to the value of keyfunc for that element. If ``binary`` is True then a tuple with lists ``T`` and ``F`` are returned where ``T`` is a list containing elements of seq for which ``keyfunc`` was ``True`` and ``F`` containing those elements for which ``keyfunc`` was ``False``; a ValueError is raised if the ``keyfunc`` is not binary. Examples ======== >>> from sympy.utilities import sift >>> from sympy.abc import x, y >>> from sympy import sqrt, exp, pi, Tuple >>> sift(range(5), lambda x: x % 2) {0: [0, 2, 4], 1: [1, 3]} sift() returns a defaultdict() object, so any key that has no matches will give []. >>> sift([x], lambda x: x.is_commutative) {True: [x]} >>> _[False] [] Sometimes you will not know how many keys you will get: >>> sift([sqrt(x), exp(x), (y**x)**2], ... lambda x: x.as_base_exp()[0]) {E: [exp(x)], x: [sqrt(x)], y: [y**(2*x)]} Sometimes you expect the results to be binary; the results can be unpacked by setting ``binary`` to True: >>> sift(range(4), lambda x: x % 2, binary=True) ([1, 3], [0, 2]) >>> sift(Tuple(1, pi), lambda x: x.is_rational, binary=True) ([1], [pi]) A ValueError is raised if the predicate was not actually binary (which is a good test for the logic where sifting is used and binary results were expected): >>> unknown = exp(1) - pi # the rationality of this is unknown >>> args = Tuple(1, pi, unknown) >>> sift(args, lambda x: x.is_rational, binary=True) Traceback (most recent call last): ... ValueError: keyfunc gave non-binary output The non-binary sifting shows that there were 3 keys generated: >>> set(sift(args, lambda x: x.is_rational).keys()) {None, False, True} If you need to sort the sifted items it might be better to use ``ordered`` which can economically apply multiple sort keys to a sequence while sorting. See Also ======== ordered """ if not binary: m = defaultdict(list) for i in seq: m[keyfunc(i)].append(i) return m sift = F, T = [], [] for i in seq: try: sift[keyfunc(i)].append(i) except (IndexError, TypeError): raise ValueError('keyfunc gave non-binary output') return T, F def take(iter, n): """Return ``n`` items from ``iter`` iterator. """ return [ value for _, value in zip(range(n), iter) ] def dict_merge(*dicts): """Merge dictionaries into a single dictionary. """ merged = {} for dict in dicts: merged.update(dict) return merged def common_prefix(*seqs): """Return the subsequence that is a common start of sequences in ``seqs``. >>> from sympy.utilities.iterables import common_prefix >>> common_prefix(list(range(3))) [0, 1, 2] >>> common_prefix(list(range(3)), list(range(4))) [0, 1, 2] >>> common_prefix([1, 2, 3], [1, 2, 5]) [1, 2] >>> common_prefix([1, 2, 3], [1, 3, 5]) [1] """ if any(not s for s in seqs): return [] elif len(seqs) == 1: return seqs[0] i = 0 for i in range(min(len(s) for s in seqs)): if not all(seqs[j][i] == seqs[0][i] for j in range(len(seqs))): break else: i += 1 return seqs[0][:i] def common_suffix(*seqs): """Return the subsequence that is a common ending of sequences in ``seqs``. >>> from sympy.utilities.iterables import common_suffix >>> common_suffix(list(range(3))) [0, 1, 2] >>> common_suffix(list(range(3)), list(range(4))) [] >>> common_suffix([1, 2, 3], [9, 2, 3]) [2, 3] >>> common_suffix([1, 2, 3], [9, 7, 3]) [3] """ if any(not s for s in seqs): return [] elif len(seqs) == 1: return seqs[0] i = 0 for i in range(-1, -min(len(s) for s in seqs) - 1, -1): if not all(seqs[j][i] == seqs[0][i] for j in range(len(seqs))): break else: i -= 1 if i == -1: return [] else: return seqs[0][i + 1:] def prefixes(seq): """ Generate all prefixes of a sequence. Examples ======== >>> from sympy.utilities.iterables import prefixes >>> list(prefixes([1,2,3,4])) [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4]] """ n = len(seq) for i in range(n): yield seq[:i + 1] def postfixes(seq): """ Generate all postfixes of a sequence. Examples ======== >>> from sympy.utilities.iterables import postfixes >>> list(postfixes([1,2,3,4])) [[4], [3, 4], [2, 3, 4], [1, 2, 3, 4]] """ n = len(seq) for i in range(n): yield seq[n - i - 1:] def topological_sort(graph, key=None): r""" Topological sort of graph's vertices. Parameters ========== graph : tuple[list, list[tuple[T, T]] A tuple consisting of a list of vertices and a list of edges of a graph to be sorted topologically. key : callable[T] (optional) Ordering key for vertices on the same level. By default the natural (e.g. lexicographic) ordering is used (in this case the base type must implement ordering relations). Examples ======== Consider a graph:: +---+ +---+ +---+ | 7 |\ | 5 | | 3 | +---+ \ +---+ +---+ | _\___/ ____ _/ | | / \___/ \ / | V V V V | +----+ +---+ | | 11 | | 8 | | +----+ +---+ | | | \____ ___/ _ | | \ \ / / \ | V \ V V / V V +---+ \ +---+ | +----+ | 2 | | | 9 | | | 10 | +---+ | +---+ | +----+ \________/ where vertices are integers. This graph can be encoded using elementary Python's data structures as follows:: >>> V = [2, 3, 5, 7, 8, 9, 10, 11] >>> E = [(7, 11), (7, 8), (5, 11), (3, 8), (3, 10), ... (11, 2), (11, 9), (11, 10), (8, 9)] To compute a topological sort for graph ``(V, E)`` issue:: >>> from sympy.utilities.iterables import topological_sort >>> topological_sort((V, E)) [3, 5, 7, 8, 11, 2, 9, 10] If specific tie breaking approach is needed, use ``key`` parameter:: >>> topological_sort((V, E), key=lambda v: -v) [7, 5, 11, 3, 10, 8, 9, 2] Only acyclic graphs can be sorted. If the input graph has a cycle, then ``ValueError`` will be raised:: >>> topological_sort((V, E + [(10, 7)])) Traceback (most recent call last): ... ValueError: cycle detected References ========== .. [1] https://en.wikipedia.org/wiki/Topological_sorting """ V, E = graph L = [] S = set(V) E = list(E) for v, u in E: S.discard(u) if key is None: key = lambda value: value S = sorted(S, key=key, reverse=True) while S: node = S.pop() L.append(node) for u, v in list(E): if u == node: E.remove((u, v)) for _u, _v in E: if v == _v: break else: kv = key(v) for i, s in enumerate(S): ks = key(s) if kv > ks: S.insert(i, v) break else: S.append(v) if E: raise ValueError("cycle detected") else: return L def strongly_connected_components(G): r""" Strongly connected components of a directed graph in reverse topological order. Parameters ========== graph : tuple[list, list[tuple[T, T]] A tuple consisting of a list of vertices and a list of edges of a graph whose strongly connected components are to be found. Examples ======== Consider a directed graph (in dot notation):: digraph { A -> B A -> C B -> C C -> B B -> D } where vertices are the letters A, B, C and D. This graph can be encoded using Python's elementary data structures as follows:: >>> V = ['A', 'B', 'C', 'D'] >>> E = [('A', 'B'), ('A', 'C'), ('B', 'C'), ('C', 'B'), ('B', 'D')] The strongly connected components of this graph can be computed as >>> from sympy.utilities.iterables import strongly_connected_components >>> strongly_connected_components((V, E)) [['D'], ['B', 'C'], ['A']] This also gives the components in reverse topological order. Since the subgraph containing B and C has a cycle they must be together in a strongly connected component. A and D are connected to the rest of the graph but not in a cyclic manner so they appear as their own strongly connected components. Notes ===== The vertices of the graph must be hashable for the data structures used. If the vertices are unhashable replace them with integer indices. This function uses Tarjan's algorithm to compute the strongly connected components in `O(|V|+|E|)` (linear) time. References ========== .. [1] https://en.wikipedia.org/wiki/Strongly_connected_component .. [2] https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm See Also ======== sympy.utilities.iterables.connected_components """ # Map from a vertex to its neighbours V, E = G Gmap = {vi: [] for vi in V} for v1, v2 in E: Gmap[v1].append(v2) return _strongly_connected_components(V, Gmap) def _strongly_connected_components(V, Gmap): """More efficient internal routine for strongly_connected_components""" # # Here V is an iterable of vertices and Gmap is a dict mapping each vertex # to a list of neighbours e.g.: # # V = [0, 1, 2, 3] # Gmap = {0: [2, 3], 1: [0]} # # For a large graph these data structures can often be created more # efficiently then those expected by strongly_connected_components() which # in this case would be # # V = [0, 1, 2, 3] # Gmap = [(0, 2), (0, 3), (1, 0)] # # XXX: Maybe this should be the recommended function to use instead... # # Non-recursive Tarjan's algorithm: lowlink = {} indices = {} stack = OrderedDict() callstack = [] components = [] nomore = object() def start(v): index = len(stack) indices[v] = lowlink[v] = index stack[v] = None callstack.append((v, iter(Gmap[v]))) def finish(v1): # Finished a component? if lowlink[v1] == indices[v1]: component = [stack.popitem()[0]] while component[-1] is not v1: component.append(stack.popitem()[0]) components.append(component[::-1]) v2, _ = callstack.pop() if callstack: v1, _ = callstack[-1] lowlink[v1] = min(lowlink[v1], lowlink[v2]) for v in V: if v in indices: continue start(v) while callstack: v1, it1 = callstack[-1] v2 = next(it1, nomore) # Finished children of v1? if v2 is nomore: finish(v1) # Recurse on v2 elif v2 not in indices: start(v2) elif v2 in stack: lowlink[v1] = min(lowlink[v1], indices[v2]) # Reverse topological sort order: return components def connected_components(G): r""" Connected components of an undirected graph or weakly connected components of a directed graph. Parameters ========== graph : tuple[list, list[tuple[T, T]] A tuple consisting of a list of vertices and a list of edges of a graph whose connected components are to be found. Examples ======== Given an undirected graph:: graph { A -- B C -- D } We can find the connected components using this function if we include each edge in both directions:: >>> from sympy.utilities.iterables import connected_components >>> V = ['A', 'B', 'C', 'D'] >>> E = [('A', 'B'), ('B', 'A'), ('C', 'D'), ('D', 'C')] >>> connected_components((V, E)) [['A', 'B'], ['C', 'D']] The weakly connected components of a directed graph can found the same way. Notes ===== The vertices of the graph must be hashable for the data structures used. If the vertices are unhashable replace them with integer indices. This function uses Tarjan's algorithm to compute the connected components in `O(|V|+|E|)` (linear) time. References ========== .. [1] https://en.wikipedia.org/wiki/Connected_component_(graph_theory) .. [2] https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm See Also ======== sympy.utilities.iterables.strongly_connected_components """ # Duplicate edges both ways so that the graph is effectively undirected # and return the strongly connected components: V, E = G E_undirected = [] for v1, v2 in E: E_undirected.extend([(v1, v2), (v2, v1)]) return strongly_connected_components((V, E_undirected)) def rotate_left(x, y): """ Left rotates a list x by the number of steps specified in y. Examples ======== >>> from sympy.utilities.iterables import rotate_left >>> a = [0, 1, 2] >>> rotate_left(a, 1) [1, 2, 0] """ if len(x) == 0: return [] y = y % len(x) return x[y:] + x[:y] def rotate_right(x, y): """ Right rotates a list x by the number of steps specified in y. Examples ======== >>> from sympy.utilities.iterables import rotate_right >>> a = [0, 1, 2] >>> rotate_right(a, 1) [2, 0, 1] """ if len(x) == 0: return [] y = len(x) - y % len(x) return x[y:] + x[:y] def least_rotation(x, key=None): ''' Returns the number of steps of left rotation required to obtain lexicographically minimal string/list/tuple, etc. Examples ======== >>> from sympy.utilities.iterables import least_rotation, rotate_left >>> a = [3, 1, 5, 1, 2] >>> least_rotation(a) 3 >>> rotate_left(a, _) [1, 2, 3, 1, 5] References ========== .. [1] https://en.wikipedia.org/wiki/Lexicographically_minimal_string_rotation ''' if key is None: key = sympy.Id S = x + x # Concatenate string to it self to avoid modular arithmetic f = [-1] * len(S) # Failure function k = 0 # Least rotation of string found so far for j in range(1,len(S)): sj = S[j] i = f[j-k-1] while i != -1 and sj != S[k+i+1]: if key(sj) < key(S[k+i+1]): k = j-i-1 i = f[i] if sj != S[k+i+1]: if key(sj) < key(S[k]): k = j f[j-k] = -1 else: f[j-k] = i+1 return k def multiset_combinations(m, n, g=None): """ Return the unique combinations of size ``n`` from multiset ``m``. Examples ======== >>> from sympy.utilities.iterables import multiset_combinations >>> from itertools import combinations >>> [''.join(i) for i in multiset_combinations('baby', 3)] ['abb', 'aby', 'bby'] >>> def count(f, s): return len(list(f(s, 3))) The number of combinations depends on the number of letters; the number of unique combinations depends on how the letters are repeated. >>> s1 = 'abracadabra' >>> s2 = 'banana tree' >>> count(combinations, s1), count(multiset_combinations, s1) (165, 23) >>> count(combinations, s2), count(multiset_combinations, s2) (165, 54) """ if g is None: if type(m) is dict: if n > sum(m.values()): return g = [[k, m[k]] for k in ordered(m)] else: m = list(m) if n > len(m): return try: m = multiset(m) g = [(k, m[k]) for k in ordered(m)] except TypeError: m = list(ordered(m)) g = [list(i) for i in group(m, multiple=False)] del m if sum(v for k, v in g) < n or not n: yield [] else: for i, (k, v) in enumerate(g): if v >= n: yield [k]*n v = n - 1 for v in range(min(n, v), 0, -1): for j in multiset_combinations(None, n - v, g[i + 1:]): rv = [k]*v + j if len(rv) == n: yield rv def multiset_permutations(m, size=None, g=None): """ Return the unique permutations of multiset ``m``. Examples ======== >>> from sympy.utilities.iterables import multiset_permutations >>> from sympy import factorial >>> [''.join(i) for i in multiset_permutations('aab')] ['aab', 'aba', 'baa'] >>> factorial(len('banana')) 720 >>> len(list(multiset_permutations('banana'))) 60 """ if g is None: if type(m) is dict: g = [[k, m[k]] for k in ordered(m)] else: m = list(ordered(m)) g = [list(i) for i in group(m, multiple=False)] del m do = [gi for gi in g if gi[1] > 0] SUM = sum([gi[1] for gi in do]) if not do or size is not None and (size > SUM or size < 1): if not do and size is None or size == 0: yield [] return elif size == 1: for k, v in do: yield [k] elif len(do) == 1: k, v = do[0] v = v if size is None else (size if size <= v else 0) yield [k for i in range(v)] elif all(v == 1 for k, v in do): for p in permutations([k for k, v in do], size): yield list(p) else: size = size if size is not None else SUM for i, (k, v) in enumerate(do): do[i][1] -= 1 for j in multiset_permutations(None, size - 1, do): if j: yield [k] + j do[i][1] += 1 def _partition(seq, vector, m=None): """ Return the partition of seq as specified by the partition vector. Examples ======== >>> from sympy.utilities.iterables import _partition >>> _partition('abcde', [1, 0, 1, 2, 0]) [['b', 'e'], ['a', 'c'], ['d']] Specifying the number of bins in the partition is optional: >>> _partition('abcde', [1, 0, 1, 2, 0], 3) [['b', 'e'], ['a', 'c'], ['d']] The output of _set_partitions can be passed as follows: >>> output = (3, [1, 0, 1, 2, 0]) >>> _partition('abcde', *output) [['b', 'e'], ['a', 'c'], ['d']] See Also ======== combinatorics.partitions.Partition.from_rgs """ if m is None: m = max(vector) + 1 elif type(vector) is int: # entered as m, vector vector, m = m, vector p = [[] for i in range(m)] for i, v in enumerate(vector): p[v].append(seq[i]) return p def _set_partitions(n): """Cycle through all partions of n elements, yielding the current number of partitions, ``m``, and a mutable list, ``q`` such that element[i] is in part q[i] of the partition. NOTE: ``q`` is modified in place and generally should not be changed between function calls. Examples ======== >>> from sympy.utilities.iterables import _set_partitions, _partition >>> for m, q in _set_partitions(3): ... print('%s %s %s' % (m, q, _partition('abc', q, m))) 1 [0, 0, 0] [['a', 'b', 'c']] 2 [0, 0, 1] [['a', 'b'], ['c']] 2 [0, 1, 0] [['a', 'c'], ['b']] 2 [0, 1, 1] [['a'], ['b', 'c']] 3 [0, 1, 2] [['a'], ['b'], ['c']] Notes ===== This algorithm is similar to, and solves the same problem as, Algorithm 7.2.1.5H, from volume 4A of Knuth's The Art of Computer Programming. Knuth uses the term "restricted growth string" where this code refers to a "partition vector". In each case, the meaning is the same: the value in the ith element of the vector specifies to which part the ith set element is to be assigned. At the lowest level, this code implements an n-digit big-endian counter (stored in the array q) which is incremented (with carries) to get the next partition in the sequence. A special twist is that a digit is constrained to be at most one greater than the maximum of all the digits to the left of it. The array p maintains this maximum, so that the code can efficiently decide when a digit can be incremented in place or whether it needs to be reset to 0 and trigger a carry to the next digit. The enumeration starts with all the digits 0 (which corresponds to all the set elements being assigned to the same 0th part), and ends with 0123...n, which corresponds to each set element being assigned to a different, singleton, part. This routine was rewritten to use 0-based lists while trying to preserve the beauty and efficiency of the original algorithm. References ========== .. [1] Nijenhuis, Albert and Wilf, Herbert. (1978) Combinatorial Algorithms, 2nd Ed, p 91, algorithm "nexequ". Available online from https://www.math.upenn.edu/~wilf/website/CombAlgDownld.html (viewed November 17, 2012). """ p = [0]*n q = [0]*n nc = 1 yield nc, q while nc != n: m = n while 1: m -= 1 i = q[m] if p[i] != 1: break q[m] = 0 i += 1 q[m] = i m += 1 nc += m - n p[0] += n - m if i == nc: p[nc] = 0 nc += 1 p[i - 1] -= 1 p[i] += 1 yield nc, q def multiset_partitions(multiset, m=None): """ Return unique partitions of the given multiset (in list form). If ``m`` is None, all multisets will be returned, otherwise only partitions with ``m`` parts will be returned. If ``multiset`` is an integer, a range [0, 1, ..., multiset - 1] will be supplied. Examples ======== >>> from sympy.utilities.iterables import multiset_partitions >>> list(multiset_partitions([1, 2, 3, 4], 2)) [[[1, 2, 3], [4]], [[1, 2, 4], [3]], [[1, 2], [3, 4]], [[1, 3, 4], [2]], [[1, 3], [2, 4]], [[1, 4], [2, 3]], [[1], [2, 3, 4]]] >>> list(multiset_partitions([1, 2, 3, 4], 1)) [[[1, 2, 3, 4]]] Only unique partitions are returned and these will be returned in a canonical order regardless of the order of the input: >>> a = [1, 2, 2, 1] >>> ans = list(multiset_partitions(a, 2)) >>> a.sort() >>> list(multiset_partitions(a, 2)) == ans True >>> a = range(3, 1, -1) >>> (list(multiset_partitions(a)) == ... list(multiset_partitions(sorted(a)))) True If m is omitted then all partitions will be returned: >>> list(multiset_partitions([1, 1, 2])) [[[1, 1, 2]], [[1, 1], [2]], [[1, 2], [1]], [[1], [1], [2]]] >>> list(multiset_partitions([1]*3)) [[[1, 1, 1]], [[1], [1, 1]], [[1], [1], [1]]] Counting ======== The number of partitions of a set is given by the bell number: >>> from sympy import bell >>> len(list(multiset_partitions(5))) == bell(5) == 52 True The number of partitions of length k from a set of size n is given by the Stirling Number of the 2nd kind: >>> from sympy.functions.combinatorial.numbers import stirling >>> stirling(5, 2) == len(list(multiset_partitions(5, 2))) == 15 True These comments on counting apply to *sets*, not multisets. Notes ===== When all the elements are the same in the multiset, the order of the returned partitions is determined by the ``partitions`` routine. If one is counting partitions then it is better to use the ``nT`` function. See Also ======== partitions sympy.combinatorics.partitions.Partition sympy.combinatorics.partitions.IntegerPartition sympy.functions.combinatorial.numbers.nT """ # This function looks at the supplied input and dispatches to # several special-case routines as they apply. if type(multiset) is int: n = multiset if m and m > n: return multiset = list(range(n)) if m == 1: yield [multiset[:]] return # If m is not None, it can sometimes be faster to use # MultisetPartitionTraverser.enum_range() even for inputs # which are sets. Since the _set_partitions code is quite # fast, this is only advantageous when the overall set # partitions outnumber those with the desired number of parts # by a large factor. (At least 60.) Such a switch is not # currently implemented. for nc, q in _set_partitions(n): if m is None or nc == m: rv = [[] for i in range(nc)] for i in range(n): rv[q[i]].append(multiset[i]) yield rv return if len(multiset) == 1 and isinstance(multiset, str): multiset = [multiset] if not has_variety(multiset): # Only one component, repeated n times. The resulting # partitions correspond to partitions of integer n. n = len(multiset) if m and m > n: return if m == 1: yield [multiset[:]] return x = multiset[:1] for size, p in partitions(n, m, size=True): if m is None or size == m: rv = [] for k in sorted(p): rv.extend([x*k]*p[k]) yield rv else: multiset = list(ordered(multiset)) n = len(multiset) if m and m > n: return if m == 1: yield [multiset[:]] return # Split the information of the multiset into two lists - # one of the elements themselves, and one (of the same length) # giving the number of repeats for the corresponding element. elements, multiplicities = zip(*group(multiset, False)) if len(elements) < len(multiset): # General case - multiset with more than one distinct element # and at least one element repeated more than once. if m: mpt = MultisetPartitionTraverser() for state in mpt.enum_range(multiplicities, m-1, m): yield list_visitor(state, elements) else: for state in multiset_partitions_taocp(multiplicities): yield list_visitor(state, elements) else: # Set partitions case - no repeated elements. Pretty much # same as int argument case above, with same possible, but # currently unimplemented optimization for some cases when # m is not None for nc, q in _set_partitions(n): if m is None or nc == m: rv = [[] for i in range(nc)] for i in range(n): rv[q[i]].append(i) yield [[multiset[j] for j in i] for i in rv] def partitions(n, m=None, k=None, size=False): """Generate all partitions of positive integer, n. Parameters ========== m : integer (default gives partitions of all sizes) limits number of parts in partition (mnemonic: m, maximum parts) k : integer (default gives partitions number from 1 through n) limits the numbers that are kept in the partition (mnemonic: k, keys) size : bool (default False, only partition is returned) when ``True`` then (M, P) is returned where M is the sum of the multiplicities and P is the generated partition. Each partition is represented as a dictionary, mapping an integer to the number of copies of that integer in the partition. For example, the first partition of 4 returned is {4: 1}, "4: one of them". Examples ======== >>> from sympy.utilities.iterables import partitions The numbers appearing in the partition (the key of the returned dict) are limited with k: >>> for p in partitions(6, k=2): # doctest: +SKIP ... print(p) {2: 3} {1: 2, 2: 2} {1: 4, 2: 1} {1: 6} The maximum number of parts in the partition (the sum of the values in the returned dict) are limited with m (default value, None, gives partitions from 1 through n): >>> for p in partitions(6, m=2): # doctest: +SKIP ... print(p) ... {6: 1} {1: 1, 5: 1} {2: 1, 4: 1} {3: 2} References ========== .. [1] modified from Tim Peter's version to allow for k and m values: http://code.activestate.com/recipes/218332-generator-for-integer-partitions/ See Also ======== sympy.combinatorics.partitions.Partition sympy.combinatorics.partitions.IntegerPartition """ if (n <= 0 or m is not None and m < 1 or k is not None and k < 1 or m and k and m*k < n): # the empty set is the only way to handle these inputs # and returning {} to represent it is consistent with # the counting convention, e.g. nT(0) == 1. if size: yield 0, {} else: yield {} return if m is None: m = n else: m = min(m, n) k = min(k or n, n) n, m, k = as_int(n), as_int(m), as_int(k) q, r = divmod(n, k) ms = {k: q} keys = [k] # ms.keys(), from largest to smallest if r: ms[r] = 1 keys.append(r) room = m - q - bool(r) if size: yield sum(ms.values()), ms.copy() else: yield ms.copy() while keys != [1]: # Reuse any 1's. if keys[-1] == 1: del keys[-1] reuse = ms.pop(1) room += reuse else: reuse = 0 while 1: # Let i be the smallest key larger than 1. Reuse one # instance of i. i = keys[-1] newcount = ms[i] = ms[i] - 1 reuse += i if newcount == 0: del keys[-1], ms[i] room += 1 # Break the remainder into pieces of size i-1. i -= 1 q, r = divmod(reuse, i) need = q + bool(r) if need > room: if not keys: return continue ms[i] = q keys.append(i) if r: ms[r] = 1 keys.append(r) break room -= need if size: yield sum(ms.values()), ms.copy() else: yield ms.copy() def ordered_partitions(n, m=None, sort=True): """Generates ordered partitions of integer ``n``. Parameters ========== m : integer (default None) The default value gives partitions of all sizes else only those with size m. In addition, if ``m`` is not None then partitions are generated *in place* (see examples). sort : bool (default True) Controls whether partitions are returned in sorted order when ``m`` is not None; when False, the partitions are returned as fast as possible with elements sorted, but when m|n the partitions will not be in ascending lexicographical order. Examples ======== >>> from sympy.utilities.iterables import ordered_partitions All partitions of 5 in ascending lexicographical: >>> for p in ordered_partitions(5): ... print(p) [1, 1, 1, 1, 1] [1, 1, 1, 2] [1, 1, 3] [1, 2, 2] [1, 4] [2, 3] [5] Only partitions of 5 with two parts: >>> for p in ordered_partitions(5, 2): ... print(p) [1, 4] [2, 3] When ``m`` is given, a given list objects will be used more than once for speed reasons so you will not see the correct partitions unless you make a copy of each as it is generated: >>> [p for p in ordered_partitions(7, 3)] [[1, 1, 1], [1, 1, 1], [1, 1, 1], [2, 2, 2]] >>> [list(p) for p in ordered_partitions(7, 3)] [[1, 1, 5], [1, 2, 4], [1, 3, 3], [2, 2, 3]] When ``n`` is a multiple of ``m``, the elements are still sorted but the partitions themselves will be *unordered* if sort is False; the default is to return them in ascending lexicographical order. >>> for p in ordered_partitions(6, 2): ... print(p) [1, 5] [2, 4] [3, 3] But if speed is more important than ordering, sort can be set to False: >>> for p in ordered_partitions(6, 2, sort=False): ... print(p) [1, 5] [3, 3] [2, 4] References ========== .. [1] Generating Integer Partitions, [online], Available: https://jeromekelleher.net/generating-integer-partitions.html .. [2] Jerome Kelleher and Barry O'Sullivan, "Generating All Partitions: A Comparison Of Two Encodings", [online], Available: https://arxiv.org/pdf/0909.2331v2.pdf """ if n < 1 or m is not None and m < 1: # the empty set is the only way to handle these inputs # and returning {} to represent it is consistent with # the counting convention, e.g. nT(0) == 1. yield [] return if m is None: # The list `a`'s leading elements contain the partition in which # y is the biggest element and x is either the same as y or the # 2nd largest element; v and w are adjacent element indices # to which x and y are being assigned, respectively. a = [1]*n y = -1 v = n while v > 0: v -= 1 x = a[v] + 1 while y >= 2 * x: a[v] = x y -= x v += 1 w = v + 1 while x <= y: a[v] = x a[w] = y yield a[:w + 1] x += 1 y -= 1 a[v] = x + y y = a[v] - 1 yield a[:w] elif m == 1: yield [n] elif n == m: yield [1]*n else: # recursively generate partitions of size m for b in range(1, n//m + 1): a = [b]*m x = n - b*m if not x: if sort: yield a elif not sort and x <= m: for ax in ordered_partitions(x, sort=False): mi = len(ax) a[-mi:] = [i + b for i in ax] yield a a[-mi:] = [b]*mi else: for mi in range(1, m): for ax in ordered_partitions(x, mi, sort=True): a[-mi:] = [i + b for i in ax] yield a a[-mi:] = [b]*mi def binary_partitions(n): """ Generates the binary partition of n. A binary partition consists only of numbers that are powers of two. Each step reduces a `2^{k+1}` to `2^k` and `2^k`. Thus 16 is converted to 8 and 8. Examples ======== >>> from sympy.utilities.iterables import binary_partitions >>> for i in binary_partitions(5): ... print(i) ... [4, 1] [2, 2, 1] [2, 1, 1, 1] [1, 1, 1, 1, 1] References ========== .. [1] TAOCP 4, section 7.2.1.5, problem 64 """ from math import ceil, log pow = int(2**(ceil(log(n, 2)))) sum = 0 partition = [] while pow: if sum + pow <= n: partition.append(pow) sum += pow pow >>= 1 last_num = len(partition) - 1 - (n & 1) while last_num >= 0: yield partition if partition[last_num] == 2: partition[last_num] = 1 partition.append(1) last_num -= 1 continue partition.append(1) partition[last_num] >>= 1 x = partition[last_num + 1] = partition[last_num] last_num += 1 while x > 1: if x <= len(partition) - last_num - 1: del partition[-x + 1:] last_num += 1 partition[last_num] = x else: x >>= 1 yield [1]*n def has_dups(seq): """Return True if there are any duplicate elements in ``seq``. Examples ======== >>> from sympy.utilities.iterables import has_dups >>> from sympy import Dict, Set >>> has_dups((1, 2, 1)) True >>> has_dups(range(3)) False >>> all(has_dups(c) is False for c in (set(), Set(), dict(), Dict())) True """ from sympy.core.containers import Dict from sympy.sets.sets import Set if isinstance(seq, (dict, set, Dict, Set)): return False uniq = set() return any(True for s in seq if s in uniq or uniq.add(s)) def has_variety(seq): """Return True if there are any different elements in ``seq``. Examples ======== >>> from sympy.utilities.iterables import has_variety >>> has_variety((1, 2, 1)) True >>> has_variety((1, 1, 1)) False """ for i, s in enumerate(seq): if i == 0: sentinel = s else: if s != sentinel: return True return False def uniq(seq, result=None): """ Yield unique elements from ``seq`` as an iterator. The second parameter ``result`` is used internally; it is not necessary to pass anything for this. Note: changing the sequence during iteration will raise a RuntimeError if the size of the sequence is known; if you pass an iterator and advance the iterator you will change the output of this routine but there will be no warning. Examples ======== >>> from sympy.utilities.iterables import uniq >>> dat = [1, 4, 1, 5, 4, 2, 1, 2] >>> type(uniq(dat)) in (list, tuple) False >>> list(uniq(dat)) [1, 4, 5, 2] >>> list(uniq(x for x in dat)) [1, 4, 5, 2] >>> list(uniq([[1], [2, 1], [1]])) [[1], [2, 1]] """ try: n = len(seq) except TypeError: n = None def check(): # check that size of seq did not change during iteration; # if n == None the object won't support size changing, e.g. # an iterator can't be changed if n is not None and len(seq) != n: raise RuntimeError('sequence changed size during iteration') try: seen = set() result = result or [] for i, s in enumerate(seq): if not (s in seen or seen.add(s)): yield s check() except TypeError: if s not in result: yield s check() result.append(s) if hasattr(seq, '__getitem__'): yield from uniq(seq[i + 1:], result) else: yield from uniq(seq, result) def generate_bell(n): """Return permutations of [0, 1, ..., n - 1] such that each permutation differs from the last by the exchange of a single pair of neighbors. The ``n!`` permutations are returned as an iterator. In order to obtain the next permutation from a random starting permutation, use the ``next_trotterjohnson`` method of the Permutation class (which generates the same sequence in a different manner). Examples ======== >>> from itertools import permutations >>> from sympy.utilities.iterables import generate_bell >>> from sympy import zeros, Matrix This is the sort of permutation used in the ringing of physical bells, and does not produce permutations in lexicographical order. Rather, the permutations differ from each other by exactly one inversion, and the position at which the swapping occurs varies periodically in a simple fashion. Consider the first few permutations of 4 elements generated by ``permutations`` and ``generate_bell``: >>> list(permutations(range(4)))[:5] [(0, 1, 2, 3), (0, 1, 3, 2), (0, 2, 1, 3), (0, 2, 3, 1), (0, 3, 1, 2)] >>> list(generate_bell(4))[:5] [(0, 1, 2, 3), (0, 1, 3, 2), (0, 3, 1, 2), (3, 0, 1, 2), (3, 0, 2, 1)] Notice how the 2nd and 3rd lexicographical permutations have 3 elements out of place whereas each "bell" permutation always has only two elements out of place relative to the previous permutation (and so the signature (+/-1) of a permutation is opposite of the signature of the previous permutation). How the position of inversion varies across the elements can be seen by tracing out where the largest number appears in the permutations: >>> m = zeros(4, 24) >>> for i, p in enumerate(generate_bell(4)): ... m[:, i] = Matrix([j - 3 for j in list(p)]) # make largest zero >>> m.print_nonzero('X') [XXX XXXXXX XXXXXX XXX] [XX XX XXXX XX XXXX XX XX] [X XXXX XX XXXX XX XXXX X] [ XXXXXX XXXXXX XXXXXX ] See Also ======== sympy.combinatorics.permutations.Permutation.next_trotterjohnson References ========== .. [1] https://en.wikipedia.org/wiki/Method_ringing .. [2] https://stackoverflow.com/questions/4856615/recursive-permutation/4857018 .. [3] http://programminggeeks.com/bell-algorithm-for-permutation/ .. [4] https://en.wikipedia.org/wiki/Steinhaus%E2%80%93Johnson%E2%80%93Trotter_algorithm .. [5] Generating involutions, derangements, and relatives by ECO Vincent Vajnovszki, DMTCS vol 1 issue 12, 2010 """ n = as_int(n) if n < 1: raise ValueError('n must be a positive integer') if n == 1: yield (0,) elif n == 2: yield (0, 1) yield (1, 0) elif n == 3: yield from [(0, 1, 2), (0, 2, 1), (2, 0, 1), (2, 1, 0), (1, 2, 0), (1, 0, 2)] else: m = n - 1 op = [0] + [-1]*m l = list(range(n)) while True: yield tuple(l) # find biggest element with op big = None, -1 # idx, value for i in range(n): if op[i] and l[i] > big[1]: big = i, l[i] i, _ = big if i is None: break # there are no ops left # swap it with neighbor in the indicated direction j = i + op[i] l[i], l[j] = l[j], l[i] op[i], op[j] = op[j], op[i] # if it landed at the end or if the neighbor in the same # direction is bigger then turn off op if j == 0 or j == m or l[j + op[j]] > l[j]: op[j] = 0 # any element bigger to the left gets +1 op for i in range(j): if l[i] > l[j]: op[i] = 1 # any element bigger to the right gets -1 op for i in range(j + 1, n): if l[i] > l[j]: op[i] = -1 def generate_involutions(n): """ Generates involutions. An involution is a permutation that when multiplied by itself equals the identity permutation. In this implementation the involutions are generated using Fixed Points. Alternatively, an involution can be considered as a permutation that does not contain any cycles with a length that is greater than two. Examples ======== >>> from sympy.utilities.iterables import generate_involutions >>> list(generate_involutions(3)) [(0, 1, 2), (0, 2, 1), (1, 0, 2), (2, 1, 0)] >>> len(list(generate_involutions(4))) 10 References ========== .. [1] http://mathworld.wolfram.com/PermutationInvolution.html """ idx = list(range(n)) for p in permutations(idx): for i in idx: if p[p[i]] != i: break else: yield p def generate_derangements(perm): """ Routine to generate unique derangements. TODO: This will be rewritten to use the ECO operator approach once the permutations branch is in master. Examples ======== >>> from sympy.utilities.iterables import generate_derangements >>> list(generate_derangements([0, 1, 2])) [[1, 2, 0], [2, 0, 1]] >>> list(generate_derangements([0, 1, 2, 3])) [[1, 0, 3, 2], [1, 2, 3, 0], [1, 3, 0, 2], [2, 0, 3, 1], \ [2, 3, 0, 1], [2, 3, 1, 0], [3, 0, 1, 2], [3, 2, 0, 1], \ [3, 2, 1, 0]] >>> list(generate_derangements([0, 1, 1])) [] See Also ======== sympy.functions.combinatorial.factorials.subfactorial """ for p in multiset_permutations(perm): if not any(i == j for i, j in zip(perm, p)): yield p def necklaces(n, k, free=False): """ A routine to generate necklaces that may (free=True) or may not (free=False) be turned over to be viewed. The "necklaces" returned are comprised of ``n`` integers (beads) with ``k`` different values (colors). Only unique necklaces are returned. Examples ======== >>> from sympy.utilities.iterables import necklaces, bracelets >>> def show(s, i): ... return ''.join(s[j] for j in i) The "unrestricted necklace" is sometimes also referred to as a "bracelet" (an object that can be turned over, a sequence that can be reversed) and the term "necklace" is used to imply a sequence that cannot be reversed. So ACB == ABC for a bracelet (rotate and reverse) while the two are different for a necklace since rotation alone cannot make the two sequences the same. (mnemonic: Bracelets can be viewed Backwards, but Not Necklaces.) >>> B = [show('ABC', i) for i in bracelets(3, 3)] >>> N = [show('ABC', i) for i in necklaces(3, 3)] >>> set(N) - set(B) {'ACB'} >>> list(necklaces(4, 2)) [(0, 0, 0, 0), (0, 0, 0, 1), (0, 0, 1, 1), (0, 1, 0, 1), (0, 1, 1, 1), (1, 1, 1, 1)] >>> [show('.o', i) for i in bracelets(4, 2)] ['....', '...o', '..oo', '.o.o', '.ooo', 'oooo'] References ========== .. [1] http://mathworld.wolfram.com/Necklace.html """ return uniq(minlex(i, directed=not free) for i in variations(list(range(k)), n, repetition=True)) def bracelets(n, k): """Wrapper to necklaces to return a free (unrestricted) necklace.""" return necklaces(n, k, free=True) def generate_oriented_forest(n): """ This algorithm generates oriented forests. An oriented graph is a directed graph having no symmetric pair of directed edges. A forest is an acyclic graph, i.e., it has no cycles. A forest can also be described as a disjoint union of trees, which are graphs in which any two vertices are connected by exactly one simple path. Examples ======== >>> from sympy.utilities.iterables import generate_oriented_forest >>> list(generate_oriented_forest(4)) [[0, 1, 2, 3], [0, 1, 2, 2], [0, 1, 2, 1], [0, 1, 2, 0], \ [0, 1, 1, 1], [0, 1, 1, 0], [0, 1, 0, 1], [0, 1, 0, 0], [0, 0, 0, 0]] References ========== .. [1] T. Beyer and S.M. Hedetniemi: constant time generation of rooted trees, SIAM J. Computing Vol. 9, No. 4, November 1980 .. [2] https://stackoverflow.com/questions/1633833/oriented-forest-taocp-algorithm-in-python """ P = list(range(-1, n)) while True: yield P[1:] if P[n] > 0: P[n] = P[P[n]] else: for p in range(n - 1, 0, -1): if P[p] != 0: target = P[p] - 1 for q in range(p - 1, 0, -1): if P[q] == target: break offset = p - q for i in range(p, n + 1): P[i] = P[i - offset] break else: break def minlex(seq, directed=True, key=None): """ Return the rotation of the sequence in which the lexically smallest elements appear first, e.g. `cba ->acb`. The sequence returned is a tuple, unless the input sequence is a string in which case a string is returned. If ``directed`` is False then the smaller of the sequence and the reversed sequence is returned, e.g. `cba -> abc`. If ``key`` is not None then it is used to extract a comparison key from each element in iterable. Examples ======== >>> from sympy.combinatorics.polyhedron import minlex >>> minlex((1, 2, 0)) (0, 1, 2) >>> minlex((1, 0, 2)) (0, 2, 1) >>> minlex((1, 0, 2), directed=False) (0, 1, 2) >>> minlex('11010011000', directed=True) '00011010011' >>> minlex('11010011000', directed=False) '00011001011' >>> minlex(('bb', 'aaa', 'c', 'a')) ('a', 'bb', 'aaa', 'c') >>> minlex(('bb', 'aaa', 'c', 'a'), key=len) ('c', 'a', 'bb', 'aaa') """ if key is None: key = sympy.Id best = rotate_left(seq, least_rotation(seq, key=key)) if not directed: rseq = seq[::-1] rbest = rotate_left(rseq, least_rotation(rseq, key=key)) best = min(best, rbest, key=key) # Convert to tuple, unless we started with a string. return tuple(best) if not isinstance(seq, str) else best def runs(seq, op=gt): """Group the sequence into lists in which successive elements all compare the same with the comparison operator, ``op``: op(seq[i + 1], seq[i]) is True from all elements in a run. Examples ======== >>> from sympy.utilities.iterables import runs >>> from operator import ge >>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2]) [[0, 1, 2], [2], [1, 4], [3], [2], [2]] >>> runs([0, 1, 2, 2, 1, 4, 3, 2, 2], op=ge) [[0, 1, 2, 2], [1, 4], [3], [2, 2]] """ cycles = [] seq = iter(seq) try: run = [next(seq)] except StopIteration: return [] while True: try: ei = next(seq) except StopIteration: break if op(ei, run[-1]): run.append(ei) continue else: cycles.append(run) run = [ei] if run: cycles.append(run) return cycles def kbins(l, k, ordered=None): """ Return sequence ``l`` partitioned into ``k`` bins. Examples ======== >>> from __future__ import print_function The default is to give the items in the same order, but grouped into k partitions without any reordering: >>> from sympy.utilities.iterables import kbins >>> for p in kbins(list(range(5)), 2): ... print(p) ... [[0], [1, 2, 3, 4]] [[0, 1], [2, 3, 4]] [[0, 1, 2], [3, 4]] [[0, 1, 2, 3], [4]] The ``ordered`` flag is either None (to give the simple partition of the elements) or is a 2 digit integer indicating whether the order of the bins and the order of the items in the bins matters. Given:: A = [[0], [1, 2]] B = [[1, 2], [0]] C = [[2, 1], [0]] D = [[0], [2, 1]] the following values for ``ordered`` have the shown meanings:: 00 means A == B == C == D 01 means A == B 10 means A == D 11 means A == A >>> for ordered_flag in [None, 0, 1, 10, 11]: ... print('ordered = %s' % ordered_flag) ... for p in kbins(list(range(3)), 2, ordered=ordered_flag): ... print(' %s' % p) ... ordered = None [[0], [1, 2]] [[0, 1], [2]] ordered = 0 [[0, 1], [2]] [[0, 2], [1]] [[0], [1, 2]] ordered = 1 [[0], [1, 2]] [[0], [2, 1]] [[1], [0, 2]] [[1], [2, 0]] [[2], [0, 1]] [[2], [1, 0]] ordered = 10 [[0, 1], [2]] [[2], [0, 1]] [[0, 2], [1]] [[1], [0, 2]] [[0], [1, 2]] [[1, 2], [0]] ordered = 11 [[0], [1, 2]] [[0, 1], [2]] [[0], [2, 1]] [[0, 2], [1]] [[1], [0, 2]] [[1, 0], [2]] [[1], [2, 0]] [[1, 2], [0]] [[2], [0, 1]] [[2, 0], [1]] [[2], [1, 0]] [[2, 1], [0]] See Also ======== partitions, multiset_partitions """ def partition(lista, bins): # EnricoGiampieri's partition generator from # https://stackoverflow.com/questions/13131491/ # partition-n-items-into-k-bins-in-python-lazily if len(lista) == 1 or bins == 1: yield [lista] elif len(lista) > 1 and bins > 1: for i in range(1, len(lista)): for part in partition(lista[i:], bins - 1): if len([lista[:i]] + part) == bins: yield [lista[:i]] + part if ordered is None: yield from partition(l, k) elif ordered == 11: for pl in multiset_permutations(l): pl = list(pl) yield from partition(pl, k) elif ordered == 00: yield from multiset_partitions(l, k) elif ordered == 10: for p in multiset_partitions(l, k): for perm in permutations(p): yield list(perm) elif ordered == 1: for kgot, p in partitions(len(l), k, size=True): if kgot != k: continue for li in multiset_permutations(l): rv = [] i = j = 0 li = list(li) for size, multiplicity in sorted(p.items()): for m in range(multiplicity): j = i + size rv.append(li[i: j]) i = j yield rv else: raise ValueError( 'ordered must be one of 00, 01, 10 or 11, not %s' % ordered) def permute_signs(t): """Return iterator in which the signs of non-zero elements of t are permuted. Examples ======== >>> from sympy.utilities.iterables import permute_signs >>> list(permute_signs((0, 1, 2))) [(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2)] """ for signs in cartes(*[(1, -1)]*(len(t) - t.count(0))): signs = list(signs) yield type(t)([i*signs.pop() if i else i for i in t]) def signed_permutations(t): """Return iterator in which the signs of non-zero elements of t and the order of the elements are permuted. Examples ======== >>> from sympy.utilities.iterables import signed_permutations >>> list(signed_permutations((0, 1, 2))) [(0, 1, 2), (0, -1, 2), (0, 1, -2), (0, -1, -2), (0, 2, 1), (0, -2, 1), (0, 2, -1), (0, -2, -1), (1, 0, 2), (-1, 0, 2), (1, 0, -2), (-1, 0, -2), (1, 2, 0), (-1, 2, 0), (1, -2, 0), (-1, -2, 0), (2, 0, 1), (-2, 0, 1), (2, 0, -1), (-2, 0, -1), (2, 1, 0), (-2, 1, 0), (2, -1, 0), (-2, -1, 0)] """ return (type(t)(i) for j in permutations(t) for i in permute_signs(j)) def rotations(s, dir=1): """Return a generator giving the items in s as list where each subsequent list has the items rotated to the left (default) or right (dir=-1) relative to the previous list. Examples ======== >>> from sympy.utilities.iterables import rotations >>> list(rotations([1,2,3])) [[1, 2, 3], [2, 3, 1], [3, 1, 2]] >>> list(rotations([1,2,3], -1)) [[1, 2, 3], [3, 1, 2], [2, 3, 1]] """ seq = list(s) for i in range(len(seq)): yield seq seq = rotate_left(seq, dir) def roundrobin(*iterables): """roundrobin recipe taken from itertools documentation: https://docs.python.org/2/library/itertools.html#recipes roundrobin('ABC', 'D', 'EF') --> A D E B F C Recipe credited to George Sakkis """ import itertools nexts = itertools.cycle(iter(it).__next__ for it in iterables) pending = len(iterables) while pending: try: for next in nexts: yield next() except StopIteration: pending -= 1 nexts = itertools.cycle(itertools.islice(nexts, pending)) sympy-sympy-1.9/sympy/utilities/lambdify.py000066400000000000000000001405151412543434000212660ustar00rootroot00000000000000""" This module provides convenient functions to transform sympy expressions to lambda functions which can be used to calculate numerical values very fast. """ from typing import Any, Dict, Iterable import builtins import inspect import keyword import textwrap import linecache from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.core.compatibility import (is_sequence, iterable, NotIterable) from sympy.utilities.misc import filldedent from sympy.utilities.decorator import doctest_depends_on __doctest_requires__ = {('lambdify',): ['numpy', 'tensorflow']} # Default namespaces, letting us define translations that can't be defined # by simple variable maps, like I => 1j MATH_DEFAULT = {} # type: Dict[str, Any] MPMATH_DEFAULT = {} # type: Dict[str, Any] NUMPY_DEFAULT = {"I": 1j} # type: Dict[str, Any] SCIPY_DEFAULT = {"I": 1j} # type: Dict[str, Any] CUPY_DEFAULT = {"I": 1j} # type: Dict[str, Any] TENSORFLOW_DEFAULT = {} # type: Dict[str, Any] SYMPY_DEFAULT = {} # type: Dict[str, Any] NUMEXPR_DEFAULT = {} # type: Dict[str, Any] # These are the namespaces the lambda functions will use. # These are separate from the names above because they are modified # throughout this file, whereas the defaults should remain unmodified. MATH = MATH_DEFAULT.copy() MPMATH = MPMATH_DEFAULT.copy() NUMPY = NUMPY_DEFAULT.copy() SCIPY = SCIPY_DEFAULT.copy() CUPY = CUPY_DEFAULT.copy() TENSORFLOW = TENSORFLOW_DEFAULT.copy() SYMPY = SYMPY_DEFAULT.copy() NUMEXPR = NUMEXPR_DEFAULT.copy() # Mappings between sympy and other modules function names. MATH_TRANSLATIONS = { "ceiling": "ceil", "E": "e", "ln": "log", } # NOTE: This dictionary is reused in Function._eval_evalf to allow subclasses # of Function to automatically evalf. MPMATH_TRANSLATIONS = { "Abs": "fabs", "elliptic_k": "ellipk", "elliptic_f": "ellipf", "elliptic_e": "ellipe", "elliptic_pi": "ellippi", "ceiling": "ceil", "chebyshevt": "chebyt", "chebyshevu": "chebyu", "E": "e", "I": "j", "ln": "log", #"lowergamma":"lower_gamma", "oo": "inf", #"uppergamma":"upper_gamma", "LambertW": "lambertw", "MutableDenseMatrix": "matrix", "ImmutableDenseMatrix": "matrix", "conjugate": "conj", "dirichlet_eta": "altzeta", "Ei": "ei", "Shi": "shi", "Chi": "chi", "Si": "si", "Ci": "ci", "RisingFactorial": "rf", "FallingFactorial": "ff", "betainc_regularized": "betainc", } NUMPY_TRANSLATIONS = { "Heaviside": "heaviside", } # type: Dict[str, str] SCIPY_TRANSLATIONS = {} # type: Dict[str, str] CUPY_TRANSLATIONS = {} # type: Dict[str, str] TENSORFLOW_TRANSLATIONS = {} # type: Dict[str, str] NUMEXPR_TRANSLATIONS = {} # type: Dict[str, str] # Available modules: MODULES = { "math": (MATH, MATH_DEFAULT, MATH_TRANSLATIONS, ("from math import *",)), "mpmath": (MPMATH, MPMATH_DEFAULT, MPMATH_TRANSLATIONS, ("from mpmath import *",)), "numpy": (NUMPY, NUMPY_DEFAULT, NUMPY_TRANSLATIONS, ("import numpy; from numpy import *; from numpy.linalg import *",)), "scipy": (SCIPY, SCIPY_DEFAULT, SCIPY_TRANSLATIONS, ("import numpy; import scipy; from scipy import *; from scipy.special import *",)), "cupy": (CUPY, CUPY_DEFAULT, CUPY_TRANSLATIONS, ("import cupy",)), "tensorflow": (TENSORFLOW, TENSORFLOW_DEFAULT, TENSORFLOW_TRANSLATIONS, ("import tensorflow",)), "sympy": (SYMPY, SYMPY_DEFAULT, {}, ( "from sympy.functions import *", "from sympy.matrices import *", "from sympy import Integral, pi, oo, nan, zoo, E, I",)), "numexpr" : (NUMEXPR, NUMEXPR_DEFAULT, NUMEXPR_TRANSLATIONS, ("import_module('numexpr')", )), } def _import(module, reload=False): """ Creates a global translation dictionary for module. The argument module has to be one of the following strings: "math", "mpmath", "numpy", "sympy", "tensorflow". These dictionaries map names of python functions to their equivalent in other modules. """ # Required despite static analysis claiming it is not used from sympy.external import import_module # noqa:F401 try: namespace, namespace_default, translations, import_commands = MODULES[ module] except KeyError: raise NameError( "'%s' module can't be used for lambdification" % module) # Clear namespace or exit if namespace != namespace_default: # The namespace was already generated, don't do it again if not forced. if reload: namespace.clear() namespace.update(namespace_default) else: return for import_command in import_commands: if import_command.startswith('import_module'): module = eval(import_command) if module is not None: namespace.update(module.__dict__) continue else: try: exec(import_command, {}, namespace) continue except ImportError: pass raise ImportError( "can't import '%s' with '%s' command" % (module, import_command)) # Add translated names to namespace for sympyname, translation in translations.items(): namespace[sympyname] = namespace[translation] # For computing the modulus of a sympy expression we use the builtin abs # function, instead of the previously used fabs function for all # translation modules. This is because the fabs function in the math # module does not accept complex valued arguments. (see issue 9474). The # only exception, where we don't use the builtin abs function is the # mpmath translation module, because mpmath.fabs returns mpf objects in # contrast to abs(). if 'Abs' not in namespace: namespace['Abs'] = abs # Used for dynamically generated filenames that are inserted into the # linecache. _lambdify_generated_counter = 1 @doctest_depends_on(modules=('numpy', 'scipy', 'tensorflow',), python_version=(3,)) def lambdify(args: Iterable, expr, modules=None, printer=None, use_imps=True, dummify=False, cse=False): """Convert a SymPy expression into a function that allows for fast numeric evaluation. .. warning:: This function uses ``exec``, and thus shouldn't be used on unsanitized input. .. versionchanged:: 1.7.0 Passing a set for the *args* parameter is deprecated as sets are unordered. Use an ordered iterable such as a list or tuple. Explanation =========== For example, to convert the SymPy expression ``sin(x) + cos(x)`` to an equivalent NumPy function that numerically evaluates it: >>> from sympy import sin, cos, symbols, lambdify >>> import numpy as np >>> x = symbols('x') >>> expr = sin(x) + cos(x) >>> expr sin(x) + cos(x) >>> f = lambdify(x, expr, 'numpy') >>> a = np.array([1, 2]) >>> f(a) [1.38177329 0.49315059] The primary purpose of this function is to provide a bridge from SymPy expressions to numerical libraries such as NumPy, SciPy, NumExpr, mpmath, and tensorflow. In general, SymPy functions do not work with objects from other libraries, such as NumPy arrays, and functions from numeric libraries like NumPy or mpmath do not work on SymPy expressions. ``lambdify`` bridges the two by converting a SymPy expression to an equivalent numeric function. The basic workflow with ``lambdify`` is to first create a SymPy expression representing whatever mathematical function you wish to evaluate. This should be done using only SymPy functions and expressions. Then, use ``lambdify`` to convert this to an equivalent function for numerical evaluation. For instance, above we created ``expr`` using the SymPy symbol ``x`` and SymPy functions ``sin`` and ``cos``, then converted it to an equivalent NumPy function ``f``, and called it on a NumPy array ``a``. Parameters ========== args : List[Symbol] A variable or a list of variables whose nesting represents the nesting of the arguments that will be passed to the function. Variables can be symbols, undefined functions, or matrix symbols. >>> from sympy import Eq >>> from sympy.abc import x, y, z The list of variables should match the structure of how the arguments will be passed to the function. Simply enclose the parameters as they will be passed in a list. To call a function like ``f(x)`` then ``[x]`` should be the first argument to ``lambdify``; for this case a single ``x`` can also be used: >>> f = lambdify(x, x + 1) >>> f(1) 2 >>> f = lambdify([x], x + 1) >>> f(1) 2 To call a function like ``f(x, y)`` then ``[x, y]`` will be the first argument of the ``lambdify``: >>> f = lambdify([x, y], x + y) >>> f(1, 1) 2 To call a function with a single 3-element tuple like ``f((x, y, z))`` then ``[(x, y, z)]`` will be the first argument of the ``lambdify``: >>> f = lambdify([(x, y, z)], Eq(z**2, x**2 + y**2)) >>> f((3, 4, 5)) True If two args will be passed and the first is a scalar but the second is a tuple with two arguments then the items in the list should match that structure: >>> f = lambdify([x, (y, z)], x + y + z) >>> f(1, (2, 3)) 6 expr : Expr An expression, list of expressions, or matrix to be evaluated. Lists may be nested. If the expression is a list, the output will also be a list. >>> f = lambdify(x, [x, [x + 1, x + 2]]) >>> f(1) [1, [2, 3]] If it is a matrix, an array will be returned (for the NumPy module). >>> from sympy import Matrix >>> f = lambdify(x, Matrix([x, x + 1])) >>> f(1) [[1] [2]] Note that the argument order here (variables then expression) is used to emulate the Python ``lambda`` keyword. ``lambdify(x, expr)`` works (roughly) like ``lambda x: expr`` (see :ref:`lambdify-how-it-works` below). modules : str, optional Specifies the numeric library to use. If not specified, *modules* defaults to: - ``["scipy", "numpy"]`` if SciPy is installed - ``["numpy"]`` if only NumPy is installed - ``["math", "mpmath", "sympy"]`` if neither is installed. That is, SymPy functions are replaced as far as possible by either ``scipy`` or ``numpy`` functions if available, and Python's standard library ``math``, or ``mpmath`` functions otherwise. *modules* can be one of the following types: - The strings ``"math"``, ``"mpmath"``, ``"numpy"``, ``"numexpr"``, ``"scipy"``, ``"sympy"``, or ``"tensorflow"``. This uses the corresponding printer and namespace mapping for that module. - A module (e.g., ``math``). This uses the global namespace of the module. If the module is one of the above known modules, it will also use the corresponding printer and namespace mapping (i.e., ``modules=numpy`` is equivalent to ``modules="numpy"``). - A dictionary that maps names of SymPy functions to arbitrary functions (e.g., ``{'sin': custom_sin}``). - A list that contains a mix of the arguments above, with higher priority given to entries appearing first (e.g., to use the NumPy module but override the ``sin`` function with a custom version, you can use ``[{'sin': custom_sin}, 'numpy']``). dummify : bool, optional Whether or not the variables in the provided expression that are not valid Python identifiers are substituted with dummy symbols. This allows for undefined functions like ``Function('f')(t)`` to be supplied as arguments. By default, the variables are only dummified if they are not valid Python identifiers. Set ``dummify=True`` to replace all arguments with dummy symbols (if ``args`` is not a string) - for example, to ensure that the arguments do not redefine any built-in names. cse : bool, or callable, optional Large expressions can be computed more efficiently when common subexpressions are identified and precomputed before being used multiple time. Finding the subexpressions will make creation of the 'lambdify' function slower, however. When ``True``, ``sympy.simplify.cse`` is used, otherwise (the default) the user may pass a function matching the ``cse`` signature. Examples ======== >>> from sympy.utilities.lambdify import implemented_function >>> from sympy import sqrt, sin, Matrix >>> from sympy import Function >>> from sympy.abc import w, x, y, z >>> f = lambdify(x, x**2) >>> f(2) 4 >>> f = lambdify((x, y, z), [z, y, x]) >>> f(1,2,3) [3, 2, 1] >>> f = lambdify(x, sqrt(x)) >>> f(4) 2.0 >>> f = lambdify((x, y), sin(x*y)**2) >>> f(0, 5) 0.0 >>> row = lambdify((x, y), Matrix((x, x + y)).T, modules='sympy') >>> row(1, 2) Matrix([[1, 3]]) ``lambdify`` can be used to translate SymPy expressions into mpmath functions. This may be preferable to using ``evalf`` (which uses mpmath on the backend) in some cases. >>> f = lambdify(x, sin(x), 'mpmath') >>> f(1) 0.8414709848078965 Tuple arguments are handled and the lambdified function should be called with the same type of arguments as were used to create the function: >>> f = lambdify((x, (y, z)), x + y) >>> f(1, (2, 4)) 3 The ``flatten`` function can be used to always work with flattened arguments: >>> from sympy.utilities.iterables import flatten >>> args = w, (x, (y, z)) >>> vals = 1, (2, (3, 4)) >>> f = lambdify(flatten(args), w + x + y + z) >>> f(*flatten(vals)) 10 Functions present in ``expr`` can also carry their own numerical implementations, in a callable attached to the ``_imp_`` attribute. This can be used with undefined functions using the ``implemented_function`` factory: >>> f = implemented_function(Function('f'), lambda x: x+1) >>> func = lambdify(x, f(x)) >>> func(4) 5 ``lambdify`` always prefers ``_imp_`` implementations to implementations in other namespaces, unless the ``use_imps`` input parameter is False. Usage with Tensorflow: >>> import tensorflow as tf >>> from sympy import Max, sin, lambdify >>> from sympy.abc import x >>> f = Max(x, sin(x)) >>> func = lambdify(x, f, 'tensorflow') After tensorflow v2, eager execution is enabled by default. If you want to get the compatible result across tensorflow v1 and v2 as same as this tutorial, run this line. >>> tf.compat.v1.enable_eager_execution() If you have eager execution enabled, you can get the result out immediately as you can use numpy. If you pass tensorflow objects, you may get an ``EagerTensor`` object instead of value. >>> result = func(tf.constant(1.0)) >>> print(result) tf.Tensor(1.0, shape=(), dtype=float32) >>> print(result.__class__) You can use ``.numpy()`` to get the numpy value of the tensor. >>> result.numpy() 1.0 >>> var = tf.Variable(2.0) >>> result = func(var) # also works for tf.Variable and tf.Placeholder >>> result.numpy() 2.0 And it works with any shape array. >>> tensor = tf.constant([[1.0, 2.0], [3.0, 4.0]]) >>> result = func(tensor) >>> result.numpy() [[1. 2.] [3. 4.]] Notes ===== - For functions involving large array calculations, numexpr can provide a significant speedup over numpy. Please note that the available functions for numexpr are more limited than numpy but can be expanded with ``implemented_function`` and user defined subclasses of Function. If specified, numexpr may be the only option in modules. The official list of numexpr functions can be found at: https://numexpr.readthedocs.io/en/latest/user_guide.html#supported-functions - In previous versions of SymPy, ``lambdify`` replaced ``Matrix`` with ``numpy.matrix`` by default. As of SymPy 1.0 ``numpy.array`` is the default. To get the old default behavior you must pass in ``[{'ImmutableDenseMatrix': numpy.matrix}, 'numpy']`` to the ``modules`` kwarg. >>> from sympy import lambdify, Matrix >>> from sympy.abc import x, y >>> import numpy >>> array2mat = [{'ImmutableDenseMatrix': numpy.matrix}, 'numpy'] >>> f = lambdify((x, y), Matrix([x, y]), modules=array2mat) >>> f(1, 2) [[1] [2]] - In the above examples, the generated functions can accept scalar values or numpy arrays as arguments. However, in some cases the generated function relies on the input being a numpy array: >>> from sympy import Piecewise >>> from sympy.testing.pytest import ignore_warnings >>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "numpy") >>> with ignore_warnings(RuntimeWarning): ... f(numpy.array([-1, 0, 1, 2])) [-1. 0. 1. 0.5] >>> f(0) Traceback (most recent call last): ... ZeroDivisionError: division by zero In such cases, the input should be wrapped in a numpy array: >>> with ignore_warnings(RuntimeWarning): ... float(f(numpy.array([0]))) 0.0 Or if numpy functionality is not required another module can be used: >>> f = lambdify(x, Piecewise((x, x <= 1), (1/x, x > 1)), "math") >>> f(0) 0 .. _lambdify-how-it-works: How it works ============ When using this function, it helps a great deal to have an idea of what it is doing. At its core, lambdify is nothing more than a namespace translation, on top of a special printer that makes some corner cases work properly. To understand lambdify, first we must properly understand how Python namespaces work. Say we had two files. One called ``sin_cos_sympy.py``, with .. code:: python # sin_cos_sympy.py from sympy import sin, cos def sin_cos(x): return sin(x) + cos(x) and one called ``sin_cos_numpy.py`` with .. code:: python # sin_cos_numpy.py from numpy import sin, cos def sin_cos(x): return sin(x) + cos(x) The two files define an identical function ``sin_cos``. However, in the first file, ``sin`` and ``cos`` are defined as the SymPy ``sin`` and ``cos``. In the second, they are defined as the NumPy versions. If we were to import the first file and use the ``sin_cos`` function, we would get something like >>> from sin_cos_sympy import sin_cos # doctest: +SKIP >>> sin_cos(1) # doctest: +SKIP cos(1) + sin(1) On the other hand, if we imported ``sin_cos`` from the second file, we would get >>> from sin_cos_numpy import sin_cos # doctest: +SKIP >>> sin_cos(1) # doctest: +SKIP 1.38177329068 In the first case we got a symbolic output, because it used the symbolic ``sin`` and ``cos`` functions from SymPy. In the second, we got a numeric result, because ``sin_cos`` used the numeric ``sin`` and ``cos`` functions from NumPy. But notice that the versions of ``sin`` and ``cos`` that were used was not inherent to the ``sin_cos`` function definition. Both ``sin_cos`` definitions are exactly the same. Rather, it was based on the names defined at the module where the ``sin_cos`` function was defined. The key point here is that when function in Python references a name that is not defined in the function, that name is looked up in the "global" namespace of the module where that function is defined. Now, in Python, we can emulate this behavior without actually writing a file to disk using the ``exec`` function. ``exec`` takes a string containing a block of Python code, and a dictionary that should contain the global variables of the module. It then executes the code "in" that dictionary, as if it were the module globals. The following is equivalent to the ``sin_cos`` defined in ``sin_cos_sympy.py``: >>> import sympy >>> module_dictionary = {'sin': sympy.sin, 'cos': sympy.cos} >>> exec(''' ... def sin_cos(x): ... return sin(x) + cos(x) ... ''', module_dictionary) >>> sin_cos = module_dictionary['sin_cos'] >>> sin_cos(1) cos(1) + sin(1) and similarly with ``sin_cos_numpy``: >>> import numpy >>> module_dictionary = {'sin': numpy.sin, 'cos': numpy.cos} >>> exec(''' ... def sin_cos(x): ... return sin(x) + cos(x) ... ''', module_dictionary) >>> sin_cos = module_dictionary['sin_cos'] >>> sin_cos(1) 1.38177329068 So now we can get an idea of how ``lambdify`` works. The name "lambdify" comes from the fact that we can think of something like ``lambdify(x, sin(x) + cos(x), 'numpy')`` as ``lambda x: sin(x) + cos(x)``, where ``sin`` and ``cos`` come from the ``numpy`` namespace. This is also why the symbols argument is first in ``lambdify``, as opposed to most SymPy functions where it comes after the expression: to better mimic the ``lambda`` keyword. ``lambdify`` takes the input expression (like ``sin(x) + cos(x)``) and 1. Converts it to a string 2. Creates a module globals dictionary based on the modules that are passed in (by default, it uses the NumPy module) 3. Creates the string ``"def func({vars}): return {expr}"``, where ``{vars}`` is the list of variables separated by commas, and ``{expr}`` is the string created in step 1., then ``exec``s that string with the module globals namespace and returns ``func``. In fact, functions returned by ``lambdify`` support inspection. So you can see exactly how they are defined by using ``inspect.getsource``, or ``??`` if you are using IPython or the Jupyter notebook. >>> f = lambdify(x, sin(x) + cos(x)) >>> import inspect >>> print(inspect.getsource(f)) def _lambdifygenerated(x): return sin(x) + cos(x) This shows us the source code of the function, but not the namespace it was defined in. We can inspect that by looking at the ``__globals__`` attribute of ``f``: >>> f.__globals__['sin'] >>> f.__globals__['cos'] >>> f.__globals__['sin'] is numpy.sin True This shows us that ``sin`` and ``cos`` in the namespace of ``f`` will be ``numpy.sin`` and ``numpy.cos``. Note that there are some convenience layers in each of these steps, but at the core, this is how ``lambdify`` works. Step 1 is done using the ``LambdaPrinter`` printers defined in the printing module (see :mod:`sympy.printing.lambdarepr`). This allows different SymPy expressions to define how they should be converted to a string for different modules. You can change which printer ``lambdify`` uses by passing a custom printer in to the ``printer`` argument. Step 2 is augmented by certain translations. There are default translations for each module, but you can provide your own by passing a list to the ``modules`` argument. For instance, >>> def mysin(x): ... print('taking the sin of', x) ... return numpy.sin(x) ... >>> f = lambdify(x, sin(x), [{'sin': mysin}, 'numpy']) >>> f(1) taking the sin of 1 0.8414709848078965 The globals dictionary is generated from the list by merging the dictionary ``{'sin': mysin}`` and the module dictionary for NumPy. The merging is done so that earlier items take precedence, which is why ``mysin`` is used above instead of ``numpy.sin``. If you want to modify the way ``lambdify`` works for a given function, it is usually easiest to do so by modifying the globals dictionary as such. In more complicated cases, it may be necessary to create and pass in a custom printer. Finally, step 3 is augmented with certain convenience operations, such as the addition of a docstring. Understanding how ``lambdify`` works can make it easier to avoid certain gotchas when using it. For instance, a common mistake is to create a lambdified function for one module (say, NumPy), and pass it objects from another (say, a SymPy expression). For instance, say we create >>> from sympy.abc import x >>> f = lambdify(x, x + 1, 'numpy') Now if we pass in a NumPy array, we get that array plus 1 >>> import numpy >>> a = numpy.array([1, 2]) >>> f(a) [2 3] But what happens if you make the mistake of passing in a SymPy expression instead of a NumPy array: >>> f(x + 1) x + 2 This worked, but it was only by accident. Now take a different lambdified function: >>> from sympy import sin >>> g = lambdify(x, x + sin(x), 'numpy') This works as expected on NumPy arrays: >>> g(a) [1.84147098 2.90929743] But if we try to pass in a SymPy expression, it fails >>> try: ... g(x + 1) ... # NumPy release after 1.17 raises TypeError instead of ... # AttributeError ... except (AttributeError, TypeError): ... raise AttributeError() # doctest: +IGNORE_EXCEPTION_DETAIL Traceback (most recent call last): ... AttributeError: Now, let's look at what happened. The reason this fails is that ``g`` calls ``numpy.sin`` on the input expression, and ``numpy.sin`` does not know how to operate on a SymPy object. **As a general rule, NumPy functions do not know how to operate on SymPy expressions, and SymPy functions do not know how to operate on NumPy arrays. This is why lambdify exists: to provide a bridge between SymPy and NumPy.** However, why is it that ``f`` did work? That's because ``f`` doesn't call any functions, it only adds 1. So the resulting function that is created, ``def _lambdifygenerated(x): return x + 1`` does not depend on the globals namespace it is defined in. Thus it works, but only by accident. A future version of ``lambdify`` may remove this behavior. Be aware that certain implementation details described here may change in future versions of SymPy. The API of passing in custom modules and printers will not change, but the details of how a lambda function is created may change. However, the basic idea will remain the same, and understanding it will be helpful to understanding the behavior of lambdify. **In general: you should create lambdified functions for one module (say, NumPy), and only pass it input types that are compatible with that module (say, NumPy arrays).** Remember that by default, if the ``module`` argument is not provided, ``lambdify`` creates functions using the NumPy and SciPy namespaces. """ from sympy.core.symbol import Symbol # If the user hasn't specified any modules, use what is available. if modules is None: try: _import("scipy") except ImportError: try: _import("numpy") except ImportError: # Use either numpy (if available) or python.math where possible. # XXX: This leads to different behaviour on different systems and # might be the reason for irreproducible errors. modules = ["math", "mpmath", "sympy"] else: modules = ["numpy"] else: modules = ["numpy", "scipy"] # Get the needed namespaces. namespaces = [] # First find any function implementations if use_imps: namespaces.append(_imp_namespace(expr)) # Check for dict before iterating if isinstance(modules, (dict, str)) or not hasattr(modules, '__iter__'): namespaces.append(modules) else: # consistency check if _module_present('numexpr', modules) and len(modules) > 1: raise TypeError("numexpr must be the only item in 'modules'") namespaces += list(modules) # fill namespace with first having highest priority namespace = {} # type: Dict[str, Any] for m in namespaces[::-1]: buf = _get_namespace(m) namespace.update(buf) if hasattr(expr, "atoms"): #Try if you can extract symbols from the expression. #Move on if expr.atoms in not implemented. syms = expr.atoms(Symbol) for term in syms: namespace.update({str(term): term}) if printer is None: if _module_present('mpmath', namespaces): from sympy.printing.pycode import MpmathPrinter as Printer # type: ignore elif _module_present('scipy', namespaces): from sympy.printing.numpy import SciPyPrinter as Printer # type: ignore elif _module_present('numpy', namespaces): from sympy.printing.numpy import NumPyPrinter as Printer # type: ignore elif _module_present('cupy', namespaces): from sympy.printing.numpy import CuPyPrinter as Printer # type: ignore elif _module_present('numexpr', namespaces): from sympy.printing.lambdarepr import NumExprPrinter as Printer # type: ignore elif _module_present('tensorflow', namespaces): from sympy.printing.tensorflow import TensorflowPrinter as Printer # type: ignore elif _module_present('sympy', namespaces): from sympy.printing.pycode import SymPyPrinter as Printer # type: ignore else: from sympy.printing.pycode import PythonCodePrinter as Printer # type: ignore user_functions = {} for m in namespaces[::-1]: if isinstance(m, dict): for k in m: user_functions[k] = k printer = Printer({'fully_qualified_modules': False, 'inline': True, 'allow_unknown_functions': True, 'user_functions': user_functions}) if isinstance(args, set): SymPyDeprecationWarning( feature="The list of arguments is a `set`. This leads to unpredictable results", useinstead=": Convert set into list or tuple", issue=20013, deprecated_since_version="1.6.3" ).warn() # Get the names of the args, for creating a docstring if not iterable(args): args = (args,) names = [] # Grab the callers frame, for getting the names by inspection (if needed) callers_local_vars = inspect.currentframe().f_back.f_locals.items() # type: ignore for n, var in enumerate(args): if hasattr(var, 'name'): names.append(var.name) else: # It's an iterable. Try to get name by inspection of calling frame. name_list = [var_name for var_name, var_val in callers_local_vars if var_val is var] if len(name_list) == 1: names.append(name_list[0]) else: # Cannot infer name with certainty. arg_# will have to do. names.append('arg_' + str(n)) # Create the function definition code and execute it funcname = '_lambdifygenerated' if _module_present('tensorflow', namespaces): funcprinter = _TensorflowEvaluatorPrinter(printer, dummify) # type: _EvaluatorPrinter else: funcprinter = _EvaluatorPrinter(printer, dummify) if cse == True: from sympy.simplify.cse_main import cse cses, _expr = cse(expr, list=False) elif callable(cse): cses, _expr = cse(expr) else: cses, _expr = (), expr funcstr = funcprinter.doprint(funcname, args, _expr, cses=cses) # Collect the module imports from the code printers. imp_mod_lines = [] for mod, keys in (getattr(printer, 'module_imports', None) or {}).items(): for k in keys: if k not in namespace: ln = "from %s import %s" % (mod, k) try: exec(ln, {}, namespace) except ImportError: # Tensorflow 2.0 has issues with importing a specific # function from its submodule. # https://github.com/tensorflow/tensorflow/issues/33022 ln = "%s = %s.%s" % (k, mod, k) exec(ln, {}, namespace) imp_mod_lines.append(ln) # Provide lambda expression with builtins, and compatible implementation of range namespace.update({'builtins':builtins, 'range':range}) funclocals = {} # type: Dict[str, Any] global _lambdify_generated_counter filename = '' % _lambdify_generated_counter _lambdify_generated_counter += 1 c = compile(funcstr, filename, 'exec') exec(c, namespace, funclocals) # mtime has to be None or else linecache.checkcache will remove it linecache.cache[filename] = (len(funcstr), None, funcstr.splitlines(True), filename) # type: ignore func = funclocals[funcname] # Apply the docstring sig = "func({})".format(", ".join(str(i) for i in names)) sig = textwrap.fill(sig, subsequent_indent=' '*8) expr_str = str(expr) if len(expr_str) > 78: expr_str = textwrap.wrap(expr_str, 75)[0] + '...' func.__doc__ = ( "Created with lambdify. Signature:\n\n" "{sig}\n\n" "Expression:\n\n" "{expr}\n\n" "Source code:\n\n" "{src}\n\n" "Imported modules:\n\n" "{imp_mods}" ).format(sig=sig, expr=expr_str, src=funcstr, imp_mods='\n'.join(imp_mod_lines)) return func def _module_present(modname, modlist): if modname in modlist: return True for m in modlist: if hasattr(m, '__name__') and m.__name__ == modname: return True return False def _get_namespace(m): """ This is used by _lambdify to parse its arguments. """ if isinstance(m, str): _import(m) return MODULES[m][0] elif isinstance(m, dict): return m elif hasattr(m, "__dict__"): return m.__dict__ else: raise TypeError("Argument must be either a string, dict or module but it is: %s" % m) def lambdastr(args, expr, printer=None, dummify=None): """ Returns a string that can be evaluated to a lambda function. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.utilities.lambdify import lambdastr >>> lambdastr(x, x**2) 'lambda x: (x**2)' >>> lambdastr((x,y,z), [z,y,x]) 'lambda x,y,z: ([z, y, x])' Although tuples may not appear as arguments to lambda in Python 3, lambdastr will create a lambda function that will unpack the original arguments so that nested arguments can be handled: >>> lambdastr((x, (y, z)), x + y) 'lambda _0,_1: (lambda x,y,z: (x + y))(_0,_1[0],_1[1])' """ # Transforming everything to strings. from sympy.matrices import DeferredVector from sympy import Dummy, sympify, Symbol, Function, flatten, Derivative, Basic if printer is not None: if inspect.isfunction(printer): lambdarepr = printer else: if inspect.isclass(printer): lambdarepr = lambda expr: printer().doprint(expr) else: lambdarepr = lambda expr: printer.doprint(expr) else: #XXX: This has to be done here because of circular imports from sympy.printing.lambdarepr import lambdarepr def sub_args(args, dummies_dict): if isinstance(args, str): return args elif isinstance(args, DeferredVector): return str(args) elif iterable(args): dummies = flatten([sub_args(a, dummies_dict) for a in args]) return ",".join(str(a) for a in dummies) else: # replace these with Dummy symbols if isinstance(args, (Function, Symbol, Derivative)): dummies = Dummy() dummies_dict.update({args : dummies}) return str(dummies) else: return str(args) def sub_expr(expr, dummies_dict): expr = sympify(expr) # dict/tuple are sympified to Basic if isinstance(expr, Basic): expr = expr.xreplace(dummies_dict) # list is not sympified to Basic elif isinstance(expr, list): expr = [sub_expr(a, dummies_dict) for a in expr] return expr # Transform args def isiter(l): return iterable(l, exclude=(str, DeferredVector, NotIterable)) def flat_indexes(iterable): n = 0 for el in iterable: if isiter(el): for ndeep in flat_indexes(el): yield (n,) + ndeep else: yield (n,) n += 1 if dummify is None: dummify = any(isinstance(a, Basic) and a.atoms(Function, Derivative) for a in ( args if isiter(args) else [args])) if isiter(args) and any(isiter(i) for i in args): dum_args = [str(Dummy(str(i))) for i in range(len(args))] indexed_args = ','.join([ dum_args[ind[0]] + ''.join(["[%s]" % k for k in ind[1:]]) for ind in flat_indexes(args)]) lstr = lambdastr(flatten(args), expr, printer=printer, dummify=dummify) return 'lambda %s: (%s)(%s)' % (','.join(dum_args), lstr, indexed_args) dummies_dict = {} if dummify: args = sub_args(args, dummies_dict) else: if isinstance(args, str): pass elif iterable(args, exclude=DeferredVector): args = ",".join(str(a) for a in args) # Transform expr if dummify: if isinstance(expr, str): pass else: expr = sub_expr(expr, dummies_dict) expr = lambdarepr(expr) return "lambda %s: (%s)" % (args, expr) class _EvaluatorPrinter: def __init__(self, printer=None, dummify=False): self._dummify = dummify #XXX: This has to be done here because of circular imports from sympy.printing.lambdarepr import LambdaPrinter if printer is None: printer = LambdaPrinter() if inspect.isfunction(printer): self._exprrepr = printer else: if inspect.isclass(printer): printer = printer() self._exprrepr = printer.doprint #if hasattr(printer, '_print_Symbol'): # symbolrepr = printer._print_Symbol #if hasattr(printer, '_print_Dummy'): # dummyrepr = printer._print_Dummy # Used to print the generated function arguments in a standard way self._argrepr = LambdaPrinter().doprint def doprint(self, funcname, args, expr, *, cses=()): """ Returns the function definition code as a string. """ from sympy import Dummy funcbody = [] if not iterable(args): args = [args] argstrs, expr = self._preprocess(args, expr) # Generate argument unpacking and final argument list funcargs = [] unpackings = [] for argstr in argstrs: if iterable(argstr): funcargs.append(self._argrepr(Dummy())) unpackings.extend(self._print_unpacking(argstr, funcargs[-1])) else: funcargs.append(argstr) funcsig = 'def {}({}):'.format(funcname, ', '.join(funcargs)) # Wrap input arguments before unpacking funcbody.extend(self._print_funcargwrapping(funcargs)) funcbody.extend(unpackings) funcbody.extend(['{} = {}'.format(s, self._exprrepr(e)) for s, e in cses]) str_expr = self._exprrepr(expr) if '\n' in str_expr: str_expr = '({})'.format(str_expr) funcbody.append('return {}'.format(str_expr)) funclines = [funcsig] funclines.extend(' ' + line for line in funcbody) return '\n'.join(funclines) + '\n' @classmethod def _is_safe_ident(cls, ident): return isinstance(ident, str) and ident.isidentifier() \ and not keyword.iskeyword(ident) def _preprocess(self, args, expr): """Preprocess args, expr to replace arguments that do not map to valid Python identifiers. Returns string form of args, and updated expr. """ from sympy import Dummy, Function, flatten, Derivative, ordered, Basic from sympy.matrices import DeferredVector from sympy.core.symbol import uniquely_named_symbol from sympy.core.expr import Expr # Args of type Dummy can cause name collisions with args # of type Symbol. Force dummify of everything in this # situation. dummify = self._dummify or any( isinstance(arg, Dummy) for arg in flatten(args)) argstrs = [None]*len(args) for arg, i in reversed(list(ordered(zip(args, range(len(args)))))): if iterable(arg): s, expr = self._preprocess(arg, expr) elif isinstance(arg, DeferredVector): s = str(arg) elif isinstance(arg, Basic) and arg.is_symbol: s = self._argrepr(arg) if dummify or not self._is_safe_ident(s): dummy = Dummy() if isinstance(expr, Expr): dummy = uniquely_named_symbol( dummy.name, expr, modify=lambda s: '_' + s) s = self._argrepr(dummy) expr = self._subexpr(expr, {arg: dummy}) elif dummify or isinstance(arg, (Function, Derivative)): dummy = Dummy() s = self._argrepr(dummy) expr = self._subexpr(expr, {arg: dummy}) else: s = str(arg) argstrs[i] = s return argstrs, expr def _subexpr(self, expr, dummies_dict): from sympy.matrices import DeferredVector from sympy import sympify expr = sympify(expr) xreplace = getattr(expr, 'xreplace', None) if xreplace is not None: expr = xreplace(dummies_dict) else: if isinstance(expr, DeferredVector): pass elif isinstance(expr, dict): k = [self._subexpr(sympify(a), dummies_dict) for a in expr.keys()] v = [self._subexpr(sympify(a), dummies_dict) for a in expr.values()] expr = dict(zip(k, v)) elif isinstance(expr, tuple): expr = tuple(self._subexpr(sympify(a), dummies_dict) for a in expr) elif isinstance(expr, list): expr = [self._subexpr(sympify(a), dummies_dict) for a in expr] return expr def _print_funcargwrapping(self, args): """Generate argument wrapping code. args is the argument list of the generated function (strings). Return value is a list of lines of code that will be inserted at the beginning of the function definition. """ return [] def _print_unpacking(self, unpackto, arg): """Generate argument unpacking code. arg is the function argument to be unpacked (a string), and unpackto is a list or nested lists of the variable names (strings) to unpack to. """ def unpack_lhs(lvalues): return '[{}]'.format(', '.join( unpack_lhs(val) if iterable(val) else val for val in lvalues)) return ['{} = {}'.format(unpack_lhs(unpackto), arg)] class _TensorflowEvaluatorPrinter(_EvaluatorPrinter): def _print_unpacking(self, lvalues, rvalue): """Generate argument unpacking code. This method is used when the input value is not interable, but can be indexed (see issue #14655). """ from sympy import flatten def flat_indexes(elems): n = 0 for el in elems: if iterable(el): for ndeep in flat_indexes(el): yield (n,) + ndeep else: yield (n,) n += 1 indexed = ', '.join('{}[{}]'.format(rvalue, ']['.join(map(str, ind))) for ind in flat_indexes(lvalues)) return ['[{}] = [{}]'.format(', '.join(flatten(lvalues)), indexed)] def _imp_namespace(expr, namespace=None): """ Return namespace dict with function implementations We need to search for functions in anything that can be thrown at us - that is - anything that could be passed as ``expr``. Examples include sympy expressions, as well as tuples, lists and dicts that may contain sympy expressions. Parameters ---------- expr : object Something passed to lambdify, that will generate valid code from ``str(expr)``. namespace : None or mapping Namespace to fill. None results in new empty dict Returns ------- namespace : dict dict with keys of implemented function names within ``expr`` and corresponding values being the numerical implementation of function Examples ======== >>> from sympy.abc import x >>> from sympy.utilities.lambdify import implemented_function, _imp_namespace >>> from sympy import Function >>> f = implemented_function(Function('f'), lambda x: x+1) >>> g = implemented_function(Function('g'), lambda x: x*10) >>> namespace = _imp_namespace(f(g(x))) >>> sorted(namespace.keys()) ['f', 'g'] """ # Delayed import to avoid circular imports from sympy.core.function import FunctionClass if namespace is None: namespace = {} # tuples, lists, dicts are valid expressions if is_sequence(expr): for arg in expr: _imp_namespace(arg, namespace) return namespace elif isinstance(expr, dict): for key, val in expr.items(): # functions can be in dictionary keys _imp_namespace(key, namespace) _imp_namespace(val, namespace) return namespace # sympy expressions may be Functions themselves func = getattr(expr, 'func', None) if isinstance(func, FunctionClass): imp = getattr(func, '_imp_', None) if imp is not None: name = expr.func.__name__ if name in namespace and namespace[name] != imp: raise ValueError('We found more than one ' 'implementation with name ' '"%s"' % name) namespace[name] = imp # and / or they may take Functions as arguments if hasattr(expr, 'args'): for arg in expr.args: _imp_namespace(arg, namespace) return namespace def implemented_function(symfunc, implementation): """ Add numerical ``implementation`` to function ``symfunc``. ``symfunc`` can be an ``UndefinedFunction`` instance, or a name string. In the latter case we create an ``UndefinedFunction`` instance with that name. Be aware that this is a quick workaround, not a general method to create special symbolic functions. If you want to create a symbolic function to be used by all the machinery of SymPy you should subclass the ``Function`` class. Parameters ---------- symfunc : ``str`` or ``UndefinedFunction`` instance If ``str``, then create new ``UndefinedFunction`` with this as name. If ``symfunc`` is an Undefined function, create a new function with the same name and the implemented function attached. implementation : callable numerical implementation to be called by ``evalf()`` or ``lambdify`` Returns ------- afunc : sympy.FunctionClass instance function with attached implementation Examples ======== >>> from sympy.abc import x >>> from sympy.utilities.lambdify import lambdify, implemented_function >>> f = implemented_function('f', lambda x: x+1) >>> lam_f = lambdify(x, f(x)) >>> lam_f(4) 5 """ # Delayed import to avoid circular imports from sympy.core.function import UndefinedFunction # if name, create function to hold implementation kwargs = {} if isinstance(symfunc, UndefinedFunction): kwargs = symfunc._kwargs symfunc = symfunc.__name__ if isinstance(symfunc, str): # Keyword arguments to UndefinedFunction are added as attributes to # the created class. symfunc = UndefinedFunction( symfunc, _imp_=staticmethod(implementation), **kwargs) elif not isinstance(symfunc, UndefinedFunction): raise ValueError(filldedent(''' symfunc should be either a string or an UndefinedFunction instance.''')) return symfunc sympy-sympy-1.9/sympy/utilities/magic.py000066400000000000000000000006201412543434000205470ustar00rootroot00000000000000"""Functions that involve magic. """ def pollute(names, objects): """Pollute the global namespace with symbols -> objects mapping. """ from inspect import currentframe frame = currentframe().f_back.f_back try: for name, obj in zip(names, objects): frame.f_globals[name] = obj finally: del frame # break cyclic dependencies as stated in inspect docs sympy-sympy-1.9/sympy/utilities/matchpy_connector.py000066400000000000000000000222461412543434000232160ustar00rootroot00000000000000""" The objects in this module allow the usage of the MatchPy pattern matching library on SymPy expressions. """ import re from typing import List, Callable from sympy.core.sympify import _sympify from sympy.external import import_module from sympy.functions import (log, sin, cos, tan, cot, csc, sec, erf, gamma, uppergamma) from sympy.functions.elementary.hyperbolic import acosh, asinh, atanh, acoth, acsch, asech, cosh, sinh, tanh, coth, sech, csch from sympy.functions.elementary.trigonometric import atan, acsc, asin, acot, acos, asec from sympy.functions.special.error_functions import fresnelc, fresnels, erfc, erfi, Ei from sympy import (Basic, Mul, Add, Pow, Integral, exp, Symbol, Expr, srepr, Equality, Unequality) from sympy.utilities.decorator import doctest_depends_on matchpy = import_module("matchpy") if matchpy: from matchpy import Operation, CommutativeOperation, AssociativeOperation, OneIdentityOperation from matchpy.expressions.functions import op_iter, create_operation_expression, op_len Operation.register(Integral) Operation.register(Pow) OneIdentityOperation.register(Pow) Operation.register(Add) OneIdentityOperation.register(Add) CommutativeOperation.register(Add) AssociativeOperation.register(Add) Operation.register(Mul) OneIdentityOperation.register(Mul) CommutativeOperation.register(Mul) AssociativeOperation.register(Mul) Operation.register(Equality) CommutativeOperation.register(Equality) Operation.register(Unequality) CommutativeOperation.register(Unequality) Operation.register(exp) Operation.register(log) Operation.register(gamma) Operation.register(uppergamma) Operation.register(fresnels) Operation.register(fresnelc) Operation.register(erf) Operation.register(Ei) Operation.register(erfc) Operation.register(erfi) Operation.register(sin) Operation.register(cos) Operation.register(tan) Operation.register(cot) Operation.register(csc) Operation.register(sec) Operation.register(sinh) Operation.register(cosh) Operation.register(tanh) Operation.register(coth) Operation.register(csch) Operation.register(sech) Operation.register(asin) Operation.register(acos) Operation.register(atan) Operation.register(acot) Operation.register(acsc) Operation.register(asec) Operation.register(asinh) Operation.register(acosh) Operation.register(atanh) Operation.register(acoth) Operation.register(acsch) Operation.register(asech) @op_iter.register(Integral) # type: ignore def _(operation): return iter((operation._args[0],) + operation._args[1]) @op_iter.register(Basic) # type: ignore def _(operation): return iter(operation._args) @op_len.register(Integral) # type: ignore def _(operation): return 1 + len(operation._args[1]) @op_len.register(Basic) # type: ignore def _(operation): return len(operation._args) @create_operation_expression.register(Basic) def sympy_op_factory(old_operation, new_operands, variable_name=True): return type(old_operation)(*new_operands) if matchpy: from matchpy import Wildcard else: class Wildcard: def __init__(self, min_length, fixed_size, variable_name, optional): pass @doctest_depends_on(modules=('matchpy',)) class _WildAbstract(Wildcard, Symbol): min_length = None # abstract field required in subclasses fixed_size = None # abstract field required in subclasses def __init__(self, variable_name=None, optional=None, **assumptions): min_length = self.min_length fixed_size = self.fixed_size if optional is not None: optional = _sympify(optional) Wildcard.__init__(self, min_length, fixed_size, str(variable_name), optional) def __new__(cls, variable_name=None, optional=None, **assumptions): cls._sanitize(assumptions, cls) return _WildAbstract.__xnew__(cls, variable_name, optional, **assumptions) def __getnewargs__(self): return self.min_count, self.fixed_size, self.variable_name, self.optional @staticmethod def __xnew__(cls, variable_name=None, optional=None, **assumptions): obj = Symbol.__xnew__(cls, variable_name, **assumptions) return obj def _hashable_content(self): if self.optional: return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name, self.optional) else: return super()._hashable_content() + (self.min_count, self.fixed_size, self.variable_name) def __copy__(self) -> '_WildAbstract': return type(self)(variable_name=self.variable_name, optional=self.optional) def __repr__(self): return str(self) def __str__(self): return self.name @doctest_depends_on(modules=('matchpy',)) class WildDot(_WildAbstract): min_length = 1 fixed_size = True @doctest_depends_on(modules=('matchpy',)) class WildPlus(_WildAbstract): min_length = 1 fixed_size = False @doctest_depends_on(modules=('matchpy',)) class WildStar(_WildAbstract): min_length = 0 fixed_size = False def _get_srepr(expr): s = srepr(expr) s = re.sub(r"WildDot\('(\w+)'\)", r"\1", s) s = re.sub(r"WildPlus\('(\w+)'\)", r"*\1", s) s = re.sub(r"WildStar\('(\w+)'\)", r"*\1", s) return s @doctest_depends_on(modules=('matchpy',)) class Replacer: """ Replacer object to perform multiple pattern matching and subexpression replacements in SymPy expressions. Examples ======== Example to construct a simple first degree equation solver: >>> from sympy.utilities.matchpy_connector import WildDot, Replacer >>> from sympy import Equality, Symbol >>> x = Symbol("x") >>> a_ = WildDot("a_", optional=1) >>> b_ = WildDot("b_", optional=0) The lines above have defined two wildcards, ``a_`` and ``b_``, the coefficients of the equation `a x + b = 0`. The optional values specified indicate which expression to return in case no match is found, they are necessary in equations like `a x = 0` and `x + b = 0`. Create two constraints to make sure that ``a_`` and ``b_`` will not match any expression containing ``x``: >>> from matchpy import CustomConstraint >>> free_x_a = CustomConstraint(lambda a_: not a_.has(x)) >>> free_x_b = CustomConstraint(lambda b_: not b_.has(x)) Now create the rule replacer with the constraints: >>> replacer = Replacer(common_constraints=[free_x_a, free_x_b]) Add the matching rule: >>> replacer.add(Equality(a_*x + b_, 0), -b_/a_) Let's try it: >>> replacer.replace(Equality(3*x + 4, 0)) -4/3 Notice that it won't match equations expressed with other patterns: >>> eq = Equality(3*x, 4) >>> replacer.replace(eq) Eq(3*x, 4) In order to extend the matching patterns, define another one (we also need to clear the cache, because the previous result has already been memorized and the pattern matcher won't iterate again if given the same expression) >>> replacer.add(Equality(a_*x, b_), b_/a_) >>> replacer._replacer.matcher.clear() >>> replacer.replace(eq) 4/3 """ def __init__(self, common_constraints: list = []): self._replacer = matchpy.ManyToOneReplacer() self._common_constraint = common_constraints def _get_lambda(self, lambda_str: str) -> Callable[..., Expr]: exec("from sympy import *") return eval(lambda_str, locals()) def _get_custom_constraint(self, constraint_expr: Expr, condition_template: str) -> Callable[..., Expr]: wilds = list(map(lambda x: x.name, constraint_expr.atoms(_WildAbstract))) lambdaargs = ', '.join(wilds) fullexpr = _get_srepr(constraint_expr) condition = condition_template.format(fullexpr) return matchpy.CustomConstraint( self._get_lambda(f"lambda {lambdaargs}: ({condition})")) def _get_custom_constraint_nonfalse(self, constraint_expr: Expr) -> Callable[..., Expr]: return self._get_custom_constraint(constraint_expr, "({}) != False") def _get_custom_constraint_true(self, constraint_expr: Expr) -> Callable[..., Expr]: return self._get_custom_constraint(constraint_expr, "({}) == True") def add(self, expr: Expr, result: Expr, conditions_true: List[Expr] = [], conditions_nonfalse: List[Expr] = []) -> None: expr = _sympify(expr) result = _sympify(result) lambda_str = f"lambda {', '.join(map(lambda x: x.name, expr.atoms(_WildAbstract)))}: {_get_srepr(result)}" lambda_expr = self._get_lambda(lambda_str) constraints = self._common_constraint[:] constraint_conditions_true = [ self._get_custom_constraint_true(cond) for cond in conditions_true] constraint_conditions_nonfalse = [ self._get_custom_constraint_nonfalse(cond) for cond in conditions_nonfalse] constraints.extend(constraint_conditions_true) constraints.extend(constraint_conditions_nonfalse) self._replacer.add( matchpy.ReplacementRule(matchpy.Pattern(expr, *constraints), lambda_expr)) def replace(self, expr: Expr) -> Expr: return self._replacer.replace(expr) sympy-sympy-1.9/sympy/utilities/mathml/000077500000000000000000000000001412543434000204015ustar00rootroot00000000000000sympy-sympy-1.9/sympy/utilities/mathml/__init__.py000066400000000000000000000040211412543434000225070ustar00rootroot00000000000000"""Module with some functions for MathML, like transforming MathML content in MathML presentation. To use this module, you will need lxml. """ from sympy.utilities.pkgdata import get_resource from sympy.utilities.decorator import doctest_depends_on __doctest_requires__ = {('apply_xsl', 'c2p'): ['lxml']} def add_mathml_headers(s): return """""" + s + "" @doctest_depends_on(modules=('lxml',)) def apply_xsl(mml, xsl): """Apply a xsl to a MathML string @param mml: a string with MathML code @param xsl: a string representing a path to a xsl (xml stylesheet) file. This file name is relative to the PYTHONPATH >>> from sympy.utilities.mathml import apply_xsl >>> xsl = 'mathml/data/simple_mmlctop.xsl' >>> mml = ' a b ' >>> res = apply_xsl(mml,xsl) >>> ''.join(res.splitlines()) ' a + b' """ from lxml import etree s = etree.XML(get_resource(xsl).read()) transform = etree.XSLT(s) doc = etree.XML(mml) result = transform(doc) s = str(result) return s @doctest_depends_on(modules=('lxml',)) def c2p(mml, simple=False): """Transforms a document in MathML content (like the one that sympy produces) in one document in MathML presentation, more suitable for printing, and more widely accepted >>> from sympy.utilities.mathml import c2p >>> mml = ' 2 ' >>> c2p(mml,simple=True) != c2p(mml,simple=False) True """ if not mml.startswith(' e - + &#x2062; &#x2148; - + &#x2062; &#x2148; Polar &#x2062; Polar &#x2062; &#x2061; [ ] -1 &#x03BB; &#x2061; &#x2218; &#x2218; id id domain codomain image &#x2061; { if otherwise &#x230A; &#x230B; &#x2147; ! max min max min | - - - + &#x2062; gcd lcm gcd lcm &#x2061; &#x2227; &#x2061; &#x2228; &#x2061; &#x22BB; &#x2061; &#x00AC; &#x2061; &#x00AC; &#x2061; &#x2200; : , &#x2203; : , &#x00AF; &#x211C; &#x2111; &#x2061; &#x230A; &#x2308; &#x230B; &#x2309; &#x2260; &#x2248; &#x2223; &#x2198; &#x2197; &#x2192; &#x21D2; &#x2208; &#x2209; &#x2284; &#x2288; &#x2286; &#x2282; &#x2265; &#x2264; &#x2261; ln ln log log log log &#x2146; &#x2146; &#x2146; &#x2146; &#x2032; &#x2145; &#x2202; &#x2202; &#x2202; &#x2202; &#x2202; &#x2202; &#x2207; 2 &#x2061; | &#x222A; &#x2229; \ &#x00D7; &#x2211; &#x220F; = &#x2211; &#x220F; &#x2211; &#x220F; &#x222B; &#x222B; &#x222B; &#x222B; &#x222B; &#x2146; lim &#x2192; &#x03C3; &#x03C3; 2 median mode det T &#x00D7; &#x22C5; &#x2297; &#x2124; &#x211D; &#x211A; &#x2115; &#x2102; &#x2119; &#x2147; &#x2148; NaN true false &#x2205; &#x03C0; &#x213D; &#x221E; sympy-sympy-1.9/sympy/utilities/mathml/data/mmltex.xsl000066400000000000000000004141301412543434000233530ustar00rootroot00000000000000 $ $ + i / _{} e^{i } E \mathrm{} ( , ) () \left( \left[ , \right) \right] \left\{\right\} ^{(-1)} \mathrm{lambda}\: .\: \circ \mathrm{id} \mathop{\mathrm{ }} \begin{cases} \end{cases} & \text{if $ $} \\ & \text{otherwise} \left\lfloor\frac{ }{ }\right\rfloor ! \left( \frac{ }{ } \right) \ \{ , , \} - - ( - + ) ^{ } \mod ( \times ) \sqrt [ ] { } \gcd \land \lor \mathop{\mathrm{xor}} \neg \implies \ , \colon \left| \right| \overline{} \Re \Im \left\lfloor \right\rfloor \left\lceil \right\rceil = \neq > < \ge \le \equiv \approx | \int _{ } ^{ } \,d ^\prime \frac{ d^{ } }{d ^{ } d }{d } } D_{ , } \frac{\partial^{ + + } }{ \partial ^{ } } , \mathop{\mathrm{div}} \nabla^2 \{\} \left[\right] \colon , \cup \cap \in \notin \subseteq \subset \nsubseteq \not\subset \setminus | | \times ^{ } \sum \prod _{ = } ^{ } \lim_{ } \to \searrow \nearrow \rightarrow \to \ \ \mathrm{ \,} \mathrm{ } e^{} \lg \log_{ } \left\langle , \right\rangle \sigma \sigma( )^2 \left\langle ^{ }\right\rangle _{ } \left(\begin{array}{c} \\ \end{array}\right) \begin{pmatrix} \end{pmatrix} & \\ \det \begin{vmatrix} \end{vmatrix} ^T _{ , } \dot \mathbb{Z} \mathbb{R} \mathbb{Q} \mathbb{N} \mathbb{C} \mathbb{P} e i NaN \mbox{true} \mbox{false} \emptyset \pi \gamma \infty ( ) ( ) \multicolumn{ }{c}{ } & \hfill \hfill & \\ \begin{array}{ | | } \hline \\ \hline \end{array} \overline{ } \overbrace{ } \underline{ } \underbrace{ } _{ }^{ } \underset{ }{\overset{ }{ }} \overline{ } \overbrace{ } ^{ } \stackrel{ }{ } \underline{ } \underbrace{ } _{ } \underset{ }{ } { }_{ }^{ } { }^{ } { }_{ } {}_{ } {}^{ } {} _{ } ^{ } {} _{ } ^{ } \genfrac{}{}{ ex .05ex .2ex }{}{ \frac{ \hfill \hfill }{ \hfill \hfill } \sqrt[ ]{ } exception 25: \text{exception 25:} \sqrt{ } \left \ \left( , \right \ \right) \phantom{ } \overline{ \hspace{.2em}|} \sqrt{ } \overline{) } \colorbox[rgb]{ }{$ \textcolor[rgb]{ }{ } $} \mathrm{ } \text{ } \phantom{\rule [- ] { 0ex }{ 0ex }} " " \colorbox[rgb]{ }{$ \textcolor[rgb]{ }{ \mathrm{ \mathbf{ \mathit{ \mathbit{ \mathbb{ { \mathcal{ \mathsc{ \mathfrak{ \mathsf{ \mathbsf{ \mathsfit{ \mathbsfit{ \mathtt{ { } } $} , , , , 0,1,1 0,0,0 0,0,1 1,0,1 .5,.5,.5 0,.5,0 0,1,0 .5,0,0 0,0,.5 .5,.5,0 .5,0,.5 1,0,0 .75,.75,.75 0,.5,.5 1,1,1 1,1,0 Exception at color template Exception at Hex2Decimal template sympy-sympy-1.9/sympy/utilities/mathml/data/simple_mmlctop.xsl000066400000000000000000003374001412543434000250750ustar00rootroot00000000000000 e - + &#x2062; &#x2148; - + &#x2062; &#x2148; Polar &#x2062; Polar &#x2062; &#x2061; [ ] -1 &#x03BB; &#x2061; &#x2218; &#x2218; id id domain codomain image &#x2061; { if otherwise &#x230A; &#x230B; e ! max min max min | - - - + &#x2062; gcd lcm gcd lcm &#x2061; &#x2227; &#x2061; &#x2228; &#x2061; &#x22BB; &#x2061; &#x00AC; &#x2061; &#x00AC; &#x2061; &#x2200; : , &#x2203; : , &#x00AF; &#x211C; &#x2111; &#x2061; &#x230A; &#x2308; &#x230B; &#x2309; &#x2260; &#x2248; &#x2223; &#x2198; &#x2197; &#x2192; &#x21D2; &#x2208; &#x2209; &#x2284; &#x2288; &#x2286; &#x2282; &#x2265; &#x2264; &#x2261; ln ln log log log log d d d d &#x2032; &#x2145; &#x2202; &#x2202; &#x2202; &#x2202; &#x2202; &#x2202; &#x2207; 2 &#x2061; | &#x222A; &#x2229; \ &#x00D7; &#x2211; &#x220F; = &#x2211; &#x220F; &#x2211; &#x220F; &#x222B; &#x222B; &#x222B; &#x222B; &#x222B; d lim &#x2192; &#x03C3; &#x03C3; 2 median mode det T &#x00D7; &#x22C5; &#x2297; &#x2124; &#x211D; &#x211A; &#x2115; &#x2102; &#x2119; e &#x2148; NaN true false &#x2205; &#x03C0; &#x213D; &#x221E; sympy-sympy-1.9/sympy/utilities/memoization.py000066400000000000000000000026411412543434000220270ustar00rootroot00000000000000from sympy.core.decorators import wraps def recurrence_memo(initial): """ Memo decorator for sequences defined by recurrence See usage examples e.g. in the specfun/combinatorial module """ cache = initial def decorator(f): @wraps(f) def g(n): L = len(cache) if n <= L - 1: return cache[n] for i in range(L, n + 1): cache.append(f(i, cache)) return cache[-1] return g return decorator def assoc_recurrence_memo(base_seq): """ Memo decorator for associated sequences defined by recurrence starting from base base_seq(n) -- callable to get base sequence elements XXX works only for Pn0 = base_seq(0) cases XXX works only for m <= n cases """ cache = [] def decorator(f): @wraps(f) def g(n, m): L = len(cache) if n < L: return cache[n][m] for i in range(L, n + 1): # get base sequence F_i0 = base_seq(i) F_i_cache = [F_i0] cache.append(F_i_cache) # XXX only works for m <= n cases # generate assoc sequence for j in range(1, i + 1): F_ij = f(i, j, cache) F_i_cache.append(F_ij) return cache[n][m] return g return decorator sympy-sympy-1.9/sympy/utilities/misc.py000066400000000000000000000323061412543434000204300ustar00rootroot00000000000000"""Miscellaneous stuff that doesn't really fit anywhere else.""" from typing import List import sys import os import re as _re import struct from textwrap import fill, dedent from sympy.core.compatibility import as_int from sympy.core.decorators import deprecated class Undecidable(ValueError): # an error to be raised when a decision cannot be made definitively # where a definitive answer is needed pass def filldedent(s, w=70): """ Strips leading and trailing empty lines from a copy of `s`, then dedents, fills and returns it. Empty line stripping serves to deal with docstrings like this one that start with a newline after the initial triple quote, inserting an empty line at the beginning of the string. See Also ======== strlines, rawlines """ return '\n' + fill(dedent(str(s)).strip('\n'), width=w) def strlines(s, c=64, short=False): """Return a cut-and-pastable string that, when printed, is equivalent to the input. The lines will be surrounded by parentheses and no line will be longer than c (default 64) characters. If the line contains newlines characters, the `rawlines` result will be returned. If ``short`` is True (default is False) then if there is one line it will be returned without bounding parentheses. Examples ======== >>> from sympy.utilities.misc import strlines >>> q = 'this is a long string that should be broken into shorter lines' >>> print(strlines(q, 40)) ( 'this is a long string that should be b' 'roken into shorter lines' ) >>> q == ( ... 'this is a long string that should be b' ... 'roken into shorter lines' ... ) True See Also ======== filldedent, rawlines """ if type(s) is not str: raise ValueError('expecting string input') if '\n' in s: return rawlines(s) q = '"' if repr(s).startswith('"') else "'" q = (q,)*2 if '\\' in s: # use r-string m = '(\nr%s%%s%s\n)' % q j = '%s\nr%s' % q c -= 3 else: m = '(\n%s%%s%s\n)' % q j = '%s\n%s' % q c -= 2 out = [] while s: out.append(s[:c]) s=s[c:] if short and len(out) == 1: return (m % out[0]).splitlines()[1] # strip bounding (\n...\n) return m % j.join(out) def rawlines(s): """Return a cut-and-pastable string that, when printed, is equivalent to the input. Use this when there is more than one line in the string. The string returned is formatted so it can be indented nicely within tests; in some cases it is wrapped in the dedent function which has to be imported from textwrap. Examples ======== Note: because there are characters in the examples below that need to be escaped because they are themselves within a triple quoted docstring, expressions below look more complicated than they would be if they were printed in an interpreter window. >>> from sympy.utilities.misc import rawlines >>> from sympy import TableForm >>> s = str(TableForm([[1, 10]], headings=(None, ['a', 'bee']))) >>> print(rawlines(s)) ( 'a bee\\n' '-----\\n' '1 10 ' ) >>> print(rawlines('''this ... that''')) dedent('''\\ this that''') >>> print(rawlines('''this ... that ... ''')) dedent('''\\ this that ''') >>> s = \"\"\"this ... is a triple ''' ... \"\"\" >>> print(rawlines(s)) dedent(\"\"\"\\ this is a triple ''' \"\"\") >>> print(rawlines('''this ... that ... ''')) ( 'this\\n' 'that\\n' ' ' ) See Also ======== filldedent, strlines """ lines = s.split('\n') if len(lines) == 1: return repr(lines[0]) triple = ["'''" in s, '"""' in s] if any(li.endswith(' ') for li in lines) or '\\' in s or all(triple): rv = [] # add on the newlines trailing = s.endswith('\n') last = len(lines) - 1 for i, li in enumerate(lines): if i != last or trailing: rv.append(repr(li + '\n')) else: rv.append(repr(li)) return '(\n %s\n)' % '\n '.join(rv) else: rv = '\n '.join(lines) if triple[0]: return 'dedent("""\\\n %s""")' % rv else: return "dedent('''\\\n %s''')" % rv ARCH = str(struct.calcsize('P') * 8) + "-bit" # XXX: PyPy doesn't support hash randomization HASH_RANDOMIZATION = getattr(sys.flags, 'hash_randomization', False) _debug_tmp = [] # type: List[str] _debug_iter = 0 def debug_decorator(func): """If SYMPY_DEBUG is True, it will print a nice execution tree with arguments and results of all decorated functions, else do nothing. """ from sympy import SYMPY_DEBUG if not SYMPY_DEBUG: return func def maketree(f, *args, **kw): global _debug_tmp global _debug_iter oldtmp = _debug_tmp _debug_tmp = [] _debug_iter += 1 def tree(subtrees): def indent(s, type=1): x = s.split("\n") r = "+-%s\n" % x[0] for a in x[1:]: if a == "": continue if type == 1: r += "| %s\n" % a else: r += " %s\n" % a return r if len(subtrees) == 0: return "" f = [] for a in subtrees[:-1]: f.append(indent(a)) f.append(indent(subtrees[-1], 2)) return ''.join(f) # If there is a bug and the algorithm enters an infinite loop, enable the # following lines. It will print the names and parameters of all major functions # that are called, *before* they are called #from functools import reduce #print("%s%s %s%s" % (_debug_iter, reduce(lambda x, y: x + y, \ # map(lambda x: '-', range(1, 2 + _debug_iter))), f.__name__, args)) r = f(*args, **kw) _debug_iter -= 1 s = "%s%s = %s\n" % (f.__name__, args, r) if _debug_tmp != []: s += tree(_debug_tmp) _debug_tmp = oldtmp _debug_tmp.append(s) if _debug_iter == 0: print(_debug_tmp[0]) _debug_tmp = [] return r def decorated(*args, **kwargs): return maketree(func, *args, **kwargs) return decorated def debug(*args): """ Print ``*args`` if SYMPY_DEBUG is True, else do nothing. """ from sympy import SYMPY_DEBUG if SYMPY_DEBUG: print(*args, file=sys.stderr) @deprecated( useinstead="the builtin ``shutil.which`` function", issue=19634, deprecated_since_version="1.7") def find_executable(executable, path=None): """Try to find 'executable' in the directories listed in 'path' (a string listing directories separated by 'os.pathsep'; defaults to os.environ['PATH']). Returns the complete filename or None if not found """ if path is None: path = os.environ['PATH'] paths = path.split(os.pathsep) extlist = [''] if os.name == 'os2': (base, ext) = os.path.splitext(executable) # executable files on OS/2 can have an arbitrary extension, but # .exe is automatically appended if no dot is present in the name if not ext: executable = executable + ".exe" elif sys.platform == 'win32': pathext = os.environ['PATHEXT'].lower().split(os.pathsep) (base, ext) = os.path.splitext(executable) if ext.lower() not in pathext: extlist = pathext for ext in extlist: execname = executable + ext if os.path.isfile(execname): return execname else: for p in paths: f = os.path.join(p, execname) if os.path.isfile(f): return f return None def func_name(x, short=False): """Return function name of `x` (if defined) else the `type(x)`. If short is True and there is a shorter alias for the result, return the alias. Examples ======== >>> from sympy.utilities.misc import func_name >>> from sympy import Matrix >>> from sympy.abc import x >>> func_name(Matrix.eye(3)) 'MutableDenseMatrix' >>> func_name(x < 1) 'StrictLessThan' >>> func_name(x < 1, short=True) 'Lt' """ alias = { 'GreaterThan': 'Ge', 'StrictGreaterThan': 'Gt', 'LessThan': 'Le', 'StrictLessThan': 'Lt', 'Equality': 'Eq', 'Unequality': 'Ne', } typ = type(x) if str(typ).startswith(">> from sympy.utilities.misc import _replace >>> f = _replace(dict(foo='bar', d='t')) >>> f('food') 'bart' >>> f = _replace({}) >>> f('food') 'food' """ if not reps: return lambda x: x D = lambda match: reps[match.group(0)] pattern = _re.compile("|".join( [_re.escape(k) for k, v in reps.items()]), _re.M) return lambda string: pattern.sub(D, string) def replace(string, *reps): """Return ``string`` with all keys in ``reps`` replaced with their corresponding values, longer strings first, irrespective of the order they are given. ``reps`` may be passed as tuples or a single mapping. Examples ======== >>> from sympy.utilities.misc import replace >>> replace('foo', {'oo': 'ar', 'f': 'b'}) 'bar' >>> replace("spamham sha", ("spam", "eggs"), ("sha","md5")) 'eggsham md5' There is no guarantee that a unique answer will be obtained if keys in a mapping overlap (i.e. are the same length and have some identical sequence at the beginning/end): >>> reps = [ ... ('ab', 'x'), ... ('bc', 'y')] >>> replace('abc', *reps) in ('xc', 'ay') True References ========== .. [1] https://stackoverflow.com/questions/6116978/python-replace-multiple-strings """ if len(reps) == 1: kv = reps[0] if type(kv) is dict: reps = kv else: return string.replace(*kv) else: reps = dict(reps) return _replace(reps)(string) def translate(s, a, b=None, c=None): """Return ``s`` where characters have been replaced or deleted. SYNTAX ====== translate(s, None, deletechars): all characters in ``deletechars`` are deleted translate(s, map [,deletechars]): all characters in ``deletechars`` (if provided) are deleted then the replacements defined by map are made; if the keys of map are strings then the longer ones are handled first. Multicharacter deletions should have a value of ''. translate(s, oldchars, newchars, deletechars) all characters in ``deletechars`` are deleted then each character in ``oldchars`` is replaced with the corresponding character in ``newchars`` Examples ======== >>> from sympy.utilities.misc import translate >>> abc = 'abc' >>> translate(abc, None, 'a') 'bc' >>> translate(abc, {'a': 'x'}, 'c') 'xb' >>> translate(abc, {'abc': 'x', 'a': 'y'}) 'x' >>> translate('abcd', 'ac', 'AC', 'd') 'AbC' There is no guarantee that a unique answer will be obtained if keys in a mapping overlap are the same length and have some identical sequences at the beginning/end: >>> translate(abc, {'ab': 'x', 'bc': 'y'}) in ('xc', 'ay') True """ mr = {} if a is None: if c is not None: raise ValueError('c should be None when a=None is passed, instead got %s' % c) if b is None: return s c = b a = b = '' else: if type(a) is dict: short = {} for k in list(a.keys()): if len(k) == 1 and len(a[k]) == 1: short[k] = a.pop(k) mr = a c = b if short: a, b = [''.join(i) for i in list(zip(*short.items()))] else: a = b = '' elif len(a) != len(b): raise ValueError('oldchars and newchars have different lengths') if c: val = str.maketrans('', '', c) s = s.translate(val) s = replace(s, mr) n = str.maketrans(a, b) return s.translate(n) def ordinal(num): """Return ordinal number string of num, e.g. 1 becomes 1st. """ # modified from https://codereview.stackexchange.com/questions/41298/producing-ordinal-numbers n = as_int(num) k = abs(n) % 100 if 11 <= k <= 13: suffix = 'th' elif k % 10 == 1: suffix = 'st' elif k % 10 == 2: suffix = 'nd' elif k % 10 == 3: suffix = 'rd' else: suffix = 'th' return str(n) + suffix sympy-sympy-1.9/sympy/utilities/pkgdata.py000066400000000000000000000033751412543434000211140ustar00rootroot00000000000000""" pkgdata is a simple, extensible way for a package to acquire data file resources. The getResource function is equivalent to the standard idioms, such as the following minimal implementation:: import sys, os def getResource(identifier, pkgname=__name__): pkgpath = os.path.dirname(sys.modules[pkgname].__file__) path = os.path.join(pkgpath, identifier) return open(os.path.normpath(path), mode='rb') When a __loader__ is present on the module given by __name__, it will defer getResource to its get_data implementation and return it as a file-like object (such as StringIO). """ import sys import os from io import StringIO def get_resource(identifier, pkgname=__name__): """ Acquire a readable object for a given package name and identifier. An IOError will be raised if the resource can not be found. For example:: mydata = get_resource('mypkgdata.jpg').read() Note that the package name must be fully qualified, if given, such that it would be found in sys.modules. In some cases, getResource will return a real file object. In that case, it may be useful to use its name attribute to get the path rather than use it as a file-like object. For example, you may be handing data off to a C API. """ mod = sys.modules[pkgname] fn = getattr(mod, '__file__', None) if fn is None: raise OSError("%r has no __file__!") path = os.path.join(os.path.dirname(fn), identifier) loader = getattr(mod, '__loader__', None) if loader is not None: try: data = loader.get_data(path) except (OSError, AttributeError): pass else: return StringIO(data.decode('utf-8')) return open(os.path.normpath(path), 'rb') sympy-sympy-1.9/sympy/utilities/pytest.py000066400000000000000000000004461412543434000210250ustar00rootroot00000000000000from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="Import sympy.utilities.pytest", useinstead="Import from sympy.testing.pytest", issue=18095, deprecated_since_version="1.6").warn() from sympy.testing.pytest import * # noqa:F401 sympy-sympy-1.9/sympy/utilities/quality_unicode.py000066400000000000000000000005011412543434000226630ustar00rootroot00000000000000from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="Import sympy.utilities.quality_unicode", useinstead="Import from sympy.testing.quality_unicode", issue=18095, deprecated_since_version="1.6").warn() from sympy.testing.quality_unicode import * # noqa:F401 sympy-sympy-1.9/sympy/utilities/randtest.py000066400000000000000000000004541412543434000213200ustar00rootroot00000000000000from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="Import sympy.utilities.randtest", useinstead="Import from sympy.testing.randtest", issue=18095, deprecated_since_version="1.6").warn() from sympy.testing.randtest import * # noqa:F401 sympy-sympy-1.9/sympy/utilities/runtests.py000066400000000000000000000004541412543434000213630ustar00rootroot00000000000000from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="Import sympy.utilities.runtests", useinstead="Import from sympy.testing.runtests", issue=18095, deprecated_since_version="1.6").warn() from sympy.testing.runtests import * # noqa:F401 sympy-sympy-1.9/sympy/utilities/source.py000066400000000000000000000027101412543434000207710ustar00rootroot00000000000000""" This module adds several functions for interactive source code inspection. """ from sympy.core.decorators import deprecated import inspect @deprecated(useinstead="?? in IPython/Jupyter or inspect.getsource", issue=14905, deprecated_since_version="1.3") def source(object): """ Prints the source code of a given object. """ print('In file: %s' % inspect.getsourcefile(object)) print(inspect.getsource(object)) def get_class(lookup_view): """ Convert a string version of a class name to the object. For example, get_class('sympy.core.Basic') will return class Basic located in module sympy.core """ if isinstance(lookup_view, str): mod_name, func_name = get_mod_func(lookup_view) if func_name != '': lookup_view = getattr( __import__(mod_name, {}, {}, ['*']), func_name) if not callable(lookup_view): raise AttributeError( "'%s.%s' is not a callable." % (mod_name, func_name)) return lookup_view def get_mod_func(callback): """ splits the string path to a class into a string path to the module and the name of the class. Examples ======== >>> from sympy.utilities.source import get_mod_func >>> get_mod_func('sympy.core.basic.Basic') ('sympy.core.basic', 'Basic') """ dot = callback.rfind('.') if dot == -1: return callback, '' return callback[:dot], callback[dot + 1:] sympy-sympy-1.9/sympy/utilities/tests/000077500000000000000000000000001412543434000202615ustar00rootroot00000000000000sympy-sympy-1.9/sympy/utilities/tests/__init__.py000066400000000000000000000000001412543434000223600ustar00rootroot00000000000000sympy-sympy-1.9/sympy/utilities/tests/test_autowrap.py000066400000000000000000000345371412543434000235500ustar00rootroot00000000000000# Tests that require installed backends go into # sympy/test_external/test_autowrap import os import tempfile import shutil from io import StringIO from sympy.core import symbols, Eq from sympy.utilities.autowrap import (autowrap, binary_function, CythonCodeWrapper, UfuncifyCodeWrapper, CodeWrapper) from sympy.utilities.codegen import ( CCodeGen, C99CodeGen, CodeGenArgumentListError, make_routine ) from sympy.testing.pytest import raises from sympy.testing.tmpfiles import TmpFileManager def get_string(dump_fn, routines, prefix="file", **kwargs): """Wrapper for dump_fn. dump_fn writes its results to a stream object and this wrapper returns the contents of that stream as a string. This auxiliary function is used by many tests below. The header and the empty lines are not generator to facilitate the testing of the output. """ output = StringIO() dump_fn(routines, output, prefix, **kwargs) source = output.getvalue() output.close() return source def test_cython_wrapper_scalar_function(): x, y, z = symbols('x,y,z') expr = (x + y)*z routine = make_routine("test", expr) code_gen = CythonCodeWrapper(CCodeGen()) source = get_string(code_gen.dump_pyx, [routine]) expected = ( "cdef extern from 'file.h':\n" " double test(double x, double y, double z)\n" "\n" "def test_c(double x, double y, double z):\n" "\n" " return test(x, y, z)") assert source == expected def test_cython_wrapper_outarg(): from sympy import Equality x, y, z = symbols('x,y,z') code_gen = CythonCodeWrapper(C99CodeGen()) routine = make_routine("test", Equality(z, x + y)) source = get_string(code_gen.dump_pyx, [routine]) expected = ( "cdef extern from 'file.h':\n" " void test(double x, double y, double *z)\n" "\n" "def test_c(double x, double y):\n" "\n" " cdef double z = 0\n" " test(x, y, &z)\n" " return z") assert source == expected def test_cython_wrapper_inoutarg(): from sympy import Equality x, y, z = symbols('x,y,z') code_gen = CythonCodeWrapper(C99CodeGen()) routine = make_routine("test", Equality(z, x + y + z)) source = get_string(code_gen.dump_pyx, [routine]) expected = ( "cdef extern from 'file.h':\n" " void test(double x, double y, double *z)\n" "\n" "def test_c(double x, double y, double z):\n" "\n" " test(x, y, &z)\n" " return z") assert source == expected def test_cython_wrapper_compile_flags(): from sympy import Equality x, y, z = symbols('x,y,z') routine = make_routine("test", Equality(z, x + y)) code_gen = CythonCodeWrapper(CCodeGen()) expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {} ext_mods = [Extension( 'wrapper_module_%(num)s', ['wrapper_module_%(num)s.pyx', 'wrapped_code_%(num)s.c'], include_dirs=[], library_dirs=[], libraries=[], extra_compile_args=['-std=c99'], extra_link_args=[] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ % {'num': CodeWrapper._module_counter} temp_dir = tempfile.mkdtemp() TmpFileManager.tmp_folder(temp_dir) setup_file_path = os.path.join(temp_dir, 'setup.py') code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected code_gen = CythonCodeWrapper(CCodeGen(), include_dirs=['/usr/local/include', '/opt/booger/include'], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math'], extra_link_args=['-lswamp', '-ltrident'], cythonize_options={'compiler_directives': {'boundscheck': False}} ) expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {'compiler_directives': {'boundscheck': False}} ext_mods = [Extension( 'wrapper_module_%(num)s', ['wrapper_module_%(num)s.pyx', 'wrapped_code_%(num)s.c'], include_dirs=['/usr/local/include', '/opt/booger/include'], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math', '-std=c99'], extra_link_args=['-lswamp', '-ltrident'] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ % {'num': CodeWrapper._module_counter} code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected expected = """\ try: from setuptools import setup from setuptools import Extension except ImportError: from distutils.core import setup from distutils.extension import Extension from Cython.Build import cythonize cy_opts = {'compiler_directives': {'boundscheck': False}} import numpy as np ext_mods = [Extension( 'wrapper_module_%(num)s', ['wrapper_module_%(num)s.pyx', 'wrapped_code_%(num)s.c'], include_dirs=['/usr/local/include', '/opt/booger/include', np.get_include()], library_dirs=['/user/local/lib'], libraries=['thelib', 'nilib'], extra_compile_args=['-slow-math', '-std=c99'], extra_link_args=['-lswamp', '-ltrident'] )] setup(ext_modules=cythonize(ext_mods, **cy_opts)) """ % {'num': CodeWrapper._module_counter} code_gen._need_numpy = True code_gen._prepare_files(routine, build_dir=temp_dir) with open(setup_file_path) as f: setup_text = f.read() assert setup_text == expected TmpFileManager.cleanup() def test_cython_wrapper_unique_dummyvars(): from sympy import Dummy, Equality x, y, z = Dummy('x'), Dummy('y'), Dummy('z') x_id, y_id, z_id = [str(d.dummy_index) for d in [x, y, z]] expr = Equality(z, x + y) routine = make_routine("test", expr) code_gen = CythonCodeWrapper(CCodeGen()) source = get_string(code_gen.dump_pyx, [routine]) expected_template = ( "cdef extern from 'file.h':\n" " void test(double x_{x_id}, double y_{y_id}, double *z_{z_id})\n" "\n" "def test_c(double x_{x_id}, double y_{y_id}):\n" "\n" " cdef double z_{z_id} = 0\n" " test(x_{x_id}, y_{y_id}, &z_{z_id})\n" " return z_{z_id}") expected = expected_template.format(x_id=x_id, y_id=y_id, z_id=z_id) assert source == expected def test_autowrap_dummy(): x, y, z = symbols('x y z') # Uses DummyWrapper to test that codegen works as expected f = autowrap(x + y, backend='dummy') assert f() == str(x + y) assert f.args == "x, y" assert f.returns == "nameless" f = autowrap(Eq(z, x + y), backend='dummy') assert f() == str(x + y) assert f.args == "x, y" assert f.returns == "z" f = autowrap(Eq(z, x + y + z), backend='dummy') assert f() == str(x + y + z) assert f.args == "x, y, z" assert f.returns == "z" def test_autowrap_args(): x, y, z = symbols('x y z') raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y), backend='dummy', args=[x])) f = autowrap(Eq(z, x + y), backend='dummy', args=[y, x]) assert f() == str(x + y) assert f.args == "y, x" assert f.returns == "z" raises(CodeGenArgumentListError, lambda: autowrap(Eq(z, x + y + z), backend='dummy', args=[x, y])) f = autowrap(Eq(z, x + y + z), backend='dummy', args=[y, x, z]) assert f() == str(x + y + z) assert f.args == "y, x, z" assert f.returns == "z" f = autowrap(Eq(z, x + y + z), backend='dummy', args=(y, x, z)) assert f() == str(x + y + z) assert f.args == "y, x, z" assert f.returns == "z" def test_autowrap_store_files(): x, y = symbols('x y') tmp = tempfile.mkdtemp() TmpFileManager.tmp_folder(tmp) f = autowrap(x + y, backend='dummy', tempdir=tmp) assert f() == str(x + y) assert os.access(tmp, os.F_OK) TmpFileManager.cleanup() def test_autowrap_store_files_issue_gh12939(): x, y = symbols('x y') tmp = './tmp' try: f = autowrap(x + y, backend='dummy', tempdir=tmp) assert f() == str(x + y) assert os.access(tmp, os.F_OK) finally: shutil.rmtree(tmp) def test_binary_function(): x, y = symbols('x y') f = binary_function('f', x + y, backend='dummy') assert f._imp_() == str(x + y) def test_ufuncify_source(): x, y, z = symbols('x,y,z') code_wrapper = UfuncifyCodeWrapper(C99CodeGen("ufuncify")) routine = make_routine("test", x + y + z) source = get_string(code_wrapper.dump_c, [routine]) expected = """\ #include "Python.h" #include "math.h" #include "numpy/ndarraytypes.h" #include "numpy/ufuncobject.h" #include "numpy/halffloat.h" #include "file.h" static PyMethodDef wrapper_module_%(num)sMethods[] = { {NULL, NULL, 0, NULL} }; static void test_ufunc(char **args, npy_intp *dimensions, npy_intp* steps, void* data) { npy_intp i; npy_intp n = dimensions[0]; char *in0 = args[0]; char *in1 = args[1]; char *in2 = args[2]; char *out0 = args[3]; npy_intp in0_step = steps[0]; npy_intp in1_step = steps[1]; npy_intp in2_step = steps[2]; npy_intp out0_step = steps[3]; for (i = 0; i < n; i++) { *((double *)out0) = test(*(double *)in0, *(double *)in1, *(double *)in2); in0 += in0_step; in1 += in1_step; in2 += in2_step; out0 += out0_step; } } PyUFuncGenericFunction test_funcs[1] = {&test_ufunc}; static char test_types[4] = {NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE}; static void *test_data[1] = {NULL}; #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "wrapper_module_%(num)s", NULL, -1, wrapper_module_%(num)sMethods, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_wrapper_module_%(num)s(void) { PyObject *m, *d; PyObject *ufunc0; m = PyModule_Create(&moduledef); if (!m) { return NULL; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(test_funcs, test_data, test_types, 1, 3, 1, PyUFunc_None, "wrapper_module_%(num)s", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "test", ufunc0); Py_DECREF(ufunc0); return m; } #else PyMODINIT_FUNC initwrapper_module_%(num)s(void) { PyObject *m, *d; PyObject *ufunc0; m = Py_InitModule("wrapper_module_%(num)s", wrapper_module_%(num)sMethods); if (m == NULL) { return; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(test_funcs, test_data, test_types, 1, 3, 1, PyUFunc_None, "wrapper_module_%(num)s", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "test", ufunc0); Py_DECREF(ufunc0); } #endif""" % {'num': CodeWrapper._module_counter} assert source == expected def test_ufuncify_source_multioutput(): x, y, z = symbols('x,y,z') var_symbols = (x, y, z) expr = x + y**3 + 10*z**2 code_wrapper = UfuncifyCodeWrapper(C99CodeGen("ufuncify")) routines = [make_routine("func{}".format(i), expr.diff(var_symbols[i]), var_symbols) for i in range(len(var_symbols))] source = get_string(code_wrapper.dump_c, routines, funcname='multitest') expected = """\ #include "Python.h" #include "math.h" #include "numpy/ndarraytypes.h" #include "numpy/ufuncobject.h" #include "numpy/halffloat.h" #include "file.h" static PyMethodDef wrapper_module_%(num)sMethods[] = { {NULL, NULL, 0, NULL} }; static void multitest_ufunc(char **args, npy_intp *dimensions, npy_intp* steps, void* data) { npy_intp i; npy_intp n = dimensions[0]; char *in0 = args[0]; char *in1 = args[1]; char *in2 = args[2]; char *out0 = args[3]; char *out1 = args[4]; char *out2 = args[5]; npy_intp in0_step = steps[0]; npy_intp in1_step = steps[1]; npy_intp in2_step = steps[2]; npy_intp out0_step = steps[3]; npy_intp out1_step = steps[4]; npy_intp out2_step = steps[5]; for (i = 0; i < n; i++) { *((double *)out0) = func0(*(double *)in0, *(double *)in1, *(double *)in2); *((double *)out1) = func1(*(double *)in0, *(double *)in1, *(double *)in2); *((double *)out2) = func2(*(double *)in0, *(double *)in1, *(double *)in2); in0 += in0_step; in1 += in1_step; in2 += in2_step; out0 += out0_step; out1 += out1_step; out2 += out2_step; } } PyUFuncGenericFunction multitest_funcs[1] = {&multitest_ufunc}; static char multitest_types[6] = {NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE, NPY_DOUBLE}; static void *multitest_data[1] = {NULL}; #if PY_VERSION_HEX >= 0x03000000 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "wrapper_module_%(num)s", NULL, -1, wrapper_module_%(num)sMethods, NULL, NULL, NULL, NULL }; PyMODINIT_FUNC PyInit_wrapper_module_%(num)s(void) { PyObject *m, *d; PyObject *ufunc0; m = PyModule_Create(&moduledef); if (!m) { return NULL; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(multitest_funcs, multitest_data, multitest_types, 1, 3, 3, PyUFunc_None, "wrapper_module_%(num)s", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "multitest", ufunc0); Py_DECREF(ufunc0); return m; } #else PyMODINIT_FUNC initwrapper_module_%(num)s(void) { PyObject *m, *d; PyObject *ufunc0; m = Py_InitModule("wrapper_module_%(num)s", wrapper_module_%(num)sMethods); if (m == NULL) { return; } import_array(); import_umath(); d = PyModule_GetDict(m); ufunc0 = PyUFunc_FromFuncAndData(multitest_funcs, multitest_data, multitest_types, 1, 3, 3, PyUFunc_None, "wrapper_module_%(num)s", "Created in SymPy with Ufuncify", 0); PyDict_SetItemString(d, "multitest", ufunc0); Py_DECREF(ufunc0); } #endif""" % {'num': CodeWrapper._module_counter} assert source == expected sympy-sympy-1.9/sympy/utilities/tests/test_codegen.py000066400000000000000000001532201412543434000233010ustar00rootroot00000000000000from io import StringIO from sympy.core import symbols, Eq, pi, Catalan, Lambda, Dummy from sympy import erf, Integral, Symbol from sympy import Equality from sympy.matrices import Matrix, MatrixSymbol from sympy.utilities.codegen import ( codegen, make_routine, CCodeGen, C89CodeGen, C99CodeGen, InputArgument, CodeGenError, FCodeGen, CodeGenArgumentListError, OutputArgument, InOutArgument) from sympy.testing.pytest import raises from sympy.utilities.lambdify import implemented_function #FIXME: Fails due to circular import in with core # from sympy import codegen def get_string(dump_fn, routines, prefix="file", header=False, empty=False): """Wrapper for dump_fn. dump_fn writes its results to a stream object and this wrapper returns the contents of that stream as a string. This auxiliary function is used by many tests below. The header and the empty lines are not generated to facilitate the testing of the output. """ output = StringIO() dump_fn(routines, output, prefix, header, empty) source = output.getvalue() output.close() return source def test_Routine_argument_order(): a, x, y, z = symbols('a x y z') expr = (x + y)*z raises(CodeGenArgumentListError, lambda: make_routine("test", expr, argument_sequence=[z, x])) raises(CodeGenArgumentListError, lambda: make_routine("test", Eq(a, expr), argument_sequence=[z, x, y])) r = make_routine('test', Eq(a, expr), argument_sequence=[z, x, a, y]) assert [ arg.name for arg in r.arguments ] == [z, x, a, y] assert [ type(arg) for arg in r.arguments ] == [ InputArgument, InputArgument, OutputArgument, InputArgument ] r = make_routine('test', Eq(z, expr), argument_sequence=[z, x, y]) assert [ type(arg) for arg in r.arguments ] == [ InOutArgument, InputArgument, InputArgument ] from sympy.tensor import IndexedBase, Idx A, B = map(IndexedBase, ['A', 'B']) m = symbols('m', integer=True) i = Idx('i', m) r = make_routine('test', Eq(A[i], B[i]), argument_sequence=[B, A, m]) assert [ arg.name for arg in r.arguments ] == [B.label, A.label, m] expr = Integral(x*y*z, (x, 1, 2), (y, 1, 3)) r = make_routine('test', Eq(a, expr), argument_sequence=[z, x, a, y]) assert [ arg.name for arg in r.arguments ] == [z, x, a, y] def test_empty_c_code(): code_gen = C89CodeGen() source = get_string(code_gen.dump_c, []) assert source == "#include \"file.h\"\n#include \n" def test_empty_c_code_with_comment(): code_gen = C89CodeGen() source = get_string(code_gen.dump_c, [], header=True) assert source[:82] == ( "/******************************************************************************\n *" ) # " Code generated with sympy 0.7.2-git " assert source[158:] == ( "*\n" " * *\n" " * See http://www.sympy.org/ for more information. *\n" " * *\n" " * This file is part of 'project' *\n" " ******************************************************************************/\n" "#include \"file.h\"\n" "#include \n" ) def test_empty_c_header(): code_gen = C99CodeGen() source = get_string(code_gen.dump_h, []) assert source == "#ifndef PROJECT__FILE__H\n#define PROJECT__FILE__H\n#endif\n" def test_simple_c_code(): x, y, z = symbols('x,y,z') expr = (x + y)*z routine = make_routine("test", expr) code_gen = C89CodeGen() source = get_string(code_gen.dump_c, [routine]) expected = ( "#include \"file.h\"\n" "#include \n" "double test(double x, double y, double z) {\n" " double test_result;\n" " test_result = z*(x + y);\n" " return test_result;\n" "}\n" ) assert source == expected def test_c_code_reserved_words(): x, y, z = symbols('if, typedef, while') expr = (x + y) * z routine = make_routine("test", expr) code_gen = C99CodeGen() source = get_string(code_gen.dump_c, [routine]) expected = ( "#include \"file.h\"\n" "#include \n" "double test(double if_, double typedef_, double while_) {\n" " double test_result;\n" " test_result = while_*(if_ + typedef_);\n" " return test_result;\n" "}\n" ) assert source == expected def test_numbersymbol_c_code(): routine = make_routine("test", pi**Catalan) code_gen = C89CodeGen() source = get_string(code_gen.dump_c, [routine]) expected = ( "#include \"file.h\"\n" "#include \n" "double test() {\n" " double test_result;\n" " double const Catalan = %s;\n" " test_result = pow(M_PI, Catalan);\n" " return test_result;\n" "}\n" ) % Catalan.evalf(17) assert source == expected def test_c_code_argument_order(): x, y, z = symbols('x,y,z') expr = x + y routine = make_routine("test", expr, argument_sequence=[z, x, y]) code_gen = C89CodeGen() source = get_string(code_gen.dump_c, [routine]) expected = ( "#include \"file.h\"\n" "#include \n" "double test(double z, double x, double y) {\n" " double test_result;\n" " test_result = x + y;\n" " return test_result;\n" "}\n" ) assert source == expected def test_simple_c_header(): x, y, z = symbols('x,y,z') expr = (x + y)*z routine = make_routine("test", expr) code_gen = C89CodeGen() source = get_string(code_gen.dump_h, [routine]) expected = ( "#ifndef PROJECT__FILE__H\n" "#define PROJECT__FILE__H\n" "double test(double x, double y, double z);\n" "#endif\n" ) assert source == expected def test_simple_c_codegen(): x, y, z = symbols('x,y,z') expr = (x + y)*z expected = [ ("file.c", "#include \"file.h\"\n" "#include \n" "double test(double x, double y, double z) {\n" " double test_result;\n" " test_result = z*(x + y);\n" " return test_result;\n" "}\n"), ("file.h", "#ifndef PROJECT__FILE__H\n" "#define PROJECT__FILE__H\n" "double test(double x, double y, double z);\n" "#endif\n") ] result = codegen(("test", expr), "C", "file", header=False, empty=False) assert result == expected def test_multiple_results_c(): x, y, z = symbols('x,y,z') expr1 = (x + y)*z expr2 = (x - y)*z routine = make_routine( "test", [expr1, expr2] ) code_gen = C99CodeGen() raises(CodeGenError, lambda: get_string(code_gen.dump_h, [routine])) def test_no_results_c(): raises(ValueError, lambda: make_routine("test", [])) def test_ansi_math1_codegen(): # not included: log10 from sympy import (acos, asin, atan, ceiling, cos, cosh, floor, log, ln, sin, sinh, sqrt, tan, tanh, Abs) x = symbols('x') name_expr = [ ("test_fabs", Abs(x)), ("test_acos", acos(x)), ("test_asin", asin(x)), ("test_atan", atan(x)), ("test_ceil", ceiling(x)), ("test_cos", cos(x)), ("test_cosh", cosh(x)), ("test_floor", floor(x)), ("test_log", log(x)), ("test_ln", ln(x)), ("test_sin", sin(x)), ("test_sinh", sinh(x)), ("test_sqrt", sqrt(x)), ("test_tan", tan(x)), ("test_tanh", tanh(x)), ] result = codegen(name_expr, "C89", "file", header=False, empty=False) assert result[0][0] == "file.c" assert result[0][1] == ( '#include "file.h"\n#include \n' 'double test_fabs(double x) {\n double test_fabs_result;\n test_fabs_result = fabs(x);\n return test_fabs_result;\n}\n' 'double test_acos(double x) {\n double test_acos_result;\n test_acos_result = acos(x);\n return test_acos_result;\n}\n' 'double test_asin(double x) {\n double test_asin_result;\n test_asin_result = asin(x);\n return test_asin_result;\n}\n' 'double test_atan(double x) {\n double test_atan_result;\n test_atan_result = atan(x);\n return test_atan_result;\n}\n' 'double test_ceil(double x) {\n double test_ceil_result;\n test_ceil_result = ceil(x);\n return test_ceil_result;\n}\n' 'double test_cos(double x) {\n double test_cos_result;\n test_cos_result = cos(x);\n return test_cos_result;\n}\n' 'double test_cosh(double x) {\n double test_cosh_result;\n test_cosh_result = cosh(x);\n return test_cosh_result;\n}\n' 'double test_floor(double x) {\n double test_floor_result;\n test_floor_result = floor(x);\n return test_floor_result;\n}\n' 'double test_log(double x) {\n double test_log_result;\n test_log_result = log(x);\n return test_log_result;\n}\n' 'double test_ln(double x) {\n double test_ln_result;\n test_ln_result = log(x);\n return test_ln_result;\n}\n' 'double test_sin(double x) {\n double test_sin_result;\n test_sin_result = sin(x);\n return test_sin_result;\n}\n' 'double test_sinh(double x) {\n double test_sinh_result;\n test_sinh_result = sinh(x);\n return test_sinh_result;\n}\n' 'double test_sqrt(double x) {\n double test_sqrt_result;\n test_sqrt_result = sqrt(x);\n return test_sqrt_result;\n}\n' 'double test_tan(double x) {\n double test_tan_result;\n test_tan_result = tan(x);\n return test_tan_result;\n}\n' 'double test_tanh(double x) {\n double test_tanh_result;\n test_tanh_result = tanh(x);\n return test_tanh_result;\n}\n' ) assert result[1][0] == "file.h" assert result[1][1] == ( '#ifndef PROJECT__FILE__H\n#define PROJECT__FILE__H\n' 'double test_fabs(double x);\ndouble test_acos(double x);\n' 'double test_asin(double x);\ndouble test_atan(double x);\n' 'double test_ceil(double x);\ndouble test_cos(double x);\n' 'double test_cosh(double x);\ndouble test_floor(double x);\n' 'double test_log(double x);\ndouble test_ln(double x);\n' 'double test_sin(double x);\ndouble test_sinh(double x);\n' 'double test_sqrt(double x);\ndouble test_tan(double x);\n' 'double test_tanh(double x);\n#endif\n' ) def test_ansi_math2_codegen(): # not included: frexp, ldexp, modf, fmod from sympy import atan2 x, y = symbols('x,y') name_expr = [ ("test_atan2", atan2(x, y)), ("test_pow", x**y), ] result = codegen(name_expr, "C89", "file", header=False, empty=False) assert result[0][0] == "file.c" assert result[0][1] == ( '#include "file.h"\n#include \n' 'double test_atan2(double x, double y) {\n double test_atan2_result;\n test_atan2_result = atan2(x, y);\n return test_atan2_result;\n}\n' 'double test_pow(double x, double y) {\n double test_pow_result;\n test_pow_result = pow(x, y);\n return test_pow_result;\n}\n' ) assert result[1][0] == "file.h" assert result[1][1] == ( '#ifndef PROJECT__FILE__H\n#define PROJECT__FILE__H\n' 'double test_atan2(double x, double y);\n' 'double test_pow(double x, double y);\n' '#endif\n' ) def test_complicated_codegen(): from sympy import sin, cos, tan x, y, z = symbols('x,y,z') name_expr = [ ("test1", ((sin(x) + cos(y) + tan(z))**7).expand()), ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))), ] result = codegen(name_expr, "C89", "file", header=False, empty=False) assert result[0][0] == "file.c" assert result[0][1] == ( '#include "file.h"\n#include \n' 'double test1(double x, double y, double z) {\n' ' double test1_result;\n' ' test1_result = ' 'pow(sin(x), 7) + ' '7*pow(sin(x), 6)*cos(y) + ' '7*pow(sin(x), 6)*tan(z) + ' '21*pow(sin(x), 5)*pow(cos(y), 2) + ' '42*pow(sin(x), 5)*cos(y)*tan(z) + ' '21*pow(sin(x), 5)*pow(tan(z), 2) + ' '35*pow(sin(x), 4)*pow(cos(y), 3) + ' '105*pow(sin(x), 4)*pow(cos(y), 2)*tan(z) + ' '105*pow(sin(x), 4)*cos(y)*pow(tan(z), 2) + ' '35*pow(sin(x), 4)*pow(tan(z), 3) + ' '35*pow(sin(x), 3)*pow(cos(y), 4) + ' '140*pow(sin(x), 3)*pow(cos(y), 3)*tan(z) + ' '210*pow(sin(x), 3)*pow(cos(y), 2)*pow(tan(z), 2) + ' '140*pow(sin(x), 3)*cos(y)*pow(tan(z), 3) + ' '35*pow(sin(x), 3)*pow(tan(z), 4) + ' '21*pow(sin(x), 2)*pow(cos(y), 5) + ' '105*pow(sin(x), 2)*pow(cos(y), 4)*tan(z) + ' '210*pow(sin(x), 2)*pow(cos(y), 3)*pow(tan(z), 2) + ' '210*pow(sin(x), 2)*pow(cos(y), 2)*pow(tan(z), 3) + ' '105*pow(sin(x), 2)*cos(y)*pow(tan(z), 4) + ' '21*pow(sin(x), 2)*pow(tan(z), 5) + ' '7*sin(x)*pow(cos(y), 6) + ' '42*sin(x)*pow(cos(y), 5)*tan(z) + ' '105*sin(x)*pow(cos(y), 4)*pow(tan(z), 2) + ' '140*sin(x)*pow(cos(y), 3)*pow(tan(z), 3) + ' '105*sin(x)*pow(cos(y), 2)*pow(tan(z), 4) + ' '42*sin(x)*cos(y)*pow(tan(z), 5) + ' '7*sin(x)*pow(tan(z), 6) + ' 'pow(cos(y), 7) + ' '7*pow(cos(y), 6)*tan(z) + ' '21*pow(cos(y), 5)*pow(tan(z), 2) + ' '35*pow(cos(y), 4)*pow(tan(z), 3) + ' '35*pow(cos(y), 3)*pow(tan(z), 4) + ' '21*pow(cos(y), 2)*pow(tan(z), 5) + ' '7*cos(y)*pow(tan(z), 6) + ' 'pow(tan(z), 7);\n' ' return test1_result;\n' '}\n' 'double test2(double x, double y, double z) {\n' ' double test2_result;\n' ' test2_result = cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))));\n' ' return test2_result;\n' '}\n' ) assert result[1][0] == "file.h" assert result[1][1] == ( '#ifndef PROJECT__FILE__H\n' '#define PROJECT__FILE__H\n' 'double test1(double x, double y, double z);\n' 'double test2(double x, double y, double z);\n' '#endif\n' ) def test_loops_c(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) (f1, code), (f2, interface) = codegen( ('matrix_vector', Eq(y[i], A[i, j]*x[j])), "C99", "file", header=False, empty=False) assert f1 == 'file.c' expected = ( '#include "file.h"\n' '#include \n' 'void matrix_vector(double *A, int m, int n, double *x, double *y) {\n' ' for (int i=0; i\n' 'void test_dummies(int m_%(mno)i, double *x, double *y) {\n' ' for (int i_%(ino)i=0; i_%(ino)i\n' 'void matrix_vector(double *A, int m, int n, int o, int p, double *x, double *y) {\n' ' for (int i=o; i<%(upperi)s; i++){\n' ' y[i] = 0;\n' ' }\n' ' for (int i=o; i<%(upperi)s; i++){\n' ' for (int j=0; j\n' 'double foo(double x, double *y) {\n' ' (*y) = sin(x);\n' ' double foo_result;\n' ' foo_result = cos(x);\n' ' return foo_result;\n' '}\n' ) assert result[0][1] == expected def test_output_arg_c_reserved_words(): from sympy import sin, cos, Equality x, y, z = symbols("if, while, z") r = make_routine("foo", [Equality(y, sin(x)), cos(x)]) c = C89CodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.c" expected = ( '#include "test.h"\n' '#include \n' 'double foo(double if_, double *while_) {\n' ' (*while_) = sin(if_);\n' ' double foo_result;\n' ' foo_result = cos(if_);\n' ' return foo_result;\n' '}\n' ) assert result[0][1] == expected def test_multidim_c_argument_cse(): A_sym = MatrixSymbol('A', 3, 3) b_sym = MatrixSymbol('b', 3, 1) A = Matrix(A_sym) b = Matrix(b_sym) c = A*b cgen = CCodeGen(project="test", cse=True) r = cgen.routine("c", c) r.arguments[-1].result_var = "out" r.arguments[-1]._name = "out" code = get_string(cgen.dump_c, [r], prefix="test") expected = ( '#include "test.h"\n' "#include \n" "void c(double *A, double *b, double *out) {\n" " double x0[9];\n" " x0[0] = A[0];\n" " x0[1] = A[1];\n" " x0[2] = A[2];\n" " x0[3] = A[3];\n" " x0[4] = A[4];\n" " x0[5] = A[5];\n" " x0[6] = A[6];\n" " x0[7] = A[7];\n" " x0[8] = A[8];\n" " double x1[3];\n" " x1[0] = b[0];\n" " x1[1] = b[1];\n" " x1[2] = b[2];\n" " const double x2 = x1[0];\n" " const double x3 = x1[1];\n" " const double x4 = x1[2];\n" " out[0] = x2*x0[0] + x3*x0[1] + x4*x0[2];\n" " out[1] = x2*x0[3] + x3*x0[4] + x4*x0[5];\n" " out[2] = x2*x0[6] + x3*x0[7] + x4*x0[8];\n" "}\n" ) assert code == expected def test_ccode_results_named_ordered(): x, y, z = symbols('x,y,z') B, C = symbols('B,C') A = MatrixSymbol('A', 1, 3) expr1 = Equality(A, Matrix([[1, 2, x]])) expr2 = Equality(C, (x + y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) expected = ( '#include "test.h"\n' '#include \n' 'void test(double x, double *C, double z, double y, double *A, double *B) {\n' ' (*C) = z*(x + y);\n' ' A[0] = 1;\n' ' A[1] = 2;\n' ' A[2] = x;\n' ' (*B) = 2*x;\n' '}\n' ) result = codegen(name_expr, "c", "test", header=False, empty=False, argument_sequence=(x, C, z, y, A, B)) source = result[0][1] assert source == expected def test_ccode_matrixsymbol_slice(): A = MatrixSymbol('A', 5, 3) B = MatrixSymbol('B', 1, 3) C = MatrixSymbol('C', 1, 3) D = MatrixSymbol('D', 5, 1) name_expr = ("test", [Equality(B, A[0, :]), Equality(C, A[1, :]), Equality(D, A[:, 2])]) result = codegen(name_expr, "c99", "test", header=False, empty=False) source = result[0][1] expected = ( '#include "test.h"\n' '#include \n' 'void test(double *A, double *B, double *C, double *D) {\n' ' B[0] = A[0];\n' ' B[1] = A[1];\n' ' B[2] = A[2];\n' ' C[0] = A[3];\n' ' C[1] = A[4];\n' ' C[2] = A[5];\n' ' D[0] = A[2];\n' ' D[1] = A[5];\n' ' D[2] = A[8];\n' ' D[3] = A[11];\n' ' D[4] = A[14];\n' '}\n' ) assert source == expected def test_ccode_cse(): a, b, c, d = symbols('a b c d') e = MatrixSymbol('e', 3, 1) name_expr = ("test", [Equality(e, Matrix([[a*b], [a*b + c*d], [a*b*c*d]]))]) generator = CCodeGen(cse=True) result = codegen(name_expr, code_gen=generator, header=False, empty=False) source = result[0][1] expected = ( '#include "test.h"\n' '#include \n' 'void test(double a, double b, double c, double d, double *e) {\n' ' const double x0 = a*b;\n' ' const double x1 = c*d;\n' ' e[0] = x0;\n' ' e[1] = x0 + x1;\n' ' e[2] = x0*x1;\n' '}\n' ) assert source == expected def test_ccode_unused_array_arg(): x = MatrixSymbol('x', 2, 1) # x does not appear in output name_expr = ("test", 1.0) generator = CCodeGen() result = codegen(name_expr, code_gen=generator, header=False, empty=False, argument_sequence=(x,)) source = result[0][1] # note: x should appear as (double *) expected = ( '#include "test.h"\n' '#include \n' 'double test(double *x) {\n' ' double test_result;\n' ' test_result = 1.0;\n' ' return test_result;\n' '}\n' ) assert source == expected def test_empty_f_code(): code_gen = FCodeGen() source = get_string(code_gen.dump_f95, []) assert source == "" def test_empty_f_code_with_header(): code_gen = FCodeGen() source = get_string(code_gen.dump_f95, [], header=True) assert source[:82] == ( "!******************************************************************************\n!*" ) # " Code generated with sympy 0.7.2-git " assert source[158:] == ( "*\n" "!* *\n" "!* See http://www.sympy.org/ for more information. *\n" "!* *\n" "!* This file is part of 'project' *\n" "!******************************************************************************\n" ) def test_empty_f_header(): code_gen = FCodeGen() source = get_string(code_gen.dump_h, []) assert source == "" def test_simple_f_code(): x, y, z = symbols('x,y,z') expr = (x + y)*z routine = make_routine("test", expr) code_gen = FCodeGen() source = get_string(code_gen.dump_f95, [routine]) expected = ( "REAL*8 function test(x, y, z)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "REAL*8, intent(in) :: z\n" "test = z*(x + y)\n" "end function\n" ) assert source == expected def test_numbersymbol_f_code(): routine = make_routine("test", pi**Catalan) code_gen = FCodeGen() source = get_string(code_gen.dump_f95, [routine]) expected = ( "REAL*8 function test()\n" "implicit none\n" "REAL*8, parameter :: Catalan = %sd0\n" "REAL*8, parameter :: pi = %sd0\n" "test = pi**Catalan\n" "end function\n" ) % (Catalan.evalf(17), pi.evalf(17)) assert source == expected def test_erf_f_code(): x = symbols('x') routine = make_routine("test", erf(x) - erf(-2 * x)) code_gen = FCodeGen() source = get_string(code_gen.dump_f95, [routine]) expected = ( "REAL*8 function test(x)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "test = erf(x) + erf(2.0d0*x)\n" "end function\n" ) assert source == expected, source def test_f_code_argument_order(): x, y, z = symbols('x,y,z') expr = x + y routine = make_routine("test", expr, argument_sequence=[z, x, y]) code_gen = FCodeGen() source = get_string(code_gen.dump_f95, [routine]) expected = ( "REAL*8 function test(z, x, y)\n" "implicit none\n" "REAL*8, intent(in) :: z\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "test = x + y\n" "end function\n" ) assert source == expected def test_simple_f_header(): x, y, z = symbols('x,y,z') expr = (x + y)*z routine = make_routine("test", expr) code_gen = FCodeGen() source = get_string(code_gen.dump_h, [routine]) expected = ( "interface\n" "REAL*8 function test(x, y, z)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "REAL*8, intent(in) :: z\n" "end function\n" "end interface\n" ) assert source == expected def test_simple_f_codegen(): x, y, z = symbols('x,y,z') expr = (x + y)*z result = codegen( ("test", expr), "F95", "file", header=False, empty=False) expected = [ ("file.f90", "REAL*8 function test(x, y, z)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "REAL*8, intent(in) :: z\n" "test = z*(x + y)\n" "end function\n"), ("file.h", "interface\n" "REAL*8 function test(x, y, z)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "REAL*8, intent(in) :: z\n" "end function\n" "end interface\n") ] assert result == expected def test_multiple_results_f(): x, y, z = symbols('x,y,z') expr1 = (x + y)*z expr2 = (x - y)*z routine = make_routine( "test", [expr1, expr2] ) code_gen = FCodeGen() raises(CodeGenError, lambda: get_string(code_gen.dump_h, [routine])) def test_no_results_f(): raises(ValueError, lambda: make_routine("test", [])) def test_intrinsic_math_codegen(): # not included: log10 from sympy import (acos, asin, atan, cos, cosh, log, ln, sin, sinh, sqrt, tan, tanh, Abs) x = symbols('x') name_expr = [ ("test_abs", Abs(x)), ("test_acos", acos(x)), ("test_asin", asin(x)), ("test_atan", atan(x)), ("test_cos", cos(x)), ("test_cosh", cosh(x)), ("test_log", log(x)), ("test_ln", ln(x)), ("test_sin", sin(x)), ("test_sinh", sinh(x)), ("test_sqrt", sqrt(x)), ("test_tan", tan(x)), ("test_tanh", tanh(x)), ] result = codegen(name_expr, "F95", "file", header=False, empty=False) assert result[0][0] == "file.f90" expected = ( 'REAL*8 function test_abs(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_abs = abs(x)\n' 'end function\n' 'REAL*8 function test_acos(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_acos = acos(x)\n' 'end function\n' 'REAL*8 function test_asin(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_asin = asin(x)\n' 'end function\n' 'REAL*8 function test_atan(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_atan = atan(x)\n' 'end function\n' 'REAL*8 function test_cos(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_cos = cos(x)\n' 'end function\n' 'REAL*8 function test_cosh(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_cosh = cosh(x)\n' 'end function\n' 'REAL*8 function test_log(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_log = log(x)\n' 'end function\n' 'REAL*8 function test_ln(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_ln = log(x)\n' 'end function\n' 'REAL*8 function test_sin(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_sin = sin(x)\n' 'end function\n' 'REAL*8 function test_sinh(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_sinh = sinh(x)\n' 'end function\n' 'REAL*8 function test_sqrt(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_sqrt = sqrt(x)\n' 'end function\n' 'REAL*8 function test_tan(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_tan = tan(x)\n' 'end function\n' 'REAL*8 function test_tanh(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'test_tanh = tanh(x)\n' 'end function\n' ) assert result[0][1] == expected assert result[1][0] == "file.h" expected = ( 'interface\n' 'REAL*8 function test_abs(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_acos(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_asin(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_atan(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_cos(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_cosh(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_log(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_ln(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_sin(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_sinh(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_sqrt(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_tan(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_tanh(x)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'end function\n' 'end interface\n' ) assert result[1][1] == expected def test_intrinsic_math2_codegen(): # not included: frexp, ldexp, modf, fmod from sympy import atan2 x, y = symbols('x,y') name_expr = [ ("test_atan2", atan2(x, y)), ("test_pow", x**y), ] result = codegen(name_expr, "F95", "file", header=False, empty=False) assert result[0][0] == "file.f90" expected = ( 'REAL*8 function test_atan2(x, y)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'test_atan2 = atan2(x, y)\n' 'end function\n' 'REAL*8 function test_pow(x, y)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'test_pow = x**y\n' 'end function\n' ) assert result[0][1] == expected assert result[1][0] == "file.h" expected = ( 'interface\n' 'REAL*8 function test_atan2(x, y)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test_pow(x, y)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'end function\n' 'end interface\n' ) assert result[1][1] == expected def test_complicated_codegen_f95(): from sympy import sin, cos, tan x, y, z = symbols('x,y,z') name_expr = [ ("test1", ((sin(x) + cos(y) + tan(z))**7).expand()), ("test2", cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))), ] result = codegen(name_expr, "F95", "file", header=False, empty=False) assert result[0][0] == "file.f90" expected = ( 'REAL*8 function test1(x, y, z)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'REAL*8, intent(in) :: z\n' 'test1 = sin(x)**7 + 7*sin(x)**6*cos(y) + 7*sin(x)**6*tan(z) + 21*sin(x) &\n' ' **5*cos(y)**2 + 42*sin(x)**5*cos(y)*tan(z) + 21*sin(x)**5*tan(z) &\n' ' **2 + 35*sin(x)**4*cos(y)**3 + 105*sin(x)**4*cos(y)**2*tan(z) + &\n' ' 105*sin(x)**4*cos(y)*tan(z)**2 + 35*sin(x)**4*tan(z)**3 + 35*sin( &\n' ' x)**3*cos(y)**4 + 140*sin(x)**3*cos(y)**3*tan(z) + 210*sin(x)**3* &\n' ' cos(y)**2*tan(z)**2 + 140*sin(x)**3*cos(y)*tan(z)**3 + 35*sin(x) &\n' ' **3*tan(z)**4 + 21*sin(x)**2*cos(y)**5 + 105*sin(x)**2*cos(y)**4* &\n' ' tan(z) + 210*sin(x)**2*cos(y)**3*tan(z)**2 + 210*sin(x)**2*cos(y) &\n' ' **2*tan(z)**3 + 105*sin(x)**2*cos(y)*tan(z)**4 + 21*sin(x)**2*tan &\n' ' (z)**5 + 7*sin(x)*cos(y)**6 + 42*sin(x)*cos(y)**5*tan(z) + 105* &\n' ' sin(x)*cos(y)**4*tan(z)**2 + 140*sin(x)*cos(y)**3*tan(z)**3 + 105 &\n' ' *sin(x)*cos(y)**2*tan(z)**4 + 42*sin(x)*cos(y)*tan(z)**5 + 7*sin( &\n' ' x)*tan(z)**6 + cos(y)**7 + 7*cos(y)**6*tan(z) + 21*cos(y)**5*tan( &\n' ' z)**2 + 35*cos(y)**4*tan(z)**3 + 35*cos(y)**3*tan(z)**4 + 21*cos( &\n' ' y)**2*tan(z)**5 + 7*cos(y)*tan(z)**6 + tan(z)**7\n' 'end function\n' 'REAL*8 function test2(x, y, z)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'REAL*8, intent(in) :: z\n' 'test2 = cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))\n' 'end function\n' ) assert result[0][1] == expected assert result[1][0] == "file.h" expected = ( 'interface\n' 'REAL*8 function test1(x, y, z)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'REAL*8, intent(in) :: z\n' 'end function\n' 'end interface\n' 'interface\n' 'REAL*8 function test2(x, y, z)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(in) :: y\n' 'REAL*8, intent(in) :: z\n' 'end function\n' 'end interface\n' ) assert result[1][1] == expected def test_loops(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m = symbols('n,m', integer=True) A, x, y = map(IndexedBase, 'Axy') i = Idx('i', m) j = Idx('j', n) (f1, code), (f2, interface) = codegen( ('matrix_vector', Eq(y[i], A[i, j]*x[j])), "F95", "file", header=False, empty=False) assert f1 == 'file.f90' expected = ( 'subroutine matrix_vector(A, m, n, x, y)\n' 'implicit none\n' 'INTEGER*4, intent(in) :: m\n' 'INTEGER*4, intent(in) :: n\n' 'REAL*8, intent(in), dimension(1:m, 1:n) :: A\n' 'REAL*8, intent(in), dimension(1:n) :: x\n' 'REAL*8, intent(out), dimension(1:m) :: y\n' 'INTEGER*4 :: i\n' 'INTEGER*4 :: j\n' 'do i = 1, m\n' ' y(i) = 0\n' 'end do\n' 'do i = 1, m\n' ' do j = 1, n\n' ' y(i) = %(rhs)s + y(i)\n' ' end do\n' 'end do\n' 'end subroutine\n' ) assert code == expected % {'rhs': 'A(i, j)*x(j)'} or\ code == expected % {'rhs': 'x(j)*A(i, j)'} assert f2 == 'file.h' assert interface == ( 'interface\n' 'subroutine matrix_vector(A, m, n, x, y)\n' 'implicit none\n' 'INTEGER*4, intent(in) :: m\n' 'INTEGER*4, intent(in) :: n\n' 'REAL*8, intent(in), dimension(1:m, 1:n) :: A\n' 'REAL*8, intent(in), dimension(1:n) :: x\n' 'REAL*8, intent(out), dimension(1:m) :: y\n' 'end subroutine\n' 'end interface\n' ) def test_dummy_loops_f95(): from sympy.tensor import IndexedBase, Idx i, m = symbols('i m', integer=True, cls=Dummy) x = IndexedBase('x') y = IndexedBase('y') i = Idx(i, m) expected = ( 'subroutine test_dummies(m_%(mcount)i, x, y)\n' 'implicit none\n' 'INTEGER*4, intent(in) :: m_%(mcount)i\n' 'REAL*8, intent(in), dimension(1:m_%(mcount)i) :: x\n' 'REAL*8, intent(out), dimension(1:m_%(mcount)i) :: y\n' 'INTEGER*4 :: i_%(icount)i\n' 'do i_%(icount)i = 1, m_%(mcount)i\n' ' y(i_%(icount)i) = x(i_%(icount)i)\n' 'end do\n' 'end subroutine\n' ) % {'icount': i.label.dummy_index, 'mcount': m.dummy_index} r = make_routine('test_dummies', Eq(y[i], x[i])) c = FCodeGen() code = get_string(c.dump_f95, [r]) assert code == expected def test_loops_InOut(): from sympy.tensor import IndexedBase, Idx from sympy import symbols i, j, n, m = symbols('i,j,n,m', integer=True) A, x, y = symbols('A,x,y') A = IndexedBase(A)[Idx(i, m), Idx(j, n)] x = IndexedBase(x)[Idx(j, n)] y = IndexedBase(y)[Idx(i, m)] (f1, code), (f2, interface) = codegen( ('matrix_vector', Eq(y, y + A*x)), "F95", "file", header=False, empty=False) assert f1 == 'file.f90' expected = ( 'subroutine matrix_vector(A, m, n, x, y)\n' 'implicit none\n' 'INTEGER*4, intent(in) :: m\n' 'INTEGER*4, intent(in) :: n\n' 'REAL*8, intent(in), dimension(1:m, 1:n) :: A\n' 'REAL*8, intent(in), dimension(1:n) :: x\n' 'REAL*8, intent(inout), dimension(1:m) :: y\n' 'INTEGER*4 :: i\n' 'INTEGER*4 :: j\n' 'do i = 1, m\n' ' do j = 1, n\n' ' y(i) = %(rhs)s + y(i)\n' ' end do\n' 'end do\n' 'end subroutine\n' ) assert (code == expected % {'rhs': 'A(i, j)*x(j)'} or code == expected % {'rhs': 'x(j)*A(i, j)'}) assert f2 == 'file.h' assert interface == ( 'interface\n' 'subroutine matrix_vector(A, m, n, x, y)\n' 'implicit none\n' 'INTEGER*4, intent(in) :: m\n' 'INTEGER*4, intent(in) :: n\n' 'REAL*8, intent(in), dimension(1:m, 1:n) :: A\n' 'REAL*8, intent(in), dimension(1:n) :: x\n' 'REAL*8, intent(inout), dimension(1:m) :: y\n' 'end subroutine\n' 'end interface\n' ) def test_partial_loops_f(): # check that loop boundaries are determined by Idx, and array strides # determined by shape of IndexedBase object. from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o, p = symbols('n m o p', integer=True) A = IndexedBase('A', shape=(m, p)) x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', (o, m - 5)) # Note: bounds are inclusive j = Idx('j', n) # dimension n corresponds to bounds (0, n - 1) (f1, code), (f2, interface) = codegen( ('matrix_vector', Eq(y[i], A[i, j]*x[j])), "F95", "file", header=False, empty=False) expected = ( 'subroutine matrix_vector(A, m, n, o, p, x, y)\n' 'implicit none\n' 'INTEGER*4, intent(in) :: m\n' 'INTEGER*4, intent(in) :: n\n' 'INTEGER*4, intent(in) :: o\n' 'INTEGER*4, intent(in) :: p\n' 'REAL*8, intent(in), dimension(1:m, 1:p) :: A\n' 'REAL*8, intent(in), dimension(1:n) :: x\n' 'REAL*8, intent(out), dimension(1:%(iup-ilow)s) :: y\n' 'INTEGER*4 :: i\n' 'INTEGER*4 :: j\n' 'do i = %(ilow)s, %(iup)s\n' ' y(i) = 0\n' 'end do\n' 'do i = %(ilow)s, %(iup)s\n' ' do j = 1, n\n' ' y(i) = %(rhs)s + y(i)\n' ' end do\n' 'end do\n' 'end subroutine\n' ) % { 'rhs': '%(rhs)s', 'iup': str(m - 4), 'ilow': str(1 + o), 'iup-ilow': str(m - 4 - o) } assert code == expected % {'rhs': 'A(i, j)*x(j)'} or\ code == expected % {'rhs': 'x(j)*A(i, j)'} def test_output_arg_f(): from sympy import sin, cos, Equality x, y, z = symbols("x,y,z") r = make_routine("foo", [Equality(y, sin(x)), cos(x)]) c = FCodeGen() result = c.write([r], "test", header=False, empty=False) assert result[0][0] == "test.f90" assert result[0][1] == ( 'REAL*8 function foo(x, y)\n' 'implicit none\n' 'REAL*8, intent(in) :: x\n' 'REAL*8, intent(out) :: y\n' 'y = sin(x)\n' 'foo = cos(x)\n' 'end function\n' ) def test_inline_function(): from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m = symbols('n m', integer=True) A, x, y = map(IndexedBase, 'Axy') i = Idx('i', m) p = FCodeGen() func = implemented_function('func', Lambda(n, n*(n + 1))) routine = make_routine('test_inline', Eq(y[i], func(x[i]))) code = get_string(p.dump_f95, [routine]) expected = ( 'subroutine test_inline(m, x, y)\n' 'implicit none\n' 'INTEGER*4, intent(in) :: m\n' 'REAL*8, intent(in), dimension(1:m) :: x\n' 'REAL*8, intent(out), dimension(1:m) :: y\n' 'INTEGER*4 :: i\n' 'do i = 1, m\n' ' y(i) = %s*%s\n' 'end do\n' 'end subroutine\n' ) args = ('x(i)', '(x(i) + 1)') assert code == expected % args or\ code == expected % args[::-1] def test_f_code_call_signature_wrap(): # Issue #7934 x = symbols('x:20') expr = 0 for sym in x: expr += sym routine = make_routine("test", expr) code_gen = FCodeGen() source = get_string(code_gen.dump_f95, [routine]) expected = """\ REAL*8 function test(x0, x1, x10, x11, x12, x13, x14, x15, x16, x17, x18, & x19, x2, x3, x4, x5, x6, x7, x8, x9) implicit none REAL*8, intent(in) :: x0 REAL*8, intent(in) :: x1 REAL*8, intent(in) :: x10 REAL*8, intent(in) :: x11 REAL*8, intent(in) :: x12 REAL*8, intent(in) :: x13 REAL*8, intent(in) :: x14 REAL*8, intent(in) :: x15 REAL*8, intent(in) :: x16 REAL*8, intent(in) :: x17 REAL*8, intent(in) :: x18 REAL*8, intent(in) :: x19 REAL*8, intent(in) :: x2 REAL*8, intent(in) :: x3 REAL*8, intent(in) :: x4 REAL*8, intent(in) :: x5 REAL*8, intent(in) :: x6 REAL*8, intent(in) :: x7 REAL*8, intent(in) :: x8 REAL*8, intent(in) :: x9 test = x0 + x1 + x10 + x11 + x12 + x13 + x14 + x15 + x16 + x17 + x18 + & x19 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 end function """ assert source == expected def test_check_case(): x, X = symbols('x,X') raises(CodeGenError, lambda: codegen(('test', x*X), 'f95', 'prefix')) def test_check_case_false_positive(): # The upper case/lower case exception should not be triggered by SymPy # objects that differ only because of assumptions. (It may be useful to # have a check for that as well, but here we only want to test against # false positives with respect to case checking.) x1 = symbols('x') x2 = symbols('x', my_assumption=True) try: codegen(('test', x1*x2), 'f95', 'prefix') except CodeGenError as e: if e.args[0].startswith("Fortran ignores case."): raise AssertionError("This exception should not be raised!") def test_c_fortran_omit_routine_name(): x, y = symbols("x,y") name_expr = [("foo", 2*x)] result = codegen(name_expr, "F95", header=False, empty=False) expresult = codegen(name_expr, "F95", "foo", header=False, empty=False) assert result[0][1] == expresult[0][1] name_expr = ("foo", x*y) result = codegen(name_expr, "F95", header=False, empty=False) expresult = codegen(name_expr, "F95", "foo", header=False, empty=False) assert result[0][1] == expresult[0][1] name_expr = ("foo", Matrix([[x, y], [x+y, x-y]])) result = codegen(name_expr, "C89", header=False, empty=False) expresult = codegen(name_expr, "C89", "foo", header=False, empty=False) assert result[0][1] == expresult[0][1] def test_fcode_matrix_output(): x, y, z = symbols('x,y,z') e1 = x + y e2 = Matrix([[x, y], [z, 16]]) name_expr = ("test", (e1, e2)) result = codegen(name_expr, "f95", "test", header=False, empty=False) source = result[0][1] expected = ( "REAL*8 function test(x, y, z, out_%(hash)s)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "REAL*8, intent(in) :: z\n" "REAL*8, intent(out), dimension(1:2, 1:2) :: out_%(hash)s\n" "out_%(hash)s(1, 1) = x\n" "out_%(hash)s(2, 1) = z\n" "out_%(hash)s(1, 2) = y\n" "out_%(hash)s(2, 2) = 16\n" "test = x + y\n" "end function\n" ) # look for the magic number a = source.splitlines()[5] b = a.split('_') out = b[1] expected = expected % {'hash': out} assert source == expected def test_fcode_results_named_ordered(): x, y, z = symbols('x,y,z') B, C = symbols('B,C') A = MatrixSymbol('A', 1, 3) expr1 = Equality(A, Matrix([[1, 2, x]])) expr2 = Equality(C, (x + y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result = codegen(name_expr, "f95", "test", header=False, empty=False, argument_sequence=(x, z, y, C, A, B)) source = result[0][1] expected = ( "subroutine test(x, z, y, C, A, B)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: z\n" "REAL*8, intent(in) :: y\n" "REAL*8, intent(out) :: C\n" "REAL*8, intent(out) :: B\n" "REAL*8, intent(out), dimension(1:1, 1:3) :: A\n" "C = z*(x + y)\n" "A(1, 1) = 1\n" "A(1, 2) = 2\n" "A(1, 3) = x\n" "B = 2*x\n" "end subroutine\n" ) assert source == expected def test_fcode_matrixsymbol_slice(): A = MatrixSymbol('A', 2, 3) B = MatrixSymbol('B', 1, 3) C = MatrixSymbol('C', 1, 3) D = MatrixSymbol('D', 2, 1) name_expr = ("test", [Equality(B, A[0, :]), Equality(C, A[1, :]), Equality(D, A[:, 2])]) result = codegen(name_expr, "f95", "test", header=False, empty=False) source = result[0][1] expected = ( "subroutine test(A, B, C, D)\n" "implicit none\n" "REAL*8, intent(in), dimension(1:2, 1:3) :: A\n" "REAL*8, intent(out), dimension(1:1, 1:3) :: B\n" "REAL*8, intent(out), dimension(1:1, 1:3) :: C\n" "REAL*8, intent(out), dimension(1:2, 1:1) :: D\n" "B(1, 1) = A(1, 1)\n" "B(1, 2) = A(1, 2)\n" "B(1, 3) = A(1, 3)\n" "C(1, 1) = A(2, 1)\n" "C(1, 2) = A(2, 2)\n" "C(1, 3) = A(2, 3)\n" "D(1, 1) = A(1, 3)\n" "D(2, 1) = A(2, 3)\n" "end subroutine\n" ) assert source == expected def test_fcode_matrixsymbol_slice_autoname(): # see issue #8093 A = MatrixSymbol('A', 2, 3) name_expr = ("test", A[:, 1]) result = codegen(name_expr, "f95", "test", header=False, empty=False) source = result[0][1] expected = ( "subroutine test(A, out_%(hash)s)\n" "implicit none\n" "REAL*8, intent(in), dimension(1:2, 1:3) :: A\n" "REAL*8, intent(out), dimension(1:2, 1:1) :: out_%(hash)s\n" "out_%(hash)s(1, 1) = A(1, 2)\n" "out_%(hash)s(2, 1) = A(2, 2)\n" "end subroutine\n" ) # look for the magic number a = source.splitlines()[3] b = a.split('_') out = b[1] expected = expected % {'hash': out} assert source == expected def test_global_vars(): x, y, z, t = symbols("x y z t") result = codegen(('f', x*y), "F95", header=False, empty=False, global_vars=(y,)) source = result[0][1] expected = ( "REAL*8 function f(x)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "f = x*y\n" "end function\n" ) assert source == expected expected = ( '#include "f.h"\n' '#include \n' 'double f(double x, double y) {\n' ' double f_result;\n' ' f_result = x*y + z;\n' ' return f_result;\n' '}\n' ) result = codegen(('f', x*y+z), "C", header=False, empty=False, global_vars=(z, t)) source = result[0][1] assert source == expected def test_custom_codegen(): from sympy.printing.c import C99CodePrinter from sympy.functions.elementary.exponential import exp printer = C99CodePrinter(settings={'user_functions': {'exp': 'fastexp'}}) x, y = symbols('x y') expr = exp(x + y) # replace math.h with a different header gen = C99CodeGen(printer=printer, preprocessor_statements=['#include "fastexp.h"']) expected = ( '#include "expr.h"\n' '#include "fastexp.h"\n' 'double expr(double x, double y) {\n' ' double expr_result;\n' ' expr_result = fastexp(x + y);\n' ' return expr_result;\n' '}\n' ) result = codegen(('expr', expr), header=False, empty=False, code_gen=gen) source = result[0][1] assert source == expected # use both math.h and an external header gen = C99CodeGen(printer=printer) gen.preprocessor_statements.append('#include "fastexp.h"') expected = ( '#include "expr.h"\n' '#include \n' '#include "fastexp.h"\n' 'double expr(double x, double y) {\n' ' double expr_result;\n' ' expr_result = fastexp(x + y);\n' ' return expr_result;\n' '}\n' ) result = codegen(('expr', expr), header=False, empty=False, code_gen=gen) source = result[0][1] assert source == expected def test_c_with_printer(): #issue 13586 from sympy.printing.c import C99CodePrinter class CustomPrinter(C99CodePrinter): def _print_Pow(self, expr): return "fastpow({}, {})".format(self._print(expr.base), self._print(expr.exp)) x = symbols('x') expr = x**3 expected =[ ("file.c", "#include \"file.h\"\n" "#include \n" "double test(double x) {\n" " double test_result;\n" " test_result = fastpow(x, 3);\n" " return test_result;\n" "}\n"), ("file.h", "#ifndef PROJECT__FILE__H\n" "#define PROJECT__FILE__H\n" "double test(double x);\n" "#endif\n") ] result = codegen(("test", expr), "C","file", header=False, empty=False, printer = CustomPrinter()) assert result == expected def test_fcode_complex(): import sympy.utilities.codegen sympy.utilities.codegen.COMPLEX_ALLOWED = True x = Symbol('x', real=True) y = Symbol('y',real=True) result = codegen(('test',x+y), 'f95', 'test', header=False, empty=False) source = (result[0][1]) expected = ( "REAL*8 function test(x, y)\n" "implicit none\n" "REAL*8, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "test = x + y\n" "end function\n") assert source == expected x = Symbol('x') y = Symbol('y',real=True) result = codegen(('test',x+y), 'f95', 'test', header=False, empty=False) source = (result[0][1]) expected = ( "COMPLEX*16 function test(x, y)\n" "implicit none\n" "COMPLEX*16, intent(in) :: x\n" "REAL*8, intent(in) :: y\n" "test = x + y\n" "end function\n" ) assert source==expected sympy.utilities.codegen.COMPLEX_ALLOWED = False sympy-sympy-1.9/sympy/utilities/tests/test_codegen_julia.py000066400000000000000000000435341412543434000244730ustar00rootroot00000000000000from io import StringIO from sympy.core import S, symbols, Eq, pi, Catalan, EulerGamma, Function from sympy import Piecewise from sympy import Equality from sympy.matrices import Matrix, MatrixSymbol from sympy.utilities.codegen import JuliaCodeGen, codegen, make_routine from sympy.testing.pytest import XFAIL import sympy x, y, z = symbols('x,y,z') def test_empty_jl_code(): code_gen = JuliaCodeGen() output = StringIO() code_gen.dump_jl([], output, "file", header=False, empty=False) source = output.getvalue() assert source == "" def test_jl_simple_code(): name_expr = ("test", (x + y)*z) result, = codegen(name_expr, "Julia", header=False, empty=False) assert result[0] == "test.jl" source = result[1] expected = ( "function test(x, y, z)\n" " out1 = z.*(x + y)\n" " return out1\n" "end\n" ) assert source == expected def test_jl_simple_code_with_header(): name_expr = ("test", (x + y)*z) result, = codegen(name_expr, "Julia", header=True, empty=False) assert result[0] == "test.jl" source = result[1] expected = ( "# Code generated with sympy " + sympy.__version__ + "\n" "#\n" "# See http://www.sympy.org/ for more information.\n" "#\n" "# This file is part of 'project'\n" "function test(x, y, z)\n" " out1 = z.*(x + y)\n" " return out1\n" "end\n" ) assert source == expected def test_jl_simple_code_nameout(): expr = Equality(z, (x + y)) name_expr = ("test", expr) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x, y)\n" " z = x + y\n" " return z\n" "end\n" ) assert source == expected def test_jl_numbersymbol(): name_expr = ("test", pi**Catalan) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test()\n" " out1 = pi^catalan\n" " return out1\n" "end\n" ) assert source == expected @XFAIL def test_jl_numbersymbol_no_inline(): # FIXME: how to pass inline=False to the JuliaCodePrinter? name_expr = ("test", [pi**Catalan, EulerGamma]) result, = codegen(name_expr, "Julia", header=False, empty=False, inline=False) source = result[1] expected = ( "function test()\n" " Catalan = 0.915965594177219\n" " EulerGamma = 0.5772156649015329\n" " out1 = pi^Catalan\n" " out2 = EulerGamma\n" " return out1, out2\n" "end\n" ) assert source == expected def test_jl_code_argument_order(): expr = x + y routine = make_routine("test", expr, argument_sequence=[z, x, y], language="julia") code_gen = JuliaCodeGen() output = StringIO() code_gen.dump_jl([routine], output, "test", header=False, empty=False) source = output.getvalue() expected = ( "function test(z, x, y)\n" " out1 = x + y\n" " return out1\n" "end\n" ) assert source == expected def test_multiple_results_m(): # Here the output order is the input order expr1 = (x + y)*z expr2 = (x - y)*z name_expr = ("test", [expr1, expr2]) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x, y, z)\n" " out1 = z.*(x + y)\n" " out2 = z.*(x - y)\n" " return out1, out2\n" "end\n" ) assert source == expected def test_results_named_unordered(): # Here output order is based on name_expr A, B, C = symbols('A,B,C') expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, (x - y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x, y, z)\n" " C = z.*(x + y)\n" " A = z.*(x - y)\n" " B = 2*x\n" " return C, A, B\n" "end\n" ) assert source == expected def test_results_named_ordered(): A, B, C = symbols('A,B,C') expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, (x - y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result = codegen(name_expr, "Julia", header=False, empty=False, argument_sequence=(x, z, y)) assert result[0][0] == "test.jl" source = result[0][1] expected = ( "function test(x, z, y)\n" " C = z.*(x + y)\n" " A = z.*(x - y)\n" " B = 2*x\n" " return C, A, B\n" "end\n" ) assert source == expected def test_complicated_jl_codegen(): from sympy import sin, cos, tan name_expr = ("testlong", [ ((sin(x) + cos(y) + tan(z))**3).expand(), cos(cos(cos(cos(cos(cos(cos(cos(x + y + z)))))))) ]) result = codegen(name_expr, "Julia", header=False, empty=False) assert result[0][0] == "testlong.jl" source = result[0][1] expected = ( "function testlong(x, y, z)\n" " out1 = sin(x).^3 + 3*sin(x).^2.*cos(y) + 3*sin(x).^2.*tan(z)" " + 3*sin(x).*cos(y).^2 + 6*sin(x).*cos(y).*tan(z) + 3*sin(x).*tan(z).^2" " + cos(y).^3 + 3*cos(y).^2.*tan(z) + 3*cos(y).*tan(z).^2 + tan(z).^3\n" " out2 = cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))))\n" " return out1, out2\n" "end\n" ) assert source == expected def test_jl_output_arg_mixed_unordered(): # named outputs are alphabetical, unnamed output appear in the given order from sympy import sin, cos a = symbols("a") name_expr = ("foo", [cos(2*x), Equality(y, sin(x)), cos(x), Equality(a, sin(2*x))]) result, = codegen(name_expr, "Julia", header=False, empty=False) assert result[0] == "foo.jl" source = result[1]; expected = ( 'function foo(x)\n' ' out1 = cos(2*x)\n' ' y = sin(x)\n' ' out3 = cos(x)\n' ' a = sin(2*x)\n' ' return out1, y, out3, a\n' 'end\n' ) assert source == expected def test_jl_piecewise_(): pw = Piecewise((0, x < -1), (x**2, x <= 1), (-x+2, x > 1), (1, True), evaluate=False) name_expr = ("pwtest", pw) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function pwtest(x)\n" " out1 = ((x < -1) ? (0) :\n" " (x <= 1) ? (x.^2) :\n" " (x > 1) ? (2 - x) : (1))\n" " return out1\n" "end\n" ) assert source == expected @XFAIL def test_jl_piecewise_no_inline(): # FIXME: how to pass inline=False to the JuliaCodePrinter? pw = Piecewise((0, x < -1), (x**2, x <= 1), (-x+2, x > 1), (1, True)) name_expr = ("pwtest", pw) result, = codegen(name_expr, "Julia", header=False, empty=False, inline=False) source = result[1] expected = ( "function pwtest(x)\n" " if (x < -1)\n" " out1 = 0\n" " elseif (x <= 1)\n" " out1 = x.^2\n" " elseif (x > 1)\n" " out1 = -x + 2\n" " else\n" " out1 = 1\n" " end\n" " return out1\n" "end\n" ) assert source == expected def test_jl_multifcns_per_file(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result = codegen(name_expr, "Julia", header=False, empty=False) assert result[0][0] == "foo.jl" source = result[0][1]; expected = ( "function foo(x, y)\n" " out1 = 2*x\n" " out2 = 3*y\n" " return out1, out2\n" "end\n" "function bar(y)\n" " out1 = y.^2\n" " out2 = 4*y\n" " return out1, out2\n" "end\n" ) assert source == expected def test_jl_multifcns_per_file_w_header(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result = codegen(name_expr, "Julia", header=True, empty=False) assert result[0][0] == "foo.jl" source = result[0][1]; expected = ( "# Code generated with sympy " + sympy.__version__ + "\n" "#\n" "# See http://www.sympy.org/ for more information.\n" "#\n" "# This file is part of 'project'\n" "function foo(x, y)\n" " out1 = 2*x\n" " out2 = 3*y\n" " return out1, out2\n" "end\n" "function bar(y)\n" " out1 = y.^2\n" " out2 = 4*y\n" " return out1, out2\n" "end\n" ) assert source == expected def test_jl_filename_match_prefix(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result, = codegen(name_expr, "Julia", prefix="baz", header=False, empty=False) assert result[0] == "baz.jl" def test_jl_matrix_named(): e2 = Matrix([[x, 2*y, pi*z]]) name_expr = ("test", Equality(MatrixSymbol('myout1', 1, 3), e2)) result = codegen(name_expr, "Julia", header=False, empty=False) assert result[0][0] == "test.jl" source = result[0][1] expected = ( "function test(x, y, z)\n" " myout1 = [x 2*y pi*z]\n" " return myout1\n" "end\n" ) assert source == expected def test_jl_matrix_named_matsym(): myout1 = MatrixSymbol('myout1', 1, 3) e2 = Matrix([[x, 2*y, pi*z]]) name_expr = ("test", Equality(myout1, e2, evaluate=False)) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x, y, z)\n" " myout1 = [x 2*y pi*z]\n" " return myout1\n" "end\n" ) assert source == expected def test_jl_matrix_output_autoname(): expr = Matrix([[x, x+y, 3]]) name_expr = ("test", expr) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x, y)\n" " out1 = [x x + y 3]\n" " return out1\n" "end\n" ) assert source == expected def test_jl_matrix_output_autoname_2(): e1 = (x + y) e2 = Matrix([[2*x, 2*y, 2*z]]) e3 = Matrix([[x], [y], [z]]) e4 = Matrix([[x, y], [z, 16]]) name_expr = ("test", (e1, e2, e3, e4)) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x, y, z)\n" " out1 = x + y\n" " out2 = [2*x 2*y 2*z]\n" " out3 = [x, y, z]\n" " out4 = [x y;\n" " z 16]\n" " return out1, out2, out3, out4\n" "end\n" ) assert source == expected def test_jl_results_matrix_named_ordered(): B, C = symbols('B,C') A = MatrixSymbol('A', 1, 3) expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, Matrix([[1, 2, x]])) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result, = codegen(name_expr, "Julia", header=False, empty=False, argument_sequence=(x, z, y)) source = result[1] expected = ( "function test(x, z, y)\n" " C = z.*(x + y)\n" " A = [1 2 x]\n" " B = 2*x\n" " return C, A, B\n" "end\n" ) assert source == expected def test_jl_matrixsymbol_slice(): A = MatrixSymbol('A', 2, 3) B = MatrixSymbol('B', 1, 3) C = MatrixSymbol('C', 1, 3) D = MatrixSymbol('D', 2, 1) name_expr = ("test", [Equality(B, A[0, :]), Equality(C, A[1, :]), Equality(D, A[:, 2])]) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(A)\n" " B = A[1,:]\n" " C = A[2,:]\n" " D = A[:,3]\n" " return B, C, D\n" "end\n" ) assert source == expected def test_jl_matrixsymbol_slice2(): A = MatrixSymbol('A', 3, 4) B = MatrixSymbol('B', 2, 2) C = MatrixSymbol('C', 2, 2) name_expr = ("test", [Equality(B, A[0:2, 0:2]), Equality(C, A[0:2, 1:3])]) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(A)\n" " B = A[1:2,1:2]\n" " C = A[1:2,2:3]\n" " return B, C\n" "end\n" ) assert source == expected def test_jl_matrixsymbol_slice3(): A = MatrixSymbol('A', 8, 7) B = MatrixSymbol('B', 2, 2) C = MatrixSymbol('C', 4, 2) name_expr = ("test", [Equality(B, A[6:, 1::3]), Equality(C, A[::2, ::3])]) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(A)\n" " B = A[7:end,2:3:end]\n" " C = A[1:2:end,1:3:end]\n" " return B, C\n" "end\n" ) assert source == expected def test_jl_matrixsymbol_slice_autoname(): A = MatrixSymbol('A', 2, 3) B = MatrixSymbol('B', 1, 3) name_expr = ("test", [Equality(B, A[0,:]), A[1,:], A[:,0], A[:,1]]) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(A)\n" " B = A[1,:]\n" " out2 = A[2,:]\n" " out3 = A[:,1]\n" " out4 = A[:,2]\n" " return B, out2, out3, out4\n" "end\n" ) assert source == expected def test_jl_loops(): # Note: an Julia programmer would probably vectorize this across one or # more dimensions. Also, size(A) would be used rather than passing in m # and n. Perhaps users would expect us to vectorize automatically here? # Or is it possible to represent such things using IndexedBase? from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) result, = codegen(('mat_vec_mult', Eq(y[i], A[i, j]*x[j])), "Julia", header=False, empty=False) source = result[1] expected = ( 'function mat_vec_mult(y, A, m, n, x)\n' ' for i = 1:m\n' ' y[i] = 0\n' ' end\n' ' for i = 1:m\n' ' for j = 1:n\n' ' y[i] = %(rhs)s + y[i]\n' ' end\n' ' end\n' ' return y\n' 'end\n' ) assert (source == expected % {'rhs': 'A[%s,%s].*x[j]' % (i, j)} or source == expected % {'rhs': 'x[j].*A[%s,%s]' % (i, j)}) def test_jl_tensor_loops_multiple_contractions(): # see comments in previous test about vectorizing from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o, p = symbols('n m o p', integer=True) A = IndexedBase('A') B = IndexedBase('B') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) k = Idx('k', o) l = Idx('l', p) result, = codegen(('tensorthing', Eq(y[i], B[j, k, l]*A[i, j, k, l])), "Julia", header=False, empty=False) source = result[1] expected = ( 'function tensorthing(y, A, B, m, n, o, p)\n' ' for i = 1:m\n' ' y[i] = 0\n' ' end\n' ' for i = 1:m\n' ' for j = 1:n\n' ' for k = 1:o\n' ' for l = 1:p\n' ' y[i] = A[i,j,k,l].*B[j,k,l] + y[i]\n' ' end\n' ' end\n' ' end\n' ' end\n' ' return y\n' 'end\n' ) assert source == expected def test_jl_InOutArgument(): expr = Equality(x, x**2) name_expr = ("mysqr", expr) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function mysqr(x)\n" " x = x.^2\n" " return x\n" "end\n" ) assert source == expected def test_jl_InOutArgument_order(): # can specify the order as (x, y) expr = Equality(x, x**2 + y) name_expr = ("test", expr) result, = codegen(name_expr, "Julia", header=False, empty=False, argument_sequence=(x,y)) source = result[1] expected = ( "function test(x, y)\n" " x = x.^2 + y\n" " return x\n" "end\n" ) assert source == expected # make sure it gives (x, y) not (y, x) expr = Equality(x, x**2 + y) name_expr = ("test", expr) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x, y)\n" " x = x.^2 + y\n" " return x\n" "end\n" ) assert source == expected def test_jl_not_supported(): f = Function('f') name_expr = ("test", [f(x).diff(x), S.ComplexInfinity]) result, = codegen(name_expr, "Julia", header=False, empty=False) source = result[1] expected = ( "function test(x)\n" " # unsupported: Derivative(f(x), x)\n" " # unsupported: zoo\n" " out1 = Derivative(f(x), x)\n" " out2 = zoo\n" " return out1, out2\n" "end\n" ) assert source == expected def test_global_vars_octave(): x, y, z, t = symbols("x y z t") result = codegen(('f', x*y), "Julia", header=False, empty=False, global_vars=(y,)) source = result[0][1] expected = ( "function f(x)\n" " out1 = x.*y\n" " return out1\n" "end\n" ) assert source == expected result = codegen(('f', x*y+z), "Julia", header=False, empty=False, argument_sequence=(x, y), global_vars=(z, t)) source = result[0][1] expected = ( "function f(x, y)\n" " out1 = x.*y + z\n" " return out1\n" "end\n" ) assert source == expected sympy-sympy-1.9/sympy/utilities/tests/test_codegen_octave.py000066400000000000000000000424301412543434000246420ustar00rootroot00000000000000from io import StringIO from sympy.core import S, symbols, Eq, pi, Catalan, EulerGamma, Function from sympy import Piecewise from sympy import Equality from sympy.matrices import Matrix, MatrixSymbol from sympy.utilities.codegen import OctaveCodeGen, codegen, make_routine from sympy.testing.pytest import raises from sympy.testing.pytest import XFAIL import sympy x, y, z = symbols('x,y,z') def test_empty_m_code(): code_gen = OctaveCodeGen() output = StringIO() code_gen.dump_m([], output, "file", header=False, empty=False) source = output.getvalue() assert source == "" def test_m_simple_code(): name_expr = ("test", (x + y)*z) result, = codegen(name_expr, "Octave", header=False, empty=False) assert result[0] == "test.m" source = result[1] expected = ( "function out1 = test(x, y, z)\n" " out1 = z.*(x + y);\n" "end\n" ) assert source == expected def test_m_simple_code_with_header(): name_expr = ("test", (x + y)*z) result, = codegen(name_expr, "Octave", header=True, empty=False) assert result[0] == "test.m" source = result[1] expected = ( "function out1 = test(x, y, z)\n" " %TEST Autogenerated by sympy\n" " % Code generated with sympy " + sympy.__version__ + "\n" " %\n" " % See http://www.sympy.org/ for more information.\n" " %\n" " % This file is part of 'project'\n" " out1 = z.*(x + y);\n" "end\n" ) assert source == expected def test_m_simple_code_nameout(): expr = Equality(z, (x + y)) name_expr = ("test", expr) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function z = test(x, y)\n" " z = x + y;\n" "end\n" ) assert source == expected def test_m_numbersymbol(): name_expr = ("test", pi**Catalan) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function out1 = test()\n" " out1 = pi^%s;\n" "end\n" ) % Catalan.evalf(17) assert source == expected @XFAIL def test_m_numbersymbol_no_inline(): # FIXME: how to pass inline=False to the OctaveCodePrinter? name_expr = ("test", [pi**Catalan, EulerGamma]) result, = codegen(name_expr, "Octave", header=False, empty=False, inline=False) source = result[1] expected = ( "function [out1, out2] = test()\n" " Catalan = 0.915965594177219; % constant\n" " EulerGamma = 0.5772156649015329; % constant\n" " out1 = pi^Catalan;\n" " out2 = EulerGamma;\n" "end\n" ) assert source == expected def test_m_code_argument_order(): expr = x + y routine = make_routine("test", expr, argument_sequence=[z, x, y], language="octave") code_gen = OctaveCodeGen() output = StringIO() code_gen.dump_m([routine], output, "test", header=False, empty=False) source = output.getvalue() expected = ( "function out1 = test(z, x, y)\n" " out1 = x + y;\n" "end\n" ) assert source == expected def test_multiple_results_m(): # Here the output order is the input order expr1 = (x + y)*z expr2 = (x - y)*z name_expr = ("test", [expr1, expr2]) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [out1, out2] = test(x, y, z)\n" " out1 = z.*(x + y);\n" " out2 = z.*(x - y);\n" "end\n" ) assert source == expected def test_results_named_unordered(): # Here output order is based on name_expr A, B, C = symbols('A,B,C') expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, (x - y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [C, A, B] = test(x, y, z)\n" " C = z.*(x + y);\n" " A = z.*(x - y);\n" " B = 2*x;\n" "end\n" ) assert source == expected def test_results_named_ordered(): A, B, C = symbols('A,B,C') expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, (x - y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result = codegen(name_expr, "Octave", header=False, empty=False, argument_sequence=(x, z, y)) assert result[0][0] == "test.m" source = result[0][1] expected = ( "function [C, A, B] = test(x, z, y)\n" " C = z.*(x + y);\n" " A = z.*(x - y);\n" " B = 2*x;\n" "end\n" ) assert source == expected def test_complicated_m_codegen(): from sympy import sin, cos, tan name_expr = ("testlong", [ ((sin(x) + cos(y) + tan(z))**3).expand(), cos(cos(cos(cos(cos(cos(cos(cos(x + y + z)))))))) ]) result = codegen(name_expr, "Octave", header=False, empty=False) assert result[0][0] == "testlong.m" source = result[0][1] expected = ( "function [out1, out2] = testlong(x, y, z)\n" " out1 = sin(x).^3 + 3*sin(x).^2.*cos(y) + 3*sin(x).^2.*tan(z)" " + 3*sin(x).*cos(y).^2 + 6*sin(x).*cos(y).*tan(z) + 3*sin(x).*tan(z).^2" " + cos(y).^3 + 3*cos(y).^2.*tan(z) + 3*cos(y).*tan(z).^2 + tan(z).^3;\n" " out2 = cos(cos(cos(cos(cos(cos(cos(cos(x + y + z))))))));\n" "end\n" ) assert source == expected def test_m_output_arg_mixed_unordered(): # named outputs are alphabetical, unnamed output appear in the given order from sympy import sin, cos a = symbols("a") name_expr = ("foo", [cos(2*x), Equality(y, sin(x)), cos(x), Equality(a, sin(2*x))]) result, = codegen(name_expr, "Octave", header=False, empty=False) assert result[0] == "foo.m" source = result[1]; expected = ( 'function [out1, y, out3, a] = foo(x)\n' ' out1 = cos(2*x);\n' ' y = sin(x);\n' ' out3 = cos(x);\n' ' a = sin(2*x);\n' 'end\n' ) assert source == expected def test_m_piecewise_(): pw = Piecewise((0, x < -1), (x**2, x <= 1), (-x+2, x > 1), (1, True), evaluate=False) name_expr = ("pwtest", pw) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function out1 = pwtest(x)\n" " out1 = ((x < -1).*(0) + (~(x < -1)).*( ...\n" " (x <= 1).*(x.^2) + (~(x <= 1)).*( ...\n" " (x > 1).*(2 - x) + (~(x > 1)).*(1))));\n" "end\n" ) assert source == expected @XFAIL def test_m_piecewise_no_inline(): # FIXME: how to pass inline=False to the OctaveCodePrinter? pw = Piecewise((0, x < -1), (x**2, x <= 1), (-x+2, x > 1), (1, True)) name_expr = ("pwtest", pw) result, = codegen(name_expr, "Octave", header=False, empty=False, inline=False) source = result[1] expected = ( "function out1 = pwtest(x)\n" " if (x < -1)\n" " out1 = 0;\n" " elseif (x <= 1)\n" " out1 = x.^2;\n" " elseif (x > 1)\n" " out1 = -x + 2;\n" " else\n" " out1 = 1;\n" " end\n" "end\n" ) assert source == expected def test_m_multifcns_per_file(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result = codegen(name_expr, "Octave", header=False, empty=False) assert result[0][0] == "foo.m" source = result[0][1]; expected = ( "function [out1, out2] = foo(x, y)\n" " out1 = 2*x;\n" " out2 = 3*y;\n" "end\n" "function [out1, out2] = bar(y)\n" " out1 = y.^2;\n" " out2 = 4*y;\n" "end\n" ) assert source == expected def test_m_multifcns_per_file_w_header(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result = codegen(name_expr, "Octave", header=True, empty=False) assert result[0][0] == "foo.m" source = result[0][1]; expected = ( "function [out1, out2] = foo(x, y)\n" " %FOO Autogenerated by sympy\n" " % Code generated with sympy " + sympy.__version__ + "\n" " %\n" " % See http://www.sympy.org/ for more information.\n" " %\n" " % This file is part of 'project'\n" " out1 = 2*x;\n" " out2 = 3*y;\n" "end\n" "function [out1, out2] = bar(y)\n" " out1 = y.^2;\n" " out2 = 4*y;\n" "end\n" ) assert source == expected def test_m_filename_match_first_fcn(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] raises(ValueError, lambda: codegen(name_expr, "Octave", prefix="bar", header=False, empty=False)) def test_m_matrix_named(): e2 = Matrix([[x, 2*y, pi*z]]) name_expr = ("test", Equality(MatrixSymbol('myout1', 1, 3), e2)) result = codegen(name_expr, "Octave", header=False, empty=False) assert result[0][0] == "test.m" source = result[0][1] expected = ( "function myout1 = test(x, y, z)\n" " myout1 = [x 2*y pi*z];\n" "end\n" ) assert source == expected def test_m_matrix_named_matsym(): myout1 = MatrixSymbol('myout1', 1, 3) e2 = Matrix([[x, 2*y, pi*z]]) name_expr = ("test", Equality(myout1, e2, evaluate=False)) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function myout1 = test(x, y, z)\n" " myout1 = [x 2*y pi*z];\n" "end\n" ) assert source == expected def test_m_matrix_output_autoname(): expr = Matrix([[x, x+y, 3]]) name_expr = ("test", expr) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function out1 = test(x, y)\n" " out1 = [x x + y 3];\n" "end\n" ) assert source == expected def test_m_matrix_output_autoname_2(): e1 = (x + y) e2 = Matrix([[2*x, 2*y, 2*z]]) e3 = Matrix([[x], [y], [z]]) e4 = Matrix([[x, y], [z, 16]]) name_expr = ("test", (e1, e2, e3, e4)) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [out1, out2, out3, out4] = test(x, y, z)\n" " out1 = x + y;\n" " out2 = [2*x 2*y 2*z];\n" " out3 = [x; y; z];\n" " out4 = [x y; z 16];\n" "end\n" ) assert source == expected def test_m_results_matrix_named_ordered(): B, C = symbols('B,C') A = MatrixSymbol('A', 1, 3) expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, Matrix([[1, 2, x]])) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result, = codegen(name_expr, "Octave", header=False, empty=False, argument_sequence=(x, z, y)) source = result[1] expected = ( "function [C, A, B] = test(x, z, y)\n" " C = z.*(x + y);\n" " A = [1 2 x];\n" " B = 2*x;\n" "end\n" ) assert source == expected def test_m_matrixsymbol_slice(): A = MatrixSymbol('A', 2, 3) B = MatrixSymbol('B', 1, 3) C = MatrixSymbol('C', 1, 3) D = MatrixSymbol('D', 2, 1) name_expr = ("test", [Equality(B, A[0, :]), Equality(C, A[1, :]), Equality(D, A[:, 2])]) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [B, C, D] = test(A)\n" " B = A(1, :);\n" " C = A(2, :);\n" " D = A(:, 3);\n" "end\n" ) assert source == expected def test_m_matrixsymbol_slice2(): A = MatrixSymbol('A', 3, 4) B = MatrixSymbol('B', 2, 2) C = MatrixSymbol('C', 2, 2) name_expr = ("test", [Equality(B, A[0:2, 0:2]), Equality(C, A[0:2, 1:3])]) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [B, C] = test(A)\n" " B = A(1:2, 1:2);\n" " C = A(1:2, 2:3);\n" "end\n" ) assert source == expected def test_m_matrixsymbol_slice3(): A = MatrixSymbol('A', 8, 7) B = MatrixSymbol('B', 2, 2) C = MatrixSymbol('C', 4, 2) name_expr = ("test", [Equality(B, A[6:, 1::3]), Equality(C, A[::2, ::3])]) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [B, C] = test(A)\n" " B = A(7:end, 2:3:end);\n" " C = A(1:2:end, 1:3:end);\n" "end\n" ) assert source == expected def test_m_matrixsymbol_slice_autoname(): A = MatrixSymbol('A', 2, 3) B = MatrixSymbol('B', 1, 3) name_expr = ("test", [Equality(B, A[0,:]), A[1,:], A[:,0], A[:,1]]) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [B, out2, out3, out4] = test(A)\n" " B = A(1, :);\n" " out2 = A(2, :);\n" " out3 = A(:, 1);\n" " out4 = A(:, 2);\n" "end\n" ) assert source == expected def test_m_loops(): # Note: an Octave programmer would probably vectorize this across one or # more dimensions. Also, size(A) would be used rather than passing in m # and n. Perhaps users would expect us to vectorize automatically here? # Or is it possible to represent such things using IndexedBase? from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m = symbols('n m', integer=True) A = IndexedBase('A') x = IndexedBase('x') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) result, = codegen(('mat_vec_mult', Eq(y[i], A[i, j]*x[j])), "Octave", header=False, empty=False) source = result[1] expected = ( 'function y = mat_vec_mult(A, m, n, x)\n' ' for i = 1:m\n' ' y(i) = 0;\n' ' end\n' ' for i = 1:m\n' ' for j = 1:n\n' ' y(i) = %(rhs)s + y(i);\n' ' end\n' ' end\n' 'end\n' ) assert (source == expected % {'rhs': 'A(%s, %s).*x(j)' % (i, j)} or source == expected % {'rhs': 'x(j).*A(%s, %s)' % (i, j)}) def test_m_tensor_loops_multiple_contractions(): # see comments in previous test about vectorizing from sympy.tensor import IndexedBase, Idx from sympy import symbols n, m, o, p = symbols('n m o p', integer=True) A = IndexedBase('A') B = IndexedBase('B') y = IndexedBase('y') i = Idx('i', m) j = Idx('j', n) k = Idx('k', o) l = Idx('l', p) result, = codegen(('tensorthing', Eq(y[i], B[j, k, l]*A[i, j, k, l])), "Octave", header=False, empty=False) source = result[1] expected = ( 'function y = tensorthing(A, B, m, n, o, p)\n' ' for i = 1:m\n' ' y(i) = 0;\n' ' end\n' ' for i = 1:m\n' ' for j = 1:n\n' ' for k = 1:o\n' ' for l = 1:p\n' ' y(i) = A(i, j, k, l).*B(j, k, l) + y(i);\n' ' end\n' ' end\n' ' end\n' ' end\n' 'end\n' ) assert source == expected def test_m_InOutArgument(): expr = Equality(x, x**2) name_expr = ("mysqr", expr) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function x = mysqr(x)\n" " x = x.^2;\n" "end\n" ) assert source == expected def test_m_InOutArgument_order(): # can specify the order as (x, y) expr = Equality(x, x**2 + y) name_expr = ("test", expr) result, = codegen(name_expr, "Octave", header=False, empty=False, argument_sequence=(x,y)) source = result[1] expected = ( "function x = test(x, y)\n" " x = x.^2 + y;\n" "end\n" ) assert source == expected # make sure it gives (x, y) not (y, x) expr = Equality(x, x**2 + y) name_expr = ("test", expr) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function x = test(x, y)\n" " x = x.^2 + y;\n" "end\n" ) assert source == expected def test_m_not_supported(): f = Function('f') name_expr = ("test", [f(x).diff(x), S.ComplexInfinity]) result, = codegen(name_expr, "Octave", header=False, empty=False) source = result[1] expected = ( "function [out1, out2] = test(x)\n" " % unsupported: Derivative(f(x), x)\n" " % unsupported: zoo\n" " out1 = Derivative(f(x), x);\n" " out2 = zoo;\n" "end\n" ) assert source == expected def test_global_vars_octave(): x, y, z, t = symbols("x y z t") result = codegen(('f', x*y), "Octave", header=False, empty=False, global_vars=(y,)) source = result[0][1] expected = ( "function out1 = f(x)\n" " global y\n" " out1 = x.*y;\n" "end\n" ) assert source == expected result = codegen(('f', x*y+z), "Octave", header=False, empty=False, argument_sequence=(x, y), global_vars=(z, t)) source = result[0][1] expected = ( "function out1 = f(x, y)\n" " global t z\n" " out1 = x.*y + z;\n" "end\n" ) assert source == expected sympy-sympy-1.9/sympy/utilities/tests/test_codegen_rust.py000066400000000000000000000276521412543434000243670ustar00rootroot00000000000000from io import StringIO from sympy.core import S, symbols, pi, Catalan, EulerGamma, Function from sympy import Piecewise from sympy import Equality from sympy.utilities.codegen import RustCodeGen, codegen, make_routine from sympy.testing.pytest import XFAIL import sympy x, y, z = symbols('x,y,z') def test_empty_rust_code(): code_gen = RustCodeGen() output = StringIO() code_gen.dump_rs([], output, "file", header=False, empty=False) source = output.getvalue() assert source == "" def test_simple_rust_code(): name_expr = ("test", (x + y)*z) result, = codegen(name_expr, "Rust", header=False, empty=False) assert result[0] == "test.rs" source = result[1] expected = ( "fn test(x: f64, y: f64, z: f64) -> f64 {\n" " let out1 = z*(x + y);\n" " out1\n" "}\n" ) assert source == expected def test_simple_code_with_header(): name_expr = ("test", (x + y)*z) result, = codegen(name_expr, "Rust", header=True, empty=False) assert result[0] == "test.rs" source = result[1] version_str = "Code generated with sympy %s" % sympy.__version__ version_line = version_str.center(76).rstrip() expected = ( "/*\n" " *%(version_line)s\n" " *\n" " * See http://www.sympy.org/ for more information.\n" " *\n" " * This file is part of 'project'\n" " */\n" "fn test(x: f64, y: f64, z: f64) -> f64 {\n" " let out1 = z*(x + y);\n" " out1\n" "}\n" ) % {'version_line': version_line} assert source == expected def test_simple_code_nameout(): expr = Equality(z, (x + y)) name_expr = ("test", expr) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn test(x: f64, y: f64) -> f64 {\n" " let z = x + y;\n" " z\n" "}\n" ) assert source == expected def test_numbersymbol(): name_expr = ("test", pi**Catalan) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn test() -> f64 {\n" " const Catalan: f64 = %s;\n" " let out1 = PI.powf(Catalan);\n" " out1\n" "}\n" ) % Catalan.evalf(17) assert source == expected @XFAIL def test_numbersymbol_inline(): # FIXME: how to pass inline to the RustCodePrinter? name_expr = ("test", [pi**Catalan, EulerGamma]) result, = codegen(name_expr, "Rust", header=False, empty=False, inline=True) source = result[1] expected = ( "fn test() -> (f64, f64) {\n" " const Catalan: f64 = %s;\n" " const EulerGamma: f64 = %s;\n" " let out1 = PI.powf(Catalan);\n" " let out2 = EulerGamma);\n" " (out1, out2)\n" "}\n" ) % (Catalan.evalf(17), EulerGamma.evalf(17)) assert source == expected def test_argument_order(): expr = x + y routine = make_routine("test", expr, argument_sequence=[z, x, y], language="rust") code_gen = RustCodeGen() output = StringIO() code_gen.dump_rs([routine], output, "test", header=False, empty=False) source = output.getvalue() expected = ( "fn test(z: f64, x: f64, y: f64) -> f64 {\n" " let out1 = x + y;\n" " out1\n" "}\n" ) assert source == expected def test_multiple_results_rust(): # Here the output order is the input order expr1 = (x + y)*z expr2 = (x - y)*z name_expr = ("test", [expr1, expr2]) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn test(x: f64, y: f64, z: f64) -> (f64, f64) {\n" " let out1 = z*(x + y);\n" " let out2 = z*(x - y);\n" " (out1, out2)\n" "}\n" ) assert source == expected def test_results_named_unordered(): # Here output order is based on name_expr A, B, C = symbols('A,B,C') expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, (x - y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn test(x: f64, y: f64, z: f64) -> (f64, f64, f64) {\n" " let C = z*(x + y);\n" " let A = z*(x - y);\n" " let B = 2*x;\n" " (C, A, B)\n" "}\n" ) assert source == expected def test_results_named_ordered(): A, B, C = symbols('A,B,C') expr1 = Equality(C, (x + y)*z) expr2 = Equality(A, (x - y)*z) expr3 = Equality(B, 2*x) name_expr = ("test", [expr1, expr2, expr3]) result = codegen(name_expr, "Rust", header=False, empty=False, argument_sequence=(x, z, y)) assert result[0][0] == "test.rs" source = result[0][1] expected = ( "fn test(x: f64, z: f64, y: f64) -> (f64, f64, f64) {\n" " let C = z*(x + y);\n" " let A = z*(x - y);\n" " let B = 2*x;\n" " (C, A, B)\n" "}\n" ) assert source == expected def test_complicated_rs_codegen(): from sympy import sin, cos, tan name_expr = ("testlong", [ ((sin(x) + cos(y) + tan(z))**3).expand(), cos(cos(cos(cos(cos(cos(cos(cos(x + y + z)))))))) ]) result = codegen(name_expr, "Rust", header=False, empty=False) assert result[0][0] == "testlong.rs" source = result[0][1] expected = ( "fn testlong(x: f64, y: f64, z: f64) -> (f64, f64) {\n" " let out1 = x.sin().powi(3) + 3*x.sin().powi(2)*y.cos()" " + 3*x.sin().powi(2)*z.tan() + 3*x.sin()*y.cos().powi(2)" " + 6*x.sin()*y.cos()*z.tan() + 3*x.sin()*z.tan().powi(2)" " + y.cos().powi(3) + 3*y.cos().powi(2)*z.tan()" " + 3*y.cos()*z.tan().powi(2) + z.tan().powi(3);\n" " let out2 = (x + y + z).cos().cos().cos().cos()" ".cos().cos().cos().cos();\n" " (out1, out2)\n" "}\n" ) assert source == expected def test_output_arg_mixed_unordered(): # named outputs are alphabetical, unnamed output appear in the given order from sympy import sin, cos a = symbols("a") name_expr = ("foo", [cos(2*x), Equality(y, sin(x)), cos(x), Equality(a, sin(2*x))]) result, = codegen(name_expr, "Rust", header=False, empty=False) assert result[0] == "foo.rs" source = result[1]; expected = ( "fn foo(x: f64) -> (f64, f64, f64, f64) {\n" " let out1 = (2*x).cos();\n" " let y = x.sin();\n" " let out3 = x.cos();\n" " let a = (2*x).sin();\n" " (out1, y, out3, a)\n" "}\n" ) assert source == expected def test_piecewise_(): pw = Piecewise((0, x < -1), (x**2, x <= 1), (-x+2, x > 1), (1, True), evaluate=False) name_expr = ("pwtest", pw) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn pwtest(x: f64) -> f64 {\n" " let out1 = if (x < -1) {\n" " 0\n" " } else if (x <= 1) {\n" " x.powi(2)\n" " } else if (x > 1) {\n" " 2 - x\n" " } else {\n" " 1\n" " };\n" " out1\n" "}\n" ) assert source == expected @XFAIL def test_piecewise_inline(): # FIXME: how to pass inline to the RustCodePrinter? pw = Piecewise((0, x < -1), (x**2, x <= 1), (-x+2, x > 1), (1, True)) name_expr = ("pwtest", pw) result, = codegen(name_expr, "Rust", header=False, empty=False, inline=True) source = result[1] expected = ( "fn pwtest(x: f64) -> f64 {\n" " let out1 = if (x < -1) { 0 } else if (x <= 1) { x.powi(2) }" " else if (x > 1) { -x + 2 } else { 1 };\n" " out1\n" "}\n" ) assert source == expected def test_multifcns_per_file(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result = codegen(name_expr, "Rust", header=False, empty=False) assert result[0][0] == "foo.rs" source = result[0][1]; expected = ( "fn foo(x: f64, y: f64) -> (f64, f64) {\n" " let out1 = 2*x;\n" " let out2 = 3*y;\n" " (out1, out2)\n" "}\n" "fn bar(y: f64) -> (f64, f64) {\n" " let out1 = y.powi(2);\n" " let out2 = 4*y;\n" " (out1, out2)\n" "}\n" ) assert source == expected def test_multifcns_per_file_w_header(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result = codegen(name_expr, "Rust", header=True, empty=False) assert result[0][0] == "foo.rs" source = result[0][1]; version_str = "Code generated with sympy %s" % sympy.__version__ version_line = version_str.center(76).rstrip() expected = ( "/*\n" " *%(version_line)s\n" " *\n" " * See http://www.sympy.org/ for more information.\n" " *\n" " * This file is part of 'project'\n" " */\n" "fn foo(x: f64, y: f64) -> (f64, f64) {\n" " let out1 = 2*x;\n" " let out2 = 3*y;\n" " (out1, out2)\n" "}\n" "fn bar(y: f64) -> (f64, f64) {\n" " let out1 = y.powi(2);\n" " let out2 = 4*y;\n" " (out1, out2)\n" "}\n" ) % {'version_line': version_line} assert source == expected def test_filename_match_prefix(): name_expr = [ ("foo", [2*x, 3*y]), ("bar", [y**2, 4*y]) ] result, = codegen(name_expr, "Rust", prefix="baz", header=False, empty=False) assert result[0] == "baz.rs" def test_InOutArgument(): expr = Equality(x, x**2) name_expr = ("mysqr", expr) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn mysqr(x: f64) -> f64 {\n" " let x = x.powi(2);\n" " x\n" "}\n" ) assert source == expected def test_InOutArgument_order(): # can specify the order as (x, y) expr = Equality(x, x**2 + y) name_expr = ("test", expr) result, = codegen(name_expr, "Rust", header=False, empty=False, argument_sequence=(x,y)) source = result[1] expected = ( "fn test(x: f64, y: f64) -> f64 {\n" " let x = x.powi(2) + y;\n" " x\n" "}\n" ) assert source == expected # make sure it gives (x, y) not (y, x) expr = Equality(x, x**2 + y) name_expr = ("test", expr) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn test(x: f64, y: f64) -> f64 {\n" " let x = x.powi(2) + y;\n" " x\n" "}\n" ) assert source == expected def test_not_supported(): f = Function('f') name_expr = ("test", [f(x).diff(x), S.ComplexInfinity]) result, = codegen(name_expr, "Rust", header=False, empty=False) source = result[1] expected = ( "fn test(x: f64) -> (f64, f64) {\n" " // unsupported: Derivative(f(x), x)\n" " // unsupported: zoo\n" " let out1 = Derivative(f(x), x);\n" " let out2 = zoo;\n" " (out1, out2)\n" "}\n" ) assert source == expected def test_global_vars_rust(): x, y, z, t = symbols("x y z t") result = codegen(('f', x*y), "Rust", header=False, empty=False, global_vars=(y,)) source = result[0][1] expected = ( "fn f(x: f64) -> f64 {\n" " let out1 = x*y;\n" " out1\n" "}\n" ) assert source == expected result = codegen(('f', x*y+z), "Rust", header=False, empty=False, argument_sequence=(x, y), global_vars=(z, t)) source = result[0][1] expected = ( "fn f(x: f64, y: f64) -> f64 {\n" " let out1 = x*y + z;\n" " out1\n" "}\n" ) assert source == expected sympy-sympy-1.9/sympy/utilities/tests/test_decorator.py000066400000000000000000000027401412543434000236570ustar00rootroot00000000000000from sympy.utilities.decorator import threaded, xthreaded, memoize_property from sympy import Eq, Matrix, Basic from sympy.abc import x, y from sympy.core.decorators import wraps def test_threaded(): @threaded def function(expr, *args): return 2*expr + sum(args) assert function(Matrix([[x, y], [1, x]]), 1, 2) == \ Matrix([[2*x + 3, 2*y + 3], [5, 2*x + 3]]) assert function(Eq(x, y), 1, 2) == Eq(2*x + 3, 2*y + 3) assert function([x, y], 1, 2) == [2*x + 3, 2*y + 3] assert function((x, y), 1, 2) == (2*x + 3, 2*y + 3) assert function({x, y}, 1, 2) == {2*x + 3, 2*y + 3} @threaded def function(expr, n): return expr**n assert function(x + y, 2) == x**2 + y**2 assert function(x, 2) == x**2 def test_xthreaded(): @xthreaded def function(expr, n): return expr**n assert function(x + y, 2) == (x + y)**2 def test_wraps(): def my_func(x): """My function. """ my_func.is_my_func = True new_my_func = threaded(my_func) new_my_func = wraps(my_func)(new_my_func) assert new_my_func.__name__ == 'my_func' assert new_my_func.__doc__ == 'My function. ' assert hasattr(new_my_func, 'is_my_func') assert new_my_func.is_my_func is True def test_memoize_property(): class TestMemoize(Basic): @memoize_property def prop(self): return Basic() member = TestMemoize() obj1 = member.prop obj2 = member.prop assert obj1 is obj2 sympy-sympy-1.9/sympy/utilities/tests/test_deprecated.py000066400000000000000000000014151412543434000237730ustar00rootroot00000000000000from sympy.testing.pytest import warns_deprecated_sympy, XFAIL # See https://github.com/sympy/sympy/pull/18095 def test_deprecated_utilities(): with warns_deprecated_sympy(): import sympy.utilities.pytest # noqa:F401 with warns_deprecated_sympy(): import sympy.utilities.runtests # noqa:F401 with warns_deprecated_sympy(): import sympy.utilities.randtest # noqa:F401 with warns_deprecated_sympy(): import sympy.utilities.tmpfiles # noqa:F401 with warns_deprecated_sympy(): import sympy.utilities.quality_unicode # noqa:F401 # This fails because benchmarking isn't importable... @XFAIL def test_deprecated_benchmarking(): with warns_deprecated_sympy(): import sympy.utilities.benchmarking # noqa:F401 sympy-sympy-1.9/sympy/utilities/tests/test_enumerative.py000066400000000000000000000137111412543434000242210ustar00rootroot00000000000000from itertools import zip_longest from sympy.utilities.enumerative import ( list_visitor, MultisetPartitionTraverser, multiset_partitions_taocp ) from sympy.utilities.iterables import _set_partitions # first some functions only useful as test scaffolding - these provide # straightforward, but slow reference implementations against which to # compare the real versions, and also a comparison to verify that # different versions are giving identical results. def part_range_filter(partition_iterator, lb, ub): """ Filters (on the number of parts) a multiset partition enumeration Arguments ========= lb, and ub are a range (in the python slice sense) on the lpart variable returned from a multiset partition enumeration. Recall that lpart is 0-based (it points to the topmost part on the part stack), so if you want to return parts of sizes 2,3,4,5 you would use lb=1 and ub=5. """ for state in partition_iterator: f, lpart, pstack = state if lpart >= lb and lpart < ub: yield state def multiset_partitions_baseline(multiplicities, components): """Enumerates partitions of a multiset Parameters ========== multiplicities list of integer multiplicities of the components of the multiset. components the components (elements) themselves Returns ======= Set of partitions. Each partition is tuple of parts, and each part is a tuple of components (with repeats to indicate multiplicity) Notes ===== Multiset partitions can be created as equivalence classes of set partitions, and this function does just that. This approach is slow and memory intensive compared to the more advanced algorithms available, but the code is simple and easy to understand. Hence this routine is strictly for testing -- to provide a straightforward baseline against which to regress the production versions. (This code is a simplified version of an earlier production implementation.) """ canon = [] # list of components with repeats for ct, elem in zip(multiplicities, components): canon.extend([elem]*ct) # accumulate the multiset partitions in a set to eliminate dups cache = set() n = len(canon) for nc, q in _set_partitions(n): rv = [[] for i in range(nc)] for i in range(n): rv[q[i]].append(canon[i]) canonical = tuple( sorted([tuple(p) for p in rv])) cache.add(canonical) return cache def compare_multiset_w_baseline(multiplicities): """ Enumerates the partitions of multiset with AOCP algorithm and baseline implementation, and compare the results. """ letters = "abcdefghijklmnopqrstuvwxyz" bl_partitions = multiset_partitions_baseline(multiplicities, letters) # The partitions returned by the different algorithms may have # their parts in different orders. Also, they generate partitions # in different orders. Hence the sorting, and set comparison. aocp_partitions = set() for state in multiset_partitions_taocp(multiplicities): p1 = tuple(sorted( [tuple(p) for p in list_visitor(state, letters)])) aocp_partitions.add(p1) assert bl_partitions == aocp_partitions def compare_multiset_states(s1, s2): """compare for equality two instances of multiset partition states This is useful for comparing different versions of the algorithm to verify correctness.""" # Comparison is physical, the only use of semantics is to ignore # trash off the top of the stack. f1, lpart1, pstack1 = s1 f2, lpart2, pstack2 = s2 if (lpart1 == lpart2) and (f1[0:lpart1+1] == f2[0:lpart2+1]): if pstack1[0:f1[lpart1+1]] == pstack2[0:f2[lpart2+1]]: return True return False def test_multiset_partitions_taocp(): """Compares the output of multiset_partitions_taocp with a baseline (set partition based) implementation.""" # Test cases should not be too large, since the baseline # implementation is fairly slow. multiplicities = [2,2] compare_multiset_w_baseline(multiplicities) multiplicities = [4,3,1] compare_multiset_w_baseline(multiplicities) def test_multiset_partitions_versions(): """Compares Knuth-based versions of multiset_partitions""" multiplicities = [5,2,2,1] m = MultisetPartitionTraverser() for s1, s2 in zip_longest(m.enum_all(multiplicities), multiset_partitions_taocp(multiplicities)): assert compare_multiset_states(s1, s2) def subrange_exercise(mult, lb, ub): """Compare filter-based and more optimized subrange implementations Helper for tests, called with both small and larger multisets. """ m = MultisetPartitionTraverser() assert m.count_partitions(mult) == \ m.count_partitions_slow(mult) # Note - multiple traversals from the same # MultisetPartitionTraverser object cannot execute at the same # time, hence make several instances here. ma = MultisetPartitionTraverser() mc = MultisetPartitionTraverser() md = MultisetPartitionTraverser() # Several paths to compute just the size two partitions a_it = ma.enum_range(mult, lb, ub) b_it = part_range_filter(multiset_partitions_taocp(mult), lb, ub) c_it = part_range_filter(mc.enum_small(mult, ub), lb, sum(mult)) d_it = part_range_filter(md.enum_large(mult, lb), 0, ub) for sa, sb, sc, sd in zip_longest(a_it, b_it, c_it, d_it): assert compare_multiset_states(sa, sb) assert compare_multiset_states(sa, sc) assert compare_multiset_states(sa, sd) def test_subrange(): # Quick, but doesn't hit some of the corner cases mult = [4,4,2,1] # mississippi lb = 1 ub = 2 subrange_exercise(mult, lb, ub) def test_subrange_large(): # takes a second or so, depending on cpu, Python version, etc. mult = [6,3,2,1] lb = 4 ub = 7 subrange_exercise(mult, lb, ub) sympy-sympy-1.9/sympy/utilities/tests/test_iterables.py000066400000000000000000000755111412543434000236550ustar00rootroot00000000000000from textwrap import dedent from itertools import islice, product from sympy import ( symbols, Integer, Integral, Tuple, Dummy, Basic, default_sort_key, Matrix, factorial, true) from sympy.combinatorics import RGS_enum, RGS_unrank, Permutation from sympy.core.compatibility import iterable from sympy.utilities.iterables import ( _partition, _set_partitions, binary_partitions, bracelets, capture, cartes, common_prefix, common_suffix, connected_components, dict_merge, filter_symbols, flatten, generate_bell, generate_derangements, generate_involutions, generate_oriented_forest, group, has_dups, ibin, iproduct, kbins, minlex, multiset, multiset_combinations, multiset_partitions, multiset_permutations, necklaces, numbered_symbols, ordered, partitions, permutations, postfixes, postorder_traversal, prefixes, reshape, rotate_left, rotate_right, runs, sift, strongly_connected_components, subsets, take, topological_sort, unflatten, uniq, variations, ordered_partitions, rotations, is_palindromic) from sympy.utilities.enumerative import ( factoring_visitor, multiset_partitions_taocp ) from sympy.core.singleton import S from sympy.functions.elementary.piecewise import Piecewise, ExprCondPair from sympy.testing.pytest import raises w, x, y, z = symbols('w,x,y,z') def test_is_palindromic(): assert is_palindromic('') assert is_palindromic('x') assert is_palindromic('xx') assert is_palindromic('xyx') assert not is_palindromic('xy') assert not is_palindromic('xyzx') assert is_palindromic('xxyzzyx', 1) assert not is_palindromic('xxyzzyx', 2) assert is_palindromic('xxyzzyx', 2, -1) assert is_palindromic('xxyzzyx', 2, 6) assert is_palindromic('xxyzyx', 1) assert not is_palindromic('xxyzyx', 2) assert is_palindromic('xxyzyx', 2, 2 + 3) def test_postorder_traversal(): expr = z + w*(x + y) expected = [z, w, x, y, x + y, w*(x + y), w*(x + y) + z] assert list(postorder_traversal(expr, keys=default_sort_key)) == expected assert list(postorder_traversal(expr, keys=True)) == expected expr = Piecewise((x, x < 1), (x**2, True)) expected = [ x, 1, x, x < 1, ExprCondPair(x, x < 1), 2, x, x**2, true, ExprCondPair(x**2, True), Piecewise((x, x < 1), (x**2, True)) ] assert list(postorder_traversal(expr, keys=default_sort_key)) == expected assert list(postorder_traversal( [expr], keys=default_sort_key)) == expected + [[expr]] assert list(postorder_traversal(Integral(x**2, (x, 0, 1)), keys=default_sort_key)) == [ 2, x, x**2, 0, 1, x, Tuple(x, 0, 1), Integral(x**2, Tuple(x, 0, 1)) ] assert list(postorder_traversal(('abc', ('d', 'ef')))) == [ 'abc', 'd', 'ef', ('d', 'ef'), ('abc', ('d', 'ef'))] def test_flatten(): assert flatten((1, (1,))) == [1, 1] assert flatten((x, (x,))) == [x, x] ls = [[(-2, -1), (1, 2)], [(0, 0)]] assert flatten(ls, levels=0) == ls assert flatten(ls, levels=1) == [(-2, -1), (1, 2), (0, 0)] assert flatten(ls, levels=2) == [-2, -1, 1, 2, 0, 0] assert flatten(ls, levels=3) == [-2, -1, 1, 2, 0, 0] raises(ValueError, lambda: flatten(ls, levels=-1)) class MyOp(Basic): pass assert flatten([MyOp(x, y), z]) == [MyOp(x, y), z] assert flatten([MyOp(x, y), z], cls=MyOp) == [x, y, z] assert flatten({1, 11, 2}) == list({1, 11, 2}) def test_iproduct(): assert list(iproduct()) == [()] assert list(iproduct([])) == [] assert list(iproduct([1,2,3])) == [(1,),(2,),(3,)] assert sorted(iproduct([1, 2], [3, 4, 5])) == [ (1,3),(1,4),(1,5),(2,3),(2,4),(2,5)] assert sorted(iproduct([0,1],[0,1],[0,1])) == [ (0,0,0),(0,0,1),(0,1,0),(0,1,1),(1,0,0),(1,0,1),(1,1,0),(1,1,1)] assert iterable(iproduct(S.Integers)) is True assert iterable(iproduct(S.Integers, S.Integers)) is True assert (3,) in iproduct(S.Integers) assert (4, 5) in iproduct(S.Integers, S.Integers) assert (1, 2, 3) in iproduct(S.Integers, S.Integers, S.Integers) triples = set(islice(iproduct(S.Integers, S.Integers, S.Integers), 1000)) for n1, n2, n3 in triples: assert isinstance(n1, Integer) assert isinstance(n2, Integer) assert isinstance(n3, Integer) for t in set(product(*([range(-2, 3)]*3))): assert t in iproduct(S.Integers, S.Integers, S.Integers) def test_group(): assert group([]) == [] assert group([], multiple=False) == [] assert group([1]) == [[1]] assert group([1], multiple=False) == [(1, 1)] assert group([1, 1]) == [[1, 1]] assert group([1, 1], multiple=False) == [(1, 2)] assert group([1, 1, 1]) == [[1, 1, 1]] assert group([1, 1, 1], multiple=False) == [(1, 3)] assert group([1, 2, 1]) == [[1], [2], [1]] assert group([1, 2, 1], multiple=False) == [(1, 1), (2, 1), (1, 1)] assert group([1, 1, 2, 2, 2, 1, 3, 3]) == [[1, 1], [2, 2, 2], [1], [3, 3]] assert group([1, 1, 2, 2, 2, 1, 3, 3], multiple=False) == [(1, 2), (2, 3), (1, 1), (3, 2)] def test_subsets(): # combinations assert list(subsets([1, 2, 3], 0)) == [()] assert list(subsets([1, 2, 3], 1)) == [(1,), (2,), (3,)] assert list(subsets([1, 2, 3], 2)) == [(1, 2), (1, 3), (2, 3)] assert list(subsets([1, 2, 3], 3)) == [(1, 2, 3)] l = list(range(4)) assert list(subsets(l, 0, repetition=True)) == [()] assert list(subsets(l, 1, repetition=True)) == [(0,), (1,), (2,), (3,)] assert list(subsets(l, 2, repetition=True)) == [(0, 0), (0, 1), (0, 2), (0, 3), (1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] assert list(subsets(l, 3, repetition=True)) == [(0, 0, 0), (0, 0, 1), (0, 0, 2), (0, 0, 3), (0, 1, 1), (0, 1, 2), (0, 1, 3), (0, 2, 2), (0, 2, 3), (0, 3, 3), (1, 1, 1), (1, 1, 2), (1, 1, 3), (1, 2, 2), (1, 2, 3), (1, 3, 3), (2, 2, 2), (2, 2, 3), (2, 3, 3), (3, 3, 3)] assert len(list(subsets(l, 4, repetition=True))) == 35 assert list(subsets(l[:2], 3, repetition=False)) == [] assert list(subsets(l[:2], 3, repetition=True)) == [(0, 0, 0), (0, 0, 1), (0, 1, 1), (1, 1, 1)] assert list(subsets([1, 2], repetition=True)) == \ [(), (1,), (2,), (1, 1), (1, 2), (2, 2)] assert list(subsets([1, 2], repetition=False)) == \ [(), (1,), (2,), (1, 2)] assert list(subsets([1, 2, 3], 2)) == \ [(1, 2), (1, 3), (2, 3)] assert list(subsets([1, 2, 3], 2, repetition=True)) == \ [(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)] def test_variations(): # permutations l = list(range(4)) assert list(variations(l, 0, repetition=False)) == [()] assert list(variations(l, 1, repetition=False)) == [(0,), (1,), (2,), (3,)] assert list(variations(l, 2, repetition=False)) == [(0, 1), (0, 2), (0, 3), (1, 0), (1, 2), (1, 3), (2, 0), (2, 1), (2, 3), (3, 0), (3, 1), (3, 2)] assert list(variations(l, 3, repetition=False)) == [(0, 1, 2), (0, 1, 3), (0, 2, 1), (0, 2, 3), (0, 3, 1), (0, 3, 2), (1, 0, 2), (1, 0, 3), (1, 2, 0), (1, 2, 3), (1, 3, 0), (1, 3, 2), (2, 0, 1), (2, 0, 3), (2, 1, 0), (2, 1, 3), (2, 3, 0), (2, 3, 1), (3, 0, 1), (3, 0, 2), (3, 1, 0), (3, 1, 2), (3, 2, 0), (3, 2, 1)] assert list(variations(l, 0, repetition=True)) == [()] assert list(variations(l, 1, repetition=True)) == [(0,), (1,), (2,), (3,)] assert list(variations(l, 2, repetition=True)) == [(0, 0), (0, 1), (0, 2), (0, 3), (1, 0), (1, 1), (1, 2), (1, 3), (2, 0), (2, 1), (2, 2), (2, 3), (3, 0), (3, 1), (3, 2), (3, 3)] assert len(list(variations(l, 3, repetition=True))) == 64 assert len(list(variations(l, 4, repetition=True))) == 256 assert list(variations(l[:2], 3, repetition=False)) == [] assert list(variations(l[:2], 3, repetition=True)) == [ (0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1) ] def test_cartes(): assert list(cartes([1, 2], [3, 4, 5])) == \ [(1, 3), (1, 4), (1, 5), (2, 3), (2, 4), (2, 5)] assert list(cartes()) == [()] assert list(cartes('a')) == [('a',)] assert list(cartes('a', repeat=2)) == [('a', 'a')] assert list(cartes(list(range(2)))) == [(0,), (1,)] def test_filter_symbols(): s = numbered_symbols() filtered = filter_symbols(s, symbols("x0 x2 x3")) assert take(filtered, 3) == list(symbols("x1 x4 x5")) def test_numbered_symbols(): s = numbered_symbols(cls=Dummy) assert isinstance(next(s), Dummy) assert next(numbered_symbols('C', start=1, exclude=[symbols('C1')])) == \ symbols('C2') def test_sift(): assert sift(list(range(5)), lambda _: _ % 2) == {1: [1, 3], 0: [0, 2, 4]} assert sift([x, y], lambda _: _.has(x)) == {False: [y], True: [x]} assert sift([S.One], lambda _: _.has(x)) == {False: [1]} assert sift([0, 1, 2, 3], lambda x: x % 2, binary=True) == ( [1, 3], [0, 2]) assert sift([0, 1, 2, 3], lambda x: x % 3 == 1, binary=True) == ( [1], [0, 2, 3]) raises(ValueError, lambda: sift([0, 1, 2, 3], lambda x: x % 3, binary=True)) def test_take(): X = numbered_symbols() assert take(X, 5) == list(symbols('x0:5')) assert take(X, 5) == list(symbols('x5:10')) assert take([1, 2, 3, 4, 5], 5) == [1, 2, 3, 4, 5] def test_dict_merge(): assert dict_merge({}, {1: x, y: z}) == {1: x, y: z} assert dict_merge({1: x, y: z}, {}) == {1: x, y: z} assert dict_merge({2: z}, {1: x, y: z}) == {1: x, 2: z, y: z} assert dict_merge({1: x, y: z}, {2: z}) == {1: x, 2: z, y: z} assert dict_merge({1: y, 2: z}, {1: x, y: z}) == {1: x, 2: z, y: z} assert dict_merge({1: x, y: z}, {1: y, 2: z}) == {1: y, 2: z, y: z} def test_prefixes(): assert list(prefixes([])) == [] assert list(prefixes([1])) == [[1]] assert list(prefixes([1, 2])) == [[1], [1, 2]] assert list(prefixes([1, 2, 3, 4, 5])) == \ [[1], [1, 2], [1, 2, 3], [1, 2, 3, 4], [1, 2, 3, 4, 5]] def test_postfixes(): assert list(postfixes([])) == [] assert list(postfixes([1])) == [[1]] assert list(postfixes([1, 2])) == [[2], [1, 2]] assert list(postfixes([1, 2, 3, 4, 5])) == \ [[5], [4, 5], [3, 4, 5], [2, 3, 4, 5], [1, 2, 3, 4, 5]] def test_topological_sort(): V = [2, 3, 5, 7, 8, 9, 10, 11] E = [(7, 11), (7, 8), (5, 11), (3, 8), (3, 10), (11, 2), (11, 9), (11, 10), (8, 9)] assert topological_sort((V, E)) == [3, 5, 7, 8, 11, 2, 9, 10] assert topological_sort((V, E), key=lambda v: -v) == \ [7, 5, 11, 3, 10, 8, 9, 2] raises(ValueError, lambda: topological_sort((V, E + [(10, 7)]))) def test_strongly_connected_components(): assert strongly_connected_components(([], [])) == [] assert strongly_connected_components(([1, 2, 3], [])) == [[1], [2], [3]] V = [1, 2, 3] E = [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1)] assert strongly_connected_components((V, E)) == [[1, 2, 3]] V = [1, 2, 3, 4] E = [(1, 2), (2, 3), (3, 2), (3, 4)] assert strongly_connected_components((V, E)) == [[4], [2, 3], [1]] V = [1, 2, 3, 4] E = [(1, 2), (2, 1), (3, 4), (4, 3)] assert strongly_connected_components((V, E)) == [[1, 2], [3, 4]] def test_connected_components(): assert connected_components(([], [])) == [] assert connected_components(([1, 2, 3], [])) == [[1], [2], [3]] V = [1, 2, 3] E = [(1, 2), (1, 3), (2, 1), (2, 3), (3, 1)] assert connected_components((V, E)) == [[1, 2, 3]] V = [1, 2, 3, 4] E = [(1, 2), (2, 3), (3, 2), (3, 4)] assert connected_components((V, E)) == [[1, 2, 3, 4]] V = [1, 2, 3, 4] E = [(1, 2), (3, 4)] assert connected_components((V, E)) == [[1, 2], [3, 4]] def test_rotate(): A = [0, 1, 2, 3, 4] assert rotate_left(A, 2) == [2, 3, 4, 0, 1] assert rotate_right(A, 1) == [4, 0, 1, 2, 3] A = [] B = rotate_right(A, 1) assert B == [] B.append(1) assert A == [] B = rotate_left(A, 1) assert B == [] B.append(1) assert A == [] def test_multiset_partitions(): A = [0, 1, 2, 3, 4] assert list(multiset_partitions(A, 5)) == [[[0], [1], [2], [3], [4]]] assert len(list(multiset_partitions(A, 4))) == 10 assert len(list(multiset_partitions(A, 3))) == 25 assert list(multiset_partitions([1, 1, 1, 2, 2], 2)) == [ [[1, 1, 1, 2], [2]], [[1, 1, 1], [2, 2]], [[1, 1, 2, 2], [1]], [[1, 1, 2], [1, 2]], [[1, 1], [1, 2, 2]]] assert list(multiset_partitions([1, 1, 2, 2], 2)) == [ [[1, 1, 2], [2]], [[1, 1], [2, 2]], [[1, 2, 2], [1]], [[1, 2], [1, 2]]] assert list(multiset_partitions([1, 2, 3, 4], 2)) == [ [[1, 2, 3], [4]], [[1, 2, 4], [3]], [[1, 2], [3, 4]], [[1, 3, 4], [2]], [[1, 3], [2, 4]], [[1, 4], [2, 3]], [[1], [2, 3, 4]]] assert list(multiset_partitions([1, 2, 2], 2)) == [ [[1, 2], [2]], [[1], [2, 2]]] assert list(multiset_partitions(3)) == [ [[0, 1, 2]], [[0, 1], [2]], [[0, 2], [1]], [[0], [1, 2]], [[0], [1], [2]]] assert list(multiset_partitions(3, 2)) == [ [[0, 1], [2]], [[0, 2], [1]], [[0], [1, 2]]] assert list(multiset_partitions([1] * 3, 2)) == [[[1], [1, 1]]] assert list(multiset_partitions([1] * 3)) == [ [[1, 1, 1]], [[1], [1, 1]], [[1], [1], [1]]] a = [3, 2, 1] assert list(multiset_partitions(a)) == \ list(multiset_partitions(sorted(a))) assert list(multiset_partitions(a, 5)) == [] assert list(multiset_partitions(a, 1)) == [[[1, 2, 3]]] assert list(multiset_partitions(a + [4], 5)) == [] assert list(multiset_partitions(a + [4], 1)) == [[[1, 2, 3, 4]]] assert list(multiset_partitions(2, 5)) == [] assert list(multiset_partitions(2, 1)) == [[[0, 1]]] assert list(multiset_partitions('a')) == [[['a']]] assert list(multiset_partitions('a', 2)) == [] assert list(multiset_partitions('ab')) == [[['a', 'b']], [['a'], ['b']]] assert list(multiset_partitions('ab', 1)) == [[['a', 'b']]] assert list(multiset_partitions('aaa', 1)) == [['aaa']] assert list(multiset_partitions([1, 1], 1)) == [[[1, 1]]] ans = [('mpsyy',), ('mpsy', 'y'), ('mps', 'yy'), ('mps', 'y', 'y'), ('mpyy', 's'), ('mpy', 'sy'), ('mpy', 's', 'y'), ('mp', 'syy'), ('mp', 'sy', 'y'), ('mp', 's', 'yy'), ('mp', 's', 'y', 'y'), ('msyy', 'p'), ('msy', 'py'), ('msy', 'p', 'y'), ('ms', 'pyy'), ('ms', 'py', 'y'), ('ms', 'p', 'yy'), ('ms', 'p', 'y', 'y'), ('myy', 'ps'), ('myy', 'p', 's'), ('my', 'psy'), ('my', 'ps', 'y'), ('my', 'py', 's'), ('my', 'p', 'sy'), ('my', 'p', 's', 'y'), ('m', 'psyy'), ('m', 'psy', 'y'), ('m', 'ps', 'yy'), ('m', 'ps', 'y', 'y'), ('m', 'pyy', 's'), ('m', 'py', 'sy'), ('m', 'py', 's', 'y'), ('m', 'p', 'syy'), ('m', 'p', 'sy', 'y'), ('m', 'p', 's', 'yy'), ('m', 'p', 's', 'y', 'y')] assert list(tuple("".join(part) for part in p) for p in multiset_partitions('sympy')) == ans factorings = [[24], [8, 3], [12, 2], [4, 6], [4, 2, 3], [6, 2, 2], [2, 2, 2, 3]] assert list(factoring_visitor(p, [2,3]) for p in multiset_partitions_taocp([3, 1])) == factorings def test_multiset_combinations(): ans = ['iii', 'iim', 'iip', 'iis', 'imp', 'ims', 'ipp', 'ips', 'iss', 'mpp', 'mps', 'mss', 'pps', 'pss', 'sss'] assert [''.join(i) for i in list(multiset_combinations('mississippi', 3))] == ans M = multiset('mississippi') assert [''.join(i) for i in list(multiset_combinations(M, 3))] == ans assert [''.join(i) for i in multiset_combinations(M, 30)] == [] assert list(multiset_combinations([[1], [2, 3]], 2)) == [[[1], [2, 3]]] assert len(list(multiset_combinations('a', 3))) == 0 assert len(list(multiset_combinations('a', 0))) == 1 assert list(multiset_combinations('abc', 1)) == [['a'], ['b'], ['c']] def test_multiset_permutations(): ans = ['abby', 'abyb', 'aybb', 'baby', 'bayb', 'bbay', 'bbya', 'byab', 'byba', 'yabb', 'ybab', 'ybba'] assert [''.join(i) for i in multiset_permutations('baby')] == ans assert [''.join(i) for i in multiset_permutations(multiset('baby'))] == ans assert list(multiset_permutations([0, 0, 0], 2)) == [[0, 0]] assert list(multiset_permutations([0, 2, 1], 2)) == [ [0, 1], [0, 2], [1, 0], [1, 2], [2, 0], [2, 1]] assert len(list(multiset_permutations('a', 0))) == 1 assert len(list(multiset_permutations('a', 3))) == 0 for nul in ([], {}, ''): assert list(multiset_permutations(nul)) == [[]] assert list(multiset_permutations(nul, 0)) == [[]] # impossible requests give no result assert list(multiset_permutations(nul, 1)) == [] assert list(multiset_permutations(nul, -1)) == [] def test(): for i in range(1, 7): print(i) for p in multiset_permutations([0, 0, 1, 0, 1], i): print(p) assert capture(lambda: test()) == dedent('''\ 1 [0] [1] 2 [0, 0] [0, 1] [1, 0] [1, 1] 3 [0, 0, 0] [0, 0, 1] [0, 1, 0] [0, 1, 1] [1, 0, 0] [1, 0, 1] [1, 1, 0] 4 [0, 0, 0, 1] [0, 0, 1, 0] [0, 0, 1, 1] [0, 1, 0, 0] [0, 1, 0, 1] [0, 1, 1, 0] [1, 0, 0, 0] [1, 0, 0, 1] [1, 0, 1, 0] [1, 1, 0, 0] 5 [0, 0, 0, 1, 1] [0, 0, 1, 0, 1] [0, 0, 1, 1, 0] [0, 1, 0, 0, 1] [0, 1, 0, 1, 0] [0, 1, 1, 0, 0] [1, 0, 0, 0, 1] [1, 0, 0, 1, 0] [1, 0, 1, 0, 0] [1, 1, 0, 0, 0] 6\n''') def test_partitions(): ans = [[{}], [(0, {})]] for i in range(2): assert list(partitions(0, size=i)) == ans[i] assert list(partitions(1, 0, size=i)) == ans[i] assert list(partitions(6, 2, 2, size=i)) == ans[i] assert list(partitions(6, 2, None, size=i)) != ans[i] assert list(partitions(6, None, 2, size=i)) != ans[i] assert list(partitions(6, 2, 0, size=i)) == ans[i] assert [p for p in partitions(6, k=2)] == [ {2: 3}, {1: 2, 2: 2}, {1: 4, 2: 1}, {1: 6}] assert [p for p in partitions(6, k=3)] == [ {3: 2}, {1: 1, 2: 1, 3: 1}, {1: 3, 3: 1}, {2: 3}, {1: 2, 2: 2}, {1: 4, 2: 1}, {1: 6}] assert [p for p in partitions(8, k=4, m=3)] == [ {4: 2}, {1: 1, 3: 1, 4: 1}, {2: 2, 4: 1}, {2: 1, 3: 2}] == [ i for i in partitions(8, k=4, m=3) if all(k <= 4 for k in i) and sum(i.values()) <=3] assert [p for p in partitions(S(3), m=2)] == [ {3: 1}, {1: 1, 2: 1}] assert [i for i in partitions(4, k=3)] == [ {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}] == [ i for i in partitions(4) if all(k <= 3 for k in i)] # Consistency check on output of _partitions and RGS_unrank. # This provides a sanity test on both routines. Also verifies that # the total number of partitions is the same in each case. # (from pkrathmann2) for n in range(2, 6): i = 0 for m, q in _set_partitions(n): assert q == RGS_unrank(i, n) i += 1 assert i == RGS_enum(n) def test_binary_partitions(): assert [i[:] for i in binary_partitions(10)] == [[8, 2], [8, 1, 1], [4, 4, 2], [4, 4, 1, 1], [4, 2, 2, 2], [4, 2, 2, 1, 1], [4, 2, 1, 1, 1, 1], [4, 1, 1, 1, 1, 1, 1], [2, 2, 2, 2, 2], [2, 2, 2, 2, 1, 1], [2, 2, 2, 1, 1, 1, 1], [2, 2, 1, 1, 1, 1, 1, 1], [2, 1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] assert len([j[:] for j in binary_partitions(16)]) == 36 def test_bell_perm(): assert [len(set(generate_bell(i))) for i in range(1, 7)] == [ factorial(i) for i in range(1, 7)] assert list(generate_bell(3)) == [ (0, 1, 2), (0, 2, 1), (2, 0, 1), (2, 1, 0), (1, 2, 0), (1, 0, 2)] # generate_bell and trotterjohnson are advertised to return the same # permutations; this is not technically necessary so this test could # be removed for n in range(1, 5): p = Permutation(range(n)) b = generate_bell(n) for bi in b: assert bi == tuple(p.array_form) p = p.next_trotterjohnson() raises(ValueError, lambda: list(generate_bell(0))) # XXX is this consistent with other permutation algorithms? def test_involutions(): lengths = [1, 2, 4, 10, 26, 76] for n, N in enumerate(lengths): i = list(generate_involutions(n + 1)) assert len(i) == N assert len({Permutation(j)**2 for j in i}) == 1 def test_derangements(): assert len(list(generate_derangements(list(range(6))))) == 265 assert ''.join(''.join(i) for i in generate_derangements('abcde')) == ( 'badecbaecdbcaedbcdeabceadbdaecbdeacbdecabeacdbedacbedcacabedcadebcaebd' 'cdaebcdbeacdeabcdebaceabdcebadcedabcedbadabecdaebcdaecbdcaebdcbeadceab' 'dcebadeabcdeacbdebacdebcaeabcdeadbceadcbecabdecbadecdabecdbaedabcedacb' 'edbacedbca') assert list(generate_derangements([0, 1, 2, 3])) == [ [1, 0, 3, 2], [1, 2, 3, 0], [1, 3, 0, 2], [2, 0, 3, 1], [2, 3, 0, 1], [2, 3, 1, 0], [3, 0, 1, 2], [3, 2, 0, 1], [3, 2, 1, 0]] assert list(generate_derangements([0, 1, 2, 2])) == [ [2, 2, 0, 1], [2, 2, 1, 0]] assert list(generate_derangements('ba')) == [list('ab')] def test_necklaces(): def count(n, k, f): return len(list(necklaces(n, k, f))) m = [] for i in range(1, 8): m.append(( i, count(i, 2, 0), count(i, 2, 1), count(i, 3, 1))) assert Matrix(m) == Matrix([ [1, 2, 2, 3], [2, 3, 3, 6], [3, 4, 4, 10], [4, 6, 6, 21], [5, 8, 8, 39], [6, 14, 13, 92], [7, 20, 18, 198]]) def test_bracelets(): bc = [i for i in bracelets(2, 4)] assert Matrix(bc) == Matrix([ [0, 0], [0, 1], [0, 2], [0, 3], [1, 1], [1, 2], [1, 3], [2, 2], [2, 3], [3, 3] ]) bc = [i for i in bracelets(4, 2)] assert Matrix(bc) == Matrix([ [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 1], [0, 1, 0, 1], [0, 1, 1, 1], [1, 1, 1, 1] ]) def test_generate_oriented_forest(): assert list(generate_oriented_forest(5)) == [[0, 1, 2, 3, 4], [0, 1, 2, 3, 3], [0, 1, 2, 3, 2], [0, 1, 2, 3, 1], [0, 1, 2, 3, 0], [0, 1, 2, 2, 2], [0, 1, 2, 2, 1], [0, 1, 2, 2, 0], [0, 1, 2, 1, 2], [0, 1, 2, 1, 1], [0, 1, 2, 1, 0], [0, 1, 2, 0, 1], [0, 1, 2, 0, 0], [0, 1, 1, 1, 1], [0, 1, 1, 1, 0], [0, 1, 1, 0, 1], [0, 1, 1, 0, 0], [0, 1, 0, 1, 0], [0, 1, 0, 0, 0], [0, 0, 0, 0, 0]] assert len(list(generate_oriented_forest(10))) == 1842 def test_unflatten(): r = list(range(10)) assert unflatten(r) == list(zip(r[::2], r[1::2])) assert unflatten(r, 5) == [tuple(r[:5]), tuple(r[5:])] raises(ValueError, lambda: unflatten(list(range(10)), 3)) raises(ValueError, lambda: unflatten(list(range(10)), -2)) def test_common_prefix_suffix(): assert common_prefix([], [1]) == [] assert common_prefix(list(range(3))) == [0, 1, 2] assert common_prefix(list(range(3)), list(range(4))) == [0, 1, 2] assert common_prefix([1, 2, 3], [1, 2, 5]) == [1, 2] assert common_prefix([1, 2, 3], [1, 3, 5]) == [1] assert common_suffix([], [1]) == [] assert common_suffix(list(range(3))) == [0, 1, 2] assert common_suffix(list(range(3)), list(range(3))) == [0, 1, 2] assert common_suffix(list(range(3)), list(range(4))) == [] assert common_suffix([1, 2, 3], [9, 2, 3]) == [2, 3] assert common_suffix([1, 2, 3], [9, 7, 3]) == [3] def test_minlex(): assert minlex([1, 2, 0]) == (0, 1, 2) assert minlex((1, 2, 0)) == (0, 1, 2) assert minlex((1, 0, 2)) == (0, 2, 1) assert minlex((1, 0, 2), directed=False) == (0, 1, 2) assert minlex('aba') == 'aab' assert minlex(('bb', 'aaa', 'c', 'a'), key=len) == ('c', 'a', 'bb', 'aaa') def test_ordered(): assert list(ordered((x, y), hash, default=False)) in [[x, y], [y, x]] assert list(ordered((x, y), hash, default=False)) == \ list(ordered((y, x), hash, default=False)) assert list(ordered((x, y))) == [x, y] seq, keys = [[[1, 2, 1], [0, 3, 1], [1, 1, 3], [2], [1]], (lambda x: len(x), lambda x: sum(x))] assert list(ordered(seq, keys, default=False, warn=False)) == \ [[1], [2], [1, 2, 1], [0, 3, 1], [1, 1, 3]] raises(ValueError, lambda: list(ordered(seq, keys, default=False, warn=True))) def test_runs(): assert runs([]) == [] assert runs([1]) == [[1]] assert runs([1, 1]) == [[1], [1]] assert runs([1, 1, 2]) == [[1], [1, 2]] assert runs([1, 2, 1]) == [[1, 2], [1]] assert runs([2, 1, 1]) == [[2], [1], [1]] from operator import lt assert runs([2, 1, 1], lt) == [[2, 1], [1]] def test_reshape(): seq = list(range(1, 9)) assert reshape(seq, [4]) == \ [[1, 2, 3, 4], [5, 6, 7, 8]] assert reshape(seq, (4,)) == \ [(1, 2, 3, 4), (5, 6, 7, 8)] assert reshape(seq, (2, 2)) == \ [(1, 2, 3, 4), (5, 6, 7, 8)] assert reshape(seq, (2, [2])) == \ [(1, 2, [3, 4]), (5, 6, [7, 8])] assert reshape(seq, ((2,), [2])) == \ [((1, 2), [3, 4]), ((5, 6), [7, 8])] assert reshape(seq, (1, [2], 1)) == \ [(1, [2, 3], 4), (5, [6, 7], 8)] assert reshape(tuple(seq), ([[1], 1, (2,)],)) == \ (([[1], 2, (3, 4)],), ([[5], 6, (7, 8)],)) assert reshape(tuple(seq), ([1], 1, (2,))) == \ (([1], 2, (3, 4)), ([5], 6, (7, 8))) assert reshape(list(range(12)), [2, [3], {2}, (1, (3,), 1)]) == \ [[0, 1, [2, 3, 4], {5, 6}, (7, (8, 9, 10), 11)]] raises(ValueError, lambda: reshape([0, 1], [-1])) raises(ValueError, lambda: reshape([0, 1], [3])) def test_uniq(): assert list(uniq(p for p in partitions(4))) == \ [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2: 1}, {1: 4}] assert list(uniq(x % 2 for x in range(5))) == [0, 1] assert list(uniq('a')) == ['a'] assert list(uniq('ababc')) == list('abc') assert list(uniq([[1], [2, 1], [1]])) == [[1], [2, 1]] assert list(uniq(permutations(i for i in [[1], 2, 2]))) == \ [([1], 2, 2), (2, [1], 2), (2, 2, [1])] assert list(uniq([2, 3, 2, 4, [2], [1], [2], [3], [1]])) == \ [2, 3, 4, [2], [1], [3]] f = [1] raises(RuntimeError, lambda: [f.remove(i) for i in uniq(f)]) f = [[1]] raises(RuntimeError, lambda: [f.remove(i) for i in uniq(f)]) def test_kbins(): assert len(list(kbins('1123', 2, ordered=1))) == 24 assert len(list(kbins('1123', 2, ordered=11))) == 36 assert len(list(kbins('1123', 2, ordered=10))) == 10 assert len(list(kbins('1123', 2, ordered=0))) == 5 assert len(list(kbins('1123', 2, ordered=None))) == 3 def test1(): for orderedval in [None, 0, 1, 10, 11]: print('ordered =', orderedval) for p in kbins([0, 0, 1], 2, ordered=orderedval): print(' ', p) assert capture(lambda : test1()) == dedent('''\ ordered = None [[0], [0, 1]] [[0, 0], [1]] ordered = 0 [[0, 0], [1]] [[0, 1], [0]] ordered = 1 [[0], [0, 1]] [[0], [1, 0]] [[1], [0, 0]] ordered = 10 [[0, 0], [1]] [[1], [0, 0]] [[0, 1], [0]] [[0], [0, 1]] ordered = 11 [[0], [0, 1]] [[0, 0], [1]] [[0], [1, 0]] [[0, 1], [0]] [[1], [0, 0]] [[1, 0], [0]]\n''') def test2(): for orderedval in [None, 0, 1, 10, 11]: print('ordered =', orderedval) for p in kbins(list(range(3)), 2, ordered=orderedval): print(' ', p) assert capture(lambda : test2()) == dedent('''\ ordered = None [[0], [1, 2]] [[0, 1], [2]] ordered = 0 [[0, 1], [2]] [[0, 2], [1]] [[0], [1, 2]] ordered = 1 [[0], [1, 2]] [[0], [2, 1]] [[1], [0, 2]] [[1], [2, 0]] [[2], [0, 1]] [[2], [1, 0]] ordered = 10 [[0, 1], [2]] [[2], [0, 1]] [[0, 2], [1]] [[1], [0, 2]] [[0], [1, 2]] [[1, 2], [0]] ordered = 11 [[0], [1, 2]] [[0, 1], [2]] [[0], [2, 1]] [[0, 2], [1]] [[1], [0, 2]] [[1, 0], [2]] [[1], [2, 0]] [[1, 2], [0]] [[2], [0, 1]] [[2, 0], [1]] [[2], [1, 0]] [[2, 1], [0]]\n''') def test_has_dups(): assert has_dups(set()) is False assert has_dups(list(range(3))) is False assert has_dups([1, 2, 1]) is True def test__partition(): assert _partition('abcde', [1, 0, 1, 2, 0]) == [ ['b', 'e'], ['a', 'c'], ['d']] assert _partition('abcde', [1, 0, 1, 2, 0], 3) == [ ['b', 'e'], ['a', 'c'], ['d']] output = (3, [1, 0, 1, 2, 0]) assert _partition('abcde', *output) == [['b', 'e'], ['a', 'c'], ['d']] def test_ordered_partitions(): from sympy.functions.combinatorial.numbers import nT f = ordered_partitions assert list(f(0, 1)) == [[]] assert list(f(1, 0)) == [[]] for i in range(1, 7): for j in [None] + list(range(1, i)): assert ( sum(1 for p in f(i, j, 1)) == sum(1 for p in f(i, j, 0)) == nT(i, j)) def test_rotations(): assert list(rotations('ab')) == [['a', 'b'], ['b', 'a']] assert list(rotations(range(3))) == [[0, 1, 2], [1, 2, 0], [2, 0, 1]] assert list(rotations(range(3), dir=-1)) == [[0, 1, 2], [2, 0, 1], [1, 2, 0]] def test_ibin(): assert ibin(3) == [1, 1] assert ibin(3, 3) == [0, 1, 1] assert ibin(3, str=True) == '11' assert ibin(3, 3, str=True) == '011' assert list(ibin(2, 'all')) == [(0, 0), (0, 1), (1, 0), (1, 1)] assert list(ibin(2, '', str=True)) == ['00', '01', '10', '11'] raises(ValueError, lambda: ibin(-.5)) raises(ValueError, lambda: ibin(2, 1)) sympy-sympy-1.9/sympy/utilities/tests/test_lambdify.py000066400000000000000000001351471412543434000234740ustar00rootroot00000000000000from itertools import product import math import inspect import mpmath from sympy.testing.pytest import raises from sympy import ( symbols, lambdify, sqrt, sin, cos, tan, pi, acos, acosh, Rational, Float, Lambda, Piecewise, exp, E, Integral, oo, I, Abs, Function, true, false, And, Or, Not, ITE, Min, Max, floor, diff, IndexedBase, Sum, DotProduct, Eq, Dummy, sinc, erf, erfc, factorial, gamma, loggamma, digamma, RisingFactorial, besselj, bessely, besseli, besselk, S, beta, betainc, betainc_regularized, fresnelc, fresnels) from sympy.codegen.cfunctions import expm1, log1p, exp2, log2, log10, hypot from sympy.codegen.numpy_nodes import logaddexp, logaddexp2 from sympy.codegen.scipy_nodes import cosm1 from sympy.functions.elementary.complexes import re, im, arg from sympy.functions.special.polynomials import \ chebyshevt, chebyshevu, legendre, hermite, laguerre, gegenbauer, \ assoc_legendre, assoc_laguerre, jacobi from sympy.matrices import Matrix, MatrixSymbol, SparseMatrix from sympy.printing.lambdarepr import LambdaPrinter from sympy.printing.numpy import NumPyPrinter from sympy.utilities.lambdify import implemented_function, lambdastr from sympy.testing.pytest import skip from sympy.utilities.decorator import conserve_mpmath_dps from sympy.external import import_module from sympy.functions.special.gamma_functions import uppergamma, lowergamma import sympy MutableDenseMatrix = Matrix numpy = import_module('numpy') scipy = import_module('scipy', import_kwargs={'fromlist': ['sparse']}) numexpr = import_module('numexpr') tensorflow = import_module('tensorflow') cupy = import_module('cupy') if tensorflow: # Hide Tensorflow warnings import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' w, x, y, z = symbols('w,x,y,z') #================== Test different arguments ======================= def test_no_args(): f = lambdify([], 1) raises(TypeError, lambda: f(-1)) assert f() == 1 def test_single_arg(): f = lambdify(x, 2*x) assert f(1) == 2 def test_list_args(): f = lambdify([x, y], x + y) assert f(1, 2) == 3 def test_nested_args(): f1 = lambdify([[w, x]], [w, x]) assert f1([91, 2]) == [91, 2] raises(TypeError, lambda: f1(1, 2)) f2 = lambdify([(w, x), (y, z)], [w, x, y, z]) assert f2((18, 12), (73, 4)) == [18, 12, 73, 4] raises(TypeError, lambda: f2(3, 4)) f3 = lambdify([w, [[[x]], y], z], [w, x, y, z]) assert f3(10, [[[52]], 31], 44) == [10, 52, 31, 44] def test_str_args(): f = lambdify('x,y,z', 'z,y,x') assert f(3, 2, 1) == (1, 2, 3) assert f(1.0, 2.0, 3.0) == (3.0, 2.0, 1.0) # make sure correct number of args required raises(TypeError, lambda: f(0)) def test_own_namespace_1(): myfunc = lambda x: 1 f = lambdify(x, sin(x), {"sin": myfunc}) assert f(0.1) == 1 assert f(100) == 1 def test_own_namespace_2(): def myfunc(x): return 1 f = lambdify(x, sin(x), {'sin': myfunc}) assert f(0.1) == 1 assert f(100) == 1 def test_own_module(): f = lambdify(x, sin(x), math) assert f(0) == 0.0 def test_bad_args(): # no vargs given raises(TypeError, lambda: lambdify(1)) # same with vector exprs raises(TypeError, lambda: lambdify([1, 2])) def test_atoms(): # Non-Symbol atoms should not be pulled out from the expression namespace f = lambdify(x, pi + x, {"pi": 3.14}) assert f(0) == 3.14 f = lambdify(x, I + x, {"I": 1j}) assert f(1) == 1 + 1j #================== Test different modules ========================= # high precision output of sin(0.2*pi) is used to detect if precision is lost unwanted @conserve_mpmath_dps def test_sympy_lambda(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin(x), "sympy") assert f(x) == sin(x) prec = 1e-15 assert -prec < f(Rational(1, 5)).evalf() - Float(str(sin02)) < prec # arctan is in numpy module and should not be available # The arctan below gives NameError. What is this supposed to test? # raises(NameError, lambda: lambdify(x, arctan(x), "sympy")) @conserve_mpmath_dps def test_math_lambda(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin(x), "math") prec = 1e-15 assert -prec < f(0.2) - sin02 < prec raises(TypeError, lambda: f(x)) # if this succeeds, it can't be a python math function @conserve_mpmath_dps def test_mpmath_lambda(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin(x), "mpmath") prec = 1e-49 # mpmath precision is around 50 decimal places assert -prec < f(mpmath.mpf("0.2")) - sin02 < prec raises(TypeError, lambda: f(x)) # if this succeeds, it can't be a mpmath function @conserve_mpmath_dps def test_number_precision(): mpmath.mp.dps = 50 sin02 = mpmath.mpf("0.19866933079506121545941262711838975037020672954020") f = lambdify(x, sin02, "mpmath") prec = 1e-49 # mpmath precision is around 50 decimal places assert -prec < f(0) - sin02 < prec @conserve_mpmath_dps def test_mpmath_precision(): mpmath.mp.dps = 100 assert str(lambdify((), pi.evalf(100), 'mpmath')()) == str(pi.evalf(100)) #================== Test Translations ============================== # We can only check if all translated functions are valid. It has to be checked # by hand if they are complete. def test_math_transl(): from sympy.utilities.lambdify import MATH_TRANSLATIONS for sym, mat in MATH_TRANSLATIONS.items(): assert sym in sympy.__dict__ assert mat in math.__dict__ def test_mpmath_transl(): from sympy.utilities.lambdify import MPMATH_TRANSLATIONS for sym, mat in MPMATH_TRANSLATIONS.items(): assert sym in sympy.__dict__ or sym == 'Matrix' assert mat in mpmath.__dict__ def test_numpy_transl(): if not numpy: skip("numpy not installed.") from sympy.utilities.lambdify import NUMPY_TRANSLATIONS for sym, nump in NUMPY_TRANSLATIONS.items(): assert sym in sympy.__dict__ assert nump in numpy.__dict__ def test_scipy_transl(): if not scipy: skip("scipy not installed.") from sympy.utilities.lambdify import SCIPY_TRANSLATIONS for sym, scip in SCIPY_TRANSLATIONS.items(): assert sym in sympy.__dict__ assert scip in scipy.__dict__ or scip in scipy.special.__dict__ def test_numpy_translation_abs(): if not numpy: skip("numpy not installed.") f = lambdify(x, Abs(x), "numpy") assert f(-1) == 1 assert f(1) == 1 def test_numexpr_printer(): if not numexpr: skip("numexpr not installed.") # if translation/printing is done incorrectly then evaluating # a lambdified numexpr expression will throw an exception from sympy.printing.lambdarepr import NumExprPrinter blacklist = ('where', 'complex', 'contains') arg_tuple = (x, y, z) # some functions take more than one argument for sym in NumExprPrinter._numexpr_functions.keys(): if sym in blacklist: continue ssym = S(sym) if hasattr(ssym, '_nargs'): nargs = ssym._nargs[0] else: nargs = 1 args = arg_tuple[:nargs] f = lambdify(args, ssym(*args), modules='numexpr') assert f(*(1, )*nargs) is not None def test_issue_9334(): if not numexpr: skip("numexpr not installed.") if not numpy: skip("numpy not installed.") expr = S('b*a - sqrt(a**2)') a, b = sorted(expr.free_symbols, key=lambda s: s.name) func_numexpr = lambdify((a,b), expr, modules=[numexpr], dummify=False) foo, bar = numpy.random.random((2, 4)) func_numexpr(foo, bar) def test_issue_12984(): import warnings if not numexpr: skip("numexpr not installed.") func_numexpr = lambdify((x,y,z), Piecewise((y, x >= 0), (z, x > -1)), numexpr) assert func_numexpr(1, 24, 42) == 24 with warnings.catch_warnings(): warnings.simplefilter("ignore", RuntimeWarning) assert str(func_numexpr(-1, 24, 42)) == 'nan' #================== Test some functions ============================ def test_exponentiation(): f = lambdify(x, x**2) assert f(-1) == 1 assert f(0) == 0 assert f(1) == 1 assert f(-2) == 4 assert f(2) == 4 assert f(2.5) == 6.25 def test_sqrt(): f = lambdify(x, sqrt(x)) assert f(0) == 0.0 assert f(1) == 1.0 assert f(4) == 2.0 assert abs(f(2) - 1.414) < 0.001 assert f(6.25) == 2.5 def test_trig(): f = lambdify([x], [cos(x), sin(x)], 'math') d = f(pi) prec = 1e-11 assert -prec < d[0] + 1 < prec assert -prec < d[1] < prec d = f(3.14159) prec = 1e-5 assert -prec < d[0] + 1 < prec assert -prec < d[1] < prec def test_integral(): f = Lambda(x, exp(-x**2)) l = lambdify(y, Integral(f(x), (x, y, oo))) d = l(-oo) assert 1.77245385 < d < 1.772453851 def test_double_integral(): # example from http://mpmath.org/doc/current/calculus/integration.html i = Integral(1/(1 - x**2*y**2), (x, 0, 1), (y, 0, z)) l = lambdify([z], i) d = l(1) assert 1.23370055 < d < 1.233700551 #================== Test vectors =================================== def test_vector_simple(): f = lambdify((x, y, z), (z, y, x)) assert f(3, 2, 1) == (1, 2, 3) assert f(1.0, 2.0, 3.0) == (3.0, 2.0, 1.0) # make sure correct number of args required raises(TypeError, lambda: f(0)) def test_vector_discontinuous(): f = lambdify(x, (-1/x, 1/x)) raises(ZeroDivisionError, lambda: f(0)) assert f(1) == (-1.0, 1.0) assert f(2) == (-0.5, 0.5) assert f(-2) == (0.5, -0.5) def test_trig_symbolic(): f = lambdify([x], [cos(x), sin(x)], 'math') d = f(pi) assert abs(d[0] + 1) < 0.0001 assert abs(d[1] - 0) < 0.0001 def test_trig_float(): f = lambdify([x], [cos(x), sin(x)]) d = f(3.14159) assert abs(d[0] + 1) < 0.0001 assert abs(d[1] - 0) < 0.0001 def test_docs(): f = lambdify(x, x**2) assert f(2) == 4 f = lambdify([x, y, z], [z, y, x]) assert f(1, 2, 3) == [3, 2, 1] f = lambdify(x, sqrt(x)) assert f(4) == 2.0 f = lambdify((x, y), sin(x*y)**2) assert f(0, 5) == 0 def test_math(): f = lambdify((x, y), sin(x), modules="math") assert f(0, 5) == 0 def test_sin(): f = lambdify(x, sin(x)**2) assert isinstance(f(2), float) f = lambdify(x, sin(x)**2, modules="math") assert isinstance(f(2), float) def test_matrix(): A = Matrix([[x, x*y], [sin(z) + 4, x**z]]) sol = Matrix([[1, 2], [sin(3) + 4, 1]]) f = lambdify((x, y, z), A, modules="sympy") assert f(1, 2, 3) == sol f = lambdify((x, y, z), (A, [A]), modules="sympy") assert f(1, 2, 3) == (sol, [sol]) J = Matrix((x, x + y)).jacobian((x, y)) v = Matrix((x, y)) sol = Matrix([[1, 0], [1, 1]]) assert lambdify(v, J, modules='sympy')(1, 2) == sol assert lambdify(v.T, J, modules='sympy')(1, 2) == sol def test_numpy_matrix(): if not numpy: skip("numpy not installed.") A = Matrix([[x, x*y], [sin(z) + 4, x**z]]) sol_arr = numpy.array([[1, 2], [numpy.sin(3) + 4, 1]]) #Lambdify array first, to ensure return to array as default f = lambdify((x, y, z), A, ['numpy']) numpy.testing.assert_allclose(f(1, 2, 3), sol_arr) #Check that the types are arrays and matrices assert isinstance(f(1, 2, 3), numpy.ndarray) # gh-15071 class dot(Function): pass x_dot_mtx = dot(x, Matrix([[2], [1], [0]])) f_dot1 = lambdify(x, x_dot_mtx) inp = numpy.zeros((17, 3)) assert numpy.all(f_dot1(inp) == 0) strict_kw = dict(allow_unknown_functions=False, inline=True, fully_qualified_modules=False) p2 = NumPyPrinter(dict(user_functions={'dot': 'dot'}, **strict_kw)) f_dot2 = lambdify(x, x_dot_mtx, printer=p2) assert numpy.all(f_dot2(inp) == 0) p3 = NumPyPrinter(strict_kw) # The line below should probably fail upon construction (before calling with "(inp)"): raises(Exception, lambda: lambdify(x, x_dot_mtx, printer=p3)(inp)) def test_numpy_transpose(): if not numpy: skip("numpy not installed.") A = Matrix([[1, x], [0, 1]]) f = lambdify((x), A.T, modules="numpy") numpy.testing.assert_array_equal(f(2), numpy.array([[1, 0], [2, 1]])) def test_numpy_dotproduct(): if not numpy: skip("numpy not installed") A = Matrix([x, y, z]) f1 = lambdify([x, y, z], DotProduct(A, A), modules='numpy') f2 = lambdify([x, y, z], DotProduct(A, A.T), modules='numpy') f3 = lambdify([x, y, z], DotProduct(A.T, A), modules='numpy') f4 = lambdify([x, y, z], DotProduct(A, A.T), modules='numpy') assert f1(1, 2, 3) == \ f2(1, 2, 3) == \ f3(1, 2, 3) == \ f4(1, 2, 3) == \ numpy.array([14]) def test_numpy_inverse(): if not numpy: skip("numpy not installed.") A = Matrix([[1, x], [0, 1]]) f = lambdify((x), A**-1, modules="numpy") numpy.testing.assert_array_equal(f(2), numpy.array([[1, -2], [0, 1]])) def test_numpy_old_matrix(): if not numpy: skip("numpy not installed.") A = Matrix([[x, x*y], [sin(z) + 4, x**z]]) sol_arr = numpy.array([[1, 2], [numpy.sin(3) + 4, 1]]) f = lambdify((x, y, z), A, [{'ImmutableDenseMatrix': numpy.matrix}, 'numpy']) numpy.testing.assert_allclose(f(1, 2, 3), sol_arr) assert isinstance(f(1, 2, 3), numpy.matrix) def test_scipy_sparse_matrix(): if not scipy: skip("scipy not installed.") A = SparseMatrix([[x, 0], [0, y]]) f = lambdify((x, y), A, modules="scipy") B = f(1, 2) assert isinstance(B, scipy.sparse.coo_matrix) def test_python_div_zero_issue_11306(): if not numpy: skip("numpy not installed.") p = Piecewise((1 / x, y < -1), (x, y < 1), (1 / x, True)) f = lambdify([x, y], p, modules='numpy') numpy.seterr(divide='ignore') assert float(f(numpy.array([0]),numpy.array([0.5]))) == 0 assert str(float(f(numpy.array([0]),numpy.array([1])))) == 'inf' numpy.seterr(divide='warn') def test_issue9474(): mods = [None, 'math'] if numpy: mods.append('numpy') if mpmath: mods.append('mpmath') for mod in mods: f = lambdify(x, S.One/x, modules=mod) assert f(2) == 0.5 f = lambdify(x, floor(S.One/x), modules=mod) assert f(2) == 0 for absfunc, modules in product([Abs, abs], mods): f = lambdify(x, absfunc(x), modules=modules) assert f(-1) == 1 assert f(1) == 1 assert f(3+4j) == 5 def test_issue_9871(): if not numexpr: skip("numexpr not installed.") if not numpy: skip("numpy not installed.") r = sqrt(x**2 + y**2) expr = diff(1/r, x) xn = yn = numpy.linspace(1, 10, 16) # expr(xn, xn) = -xn/(sqrt(2)*xn)^3 fv_exact = -numpy.sqrt(2.)**-3 * xn**-2 fv_numpy = lambdify((x, y), expr, modules='numpy')(xn, yn) fv_numexpr = lambdify((x, y), expr, modules='numexpr')(xn, yn) numpy.testing.assert_allclose(fv_numpy, fv_exact, rtol=1e-10) numpy.testing.assert_allclose(fv_numexpr, fv_exact, rtol=1e-10) def test_numpy_piecewise(): if not numpy: skip("numpy not installed.") pieces = Piecewise((x, x < 3), (x**2, x > 5), (0, True)) f = lambdify(x, pieces, modules="numpy") numpy.testing.assert_array_equal(f(numpy.arange(10)), numpy.array([0, 1, 2, 0, 0, 0, 36, 49, 64, 81])) # If we evaluate somewhere all conditions are False, we should get back NaN nodef_func = lambdify(x, Piecewise((x, x > 0), (-x, x < 0))) numpy.testing.assert_array_equal(nodef_func(numpy.array([-1, 0, 1])), numpy.array([1, numpy.nan, 1])) def test_numpy_logical_ops(): if not numpy: skip("numpy not installed.") and_func = lambdify((x, y), And(x, y), modules="numpy") and_func_3 = lambdify((x, y, z), And(x, y, z), modules="numpy") or_func = lambdify((x, y), Or(x, y), modules="numpy") or_func_3 = lambdify((x, y, z), Or(x, y, z), modules="numpy") not_func = lambdify((x), Not(x), modules="numpy") arr1 = numpy.array([True, True]) arr2 = numpy.array([False, True]) arr3 = numpy.array([True, False]) numpy.testing.assert_array_equal(and_func(arr1, arr2), numpy.array([False, True])) numpy.testing.assert_array_equal(and_func_3(arr1, arr2, arr3), numpy.array([False, False])) numpy.testing.assert_array_equal(or_func(arr1, arr2), numpy.array([True, True])) numpy.testing.assert_array_equal(or_func_3(arr1, arr2, arr3), numpy.array([True, True])) numpy.testing.assert_array_equal(not_func(arr2), numpy.array([True, False])) def test_numpy_matmul(): if not numpy: skip("numpy not installed.") xmat = Matrix([[x, y], [z, 1+z]]) ymat = Matrix([[x**2], [Abs(x)]]) mat_func = lambdify((x, y, z), xmat*ymat, modules="numpy") numpy.testing.assert_array_equal(mat_func(0.5, 3, 4), numpy.array([[1.625], [3.5]])) numpy.testing.assert_array_equal(mat_func(-0.5, 3, 4), numpy.array([[1.375], [3.5]])) # Multiple matrices chained together in multiplication f = lambdify((x, y, z), xmat*xmat*xmat, modules="numpy") numpy.testing.assert_array_equal(f(0.5, 3, 4), numpy.array([[72.125, 119.25], [159, 251]])) def test_numpy_numexpr(): if not numpy: skip("numpy not installed.") if not numexpr: skip("numexpr not installed.") a, b, c = numpy.random.randn(3, 128, 128) # ensure that numpy and numexpr return same value for complicated expression expr = sin(x) + cos(y) + tan(z)**2 + Abs(z-y)*acos(sin(y*z)) + \ Abs(y-z)*acosh(2+exp(y-x))- sqrt(x**2+I*y**2) npfunc = lambdify((x, y, z), expr, modules='numpy') nefunc = lambdify((x, y, z), expr, modules='numexpr') assert numpy.allclose(npfunc(a, b, c), nefunc(a, b, c)) def test_numexpr_userfunctions(): if not numpy: skip("numpy not installed.") if not numexpr: skip("numexpr not installed.") a, b = numpy.random.randn(2, 10) uf = type('uf', (Function, ), {'eval' : classmethod(lambda x, y : y**2+1)}) func = lambdify(x, 1-uf(x), modules='numexpr') assert numpy.allclose(func(a), -(a**2)) uf = implemented_function(Function('uf'), lambda x, y : 2*x*y+1) func = lambdify((x, y), uf(x, y), modules='numexpr') assert numpy.allclose(func(a, b), 2*a*b+1) def test_tensorflow_basic_math(): if not tensorflow: skip("tensorflow not installed.") expr = Max(sin(x), Abs(1/(x+2))) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: a = tensorflow.constant(0, dtype=tensorflow.float32) assert func(a).eval(session=s) == 0.5 def test_tensorflow_placeholders(): if not tensorflow: skip("tensorflow not installed.") expr = Max(sin(x), Abs(1/(x+2))) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: a = tensorflow.compat.v1.placeholder(dtype=tensorflow.float32) assert func(a).eval(session=s, feed_dict={a: 0}) == 0.5 def test_tensorflow_variables(): if not tensorflow: skip("tensorflow not installed.") expr = Max(sin(x), Abs(1/(x+2))) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: a = tensorflow.Variable(0, dtype=tensorflow.float32) s.run(a.initializer) assert func(a).eval(session=s, feed_dict={a: 0}) == 0.5 def test_tensorflow_logical_operations(): if not tensorflow: skip("tensorflow not installed.") expr = Not(And(Or(x, y), y)) func = lambdify([x, y], expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(False, True).eval(session=s) == False def test_tensorflow_piecewise(): if not tensorflow: skip("tensorflow not installed.") expr = Piecewise((0, Eq(x,0)), (-1, x < 0), (1, x > 0)) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(-1).eval(session=s) == -1 assert func(0).eval(session=s) == 0 assert func(1).eval(session=s) == 1 def test_tensorflow_multi_max(): if not tensorflow: skip("tensorflow not installed.") expr = Max(x, -x, x**2) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(-2).eval(session=s) == 4 def test_tensorflow_multi_min(): if not tensorflow: skip("tensorflow not installed.") expr = Min(x, -x, x**2) func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(-2).eval(session=s) == -2 def test_tensorflow_relational(): if not tensorflow: skip("tensorflow not installed.") expr = x >= 0 func = lambdify(x, expr, modules="tensorflow") with tensorflow.compat.v1.Session() as s: assert func(1).eval(session=s) == True def test_tensorflow_complexes(): if not tensorflow: skip("tensorflow not installed") func1 = lambdify(x, re(x), modules="tensorflow") func2 = lambdify(x, im(x), modules="tensorflow") func3 = lambdify(x, Abs(x), modules="tensorflow") func4 = lambdify(x, arg(x), modules="tensorflow") with tensorflow.compat.v1.Session() as s: # For versions before # https://github.com/tensorflow/tensorflow/issues/30029 # resolved, using python numeric types may not work a = tensorflow.constant(1+2j) assert func1(a).eval(session=s) == 1 assert func2(a).eval(session=s) == 2 tensorflow_result = func3(a).eval(session=s) sympy_result = Abs(1 + 2j).evalf() assert abs(tensorflow_result-sympy_result) < 10**-6 tensorflow_result = func4(a).eval(session=s) sympy_result = arg(1 + 2j).evalf() assert abs(tensorflow_result-sympy_result) < 10**-6 def test_tensorflow_array_arg(): # Test for issue 14655 (tensorflow part) if not tensorflow: skip("tensorflow not installed.") f = lambdify([[x, y]], x*x + y, 'tensorflow') with tensorflow.compat.v1.Session() as s: fcall = f(tensorflow.constant([2.0, 1.0])) assert fcall.eval(session=s) == 5.0 #================== Test symbolic ================================== def test_sym_single_arg(): f = lambdify(x, x * y) assert f(z) == z * y def test_sym_list_args(): f = lambdify([x, y], x + y + z) assert f(1, 2) == 3 + z def test_sym_integral(): f = Lambda(x, exp(-x**2)) l = lambdify(x, Integral(f(x), (x, -oo, oo)), modules="sympy") assert l(y) == Integral(exp(-y**2), (y, -oo, oo)) assert l(y).doit() == sqrt(pi) def test_namespace_order(): # lambdify had a bug, such that module dictionaries or cached module # dictionaries would pull earlier namespaces into themselves. # Because the module dictionaries form the namespace of the # generated lambda, this meant that the behavior of a previously # generated lambda function could change as a result of later calls # to lambdify. n1 = {'f': lambda x: 'first f'} n2 = {'f': lambda x: 'second f', 'g': lambda x: 'function g'} f = sympy.Function('f') g = sympy.Function('g') if1 = lambdify(x, f(x), modules=(n1, "sympy")) assert if1(1) == 'first f' if2 = lambdify(x, g(x), modules=(n2, "sympy")) # previously gave 'second f' assert if1(1) == 'first f' assert if2(1) == 'function g' def test_namespace_type(): # lambdify had a bug where it would reject modules of type unicode # on Python 2. x = sympy.Symbol('x') lambdify(x, x, modules='math') def test_imps(): # Here we check if the default returned functions are anonymous - in # the sense that we can have more than one function with the same name f = implemented_function('f', lambda x: 2*x) g = implemented_function('f', lambda x: math.sqrt(x)) l1 = lambdify(x, f(x)) l2 = lambdify(x, g(x)) assert str(f(x)) == str(g(x)) assert l1(3) == 6 assert l2(3) == math.sqrt(3) # check that we can pass in a Function as input func = sympy.Function('myfunc') assert not hasattr(func, '_imp_') my_f = implemented_function(func, lambda x: 2*x) assert hasattr(my_f, '_imp_') # Error for functions with same name and different implementation f2 = implemented_function("f", lambda x: x + 101) raises(ValueError, lambda: lambdify(x, f(f2(x)))) def test_imps_errors(): # Test errors that implemented functions can return, and still be able to # form expressions. # See: https://github.com/sympy/sympy/issues/10810 # # XXX: Removed AttributeError here. This test was added due to issue 10810 # but that issue was about ValueError. It doesn't seem reasonable to # "support" catching AttributeError in the same context... for val, error_class in product((0, 0., 2, 2.0), (TypeError, ValueError)): def myfunc(a): if a == 0: raise error_class return 1 f = implemented_function('f', myfunc) expr = f(val) assert expr == f(val) def test_imps_wrong_args(): raises(ValueError, lambda: implemented_function(sin, lambda x: x)) def test_lambdify_imps(): # Test lambdify with implemented functions # first test basic (sympy) lambdify f = sympy.cos assert lambdify(x, f(x))(0) == 1 assert lambdify(x, 1 + f(x))(0) == 2 assert lambdify((x, y), y + f(x))(0, 1) == 2 # make an implemented function and test f = implemented_function("f", lambda x: x + 100) assert lambdify(x, f(x))(0) == 100 assert lambdify(x, 1 + f(x))(0) == 101 assert lambdify((x, y), y + f(x))(0, 1) == 101 # Can also handle tuples, lists, dicts as expressions lam = lambdify(x, (f(x), x)) assert lam(3) == (103, 3) lam = lambdify(x, [f(x), x]) assert lam(3) == [103, 3] lam = lambdify(x, [f(x), (f(x), x)]) assert lam(3) == [103, (103, 3)] lam = lambdify(x, {f(x): x}) assert lam(3) == {103: 3} lam = lambdify(x, {f(x): x}) assert lam(3) == {103: 3} lam = lambdify(x, {x: f(x)}) assert lam(3) == {3: 103} # Check that imp preferred to other namespaces by default d = {'f': lambda x: x + 99} lam = lambdify(x, f(x), d) assert lam(3) == 103 # Unless flag passed lam = lambdify(x, f(x), d, use_imps=False) assert lam(3) == 102 def test_dummification(): t = symbols('t') F = Function('F') G = Function('G') #"\alpha" is not a valid python variable name #lambdify should sub in a dummy for it, and return #without a syntax error alpha = symbols(r'\alpha') some_expr = 2 * F(t)**2 / G(t) lam = lambdify((F(t), G(t)), some_expr) assert lam(3, 9) == 2 lam = lambdify(sin(t), 2 * sin(t)**2) assert lam(F(t)) == 2 * F(t)**2 #Test that \alpha was properly dummified lam = lambdify((alpha, t), 2*alpha + t) assert lam(2, 1) == 5 raises(SyntaxError, lambda: lambdify(F(t) * G(t), F(t) * G(t) + 5)) raises(SyntaxError, lambda: lambdify(2 * F(t), 2 * F(t) + 5)) raises(SyntaxError, lambda: lambdify(2 * F(t), 4 * F(t) + 5)) def test_curly_matrix_symbol(): # Issue #15009 curlyv = sympy.MatrixSymbol("{v}", 2, 1) lam = lambdify(curlyv, curlyv) assert lam(1)==1 lam = lambdify(curlyv, curlyv, dummify=True) assert lam(1)==1 def test_python_keywords(): # Test for issue 7452. The automatic dummification should ensure use of # Python reserved keywords as symbol names will create valid lambda # functions. This is an additional regression test. python_if = symbols('if') expr = python_if / 2 f = lambdify(python_if, expr) assert f(4.0) == 2.0 def test_lambdify_docstring(): func = lambdify((w, x, y, z), w + x + y + z) ref = ( "Created with lambdify. Signature:\n\n" "func(w, x, y, z)\n\n" "Expression:\n\n" "w + x + y + z" ).splitlines() assert func.__doc__.splitlines()[:len(ref)] == ref syms = symbols('a1:26') func = lambdify(syms, sum(syms)) ref = ( "Created with lambdify. Signature:\n\n" "func(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15,\n" " a16, a17, a18, a19, a20, a21, a22, a23, a24, a25)\n\n" "Expression:\n\n" "a1 + a10 + a11 + a12 + a13 + a14 + a15 + a16 + a17 + a18 + a19 + a2 + a20 +..." ).splitlines() assert func.__doc__.splitlines()[:len(ref)] == ref #================== Test special printers ========================== def test_special_printers(): from sympy.polys.numberfields import IntervalPrinter def intervalrepr(expr): return IntervalPrinter().doprint(expr) expr = sqrt(sqrt(2) + sqrt(3)) + S.Half func0 = lambdify((), expr, modules="mpmath", printer=intervalrepr) func1 = lambdify((), expr, modules="mpmath", printer=IntervalPrinter) func2 = lambdify((), expr, modules="mpmath", printer=IntervalPrinter()) mpi = type(mpmath.mpi(1, 2)) assert isinstance(func0(), mpi) assert isinstance(func1(), mpi) assert isinstance(func2(), mpi) # To check Is lambdify loggamma works for mpmath or not exp1 = lambdify(x, loggamma(x), 'mpmath')(5) exp2 = lambdify(x, loggamma(x), 'mpmath')(1.8) exp3 = lambdify(x, loggamma(x), 'mpmath')(15) exp_ls = [exp1, exp2, exp3] sol1 = mpmath.loggamma(5) sol2 = mpmath.loggamma(1.8) sol3 = mpmath.loggamma(15) sol_ls = [sol1, sol2, sol3] assert exp_ls == sol_ls def test_true_false(): # We want exact is comparison here, not just == assert lambdify([], true)() is True assert lambdify([], false)() is False def test_issue_2790(): assert lambdify((x, (y, z)), x + y)(1, (2, 4)) == 3 assert lambdify((x, (y, (w, z))), w + x + y + z)(1, (2, (3, 4))) == 10 assert lambdify(x, x + 1, dummify=False)(1) == 2 def test_issue_12092(): f = implemented_function('f', lambda x: x**2) assert f(f(2)).evalf() == Float(16) def test_issue_14911(): class Variable(sympy.Symbol): def _sympystr(self, printer): return printer.doprint(self.name) _lambdacode = _sympystr _numpycode = _sympystr x = Variable('x') y = 2 * x code = LambdaPrinter().doprint(y) assert code.replace(' ', '') == '2*x' def test_ITE(): assert lambdify((x, y, z), ITE(x, y, z))(True, 5, 3) == 5 assert lambdify((x, y, z), ITE(x, y, z))(False, 5, 3) == 3 def test_Min_Max(): # see gh-10375 assert lambdify((x, y, z), Min(x, y, z))(1, 2, 3) == 1 assert lambdify((x, y, z), Max(x, y, z))(1, 2, 3) == 3 def test_Indexed(): # Issue #10934 if not numpy: skip("numpy not installed") a = IndexedBase('a') i, j = symbols('i j') b = numpy.array([[1, 2], [3, 4]]) assert lambdify(a, Sum(a[x, y], (x, 0, 1), (y, 0, 1)))(b) == 10 def test_issue_12173(): #test for issue 12173 expr1 = lambdify((x, y), uppergamma(x, y),"mpmath")(1, 2) expr2 = lambdify((x, y), lowergamma(x, y),"mpmath")(1, 2) assert expr1 == uppergamma(1, 2).evalf() assert expr2 == lowergamma(1, 2).evalf() def test_issue_13642(): if not numpy: skip("numpy not installed") f = lambdify(x, sinc(x)) assert Abs(f(1) - sinc(1)).n() < 1e-15 def test_sinc_mpmath(): f = lambdify(x, sinc(x), "mpmath") assert Abs(f(1) - sinc(1)).n() < 1e-15 def test_lambdify_dummy_arg(): d1 = Dummy() f1 = lambdify(d1, d1 + 1, dummify=False) assert f1(2) == 3 f1b = lambdify(d1, d1 + 1) assert f1b(2) == 3 d2 = Dummy('x') f2 = lambdify(d2, d2 + 1) assert f2(2) == 3 f3 = lambdify([[d2]], d2 + 1) assert f3([2]) == 3 def test_lambdify_mixed_symbol_dummy_args(): d = Dummy() # Contrived example of name clash dsym = symbols(str(d)) f = lambdify([d, dsym], d - dsym) assert f(4, 1) == 3 def test_numpy_array_arg(): # Test for issue 14655 (numpy part) if not numpy: skip("numpy not installed") f = lambdify([[x, y]], x*x + y, 'numpy') assert f(numpy.array([2.0, 1.0])) == 5 def test_scipy_fns(): if not scipy: skip("scipy not installed") single_arg_sympy_fns = [erf, erfc, factorial, gamma, loggamma, digamma] single_arg_scipy_fns = [scipy.special.erf, scipy.special.erfc, scipy.special.factorial, scipy.special.gamma, scipy.special.gammaln, scipy.special.psi] numpy.random.seed(0) for (sympy_fn, scipy_fn) in zip(single_arg_sympy_fns, single_arg_scipy_fns): f = lambdify(x, sympy_fn(x), modules="scipy") for i in range(20): tv = numpy.random.uniform(-10, 10) + 1j*numpy.random.uniform(-5, 5) # SciPy thinks that factorial(z) is 0 when re(z) < 0 and # does not support complex numbers. # SymPy does not think so. if sympy_fn == factorial: tv = numpy.abs(tv) # SciPy supports gammaln for real arguments only, # and there is also a branch cut along the negative real axis if sympy_fn == loggamma: tv = numpy.abs(tv) # SymPy's digamma evaluates as polygamma(0, z) # which SciPy supports for real arguments only if sympy_fn == digamma: tv = numpy.real(tv) sympy_result = sympy_fn(tv).evalf() assert abs(f(tv) - sympy_result) < 1e-13*(1 + abs(sympy_result)) assert abs(f(tv) - scipy_fn(tv)) < 1e-13*(1 + abs(sympy_result)) double_arg_sympy_fns = [RisingFactorial, besselj, bessely, besseli, besselk] double_arg_scipy_fns = [scipy.special.poch, scipy.special.jv, scipy.special.yv, scipy.special.iv, scipy.special.kv] for (sympy_fn, scipy_fn) in zip(double_arg_sympy_fns, double_arg_scipy_fns): f = lambdify((x, y), sympy_fn(x, y), modules="scipy") for i in range(20): # SciPy supports only real orders of Bessel functions tv1 = numpy.random.uniform(-10, 10) tv2 = numpy.random.uniform(-10, 10) + 1j*numpy.random.uniform(-5, 5) # SciPy supports poch for real arguments only if sympy_fn == RisingFactorial: tv2 = numpy.real(tv2) sympy_result = sympy_fn(tv1, tv2).evalf() assert abs(f(tv1, tv2) - sympy_result) < 1e-13*(1 + abs(sympy_result)) assert abs(f(tv1, tv2) - scipy_fn(tv1, tv2)) < 1e-13*(1 + abs(sympy_result)) def test_scipy_polys(): if not scipy: skip("scipy not installed") numpy.random.seed(0) params = symbols('n k a b') # list polynomials with the number of parameters polys = [ (chebyshevt, 1), (chebyshevu, 1), (legendre, 1), (hermite, 1), (laguerre, 1), (gegenbauer, 2), (assoc_legendre, 2), (assoc_laguerre, 2), (jacobi, 3) ] msg = \ "The random test of the function {func} with the arguments " \ "{args} had failed because the SymPy result {sympy_result} " \ "and SciPy result {scipy_result} had failed to converge " \ "within the tolerance {tol} " \ "(Actual absolute difference : {diff})" for sympy_fn, num_params in polys: args = params[:num_params] + (x,) f = lambdify(args, sympy_fn(*args)) for _ in range(10): tn = numpy.random.randint(3, 10) tparams = tuple(numpy.random.uniform(0, 5, size=num_params-1)) tv = numpy.random.uniform(-10, 10) + 1j*numpy.random.uniform(-5, 5) # SciPy supports hermite for real arguments only if sympy_fn == hermite: tv = numpy.real(tv) # assoc_legendre needs x in (-1, 1) and integer param at most n if sympy_fn == assoc_legendre: tv = numpy.random.uniform(-1, 1) tparams = tuple(numpy.random.randint(1, tn, size=1)) vals = (tn,) + tparams + (tv,) scipy_result = f(*vals) sympy_result = sympy_fn(*vals).evalf() atol = 1e-9*(1 + abs(sympy_result)) diff = abs(scipy_result - sympy_result) try: assert diff < atol except TypeError: raise AssertionError( msg.format( func=repr(sympy_fn), args=repr(vals), sympy_result=repr(sympy_result), scipy_result=repr(scipy_result), diff=diff, tol=atol) ) def test_lambdify_inspect(): f = lambdify(x, x**2) # Test that inspect.getsource works but don't hard-code implementation # details assert 'x**2' in inspect.getsource(f) def test_issue_14941(): x, y = Dummy(), Dummy() # test dict f1 = lambdify([x, y], {x: 3, y: 3}, 'sympy') assert f1(2, 3) == {2: 3, 3: 3} # test tuple f2 = lambdify([x, y], (y, x), 'sympy') assert f2(2, 3) == (3, 2) # test list f3 = lambdify([x, y], [y, x], 'sympy') assert f3(2, 3) == [3, 2] def test_lambdify_Derivative_arg_issue_16468(): f = Function('f')(x) fx = f.diff() assert lambdify((f, fx), f + fx)(10, 5) == 15 assert eval(lambdastr((f, fx), f/fx))(10, 5) == 2 raises(SyntaxError, lambda: eval(lambdastr((f, fx), f/fx, dummify=False))) assert eval(lambdastr((f, fx), f/fx, dummify=True))(10, 5) == 2 assert eval(lambdastr((fx, f), f/fx, dummify=True))(S(10), 5) == S.Half assert lambdify(fx, 1 + fx)(41) == 42 assert eval(lambdastr(fx, 1 + fx, dummify=True))(41) == 42 def test_imag_real(): f_re = lambdify([z], sympy.re(z)) val = 3+2j assert f_re(val) == val.real f_im = lambdify([z], sympy.im(z)) # see #15400 assert f_im(val) == val.imag def test_MatrixSymbol_issue_15578(): if not numpy: skip("numpy not installed") A = MatrixSymbol('A', 2, 2) A0 = numpy.array([[1, 2], [3, 4]]) f = lambdify(A, A**(-1)) assert numpy.allclose(f(A0), numpy.array([[-2., 1.], [1.5, -0.5]])) g = lambdify(A, A**3) assert numpy.allclose(g(A0), numpy.array([[37, 54], [81, 118]])) def test_issue_15654(): if not scipy: skip("scipy not installed") from sympy.abc import n, l, r, Z from sympy.physics import hydrogen nv, lv, rv, Zv = 1, 0, 3, 1 sympy_value = hydrogen.R_nl(nv, lv, rv, Zv).evalf() f = lambdify((n, l, r, Z), hydrogen.R_nl(n, l, r, Z)) scipy_value = f(nv, lv, rv, Zv) assert abs(sympy_value - scipy_value) < 1e-15 def test_issue_15827(): if not numpy: skip("numpy not installed") A = MatrixSymbol("A", 3, 3) B = MatrixSymbol("B", 2, 3) C = MatrixSymbol("C", 3, 4) D = MatrixSymbol("D", 4, 5) k=symbols("k") f = lambdify(A, (2*k)*A) g = lambdify(A, (2+k)*A) h = lambdify(A, 2*A) i = lambdify((B, C, D), 2*B*C*D) assert numpy.array_equal(f(numpy.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])), \ numpy.array([[2*k, 4*k, 6*k], [2*k, 4*k, 6*k], [2*k, 4*k, 6*k]], dtype=object)) assert numpy.array_equal(g(numpy.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])), \ numpy.array([[k + 2, 2*k + 4, 3*k + 6], [k + 2, 2*k + 4, 3*k + 6], \ [k + 2, 2*k + 4, 3*k + 6]], dtype=object)) assert numpy.array_equal(h(numpy.array([[1, 2, 3], [1, 2, 3], [1, 2, 3]])), \ numpy.array([[2, 4, 6], [2, 4, 6], [2, 4, 6]])) assert numpy.array_equal(i(numpy.array([[1, 2, 3], [1, 2, 3]]), numpy.array([[1, 2, 3, 4], [1, 2, 3, 4], [1, 2, 3, 4]]), \ numpy.array([[1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5], [1, 2, 3, 4, 5]])), numpy.array([[ 120, 240, 360, 480, 600], \ [ 120, 240, 360, 480, 600]])) def test_issue_16930(): if not scipy: skip("scipy not installed") x = symbols("x") f = lambda x: S.GoldenRatio * x**2 f_ = lambdify(x, f(x), modules='scipy') assert f_(1) == scipy.constants.golden_ratio def test_issue_17898(): if not scipy: skip("scipy not installed") x = symbols("x") f_ = lambdify([x], sympy.LambertW(x,-1), modules='scipy') assert f_(0.1) == mpmath.lambertw(0.1, -1) def test_issue_13167_21411(): if not numpy: skip("numpy not installed") f1 = lambdify(x, sympy.Heaviside(x)) f2 = lambdify(x, sympy.Heaviside(x, 1)) res1 = f1([-1, 0, 1]) res2 = f2([-1, 0, 1]) assert Abs(res1[0]).n() < 1e-15 # First functionality: only one argument passed assert Abs(res1[1] - 1/2).n() < 1e-15 assert Abs(res1[2] - 1).n() < 1e-15 assert Abs(res2[0]).n() < 1e-15 # Second functionality: two arguments passed assert Abs(res2[1] - 1).n() < 1e-15 assert Abs(res2[2] - 1).n() < 1e-15 def test_single_e(): f = lambdify(x, E) assert f(23) == exp(1.0) def test_issue_16536(): if not scipy: skip("scipy not installed") a = symbols('a') f1 = lowergamma(a, x) F = lambdify((a, x), f1, modules='scipy') assert abs(lowergamma(1, 3) - F(1, 3)) <= 1e-10 f2 = uppergamma(a, x) F = lambdify((a, x), f2, modules='scipy') assert abs(uppergamma(1, 3) - F(1, 3)) <= 1e-10 def test_fresnel_integrals_scipy(): if not scipy: skip("scipy not installed") f1 = fresnelc(x) f2 = fresnels(x) F1 = lambdify(x, f1, modules='scipy') F2 = lambdify(x, f2, modules='scipy') assert abs(fresnelc(1.3) - F1(1.3)) <= 1e-10 assert abs(fresnels(1.3) - F2(1.3)) <= 1e-10 def test_beta_scipy(): if not scipy: skip("scipy not installed") f = beta(x, y) F = lambdify((x, y), f, modules='scipy') assert abs(beta(1.3, 2.3) - F(1.3, 2.3)) <= 1e-10 def test_beta_math(): f = beta(x, y) F = lambdify((x, y), f, modules='math') assert abs(beta(1.3, 2.3) - F(1.3, 2.3)) <= 1e-10 def test_betainc_scipy(): if not scipy: skip("scipy not installed") f = betainc(w, x, y, z) F = lambdify((w, x, y, z), f, modules='scipy') assert abs(betainc(1.4, 3.1, 0.1, 0.5) - F(1.4, 3.1, 0.1, 0.5)) <= 1e-10 def test_betainc_regularized_scipy(): if not scipy: skip("scipy not installed") f = betainc_regularized(w, x, y, z) F = lambdify((w, x, y, z), f, modules='scipy') assert abs(betainc_regularized(0.2, 3.5, 0.1, 1) - F(0.2, 3.5, 0.1, 1)) <= 1e-10 def test_numpy_special_math(): if not numpy: skip("numpy not installed") funcs = [expm1, log1p, exp2, log2, log10, hypot, logaddexp, logaddexp2] for func in funcs: if 2 in func.nargs: expr = func(x, y) args = (x, y) num_args = (0.3, 0.4) elif 1 in func.nargs: expr = func(x) args = (x,) num_args = (0.3,) else: raise NotImplementedError("Need to handle other than unary & binary functions in test") f = lambdify(args, expr) result = f(*num_args) reference = expr.subs(dict(zip(args, num_args))).evalf() assert numpy.allclose(result, float(reference)) lae2 = lambdify((x, y), logaddexp2(log2(x), log2(y))) assert abs(2.0**lae2(1e-50, 2.5e-50) - 3.5e-50) < 1e-62 # from NumPy's docstring def test_scipy_special_math(): if not scipy: skip("scipy not installed") cm1 = lambdify((x,), cosm1(x), modules='scipy') assert abs(cm1(1e-20) + 5e-41) < 1e-200 def test_cupy_array_arg(): if not cupy: skip("CuPy not installed") f = lambdify([[x, y]], x*x + y, 'cupy') result = f(cupy.array([2.0, 1.0])) assert result == 5 assert "cupy" in str(type(result)) def test_cupy_array_arg_using_numpy(): # numpy functions can be run on cupy arrays # unclear if we can "officialy" support this, # depends on numpy __array_function__ support if not cupy: skip("CuPy not installed") f = lambdify([[x, y]], x*x + y, 'numpy') result = f(cupy.array([2.0, 1.0])) assert result == 5 assert "cupy" in str(type(result)) def test_cupy_dotproduct(): if not cupy: skip("CuPy not installed") A = Matrix([x, y, z]) f1 = lambdify([x, y, z], DotProduct(A, A), modules='cupy') f2 = lambdify([x, y, z], DotProduct(A, A.T), modules='cupy') f3 = lambdify([x, y, z], DotProduct(A.T, A), modules='cupy') f4 = lambdify([x, y, z], DotProduct(A, A.T), modules='cupy') assert f1(1, 2, 3) == \ f2(1, 2, 3) == \ f3(1, 2, 3) == \ f4(1, 2, 3) == \ cupy.array([14]) def test_lambdify_cse(): def dummy_cse(exprs): return (), exprs def minmem(exprs): from sympy.simplify.cse_main import cse_release_variables, cse return cse(exprs, postprocess=cse_release_variables) class Case: def __init__(self, *, args, exprs, num_args, requires_numpy=False): self.args = args self.exprs = exprs self.num_args = num_args subs_dict = dict(zip(self.args, self.num_args)) self.ref = [e.subs(subs_dict).evalf() for e in exprs] self.requires_numpy = requires_numpy def lambdify(self, *, cse): return lambdify(self.args, self.exprs, cse=cse) def assertAllClose(self, result, *, abstol=1e-15, reltol=1e-15): if self.requires_numpy: assert all(numpy.allclose(result[i], numpy.asarray(r, dtype=float), rtol=reltol, atol=abstol) for i, r in enumerate(self.ref)) return for i, r in enumerate(self.ref): abs_err = abs(result[i] - r) if r == 0: assert abs_err < abstol else: assert abs_err/abs(r) < reltol cases = [ Case( args=(x, y, z), exprs=[ x + y + z, x + y - z, 2*x + 2*y - z, (x+y)**2 + (y+z)**2, ], num_args=(2., 3., 4.) ), Case( args=(x, y, z), exprs=[ x + sympy.Heaviside(x), y + sympy.Heaviside(x), z + sympy.Heaviside(x, 1), z/sympy.Heaviside(x, 1) ], num_args=(0., 3., 4.) ), Case( args=(x, y, z), exprs=[ x + sinc(y), y + sinc(y), z - sinc(y) ], num_args=(0.1, 0.2, 0.3) ), Case( args=(x, y, z), exprs=[ Matrix([[x, x*y], [sin(z) + 4, x**z]]), x*y+sin(z)-x**z, Matrix([x*x, sin(z), x**z]) ], num_args=(1.,2.,3.), requires_numpy=True ), Case( args=(x, y), exprs=[(x + y - 1)**2, x, x + y, (x + y)/(2*x + 1) + (x + y - 1)**2, (2*x + 1)**(x + y)], num_args=(1,2) ) ] for case in cases: if not numpy and case.requires_numpy: continue for cse in [False, True, minmem, dummy_cse]: f = case.lambdify(cse=cse) result = f(*case.num_args) case.assertAllClose(result) sympy-sympy-1.9/sympy/utilities/tests/test_matchpy_connector.py000066400000000000000000000075111412543434000254150ustar00rootroot00000000000000from sympy import symbols, cos, sin, S, Eq, Equality, sqrt, Ne from sympy.external import import_module from sympy.testing.pytest import skip from sympy.utilities.matchpy_connector import WildDot, WildPlus, WildStar, Replacer matchpy = import_module("matchpy") x, y, z = symbols("x y z") def _get_first_match(expr, pattern): from matchpy import ManyToOneMatcher, Pattern matcher = ManyToOneMatcher() matcher.add(Pattern(pattern)) return next(iter(matcher.match(expr))) def test_matchpy_connector(): if matchpy is None: skip("matchpy not installed") from multiset import Multiset from matchpy import Pattern, Substitution w_ = WildDot("w_") w__ = WildPlus("w__") w___ = WildStar("w___") expr = x + y pattern = x + w_ p, subst = _get_first_match(expr, pattern) assert p == Pattern(pattern) assert subst == Substitution({'w_': y}) expr = x + y + z pattern = x + w__ p, subst = _get_first_match(expr, pattern) assert p == Pattern(pattern) assert subst == Substitution({'w__': Multiset([y, z])}) expr = x + y + z pattern = x + y + z + w___ p, subst = _get_first_match(expr, pattern) assert p == Pattern(pattern) assert subst == Substitution({'w___': Multiset()}) def test_matchpy_optional(): if matchpy is None: skip("matchpy not installed") from matchpy import Pattern, Substitution from matchpy import ManyToOneReplacer, ReplacementRule p = WildDot("p", optional=1) q = WildDot("q", optional=0) pattern = p*x + q expr1 = 2*x pa, subst = _get_first_match(expr1, pattern) assert pa == Pattern(pattern) assert subst == Substitution({'p': 2, 'q': 0}) expr2 = x + 3 pa, subst = _get_first_match(expr2, pattern) assert pa == Pattern(pattern) assert subst == Substitution({'p': 1, 'q': 3}) expr3 = x pa, subst = _get_first_match(expr3, pattern) assert pa == Pattern(pattern) assert subst == Substitution({'p': 1, 'q': 0}) expr4 = x*y + z pa, subst = _get_first_match(expr4, pattern) assert pa == Pattern(pattern) assert subst == Substitution({'p': y, 'q': z}) replacer = ManyToOneReplacer() replacer.add(ReplacementRule(Pattern(pattern), lambda p, q: sin(p)*cos(q))) assert replacer.replace(expr1) == sin(2)*cos(0) assert replacer.replace(expr2) == sin(1)*cos(3) assert replacer.replace(expr3) == sin(1)*cos(0) assert replacer.replace(expr4) == sin(y)*cos(z) def test_replacer(): if matchpy is None: skip("matchpy not installed") x1_ = WildDot("x1_") x2_ = WildDot("x2_") a_ = WildDot("a_", optional=S.One) b_ = WildDot("b_", optional=S.One) c_ = WildDot("c_", optional=S.Zero) replacer = Replacer(common_constraints=[ matchpy.CustomConstraint(lambda a_: not a_.has(x)), matchpy.CustomConstraint(lambda b_: not b_.has(x)), matchpy.CustomConstraint(lambda c_: not c_.has(x)), ]) # Rewrite the equation into implicit form, unless it's already solved: replacer.add(Eq(x1_, x2_), Eq(x1_ - x2_, 0), conditions_nonfalse=[Ne(x2_, 0), Ne(x1_, 0), Ne(x1_, x), Ne(x2_, x)]) # Simple equation solver for real numbers: replacer.add(Equality(a_*x + b_, 0), Equality(x, -b_/a_)) disc = b_**2 - 4*a_*c_ replacer.add( Equality(a_*x**2 + b_*x + c_, 0), Eq(x, (-b_ - sqrt(disc))/(2*a_)) | Eq(x, (-b_ + sqrt(disc))/(2*a_)), conditions_nonfalse=[disc >= 0] ) replacer.add( Equality(a_*x**2 + c_, 0), Eq(x, sqrt(-c_/a_)) | Eq(x, -sqrt(-c_/a_)), conditions_nonfalse=[-c_*a_ > 0] ) assert replacer.replace(Eq(3*x, y)) == Eq(x, y/3) assert replacer.replace(Eq(x**2 + 1, 0)) == Eq(x**2 + 1, 0) assert replacer.replace(Eq(x**2, 4)) == (Eq(x, 2) | Eq(x, -2)) assert replacer.replace(Eq(x**2 + 4*y*x + 4*y**2, 0)) == Eq(x, -2*y) sympy-sympy-1.9/sympy/utilities/tests/test_misc.py000066400000000000000000000065071412543434000226350ustar00rootroot00000000000000from textwrap import dedent import sys from subprocess import Popen, PIPE import os from sympy.utilities.misc import translate, replace, ordinal, rawlines, strlines def test_translate(): abc = 'abc' translate(abc, None, 'a') == 'bc' translate(abc, None, '') == 'abc' translate(abc, {'a': 'x'}, 'c') == 'xb' assert translate(abc, {'a': 'bc'}, 'c') == 'bcb' assert translate(abc, {'ab': 'x'}, 'c') == 'x' assert translate(abc, {'ab': ''}, 'c') == '' assert translate(abc, {'bc': 'x'}, 'c') == 'ab' assert translate(abc, {'abc': 'x', 'a': 'y'}) == 'x' u = chr(4096) assert translate(abc, 'a', 'x', u) == 'xbc' assert (u in translate(abc, 'a', u, u)) is True def test_replace(): assert replace('abc', ('a', 'b')) == 'bbc' assert replace('abc', {'a': 'Aa'}) == 'Aabc' assert replace('abc', ('a', 'b'), ('c', 'C')) == 'bbC' def test_ordinal(): assert ordinal(-1) == '-1st' assert ordinal(0) == '0th' assert ordinal(1) == '1st' assert ordinal(2) == '2nd' assert ordinal(3) == '3rd' assert all(ordinal(i).endswith('th') for i in range(4, 21)) assert ordinal(100) == '100th' assert ordinal(101) == '101st' assert ordinal(102) == '102nd' assert ordinal(103) == '103rd' assert ordinal(104) == '104th' assert ordinal(200) == '200th' assert all(ordinal(i) == str(i) + 'th' for i in range(-220, -203)) def test_rawlines(): assert rawlines('a a\na') == "dedent('''\\\n a a\n a''')" assert rawlines('a a') == "'a a'" assert rawlines(strlines('\\le"ft')) == ( '(\n' " '(\\n'\n" ' \'r\\\'\\\\le"ft\\\'\\n\'\n' " ')'\n" ')') def test_strlines(): q = 'this quote (") is in the middle' # the following assert rhs was prepared with # print(rawlines(strlines(q, 10))) assert strlines(q, 10) == dedent('''\ ( 'this quo' 'te (") i' 's in the' ' middle' )''') assert q == ( 'this quo' 'te (") i' 's in the' ' middle' ) q = "this quote (') is in the middle" assert strlines(q, 20) == dedent('''\ ( "this quote (') is " "in the middle" )''') assert strlines('\\left') == ( '(\n' "r'\\left'\n" ')') assert strlines('\\left', short=True) == r"r'\left'" assert strlines('\\le"ft') == ( '(\n' 'r\'\\le"ft\'\n' ')') q = 'this\nother line' assert strlines(q) == rawlines(q) def test_translate_args(): try: translate(None, None, None, 'not_none') except ValueError: pass # Exception raised successfully else: assert False assert translate('s', None, None, None) == 's' try: translate('s', 'a', 'bc') except ValueError: pass # Exception raised successfully else: assert False def test_debug_output(): env = os.environ.copy() env['SYMPY_DEBUG'] = 'True' cmd = 'from sympy import *; x = Symbol("x"); print(integrate((1-cos(x))/x, x))' cmdline = [sys.executable, '-c', cmd] proc = Popen(cmdline, env=env, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() out = out.decode('ascii') # utf-8? err = err.decode('ascii') expected = 'substituted: -x*(1 - cos(x)), u: 1/x, u_var: _u' assert expected in err, err sympy-sympy-1.9/sympy/utilities/tests/test_pickling.py000066400000000000000000000546231412543434000235040ustar00rootroot00000000000000import inspect import copy import pickle from sympy.physics.units import meter from sympy.testing.pytest import XFAIL, raises from sympy.core.basic import Atom, Basic from sympy.core.core import BasicMeta from sympy.core.singleton import SingletonRegistry from sympy.core.symbol import Str, Dummy, Symbol, Wild from sympy.core.numbers import (E, I, pi, oo, zoo, nan, Integer, Rational, Float) from sympy.core.relational import (Equality, GreaterThan, LessThan, Relational, StrictGreaterThan, StrictLessThan, Unequality) from sympy.core.add import Add from sympy.core.mul import Mul from sympy.core.power import Pow from sympy.core.function import Derivative, Function, FunctionClass, Lambda, \ WildFunction from sympy.sets.sets import Interval from sympy.core.multidimensional import vectorize from sympy.core.compatibility import HAS_GMPY from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy import symbols, S from sympy.external import import_module cloudpickle = import_module('cloudpickle') excluded_attrs = { '_assumptions', # This is a local cache that isn't automatically filled on creation '_mhash', # Cached after __hash__ is called but set to None after creation 'is_EmptySet', # Deprecated from SymPy 1.5. This can be removed when is_EmptySet is removed. 'expr_free_symbols', # Deprecated from SymPy 1.9. This can be removed when exr_free_symbols is removed. '_mat', # Deprecated from SymPy 1.9. This can be removed when Matrix._mat is removed '_smat', # Deprecated from SymPy 1.9. This can be removed when SparseMatrix._smat is removed } def check(a, exclude=[], check_attr=True): """ Check that pickling and copying round-trips. """ # Pickling with protocols 0 and 1 is disabled for Basic instances: if isinstance(a, Basic): for protocol in [0, 1]: raises(NotImplementedError, lambda: pickle.dumps(a, protocol)) protocols = [2, copy.copy, copy.deepcopy, 3, 4] if cloudpickle: protocols.extend([cloudpickle]) for protocol in protocols: if protocol in exclude: continue if callable(protocol): if isinstance(a, BasicMeta): # Classes can't be copied, but that's okay. continue b = protocol(a) elif inspect.ismodule(protocol): b = protocol.loads(protocol.dumps(a)) else: b = pickle.loads(pickle.dumps(a, protocol)) d1 = dir(a) d2 = dir(b) assert set(d1) == set(d2) if not check_attr: continue def c(a, b, d): for i in d: if i in excluded_attrs: continue if not hasattr(a, i): continue attr = getattr(a, i) if not hasattr(attr, "__call__"): assert hasattr(b, i), i assert getattr(b, i) == attr, "%s != %s, protocol: %s" % (getattr(b, i), attr, protocol) c(a, b, d1) c(b, a, d2) #================== core ========================= def test_core_basic(): for c in (Atom, Atom(), Basic, Basic(), # XXX: dynamically created types are not picklable # BasicMeta, BasicMeta("test", (), {}), SingletonRegistry, S): check(c) def test_core_Str(): check(Str('x')) def test_core_symbol(): # make the Symbol a unique name that doesn't class with any other # testing variable in this file since after this test the symbol # having the same name will be cached as noncommutative for c in (Dummy, Dummy("x", commutative=False), Symbol, Symbol("_issue_3130", commutative=False), Wild, Wild("x")): check(c) def test_core_numbers(): for c in (Integer(2), Rational(2, 3), Float("1.2")): check(c) def test_core_float_copy(): # See gh-7457 y = Symbol("x") + 1.0 check(y) # does not raise TypeError ("argument is not an mpz") def test_core_relational(): x = Symbol("x") y = Symbol("y") for c in (Equality, Equality(x, y), GreaterThan, GreaterThan(x, y), LessThan, LessThan(x, y), Relational, Relational(x, y), StrictGreaterThan, StrictGreaterThan(x, y), StrictLessThan, StrictLessThan(x, y), Unequality, Unequality(x, y)): check(c) def test_core_add(): x = Symbol("x") for c in (Add, Add(x, 4)): check(c) def test_core_mul(): x = Symbol("x") for c in (Mul, Mul(x, 4)): check(c) def test_core_power(): x = Symbol("x") for c in (Pow, Pow(x, 4)): check(c) def test_core_function(): x = Symbol("x") for f in (Derivative, Derivative(x), Function, FunctionClass, Lambda, WildFunction): check(f) def test_core_undefinedfunctions(): f = Function("f") # Full XFAILed test below exclude = list(range(5)) # https://github.com/cloudpipe/cloudpickle/issues/65 # https://github.com/cloudpipe/cloudpickle/issues/190 exclude.append(cloudpickle) check(f, exclude=exclude) @XFAIL def test_core_undefinedfunctions_fail(): # This fails because f is assumed to be a class at sympy.basic.function.f f = Function("f") check(f) def test_core_interval(): for c in (Interval, Interval(0, 2)): check(c) def test_core_multidimensional(): for c in (vectorize, vectorize(0)): check(c) def test_Singletons(): protocols = [0, 1, 2, 3, 4] copiers = [copy.copy, copy.deepcopy] copiers += [lambda x: pickle.loads(pickle.dumps(x, proto)) for proto in protocols] if cloudpickle: copiers += [lambda x: cloudpickle.loads(cloudpickle.dumps(x))] for obj in (Integer(-1), Integer(0), Integer(1), Rational(1, 2), pi, E, I, oo, -oo, zoo, nan, S.GoldenRatio, S.TribonacciConstant, S.EulerGamma, S.Catalan, S.EmptySet, S.IdentityFunction): for func in copiers: assert func(obj) is obj #================== functions =================== from sympy.functions import (Piecewise, lowergamma, acosh, chebyshevu, chebyshevt, ln, chebyshevt_root, legendre, Heaviside, bernoulli, coth, tanh, assoc_legendre, sign, arg, asin, DiracDelta, re, rf, Abs, uppergamma, binomial, sinh, cos, cot, acos, acot, gamma, bell, hermite, harmonic, LambertW, zeta, log, factorial, asinh, acoth, cosh, dirichlet_eta, Eijk, loggamma, erf, ceiling, im, fibonacci, tribonacci, conjugate, tan, chebyshevu_root, floor, atanh, sqrt, sin, atan, ff, lucas, atan2, polygamma, exp) def test_functions(): one_var = (acosh, ln, Heaviside, factorial, bernoulli, coth, tanh, sign, arg, asin, DiracDelta, re, Abs, sinh, cos, cot, acos, acot, gamma, bell, harmonic, LambertW, zeta, log, factorial, asinh, acoth, cosh, dirichlet_eta, loggamma, erf, ceiling, im, fibonacci, tribonacci, conjugate, tan, floor, atanh, sin, atan, lucas, exp) two_var = (rf, ff, lowergamma, chebyshevu, chebyshevt, binomial, atan2, polygamma, hermite, legendre, uppergamma) x, y, z = symbols("x,y,z") others = (chebyshevt_root, chebyshevu_root, Eijk(x, y, z), Piecewise( (0, x < -1), (x**2, x <= 1), (x**3, True)), assoc_legendre) for cls in one_var: check(cls) c = cls(x) check(c) for cls in two_var: check(cls) c = cls(x, y) check(c) for cls in others: check(cls) #================== geometry ==================== from sympy.geometry.entity import GeometryEntity from sympy.geometry.point import Point from sympy.geometry.ellipse import Circle, Ellipse from sympy.geometry.line import Line, LinearEntity, Ray, Segment from sympy.geometry.polygon import Polygon, RegularPolygon, Triangle def test_geometry(): p1 = Point(1, 2) p2 = Point(2, 3) p3 = Point(0, 0) p4 = Point(0, 1) for c in ( GeometryEntity, GeometryEntity(), Point, p1, Circle, Circle(p1, 2), Ellipse, Ellipse(p1, 3, 4), Line, Line(p1, p2), LinearEntity, LinearEntity(p1, p2), Ray, Ray(p1, p2), Segment, Segment(p1, p2), Polygon, Polygon(p1, p2, p3, p4), RegularPolygon, RegularPolygon(p1, 4, 5), Triangle, Triangle(p1, p2, p3)): check(c, check_attr=False) #================== integrals ==================== from sympy.integrals.integrals import Integral def test_integrals(): x = Symbol("x") for c in (Integral, Integral(x)): check(c) #==================== logic ===================== from sympy.core.logic import Logic def test_logic(): for c in (Logic, Logic(1)): check(c) #================== matrices ==================== from sympy.matrices import Matrix, SparseMatrix def test_matrices(): for c in (Matrix, Matrix([1, 2, 3]), SparseMatrix, SparseMatrix([[1, 2], [3, 4]])): check(c) #================== ntheory ===================== from sympy.ntheory.generate import Sieve def test_ntheory(): for c in (Sieve, Sieve()): check(c) #================== physics ===================== from sympy.physics.paulialgebra import Pauli from sympy.physics.units import Unit def test_physics(): for c in (Unit, meter, Pauli, Pauli(1)): check(c) #================== plotting ==================== # XXX: These tests are not complete, so XFAIL them @XFAIL def test_plotting(): from sympy.plotting.pygletplot.color_scheme import ColorGradient, ColorScheme from sympy.plotting.pygletplot.managed_window import ManagedWindow from sympy.plotting.plot import Plot, ScreenShot from sympy.plotting.pygletplot.plot_axes import PlotAxes, PlotAxesBase, PlotAxesFrame, PlotAxesOrdinate from sympy.plotting.pygletplot.plot_camera import PlotCamera from sympy.plotting.pygletplot.plot_controller import PlotController from sympy.plotting.pygletplot.plot_curve import PlotCurve from sympy.plotting.pygletplot.plot_interval import PlotInterval from sympy.plotting.pygletplot.plot_mode import PlotMode from sympy.plotting.pygletplot.plot_modes import Cartesian2D, Cartesian3D, Cylindrical, \ ParametricCurve2D, ParametricCurve3D, ParametricSurface, Polar, Spherical from sympy.plotting.pygletplot.plot_object import PlotObject from sympy.plotting.pygletplot.plot_surface import PlotSurface from sympy.plotting.pygletplot.plot_window import PlotWindow for c in ( ColorGradient, ColorGradient(0.2, 0.4), ColorScheme, ManagedWindow, ManagedWindow, Plot, ScreenShot, PlotAxes, PlotAxesBase, PlotAxesFrame, PlotAxesOrdinate, PlotCamera, PlotController, PlotCurve, PlotInterval, PlotMode, Cartesian2D, Cartesian3D, Cylindrical, ParametricCurve2D, ParametricCurve3D, ParametricSurface, Polar, Spherical, PlotObject, PlotSurface, PlotWindow): check(c) @XFAIL def test_plotting2(): #from sympy.plotting.color_scheme import ColorGradient from sympy.plotting.pygletplot.color_scheme import ColorScheme #from sympy.plotting.managed_window import ManagedWindow from sympy.plotting.plot import Plot #from sympy.plotting.plot import ScreenShot from sympy.plotting.pygletplot.plot_axes import PlotAxes #from sympy.plotting.plot_axes import PlotAxesBase, PlotAxesFrame, PlotAxesOrdinate #from sympy.plotting.plot_camera import PlotCamera #from sympy.plotting.plot_controller import PlotController #from sympy.plotting.plot_curve import PlotCurve #from sympy.plotting.plot_interval import PlotInterval #from sympy.plotting.plot_mode import PlotMode #from sympy.plotting.plot_modes import Cartesian2D, Cartesian3D, Cylindrical, \ # ParametricCurve2D, ParametricCurve3D, ParametricSurface, Polar, Spherical #from sympy.plotting.plot_object import PlotObject #from sympy.plotting.plot_surface import PlotSurface # from sympy.plotting.plot_window import PlotWindow check(ColorScheme("rainbow")) check(Plot(1, visible=False)) check(PlotAxes()) #================== polys ======================= from sympy import Poly, ZZ, QQ, lex def test_pickling_polys_polytools(): from sympy.polys.polytools import PurePoly # from sympy.polys.polytools import GroebnerBasis x = Symbol('x') for c in (Poly, Poly(x, x)): check(c) for c in (PurePoly, PurePoly(x)): check(c) # TODO: fix pickling of Options class (see GroebnerBasis._options) # for c in (GroebnerBasis, GroebnerBasis([x**2 - 1], x, order=lex)): # check(c) def test_pickling_polys_polyclasses(): from sympy.polys.polyclasses import DMP, DMF, ANP for c in (DMP, DMP([[ZZ(1)], [ZZ(2)], [ZZ(3)]], ZZ)): check(c) for c in (DMF, DMF(([ZZ(1), ZZ(2)], [ZZ(1), ZZ(3)]), ZZ)): check(c) for c in (ANP, ANP([QQ(1), QQ(2)], [QQ(1), QQ(2), QQ(3)], QQ)): check(c) @XFAIL def test_pickling_polys_rings(): # NOTE: can't use protocols < 2 because we have to execute __new__ to # make sure caching of rings works properly. from sympy.polys.rings import PolyRing ring = PolyRing("x,y,z", ZZ, lex) for c in (PolyRing, ring): check(c, exclude=[0, 1]) for c in (ring.dtype, ring.one): check(c, exclude=[0, 1], check_attr=False) # TODO: Py3k def test_pickling_polys_fields(): pass # NOTE: can't use protocols < 2 because we have to execute __new__ to # make sure caching of fields works properly. # from sympy.polys.fields import FracField # field = FracField("x,y,z", ZZ, lex) # TODO: AssertionError: assert id(obj) not in self.memo # for c in (FracField, field): # check(c, exclude=[0, 1]) # TODO: AssertionError: assert id(obj) not in self.memo # for c in (field.dtype, field.one): # check(c, exclude=[0, 1]) def test_pickling_polys_elements(): from sympy.polys.domains.pythonrational import PythonRational #from sympy.polys.domains.pythonfinitefield import PythonFiniteField #from sympy.polys.domains.mpelements import MPContext for c in (PythonRational, PythonRational(1, 7)): check(c) #gf = PythonFiniteField(17) # TODO: fix pickling of ModularInteger # for c in (gf.dtype, gf(5)): # check(c) #mp = MPContext() # TODO: fix pickling of RealElement # for c in (mp.mpf, mp.mpf(1.0)): # check(c) # TODO: fix pickling of ComplexElement # for c in (mp.mpc, mp.mpc(1.0, -1.5)): # check(c) def test_pickling_polys_domains(): # from sympy.polys.domains.pythonfinitefield import PythonFiniteField from sympy.polys.domains.pythonintegerring import PythonIntegerRing from sympy.polys.domains.pythonrationalfield import PythonRationalField # TODO: fix pickling of ModularInteger # for c in (PythonFiniteField, PythonFiniteField(17)): # check(c) for c in (PythonIntegerRing, PythonIntegerRing()): check(c, check_attr=False) for c in (PythonRationalField, PythonRationalField()): check(c, check_attr=False) if HAS_GMPY: # from sympy.polys.domains.gmpyfinitefield import GMPYFiniteField from sympy.polys.domains.gmpyintegerring import GMPYIntegerRing from sympy.polys.domains.gmpyrationalfield import GMPYRationalField # TODO: fix pickling of ModularInteger # for c in (GMPYFiniteField, GMPYFiniteField(17)): # check(c) for c in (GMPYIntegerRing, GMPYIntegerRing()): check(c, check_attr=False) for c in (GMPYRationalField, GMPYRationalField()): check(c, check_attr=False) #from sympy.polys.domains.realfield import RealField #from sympy.polys.domains.complexfield import ComplexField from sympy.polys.domains.algebraicfield import AlgebraicField #from sympy.polys.domains.polynomialring import PolynomialRing #from sympy.polys.domains.fractionfield import FractionField from sympy.polys.domains.expressiondomain import ExpressionDomain # TODO: fix pickling of RealElement # for c in (RealField, RealField(100)): # check(c) # TODO: fix pickling of ComplexElement # for c in (ComplexField, ComplexField(100)): # check(c) for c in (AlgebraicField, AlgebraicField(QQ, sqrt(3))): check(c, check_attr=False) # TODO: AssertionError # for c in (PolynomialRing, PolynomialRing(ZZ, "x,y,z")): # check(c) # TODO: AttributeError: 'PolyElement' object has no attribute 'ring' # for c in (FractionField, FractionField(ZZ, "x,y,z")): # check(c) for c in (ExpressionDomain, ExpressionDomain()): check(c, check_attr=False) def test_pickling_polys_numberfields(): from sympy.polys.numberfields import AlgebraicNumber for c in (AlgebraicNumber, AlgebraicNumber(sqrt(3))): check(c, check_attr=False) def test_pickling_polys_orderings(): from sympy.polys.orderings import (LexOrder, GradedLexOrder, ReversedGradedLexOrder, InverseOrder) # from sympy.polys.orderings import ProductOrder for c in (LexOrder, LexOrder()): check(c) for c in (GradedLexOrder, GradedLexOrder()): check(c) for c in (ReversedGradedLexOrder, ReversedGradedLexOrder()): check(c) # TODO: Argh, Python is so naive. No lambdas nor inner function support in # pickling module. Maybe someone could figure out what to do with this. # # for c in (ProductOrder, ProductOrder((LexOrder(), lambda m: m[:2]), # (GradedLexOrder(), lambda m: m[2:]))): # check(c) for c in (InverseOrder, InverseOrder(LexOrder())): check(c) def test_pickling_polys_monomials(): from sympy.polys.monomials import MonomialOps, Monomial x, y, z = symbols("x,y,z") for c in (MonomialOps, MonomialOps(3)): check(c) for c in (Monomial, Monomial((1, 2, 3), (x, y, z))): check(c) def test_pickling_polys_errors(): from sympy.polys.polyerrors import (HeuristicGCDFailed, HomomorphismFailed, IsomorphismFailed, ExtraneousFactors, EvaluationFailed, RefinementFailed, CoercionFailed, NotInvertible, NotReversible, NotAlgebraic, DomainError, PolynomialError, UnificationFailed, GeneratorsError, GeneratorsNeeded, UnivariatePolynomialError, MultivariatePolynomialError, OptionError, FlagError) # from sympy.polys.polyerrors import (ExactQuotientFailed, # OperationNotSupported, ComputationFailed, PolificationFailed) # x = Symbol('x') # TODO: TypeError: __init__() takes at least 3 arguments (1 given) # for c in (ExactQuotientFailed, ExactQuotientFailed(x, 3*x, ZZ)): # check(c) # TODO: TypeError: can't pickle instancemethod objects # for c in (OperationNotSupported, OperationNotSupported(Poly(x), Poly.gcd)): # check(c) for c in (HeuristicGCDFailed, HeuristicGCDFailed()): check(c) for c in (HomomorphismFailed, HomomorphismFailed()): check(c) for c in (IsomorphismFailed, IsomorphismFailed()): check(c) for c in (ExtraneousFactors, ExtraneousFactors()): check(c) for c in (EvaluationFailed, EvaluationFailed()): check(c) for c in (RefinementFailed, RefinementFailed()): check(c) for c in (CoercionFailed, CoercionFailed()): check(c) for c in (NotInvertible, NotInvertible()): check(c) for c in (NotReversible, NotReversible()): check(c) for c in (NotAlgebraic, NotAlgebraic()): check(c) for c in (DomainError, DomainError()): check(c) for c in (PolynomialError, PolynomialError()): check(c) for c in (UnificationFailed, UnificationFailed()): check(c) for c in (GeneratorsError, GeneratorsError()): check(c) for c in (GeneratorsNeeded, GeneratorsNeeded()): check(c) # TODO: PicklingError: Can't pickle at 0x38578c0>: it's not found as __main__. # for c in (ComputationFailed, ComputationFailed(lambda t: t, 3, None)): # check(c) for c in (UnivariatePolynomialError, UnivariatePolynomialError()): check(c) for c in (MultivariatePolynomialError, MultivariatePolynomialError()): check(c) # TODO: TypeError: __init__() takes at least 3 arguments (1 given) # for c in (PolificationFailed, PolificationFailed({}, x, x, False)): # check(c) for c in (OptionError, OptionError()): check(c) for c in (FlagError, FlagError()): check(c) #def test_pickling_polys_options(): #from sympy.polys.polyoptions import Options # TODO: fix pickling of `symbols' flag # for c in (Options, Options((), dict(domain='ZZ', polys=False))): # check(c) # TODO: def test_pickling_polys_rootisolation(): # RealInterval # ComplexInterval def test_pickling_polys_rootoftools(): from sympy.polys.rootoftools import CRootOf, RootSum x = Symbol('x') f = x**3 + x + 3 for c in (CRootOf, CRootOf(f, 0)): check(c) for c in (RootSum, RootSum(f, exp)): check(c) #================== printing ==================== from sympy.printing.latex import LatexPrinter from sympy.printing.mathml import MathMLContentPrinter, MathMLPresentationPrinter from sympy.printing.pretty.pretty import PrettyPrinter from sympy.printing.pretty.stringpict import prettyForm, stringPict from sympy.printing.printer import Printer from sympy.printing.python import PythonPrinter def test_printing(): for c in (LatexPrinter, LatexPrinter(), MathMLContentPrinter, MathMLPresentationPrinter, PrettyPrinter, prettyForm, stringPict, stringPict("a"), Printer, Printer(), PythonPrinter, PythonPrinter()): check(c) @XFAIL def test_printing1(): check(MathMLContentPrinter()) @XFAIL def test_printing2(): check(MathMLPresentationPrinter()) @XFAIL def test_printing3(): check(PrettyPrinter()) #================== series ====================== from sympy.series.limits import Limit from sympy.series.order import Order def test_series(): e = Symbol("e") x = Symbol("x") for c in (Limit, Limit(e, x, 1), Order, Order(e)): check(c) #================== concrete ================== from sympy.concrete.products import Product from sympy.concrete.summations import Sum def test_concrete(): x = Symbol("x") for c in (Product, Product(x, (x, 2, 4)), Sum, Sum(x, (x, 2, 4))): check(c) def test_deprecation_warning(): w = SymPyDeprecationWarning('value', 'feature', issue=12345, deprecated_since_version='1.0') check(w) def test_issue_18438(): assert pickle.loads(pickle.dumps(S.Half)) == 1/2 sympy-sympy-1.9/sympy/utilities/tests/test_source.py000066400000000000000000000014351412543434000231750ustar00rootroot00000000000000import sys from sympy.utilities.source import get_mod_func, get_class, source from sympy.testing.pytest import warns_deprecated_sympy from sympy.geometry import point def test_source(): # Dummy stdout class StdOut: def write(self, x): pass # Test SymPyDeprecationWarning from source() with warns_deprecated_sympy(): # Redirect stdout temporarily so print out is not seen stdout = sys.stdout try: sys.stdout = StdOut() source(point) finally: sys.stdout = stdout def test_get_mod_func(): assert get_mod_func( 'sympy.core.basic.Basic') == ('sympy.core.basic', 'Basic') def test_get_class(): _basic = get_class('sympy.core.basic.Basic') assert _basic.__name__ == 'Basic' sympy-sympy-1.9/sympy/utilities/tests/test_timeutils.py000066400000000000000000000005211412543434000237070ustar00rootroot00000000000000"""Tests for simple tools for timing functions' execution. """ from sympy.utilities.timeutils import timed def test_timed(): result = timed(lambda: 1 + 1, limit=100000) assert result[0] == 100000 and result[3] == "ns", str(result) result = timed("1 + 1", limit=100000) assert result[0] == 100000 and result[3] == "ns" sympy-sympy-1.9/sympy/utilities/tests/test_wester.py000066400000000000000000002643741412543434000232230ustar00rootroot00000000000000""" Tests from Michael Wester's 1999 paper "Review of CAS mathematical capabilities". http://www.math.unm.edu/~wester/cas/book/Wester.pdf See also http://math.unm.edu/~wester/cas_review.html for detailed output of each tested system. """ from sympy import (Rational, symbols, Dummy, factorial, sqrt, log, exp, oo, zoo, product, binomial, rf, pi, gamma, igcd, factorint, radsimp, combsimp, npartitions, totient, primerange, factor, simplify, gcd, resultant, expand, I, trigsimp, tan, sin, cos, cot, diff, nan, limit, EulerGamma, polygamma, bernoulli, hyper, hyperexpand, besselj, asin, assoc_legendre, Function, re, im, DiracDelta, chebyshevt, legendre_poly, polylog, series, O, atan, sinh, cosh, tanh, floor, ceiling, solve, asinh, acot, csc, sec, LambertW, N, apart, sqrtdenest, factorial2, powdenest, Mul, S, ZZ, Poly, expand_func, E, Q, And, Lt, Min, ask, refine, AlgebraicNumber, continued_fraction_iterator as cf_i, continued_fraction_periodic as cf_p, continued_fraction_convergents as cf_c, continued_fraction_reduce as cf_r, FiniteSet, elliptic_e, elliptic_f, powsimp, hessian, wronskian, fibonacci, sign, Lambda, Piecewise, Subs, residue, Derivative, logcombine, Symbol, Intersection, Union, EmptySet, Interval, idiff, ImageSet, acos, Max, MatMul, conjugate, Eq) import mpmath from sympy.functions.combinatorial.numbers import stirling from sympy.functions.special.delta_functions import Heaviside from sympy.functions.special.error_functions import Ci, Si, erf from sympy.functions.special.zeta_functions import zeta from sympy.testing.pytest import (XFAIL, slow, SKIP, skip, ON_TRAVIS, raises) from sympy.utilities.iterables import partitions from mpmath import mpi, mpc from sympy.matrices import Matrix, GramSchmidt, eye from sympy.matrices.expressions.blockmatrix import BlockMatrix, block_collapse from sympy.matrices.expressions import MatrixSymbol, ZeroMatrix from sympy.physics.quantum import Commutator from sympy.assumptions import assuming from sympy.polys.rings import PolyRing from sympy.polys.fields import FracField from sympy.polys.solvers import solve_lin_sys from sympy.concrete import Sum from sympy.concrete.products import Product from sympy.integrals import integrate from sympy.integrals.transforms import laplace_transform,\ inverse_laplace_transform, LaplaceTransform, fourier_transform,\ mellin_transform from sympy.solvers.recurr import rsolve from sympy.solvers.solveset import solveset, solveset_real, linsolve from sympy.solvers.ode import dsolve from sympy.core.relational import Equality from itertools import islice, takewhile from sympy.series.formal import fps from sympy.series.fourier import fourier_series from sympy.calculus.util import minimum R = Rational x, y, z = symbols('x y z') i, j, k, l, m, n = symbols('i j k l m n', integer=True) f = Function('f') g = Function('g') # A. Boolean Logic and Quantifier Elimination # Not implemented. # B. Set Theory def test_B1(): assert (FiniteSet(i, j, j, k, k, k) | FiniteSet(l, k, j) | FiniteSet(j, m, j)) == FiniteSet(i, j, k, l, m) def test_B2(): assert (FiniteSet(i, j, j, k, k, k) & FiniteSet(l, k, j) & FiniteSet(j, m, j)) == Intersection({j, m}, {i, j, k}, {j, k, l}) # Previous output below. Not sure why that should be the expected output. # There should probably be a way to rewrite Intersections that way but I # don't see why an Intersection should evaluate like that: # # == Union({j}, Intersection({m}, Union({j, k}, Intersection({i}, {l})))) def test_B3(): assert (FiniteSet(i, j, k, l, m) - FiniteSet(j) == FiniteSet(i, k, l, m)) def test_B4(): assert (FiniteSet(*(FiniteSet(i, j)*FiniteSet(k, l))) == FiniteSet((i, k), (i, l), (j, k), (j, l))) # C. Numbers def test_C1(): assert (factorial(50) == 30414093201713378043612608166064768844377641568960512000000000000) def test_C2(): assert (factorint(factorial(50)) == {2: 47, 3: 22, 5: 12, 7: 8, 11: 4, 13: 3, 17: 2, 19: 2, 23: 2, 29: 1, 31: 1, 37: 1, 41: 1, 43: 1, 47: 1}) def test_C3(): assert (factorial2(10), factorial2(9)) == (3840, 945) # Base conversions; not really implemented by sympy # Whatever. Take credit! def test_C4(): assert 0xABC == 2748 def test_C5(): assert 123 == int('234', 7) def test_C6(): assert int('677', 8) == int('1BF', 16) == 447 def test_C7(): assert log(32768, 8) == 5 def test_C8(): # Modular multiplicative inverse. Would be nice if divmod could do this. assert ZZ.invert(5, 7) == 3 assert ZZ.invert(5, 6) == 5 def test_C9(): assert igcd(igcd(1776, 1554), 5698) == 74 def test_C10(): x = 0 for n in range(2, 11): x += R(1, n) assert x == R(4861, 2520) def test_C11(): assert R(1, 7) == S('0.[142857]') def test_C12(): assert R(7, 11) * R(22, 7) == 2 def test_C13(): test = R(10, 7) * (1 + R(29, 1000)) ** R(1, 3) good = 3 ** R(1, 3) assert test == good def test_C14(): assert sqrtdenest(sqrt(2*sqrt(3) + 4)) == 1 + sqrt(3) def test_C15(): test = sqrtdenest(sqrt(14 + 3*sqrt(3 + 2*sqrt(5 - 12*sqrt(3 - 2*sqrt(2)))))) good = sqrt(2) + 3 assert test == good def test_C16(): test = sqrtdenest(sqrt(10 + 2*sqrt(6) + 2*sqrt(10) + 2*sqrt(15))) good = sqrt(2) + sqrt(3) + sqrt(5) assert test == good def test_C17(): test = radsimp((sqrt(3) + sqrt(2)) / (sqrt(3) - sqrt(2))) good = 5 + 2*sqrt(6) assert test == good def test_C18(): assert simplify((sqrt(-2 + sqrt(-5)) * sqrt(-2 - sqrt(-5))).expand(complex=True)) == 3 @XFAIL def test_C19(): assert radsimp(simplify((90 + 34*sqrt(7)) ** R(1, 3))) == 3 + sqrt(7) def test_C20(): inside = (135 + 78*sqrt(3)) test = AlgebraicNumber((inside**R(2, 3) + 3) * sqrt(3) / inside**R(1, 3)) assert simplify(test) == AlgebraicNumber(12) def test_C21(): assert simplify(AlgebraicNumber((41 + 29*sqrt(2)) ** R(1, 5))) == \ AlgebraicNumber(1 + sqrt(2)) @XFAIL def test_C22(): test = simplify(((6 - 4*sqrt(2))*log(3 - 2*sqrt(2)) + (3 - 2*sqrt(2))*log(17 - 12*sqrt(2)) + 32 - 24*sqrt(2)) / (48*sqrt(2) - 72)) good = sqrt(2)/3 - log(sqrt(2) - 1)/3 assert test == good def test_C23(): assert 2 * oo - 3 is oo @XFAIL def test_C24(): raise NotImplementedError("2**aleph_null == aleph_1") # D. Numerical Analysis def test_D1(): assert 0.0 / sqrt(2) == 0.0 def test_D2(): assert str(exp(-1000000).evalf()) == '3.29683147808856e-434295' def test_D3(): assert exp(pi*sqrt(163)).evalf(50).num.ae(262537412640768744) def test_D4(): assert floor(R(-5, 3)) == -2 assert ceiling(R(-5, 3)) == -1 @XFAIL def test_D5(): raise NotImplementedError("cubic_spline([1, 2, 4, 5], [1, 4, 2, 3], x)(3) == 27/8") @XFAIL def test_D6(): raise NotImplementedError("translate sum(a[i]*x**i, (i,1,n)) to FORTRAN") @XFAIL def test_D7(): raise NotImplementedError("translate sum(a[i]*x**i, (i,1,n)) to C") @XFAIL def test_D8(): # One way is to cheat by converting the sum to a string, # and replacing the '[' and ']' with ''. # E.g., horner(S(str(_).replace('[','').replace(']',''))) raise NotImplementedError("apply Horner's rule to sum(a[i]*x**i, (i,1,5))") @XFAIL def test_D9(): raise NotImplementedError("translate D8 to FORTRAN") @XFAIL def test_D10(): raise NotImplementedError("translate D8 to C") @XFAIL def test_D11(): #Is there a way to use count_ops? raise NotImplementedError("flops(sum(product(f[i][k], (i,1,k)), (k,1,n)))") @XFAIL def test_D12(): assert (mpi(-4, 2) * x + mpi(1, 3)) ** 2 == mpi(-8, 16)*x**2 + mpi(-24, 12)*x + mpi(1, 9) @XFAIL def test_D13(): raise NotImplementedError("discretize a PDE: diff(f(x,t),t) == diff(diff(f(x,t),x),x)") # E. Statistics # See scipy; all of this is numerical. # F. Combinatorial Theory. def test_F1(): assert rf(x, 3) == x*(1 + x)*(2 + x) def test_F2(): assert expand_func(binomial(n, 3)) == n*(n - 1)*(n - 2)/6 @XFAIL def test_F3(): assert combsimp(2**n * factorial(n) * factorial2(2*n - 1)) == factorial(2*n) @XFAIL def test_F4(): assert combsimp(2**n * factorial(n) * product(2*k - 1, (k, 1, n))) == factorial(2*n) @XFAIL def test_F5(): assert gamma(n + R(1, 2)) / sqrt(pi) / factorial(n) == factorial(2*n)/2**(2*n)/factorial(n)**2 def test_F6(): partTest = [p.copy() for p in partitions(4)] partDesired = [{4: 1}, {1: 1, 3: 1}, {2: 2}, {1: 2, 2:1}, {1: 4}] assert partTest == partDesired def test_F7(): assert npartitions(4) == 5 def test_F8(): assert stirling(5, 2, signed=True) == -50 # if signed, then kind=1 def test_F9(): assert totient(1776) == 576 # G. Number Theory def test_G1(): assert list(primerange(999983, 1000004)) == [999983, 1000003] @XFAIL def test_G2(): raise NotImplementedError("find the primitive root of 191 == 19") @XFAIL def test_G3(): raise NotImplementedError("(a+b)**p mod p == a**p + b**p mod p; p prime") # ... G14 Modular equations are not implemented. def test_G15(): assert Rational(sqrt(3).evalf()).limit_denominator(15) == R(26, 15) assert list(takewhile(lambda x: x.q <= 15, cf_c(cf_i(sqrt(3)))))[-1] == \ R(26, 15) def test_G16(): assert list(islice(cf_i(pi),10)) == [3, 7, 15, 1, 292, 1, 1, 1, 2, 1] def test_G17(): assert cf_p(0, 1, 23) == [4, [1, 3, 1, 8]] def test_G18(): assert cf_p(1, 2, 5) == [[1]] assert cf_r([[1]]).expand() == S.Half + sqrt(5)/2 @XFAIL def test_G19(): s = symbols('s', integer=True, positive=True) it = cf_i((exp(1/s) - 1)/(exp(1/s) + 1)) assert list(islice(it, 5)) == [0, 2*s, 6*s, 10*s, 14*s] def test_G20(): s = symbols('s', integer=True, positive=True) # Wester erroneously has this as -s + sqrt(s**2 + 1) assert cf_r([[2*s]]) == s + sqrt(s**2 + 1) @XFAIL def test_G20b(): s = symbols('s', integer=True, positive=True) assert cf_p(s, 1, s**2 + 1) == [[2*s]] # H. Algebra def test_H1(): assert simplify(2*2**n) == simplify(2**(n + 1)) assert powdenest(2*2**n) == simplify(2**(n + 1)) def test_H2(): assert powsimp(4 * 2**n) == 2**(n + 2) def test_H3(): assert (-1)**(n*(n + 1)) == 1 def test_H4(): expr = factor(6*x - 10) assert type(expr) is Mul assert expr.args[0] == 2 assert expr.args[1] == 3*x - 5 p1 = 64*x**34 - 21*x**47 - 126*x**8 - 46*x**5 - 16*x**60 - 81 p2 = 72*x**60 - 25*x**25 - 19*x**23 - 22*x**39 - 83*x**52 + 54*x**10 + 81 q = 34*x**19 - 25*x**16 + 70*x**7 + 20*x**3 - 91*x - 86 def test_H5(): assert gcd(p1, p2, x) == 1 def test_H6(): assert gcd(expand(p1 * q), expand(p2 * q)) == q def test_H7(): p1 = 24*x*y**19*z**8 - 47*x**17*y**5*z**8 + 6*x**15*y**9*z**2 - 3*x**22 + 5 p2 = 34*x**5*y**8*z**13 + 20*x**7*y**7*z**7 + 12*x**9*y**16*z**4 + 80*y**14*z assert gcd(p1, p2, x, y, z) == 1 def test_H8(): p1 = 24*x*y**19*z**8 - 47*x**17*y**5*z**8 + 6*x**15*y**9*z**2 - 3*x**22 + 5 p2 = 34*x**5*y**8*z**13 + 20*x**7*y**7*z**7 + 12*x**9*y**16*z**4 + 80*y**14*z q = 11*x**12*y**7*z**13 - 23*x**2*y**8*z**10 + 47*x**17*y**5*z**8 assert gcd(p1 * q, p2 * q, x, y, z) == q def test_H9(): p1 = 2*x**(n + 4) - x**(n + 2) p2 = 4*x**(n + 1) + 3*x**n assert gcd(p1, p2) == x**n def test_H10(): p1 = 3*x**4 + 3*x**3 + x**2 - x - 2 p2 = x**3 - 3*x**2 + x + 5 assert resultant(p1, p2, x) == 0 def test_H11(): assert resultant(p1 * q, p2 * q, x) == 0 def test_H12(): num = x**2 - 4 den = x**2 + 4*x + 4 assert simplify(num/den) == (x - 2)/(x + 2) @XFAIL def test_H13(): assert simplify((exp(x) - 1) / (exp(x/2) + 1)) == exp(x/2) - 1 def test_H14(): p = (x + 1) ** 20 ep = expand(p) assert ep == (1 + 20*x + 190*x**2 + 1140*x**3 + 4845*x**4 + 15504*x**5 + 38760*x**6 + 77520*x**7 + 125970*x**8 + 167960*x**9 + 184756*x**10 + 167960*x**11 + 125970*x**12 + 77520*x**13 + 38760*x**14 + 15504*x**15 + 4845*x**16 + 1140*x**17 + 190*x**18 + 20*x**19 + x**20) dep = diff(ep, x) assert dep == (20 + 380*x + 3420*x**2 + 19380*x**3 + 77520*x**4 + 232560*x**5 + 542640*x**6 + 1007760*x**7 + 1511640*x**8 + 1847560*x**9 + 1847560*x**10 + 1511640*x**11 + 1007760*x**12 + 542640*x**13 + 232560*x**14 + 77520*x**15 + 19380*x**16 + 3420*x**17 + 380*x**18 + 20*x**19) assert factor(dep) == 20*(1 + x)**19 def test_H15(): assert simplify(Mul(*[x - r for r in solveset(x**3 + x**2 - 7)])) == x**3 + x**2 - 7 def test_H16(): assert factor(x**100 - 1) == ((x - 1)*(x + 1)*(x**2 + 1)*(x**4 - x**3 + x**2 - x + 1)*(x**4 + x**3 + x**2 + x + 1)*(x**8 - x**6 + x**4 - x**2 + 1)*(x**20 - x**15 + x**10 - x**5 + 1)*(x**20 + x**15 + x**10 + x**5 + 1)*(x**40 - x**30 + x**20 - x**10 + 1)) def test_H17(): assert simplify(factor(expand(p1 * p2)) - p1*p2) == 0 @XFAIL def test_H18(): # Factor over complex rationals. test = factor(4*x**4 + 8*x**3 + 77*x**2 + 18*x + 153) good = (2*x + 3*I)*(2*x - 3*I)*(x + 1 - 4*I)*(x + 1 + 4*I) assert test == good def test_H19(): a = symbols('a') # The idea is to let a**2 == 2, then solve 1/(a-1). Answer is a+1") assert Poly(a - 1).invert(Poly(a**2 - 2)) == a + 1 @XFAIL def test_H20(): raise NotImplementedError("let a**2==2; (x**3 + (a-2)*x**2 - " + "(2*a+3)*x - 3*a) / (x**2-2) = (x**2 - 2*x - 3) / (x-a)") @XFAIL def test_H21(): raise NotImplementedError("evaluate (b+c)**4 assuming b**3==2, c**2==3. \ Answer is 2*b + 8*c + 18*b**2 + 12*b*c + 9") def test_H22(): assert factor(x**4 - 3*x**2 + 1, modulus=5) == (x - 2)**2 * (x + 2)**2 def test_H23(): f = x**11 + x + 1 g = (x**2 + x + 1) * (x**9 - x**8 + x**6 - x**5 + x**3 - x**2 + 1) assert factor(f, modulus=65537) == g def test_H24(): phi = AlgebraicNumber(S.GoldenRatio.expand(func=True), alias='phi') assert factor(x**4 - 3*x**2 + 1, extension=phi) == \ (x - phi)*(x + 1 - phi)*(x - 1 + phi)*(x + phi) def test_H25(): e = (x - 2*y**2 + 3*z**3) ** 20 assert factor(expand(e)) == e def test_H26(): g = expand((sin(x) - 2*cos(y)**2 + 3*tan(z)**3)**20) assert factor(g, expand=False) == (-sin(x) + 2*cos(y)**2 - 3*tan(z)**3)**20 def test_H27(): f = 24*x*y**19*z**8 - 47*x**17*y**5*z**8 + 6*x**15*y**9*z**2 - 3*x**22 + 5 g = 34*x**5*y**8*z**13 + 20*x**7*y**7*z**7 + 12*x**9*y**16*z**4 + 80*y**14*z h = -2*z*y**7 \ *(6*x**9*y**9*z**3 + 10*x**7*z**6 + 17*y*x**5*z**12 + 40*y**7) \ *(3*x**22 + 47*x**17*y**5*z**8 - 6*x**15*y**9*z**2 - 24*x*y**19*z**8 - 5) assert factor(expand(f*g)) == h @XFAIL def test_H28(): raise NotImplementedError("expand ((1 - c**2)**5 * (1 - s**2)**5 * " + "(c**2 + s**2)**10) with c**2 + s**2 = 1. Answer is c**10*s**10.") @XFAIL def test_H29(): assert factor(4*x**2 - 21*x*y + 20*y**2, modulus=3) == (x + y)*(x - y) def test_H30(): test = factor(x**3 + y**3, extension=sqrt(-3)) answer = (x + y)*(x + y*(-R(1, 2) - sqrt(3)/2*I))*(x + y*(-R(1, 2) + sqrt(3)/2*I)) assert answer == test def test_H31(): f = (x**2 + 2*x + 3)/(x**3 + 4*x**2 + 5*x + 2) g = 2 / (x + 1)**2 - 2 / (x + 1) + 3 / (x + 2) assert apart(f) == g @XFAIL def test_H32(): # issue 6558 raise NotImplementedError("[A*B*C - (A*B*C)**(-1)]*A*C*B (product \ of a non-commuting product and its inverse)") def test_H33(): A, B, C = symbols('A, B, C', commutative=False) assert (Commutator(A, Commutator(B, C)) + Commutator(B, Commutator(C, A)) + Commutator(C, Commutator(A, B))).doit().expand() == 0 # I. Trigonometry def test_I1(): assert tan(pi*R(7, 10)) == -sqrt(1 + 2/sqrt(5)) @XFAIL def test_I2(): assert sqrt((1 + cos(6))/2) == -cos(3) def test_I3(): assert cos(n*pi) + sin((4*n - 1)*pi/2) == (-1)**n - 1 def test_I4(): assert refine(cos(pi*cos(n*pi)) + sin(pi/2*cos(n*pi)), Q.integer(n)) == (-1)**n - 1 @XFAIL def test_I5(): assert sin((n**5/5 + n**4/2 + n**3/3 - n/30) * pi) == 0 @XFAIL def test_I6(): raise NotImplementedError("assuming -3*pi 0): # TODO: Replace solve with solveset solve(log(acos(asin(x**R(2, 3) - b) - 1)) + 2, x) == [-b - sin(1 + cos(1/E**2))**R(3/2), b + sin(1 + cos(1/E**2))**R(3/2)] @XFAIL def test_M28(): assert solveset_real(5*x + exp((x - 5)/2) - 8*x**3, x, assume=Q.real(x)) == [-0.784966, -0.016291, 0.802557] def test_M29(): x = symbols('x') assert solveset(abs(x - 1) - 2, domain=S.Reals) == FiniteSet(-1, 3) def test_M30(): # TODO: Replace solve with solveset, as of now # solveset doesn't supports assumptions # assert solve(abs(2*x + 5) - abs(x - 2),x, assume=Q.real(x)) == [-1, -7] assert solveset_real(abs(2*x + 5) - abs(x - 2), x) == FiniteSet(-1, -7) def test_M31(): # TODO: Replace solve with solveset, as of now # solveset doesn't supports assumptions # assert solve(1 - abs(x) - max(-x - 2, x - 2),x, assume=Q.real(x)) == [-3/2, 3/2] assert solveset_real(1 - abs(x) - Max(-x - 2, x - 2), x) == FiniteSet(R(-3, 2), R(3, 2)) @XFAIL def test_M32(): # TODO: Replace solve with solveset, as of now # solveset doesn't supports assumptions assert solveset_real(Max(2 - x**2, x)- Max(-x, (x**3)/9), x) == FiniteSet(-1, 3) @XFAIL def test_M33(): # TODO: Replace solve with solveset, as of now # solveset doesn't supports assumptions # Second answer can be written in another form. The second answer is the root of x**3 + 9*x**2 - 18 = 0 in the interval (-2, -1). assert solveset_real(Max(2 - x**2, x) - x**3/9, x) == FiniteSet(-3, -1.554894, 3) @XFAIL def test_M34(): z = symbols('z', complex=True) assert solveset((1 + I) * z + (2 - I) * conjugate(z) + 3*I, z) == FiniteSet(2 + 3*I) def test_M35(): x, y = symbols('x y', real=True) assert linsolve((3*x - 2*y - I*y + 3*I).as_real_imag(), y, x) == FiniteSet((3, 2)) def test_M36(): # TODO: Replace solve with solveset, as of now # solveset doesn't supports solving for function # assert solve(f**2 + f - 2, x) == [Eq(f(x), 1), Eq(f(x), -2)] assert solveset(f(x)**2 + f(x) - 2, f(x)) == FiniteSet(-2, 1) def test_M37(): assert linsolve([x + y + z - 6, 2*x + y + 2*z - 10, x + 3*y + z - 10 ], x, y, z) == \ FiniteSet((-z + 4, 2, z)) def test_M38(): a, b, c = symbols('a, b, c') domain = FracField([a, b, c], ZZ).to_domain() ring = PolyRing('k1:50', domain) (k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13, k14, k15, k16, k17, k18, k19, k20, k21, k22, k23, k24, k25, k26, k27, k28, k29, k30, k31, k32, k33, k34, k35, k36, k37, k38, k39, k40, k41, k42, k43, k44, k45, k46, k47, k48, k49) = ring.gens system = [ -b*k8/a + c*k8/a, -b*k11/a + c*k11/a, -b*k10/a + c*k10/a + k2, -k3 - b*k9/a + c*k9/a, -b*k14/a + c*k14/a, -b*k15/a + c*k15/a, -b*k18/a + c*k18/a - k2, -b*k17/a + c*k17/a, -b*k16/a + c*k16/a + k4, -b*k13/a + c*k13/a - b*k21/a + c*k21/a + b*k5/a - c*k5/a, b*k44/a - c*k44/a, -b*k45/a + c*k45/a, -b*k20/a + c*k20/a, -b*k44/a + c*k44/a, b*k46/a - c*k46/a, b**2*k47/a**2 - 2*b*c*k47/a**2 + c**2*k47/a**2, k3, -k4, -b*k12/a + c*k12/a - a*k6/b + c*k6/b, -b*k19/a + c*k19/a + a*k7/c - b*k7/c, b*k45/a - c*k45/a, -b*k46/a + c*k46/a, -k48 + c*k48/a + c*k48/b - c**2*k48/(a*b), -k49 + b*k49/a + b*k49/c - b**2*k49/(a*c), a*k1/b - c*k1/b, a*k4/b - c*k4/b, a*k3/b - c*k3/b + k9, -k10 + a*k2/b - c*k2/b, a*k7/b - c*k7/b, -k9, k11, b*k12/a - c*k12/a + a*k6/b - c*k6/b, a*k15/b - c*k15/b, k10 + a*k18/b - c*k18/b, -k11 + a*k17/b - c*k17/b, a*k16/b - c*k16/b, -a*k13/b + c*k13/b + a*k21/b - c*k21/b + a*k5/b - c*k5/b, -a*k44/b + c*k44/b, a*k45/b - c*k45/b, a*k14/c - b*k14/c + a*k20/b - c*k20/b, a*k44/b - c*k44/b, -a*k46/b + c*k46/b, -k47 + c*k47/a + c*k47/b - c**2*k47/(a*b), a*k19/b - c*k19/b, -a*k45/b + c*k45/b, a*k46/b - c*k46/b, a**2*k48/b**2 - 2*a*c*k48/b**2 + c**2*k48/b**2, -k49 + a*k49/b + a*k49/c - a**2*k49/(b*c), k16, -k17, -a*k1/c + b*k1/c, -k16 - a*k4/c + b*k4/c, -a*k3/c + b*k3/c, k18 - a*k2/c + b*k2/c, b*k19/a - c*k19/a - a*k7/c + b*k7/c, -a*k6/c + b*k6/c, -a*k8/c + b*k8/c, -a*k11/c + b*k11/c + k17, -a*k10/c + b*k10/c - k18, -a*k9/c + b*k9/c, -a*k14/c + b*k14/c - a*k20/b + c*k20/b, -a*k13/c + b*k13/c + a*k21/c - b*k21/c - a*k5/c + b*k5/c, a*k44/c - b*k44/c, -a*k45/c + b*k45/c, -a*k44/c + b*k44/c, a*k46/c - b*k46/c, -k47 + b*k47/a + b*k47/c - b**2*k47/(a*c), -a*k12/c + b*k12/c, a*k45/c - b*k45/c, -a*k46/c + b*k46/c, -k48 + a*k48/b + a*k48/c - a**2*k48/(b*c), a**2*k49/c**2 - 2*a*b*k49/c**2 + b**2*k49/c**2, k8, k11, -k15, k10 - k18, -k17, k9, -k16, -k29, k14 - k32, -k21 + k23 - k31, -k24 - k30, -k35, k44, -k45, k36, k13 - k23 + k39, -k20 + k38, k25 + k37, b*k26/a - c*k26/a - k34 + k42, -2*k44, k45, k46, b*k47/a - c*k47/a, k41, k44, -k46, -b*k47/a + c*k47/a, k12 + k24, -k19 - k25, -a*k27/b + c*k27/b - k33, k45, -k46, -a*k48/b + c*k48/b, a*k28/c - b*k28/c + k40, -k45, k46, a*k48/b - c*k48/b, a*k49/c - b*k49/c, -a*k49/c + b*k49/c, -k1, -k4, -k3, k15, k18 - k2, k17, k16, k22, k25 - k7, k24 + k30, k21 + k23 - k31, k28, -k44, k45, -k30 - k6, k20 + k32, k27 + b*k33/a - c*k33/a, k44, -k46, -b*k47/a + c*k47/a, -k36, k31 - k39 - k5, -k32 - k38, k19 - k37, k26 - a*k34/b + c*k34/b - k42, k44, -2*k45, k46, a*k48/b - c*k48/b, a*k35/c - b*k35/c - k41, -k44, k46, b*k47/a - c*k47/a, -a*k49/c + b*k49/c, -k40, k45, -k46, -a*k48/b + c*k48/b, a*k49/c - b*k49/c, k1, k4, k3, -k8, -k11, -k10 + k2, -k9, k37 + k7, -k14 - k38, -k22, -k25 - k37, -k24 + k6, -k13 - k23 + k39, -k28 + b*k40/a - c*k40/a, k44, -k45, -k27, -k44, k46, b*k47/a - c*k47/a, k29, k32 + k38, k31 - k39 + k5, -k12 + k30, k35 - a*k41/b + c*k41/b, -k44, k45, -k26 + k34 + a*k42/c - b*k42/c, k44, k45, -2*k46, -b*k47/a + c*k47/a, -a*k48/b + c*k48/b, a*k49/c - b*k49/c, k33, -k45, k46, a*k48/b - c*k48/b, -a*k49/c + b*k49/c ] solution = { k49: 0, k48: 0, k47: 0, k46: 0, k45: 0, k44: 0, k41: 0, k40: 0, k38: 0, k37: 0, k36: 0, k35: 0, k33: 0, k32: 0, k30: 0, k29: 0, k28: 0, k27: 0, k25: 0, k24: 0, k22: 0, k21: 0, k20: 0, k19: 0, k18: 0, k17: 0, k16: 0, k15: 0, k14: 0, k13: 0, k12: 0, k11: 0, k10: 0, k9: 0, k8: 0, k7: 0, k6: 0, k5: 0, k4: 0, k3: 0, k2: 0, k1: 0, k34: b/c*k42, k31: k39, k26: a/c*k42, k23: k39 } assert solve_lin_sys(system, ring) == solution def test_M39(): x, y, z = symbols('x y z', complex=True) # TODO: Replace solve with solveset, as of now # solveset doesn't supports non-linear multivariate assert solve([x**2*y + 3*y*z - 4, -3*x**2*z + 2*y**2 + 1, 2*y*z**2 - z**2 - 1 ]) ==\ [{y: 1, z: 1, x: -1}, {y: 1, z: 1, x: 1},\ {y: sqrt(2)*I, z: R(1,3) - sqrt(2)*I/3, x: -sqrt(-1 - sqrt(2)*I)},\ {y: sqrt(2)*I, z: R(1,3) - sqrt(2)*I/3, x: sqrt(-1 - sqrt(2)*I)},\ {y: -sqrt(2)*I, z: R(1,3) + sqrt(2)*I/3, x: -sqrt(-1 + sqrt(2)*I)},\ {y: -sqrt(2)*I, z: R(1,3) + sqrt(2)*I/3, x: sqrt(-1 + sqrt(2)*I)}] # N. Inequalities def test_N1(): assert ask(E**pi > pi**E) @XFAIL def test_N2(): x = symbols('x', real=True) assert ask(x**4 - x + 1 > 0) is True assert ask(x**4 - x + 1 > 1) is False @XFAIL def test_N3(): x = symbols('x', real=True) assert ask(And(Lt(-1, x), Lt(x, 1)), abs(x) < 1 ) @XFAIL def test_N4(): x, y = symbols('x y', real=True) assert ask(2*x**2 > 2*y**2, (x > y) & (y > 0)) is True @XFAIL def test_N5(): x, y, k = symbols('x y k', real=True) assert ask(k*x**2 > k*y**2, (x > y) & (y > 0) & (k > 0)) is True @slow @XFAIL def test_N6(): x, y, k, n = symbols('x y k n', real=True) assert ask(k*x**n > k*y**n, (x > y) & (y > 0) & (k > 0) & (n > 0)) is True @XFAIL def test_N7(): x, y = symbols('x y', real=True) assert ask(y > 0, (x > 1) & (y >= x - 1)) is True @XFAIL @slow def test_N8(): x, y, z = symbols('x y z', real=True) assert ask(Eq(x, y) & Eq(y, z), (x >= y) & (y >= z) & (z >= x)) def test_N9(): x = Symbol('x') assert solveset(abs(x - 1) > 2, domain=S.Reals) == Union(Interval(-oo, -1, False, True), Interval(3, oo, True)) def test_N10(): x = Symbol('x') p = (x - 1)*(x - 2)*(x - 3)*(x - 4)*(x - 5) assert solveset(expand(p) < 0, domain=S.Reals) == Union(Interval(-oo, 1, True, True), Interval(2, 3, True, True), Interval(4, 5, True, True)) def test_N11(): x = Symbol('x') assert solveset(6/(x - 3) <= 3, domain=S.Reals) == Union(Interval(-oo, 3, True, True), Interval(5, oo)) def test_N12(): x = Symbol('x') assert solveset(sqrt(x) < 2, domain=S.Reals) == Interval(0, 4, False, True) def test_N13(): x = Symbol('x') assert solveset(sin(x) < 2, domain=S.Reals) == S.Reals @XFAIL def test_N14(): x = Symbol('x') # Gives 'Union(Interval(Integer(0), Mul(Rational(1, 2), pi), false, true), # Interval(Mul(Rational(1, 2), pi), Mul(Integer(2), pi), true, false))' # which is not the correct answer, but the provided also seems wrong. assert solveset(sin(x) < 1, x, domain=S.Reals) == Union(Interval(-oo, pi/2, True, True), Interval(pi/2, oo, True, True)) def test_N15(): r, t = symbols('r t') # raises NotImplementedError: only univariate inequalities are supported solveset(abs(2*r*(cos(t) - 1) + 1) <= 1, r, S.Reals) def test_N16(): r, t = symbols('r t') solveset((r**2)*((cos(t) - 4)**2)*sin(t)**2 < 9, r, S.Reals) @XFAIL def test_N17(): # currently only univariate inequalities are supported assert solveset((x + y > 0, x - y < 0), (x, y)) == (abs(x) < y) def test_O1(): M = Matrix((1 + I, -2, 3*I)) assert sqrt(expand(M.dot(M.H))) == sqrt(15) def test_O2(): assert Matrix((2, 2, -3)).cross(Matrix((1, 3, 1))) == Matrix([[11], [-5], [4]]) # The vector module has no way of representing vectors symbolically (without # respect to a basis) @XFAIL def test_O3(): # assert (va ^ vb) | (vc ^ vd) == -(va | vc)*(vb | vd) + (va | vd)*(vb | vc) raise NotImplementedError("""The vector module has no way of representing vectors symbolically (without respect to a basis)""") def test_O4(): from sympy.vector import CoordSys3D, Del N = CoordSys3D("N") delop = Del() i, j, k = N.base_vectors() x, y, z = N.base_scalars() F = i*(x*y*z) + j*((x*y*z)**2) + k*((y**2)*(z**3)) assert delop.cross(F).doit() == (-2*x**2*y**2*z + 2*y*z**3)*i + x*y*j + (2*x*y**2*z**2 - x*z)*k @XFAIL def test_O5(): #assert grad|(f^g)-g|(grad^f)+f|(grad^g) == 0 raise NotImplementedError("""The vector module has no way of representing vectors symbolically (without respect to a basis)""") #testO8-O9 MISSING!! def test_O10(): L = [Matrix([2, 3, 5]), Matrix([3, 6, 2]), Matrix([8, 3, 6])] assert GramSchmidt(L) == [Matrix([ [2], [3], [5]]), Matrix([ [R(23, 19)], [R(63, 19)], [R(-47, 19)]]), Matrix([ [R(1692, 353)], [R(-1551, 706)], [R(-423, 706)]])] def test_P1(): assert Matrix(3, 3, lambda i, j: j - i).diagonal(-1) == Matrix( 1, 2, [-1, -1]) def test_P2(): M = Matrix([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) M.row_del(1) M.col_del(2) assert M == Matrix([[1, 2], [7, 8]]) def test_P3(): A = Matrix([ [11, 12, 13, 14], [21, 22, 23, 24], [31, 32, 33, 34], [41, 42, 43, 44]]) A11 = A[0:3, 1:4] A12 = A[(0, 1, 3), (2, 0, 3)] A21 = A A221 = -A[0:2, 2:4] A222 = -A[(3, 0), (2, 1)] A22 = BlockMatrix([[A221, A222]]).T rows = [[-A11, A12], [A21, A22]] raises(ValueError, lambda: BlockMatrix(rows)) B = Matrix(rows) assert B == Matrix([ [-12, -13, -14, 13, 11, 14], [-22, -23, -24, 23, 21, 24], [-32, -33, -34, 43, 41, 44], [11, 12, 13, 14, -13, -23], [21, 22, 23, 24, -14, -24], [31, 32, 33, 34, -43, -13], [41, 42, 43, 44, -42, -12]]) @XFAIL def test_P4(): raise NotImplementedError("Block matrix diagonalization not supported") def test_P5(): M = Matrix([[7, 11], [3, 8]]) assert M % 2 == Matrix([[1, 1], [1, 0]]) def test_P6(): M = Matrix([[cos(x), sin(x)], [-sin(x), cos(x)]]) assert M.diff(x, 2) == Matrix([[-cos(x), -sin(x)], [sin(x), -cos(x)]]) def test_P7(): M = Matrix([[x, y]])*( z*Matrix([[1, 3, 5], [2, 4, 6]]) + Matrix([[7, -9, 11], [-8, 10, -12]])) assert M == Matrix([[x*(z + 7) + y*(2*z - 8), x*(3*z - 9) + y*(4*z + 10), x*(5*z + 11) + y*(6*z - 12)]]) def test_P8(): M = Matrix([[1, -2*I], [-3*I, 4]]) assert M.norm(ord=S.Infinity) == 7 def test_P9(): a, b, c = symbols('a b c', nonzero=True) M = Matrix([[a/(b*c), 1/c, 1/b], [1/c, b/(a*c), 1/a], [1/b, 1/a, c/(a*b)]]) assert factor(M.norm('fro')) == (a**2 + b**2 + c**2)/(abs(a)*abs(b)*abs(c)) @XFAIL def test_P10(): M = Matrix([[1, 2 + 3*I], [f(4 - 5*I), 6]]) # conjugate(f(4 - 5*i)) is not simplified to f(4+5*I) assert M.H == Matrix([[1, f(4 + 5*I)], [2 + 3*I, 6]]) @XFAIL def test_P11(): # raises NotImplementedError("Matrix([[x,y],[1,x*y]]).inv() # not simplifying to extract common factor") assert Matrix([[x, y], [1, x*y]]).inv() == (1/(x**2 - 1))*Matrix([[x, -1], [-1/y, x/y]]) def test_P11_workaround(): # This test was changed to inverse method ADJ because it depended on the # specific form of inverse returned from the 'GE' method which has changed. M = Matrix([[x, y], [1, x*y]]).inv('ADJ') c = gcd(tuple(M)) assert MatMul(c, M/c, evaluate=False) == MatMul(c, Matrix([ [x*y, -y], [ -1, x]]), evaluate=False) def test_P12(): A11 = MatrixSymbol('A11', n, n) A12 = MatrixSymbol('A12', n, n) A22 = MatrixSymbol('A22', n, n) B = BlockMatrix([[A11, A12], [ZeroMatrix(n, n), A22]]) assert block_collapse(B.I) == BlockMatrix([[A11.I, (-1)*A11.I*A12*A22.I], [ZeroMatrix(n, n), A22.I]]) def test_P13(): M = Matrix([[1, x - 2, x - 3], [x - 1, x**2 - 3*x + 6, x**2 - 3*x - 2], [x - 2, x**2 - 8, 2*(x**2) - 12*x + 14]]) L, U, _ = M.LUdecomposition() assert simplify(L) == Matrix([[1, 0, 0], [x - 1, 1, 0], [x - 2, x - 3, 1]]) assert simplify(U) == Matrix([[1, x - 2, x - 3], [0, 4, x - 5], [0, 0, x - 7]]) def test_P14(): M = Matrix([[1, 2, 3, 1, 3], [3, 2, 1, 1, 7], [0, 2, 4, 1, 1], [1, 1, 1, 1, 4]]) R, _ = M.rref() assert R == Matrix([[1, 0, -1, 0, 2], [0, 1, 2, 0, -1], [0, 0, 0, 1, 3], [0, 0, 0, 0, 0]]) def test_P15(): M = Matrix([[-1, 3, 7, -5], [4, -2, 1, 3], [2, 4, 15, -7]]) assert M.rank() == 2 def test_P16(): M = Matrix([[2*sqrt(2), 8], [6*sqrt(6), 24*sqrt(3)]]) assert M.rank() == 1 def test_P17(): t = symbols('t', real=True) M=Matrix([ [sin(2*t), cos(2*t)], [2*(1 - (cos(t)**2))*cos(t), (1 - 2*(sin(t)**2))*sin(t)]]) assert M.rank() == 1 def test_P18(): M = Matrix([[1, 0, -2, 0], [-2, 1, 0, 3], [-1, 2, -6, 6]]) assert M.nullspace() == [Matrix([[2], [4], [1], [0]]), Matrix([[0], [-3], [0], [1]])] def test_P19(): w = symbols('w') M = Matrix([[1, 1, 1, 1], [w, x, y, z], [w**2, x**2, y**2, z**2], [w**3, x**3, y**3, z**3]]) assert M.det() == (w**3*x**2*y - w**3*x**2*z - w**3*x*y**2 + w**3*x*z**2 + w**3*y**2*z - w**3*y*z**2 - w**2*x**3*y + w**2*x**3*z + w**2*x*y**3 - w**2*x*z**3 - w**2*y**3*z + w**2*y*z**3 + w*x**3*y**2 - w*x**3*z**2 - w*x**2*y**3 + w*x**2*z**3 + w*y**3*z**2 - w*y**2*z**3 - x**3*y**2*z + x**3*y*z**2 + x**2*y**3*z - x**2*y*z**3 - x*y**3*z**2 + x*y**2*z**3 ) @XFAIL def test_P20(): raise NotImplementedError("Matrix minimal polynomial not supported") def test_P21(): M = Matrix([[5, -3, -7], [-2, 1, 2], [2, -3, -4]]) assert M.charpoly(x).as_expr() == x**3 - 2*x**2 - 5*x + 6 def test_P22(): d = 100 M = (2 - x)*eye(d) assert M.eigenvals() == {-x + 2: d} def test_P23(): M = Matrix([ [2, 1, 0, 0, 0], [1, 2, 1, 0, 0], [0, 1, 2, 1, 0], [0, 0, 1, 2, 1], [0, 0, 0, 1, 2]]) assert M.eigenvals() == { S('1'): 1, S('2'): 1, S('3'): 1, S('sqrt(3) + 2'): 1, S('-sqrt(3) + 2'): 1} def test_P24(): M = Matrix([[611, 196, -192, 407, -8, -52, -49, 29], [196, 899, 113, -192, -71, -43, -8, -44], [-192, 113, 899, 196, 61, 49, 8, 52], [ 407, -192, 196, 611, 8, 44, 59, -23], [ -8, -71, 61, 8, 411, -599, 208, 208], [ -52, -43, 49, 44, -599, 411, 208, 208], [ -49, -8, 8, 59, 208, 208, 99, -911], [ 29, -44, 52, -23, 208, 208, -911, 99]]) assert M.eigenvals() == { S('0'): 1, S('10*sqrt(10405)'): 1, S('100*sqrt(26) + 510'): 1, S('1000'): 2, S('-100*sqrt(26) + 510'): 1, S('-10*sqrt(10405)'): 1, S('1020'): 1} def test_P25(): MF = N(Matrix([[ 611, 196, -192, 407, -8, -52, -49, 29], [ 196, 899, 113, -192, -71, -43, -8, -44], [-192, 113, 899, 196, 61, 49, 8, 52], [ 407, -192, 196, 611, 8, 44, 59, -23], [ -8, -71, 61, 8, 411, -599, 208, 208], [ -52, -43, 49, 44, -599, 411, 208, 208], [ -49, -8, 8, 59, 208, 208, 99, -911], [ 29, -44, 52, -23, 208, 208, -911, 99]])) ev_1 = sorted(MF.eigenvals(multiple=True)) ev_2 = sorted( [-1020.0490184299969, 0.0, 0.09804864072151699, 1000.0, 1000.0, 1019.9019513592784, 1020.0, 1020.0490184299969]) for x, y in zip(ev_1, ev_2): assert abs(x - y) < 1e-12 def test_P26(): a0, a1, a2, a3, a4 = symbols('a0 a1 a2 a3 a4') M = Matrix([[-a4, -a3, -a2, -a1, -a0, 0, 0, 0, 0], [ 1, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 1, 0, 0, 0, 0, 0, 0, 0], [ 0, 0, 1, 0, 0, 0, 0, 0, 0], [ 0, 0, 0, 1, 0, 0, 0, 0, 0], [ 0, 0, 0, 0, 0, -1, -1, 0, 0], [ 0, 0, 0, 0, 0, 1, 0, 0, 0], [ 0, 0, 0, 0, 0, 0, 1, -1, -1], [ 0, 0, 0, 0, 0, 0, 0, 1, 0]]) assert M.eigenvals(error_when_incomplete=False) == { S('-1/2 - sqrt(3)*I/2'): 2, S('-1/2 + sqrt(3)*I/2'): 2} def test_P27(): a = symbols('a') M = Matrix([[a, 0, 0, 0, 0], [0, 0, 0, 0, 1], [0, 0, a, 0, 0], [0, 0, 0, a, 0], [0, -2, 0, 0, 2]]) assert M.eigenvects() == [ (a, 3, [ Matrix([1, 0, 0, 0, 0]), Matrix([0, 0, 1, 0, 0]), Matrix([0, 0, 0, 1, 0]) ]), (1 - I, 1, [ Matrix([0, (1 + I)/2, 0, 0, 1]) ]), (1 + I, 1, [ Matrix([0, (1 - I)/2, 0, 0, 1]) ]), ] @XFAIL def test_P28(): raise NotImplementedError("Generalized eigenvectors not supported \ https://github.com/sympy/sympy/issues/5293") @XFAIL def test_P29(): raise NotImplementedError("Generalized eigenvectors not supported \ https://github.com/sympy/sympy/issues/5293") def test_P30(): M = Matrix([[1, 0, 0, 1, -1], [0, 1, -2, 3, -3], [0, 0, -1, 2, -2], [1, -1, 1, 0, 1], [1, -1, 1, -1, 2]]) _, J = M.jordan_form() assert J == Matrix([[-1, 0, 0, 0, 0], [0, 1, 1, 0, 0], [0, 0, 1, 0, 0], [0, 0, 0, 1, 1], [0, 0, 0, 0, 1]]) @XFAIL def test_P31(): raise NotImplementedError("Smith normal form not implemented") def test_P32(): M = Matrix([[1, -2], [2, 1]]) assert exp(M).rewrite(cos).simplify() == Matrix([[E*cos(2), -E*sin(2)], [E*sin(2), E*cos(2)]]) def test_P33(): w, t = symbols('w t') M = Matrix([[0, 1, 0, 0], [0, 0, 0, 2*w], [0, 0, 0, 1], [0, -2*w, 3*w**2, 0]]) assert exp(M*t).rewrite(cos).expand() == Matrix([ [1, -3*t + 4*sin(t*w)/w, 6*t*w - 6*sin(t*w), -2*cos(t*w)/w + 2/w], [0, 4*cos(t*w) - 3, -6*w*cos(t*w) + 6*w, 2*sin(t*w)], [0, 2*cos(t*w)/w - 2/w, -3*cos(t*w) + 4, sin(t*w)/w], [0, -2*sin(t*w), 3*w*sin(t*w), cos(t*w)]]) @XFAIL def test_P34(): a, b, c = symbols('a b c', real=True) M = Matrix([[a, 1, 0, 0, 0, 0], [0, a, 0, 0, 0, 0], [0, 0, b, 0, 0, 0], [0, 0, 0, c, 1, 0], [0, 0, 0, 0, c, 1], [0, 0, 0, 0, 0, c]]) # raises exception, sin(M) not supported. exp(M*I) also not supported # https://github.com/sympy/sympy/issues/6218 assert sin(M) == Matrix([[sin(a), cos(a), 0, 0, 0, 0], [0, sin(a), 0, 0, 0, 0], [0, 0, sin(b), 0, 0, 0], [0, 0, 0, sin(c), cos(c), -sin(c)/2], [0, 0, 0, 0, sin(c), cos(c)], [0, 0, 0, 0, 0, sin(c)]]) @XFAIL def test_P35(): M = pi/2*Matrix([[2, 1, 1], [2, 3, 2], [1, 1, 2]]) # raises exception, sin(M) not supported. exp(M*I) also not supported # https://github.com/sympy/sympy/issues/6218 assert sin(M) == eye(3) @XFAIL def test_P36(): M = Matrix([[10, 7], [7, 17]]) assert sqrt(M) == Matrix([[3, 1], [1, 4]]) def test_P37(): M = Matrix([[1, 1, 0], [0, 1, 0], [0, 0, 1]]) assert M**S.Half == Matrix([[1, R(1, 2), 0], [0, 1, 0], [0, 0, 1]]) @XFAIL def test_P38(): M=Matrix([[0, 1, 0], [0, 0, 0], [0, 0, 0]]) #raises ValueError: Matrix det == 0; not invertible M**S.Half @XFAIL def test_P39(): """ M=Matrix([ [1, 1], [2, 2], [3, 3]]) M.SVD() """ raise NotImplementedError("Singular value decomposition not implemented") def test_P40(): r, t = symbols('r t', real=True) M = Matrix([r*cos(t), r*sin(t)]) assert M.jacobian(Matrix([r, t])) == Matrix([[cos(t), -r*sin(t)], [sin(t), r*cos(t)]]) def test_P41(): r, t = symbols('r t', real=True) assert hessian(r**2*sin(t),(r,t)) == Matrix([[ 2*sin(t), 2*r*cos(t)], [2*r*cos(t), -r**2*sin(t)]]) def test_P42(): assert wronskian([cos(x), sin(x)], x).simplify() == 1 def test_P43(): def __my_jacobian(M, Y): return Matrix([M.diff(v).T for v in Y]).T r, t = symbols('r t', real=True) M = Matrix([r*cos(t), r*sin(t)]) assert __my_jacobian(M,[r,t]) == Matrix([[cos(t), -r*sin(t)], [sin(t), r*cos(t)]]) def test_P44(): def __my_hessian(f, Y): V = Matrix([diff(f, v) for v in Y]) return Matrix([V.T.diff(v) for v in Y]) r, t = symbols('r t', real=True) assert __my_hessian(r**2*sin(t), (r, t)) == Matrix([ [ 2*sin(t), 2*r*cos(t)], [2*r*cos(t), -r**2*sin(t)]]) def test_P45(): def __my_wronskian(Y, v): M = Matrix([Matrix(Y).T.diff(x, n) for n in range(0, len(Y))]) return M.det() assert __my_wronskian([cos(x), sin(x)], x).simplify() == 1 # Q1-Q6 Tensor tests missing @XFAIL def test_R1(): i, j, n = symbols('i j n', integer=True, positive=True) xn = MatrixSymbol('xn', n, 1) Sm = Sum((xn[i, 0] - Sum(xn[j, 0], (j, 0, n - 1))/n)**2, (i, 0, n - 1)) # sum does not calculate # Unknown result Sm.doit() raise NotImplementedError('Unknown result') @XFAIL def test_R2(): m, b = symbols('m b') i, n = symbols('i n', integer=True, positive=True) xn = MatrixSymbol('xn', n, 1) yn = MatrixSymbol('yn', n, 1) f = Sum((yn[i, 0] - m*xn[i, 0] - b)**2, (i, 0, n - 1)) f1 = diff(f, m) f2 = diff(f, b) # raises TypeError: solveset() takes at most 2 arguments (3 given) solveset((f1, f2), (m, b), domain=S.Reals) @XFAIL def test_R3(): n, k = symbols('n k', integer=True, positive=True) sk = ((-1)**k) * (binomial(2*n, k))**2 Sm = Sum(sk, (k, 1, oo)) T = Sm.doit() T2 = T.combsimp() # returns -((-1)**n*factorial(2*n) # - (factorial(n))**2)*exp_polar(-I*pi)/(factorial(n))**2 assert T2 == (-1)**n*binomial(2*n, n) @XFAIL def test_R4(): # Macsyma indefinite sum test case: #(c15) /* Check whether the full Gosper algorithm is implemented # => 1/2^(n + 1) binomial(n, k - 1) */ #closedform(indefsum(binomial(n, k)/2^n - binomial(n + 1, k)/2^(n + 1), k)); #Time= 2690 msecs # (- n + k - 1) binomial(n + 1, k) #(d15) - -------------------------------- # n # 2 2 (n + 1) # #(c16) factcomb(makefact(%)); #Time= 220 msecs # n! #(d16) ---------------- # n # 2 k! 2 (n - k)! # Might be possible after fixing https://github.com/sympy/sympy/pull/1879 raise NotImplementedError("Indefinite sum not supported") @XFAIL def test_R5(): a, b, c, n, k = symbols('a b c n k', integer=True, positive=True) sk = ((-1)**k)*(binomial(a + b, a + k) *binomial(b + c, b + k)*binomial(c + a, c + k)) Sm = Sum(sk, (k, 1, oo)) T = Sm.doit() # hypergeometric series not calculated assert T == factorial(a+b+c)/(factorial(a)*factorial(b)*factorial(c)) def test_R6(): n, k = symbols('n k', integer=True, positive=True) gn = MatrixSymbol('gn', n + 2, 1) Sm = Sum(gn[k, 0] - gn[k - 1, 0], (k, 1, n + 1)) assert Sm.doit() == -gn[0, 0] + gn[n + 1, 0] def test_R7(): n, k = symbols('n k', integer=True, positive=True) T = Sum(k**3,(k,1,n)).doit() assert T.factor() == n**2*(n + 1)**2/4 @XFAIL def test_R8(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(k**2*binomial(n, k), (k, 1, n)) T = Sm.doit() #returns Piecewise function assert T.combsimp() == n*(n + 1)*2**(n - 2) def test_R9(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(binomial(n, k - 1)/k, (k, 1, n + 1)) assert Sm.doit().simplify() == (2**(n + 1) - 1)/(n + 1) @XFAIL def test_R10(): n, m, r, k = symbols('n m r k', integer=True, positive=True) Sm = Sum(binomial(n, k)*binomial(m, r - k), (k, 0, r)) T = Sm.doit() T2 = T.combsimp().rewrite(factorial) assert T2 == factorial(m + n)/(factorial(r)*factorial(m + n - r)) assert T2 == binomial(m + n, r).rewrite(factorial) # rewrite(binomial) is not working. # https://github.com/sympy/sympy/issues/7135 T3 = T2.rewrite(binomial) assert T3 == binomial(m + n, r) @XFAIL def test_R11(): n, k = symbols('n k', integer=True, positive=True) sk = binomial(n, k)*fibonacci(k) Sm = Sum(sk, (k, 0, n)) T = Sm.doit() # Fibonacci simplification not implemented # https://github.com/sympy/sympy/issues/7134 assert T == fibonacci(2*n) @XFAIL def test_R12(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(fibonacci(k)**2, (k, 0, n)) T = Sm.doit() assert T == fibonacci(n)*fibonacci(n + 1) @XFAIL def test_R13(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(sin(k*x), (k, 1, n)) T = Sm.doit() # Sum is not calculated assert T.simplify() == cot(x/2)/2 - cos(x*(2*n + 1)/2)/(2*sin(x/2)) @XFAIL def test_R14(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(sin((2*k - 1)*x), (k, 1, n)) T = Sm.doit() # Sum is not calculated assert T.simplify() == sin(n*x)**2/sin(x) @XFAIL def test_R15(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(binomial(n - k, k), (k, 0, floor(n/2))) T = Sm.doit() # Sum is not calculated assert T.simplify() == fibonacci(n + 1) def test_R16(): k = symbols('k', integer=True, positive=True) Sm = Sum(1/k**2 + 1/k**3, (k, 1, oo)) assert Sm.doit() == zeta(3) + pi**2/6 def test_R17(): k = symbols('k', integer=True, positive=True) assert abs(float(Sum(1/k**2 + 1/k**3, (k, 1, oo))) - 2.8469909700078206) < 1e-15 def test_R18(): k = symbols('k', integer=True, positive=True) Sm = Sum(1/(2**k*k**2), (k, 1, oo)) T = Sm.doit() assert T.simplify() == -log(2)**2/2 + pi**2/12 @slow @XFAIL def test_R19(): k = symbols('k', integer=True, positive=True) Sm = Sum(1/((3*k + 1)*(3*k + 2)*(3*k + 3)), (k, 0, oo)) T = Sm.doit() # assert fails, T not simplified assert T.simplify() == -log(3)/4 + sqrt(3)*pi/12 @XFAIL def test_R20(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(binomial(n, 4*k), (k, 0, oo)) T = Sm.doit() # assert fails, T not simplified assert T.simplify() == 2**(n/2)*cos(pi*n/4)/2 + 2**(n - 1)/2 @XFAIL def test_R21(): k = symbols('k', integer=True, positive=True) Sm = Sum(1/(sqrt(k*(k + 1)) * (sqrt(k) + sqrt(k + 1))), (k, 1, oo)) T = Sm.doit() # Sum not calculated assert T.simplify() == 1 # test_R22 answer not available in Wester samples # Sum(Sum(binomial(n, k)*binomial(n - k, n - 2*k)*x**n*y**(n - 2*k), # (k, 0, floor(n/2))), (n, 0, oo)) with abs(x*y)<1? @XFAIL def test_R23(): n, k = symbols('n k', integer=True, positive=True) Sm = Sum(Sum((factorial(n)/(factorial(k)**2*factorial(n - 2*k)))* (x/y)**k*(x*y)**(n - k), (n, 2*k, oo)), (k, 0, oo)) # Missing how to express constraint abs(x*y)<1? T = Sm.doit() # Sum not calculated assert T == -1/sqrt(x**2*y**2 - 4*x**2 - 2*x*y + 1) def test_R24(): m, k = symbols('m k', integer=True, positive=True) Sm = Sum(Product(k/(2*k - 1), (k, 1, m)), (m, 2, oo)) assert Sm.doit() == pi/2 def test_S1(): k = symbols('k', integer=True, positive=True) Pr = Product(gamma(k/3), (k, 1, 8)) assert Pr.doit().simplify() == 640*sqrt(3)*pi**3/6561 def test_S2(): n, k = symbols('n k', integer=True, positive=True) assert Product(k, (k, 1, n)).doit() == factorial(n) def test_S3(): n, k = symbols('n k', integer=True, positive=True) assert Product(x**k, (k, 1, n)).doit().simplify() == x**(n*(n + 1)/2) def test_S4(): n, k = symbols('n k', integer=True, positive=True) assert Product(1 + 1/k, (k, 1, n -1)).doit().simplify() == n def test_S5(): n, k = symbols('n k', integer=True, positive=True) assert (Product((2*k - 1)/(2*k), (k, 1, n)).doit().gammasimp() == gamma(n + S.Half)/(sqrt(pi)*gamma(n + 1))) @XFAIL def test_S6(): n, k = symbols('n k', integer=True, positive=True) # Product does not evaluate assert (Product(x**2 -2*x*cos(k*pi/n) + 1, (k, 1, n - 1)).doit().simplify() == (x**(2*n) - 1)/(x**2 - 1)) @XFAIL def test_S7(): k = symbols('k', integer=True, positive=True) Pr = Product((k**3 - 1)/(k**3 + 1), (k, 2, oo)) T = Pr.doit() # Product does not evaluate assert T.simplify() == R(2, 3) @XFAIL def test_S8(): k = symbols('k', integer=True, positive=True) Pr = Product(1 - 1/(2*k)**2, (k, 1, oo)) T = Pr.doit() # Product does not evaluate assert T.simplify() == 2/pi @XFAIL def test_S9(): k = symbols('k', integer=True, positive=True) Pr = Product(1 + (-1)**(k + 1)/(2*k - 1), (k, 1, oo)) T = Pr.doit() # Product produces 0 # https://github.com/sympy/sympy/issues/7133 assert T.simplify() == sqrt(2) @XFAIL def test_S10(): k = symbols('k', integer=True, positive=True) Pr = Product((k*(k + 1) + 1 + I)/(k*(k + 1) + 1 - I), (k, 0, oo)) T = Pr.doit() # Product does not evaluate assert T.simplify() == -1 def test_T1(): assert limit((1 + 1/n)**n, n, oo) == E assert limit((1 - cos(x))/x**2, x, 0) == S.Half def test_T2(): assert limit((3**x + 5**x)**(1/x), x, oo) == 5 def test_T3(): assert limit(log(x)/(log(x) + sin(x)), x, oo) == 1 def test_T4(): assert limit((exp(x*exp(-x)/(exp(-x) + exp(-2*x**2/(x + 1)))) - exp(x))/x, x, oo) == -exp(2) def test_T5(): assert limit(x*log(x)*log(x*exp(x) - x**2)**2/log(log(x**2 + 2*exp(exp(3*x**3*log(x))))), x, oo) == R(1, 3) def test_T6(): assert limit(1/n * factorial(n)**(1/n), n, oo) == exp(-1) def test_T7(): limit(1/n * gamma(n + 1)**(1/n), n, oo) def test_T8(): a, z = symbols('a z', real=True, positive=True) assert limit(gamma(z + a)/gamma(z)*exp(-a*log(z)), z, oo) == 1 @XFAIL def test_T9(): z, k = symbols('z k', real=True, positive=True) # raises NotImplementedError: # Don't know how to calculate the mrv of '(1, k)' assert limit(hyper((1, k), (1,), z/k), k, oo) == exp(z) @XFAIL def test_T10(): # No longer raises PoleError, but should return euler-mascheroni constant assert limit(zeta(x) - 1/(x - 1), x, 1) == integrate(-1/x + 1/floor(x), (x, 1, oo)) @XFAIL def test_T11(): n, k = symbols('n k', integer=True, positive=True) # evaluates to 0 assert limit(n**x/(x*product((1 + x/k), (k, 1, n))), n, oo) == gamma(x) def test_T12(): x, t = symbols('x t', real=True) # Does not evaluate the limit but returns an expression with erf assert limit(x * integrate(exp(-t**2), (t, 0, x))/(1 - exp(-x**2)), x, 0) == 1 def test_T13(): x = symbols('x', real=True) assert [limit(x/abs(x), x, 0, dir='-'), limit(x/abs(x), x, 0, dir='+')] == [-1, 1] def test_T14(): x = symbols('x', real=True) assert limit(atan(-log(x)), x, 0, dir='+') == pi/2 def test_U1(): x = symbols('x', real=True) assert diff(abs(x), x) == sign(x) def test_U2(): f = Lambda(x, Piecewise((-x, x < 0), (x, x >= 0))) assert diff(f(x), x) == Piecewise((-1, x < 0), (1, x >= 0)) def test_U3(): f = Lambda(x, Piecewise((x**2 - 1, x == 1), (x**3, x != 1))) f1 = Lambda(x, diff(f(x), x)) assert f1(x) == 3*x**2 assert f1(1) == 3 @XFAIL def test_U4(): n = symbols('n', integer=True, positive=True) x = symbols('x', real=True) d = diff(x**n, x, n) assert d.rewrite(factorial) == factorial(n) def test_U5(): # issue 6681 t = symbols('t') ans = ( Derivative(f(g(t)), g(t))*Derivative(g(t), (t, 2)) + Derivative(f(g(t)), (g(t), 2))*Derivative(g(t), t)**2) assert f(g(t)).diff(t, 2) == ans assert ans.doit() == ans def test_U6(): h = Function('h') T = integrate(f(y), (y, h(x), g(x))) assert T.diff(x) == ( f(g(x))*Derivative(g(x), x) - f(h(x))*Derivative(h(x), x)) @XFAIL def test_U7(): p, t = symbols('p t', real=True) # Exact differential => d(V(P, T)) => dV/dP DP + dV/dT DT # raises ValueError: Since there is more than one variable in the # expression, the variable(s) of differentiation must be supplied to # differentiate f(p,t) diff(f(p, t)) def test_U8(): x, y = symbols('x y', real=True) eq = cos(x*y) + x # If SymPy had implicit_diff() function this hack could be avoided # TODO: Replace solve with solveset, current test fails for solveset assert idiff(y - eq, y, x) == (-y*sin(x*y) + 1)/(x*sin(x*y) + 1) def test_U9(): # Wester sample case for Maple: # O29 := diff(f(x, y), x) + diff(f(x, y), y); # /d \ /d \ # |-- f(x, y)| + |-- f(x, y)| # \dx / \dy / # # O30 := factor(subs(f(x, y) = g(x^2 + y^2), %)); # 2 2 # 2 D(g)(x + y ) (x + y) x, y = symbols('x y', real=True) su = diff(f(x, y), x) + diff(f(x, y), y) s2 = su.subs(f(x, y), g(x**2 + y**2)) s3 = s2.doit().factor() # Subs not performed, s3 = 2*(x + y)*Subs(Derivative( # g(_xi_1), _xi_1), _xi_1, x**2 + y**2) # Derivative(g(x*2 + y**2), x**2 + y**2) is not valid in SymPy, # and probably will remain that way. You can take derivatives with respect # to other expressions only if they are atomic, like a symbol or a # function. # D operator should be added to SymPy # See https://github.com/sympy/sympy/issues/4719. assert s3 == (x + y)*Subs(Derivative(g(x), x), x, x**2 + y**2)*2 def test_U10(): # see issue 2519: assert residue((z**3 + 5)/((z**4 - 1)*(z + 1)), z, -1) == R(-9, 4) @XFAIL def test_U11(): # assert (2*dx + dz) ^ (3*dx + dy + dz) ^ (dx + dy + 4*dz) == 8*dx ^ dy ^dz raise NotImplementedError @XFAIL def test_U12(): # Wester sample case: # (c41) /* d(3 x^5 dy /\ dz + 5 x y^2 dz /\ dx + 8 z dx /\ dy) # => (15 x^4 + 10 x y + 8) dx /\ dy /\ dz */ # factor(ext_diff(3*x^5 * dy ~ dz + 5*x*y^2 * dz ~ dx + 8*z * dx ~ dy)); # 4 # (d41) (10 x y + 15 x + 8) dx dy dz raise NotImplementedError( "External diff of differential form not supported") def test_U13(): assert minimum(x**4 - x + 1, x) == -3*2**R(1,3)/8 + 1 @XFAIL def test_U14(): #f = 1/(x**2 + y**2 + 1) #assert [minimize(f), maximize(f)] == [0,1] raise NotImplementedError("minimize(), maximize() not supported") @XFAIL def test_U15(): raise NotImplementedError("minimize() not supported and also solve does \ not support multivariate inequalities") @XFAIL def test_U16(): raise NotImplementedError("minimize() not supported in SymPy and also \ solve does not support multivariate inequalities") @XFAIL def test_U17(): raise NotImplementedError("Linear programming, symbolic simplex not \ supported in SymPy") def test_V1(): x = symbols('x', real=True) assert integrate(abs(x), x) == Piecewise((-x**2/2, x <= 0), (x**2/2, True)) def test_V2(): assert integrate(Piecewise((-x, x < 0), (x, x >= 0)), x ) == Piecewise((-x**2/2, x < 0), (x**2/2, True)) def test_V3(): assert integrate(1/(x**3 + 2),x).diff().simplify() == 1/(x**3 + 2) def test_V4(): assert integrate(2**x/sqrt(1 + 4**x), x) == asinh(2**x)/log(2) @XFAIL def test_V5(): # Returns (-45*x**2 + 80*x - 41)/(5*sqrt(2*x - 1)*(4*x**2 - 4*x + 1)) assert (integrate((3*x - 5)**2/(2*x - 1)**R(7, 2), x).simplify() == (-41 + 80*x - 45*x**2)/(5*(2*x - 1)**R(5, 2))) @XFAIL def test_V6(): # returns RootSum(40*_z**2 - 1, Lambda(_i, _i*log(-4*_i + exp(-m*x))))/m assert (integrate(1/(2*exp(m*x) - 5*exp(-m*x)), x) == sqrt(10)*( log(2*exp(m*x) - sqrt(10)) - log(2*exp(m*x) + sqrt(10)))/(20*m)) def test_V7(): r1 = integrate(sinh(x)**4/cosh(x)**2) assert r1.simplify() == x*R(-3, 2) + sinh(x)**3/(2*cosh(x)) + 3*tanh(x)/2 @XFAIL def test_V8_V9(): #Macsyma test case: #(c27) /* This example involves several symbolic parameters # => 1/sqrt(b^2 - a^2) log([sqrt(b^2 - a^2) tan(x/2) + a + b]/ # [sqrt(b^2 - a^2) tan(x/2) - a - b]) (a^2 < b^2) # [Gradshteyn and Ryzhik 2.553(3)] */ #assume(b^2 > a^2)$ #(c28) integrate(1/(a + b*cos(x)), x); #(c29) trigsimp(ratsimp(diff(%, x))); # 1 #(d29) ------------ # b cos(x) + a raise NotImplementedError( "Integrate with assumption not supported") def test_V10(): assert integrate(1/(3 + 3*cos(x) + 4*sin(x)), x) == log(tan(x/2) + R(3, 4))/4 def test_V11(): r1 = integrate(1/(4 + 3*cos(x) + 4*sin(x)), x) r2 = factor(r1) assert (logcombine(r2, force=True) == log(((tan(x/2) + 1)/(tan(x/2) + 7))**R(1, 3))) def test_V12(): r1 = integrate(1/(5 + 3*cos(x) + 4*sin(x)), x) assert r1 == -1/(tan(x/2) + 2) @XFAIL def test_V13(): r1 = integrate(1/(6 + 3*cos(x) + 4*sin(x)), x) # expression not simplified, returns: -sqrt(11)*I*log(tan(x/2) + 4/3 # - sqrt(11)*I/3)/11 + sqrt(11)*I*log(tan(x/2) + 4/3 + sqrt(11)*I/3)/11 assert r1.simplify() == 2*sqrt(11)*atan(sqrt(11)*(3*tan(x/2) + 4)/11)/11 @slow @XFAIL def test_V14(): r1 = integrate(log(abs(x**2 - y**2)), x) # Piecewise result does not simplify to the desired result. assert (r1.simplify() == x*log(abs(x**2 - y**2)) + y*log(x + y) - y*log(x - y) - 2*x) def test_V15(): r1 = integrate(x*acot(x/y), x) assert simplify(r1 - (x*y + (x**2 + y**2)*acot(x/y))/2) == 0 @XFAIL def test_V16(): # Integral not calculated assert integrate(cos(5*x)*Ci(2*x), x) == Ci(2*x)*sin(5*x)/5 - (Si(3*x) + Si(7*x))/10 @XFAIL def test_V17(): r1 = integrate((diff(f(x), x)*g(x) - f(x)*diff(g(x), x))/(f(x)**2 - g(x)**2), x) # integral not calculated assert simplify(r1 - (f(x) - g(x))/(f(x) + g(x))/2) == 0 @XFAIL def test_W1(): # The function has a pole at y. # The integral has a Cauchy principal value of zero but SymPy returns -I*pi # https://github.com/sympy/sympy/issues/7159 assert integrate(1/(x - y), (x, y - 1, y + 1)) == 0 @XFAIL def test_W2(): # The function has a pole at y. # The integral is divergent but SymPy returns -2 # https://github.com/sympy/sympy/issues/7160 # Test case in Macsyma: # (c6) errcatch(integrate(1/(x - a)^2, x, a - 1, a + 1)); # Integral is divergent assert integrate(1/(x - y)**2, (x, y - 1, y + 1)) is zoo @XFAIL @slow def test_W3(): # integral is not calculated # https://github.com/sympy/sympy/issues/7161 assert integrate(sqrt(x + 1/x - 2), (x, 0, 1)) == R(4, 3) @XFAIL @slow def test_W4(): # integral is not calculated assert integrate(sqrt(x + 1/x - 2), (x, 1, 2)) == -2*sqrt(2)/3 + R(4, 3) @XFAIL @slow def test_W5(): # integral is not calculated assert integrate(sqrt(x + 1/x - 2), (x, 0, 2)) == -2*sqrt(2)/3 + R(8, 3) @XFAIL @slow def test_W6(): # integral is not calculated assert integrate(sqrt(2 - 2*cos(2*x))/2, (x, pi*R(-3, 4), -pi/4)) == sqrt(2) def test_W7(): a = symbols('a', real=True, positive=True) r1 = integrate(cos(x)/(x**2 + a**2), (x, -oo, oo)) assert r1.simplify() == pi*exp(-a)/a @XFAIL def test_W8(): # Test case in Mathematica: # In[19]:= Integrate[t^(a - 1)/(1 + t), {t, 0, Infinity}, # Assumptions -> 0 < a < 1] # Out[19]= Pi Csc[a Pi] raise NotImplementedError( "Integrate with assumption 0 < a < 1 not supported") @XFAIL @slow def test_W9(): # Integrand with a residue at infinity => -2 pi [sin(pi/5) + sin(2pi/5)] # (principal value) [Levinson and Redheffer, p. 234] *) r1 = integrate(5*x**3/(1 + x + x**2 + x**3 + x**4), (x, -oo, oo)) r2 = r1.doit() assert r2 == -2*pi*(sqrt(-sqrt(5)/8 + 5/8) + sqrt(sqrt(5)/8 + 5/8)) @XFAIL def test_W10(): # integrate(1/[1 + x + x^2 + ... + x^(2 n)], x = -infinity..infinity) = # 2 pi/(2 n + 1) [1 + cos(pi/[2 n + 1])] csc(2 pi/[2 n + 1]) # [Levinson and Redheffer, p. 255] => 2 pi/5 [1 + cos(pi/5)] csc(2 pi/5) */ r1 = integrate(x/(1 + x + x**2 + x**4), (x, -oo, oo)) r2 = r1.doit() assert r2 == 2*pi*(sqrt(5)/4 + 5/4)*csc(pi*R(2, 5))/5 @XFAIL def test_W11(): # integral not calculated assert (integrate(sqrt(1 - x**2)/(1 + x**2), (x, -1, 1)) == pi*(-1 + sqrt(2))) def test_W12(): p = symbols('p', real=True, positive=True) q = symbols('q', real=True) r1 = integrate(x*exp(-p*x**2 + 2*q*x), (x, -oo, oo)) assert r1.simplify() == sqrt(pi)*q*exp(q**2/p)/p**R(3, 2) @XFAIL def test_W13(): # Integral not calculated. Expected result is 2*(Euler_mascheroni_constant) r1 = integrate(1/log(x) + 1/(1 - x) - log(log(1/x)), (x, 0, 1)) assert r1 == 2*EulerGamma def test_W14(): assert integrate(sin(x)/x*exp(2*I*x), (x, -oo, oo)) == 0 @XFAIL def test_W15(): # integral not calculated assert integrate(log(gamma(x))*cos(6*pi*x), (x, 0, 1)) == R(1, 12) def test_W16(): assert integrate((1 + x)**3*legendre_poly(1, x)*legendre_poly(2, x), (x, -1, 1)) == R(36, 35) def test_W17(): a, b = symbols('a b', real=True, positive=True) assert integrate(exp(-a*x)*besselj(0, b*x), (x, 0, oo)) == 1/(b*sqrt(a**2/b**2 + 1)) def test_W18(): assert integrate((besselj(1, x)/x)**2, (x, 0, oo)) == 4/(3*pi) @XFAIL def test_W19(): # Integral not calculated # Expected result is (cos 7 - 1)/7 [Gradshteyn and Ryzhik 6.782(3)] assert integrate(Ci(x)*besselj(0, 2*sqrt(7*x)), (x, 0, oo)) == (cos(7) - 1)/7 @XFAIL def test_W20(): # integral not calculated assert (integrate(x**2*polylog(3, 1/(x + 1)), (x, 0, 1)) == -pi**2/36 - R(17, 108) + zeta(3)/4 + (-pi**2/2 - 4*log(2) + log(2)**2 + 35/3)*log(2)/9) def test_W21(): assert abs(N(integrate(x**2*polylog(3, 1/(x + 1)), (x, 0, 1))) - 0.210882859565594) < 1e-15 def test_W22(): t, u = symbols('t u', real=True) s = Lambda(x, Piecewise((1, And(x >= 1, x <= 2)), (0, True))) assert integrate(s(t)*cos(t), (t, 0, u)) == Piecewise( (0, u < 0), (-sin(Min(1, u)) + sin(Min(2, u)), True)) @slow def test_W23(): a, b = symbols('a b', real=True, positive=True) r1 = integrate(integrate(x/(x**2 + y**2), (x, a, b)), (y, -oo, oo)) assert r1.collect(pi).cancel() == -pi*a + pi*b def test_W23b(): # like W23 but limits are reversed a, b = symbols('a b', real=True, positive=True) r2 = integrate(integrate(x/(x**2 + y**2), (y, -oo, oo)), (x, a, b)) assert r2.collect(pi) == pi*(-a + b) @XFAIL @slow def test_W24(): if ON_TRAVIS: skip("Too slow for travis.") # Not that slow, but does not fully evaluate so simplify is slow. # Maybe also require doit() x, y = symbols('x y', real=True) r1 = integrate(integrate(sqrt(x**2 + y**2), (x, 0, 1)), (y, 0, 1)) assert (r1 - (sqrt(2) + asinh(1))/3).simplify() == 0 @XFAIL @slow def test_W25(): if ON_TRAVIS: skip("Too slow for travis.") a, x, y = symbols('a x y', real=True) i1 = integrate( sin(a)*sin(y)/sqrt(1 - sin(a)**2*sin(x)**2*sin(y)**2), (x, 0, pi/2)) i2 = integrate(i1, (y, 0, pi/2)) assert (i2 - pi*a/2).simplify() == 0 def test_W26(): x, y = symbols('x y', real=True) assert integrate(integrate(abs(y - x**2), (y, 0, 2)), (x, -1, 1)) == R(46, 15) def test_W27(): a, b, c = symbols('a b c') assert integrate(integrate(integrate(1, (z, 0, c*(1 - x/a - y/b))), (y, 0, b*(1 - x/a))), (x, 0, a)) == a*b*c/6 def test_X1(): v, c = symbols('v c', real=True) assert (series(1/sqrt(1 - (v/c)**2), v, x0=0, n=8) == 5*v**6/(16*c**6) + 3*v**4/(8*c**4) + v**2/(2*c**2) + 1 + O(v**8)) def test_X2(): v, c = symbols('v c', real=True) s1 = series(1/sqrt(1 - (v/c)**2), v, x0=0, n=8) assert (1/s1**2).series(v, x0=0, n=8) == -v**2/c**2 + 1 + O(v**8) def test_X3(): s1 = (sin(x).series()/cos(x).series()).series() s2 = tan(x).series() assert s2 == x + x**3/3 + 2*x**5/15 + O(x**6) assert s1 == s2 def test_X4(): s1 = log(sin(x)/x).series() assert s1 == -x**2/6 - x**4/180 + O(x**6) assert log(series(sin(x)/x)).series() == s1 @XFAIL def test_X5(): # test case in Mathematica syntax: # In[21]:= (* => [a f'(a d) + g(b d) + integrate(h(c y), y = 0..d)] # + [a^2 f''(a d) + b g'(b d) + h(c d)] (x - d) *) # In[22]:= D[f[a*x], x] + g[b*x] + Integrate[h[c*y], {y, 0, x}] # Out[22]= g[b x] + Integrate[h[c y], {y, 0, x}] + a f'[a x] # In[23]:= Series[%, {x, d, 1}] # Out[23]= (g[b d] + Integrate[h[c y], {y, 0, d}] + a f'[a d]) + # 2 2 # (h[c d] + b g'[b d] + a f''[a d]) (-d + x) + O[-d + x] h = Function('h') a, b, c, d = symbols('a b c d', real=True) # series() raises NotImplementedError: # The _eval_nseries method should be added to to give terms up to O(x**n) at x=0 series(diff(f(a*x), x) + g(b*x) + integrate(h(c*y), (y, 0, x)), x, x0=d, n=2) # assert missing, until exception is removed def test_X6(): # Taylor series of nonscalar objects (noncommutative multiplication) # expected result => (B A - A B) t^2/2 + O(t^3) [Stanly Steinberg] a, b = symbols('a b', commutative=False, scalar=False) assert (series(exp((a + b)*x) - exp(a*x) * exp(b*x), x, x0=0, n=3) == x**2*(-a*b/2 + b*a/2) + O(x**3)) def test_X7(): # => sum( Bernoulli[k]/k! x^(k - 2), k = 1..infinity ) # = 1/x^2 - 1/(2 x) + 1/12 - x^2/720 + x^4/30240 + O(x^6) # [Levinson and Redheffer, p. 173] assert (series(1/(x*(exp(x) - 1)), x, 0, 7) == x**(-2) - 1/(2*x) + R(1, 12) - x**2/720 + x**4/30240 - x**6/1209600 + O(x**7)) def test_X8(): # Puiseux series (terms with fractional degree): # => 1/sqrt(x - 3/2 pi) + (x - 3/2 pi)^(3/2) / 12 + O([x - 3/2 pi]^(7/2)) # see issue 7167: x = symbols('x', real=True) assert (series(sqrt(sec(x)), x, x0=pi*3/2, n=4) == 1/sqrt(x - pi*R(3, 2)) + (x - pi*R(3, 2))**R(3, 2)/12 + (x - pi*R(3, 2))**R(7, 2)/160 + O((x - pi*R(3, 2))**4, (x, pi*R(3, 2)))) def test_X9(): assert (series(x**x, x, x0=0, n=4) == 1 + x*log(x) + x**2*log(x)**2/2 + x**3*log(x)**3/6 + O(x**4*log(x)**4)) def test_X10(): z, w = symbols('z w') assert (series(log(sinh(z)) + log(cosh(z + w)), z, x0=0, n=2) == log(cosh(w)) + log(z) + z*sinh(w)/cosh(w) + O(z**2)) def test_X11(): z, w = symbols('z w') assert (series(log(sinh(z) * cosh(z + w)), z, x0=0, n=2) == log(cosh(w)) + log(z) + z*sinh(w)/cosh(w) + O(z**2)) @XFAIL def test_X12(): # Look at the generalized Taylor series around x = 1 # Result => (x - 1)^a/e^b [1 - (a + 2 b) (x - 1) / 2 + O((x - 1)^2)] a, b, x = symbols('a b x', real=True) # series returns O(log(x-1)**2) # https://github.com/sympy/sympy/issues/7168 assert (series(log(x)**a*exp(-b*x), x, x0=1, n=2) == (x - 1)**a/exp(b)*(1 - (a + 2*b)*(x - 1)/2 + O((x - 1)**2))) def test_X13(): assert series(sqrt(2*x**2 + 1), x, x0=oo, n=1) == sqrt(2)*x + O(1/x, (x, oo)) @XFAIL def test_X14(): # Wallis' product => 1/sqrt(pi n) + ... [Knopp, p. 385] assert series(1/2**(2*n)*binomial(2*n, n), n, x==oo, n=1) == 1/(sqrt(pi)*sqrt(n)) + O(1/x, (x, oo)) @SKIP("https://github.com/sympy/sympy/issues/7164") def test_X15(): # => 0!/x - 1!/x^2 + 2!/x^3 - 3!/x^4 + O(1/x^5) [Knopp, p. 544] x, t = symbols('x t', real=True) # raises RuntimeError: maximum recursion depth exceeded # https://github.com/sympy/sympy/issues/7164 # 2019-02-17: Raises # PoleError: # Asymptotic expansion of Ei around [-oo] is not implemented. e1 = integrate(exp(-t)/t, (t, x, oo)) assert (series(e1, x, x0=oo, n=5) == 6/x**4 + 2/x**3 - 1/x**2 + 1/x + O(x**(-5), (x, oo))) def test_X16(): # Multivariate Taylor series expansion => 1 - (x^2 + 2 x y + y^2)/2 + O(x^4) assert (series(cos(x + y), x + y, x0=0, n=4) == 1 - (x + y)**2/2 + O(x**4 + x**3*y + x**2*y**2 + x*y**3 + y**4, x, y)) @XFAIL def test_X17(): # Power series (compute the general formula) # (c41) powerseries(log(sin(x)/x), x, 0); # /aquarius/data2/opt/local/macsyma_422/library1/trgred.so being loaded. # inf # ==== i1 2 i1 2 i1 # \ (- 1) 2 bern(2 i1) x # (d41) > ------------------------------ # / 2 i1 (2 i1)! # ==== # i1 = 1 # fps does not calculate assert fps(log(sin(x)/x)) == \ Sum((-1)**k*2**(2*k - 1)*bernoulli(2*k)*x**(2*k)/(k*factorial(2*k)), (k, 1, oo)) @XFAIL def test_X18(): # Power series (compute the general formula). Maple FPS: # > FormalPowerSeries(exp(-x)*sin(x), x = 0); # infinity # ----- (1/2 k) k # \ 2 sin(3/4 k Pi) x # ) ------------------------- # / k! # ----- # # Now, sympy returns # oo # _____ # \ ` # \ / k k\ # \ k |I*(-1 - I) I*(-1 + I) | # \ x *|----------- - -----------| # / \ 2 2 / # / ------------------------------ # / k! # /____, # k = 0 k = Dummy('k') assert fps(exp(-x)*sin(x)) == \ Sum(2**(S.Half*k)*sin(R(3, 4)*k*pi)*x**k/factorial(k), (k, 0, oo)) @XFAIL def test_X19(): # (c45) /* Derive an explicit Taylor series solution of y as a function of # x from the following implicit relation: # y = x - 1 + (x - 1)^2/2 + 2/3 (x - 1)^3 + (x - 1)^4 + # 17/10 (x - 1)^5 + ... # */ # x = sin(y) + cos(y); # Time= 0 msecs # (d45) x = sin(y) + cos(y) # # (c46) taylor_revert(%, y, 7); raise NotImplementedError("Solve using series not supported. \ Inverse Taylor series expansion also not supported") @XFAIL def test_X20(): # Pade (rational function) approximation => (2 - x)/(2 + x) # > numapprox[pade](exp(-x), x = 0, [1, 1]); # bytes used=9019816, alloc=3669344, time=13.12 # 1 - 1/2 x # --------- # 1 + 1/2 x # mpmath support numeric Pade approximant but there is # no symbolic implementation in SymPy # https://en.wikipedia.org/wiki/Pad%C3%A9_approximant raise NotImplementedError("Symbolic Pade approximant not supported") def test_X21(): """ Test whether `fourier_series` of x periodical on the [-p, p] interval equals `- (2 p / pi) sum( (-1)^n / n sin(n pi x / p), n = 1..infinity )`. """ p = symbols('p', positive=True) n = symbols('n', positive=True, integer=True) s = fourier_series(x, (x, -p, p)) # All cosine coefficients are equal to 0 assert s.an.formula == 0 # Check for sine coefficients assert s.bn.formula.subs(s.bn.variables[0], 0) == 0 assert s.bn.formula.subs(s.bn.variables[0], n) == \ -2*p/pi * (-1)**n / n * sin(n*pi*x/p) @XFAIL def test_X22(): # (c52) /* => p / 2 # - (2 p / pi^2) sum( [1 - (-1)^n] cos(n pi x / p) / n^2, # n = 1..infinity ) */ # fourier_series(abs(x), x, p); # p # (e52) a = - # 0 2 # # %nn # (2 (- 1) - 2) p # (e53) a = ------------------ # %nn 2 2 # %pi %nn # # (e54) b = 0 # %nn # # Time= 5290 msecs # inf %nn %pi %nn x # ==== (2 (- 1) - 2) cos(---------) # \ p # p > ------------------------------- # / 2 # ==== %nn # %nn = 1 p # (d54) ----------------------------------------- + - # 2 2 # %pi raise NotImplementedError("Fourier series not supported") def test_Y1(): t = symbols('t', real=True, positive=True) w = symbols('w', real=True) s = symbols('s') F, _, _ = laplace_transform(cos((w - 1)*t), t, s) assert F == s/(s**2 + (w - 1)**2) def test_Y2(): t = symbols('t', real=True, positive=True) w = symbols('w', real=True) s = symbols('s') f = inverse_laplace_transform(s/(s**2 + (w - 1)**2), s, t) assert f == cos(t*w - t) def test_Y3(): t = symbols('t', real=True, positive=True) w = symbols('w', real=True) s = symbols('s') F, _, _ = laplace_transform(sinh(w*t)*cosh(w*t), t, s) assert F == w/(s**2 - 4*w**2) def test_Y4(): t = symbols('t', real=True, positive=True) s = symbols('s') F, _, _ = laplace_transform(erf(3/sqrt(t)), t, s) assert F == (1 - exp(-6*sqrt(s)))/s @XFAIL def test_Y5_Y6(): # Solve y'' + y = 4 [H(t - 1) - H(t - 2)], y(0) = 1, y'(0) = 0 where H is the # Heaviside (unit step) function (the RHS describes a pulse of magnitude 4 and # duration 1). See David A. Sanchez, Richard C. Allen, Jr. and Walter T. # Kyner, _Differential Equations: An Introduction_, Addison-Wesley Publishing # Company, 1983, p. 211. First, take the Laplace transform of the ODE # => s^2 Y(s) - s + Y(s) = 4/s [e^(-s) - e^(-2 s)] # where Y(s) is the Laplace transform of y(t) t = symbols('t', real=True, positive=True) s = symbols('s') y = Function('y') F, _, _ = laplace_transform(diff(y(t), t, 2) + y(t) - 4*(Heaviside(t - 1) - Heaviside(t - 2)), t, s) # Laplace transform for diff() not calculated # https://github.com/sympy/sympy/issues/7176 assert (F == s**2*LaplaceTransform(y(t), t, s) - s + LaplaceTransform(y(t), t, s) - 4*exp(-s)/s + 4*exp(-2*s)/s) # TODO implement second part of test case # Now, solve for Y(s) and then take the inverse Laplace transform # => Y(s) = s/(s^2 + 1) + 4 [1/s - s/(s^2 + 1)] [e^(-s) - e^(-2 s)] # => y(t) = cos t + 4 {[1 - cos(t - 1)] H(t - 1) - [1 - cos(t - 2)] H(t - 2)} @XFAIL def test_Y7(): # What is the Laplace transform of an infinite square wave? # => 1/s + 2 sum( (-1)^n e^(- s n a)/s, n = 1..infinity ) # [Sanchez, Allen and Kyner, p. 213] t = symbols('t', real=True, positive=True) a = symbols('a', real=True) s = symbols('s') F, _, _ = laplace_transform(1 + 2*Sum((-1)**n*Heaviside(t - n*a), (n, 1, oo)), t, s) # returns 2*LaplaceTransform(Sum((-1)**n*Heaviside(-a*n + t), # (n, 1, oo)), t, s) + 1/s # https://github.com/sympy/sympy/issues/7177 assert F == 2*Sum((-1)**n*exp(-a*n*s)/s, (n, 1, oo)) + 1/s @XFAIL def test_Y8(): assert fourier_transform(1, x, z) == DiracDelta(z) def test_Y9(): assert (fourier_transform(exp(-9*x**2), x, z) == sqrt(pi)*exp(-pi**2*z**2/9)/3) def test_Y10(): assert (fourier_transform(abs(x)*exp(-3*abs(x)), x, z).cancel() == (-8*pi**2*z**2 + 18)/(16*pi**4*z**4 + 72*pi**2*z**2 + 81)) @SKIP("https://github.com/sympy/sympy/issues/7181") @slow def test_Y11(): # => pi cot(pi s) (0 < Re s < 1) [Gradshteyn and Ryzhik 17.43(5)] x, s = symbols('x s') # raises RuntimeError: maximum recursion depth exceeded # https://github.com/sympy/sympy/issues/7181 # Update 2019-02-17 raises: # TypeError: cannot unpack non-iterable MellinTransform object F, _, _ = mellin_transform(1/(1 - x), x, s) assert F == pi*cot(pi*s) @XFAIL def test_Y12(): # => 2^(s - 4) gamma(s/2)/gamma(4 - s/2) (0 < Re s < 1) # [Gradshteyn and Ryzhik 17.43(16)] x, s = symbols('x s') # returns Wrong value -2**(s - 4)*gamma(s/2 - 3)/gamma(-s/2 + 1) # https://github.com/sympy/sympy/issues/7182 F, _, _ = mellin_transform(besselj(3, x)/x**3, x, s) assert F == -2**(s - 4)*gamma(s/2)/gamma(-s/2 + 4) @XFAIL def test_Y13(): # Z[H(t - m T)] => z/[z^m (z - 1)] (H is the Heaviside (unit step) function) z raise NotImplementedError("z-transform not supported") @XFAIL def test_Y14(): # Z[H(t - m T)] => z/[z^m (z - 1)] (H is the Heaviside (unit step) function) raise NotImplementedError("z-transform not supported") def test_Z1(): r = Function('r') assert (rsolve(r(n + 2) - 2*r(n + 1) + r(n) - 2, r(n), {r(0): 1, r(1): m}).simplify() == n**2 + n*(m - 2) + 1) def test_Z2(): r = Function('r') assert (rsolve(r(n) - (5*r(n - 1) - 6*r(n - 2)), r(n), {r(0): 0, r(1): 1}) == -2**n + 3**n) def test_Z3(): # => r(n) = Fibonacci[n + 1] [Cohen, p. 83] r = Function('r') # recurrence solution is correct, Wester expects it to be simplified to # fibonacci(n+1), but that is quite hard expected = ((S(1)/2 - sqrt(5)/2)**n*(S(1)/2 - sqrt(5)/10) + (S(1)/2 + sqrt(5)/2)**n*(sqrt(5)/10 + S(1)/2)) sol = rsolve(r(n) - (r(n - 1) + r(n - 2)), r(n), {r(1): 1, r(2): 2}) assert sol == expected @XFAIL def test_Z4(): # => [c^(n+1) [c^(n+1) - 2 c - 2] + (n+1) c^2 + 2 c - n] / [(c-1)^3 (c+1)] # [Joan Z. Yu and Robert Israel in sci.math.symbolic] r = Function('r') c = symbols('c') # raises ValueError: Polynomial or rational function expected, # got '(c**2 - c**n)/(c - c**n) s = rsolve(r(n) - ((1 + c - c**(n-1) - c**(n+1))/(1 - c**n)*r(n - 1) - c*(1 - c**(n-2))/(1 - c**(n-1))*r(n - 2) + 1), r(n), {r(1): 1, r(2): (2 + 2*c + c**2)/(1 + c)}) assert (s - (c*(n + 1)*(c*(n + 1) - 2*c - 2) + (n + 1)*c**2 + 2*c - n)/((c-1)**3*(c+1)) == 0) @XFAIL def test_Z5(): # Second order ODE with initial conditions---solve directly # transform: f(t) = sin(2 t)/8 - t cos(2 t)/4 C1, C2 = symbols('C1 C2') # initial conditions not supported, this is a manual workaround # https://github.com/sympy/sympy/issues/4720 eq = Derivative(f(x), x, 2) + 4*f(x) - sin(2*x) sol = dsolve(eq, f(x)) f0 = Lambda(x, sol.rhs) assert f0(x) == C2*sin(2*x) + (C1 - x/4)*cos(2*x) f1 = Lambda(x, diff(f0(x), x)) # TODO: Replace solve with solveset, when it works for solveset const_dict = solve((f0(0), f1(0))) result = f0(x).subs(C1, const_dict[C1]).subs(C2, const_dict[C2]) assert result == -x*cos(2*x)/4 + sin(2*x)/8 # Result is OK, but ODE solving with initial conditions should be # supported without all this manual work raise NotImplementedError('ODE solving with initial conditions \ not supported') @XFAIL def test_Z6(): # Second order ODE with initial conditions---solve using Laplace # transform: f(t) = sin(2 t)/8 - t cos(2 t)/4 t = symbols('t', real=True, positive=True) s = symbols('s') eq = Derivative(f(t), t, 2) + 4*f(t) - sin(2*t) F, _, _ = laplace_transform(eq, t, s) # Laplace transform for diff() not calculated # https://github.com/sympy/sympy/issues/7176 assert (F == s**2*LaplaceTransform(f(t), t, s) + 4*LaplaceTransform(f(t), t, s) - 2/(s**2 + 4)) # rest of test case not implemented sympy-sympy-1.9/sympy/utilities/timeutils.py000066400000000000000000000036601412543434000215150ustar00rootroot00000000000000"""Simple tools for timing functions' execution, when IPython is not available. """ import timeit import math _scales = [1e0, 1e3, 1e6, 1e9] _units = ['s', 'ms', '\N{GREEK SMALL LETTER MU}s', 'ns'] def timed(func, setup="pass", limit=None): """Adaptively measure execution time of a function. """ timer = timeit.Timer(func, setup=setup) repeat, number = 3, 1 for i in range(1, 10): if timer.timeit(number) >= 0.2: break elif limit is not None and number >= limit: break else: number *= 10 time = min(timer.repeat(repeat, number)) / number if time > 0.0: order = min(-int(math.floor(math.log10(time)) // 3), 3) else: order = 3 return (number, time, time*_scales[order], _units[order]) # Code for doing inline timings of recursive algorithms. def __do_timings(): import os res = os.getenv('SYMPY_TIMINGS', '') res = [x.strip() for x in res.split(',')] return set(res) _do_timings = __do_timings() _timestack = None def _print_timestack(stack, level=1): print('-'*level, '%.2f %s%s' % (stack[2], stack[0], stack[3])) for s in stack[1]: _print_timestack(s, level + 1) def timethis(name): def decorator(func): global _do_timings if not name in _do_timings: return func def wrapper(*args, **kwargs): from time import time global _timestack oldtimestack = _timestack _timestack = [func.func_name, [], 0, args] t1 = time() r = func(*args, **kwargs) t2 = time() _timestack[2] = t2 - t1 if oldtimestack is not None: oldtimestack[1].append(_timestack) _timestack = oldtimestack else: _print_timestack(_timestack) _timestack = None return r return wrapper return decorator sympy-sympy-1.9/sympy/utilities/tmpfiles.py000066400000000000000000000004541412543434000213170ustar00rootroot00000000000000from sympy.utilities.exceptions import SymPyDeprecationWarning SymPyDeprecationWarning( feature="Import sympy.utilities.tmpfiles", useinstead="Import from sympy.testing.tmpfiles", issue=18095, deprecated_since_version="1.6").warn() from sympy.testing.tmpfiles import * # noqa:F401 sympy-sympy-1.9/sympy/vector/000077500000000000000000000000001412543434000164065ustar00rootroot00000000000000sympy-sympy-1.9/sympy/vector/__init__.py000066400000000000000000000036351412543434000205260ustar00rootroot00000000000000from sympy.vector.coordsysrect import CoordSys3D, CoordSysCartesian from sympy.vector.vector import (Vector, VectorAdd, VectorMul, BaseVector, VectorZero, Cross, Dot, cross, dot) from sympy.vector.dyadic import (Dyadic, DyadicAdd, DyadicMul, BaseDyadic, DyadicZero) from sympy.vector.scalar import BaseScalar from sympy.vector.deloperator import Del from sympy.vector.functions import (express, matrix_to_vector, laplacian, is_conservative, is_solenoidal, scalar_potential, directional_derivative, scalar_potential_difference) from sympy.vector.point import Point from sympy.vector.orienters import (AxisOrienter, BodyOrienter, SpaceOrienter, QuaternionOrienter) from sympy.vector.operators import Gradient, Divergence, Curl, Laplacian, gradient, curl, divergence from sympy.vector.implicitregion import ImplicitRegion from sympy.vector.parametricregion import (ParametricRegion, parametric_region_list) from sympy.vector.integrals import (ParametricIntegral, vector_integrate) __all__ = [ 'Vector', 'VectorAdd', 'VectorMul', 'BaseVector', 'VectorZero', 'Cross', 'Dot', 'cross', 'dot', 'Dyadic', 'DyadicAdd', 'DyadicMul', 'BaseDyadic', 'DyadicZero', 'BaseScalar', 'Del', 'CoordSys3D', 'CoordSysCartesian', 'express', 'matrix_to_vector', 'laplacian', 'is_conservative', 'is_solenoidal', 'scalar_potential', 'directional_derivative', 'scalar_potential_difference', 'Point', 'AxisOrienter', 'BodyOrienter', 'SpaceOrienter', 'QuaternionOrienter', 'Gradient', 'Divergence', 'Curl', 'Laplacian', 'gradient', 'curl', 'divergence', 'ParametricRegion', 'parametric_region_list', 'ImplicitRegion', 'ParametricIntegral', 'vector_integrate', ] sympy-sympy-1.9/sympy/vector/basisdependent.py000066400000000000000000000261771412543434000217650ustar00rootroot00000000000000from typing import Any, Dict from sympy.simplify import simplify as simp, trigsimp as tsimp from sympy.core.decorators import call_highest_priority, _sympifyit from sympy.core.assumptions import StdFactKB from sympy import factor as fctr, diff as df, Integral from sympy.core import S, Add, Mul from sympy.core.expr import Expr class BasisDependent(Expr): """ Super class containing functionality common to vectors and dyadics. Named so because the representation of these quantities in sympy.vector is dependent on the basis they are expressed in. """ @call_highest_priority('__radd__') def __add__(self, other): return self._add_func(self, other) @call_highest_priority('__add__') def __radd__(self, other): return self._add_func(other, self) @call_highest_priority('__rsub__') def __sub__(self, other): return self._add_func(self, -other) @call_highest_priority('__sub__') def __rsub__(self, other): return self._add_func(other, -self) @_sympifyit('other', NotImplemented) @call_highest_priority('__rmul__') def __mul__(self, other): return self._mul_func(self, other) @_sympifyit('other', NotImplemented) @call_highest_priority('__mul__') def __rmul__(self, other): return self._mul_func(other, self) def __neg__(self): return self._mul_func(S.NegativeOne, self) @_sympifyit('other', NotImplemented) @call_highest_priority('__rtruediv__') def __truediv__(self, other): return self._div_helper(other) @call_highest_priority('__truediv__') def __rtruediv__(self, other): return TypeError("Invalid divisor for division") def evalf(self, n=15, subs=None, maxn=100, chop=False, strict=False, quad=None, verbose=False): """ Implements the SymPy evalf routine for this quantity. evalf's documentation ===================== """ options = {'subs':subs, 'maxn':maxn, 'chop':chop, 'strict':strict, 'quad':quad, 'verbose':verbose} vec = self.zero for k, v in self.components.items(): vec += v.evalf(n, **options) * k return vec evalf.__doc__ += Expr.evalf.__doc__ # type: ignore n = evalf def simplify(self, **kwargs): """ Implements the SymPy simplify routine for this quantity. simplify's documentation ======================== """ simp_components = [simp(v, **kwargs) * k for k, v in self.components.items()] return self._add_func(*simp_components) simplify.__doc__ += simp.__doc__ # type: ignore def trigsimp(self, **opts): """ Implements the SymPy trigsimp routine, for this quantity. trigsimp's documentation ======================== """ trig_components = [tsimp(v, **opts) * k for k, v in self.components.items()] return self._add_func(*trig_components) trigsimp.__doc__ += tsimp.__doc__ # type: ignore def _eval_simplify(self, **kwargs): return self.simplify(**kwargs) def _eval_trigsimp(self, **opts): return self.trigsimp(**opts) def _eval_derivative(self, wrt): return self.diff(wrt) def _eval_Integral(self, *symbols, **assumptions): integral_components = [Integral(v, *symbols, **assumptions) * k for k, v in self.components.items()] return self._add_func(*integral_components) def as_numer_denom(self): """ Returns the expression as a tuple wrt the following transformation - expression -> a/b -> a, b """ return self, S.One def factor(self, *args, **kwargs): """ Implements the SymPy factor routine, on the scalar parts of a basis-dependent expression. factor's documentation ======================== """ fctr_components = [fctr(v, *args, **kwargs) * k for k, v in self.components.items()] return self._add_func(*fctr_components) factor.__doc__ += fctr.__doc__ # type: ignore def as_coeff_Mul(self, rational=False): """Efficiently extract the coefficient of a product. """ return (S.One, self) def as_coeff_add(self, *deps): """Efficiently extract the coefficient of a summation. """ l = [x * self.components[x] for x in self.components] return 0, tuple(l) def diff(self, *args, **kwargs): """ Implements the SymPy diff routine, for vectors. diff's documentation ======================== """ for x in args: if isinstance(x, BasisDependent): raise TypeError("Invalid arg for differentiation") diff_components = [df(v, *args, **kwargs) * k for k, v in self.components.items()] return self._add_func(*diff_components) diff.__doc__ += df.__doc__ # type: ignore def doit(self, **hints): """Calls .doit() on each term in the Dyadic""" doit_components = [self.components[x].doit(**hints) * x for x in self.components] return self._add_func(*doit_components) class BasisDependentAdd(BasisDependent, Add): """ Denotes sum of basis dependent quantities such that they cannot be expressed as base or Mul instances. """ def __new__(cls, *args, **options): components = {} # Check each arg and simultaneously learn the components for i, arg in enumerate(args): if not isinstance(arg, cls._expr_type): if isinstance(arg, Mul): arg = cls._mul_func(*(arg.args)) elif isinstance(arg, Add): arg = cls._add_func(*(arg.args)) else: raise TypeError(str(arg) + " cannot be interpreted correctly") # If argument is zero, ignore if arg == cls.zero: continue # Else, update components accordingly if hasattr(arg, "components"): for x in arg.components: components[x] = components.get(x, 0) + arg.components[x] temp = list(components.keys()) for x in temp: if components[x] == 0: del components[x] # Handle case of zero vector if len(components) == 0: return cls.zero # Build object newargs = [x * components[x] for x in components] obj = super().__new__(cls, *newargs, **options) if isinstance(obj, Mul): return cls._mul_func(*obj.args) assumptions = {'commutative': True} obj._assumptions = StdFactKB(assumptions) obj._components = components obj._sys = (list(components.keys()))[0]._sys return obj class BasisDependentMul(BasisDependent, Mul): """ Denotes product of base- basis dependent quantity with a scalar. """ def __new__(cls, *args, **options): from sympy.vector import Cross, Dot, Curl, Gradient count = 0 measure_number = S.One zeroflag = False extra_args = [] # Determine the component and check arguments # Also keep a count to ensure two vectors aren't # being multiplied for arg in args: if isinstance(arg, cls._zero_func): count += 1 zeroflag = True elif arg == S.Zero: zeroflag = True elif isinstance(arg, (cls._base_func, cls._mul_func)): count += 1 expr = arg._base_instance measure_number *= arg._measure_number elif isinstance(arg, cls._add_func): count += 1 expr = arg elif isinstance(arg, (Cross, Dot, Curl, Gradient)): extra_args.append(arg) else: measure_number *= arg # Make sure incompatible types weren't multiplied if count > 1: raise ValueError("Invalid multiplication") elif count == 0: return Mul(*args, **options) # Handle zero vector case if zeroflag: return cls.zero # If one of the args was a VectorAdd, return an # appropriate VectorAdd instance if isinstance(expr, cls._add_func): newargs = [cls._mul_func(measure_number, x) for x in expr.args] return cls._add_func(*newargs) obj = super().__new__(cls, measure_number, expr._base_instance, *extra_args, **options) if isinstance(obj, Add): return cls._add_func(*obj.args) obj._base_instance = expr._base_instance obj._measure_number = measure_number assumptions = {'commutative': True} obj._assumptions = StdFactKB(assumptions) obj._components = {expr._base_instance: measure_number} obj._sys = expr._base_instance._sys return obj def _sympystr(self, printer): measure_str = printer._print(self._measure_number) if ('(' in measure_str or '-' in measure_str or '+' in measure_str): measure_str = '(' + measure_str + ')' return measure_str + '*' + printer._print(self._base_instance) class BasisDependentZero(BasisDependent): """ Class to denote a zero basis dependent instance. """ # XXX: Can't type the keys as BaseVector because of cyclic import # problems. components = {} # type: Dict[Any, Expr] def __new__(cls): obj = super().__new__(cls) # Pre-compute a specific hash value for the zero vector # Use the same one always obj._hash = tuple([S.Zero, cls]).__hash__() return obj def __hash__(self): return self._hash @call_highest_priority('__req__') def __eq__(self, other): return isinstance(other, self._zero_func) __req__ = __eq__ @call_highest_priority('__radd__') def __add__(self, other): if isinstance(other, self._expr_type): return other else: raise TypeError("Invalid argument types for addition") @call_highest_priority('__add__') def __radd__(self, other): if isinstance(other, self._expr_type): return other else: raise TypeError("Invalid argument types for addition") @call_highest_priority('__rsub__') def __sub__(self, other): if isinstance(other, self._expr_type): return -other else: raise TypeError("Invalid argument types for subtraction") @call_highest_priority('__sub__') def __rsub__(self, other): if isinstance(other, self._expr_type): return other else: raise TypeError("Invalid argument types for subtraction") def __neg__(self): return self def normalize(self): """ Returns the normalized version of this vector. """ return self def _sympystr(self, printer): return '0' sympy-sympy-1.9/sympy/vector/coordsysrect.py000066400000000000000000001105121412543434000215030ustar00rootroot00000000000000from collections.abc import Callable from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.core.basic import Basic from sympy.core.cache import cacheit from sympy.core import S, Dummy, Lambda from sympy.core.symbol import Str from sympy import symbols, MatrixBase, ImmutableDenseMatrix from sympy.solvers import solve from sympy.vector.scalar import BaseScalar from sympy import eye, trigsimp, ImmutableMatrix as Matrix, sin, cos,\ sqrt, diff, Tuple, acos, atan2, simplify import sympy.vector from sympy.vector.orienters import (Orienter, AxisOrienter, BodyOrienter, SpaceOrienter, QuaternionOrienter) def CoordSysCartesian(*args, **kwargs): SymPyDeprecationWarning( feature="CoordSysCartesian", useinstead="CoordSys3D", issue=12865, deprecated_since_version="1.1" ).warn() return CoordSys3D(*args, **kwargs) class CoordSys3D(Basic): """ Represents a coordinate system in 3-D space. """ def __new__(cls, name, transformation=None, parent=None, location=None, rotation_matrix=None, vector_names=None, variable_names=None): """ The orientation/location parameters are necessary if this system is being defined at a certain orientation or location wrt another. Parameters ========== name : str The name of the new CoordSys3D instance. transformation : Lambda, Tuple, str Transformation defined by transformation equations or chosen from predefined ones. location : Vector The position vector of the new system's origin wrt the parent instance. rotation_matrix : SymPy ImmutableMatrix The rotation matrix of the new coordinate system with respect to the parent. In other words, the output of new_system.rotation_matrix(parent). parent : CoordSys3D The coordinate system wrt which the orientation/location (or both) is being defined. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. """ name = str(name) Vector = sympy.vector.Vector Point = sympy.vector.Point if not isinstance(name, str): raise TypeError("name should be a string") if transformation is not None: if (location is not None) or (rotation_matrix is not None): raise ValueError("specify either `transformation` or " "`location`/`rotation_matrix`") if isinstance(transformation, (Tuple, tuple, list)): if isinstance(transformation[0], MatrixBase): rotation_matrix = transformation[0] location = transformation[1] else: transformation = Lambda(transformation[0], transformation[1]) elif isinstance(transformation, Callable): x1, x2, x3 = symbols('x1 x2 x3', cls=Dummy) transformation = Lambda((x1, x2, x3), transformation(x1, x2, x3)) elif isinstance(transformation, str): transformation = Str(transformation) elif isinstance(transformation, (Str, Lambda)): pass else: raise TypeError("transformation: " "wrong type {}".format(type(transformation))) # If orientation information has been provided, store # the rotation matrix accordingly if rotation_matrix is None: rotation_matrix = ImmutableDenseMatrix(eye(3)) else: if not isinstance(rotation_matrix, MatrixBase): raise TypeError("rotation_matrix should be an Immutable" + "Matrix instance") rotation_matrix = rotation_matrix.as_immutable() # If location information is not given, adjust the default # location as Vector.zero if parent is not None: if not isinstance(parent, CoordSys3D): raise TypeError("parent should be a " + "CoordSys3D/None") if location is None: location = Vector.zero else: if not isinstance(location, Vector): raise TypeError("location should be a Vector") # Check that location does not contain base # scalars for x in location.free_symbols: if isinstance(x, BaseScalar): raise ValueError("location should not contain" + " BaseScalars") origin = parent.origin.locate_new(name + '.origin', location) else: location = Vector.zero origin = Point(name + '.origin') if transformation is None: transformation = Tuple(rotation_matrix, location) if isinstance(transformation, Tuple): lambda_transformation = CoordSys3D._compose_rotation_and_translation( transformation[0], transformation[1], parent ) r, l = transformation l = l._projections lambda_lame = CoordSys3D._get_lame_coeff('cartesian') lambda_inverse = lambda x, y, z: r.inv()*Matrix( [x-l[0], y-l[1], z-l[2]]) elif isinstance(transformation, Str): trname = transformation.name lambda_transformation = CoordSys3D._get_transformation_lambdas(trname) if parent is not None: if parent.lame_coefficients() != (S.One, S.One, S.One): raise ValueError('Parent for pre-defined coordinate ' 'system should be Cartesian.') lambda_lame = CoordSys3D._get_lame_coeff(trname) lambda_inverse = CoordSys3D._set_inv_trans_equations(trname) elif isinstance(transformation, Lambda): if not CoordSys3D._check_orthogonality(transformation): raise ValueError("The transformation equation does not " "create orthogonal coordinate system") lambda_transformation = transformation lambda_lame = CoordSys3D._calculate_lame_coeff(lambda_transformation) lambda_inverse = None else: lambda_transformation = lambda x, y, z: transformation(x, y, z) lambda_lame = CoordSys3D._get_lame_coeff(transformation) lambda_inverse = None if variable_names is None: if isinstance(transformation, Lambda): variable_names = ["x1", "x2", "x3"] elif isinstance(transformation, Str): if transformation.name == 'spherical': variable_names = ["r", "theta", "phi"] elif transformation.name == 'cylindrical': variable_names = ["r", "theta", "z"] else: variable_names = ["x", "y", "z"] else: variable_names = ["x", "y", "z"] if vector_names is None: vector_names = ["i", "j", "k"] # All systems that are defined as 'roots' are unequal, unless # they have the same name. # Systems defined at same orientation/position wrt the same # 'parent' are equal, irrespective of the name. # This is true even if the same orientation is provided via # different methods like Axis/Body/Space/Quaternion. # However, coincident systems may be seen as unequal if # positioned/oriented wrt different parents, even though # they may actually be 'coincident' wrt the root system. if parent is not None: obj = super().__new__( cls, Str(name), transformation, parent) else: obj = super().__new__( cls, Str(name), transformation) obj._name = name # Initialize the base vectors _check_strings('vector_names', vector_names) vector_names = list(vector_names) latex_vects = [(r'\mathbf{\hat{%s}_{%s}}' % (x, name)) for x in vector_names] pretty_vects = ['%s_%s' % (x, name) for x in vector_names] obj._vector_names = vector_names v1 = BaseVector(0, obj, pretty_vects[0], latex_vects[0]) v2 = BaseVector(1, obj, pretty_vects[1], latex_vects[1]) v3 = BaseVector(2, obj, pretty_vects[2], latex_vects[2]) obj._base_vectors = (v1, v2, v3) # Initialize the base scalars _check_strings('variable_names', vector_names) variable_names = list(variable_names) latex_scalars = [(r"\mathbf{{%s}_{%s}}" % (x, name)) for x in variable_names] pretty_scalars = ['%s_%s' % (x, name) for x in variable_names] obj._variable_names = variable_names obj._vector_names = vector_names x1 = BaseScalar(0, obj, pretty_scalars[0], latex_scalars[0]) x2 = BaseScalar(1, obj, pretty_scalars[1], latex_scalars[1]) x3 = BaseScalar(2, obj, pretty_scalars[2], latex_scalars[2]) obj._base_scalars = (x1, x2, x3) obj._transformation = transformation obj._transformation_lambda = lambda_transformation obj._lame_coefficients = lambda_lame(x1, x2, x3) obj._transformation_from_parent_lambda = lambda_inverse setattr(obj, variable_names[0], x1) setattr(obj, variable_names[1], x2) setattr(obj, variable_names[2], x3) setattr(obj, vector_names[0], v1) setattr(obj, vector_names[1], v2) setattr(obj, vector_names[2], v3) # Assign params obj._parent = parent if obj._parent is not None: obj._root = obj._parent._root else: obj._root = obj obj._parent_rotation_matrix = rotation_matrix obj._origin = origin # Return the instance return obj def _sympystr(self, printer): return self._name def __iter__(self): return iter(self.base_vectors()) @staticmethod def _check_orthogonality(equations): """ Helper method for _connect_to_cartesian. It checks if set of transformation equations create orthogonal curvilinear coordinate system Parameters ========== equations : Lambda Lambda of transformation equations """ x1, x2, x3 = symbols("x1, x2, x3", cls=Dummy) equations = equations(x1, x2, x3) v1 = Matrix([diff(equations[0], x1), diff(equations[1], x1), diff(equations[2], x1)]) v2 = Matrix([diff(equations[0], x2), diff(equations[1], x2), diff(equations[2], x2)]) v3 = Matrix([diff(equations[0], x3), diff(equations[1], x3), diff(equations[2], x3)]) if any(simplify(i[0] + i[1] + i[2]) == 0 for i in (v1, v2, v3)): return False else: if simplify(v1.dot(v2)) == 0 and simplify(v2.dot(v3)) == 0 \ and simplify(v3.dot(v1)) == 0: return True else: return False @staticmethod def _set_inv_trans_equations(curv_coord_name): """ Store information about inverse transformation equations for pre-defined coordinate systems. Parameters ========== curv_coord_name : str Name of coordinate system """ if curv_coord_name == 'cartesian': return lambda x, y, z: (x, y, z) if curv_coord_name == 'spherical': return lambda x, y, z: ( sqrt(x**2 + y**2 + z**2), acos(z/sqrt(x**2 + y**2 + z**2)), atan2(y, x) ) if curv_coord_name == 'cylindrical': return lambda x, y, z: ( sqrt(x**2 + y**2), atan2(y, x), z ) raise ValueError('Wrong set of parameters.' 'Type of coordinate system is defined') def _calculate_inv_trans_equations(self): """ Helper method for set_coordinate_type. It calculates inverse transformation equations for given transformations equations. """ x1, x2, x3 = symbols("x1, x2, x3", cls=Dummy, reals=True) x, y, z = symbols("x, y, z", cls=Dummy) equations = self._transformation(x1, x2, x3) solved = solve([equations[0] - x, equations[1] - y, equations[2] - z], (x1, x2, x3), dict=True)[0] solved = solved[x1], solved[x2], solved[x3] self._transformation_from_parent_lambda = \ lambda x1, x2, x3: tuple(i.subs(list(zip((x, y, z), (x1, x2, x3)))) for i in solved) @staticmethod def _get_lame_coeff(curv_coord_name): """ Store information about Lame coefficients for pre-defined coordinate systems. Parameters ========== curv_coord_name : str Name of coordinate system """ if isinstance(curv_coord_name, str): if curv_coord_name == 'cartesian': return lambda x, y, z: (S.One, S.One, S.One) if curv_coord_name == 'spherical': return lambda r, theta, phi: (S.One, r, r*sin(theta)) if curv_coord_name == 'cylindrical': return lambda r, theta, h: (S.One, r, S.One) raise ValueError('Wrong set of parameters.' ' Type of coordinate system is not defined') return CoordSys3D._calculate_lame_coefficients(curv_coord_name) @staticmethod def _calculate_lame_coeff(equations): """ It calculates Lame coefficients for given transformations equations. Parameters ========== equations : Lambda Lambda of transformation equations. """ return lambda x1, x2, x3: ( sqrt(diff(equations(x1, x2, x3)[0], x1)**2 + diff(equations(x1, x2, x3)[1], x1)**2 + diff(equations(x1, x2, x3)[2], x1)**2), sqrt(diff(equations(x1, x2, x3)[0], x2)**2 + diff(equations(x1, x2, x3)[1], x2)**2 + diff(equations(x1, x2, x3)[2], x2)**2), sqrt(diff(equations(x1, x2, x3)[0], x3)**2 + diff(equations(x1, x2, x3)[1], x3)**2 + diff(equations(x1, x2, x3)[2], x3)**2) ) def _inverse_rotation_matrix(self): """ Returns inverse rotation matrix. """ return simplify(self._parent_rotation_matrix**-1) @staticmethod def _get_transformation_lambdas(curv_coord_name): """ Store information about transformation equations for pre-defined coordinate systems. Parameters ========== curv_coord_name : str Name of coordinate system """ if isinstance(curv_coord_name, str): if curv_coord_name == 'cartesian': return lambda x, y, z: (x, y, z) if curv_coord_name == 'spherical': return lambda r, theta, phi: ( r*sin(theta)*cos(phi), r*sin(theta)*sin(phi), r*cos(theta) ) if curv_coord_name == 'cylindrical': return lambda r, theta, h: ( r*cos(theta), r*sin(theta), h ) raise ValueError('Wrong set of parameters.' 'Type of coordinate system is defined') @classmethod def _rotation_trans_equations(cls, matrix, equations): """ Returns the transformation equations obtained from rotation matrix. Parameters ========== matrix : Matrix Rotation matrix equations : tuple Transformation equations """ return tuple(matrix * Matrix(equations)) @property def origin(self): return self._origin @property def delop(self): SymPyDeprecationWarning( feature="coord_system.delop has been replaced.", useinstead="Use the Del() class", deprecated_since_version="1.1", issue=12866, ).warn() from sympy.vector.deloperator import Del return Del() def base_vectors(self): return self._base_vectors def base_scalars(self): return self._base_scalars def lame_coefficients(self): return self._lame_coefficients def transformation_to_parent(self): return self._transformation_lambda(*self.base_scalars()) def transformation_from_parent(self): if self._parent is None: raise ValueError("no parent coordinate system, use " "`transformation_from_parent_function()`") return self._transformation_from_parent_lambda( *self._parent.base_scalars()) def transformation_from_parent_function(self): return self._transformation_from_parent_lambda def rotation_matrix(self, other): """ Returns the direction cosine matrix(DCM), also known as the 'rotation matrix' of this coordinate system with respect to another system. If v_a is a vector defined in system 'A' (in matrix format) and v_b is the same vector defined in system 'B', then v_a = A.rotation_matrix(B) * v_b. A SymPy Matrix is returned. Parameters ========== other : CoordSys3D The system which the DCM is generated to. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q1 = symbols('q1') >>> N = CoordSys3D('N') >>> A = N.orient_new_axis('A', q1, N.i) >>> N.rotation_matrix(A) Matrix([ [1, 0, 0], [0, cos(q1), -sin(q1)], [0, sin(q1), cos(q1)]]) """ from sympy.vector.functions import _path if not isinstance(other, CoordSys3D): raise TypeError(str(other) + " is not a CoordSys3D") # Handle special cases if other == self: return eye(3) elif other == self._parent: return self._parent_rotation_matrix elif other._parent == self: return other._parent_rotation_matrix.T # Else, use tree to calculate position rootindex, path = _path(self, other) result = eye(3) i = -1 for i in range(rootindex): result *= path[i]._parent_rotation_matrix i += 2 while i < len(path): result *= path[i]._parent_rotation_matrix.T i += 1 return result @cacheit def position_wrt(self, other): """ Returns the position vector of the origin of this coordinate system with respect to another Point/CoordSys3D. Parameters ========== other : Point/CoordSys3D If other is a Point, the position of this system's origin wrt it is returned. If its an instance of CoordSyRect, the position wrt its origin is returned. Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> N1 = N.locate_new('N1', 10 * N.i) >>> N.position_wrt(N1) (-10)*N.i """ return self.origin.position_wrt(other) def scalar_map(self, other): """ Returns a dictionary which expresses the coordinate variables (base scalars) of this frame in terms of the variables of otherframe. Parameters ========== otherframe : CoordSys3D The other system to map the variables to. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import Symbol >>> A = CoordSys3D('A') >>> q = Symbol('q') >>> B = A.orient_new_axis('B', q, A.k) >>> A.scalar_map(B) {A.x: B.x*cos(q) - B.y*sin(q), A.y: B.x*sin(q) + B.y*cos(q), A.z: B.z} """ relocated_scalars = [] origin_coords = tuple(self.position_wrt(other).to_matrix(other)) for i, x in enumerate(other.base_scalars()): relocated_scalars.append(x - origin_coords[i]) vars_matrix = (self.rotation_matrix(other) * Matrix(relocated_scalars)) mapping = {} for i, x in enumerate(self.base_scalars()): mapping[x] = trigsimp(vars_matrix[i]) return mapping def locate_new(self, name, position, vector_names=None, variable_names=None): """ Returns a CoordSys3D with its origin located at the given position wrt this coordinate system's origin. Parameters ========== name : str The name of the new CoordSys3D instance. position : Vector The position vector of the new system's origin wrt this one. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. Examples ======== >>> from sympy.vector import CoordSys3D >>> A = CoordSys3D('A') >>> B = A.locate_new('B', 10 * A.i) >>> B.origin.position_wrt(A.origin) 10*A.i """ if variable_names is None: variable_names = self._variable_names if vector_names is None: vector_names = self._vector_names return CoordSys3D(name, location=position, vector_names=vector_names, variable_names=variable_names, parent=self) def orient_new(self, name, orienters, location=None, vector_names=None, variable_names=None): """ Creates a new CoordSys3D oriented in the user-specified way with respect to this system. Please refer to the documentation of the orienter classes for more information about the orientation procedure. Parameters ========== name : str The name of the new CoordSys3D instance. orienters : iterable/Orienter An Orienter or an iterable of Orienters for orienting the new coordinate system. If an Orienter is provided, it is applied to get the new system. If an iterable is provided, the orienters will be applied in the order in which they appear in the iterable. location : Vector(optional) The location of the new coordinate system's origin wrt this system's origin. If not specified, the origins are taken to be coincident. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') >>> N = CoordSys3D('N') Using an AxisOrienter >>> from sympy.vector import AxisOrienter >>> axis_orienter = AxisOrienter(q1, N.i + 2 * N.j) >>> A = N.orient_new('A', (axis_orienter, )) Using a BodyOrienter >>> from sympy.vector import BodyOrienter >>> body_orienter = BodyOrienter(q1, q2, q3, '123') >>> B = N.orient_new('B', (body_orienter, )) Using a SpaceOrienter >>> from sympy.vector import SpaceOrienter >>> space_orienter = SpaceOrienter(q1, q2, q3, '312') >>> C = N.orient_new('C', (space_orienter, )) Using a QuaternionOrienter >>> from sympy.vector import QuaternionOrienter >>> q_orienter = QuaternionOrienter(q0, q1, q2, q3) >>> D = N.orient_new('D', (q_orienter, )) """ if variable_names is None: variable_names = self._variable_names if vector_names is None: vector_names = self._vector_names if isinstance(orienters, Orienter): if isinstance(orienters, AxisOrienter): final_matrix = orienters.rotation_matrix(self) else: final_matrix = orienters.rotation_matrix() # TODO: trigsimp is needed here so that the matrix becomes # canonical (scalar_map also calls trigsimp; without this, you can # end up with the same CoordinateSystem that compares differently # due to a differently formatted matrix). However, this is # probably not so good for performance. final_matrix = trigsimp(final_matrix) else: final_matrix = Matrix(eye(3)) for orienter in orienters: if isinstance(orienter, AxisOrienter): final_matrix *= orienter.rotation_matrix(self) else: final_matrix *= orienter.rotation_matrix() return CoordSys3D(name, rotation_matrix=final_matrix, vector_names=vector_names, variable_names=variable_names, location=location, parent=self) def orient_new_axis(self, name, angle, axis, location=None, vector_names=None, variable_names=None): """ Axis rotation is a rotation about an arbitrary axis by some angle. The angle is supplied as a SymPy expr scalar, and the axis is supplied as a Vector. Parameters ========== name : string The name of the new coordinate system angle : Expr The angle by which the new system is to be rotated axis : Vector The axis around which the rotation has to be performed location : Vector(optional) The location of the new coordinate system's origin wrt this system's origin. If not specified, the origins are taken to be coincident. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q1 = symbols('q1') >>> N = CoordSys3D('N') >>> B = N.orient_new_axis('B', q1, N.i + 2 * N.j) """ if variable_names is None: variable_names = self._variable_names if vector_names is None: vector_names = self._vector_names orienter = AxisOrienter(angle, axis) return self.orient_new(name, orienter, location=location, vector_names=vector_names, variable_names=variable_names) def orient_new_body(self, name, angle1, angle2, angle3, rotation_order, location=None, vector_names=None, variable_names=None): """ Body orientation takes this coordinate system through three successive simple rotations. Body fixed rotations include both Euler Angles and Tait-Bryan Angles, see https://en.wikipedia.org/wiki/Euler_angles. Parameters ========== name : string The name of the new coordinate system angle1, angle2, angle3 : Expr Three successive angles to rotate the coordinate system by rotation_order : string String defining the order of axes for rotation location : Vector(optional) The location of the new coordinate system's origin wrt this system's origin. If not specified, the origins are taken to be coincident. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q1, q2, q3 = symbols('q1 q2 q3') >>> N = CoordSys3D('N') A 'Body' fixed rotation is described by three angles and three body-fixed rotation axes. To orient a coordinate system D with respect to N, each sequential rotation is always about the orthogonal unit vectors fixed to D. For example, a '123' rotation will specify rotations about N.i, then D.j, then D.k. (Initially, D.i is same as N.i) Therefore, >>> D = N.orient_new_body('D', q1, q2, q3, '123') is same as >>> D = N.orient_new_axis('D', q1, N.i) >>> D = D.orient_new_axis('D', q2, D.j) >>> D = D.orient_new_axis('D', q3, D.k) Acceptable rotation orders are of length 3, expressed in XYZ or 123, and cannot have a rotation about about an axis twice in a row. >>> B = N.orient_new_body('B', q1, q2, q3, '123') >>> B = N.orient_new_body('B', q1, q2, 0, 'ZXZ') >>> B = N.orient_new_body('B', 0, 0, 0, 'XYX') """ orienter = BodyOrienter(angle1, angle2, angle3, rotation_order) return self.orient_new(name, orienter, location=location, vector_names=vector_names, variable_names=variable_names) def orient_new_space(self, name, angle1, angle2, angle3, rotation_order, location=None, vector_names=None, variable_names=None): """ Space rotation is similar to Body rotation, but the rotations are applied in the opposite order. Parameters ========== name : string The name of the new coordinate system angle1, angle2, angle3 : Expr Three successive angles to rotate the coordinate system by rotation_order : string String defining the order of axes for rotation location : Vector(optional) The location of the new coordinate system's origin wrt this system's origin. If not specified, the origins are taken to be coincident. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. See Also ======== CoordSys3D.orient_new_body : method to orient via Euler angles Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q1, q2, q3 = symbols('q1 q2 q3') >>> N = CoordSys3D('N') To orient a coordinate system D with respect to N, each sequential rotation is always about N's orthogonal unit vectors. For example, a '123' rotation will specify rotations about N.i, then N.j, then N.k. Therefore, >>> D = N.orient_new_space('D', q1, q2, q3, '312') is same as >>> B = N.orient_new_axis('B', q1, N.i) >>> C = B.orient_new_axis('C', q2, N.j) >>> D = C.orient_new_axis('D', q3, N.k) """ orienter = SpaceOrienter(angle1, angle2, angle3, rotation_order) return self.orient_new(name, orienter, location=location, vector_names=vector_names, variable_names=variable_names) def orient_new_quaternion(self, name, q0, q1, q2, q3, location=None, vector_names=None, variable_names=None): """ Quaternion orientation orients the new CoordSys3D with Quaternions, defined as a finite rotation about lambda, a unit vector, by some amount theta. This orientation is described by four parameters: q0 = cos(theta/2) q1 = lambda_x sin(theta/2) q2 = lambda_y sin(theta/2) q3 = lambda_z sin(theta/2) Quaternion does not take in a rotation order. Parameters ========== name : string The name of the new coordinate system q0, q1, q2, q3 : Expr The quaternions to rotate the coordinate system by location : Vector(optional) The location of the new coordinate system's origin wrt this system's origin. If not specified, the origins are taken to be coincident. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') >>> N = CoordSys3D('N') >>> B = N.orient_new_quaternion('B', q0, q1, q2, q3) """ orienter = QuaternionOrienter(q0, q1, q2, q3) return self.orient_new(name, orienter, location=location, vector_names=vector_names, variable_names=variable_names) def create_new(self, name, transformation, variable_names=None, vector_names=None): """ Returns a CoordSys3D which is connected to self by transformation. Parameters ========== name : str The name of the new CoordSys3D instance. transformation : Lambda, Tuple, str Transformation defined by transformation equations or chosen from predefined ones. vector_names, variable_names : iterable(optional) Iterables of 3 strings each, with custom names for base vectors and base scalars of the new system respectively. Used for simple str printing. Examples ======== >>> from sympy.vector import CoordSys3D >>> a = CoordSys3D('a') >>> b = a.create_new('b', transformation='spherical') >>> b.transformation_to_parent() (b.r*sin(b.theta)*cos(b.phi), b.r*sin(b.phi)*sin(b.theta), b.r*cos(b.theta)) >>> b.transformation_from_parent() (sqrt(a.x**2 + a.y**2 + a.z**2), acos(a.z/sqrt(a.x**2 + a.y**2 + a.z**2)), atan2(a.y, a.x)) """ return CoordSys3D(name, parent=self, transformation=transformation, variable_names=variable_names, vector_names=vector_names) def __init__(self, name, location=None, rotation_matrix=None, parent=None, vector_names=None, variable_names=None, latex_vects=None, pretty_vects=None, latex_scalars=None, pretty_scalars=None, transformation=None): # Dummy initializer for setting docstring pass __init__.__doc__ = __new__.__doc__ @staticmethod def _compose_rotation_and_translation(rot, translation, parent): r = lambda x, y, z: CoordSys3D._rotation_trans_equations(rot, (x, y, z)) if parent is None: return r dx, dy, dz = [translation.dot(i) for i in parent.base_vectors()] t = lambda x, y, z: ( x + dx, y + dy, z + dz, ) return lambda x, y, z: t(*r(x, y, z)) def _check_strings(arg_name, arg): errorstr = arg_name + " must be an iterable of 3 string-types" if len(arg) != 3: raise ValueError(errorstr) for s in arg: if not isinstance(s, str): raise TypeError(errorstr) # Delayed import to avoid cyclic import problems: from sympy.vector.vector import BaseVector sympy-sympy-1.9/sympy/vector/deloperator.py000066400000000000000000000067431412543434000213120ustar00rootroot00000000000000from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.core import Basic from sympy.vector.operators import gradient, divergence, curl class Del(Basic): """ Represents the vector differential operator, usually represented in mathematical expressions as the 'nabla' symbol. """ def __new__(cls, system=None): if system is not None: SymPyDeprecationWarning( feature="delop operator inside coordinate system", useinstead="it as instance Del class", deprecated_since_version="1.1", issue=12866, ).warn() obj = super().__new__(cls) obj._name = "delop" return obj def gradient(self, scalar_field, doit=False): """ Returns the gradient of the given scalar field, as a Vector instance. Parameters ========== scalar_field : SymPy expression The scalar field to calculate the gradient of. doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> delop.gradient(9) 0 >>> delop(C.x*C.y*C.z).doit() C.y*C.z*C.i + C.x*C.z*C.j + C.x*C.y*C.k """ return gradient(scalar_field, doit=doit) __call__ = gradient __call__.__doc__ = gradient.__doc__ def dot(self, vect, doit=False): """ Represents the dot product between this operator and a given vector - equal to the divergence of the vector field. Parameters ========== vect : Vector The vector whose divergence is to be calculated. doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, Del >>> delop = Del() >>> C = CoordSys3D('C') >>> delop.dot(C.x*C.i) Derivative(C.x, C.x) >>> v = C.x*C.y*C.z * (C.i + C.j + C.k) >>> (delop & v).doit() C.x*C.y + C.x*C.z + C.y*C.z """ return divergence(vect, doit=doit) __and__ = dot __and__.__doc__ = dot.__doc__ def cross(self, vect, doit=False): """ Represents the cross product between this operator and a given vector - equal to the curl of the vector field. Parameters ========== vect : Vector The vector whose curl is to be calculated. doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> v = C.x*C.y*C.z * (C.i + C.j + C.k) >>> delop.cross(v, doit = True) (-C.x*C.y + C.x*C.z)*C.i + (C.x*C.y - C.y*C.z)*C.j + (-C.x*C.z + C.y*C.z)*C.k >>> (delop ^ C.i).doit() 0 """ return curl(vect, doit=doit) __xor__ = cross __xor__.__doc__ = cross.__doc__ def _sympystr(self, printer): return self._name sympy-sympy-1.9/sympy/vector/dyadic.py000066400000000000000000000204051412543434000202160ustar00rootroot00000000000000from typing import Type from sympy.vector.basisdependent import (BasisDependent, BasisDependentAdd, BasisDependentMul, BasisDependentZero) from sympy.core import S, Pow from sympy.core.expr import AtomicExpr from sympy import ImmutableMatrix as Matrix import sympy.vector class Dyadic(BasisDependent): """ Super class for all Dyadic-classes. References ========== .. [1] https://en.wikipedia.org/wiki/Dyadic_tensor .. [2] Kane, T., Levinson, D. Dynamics Theory and Applications. 1985 McGraw-Hill """ _op_priority = 13.0 _expr_type = None # type: Type[Dyadic] _mul_func = None # type: Type[Dyadic] _add_func = None # type: Type[Dyadic] _zero_func = None # type: Type[Dyadic] _base_func = None # type: Type[Dyadic] zero = None # type: DyadicZero @property def components(self): """ Returns the components of this dyadic in the form of a Python dictionary mapping BaseDyadic instances to the corresponding measure numbers. """ # The '_components' attribute is defined according to the # subclass of Dyadic the instance belongs to. return self._components def dot(self, other): """ Returns the dot product(also called inner product) of this Dyadic, with another Dyadic or Vector. If 'other' is a Dyadic, this returns a Dyadic. Else, it returns a Vector (unless an error is encountered). Parameters ========== other : Dyadic/Vector The other Dyadic or Vector to take the inner product with Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> D1 = N.i.outer(N.j) >>> D2 = N.j.outer(N.j) >>> D1.dot(D2) (N.i|N.j) >>> D1.dot(N.j) N.i """ Vector = sympy.vector.Vector if isinstance(other, BasisDependentZero): return Vector.zero elif isinstance(other, Vector): outvec = Vector.zero for k, v in self.components.items(): vect_dot = k.args[1].dot(other) outvec += vect_dot * v * k.args[0] return outvec elif isinstance(other, Dyadic): outdyad = Dyadic.zero for k1, v1 in self.components.items(): for k2, v2 in other.components.items(): vect_dot = k1.args[1].dot(k2.args[0]) outer_product = k1.args[0].outer(k2.args[1]) outdyad += vect_dot * v1 * v2 * outer_product return outdyad else: raise TypeError("Inner product is not defined for " + str(type(other)) + " and Dyadics.") def __and__(self, other): return self.dot(other) __and__.__doc__ = dot.__doc__ def cross(self, other): """ Returns the cross product between this Dyadic, and a Vector, as a Vector instance. Parameters ========== other : Vector The Vector that we are crossing this Dyadic with Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> d = N.i.outer(N.i) >>> d.cross(N.j) (N.i|N.k) """ Vector = sympy.vector.Vector if other == Vector.zero: return Dyadic.zero elif isinstance(other, Vector): outdyad = Dyadic.zero for k, v in self.components.items(): cross_product = k.args[1].cross(other) outer = k.args[0].outer(cross_product) outdyad += v * outer return outdyad else: raise TypeError(str(type(other)) + " not supported for " + "cross with dyadics") def __xor__(self, other): return self.cross(other) __xor__.__doc__ = cross.__doc__ def to_matrix(self, system, second_system=None): """ Returns the matrix form of the dyadic with respect to one or two coordinate systems. Parameters ========== system : CoordSys3D The coordinate system that the rows and columns of the matrix correspond to. If a second system is provided, this only corresponds to the rows of the matrix. second_system : CoordSys3D, optional, default=None The coordinate system that the columns of the matrix correspond to. Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> v = N.i + 2*N.j >>> d = v.outer(N.i) >>> d.to_matrix(N) Matrix([ [1, 0, 0], [2, 0, 0], [0, 0, 0]]) >>> from sympy import Symbol >>> q = Symbol('q') >>> P = N.orient_new_axis('P', q, N.k) >>> d.to_matrix(N, P) Matrix([ [ cos(q), -sin(q), 0], [2*cos(q), -2*sin(q), 0], [ 0, 0, 0]]) """ if second_system is None: second_system = system return Matrix([i.dot(self).dot(j) for i in system for j in second_system]).reshape(3, 3) def _div_helper(one, other): """ Helper for division involving dyadics """ if isinstance(one, Dyadic) and isinstance(other, Dyadic): raise TypeError("Cannot divide two dyadics") elif isinstance(one, Dyadic): return DyadicMul(one, Pow(other, S.NegativeOne)) else: raise TypeError("Cannot divide by a dyadic") class BaseDyadic(Dyadic, AtomicExpr): """ Class to denote a base dyadic tensor component. """ def __new__(cls, vector1, vector2): Vector = sympy.vector.Vector BaseVector = sympy.vector.BaseVector VectorZero = sympy.vector.VectorZero # Verify arguments if not isinstance(vector1, (BaseVector, VectorZero)) or \ not isinstance(vector2, (BaseVector, VectorZero)): raise TypeError("BaseDyadic cannot be composed of non-base " + "vectors") # Handle special case of zero vector elif vector1 == Vector.zero or vector2 == Vector.zero: return Dyadic.zero # Initialize instance obj = super().__new__(cls, vector1, vector2) obj._base_instance = obj obj._measure_number = 1 obj._components = {obj: S.One} obj._sys = vector1._sys obj._pretty_form = ('(' + vector1._pretty_form + '|' + vector2._pretty_form + ')') obj._latex_form = ('(' + vector1._latex_form + "{|}" + vector2._latex_form + ')') return obj def _sympystr(self, printer): return "({}|{})".format( printer._print(self.args[0]), printer._print(self.args[1])) class DyadicMul(BasisDependentMul, Dyadic): """ Products of scalars and BaseDyadics """ def __new__(cls, *args, **options): obj = BasisDependentMul.__new__(cls, *args, **options) return obj @property def base_dyadic(self): """ The BaseDyadic involved in the product. """ return self._base_instance @property def measure_number(self): """ The scalar expression involved in the definition of this DyadicMul. """ return self._measure_number class DyadicAdd(BasisDependentAdd, Dyadic): """ Class to hold dyadic sums """ def __new__(cls, *args, **options): obj = BasisDependentAdd.__new__(cls, *args, **options) return obj def _sympystr(self, printer): items = list(self.components.items()) items.sort(key=lambda x: x[0].__str__()) return " + ".join(printer._print(k * v) for k, v in items) class DyadicZero(BasisDependentZero, Dyadic): """ Class to denote a zero dyadic """ _op_priority = 13.1 _pretty_form = '(0|0)' _latex_form = r'(\mathbf{\hat{0}}|\mathbf{\hat{0}})' def __new__(cls): obj = BasisDependentZero.__new__(cls) return obj Dyadic._expr_type = Dyadic Dyadic._mul_func = DyadicMul Dyadic._add_func = DyadicAdd Dyadic._zero_func = DyadicZero Dyadic._base_func = BaseDyadic Dyadic.zero = DyadicZero() sympy-sympy-1.9/sympy/vector/functions.py000066400000000000000000000363331412543434000210000ustar00rootroot00000000000000from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.deloperator import Del from sympy.vector.scalar import BaseScalar from sympy.vector.vector import Vector, BaseVector from sympy.vector.operators import gradient, curl, divergence from sympy import diff, integrate, S, simplify from sympy.core import sympify from sympy.vector.dyadic import Dyadic def express(expr, system, system2=None, variables=False): """ Global function for 'express' functionality. Re-expresses a Vector, Dyadic or scalar(sympyfiable) in the given coordinate system. If 'variables' is True, then the coordinate variables (base scalars) of other coordinate systems present in the vector/scalar field or dyadic are also substituted in terms of the base scalars of the given system. Parameters ========== expr : Vector/Dyadic/scalar(sympyfiable) The expression to re-express in CoordSys3D 'system' system: CoordSys3D The coordinate system the expr is to be expressed in system2: CoordSys3D The other coordinate system required for re-expression (only for a Dyadic Expr) variables : boolean Specifies whether to substitute the coordinate variables present in expr, in terms of those of parameter system Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import Symbol, cos, sin >>> N = CoordSys3D('N') >>> q = Symbol('q') >>> B = N.orient_new_axis('B', q, N.k) >>> from sympy.vector import express >>> express(B.i, N) (cos(q))*N.i + (sin(q))*N.j >>> express(N.x, B, variables=True) B.x*cos(q) - B.y*sin(q) >>> d = N.i.outer(N.i) >>> express(d, B, N) == (cos(q))*(B.i|N.i) + (-sin(q))*(B.j|N.i) True """ if expr == 0 or expr == Vector.zero: return expr if not isinstance(system, CoordSys3D): raise TypeError("system should be a CoordSys3D \ instance") if isinstance(expr, Vector): if system2 is not None: raise ValueError("system2 should not be provided for \ Vectors") # Given expr is a Vector if variables: # If variables attribute is True, substitute # the coordinate variables in the Vector system_list = [] for x in expr.atoms(BaseScalar, BaseVector): if x.system != system: system_list.append(x.system) system_list = set(system_list) subs_dict = {} for f in system_list: subs_dict.update(f.scalar_map(system)) expr = expr.subs(subs_dict) # Re-express in this coordinate system outvec = Vector.zero parts = expr.separate() for x in parts: if x != system: temp = system.rotation_matrix(x) * parts[x].to_matrix(x) outvec += matrix_to_vector(temp, system) else: outvec += parts[x] return outvec elif isinstance(expr, Dyadic): if system2 is None: system2 = system if not isinstance(system2, CoordSys3D): raise TypeError("system2 should be a CoordSys3D \ instance") outdyad = Dyadic.zero var = variables for k, v in expr.components.items(): outdyad += (express(v, system, variables=var) * (express(k.args[0], system, variables=var) | express(k.args[1], system2, variables=var))) return outdyad else: if system2 is not None: raise ValueError("system2 should not be provided for \ Vectors") if variables: # Given expr is a scalar field system_set = set() expr = sympify(expr) # Substitute all the coordinate variables for x in expr.atoms(BaseScalar): if x.system != system: system_set.add(x.system) subs_dict = {} for f in system_set: subs_dict.update(f.scalar_map(system)) return expr.subs(subs_dict) return expr def directional_derivative(field, direction_vector): """ Returns the directional derivative of a scalar or vector field computed along a given vector in coordinate system which parameters are expressed. Parameters ========== field : Vector or Scalar The scalar or vector field to compute the directional derivative of direction_vector : Vector The vector to calculated directional derivative along them. Examples ======== >>> from sympy.vector import CoordSys3D, directional_derivative >>> R = CoordSys3D('R') >>> f1 = R.x*R.y*R.z >>> v1 = 3*R.i + 4*R.j + R.k >>> directional_derivative(f1, v1) R.x*R.y + 4*R.x*R.z + 3*R.y*R.z >>> f2 = 5*R.x**2*R.z >>> directional_derivative(f2, v1) 5*R.x**2 + 30*R.x*R.z """ from sympy.vector.operators import _get_coord_sys_from_expr coord_sys = _get_coord_sys_from_expr(field) if len(coord_sys) > 0: # TODO: This gets a random coordinate system in case of multiple ones: coord_sys = next(iter(coord_sys)) field = express(field, coord_sys, variables=True) i, j, k = coord_sys.base_vectors() x, y, z = coord_sys.base_scalars() out = Vector.dot(direction_vector, i) * diff(field, x) out += Vector.dot(direction_vector, j) * diff(field, y) out += Vector.dot(direction_vector, k) * diff(field, z) if out == 0 and isinstance(field, Vector): out = Vector.zero return out elif isinstance(field, Vector): return Vector.zero else: return S.Zero def laplacian(expr): """ Return the laplacian of the given field computed in terms of the base scalars of the given coordinate system. Parameters ========== expr : SymPy Expr or Vector expr denotes a scalar or vector field. Examples ======== >>> from sympy.vector import CoordSys3D, laplacian >>> R = CoordSys3D('R') >>> f = R.x**2*R.y**5*R.z >>> laplacian(f) 20*R.x**2*R.y**3*R.z + 2*R.y**5*R.z >>> f = R.x**2*R.i + R.y**3*R.j + R.z**4*R.k >>> laplacian(f) 2*R.i + 6*R.y*R.j + 12*R.z**2*R.k """ delop = Del() if expr.is_Vector: return (gradient(divergence(expr)) - curl(curl(expr))).doit() return delop.dot(delop(expr)).doit() def is_conservative(field): """ Checks if a field is conservative. Parameters ========== field : Vector The field to check for conservative property Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector import is_conservative >>> R = CoordSys3D('R') >>> is_conservative(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) True >>> is_conservative(R.z*R.j) False """ # Field is conservative irrespective of system # Take the first coordinate system in the result of the # separate method of Vector if not isinstance(field, Vector): raise TypeError("field should be a Vector") if field == Vector.zero: return True return curl(field).simplify() == Vector.zero def is_solenoidal(field): """ Checks if a field is solenoidal. Parameters ========== field : Vector The field to check for solenoidal property Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector import is_solenoidal >>> R = CoordSys3D('R') >>> is_solenoidal(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) True >>> is_solenoidal(R.y * R.j) False """ # Field is solenoidal irrespective of system # Take the first coordinate system in the result of the # separate method in Vector if not isinstance(field, Vector): raise TypeError("field should be a Vector") if field == Vector.zero: return True return divergence(field).simplify() is S.Zero def scalar_potential(field, coord_sys): """ Returns the scalar potential function of a field in a given coordinate system (without the added integration constant). Parameters ========== field : Vector The vector field whose scalar potential function is to be calculated coord_sys : CoordSys3D The coordinate system to do the calculation in Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector import scalar_potential, gradient >>> R = CoordSys3D('R') >>> scalar_potential(R.k, R) == R.z True >>> scalar_field = 2*R.x**2*R.y*R.z >>> grad_field = gradient(scalar_field) >>> scalar_potential(grad_field, R) 2*R.x**2*R.y*R.z """ # Check whether field is conservative if not is_conservative(field): raise ValueError("Field is not conservative") if field == Vector.zero: return S.Zero # Express the field exntirely in coord_sys # Substitute coordinate variables also if not isinstance(coord_sys, CoordSys3D): raise TypeError("coord_sys must be a CoordSys3D") field = express(field, coord_sys, variables=True) dimensions = coord_sys.base_vectors() scalars = coord_sys.base_scalars() # Calculate scalar potential function temp_function = integrate(field.dot(dimensions[0]), scalars[0]) for i, dim in enumerate(dimensions[1:]): partial_diff = diff(temp_function, scalars[i + 1]) partial_diff = field.dot(dim) - partial_diff temp_function += integrate(partial_diff, scalars[i + 1]) return temp_function def scalar_potential_difference(field, coord_sys, point1, point2): """ Returns the scalar potential difference between two points in a certain coordinate system, wrt a given field. If a scalar field is provided, its values at the two points are considered. If a conservative vector field is provided, the values of its scalar potential function at the two points are used. Returns (potential at point2) - (potential at point1) The position vectors of the two Points are calculated wrt the origin of the coordinate system provided. Parameters ========== field : Vector/Expr The field to calculate wrt coord_sys : CoordSys3D The coordinate system to do the calculations in point1 : Point The initial Point in given coordinate system position2 : Point The second Point in the given coordinate system Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector import scalar_potential_difference >>> R = CoordSys3D('R') >>> P = R.origin.locate_new('P', R.x*R.i + R.y*R.j + R.z*R.k) >>> vectfield = 4*R.x*R.y*R.i + 2*R.x**2*R.j >>> scalar_potential_difference(vectfield, R, R.origin, P) 2*R.x**2*R.y >>> Q = R.origin.locate_new('O', 3*R.i + R.j + 2*R.k) >>> scalar_potential_difference(vectfield, R, P, Q) -2*R.x**2*R.y + 18 """ if not isinstance(coord_sys, CoordSys3D): raise TypeError("coord_sys must be a CoordSys3D") if isinstance(field, Vector): # Get the scalar potential function scalar_fn = scalar_potential(field, coord_sys) else: # Field is a scalar scalar_fn = field # Express positions in required coordinate system origin = coord_sys.origin position1 = express(point1.position_wrt(origin), coord_sys, variables=True) position2 = express(point2.position_wrt(origin), coord_sys, variables=True) # Get the two positions as substitution dicts for coordinate variables subs_dict1 = {} subs_dict2 = {} scalars = coord_sys.base_scalars() for i, x in enumerate(coord_sys.base_vectors()): subs_dict1[scalars[i]] = x.dot(position1) subs_dict2[scalars[i]] = x.dot(position2) return scalar_fn.subs(subs_dict2) - scalar_fn.subs(subs_dict1) def matrix_to_vector(matrix, system): """ Converts a vector in matrix form to a Vector instance. It is assumed that the elements of the Matrix represent the measure numbers of the components of the vector along basis vectors of 'system'. Parameters ========== matrix : SymPy Matrix, Dimensions: (3, 1) The matrix to be converted to a vector system : CoordSys3D The coordinate system the vector is to be defined in Examples ======== >>> from sympy import ImmutableMatrix as Matrix >>> m = Matrix([1, 2, 3]) >>> from sympy.vector import CoordSys3D, matrix_to_vector >>> C = CoordSys3D('C') >>> v = matrix_to_vector(m, C) >>> v C.i + 2*C.j + 3*C.k >>> v.to_matrix(C) == m True """ outvec = Vector.zero vects = system.base_vectors() for i, x in enumerate(matrix): outvec += x * vects[i] return outvec def _path(from_object, to_object): """ Calculates the 'path' of objects starting from 'from_object' to 'to_object', along with the index of the first common ancestor in the tree. Returns (index, list) tuple. """ if from_object._root != to_object._root: raise ValueError("No connecting path found between " + str(from_object) + " and " + str(to_object)) other_path = [] obj = to_object while obj._parent is not None: other_path.append(obj) obj = obj._parent other_path.append(obj) object_set = set(other_path) from_path = [] obj = from_object while obj not in object_set: from_path.append(obj) obj = obj._parent index = len(from_path) i = other_path.index(obj) while i >= 0: from_path.append(other_path[i]) i -= 1 return index, from_path def orthogonalize(*vlist, orthonormal=False): """ Takes a sequence of independent vectors and orthogonalizes them using the Gram - Schmidt process. Returns a list of orthogonal or orthonormal vectors. Parameters ========== vlist : sequence of independent vectors to be made orthogonal. orthonormal : Optional parameter Set to True if the vectors returned should be orthonormal. Default: False Examples ======== >>> from sympy.vector.coordsysrect import CoordSys3D >>> from sympy.vector.functions import orthogonalize >>> C = CoordSys3D('C') >>> i, j, k = C.base_vectors() >>> v1 = i + 2*j >>> v2 = 2*i + 3*j >>> orthogonalize(v1, v2) [C.i + 2*C.j, 2/5*C.i + (-1/5)*C.j] References ========== .. [1] https://en.wikipedia.org/wiki/Gram-Schmidt_process """ if not all(isinstance(vec, Vector) for vec in vlist): raise TypeError('Each element must be of Type Vector') ortho_vlist = [] for i, term in enumerate(vlist): for j in range(i): term -= ortho_vlist[j].projection(vlist[i]) # TODO : The following line introduces a performance issue # and needs to be changed once a good solution for issue #10279 is # found. if simplify(term).equals(Vector.zero): raise ValueError("Vector set not linearly independent") ortho_vlist.append(term) if orthonormal: ortho_vlist = [vec.normalize() for vec in ortho_vlist] return ortho_vlist sympy-sympy-1.9/sympy/vector/implicitregion.py000066400000000000000000000371441412543434000220070ustar00rootroot00000000000000from sympy import S, Rational, gcd, sqrt, sign, symbols, Complement from sympy.core import Basic, Tuple, diff, expand, Eq, Integer from sympy.core.compatibility import ordered from sympy.core.symbol import _symbol from sympy.solvers import solveset, nonlinsolve, diophantine from sympy.polys import total_degree from sympy.geometry import Point from sympy.ntheory.factor_ import core class ImplicitRegion(Basic): """ Represents an implicit region in space. Examples ======== >>> from sympy import Eq >>> from sympy.abc import x, y, z, t >>> from sympy.vector import ImplicitRegion >>> ImplicitRegion((x, y), x**2 + y**2 - 4) ImplicitRegion((x, y), x**2 + y**2 - 4) >>> ImplicitRegion((x, y), Eq(y*x, 1)) ImplicitRegion((x, y), x*y - 1) >>> parabola = ImplicitRegion((x, y), y**2 - 4*x) >>> parabola.degree 2 >>> parabola.equation -4*x + y**2 >>> parabola.rational_parametrization(t) (4/t**2, 4/t) >>> r = ImplicitRegion((x, y, z), Eq(z, x**2 + y**2)) >>> r.variables (x, y, z) >>> r.singular_points() {(0, 0, 0)} >>> r.regular_point() (-10, -10, 200) Parameters ========== variables : tuple to map variables in implicit equation to base scalars. equation : An expression or Eq denoting the implicit equation of the region. """ def __new__(cls, variables, equation): if not isinstance(variables, Tuple): variables = Tuple(*variables) if isinstance(equation, Eq): equation = equation.lhs - equation.rhs return super().__new__(cls, variables, equation) @property def variables(self): return self.args[0] @property def equation(self): return self.args[1] @property def degree(self): return total_degree(self.equation) def regular_point(self): """ Returns a point on the implicit region. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.vector import ImplicitRegion >>> circle = ImplicitRegion((x, y), (x + 2)**2 + (y - 3)**2 - 16) >>> circle.regular_point() (-2, -1) >>> parabola = ImplicitRegion((x, y), x**2 - 4*y) >>> parabola.regular_point() (0, 0) >>> r = ImplicitRegion((x, y, z), (x + y + z)**4) >>> r.regular_point() (-10, -10, 20) References ========== - Erik Hillgarter, "Rational Points on Conics", Diploma Thesis, RISC-Linz, J. Kepler Universitat Linz, 1996. Availaible: https://www3.risc.jku.at/publications/download/risc_1355/Rational%20Points%20on%20Conics.pdf """ equation = self.equation if len(self.variables) == 1: return (list(solveset(equation, self.variables[0], domain=S.Reals))[0],) elif len(self.variables) == 2: if self.degree == 2: coeffs = a, b, c, d, e, f = conic_coeff(self.variables, equation) if b**2 == 4*a*c: x_reg, y_reg = self._regular_point_parabola(*coeffs) else: x_reg, y_reg = self._regular_point_ellipse(*coeffs) return x_reg, y_reg if len(self.variables) == 3: x, y, z = self.variables for x_reg in range(-10, 10): for y_reg in range(-10, 10): if not solveset(equation.subs({x: x_reg, y: y_reg}), self.variables[2], domain=S.Reals).is_empty: return (x_reg, y_reg, list(solveset(equation.subs({x: x_reg, y: y_reg})))[0]) if len(self.singular_points()) != 0: return list[self.singular_points()][0] raise NotImplementedError() def _regular_point_parabola(self, a, b, c, d, e, f): ok = (a, d) != (0, 0) and (c, e) != (0, 0) and b**2 == 4*a*c and (a, c) != (0, 0) if not ok: raise ValueError("Rational Point on the conic does not exist") if a != 0: d_dash, f_dash = (4*a*e - 2*b*d, 4*a*f - d**2) if d_dash != 0: y_reg = -f_dash/d_dash x_reg = -(d + b*y_reg)/(2*a) else: ok = False elif c != 0: d_dash, f_dash = (4*c*d - 2*b*e, 4*c*f - e**2) if d_dash != 0: x_reg = -f_dash/d_dash y_reg = -(e + b*x_reg)/(2*c) else: ok = False if ok: return x_reg, y_reg else: raise ValueError("Rational Point on the conic does not exist") def _regular_point_ellipse(self, a, b, c, d, e, f): D = 4*a*c - b**2 ok = D if not ok: raise ValueError("Rational Point on the conic does not exist") if a == 0 and c == 0: K = -1 L = 4*(d*e - b*f) elif c != 0: K = D L = 4*c**2*d**2 - 4*b*c*d*e + 4*a*c*e**2 + 4*b**2*c*f - 16*a*c**2*f else: K = D L = 4*a**2*e**2 - 4*b*a*d*e + 4*b**2*a*f ok = L != 0 and not(K > 0 and L < 0) if not ok: raise ValueError("Rational Point on the conic does not exist") K = Rational(K).limit_denominator(10**12) L = Rational(L).limit_denominator(10**12) k1, k2 = K.p, K.q l1, l2 = L.p, L.q g = gcd(k2, l2) a1 = (l2*k2)/g b1 = (k1*l2)/g c1 = -(l1*k2)/g a2 = sign(a1)*core(abs(a1), 2) r1 = sqrt(a1/a2) b2 = sign(b1)*core(abs(b1), 2) r2 = sqrt(b1/b2) c2 = sign(c1)*core(abs(c1), 2) r3 = sqrt(c1/c2) g = gcd(gcd(a2, b2), c2) a2 = a2/g b2 = b2/g c2 = c2/g g1 = gcd(a2, b2) a2 = a2/g1 b2 = b2/g1 c2 = c2*g1 g2 = gcd(a2,c2) a2 = a2/g2 b2 = b2*g2 c2 = c2/g2 g3 = gcd(b2, c2) a2 = a2*g3 b2 = b2/g3 c2 = c2/g3 x, y, z = symbols("x y z") eq = a2*x**2 + b2*y**2 + c2*z**2 solutions = diophantine(eq) if len(solutions) == 0: raise ValueError("Rational Point on the conic does not exist") flag = False for sol in solutions: syms = Tuple(*sol).free_symbols rep = {s: 3 for s in syms} sol_z = sol[2] if sol_z == 0: flag = True continue if not (isinstance(sol_z, Integer) or isinstance(sol_z, int)): syms_z = sol_z.free_symbols if len(syms_z) == 1: p = next(iter(syms_z)) p_values = Complement(S.Integers, solveset(Eq(sol_z, 0), p, S.Integers)) rep[p] = next(iter(p_values)) if len(syms_z) == 2: p, q = list(ordered(syms_z)) for i in S.Integers: subs_sol_z = sol_z.subs(p, i) q_values = Complement(S.Integers, solveset(Eq(subs_sol_z, 0), q, S.Integers)) if not q_values.is_empty: rep[p] = i rep[q] = next(iter(q_values)) break if len(syms) != 0: x, y, z = tuple(s.subs(rep) for s in sol) else: x, y, z = sol flag = False break if flag: raise ValueError("Rational Point on the conic does not exist") x = (x*g3)/r1 y = (y*g2)/r2 z = (z*g1)/r3 x = x/z y = y/z if a == 0 and c == 0: x_reg = (x + y - 2*e)/(2*b) y_reg = (x - y - 2*d)/(2*b) elif c != 0: x_reg = (x - 2*d*c + b*e)/K y_reg = (y - b*x_reg - e)/(2*c) else: y_reg = (x - 2*e*a + b*d)/K x_reg = (y - b*y_reg - d)/(2*a) return x_reg, y_reg def singular_points(self): """ Returns a set of singular points of the region. The singular points are those points on the region where all partial derivatives vanish. Examples ======== >>> from sympy.abc import x, y >>> from sympy.vector import ImplicitRegion >>> I = ImplicitRegion((x, y), (y-1)**2 -x**3 + 2*x**2 -x) >>> I.singular_points() {(1, 1)} """ eq_list = [self.equation] for var in self.variables: eq_list += [diff(self.equation, var)] return nonlinsolve(eq_list, list(self.variables)) def multiplicity(self, point): """ Returns the multiplicity of a singular point on the region. A singular point (x,y) of region is said to be of multiplicity m if all the partial derivatives off to order m - 1 vanish there. Examples ======== >>> from sympy.abc import x, y, z >>> from sympy.vector import ImplicitRegion >>> I = ImplicitRegion((x, y, z), x**2 + y**3 - z**4) >>> I.singular_points() {(0, 0, 0)} >>> I.multiplicity((0, 0, 0)) 2 """ if isinstance(point, Point): point = point.args modified_eq = self.equation for i, var in enumerate(self.variables): modified_eq = modified_eq.subs(var, var + point[i]) modified_eq = expand(modified_eq) if len(modified_eq.args) != 0: terms = modified_eq.args m = min([total_degree(term) for term in terms]) else: terms = modified_eq m = total_degree(terms) return m def rational_parametrization(self, parameters=('t', 's'), reg_point=None): """ Returns the rational parametrization of implict region. Examples ======== >>> from sympy import Eq >>> from sympy.abc import x, y, z, s, t >>> from sympy.vector import ImplicitRegion >>> parabola = ImplicitRegion((x, y), y**2 - 4*x) >>> parabola.rational_parametrization() (4/t**2, 4/t) >>> circle = ImplicitRegion((x, y), Eq(x**2 + y**2, 4)) >>> circle.rational_parametrization() (4*t/(t**2 + 1), 4*t**2/(t**2 + 1) - 2) >>> I = ImplicitRegion((x, y), x**3 + x**2 - y**2) >>> I.rational_parametrization() (t**2 - 1, t*(t**2 - 1)) >>> cubic_curve = ImplicitRegion((x, y), x**3 + x**2 - y**2) >>> cubic_curve.rational_parametrization(parameters=(t)) (t**2 - 1, t*(t**2 - 1)) >>> sphere = ImplicitRegion((x, y, z), x**2 + y**2 + z**2 - 4) >>> sphere.rational_parametrization(parameters=(t, s)) (-2 + 4/(s**2 + t**2 + 1), 4*s/(s**2 + t**2 + 1), 4*t/(s**2 + t**2 + 1)) For some conics, regular_points() is unable to find a point on curve. To calulcate the parametric representation in such cases, user need to determine a point on the region and pass it using reg_point. >>> c = ImplicitRegion((x, y), (x - 1/2)**2 + (y)**2 - (1/4)**2) >>> c.rational_parametrization(reg_point=(3/4, 0)) (0.75 - 0.5/(t**2 + 1), -0.5*t/(t**2 + 1)) References ========== - Christoph M. Hoffmann, "Conversion Methods between Parametric and Implicit Curves and Surfaces", Purdue e-Pubs, 1990. Available: https://docs.lib.purdue.edu/cgi/viewcontent.cgi?article=1827&context=cstech """ equation = self.equation degree = self.degree if degree == 1: if len(self.variables) == 1: return (equation,) elif len(self.variables) == 2: x, y = self.variables y_par = list(solveset(equation, y))[0] return x, y_par else: raise NotImplementedError() point = () # Finding the (n - 1) fold point of the monoid of degree if degree == 2: # For degree 2 curves, either a regular point or a singular point can be used. if reg_point is not None: # Using point provided by the user as regular point point = reg_point else: if len(self.singular_points()) != 0: point = list(self.singular_points())[0] else: point = self.regular_point() if len(self.singular_points()) != 0: singular_points = self.singular_points() for spoint in singular_points: syms = Tuple(*spoint).free_symbols rep = {s: 2 for s in syms} if len(syms) != 0: spoint = tuple(s.subs(rep) for s in spoint) if self.multiplicity(spoint) == degree - 1: point = spoint break if len(point) == 0: # The region in not a monoid raise NotImplementedError() modified_eq = equation # Shifting the region such that fold point moves to origin for i, var in enumerate(self.variables): modified_eq = modified_eq.subs(var, var + point[i]) modified_eq = expand(modified_eq) hn = hn_1 = 0 for term in modified_eq.args: if total_degree(term) == degree: hn += term else: hn_1 += term hn_1 = -1*hn_1 if not isinstance(parameters, tuple): parameters = (parameters,) if len(self.variables) == 2: parameter1 = parameters[0] if parameter1 == 's': # To avoid name conflict between parameters s = _symbol('s_', real=True) else: s = _symbol('s', real=True) t = _symbol(parameter1, real=True) hn = hn.subs({self.variables[0]: s, self.variables[1]: t}) hn_1 = hn_1.subs({self.variables[0]: s, self.variables[1]: t}) x_par = (s*(hn_1/hn)).subs(s, 1) + point[0] y_par = (t*(hn_1/hn)).subs(s, 1) + point[1] return x_par, y_par elif len(self.variables) == 3: parameter1, parameter2 = parameters if parameter1 == 'r' or parameter2 == 'r': # To avoid name conflict between parameters r = _symbol('r_', real=True) else: r = _symbol('r', real=True) s = _symbol(parameter2, real=True) t = _symbol(parameter1, real=True) hn = hn.subs({self.variables[0]: r, self.variables[1]: s, self.variables[2]: t}) hn_1 = hn_1.subs({self.variables[0]: r, self.variables[1]: s, self.variables[2]: t}) x_par = (r*(hn_1/hn)).subs(r, 1) + point[0] y_par = (s*(hn_1/hn)).subs(r, 1) + point[1] z_par = (t*(hn_1/hn)).subs(r, 1) + point[2] return x_par, y_par, z_par raise NotImplementedError() def conic_coeff(variables, equation): if total_degree(equation) != 2: raise ValueError() x = variables[0] y = variables[1] equation = expand(equation) a = equation.coeff(x**2) b = equation.coeff(x*y) c = equation.coeff(y**2) d = equation.coeff(x, 1).coeff(y, 0) e = equation.coeff(y, 1).coeff(x, 0) f = equation.coeff(x, 0).coeff(y, 0) return a, b, c, d, e, f sympy-sympy-1.9/sympy/vector/integrals.py000066400000000000000000000152611412543434000207550ustar00rootroot00000000000000from sympy import S, simplify from sympy.core import Basic, diff from sympy.matrices import Matrix from sympy.vector import (CoordSys3D, Vector, ParametricRegion, parametric_region_list, ImplicitRegion) from sympy.vector.operators import _get_coord_sys_from_expr from sympy.integrals import Integral, integrate from sympy.utilities.iterables import topological_sort, default_sort_key from sympy.geometry.entity import GeometryEntity class ParametricIntegral(Basic): """ Represents integral of a scalar or vector field over a Parametric Region Examples ======== >>> from sympy import cos, sin, pi >>> from sympy.vector import CoordSys3D, ParametricRegion, ParametricIntegral >>> from sympy.abc import r, t, theta, phi >>> C = CoordSys3D('C') >>> curve = ParametricRegion((3*t - 2, t + 1), (t, 1, 2)) >>> ParametricIntegral(C.x, curve) 5*sqrt(10)/2 >>> length = ParametricIntegral(1, curve) >>> length sqrt(10) >>> semisphere = ParametricRegion((2*sin(phi)*cos(theta), 2*sin(phi)*sin(theta), 2*cos(phi)),\ (theta, 0, 2*pi), (phi, 0, pi/2)) >>> ParametricIntegral(C.z, semisphere) 8*pi >>> ParametricIntegral(C.j + C.k, ParametricRegion((r*cos(theta), r*sin(theta)), r, theta)) 0 """ def __new__(cls, field, parametricregion): coord_set = _get_coord_sys_from_expr(field) if len(coord_set) == 0: coord_sys = CoordSys3D('C') elif len(coord_set) > 1: raise ValueError else: coord_sys = next(iter(coord_set)) if parametricregion.dimensions == 0: return S.Zero base_vectors = coord_sys.base_vectors() base_scalars = coord_sys.base_scalars() parametricfield = field r = Vector.zero for i in range(len(parametricregion.definition)): r += base_vectors[i]*parametricregion.definition[i] if len(coord_set) != 0: for i in range(len(parametricregion.definition)): parametricfield = parametricfield.subs(base_scalars[i], parametricregion.definition[i]) if parametricregion.dimensions == 1: parameter = parametricregion.parameters[0] r_diff = diff(r, parameter) lower, upper = parametricregion.limits[parameter][0], parametricregion.limits[parameter][1] if isinstance(parametricfield, Vector): integrand = simplify(r_diff.dot(parametricfield)) else: integrand = simplify(r_diff.magnitude()*parametricfield) result = integrate(integrand, (parameter, lower, upper)) elif parametricregion.dimensions == 2: u, v = cls._bounds_case(parametricregion.parameters, parametricregion.limits) r_u = diff(r, u) r_v = diff(r, v) normal_vector = simplify(r_u.cross(r_v)) if isinstance(parametricfield, Vector): integrand = parametricfield.dot(normal_vector) else: integrand = parametricfield*normal_vector.magnitude() integrand = simplify(integrand) lower_u, upper_u = parametricregion.limits[u][0], parametricregion.limits[u][1] lower_v, upper_v = parametricregion.limits[v][0], parametricregion.limits[v][1] result = integrate(integrand, (u, lower_u, upper_u), (v, lower_v, upper_v)) else: variables = cls._bounds_case(parametricregion.parameters, parametricregion.limits) coeff = Matrix(parametricregion.definition).jacobian(variables).det() integrand = simplify(parametricfield*coeff) l = [(var, parametricregion.limits[var][0], parametricregion.limits[var][1]) for var in variables] result = integrate(integrand, *l) if not isinstance(result, Integral): return result else: return super().__new__(cls, field, parametricregion) @classmethod def _bounds_case(cls, parameters, limits): V = list(limits.keys()) E = list() for p in V: lower_p = limits[p][0] upper_p = limits[p][1] lower_p = lower_p.atoms() upper_p = upper_p.atoms() for q in V: if p == q: continue if lower_p.issuperset({q}) or upper_p.issuperset({q}): E.append((p, q)) if not E: return parameters else: return topological_sort((V, E), key=default_sort_key) @property def field(self): return self.args[0] @property def parametricregion(self): return self.args[1] def vector_integrate(field, *region): """ Compute the integral of a vector/scalar field over a a region or a set of parameters. Examples ======== >>> from sympy.vector import CoordSys3D, ParametricRegion, vector_integrate >>> from sympy.abc import x, y, t >>> C = CoordSys3D('C') >>> region = ParametricRegion((t, t**2), (t, 1, 5)) >>> vector_integrate(C.x*C.i, region) 12 Integrals over some objects of geometry module can also be calculated. >>> from sympy.geometry import Point, Circle, Triangle >>> c = Circle(Point(0, 2), 5) >>> vector_integrate(C.x**2 + C.y**2, c) 290*pi >>> triangle = Triangle(Point(-2, 3), Point(2, 3), Point(0, 5)) >>> vector_integrate(3*C.x**2*C.y*C.i + C.j, triangle) -8 Integrals over some simple implicit regions can be computed. But in most cases, it takes too long to compute over them. This is due to the expressions of parametric representation becoming large. >>> from sympy.vector import ImplicitRegion >>> c2 = ImplicitRegion((x, y), (x - 2)**2 + (y - 1)**2 - 9) >>> vector_integrate(1, c2) 6*pi Integral of fields with respect to base scalars: >>> vector_integrate(12*C.y**3, (C.y, 1, 3)) 240 >>> vector_integrate(C.x**2*C.z, C.x) C.x**3*C.z/3 >>> vector_integrate(C.x*C.i - C.y*C.k, C.x) (Integral(C.x, C.x))*C.i + (Integral(-C.y, C.x))*C.k >>> _.doit() C.x**2/2*C.i + (-C.x*C.y)*C.k """ if len(region) == 1: if isinstance(region[0], ParametricRegion): return ParametricIntegral(field, region[0]) if isinstance(region[0], ImplicitRegion): region = parametric_region_list(region[0])[0] return vector_integrate(field, region) if isinstance(region[0], GeometryEntity): regions_list = parametric_region_list(region[0]) result = 0 for reg in regions_list: result += vector_integrate(field, reg) return result return integrate(field, *region) sympy-sympy-1.9/sympy/vector/operators.py000066400000000000000000000245611412543434000210060ustar00rootroot00000000000000import collections from sympy.core.expr import Expr from sympy.core import sympify, S, preorder_traversal from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.vector import Vector, VectorMul, VectorAdd, Cross, Dot from sympy.vector.scalar import BaseScalar from sympy.utilities.exceptions import SymPyDeprecationWarning from sympy.core.function import Derivative from sympy import Add, Mul def _get_coord_systems(expr): g = preorder_traversal(expr) ret = set() for i in g: if isinstance(i, CoordSys3D): ret.add(i) g.skip() return frozenset(ret) def _get_coord_sys_from_expr(expr, coord_sys=None): """ expr : expression The coordinate system is extracted from this parameter. """ # TODO: Remove this line when warning from issue #12884 will be removed if coord_sys is not None: SymPyDeprecationWarning( feature="coord_sys parameter", useinstead="do not use it", deprecated_since_version="1.1", issue=12884, ).warn() return _get_coord_systems(expr) def _split_mul_args_wrt_coordsys(expr): d = collections.defaultdict(lambda: S.One) for i in expr.args: d[_get_coord_systems(i)] *= i return list(d.values()) class Gradient(Expr): """ Represents unevaluated Gradient. Examples ======== >>> from sympy.vector import CoordSys3D, Gradient >>> R = CoordSys3D('R') >>> s = R.x*R.y*R.z >>> Gradient(s) Gradient(R.x*R.y*R.z) """ def __new__(cls, expr): expr = sympify(expr) obj = Expr.__new__(cls, expr) obj._expr = expr return obj def doit(self, **kwargs): return gradient(self._expr, doit=True) class Divergence(Expr): """ Represents unevaluated Divergence. Examples ======== >>> from sympy.vector import CoordSys3D, Divergence >>> R = CoordSys3D('R') >>> v = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> Divergence(v) Divergence(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) """ def __new__(cls, expr): expr = sympify(expr) obj = Expr.__new__(cls, expr) obj._expr = expr return obj def doit(self, **kwargs): return divergence(self._expr, doit=True) class Curl(Expr): """ Represents unevaluated Curl. Examples ======== >>> from sympy.vector import CoordSys3D, Curl >>> R = CoordSys3D('R') >>> v = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> Curl(v) Curl(R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k) """ def __new__(cls, expr): expr = sympify(expr) obj = Expr.__new__(cls, expr) obj._expr = expr return obj def doit(self, **kwargs): return curl(self._expr, doit=True) def curl(vect, coord_sys=None, doit=True): """ Returns the curl of a vector field computed wrt the base scalars of the given coordinate system. Parameters ========== vect : Vector The vector operand coord_sys : CoordSys3D The coordinate system to calculate the gradient in. Deprecated since version 1.1 doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, curl >>> R = CoordSys3D('R') >>> v1 = R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> curl(v1) 0 >>> v2 = R.x*R.y*R.z*R.i >>> curl(v2) R.x*R.y*R.j + (-R.x*R.z)*R.k """ coord_sys = _get_coord_sys_from_expr(vect, coord_sys) if len(coord_sys) == 0: return Vector.zero elif len(coord_sys) == 1: coord_sys = next(iter(coord_sys)) i, j, k = coord_sys.base_vectors() x, y, z = coord_sys.base_scalars() h1, h2, h3 = coord_sys.lame_coefficients() vectx = vect.dot(i) vecty = vect.dot(j) vectz = vect.dot(k) outvec = Vector.zero outvec += (Derivative(vectz * h3, y) - Derivative(vecty * h2, z)) * i / (h2 * h3) outvec += (Derivative(vectx * h1, z) - Derivative(vectz * h3, x)) * j / (h1 * h3) outvec += (Derivative(vecty * h2, x) - Derivative(vectx * h1, y)) * k / (h2 * h1) if doit: return outvec.doit() return outvec else: if isinstance(vect, (Add, VectorAdd)): from sympy.vector import express try: cs = next(iter(coord_sys)) args = [express(i, cs, variables=True) for i in vect.args] except ValueError: args = vect.args return VectorAdd.fromiter(curl(i, doit=doit) for i in args) elif isinstance(vect, (Mul, VectorMul)): vector = [i for i in vect.args if isinstance(i, (Vector, Cross, Gradient))][0] scalar = Mul.fromiter(i for i in vect.args if not isinstance(i, (Vector, Cross, Gradient))) res = Cross(gradient(scalar), vector).doit() + scalar*curl(vector, doit=doit) if doit: return res.doit() return res elif isinstance(vect, (Cross, Curl, Gradient)): return Curl(vect) else: raise Curl(vect) def divergence(vect, coord_sys=None, doit=True): """ Returns the divergence of a vector field computed wrt the base scalars of the given coordinate system. Parameters ========== vector : Vector The vector operand coord_sys : CoordSys3D The coordinate system to calculate the gradient in Deprecated since version 1.1 doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, divergence >>> R = CoordSys3D('R') >>> v1 = R.x*R.y*R.z * (R.i+R.j+R.k) >>> divergence(v1) R.x*R.y + R.x*R.z + R.y*R.z >>> v2 = 2*R.y*R.z*R.j >>> divergence(v2) 2*R.z """ coord_sys = _get_coord_sys_from_expr(vect, coord_sys) if len(coord_sys) == 0: return S.Zero elif len(coord_sys) == 1: if isinstance(vect, (Cross, Curl, Gradient)): return Divergence(vect) # TODO: is case of many coord systems, this gets a random one: coord_sys = next(iter(coord_sys)) i, j, k = coord_sys.base_vectors() x, y, z = coord_sys.base_scalars() h1, h2, h3 = coord_sys.lame_coefficients() vx = _diff_conditional(vect.dot(i), x, h2, h3) \ / (h1 * h2 * h3) vy = _diff_conditional(vect.dot(j), y, h3, h1) \ / (h1 * h2 * h3) vz = _diff_conditional(vect.dot(k), z, h1, h2) \ / (h1 * h2 * h3) res = vx + vy + vz if doit: return res.doit() return res else: if isinstance(vect, (Add, VectorAdd)): return Add.fromiter(divergence(i, doit=doit) for i in vect.args) elif isinstance(vect, (Mul, VectorMul)): vector = [i for i in vect.args if isinstance(i, (Vector, Cross, Gradient))][0] scalar = Mul.fromiter(i for i in vect.args if not isinstance(i, (Vector, Cross, Gradient))) res = Dot(vector, gradient(scalar)) + scalar*divergence(vector, doit=doit) if doit: return res.doit() return res elif isinstance(vect, (Cross, Curl, Gradient)): return Divergence(vect) else: raise Divergence(vect) def gradient(scalar_field, coord_sys=None, doit=True): """ Returns the vector gradient of a scalar field computed wrt the base scalars of the given coordinate system. Parameters ========== scalar_field : SymPy Expr The scalar field to compute the gradient of coord_sys : CoordSys3D The coordinate system to calculate the gradient in Deprecated since version 1.1 doit : bool If True, the result is returned after calling .doit() on each component. Else, the returned expression contains Derivative instances Examples ======== >>> from sympy.vector import CoordSys3D, gradient >>> R = CoordSys3D('R') >>> s1 = R.x*R.y*R.z >>> gradient(s1) R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k >>> s2 = 5*R.x**2*R.z >>> gradient(s2) 10*R.x*R.z*R.i + 5*R.x**2*R.k """ coord_sys = _get_coord_sys_from_expr(scalar_field, coord_sys) if len(coord_sys) == 0: return Vector.zero elif len(coord_sys) == 1: coord_sys = next(iter(coord_sys)) h1, h2, h3 = coord_sys.lame_coefficients() i, j, k = coord_sys.base_vectors() x, y, z = coord_sys.base_scalars() vx = Derivative(scalar_field, x) / h1 vy = Derivative(scalar_field, y) / h2 vz = Derivative(scalar_field, z) / h3 if doit: return (vx * i + vy * j + vz * k).doit() return vx * i + vy * j + vz * k else: if isinstance(scalar_field, (Add, VectorAdd)): return VectorAdd.fromiter(gradient(i) for i in scalar_field.args) if isinstance(scalar_field, (Mul, VectorMul)): s = _split_mul_args_wrt_coordsys(scalar_field) return VectorAdd.fromiter(scalar_field / i * gradient(i) for i in s) return Gradient(scalar_field) class Laplacian(Expr): """ Represents unevaluated Laplacian. Examples ======== >>> from sympy.vector import CoordSys3D, Laplacian >>> R = CoordSys3D('R') >>> v = 3*R.x**3*R.y**2*R.z**3 >>> Laplacian(v) Laplacian(3*R.x**3*R.y**2*R.z**3) """ def __new__(cls, expr): expr = sympify(expr) obj = Expr.__new__(cls, expr) obj._expr = expr return obj def doit(self, **kwargs): from sympy.vector.functions import laplacian return laplacian(self._expr) def _diff_conditional(expr, base_scalar, coeff_1, coeff_2): """ First re-expresses expr in the system that base_scalar belongs to. If base_scalar appears in the re-expressed form, differentiates it wrt base_scalar. Else, returns 0 """ from sympy.vector.functions import express new_expr = express(expr, base_scalar.system, variables=True) if base_scalar in new_expr.atoms(BaseScalar): return Derivative(coeff_1 * coeff_2 * new_expr, base_scalar) return S.Zero sympy-sympy-1.9/sympy/vector/orienters.py000066400000000000000000000266351412543434000210060ustar00rootroot00000000000000from sympy.core.basic import Basic from sympy import (sympify, eye, sin, cos, rot_axis1, rot_axis2, rot_axis3, ImmutableMatrix as Matrix) from sympy.core.cache import cacheit from sympy.core.symbol import Str import sympy.vector class Orienter(Basic): """ Super-class for all orienter classes. """ def rotation_matrix(self): """ The rotation matrix corresponding to this orienter instance. """ return self._parent_orient class AxisOrienter(Orienter): """ Class to denote an axis orienter. """ def __new__(cls, angle, axis): if not isinstance(axis, sympy.vector.Vector): raise TypeError("axis should be a Vector") angle = sympify(angle) obj = super().__new__(cls, angle, axis) obj._angle = angle obj._axis = axis return obj def __init__(self, angle, axis): """ Axis rotation is a rotation about an arbitrary axis by some angle. The angle is supplied as a SymPy expr scalar, and the axis is supplied as a Vector. Parameters ========== angle : Expr The angle by which the new system is to be rotated axis : Vector The axis around which the rotation has to be performed Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q1 = symbols('q1') >>> N = CoordSys3D('N') >>> from sympy.vector import AxisOrienter >>> orienter = AxisOrienter(q1, N.i + 2 * N.j) >>> B = N.orient_new('B', (orienter, )) """ # Dummy initializer for docstrings pass @cacheit def rotation_matrix(self, system): """ The rotation matrix corresponding to this orienter instance. Parameters ========== system : CoordSys3D The coordinate system wrt which the rotation matrix is to be computed """ axis = sympy.vector.express(self.axis, system).normalize() axis = axis.to_matrix(system) theta = self.angle parent_orient = ((eye(3) - axis * axis.T) * cos(theta) + Matrix([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]], [-axis[1], axis[0], 0]]) * sin(theta) + axis * axis.T) parent_orient = parent_orient.T return parent_orient @property def angle(self): return self._angle @property def axis(self): return self._axis class ThreeAngleOrienter(Orienter): """ Super-class for Body and Space orienters. """ def __new__(cls, angle1, angle2, angle3, rot_order): if isinstance(rot_order, Str): rot_order = rot_order.name approved_orders = ('123', '231', '312', '132', '213', '321', '121', '131', '212', '232', '313', '323', '') original_rot_order = rot_order rot_order = str(rot_order).upper() if not (len(rot_order) == 3): raise TypeError('rot_order should be a str of length 3') rot_order = [i.replace('X', '1') for i in rot_order] rot_order = [i.replace('Y', '2') for i in rot_order] rot_order = [i.replace('Z', '3') for i in rot_order] rot_order = ''.join(rot_order) if rot_order not in approved_orders: raise TypeError('Invalid rot_type parameter') a1 = int(rot_order[0]) a2 = int(rot_order[1]) a3 = int(rot_order[2]) angle1 = sympify(angle1) angle2 = sympify(angle2) angle3 = sympify(angle3) if cls._in_order: parent_orient = (_rot(a1, angle1) * _rot(a2, angle2) * _rot(a3, angle3)) else: parent_orient = (_rot(a3, angle3) * _rot(a2, angle2) * _rot(a1, angle1)) parent_orient = parent_orient.T obj = super().__new__( cls, angle1, angle2, angle3, Str(rot_order)) obj._angle1 = angle1 obj._angle2 = angle2 obj._angle3 = angle3 obj._rot_order = original_rot_order obj._parent_orient = parent_orient return obj @property def angle1(self): return self._angle1 @property def angle2(self): return self._angle2 @property def angle3(self): return self._angle3 @property def rot_order(self): return self._rot_order class BodyOrienter(ThreeAngleOrienter): """ Class to denote a body-orienter. """ _in_order = True def __new__(cls, angle1, angle2, angle3, rot_order): obj = ThreeAngleOrienter.__new__(cls, angle1, angle2, angle3, rot_order) return obj def __init__(self, angle1, angle2, angle3, rot_order): """ Body orientation takes this coordinate system through three successive simple rotations. Body fixed rotations include both Euler Angles and Tait-Bryan Angles, see https://en.wikipedia.org/wiki/Euler_angles. Parameters ========== angle1, angle2, angle3 : Expr Three successive angles to rotate the coordinate system by rotation_order : string String defining the order of axes for rotation Examples ======== >>> from sympy.vector import CoordSys3D, BodyOrienter >>> from sympy import symbols >>> q1, q2, q3 = symbols('q1 q2 q3') >>> N = CoordSys3D('N') A 'Body' fixed rotation is described by three angles and three body-fixed rotation axes. To orient a coordinate system D with respect to N, each sequential rotation is always about the orthogonal unit vectors fixed to D. For example, a '123' rotation will specify rotations about N.i, then D.j, then D.k. (Initially, D.i is same as N.i) Therefore, >>> body_orienter = BodyOrienter(q1, q2, q3, '123') >>> D = N.orient_new('D', (body_orienter, )) is same as >>> from sympy.vector import AxisOrienter >>> axis_orienter1 = AxisOrienter(q1, N.i) >>> D = N.orient_new('D', (axis_orienter1, )) >>> axis_orienter2 = AxisOrienter(q2, D.j) >>> D = D.orient_new('D', (axis_orienter2, )) >>> axis_orienter3 = AxisOrienter(q3, D.k) >>> D = D.orient_new('D', (axis_orienter3, )) Acceptable rotation orders are of length 3, expressed in XYZ or 123, and cannot have a rotation about about an axis twice in a row. >>> body_orienter1 = BodyOrienter(q1, q2, q3, '123') >>> body_orienter2 = BodyOrienter(q1, q2, 0, 'ZXZ') >>> body_orienter3 = BodyOrienter(0, 0, 0, 'XYX') """ # Dummy initializer for docstrings pass class SpaceOrienter(ThreeAngleOrienter): """ Class to denote a space-orienter. """ _in_order = False def __new__(cls, angle1, angle2, angle3, rot_order): obj = ThreeAngleOrienter.__new__(cls, angle1, angle2, angle3, rot_order) return obj def __init__(self, angle1, angle2, angle3, rot_order): """ Space rotation is similar to Body rotation, but the rotations are applied in the opposite order. Parameters ========== angle1, angle2, angle3 : Expr Three successive angles to rotate the coordinate system by rotation_order : string String defining the order of axes for rotation See Also ======== BodyOrienter : Orienter to orient systems wrt Euler angles. Examples ======== >>> from sympy.vector import CoordSys3D, SpaceOrienter >>> from sympy import symbols >>> q1, q2, q3 = symbols('q1 q2 q3') >>> N = CoordSys3D('N') To orient a coordinate system D with respect to N, each sequential rotation is always about N's orthogonal unit vectors. For example, a '123' rotation will specify rotations about N.i, then N.j, then N.k. Therefore, >>> space_orienter = SpaceOrienter(q1, q2, q3, '312') >>> D = N.orient_new('D', (space_orienter, )) is same as >>> from sympy.vector import AxisOrienter >>> axis_orienter1 = AxisOrienter(q1, N.i) >>> B = N.orient_new('B', (axis_orienter1, )) >>> axis_orienter2 = AxisOrienter(q2, N.j) >>> C = B.orient_new('C', (axis_orienter2, )) >>> axis_orienter3 = AxisOrienter(q3, N.k) >>> D = C.orient_new('C', (axis_orienter3, )) """ # Dummy initializer for docstrings pass class QuaternionOrienter(Orienter): """ Class to denote a quaternion-orienter. """ def __new__(cls, q0, q1, q2, q3): q0 = sympify(q0) q1 = sympify(q1) q2 = sympify(q2) q3 = sympify(q3) parent_orient = (Matrix([[q0 ** 2 + q1 ** 2 - q2 ** 2 - q3 ** 2, 2 * (q1 * q2 - q0 * q3), 2 * (q0 * q2 + q1 * q3)], [2 * (q1 * q2 + q0 * q3), q0 ** 2 - q1 ** 2 + q2 ** 2 - q3 ** 2, 2 * (q2 * q3 - q0 * q1)], [2 * (q1 * q3 - q0 * q2), 2 * (q0 * q1 + q2 * q3), q0 ** 2 - q1 ** 2 - q2 ** 2 + q3 ** 2]])) parent_orient = parent_orient.T obj = super().__new__(cls, q0, q1, q2, q3) obj._q0 = q0 obj._q1 = q1 obj._q2 = q2 obj._q3 = q3 obj._parent_orient = parent_orient return obj def __init__(self, angle1, angle2, angle3, rot_order): """ Quaternion orientation orients the new CoordSys3D with Quaternions, defined as a finite rotation about lambda, a unit vector, by some amount theta. This orientation is described by four parameters: q0 = cos(theta/2) q1 = lambda_x sin(theta/2) q2 = lambda_y sin(theta/2) q3 = lambda_z sin(theta/2) Quaternion does not take in a rotation order. Parameters ========== q0, q1, q2, q3 : Expr The quaternions to rotate the coordinate system by Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy import symbols >>> q0, q1, q2, q3 = symbols('q0 q1 q2 q3') >>> N = CoordSys3D('N') >>> from sympy.vector import QuaternionOrienter >>> q_orienter = QuaternionOrienter(q0, q1, q2, q3) >>> B = N.orient_new('B', (q_orienter, )) """ # Dummy initializer for docstrings pass @property def q0(self): return self._q0 @property def q1(self): return self._q1 @property def q2(self): return self._q2 @property def q3(self): return self._q3 def _rot(axis, angle): """DCM for simple axis 1, 2 or 3 rotations. """ if axis == 1: return Matrix(rot_axis1(angle).T) elif axis == 2: return Matrix(rot_axis2(angle).T) elif axis == 3: return Matrix(rot_axis3(angle).T) sympy-sympy-1.9/sympy/vector/parametricregion.py000066400000000000000000000134311412543434000223150ustar00rootroot00000000000000from functools import singledispatch from sympy import pi, tan from sympy.simplify import trigsimp from sympy.core import Basic, Tuple from sympy.core.symbol import _symbol from sympy.solvers import solve from sympy.geometry import Point, Segment, Curve, Ellipse, Polygon from sympy.vector import ImplicitRegion class ParametricRegion(Basic): """ Represents a parametric region in space. Examples ======== >>> from sympy import cos, sin, pi >>> from sympy.abc import r, theta, t, a, b, x, y >>> from sympy.vector import ParametricRegion >>> ParametricRegion((t, t**2), (t, -1, 2)) ParametricRegion((t, t**2), (t, -1, 2)) >>> ParametricRegion((x, y), (x, 3, 4), (y, 5, 6)) ParametricRegion((x, y), (x, 3, 4), (y, 5, 6)) >>> ParametricRegion((r*cos(theta), r*sin(theta)), (r, -2, 2), (theta, 0, pi)) ParametricRegion((r*cos(theta), r*sin(theta)), (r, -2, 2), (theta, 0, pi)) >>> ParametricRegion((a*cos(t), b*sin(t)), t) ParametricRegion((a*cos(t), b*sin(t)), t) >>> circle = ParametricRegion((r*cos(theta), r*sin(theta)), r, (theta, 0, pi)) >>> circle.parameters (r, theta) >>> circle.definition (r*cos(theta), r*sin(theta)) >>> circle.limits {theta: (0, pi)} Dimension of a parametric region determines whether a region is a curve, surface or volume region. It does not represent its dimensions in space. >>> circle.dimensions 1 Parameters ========== definition : tuple to define base scalars in terms of parameters. bounds : Parameter or a tuple of length 3 to define parameter and corresponding lower and upper bound. """ def __new__(cls, definition, *bounds): parameters = () limits = {} if not isinstance(bounds, Tuple): bounds = Tuple(*bounds) for bound in bounds: if isinstance(bound, tuple) or isinstance(bound, Tuple): if len(bound) != 3: raise ValueError("Tuple should be in the form (parameter, lowerbound, upperbound)") parameters += (bound[0],) limits[bound[0]] = (bound[1], bound[2]) else: parameters += (bound,) if not (isinstance(definition, tuple) or isinstance(definition, Tuple)): definition = (definition,) obj = super().__new__(cls, Tuple(*definition), *bounds) obj._parameters = parameters obj._limits = limits return obj @property def definition(self): return self.args[0] @property def limits(self): return self._limits @property def parameters(self): return self._parameters @property def dimensions(self): return len(self.limits) @singledispatch def parametric_region_list(reg): """ Returns a list of ParametricRegion objects representing the geometric region. Examples ======== >>> from sympy.abc import t >>> from sympy.vector import parametric_region_list >>> from sympy.geometry import Point, Curve, Ellipse, Segment, Polygon >>> p = Point(2, 5) >>> parametric_region_list(p) [ParametricRegion((2, 5))] >>> c = Curve((t**3, 4*t), (t, -3, 4)) >>> parametric_region_list(c) [ParametricRegion((t**3, 4*t), (t, -3, 4))] >>> e = Ellipse(Point(1, 3), 2, 3) >>> parametric_region_list(e) [ParametricRegion((2*cos(t) + 1, 3*sin(t) + 3), (t, 0, 2*pi))] >>> s = Segment(Point(1, 3), Point(2, 6)) >>> parametric_region_list(s) [ParametricRegion((t + 1, 3*t + 3), (t, 0, 1))] >>> p1, p2, p3, p4 = [(0, 1), (2, -3), (5, 3), (-2, 3)] >>> poly = Polygon(p1, p2, p3, p4) >>> parametric_region_list(poly) [ParametricRegion((2*t, 1 - 4*t), (t, 0, 1)), ParametricRegion((3*t + 2, 6*t - 3), (t, 0, 1)),\ ParametricRegion((5 - 7*t, 3), (t, 0, 1)), ParametricRegion((2*t - 2, 3 - 2*t), (t, 0, 1))] """ raise ValueError("SymPy cannot determine parametric representation of the region.") @parametric_region_list.register(Point) def _(obj): return [ParametricRegion(obj.args)] @parametric_region_list.register(Curve) # type: ignore def _(obj): definition = obj.arbitrary_point(obj.parameter).args bounds = obj.limits return [ParametricRegion(definition, bounds)] @parametric_region_list.register(Ellipse) # type: ignore def _(obj, parameter='t'): definition = obj.arbitrary_point(parameter).args t = _symbol(parameter, real=True) bounds = (t, 0, 2*pi) return [ParametricRegion(definition, bounds)] @parametric_region_list.register(Segment) # type: ignore def _(obj, parameter='t'): t = _symbol(parameter, real=True) definition = obj.arbitrary_point(t).args for i in range(0, 3): lower_bound = solve(definition[i] - obj.points[0].args[i], t) upper_bound = solve(definition[i] - obj.points[1].args[i], t) if len(lower_bound) == 1 and len(upper_bound) == 1: bounds = t, lower_bound[0], upper_bound[0] break definition_tuple = obj.arbitrary_point(parameter).args return [ParametricRegion(definition_tuple, bounds)] @parametric_region_list.register(Polygon) # type: ignore def _(obj, parameter='t'): l = [parametric_region_list(side, parameter)[0] for side in obj.sides] return l @parametric_region_list.register(ImplicitRegion) # type: ignore def _(obj, parameters=('t', 's')): definition = obj.rational_parametrization(parameters) bounds = [] for i in range(len(obj.variables) - 1): # Each parameter is replaced by its tangent to simplify intergation parameter = _symbol(parameters[i], real=True) definition = [trigsimp(elem.subs(parameter, tan(parameter/2))) for elem in definition] bounds.append((parameter, 0, 2*pi),) definition = Tuple(*definition) return [ParametricRegion(definition, *bounds)] sympy-sympy-1.9/sympy/vector/point.py000066400000000000000000000106441412543434000201160ustar00rootroot00000000000000from sympy.core.basic import Basic from sympy.core.symbol import Str from sympy.vector.vector import Vector from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.functions import _path from sympy.core.cache import cacheit class Point(Basic): """ Represents a point in 3-D space. """ def __new__(cls, name, position=Vector.zero, parent_point=None): name = str(name) # Check the args first if not isinstance(position, Vector): raise TypeError( "position should be an instance of Vector, not %s" % type( position)) if (not isinstance(parent_point, Point) and parent_point is not None): raise TypeError( "parent_point should be an instance of Point, not %s" % type( parent_point)) # Super class construction if parent_point is None: obj = super().__new__(cls, Str(name), position) else: obj = super().__new__(cls, Str(name), position, parent_point) # Decide the object parameters obj._name = name obj._pos = position if parent_point is None: obj._parent = None obj._root = obj else: obj._parent = parent_point obj._root = parent_point._root # Return object return obj @cacheit def position_wrt(self, other): """ Returns the position vector of this Point with respect to another Point/CoordSys3D. Parameters ========== other : Point/CoordSys3D If other is a Point, the position of this Point wrt it is returned. If its an instance of CoordSyRect, the position wrt its origin is returned. Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> p1 = N.origin.locate_new('p1', 10 * N.i) >>> N.origin.position_wrt(p1) (-10)*N.i """ if (not isinstance(other, Point) and not isinstance(other, CoordSys3D)): raise TypeError(str(other) + "is not a Point or CoordSys3D") if isinstance(other, CoordSys3D): other = other.origin # Handle special cases if other == self: return Vector.zero elif other == self._parent: return self._pos elif other._parent == self: return -1 * other._pos # Else, use point tree to calculate position rootindex, path = _path(self, other) result = Vector.zero i = -1 for i in range(rootindex): result += path[i]._pos i += 2 while i < len(path): result -= path[i]._pos i += 1 return result def locate_new(self, name, position): """ Returns a new Point located at the given position wrt this Point. Thus, the position vector of the new Point wrt this one will be equal to the given 'position' parameter. Parameters ========== name : str Name of the new point position : Vector The position vector of the new Point wrt this one Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> p1 = N.origin.locate_new('p1', 10 * N.i) >>> p1.position_wrt(N.origin) 10*N.i """ return Point(name, position, self) def express_coordinates(self, coordinate_system): """ Returns the Cartesian/rectangular coordinates of this point wrt the origin of the given CoordSys3D instance. Parameters ========== coordinate_system : CoordSys3D The coordinate system to express the coordinates of this Point in. Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> p1 = N.origin.locate_new('p1', 10 * N.i) >>> p2 = p1.locate_new('p2', 5 * N.j) >>> p2.express_coordinates(N) (10, 5, 0) """ # Determine the position vector pos_vect = self.position_wrt(coordinate_system.origin) # Express it in the given coordinate system return tuple(pos_vect.to_matrix(coordinate_system)) def _sympystr(self, printer): return self._name sympy-sympy-1.9/sympy/vector/scalar.py000066400000000000000000000037531412543434000202350ustar00rootroot00000000000000from sympy.core import AtomicExpr, Symbol, S from sympy.core.sympify import _sympify from sympy.printing.pretty.stringpict import prettyForm from sympy.printing.precedence import PRECEDENCE class BaseScalar(AtomicExpr): """ A coordinate symbol/base scalar. Ideally, users should not instantiate this class. Unicode pretty forms in Python 2 should use the `u` prefix. """ def __new__(cls, index, system, pretty_str=None, latex_str=None): from sympy.vector.coordsysrect import CoordSys3D if pretty_str is None: pretty_str = "x{}".format(index) elif isinstance(pretty_str, Symbol): pretty_str = pretty_str.name if latex_str is None: latex_str = "x_{}".format(index) elif isinstance(latex_str, Symbol): latex_str = latex_str.name index = _sympify(index) system = _sympify(system) obj = super().__new__(cls, index, system) if not isinstance(system, CoordSys3D): raise TypeError("system should be a CoordSys3D") if index not in range(0, 3): raise ValueError("Invalid index specified.") # The _id is used for equating purposes, and for hashing obj._id = (index, system) obj._name = obj.name = system._name + '.' + system._variable_names[index] obj._pretty_form = '' + pretty_str obj._latex_form = latex_str obj._system = system return obj is_commutative = True is_symbol = True @property def free_symbols(self): return {self} _diff_wrt = True def _eval_derivative(self, s): if self == s: return S.One return S.Zero def _latex(self, printer=None): return self._latex_form def _pretty(self, printer=None): return prettyForm(self._pretty_form) precedence = PRECEDENCE['Atom'] @property def system(self): return self._system def _sympystr(self, printer): return self._name sympy-sympy-1.9/sympy/vector/tests/000077500000000000000000000000001412543434000175505ustar00rootroot00000000000000sympy-sympy-1.9/sympy/vector/tests/__init__.py000066400000000000000000000000001412543434000216470ustar00rootroot00000000000000sympy-sympy-1.9/sympy/vector/tests/test_coordsysrect.py000066400000000000000000000457421412543434000237200ustar00rootroot00000000000000from sympy.testing.pytest import raises, warns_deprecated_sympy from sympy.vector.coordsysrect import CoordSys3D, CoordSysCartesian from sympy.vector.scalar import BaseScalar from sympy import sin, sinh, cos, cosh, sqrt, pi, ImmutableMatrix as Matrix, \ symbols, simplify, zeros, expand, acos, atan2 from sympy.vector.functions import express from sympy.vector.point import Point from sympy.vector.vector import Vector from sympy.vector.orienters import (AxisOrienter, BodyOrienter, SpaceOrienter, QuaternionOrienter) x, y, z = symbols('x y z') a, b, c, q = symbols('a b c q') q1, q2, q3, q4 = symbols('q1 q2 q3 q4') def test_func_args(): A = CoordSys3D('A') assert A.x.func(*A.x.args) == A.x expr = 3*A.x + 4*A.y assert expr.func(*expr.args) == expr assert A.i.func(*A.i.args) == A.i v = A.x*A.i + A.y*A.j + A.z*A.k assert v.func(*v.args) == v assert A.origin.func(*A.origin.args) == A.origin def test_coordsyscartesian_equivalence(): A = CoordSys3D('A') A1 = CoordSys3D('A') assert A1 == A B = CoordSys3D('B') assert A != B def test_orienters(): A = CoordSys3D('A') axis_orienter = AxisOrienter(a, A.k) body_orienter = BodyOrienter(a, b, c, '123') space_orienter = SpaceOrienter(a, b, c, '123') q_orienter = QuaternionOrienter(q1, q2, q3, q4) assert axis_orienter.rotation_matrix(A) == Matrix([ [ cos(a), sin(a), 0], [-sin(a), cos(a), 0], [ 0, 0, 1]]) assert body_orienter.rotation_matrix() == Matrix([ [ cos(b)*cos(c), sin(a)*sin(b)*cos(c) + sin(c)*cos(a), sin(a)*sin(c) - sin(b)*cos(a)*cos(c)], [-sin(c)*cos(b), -sin(a)*sin(b)*sin(c) + cos(a)*cos(c), sin(a)*cos(c) + sin(b)*sin(c)*cos(a)], [ sin(b), -sin(a)*cos(b), cos(a)*cos(b)]]) assert space_orienter.rotation_matrix() == Matrix([ [cos(b)*cos(c), sin(c)*cos(b), -sin(b)], [sin(a)*sin(b)*cos(c) - sin(c)*cos(a), sin(a)*sin(b)*sin(c) + cos(a)*cos(c), sin(a)*cos(b)], [sin(a)*sin(c) + sin(b)*cos(a)*cos(c), -sin(a)*cos(c) + sin(b)*sin(c)*cos(a), cos(a)*cos(b)]]) assert q_orienter.rotation_matrix() == Matrix([ [q1**2 + q2**2 - q3**2 - q4**2, 2*q1*q4 + 2*q2*q3, -2*q1*q3 + 2*q2*q4], [-2*q1*q4 + 2*q2*q3, q1**2 - q2**2 + q3**2 - q4**2, 2*q1*q2 + 2*q3*q4], [2*q1*q3 + 2*q2*q4, -2*q1*q2 + 2*q3*q4, q1**2 - q2**2 - q3**2 + q4**2]]) def test_coordinate_vars(): """ Tests the coordinate variables functionality with respect to reorientation of coordinate systems. """ A = CoordSys3D('A') # Note that the name given on the lhs is different from A.x._name assert BaseScalar(0, A, 'A_x', r'\mathbf{{x}_{A}}') == A.x assert BaseScalar(1, A, 'A_y', r'\mathbf{{y}_{A}}') == A.y assert BaseScalar(2, A, 'A_z', r'\mathbf{{z}_{A}}') == A.z assert BaseScalar(0, A, 'A_x', r'\mathbf{{x}_{A}}').__hash__() == A.x.__hash__() assert isinstance(A.x, BaseScalar) and \ isinstance(A.y, BaseScalar) and \ isinstance(A.z, BaseScalar) assert A.x*A.y == A.y*A.x assert A.scalar_map(A) == {A.x: A.x, A.y: A.y, A.z: A.z} assert A.x.system == A assert A.x.diff(A.x) == 1 B = A.orient_new_axis('B', q, A.k) assert B.scalar_map(A) == {B.z: A.z, B.y: -A.x*sin(q) + A.y*cos(q), B.x: A.x*cos(q) + A.y*sin(q)} assert A.scalar_map(B) == {A.x: B.x*cos(q) - B.y*sin(q), A.y: B.x*sin(q) + B.y*cos(q), A.z: B.z} assert express(B.x, A, variables=True) == A.x*cos(q) + A.y*sin(q) assert express(B.y, A, variables=True) == -A.x*sin(q) + A.y*cos(q) assert express(B.z, A, variables=True) == A.z assert expand(express(B.x*B.y*B.z, A, variables=True)) == \ expand(A.z*(-A.x*sin(q) + A.y*cos(q))*(A.x*cos(q) + A.y*sin(q))) assert express(B.x*B.i + B.y*B.j + B.z*B.k, A) == \ (B.x*cos(q) - B.y*sin(q))*A.i + (B.x*sin(q) + \ B.y*cos(q))*A.j + B.z*A.k assert simplify(express(B.x*B.i + B.y*B.j + B.z*B.k, A, \ variables=True)) == \ A.x*A.i + A.y*A.j + A.z*A.k assert express(A.x*A.i + A.y*A.j + A.z*A.k, B) == \ (A.x*cos(q) + A.y*sin(q))*B.i + \ (-A.x*sin(q) + A.y*cos(q))*B.j + A.z*B.k assert simplify(express(A.x*A.i + A.y*A.j + A.z*A.k, B, \ variables=True)) == \ B.x*B.i + B.y*B.j + B.z*B.k N = B.orient_new_axis('N', -q, B.k) assert N.scalar_map(A) == \ {N.x: A.x, N.z: A.z, N.y: A.y} C = A.orient_new_axis('C', q, A.i + A.j + A.k) mapping = A.scalar_map(C) assert mapping[A.x].equals(C.x*(2*cos(q) + 1)/3 + C.y*(-2*sin(q + pi/6) + 1)/3 + C.z*(-2*cos(q + pi/3) + 1)/3) assert mapping[A.y].equals(C.x*(-2*cos(q + pi/3) + 1)/3 + C.y*(2*cos(q) + 1)/3 + C.z*(-2*sin(q + pi/6) + 1)/3) assert mapping[A.z].equals(C.x*(-2*sin(q + pi/6) + 1)/3 + C.y*(-2*cos(q + pi/3) + 1)/3 + C.z*(2*cos(q) + 1)/3) D = A.locate_new('D', a*A.i + b*A.j + c*A.k) assert D.scalar_map(A) == {D.z: A.z - c, D.x: A.x - a, D.y: A.y - b} E = A.orient_new_axis('E', a, A.k, a*A.i + b*A.j + c*A.k) assert A.scalar_map(E) == {A.z: E.z + c, A.x: E.x*cos(a) - E.y*sin(a) + a, A.y: E.x*sin(a) + E.y*cos(a) + b} assert E.scalar_map(A) == {E.x: (A.x - a)*cos(a) + (A.y - b)*sin(a), E.y: (-A.x + a)*sin(a) + (A.y - b)*cos(a), E.z: A.z - c} F = A.locate_new('F', Vector.zero) assert A.scalar_map(F) == {A.z: F.z, A.x: F.x, A.y: F.y} def test_rotation_matrix(): N = CoordSys3D('N') A = N.orient_new_axis('A', q1, N.k) B = A.orient_new_axis('B', q2, A.i) C = B.orient_new_axis('C', q3, B.j) D = N.orient_new_axis('D', q4, N.j) E = N.orient_new_space('E', q1, q2, q3, '123') F = N.orient_new_quaternion('F', q1, q2, q3, q4) G = N.orient_new_body('G', q1, q2, q3, '123') assert N.rotation_matrix(C) == Matrix([ [- sin(q1) * sin(q2) * sin(q3) + cos(q1) * cos(q3), - sin(q1) * cos(q2), sin(q1) * sin(q2) * cos(q3) + sin(q3) * cos(q1)], \ [sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), \ cos(q1) * cos(q2), sin(q1) * sin(q3) - sin(q2) * cos(q1) * \ cos(q3)], [- sin(q3) * cos(q2), sin(q2), cos(q2) * cos(q3)]]) test_mat = D.rotation_matrix(C) - Matrix( [[cos(q1) * cos(q3) * cos(q4) - sin(q3) * (- sin(q4) * cos(q2) + sin(q1) * sin(q2) * cos(q4)), - sin(q2) * sin(q4) - sin(q1) * cos(q2) * cos(q4), sin(q3) * cos(q1) * cos(q4) + cos(q3) * \ (- sin(q4) * cos(q2) + sin(q1) * sin(q2) * cos(q4))], \ [sin(q1) * cos(q3) + sin(q2) * sin(q3) * cos(q1), cos(q1) * \ cos(q2), sin(q1) * sin(q3) - sin(q2) * cos(q1) * cos(q3)], \ [sin(q4) * cos(q1) * cos(q3) - sin(q3) * (cos(q2) * cos(q4) + \ sin(q1) * sin(q2) * \ sin(q4)), sin(q2) * cos(q4) - sin(q1) * sin(q4) * cos(q2), sin(q3) * \ sin(q4) * cos(q1) + cos(q3) * (cos(q2) * cos(q4) + \ sin(q1) * sin(q2) * sin(q4))]]) assert test_mat.expand() == zeros(3, 3) assert E.rotation_matrix(N) == Matrix( [[cos(q2)*cos(q3), sin(q3)*cos(q2), -sin(q2)], [sin(q1)*sin(q2)*cos(q3) - sin(q3)*cos(q1), \ sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q2)], \ [sin(q1)*sin(q3) + sin(q2)*cos(q1)*cos(q3), - \ sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1), cos(q1)*cos(q2)]]) assert F.rotation_matrix(N) == Matrix([[ q1**2 + q2**2 - q3**2 - q4**2, 2*q1*q4 + 2*q2*q3, -2*q1*q3 + 2*q2*q4],[ -2*q1*q4 + 2*q2*q3, q1**2 - q2**2 + q3**2 - q4**2, 2*q1*q2 + 2*q3*q4], [2*q1*q3 + 2*q2*q4, -2*q1*q2 + 2*q3*q4, q1**2 - q2**2 - q3**2 + q4**2]]) assert G.rotation_matrix(N) == Matrix([[ cos(q2)*cos(q3), sin(q1)*sin(q2)*cos(q3) + sin(q3)*cos(q1), sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3)], [ -sin(q3)*cos(q2), -sin(q1)*sin(q2)*sin(q3) + cos(q1)*cos(q3), sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1)],[ sin(q2), -sin(q1)*cos(q2), cos(q1)*cos(q2)]]) def test_vector_with_orientation(): """ Tests the effects of orientation of coordinate systems on basic vector operations. """ N = CoordSys3D('N') A = N.orient_new_axis('A', q1, N.k) B = A.orient_new_axis('B', q2, A.i) C = B.orient_new_axis('C', q3, B.j) # Test to_matrix v1 = a*N.i + b*N.j + c*N.k assert v1.to_matrix(A) == Matrix([[ a*cos(q1) + b*sin(q1)], [-a*sin(q1) + b*cos(q1)], [ c]]) # Test dot assert N.i.dot(A.i) == cos(q1) assert N.i.dot(A.j) == -sin(q1) assert N.i.dot(A.k) == 0 assert N.j.dot(A.i) == sin(q1) assert N.j.dot(A.j) == cos(q1) assert N.j.dot(A.k) == 0 assert N.k.dot(A.i) == 0 assert N.k.dot(A.j) == 0 assert N.k.dot(A.k) == 1 assert N.i.dot(A.i + A.j) == -sin(q1) + cos(q1) == \ (A.i + A.j).dot(N.i) assert A.i.dot(C.i) == cos(q3) assert A.i.dot(C.j) == 0 assert A.i.dot(C.k) == sin(q3) assert A.j.dot(C.i) == sin(q2)*sin(q3) assert A.j.dot(C.j) == cos(q2) assert A.j.dot(C.k) == -sin(q2)*cos(q3) assert A.k.dot(C.i) == -cos(q2)*sin(q3) assert A.k.dot(C.j) == sin(q2) assert A.k.dot(C.k) == cos(q2)*cos(q3) # Test cross assert N.i.cross(A.i) == sin(q1)*A.k assert N.i.cross(A.j) == cos(q1)*A.k assert N.i.cross(A.k) == -sin(q1)*A.i - cos(q1)*A.j assert N.j.cross(A.i) == -cos(q1)*A.k assert N.j.cross(A.j) == sin(q1)*A.k assert N.j.cross(A.k) == cos(q1)*A.i - sin(q1)*A.j assert N.k.cross(A.i) == A.j assert N.k.cross(A.j) == -A.i assert N.k.cross(A.k) == Vector.zero assert N.i.cross(A.i) == sin(q1)*A.k assert N.i.cross(A.j) == cos(q1)*A.k assert N.i.cross(A.i + A.j) == sin(q1)*A.k + cos(q1)*A.k assert (A.i + A.j).cross(N.i) == (-sin(q1) - cos(q1))*N.k assert A.i.cross(C.i) == sin(q3)*C.j assert A.i.cross(C.j) == -sin(q3)*C.i + cos(q3)*C.k assert A.i.cross(C.k) == -cos(q3)*C.j assert C.i.cross(A.i) == (-sin(q3)*cos(q2))*A.j + \ (-sin(q2)*sin(q3))*A.k assert C.j.cross(A.i) == (sin(q2))*A.j + (-cos(q2))*A.k assert express(C.k.cross(A.i), C).trigsimp() == cos(q3)*C.j def test_orient_new_methods(): N = CoordSys3D('N') orienter1 = AxisOrienter(q4, N.j) orienter2 = SpaceOrienter(q1, q2, q3, '123') orienter3 = QuaternionOrienter(q1, q2, q3, q4) orienter4 = BodyOrienter(q1, q2, q3, '123') D = N.orient_new('D', (orienter1, )) E = N.orient_new('E', (orienter2, )) F = N.orient_new('F', (orienter3, )) G = N.orient_new('G', (orienter4, )) assert D == N.orient_new_axis('D', q4, N.j) assert E == N.orient_new_space('E', q1, q2, q3, '123') assert F == N.orient_new_quaternion('F', q1, q2, q3, q4) assert G == N.orient_new_body('G', q1, q2, q3, '123') def test_locatenew_point(): """ Tests Point class, and locate_new method in CoordSysCartesian. """ A = CoordSys3D('A') assert isinstance(A.origin, Point) v = a*A.i + b*A.j + c*A.k C = A.locate_new('C', v) assert C.origin.position_wrt(A) == \ C.position_wrt(A) == \ C.origin.position_wrt(A.origin) == v assert A.origin.position_wrt(C) == \ A.position_wrt(C) == \ A.origin.position_wrt(C.origin) == -v assert A.origin.express_coordinates(C) == (-a, -b, -c) p = A.origin.locate_new('p', -v) assert p.express_coordinates(A) == (-a, -b, -c) assert p.position_wrt(C.origin) == p.position_wrt(C) == \ -2 * v p1 = p.locate_new('p1', 2*v) assert p1.position_wrt(C.origin) == Vector.zero assert p1.express_coordinates(C) == (0, 0, 0) p2 = p.locate_new('p2', A.i) assert p1.position_wrt(p2) == 2*v - A.i assert p2.express_coordinates(C) == (-2*a + 1, -2*b, -2*c) def test_create_new(): a = CoordSys3D('a') c = a.create_new('c', transformation='spherical') assert c._parent == a assert c.transformation_to_parent() == \ (c.r*sin(c.theta)*cos(c.phi), c.r*sin(c.theta)*sin(c.phi), c.r*cos(c.theta)) assert c.transformation_from_parent() == \ (sqrt(a.x**2 + a.y**2 + a.z**2), acos(a.z/sqrt(a.x**2 + a.y**2 + a.z**2)), atan2(a.y, a.x)) def test_evalf(): A = CoordSys3D('A') v = 3*A.i + 4*A.j + a*A.k assert v.n() == v.evalf() assert v.evalf(subs={a:1}) == v.subs(a, 1).evalf() def test_lame_coefficients(): a = CoordSys3D('a', 'spherical') assert a.lame_coefficients() == (1, a.r, sin(a.theta)*a.r) a = CoordSys3D('a') assert a.lame_coefficients() == (1, 1, 1) a = CoordSys3D('a', 'cartesian') assert a.lame_coefficients() == (1, 1, 1) a = CoordSys3D('a', 'cylindrical') assert a.lame_coefficients() == (1, a.r, 1) def test_transformation_equations(): x, y, z = symbols('x y z') # Str a = CoordSys3D('a', transformation='spherical', variable_names=["r", "theta", "phi"]) r, theta, phi = a.base_scalars() assert r == a.r assert theta == a.theta assert phi == a.phi raises(AttributeError, lambda: a.x) raises(AttributeError, lambda: a.y) raises(AttributeError, lambda: a.z) assert a.transformation_to_parent() == ( r*sin(theta)*cos(phi), r*sin(theta)*sin(phi), r*cos(theta) ) assert a.lame_coefficients() == (1, r, r*sin(theta)) assert a.transformation_from_parent_function()(x, y, z) == ( sqrt(x ** 2 + y ** 2 + z ** 2), acos((z) / sqrt(x**2 + y**2 + z**2)), atan2(y, x) ) a = CoordSys3D('a', transformation='cylindrical', variable_names=["r", "theta", "z"]) r, theta, z = a.base_scalars() assert a.transformation_to_parent() == ( r*cos(theta), r*sin(theta), z ) assert a.lame_coefficients() == (1, a.r, 1) assert a.transformation_from_parent_function()(x, y, z) == (sqrt(x**2 + y**2), atan2(y, x), z) a = CoordSys3D('a', 'cartesian') assert a.transformation_to_parent() == (a.x, a.y, a.z) assert a.lame_coefficients() == (1, 1, 1) assert a.transformation_from_parent_function()(x, y, z) == (x, y, z) # Variables and expressions # Cartesian with equation tuple: x, y, z = symbols('x y z') a = CoordSys3D('a', ((x, y, z), (x, y, z))) a._calculate_inv_trans_equations() assert a.transformation_to_parent() == (a.x1, a.x2, a.x3) assert a.lame_coefficients() == (1, 1, 1) assert a.transformation_from_parent_function()(x, y, z) == (x, y, z) r, theta, z = symbols("r theta z") # Cylindrical with equation tuple: a = CoordSys3D('a', [(r, theta, z), (r*cos(theta), r*sin(theta), z)], variable_names=["r", "theta", "z"]) r, theta, z = a.base_scalars() assert a.transformation_to_parent() == ( r*cos(theta), r*sin(theta), z ) assert a.lame_coefficients() == ( sqrt(sin(theta)**2 + cos(theta)**2), sqrt(r**2*sin(theta)**2 + r**2*cos(theta)**2), 1 ) # ==> this should simplify to (1, r, 1), tests are too slow with `simplify`. # Definitions with `lambda`: # Cartesian with `lambda` a = CoordSys3D('a', lambda x, y, z: (x, y, z)) assert a.transformation_to_parent() == (a.x1, a.x2, a.x3) assert a.lame_coefficients() == (1, 1, 1) a._calculate_inv_trans_equations() assert a.transformation_from_parent_function()(x, y, z) == (x, y, z) # Spherical with `lambda` a = CoordSys3D('a', lambda r, theta, phi: (r*sin(theta)*cos(phi), r*sin(theta)*sin(phi), r*cos(theta)), variable_names=["r", "theta", "phi"]) r, theta, phi = a.base_scalars() assert a.transformation_to_parent() == ( r*sin(theta)*cos(phi), r*sin(phi)*sin(theta), r*cos(theta) ) assert a.lame_coefficients() == ( sqrt(sin(phi)**2*sin(theta)**2 + sin(theta)**2*cos(phi)**2 + cos(theta)**2), sqrt(r**2*sin(phi)**2*cos(theta)**2 + r**2*sin(theta)**2 + r**2*cos(phi)**2*cos(theta)**2), sqrt(r**2*sin(phi)**2*sin(theta)**2 + r**2*sin(theta)**2*cos(phi)**2) ) # ==> this should simplify to (1, r, sin(theta)*r), `simplify` is too slow. # Cylindrical with `lambda` a = CoordSys3D('a', lambda r, theta, z: (r*cos(theta), r*sin(theta), z), variable_names=["r", "theta", "z"] ) r, theta, z = a.base_scalars() assert a.transformation_to_parent() == (r*cos(theta), r*sin(theta), z) assert a.lame_coefficients() == ( sqrt(sin(theta)**2 + cos(theta)**2), sqrt(r**2*sin(theta)**2 + r**2*cos(theta)**2), 1 ) # ==> this should simplify to (1, a.x, 1) raises(TypeError, lambda: CoordSys3D('a', transformation={ x: x*sin(y)*cos(z), y:x*sin(y)*sin(z), z: x*cos(y)})) def test_check_orthogonality(): x, y, z = symbols('x y z') u,v = symbols('u, v') a = CoordSys3D('a', transformation=((x, y, z), (x*sin(y)*cos(z), x*sin(y)*sin(z), x*cos(y)))) assert a._check_orthogonality(a._transformation) is True a = CoordSys3D('a', transformation=((x, y, z), (x * cos(y), x * sin(y), z))) assert a._check_orthogonality(a._transformation) is True a = CoordSys3D('a', transformation=((u, v, z), (cosh(u) * cos(v), sinh(u) * sin(v), z))) assert a._check_orthogonality(a._transformation) is True raises(ValueError, lambda: CoordSys3D('a', transformation=((x, y, z), (x, x, z)))) raises(ValueError, lambda: CoordSys3D('a', transformation=( (x, y, z), (x*sin(y/2)*cos(z), x*sin(y)*sin(z), x*cos(y))))) def test_coordsys3d(): with warns_deprecated_sympy(): assert CoordSysCartesian("C") == CoordSys3D("C") def test_rotation_trans_equations(): a = CoordSys3D('a') from sympy import symbols q0 = symbols('q0') assert a._rotation_trans_equations(a._parent_rotation_matrix, a.base_scalars()) == (a.x, a.y, a.z) assert a._rotation_trans_equations(a._inverse_rotation_matrix(), a.base_scalars()) == (a.x, a.y, a.z) b = a.orient_new_axis('b', 0, -a.k) assert b._rotation_trans_equations(b._parent_rotation_matrix, b.base_scalars()) == (b.x, b.y, b.z) assert b._rotation_trans_equations(b._inverse_rotation_matrix(), b.base_scalars()) == (b.x, b.y, b.z) c = a.orient_new_axis('c', q0, -a.k) assert c._rotation_trans_equations(c._parent_rotation_matrix, c.base_scalars()) == \ (-sin(q0) * c.y + cos(q0) * c.x, sin(q0) * c.x + cos(q0) * c.y, c.z) assert c._rotation_trans_equations(c._inverse_rotation_matrix(), c.base_scalars()) == \ (sin(q0) * c.y + cos(q0) * c.x, -sin(q0) * c.x + cos(q0) * c.y, c.z) sympy-sympy-1.9/sympy/vector/tests/test_dyadic.py000066400000000000000000000101421412543434000224140ustar00rootroot00000000000000from sympy import sin, cos, symbols, pi, ImmutableMatrix as Matrix, \ simplify from sympy.vector import (CoordSys3D, Vector, Dyadic, DyadicAdd, DyadicMul, DyadicZero, BaseDyadic, express) A = CoordSys3D('A') def test_dyadic(): a, b = symbols('a, b') assert Dyadic.zero != 0 assert isinstance(Dyadic.zero, DyadicZero) assert BaseDyadic(A.i, A.j) != BaseDyadic(A.j, A.i) assert (BaseDyadic(Vector.zero, A.i) == BaseDyadic(A.i, Vector.zero) == Dyadic.zero) d1 = A.i | A.i d2 = A.j | A.j d3 = A.i | A.j assert isinstance(d1, BaseDyadic) d_mul = a*d1 assert isinstance(d_mul, DyadicMul) assert d_mul.base_dyadic == d1 assert d_mul.measure_number == a assert isinstance(a*d1 + b*d3, DyadicAdd) assert d1 == A.i.outer(A.i) assert d3 == A.i.outer(A.j) v1 = a*A.i - A.k v2 = A.i + b*A.j assert v1 | v2 == v1.outer(v2) == a * (A.i|A.i) + (a*b) * (A.i|A.j) +\ - (A.k|A.i) - b * (A.k|A.j) assert d1 * 0 == Dyadic.zero assert d1 != Dyadic.zero assert d1 * 2 == 2 * (A.i | A.i) assert d1 / 2. == 0.5 * d1 assert d1.dot(0 * d1) == Vector.zero assert d1 & d2 == Dyadic.zero assert d1.dot(A.i) == A.i == d1 & A.i assert d1.cross(Vector.zero) == Dyadic.zero assert d1.cross(A.i) == Dyadic.zero assert d1 ^ A.j == d1.cross(A.j) assert d1.cross(A.k) == - A.i | A.j assert d2.cross(A.i) == - A.j | A.k == d2 ^ A.i assert A.i ^ d1 == Dyadic.zero assert A.j.cross(d1) == - A.k | A.i == A.j ^ d1 assert Vector.zero.cross(d1) == Dyadic.zero assert A.k ^ d1 == A.j | A.i assert A.i.dot(d1) == A.i & d1 == A.i assert A.j.dot(d1) == Vector.zero assert Vector.zero.dot(d1) == Vector.zero assert A.j & d2 == A.j assert d1.dot(d3) == d1 & d3 == A.i | A.j == d3 assert d3 & d1 == Dyadic.zero q = symbols('q') B = A.orient_new_axis('B', q, A.k) assert express(d1, B) == express(d1, B, B) expr1 = ((cos(q)**2) * (B.i | B.i) + (-sin(q) * cos(q)) * (B.i | B.j) + (-sin(q) * cos(q)) * (B.j | B.i) + (sin(q)**2) * (B.j | B.j)) assert (express(d1, B) - expr1).simplify() == Dyadic.zero expr2 = (cos(q)) * (B.i | A.i) + (-sin(q)) * (B.j | A.i) assert (express(d1, B, A) - expr2).simplify() == Dyadic.zero expr3 = (cos(q)) * (A.i | B.i) + (-sin(q)) * (A.i | B.j) assert (express(d1, A, B) - expr3).simplify() == Dyadic.zero assert d1.to_matrix(A) == Matrix([[1, 0, 0], [0, 0, 0], [0, 0, 0]]) assert d1.to_matrix(A, B) == Matrix([[cos(q), -sin(q), 0], [0, 0, 0], [0, 0, 0]]) assert d3.to_matrix(A) == Matrix([[0, 1, 0], [0, 0, 0], [0, 0, 0]]) a, b, c, d, e, f = symbols('a, b, c, d, e, f') v1 = a * A.i + b * A.j + c * A.k v2 = d * A.i + e * A.j + f * A.k d4 = v1.outer(v2) assert d4.to_matrix(A) == Matrix([[a * d, a * e, a * f], [b * d, b * e, b * f], [c * d, c * e, c * f]]) d5 = v1.outer(v1) C = A.orient_new_axis('C', q, A.i) for expected, actual in zip(C.rotation_matrix(A) * d5.to_matrix(A) * \ C.rotation_matrix(A).T, d5.to_matrix(C)): assert (expected - actual).simplify() == 0 def test_dyadic_simplify(): x, y, z, k, n, m, w, f, s, A = symbols('x, y, z, k, n, m, w, f, s, A') N = CoordSys3D('N') dy = N.i | N.i test1 = (1 / x + 1 / y) * dy assert (N.i & test1 & N.i) != (x + y) / (x * y) test1 = test1.simplify() assert test1.simplify() == simplify(test1) assert (N.i & test1 & N.i) == (x + y) / (x * y) test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * dy test2 = test2.simplify() assert (N.i & test2 & N.i) == (A**2 * s**4 / (4 * pi * k * m**3)) test3 = ((4 + 4 * x - 2 * (2 + 2 * x)) / (2 + 2 * x)) * dy test3 = test3.simplify() assert (N.i & test3 & N.i) == 0 test4 = ((-4 * x * y**2 - 2 * y**3 - 2 * x**2 * y) / (x + y)**2) * dy test4 = test4.simplify() assert (N.i & test4 & N.i) == -2 * y sympy-sympy-1.9/sympy/vector/tests/test_field_functions.py000066400000000000000000000333521412543434000243420ustar00rootroot00000000000000from sympy.core.function import Derivative from sympy.vector.vector import Vector from sympy.vector.coordsysrect import CoordSys3D from sympy.simplify import simplify from sympy.core.symbol import symbols from sympy.core import S from sympy import sin, cos from sympy.vector.vector import Dot from sympy.vector.operators import curl, divergence, gradient, Gradient, Divergence, Cross from sympy.vector.deloperator import Del from sympy.vector.functions import (is_conservative, is_solenoidal, scalar_potential, directional_derivative, laplacian, scalar_potential_difference) from sympy.testing.pytest import raises C = CoordSys3D('C') i, j, k = C.base_vectors() x, y, z = C.base_scalars() delop = Del() a, b, c, q = symbols('a b c q') def test_del_operator(): # Tests for curl assert delop ^ Vector.zero == Vector.zero assert ((delop ^ Vector.zero).doit() == Vector.zero == curl(Vector.zero)) assert delop.cross(Vector.zero) == delop ^ Vector.zero assert (delop ^ i).doit() == Vector.zero assert delop.cross(2*y**2*j, doit=True) == Vector.zero assert delop.cross(2*y**2*j) == delop ^ 2*y**2*j v = x*y*z * (i + j + k) assert ((delop ^ v).doit() == (-x*y + x*z)*i + (x*y - y*z)*j + (-x*z + y*z)*k == curl(v)) assert delop ^ v == delop.cross(v) assert (delop.cross(2*x**2*j) == (Derivative(0, C.y) - Derivative(2*C.x**2, C.z))*C.i + (-Derivative(0, C.x) + Derivative(0, C.z))*C.j + (-Derivative(0, C.y) + Derivative(2*C.x**2, C.x))*C.k) assert (delop.cross(2*x**2*j, doit=True) == 4*x*k == curl(2*x**2*j)) #Tests for divergence assert delop & Vector.zero is S.Zero == divergence(Vector.zero) assert (delop & Vector.zero).doit() is S.Zero assert delop.dot(Vector.zero) == delop & Vector.zero assert (delop & i).doit() is S.Zero assert (delop & x**2*i).doit() == 2*x == divergence(x**2*i) assert (delop.dot(v, doit=True) == x*y + y*z + z*x == divergence(v)) assert delop & v == delop.dot(v) assert delop.dot(1/(x*y*z) * (i + j + k), doit=True) == \ - 1 / (x*y*z**2) - 1 / (x*y**2*z) - 1 / (x**2*y*z) v = x*i + y*j + z*k assert (delop & v == Derivative(C.x, C.x) + Derivative(C.y, C.y) + Derivative(C.z, C.z)) assert delop.dot(v, doit=True) == 3 == divergence(v) assert delop & v == delop.dot(v) assert simplify((delop & v).doit()) == 3 #Tests for gradient assert (delop.gradient(0, doit=True) == Vector.zero == gradient(0)) assert delop.gradient(0) == delop(0) assert (delop(S.Zero)).doit() == Vector.zero assert (delop(x) == (Derivative(C.x, C.x))*C.i + (Derivative(C.x, C.y))*C.j + (Derivative(C.x, C.z))*C.k) assert (delop(x)).doit() == i == gradient(x) assert (delop(x*y*z) == (Derivative(C.x*C.y*C.z, C.x))*C.i + (Derivative(C.x*C.y*C.z, C.y))*C.j + (Derivative(C.x*C.y*C.z, C.z))*C.k) assert (delop.gradient(x*y*z, doit=True) == y*z*i + z*x*j + x*y*k == gradient(x*y*z)) assert delop(x*y*z) == delop.gradient(x*y*z) assert (delop(2*x**2)).doit() == 4*x*i assert ((delop(a*sin(y) / x)).doit() == -a*sin(y)/x**2 * i + a*cos(y)/x * j) #Tests for directional derivative assert (Vector.zero & delop)(a) is S.Zero assert ((Vector.zero & delop)(a)).doit() is S.Zero assert ((v & delop)(Vector.zero)).doit() == Vector.zero assert ((v & delop)(S.Zero)).doit() is S.Zero assert ((i & delop)(x)).doit() == 1 assert ((j & delop)(y)).doit() == 1 assert ((k & delop)(z)).doit() == 1 assert ((i & delop)(x*y*z)).doit() == y*z assert ((v & delop)(x)).doit() == x assert ((v & delop)(x*y*z)).doit() == 3*x*y*z assert (v & delop)(x + y + z) == C.x + C.y + C.z assert ((v & delop)(x + y + z)).doit() == x + y + z assert ((v & delop)(v)).doit() == v assert ((i & delop)(v)).doit() == i assert ((j & delop)(v)).doit() == j assert ((k & delop)(v)).doit() == k assert ((v & delop)(Vector.zero)).doit() == Vector.zero # Tests for laplacian on scalar fields assert laplacian(x*y*z) is S.Zero assert laplacian(x**2) == S(2) assert laplacian(x**2*y**2*z**2) == \ 2*y**2*z**2 + 2*x**2*z**2 + 2*x**2*y**2 A = CoordSys3D('A', transformation="spherical", variable_names=["r", "theta", "phi"]) B = CoordSys3D('B', transformation='cylindrical', variable_names=["r", "theta", "z"]) assert laplacian(A.r + A.theta + A.phi) == 2/A.r + cos(A.theta)/(A.r**2*sin(A.theta)) assert laplacian(B.r + B.theta + B.z) == 1/B.r # Tests for laplacian on vector fields assert laplacian(x*y*z*(i + j + k)) == Vector.zero assert laplacian(x*y**2*z*(i + j + k)) == \ 2*x*z*i + 2*x*z*j + 2*x*z*k def test_product_rules(): """ Tests the six product rules defined with respect to the Del operator References ========== .. [1] https://en.wikipedia.org/wiki/Del """ #Define the scalar and vector functions f = 2*x*y*z g = x*y + y*z + z*x u = x**2*i + 4*j - y**2*z*k v = 4*i + x*y*z*k # First product rule lhs = delop(f * g, doit=True) rhs = (f * delop(g) + g * delop(f)).doit() assert simplify(lhs) == simplify(rhs) # Second product rule lhs = delop(u & v).doit() rhs = ((u ^ (delop ^ v)) + (v ^ (delop ^ u)) + \ ((u & delop)(v)) + ((v & delop)(u))).doit() assert simplify(lhs) == simplify(rhs) # Third product rule lhs = (delop & (f*v)).doit() rhs = ((f * (delop & v)) + (v & (delop(f)))).doit() assert simplify(lhs) == simplify(rhs) # Fourth product rule lhs = (delop & (u ^ v)).doit() rhs = ((v & (delop ^ u)) - (u & (delop ^ v))).doit() assert simplify(lhs) == simplify(rhs) # Fifth product rule lhs = (delop ^ (f * v)).doit() rhs = (((delop(f)) ^ v) + (f * (delop ^ v))).doit() assert simplify(lhs) == simplify(rhs) # Sixth product rule lhs = (delop ^ (u ^ v)).doit() rhs = (u * (delop & v) - v * (delop & u) + (v & delop)(u) - (u & delop)(v)).doit() assert simplify(lhs) == simplify(rhs) P = C.orient_new_axis('P', q, C.k) # type: ignore scalar_field = 2*x**2*y*z grad_field = gradient(scalar_field) vector_field = y**2*i + 3*x*j + 5*y*z*k curl_field = curl(vector_field) def test_conservative(): assert is_conservative(Vector.zero) is True assert is_conservative(i) is True assert is_conservative(2 * i + 3 * j + 4 * k) is True assert (is_conservative(y*z*i + x*z*j + x*y*k) is True) assert is_conservative(x * j) is False assert is_conservative(grad_field) is True assert is_conservative(curl_field) is False assert (is_conservative(4*x*y*z*i + 2*x**2*z*j) is False) assert is_conservative(z*P.i + P.x*k) is True def test_solenoidal(): assert is_solenoidal(Vector.zero) is True assert is_solenoidal(i) is True assert is_solenoidal(2 * i + 3 * j + 4 * k) is True assert (is_solenoidal(y*z*i + x*z*j + x*y*k) is True) assert is_solenoidal(y * j) is False assert is_solenoidal(grad_field) is False assert is_solenoidal(curl_field) is True assert is_solenoidal((-2*y + 3)*k) is True assert is_solenoidal(cos(q)*i + sin(q)*j + cos(q)*P.k) is True assert is_solenoidal(z*P.i + P.x*k) is True def test_directional_derivative(): assert directional_derivative(C.x*C.y*C.z, 3*C.i + 4*C.j + C.k) == C.x*C.y + 4*C.x*C.z + 3*C.y*C.z assert directional_derivative(5*C.x**2*C.z, 3*C.i + 4*C.j + C.k) == 5*C.x**2 + 30*C.x*C.z assert directional_derivative(5*C.x**2*C.z, 4*C.j) is S.Zero D = CoordSys3D("D", "spherical", variable_names=["r", "theta", "phi"], vector_names=["e_r", "e_theta", "e_phi"]) r, theta, phi = D.base_scalars() e_r, e_theta, e_phi = D.base_vectors() assert directional_derivative(r**2*e_r, e_r) == 2*r*e_r assert directional_derivative(5*r**2*phi, 3*e_r + 4*e_theta + e_phi) == 5*r**2 + 30*r*phi def test_scalar_potential(): assert scalar_potential(Vector.zero, C) == 0 assert scalar_potential(i, C) == x assert scalar_potential(j, C) == y assert scalar_potential(k, C) == z assert scalar_potential(y*z*i + x*z*j + x*y*k, C) == x*y*z assert scalar_potential(grad_field, C) == scalar_field assert scalar_potential(z*P.i + P.x*k, C) == x*z*cos(q) + y*z*sin(q) assert scalar_potential(z*P.i + P.x*k, P) == P.x*P.z raises(ValueError, lambda: scalar_potential(x*j, C)) def test_scalar_potential_difference(): point1 = C.origin.locate_new('P1', 1*i + 2*j + 3*k) point2 = C.origin.locate_new('P2', 4*i + 5*j + 6*k) genericpointC = C.origin.locate_new('RP', x*i + y*j + z*k) genericpointP = P.origin.locate_new('PP', P.x*P.i + P.y*P.j + P.z*P.k) assert scalar_potential_difference(S.Zero, C, point1, point2) == 0 assert (scalar_potential_difference(scalar_field, C, C.origin, genericpointC) == scalar_field) assert (scalar_potential_difference(grad_field, C, C.origin, genericpointC) == scalar_field) assert scalar_potential_difference(grad_field, C, point1, point2) == 948 assert (scalar_potential_difference(y*z*i + x*z*j + x*y*k, C, point1, genericpointC) == x*y*z - 6) potential_diff_P = (2*P.z*(P.x*sin(q) + P.y*cos(q))* (P.x*cos(q) - P.y*sin(q))**2) assert (scalar_potential_difference(grad_field, P, P.origin, genericpointP).simplify() == potential_diff_P.simplify()) def test_differential_operators_curvilinear_system(): A = CoordSys3D('A', transformation="spherical", variable_names=["r", "theta", "phi"]) B = CoordSys3D('B', transformation='cylindrical', variable_names=["r", "theta", "z"]) # Test for spherical coordinate system and gradient assert gradient(3*A.r + 4*A.theta) == 3*A.i + 4/A.r*A.j assert gradient(3*A.r*A.phi + 4*A.theta) == 3*A.phi*A.i + 4/A.r*A.j + (3/sin(A.theta))*A.k assert gradient(0*A.r + 0*A.theta+0*A.phi) == Vector.zero assert gradient(A.r*A.theta*A.phi) == A.theta*A.phi*A.i + A.phi*A.j + (A.theta/sin(A.theta))*A.k # Test for spherical coordinate system and divergence assert divergence(A.r * A.i + A.theta * A.j + A.phi * A.k) == \ (sin(A.theta)*A.r + cos(A.theta)*A.r*A.theta)/(sin(A.theta)*A.r**2) + 3 + 1/(sin(A.theta)*A.r) assert divergence(3*A.r*A.phi*A.i + A.theta*A.j + A.r*A.theta*A.phi*A.k) == \ (sin(A.theta)*A.r + cos(A.theta)*A.r*A.theta)/(sin(A.theta)*A.r**2) + 9*A.phi + A.theta/sin(A.theta) assert divergence(Vector.zero) == 0 assert divergence(0*A.i + 0*A.j + 0*A.k) == 0 # Test for spherical coordinate system and curl assert curl(A.r*A.i + A.theta*A.j + A.phi*A.k) == \ (cos(A.theta)*A.phi/(sin(A.theta)*A.r))*A.i + (-A.phi/A.r)*A.j + A.theta/A.r*A.k assert curl(A.r*A.j + A.phi*A.k) == (cos(A.theta)*A.phi/(sin(A.theta)*A.r))*A.i + (-A.phi/A.r)*A.j + 2*A.k # Test for cylindrical coordinate system and gradient assert gradient(0*B.r + 0*B.theta+0*B.z) == Vector.zero assert gradient(B.r*B.theta*B.z) == B.theta*B.z*B.i + B.z*B.j + B.r*B.theta*B.k assert gradient(3*B.r) == 3*B.i assert gradient(2*B.theta) == 2/B.r * B.j assert gradient(4*B.z) == 4*B.k # Test for cylindrical coordinate system and divergence assert divergence(B.r*B.i + B.theta*B.j + B.z*B.k) == 3 + 1/B.r assert divergence(B.r*B.j + B.z*B.k) == 1 # Test for cylindrical coordinate system and curl assert curl(B.r*B.j + B.z*B.k) == 2*B.k assert curl(3*B.i + 2/B.r*B.j + 4*B.k) == Vector.zero def test_mixed_coordinates(): # gradient a = CoordSys3D('a') b = CoordSys3D('b') c = CoordSys3D('c') assert gradient(a.x*b.y) == b.y*a.i + a.x*b.j assert gradient(3*cos(q)*a.x*b.x+a.y*(a.x+(cos(q)+b.x))) ==\ (a.y + 3*b.x*cos(q))*a.i + (a.x + b.x + cos(q))*a.j + (3*a.x*cos(q) + a.y)*b.i # Some tests need further work: # assert gradient(a.x*(cos(a.x+b.x))) == (cos(a.x + b.x))*a.i + a.x*Gradient(cos(a.x + b.x)) # assert gradient(cos(a.x + b.x)*cos(a.x + b.z)) == Gradient(cos(a.x + b.x)*cos(a.x + b.z)) assert gradient(a.x**b.y) == Gradient(a.x**b.y) # assert gradient(cos(a.x+b.y)*a.z) == None assert gradient(cos(a.x*b.y)) == Gradient(cos(a.x*b.y)) assert gradient(3*cos(q)*a.x*b.x*a.z*a.y+ b.y*b.z + cos(a.x+a.y)*b.z) == \ (3*a.y*a.z*b.x*cos(q) - b.z*sin(a.x + a.y))*a.i + \ (3*a.x*a.z*b.x*cos(q) - b.z*sin(a.x + a.y))*a.j + (3*a.x*a.y*b.x*cos(q))*a.k + \ (3*a.x*a.y*a.z*cos(q))*b.i + b.z*b.j + (b.y + cos(a.x + a.y))*b.k # divergence assert divergence(a.i*a.x+a.j*a.y+a.z*a.k + b.i*b.x+b.j*b.y+b.z*b.k + c.i*c.x+c.j*c.y+c.z*c.k) == S(9) # assert divergence(3*a.i*a.x*cos(a.x+b.z) + a.j*b.x*c.z) == None assert divergence(3*a.i*a.x*a.z + b.j*b.x*c.z + 3*a.j*a.z*a.y) == \ 6*a.z + b.x*Dot(b.j, c.k) assert divergence(3*cos(q)*a.x*b.x*b.i*c.x) == \ 3*a.x*b.x*cos(q)*Dot(b.i, c.i) + 3*a.x*c.x*cos(q) + 3*b.x*c.x*cos(q)*Dot(b.i, a.i) assert divergence(a.x*b.x*c.x*Cross(a.x*a.i, a.y*b.j)) ==\ a.x*b.x*c.x*Divergence(Cross(a.x*a.i, a.y*b.j)) + \ b.x*c.x*Dot(Cross(a.x*a.i, a.y*b.j), a.i) + \ a.x*c.x*Dot(Cross(a.x*a.i, a.y*b.j), b.i) + \ a.x*b.x*Dot(Cross(a.x*a.i, a.y*b.j), c.i) assert divergence(a.x*b.x*c.x*(a.x*a.i + b.x*b.i)) == \ 4*a.x*b.x*c.x +\ a.x**2*c.x*Dot(a.i, b.i) +\ a.x**2*b.x*Dot(a.i, c.i) +\ b.x**2*c.x*Dot(b.i, a.i) +\ a.x*b.x**2*Dot(b.i, c.i) sympy-sympy-1.9/sympy/vector/tests/test_functions.py000066400000000000000000000172251412543434000232000ustar00rootroot00000000000000from sympy.vector.vector import Vector from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.functions import express, matrix_to_vector, orthogonalize from sympy import symbols, S, sqrt, sin, cos, ImmutableMatrix as Matrix, Rational from sympy.testing.pytest import raises N = CoordSys3D('N') q1, q2, q3, q4, q5 = symbols('q1 q2 q3 q4 q5') A = N.orient_new_axis('A', q1, N.k) # type: ignore B = A.orient_new_axis('B', q2, A.i) C = B.orient_new_axis('C', q3, B.j) def test_express(): assert express(Vector.zero, N) == Vector.zero assert express(S.Zero, N) is S.Zero assert express(A.i, C) == cos(q3)*C.i + sin(q3)*C.k assert express(A.j, C) == sin(q2)*sin(q3)*C.i + cos(q2)*C.j - \ sin(q2)*cos(q3)*C.k assert express(A.k, C) == -sin(q3)*cos(q2)*C.i + sin(q2)*C.j + \ cos(q2)*cos(q3)*C.k assert express(A.i, N) == cos(q1)*N.i + sin(q1)*N.j assert express(A.j, N) == -sin(q1)*N.i + cos(q1)*N.j assert express(A.k, N) == N.k assert express(A.i, A) == A.i assert express(A.j, A) == A.j assert express(A.k, A) == A.k assert express(A.i, B) == B.i assert express(A.j, B) == cos(q2)*B.j - sin(q2)*B.k assert express(A.k, B) == sin(q2)*B.j + cos(q2)*B.k assert express(A.i, C) == cos(q3)*C.i + sin(q3)*C.k assert express(A.j, C) == sin(q2)*sin(q3)*C.i + cos(q2)*C.j - \ sin(q2)*cos(q3)*C.k assert express(A.k, C) == -sin(q3)*cos(q2)*C.i + sin(q2)*C.j + \ cos(q2)*cos(q3)*C.k # Check to make sure UnitVectors get converted properly assert express(N.i, N) == N.i assert express(N.j, N) == N.j assert express(N.k, N) == N.k assert express(N.i, A) == (cos(q1)*A.i - sin(q1)*A.j) assert express(N.j, A) == (sin(q1)*A.i + cos(q1)*A.j) assert express(N.k, A) == A.k assert express(N.i, B) == (cos(q1)*B.i - sin(q1)*cos(q2)*B.j + sin(q1)*sin(q2)*B.k) assert express(N.j, B) == (sin(q1)*B.i + cos(q1)*cos(q2)*B.j - sin(q2)*cos(q1)*B.k) assert express(N.k, B) == (sin(q2)*B.j + cos(q2)*B.k) assert express(N.i, C) == ( (cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*C.i - sin(q1)*cos(q2)*C.j + (sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*C.k) assert express(N.j, C) == ( (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*C.i + cos(q1)*cos(q2)*C.j + (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*C.k) assert express(N.k, C) == (-sin(q3)*cos(q2)*C.i + sin(q2)*C.j + cos(q2)*cos(q3)*C.k) assert express(A.i, N) == (cos(q1)*N.i + sin(q1)*N.j) assert express(A.j, N) == (-sin(q1)*N.i + cos(q1)*N.j) assert express(A.k, N) == N.k assert express(A.i, A) == A.i assert express(A.j, A) == A.j assert express(A.k, A) == A.k assert express(A.i, B) == B.i assert express(A.j, B) == (cos(q2)*B.j - sin(q2)*B.k) assert express(A.k, B) == (sin(q2)*B.j + cos(q2)*B.k) assert express(A.i, C) == (cos(q3)*C.i + sin(q3)*C.k) assert express(A.j, C) == (sin(q2)*sin(q3)*C.i + cos(q2)*C.j - sin(q2)*cos(q3)*C.k) assert express(A.k, C) == (-sin(q3)*cos(q2)*C.i + sin(q2)*C.j + cos(q2)*cos(q3)*C.k) assert express(B.i, N) == (cos(q1)*N.i + sin(q1)*N.j) assert express(B.j, N) == (-sin(q1)*cos(q2)*N.i + cos(q1)*cos(q2)*N.j + sin(q2)*N.k) assert express(B.k, N) == (sin(q1)*sin(q2)*N.i - sin(q2)*cos(q1)*N.j + cos(q2)*N.k) assert express(B.i, A) == A.i assert express(B.j, A) == (cos(q2)*A.j + sin(q2)*A.k) assert express(B.k, A) == (-sin(q2)*A.j + cos(q2)*A.k) assert express(B.i, B) == B.i assert express(B.j, B) == B.j assert express(B.k, B) == B.k assert express(B.i, C) == (cos(q3)*C.i + sin(q3)*C.k) assert express(B.j, C) == C.j assert express(B.k, C) == (-sin(q3)*C.i + cos(q3)*C.k) assert express(C.i, N) == ( (cos(q1)*cos(q3) - sin(q1)*sin(q2)*sin(q3))*N.i + (sin(q1)*cos(q3) + sin(q2)*sin(q3)*cos(q1))*N.j - sin(q3)*cos(q2)*N.k) assert express(C.j, N) == ( -sin(q1)*cos(q2)*N.i + cos(q1)*cos(q2)*N.j + sin(q2)*N.k) assert express(C.k, N) == ( (sin(q3)*cos(q1) + sin(q1)*sin(q2)*cos(q3))*N.i + (sin(q1)*sin(q3) - sin(q2)*cos(q1)*cos(q3))*N.j + cos(q2)*cos(q3)*N.k) assert express(C.i, A) == (cos(q3)*A.i + sin(q2)*sin(q3)*A.j - sin(q3)*cos(q2)*A.k) assert express(C.j, A) == (cos(q2)*A.j + sin(q2)*A.k) assert express(C.k, A) == (sin(q3)*A.i - sin(q2)*cos(q3)*A.j + cos(q2)*cos(q3)*A.k) assert express(C.i, B) == (cos(q3)*B.i - sin(q3)*B.k) assert express(C.j, B) == B.j assert express(C.k, B) == (sin(q3)*B.i + cos(q3)*B.k) assert express(C.i, C) == C.i assert express(C.j, C) == C.j assert express(C.k, C) == C.k == (C.k) # Check to make sure Vectors get converted back to UnitVectors assert N.i == express((cos(q1)*A.i - sin(q1)*A.j), N).simplify() assert N.j == express((sin(q1)*A.i + cos(q1)*A.j), N).simplify() assert N.i == express((cos(q1)*B.i - sin(q1)*cos(q2)*B.j + sin(q1)*sin(q2)*B.k), N).simplify() assert N.j == express((sin(q1)*B.i + cos(q1)*cos(q2)*B.j - sin(q2)*cos(q1)*B.k), N).simplify() assert N.k == express((sin(q2)*B.j + cos(q2)*B.k), N).simplify() assert A.i == express((cos(q1)*N.i + sin(q1)*N.j), A).simplify() assert A.j == express((-sin(q1)*N.i + cos(q1)*N.j), A).simplify() assert A.j == express((cos(q2)*B.j - sin(q2)*B.k), A).simplify() assert A.k == express((sin(q2)*B.j + cos(q2)*B.k), A).simplify() assert A.i == express((cos(q3)*C.i + sin(q3)*C.k), A).simplify() assert A.j == express((sin(q2)*sin(q3)*C.i + cos(q2)*C.j - sin(q2)*cos(q3)*C.k), A).simplify() assert A.k == express((-sin(q3)*cos(q2)*C.i + sin(q2)*C.j + cos(q2)*cos(q3)*C.k), A).simplify() assert B.i == express((cos(q1)*N.i + sin(q1)*N.j), B).simplify() assert B.j == express((-sin(q1)*cos(q2)*N.i + cos(q1)*cos(q2)*N.j + sin(q2)*N.k), B).simplify() assert B.k == express((sin(q1)*sin(q2)*N.i - sin(q2)*cos(q1)*N.j + cos(q2)*N.k), B).simplify() assert B.j == express((cos(q2)*A.j + sin(q2)*A.k), B).simplify() assert B.k == express((-sin(q2)*A.j + cos(q2)*A.k), B).simplify() assert B.i == express((cos(q3)*C.i + sin(q3)*C.k), B).simplify() assert B.k == express((-sin(q3)*C.i + cos(q3)*C.k), B).simplify() assert C.i == express((cos(q3)*A.i + sin(q2)*sin(q3)*A.j - sin(q3)*cos(q2)*A.k), C).simplify() assert C.j == express((cos(q2)*A.j + sin(q2)*A.k), C).simplify() assert C.k == express((sin(q3)*A.i - sin(q2)*cos(q3)*A.j + cos(q2)*cos(q3)*A.k), C).simplify() assert C.i == express((cos(q3)*B.i - sin(q3)*B.k), C).simplify() assert C.k == express((sin(q3)*B.i + cos(q3)*B.k), C).simplify() def test_matrix_to_vector(): m = Matrix([[1], [2], [3]]) assert matrix_to_vector(m, C) == C.i + 2*C.j + 3*C.k m = Matrix([[0], [0], [0]]) assert matrix_to_vector(m, N) == matrix_to_vector(m, C) == \ Vector.zero m = Matrix([[q1], [q2], [q3]]) assert matrix_to_vector(m, N) == q1*N.i + q2*N.j + q3*N.k def test_orthogonalize(): C = CoordSys3D('C') a, b = symbols('a b', integer=True) i, j, k = C.base_vectors() v1 = i + 2*j v2 = 2*i + 3*j v3 = 3*i + 5*j v4 = 3*i + j v5 = 2*i + 2*j v6 = a*i + b*j v7 = 4*a*i + 4*b*j assert orthogonalize(v1, v2) == [C.i + 2*C.j, C.i*Rational(2, 5) + -C.j/5] # from wikipedia assert orthogonalize(v4, v5, orthonormal=True) == \ [(3*sqrt(10))*C.i/10 + (sqrt(10))*C.j/10, (-sqrt(10))*C.i/10 + (3*sqrt(10))*C.j/10] raises(ValueError, lambda: orthogonalize(v1, v2, v3)) raises(ValueError, lambda: orthogonalize(v6, v7)) sympy-sympy-1.9/sympy/vector/tests/test_implicitregion.py000066400000000000000000000100311412543434000241720ustar00rootroot00000000000000from sympy import Eq, S, sqrt from sympy.abc import x, y, z, s, t from sympy.sets import FiniteSet, EmptySet from sympy.geometry import Point from sympy.vector import ImplicitRegion from sympy.testing.pytest import raises def test_ImplicitRegion(): ellipse = ImplicitRegion((x, y), (x**2/4 + y**2/16 - 1)) assert ellipse.equation == x**2/4 + y**2/16 - 1 assert ellipse.variables == (x, y) assert ellipse.degree == 2 r = ImplicitRegion((x, y, z), Eq(x**4 + y**2 - x*y, 6)) assert r.equation == x**4 + y**2 - x*y - 6 assert r.variables == (x, y, z) assert r.degree == 4 def test_regular_point(): r1 = ImplicitRegion((x,), x**2 - 16) r1.regular_point() == (-4,) c1 = ImplicitRegion((x, y), x**2 + y**2 - 4) c1.regular_point() == (2, 0) c2 = ImplicitRegion((x, y), (x - S(5)/2)**2 + y**2 - (S(1)/4)**2) c2.regular_point() == (11/4, 0) c3 = ImplicitRegion((x, y), (y - 5)**2 - 16*(x - 5)) c3.regular_point() == (5, 5) r2 = ImplicitRegion((x, y), x**2 - 4*x*y - 3*y**2 + 4*x + 8*y - 5) r2.regular_point == (4/7, 13/21) r3 = ImplicitRegion((x, y), x**2 - 2*x*y + 3*y**2 - 2*x - 5*y + 3/2) raises(ValueError, lambda: r3.regular_point()) def test_singular_points_and_multiplicty(): r1 = ImplicitRegion((x, y, z), Eq(x + y + z, 0)) assert r1.singular_points() == FiniteSet((-y - z, y, z)) assert r1.multiplicity((0, 0, 0)) == 1 assert r1.multiplicity((-y - z, y, z)) == 1 r2 = ImplicitRegion((x, y, z), x*y*z + y**4 -x**2*z**2) assert r2.singular_points() == FiniteSet((0, 0, z), ((-y*sqrt(4*y**2 + 1)/2 + y/2)/z, y, z),\ ((y*sqrt(4*y**2 + 1)/2 + y/2)/z, y, z)) assert r2.multiplicity((0, 0, 0)) == 3 assert r2.multiplicity((0, 0, 6)) == 2 r3 = ImplicitRegion((x, y, z), z**2 - x**2 - y**2) assert r3.singular_points() == FiniteSet((0, 0, 0)) assert r3.multiplicity((0, 0, 0)) == 2 r4 = ImplicitRegion((x, y), x**2 + y**2 - 2*x) assert r4.singular_points() == EmptySet assert r4.multiplicity(Point(1, 3)) == 0 def test_rational_parametrization(): p = ImplicitRegion((x,), x - 2) assert p.rational_parametrization() == (x - 2,) line = ImplicitRegion((x, y), Eq(y, 3*x + 2)) assert line.rational_parametrization() == (x, 3*x + 2) circle1 = ImplicitRegion((x, y), (x-2)**2 + (y+3)**2 - 4) assert circle1.rational_parametrization(parameters=t) == (4*t/(t**2 + 1) + 2, 4*t**2/(t**2 + 1) - 5) circle2 = ImplicitRegion((x, y), (x - S.Half)**2 + y**2 - (S(1)/2)**2) assert circle2.rational_parametrization(parameters=t) == (t/(t**2 + 1) + S(1)/2, t**2/(t**2 + 1) - S(1)/2) circle3 = ImplicitRegion((x, y), Eq(x**2 + y**2, 2*x)) assert circle3.rational_parametrization(parameters=(t,)) == (2*t/(t**2 + 1) + 1, 2*t**2/(t**2 + 1) - 1) parabola = ImplicitRegion((x, y), (y - 3)**2 - 4*(x + 6)) assert parabola.rational_parametrization(t) == (-6 + 4/t**2, 3 + 4/t) rect_hyperbola = ImplicitRegion((x, y), x*y - 1) assert rect_hyperbola.rational_parametrization(t) == (-1 + (t + 1)/t, t) cubic_curve = ImplicitRegion((x, y), x**3 + x**2 - y**2) assert cubic_curve.rational_parametrization(parameters=(t)) == (t**2 - 1, t*(t**2 - 1)) cuspidal = ImplicitRegion((x, y), (x**3 - y**2)) assert cuspidal.rational_parametrization(t) == (t**2, t**3) I = ImplicitRegion((x, y), x**3 + x**2 - y**2) assert I.rational_parametrization(t) == (t**2 - 1, t*(t**2 - 1)) sphere = ImplicitRegion((x, y, z), Eq(x**2 + y**2 + z**2, 2*x)) assert sphere.rational_parametrization(parameters=(s, t)) == (2/(s**2 + t**2 + 1), 2*t/(s**2 + t**2 + 1), 2*s/(s**2 + t**2 + 1)) conic = ImplicitRegion((x, y), Eq(x**2 + 4*x*y + 3*y**2 + x - y + 10, 0)) conic.rational_parametrization(t) == (17/2 + 4/(3*t**2 + 4*t + 1), 4*t/(3*t**2 + 4*t + 1) - 11/2) r1 = ImplicitRegion((x, y), y**2 - x**3 + x) raises(NotImplementedError, lambda: r1.rational_parametrization()) r2 = ImplicitRegion((x, y), y**2 - x**3 - x**2 + 1) raises(NotImplementedError, lambda: r2.rational_parametrization()) sympy-sympy-1.9/sympy/vector/tests/test_integrals.py000066400000000000000000000115071412543434000231550ustar00rootroot00000000000000from sympy import sin, cos, pi, S, sqrt from sympy.testing.pytest import raises from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.integrals import ParametricIntegral, vector_integrate from sympy.vector.parametricregion import ParametricRegion from sympy.vector.implicitregion import ImplicitRegion from sympy.abc import x, y, z, u, v, r, t, theta, phi from sympy.geometry import Point, Segment, Curve, Circle, Polygon, Plane C = CoordSys3D('C') def test_parametric_lineintegrals(): halfcircle = ParametricRegion((4*cos(theta), 4*sin(theta)), (theta, -pi/2, pi/2)) assert ParametricIntegral(C.x*C.y**4, halfcircle) == S(8192)/5 curve = ParametricRegion((t, t**2, t**3), (t, 0, 1)) field1 = 8*C.x**2*C.y*C.z*C.i + 5*C.z*C.j - 4*C.x*C.y*C.k assert ParametricIntegral(field1, curve) == 1 line = ParametricRegion((4*t - 1, 2 - 2*t, t), (t, 0, 1)) assert ParametricIntegral(C.x*C.z*C.i - C.y*C.z*C.k, line) == 3 assert ParametricIntegral(4*C.x**3, ParametricRegion((1, t), (t, 0, 2))) == 8 helix = ParametricRegion((cos(t), sin(t), 3*t), (t, 0, 4*pi)) assert ParametricIntegral(C.x*C.y*C.z, helix) == -3*sqrt(10)*pi field2 = C.y*C.i + C.z*C.j + C.z*C.k assert ParametricIntegral(field2, ParametricRegion((cos(t), sin(t), t**2), (t, 0, pi))) == -5*pi/2 + pi**4/2 def test_parametric_surfaceintegrals(): semisphere = ParametricRegion((2*sin(phi)*cos(theta), 2*sin(phi)*sin(theta), 2*cos(phi)),\ (theta, 0, 2*pi), (phi, 0, pi/2)) assert ParametricIntegral(C.z, semisphere) == 8*pi cylinder = ParametricRegion((sqrt(3)*cos(theta), sqrt(3)*sin(theta), z), (z, 0, 6), (theta, 0, 2*pi)) assert ParametricIntegral(C.y, cylinder) == 0 cone = ParametricRegion((v*cos(u), v*sin(u), v), (u, 0, 2*pi), (v, 0, 1)) assert ParametricIntegral(C.x*C.i + C.y*C.j + C.z**4*C.k, cone) == pi/3 triangle1 = ParametricRegion((x, y), (x, 0, 2), (y, 0, 10 - 5*x)) triangle2 = ParametricRegion((x, y), (y, 0, 10 - 5*x), (x, 0, 2)) assert ParametricIntegral(-15.6*C.y*C.k, triangle1) == ParametricIntegral(-15.6*C.y*C.k, triangle2) assert ParametricIntegral(C.z, triangle1) == 10*C.z def test_parametric_volumeintegrals(): cube = ParametricRegion((x, y, z), (x, 0, 1), (y, 0, 1), (z, 0, 1)) assert ParametricIntegral(1, cube) == 1 solidsphere1 = ParametricRegion((r*sin(phi)*cos(theta), r*sin(phi)*sin(theta), r*cos(phi)),\ (r, 0, 2), (theta, 0, 2*pi), (phi, 0, pi)) solidsphere2 = ParametricRegion((r*sin(phi)*cos(theta), r*sin(phi)*sin(theta), r*cos(phi)),\ (r, 0, 2), (phi, 0, pi), (theta, 0, 2*pi)) assert ParametricIntegral(C.x**2 + C.y**2, solidsphere1) == -256*pi/15 assert ParametricIntegral(C.x**2 + C.y**2, solidsphere2) == 256*pi/15 region_under_plane1 = ParametricRegion((x, y, z), (x, 0, 3), (y, 0, -2*x/3 + 2),\ (z, 0, 6 - 2*x - 3*y)) region_under_plane2 = ParametricRegion((x, y, z), (x, 0, 3), (z, 0, 6 - 2*x - 3*y),\ (y, 0, -2*x/3 + 2)) assert ParametricIntegral(C.x*C.i + C.j - 100*C.k, region_under_plane1) == \ ParametricIntegral(C.x*C.i + C.j - 100*C.k, region_under_plane2) assert ParametricIntegral(2*C.x, region_under_plane2) == -9 def test_vector_integrate(): halfdisc = ParametricRegion((r*cos(theta), r* sin(theta)), (r, -2, 2), (theta, 0, pi)) assert vector_integrate(C.x**2, halfdisc) == 4*pi vector_integrate(C.x, ParametricRegion((t, t**2), (t, 2, 3))) == -17*sqrt(17)/12 + 37*sqrt(37)/12 assert vector_integrate(C.y**3*C.z, (C.x, 0, 3), (C.y, -1, 4)) == 765*C.z/4 s1 = Segment(Point(0, 0), Point(0, 1)) assert vector_integrate(-15*C.y, s1) == S(-15)/2 s2 = Segment(Point(4, 3, 9), Point(1, 1, 7)) assert vector_integrate(C.y*C.i, s2) == -6 curve = Curve((sin(t), cos(t)), (t, 0, 2)) assert vector_integrate(5*C.z, curve) == 10*C.z c1 = Circle(Point(2, 3), 6) assert vector_integrate(C.x*C.y, c1) == 72*pi c2 = Circle(Point(0, 0), Point(1, 1), Point(1, 0)) assert vector_integrate(1, c2) == c2.circumference triangle = Polygon((0, 0), (1, 0), (1, 1)) assert vector_integrate(C.x*C.i - 14*C.y*C.j, triangle) == 0 p1, p2, p3, p4 = [(0, 0), (1, 0), (5, 1), (0, 1)] poly = Polygon(p1, p2, p3, p4) assert vector_integrate(-23*C.z, poly) == -161*C.z - 23*sqrt(17)*C.z point = Point(2, 3) assert vector_integrate(C.i*C.y - C.z, point) == ParametricIntegral(C.y*C.i, ParametricRegion((2, 3))) c3 = ImplicitRegion((x, y), x**2 + y**2 - 4) assert vector_integrate(45, c3) == 180*pi c4 = ImplicitRegion((x, y), (x - 3)**2 + (y - 4)**2 - 9) assert vector_integrate(1, c4) == 6*pi pl = Plane(Point(1, 1, 1), Point(2, 3, 4), Point(2, 2, 2)) raises(ValueError, lambda: vector_integrate(C.x*C.z*C.i + C.k, pl)) sympy-sympy-1.9/sympy/vector/tests/test_operators.py000066400000000000000000000027271412543434000232070ustar00rootroot00000000000000from sympy.vector import CoordSys3D, Gradient, Divergence, Curl, VectorZero, Laplacian from sympy.printing.repr import srepr R = CoordSys3D('R') s1 = R.x*R.y*R.z # type: ignore s2 = R.x + 3*R.y**2 # type: ignore s3 = R.x**2 + R.y**2 + R.z**2 # type: ignore v1 = R.x*R.i + R.z*R.z*R.j # type: ignore v2 = R.x*R.i + R.y*R.j + R.z*R.k # type: ignore v3 = R.x**2*R.i + R.y**2*R.j + R.z**2*R.k # type: ignore def test_Gradient(): assert Gradient(s1) == Gradient(R.x*R.y*R.z) assert Gradient(s2) == Gradient(R.x + 3*R.y**2) assert Gradient(s1).doit() == R.y*R.z*R.i + R.x*R.z*R.j + R.x*R.y*R.k assert Gradient(s2).doit() == R.i + 6*R.y*R.j def test_Divergence(): assert Divergence(v1) == Divergence(R.x*R.i + R.z*R.z*R.j) assert Divergence(v2) == Divergence(R.x*R.i + R.y*R.j + R.z*R.k) assert Divergence(v1).doit() == 1 assert Divergence(v2).doit() == 3 def test_Curl(): assert Curl(v1) == Curl(R.x*R.i + R.z*R.z*R.j) assert Curl(v2) == Curl(R.x*R.i + R.y*R.j + R.z*R.k) assert Curl(v1).doit() == (-2*R.z)*R.i assert Curl(v2).doit() == VectorZero() def test_Laplacian(): assert Laplacian(s3) == Laplacian(R.x**2 + R.y**2 + R.z**2) assert Laplacian(v3) == Laplacian(R.x**2*R.i + R.y**2*R.j + R.z**2*R.k) assert Laplacian(s3).doit() == 6 assert Laplacian(v3).doit() == 2*R.i + 2*R.j + 2*R.k assert srepr(Laplacian(s3)) == \ 'Laplacian(Add(Pow(R.x, Integer(2)), Pow(R.y, Integer(2)), Pow(R.z, Integer(2))))' sympy-sympy-1.9/sympy/vector/tests/test_parametricregion.py000066400000000000000000000075461412543434000245300ustar00rootroot00000000000000from sympy import sin, cos, pi from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.parametricregion import ParametricRegion, parametric_region_list from sympy.geometry import Point, Segment, Curve, Ellipse, Line, Parabola, Polygon from sympy.testing.pytest import raises from sympy.abc import a, b, r, t, x, y, z, theta, phi C = CoordSys3D('C') def test_ParametricRegion(): point = ParametricRegion((3, 4)) assert point.definition == (3, 4) assert point.parameters == () assert point.limits == {} assert point.dimensions == 0 # line x = y line_xy = ParametricRegion((y, y), (y, 1, 5)) assert line_xy .definition == (y, y) assert line_xy.parameters == (y,) assert line_xy.dimensions == 1 # line y = z line_yz = ParametricRegion((x,t,t), x, (t, 1, 2)) assert line_yz.definition == (x,t,t) assert line_yz.parameters == (x, t) assert line_yz.limits == {t: (1, 2)} assert line_yz.dimensions == 1 p1 = ParametricRegion((9*a, -16*b), (a, 0, 2), (b, -1, 5)) assert p1.definition == (9*a, -16*b) assert p1.parameters == (a, b) assert p1.limits == {a: (0, 2), b: (-1, 5)} assert p1.dimensions == 2 p2 = ParametricRegion((t, t**3), t) assert p2.parameters == (t,) assert p2.limits == {} assert p2.dimensions == 0 circle = ParametricRegion((r*cos(theta), r*sin(theta)), r, (theta, 0, 2*pi)) assert circle.definition == (r*cos(theta), r*sin(theta)) assert circle.dimensions == 1 halfdisc = ParametricRegion((r*cos(theta), r*sin(theta)), (r, -2, 2), (theta, 0, pi)) assert halfdisc.definition == (r*cos(theta), r*sin(theta)) assert halfdisc.parameters == (r, theta) assert halfdisc.limits == {r: (-2, 2), theta: (0, pi)} assert halfdisc.dimensions == 2 ellipse = ParametricRegion((a*cos(t), b*sin(t)), (t, 0, 8)) assert ellipse.parameters == (t,) assert ellipse.limits == {t: (0, 8)} assert ellipse.dimensions == 1 cylinder = ParametricRegion((r*cos(theta), r*sin(theta), z), (r, 0, 1), (theta, 0, 2*pi), (z, 0, 4)) assert cylinder.parameters == (r, theta, z) assert cylinder.dimensions == 3 sphere = ParametricRegion((r*sin(phi)*cos(theta),r*sin(phi)*sin(theta), r*cos(phi)), r, (theta, 0, 2*pi), (phi, 0, pi)) assert sphere.definition == (r*sin(phi)*cos(theta),r*sin(phi)*sin(theta), r*cos(phi)) assert sphere.parameters == (r, theta, phi) assert sphere.dimensions == 2 raises(ValueError, lambda: ParametricRegion((a*t**2, 2*a*t), (a, -2))) raises(ValueError, lambda: ParametricRegion((a, b), (a**2, sin(b)), (a, 2, 4, 6))) def test_parametric_region_list(): point = Point(-5, 12) assert parametric_region_list(point) == [ParametricRegion((-5, 12))] e = Ellipse(Point(2, 8), 2, 6) assert parametric_region_list(e, t) == [ParametricRegion((2*cos(t) + 2, 6*sin(t) + 8), (t, 0, 2*pi))] c = Curve((t, t**3), (t, 5, 3)) assert parametric_region_list(c) == [ParametricRegion((t, t**3), (t, 5, 3))] s = Segment(Point(2, 11, -6), Point(0, 2, 5)) assert parametric_region_list(s, t) == [ParametricRegion((2 - 2*t, 11 - 9*t, 11*t - 6), (t, 0, 1))] s1 = Segment(Point(0, 0), (1, 0)) assert parametric_region_list(s1, t) == [ParametricRegion((t, 0), (t, 0, 1))] s2 = Segment(Point(1, 2, 3), Point(1, 2, 5)) assert parametric_region_list(s2, t) == [ParametricRegion((1, 2, 2*t + 3), (t, 0, 1))] s3 = Segment(Point(12, 56), Point(12, 56)) assert parametric_region_list(s3) == [ParametricRegion((12, 56))] poly = Polygon((1,3), (-3, 8), (2, 4)) assert parametric_region_list(poly, t) == [ParametricRegion((1 - 4*t, 5*t + 3), (t, 0, 1)), ParametricRegion((5*t - 3, 8 - 4*t), (t, 0, 1)), ParametricRegion((2 - t, 4 - t), (t, 0, 1))] p1 = Parabola(Point(0, 0), Line(Point(5, 8), Point(7,8))) raises(ValueError, lambda: parametric_region_list(p1)) sympy-sympy-1.9/sympy/vector/tests/test_printing.py000066400000000000000000000132541412543434000230200ustar00rootroot00000000000000# -*- coding: utf-8 -*- from sympy import Integral, latex, Function from sympy import pretty as xpretty from sympy.vector import CoordSys3D, Vector, express from sympy.abc import a, b, c from sympy.testing.pytest import XFAIL def pretty(expr): """ASCII pretty-printing""" return xpretty(expr, use_unicode=False, wrap_line=False) def upretty(expr): """Unicode pretty-printing""" return xpretty(expr, use_unicode=True, wrap_line=False) # Initialize the basic and tedious vector/dyadic expressions # needed for testing. # Some of the pretty forms shown denote how the expressions just # above them should look with pretty printing. N = CoordSys3D('N') C = N.orient_new_axis('C', a, N.k) # type: ignore v = [] d = [] v.append(Vector.zero) v.append(N.i) # type: ignore v.append(-N.i) # type: ignore v.append(N.i + N.j) # type: ignore v.append(a*N.i) # type: ignore v.append(a*N.i - b*N.j) # type: ignore v.append((a**2 + N.x)*N.i + N.k) # type: ignore v.append((a**2 + b)*N.i + 3*(C.y - c)*N.k) # type: ignore f = Function('f') v.append(N.j - (Integral(f(b)) - C.x**2)*N.k) # type: ignore upretty_v_8 = """\ ⎛ 2 ⌠ ⎞ \n\ j_N + ⎜x_C - ⎮ f(b) db⎟ k_N\n\ ⎝ ⌡ ⎠ \ """ pretty_v_8 = """\ j_N + / / \\\n\ | 2 | |\n\ |x_C - | f(b) db|\n\ | | |\n\ \\ / / \ """ v.append(N.i + C.k) # type: ignore v.append(express(N.i, C)) # type: ignore v.append((a**2 + b)*N.i + (Integral(f(b)))*N.k) # type: ignore upretty_v_11 = """\ ⎛ 2 ⎞ ⎛⌠ ⎞ \n\ ⎝a + b⎠ i_N + ⎜⎮ f(b) db⎟ k_N\n\ ⎝⌡ ⎠ \ """ pretty_v_11 = """\ / 2 \\ + / / \\\n\ \\a + b/ i_N| | |\n\ | | f(b) db|\n\ | | |\n\ \\/ / \ """ for x in v: d.append(x | N.k) # type: ignore s = 3*N.x**2*C.y # type: ignore upretty_s = """\ 2\n\ 3⋅y_C⋅x_N \ """ pretty_s = """\ 2\n\ 3*y_C*x_N \ """ # This is the pretty form for ((a**2 + b)*N.i + 3*(C.y - c)*N.k) | N.k upretty_d_7 = """\ ⎛ 2 ⎞ \n\ ⎝a + b⎠ (i_N|k_N) + (3⋅y_C - 3⋅c) (k_N|k_N)\ """ pretty_d_7 = """\ / 2 \\ (i_N|k_N) + (3*y_C - 3*c) (k_N|k_N)\n\ \\a + b/ \ """ def test_str_printing(): assert str(v[0]) == '0' assert str(v[1]) == 'N.i' assert str(v[2]) == '(-1)*N.i' assert str(v[3]) == 'N.i + N.j' assert str(v[8]) == 'N.j + (C.x**2 - Integral(f(b), b))*N.k' assert str(v[9]) == 'C.k + N.i' assert str(s) == '3*C.y*N.x**2' assert str(d[0]) == '0' assert str(d[1]) == '(N.i|N.k)' assert str(d[4]) == 'a*(N.i|N.k)' assert str(d[5]) == 'a*(N.i|N.k) + (-b)*(N.j|N.k)' assert str(d[8]) == ('(N.j|N.k) + (C.x**2 - ' + 'Integral(f(b), b))*(N.k|N.k)') @XFAIL def test_pretty_printing_ascii(): assert pretty(v[0]) == '0' assert pretty(v[1]) == 'i_N' assert pretty(v[5]) == '(a) i_N + (-b) j_N' assert pretty(v[8]) == pretty_v_8 assert pretty(v[2]) == '(-1) i_N' assert pretty(v[11]) == pretty_v_11 assert pretty(s) == pretty_s assert pretty(d[0]) == '(0|0)' assert pretty(d[5]) == '(a) (i_N|k_N) + (-b) (j_N|k_N)' assert pretty(d[7]) == pretty_d_7 assert pretty(d[10]) == '(cos(a)) (i_C|k_N) + (-sin(a)) (j_C|k_N)' def test_pretty_print_unicode_v(): assert upretty(v[0]) == '0' assert upretty(v[1]) == 'i_N' assert upretty(v[5]) == '(a) i_N + (-b) j_N' # Make sure the printing works in other objects assert upretty(v[5].args) == '((a) i_N, (-b) j_N)' assert upretty(v[8]) == upretty_v_8 assert upretty(v[2]) == '(-1) i_N' assert upretty(v[11]) == upretty_v_11 assert upretty(s) == upretty_s assert upretty(d[0]) == '(0|0)' assert upretty(d[5]) == '(a) (i_N|k_N) + (-b) (j_N|k_N)' assert upretty(d[7]) == upretty_d_7 assert upretty(d[10]) == '(cos(a)) (i_C|k_N) + (-sin(a)) (j_C|k_N)' def test_latex_printing(): assert latex(v[0]) == '\\mathbf{\\hat{0}}' assert latex(v[1]) == '\\mathbf{\\hat{i}_{N}}' assert latex(v[2]) == '- \\mathbf{\\hat{i}_{N}}' assert latex(v[5]) == ('(a)\\mathbf{\\hat{i}_{N}} + ' + '(- b)\\mathbf{\\hat{j}_{N}}') assert latex(v[6]) == ('(\\mathbf{{x}_{N}} + a^{2})\\mathbf{\\hat{i}_' + '{N}} + \\mathbf{\\hat{k}_{N}}') assert latex(v[8]) == ('\\mathbf{\\hat{j}_{N}} + (\\mathbf{{x}_' + '{C}}^{2} - \\int f{\\left(b \\right)}\\,' + ' db)\\mathbf{\\hat{k}_{N}}') assert latex(s) == '3 \\mathbf{{y}_{C}} \\mathbf{{x}_{N}}^{2}' assert latex(d[0]) == '(\\mathbf{\\hat{0}}|\\mathbf{\\hat{0}})' assert latex(d[4]) == ('(a)(\\mathbf{\\hat{i}_{N}}{|}\\mathbf' + '{\\hat{k}_{N}})') assert latex(d[9]) == ('(\\mathbf{\\hat{k}_{C}}{|}\\mathbf{\\' + 'hat{k}_{N}}) + (\\mathbf{\\hat{i}_{N}}{|' + '}\\mathbf{\\hat{k}_{N}})') assert latex(d[11]) == ('(a^{2} + b)(\\mathbf{\\hat{i}_{N}}{|}\\' + 'mathbf{\\hat{k}_{N}}) + (\\int f{\\left(' + 'b \\right)}\\, db)(\\mathbf{\\hat{k}_{N}' + '}{|}\\mathbf{\\hat{k}_{N}})') def test_custom_names(): A = CoordSys3D('A', vector_names=['x', 'y', 'z'], variable_names=['i', 'j', 'k']) assert A.i.__str__() == 'A.i' assert A.x.__str__() == 'A.x' assert A.i._pretty_form == 'i_A' assert A.x._pretty_form == 'x_A' assert A.i._latex_form == r'\mathbf{{i}_{A}}' assert A.x._latex_form == r"\mathbf{\hat{x}_{A}}" sympy-sympy-1.9/sympy/vector/tests/test_vector.py000066400000000000000000000155211412543434000224670ustar00rootroot00000000000000from sympy.core import Rational, S from sympy.simplify import simplify, trigsimp from sympy import pi, sqrt, symbols, ImmutableMatrix as Matrix, \ sin, cos, Function, Integral, Derivative, diff from sympy.vector.vector import Vector, BaseVector, VectorAdd, \ VectorMul, VectorZero from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.vector import Cross, Dot, cross from sympy.testing.pytest import raises C = CoordSys3D('C') i, j, k = C.base_vectors() a, b, c = symbols('a b c') def test_cross(): v1 = C.x * i + C.z * C.z * j v2 = C.x * i + C.y * j + C.z * k assert Cross(v1, v2) == Cross(C.x*C.i + C.z**2*C.j, C.x*C.i + C.y*C.j + C.z*C.k) assert Cross(v1, v2).doit() == C.z**3*C.i + (-C.x*C.z)*C.j + (C.x*C.y - C.x*C.z**2)*C.k assert cross(v1, v2) == C.z**3*C.i + (-C.x*C.z)*C.j + (C.x*C.y - C.x*C.z**2)*C.k assert Cross(v1, v2) == -Cross(v2, v1) assert Cross(v1, v2) + Cross(v2, v1) == Vector.zero def test_dot(): v1 = C.x * i + C.z * C.z * j v2 = C.x * i + C.y * j + C.z * k assert Dot(v1, v2) == Dot(C.x*C.i + C.z**2*C.j, C.x*C.i + C.y*C.j + C.z*C.k) assert Dot(v1, v2).doit() == C.x**2 + C.y*C.z**2 assert Dot(v1, v2).doit() == C.x**2 + C.y*C.z**2 assert Dot(v1, v2) == Dot(v2, v1) def test_vector_sympy(): """ Test whether the Vector framework confirms to the hashing and equality testing properties of SymPy. """ v1 = 3*j assert v1 == j*3 assert v1.components == {j: 3} v2 = 3*i + 4*j + 5*k v3 = 2*i + 4*j + i + 4*k + k assert v3 == v2 assert v3.__hash__() == v2.__hash__() def test_vector(): assert isinstance(i, BaseVector) assert i != j assert j != k assert k != i assert i - i == Vector.zero assert i + Vector.zero == i assert i - Vector.zero == i assert Vector.zero != 0 assert -Vector.zero == Vector.zero v1 = a*i + b*j + c*k v2 = a**2*i + b**2*j + c**2*k v3 = v1 + v2 v4 = 2 * v1 v5 = a * i assert isinstance(v1, VectorAdd) assert v1 - v1 == Vector.zero assert v1 + Vector.zero == v1 assert v1.dot(i) == a assert v1.dot(j) == b assert v1.dot(k) == c assert i.dot(v2) == a**2 assert j.dot(v2) == b**2 assert k.dot(v2) == c**2 assert v3.dot(i) == a**2 + a assert v3.dot(j) == b**2 + b assert v3.dot(k) == c**2 + c assert v1 + v2 == v2 + v1 assert v1 - v2 == -1 * (v2 - v1) assert a * v1 == v1 * a assert isinstance(v5, VectorMul) assert v5.base_vector == i assert v5.measure_number == a assert isinstance(v4, Vector) assert isinstance(v4, VectorAdd) assert isinstance(v4, Vector) assert isinstance(Vector.zero, VectorZero) assert isinstance(Vector.zero, Vector) assert isinstance(v1 * 0, VectorZero) assert v1.to_matrix(C) == Matrix([[a], [b], [c]]) assert i.components == {i: 1} assert v5.components == {i: a} assert v1.components == {i: a, j: b, k: c} assert VectorAdd(v1, Vector.zero) == v1 assert VectorMul(a, v1) == v1*a assert VectorMul(1, i) == i assert VectorAdd(v1, Vector.zero) == v1 assert VectorMul(0, Vector.zero) == Vector.zero raises(TypeError, lambda: v1.outer(1)) raises(TypeError, lambda: v1.dot(1)) def test_vector_magnitude_normalize(): assert Vector.zero.magnitude() == 0 assert Vector.zero.normalize() == Vector.zero assert i.magnitude() == 1 assert j.magnitude() == 1 assert k.magnitude() == 1 assert i.normalize() == i assert j.normalize() == j assert k.normalize() == k v1 = a * i assert v1.normalize() == (a/sqrt(a**2))*i assert v1.magnitude() == sqrt(a**2) v2 = a*i + b*j + c*k assert v2.magnitude() == sqrt(a**2 + b**2 + c**2) assert v2.normalize() == v2 / v2.magnitude() v3 = i + j assert v3.normalize() == (sqrt(2)/2)*C.i + (sqrt(2)/2)*C.j def test_vector_simplify(): A, s, k, m = symbols('A, s, k, m') test1 = (1 / a + 1 / b) * i assert (test1 & i) != (a + b) / (a * b) test1 = simplify(test1) assert (test1 & i) == (a + b) / (a * b) assert test1.simplify() == simplify(test1) test2 = (A**2 * s**4 / (4 * pi * k * m**3)) * i test2 = simplify(test2) assert (test2 & i) == (A**2 * s**4 / (4 * pi * k * m**3)) test3 = ((4 + 4 * a - 2 * (2 + 2 * a)) / (2 + 2 * a)) * i test3 = simplify(test3) assert (test3 & i) == 0 test4 = ((-4 * a * b**2 - 2 * b**3 - 2 * a**2 * b) / (a + b)**2) * i test4 = simplify(test4) assert (test4 & i) == -2 * b v = (sin(a)+cos(a))**2*i - j assert trigsimp(v) == (2*sin(a + pi/4)**2)*i + (-1)*j assert trigsimp(v) == v.trigsimp() assert simplify(Vector.zero) == Vector.zero def test_vector_dot(): assert i.dot(Vector.zero) == 0 assert Vector.zero.dot(i) == 0 assert i & Vector.zero == 0 assert i.dot(i) == 1 assert i.dot(j) == 0 assert i.dot(k) == 0 assert i & i == 1 assert i & j == 0 assert i & k == 0 assert j.dot(i) == 0 assert j.dot(j) == 1 assert j.dot(k) == 0 assert j & i == 0 assert j & j == 1 assert j & k == 0 assert k.dot(i) == 0 assert k.dot(j) == 0 assert k.dot(k) == 1 assert k & i == 0 assert k & j == 0 assert k & k == 1 raises(TypeError, lambda: k.dot(1)) def test_vector_cross(): assert i.cross(Vector.zero) == Vector.zero assert Vector.zero.cross(i) == Vector.zero assert i.cross(i) == Vector.zero assert i.cross(j) == k assert i.cross(k) == -j assert i ^ i == Vector.zero assert i ^ j == k assert i ^ k == -j assert j.cross(i) == -k assert j.cross(j) == Vector.zero assert j.cross(k) == i assert j ^ i == -k assert j ^ j == Vector.zero assert j ^ k == i assert k.cross(i) == j assert k.cross(j) == -i assert k.cross(k) == Vector.zero assert k ^ i == j assert k ^ j == -i assert k ^ k == Vector.zero assert k.cross(1) == Cross(k, 1) def test_projection(): v1 = i + j + k v2 = 3*i + 4*j v3 = 0*i + 0*j assert v1.projection(v1) == i + j + k assert v1.projection(v2) == Rational(7, 3)*C.i + Rational(7, 3)*C.j + Rational(7, 3)*C.k assert v1.projection(v1, scalar=True) == S.One assert v1.projection(v2, scalar=True) == Rational(7, 3) assert v3.projection(v1) == Vector.zero assert v3.projection(v1, scalar=True) == S.Zero def test_vector_diff_integrate(): f = Function('f') v = f(a)*C.i + a**2*C.j - C.k assert Derivative(v, a) == Derivative((f(a))*C.i + a**2*C.j + (-1)*C.k, a) assert (diff(v, a) == v.diff(a) == Derivative(v, a).doit() == (Derivative(f(a), a))*C.i + 2*a*C.j) assert (Integral(v, a) == (Integral(f(a), a))*C.i + (Integral(a**2, a))*C.j + (Integral(-1, a))*C.k) def test_vector_args(): raises(ValueError, lambda: BaseVector(3, C)) raises(TypeError, lambda: BaseVector(0, Vector.zero)) sympy-sympy-1.9/sympy/vector/vector.py000066400000000000000000000426111412543434000202660ustar00rootroot00000000000000from typing import Type from sympy.core.assumptions import StdFactKB from sympy.core import S, Pow, sympify from sympy.core.expr import AtomicExpr, Expr from sympy.core.compatibility import default_sort_key from sympy import sqrt, ImmutableMatrix as Matrix, Add from sympy.vector.coordsysrect import CoordSys3D from sympy.vector.basisdependent import (BasisDependent, BasisDependentAdd, BasisDependentMul, BasisDependentZero) from sympy.vector.dyadic import BaseDyadic, Dyadic, DyadicAdd class Vector(BasisDependent): """ Super class for all Vector classes. Ideally, neither this class nor any of its subclasses should be instantiated by the user. """ is_Vector = True _op_priority = 12.0 _expr_type = None # type: Type[Vector] _mul_func = None # type: Type[Vector] _add_func = None # type: Type[Vector] _zero_func = None # type: Type[Vector] _base_func = None # type: Type[Vector] zero = None # type: VectorZero @property def components(self): """ Returns the components of this vector in the form of a Python dictionary mapping BaseVector instances to the corresponding measure numbers. Examples ======== >>> from sympy.vector import CoordSys3D >>> C = CoordSys3D('C') >>> v = 3*C.i + 4*C.j + 5*C.k >>> v.components {C.i: 3, C.j: 4, C.k: 5} """ # The '_components' attribute is defined according to the # subclass of Vector the instance belongs to. return self._components def magnitude(self): """ Returns the magnitude of this vector. """ return sqrt(self & self) def normalize(self): """ Returns the normalized version of this vector. """ return self / self.magnitude() def dot(self, other): """ Returns the dot product of this Vector, either with another Vector, or a Dyadic, or a Del operator. If 'other' is a Vector, returns the dot product scalar (Sympy expression). If 'other' is a Dyadic, the dot product is returned as a Vector. If 'other' is an instance of Del, returns the directional derivative operator as a Python function. If this function is applied to a scalar expression, it returns the directional derivative of the scalar field wrt this Vector. Parameters ========== other: Vector/Dyadic/Del The Vector or Dyadic we are dotting with, or a Del operator . Examples ======== >>> from sympy.vector import CoordSys3D, Del >>> C = CoordSys3D('C') >>> delop = Del() >>> C.i.dot(C.j) 0 >>> C.i & C.i 1 >>> v = 3*C.i + 4*C.j + 5*C.k >>> v.dot(C.k) 5 >>> (C.i & delop)(C.x*C.y*C.z) C.y*C.z >>> d = C.i.outer(C.i) >>> C.i.dot(d) C.i """ # Check special cases if isinstance(other, Dyadic): if isinstance(self, VectorZero): return Vector.zero outvec = Vector.zero for k, v in other.components.items(): vect_dot = k.args[0].dot(self) outvec += vect_dot * v * k.args[1] return outvec from sympy.vector.deloperator import Del if not isinstance(other, Vector) and not isinstance(other, Del): raise TypeError(str(other) + " is not a vector, dyadic or " + "del operator") # Check if the other is a del operator if isinstance(other, Del): def directional_derivative(field): from sympy.vector.functions import directional_derivative return directional_derivative(field, self) return directional_derivative return dot(self, other) def __and__(self, other): return self.dot(other) __and__.__doc__ = dot.__doc__ def cross(self, other): """ Returns the cross product of this Vector with another Vector or Dyadic instance. The cross product is a Vector, if 'other' is a Vector. If 'other' is a Dyadic, this returns a Dyadic instance. Parameters ========== other: Vector/Dyadic The Vector or Dyadic we are crossing with. Examples ======== >>> from sympy.vector import CoordSys3D >>> C = CoordSys3D('C') >>> C.i.cross(C.j) C.k >>> C.i ^ C.i 0 >>> v = 3*C.i + 4*C.j + 5*C.k >>> v ^ C.i 5*C.j + (-4)*C.k >>> d = C.i.outer(C.i) >>> C.j.cross(d) (-1)*(C.k|C.i) """ # Check special cases if isinstance(other, Dyadic): if isinstance(self, VectorZero): return Dyadic.zero outdyad = Dyadic.zero for k, v in other.components.items(): cross_product = self.cross(k.args[0]) outer = cross_product.outer(k.args[1]) outdyad += v * outer return outdyad return cross(self, other) def __xor__(self, other): return self.cross(other) __xor__.__doc__ = cross.__doc__ def outer(self, other): """ Returns the outer product of this vector with another, in the form of a Dyadic instance. Parameters ========== other : Vector The Vector with respect to which the outer product is to be computed. Examples ======== >>> from sympy.vector import CoordSys3D >>> N = CoordSys3D('N') >>> N.i.outer(N.j) (N.i|N.j) """ # Handle the special cases if not isinstance(other, Vector): raise TypeError("Invalid operand for outer product") elif (isinstance(self, VectorZero) or isinstance(other, VectorZero)): return Dyadic.zero # Iterate over components of both the vectors to generate # the required Dyadic instance args = [] for k1, v1 in self.components.items(): for k2, v2 in other.components.items(): args.append((v1 * v2) * BaseDyadic(k1, k2)) return DyadicAdd(*args) def projection(self, other, scalar=False): """ Returns the vector or scalar projection of the 'other' on 'self'. Examples ======== >>> from sympy.vector.coordsysrect import CoordSys3D >>> C = CoordSys3D('C') >>> i, j, k = C.base_vectors() >>> v1 = i + j + k >>> v2 = 3*i + 4*j >>> v1.projection(v2) 7/3*C.i + 7/3*C.j + 7/3*C.k >>> v1.projection(v2, scalar=True) 7/3 """ if self.equals(Vector.zero): return S.Zero if scalar else Vector.zero if scalar: return self.dot(other) / self.dot(self) else: return self.dot(other) / self.dot(self) * self @property def _projections(self): """ Returns the components of this vector but the output includes also zero values components. Examples ======== >>> from sympy.vector import CoordSys3D, Vector >>> C = CoordSys3D('C') >>> v1 = 3*C.i + 4*C.j + 5*C.k >>> v1._projections (3, 4, 5) >>> v2 = C.x*C.y*C.z*C.i >>> v2._projections (C.x*C.y*C.z, 0, 0) >>> v3 = Vector.zero >>> v3._projections (0, 0, 0) """ from sympy.vector.operators import _get_coord_sys_from_expr if isinstance(self, VectorZero): return (S.Zero, S.Zero, S.Zero) base_vec = next(iter(_get_coord_sys_from_expr(self))).base_vectors() return tuple([self.dot(i) for i in base_vec]) def __or__(self, other): return self.outer(other) __or__.__doc__ = outer.__doc__ def to_matrix(self, system): """ Returns the matrix form of this vector with respect to the specified coordinate system. Parameters ========== system : CoordSys3D The system wrt which the matrix form is to be computed Examples ======== >>> from sympy.vector import CoordSys3D >>> C = CoordSys3D('C') >>> from sympy.abc import a, b, c >>> v = a*C.i + b*C.j + c*C.k >>> v.to_matrix(C) Matrix([ [a], [b], [c]]) """ return Matrix([self.dot(unit_vec) for unit_vec in system.base_vectors()]) def separate(self): """ The constituents of this vector in different coordinate systems, as per its definition. Returns a dict mapping each CoordSys3D to the corresponding constituent Vector. Examples ======== >>> from sympy.vector import CoordSys3D >>> R1 = CoordSys3D('R1') >>> R2 = CoordSys3D('R2') >>> v = R1.i + R2.i >>> v.separate() == {R1: R1.i, R2: R2.i} True """ parts = {} for vect, measure in self.components.items(): parts[vect.system] = (parts.get(vect.system, Vector.zero) + vect * measure) return parts def _div_helper(one, other): """ Helper for division involving vectors. """ if isinstance(one, Vector) and isinstance(other, Vector): raise TypeError("Cannot divide two vectors") elif isinstance(one, Vector): if other == S.Zero: raise ValueError("Cannot divide a vector by zero") return VectorMul(one, Pow(other, S.NegativeOne)) else: raise TypeError("Invalid division involving a vector") class BaseVector(Vector, AtomicExpr): """ Class to denote a base vector. Unicode pretty forms in Python 2 should use the prefix ``u``. """ def __new__(cls, index, system, pretty_str=None, latex_str=None): if pretty_str is None: pretty_str = "x{}".format(index) if latex_str is None: latex_str = "x_{}".format(index) pretty_str = str(pretty_str) latex_str = str(latex_str) # Verify arguments if index not in range(0, 3): raise ValueError("index must be 0, 1 or 2") if not isinstance(system, CoordSys3D): raise TypeError("system should be a CoordSys3D") name = system._vector_names[index] # Initialize an object obj = super().__new__(cls, S(index), system) # Assign important attributes obj._base_instance = obj obj._components = {obj: S.One} obj._measure_number = S.One obj._name = system._name + '.' + name obj._pretty_form = '' + pretty_str obj._latex_form = latex_str obj._system = system # The _id is used for printing purposes obj._id = (index, system) assumptions = {'commutative': True} obj._assumptions = StdFactKB(assumptions) # This attr is used for re-expression to one of the systems # involved in the definition of the Vector. Applies to # VectorMul and VectorAdd too. obj._sys = system return obj @property def system(self): return self._system def _sympystr(self, printer): return self._name @property def free_symbols(self): return {self} class VectorAdd(BasisDependentAdd, Vector): """ Class to denote sum of Vector instances. """ def __new__(cls, *args, **options): obj = BasisDependentAdd.__new__(cls, *args, **options) return obj def _sympystr(self, printer): ret_str = '' items = list(self.separate().items()) items.sort(key=lambda x: x[0].__str__()) for system, vect in items: base_vects = system.base_vectors() for x in base_vects: if x in vect.components: temp_vect = self.components[x] * x ret_str += printer._print(temp_vect) + " + " return ret_str[:-3] class VectorMul(BasisDependentMul, Vector): """ Class to denote products of scalars and BaseVectors. """ def __new__(cls, *args, **options): obj = BasisDependentMul.__new__(cls, *args, **options) return obj @property def base_vector(self): """ The BaseVector involved in the product. """ return self._base_instance @property def measure_number(self): """ The scalar expression involved in the definition of this VectorMul. """ return self._measure_number class VectorZero(BasisDependentZero, Vector): """ Class to denote a zero vector """ _op_priority = 12.1 _pretty_form = '0' _latex_form = r'\mathbf{\hat{0}}' def __new__(cls): obj = BasisDependentZero.__new__(cls) return obj class Cross(Vector): """ Represents unevaluated Cross product. Examples ======== >>> from sympy.vector import CoordSys3D, Cross >>> R = CoordSys3D('R') >>> v1 = R.i + R.j + R.k >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k >>> Cross(v1, v2) Cross(R.i + R.j + R.k, R.x*R.i + R.y*R.j + R.z*R.k) >>> Cross(v1, v2).doit() (-R.y + R.z)*R.i + (R.x - R.z)*R.j + (-R.x + R.y)*R.k """ def __new__(cls, expr1, expr2): expr1 = sympify(expr1) expr2 = sympify(expr2) if default_sort_key(expr1) > default_sort_key(expr2): return -Cross(expr2, expr1) obj = Expr.__new__(cls, expr1, expr2) obj._expr1 = expr1 obj._expr2 = expr2 return obj def doit(self, **kwargs): return cross(self._expr1, self._expr2) class Dot(Expr): """ Represents unevaluated Dot product. Examples ======== >>> from sympy.vector import CoordSys3D, Dot >>> from sympy import symbols >>> R = CoordSys3D('R') >>> a, b, c = symbols('a b c') >>> v1 = R.i + R.j + R.k >>> v2 = a * R.i + b * R.j + c * R.k >>> Dot(v1, v2) Dot(R.i + R.j + R.k, a*R.i + b*R.j + c*R.k) >>> Dot(v1, v2).doit() a + b + c """ def __new__(cls, expr1, expr2): expr1 = sympify(expr1) expr2 = sympify(expr2) expr1, expr2 = sorted([expr1, expr2], key=default_sort_key) obj = Expr.__new__(cls, expr1, expr2) obj._expr1 = expr1 obj._expr2 = expr2 return obj def doit(self, **kwargs): return dot(self._expr1, self._expr2) def cross(vect1, vect2): """ Returns cross product of two vectors. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector.vector import cross >>> R = CoordSys3D('R') >>> v1 = R.i + R.j + R.k >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k >>> cross(v1, v2) (-R.y + R.z)*R.i + (R.x - R.z)*R.j + (-R.x + R.y)*R.k """ if isinstance(vect1, Add): return VectorAdd.fromiter(cross(i, vect2) for i in vect1.args) if isinstance(vect2, Add): return VectorAdd.fromiter(cross(vect1, i) for i in vect2.args) if isinstance(vect1, BaseVector) and isinstance(vect2, BaseVector): if vect1._sys == vect2._sys: n1 = vect1.args[0] n2 = vect2.args[0] if n1 == n2: return Vector.zero n3 = ({0,1,2}.difference({n1, n2})).pop() sign = 1 if ((n1 + 1) % 3 == n2) else -1 return sign*vect1._sys.base_vectors()[n3] from .functions import express try: v = express(vect1, vect2._sys) except ValueError: return Cross(vect1, vect2) else: return cross(v, vect2) if isinstance(vect1, VectorZero) or isinstance(vect2, VectorZero): return Vector.zero if isinstance(vect1, VectorMul): v1, m1 = next(iter(vect1.components.items())) return m1*cross(v1, vect2) if isinstance(vect2, VectorMul): v2, m2 = next(iter(vect2.components.items())) return m2*cross(vect1, v2) return Cross(vect1, vect2) def dot(vect1, vect2): """ Returns dot product of two vectors. Examples ======== >>> from sympy.vector import CoordSys3D >>> from sympy.vector.vector import dot >>> R = CoordSys3D('R') >>> v1 = R.i + R.j + R.k >>> v2 = R.x * R.i + R.y * R.j + R.z * R.k >>> dot(v1, v2) R.x + R.y + R.z """ if isinstance(vect1, Add): return Add.fromiter(dot(i, vect2) for i in vect1.args) if isinstance(vect2, Add): return Add.fromiter(dot(vect1, i) for i in vect2.args) if isinstance(vect1, BaseVector) and isinstance(vect2, BaseVector): if vect1._sys == vect2._sys: return S.One if vect1 == vect2 else S.Zero from .functions import express try: v = express(vect2, vect1._sys) except ValueError: return Dot(vect1, vect2) else: return dot(vect1, v) if isinstance(vect1, VectorZero) or isinstance(vect2, VectorZero): return S.Zero if isinstance(vect1, VectorMul): v1, m1 = next(iter(vect1.components.items())) return m1*dot(v1, vect2) if isinstance(vect2, VectorMul): v2, m2 = next(iter(vect2.components.items())) return m2*dot(vect1, v2) return Dot(vect1, vect2) Vector._expr_type = Vector Vector._mul_func = VectorMul Vector._add_func = VectorAdd Vector._zero_func = VectorZero Vector._base_func = BaseVector Vector.zero = VectorZero()

fw(zѨwMDi[D@D@D@D@D@$TyvA^|sɲITn*l'O4_oc/"IP6IjU%PK}>C~.Y191͢8-?Cf.+v1S'm^*cA/tnC֤q0=&:xs٤dUM1W+]Z)ňLG ǔx3̗srg#&T󠛵t*缵GT@G'`Sby%*B"PK}^sCYEwAy̗̗{"s289C7xt[r)?MVvx7|e9<14(!)C3A咈WI(weP1tUޔQ3GIFWh*'M#<@%(pr$SfxVE2{+~X7sA9F7}}0׿;u>M0Թz}3[:MD@D@D@D@D`f0O2ǃJ<;gxWO97w1NlA)Bu؀0=P&`ul\pm'i'E 38`Y9!k]0'_.ʵ":#ބ+^ l3"cFWm'(dOsP牀$'2Y^P] YKT:0OgOGĢDR Q!+iG?[qy[b2PX4kyt= d_4l~P~lL/=_M6=HcD!-{#l'װRi_ W=eAk4,Jʄ.yWx-s1܅w2b4ikt Sz}4.*'˦ #{-IyD^ˇ_T0F>ÓpEeg=>q2,:8M] #_[/o1F+ɿi׶|ꄩ7w%S \Q.GPN ctm>멇6FڗM5w%Sv[~42 NQgs5]d {5uGSdPJR&?mv4ز~=_" " " " " "!vId6]{ĕ8柷⪺@ HPn"\%-" " " " " " " " " ӉPN@ HPn"\%-" " " " " " " " " ӉTʋ4&U" " " " " " " " " "0̚N~^:CΝ>j׏:mL!K{XysGz]͔+" " " " " " " "Ж~ ٖyh/tf;'GPB{CV@vZZ|P;E@D@D@D@D@D@D@D  ۦݴȹ>Цlh"Tc[.N&`{61x " " " " " " "  N?yEDŽݼ{Ν觰IMD`&8ɿ$f=iY?>4y$(OК@]$(ׅq:Pu. "# I4WZ" " " " " " " 3f|)bs^9o6rF60 Æ6W@`.'S6׆RHRI@mrxq㲖N9*Nvt{[㮵̏z qn'GJο:w}ocSlWqϞ8Ers.ܐb^{/vᒹ VaSƘ.ֱ9Ѿʴ>=$jfHDK7Q.-."" " " " " " "8DދNHwsOND_{62$t]i-7.F,+0&xi3xOutnvD0򇌑p$-9]yC1;u8Btg$-GXmvȥژDs_un]Dqz"m2țǜ[T9h ^iyy=F_W({Ӎ1b\ZJ{]LS\9N~md5eq =7Օ n3B=ңҋQH|s1uxb Ver_ܧౌHYWZ:ue@:9ř݉7nBhڏ8s^Fz&aľb_}z#|ߗFca]NLg^qBsp#l, &&\qX1_QzCѐV馱iVGA0 ΁G+~tYyt=}ao41md@ D#s\|d)S,tnm5BI(!TEp˔ ,?z^e [ ޝKGװ {ޜ;JݎWp_Rn? ] FL0N޷ +|hJ×#:MOaV-ŽQxC0qrk~VXuWeܿs#'5'_~Qg k/{iBxf]/Q(QPGk N5眩Mh_5'ַݶaG5u>qtQ3T?۹oS$ll_xُwفQ/n~(uݫE+YKȸ6 t@TS7?t: {x5vx/ײ17Gj|XD]iFajµ0<.E$ĉffY>=expo*\=p6| :F&&ˤ| ;MC&8Wb4ɪ{پ4}i>𤿖˸o|n/Sp|.P/׊@ !jb]j1"]'B5tky"0hZ:Q@pxR1'Ay}`͓hLpnBcQu{\ona.ȁMmľ1F$Fh>1 L=\9N_lNRD@D@D@D@D@D@D` X6[X`sLJHA.%"?|Tn g-x+{eU8oe;M. x~f!fAm?x3pqUxn7<}VB,_W:.(yq%XΝv옲 pnJGNWw9wYeǙ[| o(d@*SL/p^ex7]"k锳vMf ˈ?2?$('_{t+/r๼bfe\h_`zU|#9i-i3C*Ps u>6*z9}33֌_}s_7 g)ZD@D@D@D@D@D@D`j'(ܣyy)DD]R~NSR Ev3V,߈~٢ЬDֳF~:Y3%ra775s_Ӎ^ш'b'3Ƌ:Df5_,܊UK{ ;h{pox'ip=}%g*BD@D@D@D@D@D@D {jP'gjs#d0?ֶo ~!3tچq#vNdIvxÖ_nJ0* fnLWj 6/@S/^M__i^H\b32[r Yal7H@Gī4Ϲ+hao $qKZ:6 a}w3*2cQf#2\vn z-]]avHVDḰoU9ĭ rL! _Wʵ^le&.d1_qvNe\޾}^=iCvcc @Žه87/^K}W#(_ι_yju-D@D@D@D@D@D@D@@9)%bģkAΛq{#9fCH YK'1׊9d^IWBEFrLY17i'p5ts9n73_ OkۋkI,|^6`V:rzuO b$OX1y/_;F&91;/ߒ:X.)^#Ӧ@$P!?ELYK4'fNI.91qVN,俖`gBDbrny>>j 8)d._INU|޾?ÍBx{K8Ҽx=Eqy)28(s›YAD@D@D@D@D@D@D s cxl>s߅/ʄ9Sb4@2S!:FN^O/#NFΞ^l?ϹX$X8,[04|s$;y.&?TG4Mw@rt>nV-+W/?V:K|"M*d_>+?A8[I6kD̛vCWLB7/qq_~r.{u d=:o Wec7Og: ")+6T}[/qm* 3eg24ۯ+)#OynjqSa6ܟXbɱ'PW݊P'L/32FܑxO3qhue t~;ŠD L9|+1kr*fH%jQ4t0\RLw級@!_l _$r`.7DI)Eyz/&<_ ~k4/~{ Ef sxs.J{X톱TI7_:6.:_E.20%1僵%rބW;9f`{c6 wͺY 5=vF7Gy}鼞Mo˅f/6P1=ԑ w9Էrn}E|mzޝ{ztksPQ6ZU73xh=JWD@D@D@D@D@D@D&3Ae).rwX> u'x0m%O}x[ YLq"U;*Dl$OCv BIν^K115LUr*u"j䉤|3lؾRfCD@D@D@D@D@D@D ">g&LX LAڃ)]wN)%@27k$d1_y:fV" " " " " " " mKwG6j^׌tW1r" " " " " " " " şy6.p"4"{4tW9%MXwrTNlsLR" " " " " " " "U"%#^;E7vYOÚ)WH3 6miD@D@D@D@D@D@D@D c$sDuz?'"h ?+yu/R\>{DGbs8g-_%∴8Oq6tyh5 ʭ&뉀@ДmZp2[D@D@D@D@D@D@D@D@D@ZM@rz" " " " " " " " " "Ц$(ilh5Y'" " #~s׽¬EdD$>s+" " " " " )H%#" SNa$ДG[֔61scZ ? 篻HWisKy=/GkOCg\ q^ǠuWoV&\D@D@D@D@O׸į]AD@DvڎGdB/Ys{{R 1%]v„uF-ss=+w978E"FO WD"t " " " " "P/͡\/9'mCC=1 qm^plehfp2ifF:MZW/ !# h%})֟ל ?j~YV" " " " " "')/TD`UeL§7Ὢ0 dw?:wjsupO`@,櫸–VD @U`O0yos" " " " " "P7,^Õ{޵~e*,SBcNާ87'?TU6>u&>Ĵ7Uuf>~mĪc3۾7pHKW*UG)Mrle_J^Fa6m/" " " " "4EއOH{^FI}/rCS\j]mI;?\Oޙ}]-ZEKk(WBWǺٕhYy/n,){Fk݇H%eWG[iis0qμoc[+O1K#pGCaVI?tg&?{]laB:#\:ZDwkQ||1VyHyi \C {O,Xi2Y}WIYsZO" #O}vɳ&" " " " " *a쾄HNoDGtDIx nh#9XLvVbN]B'bMa+fx2>7d-bSLM*%^:MlBM[}פl4=>/doD'BgV8"WccTLO8N,f8AX1ٟLfs~Ĺ$&d 8ݔ`?&hyEf[ 2d~V}NaVzzϫ#x̜|lH@ S#s__ qd)f/tnm5BI(~7mIAx0 WCuƧt⭬?v~ >aʇ.Ěm.}}"G87ϰ6\ [[̩q^0I|jkO6i"@}$Ӂ v|ldU^rX`Ї ޗ|",Bh+8yOUznKߎJ܄v1o5{`#ן„ufj|XdEщX㵜tj|u|^9XܾchO>?k{)9Y\܏W gk79Yxך 'Flvk5ͼAp1DΡf@IDATTYrr-˩1Sdn a'By|.^ť_6'hϹ@'.ߞl?|'\t9~}f!l{Yf~v}jjQSCD@D@D@D@D@DVVx}x^0q"l#ZsDI|hZ:u(&)#\ _v3Vp5ݎuEsq^Q^(v g&_QخOB N8żUq;ݴۅ31U/Xbs9·w# 'WN.-`-ZV^ WHhH&i&S$JVD@D@D@D@D@#^TwrQoɲDS%'cLiu2mHĆB|9SC9h<5IX> [ZN x aMLs\??vq\7y!,5f ?m3&V~d?a҉fg,Fv0.+P -E@D@D@D@D@D`'({G3S;܍7r0QF(Z:\ljI m-}71s}cfV/o j V3Dyyȹ1\ҡMv'-5kZ=;66 "bϒϭqOZ.{Nh2 ~U…8b$VUj:HD@D@D@D@D@J4((3~ܹ3 t؇t?& ~ZmYKS<|p sD#d16/Q~}dFnXk+m̚j$O?T%|kr/7]w5t ҡBlੜvH LG"'taɶXM|pvl2-\"g?WWH{.%" " " " " e isWc=! @H(㖜tl^Gh' i9׽6+(LAda->V8 +#ÒS>pjAl@k5BႷP0sZ2X.f\b3} 3Gf8ccsB?cI'26m;0=K̠X6WL/c,*֙0l߂6dE@D@D@D@D@-eREd "",-νUYZ:|ywMId>Ʊ8wEeفhKS;ӝ,?p.S]nyħGc>7Zbquʗ7x_C- |To5'0' SOܤ4@"\ei?i Ĥӏ`l{cN5ٟI>q܈൷i_M9kXZBeVc<]E \SzDHz,؃)x崛 sx~$w9\b< 0eba } ac2%~NqjBnp" _ƞG&$ЌxA,h$kϫ~"ZC /P?OeTV2H(Ci ք<8T0Eko0&zBҩ' FTG݆ wAtK"T+*&L="-Ɖ+2aiy#ɖxs$N ?^høbw$?8v6,i:U@pQv{d.H'DŽ7TYlמ:y<,cU 8ajgӾ ,?pMw+=:яY%_}6]jkVy ?Mcer/>g`^Mm=|נ@v D2z!<9쮬Sw>anQ?;s>z-ׅ$+ S\IyOckb:vv¶*= 'd _"V&V`> [6d _QM羋@h˫+n3}AimDy/)L]Z{nQуGbAнQN:W ܁0;T#!a?SB/TAc)S ;i}>&i=y6,kWg>S)MSbZoc-Ih o 3& [D}cF̼7xZ!v[IgK~̵,+N7\B #vs1M3Q[={ᘋ 6y'N]]Ee`l{׬;HglV;78A.}5vo.r`ĹK^cLI cW;9f,?ȵ>c3oN(ʯ?YE(-8ryˤ١Tm>yfiڗ~~ x?NۗQ'}~3gŶ߇\|Txx?)tExXze2_e!隯NH?؜x"]ojCULsQ vQ^xݮsaD~o#$t]gddQF sd\[Gx%e6!SE@b JSD@D@D@D@D@ ӮH!hӜdt# Ay#" " " " " " " " " M" AI`L7[&Xȹ?qE4bJZD@D=|عӝOǏ9b{-+E@D@D@D@" A.lNmsÓ8.~^h)>|h<׏:^>btnbwwX&=GjMKy9=/GKCju>Jێf!VQ۴C͸B{qR.CU3)" " " ӉtestO .ǝ;_|S_.@ c"8s^0;b5oDMȄ.;aºp]{V޹ԹϕJ?Gj2U^iѤ24)J>~0Sw:8~T:NnS8w眼 ^*6ͫN@ͨSnv>_Hob) 8fQP |zL؈Y}V Dd f]!ZVN ì2}L!wBoNHP4l; S!]GHx{Ħ> SLʉK`s<+L@̈^;Ɍe2D&05;`뾰9PK뮐 9^9ͳ1GpxO3#'cz4{~eCoF jSD@D@D@D HPn" "l# N`6{&dONz<.Os O>96߃xcްY?~$(y|(!P R0k`QDYW1gys>9/"~^9xv WQ/#3J4G{4]p%Y]xG5\vկ^y9Ν>Ĵ7Fz)+\ȷitVyʿp^wIz=LPV)pj5/nI <ع!Cل֟B=BiSHxe-o=7̃ 39?7zعGec{\I?1VUw/ynBNn(0'~'b=H@Zl86BZ#\:="XZR/;_!WUJKxI5?'|)Bt6_MJ3ʫ4']LS\q}E%ip^=3@Sr{FG.i6ޯ%_^|kyo[ t[Ɯ;7z24q} so?X11ߣ̅mύ!nr=_;rN M>U!iC ԒN1 ilZ:ƴf>XL֟0W}rnά.ldoňO32By~2.'&{& (|0$]fN:&Q+x jF=R'NK?u<-ϭs;9&ILts'ojA{h6b-g0Zկ66SXU?䁕(-=R<ؑxbOQ3{Q"H'&{5}r?hgc?h=!85 p'oĉ./‰_6/1IFXR8Eǧ\^O6;QVjxh:!#<<йCҩhpx+:oGMZ9q{ 5"6B4;cMXe<5!C=x 8<n]=,a`=Ez%=zF;Qn 91J`u^_칑ҨQOg +o{57vvd&SJ  X!cF#{1G#iNeF=l$Huic(/ks+_bj HGgu8ҿWkK#~F^l`r~|\=x秧Ɠ'?hLl;Q܂G3q׍&S'$W|z~{h(2Ӣ 7jW 50/( YE@D@D@D@C *$[6īr{?a֗v7u<| AWZ:V6'־*_s,?R{_|4/0xfEԉ[P=j1!?1vˈK!sCSTq8qnBIg5fJL<מj?;EJo6M>catepg3+&{1V]km@L+C#Txclt=J#zhSuiúXDNJK"6feNPMiq6@y\Ñ7dde=KL$olx g!%{^~.ިpA&z?-jUG{ zn]!Z+" " " " mK75aesx | gx@aߝ qZZ:5bx0BL^/ƊdQZCyLQmo+.ØfvP_Ds9chӗ#ĴJ̙tjm雜R $y nF~Zo#0y3qEޣw޾}o'|2{}BbHztĄ@( =??*c $\@^蕠k揪kZy%\}V"a3ӯXb7XZz:S'g1B_e>܊Eh?*3Bs!.2Dv"s)XJO4NWKҨ5UM:^D@D@D@D$< י`˿dYDėrZ:lyRY:.[0wt#:im_41s{++;@^׮ M R|2/v63&V~d"|¤9+ΐY4S~P (2՜9_߶+ҭ}{*6ŞUwa9M7"_(6--" " " "Pj*?a%w6KpS0,ŕkη7fX}bA\E'rL8ڟwnSCf0%|7tv̥Ís&5zj^ї µ$1ЀA(?wnyn{F?N>w>y @~ҕG~-6oSo$u 67 @Ȋ@])Mߐ^_ߪ͕cm;$oz˱cŦ۳>KNX*AY8xHIbk'#vCc+o8ɹ=CÃ{5'[Δ\FkZ~gmT}ks)tN'PX(?,f_>OyZy'Vj>\ H]t>V$Q;/#Q8uXF ?OHJ{_hyٞq@  ^wٰ%*!dTїPhT} oYY#qyD% DU1Ҳ?) onT[7I^$ޤ % GͺF)Y,SsVK(TTxY{Nm\z? 8H= / '-"|j;MZfr踰`Lj*fjSpGm\cU8IJDnxnrM]=9RAZl&ᙗ@ 'Pox UÇ v5W#E '"YzX&^(.N TiĵI1"T%,rT Jw½.PЍ隮xKD/UU6o7KV̋h1<%_VnUy1YШ>3oPm%rg폽ODq\fUifYw/7rzFI[}mژz>#Ҋӄwm5~s 6Idڋ֨-XGV fͤ.C.>p[Ǫ 7Xw=q*Y)JHe)-~@T SǫrίFk\9v @ԏ-^D/BX#GXp/jxxXZyߜ!l WzB#Dz>M %>7VdJZ!lg^;SI.a}qch b2 }n[>{cIw[@%@,W;E9MxyYbL H*yЮz H_EMWŝ\c]$VzڨV7Vwu@Н8}ELؑr]/ ߰9ҥf|5jKw6h;[O۩>Hzny`׵ St*V́oV ~5!}zFTzۣ(so\^'6{ͽ^A L;!ŤNF5p_hᴚTkP,ǹ :0+rʮU5]] "k V_q#(z=Hh[X "Iv ..v -Zփ5~v~ cʉr?U~٭e6^pбBY5ۮD'Pv^ gۛ|pRuy<*(+OKS6~=ݫ8҄?YPۧE~u/o! e4&;K+:2Ol$I|9*D1_yxM>&G@ z ]ǹzdF^r. 4ڠ:qCQY BЦJ.[Ol^,Ųv*; ENdžUμQ)*}c*kIKk S_Jd2-{{f\B6[m$o۸U_Иs~YK}u݄Wufܰ=W".x-pn7KtIӘD/M v5mls"{S$W"`TpmQ~k7xe.YWqnp@b_ҿj۔Ӡ©T{;C{Ui[Br3։kz-Y,%%kkjUieyiWbŅO7'L#Ģoc}ޠvzoj~yؤοDwv@YNN-Q|&cQ߿'5ɐe_=e9Lp @@ (?K}|*go7ļ~k꧚ii,Ka\ (*uwbY Gv>Lw8Ck;kݫ @83&T7ob"c# @ HϬ8kTqz]k>cO@JXkd| br3P_/ Fƴ>&hcYS[~""f%l턻 +8(:~KdJ @z!Y'k|hNi@>P|rs6D;78uO~iR0w~H߰z9-Jo>+hW]XUyݷ_x玪]|Mm]C}cJC&Gھw) @f_P9Rܩ$nZ,!fΔcqL#l]'A;aLp>Ϲ7zۇ"9rXGKGwz\۹ɽ]Dgy2]%4 !MhUФn?@0g]Z ~ MV6U  @ 0L5/l7J(%=d{+.(ʈ(OѮv8f ]O3ʖ2۲5}pܷR_U῿Ъ;&o>> ޠ ʥԳlV)q= @@ (!TKjd% 6 |c(ACmqmhWcpZ$E-kwxaCP# @ 9eoe0Ah$§ڡߞBd}˧M҄,nHQYXWQozt;5z}GT~GL6c!- 8/*U4J22׹ʃ׵ M~IKVp)nPsoU~X*:]Ԯ= JmDeemA=˾ڲ6it*?Z2в"Jϳmf^.Ms' 3ջ9j#dt @ gTׯk|M"@đ/N$)Z8 ޔ-K֎Kz!poRߝw"nV3bķdx?e/u6/ |svɳJD˴Lti?+.Kk2~!1_UF |s}~p$es&?=)VE`;,NWc*a8Njwi}bĩ8a\W $q<נ?ࢲV.ZbwByTOY?GjnZ}jQC[VnWuo%}T]WФlcu-Ȕ$#d {N; vO==&OV ǣ_qٺKBQ]բcuJ^߳\uZe^3ԣ6FyiqMC$νÜ|r >/e?u8+'Iա߬(,%`΍&܄'.չuu.=UЖJ|YP5q咵ZO6X^-a~s8aޡٌCcەʻ]mSRWJv9Rߤoi#Z}[~bWNEU;pY=t$4 ~?hķwiɧF]-j{y;&gG95v |_I />MoMmyާ8ܮ0O6MFQ}<7 гQr^P?4yĹڞceo??w2/S.C -_!@@y #z%I%ٶRMFu-Z8ѱLtEYmOk:W= >OTRx $IVkBiP]?ѫMs%jYrhsïNbk[~]Nup.zߧWyT\.T~ķO5::d}y &b!cMuM>5|[bEprZ2k%*߼/8;{lݘˬOn, Vm¹\LpW(b'lU- wpv TMQvaXΝGoX1ڗ~uӟsז{!Viϋe_=7eQ[m"zPDcgTpe5~d9Hfӯ# @Lw#-ϻA Ħ| 8J `ڋy5i7+^8na>+&x_cΜzEzY!tHi+&T_tm?J"f I8]$JoԶK ,:΁+-Q.^#ޥvʊ>νqu:5ڿKMy?ɴ*1S/8P]~~O$(g_Ak~3(gc& jU@'բYcYWl)-SILۗ[ɠ\ϋr CsZND#-ӫUfd[f\`n^qˍ0>܅6}+&7oJ| '䵵 +*"TINcliF:rM\wϬ<!3@s'3 @@vN~x tTk .u S%ފe4^M?q!DU %HRpD򺚊?{%hP_5 *078_7j%ͺiZkTVWV Ĭad; "S҉"@{8Ţkdeͺ IŎBAUHE}Dkys8 @@])q>)Z?YU'+GvHIޢcȢcf59 ]T3'?/.NpckMt7V2 QjNRys$&lϷoo\nLKGs)tN'PX(?,f_>Oy`@y'V?}7h0o5 N[O(h(߫#^;,2Ce/ @]G]-QZ%J8^#<--)O~KcUL["pCVMq/MyTZ7IҬ}EM 9f=ͺF):jq} zZ.ϓ8H= 'e_>NeU Bp[|xYPm4ϋ7/8,Ш v<}_8aЎ4JzU]22A L+V*>+ duB1V6䢅cVm N I"~O'e@ڍe_T74`و#NWD:vhd\V?s㱑=,D{ix{yZXI)f __?F{mu˒ju1<V$V[V<5he %ps4u5ZVK+ (,_X2hU9 bҧ.a`:ʭ=NlZ [%#6~y$CNӢ>/LU\\NpyC ܠcԎy?wJj+Nˍ gg8 @LP)%A\-&?#K<Ω]R..s4gsMxVhkKh_U]MkhY."/4Rҵ_d#EJÐDA3ݲTb)~X~GNZgim=U/Ov~*;UkksPzCT2kv[A1PkSe˜ Je3{&>FE|^-$.r̳r~Իu3VuMk> @m#`o_;W~(Q勯hQ!-8r'5`ک`ze}r=5/!m~,D![dU5G?Vㅚ\y8d@4+&kstJ5۱yݙLv) +$z 6vU/HT\=$Q>KUO,_I6&*7Oˁ/#Mxyu &9eaPwpic9;$./ Q}=[3?%qEI⛧C}ZmgRmO=='\晑g||ؙޢ`}1cGmoE= d9@#NVv)MWdb0sr6fWA L;StJ1EK"-HfxPzPNSv=oR?oW$X)z@Z ;K5k@+Q}5aU_ʏ9&ON(_i#Y> o ՙvK{TEi%.T+ z[v]⏤}1~H<5 r9mKpjDLj{ ޯ?{]Zだ|DEc>̞|l!@@7HuSe]qe~u2 @ʚݯo`qYz.l)Ro7Ho!eXV(]Qw1=j1>urz/0UR"s=g-&SL86JUy|eEMtMe"ϖ9a1[C'$\[7qú\ջ]6&xn7kRbh&?=D͛YF9:Pv|WmRT#c/?0|wYE6^l&g&F[m]j3#uy8G%#z>o[ N v3ϖL;Ysi:ٹ4bp$ @8ocz"px<̽Chm[q.)/O(YkS6c}_l|?^M/$6<|NM*QtsghRx-!b Fkz-Y,%akjUN]B>KaW&WE?Z⾃΍$9Z_}Z4}M<4!PH"@ @@PΏ-!C @ @Vd^ @ @ 4&ܘ> @ @ @@) @ @ r"Lx @ @ e @ @ $" @ @ @A2@ @ @ ('„'@ @ @@P @ @ @@"ʉ0  @ @) @ @ r"Lx @ @ e @ @ $" @ @ @A2@ @ @ ('„'@ @ @@P @ @ @@"ʉ0  @ @) @ @ r"Lx @ @ e @ @ $" @ @ @A2@ @ @ ('„'@ @ @@P @ @ @@"ʉ0  @ @) @ @ r"Lx @ @ e @ @ $" @ @ @A2@ @ @ ('„'@ @ @@P @ @ @@"ʉ0  @ @) @ @ r"Lx @ @ e @ @ $" @ @ @A2@ @ @ ('„'@ @ @@ @;[ysG5ϝz=fk6JX~oy|m7uUG%dWKuE7pnBCÛJm/XoҸY esg\u,iXVvo( ~›g,_EK)MPHȇ6OUZɺ<_-&%VWVn#V(>AgRᏵRkojϾ͊G"T~ܺEx7 =k+;5U*bdn+U 'Hu~evBͶݸ$^lʷ ĆMz+OtGezuIFL(~{EZy>i|qԾ_ո8JϯM'g|Uv'-_ @m=n>Nkkox^}0} eLL"f7\X_YyT}K˅f\=g+?pq7<߭_?zU;0g᧓lxv?KmŦk(uݩr\rƻǹ7v\v{¹m݀Y4@Sw: /(6b;3eu^B9g'~o"t`%.'T_4Yr=kϜWXRz Gk7_:RLWVmçR_=:䦏ۀI" =)JL7}Q^bv^X/if9_:JΨJ%ҷ \=Mr~B%6rKTg+_i[q7g:i\pYq%[QI }HV;ޘQ#v}R5 qHlRLD0^C N(޻tCoԆE0:?:CC,VS1 >jWk+=fD%! ]鐍O_qx<Ͳ<>Fk&.b'Eۤ"3,?gO(+OQBIݲJ]S%$Y뷭{Ug"Uθ^8l֔׆jV,WMfNꯕ*]YSJsmSn72ٺ+nYMNBJ=?sn8]3]W$'u%wTmSQi{~%~.q9}qqS"bn׺^͆_bkC[fP/JW(T7*m~&W:|͙ϯqkWTai. @`0#L ieݘ#]Zcuf .?h7JS.Я{~Zracoh9:z{eɶ@Sgms++@hIHO'_nsM _|cFޏpRTB2q]#_߱u\P6^~{-mөCK-Jo7uoe]߫Co~nPq3F%zu4Z-? G\ZmM͑4MrMn+MI܄V+teN\U1hڍs0U:26gv(]m :/$roIYv43„#.kק JR?uድwʾUDjv i64o^qHmhk 9+Kv<}Al8Soe,?eDue6,RSr:@rO2tW}t𥁀dQR%&{/- *GA?<]+&S#/-'+>KN I_.pռŕ+G5G ˿[& ׁ-6u1^c"s侮C&qƨkc#b1[&^ )fdžcמβ 4[n _gDѪhhXLХnNUg381i:f5 ܓ!Fqof(ƹ!۩}Z=8ZwD ,GFW|Zh`hE:\uWWS^>U2ݾkmNn&1{nܿՋ Y{ rچ9C5U:L_u,I/mei7WS_/_sI~=1DN?^̈́|o /2i '>ԉ~y*URi?2F(Z8SaKϓ+ꔋzwGZ-:fdwP{CAdK[/NWMܚ8ЎQ՛Q}x䗍0^Ĺk@2xJ~cU*L|1f`~nczc8ȽNߗX/@=84H^$x~+qUYo ey*B~e]"$2m=7$q6cAe:n߉EViI]~L$؍(viE*uɲ~չMGNί6M}5{iN%zӨG8YUXL9m{&}Δn~ź~_/m] AV@ .Z8Ad3V}yrbUڝF , ~@x^ezrcIK _R:]5ߎ}IL=k~W{_I?@ C AK%/gfO }XzfSM hVF Jly5[W-`aGm7{sys4x4}뎄yؓΫ<%*[_Y{WNU15ί˫Wn֡EVɤNy|eDd]ݴ2ɯ67%Q47)sMM(DȶWӄ% 5^0bE4nb&+E 'h9_L/-7.K`>ϹGjn %}wz>Yp&VEQՎ4=> ڗVr@/z̪,4x+Ef;vC2EO7W'seq^Be{̤O /\Pc֣vvP/`Glmv{*PfVVؽXj7pUocpop2Bim'Lo|xwXYWNjN)s|qTG$,j|(/9Gb~U΁̸/?Ng5Z{3lT/v<OH9o}ҝ< 4 P۠%Y/Zg;xi[&vOK<*M+dhzkR5@>bv6#k9 r+EK|5]==fNmbP/f9קlj7Sꗯ5nm:>_lXYk_"W׫ r75䬦|鯾]^gͿ6Ps}Z5:'>4l`&ʣn/ՇTup#(_& ,s㻵GV fQ6$~VVI3%Oi fY/>g?Aw1ϯ?0LRϰ~u]M͠Y+pdžL_i M40F8K|W!x//2+ql)/.wO_05[>^Ohᄨm\ -݌2,qH)~Ϝk&̖fT/JW9e?*fPSU1a@ 0 hт >ѯ-85zBV"5Yk=CS5s#XA_] 3C3%,]T_?[`+̞qò -Ĺwi;(NwWkSp,Gr>sF؇/lz<&>W}m=\/R8A3;=/R7j[TwzMjtA}Ma(R<5R=TnYfgʺ]6C*]Ysڍ-vcH6.pN[<^&/p\ pwcI0S{|Sj-pwH}ȣ*SjL{=72~i׼K\9 ic;~|GnXn8@ Ѐ7qڅJ}gWSs䴩sj>$!Q?(P.zoOo@>ʭٹѫDl~lQxgK\VNq ii ƁqRmO(> ޕWOmd1u̩,*UiZx@ ePP~WqIl+LؑD}T7s o"E~ʰ:~]4ؔ)J8/P7>JSS`W^wc\Y} j- 'T~Ue{ #}z6lMOE魬EgoU~ڲ]gnz!Mbnv5S߬ҕU8)P_+¼gj,[s[;#N8~i2 WR׳f~Ni'hegdߪy;ұ P{2Eӕs0+ܟkd׫v=PP/;jB C t3nxx:HTQ fWtJ!H qi PZ [ ;ZhSmc(>2>?>EyŻOQ.2]Q38WD@ASoXTQ'M}JU9,ST xl:RYAZSږ@bʟȲ~.eۦo۸syt0|Kg^A@3Qs)&֯z^Z&7 [gpkOf+tj(Ի旍CVj5nx ЇTUqFngku^7kgt4.pRauykqS6WpL"ۃm߀9j+cz}dɥ7{/;TU3TieXڬJCpRiIRxxh] UgTpɸ56eIB 0cx3ӻ`8[89ԉyKⷤmM[qy bÇz_#\ 믑׵זtlQgiz]~m _w{9Ƚ4@.Md*ϴ Mw2ϴ_ 9ٛCFQ7%sn:ۍzߐ@Hn9{h 4۴*opRޞZ$w,䍘-)&˧kbYSu5N˟{ũ}1 @*+(؀ @3@lU8ĆPزȹ0@ke>V7]ӕe~ϝ\f/F%qY HL1s qɝZ)4 @@P)B "*@uw!7Ym1%R/A =^;&eᲗp   @Cxv{n] O`L>3.d]/:\ >T^Wz;1򎕅t*@KkA Nos:n6uph7~>-wQr |_V#펄_Vh2I,w9;EE? kE2AGAxyB @ @ K^2[ @ @ @P.^#@ @ @$\l!R @ @GAxyB @ @ r!HA @ @( 1 @ @ PHʅ"@ @ @x' @ @@! (2[ @ @ @P.^#@ @ @$\l!R @ @GAxyB @ @ r!HA @ @( 1 @ @ PHʅ"@ @ @x' @ @@! (2[ @ @ @P.^#@ @ @$\l!R @ @GAxyB @ @ r!HA @ @( 1 @ @ PHʅ"@ @ @x' @ @@! (2[ @ @ @P.^#@ @ @$\l!R @ @GAxyB @ @ r!HA @ @( 1 @ @ PHʅ"@‰R@IDAT @ @x' @ @@! (2[ @ @ @P.^#@ @ @$\l!R @ @GAxyB @ @ r!HA @ @( 1 @ @ PHʅ"@ @ @xf/J$isO<Ϝ'8"8rn4؛>oα|( @ 0 (ϼ<'yrs1:;78}.Q WKž̑DWYp&vTB^dG51j/3z>3:I< @ Ji'R^@[ ?_W0b{wJ ws\ܪ&8ݳ7LN }t?c__oek]udέm;ȹcj%ZL %9 @ Јr#B͞:۹f7wնAFS;KzB׺<V|Hr\EqOgG@V^7"EΗP ڞZv7IP>qfP}s S-r ;vW" @ *>*n~@K&صLK%| ND%;GnŨc3Y-> 02Paq7.i9HD~bs_[X+&{zG3z dT I7KI[n%7Odф @ "seiSz xZSw^Q8K*l-&+C–ːvYnZwƖĻUܓo[fZSres7-r%Vzű~ _ƣ7=or9 @ tnJsq*+խ8۹9c~ YbSe/w:9@Z'O;:z X"œJ9 >Bc.p&VS )lA @t'М҆2NluYT3_d>&]Yn s߃7uHB;XIPxxp>#QҧT~45|5bڃ&ʲ<\Dy!3/M~`s| ʦnKws7d|s~6R[:A-L3@ @@,{~D,&I{R~g=qnꭢS>X(:?ٶUO s}/etmRA2|>n1nКqwkQĮKTSnY%HLiH|@i̽ԟTzWYLaF:= ^r=k8i ps"XMhIkDP]_$q̋qnBf1#H"N(sJUa؈|&3 *7Kk@Oy<$a mNݦJԥIG/\%!OHX]z2JSʫ<89ݹuB07Ud}N품+\6Gw8oZ,{uXp#8#/k nq閜" @ Ppu뒋$}Iع$4rE 'U"rH\z$|IR\" a7/E0b}ƖNj.zS/PQTdI ὖDte%&{?=xUt+n sD;ſ&ׯ|&"-wI oerZ}1ه7_7 dLRԈޟkUOn{z/.m~Ŗ[45q br4}z-sL]O:'19 ~y*&| =D @@&Db]HDNBO,h4pg=ʍI1!+|:I,daϙ1m?kj,]/r>%!FCT 5| Q)/[WtUG^o9&tO#JHs(rqJsv"ߏz!Y"?Th% [vWy*%&\6eXԈѫHV=8]mIeorCUVէ_0jw^4efaef oB @ @AGdas.SBlkpS%H~USICA7|yt~R-=, 2; a&zQnOo^G,(OVWY:Bd?UEeOٵ`u1YU^nʆE:^~6e6TFw;Rurr>YT_N"߰5Ռ&CU|e&>pJ߅!>ʯ[Un~(g lߚtN eym 'mS9R*]eY{nxT~rCxs*'R%(Qutf Q @ n#Є6SVg0'r4B/Zjy VE u ZТPvϓ IT„?k!.xc*ٲdOֲ_:?&VLg6 ZMJڮa1هYb[~D+bdZy=&1/p4܂x] M/Kr.?ǢraeP@wn5_>˳ $$]L)`/oMp=^ n]&1u~\6?XqjOL.|C @ N 06! qϹ{_󲠬rf$H.2;lehT"V f~G'W, W_KsCNUq2!arwQ:|cGWvY%s^N)eM.-⾧zDOʯ4q״9Mclݽu]8 d_lRߺ\VdG99yMJ!@ @ sJTYVcZ~F|GyWgN%8,Бy{Ky9X5 ;Kk Kz#Y*nkb$FQYtߎ ѥ}\\*+ӵTfQYCw K"%hb\5F_WoۑNo+<PX{0m~Ն͑f9gs׈P$Q'T'Y)Onu=ehmg!̘& @ 9la>^~+qA;NN šJsUk%N5gEU-L]ɭL]S9ZEkz,r%Fˆrlke{ @3H0!r4_Z2$́󴾮ζO(CI :ݦ9gz6iNlS~6붎cX;|f 3g@ @) X(eN媬lOeuBqKUUv}Rq~}PJ}.U="k}P^`yf+8شydA~&7wX$gp >q恇:1˰ԹG;O @ L- >dIJ bC4vH ٢5cĢ3Mr7dHh]tLx9Z_~G*tVNjESYn{Ź*R)^AƁ{AnRXZ\ ZyzẪf`,>y%>=m% =kW?:s5s.G˔uxyd,ʒEa'W@ @ӖQHZ/YV_`VӨ,!dVpɘnʲT. :-U#HLW2KxA1K؜ﭲLR[V0yX9V$Y7ibǦXIJNyүbmk(}mc_0cZbɻ؋'OG\Ĺ} b3_k|68 @ t@Ą%BF$.Z8u:N ["7{ZRv,^GR\$L]uʟ`*tPٵbj[N ?n % .(Z":G51 .rSTy!x]W<#4֜@\8'uz  q*&n!kʓ(=. աk٥3tSct,Ů_pncDN( Of# @ @@@V K>i &ڢNNŌ"5*Bl܄ Cl7FM6pV͏Nؠ9}pTU?&{$֔]/1`O&V~}պ}IKg 8WbeH'a4c-5daͭʾ&9VxO2+$(]rʤUzwvdnvRI2'w視Fh|a0 @ FI"%ZuDw;w~¬h$M%_O*_궳܋OA JDNZ~=߲KA-[kO;+ku͇gIqnE! N랟9#ؙݢ]R- _91ky1yke+)oP걿okdaNuVh>^|]/yu8u޻r*u" ʿkQ~d뵞rؽfɕqñ> |>@ @]B1_/?% ~(8= hᄢ%i%QfgHwLD-%Hw}Lؑ/ P~LgN@iru~wKl0)e:'%*^G#Z֘u| jNw"Em><Ebv—[r1;\f=KiUwQc8p0nc5VXU!EFai]Z"Ej5Bj7V[G}nOwr6+h.(/DZ+4 fcm;s#fs99y{?pħmkij._!-g\l24nLM ޛݰnngفrܚCs[_kifEޛe[9Fd1kZ8?a\-/e0bsy rn3z/yYk"_^;˿ΙD~D|PzTbS=4ƃgc}\{ e$@ @jԦ]ې36gRӜ=ۻ.|%08?+3gCk-ѫ%Ad(٧ay>/mwG<3Iog6ɸ'yY7 o _IF"|4־n2m1 \ Փ=%F]?GuK kٮƇz]ܲNta*$@ @(wUh<fpܞ>t&nM=@ +߿Z[Qya Sh{{m18Rf [|i]k-F/N6_q:}ti#@ @]XڥzUKZ9xeb}<+dYO-gXu C!gv.D4#}pL2l~w MI;qAt~&G>|_zw|A  @ @`PEw3w6qx2\Ija鿘3thF\F`hf(_-\`ӝxC9;A @%3Gi@\3v8C'a\2~/S\U$Sζ @ @) PaFL_rU?2tz!T ޯ@s[6Wž" @ 0';>luUI˷dǟ>1ч6 A`珍 @ @`C7:D @ @N;7P+ @ @ @y8Q/ @ @ ur׉݀ @ @! Pq  @ @t]@ub7 @ @ @p,nыk">,t{LģSm\ @ @h \s͝~\1nc@ E  @ @ @-XbNJ09]{-' @ @ @@K`4f(+ @ @ @}fvۋ09A @ @ @(oH}6Cž" @ @+0܁KZEm* @ @ @@(o0ɩb_ @ @#0[q֖d|־ @ @K`xg(ZU@!L.@  @ @ 0o!|S#_Tqs?8?3gl_\34 E @ @ g۝wڼ[;N)Q`SL.rM?x@Ľ?wˣywo_Zulnn-g/7rӚz%@ @ rWXUM^֪|]> g໶yzHW"^ȥ)Id~Y>ҷNc˹?Yi^ @ @@P*;+#\`z{@6]wVr93Og@9|e35vq3uy&g3.C @ @n w_(ù@-uӏ ksOʛro26h'2P?ݝzʹG^Z.11%@ @ -NV{[%햙A38*5 +nUعz^e.&s @ @: `r_ET}mNکԲUmwKDʰuiδ=[My͡6 n.t6SUuA]{3/ߺff}{ @ @z$ Pn%ʖMo~4݅-,?ݜQ,v>=Ac|#q=Ss  @ @O`_/ v+~9{ͿM{ @ @*ʕ459XX.ܞYZr f5pC6c.qƺ=:uu~5}% @ @=(yQtCqy .wQta>1W"PWXμdަ;#\zp 1U[W( @ @芀@+tkY/PŪDE{En_ n㶍u9;3x"S[ @ @tK@-NԻ .mq|f>wk|wğ?Xvֺu'gk{7[LF @ @ />%Kh*L`\8gUpw.uQ=eozBD|?`hn>߻ @ @@]]dsلÈ'j*?DѬKb< |5@(8q2ޜ\}*./?/W} @ @h,[Rt"ί!?س\Gd.&s{6^  xo?7׷s 3k?rH @ py\V;7Mʼ0bq\x @ @(Srr5r =o @ @ @%$5x4B @ @ 0SCfz#@ @ @ r  @ @ @`@y= @ @ȧŹcy{|yK"|1q?mpW @ @D~%M @ @Aum @ @ @`4 @ @u(a @ @ ^mZ*v>}&b|0_Z5 @ @U=oe1_ӃvG]KFou38 Vѩ @ @ PΞʟeܫ#6vmķ3P߿9byO{  @ @5.(3m.7~MTI @ @ 9r1#UU]:2@ @ @ #G'|͵wTwţ\U @ @@lv&Q7"YʟR#و @ @@yzliXKZ5;;k#N_YrYvWqn^kZ[)IDAT󽴳 @ @ Wr-\@RVF<9U}3]\~ޟx#יž" @ @(P7N>zgu`uh,m]6vGvx&g"rf_\ː|Ո-E @ @" P;9C|d܉mת Iw,G@wouxu;#nۧ57J @ @@ʗ ggr좶\:Z5zgkwJ$b2C cc^|7N @ @ 9[wͷ#2~\=ޓk"OOES9<\Oo#@ @ @?vwO_!P޼5-y-rY&?Zg"nF.3ž" @ @(%3ge FwsKZGhtiw.uQ+=Jo*רW"A|s[}]|[s+ @ @}( =gΖ1|b2h0ɩv05svdĽ9;jT;\ /]: @ @B '0<ٲmE6\!dA:\8}Oqm屗>ۉ @ @t_ o}3DqoZdqw9k9g88= @ @ @y^fGR>A.ǐ?yuNPoXc3#@ @ @ 4b~weecD?dD  @ @ pQ e @ @hK@ @ @ @@3@ @ @m l l򈛗DMjN"@ @ @ /P~݁ @ @ `ɋ @ @( PQg @ @,@@4 @ @ @`֫@]k"VΧDl=W  @ @*P8>q>>K{Fuh @ @ߒ@( @ @ @6 kC! @ @ P K e @ @(W8@ @ @@P&@ @ @Jr% @ @ P K e @ @(W8@ @ @@P&@ @ @Jr% @ @ P K e @ @(W8@ @ @@P&@ @ @Jr% @ @ P K e @ @(W8@ @ @@P&@ @ @Jr% @ @ P K e @ @(W8@ @ @@P&@ @ @Jr% @ @ P K e @ @(W8@ @ @@P&@ @ @Jr% @ @ P K e @ @(W8@ @ @@P&@ @ @Jȹʣ80<%G>8Տ' @ @!P@yFz @ @/`ɋ @ @ @` 1LI @ @ ?Z@ @ @(0i$ @ @/kMظ&"NNxtkR1 @ @t_઼Źfr]XƖ~ @ @ @@ tgɋ+týh @ @h tg?1̪Nnq+ @ @ @`poz"Lj_<ڹD @ @}|#EgFsU @ @ "g(_=NOGG @ @ @%[2Inɍ:5;ED @ @X u^rξqO.&@ @ @X A|0[CC @ @ X k/N3NjU"@ @ @X warxt`t @ @f ,,P޼lĖCž" @ @ 5뗴,h* @ @ @p ?P~c!aēSž" @ @ <ʷ:-\;}% @ @ZP}Sq.b0Q$@ @ @P ,Wrr͇͉GN&@ @ @SM'@ @ @E oɋE @ @ 0A=m'@ @ @@=v+ @ @ @yGO  @ @ C=pxgwDgQ  @ @:,`rAUG @ @a( @ @:, P0 @ @ 0aY"@ @ @@U @ @U@<#_ @ @谀@à#@ @ @ ud @ @(wTu @ @VʛnCLB @ @h?P?-'"ԭU @ @9id #+ԭ @ @5y.Y,(\_xYuny @ @.*ߚ#SĦ#~ڈK؎w"}ߪ[=-mϽܙN\c @ @岙r=2bݢ9{z$Ȁj[=U+ 9N @ @ ,%[FnWVϕ8 @ @h?P vF>TFnd @ @ @Ir;HaPa`!dxPl~xԸ&"4Z:gdM|ϙ$v1߲PC4ZK%@(3.L9>I؇'^xp?Ø1Lq8c>0sowi KBy'L$(*ŔL )i5J/僔TPjT~SRפI KKK;JKsIo.n*+=LUR$JjzFFFFGAf@fL!K22i4'mMB@5t=I@?eN.-&RNZN_]n\\rle%o)0,R+*)R k)Ua` ]'X(gg* *+ *+*[+G*/T.Q>ĘLf s#0$IxOtm{*n*<\:*TYުɪUTj&jR;60Yidɇ'SGMCSoSi81tLܪyJ_%ڪuZ9KJaαյ%{۵u u"tV<ԥ&nmқDF>_EQk  U k э\ҍʌn퍓ww&6&|ti))eSnͲj̺2M]5aizbmvqWsr,,^[Xr,K,oXѭ|[5Z6Yﲾcða֦拭ضֶN.ή}}%rm3;dߩot=:l].,8=.]ڮl2nn\ gI_z{=yt\yzz{+zGx{?I]G w_ß_?`4\ -0,8qI8i:#`Ɩfl[6<+dVɬKB/1{1~Q$%R.rNdu(iKĨbc)Cgo;fNΜ[s .:Om^ʼ#EfK9\7Vn?ϙW{PЗ蜸%/<łWI~I''W&DԥJƥ* 4uLE9tm@qE171S r$F$Y.Y%YD.8Papa"E=e1eK/ݻ Ye5{WZI]U V]iƚkz~&G6Gs{uuX5{9<0s>'?˾>g?}!z1<Ÿ/^WW#ߨ|ke(dѻws?~h⧨Oφ||.bk###"=z`&$ދb١hT F A? *X@P3`ч1? VV d'#r 41<|y /⑑##_.cw2BM=rjm_A|m`X?h pHYs%%IR$iTXtXML:com.adobe.xmp 1418 862 ?6@IDATx tUy.l 1J uCrL9-%ԇajJR<8U.fආQ잸&!uj.Nإ I 6˶ @zn=c5k^{kK54k|$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H )KY&,B.ιJo]ǝD@" 0m>Ծ}ZfT" H$^ArF< 1YHj2Apd\~qGPH'%9#q= 8u]" Ha<m.ZJJ$DFEJ|q.F- `61hYei(P|1ө7B,|I=> -e|qi&GUW.džY sClu镨WJj.@\Leݎ16,q\9T~##}JK<q<ہki^_/v@orηV X>[s&9ׇqHg+XA$@c۽( P+1pkb,·*SH%keF1FUXRD_GU'qoќ 2D@" Hfl8_|c/HBZ TϊKI^T]aT^w3>GqElsΨ$%2|=h$^]ժ*n|$ea=K𐓨h*eQBeSizH[&7҇n]rY઒x$PX+!kQ!^iD&ҳ5⑨2/%}۸SJ@Иzd Nv۲G*Q_j6[&`FLqHy ZZ}Ɲa FƔH$#20-z. Ё?mB0~ ͪ?I"Ľenl|!h~>b%N21I@5-00#l(룘M \ H2h}J;*o>cZڲ#ODq/3@_XT7c,-ofc9+ցTӲo)5ʲ"A^$>H{J Nݙ=&pLX(ImY?%}#S;Jt5\Wr'_0&0sBpt,g+75Fl`9x&4股1KU.M[JYU{ ?NU!7X^ &&5|g q_.=)P0a^C#Q0LᆴRc>޾tK$D`"xjЄyVZ˙wb!]>KgjP\Epmj^~'zJ"8Q bL`ESJ6OlIH̩62IdhL_ 0n[=}MN98K x_ g#uc(ؑ Oz=UҺgup̑N[+}Dp΃h'*FLkhN@&E:<%O|hXA܄gN [<MڠC?#Q0M~S+4BOБ/D@"p##wޝ%0-&uy.S_d?ި0f>hm-ǝs0R7%[鑮zb~#yN>|#ߴf#84Vo|IA.}aq e({}6eg4J4W5c]onbr5C~?XPk}!>UE@MtɄO1w"SliK'y2?Q;Ԏq|9+`⯮(&f[VUE[>tBž ԇ#,@JA{.L6pRbh4:ZZ m'~LxS$԰3d,͗qa0ڠS98x<*DA'bX*1y<ёD@" YO8XICӷ^U=q);z hq|Me`v*Xic|4[VXbǫPgo+7B:h b_ZOgل֛T<7/<1OQJ7;A% ǻ0$]tVkg-sWJjOPM\!HVKKkQP|T]q#;9HG?MT2/HHƘqAO*GOWwlNETaSvaaE*qΡf9 R}LVF"n CZGA['k!BA%9Lq<0⡛aֿN IapND)Ǚ cޡŕe_hYXHI>`wsG-TqgRwdQ9_4%9ȉ~SĻ*dћڡz|hok\I~Bo89xVN)S%c[NG.$'fz7_mя@jU#` i9"ݎaU5Z0tnz6׸x1H.VэUkAbM*tCfΔ&HQ|P)\j C%;tqiBw֘kH$[yVAgZ;UlQ'sB2;8sMtI8 tڦ.ӝ:xqsbLˏr4(A,EX\qi1!FU>ϼ5W&[|1Oe5Ŋ+)T ޭ {fw_F>߉͝zK#oyTP2'i vdwot0?_Fa\'pv.h^4ԑN=fa N:i(tp`dz,;wi^!I4+Pp6jjvGK=6~`ٰ/gd.ܖYNv2IRr9 ô] z*'K!WŇ?yػ[k z6k-ejۘ 4w>TƾPEP&ĉPS ^Դ\ @tA^teťr O6h괾t_!y$"K -%D@"0DrgW]k[nW??T7z7=@8HhZ{S#o/ٺy(4A 5bjgIБ9 5etB=/ʴ> g.anL)4'x;]O쫓[+/l,|yM|3Ig|GmR YyQr YtVJ} qD93r/t_M+"%IJW1}:0xIN   윿38bn1XX"LMV%/KXkf8ڑȒe*H$eG&_߼ˣؤN 3|Mx/jiʦcxׂa4s֝9iq;z|e޶IR%pk|׊}h-%h |_Ae-߭s|3컹 tpyѺ/R=[_oK͢FδJwp?+`|#?!cSiKtn]z+N"Yˡ6诽dR}13 us86T|1RzWF5>'+5މc/g;KvtKɖ*}Af˶{Lr8#;D@" HnXK`0&ps!"a>aWtd(k =Vby&0UΧ@Ѹ3bK{َ+w||Γ%$[odžq&I%#q{[QΛk@,H7hih"dG>q; xq'JXL/5΄, Ҏ\, 0+q-D;>wgܮmc$ݵ4KeL).)|@Awvigs:-~/P`oc OR {Wݎrٞ!lf] ucWple"@Mnf*YYj2d^] IA]d=I_æY@92Efhqq Dt^jz^IJLet&52,EITy[|5@²f2ҳ'U yH7m,DR{%$ؔBfO]NUǩ`[K:"x T RD>kËŁz\ޝ{vC])FJl`1Suuz*c:n:S{u!-x$/Eg0a[yƥ<#k ]5x .*qIHS]&`t|$D@" P`w8*ŃE69d5'47!F)҈3cٷxBYWv# 5F5:/p,0]vKʹt y"N˞~.&9ۑa|ժRƞ%v]t$ipM3>9qdriNX?띡.Ѝy+d0&E9M#nP#H$D0|lPWK!6#G<n<¾ᙚ+8!23븮B\92eO!ΓH`/~B6鲌''r)6)NJ I[ճU%+\= Q &KK{Vؘl8]~OK瓦.2@)hL5rԻ-ɖG؅S!F^#hr6lS_fT$$)n(Ϟ:ʌ-"d#[XHv5-ckPsqP~SыY\V) gtRqc27uB>0$s2~\7I6TD@" u`ZVdpkM~y/[gcIba6ޯAwŭC`r*υFpnpg/#cU_u'14z[fLɳpB1Mk SnQaٍH_'V :\Dq|)_wWv7q؉O\hQ.h.5yȪOsC=Ek62}V[X<%ML{[:qJ(bW M̰~;A@el茍(Miu:~ Sڈsa p1|M:սS\;OQ7 P2ǡCD&j د>D@" 1`s涥X5ƗK\(qOt%god8Xjc os!~HNbcaɬk.\ fXSfL $JC Zl3-F/܊ \2?$zoL')Cbqپ/ V`$/ŭqip1Kq^~X!~$; b w_zI8ԳMu LYHː﬊*Ḵ3a#/͹T3Qv G" H$3hHsaGgtf9>6*x^@%.9cLws7imzv](ey?Ѓ{:l,G=SW&ʪBe 񒢉~w ^⬍DM uxzElᤥgcIE$*6ǹb2"gvk.ܩ.+qvFQEl.Y6< pTxyyV3vbM=za]1%X͕y|tb_ժesx%TH.mo/owuF^d+H(>\xC1u#Hv[GIn+CT Wr{8eK\|{)0\%բ~㈍hB;qi[<7Ryg32/;d ֳzRa,;B)"}Csl$Kղ pY"WD@" tHZzdf?fUY_޷O6"]>54%/V哖a=t1[d,oҢVRx-EU$QESqhI]&M(q{tA}`ClBmsvqV:J-dqqiK>U4 l2k _fd!# F[Xbi1ڈ%F^,X('1+;#o_[M&ĩnC wm n}`9XShMPoD_R"sXfD+d&`N](6dO8;>^;(3!P̋(axF-7GhPtH$D`#`eǰ[td{|J4uB;x~XߛCY*^!$77D?ƂMmhsZtp9z,FoZ!GN(qι=7f6 ;v1ѫAnǓXnRvfUVxԮljx0vN w1-o:fblѽ_5ﴯx2~ucED:Ie2˗I8clEіYJ;t#6<~B"Cb+cI_? <'Kb݃F%Ye@J&x4~F%'~{^ԶP3K~ gFskqga4^!~DsxjС렏{D]niF)S ϑ,0-fD@" H$ DzjFk/Vgc<Vs1^q$R>dBxlTbvfLfp`:XN+&NKPzuG;"dJc41q_x~{`0: [ %z v M6៾!64fY \Q4MA!*7@Y4D7vj͝iQsTDPb5!ִǺw_{4JaʲRXˊ/dUH$D`Ȕxigf~gor%S@t gqgT"vC@µbe1*\{ naKM7WXN)HjD`z QNKD@" H$)C êwi1>eɄ%d-V" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" d '+1+.X&HD@" H$Y%9Wrֳ+d rG>0>ڷZP&A +zID@" !@gI>JIam,ퟐ! ~6bBS3ݍ8#@g 8^EUFOqnqdpz#e5s(dc 5xI&Hɴ'VO(UMs 3a@Cn,I\K}w=bX|/71ja1 ] S%\ܜGv/z/ oC8.u(ԹB Mp:'3^8ČV__$$˴O5zfOq68Ft N93J|q.Fh&KhT}G["ɽ_DY)jh52ݶSnJ8HU3'] P٪8B{·Հ<(sj_.L5wcODIV'*6|Lo1\HK?jl-|](Lo}ux*4gӴ'(0J=*_fJԫJ[gV3e$=a6ͿM6 t - 4b[F]=zԺ"*"1v>V+UGXF\:;-W2/Z!$WҶpSU^6FãVBtrK8s8[ŘÞ+/agH r$ؤjk cSfTÍ*! tFl4h| @ oB"" _Ke % ՙU z=fu\-I :\j4\QQ?A.≏La?aP2,wDXQ.zc6)،,UeQ i1g}7X WtK֛l p.ތ޷S h d"Z]-CE#)+ghhwdb/]|;fHe6$iD< 9W 8NIªXW5.7QkME"|N`Br &!в sDh1^2u"JG5;,Ж9t}:&W[RΦrf"z(sJ86(W"*X!LhZ_I rG.pLM`& [?Yt<λF>h22=B|S؃"DQ0*B Mam oulrvźZV$*q)וJ瓏rUM˗ ξn$ e^%Xw2lsZN@C%GEP9g\2#pp1v΁LCX,T~[̌iLDqd@^&b=߶(?qf UD z #M]y%dkzq8gXe].἟&%o,tO0  ԰g&8_j|}4)V)8 UM3`FyRx4_bib?ױ.O"{J\7yt;2| K҂@[+P8! `@sC[X})0 ˽Y65پyu+p=cOo9B,/*ԙ&!Yj kJ3Rr|a=a ~*bdtK{x>yVp2ųXA%SMG,F9X]fZm AX Ony(ng]!;%cZ]aQߋܒj0YnZo+ÎnkwExЬu ǻ0TrUFg*}ԨLYZD#<7Ъ F ZzfMיFҲwۅkFDRƭ} ֎L:3RW/_"QTߌ+<3ϼiLzu"JWx]`S8#oɇ|LlX(h#97\X"_ה s 4%qNW[exv1ρh)Mhd]/ĝ6 TZeJ<<OWjČtلrYä*n6-ODWx;r\!\FΈ悶`KоZ[B׻8-#$geAc{'5̎~!q⷏2q#_$7F~Ѹ;WZ P $N=X4~_-lV*If>)L5 ={W9U({q<`NC7V; S8˷QTOwB+ڧQ@!C+[VϦ*Wm5?ߏC9x4K@,:l w`"O6ʙ%Ac AbZ|Y_lv/^a6rT $j61X]w7R!=XR֮1R7g>3O Z#x^ey fp?Ih%P1xTf؄R0N)[=B)@/ʋ1xNuu0[II@b8ދ3N=-O"EG5 /p=N/SoG"nKXXX49XenaqEcΔ&Q4pa`7q5w4K>)̈\ Aؾچe uX<ΣDH Czz6u]Apc;lkL}R 6 )SP7E2YzZ&BbHxz9^k%39')|< RH2=Q sbTa&kǡ*>߶~4GWnu)آ?Ky*>َFeآɆG a); 5^ ]-<_.=V%4 '>j9?vdj3DUaQAkj7Q-WBI-6kitz^x-e3`4\2+#!8oDbA ]xvL)j5Q2LVgp?oBՆYq}tN/0 /$ߋr4~]6=w+k iY8tD=/ ,CI7} HsXX4UU{1GKs8uՐMPd% :姥slBNn(n[pf&(Jc+ΰݡH-Xa3WsdH;*`  kl3KO̶{/eLX"DcpuW|oCZZZ ;QuUύ WWǂodZ\y;;\ xb/Jd!t4FES"z2NkСpm{( ^ M} QzTunMMÖN=(_vM4eVRdVAyuFu. ԟLCY;ȵ\GO.آn(eJ!X,ZcB4bVdyEzg_1cwp?=4dǍ6l%?ؿMiZngR~b6Z1Pnh)꟢DžF%wsUZ/_o!R/&Tb7%2R[zmU ܞBF}%^oޞ P5/Fr|%NuFD6ZJ&l_(5 ŞByGPT3c3k^agaH;򾸑%وm}xmV%F9awx`Qu޸k\^rC-w|W (,“ӘdM9[q Rf,{^ߑ'ܦެb.1_@IDAT2\,e5nM>qWA8H-K?oEJ<i2tID G4F&X,3j050Dk探YvC1yW*L]_ҋcYzqNk@waAeURavϳ,S&V-YC&CJNZAxDn"g|nUreE[[,d,띩ψ`Lp`=6D7Yըh~`G̢(b0V4tPWCx L#8r,VR OlG@iO'Pe=X_$ .>e^#oFc*)XX)չӝULNI=miѥj pz+2 Kl3neÐsĂ?-(4ѻM/6J-D*2,ˑ }B>jw .Q!ngD;t #nVIҞZ<,V~d̳ -ӗ tN*rgGѤ)$X6NTBeЎU#ѫ \zFj'wh4Mlmúv!a2y߮OKiE`g13"Ӱ|N+˨sfD2IpأS#>Š`NVTf}#+l6Se I2QH҅kxOt-16-wUQ,o )z%RS'Rgľ+9Up)SdLmꔐV^:qH#tskڇvcopQWcA1ƷT\ל':CX]'؄.5gfD2t3Ld9{ZA+y+VB1&['_%`m $L}zg2Hpf߳μ6RTU43sx-X,'J|&9 LPm%[ma΋kW)Ƚe93TTMz%nB򷜺ҩ2D`gRИbQH<)m\w5idp,e!( /dS?.RMSQtX}yt,Y7Sϻ10zm 1qxk1y 3P꽨tCnd;!SQA,.nTf4?5! $ӷ?A GdpHw)nj>ۙ`XbOdpdUy>,%y0 tu8KD@""k~< ܍Ft\\W +9][Q:|7y0_-90; Tz&U(dbD!Γ-+`/~}`8WTTlu|<gtӜselad(ÊdV^ _FɜFVT=G<0Tujtr sJn!d!X/ztСteX"rg 2z o5W:kA$ioGG!.rZ\XcW\yNPSEc{ˌ~4O : 7cA+YLpW1?!{ĺ-lp {Z:>0PCh+%7PË3Y>U3"3x ߸Bk~<7YHd Tq2Ym( :b/ U"   'ԅ3l/$6MU}?h{bYh&#oMI|¼9cxVQ=X=կ{qepΞr&MGJ%@y5&'~mill]`61]/`2ӚJQ}?3h>%lNzZ~j7Zi1Ϋ͟[K%Sx:q@;ԅG n)rXjنtS.cz,P^.){ᗬ֪ZE 4c֖8oZ\'Z^/h/jPH:p6،е=Ԩ,<[6\|qRZ VK_l>HV)6Y?_Pψ=fl~|lF9?Gmf}ѩ,LPZ=_&'- ڎf/9gʷ &D@"&'J8<|W~cXZky 1kV<-0̄`BlI(#8İ5U@"|_}(ɩD#x՛RN.HyѽhlDF/ 􋰧kqHi)V1dRrkO&V/66}{*L5_mnMB1YFFNswu} P9,iqn 8=]Z(gGXHd\ų~h> Ym2HrLZӚ*ϙk Q<β$_cD BK7¤Ћ:%׍_+Qa[ ˜b门F4`?U4LO/܊ LG47)*tmQ1&.A}슉 /x[`y)暨*M¨G Ϛ+"82ힺǜyVWbB~bU=PF{6@Gj}fAiρ(Q:}Lѯ2g2D 9yjuz ZCd(eSX {bYdr (U*sg`_yc1%Xvb嵹hMmz3qW!޸sgFA*BFRGp8KIV/-DF!-ő6|b0M+2MMI e<]FP#>~cnl10J}Y" P$Al-2:ރ.Vb8fO.Լ1h^lwDʩx'v CKq} K0n\bp4F׋DfԆ|OW k<3 pL{q~pOv8ܟ_5is&'eij  LJú>Ȃ;-spp|u ):0:ptwz5wg8,sjĐsCVD61|E[;=la-e-nXbكk"nSK K@'+O](Gkc¤4Ț~>}38_czQw]3]dmK؋zػ~iy<֎t<g}=6Ugl:%,wt)& ^+ߵ}<8\,EЋ61c}:?J'M+$4ԠLit>މVΑQ?`d5\LH4+&>cxQ HI5-%/Qd'Va,u `㣀°Ap$Kt0.g)̾ oͩ|L'.z2B'_ ,/ү 0PZp-&V:׆p̼`ҕYJ|z.f;T~֏#j<9jV^\E{ 7tIJZ͐תF-8876\q>)JR'(Mv'F G!B"X)‚OdlD`Wl?#Ss:A4b&/Dp/JqK;}*tm~p64:$z 3uQI{2rхb@S:3"e@*9w(h~)19s8L2t(/x"Zb#$x(HgDP1U:Eh~&=|0@F$xbFxHҏe e S@Rk 'xA e)3ݸKFߍS-Kgg+ WO]N/ ZveJΐW" $E@M'fa6S|tCWEs 1*H$!×>.^@;6ELAkN:.>>xYwF!0ճ #dQ0جuf23D@ Kt8/D@"  .ߍ4eLQn1[㸥\d(瓅,O^nLf|{ٯp*x\d%@&H?D `ƛ-N+`Be\HRB@1{XtWk< NY" H$f.D`fY\'+`5Py E}^tP f( 2[D@" R<{JKRzSYW>0 cIE" H[qn&a IR" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D@" H$D ț;CP5"x2 p[@S7e 1}eB=UfDCh=BpC#=~=g%g#!4X&[J׍0̲g\~qGޛzx{cFeʶR.вܜN23!V)kTI=啘B xbO5>: ~uz=G_suF+Q}lZ2Qc(h[ȷMGаF0OQu#9K`D2Y[ݘro FHW +:BjuޒIKHJ2Ad5*H d)˷ }elmOl|'&Ma) 9}Juah%i$F# LM_}Nr ^D0+G/9%xnd? c._u0ϑ+i8(_ƴ4-yڳ S'#)d;kFU!Q/cWi'2 ^& WQr M*l oY$0ūsK꺱T|4L<:Ӓ`fUelM-Wʫw(^lQ!+gjFڒ⨗b_C 烘1~i;떹(|8KdVN%ޮHIg8&XQt$rAم@H^3Ueݘ.!Wݘ.L>#(eȗ;qw̥!V)km)z*/ƭ0'e!ߖXbGZ)C7FNe.Yt7Y7o,jKKi23R֨Ff+,n%@2cVg1|&fi-(nVMQvb'(JbY{!A ,$wQxǒW"1=5VCtF&Oђ6c=͹&0$^ñw(L;*jr]B$^̭+e"1oX 櫥DNhݨNׂ׺"XQn2BkມX/\#8Ս BFk) QfwK Pjz6!4ͿӞ=u~k%>5#xGݑϝQs}8͌+ZC;+kTQ_O`,@qJTjRƢ5=$ӷ^) E-آ- 7 .A< <ց ;'.ņfRW=9Bz߆غ,7)meэuIg _)"qeh|t ֗xꘀL VUM/4hEEVP_֊? kƓAԾcx]bݓ]U8ޅjK+W=ue(4r6v!goEApƐpB^aucc%u=c䷷ Z*_u¹j757\J ,izhz2k|mX=(ePZ|gwF +cuouWKL(kjTųXQGjGy+Qoyi\|:sUz٫(=\oO^lss`XSY%PuU6 tHж&P?Fk!^XBNoi[aMh-ë5Ne*_wzJl&U֌ -Pm^{l }qvRlB T9Kxhաҙ2}K,P(`K"T}sRʛMȃH{H1tuZN}׍@}T.W=^k|'لL,ܫaˬ3@o]l`!o̹9F N)nm!j8чChci՚nr˃xy<\jGn +uC-aAR'eK (!t\r9[Bc)[by{(*Kꆞ-%Pגճ)QCE(ejt);{=6 FVSY_Y>pjڡpBd]1 d2_ogV 6-QSK:PӨFmK~e`9xڴv0AIgDZ.jw) ,tLVzf5k}reآ)bС*j3Bo;J;jenИ.CX>q<ډesk&M1?.GTՋ?/Y@#21 xD>4,)50OT錏c& r<$ .IiwX ",8T8'Cj_T-Oسv7_4i!g,Y#z t M< 3'>#9 0@uEҺj*ܩ'~p v7\F}LpZPq&\^l& RIZIq I44| -Jk{600'pӉB 4?j[?SDKKY72u=z+%> V7xphߖ2]jߺlq^6̵R8[Z+ܥ3@oyR{C3 栳TFa%2|%}~8G ~+I ғoX{9jͦ.`Q9(&hv>Q7/d!(tg! dʳeDyly E4Xi aJgmh5R*41M@GĪv?Nv5wSo_hF_H@%Nv&s Lx,"#X)J틥YeKJf[{j[= :"nLuC[L<;kG2{XR a2 8`uބ]s= C2|LjQ.]|MxD3nXnk|qk-tC0ͥLK@o#>ɠGax 3T*ŚJI>L&z 6y~GvnZu ϰo(X(44"t?􎀟f$M x2Mjڵr C31ih;.+x_T}\ңuɹ`q)A kc-j!}~SgP҆A%vr {fS!lvSc{Ƈ wqн{Y"Qzb34o-L:GCHxYiXZLi 9 /"Hۧ)oH~"S(5UU/q CjBw{(8L4Ŷ_ߔKj[w7ŒK\v gM;eoL/,ŻܫFsUm_"pUTV-LP(SoXʨJޫ dt-߁Ul¥Kk+qp-"^×6!/F9(͛3L1jh@k/NWW}ds{9|ru5/jmL'%H;D\Ga tB='5vïOӐ&=n.V__f'^S3"q+Yp`je@8Gkc2x(7ǍVh,|^ho٬-62KT]ặ旸GwBm((RlH _īoKS¦ySa44_5Ś6!8;%ud{}"m=0;zayKz`0jv|wvҮq|HL2 )J4YB^Z|7F$2_iCFq^ &2M2B6ĮbބL*g _~S'Rj6{ #~Iy4/R8hkUrF"R܆RN*O#(6"W|i,WJDrTJ0E Vh*3;ٓUʱ*LRolgT$瑥fѰhUCkLVib=j]h63밫+QU +{c1)dg ʾ?{8^+`Oi1~U2QF(\&] ^l15_ġ,QECِxz89XE}|Q\feoК2eRdzMEVkUe_)}C4鿴L+E@&`弨S0Oqi(cXi>x-Ҵac%\{Wc1tdN"WDF)>|2j1['6M&‘14w [[l]r/ eۥxF)mވ3ED$@$@$@$@$_ۃ%&Ĝ}&%ЄV7!"NnbּVXSk94VbNXCS1 [3m8ʅ3Eg$@$@$@$@$@!':jѮ ư˵`6EhٞӾPb&/6sk}PY@"2Ń$Q a<J So2\    BvOdv^G#F/@;CgXaEAoR4>Ԟ#c K϶Xp&ʨ0 @iBhQO&g|]d[b9=7w] @`EԌYTql§;^4 ݑ ,&B|N$@$@$@ '/J-*3Xӊw$@Fܙ28)+2@" _    ˽pOc55gBNƉZB6cd_?Cq'`A#Ő|14L    =P%EI^'ʁ2% J ibp[#뉘'$HVQh,d@ @`z 4Bz@ @O9fq@amd\| YE"rG$@$@$@$@fx{:0H@:=|HcY    |̞ӄ%eS'01=aaw3]1}x?ã*mkV],&+P7gul09Wp8t_Pe81 3 ~h./g' 2Eq*^5W``  DPQÈA:tT悕;JلZ20Z L0/̵:(u5>N/2e쥄I1 H ,Z3JbFks[ѩ@婶O˃m[o"1v=Co+ +KP90Ս&<mүU>44gЈKo|_о c֌hBW4݇ZWנ=;(ǓWTtӊq^ 7%e3}{{3 AUZa_eEiB⤡JpO rكZr< x[qe+%AD YE(/|rR[X|C<_ʑ,3_+ 0iC HHHH d2r\Ol@ϕ\yE|+;\/˳8Kx>oBjMKzG߄pҺ /^{,z߄p|*G߄i9jb gVyMPNLoqoLcqSr|d*bK/B4[j\}BV^*i"g*? k*2}4RQ u|]\2waWo+2& !@ѿKomм׈}i L/!6&i>DH$@$@$@$@& wfs?.ĶB$=FMgA, 9T>o=):&C0z"+%5Ԕk|o 3@ MÒ.c#;2A*sMA䵷2RU>J93jQi o6/dM#x^(fǬAl-p䢣=[2|[>ByTHHHHЛz^~IoU> [jh-Oø˵ N_^ZȲ'KFfEDD+r^ܕؚY(6+3 , Uvgb´k!@VbLTD^x FJO'   H S vt;iCXaMx}80;2NJ o.:&g&\TSG4 tB%_fIL}9Cllk/1{(çX\ș0Т4¦C-yӼvվiAY+Y-w^͸ j2mN,̗i~ B$@$@$@qp >:[)Ж|8}KH'WX+;Wee _t7|=pt$WZޫڬV1*ǟȃ]WclkS̬x0̺Fjx25Ȝa:̛#^,9KH54I=OY; 9IڨʵeI,of bK! N{b[#kFm[ϋW*Qy(G&&Cْr%y<7;NሚǡD7c*:9!N [U;ei*dSwݽVNHI_CӘO#t7͛Ą~#`SRd?0kL_f|r#L~ @-֠snA_Cl0yyIVWCql¥KРJ\Co{cx01m޾W76{☒ 4Z3VO ۮ,1kUp (@Y^,U$f&WNE22g= .S{[&o˝}8>z$v&S"?|M͈( r~>i,N{ k~z)Mv8pGTצgZG={1ܒ3FҡW7' yYv'Z8oK!Xi>V|J$@$@$@$Ee;slsGҁ.pׇkiӗYʿuڍO.6k̸nV&n'tݎaYGb !/knIwr<(+NQ늬YF ,w[̗J rYdbȝOcJ*o."[V|e -e_4[+>%   "n9]m[}86?=mMԷD#Nj0 j4}q%Gmr̗" n%   G@·n?V;i+rG[~szϢG LK'߹S RyIZ}~qk&„ YSO{wrM_{ f /Ѱ2í{i lE~;FtGHi3+pϏcDN78yKT&5#CeYځ,-B0ϣPhZ[ڮo8,3_bVR$˗,m8xHHHH m+?:C`g3~UZY"9;&z\e*B;ʾÖ؈5 |~ի ib jU) a$Hx%}rrcs,~5C9w1e+Gs?b͇OIHHHH`܈>皋Hb($4HHHHHH " Bd0S++ݰ?fQ,} 1[k5Cơ yՕHHHHHMn& B: RQh[i>7$-} /<WV"}F NIHHHH4{4բLư˹y^U» D#8I3Μh} @{HQl>]WцAV u:aY׉Eh~GtA$@$@$@$@I@pJS;jU:ivݻ8sK,$&pqj2E$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@y pk̼A G4g <3h}'3>!     &EG 0a糨 ;@ _:uj<' ̔Y8FW :r:C      As#ۭ o %?)ݳ.xl.HHHHHH NTir>-}B M0Yx qNlDX|Hq˒#wE_*?.HHHHHH{N8|] Yje)6-E[p!pL|?Y/}M Ҝw(lCG|D$@$@$@$@$@%J{O8_Lz1ywd k9&V q-K2_Wޏ˒{UTbOHw$@$@$@$@$@$@$@@;:zta7،=AɼzܮSjI$@$@$@$@$@'`lg8}i)qgnX k<~8ѫQ-6KQ!Zg[Tbwv K=f帬"qu,3_m [EO,&+P7hnӠicDz߉ItIHG&[5եHHHHHC@kz* _l(VY<dpcþ04Ӷn:؆mȁQ8 N ^݇m$6#v^o`oDǠnk_4ͫjh,Tg*71o}l`&W *Mxz%d]5a҆xZQs|eIEJ ϟŎCސ @i5f9_'6Jt8}V <\'VdMolīYP$.hwym Y7!6,SM 7!\%*qZ:Ãuk&̗|Jݗ u^&g+H"t߄0sf GjW?Q~tA$@$@$@$@$@$(l+1nwL$N_J) ̠OMcĩy bŗFI?[s Y>B#g oM{ j_5~WFpdo6m!k,byhWV22 j44GFYehWA: gU<~de%|gkZ#%ՔHHHHHJ~]߮>|~{[հ,ÖZk='WЎpZ?oĭ2b+VoB5t}֞3bKWc>¤ sԖG ,zA'0FmėzXl['֔Tc4 %}|ɍ+{%[} RΕ<;/f\t ]fL` K4% ;{ U!F-lIHHHHH`0螐nA{DkI8}9F- [o{:(9)[q\X{^Xk?R&{5*v'qQ ˲14m\!ږ*+PeWDȴQYOi@ ,*\5Zh="3\Yk+2;Nሚ7c*jN?`:Ed1۳B)LIǃP7<Ŭs.ff6ē-IHHHHJ@A^5\[jK8g`ӗ-&zp4/^b^˭3eK czRj==ux[!&e:*:է{u2;cPy " 3y_C@<ՔW(,hq N%Jgyߌix5vge遚Cm~M̈HuK:vm})uXK@}<=4GޤWձ^%JGݐ @힨slsGR1]tӗgwZ׏M)pTaYG%ǚRǔT`G=dRee WRuڍO.{j< hIJʭzQcBzlLY@$@$@$@$@$@ nؚͦ71c#Xs2Kl/2&v*E,΋ao6}¥j6Y. 3_ Hykr:Y9(]&3պ ꌕY O_] @uO'q L{>!mݴeKѢA^A:%n]Qc:Z0t5jhѣe8 jt=-8q5.w<0rN']*\-dD z|W%v{FCVobІHHHHH &o=Ś9r}swIh!KܘZseSDex `[?Jߐܘ|_*B     @iRAPSw>R2<ɧҐv`&K Nqd Li^&\×ɜ:zt[c ^QqOV4|@$@$@$@$@$@$Ξs,RD|]?                                                EJ.EmIH>ڀxncaFH@zVA73w {aeΎ>I`!Y,v4,$? Sg_L}c3iYB eO+TZBo|tck&qa %&|jrxIjC)~}@% ۢUL9jt/. V~9{Vr,~wO$P6fOlkVc*DItG'2}۹w&,3Xv)/&uؚK?_Թ;WK$YtLaho#vMQ6<֌ʁY슮N)ڄ\cKe}Vj\V"F4qW0tWߋg7%14w{)4_%ǜU폾v96UKYc>tx?c*?5YYU*$#˓_h=SFE'mf'U'p--PcWioKpKs9\q<EIQW X2jAfS_ĩd_pφb鿚:[2Jr4Tm)Nx"R2*xd:J.m x G1۳Nɢa[ol/\Ĉ몭 l#%""ȗ\'gsoB>8i>`ul1ǚ?#힨yV6U}szyl9pe :, Kjγ_k"kp4Ng_镖Dx:VQԐ$ UڤF!Wk6-xt#j~[ ,ŦhK}ֶڮ&4 Ozq_gϓd.wM^'Ƒx#iP~D:MwE)Fp祮 D9 {|t_(,T^}J+*ozeQA*JBre%`GO*\S+y3%ZD}J3͇˰z;zNY=! bMdC8J \ѿ}Qx;;v5)p ^j[]ڇaj<A>3bS ^$ ;,z 4BIrVA9K*tj;U QX!Bl UhKuKzoWGlcI6B{lń54GMwQ/ʭӻWdIQa{&SKT[dkjv[_-ǜuVM/ȶSY$֣M~"#0pR\W"D=+MS<ޏ˒sK+ ] è*B ;+Y)XJn-Vc~e8|4Ge2_?J?* ))G;3niHVeԽ+.1 t5=QunJskrRH:cyGmBH%]ZbCq ^P{npY/T|AA1|yF:vGW&YS>(;,o.2|^{SisXH"6D!'LʨxS @ QڨσϸYROɨ뢛\u$ZZv6ᆥ㇃8}(vi*dawnPYrg%>!a~t]9gbrK7wv :Xa4 0e -H]o@L*_2*^Uf\zx? %{դ_R*Lաt67pb! Qe<ɾ +zܓg٢H(yVx(N{we9"\"7l6g +ȃjDsx<'(H,;d$:=C1͇[< *ۦXi>C+E#1_gMw߄x8CX+72{RH L`KrڄNoIQn5rk?W:^~6xܬ!Tda3emO$*CYK17~˙d ^3SQ;J,tڦz`12O6 Ċ̾ ʍֹkxţoBl]$@krKkSqW߄y)[RڶϬj5,VhK7!'*qZwP9.Ӈ/jAnx>oBiibWmrѬHW*B&mmxas sMo]ʨlroKjC⢍@^"4wfODLH]8T )).}BBn[DNHΗxeCRTG?cP]:f¿K_MG\s?b]l.w9ۈma|z W{/ xYlq:{rM:q:oVKthԛ7!<[lqJ1]#1ފ ZFBuzڸTt_ˤ2H4R n ltfu6f+rJKoB(3STEA72\%CLF|Fo#Es;g S8kqVN9!7i9%ʡFGU ati>$ .gyyo9xq3F5ZW y\k0bJ\w+EC '(p7,2-a֕xȫ.Ni33ҵFi蝄LmQaJl[AuHQ&-!*v:_=KυYm^gK~"bT7nWjf-ɭp gLɛeÔ्2d}h=0h׏c+%mՊحgiagЩƸXc.ʋy|{*sWbجA\&~j(6N:j:lJTJcʒA}gSCфovt^qƫ.yv2Z/3v4&|j?!͓쎰e?5;S`%.,x*idtho޵a6vrPſk;>%z=܂eƚO^ے9zj)oY QY$лʨMӸ;U-,>\t+ߦ_Q98M^[ux+c{:$O&W r/Qsg $G~e锣`6yOqqeE/:,a zf\#.Zw6vYxXliv咱  ]lGXTQ+Vib"s<&KQaJ m"Gev+T أ}ǎtm=[MX{W:R^9ɍ-5J!}ā f5s-0i>d޲YF}$|3G ..wS[rX3c.?H'nסV绾.B}ѺjnHMn QLi}(}}Fҽ27 ~MG߄I7^{H^o}h kĭ򥋭B}cCb{Blc ی)LC4ĊSoBۆ7Ӕ)*i3] SgAJWq*lQd#nqXNXK;Ur.*- zoFط-Y%2j3$|}gw/Oa{rB2kU=jPePs5Cql/K 5&jamIUn\:|?yex =#iy6ye1ONݏ. t! ǗĥtǓ-ٱ!VkyY|Ui3tP%]Fc|[>HdgZ[mZߟW bݯqSJtgw%^\F1;b[;%%YYXXI&AfS@7pm =*o5Rplu m>mcB3۟+;D߫JOl2|B5a5eiLsچ9È;^ w0Wᅵ#,V# }Yب`C4"}CEe5]KTrR{[Ӵ! S}(lFN9ge?8ej<}]']ߩ9KӼ2|y_a4&|-9AA&qD7ge_u>m7s#LC]KNԃi\^Cp(By6 dRD=boy6_al9jKa%/yo4H]Syˁ XA>\Y9 lq1Evi^ ,1(0oYiS;NJ0 ze-Cecx0փ_ߔ_qXF P%=A)x *9$Eh (c%\KAΕ8޶/b7Z5^1Ftq.w:帡q6!'$˨^mIz ѻyZCR2JC]ӨeAy޻KrDT4:ge%,3<<28~ (^">?u~&#V>5`Uɍ189`8^;n Gd[7S!ډ\BR'3YM Y/4P |^h yYr]aS&.g~-?T:DKr׽V7焛_a{~u ;Z2]PcZx_of^a5GuGS)SMeT%qj(yR7jqDe{o̾ba*Sd,Dͼ3KC'ҹA~LLC@siޡo/÷ M,]}*V׻:YuߺvF:^o~"s". ZRon}TAhQWj/1tj `A2UȺaƢ̬_~:t@_ijR2,mݮM %X]nHl >e OØӼJ)A7A}kC8?ehs+QF2KplNZs ^C<>UVٞ9?εtMarkL/ͶVYkGr0`Q%fF<]?l[MK^ iIt<*{‰xeRȾ 㖔Aĸ wEWN3/ZoqyG<|}XJ5ܼ!TjOnA_=k[7kڶFp_5Eb k~n`'䎑a֖^"Mˬ?J⌗V|TAe^xL;?xI6KRZR|ͩeh~ ]*ʇHhcD\Bm6?WX=#v!Jw8AÎ>{4TqkAWjˊkbKXqr8 Get뽽]N1J<(MV΢ -2E7O%쯏(NekG.]%ӆ;{g Nx|]ƐVJ-ZVHe> tqcmf}mw\'3Ѐzg{ ğ~|dt#̤ohzL}Q%v@eʍaSDolmRV2.;!wN'yevk̵!)\" kOo95Ƴ22ij8s祐 f%N$s/"xjzRҙrكϟEOƺ |#, *K lD <=f/Cw\3XeT8^@k:9w\^ r$9YZ9܋pɰo_>J9,秡L _Y_"Gr -Xi> U=߾JfK̎,r4"~OOOJmJQo~ 3/~}~CS9wδLboSKQy|_PKCQJFK:uMFF볌~LJl)JN>u]o[kJ/ęYFl3uq^2ˇL(ٔSļx̾#qyI^5sGJӪH({Uy΃{S*-[c*mrV(75bhMz6G:H^;fv5D-,~|H Hcs=X4)X-*OPZc K41w ZH j ^37nqdա # -+[)dDG-ڝ{[ aW .)$=2 '/J_C'QڢٽYi54 K4_g:-Oȇ|qy G (E_^թ7 2xIOL4  ;s ǡPb[Ҽ߷7EB~28ܚ& ./J_}Elg>478*R<3{b% @.C6:喟Kk{n|1y3foYF$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$.Q\փHifIL=y N|CG9s}9^w,C2G<|̈́;1q3h3cgF-c dG]Ԓ]oWA$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$@$940PE к`pxHH IqX    &=_,Ƅk+KϰPжZ`* Z hIP2 n|Rfwz   R쁚X/E:{b< ˀA2iP9eUU8B8g.p8] O| ~@$@$Zʰa. /h 4Tͥ(D)>)3D8@:IH ){<nq:J듒ULJ$@$@$@$@!Pv/ԭؠ c aCpvw`(VuocsO쯬ƽzv5Ex ;pKߨ*'$݋ :tkwJ2:[XTTcuX%4ƭQ{^:aN`,.[ p*4&[.-s%^YMAA[*<,FWc鵍}h,>,zlg?6Ƶ+m#P1;l=߳׈=}Gԇد+ӈj]S0O܄r7{p貗{]Ž&scO{`%)}*6l^%pTXGwq\k7bS\CE2]MK?ŚTEnZu|IC$@$@$@$@pR'E"oB仳נ{oB$ ᑥx}C7!RWk3y=鲊H !'߄ZG٥;&Dƅx6약hNGP}"fboBܵd^o ܻ7!=DzH#Ce鵍W1oB`[]OhU6e9E^0Vg)—%RZ΅oȠ&F5Xs2B͊.3كkc*‹+ ASA< TJ+ܟχ= ^xS{SI"oL$@$@$@$@9$`"=B2ڟWoh'\k#c#EmPmMաUTzK@j":駦ǖY͵B}菉^rzp\:?NеZ™D[MRGKt}#81g>Oj8ۢ +>i<6ZgkWUY/egom&4TuqHm5=r,C w)U eQ\t.6}U1uٶ_Y.1p%^oD^Oe|ISƴ]Bh ?#V.oOA    @GO2.Ӊ+oBwE>y)-yꒇ{`+ʰE8YkEYv|nݾAcȓT=d&/,l 3 kY5U_Y_lM/!ڣeUWTd3е}-1rM wX{XϺ<<^.e+<1I1 Y8HHHHH 9Tu\s~_Vm漆/9N$! &k)5&ow$HnRn$˘c9;aDx,s0ح_M)*A _J]M 6"q6v(CڍR tv6⳦9!.S2<۠}K~-o.Cya8MZ=gQUUnTzxr\yTW?SiםkoI863(75 eZ. L$@$@$@$@1 'ƅQك[oi?n/ԕ)$z;?l.ayU>uY_8s [X!rLzXR%𔫩 G 6-@5l0ۆi4:zK1\-{ֲyhVGgQaaH΍rǗe@ti[,ITXLz%$F1KUQuyx*K2p鼂m|q    kg2GZ@T/øѠX7'b2E K"|o%֣g^_jd2u2< ASN=_E&}fYQh/CۘZFlIնaJ[nm>4d^nҊJЪWп8cJY*,ꊓm\ncyN~uSi/g.3-WOJ.B$@$@$@$@$@rA9?0e n Ozl=V~t^E cq8A-]]޴ÅX.48k8w %cӨn@L"vۤT15CbUюxRe%E&m"(Żb}}KtіJ&)b:P`pA: uY OqYۓ52 L"u~*uryxRr] '    dg)qs[sŝܚ?e&/犭 ph)_pI wq7𡻄n"s[~w'/~c4^1bSaikj asLٴzl6)I/2.}3+#*6 TSơg;Bx[_ LrvS=)9+ @r|nM.)+wk=IGïbBه>>*8s] bs%s/gNq>\YT, ғ rT +,s. \i>)„$@$@$@$@$Ey8olQ6Hsʞ6~ՕČ}PKR&T/"u̽Xo"  $mSo n cH~+'v9q􉚗mEH+4J>~$?4 ]b 4J}fmpHHH<{=WyŻ()6*cyȷaѮ_ =L!sYk.6aHHHrD lղt b` "?|+q(ޑ@wzϋYk^iHHHC ɱe!I9_bL>@/`B3\.HHHH J{mgs N`?n/֖q4-"|!70^ih(aJ!|85DQW 3y7WՑχ˶26|5&6/0VbM$'Oe47k;Tcu&">t=;c>J*жXq)K&mc{-XmJ?ꏽsc& l't܀7j zG𝫩{Q!~r4eUxXYo"QQ4tݬDO#.`p V}.KJv> ݣemݱt T+Y]Fu q*Լ7VƸysq#KJ&uc12e6DWVRSL4·>rK6<AE3yn]zvٞx{0L4LE:l4'3{&H*zr-x)VMi{7bB1߄7i.-]Q- xyoB$.Uf؃./mC6PYS U (RvޔEP val=N$a?s)I7x^,7 tWl'ncMZ"MAq8DlDC-еO'GprR) 24atZ>@c ʖ"+*;]ѢH)3xߟt!.$.ۆ߀؈AuK T[e"GBİR)KbcCg:5쩌E-w6!eN ZSi ץ"gw2m oK7x!5^Yщue6WXz -v&   ԟN@:zq8Z0 `C9- pjqmf]E |eF$I@<=KfKZV^exw9FDE8XiHu44Zh'v 4 Gn-Rh}d|:+'X$@wS#cpۄ ۚcGuhu$?ljT9z*8ۢ^ 1gTRPZ*׮`܇J<ĭ$jD_5R~Gx"$s=4F[艴t Mtbwkd->IHWW&mC4(O)Eނ-ZxdPeHHH('~lBYPl)%&K3nfϼmVfTCϨa   HA oę[j _Vˌ&$AgĶgNm2/d șR \SVgzOж+r\D6OeZ,ޝrb1'+ZcWj ?1twwyJ wUa!Kwg-Ylm`F   'PE q.b'pײ_L>w^b'_K^y7=g<T5E>zdu?EEFJBغ &+8(bw̎Q'/WU"߃ {n|FE8/d ]:FHHHrB{bo=D2O>fO59 #3WNdIi1""7*8JK|^v|̃HXiz.Nú{Lip|5z z*jf< M r\dA-ҕb'p&ۨ9bWrOc!s{"A:|!ĊdE5\Q޴3eDt%;ީVܤ:z*jɊ1UvFI<+4w?ã ž(|5C&9кO36bHHH)K=Q[*E,0ގaE4K̥vʼn47?U<1]]Fc/oܺՖ˸ `hܵ2epDR.o}=}-NL=iC{I\\15{ûNktmڹaocm36R$@$@$@$0 rO;qM+(=;cNcwbrsZ849V(qtL 7?M,u8$:]J3YChք\M`kh]goE-˜2㸿FJsg-UVc|*{*ݷCCb%,K!3W:ġmC/@b;nt5cVTa;^7\{tZ̵ [xI$@$@$@39A8ij߹]?s)j:cc6c`-^j""x'KܻlSI$.0sʋ,|~R疱.IB9ڟP;~[yzoM6#gč,(UT'XK GO~lMK;g=#HHHH`cOtX+QN҈7 y{Nn}݆"%M_~"vq#mT 9-XI(Tb%/X$i<׃rdb9}0Ƅ,g˨;tR%>^[f$O-np3C֔6/c8e* ӚSJ5uYF޴ڡ+ x&~Mǯ-Hӯ/IW5Fp4OǴ1a$lA ȓ.KېEe,4'yGٲHHHc|* u{W%+ :[3l_ޫoLDAb?uibo֋_q+SbuKx @l6 PR089&l"SY-X\ >/[p{ QxVz& JTsmŒ wtOxgǜ$@Bh [,c=&"D,7!$x)d1_hvP [Z@#Ztۡ }LԨҢa)Fc7 Ia< LHمPִvJcqjv&+|Ų@8zMA"LESyD5.*Z<k ONbP['ɸN9aW\a*o*Oa['I5< FkcLĝ5++S!6X96.i|QnMo ojH% 44X \yå@pM@ȅ2_ 3I#kwzb1O%*ˍ]`tiQ̄\ܘrjf#:ư ](D֒vgx/eĥc h0֊#"U'<̕ЈHA-|م"{"Rby7q*.]U[ʎhߒK1Vʜ IgzRˁ{[(mFa6Gm:8 hxc=^m% @^H=Q /7`Be/$]_;?s^iL\ZBD]hyS?; $=;]G8!~&8 O0; b6%AW"tt\ⳅY91a,6 ݶ\"!-5G]^ <vh2FI"iԄ 0pZ% pG%ƱRGݟZ\"Nc!/#Á2!jF84iQLyٱ6^g >Әv(zM GևsxDKƮ*VjOl9BIHHHH&سQT\j'%~v;3jm+ksOl6&MDL'TCxp񴜬1 :^{O]TV-,$;a_sɌ䯅-{3/ٹCƊ}r4s:%BnUۺqet}aw}L6$+`(dC'>뷊WKtlŸcRq /7͝ȴ2SiֺlF>T_kc6Zg6oyϧx໩f|dHHHHHA@` q~%Zu:&\IY*IJB PL}n`!k/eSbC&SnXĦ;ʱ% cOrDԖ['9AcWH?HPRJ=l +Bk-:y2HHHH`yT,* @ V<*2W,f7kX !6HHHHrJ ٧->~)! 3*`9R8RPr8Nd0RiQ}v<˰5&ņ-"V BTNGC8:TE71ܪjht 706i%+5C%S &t܀7jN;W hHc}D׳:,bnf3͙ФoEC܌mѮ~/'=ED_8h0*<";<gɇ-!|v/+ [XMVvB**,Y P=^uz;&Dƅx6"ny;eji.3swmdRNk)(( ĭ.LJ$@$@$@@Λ*:ǩؙg.uv {eJEPd,S[pgRU1,qZT57paq]'O>Us>5aOl?ΉH=3ț}M!t߆[]݌&o\A|Ө~@a[3meʼEFuρ0+=} ű!S$lۛ* ONb\'eL/*-}"e/ӜQl{G ʼm8؟$ʯF+#$Ɔz [   SjĎ^=*n)6r;ndvw~469"Tp-+Q/ {xU2nLS\OiL[w O$#xIF i)*8U\%`lQxVW1XY-pej4[i 6^(oȬEu_GG@]I4\[Dcj@Y\3}ⲵ ȯʡi$]CDLM( q={,K7y1tЗ~mWTEQ &r ྾lKƎX< =Dz!PZ[z@S._OgaLg.pHr\;&exm {jFUَĪ2z;z8ˮ{j&}3OVU9$ӣ2iQrΙ lGI|8sZls4T "8DbCtLP כ޶[J?Ãl}Q1Z03 ҶH2">}12i1<|o8r`$ WF=?pG)e^,ŷ?闺ܗ%RL.ó[,2{prߓZc_a<gK\>&у!kKX>:}\JmՏ^'ex$ƪSORώn 㩊Ƙ!S3 VH SlTGjpQ#qI2IȬ|"}odLHHHH`o/Y{?vޅ(?s9yhWpЩw=O rZIL-Tl15!m vLcՇz5˄)7:Jl#&[K[-j0 cxzf gv)+Q>/s) zehSSTszmDC$@$@$@$0KxuOz<[O0S"v\E.b3fjOqN-9wyOf/ĭ/࿑1!P3d(z T*N-yV90cMUq[WNE5Qao 8_ҰURQ sBrW晈HHH tb /7`Be/@,w6iF?sy*|,[;ZzoW bpwD r:= Ug.!>T7$]ٱ 疣.mj}(7TcqluxRZ+v^@¶0/.,\T^6q2uMĩr~su9Pܢ< @[L͚k3.Rm ?Ul1]%7=έ^e(\Go]+yJ(7Q67<+oGb6q91%#IHHHIT`gwp'^9\mwuGt+Z˫c]!c QS;n}G"u"18Z-OqXuR'MԾXs)vF"<&-鋅Qam6A|EJ\4;zҔhQ=w3E%<>J="xWhpM~C|y?e%o QߍT송XS1aB4!'{dJ]PVQVch1%#IHHHR'77[tS~JiLb:,zuIjŲ= 'sZP#߮sֹ[)\*j <N?veIs=*>zuO-3 |nQj6fN9 䒁}iQ> P L9gI;{ڪq*Gm)8gPi{ktyEQj4}`&Q>zo _[䔟,mu1HHHf?ZsG3MuASK9v̝WT~*‹И{#sq1]K[xg*Фy^6[+rc9u{IJbj-Op̛9ÎtU-UvO;*mcfQ>79MK$@$@$@yA@$8#:!S1c prcg?Z_DXW6ocsz EJ\WiLwc@i[v"X[8J i[衮B9ݓJ-ʓi$n|GjgQ+5RExw8ʪ9wyU&֣ώVj#   !@纨52﫞(!Hۦ;BGRD濅) 0o{iQ96=?G(s+62e<&8vY$(S}O$@$@$@s^뱵\'6ժQGؠ"y ,O˗fR̛IU}`Z b+YIA$@$@$@յXPi̤$\& }ؑBk0n俅nK2eޢfC)il^1 @XYKAY"pf=5$b%yY Ͷ  "UB.*_#;R)e`ul> @Npi̜`P l8K5;>ɦd" /jѽbsq4~E c_=X3,XYE- 0\ cM?+(zGڧ\(X,Ӻ8?Jz/H;ݽɲ {$/vRpG6B I U):ќ=#L$@$@$<=Q덱nϹί[ 5 B-SUWbM(B]3}EY'Jo$ m)hZm}X+FIK7Z ݚi<1 @'@^K,H qb2~p 1G*աoB=z4 ja \>x p*@q\abx"@Ji_35m񿕣^xB h1J 7= s@!Ÿ`>aý%T'{}\+ d]SK6 Y<cxX hAl. m'  < C"JIH2$pTpkm\gĽgx\L8ot]1ݢ$ )pR/<0$o.UDbQ*3BQ[Zt\S @H3 Dϼ2RE^Yd1Cv܊M1lt|_a^.P+ȷ =$@$@ Ж~e==`|pT$b(AEgp0^;@tcz*tdv(Eb<9ěQ-a_鿒&ņ-"׼BTNGC8k1ܪ ϵ|h5.A&ix8jqF=]=/?0u:bh񴤌8uk{xw%[Q?,b Jms7ɥ&;1^ lBKfzB =MiDߌ~[ Oa[-I}1Fb%ZVvt)li-5?Q feӋJKa|/ӜQldD27ZNic!S!CG+&1g Oy$&5ny9)'- F%43D4떷&UZݾ] ޱI/<鲋 `SPEhDl` {m&Ж<ˬ0%B21=KHHH@#vntqVwKar<[v 73ð$3ґfhH|zCj}u} 4)Gn6}JmⳐ\#(>9t[%:\ ܨ_Y-оe2,RrEys 't;ecɖ1 dᦐ,H#ҲPWc@ַnnSy\u^,첚 )[\Úԕhdz f*{_̄!fֳhUbtx(g&ȸۗ節GסETfzWa$;X^vNZH96&۽âo{5` HCa1٤5MbʞMHHH$އ:zq*`epHL{2e2Y/c$ᴕF8>mjBA͞3$x} L{Xa >byZ' j'`mo\b7I HHHwei(m}ԁsva(S*`Ԗ.]\%@/]V$Sn+˓jzǟɅ3_ssTS7$uKI93xCe U<|B eMaaUߝ/-|+_T1M/35ka>(aƙcd&TfVHMRY0D*9 G ZrµeDI5U5Tutf=eI`xZ-G=XCU!h}Lx?y-MbCi<7&cx7q=C`-іPE@}"p0llߺK/vrgB,> t"Y |A_)t9 Ga W^SSnGIHH`p$/p<K52pxt^L% +<;SĖ<(߯b$|{܏k}-vq?CKºb\]*=."yɅ=%[ߖO($tsL 68ةE;e# ` >o6! /26(L lۢߛ4iJK81[mo"<1UjLkc1e |% i˷VQ[k%|n(S-B&ķhBM(& րZܧUEIbkRkPL+RY%e+gC<1q['ܳ쏷e*>`(r88'Ҿ3gu%Eu0}J]*ϭʷ]Tt óz01S[V`\^E$@$@@ZD^1#b?s 'ā(Sؤn|9/{k 㡄^%W.1x}aBIz+[:9/ e5@l4my7ai>kyJV2зd᪶)ՌN*&"'(eT gR蕡PPo)6†%y#d6q^'Q͕hfM%3TCgҷ-e._!X^di{jJ%nPbTjS;[<@$@$@$N y:381=8?K˕>*?޿̘*cח% #;zCލ{Q&PM4¢ 扄1hMSy+E@~`Hvwj*c (,X+A1 %m&+qK Q-֦*8EXlK|kJ CY U<4yI2-ѯxb~߉ 1Z~/< 9)0J9eErcf̰ESOSgIHH`<Ζ0+?L~O*7Wyh_ylw:- Df[=OvBPo\6g[C$9Q`\m5F"9/D@IDATjSr%0U6R0P7rNډ/GgBI{p)0H]8+.'e=( J%=/#xQޕQ6_M8ك3xy%k`_Pyd/NȈ1e3g}Bkp t3M(|1؊+:+C;rt٨5.Ol d^`ejO4M, x }Qޚf;L'Z<"f@ŜKpM PtM@Æo0Xw6}bbU:SҏlR]b9efghٷblS2_/J4&f0xtU3fU@O5g!#&P^ ϋJ`z.Ok~o{ΈIHHy")'N}#}c來25!G?r&VDycDn\"%OMLXܞ9kF^@YLgx'IHH %͡B .vKNje-akϺ:l 1g4 HHx4OdVD[3Թa6K24:'L`[b~$ 61. /+}fN77cB   IήTNHH`8aƺ3sFy*J$0[^@ԫ+1}ԭbHHH+'efpIX}h ' %Z;bG阣j @ט>`1* ط ;Y1nhvt`$@$`Acq4gfHHH -@ TEE)E\'k!˱2(VhY /J5zDŽ;~e-@(weF =]"f퍮6'"҆bc`9S1LVhL9 p^}+eO]g P/,eh *HHH,4OP"ޞvzoNX|C<X(Ϻ0rwafVJ9 -@u#"\W{Ct˼Ǟk1K~K|'a%2+氾M]hͨ Q|{UU : k#n H6^ͱKYΔ-@Ϣ٩ <6_OH>t^SBxP$:Й1;cEȗBԠoHHH@'@Ѽ c>J%@K<Ô(-@"4t,;^/~YT24Oе*$@$@s epUI+j %g3"X.!(-5m3Q}[7~!j\q -|1ƧFMy85ny)+Έmp<Ԑl6/@4~4AztnњY 0+c5$^,ԓ`7=~u܄{ԐW áBML&-[GưZUVTnE1  /"5- ^L媶ǃV[FS2ox8m`I<~w ,>W:އ;ðZa<񐞤O(%'U]~sk[ы?CT͟/}ރE^tz8 {9û#CgRt.c1BP懳ޭV%7&adSE qW 7W8mGPO0qމkIM ?BAƦ 2Mf^#*y=ڏ.fplt'TMp5n1܎OVs֑cb@ '<<" %yY|5 %e쒟_?xm)6mBa1; m}dH,&swlޕ_f1Ozl;)anZ(1ɜx~\Z6?4<ň$@$@$@~ 14WcG%n[hO ι%Lshڮg3o|pՁIHH #.:W}.qe*WiyS[|qЋc׌C xe}*.2$Ky:9Ōk횸MB X';u3;/7Z_"2vg0(øl C<٢]*4T8Kjo\lye˼e HÿLA$@$@$@P:j5h[#z,Ls9V9qDNCU! ց?y YȻbCi<70b]hPrWgG~@5Q1dO8wQg^`e8RIɤ;EB/[8 W^]\W4 @{6u'ccxBn@[G:TR[|O%MVYZmSe_zu"TBX{y%G7{J-=2ByR)y/1ujQNYI`P3@zR>-p.e4Rj Ql+䫔X @35׹lde%-T*y]Z3V|7i^um qĪbkq"!J]?,T<{)D >P yÚNHĈY"UpB_#Le  PdupOz־*1l{9oz G76^-Ml D^RjZ6<X)-~@%  J@>S_E#q,)*.b)rƱ!*TIURɘszMؓby\s{o)~5Td;{>v^)rl<\r<,gvT~*²IɫwMJ(EH-wz P=\IHHL! 1&shƷ/pqLϳNqh]cuO>Ēe?SŃj 5 1C۱‰ /Gv_r.K пZERjKԭ)/ ԛbI'=K͜a{:,+OQ'\tBx/#kh^T k͚/GIEV{Sʩ~| =k1#Ÿ5[T(y !Ϧ,S{I1^hDFFCl=E ~y3P-WD.[7CUҲI>~A~ HHH֍q;P+;\FU*rT(Dr!,bcPSxy.K8d_CGviGq2 0/#M9AO+,>O^๳,cJ=.1v1e/Y oyb-`0"bP<l"vʐD2R'33:Ѵ6X&VF5]oiFX{uJ1eE3ǏW{%v{X5 rNy >Ubnj+KnV9_lqym ܶz(+ @I/H"[Zgr/KV((Z>>GdT{MEԝ䫩!~Ɠ]xU҉IȀTˣH+]g^qmF,H˖ c5~GV:oEb,   PW8`zܭ}T-ućUC3p 4X#{e ŜKpM v T cg*žpu>;Υw$?K8 IjjcMᖷҗˌ9]SYhmJ늍:<1hF>M j0TH#dd, 7ip:e{z5zEL+;LH$@$@$Amh/<홳[D]jkr[`w t!-Aʼn>5ߊ^2kD $Pk9t;3}/L)HHm6Tb b;ЀQt:8D)U.QTfsYncIۄCDFs z(:34˳x8$^231N|, 艠[V1x`YֆN_FN4ÉQ3JEq4 p; _k~6NKWw˾s<[ȑ3C   8z"k*\'o: fyE_3nP"P@SaK7qhЁ\ G&5$   &J尢Wj/^] Wp1h6ueJa; ^kO$@$@$@$й-5,6eKH?g/̇% rq4WWKaȤyF<, țl<&T ZqAdњkм1;E(J\SK9:-Kq}>?ŞjGs}, 0 R +0 3xsrhTm#1;KJ0$ٷQBgY:fk|7,|ܛpÖ$u{"X*HHHB -Uh6O>q5N`%p TZ,fY WSZfycI˙f:W٢]@d.5^eZi,d3ACCDT,e @Z=EX֖u8ԍshKIrPs)֋'2kS"í\J_MNn<ȣ @-/u`K8G޲\&/z,WG$@$@$@"ݰg WJtb[.3BPX@3}SeW:1tfUM J^.\E΁"fDP`KAqRdq<9ͽ27XtRyHHHMyBxHmk7`9 Y߇Vs؟JR9AyIJguBӜA%0(?Ryx$@$@$@$E>E.}o܈1 E!bSA6~eb?aiУ[b`pa]B{-|1ƧF?őۊQS؟bR)7mbI.[jpS!f>+_W`,rGR|~Vɽ P&uCzGUWYFW.N`WW)f$bWw񲣪4~6tʤF9%yw*$U673=Y1ʾ0X*j_kLcArx>IJ£K%sQ QoDOo&DR;)s/gݾH*E mwۄ(GU)S1$حfQJ!f&,R75*z * \*m"ZBRBƠi$ RcT|l_jD̖n ^ƫ#R5hT*PN]81#8:N>E+ ᤔӢ G,Wʉmrh}Yb-Ũ0􇶃Ru/38:?N쵸/VE[.x^&,/ /V+"+Qu  OVy=;/ax'*'բ8_|q c_8Ӷ6)Hw`K3]h?>Iuߙ=#ϩn Z?*-UA/1ޠ=\EsFq51wWlon9H 6&*^+_S~U}xZUHH ͚Hj KZ[_`&4ۄ8=^E>=f9a{vzjL26Jb J$ئV#ɫI7\Ԅƒmxl`&DMl+pMlҮ4.Zl OaSmB:EܖwPk_K&`CL7P=̐|J/&tXǓ뼒7`W<Ǩx9רx_:>A6!fmXC+Hi,E6!va!f)6ɰ[/ϥ]9i"K K2)#z۫&حJQDcA]5)eX OMK/kЪfNWRxCAei(ۉ y }6!Kzվer#ӘIH%IT:\f1۹ 5k#hN#21i=Z3nO=#N|gˌoyMj 0L%7ܮPVFg=H_oZ:clL؊asK3wG{7Fgr k@&\-!A 7W?ņ<=~dÙ^ 33i}|ੴkw\?6" (SQ=0"m`JjܺU , a 3GP.Pi7::GFU=2J~ר`^4|]PS-Uz&,[|0̖ i;%qaVg9BtjxpP>B0nRw R c|< kdl3>>'4(SѶqsdY*xuw0 Lm=l'|t)T_DC=t[@Z ?)C5᷇< @HxK̯&w|R,fFr0|B9r!8XDPUaNmrh(/]; jhe.:㘙׍hZY3!e\$ԇu̼g\eȼF W$z:I=AH0 )kb\%ӗ.wbcv(A2!R yҴl)h1oߔ&xkt@^ztcb|gFסL.Z$gU^ssT~kT4؊hSq1F! apeq_1~]8/Vn[qcD,zb1Ʃ`v 3~aױw<=RB87Qo{U\+x29T.$5_f=JUcCZTo|sU7[(S.h곛Ƒ)U7`4rH!wiyLLOvÊĹZP*,4R#/@=ܹU:wʻ޿+Z{ժ#NxOqgZk!2 WSRŐ j4[MJsKAiu"BXHryg3O zOi0X*ѧݞp9lonQtb:\R7?j 7A>7O?*/0bU1VX7{9P$+b>>TZYwaʷi xCd 5¤r<,gv5wy_6F;h&FaqOuy%J9 nUK\˷ŋvҶso$+9_LOnLJg/`Xf[ #*tzg4{'#>qr[ %5H^d\7܄eXzhi| *7OlV)?VW.~Y P":fTG`K%2lI0߭8*]UNn_X&WK5LK3dQs-!TZy'U'6vP8^rJȭ !V]z\L0ȩ@5*nE1ݑ]f  9Oy"BU,VK+5T%8^o!iܻ]RMpgU7nk|<>T/k-Hz&-Dj@K=N݈kUpjD&=L38 [ՠǙy'3ՀyWFu5,_C!Ҹm$vS:o+:FEne&OVhu%˳g%6>}4P(0 }$ aTv^=06_m/ RKq5==-s]C_z߈]&>$XjxSz{7:*|fsHQY0h+J~*{Ut< C%[ٶ.K:޿w&>.6-^o<‡v)VaBt(b9ر‰ /Gr::4Ne!TۄB=29L`D hrS̤d dO5 ?˵Ae;+QJV܄]cuO>Ēe!&kObeA1@fMwjT5 ֊(H>˸6b&tLCaОE3 %Cn~ AX[WI>@ fH1e]7:m"?}+82f (+ Rչ-^øwڋ/Gj׮Aᛕ_#B"Sh:k^B` >UbkWj8Qd,\72zH K!ՋΑP,yx% Q;[kpz_V0ꡏ +eH/4~SS^qbR{҉e#'1a7XGk4,/`4OM 2UBA^ !V˷C$cHH !Hĸ}B̹3IlfN|Nzp)u~a){K9kw Ư/"~V4"c۱I-8-XQ|< i7$RyHH`>8d([j Q,1q?)^tUJX\IuD=b,,# zv0(L/c88)iu ir9^uC o0+žpu>;yr+Qfe P"m7J G &]<0ZL= ZbsFQ+ ;k &|Tkς<ݏ?& X*otJ\k P1KVKQj/FOt `Q FeYCTZQ=ʜyzfl +`͟}-}e$@$@$@$@$@$0WhmvU~q:L,U2i<.{Byʶ3s!ku͙K  @>$@$@$07SY1sႥ,Xm/7B%s)\[)UsTNeHH l4OMHHH##:K &ނ ^s]#@$05xg וew8-LH$@$e4Od0œ ]N}s܅@SzF-SLQabNd3`}&.ĝnN}g$@$@st<Ԧ$@$@$=S3$1 e$OFʮuƙIHGhٻ( e F@>/CHA$@$@$0 a/2pQ{8\Q_,Is%EڳW,}R[j֚8bGQR=xHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH ( rUعP坏qGi1hԠs q47{@Cy+tPH$@$@$@$pH`6Xw'`Eщۣ"^1LV\hGS|\$@$@$@$@G=\?Y62O%PK YAO:5wi/"#j;Dh^d0A mY{hb³#c>ӸWh Z.EԉHHHH`.k$:t;uEWZ.a ?W Hd?4Z#k1b5rr?II{jpP~mC*uh$XxZ8PkQoJ>чۺ2#kr/    sWR_ N݂|օ??_YNj?Rͤnx\7 Qر %޲\&/4UNY_ډZv/ @13WoB & XI1l+84Z'p\fx }cF%r<^ƞxP戣1B^wCBԠ=l![|-oL@$@$@$@$@6`=;AUA+r;2P`r3Re],aZz?7uN+4r:16/Cj6B/~Y &1Xf'DAg!&!    hWep:!:piom @p8h M63B);د @pQ}ը5C$nENgpxX;'"(( .LKhOB& YG\DwB8ևtXhđ^LwF-57asQ/+)J£d8#cX_jH,+AKk % \)d_%Yy4 iL{#i>ȏ*o3okPzt۷tjĮA(/^ ㏏MP{Vr3xKp0K\LTUGb|*9 3됽 }ĭgf#_1KDX'pM UZj7{\$Սn؛pִ(Q3xYXʍC3s2auC\2Uull_F7n'x/Kٸ[;'zq[;5ۄ O]i6!mkPK,ޱ0m(ۄD3Rh"qcNŊ,0_@fD$@$@$@$@I$ڱ5?`m1vatX˧YL260e9JZ9 t; M8(:'SweZyZw,FrOh&)l:rcx~'$k1V>3rq7Ǟ)C/U;wpϩigv fC82G}ՅM R*G/ea!!Se[ r(і(ԸBR-r: G$ GqV^e5^Tk|HHHHH Hr8Z*; Q"G DNؙ3T4qANt nKcĊE>mgGY*bTC%-2]߱L=ʎOsj=U6ytj؟kRbĜmn7sIGECv|ƭfn>'mvyxxPIz9c ~V҉տ½]!gjx2UTgh"8L0Eנ.9=D.R_U` ]aۢV$$O/F\Iv0gJ]Z۸mM}1KEZs_$[y5<蝡L U 4kǸp֠*ٔ.'Tv9YTHHHH`ȠևM>i4F*]+c^, ITh?ζl'ӘUsqL46lo9GDOR?]JW1gǭ:9S1 @R':c36NzJt!/Jӯ?.;V.+޴E˽ط!~Ϝ;|oV'zd6@_Y$+P.n^7.5p{}GܨOf8ɕQUwpWwnW˛:1Vw|!oK$wƋe?қL%wmVWc)  @HY}y!dơKǧc_,5$Cvgsrڊ`Q]iY}J66E^:yU{i^.UskFͧ{Ig=NlN( d',hȯ㏧{v\) ;՞)O]{}mcWǻXy3\(9YZu\șz @%f Oou/RA2]clj)z*~#iwXIo㞮8X޷:ſ_f?̽s!?"+{+:ogq'6~yҒ]Ve.uu^dƤ[2 sO+(hc>I ڛUsUPɖgQކ`U3+, Û-F.Ɏ-osEǕg @@+ -k#`"@232{;g޶6,?7=0|o|4`cdc@#qGr`BgG{<%z'"igZ.'2c"stЪ#. @(W`Ŷ7*M$M׳T#-/vZb.q&\>s:v )K~YPǹ7ǣ?;-VGΕї&^Nb˲Wq<9EAKU>"ܽ&_&) 3~(~tnMJe)KGОNNB0- ɻVkD2E?ܿC'⩼xsBFaHJQpJ-7rȼ)Y8tfrt~JDhiL$ىsTA5|#m\tB @jŻ.gO_oRS&^Lʐ5w3s3Ln+|:z_/}{/0*#Ư>w,n=o%5TdDž2=v$?Wm(=r53uJEEgپ$Yz'{t3ΤLmr;1m5m. @h !Oy|Y B%0oG̦_+W k,+{c'BㅭTx_Ь3Dy3vzs=Į_T;jS @@^,#Ϣ{{c`{EX/]ieK4P|xxUGӅ$zhn4#ΎH[vb ؕ×+Mĺ܆It^Sݸʯ_N @*`D޹w7G_kxe0~:[*q@Ξ(sSA*ӳF:`n @\͚ضmc`&oH~'_DRL[dVYbHA[CY @, :H\eUW @ &<ݕaz|nk_ @ @%o9vuw#uWoK @4@{U&Լ;Vš8XUM  @ @ ^ۗE&zR2 @ @ T1{"bx]R  @ @UTE @ @%'JH&@ @% % gիT[3 @ @cn}ruUUB @ @TjxkE%փLP]kq*A @j'PUx#mIuOq߲i3op  @T'PExjknLx)):~3ę\ @ @ ^ZKF-x{ק{[^ݿ( @ Tq_6wL @XU'WCr};oDl @ @KN9E$@ @# <1rwOnSoA$@ @-%P֘-59Lg|3S푷cM[8y)8WUF @G@xz{њվmm^/U8Bx" @Y@xw#>n8:jQuq˒u NNqN @S@xm6^h|T{K<;&UMqJ @M+`k޺x(u7Tv52MH5| @ @@ON>zh—OԦeiI`#zZmjV  @h+jw+>2SW@ԉ {oSH/$@ @* {jթ @,8{xu.#jW @ @Bݝ~C0ubvJ @ @BHZ/vܟNN̖Sy @X6-3_<=%@ @ Z@xb]CC,*R @,hjo2ut7T[r @ @@OTNw;#<1Rmϕ#@ @ &`imS?]':2."e;CKKCMb @ @`@{riN sN8r>> @ @@5U=QM3ZfwOnSo6(;7{7cy숦  @ @';#oirTBE+Onk(a$ @螸:_9Z:+v2Z:+ @ 'J=t׉T6 @ @l'J&&l_ŷJdL @@@x(bG<:qb*I" @ P[ccy}NLb9MkE1<W845 @ PD@xJ|re& :QhRMWEpO<ָsx#&UOn+/MrN @c }7S'?岄)_)-Mei="iOϾ D\ψM8#@ @@+ OL$_'.N,P ܿsG:u")/8v Ɣ$PtQlUɖorb @Dzw}ԉoԉOvG_zr>7<ӵ^`W.ydg%ײ# @/ |8~.;ub0vVUI7e+IGFतj NM[T)9$ @ @@ =1~m[gnz9__6)+2G+GK;PwƋ?RUҒ  @ @%'o2wsh(vLwտٵ(6O OXeGڌe @ @#":q[:ugZe WH[޾r}1#^-ɖgJvw6$@ @؝:1r9vOT?7%<۫k禸si&CdJ/F#ׇ3 @ @@ ,Ğt׉xԉ}o}}%zc`ku @ @X;Ň^#y  @R`']##e l @,Xۗfn"a<J @ * OMuAn @ @#P֘)ϒ*^xGX'cȲL/3u">8&@ @"P쉫qZ H[ĕEkus:><2OTO @,PExbqt-d6s Le#3sZ|GqpZR3 @ P@ቈrk/7ߡW3oE@ @Ssѣej舯vE X3Qh/  @ @ 4Lxx%@sEg|,:q|?K} @ @fhDco 3h+ah(v!s\W{}Rw/6OJrJ @Qg [@L-:3x?ؒl9p&[wg|oC"R  @ @@4Ex"S10($t׉˱U;7ŝK3CwLΒ . @ @fhD\?xub}tß̮ɖюGƏÙ>ؖfI @PYӹ +6bOp<S':pޖ_?GB̖O @ |s -M/HNh/ltˉCg&$ H{ IDAT @ 4Qx"b( ?6q_K'*w. j`0n=0Ǣ? EM^F @ @\7ec %(t ɼ4WI'f}u< @ @Fh ؝Sԉ+qOޞ @ @@'L|r}P33> @ @`4]x"ʑ=ij"c$3ub;tL @ T3=}UܱpD/ճT^  @ @f)<yo<;N1z*; @ @M, FQRtKV @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @ @Ã~rfIENDB`sympy-sympy-1.9/doc/src/pics/ipythonnotebook.png000066400000000000000000001106161412543434000221630ustar00rootroot00000000000000PNG  IHDRY iCCPICC ProfileH WgXSS@HhH ҫ^Jb/ !KZ+".l9uw̜}͜yf`D)<Lq+:&Ey6'Cyw Du3ֿw N*G9"q&$žނL7A$B\N1H16 .hl8YYDhG+B<bͅx SRS\Qvlv7lv7<6:dR؋F?Ujkф5-#9,0o 9l0U Lq ?b%E>Ir;HaPa`!dxPl~xԸ&"4Z:gdM|ϙ$v1߲PC4ZK%@(3.L9>I؇'^xp?Ø1Lq8c>0sowi KBy'L$(*ŔL )i5J/僔TPjT~SRפI KKK;JKsIo.n*+=LUR$JjzFFFFGAf@fL!K22i4'mMB@5t=I@?eN.-&RNZN_]n\\rle%o)0,R+*)R k)Ua` ]'X(gg* *+ *+*[+G*/T.Q>ĘLf s#0$IxOtm{*n*<\:*TYުɪUTj&jR;60Yidɇ'SGMCSoSi81tLܪyJ_%ڪuZ9KJaαյ%{۵u u"tV<ԥ&nmқDF>_EQk  U k э\ҍʌn퍓ww&6&|ti))eSnͲj̺2M]5aizbmvqWsr,,^[Xr,K,oXѭ|[5Z6Yﲾcða֦拭ضֶN.ή}}%rm3;dߩot=:l].,8=.]ڮl2nn\ gI_z{=yt\yzz{+zGx{?I]G w_ß_?`4\ -0,8qI8i:#`Ɩfl[6<+dVɬKB/1{1~Q$%R.rNdu(iKĨbc)Cgo;fNΜ[s .:Om^ʼ#EfK9\7Vn?ϙW{PЗ蜸%/<łWI~I''W&DԥJƥ* 4uLE9tm@qE171S r$F$Y.Y%YD.8Papa"E=e1eK/ݻ Ye5{WZI]U V]iƚkz~&G6Gs{uuX5{9<0s>'?˾>g?}!z1<Ÿ/^WW#ߨ|ke(dѻws?~h⧨Oφ||.bk###"=z`&$ދb١hT F A? *X@P3`ч1? VV d'#r 41<|y /⑑##_.cw2BM=rjm_A|m`X?h pHYs%%IR$iTXtXML:com.adobe.xmp 722 424 t@IDATxxƓ@ -{ޛ M" vP4 oEґ.H5 e{7O9sK33!!   |lHHH2 {@$@$@$`6f3$@$@$@4; DfM $@$@$@6ah6C$@$@$@ Mhv͐ ;@$@$@$`6f3$@$@$@4; DfM @N"/III 9%  =z1u%   ܹsp,X0:::W\/#  5j"y ?l2egDHH%ly9 m? j@$@$n*bHV 9! jP[@sX+HHHf4;lJs"Wر /KO @@Џ#  _"@×u!  &@#/;G$@$@Df/= B$@$@MfG@?^vHH|_zԅHH͎~ KO8##$-V+\-<,cQ0 8&@1@~z{oN-2K&HHevΊMN vG\4 rٲCbbrKQ;jYMlJ$&;g;`TA\?Ct$Oximr=,!'4-)$<_H>$ !p_"#ө47?SN12{ӷ)%?餤'v>cbs+yFh#QRyK9rq_5T騜QIc\_HK SK0=ad^ Y72RHrwN 43i@R)99Mcϥ4oQh%jϯޤOHHNIIWeKXQ#7l}z9J, ̵.?/TkٽGD|_5 "g/,zAΝnպ}e3gO].%_2ʵf7B`b;uA[|s͈|㿏?g* ׯ˖-+ٳg_tiĈw}H:tcǎ+W.T?|.\hҤ 2cƌyOmڴi5jT\>xE>~-Z~_1OΜxO0" <fW.<+)W|&Lqk̻TkQ}_,:#6~v/S[3wΔ:υ-'ZIg%aJFWͨ3:`}pJ LL!3߹sš3vk|CoU̙;wYeݺ'5*~tdkVm+U+Y0` wN>qġM 㗝G[oFwW#LO_av ]ZVZ}j;,,m۶Fi¼+V3ψʕ[x1Ǐo׮vqϐ!Cpw߾}׮K$zqҥ3}6 ,S7o>c iG%s{qX=8i6R +6ږ'Hc)̎l_~ u'4hsB0'@mӓLd4 8$ү,l+͛!D(2>C=Sݶ\Mj-8?DpwhsF(|-eB C^~يDFjȡ96Q|>qr(6 Je1.7;8ǎm3wnoX=Ts*wfbLLrw֫f/8)Zk_vM&&M5ԨD#f&19{k[GմdSes(e$3TY Q ^wi4B.@IXp3<0`p|rbk Aa"sH֩]6Ç7 W^y%,,ˬGD}fΜ.(> #ywws{kYH-K2pXk^m!2M?wCV S( 6!9AZ!MH!$ N-sꊞW#nlIl?zK4y;~axM͕-5~4)5iRo˕=݄١l(%=Eyܝ6JbbVK|K-i*Vxy UGW)/۔oH9w Ɔw"##EC?|FVڪU+Bdž dxM% *ɛ&wѮ]nm4J T>"nRЩ[M6BFK-!o~jFSHWxǕ i1KK/!<7$=9ӫt&4"H)&L^+]K9$ d\O$Ԟ?DCOEUzp(Bע7du ̆ T’Du s˗rVyK&0#B4̙0>޽{ YTB"ZB_{ѶmG27і~f# ];H&(}fG  68`][bP&>Zꫯὸ&N/X 6@&  lׁ<9ҠAUy.o <B0f>v-Q9JTej^#Wȝ&޵84gK'\\tnbEo,Zq6S#X(R7gƱc0]2l0)|ر¥!s{W_} KU*MoٲEUN^aʻ6lCi&%XN^{ts22&$W 0*Kbt`၅8mN^rfe2]l& 6ݱcIK H`ef7m/i[J|O#XFP 8lۧKK4%-eRPT  oAk6lg0` {%ϋl}re;rKM~RޭS}/dm vtY4\ +rgN_BK`*Qw_O,UT~V^`Te6Ts*q-=uqEݯ7\k}g;sQdYt`j#:Z$@P.qYx]1~|HG'VͰX7NyGV`C{5čs=b Q-Mnv b(֧O͆rdqA7|SH===`6|&"sFnECUa6(،õZ‰*J9F#Q :П2cPmŰD\]%sHl fʗiiu]H͛EDGG YU%w(Í>U qR3!APn75_mQ&+0k3.ܕ cZU8",#ѱJ Uyg(~k ؾ}CkIrbbbp'O"6eƤ Ҩ^y=Z) _ۊ2eȒƑ8k^yo G-VWfzD-U/Oj-K#X?VL@ug3A+N@~.U=hZjZ}0]È1_N̝{E%sŋxa%)SF?R Tz%[`/@%DB%%r3 }U؝X1[ZܟE/Τ'NxGGD.ZY?p`] S~Sѭbbdܸիv_U.}}i >l2°жn\+{jhyي'[YH*ev\Sp~h(XNs*+?u2i ĴiӠ+&hڷou}M$@J ̎+rKeONNkxum-T Lhܺ'%˗9rdڬ`C ZkxL$@@@ݻsi=z&2'3pv2Ņ&XH x=`3ptKbgRk:0eӵkWO*V+o> yG5+ {u n)OuS2 0ZW*jHHLQm(HHH ˮ o[σڐ @]#  "@÷!  &@#.F%_uܹu;v찼D,rA6ʟ5jlR 1~{޽;Q3!GѣN`^tX"};|qP'8nʕ+띖v˗/2-<}O?})lRX1iWn9BwQOBs}Ĵnp8B ߿N/_|?uz;<ǖI ȃ<ܹs?/Mhe~9oDEEi IOHNeٳ72 m;v8)I`" NMSN:aʣvڞ\\*U4k,B0çUV{/^t&Al9$0bC̙#\jΜyVp,=c5̖AAm@n!A`#rRRRpNC0N<)+Y >jϟ?}7o[2| Z:eB0A]vg}>({b?Q/^T)Un1yqi~ _~,[7?+#I&/3'r6m(iD`Gc駟NUǏ;H 6lСx Q ߺuwީLyƎ /T(D&+K]g8PbSyHĉAN/ҩՃ}Ȓ% *9 һws窌S{uཽۗ-[zݻwcɒY ,/hv˓^Oޣ… bŊ/Nll̙3bW<.WX0~x|h ` 2D{Z/AKom۶QFZ5``sg]'׮K$zqҥK+3[lDo>*4o\#ƍ`TVM{xq>*K,93+J,pw>7ed썍arʖ-mɍ7Rʗ{7}iC5B#ҥ]`hJOOmÒFxC["B N(xt(:Ar&r2f9SO=n:_j@x@`  PҪ 0M+V30׃ ab S0`~ 0 7F\0իo$gA44l3M;VV7 !l`AdѢv)V{}8-5=;9kMޔmےq+@|>}ڻ)7p:?#c/9+ѣk#|T>?ސUV%$$Ve`Jx7z`#\_/Fz m|{FQϧt"o^l~ÇgEٺ2!9/XA?AiΊat6&5ZU #wÆ .X߆KLl\"Xxae+HJ!2tSi3EDbET裏!.kժ 3DBI6,),0cPϡ [kẀ#G'&nnٳ8JDNΘܱ-#_e}օ5MF7qVe]D+ K/=3mz;lCmSC|;b#Sao,T Vc6l*j`sh#~IH裏fU~}̕`Fd׮]T5L29mp!Q#x萩ꚜ;_fHዞybЪظAQJ#n^DުUsW|e^_\X)Ҙ%)|]jn\_Xn[o p4OAixg0-КU}zh!Pyw~s,%m _`=`hXbЧߐkwO8!JO"ո&/liruQxR1xwij֬ժLԎG]V窶lZXS V q?3=5MJ{hA%W*b-ʤxWcXQ.*ӧ<KP6I "uf<kLD-q񡚷?% *͋Pnu*n91Q؅f y-NbZ"ozm.]6,s\O N-ٳ뛋ÿ\2#+~qK?T[T|ʔ)c" N2*b_p4[bɥQDB$'ʀ,F;( KH:)kiX-Ўg sG yh1Wl7E^Ha0) # &b*_\B &~bc:yz"x#Pe}V9pYb5ri"b/0ReG(6Oh^_ 7"dl]!>C:`W4{*%cI]0䈅ʻ > XWF 4:}>h=uwYJUUiұWi#]c\lbO>gԨ-}^aFz6D25Pb:HO3XW)%$#"؁dU: c;Ly0(}'Qb{+JLc)f'XǂE c e]# ؓ&M%ᜐrrD_dy(Ɖk[J'cGȗu `JHFr-0B)40q^Cb)շotD4,TˊX: WD-61SO+HtX/ڦazL㠭?"@o=UŔ 6"hߗ|9 PE3\#ag.մiSڞ?|4/^ڕS$U_7oE8a1 灇 z. ρ݀Y}1\Vk-&rXr7DWlSg#>G< |Nեف[pk!2 g-* >a†NFŽyD.\s]B_rDbyQ=b"G>c=6e *2IIo-_Lg&g(q4;|Po޼y(LTvRuppkcxژYݒvȐf#<]JۄF;!|R9"\*寲PKs7dn!YAyv%bv򔅑0 UXWx:|~D>ivvUMe0>֜4 [vJ`%T9.@+e&BC4F8-g7pZ1Xbv`8! B_:0ǿpſSm1}OLq Lr^oeW@TU1u ?=9{ +Żx4ojJKn1^g1=*h>Dn Bp` U`"U}UyQ"l.%Uax/0ݽTC8 dGD@,qFb6d&֜R[exW^t&TsW(s2ǵDiѿأg}WSz:j>l̏ Udٺuk@Kձm' 1``vqPZ6mԏŕW/P(Su܂Jqqqg~!5l<iK5<@ x:tL4+`]a|=lt @~MFN'YA ywS:FG9)mT>Z +n#)eES SZT) D ᡁ偭s@%*k^(SҹBsID/kyx)N8ET7C]9\azӮm 7xkr7i}[f=B8?!B/vbƌs&I3~3~ uZk "(?\Saݩפ lsp=׈Y!},_r_J"x{.XD+=ќ[2322Q,Ǐ';&D#n5aKepF<bkڵkGW-Ƚc;4/>=aD e_ɓ'ˊVe@< m]TjJUKL' E G$'ΤFuܨϔ{=~>_;4@Ӧi/cӰܹ v[.)SA a=S%rH$@$RO 7 O 7 O 7E?xhEOwk5}|ܻwݻ;;Cѣؕ.U9G$@Cvγ^%]9N۲^zHq8BǬ`+M= 2׬2>fO>OP{lRX1L*ThV4Z T7$@V {VTry:x?`|9qqTTg;wnŭcǎzc& @@5SJI+˗džq8](l(z4_Ms_>HL/ #UVx3QÑ:%yH zSwp&` znaх[eb|Ϝ9sW_C>x ܂9,L $؎|wٳW^E&.#99dɑ#Gɒ%x3gΤ`2M5&Ɓ$&&~'X"-%7*|gw̳mHHgxѦM/q~ʕ_~š㯿z׎?>w˗/:tղ"0z%/E¸|>|xQq;JgϞ]zuU+/QFH[ xQ|eE ~[eL`%< qȑ /D &@l\/ #Z O :XʻpBe;S85iD)i͛71cw߭1?p 2/Px뭷|AL !xǣ0G2Gz)dH,YD$@Inav,_f$hv#ƴ>F[l! ڮiasmvРA.\6l8nܸ={)RD5%qǏD={|ҦM| c:CĴ>̑ءFlV2v GKժUb>Gy%8KYTQKc |<Gk(`{}p]Hk[nQI׭[W]r%[#Ɗ4" 4;1Pk?00qno kC BFn`H!c>+*^&eZ  SN2eʔXm;v0 CM\Gxx4_Ut駟^`=+"!#;w%ŋ|6@ycց_wI 2x+?샐=\++ސ&*TQ~.cC8 t6i @<^z%7i4#`QԩS4^ DB@p5lиx#_bՑ[$@CfG*E`˖-*v_DRN T[RFjo!Gb,uXaa=%rX$@CfǴM~]u%φmTAz:屪~d]E$hvs&/>#~UG⯼ f;E>flX.tñRI!f8?R28KAUZgǝZ~8DuPlܰ:&VXyWbz؝ . @$Keʔm۪26_`4V8K&H͎z>Y{\ai]v~$8:R]&+( ?xl>:%0B+YPr_ɂ I1>|Ž^~BlHH8yT^IH#,fK$@$@$hv }hvǚ- @/O$@$@akD$@$@ANfG> Gf} 9~M@WH$@$@ pg.\3Q  pW\H"hDža3y6G$@$`-4L.\>L#)HH<V4cǎ$H.TPTTR)HH#@>tӧO/HHH+hvxuAI$@$@a;r6H$@$@J!o  ۑA  V4;ɳ$@$@$`;#g$@$@$hvgIHHv4;lGIHH X '~ hv؎ @O&   9$  `%@#XyHHl'@vlHH͎`}7 Nf +o  ۑA  V4;ɳ$@$@$`;#g$@$@$hv$@IDATgIHHv4;lGIHH X '~ hv؎ @O&   9$  `%@#XyHHl'@vlHH͎`}7 Nf +o  ۑA  V4;ɳ$@$@$`;#g$@$@$hvgIHHv9mo E )))>>>!!!11-AL$@$@a;r7}RKO]ᄏrs[<&Lػwp$/\_YK9r݁ROmzڵkIKK;ydFFFkFϜ9T:O~O:u뭷+:rfĸq[Oo]thC ^<5GH&Ƈ,r)J)s_ZfʥB ߿7mdʦtA+8'`Y;k'''@+x4obc[(qӈڲ<@.%?جj>9s檶EXQGy냮 .H%{VTr_}ZU2w|?/sMo6QQQ W!m͇xh́%&%%r #,"ptSuUtyرiӲRKR; v,@Kh:uYY۶ngTmapC޼|Ѣy jRFoT"=pS(\vQ'Oެjw.K(ӬY3yf1! Főؾ};HpΜYo f{ھ}{Q+%%e„ 6%1TRE<SսXصkyrqدP@B~} -W 2gj F|1ֳgh~x92LZx%ѓ{VWCFGGBk3#!!_lQfFƘ1K[GhQ^ IMuJ+ڜo]U-ZtѢE~Z2nJä ̙#ǫ*rK-D*{׹sswqssWGh }Ly9k O<1x`8<,XЭ[7g%}3MCLHK3@ΫW1?K6?**ʕ/~ @0ȑ-n].7l8Vۤ5^{<( ck6Dǥpaǡ(111flTGX\Ϊ&"ptl>;D~'(n˶|RRtFe W9wˠ< JgGiw74$ێ怱pgٝEg] 31˟ZmZFm׮(gw}f ᮿo"6#L86]xѢML*Sݻ`R11.=|w[\r-!D"i֬H'%YQ0._NG+_gӵnݺTR[)^z5 s%bF97رC3LbŊd)Ss۶+kZ o;R|%KΘ1G0<sΕ%E5jԀcǎŰ?-2Y/- ch_d >jaQ J>֭[Ť̝wީLzq`!ߘ,L%W^ޡHL<СCݻwRmW4g@ W|'@}D޽e90&\11dȐ/Bz,X;v쨺+. H0 FTԾZ53(bE͕9(,#Qd|\{]K윐Wpn:V2n/ؙ3g">b<#%˖-C˗ÐUV!ۀMr9ڷ4dȭXssE8>})bA;>ŋ pG+.s|-PIئ[`aذa"(aܸq7n<~HԂw<٦MzBKg9O̻[Fb(o0FÆ Eux\́}x)`+|JH,իW1bN Bd@^׮]- !n:ٰaHOO;J] nݺp̀؏?nղ#0bdy? 0dǝ5l|es+˻8:ᬗקk2QŠWңGq֢E .^W@s%U_\'1U-w-@!@fرmFh)F֭+4k?qq#ʒLټ}{ aT)d^o7߄!ulx`|`T9Z/cw4]܊9`Cr;P+D1?駟 !P!K W^i9rr!aFDDd-Y#3b P2O0 nI&df|\xR%0'󬨎<2 Ul7y(^zIH'֊ρmT2]Dp0Zb-[Āj-0G (GasK<,35*#y0Bs[\5^L uф75p-8ۄi; 䬤]ϑ!` U-_pȊl VDt:]4GキUj4iRjҤ.~{~+Y[+?@EԧH+pyHc*%(h7TUGb3l*.WYX%A{ 2A[@FaqW&ͦ:;Ҙ 駟ĬA0a4mT#gs%M񑵌$ ׈(e2BvO24" m؎mX¢UL 0a:~z!S/'Pfp.bJ0"G*`%-e^X)6 sGL|dgZU~~Y ۢ BO.9RQ<9Vʻ"Pe.@&"'T%&#rU2ݢQ^/С4Y&[eNxAQAKrT9K#|Lה(U BOL:c!ʰV[W~}g/r]a؀!6<1|;nՂUgc}#(ϖ.Wl_S襡`V2&Yd,im+W4h GYlԡ-cd9'N_Q+b3e>#20A"\U.KJ'dA̖,sSX )CU$1f!#|Jhl_gvG{9l!2ad]ˢ< 9|+Gm[r0lTEt*6"*{a;/2U9r@Q "#G"RX+/J<_e.WY]?=IN@/5~9փ\}\DY&vzo,F~Ow=2@0~)Ο߻e˲zk6lg0` {k.3ߵkW `ٖ-[>ȎX*:in`ik6UJ+LB;+K4*²pHf"`xQE3 4IJxGPX*pQ_s'gWGٸ:`Itf'Nb'إ^#~o22zw®2̈́m',3;,\rgT:uܢcU2R˵205Ə_=v `cVׄXR _Җ s"('v@_R\ 6r(bfx܏T wE}U~p]|p~^8L3]- ,kl`u@=,J-5 ";(̛7CfUv`Up2'g _q[efs=f}Q!"Xo߾L@@6-؟MvK ̈A*^`g d{i*$!4d{y2(3>Q;v7%Jdm[<\5j[ז֧O'Yd2…*}L2?D`o֬Ts]w%IN,sOR[p*v'6뇥(jժa5se)_m$ ,.;lJ\H hBo>p_ue3A7#* cc=ܹKVf-?xqc >@I͛7z"92aaV\HB<, xndK-#EfW5}vX˲"C=Wٜш)a>o,f@>0~A4*".VN3icai#.flr+WNw}$L޼Yۘ\Q # y 3b9,g\|bMUfEovE 8RU ,iύx[t ;L`(X W*Pv5:ʣšZ!8K {cng_ ?Z!wGAvrSm]9-i*+oԌ-7MA2edy˩ +lyy!ym:ya]dD|fX]{笤|7LOB/:A gB*T(hfsg=5͡E iݧlBa E@WHאdfO` (=!V')[ڝdF }8<plؔ'"ߙ >f͂ H(z^~GLE8T)nljv>SrRF |d$ >_YHQ8d6hМ#ʨθWf(.A0BpR 4qT Qqn驼B~]PUH~,iBp_{ v(30E\"kr)pʕ&oN|VZUUp \c#ia1.`l,k\%H':=HuSeJbP:2$l:5,oy%aV(FI@0=1*[p?V̝ת#pr@W_mڿh5S2 a}4ID W117 A1f[HsTgR륔:!״gQGx[}2+{ {T '}h߾-04Fum-TPLh95YYt83`a b૯6ZMx/X%<8G]@٥Ò oZv팸:(,H`Gw9%7 Tl,|z`vۻw3f8,4;$@$@$%4;͒ @|Ϝ=&  /%lHH͎{1 x/g$@$@$|hv3gIHHKhvx <%  #@#9{L$@$@^"@K, c  xܕSҒs)^<@w_w;ڴ)4,˖xHIbWw('=/_ҥr:qtٲձbbBի75*$4T0A$@$@$O@_޽KG3cXk>zttrLiiO Ȉ̟?~|￯} +of„{+E̡ tHO͑C4 W̎-[&׭ws  Vk6ܞ=__sT 3R]]hZbb%Sl28DK=\׮Uz5"u괌>aöɓdա4 dGّ|={J&M*Ѵ鑿k`dbCGn͙+,ZBNyt毽;v#;N`4pɗ.z a;M*-!H 0;6L   'L8}k͚!!9F۶E#s<=HNH#_|p͚R?Ol1cQ^=yWHMU^2M$@$@$`,f﫯V C\毿.һg@I9z\o64gȑ7b&ŧԦ2$@$@$y;nE:*tBP{W]<-Zt̙E_~9,"_# ?{Fh!Cn\!Q !5)0bWbOo*Qn qXIfN[p8,c6]C4',O$@$@Fفe <Xqb+be.:$Scyʕ+򘰈[WO`ʒ982'ϦwϜ99 {[WQ#U ̙gv:nR95ܣdӦm>8Gd$8{ރrmV l&$lYU+_\|xb!h S}E !  _&`!:AZ+DHD,7Sr|/3.ĵۦLGpX55XHHR}0;J5o._FpwLɶܹ!*\Mz"FDzk,L!$@$@$y;aF[\9>s'v`QZZ&M vVmjnC$@$@ [ù{˷oo̶&3t+{Faf*c5J L 9+'YSSOZaC' ?XMMK{,]|5$   3;Dp by-ȭ]32i΁bvIu`$@$@$L̙Xi"]B%U;d4Kǎbv'22V}&d gC~lHH 3; G&ũpa0q&,*+w5"s&é|w27z._^Aw. eZrqޛϒX1N9܊4VF?TIpxyB22r-?_2tmR-[&'Z׮]2l_4`{-$@$@$̙aa5Dpxʉ%#K.%qYkWEbÇ^qV͞mtSϞ]]; Ǐ_3v,fsϟ\> 0}反)S7J4mztr, =2TX^R%yP˷juJe#GF8G`.2en;6򨂘J;Ko]]k2s>D^|)wG[f/妮f+< $fGT]~qj&ǜ>}T\=[y\KDtta0ˀb0 ~nVUeXxmo-KW Z5{rD+Z,ڠszt 7p 3IHH dtxtv!'I_6B~@aQ77G?yr[GFL~xKҧ6ntV1 rY#9zbR#UXHH@hњոr$6.؟T(^8p. @ə+X?ܦ?Ğ=X.хI+"m7KOI$@$@$LO(HI(ѷKtꚺYݺ)V3ƍ1 ǭZ:6V% An۰…[G gLqQdVB$@$@E ̎ +P0D KG:uZ*W+S1  !VlG`bOIHH'J[   $@#:L$@$@!@;* ! ) ]2dȴiӮ^>zp% pHfC,2?))).]*/_d% pFf32&M6=C|ș/R, 8%N l۶-));,T`$@$@`H<DZzz5k?ogQQQ͚5lHHhvxDߎ!E 6^3!!a˖-UV-\&ϑ#G$@$@ajhhĉ:tXr%̎|pwuמ={[nQqcڵ?x^̙Nm q0*K:uW^A?7ocرJ:|q`v8q \uZLMMcǎ9rѪUt  #jdddٳPeBMcbZu:oڵK^;t /$/<abzu QR-D^z4 RJ i(w܃oG0o z;|Ax_ɓ' %:vѴi=zOpryGEvl߾f͚Ei>쳲7(  _&@o/?tC8̙3E{!E"44~>;wM{ѠA5ʆHH!@ξ fXծHu/.$֯_pמ hvIwZbPv%K(A(kbŠt`$@$@#@slF֭['_.>} R`sx-' \X;Zmڴ~0; "XY6M$@AHfG>tu͛'ԩc|cP+/^ 1׷Be >HlV(I5*6psǶ-Fl~RlH͎xnu+Y,*9s;׭[dm ]4;|أիh ӨV`v 2HH/A%1!GEEaoP}  %@;`:ꋑ.1RB(k4uQ `1CBrɸ #4DUfD"%Wvg?9qf^s'ʸY`Ԏ9.3̝;INێBy$ Pvo7NhOF X(K: 1㓀$P[x1/! ,[ +M-J8 $ Pvo7c3#6nxi;2' H@Pvߺe$Xi s̡Ν;5 \b_5{,H@@9hXp %!aǺuB'mڴiIA۷o/im۶mc@s1;v p#1H?=z4lذ~ƍ;蠃lj$Plʎb.?~!C~I`;C9$O^jޫ^!Ϗ5*y!t%ߤI˗aÆ & t3$P:J9VlT3o֬Yӷo_>yAO?4 5bU 'mo{n|Ok׮=w+ĭHÂ$ $GDuΝ;׈sҥK,g_5k|5-V>Cx\x aۺuv H@C@Q9O3Ű}x}q%KZl}I]״8`С܅;Cv5%  ,%I};v,8 p,Ԗ pݖ Rq_ H@6>5BC4k,FqŊ+c-a&QGծ]? H@6?GŻ۴i;f\>}:=6m7X{^+K@pʎJ|aIvARXp!<]v-j/-7kܸqMo$ J&Ii%>}dW_}g^B[N"v| pq.( bkuVC/sNpb SquH",,2 $  Q Zy;K18餓J5 d+t@a:ڽ{wR̜9-G}4SUe!cݺu~H;p@ ]pUP@PvTγL;l޼y≮ '|o뮻nҥ]vC=t 7^k (JL՗_~A4[og8ݻ1cgy[MFzI@&&K~=5wZ*^X• 0Vxʤ0`T!>XA_z*%/ {駟>y54'NAy\r%xp R&hA@Epn޼yʕqUj; |-bǝw9vX5wqG*{(! F=XLsxC aw j*ye H@C@Q9?3駟(_uLNHeeeOJё#G)u]ɹ`.m)gؙJf{㭷޺+O=X?a AXBq'x"V  HRQ{dFn۶-NSN\xaʔ)/IYi R(,{ e˖娐%VV&&_G|9؁`nKVO!/M6hтuɚ%  TeG<4:˷3Ť.w}l.$7#r3gW/>o޼>G/šZ!j?J3(d|@X~}8IG+ H@C@Q9zLɻVŞ4}'ѣGx lZi{}S3GA\4iRРA.(Y-U1HV er& 4zu>*= ͂Iq & 8b()maӰH<fZE9.,RiѢEaPoݺu# H@@Z1J*U2"LϡhMu֑s&MVKX`_c "$PpNq;JHbIlY@PvTγ;S:i-!kƌx]v&;{l*`$ZWg,`\( 6Aௐss&U&O!mlւ$ "쨨]/iO>B*;,x>#N%|vɒ%XZwuJr>.N.9bԍP'tMAA}&EX^bf`z5לp -K@ʎy{gwcm3l0}{<qA0"&~m9JR4#MF+k` R!"t)W_A|_=~CW-H@4ʎ z⸏+NSf͚}+E~ ܲ>}zN@,v+rT{"!,)o~Y`}ŏ>} 8H߇`bl8`\%)XƏPyp9묳PHǶ#y٣$ r!cTgc%y;q4 o1G|ΩF`uJx qХK0}ٳg8I/DIrq Rf,AX$PŜ_F u~rfaXիi,hSNkITRl vsBh,n ce*a+JӦMO裁iҎ$֦8Z6yղ$  aʎ:p45 ":tиq?H 5DjYn H@H#ue !D8ϤR3Z6 ͆[xV H@uov,u#tIc7$X2^z͛7c^LXb$  HPvԁ"iR~*6lxdž/Z]vpف4)eI^ $ H@#'Kg3bE f;vR@sPbɓ A;vH+uӦM+ H uvLL$w>\\Tu%2GIʙ\_s=z+~ ҵkWWͶs5ke H@(eGؖQ|zS#^|駬CĚ ѷ !ʤI=\bG3`kر+K8* $eGfK 1|pFH6mBׯi8C06Y0hѢE!x졼o_{`gk֬7Z B^ H@H#-eqYfCĜ+pc*hI CSN9QF & =ʃ 1CyȐ!Ȭ~;Q2$PQ,Y3ۜ1cF,Îݻ3P Y8p`-[rخ];VXq R-裏>kAjD@Q#\2qXYr D^.\zdٲeXm۶~!"+&FI#ܹsIÆ5IMIJ$  m8uڵkd0 N:NIeBiӦUy6KD$  W;Aq|=)_ >$,֭ VԃHMw`%zGht5 H@H#Ee ў4fhW(Ϝ9߄HBX2XI}6( Hr(;5kV$. Eyr [ Y9M#T֪U>z'-H@@ (;J?R1_vyBBK.ݰaʕ+Iv_a +.}{%Zv99|p„ H2, H_C ) P͛UׯI 1 ~9#]8L<[nH'-H@@i (;J˿UQzY::u Gir* Fy6=ѣGUoҤ_|ѷoO[$ Ёijw'lUh^t۶mEb:3l0$AB<={61Bj\%d/9j4`+K@@ ?(v rAaȉ*PHXI腽K/t)y5e^Da~{sR;xҺjۑ$"W;RY⦰ ΢8 |3tJsJ&E@l+~'-K@@YФGAiٲe`IDATdye3,uRd9O]ۗ$  !eG>}֔!HǍO:0ر>6Zm1֬,~֘wK@@'0Nsn xy`0dȐo=ɸSb^\xv' H@eB@Q&"abѢE{_z5qđ#G>JHsYP}7I@@FdH@$j$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@Pvdn$  H@PvH@$eGFF$ e$  H@?S):_IENDB`sympy-sympy-1.9/doc/src/pics/ipythonqtconsole.png000066400000000000000000007354071412543434000223650ustar00rootroot00000000000000PNG  IHDR.nD iCCPICC ProfileH WgXSS@HhH ҫ^Jb/ !KZ+".l9uw̜}͜yf`D)<Lq+:&Ey6'Cyw Du3ֿw N*G9"q&$žނL7A$B\N1H16 .hl8YYDhG+B<bͅx SRS\Qvlv7lv7<6:dR؋F?Ujkф5-#9,0o 9l0U Lq ?b%E>Ir;HaPa`!dxPl~xԸ&"4Z:gdM|ϙ$v1߲PC4ZK%@(3.L9>I؇'^xp?Ø1Lq8c>0sowi KBy'L$(*ŔL )i5J/僔TPjT~SRפI KKK;JKsIo.n*+=LUR$JjzFFFFGAf@fL!K22i4'mMB@5t=I@?eN.-&RNZN_]n\\rle%o)0,R+*)R k)Ua` ]'X(gg* *+ *+*[+G*/T.Q>ĘLf s#0$IxOtm{*n*<\:*TYުɪUTj&jR;60Yidɇ'SGMCSoSi81tLܪyJ_%ڪuZ9KJaαյ%{۵u u"tV<ԥ&nmқDF>_EQk  U k э\ҍʌn퍓ww&6&|ti))eSnͲj̺2M]5aizbmvqWsr,,^[Xr,K,oXѭ|[5Z6Yﲾcða֦拭ضֶN.ή}}%rm3;dߩot=:l].,8=.]ڮl2nn\ gI_z{=yt\yzz{+zGx{?I]G w_ß_?`4\ -0,8qI8i:#`Ɩfl[6<+dVɬKB/1{1~Q$%R.rNdu(iKĨbc)Cgo;fNΜ[s .:Om^ʼ#EfK9\7Vn?ϙW{PЗ蜸%/<łWI~I''W&DԥJƥ* 4uLE9tm@qE171S r$F$Y.Y%YD.8Papa"E=e1eK/ݻ Ye5{WZI]U V]iƚkz~&G6Gs{uuX5{9<0s>'?˾>g?}!z1<Ÿ/^WW#ߨ|ke(dѻws?~h⧨Oφ||.bk###"=z`&$ދb١hT F A? *X@P3`ч1? VV d'#r 41<|y /⑑##_.cw2BM=rjm_A|m`X?h pHYs%%IR$iTXtXML:com.adobe.xmp 1582 1134 .`@IDATxieUy"#2#2#NvzHmc(\]* n u#>PS Ňbm)袱B@ c0 vgzv3cDd~y";uZ{}{wCFa 0@a 0@a 0&Ca 0@a 0@a 0` .@a 0@a 0@a }@\KF@a 0@a 0@a <a 0@a 0@a 0 ypo.E a 0@a 0@a 0"k 0@a 0@a 0@7 ži$ 0@a 0@a 0@ȃ0@a 0@a 0@a`0R0@a 0@a 0@a .@a 0@a 0@a }@\KF@a 0@a 0@a <a 0@a 0@a 0 ypo.E a 0@a 0@a 0"k 0@a 0@a 0@7 ži$ 0@a 0@a 0@8 ~bP@a 0@a 0.Nq!g`0p(`\se" S3 0@a 0@a \ aɅqsypPL>V@a 0@a 0@X~P{p2 0@a 0@a |Бb8'+`bg҄0@a 0@a 0p86cwL\sBz@q!VcB@a 0@a 0Z /vgsrykrwV/Bk^@a 0@a 0@!a=c++uV쇇J a 0@a 0@a G  8;+=!Ƃ+ʃg!ٮݸ@a 0@a 0@k1pV,^`;5.:B~x'۱ N0@a 0@a 0O/=˟^yp}X=<{e@a 0@a 0d`Ͼ_;!^.n~YkY/0@a 0@a 0pa0g&Zk bX֗gsw^e@a 0@a 0@6{pt[w+fk <؍csAo({1o~.k)0@a 0@a 0v]~n܍4\/.n}[y67Ä52ĩ@a 0@a 0v^ni{>`\.~I3{$NbK Q@a 0@a 0@8;]DN$~': ybZl ƹ(w__z[[oqg>>8\Y2zn[d a 0@a 0@a ʗeKMuݘun<`7.vv_'n oQ"nXVC٬e0@a 0@a 0v|b QkQEy-nfybZluγo.Nbݍc^0@a 0@a 0;ۍ};9/v|v\q<^:_v.[:y@a 0@a 0@8 :El'ϼy{:ٔŁ~pqZyy)k*`ja 0@a 0@a U_un<8p.v Η軍7e*Wg*rMըyr_@a 0@a 0/ܗ3esY"}e~'.|2LxY}]Ty&Ţ|0e54 0@a 0@a \P ,ʽ7Ub cyŢ/~N.rC݌0| v2yI1SUm3S2-'0@a 0@a 03/[ɢE>b S}L^c|͓;#6.Πc6b/W-~^Ot//ѾH.Y柗{q@a 0@a 0r{#岸e̳/\G~^S޿*fff_/\6W_ՍUesSE0@a 0@a 0p=^u ^WT|_6MWl}5f^cŭ"w3* /U9i 齯טyj׉ت˹܎>vr%& 0@a 0@a _j^u}>W|[67⪮9>[[kLs܏?uqe3sqz[5F\K{ͻSq5Ůyp!ms9Ie_~-/ONyS9Vcv}*:ة@a 0@a 0@={v}QS1>f_sqEE>㑫6c7.V{UE*Jznlos\)LTyyv"@a 0@a 0@؟ w{T[fsU|_UЯϹ~52y̻\5vU:?X(.Т_}Uٗ%FYW/yky)Z4~Y@a 0@a 0@9}yi__XsTLW̢]#~rcgX|_2TFU7b&EU}j(|++n^(uz,fw< 0@a 0@a O ,{\gT̪6-OyJ⪾nU|U̳(^̦/. Ū_X/-m^ʼjRrUgn*{_?_(_ceubb a 0@a 0@a`=nSqƬə_9{gULj)T}"W1}o<.V!_xĀqUS޶hO9{ʷyE1Sl< 0@a 0@a 3}~[37^8r;_TG 񌊭̻kz>G_毈.ufګ^k-Or*CyzY7͋7Ϫr^U a 0@a 0@a`}/ϰ~;{Uz|W]ƢQUvyqg__uΑOno&6~V;<)+N 6+`s|ګ4{܁^E䮂NX9\] F]iWtE;zk_W_~Ç/Wx )ڀd3]Rx_m^:cX3eͣhΕHj*k~袋61͋n=$zZG7N1_4kS}?W㭹H=Ҧmj~u :_q}e>ֹpyՕbӹi^m[e/|{͋n=X xV]8]|Ye=Ҧaj~u :_q}e>ֹpyՕbӹi^m[e/|3Ry綟ϲMk$B[jڪ\֗}֪5<8Ҧ[sЫgj3\6cxW])>+1f]U/kܼy~cNȼlGϭ*XJ1ڍG*76em 8WV{#Smos.Moc3j4j]U;Ey>>wo缗朲kWcaxu~Ǿ[ovcԩSgq&\}T yy Ziij-scz?>daXZV[^k} A2V_<5CE rO֕ÞMbk}j\ՉOyɓkU,xC^s8Xuc3W6y47vD7\ycϾuiCz~ڈ!}AoZbU{su)c{MCԯCW]u/hKƸČ'^ۻ\{}Skd-{ s1qؓXlU^3koJ_zQvִn,~^w_vk߇}wùx8bI,s}}}n}`7%{}` uΨ{A;k:?5:L{g^(^0חkT}<ȥ]ƀqcݹ175S!Fͼ->*7^:WG2,:ʷ<8⭃]NvG,-ԧ~׽# vۆ_+g٫^k7_sΕPjWγ_[u^>vUm!NiOkv}v#Vy/XbzK~ooKXoz`3ЍW獨pMfd,~^qE.V?8t8pdl7Ĩ9rdäm>0zۏ=N\sbe^m=TխM^A'a s LUsz̓ڔ*8{QشǨ5Վ:@wT6}27/R]^O }5p^q08lb[T9ץ9G1r˼ڰ3ȃQU6y]W\skщsz̓Xm1q{^ZӞVrbjyQڔܼHuqHrs>ןxs+N7߯ k5#,pTBf :kC2W߫9c3G'ю}0)|˩&)^\k#ޜS'\aCy^X' L?gkR} ?ݵxϿCqgZ+y/O٦^c\ֵ/ӿ)Wc~~p8}{L?v<Fv唭b?ohZMI\oVxt3)g֙]I*=7lbLocΰq2ElI9Fk1Էocӻ!S¦r1xrkCg}U{O{C{;GkC*V~racxϬk^97s7ƀ.^ F~>u:\3g0g2W'G?7^sCՑsæ.6 's^7z3UT֬e1]ސ 5O}>Nsn476b799 |!5O}SkOׯگZ| ?,˥ ἗|cp˙~Jo 9/fĵuΤ;ʃ'[UVU7S>?1MjUW~Wl/+&kSYm#pź}N|3`q8GNňzHϡ|5'*<攳^M>9iCrxx^M<6up赆:11>: \[|ΧZc27fyU'N.;6R9k>0hGZK Y9F ڏϵlM%81xź}NeG9r /F\x.جmnPcjSn as>W,6u#է9_IvjMzAfq̵!W&j=3L፫ukcƉKέf>31ڑRjC|αs-[S N} xn%FYp‹W1 6k9ԘlBgǜrza]HG}s҆煝cS^k#~бcsa|*ڬe=&i/SxjlƚXqRsk#iovڐ5slx\TS7^yQxt8#bUFz591᳞zbsXWsI޸Z1Vi8Hm@گ8i-6d=0k?^?ײ59z^b5,>)q`CjNf.ty)g^tT\='mHzpx^M<6up赆:11>: \[|ΧZc27fyU'N.;6R9k>0hGZK Y9F ڏϵlM%81xź}NeG9r /F\ŔsyWF16ؖM9C7F9/c*v7esM嘊VTvV=+pbZOj;Su*j}{,f o")Ao{~[n_FK{QDlnmyǍܜ#/f=lDg0gƘgt/zu361Αڐ9vV5~S7A^>g]eӷq17vk:*=8qΫ=1^Y#gjC^e)?c*{&Տ?'Yu댏8B<[~C.%`Б_976a 8c]9nbS6tsiڱU8l}Sq쑜ĉSw^9ތCfցx}9N AkCcטyk |=:ȗ~\Գ.0G~œ=4^Y+\Fe΋9uKi]e^Xz>@7ZHcotت]8l.ĉSwNMm=1؛q-\np;5 )^s[c+J|=:5ĦS׼j3\bsIկo mQ>cSyh_7hu=hoZ[c9hSڝ^΋qΧէ_[/G>=z^֏T+!90uNXp\QsQ:W\&c,8㑜s0 ׼q8jƼd\9k7'!88;GH2u{NY`I,Xl/k>y b +~mhW|rb=|rf-9#pԦ_ިUNvu÷8d^KŘcNp61\Tz]f^|}>pt-cזł19>k! }Ե^ߘ>oG Ҝ֨˙+UGRKi>GkϺ`?9/_8t>^_ڐK:zcpǚ͉ds3N)?8Ç#[|˓[9'H'9yz;xw^ElVNÕέ%[cۓXsV9 |q))?Ѻ˫ʱ|"s^Zu?z.oz/x ~>6f lhR}f;>byXmMa-/ݜwi|Vu2j}{9/9T< ~#ݛkΧnW's 9M-{I*61N>eU7fʶ̷(Q25'G5|۹*MU[ϫ9墘y>rg5Ɯx7/7K7:h̽Ƀ?ͧDZ=`#ͼf~o⑾91 oC=b?8lƊ!}=r)Vi=և4Nsb~l`_`XHcnNtuc#kk.0ă!?ż83shqNk `G:<#'=XW 1Oc׹Qv<sx3ƢCU)rQLOrVS:1\fs~BX'^Ys6J{M9e9s7܄p ;70nLK<تM̸_!I/}?ڽ O\=7uxo[{=?kt3?Wm^j5~|bsfN2g3X|AkFbh/5c(ȹ8rkCkOCm;j 9Y!1.*qJ7:C\xUs㘃U9!G;}3zni̍;~lY}۟ǨjR{#3s39Þ|a`jmṡ#ƥnYϱc ]in_m7zX༖}qX_u6rZ6;w=7ϑ1^s+_N\_@?gu l/Ï:z̉19,>FgΨ)̇5Sc=[a`sX*^R#6tѽģ3fm㪿 6^j 90\EW^acG׆N}s3+幊[up==9>_C^~7>fxmΉǦj|l/?>r193?c3,>]6F6gͯ|8`Xlh/5yWbr\cwN&6kWmLR6Aκ.ʜ96tk,vU6k!9z.zsp}j#8$ho|W͞푹ڜ_yǏM{=?kt3?Wm^j5~|bsfN2g3X|>l\mΚ_qeS36^9kc(ȹ8rkC=E<:?>m6{ۘ`m uZI]0Jc9s_m7zX잫xmBr\8|FqHzN'=#[ɳ1\hUKͳG2zirWmSU|#]Eٱo?q3#lg"=ce6SNyi!fCnRnl6kn`o37Oçx |#o旾l啯n}+\䛪o~zeCxGsǰw$'}?g?϶ˆڛsp/nk[~hE!MZkڇh1GG?|>y~plẫwo{p/^xK7c \okcrް:14l`wC-mc0̅Ͼŧ ?=1AL7{R|S駟\Է_V;W?5تUه8UQ _7y qd[ojY˹ysL79g'/qן+9g15NXsuMʕ8'zkssvn=:H9>~󏆍s]9Ǐnu|þެ9cߺUn:gp:c5Y5Qmx n>l`9g;71ՏuTkc` ݾŧ ެ9cg vw{~d^yӆCmݳ:EykVU^gץbc/xDžR^\wгg{7N9~=uBqzɅ8sLaSګ$[uV¿s;e['9ڪ.1U|+R"z{{v8uщ#ߑ!dTSoPFr༾樱lx31bT 8F^HRWdnH{7{='~P8tzcI,\`_EZWyeM87bX8Ċaΰ:)c*TΈ`Xɋؿ6>X֠^]E*s]S7ƈgn 6pԫ0{doʍ|^s77* ^Ѯ` CL/|:G:U?~ۖ3p3b,Ev~zp1IMٵ)k\)6%>ueoۮsy5-o~/I*~m?j?]qLJۮrU/.R L~屯_x<2|櫏 Oa{w>}G&?"K9xM7-?<؃7\1zU M^uU=+_ylxGO>ax7~nEz1?suC|+?yxǟ _yõ7]9\kozˇcg==:}H~sN81ƀxKrj 61ΰcubUsØx!x9[;6^Ansهy۳xs!>v0`sq^]R}4sb{Çdmu0gO>jQ닷>EeϮ\É> ~9؈s`c,y[Z` oZԕĺ;'F \|?f棆8͓rG+ l^׏57l=ףAƢkZw먮!0X_˜zG\^{9c'j[\#`SljW.K=/vprSq]S ׺k_G;{cp89^{9z{ 0FXmK]g֝80#Hp 8x1i={j?E/эs*ǰw>ϯ]WQjg7"lU"2ץϽ+=UQmˮ=&;ebsަY}JqΑ:MauCvүd$us^~ۭcs8rE^;?/ '?v| ~p_~G\Ǐi@IDAT8\/Ǡ!18n2׽қ.wɯ 'DQ_LJ}s~56֡.C=/Wu=/sU/i~Ǟ7;|S >_y`Hj _}?}O r˅퍄[8%>$7?8Rudo`Gړ>zs%UjǦ^?1^7[1n- kӷ>k bz^[lUX\rBs0g1?ҚU듃gn|ݜՏ+\WShX/oljoYWpߵ7/;>;o^WEw6\|ps Gn ñ|bqeÿm?yፙ޴ӓ=#w5}kx%6БC]J뗞hÌc=gÍᢋ/&`=rϳǠ_?y=\uK^Kzp[/ynu[W ~_7\{W꫆>?l?҇8p [YmM~\9#F78vk2w ;a^O}䬺8$>+C}؋axy\; , 9Ա37Ɯ\En]$>щ'CgNb^Hl s0"ٯ΃?#s`[c.Α39'kxN^bGC{7%s1+ySYm|+'uOQ5s͐s&6א~$~&?cHUѹ6pdT^3\t0x{1F;̳g7O k  Jy׃ C8`#1̉s _~B_tIY0/~G?Q'fj}7|w}xqw=Z^G`ıGˍE; F^4Ɯ+^>ݺH}_k뷇Ϝ 6H{6-t)}]kĻn#dO]Gb?M&sF C 0ձ37Ɯ\Em%ͺē[13x{1F;̳Y[ևk݁?v/|N&j4l6f@ϖ!8_WZoس.!Ab{s:9nNm){sbU^[f1=f_nX6:Ilzlnr l􏶿ipcx{}/O>5◆SoZۓ{'ڗWF=w''ߔ'wÍw=WG? h.9෿}᮫ wm7>tõ=>h'Mo\O1o{pON<5~'\7<X>[AgOЈސhYIW9Ewps zb8_8gjٓ.=|^pÿMGH Ey.]s5zc_s\6#i}#?ibI y+oO3>8urٯmj14vq`^01|V9sLZ3~uxp5S>XJk<:x\Ka?'kʵƺag\ONwpRsN[v4+> S'$oTzʵ>/O}d_]g`7nv7͛8#=^;CoǏ9qSc^)쁰B~fiSc[^qtj>ƞď~nl rsrpƍ~8'χ_nXtO'>׶s{3>4Z>=}?2}=8`"'.|cߘ:{c'lxM7p'Zϵ>l?z=Z;=!7yxr8bn><ڨ㛆;_4{B oqnoJb77p nnzuå03Wb`%X*e,\/pnm|}Nla >jrȑ}!<̩<R'p$Xbc84,@޹5k`{8'3ؚ9qPq'76`󖷼e{79'Ϻ׽n fjyZ4':3֮u*amߺr ޼.S׀ᵨz ~kw=f>9gluþ'"]ՙ4yB7YC3xquEa ۥ2ȵlCslüup|O٫ ~}#`W91UU5vbH73<ᶣ O <ؾg7-Jf7ك>h'Xr|׿í/{Xް7|6h>>^yݱoK$ũ*?˛HP4Ʀ[߳]mwUqt8yc?Ҟn<ݢxCϽjxy9?u؟/Ü^se73=O b#`e:Em/Բ?𭭴Gf߯}ǯ8$_>`_9}UA.8 qipڕO,~yZģ@o*F5RuN.qgogΨdn^^#Za|HC{9g}-pa^_ϫsM A,~{l?kŵbmpN8\O3\bs%N_WgΚ ,s󘓹7$Hu\^o>ox>?a3q-fN㘫#9F}.ƛZ<b8p}YstB2ѯ8tSsiC:Eg<^K0E<:8zNo*F5RuɅN.qȇΰ>stF%5's>j.|2s0C'rX>kssjz^gkX b 6`֊k`pXsu-ag>2p/KϜ5X1'sփk\z#Esb]H6stCs3>ѵ+O,~yM˽ |R>kgX \ެQs)6F95M7 zW]<;ϫوFۦN̪w.N_`lSěC.V|o6ۚcOlz`npp9? _tLJAő+hS OVG9na鍟8tp'7=2|{3{Ǜހ$7-oVb>}{+?=\{%H'O=|W'[?-Q=zB%ǵ_2\WܷұqHz~~o8tǎm8~PMCmz@?~C'K_2zs |Ɉ'orm=Àw!;Syrgn9`NX+xSt8zyȉcN~j3XC>8Ÿz3荃9Rs029/qrf 9qz?><_bnOWOks`^@>$.aj~ S|$'cSc8O >xvmcO\sfOp''kH}~b;78r˻Z^ScgyߋOty {MX"13U5=i{= 9R{29/qNYg=zSƁ}ƚf`=u Ƶ 9=q^oXk=gE/13{E37!)?s29/qrf.s'"_ǰK: ;j|qMskd`#y0 {@ Bs[' 7g7st5b;G㪯 a݊UڃEyA̛W2;ڨ^'|n(lxn4Fc{& }np}{ Hhܺ帨(͟hvi?enccCO O?B}hu'[7*yc ˛~艣>wpdž˯:6=mp=uív?john ~m,7˦hc%n~go>vzsսas|_>\qŜE~Q=첵qS횴 #?>|Q^8; 8YWA8rWYrmĀ6OyO=#I^m#h;9n Y>g͚OjP\5\=1y^3P|bN.27806| K m5F?>ZO>硍< j+'x|Z=o$?,`G*k+ e?o<9s[8V΍U0Y[qݺǨEDLZ;6N`dp{8>xk^3F|S\y^aWǿД~ ??=>\O<[ց$ٮQRӟ?0X~yo냣?3?3mlIu=Z+k ^u!<9D[k[m`c0nMk7V8j>kW^o>o}_گk5Vb|W:tb[d%cp{1]n~3?o2v"̣^{8rj1Sslrl}s Ӧ"_myceFǨқ&7Ln~yg>3\~x{Hq}~QKwڧ#v{n}`rA7>ܰ[gO[THZ]+ԳҋvoO=ƣ ]zpl[=Li/+*ÁT)ηK9 K̩vr ץG_lD9́/>+[.=h=~CXp\klzsΨ~r{52@gx>޹ z'5q {bSh75?zq`s N,vAIn9`=W%|N?׼N=򙛾n|_ k=_kb=bC];ٓ8u%.{=k??õ`k͵;b]jsqooC=4~yx4- // oۇkW_Ѓk|k6]^W __?EJR~//Xo',~7sȏp׏/~ïꯎ$O`S!u׾v[n7ppd}spm+랖s9 6rV,ܗ˼%޽pnkP;9|)UVμy6#Fg;nխg]y305N,v99AInz^npܞι~^l $:56A= 9+K|5?G<;zc#N:zS{={C,>{/d=e@". "טuuqWr;|_n^ڽІbg]SxG ZKuA̷ޜ `zp__d9go؜gȼ l}eBڢ˼?[d}ծTש<{dT93V-տnCpxBr~o^7Ⱦ#ڃ)_.j?=1 pYml5}ގka8d\|79Go þƧ.;vmÑPp{@0MБE}>;TnZϜx8ޗEwִ*=nB7rGln/Q/hFG3qL e&2fpLPSSk"TNS2!Ш\<ۿ}ݽiӵY빯g}}gXs1Nm- .j&jW+D<"?3fţaF/n7_[śhذ`'Fㆆ9~] O;ۅ`C}h| 1HA;ǢoBN!O.K[ƈ|Pt7O2:ƃ,th6?<;xc|+d+f]z%担5J<+_|;ʥ^/M??44nωk#|񐂇&Ʊp²x'k7#9i3GT֮][xxF㟇}=O,Y/lTʸFNm'of|(W\qE+Onsuv|x>mrixȩuԭ뿮s,;0\sae4/r] AAk^woz?zM; K?.|ͦ=GoC?^i{A:Lm舎'_u>&JSmn dgŞ|9-n]ܖ-'mtez'VO;#r;/9 (_H͎Á3M `9 .N(VIh_Lxc`ƌxA (&FMЍM7Ι?0; uQVŒ(VuV{0Ê}x17.#ށ=qx0gNwb.?njx|%e6mr:lc$-,ˇV({}x>ЉA1;J<I,t 7H0! l_A>ɲА52o@{Ե |Ќ^+m:tʁ_o.@8ty9Ī2?Ca?&< l9ߵhn9t!tt 6OɃSYl?tg]m9)k=(:6m'>/]es"cdƆ]GZ]ݜ1F:Or8w=\C VqA1 OKlpzmhbzZĖkmFs Y6R}*M=>-=e~Sdžm<}2е,6qd,rذ@ : [7F_M}`峟loܼۛB`O6v/&vx;<>C/$G>Ǝs?_ tO|oݺA'xy׾>?7R?~چ}D6*-r yx64}t B=D}}뿛S @.\n~S/tsMs"cdC@XGZ]g .XFm7_SԆtۖmYWs[6ݶ8fZkUWӿ Dч׋/Mi]ye?efx(zxq8NC `|Kq<̉7xx y( ku)\:{w7> ďK<t M9C 86Ɗ,1.xMvo0>Gl~{q-?m62ӯ>S|m=;^pF@>S֮8t4b&Ŷ)&rc @N:mڄG/-@G`1 ǂ2c,:0~(|O䴫nBa= `O[rk>SGNb(Ɩu :eٲex}a<7nXx9xt Sh} uPl+O m"G-016a Z]C5usI1&wrmr͜0 #cS#/1rc˺ Q_@4t}tQ GA@1|l)chA: s=tEƇn=L^Ͼ¾@/ឪLnk}{Cc:6)M6v/'v9鴳Mx؂t9lj = 9bp/6VڀyEBu@\_?|#O:{P:Ӧ'ӏzC3,^Xُ>ԕg{Z;dmk[ܦ<66|edܕdz'faA7 ,o܈Xxg^voya%~;I E*n +<5 |UZyCɏolįC;pF|Q̏mF,]pJ0TuĀ*xh1w2oּHc|Mp|a).;ˮf'wBpG<؈/Sb2fdԑ+S)O[0mtQ[a+PMxٞv!UYbB,4a.FNz/hxМ#ʁ1>eC?:|8@?p#/Ay˹Ï}яte̴)Ƕ?6 &7ƣ=3k:u}SWV;| 4vӈE>]c@v]ut׿ҵC;UJn&7ե|n?~wgG?j?4|P ؏Uq&3,l'&m7<C#rqmyڑ\{i8:v3X7,.F] 4^;/ hyMpQ<5m!G!8?Wyu߹¼3wD@QI &0 '>2Xl# oGox@]evFOブ6IL}ɮ qmLԉ đ_; ص =>Mi6~}lذh{#-}D  <0GHw^Cۺk6zPh;/lR.5 (Mx#S/֍m]@Y6@CL\C~+?iC?EV=:.'2}mq&E 36a ]sP>Qx^?t@CAdzѻ+mqy|ȴA-3mvd#Q&k*=mʴ\o{@E׆<22n>`>sXPXYnaQ# 9 } `K4C<[~d̏).KYtWLJSp4z;;RoD,7݀ؐ˳ ߈ О+j[ʪxH?fYkp1^ltwE^\|ML|B8{ DfIv_͊}Eu?P g302Јln`C}>"oh+OlАi1.}+Hg;Ƃ,PM`~؀&`@MNe?4btc]͜ k+:Q#}@Ogg/O=œ[ {RȺ/;6oY lmokxCQQ䁭k b"NIߧPd}rB?Ǘc/r7i) s;wM?s Rȥy$9rcرE^Б]z`NX+;sz]{,a_ysjiFӼ~!Mz'O<5?Ur;u׮sp:>%[%tY:X:۴iYP>{ҝo\ ulX~J|q)צg~/63ݿN^@scp-,=rEy_4'~ix"Ž \J/k(ax(Й-޲2o1lkwE6Aʇhm,) Sm幗cW ~>9qvf:+^[ 3+H -dtv>l";K#FuS|6Ɔ1ХP&},2ؓ]y[>ɮhAd y%40ڂqs-M 8g~0ߘɻMA8hԍGɃMdŧ9+K{Rla_҆,m6t v%6ĈMhĊ1>OGoIgkrlK_]o>Q]G~w0yeƍ:k:z|ԅ*?OʏbŊ x|;_/ʀ?R枪\=s͛ REcklW8uOLgUwPk=?sy`oYLo`ۛ[^..*'_=xh#vmS?q%e@xÎK8[1ViN8nΞSy~Km9=8xaσ6fYX^ذ ohf|%{嬈a)^E<#DȢ3om~s~7'āo u  Y ~g>PїNV=dlƟeqKs|E6ڃ}2M>!>C|0n~m hc{uMЕ]Z#h!so#c.w?ɾ7:`N:`цgnmkƂvC=e}9E#_䔁OmKyxв-h㗛4dP@ Y4r%`Ƨ-qd>m|e~4Еsܤ12qrթ{3G( 0( 8gF:nڼq%46w@IDATQo6u~SOmt^qO?ݸG˚q' |c=k^󚦿YwY 96Ֆc-xʁ[[]s˶ swR~.ndz?2@qEy.š$Dhmbzn;ѕ'rX~販qȲٹq͎:0,sgw*}w`kB9!޼$fCY~{#6:v*/_xiKYyK9˒sm6Z|՛C%Fmg~e6oH̝]y\oW V"ٿڻl޲1|^qoS.+_R`<_ՙqa#m_f,f܄w-;^*=byW/wrkApLOLے6 LJ:|0SyƒkO_C}RԑDP?vAl \G|XCkG8I" l?o ٦<+>[_? ?0֟m}і0Wct\AKs;!G6(Xbꉱ ৮IVwp&`iLgRl9oy{12!ty׍.ZlݺL|_K}Gi~xu6&2b+|_m|{+^ziGw_>67xJ_c]wM9ZB,fxBاtQg /מ8"Otml(__ؗ1ֿu}'6u|sy_ݿ;Cc!\N]y-=@FӾvlHWWfӓ>D\f:=Α6d@&ۡnv:w?YqQ @A΋EhO{ʌ k1XKo0Ccg7twƦy ϕ_nz+-#AN?nֹ >q".vU="9|/1 ^Yn|>˞C/\}fcys|]I)ƁOKo}3 c.`@G;4͹yQ9>SWN"h?s@[7m/! dc-בU:ĉA}qOY0FSk[]hAcnlkWҦtc; c]5"䧮Zvxi ]uq6sm2J#q՟y~#2棞Kȩ"?u]|3>ԑ=YW1ף{ m9{m@z]^~gxyT_5`c+Lu AoDV Wá0ϴWu}:?`zA?z%3Z[v/2O|q[vhw֢E1\y!'F`3|0~zQY˶_\Ny;sl ~M\l3F|0Aq ̞_woyi۳3'twEl`Ξ͈ݻ[ ϕM/>6m;or47o &oėcD:2R~q+[.۷ߩ_v.] o]jʦϗ^x3W7d iQO;Oؗq 퓶A~6/2MB_u`/m6aG/4cQ:um?=!v?Q;>CPGdEk<9M`:d@C@P?v[M8'AӜ7+:֕]mQow;/U]̮n>sy\u>9hG:QWû5k?sMg/a<7([1?o~sC">O~O!=å{tiC+CYic{3M;4mA3uhg{wTp@L\6?Qz[ζXm]upymib8u'vd[ʝ{m666  !h[l_[,822'~0voj۞XTN8r?>]8"eLl`d>m痝/+_=,Z F||UdiЎseKˎCeIo*2oѲC2a/#q(G#K|o]_~Ceݯ-OX|rYơ}2mٱeu'__rӛOR 1Is\!k]|G u Cc|?;o!g] Z`smBsb~39(^psk |3V馛Z?R-\饗 /N8fbۘ6560y62`_<~-i`mc|~m۶ 3>dЁV< ` txQ?аO;zxڳߴPgB'vQ.<@eLl`dݿѧ6еo`bw\͡&Wq+rIq+C#+ƖG:m3|;D:+z_׿sq2WCسkwsh#C۽ s9 @{clVd ϛ Q M~6|iYVXdZ dh]2Y-g[ uԓ>F S"x'f;c%Muq'-e^N_qg(Kww,rl|;'oZ=|-!9[_!uמ^snYe >8`Ӄ`@SrAam7>lC_߲xً˼'Y|~9nY͇>? 7tQ]e>jeWl,/E|;hΞ_ .-KR8)"a4.chE㡭r=>ӖF]sБmxh_ЬK1>7vݦeo_ݬsrvm)MLƣ>yɹ 6ŖR~LbK{`M1ƠЁ8ѡ㑯q8?U&cX/ZرFiK#&uNJ8䋶9fkrڣ$_:{O䇼oHs]/m`^8s]/X\#ypAsnGG*A|3#__yuуu}.Јuk7e p-6yp} 4E3b;́>!oĨhJmp=Gs~|9&,D dC\4C0 ^m,mWG8ӵ'n'^F(g;v=^S.?"PEil3zt/z{6:m}iy`!EΆƈdsduE:+>rcMJCmA‡JXO,j64|sG:|)a#V<\z?byt|Ѧ6g|;?lQȝ]?611!.rO lFmeYǔ6v&mt/b5>2t3}n̗6c,ҨS?t̅ş@[i1V۱ӯzfl2:OO֡^ēc>ceā }ԉE#cMӶRdžkОivG[ԑ|j^~ Wc#s|G %73u$3c:cM9NrR_Z^C)tnsƚem]?\_|͍G>r6s{#U{k8q&8 S"xM":~r(< 6 }16h|1G{`4fbEhnhmzĠAB@]@7 XG> `?clNzmr/@B2u|`1w/]I]s0 u0/70m0ИG#E5k4skwG>5 >u@:>#Oabп Ot:s<|SE Y1u]Y@GPw!ӯ>6(z˱+ th}c:<,!6Qұ>4uK&u}UOYm+Ny՞'tD?6^#G^\AY]xįhb~ؗ]8' G\,YrF 27`Mڵ_bGBߤ>:|@1(Omlk k=66싱IGta>@B/ vԑE]lPW7M"PG;}ҦDУ`A dxc43?nj ڃ@6U  _m/ta(}uv}q!G{|t3{;Ā:&ԡEyG؀FW>maxslda:vsa[ƌmlj>g2O#̕{slv_aFyE" O=8c6]d??k~ ?ҝ}G"K?v!䉼\`VXko:z_ٻ( O.4-J\a^Y:!|r98Shru>by M`=)Ak[Ӯ&.^Le{)#d5ږ.r++VGʾj z4ڽhړ'uY.eY^9#ne::kںȨw=56I7F`iۛ46[7vhnl5q#r6PЃ.>`5>⠮/u67yJ]0svbcC>Z< _]0|>!40| &MLMi:=EO#o>< `Eѱ?a`a;؃Nsb ز>|hñÖi=yp>{: cp?zhla=Q-S'sLc K/WGF;Zzɲ6c{lԟzmw}_IAHA1 ͆-d)݌hg]ِ,F1G^ԉIl|/_bW؄K9|m#&|ni >m_#]CҨ3?=1 F]yP;ԱmlA:u}C^>cR`_@Ou~!vhGutoGdti&6C_ꢇ~.nސzPy\h!K>V]s0o?0)iAמwA:u}|02zo53͜aCyļ\=!Gi3܃A{䳘6d)[n.ya1gyl*y/خ^3_\'/R~g\]byuy5,c=ce3z?re3~vvt`l^~c7)<\t]u(M_[zmiG^qg>rҴ~klԃ~g.nldlh6\1z\$Qhc_yᩪ- m8qw-?Cg?|/vӶNămNcM6ԓoa!1ԑh=5е Ģ-xs4`N'mƧy2Ͻ>[{[Uz3/<יG #3^y >mG\?A˶S`툱 Цh 7^y@k<PGu33us-gsy܂<h3]Oz_y/qPw8?|:k4M-Bi嬋 :36 :|@䋳\/ׯ ]hBϴ^r2ldIջWCR9cvՖiV۹4mdhnKgu??4 `b¹ 4t|\ֵa{#_/aXrgАf/!f̶'+/#K0Fm )+eab0l~7z`leP,}oAC0_tdrM贉:zevl3e#UЩ qL6 vIʃ'}ay |8_tcܶcߝ'ٱq͝4Ш3ԑd{PA M뿛 sIN\+`r1#eAu =4bhBe>hCOs lbhBe C3ܑ7sN G{ceG6CkmOWu;PLyPG9ئ -ۧ_m_?ϼܻ9h̙ܶ 幋.F,HB.,/s= M.ҵۥvԡ+&BӞ:]QlOX۶L?_{aKm_|6g6X>Ffa .ōE /o<+-F]_m:6j/:9D;ذFO;\:k}9}G`Gبv!K=BMB:6?َmld,\> _F;e}1,y"]`3 {d6(؇&}UmҞ{f\w> F@G{sզc}0Fk@ur6=?ͱ%w10w(F߼c~c 4ӭ;h+iQxc[6hS}Y.Jz2::e\|t~rlv5z6~ ~=j.e-~4udi^tu~-S/_kjjjjjjjjjjjjjjjjjj~3=WrC z֕4xB?:|k+cvIe3-p6Zo1A&WG\?0< ~xKO]xjjjjjjjjjjjjjjjjjjj~]3TGIdym t]x2UT$=06>4^2be^m,ׯ?u7W3P3P3P3P3P3P3P3P3P3P3P3P3P3P3P3P3P3P3p3O6_hѢ櫤_)WCS&?Ӥ*v᫦qx<{ , Ym>r{a3h/,c]l Mk}U# LzL6bx6=LDV}:m;{nS~q2wh E8U3P3P3p344/G =X{ʃm8:T@[*Q3P3P3P3P3P3P3pe}Զ=mbdƫ#k}:r_@vӆ팵qަlf?דjg&@/ׯ]O{rmҕ>A[ꩲew^N[2oޭϗ6ni,K.-Kʏ#_++>D5kr9zzrXَrɥ字|c/xdm놧ƝLYeqwc=`y?-?{e˖⋥ޏ~%8|-X[ۃk?y_c_ |[{>ra(OݡZT/;q6ZESwf˝- S|X%?i:浱qJ:4yN+Gfm;ÒG|}kkxl.q4+eW5555555?/m"[7ޮ+m@%צi_K^++1ۭ)LclG84K\ns`um3Z;d#ßhDzmWkXuegr/:L7i|Ӗׯe(Xm(\sy[׾wukŻ/_G5 k6Ͻ=rѱv}h.|3+q]֯З˚Mq1ǜ?~*l\tl;Rl0ckL됼L<up~sSK\^V&2׮Y.ر@\?~\{0kjjjjjjj&S2@~Хt/O41tbe}jŪ/7|=V]nzySn~,1W*W^qr]mx"w}hju:k˪1ٹ̍q*ll-Ӈ_jz Dr>Yu`]]=~17ÿ-{:w~]=r*UfCu䭕c_/|8kpf-4c|V4O/n-A<9uzs}vA;؍ak9,{ĸ:{}սurkSҡ ?2;I4::~[+M|gtӧn&c/kks׍)IRu@{_Ϝi{ɷf^uj1M~/6mmKLom׮k=8 u+"nmrUהk|k0'r5!:~ a|*[f̓q-eU_n{A}` =_5W\VVeeVИ2;}daC.2{,llp eC'N{qto֧_.r?n 8\Wb'ʷore+:su\su}=:"J El{?/Wz\|q1ok91}PkIjػV毿]ڗ":׻-{K*EugB\7.]Smܪᚁc3{mv/ށB[vmu{wNLeN pW\ m\"a>SM9.ʂŸ>/Jeqԏm[('Dyp91IQNrp950)gDymE9sQG9;ʹQ.0oDycxe7EysF(orpyGKs+𻣼'ʥQVEyp(wӡlܶe{~վsMY{o\[vΕG&wlY{^tqݬ\?s=M~sͷunm7^l6xdW޶ cu;Gtl\s['r୾+Ttn^ޕ5unN9I~kuP8շ?:wbRkb4[׏G_ʉ9~uݪ/P-s֤5v흵w1u=z%鬞:2uwwV} շUZyvӁz[0bV݂nj^cLh];GsKC9S"=9b˦owv>;yx7wz`_\娝ќ]ylY3NVYyunѻw|;NSGsDkvmsnt:wReE|19139kǵ9טnx`\Nzs-ts}*֍ۯ]quR:7xoS f@@@@@@ORbbNs)7ݩ\ "a}pP\0\0q(>h?`QLs09G~p1Yo‚8 u(\Q~;?e=9!՝t)?T[1Ys~h\$7P#W:+sMa8Ӆ 8^ p°+6#g'kkH' ȵ>5H:"AR֋^{cI 8D:^ectmdu%[ɖf{ggoﭷz}K'LIQ:JClHauJn]/O)RJ G{ }5aY645*Zʉb-m(nb*YbދvSi )*CFAb+x*LژOWhlq3S)L M^SϨ R\^Ьt(UzŕPMvjkb4*F?T1uM5[cx.6YuuTB=4Ra֯͑1;?z>3zqRÌJ1.tO' %|ef{q|UJs;[cOT>hSz@ЦXbs.@%h,bcVT* -uL 1߼G(\xT +/45:ؘkHؔEv4fo[]C~S2bѬIaH:`yXtkވ_OtgXioiPy˪?m'(I!@F`.ΔNRNV^ޕ`BejΖnr  :a:b+y?cqp!B̍멹B./.‰"Na4Ҫg7\d0@-Iт/dD0Z@6ZI' 89ˆ >rcO<>W0'#|r'+dObn9Ovn ~A|yh!mge2/4~<61{Fq1~Iz[('=Gu u5,bjo釰)Yb*#?$ٛ ^߶SꤧP;BS*E]1ʛ[ cJ^A[Un#}KέW~=-;23p1lkLa௻ G2pviX,*oM1njr| R)+Wt>vHO oFy]-]{a[қp:xoHZb%^ͅT:Ow*f6,Ji^v+۸n0稣UO's}D>n{>w'`~(:D9/m#7rE. Wļ7(J|+[FIqQzS޻ n]#Q>C3ʛM(x^y3z3d'5\$[ߺ$ ox7ym5^Uw:QBm\[ !@!0יr)סr]*שrݪг~Ź`er]0\p.rr]/r/s] s1s1srs27Z=s0\ a a0/7.Np7Pt>MB~KŔ.xC3N'rʭʌ4oϘgLۡ<-_#H z#?un.M` ݿ" T>\ؑI1Be9>U`K. ?5%GVɊt> 9|وll;P#87x##簷@ꕆ;>LySb8/Ff\NZo:=S~Tc0066Kmmg"ehH;?@l]mxc$'E#7bիc_[CPXZ= [Mv{kpl}hEnuBEK/oYP!Lc^i/}K]8V=ߛIFd˗Gܻ9\\V׍PLa|dzld ǔb? $kp٥lB7EXK&Tyw@<+kpfHM !IZ 7 H٘8m;P6]U*M7(0\OEP\{;:&.?dfۣQg&aןZq5^_W*r~AީN؉@M=wY˔S%4m1H?.B}L\7 aهqMh=*,!25)i)ʄE{}ʿ4O3MY$:nݼK'de~,|1&P@@X&Ԥx! "*Lꘆ{gdh6>&&۩VHNLmy3]@w(}pŧ ƹ23a\ךp|5v ?Ֆ<(m*?Fukq4EY!@!@zSDHqViA#x}崨#B#:Yhόnp1Ysf5_>ߪJ↓JC'oVg _mm| NÉ>*rUƓms؅QtX(*P>; / s$ mZF&2cfffp ŵqϮfpDI-U8s-.2E~s1mn1T q~zvw4#&c.gg5Ə~ރ_NSф蔪V"/]{wL*&5b͚voؒ9mU i/u K\b<2뜷⢻#oSZ[A=`X꧍kPz3zvcڙ2[;5zoi]>BWv";>ng8Sm;cf[hB~P~ϲW7c=a"cF LLZwp}ׯm-݄p7b&6@Y!@!@uUqy"_qN&8 ӢX,m'e^rUe'ȳ+ޥ'TRy/.$f/[^F>fոdN߰ںի .-'({Tka<Z;VPm4~$r *o53q$%ͽ3]l܉* vШZl|$-v0 YMض_]m릨 B BB*trZqNrYZ;AME2}.5xYs3M4*decXne7i#/QטL ͶA}/a|V_.{+w4HwEn*^Cfra`I(ZyoH+oAe4k&vpo-gOF=pVo"Gߴ2oZ3qyvz=T6(M($MCacV_yNU"?XKJGJÒ\3'xMozD\\W mȅ;.K>1r7=lYHkMϔ\OE'$KϾY7e$m/;,U:cD|3rt/ŁؾR&|idsԗzqg+^h!\x8V] x?B##׫xo5g0[gBfv B B BgC|gE:2ގ\njF.ܙEK7+NV.ӚS!_Gy3pHPIsZ3z|+:ѾY^&qrc]܆OmZْǫq(l=HH؋r{GjD24]^/:Ǎ2;W ӛn<k|{]7lݶ,֋4_Z"5p}@$C/M6+}pԐض=OWjUâi33q}LWoi6-*x˞cG{n & &B B`"u EZf"v4>Ίt*ߊ֊^'x6dg5p<_xc:VtLkF,ϬgAzgOA( YGIu?&bAg?̲MZLALz֩CF/r>uZ2SP}DndE='R{&͟\lƺqdZBּ9اQ-8.dmC`1I֍;}ǵ'v5_*QIRu~Wm)R =UaOyIQDZ!{^zhH~z=cuؙu"4&NJte|]fӘnCLgV ^sCjZ@WkNx;BO4.cxdVg 6/zbRFÞ4Gdvdԅb%'od s6=w{!vd+TOTOuPBHϩ#&ZK/6 ?B B f/\w*Osg̷'GHI$KXLFÅ\;fX확Y".B!;O[".EZ$Z}ؓCz~5ʏԅ(+}੸Oĝh cPz=}}f98Hs9M1vJ\Oun.5EYߧ./_sBj(vkDlNIv;[հ/lggTWۛb5Ո@{2Q?]S,^8X{1*cpN-0_$xZөڧ6]wc_Yʬ|I h\1}ANMŃjBƝ~答f*LŰ~dG׍s'ql3֝?|]&p%V_M8Ȍ+ FTgR*Z[t]83h=sMBE|]q{z3|ԣCvbXR^Mlf"][mnbl[c߮ 2j(vx'D&Ҿ>' }$*Zԧr#INfRD] ۥ #j!UтV/&>BûK{Y60_x8ဤG%y3鍭\9+7.*{z-J$wJ +x Z5YZ/bSnn4||F"0[-'*r%&<|ML_S3欒pOG.{2?+; Sٵ``d\}CU#N$v>f< B*D)ݴfZN=8>(+ l7ٽ(y &B [r` 6zY-P/3T]AC_.dX[y[r6J e"kǰr K:&'2|‚\=~H+Ƃ[rr|?K Z񳧍k^i}Jead!rVQWM6"8P; E y/*H5ZIJ1wMtGu{˶Dz ַԎDX?Qr 7HArS.Ak2) B B ta) m􂏜'fefy{qvۥ"ˤ՝(Fc0,QZPi8/"ߘgLz`#DZiOӢXsϝL'/ACAi/ȡ饗"ʜیv#89 ;cքQ&ܢ/#}['/XE cͳK8/H{V!wR4q.;b+BwX =\pV qvB%06ԇ_e6ƃހ7 5Xv ,dS-6g#x|u~=غ曱4gA95n5W!L`o#cAXt12m\pCO׫x܌Ȝi &FؑW;l²9`",Y!\w#}՝7/[1` IX41EX"mq>"!2 cIj10cp|v'Κ`ݏ\|M_a5Zc]%%?dw`bSA7S2q#B BoΝ6W ϙG>H(rΘzl> H\XrHTzϝ(DZFEEl!ƼA@U O% B B f!g(vW)8}J!@!@\)Q/rhF# HDe9mQ&B;4vօp!)v륂HG$*}ix>aW|l\=%B B  Ìɻ/m@;6oDlK!@!0:T2:3De&2f"nNЋm=Q'<4$gU&ˡLS^z8<5K!@!0dx/hJۤB B Йr0̌r9sgEgE=&*缸K'JKKp}[ [y}<LT.x(F>̪\thE B B B B BpWi0,6Q\7AnW9 6E@;HNVrhx'q3r?zG!@!@!@!@F0e k"͆ OF7#OD#8u($B B B B B"DjVq3?2UvpJ:isROCΟkpe"_]3v:7m!@!@!@!@!p"D71urDtrԜnFFz(ʽ}víXr}zz0<1[9DÐ5}Ki(zFy+΅Iحj%߲cO$B@7f|K$5_6X/cz;{"vJ:8t[݃Pf (yxɧPe$=|?0RT˜=E7k{RT,0[~ N\O݈:ok8!@C@L9v L+t|ӎevѸ׬ɛI߸9URզ%yv#hE}9-M3>rU!P\*0vSS}kR1E B` +y+rj,:oZ`\dF[GU,?FF  zFcF ؘ/#h|Z6ZqE gqR'BuxYԟ˒6n0)bMZ)u.̻] k*|Sq!@!00ӿyvVy ']n{t9l@6'q7҉rhqhv -=v:P܀Ñèi cӳx9!".}1}ڼyx췰nh'"&R?*jgk[*3'")2݉b˳/Etchu#պH[gLJQӏ%ɤ+ֈzA@Kq.ivWf6rW-'݋t2om!])^ok8C)]i2Q}CgUIe3s=}[*q$^!@@:UDn߄kĸ/~zSDi?4Lb<-A}h2 rbS8E=M5Bye&ãXd7/M=I^4e0Sf xGemfs{MⷛM#B f2)ڵkQX;JJPƼqR*fO6ٙ}<.f.:)c#-U:9-=tQ][$ Ǻp%̗9hy"򾶾}ܼ%j|VG:#|}%^k~*7j/wFDcʑȵϯ6&kk=eXXsw@-6B#=ޥI K |g_xs i*-@nuUf:Q({{^v7 7Z+ Bbd i6a45sTHQ<bPEȍ"(K˞?o!{s3Xkڼy,Gg>;p7;$b~ kcS  en7292y/0"2sf~ [߿K ^f=-~+oVƽ2+j9JڀFN~Z ԅv--/-)+ڕ6xESbǢ2ԅ^*Ugu@[TiiTE#JCOoKzZNa\RrÝ՝396ܩ0K/SRO޶=yPiib܋V+Wٵu?'5"ڵaFǂJg&[<6Ӊ]k=čTTukDL.4-@nupW9= F}Փ>8!@!ݭ7QVNy#իؘ?TǕ Ȟs:Ns>А288эr(y7:TK:U[:Vk:W{:X:Y:Z:[\u\u\u\u\,\Gu\gu\u\u\u\|.\-\Gu7+3Y=י|>5xY'd=:}aigϻ!%L 5vA#$@(2t0\!,>hb`NOHb'_<̓e]S?MeZѫoG0dFRÅl䐯+KRj8 ;ZLc7W@Ȋ"][OqyRU2QD$(;J{KR,)9jI (fņ>+fp(W~("-cliԔ[f 3ZZ VNnVj`}p1n"W^(R\\|)kCP^:ai%nWdV4իȸ2xf]W0 J3TW1\9mTvV`c#ƪhҚP49/։ SmحjhV:[b]WZ#<>fG:׊da|Å~Kח|=J>SMX \[# sVQok|_p(%|__|=(nbmuʣ8lcbKnOs&wHs&ٽC#n**v[i9;KZd{hP B`v"0 l/:Sn,r/ˆ #2\px2Åx!ptj;WIz#0OT<}>} #FG*;|Jd5j|z#[CR01nٓMw %<}xb8IF٫<~N09^J7+v}\iֽ)`m+ly?/u*bO^Tjkalc!5a.z*2(LN͚i8fbؙoB/avoDX5EKORﲻo^E:*YKfo7;vd3Z*5WH:wn\iЌ>ݮ]宅=Å~30(* H[-U|:!fN֋uQ`5*NPU5mVMkzk\3n/|;okDWڠÒlVum >%,$3eOQZd^纫5B힖&$V4 ZB۸̽)MXzQmgLJA!0 \uF e~ \΍ fo]H+b9I"$?eB6m<e±-+Q5A.7-# 4ٲGRWY7cP@IDATȇys6Md9?tm.pȇHy"۳Ο?eA<3zwܖEEBo~Ɏ^ܣW?01?KWƞMj:aQ`Gz<'nzjõ( 8:42" cm ]/1gc1g?S 2Hx ڍJϵL;CʏB{>*CC];$M26Њݪh-k"O'm٧ky{}R'\Y3CjR]aw[,ɮ@4Gع^]fi(,-W׏GTqkYv]0B>e"nώh_IaV'aHĉ!mBcccbCQ3̀;k a[:6XxɪǾdy/Ί9"9$QTK_aқKl̍]OF[&.m mV,>}GcPڗԨ2IA畟j\ ()L{: J.RXIȘE ś&$OE ԡP3ΩL'ZF>}똥~u/ *s;ռo<9RdhrW2M<2oS mL>P^EU*Ƶef!ZG C?"fp~-3j|ڷJV}SSF[ ڍ}}pP~{P)jy}k(TVvWa;Ú1LRK!I΢lvx#U/y*c ذpx 'g\wFDLٞqy-Vɺ7ޤ<wÜ24utaB ЯʡQDeFJ ig͆ ?.>4\O!UnF񓲭ؾ}{bs;Y 3k XF MuK攆Qb/>VykGY_eϋ mK:Ej*yF3$?84빉IO-d _0q-L|X&Y!@7_ m jY9}1D)M[{薕;}?ARl3N J(K9K76$j5"Rٛfs Q ޤo&_F-+yzKL0Y.~ˑ?>uk ^V 6Tѓ+FA H4qñ_X]*}*"N'y7uFhrp۲OyAuJ,˚}mFpSMZNuEZ^~s^ѽ;a2|}3ihxQ B&49=NӬUFk|bC}a6h7cS);~_/>.Ж,AZFH|m(|k"dsEbHokb[oQ\ }SM.Oj"ؕۇM,KS9&Zt ,Uj5ȋ盩<63ݏY/ŁQk7§=vmS_G uGx4,ɵR /:0ܢD(Zֹ l㰷@nKq급\!PSAf/d~ڥ~ rJqaRR>_#l[iY\Ϗ"tv]81*o^ هC<_#=Mi= g=17q9#U Kj‰Kزb&$ E B iF@rpZ;t6X.kiɒK)˼l{nם=s$I.D#} O&郕,ٵT> V ŕ/,_;H0yM7n9m2CC'}H9z<* 1DhECc_">\X~=֬Ȟ䶈=!n8swlf3%נт5o B/>+c P.0}x;LsKsDb T-6;CV‘s:jn֮b犴,>a}4FHE& 9ywݭrl;P S;4>Nu _L<Zq&L#VR>Bt Aә%V@*0,Tc'}Ys,|b +fm,ەt f'q'Iԗ'g,==.\=*:Dh,[uH,:Y+B/wBnnإ72 ~-s/B;61sE˒;U&NQ0gKocNP7ӎD| MH3FNt>u۫Y 0y|Kބ%E*l}pK׳/%lr-9(S׆zlx63'ţYyd䞉yO-/ '~3V|6Q[dj0ҹ\JMYG1ɗx?M!bʢݧ~rۗf)-qC:U{(10IJަ=Rv}r 7?OH6 !++ ps(ɚrB B@ r(ʌSNO%dp E51y-#قĕi'j״Ilغ{{Vͦ)$& 4a1V4kDcc#|TIzgyM76NR30o:@mMD =1S U. Eyq9 ` 67a8(c5J: |N6ar.DF 1Oi?jw⫬3pyVUD]b߼y^pc펾{aY wñՃ! %ERX(1|=-*Qt!@F[ez#/9-<{A@Qx}10rȍ"(K˞=c ,.tudJPNWD&P9W0cSazTY<_ѬeYau`rN-3(NP~%ޢQz{Zo%{D~˱QN ?s17)c}xu6(Wm񔥲9*ҵj6v~&oe~4h^e6lu0!132q_k$2I_i1g8!V( y^9"xEn"U\`vNi]SLyX[]fd3e?Msz) #tT>f]@~2>>LLL{Eqz^nGos)םr*ץr*׭r+׵r+׽r,r,r-r-r:]:^:_:` :a:b+:c;:dK:e[:fk:g{c>yioy:m^\-g 8ו,]8\>W7\Gfei:clVz9pf/pՋ=96C@ s 7rЭeuYϗgdK1ߊ,{=zO<=>;KJ{]^`&SGM%DxZ&t\iAq썙>VaKU/XV<>7Fj#ziv߃X96usWP]ו[+ʷ{ .-fٰļ݂jG8KkpqElK|ڌe~4ɛOԆW/^e6T1\G܎59+?(rD&Mn 1j8}Wכh5Bŭ삅\{a-s<nXnLTuzX[63ɹNwG5߾ 2リ+ޏ{O8;~u}"_#ҡݦ[#{M*0޹ۨ(?~;$,D':Jyn˞^q˸u( ȘޗPcX|e"+(nbU(N!038S8CSʘMsëclvec\0QX&N^y"-B9_PyrFN[W3k2(**7֗pcDJS@3sXh rZ{kob|_} nƪ\h}55W{L֛I;U n.[e?'Fs-s*Ӟc>K`qM&Fر\W;|,XK8ꋱo(~gcaGBK 6f18ݼ|rԴb|j?,{zKnKsivP~_[gǸL#89 ;Cj(Ycs=t#C-n>^|mcUޑ5"{{ Q}Cl~5͘Uyɴ9c&pşmVcbSS.RB ID7ܹs#+jcy<|D{3#gރc/WLE=BWȫ0XhBc%8/rhiUZfiLE34qa#ڲ"j8 :c,_Per(O29B B B`#w  0~!@!@\K1\p; ~mpxa丙=uM7gdn$g$Eu9dp쫐BB B B Zhno_%F!@@J nx뭷gᆉ>[`ҥ\Nk2\\cK=#B B f)c8:>K} GCa/Nl[aEB B Vӂ-:Nя~f52\\L}$B B fBmTJ $B B-oZ-:^'333͋|BiD?bB B B Ć |޲X6|*S9!@!@ D@m1<<SQXD? / B BCg:*u B  n|pxݜթ,B#HV B B B B B`#pUҋ ׌G 3~H@B B B B B f7|ru&՛p1=S!@!@!@!@!@!`.L@,B B B B B Bp1=S!@!@!@!@!@!`.L@,B B B B B Bp1=S!@!@!@!@!@!`@Ie.|X3rOakƫ]=zCpaeθVz9Sc6"4#:zzv܈/^EbYN5LDB B B Bi%mt-L *bqT-Om]dmB3fnXC}lj(Y9y5v[C0M^?b':Pæm:q~Oi9s? M g_}Z wE<_1L\gP]َ:vm=6:`~>܊y1U'B B B B XhS I\hJH'xf]O'p ɯ\7s\˜6^fȏ:YTd7/&I;t[5X4%[vjw,.a!S߆PQT.aC+ԒGaC2 7/Oqذ;j>^!@!@!@!0b1N-@[}ҋqKc]pިWތ'/Vl3#{ihĉx3LM`2Οyn4f14@GVbA{?kd:J:ը3ZNoC ry*pۼԶKB B B B}\{śEΡu8 =.쌵D݁tD{ <;>Ҟ~rFxUGdFB!0p[zTŰ{z`%b= ?Z856S{P[W=tFF&@R(B!@!@!@! xNgcol >s2 Aą͑h\^VT`2Ѧ{OJd$삌H9(P1u54A# Ij h߈F[䚠Z/F#OC u-%džB!g KDE,j&#3+=gfea.ڜ}߾3s ٳXiEյ;E^oʙW{ZVZ Y866.]nᶮ:Zΐ8&k(L 0&`L 0&P+.cc>.sqmU/E*._vT,%,vjl ʇ [P[ a=58Q/[?{`eRYڼyQn *$!dxIWbS[p mDnV[pEx^yJ2or~Cs! gًp{#f8_^wPU$W>s#ta@/qȏ")ɕ$5ǩoƀ>2:.Jo'%&ҘS?Cp7}yR"]osj=H:na،46W9Va,s6%qƥ-jw\hl [`L 0&`L 0MXj4)͡0eot^]~M)ZTu_OS[K ]X`%#yTaAr_õiW}|EfTcB/+~|:q;#u3`#ÏpY粍tޤ\gnmO!78#xHGvfWx?e::%C΁Jj׵G<U:{tfa6uw^5, .硻/ |"{|zڬ8^ -=GWپZ˂|(]Nƞ? %Ĩ)o@)Sx2?<$ p،3xT#:mĈgLgAcE!/`GpL 0&`L 0&A@s{K'S0,**1ZP2BN"0բ ֕w j_a)ȍT}{˝qD[$Z"#LЗ*v\DZ0 {P(LSIQ9\m\r}Ge5[#-tCih2RB=z|!g(vQ)E JPQQ̄Iq쉠 jpRzT("h,ĩ}3(TE4Fm6`L 0&`L 0%E@ /lsf#&TlؑN)cL]H%e8}{WLwػ+Mu,ly\a|&gPZOGe%,عی/amߨD4&[jydۻjaI 5Q@i6Ǜ!ۭ. ?QET~aQ!'e VxKcX;:<nAstݚ P"2650Y#o#z+ )~N_SԄm:afmY@kI:$]'?}3j)L5[P3SpOV\x< BRC3A+vyU=K/t)':Zؙp_̎^ᑴpI?1BLJyW@On97(EP\D:.7ea`L 0&`L ,)Œ3WϴĬA3h)(kGd\ ΞƤc]ϡN2ZnCi!ܚnYc6$fǫ5Znj=K{:J Cp'%վCNM?%U|ˇ%+W֐huXOb3p88ށ&4t=G51Av!5>4GPĸ"(@E45HH_Cm뤶?F4 {*-9NANݧijh.TZ4pJ !B%ҬAi!3}_9 EuOనpJ+@,x/)!OBhA}Og-ɶQ+"짞Q(r.y1 *-}E/HvAIت27E`L 0&`L ,QIJKDy m}155CRDoRJbzrÉ`wN2٧3惞kKDǢ*~J쫽iw8;r\?nBf!號@—vgJm]^S,Tu .htJKJap_0&7CMbqemzyRZlCTnSn=@Rx|FrIؔa-K3&ʋr&+&S_rʳΒTH-6cie8{plUW 0&`L 0&X,bq'da;J%]K س+Fk+OQ=@KĸPM-ϔ)!R>Qv7ZCSTl~J9^/nus^7uUMϞ~ iQU`6['ˡ3 ަ ϰǦ O*Zkдk *x+5 )Yca&J/!\NW~1B/ Z$ت6j}1&`L 0&`/k' y:/0(do$uil=M%0VS `L 0&`L 0&K!J'bUN[uQhE`O0/ot& Z Y=C탊\WȊX7hz\o~j ӕ #P'EkP~b.݄k.㹂 ˳RjlzZ&g}!2(\ήǵwpFO;~=A|ZЩj0@lsav_yCP?mѻ,w? 6=s4cB\ 8tYw_8A>I}\D])ЂjtYtB<*RWf2g؅5JvgL 0&`L 0&h;,}+-7{nkBjZ\-|yNiZBBbqxO "/+ҍ9M[+9AsH،BB5i0R̒u5Bxx́f"rGw0~rb&(,$.JՙxΤB@n;*E8=;~"W}NZB9avܺ9 ]~\4q+1A#fBꐤlpT3~˴غ y`Z jĘ`L 0&`L 0 "ddCq)5NknaR_9\6`3>YȲԶ*L*|!y7܉`)|I!蠝BWH~֩^,bIOD+GŶkTآlbe|C޶읿xW|UR抭hrc]Gle?eڴTDcymF=?M `L 0&`L 0""nSgѽ,T֗pߏO~C=Q}$ ݄]g耹bCwg3VaO 1s4sxž=ۋ|d&0p{с^DWW':;t)OssI[L0J㐔 zdC֫!ˈa|gU d9:ʑ_QLLLp_7-Tm QQ?%xaEg{((,ܯ뵿%Ýx|ٷ_͑u[-ⴷ?cצ$vbpd#Ãđ%&f*E(ok3+RWeϺlG/ߚn dc>vE[شc__<Dz2m UͼP,CGTc 0&`L 0&:Iq} [+J3VCj> mغʓ(s efmIyqsO \Bik^>C.sÒ<-mF@cIg`$`gC.CKpgḨq%\(JǫN"w.73^UtaNA9h2vrO-2 öƠzzRb^܇Pw 1gϟĦ]nΤ0ZGFP}y 8zN{d&?, r۪znWݚc'8뇤U抇a˂~„,U=kFv/ݕXa@#.h?p^?r%cr+Y#=M/dL 0&`L 0&;qkHQvc4bv'5W`17!O@3i(&Ф`iI~LNZL/PtM97czvf`$)~N[YW)#4?5!*A]o|wyġ7]T @"FwK%C֛Wp҃Jw/zkp>6.ZZ)L|yG["o,n3 衴ȫ.lO֩oߏCh Qa'xeӡu(q=T["M+o 8ȹT48t:z>ψg;KrH=eq;HilVXwjFK݁[]#&^oh{= 0&`L 0&XGęG$n\+xk9ZPs-Q1&^g&Ep_+ݕn~^}QXX(|qt}3._Ikju*t&HJ޻1&}PrNKLQc_)v3]18 +Xmf.X'1~~#4˗իζ)*%|4Y*XQ짱L['Q8{?'7>4[`L 0&`w=(E @a(Z ?y=s-?Od@F|}g:{Rvx_yvų{w-VY/v'k>Èi}fŅK1!*pZ4?k_pʸJ{p tQ:Q\D)+ P͹ƞW'/xiptL 0&`L 0&XXqx _0B+É}]+v,oZ* AP`L M i]ojّ1LNYa#CɲG&`L 0&`L 0&p`R\L&T$@N^G[֯ê$$L#mE_|fL 0&`L 0&`L  9%mҦ7.؟Z*7yօ-L 0&`L 0&`L DC ޙ<t iQ Lx@IDAT`iH޸_/_]Ƈ2ܷ6ziV 0&`L 0&`L` `%U]vg-,sf@x4H4PL 0&`L 0&`L ( RQJlgL 0&`L 0&`L 0&bJ1ω3&`L 0&`L 0&`JP`;`L 0&`L 0&`L 0&S)~N 0&`L 0&`L 0&P`Ņۙ`L 0&`L 0&`L 0`ELsL 0&`L 0&`L 0&+.4`L 0&`L 0&`L Ĕ+.bgL 0&`L 0&`L 0&4 96T\MBل 5ة{xýi8@jd%kS%{\sWޓ\^Lb{g 0{s;W]0`L 0&`KD5.LFqid~ -B,] X߁ TLC Oenp~W\/5kJ,cӉ\8m'Cdn{iܹ/R 8~>8F&`L 0&E_|̑+#).:d1EJ@_y/|t7HE,b~w[,8LYR4!0Ph4$v>34)sH ~HܦP&,e-邃`L 0&`L E(دf٨;G#vc62RӐ\g(ЃIR}۝n%e?WY-rl[%`L 0&`L 0&<qPجCINBv gp¡ILFAU*Vv:lDQC I3r?Zާ݀SRFS:5qMxA1H4S%(.S[ ̽h'ܨqQ[0) oV4Hq=ڇ\hifQJazQ_StPؐ#N%{gvz1=:49&`L 0&ϸ61fSDl)BT"N w`I>pΰq0„( C(7'p &S 3g;"?NKyN'!1.ͽD~)q`qTHK9QNR&QRj ϛ(1 =UrxgC6-6 w5hh{}($Z䛎bp =sa*gyJLs-ƪCCbQ BqӪJM-IZmɧ)ErpUԿmGLUYIq$6Ma^UsOJhs;|z$%Æmck\'6b'IO]~%% ʪQ-ΈYDsϒ!G:=_1&ҾUlO-#xY#wDmzRw$js 5 0&`L 0&I ZELVt$lF9,F`<޳/l=4 K+{oޅJ M7 Gep͵ֽaGBM6ЏM82\ёK 3Qa1 {I̤eR"v>l_8^4T15ڇ+foO2$ڼ- }M?>)\P0~6w{,4awaڻul?Oa{˱B\%qv@Ȃ*Wp2Og(oîm(;aAl坈Ou:F?|cݵXg ^G[6PwI4篂{okT]_zvBF"cĄ+S4W4 {k(Km=@#rE#O`gn{GR;6l?*uvs؏]\MՊkm^`L 0&`ϸXtU u=zc%k+@?'OPZ30'!/G߈{;3#Qk%ȥSRi2;ʷk;^bQ#~A3 4#'n{-YX!h& / Mmj ILZvkϢ{PZѦkFV*ܓMyi#!)|mЧ(zT֣Rj4G_˴Ciai! N@Q]̓;{'U]S/P/000Y}Ri7 tNPٍyN ZquTH{$;І7.ȳ17亗LAԸq]Xp)Ci=8zEkۣDZQfhO=y<,S[UncPZ*a>Mm} z'P_SI:PE:8 Xų{\:+uܔSiy9ߐ۵3m{s+jRZŚKi[|~׋[1&`L 0&`77=8ԀC-2WpA)'셱T֜| -EG=^S{(Ahj1 fp3r-mKU(>Z,$˫7b~rDCueΊz_MY%+4R(=1%=%'pu<@éhQe#.Ӭ8 siSr0b[ ['PO# "7gzڮ_{S8Ngm46̕`4BK>p+pXwlyu/`s&.X"L%@JFR͸} ,}898JJZ3Ubf aԺTNm8㩧uzS Wy"N5|jQs7<׀> W=G68 hW5B(cr[1K_XNH\\v80$93zC \)`L 0&`L ,V\,%K萇CxFCrnPCTK<q\x=ʪI+@S 8[ҿQ^+׸%Ɩ!:SZ>#!k'ڍRX`᜔[T'Av!5 TO}Il:I|l<[u.Qe?II*ڇ{egWYע8ǵ p0pLHBm ¸8O!$KpW{C !݇euZvǿ*1gh) ). mJo{aKu\ob^ }ib=nщ$ 2#b9kz=\EH_|. ~s垾*eQj\sn$5L#9,/Iad FWePjNaFW_ ٤hSF| >7d $lDO1ʁ!y4 p[<;hF#\TatZ/HlCyhxD' 0&`L 0&V\,R=_eX)p(l'ʋ/}[{BnC2侁[@Tr"d$^0̉+sCmfpRm6*Bggg`sg|RsSDm,ljèS[ڽ־OƓuM$sE-J]Y5)$ V+i03&|(nXc .?O߁)ml쫗435]=Ĵ}SBgBfZ'%6P#Dޝ@N;^'Fn[NmA?d>w{@(B少I{k%j-))d^ICtO'^D$!iYH)QuoE\~Ga"D6ƨWm͟g#É95Bϻ\`L 0&`L ,>X|u+/ i{h,D\\$\ ][ ŀ;&,/5}O`Uu6wþ?{ i1V`pidf1gK( UȲ}3j;۴ Q hמPnp-{՞8^goaHh|vbR, ٨j鈴b6J–*|+SzDaḊ!{o.$Z/\L}KNᚁth7!! 9Cbߌ7ޛ 0>UO(+Cɹh3yXV]mWt~l}_,+_ Z_3_/~vgL 0&`L 0GׯŗKu'ZCJEEz,4I!+;F'ޘr ZZX2jFO;~5-\Z:F%;za+dycaq)n~KoBhש98~~fT4[\نWΙ1ذ3<4:7OwVwv f(U>'q5!dPu)e,axqQ4",*Ï:"ܚT(P'n/b&$g ~2{1166qa: vbngOu¼#-{`L 0&`L 0(ॢJBQ#ҏ/F C(cWަE?L1%BC=:sϙPin Lh6P'X+5b,1~ᜰ;ʨ>S3^V̗"t]Ge4Ioj;E->LQm,SoAN:o(o%A#!pC+-Ն?Kr6͝ WŦAڇ˧Z!LuD4xEj_YRw|\. V%`'&`L 0&V\D필_jT$sV[kNt{xR xВhߴGrWA'x),$KCa!e0+KV|8MiѬFIne_ r|:QҥsG 1@-{,4fGRR&8+`L 0&`L DN3beIx# ʷ0E-6؅Q.tvv:MWߨٍͧ>cGJi H-POT ؓ,qϰ"^j )x|UlWfB\8ZF0N}mb| }]((a9mi娗x? 3s=ILN`K\B\>C5_GoP`5)&ƆyԄBiVpWǃKRd?$IqdJq_” #s,Y$&i-&Z+)Uu>S&&0MKA J}S~tȔGKm;a^[R`j"ER{v }ؖ8݇qLNMajj S<; W\,1F{yq:qpZiHLzc&BG(?88Z +du|6&`L 0&yEf1'sHi}šv/S⺱€Fog|4gn -҄7YFnj=s ٷLOQ;J+w(a!&PgMDFL_ *ߨz:QC*Hlφ0.j{д[Z4d+[ݾQWM&@}iHoEm8!g6NJâ ]SBDzn؉=,toZ6ӕ4l]"OML1$ _x&giڠZ;h @5]$fcZ}%y;b$e{j,~GMȽ4ψg~Y^Iq⌉$ r|b7&`L 0&B #>>޹ 6 nbhY<{ׂ[0̭[N??A{ٟ]}OK.څ{}]bx ߵNZyOgxxەׂP#9Jȃ{\HL4vt N#$+f&8-&X"l>4^ي?Յ6EʻeH Aǘ;L 0&`L 0;+.Ok_3-,ocB$0_a'U@Ciz/|%=U`}ccҨ'%`L 0&`L DB%یKD>4->GY9mO'=˹z~1G&fp2}Jd>{bn^dcHL 0&`L 0&p`[at)(~VmU|8۪P\&p[HA1us`L 0&`͹áa`L 0&`L 0&`L 0!ʑ2&`L 0&`L 0&``E88 `L 0&`L 0&`L 0& Xq X9R&`L 0&`L 0&`L aL 0&`L 0&`L 0&+.+G`L 0&`L 0&`L CP0L 0&`L 0&`L 0&,HMnNE$ A456#}S.3oo\:&d0:.S?l9s҈N#c\&oS]X Vg) um:rd"qn-2/\Dq7@CwI4 a;'eԧwt$7r(ƪ/t*>ލuwlz~*Ehblξs}]|hbzzHJǖ˻oB/f:9 LS=)%ijPs]ǾMDcHT;h鸎vistD4C9V ޜ̍>l_]ՙ9@_{mWբ/uh 3:w[Kdg󟿍w/}+wқ'oCe< T%~p'~}r#,[.@!?;2H FZ/wFch);(]x~_tUbL 0" nŇb$Ѣy(~gtSXIUٵcr|Y q5҂̣m>\Jy7wp9ƽh:YT&] wz#CIq.l f{ gh7G O0H~ s>fI'Fγ֛ /ƾ\#7$,[pX:,).n yG( A uTa9͠m7Oi{/CB6J3HJJ2u Y ['1~>E3Yԉw)Ѻny\VXs}ժ#bL 0 *¼#(2|2xtfSn&+<)EZgoJ350?݇|/#zsT'htb6Ĩ _#j^f,?-lm.i===dND|S1CmX-%sgqAzxZWd xa˼EPGugZg~?S9)g8 ݂ ;Hគ{Bs (!~ˆg.0sd._ {7 y3m:d^8/;2}fL 00 ,7a憃R7scWo"%=cQݓ.-?Li Cҡ966fGZ,l߉qfve*gQj(MeLԌ3-&',$[ef{=mK f*Ko:[RIfo:wG%x?qM0I=, iSY*yzܞsfVrl\T񮚃{ UڿPZGsC`L 0F`%l@SSDDt 4 ;ٴݮA"mZ3j kz&1>mj4H)Cr}xWH/|E3-˺h^}DI;dsoon^۬SpwqhhD}җ!S 3o$; t^ k Hq!J>(TV)]1"&ϴ,,V$0kC|RBaτ1 tц!,×i {B~ ޒ)#fCl=b<\p opB]&uiYplu;łaL 0q!mvdKRR6IZ䛎bpIQ.\mbU%&C Z޿"ax"+MGv2>QA('lSEw JaMI\ ]>CȁUho1tAIQ۲[䣨AS crO܄{>j"ͽrf`W39q5F%%%AC~Q tJ Wb`7xH▟_ UdS.u,q*)I_1aO06c0ji\=5slu;ѻ.={9cUhoiuCCw93{YzRQ=`dpgZu&?jgzVQ(/g۟s!~*CZb: y\SD|N!9Yg31(ٻCN-#М>pN Jow}[U}c{'{"Ta$@W?~|8Fu?Lg#]>|O>T{k ƣm}0S] Μ\}C3(Tn]|`b$r8z?V/Dŀ#ED266,o +J96ދ3 6چ]UmoG^JLbq~N'̵_Y"h{ 2:O9* _zv窿uGK6ZꓮbZT7Ǻba8VMm0p8r=Nã[K7)j P?:,Wu9~kLY\){R ;y 苕ɯzVvZGxrw׻@sf>B47 }0f8n ktB gqZ*8ebn?;agrNތ_eSGڠ{9n/4R-VL%qO;ޙ=|&N/LuSvǿIvdL 0F (b4'R6tVaB.ii?e3 !a:Mҏ=\h}(C׺kTXNA&.jNȱ _{ˮ]n_#}3w1r}Gh"e粒iIB/,}JQͨ(n:By~ ^G: Opt#~P:3 vRI6g30߳"WU6 EOYKUvw=z|!gltUMUZkІQ҈~-)q}4qsC{nA]r ~u~CiaמVL }tz(;N yh+QCXqc% 8uCGXomt!w0ۺS*m |P7\ #=/aO{2Wc ޷/ļ|GnK Ա+}7EVé3!`4QgSOJUL`s9rt3lwfޭbYų{`^|{^sr 5`F;CY- pn]y}YH :Jvg2`L Ĝ6 P!|a*_t4¯9TE#HyqIҀOn# ?EIv: ϻF&m>Ct2wkL2kKFr2%&2L>2z2[OsdyCf|Cd&%2ydvycdL!9'ȐEdL+d'ml!L좹#?u5발oW58Zz,MU@ӎvXp4 -;N*ڋahӵ=n 8hG^"6hw.p^hnj@+!E*O^+^8Eb[&NVKcG*)"߮*78Ķ3͓XcqgvzeCGqo] UڛX#Y.WcLxϊ=2ls{ūe;7"s1ܜcyhC{Q1qFY>5m[S^dE\v׻qA2| ~fk;;|HLj91iGvY3B&3/s8H1(pSunsqV8}㥝ޅaיUv'">`s|}A{9~:~9fff?㭷ޒot(p_7;;O6qMԔƍN٨ 1Y2T 2TA*T٪ cdU 2XA+d٬ dV 2/dlW ^A+~ d‚lX bAf,Ȏ KdʂlY1 fA,Ȟ3ddҢ|:zlA-ʷW]y?$ 2l\0n#Eyz"#fE#5^ѵ(e=PKX DErĤTl!WHmxbZywbvϊ9(6Ɯǫ~L~k?1qCMD 1aƩ`HA΍{p$M|y>'o0<˜uT|gQjWyMc+Lr6[ztK5n0q{k;*?c8c]gMtZUT6>~v`HzH绸;wV)R~Sz`N0CGpo6ƈ %tcP,I[xDF4 wL@NZ 7` y b9IhVgx_$uw51R] 0&V\,ZR369½C}Buhze')Gvs2 HAX.SӋ}( +|ѩt ݐ/-O E8޴[RHXZetA;^+kC䮅 x}s#a %2D2Evu*5/ Jmnb˷)ǖonL7WNɥ2Tnl9%V{{ADR"n-  RA hZ,%ݝ33ݝv3g|̙doPkb"*} ^U /PolrRH:xoert_G}SvGZCsJwScgt?}NWHzꩲԂ,\a={Ca߰B;[!#9O+Q) <o8d"ZfNwGҘ, fi|[0?H=6+R @IDATLZsoɘ;i;d̢$>G묧<+ޮ4/ʹb<86f4'Apibb< [G酧ʦS>|&g91e1fI&S.7'-B$.E>YN\=tbfq]⍩ǪMP_m|c!ڕrmL {B:XHs̡LViۥz1*4>IcYyG9s2Q&8˻Ҷm"[}gƻ 3}Μ"ZoZ"~naѦê+sMh*`G'u675@G_T!V ]I=g_ݧ-v~)D[oN6-2EN+ӬwٺeқO"OJ+ͻNYp\Iv&1t6wiszB|d9ڝkՓmz'i)\ӄ9%tWr02~PF-VDSNxwlo'"W ˫If)Qlə&#|$._3+?ڠW|͑): =y6Juc9eӵO GK_ѷûBDt%uNo+|YYr{LuΟ [?-*ө51MP)~?o#\ޣ bћ筥CCT#yd[l~: %Ix"g}WڰQ)1ݓ…s- ? 6{9츏H12eshN޴x8.sct3xvF;]n掾Iyzvӽz-P*ErxS`?R$?}DΪߡmڃA]/AyТ[签ߐP"Tf` p-w%eE%ܢ1$#ʄ  )G` r.#ч㜝(]\ ýɻ{䚮{qJzE8On$Y1G?A rkỼ>/ՃNMMN`Řs# D)RU[u|'tמZG7kik?SOk:ج({-ߊ0ӂ%ߒ69B>N`.jjGNR7.Qݝ O"kHB,H4Oxibn.J5ͿSnN,>RiGh1${L@rCEhdme\TO#iS 7Q瓛>X72h.8mgc%h8AXs^H9j4pt'< =O2?DyTb2Vn{+Ԣ.|)O~M|!MYFW꽒؇Ԣ_N.oUZ>?Uv5G}jݝr72 =}^{;Eg^kz[Vt 񳨠vyz^F󭻴1)]=z=e>@~yڙPbsV~Xg7"W>g>b ۥM$ytCuO#j$ezIr2KOl4'̂2=4h|?1"$fvJ$u#ݩmF/؈5H?}T$?-|B=?!SVE[+xY2n߫rh?>[tY+icdWkc\oƱ+QN~1]*ʳ! ?H@,Xsuh!,i` =Q1?KEzȭ麋{mE􂏣e]׶}R!}w򍛞z 2(vyZju|$^s~oQ:g^ jG$E?9ldO?ybTV ߦ67>[n_:yݾe'NQ6"gqG/NB}N;#q"s6w̡1\KNlD>bvHߵhUZ54#y ;j}r d[3/'~jW2 E+drWI?|扐qL',\L'ݔ;YIvtR}&[_)hܹ[ўFg6UYC$J3An-]kiIJN6ϢߪS.-'c1kJ. Ƿr%C6AHwiB1 s3-y&iv?Mͻ*oZ=9J>dP6M5~uSeJߧ!G?8oE:yY4#[}$Ϧk}?tKwW7B<,i#?^l)q"aYȆ0bs!Ґ4/csm\BXf9 lnbs31[l>Fܡfy6f /-6جgs+llds.la6jlkl:|l*/"LtǐR"ÅKm*CCC@P呮RЭG;UxrQjmW ʕ1=69nwbtBitҩmR|WiQ.MǕ2c+]uz詬UZ/+M wY}1|6dJU^xo}sw{%~-j1^iooVj*(C-,W2;9Zu;qG BI`C&EQDjMxzn 5 O`7sy>^i226 * 5x{(euVI;SL探ܱADiЪsdHssԈ:aT'IQO( UL]=i7z|_^ۢ-qs3ykl!-C55Ԛ]Id{b~rS>6 UyellL7>H㏕yWSNi^S0NE6711\tIŋQtB?sН Х Э е н        % - 5 =)`#tҪ~zۅzi]il:oU}5 +*d]էg]k++خ0Old1hp,9r 3p>UM1nmbᘢXR)QC`QX"_˧/fb&% ABMzܯJ~J8D\nᮬ15ԞZҦG,v-oΠcQfN鼏H@Fo Èmgm |''=*0Ril)+|+߼p~p^VN[L{0wqҷ:;7Mh\W8&A)dm>G03z~tYxO%>bwiByD<|i>EoM?)p^R,uW4.Vʪj%rj) BFiit<j A،rO$Y;{2uj¹a}7@@f9b18nќ~v\d7_łM4lpzWje7ξ_S6n(b:&Gib|ʼ!M_J7U|q !oQ^{_'m ꮥ֝,lQ@Ọ̉BZl -ʉvфU0OoK ʜ7.KQQw"7>-\E>K/,[[$Zq-i қo$.ru]t)-_d\";1׷Q@nE178{1M\Dt"Bʏ)a~):ZFϋNǹT;Ǭ<1*@#+_N"/Ng [D\.}~uTE;Ybov͘{ܜ1n50T"8#3sϙzx vXkEx R <r4az]PO<- םq0wugo/ w`!;eI&`+&pSRU]=W[O׿&a>9o%z=%[Cvvz55.]ku쮞jxnowS[T/. ?0Qӊ  u@3/sըVWrܲz}9lwp!2 KѲĆAR!C@@ M cѾ.}7/b7RFт;Ml'7a`O WB0wDU$ ƒ !˜Pevj8չ|M¿zyB.(ߨ3Vz$h!lk FD8H5D6Ƀ-n*Ƣ%7Hv-g1X]1Jf4m_\n*[V]M⪡oԙ+  ?N)ukVhtq?5޴FYM†x'BOM VEn>6\, `xY+2    Sq7ߩu"ptQ6G9ul<`  b&> tڤwU̲z*{EvXk nLst.}@@@@ `" ?)YϹj(9P\7۾z2)EDA@b#pmeTY.&]xxD]nqӗv5%Мe۔ !)C1 Yl:0і=OЖO @b ,*BOˆjV>ݎR!cx1r    qp&pH,\$ <'p&pH,\$ <'p&pH,\$ <'p&pH$dA !=tGWhmq~BLF$^:O_" ʫi5 iɲef2Iz~OY*৞SZDgGoRqKr%]h-\RG$Υx~%̠w)N*MNr̝ssgcHhxv3 3=M-E)1EKb@Lpo.r&)wq-ʱ ؖm}]WCOlH,=EGCR5FrfU!MvGi.K]5^:@?J#3r`u"Eψu4ZAɬ=;B--)|>n)nkɄ4=5GL ڞcb[Z, @ʕoɥMB0yǞ'`OB2 2KxhʞmϦm$} HΞw@@@ ^6xC@l^rmox=eM_Ҿ{5h!$ʘG׹?|; YgIڲ ?l^H6W 'tCHQ+ ӧ, 檖g^uk\xϤ7hݮH-E򲠏3C5I隣I벗P95sG|i" ZDY1/WCQ>#zdշnc G3m玳 1D$x.//Z\z4_˴0HpUL˵cK7e c i!|tlhQF2^ t+tu}$Df>:+môtE0o4 3Zz]E 1âEYqӲ/R,Ѕ395/ ˤ H]t_ 4\4rf'Eiϕ]5Y@ e06y ߹$v WHآ$HN}뮿\c9!w|@@R.R8[A:E9oqpJ4m = voCA};BQ"JŔQDONQeevWv]Su^P99yTPTJCQUziJh˓46TIC3 F]NGܮgePޢ*ѝkނ>b!2esgo&3m5]9J*6IS, mktIosޑf mPG$L7ߘ KxBM{2з  ZOzVPI" ٵh}opEo-%T#0/?>̂S/yoR9@P4ËRW}-.xz_QqLB ˡ(&jnǓLhDV&UrSLbVAU[ <.hm%V~Qח}('G2R{u< 9Ѿ8ɬ}L-JF7\rbSpBUu댌)\j1u5?ZfZq[NrvsnC%qE{|3]tg֧cRd(Y19L56qܒ_ 8#7.]3%ΡLC;q6C١\pΤ97dMq~.yqo5>իWSiq<4TzOҁ }lͤR{"u=thvgY&/;1XOXCYܹ<#i:(:}j}%QE8Z߈{Z *zVx$ULBF29K'=FKiasGs 爃quQ1?%`<$nMqOqpM֑>cn?ekm?RQd]d>v@ା}݁1CoO҇a28'q8w2b抽t'7 8ˊ(09F,S|.q-q+ӌ2F_F<+x@ %%ļ_lym\l ,gs=H lnbs3b6+|؈cVE̿:,s儻0oU4w!t4umyꄛ,  Jz{{wyGSx壏>R>ce||<`^}UԩSya::: S.MLL(.]R~rEettT F~n:S;:TK:U[:Vk:W{:X:Y:Z:[:/:]:^:_:` :a:b+:c;:dK:e[:fk:g{.dSFU2 ҐlV .tުjgDž:tUva}d`j>d>粑u>l>:_sHH$± șv3,\Lk m k&Zl:B a7jV0+UҮ]Q,\J[VrL(RV^"&M`"mVָ˕LSU/+RIq(^xQShF(0/WZduLt AqlWDnd+ф}C =)UǻX͒• 6="Zo#h7"ma\. JŤ4'Jj ~CjSmrSU&MMR}-opz.QpNڊzh n; cZN,6#8ݖjiqUt /*Id}2'I?#GR >đ^{tٝT5Cz+J佚]W_,/{?<[O/zcIQk#1k2UmIs 7E䰡ǟMDظ*4>[D6l|Űƫs ΄evL0>(#StK #rL7޺GCO&-2G_"ΝMs.CǨK8OpZ]r4gv.K[}i񛽕j09)y_gDNr6 [N@6r{jZ` ԄUBpr8E ,\`Ⴋ V4"v' qҲ*rx)xI;4W{S9yQiX;ҏ >} $Ȼ825-U┳qu$ڷez@kf袿5[@=sF!~Z7t2|]QbVZjˣtf|Z=~G=wL^:kz"{^kvxY,:??: 'iY߳)H"hR_e?GiUZи1@)~UtH nMu $箣n#gvWmi8$㽸iW *Tut֥b/ L;-K+X{+ґ'4aIUwGp 'PEz3EjѤk]WQf(Qi'))4)]tQ5gdLq1,,C{MO.~_*'C)SB#rgbcIz{jRoDfQ%'c/\VpqYgtɿjUƉ~qn&]̓w un:58*;U/SA{JujWubZNq) ?nrۭ $i}ݴTx߂gMFM+';>fܬET1sFͻ /^Jt5k|]zJيk֊?lk;W\۩/t`ST%׈q$dfJ08b#xe]1GU侁5rvʹJ >[5a}D"R_5e{kf*D\^MH٧L9O=UƢg9gm>EW%ft)(:tmAsJfw6Sws66}J |L.Ga ^49OWCa,"9Ku] ^f9-vɓ"kҢQZ`zb $Dh11j}i{m]M$stsmNct'2W.:b,хVM|OsK?ߡ3]tUR#̌c?s?%['9?A:C'ڵ'Jߠk)ߢ?J|;m.drg'{,}-(vl"I#* -*ɝ;F @@@ e)2zGbC;}o<,USBjX㵔9Ђh'c臯υE+x{;\/CS.j.'vVb#^㑸gUK"iV_v-쐼Wt}hS[(ԉ>&G i=0{95jC }2sQl9ـ=cyD3uG1 7Io&$GoPS8{5GOͶȆߘGJw\fqYO 䤏XTO#iS :z&|rTb $h%ȁ=R[w*>Lyӧ,Zh;Z'H1$@^ݯ;䃡D|fd%Q."@5)J5oxHlGVN}R#j-i7}"*m7-4,Nl(WI 5? } UG'[8x!6j7\dڎ-<e~ez}fߤ-rvArys0ٜ:$!7feP<8=^O1/j-ұan қG p YTPRJ;<\=HS#]]Oy*`v6.:~yh'fʒq^XG3D@,Xsuh!,i` =QE ҏ4jj”C} IOm\ս"QQ;'ۊ}PgX m隶`r7hvёJZ)gA=!` << a'ΕhEhݡpm{۾z:k0uPC h,ϞOUIĜFKBv?\5z3 n*}a6GYW@{,j;C+a_ףcz|:韦>YFN>ݾe'NQG8&ݸ$vۼZLUvf+w,k%m,:BBۤ|>ߌݓ蹇 @@O g: bBrsU>I}5Z7O/Q;Lvd{:9C_I385mƕU;T+- Z5j1#PFdrѤz%z_:@ m栭ްܰpN콇i/.!9jM}v}ph'ٝy *RDXk3]gՁY,NK2NZ}ˢϭ zNJSh i+Nv23W׽zeH$l^j uCDL9:͜pf/ .(n &HI-Q.XB ~sF=M߶CeGDgOӭ'x͔G)]h%FmuE.U8Fg{tRc4';tPz7XKN吧\RttM'醍EP :zN=M'OigKM|zzm6Қtdza9y6/Xm'IiJXC+׫N]m=t,:KxnMgNK(k2NV}#;l'NimAi*2')S#/>FsWbTI^ק1ьNDr3sX2 s}ć"wN)=pD0LQ=MTF`kg1b{t-(m=\tt?xsq{=,oN=b~宮crV:v1^:r|DrCwڶrV? @@f#EQȩ|ϱ0bQD6sulg&!3U!#[ /6  J9`ė Y2el M!lgS67{_lXбϳM6k|oYf=[6_d#wl~F6 {xlfU6_clg#~_T8\aAS٤Ltz?_y\hVڟp/WuOWJe\9^!,:eD m)uJǘwlܫ0(+&~JU˛RSw6Us*u)%2VFL+K&^ꄫ9],TO59GiUW夞ui뼫:{h+2}q:#8Ѿj[^F~6o$m%޴e/n@{mT݆1)Fn0=4m߭K}\GJT7kYFo}y̬#Rk]͗ۮ1g(Ӟ ɩoJK;byut+ ͣxMI1GD9[n}iJSNWVu=1e #Y?9ʬG3\j ;#̞Q;K\Rco^i)s'5cbـۗEc0NiJw<]  L^wQN裏?XW_}U9uf^{5ETd# ʥK߯\xQUFFFQ~q6Bg*tB*tB*tB*tB*tB+tB'+tBG+tBg+tBE6B+tB+tB+tB,tB',tBG,:c;:dK:e[:fk:g{.dSFU2 ҐlV .tުjgDž:tUva}d`j>d>粑u>lv9^sHE [C-#olג[4O׷[foξ*ynbLϢ-究,,0j;JZS;o#Zݑ#q#ͳ|45Sq[F˯?zfk+-/ GjvRkLz:,qSt}"X[ӧe_b=2跿*uՓxz O?O Xc}dRuPόѫ1-ő)q/ N'}ZQjJ.*hMo$m%޴33u9w/oI^NEn nJtyT5XTwy-u;˨]iQ;jNOJ8D^ݕu=f$p,[KT (?K9L úKriUS2<(TQ1X[H/LրIWRAC\»E76wˏRFX۩s[Ģu=1e)ێ!)"j-+|+DTsK\wg\JXbo%RG}eD pI11,v>?N^8 )[OXLup(S ! ki@@ÇEfhe?fz.Gb&sG6j8M=WewMvq]ُ|ng_qƍşƿ}竟WiSXsr͛ o(*Cb@-hi~XBmʅI7 ?s5z\_=v\@_ ׮     pVӜR:LPM~_믜3 e.ݸn= wo_R7ӌу@Ȣ=Ghksgh`,(nimC]Z~;r}:Kt|}*-$    !,\\:Yʠt0ӟRpF #'n?`4 Jh      ENFnA@@@@@@@@@@ `"@zEz7r           )M )]<@@@@@@@@@@ҋ.ҫ[HiXHp           ^p^܂@JEJ"*o@@@@@@@@@@R.Rx ,\Wy#           p@@@@@@@@@@@ `"&.          E U-4,\t@8H/XHFnA@@@@@@@@@@ `"@zEz7r           )M )]<@@@@@@@@@@ҋ.ҫ[HiXHp           ^p^܂@JEJ"*o@@@@@@@@@@R.Rx ,\Wy#           p@@@@@@@@@@@ `"&.          E U-4,\t@8H/XHFnA@@@@@@@@@@ `"@zEz7r           )M )]<@@@@@@@@@@ҋ.ҫ[HiXHp           ^p^܂@JEJ"*o@@@@@@@@@@R.Rx ,\Wy#           2RZ:vQߡKv%+VRIAWyՔȻXfS}Kљw#bV ׮>ʻb6f"YGO==?oҕo/R.i&0Y)Jrʚ{蔷,tMEe6˚4ueW4M]7g/RKS;:ݹkUs%Slsu{?}ͥ¥To^D/7Ѯ.(dg9ʓR>~'еKg6^n=-ҊWƾ]A9 l)F0َPZgg.RkL]UBmI*bef3,\cE] -ʼj2D{ˌ.?: GtfaBO$$m)/|m!MLA`z df]gH`s.PEN&LJ 44ghE˴d^k W< -4 k#I02~S(M9(4@^vh. g^^ys|^ܳoSFYc+i'|f ͗,PYkXy^:|Sib[Gvzs"n)&;I?,˼ "'-˫/M7B{g=0̺|y-l\ۮ fv&&YA6A@@@@@ - `"=k9=`hOQvo`<bQy|}g}VQ|feQB)ӝ݊hqeض,Zf]J::ռ'K桖]S!${F'i쳕tC47g-ɟo5%'a쑲lh P% ]̤."zrb*(sqĐ:lzJ:A:)h@@@@@@R@ w'<$h+ihOB߼þy5E iYEMu@-A`\]@.68fE{3&# -,)lV iXdrO(r+.dedL?;~˃%t.zraCSǑ`q]Urg)O EO&7>J>bS6]}ՔsEQgtɉ:~Nktpz:>${~"`GG>ଊKW*9 qڜnUļ8y]nq\|@Ļ.ռ . $L^ [QN?N^~jܫa.9NU~Mh^43G3ιr_-g&ZAF#_2JXO ʓ; +ۤfu/^S63a w.,Llvẃ,s fzJ*;1_3գ @@@@@@ܖ9—E'63.>ڼBEtTڻi5:gӖ'iqMT߾OZ!8N7xw-'^7`bùɯѽ( *w/mO<1^ cEBkcnZb*kK,$s)V,L|Nk;m~޷ rb0Xam +œXy?m&Ye9tB?6Kݫ/aZ$&W~ôo c0%&y8(@ P@teo n qʹ6:juv*i7JGͧSo|u+q|<4iOS|JHKKS|ZnXl*r4tJkEyʳȱvAo`#k[ҥFh_蹳E)m4YӧebK$Cw\$':շGh:)<>h 4}H_mlɞk^&܆_<~WتLMZۆECVFbڤ¢)ݘl41`9ui2u\VҫvZI봲=\uyu^DŽW@tچSH-A(AW:,G'ڑǟsAhlcո-i\} w~%xP}s Z$!:VNAf~+o°[>+ r` S QR Z(-'GgqV3e{ɦҔS%gۿgnD-95珢cP8:.~8how N#7ơP6-"nF]K#ϼr܄/?,vE ***%hO!E2u)s;?ր.mxBH/w1.14¶RiK-Q~9ܷ_Z [$"ӌ;Z(.\]{R7M0dw0s\ 4`m(@C;\4v?reqV\kXƝ^,FAcr%91oJ WX~ܒV_ &a$>Q欖c(@ P(D be,z gakL؞$1qq' \7~ HJMq41YJsUvʴkfx2O$MAP,v cD^ټ@_̰Y1DƘ! GW?>$;nm\wEVϗھUil"}]N1rT?<_=\?.j ʣ4iLz-yJosيW%P"t:^g:c sKdJ]R'#4^.V]ݓ4422eKSy:CK/#A_;7>6"mFRlÿƂOM*Uc,,y7F5xr% } 9O`g=4#\&q>.\h%}} N5۬q*VfڭXdᑯaDb-#rMh3rWa6qR4t,r uh7j2k1S8/RM*c:iN˟)VTegļ ;ATۮB[(hU;=p&ZEnKI(~"v9qI6z-{8s4PU1⑴竸#{ۣy1f_/a<"aFh~ / P(@ P='pUUŚ*%~Pf0ɱc#dUغ5;~.'v:'+<'[[OBmҺNSIu E%qǩ߻3_ՠInh*qBlQ:ǬŊ[5}0Oݎ[ з;SgzӠ,6u&Yx~gӭR3O:O3j"JeV̵2t]$﬘m])87$h.Ҟ9rvMyI- 87$haUCjg5ցW;LE^q__ٱ_KpOIiUc\9m˩0 D [U-9Q F=uTc7ǡht.wpqlx97egU,S ҺOϞwHeV\{v'au3ڲvc#haKPתt=4nmМpwn.A 7a>l38{y%1ZqJq&Xc̺!hQJQFN(@ P(@`^U)WڹSs < ckdBҼ$&!%~" r}"YkV:P\wLcL?苿>\L}E^>}}n_ HZČ*W{+:=4JС᛺g@;'9ݿ5,2TQ&YJ0$s$8͡bS2 .d.![ahWALѻnPc4dt9رdc5]9Ҡ+b:Mx0(Mhhd=wh29)!RcvJr 1VHuv_K ah4:QD ̚h=tL, Sq{K;"frNv7VSÂk5Cs< mwc_bu6߄7װk_jގp-3[?OkScc")i9I9 ߛÎݯV;ͥkmCM)L"i~vO8^3»Pj>ux9jGi9EbeXZsR?m4ܷvqG?ƔBo9λ;Qm 05(@ P(@`ǨbEQq\V^kz\%Q#=d ?LV^q%rհ+}F0cr=6sjsr䮋6THO_] B|'tDhƥ}]"w'n nlUu/B>ÇtN oX.ufy&= K4J\V1}8 cԝH"Ux@Er~ۄ,n6J8} uwSȔmT3$h<1DwǘY~øL.(@ P(@``M?g: U29%-sZSxYFI`Gi ut]Qe;2 1}\"6r=hnZǏ]|Q xyO߶,DřӑN6jn+i9\)4wǘ]"Φ(@ P(s hnuB]Ջ]w!D\(Ԋ}Ɠ륯K5/2>[(^iͲN<\W)w]J*]'7/'|ц߽@hB&(2ukDp[>csjiꃟ9^`H[4 At W2gc[`o@9u 2 1EcFF.ۏLsFsK7jO.ǙMrSq8c}8(@ P)E 5mYC}{vmxY[}#n{]^Zgҷ&܇"%ܪm@OȣPC٘8X;wm ~x]B7[y^ ߾eF'#ۯkSscԩ^m;P lMxmאώG?ͱS]3N#wKn3::NW],lkm~t 1yM0jLBʢ_rnli跧2q=+p{vNt'.,stWbߕ!upF{8m5Wx=$7MPC#.v✓m39rYGhm\T9 1o P(@ Ptq,޼'g!2 WөW.^Tz8:0"> Kh~oG!oȕ]kJ?!/Dt|a\;)q) ԡ~w[Ww4r+Axg_|D_n.;*#KYJ4]`N? <[b0Xo@Ucܵp {cн[)9]. Xˣn+Ivm#ejXzJVãaH*0k(@0])uI_n1oS-l-D#0.֘{~oFw ݣ.{eu2];^{*O6yŸʰQI>tڞņREA&lmKJ]#mcxexwz[CZ-MȈPlۛW#b? Q]Z<$gA:Rwv5޷uԭx|i=G"4{;~c|\L)lf-J5x>) uJw-_51Զ|mvvG4'S,QFrln5av L*f{a5P>dlr>\Cb"ĦROh^pԎtUh4F8{GqրDi '1Pij?rSgQ(@ P@ Hw+N@5YVZӗ%yqJ|0 wChs) .a S/ \tnyv;/74'de~E&5TB#wu 41ڊ<^M'.ݘWdu;5X`64W_cr\momC(}a>Х1ɩ@'h<>:')=I0FK]\ɤI"r$a&j _{wph#2]mk>C]Rt_7)ڥ%ISʟ8_uӱ&ٷvreN$!ks8yuS5ǒd>qG;Zphs6< bǿ=J^g:ג&wOI-nadq?YEbf= ;wܺ1ħoA$)]Tm]"'/)O.ABsuLJn䥡m1fdxK-ݝ"S3/7KQb2J6=܌=fڮ6],(!U ӚDv1&'u:~kou\Ykk繦N{oPFZZ5m4Y3,[r':[GN%':Uׁa-{pJru-HM1YЁ'>D}#nE&`iH CX$s/_CLF: X=$[}oI{%_ IX}hS̚oOyf(DExa9~ p]q\Eؕ@IDAT}C8{2:ČÍa+1e08;E 7GqbMX2yn]7'E]xgNhoiGha0~r,Mޜ]lYNc1tx(Z#ǎŘQݞ,MgpIWnoWQcoDlLyi1>zLI P(@+F?FXX5J* ؽ{u v-߮i[vm/\%̯&;wOdd|'遲~{WwL-K;_W˵߮i[/u=Mq[Ii%pͣ^`B 5^}0X51i=!ߐOLhc'HJ#hqrɕy1WEdD577xUe)~Y>^R&DˣBmb|<;&-|rYmv >Opbkj5&ipB:)j!@m7Td F|6Z!Q(@ P@sJ(0WNW[,NyT:5._KR 8~ye{֊ $rs8x gfs82z-= ||.L P(@ P`O@f%vmETVؐw6מBU*4 :/R&3o_- }M/'b(@ P(@ PA`"(,4cQ=o^^DpX<2;_X`J)qm>sccך(@ P(@ P@+V 0@搐 (_v_c0U>*P(@ P(@ P.f(@ P(@ P(@ PA`",(@ P(@ P(@c \sc. P(@ P(@ P EPY$(@ P(@ P(@ P0\(@ P(@ P(@ A H P(@ P(@ P 0pa̍(@ P(@ P(@ PA@e(@ P(@ P(@ `˜sQ(@ P(@ P(.")@ P(@ P(@ P0&17(@ P(@ P(@ P  \ER(@ P(@ P(`L cnE P(@ P(@ P@*(@ P(@ P(@ Pܘ(@ P(@ P(@ 0pTI P(@ P(@ P1.1(@ P(@ P(@ PA`",(@ P(@ P(@c \sc. P(@ P(@ P EPY$(@ P(@ P(@ P0\(@ P(@ P(@ A H P(@ P(@ P 0pa̍(@ P(@ P(@ PA@e(@ P(@ P(@ `˜sQ(@ P(@ P(.")@ P(@ P(@ P0&17(@ P(@ P(@ P  \ER(@ P(@ P(`L cnE P(@ P(@ P@*(@ P(@ P(@ Pܘ(@ P(@ P(@ 0pTI P(@ P(@ P1.1(@ P(@ P(@ PA`",(@ P(@ P(@c \sc. P(@ P(@ P EPY$(@ P(@ P(@ P0\(@ P(@ P(@ A H P(@ P(@ P 0pa̍(@ P(@ P(@ PA@e(@ P(@ P(@ `˜sQ(@ P(@ P(.")@ P(@ P(@ P0&17(@ P(@ P(@ P  \ER(@ P(@ P(`L X6@/ B;=e*b"H)%ۋM<%pu=I~`iG0,֌hG{b7u}|w&!:e '\Dܝ3XYo;5ј8!Qv(@ P(@__~MK8s;1ZP]Jeٷ 꽪\2 {9vX-o~?}#':px \Yo݁&{xcIEx1'ܞ{9E/iۋGFQioɚfdǫfA^\|G0e}I^lP֣_CRW8-=I}B :#!=&k)-~2/AA2ܟ0,(@ P(@+T+q[pvu`.y@uZ;axQgxuF~zrefdm&M 1~>BbYm?. g`GB [;1`gsJqWw4<. m2՟gvDV9V9Sc~+Ig f!ۿF*ɔӤsh@|`*B#x_oNQ(@ P{+ejGAƛ˧mn[ t Z M0صGbz<%IV_ޡ"ZcWmf+Z5wψ DLlwj+s^0~4nS28 *=s]0fT6|;9ٟټG|.G>sC)fO*EَȝѳYF P(@ P,g$|6y9Ծ2;Mhmu+Cdxix4qckba"Q(@ P*/Wk0FI(Gۣ0-]&Dq_h^f(oH'mmr&&;a={rMqbz1$ؑiO_GV?pxKP{I__@+egQIHtSA?IxFڴ1c/NqoȜRg0,6-R(@ P)׷PO Fq K ::Bap#m%C ⧏ ngm[+)[1F3\< msCLޜШ>i^Ԣ~txE h&x(@ P(@ PE@K;P֊DKxozTEX~~\ z7ף~(0e_Canb?[zݴ[F`Օ~k0)}my6W^gqСƴӖsřD5_-3Fnj NԡGȫߦ#%?-Djv%[XԴ=2 =:-}y&Y'ȚO~I:WN`ۯ_9Ś;$wlzId$tQuF-~ j9Ůn(T܌Nю ot4tw@Jj'glĖ7jQٌ#'`1r,z<%Ǐz5|ۡאҾTMt?tli&fly NJ[og6Wy5Co<1!8ڸoM?Lֲڏq^oy×dm.ll67ۥ(>刘꛶ Oޗnf(-* /n/BB묪"=IS#1G(@ P(@ PSʁ\+.bߖè˴cӧP8\Di(= J Z翿k߸wX[aXUڼ¯Ԡ0~w['^T9,b}'O%pŅ'?Die5[Ȩ[qTCU)ҪzM'u7IwڂuCv\ܗ5͑:RSX dߺnsF%߾r:}f:I\)#Q LGAz }mݾo NXezZ#ga,w@7HBt8OG}Z~ܼ짒M$Vj*u5o}8So'ըbz@w.Kաj2o ի̛h/gVWᷞFy?2ٗ%EM!ݏʕOht,fN7؁ڹM;5us:mۋ<]B4Xsxxe(] ^i X} u?b-Bh9PjVBEm6c-C:T=;' ޭ/!V*8]|_Rc__z۫-؜=ȇ4vW H_wnνƿcZ׏3Py:&V~/\"(8={ٓxs4ҕ釽tA %(k}.+HhYЗ圊7T"묊r,*=t(@ P(@ L̵Z]? [gو0>><.,bzQrQ:IЉ_m-z~ҸV,,3rWacF8Urwc#f݊EI|=#sly edz4)*l5,#j220@OG3 ^{LI(~тkӖ,h q]hL]UV:;E~NSk8 S"7#ykqdIHsfwcaն 9l3vM@U׌o̊Q'> 4Ax17Eq7qD[g81"4,Y!\:s϶!ksY1o/5qf|4M:JobHIsn,Yl۝ਜX'N3q (@ P(@ P`x\@ (P:ZyU&IZ| ̸&Еyw)Z2 U> {>4 qhb)FG![T;bMz-XUS-r^:p.:X0?58WT X%Q5R- ]]`BGVBRW ]J袡t=R`wn)6qNdl ZeF%,ƵlX #[ۑG3s.Ҝwkdˋfۿ/vYIߎ7K=&ZS43si7n h^]9 Ѷ{gtz:utLxi~KUݬgdܝ. %>I&S(@ Pc;Z\ 'b.haoXGmxGSsUwi, I^7,T_c.h֧-ͯM;4Թ]yE=q %ϕ>R^: 'Ĺ8VĮ4ZITt8R:nDJ2Pe}EBJRloc Kq+ҳ,XW}#o-(U ý|,-CS[PzNA XwsY۩=NVtՈsagBiO:߀cҾr^Yjt87Z o˺u\Cp${dڣzM5E"U:="(@ P(Ofle}M^6̇Ȉ}^%3W{3Wx(9Z5erʑ<=nJOuhm1鶶>'՜Z-)G^{sj/Bmpx{pxz wn^~jf\Rӆ'/c|g%z߫CA}Zs##6I|\(@ P(@ PU'.Z6lwQq\xcX6U@ia齝sBѽݸ ՟_/@q UH$+עha&T hBRQ0FV7ZoΎ #0s6Oncdk=&PuۂjGN}glWܲ@oFV*lBӌd Z#V`vyڻ{wyHnSǻy(@ P(@)ŀܬ=Rr yG>/iàO/9>xTB^ӊwW#48s:UU4V8X"j!iC0:P[-/I7vg~9+ٽo2iS&w t%޹B rZ~;3iƺzfwTSﭸs>=[HFD=9.hEz5I<Ӡu&h} %XiQ` CТ {wV: }D(@ P(@ +xlHw^?<o;-k#SyЧ+=p$ W>O.s4d7cQ펃1ot;VKf7|3`#0׏L{QQ֢k⣦l$um6?b3wAv|~L*!FqDw~,lmVa  QND5 728v9ʟlF(@ Pq?D@j0lz?<avqn*D u5v‛w"bƌ\TA @sZ뉳!5sD]k7uwU*[Y{ݎ$5kv:pNp77\8 etΨ[2w(FNP5nƤwwJaFAʑ\kMrGo QYm6x1Ygjznk:y4w@=(u..(@ P(@ ^70k1C4%iΨ_P]/cVt」VokQdԿh[qBas+};d4 R4iCBUm:2ڶKw(\ Mn/$waw8r6]Ԉ-UG03+ge6_]Nag1uZ S}(2JR2T?T'f:2gĀ5؎le$LS:m۲*g˘a`gvoL]NhEze;vz5bg}INJc]|<Ά5{4 ė (:%6;" mgfU]mu2bT'<'=-Ꙙ7i+ށwW9ҙҼz#G(@ P(@ P\~lSͻqR^Q!G2 ʹto1&\\=ށH/u\ !6q3Y*b~BPj9Ɩl=nxWik$d{KC#-cޯۄwʥUci9e.,ː7h6V/AsY=sGQd(6Lci Axrd:n0!J鶶T`FTg2'%Xߙ=B_݀=Vm-6m}f4i;jB )QSOʰ <.i ~:CҲ,aJrwOJVUJ3X[͵/!Xs*[wXx&YcgQP3D0loS7gu>ga#0y@tfmIfu>~&dj*r֏@cbo w$xJi^.isK0M P(@ P0&Xc` q<ߵ:2s8]y}ܮ]cc] _.^nǚY%{Ojk*mSIjP\ .2cD!1pdkYcӽ{ֵ\sI-%Rk!qqu~CEyH#e3HuQ3P,/C.L yZd.TW@-04Uӗ0N=ؗU.hɨ}oLp1}Qʔv9V4q[ծ:/(6^'ҫ6ӝe= lmyXJ`BJcwY w?5w,لo[/)(@ P(@ P[XQP}i}t`89< r!4Թ{c6N&ǯ]fi ҧIM)NLltnW9ө mZg:\esݮ)w`Ez瀅5mru΍ю3{֭#_- S3ڢ|${Ζ*%Q2ŞK"r5Y+ʰcF]ߺͯmeh>z6cuzyNڏCcɈl_$>^+թS%mgb'.׎h5gw^/ "M)MԖTo5i8ӦMgem"Zf׸ٰݭ&=ug;"a#11й-GN#jUG̼9(@ P@_H(窫.P`yjծeu:c+n_@\(kkkIΝ/ quyW߮Բqe\:_V]ӴO]nZLW:V:l P(@ P(@ P.EIY (@ P(@ P(@ PF0*|(@ P(@ P(@ \@ P(@ P(@ P 0paT(@ P(@ P(@ P'e(@ P(@ P(@ `¨Q(@ P(@ P(p.N)@ P(@ P(@ P0*Q9(@ P(@ P(@ P  \R(@ P(@ P(`T rG P(@ P(@ P@8) (@ P(@ P(@ PF嘏(@ P(@ P(@ 0ppRH P(@ P(@ PQ.1(@ P(@ P(@ P`",(@ P(@ P(@ \c> P(@ P(@ P.EIY (@ P(@ P(@ PF0*|(@ P(@ P(@ \@ P(@ P(@ P 0paT(@ P(@ P(@ P'e(@ P(@ P(@ `¨Q(@ P(@ P(p.N)@ P(@ P(@ P0*Q9(@ P(@ P(@ P  \R(@ P(@ P(`T rG P(@ P(@ P@8) (@ P(@ P(@ PF嘏(@ P(@ P(@ 0ppRH P(@ P(@ PQ.1(@ P(@ P(@ P x,] tMswtY(w{+Bݵ C'EcV(|n l4#kFR\tmr77$P!ᲅ8C DWpŁ8=4↌]) 0))o}}y8t55$ORL@ \ Wϕ5h9sp6:?# J]6=ty9n"F9k z @f eMvs)Ѓm1eנ:D)۶fT(.Z}B?[v9vmgfMC3=]iܐ)# =77m7h[s5UlɎ&w;,gpt!1bL~q_s-XUJAodg Գcm}K͋A^7JFms5BoǶȈH// loX CFCnּg@b}njz)477#rd$u,kP^}[Ad$"M&Li !R)5ٿ"=/cmjKf{w\pnO.z\R{ \mYaN,r??r-2VuI9,Olۇœ,Z 3&ѾV|p׶QvPl/1͟Cls[?]/t?;`sqJ-,u;C#b'j^X9n{P7 oni,ٿAYfrtS><YxѥXCRó}?V ')ưtoޔM 7Chߎr?ko.jځ97 g!@AUe ڇX9SlxdwVF33PzzoCX1ڙ.}~lY4a#Ռ|Oq1(pWζi#:hzC;N]vPf|h|c#QXUU[uVl߾EJb.m x@~lM4^Fbl^UeWnݎ닜mvNzL[ tYU`tN"ǚ|~'GZ9ށo{߯3bGR@'6N7ny #bf48 iOɡ Կ4k[ڊVHPn`Օ}[X"="] m؜=N0磤(+P> ܭ\-HF~QV#+S'E ߮7ae&*vw)gp+PHƄt8jMo P ^Y iYKdPw Iʝb0"޶sXK":F D'`^3{߲P(zNe+9FFʼy4Yxs(F@93VжLĪf=Pm;Y*/={^G (dA(x+XKv%=qQ,Vs+uA~l H\-(Nd Z6uD1=sΜgið3sfy7}vPaM@Sօ߈aŁG9\.v:L~e#QD`?pHv?V_`|3X=CIs }klU O&0̌BaxϖnQ ^Tyb(؃zA͛廟W. N|wk3TSCE'~sZW" H w\\g`"bIW7yAu%oQ|mdmZ*==i'{+`kĞUő6D@" k#઻ Ԍ7_Ac8Kf\NLLLxsUPS󵸜޴'&pf|q*<3ޝ!cǞktҎn$ yWL8C\_|2@3g7  r FͰ00C"y! k:.ǿ']0i`h/W)6jy䫺ŔT}gtȻ%N$pi sfG(2}t%Q̌j2k6yt R=~C~Woۊ)y0&䢲ᴺsVdkg,vyՐg~Nھ܄r} w޷yq3̍#?Lq%N+Ho;*iΩοSh.@6\(e9JŒsNP/I hW:ӡGԱ&)]>o/ΙgF<96؅v)6nYh?;yQ2o*ay^c8Hԗ__Mb~C}-xCǽF/NjLӍGKN<,O6D@" ۍH gbRD4LnѰtѰO>090$|'Æ, FܤWf2(SAVF,2N&d$i29d֐a0i.ϐ32M濑@f#{K>2#c%d$d l%2)"%2_&d!(dݗ^z̬Y7%8nKOm^7eϻFrw<ݧvF}߸{jƯ>]Rc qZaQ?FZƾSOOq"otp3 tnnnu7חy_3{fʴd8isS#%wE+_chju X<X_<m򒻖#h,iZCwN%GP-7QlޙVo;j Z+Olg͍nG-7uf o,pjݗuZXVm> 6wOcPIeGu=j#U "3ê^_.pG;%~1buIem}~iB/ݩGq3srSKHuZ{`|ح̰9Pw,W}WgK7Ox-|źB}2_v^=YܝyDdG^w6 ϘCy_}doAK=Z;Ju69d֯ٚWz4PVaFLگm~OyhGk8pRTyV-o2Ϟh5QˎaI<_֬AsX;bry+*R՗[ !ӸQ[rҼΊ|P튻P`kIhH.HSL+|s2߾W*-յFwmu*bl'/oc[ ֧fM%(y}qgs7:κzHYkhgz.|vhOW%%є4U#eq+%F`$AzE'0+q~,CXzc_ c]9-ф!N5_ L]j?m%5G4k6eg}*![tQL%nξ^A ,X U+EVqwE ) H0k8C.'a׷x2SOP=c^☧*"xRbh|jMo+)sq6]\Aw(} 5G#n"c'#"S, >shuV!/Ή8)uu>]L,'}X. ǁӷs幚XT,xۧ8^JS =C/b e@*E|\[H'c@Ta8e'AP \Pe @l '480q RTT>]?,־m5;)5&j0~5NAgo&d_:혰jI2W:a _uLAk5[ݡ|ܨPh0=]&..oN/Kb(7V'57 }gva3K8Ji]_Oz@9iLO )Wgj1B+_q"3®LgǁFMsmürҫh+XNvMN_fe 9]~<,(e06bhl,b} H#iڜ?@Biמ?8_"-՝~2WT?}'Wj?%ӗ4XcUtav{+߰.5|^/΃"3i+wq\Qq;Xog1dHXZz~ژ'Ӷ w]>F8m 97-/֊F%]!jX %."K" j튐u@nc0pF :Zܥ{ ow7_ݫU{s%[qp:ħozӊ=x/yQ?3r u*fdMOjvَ)ϔyط%Su{-t!i<|(wsX\:Ssn,5g7/7ZEn9;z: .-=pw_2nn.N*D7N*_|mS/:KކfԺa1_~~~iv*è4B{n{DΚ8\)xydњ3{Vtt5Լ %ۼGͯ%yDc zi*eB>ħ"oS SC]0v~hܠ}VOsJ9Jcp}ft6ٛpbogUFŚ?[|v_IG'3^_vdnu,ڣk6"Gp{<4M^{ʰ&-O 8rے,ě͕e#nOFN+ݿ@6< c+v㙐@55&K5m#LloEIBfe9'~a{9[NFW@ jAmϳ4HH&)wf(fF:d?~IYpYOnEhkk lNڑ Qނ iqts;L /kITzIyّ|0F:e~6 W8 rCBstc + 8XA@)B eO zIOo"k+DZ'ACT:B$?71y hk#8($ gv~5\Q-O>ݸSo]Lς(s›*Z[dZR$ Xwޜ g_6 B׭{ <"13:-;^7RUA{#ګe,ZfT㻏qGؿؾm m+a%⇸q:]Z??*m@&~4닁5Sl#9N1|UX}wx}H)j's-/ gK#ID@" C*X-(R[=Zd]m_Hr>SW8$@\5NP΃Dߨlw瘯QC!+I"hvf#A.)$<%p?St?1M wLrKh _wM<ֵ@Ր@E9P֯%IP."`F! /!'.Z%v<_Tf!V;f̧߬B B9wvkNӕXQ\˕;k׮f.'>ӎB}M\Ja 㤮|֬LAnQ%wbw{2qY qd[BB&T@ `vak͌K :/tqD*S(?SRht5N N>fhEu,1 (#ɰ@~Ck8ziHACd G=6E;.iڙM`yBuI(Ι-@tl,7#0L鿵,Ya.`vcf['Jy#R+EǢ‚umW?}M+X ]_]xF[7ܴ'ܓis#kwߝ3SG}-jYy34I$@HE-֨ j,!\ niyu(KKB:`NX޹y@ Le$dRcgO,{Up;p8Ć5HGR_ 4je>ޘ^Z\_spdREµ~;1tNaB .*Q_kվ0ndQ \ فykC9̏$-Y~$Cӏ{v%5hluU/4az\ojvVŬ@hS}%7rT|,=#HTӎB~#o=5;~8g=yܽ-GÏͥ7gQUtybY=#'Ogϖ?oU9+ØGD‰.m~pƬ\.W4gG~ Ʊ/eS29.~%oV;d)1i c0}Z@.935 ?Mt4(9{)D@" zPȰu6O3yIIw'跹27iħdGo-Yޟ)č_IQme&; =GX7T\ 237aݟdnwql<7|(͋7R荽2jYi,H32g8~Ղ[h# ??#9pӎb}]'.L8р:MruxuznLތl[۔+3MNVr^C%2ضf ~l?Z1Qv?՗Yg(l;1PΛg^ٯ:呤ퟫoT 6,ұ@sV;3Uʪd:iϗ3@}±,s>K9Dsˇě30~YnTVLj)I'g)A4jT_<ô;rh\7o_ӿ>-gKqgiء4vNEH$# ౺fBNL=uEx⭸-;̘뤥YOnF<W8^|t߁(D2߱~_QZ5Tr(~ pfʇs'U=EM6Vry^K سъgd.,K' ~f&=sӻ L  KSoT)N^5[DjazcQܗϯ-mpkI֩ZLoejظ1vk"2 5x_;՝lu6tx4Y ܙs$qt":3NyF \Q8) gN/X_٬W뗁sn]cGT MiaOwyޤ.>DwfHxB3{p|~QSсWޘ@񒠠sv' p٫k3#t LwCO] Lƃet3=#qV^?4LKJˋh(]g*@>+'1*pUX{Na8IHg LfyI̾tſRE" HBG@:f>Fj:A e;k!P֢htb5[(k?WD'zGOh~lVxn4d; 8lws2%Ƹ'-#q8^[Qk8~]?N` 5ӷz4yA+O7~ާ+}G>LTZg.7o- FGF0Bf"4AoLWasy> xQQT*s(etpe\YUvlE?B:PObv\[e.&:)J Tš{#c9Pѭ"ش}/QZǑ}=1Yl/ar-96u[_ Ze*9Ovl@Ae~ msGh E089#o:B8G0 O~ U` ]ePT*N_ |(GDaLI\Bdy Lhl4'P?;B}+qtl*] t'vܡytg> ZD1|qxA}I3~n'LӕZ~[<;Aܯ1z('IVW=>Bm?C#y,o2D@" _\u6mrEPO6ueC cs>Jw4&iom BR39+A|8g:FHA)ʀz-L,m*3OkwjUiT\Ko5yC-(mO*0ʞM>#ʷƲjw5%A +jLߴ&бG~?UBaXJ;:tG nǓL)dtJsׯh+DSČO '~^*CUF 5}㴆)ډFh_.D4lkD0T@ B+{+wrh?*s/93;i&yDc Z\Vc_wqNL5^[|6zȴg7-<0~ŬH]A>ېFXeÿ5\$ %3uhIǩiL+x4\Kr.Oqc,r a@|mbd~'@t\Md9 [w]%F~[@W8P]wNuK,K3# J$sk7y U5euuhruߢ=n*[ʆ bttC8~E Xy~6G{{;صf+.bm&p]M(KXJ6ָ8NX[S9CHTlMJո%s!9&Xc\x>voE6dJøJw}QhPZ(čw=3-_cPaҾF"I||[CMY"T"jˌKu2P[+ЈB7I)[WaEEf[QV_b}iOg6mZß|ۮ)f/("!>;&T|+1_:1ttC~84k=BNv.T)q8zX0 Fv&d謆2TwSGGՁ#EHH[)Dr ~G:Vbf@l9)dÓ _{hEn+`5}A}3g8 8BM=g I\ c1ͤ+yDc Hj^7baRrKՋA[{u ␒e+$uNv۲wXŏܗVhyKA/GeLJf_bx+&Phï/;?U(nӻBbF6XQ;̉@FJՄAM8SbaÂ}5VWcNÜ8u'lY>|1%g::1/Ɇ"H#vL S-&* %d熉~O*S~o$4]Nv#dnQ̧7̭a&f"dd$i2ltZCOEdL2Ff=72l$s{ɰ#äǛ<@A2AV2_ 6*"%2_&d!(drKnf{&ݍ6)&ܔo\5- ek5 4t|Z&){b_9[?ސx9gktO| xY4ΔvQMe-x> =pӓEXƫܝZJ -ΫB X_k{u\Ό [>Zg9Yhag%=%:,x_ozB֜q_Ԭ֞ +}$="vAj2~I%bz8}k_s,2gs!px@s^tcZ$ӎ[(oo}P5{;k~J&Nڛݗ>B7ƚ1߀.BwTj^,XZ[M; ''aQHg8[ty+3#'+Yy%7e.b$믚?Nsf-}ڀXz~ %vj{ݬ~}:`Ќx٘quM2[O4܅'b}&xsZ11[cSۃ:oSK'%:0 Rk0VϷcߒKWϺIڳ>Ľa߰%'قFNg.ʑLyjM"0 _'''NJcw0)2*2*2+2+2,2,2-2-20.2/2/2030 313132%32-33533=g$dҷ*&~0Y6isr37Hed|?&C$3dKsٹa2xcrF3{PXC )`ڈ$߆+wpm :B謧u?jGɳE&`}@aVTӪ+S%?+ogc" -EkR֧{*Z+Ƥc`e99w؍7qz̒3Cw|Ϊ$kRT-y*䭨 F=G~1FPf& >jhc{q.V>y5 _PшKHbz zz쫱T/`Zj NaxDvduV?͒'KmrW:a)NzK8Joӷw J|Ҷ,&O<;9я7߄d6_>Q;z}Vhn>U<>u_cy F^}.뾤;Wg=Lr(D) ƹ7e.ts#]CtOsiBZY0khy>#Sc)9yNYqnL־[,VbvQ#@7!YG&iOXcR}D< 3%:^b˓('ԇuBk)Zֿ&Awyl:NI7:p Iv6ad,%83]m |h|-v\Abg-n{3xOuqGgq~L5|՗1, I$0cڏH8zLhqavٍD7SfaDq?濢?cs/Èn5M6Faab13$"UWHs[iGZ_c> l)+nY+n^ާ$l8^~-9}. -18v1wGq$Yv{ٚ1yρ",[.苺N =h@T^#;F:hѱ;#xMhr V޼s>567~4׻,d11؅qK[, Emf}q00{݀Ӳ漍X>woaw#4ô9ɻg?@;7E ;m՗(&-l~m,Y)tosGD@Ǐ炋џ*~G}qӎ OЭ[-Y.a?(}_;NKvy|fn_?FfaBu0i+^W0憇3v+U\0# Da">ƒ^N0E>D 6{W U80}tN+1(Y",r>_ŇX"  ⢏v煲%dhD`! 0s  uɃDRqSTlB,o ]a#?06etM%?Gi 5캾r),Zef-- (Q\ r6hU2.X#LfH$!O 2D@" nZmˌK۲HĶNY yӱ }I@u=eLD xԅmG!%D@" H$D "(2D@" H$D@" H$D@" H$(" QSH$D@" H$D@" H$D 2"2dlD@" H$D@" H$D@" HT\DLIJ" H$D@" H$D@" H$%D@" H$D@" H$D@" "RqE0%)D@" H$D@" H$D@" H"C@*."OƖH$D@" H$D@" H$D G$%\0{|HO]cCxcp| p>9#{^,2^$ \x$j3 )|f\.i'/+Fsi]z yђ)n3./Ke46؋Q +62su]P$D@" H$5qq L`dhC1sF`7ffnހMp 38Tw`}Ka!mX5wdpu&EẄ㻑$qn8=6a;Cr GOc7rTAG~%aeO?y~aT#ν%.4A)ȉ<3#I (=҆1WXVJBFH$D@" H$pѢw@ s`Ed .]$|65%`y=>8T.|-1yЊL&I7#;=5d$b^!s31\0M;bb`-Z97|$dl>[׬)u~m3o?;o!Sܦked9'~pj jJ BCb.H$D@" Hu_KXr >Sjԁ IHF D^Qiaɳd _}ν-55G֣eR {"e8KR#{PGm8凎y\eݩ'b-h9qƑ::A1D{QqVQߊ*v%4FDJaQ2if} v$Յ+یz\9j]dP" H$D@" \H5PfZ}{̔IݴJ; ~G1yW?L@&=mp nH%"3;O6UK*9}.QQG|JN&&fX`#:Iܾ~Qm IqvQڛy;b)-,qMnN|b23acd}O?(GFi:#MV /H$D@" H$1d~s@YVH^ZL:}K]jNi1l,ޤZan|-9Xo!Ņ%;hEdDZm}U>{cNLj!n!r0Cæ9՟۲}}k]7C%D@" H$ /Pɏ"8111gyr»2hg\]ƍ&J~|o`ƥtbִ=hXML㍴Fvs/a4f TmBREZr^D(ma@ :.0 9#6 f/EE[9ޠYep9"?ͳA|M?>uo7SD@" H$DA@*.L i1R$H{*KQZZʆ.9#ȍK@JVJR*q1 iTx?M΋m(HHPAa5?I E1I<|S t5J GzQY$ǔ$%ġmмL]8ݴVii)+(E{y|gF<ؕVVR0h8=2 kDq)a_ڀ!O]tylryYR]8 *o.Zg` ŹqHQjRPPzf ̢Z߈!t4BqA.8"7ET\JNu UĥJN'e 9(2גCmEM[_^4!Ni#))I-648[xgxk>'6> zg˖kGd}hʋ@IDATku9t}KJ P;,w`)I'ihhi~u BO5Ze6vUJrx[G~8\z2^;qhic 47֏E|x?P୛AI2Po/Կ1ǂ"O4h3 .bsϢFU9PT+D@" H$D@"p- v#}(ƙ1-߉n ˆ~E~v_3k^zomY&XXc,0\@;GԂlo.p,Z18qk$:qKxN vGX. .?aj! ٷ!]9<02iۚndupe.S'fZ+uy)K8^Jkc~FOGF"V̀ط\o>MGhl=nv􌟀}.>( yH}GalJZh1+$RJ00wcO?<ɨ~'qamdWi#t}Ke6q1LGqa_\+=%+Ύwa/KjBčGxkgUbâ? :A /ҎXg_ S" H$D@"xI&'B[S1GLJ~-_?w3963g=G{zzֈ|og53xDoD9,Y<oIu-qU ()-m݇o_D1/`vYySx,gi.u[BݎK[uhOM}D Ԃ+[TйfW:B3킶W\IP8\n3BNKWbR%Yt[u#}#nEP l*=W7_W[+(7hN;7q'u64wM1cs8K@}/ByDmEتMNG1 :XK:|~7]Mu(T|P3 ߽}Swa~y&hwhsG'-e-Z[nu8ق snZ~QJQTawc9w"RpҮeXu>h=&4v>ƆS.*bԷF\CPFL=$\8)r/}>_?:>P-;?| :߳DRZk9׍ǺM1H'n"D@" H$DC%sR64oBSihhrBщ~sFZS(ݶ c&5Hyq@ް5t4o_c*N`~fXϙ#tOQyQ̷1KZ%<᯿Zd|C#Y1@܂kÙhM5YħJ8ga,2uGShXۣDbъDMd/xb4p^>v8T)6C~N4]pFjKeF Q̉^V}OųOصmMחR0Sq!YE[ .8}RӨeYϡ^ԩ*jUJMPWW˴c}Yh$=ѫ-NzS؁QSv6ǎǪ\12]JKJ>sd?N:_XZAӭBGAE5$f)Hx1֜AѝHW7bAMv*LX{k=^،~;a᪀%ξD7|F9ʬ%f8n4dO86e~͟w_Qy>ghդeXݎW6˃D FGF0Bflo,]"M0G:c elKBuGOW._(~-5n[}k2Seսڅݭ/kG (,a]cJ,}K)7u`Ǫ~!S[Ur>dTyIuUq 4`ÚÅW,j=&aθvgHy ;-Q" H$D@"%nHOOxl;a-X\?HSQih%0'ՂO~,OI\E'Nh/ ڏX(Kp$5*w-_}w#xP=_%j![KぃxC;: A)@UlWz~EJugþ$2Sf)N& #+ YdJEX;N>oyQPR&ג|ؿuT< {RpGS?f0Վ~?;T*2W}k;^f^|SZR0&N c]2,ؚo DìVV[$^ !t;W=!a:}Q,&io}2532jU=9݀8j߄l}Y>D@" H$#L)zjr0;{wwz~"E6 HżCLG3j&b}iGF166sm(JU>F"o5qYbd-eH+DGw(w-YjF(6=kn0=^~9UݭYSKhٽ:)Jw őq0 B<`h]IO7$ʂ،"ϢFY?us}i^{YOuR-v>vԖS8=K<߮bjNJGɩδ1#F '$<"pxӢ(G}YCt_JHx+ q_o斃SWp:$2g`٘;/Y1. ӵ%Pz>1b(@F>}dfHMGow= /_laq$vk۱q6!軗2.|_f HHHHH#ĸ @yK_(=;}h8&5z4|q|2heݱW|W<+Z m/W~[&u #Mk# eAn -S6 nFrOUYpbe3C$@$@$@$@$pH 8M k?%w!vӡ$_p\'-lrs{y K/v's_o'oc#hӇ$ G`Tָf-ƷNߋ3SƂ^}:>U6籯`E*!.A ?!JSC$@$@$@$@$@H`_&qVxU;VvF[K;ifڽkfW^5WͬvHE=7XfE$@$@$@$@$@$@$@$@$@N^ӑ-ƺЇZĬvTsM/۪}\~otJ'BמG>R5|=WڽM#kg^˪W2?ns^$@$@$@$@$@$@$@$@$@$@$@$pH H\`9           H\H`DHHHHHHHHHHHp2@$@$@$@$@$@$@$@$@$@$@$2p2Y peHHHHHHHHHHH eLL^/FE8i`<$#- w㕮^ {&|#Ügy3Q4  /#](*ȍY󢿷gn|+L1+D4;-5!}QQȘƋGົcۏ/v+ #7g,K$SmMxa?֓MՆ>`~mBNj9d+$1'YϘ#NFńRǕ9ki<:ԏ+]eb֬YJ6x-xkq0|hJKE-e y}mط{u/?1u@w8ue[ldgeamK %KLm0 ?6mj ^njwZ/(X ށ>\:lF4Cc#Quw:/_ƯxCE/|k/DcEO]BO. :Dْ&J'{>譜W_ގ lli q} 'aś;^_0(ڼ[Aa|H̋s,CH˜\2gtWnb>@%ńl>G'~>5[qYY%XٻQbI|"!m2g9c׉2,tM 'YQ|[1 ,_w.xdlO=X8X^y2'CnS /c`Ꝩ UyX@pv*b<lt[SWufcَ](BsQ}5RN}#?i#/E:Nq3#I\(8){X(0ۉp_ !gomE8ƣа6HѯTgpSF1S[}8l9Mov 2-ZRKM۲ ڜleaY0ݹH\<lx (VxbݰG_8xv7:f|4~UsmzRώX0΋J׶[>-XIЬ`%ڷ . =7=b\;ux̓#cN.3\xR4d)*?َ{6ˣ"]8>o_m 7K;p%H\ĄcCS@F.J֮55:M{T@n4_99FrUq׍šS{O0 z/~x\DRهڠ݈|I>C2cvF:!\MWf73ß2nԜ֯t'] 6sRإ { }89ZfAλk2ij1yBs3$Х|l=Z/U -\ϧ^"K&N,,K_܁=^iL&[{7n܊2U-{-SU7]=Vwmf)_WqZ:vzs4dbIZzLl۶l쎕ps06:b)-XOށ8]PysrsŇa "^ Jh߈FanwC`TMkW`ib&)b{Ƴғ!]F VRPmk\.4`VT,P-(E{ئ[D^DzQ<+;XtK+-Vȣ~oP}vOiD۫(JҲ3\ CXSۊeіœL,VZ%8:TѐUJqnΞ?^dz&a>iyxt/ֽ$.-W7-t2l\ܢo`GNcxx$89E~U2gdw'#u+c Ր4ێs56mE3z̋aEhgƳSa2}7ve.8(Uʅ;oMJsFS˃o;WyXp3|#{m3zbaGLJ+pq$̑}ǂOkcbl  u4|OUل!㘚G1>',h㏡qp'ixOO_nׁu b]cGgڷ$2lQ `RjymjS_dgj]KD!j=L8%I$lZc@xNo3bp124e5ȳ8Za2mƮ#ݧcs/ܜ3 ߳#ѳ>}m8T21k,dggb 0Pk3Hwfe#}Z 7E(gs!tK^1CXT#3})*ovpOp!n0tL[|w􏢫l;L+)ۏp>Υ{WUW.ßD݋pqHܭĽgvdJpaO|%=yؚĹj}OAo[*-EzFf48mJn٦l= Vm޼ ]<`YL/ACPP}fvdCKz'!T3mkhM>u f].hގD%6hGxQکw=bG{ar̟KH6ZphWJ.ŴiӰT;l}A͢M}lEEU6RP&s̏}b?ÿJqlZ*3Np,,E=o Mva1OӰbķ6 q|G$Ү;חvR7};t]\Y}\pܱtO5Rf41W;/F7\kj5q9 CE},rzh_?/3b>Fqh#O7ZkQ j[I$?vL}cMDljy#9i`^j7򢔏, ϭȲ$r%V@N=Uw4vm6w`~*c2e0ػ.0?mKEr5v ss Lt}K$ qj,?*# 8I!Y%3-"WIJNnRkJnaZѠ[jP9A5K栒'"ԭAq+eįjjP %N-N>)|O{Prk龍R>-gZ&8UB-=B+J>'TP_ P_AB!,z"B="Fl[=OĮA_>_մ_MGGiow 'k;juw"sQU]#;z_}q_}MW#3C73Rw.(~pa n5͕z(3wRA_mkUk&u-;|z<[-a]/wEO">s&WE+#խ Uq$e(ŵ>Q㺆{|"GeWz#.X/Ǐ]F43Օ;Prqkqi5Wz9r؎Ip`G Ga?jH4no'C]l5 J>Qmkx"[lWZ봴}窊Mx'ÝǕE_Zc{ *u\>p'jJZ_쪯Fi|ّk!<}5^]BO.+c{%z:V*'QTi=,7uVka-Fmםˍx8WDŽž+c2 AR8iMߕ+W8#=xUK_ ^*F.VKJ]42^~a=8Ҽ'xs- *s Jwiml"}RurcG714LPΕk~ϭ=I)atI>ʳzHа*"0)E@ڣ6F-avrĹ%gɶoj6޲ih]5_}hȓä_788~u5]~]W7nFGGMJ>}^#o\^ꗍJh%J٩JYJ٪JYJ٫JYJ٬JYJ٭~N()ӕ])㕲^)_)`)a)#b)3c)Cd)Se)cf)sB %eҚ|zKA%eRɷg yk L44 ]g TR>]Q7 >͢>,U~U#5j ShbشH I7|&WEғ>#1&GR(LK,E\r_uU~×NsVju,-KiWmWnY8%%_hQYA Νky態aIebpW;km>+U&YM*&v #xܾj(;w'P6jBF݂9 RMf_uy!*o^}1Qړ@LUveҘh8+0OaJ}.j}־XoW&*HLƢm[Tt[#; \վv-&[>%`O=nBhNp!uU.PTkk|nC(̍&rw)-!A7셉`OڍšV„h %@a|J J"/!eqٟ'FڑHL2za;= :^eiljZ;+cq_8Lm{*}Ǜ;Ha'tu1^×;x..K*k:.+mK  ~,R_g֭{ԶM=xTm%Sxr\ Tr{v:ԫ (]Rxtq=Mm hp杹5vt}26QfZ0y}c8/a2r5ޘpüQ";ϫ}헌FVn!B+z^ݙ@/7)B2#$mX[%wICXhRʪסGmK[6TeaI֗@RJiԁu:W\%v riDj(V`]q(.u9'[J: 1ʁKo2IVe2Fmk8;'窻lkecz٨&fǞ #cC8waKT_f1)@IDAT8' v2i1-HkODtWa,Uۑ` ;7r+z&VL;{Ou47Ѩ]6jr-"ިm|UG6|#D z_ƽw\&N-/*E`_iz GXSY=yqQ.mu3T3^Iv3XT-dVdyQ-S2nߢMԸisSfk؁2e~f3Yn2/$uj?Uy&TO4'N ˺QX&{$0"ɶo늃aN͵D4S.p!8.DGDž<*$]truGy7t :z% bj&!Q߶JQ6U U)K*3D8T-ԴH[C8kcC@RwܼbQbfb ˷'P ڍ㍢-\hBj} uoļ"Z63v5͕be6dn[5/#mד ۜnQF7JGhם QDzS׼QEV7Y)WV*+O1d`JWSSs[.Mov}Rx7KD EaƎ#m‘Ō W9W^~Ym$׶B.2&Q㦶j;7k\O/O?Ty&RO}B@P2֓´6!^;kllV6%$rK&LK}Kee1ɄmJwyF%Sؘ \; y/H@صw*䇇.\}g jQ$O[ӯ|e_~'?.waHk.Aҝk~KOfs\"sbu^Kyv})n._5#"F9VS\n;%m'"<$4ZaNƨ%%(-4eJd𯇍6c\iKxGRMM&yrԮcX>ky,6^]K?An 񁣣⿡u;JtlC;I._Jns. nYU'NsR~a۴!NO:ȒOU'U(ڎqẌ́acpTy^ix xP_:֍QgިMZBʱX)Q}kNh`#'pD pY%h~F츷վ8 )GѬ]xŷp31P/h7ߡ6?X_?^v#>m]6 l6{gnhMWI m4ƅŇQ0(oDyœeƁu8x;z A\joBGƵgն6'\;c]W .N؍w˃hKkߚ ܴ>یGb>)=bVvҽܬq>>ɩP*6icU!K6Ewcp\7ϲ_F_kWc&>,{xcܜ n]qRc7ͦY ~2uޑ $hfд>5ž=QIM5V sw&&|'.TYah"n||Q+|1࣑tK?D(SxX46wYl…kSWpW#נs#2Xy7 ;c *Kql.&QG"Z9;0ɉa/0?}r1VX #o-ZX_y+6A<~ oc׸܌faSk:nw>v~L] 1(,(+0b!mqϕM( MoO;xNNfֆYN*?/`ca21Yl"W1Z[Pxz[SqZуPQd4҄bdomqv?paQww`iG:Z ۽wϏតH[P%Apb֯6iSͰN⁷ sW ChnK?Y֌y_P[,k6)*ځ70/KՋ:3dNm i>ƛی%yg]Ti:6_M~ٜKU$Z ޙrJq~\{;ţݸ/pHÞ^{b;v=1w׏C,262}?w-Y^=LGmca{_="ulwig=ߙu ,m##`/.`g7BL,(mFُhQI}ˎ2d-2r)jcg|9꩘GQz =QXy~iLHn~21L>t$QW$vz{:ʧoGOs {pam[ $Jݷc[?ӚklcS,Qzi]dYK!/?Qw7>iR`]U=/{`At[h2WXNad2Ν1)"8ԡ}F-Z(3yU'n5N([[vP{j[F9c65IyD\@&qDA@8&%nR34^ğܡ\x(rU &Iy67d.S*q/gb1jOO=ǥlU2>ܴMvȟ㹂ii ڏz izژIݒ;t,nҲrbvF#0֛߂;Q{-Xs1z@nRsQMȧ{?T@0G4X5wYOMW|y(B[j|Nt'Eaw;zlnY:f/kz] X 1ү7G -=w1/pްko¨+ޮ#lB]Tͅ!hc7Т->b:7Yɱf?;.sfA%m!rGVbQ?;= #kGjWJJ D׬ja&ʏ捋Nj=A7aX3y1*>#u'9ܾ yGz_oyr<>)mz*'8 H42x(L'gcоgImY?WkW{5K$.\I0]C;>WF1&isQ:v{z겖7_{oyCzLSFB_\{axDc[OZipzؤ(wc8>WO z\ֱbE=m͎C 㑹F'9IijP!EWKN_0.5v4%b2y7sܬw, bxy.R<8qB44<^5ް.C&()5I|6-zu-ׇ>!liúipvjF.~ZO=k.]O`ݬZT19 JgaQ6Gtu6>1-3ܒGHb":}.ص˶3@zo`~E-m2104 8 kYŽ^ԑH.XWQ*ֱURm]崯ZNc:Z [8!/DD#!]uhЅmG({/Pٽ7O7`o>x=-KFm؂mQoNRGkmF]OcF޷I|? NwW.%tݰSށ]pNt]XVYqime"V|c3'8 8Nh8qU}7#o/N'3g:XO6؍TQ'Kn|؋m[c׮LԿ:Zd-5;;݇ű8:;-{)_6 ^s3b?Z-?p{8$qp~NWM^cnwm'bl_I{q<.\`Yp_k6B%9'9ґhPoxdx3$ֱb'--dẻ(ɜ/#ODrS|xH=Z~Y8t]bn.YbX4Vm_Sd&čݱ}p3x͍H^z85pwuL LN>_|>fO|Z%ETaq*)V"7kJ4%5fGGJncB,;[J6%X[WJ8>T_L:_B..N>)H/P\*ԧP˄*rjPJV uP B$ԃBZ'CB}YB}EzDBm[=OV'ť\խ&o;j=;wMY"7N +qr牑b%z8=uk\ܾAs\Ku?"sz},GͶj?||+Z(jS|k㊳ U %[l 1.խW-=MUݘPqHy an=5mv"0C"a@yd _Θ>uWMannOt>ŵu\(gۨQ-wA2ڈs1CQ9.WMyAxM텭o񕻐5|445WEok[;}K}Za !ZZbMʸZR,LcxRc'oO,]m2L?!-yNmNv$v݁#0XMSeYކC87\ەhI^[nM徸3bΉMzqu/tZy"WCƬj|YH!>؜ .]JEVQ}>n|K'6ܚ򾸪׬ո#ryV벵:?7kcٳ'Fu8Yz:Rk_WYfRI~hZyXNR.(Mhfݾ_׾A8յk|^wu]ݸq7225{ϧ*\ړ{o``wUlTGE-TN URLUVUZU^ VbLVfVjVn sBIJJJK KKK%K-K5K=*O()^ʬo *)˖2mM=[[Lg ǥA%e<=S襒銺I5%eiaq*U/ӬJy$Ǽ>hgiv͔e۸ҳlY.n*ݍd5)Bst˶ U/ۀ.l,-aI^u~HAעsV^0f3=]+Z5;vsWlvԔv9;e[\9Ub(UKhٽrN^ۨ*Gqd;v.[Ikn$ލ+M(/Oe u>"EyzH 9InӍvBy=>_Ή˃㭗QQi{"X}RͦiKcǴ+eV-Bv~.ͺPju^Z{=jrr\ndbF#w9WZaţ3 P94הFA]sQV472]Z}T)nCc'xZhMgK|=nH]w a-F) eVc3smeȆ`yM</%QZj4^j8Nv剒[w<>FMճ.T2NYm26X>2^Z9W:{qf;;hykMmdƎ oBj=5FaDn1Ug&d[״HYk„g:>^h-z* 4Ո.Ԝ<l$=T|;vT:j2yf}Kb[&𪝺qq9ϷʀԐ $A`\H&0~XWXڽMo}xUi43^U53sMfV;}$"M7ֈMkGecKc ֵBв$*$C}yM\R3gbȝcߟ#c:̙wF߁1 3bdz0:ԏޞ7kb$3f[bNNtn}ӯ⎂qՐ8[ob7Dz;ͱ,G2q1C;Cb}뭸%7ON47*^}U̺u~/!. Dyo)ř~p1qqGYWEe͊L@W .b=FZ"1aGRLco/^yM 7:v| s^X4 C[ٯٳ1w^.ld}4<@ݺYǫ;PvIu<6 ӵ%]SǝpO`_nGqԿ-1h}X]||L$lnQ}hS䌋dNm~়Ÿm؉7Bh^!A5HQ\E_!l=ZO2Jm>)mtݝшߊ &K[> >Nxn3\[#Vu2*?)BD=Gf }DAfƭn dK;:NE+E oA1N`paZx$ _*\fj/ҽN{^}_i_z^ڱ{…" !Vg,Z_ߥ8!1g$@Sdn&sܧzr.}C_3\HlFufh!Vm[ǔ dz^Ӱ9П$Č^ LR.!L3g*ˢEv4עgme4I3N?u&8_t}`DyUE*sT "e  ֋ӻnipX]vl䙀 +>M渏k&OO9O[K~wg7H~m^~eopXI|Go^n#5b٦%q7VvB{)6zjHƃȵ>s-TLn^m+(!;`١e+zYX{ OIMjID ܞд7h<+%f,ޒ df:w=X={pK5 |wA:dW^zԵ׽]h{ۊys>4v Ń\XH.Eue6ԝ( K?m+$y=;\#oT@ܜȳb8memը\> W.XLŬfRďR #,t||3~籯`E,DF$0&&s4>&4%OȟU?ν˃gϻwGX$;FWR9p\jk9ֹ=ؼnE8zE$0 )Ol*#R6 bNDn'o-ͦD9gqKC'z)cH`ǹ~ZU}<[3_\3^>jfGOڏs HHHHHHHHH~qmǸRis쇻WizW.^vY L r?/           H \Hl`$HHHHHHHHHHH$.\ .\LV0"$@$@$@$@$@$@$@$@$@$@$@\`           H\H`DHHHHHHHHHHHp2@$@$@$@$@$@$@$@$@$@$@$2p2Y peHHHHHHHHHHH ep"e!           @Ed#B$@$@$@$@$@$@$@$@$@$@$            ! FHHHHHHHHHHH ,$@$@$@$@$@$@$@$@$@$@$@)C ) .XHHHHHHHHHHHR.R&+           .\ .\LV0"$@$@$@$@$@$@$@$@$@$@$@\`           H\H`DHHHHHHHHHHHp2@$@$@$@$@$@$@$@$@$@$@$2p2Y peHHHHHHHHHHH ep"e!           @Ed#B$@$@$@$@$@$@$@$@$@$@$            ! FHHHHHHHHHHH ,$@$@$@$@$@$@$@$@$@$@$@)C ) .XHHHHHHHHHHHR.R&+           .\ .\LV0"$@$@$@$@$@$@$@$@$@$@$@\`           H\H`DHHHHHHHHHHHp2@$@$@$@$@$@$@$@$@$@$@$2p2Y peHHHHHHHHHHH ep"e!          H#o姿ƍ8"?wbea3vɂn~S'bHI׋pn2P5@+.@ xۃ7>VKr͏']Wy XKy~xQe.Gn+A#H$@$@$@$@$@$ j %=!x{ a̜u`M^y ִWG~ށoͿ@W1>4d}_loKC1u-՗H'|T{ zZ&Ie|ik x sі>b j o1iӨ;p-U^EVrMfOa}ЛWcw7Ҧ~$\{j: 9_+m ;Q!̙-+?U; WVޏOޣ $(pAZJmQ07Nj:؂d$dɨX0 f#@-ϥ<,&a8r-"Sv$WG/`חaOJTyŅ}Xagf㩚GD=Q-~񻀧wWE n6wn (mFUYIR eM$\hqJo'.q HHHHHH&(Qj SL@Y\e<"("B^n 2$ ǗoML u⁹X"oV`jblYS\;?dGs|ܸI]k6 w&mǷo=K9Sl!ɑ6{{`<}q@^F|_;5&#<}!q/fARg[={ܺ jpvLC̸ azq;X0;bƒ9wWLŔ9HHHHHHR.R-G#> l׃GE}iCxJq0vM0<XGE!",i.f^yn߳q޷q:lyX8'PZBqRJZMBEyk˳ŀ;-3oAqW%O?MQy<*j6LO7SR$DYEڵFtF#.&t6-ZPcgN6-Zk2Dۄgڂ u]7h/=fwi2k6l^i܁ye[?OJCVN.*mͼ+alܼHHHHHHHƏ@DQE!?c=,u1d>f{Z[_x;_E3WoN{O@tӴ9Bj-\j8X;Dy #UXCQMF@5CT+E:!a'@!imѲIDKXP^̽/^E w=o'/of;EPݧpi^,t9_kbWnzޢE iQFD>GL  >䴇o20t}$Hq$= Mԋ8B3+^\7:a?FI_;ewB]?V8v`7hSxretϛ -Zxy!wɏːw2O-ߡ*oD}E ixcXOc/tЈr zp {%$4nA76TyQ?m}J      p1))">6=#?/!>^OX[̚PqqycE铘+}q!Eabs6oơ3~޾6*['-?K{&(Șa@t$򩕾 ks ҃Μ CՂCPt)Mⷤd(e(eڈjo!l_7Ho[*-5⑝-ʼlj.áI7[Y9-4l~3!'x3څ'!p6>i̞@~g#]df=&|yr֕``>mR۲ S=!eWšCh_!H-lqٴin"}b?)ű}k<#(y?EsBƻ"{F~ՠ;mKh7 V~w(ʠ* s~??*]#*vgg؎^lL՝^fertsUhҼ!      p #ғN^9:OPAŷBk-8pu`8~ftu7GX#Qq̉:~8x+'^3Oٍxk[Ďv]8>  ~bhg1\pMDEnHř`vH T90W8Q064^ttȳ`ҍxM0x-8v,UD9Z.z4;ԅ$$Bˤu}^UP\mPgwEa?R^Cp yh9x8pzg~*L@h Ġ)deM *YIZT6&ed]ҕBD٦B66v4 nH50TTceA;Μ{Ͻ̟; >xs{?s9ㆍ1+I?ޤumo|Ƣڭ)g]Px<+ߖ/0&XxFW[t?T}tˡ{ gV2QUw/ܴpec._5ڹgEYtR!5#jF|&ܣ俛> <#-Ϟ(HR1A@̾;fNlnhl}|`_4:%1xy̾kC|ˋcN!j%;lybqtm.6'c_::#~.\>d$ -wM[$2, {\u %z2i{bӝd;'6<|L!5&N(>PT.K _cwuhܻH/3KE۳zj]; g-HlqqKp1.{1486.Ha\<9µie)^^+>:5{U|qn˿v?+0Oouؓ.j\q P @8^Ǜ8R@sŴ 4hxhpB+?ɯ ( 0DŽ 2'W3WaCcS㪫GX/pn]}=je R~ 3to|z{:zh~6կRgQ&;'M^z7'z7 ߵY ˳W&=9J&`xejfz8btrǷP)FD_Ht w= JƛߞϋӲM[;ۑ$$m Y6⁓\.dAIMGƎUώ$2\A9I[Ioygo k`lܯngG4)Vf^öj5ISC㝗f; |Wgz%@ @}M@ࢯѓ:AK3*~OIZoo>{OqߋO]0cGen+b=)*$lz.|ƹq)t'bK޼14fѹ%.-nmf@znձ1U(,//*m {x; +ΌiuNF=ٴvbQ|3eֹYl @ @@ \lhvx}jjݨ ס'D>oz~&Źm$- L0&*W^PtAif w{3fXV8{QVi9'+s)PioZo?k  @H@"&Z8ܙZoƎxa,*oJkNC֧dA♧ynEf!Bg]+ gLx6^F_/]ܫԤxEf$ش.šu7o?>P5'K#f?'Icޣ̢Y8[(V\q,}F|W q}7]\zɞ_>+ݙ=Rqm/]7o- |G_;O$zwR[İZFm @ @nF%;(^_׃:z8Y 5|oCrzd%=E-Wmv[Bہ1ڈu?|k\*.}\>04J76Ń[_beqCv`bF!cHGXv@iܲbc=2U6}S+|ƺPYk;+4~X=u{Zj^qt裱ko"f;*L2kֵ8lcf1?w>Sgb t< @mxŠLV5bzlOsܓԖ7Ž ;ix[Sy[q%1lزxbIzސ=68NJRɀb|C#v>CTrx@oK/cEPGcƵm/ԯ Q \4λ3k1u¬B^|o,+޻X({ϦR´nK^U8Z!ɈemDnpѿ cͅkMYK~2绱xB߷oV\|6h2 K zJKC% rǻ.J|C+n0?-=K[h}{twci!`Z|\߿8btLG~ZkG˲Lf/0>:٘y$k;;ފ; ψg^@ @tQ;;/oks ?_ۍ1_ù'Gcq3zT3nzGq#~kKܨb?>qWiNJcɷX*ii΍"4hP)xoG+,`|΅ј<zҙϟO\We#"V5Ί|%/| uWah4Ytر$Xs{5WྡྷR:<(&6\Ϙbe䓈_=|m,٦ݙ|96._iueL~۸8MÒ1?^b1$mnB̺5z7ο8yyU||܁ʍ[QzmnOucDeyWqQZ2;_ly_x*5[aGDF}^.=lA|C9my=[cĖـq -le|I:̜$;뒁T]yman]:W9;;Oi\88vX; qԦFpQ;"@ @Sg"tMƟ^VZߴdsɹKu҇o4S_GqSgњ 㳹(CMX%^ʖq~u+-5ƼYه'L@+w(;޼$f/%)]Q̈Hvq_|3o<7noy޿|~C,^Q}1?2`5at㦆%1+ƕ%3қ㞆lZgZ{fuqc~H7b~E,}d_LJm$yqCI\}pEW%{rt%i3-6dkuQ|F!xM/-bl8\X5V=P,j8>`ovdg_ƺ?oS\{ךLF.~'6U|eRzy}âx1wqh>FPIJV6*l0<˸B;}73*_~6cOg':>HpZ<⫏ 7 ֽ=Z*n}سJ]*6?!wcѪl+j<({tiu?[}L~EYS:#U?- rg6S %w{W?jب%\Rg?*y}Zz<͸>Ji>|ig~ GZ)F0gL&IX!23?t~(X(MbßR<|x>y?_WMYY}V {㙟?$~zyV$ӒWL\<2$C>žxlsqdiƳύqZsmo^~q<1Eߟ]vs1bro4,zN^x܁Hr$ן\pn<=;^>Ж(Dӣ+y׃_p:n]>[n5#2ɻ]=`x2;ƑAc[3~JyxE\}ټBL$dw\=$Dw @w'c'7\u{]~0=f??&o1GI'[mmϥmeܹ|v[~'tL1]xq{zOc|i1Q83 浻AKդUMtӉߒKR_~ܞd >hcZBCvA|#Ɋrm4p(>ai \\q"xݙi"6m5j6Çrv`MD҇-j @3~vt]|$Y7y :|%XDuH>߲fCb 4Ūcպۢ4h| 1~ҏ_k`b'47O}^\{ƒBIqߎ ,X|B֋8aVɺNi3o(]+$=gK @@DXNr#UϷy>ko<<;ӣ9oJ䞱:sb$MK>L4Z[dw-@Cdمw/^mn\qǢY2G~G~ߏ홉 ꓀ߝ-f_>JևcFHVxlp+{KH>{Ѫo͎ ִq @8!bsQsn,u_Wx%'O n8Y#xRw[:eɫjN6^yC"_vmcb;-㑟'vɵ]:#Ź>,tR1SgƊ[?3fwshSKcQo.S/qgv2`x0X5Z$.m=!.!7.Zqbw't+U  @ @@8wع^vn?Iv<=ۦl~8wFDh?=%}l{<{a/wwzBݕ4N4oDw+d!£#IƝ2  @ŹKN>h~ˏnJ^[urO?~Ng-Ν @-CGԫnU* WϬނUq̉bD  @ @rC @ @  A @ @.| @ @ @[a  @ @ @ @ @ P35s+  @ @ @ @ @jF@fn @ @ @Ͼx`&'ƎZAͶ6??V'Ąc @ @茀Egbݦ=l=GbX {ǻkw]:>>̘_.}$/{xص;7/w88vPkcu7ƻi`sEؑ9V8w-;N @ @ \ӷOyE|yMM|6Rw\n9Z B,}pxCg81vium5brƕ(^Xh\hM3 SGqQ˶(7O @ @N\t/U=kmYТ>Y|c xxzuKj>xzܼ8&Uǚ-Oxd_|hj6ˡO[P|r%Zqԩu-#ǷSb#ꏶDZKfߜH|\xwƥ6 5(qLK @ @ h{cݵ25wg s7.364?>a|~7.44p`'Ju|1D/_޲ .zbǡO2|B_cǩ꒟©#ӑ\K @ @x]窫~mm9[(qNaoI;-=Q0'iO}[qG @ @T'Sڞ/\E!뢝:btکөSuc ͯߺ/>0ix\fh i{jLu1už7kN쩾Z @ @I-=7/kEAAV_'U @ @ @ ^Ǡ d_?ht[E}b1ocm\q˳śi_K @ @=' ps5VhdNl.Zɾ3hԥ1sǪ҉5+e(=o @ @U@[9kA׭ȏoےC#Ynw>2qZW2qh; @ @ s=g[-׍VS;eC nz|" |G4yBj1qZ <0L @ @=) pѓ5x' #񕇣W@[WcEcҝ׾>zqEkc Ymس%Vmgx|Scp]a,~{2 @ @E?iʆxRS^G}"~kLh=X?2rqhO|gO*IH8Ƨ +;%MOԴ7{xnO[Y&Έ#fěft_9lXygbw[.D @ @[~Yݍڡ4ď K>o(Tߥ#O~mY|qȹcub!oy{RY׷{v}{ö3>Ov>6VsG] H?p4^޹>ld:QaO<4c~% @ @ O?Ӯw'Ws-;8?vq҇Swç"nOߧ[(M8mqc\vηせ2яZv_W3;a^s7Ś-Aܱ֚GϹ‘ y<3qЋ#r\%@ @ @@quL&}[r瓽y(>73`]qq^o|CKqcc~)V-jn߸1rqC8FnW{3j{{gؕkbԱ'Ғk @ @ Ч~ܧi2  wm6CFĀ_'ygO 39F mq#:^9N?;:L iwnK#^</*:xZ6rd>zTkNl1Wǧ}~O<]qGSc. g\cƔft[ɢnde kX=sҙ^ @ @@OM\qbrπqr1b䧕s||Gۗ%}Ln L^fސ9H @ @^y׷:#Mƨy_]u"C37Ƕǒd̮" @ @ʼn۹G^#~ś$Хőxry㋯kt @ @*Jtλ[oC:Xx%tqM,s.h`1 @ @YYkZ3/;/=Ic o#. 6 @ @W@Ezj @ @肀.๔s΅A @ @ 5A @ @tqJ?x3_bE?0m @ @t @ @ ]sigqFE-/T;/R{v7l# ! @ @ @D@E  @ @ @2.^pa~o.]ߞwyݻ5k䷽?W^ye?Hٶm[s1 @ @z~ @ @!}fT5 -[t-#F/ZvcٲeK+&W1u5kVc淩K~ @ @ Џd\o @ @ @d\#YreLׂصkW޶qhѢN =ͬH3Pҋ̔kצl  @ @ /d\n @ @ @6d\}ZbE~3gsioiE{u#@ @ @d\Tn& @ @ 2.z5{ܹsAŔ)SԼL @ @" Vq @ @ @!—[֮][ޕW^Ywmۖ{T @ @5) &oA @ @ @) Kڞ4iR~oIf͚>'@ @ @@M ȸbP @ @ @ ȸfk)ݻ38#=dK @ @( 15E @ @tM@E\"m۶)St~}5'@ @ @ȸ;L @ @ @@qoamL ]"ɓbئ>}zI @ @ @Vd\1. @ @ d\ÛS^~}I}m-[tҒy!@ @ @qѽZ#@ @ @ x.- k@G&Mv۶my;O$ @ @ P2.j @ @2.M)i}-#auΝow߾}myɓ̕ӧ̙ @ @zg͋ @ @BҐ '(9؋wL4㡻bŊjꤴ:,]4_z߯~oIA  @ @'$ \D @ @􄀌PGm_d]tQ~oٺuk~ }>':+2i=Sݝrs @ @}G@E߹fB @ @z^ ;tt}u k84f`ߖ @ @]qUA @ @ @& (WC/R~6)Sbަ:3z<{&cǎ7ͧG @ @  @ @ @fd\̭])_ tۻfshYáԆK= @ @_@Ej @ @8A'/۲eK A׶ؽ{w~<&M*_gwM>… Oװ9rd~?<ٶm[~ѢE3+W,.]4<7m_O]`Av @ @2.=6C @ @ kd\[U[M:HG Κ5+_vu<:,8u͌H3-̈i&K[.iE[*vSk[̙3&GOI; @ @ 6$ @ @2.z}Q)_>i}CI35W~z)S*zrJzرc'… ץ]w].3gl^iVFFNFFyos'  @ @2.m4  @ @ 7d\xf%QaP~ӿOHغuk+Wi&A_w4L>?ьBo||HNL\:N?Zi? @ @Hd\ @ @ @@d\Tlٲd'{m&Ooӌz%ZI3ҵZҫ鶣:N34J3-IJM @ @ wd\{i& @ @ @ ȸN HH{2eJZ/̐f\k9tAPvc]tQX"<3cڵ%Sxz?XlY]%@ @ @ȸ?L  @ @ @@ ȸ[T[\2ӧWkgر%]VvL2ZWJ3 y&YrePz>+hIg͚f͚6xY~}zi۴t| @ @ Чd\kr @ @ @w ȸ]j}饗}t Z~if@AQxҌZ t'ZoÆ Ko6][__m)p’zNZ'iEAf`i{ƍ˷- @ @+ {3'@ @ @5' nIm|mt t[+N3@Ҍtfb5t͆KUOO[ :Wi{ ,+  @ @2.  @ @ @@- ȸQcI3! ~l/袒"e\;vlv @ @-7?@IDAT @ ȸ8z#@ @ @qSEt bMm3A֯_ߜ9sZݻeZ  @ @NNC @ @ @-m8^"2eJZgO-w`|Z )} @ @u} @ @E2.zͪPӵ 1L4)-6]bڵKmzܹ֭sC @ @ PEU5 @ @ P* ^@i&CY۽袋cJ3.~ǟqbŊ24cʕ%mٲ%t6pI_|#G ,o @ @}M@E_C @ @z^|NӌZ_"gyfEO3׼Hmߒ%KMi?i57̊q叧M @ @ @ȸ+w< @ @ @@qnbON!]{!#Hku[~PL4$y-j]v叧k[̙3^Q>Jv @ @ d\h  @ @ @ȸ+w摮 62M3~4f`̚5xOgכ9sf%  @ @ 'd\jR @ @ @w ȸ:]s!\8iwSGSLɷfI30VXM=LyEyt|Z @ @ @ȸ/w<  @ @ @@/q nR5f}_iWm'O\2t-U)wh ^z)?ڎ288%] @ @ @K2.b @ @ @;d\tfj+]"RGiZۖ;]CxO{ڵ.~ӌ YlY9sPO @ @ ȸ*  @ @ @rA`رc۶2 h!:ݻwӧOO6ͨ5kV5k3goS7Hmw @ @]@EoO @ @>t3s* ,fVDL"ͰH3(5+ +W-\07n\ЬmQa @ @>, \S#@ @ @M@Eoc=<4#!fܹiWo5:ҌVDOYb_lik~ @ @ @RJG @ @'55,vU2+V5 Ǝ[rL>ݸ  @ @ Яd\m @ @ @d\m۶6[nm^o=f:&@ @ @@_q @ @ @^$ ݬjE]lY-[6loa  @ @8y2.N @ @ @.:r @ @8y^ukPK. @ @ ȸj( @ @ @U*  @ @ @EVC @ @EUuN @ @d. @ @ @@U.ʯs @ @ @ + pP&@ @ @* pQU~ @ @ @Y2 @ @ PU @ @ \d5  @ @ @ \T_ @ @ @@V@"L @ @TU@ࢪ:'@ @ @Y e @ @ @U9 @ @ j( @ @ @U*  @ @ @EVC @ @EUuN @ @d. @ @ @@U.ʯs @ @ @ + pP&@ @ @* pQU~ @ @ @Y2 @ @ PU @ @ \d5  @ @ @ \T_ @ @ @@V@"L @ @TU@ࢪ:'@ @ @Y e @ @ @U9 @ @ j( @ @ @U*  @ @ @EVC @ @EUuN @ @d. @ @ @@U.ʯs @ @ @ + pP&@ @ @* pQU~ @ @ @Y2 @ @ PU @ @ \d5  @ @ @ \T_ @ @ @@V@"L @ @TU@ࢪ:'@ @ @Y e @ @ @U9 @ @ j( @ @ @U*  @ @ @EVC @ @EUuN @ @d. @ @ @@U.ʯs @ @ @ + pP&@ @ @* pQU~ @ @ @Y2 @ @ PU @ @ \d5  @ @ @ \T_ @ @ @@V@"L @ @TU@ࢪ:'@ @ @Y e @ @ @U9 @ @ j( @ @ @U*  @ @ @EVC @ @EUuN @ @d. @ @ @@U.ʯs @ @ @ + pP&@ @ @* pQU~ @ @ @Y2 @ @ PU @ @ \d5  @ @ @ \T_ @ @ @@V@"L @ @TU`@U{98|l/pן51i̐ jUصxrkmU(4-q7_ @ @:%jJ=ǁgȈ7ƨ*|j5=%ꗾ>/~C/Ůǿ>(>2=ɜOmp|{Nc~c߉TU @ @8ޤiz:?TL^ j+w=~䮸X|΃Gϵ[:olv$@ @ @@?mg{4؎:mwL8Ե-k횒E겿C]jJx|oxj @ @ @@٧mro ԝ_WEC4_$[fy=4l^U˟auuQI.}S'Fwk\;/0`P h.Fw؂  @ @ P@b+X*pj9fTYxGC5:FbօkR=[Q5>#@ @ @@x]tAKiHZ455Љ6QA/U{.WGwuZΡy^U>r @ @aˍ7ѹ_N~OǶߊkg1lbĈe1dF)A|ftu1&w2&N,5jd` @ @- 8t^,ɳFc;ߊm&x1\`ɼ~Srw/7AK3enx7+י>Iu:Y/ʜx+ChrnPs_&U2; @ @/N<ѽӛw &.Xq{ w ]Xܿgǂ;qH @ @Ź{4*Hok+G{D'.Ϫ_&i+$Ɖȉc BlF1 +d"(L[B`b2!!d+n)?G}{ꜺT=[Z~k>췫甀$  H@$  H@$p>ys|m?O'wgOǟ_w?w'[_Iwp$  H@$  H@$pꮔ=&ЯpVMe?Zҳ0KПַ~qޖ__Ŝo}_wb, H@$  H@$: p]OEmUK?v;D'ow?#9>$  H@$  H@$p3꾙;C\5cED@ln?q؋H|( H@$  H@$  H`y=j@7ܭm57ͯyN g=/ g~tX_K~߸G)Ao}iS$  H@$  H@;t|NpD2Y5Z>+78cߟ<|+||obo~+w?s_}w//?w}.O6֘$  H@$  H@MHgdnݱ.z]KWSڛ\أ |> 綜l}sdΕg_˿}[w?gv»߿lG{%  H@$  H@$ s;9[;ZlfZέU=O^_]F?Vʹ~WW_͟;e|ݿ3sw?ݏ?nn# H@$  H@$  #o}uGz:랗l~iuUݥϻ;3]\ij??j/oگ|Γ$  H@$  H@$pnH;_q'o~iW4>[)ؗm}y־So?/|;~~$  H@$  H@$@įʯu7zW;}|y_l%~N;:s>䓧?Gkp[4U:19: ~o)V,2OKן#_җOOȏ~Fp$  H@$  H@$ԟߴi?￾qŋB_qSy{[mc9O"j+}ѻy3VC%xP/j=WZ%k6_=sg޷b}Oԟ?}}/~?㪹$  H@$  H@$  ,o~_/RaBF>=u~{dm\s[qfǣZї(G^E@]bre?¿fW\eaaKϜ3_]}̊ _?٨UVN~Ŧ:kof֜$  H@$  H@^~ܟ벝5U[3/2&Wyj=G--3? U___{}S5fX4}.U+sg'ʒg>qZxT\rc],/.^ʿqSm}@"|[^ΫY?دK}ݧzxlֺ_1ᒀ$  H@$  H@W]SO'e}b.+΀.㑟sxt+rQ(wI@$  H@$  H@E{Ñ\_|~tlf?eeܩ~?۩snﵽΡ{䇥zja?YrFSgfene|C7$  H@$  H@k&wKdS;:+wқ=皓3/.} ~Nڇ^>qN諿9rYhzapo]Ԭ{WK$  H@$  H@#ܲYK3>$;9_k{Wu}©}b،j} )|(\:7};CrֽWq-_ʹ[#~#j%  H@$  H@$ m{oqۻVUS2^ݿ^65?ҒK]gzfSf*_\woC5=qWΦgݛCOxo]}_+ H@$  H@$  #}azЦ-{vmegsmGboǩ~$  H@$  H@w[6kVz4[φ~dǜnӃ:bīvohNh.Ob9_\! T^xo?@s9ﳫzt5c뼩c?rG3uW߇S/ H@$  H@$  \޽\g읹=Ԟw^/.>~>?C;ڟZ3-:>Q+Զf=wQs~k63K@$  H@$  H@k{Џ-=>SKꣅۑ6s]_ht+,r9Ȳvܪ.{n޿!ye{asN[uÎV`gcW<|j*5AS?Ō{V_$  H@$  H@8#,hNVJ՛?گFr%zʟZP/ݪn]4OQޥ8Su9gkY3QLS쨯[=U+3']$  H@$  H@8=\g<,<>|U :>3R?RvMţ5˗F4Gu[s^L^\/W>վs!3VLM>F][=F՜h&liI@$  H@$  H@8FxUgL䋋.f}fyzM4yZ9\RDKoZo^p>>Z H@$  H@$  H8{:;tQ/;E|2O=mFڬg~{fz4,O{f|_R^\SحiK]#NOhg]ٮZj=rS'V~k/,7iE=rT~԰+7Wok?vjS#N-]h/0rS~{$  H@$  H@$ z#=j&˪e][1zԶzG33~>gj<^J{\Կ]n憎r=_qљfE7^*?[9tO}#З$  H@$  H@ p7}^F3fG[g:4eY|շjG342{r,gUs1UݗPJ@$  H@$  H<M.5xd{.Z||#^6ˏfksV.kؚ1[YL4G{C$oҎt|5<>Uq}#-<`.q/1$  H@$  H@N#wgyG7Ve"O۪ךjكl^{̾M_3Z7նz-˞⋋KAptl]WgNmSVV~?|/sue-Mնty }1f^$  H@$  H@s{t.'e//9RK[ϕ5h/?zg9UƷ>м}h[Qm[srRSvMє?VzfЋq^9[#O}P_h@H+ H@$  H@$ Oݫ}Z{O[U>k#Ғf-F̕Zɣ-h&슦wig5[{qs%{gQgzR+M߃ZɍE_o欭ygAw?i%  H@$  H@$ O}\#_vԧ|YQ>~V4虓=xFbH4icv5zl߫1;cu^&}P#z>(_\﹪Q9ˬ^K.Ζ$  H@$  H@ػG~ qV9CGEvV+W?fyh]C=+hc{hf9\_=X$  H@$  H@{}q< =[Ҥ?kh4ڭއ1?c|,*NӃzGv4o5(\ngqs=^dO+Uϖ~RK\64RFq<{dFiY9k%  H@$  H@$ ݹzٕ-}jF>y쨖?gL+ߊϩH=_~@mfdkGs4'Y~cOyK7R/|t#Mjq(W4X$  H@$  H@x^yG8ڹ{L=[Ԥ?U"r=?rzKҐ'~{Y93<}Wi?ċ lf>;ӵ=K3W~-kUfg_{ck~=.(WZ=F9+}Y[ڿ H@$  H@$  H`^g6uI4W<>9e{{ Befg_hs,٫>)!^\<DžyJF;VtB`W6}VVH-85+ggm/V-gK@$  H@$  H@޽`Sԥģv_TLWZs>Wn/ifߔaՅ{hw6'.[#_{\˃ۋkK$  H@$  H@xys=Y>3W|bSў~BI[=kƵO~obB@V<,VV`˯>07kU˕TM-~(~dgT3' H@$  H@$  |x;EN=:ݦ.k&394^=gK]?$٬Yf䣧6o@ҝcO}f댼@ͭ\-4壣+VSzȳ>. H@$  H@$  H|m43N^rf=k&Ut]8ςgVs}VXy֚sl3Es/?kyswt`Z-ɕ:[纵g$  H@$  H@PZs>rf=k&U*9fj3VϬyޏ訥-=<̮?^\P ]_ڮˍ5ﻢKȯ\}!=3HK9-{L~Β$  H@$  H@C kb=ˬ-]ֶ^qUzj˯EzV\9Aߺ> gcWu^S|=ekm큶tʱ*W_Kbԥ?1cO\{swj3$  H@$  H@k 0W={g~RY4z峖~t(fFܣZY^Z3 z-g&̧{M/އP??lV<wM٣rӗ$  H@$  H@nwO_,YYK?{3Cۜ_HKAFCiGs4O}[}1s,V4yت_ei_A[YK[d ~qH3ғӣJ@$  H@$  H@p/.U~L<~'Zſ_3ڃ7tY岎me.]Ξq =r+}r~Y?/.rɐ=#Ǝ4+*W3YtVy_U.gѕz ~5'S# H@$  H@$  \8}XÎY/_=FL?vϟs.nGM >Y5lj#,{݄[냙]o՘gzSK}d575,zGs˙{1:~ H@$  H@$  F~-aC۬j#_Zbr#fϞcG=ԺenY(OvKU&|qK\l>w-ϓڑO.{5V mYԈs&5,]WOW{>c H@$  H@$  {ٳ~W/5,*&EcK=>6ʒR1I >FG}ٓ>K]:Ӈ|qt7uQcy,z,y쬧,I:qUh^f4\9y{4O~>V$  H@$  H@l]U>9'?g匾}جVVŵ}̠̎gOL,y,y(IWOж.♾2Nrjul[Зezd\֙9ڇQˬ#}|+{fϊ^$  H@$  H@$@_1JY>3Mck|lsa{[Z¦sLj䰣lGg]ۋ`uYtUoe<37ڋ:65b߭<ǎR2hr9t<=FOG3WOe~'u$  H@$  H@xfj3O=9V4,{vz-jٟS}1=[7}ȍ,3'6793_#` QO𱜧bVIj<d_>,{7g}r33:sУ$  H@$  H@k':zүXV9-;ܞ,zje1RKϞ0ԛ.s{>{鮾^\$N4Q_>[uW-ck|,ZK k%  H@$  H@$ w}V=kXc+%7+?ﹾV}Vct+Q=geH=ޛoE}Hyq|K;Ԡ-4Znj;Zfϥߚ=[:k$  H@$  H@ AG-m8khzn++{cASZ>V=<>M~s=Fczҋxs`-}=Oʗ>W쓚|~Y񊟺>ogO,H_WkhҟzX$  H@$  H@^m!'ʗ&uxI_gA%%v̦4*Wzzojf*/{+ФeѹRW8nk1kyjjMU̙S[yuUz$  H@$  H@$OeG/ 13e1Oղ=GliklՏu1s@Wz~Y]ӟΎhF=3n5_~ʹwSb$  H@$  H@$^}/9blfqWjhR?miz8-gf j1.OȨuԦO}f5 g:53FmV:o+'4,GIDAT|oFO,}}J[_g/{\R1:,ub#J@$  H@$  H@=[تg-13_jnd3s7E⴩z`у.-Y+gGm{⳿~S~tiL<=7yE]V}ˌ]1Q_Uk* |뚌9EǏR=9 H@$  H@$  H`N߯N؞ jGL˼&}4QQjH79cwc5G~so~>`̫KH?i2eN:5,*UgHķ<cT3;З6LWkhʦ.[=ӗ$  H@$  H@k$0WH}a)9ȒC|fK˜JM3?sK }WiEA]NwTw%5d-s+sjRV~63zL~ds'Pӟ>X+ H@$  H@$  ;1zu9ܮ,j]CKF\Ҧz3ɣŕY{Ѽ`58Jݙ߳}Ug Wo*RwXfe~+UskKC5$  H@$  H@k#0WqH}a{bjQi{xG4ٳ3mZ7 rMz=]u 16JSk\鶴C[?}Q~E^23,9,gfO*/k>˳HrZ H@$  H@$  H`@_1Sz;U-#kr\^ȥ9Xj9j,؞'.ˬ̍¢ߋȯا_\ӋC8.」9l!|T<s/V$  H@$  H@$TjeU,gWs,ԕ_ =+?V1k%  H@$  H@$ wp,'Ƣqg|blGv=#M*}Q>*eff~kjf=ׯ:@fߝ=h}[5t#M߿49[ղ'VsgN*ggY%  H@$  H@$ V}ƌx͕lMFQ-u#޲Rcj=?+wd1\֯¿G`&,|,{<ˣ+[HɕO>ϔsfe|f1+Zs~j*59W評e,ⴳZ^_$  H@$  H@xw/T~n+ڞO[,Ӧ_Ԯ8Cߣ{ٓ}z߬O3Y>_;gQ~+k8e븣xi3\r]3|ŵǎV,i^ų\k3~$  H@$  H@J`bxT빭8k:7~Y̗_nS7٧jzeܚ7V=k[v(?Ϝ+gVH_Zm1cK<Ғ+mQ\f1$  H@$  H@$0'R9rՓy|liuzY/s>z9>=u-;Ҏr[3>h_\ȼ^{žQslh3|zʧHK.uc{5} H@$  H@$  v{^˽-~V.K_,_=C|ƙ|1}Xtgߵ=FeOٚw5EH_Y`v{ѢxWUz>FP~*Zr\YǯZ-i+?ꝝ9̥Z~}2z$  H@$  H@*QzZ{ҥa+xd3_cϘ\kuc;5Fnն=޳\S@%lha^i==ϼa&O=~*WC"l嘝٣C:,zUcOT42OQNK2WZc H@$  H@$  H`@ˮZOma's[QzǽLy9ײ4,t؞Z#-7|je,'b.5Y+|++kӃ&F6uc}gbVbFfbVE-ח$  H@$  H@>}x*\oY[9+n^QZ#mүZ<~U\zeer=gy3~tvl>䰹mcVL[5|lϝ}6gE1z|z2WZc H@$  H@$  H`Zj=OEm{x v6gV'^}e ʢj˞߫ݿO35E=r{60笪8zl>5C6@>,j]Q1+fg}2_7ӑJ@$  H@$  H@{=j2N?yblicϴ[弜O]%q~szճUs._ӋS@.kO> zbfbSʳc+_~_9]>K {.c-mKMУ%ν~T#W벦/ H@$  H@$  lغ_;RiG9NC Sf뻆;Sæ\Ycz}]̾{/.{P9|j=W1tKڪ\]|{Ӄ%W|S>{,snU:Z H@$  H@$  H;yG7zG=CEGG[\Z|tig3-v3ʥ>^}ƩsVz6->4X>n>ы3E̳d vKh'gQgVƣ̮VZ-{k%  H@$  H@$ })Oe__3?υˌQ}+G >ؕ<ڴ3[ZfyjhEss.g2~%9[Y-YUig=}#WyW=Gz_=P/ H@$  H@$ JܗԳy|/CG>9,ctenwdWs}|L[^fǹoE]X仦9׈tH5亭:j+E7fg?>Z,c/7fhjZ H@$  H@$  H4KѤnʍj_G>97kg\Z-)avy䳗3Fܖ~3^܋ a4Բ':B3klЌljџ( ~mT\~h=[vkV5 H@$  H@$  y}yzgq!k闆[=fY?Z+5L;3!ճW{\/,8.F>ۭ^#frs H@$  H@$  D>ln\ٻ;Ғâ-K[4=O<]%=־Xޮxg.gxkFF>?gtu$  H@$  H@:K7fQ~(u6jؽޑ.s'ғ^#2K;W}P/..ت3kdV˼ʳj猙OުO^jeGu=/T]c, H@$  H@$ L`v6c_ձOgLOlNߨZ9?mͦ69kT_~q~MU2>3ˎ#=5,bVkJK9fa`{~wQ;tz H@$  H@$  Hs]^|$ܻ_Zblh>1vf?;&k[J?nWc H@$  H@$  {[Vz4[5iz.yb,nݫQO-[~ow6ڃܧzaA߸e~e?YӃES6{2_~Aԗvaƪ=2z^3sgu$  H@$  H@i޶jF=+=6іi27:1q?ʭu Gf<^\)[z=Gժ={}Ti_K?uOK)=ٜݵ[֌>X$  H@$  H@8;ul(,]qf~N[ejYϞgƖQr߸蔞OFֳ̧{n+S~ޗh(2s֗K@$  H@$  H@E`v)gQ~cNڮ8)?k3?{`j]3jO>cy_o\|!rA·W3hvvM֩a39şP߳9s$  H@$  H@58޼Y}FqZ1}以^Zg+}hlT_\A]\n٪|3d~9ty^FGmUlQOgR' H@$  H@$  pO7WUGzVsӏw!A˜ ګW󧢊ȁ?=V=kñ3=6Jn+ڮgwԏn;ʡ_O_C$  H@$  H@$4+[;G1ԤןGvT\9/-]9m'm]oճ~~t+爱9fUVf/ H@$  H@$  6e,_OUK#]x%eF+Y~ֻϬ^4+sR{5ETT¬h|UJ>Y+?Ұz-~rY;c3$  H@$  H@$ 8r8['=麦ǽg=FbW{Wu+{>~ェП{-ݬyR~u-h(7ό-;59$  H@$  H@Gȥ-'s]cte~-M7~5(ॼYm{p:Ou=>қg3s)lSf# H@$  H@$  8tٽ6A5{4߷=N}.}egQ6u=мg}quQ]|?ê{ڑ?ثJ@$  H@$  H@K`|Vg$ǽOm)VA׏Uo\rYcUZseϞq1Zlgft>j#=Kح\b?gJ@$  H@$  H@/^=Fug=<Ӈ]we{ǩ{HבYT{* "'E^i>vVG,4쩽Ǻ$  H@$  H@$0'p}uޭO1Ҭ1:hH3z}6zG̮{D|/.َ\~h4cx8gzF>+-V-g_r)G$  H@$  H@PfoF[{z#@Wm/.ޢ8͹߼]zVmמ#(7ڃ[v6::$  H@$  H@$r]G$f=(2sok=ѯJD0_XCǍ]HH;}V4>^X7_^#G[dN3G_J^GKzq:r?+xJl9fc|%  H@$  H@$ ctifs~Y,={݇{/-!^ċyˋ1ull߳瘱܋=$  H@$  H@<2kkVmv#=Gߩ}og0/Üèv:z)T_G٫}s;z H@$  H@$  Hx%}C7o=G{>{ /s]:甾Sz>2>ed{Ko3 H@$  H@$  H \}o^} )N{/,^䋋z+xyp}?Nj?,3> $  H@$  H@xrD6gXmYY^KzO/0x1}S9)sNa?$  H@$  H@$ S.O99sڗ{?/_\ԃH`"#?eSzg1/ H@$  H@$  &\?wS>)zҢU9s8DK@$  H@$  H8E{wlu=:<σ} /,xWC߿?=Ǽss}Y!ɼ$  H@$  H@$p^g?xK}kzaC틇}?m$  H@$  H@$Y_9sy{Ңվ q/s3q$  H@$  H@$9:笷G~/,_\q?貗zpy=ΰwF$  H@$  H@ȅG.5$^0jK__z~:{g>;H$  H@$  H@WFb|Kb}Y _\|̅_`>}ae# H@$  H@$  H.`r /.lV{]Ëk8<$  H@$  H@ pї 4|q=3Ĩ}o%-@$  H@$  H@8gy ħx3'勋cS?K5,xMϚ$  H@$  H@.I./?ȳb|q1rJzɟ4%  H@$  H@$ DHH8ݴJ^b狍s$  H@$  H@-/&F|Y1/.o_d{K@$  H@$  H@{㋊=BO M3ľ$  H@$  H@x!né}Yq*|qqv—g0 H@$  H@$  H@"Ks<}/.NgwN_h\H@$  H@$  H@/(~6'."$  H@$  H@+%}qq}I$  H@$  H@$pC|)qC G ^K/=^'sJ@$  H@$  H ʎOꕜӗ%1%  H@$  H@/xū$  H@$  H@$  Hz|zI$  H@$  H@$  H@x|q|~ H@$  H@$  H@}E$  H@$  H@$ $  H@$  H@$ +"+0<$  H@$  H@$  Hk %  H@$  H@$  H@WDWax H@$  H@$  H@k'K@$  H@$  H@/.($  H@$  H@$ N'痀$  H@$  H@$  \_\\чQ$  H@$  H@$  H@/.^O/ H@$  H@$  H@"ãH@$  H@$  H@^;_\_$  H@$  H@$pE|qqEG$  H@$  H@$  v?gz&IENDB`sympy-sympy-1.9/doc/src/pics/pngview1.png000066400000000000000000000062631412543434000204720ustar00rootroot00000000000000PNG  IHDRks:sRGBbKGD pHYs B(xtIME iTXtCommentCreated with GIMPd.e IDATx{PSW?Wvv[N.Ji[uEk;ZvkUXۊjK|[*/y RLL8=7s;RIqſ* R6w*yv~>SWG럱@nk?,ZY]?ZM=:E%U>?ٽi 枸kKUpYxu589=-x @QTUVyj22+~:/H꧌0>^#>?R[xODՍjNwceHw<2FVQ&?855(}CpTF&JŌ)QT?qG:q'32JBP{ XYT39*#{[_G惖jC,[@R+@vV0V|מFP?$Bn1L~^!SR̳GeNJض4/%ƢUSP\Ň<H̄IzsF%ϔuYw&M#yA 7$iڷ De.HVߓqR/=> -oI牿|Ƨ&1f,ƛ|n.<čRʍD ۃBWZ@X`+|M4v%is*oN#t_G@OsKgjf=0K_efwqd~ hBm{677vwDd";'|d@⧍Ry&n kWFZ۾>ǨQ8sBf[jn;g{k8k_hZY8 aCkOōfc2)RX/ 55QXV!} BkȻnd\Xm5lSQ](wW]i}*1s:n 䉑Yhկ-_w:=:T. =K-Ut+izb7.a\`NjOeľcч "~~twWf{mZяukN!`k@O[\$ۖo6 3Q:@d\%[=r9z2a~^3ӲdB%4o.Ka93:LAyMN+߷S0`:cn۾ɛ[H}֙͜e0:x$?cWjҀV YβUtաjv0:FFݖC`쥘L%*W>o*H5ZAడxyQ?__ϝf.*<0Eax= l0^ose-w}Yv03{?^m`H.puR2uoݻ,&[ipS{!ɲ##:\6uNj⢲*;wס ]̺^c'Yy6 ]Pƺfb>GOױ c5W҉MHrMvS_ht( xzz,5VƬI=&jI>ˊYOc=:rZXҊ~k·.5%|9FkJZ"(+- @;@̤j>XK,KH,!KH,!K,KH,!KH,+77C۫ҥKԩS455 :Y3gΰvZZ-: ȑ#qwwg۶mh4dYN +33!C₯`ee%"|QPODVUQQd4Cqg8w'O&11///NY3|j5DEE1v.WHnn.cƌia5I"??ݻwS] AAA\x.1&&I&ԅ]3 Ι33fhD{-^^O\\"ü^j:#FV,N_UyZ;w.3gDVU_Ǐ3e8%عsehZfΜIQQgϞIII!!!%Kh"O!Nlj' dӦM(̝;/// = .dذa >]RRܹM6Pb`yرc׮]cݺu`$z U8p={Xt:\]]OBzvő#Gz4piiiKwO|||((( ''Gk+W8twھ}; ,\ 6PZZ#Z&܉i-' ::kע>|xKnʲeزe *w}HZZuuuDEEindt!/_?^{b4J׳fә8q"o&/FӱcFc%'=(+%ʯ˗/:$$DY~RYY$?DP?,!KHZM",{XkXXOb!',Nϗ>`<<==Ӡ3:~8ʼyh4Fy'::+VqFL&6lh!'ʕ+u%$` X%$` XB%` XB%$` X%$` XB%` XBvCe%bTDd ݱ*/F%%'=a?݇*IENDB`sympy-sympy-1.9/doc/src/special_topics/000077500000000000000000000000001412543434000202605ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/special_topics/classification.rst000066400000000000000000000060421412543434000240070ustar00rootroot00000000000000=============================== Classification of SymPy objects =============================== There are several ways of how SymPy object is classified. class ===== Like any other object in Python, SymPy expression is an instance of class. You can get the class of the object with built-in `type()` function, and check it with `isinstance()` function. >>> from sympy import Add >>> from sympy.abc import x,y >>> type(x + y) >>> isinstance(x + y, Add) True Classes represent only the programmatic structures of the objects, and does not distinguish the mathematical difference between them. For example, the integral of number and the integral of matrix both have the class `Integral`, although the former is number and the latter is matrix. >>> from sympy import MatrixSymbol, Integral >>> A = MatrixSymbol('A', 2, 2) >>> type(Integral(1, x)) >>> type(Integral(A, x)) kind ==== Kind indicates what mathematical object does the expression represent. You can retrieve the kind of expression with `.kind` property. >>> Integral(1, x).kind NumberKind >>> Integral(A, x).kind MatrixKind(NumberKind) This result shows that `Integral(1, x)` is number, and `Integral(A, x)` is matrix with number element. Since the class cannot guarantee to catch this difference, kind of the object is very important. For example, if you are building a function or class that is designed to work only for numbers, you should consider filtering the arguments with `NumberKind` so that the user does not naively pass unsupported objects such as `Integral(A, x)`. For the performance, set theory is not implemented in kind system. For example, `NumberKind` does not distinguish the real number and complex number. >>> from sympy import pi, I >>> pi.kind NumberKind >>> I.kind NumberKind SymPy's `Set` and kind are not compatible. >>> from sympy import S >>> from sympy.core.kind import NumberKind >>> S.Reals.is_subset(S.Complexes) True >>> S.Reals.is_subset(NumberKind) Traceback (most recent call last): ... ValueError: Unknown argument 'NumberKind' sets and assumptions ==================== If you want to classify the object in strictly mathematical way, you may need SymPy's sets and assumptions. >>> from sympy import ask, Q >>> S.One in S.Reals True >>> ask(Q.even(2*x), Q.odd(x)) True See `assumptions` module and `sets` module for more information. func ==== `func` is the head of the object, and it is used to recurse over the expression tree. >>> Add(x + y).func >>> Add(x + x).func >>> Q.even(x).func As you can see, resulting head may be a class or another SymPy object. Keep this in mind when you classify the object with this attribute. See :ref:`tutorial-manipulation` for detailed information. sympy-sympy-1.9/doc/src/special_topics/finite_diff_derivatives.rst000066400000000000000000000271641412543434000256770ustar00rootroot00000000000000=============================================== Finite Difference Approximations to Derivatives =============================================== Introduction ============ Finite difference approximations to derivatives is quite important in numerical analysis and in computational physics. In this tutorial we show how to use SymPy to compute approximations of varying accuracy. The hope is that these notes could be useful for the practicing researcher who is developing code in some language and needs to be able to efficiently generate finite difference formulae for various approximations. In order to establish notation, we first state that we envision that there exists a continuous function F of a single variable x, with F having as many derivatives as desired. We sample x values uniformly at points along the real line separated by h. In most cases we want h to be small in some sense. F(x) may be expanded about some point `x_{0}` via the usual Taylor series expansion. Let `x = x_{0} + h`. Then the Taylor expansion is .. math:: F(x_{0}+h) = F(x_{0}) + \big(\frac{dF}{dx}\big)_{x_{0}} * h + \frac{1}{2!} \big(\frac{d^{2}F }{dx^{2}}\big)_{x_{0}}* h^2 + \frac{1}{3!} \big(\frac{d^{3}F }{dx^{3}}\big)_{x_{0}}* h^3 + ... In order to simplify the notation, we now define a set of coefficients `c_{n}`, where .. math:: c_{n} := \frac{1}{n!} \big(\frac{d^{n}F }{dx^{n}}\big)_{x_{0}}. So now our series has the form: .. math:: F(x_{0}+h) = F(x_{0}) + c_{1} * h + c_{2}* h^2 + c_{3}* h^3 + ... In the following we will only use a finite grid of values `x_{i}` with `i` running from `1,...,N` and the corresponding values of our function F at these grid points denoted by `F_{i}`. So the problem is how to generate approximate values for the derivatives of F with the constraint that we use a subset of the finite set of pairs `(x_{i},F_{i})` of size N. What follows are manipulations using SymPy to formulate approximations for derivatives of a given order and to assess its accuracy. First, we use SymPy to derive the approximations by using a rather brute force method frequently covered in introductory treatments. Later we shall make use of other SymPy functions which get the job done with more efficiency. A Direct Method Using SymPy Matrices ==================================== If we let `x_{0} = x_{i}`, evaluate the series at `x_{i+1}=x_{i}+ h` and truncate all terms above `O(h^1)` we can solve for the single coefficient `c_{1}` and obtain an approximation to the first derivative: .. math:: \big(\frac{dF}{dx}\big)_{x_{0}} \approx \frac{F_{i+1} - F_{i}}{h} + O(h) where the `O(h)` refers to the lowest order term in the series in `h`. This establishes that the derivative approximation is of first order accuracy. Put another way, if we decide that we can only use the two pairs `(x_{i},F_{i})` and `(x_{i+1},F_{i+1})` we obtain a "first order accurate" derivative. In addition to `(x_{i},F_{i})` we next use the two points `(x_{i+1},F_{i+1})` and `(x_{i+2},F_{i+2})`. Then we have two equations: .. math:: F_{i+1} = F_{i} + c_{1}* h + \frac{1}{2}*c_{2}*h^2 + \frac{1}{3!}*c_{3}*h^3 + ... .. math:: F_{i+2} = F_{i} + c_{1}* (2h) + \frac{1}{2}*c_{2}*(2h)^2 + \frac{1}{3!}*c_{3}*(2h)^3 + ... If we again want to find the first derivative (`c_{1}`), we can do that by eliminating the term involving `c_{2}` from the two equations. We show how to do it using SymPy. >>> from __future__ import print_function >>> from sympy import * >>> x, x0, h = symbols('x, x_0, h') >>> Fi, Fip1, Fip2 = symbols('F_{i}, F_{i+1}, F_{i+2}') >>> n = 3 # there are the coefficients c_0=Fi, c_1=dF/dx, c_2=d**2F/dx**2 >>> c = symbols('c:3') >>> def P(x, x0, c, n): ... return sum( ((1/factorial(i))*c[i] * (x-x0)**i for i in range(n)) ) Vector of right hand sides: >>> R = Matrix([[Fi], [Fip1], [Fip2]]) Now we make a matrix consisting of the coefficients of the c_i in the nth degree polynomial P. Coefficients of `c_i` evaluated at `x_i`: >>> m11 = P(x0 , x0, c, n).diff(c[0]) >>> m12 = P(x0 , x0, c, n).diff(c[1]) >>> m13 = P(x0 , x0, c, n).diff(c[2]) Coefficients of `c_i` evaluated at `x_i + h`: >>> m21 = P(x0+h, x0, c, n).diff(c[0]) >>> m22 = P(x0+h, x0, c, n).diff(c[1]) >>> m23 = P(x0+h, x0, c, n).diff(c[2]) Coefficients of `c_i` evaluated at `x_i + 2*h`: >>> m31 = P(x0+2*h, x0, c, n).diff(c[0]) >>> m32 = P(x0+2*h, x0, c, n).diff(c[1]) >>> m33 = P(x0+2*h, x0, c, n).diff(c[2]) Matrix of the coefficients is 3x3 in this case: >>> M = Matrix([[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]]) Matrix form of the three equations for the `c_i` is M*X = R: The solution is obtained by directly inverting the 3x3 matrix M: >>> X = M.inv() * R Note that all three coefficients make up the solution. The desired first derivative is coefficient `c_1` which is X[1]. >>> print(together(X[1])) (4*F_{i+1} - F_{i+2} - 3*F_{i})/(2*h) It is instructive to compute another three-point approximation to the first derivative, except centering the approximation at `x_i` and thus using points at `x_{i-1}`, `x_{i}`, and `x_{i+1}`. So here is how this can be done using the 'brute force' method: >>> from __future__ import print_function >>> from sympy import * >>> x, x0, h = symbols('x, x_i, h') >>> Fi, Fim1, Fip1 = symbols('F_{i}, F_{i-1}, F_{i+1}') >>> n = 3 # there are the coefficients c_0=Fi, c_1=dF/h, c_2=d**2F/h**2 >>> c = symbols('c:3') >>> # define a polynomial of degree n >>> def P(x, x0, c, n): ... return sum( ((1/factorial(i))*c[i] * (x-x0)**i for i in range(n)) ) >>> # now we make a matrix consisting of the coefficients >>> # of the c_i in the nth degree polynomial P >>> # coefficients of c_i evaluated at x_i >>> m11 = P(x0 , x0, c, n).diff(c[0]) >>> m12 = P(x0 , x0, c, n).diff(c[1]) >>> m13 = P(x0 , x0, c, n).diff(c[2]) >>> # coefficients of c_i evaluated at x_i - h >>> m21 = P(x0-h, x0, c, n).diff(c[0]) >>> m22 = P(x0-h, x0, c, n).diff(c[1]) >>> m23 = P(x0-h, x0, c, n).diff(c[2]) >>> # coefficients of c_i evaluated at x_i + h >>> m31 = P(x0+h, x0, c, n).diff(c[0]) >>> m32 = P(x0+h, x0, c, n).diff(c[1]) >>> m33 = P(x0+h, x0, c, n).diff(c[2]) >>> # matrix of the coefficients is 3x3 in this case >>> M = Matrix([[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]]) Now that we have the matrix of coefficients we next form the right-hand-side and solve by inverting `M`: >>> # matrix of the function values...actually a vector of right hand sides >>> R = Matrix([[Fi], [Fim1], [Fip1]]) >>> # matrix form of the three equations for the c_i is M*X = R >>> # solution directly inverting the 3x3 matrix M: >>> X = M.inv() * R >>> # note that all three coefficients make up the solution >>> # the first derivative is coefficient c_1 which is X[1]. >>> print("The second-order accurate approximation for the first derivative is: ") The second-order accurate approximation for the first derivative is: >>> print(together(X[1])) (F_{i+1} - F_{i-1})/(2*h) These two examples serve to show how one can directly find second order accurate first derivatives using SymPy. The first example uses values of `x` and `F` at all three points `x_i`, `x_{i+1}`, and `x_{i+2}` whereas the second example only uses values of `x` at the two points `x_{i-1}` and `x_{i+1}` and thus is a bit more efficient. From these two simple examples a general rule is that if one wants a first derivative to be accurate to `O(h^{n})` then one needs n+1 function values in the approximating polynomial (here provided via the function `P(x,x0,c,n)`). Now let's assess the question of the accuracy of the centered difference result to see how we determine that it is really second order. To do this we take the result for `dF/dx` and substitute in the polynomial expansion for a higher order polynomial and see what we get. To this end, we make a set of eight coefficients d and use them to perform the check: >>> d = symbols('c:8') >>> dfdxcheck = (P(x0+h, x0, d, 8) - P(x0-h, x0, d, 8))/(2*h) >>> print(simplify(dfdxcheck)) # so the appropriate cancellation of terms involving `h` happens c1 + c3*h**2/6 + c5*h**4/120 + c7*h**6/5040 Thus we see that indeed the derivative is `c_1` with the next term in the series of order `h^2`. However, it can quickly become rather tedious to generalize the direct method as presented above when attempting to generate a derivative approximation to high order, such as 6 or 8 although the method certainly works and using the present method is certainly less tedious than performing the calculations by hand. As we have seen in the discussion above, the simple centered approximation for the first derivative only uses two point values of the `(x_{i},F_{i})` pairs. This works fine until one encounters the last point in the domain, say at `i=N`. Since our centered derivative approximation would use data at the point `(x_{N+1},F_{N+1})` we see that the derivative formula will not work. So, what to do? Well, a simple way to handle this is to devise a different formula for this last point which uses points for which we do have values. This is the so-called backward difference formula. To obtain it, we can use the same direct approach, except now us the three points `(x_{N},F_{N})`, `(x_{N-1},F_{N-1})`, and `(x_{N-2},F_{N-2})` and center the approximation at `(x_{N},F_{N})`. Here is how it can be done using SymPy: >>> from __future__ import print_function >>> from sympy import * >>> x, xN, h = symbols('x, x_N, h') >>> FN, FNm1, FNm2 = symbols('F_{N}, F_{N-1}, F_{N-2}') >>> n = 8 # there are the coefficients c_0=Fi, c_1=dF/h, c_2=d**2F/h**2 >>> c = symbols('c:8') >>> # define a polynomial of degree d >>> def P(x, x0, c, n): ... return sum( ((1/factorial(i))*c[i] * (x-x0)**i for i in range(n)) ) Now we make a matrix consisting of the coefficients of the `c_i` in the dth degree polynomial P coefficients of `c_i` evaluated at `x_i, x_{i-1},` and `x_{i+1}`: >>> m11 = P(xN , xN, c, n).diff(c[0]) >>> m12 = P(xN, xN, c, n).diff(c[1]) >>> m13 = P(xN , xN, c, n).diff(c[2]) >>> # coefficients of c_i evaluated at x_i - h >>> m21 = P(xN-h, xN, c, n).diff(c[0]) >>> m22 = P(xN-h, xN, c, n).diff(c[1]) >>> m23 = P(xN-h, xN, c, n).diff(c[2]) >>> # coefficients of c_i evaluated at x_i + h >>> m31 = P(xN-2*h, xN, c, n).diff(c[0]) >>> m32 = P(xN-2*h, xN, c, n).diff(c[1]) >>> m33 = P(xN-2*h, xN, c, n).diff(c[2]) Next we construct the `3 \times 3` matrix of the coefficients: >>> M = Matrix([[m11, m12, m13], [m21, m22, m23], [m31, m32, m33]]) >>> # matrix of the function values...actually a vector of right hand sides >>> R = Matrix([[FN], [FNm1], [FNm2]]) Then we invert `M` and write the solution to the `3 \times 3` system. The matrix form of the three equations for the c_i is `M*C = R`. The solution is obtained by directly inverting `M`: >>> X = M.inv() * R The first derivative is coefficient `c_1` which is `X[1]`. Thus the second order accurate approximation for the first derivative is: >>> print("The first derivative centered at the last point on the right is:") The first derivative centered at the last point on the right is: >>> print(together(X[1])) (-4*F_{N-1} + F_{N-2} + 3*F_{N})/(2*h) Of course, we can devise a similar formula for the value of the derivative at the left end of the set of points at `(x_{1},F_{1})` in terms of values at `(x_{2},F_{2})` and `(x_{3},F_{3})`. Also, we note that output of formats appropriate to Fortran, C, etc. may be done in the examples given above. Next we show how to perform these and many other discritizations of derivatives, but using a much more efficient approach originally due to Bengt Fornberg and now incorporated into SymPy. :ref:`calculus-finite-differences` :ref:`Finite difference weights ` sympy-sympy-1.9/doc/src/special_topics/index.rst000066400000000000000000000002701412543434000221200ustar00rootroot00000000000000.. _special_topics: ===================== SymPy Special Topics ===================== .. toctree:: :maxdepth: 2 intro.rst finite_diff_derivatives.rst classification.rst sympy-sympy-1.9/doc/src/special_topics/intro.rst000066400000000000000000000005161412543434000221470ustar00rootroot00000000000000============ Introduction ============ The purpose of this collection of documents is to provide users of SymPy with topics which are not strictly tutorial or are longer than tutorials and tests. The documents will hopefully fill a gap as SymPy matures and users find more ways to show how SymPy can be used in more advanced topics. sympy-sympy-1.9/doc/src/tutorial/000077500000000000000000000000001412543434000171225ustar00rootroot00000000000000sympy-sympy-1.9/doc/src/tutorial/basic_operations.rst000066400000000000000000000156231412543434000232070ustar00rootroot00000000000000.. _tutorial-basic: ================== Basic Operations ================== Here we discuss some of the most basic operations needed for expression manipulation in SymPy. Some more advanced operations will be discussed later in the :ref:`advanced expression manipulation ` section. >>> from sympy import * >>> x, y, z = symbols("x y z") Substitution ============ One of the most common things you might want to do with a mathematical expression is substitution. Substitution replaces all instances of something in an expression with something else. It is done using the ``subs`` method. For example >>> expr = cos(x) + 1 >>> expr.subs(x, y) cos(y) + 1 Substitution is usually done for one of two reasons: 1. Evaluating an expression at a point. For example, if our expression is ``cos(x) + 1`` and we want to evaluate it at the point ``x = 0``, so that we get ``cos(0) + 1``, which is 2. >>> expr.subs(x, 0) 2 2. Replacing a subexpression with another subexpression. There are two reasons we might want to do this. The first is if we are trying to build an expression that has some symmetry, such as `x^{x^{x^x}}`. To build this, we might start with ``x**y``, and replace ``y`` with ``x**y``. We would then get ``x**(x**y)``. If we replaced ``y`` in this new expression with ``x**x``, we would get ``x**(x**(x**x))``, the desired expression. >>> expr = x**y >>> expr x**y >>> expr = expr.subs(y, x**y) >>> expr x**(x**y) >>> expr = expr.subs(y, x**x) >>> expr x**(x**(x**x)) The second is if we want to perform a very controlled simplification, or perhaps a simplification that SymPy is otherwise unable to do. For example, say we have `\sin(2x) + \cos(2x)`, and we want to replace `\sin(2x)` with `2\sin(x)\cos(x)`. As we will learn later, the function ``expand_trig`` does this. However, this function will also expand `\cos(2x)`, which we may not want. While there are ways to perform such precise simplification, and we will learn some of them in the :ref:`advanced expression manipulation ` section, an easy way is to just replace `\sin(2x)` with `2\sin(x)\cos(x)`. >>> expr = sin(2*x) + cos(2*x) >>> expand_trig(expr) 2*sin(x)*cos(x) + 2*cos(x)**2 - 1 >>> expr.subs(sin(2*x), 2*sin(x)*cos(x)) 2*sin(x)*cos(x) + cos(2*x) There are two important things to note about ``subs``. First, it returns a new expression. SymPy objects are immutable. That means that ``subs`` does not modify it in-place. For example >>> expr = cos(x) >>> expr.subs(x, 0) 1 >>> expr cos(x) >>> x x .. sidebar:: Quick Tip SymPy expressions are immutable. No function will change them in-place. Here, we see that performing ``expr.subs(x, 0)`` leaves ``expr`` unchanged. In fact, since SymPy expressions are immutable, no function will change them in-place. All functions will return new expressions. To perform multiple substitutions at once, pass a list of ``(old, new)`` pairs to ``subs``. >>> expr = x**3 + 4*x*y - z >>> expr.subs([(x, 2), (y, 4), (z, 0)]) 40 It is often useful to combine this with a list comprehension to do a large set of similar replacements all at once. For example, say we had `x^4 - 4x^3 + 4x^2 - 2x + 3` and we wanted to replace all instances of `x` that have an even power with `y`, to get `y^4 - 4x^3 + 4y^2 - 2x + 3`. >>> expr = x**4 - 4*x**3 + 4*x**2 - 2*x + 3 >>> replacements = [(x**i, y**i) for i in range(5) if i % 2 == 0] >>> expr.subs(replacements) -4*x**3 - 2*x + y**4 + 4*y**2 + 3 Converting Strings to SymPy Expressions ======================================= The ``sympify`` function (that's ``sympify``, not to be confused with ``simplify``) can be used to convert strings into SymPy expressions. For example >>> str_expr = "x**2 + 3*x - 1/2" >>> expr = sympify(str_expr) >>> expr x**2 + 3*x - 1/2 >>> expr.subs(x, 2) 19/2 .. warning:: ``sympify`` uses ``eval``. Don't use it on unsanitized input. ``evalf`` ========= To evaluate a numerical expression into a floating point number, use ``evalf``. >>> expr = sqrt(8) >>> expr.evalf() 2.82842712474619 SymPy can evaluate floating point expressions to arbitrary precision. By default, 15 digits of precision are used, but you can pass any number as the argument to ``evalf``. Let's compute the first 100 digits of `\pi`. >>> pi.evalf(100) 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117068 To numerically evaluate an expression with a Symbol at a point, we might use ``subs`` followed by ``evalf``, but it is more efficient and numerically stable to pass the substitution to ``evalf`` using the ``subs`` flag, which takes a dictionary of ``Symbol: point`` pairs. >>> expr = cos(2*x) >>> expr.evalf(subs={x: 2.4}) 0.0874989834394464 Sometimes there are roundoff errors smaller than the desired precision that remain after an expression is evaluated. Such numbers can be removed at the user's discretion by setting the ``chop`` flag to True. >>> one = cos(1)**2 + sin(1)**2 >>> (one - 1).evalf() -0.e-124 >>> (one - 1).evalf(chop=True) 0 ``lambdify`` ============ ``subs`` and ``evalf`` are good if you want to do simple evaluation, but if you intend to evaluate an expression at many points, there are more efficient ways. For example, if you wanted to evaluate an expression at a thousand points, using SymPy would be far slower than it needs to be, especially if you only care about machine precision. Instead, you should use libraries like `NumPy `_ and `SciPy `_. The easiest way to convert a SymPy expression to an expression that can be numerically evaluated is to use the ``lambdify`` function. ``lambdify`` acts like a ``lambda`` function, except it converts the SymPy names to the names of the given numerical library, usually NumPy. For example >>> import numpy # doctest:+SKIP >>> a = numpy.arange(10) # doctest:+SKIP >>> expr = sin(x) >>> f = lambdify(x, expr, "numpy") # doctest:+SKIP >>> f(a) # doctest:+SKIP [ 0. 0.84147098 0.90929743 0.14112001 -0.7568025 -0.95892427 -0.2794155 0.6569866 0.98935825 0.41211849] .. warning:: ``lambdify`` uses ``eval``. Don't use it on unsanitized input. You can use other libraries than NumPy. For example, to use the standard library math module, use ``"math"``. >>> f = lambdify(x, expr, "math") >>> f(0.1) 0.0998334166468 To use lambdify with numerical libraries that it does not know about, pass a dictionary of ``sympy_name:numerical_function`` pairs. For example >>> def mysin(x): ... """ ... My sine. Note that this is only accurate for small x. ... """ ... return x >>> f = lambdify(x, expr, {"sin":mysin}) >>> f(0.1) 0.1 .. TODO: Write an advanced numerics section sympy-sympy-1.9/doc/src/tutorial/calculus.rst000066400000000000000000000276471412543434000215070ustar00rootroot00000000000000.. _calculus: ========== Calculus ========== This section covers how to do basic calculus tasks such as derivatives, integrals, limits, and series expansions in SymPy. If you are not familiar with the math of any part of this section, you may safely skip it. >>> from sympy import * >>> x, y, z = symbols('x y z') >>> init_printing(use_unicode=True) .. _tutorial-derivatives: Derivatives =========== To take derivatives, use the ``diff`` function. >>> diff(cos(x), x) -sin(x) >>> diff(exp(x**2), x) ⎛ 2⎞ ⎝x ⎠ 2⋅x⋅ℯ ``diff`` can take multiple derivatives at once. To take multiple derivatives, pass the variable as many times as you wish to differentiate, or pass a number after the variable. For example, both of the following find the third derivative of `x^4`. >>> diff(x**4, x, x, x) 24⋅x >>> diff(x**4, x, 3) 24⋅x You can also take derivatives with respect to many variables at once. Just pass each derivative in order, using the same syntax as for single variable derivatives. For example, each of the following will compute `\frac{\partial^7}{\partial x\partial y^2\partial z^4} e^{x y z}`. >>> expr = exp(x*y*z) >>> diff(expr, x, y, y, z, z, z, z) 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ >>> diff(expr, x, y, 2, z, 4) 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ >>> diff(expr, x, y, y, z, 4) 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ ``diff`` can also be called as a method. The two ways of calling ``diff`` are exactly the same, and are provided only for convenience. >>> expr.diff(x, y, y, z, 4) 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ To create an unevaluated derivative, use the ``Derivative`` class. It has the same syntax as ``diff``. >>> deriv = Derivative(expr, x, y, y, z, 4) >>> deriv 7 ∂ ⎛ x⋅y⋅z⎞ ──────────⎝ℯ ⎠ 4 2 ∂z ∂y ∂x To evaluate an unevaluated derivative, use the ``doit`` method. >>> deriv.doit() 3 2 ⎛ 3 3 3 2 2 2 ⎞ x⋅y⋅z x ⋅y ⋅⎝x ⋅y ⋅z + 14⋅x ⋅y ⋅z + 52⋅x⋅y⋅z + 48⎠⋅ℯ These unevaluated objects are useful for delaying the evaluation of the derivative, or for printing purposes. They are also used when SymPy does not know how to compute the derivative of an expression (for example, if it contains an undefined function, which are described in the :ref:`Solving Differential Equations ` section). Derivatives of unspecified order can be created using tuple ``(x, n)`` where ``n`` is the order of the derivative with respect to ``x``. >>> m, n, a, b = symbols('m n a b') >>> expr = (a*x + b)**m >>> expr.diff((x, n)) n ∂ ⎛ m⎞ ───⎝(a⋅x + b) ⎠ n ∂x Integrals ========= To compute an integral, use the ``integrate`` function. There are two kinds of integrals, definite and indefinite. To compute an indefinite integral, that is, an antiderivative, or primitive, just pass the variable after the expression. >>> integrate(cos(x), x) sin(x) Note that SymPy does not include the constant of integration. If you want it, you can add one yourself, or rephrase your problem as a differential equation and use ``dsolve`` to solve it, which does add the constant (see :ref:`tutorial-dsolve`). .. sidebar:: Quick Tip `\infty` in SymPy is ``oo`` (that's the lowercase letter "oh" twice). This is because ``oo`` looks like `\infty`, and is easy to type. To compute a definite integral, pass the argument ``(integration_variable, lower_limit, upper_limit)``. For example, to compute .. math:: \int_0^\infty e^{-x}\,dx, we would do >>> integrate(exp(-x), (x, 0, oo)) 1 As with indefinite integrals, you can pass multiple limit tuples to perform a multiple integral. For example, to compute .. math:: \int_{-\infty}^{\infty}\int_{-\infty}^{\infty} e^{- x^{2} - y^{2}}\, dx\, dy, do >>> integrate(exp(-x**2 - y**2), (x, -oo, oo), (y, -oo, oo)) π If ``integrate`` is unable to compute an integral, it returns an unevaluated ``Integral`` object. >>> expr = integrate(x**x, x) >>> print(expr) Integral(x**x, x) >>> expr ⌠ ⎮ x ⎮ x dx ⌡ As with ``Derivative``, you can create an unevaluated integral using ``Integral``. To later evaluate this integral, call ``doit``. >>> expr = Integral(log(x)**2, x) >>> expr ⌠ ⎮ 2 ⎮ log (x) dx ⌡ >>> expr.doit() 2 x⋅log (x) - 2⋅x⋅log(x) + 2⋅x ``integrate`` uses powerful algorithms that are always improving to compute both definite and indefinite integrals, including heuristic pattern matching type algorithms, a partial implementation of the `Risch algorithm `_, and an algorithm using `Meijer G-functions `_ that is useful for computing integrals in terms of special functions, especially definite integrals. Here is a sampling of some of the power of ``integrate``. >>> integ = Integral((x**4 + x**2*exp(x) - x**2 - 2*x*exp(x) - 2*x - ... exp(x))*exp(x)/((x - 1)**2*(x + 1)**2*(exp(x) + 1)), x) >>> integ ⌠ ⎮ ⎛ 4 2 x 2 x x⎞ x ⎮ ⎝x + x ⋅ℯ - x - 2⋅x⋅ℯ - 2⋅x - ℯ ⎠⋅ℯ ⎮ ──────────────────────────────────────── dx ⎮ 2 2 ⎛ x ⎞ ⎮ (x - 1) ⋅(x + 1) ⋅⎝ℯ + 1⎠ ⌡ >>> integ.doit() x ⎛ x ⎞ ℯ log⎝ℯ + 1⎠ + ────── 2 x - 1 >>> integ = Integral(sin(x**2), x) >>> integ ⌠ ⎮ ⎛ 2⎞ ⎮ sin⎝x ⎠ dx ⌡ >>> integ.doit() ⎛√2⋅x⎞ 3⋅√2⋅√π⋅S⎜────⎟⋅Γ(3/4) ⎝ √π ⎠ ────────────────────── 8⋅Γ(7/4) >>> integ = Integral(x**y*exp(-x), (x, 0, oo)) >>> integ ∞ ⌠ ⎮ y -x ⎮ x ⋅ℯ dx ⌡ 0 >>> integ.doit() ⎧ Γ(y + 1) for re(y) > -1 ⎪ ⎪∞ ⎪⌠ ⎨⎮ y -x ⎪⎮ x ⋅ℯ dx otherwise ⎪⌡ ⎪0 ⎩ This last example returned a ``Piecewise`` expression because the integral does not converge unless `\Re(y) > 1.` Limits ====== SymPy can compute symbolic limits with the ``limit`` function. The syntax to compute .. math:: \lim_{x\to x_0} f(x) is ``limit(f(x), x, x0)``. >>> limit(sin(x)/x, x, 0) 1 ``limit`` should be used instead of ``subs`` whenever the point of evaluation is a singularity. Even though SymPy has objects to represent `\infty`, using them for evaluation is not reliable because they do not keep track of things like rate of growth. Also, things like `\infty - \infty` and `\frac{\infty}{\infty}` return `\mathrm{nan}` (not-a-number). For example >>> expr = x**2/exp(x) >>> expr.subs(x, oo) nan >>> limit(expr, x, oo) 0 Like ``Derivative`` and ``Integral``, ``limit`` has an unevaluated counterpart, ``Limit``. To evaluate it, use ``doit``. >>> expr = Limit((cos(x) - 1)/x, x, 0) >>> expr ⎛cos(x) - 1⎞ lim ⎜──────────⎟ x─→0⁺⎝ x ⎠ >>> expr.doit() 0 To evaluate a limit at one side only, pass ``'+'`` or ``'-'`` as a fourth argument to ``limit``. For example, to compute .. math:: \lim_{x\to 0^+}\frac{1}{x}, do >>> limit(1/x, x, 0, '+') ∞ As opposed to >>> limit(1/x, x, 0, '-') -∞ Series Expansion ================ SymPy can compute asymptotic series expansions of functions around a point. To compute the expansion of `f(x)` around the point `x = x_0` terms of order `x^n`, use ``f(x).series(x, x0, n)``. ``x0`` and ``n`` can be omitted, in which case the defaults ``x0=0`` and ``n=6`` will be used. >>> expr = exp(sin(x)) >>> expr.series(x, 0, 4) 2 x ⎛ 4⎞ 1 + x + ── + O⎝x ⎠ 2 The `O\left(x^4\right)` term at the end represents the Landau order term at `x=0` (not to be confused with big O notation used in computer science, which generally represents the Landau order term at `x=\infty`). It means that all x terms with power greater than or equal to `x^4` are omitted. Order terms can be created and manipulated outside of ``series``. They automatically absorb higher order terms. >>> x + x**3 + x**6 + O(x**4) 3 ⎛ 4⎞ x + x + O⎝x ⎠ >>> x*O(1) O(x) If you do not want the order term, use the ``removeO`` method. >>> expr.series(x, 0, 4).removeO() 2 x ── + x + 1 2 The ``O`` notation supports arbitrary limit points (other than 0): >>> exp(x - 6).series(x, x0=6) 2 3 4 5 (x - 6) (x - 6) (x - 6) (x - 6) ⎛ 6 ⎞ -5 + ──────── + ──────── + ──────── + ──────── + x + O⎝(x - 6) ; x → 6⎠ 2 6 24 120 .. _calculus-finite-differences: Finite differences ================== So far we have looked at expressions with analytic derivatives and primitive functions respectively. But what if we want to have an expression to estimate a derivative of a curve for which we lack a closed form representation, or for which we don't know the functional values for yet. One approach would be to use a finite difference approach. The simplest way the differentiate using finite differences is to use the ``differentiate_finite`` function: >>> f, g = symbols('f g', cls=Function) >>> differentiate_finite(f(x)*g(x)) -f(x - 1/2)⋅g(x - 1/2) + f(x + 1/2)⋅g(x + 1/2) If you already have a ``Derivative`` instance, you can use the ``as_finite_difference`` method to generate approximations of the derivative to arbitrary order: >>> f = Function('f') >>> dfdx = f(x).diff(x) >>> dfdx.as_finite_difference() -f(x - 1/2) + f(x + 1/2) here the first order derivative was approximated around x using a minimum number of points (2 for 1st order derivative) evaluated equidistantly using a step-size of 1. We can use arbitrary steps (possibly containing symbolic expressions): >>> f = Function('f') >>> d2fdx2 = f(x).diff(x, 2) >>> h = Symbol('h') >>> d2fdx2.as_finite_difference([-3*h,-h,2*h]) f(-3⋅h) f(-h) 2⋅f(2⋅h) ─────── - ───── + ──────── 2 2 2 5⋅h 3⋅h 15⋅h If you are just interested in evaluating the weights, you can do so manually: >>> finite_diff_weights(2, [-3, -1, 2], 0)[-1][-1] [1/5, -1/3, 2/15] note that we only need the last element in the last sublist returned from ``finite_diff_weights``. The reason for this is that the function also generates weights for lower derivatives and using fewer points (see the documentation of ``finite_diff_weights`` for more details). If using ``finite_diff_weights`` directly looks complicated, and the ``as_finite_difference`` method of ``Derivative`` instances is not flexible enough, you can use ``apply_finite_diff`` which takes ``order``, ``x_list``, ``y_list`` and ``x0`` as parameters: >>> x_list = [-3, 1, 2] >>> y_list = symbols('a b c') >>> apply_finite_diff(1, x_list, y_list, 0) 3⋅a b 2⋅c - ─── - ─ + ─── 20 4 5 sympy-sympy-1.9/doc/src/tutorial/gotchas.rst000066400000000000000000000255521412543434000213150ustar00rootroot00000000000000========= Gotchas ========= To begin, we should make something about SymPy clear. SymPy is nothing more than a Python library, like ``NumPy``, ``Django``, or even modules in the Python standard library ``sys`` or ``re``. What this means is that SymPy does not add anything to the Python language. Limitations that are inherent in the Python language are also inherent in SymPy. It also means that SymPy tries to use Python idioms whenever possible, making programming with SymPy easy for those already familiar with programming with Python. As a simple example, SymPy uses Python syntax to build expressions. Implicit multiplication (like ``3x`` or ``3 x``) is not allowed in Python, and thus not allowed in SymPy. To multiply ``3`` and ``x``, you must type ``3*x`` with the ``*``. .. _tutorial-gotchas-symbols: Symbols ======= One consequence of this fact is that SymPy can be used in any environment where Python is available. We just import it, like we would any other library: >>> from sympy import * This imports all the functions and classes from SymPy into our interactive Python session. Now, suppose we start to do a computation. >>> x + 1 Traceback (most recent call last): ... NameError: name 'x' is not defined Oops! What happened here? We tried to use the variable ``x``, but it tells us that ``x`` is not defined. In Python, variables have no meaning until they are defined. SymPy is no different. Unlike many symbolic manipulation systems you may have used, in SymPy, variables are not defined automatically. To define variables, we must use ``symbols``. >>> x = symbols('x') >>> x + 1 x + 1 ``symbols`` takes a string of variable names separated by spaces or commas, and creates Symbols out of them. We can then assign these to variable names. Later, we will investigate some convenient ways we can work around this issue. For now, let us just define the most common variable names, ``x``, ``y``, and ``z``, for use through the rest of this section >>> x, y, z = symbols('x y z') As a final note, we note that the name of a Symbol and the name of the variable it is assigned to need not have anything to do with one another. >>> a, b = symbols('b a') >>> a b >>> b a Here we have done the very confusing thing of assigning a Symbol with the name ``a`` to the variable ``b``, and a Symbol of the name ``b`` to the variable ``a``. Now the Python variable named ``a`` points to the SymPy Symbol named ``b``, and vice versa. How confusing. We could have also done something like >>> crazy = symbols('unrelated') >>> crazy + 1 unrelated + 1 This also shows that Symbols can have names longer than one character if we want. Usually, the best practice is to assign Symbols to Python variables of the same name, although there are exceptions: Symbol names can contain characters that are not allowed in Python variable names, or may just want to avoid typing long names by assigning Symbols with long names to single letter Python variables. To avoid confusion, throughout this tutorial, Symbol names and Python variable names will always coincide. Furthermore, the word "Symbol" will refer to a SymPy Symbol and the word "variable" will refer to a Python variable. Finally, let us be sure we understand the difference between SymPy Symbols and Python variables. Consider the following:: x = symbols('x') expr = x + 1 x = 2 print(expr) What do you think the output of this code will be? If you thought ``3``, you're wrong. Let's see what really happens >>> x = symbols('x') >>> expr = x + 1 >>> x = 2 >>> print(expr) x + 1 Changing ``x`` to ``2`` had no effect on ``expr``. This is because ``x = 2`` changes the Python variable ``x`` to ``2``, but has no effect on the SymPy Symbol ``x``, which was what we used in creating ``expr``. When we created ``expr``, the Python variable ``x`` was a Symbol. After we created, it, we changed the Python variable ``x`` to 2. But ``expr`` remains the same. This behavior is not unique to SymPy. All Python programs work this way: if a variable is changed, expressions that were already created with that variable do not change automatically. For example >>> x = 'abc' >>> expr = x + 'def' >>> expr 'abcdef' >>> x = 'ABC' >>> expr 'abcdef' .. sidebar:: Quick Tip To change the value of a Symbol in an expression, use ``subs`` >>> x = symbols('x') >>> expr = x + 1 >>> expr.subs(x, 2) 3 In this example, if we want to know what ``expr`` is with the new value of ``x``, we need to reevaluate the code that created ``expr``, namely, ``expr = x + 1``. This can be complicated if several lines created ``expr``. One advantage of using a symbolic computation system like SymPy is that we can build a symbolic representation for ``expr``, and then substitute ``x`` with values. The correct way to do this in SymPy is to use ``subs``, which will be discussed in more detail later. >>> x = symbols('x') >>> expr = x + 1 >>> expr.subs(x, 2) 3 .. TODO: Add link to basic operations section .. _tutorial_gotchas_equals: Equals signs ============ Another very important consequence of the fact that SymPy does not extend Python syntax is that ``=`` does not represent equality in SymPy. Rather it is Python variable assignment. This is hard-coded into the Python language, and SymPy makes no attempts to change that. You may think, however, that ``==``, which is used for equality testing in Python, is used for SymPy as equality. This is not quite correct either. Let us see what happens when we use ``==``. >>> x + 1 == 4 False Instead of treating ``x + 1 == 4`` symbolically, we just got ``False``. In SymPy, ``==`` represents exact structural equality testing. This means that ``a == b`` means that we are *asking* if `a = b`. We always get a ``bool`` as the result of ``==``. There is a separate object, called ``Eq``, which can be used to create symbolic equalities >>> Eq(x + 1, 4) Eq(x + 1, 4) There is one additional caveat about ``==`` as well. Suppose we want to know if `(x + 1)^2 = x^2 + 2x + 1`. We might try something like this: >>> (x + 1)**2 == x**2 + 2*x + 1 False We got ``False`` again. However, `(x + 1)^2` *does* equal `x^2 + 2x + 1`. What is going on here? Did we find a bug in SymPy, or is it just not powerful enough to recognize this basic algebraic fact? Recall from above that ``==`` represents *exact* structural equality testing. "Exact" here means that two expressions will compare equal with ``==`` only if they are exactly equal structurally. Here, `(x + 1)^2` and `x^2 + 2x + 1` are not the same structurally. One is the power of an addition of two terms, and the other is the addition of three terms. It turns out that when using SymPy as a library, having ``==`` test for exact structural equality is far more useful than having it represent symbolic equality, or having it test for mathematical equality. However, as a new user, you will probably care more about the latter two. We have already seen an alternative to representing equalities symbolically, ``Eq``. To test if two things are equal, it is best to recall the basic fact that if `a = b`, then `a - b = 0`. Thus, the best way to check if `a = b` is to take `a - b` and simplify it, and see if it goes to 0. We will learn :ref:`later ` that the function to do this is called ``simplify``. This method is not infallible---in fact, it can be `theoretically proven `_ that it is impossible to determine if two symbolic expressions are identically equal in general---but for most common expressions, it works quite well. >>> a = (x + 1)**2 >>> b = x**2 + 2*x + 1 >>> simplify(a - b) 0 >>> c = x**2 - 2*x + 1 >>> simplify(a - c) 4*x There is also a method called ``equals`` that tests if two expressions are equal by evaluating them numerically at random points. >>> a = cos(x)**2 - sin(x)**2 >>> b = cos(2*x) >>> a.equals(b) True .. _tutorial-gotchas-final-notes: Two Final Notes: ``^`` and ``/`` ================================ You may have noticed that we have been using ``**`` for exponentiation instead of the standard ``^``. That's because SymPy follows Python's conventions. In Python, ``^`` represents logical exclusive or. SymPy follows this convention: >>> True ^ False True >>> True ^ True False >>> Xor(x, y) x ^ y Finally, a small technical discussion on how SymPy works is in order. When you type something like ``x + 1``, the SymPy Symbol ``x`` is added to the Python int ``1``. Python's operator rules then allow SymPy to tell Python that SymPy objects know how to be added to Python ints, and so ``1`` is automatically converted to the SymPy Integer object. This sort of operator magic happens automatically behind the scenes, and you rarely need to even know that it is happening. However, there is one exception. Whenever you combine a SymPy object and a SymPy object, or a SymPy object and a Python object, you get a SymPy object, but whenever you combine two Python objects, SymPy never comes into play, and so you get a Python object. >>> type(Integer(1) + 1) >>> type(1 + 1) <... 'int'> .. note:: On running the example above in SymPy Live, (1+1) is wrapped by Integer, so it does not show the correct output. This is usually not a big deal. Python ints work much the same as SymPy Integers, but there is one important exception: division. In SymPy, the division of two Integers gives a Rational: >>> Integer(1)/Integer(3) 1/3 >>> type(Integer(1)/Integer(3)) But in Python ``/`` represents either integer division or floating point division, depending on whether you are in Python 2 or Python 3, and depending on whether or not you have run ``from __future__ import division``: >>> from __future__ import division >>> 1/2 #doctest: +SKIP 0.5 .. note:: On running the example above in SymPy Live, (1/2) is wrapped by Integer, so it does not show the correct output. To avoid this, we can construct the rational object explicitly >>> Rational(1, 2) 1/2 This problem also comes up whenever we have a larger symbolic expression with ``int/int`` in it. For example: >>> x + 1/2 #doctest: +SKIP x + 0.5 .. note:: On running the example above in SymPy Live, (1/2) is wrapped by Integer, so it does not show the correct output. This happens because Python first evaluates ``1/2`` into ``0.5``, and then that is cast into a SymPy type when it is added to ``x``. Again, we can get around this by explicitly creating a Rational: >>> x + Rational(1, 2) x + 1/2 There are several tips on avoiding this situation in the :ref:`gotchas` document. Further Reading =============== For more discussion on the topics covered in this section, see :ref:`gotchas`. sympy-sympy-1.9/doc/src/tutorial/index.rst000066400000000000000000000004221412543434000207610ustar00rootroot00000000000000.. _tutorial: ================ SymPy Tutorial ================ .. toctree:: :maxdepth: 2 preliminaries.rst intro.rst gotchas.rst basic_operations.rst printing.rst simplification.rst calculus.rst solvers.rst matrices.rst manipulation.rst sympy-sympy-1.9/doc/src/tutorial/intro.rst000066400000000000000000000203541412543434000210130ustar00rootroot00000000000000============== Introduction ============== What is Symbolic Computation? ============================= Symbolic computation deals with the computation of mathematical objects symbolically. This means that the mathematical objects are represented exactly, not approximately, and mathematical expressions with unevaluated variables are left in symbolic form. Let's take an example. Say we wanted to use the built-in Python functions to compute square roots. We might do something like this >>> import math >>> math.sqrt(9) 3.0 9 is a perfect square, so we got the exact answer, 3. But suppose we computed the square root of a number that isn't a perfect square >>> math.sqrt(8) 2.82842712475 Here we got an approximate result. 2.82842712475 is not the exact square root of 8 (indeed, the actual square root of 8 cannot be represented by a finite decimal, since it is an irrational number). If all we cared about was the decimal form of the square root of 8, we would be done. But suppose we want to go further. Recall that `\sqrt{8} = \sqrt{4\cdot 2} = 2\sqrt{2}`. We would have a hard time deducing this from the above result. This is where symbolic computation comes in. With a symbolic computation system like SymPy, square roots of numbers that are not perfect squares are left unevaluated by default >>> import sympy >>> sympy.sqrt(3) sqrt(3) Furthermore---and this is where we start to see the real power of symbolic computation---symbolic results can be symbolically simplified. >>> sympy.sqrt(8) 2*sqrt(2) A More Interesting Example ========================== The above example starts to show how we can manipulate irrational numbers exactly using SymPy. But it is much more powerful than that. Symbolic computation systems (which by the way, are also often called computer algebra systems, or just CASs) such as SymPy are capable of computing symbolic expressions with variables. As we will see later, in SymPy, variables are defined using ``symbols``. Unlike many symbolic manipulation systems, variables in SymPy must be defined before they are used (the reason for this will be discussed in the :ref:`next section `). Let us define a symbolic expression, representing the mathematical expression `x + 2y`. >>> from sympy import symbols >>> x, y = symbols('x y') >>> expr = x + 2*y >>> expr x + 2*y Note that we wrote ``x + 2*y`` just as we would if ``x`` and ``y`` were ordinary Python variables. But in this case, instead of evaluating to something, the expression remains as just ``x + 2*y``. Now let us play around with it: >>> expr + 1 x + 2*y + 1 >>> expr - x 2*y Notice something in the above example. When we typed ``expr - x``, we did not get ``x + 2*y - x``, but rather just ``2*y``. The ``x`` and the ``-x`` automatically canceled one another. This is similar to how ``sqrt(8)`` automatically turned into ``2*sqrt(2)`` above. This isn't always the case in SymPy, however: >>> x*expr x*(x + 2*y) Here, we might have expected `x(x + 2y)` to transform into `x^2 + 2xy`, but instead we see that the expression was left alone. This is a common theme in SymPy. Aside from obvious simplifications like `x - x = 0` and `\sqrt{8} = 2\sqrt{2}`, most simplifications are not performed automatically. This is because we might prefer the factored form `x(x + 2y)`, or we might prefer the expanded form `x^2 + 2xy`. Both forms are useful in different circumstances. In SymPy, there are functions to go from one form to the other >>> from sympy import expand, factor >>> expanded_expr = expand(x*expr) >>> expanded_expr x**2 + 2*x*y >>> factor(expanded_expr) x*(x + 2*y) The Power of Symbolic Computation ================================= The real power of a symbolic computation system such as SymPy is the ability to do all sorts of computations symbolically. SymPy can simplify expressions, compute derivatives, integrals, and limits, solve equations, work with matrices, and much, much more, and do it all symbolically. It includes modules for plotting, printing (like 2D pretty printed output of math formulas, or `\mathrm{\LaTeX}`), code generation, physics, statistics, combinatorics, number theory, geometry, logic, and more. Here is a small sampling of the sort of symbolic power SymPy is capable of, to whet your appetite. >>> from sympy import * >>> x, t, z, nu = symbols('x t z nu') This will make all further examples pretty print with unicode characters. >>> init_printing(use_unicode=True) Take the derivative of `\sin{(x)}e^x`. >>> diff(sin(x)*exp(x), x) x x ℯ ⋅sin(x) + ℯ ⋅cos(x) Compute `\int(e^x\sin{(x)} + e^x\cos{(x)})\,dx`. >>> integrate(exp(x)*sin(x) + exp(x)*cos(x), x) x ℯ ⋅sin(x) Compute `\int_{-\infty}^\infty \sin{(x^2)}\,dx`. >>> integrate(sin(x**2), (x, -oo, oo)) √2⋅√π ───── 2 Find :math:`\lim_{x\to 0}\frac{\sin{(x)}}{x}`. >>> limit(sin(x)/x, x, 0) 1 Solve `x^2 - 2 = 0`. >>> solve(x**2 - 2, x) [-√2, √2] Solve the differential equation `y'' - y = e^t`. >>> y = Function('y') >>> dsolve(Eq(y(t).diff(t, t) - y(t), exp(t)), y(t)) -t ⎛ t⎞ t y(t) = C₂⋅ℯ + ⎜C₁ + ─⎟⋅ℯ ⎝ 2⎠ Find the eigenvalues of `\left[\begin{smallmatrix}1 & 2\\2 & 2\end{smallmatrix}\right]`. >>> Matrix([[1, 2], [2, 2]]).eigenvals() ⎧3 √17 3 √17 ⎫ ⎨─ - ───: 1, ─ + ───: 1⎬ ⎩2 2 2 2 ⎭ Rewrite the Bessel function `J_{\nu}\left(z\right)` in terms of the spherical Bessel function `j_\nu(z)`. >>> besselj(nu, z).rewrite(jn) √2⋅√z⋅jn(ν - 1/2, z) ──────────────────── √π Print `\int_{0}^{\pi} \cos^{2}{\left (x \right )}\, dx` using `\mathrm{\LaTeX}`. >>> latex(Integral(cos(x)**2, (x, 0, pi))) \int\limits_{0}^{\pi} \cos^{2}{\left(x \right)}\, dx Why SymPy? ========== There are many computer algebra systems out there. `This `_ Wikipedia article lists many of them. What makes SymPy a better choice than the alternatives? First off, SymPy is completely free. It is open source, and licensed under the liberal BSD license, so you can modify the source code and even sell it if you want to. This contrasts with popular commercial systems like Maple or Mathematica that cost hundreds of dollars in licenses. Second, SymPy uses Python. Most computer algebra systems invent their own language. Not SymPy. SymPy is written entirely in Python, and is executed entirely in Python. This means that if you already know Python, it is much easier to get started with SymPy, because you already know the syntax (and if you don't know Python, it is really easy to learn). We already know that Python is a well-designed, battle-tested language. The SymPy developers are confident in their abilities in writing mathematical software, but programming language design is a completely different thing. By reusing an existing language, we are able to focus on those things that matter: the mathematics. Another computer algebra system, Sage also uses Python as its language. But Sage is large, with a download of over a gigabyte. An advantage of SymPy is that it is lightweight. In addition to being relatively small, it has no dependencies other than Python, so it can be used almost anywhere easily. Furthermore, the goals of Sage and the goals of SymPy are different. Sage aims to be a full featured system for mathematics, and aims to do so by compiling all the major open source mathematical systems together into one. When you call some function in Sage, such as ``integrate``, it calls out to one of the open source packages that it includes. In fact, SymPy is included in Sage. SymPy on the other hand aims to be an independent system, with all the features implemented in SymPy itself. A final important feature of SymPy is that it can be used as a library. Many computer algebra systems focus on being usable in interactive environments, but if you wish to automate or extend them, it is difficult to do. With SymPy, you can just as easily use it in an interactive Python environment or import it in your own Python application. SymPy also provides APIs to make it easy to extend it with your own custom functions. sympy-sympy-1.9/doc/src/tutorial/manipulation.rst000066400000000000000000000517311412543434000223630ustar00rootroot00000000000000.. _tutorial-manipulation: ================================== Advanced Expression Manipulation ================================== In this section, we discuss some ways that we can perform advanced manipulation of expressions. Understanding Expression Trees ============================== .. sidebar :: Quick Tip To play with the ``srepr`` form of expressions in the SymPy Live shell, change the output format to ``Repr`` in the settings. Before we can do this, we need to understand how expressions are represented in SymPy. A mathematical expression is represented as a tree. Let us take the expression `x^2 + xy`, i.e., ``x**2 + x*y``. We can see what this expression looks like internally by using ``srepr`` >>> from sympy import * >>> x, y, z = symbols('x y z') >>> expr = x**2 + x*y >>> srepr(expr) "Add(Pow(Symbol('x'), Integer(2)), Mul(Symbol('x'), Symbol('y')))" The easiest way to tear this apart is to look at a diagram of the expression tree: .. This comes from dotprint(x**2 + x*y, labelfunc=srepr) .. graphviz:: digraph{ # Graph style "ordering"="out" "rankdir"="TD" ######### # Nodes # ######### "Add(Pow(Symbol('x'), Integer(2)), Mul(Symbol('x'), Symbol('y')))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; "Pow(Symbol('x'), Integer(2))_(0,)" ["color"="black", "label"="Pow", "shape"="ellipse"]; "Symbol('x')_(0, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; "Integer(2)_(0, 1)" ["color"="black", "label"="Integer(2)", "shape"="ellipse"]; "Mul(Symbol('x'), Symbol('y'))_(1,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; "Symbol('x')_(1, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; "Symbol('y')_(1, 1)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; ######### # Edges # ######### "Add(Pow(Symbol('x'), Integer(2)), Mul(Symbol('x'), Symbol('y')))_()" -> "Pow(Symbol('x'), Integer(2))_(0,)"; "Add(Pow(Symbol('x'), Integer(2)), Mul(Symbol('x'), Symbol('y')))_()" -> "Mul(Symbol('x'), Symbol('y'))_(1,)"; "Pow(Symbol('x'), Integer(2))_(0,)" -> "Symbol('x')_(0, 0)"; "Pow(Symbol('x'), Integer(2))_(0,)" -> "Integer(2)_(0, 1)"; "Mul(Symbol('x'), Symbol('y'))_(1,)" -> "Symbol('x')_(1, 0)"; "Mul(Symbol('x'), Symbol('y'))_(1,)" -> "Symbol('y')_(1, 1)"; } .. note:: The above diagram was made using `Graphviz `_ and the :py:meth:`dotprint ` function. First, let's look at the leaves of this tree. Symbols are instances of the class Symbol. While we have been doing >>> x = symbols('x') we could have also done >>> x = Symbol('x') Either way, we get a Symbol with the name "x" [#symbols-fn]_. For the number in the expression, 2, we got ``Integer(2)``. ``Integer`` is the SymPy class for integers. It is similar to the Python built-in type ``int``, except that ``Integer`` plays nicely with other SymPy types. When we write ``x**2``, this creates a ``Pow`` object. ``Pow`` is short for "power". >>> srepr(x**2) "Pow(Symbol('x'), Integer(2))" We could have created the same object by calling ``Pow(x, 2)`` >>> Pow(x, 2) x**2 Note that in the ``srepr`` output, we see ``Integer(2)``, the SymPy version of integers, even though technically, we input ``2``, a Python int. In general, whenever you combine a SymPy object with a non-SymPy object via some function or operation, the non-SymPy object will be converted into a SymPy object. The function that does this is ``sympify`` [#sympify-fn]_. >>> type(2) <... 'int'> >>> type(sympify(2)) We have seen that ``x**2`` is represented as ``Pow(x, 2)``. What about ``x*y``? As we might expect, this is the multiplication of ``x`` and ``y``. The SymPy class for multiplication is ``Mul``. >>> srepr(x*y) "Mul(Symbol('x'), Symbol('y'))" Thus, we could have created the same object by writing ``Mul(x, y)``. >>> Mul(x, y) x*y Now we get to our final expression, ``x**2 + x*y``. This is the addition of our last two objects, ``Pow(x, 2)``, and ``Mul(x, y)``. The SymPy class for addition is ``Add``, so, as you might expect, to create this object, we use ``Add(Pow(x, 2), Mul(x, y))``. >>> Add(Pow(x, 2), Mul(x, y)) x**2 + x*y SymPy expression trees can have many branches, and can be quite deep or quite broad. Here is a more complicated example >>> expr = sin(x*y)/2 - x**2 + 1/y >>> srepr(expr) "Add(Mul(Integer(-1), Pow(Symbol('x'), Integer(2))), Mul(Rational(1, 2), sin(Mul(Symbol('x'), Symbol('y')))), Pow(Symbol('y'), Integer(-1)))" Here is a diagram .. dotprint(sin(x*y)/2 - x**2 + 1/y, labelfunc=srepr) .. graphviz:: digraph{ # Graph style "rankdir"="TD" ######### # Nodes # ######### "Half()_(0, 0)" ["color"="black", "label"="Rational(1, 2)", "shape"="ellipse"]; "Symbol(y)_(2, 0)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; "Symbol(x)_(1, 1, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; "Integer(2)_(1, 1, 1)" ["color"="black", "label"="Integer(2)", "shape"="ellipse"]; "NegativeOne()_(2, 1)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; "NegativeOne()_(1, 0)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; "Symbol(y)_(0, 1, 0, 1)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; "Symbol(x)_(0, 1, 0, 0)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; "Pow(Symbol(x), Integer(2))_(1, 1)" ["color"="black", "label"="Pow", "shape"="ellipse"]; "Pow(Symbol(y), NegativeOne())_(2,)" ["color"="black", "label"="Pow", "shape"="ellipse"]; "Mul(Symbol(x), Symbol(y))_(0, 1, 0)" ["color"="black", "label"="Mul", "shape"="ellipse"]; "sin(Mul(Symbol(x), Symbol(y)))_(0, 1)" ["color"="black", "label"="sin", "shape"="ellipse"]; "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; ######### # Edges # ######### "Pow(Symbol(y), NegativeOne())_(2,)" -> "Symbol(y)_(2, 0)"; "Pow(Symbol(x), Integer(2))_(1, 1)" -> "Symbol(x)_(1, 1, 0)"; "Pow(Symbol(x), Integer(2))_(1, 1)" -> "Integer(2)_(1, 1, 1)"; "Pow(Symbol(y), NegativeOne())_(2,)" -> "NegativeOne()_(2, 1)"; "Mul(Symbol(x), Symbol(y))_(0, 1, 0)" -> "Symbol(x)_(0, 1, 0, 0)"; "Mul(Symbol(x), Symbol(y))_(0, 1, 0)" -> "Symbol(y)_(0, 1, 0, 1)"; "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)" -> "Half()_(0, 0)"; "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)" -> "NegativeOne()_(1, 0)"; "sin(Mul(Symbol(x), Symbol(y)))_(0, 1)" -> "Mul(Symbol(x), Symbol(y))_(0, 1, 0)"; "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)" -> "Pow(Symbol(x), Integer(2))_(1, 1)"; "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)" -> "sin(Mul(Symbol(x), Symbol(y)))_(0, 1)"; "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" -> "Pow(Symbol(y), NegativeOne())_(2,)"; "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" -> "Mul(Half(), sin(Mul(Symbol(x), Symbol(y))))_(0,)"; "Add(Mul(Half(), sin(Mul(Symbol(x), Symbol(y)))), Mul(NegativeOne(), Pow(Symbol(x), Integer(2))), Pow(Symbol(y), NegativeOne()))_()" -> "Mul(NegativeOne(), Pow(Symbol(x), Integer(2)))_(1,)"; } This expression reveals some interesting things about SymPy expression trees. Let's go through them one by one. Let's first look at the term ``x**2``. As we expected, we see ``Pow(x, 2)``. One level up, we see we have ``Mul(-1, Pow(x, 2))``. There is no subtraction class in SymPy. ``x - y`` is represented as ``x + -y``, or, more completely, ``x + -1*y``, i.e., ``Add(x, Mul(-1, y))``. >>> srepr(x - y) "Add(Symbol('x'), Mul(Integer(-1), Symbol('y')))" .. dotprint(x - y, labelfunc=srepr) .. graphviz:: digraph{ # Graph style "rankdir"="TD" ######### # Nodes # ######### "Symbol(x)_(1,)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; "Symbol(y)_(0, 1)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; "NegativeOne()_(0, 0)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; "Mul(NegativeOne(), Symbol(y))_(0,)" ["color"="black", "label"="Mul", "shape"="ellipse"]; "Add(Mul(NegativeOne(), Symbol(y)), Symbol(x))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; ######### # Edges # ######### "Mul(NegativeOne(), Symbol(y))_(0,)" -> "Symbol(y)_(0, 1)"; "Mul(NegativeOne(), Symbol(y))_(0,)" -> "NegativeOne()_(0, 0)"; "Add(Mul(NegativeOne(), Symbol(y)), Symbol(x))_()" -> "Symbol(x)_(1,)"; "Add(Mul(NegativeOne(), Symbol(y)), Symbol(x))_()" -> "Mul(NegativeOne(), Symbol(y))_(0,)"; } Next, look at ``1/y``. We might expect to see something like ``Div(1, y)``, but similar to subtraction, there is no class in SymPy for division. Rather, division is represented by a power of -1. Hence, we have ``Pow(y, -1)``. What if we had divided something other than 1 by ``y``, like ``x/y``? Let's see. >>> expr = x/y >>> srepr(expr) "Mul(Symbol('x'), Pow(Symbol('y'), Integer(-1)))" .. dotprint(x/y, labelfunc=srepr) .. graphviz:: digraph{ # Graph style "rankdir"="TD" ######### # Nodes # ######### "Symbol(x)_(0,)" ["color"="black", "label"="Symbol('x')", "shape"="ellipse"]; "Symbol(y)_(1, 0)" ["color"="black", "label"="Symbol('y')", "shape"="ellipse"]; "NegativeOne()_(1, 1)" ["color"="black", "label"="Integer(-1)", "shape"="ellipse"]; "Pow(Symbol(y), NegativeOne())_(1,)" ["color"="black", "label"="Pow", "shape"="ellipse"]; "Mul(Symbol(x), Pow(Symbol(y), NegativeOne()))_()" ["color"="black", "label"="Mul", "shape"="ellipse"]; ######### # Edges # ######### "Pow(Symbol(y), NegativeOne())_(1,)" -> "Symbol(y)_(1, 0)"; "Pow(Symbol(y), NegativeOne())_(1,)" -> "NegativeOne()_(1, 1)"; "Mul(Symbol(x), Pow(Symbol(y), NegativeOne()))_()" -> "Symbol(x)_(0,)"; "Mul(Symbol(x), Pow(Symbol(y), NegativeOne()))_()" -> "Pow(Symbol(y), NegativeOne())_(1,)"; } We see that ``x/y`` is represented as ``x*y**-1``, i.e., ``Mul(x, Pow(y, -1))``. Finally, let's look at the ``sin(x*y)/2`` term. Following the pattern of the previous example, we might expect to see ``Mul(sin(x*y), Pow(Integer(2), -1))``. But instead, we have ``Mul(Rational(1, 2), sin(x*y))``. Rational numbers are always combined into a single term in a multiplication, so that when we divide by 2, it is represented as multiplying by 1/2. Finally, one last note. You may have noticed that the order we entered our expression and the order that it came out from ``srepr`` or in the graph were different. You may have also noticed this phenomenon earlier in the tutorial. For example >>> 1 + x x + 1 This because in SymPy, the arguments of the commutative operations ``Add`` and ``Mul`` are stored in an arbitrary (but consistent!) order, which is independent of the order inputted (if you're worried about noncommutative multiplication, don't be. In SymPy, you can create noncommutative Symbols using ``Symbol('A', commutative=False)``, and the order of multiplication for noncommutative Symbols is kept the same as the input). Furthermore, as we shall see in the next section, the printing order and the order in which things are stored internally need not be the same either. .. sidebar:: Quick Tip The way an expression is represented internally and the way it is printed are often not the same. In general, an important thing to keep in mind when working with SymPy expression trees is this: the internal representation of an expression and the way it is printed need not be the same. The same is true for the input form. If some expression manipulation algorithm is not working in the way you expected it to, chances are, the internal representation of the object is different from what you thought it was. Recursing through an Expression Tree ==================================== Now that you know how expression trees work in SymPy, let's look at how to dig our way through an expression tree. Every object in SymPy has two very important attributes, ``func``, and ``args``. func ---- ``func`` is the head of the object. For example, ``(x*y).func`` is ``Mul``. Usually it is the same as the class of the object (though there are exceptions to this rule). Two notes about ``func``. First, the class of an object need not be the same as the one used to create it. For example >>> expr = Add(x, x) >>> expr.func We created ``Add(x, x)``, so we might expect ``expr.func`` to be ``Add``, but instead we got ``Mul``. Why is that? Let's take a closer look at ``expr``. >>> expr 2*x ``Add(x, x)``, i.e., ``x + x``, was automatically converted into ``Mul(2, x)``, i.e., ``2*x``, which is a ``Mul``. SymPy classes make heavy use of the ``__new__`` class constructor, which, unlike ``__init__``, allows a different class to be returned from the constructor. Second, some classes are special-cased, usually for efficiency reasons [#singleton-fn]_. >>> Integer(2).func >>> Integer(0).func >>> Integer(-1).func For the most part, these issues will not bother us. The special classes ``Zero``, ``One``, ``NegativeOne``, and so on are subclasses of ``Integer``, so as long as you use ``isinstance``, it will not be an issue. args ---- ``args`` are the top-level arguments of the object. ``(x*y).args`` would be ``(x, y)``. Let's look at some examples >>> expr = 3*y**2*x >>> expr.func >>> expr.args (3, x, y**2) From this, we can see that ``expr == Mul(3, y**2, x)``. In fact, we can see that we can completely reconstruct ``expr`` from its ``func`` and its ``args``. >>> expr.func(*expr.args) 3*x*y**2 >>> expr == expr.func(*expr.args) True Note that although we entered ``3*y**2*x``, the ``args`` are ``(3, x, y**2)``. In a ``Mul``, the Rational coefficient will come first in the ``args``, but other than that, the order of everything else follows no special pattern. To be sure, though, there is an order. >>> expr = y**2*3*x >>> expr.args (3, x, y**2) Mul's ``args`` are sorted, so that the same ``Mul`` will have the same ``args``. But the sorting is based on some criteria designed to make the sorting unique and efficient that has no mathematical significance. The ``srepr`` form of our ``expr`` is ``Mul(3, x, Pow(y, 2))``. What if we want to get at the ``args`` of ``Pow(y, 2)``. Notice that the ``y**2`` is in the third slot of ``expr.args``, i.e., ``expr.args[2]``. >>> expr.args[2] y**2 So to get the ``args`` of this, we call ``expr.args[2].args``. >>> expr.args[2].args (y, 2) Now what if we try to go deeper. What are the args of ``y``. Or ``2``. Let's see. >>> y.args () >>> Integer(2).args () They both have empty ``args``. In SymPy, empty ``args`` signal that we have hit a leaf of the expression tree. So there are two possibilities for a SymPy expression. Either it has empty ``args``, in which case it is a leaf node in any expression tree, or it has ``args``, in which case, it is a branch node of any expression tree. When it has ``args``, it can be completely rebuilt from its ``func`` and its ``args``. This is expressed in the key invariant. .. topic:: Key Invariant Every well-formed SymPy expression must either have empty ``args`` or satisfy ``expr == expr.func(*expr.args)``. (Recall that in Python if ``a`` is a tuple, then ``f(*a)`` means to call ``f`` with arguments from the elements of ``a``, e.g., ``f(*(1, 2, 3))`` is the same as ``f(1, 2, 3)``.) This key invariant allows us to write simple algorithms that walk expression trees, change them, and rebuild them into new expressions. Walking the Tree ---------------- With this knowledge, let's look at how we can recurse through an expression tree. The nested nature of ``args`` is a perfect fit for recursive functions. The base case will be empty ``args``. Let's write a simple function that goes through an expression and prints all the ``args`` at each level. >>> def pre(expr): ... print(expr) ... for arg in expr.args: ... pre(arg) See how nice it is that ``()`` signals leaves in the expression tree. We don't even have to write a base case for our recursion; it is handled automatically by the for loop. Let's test our function. >>> expr = x*y + 1 >>> pre(expr) x*y + 1 1 x*y x y Can you guess why we called our function ``pre``? We just wrote a pre-order traversal function for our expression tree. See if you can write a post-order traversal function. Such traversals are so common in SymPy that the generator functions ``preorder_traversal`` and ``postorder_traversal`` are provided to make such traversals easy. We could have also written our algorithm as >>> for arg in preorder_traversal(expr): ... print(arg) x*y + 1 1 x*y x y Prevent expression evaluation ============================= There are generally two ways to prevent the evaluation, either pass an ``evaluate=False`` parameter while constructing the expression, or create an evaluation stopper by wrapping the expression with ``UnevaluatedExpr``. For example: >>> from sympy import Add >>> from sympy.abc import x, y, z >>> x + x 2*x >>> Add(x, x) 2*x >>> Add(x, x, evaluate=False) x + x If you don't remember the class corresponding to the expression you want to build (operator overloading usually assumes ``evaluate=True``), just use ``sympify`` and pass a string: >>> from sympy import sympify >>> sympify("x + x", evaluate=False) x + x Note that ``evaluate=False`` won't prevent future evaluation in later usages of the expression: >>> expr = Add(x, x, evaluate=False) >>> expr x + x >>> expr + x 3*x That's why the class ``UnevaluatedExpr`` comes handy. ``UnevaluatedExpr`` is a method provided by SymPy which lets the user keep an expression unevaluated. By *unevaluated* it is meant that the value inside of it will not interact with the expressions outside of it to give simplified outputs. For example: >>> from sympy import UnevaluatedExpr >>> expr = x + UnevaluatedExpr(x) >>> expr x + x >>> x + expr 2*x + x The `x` remaining alone is the `x` wrapped by ``UnevaluatedExpr``. To release it: >>> (x + expr).doit() 3*x Other examples: >>> from sympy import * >>> from sympy.abc import x, y, z >>> uexpr = UnevaluatedExpr(S.One*5/7)*UnevaluatedExpr(S.One*3/4) >>> uexpr (5/7)*(3/4) >>> x*UnevaluatedExpr(1/x) x*1/x A point to be noted is that ``UnevaluatedExpr`` cannot prevent the evaluation of an expression which is given as argument. For example: >>> expr1 = UnevaluatedExpr(x + x) >>> expr1 2*x >>> expr2 = sympify('x + x', evaluate=False) >>> expr2 x + x Remember that ``expr2`` will be evaluated if included into another expression. Combine both of the methods to prevent both inside and outside evaluations: >>> UnevaluatedExpr(sympify("x + x", evaluate=False)) + y y + x + x ``UnevalutedExpr`` is supported by SymPy printers and can be used to print the result in different output forms. For example >>> from sympy import latex >>> uexpr = UnevaluatedExpr(S.One*5/7)*UnevaluatedExpr(S.One*3/4) >>> print(latex(uexpr)) \frac{5}{7} \frac{3}{4} In order to release the expression and get the evaluated LaTeX form, just use ``.doit()``: >>> print(latex(uexpr.doit())) \frac{15}{28} .. rubric:: Footnotes .. [#symbols-fn] We have been using ``symbols`` instead of ``Symbol`` because it automatically splits apart strings into multiple ``Symbol``\ s. ``symbols('x y z')`` returns a tuple of three ``Symbol``\ s. ``Symbol('x y z')`` returns a single ``Symbol`` called ``x y z``. .. [#sympify-fn] Technically, it is an internal function called ``_sympify``, which differs from ``sympify`` in that it does not convert strings. ``x + '2'`` is not allowed. .. [#singleton-fn] Classes like ``One`` and ``Zero`` are singletonized, meaning that only one object is ever created, no matter how many times the class is called. This is done for space efficiency, as these classes are very common. For example, ``Zero`` might occur very often in a sparse matrix represented densely. As we have seen, ``NegativeOne`` occurs any time we have ``-x`` or ``1/x``. It is also done for speed efficiency because singletonized objects can be compared by ``is``. The unique objects for each singletonized class can be accessed from the ``S`` object. sympy-sympy-1.9/doc/src/tutorial/matrices.rst000066400000000000000000000431621412543434000214710ustar00rootroot00000000000000.. _matrices: ========== Matrices ========== >>> from sympy import * >>> init_printing(use_unicode=True) To make a matrix in SymPy, use the ``Matrix`` object. A matrix is constructed by providing a list of row vectors that make up the matrix. For example, to construct the matrix .. math:: \left[\begin{array}{cc}1 & -1\\3 & 4\\0 & 2\end{array}\right] use >>> Matrix([[1, -1], [3, 4], [0, 2]]) ⎡1 -1⎤ ⎢ ⎥ ⎢3 4 ⎥ ⎢ ⎥ ⎣0 2 ⎦ To make it easy to make column vectors, a list of elements is considered to be a column vector. >>> Matrix([1, 2, 3]) ⎡1⎤ ⎢ ⎥ ⎢2⎥ ⎢ ⎥ ⎣3⎦ Matrices are manipulated just like any other object in SymPy or Python. >>> M = Matrix([[1, 2, 3], [3, 2, 1]]) >>> N = Matrix([0, 1, 1]) >>> M*N ⎡5⎤ ⎢ ⎥ ⎣3⎦ One important thing to note about SymPy matrices is that, unlike every other object in SymPy, they are mutable. This means that they can be modified in place, as we will see below. The downside to this is that ``Matrix`` cannot be used in places that require immutability, such as inside other SymPy expressions or as keys to dictionaries. If you need an immutable version of ``Matrix``, use ``ImmutableMatrix``. Basic Operations ================ Here are some basic operations on ``Matrix``. Shape ----- To get the shape of a matrix, use :func:`~.shape()` function. >>> from sympy import shape >>> M = Matrix([[1, 2, 3], [-2, 0, 4]]) >>> M ⎡1 2 3⎤ ⎢ ⎥ ⎣-2 0 4⎦ >>> shape(M) (2, 3) Accessing Rows and Columns -------------------------- To get an individual row or column of a matrix, use ``row`` or ``col``. For example, ``M.row(0)`` will get the first row. ``M.col(-1)`` will get the last column. >>> M.row(0) [1 2 3] >>> M.col(-1) ⎡3⎤ ⎢ ⎥ ⎣4⎦ Deleting and Inserting Rows and Columns --------------------------------------- To delete a row or column, use ``row_del`` or ``col_del``. These operations will modify the Matrix **in place**. >>> M.col_del(0) >>> M ⎡2 3⎤ ⎢ ⎥ ⎣0 4⎦ >>> M.row_del(1) >>> M [2 3] .. TODO: This is a mess. See issue 6992. To insert rows or columns, use ``row_insert`` or ``col_insert``. These operations **do not** operate in place. >>> M [2 3] >>> M = M.row_insert(1, Matrix([[0, 4]])) >>> M ⎡2 3⎤ ⎢ ⎥ ⎣0 4⎦ >>> M = M.col_insert(0, Matrix([1, -2])) >>> M ⎡1 2 3⎤ ⎢ ⎥ ⎣-2 0 4⎦ Unless explicitly stated, the methods mentioned below do not operate in place. In general, a method that does not operate in place will return a new ``Matrix`` and a method that does operate in place will return ``None``. Basic Methods ============= As noted above, simple operations like addition and multiplication are done just by using ``+``, ``*``, and ``**``. To find the inverse of a matrix, just raise it to the ``-1`` power. >>> M = Matrix([[1, 3], [-2, 3]]) >>> N = Matrix([[0, 3], [0, 7]]) >>> M + N ⎡1 6 ⎤ ⎢ ⎥ ⎣-2 10⎦ >>> M*N ⎡0 24⎤ ⎢ ⎥ ⎣0 15⎦ >>> 3*M ⎡3 9⎤ ⎢ ⎥ ⎣-6 9⎦ >>> M**2 ⎡-5 12⎤ ⎢ ⎥ ⎣-8 3 ⎦ >>> M**-1 ⎡1/3 -1/3⎤ ⎢ ⎥ ⎣2/9 1/9 ⎦ >>> N**-1 Traceback (most recent call last): ... NonInvertibleMatrixError: Matrix det == 0; not invertible. To take the transpose of a Matrix, use ``T``. >>> M = Matrix([[1, 2, 3], [4, 5, 6]]) >>> M ⎡1 2 3⎤ ⎢ ⎥ ⎣4 5 6⎦ >>> M.T ⎡1 4⎤ ⎢ ⎥ ⎢2 5⎥ ⎢ ⎥ ⎣3 6⎦ Matrix Constructors =================== Several constructors exist for creating common matrices. To create an identity matrix, use ``eye``. ``eye(n)`` will create an `n\times n` identity matrix. >>> eye(3) ⎡1 0 0⎤ ⎢ ⎥ ⎢0 1 0⎥ ⎢ ⎥ ⎣0 0 1⎦ >>> eye(4) ⎡1 0 0 0⎤ ⎢ ⎥ ⎢0 1 0 0⎥ ⎢ ⎥ ⎢0 0 1 0⎥ ⎢ ⎥ ⎣0 0 0 1⎦ To create a matrix of all zeros, use ``zeros``. ``zeros(n, m)`` creates an `n\times m` matrix of `0`\ s. >>> zeros(2, 3) ⎡0 0 0⎤ ⎢ ⎥ ⎣0 0 0⎦ Similarly, ``ones`` creates a matrix of ones. >>> ones(3, 2) ⎡1 1⎤ ⎢ ⎥ ⎢1 1⎥ ⎢ ⎥ ⎣1 1⎦ To create diagonal matrices, use ``diag``. The arguments to ``diag`` can be either numbers or matrices. A number is interpreted as a `1\times 1` matrix. The matrices are stacked diagonally. The remaining elements are filled with `0`\ s. >>> diag(1, 2, 3) ⎡1 0 0⎤ ⎢ ⎥ ⎢0 2 0⎥ ⎢ ⎥ ⎣0 0 3⎦ >>> diag(-1, ones(2, 2), Matrix([5, 7, 5])) ⎡-1 0 0 0⎤ ⎢ ⎥ ⎢0 1 1 0⎥ ⎢ ⎥ ⎢0 1 1 0⎥ ⎢ ⎥ ⎢0 0 0 5⎥ ⎢ ⎥ ⎢0 0 0 7⎥ ⎢ ⎥ ⎣0 0 0 5⎦ Advanced Methods ================ Determinant ----------- To compute the determinant of a matrix, use ``det``. >>> M = Matrix([[1, 0, 1], [2, -1, 3], [4, 3, 2]]) >>> M ⎡1 0 1⎤ ⎢ ⎥ ⎢2 -1 3⎥ ⎢ ⎥ ⎣4 3 2⎦ >>> M.det() -1 RREF ---- To put a matrix into reduced row echelon form, use ``rref``. ``rref`` returns a tuple of two elements. The first is the reduced row echelon form, and the second is a tuple of indices of the pivot columns. >>> M = Matrix([[1, 0, 1, 3], [2, 3, 4, 7], [-1, -3, -3, -4]]) >>> M ⎡1 0 1 3 ⎤ ⎢ ⎥ ⎢2 3 4 7 ⎥ ⎢ ⎥ ⎣-1 -3 -3 -4⎦ >>> M.rref() ⎛⎡1 0 1 3 ⎤ ⎞ ⎜⎢ ⎥ ⎟ ⎜⎢0 1 2/3 1/3⎥, (0, 1)⎟ ⎜⎢ ⎥ ⎟ ⎝⎣0 0 0 0 ⎦ ⎠ .. Note:: The first element of the tuple returned by ``rref`` is of type ``Matrix``. The second is of type ``tuple``. Nullspace --------- To find the nullspace of a matrix, use ``nullspace``. ``nullspace`` returns a ``list`` of column vectors that span the nullspace of the matrix. >>> M = Matrix([[1, 2, 3, 0, 0], [4, 10, 0, 0, 1]]) >>> M ⎡1 2 3 0 0⎤ ⎢ ⎥ ⎣4 10 0 0 1⎦ >>> M.nullspace() ⎡⎡-15⎤ ⎡0⎤ ⎡ 1 ⎤⎤ ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ ⎢⎢ 6 ⎥ ⎢0⎥ ⎢-1/2⎥⎥ ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ ⎢⎢ 1 ⎥, ⎢0⎥, ⎢ 0 ⎥⎥ ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ ⎢⎢ 0 ⎥ ⎢1⎥ ⎢ 0 ⎥⎥ ⎢⎢ ⎥ ⎢ ⎥ ⎢ ⎥⎥ ⎣⎣ 0 ⎦ ⎣0⎦ ⎣ 1 ⎦⎦ Columnspace ----------- To find the columnspace of a matrix, use ``columnspace``. ``columnspace`` returns a ``list`` of column vectors that span the columnspace of the matrix. >>> M = Matrix([[1, 1, 2], [2 ,1 , 3], [3 , 1, 4]]) >>> M ⎡1 1 2⎤ ⎢ ⎥ ⎢2 1 3⎥ ⎢ ⎥ ⎣3 1 4⎦ >>> M.columnspace() ⎡⎡1⎤ ⎡1⎤⎤ ⎢⎢ ⎥ ⎢ ⎥⎥ ⎢⎢2⎥, ⎢1⎥⎥ ⎢⎢ ⎥ ⎢ ⎥⎥ ⎣⎣3⎦ ⎣1⎦⎦ Eigenvalues, Eigenvectors, and Diagonalization ---------------------------------------------- To find the eigenvalues of a matrix, use ``eigenvals``. ``eigenvals`` returns a dictionary of ``eigenvalue: algebraic_multiplicity`` pairs (similar to the output of :ref:`roots `). >>> M = Matrix([[3, -2, 4, -2], [5, 3, -3, -2], [5, -2, 2, -2], [5, -2, -3, 3]]) >>> M ⎡3 -2 4 -2⎤ ⎢ ⎥ ⎢5 3 -3 -2⎥ ⎢ ⎥ ⎢5 -2 2 -2⎥ ⎢ ⎥ ⎣5 -2 -3 3 ⎦ >>> M.eigenvals() {-2: 1, 3: 1, 5: 2} This means that ``M`` has eigenvalues -2, 3, and 5, and that the eigenvalues -2 and 3 have algebraic multiplicity 1 and that the eigenvalue 5 has algebraic multiplicity 2. To find the eigenvectors of a matrix, use ``eigenvects``. ``eigenvects`` returns a list of tuples of the form ``(eigenvalue, algebraic_multiplicity, [eigenvectors])``. >>> M.eigenvects() ⎡⎛ ⎡⎡0⎤⎤⎞ ⎛ ⎡⎡1⎤⎤⎞ ⎛ ⎡⎡1⎤ ⎡0 ⎤⎤⎞⎤ ⎢⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥ ⎢ ⎥⎥⎟⎥ ⎢⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥ ⎢-1⎥⎥⎟⎥ ⎢⎜-2, 1, ⎢⎢ ⎥⎥⎟, ⎜3, 1, ⎢⎢ ⎥⎥⎟, ⎜5, 2, ⎢⎢ ⎥, ⎢ ⎥⎥⎟⎥ ⎢⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥⎥⎟ ⎜ ⎢⎢1⎥ ⎢0 ⎥⎥⎟⎥ ⎢⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥⎥⎟ ⎜ ⎢⎢ ⎥ ⎢ ⎥⎥⎟⎥ ⎣⎝ ⎣⎣1⎦⎦⎠ ⎝ ⎣⎣1⎦⎦⎠ ⎝ ⎣⎣0⎦ ⎣1 ⎦⎦⎠⎦ This shows us that, for example, the eigenvalue 5 also has geometric multiplicity 2, because it has two eigenvectors. Because the algebraic and geometric multiplicities are the same for all the eigenvalues, ``M`` is diagonalizable. To diagonalize a matrix, use ``diagonalize``. ``diagonalize`` returns a tuple `(P, D)`, where `D` is diagonal and `M = PDP^{-1}`. >>> P, D = M.diagonalize() >>> P ⎡0 1 1 0 ⎤ ⎢ ⎥ ⎢1 1 1 -1⎥ ⎢ ⎥ ⎢1 1 1 0 ⎥ ⎢ ⎥ ⎣1 1 0 1 ⎦ >>> D ⎡-2 0 0 0⎤ ⎢ ⎥ ⎢0 3 0 0⎥ ⎢ ⎥ ⎢0 0 5 0⎥ ⎢ ⎥ ⎣0 0 0 5⎦ >>> P*D*P**-1 ⎡3 -2 4 -2⎤ ⎢ ⎥ ⎢5 3 -3 -2⎥ ⎢ ⎥ ⎢5 -2 2 -2⎥ ⎢ ⎥ ⎣5 -2 -3 3 ⎦ >>> P*D*P**-1 == M True .. sidebar:: Quick Tip ``lambda`` is a reserved keyword in Python, so to create a Symbol called `\lambda`, while using the same names for SymPy Symbols and Python variables, use ``lamda`` (without the ``b``). It will still pretty print as `\lambda`. Note that since ``eigenvects`` also includes the eigenvalues, you should use it instead of ``eigenvals`` if you also want the eigenvectors. However, as computing the eigenvectors may often be costly, ``eigenvals`` should be preferred if you only wish to find the eigenvalues. If all you want is the characteristic polynomial, use ``charpoly``. This is more efficient than ``eigenvals``, because sometimes symbolic roots can be expensive to calculate. >>> lamda = symbols('lamda') >>> p = M.charpoly(lamda) >>> factor(p.as_expr()) 2 (λ - 5) ⋅(λ - 3)⋅(λ + 2) .. TODO: Add an example for ``jordan_form``, once it is fully implemented. Possible Issues =============== Zero Testing ------------ If your matrix operations are failing or returning wrong answers, the common reasons would likely be from zero testing. If there is an expression not properly zero-tested, it can possibly bring issues in finding pivots for gaussian elimination, or deciding whether the matrix is inversible, or any high level functions which relies on the prior procedures. Currently, the SymPy's default method of zero testing ``_iszero`` is only guaranteed to be accurate in some limited domain of numerics and symbols, and any complicated expressions beyond its decidability are treated as ``None``, which behaves similarly to logical ``False``. The list of methods using zero testing procedures are as follows: ``echelon_form`` , ``is_echelon`` , ``rank`` , ``rref`` , ``nullspace`` , ``eigenvects`` , ``inverse_ADJ`` , ``inverse_GE`` , ``inverse_LU`` , ``LUdecomposition`` , ``LUdecomposition_Simple`` , ``LUsolve`` They have property ``iszerofunc`` opened up for user to specify zero testing method, which can accept any function with single input and boolean output, while being defaulted with ``_iszero``. Here is an example of solving an issue caused by undertested zero. While the output for this particular matrix has since been improved, the technique below is still of interest. [#zerotestexampleidea-fn]_ [#zerotestexamplediscovery-fn]_ [#zerotestexampleimproved-fn]_ >>> from sympy import * >>> q = Symbol("q", positive = True) >>> m = Matrix([ ... [-2*cosh(q/3), exp(-q), 1], ... [ exp(q), -2*cosh(q/3), 1], ... [ 1, 1, -2*cosh(q/3)]]) >>> m.nullspace() # doctest: +SKIP [] You can trace down which expression is being underevaluated, by injecting a custom zero test with warnings enabled. >>> import warnings >>> >>> def my_iszero(x): ... try: ... result = x.is_zero ... except AttributeError: ... result = None ... ... # Warnings if evaluated into None ... if result is None: ... warnings.warn("Zero testing of {} evaluated into None".format(x)) ... return result ... >>> m.nullspace(iszerofunc=my_iszero) # doctest: +SKIP __main__:9: UserWarning: Zero testing of 4*cosh(q/3)**2 - 1 evaluated into None __main__:9: UserWarning: Zero testing of (-exp(q) - 2*cosh(q/3))*(-2*cosh(q/3) - exp(-q)) - (4*cosh(q/3)**2 - 1)**2 evaluated into None __main__:9: UserWarning: Zero testing of 2*exp(q)*cosh(q/3) - 16*cosh(q/3)**4 + 12*cosh(q/3)**2 + 2*exp(-q)*cosh(q/3) evaluated into None __main__:9: UserWarning: Zero testing of -(4*cosh(q/3)**2 - 1)*exp(-q) - 2*cosh(q/3) - exp(-q) evaluated into None [] In this case, ``(-exp(q) - 2*cosh(q/3))*(-2*cosh(q/3) - exp(-q)) - (4*cosh(q/3)**2 - 1)**2`` should yield zero, but the zero testing had failed to catch. possibly meaning that a stronger zero test should be introduced. For this specific example, rewriting to exponentials and applying simplify would make zero test stronger for hyperbolics, while being harmless to other polynomials or transcendental functions. >>> def my_iszero(x): ... try: ... result = x.rewrite(exp).simplify().is_zero ... except AttributeError: ... result = None ... ... # Warnings if evaluated into None ... if result is None: ... warnings.warn("Zero testing of {} evaluated into None".format(x)) ... return result ... >>> m.nullspace(iszerofunc=my_iszero) # doctest: +SKIP __main__:9: UserWarning: Zero testing of -2*cosh(q/3) - exp(-q) evaluated into None ⎡⎡ ⎛ q ⎛q⎞⎞ -q 2⎛q⎞ ⎤⎤ ⎢⎢- ⎜- ℯ - 2⋅cosh⎜─⎟⎟⋅ℯ + 4⋅cosh ⎜─⎟ - 1⎥⎥ ⎢⎢ ⎝ ⎝3⎠⎠ ⎝3⎠ ⎥⎥ ⎢⎢─────────────────────────────────────────⎥⎥ ⎢⎢ ⎛ 2⎛q⎞ ⎞ ⎛q⎞ ⎥⎥ ⎢⎢ 2⋅⎜4⋅cosh ⎜─⎟ - 1⎟⋅cosh⎜─⎟ ⎥⎥ ⎢⎢ ⎝ ⎝3⎠ ⎠ ⎝3⎠ ⎥⎥ ⎢⎢ ⎥⎥ ⎢⎢ ⎛ q ⎛q⎞⎞ ⎥⎥ ⎢⎢ -⎜- ℯ - 2⋅cosh⎜─⎟⎟ ⎥⎥ ⎢⎢ ⎝ ⎝3⎠⎠ ⎥⎥ ⎢⎢ ──────────────────── ⎥⎥ ⎢⎢ 2⎛q⎞ ⎥⎥ ⎢⎢ 4⋅cosh ⎜─⎟ - 1 ⎥⎥ ⎢⎢ ⎝3⎠ ⎥⎥ ⎢⎢ ⎥⎥ ⎣⎣ 1 ⎦⎦ You can clearly see ``nullspace`` returning proper result, after injecting an alternative zero test. Note that this approach is only valid for some limited cases of matrices containing only numerics, hyperbolics, and exponentials. For other matrices, you should use different method opted for their domains. Possible suggestions would be either taking advantage of rewriting and simplifying, with tradeoff of speed [#zerotestsimplifysolution-fn]_ , or using random numeric testing, with tradeoff of accuracy [#zerotestnumerictestsolution-fn]_ . If you wonder why there is no generic algorithm for zero testing that can work with any symbolic entities, it's because of the constant problem stating that zero testing is undecidable [#constantproblemwikilink-fn]_ , and not only the SymPy, but also other computer algebra systems [#mathematicazero-fn]_ [#matlabzero-fn]_ would face the same fundamental issue. However, discovery of any zero test failings can provide some good examples to improve SymPy, so if you have encountered one, you can report the issue to SymPy issue tracker [#sympyissues-fn]_ to get detailed help from the community. .. rubric:: Footnotes .. [#zerotestexampleidea-fn] Inspired by https://gitter.im/sympy/sympy?at=5b7c3e8ee5b40332abdb206c .. [#zerotestexamplediscovery-fn] Discovered from https://github.com/sympy/sympy/issues/15141 .. [#zerotestexampleimproved-fn] Improved by https://github.com/sympy/sympy/pull/19548 .. [#zerotestsimplifysolution-fn] Suggested from https://github.com/sympy/sympy/issues/10120 .. [#zerotestnumerictestsolution-fn] Suggested from https://github.com/sympy/sympy/issues/10279 .. [#constantproblemwikilink-fn] https://en.wikipedia.org/wiki/Constant_problem .. [#mathematicazero-fn] How mathematica tests zero https://reference.wolfram.com/language/ref/PossibleZeroQ.html .. [#matlabzero-fn] How matlab tests zero https://www.mathworks.com/help/symbolic/mupad_ref/iszero.html .. [#sympyissues-fn] https://github.com/sympy/sympy/issues sympy-sympy-1.9/doc/src/tutorial/preliminaries.rst000066400000000000000000000115461412543434000225260ustar00rootroot00000000000000=============== Preliminaries =============== This tutorial assumes that the reader already knows the basics of the Python programming language. If you do not, the `official Python tutorial `_ is excellent. This tutorial assumes a decent mathematical background. Most examples require knowledge lower than a calculus level, and some require knowledge at a calculus level. Some of the advanced features require more than this. If you come across a section that uses some mathematical function you are not familiar with, you can probably skip over it, or replace it with a similar one that you are more familiar with. Or look up the function on Wikipedia and learn something new. Some important mathematical concepts that are not common knowledge will be introduced as necessary. Installation ============ .. sidebar:: Quick Tip You do not need to install SymPy to try it. You can use the online shell at http://live.sympy.org, or the shell at the bottom right of this documentation page. You will need to install SymPy first. See the :ref:`installation guide `. Alternately, you can just use the SymPy Live Sphinx extension to run the code blocks in the browser. For example, click on the green "Run code block in SymPy Live" button below >>> from sympy import * >>> x = symbols('x') >>> a = Integral(cos(x)*exp(x), x) >>> Eq(a, a.doit()) Eq(Integral(exp(x)*cos(x), x), exp(x)*sin(x)/2 + exp(x)*cos(x)/2) The SymPy Live shell in the bottom corner will pop up and evaluate the code block. You can also click any individual line to evaluate it one at a time. The SymPy Live shell is a fully interactive Python shell. You can type any expression in the input box to evaluate it. Feel free to use it throughout the tutorial to experiment. To show or hide the SymPy Live shell at any time, just click the green button on the bottom right of the screen. By default, the SymPy Live shell uses `\mathrm{\LaTeX}` for output. If you want the output to look more like the output in the documentation, change the output format to ``Str`` or ``Unicode`` in the settings. If you wish to modify an example before evaluating it, change the evaluation mode to "copy" in the SymPy Live settings. This will cause clicking on an example to copy the example to the SymPy Live shell, but not evaluate it, allowing you to change it before execution. You can also use the up/down arrow keys on your keyboard in the input box to move through the shell history. The SymPy Live shell is also available at http://live.sympy.org, with extra features, like a mobile phone enhanced version and saved history. Exercises ========= This tutorial was the basis for a tutorial given at the 2013 SciPy conference in Austin, TX. The website for that tutorial is `here `_. It has links to videos, materials, and IPython notebook exercises. The IPython notebook exercises in particular are recommended to anyone going through this tutorial. About This Tutorial =================== This tutorial aims to give an introduction to SymPy for someone who has not used the library before. Many features of SymPy will be introduced in this tutorial, but they will not be exhaustive. In fact, virtually every functionality shown in this tutorial will have more options or capabilities than what will be shown. The rest of the SymPy documentation serves as API documentation, which extensively lists every feature and option of each function. These are the goals of this tutorial: .. NB: This is mainly here for you, the person who is editing and adding to this tutorial. Try to keep these principles in mind. - To give a guide, suitable for someone who has never used SymPy (but who has used Python and knows the necessary mathematics). - To be written in a narrative format, which is both easy and fun to follow. It should read like a book. - To give insightful examples and exercises, to help the reader learn and to make it entertaining to work through. - To introduce concepts in a logical order. .. In other words, don't try to get ahead of yourself. - To use good practices and idioms, and avoid antipatterns. Functions or methodologies that tend to lead to antipatterns are avoided. Features that are only useful to advanced users are not shown. - To be consistent. If there are multiple ways to do it, only the best way is shown. .. For example, there are at least five different ways to create Symbols. ``symbols`` is the only one that is general and doesn't lead to antipatterns, so it is the only one used. - To avoid unnecessary duplication, it is assumed that previous sections of the tutorial have already been read. Feedback on this tutorial, or on SymPy in general is always welcome. Just write to our `mailing list `_. sympy-sympy-1.9/doc/src/tutorial/printing.rst000066400000000000000000000167211412543434000215150ustar00rootroot00000000000000.. _tutorial-printing: ========== Printing ========== As we have already seen, SymPy can pretty print its output using Unicode characters. This is a short introduction to the most common printing options available in SymPy. Printers ======== There are several printers available in SymPy. The most common ones are - str - srepr - ASCII pretty printer - Unicode pretty printer - LaTeX - MathML - Dot In addition to these, there are also "printers" that can output SymPy objects to code, such as C, Fortran, Javascript, Theano, and Python. These are not discussed in this tutorial. Setting up Pretty Printing ========================== If all you want is the best pretty printing, use the ``init_printing()`` function. This will automatically enable the best printer available in your environment. >>> from sympy import init_printing >>> init_printing() # doctest: +SKIP .. sidebar:: Quick Tip You can also change the printer used in SymPy Live. Just change the "Output Format" in the settings. If you plan to work in an interactive calculator-type session, the ``init_session()`` function will automatically import everything in SymPy, create some common Symbols, setup plotting, and run ``init_printing()``. >>> from sympy import init_session >>> init_session() # doctest: +SKIP :: Python console for SymPy 0.7.3 (Python 2.7.5-64-bit) (ground types: gmpy) These commands were executed: >>> from __future__ import division >>> from sympy import * >>> x, y, z, t = symbols('x y z t') >>> k, m, n = symbols('k m n', integer=True) >>> f, g, h = symbols('f g h', cls=Function) >>> init_printing() # doctest: +SKIP Documentation can be found at http://www.sympy.org >>> In any case, this is what will happen: - In the IPython QTConsole, if `\mathrm{\LaTeX}` is installed, it will enable a printer that uses `\mathrm{\LaTeX}`. .. image:: ../pics/ipythonqtconsole.png :height: 500 If `\mathrm{\LaTeX}` is not installed, but Matplotlib is installed, it will use the Matplotlib rendering engine. If Matplotlib is not installed, it uses the Unicode pretty printer. - In the IPython notebook, it will use MathJax to render `\mathrm{\LaTeX}`. .. image:: ../pics/ipythonnotebook.png :height: 250 - In an IPython console session, or a regular Python session, it will use the Unicode pretty printer if the terminal supports Unicode. .. image:: ../pics/consoleunicode.png :width: 700 - In a terminal that does not support Unicode, the ASCII pretty printer is used. .. image:: ../pics/consoleascii.png :width: 700 To explicitly not use `\mathrm{\LaTeX}`, pass ``use_latex=False`` to ``init_printing()`` or ``init_session()``. To explicitly not use Unicode, pass ``use_unicode=False``. Printing Functions ================== In addition to automatic printing, you can explicitly use any one of the printers by calling the appropriate function. str --- To get a string form of an expression, use ``str(expr)``. This is also the form that is produced by ``print(expr)``. String forms are designed to be easy to read, but in a form that is correct Python syntax so that it can be copied and pasted. The ``str()`` form of an expression will usually look exactly the same as the expression as you would enter it. >>> from sympy import * >>> x, y, z = symbols('x y z') >>> str(Integral(sqrt(1/x), x)) 'Integral(sqrt(1/x), x)' >>> print(Integral(sqrt(1/x), x)) Integral(sqrt(1/x), x) srepr ----- The srepr form of an expression is designed to show the exact form of an expression. It will be discussed more in the :ref:`tutorial-manipulation` section. To get it, use ``srepr()`` [#srepr-fn]_. >>> srepr(Integral(sqrt(1/x), x)) "Integral(Pow(Pow(Symbol('x'), Integer(-1)), Rational(1, 2)), Tuple(Symbol('x')))" The srepr form is mostly useful for understanding how an expression is built internally. ASCII Pretty Printer -------------------- The ASCII pretty printer is accessed from ``pprint()``. If the terminal does not support Unicode, the ASCII printer is used by default. Otherwise, you must pass ``use_unicode=False``. >>> pprint(Integral(sqrt(1/x), x), use_unicode=False) / | | ___ | / 1 | / - dx | \/ x | / ``pprint()`` prints the output to the screen. If you want the string form, use ``pretty()``. >>> pretty(Integral(sqrt(1/x), x), use_unicode=False) ' / \n | \n | ___ \n | / 1 \n | / - dx\n | \\/ x \n | \n/ ' >>> print(pretty(Integral(sqrt(1/x), x), use_unicode=False)) / | | ___ | / 1 | / - dx | \/ x | / Unicode Pretty Printer ---------------------- The Unicode pretty printer is also accessed from ``pprint()`` and ``pretty()``. If the terminal supports Unicode, it is used automatically. If ``pprint()`` is not able to detect that the terminal supports unicode, you can pass ``use_unicode=True`` to force it to use Unicode. >>> pprint(Integral(sqrt(1/x), x), use_unicode=True) ⌠ ⎮ ___ ⎮ ╱ 1 ⎮ ╱ ─ dx ⎮ ╲╱ x ⌡ .. _LaTeX: `\mathrm{\LaTeX}` ----------------- To get the `\mathrm{\LaTeX}` form of an expression, use ``latex()``. >>> print(latex(Integral(sqrt(1/x), x))) \int \sqrt{\frac{1}{x}}\, dx The ``latex()`` function has many options to change the formatting of different things. See :py:meth:`its documentation ` for more details. MathML ------ There is also a printer to MathML, called ``print_mathml()``. It must be imported from ``sympy.printing.mathml``. >>> from sympy.printing.mathml import print_mathml >>> print_mathml(Integral(sqrt(1/x), x)) x x -1 ``print_mathml()`` prints the output. If you want the string, use the function ``mathml()``. Dot --- The ``dotprint()`` function in ``sympy.printing.dot`` prints output to dot format, which can be rendered with Graphviz. See the :ref:`tutorial-manipulation` section for some examples of the output of this printer. Here is an example of the raw output of the ``dotprint()`` function >>> from sympy.printing.dot import dotprint >>> from sympy.abc import x >>> print(dotprint(x+2)) digraph{ # Graph style "ordering"="out" "rankdir"="TD" ######### # Nodes # ######### "Add(Integer(2), Symbol('x'))_()" ["color"="black", "label"="Add", "shape"="ellipse"]; "Integer(2)_(0,)" ["color"="black", "label"="2", "shape"="ellipse"]; "Symbol('x')_(1,)" ["color"="black", "label"="x", "shape"="ellipse"]; ######### # Edges # ######### "Add(Integer(2), Symbol('x'))_()" -> "Integer(2)_(0,)"; "Add(Integer(2), Symbol('x'))_()" -> "Symbol('x')_(1,)"; } .. rubric:: Footnotes .. [#srepr-fn] SymPy does not use the Python builtin ``repr()`` function for repr printing, because in Python ``str(list)`` calls ``repr()`` on the elements of the list, and some SymPy functions return lists (such as ``solve()``). Since ``srepr()`` is so verbose, it is unlikely that anyone would want it called by default on the output of ``solve()``. sympy-sympy-1.9/doc/src/tutorial/simplification.rst000066400000000000000000000710661412543434000227000ustar00rootroot00000000000000.. _tutorial-simplify: ================ Simplification ================ To make this document easier to read, we are going to enable pretty printing. >>> from sympy import * >>> x, y, z = symbols('x y z') >>> init_printing(use_unicode=True) ``simplify`` ============ Now let's jump in and do some interesting mathematics. One of the most useful features of a symbolic manipulation system is the ability to simplify mathematical expressions. SymPy has dozens of functions to perform various kinds of simplification. There is also one general function called ``simplify()`` that attempts to apply all of these functions in an intelligent way to arrive at the simplest form of an expression. Here are some examples >>> simplify(sin(x)**2 + cos(x)**2) 1 >>> simplify((x**3 + x**2 - x - 1)/(x**2 + 2*x + 1)) x - 1 >>> simplify(gamma(x)/gamma(x - 2)) (x - 2)⋅(x - 1) Here, ``gamma(x)`` is `\Gamma(x)`, the `gamma function `_. We see that ``simplify()`` is capable of handling a large class of expressions. But ``simplify()`` has a pitfall. It just applies all the major simplification operations in SymPy, and uses heuristics to determine the simplest result. But "simplest" is not a well-defined term. For example, say we wanted to "simplify" `x^2 + 2x + 1` into `(x + 1)^2`: >>> simplify(x**2 + 2*x + 1) 2 x + 2⋅x + 1 We did not get what we want. There is a function to perform this simplification, called ``factor()``, which will be discussed below. Another pitfall to ``simplify()`` is that it can be unnecessarily slow, since it tries many kinds of simplifications before picking the best one. If you already know exactly what kind of simplification you are after, it is better to apply the specific simplification function(s) that apply those simplifications. Applying specific simplification functions instead of ``simplify()`` also has the advantage that specific functions have certain guarantees about the form of their output. These will be discussed with each function below. For example, ``factor()``, when called on a polynomial with rational coefficients, is guaranteed to factor the polynomial into irreducible factors. ``simplify()`` has no guarantees. It is entirely heuristical, and, as we saw above, it may even miss a possible type of simplification that SymPy is capable of doing. ``simplify()`` is best when used interactively, when you just want to whittle down an expression to a simpler form. You may then choose to apply specific functions once you see what ``simplify()`` returns, to get a more precise result. It is also useful when you have no idea what form an expression will take, and you need a catchall function to simplify it. Polynomial/Rational Function Simplification =========================================== expand ------ ``expand()`` is one of the most common simplification functions in SymPy. Although it has a lot of scopes, for now, we will consider its function in expanding polynomial expressions. For example: >>> expand((x + 1)**2) 2 x + 2⋅x + 1 >>> expand((x + 2)*(x - 3)) 2 x - x - 6 Given a polynomial, ``expand()`` will put it into a canonical form of a sum of monomials. ``expand()`` may not sound like a simplification function. After all, by its very name, it makes expressions bigger, not smaller. Usually this is the case, but often an expression will become smaller upon calling ``expand()`` on it due to cancellation. >>> expand((x + 1)*(x - 2) - (x - 1)*x) -2 factor ------ ``factor()`` takes a polynomial and factors it into irreducible factors over the rational numbers. For example: >>> factor(x**3 - x**2 + x - 1) ⎛ 2 ⎞ (x - 1)⋅⎝x + 1⎠ >>> factor(x**2*z + 4*x*y*z + 4*y**2*z) 2 z⋅(x + 2⋅y) For polynomials, ``factor()`` is the opposite of ``expand()``. ``factor()`` uses a complete multivariate factorization algorithm over the rational numbers, which means that each of the factors returned by ``factor()`` is guaranteed to be irreducible. If you are interested in the factors themselves, ``factor_list`` returns a more structured output. >>> factor_list(x**2*z + 4*x*y*z + 4*y**2*z) (1, [(z, 1), (x + 2⋅y, 2)]) Note that the input to ``factor`` and ``expand`` need not be polynomials in the strict sense. They will intelligently factor or expand any kind of expression (though note that the factors may not be irreducible if the input is no longer a polynomial over the rationals). >>> expand((cos(x) + sin(x))**2) 2 2 sin (x) + 2⋅sin(x)⋅cos(x) + cos (x) >>> factor(cos(x)**2 + 2*cos(x)*sin(x) + sin(x)**2) 2 (sin(x) + cos(x)) collect ------- ``collect()`` collects common powers of a term in an expression. For example >>> expr = x*y + x - 3 + 2*x**2 - z*x**2 + x**3 >>> expr 3 2 2 x - x ⋅z + 2⋅x + x⋅y + x - 3 >>> collected_expr = collect(expr, x) >>> collected_expr 3 2 x + x ⋅(2 - z) + x⋅(y + 1) - 3 ``collect()`` is particularly useful in conjunction with the ``.coeff()`` method. ``expr.coeff(x, n)`` gives the coefficient of ``x**n`` in ``expr``: >>> collected_expr.coeff(x, 2) 2 - z .. TODO: Discuss coeff method in more detail in some other section (maybe basic expression manipulation tools) cancel ------ ``cancel()`` will take any rational function and put it into the standard canonical form, `\frac{p}{q}`, where `p` and `q` are expanded polynomials with no common factors, and the leading coefficients of `p` and `q` do not have denominators (i.e., are integers). >>> cancel((x**2 + 2*x + 1)/(x**2 + x)) x + 1 ───── x >>> expr = 1/x + (3*x/2 - 2)/(x - 4) >>> expr 3⋅x ─── - 2 2 1 ─────── + ─ x - 4 x >>> cancel(expr) 2 3⋅x - 2⋅x - 8 ────────────── 2 2⋅x - 8⋅x >>> expr = (x*y**2 - 2*x*y*z + x*z**2 + y**2 - 2*y*z + z**2)/(x**2 - 1) >>> expr 2 2 2 2 x⋅y - 2⋅x⋅y⋅z + x⋅z + y - 2⋅y⋅z + z ─────────────────────────────────────── 2 x - 1 >>> cancel(expr) 2 2 y - 2⋅y⋅z + z ─────────────── x - 1 Note that since ``factor()`` will completely factorize both the numerator and the denominator of an expression, it can also be used to do the same thing: >>> factor(expr) 2 (y - z) ──────── x - 1 However, if you are only interested in making sure that the expression is in canceled form, ``cancel()`` is more efficient than ``factor()``. apart ----- ``apart()`` performs a `partial fraction decomposition `_ on a rational function. >>> expr = (4*x**3 + 21*x**2 + 10*x + 12)/(x**4 + 5*x**3 + 5*x**2 + 4*x) >>> expr 3 2 4⋅x + 21⋅x + 10⋅x + 12 ──────────────────────── 4 3 2 x + 5⋅x + 5⋅x + 4⋅x >>> apart(expr) 2⋅x - 1 1 3 ────────── - ───── + ─ 2 x + 4 x x + x + 1 Trigonometric Simplification ============================ .. note:: SymPy follows Python's naming conventions for inverse trigonometric functions, which is to append an ``a`` to the front of the function's name. For example, the inverse cosine, or arc cosine, is called ``acos()``. >>> acos(x) acos(x) >>> cos(acos(x)) x >>> asin(1) π ─ 2 .. TODO: Can we actually do anything with inverse trig functions, simplification wise? trigsimp -------- To simplify expressions using trigonometric identities, use ``trigsimp()``. >>> trigsimp(sin(x)**2 + cos(x)**2) 1 >>> trigsimp(sin(x)**4 - 2*cos(x)**2*sin(x)**2 + cos(x)**4) cos(4⋅x) 1 ──────── + ─ 2 2 >>> trigsimp(sin(x)*tan(x)/sec(x)) 2 sin (x) ``trigsimp()`` also works with hyperbolic trig functions. >>> trigsimp(cosh(x)**2 + sinh(x)**2) cosh(2⋅x) >>> trigsimp(sinh(x)/tanh(x)) cosh(x) Much like ``simplify()``, ``trigsimp()`` applies various trigonometric identities to the input expression, and then uses a heuristic to return the "best" one. expand_trig ----------- To expand trigonometric functions, that is, apply the sum or double angle identities, use ``expand_trig()``. >>> expand_trig(sin(x + y)) sin(x)⋅cos(y) + sin(y)⋅cos(x) >>> expand_trig(tan(2*x)) 2⋅tan(x) ─────────── 2 1 - tan (x) Because ``expand_trig()`` tends to make trigonometric expressions larger, and ``trigsimp()`` tends to make them smaller, these identities can be applied in reverse using ``trigsimp()`` >>> trigsimp(sin(x)*cos(y) + sin(y)*cos(x)) sin(x + y) .. TODO: It would be much better to teach individual trig rewriting functions here, but they don't exist yet. See https://github.com/sympy/sympy/issues/3456. Powers ====== Before we introduce the power simplification functions, a mathematical discussion on the identities held by powers is in order. There are three kinds of identities satisfied by exponents 1. `x^ax^b = x^{a + b}` 2. `x^ay^a = (xy)^a` 3. `(x^a)^b = x^{ab}` Identity 1 is always true. Identity 2 is not always true. For example, if `x = y = -1` and `a = \frac{1}{2}`, then `x^ay^a = \sqrt{-1}\sqrt{-1} = i\cdot i = -1`, whereas `(xy)^a = \sqrt{-1\cdot-1} = \sqrt{1} = 1`. However, identity 2 is true at least if `x` and `y` are nonnegative and `a` is real (it may also be true under other conditions as well). A common consequence of the failure of identity 2 is that `\sqrt{x}\sqrt{y} \neq \sqrt{xy}`. Identity 3 is not always true. For example, if `x = -1`, `a = 2`, and `b = \frac{1}{2}`, then `(x^a)^b = {\left((-1)^2\right)}^{1/2} = \sqrt{1} = 1` and `x^{ab} = (-1)^{2\cdot1/2} = (-1)^1 = -1`. However, identity 3 is true when `b` is an integer (again, it may also hold in other cases as well). Two common consequences of the failure of identity 3 are that `\sqrt{x^2}\neq x` and that `\sqrt{\frac{1}{x}} \neq \frac{1}{\sqrt{x}}`. To summarize +-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ |Identity |Sufficient conditions to hold |Counterexample when conditions are not met |Important consequences | +=======================+====================================+====================================================+=============================================================================+ |1. `x^ax^b = x^{a + b}`|Always true |None |None | +-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ |2. `x^ay^a = (xy)^a` |`x, y \geq 0` and `a \in \mathbb{R}`|`(-1)^{1/2}(-1)^{1/2} \neq (-1\cdot-1)^{1/2}` |`\sqrt{x}\sqrt{y} \neq \sqrt{xy}` in general | +-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ |3. `(x^a)^b = x^{ab}` |`b \in \mathbb{Z}` |`{\left((-1)^2\right)}^{1/2} \neq (-1)^{2\cdot1/2}` |`\sqrt{x^2}\neq x` and `\sqrt{\frac{1}{x}}\neq\frac{1}{\sqrt{x}}` in general | +-----------------------+------------------------------------+----------------------------------------------------+-----------------------------------------------------------------------------+ This is important to remember, because by default, SymPy will not perform simplifications if they are not true in general. In order to make SymPy perform simplifications involving identities that are only true under certain assumptions, we need to put assumptions on our Symbols. We will undertake a full discussion of the assumptions system later, but for now, all we need to know are the following. - By default, SymPy Symbols are assumed to be complex (elements of `\mathbb{C}`). That is, a simplification will not be applied to an expression with a given Symbol unless it holds for all complex numbers. - Symbols can be given different assumptions by passing the assumption to ``symbols()``. For the rest of this section, we will be assuming that ``x`` and ``y`` are positive, and that ``a`` and ``b`` are real. We will leave ``z``, ``t``, and ``c`` as arbitrary complex Symbols to demonstrate what happens in that case. >>> x, y = symbols('x y', positive=True) >>> a, b = symbols('a b', real=True) >>> z, t, c = symbols('z t c') .. TODO: Rewrite this using the new assumptions .. note:: In SymPy, ``sqrt(x)`` is just a shortcut to ``x**Rational(1, 2)``. They are exactly the same object. >>> sqrt(x) == x**Rational(1, 2) True powsimp ------- ``powsimp()`` applies identities 1 and 2 from above, from left to right. >>> powsimp(x**a*x**b) a + b x >>> powsimp(x**a*y**a) a (x⋅y) Notice that ``powsimp()`` refuses to do the simplification if it is not valid. >>> powsimp(t**c*z**c) c c t ⋅z If you know that you want to apply this simplification, but you don't want to mess with assumptions, you can pass the ``force=True`` flag. This will force the simplification to take place, regardless of assumptions. >>> powsimp(t**c*z**c, force=True) c (t⋅z) Note that in some instances, in particular, when the exponents are integers or rational numbers, and identity 2 holds, it will be applied automatically. >>> (z*t)**2 2 2 t ⋅z >>> sqrt(x*y) √x⋅√y This means that it will be impossible to undo this identity with ``powsimp()``, because even if ``powsimp()`` were to put the bases together, they would be automatically split apart again. >>> powsimp(z**2*t**2) 2 2 t ⋅z >>> powsimp(sqrt(x)*sqrt(y)) √x⋅√y expand_power_exp / expand_power_base ------------------------------------ ``expand_power_exp()`` and ``expand_power_base()`` apply identities 1 and 2 from right to left, respectively. >>> expand_power_exp(x**(a + b)) a b x ⋅x >>> expand_power_base((x*y)**a) a a x ⋅y As with ``powsimp()``, identity 2 is not applied if it is not valid. >>> expand_power_base((z*t)**c) c (t⋅z) And as with ``powsimp()``, you can force the expansion to happen without fiddling with assumptions by using ``force=True``. >>> expand_power_base((z*t)**c, force=True) c c t ⋅z As with identity 2, identity 1 is applied automatically if the power is a number, and hence cannot be undone with ``expand_power_exp()``. >>> x**2*x**3 5 x >>> expand_power_exp(x**5) 5 x powdenest --------- ``powdenest()`` applies identity 3, from left to right. >>> powdenest((x**a)**b) a⋅b x As before, the identity is not applied if it is not true under the given assumptions. >>> powdenest((z**a)**b) b ⎛ a⎞ ⎝z ⎠ And as before, this can be manually overridden with ``force=True``. >>> powdenest((z**a)**b, force=True) a⋅b z Exponentials and logarithms =========================== .. note:: In SymPy, as in Python and most programming languages, ``log`` is the natural logarithm, also known as ``ln``. SymPy automatically provides an alias ``ln = log`` in case you forget this. >>> ln(x) log(x) Logarithms have similar issues as powers. There are two main identities 1. `\log{(xy)} = \log{(x)} + \log{(y)}` 2. `\log{(x^n)} = n\log{(x)}` Neither identity is true for arbitrary complex `x` and `y`, due to the branch cut in the complex plane for the complex logarithm. However, sufficient conditions for the identities to hold are if `x` and `y` are positive and `n` is real. >>> x, y = symbols('x y', positive=True) >>> n = symbols('n', real=True) As before, ``z`` and ``t`` will be Symbols with no additional assumptions. Note that the identity `\log{\left(\frac{x}{y}\right)} = \log(x) - \log(y)` is a special case of identities 1 and 2 by `\log{\left(\frac{x}{y}\right)} =` `\log{\left(x\cdot\frac{1}{y}\right)} =` `\log(x) + \log{\left( y^{-1}\right)} =` `\log(x) - \log(y)`, and thus it also holds if `x` and `y` are positive, but may not hold in general. We also see that `\log{\left( e^x \right)} = x` comes from `\log{\left( e^x \right)} = x\log(e) = x`, and thus holds when `x` is real (and it can be verified that it does not hold in general for arbitrary complex `x`, for example, `\log{\left(e^{x + 2\pi i}\right)} = \log{\left(e^x\right)} = x \neq x + 2\pi i`). expand_log ---------- To apply identities 1 and 2 from left to right, use ``expand_log()``. As always, the identities will not be applied unless they are valid. >>> expand_log(log(x*y)) log(x) + log(y) >>> expand_log(log(x/y)) log(x) - log(y) >>> expand_log(log(x**2)) 2⋅log(x) >>> expand_log(log(x**n)) n⋅log(x) >>> expand_log(log(z*t)) log(t⋅z) As with ``powsimp()`` and ``powdenest()``, ``expand_log()`` has a ``force`` option that can be used to ignore assumptions. >>> expand_log(log(z**2)) ⎛ 2⎞ log⎝z ⎠ >>> expand_log(log(z**2), force=True) 2⋅log(z) logcombine ---------- To apply identities 1 and 2 from right to left, use ``logcombine()``. >>> logcombine(log(x) + log(y)) log(x⋅y) >>> logcombine(n*log(x)) ⎛ n⎞ log⎝x ⎠ >>> logcombine(n*log(z)) n⋅log(z) ``logcombine()`` also has a ``force`` option that can be used to ignore assumptions. >>> logcombine(n*log(z), force=True) ⎛ n⎞ log⎝z ⎠ Special Functions ================= SymPy implements dozens of special functions, ranging from functions in combinatorics to mathematical physics. An extensive list of the special functions included with SymPy and their documentation is at the :ref:`Functions Module ` page. For the purposes of this tutorial, let's introduce a few special functions in SymPy. Let's define ``x``, ``y``, and ``z`` as regular, complex Symbols, removing any assumptions we put on them in the previous section. We will also define ``k``, ``m``, and ``n``. >>> x, y, z = symbols('x y z') >>> k, m, n = symbols('k m n') The `factorial `_ function is ``factorial``. ``factorial(n)`` represents `n!= 1\cdot2\cdots(n - 1)\cdot n`. `n!` represents the number of permutations of `n` distinct items. >>> factorial(n) n! The `binomial coefficient `_ function is ``binomial``. ``binomial(n, k)`` represents `\binom{n}{k}`, the number of ways to choose `k` items from a set of `n` distinct items. It is also often written as `nCk`, and is pronounced "`n` choose `k`". >>> binomial(n, k) ⎛n⎞ ⎜ ⎟ ⎝k⎠ The factorial function is closely related to the `gamma function `_, ``gamma``. ``gamma(z)`` represents `\Gamma(z) = \int_0^\infty t^{z - 1}e^{-t}\,dt`, which for positive integer `z` is the same as `(z - 1)!`. >>> gamma(z) Γ(z) The `generalized hypergeometric function `_ is ``hyper``. ``hyper([a_1, ..., a_p], [b_1, ..., b_q], z)`` represents `{}_pF_q\left(\begin{matrix} a_1, \cdots, a_p \\ b_1, \cdots, b_q \end{matrix} \middle| z \right)`. The most common case is `{}_2F_1`, which is often referred to as the `ordinary hypergeometric function `_. >>> hyper([1, 2], [3], z) ┌─ ⎛1, 2 │ ⎞ ├─ ⎜ │ z⎟ 2╵ 1 ⎝ 3 │ ⎠ rewrite ------- A common way to deal with special functions is to rewrite them in terms of one another. This works for any function in SymPy, not just special functions. To rewrite an expression in terms of a function, use ``expr.rewrite(function)``. For example, >>> tan(x).rewrite(sin) 2 2⋅sin (x) ───────── sin(2⋅x) >>> factorial(x).rewrite(gamma) Γ(x + 1) For some tips on applying more targeted rewriting, see the :ref:`tutorial-manipulation` section. expand_func ----------- To expand special functions in terms of some identities, use ``expand_func()``. For example >>> expand_func(gamma(x + 3)) x⋅(x + 1)⋅(x + 2)⋅Γ(x) hyperexpand ----------- To rewrite ``hyper`` in terms of more standard functions, use ``hyperexpand()``. >>> hyperexpand(hyper([1, 1], [2], z)) -log(1 - z) ──────────── z ``hyperexpand()`` also works on the more general Meijer G-function (see :py:meth:`its documentation ` for more information). >>> expr = meijerg([[1],[1]], [[1],[]], -z) >>> expr ╭─╮1, 1 ⎛1 1 │ ⎞ │╶┐ ⎜ │ -z⎟ ╰─╯2, 1 ⎝1 │ ⎠ >>> hyperexpand(expr) 1 ─ z ℯ combsimp -------- To simplify combinatorial expressions, use ``combsimp()``. >>> n, k = symbols('n k', integer = True) >>> combsimp(factorial(n)/factorial(n - 3)) n⋅(n - 2)⋅(n - 1) >>> combsimp(binomial(n+1, k+1)/binomial(n, k)) n + 1 ───── k + 1 gammasimp --------- To simplify expressions with gamma functions or combinatorial functions with non-integer argument, use ``gammasimp()``. >>> gammasimp(gamma(x)*gamma(1 - x)) π ──────── sin(π⋅x) Example: Continued Fractions ============================ Let's use SymPy to explore continued fractions. A `continued fraction `_ is an expression of the form .. math:: a_0 + \cfrac{1}{a_1 + \cfrac{1}{a_2 + \cfrac{1}{ \ddots + \cfrac{1}{a_n} }}} where `a_0, \ldots, a_n` are integers, and `a_1, \ldots, a_n` are positive. A continued fraction can also be infinite, but infinite objects are more difficult to represent in computers, so we will only examine the finite case here. A continued fraction of the above form is often represented as a list `[a_0; a_1, \ldots, a_n]`. Let's write a simple function that converts such a list to its continued fraction form. The easiest way to construct a continued fraction from a list is to work backwards. Note that despite the apparent symmetry of the definition, the first element, `a_0`, must usually be handled differently from the rest. >>> def list_to_frac(l): ... expr = Integer(0) ... for i in reversed(l[1:]): ... expr += i ... expr = 1/expr ... return l[0] + expr >>> list_to_frac([x, y, z]) 1 x + ───── 1 y + ─ z We use ``Integer(0)`` in ``list_to_frac`` so that the result will always be a SymPy object, even if we only pass in Python ints. >>> list_to_frac([1, 2, 3, 4]) 43 ── 30 Every finite continued fraction is a rational number, but we are interested in symbolics here, so let's create a symbolic continued fraction. The ``symbols()`` function that we have been using has a shortcut to create numbered symbols. ``symbols('a0:5')`` will create the symbols ``a0``, ``a1``, ..., ``a4``. >>> syms = symbols('a0:5') >>> syms (a₀, a₁, a₂, a₃, a₄) >>> a0, a1, a2, a3, a4 = syms >>> frac = list_to_frac(syms) >>> frac 1 a₀ + ───────────────── 1 a₁ + ──────────── 1 a₂ + ─────── 1 a₃ + ── a₄ This form is useful for understanding continued fractions, but lets put it into standard rational function form using ``cancel()``. >>> frac = cancel(frac) >>> frac a₀⋅a₁⋅a₂⋅a₃⋅a₄ + a₀⋅a₁⋅a₂ + a₀⋅a₁⋅a₄ + a₀⋅a₃⋅a₄ + a₀ + a₂⋅a₃⋅a₄ + a₂ + a₄ ───────────────────────────────────────────────────────────────────────── a₁⋅a₂⋅a₃⋅a₄ + a₁⋅a₂ + a₁⋅a₄ + a₃⋅a₄ + 1 Now suppose we were given ``frac`` in the above canceled form. In fact, we might be given the fraction in any form, but we can always put it into the above canonical form with ``cancel()``. Suppose that we knew that it could be rewritten as a continued fraction. How could we do this with SymPy? A continued fraction is recursively `c + \frac{1}{f}`, where `c` is an integer and `f` is a (smaller) continued fraction. If we could write the expression in this form, we could pull out each `c` recursively and add it to a list. We could then get a continued fraction with our ``list_to_frac()`` function. The key observation here is that we can convert an expression to the form `c + \frac{1}{f}` by doing a partial fraction decomposition with respect to `c`. This is because `f` does not contain `c`. This means we need to use the ``apart()`` function. We use ``apart()`` to pull the term out, then subtract it from the expression, and take the reciprocal to get the `f` part. >>> l = [] >>> frac = apart(frac, a0) >>> frac a₂⋅a₃⋅a₄ + a₂ + a₄ a₀ + ─────────────────────────────────────── a₁⋅a₂⋅a₃⋅a₄ + a₁⋅a₂ + a₁⋅a₄ + a₃⋅a₄ + 1 >>> l.append(a0) >>> frac = 1/(frac - a0) >>> frac a₁⋅a₂⋅a₃⋅a₄ + a₁⋅a₂ + a₁⋅a₄ + a₃⋅a₄ + 1 ─────────────────────────────────────── a₂⋅a₃⋅a₄ + a₂ + a₄ Now we repeat this process >>> frac = apart(frac, a1) >>> frac a₃⋅a₄ + 1 a₁ + ────────────────── a₂⋅a₃⋅a₄ + a₂ + a₄ >>> l.append(a1) >>> frac = 1/(frac - a1) >>> frac = apart(frac, a2) >>> frac a₄ a₂ + ───────── a₃⋅a₄ + 1 >>> l.append(a2) >>> frac = 1/(frac - a2) >>> frac = apart(frac, a3) >>> frac 1 a₃ + ── a₄ >>> l.append(a3) >>> frac = 1/(frac - a3) >>> frac = apart(frac, a4) >>> frac a₄ >>> l.append(a4) >>> list_to_frac(l) 1 a₀ + ───────────────── 1 a₁ + ──────────── 1 a₂ + ─────── 1 a₃ + ── a₄ .. sidebar:: Quick Tip You can execute multiple lines at once in SymPy Live. Typing ``Shift-Enter`` instead of ``Enter`` will enter a newline instead of executing. Of course, this exercise seems pointless, because we already know that our ``frac`` is ``list_to_frac([a0, a1, a2, a3, a4])``. So try the following exercise. Take a list of symbols and randomize them, and create the canceled continued fraction, and see if you can reproduce the original list. For example >>> import random >>> l = list(symbols('a0:5')) >>> random.shuffle(l) >>> orig_frac = frac = cancel(list_to_frac(l)) >>> del l Click on "Run code block in SymPy Live" on the definition of ``list_to_frac()`` above, and then on the above example, and try to reproduce ``l`` from ``frac``. I have deleted ``l`` at the end to remove the temptation for peeking (you can check your answer at the end by calling ``cancel(list_to_frac(l))`` on the list that you generate at the end, and comparing it to ``orig_frac``. See if you can think of a way to figure out what symbol to pass to ``apart()`` at each stage (hint: think of what happens to `a_0` in the formula `a_0 + \frac{1}{a_1 + \cdots}` when it is canceled). .. Answer: a0 is the only symbol that does not appear in the denominator sympy-sympy-1.9/doc/src/tutorial/solvers.rst000066400000000000000000000162071412543434000213570ustar00rootroot00000000000000========= Solvers ========= >>> from sympy import * >>> x, y, z = symbols('x y z') >>> init_printing(use_unicode=True) A Note about Equations ====================== Recall from the :ref:`gotchas ` section of this tutorial that symbolic equations in SymPy are not represented by ``=`` or ``==``, but by ``Eq``. >>> Eq(x, y) x = y However, there is an even easier way. In SymPy, any expression not in an ``Eq`` is automatically assumed to equal 0 by the solving functions. Since `a = b` if and only if `a - b = 0`, this means that instead of using ``x == y``, you can just use ``x - y``. For example >>> solveset(Eq(x**2, 1), x) {-1, 1} >>> solveset(Eq(x**2 - 1, 0), x) {-1, 1} >>> solveset(x**2 - 1, x) {-1, 1} This is particularly useful if the equation you wish to solve is already equal to 0. Instead of typing ``solveset(Eq(expr, 0), x)``, you can just use ``solveset(expr, x)``. Solving Equations Algebraically =============================== The main function for solving algebraic equations is ``solveset``. The syntax for ``solveset`` is ``solveset(equation, variable=None, domain=S.Complexes)`` Where ``equations`` may be in the form of ``Eq`` instances or expressions that are assumed to be equal to zero. Please note that there is another function called ``solve`` which can also be used to solve equations. The syntax is ``solve(equations, variables)`` However, it is recommended to use ``solveset`` instead. When solving a single equation, the output of ``solveset`` is a ``FiniteSet`` or an ``Interval`` or ``ImageSet`` of the solutions. >>> solveset(x**2 - x, x) {0, 1} >>> solveset(x - x, x, domain=S.Reals) ℝ >>> solveset(sin(x) - 1, x, domain=S.Reals) ⎧ π │ ⎫ ⎨2⋅n⋅π + ─ │ n ∊ ℤ⎬ ⎩ 2 │ ⎭ If there are no solutions, an ``EmptySet`` is returned and if it is not able to find solutions then a ``ConditionSet`` is returned. >>> solveset(exp(x), x) # No solution exists ∅ >>> solveset(cos(x) - x, x) # Not able to find solution {x │ x ∊ ℂ ∧ (-x + cos(x) = 0)} In the ``solveset`` module, the linear system of equations is solved using ``linsolve``. In future we would be able to use linsolve directly from ``solveset``. Following is an example of the syntax of ``linsolve``. * List of Equations Form: >>> linsolve([x + y + z - 1, x + y + 2*z - 3 ], (x, y, z)) {(-y - 1, y, 2)} * Augmented Matrix Form: >>> linsolve(Matrix(([1, 1, 1, 1], [1, 1, 2, 3])), (x, y, z)) {(-y - 1, y, 2)} * A*x = b Form >>> M = Matrix(((1, 1, 1, 1), (1, 1, 2, 3))) >>> system = A, b = M[:, :-1], M[:, -1] >>> linsolve(system, x, y, z) {(-y - 1, y, 2)} .. note:: The order of solution corresponds the order of given symbols. In the ``solveset`` module, the non linear system of equations is solved using ``nonlinsolve``. Following are examples of ``nonlinsolve``. 1. When only real solution is present: >>> a, b, c, d = symbols('a, b, c, d', real=True) >>> nonlinsolve([a**2 + a, a - b], [a, b]) {(-1, -1), (0, 0)} >>> nonlinsolve([x*y - 1, x - 2], x, y) {(2, 1/2)} 2. When only complex solution is present: >>> nonlinsolve([x**2 + 1, y**2 + 1], [x, y]) {(-ⅈ, -ⅈ), (-ⅈ, ⅈ), (ⅈ, -ⅈ), (ⅈ, ⅈ)} 3. When both real and complex solution are present: >>> from sympy import sqrt >>> system = [x**2 - 2*y**2 -2, x*y - 2] >>> vars = [x, y] >>> nonlinsolve(system, vars) {(-2, -1), (2, 1), (-√2⋅ⅈ, √2⋅ⅈ), (√2⋅ⅈ, -√2⋅ⅈ)} >>> system = [exp(x) - sin(y), 1/y - 3] >>> nonlinsolve(system, vars) {({2⋅n⋅ⅈ⋅π + log(sin(1/3)) │ n ∊ ℤ}, 1/3)} 4. When the system is positive-dimensional system (has infinitely many solutions): >>> nonlinsolve([x*y, x*y - x], [x, y]) {(0, y)} >>> system = [a**2 + a*c, a - b] >>> nonlinsolve(system, [a, b]) {(0, 0), (-c, -c)} .. note:: 1. The order of solution corresponds the order of given symbols. 2. Currently ``nonlinsolve`` doesn't return solution in form of ``LambertW`` (if there is solution present in the form of ``LambertW``). ``solve`` can be used for such cases: >>> solve([x**2 - y**2/exp(x)], [x, y], dict=True) ⎡⎧ ____⎫ ⎧ ____⎫⎤ ⎢⎨ ╱ x ⎬ ⎨ ╱ x ⎬⎥ ⎣⎩y: -x⋅╲╱ ℯ ⎭, ⎩y: x⋅╲╱ ℯ ⎭⎦ >>> solve(x**2 - y**2/exp(x), x, dict=True) ⎡⎧ ⎛-y ⎞⎫ ⎧ ⎛y⎞⎫⎤ ⎢⎨x: 2⋅W⎜───⎟⎬, ⎨x: 2⋅W⎜─⎟⎬⎥ ⎣⎩ ⎝ 2 ⎠⎭ ⎩ ⎝2⎠⎭⎦ 3. Currently ``nonlinsolve`` is not properly capable of solving the system of equations having trigonometric functions. ``solve`` can be used for such cases (but does not give all solution): >>> solve([sin(x + y), cos(x - y)], [x, y]) ⎡⎛-3⋅π 3⋅π⎞ ⎛-π π⎞ ⎛π 3⋅π⎞ ⎛3⋅π π⎞⎤ ⎢⎜─────, ───⎟, ⎜───, ─⎟, ⎜─, ───⎟, ⎜───, ─⎟⎥ ⎣⎝ 4 4 ⎠ ⎝ 4 4⎠ ⎝4 4 ⎠ ⎝ 4 4⎠⎦ .. _tutorial-roots: ``solveset`` reports each solution only once. To get the solutions of a polynomial including multiplicity use ``roots``. >>> solveset(x**3 - 6*x**2 + 9*x, x) {0, 3} >>> roots(x**3 - 6*x**2 + 9*x, x) {0: 1, 3: 2} The output ``{0: 1, 3: 2}`` of ``roots`` means that ``0`` is a root of multiplicity 1 and ``3`` is a root of multiplicity 2. .. note:: Currently ``solveset`` is not capable of solving the following types of equations: * Equations solvable by LambertW (Transcendental equation solver). ``solve`` can be used for such cases: >>> solve(x*exp(x) - 1, x ) [W(1)] .. _tutorial-dsolve: Solving Differential Equations ============================== To solve differential equations, use ``dsolve``. First, create an undefined function by passing ``cls=Function`` to the ``symbols`` function. >>> f, g = symbols('f g', cls=Function) ``f`` and ``g`` are now undefined functions. We can call ``f(x)``, and it will represent an unknown function. >>> f(x) f(x) Derivatives of ``f(x)`` are unevaluated. >>> f(x).diff(x) d ──(f(x)) dx (see the :ref:`Derivatives ` section for more on derivatives). To represent the differential equation `f''(x) - 2f'(x) + f(x) = \sin(x)`, we would thus use >>> diffeq = Eq(f(x).diff(x, x) - 2*f(x).diff(x) + f(x), sin(x)) >>> diffeq 2 d d f(x) - 2⋅──(f(x)) + ───(f(x)) = sin(x) dx 2 dx To solve the ODE, pass it and the function to solve for to ``dsolve``. >>> dsolve(diffeq, f(x)) x cos(x) f(x) = (C₁ + C₂⋅x)⋅ℯ + ────── 2 ``dsolve`` returns an instance of ``Eq``. This is because in general, solutions to differential equations cannot be solved explicitly for the function. >>> dsolve(f(x).diff(x)*(1 - sin(f(x))) - 1, f(x)) x - f(x) - cos(f(x)) = C₁ The arbitrary constants in the solutions from dsolve are symbols of the form ``C1``, ``C2``, ``C3``, and so on. sympy-sympy-1.9/doc/src/wiki.rst000066400000000000000000000004431412543434000167550ustar00rootroot00000000000000Wiki ==== SymPy has a public wiki located at http://wiki.sympy.org. Users should feel free to contribute to this wiki anything interesting/useful. FAQ --- `FAQ `_ is one of the most useful wiki pages. It has answers to frequently-asked questions. sympy-sympy-1.9/examples/000077500000000000000000000000001412543434000155415ustar00rootroot00000000000000sympy-sympy-1.9/examples/README000066400000000000000000000030531412543434000164220ustar00rootroot00000000000000This directory contains SymPy example programs. ------------------------------------------------------------------------------- DIRECTORY STRUCTURE The examples are broken up into three categories based on difficulty of both the mathematics and programming concepts. They roughly follow the following guide: beginner : Simple examples appropriate for first steps in using SymPy, for someone with little or no programming experience. intermediate : Demonstrations of more complex mathematical concepts, but still for someone with little programming experience. advanced : Larger demonstrations of advanced mathematical topics. ------------------------------------------------------------------------------- RUNNING EXAMPLES All the working examples can be run by executing the "all.py" script, use ./all.py -h for usage, if an example is known to be broken it will be commented out in this script. To run the individual examples one needs to have Python version >= 2.6 installed and SymPy must be in your PYTHONPATH environment variable. Most examples can be run from the command line python and the name of the example: aterrel@lilac:~/sympy/examples$ export PYTHONPATH=$PWD/..:$PYTHONPATH aterrel@lilac:~/sympy/examples$ python beginner/basic.py (3*a*b**2)**c Note: on most systems, the current directory is searched by Python automatically, so "python beginner/basic.py" works from the sympy root directory, however there are systems (Ubuntu Intrepid) where this doesn't work by default, unless you put "PYTHONPATH=." into your .bashrc for example. sympy-sympy-1.9/examples/advanced/000077500000000000000000000000001412543434000173065ustar00rootroot00000000000000sympy-sympy-1.9/examples/advanced/autowrap_integrators.py000077500000000000000000000212751412543434000241550ustar00rootroot00000000000000#!/usr/bin/env python """ Numerical integration with autowrap ----------------------------------- This example demonstrates how you can use the autowrap module in SymPy to create fast, numerical integration routines callable from python. See in the code for detailed explanations of the various steps. An autowrapped sympy expression can be significantly faster than what you would get by applying a sequence of the ufuncs shipped with numpy. [0] We will find the coefficients needed to approximate a quantum mechanical Hydrogen wave function in terms of harmonic oscillator solutions. For the sake of demonstration, this will be done by setting up a simple numerical integration scheme as a SymPy expression, and obtain a binary implementation with autowrap. You need to have numpy installed to run this example, as well as a working fortran compiler. If you have pylab installed, you will be rewarded with a nice plot in the end. [0]: http://ojensen.wordpress.com/2010/08/10/fast-ufunc-ish-hydrogen-solutions/ ---- """ import sys from sympy.external import import_module np = import_module('numpy') if not np: sys.exit("Cannot import numpy. Exiting.") pylab = import_module('pylab', warn_not_installed=True) from sympy.utilities.lambdify import implemented_function from sympy.utilities.autowrap import autowrap, ufuncify from sympy import Idx, IndexedBase, Lambda, pprint, Symbol, oo, Integral,\ Function from sympy.physics.sho import R_nl from sympy.physics.hydrogen import R_nl as hydro_nl # *************************************************************************** # calculation parameters to play with # *************************************************************************** basis_dimension = 5 # Size of h.o. basis (n < basis_dimension) omega2 = 0.1 # in atomic units: twice the oscillator frequency orbital_momentum_l = 1 # the quantum number `l` for angular momentum hydrogen_n = 2 # the nodal quantum number for the Hydrogen wave rmax = 20 # cut off in the radial direction gridsize = 200 # number of points in the grid # *************************************************************************** def main(): print(__doc__) # arrays are represented with IndexedBase, indices with Idx m = Symbol('m', integer=True) i = Idx('i', m) A = IndexedBase('A') B = IndexedBase('B') x = Symbol('x') print("Compiling ufuncs for radial harmonic oscillator solutions") # setup a basis of ho-solutions (for l=0) basis_ho = {} for n in range(basis_dimension): # Setup the radial ho solution for this n expr = R_nl(n, orbital_momentum_l, omega2, x) # Reduce the number of operations in the expression by eval to float expr = expr.evalf(15) print("The h.o. wave function with l = %i and n = %i is" % ( orbital_momentum_l, n)) pprint(expr) # implement, compile and wrap it as a ufunc basis_ho[n] = ufuncify(x, expr) # now let's see if we can express a hydrogen radial wave in terms of # the ho basis. Here's the solution we will approximate: H_ufunc = ufuncify(x, hydro_nl(hydrogen_n, orbital_momentum_l, 1, x)) # The transformation to a different basis can be written like this, # # psi(r) = sum_i c(i) phi_i(r) # # where psi(r) is the hydrogen solution, phi_i(r) are the H.O. solutions # and c(i) are scalar coefficients. # # So in order to express a hydrogen solution in terms of the H.O. basis, we # need to determine the coefficients c(i). In position space, it means # that we need to evaluate an integral: # # psi(r) = sum_i Integral(R**2*conj(phi(R))*psi(R), (R, 0, oo)) phi_i(r) # # To calculate the integral with autowrap, we notice that it contains an # element-wise sum over all vectors. Using the Indexed class, it is # possible to generate autowrapped functions that perform summations in # the low-level code. (In fact, summations are very easy to create, and as # we will see it is often necessary to take extra steps in order to avoid # them.) # we need one integration ufunc for each wave function in the h.o. basis binary_integrator = {} for n in range(basis_dimension): # # setup basis wave functions # # To get inline expressions in the low level code, we attach the # wave function expressions to a regular SymPy function using the # implemented_function utility. This is an extra step needed to avoid # erroneous summations in the wave function expressions. # # Such function objects carry around the expression they represent, # but the expression is not exposed unless explicit measures are taken. # The benefit is that the routines that searches for repeated indices # in order to make contractions will not search through the wave # function expression. psi_ho = implemented_function('psi_ho', Lambda(x, R_nl(n, orbital_momentum_l, omega2, x))) # We represent the hydrogen function by an array which will be an input # argument to the binary routine. This will let the integrators find # h.o. basis coefficients for any wave function we throw at them. psi = IndexedBase('psi') # # setup expression for the integration # step = Symbol('step') # use symbolic stepsize for flexibility # let i represent an index of the grid array, and let A represent the # grid array. Then we can approximate the integral by a sum over the # following expression (simplified rectangular rule, ignoring end point # corrections): expr = A[i]**2*psi_ho(A[i])*psi[i]*step if n == 0: print("Setting up binary integrators for the integral:") pprint(Integral(x**2*psi_ho(x)*Function('psi')(x), (x, 0, oo))) # Autowrap it. For functions that take more than one argument, it is # a good idea to use the 'args' keyword so that you know the signature # of the wrapped function. (The dimension m will be an optional # argument, but it must be present in the args list.) binary_integrator[n] = autowrap(expr, args=[A.label, psi.label, step, m]) # Lets see how it converges with the grid dimension print("Checking convergence of integrator for n = %i" % n) for g in range(3, 8): grid, step = np.linspace(0, rmax, 2**g, retstep=True) print("grid dimension %5i, integral = %e" % (2**g, binary_integrator[n](grid, H_ufunc(grid), step))) print("A binary integrator has been set up for each basis state") print("We will now use them to reconstruct a hydrogen solution.") # Note: We didn't need to specify grid or use gridsize before now grid, stepsize = np.linspace(0, rmax, gridsize, retstep=True) print("Calculating coefficients with gridsize = %i and stepsize %f" % ( len(grid), stepsize)) coeffs = {} for n in range(basis_dimension): coeffs[n] = binary_integrator[n](grid, H_ufunc(grid), stepsize) print("c(%i) = %e" % (n, coeffs[n])) print("Constructing the approximate hydrogen wave") hydro_approx = 0 all_steps = {} for n in range(basis_dimension): hydro_approx += basis_ho[n](grid)*coeffs[n] all_steps[n] = hydro_approx.copy() if pylab: line = pylab.plot(grid, all_steps[n], ':', label='max n = %i' % n) # check error numerically diff = np.max(np.abs(hydro_approx - H_ufunc(grid))) print("Error estimate: the element with largest deviation misses by %f" % diff) if diff > 0.01: print("This is much, try to increase the basis size or adjust omega") else: print("Ah, that's a pretty good approximation!") # Check visually if pylab: print("Here's a plot showing the contribution for each n") line[0].set_linestyle('-') pylab.plot(grid, H_ufunc(grid), 'r-', label='exact') pylab.legend() pylab.show() print("""Note: These binary integrators were specialized to find coefficients for a harmonic oscillator basis, but they can process any wave function as long as it is available as a vector and defined on a grid with equidistant points. That is, on any grid you get from numpy.linspace. To make the integrators even more flexible, you can setup the harmonic oscillator solutions with symbolic parameters omega and l. Then the autowrapped binary routine will take these scalar variables as arguments, so that the integrators can find coefficients for *any* isotropic harmonic oscillator basis. """) if __name__ == '__main__': main() sympy-sympy-1.9/examples/advanced/autowrap_ufuncify.py000077500000000000000000000045241412543434000234420ustar00rootroot00000000000000#!/usr/bin/env python """ Setup ufuncs for the legendre polynomials ----------------------------------------- This example demonstrates how you can use the ufuncify utility in SymPy to create fast, customized universal functions for use with numpy arrays. An autowrapped sympy expression can be significantly faster than what you would get by applying a sequence of the ufuncs shipped with numpy. [0] You need to have numpy installed to run this example, as well as a working fortran compiler. [0]: http://ojensen.wordpress.com/2010/08/10/fast-ufunc-ish-hydrogen-solutions/ """ import sys from sympy.external import import_module np = import_module('numpy') if not np: sys.exit("Cannot import numpy. Exiting.") plt = import_module('matplotlib.pyplot') if not plt: sys.exit("Cannot import matplotlib.pyplot. Exiting.") import mpmath from sympy.utilities.autowrap import ufuncify from sympy import symbols, legendre, pprint def main(): print(__doc__) x = symbols('x') # a numpy array we can apply the ufuncs to grid = np.linspace(-1, 1, 1000) # set mpmath precision to 20 significant numbers for verification mpmath.mp.dps = 20 print("Compiling legendre ufuncs and checking results:") # Let's also plot the ufunc's we generate for n in range(6): # Setup the SymPy expression to ufuncify expr = legendre(n, x) print("The polynomial of degree %i is" % n) pprint(expr) # This is where the magic happens: binary_poly = ufuncify(x, expr) # It's now ready for use with numpy arrays polyvector = binary_poly(grid) # let's check the values against mpmath's legendre function maxdiff = 0 for j in range(len(grid)): precise_val = mpmath.legendre(n, grid[j]) diff = abs(polyvector[j] - precise_val) if diff > maxdiff: maxdiff = diff print("The largest error in applied ufunc was %e" % maxdiff) assert maxdiff < 1e-14 # We can also attach the autowrapped legendre polynomial to a sympy # function and plot values as they are calculated by the binary function plot1 = plt.pyplot.plot(grid, polyvector, hold=True) print("Here's a plot with values calculated by the wrapped binary functions") plt.pyplot.show() if __name__ == '__main__': main() sympy-sympy-1.9/examples/advanced/curvilinear_coordinates.py000077500000000000000000000071561412543434000246110ustar00rootroot00000000000000#!/usr/bin/env python """ This example shows how to work with coordinate transformations, curvilinear coordinates and a little bit with differential geometry. It takes polar, cylindrical, spherical, rotating disk coordinates and others and calculates all kinds of interesting properties, like Jacobian, metric tensor, Laplace operator, ... """ from sympy import var, sin, cos, pprint, Matrix, eye, trigsimp, Eq, \ Function, simplify, sinh, cosh, expand, symbols def laplace(f, g_inv, g_det, X): """ Calculates Laplace(f), using the inverse metric g_inv, the determinant of the metric g_det, all in variables X. """ r = 0 for i in range(len(X)): for j in range(len(X)): r += g_inv[i, j]*f.diff(X[i]).diff(X[j]) for sigma in range(len(X)): for alpha in range(len(X)): r += g_det.diff(X[sigma]) * g_inv[sigma, alpha] * \ f.diff(X[alpha]) / (2*g_det) return r def transform(name, X, Y, *, g_correct=None, recursive=False): """ Transforms from cartesian coordinates X to any curvilinear coordinates Y. It printing useful information, like Jacobian, metric tensor, determinant of metric, Laplace operator in the new coordinates, ... g_correct ... if not None, it will be taken as the metric --- this is useful if sympy's trigsimp() is not powerful enough to simplify the metric so that it is usable for later calculation. Leave it as None, only if the metric that transform() prints is not simplified, you can help it by specifying the correct one. recursive ... apply recursive trigonometric simplification (use only when needed, as it is an expensive operation) """ print("_"*80) print("Transformation:", name) for x, y in zip(X, Y): pprint(Eq(y, x)) J = X.jacobian(Y) print("Jacobian:") pprint(J) g = J.T*eye(J.shape[0])*J g = g.applyfunc(expand) print("metric tensor g_{ij}:") pprint(g) if g_correct is not None: g = g_correct print("metric tensor g_{ij} specified by hand:") pprint(g) print("inverse metric tensor g^{ij}:") g_inv = g.inv(method="ADJ") g_inv = g_inv.applyfunc(simplify) pprint(g_inv) print("det g_{ij}:") g_det = g.det() pprint(g_det) f = Function("f")(*list(Y)) print("Laplace:") pprint(laplace(f, g_inv, g_det, Y)) def main(): mu, nu, rho, theta, phi, sigma, tau, a, t, x, y, z, w = symbols( "mu, nu, rho, theta, phi, sigma, tau, a, t, x, y, z, w") transform("polar", Matrix([rho*cos(phi), rho*sin(phi)]), [rho, phi]) transform("cylindrical", Matrix([rho*cos(phi), rho*sin(phi), z]), [rho, phi, z]) transform("spherical", Matrix([rho*sin(theta)*cos(phi), rho*sin(theta)*sin(phi), rho*cos(theta)]), [rho, theta, phi], recursive=True ) transform("rotating disk", Matrix([t, x*cos(w*t) - y*sin(w*t), x*sin(w*t) + y*cos(w*t), z]), [t, x, y, z]) transform("parabolic", Matrix([sigma*tau, (tau**2 - sigma**2) / 2]), [sigma, tau]) transform("bipolar", Matrix([a*sinh(tau)/(cosh(tau)-cos(sigma)), a*sin(sigma)/(cosh(tau)-cos(sigma))]), [sigma, tau] ) transform("elliptic", Matrix([a*cosh(mu)*cos(nu), a*sinh(mu)*sin(nu)]), [mu, nu] ) if __name__ == "__main__": main() sympy-sympy-1.9/examples/advanced/dense_coding_example.py000077500000000000000000000027351412543434000240260ustar00rootroot00000000000000#!/usr/bin/env python """Demonstration of quantum dense coding.""" from sympy import pprint from sympy.physics.quantum import qapply from sympy.physics.quantum.gate import H, X, Z, CNOT from sympy.physics.quantum.grover import superposition_basis def main(): psi = superposition_basis(2) psi # Dense coding demo: # Assume Alice has the left QBit in psi print("An even superposition of 2 qubits. Assume Alice has the left QBit.") pprint(psi) # The corresponding gates applied to Alice's QBit are: # Identity Gate (1), Not Gate (X), Z Gate (Z), Z Gate and Not Gate (ZX) # Then there's the controlled not gate (with Alice's as control):CNOT(1, 0) # And the Hadamard gate applied to Alice's Qbit: H(1) # To Send Bob the message |0>|0> print("To Send Bob the message |00>.") circuit = H(1)*CNOT(1, 0) result = qapply(circuit*psi) result pprint(result) # To send Bob the message |0>|1> print("To Send Bob the message |01>.") circuit = H(1)*CNOT(1, 0)*X(1) result = qapply(circuit*psi) result pprint(result) # To send Bob the message |1>|0> print("To Send Bob the message |10>.") circuit = H(1)*CNOT(1, 0)*Z(1) result = qapply(circuit*psi) result pprint(result) # To send Bob the message |1>|1> print("To Send Bob the message |11>.") circuit = H(1)*CNOT(1, 0)*Z(1)*X(1) result = qapply(circuit*psi) result pprint(result) if __name__ == "__main__": main() sympy-sympy-1.9/examples/advanced/fem.py000077500000000000000000000126771412543434000204470ustar00rootroot00000000000000#!/usr/bin/env python """FEM library Demonstrates some simple finite element definitions, and computes a mass matrix $ python fem.py [ 1/60, 0, -1/360, 0, -1/90, -1/360] [ 0, 4/45, 0, 2/45, 2/45, -1/90] [-1/360, 0, 1/60, -1/90, 0, -1/360] [ 0, 2/45, -1/90, 4/45, 2/45, 0] [ -1/90, 2/45, 0, 2/45, 4/45, 0] [-1/360, -1/90, -1/360, 0, 0, 1/60] """ from sympy import symbols, Symbol, factorial, Rational, zeros, eye, \ integrate, diff, pprint, reduced x, y, z = symbols('x,y,z') class ReferenceSimplex: def __init__(self, nsd): self.nsd = nsd if nsd <= 3: coords = symbols('x,y,z')[:nsd] else: coords = [Symbol("x_%d" % d) for d in range(nsd)] self.coords = coords def integrate(self, f): coords = self.coords nsd = self.nsd limit = 1 for p in coords: limit -= p intf = f for d in range(0, nsd): p = coords[d] limit += p intf = integrate(intf, (p, 0, limit)) return intf def bernstein_space(order, nsd): if nsd > 3: raise RuntimeError("Bernstein only implemented in 1D, 2D, and 3D") sum = 0 basis = [] coeff = [] if nsd == 1: b1, b2 = x, 1 - x for o1 in range(0, order + 1): for o2 in range(0, order + 1): if o1 + o2 == order: aij = Symbol("a_%d_%d" % (o1, o2)) sum += aij*binomial(order, o1)*pow(b1, o1)*pow(b2, o2) basis.append(binomial(order, o1)*pow(b1, o1)*pow(b2, o2)) coeff.append(aij) if nsd == 2: b1, b2, b3 = x, y, 1 - x - y for o1 in range(0, order + 1): for o2 in range(0, order + 1): for o3 in range(0, order + 1): if o1 + o2 + o3 == order: aij = Symbol("a_%d_%d_%d" % (o1, o2, o3)) fac = factorial(order) / (factorial(o1)*factorial(o2)*factorial(o3)) sum += aij*fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3) basis.append(fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)) coeff.append(aij) if nsd == 3: b1, b2, b3, b4 = x, y, z, 1 - x - y - z for o1 in range(0, order + 1): for o2 in range(0, order + 1): for o3 in range(0, order + 1): for o4 in range(0, order + 1): if o1 + o2 + o3 + o4 == order: aij = Symbol("a_%d_%d_%d_%d" % (o1, o2, o3, o4)) fac = factorial(order)/(factorial(o1)*factorial(o2)*factorial(o3)*factorial(o4)) sum += aij*fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)*pow(b4, o4) basis.append(fac*pow(b1, o1)*pow(b2, o2)*pow(b3, o3)*pow(b4, o4)) coeff.append(aij) return sum, coeff, basis def create_point_set(order, nsd): h = Rational(1, order) set = [] if nsd == 1: for i in range(0, order + 1): x = i*h if x <= 1: set.append((x, y)) if nsd == 2: for i in range(0, order + 1): x = i*h for j in range(0, order + 1): y = j*h if x + y <= 1: set.append((x, y)) if nsd == 3: for i in range(0, order + 1): x = i*h for j in range(0, order + 1): y = j*h for k in range(0, order + 1): z = k*h if x + y + z <= 1: set.append((x, y, z)) return set def create_matrix(equations, coeffs): A = zeros(len(equations)) i = 0 j = 0 for j in range(0, len(coeffs)): c = coeffs[j] for i in range(0, len(equations)): e = equations[i] d, _ = reduced(e, [c]) A[i, j] = d[0] return A class Lagrange: def __init__(self, nsd, order): self.nsd = nsd self.order = order self.compute_basis() def nbf(self): return len(self.N) def compute_basis(self): order = self.order nsd = self.nsd N = [] pol, coeffs, basis = bernstein_space(order, nsd) points = create_point_set(order, nsd) equations = [] for p in points: ex = pol.subs(x, p[0]) if nsd > 1: ex = ex.subs(y, p[1]) if nsd > 2: ex = ex.subs(z, p[2]) equations.append(ex) A = create_matrix(equations, coeffs) Ainv = A.inv() b = eye(len(equations)) xx = Ainv*b for i in range(0, len(equations)): Ni = pol for j in range(0, len(coeffs)): Ni = Ni.subs(coeffs[j], xx[j, i]) N.append(Ni) self.N = N def main(): t = ReferenceSimplex(2) fe = Lagrange(2, 2) u = 0 # compute u = sum_i u_i N_i us = [] for i in range(0, fe.nbf()): ui = Symbol("u_%d" % i) us.append(ui) u += ui*fe.N[i] J = zeros(fe.nbf()) for i in range(0, fe.nbf()): Fi = u*fe.N[i] print(Fi) for j in range(0, fe.nbf()): uj = us[j] integrands = diff(Fi, uj) print(integrands) J[j, i] = t.integrate(integrands) pprint(J) if __name__ == "__main__": main() sympy-sympy-1.9/examples/advanced/gibbs_phenomenon.py000077500000000000000000000067301412543434000232050ustar00rootroot00000000000000#!/usr/bin/env python """ This example illustrates the Gibbs phenomenon. It also calculates the Wilbraham-Gibbs constant by two approaches: 1) calculating the fourier series of the step function and determining the first maximum. 2) evaluating the integral for si(pi). See: * https://en.wikipedia.org/wiki/Gibbs_phenomena """ from sympy import var, sqrt, integrate, conjugate, seterr, Abs, pprint, I, pi,\ sin, cos, sign, lambdify, Integral, S x = var("x", real=True) def l2_norm(f, lim): """ Calculates L2 norm of the function "f", over the domain lim=(x, a, b). x ...... the independent variable in f over which to integrate a, b ... the limits of the interval Examples ======== >>> from sympy import Symbol >>> from gibbs_phenomenon import l2_norm >>> x = Symbol('x', real=True) >>> l2_norm(1, (x, -1, 1)) sqrt(2) >>> l2_norm(x, (x, -1, 1)) sqrt(6)/3 """ return sqrt(integrate(Abs(f)**2, lim)) def l2_inner_product(a, b, lim): """ Calculates the L2 inner product (a, b) over the domain lim. """ return integrate(conjugate(a)*b, lim) def l2_projection(f, basis, lim): """ L2 projects the function f on the basis over the domain lim. """ r = 0 for b in basis: r += l2_inner_product(f, b, lim) * b return r def l2_gram_schmidt(list, lim): """ Orthonormalizes the "list" of functions using the Gram-Schmidt process. Examples ======== >>> from sympy import Symbol >>> from gibbs_phenomenon import l2_gram_schmidt >>> x = Symbol('x', real=True) # perform computations over reals to save time >>> l2_gram_schmidt([1, x, x**2], (x, -1, 1)) [sqrt(2)/2, sqrt(6)*x/2, 3*sqrt(10)*(x**2 - 1/3)/4] """ r = [] for a in list: if r == []: v = a else: v = a - l2_projection(a, r, lim) v_norm = l2_norm(v, lim) if v_norm == 0: raise ValueError("The sequence is not linearly independent.") r.append(v/v_norm) return r def integ(f): return integrate(f, (x, -pi, 0)) + integrate(-f, (x, 0, pi)) def series(L): """ Normalizes the series. """ r = 0 for b in L: r += integ(b)*b return r def msolve(f, x): """ Finds the first root of f(x) to the left of 0. The x0 and dx below are tailored to get the correct result for our particular function --- the general solver often overshoots the first solution. """ f = lambdify(x, f) x0 = -0.001 dx = 0.001 while f(x0 - dx) * f(x0) > 0: x0 = x0 - dx x_max = x0 - dx x_min = x0 assert f(x_max) > 0 assert f(x_min) < 0 for n in range(100): x0 = (x_max + x_min)/2 if f(x0) > 0: x_max = x0 else: x_min = x0 return x0 def main(): L = [1] for i in range(1, 100): L.append(cos(i*x)) L.append(sin(i*x)) # next 2 lines equivalent to L = l2_gram_schmidt(L, (x, -pi, pi)), but faster: L[0] /= sqrt(2) L = [f/sqrt(pi) for f in L] f = series(L) print("Fourier series of the step function") pprint(f) x0 = msolve(f.diff(x), x) print("x-value of the maximum:", x0) max = f.subs(x, x0).evalf() print("y-value of the maximum:", max) g = max*pi/2 print("Wilbraham-Gibbs constant :", g.evalf()) print("Wilbraham-Gibbs constant (exact):", \ Integral(sin(x)/x, (x, 0, pi)).evalf()) if __name__ == "__main__": main() sympy-sympy-1.9/examples/advanced/grover_example.py000077500000000000000000000040411412543434000227010ustar00rootroot00000000000000#!/usr/bin/env python """Grover's quantum search algorithm example.""" from sympy import pprint from sympy.physics.quantum import qapply from sympy.physics.quantum.qubit import IntQubit from sympy.physics.quantum.grover import (OracleGate, superposition_basis, WGate, grover_iteration) def demo_vgate_app(v): for i in range(2**v.nqubits): print('qapply(v*IntQubit(%i, %r))' % (i, v.nqubits)) pprint(qapply(v*IntQubit(i, nqubits=v.nqubits))) qapply(v*IntQubit(i, nqubits=v.nqubits)) def black_box(qubits): return True if qubits == IntQubit(1, nqubits=qubits.nqubits) else False def main(): print() print('Demonstration of Grover\'s Algorithm') print('The OracleGate or V Gate carries the unknown function f(x)') print('> V|x> = ((-1)^f(x))|x> where f(x) = 1 when x = a (True in our case)') print('> and 0 (False in our case) otherwise') print() nqubits = 2 print('nqubits = ', nqubits) v = OracleGate(nqubits, black_box) print('Oracle or v = OracleGate(%r, black_box)' % nqubits) print() psi = superposition_basis(nqubits) print('psi:') pprint(psi) demo_vgate_app(v) print('qapply(v*psi)') pprint(qapply(v*psi)) print() w = WGate(nqubits) print('WGate or w = WGate(%r)' % nqubits) print('On a 2 Qubit system like psi, 1 iteration is enough to yield |1>') print('qapply(w*v*psi)') pprint(qapply(w*v*psi)) print() nqubits = 3 print('On a 3 Qubit system, it requires 2 iterations to achieve') print('|1> with high enough probability') psi = superposition_basis(nqubits) print('psi:') pprint(psi) v = OracleGate(nqubits, black_box) print('Oracle or v = OracleGate(%r, black_box)' % nqubits) print() print('iter1 = grover.grover_iteration(psi, v)') iter1 = qapply(grover_iteration(psi, v)) pprint(iter1) print() print('iter2 = grover.grover_iteration(iter1, v)') iter2 = qapply(grover_iteration(iter1, v)) pprint(iter2) print() if __name__ == "__main__": main() sympy-sympy-1.9/examples/advanced/hydrogen.py000077500000000000000000000012761412543434000215100ustar00rootroot00000000000000#!/usr/bin/env python """ This example shows how to work with the Hydrogen radial wavefunctions. """ from sympy import Eq, Integral, oo, pprint, symbols from sympy.physics.hydrogen import R_nl def main(): print("Hydrogen radial wavefunctions:") a, r = symbols("a r") print("R_{21}:") pprint(R_nl(2, 1, a, r)) print("R_{60}:") pprint(R_nl(6, 0, a, r)) print("Normalization:") i = Integral(R_nl(1, 0, 1, r)**2 * r**2, (r, 0, oo)) pprint(Eq(i, i.doit())) i = Integral(R_nl(2, 0, 1, r)**2 * r**2, (r, 0, oo)) pprint(Eq(i, i.doit())) i = Integral(R_nl(2, 1, 1, r)**2 * r**2, (r, 0, oo)) pprint(Eq(i, i.doit())) if __name__ == '__main__': main() sympy-sympy-1.9/examples/advanced/identitysearch_example.ipynb000066400000000000000000000121061412543434000251030ustar00rootroot00000000000000{ "metadata": { "name": "identitysearch_example" }, "nbformat": 2, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": true, "input": [ "\"\"\"Demonstration of quantum gate identity search.\"\"\"", "", "from sympy.physics.quantum.gate import (X, Y, Z, H, S, T, CNOT,", " IdentityGate, CGate, gate_simp)", "from sympy.physics.quantum.identitysearch import *", "from sympy.physics.quantum.dagger import Dagger" ], "language": "python", "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": true, "input": [ "# Declare a few quantum gates", "x = X(0)", "y = Y(0)", "z = Z(0)", "h = H(0)", "cnot = CNOT(1,0)", "cgate_z = CGate((0,), Z(1))" ], "language": "python", "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "# Start with the trivial cases", "gate_list = [x]", "", "bfs_identity_search(gate_list, 1, max_depth=2)" ], "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 6, "text": [ "set([GateIdentity(X(0), X(0))])" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "gate_list = [y]", "", "bfs_identity_search(gate_list, 1, max_depth=2)" ], "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 7, "text": [ "set([GateIdentity(Y(0), Y(0))])" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "# bfs_identity_search looks for circuits that reduce to a", "# scalar value unless told otherwise.", "# The following list should produce 4 identities as a result.", "gate_list = [x, y, z]", "", "bfs_identity_search(gate_list, 2)" ], "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 9, "text": [ "set([GateIdentity(X(0), X(0)),", " GateIdentity(Z(0), Z(0)),", " GateIdentity(X(0), Y(0), Z(0)),", " GateIdentity(Y(0), Y(0))])" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "gate_list = [x, y, z, h]", "", "bfs_identity_search(gate_list, 2)" ], "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 10, "text": [ "set([GateIdentity(Y(0), H(0), Y(0), H(0)),", " GateIdentity(X(0), Y(0), X(0), Y(0)),", " GateIdentity(X(0), Y(0), Z(0)),", " GateIdentity(X(0), H(0), Z(0), H(0)),", " GateIdentity(Z(0), Z(0)),", " GateIdentity(X(0), X(0)),", " GateIdentity(Y(0), Y(0)),", " GateIdentity(X(0), Z(0), X(0), Z(0)),", " GateIdentity(Y(0), Z(0), Y(0), Z(0)),", " GateIdentity(H(0), H(0))])" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "# One has the option to limit the max size of the circuit.", "# The default size is the size of the gate list.", "bfs_identity_search(gate_list, 2, max_depth=3)" ], "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 12, "text": [ "set([GateIdentity(X(0), X(0)),", " GateIdentity(X(0), Y(0), Z(0)),", " GateIdentity(Z(0), Z(0)),", " GateIdentity(H(0), H(0)),", " GateIdentity(Y(0), Y(0))])" ] } ], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "# One also has the option to find circuits that only reduce", "# to the Identity matrix rather than only scalar matrices.", "bfs_identity_search(gate_list, 2, identity_only=True)" ], "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 13, "text": [ "set([GateIdentity(X(0), X(0)),", " GateIdentity(Z(0), Z(0)),", " GateIdentity(H(0), H(0)),", " GateIdentity(Y(0), Y(0))])" ] } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": false, "input": [ "gate_list = [cnot, cgate_z, h]", "", "bfs_identity_search(gate_list, 2, max_depth=4)" ], "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 14, "text": [ "set([GateIdentity(CNOT(1,0), H(0), C((0),Z(1)), H(0)),", " GateIdentity(H(0), H(0)),", " GateIdentity(C((0),Z(1)), C((0),Z(1))),", " GateIdentity(CNOT(1,0), CNOT(1,0))])" ] } ], "prompt_number": 14 } ] } ] }sympy-sympy-1.9/examples/advanced/pidigits.py000077500000000000000000000052341412543434000215030ustar00rootroot00000000000000#!/usr/bin/env python """Pi digits example Example shows arbitrary precision using mpmath with the computation of the digits of pi. """ from mpmath import libmp, pi import math from sympy.core.compatibility import clock import sys def display_fraction(digits, *, skip=0, colwidth=10, columns=5): """Pretty printer for first n digits of a fraction""" perline = colwidth * columns printed = 0 for linecount in range((len(digits) - skip) // (colwidth * columns)): line = digits[skip + linecount*perline:skip + (linecount + 1)*perline] for i in range(columns): print(line[i*colwidth: (i + 1)*colwidth],) print(":", (linecount + 1)*perline) if (linecount + 1) % 10 == 0: print() printed += colwidth*columns rem = (len(digits) - skip) % (colwidth * columns) if rem: buf = digits[-rem:] s = "" for i in range(columns): s += buf[:colwidth].ljust(colwidth + 1, " ") buf = buf[colwidth:] print(s + ":", printed + colwidth*columns) def calculateit(func, base, n, tofile): """Writes first n base-digits of a mpmath function to file""" prec = 100 intpart = libmp.numeral(3, base) if intpart == 0: skip = 0 else: skip = len(intpart) print("Step 1 of 2: calculating binary value...") prec = int(n*math.log(base, 2)) + 10 t = clock() a = func(prec) step1_time = clock() - t print("Step 2 of 2: converting to specified base...") t = clock() d = libmp.bin_to_radix(a.man, -a.exp, base, n) d = libmp.numeral(d, base, n) step2_time = clock() - t print("\nWriting output...\n") if tofile: out_ = sys.stdout sys.stdout = tofile print("%i base-%i digits of pi:\n" % (n, base)) print(intpart, ".\n") display_fraction(d, skip=skip, colwidth=10, columns=5) if tofile: sys.stdout = out_ print("\nFinished in %f seconds (%f calc, %f convert)" % \ ((step1_time + step2_time), step1_time, step2_time)) def interactive(): """Simple function to interact with user""" print("Compute digits of pi with SymPy\n") base = int(input("Which base? (2-36, 10 for decimal) \n> ")) digits = int(input("How many digits? (enter a big number, say, 10000)\n> ")) tofile = input("Output to file? (enter a filename, or just press enter\nto print directly to the screen) \n> ") if tofile: tofile = open(tofile, "w") calculateit(pi, base, digits, tofile) def main(): """A non-interactive runner""" base = 16 digits = 500 tofile = None calculateit(pi, base, digits, tofile) if __name__ == "__main__": interactive() sympy-sympy-1.9/examples/advanced/pyglet_plotting.py000077500000000000000000000160121412543434000231070ustar00rootroot00000000000000#!/usr/bin/env python """ Plotting Examples Suggested Usage: python -i pyglet_plotting.py """ from sympy import symbols, sin, cos, pi, sqrt from sympy.core.compatibility import clock from sympy.plotting.pygletplot import PygletPlot from time import sleep def main(): x, y, z = symbols('x,y,z') # toggle axes visibility with F5, colors with F6 axes_options = 'visible=false; colored=true; label_ticks=true; label_axes=true; overlay=true; stride=0.5' # axes_options = 'colored=false; overlay=false; stride=(1.0, 0.5, 0.5)' p = PygletPlot( width=600, height=500, ortho=False, invert_mouse_zoom=False, axes=axes_options, antialiasing=True) examples = [] def example_wrapper(f): examples.append(f) return f @example_wrapper def mirrored_saddles(): p[5] = x**2 - y**2, [20], [20] p[6] = y**2 - x**2, [20], [20] @example_wrapper def mirrored_saddles_saveimage(): p[5] = x**2 - y**2, [20], [20] p[6] = y**2 - x**2, [20], [20] p.wait_for_calculations() # although the calculation is complete, # we still need to wait for it to be # rendered, so we'll sleep to be sure. sleep(1) p.saveimage("plot_example.png") @example_wrapper def mirrored_ellipsoids(): p[2] = x**2 + y**2, [40], [40], 'color=zfade' p[3] = -x**2 - y**2, [40], [40], 'color=zfade' @example_wrapper def saddle_colored_by_derivative(): f = x**2 - y**2 p[1] = f, 'style=solid' p[1].color = abs(f.diff(x)), abs(f.diff(x) + f.diff(y)), abs(f.diff(y)) @example_wrapper def ding_dong_surface(): f = sqrt(1.0 - y)*y p[1] = f, [x, 0, 2*pi, 40], [y, - 1, 4, 100], 'mode=cylindrical; style=solid; color=zfade4' @example_wrapper def polar_circle(): p[7] = 1, 'mode=polar' @example_wrapper def polar_flower(): p[8] = 1.5*sin(4*x), [160], 'mode=polar' p[8].color = z, x, y, (0.5, 0.5, 0.5), ( 0.8, 0.8, 0.8), (x, y, None, z) # z is used for t @example_wrapper def simple_cylinder(): p[9] = 1, 'mode=cylindrical' @example_wrapper def cylindrical_hyperbola(): # (note that polar is an alias for cylindrical) p[10] = 1/y, 'mode=polar', [x], [y, -2, 2, 20] @example_wrapper def extruded_hyperbolas(): p[11] = 1/x, [x, -10, 10, 100], [1], 'style=solid' p[12] = -1/x, [x, -10, 10, 100], [1], 'style=solid' @example_wrapper def torus(): a, b = 1, 0.5 # radius, thickness p[13] = (a + b*cos(x))*cos(y), (a + b*cos(x)) *\ sin(y), b*sin(x), [x, 0, pi*2, 40], [y, 0, pi*2, 40] @example_wrapper def warped_torus(): a, b = 2, 1 # radius, thickness p[13] = (a + b*cos(x))*cos(y), (a + b*cos(x))*sin(y), b *\ sin(x) + 0.5*sin(4*y), [x, 0, pi*2, 40], [y, 0, pi*2, 40] @example_wrapper def parametric_spiral(): p[14] = cos(y), sin(y), y / 10.0, [y, -4*pi, 4*pi, 100] p[14].color = x, (0.1, 0.9), y, (0.1, 0.9), z, (0.1, 0.9) @example_wrapper def multistep_gradient(): p[1] = 1, 'mode=spherical', 'style=both' # p[1] = exp(-x**2-y**2+(x*y)/4), [-1.7,1.7,100], [-1.7,1.7,100], 'style=solid' # p[1] = 5*x*y*exp(-x**2-y**2), [-2,2,100], [-2,2,100] gradient = [0.0, (0.3, 0.3, 1.0), 0.30, (0.3, 1.0, 0.3), 0.55, (0.95, 1.0, 0.2), 0.65, (1.0, 0.95, 0.2), 0.85, (1.0, 0.7, 0.2), 1.0, (1.0, 0.3, 0.2)] p[1].color = z, [None, None, z], gradient # p[1].color = 'zfade' # p[1].color = 'zfade3' @example_wrapper def lambda_vs_sympy_evaluation(): start = clock() p[4] = x**2 + y**2, [100], [100], 'style=solid' p.wait_for_calculations() print("lambda-based calculation took %s seconds." % (clock() - start)) start = clock() p[4] = x**2 + y**2, [100], [100], 'style=solid; use_sympy_eval' p.wait_for_calculations() print( "sympy substitution-based calculation took %s seconds." % (clock() - start)) @example_wrapper def gradient_vectors(): def gradient_vectors_inner(f, i): from sympy import lambdify from sympy.plotting.plot_interval import PlotInterval from pyglet.gl import glBegin, glColor3f from pyglet.gl import glVertex3f, glEnd, GL_LINES def draw_gradient_vectors(f, iu, iv): """ Create a function which draws vectors representing the gradient of f. """ dx, dy, dz = f.diff(x), f.diff(y), 0 FF = lambdify([x, y], [x, y, f]) FG = lambdify([x, y], [dx, dy, dz]) iu.v_steps /= 5 iv.v_steps /= 5 Gvl = list(list([FF(u, v), FG(u, v)] for v in iv.frange()) for u in iu.frange()) def draw_arrow(p1, p2): """ Draw a single vector. """ glColor3f(0.4, 0.4, 0.9) glVertex3f(*p1) glColor3f(0.9, 0.4, 0.4) glVertex3f(*p2) def draw(): """ Iterate through the calculated vectors and draw them. """ glBegin(GL_LINES) for u in Gvl: for v in u: point = [[v[0][0], v[0][1], v[0][2]], [v[0][0] + v[1][0], v[0][1] + v[1][1], v[0][2] + v[1][2]]] draw_arrow(point[0], point[1]) glEnd() return draw p[i] = f, [-0.5, 0.5, 25], [-0.5, 0.5, 25], 'style=solid' iu = PlotInterval(p[i].intervals[0]) iv = PlotInterval(p[i].intervals[1]) p[i].postdraw.append(draw_gradient_vectors(f, iu, iv)) gradient_vectors_inner(x**2 + y**2, 1) gradient_vectors_inner(-x**2 - y**2, 2) def help_str(): s = ("\nPlot p has been created. Useful commands: \n" " help(p), p[1] = x**2, print(p), p.clear() \n\n" "Available examples (see source in plotting.py):\n\n") for i in range(len(examples)): s += "(%i) %s\n" % (i, examples[i].__name__) s += "\n" s += "e.g. >>> example(2)\n" s += " >>> ding_dong_surface()\n" return s def example(i): if callable(i): p.clear() i() elif i >= 0 and i < len(examples): p.clear() examples[i]() else: print("Not a valid example.\n") print(p) example(0) # 0 - 15 are defined above print(help_str()) if __name__ == "__main__": main() sympy-sympy-1.9/examples/advanced/qft.py000077500000000000000000000065111412543434000204600ustar00rootroot00000000000000#!/usr/bin/env python """Quantum field theory example * https://en.wikipedia.org/wiki/Quantum_field_theory This particular example is a work in progress. Currently it calculates the scattering amplitude of the process: electron + positron -> photon -> electron + positron in QED (https://en.wikipedia.org/wiki/Quantum_electrodynamics). The aim is to be able to do any kind of calculations in QED or standard model in SymPy, but that's a long journey. """ from sympy import Basic, Symbol, Matrix, \ ones, sqrt, pprint, Eq, sympify from sympy.physics import msigma, mgamma # gamma^mu gamma0 = mgamma(0) gamma1 = mgamma(1) gamma2 = mgamma(2) gamma3 = mgamma(3) gamma5 = mgamma(5) # sigma_i sigma1 = msigma(1) sigma2 = msigma(2) sigma3 = msigma(3) E = Symbol("E", real=True) m = Symbol("m", real=True) def u(p, r): """ p = (p1, p2, p3); r = 0,1 """ if r not in [1, 2]: raise ValueError("Value of r should lie between 1 and 2") p1, p2, p3 = p if r == 1: ksi = Matrix([[1], [0]]) else: ksi = Matrix([[0], [1]]) a = (sigma1*p1 + sigma2*p2 + sigma3*p3) / (E + m)*ksi if a == 0: a = zeros(2, 1) return sqrt(E + m) *\ Matrix([[ksi[0, 0]], [ksi[1, 0]], [a[0, 0]], [a[1, 0]]]) def v(p, r): """ p = (p1, p2, p3); r = 0,1 """ if r not in [1, 2]: raise ValueError("Value of r should lie between 1 and 2") p1, p2, p3 = p if r == 1: ksi = Matrix([[1], [0]]) else: ksi = -Matrix([[0], [1]]) a = (sigma1*p1 + sigma2*p2 + sigma3*p3) / (E + m)*ksi if a == 0: a = zeros(2, 1) return sqrt(E + m) *\ Matrix([[a[0, 0]], [a[1, 0]], [ksi[0, 0]], [ksi[1, 0]]]) def pslash(p): p1, p2, p3 = p p0 = sqrt(m**2 + p1**2 + p2**2 + p3**2) return gamma0*p0 - gamma1*p1 - gamma2*p2 - gamma3*p3 def Tr(M): return M.trace() def xprint(lhs, rhs): pprint(Eq(sympify(lhs), rhs)) def main(): a = Symbol("a", real=True) b = Symbol("b", real=True) c = Symbol("c", real=True) p = (a, b, c) assert u(p, 1).D*u(p, 2) == Matrix(1, 1, [0]) assert u(p, 2).D*u(p, 1) == Matrix(1, 1, [0]) p1, p2, p3 = [Symbol(x, real=True) for x in ["p1", "p2", "p3"]] pp1, pp2, pp3 = [Symbol(x, real=True) for x in ["pp1", "pp2", "pp3"]] k1, k2, k3 = [Symbol(x, real=True) for x in ["k1", "k2", "k3"]] kp1, kp2, kp3 = [Symbol(x, real=True) for x in ["kp1", "kp2", "kp3"]] p = (p1, p2, p3) pp = (pp1, pp2, pp3) k = (k1, k2, k3) kp = (kp1, kp2, kp3) mu = Symbol("mu") e = (pslash(p) + m*ones(4))*(pslash(k) - m*ones(4)) f = pslash(p) + m*ones(4) g = pslash(p) - m*ones(4) xprint('Tr(f*g)', Tr(f*g)) M0 = [(v(pp, 1).D*mgamma(mu)*u(p, 1))*(u(k, 1).D*mgamma(mu, True) * v(kp, 1)) for mu in range(4)] M = M0[0] + M0[1] + M0[2] + M0[3] M = M[0] if not isinstance(M, Basic): raise TypeError("Invalid type of variable") d = Symbol("d", real=True) # d=E+m xprint('M', M) print("-"*40) M = ((M.subs(E, d - m)).expand()*d**2).expand() xprint('M2', 1 / (E + m)**2*M) print("-"*40) x, y = M.as_real_imag() xprint('Re(M)', x) xprint('Im(M)', y) e = x**2 + y**2 xprint('abs(M)**2', e) print("-"*40) xprint('Expand(abs(M)**2)', e.expand()) if __name__ == "__main__": main() sympy-sympy-1.9/examples/advanced/relativity.py000077500000000000000000000103301412543434000220540ustar00rootroot00000000000000#!/usr/bin/env python """ This example calculates the Ricci tensor from the metric and does this on the example of Schwarzschild solution. If you want to derive this by hand, follow the wiki page here: https://en.wikipedia.org/wiki/Deriving_the_Schwarzschild_solution Also read the above wiki and follow the references from there if something is not clear, like what the Ricci tensor is, etc. """ from sympy import (exp, Symbol, sin, dsolve, Function, Matrix, Eq, pprint, solve) def grad(f, X): a = [] for x in X: a.append(f.diff(x)) return a def d(m, x): return grad(m[0, 0], x) class MT: def __init__(self, m): self.gdd = m self.guu = m.inv() def __str__(self): return "g_dd =\n" + str(self.gdd) def dd(self, i, j): return self.gdd[i, j] def uu(self, i, j): return self.guu[i, j] class G: def __init__(self, g, x): self.g = g self.x = x def udd(self, i, k, l): g = self.g x = self.x r = 0 for m in [0, 1, 2, 3]: r += g.uu(i, m)/2 * (g.dd(m, k).diff(x[l]) + g.dd(m, l).diff(x[k]) - g.dd(k, l).diff(x[m])) return r class Riemann: def __init__(self, G, x): self.G = G self.x = x def uddd(self, rho, sigma, mu, nu): G = self.G x = self.x r = G.udd(rho, nu, sigma).diff(x[mu]) - G.udd(rho, mu, sigma).diff(x[nu]) for lam in [0, 1, 2, 3]: r += G.udd(rho, mu, lam)*G.udd(lam, nu, sigma) \ - G.udd(rho, nu, lam)*G.udd(lam, mu, sigma) return r class Ricci: def __init__(self, R, x): self.R = R self.x = x self.g = R.G.g def dd(self, mu, nu): R = self.R x = self.x r = 0 for lam in [0, 1, 2, 3]: r += R.uddd(lam, mu, lam, nu) return r def ud(self, mu, nu): r = 0 for lam in [0, 1, 2, 3]: r += self.g.uu(mu, lam)*self.dd(lam, nu) return r.expand() def curvature(Rmn): return Rmn.ud(0, 0) + Rmn.ud(1, 1) + Rmn.ud(2, 2) + Rmn.ud(3, 3) nu = Function("nu") lam = Function("lambda") t = Symbol("t") r = Symbol("r") theta = Symbol(r"theta") phi = Symbol(r"phi") # general, spherically symmetric metric gdd = Matrix(( (-exp(nu(r)), 0, 0, 0), (0, exp(lam(r)), 0, 0), (0, 0, r**2, 0), (0, 0, 0, r**2*sin(theta)**2) )) g = MT(gdd) X = (t, r, theta, phi) Gamma = G(g, X) Rmn = Ricci(Riemann(Gamma, X), X) def pprint_Gamma_udd(i, k, l): pprint(Eq(Symbol('Gamma^%i_%i%i' % (i, k, l)), Gamma.udd(i, k, l))) def pprint_Rmn_dd(i, j): pprint(Eq(Symbol('R_%i%i' % (i, j)), Rmn.dd(i, j))) # from Differential Equations example def eq1(): r = Symbol("r") e = Rmn.dd(0, 0) e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) def eq2(): r = Symbol("r") e = Rmn.dd(1, 1) C = Symbol("CC") e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) def eq3(): r = Symbol("r") e = Rmn.dd(2, 2) e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) def eq4(): r = Symbol("r") e = Rmn.dd(3, 3) e = e.subs(nu(r), -lam(r)) pprint(dsolve(e, lam(r))) pprint(dsolve(e, lam(r), 'best')) def main(): print("Initial metric:") pprint(gdd) print("-"*40) print("Christoffel symbols:") pprint_Gamma_udd(0, 1, 0) pprint_Gamma_udd(0, 0, 1) print() pprint_Gamma_udd(1, 0, 0) pprint_Gamma_udd(1, 1, 1) pprint_Gamma_udd(1, 2, 2) pprint_Gamma_udd(1, 3, 3) print() pprint_Gamma_udd(2, 2, 1) pprint_Gamma_udd(2, 1, 2) pprint_Gamma_udd(2, 3, 3) print() pprint_Gamma_udd(3, 2, 3) pprint_Gamma_udd(3, 3, 2) pprint_Gamma_udd(3, 1, 3) pprint_Gamma_udd(3, 3, 1) print("-"*40) print("Ricci tensor:") pprint_Rmn_dd(0, 0) e = Rmn.dd(1, 1) pprint_Rmn_dd(1, 1) pprint_Rmn_dd(2, 2) pprint_Rmn_dd(3, 3) print("-"*40) print("Solve Einstein's equations:") e = e.subs(nu(r), -lam(r)).doit() l = dsolve(e, lam(r)) pprint(l) lamsol = solve(l, lam(r))[0] metric = gdd.subs(lam(r), lamsol).subs(nu(r), -lamsol) # .combine() print("metric:") pprint(metric) if __name__ == "__main__": main() sympy-sympy-1.9/examples/all.py000077500000000000000000000151141412543434000166700ustar00rootroot00000000000000#!/usr/bin/env python DESCRIPTION = """ Runs all the examples for testing purposes and reports successes and failures to stderr. An example is marked successful if the running thread does not throw an exception, for threaded examples, such as plotting, one needs to check the stderr messages as well. """ EPILOG = """ Example Usage: When no examples fail: $ ./all.py > out SUCCESSFUL: - beginner.basic [...] NO FAILED EXAMPLES $ When examples fail: $ ./all.py -w > out Traceback (most recent call last): File "./all.py", line 111, in run_examples [...] SUCCESSFUL: - beginner.basic [...] FAILED: - intermediate.mplot2D [...] $ Obviously, we want to achieve the first result. """ import imp import optparse import os import sys import traceback # add local sympy to the module path this_file = os.path.abspath(__file__) sympy_dir = os.path.join(os.path.dirname(this_file), "..") sympy_dir = os.path.normpath(sympy_dir) sys.path.insert(0, sympy_dir) import sympy TERMINAL_EXAMPLES = [ "beginner.basic", "beginner.differentiation", "beginner.expansion", "beginner.functions", "beginner.limits_examples", "beginner.precision", "beginner.print_pretty", "beginner.series", "beginner.substitution", "intermediate.coupled_cluster", "intermediate.differential_equations", "intermediate.infinite_1d_box", "intermediate.partial_differential_eqs", "intermediate.trees", "intermediate.vandermonde", "advanced.curvilinear_coordinates", "advanced.dense_coding_example", "advanced.fem", "advanced.gibbs_phenomenon", "advanced.grover_example", "advanced.hydrogen", "advanced.pidigits", "advanced.qft", "advanced.relativity", ] WINDOWED_EXAMPLES = [ "beginner.plotting_nice_plot", "intermediate.mplot2d", "intermediate.mplot3d", "intermediate.print_gtk", "advanced.autowrap_integrators", "advanced.autowrap_ufuncify", "advanced.pyglet_plotting", ] EXAMPLE_DIR = os.path.dirname(__file__) def __import__(name, globals=None, locals=None, fromlist=None): """An alternative to the import function so that we can import modules defined as strings. This code was taken from: http://docs.python.org/lib/examples-imp.html """ # Fast path: see if the module has already been imported. try: return sys.modules[name] except KeyError: pass # If any of the following calls raises an exception, # there's a problem we can't handle -- let the caller handle it. module_name = name.split('.')[-1] module_path = os.path.join(EXAMPLE_DIR, *name.split('.')[:-1]) fp, pathname, description = imp.find_module(module_name, [module_path]) try: return imp.load_module(module_name, fp, pathname, description) finally: # Since we may exit via an exception, close fp explicitly. if fp: fp.close() def load_example_module(example): """Loads modules based upon the given package name""" mod = __import__(example) return mod def run_examples(*, windowed=False, quiet=False, summary=True): """Run all examples in the list of modules. Returns a boolean value indicating whether all the examples were successful. """ successes = [] failures = [] examples = TERMINAL_EXAMPLES if windowed: examples += WINDOWED_EXAMPLES if quiet: from sympy.testing.runtests import PyTestReporter reporter = PyTestReporter() reporter.write("Testing Examples\n") reporter.write("-" * reporter.terminal_width) else: reporter = None for example in examples: if run_example(example, reporter=reporter): successes.append(example) else: failures.append(example) if summary: show_summary(successes, failures, reporter=reporter) return len(failures) == 0 def run_example(example, *, reporter=None): """Run a specific example. Returns a boolean value indicating whether the example was successful. """ if reporter: reporter.write(example) else: print("=" * 79) print("Running: ", example) try: mod = load_example_module(example) if reporter: suppress_output(mod.main) reporter.write("[PASS]", "Green", align="right") else: mod.main() return True except KeyboardInterrupt as e: raise e except: if reporter: reporter.write("[FAIL]", "Red", align="right") traceback.print_exc() return False class DummyFile: def write(self, x): pass def suppress_output(fn): """Suppresses the output of fn on sys.stdout.""" save_stdout = sys.stdout try: sys.stdout = DummyFile() fn() finally: sys.stdout = save_stdout def show_summary(successes, failures, *, reporter=None): """Shows a summary detailing which examples were successful and which failed.""" if reporter: reporter.write("-" * reporter.terminal_width) if failures: reporter.write("FAILED:\n", "Red") for example in failures: reporter.write(" %s\n" % example) else: reporter.write("ALL EXAMPLES PASSED\n", "Green") else: if successes: print("SUCCESSFUL: ", file=sys.stderr) for example in successes: print(" -", example, file=sys.stderr) else: print("NO SUCCESSFUL EXAMPLES", file=sys.stderr) if failures: print("FAILED: ", file=sys.stderr) for example in failures: print(" -", example, file=sys.stderr) else: print("NO FAILED EXAMPLES", file=sys.stderr) def main(*args, **kws): """Main script runner""" parser = optparse.OptionParser() parser.add_option('-w', '--windowed', action="store_true", dest="windowed", help="also run examples requiring windowed environment") parser.add_option('-q', '--quiet', action="store_true", dest="quiet", help="runs examples in 'quiet mode' suppressing example output and \ showing simple status messages.") parser.add_option('--no-summary', action="store_true", dest="no_summary", help="hides the summary at the end of testing the examples") (options, _) = parser.parse_args() return 0 if run_examples(windowed=options.windowed, quiet=options.quiet, summary=not options.no_summary) else 1 if __name__ == "__main__": sys.exit(main(*sys.argv[1:])) sympy-sympy-1.9/examples/beginner/000077500000000000000000000000001412543434000173325ustar00rootroot00000000000000sympy-sympy-1.9/examples/beginner/basic.py000077500000000000000000000005201412543434000207650ustar00rootroot00000000000000#!/usr/bin/env python """Basic example Demonstrates how to create symbols and print some algebra operations. """ from sympy import Symbol, pprint def main(): a = Symbol('a') b = Symbol('b') c = Symbol('c') e = ( a*b*b + 2*b*a*b )**c print('') pprint(e) print('') if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/differentiation.py000077500000000000000000000012471412543434000230650ustar00rootroot00000000000000#!/usr/bin/env python """Differentiation example Demonstrates some differentiation operations. """ from sympy import pprint, Symbol def main(): a = Symbol('a') b = Symbol('b') e = (a + 2*b)**5 print("\nExpression : ") print() pprint(e) print("\n\nDifferentiating w.r.t. a:") print() pprint(e.diff(a)) print("\n\nDifferentiating w.r.t. b:") print() pprint(e.diff(b)) print("\n\nSecond derivative of the above result w.r.t. a:") print() pprint(e.diff(b).diff(a, 2)) print("\n\nExpanding the above result:") print() pprint(e.expand().diff(b).diff(a, 2)) print() if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/expansion.py000077500000000000000000000005511412543434000217140ustar00rootroot00000000000000#!/usr/bin/env python """Expansion Example Demonstrates how to expand expressions. """ from sympy import pprint, Symbol def main(): a = Symbol('a') b = Symbol('b') e = (a + b)**5 print("\nExpression:") pprint(e) print('\nExpansion of the above expression:') pprint(e.expand()) print() if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/functions.py000077500000000000000000000006121412543434000217160ustar00rootroot00000000000000#!/usr/bin/env python """Functions example Demonstrates functions defined in SymPy. """ from sympy import pprint, Symbol, log, exp def main(): a = Symbol('a') b = Symbol('b') e = log((a + b)**5) print() pprint(e) print('\n') e = exp(e) pprint(e) print('\n') e = log(exp((a + b)**5)) pprint(e) print() if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/limits_examples.py000077500000000000000000000014551412543434000231130ustar00rootroot00000000000000#!/usr/bin/env python """Limits Example Demonstrates limits. """ from sympy import exp, log, Symbol, Rational, sin, limit, sqrt, oo def sqrt3(x): return x**Rational(1, 3) def show(computed, correct): print("computed:", computed, "correct:", correct) def main(): x = Symbol("x") show( limit(sqrt(x**2 - 5*x + 6) - x, x, oo), -Rational(5)/2 ) show( limit(x*(sqrt(x**2 + 1) - x), x, oo), Rational(1)/2 ) show( limit(x - sqrt3(x**3 - 1), x, oo), Rational(0) ) show( limit(log(1 + exp(x))/x, x, -oo), Rational(0) ) show( limit(log(1 + exp(x))/x, x, oo), Rational(1) ) show( limit(sin(3*x)/x, x, 0), Rational(3) ) show( limit(sin(5*x)/sin(2*x), x, 0), Rational(5)/2 ) show( limit(((x - 1)/(x + 1))**x, x, oo), exp(-2)) if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/plot_advanced.ipynb000066400000000000000000000045101412543434000232000ustar00rootroot00000000000000{ "metadata": { "name": "plot_advanced" }, "nbformat": 2, "worksheets": [ { "cells": [ { "cell_type": "markdown", "source": [ "## Unevaluated Integrals" ] }, { "cell_type": "code", "collapsed": true, "input": [ "from sympy.plotting import plot" ], "language": "python", "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": true, "input": [ "i = Integral(log((sin(x)**2+1)*sqrt(x**2+1)),(x,0,y))" ], "language": "python", "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "i" ], "language": "python", "outputs": [], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "i.evalf(subs={y:1})" ], "language": "python", "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(i,(y, 1, 5))" ], "language": "python", "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "source": [ "## Infinite Sums" ] }, { "cell_type": "code", "collapsed": true, "input": [ "s = summation(1/x**y,(x,1,oo))" ], "language": "python", "outputs": [], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "s" ], "language": "python", "outputs": [], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(s, (y, 2, 10))" ], "language": "python", "outputs": [], "prompt_number": 9 }, { "cell_type": "markdown", "source": [ "## Finite sums" ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot(summation(1/x,(x,1,y)), (y, 2, 10))" ], "language": "python", "outputs": [], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].only_integers = True", "", "p[0].steps = True", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 11 } ] } ] }sympy-sympy-1.9/examples/beginner/plot_colors.ipynb000066400000000000000000000155541412543434000227460ustar00rootroot00000000000000{ "metadata": { "name": "plot_colors" }, "nbformat": 2, "worksheets": [ { "cells": [ { "cell_type": "markdown", "source": [ "#Coloring" ] }, { "cell_type": "markdown", "source": [ "", "", "### Cartesian Line Plot" ] }, { "cell_type": "code", "collapsed": true, "input": [ "from sympy.plotting import plot, plot_parametric, plot3d, plot3d_parametric_line, plot3d_parametric_surface" ], "language": "python", "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot(sin(x))" ], "language": "python", "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "source": [ "", "", "If the `line_color` aesthetic is a function of arity 1 then the coloring is a function of the x value of a point." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a : a", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 3 }, { "cell_type": "markdown", "source": [ "", "", "If the arity is 2 then the coloring is a function of both coordinates." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a, b : b", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 4 }, { "cell_type": "markdown", "source": [ "### Parametric Lines" ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot_parametric(x*sin(x), x*cos(x), (x, 0, 10))" ], "language": "python", "outputs": [], "prompt_number": 5 }, { "cell_type": "markdown", "source": [ "", "", "If the arity is 1 the coloring depends on the parameter." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a : a", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 6 }, { "cell_type": "markdown", "source": [ "", "", "For arity 2 the coloring depends on coordinates." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a, b : a", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a, b : b", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 8 }, { "cell_type": "markdown", "source": [ "### 3D Parametric line" ] }, { "cell_type": "markdown", "source": [ "", "", "Arity 1 - the first parameter. Arity 2 or 3 - the first two coordinates or all coordinates." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot3d_parametric_line(sin(x)+0.1*sin(x)*cos(7*x),", "", " cos(x)+0.1*cos(x)*cos(7*x),", "", " 0.1*sin(7*x),", "", " (x, 0, 2*pi))" ], "language": "python", "outputs": [], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a : sin(4*a)", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a, b : b", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].line_color = lambda a, b, c : c", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 12 }, { "cell_type": "markdown", "source": [ "### Cartesian Surface Plot" ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot3d(sin(x)*y, (x, 0, 6*pi), (y, -5, 5))" ], "language": "python", "outputs": [], "prompt_number": 14 }, { "cell_type": "markdown", "source": [ "", "", "Arity 1, 2 or 3 for first, the two first or all coordinates." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a : a", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a, b : b", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a, b, c : c", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a, b, c : sqrt((a-3*pi)**2+b**2)", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 18 }, { "cell_type": "markdown", "source": [ "### Parametric surface plots" ] }, { "cell_type": "markdown", "source": [ "", "", "Arity 1 or 2 - first or both parameters." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot3d_parametric_surface(x*cos(4*y), x*sin(4*y), y,", "", " (x, -1, 1), (y, -1, 1))" ], "language": "python", "outputs": [], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a : a", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a, b : a*b", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 21 }, { "cell_type": "markdown", "source": [ "Arrity of 3 will color by coordinates." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a, b, c : sqrt(a**2+b**2+c**2)", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 22 } ] } ] }sympy-sympy-1.9/examples/beginner/plot_discont.ipynb000066400000000000000000000033511412543434000231000ustar00rootroot00000000000000{ "metadata": { "name": "plot_discont" }, "nbformat": 2, "worksheets": [ { "cells": [ { "cell_type": "markdown", "source": [ "The module does not cope well with discontinuities." ] }, { "cell_type": "code", "collapsed": true, "input": [ "from sympy.plotting import plot" ], "language": "python", "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(1/x)" ], "language": "python", "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(1/x,(x, 0, 3))" ], "language": "python", "outputs": [], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(Heaviside(x))" ], "language": "python", "outputs": [], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(sqrt(x))" ], "language": "python", "outputs": [], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(-sqrt(sqrt(x)),sqrt(sqrt(x)))" ], "language": "python", "outputs": [], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(LambertW(x))" ], "language": "python", "outputs": [], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(LambertW(x), sqrt(LambertW(x)), (x, -2, 1))" ], "language": "python", "outputs": [], "prompt_number": 10 } ] } ] }sympy-sympy-1.9/examples/beginner/plot_examples.py000077500000000000000000000035711412543434000225710ustar00rootroot00000000000000#! /usr/bin/env python # Check the plot docstring from sympy import Symbol, exp, sin, cos from sympy.plotting import (plot, plot_parametric, plot3d_parametric_surface, plot3d_parametric_line, plot3d) lx = range(5) ly = [i**2 for i in lx] x = Symbol('x') y = Symbol('y') u = Symbol('u') v = Symbol('v') expr = x**2 - 1 b = plot(expr, (x, 2, 4), show=False) # cartesian plot e = plot(exp(-x), (x, 0, 4), show=False) # cartesian plot (and coloring, see below) f = plot3d_parametric_line(sin(x), cos(x), x, (x, 0, 10), show=False) # 3d parametric line plot g = plot3d(sin(x)*cos(y), (x, -5, 5), (y, -10, 10), show=False) # 3d surface cartesian plot h = plot3d_parametric_surface(cos(u)*v, sin(u)*v, u, (u, 0, 10), (v, -2, 2), show=False) # 3d parametric surface plot # Some aesthetics e[0].line_color = lambda x: x / 4 f[0].line_color = lambda x, y, z: z / 10 g[0].surface_color = lambda x, y: sin(x) # Some more stuff on aesthetics - coloring wrt coordinates or parameters param_line_2d = plot_parametric((x*cos(x), x*sin(x), (x, 0, 15)), (1.1*x*cos(x), 1.1*x*sin(x), (x, 0, 15)), show=False) param_line_2d[0].line_color = lambda u: sin(u) # parametric param_line_2d[1].line_color = lambda u, v: u**2 + v**2 # coordinates param_line_2d.title = 'The inner one is colored by parameter and the outher one by coordinates' param_line_3d = plot3d_parametric_line((x*cos(x), x*sin(x), x, (x, 0, 15)), (1.5*x*cos(x), 1.5*x*sin(x), x, (x, 0, 15)), (2*x*cos(x), 2*x*sin(x), x, (x, 0, 15)), show=False) param_line_3d[0].line_color = lambda u: u # parametric param_line_3d[1].line_color = lambda u, v: u*v # first and second coordinates param_line_3d[2].line_color = lambda u, v, w: u*v*w # all coordinates if __name__ == '__main__': for p in [b, e, f, g, h, param_line_2d, param_line_3d]: p.show() sympy-sympy-1.9/examples/beginner/plot_gallery.ipynb000066400000000000000000000016371412543434000231010ustar00rootroot00000000000000{ "metadata": { "name": "plot_gallery" }, "nbformat": 2, "worksheets": [ { "cells": [ { "cell_type": "markdown", "source": [ "### Beach ball" ] }, { "cell_type": "code", "collapsed": true, "input": [ "from sympy.plotting import plot3d_parametric_surface" ], "language": "python", "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot3d_parametric_surface(sin(x)*sin(y), sin(x)*cos(y), cos(x), (x, 0, pi), (y, 0, 2*pi))" ], "language": "python", "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].surface_color = lambda a, b : cos(4*a)*sin(2*b)", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 3 } ] } ] }sympy-sympy-1.9/examples/beginner/plot_intro.ipynb000066400000000000000000000272071412543434000225760ustar00rootroot00000000000000{ "metadata": { "name": "plot_intro" }, "nbformat": 2, "worksheets": [ { "cells": [ { "cell_type": "markdown", "source": [ "#New Plotting Framework for SymPy" ] }, { "cell_type": "markdown", "source": [ "", "", "## Structure of the Module", "", "", "", "This module implements a new plotting framework for SymPy. The central class of the module is the `Plot` class that connects the data representations (subclasses of `BaseSeries`) with different plotting backends. It's not imported by default for backward compatibility with the old module.", "", "", "", "Then there are the `plot_*()` functions for plotting different kinds of plots and is better suited for interactive work.", "", "", "", "* ``plot``: Plots line plots in 2D.", "", "* ``plot_parametric``: Plots parametric line plots in 2D.", "", "* ``plot_implicit`` : Plots implicit equations and region plots in 2D", "", "* ``plot3d`` : Plots functions of two variables in 3D", "", "* ``plot3d_parametric_line``: Plots line parametric plots in 3D", "", "* ``plot3d_parametric_surface`` : Plots surface parametric plots of functions with two variables in 3D." ] }, { "cell_type": "markdown", "source": [ "##General examples" ] }, { "cell_type": "code", "collapsed": true, "input": [ "from sympy.plotting import plot, plot_parametric, plot3d, plot3d_parametric_line, plot3d_parametric_surface" ], "language": "python", "outputs": [], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot(x)" ], "language": "python", "outputs": [], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "p # the Plot object" ], "language": "python", "outputs": [], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0] # one of the data series objects" ], "language": "python", "outputs": [], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "p[0].label # an option of the data series" ], "language": "python", "outputs": [], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "p.legend # a global option of the plot" ], "language": "python", "outputs": [], "prompt_number": 13 }, { "cell_type": "code", "collapsed": false, "input": [ "p.legend = True", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 14 }, { "cell_type": "markdown", "source": [ "You can plot 2D different functions in the same plot." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p1 = plot_parametric(x*sin(x),x*cos(x), show=False)", "", "p1.extend(p) # Plot objects are just like lists.", "", "p1.show()" ], "language": "python", "outputs": [], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "p1.legend = True", "", "p1.show()" ], "language": "python", "outputs": [], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "p1[0].line_color='r'", "", "p1[1].line_color='b' # a constant color", "", "p1.show()" ], "language": "python", "outputs": [], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "p1[0].line_color = lambda a : a # color dependent on the parameter", "", "p1.show()" ], "language": "python", "outputs": [], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": [ "p1.title = 'Big title'", "", "p1.xlabel = 'the x axis'", "", "p1[1].label = 'straight line'", "", "p1.show()" ], "language": "python", "outputs": [], "prompt_number": 19 }, { "cell_type": "code", "collapsed": false, "input": [ "p1.aspect_ratio" ], "language": "python", "outputs": [], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": [ "p1.aspect_ratio = (1,1)", "", "p1.xlim = (-15,20)", "", "p1.show()" ], "language": "python", "outputs": [], "prompt_number": 21 }, { "cell_type": "markdown", "source": [ "Hm, `xlim` does not work in the notebook. Hopefully it works in IPython." ] }, { "cell_type": "code", "collapsed": true, "input": [ "p1._backend.ax.get_xlim()" ], "language": "python", "outputs": [], "prompt_number": 17 }, { "cell_type": "markdown", "source": [ "Yeah, the backend got the command, but the `inline` backend does not honour it." ] }, { "cell_type": "markdown", "source": [ "## Adding expressions to a plot" ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot(x)", "", "p" ], "language": "python", "outputs": [], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "p.extend(plot(x+1, show=False))", "", "p.show()", "", "p" ], "language": "python", "outputs": [], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": [ "p.append(plot(x+3, x**2, show=False)[1])", "", "p.show()", "", "p" ], "language": "python", "outputs": [], "prompt_number": 25 }, { "cell_type": "markdown", "source": [ "## Different types of plots" ] }, { "cell_type": "markdown", "source": [ "###``plot``", "", "The ``plot`` by default uses an recursive adaptive algorithm to plot line plots. The default depth of recursion is 12, which means the function will be sampled at a maximum of $2^{12}$ points." ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(plot)" ], "language": "python", "outputs": [], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(sin(x**2)) # plots with adaptive sampling and default range of (-10, 10)" ], "language": "python", "outputs": [], "prompt_number": 28 }, { "cell_type": "markdown", "source": [ "You can also specify the depth of the recursion. It is also possible to disable adaptive sampling and use uniform sampling with ``nb_of_points``." ] }, { "cell_type": "code", "collapsed": false, "input": [ "plot(sin(x**2), depth=7) #specifying the depth of recursion." ], "language": "python", "outputs": [], "prompt_number": 30 }, { "cell_type": "code", "collapsed": false, "input": [ "plot(sin(x**2), adaptive=False, nb_of_points=500)" ], "language": "python", "outputs": [], "prompt_number": 31 }, { "cell_type": "markdown", "source": [ "###``plot_parametric``", "", "``plot_parametric`` uses an recursive adaptive sampling algorithm to plot." ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(plot_parametric)" ], "language": "python", "outputs": [], "prompt_number": 32 }, { "cell_type": "code", "collapsed": false, "input": [ "plot_parametric(cos(x), sin(x))" ], "language": "python", "outputs": [], "prompt_number": 33 }, { "cell_type": "markdown", "source": [ "Multiple plots." ] }, { "cell_type": "code", "collapsed": false, "input": [ "plot_parametric((cos(x), sin(x)), (x, cos(x)))" ], "language": "python", "outputs": [], "prompt_number": 34 }, { "cell_type": "markdown", "source": [ "We can combine parametric and line plots into a single plot." ] }, { "cell_type": "code", "collapsed": false, "input": [ "p = plot(sin(x), show=False)", "", "", "", "p.extend(plot_parametric(cos(x), sin(x), show=False))", "", "p.show()" ], "language": "python", "outputs": [], "prompt_number": 35 }, { "cell_type": "markdown", "source": [ "###``plot3d``" ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(plot3d)" ], "language": "python", "outputs": [], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": [ "plot3d(x*y)" ], "language": "python", "outputs": [], "prompt_number": 37 }, { "cell_type": "code", "collapsed": false, "input": [ "plot3d(x*y, nb_of_points_x=100, nb_of_points_y=50) " ], "language": "python", "outputs": [], "prompt_number": 38 }, { "cell_type": "markdown", "source": [ "###``plot3_parametric_line``" ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(plot3d_parametric_line)" ], "language": "python", "outputs": [], "prompt_number": 39 }, { "cell_type": "code", "collapsed": false, "input": [ "plot3d_parametric_line(cos(x), sin(x), x)" ], "language": "python", "outputs": [], "prompt_number": 40 }, { "cell_type": "markdown", "source": [ "###``plot3d_parametric_surface``" ] }, { "cell_type": "code", "collapsed": false, "input": [ "help(plot3d_parametric_surface)" ], "language": "python", "outputs": [], "prompt_number": 41 }, { "cell_type": "code", "collapsed": false, "input": [ "plot3d_parametric_surface(cos(x + y), sin(x - y), x - y)" ], "language": "python", "outputs": [], "prompt_number": 42 }, { "cell_type": "markdown", "source": [ "## Complex values", "", "If complex values are encountered, they are discarded while plotting." ] }, { "cell_type": "code", "collapsed": false, "input": [ "plot(sqrt(x), (x, -5, 5))" ], "language": "python", "outputs": [], "prompt_number": 43 }, { "cell_type": "markdown", "source": [ "", "", "## Textplot", "", "", "", "There is also the textplot backend that permits plotting in the terminal." ] }, { "cell_type": "code", "collapsed": true, "input": [ "pt = plot(sin(x),show=False)" ], "language": "python", "outputs": [], "prompt_number": 44 }, { "cell_type": "code", "collapsed": true, "input": [ "pt.backend = plot_backends['text']" ], "language": "python", "outputs": [], "prompt_number": 45 }, { "cell_type": "code", "collapsed": false, "input": [ "pt.show()" ], "language": "python", "outputs": [], "prompt_number": 46 } ] } ] }sympy-sympy-1.9/examples/beginner/plotting_nice_plot.py000077500000000000000000000006271412543434000236100ustar00rootroot00000000000000#!/usr/bin/env python """Plotting example Demonstrates simple plotting. """ from sympy import Symbol, cos, sin, log, tan from sympy.plotting import PygletPlot from sympy.abc import x, y def main(): fun1 = cos(x)*sin(y) fun2 = sin(x)*sin(y) fun3 = cos(y) + log(tan(y/2)) + 0.2*x PygletPlot(fun1, fun2, fun3, [x, -0.00, 12.4, 40], [y, 0.1, 2, 40]) if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/precision.py000077500000000000000000000006731412543434000217100ustar00rootroot00000000000000#!/usr/bin/env python """Precision Example Demonstrates SymPy's arbitrary integer precision abilities """ import sympy from sympy import Mul, Pow, S def main(): x = Pow(2, 50, evaluate=False) y = Pow(10, -50, evaluate=False) # A large, unevaluated expression m = Mul(x, y, evaluate=False) # Evaluating the expression e = S(2)**50/S(10)**50 print("{} == {}".format(m, e)) if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/print_pretty.py000077500000000000000000000015571412543434000224620ustar00rootroot00000000000000#!/usr/bin/env python """Pretty print example Demonstrates pretty printing. """ from sympy import Symbol, pprint, sin, cos, exp, sqrt, MatrixSymbol, KroneckerProduct def main(): x = Symbol("x") y = Symbol("y") a = MatrixSymbol("a", 1, 1) b = MatrixSymbol("b", 1, 1) c = MatrixSymbol("c", 1, 1) pprint( x**x ) print('\n') # separate with two blank lines pprint(x**2 + y + x) print('\n') pprint(sin(x)**x) print('\n') pprint( sin(x)**cos(x) ) print('\n') pprint( sin(x)/(cos(x)**2 * x**x + (2*y)) ) print('\n') pprint( sin(x**2 + exp(x)) ) print('\n') pprint( sqrt(exp(x)) ) print('\n') pprint( sqrt(sqrt(exp(x))) ) print('\n') pprint( (1/cos(x)).series(x, 0, 10) ) print('\n') pprint(a*(KroneckerProduct(b, c))) print('\n') if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/series.py000077500000000000000000000006411412543434000212020ustar00rootroot00000000000000#!/usr/bin/env python """Series example Demonstrates series. """ from sympy import Symbol, cos, sin, pprint def main(): x = Symbol('x') e = 1/cos(x) print('') print("Series for sec(x):") print('') pprint(e.series(x, 0, 10)) print("\n") e = 1/sin(x) print("Series for csc(x):") print('') pprint(e.series(x, 0, 4)) print('') if __name__ == "__main__": main() sympy-sympy-1.9/examples/beginner/substitution.py000077500000000000000000000013001412543434000224550ustar00rootroot00000000000000#!/usr/bin/env python """Substitution example Demonstrates substitution. """ import sympy from sympy import pprint def main(): x = sympy.Symbol('x') y = sympy.Symbol('y') e = 1/sympy.cos(x) print() pprint(e) print('\n') pprint(e.subs(sympy.cos(x), y)) print('\n') pprint(e.subs(sympy.cos(x), y).subs(y, x**2)) e = 1/sympy.log(x) e = e.subs(x, sympy.Float("2.71828")) print('\n') pprint(e) print('\n') pprint(e.evalf()) print() a = sympy.Symbol('a') b = sympy.Symbol('b') e = a*2 + a**b/a print('\n') pprint(e) a = 2 print('\n') pprint(e.subs(a,8)) print() if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/000077500000000000000000000000001412543434000202135ustar00rootroot00000000000000sympy-sympy-1.9/examples/intermediate/coupled_cluster.py000077500000000000000000000071511412543434000237700ustar00rootroot00000000000000#!/usr/bin/env python """ Calculates the Coupled-Cluster energy- and amplitude equations See 'An Introduction to Coupled Cluster Theory' by T. Daniel Crawford and Henry F. Schaefer III. Other Resource : http://vergil.chemistry.gatech.edu/notes/sahan-cc-2010.pdf """ from sympy.physics.secondquant import (AntiSymmetricTensor, wicks, F, Fd, NO, evaluate_deltas, substitute_dummies, Commutator, simplify_index_permutations, PermutationOperator) from sympy import ( symbols, Rational, latex, Dummy ) pretty_dummies_dict = { 'above': 'cdefgh', 'below': 'klmno', 'general': 'pqrstu' } def get_CC_operators(): """ Returns a tuple (T1,T2) of unique operators. """ i = symbols('i', below_fermi=True, cls=Dummy) a = symbols('a', above_fermi=True, cls=Dummy) t_ai = AntiSymmetricTensor('t', (a,), (i,)) ai = NO(Fd(a)*F(i)) i, j = symbols('i,j', below_fermi=True, cls=Dummy) a, b = symbols('a,b', above_fermi=True, cls=Dummy) t_abij = AntiSymmetricTensor('t', (a, b), (i, j)) abji = NO(Fd(a)*Fd(b)*F(j)*F(i)) T1 = t_ai*ai T2 = Rational(1, 4)*t_abij*abji return (T1, T2) def main(): print() print("Calculates the Coupled-Cluster energy- and amplitude equations") print("See 'An Introduction to Coupled Cluster Theory' by") print("T. Daniel Crawford and Henry F. Schaefer III") print("Reference to a Lecture Series: http://vergil.chemistry.gatech.edu/notes/sahan-cc-2010.pdf") print() # setup hamiltonian p, q, r, s = symbols('p,q,r,s', cls=Dummy) f = AntiSymmetricTensor('f', (p,), (q,)) pr = NO(Fd(p)*F(q)) v = AntiSymmetricTensor('v', (p, q), (r, s)) pqsr = NO(Fd(p)*Fd(q)*F(s)*F(r)) H = f*pr + Rational(1, 4)*v*pqsr print("Using the hamiltonian:", latex(H)) print("Calculating 4 nested commutators") C = Commutator T1, T2 = get_CC_operators() T = T1 + T2 print("commutator 1...") comm1 = wicks(C(H, T)) comm1 = evaluate_deltas(comm1) comm1 = substitute_dummies(comm1) T1, T2 = get_CC_operators() T = T1 + T2 print("commutator 2...") comm2 = wicks(C(comm1, T)) comm2 = evaluate_deltas(comm2) comm2 = substitute_dummies(comm2) T1, T2 = get_CC_operators() T = T1 + T2 print("commutator 3...") comm3 = wicks(C(comm2, T)) comm3 = evaluate_deltas(comm3) comm3 = substitute_dummies(comm3) T1, T2 = get_CC_operators() T = T1 + T2 print("commutator 4...") comm4 = wicks(C(comm3, T)) comm4 = evaluate_deltas(comm4) comm4 = substitute_dummies(comm4) print("construct Hausdorff expansion...") eq = H + comm1 + comm2/2 + comm3/6 + comm4/24 eq = eq.expand() eq = evaluate_deltas(eq) eq = substitute_dummies(eq, new_indices=True, pretty_indices=pretty_dummies_dict) print("*********************") print() print("extracting CC equations from full Hbar") i, j, k, l = symbols('i,j,k,l', below_fermi=True) a, b, c, d = symbols('a,b,c,d', above_fermi=True) print() print("CC Energy:") print(latex(wicks(eq, simplify_dummies=True, keep_only_fully_contracted=True))) print() print("CC T1:") eqT1 = wicks(NO(Fd(i)*F(a))*eq, simplify_kronecker_deltas=True, keep_only_fully_contracted=True) eqT1 = substitute_dummies(eqT1) print(latex(eqT1)) print() print("CC T2:") eqT2 = wicks(NO(Fd(i)*Fd(j)*F(b)*F(a))*eq, simplify_dummies=True, keep_only_fully_contracted=True, simplify_kronecker_deltas=True) P = PermutationOperator eqT2 = simplify_index_permutations(eqT2, [P(a, b), P(i, j)]) print(latex(eqT2)) if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/differential_equations.py000077500000000000000000000011071412543434000253130ustar00rootroot00000000000000#!/usr/bin/env python """Differential equations example Demonstrates solving 1st and 2nd degree linear ordinary differential equations. """ from sympy import dsolve, Eq, Function, sin, Symbol def main(): x = Symbol("x") f = Function("f") eq = Eq(f(x).diff(x), f(x)) print("Solution for ", eq, " : ", dsolve(eq, f(x))) eq = Eq(f(x).diff(x, 2), -f(x)) print("Solution for ", eq, " : ", dsolve(eq, f(x))) eq = Eq(x**2*f(x).diff(x), -3*x*f(x) + sin(x)/x) print("Solution for ", eq, " : ", dsolve(eq, f(x))) if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/infinite_1d_box.py000077500000000000000000000055421412543434000236370ustar00rootroot00000000000000#!/usr/bin/env python """ Applying perturbation theory to calculate the ground state energy of the infinite 1D box of width ``a`` with a perturbation which is linear in ``x``, up to second order in perturbation """ from sympy.core import pi from sympy import Integral, var, S from sympy.functions import sin, sqrt def X_n(n, a, x): """ Returns the wavefunction X_{n} for an infinite 1D box ``n`` the "principal" quantum number. Corresponds to the number of nodes in the wavefunction. n >= 0 ``a`` width of the well. a > 0 ``x`` x coordinate. """ n, a, x = map(S, [n, a, x]) C = sqrt(2 / a) return C * sin(pi * n * x / a) def E_n(n, a, mass): """ Returns the Energy psi_{n} for a 1d potential hole with infinity borders ``n`` the "principal" quantum number. Corresponds to the number of nodes in the wavefunction. n >= 0 ``a`` width of the well. a > 0 ``mass`` mass. """ return ((n * pi / a)**2) / mass def energy_corrections(perturbation, n, *, a=10, mass=0.5): """ Calculating first two order corrections due to perturbation theory and returns tuple where zero element is unperturbated energy, and two second is corrections ``n`` the "nodal" quantum number. Corresponds to the number of nodes in the wavefunction. n >= 0 ``a`` width of the well. a > 0 ``mass`` mass. """ x, _a = var("x _a") Vnm = lambda n, m, a: Integral(X_n(n, a, x) * X_n(m, a, x) * perturbation.subs({_a: a}), (x, 0, a)).n() # As we know from theory for V0*r/a we will just V(n, n-1) and V(n, n+1) # wouldn't equals zero return (E_n(n, a, mass).evalf(), Vnm(n, n, a).evalf(), (Vnm(n, n - 1, a)**2/(E_n(n, a, mass) - E_n(n - 1, a, mass)) + Vnm(n, n + 1, a)**2/(E_n(n, a, mass) - E_n(n + 1, a, mass))).evalf()) def main(): print() print("Applying perturbation theory to calculate the ground state energy") print("of the infinite 1D box of width ``a`` with a perturbation") print("which is linear in ``x``, up to second order in perturbation.") print() x, _a = var("x _a") perturbation = .1 * x / _a E1 = energy_corrections(perturbation, 1) print("Energy for first term (n=1):") print("E_1^{(0)} = ", E1[0]) print("E_1^{(1)} = ", E1[1]) print("E_1^{(2)} = ", E1[2]) print() E2 = energy_corrections(perturbation, 2) print("Energy for second term (n=2):") print("E_2^{(0)} = ", E2[0]) print("E_2^{(1)} = ", E2[1]) print("E_2^{(2)} = ", E2[2]) print() E3 = energy_corrections(perturbation, 3) print("Energy for third term (n=3):") print("E_3^{(0)} = ", E3[0]) print("E_3^{(1)} = ", E3[1]) print("E_3^{(2)} = ", E3[2]) print() if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/limit_examples_advanced.ipynb000066400000000000000000000667241412543434000261360ustar00rootroot00000000000000{ "metadata": { "name": "limit_examples_advanced" }, "name": "limit_examples_advanced", "nbformat": 2, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": true, "input": "from sympy import *", "language": "python", "outputs": [], "prompt_number": 1 }, { "cell_type": "code", "collapsed": true, "input": "x = Symbol(\"x\")", "language": "python", "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": "limit(exp(x)*exp(x**2)*(erf(x+1/exp(x))-erf(x)), x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 3, "text": "2/sqrt(pi)" } ], "prompt_number": 3 }, { "cell_type": "markdown", "source": "The examples here show the limit computation on exp-log expressions (from Gruntz' thesis pp. 122 to 123)" }, { "cell_type": "markdown", "source": "Eqn 8.1" }, { "cell_type": "code", "collapsed": false, "input": "exp(x)*(exp(1/x-exp(-x))-exp(1/x))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 4, "text": "(-exp(1/x) + exp(-exp(-x) + 1/x))*exp(x)" } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 5, "text": "-1" } ], "prompt_number": 5 }, { "cell_type": "markdown", "source": "Eqn 8.2" }, { "cell_type": "code", "collapsed": false, "input": "exp(x)*(exp(1/x+exp(-x)+exp(-x**2)) - exp(1/x-exp(-exp(x))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 6, "text": "(-exp(-exp(-exp(x)) + 1/x) + exp(exp(-x**2) + exp(-x) + 1/x))*exp(x)" } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 7, "text": "1" } ], "prompt_number": 7 }, { "cell_type": "markdown", "source": "Eqn 8.3" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(x-exp(-x))/(1-1/x)) - exp(exp(x))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 8, "text": "exp(exp(x - exp(-x))/(1 - 1/x)) - exp(exp(x))" } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 9, "text": "oo" } ], "prompt_number": 9 }, { "cell_type": "markdown", "source": "Eqn 8.4" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(exp(x)/(1-1/x))) - exp(exp(exp(x)/(1-1/x-log(x)**(-log(x)))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 10, "text": "exp(exp(exp(x)/(1 - 1/x))) - exp(exp(exp(x)/(1 - log(x)**(-log(x)) - 1/x)))" } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 11, "text": "-oo" } ], "prompt_number": 11 }, { "cell_type": "markdown", "source": "Eqn 8.5" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(exp(x+exp(-x)))) / exp(exp(exp(x)))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 12, "text": "exp(-exp(exp(x)))*exp(exp(exp(x + exp(-x))))" } ], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 13, "text": "oo" } ], "prompt_number": 13 }, { "cell_type": "markdown", "source": "Eqn 8.6" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(exp(x))) / exp(exp(exp(x-exp(-exp(x)))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 14, "text": "exp(exp(exp(x)))*exp(-exp(exp(x - exp(-exp(x)))))" } ], "prompt_number": 14 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 15, "text": "oo" } ], "prompt_number": 15 }, { "cell_type": "markdown", "source": "Eqn 8.7" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(exp(x))) / exp(exp(exp(x-exp(-exp(exp(x))))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 16, "text": "exp(exp(exp(x)))*exp(-exp(exp(x - exp(-exp(exp(x))))))" } ], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 17, "text": "1" } ], "prompt_number": 17 }, { "cell_type": "markdown", "source": "Eqn 8.8" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(x)) / exp(exp(x-exp(-exp(exp(x)))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 18, "text": "exp(exp(x))*exp(-exp(x - exp(-exp(exp(x)))))" } ], "prompt_number": 18 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 19, "text": "1" } ], "prompt_number": 19 }, { "cell_type": "markdown", "source": "Eqn 8.9" }, { "cell_type": "code", "collapsed": false, "input": "log(x)**2 * exp(sqrt(log(x))*(log(log(x)))**2 * exp(sqrt(log(log(x))) * (log(log(log(x))))**3)) / sqrt(x)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 20, "text": "exp(exp(sqrt(log(log(x)))*log(log(log(x)))**3)*sqrt(log(x))*log(log(x))**2)*log(x)**2/sqrt(x)" } ], "prompt_number": 20 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 21, "text": "0" } ], "prompt_number": 21 }, { "cell_type": "markdown", "source": "Eqn 8.10" }, { "cell_type": "code", "collapsed": false, "input": "(x*log(x)*(log(x*exp(x)-x**2))**2) / (log(log(x**2+2*exp(exp(3*x**3*log(x))))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 22, "text": "x*log(x)*log(-x**2 + x*exp(x))**2/log(log(x**2 + 2*exp(exp(3*x**3*log(x)))))" } ], "prompt_number": 22 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 23, "text": "1/3" } ], "prompt_number": 23 }, { "cell_type": "markdown", "source": "Eqn 8.11" }, { "cell_type": "code", "collapsed": false, "input": "(exp(x*exp(-x)/(exp(-x)+exp(-2*x**2/(x+1)))) - exp(x))/x", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 24, "text": "(-exp(x) + exp(x*exp(-x)/(exp(-2*x**2/(x + 1)) + exp(-x))))/x" } ], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 25, "text": "-exp(2)" } ], "prompt_number": 25 }, { "cell_type": "markdown", "source": "Eqn 8.12" }, { "cell_type": "code", "collapsed": false, "input": "(3**x + 5**x)**(1/x)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 26, "text": "(3**x + 5**x)**(1/x)" } ], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 27, "text": "5" } ], "prompt_number": 27 }, { "cell_type": "markdown", "source": "Eqn 8.13" }, { "cell_type": "code", "collapsed": false, "input": "x/log(x**(log(x**(log(2)/log(x)))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 28, "text": "x/log(x**log(x**(log(2)/log(x))))" } ], "prompt_number": 28 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 29, "text": "oo" } ], "prompt_number": 29 }, { "cell_type": "markdown", "source": "Eqn 8.14" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(2*log(x**5+x)*log(log(x)))) / exp(exp(10*log(x)*log(log(x))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 30, "text": "exp(-exp(10*log(x)*log(log(x))))*exp(exp(2*log(x**5 + x)*log(log(x))))" } ], "prompt_number": 30 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 31, "text": "oo" } ], "prompt_number": 31 }, { "cell_type": "markdown", "source": "Eqn 8.15" }, { "cell_type": "code", "collapsed": false, "input": "4*exp(exp(S(5)/2*x**(-S(5)/7)+ S(21)/8*x**(S(6)/11)+2*x**(-8)+S(54)/17*x**(S(49)/45) ))**8 / (9*log(log(-log(S(4)/3*x**(-S(5)/14))))**(S(7)/6))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 32, "text": "4*exp(8*exp(54*x**(49/45)/17 + 21*x**(6/11)/8 + 2/x**8 + 5/(2*x**(5/7))))/(9*log(log(-log(4/(3*x**(5/14)))))**(7/6))" } ], "prompt_number": 32 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 33, "text": "oo" } ], "prompt_number": 33 }, { "cell_type": "markdown", "source": "Eqn 8.16" }, { "cell_type": "code", "collapsed": false, "input": "(exp(4*x*exp(-x)/(1/exp(x)+1/exp(2*x**2/(x+1)))) - exp(x)) / exp(x)**4", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 34, "text": "(-exp(x) + exp(4*x*exp(-x)/(exp(-2*x**2/(x + 1)) + exp(-x))))*exp(-4*x)" } ], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 35, "text": "1" } ], "prompt_number": 35 }, { "cell_type": "markdown", "source": "Eqn 8.17" }, { "cell_type": "code", "collapsed": false, "input": "exp(x*exp(-x)/(exp(-x)+exp(-2*x**2/(x+1))))/exp(x)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 36, "text": "exp(-x)*exp(x*exp(-x)/(exp(-2*x**2/(x + 1)) + exp(-x)))" } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 37, "text": "1" } ], "prompt_number": 37 }, { "cell_type": "markdown", "source": "Eqn 8.18" }, { "cell_type": "code", "collapsed": false, "input": "(exp(exp(-x/(1+exp(-x))))*exp(-x/(1+exp(-x/(1+exp(-x)))))*exp(exp(-x+exp(-x/(1+exp(-x)))))) / (exp(-x/(1+exp(-x))))**2 - exp(x) + x", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 38, "text": "x - exp(x) + exp(2*x/(1 + exp(-x)))*exp(-x/(1 + exp(-x/(1 + exp(-x)))))*exp(exp(-x/(1 + exp(-x))))*exp(exp(-x + exp(-x/(1 + exp(-x)))))" } ], "prompt_number": 38 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 39, "text": "2" } ], "prompt_number": 39 }, { "cell_type": "markdown", "source": "Eqn 8.19" }, { "cell_type": "code", "collapsed": false, "input": "log(x)*(log(log(x)+log(log(x))) - log(log(x))) / (log(log(x)+log(log(log(x)))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 40, "text": "(log(log(x) + log(log(x))) - log(log(x)))*log(x)/log(log(x) + log(log(log(x))))" } ], "prompt_number": 40 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 41, "text": "1" } ], "prompt_number": 41 }, { "cell_type": "markdown", "source": "Eqn 8.20" }, { "cell_type": "code", "collapsed": false, "input": "exp((log(log(x+exp(log(x)*log(log(x)))))) / (log(log(log(exp(x)+x+log(x))))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 42, "text": "exp(log(log(x + exp(log(x)*log(log(x)))))/log(log(log(x + exp(x) + log(x)))))" } ], "prompt_number": 42 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 43, "text": "E" } ], "prompt_number": 43 }, { "cell_type": "markdown", "source": "The following examples show limit computation on special functions (from Gruntz' thesis p. 126)" }, { "cell_type": "markdown", "source": "Eqn 8.21" }, { "cell_type": "code", "collapsed": false, "input": "exp(x)*(sin(1/x+exp(-x))-sin(1/x+exp(-x**2)))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 44, "text": "(sin(exp(-x) + 1/x) - sin(exp(-x**2) + 1/x))*exp(x)" } ], "prompt_number": 44 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 45, "text": "1" } ], "prompt_number": 45 }, { "cell_type": "markdown", "source": "Eqn 8.22" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(x)) * (exp(sin(1/x+exp(-exp(x)))) - exp(sin(1/x)))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 46, "text": "(-exp(sin(1/x)) + exp(sin(exp(-exp(x)) + 1/x)))*exp(exp(x))" } ], "prompt_number": 46 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 47, "text": "1" } ], "prompt_number": 47 }, { "cell_type": "markdown", "source": "Eqn 8.23" }, { "cell_type": "code", "collapsed": false, "input": "(erf(x-exp(-exp(x))) - erf(x)) * exp(exp(x)) * exp(x**2)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 48, "text": "(-erf(x) + erf(x - exp(-exp(x))))*exp(x**2)*exp(exp(x))" } ], "prompt_number": 48 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 49, "text": "-2/sqrt(pi)" } ], "prompt_number": 49 }, { "cell_type": "markdown", "source": "Eqn 8.24" }, { "cell_type": "code", "collapsed": false, "input": "(Ei(x-exp(-exp(x))) - Ei(x)) *exp(-x)*exp(exp(x))*x", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 50, "text": "x*(-Ei(x) + Ei(x - exp(-exp(x))))*exp(-x)*exp(exp(x))" } ], "prompt_number": 50 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 51, "text": "-1" } ], "prompt_number": 51 }, { "cell_type": "markdown", "source": "Eqn 8.25" }, { "cell_type": "code", "collapsed": false, "input": "exp((log(2)+1)*x) * (zeta(x+exp(-x)) - zeta(x))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 52, "text": "(-zeta(x) + zeta(x + exp(-x)))*exp(x*(log(2) + 1))" } ], "prompt_number": 52 }, { "cell_type": "code", "collapsed": false, "input": "#limit(_, x, oo)", "language": "python", "outputs": [], "prompt_number": 53 }, { "cell_type": "markdown", "source": "Eqn 8.26" }, { "cell_type": "code", "collapsed": false, "input": "exp(x)*(gamma(x+exp(-x)) - gamma(x))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 54, "text": "(-gamma(x) + gamma(x + exp(-x)))*exp(x)" } ], "prompt_number": 54 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 55, "text": "oo" } ], "prompt_number": 55 }, { "cell_type": "markdown", "source": "Eqn 8.27" }, { "cell_type": "code", "collapsed": false, "input": "exp(gamma(x-exp(-x))*exp(1/x)) - exp(gamma(x))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 56, "text": "exp(exp(1/x)*gamma(x - exp(-x))) - exp(gamma(x))" } ], "prompt_number": 56 }, { "cell_type": "code", "collapsed": false, "input": "#limit(_, x, oo)", "language": "python", "outputs": [], "prompt_number": 57 }, { "cell_type": "markdown", "source": "Eqn 8.28" }, { "cell_type": "code", "collapsed": false, "input": "(gamma(x+1/gamma(x)) - gamma(x)) / log(x)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 58, "text": "(-gamma(x) + gamma(x + 1/gamma(x)))/log(x)" } ], "prompt_number": 58 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 59, "text": "1" } ], "prompt_number": 59 }, { "cell_type": "markdown", "source": "Eqn 8.29" }, { "cell_type": "code", "collapsed": false, "input": "x * (gamma(x-1/gamma(x)) - gamma(x) + log(x))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 60, "text": "x*(log(x) - gamma(x) + gamma(x - 1/gamma(x)))" } ], "prompt_number": 60 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 61, "text": "1/2" } ], "prompt_number": 61 }, { "cell_type": "markdown", "source": "Eqn 8.30" }, { "cell_type": "code", "collapsed": false, "input": "((gamma(x+1/gamma(x)) - gamma(x))/log(x) - cos(1/x))*x*log(x)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 62, "text": "x*((-gamma(x) + gamma(x + 1/gamma(x)))/log(x) - cos(1/x))*log(x)" } ], "prompt_number": 62 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 63, "text": "-1/2" } ], "prompt_number": 63 }, { "cell_type": "markdown", "source": "Eqn 8.31" }, { "cell_type": "code", "collapsed": false, "input": "gamma(x+1)/sqrt(2*pi) - exp(-x)*(x**(x+S(1)/2) + x**(x-S(1)/2)/12)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 64, "text": "-(x**(x - 1/2)/12 + x**(x + 1/2))*exp(-x) + sqrt(2)*gamma(x + 1)/(2*sqrt(pi))" } ], "prompt_number": 64 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 65, "text": "oo" } ], "prompt_number": 65 }, { "cell_type": "markdown", "source": "Eqn 8.32" }, { "cell_type": "code", "collapsed": false, "input": "log(gamma(gamma(x)))/exp(x)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 66, "text": "exp(-x)*log(gamma(gamma(x)))" } ], "prompt_number": 66 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 67, "text": "oo" } ], "prompt_number": 67 }, { "cell_type": "markdown", "source": "Eqn 8.33" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(digamma(digamma(x))))/x", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 68, "text": "exp(exp(polygamma(0, polygamma(0, x))))/x" } ], "prompt_number": 68 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 69, "text": "exp(-1/2)" } ], "prompt_number": 69 }, { "cell_type": "markdown", "source": "Eqn 8.34" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(digamma(log(x))))/x", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 70, "text": "exp(exp(polygamma(0, log(x))))/x" } ], "prompt_number": 70 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 71, "text": "exp(-1/2)" } ], "prompt_number": 71 }, { "cell_type": "markdown", "source": "Eqn 8.35" }, { "cell_type": "code", "collapsed": false, "input": "exp(exp(exp(digamma(digamma(digamma(x))))))/x", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 72, "text": "exp(exp(exp(polygamma(0, polygamma(0, polygamma(0, x))))))/x" } ], "prompt_number": 72 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 73, "text": "0" } ], "prompt_number": 73 }, { "cell_type": "markdown", "source": "Eqn 8.36" }, { "cell_type": "code", "collapsed": false, "input": "besselj(2,x)*exp(x*(2*log(2+sqrt(3))-sqrt(3)))*sqrt(x)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 74, "text": "sqrt(x)*exp(x*(-sqrt(3) + 2*log(sqrt(3) + 2)))*besselj(2, x)" } ], "prompt_number": 74 }, { "cell_type": "code", "collapsed": false, "input": "#limit(_, x, oo)", "language": "python", "outputs": [], "prompt_number": 75 }, { "cell_type": "markdown", "source": "Eqn 8.37" }, { "cell_type": "code", "collapsed": false, "input": "Max(x, exp(x))/log(Min(exp(-x), exp(-exp(x))))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 76, "text": "Max(x, exp(x))/log(Min(exp(-x), exp(-exp(x))))" } ], "prompt_number": 76 }, { "cell_type": "code", "collapsed": false, "input": "#limit(_, x, oo)", "language": "python", "outputs": [], "prompt_number": 77 }, { "cell_type": "markdown", "source": "Some other examples" }, { "cell_type": "code", "collapsed": false, "input": "digamma(digamma(digamma(x)))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 78, "text": "polygamma(0, polygamma(0, polygamma(0, x)))" } ], "prompt_number": 78 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 79, "text": "oo" } ], "prompt_number": 79 }, { "cell_type": "code", "collapsed": false, "input": "loggamma(loggamma(x))", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 80, "text": "loggamma(loggamma(x))" } ], "prompt_number": 80 }, { "cell_type": "code", "collapsed": false, "input": "limit(_, x, oo)", "language": "python", "outputs": [ { "output_type": "pyout", "prompt_number": 81, "text": "oo" } ], "prompt_number": 81 } ] } ] }sympy-sympy-1.9/examples/intermediate/mplot2d.py000077500000000000000000000017051412543434000221540ustar00rootroot00000000000000#!/usr/bin/env python """Matplotlib 2D plotting example Demonstrates plotting with matplotlib. """ import sys from sample import sample from sympy import sqrt, Symbol from sympy.core.compatibility import is_sequence from sympy.external import import_module def mplot2d(f, var, *, show=True): """ Plot a 2d function using matplotlib/Tk. """ import warnings warnings.filterwarnings("ignore", r"Could not match \S") p = import_module('pylab') if not p: sys.exit("Matplotlib is required to use mplot2d.") if not is_sequence(f): f = [f, ] for f_i in f: x, y = sample(f_i, var) p.plot(x, y) p.draw() if show: p.show() def main(): x = Symbol('x') # mplot2d(log(x), (x, 0, 2, 100)) # mplot2d([sin(x), -sin(x)], (x, float(-2*pi), float(2*pi), 50)) mplot2d([sqrt(x), -sqrt(x), sqrt(-x), -sqrt(-x)], (x, -40.0, 40.0, 80)) if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/mplot3d.py000077500000000000000000000023401412543434000221510ustar00rootroot00000000000000#!/usr/bin/env python """Matplotlib 3D plotting example Demonstrates plotting with matplotlib. """ import sys from sample import sample from sympy import Symbol from sympy.external import import_module def mplot3d(f, var1, var2, *, show=True): """ Plot a 3d function using matplotlib/Tk. """ import warnings warnings.filterwarnings("ignore", r"Could not match \S") p = import_module('pylab') # Try newer version first p3 = import_module('mpl_toolkits.mplot3d', import_kwargs={'fromlist': ['something']}) or import_module('matplotlib.axes3d') if not p or not p3: sys.exit("Matplotlib is required to use mplot3d.") x, y, z = sample(f, var1, var2) fig = p.figure() ax = p3.Axes3D(fig) # ax.plot_surface(x, y, z, rstride=2, cstride=2) ax.plot_wireframe(x, y, z) ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') if show: p.show() def main(): x = Symbol('x') y = Symbol('y') mplot3d(x**2 - y**2, (x, -10.0, 10.0, 20), (y, -10.0, 10.0, 20)) # mplot3d(x**2+y**2, (x, -10.0, 10.0, 20), (y, -10.0, 10.0, 20)) # mplot3d(sin(x)+sin(y), (x, -3.14, 3.14, 10), (y, -3.14, 3.14, 10)) if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/partial_differential_eqs.py000077500000000000000000000036751412543434000256230ustar00rootroot00000000000000#!/usr/bin/env python """Partial Differential Equations example Demonstrates various ways to solve partial differential equations """ from sympy import symbols, Eq, Function, pde_separate, pprint, sin, cos from sympy import Derivative as D def main(): r, phi, theta = symbols("r,phi,theta") Xi = Function('Xi') R, Phi, Theta, u = map(Function, ['R', 'Phi', 'Theta', 'u']) C1, C2 = symbols('C1,C2') pprint("Separation of variables in Laplace equation in spherical coordinates") pprint("Laplace equation in spherical coordinates:") eq = Eq(D(Xi(r, phi, theta), r, 2) + 2/r * D(Xi(r, phi, theta), r) + 1/(r**2 * sin(phi)**2) * D(Xi(r, phi, theta), theta, 2) + cos(phi)/(r**2 * sin(phi)) * D(Xi(r, phi, theta), phi) + 1/r**2 * D(Xi(r, phi, theta), phi, 2), 0) pprint(eq) pprint("We can either separate this equation in regards with variable r:") res_r = pde_separate(eq, Xi(r, phi, theta), [R(r), u(phi, theta)]) pprint(res_r) pprint("Or separate it in regards of theta:") res_theta = pde_separate(eq, Xi(r, phi, theta), [Theta(theta), u(r, phi)]) pprint(res_theta) res_phi = pde_separate(eq, Xi(r, phi, theta), [Phi(phi), u(r, theta)]) pprint("But we cannot separate it in regards of variable phi: ") pprint("Result: %s" % res_phi) pprint("\n\nSo let's make theta dependent part equal with -C1:") eq_theta = Eq(res_theta[0], -C1) pprint(eq_theta) pprint("\nThis also means that second part is also equal to -C1:") eq_left = Eq(res_theta[1], -C1) pprint(eq_left) pprint("\nLets try to separate phi again :)") res_theta = pde_separate(eq_left, u(r, phi), [Phi(phi), R(r)]) pprint("\nThis time it is successful:") pprint(res_theta) pprint("\n\nSo our final equations with separated variables are:") pprint(eq_theta) pprint(Eq(res_theta[0], C2)) pprint(Eq(res_theta[1], C2)) if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/print_gtk.py000077500000000000000000000006001412543434000225650ustar00rootroot00000000000000#!/usr/bin/env python """print_gtk example Demonstrates printing with gtkmathview using mathml """ from sympy import Integral, Limit, print_gtk, sin, Symbol def main(): x = Symbol('x') example_limit = Limit(sin(x)/x, x, 0) print_gtk(example_limit) example_integral = Integral(x, (x, 0, 1)) print_gtk(example_integral) if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/sample.py000066400000000000000000000066721412543434000220610ustar00rootroot00000000000000r""" Utility functions for plotting sympy functions. See examples\mplot2d.py and examples\mplot3d.py for usable 2d and 3d graphing functions using matplotlib. """ from sympy.core.sympify import sympify, SympifyError from sympy.external import import_module np = import_module('numpy') def sample2d(f, x_args): r""" Samples a 2d function f over specified intervals and returns two arrays (X, Y) suitable for plotting with matlab (matplotlib) syntax. See examples\mplot2d.py. f is a function of one variable, such as x**2. x_args is an interval given in the form (var, min, max, n) """ try: f = sympify(f) except SympifyError: raise ValueError("f could not be interpreted as a SymPy function") try: x, x_min, x_max, x_n = x_args except (TypeError, IndexError): raise ValueError("x_args must be a tuple of the form (var, min, max, n)") x_l = float(x_max - x_min) x_d = x_l/float(x_n) X = np.arange(float(x_min), float(x_max) + x_d, x_d) Y = np.empty(len(X)) for i in range(len(X)): try: Y[i] = float(f.subs(x, X[i])) except TypeError: Y[i] = None return X, Y def sample3d(f, x_args, y_args): r""" Samples a 3d function f over specified intervals and returns three 2d arrays (X, Y, Z) suitable for plotting with matlab (matplotlib) syntax. See examples\mplot3d.py. f is a function of two variables, such as x**2 + y**2. x_args and y_args are intervals given in the form (var, min, max, n) """ x, x_min, x_max, x_n = None, None, None, None y, y_min, y_max, y_n = None, None, None, None try: f = sympify(f) except SympifyError: raise ValueError("f could not be interpreted as a SymPy function") try: x, x_min, x_max, x_n = x_args y, y_min, y_max, y_n = y_args except (TypeError, IndexError): raise ValueError("x_args and y_args must be tuples of the form (var, min, max, intervals)") x_l = float(x_max - x_min) x_d = x_l/float(x_n) x_a = np.arange(float(x_min), float(x_max) + x_d, x_d) y_l = float(y_max - y_min) y_d = y_l/float(y_n) y_a = np.arange(float(y_min), float(y_max) + y_d, y_d) def meshgrid(x, y): """ Taken from matplotlib.mlab.meshgrid. """ x = np.array(x) y = np.array(y) numRows, numCols = len(y), len(x) x.shape = 1, numCols X = np.repeat(x, numRows, 0) y.shape = numRows, 1 Y = np.repeat(y, numCols, 1) return X, Y X, Y = np.meshgrid(x_a, y_a) Z = np.ndarray((len(X), len(X[0]))) for j in range(len(X)): for k in range(len(X[0])): try: Z[j][k] = float(f.subs(x, X[j][k]).subs(y, Y[j][k])) except (TypeError, NotImplementedError): Z[j][k] = 0 return X, Y, Z def sample(f, *var_args): """ Samples a 2d or 3d function over specified intervals and returns a dataset suitable for plotting with matlab (matplotlib) syntax. Wrapper for sample2d and sample3d. f is a function of one or two variables, such as x**2. var_args are intervals for each variable given in the form (var, min, max, n) """ if len(var_args) == 1: return sample2d(f, var_args[0]) elif len(var_args) == 2: return sample3d(f, var_args[0], var_args[1]) else: raise ValueError("Only 2d and 3d sampling are supported at this time.") sympy-sympy-1.9/examples/intermediate/schwarzschild.ipynb000066400000000000000000002102611412543434000241300ustar00rootroot00000000000000{ "metadata": { "name": "schwarzschild" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Schwarzschild Solution to the Einstein's equation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We will rederive the equations from *General Theory of Relativity*, chapter 18, by Dirac. They describe a spherically symmetric solution to the Einstein's equation in vacuum.\n", "\n", "We will not try to solve the resulting equations.\n", "\n", "This version of the notebook uses functions that explicitly calculate the Christoffel symbols, hence the work is coordinate-system-dependent." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Import the necessary modules." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sympy.diffgeom import *\n", "TP = TensorProduct" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a 4D manifold with a patch and a coordinate chart on which we will work." ] }, { "cell_type": "code", "collapsed": false, "input": [ "m = Manifold('Schwarzschild', 4)\n", "p = Patch('origin', m)\n", "cs = CoordSystem('spherical', p, ['t', 'r', 'theta', 'phi'])" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "m, p, cs" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left ( \\mathrm{Schwarzschild}, \\quad \\mathrm{origin}_{\\mathrm{Schwarzschild}}, \\quad \\mathrm{spherical}^{\\mathrm{origin}}_{\\mathrm{Schwarzschild}}\\right )$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAhgAAAAmBAMAAAB0Rf/XAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAZnbNRO8QMquZIt27\nVInfsDh2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAIDElEQVRoBe2Zf4xUVxXHvzPz5r3Z+d01ViuG\nDkO0pC3jllJTLdBJCIamjbsSsws1kEcNYbXIjBQsGuu8UtO6aLoD/yhp3D5tkLbWztiW/sDUnVJr\nNoRmxyaSGLG8QlW20WEWYX8gMJ5z39vZ2fmxM7sYDdO9u/t+3Pu95537uefed+9bALAF6fAhT7Jm\nAVj4IQchmr/ShCB1zsEA7JqgsCnerDBsadGyeQ217xah6mlIezWKJE14vboh31MqyZSRhrRNL3Jp\n1ERHsmnbKZsTwOaGGiiCIqU3pL26ROGI+tTSfVvy+Nqi8KODeKorotVtwBJSPFFXdfUJvFk5LX35\neTmPh+URPQb3JSyv24qPkmJNXdW0Anm7Om35/6UwARxW8iAYL6ELBGMEu+o6korCPUoqed++rJg6\nlDeNepUsyY6Q8ghrfYPZWjUUi/PEuZZuNvnfXTGl1o7Q5O3OFaBO7lE6GEbOnWYY+QZgOA3Y8mTm\n/jhWtglz92uTVmtcmZKEAfMiVhvGZdOCYp1r2JtVtvzqlGrkTTFRkYgMAaM1pzYKw9WGljRZ2Ucr\nMBOGVysarXVRlJgXtWHUMvBfyR+obWUA3qC704yMH6toFIY9D0+GrH6ORkozwUBuSH9uXO8eR3th\nTO5Nbhmzf6VmAE9Q9V1AIEk3b6mAITKL3S7uqh5MyYE46kWG+0Gz/sS5qrXZZk6NDPJmMpUUKUfw\ntDFZMu2VcgmBECnaN0TpKPflst7d4V2Y9+8/9C91nQ+2RkJYuebdzwdWhPv1be8sFAoIiXtQYxhy\nLpyoQL41/L6o9twYsHqo9WY6P7Bu2yJ+0BUmZXG4beWG604HgYGfs8Fn5u+Wblt86lnyhr0He4wS\nGJIGm4HGkjyMGBmGrVBYCuzPKvd630BKl88iFsUR3yH8BFh3bNgB5aycgUcoICRMgn43ZXGmHIZy\nCN4QVyOvpBH82s7eLQu5LzTm03SqLUAaB6Pya8DRIBmUXsYq1fnTWJBcYe9Nj+lxxfSn8Mnidb2L\ns0gxDGx8ohDErfCNejsQCOIRODUYvi60q7gD2IpNGdro+4UCpoQeT7+3AqlyGB4DyihXIwiuNH4o\nuuotYLieM+Xl8i/Kc1apNJpvB05EIQzS29AZcqRhuuIbNT0uhVFuYbr7y5iI8h15eZyU3jYeOCf0\nd/JSFErkSZ2f7eZJpf+wLhSWRMCQ6aVZAYMtXuZqBKOlw4LxJnAWiAx9j715OsPHqsn9I8q2pWU+\n2S+VSzwXbwRbjiUhDCb2XPPxoENjGKZvwuOZw/i6yk8aR4IjwwCkcxJ5C2+GYTgNY70f8jI9Eec3\nDWznKDzuHBcKSyJgcEYFDOo2XBTVBmhJJ68XkXGUYfij4EZCyvOxemqnbEkDnyqX0PKpQpJhBDIQ\nBq8n7mKn6dWEb6bHBKM+dbNH5qE7QyY+w3YIhhgmnDEq2JowWl4O/WMrKP4S31IZRsJQvqPj+i9w\n7JTCoMmlEgZHxvgEjEgkPgnDCWxhC7QgrJlSZkmMT8vLVc9yt5iRIWAkQqTgbbcVGabHAw1RFz2y\n2uwYB7nM4Rxje6/TZ408TwA+E4YypiduRMzAie1xhvEibA8ZcAVZUQoDy6rAcCYpzCwYvijV5glU\n+O7Jws739WDIcVooUaqA8S7wMMM4EbUMtkEOmTCE96bHA2iEuuUELdmJp4AxjIBBNy9m8dUg9gfx\ngQmDWu9pgzODM99UXwNcF+D4Rie8OismYGT4Yn8UvUH5X2RiMildcBigauSwtPRBXZAQMGwXPwH4\nc4+5RyPa3V13H3K8Ir23B7TXju09k10wP4Tc6Xhq22nQ1ptgRMLLUWb6jyqO4DZd3mDRVYbRono4\nMsgV8s30+CgaoS5gbOb9iwWDtrb02gC0u37wO1pn9EQO9I49NLgWWAB7EO6e8H1L7im8jfYVQ/3S\newveZ4WuCAkdN/eO6XJfa2It+lWyMZmeyX0fXG1n4VHcWTifpPPOwmPHz2s4XvgsHsfjvKP2pe0Z\nW9weckRpr/08jkqG23DRTyrryJKDMbQYWI8y019snR/F7a2LomRbGOze+zdp8GKWvFHZN+HxzsLu\nUurSwe2/0e/YXkGde0QeZBj2kws5MpRz/G644iTptUzQh4VfvVBSqCyj3bS5ox71d/qBbTeFaIAe\nsHe6x4+pKZVGneoKCRgxlYdJFdM0TOqmEur4M27Gxyqpi28cMYbRByfD8I3A31HXcl2BrabiOJV8\nslhKE0aA5y2K0F3o+9mejfD/3hVSyINEVL2nEG0nZQoWDLohGFVMNwIDJdQD8b+qRiV18Y2DYcgj\n5pxBJIjHFaeNNS3QtwG8XSx1AB5eiAoYqz79wLUI6N7FDOO3+LvuS6f0EhgUJgSjiulXi/ZqXkyh\n3vLBddcGK6kLJxgGdY8jS6a8tKSf8cKw0oVgZZaVQ3uXIeJhpUAId6EH9wk/nJoziZjuCRMMV5u0\nOImMKymHipHhCrm/BFSaXl3YPWGv5nkKdWnN5lvUSupFGBQiAgatvPm9979KLd8eMuDfa4gdtT/r\nz8J2+IYltNdu73vyLycjOoYi8qD2qde7x+VeDbnwwewsPZtCHWuxrgr1IgwasvuZeUIHfyJrujSF\nOv5JPxXUwT1yrDfZPQb/yZvovYVT9BebLf5mQ0iDcuJ7X7M1bcbt8XVwla4Z12vKCh6eN/CRpmzb\njBtlYqDPUnMJ7nsFBPmVORb0ryPrPfJLfY4G3rAYuONzMOQoMfgPYUL/y7wMCjoAAAAASUVORK5C\nYII=\n", "prompt_number": 3, "text": [ "(Manifold(Schwarzschild, 4), Patch(origin, Manifold(Schwarzschild, 4)), CoordS\n", "ystem(spherical, Patch(origin, Manifold(Schwarzschild, 4)), (t, r, theta, phi)\n", "))" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Prepare the variables containing the scalar fields and the 1-form fields." ] }, { "cell_type": "code", "collapsed": false, "input": [ "t, r, theta, phi = cs.coord_functions()\n", "t, r, theta, phi" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left ( \\boldsymbol{\\mathrm{t}}, \\quad \\boldsymbol{\\mathrm{r}}, \\quad \\boldsymbol{\\mathrm{\\theta}}, \\quad \\boldsymbol{\\mathrm{\\phi}}\\right )$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAJQAAAAVBAMAAABS/tqaAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAMmYiu80QdonvRN2Z\nVKvu110NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB3ElEQVQ4EaWUv2sTYRjHP3dnfjSBJovzBaGb\naKQuThELbiVV0UEpydLJoVkKbn1nES9dlNYhAUeH+g9Ig6tKCo46VJycNJTWYMXX5y6HNM+9hRYf\nuPe5+zzf58vzvtwdnCW8C22X/EoKvZqr6mbfLm24Cm/Br0rhKhSNS5BlK6P8QZbCLYFf5LoH54zk\nU8RwQK/t0P0QloOCgYZcp4iSrWPjjagoXRcgPjN1Sj2jiu7H2QPytp+txdOQ7/IKhtaOlcCzo7Xn\nilEZ48lgKoJ3O3e/Clvmiaw7RpUhHD+2bUUv/6JgFYP1hQrDPmJ0Q2oOq9xR8EJ3fbfWHmno/+E8\nlS7M8eYEq9+6B1p35hv6JGgc8ojKPnxi6wSrn1mrniEcaRztsciqWIVnsbK7REvaqtnhGduywTDd\n4IxW5FxTVen1tbC5G7ymaZBXIT72lnmoFS6rZrWQPcGo4w/8+HOa46ms0dJFVqdHT6wUC832HlpY\n3pj9GMnHx/v4FaW4eZPyodz8C89aOeBpRunBbREoyFprczHuu0+5nva/TPPx5GJoeC3pCLr4g7S3\nlubjycXQ8HPSUezAwqQ3rxWCXSwLPyQGK7LKry8Of5KmVhfLCuMzn0wU1JLb/1z8On8BryB67lhP\nHhEAAAAASUVORK5CYII=\n", "prompt_number": 4, "text": [ "(t, r, \u03b8, \u03c6)" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "dt, dr, dtheta, dphi = cs.base_oneforms()\n", "dt, dr, dtheta, dphi" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left ( \\mathrm{d}t, \\quad \\mathrm{d}r, \\quad \\mathrm{d}\\theta, \\quad \\mathrm{d}\\phi\\right )$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAALsAAAAVBAMAAADsqILHAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAMmYiu80QdonvRN2Z\nVKvu110NAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACaUlEQVQ4EbVVTWgTQRT+NptMt/lpctVLR3rw\nGsRLT5WKFUFsDv5cYy9VKCQ9VVBw9VJBsQVvAXVFkELBBkXw4E9QRC/Cgh4Fc/LYhoJahYLv7WzD\n7swk4KHvsPvmfT/z5mcTYJ/DkTTBxSf2WcTB+jBgTppoLHGBQwwe5cfXXX6aUZoNzSJXIiA/881E\nY4kHjFUIPc8MQfbiuclFY4B9BByol+umRknIHjVgxGcC25d6nGkx1P4ZypbZlWSejK4Ao1U2ZPsi\nTWbEMPvMKsrSUMQLfkTAZWA9wtm+4JvUoZtT6GB8YPdslgtxh16Xlhd38XT2TFPzF7eWSL/2Y23J\nCmwEuB5YETiV918Ar4Np2pn78Kj77xqTFhdiJYR/IjylQQrY2tx8qAGxBJ9dmasiU8NrWkMNLtl/\n0Kk4B0yFTvgGvJHJiAC8AH4mq5wrJCszVa+LUhstoOFH9i91qthheyH+2gHswKGuUqEkuAoPxTac\nHttvNNnedMn/ZnvLhVUAXYfiasociCWvyD53jO1pcxqRfb6HeposlL15YRVA/ZSNy6Ak2zjCjeXb\nfLQ0D3Xv1UqVtD3ORt2P+loZMdDC7QHIBUzgNPho7wJuC2PbKHbn0ail+JMBtiSmArpc6TNUwEf3\nHi3dJlmHn+3Qh9qJPquFm4t/uu7JJgq/Uvbi0+HxB+rDe1tPIgpYuEZFq8R5N32D+LkAhSq9+/G4\nn2lJPkVLglaJK5kySfvT4WQv5F6ivzN6oT+W/SyRZKJulqlyPFEVMjFIpXOpUWJgl/DPMQQfS/R3\nEvP/s0dW2SUjDGV5Ca7kdD9iAvgHv9m2uFa43G4AAAAASUVORK5CYII=\n", "prompt_number": 5, "text": [ "(\u2146 t, \u2146 r, \u2146 \u03b8, \u2146 \u03c6)" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The most general spherically-symmetric metric has the following form." ] }, { "cell_type": "code", "collapsed": false, "input": [ "metric = exp(2*f(r))*TP(dt, dt) - exp(2*g(r))*TP(dr, dr) - r**2*TP(dtheta, dtheta) - r**2*sin(theta)**2*TP(dphi, dphi)\n", "metric" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$e^{2 f{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} \\mathrm{d}t\\otimes\\mathrm{d}t - e^{2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} \\mathrm{d}r\\otimes\\mathrm{d}r - \\sin^{2}{\\left (\\boldsymbol{\\mathrm{\\theta}} \\right )} \\left(\\boldsymbol{\\mathrm{r}}\\right)^{2} \\mathrm{d}\\phi\\otimes\\mathrm{d}\\phi - \\left(\\boldsymbol{\\mathrm{r}}\\right)^{2} \\mathrm{d}\\theta\\otimes\\mathrm{d}\\theta$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAlQAAAAaBAMAAACDe98vAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEIl2mSJE3e9UMqtm\nzbsXyEShAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAIQ0lEQVRYCdVYb4xcVRX/vdn5szM7szuhm4Ca\nsi+71cRq48jWECkfHqUbJWJ8JlZrJO1YjTWidDQQY/xgjYQEMenEaPyDwkSMHyhlhpiYBo2MJSRG\nQIcYVIjSJZZEpLgFpbbQ9nn+3PfunTczlJn9YHqSue+c3z33d889997z3i5wMcum49X1hz8xyU6e\nu7i+AHIhj2+uj+QNjM6EM7034Pb6LuOSSGa97TV4PhOXutyOK8n2XCIj7xt3fMo/oUvh1iyEpVes\nNaE2JolmNnOFj1k90ZsnmNduz7MyOtOagMQOsXQWS2nT9dypFDS+OSaJZrZSBz6lc10+/pRItidf\nk9He6gQkdkhCZ6FBrfjSIDY2MhaJZnaOTtRzOtFsa+wJkWzPbKiD/zk+hzMioWOs9Jiedqdf1ILu\nShoezx6ThDJbXrseaKB95kgHUxyC97Oh8b35k6MiYZKlbSigFN15B7DMfiNIRsB9zLrbUjePPPpN\n/E47TR0tt9jcpJhhy6nltCbW0IFEHUYivt5jaVekcc7s47R7PRTP3f8Sih0aUVxrDowj4K4zw1DG\niGQbjuMwcPfTa1XcydgIkhEwRfANHiWiu72b9I2veucw0xKUbZYH6VcOWEsmyajltCZW34FEHUYi\nvje9KUj7pnHenh1AfhWl87k6P0kWKFWXhqy54lGqvFtcJNY3IfcKnsdNQHv1o+AnCZMMkREwSi8n\nznpkniD7QwEOVtGTHrZZKvTbi8+JbiYZTBXHSuJL6zTDSNi39HUMVL8ULttzglLV0VjpdJHwcu6W\nCbyti0tVMxUPLZ40hvsgknKDprqRUuVTB50uEicnLosDi9tgIzFhyqeoohBRC1ewD9sipJSe+sGz\naijbBjU2bF98t2rQVHk1Y8aPoSTsW+hCkutG6uJEINtzG2WVThVvK6WMhAP4ICv4dBXe20WjE0Vk\n2Z4x3AeRZDqlA7jfpIpSRuLkxGVxYJfD0fXITIfAzDl4UR2XcSfbIt4BTEfRSTWUTY9Y/hrgkqZx\nkoXnW2ol7VASXtdvgbPs5Ubq4pQh3h6Pjp7X0FSVfR7AAXyJlfyT1FzuTF/wGe4XJil2Zjq41KTq\nqPTbnPSxWLifJXevsc2R2Ufm3Mv0oghR4QDIbkf3/KUGPOUMVDZfkC+EtI7ntZOXCWTUsO1QEva9\nGSUe0Repxb2lraFsT75BTl/Ex04HtI91eIvL7Wb+1+d/TuhMNoQX0G7Rfi1ddQY3rr1AsTqSkFy7\npYtCNfe1W6nzFxQyk2DvA3v5bWhZ+mBLU3rvcm/3azh86z3bavGR4YL1h1OYimjFAelkl6LF/bSt\nWsoIUjaUWivfJQudFWA+WyVNYgXuzX6csufKEBLxzdNE/FFrI1UOg+8Lc77QSG24WhkrwGVNvKtp\nitIjWME8uBR4tyNDedcKpr7cJiSYbmGqqx29mMR/sfkPgiyLchtYnbmlD98GXgCeqdHrwQgVUDwU\nRdF/6X1HhGD7WGNXQ17Y6qNsuC7XrVBKymE29AIuTybWbPMG8K1wZJBEfWde++WRk+RnI3Xx3O2Y\nbzFL5VF+zLIK/Aj4G7CnaYpSgOyHAznHlR5ylCqtYOpLbULyCfyYzFXpKHYNSan5VXlTWRbhjmFx\nluazVficKsqrVAwGv0K/Y0/u3EMVtEj5UTsgBd/jhkUjne2Ww0yHyiiwMi8vPRPrCVr5O9QzboU0\nYCsmUd9CD3M9Qm2kLj7zreXf8Bhk+I4g36UGXgcexUap0qLky5cEX/kFX1IlFWzjl1meJjQhObzM\nt/Tz9APeQjxC4nn6l5ofs/TDlqZw/j3gVL0I/FsoqKF3DQ76aL9KF483nO1jNWrQ5obERHolbWW2\nQeugbAWSKo11qkH5fx/52XmGkKjvHE3UJFc/jtSsV/G5DnU58kPWp6rIU7CUqoU62wG8HSHvF/bX\nOFVm7dwlkiIpthilF7YhMZ8WCUs/LAzSeFuigFP1r1SqIqoFvZGpMmw3U5Iqq3Kq5qlaBXGshYBW\n/oydhLXBfOu6Fpp4P/cnkZr1Kk4JGyqepmo/PBk6T9WKU7UgqcqfRNUddQES82kRUL0TFsM98MWx\nE+VT6VTxXTnYwsE6Jb5ButydGk9OrzERw3YWN/DeUpReQG+hII51rpvrcs1wZZBE10UHQ45zEqlZ\nr+LTPiAzu1Ss00bQzFvAx+wzOapU4X2k0b7RvJmeHhz2Y7kACXeTWBblNrD0SfNt4FfpVJ2gnrXW\n1H/oYcu6BPx4PFDZ/kgl6ThB+fpHgLeWunGslVo5nA1iX30yqd7imETXNV3PNNjDRuriUz3Mh0rQ\n3+6q46EuPiBfulmaHZs71ORuw8xZZDsb+pwvQLKnLt6WRbkNbJm+X6X/bNDtcy8gF+S2v5/n5hIk\nBVpXuYMsEWXbB18zshJQwTpEPRprvpGRFKqvtkzaT2LWVdslubCR9uFbr+66LInubX+4fQd2LzPg\nPUENv4npi+WdV53u5P5eY93K65OYq2JZlDu+QQnN3oeP1g9FDxyKHrzrNOeGhZ3yf/4rq5U6NWS3\no6hF2p/oJ6JspetPbBZzY5Ue8nUgseKnvz/akg7bDCERX+/aa8TJRqrrjXHLMFqbpy8sqpXrlElY\nCrJBMvEubhM7d0BA2+S6qnvXAd+xo0A1LC2jSYznJJHGk/xk8W2xuo7nBCzlIJlvibXEztSSDlXK\ncXpKi4t1t+8R1xB9NEnsOkGk8dD/3/O5eGqvJ1psb4zx+JmJlfTTTwPJP3sxQDLoehEhu+NYZ/XU\nxHacsrgbU4mWUtLHj7pHkqSGXlxmXILoW0DE2Ml1m2g1k5D8D+WWqIkCxW0zAAAAAElFTkSuQmCC\n", "prompt_number": 6, "text": [ " 2\u22c5f(r) 2\u22c5g(r) 2 2 \n", "\u212f \u22c5TensorProduct(dt, dt) - \u212f \u22c5TensorProduct(dr, dr) - sin (\u03b8)\u22c5r \u22c5Ten\n", "\n", " 2 \n", "sorProduct(dphi, dphi) - r \u22c5TensorProduct(dtheta, dtheta)" ] } ], "prompt_number": 6 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The matrix $M$ representing the two-form as a bilinear map $V,U\\to V^tMU$ over the column vectors $V$ and $U$ in the canonical basis of the chosen coordinate system is:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "twoform_to_matrix(metric)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left[\\begin{matrix}e^{2 f{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} & 0 & 0 & 0\\\\0 & - e^{2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} & 0 & 0\\\\0 & 0 & - \\left(\\boldsymbol{\\mathrm{r}}\\right)^{2} & 0\\\\0 & 0 & 0 & - \\sin^{2}{\\left (\\boldsymbol{\\mathrm{\\theta}} \\right )} \\left(\\boldsymbol{\\mathrm{r}}\\right)^{2}\\end{matrix}\\right]$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAXQAAABpCAMAAAAdgiiQAAAAP1BMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFBd4eAAAAFHRS\nTlMAMquZdlQQQO0wRIki3e9mzbt8bDjT79EAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAonSURBVHgB\n7Z3rgps4DIUhAdoFwmWX93/WlSVfuUQDHNJOCz8yBIMkPhzZ4DMmy762tG3Yrwyr9xqMQPMcn5VY\nq55NQWtVExnP++jLvYoh0FCtfgxiqykaw3u018BuzDGObiuBwIug55Pkk6E222tT28NSjWH9XjtA\nIJ94eUSHdgS6nZh2NnEVH6OMbnYc76oe8fry6ktYmyr9LGiZN44l0+7H6WkS+MvYpctTPjq+OkVa\n87/o1bQPT+DlQttTTuO8u96QfkwG5SqGl2DtObXnkuDLachHvhhl/MNQYg3FA13ZyuQu0IK2p4QF\nctdvQm+eEsGT/9aSw/NpzFrJ8UeSet8Zm41toZUz/EIx2p7iEuVuE3pvmWcj9w5rqdj55DqOtuor\nYc6KR7YieWtWdOgr2p4SBMrdFvSa4NacdUybSinI1XQH3V4FJcxZ8cTQ62nefMx2+/JXtD3FMcrd\nDHrVFMXTdBeHsiy5Z15J56XihpTSv4PeuxUl0Li4miRVTYca4diSrKPtLT0kW2DuUui1aeNawtlx\nz8a4rIV29jIdx/Y1dTbtPKQ/mUSlfWnlkoUrpx2glKPtfcpdAr3tTOci7dK53F7MbvyPNIZoSGh7\nvwT6o6NuZB/f7g/9w3Un095KObsGSrxSXElNr3HphXMczJ5yErDwk5ouDUXsmlK8+1rHmKtDvfRM\ncnqJa0g51+HsuXPd+IsKP4X+tnEsXZ2nkIr457AR4srmF/9cemmbV8r3bkLbU/yj3CXQO4HuK7cS\nw/7igm+Onkfag1VnaHurTsJGlLsEemFoVKbLeNXyMi11F/1kTjpC21PCAblLoGfFs+jj1K3EsL/Y\n3Af4pnn/4Ysj0PYWDtINIHcp9NTF/e0iAjf0i8C+M3tDf0fnorIb+kVg35m9ob+jc1HZDf0isO/M\n3tDf0bmo7JdDj3RjqKGNi1DhzH4WeqQbs6cQ68b+GtnYR6HHujELPdGNNbjnA7hqeYGlj0KPdWNy\nLqlu7G+RjX0UeqwbE+gz3dhfIhtToZ8XNaW/T6sbMw++qMAMwJ6RjaGjS2NdfAO5U6GDRE0+ftaN\nGeAjjfqIeOaEbAwdnQ9zfQXkToOOEjW5k2DdWGv0wCP1EEU3dlw2ho7ORbnxF+VOg44SNdnTEG1B\nb7KKGbMTxVKQZOyVjYGj22DtN6PcadBRoiYJ3OrGGsouuRm5E91YgL5XNoaNzsPdWkG5U6BjRE1z\n3ZhR/D5MOyq6sQB9p2wME90W4sV2mDsFOkTOs9SNPYtm4GFBoxs7LhuDRLdgu7kB5u4D0Nd0YyTc\n47vPmW5sp0wARmGTc1IAc6dAPyJqqoaXXwZCu9CNtZRZSss30Y3tlY0diS7BuO8LzJ0CHaHJWujG\n8oGkwVatFOvG9svGUJKrL8JHuTPQq3JbrwUQNXl19eqpRbqx/bIxQHSrQW1sRLlr6RZl43+O2DNA\n1HShbgwQ3Qbf1c0od1p6yc6Lmq7UjZ2PbpXu1kaQOxU6QNR0oW4MEN0W4LXtIHcq9DXf97ZzBG7o\n5/gdOvqGfgjbuYNu6Of4HTr6hn4I27mDbujn+B06+g+FvhTYHKJz0UF/JvQVgc1F/A6Z/TOhLwU2\nh+BcdZCB/mP6cZX5X2R3KbD5RYGsu/13c76X9f2/z1bcBCfwc/4z04vBZCdmghMDGPzu0FOlbx8U\nqG5iJgAjuAkVOkhJZgPHWqNB7WS4j4YGHXU3eQcWGCh8FTpISWZPHmsty4b5mJcdeg0TM0Gpg8LX\noKOUZHLuWGs0L8RiBgnZEiZmgjJHha9BRynJ5OSx1kjHsZjGoOIpH8LETFDoqPA16CglmZw81pqd\n6spMoJoXQyeTd5gMcNWCCl+BDlOSMQesNZrgUeYTI+pNU08yi8yFvRZY+Ap0mKiJoWOtkdraztgx\nTK+s7WSGN5kw9ZK6Dgv/W0M3g/NmGUQFxOulnV2Pv2A/oNB//PxnKzqYkowdnLA21+qxPZmn00AP\nkzHl9FzjouVE+GlE//18LzZCKcnEK9Za9mHoCI0hc1DSS4ZSkgl0rDUWQhnDcU13k3eKQ+wnKnwN\nOkpJJmePtRY1pCG9XNiQZqjwNegAWV1c20C6NGvS/BuNWeKaLjOPy3b4Jyh8FTpISWbPH2tNUom5\nOaLbI+tB3uABxy0GQeGr0C8KH2N2+c6Blh8DYKxfZuV7Q18+wOVXMl1GC2T4e0PPZnMLZNXO/1oC\nUdxp5ptDnw9izC/CThof2v2bQ8/aZMLUfvGo90MY97n57tD3ne1vsvcN/TMXItH53dA/Aj3V+d3Q\nNehJHdV23ipPdX439C1OdntaR5WdN4tTnd8NfROUFKR1VNn5bXHQ+d3Q34IiwQG9z8m9JFTZVSkO\nOr8buoLKFIc6Gu+c98nbieKitfVoxPyGvgZoti3UUSpw6kma3ONh5k+J9JPmMFcsJkJh/JhIhQ6S\n70kM9JaT3/slsLlVz9hw5U9UR716shroYXI1mUc9Xj9p9p4/l3CFic5PhQ6S70n4GdYaDV+QHgD5\nUtkws5UNmP7EdZQ8inryycO9HWtt4odsG+LKVOenQUfJ9+QcsNaIBz89x71UNpAOa0kddepJkjaZ\nxzwydhIpKqNVa0G2pDo/DTpKvichYK2R2ojH69bbuYDt1FpaR5168sGJpZr43eein2QvW+LKNAQN\nOkq+J16x1qimMXTcS2WzNnfDfg5TWked1oCEfLQDDRTyY02vn7TFibrSFzqL9AN9/z9HMPkee8Ra\no2wuOhrAWxrzoixoXpp2NJcxH7pnTnMBB4mB52Xb1F6qeDGJssm3tG4lVle6bd6GCh2mJGOXWGvm\npoX16WutX3SKX1iVOcSNIE8S1jAScJ6cdnawVU8+eCycPmb6SSeuJH2CV1euaEKUmg47LQ4eaw0I\nve5Mn8RcQYE+cgM9JQMkfAZWPTlMQ0uLJBm6eXL6SSeuJOj2BcVRIRvgDwU6TL7HzrDWTHrhmr43\nvazoIl/TWHB6ttC5FxgpJB0wK+TrXEqXFsDrJ53OL1bi+EJnQ00vMPmeeARrGXHRVc0wcXAWOv//\n2Db0iV9j23AXhs7McwVBR8n3BDrWGv2vKOilsvwKmt70/xToNn90rG3quMNIZ+b6NF5cGdd0XygI\nzKeSXmDyPfGIEgO6+FH2Sk5TD8rhCnTbUo4GeuHztm8ro4bUd318oQtah/5baxmpqpvHAOdfKlty\nQ2r0GyP/duRzJb1Y9aTpL9Vyk2BQev2kE1fGNd0X7oAOku9Zj1hrBBzzUtm66Yu+qbOc+oKPij/z\ncpw6K1ANuFyuqIeXTIvNRV4/Gd0ceXWlLwxWtPQS9rzXDIGlepJ6rkE/uSyOCj3BG7pH8aWV9JGj\nHBLpJ5fFUaF3IND5BmvxW/I73SuBwFK4l+gn58VJIVl5yb0sJcaCF+ow3YtKYD5KQW0v31XZA+fF\nSSHt0wtr1c29Q0IgVU8Sxpg5Jfjk2cGsMBj6Hyubbdmjjw6lAAAAAElFTkSuQmCC\n", "prompt_number": 7, "text": [ "\u23a1 2\u22c5f(r) \u23a4\n", "\u23a2\u212f 0 0 0 \u23a5\n", "\u23a2 \u23a5\n", "\u23a2 2\u22c5g(r) \u23a5\n", "\u23a2 0 -\u212f 0 0 \u23a5\n", "\u23a2 \u23a5\n", "\u23a2 2 \u23a5\n", "\u23a2 0 0 -r 0 \u23a5\n", "\u23a2 \u23a5\n", "\u23a2 2 2\u23a5\n", "\u23a3 0 0 0 -sin (\u03b8)\u22c5r \u23a6" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we will calculate the components in the same basis of the Ricci tensor." ] }, { "cell_type": "code", "collapsed": false, "input": [ "ricci = metric_to_Ricci_components(metric)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "ricci = [[simplify(ricci[i][j])\n", " for j in range(4)] for i in range(4)]\n" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The diagonal components give the equations we are interested in." ] }, { "cell_type": "code", "collapsed": false, "input": [ "ricci[0][0]" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{\\boldsymbol{\\mathrm{r}}} \\left(\\boldsymbol{\\mathrm{r}} \\left(\\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }}\\right)^{2} - \\boldsymbol{\\mathrm{r}} \\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} \\left. \\frac{d}{d \\xi_{1}} g{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} + \\boldsymbol{\\mathrm{r}} \\left. \\frac{d^{2}}{d \\xi_{1}^{2}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} + 2 \\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }}\\right) e^{2 f{\\left (\\boldsymbol{\\mathrm{r}} \\right )} - 2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}}$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAA8cAAABMCAMAAAB3TjXuAAAAOVBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXHtMAAAAEnRSTlMAzRAi\nu5mrdu/dZjKJRFTz+71ileTvAAAACXBIWXMAAA7EAAAOxAGVKw4bAAATaklEQVR4Ae2d14KEKhKG\nzdrdtrvr+z/skiUUoRBa5xz7YsZA+PixJGPTRH7jN+Lguf0o8CigFOgndXing7m9E00ayzoOY5fm\n9HH1KFBYgWktHGCJ4D57XyKYn4axEuTpD75+firSE1ktBbrlhjXY1x1fLpEceBE7/ovvn0iyntt/\nRIH3crvK4Pr6I9rpmPR92O83fCnqkM/xP1eB9m5N5H5//1G1t/1278Q/quSDjVbgu3/Qfqp6GJaq\nwVcM/DVXDPwJ+lEgqEB7r96ZT7w4ni+3l+8ISLpCFwF3z6VHgQoKfPetQqjZQcaL4+0G7efBfZW8\nHzPOzvTHYwEFXjewC5WMfo91VvfLDRoCbj//l3B/b0CmlHwO/mUKvO/UzTpGx47v0Qr9LuYY96fd\ntm14+rn+ZbZzp+R2+3AfnD1WOVhv0pwfTY5lp7/76PiPJnnmzoHZO0TLQNBbjYvb7jY8jXiqjtFi\nqsXdvboVmEgYfkPVYic/ITg/d+4nmOdFRWJGjec8UWoIU+yVMtSsO6BGvFaU61QBTrm7nugnBOfn\nzv0E81RWMs9YzGhl9jxSYgh7BH2rOtodidxMQxerOpjOf3GG4q8C9BOC83PnfoJ5XmAsZhsrBc8j\nASG0bq/QtkcGb4KD3d9hiXgHKPRLON3W0tO3fsyvp1wen0XAKShjTf+v+M7NnauNyRKkWNOTZ7nE\nYq4XFC39AJjBFGl0xiaJRLxbMjmnON0qTCD9Kb+TfHbhHAJOQZggfFXwnRu1qI9ZQMumwWJ+drPz\nNaxkibvdME6AHb+Aa3p0U7hH+BvxrgcFHSN1C1YOoPBj137MD+GcREAqCBGErwm+k3PnqmOyRJzU\nEm/HzRUjJrNrdF2kedzt4UUdZ1dKIbN3Lt0c+TE/ZDEnEZAKQgTha5zv7Ny56pgsESe1zLDjtmr3\nEZwzgB1/IyPZsRkr7bnmMbYe00XnnsEp9179MT/EcRKhuoEwvtNz56pjMmlPaplhx2N8cQKU6aeu\nAXa8Rgxj8Fer+2mdP+fadnjd2nLPwyX8Zv6VQCgniMlGzxTf+blzNTEZuGJ1k4G4gsacIxVWRNzJ\nTgE7HiKvE38znk2ThHrOknGoQ6xua7FqzDX8hjhFELAKGgThk4Pv/Ny5ipgsEQdrOE2Ru2jM7wUj\nyIAdL2G7+HqL626hew9YUyUjIgG3sboVm0BzEb8uQRkErII6Qfi4DJ+Iox4mi6AUKxqzu6CjC7Dj\n3e360jN39S7oGJnH0/t6YXUrNjP9In5d3DIIWAV1gvBxGT4RRz1MFkEpVjzmjuh67Y+VPqkrlyEv\nrh33kbdJ6zXzhc7W7LxmHn5Cjrv/OQ7Tjha80mDAV/FrMGUQ0ApqBOHDMnwijnqYLIJSrHjMxWMD\n2sqSblzZGoZOWyD8gbbS0vwI2UAvrh1/I8NO3so/7zjeSC+YO0Us/HSYd/9rnsbPotPB40FQF5fx\nH3iFENAKHgTho0J8IpJqmCz8Yqx4zBbuYdJXlqzzyizYWGS7uksydD9CNtCLa8dvfz8WDaj3jkrx\ntUdD22xHVUFEjfqHLl1XWDZUpMTxZfwHaCEEtIIHQfioEJ+IpBomC78YKx5zgruQ9JUlLd/U9Wss\nLOzc5Ue6Hy4b7MW149VrqCycwOTrlkC9X1OjVRVEjqH+oXV7w7KhIqWOr+LXQMsgoBXUCMKHZfhE\nHPUwWQSlWPGYIzzwpK8sEY3TwSzyBqdA1v1w2SAv47Tsr8mslnsgZP7O/lng3TSvn36aw/tHq1ZA\nZ1S/3yoJaN2+sGySOPl/Gn8jE1CMXwNMQogBoEfuNIDIYRKfCAPGbE5kdATOup3IWgEzUBTylSXv\nYR+Z1bH9Oj77vk0LnSQJ710p/KzzTN1QL4cPjxfiZghbReZklW6cR/bu6VXd4W2+iyZpyGg77sMt\nAZKm8z/F36gEFONH0kUBKtpxHFUJ5cNs8jMaiL0fx8EtxQCH1qWqmKv/gRQrS958KcWH/9v29sOm\nXWzgjGfmh9rwQGZKci/KRwN7Ialtw6sWB09fnKWTfTqtG5/npdZJdispvvUiWa4SQdtxE+mZs1ly\nzhV/IxNQkB8HFAW41I6VUF7MJj+jHaE6+uD7R0Id9+pCVczZ2xcsV5aMfO7ylxdqH9KU7WktVpwr\nSnbA/PR0KGsgI1PcifIBe6H+2nBrM2+VNBmN6lh1e5aN5/c+zmY1Qt7KsGP/TFFTkuwzxd9IypL8\nKKw4QJYdd2btCIWkOVZC+TGVhPiMJhGZnBMrCPADj3UxvXasVpYMvC375eXvR5ocK2y3Qf5Y4rif\nN61O00Y196J8iPJZywF5+JKBygvm/8U7fGy6M8/oaBT7yQ0ugUlYnchXfPbmMZmE4TPF34gEFOUP\nx23djQNk2fFm9JxacaafKqH8mE1+RhMOk3NhDcwpPAMRoK+L+fZUEI+VJbT7ivw+sjwWpZuwax1Y\n+FmJxX+oZXAvhx0DXrj3l96RRRrU+2dulyOTI7NEdATtWC4e+zLdyQ1ocUPLJ7Tg7fiVPH/GTY8G\nGTiU/I1MQFH+QMTOrQSAAnacq1MjhQphNtkZTdQw7ZhPSsLbcV3MDTaSY2VJJwrDjpuDssq3rK2q\nbJd+aDN4oqU396J8NK4X4XfR7Zj2jK3rV5uqCSOqeMGD97S8JtYikO2DppUGrXkQN2vasZseLX7v\n4cHfyAQU5fdGfNzYSG/lRt/eCQAF7DhPp+YQKoQp04DPaJJ+0465QLGNLw4Z+VFtTMuOO5J3tJP3\nWFki33LNi1ad+9cutsKanKEe5Wec15Z3cRMvh4/G9SJSu5izKlrSZu959YU5yLFjUrMXBbpoF5Dq\nAW0eMy5RtyCBi048fPZiFm7b6RGpjvyT/I1MQFH+SOTk9kpMuGcdkAkAJeyYdJOY+R5nZC6kUCHM\n/IwmUQB27F+544Wui0nKPS3mL53L0RslrWoncxNQjmUPoLpgHPBPuKR6IYNZum+r+zpvLUcvGzAv\nGXY/0AKG2PM4qZJZfDIqx46d95ieBOPYSo9xz3ui+BuZgKL83njlDT6CyDImAaCQHedsB6GECmE2\n2RlN9ADs+MVbmVKshP+VMfX6KykEyWPejXJUldC1bzX01hjoG+/9AhLQkyr1Jqzc8cI+vsD/aF4n\ncziula8u7sTZ9EcLBDgU4R7dCsLgPrSqz3/HB98+/C32P3kn+T88Fta1L/VrlYxWeshmSqGfZFTv\nV9lBUZQ/RMBe7WzK/4f1AiQANHgFXfvA6ST1sTMazGdSGWO65mACdjwaD3ZUSxp1Zcxe3999Wt6k\n5sm6nsXTREowcUS6nzXTZYNo6o5x8GlJ1VyEkejFKY+PSEnQjh0b0flOZLdCI55CNQhLPDh2jC+P\nYTuGYeznE3ZlXVX8MgFycLQMvxWbc8o3KJ1ZxUUoGAJAlsdrS3+vhf1ThXCWTqqbK6iTtGNkRsOc\nDZvk5EgWvqDyM6RmJiaJmXQqHXYbnlbVbKqEaebDUxA/zUvMjuWrNxiVdXOQxZeobumTUA47Fq1/\nZPaSqKrbseIX9erC/JZazumblcR0Ng+ZlsdaJkEApB3z6Oz6aqIdW8vqlFAhTNnpj89ogmpzblQV\nbUUuT03kb2VM046NlnEErODtxW4fG+Vx3qaeatxKdH/MWlXosOMT/VyY9rGZniTlFL/o5yrMH2Pg\n1UCeL1zBIMAP7dheVqeECmGW7Of6sJfbjJzEUhnT6OdauB1nPHWxxyJ8/2X3V5sERldcOCR1l8ye\nEcd0OJv89B7Gw47FZDX8axrXX22mR4AF/x38DU9AYf5g5ORmR8tjsco6AeCHdmwtqzuECmE22RlN\ntDDL4/61rqvWVRpTkt+vjWnY8Uy7pzq+uCANr4wrw47pfAAyE0QLOWbH5iog7vHYClwOnK37Lnvw\nDjsWazLxdvwyCDVY59BNj+0kzC+rhGX5owxfMhVdtOmEgiGAAnacqhNtX2of33QyGsRssjOaCGXa\nccu7tdSQh60ksSCg0Vkb07DjZh7nt9ab5SLWueLZzEBG5pkDqT6jY60CYt7o6Kf40Rc4/fUrWTHJ\n3g/KjnthwDl2jKxXcQb9byp/IxJQlF+ABBnYYhfqMA5QwI51aYxjgFH7yJOb0YBOZCSGB4nPaOLP\ntGODTT8BOI/btTGteSBHxL88GsyBJjtq79wZ3nxzVgHRhVV8IgoLSY2Akxx5sQGxTWYn37AIv+8t\nnShjU2acp/E3RwLK8StaDwN936m6YBwgy4710QzFAx04jPIjT76MtnVq8jOa8ORzisT8ANM3vxqS\ns9q1IbxOYvDUYXldxV0F1LwGMYuUE8vtDEh1500ay/342ifWYu3kZBZp1+kpjNX1U0JK5W9EAkry\nSz4PA/ukpOpijQNk2bFkiP13GOUMTE9GOzo1JzI6BqfddzjlPfh5LIrpXe8kGX7xfwqvPx75+9gh\nYc03YBVQ8xYbCAgfcnl5T3Y3IOIdP2ng+Kew8y73PEKPHqXyy30ECvIrNg/DNhEN5UQ48urjrRQ/\nAF5BRRA/sBmP6gGc0Q6mfA/lVLzieMqFzalu/AAzsI+Awih4QDszzMVMNPDMfX3YZ3SgVUA2cA+3\n+Y92Nbo8pouqT/+S+Rs4ASf4FXsiQwygqh1bjMdSPJUKeQBjNiWEklEE/lucfpcVMMcSD6Sf2LlD\nDNlczERdzGGIza12H5/RgVYBObHGLqDteItMmYlFeDU/5SvKgFYwphC/DzDKZXVpAViuKmGW1TKn\n2jCdfCAtneKn0KIWsvVPyOPHYdQ+owOtAgoFBt5D7/sd2PoPjMC6eDk/4SnLgFbQUgQ+hRjVsjrY\nS/hqHczCWjYNHjPSxRRWJecutPjn49nMQITf2Wauf0YHWgWE5kLv+z16ut7SYr6en3RGa1/GKqAh\nWsEUpSDGFH9+N1UwS2vZNHjM1tOH5Jfi5B1oEm1sZeLLGuTRPqMDr27BMqKrW61FhIvwen7aJ0G7\n/NiXsUpoiFYwRTGYMcWnz00VzNJa5tSrI1869OmRfx2yYzKDOjirwi79tM/ogItw0HTo7D3XXX09\nP3lUaEcdHyEuoSFawZQ8ghmPXSBSwjDdVMEsrWWGHZOS0BiJMVNd4wy045eaDQ1GuZnzr7XP6MCL\ncMBAQhdl9sL92q5P0ih3LyZfuZ6fWjCdS09XQ3RFNBQKpgqYpBXIqO8CkRSK4Qib0YZn3wnISScd\n+TxEr6MxSfdxNNCyDkA7nkxDtWPszY4u7TM68CIc23/0XOjWfd/HmGnI03yqNXI9P7VjmlL2Zawi\nGnIFkwUMiavulWYkAWMzWrGEDspzojEjX0gL0WfeA+14jpRv2mZdNNrjMzrwKiA0GtdtS162OZ17\n+13OX15DpmC6gGk5VFwnYce358Q+j2Rf/DMVxLTc0F15FrV87B5p3Q85Xs32s/YZHXh1i+U9esp0\n69L7oJfgOFk0usv5CWFhBqogQsCoRMxBYUYSJjajL+JEYw6nKohpqUxxFane9+5MEBkqtLpF3kv+\nz3T7BLoKyPtHfNeKhvkNr+tIjpY6vILfBizAQBVMF9AGSDgvwEhiiWW0mc8JWI6TIpxozPTt1B3g\nohdiHMFZW87qFjQa043Mul/515/4LOyJ7R5F/5Dem+MrVSTwKWDx6LjdVVj4IJD8QARnNWQEyQIC\nAAmXJGN+/5GoV5uc/nxOYIKcSE6eK5CL2DUoP0OYeVvYxSgy7se+C/7213ndZSP4+Llu48g+2P5d\n5ZdktICOr1SRi0UbIxfwa+nih+cZmILJAjoACRcE46l+YGHHAU4jnxOoXCfntZTdcemYZ6cJu6nI\nvPINz7AmpuPtg3JXt+AZ2FM4qTFsufOAFtDxVQyy+NH/UtF8pB7+nt8lO89AFUwW0AVIuKIYT4zn\ncDsOcer5nAAFOFGcwL3US9Hn0cKcbtI8Jm+gSA8wWxCbKgPaHdWtP3r8uB0fFRmyWFkXrj3Xy4Wm\ni3vA8cfDw7sgBOkC4oPXfahdIPSLiceQUN58TgyzgjMsZsx6KiB6grSnbDnOxB6AzvUiF+hWfOxT\nRjy0cHn8LVoc/56/SIx2IETBZAFtv6jzYxcIlDfhOJrR+vs6J4IyfpCYfaw2W4YqJRR9IBh0/y7b\nt+TG0b0WuqUq/bl2rH2lqmmpyvf7JfPXQr8cIDFhIU49nxODq+UMgXluWlLZBEQ/DM2m9JeN0wrt\n3e58qrFrx5pLbY837eodDtP4K5JeDpCYtj/CmYyZspdGojSnnc3hKda0har6oU5H5gugp9ujfsjs\nssD0TLbezxfAxddT+KsiXg6QmLo/wpmGeY+2gFC+M+dQA/nxPjFuCAQHXHrTbfgiv6nAhj6RKLJv\np/BnB57i8XKAFEji5o9wJmLy5Z2JSa/uLE7Dv0teHSQYwZlBj2DAz81HgTwF4iVgXriZvvjqr6Dn\nNlDdDXosdrMHpogUC/wJ6FEgQ4H5Bw1ODNYc7ZHu9K/FYIIu5hb7lb1iET8BPQp4FFiOiQ8eFz++\nXHWI+MdpeaJ7FPiNAtUHZNHJuO+IDjopj4dHgd8o0BVce1eK+M59waXS+ITzKFBSgel2k4RJ6vgn\n5Usm8wnrUeCfrMD3Zp1cXOvPQlZ9Pb9HgUeBRAVeZOLSDX/f+nO2bpjqB+lRIE+B/pqR2P8DFo22\n0BqbFtkAAAAASUVORK5CYII=\n", "prompt_number": 10, "text": [ "\u239b 2 \u239b 2 \n", "\u239c \u239b d \u239e\u2502 \u239b d \u239e\u2502 \u239b d \u239e\u2502 \u239c d \n", "\u239cr\u22c5\u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 - r\u22c5\u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 \u22c5\u239c\u2500\u2500\u2500(g(\u03be\u2081))\u239f\u2502 + r\u22c5\u239c\u2500\u2500\u2500\u2500(f(\u03be\u2081))\n", "\u239c \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239c 2 \n", "\u239d \u239dd\u03be\u2081 \n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " r \n", "\n", "\u239e\u2502 \u239e \n", "\u239f\u2502 \u239b d \u239e\u2502 \u239f 2\u22c5f(r) - 2\u22c5g(r)\n", "\u239f\u2502 + 2\u22c5\u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 \u239f\u22c5\u212f \n", "\u239f\u2502 \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r\u239f \n", "\u23a0\u2502\u03be\u2081=r \u23a0 \n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " " ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "ricci[1][1]" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$- \\left(\\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }}\\right)^{2} + \\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} \\left. \\frac{d}{d \\xi_{1}} g{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} - \\left. \\frac{d^{2}}{d \\xi_{1}^{2}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} + \\frac{2}{\\boldsymbol{\\mathrm{r}}} \\left. \\frac{d}{d \\xi_{1}} g{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }}$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAv8AAABFCAMAAADq63kqAAAAOVBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXHtMAAAAEnRSTlMAEM3d\nMnZUIu+JRLtmq5nz+70bbQ4wAAAACXBIWXMAAA7EAAAOxAGVKw4bAAANoUlEQVR4Ae2d2QKjIBJF\n0SQu2WbG///YYd8LgSqTdLc+JKIIx0tFWSuM/Ynb+n68hz8R/GQ+FcArsM6MvUZ8OmcKpwJ/ogIX\nbv/XjX+c26nAP6jAcmds3vjHuZ0K/KMKTNvZAPhHi/68ba7A5XbKcCpwvAK3r9vZ/Z25yzV3MBPv\nPHQqgFFgumCuprn2kf4En6f502h7plJUYF6uxfMfOTmI9m6w3VfG7j9AFkCdgb9Pgd+oZd+XsK/z\nOk7T9Djbv3+fvf3YHa0/Msj0DjmWTWw/ptWfhHOOn1eV1qF97C3Vl2GbqoCPidRCeggBNQB6/Jwa\niFw1GsDHgxzMJbi43f29tSn2fnpNMb6ZtwSlBkCPn1MDNRVHTWQSwGmj+RnlgZsQhy3tA8one8DR\nJtID8mfUAOjxc2ogctFIAMew1h1C3h8Lrg+yDXHtHu5FgxKYH5KhTaqwnKKQJUGNn+OA5vf78Sg/\nWi1mhF8bxAGqXK7bs5gdsk7ehjjvwJRIkaAE9s8YiqFNqpIU/JwmQfXsoYCGF6dY96ZvoQQjKbJX\nuYfl3v1EVgXUqGHxZVQsciwohZg4hkapatTAjZ+jgF6y43opp4ETjKLIhk38TuFtRY4Ml+8/yffW\nPd8ZC0ohJo6hUapEO/+AIkGOn6OAFmk4r3LjEicYRZE9d95QI67634o4bHzMt2vDgraS5iBxDChz\ni3AkCXb8HAU0yorDjv3jBKMosgdc/Zlf6+2Kq6CxZsSxQ3QS0GbS0OIIGDruPGRQIUuCHj8nALqA\n1WeLmbuHymMEgBvY+yOnIzxA/oMQ1/ILM5crDSjO/ikYCEqTy+NI0OPneKA7+Dp3mLkirTx2JOCw\niH6haEpCJZcXrRVxah4CIAJF2T8JQ6tUnspul4REJ4cHukBDqzSYeEC4g+otn/yX3uq4KZFWxGGD\nJDMpxt9EoCj7J2FolSoWQoZJSHTKaKA3WJY0mGhAplopOSUXwT7stI5zF4bH/hMG90M7PWZpAkSg\nrJnUQyFhwABYFhISnRoW6AZ3LdJgYgH5MAnUvak6YibeOsZNQP6vLZnKnVdjDygVKGsmdTdEw4AA\nsCg0JDo5JNAkug7ncE67TpkIEwko3CtAbyg1F/Mxsil7A1bwvZ3mV9TaOARMBYqp/9AwNEuV0Z6G\nRCeMA7rKnvNb1nyIMHGA/C6nDezeH/lUtOflxZANgGbEJ9hlkClucYgIFGP/NAzNUuUEoVJDpI0C\nmi/rur5fQP2CBhMFKO7wBve2DK/bep1ft3hRorjM26569tAQVJOedt5TM+J9Z0Day1vtokAZgtQj\nqWIgl8oDsLtVJDr2oUCjXL0E1a/rMA8FFCK8GysbWrjhfXur99ps6k/P8D33Mj+AZvuf4REJnXvL\nlyWFQFk/aQsHjwsRfAxA8VpFfgUIlvF4xR59/TuvddLjwqN+7A8rf134rwAzrNZs/2xrvwSW0JKC\noKyfFM42dwYk+BSAgrKKsB8Bymmljh0PODZ2tigu3is6qGrRTbcOntv7FroQMmfajRla8juEbxhY\nNu+MJTU4KSgzp9pJvYz2d002KYE5czCAQrSK2PumA+opoYJwRhc6wCSzpWt6g+gVVZv22JAZtB10\nabYXKsQ0dawNs6QwKOsnNSpUfcMEHwJQlFYRRg/UU0IF7egBk8ygZ20SMThgZ63edes+N2ltVGvZ\n2+3/AryTetQ1pCVQ1k0aiLITKBF8BEDzGUXYAUA9JQTLdgBgklmP/T9fy+Wluk3N8oox08ulz33T\n/h1pCZR1kyZypgem9XabRB9BieBIgBDJKXIEEIn9f1SxHvvng8amJvLQnZ9XUf2X+1fTH8SeqlnX\nbv8jMAO0R11DWgLtJw1tKxdauRyzHGMpEXRLlcty55hRhB0A1FNCMe5HFRu67H+2BnrR/nrmh3jM\n8X+r8MY7tEvRHvvPDzl0qGtJS6CsmzQuuySsVp/LrrISwXEACZFVhB0A1FFCMeBRig3jxW6j6Zvn\n09ti81SDFtCnovWaUMpSr26ek3Oke1WN5P/Fd7gbhvpkQ3UhRHVcZ2JJtWvRLCj/jxkZvZl0H0HO\n8lJ/YVMiaAbIlmYZR3dZWEUYKZDS2y8hj8aVuHcwsyviHaWYY/D3Uvv3z0L7tgllNDT9tPyCxP7j\nHxiUqDue2v86iu2yyC9wwoZLwe5ZUl3YWVBj/+2kNh9gR7nWuMnGUYlA2z89QMplFaEtu+4Sigg/\nrFhf/edhH/fqHTrZsG//uvneXqip/SuR/KdLJBsUtKQlUNMT0k4KZWuOP2VP1kP+YksE3VKZjArf\nkQ9Qq4iu/5CWXUcJReSfVqyr/r+Y5q9uQ91sm9e3/+5G3QiMSXeoa0lVYy8Pelz7V1U21Eh5iaBb\nqsh6MsHYB6hV5Iiy6yihCPnTivXYv7cmZpVPfn+Rp6v/vFVFpf2pStf/40hLoKybNCq8JDiI579e\nz1AiOAyA/38UJ/D+Q9Mpwg4Awtv/pxXbtf9wWqcsYc9nkX5xr9v21m1qZ/+jahu32//Fdi+FBlVW\nNwPKHGkJlHWThnwsRbjzSVG6xl0ioAIIeSSOaHZ4/r2dIqbWR1l25RIK6WTo64pBcw2sY8ZoWqeg\nFj20ZhOPF77N67Jd5C/A2v+sDb/H/vMTfbLqlkB9UhiU9ZMqFYoIjKnqv3oSU0ulAMLPFMfzAXps\n2WVLKKSToRQxiPRBxWD3LKrWmkzr5O2lUQ96CWbnYGy6yPGuydj7qhsJJhzcYTGw2NlFYbS7l693\nBgBlISkMyvpJDQWEIJ4ItsYBE+ABDIj6jnGMD9BQkQPKDiihkE6GYkQT5dOKPYC6hq46pDPvLo8h\nmOvwUM9qPvP5ydsC8/uyvaThD/2TenfrZEYs+a3e6Ckoi0ghUIYg1SAQgnRm7TpcIAI8QCBIUnRm\n5kWsCPsUUIgnQj+j2Fv9EFNCWWvNTOt8moUv+hK9RGG+3ZS/U5OS1rZjDd0ALRkySYffECiLSCFQ\nYwUdpAYEQphenMH9ow1E0C+VAQi/Ixz33okUMetfCMsuBIFDEaKN+HHFwPWP0jFjblqnZdU7c7ZW\n4poNzfWfK7gkP85ahpGgDEFqeGoRyKUyAOF3iFPyAXok0JUP8F5vo+tv9SFDRP9MuH8koMxpyiw2\nd44Zc9M6Q8D9ULP9T9Xrf2lBu1Z7kyI0S5Won+KgfICigPgPYF3vW7zAJEVM7qL+AApQZHNNjc1z\nzJib1lkPp2I2uygCX0lxzsSgPf6vaBGapapQBOUDFAc08orsrLygO9AfU2xIFpv7jhlz0zrdrdTt\nNbsoekNN8ig/atAO/1fECM1SVSgSRWkL4oDGjG+dH1OM90rHnY2eY8b8bMk2CdtrFWNMBGRIDdpO\nyr1niBX/0kUqhVbYt3keB5Cv5jAOaLRLDVxeeUQ7aOQi1u3hAEUeydPWc8yYny1ZR2ZjNSPWdv9Q\ng3bYPzFCs1RWZLWTx3ErkqLo+0EcUM7+84hftP8pcgDkOWbMTw3cVy2MYTTMdhOFUWWItzkyR9ND\n5KDW/mtJ+dCW8H4hpmwNJFq1ShWJksXxVyRF8feDOKCM/WcR/UmT+0xBDBygSGqOGsCeY0ZgtmQA\nsB/QiMP96XrCS1fdoBGJ6CJyUGP/1aTc/sUtSRepJFq1SvV7igREWfv/KcUEbtxAd44Z89M6g1us\nCKhCnaq9iO78HaXLkRpU2389qe95lESrVqmcFmrvBxTxkTL27/lJ/QnFOO4aeRvxHDNmpwb6d1iz\nLwt1qOzT4QkuZuLEXuLUoMr+G0h5tce5SKXQqlWqWCFiHD0i3qSIQxLjX3wEzB2Qe8SIWMU405wZ\nATPQmWmd5lT1t0S8xqMg3uVcqOm1mCVk90yngRcZ2KUAVfZfIA1BYxIChEapYoIgTICj7b+gCB8+\n8ssuANgPECBSKFYe5I2nde7fVhRDIvKpV6vyDqpmCb3kSl7xwRub0zZe7d/svQq/lCjlMIgG1fWf\nkBQGDXOXISxCo1QZguCQwQnmKwYx9gLEQGl2BlFllJ7fO0IB+ExeUi7XZFqnO1W7pxDf71W0AO6r\n9mnnXy0m/MzG5Ull749/vdgnANX2XyANQGMCAoRGqRKC4IBWBNG5op//fHlcZdkF+VcE8IVGolip\nAhRP66y4qyiKRHzZFS16HYof6eoBlH6M/jXxfjKHMY5QEd4l9UHT9PAIuwC8vlHdj2BxujvXtf1X\nl10qyc4Ri7gTDz5Nopicpg7ngTwjEGfXpa/s31Ur+GIBv1DH2tYvkip3eY4UBM0lgD2WA2BoArsi\nqR3vGKB2DvAKGsCl+qECgsAnRMNWOsBUUcrP/3uhLgZnQXRml9T/oRLlGSSzCxA8KoJLwYBbkQRG\ngU8cAQTn1nGGBvDZ2+asJR4ui/DDIbbU/ufLtpj3wyhu6JtbidQHPYyxBMA+QhDd2s8BRXyMABD9\nJ9cxUxJ+jpuaTZTavxfXW6jtHf3sbh3pgUxfB4jv7eeAyAE9BzFx2mThWTj5uN42b0FgkvZSPfUm\nuZTwQA0pYXZpUl8HiJF+Doga8NnfRxyjAOGnWB6/s708xyo7UQ88XUN6YPbckUCFVIcCxIn/HBA9\noP4/izjhj4YRHXUf5Twz+wsV0H/B88U7mzNDY1/EObP+pxQY4plKH7/72Y6RfTzrM8O/XYH/A61h\niJXg9gmbAAAAAElFTkSuQmCC\n", "prompt_number": 11, "text": [ " \n", " 2 \u239b 2 \u239e\u2502 \n", " \u239b d \u239e\u2502 \u239b d \u239e\u2502 \u239b d \u239e\u2502 \u239c d \u239f\u2502 \n", "- \u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 + \u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 \u22c5\u239c\u2500\u2500\u2500(g(\u03be\u2081))\u239f\u2502 - \u239c\u2500\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 \n", " \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239c 2 \u239f\u2502 \n", " \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=\n", "\n", " \u239b d \u239e\u2502 \n", " 2\u22c5\u239c\u2500\u2500\u2500(g(\u03be\u2081))\u239f\u2502 \n", " \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r\n", " + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " r \n", "r " ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "ricci[2][2]" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left(e^{2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} - \\boldsymbol{\\mathrm{r}} \\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} + \\boldsymbol{\\mathrm{r}} \\left. \\frac{d}{d \\xi_{1}} g{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} - 1\\right) e^{- 2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}}$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAfsAAAA/CAMAAADQW5H2AAAAOVBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXHtMAAAAEnRSTlMAdlTd\nIu8yic1Eu2arEJm98/tBGNu2AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAJ40lEQVR4Ae1ciZKtKAx1\nQXHDN+P/f+ywBUFQWcLtfjXXqm4VIRxyWEKA2zTmalvz+H34jRqY91qour6W5K9cJA0slVonGUYk\nhF8xtTTAhrmK6L5SnaoC9v8qdB5IhaLTqYLQr0hsDewVaCJHnd4Eu+y2vL9ijEIGyY7OVgHK87Kg\niPmokOGjuWVmhg2SYgtsugO5fmZqKikZuhaSco+MjA2SHdh22VRhGHlTzrwMZfNVbLUGAZeiRAdJ\nDxYEmhs4Hmtu0pJ0hWMXulrDZSlDiQ6SIHO1HeFi1w2dC2swulqDxS1EiQ8St49mxxYsduVAWuhI\nxFdrqMCFKPFBtgfmHH/9mQneVDbcN/hqDXFfiBIfJDtoCGdm2PLxLp9stB3LBtKmPvcYKPG5byZM\nmcenrXzpmlwKh/vq3KOgxORJN22KOCGfUTuRiL6HDWJaUeyerKBWGzwOygogO8QpPo0d7ollZJS4\nFnfZ4vvSYauCWm3ucVBWAMmOTCdsgL8p3PnSfdkdNwKzyRoLPAKDwM5ia5zNh/NcQa22fByUNUAO\nUUKj+DuCcy3KG/nmGAKLUxNothdYGaodNzAdgbbeo57/RMXKjYSEsgbILWaWF8UfCXchPed+tDOZ\nXUcyy+x4RIsXA8YyNZ01hmRQFFX7M+SqJEgoa4CkMa69KP66IzjPFltEnJXd5cLUkt3wJ16L1n5r\n7DEkg6MaarVg4KCsAXKNMc6j+GvvzcZOWgIrbVvu+JMjw3gc3TZIN2D+1k62tXQkW/uyZQBMCuYM\nDaupcjXUanEfhRIwNp8EOcf6YV/52+97ELmPS/C+7M2oxv7umEY1M++qOILZ3u6qgyEwqKxuh7MB\n+ZW5t6rB7aPB2FQGOdn1n8Q6ZF75W24NbioGAyLG/KVrZkXFyK0DIhusDrjVS96HjXba3wfFZZR3\nE3bRwQD9BdwDxqYuSHLxgx1xRX/nb7INOpuwVdoBq+jred8/q2Y+mrFGdwR2ivJnPvNjaihotTWw\nHnvrDi/wJU4BF0zM7UQuXxNfAUmDDNKFwZZ9c6fhR9gJ3y1wyaYSwd/gyjX5zlz589hQzvnI1TxC\nuwcLTVcGEx/lQcz81KV3pAacWEyTnsV9585WILe8O+yaxQbpoWldju4oc9LF8HdTicap6zo+pRfD\n+sb/mPICnO1+hUrg5KhfuE14jO00pGrarJjO2ukQWriYlFMRgftcmKqUgDG4ulIC0tPohfv+rqu2\nEkbxd+GecateWFsDZ09+2ls6CSdeLzoS0h+w02p7NNO5VimdD7e+WtCCj+s29JuaccqxikeadB2w\n4+tvCNxzD0YGzI6rqOPdIGBEB2kXVj4/cw+UOcmi+HO5n4VPgFyatDyy0168uGByOTmeLxN3F5Ih\nwNwZJfBk5puLzm0Uw7181oMOT7SqrDG4bzJgUk47EU4RwMhrEC5ITzEX7idnJS9ImSPijj/mcE8G\n3p+yHaZRvJC8u++UrtWAD0K7S1WAcLhPYZcRfA7fiSlUrxeLyCIaGTc39s3UI31yEIl71c+E8YRC\n1aRZTEYAY4MN0svW497qcz3KnNSP/DFnwrANK29m1oxqnPgQoN5nm23G6wRcbOrNNUG1mUwT1tHk\nGHL7T0WyTD1VuvHM5jwrOiqD8B/IP+V+tfWuMG8Byg8iJ7nGI73dcDoOEWRQlU1z4d6ZlnuUOep4\n5M/l/tFj1AGvXHpr1Q8nM3i5KhXCH+/G1Gu0Xs0Emvc+pt1r7v99FOV9pJO4+kHeTGNPhqn2NLcC\nDHCPCNJDrQKeuH+kzJHn8ef2+Wb27iTKeUlWqshkMc1c9ae27/DkXtvXSH1+4lRklTY2d3SaPh8f\npKfvR+4vxpmX+CHAGe8HJShRHyHpWdyfc0JlR7WWjXFyj2vrJZZVDUtqKVINgvggPX1euJ9sV2wJ\nZQ73rTDrmPaoexBSAnK4t/ZzCJcS9y1Z/dDJ/a567J9p90y0e7WCrjBWAOnp2ePeHn0LKHO4b9q9\nXW2bzoMRFyCcJty78xTZXfmSMa1zELpfp8cBk46T+0nZgQjcv8P0Uc58eUHZJeDbQQd5Udu+DUe/\nWaz0jmYLKItyEF7QFLyaA26XlS8hUsyc4RJ+Bn4Rysst65DhnmjSEbiHzLz7E0oeWQ73fMBXGNFB\nenAuATF+vUuS8Guf5nsLC0kJVet03soXN5mk/1CLUisR4qXrpX+hA66pHqHhPSXvxpmoPqW8QdmI\neghj04kRF+QTLvFtMKsebzFfvi9OB/ISGeGz6tj9la9+0UsGOg+9T4jPJVc+9pO9PzZJOlOeJq4B\nBDC3Iu5QymOwZjoCe5k+DNIdpm/L8P5hVzX8PSJSDDlWBla+Vti0ofPR+yII3zTk+BJA33W5v0PZ\nbRyn9jnyGqkHqc+CZOHdtRn8POzZypD2nkQecAstz12TEsu6Ob+dZkLVdh+JMozR2sVTA6TYP4Nz\nddY8CkfirZTzgFtoee422c2HGmoVWaGirAGyi3fl3agOgkc0SSDx7m4dcDtXvu4iv4dn+fPfxeKi\nrAESr6dmsTv/3tX2HMM+4AYrX2Y/0HPS4NdEf35Qhh+IjLIGyB3POu+xZgy+Ip0Q64CbWfmyl2ad\nyBEvNbpTfkRUTnnlYUEMlDVATniEIVajR8asA27Bla/HxIGPNdSql2jVBB4DZQ2QaGY+953cb9AP\naDw7yDrgFl75SpUMag1OB1KFQXxslBVAclsJ0BbfyWeMPeuAW3jlK7UgWq1sXs18O1WEHx8bZQWQ\nLaZDJnlXna+ymJDzgFt4eS5Ghh1HqbUrWL62pcEzMsoKIFF/FY1GbPkF1RTcrQNuwZWvVNFSrQzP\n5lX5I6OsAHIAp3aqwkLxyee8O5B9YHkOPkXfpVrHh5UovkILB0ejhToREVDig5yvGyEdyMkvGF62\n5Exhec5sw0uVINXa9AtVp/WU13+T2/HEP24CngdHU2Wb+KUo8UFezmcZpJkPK3bH+Y5Dr3xxfpR2\n3lN4MVTCfadixJ8pHJCy4p0HR63AlMdylPggEa18qYof6PTV8ty5NJtCiYor1brp7RPnRgpL0HmA\nzApMedTrcwUo0UGit1PsH2dO0W92XKFWck511Saas8/ni/3F3GdjMwnRQeL+nK7AqTd7Gsh/w4PY\nzSmOxekLNlDBO7//Au6xQc74w/P6YC5byvx1j6wfxA9Kicvn3jo4qqL80H9MkJPcv4xbkOJfOsSF\nEy9tnQ7ld/e5jxdSOyYaSHUYEBmu83NqyLIriyNiz/bYHudWqsoZ5ohHAil/jTYn/8c08rdVHmP8\n0o+r2Mr52y8kkNtp3qCWWP/oAarMrzBUDZgjCqhShTD9KyHocr8CkTRAAu4rJNHs8QgVUiZfMfka\nsH8HO1/KmfI/H2lQy4ZnQV8AAAAASUVORK5CYII=\n", "prompt_number": 12, "text": [ "\u239b 2\u22c5g(r) \u239b d \u239e\u2502 \u239b d \u239e\u2502 \u239e -2\u22c5g(r)\n", "\u239c\u212f - r\u22c5\u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 + r\u22c5\u239c\u2500\u2500\u2500(g(\u03be\u2081))\u239f\u2502 - 1\u239f\u22c5\u212f \n", "\u239d \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u23a0 " ] } ], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": [ "ricci[3][3]" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left(e^{2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} - \\boldsymbol{\\mathrm{r}} \\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} + \\boldsymbol{\\mathrm{r}} \\left. \\frac{d}{d \\xi_{1}} g{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }} - 1\\right) e^{- 2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} \\sin^{2}{\\left (\\boldsymbol{\\mathrm{\\theta}} \\right )}$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAkEAAAA/CAMAAADQbewHAAAAOVBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXHtMAAAAEnRSTlMAdlTd\nIu8yic1Eu2arEJnz+71sehXRAAAACXBIWXMAAA7EAAAOxAGVKw4bAAALw0lEQVR4Ae1dibKlIA51\nxw1nxv//2EkCCAgqClztqmdVv4uIeMKJIQSwi2I7ynJL/iW+2ALD8kVUGlNV6/Rf6pMtMH76HW/a\n7pOt9gdKtwBvB33yuVT9af3+XHO9A2hom3ceHPBU1gcU+ivydgssn6WpWb9sH9/m7TvP52v1HTAW\nknG0Tv+Jk3/Cb0sNkrXf5KZaU0v6Azk/2pa25KlB8vWb/mr/2e7V5sM6S02OVXmqk+Qg2cpTYUtY\nT7dOCWsLrGoY27gIWXJyfMBjUSYH2bzBla9lrLx5tU5/dRLpFSYnxy93HMr0IL/YX/B19jde3twh\n0h6nJ8cnbyTK9CDL9XsxoemdoTyLnEZJT45PgyJRpgfJV+bD+Wre+E4n1se5QUV6cnwsRKLMALLP\nUKdP8ht5689HYs3Myi7OwSjya1AKlBnYZp8LvQw/N4s0vTNGukHZNSgJygwaVH0uJMRC3aDGcOFi\nguu8xeBB9BRPBnJMw50GZQaQfH04gWDwF0Of2Ugi3fuNAVvGxQpecdOD6yIiSAs9sDarc1Fd52Qg\nx3xoGpQ5QLZBlZ7yF0afU4XZPkZ69Y6JGBic2XKQRkuf2PN5kBbfIR5q+QykdvI/9mnqszQoc4Cc\nQ8bzF/yF0OdW4W/jxm8Ua9CgzoQ62BMy/KEpRd1B61PBANBSST+6k9z/nlyLv5QIZQ6QLCQsfcFf\nCH1OFQetWq3eUTUuh7PWfIyGF4RVjU+NkFihMPZFtavxAOBRdpAtP7r5Mj8Ryhwgp5ChzxV/AfQ5\nVRw0Wnns2lfksEysLCFoTX1dt67V3FII+/nC/B6s2VTPRaQjlIMco43SoMwBcgidQzjjL5A+UYXR\nLJTspsnoP5Zjm0grX1F7xqXohE9UrX0nxuHV46kQPpesa+byYlGb8va4ARZUbzN9OcgxmioIpR9j\nZpBNaADvjL9A+qzFz0rauZ1mXFYvuRgPXVqG3VuDvtBYFYPwezrwmhqiXmYYbZ4iyZdyEZ1boxyt\nye7sZqVCmTUoRJojjEVqkL31Fq1hop/y59DXtbajS/JTFaolpLS8h5AmJy0WYvamu6wK4+9E/tGE\nvRf0ZoMwOd3WB0ujZN6RID2zSsaqVaNxBibLbEA1QAxrxgSYjqs4xFgkBdnsoq+rfxqqGtVBzXXO\nn0OfZlbLK6pQ51LahRznljwcElMkVSn9O4CbMnQFA83pgKxO2SDlvUiV0jekSMEYn4vOrZTPmdal\ntPtsdeWRBnHboMVhVkhcjIW69AikjYqPy0x0bdlHlG0FMHHBXwh9sgpZrRRpWMnkrDS3QnkHCt31\nVVVBCAj7yxn+cRE10po6KVWycEee4BhfHHJfiyeEzyUrj8ipPKZaPfL27zHGIgqkA6S0Nag+6jaM\nG6/4C6BPVSFrldLO1H/xlZwfEvNAg9oVD7h5KVmPAegaTWNTr2pl4XzmCMOYbe3K3te1Sjz+n20t\nxSDDnL6J6F7E5BNo0FOYAvwZxiIGpNM2DzToij+HvqZTDqZ6/FYFZShpV/JjoOXImqOYOw3iMHaX\nvqyqqaDtrOVuHkP19FspKwFPYAwMnunAWAV8J+Dh17OITikXrpeaZBaX1xJoEMRMH8CsoIkq6NTP\nMKqLj0CawlJ6p0HoyhqHjzLjMqxiwOI7/jb6urIqy74AXwv9lb5dOgjeeCy1lHYSxqeUagO5YI7M\npw0YiGx0B9VAtZV4mhobieLVTqHMSjDdw2RJ03r43xe0zrfY1Cir79ANorR0xKD4JPA8Imffiz2A\nyaAhGvQmzzBGgbSaBE8cDTLt/54y6+4j/jb6RHAaeRqBauANN+fTANyqZ5N2pr4J/ghqgQtuDQ2b\nFqwSX7SKdz2YJGFIBlNnOD1u9xDztPeHus0ibrrZXq5azh43I77w8HIs86aN8hsRiTRI2DwXy1GO\niLHhgPEMYxED0nn0ToOsAIxDmXX3AX+avqFFdtFkCA0aqVk9MUIpbb/2DRyiLwPrUu80CGJF8Mof\ndD2VVqyiNMrwvt6OXpXpN3MiJVK66/8VhQxHWrxlnVZU/W2RTljN/8mKb/24Nsg22H50KhcfRTOu\nNGMov4PgxQj9I+G6CdLblI4NsjTolDKrbQz+DPrqdSzJpZEaRAZ+Tx7KLRhplRskiAYx7V4sNF5u\nIfOeOBrkLbXL3BxphVcFXKCco0E3bRDr8ahb+tkMz22YYmdUiQZRtqkXo9KgmyB37aFOz2xQLGWc\n9Sv1F1KDyFk51iCY1gJUTIXF8UWx/KAtXqiwP/69TQ0+SQiBKWEzzdC71iA5KnhEzpUNwmefHhON\nQWCa5xxjEQPSAbDToN6cRoikjJad0V6LCw2SvVhLjkarEKCYlga1woe2LbsjUEjGIw3So3/hpZaG\n9641KK0nfVNW0dHSi3iGMbMnrXwFYCKSsooYn8HHvdAgOW4YUYPKzclFLiwNgmEdetIJArdPNMhY\ndYahcIirGi+Y1qBF9EHv2CCONkis8TrDWMSARNGtY2eD6m3AAaUiKavIk8alO+LrG+KvpxcT0kLv\nzICWzT1FMe0QebmUkznmsgQJP8FQnYh7H95jT7lTMWN3n+wEGHTR8n3TGtRLn+6w6pMLdi92DdNF\nOcA0nfDXzjAWMSB3+Je5XWu0EuqwY9JxlA1sKic2FB0M02dOf7tqXMUKHvVA/JXSFkNfU4RZXEMx\n63tRP7PSJ+ltI/puyh3rwkiLOjAuBUfDoPVIhzYNaqTxSWKD1ON2v2cooSi5QdB0hxghFCZqfARy\nB8Y5ba0QnnM5U4aU1qqdxKSOzcrOfCLm3p0pd/CaDd2WKwMQSlXTALNSZDDpuajzW3CtoNbZnQco\nC9Rm1dvqqes9xiIK5BkuvGY5HleFk13X0uoqScxFtJXOzZwSXZU7nV2PcvJWPl+uqoW40wS9brPU\nq4i1c9InKPRIg0KFO0JJH1/ZhoxHGIusILl/b0SoaI/L7dc5w6tEXJyscn38rLMbyYfwTLlPu+k4\nuZ6pgVkaI3oJPYjoOjJr0BHKagacMl4Oei26XQdjXpC4yu+NY1tPtz1ccFEZ453tUsYEbUT3Tbnv\nn9kYvqO+pt2nrDYoEKUfY5EXZKWHQrpdfpHaSyvF7H6HR29E9025322DXBqUFGUOkL/uNa6IESte\nr0qluG5sRPdNud99RI7NfIAhLcocIBczHHS31XKUr380NjQ3ovum3O/KlmMzHziHxqb+BChzgOx/\nRFgwIb9SaWMjun86OxixKJijg4AlmRQeo039KVDmAPnSUOyYnsqzGOS49PMrxkZ0/3T2zapzkAMj\nPBzniIBPCpQZQIIHcLOlchdvfuNKGxvR/VPud+VU5HiHbHcrU+VTo8wAsvxxAE81zcnv7bWoJ3Ud\nXzI2ovun3I9v9V+R5PBh2uIz/oJ3clOjzADypS/vnrUiC9g8cnZ/4DW9Ed0/5R5YzVZMkCNWJ2yZ\n0YnEKDOAbFVQPlrWZBU0v4kpGhvRvVPud+UhcnjqkW1ilOlBDp6VF3ebLnn5FPG9e6A8U+73KoDS\nRE53srIA1m6oD43crpxuSIDyCuR9jLv9q88kS33XlPpFDgHoTGeH3GSWIXKKemRiV72YPZtpGTT+\nAQdbf2jEvO9WOhalD2Qcxs+NxKg9f9ONmdQ5U+7mxbC0IGdZGK7THJjnv//THxoJq9EpFY/yEuRd\njK+87U7DOBm//w9j3OlsB9RVBpEzq5l6tdzLvEtv8jdzb6TjUV6CvIvxi/+tBraoXK59o3HfL4rk\nNDq4JpbQ6R4C1qHdZSeDTD6QMRiHNxyOkHaZThzSkPvfKIOrvXH7ujw8izA/oEGXIG9i7Lc17kru\nr/xGf935HUF43eI3a/FwNcj40Igo8tLfM5A3Mfo/a/iSXPZjrQ//2pe+fTbBRm5aw+hq0HeAJwNJ\nCwe+I5eFhL52Z+X8KycN7jjpYBNcwsmN5LKnATnrTjs5wvgK5Yd74iv6cQ0TLsT/+pEG5Lbh6aPi\nyq9ufRTdHyzYg7aFLr7ZGlxuDv0muj9UhfF/83yoNf4PrtJeNRRCo24AAAAASUVORK5CYII=\n", "prompt_number": 13, "text": [ "\u239b 2\u22c5g(r) \u239b d \u239e\u2502 \u239b d \u239e\u2502 \u239e -2\u22c5g(r) 2 \n", "\u239c\u212f - r\u22c5\u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 + r\u22c5\u239c\u2500\u2500\u2500(g(\u03be\u2081))\u239f\u2502 - 1\u239f\u22c5\u212f \u22c5sin (\u03b8)\n", "\u239d \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r \u23a0 " ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The off-diagonal components are zero." ] }, { "cell_type": "code", "collapsed": false, "input": [ "all(ricci[i][j]==0 for i in range(4) for j in range(4) if i!=j)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 14, "text": [ "True" ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "For completeness we can also check out the Christoffel symbol of 2nd kind. We will print only the non-zero components, and only one of the symmetric components (symmetric in the last two indices)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "ch_2nd = metric_to_Christoffel_2nd(metric)\n", "filt = [((i,j,k), simplify(ch_2nd[i][j][k]))\n", " for i in range(4) for j in range(4) for k in range(j,4)\n", " if ch_2nd[i][j][k]!=0]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "filt[0:3]" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left [ \\left ( \\left ( 0, \\quad 0, \\quad 1\\right ), \\quad \\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }}\\right ), \\quad \\left ( \\left ( 1, \\quad 0, \\quad 0\\right ), \\quad e^{2 f{\\left (\\boldsymbol{\\mathrm{r}} \\right )} - 2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} \\left. \\frac{d}{d \\xi_{1}} f{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }}\\right ), \\quad \\left ( \\left ( 1, \\quad 1, \\quad 1\\right ), \\quad \\left. \\frac{d}{d \\xi_{1}} g{\\left (\\xi_{1} \\right )} \\right|_{\\substack{ \\xi_{1}=\\boldsymbol{\\mathrm{r}} }}\\right )\\right ]$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAABD4AAAA/CAMAAAA/mvhRAAAAOVBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACXHtMAAAAEnRSTlMARM1U\nEHbdIu8yibtmq5nz+73gcdcAAAAACXBIWXMAAA7EAAAOxAGVKw4bAAASHElEQVR4Ae1d24LCqg5F\nrVar9Zzt/3/sDpcUQmlJgLrtaB9mbEuArAUphJs6vPR1VOQ6n8ntt98cnlUI/NCsgq9UuJI19aMt\nQD4G827MxkkdXie4DkFIpU4Xcvu7udeY0x+a/1EBqmLtVwkoaxGYB201Xtp80GBw119vs2ff/aC7\nUvsqQeOHpgStlmFrWPtVgoiJFJjXpPm41Hxro1T/yO3h2pdq8kOzFLlquQrW1I+2CP4EmEnzMUSO\nkCia77x9loLyQ/M/LDDFrKkfbTPa5mCmzEf/Km+oz5L8Mw866OeVXD80S1BrJVPKmvrRNqdgDmbK\nfNzvc8k/+UTm4BmuRSB8DZpF6JQIiWgrZE19C211YCbMx+klirKkAHyIjMwedK8Sj9D3oPk2UkW0\nlbGmvoa2OjAT5uNY2sl/W/lplZAIOqWGVydP+XvQlGNTKCGjrYg19TW01YE5Nx+316OQ1neLHe7X\nutlcMuigOyxHZj9ovou9ataUjLYS1tR+aKuFsw7MufkY59NA3lWyxOkUejMxHRl0quSTtCc0EZat\n/1eyJjQfJaypPdFWB6ewDkStspn56F7j1sWnWfyHkt5EkLoQOnV+Sed+7AnNAJhNf9ayJjUfctbU\nnmirhFNYByIwZ+bjsaNR26Fyar0QOihVg7Bi7QlNoWrFwWtZk5oPOWtqT7RVwimsAxGYM/Nx31Hf\n5Vjn+pCWQ+i9CMFWe0Kz2B4IBWtZE9MmZm1XtFXCKS3RFMyZ+YiX3grLxruC9+NwvtX1+pS4HMLY\ni3BMeydo7oo1MW1i1tROaGtRCaTmg4IZm4+DuH3+rqJH0jHT7++Vrg9xOYTZALKpHztBk0C74U0b\n1sS0SVmDRaTSTuqGoC1H3QROqfmgYMbmY9iF66O76iHU+RT8ZaiTb6TQgfNDNiF3H2jOsOm9h5g7\nUZ8j0og1sfmQsgaNzD2s2mgDp7QOUDBj83Gs/aLPyuIWD54ml5fab4QUOujuyET2gObwvD/ddLju\nOejWVRfgektNdQlEHLtZER2uEWti8yFlTe2BtlZwygo0sEiqQGw+XpWDGa44bfzvqhsBXfU34n/i\nbI6yodsdoDlAS2N084yH86Atxz2cXDvMvT2hiEMwJ2KCNWJNiWkTsqZ2QBsA2gbOOjAj89ELW+eu\n9Lz5nx09OsEYUVjQ5Zn4v1hkEE083QOaFzAfN2cUj6bNfiD+nW7eXQtFLIJZER2sFWtKTJuMNZhd\nPNdZXFI2F2gEZx2Ykfk4vSrHQjdHTSdgFw7fj+rkO+klCYsbbjAhIGjYZ5PcA5p6FzVcnG47rncK\n6n3W/AhFLAZZER2sFWvyzouMNXCQf1ElENcBAmZkPs7CoYVsDdomwBE+kI/LqCR1OZETMXTgk5fM\nyd0JmlBfdCvucX89tafDdF9vr9dpvGpl0/sFO5HhfNZhtIiXWBBRjViTmw8ZazC5mLS/QLePvNrA\nKa4DBMzIfDyjxnnSc9YOzMfsy8aLuxvPw60fzxkHOea+I30cn6gYOvhOS5Yjx2gqzBBPS3Eor5lM\n1G3L9zC63ayGp9fxZkbGT0mDaUS06bjDl9qKTBIqLaKqWFNeOTFtMtbAxUv9xR/KGgtOzDutAs3A\njMzHnboje9MJ1A75J6eiswPC/E1bo0dOtLK6oLrn+Wna3zb3IP2gzfEpUXE5VOolkYnQVFOGnPbr\nirHR9AEnzdZjjt4Orq3+NP8PtuN/AwdAr82zu6cyRqTXLpM7DO3aIJNEWoRGMLvLsqYm5SQU2HRE\nrMGcU/JZkrGmE2TR68NNitnMtvw75T2qAq3AjMzHkY4sWByOUEI67S/LXeyA/TTjS/IxzyXv3o+D\n3j8eLmSxG6CxEjZAMFF5OVQvyZz+CE3MkNd+VSM2mkFA1Gw14ujlA3v6d/PRPdjWxg29PKZpcbrj\nZXC0Ig/dZ9H9HisySbjWSJRM5jbPmkLl5LSJWINxW1LWXTFisgaepKlwr6vsw6Fi6+FL3i5WgUZg\nRubjar1nLqdn41t4GLoYO8dyA3b354jp2CRKkFmSgfHcznw9MOrH63mmHXh8Iy+HigK0lAf3PAps\nkw21X5PnoqnCgKjZWsTRuwOQfDCNQHsWxQ1bH86x5MxJKOVEBjA0N42hFfHmIyESiqd+M1hTqJyc\ntoiIVAaCZzS0jDXFpTcMh4oFeWjzEyOeV4FGYEbmg5ppezbB3XyOrK9sVSt2QPDHofno5GVhNQ9w\nwhW2D9zJCnSWrRHGRAvSvtAv03peKJpqOuph0n5NnI1mGBA1W4uYvrsd4bQfM22js5x0dubPZAwe\nM/80imgXx6gLhxWZJNRchKaZuGOwplA5OW0i1qIWpow1rRqL3jAcKpbApe7RchVoBOaa+TjYgmQH\nG+Asupwq7IAhwrrl3fTCBcwu98lVsi5ReTlUooJIzQdmKNR+RXM2miSgGM6rOWtQ5wPzd9H9k/7y\nclu5jcQRoANOIs/zcDQdHi3iJdRcRIutXhzWVDFtItao+UBUmKxpJcXmAxVbRajgJeadrpJ1ETUB\nc818WJdaZ0fBD9nRLHZAgjD67QrQSYk8xutlNJ15jPhojSAJ7N4VmI+jZM0tNR+YIV75YqNJA/pE\niMLzmw7GXK2HGd+hD+RMxx3WO+b2OEKRCKYX/OexpoppE7FGzYcHlGsVCsyHTyQApfjnCag96S4o\nRpuqAvhSXgdCMKn56EiBt6603vrQfNN0SS12QIjAU2FHC5fiLHiOZs7mXs9HANeHqRGuVw9xukTl\n0IFbbfYxXswjRVNhhkLtF2VhiNh0GqSwc+E8aFd4H/RLjo9pAMA6P1zWTtSYBBnuod9ycsaFKRJI\nRz85rJXTJmENprdh91fnUcaa0coX7kjJ6NaH47IWRZC+HYCM3nzzMe+pKtAGzNh8hDXqYvoVheU4\nrRo+9ci1Pj66x+aBzT0gedfGGMzIc5zaIS7RUFnMWeZ/NKi3Grqj44WYoU3NBxPOHniHEe5g2BxA\nQmUOgcXojOML35D/tyO0X8xADHR8eCJEPrxhsYZnVstpk7AG5iNMQMaa0ckX7lDF+W8fjsnaPIrE\nE+ukNK4GzHuqCrQBc818WE+8256M03kxH7N8QNDZI3cLTX0CjeCR6aUv/nEBvQ/ONhNuvvx7klyi\n/wSRM39KCiIth8rCqdPx2i+nWgg7E87x+oAmmav7s0ycvFk5L4WJhJZFFgmbnC4QFYs1aEiaVOW0\nSViLzIeMNZM/Dr06oA/HZE0LZeE0K+nsKiaX92QVaANmbD7CyuxSt74PN5dCa7B0sQMWIreULnmO\nPjisrTjyDYFm5iP8ypBIlm8kBZG2gjFDELcvN8sJKTaaJCCzIFp360rqb37FYg1LvJw2CWtR5+XT\nzEeOGHvExNk0tF3ek1WgDZjUfFCvkWv7XEzH9oFDrcv5ZwcMKxB6h5ejlb2xw5ggY3Mfzp/25sMl\nKi+HIt8HRdNlSGvDMh9sNElAJpw4J0yG7XahWazh2JCcNpHvg9KGHQAma2x6STFgssbB/2FmFuil\nBOtVoA2Ya+bDeV7Ohi7G1l7sgCEVTb1GANkVu/A29+fAqefNR43r1Dfss2wSH5zUCcdGkwRkwnm1\nTlPEKqvJ1gFYrNV4+wSsUfOB7sewzGbQYH0dIA4fjslaJl3z2nYD7SyLtSrQBsw186FnFepLG+BO\nj9B1mQVj7IABcnahBaSSi9xkJfvH7yFkcx9uW+nNh0tU/hmDeR9TQcxnmJoPhHMqN5kI2GhOAQEd\nJpxnPWLS0YHbLLbbBeCxhsrJaQtYY5QzQpuUNQDJmYUMvVM4kGCyxiGg060Ptz/SWhXANOvAjMwH\nma+LTSo9RcCO6l3WezDcgM/x+rqM1llvt6jRwGQin2MXrSI0AfyhOS73w+uFAwzefLhE5dCRaWPZ\nDBM0sbWovPbrEXDRhM0FkR9Y5zONK69Hfn6eH8FoyRzczZ6Us4bKyWkj08bWgQG9CW1YCbissen1\nEfJZS5Ayg/MAC7ycK2mtCrQBMzIfFNr5MrkDWUyU0AYfcQP2QVlgykynesarCHXaetDbXS73/QC2\nyjQZJvOBiQZpo1Du/zX0LecyTNFU5XDmEppyjZrpB2yhSXrLH/WsKVROThthLQsMpa2ctWxCiDcq\npu+ZrK3CaXZR0JEtV4FGYEbm4+7b5pA6zkPUObEX+4PFDWj25pVGbnt2s4W0ep8JO4naROhzf7qY\n2U0nLHeYKN679Dn/SMM2pyRFswLOXEJTzlEz/YAtNElv+6OWNYXKyWkjrGWBobT5YoTwsIHlBkTF\ndAJcGbUAp/5QTn1Bn/e4CjQCMzIfT5spBCrahE51XOW4AbtgSjRXBrb80pMREqsIL3e33svm3+Ue\nAj/Ai9M/L6/R+AqnROXlsAt30c1mOEJTlcKZTQj5mjSDB2whFN74fy1ralJOTBthLQ9MRFspa/mE\nHOKTYhLWFuAcdN2YxrGwxM2qQCswI/MR7dM27TbiFOVaD7YNDalhR256domFtOpBV3G43PfgGdD2\nZrqmRMXlEAbLfecor2SEpt8uyGWFqzE3HJYWEz1baMJl2x+1rHnlxLQR1sS07aoSnEaoBGa2uGFz\nqQq0AjMyH6doQkC/bSFMeS/yhdic6plcRRjJpnPvExWXQ5gd6SexRoklbmM0VTpDCcmyR16zMvlN\npSpZC7aME9MmYw1IDtYCASYfyRoTzoW8+5JSB2ZkPm6i6rFpcUtG7k/1TK4iTMosPxRDB2NykqkS\nn47mMjJt37RlTb5Vsow1aGJKvhFtoeLE1hROcR0gYEbmIztWzVFvuzDBqZ7JVYTClMVH5MAuutO0\nD0ZaH44mQ4MmQRqzJj8mSsYaY2ZIE1hKI2kLp7gOEDAj8wHzGkq1eoNceKpnchWhMA/iI3Jgzroo\niY9GU6RJReDWrMmPiRKy9lWVQFwHCJix+SC2paLMbCIaHJKaXkUoTFXccJMeX/jRaArBKg7emjV5\n5yUcLuOo8dG0NYZTXAcImLH5OEVnXHDQfluY4FTP9CpCYU7E0EGPSZTER6Mp0qQicGvWxOZDyhr4\nTrcdMagAkxxt26ISSOsABTM2H/0Hu42CUz3TC2mltCB07MJyptNisul9MprZzDcK0Jy1yXxwaZOy\nBnt1fa7vtDWc0jpAwYzNh7pOW3I1Kj7togkOSU0vpJUm5aDrDg8/Ur4axyhzfcCn4nPRXFW04cvm\nrKH5YNMmZu2TaWsNp7QOUDBn5mOQnETQsJRxovKneqYX0nLiCMNY6E50lD8MEP++BpNk43fJ+09G\nM5nhDR62Zs2ZDz5tYtbUJ9PWGE5pHaBgzsyH29p0g2JUH2VwqmdyIa00BQNdxx+LZe3DSDLxyWiS\njG5405o1az74tMlZw32qNwSlPOrGcArrQATmzHyoFvOxysFhSyYW0rJlMaCB7rayCUFwaryWmc7G\nwwjy/3eCZl6RNiFasGbNxwpt9ax9USXI1YF1MOfm48H/GrcpUsWxzFYRSmMy0KnLfbAn4NqVMeMR\nL3DN+VPjddzCcRctsh80dW7fcVWz5jovlLa2rO2Itlo4U3WAD+bcfKhoxv87ilRJGvNVhOJYLHTP\n56C9H4dhOo7QR+RPjYdnRaZgJ2h6lbf91YA1Zz5WaKtn7XsqQbYOrIKZMB9mze+2hahF7LOFtPJI\nDXTjtAPSfGMYWP4Q+FWPUsepztFO0JSDVybRgDVrPtZoq2dtL7TVw5mtA6tgJsyHcvvolpWPPUlp\n6Ho/EcyaD99yg9VxIXaHsl7d16D5NuZTtLVm7WsqQR2YKfPBOJPhbUVl04T05CBzGKhNJdP6OJbN\nJfoaNDelKow8S1to9AtZg54q2SMmTP9P/a4DM2U+1CVosf8prBLKdJfr4Lovc/MRnBoPXtTC8vRN\naCYA3ubRGm1NWPumSlAOZtJ82CPutuH982J9HF928cDcfISZvXLnSIdC+vd3oRlrv9k9j7Zi1r6L\ntlIwk+ZDPb5rrnWvjze4nV/BLm+zUj8GuxTOXq4/+DI018Fo+JZBWwVrX1YJysBMmw81eodiQ74/\nNKqH3kk5c02HPGTCJV9/FZpJBLZ4yKCtirWvqgSFYBrzoU/tjgYlj8xFZFuUiw+Ms0/MCRFk84em\nAKx2QStZUz/aAi5iMO/aasAK9O6kr+l0MivRSTblCxL5oz/7aXJIkYI/NItgqxWqZE39aAsYiME8\nGLPR/wvQqqJqrheD7AAAAABJRU5ErkJggg==\n", "prompt_number": 16, "text": [ "\u23a1\u239b \u239b d \u239e\u2502 \u239e \u239b 2\u22c5f(r) - 2\u22c5g(r) \u239b d \u239e\u2502 \n", "\u23a2\u239c(0, 0, 1), \u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 \u239f, \u239c(1, 0, 0), \u212f \u22c5\u239c\u2500\u2500\u2500(f(\u03be\u2081))\u239f\u2502 \n", "\u23a3\u239d \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r\u23a0 \u239d \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=\n", "\n", " \u239e \u239b \u239b d \u239e\u2502 \u239e\u23a4\n", " \u239f, \u239c(1, 1, 1), \u239c\u2500\u2500\u2500(g(\u03be\u2081))\u239f\u2502 \u239f\u23a5\n", "r\u23a0 \u239d \u239dd\u03be\u2081 \u23a0\u2502\u03be\u2081=r\u23a0\u23a6" ] } ], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "filt[3:6]" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left [ \\left ( \\left ( 1, \\quad 2, \\quad 2\\right ), \\quad - e^{- 2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} \\boldsymbol{\\mathrm{r}}\\right ), \\quad \\left ( \\left ( 1, \\quad 3, \\quad 3\\right ), \\quad - e^{- 2 g{\\left (\\boldsymbol{\\mathrm{r}} \\right )}} \\sin^{2}{\\left (\\boldsymbol{\\mathrm{\\theta}} \\right )} \\boldsymbol{\\mathrm{r}}\\right ), \\quad \\left ( \\left ( 2, \\quad 1, \\quad 2\\right ), \\quad \\frac{1}{\\boldsymbol{\\mathrm{r}}}\\right )\\right ]$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAA0kAAAAyBAMAAAB7Wo3sAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMA74lUMhBmds1Eq5ki\n3bvZob9JAAAACXBIWXMAAA7EAAAOxAGVKw4bAAALL0lEQVR4Ae1cfYhcVxU/8/Fmd3ZnP6yfaYwZ\n80+rEbux/iGVZgeNbajgTvqH1EC7Q9FUqNBFsQlB2JFUUAR3WkSDWHcCba2CZASlkLTJRETQxmSt\n+IFNm/GjKiYmMd00Tdvkec659755775733y8584fzoF999zzdX/vnPfuu+++3YWN7kUYUhIZSNeS\niOLFcOqCTbvuNLx528c8xZCJk4HNcZwNvvuFzNn20Wl4i0E/FPWRgXS9D6col1xVarPDKkXlqSfd\nlnJP5tHGXyH1X6TNsErRyepB66zrwbiT6YlLZLFjRtgNq9QpX13rJxtdm3Y0vOcQVykzLSyHVeqY\nsW4NZpOc8Ea4SvBcqEq7uoWTnN3OiFADgBOBRqkiED+vbJJoZZVmmxysfS+NVJOI3luMvH3MQcDp\nArwdce6NLty7NpFVmhCzaLtKDyd5w3aLZq/VcCBwrGjaCiviiVbbKD4nq5QTE59XJWdtXpuO8wnM\nqNMYrShOa9cITqFJ43pwNBCmrhXxXM1k3q9MVsm5zAG8Ko01+g3Yjd/mM2U2c4rc3KZ8CuJaUd12\nuzZw4M4gHG/89JGfenyQsSL+cdAuZk9WCb7KcbwqzYk0xgxucU83x6qsmhSjpEvcw8MPFaO1awMH\nXuJh0yVtdHgfPKmLVN+G+HplkEirqrTYpHBelb6eSHBLkIlmVjxbvy0MnJYytFVjbeDkFxhHG46C\ndQrmmorXWgvi7CuaXbyuqtJJRqiqVEh0haIjTNUKV1h2Vmr+pixGRZ5UV7VrBGeyKQb04Kjx18HJ\nmuK11oJ4JNkEqiqlWjS8qtL4igYm4W7mEuRu2AsrkHVvwblhtwqfm1ZcoF0jOBM6nDYI3zvqbZ9p\niwEsiCfNJ+L37IVXVRJhVZVSCxQjW+klEsCnuzafWIC9cCZbBZh96HwZblGO8h5TXdWuDRzYrsNR\n4wP8gVlKyNjbDpRyJU9jQ9wSFt7CyHOIZHyB/XbjB64+wf0036KqSidLJDyBP6Nl4gL07JHQlACF\nw+dKMFYK2EV0NgNOYn/NtwDmWr8E+J5nep3H+ZlIOIVN75/xGxPPsl7hEIwAnOzbVdx0gzlMiLNU\nmq/CY0oBYEY8LxwKLQBTuqxp9QVuD9HmcvykUFV6gBW4XV7AK10jpw431TQZ7IQ0BqjqYr2/9RxS\nGXINyK3ApXwd01JEG7yIJT2pmEAbBQeehUzoUS1k1UAQQycIB76jwcleVD73CwYTMv46pC7BqFKA\nZfW3vMAWeI07pnRZ0+oL3B6izWUvE6+q9Ax1RorgnDkYqtJYGVLTpPfT4wBvAvi8XxTBPwLfTNez\n09mWTAumR9KiYgJtFBxYnIGrAWvsCFmPcOATITgybr6YLyGLCYHlN2BqlTmpMyOenWE1IjCly55W\nGiKCnNdJqar0InVSTTwshqqUWoGxVdL7aQPAwRLs8IvsfHbfzS9l6mN1Z0Wm5V7PdrbpsT4mCg48\nXHNe9dkyK2Q9woG7Q3Bk3O03b6U0UEIOVmH+CjjTUoNPMhSGabHEsneikyld1rT6AoeDouQ1kqoq\ncckeJUm4SqOXDFVaKlOVRmfIpSOlXPcCPHVjBX4HhdPr0fwHMOfe/uUF5OaMEaLgoFN4xhOyXuFM\nlBUccQqFbaKFja5LHCXELcIcPsL34XJwdQ89t8yIjzZRBfkVfLCb0mVP6z7ys9M1Uqkq8fS3mSTh\nKqFwwrSTc7oM8iFLfmG6c/fTAWGqBA9KQRXPedMyBZ2vBGxkpwOc0UbYiWS9whmRg1cxXPYLu6sn\nXoPt62/fu6CiY0Jybg0WLwAgO3fxPW7ZhlhUSQIwpMuaVk66GjDcvoNEskoOP47/ThJjuOUiqYKU\nx0dtrhqU+Xv5U/AzX/9X8CGASSHIVACWVo6tYG/KS4lQ8bEDnI8877OVLMt6hQMt9s5UsLkH8G3u\nXwDfWGi/UmNCxlwkBPpZvEmuFjagoRExiMf5JEXCZ1mRG//BmlYMHEU0oqpSgav0W5IYw71IGo0m\nWjjNUKItdGzG+YlPtX03bmDmKyzZicelBrNTRW6Ch05w0oYNfJL1Cge+xeMSHMBPJUWq0p8BOBkk\nw4SMvnr8uFsEuBVZnofBiBgOkj1MzHBjSJc1rRg4in5DSnkvZV+mzjo6mMKNt0ij0RHsZy9oQuze\n9QLRQ3DgvgfLIe0HWfJFPC4tMDvVCNlg2Gg4uLwMRyZZz3AyJRqd4MDEtS8BVemfADzfkgwTkrqI\nk3MJpzuskpAbEcsqpWrkZkqXNa0YOERTdAPzkxECVeLLx1qlvaE4uEqto9CUFmXLqxPVCbeRVYqE\ncxzg/IwWUMhiwAHnRrdBVToXrNLUy5CmFWWnKh3l60ZUyZQuU5XYzlQl38m9QLy8l6KnmEwDMAsa\nfRgKTV7TaHKvi4+tKFJVKhqMouG4ZThf0byEjJZYNuoAB88Q3/O1KuGMl1qF1BWM+Wj7Xiqahrip\nSVKe8YzpMlRJ2GHgKNpASrV64JvZtnr4OADOBkHKNmCkGbl6uA7vt6BPoKeqVAlIRUd8orTBeRfA\n6abmJWRRq4cOcOADAE/oVUIEk6uw2MDBaPUgZ7yKNjZ3F0vU8OrBlC7Tg0TYdVg9+Nd4wFfae2kg\nLLr20lh4btOhFU0Gv960+Uc4A9MJzFfJL0R7wAmuxIMWskonZ1CsB4+EA7sgc1kflGVx4MCWMpyl\n6c4/42FCshfzPHUf9qpkRvxAjU4vXcc9NlO6bGkFwMDh86dYgq5RI+8luJ46dPMd2vinCpwuU1fR\nKK9FgzJYct2rCJywGd4OyHXkqV0qgqGdc90Sief47LTgkXAgf/hITR+UZTHgADxy3721O9zH73Af\n2/qfOiFDooTs/2OF2K/hIsJdJc6MeJbPg99qTemyphUDI+nnTzKm4A4Rrmww3U3W4IJZMbJPjUkG\nx9jguz6zXtlZviD04J3hgGnQ+HCC8L2EQGHa05gRy93WU8pMPyOSm2QisEnDkYK7re8mWa7BGmRk\n629MMriBLSp+ux55Hjg0YGc4YBo0Ppwgei8hkF7wNGbE8svF/crMlC6TTAQ2aThSht9J1IwnLpCz\ncoxPqrF8rUnmVMnAqdCxT8JVFZIevDMc06AJwNHOQiUE7morzIhTVbaYbEpD/YxIbJKJwCYNBwp+\nBZyvkPAEa8B4nbKB1KtGYLJeCMosqn2FlRXNpDMc06AJwNFwqITgwsIjM+LJC2xQaEm7imz9jUkm\nAps07DnGYdW9NFknYaFCx+7pc92bWizl7xbp2kHB0XGohOSansaCWP2iwi88w66YXNNkprbf8XWt\nRXpVpdy0yfp/L0tXjWMMCo4RTFBoQSw2tYKm/ffk9jvASX4eqio5/JTqP2y/nqmK0XNQcIxggkIL\nYvHyEDTtvye33/HttUlBVJVgT/8h43husTgPCI4FjV9sQ3zUbxSXl9vvAP/mSF6V8BPdIOj3lkEH\nBMeCxi+2IV6u+a1i8nIzSm38elWK2gKLOWSEu3VUqyIi2JqorMDknxolA0JVSf/LGPhHMvF7i3Ks\nabMfCBwbGJ/cilgm1Gcag1VVGq1zEO9egrtLMaL26ergpwELDQKOBYpfHIF4vd8uJq+qtNzkQO0q\nFbwtqJgj9ODOG/1m+0HAMSMJSCMQi/2SgHXfHVWlMyJCu0rw875j9u34qQjPAcCJQKNUEYhNv9ik\n3Hps1fZ75q3C0VelHiMNzbUMFPi7hiaM190h143DKsXLo9/7Vn8nEV5OeO232kSi/n8HGa8nfP65\nlgyI99LwP68lldzvJxVIxtkvWv7Pa8P/YphUcseT3H7A73b4dy1E9F8M/wsWBQw0hqNbYgAAAABJ\nRU5ErkJggg==\n", "prompt_number": 17, "text": [ "\u23a1\u239b -2\u22c5g(r) \u239e \u239b -2\u22c5g(r) 2 \u239e \u239b 1\u239e\u23a4\n", "\u23a2\u239d(1, 2, 2), -\u212f \u22c5r\u23a0, \u239d(1, 3, 3), -\u212f \u22c5sin (\u03b8)\u22c5r\u23a0, \u239c(2, 1, 2), \u2500\u239f\u23a5\n", "\u23a3 \u239d r\u23a0\u23a6" ] } ], "prompt_number": 17 }, { "cell_type": "code", "collapsed": false, "input": [ "filt[6:9]" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left [ \\left ( \\left ( 2, \\quad 3, \\quad 3\\right ), \\quad - \\frac{1}{2} \\sin{\\left (2 \\boldsymbol{\\mathrm{\\theta}} \\right )}\\right ), \\quad \\left ( \\left ( 3, \\quad 1, \\quad 3\\right ), \\quad \\frac{1}{\\boldsymbol{\\mathrm{r}}}\\right ), \\quad \\left ( \\left ( 3, \\quad 2, \\quad 3\\right ), \\quad \\frac{1}{\\tan{\\left (\\boldsymbol{\\mathrm{\\theta}} \\right )}}\\right )\\right ]$$" ], "metadata": {}, "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAwkAAAAyBAMAAADl4IpMAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMA74lUMhBEmau73WYi\nds1/9lIHAAAACXBIWXMAAA7EAAAOxAGVKw4bAAALJklEQVR4AcVcbYhcVxl+53Pna2e2NGmrFnfc\nH01VSqa/REF2tK0VQpxpERoRu+MvQcRdQUzin51IRVHKblEsResO+iNGQrM/KlZa3WkRSnQhQ34F\ntO4Uqf1Q2ZjsJmFNMr7nPefce8+559y5c3NzPT/uPe/HOc9zzzP3653ZhdnRJaCW7vD9/2F7JBjz\nvuDwpNFk0ezsBI/0aDQDdz78CE88YM+/3ZH8MAghvRQUnTyWLJqdn+CRe/ihGdgn0tJde/5tj/wh\nCOH+oGCUWLJodoaSR9ZV4cG2PT1qpBp2zmLdDpHZb49NHHmLjUgMTaFH0IpH8nBVyN2lJMRiVNbC\nqpC70w74WMcemzRydpeNSApNYcehFZfk4apQjPniyw722ZWwKsCDCj3FeFaxbsn4wjFSISE0haqE\nVpziqF0V5kMvmDJPsLEVetJS3TZThi+cLTyZf5pPlhCawk1AKz7Bw1XhpBKOyQivQua6DbIU50kq\nliIhNOWQTCoIHo4KZesqKFNNaIRXAayfgo3+hKBB6XIpkkFTmEhoxcl5OCqUVpVoTMYEKmzYLl6n\nYuJC08ilSAZNYS6hFSfn4ajQ6ijRmIwJVFgYmDGzV8z+aF65FMmgKRwltOLkPBwVvqEE4zImUKE6\nNINOzZj90bxyKZJBUzhKaMXJeTgq3KME4zImUGHacmNKdeMiw+aRS5EMmsJcQqtOOmqpQva/SjAu\nYwIVKjfMoK11sz+aVy5FMmgKRwmtODkPqYLts6EMmdyYQAV4n3n6rb7ZH83rLEUiaApHB1rxEg+p\nQjHWq6+DM1aFQ79xcp9xekrH4lZywhvOUlimtbjDA9gzHWglhQClCqlVHjukpIw1ys3AlGOzvzJe\nTxyUwgdONOUcB/vGucSHNmucyDiCnC8aQ1Mn9n7IA0mgKRRcaMVNPKQKC0sUq6xC5ehzTSUPjcrc\nhxu6D16b+xHAUz63zfGpgRNBFHj9+I+x0LTdXBjKOTY6ToKnk7vKjbPAAT0h3vVXKoltoenLVByR\n0KxrMw5NgVYM4iFVWORrhJXoI5D2PaG/Dhnf3buyBPPrUFWmDDJadSeKKLkuHOzA1FVI7co5Wq5M\nTiZAXty03wIO6AlR11Cp5GyHeqZqR0Kzr80YNBXbaxEPqcJ8g0LnAb4LcIc3jfW3GrCn+6YvQ60H\n03XdH8JGlEIbUjOweB1qO3IOcTpq4zOXyYE4HFALmyqVnC2CBLVIaPa1GYNmZ0I8pApbTUq8F+D9\nACvccId+uZO76Vq8l78L8GqSm9H9IWxESfWgsAMrQ1i4IueodU1Dp3fIm+oDB9RzDPc8zvYxPVO1\nI6HZ12YMmorttYiHVGG5z0L5HsB2268CGK5ImI5XJPg7Gxem/bEpsxhKdZepMKpD67qco7YqE7z7\nKYxj+yptGaDWDCpwttWGlqmakdDsazMGTcX2WsRDVUF8zX6m7c2jfnXJ5wJ4G30HDH6f6/An/1ZZ\n62bf/OYbT2NMoJR2y6MObF2Uc6SGvnHoECpwGAaoNaMKjK1A0dIdMxoagGVtxqA5sL4O8ZAqrNDC\nF9dZVv6SL/fTJ30uyH4EjxXkF9j+uOvJrUIJil2oPg/n+vitL6HAYr0wwtaTc+BFytAK/GuZn2KI\nA2o5JhWIbXmoZapmNDTr2oxBU7G9FvFwVKBIqcF2piJ3Wv5SwzvDh5oAn/A6LP38fkgzFYozUEMF\nOAqcgurNzU28KIk5SjOm4YWL5P0lbRmg1kwqAGOb6WmZqhkNzbo2Y9BUbK9FPFQVUh2WcNybJft3\ntGXP3af2A7RcU/Zy7/0a2wtNYB/1EVvFM8/3SYUh1AZ4Z+6wzKlVSF2C7Kgp5whcF/7TBAaoNaMK\ngGyzXD4lvUaMyBUNzbo2JjR+/ARp3Lg8pArLtMi0PtNdhTkzNgHWGpq3gguLT5EGFbRENB/fvkoq\nrHpUuABQuwxp9uzF5yj1/ANRLH5FQhUEoJZkUIGzNa6LOzgiWtedQfRCoflGOQ7iIVWgF2l+rfgY\nO161jdqwtq66oLYLRXyV4w8vWkwzcb6NDrsicRXoipRZgs3UDqTYGyKfw3ylTvNnJLwiCUBtboMK\nnG2+p2WqZjQ069qMQVOxvZZyX+DvC+y+mV2C6b43D/tYyzmj+7DyVMIVCnN3ztShsO6qQHfnRwH+\nWtyBrSWcns9hfmoR7wt4dxaAGjWDCpxteahlqmYkNPvajEFTsb0W8ZDnwkaHhdJdgD/NHfgBex/z\ntpchc0P3lddhfgBwFPP8r3TewXij3A/FPp4I4lxgKJVfzB3rZS/lr7FMNgd+1lfZVkOGMi+n3A9A\ngD4opoI2htjCFNNXizAA0SKhWddmHJpEpX325bZrEw+pwnyHBdh5tT0a7UGJX42Zj7X80eMd3Qdf\nOfoTDP2Dxc94pmW21vIf/ct92ZVrn1+59tDaPRyliverHnz9hXWWSnMAryloyJDhKrCLFgFqUFSp\n1MYQW6h2cIgWQY9skdCsazMOTaLCIeydeGkfvCg9SgVjcUDu0zL4Ndnx7E2+ygxLyPdxY2hUOPX7\nHRQe4nNAi1PQUEQ1r9QX0+RlR9i008aQ71VrhALJohEkblg1+ckdPKELTeEiHvJc4B8N+K1MX5cd\nz97kS9PSlT1Zni4vnHocouugcJvPAaKgqKGIynZ5SYw1QmljKPUB2poiFEgELS9IO7tqG2B5CWbb\nMBQ+4iFVSHFvsc+DOQN7kw+epPwv8lH6tkCFU90LeJNQfHwO4I9pPpQP8tyfiSEmKN8YzM0N2QBT\nhPkhGbQnOJa7xdJrftQHfEmSRVg6aqlC8SKlsjOGNdMnzuQDvjgGzdgs+BSGJTt/kygiIhZ4hUwf\nyhrPOiuSTVC+MZjLlTZF+ESJoGknPcC9WNO/CblRB2QRlnhIFeQD35/FwYbclftBibxwashQUOQc\n+IBpaltt8lZMy2/KF75XjLHW6PCbA4okgZa5qpFgTz81VjDogyzCEg+pQpZ/maKNunXT/pCiz239\nbUpDz7wFOzuaW6THv0TQXtr7fgN+f34An7v78AUmPqu8blyB6ZFT8lV/CQP4BHk72mI97Ky23+LE\n+6uw7d6rPcYoGTSsRGdOwzGAdweV64jK3ldX8Bl9D6/5Q0ZD8JDnAiyTM/bNqdAzFnvm1KmLZn80\n7zZ+GllLBo2psA8W2/AMAFZ7qEK0/a/Nc/jVQabHaAgejgqLHfLGvMHCadhWG5gz8/y1zRyc2Lst\nUJJBQxUge365Dz8HuIF9Vi2drUMLH1lEsZHzcFQoiQ/JxMcVOOBCYFQJbrQV0zXYocTWpArJoCH1\n3Lv9VhOec1UYNeDg0FGB83BUKKs1i3gOO4OF07AzvWNLtC6YbUCQX6qQDNpJGFR70HqkLVQoNfBc\naMJsh5dxkCjn4agAdweRjxh7FAunIYfm2d3L2FJxnqVChYTQ3oH6Qh3mP9MUKrC781pzmj3Alofs\nYAUPV4V52xWBZUdrVDgNObRoXetY/7pQqJAQ2rehjvX4g4fkuZDu4lda9UXc8iIsCB6uClXrMoRc\nR38aL5z6/SZPwN+8v23Kj+ZrjbB4gC0ZNCh8p1/53htf+vdnR099/D9dfhnKv/dPxqDaYVvBw1Wh\nYqo1sMxEWtDfvJ9rxk0hWTQP+9NOn0q+koerQqhfUziTxN2xXyKcR+sYIZNF8xB3C0sPMK/k4VFh\nqutJT7r7uyBAfPmMtyWL5uHOa4zo4CVfyQNVcP4zz9Oe9IS7+WEQYGEQFJ08liyal59TTSY5BA/6\nzzzOf6ma6ngHJNo/EvyA9q14ySSLpnCX1eRXmFfwYP+l6n8DOVW+o5MeMAAAAABJRU5ErkJggg==\n", "prompt_number": 18, "text": [ "\u23a1\u239b -sin(2\u22c5\u03b8) \u239e \u239b 1\u239e \u239b 1 \u239e\u23a4\n", "\u23a2\u239c(2, 3, 3), \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u239f, \u239c(3, 1, 3), \u2500\u239f, \u239c(3, 2, 3), \u2500\u2500\u2500\u2500\u2500\u2500\u239f\u23a5\n", "\u23a3\u239d 2 \u23a0 \u239d r\u23a0 \u239d tan(\u03b8)\u23a0\u23a6" ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also confirm that the Christoffel symbol is symmetric." ] }, { "cell_type": "code", "collapsed": false, "input": [ "all([ch_2nd[k][i][j] == ch_2nd[k][j][i] for k in range(4) for i in range(4) for j in range(4)])" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 19, "text": [ "True" ] } ], "prompt_number": 19 } ], "metadata": {} } ] }sympy-sympy-1.9/examples/intermediate/trees.py000077500000000000000000000013151412543434000217120ustar00rootroot00000000000000#!/usr/bin/env python """ Calculates the Sloane's A000055 integer sequence, i.e. the "Number of trees with n unlabeled nodes." You can also google for "The On-Line Encyclopedia of Integer Sequences" and paste in the sequence returned by this script: 1, 1, 1, 1, 2, 3, 6, 11, 23, 47, 106 and it will show you the A000055 """ from sympy import Symbol, Poly def T(x): return x + x**2 + 2*x**3 + 4*x**4 + 9*x**5 + 20*x**6 + 48 * x**7 + \ 115*x**8 + 286*x**9 + 719*x**10 def A(x): return 1 + T(x) - T(x)**2/2 + T(x**2)/2 def main(): x = Symbol("x") s = Poly(A(x), x) num = list(reversed(s.coeffs()))[:11] print(s.as_expr()) print(num) if __name__ == "__main__": main() sympy-sympy-1.9/examples/intermediate/vandermonde.py000077500000000000000000000110361412543434000230730ustar00rootroot00000000000000#!/usr/bin/env python """Vandermonde matrix example Demonstrates matrix computations using the Vandermonde matrix. * https://en.wikipedia.org/wiki/Vandermonde_matrix """ from sympy import Matrix, pprint, Rational, symbols, Symbol, zeros def symbol_gen(sym_str): """Symbol generator Generates sym_str_n where n is the number of times the generator has been called. """ n = 0 while True: yield Symbol("%s_%d" % (sym_str, n)) n += 1 def comb_w_rep(n, k): """Combinations with repetition Returns the list of k combinations with repetition from n objects. """ if k == 0: return [[]] combs = [[i] for i in range(n)] for i in range(k - 1): curr = [] for p in combs: for m in range(p[-1], n): curr.append(p + [m]) combs = curr return combs def vandermonde(order, dim=1, syms='a b c d'): """Computes a Vandermonde matrix of given order and dimension. Define syms to give beginning strings for temporary variables. Returns the Matrix, the temporary variables, and the terms for the polynomials. """ syms = syms.split() n = len(syms) if n < dim: new_syms = [] for i in range(dim - n): j, rem = divmod(i, n) new_syms.append(syms[rem] + str(j)) syms.extend(new_syms) terms = [] for i in range(order + 1): terms.extend(comb_w_rep(dim, i)) rank = len(terms) V = zeros(rank) generators = [symbol_gen(syms[i]) for i in range(dim)] all_syms = [] for i in range(rank): row_syms = [next(g) for g in generators] all_syms.append(row_syms) for j, term in enumerate(terms): v_entry = 1 for k in term: v_entry *= row_syms[k] V[i*rank + j] = v_entry return V, all_syms, terms def gen_poly(points, order, syms): """Generates a polynomial using a Vandermonde system""" num_pts = len(points) if num_pts == 0: raise ValueError("Must provide points") dim = len(points[0]) - 1 if dim > len(syms): raise ValueError("Must provide at least %d symbols for the polynomial" % dim) V, tmp_syms, terms = vandermonde(order, dim) if num_pts < V.shape[0]: raise ValueError( "Must provide %d points for order %d, dimension " "%d polynomial, given %d points" % (V.shape[0], order, dim, num_pts)) elif num_pts > V.shape[0]: print("gen_poly given %d points but only requires %d, "\ "continuing using the first %d points" % \ (num_pts, V.shape[0], V.shape[0])) num_pts = V.shape[0] subs_dict = {} for j in range(dim): for i in range(num_pts): subs_dict[tmp_syms[i][j]] = points[i][j] V_pts = V.subs(subs_dict) V_inv = V_pts.inv() coeffs = V_inv.multiply(Matrix([points[i][-1] for i in range(num_pts)])) f = 0 for j, term in enumerate(terms): t = 1 for k in term: t *= syms[k] f += coeffs[j]*t return f def main(): order = 2 V, tmp_syms, _ = vandermonde(order) print("Vandermonde matrix of order 2 in 1 dimension") pprint(V) print('-'*79) print(r"Computing the determinant and comparing to \sum_{0 : \", polygon_integrate(facet, 0, facets, vertices, 1, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### distance_to_side(point, line_seg)\n", "\n", " Helper function to compute the distance between given 3D point and\n", " a line segment.\n", "\n", " Parameters\n", " -----------------\n", " point : 3D Point\n", " line_seg : Line Segment\n", " \n", "#### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "point = (0, 0, 0)\n", "distance_to_side(point, [(0, 0, 1), (0, 1, 0)])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### lineseg_integrate(polygon, index, line_seg, expr, degree)\n", " Helper function to compute the line integral of `expr` over `line_seg`\n", "\n", " Parameters\n", " -------------\n", " polygon : Face of a 3-Polytope\n", " index : index of line_seg in polygon\n", " line_seg : Line Segment\n", "#### Examples :" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "polygon = [(0, 5, 0), (5, 5, 0), (5, 5, 5), (0, 5, 5)]\n", "line_seg = [(0, 5, 0), (5, 5, 0)]\n", "print(lineseg_integrate(polygon, 0, line_seg, 1, 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### main_integrate(expr, facets, hp_params, max_degree=None)\n", "\n", " Function to translate the problem of integrating univariate/bivariate\n", " polynomials over a 2-Polytope to integrating over its boundary facets.\n", " This is done using Generalized Stokes's Theorem and Euler's Theorem.\n", "\n", " Parameters\n", " --------------------\n", " expr : The input polynomial\n", " facets : Facets(Line Segments) of the 2-Polytope\n", " hp_params : Hyperplane Parameters of the facets\n", "\n", " Optional Parameters:\n", " --------------------\n", " max_degree : The maximum degree of any monomial of the input polynomial.\n", " \n", "#### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "triangle = Polygon(Point(0, 3), Point(5, 3), Point(1, 1))\n", "facets = triangle.sides\n", "hp_params = hyperplane_parameters(triangle)\n", "print(main_integrate(x**2 + y**2, facets, hp_params))\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### integration_reduction(facets, index, a, b, expr, dims, degree)\n", " This is a helper function for polytope_integrate. It relates the result of the integral of a polynomial over a\n", " d-dimensional entity to the result of the same integral of that polynomial over the (d - 1)-dimensional \n", " facet[index].\n", " \n", " For the 2D case, surface integral --> line integrals --> evaluation of polynomial at vertices of line segments\n", " For the 3D case, volume integral --> 2D use case\n", " \n", " The only minor limitation is that some lines of code are 2D specific, but that can be easily changed. Note that\n", " this function is a helper one and works for a facet which bounds the polytope(i.e. the intersection point with the\n", " other facets is required), not for an independent line.\n", " \n", " Parameters\n", " ------------------\n", " facets : List of facets that decide the region enclose by 2-Polytope.\n", " index : The index of the facet with respect to which the integral is supposed to be found.\n", " a, b : Hyperplane parameters corresponding to facets.\n", " expr : Uni/Bi-variate Polynomial\n", " dims : List of symbols denoting axes\n", " degree : Degree of the homogeneous polynoimal(expr)\n", " \n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "facets = [Segment2D(Point(0, 0), Point(1, 1)), Segment2D(Point(1, 1), Point(1, 0)), Segment2D(Point(0, 0), Point(1, 0))]\n", "print(integration_reduction(facets, 0, (0, 1), 0, 1, [x, y], 0))\n", "print(integration_reduction(facets, 1, (0, 1), 0, 1, [x, y], 0))\n", "print(integration_reduction(facets, 2, (0, 1), 0, 1, [x, y], 0))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### hyperplane_parameters(poly) :\n", " poly : 2-Polytope\n", " \n", " Returns the list of hyperplane parameters for facets of the polygon.\n", " \n", " Limitation : 2D specific.\n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "triangle = Polygon(Point(0,0), Point(1,1), Point(1,0))\n", "hyperplane_parameters(triangle)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### best_origin(a, b, lineseg, expr) :\n", " a, b : Line parameters of the line-segment\n", " expr : Uni/Bi-variate polynomial\n", " \n", " Returns a point on the lineseg whose vector inner product with the divergence of expr yields an expression with \n", " the least maximum total power. This is for reducing the number of computations in the integration reduction call.\n", " \n", " Limitation : 2D specific.\n", " \n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(\"Best origin for x**3*y on x + y = 3 : \", best_origin((1,1), 3, Segment2D(Point(0, 3), Point(3, 0)), x**3*y))\n", "print(\"Best origin for x*y**3 on x + y = 3 : \",best_origin((1,1), 3, Segment2D(Point(0, 3), Point(3, 0)), x*y**3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### decompose(expr, separate=False) :\n", " expr : Uni/Bi-variate polynomial.\n", " separate(default : False) : If separate is True then return list of constituting monomials.\n", " \n", " Returns a dictionary of the terms having same total power. This is done to get homogeneous polynomials of\n", " different degrees from the expression.\n", " \n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(decompose(1 + x + x**2 + x*y))\n", "print(decompose(x**2 + x + y + 1 + x**3 + x**2*y + y**4 + x**3*y + y**2*x**2))\n", "print(decompose(x**2 + x + y + 1 + x**3 + x**2*y + y**4 + x**3*y + y**2*x**2, 1))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### norm(expr) :\n", " \n", " point : Tuple/SymPy Point object/Dictionary\n", " \n", " Returns Euclidean norm of the point object.\n", "\n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(norm((1, 2)))\n", "print(norm(Point(1, 2)))\n", "print(norm({x: 3, y: 3, z: 1}))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### intersection(lineseg_1, lineseg_2) :\n", " \n", " lineseg_1, lineseg_2 : The input line segments whose intersection is to be found.\n", " \n", " Returns intersection point of two lines of which lineseg_1, lineseg_2 are part of. This function is\n", " called for adjacent line segments so the intersection point is always present with line segment boundaries.\n", "\n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print(intersection(Segment2D(Point(0, 0), Point(2, 2)), Segment2D(Point(1, 0), Point(0, 1))))\n", "print(intersection(Segment2D(Point(2, 0), Point(2, 2)), Segment2D(Point(0, 0), Point(4, 4))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### is_vertex(ent) :\n", " \n", " ent : Geometrical entity to denote a vertex.\n", " \n", " Returns True if ent is a vertex. Currently tuples of length 2 or 3 and SymPy Point object are supported.\n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [ "print(is_vertex(Point(2, 8)))\n", "print(is_vertex(Point(2, 8, 1)))\n", "print(is_vertex((1, 1)))\n", "print(is_vertex([2, 9]))\n", "print(is_vertex(Polygon(Point(0, 0), Point(1, 1), Point(1, 0))))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### plot_polytope(poly) :\n", " \n", " poly : 2-Polytope\n", " \n", " Plots the 2-Polytope. Currently just defers it to plotting module in SymPy which in turn uses matplotlib.\n", " \n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hexagon = Polygon(Point(0, 0), Point(-sqrt(3) / 2, 0.5),\n", " Point(-sqrt(3) / 2, 3 / 2), Point(0, 2),\n", " Point(sqrt(3) / 2, 3 / 2), Point(sqrt(3) / 2, 0.5))\n", "plot_polytope(hexagon)\n", "\n", "twist = Polygon(Point(-1, 1), Point(0, 0), Point(1, 1), Point(1, -1),\n", " Point(0, 0), Point(-1, -1))\n", "plot_polytope(twist)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### plot_polynomial(expr) :\n", " \n", " expr : The uni/bi-variate polynomial to plot\n", " \n", " Plots the polynomial. Currently just defers it to plotting module in SymPy which in turn uses matplotlib.\n", " \n", " #### Examples:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "expr = x**2\n", "plot_polynomial(expr)\n", "\n", "expr = x*y\n", "plot_polynomial(expr)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 2 } sympy-sympy-1.9/examples/notebooks/Macaulay_resultant.ipynb000066400000000000000000001637641412543434000244650ustar00rootroot00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import sympy as sym\n", "from sympy.polys.multivariate_resultants import MacaulayResultant\n", "\n", "sym.init_printing()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Macaulay Resultant\n", "------------------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Macauly resultant is a multivariate resultant. It is used for calculating the resultant of $n$ polynomials\n", "in $n$ variables. The Macaulay resultant is calculated as the determinant of two matrices,\n", "\n", "$$R = \\frac{\\text{det}(A)}{\\text{det}(M)}.$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Matrix $A$\n", "-----------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are a number of steps needed to construct matrix $A$. Let us consider an example from https://dl.acm.org/citation.cfm?id=550525 to \n", "show the construction." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x, y, z = sym.symbols('x, y, z')" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a_1_1, a_1_2, a_1_3, a_2_2, a_2_3, a_3_3 = sym.symbols('a_1_1, a_1_2, a_1_3, a_2_2, a_2_3, a_3_3')\n", "b_1_1, b_1_2, b_1_3, b_2_2, b_2_3, b_3_3 = sym.symbols('b_1_1, b_1_2, b_1_3, b_2_2, b_2_3, b_3_3')\n", "c_1, c_2, c_3 = sym.symbols('c_1, c_2, c_3')" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "variables = [x, y, z]" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f_1 = a_1_1 * x ** 2 + a_1_2 * x * y + a_1_3 * x * z + a_2_2 * y ** 2 + a_2_3 * y * z + a_3_3 * z ** 2" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f_2 = b_1_1 * x ** 2 + b_1_2 * x * y + b_1_3 * x * z + b_2_2 * y ** 2 + b_2_3 * y * z + b_3_3 * z ** 2" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f_3 = c_1 * x + c_2 * y + c_3 * z" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": true }, "outputs": [], "source": [ "polynomials = [f_1, f_2, f_3]\n", "mac = MacaulayResultant(polynomials, variables)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Step 1** Calculated $d_i$ for $i \\in n$. " ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGMAAAAUBAMAAABrMp7fAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAdt3NMolEIpm7EKvvVGZvmWXoAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABGUlEQVQoFZWSsU/CQBSHfwVqSaHEsOjYEFhwkBh3GB1ZMG70P9CwwNgRwsriVmcGiKMxahgJO4z+DQIOLMdBEe7eKya87b4v370bDtlbnDKZGw/3QKvTY5XVfq4wuAHmJrGHqHtU92H+UgZnvEtSAdJfVL8BE8r63dUuSbtILageAZ8VCo2/JL6KSMrBf4m8KyZzNtcBRfstUjxWqQXOloypyRWzcvOQQSVJ+swCbc6U5JJbGBHXHBLHR5NFM1hPFB6SO+CC2oQP43hiFWpd157rUaP28IpBSYf7LXEhhItcoOmyED+IFTWWfJ9/hN8yxA57huRTLdketj85xCa3QJVDJXnhFvY5h0ryzS0yEUwm2XwEP46MnLcGoZlHCf5KLDEAAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left [ 2, \\quad 2, \\quad 1\\right ]$$" ], "text/plain": [ "[2, 2, 1]" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.degrees" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "**Step 2.** Get $d_M$." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAOBAMAAADkjZCYAAAAKlBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADmU0mKAAAADXRSTlMAIom7VJlmdt1E7xDNIS4hGwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAFJJREFUCB1jYBBSMmFgYAxg8E1gYL/CwNvAwLmSYe8BBiAAijAwcDcBCUaNaCDJwKA1AURyrWZgFGBgBiq+DSK5DBg4LjKwJTD4FjAwTA21ZAAAM4UOK1ZklQ8AAAAASUVORK5CYII=\n", "text/latex": [ "$$3$$" ], "text/plain": [ "3" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.degree_m" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "**Step 3.** All monomials of degree $d_M$ and size of set." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "mac.get_monomials_set()" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjQAAAAbBAMAAACZwAj6AAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAu90iEHarRIlmzVQyme/la43/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEtklEQVRYCe2ZT2hcVRTGT2be5M04MzUV250oU2vV1awsIpi3SXHVzqKRIkxbqIJ0FYSCCyEDGnfFQRB0IY4LV24iipuCjq7ETRNQsUGwC0UQwYAR6R+I957z3tx7zz3nvcy6ncV9597f+c755uS9ZJIAFK/m8OUiZNerj2TsJNhWYMxtbv8QaObcqC02fsrkUqrCpaueokncgG0n86Nmf3Hi71lcgSn7TbjMZPNs1RbdcXdJLKQqvGzVUzGJh3p9Sv8ZPvJ0Xljrd/7xtjyswJR+DK7nbbj8IHu1RXfU2hULqAovW/VkJ5H2noTHXLJy19TW6v+5pCiqwJR/ApbXIuWBD0paKHdNiWLWtcSTncQz3miSv2YqFrT32EG4rcCU/HUWiubbqS1OT5VCqsLL1zzhJPzRvDTwVEFYUwmmVWAqdTyoOO9Ga9H4RKukKfx8zRNOwh+N9m0Y4KpfL44rMAqaW7FujhO1hfJAVXq2vXVP/IGC5U3ZbKv8bVVgqvmhXPqAp3qL+h25hK5w+bonOwl315jna3nsZH70Orzhb3lcgTE9HaVTrptjr7U4Pa3fkstoCi9b85RPwo0GjsH5zBO6sPPptYfdLooqMOV/f+2zLFIe+EBtUes3fhOrqAovW/VEk8DRJKuXrmzAd+cueToKV148eW5waH9/F1Z+hHrkwmF47Y9OdM8hToYDeD77e39fLk5YkpMrJOiA6dFQZ+PtPjsnp6QQTHn9JE/YjiaBo3kB3h08zTvYfTJqHa9NbASjr6Cxi5FbPJwcGUafigg32zfhgtO4yMeSnFxJBGtIhhiQtGRHIij2AI7mLXgn+9x5dlEza+618ctS39yBhSVHMHIYEqhzCoSf607gMBN6asKSnFxJxMpFQwxIWr0fmvIkOJoMPsbzaEnggfwNJ/A7PDhgCQ4b8E3GqBmXVWeHBvAvR3Yf4lheuIoJqQVDEYi1hZ2YWLF5zQCOBmTvNnE2jnQPrk/tSfCaYUgvBoA2iNezzl2BmSMPi3KcqEiMWDYUAklLdiSCJh2g0WjewY3DPBbnURssblpfBuf5BvEONG5KMC9OWJKTK4nYcrKhEEhavR+adBIczRfmG+xZBGxpZxegkeHhwkU4yih4uL0Fiwo+CkYrvHI1YklOriSCxSRDDIhatR+KPYkdTXpnYbc+RpLcxkuxrG8+Cs/SpruU3gIdf/v+eycUvA3rZcURo/zMpOhrr7krJHgeYkBD5UAyZX4bMnbUqg7gp+HklbPDD7AJQC/LA7ycWl25QW8LkleH5o82Kt5q/bmm4FMbv/apqKhGjPLa45RGa+6KCtujEOeGSoFkClw/7MOqunbeLwqYCPSjmmK2moe7DNtsRb2TV6rAIH6AyLXmwrE1hC8VII26FnZkMZ2aNf8JNds3ZxELLsMZc1uomLIlvDhJij+EVWAYsZ5sG2IyhCkqQBp29ewg1Zvy0axQfrw+BUfMoYpJIOHaeGGQl6vASZEXd7cnDJOhUkB1wq6eHcSsKklw5aMZeywIrwynZq9iypVwuvpLUagCt4o8+cowGbKpKqA6YVfPDmImJgmufDQeutfD+6NR74D7oykZTa/4P5Sac0+CtPfE//bDgtyc5ulCAAAAAElFTkSuQmCC\n", "text/latex": [ "$$\\left [ x^{3}, \\quad x^{2} y, \\quad x^{2} z, \\quad x y^{2}, \\quad x y z, \\quad x z^{2}, \\quad y^{3}, \\quad y^{2} z, \\quad y z^{2}, \\quad z^{3}\\right ]$$" ], "text/plain": [ "⎡ 3 2 2 2 2 3 2 2 3⎤\n", "⎣x , x ⋅y, x ⋅z, x⋅y , x⋅y⋅z, x⋅z , y , y ⋅z, y⋅z , z ⎦" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.monomial_set" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAABMAAAAPBAMAAAD0aukfAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAVO8Qq5l2zWaJMt0iu0SCRuA9AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAcUlEQVQIHWNgAAHmyM4FQIpRmYGBXYB5DwODSchnBoYmBobpQFE2IPMKA4O8AYT5hYHhvQCYyfwVyEwAM3l+MjCsnwBhAkWhTCQFDEBt8hBtDHcZGPqhhgGtCIdawS3ArMXAwOr03YOBeVrKAqAoHAAARgMh+ZrNuUcAAAAASUVORK5CYII=\n", "text/latex": [ "$$10$$" ], "text/plain": [ "10" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.monomials_size" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "These are the columns of matrix $A$." ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "**Step 4** Get rows and fill matrix." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAeAAAAAbBAMAAABW2EHIAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAu90ids0yiUQQq2ZUme/cMhILAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADlUlEQVRYCeVYTWgTQRh9+TG726ZapRd7UbYtVgsSb6KioQSkQmy8eYyCJw8N6EHx4FJ68tIVAkIvDah4DaJ4EKXiSfGnBSuIiD0o6MmCP1gU6szOJjt/Wdiwi4cMtLv73nzvey+zs2kX6IVhrLzrhZhBxgu43b7YYRfa5///JGWPJGFiBDOFWbsG096D3Uk06Foz3XVlaOE4jjnINMicQ70RGHjtcoGzY9XQz0ch748rEGIRQUIrDIyCC2w4qv9w5JJKxyKSWGBjuccCPyIrFOzhWBYnFpGkVtismdWeCnzuxRP+oRXL4sQiktQKf9vclG7p+omDx4vSk8gqF3HUlUDMfsk1oX9oWaWbcxel+dFEvMCeF20dc2nud85LXVB/g8xX6JgA4/ewVesfTVckFSO/hmkJgzVUXkGHwDdwtzgmFUQToYGZF12d7/J66cOg1AW1V8iuQ8cEGB/YcI2NfEFSOTJQwXYJg4UM6aZf4cu46j6VCqKJ0MDMi67Od+nigNQEmaVVpAahYTiMD2xhi/Khwd1axA9ZGjjjdgrs4pQyPZqIt8KeF11dy2Vup9zGwidsKwIqw2F8YHjTZZl5N/dLxmA2CKRfYeg+n0gi3h5mXrR1NBRwjf4Sh7mBmaqWCWaLgel0eawiuyZjeE6RDoE1nw8iibDAnhdtncfkG4opkN13EtAxAcYHzrvTyJJbVRzDSDVEhGguo69T4GfkuTElF0QSoYF9L5o6n3kJKLaI0WFAxwQYH3h+aRcOw/opul3BfBOLFQE8++Ae+c+BrrBEGI75N7WeUQoiidDAzAs0dYzJTVyZdOTuA4PmH3iMFILN9iLwgRdK9fdNwBYXeeHixwLSe4XAy/2fHRZYIgzHujVVfgi5IJIIDex70dQxZgCPTytdrDvl72CMGIJhSmA/k/LNtEoI+YuGzvX2sEgYDiXoEHGQXaxidJ5GhO1hSpLRqY6xcheyi9lQQvi47m9po8V5x76K9Zuc1ASQXXheRSIILODRRILAIXXMgtCFvLJadHyfYggfpAf+lvbhOkeTu6aZKpI/fMiPMmhgiWgHFvFoIkHgkDrPjdgFExhqmRRDtFBy1ARucjRglt6S634B8y9oYIloBxbxaCJB4JA6z4PYBXPlqm8NYogWSo5B4Kzdns3xIaeTulc8cYgEgUO6d0sFgbtVSKCOPKUTG35g2y4k1iK6cDqZ99LUyKzdIO+l9/0D+IgVyQXlgowAAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left [ \\left [ x, \\quad y, \\quad z\\right ], \\quad \\left [ x, \\quad y, \\quad z\\right ], \\quad \\left [ x y, \\quad x z, \\quad y z, \\quad z^{2}\\right ]\\right ]$$" ], "text/plain": [ "⎡ ⎡ 2⎤⎤\n", "⎣[x, y, z], [x, y, z], ⎣x⋅y, x⋅z, y⋅z, z ⎦⎦" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.get_row_coefficients()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Each list is being multiplied by polynomials $f_1$, $f_2$ and $f_3$ equivalently. Then we fill the matrix\n", "based on the coefficient of the monomials in the columns." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAegAAAD5CAMAAADbc1a0AAAAP1BMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFBd4eAAAAFHRSTlMAMquZdlQQQO0wRCKJ781mu918bN6TUK4AAAAJcEhZcwAADsQAAA7EAZUrDhsAABl9SURBVHgB7V3tgqq6smTUcZ8z43zd6/s/60mASgJ0Qxckiuz4YzVCV7o6paizKtC83dvHqamPQ87AX6dv07zdzxf3eD9kl7Wp5sere7p7od/qdBx9Bn6q0Bskvp5vPzfqXUIjcgGq0Bt0br7dx93175MYgkbkAlShCZXGqT9ffs/te7xff04jsgGq0Loqi0d+2x8q7/frYiYSaEQ2QBUaGqyI91boj7v99wqNyAYYCf15vp0vX/ZXaLNDwAM4dS+K6/3sNz7uF+uLhEbkAwyF/vhyXyy+3Rdx93jrP3oQxWYEwO38e9ZfKRLgcj6ZABgZUWTkJj42gcybuUSfOA/oC3/eb37rrQsKm8FuGpEPMBD6+vXjeJ1/Pfvz6c9zRPTb04cAuLmXykn9eiIAzq5mW3I6vNuTADAyopgvIswlkIiolOh3f3bvaEro9hxgR9AlVMBA6HP7teKvOxO9t0I3DaLUtADwPzbe7tovDgFwdm8Lz0J+JACMjCgDGgFhLoFERKVEv5s+rzY0Ih9gIPSXfy9f+7+TQWBEqWkB8PfRNJ9394/4EAA+T39HJwCMjCgWaBoBYS6RJuqcQuHum9I7/WWMQNAlNEAq9LX9sHnv310QGDG0FzdkgDsJaD84FMD1S/vr0hAQR1YruNep/+BEEwFhLoFExNjtdOvXvzHc6Uj/hjHG0IhsgKHQ/nfC73fz7s+8EBhxzNk9v7av5TGgafqT/xQhAy7f6tfWISCOrFYYcQLCXAKJiNMekj3dXzPO6jeSJLXfpBHZAKnQjZ/wn79T036ZhMCIU9buC7oEaG7tNw4pXwHMnLoHFcLIMxWGJQLCXCIkGk7dzZ//E6h6OpJmgEbkAgyEvp4ut7fP06X9hIXAiBJtEfCj69yIAP+hrv3NYQDAyIgSpWGJmGksEbnogFj2enP//6d97MS0ZItG5AIMhE4ImU7dg3yc6z/c+eDD1Hz7EmrfEJ93/7tu6YGREZfyHY+Wi7kEEhGXC7xOxozQ7V/sneB9XOypS3z7fn9//zV9PekA/teS6Y9xGBlxkZD7m0/HxVwCiYjLJV4mQxP68/x3P7lPYMTFhpD41fpWFtPjyG+3y+2k/e5Ox8HIiOkxeRuZ5hJIRJSHfcm9mtAv2Uwlrc9AFVqfm0MdqUIfSk69mSq0PjeHOlKFPpScejNVaH1uDnWkCn0oOfVmqtD63BzqiCI0bRunJ6V8BZpSs0dOdBdKE4rQtG2c5lO+Ak1phR+fr1EcoUysLDRtG6fpl69AU2r2yInuQmtCFpq2jdN8ylegKTV75ER3oTUhC03bxmk+5SvQlJo9cqK70JoQhSa8h7SBv2NetMIhOOVuQhTabhtPzPI2x3//Ct1UAbZ85dUucMrsx08qgAviMidkznNKS2RZVKAIbfSZJ/Z6OP0RlY6D0Osr2A384JLZj590DS6IStcCYp5TAkAiolJiaWJFoc0n1sQsz3mPtlTw9g99iUBq4AenzH78pGtwQVRUEBDznBIAEhGVEv1udWK90P/c/xmhu0/0ZZ95YpbHpMY4GnP4dEMFu4E/5WIwda7gBC6IwybDs2Se0kydUwLwgyARMQw83dCa+D8n9PQaJkbb+NAsD7so4pREsmdTBSegapqXOZlMuas4RS5WTgHRehCTOYmbwyYCeR0QoVoT4qm7/9PBojN9aK+HwIixuLDV/a5fWQG2fGHckYEfXHL68YddRy77XlQgC211pg/s9ZhUREmGuM9oTBcrRFt+HC9syYhw9gt5wsYaToHLzhcVKEIbbeMDez0ERhRmMtm1pUK05ScDYlPkFH35SJPiGk7ggiiNu4dFBYrQIt2FnRAYcSF9xeF+ZLuBv1tUUNKPDy6Iy109aVFBTqFZx//ypIwy6CUC/eqDcn58LBFAHBEWniLTzAmJiMKYll3ZhIaBH9FSnMvByLDlL6OBKOfHBxfEZU7INHNCIuJyCTEjm9Di6HXnbmagCr0bKcoSqUKXnd/djF6F3o0UZYl4oa8X0yrXskTq6GVn4NMtjZ3+rbtszTr6E2agnrqfMOnPKFmFfsasP6GmIrTiAtcJ0gB9KO3IA0popbX9O6SkUVWEVlzg2ijuQlT+Qkz+r3TlHg8owZLfISWtBVlozQWujfII7zvNSSWb7cAOKam9yUJrLnB1GBqgjqQeeEAJtbZyYIeUFKbddXWnP6864xFxaXkaoBJSDzyghFpbObBDSgpTRWjVSqgNQwBWGtOdRag1CFsud0+XoAHdPBCUHnBXgIUmxFO33V7fK28HJMZ0yvHvriLZXqHUcE1zoQRM8/ILVQLMXrKf7lq8K4D1TgUgv83xrwhttNdj4tTrviMBMTGmw12PiBQlbikxb68XOG00y09aSEqAC+Ikt90hAOY5JQAkInYVRKGZc1LHy3peTYzp0XRt8h6ZOQkl/M8+3fIvADaa5SfiJSXABXGS2+4QAPOcEgASEbsKXuj1Bv7AsvtaUtLx3691XFUiNc0HymFjYJaPL7oNZvkwNDaSEuCCiJRhFAA+QeeUANLECNhk4I/kNNt4zGi3hsZ0TCriKHn0dFOJYJofDeqeypyCaX4KiHuMlEYlIhfV8j/kFAC6gX8EQCKioyyeuq0G/tjyJj++TehNJaLNPnLut4Z+fHDJ6fgfLSqIXFTL/5ATADOchgAkIvpOZaGtBv44a2u875hUxDiauLWlRLDZCyOXd/wrdwWYsfwPOEXy8Uw87mMICOf4CFCENlrZYzkjQHTXG4XeUmLOXi9yyur4lw38Zk4xUb8rwKCJSD4CFKGjggW3IDBigVL90HZ7fQso6fjv7wqAuwMYes7j+H+q0MUd/72BH6Z5w6ySdwUwjDhKARfE0eHpUyT632OmOxUgEbEb8nlCw12POG1x8x4MDdP84oAAbDTLz9UBF8S53PYYEs2ckIjYVXie0Isd1oScM1CFzjmbOx6rCr1jcXJSq0LnnM0dj+WFrgb+HQuUi1o18OeayZ2PU0/dOxcoF70qdK6Z3Pk4Q6Gvv19/FOEdAprynMIU8QZ+GpELMBTaGfFPoQvbxg4BD2iinxvewE8jcgHGQqs3ctZk3yGgKc+pmw3ewE8jsgFGQn+ol15UhN4hoCnPqZ8M3sBPI7IBRkLfuI/optkh4AGceqF5Az+NyAYYCf19ulzObr2c+bFDgPuILt1ENz1mY2qYTRqRDzAU+nr/vjqHk18U+fbd0UMMZAcbUwDs5oO0+EQAzHvlIwAjI8ZBh1sCwlyCudg9saYABO2rEHpEPsBQ6M6W6NZEwFWPCKbjOAHM+9LhZ0wqDG3m4/ETAEZGnKb2ewInZJpLIBFRLdEdMK8pCOPQiHyAodDtZZV762j/aT3v85kA5n3pzpnsTxRphaHNPExJ2AgAjIwYMsYbE4S5BBIRxyOPntPnVde4eQFZVysfwAsdDfzfnke3iBICI46a7J9OAPO+dPc7fVphzpeeADAyokzI7Q0l0sxoh5ziAsAfQiLiND3usS5b2ICgS2iAoYH//uNbbX9iQWDESDbdEgA426ZpcVsCJDbzmIitBBBHVp3vHiUhzCWQiAgaYrQa+COYRmQDDE/d9w93Xv3yancXQE5iJJtuCQDYzdO0uC0AUpt5TMRWAogjq853jxIQ5hJIRAQLORrXFCRgGpENMBT65DT+bT9GjEILgGg3TxoMmxIgnC5DVrKRAMLIM853h5QQ5hIh0XLq5tc58AjjsoU4YwpgKPT1fPHfOP0Dp2zEbu/4XwEQ7ebjZP9cAES7+QIAIyNK6cMSMTM62aeohFPkMgcIQxjXFIR81//tcjm9JTuWNnMBhkInVSEwYnJI3uwTy3nlMTKiTCPdm8f6no74utu60Ky7nr48PumVh5EdcXnOkTl0ss/gkIg4k/pyhxSh4WRHXOwLibCbmwFDm/kMDCMjzqT2h5BpLoFExOUSr5OhCP06DVSmthmoQtvm6eWzqtAvL6GtgSq0bZ5ePssLHf/W/fLt1Aa0GRj+rVvLqvtffgbqqfvlJbQ1UIW2zdPLZylCW23jtFk+TFi5CofglL0JRWi7bZw28PdSl6xwCE6Zm5CFJmzjtFm+E7pohUNwytyELLTdNk6b5fs3dMkKh+CUuwlZaLttnDbw90KXrHAITrmbEIUmvIe0Wb4TumiFQ3DK3YQotN02Hs3yRsd//4beUsFu4Aen+WvX95QIP37sGlwQMdY4CogHLypQhG59Y4bbGgSzPJz+iONOR8/txvRJBdjyRyPGpxNEdj9+qAAuiJHEaGuCWOIUAEhEHA08fqpOrBd6crEa+4k1mOWtJrOe2IYKdgM/OGX344euwQVxPO3h+QSxxCkAkIgYhpQ31ImVL1ajucAngyfed5jLECe5gx3rK6S2/MGQeCJwir58JEmR5wQuiNKo7b7AKc2cM5oGgIcjEVEt4w5oTYin7sZsG0/M8hAYcY6NMxX/+uM/y8uxhQrunTqHkxB5/fhJhcjFyikgZjmlJZCIODuz2sTKQptt44lZHgIjztKxX+NfqBCN/GINAZHZj59UiFx2vqhAFtrsM0/M8hAYURQh7lR85jGh3xIqBCP/JLndISHC2U+G9HtXcApc9r6oQBHaahtPvO8QGHF2Su1OdqFCtOWLNQRE9OWLCOxc0TW4IGKoUUw4xcy5NQIJIJKfA4SCShOK0AFm34DAiHakNbMf2W7g75abtB9tn+2HnrWSOQ9cEJeBz1pUkFFo1vG/PCmjDHqJQH8B/nJ+fCwRQBwRFp4i08wJiYjCmKZduYSGgR/RVJxKwsiw5S+DgSjnxwcXxGVOyDRzQiLicgk5I5fQ8uh1725moAq9GynKEqlCl53f3Yxehd6NFGWJeKGrgb/sHO9i9Grg34UM5UnUU3f5Od5FhSr0LmQoT0IR2mqvDwStgPXGdHedm9vPzXCdF7oEDaC7fsBdAZaaUIS22+v7pu2Atcb0pmCJtZzslB5wV4D5JmShCXt9JzQBWGlM7/8H+9ZfdDi8qaQNugQNoLt+wF0B5puQhbbb6/t5tgPWGtObgiXWcrJTesBdARaakIXujEfd1V+lt8xknx2w1pjem6EsnOgSNKDv3971A+4KsNCEKLRqJZwI3O8gACuN6cwVkOkSNKBrm+j6AXcFWGhCFNpur++FtgOikx3u+hC1V1G3f0uJBXv9lFNux797meLWBuCCqHQtALY5/hWhrQb+ILQVEIzpcPojKg2H3aozPWRgY1JiyV4/AWw1y4NJjKEEuCDGlOHWBLDEKQCQiNiP64XeYODvR7GfxIIxHe76GIedjp9tKOHNGW/tjULGg3bPJ5y2muWnZUIJcEGcpo44IXGJU6iARMS+wkYDP3hqtnEcDzExpsNchhhy5I31JVLTvDS2wCma5iUA9pkpTe8KYOaUJs4Z+JMmIvkEIJ667fZ6tKzZxnE8xMSYDoERQ468saVEMM2LQwuc3OXpDX+DM1MS7wowuwwh4RTIz3JKAUhE9F3LQpsN/Jg4MyDxvkNgRIylxC0los1eGlzglNnxL90VwMwJifOckiaQiNj2LAttNvCHeVvhfYfAiGEsZWNDiWCzF4cu7/gX7wowa/lPOEXyyZl40kgKCMsVEoAitOICnwwfdlgBiTEdAiOGsZSNDSWiaV4aW+AUTfMSIOyzUkpvPAAuiGGwwUbCKSbOGfgTQCSfABShB0ULPYHAiAXK9EPb7fUtoP1oK+T4b8AFcbHrTI7/Zwpd3PHfG/hhml+cU/e1p+Xkf9Jcvq6GfDoFXBAXB0CimRMSEfsKTxMa7nrExY75BAwN0/ziCABsNcvPFAIXxJnU7hASzZyQiNhXeJrQix3WhKwzUIXOOp37HawKvV9tsjKrQmedzv0O5oWuBv796pONWTXwZ5vKfQ9UT9371icbuyp0tqnc90CK0Faz/PrmylfgudGcaIB5FUIgT5dQAIrQhDM9UOI2ylfg+PhsmhMNeEAJhZMsNOHH56ezRZSvwBOjOdEAZhVCx58uoQFkoQlnOj+fLaJ8BZ4YzYkGEKsQevp0CQ0gC0040/n5bBHlK/DEaE40gFiF0NOnS2gAUWi747Kn4+5nfzF4rOLc0xUaugQNoDnRAGYVQjdXdAkVIAptN8u3dD69yefbr357syyB8xiyQhNKLPjeWz5tAXCyefHXcKKb4NvmS6gTqwht9eO3E/t1c+H03li9+C7bbsdvKzQoseR777LdvwCMbOzhuLDBcqKb4NvmS6hNeKE3GvjP8eLZZleQeoYRBHC7Qglvm5jz4gMeACMbO45LkeTk5u3evh8+7hdpOGkfjcgHyGDg/2qvsd72ZRZavVC8ND3u/YkSqZ1dTu32BoB/mngh5zAkJzdU98XnfX5h8qAkjcgGEE/dlIH/evdn7u5hF9rufXcjpyWCnR01pTgApDZ2KTnsozh5FA3gEXQJDSAL3f3qbpfzhGlQN9o1Am7+XYJdaKpCt9ChKwE7u0qnPZBwGtjYZ1EcJzcUDeARdAkNIAtNGfjPJ9fz9ex/XtmFpio0SYloZ58TLQWYT90cJ1/euqYgUqURuQCK0GZnum/hdvv56b6PEEJTFZIS0c4eZ0/Yipz8d11/tjE8OE5uQBrAI+gSCkAR2jArUgohtAQ37DP73ruxinrxDXT3k5JZ6N6TX6w/2NnNBUY2djPucIk5hYb/veAkwc5uLjGysZtxh0vMKfThJudIDVWhj6TmTC9V6JnJOdKhKvSR1JzpxQtdDfwzE3SUQ9XAfxQlF/qop+6FCTrK4Sr0UZRc6EMRWnGB64PRAH0o7cgDSmiltf08JRqRC6AIrbjAtYZXeN/1obQjNCdtoHz7eUo0IhdAFrr7T03T1e67WaMB/GQ/oARLiqdEI7IBZKE1F7g6EzRAHUk98IASam3lAE+JRmQDyEJrLnClYbinLJfHV4dYOkBzWhpw+3GeEo3IBhCFzuc91CaTdtfzlku6BA2gp4lvgi6hAkShVRe4phsJCHZ8u+Pf2URaD+JbYkXU2Pj9ocSeHP9sE94cQ3U9A1CEpgz8fngKAHc94fhfW2JXjn+2CXpiZwBe6I0Gfvf+UU8Y4psuuOsZN+HKErty/JPzRE/sHCCDgd+L2X1nMFrZE3c9YTJbV2Jfjn9unuiJnQOIp+6yPvPUXU8IrTnTfXfjR1rCnTbimqFxIp4PAOUc/2Untm1GmyZZ6O5nutHA78enAIm7nhB6bYk9Of65eaIndg4gC8070xmfeeKuJ4SmOCUlduX4p5rwumUDKEIrLvC2tPgPBYjuekbolSV25fg/ioFffA3M7WSEnhtHP1Yd/93cKO9ofeLyHumueJ93zMFo1fHfT8dTha6O/8GLsuiTpwpdtLM6+GAGqtCD6Tjukyr0cbUddFaFHkzHcZ94oauB/7j6hs6qgT9MxbE36qn72PqG7qrQYSqOvaEIncs2rk8eXYG/eL1eXDlCc6IBSuGcuxVOitC5bON6B3QF/uL1enHlCM2JBiiFc+5WOMlCZ7ONqx3QFfr/yiUWFai1tQM0JxqgVc64X+MkC53NNq52QFfgL16v1tYO0JxogFY5436Nkyx0Ntu42gFdobdblVwjQHOiAep05DugcRKF5hyXjmR5AF+ivB+f7vqZtxEQhc5nG9deqXQF1soeDPz2NQI0JxYQOD1jUYEiNOXHn7GN60KTFVjv+4o1AuQqBL5rcHrKogIv9D//+e9QEPqcVB5AnrrXrBEo3UTg9JRFBf//H3/vgvEdbrpPdKMf379IygO4EqvWCBRuInB6yqIC8dT9RJ/58NSSPtOc6WkOtlM/vt1/yFRoK1GAlNMTFhXIQne/uksZ+P0k0RU4xKo1AjQnDpBwesKiAlnobLZxvMWmkXH8d2gGkRj47e/owl0nnJ6wqEARmjLLex3KA7gSq9YIFG4icnrCogJF6Ok78GX3EO/oR/X4jEUF/wKhS98VgH55PGVRwdGFfsAaAVrop9xG4OhC0yocFVCFPqqyo76q0KMJOerTKvRRlR31VYUeTchRn1ahj6rsqK8q9GhCjvpUEVoxB+uzUB7A+7ppTnp7yhG+Ao9QSrO7FaEVc7A+enkA7+umOentKUf4CjxCKc3uloXu/v+N8FCXB/C+bpoTO3c8pRUImpQCkIXWzMHKIA1vuqYrPKKE2p5y4AFNKJX53bLQmjlYHb88gPd105zU7rQDfAUeodVm94tCl7bJrTCCk+ZANw10E+WN4A/gpDYhCs0allnTtXfKkhcc5xFkiWC6tr9VyApuYBJBc5oBKEKTruvilmjeRO0mlWoCpmtniv02ak1WaIVex8nq+A9N3C7n03XQhig0fdYrD+DPehynYLom7grAVfDTziECJ6vjPwDOP01z/l0WmvNQ+/G6LxkljeCFSwTTNXNXALprronAyer4D4Cz+2D0b+HkIb6jX97X3TbIuK5T07XdZMZU6OacQURORsd/BPhipnc0Z1h2o5YHFC6RmK7tQtNdc00knEyO/yYFjG8jIL+jCzuc/QuOcWn7/BUIpkRiurYLXbiJhJPN8Z8ALt+XbtbwryJ0YYezq05X4BFUiWi6JoSmKrRTTiEiJ5vjv0kAtlM3Xgb/ykgI/bD5MTr+Uz6f9/f0qfKOTlP+bds7FDqD478KPXkdF78rwKTi0o4cjv8q9GiWj+r4r0KPhD7q0yr0UZUd9dUJffeP0+hQfXqQGfhr5W3vNnvxj4+D9FXbGM3ATyvvpfkfo/61IhMiom4AAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left[\\begin{matrix}a_{1 1} & a_{1 2} & a_{1 3} & a_{2 2} & a_{2 3} & a_{3 3} & 0 & 0 & 0 & 0\\\\0 & a_{1 1} & 0 & a_{1 2} & a_{1 3} & 0 & a_{2 2} & a_{2 3} & a_{3 3} & 0\\\\0 & 0 & a_{1 1} & 0 & a_{1 2} & a_{1 3} & 0 & a_{2 2} & a_{2 3} & a_{3 3}\\\\b_{1 1} & b_{1 2} & b_{1 3} & b_{2 2} & b_{2 3} & b_{3 3} & 0 & 0 & 0 & 0\\\\0 & b_{1 1} & 0 & b_{1 2} & b_{1 3} & 0 & b_{2 2} & b_{2 3} & b_{3 3} & 0\\\\0 & 0 & b_{1 1} & 0 & b_{1 2} & b_{1 3} & 0 & b_{2 2} & b_{2 3} & b_{3 3}\\\\0 & c_{1} & 0 & c_{2} & c_{3} & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & c_{1} & 0 & c_{2} & c_{3} & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & c_{1} & 0 & 0 & c_{2} & c_{3} & 0\\\\0 & 0 & 0 & 0 & 0 & c_{1} & 0 & 0 & c_{2} & c_{3}\\end{matrix}\\right]$$" ], "text/plain": [ "⎡a₁ ₁ a₁ ₂ a₁ ₃ a₂ ₂ a₂ ₃ a₃ ₃ 0 0 0 0 ⎤\n", "⎢ ⎥\n", "⎢ 0 a₁ ₁ 0 a₁ ₂ a₁ ₃ 0 a₂ ₂ a₂ ₃ a₃ ₃ 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 a₁ ₁ 0 a₁ ₂ a₁ ₃ 0 a₂ ₂ a₂ ₃ a₃ ₃⎥\n", "⎢ ⎥\n", "⎢b₁ ₁ b₁ ₂ b₁ ₃ b₂ ₂ b₂ ₃ b₃ ₃ 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 b₁ ₁ 0 b₁ ₂ b₁ ₃ 0 b₂ ₂ b₂ ₃ b₃ ₃ 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 b₁ ₁ 0 b₁ ₂ b₁ ₃ 0 b₂ ₂ b₂ ₃ b₃ ₃⎥\n", "⎢ ⎥\n", "⎢ 0 c₁ 0 c₂ c₃ 0 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 c₁ 0 c₂ c₃ 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 c₁ 0 0 c₂ c₃ 0 ⎥\n", "⎢ ⎥\n", "⎣ 0 0 0 0 0 c₁ 0 0 c₂ c₃ ⎦" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix = mac.get_matrix()\n", "matrix" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Matrix $M$\n", "-----------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Columns that are non reduced are kept. The rows which contain one if the $a_i$s is dropoed.\n", "$a_i$s are the coefficients of $x_i ^ {d_i}$." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAFoAAAAyBAMAAAAuIdEGAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMA74lUMhAimXZEzWa73asFX9bSAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACQUlEQVRIDe2WP2gTURzHv73kEu7aNIJ/FpXeIHYSUwpOSitUhS6eILiId1s3DYpQtGp0qW5R3BsQ0almcxLqIAWnTqKLdgyKUBNbqILn7/feXd69uzcks/7gA+993ye/vLzkHsFE1MVgdTz6gb1zZwaTcXFuCvsGdFk7/Q/ZpeuL+41HszB5308tyDN5HLpbwDzljCrnAF4Bk+u+ID5B+yDKazj3HQIl40IbS7DC8RZDuehd3kalAZyiOaPqno+PqITFHYZiYY+sIZg12Ydg/0SlWdplEjvwMEPjXG+7iwJ9HhS2JbJ3UMP7QmiwexhrnYDYJm9V2m5j9LNl6I2XeLPp0aGQyEjb7hy5+shkX3lwttPEaB2C2OaXUeX2LWM8wVOBbk/RKpOp4rPpdwzFqd/3wpcOmGyNRNEWo9tZyzBP9TasZqP/dvZEkm/n8uH8Cif22w1tIT7BVS1UE3dTjWkU2z0tVJNqTY37tkMPh7FWfC2WvS19e8o4poY8krbbWdbfMpFWH95IhsoOnts7KLYgSC3bv/wgtJZugqGSvWd8dIt3N8Ckix72qncUX8H07Vvgy4BMJlXlFgLvA86HDOWy9ws4PZPt1rFS+4RrTaZv/wZdbobe1TbocgNtVBD33uX70WQ36UIF3YWS2P6GdbnnzL7H22N1wIpJ9n1puW207cXb1PZ1TGLT1GiL3PGcWYYm8kxEWthDryCyNT990mcoV3bpzp8Gk5UxEUUCzc5ZhkD1NizmomHt4f5xDPVv5i+476lodELMLAAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left[\\begin{matrix}a_{1 1} & a_{2 2}\\\\b_{1 1} & b_{2 2}\\end{matrix}\\right]$$" ], "text/plain": [ "⎡a₁ ₁ a₂ ₂⎤\n", "⎢ ⎥\n", "⎣b₁ ₁ b₂ ₂⎦" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.get_submatrix(matrix)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Second example\n", "-----------------\n", "This is from: http://isc.tamu.edu/resources/preprints/1996/1996-02.pdf" ] }, { "cell_type": "code", "execution_count": 17, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x, y, z = sym.symbols('x, y, z')" ] }, { "cell_type": "code", "execution_count": 18, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a_0, a_1, a_2 = sym.symbols('a_0, a_1, a_2')\n", "b_0, b_1, b_2 = sym.symbols('b_0, b_1, b_2')\n", "c_0, c_1, c_2,c_3, c_4 = sym.symbols('c_0, c_1, c_2, c_3, c_4')" ] }, { "cell_type": "code", "execution_count": 19, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f = a_0 * y - a_1 * x + a_2 * z\n", "g = b_1 * x ** 2 + b_0 * y ** 2 - b_2 * z ** 2\n", "h = c_0 * y - c_1 * x ** 3 + c_2 * x ** 2 * z - c_3 * x * z ** 2 + c_4 * z ** 3" ] }, { "cell_type": "code", "execution_count": 20, "metadata": { "collapsed": true }, "outputs": [], "source": [ "polynomials = [f, g, h]" ] }, { "cell_type": "code", "execution_count": 21, "metadata": { "collapsed": true }, "outputs": [], "source": [ "mac = MacaulayResultant(polynomials, variables=[x, y, z])" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAGMAAAAUBAMAAABrMp7fAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAdt3NMolEVO8Qq5lmIrurE6D6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAABF0lEQVQoFWMQMmEgBfAYJTCEYdfAu/udA7oMb2hcAQMrREvFBHRZhlkMrN/QBW8zsP+BaOFcvR5Ty0oGhg50LfIFDJ9gtshjamliYFjvgKYnI4HzMx4t9hMwtTDAHcbAgMUWoAX6mHZPCsBjCwMD21c0dzEwXNWegFcL0wIMLQysbXi17MbUAQzFCdB4weYXxg0YWu4yMLwvwKOlmoH3Apqm/xPwamHZwMCIrqUPGIoXELYAIwkFXAqNXsQw3wBF7AwD+0eo93f1Wx1gUJqAIm3///8nBiZNFDG23fsSYCEGkmBHdwZIsBZEoAKow0CCrKgyEF4ApiCSlomYsgycApiCSFoOYMoy8GARA2oRUsEijluIUSkBADifSkf5V5C+AAAAAElFTkSuQmCC\n", "text/latex": [ "$$\\left [ 1, \\quad 2, \\quad 3\\right ]$$" ], "text/plain": [ "[1, 2, 3]" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.degrees" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAPBAMAAAAv0UM9AAAALVBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADAOrOgAAAADnRSTlMAMpndu3bvImbNiRBUq9OBhjcAAAAJcEhZcwAADsQAAA7EAZUrDhsAAABESURBVAgdY2BgYBACYgYGExDBmgIiK6aAyAUgkqMARG5lAJELQCSPAIjcxQAiz969++wqUIIBrIvhCYi55N0NEMXAAABbkhBrtxdTYQAAAABJRU5ErkJggg==\n", "text/latex": [ "$$4$$" ], "text/plain": [ "4" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.degree_m" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": true }, "outputs": [], "source": [ "mac.get_monomials_set()" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAABMAAAAPBAMAAAD0aukfAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAVO8Qq5l2zWYyiSK7RN2jbGmSAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAZUlEQVQIHWNgAAH2ZM5AIMWozMDA9P//AgYGk5DPQNEl2SBJNiCTBcTAZHakToCK8hhw/4UygdQ5BDN+A0SbOwPD+gsQpjoDQ7wBhBnAwPAcqnYrA4c2AwOr03cPBu4oV6A8AgAAADwbeTiD1lMAAAAASUVORK5CYII=\n", "text/latex": [ "$$15$$" ], "text/plain": [ "15" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.get_size()" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA6IAAAAbBAMAAACU+y+UAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAu90iEHarRIlmzVQyme/la43/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAG9ElEQVRoBe1aTWhcVRQ+mZl0ZsykVrHdSWVqrXUh46YignkuUly1gzRShLSFKkjdBKHiQmhAI7goDYKgCzUuxIWbiuKmVKMrfxZtQMUWS7tQhCJYsCK1Qnz33Hffd+59594XJqvWzmLud893zne+c2/mJ02JysdYiXzQmX3GDwS7hR+zICK3nZXviy2Q5A2OM8hEDhBYgWrs1lQLoeN3Z2JXgfGxRztIGAOqNDWBtTf+IlMF6Byt6ISNTi5Obkrwr9CRggUK0+MMMpEDBFagGrs11RDqDDYsYVdBibFHO0gYA6p0zQO1je/sD2xd60SmCRD9RO/phI1OznevJPhtdKZoABSmxxlkIgcIrEA1dmuqIdQY9P7EroLiY494kDAGVOmaB5KN2/376R5XNb43czBck6/RvEfqNbqDpuasHlCoH2eQiRwgsB5K2q2tdlKNuebfDqtrbOwRDxLGgNS+0fPmxrtwo99Fb7T1u67sonuWHVJXvAkBhYlxBpnIAQILVGc3XQ0dmrgqNlUYG3vkg4QxoGpbomRjcaPz0Rt9eqjplrHxD0qogu1lFKgMFSDOIBM5QGCBauxSuho61EjOHR175IOEMSBhx8F0Y9xodxC90fQ3o5p3XeqcdVaAXMStccZl5F+I16Bjs5PvukIH2jo6roddNPKuO/JBrnnAZGPc6DTFb3TqpJtCXZvX1XARfKckgcpQJSdksEc1EFiJ0nbrqkulbvkjVIY8EBl75IOEMSCvodskG+NGT1+4eM6VeGv+sTS16EX8zZ7l5jU/4u3a8+1lGwDyEvJNnEEmcoDAAtXZTVdDh+glelluAxwde9SDhDGgoCdvaxrjRommMk2AaBsdiDCc3xiM/6IXcvTbUx8X1UBhepxBJnKAwApUY7emGkK9j07dhV0FJcYe7SBhDKjSNQ/UNOYbnX7q4f1D6m59PhRozRw+ukBf7z9MNP0DNSsXx4W9hdcGRC/81gtfyLb6j9VVas0O6bHMoPAR5qR1qP3g3Dek6bAT24btBn0EzdWsE+RYK3ZOw29cXb0SpOTHwEdlaDu2n2CLtYPkA2BnSmt5POYclQFtCp+O1tgeGzc2N9qa725vLPne7O4JemP4gIXzn9N4OKAobG2erXwfQXVn4hId1BpQmJPWocdnLmzSdKyTaJsKrelYK3ZOjTd9i4ljtHZIbFc4U2oFq81vFGxKjCVBmBvtZJ2rEwPuHDy9SieyTzjWPHmexsLDFIUtaoYsofrRySW6I9C22zAnrUMZPaTKWCfRNhVa02ErxZwabxoXE0do9ZDYr3Cm1ApWm98o2JQYS4Lg1yjdVrkN9pEf4PsW5CW/0u3DYuOWliz8MnNht6I62zikv1zYW6s5KR2inv7RZp1E21RpRYetuDkV3vh2E+u0K/Ym5I10Vq2VLFXnNwouRWfzhJLgz9HqXbEN81TeQ/sqnVkuww7gktuHXEysZfWxrPeviEsY5KR16EVZKjE7ibcJaVXHWCnmVHnTz04cofVDMmXCmVIrWHX+UiDGEgh7o8pdGRv5S6K8h/x984CNyWcUfibDBUb1eRq/pCTkoTAnrTNxSFch++MWb8NGQas6bMXOqfLcmoVitC3WLKZbgyVtfiNoU2KsKDM3OpEdpPFM8/Fp/mVonyXGDtGWMEUUTpylDSEtqrdQXq89wpwandNEqk7hJNamQms61oqdU+ON/UIoRmuHZKeGM60WrDY/K3BKlBWEudFjJ7fSI7Zx6x+72uf29bErzUWLJze1r5FPy8Kv3npzB+1dilWv0LFCpyYnrdPb+fqTc9xDd1K2qaGtjmqF56zpA9qXyP8okh+S5i//d9TiALg2sAeWeH6joKaUbHDUKCMyN7p7Zvpccd7Uz4xc8Wg9u2/2bYefm83/WtjPii0vovBs9/IcNe6VrKzevXBxYLmanLTOJL37YdGinxWAl8IJ2qRpq6NaaZk5a/qA9iWIi60v3wCVzmxtjCWenxW0FLBBYxB8oyxQPOm/xTCZf0hQgjY59jcdzg6fzrvAOnOcTMSJa1NDWxXdipkTj4iQSwglyuJKnXPGlWl2LSlhY2eocqOdkgnAEdqbv99FaZs9HxS57YalVvnH4/XkOL181ZyINjW0FdKs2DnRSBMCS76EKPbrhDMuTrNrSfEbc4V9st91EZgG9NFO2pwHojQnt4Z+TblrLI45al05paDuRLTRjAo6btfOiUaaENhgGlHs14Wt0yzrp1OCxnBUeY0uCs6DR2eX832U5tyuVyE27Zmf3W5dOU4kXzUnok0NzUKqFTsnGmlCYAMJUezXCWdcnGbXkBI0hqPKjQrqFrwhTyB8170hh7hlWpzArRsVh3FTwF3Ud/9f96aY5/8+RLt/3386MpnwpE06aQAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left [ x^{4}, \\quad x^{3} y, \\quad x^{3} z, \\quad x^{2} y^{2}, \\quad x^{2} y z, \\quad x^{2} z^{2}, \\quad x y^{3}, \\quad x y^{2} z, \\quad x y z^{2}, \\quad x z^{3}, \\quad y^{4}, \\quad y^{3} z, \\quad y^{2} z^{2}, \\quad y z^{3}, \\quad z^{4}\\right ]$$" ], "text/plain": [ "⎡ 4 3 3 2 2 2 2 2 3 2 2 3 4 3 \n", "⎣x , x ⋅y, x ⋅z, x ⋅y , x ⋅y⋅z, x ⋅z , x⋅y , x⋅y ⋅z, x⋅y⋅z , x⋅z , y , y ⋅z, y\n", "\n", "2 2 3 4⎤\n", " ⋅z , y⋅z , z ⎦" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.monomial_set" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA1EAAAAbBAMAAABvgBgOAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAu90iEHarRIlmzVQyme/la43/AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAGs0lEQVRoBe1aQWhcZRCe7L7NbsxujWJ7E2Vjje1B1ktFBPM8pHhql9JIEdIGqiA9LYGKByEBjeKhGARBBTUexIOXiOKlqKsn9dIEVGxQ7EERRDBgRGqF+P8z7+3///Nm3p+tgof4YP83/3zzfTM7k/d2N7sA/tGYe9TfevaFW1NvVzAjMMY3Nr4s8IZwqCmWv05lGZXhhWsxeiccWeO6iIJ1HZSCBjouw4YMNDqjqzKC3ghMzKfhXIlEDFJTtFZaEyJZZXjRaozaCUdWuS6EW9dBcRI3tztgH3h8A284xLcqneZv/p7ZEZiiJ+FSloaxd7VVU7SWxrZEBZXhRasxthP19l1e6MAcaU+irXIHkQXDUhTVQmzgWGgvwe3GYx/ZoVxTlV71jzxEOEdgYkzBdE/g7tJVkkK5pkoYg5wlMbYTRwaBnlHJ7BKuFx2YRBFVg7jipjrPJpX8Ugwiz/i2hqA/AhP347RUIwKqKY71FabK8OK1GOyE2NN8UgAa15PnpqVIqrXDfR462L86BVDlk3qkO8CZUVERDIzAJHaQaQ631VLU3tJ0NIYfr8VgJ6SegpuUxvX1mW0pkmqj7HbznDAp7R0FwAWWkm0jMEY31hlpuK2aQrn7RWvG9Kpq9O63O332HG26f2dS02tMOtuOlXc5ApPIa7L0Lr16iuo1WUJnuHg9xnZC6qm7pnSu02cWUiTVIa8pc2+eXmHa2fZJeEoGyBuBMai+VO+XaUQwLcWxfvWqTNUYfrQSk3VC6qmblML15bmNFEl1yEnBJJxOuTjum+9cvEUEyBmBKeiLi++mJRoRSE1R6dR+ELkqw4tWY6gTUk8Hk1K5nj4ziSKp7n5SyezZ88vw2amzTBtg5uF7T3X37exswcxXUC00xcGw8FOzcEUinMx14YH0150dWZxgiU5VIYIVMD4W1Fx+tsP8VCkxhKK8fJIqpqNOSD21k8LEEteT5jXZQogiqZpJie2t3937HIJ3FA/Bi93DXNzuk6Wxg5VVa8HSR1DbQsstHpzsnyt8GiO4MX4FzjiOs3xYolNVEoIaUkEMkLhUjoQg2QOkntpJqYl16YiqmZQo+uDsdxPhpJ6BF9L3XAud1Ugb2+P4R1td24SRCYeg5WBIoMpRIPj+1ircxIgem2CJTlVJiKWLBTFA4ur5sCiPokxKTQy6dES10ZNFU7gHwkml8CaWWVgSuCHrfwI/wo1dFuBgA3ySMtRMz7LTfV34nUN2H8JFel5VESG2UFABKHLzcoqIJZtjACiTEjuBzDLpUtVGTxFtmvcHwd0P5Fba9IPp1LfhUh8L8pcBDPV535/ZCC+mzb8EzLg8WKTjgEXEkOWCQkDiUjkSgkU6QJmUnhh06XJVc/eTn80TpqRwUlorwU3H3MNO41MJFje8DwJ/tkF4E2pXJDATJ1iiU1USYuXkgkJA4ur5sEhHOYJ7tpjXKTUx6NLlqmZSouj4vMkeTOp9817hJCsJt+PpGailaI7MwwEe4sHj6zCqwAfAcIUjYyMs0akqCUExqSAGiFw1H5I9ijYpNbFpkME8hcGT9nySqpmUKPohwHwwqfq1ka3qCsomfw7UrbG4dhvcR57WRP0q6PCnL780pcAbsFgmjjDSj69SKlqzqhBBTwgDFlQOSEWZf5mZclRVB9D/KFhSqJhrynYCD9YOT5rRIqr2mhLa2zz0/IleMKnksZNzr1BuaKeZgaejszOXqcuQPD5nvqRS4fWxn3sKfHT5+w6JimyEkV65g8JozaoiYesK4aygUkAqClw+zMNUXTqaFIPtpKgTSG6neMoXJ81oEVUzKam9LXj9bXb3yzOZM70n9xzONLfSMtgGKuzNTCQCg/hJIeOaE4dtQXioAKKFrHk5Mpm8ZqX7FNM2k8JXKorSpRmNwu0qqZpJkWhBz/iD1ymrkB2N3ODnc3Dc6KkwhUvw6GqSfw8ZgWGJJw33IUwFYYQKIBpm9cpBVE9KPQ217TXlJdalGY1S2VVSNZPS26tNasZphtYh2G8cKkzBElxZGelmUhE4yePCzPmOwVSQBVWAmGFWrxyEGZkouGJPOWwm5RKzdnjSnOZkJVUzKb292qRWnGZonZ/rG4cKU7AE12e/zZUi8FgeJ58ZTAXZUBUgnTCrVw7CjEwUXLGnHDaTcolZOzxpTnOykqqZlN5ebVJOcs9b2FPeBXyd4s5h9pJqrd1XJU5MSd/5quF7EpB6al+n/tkhqkYkq/x3FJH4vQaLPf2vJtU2v/Wzj/+PQgfq7TsLPuOoZL/3k7Bd+BTVcuZCe/5vxnYjqFpiV+sAAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left [ \\left [ x^{3}, \\quad x^{2} y, \\quad x^{2} z, \\quad x y^{2}, \\quad x y z, \\quad x z^{2}, \\quad y^{3}, \\quad y^{2} z, \\quad y z^{2}, \\quad z^{3}\\right ], \\quad \\left [ y^{2}, \\quad y z, \\quad z^{2}\\right ], \\quad \\left [ y, \\quad z\\right ]\\right ]$$" ], "text/plain": [ "⎡⎡ 3 2 2 2 2 3 2 2 3⎤ ⎡ 2 2⎤ \n", "⎣⎣x , x ⋅y, x ⋅z, x⋅y , x⋅y⋅z, x⋅z , y , y ⋅z, y⋅z , z ⎦, ⎣y , y⋅z, z ⎦, [y, z\n", "\n", " ⎤\n", "]⎦" ] }, "execution_count": 27, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.get_row_coefficients()" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAA0MAAAF3CAMAAABQamBPAAAANlBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABHL6OuAAAAEXRSTlMAMquZdlQQQN0iRM2J72a7fJC/CQQAAAAJcEhZcwAADsQAAA7EAZUrDhsAACAASURBVHgB7V3hYqrMEsOq/dpT217f/2XvLjvAYhGTKCuL448D4oSZyWyq2JLT7M7t463xhzPgDDAMfCTpNM3uvD+Ex5EBe6wz4Aw0P1E4b+eooZ3T4Qw4AyIDP64hkTmHOQOJga1p6H1/+jlJb6sy8hWADd0kDIADTbJs/PKwrWnoK1zVvX98Cj8iZeQrABu6SRgAB9pM2fjlYRvT0M93pOz0ZcQRGxn5CsCGbhIGwIE2Sza+AGxjGvptv6A/nt8J9aRQGfkKwIZuEgbAgTZRNr4AbGMaOrca+nfmv6eXka8AbOgmYQAcaGJg4wvAYA197k/7wzfx850GWLeNDAxXQud9PMu/86E7GbqVka8A5HmFWYEDbZBsfAkYqqF/3+E6/St8ER4eO+RyIwMcToeT9QJsMuBp/7snVNs0n+c20S5tgGR9iIx8BSDPK8wKHGiTYuNLwEANvX//hGr2v+Gf3f7twyqb2WSAn7Cuj/AfEmXAU5DtG6LXvo7P9D4kaah9B+ORcsqKgEFDJDswAA60GbPxJWBXNPT+9dE/vsKvW/btVfpH+oh0BDSUAT7+hUbgq/wcGDS0OzPfU4vv9KE+GfkKQJ4dmBU40MTAxpeAXdGQpe433/Ed6N3+JgjR0ABIqG/0Kn8ANlF8n+eoQPiRrjiP8ncKAlJOWRHQvlMg2IGbgwNtDbDxBWCYht7bC4xjuhxqAA1lgPRO8hE/CwKPDNhGk19T/0atNz/wu95QkYx8BWBDNwkD4EAbFRtfAIZqKL6N/H41x/jJCtJQD9jlHwOto+ub9/YtpMvUNPbx8Tpg/Er6DdyeuohKZ5CRrwC037ESvMKswIE2aDa+AAzTUPMVroR+Pt6a9msvQEMZIL0PfaPfNo8yNaf2Wnask9lnH0G779/KH8zJyFcANnSTMAAOtLmz8cvDQA29vx1Ou8+3Q3txgmhoAKTrIfiyZgCG5n9YCTXvp3A/hyIhHSmnrAjIswM3BweaGNj45WGghqyQtEE0lAG47+UyYPMvvO39kwSRn8X3nYFFGZA01P5hJ1zWIbyZ4L8fyk67+zoej7/UL1kztO86A2UY4DX0uf84v6FXN20Tp/BnQooSvtub1cvw4FmcAZUBXkNqJsc5A9tkwDW0zbl6V+UYcA2V49ozbZMB19A25+pdlWPANVSOa8+0TQZcQ9ucq3dVjgHXUDmuPdM2GXANbXOu3lU5BiANibZ4d3RRPqNerFxrRUD3aJxZH5CGRFu8mbS3Xiqf8VZF11+Xa60I6B6N1+cfble77VmfbtlQjA9nEs++VD7jbDmzL8q1VgR0j8a5JYBoSLTFm0t747XyGW8UNPOyXGtFQPdonFkA0PtQuoVdMT6cyzz3WvmMc9XMvybXWhHQPRrn1gDwPiRaqXRZBctFNaOQKlUpA1/DEMh9fWbvUwA0JNrimYYyy0XM3DHgxIxZqgpsIcUmZXbuAPIDgZuDA205sfElYJCGSIM+q7vdZJaLmLljRGlGfFmqGmwhtSZldu4B8gOBm4MD47oIDzY+oZaFRQ29H2fvkKM+Wd1t7hibpjIaSyMfSe728+fYQmpNyuzcA+QHAjcHB9qY2fgSsM/gg3Pr/2NNF7+EQZ8VHjeZ5SJkqpWgUsYhVR22kFKTkZ/yQD4lXCMcmFYGX8kdKwqkGvgsxxv0WbthM7ZchM1MFCO+LFUdtpBKky2z5YH8EoBrhANtUbHxBWCIhtIvAwmDPqs7bMaWi7CGlIxZqjpsIZUmW2bLA92jcVjSf/cQDfEGfUOekeUirCEp45CqEltI0W0wmL+qRpQykE8Jp4IDbVGx8cvDIA2Jtnix+pHlIq4hJeOQqhJbSKXJdkWUB7pHo0lxagNpaAqoHMM1pJw9w3Dfy2VAt4XMyfB9iIGyGuLMHaEGJoPcFnKSFj+4CAMFNcSbO+oduy2kzp0jSQYKaoiszMOdgToYcA3VMSevcr0MuIbWOxuvrA4GXEN1zMmrXC8DUUP/nf9bb4FemTOwcgb+B/gprLwFL88ZeCoD/lnuqfR78g0w4BrawBC9hacyAGmovJmgzIlcqpxRB8q1lge6R+PMmCENlTcTnKl4/iW51PnTLvKqXGt5oHs0zqwAREPpfhXBo1EGzhQ8/1L5jPP1zL0q11oe6B6Ns4MEvpcrbyY4V/Hsa3Kps2dd5kW51vJA92icWwLI+1C65V3waJSBcxXPvlY+42w5sy/KtZYHukfj3CQBDYlWKqo9T1+tYJyoliqkSmXKwDvYUZvk3Xn6UdApYQAcaLWw8SVggIZEW7x7PAFj55njops72lJoN0+YB50SBsCBxgAbXwIGaUj0aBT99FLbmeOimzvaSkgbmVYZyFscwqngwF4M0mJk01DZoobeD4/zaMynTb3vurljTt3cPkVrfiIZyH8KhFPBgdYIG18C9hncuBfzaEwXv27umC/kYV9mpzyQd0aEa4QDjTg2vgAM+CzHG/R160T004vwzHExPIPNTJSMWSo3d+xGd7GleYUBcKBVxMYXgCEaSr/TEzwaZWDUUPBQa36/muNn2MIaUjJmqdzc0Zbc5YbmFQbAgVYSG18AhmiIN+jrRiD66UX44LgYnsAakkodUrm5Yze5yy09SRgAB1pJbPzyMEhDT/AEdHPHy1WcPX/CPOiUMAAONALY+OVhkIay8T1nF38furM+N3e8k8BXhFeiITd3fMXFWUnPNWjIzR0rWUwvWmYNGnrR0XjblTDgGqpkUF7mahlwDa12NF5YJQy4hioZlJe5WgaihtyjcbXj8cIqYMA9GisYkpe4agb8s9yqx+PFVcCAa6iCIXmJq2YA0lB5T0A5o062nFIG6rWqSL1UGgkD4EBrmo1fHgZpqLwnoJxRXV3hD8Xjf1j/Ee+0IB8ykMzzgHC9VBoJA+BA65+NXx6GaCjdslHSo1HOqK8zOaUM1GtVkXqpNBIGwIHWNBtfAIZoqLwnoJxRXV3hdr+3iD2eZ60lpk4vA6dOtuwxvVQaCQPgQKOGjS8AQzSUbmEv6dEoZ9TXoJxSBuq1qki9VBoJA+BAa5qNLwADNCRaqcT7uVsfo3/n4HtCPWRgyqIYJ8opRaBSY9udDLxjHvwkYVbgQFtAbHwJGKAh0RbvDo9GOWPLmGLuGBzUThG8SxtjHtlowKzGw+nQpkaSjZwrT/vfPfXJUys11kUjYQAcaPSw8SVgkIYkW7zIfGlgZEwydyxca1bjTxDQsb0Ws3HPbjLgKXyF+PY1G33xojwPnh04FRxovbDxJWBRQ6vwaMznTb1hP8Tckf+00tVL1dqB9u1XFx/xMy5393kODBpKHirdWW9tpVLbk9JIGAAHWnNsfAnYOj0a04VjSXNH3oWwW7FKrd+/Af1+3tk/zXc0AkMeA7AV3+f5H4LqYpRSE5ZGwgA40Jpg4wvAgM9yT/BoFI34Il+Z42J4hpuZyCkFYFZjHa6Q/BKAWYEDTQxsfAEYoqH0a62SHo1yxqghydzR/qe3Mk1mNdbhCsmzA08QDjQxsPEFYIiGJOPDtnbRTy9cJcQ/vPkOn3X4x+C4GLD4+5CeUqh1qLESV0ieHZgVONCWAhu/PAzSkGiLF2RwOhzeFCXIwJDz7XDafb4d2isFQkNySgE41NheFDXwZc0ADEvjp/3a09YItBFKtfPSSBgAB6qVJBybhsgGacjOV+GG0NCTuuO+l8uL/Be+Ff+n/IDKT+L79zOwdQ2VMneUJ3EIbyb474eyNLuv4/H4S/2SNUP77uMY2LSGSpo7yiM57U/cnxtYpu9zfMhpHfgwBjatoYex5CdyBq4z4Bq6zo2/4gwgDLiGEJY8xhm4zoBr6Do3/oozgDAQNeQejQhTHuMMTDPgHo3TvPhRZwBlwD/LoUx5nDMwzYBraJoXP+oMoAxAGhJt8cLfru1PPyflz1HKA1HC/sbVVOvf6sEjdJMwAA60Stn45WGQhkRbvGf4HsqlgmtpIkxOKQMnilj6EF0rDIADrUU2fnkYoqF0y0YVHo1yqfoalFPKQL1WGUnXCgPgQKudjS8AQzQk2uI9w/dQLlVeXS9h7sg3CQ8CDrQJsfEFYIiG0i3sVXg0yqXqGpJTykC9VhlJ1woD4ECrnY0vAAM0JFqphG8Uins0yhmNacEAUU4pAoUSU3MyMMDpWmEAHGgTYuNLwAANibZ4grOfNcxbAt4NTCfInBObHWjdVpidrMRy5o78QGBW4EAbMRtfAgZpqLTVomjEd4crZEt1ZoC42799GP03NmVrzUosaO7oHo2zTrRRQ3V7NOZrnHunf4i7I5cyK1YC5h6N0TAC/m8qciBt7uif5WYd4zfm0ZiuODVzxyYzQCQcgeSUCnAoMZmZFDJ35B0s4ebgQPvxw8YXgAGf5XiDvu6nreinF74Ujz6gzQ/8U7ZLqAPDGTLnxPAMdjMpWWtWYlFzR55XmBU40GbMxheAIRpKv9YqY1+YWi6fMeTNnBPDM1hDJWvNSixq7ugejSbFyQ2iId6gr0sl+und4dEoZwwlD86J4QmsoaLsDCWWNXfkm4QHAQfaomLjl4dBGhL97cKP9uIejXLGQPXIABHXkJxSAA4lljV35CcJNwcHmhjY+OVhkIasjJfa4Bp6Ei1u7vgk4v+kdQ39oSQdOK7d3dHNHa9Mrvhh19Ak5TW4O7q54+Toyh90DZXn3DNuiwHX0Lbm6d2UZ8A1VJ5zz7gtBlxD25qnd1Oegagh92gsz7tn3A4D7tG4nVl6J89hwD/LPYd3z7odBlxD25mld/IcBiANibZ44S/QKvJolGuVBydnlIFyqTwQrhEOtBrY+OVhkIZEW7y6PBrlJvn1ZQg5owyUS+WBcI1w4H2ssWmIbIiGRFu8cBNd+zdnVZg76rXyy8sQ5dmRS+WBcHNw4H2ssWmYbIiGRFu8ujwa5Sb59WUIOaMMlEvlgXCNcOB9rLFpmGyIhtIt7Bv3aJSb5NeXIeSMMlAulQfCNcKB97HGpmGyARqSDGhiDRUB9VoT2YIBYml2hBJtIQlIuDk40Gph40vAAA2Jtnh1eTTKTbZDypwTN2fu2GTNnfa/+3dblrMbmE440NKx8SVgkIZewKNRtlqMQ8qcEzdn7pg3dwrOdG+Q/ytMJxzYi0FajGwaKlvU0Kt6NBpR7Yb6jPBK5o6N5O4I0wkH2rDY+BIw92g0ltNFp+buODgnhpPBRgxyRgU4lEiaO+bOldHC4fMc/VVvPuAa4UBLycYXgAGf5XiDvo5h0U/vKR6Ncq3xu5Nox3wM7+jxAWtIzigAsxI5c8eL5mKb0AURXCMcmNhVFyObhsmGaCj9fmrjHo1yk1FDx0D571dzDNcLuIbkjAIwK5Ezd7xoLjj/zVpP29Lrfr0OrBm2GTbeKloShmiIN+jrqBT99J7i0SjXum1zx7FzZXNqL+m7+c5sYTrhQEvGxi8PgzQk2uKFn9AVeTTKtYY23w6n3efbob1SgD/LFWVnKJE0dxw394NKCG+O5Z2NNw0tCIM0NPPjxl+6ZADX0CWy0HPd3LH5Fy78/u0K1VlNGtfQo0e1XXPH8Ovj4/H4C32n8GhW13w+19Bjp7Nlc8fm+xwfjyVsA2dzDW1giN7CUxlwDT2Vfk++AQZcQxsYorfwVAZcQ0+l35NvgIGoIfdo3MAgvYWnMeAejU+j3hNvhAH/LLeRQXobT2MA0pBo6RX+COYV/OXkJuWhyxlloD5JuclrQLGHBWGQhkRvrhfxl5PZubZKbh6XM8rARkfe7IYMECtZEIZoKP3deBU2cXKpur+cnpJcPH24nFEG6uz0RT9qR+xhSRiiIdGb60X85WR25FUlZ5SBjY6Uu7wCFCtZEoZoKN1+6/5y01OV2Zk+HXBUzigDGx0J9EOFiJUsCQM0JNpAxPs727tN/p2xWx8HKssDn1BrandJ77aB0LQn08qyAzcFB/atiD0sCgM0JFp6vYi/nMxOuywy77Z+mdzakTPKwGBEEh0jml3a3CoQbgoOHDJylfS4RWGQhiRLr6ihaoBPqDXONzOmCysUcm57Bq0cO3lTh9OhVV+/mPOdPBB1fxTX1KIwQEPi+6B/lsvXS9qfMabDzR3Lz4P7LJcZ0v0EAR3f/vKQjmSBsPuj2PyisKihW38vl67HBOu1ioB21VyyybCQBte38AS+ibw8rRQ7WVPzt53ngcERKZl2XRNcd1xsfkkY8vdyojfXM2zi5FJV37I7moxv1PGDzqqN6WzpErxmTc3bQWaBDe7+SFTSyS5ul4QBn+XsF2yAV1hedNxPv9iqAviEWqOGVm9MZyMlJpk1NW8HmQW2WTD3R6ISq73dLAlDNOT+cvk0/uyLhmfxPF/hW/+fj7emve6GP8s9YR5MyqGpG3aQQ2DLKej+KNK9IAzSkOjNFX7QvoK/nNxk4Gf9xnT2I4NocmgqvQ99X/v14BAYk6Duj0QlVnu7WRAGaSivxfeXYgB/H1qqgkefl7GDxN0fH13l3edzDd1N4aNOsD0NtV8VNJDJfc3uj66hR0ng7vOs3tyR7/AQfsl+/fdD2fmqdn90DWWTfOZuDeaOPD+n/Qn6zyerdn90DfELwxHOQM6Aayhnw/edAZ4B1xDPmSOcgZyBqKEb/6dxHu77zoAzcMEA8n8aX0D8qTPgDGQM+Ge5jAzfdQYEBlxDAmkOcQYyBiANif524UrLPRozri93ZXYuTwQ/1zPSSBoAN6EFivUgMEhDor+dezTOj1umdf60M6/qGWkkDZgp+xEvifUgMERD6d4L92icHmV5dqbrAI7KpfIejXoqoA8hRKwHgiEaEv3t3KNxftYyrfOnnXlVz0gjacBM2Y94SawHgiEaSveiu0fj9CzLszNdB3BULpX3aNRTAX0IIWI9EAzQkOiJEr5RcI/GmWnL7KRz8vaG+jx4JNgc2wQb39MP1tPH2w4GAzQk+tu5R+PlRMbPZVrb0+T2hrgxXXvPOei0mFdL14oBsiZmjei6UrJ41I/OoFg9XZ5+i8EgDVVjtSha8QXOZGR5YJxwZm+IG9PJpfLsQKmyJuaN6GxNZ/GwH51BoXosNttgMEBD2BtalrnbrQjIf1op2+SMuSNuTCfPg2cHSpV5NM4b0RnXeTzsR5ewUD3dSIctBosaco/GwFq6eizp0ShnDNVm9oa4hvQeeSTS3NDEvBFdt6aHeMKPzsBIPV2ebAvB3KPRGBNN/GT3vzuA8duasuaOvMUhQGfWxLwRnU0oi2+PYH50940XaCO4m4X3od15Z5mmN+kXTVVYLcqlPsGjUa81aKisuSPPDtBc1sQNI7q0LLP49gDoR5fAQD1Tix+CIRpiDPrGhYjGeM0TMj4hpcxOeXNHnh2gucGj8YYRnS2qIT4eQP3oDAzUY5GjDQKDNCT624XPHO7ROJrI+InMTiC2sLkjP0mguaEJzIhuiA88sn50QD3j6aRnCAzS0NTJ/dhqGNiAMR30vVxO+Jr86FxD+WTq3N+AMR1sRGcTWpUfnWuoTt0MVW/DmA41orO+V+VH5xoaVqPvOQMKA64hhTXHOAMDA66hgQvfcwYUBlxDCmuOcQYGBqKG3KNx4MP3nAGWAfdoZBnzeGdgzIB/lhvz4c+cAZYB1xDLmMc7A2MGIA0hRnXj09qzioA1+UnKtE4OCTpIp4QBcCBU56ODkOogDSFGdZPFVwRsKqpVLnVySNBBOiUMgAOhOh8dhFSHaCjdROEejdPzqYid6QaQo3STMAAORMp8eAxUHaIhyKhuqvyKgE1FtcqlTs0IO0anhAFwIFbog6Og6hANpZvK3aNxej4VsTPdAHKUbhIGwIFImQ+PgaoDNISZm0yUXxGQd67p+q2pybZmxeeQbhIGwIFy7QGotNzmw6oDNIQZ1bU5x/9UBAwOaqJ/YUXAdjqZz2GDmjvy7MCswIGx+Kx2yNPRlmMGW8TaEdKQezTaNCY2mI3fKoCxiMznEDd3XMijMdbD0JfVDnk6xvOHRwZbxtoR0BD2hpbqHf1bEXCzn+UeYu7IswOPHg4MKyv3aPwXnp/fR8vt2pMctoi1Y9SQezTGgbzFGVTh0SiXGhrMfA4Jc0eeHbhGODCvHfN0jAMNj6zlaNvweY76Ax9Qde7RaGxCbnxTzFcEDJ9rNHPHRTwaE5k4fVntkKejDSuDtUceb+0IfJbjDfq6pZZ+Q1WFueNrNBk0JJk78uzAo4cD89ohT8deQ3nLwbrw0C1PYAtVh2iIN+jrqkMc7rrY0bY88DWabEY+h4SpFj0QGAAHZrVjno62okYtL2HtCGkIMaobSaB7UhGQdyGssUnV3JFnBx49HJjVjnk62oAWt3aENNStFt9uiwHifWhljdOejlb/ItaOrqGVrY6S5dRr7sh6Ohqry1g7uoZKLtpV5ara3JH0dDTil7F2dA2tal17MRUy4BqqcGhe8qoYcA2tahxeTIUMuIYqHJqXvCoGoobco3FVI/FiKmPAPRorG5iXuzoG/LPc6kbiBVXGgGuosoF5uatjANIQYlQ32VlFwJfwaJTnMTnd2YNwKjjQ0rHxs1U+5EVIQ4hR3WQ1FQFfwqNRnsfkdGcPwqngQEvHxs9W+ZAXEQ2lmyjco3Ga8JdgZ7r1maMwK3CgJWPjZ2p81EuIhiCjuqmCKgK+hEejPI+p4c4fg1PBgZaPjZ8v8yGvIhpKN5W7R+M04S/BznTrM0dhVuBAS8bGz9T4qJcADTHWK6OyKgLyzjVdpxU1KZdqvRJWh3AqONBqYONbGFF4N9a4RWGAhigbvVEN9fge8i6EXaMvwU7bbGZ1eNPdEWYFDjS+2fgIywpfxNoR0pB7NNoEJzaMyeAIXhGwrTuzOrzt7gg3Bwcad2x8gGWFL2PtCGhIevuMLVcErKnWQrTe5e4I1wgHmobY+ADLPRoXsXaMGnKPxsB0ulbdtkej3GNcwJnVIeDuCKeCA2MN4cHG54UvZO3oHo1pNLwLoeFeAhh6HVsd3nQzga0X4UB1TlnhC1k7Ap/leIO+bnml34e5R2PHx3hbEztRQ7nV4U0Nwc3BgUYeG58XvpC1I6Kh17AvxL0Cx1J4DXaazCEx9H9TQzgrLO9sfFb4QtaOkIZwG72L5VURkHch7HqtqEm51NDryOrwtobgVHCg8c3GZ4UvZO0IaahbLb51BhIDtzW0SqaWsXZ0Da1y2GsvqlJ3x2WsHV1Da1+uK6yvXnfHRawdXUMrXKNeUlUMuIaqGpcXu0IGXEMrHIqXVBUDrqGqxuXFrpCBqCH3aFzhYLykahhwj8ZqRuWFrpQB/yy30sF4WdUw4BqqZlRe6EoZgDQk2+KVBb7/fn/oNJetNdZZUUaqVm4OAgtcgrQkhDTojCANybZ4pYFfb4kw5d/StYa/hA53E7x/fPLFlgeStTJzkJphEiR+pTTYjBANpVs2avBobO9x4ddkRNTT5BNKZVMSc9B4JxKk5aClwfpGNCTb4pUG/ju/awIKqNK1VpWRZIeZg8Q7kyCtCCkNOCNEQ+kW9go8Gk93XA5V02RnKVByHuZigKZk5iDxziRIGpLSgFQDGhKsVFLdxYFfb4fDPt6yzD+K11qTkxBbKzEHjXciQVoKWhqwb0BDii1eW3lp4Pv56z20HS/Sd1+kjErXGlw0N+tgOczhtiWixMKQ4LT/3SOf36U06IwgDVXi0XhsL4fC0rztIfhHYYL3XzrHKwCD3pkl0M8BsETkzmxj6xOcws/LN+THpZQmagjpG9CQ+D4YvrdNFfw7H/4s2fkDIrA1EDIrJPbKSExZvslnZCQn2c8BuPUa4v2PXWSUTRx0/MVAMhqZX1BkA/3JoOqaqKGteDR+xR8a6bqXv98/XXS6R2O/fkY7FDvdHCBLROrMVlOXoIki/TxH89JbDyVNOCcE25JH4/kndJ2cYXkNsV6B/dBeAcgZUXZzgCwRFfq6BO0M0ge7fhxXdpQ04VQQDPgsZ79oWr/VYvyBlAzKAf+zS67TL+HW32Sou3ypXMpuDpAlotJMl6Cd4Qd0paCkQalGNIT77V0uTNpPrzuBBHwL70O/7UWgoKFamowMSezcBaRSdnPALBGFZroEsaVTGnjcnX0IaeL5EBikIdoWr+umLPB9f9jHj3PhwX+Wc4/GxNyVf5lJdnPALBGZM1txXYLw9AeUkDpepDpIQ1d4XfFhQUMr7qbW0oDv5e5s7d8pfIu0u/Mk98K3qqHve4lx/P0MiJaIeOLd1/F4/EV+yYqfk4/cpIbq9RDkB7hqhGaJiLf0fY4PPH6ZyE1qaBmq/KzOwCQDrqFJWvygMwAz4BqCqfJAZ2CSAdfQJC1+0BmAGYgaco9GmC4PdAb+MOAejX8o8QPOAMWAf5aj6PJgZ+APA66hP5T4AWeAYgDSkOhvF6609qefk/KnGGWBiuffwHLZWmPe8hn5lEiNEu/IiYfh5HtKOiQbpCHR3w5zuMu77PdLZ+Q9//pSSfvCAVcTkK8Vm6DAO3bijOZsl0+HZEM0lO69qMGjEfPUy0jtdmnPvw7Y3c2zaXaEJsE1w/MOnniYT75Hp4OyIRoS/e1Ah7u8x26/dEbe86+rtKIm7yiV9GgM5GATFHjHTjyMJ9/j00HZEA2lm8pRg76s6GqAvOff0GU1TXbuAMIgSY/GQA7GisA7duJhPPkenw7KBmgIMzfJa7X9eoC059/QbT1NquY2oVe6SRDA8w6eeJhPvkenw7IBGhL97VCHu7xJ2y+dcfD8c3PHiXEIk8QmOPB+28zx3qUR8EO6x1o7Qhpq77fdJV/OSY6nD2IOdxPY0sDe88/NHSemEQ7RA8EAPe+AmaMVhp14uos+3YOtHQENYW9oE2VXA+xNBQUjhmqaFD6R9TOlm8QAPe/4TePYiVPhpawdo4a24tEYmEvXgKzTYu/5J2hITCnX+hQg3yQ0iI53yMwx6YKvxHBh06V7tLXjljwaA02Qp97Aqu1lnn+8mYmWUq71KUCeV4iVjnfIzNFmBZ3Y03NwAQAACuhJREFUYi82Xbr28AOtHYHPcpxBX153+g3V+n0PM88/XkO1NBkGI5fKI6FUHe+QmaMtLOjE+SIc9rt07ZEHWjsiGoKM6oZSsz3E4S4LH3bLAjPPP15Dm2ennQo9EATQ8Y6ZOdrqQE48LKR8r0sXjz3S2hHSEGJUlxfb71cCzDz/BA1V0mQcilwqj0RSdbxjZo62qpAT9wtwtNOlCwcfau0IaWhUybafCBraNiFFusO/l3tMOY+1dnQNjadydHPHMSFFni1u5jju4sHWjq6hnF43d8zZKLi/tJnjuJUHWzu6hsb0+jNngGXANcQy5vHOwJgB19CYD3/mDLAMuIZYxjzeGRgzEDV06+/lxgh/5gw4AzkDyN/L5fG+7ww4A2MG/LPcmA9/5gywDLiGWMY83hkYMwBpCDGqG5/WnlUE5F0IQ4+K699A1KbZgZuDA++jm0gzTKjduzlkSEOIUd1F4vS0IiDvQti2yLv+DURtmh24OTgwEqfTTaUZZtTu3ciKaCjdsuEuhBfMtk9p17/hJBXRyntfws3BgffRzaUZhoRkRTQEGdVdpG2fVgQETQUvu+Rd/4YzbJoduDk4MBKn002lGWbU7t3KimgIMqq7yNs+rQho9+mz/oW869/A06bZgZuDAyNxOt1UmmFG7d6trICGGCuVUfaKgLwLYeqUdv0bCNo0O3BzcGBLnEw3l2YYEpQV0BDmt3eRNz6tCCjWOrj+bdrckWcHHj0cGBfUQDfs6Rhh4UGlSZD+3yHrFWtHSENb92hsSVaa7F3/tm3uGJYgyQ4MgAPjku7pxj0dTQlUGsN0mz7rNWvHqKEb/6ex/D5YEVD8LNebDArGdJtmB24ODowruqebvnecSUNbOyL/p3G6HmOND0PPFQG1WnvXP0FDWsa4lMrTyqeEa4QDQ+Md3YynYyQsPJg0CdH/22W9au0IfJbjDfq69LKfXnmg1mTm+sebmZRvUs7IswOnggOjEH7CP/vzO+PpaGuRSdMtX9t2WdunU9aOiIbS76fWb7UYmpRL1ZCZ6x+vIbnW8kCeHbhGODBMt6Ob8XQ0ITBpDNJtuqzt8ylrR0RD7kLY0Xm5zVz/eA3VRCtfK2ylCAc2TUc35eloMyPSXEy5yxoPT1o7QhqSbfEqAvIuhIHSzPVP0NCm2YGbgwMHuilPR1MEkcYQ3SYb8rS1I6Sh7my+vc6AoKHrJ/NX5hmgv5ebPx366hVrR9cQSuCNODd3vEHQI18u7OlopV+zdnQNPWS2bu74EBrhk5T1dLSyrlk7uobguXmgMzDJgGtokhY/6AzADLiGYKo80BmYZMA1NEmLH3QGYAaihtyjEabLA52BPwy4R+MfSvyAM0Ax4J/lKLo82Bn4w4Br6A8lfsAZoBiANKT721G1ZMFyRhmYJSd35ZTlgWRnWThdKwyAA60aNj5rQthFskEausffTqg7QOSMMlCrM6LklOWBBZuEm4MDrXg2Xu85IpFsiIbSvReCR6NcvpxRBsql8vaFXSq5VhnYZea3dEoYAAda0Ww832uOgLIhGrrH3y4vCN+XM8pAvLbLSDlleeBl6fhzulYYAAdasWw83uNUJJQN0VC6F521L5wqCT0mZ5SBaGV/4+SU5YF/i0eP0LXCADjQSmXj0Q6n46BsgIYYT5TJSk6Hw2E3+cqVg3JGGdjQNXalyynLA7uS+V7pWmEAHGjFs/EG41tugVg2QEP3+NuFSj7jXbhfX2FvF/9BHnJGFdjXeMWFb6ZoNaVuGyhnTF0MvR72b+8znWUv0SlhABxo1bDxLaxvOTz7zdq6uYtlgzREGvSNS/s+hedvx4awMZQd9VRgV+M1F75xR6Nnakre97BLK2dMJ+h63QeTnD24ouiUMAAOtO7Z+BbWtRyeTPny2KknNli2qKGHejT+cbg79z/r4NulsbfQiZ5FYLBbSif7+AzvlufwD/4QUwbWk3fov/MBT9ZGcsCr89iHn21x+siDSxnOCAPgQCuTjY+wfryhrlM3ajvf/AbL1no0xqUz80gXVoJHYzzn9/CjDtaQ7qinldrXGO/T/4xeSMRDSxkSlAfGrvpe4xP0fYivFW4ODoz1hgcbHyBZy4d3SkNYtriud+f5K/47/O3CD6T4US49cA3JGSVgXiP7bh8+YLc/JH642URCygND0lGv79/zg09jk2qFm4MDrRg2ftTy7khqCMoGXA/xBn0D9+ZNGVZmOIZrKP1qq5grZOtkmWpsmikXvryhy/3CtYb0csZYetbr4Qv+GEmnhAFwoPHOxo9aPoWfIf2lhZ1wdgNlQzTEG/Rlde3fwpP3ffyBh2tIzyhZ8WU1TrvwZf383ZVSxtOUB4akea/4Zzm+Vrg5ONCYZ+Ozln8+WQ1BfUMa0v3tQt+n089P+nlHaEjOqAGHGqdd+Gx80xstZThXeWBsYOg1XvvFzwfIg64VBsCBViYbH2DW8ntYhuT7EDQjSEMIyUAMoSHgbIuEXHHhWyTXc0/aXgt92ie755ZSKvtxHx7n+J3+Yx9FNfT92Noff7ZrLnyPz/T8M8YvYw/f1NXB84u+u4JP7noIyldOQzXYGF5z4YOorCxodzqc3uZ/qVFZR0C5P7/n8Ov+Bz/KaejBhfvpnIGVMOAaWskgvIxqGXANVTs6L3wlDLiGVjIIL6NaBlxD1Y7OC18JA66hlQzCy6iWAddQtaPzwlfCgGtoJYPwMqplANIQYlQ3yYAMnDwbclDPqCORuqZi5IzlgVPlzx+Da4QDLR8bfx9svsn0KqQhxKhuMpkMnDwbclDPqCORuqZi5IzlgVPlzx+Da4QDLR8bfx9svsn0KqKhdBOF4NEoA5HKJ2P0jDpyshDgoJyxPBDo5iIErhEOtARs/H2wi66mnyIagozqpk4vA6dOBh3TM+pIqLCJIDljeeBE9TcOwTXCgZaQjb8PdqPL9DKioXQLu+DRKAOh0qeC9Iw6cqoO5JicsTwQaWccA9cIB9r52fj7YOOmrjwDNISZm0ycXwZ256Kd9fSMMpKusWtOzlge2JWMO1nCNcKBVgMbfx8MGy6gIcyorud52JGB6RSDs97y5o6qY2Jf4wuYOw5um6eb7o7w6OFAW1Zs/D2wfrjhJIM7lZ0x20AaEj0aMYe7rJjxbuesV8LcUXVM7Gp8BXPHpmsWcHeERw8H2tpg4++Bdf2Gc8xaOwIaEt8+473rrfhAF8KrZoKEmQmXMZeshuzd/zZo7thcHQjg7gjTCQfasNj4O2D9cKPzxdztr4CGMKO6fEF2++n6rwpzR63J3v3vBcwdc6vD2+6O8OjhQFtUbLwO64cb7pmftTJBNAQZ1XW6ybcyMJwkNxPEzUz0jAoyr/HG+31Oi+0rGVtoeWBMO2r2prsjXCMceB9rbJpRvzesHRENpV9rFXNMNLIyM0FcQ3KpmvFhVuPmzR05d0d4EHCgLQs2XocNw71h7YhoCDKqs1rHG95Pb8BnZoK4hvRSJWRW4+bNHUl3R3j0cKAtDTZehvXDvWXtCGlIsMVLlcvACB/MBAkN6Rkl5FDj9s0ds4EA7o4wnXCgiYGN12GotSOkISvjaRtCQ8+q8XXMHZtXc3e8ae1Yh4bc3PFZPxum8r6gu+OstWMFGnJzx6mF/MRjr+fuOG/tWIGGnrhaPLUzcJsB19BtjjzCGZhjwDU0x46/5gzcZiBp6Bwf8T/b8ocz4AzgDHy0ymn/X/BDfHD/lS+exyOdga0y8NMq59D8HyucxRMdxICfAAAAAElFTkSuQmCC\n", "text/latex": [ "$$\\left[\\begin{array}{ccccccccccccccc}- a_{1} & a_{0} & a_{2} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & - a_{1} & 0 & a_{0} & a_{2} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & - a_{1} & 0 & a_{0} & a_{2} & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & - a_{1} & 0 & 0 & a_{0} & a_{2} & 0 & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & - a_{1} & 0 & 0 & a_{0} & a_{2} & 0 & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & - a_{1} & 0 & 0 & a_{0} & a_{2} & 0 & 0 & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & - a_{1} & 0 & 0 & 0 & a_{0} & a_{2} & 0 & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & - a_{1} & 0 & 0 & 0 & a_{0} & a_{2} & 0 & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - a_{1} & 0 & 0 & 0 & a_{0} & a_{2} & 0\\\\0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & 0 & - a_{1} & 0 & 0 & 0 & a_{0} & a_{2}\\\\0 & 0 & 0 & b_{1} & 0 & 0 & 0 & 0 & 0 & 0 & b_{0} & 0 & - b_{2} & 0 & 0\\\\0 & 0 & 0 & 0 & b_{1} & 0 & 0 & 0 & 0 & 0 & 0 & b_{0} & 0 & - b_{2} & 0\\\\0 & 0 & 0 & 0 & 0 & b_{1} & 0 & 0 & 0 & 0 & 0 & 0 & b_{0} & 0 & - b_{2}\\\\0 & - c_{1} & 0 & 0 & c_{2} & 0 & 0 & 0 & - c_{3} & 0 & 0 & 0 & 0 & c_{4} & 0\\\\0 & 0 & - c_{1} & 0 & 0 & c_{2} & 0 & 0 & 0 & - c_{3} & 0 & 0 & 0 & 0 & c_{4}\\end{array}\\right]$$" ], "text/plain": [ "⎡-a₁ a₀ a₂ 0 0 0 0 0 0 0 0 0 0 0 0 ⎤\n", "⎢ ⎥\n", "⎢ 0 -a₁ 0 a₀ a₂ 0 0 0 0 0 0 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 -a₁ 0 a₀ a₂ 0 0 0 0 0 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 -a₁ 0 0 a₀ a₂ 0 0 0 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 -a₁ 0 0 a₀ a₂ 0 0 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 0 -a₁ 0 0 a₀ a₂ 0 0 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 0 0 -a₁ 0 0 0 a₀ a₂ 0 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 0 0 0 -a₁ 0 0 0 a₀ a₂ 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 0 0 0 0 -a₁ 0 0 0 a₀ a₂ 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 0 0 0 0 0 -a₁ 0 0 0 a₀ a₂ ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 b₁ 0 0 0 0 0 0 b₀ 0 -b₂ 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 b₁ 0 0 0 0 0 0 b₀ 0 -b₂ 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 0 0 0 b₁ 0 0 0 0 0 0 b₀ 0 -b₂⎥\n", "⎢ ⎥\n", "⎢ 0 -c₁ 0 0 c₂ 0 0 0 -c₃ 0 0 0 0 c₄ 0 ⎥\n", "⎢ ⎥\n", "⎣ 0 0 -c₁ 0 0 c₂ 0 0 0 -c₃ 0 0 0 0 c₄ ⎦" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix = mac.get_matrix()\n", "matrix" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAFMAAAAUBAMAAAADwRznAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIma7zZnddlTvRIkQqzLsm4+cAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABZElEQVQoFY2TP0jDQBTGv7SJtiYpAamr0UUcdXByiJODCBkFrc0g4urQTdDVUXASoZmcu4hT8TZxEKRYxMku7gqdVIjvXf5wVwX7IC/fe/e73Lu7F8DwMYbNMTOdgevi7SST+ss8qm3B9Si5Rs+pANrJl45wVLkEqknSgRMApRBO/1UAG888UbeHxjdgdg8pewNMMHAsgEedSqNJQl0p74EZFmOgZoxWjvYWduV0zcmvzrcGgB1iOUdXMRtrGAeMloXxSXsKcMAZLoByETndGCVbobOIcMEyRa0P1pplaNND7b1A3QA2rTNijD4BtzGjeQHVAFa6mkozeg40BaaiYlsWHXGgUlIzGgJ7clvXnKJajRCLnjMcgRmto3QGWB1c0WCjvemj3t0B9oXGWi/DHoztPmXNQXqxxXjldx9kY3Sr1C6K2YrWJbULltTUnRqompuwaG054Ev/hytzZYZP7l+jH+YH96tTwlcb7qAAAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left ( 15, \\quad 15\\right )$$" ], "text/plain": [ "(15, 15)" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix.shape" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAOAAAABkCAMAAACo0swdAAAAP1BMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFBd4eAAAAFHRSTlMAMquZdlQQQO0wRM3dIonvZrt8bPfhUawAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAU5SURBVHgB7ZzZeqMwDIXN2k5YM8P7P+t4abFIrFMjtobAReuYHEu/ZRN6yheVDPZI1cmO2nEplQxZro/iZHyqN1TpYACTs7F5nv4UgGXW9m24SucArPT2KuvG1823TgHYdwaorTyWb50C8G4/AIqh9Fxj6xSAgwW8DaHPgR8Am6zN8i40M+MUTRuzBd9ysVDvviEzo9yG/Hsw8hsD3jq9cSt9odVHElziZCjTJIK8zduHs+AlEbbZPZsxpUo1gw2UuF8PQSBg2fX67dld/0iytH6QBl4SQa+DFtE3R0TY6jlNYyZzjN+4CkYAllU9HpX+WMnstq1d5YsIQCKobzqB4LYfEyMNKtSAyRC85BMBbcqXaGdqV37d58QAeoFTdaFtT3P7bnuhMjPTDGZ6og93kSlmX2RKu6gLtwVVBCARuBrUZolHHERo3x2+4rMD3U0hVB9cL2gPlnZK7pUqzIKJAjQVs4KErm4THh7TSEp97QqoISfdB30W3LgIUFV69/V1quxFKgKQCFwFu9CFm2Q2NieRVGsv++PJnxu1uVXrgjejELBM8zZp0txuiBhAL3B7MHoreaGm6efyqbLVfxcF+fTCjf1zKQaQzPW8qygRqpteMLdwtvRtke0ZgPaONnJYpXJdhvjPQTJsUhVFcZ/1SU/UT81YwCarhzR2R9korb7Lk6TZWaPhKVFpRyygdPzDdRfg4SVYmMBVwYUTeLj8quDhJViYwDtXELipC2eVk4sjAiGoIHBTuQwX9osjAiEPiNzUhSCMXBwRCXlA5KYyGS7sFkdEQh4QuakLSRi5OCISsoDQqmIyJN0CH1ccEQpZQOimEpJwk/i4cY6xHkYcEQoBoDUOwm5qmMr3Eh83zjE2Uujf+rGfW1DIAsK6PwZZ7BibAWdFpBlAoQH8GD7o+7/ayE0NvH3SRXzcKL/RicURkfAvazohN3VC8/xi6uNGu1XiiEjILlGF3NRnpknP1MeNBhRHREIeUAE3dYITeDHxcaMB5RFBqgAQuKkBpknXxMeNBxRHBEIAOEl5wYt4wAVBWOkegPMcYzZV2YnNAec7xjIQTrU5IBd4r/4LcK+Z3irOW1SwzCX/Bdpqylcet9H/ErueF115Uncd7i32ILNEgZuKayAW4mHBWRARVBC4qSCWPiUW4mHBWRCRB0RuKoilnwIBz99CofgkisgDIjcVpiIWwlHRSRSRB0RuKoqmxEI4KjqJIrKA0KpC0cRCN+jajjELCN1UBCgW2kFXd4wBoND4hTYsmhlzbn3HmAUUr7RZwu0dYwP48fknMLPITQ283XeJhXqI9R3jf5/czTZyUz1NoCUWGvfePJo64xljFx5FZJeo3PhFNmxgPmjXBo4xD7iJDUtpQu31HWMACNzUUG6+TyzUa3TuM8YuKogIAH3GB7VWcYx/NeAajvHvBVzJMf69gCvtiwtwpYk8bJirgodN/UqBrwquNJGHDfPOFQRuKq7H/kKQD6ggcFPBgPrU/kKQDw+I3FQw4ALjVxwRpcMDIjcVjaj2F6J0eEDkpqIR5cavOCJKhwWcZY7RCPsLXXTGMWYBxf7t/kILyDnGAHBv43cbx5gF3H+lzYoY7RizgF/XivD3J9A999QWG79ioU6BdYx5QOSmPkHRjv2FyDHmAcX+7f5CAzh+yYSea2rH8YAHGL/gwV26REJt1jEGgMBNDYXwffsLgWMMAH3Gr9aKXKKvhuXzLYhjfMIKTh3jEwL6SprWBTidj9d75Sp48m+ILc03qebui41er0R8xvYbYvNc/QfUHU15fLswzwAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left[\\begin{matrix}- a_{1} & a_{0} & a_{2} & 0\\\\0 & - a_{1} & 0 & 0\\\\0 & 0 & - a_{1} & 0\\\\0 & 0 & 0 & - a_{1}\\end{matrix}\\right]$$" ], "text/plain": [ "⎡-a₁ a₀ a₂ 0 ⎤\n", "⎢ ⎥\n", "⎢ 0 -a₁ 0 0 ⎥\n", "⎢ ⎥\n", "⎢ 0 0 -a₁ 0 ⎥\n", "⎢ ⎥\n", "⎣ 0 0 0 -a₁⎦" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mac.get_submatrix(mac.get_matrix())" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [conda env:sympy]", "language": "python", "name": "conda-env-sympy-py" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.4" } }, "nbformat": 4, "nbformat_minor": 2 } sympy-sympy-1.9/examples/notebooks/README.txt000066400000000000000000000004341412543434000212430ustar00rootroot00000000000000This directory contains `IPython`_ Notebooks. To open them, run ``ipython notebook`` in this directory. This command will start IPython `notebook`_ server, and let your default browser connect to it. .. _ipython: https://ipython.org/ .. _notebook: https://ipython.org/notebook.html sympy-sympy-1.9/examples/notebooks/Sylvester_resultant.ipynb000066400000000000000000001046221412543434000247150ustar00rootroot00000000000000{ "cells": [ { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "import sympy as sym\n", "from sympy.polys import subresultants_qq_zz\n", "\n", "sym.init_printing()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Resultant\n", "----------" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If $p$ and $q$ are two polynomials over a commutative ring with identity which can be factored into linear factors,\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$p(x)= a_0 (x - r_1) (x- r_2) \\dots (x - r_m) $$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$$q(x)=b_0 (x - s_1)(x - s_2) \\dots (x - s_n)$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "\n", "\n", "then the resultant $R(p,q)$ of $p$ and $q$ is defined as:\n", "\n", "$$R(p,q)=a^n_{0}b^m_{0}\\prod_{i=1}^{m}\\prod_{j=1}^{n}(r_i - s_j)$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since the resultant is a symmetric function of the roots of the polynomials $p$ and $q$, it can be expressed as a polynomial in the coefficients of $p$ and $q$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "From the definition, it is clear that the resultant will equal zero if and only if $p$ and $q$ have at least one common root. Thus, the resultant becomes very useful in identifying whether common roots exist. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sylvester's Resultant\n", "---------------------\n", "\n", "It was proven that the determinant of the Sylvester's matrix is equal to the resultant. Assume the two polynomials:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $$p(x) = a_0 x_m + a_1 x_{m-1}+\\dots+a_{m-1}x+a_m$$\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- $$q(x)=b_0x_n + b_1x_{n-1}+\\dots+b_{n-1}x+b_n$$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Then the Sylverster matrix in the $(m+n)\\times(m+n)$ matrix:\n", "\n", "$$\n", "\\left|\n", "\\begin{array}{cccccc} \n", "a_{0} & a_{1} & a_{2} & \\ldots & a_{m} & 0 & \\ldots &0 \\\\ \n", "0 & a_{0} & a_{1} & \\ldots &a_{m-1} & a_{m} & \\ldots &0 \\\\\n", "\\vdots & \\ddots & \\ddots& \\ddots& \\ddots& \\ddots& \\ddots&\\vdots \\\\\n", "0 & 0 & \\ddots & \\ddots& \\ddots& \\ddots& \\ddots&a_{m}\\\\\n", "b_{0} & b_{1} & b_{2} & \\ldots & b_{n} & 0 & \\ldots & 0 \\\\\n", "0 & b_{0} & b_{1} & \\ldots & b_{n-1} & b_{n} & \\ldots & 0\\\\\n", "\\ddots &\\ddots & \\ddots& \\ddots& \\ddots& \\ddots& \\ddots&\\ddots \\\\\n", "0 & 0 & \\ldots& \\ldots& \\ldots& \\ldots& \\ldots& b_{n}\\\\\n", "\\end{array}\n", "\\right| = \\Delta $$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Thus $\\Delta$ is equal to the $R(p, q)$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example: Existence of common roots\n", "------------------------------------------\n", "\n", "Two examples are consider here. Note that if the system has a common root we are expecting the resultant/determinant to equal to zero." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": true }, "outputs": [], "source": [ "x = sym.symbols('x')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**A common root exists.**" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f = x ** 2 - 5 * x + 6\n", "g = x ** 2 - 3 * x + 2" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPwAAAAcBAMAAAC3wc/WAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAMkS7zRCZdiKJ71Rmq90icBAQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADWUlEQVRIDb1XTWgTQRh9+c82aRrEe+NJFKSBokdbMTe1nUOhKNQGqxFRaC5trSBdFIqC2IDY2oM0aAXpQYOiCD2YkwepoviP4B+19VRrMVSpGGd2djYzyaaki3Sgme9733vvy+zMTihgjdEdxIodBlrPEYdKaHp9q1Ot0F3BSxHWPG/gzIju+lWzpgrxGxr1KiUbOM0wV5xXIrHgkg1nTdAXjMRqF2xjVK+146FC7dJqzIeWWzVGCdfyND5q5RHjaVipo2B+LaqvQLC05NEyqbfPdbwM4un4YNQWB7SkWgiOX8qpCM+CqWZq0S8LwmVS1BWLGTttR8zfaodT7FEZPozQnzLISLug0YM2AtRZ324LNqlM79WTChBK83QHPHGlYCXujDtqJSwYyuGvDAiLV8AUEMmjkZhl157p7TITqFdTmFp39fdz4/RdYce1W2O+n7KLaH8L+BiFP47Hokof9aKI+VylvSer0qTsdrEoZUaoPnzRvp2w9oEsDlNS5+kzg+lyHV39TH8UvoG3m8d4zdQ27Bo7VEGWaGrtYMbGglG+E7gLaAZ8mfB8pFVVscxD6EW0H0/Ts7xmtu/eKx0YoZJoAjLm83PExoKW3L/pjfcD++jhJ1ohpCsqkezEZUyQBzwV7Qvw3xAEMUs0AfFZu2ZjQUuRZ/SlX8IcXT28cUvja1ugYzbKgV6dYLcRaolE22QiQUUNnxCuuJ4FjXFViykiaiULSkrRv+AKWz11TLPP8kF/vSZiwLLAzdXTfQrbvMwWTdDZfA5oyVVaAIEkrdLVG+0bzcUyRWlMAr2EbZA5zPb1WZvVSzRBZ3ORsPYVFsB9BHXQn9gXQIgMIUBkFY+TwCzuBRbRx3OzvYvufZYjpU+JVgKB6/SE61LNtIAriYDOTv4poCnXgguyyIyHEb7pXvEsBvMcENp3OJBTbxPINNlpBqFluSYsLo6PfgDCWTQRdA10njA7yFIEj70mvjd9/TMmKrRa6jmwoDwumSZ7uFM9MbkmLNqLRXoZ01uvLibTV42F1iBVeVNXNaD7nJYJ3jT8GRlYNfbpUlmT4tpDxQLd9GBnaxfLzE45cRg/obr3zrR5ZzJF9ZlmHQqynkmY7XsouZ4t5V5njeSODK1n7Pg/ov/2Jf8B6oTd7JsJTuYAAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left ( x^{2} - 5 x + 6, \\quad x^{2} - 3 x + 2\\right )$$" ], "text/plain": [ "⎛ 2 2 ⎞\n", "⎝x - 5⋅x + 6, x - 3⋅x + 2⎠" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f, g" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAJgAAABkCAMAAABNTAlxAAAAP1BMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFBd4eAAAAFHRSTlMAMquZdlQQQO0wRO/NZt2JIrt8bAICnK4AAAAJcEhZcwAADsQAAA7EAZUrDhsAAASpSURBVGgF7Ztrl6MgDECpWGbXF7rL//+ty6OxJlLTYLvTMwc/lA5FvAaovcZRFxe3Rn3INiUepS5Ot367fgiXGgNN4wLY5VOY7hzjGbChNeqin4i0ta1lT95oO95bUbBrb+7U3Ls+TAbLtVJm6JTSA9du8GdopvnWDIGZRjdOADbYpoWODg67aP/hshy0CB+NfXi1wI/A/AetBOy5ddy5J+A9eeztCsf/D2BLDEUIx+HmIljnblP2HNg4tpqd1G642Fb7aXa4GRcGXHWuTc1OgS1+Ps6OOaRxw+iP1TOLd06r6AKL6RRYPLdlSqf46NW4OG00s9znFLEiMDNM6zasI6i5ue0i+chE9pVD2cSlbZkjqik2G10Y0IMtTf7rKyZ/H4+oYYE/OmgTVyUXsdsX3Qi9nZljcRndAvKIytdfbnPsoEn4KH3BrheIM2BzIBt79uuz8Vctw61KpaZwSeph7mIw3fRuaJjJcD/zWdtGP3EJs1o3cMD73vSdsf7HztoMg9G23/h3BZMGv0asRkwaAWn7OsdqxKQRkLbHcww7p7Qvrj3rx1svxmDYOQ8OJPJi6IfxY+zFCIw4J3RIS6kXw/6MH2MvRmDEOaHDTCnyYtj/2I+JFyMw4pzQYaZ8Axjx4i0YFZUMEFSVgR36MfHiLRh1TqDIlEVgh35MvRiDRb1YnTMDBFVFYHHnR35MvXgL9uKhFPox8eIA9uW+UiSIc0J4MmVJxBg/Jl78Z3urM91cW50zAwRVJWCMHxMv3g4ldU6gyJQlYIwfEy9GYMQ5M0BQVQLG+TH2YgyGnRModqXQi2F/zo+RF2Mw6OIDygomHYQasRoxaQSk7cMcMz6J9nHb7BMRPy9f+c4w/8yvi9lauzA5Ih/VWetlWe/6Pgwztm0aMYnJxp8LVy7joUzQNjZ/ohS2bQQmNNk2plfST+KHcVCqiWu+57KWxLYRmO9d8kOr631G0NvNAVT4qI9JroZ7VIHY9hmwCMQP5RBTNiwYse2zYGbinyKIJzBB9ir+tX+hinYObLbTMykbj9FB5naPlGqobZ8D833aMNH4bTq+oxJS2Ni2JWB5g+2ZnHKE1kmRDk4gN5Rfv36ve0hW5RwTggvkZNc+9m9alkspYtt/f+GLuAQsZeGfALsGrnQae2ioIbYtGUroAso+PhUzccl6/1xS2IN72OaFGd4xZFyv8AQH4O7KefKXVN0wT0G8NMPbaX95ZhflkB6gY8GwbdOh3J3vd1VUMGnka8RqxKQRkLavc6xGTBoBaXs8x7BzSvvi2jN+jL0Yg2HnPDiQxIuhG8aPiRcjMOKc0CMthV4MuzN+TLwYgRHnhB4zpeSHLuzO+DHxYgRGnBN6zJQlYLGbx35MvHgLRkUlAwRVpWCsH69evAWjzgkUmbIMjPfjuxdjsGgNb83wMn589+It2IuHssCPN168BaPOmRlCqCoZSt6Pt16MwIhzAkWmLAFj/Rh5MQIjzpkBgqoSMM6PsRcjsPdmeBk/Jl6MwbBzQnh2ZWGG99iPiRdjsB3C91VUMGnsa8R+WMTiHSzuvrL0nIvbr/+RasJ/gLYteweu+EjCHeN/pLat+geLi0LWzT5q8AAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left[\\begin{matrix}1 & -5 & 6 & 0\\\\0 & 1 & -5 & 6\\\\1 & -3 & 2 & 0\\\\0 & 1 & -3 & 2\\end{matrix}\\right]$$" ], "text/plain": [ "⎡1 -5 6 0⎤\n", "⎢ ⎥\n", "⎢0 1 -5 6⎥\n", "⎢ ⎥\n", "⎢1 -3 2 0⎥\n", "⎢ ⎥\n", "⎣0 1 -3 2⎦" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "subresultants_qq_zz.sylvester(f, g, x)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAAoAAAAOBAMAAADkjZCYAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEJmJZjLNVN0i77urRHZ72Yd1AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAVElEQVQIHWNgEDIxZWBgSGeQmMDAsoCBOYGB+wAD+0cG/gMMvN8Z5BUYeP8xzDdgYP3MMF8BREJEgLLs3xm4NzCwfATpYkpgYGhnkApgYBB+d5QBAPogE3QldevOAAAAAElFTkSuQmCC\n", "text/latex": [ "$$0$$" ], "text/plain": [ "0" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "subresultants_qq_zz.sylvester(f, g, x).det()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**A common root does not exist.**" ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": true }, "outputs": [], "source": [ "z = x ** 2 - 7 * x + 12\n", "h = x ** 2 - x" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAANgAAAAcBAMAAADxd2x8AAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAMkS7zRCZdiKJ71Rmq90icBAQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAC3klEQVRIDb1WS2sTURT+kmaa91hEXJq4EheSiOjWitlJZRaF6EIaqKILC9m0VaE0KIiI0AhaLQjNP2hRRLGLZuVCfASUKriwSrUqWFIxKHQxnnncO2cm08S00rvI/V7nnrkzd6YF5Jg8pEm8GRAdPNO2PFpK9rYN/UvgLt6sH9tuWWop8Gf9UAfOV6RKPvGioQWylqOmIz99Mp1LnzCR9qnaZ2gh+aTiDZ/MRqR5uSSrjlaJnJWCau5U0o2DZd/Sz0DE2c6kJ7NrYWqq7NEkvTq4X2IPiBY8gkVHAMdJeDOvdF2v+dU90aDUMJ3280h76q9PALFZYe3FbgGt+RyQ5MojiygLHzQkNcQq3HRwsBzscZiD1CpSmk0Dx+YOOo6BysBNrtjNgHHqtIjkKjcdvGPugVjTEQl1Z/FMCDFdrwss5mBRIGPmzUKNdZvN6DqvkjhcwWki+bHLF13LikAXoIy+23PH4rwZKapztOw8y4oVjNmWgw0cIFJOLKu93Bb4HnASL4tLFvc0y5RFTMwsKyRjtuXAKvroQGrRRrzEbRsrdF9vY1p7bHFPsx9NFSzLPVumD9QX2hlCWWkqx1doLPUYQrgX0HDU9G7lct9zObo0GnRA6HkXDOgaImuK/cY6K0cI23JkzdgZsK1o+t4f1byG30J274ze0eYhs27LlGlnZrOUuRF3gNhAjX7oVtvD1SxewDVhyNnJSskAlkx/VF4DcW0cYc1lWyRVAB6G6xi2qKvZTuCCt4RluWXLdBovAZnZw7jBXYHnCwiuddUjVUvgzSLfpoYWlV8iac48ywwhJyrIaDg1mj9fZa6E12ehvB0eeW4LotnQTF81RN/NRay47gfPyjXo/NlL0BcklmZ6ayiaOSnfF8ax3ShURHfZLbVgJ5q8aJPSQhjQEKi08NtZ+XYB7r8g8p4LHeJqJ/mPFO7vpGAT2YTxvOjt3JJxxexyf0t6of2/yf/3Ov4CP+2+nhhj8lkAAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left ( x^{2} - 7 x + 12, \\quad x^{2} - x\\right )$$" ], "text/plain": [ "⎛ 2 2 ⎞\n", "⎝x - 7⋅x + 12, x - x⎠" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "z, h" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAKIAAABkCAMAAAAynRuAAAAAP1BMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFBd4eAAAAFHRSTlMAMquZdlQQQO0wRO/NZt2JIrt8bAICnK4AAAAJcEhZcwAADsQAAA7EAZUrDhsAAARLSURBVGgF7ZvrmqMgDIapWjtbj931/q91BU8JfgiMsdNnF3/MWAjJ24DUfLbqNpgjUx93tBOZUrchL8bj/nGEqtFc2aARb59HtxE1JxBvbZZ3+tjcuc/6PH+9/Kko867puJmFeK9KdxS7p5lWynC4iGePpTbqhqftw35dj8utbHvaTBHLLM+GCMR88nRAuHnMjN+qorHBeWMMupp2UcSxvYhBnCbYmhbqXJ/PHqtWv8h8q/5l3u+dUZxB1EHVszD/nH9mxNpE9SJOi+Y50N3lNOLLCTd1sHlpWXr2I8sh143Pgb7vs4hdsw/EWijic/Bc/P1kcGN2JxHLcc86Pihie3BlGS/9lMXvI5Z1ux71tHcV7NpDsAQxN7OIjJa2Kya69S3F5YoeIQovoVLT5XIXvFzK421bJ2fN4l0T9mxT1v38eJm33LCr6txaHG9AeIj9qwXxZiwLD+K0deds+ZxDvAcj9u34WZ5nZgPfv4+tpdUfgBX7kGaIeVYNdebbRjZ/qq/oHks6ltPVYz19nnsRy268+2KEiiEujj/rf0KUmI+UxZRFiQxI+EhrMWVRIgMSPthaBHW2RIzZR7gywGUBhgjqbAdilCQw+/ArA1gWoIiozkaIWwGPep1tHmVg82rJAhQR1dmOgMuNqqMbNvuVgdmrJQtQRFRnw2Dkdt/R72w+VAZmREsWIIiw/HLE+k4WjavDcox5XWUBggjrbGHEY2WAIm6yAEM0FRCvs2URPcoARdxkAYIoPdHxygBBJLKARnwMD5MsVGfLZtGjDGyIVBb4TYRkVGeLIvqUgRWRyQJkohWqs0URfcrAgshlAYqoQJ0tiuhTBmZESxZgiKDOhohrAQ973Y3HysDq1ZIFGKLb+U/2JESJ7KcspixKZEDCh16LZRHx4E8iaJyPfnxO9A8/j45Lxret06ZjUhejIABbK4uxJXyQfbiCoBSwpYhbsR22bgLtQxUEHRTZUsTRZLmpDGMMs49QEBSyfQNihIIwP6YUfaofkPWYwhLaXp/FGAUB2r4DMVxBuOSpPntyDC8yOHnQcrxbcH194/H1axkSsLYWU/M/xD5CQYBP9f98sduIkJCUMcQ+QkFQyPb6tRijIEDbNyBGKAgK2TLEtdimc3lwHmgfqiDoSMCWIR7Q/GBXQpRIfspiyqJEBiR8pLWYsiiRAQkfbC2COlsiRowPgMAQQZ3tcB9U4u/H+ocBBIqI6ux9mPFuJPKL/rOPkGEIgSKiOhshjm0hd9tgqHcYQqCIETW5NxbgC3lnCIEgwvILh7oqixCBIMI6+72IEIEhhtfkF020r9SHWT6RRfRU36MMQASSRVhnn0AEQ73JR7IARUR1Noijm7yx8DjvMIRAEad9k397Hoe6DBEhUERUZ78ZESEwRFBnQ8TAEt8eGzIMIDBE2+dnvE6IEvOQsvhfZfHjf2Ve6t9yF4X3h8ESsxbnw/zKvCjUX4xyQxa1ycz1AAAAAElFTkSuQmCC\n", "text/latex": [ "$$\\left[\\begin{matrix}1 & -7 & 12 & 0\\\\0 & 1 & -7 & 12\\\\1 & -1 & 0 & 0\\\\0 & 1 & -1 & 0\\end{matrix}\\right]$$" ], "text/plain": [ "⎡1 -7 12 0 ⎤\n", "⎢ ⎥\n", "⎢0 1 -7 12⎥\n", "⎢ ⎥\n", "⎢1 -1 0 0 ⎥\n", "⎢ ⎥\n", "⎣0 1 -1 0 ⎦" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix = subresultants_qq_zz.sylvester(z, h, x)\n", "matrix" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAABMAAAAOBAMAAAA/Njq6AAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAMt2rmYlmIkR2uxDNVO+L8+I6AAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAh0lEQVQIHWMQMgkNDWB3WSXAwJD///9/g80MrD8YGNwZGJgZrBkY3jEwBDAwBDI8YmCwB6pg4JjAcH4DhMkF5DIw6G8AEmEgFsdXIMH9AcRkMgASnAdATBcQwbQASHA6AAmG/SCpKwzsBQwM8kABRgcGTiDzPpBZFBpiBJSru8DAcP7//08MAOXiHWpRp63NAAAAAElFTkSuQmCC\n", "text/latex": [ "$$72$$" ], "text/plain": [ "72" ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix.det()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Example: Two variables, eliminator\n", "----------\n", "\n", "When we have system of two variables we solve for one and the second is kept as a coefficient.Thus we can find the roots of the equations, that is why the resultant is often refeered to as the eliminator." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "y = sym.symbols('y')" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAa0AAAAcBAMAAAAgmf1gAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAMkS7zRCZdiKJ71Rmq90icBAQAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAEqElEQVRYCd1XTWhcVRT+ZiZv/vMSRNxm3FhczaioCymOOOBCKm9RiC5CR5LajcHZNLEFyeBC/ANnoa0VsUEsLhsUUdpFZiUoIgMW/8Egaq1UieJgIcJ4/867592ZN+nL0IW5i/fOPd/3nXu+d++8lwDhKCweDeMbH5y6J0iwyCS9vY5LCVaakFpoT9cTlNhLbzeZ+r9irp1gqcmofjt1LUGFRL3lVOFUzdT/Ea9UEiw1GdWv5P9KUCFRb+merDxlz/mmDROsuUdqqZ9ImKS3N2XlY7b8ZRve+MhvJVojSW++2J+8fWyF5nWu9NziHdfJHEM75WAvnLnPyfDpUG/jesg1ASb4mBcaE3s9nK2MwRlUOscmkbDcjEyRb2KzG03xmdtbbA8X5F5tA8UNkqc76Vkdf0gp527y0wGK6wwqtdgkEi4s29MQAYDbcavOGHVuBzNbDsdOh3pzezBU78sfAhFeBebkXY2bL75v4l18Fbcw/SepxD3eF3JxvlIPX7xblzDq9Ns4UmdFo+FQb24PIX1NelgEPg0z5wcDE+/ia6o/ua/iYLCtV7NPZcw5HOrN7SF0oXydBJZExlv9+sDpEAGML52eP4a8+ZVYv34f8888e6KlRNQZY1KxUftlhRE1vCtgRamCt9LCi+YcyRzvwcUkrnxVA9wl4sfweesnmTTDaHW6cwE582htzWrH65Qv+3UlIF+MSZVG+GLCiDr/1lG4mCAUSutYo3LizntwMUlTvuZmcUjEr+Fs8JFMmmG0Kp3fWEKmpgFb83cUgkK/1FZ544szTaFRvy8m5GoRv1FxMZF8KVtXz54q8h5cTHKUL/GH0y8iDvAgyYBXG43fGg1pV6U9vIsZed5sHsg24WFKuS00Go+802j0xGkm5uE/5HhAlhy1X0YoYVi1mBTPUVHYEkGxhX8UV1ycHgizbPK1ofYLVqkqhM9EFkz3IbY1ml+RU+VWBnQOGVOm5RjhiwkVhXa7jcyOi0lCNUjxl2/Ym+zBwSSd9ktuDCJKe4ZVWpwD8XpRg2qWmnhefCGM29AXYxrBaF+hULGMr5m+8hXFJGEJuXVF1JdIDw4mGfr31cYXIv5AvBiOa5m6Gq1OZ3o4aDCqeQvwdClYQy5QAO0XY1KxEfvFhFxdrMG/5mKScBCirh28BxeTLOVLvA/FXqR3Mtv5rpWad45JZ2vpfw1mauavnFneqm7cj5d1nnwxJhWTvpzPLRMqllGXu9hsuZgkLKLaVUR94T24mGQoX+KjLKx5Xx1f+YxJjS+T9r5Zof8ATc2pwWCwtbA6/2RXi8gXY5pq2W///h7+z7w2mFDlSX3bE3cOYZKwcPqptiLqC+/BxQRj+fyhrvp7o1jRfH41WkqJ340eTp5w6ky8J4lJkLrzT0gEUBOrHsZ0ZokDTg8RLOQ9JFrphLMweDSMRHAJRypmHslbjtfWMWNaUEQjVmA4qVmKh9N1L/KPNe/BxUjnidOfWqdZzP0q7o1B3HQM02u5xCRzv5uJ1cdh5Z5Y4btdVjmwMrsLg+AYZpnwPd3Tq4/H6uIwX3Z8OFb2vwU+kZ2Lj+w+G/maMvTePrOFbLDfHFk//wEkcWXbNbjf6AAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left ( x^{2} + x y + 2 x + y - 1, \\quad x^{2} + 3 x - y^{2} + 2 y - 1\\right )$$" ], "text/plain": [ "⎛ 2 2 2 ⎞\n", "⎝x + x⋅y + 2⋅x + y - 1, x + 3⋅x - y + 2⋅y - 1⎠" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f = x ** 2 + x * y + 2 * x + y -1\n", "g = x ** 2 + 3 * x - y ** 2 + 2 * y - 1\n", "f, g" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "matrix = subresultants_qq_zz.sylvester(f, g, y)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAToAAABMCAMAAADKkIsGAAAAPFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo1xBWAAAAE3RSTlMAMquZdlQQQOkwRCKJZt3Nu+9spI9gpgAAAAlwSFlzAAAOxAAADsQBlSsOGwAABclJREFUeAHtXNmCpCgQpLx2tsRr/f9/3QQb5L6ZcmrwoUElM5KQq4xGhKoduN/7qZr3Bzh+nfToioeCZ4S6rbjbzztcL8YQep39AMdYPKQVqHud8OfbjoXw1Z2kdq86dVvfCM0n/PnKY6lJHWFsPN2D3dz3+17p0Xmf2NTjBaeCJ1E3Hm46xJDXQTzT8hMZYXFMy4wB1+CUCxsMUhMZVlKOAOpGufJT13eeliQEgnvhhGQVbx19CMehlLKdxoHbvLDrC4XFiRNZPHWAOwRTt6jMqdQdK6lHFzHahoMzhqzpThcVviHFZl6XujdG6C2PJUqr2+hT+BB1J6XufaatLWTqJphy5/eApS6qVBYegvPBCz5e2ziOuzwu6t7A4UoIFAxtD5pcd4K7DLV700n7xPuUqqsVs12QqJugkSwwrq9S79cr64pe9HHQlaMMrXuDhnkCsGgom8hnLnC5pO9sJrBkbUYTX2ntvkQdhmePoQGM0pyjV9YVvdnHjat7g0ZHp1kj+G3Ici5wViYsna9WV4Q60rW2/cbFGznWgyZ0XLjuuaJXffi9oZ72G9Vw2lZ+bMJ46QK/wUJyJTsswdM7vt5OfNHrPu6aGLzds7DLkLnwgbNyAek1TYxFpgnjjzJDZd2LE+cPO83bSJib6RDhNGRUFKRupz1scdeG4WqpNNaNE8xfUGQgnYcfWmWdk5zZB3emruvQi7a5YUY+Q+aiIHXXkriXJkUG409F6sgCZwfq5kWyi6LO4uN2qHibV4xx360wyxrBb0OWK0gdWskPsUMYSBlISCpSN3XDMA39IjOntZO+O86tUwoxLIsPdlv7IbZdb75W5DW8XDjBb5TA3IRhIZvIHBKps+Ap7cRSKvRyWW+hqDXKBVA3Sau83CDKesuNJsc+gLoc999s26hLfrqNukZdMgPJhq3VNep0Bmrr59/b6qrr599LXXX9/Iupq62f+6jLEnn18ec3X/GJXVn6uY+6LJE3mahSMnVV/dxDXZ7IG0id8kagnExdVz/3UJcn8qZRB1Zl3slV1s891OWJvJ+lrrZ+7qYuUzPSqDOr1EqHzWl1AkB1/dxNXabIq1JnUanLUScCVNfPfdRR0SVV5FWps8jb5aizAPA4dKQM/dxNXeEOq6rUKEUj5zwYMhoAL2NDsujnyCKgi/MXoe6fX/9yCCWTJ/IqzuipQaXW24IYocmJ65oBgBc3IKXr5//9MsrWDCxP5GVehNSkUhsqlKgqA5AJgONrSDn6ubvDojyRl4f8k7Go1FqFktd1FgAeh4qUpZ97qMsTeXnIV8amUqsVSl4S2wB4HApSnn7uoy5L5OUhXxmbSq1UCCXL1DYAHoeClKef+6jjqBUzSoX+FKQnUPf7VO2iSE+grmIzq+m6UZfMbqOuUZfMQLJha3WNOp2BJmHrnIRdaRJ2GE+GUk3CNpASdqn6FvCPTxNZKrKPRK+EDf8+v6ftS4TddMEb2EvJynJ143dhy/buM4+EPZP3nONp+Wd8k2uRhEDqysnKSkCRu7AVa8+pT8Ie6Bank+5m9rgitxUSAqkDw5yX3va44ndh232pd7wS9vuAf+mZzojdOiIJn6Yufhe2SpD13C9hU9OoDvsk6q6K013YVg4ibsRL2NNKNxILhi64x1FHd2G7Ig69Fy1hz3ilH50SDV1gj6OO7sJ2RRx6L0XCxmTA8xmyAAKoMyi4ohXzVCa9dmGX8JUgYSN0wAdvNEMDASRAkYRPTxMknFtFLkFfhIR9bWDef3ZhuwxZYM+iTlCRWYA5aYyEfVKl/Ic6pyGL6FHUcRWZRZeTRkrYB93AvsJn4nyGLKgnUcdVZBZcThorYdNN0yN0VK8hiyqFumRZmYFaUq4iW+5HXY6VsNG7h0/AkV8U5v3nKrhMQvg0ofr5E8+LiuV/F3VNwn5Gg/+7Wl1Rzht1yXQ26jKpq/RJ5+Sonm7IP+kM76rIAeubdoQxQD/pPAzofxopSUWPYvBTAAAAAElFTkSuQmCC\n", "text/latex": [ "$$\\left[\\begin{matrix}x + 1 & x^{2} + 2 x - 1 & 0\\\\0 & x + 1 & x^{2} + 2 x - 1\\\\-1 & 2 & x^{2} + 3 x - 1\\end{matrix}\\right]$$" ], "text/plain": [ "⎡ 2 ⎤\n", "⎢x + 1 x + 2⋅x - 1 0 ⎥\n", "⎢ ⎥\n", "⎢ 2 ⎥\n", "⎢ 0 x + 1 x + 2⋅x - 1⎥\n", "⎢ ⎥\n", "⎢ 2 ⎥\n", "⎣ -1 2 x + 3⋅x - 1⎦" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAJ8AAAAUBAMAAABhQvLIAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEM3dMnarIkSJZlS7me8N5bApAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACQElEQVQ4EY1VPWtUQRQ9bzfrfqpDJIqNLGuIFhZLRFJIdP9BNkUEi7CVpBIfWPiBwoLY6iqkEBSXWAQCwhMRO0kn2CSVoChYWoiuH2m00Hvv3Jnd55sVB/bOuefcOW/mzZtZINOuZhglKrEFxf64ivWQUNwMscKtWOVaqKB4736CXfrIVEEuRAIvDDBpC4+k6jW5jupPRHXNRrvHo4nD0fkLZFhuc17Zdqz0z2zWSfAdWE1JNpkLcER1yDD6wFo+5uibGt7qRt+AQ572oNj0MAXYEEeZupjioYbgJSPX9WK0tHKTJ1zYppko9iIBMXzAzDL9ps5cPtvmBEPDfT16KTRa20E8as8SrvUBh53GvRiuMXpFT+xVTuTrnAwNr8wber914TjcwUPznPp8MsReJCCGT5k5SRMx5a/V2Mp+yeWPtOwmJo9zm4bBMSnY04XH0WHWZlssiOECIxoXIbfJEHcbjVONxoxgfDaYGFgocUciGwIWC6EhZQjsbTtRZ3gJ2EpShhM/pISXDMVuDPdieIMRLRlYaHHkpoa/DRuWmpak+KQwwCL1vCkOe5GAGLpNqZoOCsbKavgJOB2PbErpV20gh5423uOM4Rtm6Nu5nWzB3SFquIHqDrC758ZE5xaXNzihSXvsROpff5npA9PM0Lr3L029pVSaGpbev+vSh91Cpo05elxnT1H46Fmfv06RkMHLwZYHL4cDVrNxdTRRXIsDpKX0+no5tiCqB6R/XLDqFLxgxSk8Gbd9mYf911/AH734eeMHxXpdAAAAAElFTkSuQmCC\n", "text/latex": [ "$$- x \\left(x - 1\\right) \\left(x + 3\\right)$$" ], "text/plain": [ "-x⋅(x - 1)⋅(x + 3)" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix.det().factor()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Three roots for x $\\in \\{-3, 0, 1\\}$." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For $x=-3$ then $y=1$." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAO0AAAAmBAMAAADaTAHLAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAZnbNRO8QMqsimd27VInIquLFAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADGElEQVRYCb1XTWgTQRT+0jTbbDdJA+LZRRG0l+YgqIjQmwfBRBG96WIVekvPXhLwol66lx60lQZ6sGDRgAeFouhFq3joxZOIRfDSg7+l4im+N5NmZjY/u5fMI5n93nvzvW/nJ7MbAEgVqbFns3tSh/aAnetoSeqMXrKjxyrb7wPgiNS7MSevFtpCmKXBpuW63rYg2JbwwrF/gLvLLiNb5k27O6QlRpqu21JlnTyPtRZQsxxSY808n6TS3Dyirz3bZqlUhZoLvURdueW6U6m42RnMTDW4JC+y+1cvfn/trXCX9KCB7xhetzOYeQ5nmHKFxvxT4zp1/Jhm/6QWVPBjAMwotycayBw7/fkNs24B402Nng2QqZAvp0NLMHTuzgdAwWfc1wYzM62WGOYU4L3SamSayPK8e6EWVHAqIHW+r/6WjPklxERDK5LelbqLWkyDrItjWqAbJmPWNjHhm2SPf9iTNK5JHwuBmRO64pdgxjUvGbNaBH0MK2+R+5rWMV8BLYNhQnefEYo6yZg02OWI7nOu9AJ4MF7Ch0hVofspEjTdZMyJLdBU06SeWid7Okfbu8F1LgJBxsdvgjOcWT/OUQjdmoBGo+gJmbSpauZ4aX3ISBflYMw4UijUT5cpbUvGJF1znvMN3KMKNFtYwUhlr1r7KnTPRoKmm4xZ3ULV14k3gaPk0+7ABnJ1PUVY6MbuqwRMGiwtsTL35ffVJrnb9F1D2VyCtu5jyjl/FMdEcUzZmzZVpq4R061Wi3V5Lme/Pgm1FMHVqyfoTsQWWw/MVMeLZYqe5WnkSh2OAp5QXFEBhdwm47zooKIdFMsUPQ8EKFQ6HAXodM+WnB0VUEg+FwoqYKJYpuj+rf3CY3LJewevmPO7whSQz8FrvVIiFscUnehwcn71KrGE0YMPeyXojtiKPXMcjGNyH6G5wShqg99Wor11Pwkzz6/O+3WWHUxHP1DdtCOmqWR4mUZY3K4dFnKX7YqS2nmhOPjAHcJNtWdY/GsYQvm+JRdCkXKe9e0xlITDz0q2RakvneG3Od7NbO6cvFpqr7POf3OSvg90eF49AAAAAElFTkSuQmCC\n", "text/latex": [ "$$\\left ( - 2 \\left(y - 1\\right), \\quad - \\left(y - 1\\right)^{2}\\right )$$" ], "text/plain": [ "⎛ 2⎞\n", "⎝-2⋅(y - 1), -(y - 1) ⎠" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.subs({x:-3}).factor(), g.subs({x:-3}).factor()" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAD8AAAAUBAMAAADIGvgZAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIma7zZnddlTvRIkQMqvFy5UvAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABJ0lEQVQoFX2Sv0vDUBDHP/nREpJXLQiuxrE4+GuXuDlmcHOpi3R0ETfJf1BnQXByNYjSSciiUhzMf9D+A4KDoqCI92wDeWnrd3h3ufuQu3f3wAqZqWWdWYD767sJRu2t5Mw1Jb4NOzxoz5CbqH1UBHaMfUognqkW3EAP6k2cId63mYYt6Gb0YRHmh/ifVeAHrhLcC47gOcb/qADqXYBDgpgNWEppfFUASwKDFDuiI0A8BZA/COC1Ofu3RONVA9KkN63JboIAUsJZw5645iasZvht3aQMqhZVmqQFu5KKuJVMh36u3kyknqhzqKVcSvzp+AUOMoNQvZMc3FyPeiSvcMqczFmWNVJQThS+LIv18cdjESxZvW79YP4Ujm3ZOLqsFcoxQ/LkfgFOMUE70U7oaQAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left ( 0, \\quad 0\\right )$$" ], "text/plain": [ "(0, 0)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.subs({x:-3, y:1}), g.subs({x:-3, y:1})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For $x=0$ the $y=1$." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAALsAAAAmBAMAAABuRvfEAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAZnbNRO8QMqsimd27VInIquLFAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACsElEQVRIDbWWz2sTQRTHv2mSrdskm4B48eKiCNJLcxBUvPTuIauI3uxiFXpLwD9gA17Ui7n01EoCBVuwaFFBpQh6a8FDL55UGgQPevIXiqf63szuJJv9YVcmj2Tej5nvZzdvJ5MAQK5Gg3ZbCIjHgkCrL9QlrnBJK5Zh1vp94ITEXm9px3/GTSAve35LOx0v4HVg/mLw5B/9+KfozgLivvNt/Xhg1wU8eqPbGQf+MUHzNg0PxkG3ekTNOTRc+C+8KbdFVJsTzTjME+ZPev+OLtlHZTlxzW2aKfQLLXJX6BN8TVj41k2YEOUzsZOsmaeZGx/eU8Sbf2qDfNSMO3fdaFVVcj0VDgKpsWxgbm+PyzNA6RUHMTbjxhSDUkl0OMiUZ43hqHS3g2pPZeEgFb8UXhtkQnMyyODtoGpTZkzbWHRVWQSp+OkUzRfFadZALzrhKg43KmSp+NcpmoMKQ7feZfy9qTreqKoMUvEvUzTvFKja5/4AbtHGd/Lzm2ynxHwUb5zl2Sctmr6YovGEnAd6rh7fPRru5OjXK4rnhb4RPlETwovmYAUTTiD1fSqempOoOadAzT6aNmdbKLfZD1kqnh5tombwaOnWqf1k62iIJnHsG+GNH0Ey6nnzxWuAh2oxPddim7OFj486qiqCtbnTNWy64aLKuAEJGsidwUsbsyjXpWZFuvBYGbmmmi2JiViNuaFWHXFhOZQdqBt0NkfNipZkhY60RI2tRJ+ACv+el2rlQVHNAleH4nC4najhA9m353R0fKO4cHQ1KIV8LZQNJ8uJmm21TKC3VJol+MePoUBV+C/OoSzUTGvpIAOaO5k0GRYXubcTfI2x2HFBvTwWNkHPC/DgjNB7Hb8t4r+aXrKgLXaEM56NgU1fKD602ZbkZWSibSzzvmEzW9LrHa8x7i/1GZLq14Wu0gAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left ( y - 1, \\quad - \\left(y - 1\\right)^{2}\\right )$$" ], "text/plain": [ "⎛ 2⎞\n", "⎝y - 1, -(y - 1) ⎠" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.subs({x:0}).factor(), g.subs({x:0}).factor()" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAD8AAAAUBAMAAADIGvgZAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIma7zZnddlTvRIkQMqvFy5UvAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABJ0lEQVQoFX2Sv0vDUBDHP/nREpJXLQiuxrE4+GuXuDlmcHOpi3R0ETfJf1BnQXByNYjSSciiUhzMf9D+A4KDoqCI92wDeWnrd3h3ufuQu3f3wAqZqWWdWYD767sJRu2t5Mw1Jb4NOzxoz5CbqH1UBHaMfUognqkW3EAP6k2cId63mYYt6Gb0YRHmh/ifVeAHrhLcC47gOcb/qADqXYBDgpgNWEppfFUASwKDFDuiI0A8BZA/COC1Ofu3RONVA9KkN63JboIAUsJZw5645iasZvht3aQMqhZVmqQFu5KKuJVMh36u3kyknqhzqKVcSvzp+AUOMoNQvZMc3FyPeiSvcMqczFmWNVJQThS+LIv18cdjESxZvW79YP4Ujm3ZOLqsFcoxQ/LkfgFOMUE70U7oaQAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left ( 0, \\quad 0\\right )$$" ], "text/plain": [ "(0, 0)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.subs({x:0, y:1}), g.subs({x:0, y:1})" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For $x=1$ then $y=-1$ is the common root," ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAQ8AAAAUBAMAAABhZ6XhAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIma7zZnddlTvRIkyEKtZsEGBAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAC7klEQVRIDY1WPWsUURQ9M/u9m9msBEWxmYA/wGgjIjKBJYVYLCRWapxCghCQtQiWdrbZIlUgsI22m0aDpDCNtVsIYhOjnZ1CwCAu673vvcm8O28meIt3z733nLNv5xvwQiRhwaRl8nymzpZemO2Y2u9o4IWm4SS2VvZzwPnlW2pOsCDaxq9gjFzl5f0bwDctySWoEVsr+0UER3g/5OaimmSX+g4QRNmurPOUXg+bIT5pYh4BSKzZ3u+hPUZjQHyCVtT7ujhcnRDYsyYulEozr51gNkZL2UiCa0321Q4aMdp/SU3QioSNGm/kizVxoVSaeXMbXyMEAy4lwbUm+wtAeaI3QtAKyS4PrZEDpTId06nBHS4lwbUm+w0lq/K/Jhhs9HFprFqS3eqpZsEilaekYJ3gGy4lwbUm+2tKNtqlRLBVH+CF6kCy/Uh381epTDje24cEr3ApCa61H+EJ8/CUF4IXKxGuM6Yruq+zvkbqsalyk1SmlHdD4CWXkuBak/028yrqwBMcN/r4TY1Wt7u01e0e8VBdrDM/GYoIltYoHh9Q01JaXaCxA3xkkUXItSZ7tRE6hZqN0XiGbyAKue2cjWiaWtkkVZqB10HpJN2IRXCtyZ5PTb2Hc5QYrqA20EaS3Yx1N3+VSsOZnaiNvOZSElxrsueL9QPwjBLD2ygdUaKQbD/iXlFIpWE1rqL6K71Yz7T2I767vPX91ZjUfKMtYxRSopAbqezSvX2sJ+4qlWbuh9jsA/e5lATXmuzpyJWn02lMbD6Ih3uPOpQoEnblx/F34hxQa23Mg5yQyoTw6t5Ngne5lATXmuyth6+GK8YnYetSPRrrZo+GkSapTPuEvJhLSXCtyd56HRFsR8EfFlIE4lfVS6+lJ+4qlWJ++tI705rtF1LdAqphqZ/WKdKfAZ/TRgYVK81nQDGBrZW99ckyh+bzB5mf0GVJHZ4wd8bNYqX5n8UEtlb2XshOKrxQZ3edd1ui44WiTIv//lT8By+sy4Yb1UdQAAAAAElFTkSuQmCC\n", "text/latex": [ "$$\\left ( 2 \\left(y + 1\\right), \\quad - \\left(y - 3\\right) \\left(y + 1\\right)\\right )$$" ], "text/plain": [ "(2⋅(y + 1), -(y - 3)⋅(y + 1))" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.subs({x:1}).factor(), g.subs({x:1}).factor()" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAD8AAAAUBAMAAADIGvgZAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIma7zZnddlTvRIkQMqvFy5UvAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABJ0lEQVQoFX2Sv0vDUBDHP/nREpJXLQiuxrE4+GuXuDlmcHOpi3R0ETfJf1BnQXByNYjSSciiUhzMf9D+A4KDoqCI92wDeWnrd3h3ufuQu3f3wAqZqWWdWYD767sJRu2t5Mw1Jb4NOzxoz5CbqH1UBHaMfUognqkW3EAP6k2cId63mYYt6Gb0YRHmh/ifVeAHrhLcC47gOcb/qADqXYBDgpgNWEppfFUASwKDFDuiI0A8BZA/COC1Ofu3RONVA9KkN63JboIAUsJZw5645iasZvht3aQMqhZVmqQFu5KKuJVMh36u3kyknqhzqKVcSvzp+AUOMoNQvZMc3FyPeiSvcMqczFmWNVJQThS+LIv18cdjESxZvW79YP4Ujm3ZOLqsFcoxQ/LkfgFOMUE70U7oaQAAAABJRU5ErkJggg==\n", "text/latex": [ "$$\\left ( 0, \\quad 0\\right )$$" ], "text/plain": [ "(0, 0)" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.subs({x:1, y:-1}), g.subs({x:1, y:-1})" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAD8AAAAUBAMAAADIGvgZAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIma7zZnddlTvRIkQqzLsm4+cAAAACXBIWXMAAA7EAAAOxAGVKw4bAAABMUlEQVQoFXWSvUoDURCFv40xxOxNWBCs1zJY+FcLsU+Rwso0sRHLNFYi7gtIehFJldYgStrtgpXiC5gXEMUfUET0XJOV3Ss5xc4w5+PO7J0LXshULVpnHoYH2/8Y01waUQ5U34QG5cgl8pHZwdQg16AY4inLqgqXMIBCgL+CaWVt2IBOzDUsQOkl9kMX+ILziHyXfTn3zxeub94EtPEbrMnyv+su4H3CY59cjT1Zx72PrkJank4QUGxxoh+55eg07SqftKg8WWAuoPLuAGjIToQAtbiReecC67AcU2rZIXUCqy5QhS11r3Gle6iTa5vXLFKIzBnM9ump/tDUsnbjDGEGhyPIj+xVj1VMkjSne9ayxvLTRpJrWX/jDZNiKtp12wfzq3AS02HGtvVCfaZIT+4HIgs9RHw/mCAAAAAASUVORK5CYII=\n", "text/latex": [ "$$\\left ( 8, \\quad 0\\right )$$" ], "text/plain": [ "(8, 0)" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f.subs({x:1, y:3}), g.subs({x:1, y:3})" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Example: Generic Case\n", "-----------------" ] }, { "cell_type": "code", "execution_count": 23, "metadata": { "collapsed": true }, "outputs": [], "source": [ "a = sym.IndexedBase(\"a\")\n", "b = sym.IndexedBase(\"b\")" ] }, { "cell_type": "code", "execution_count": 24, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f = a[1] * x + a[0]\n", "g = b[2] * x ** 2 + b[1] * x + b[0]" ] }, { "cell_type": "code", "execution_count": 25, "metadata": { "collapsed": true }, "outputs": [], "source": [ "matrix = subresultants_qq_zz.sylvester(f, g, x)" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAALoAAAAZBAMAAAB0qCmCAAAAMFBMVEX///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIpmJdu8QRM1mu90yVKvMIHo8AAAACXBIWXMAAA7EAAAOxAGVKw4bAAACkElEQVRIDa2WP2gTYRjGn/SaS+Ll7NHBSTRQEamgMXR0CAniqiDiH8RDcHEwAXFzCFIkULRFR5fSQRwVhCqCRqdujYOLUpshg+LSUkgRjPF93++73J8cIaV5h7v3vuf5fnnyfpdSQMqYPa6afV/jSGfwc99cBYgjvca6Mx58HGkVR6vjoceTNt3x0IE40ptxwRFDMnLAneujfsIwZxzpKYOfjEof5owhpfKpBtAdmR5y2sXAvjjS2sY3F6lOwDW0DTtD9DjSzV4PMF4NRQbEsDNEj5ASM8cuq43pdqkZQOjW1zFdOOfKatjp0X2nr9930lsKVHlkbqOwogBqia6iT87lgdRFLALZGiBObqQ8eoRULgPmVUwsKxf9DHYM52BNPemr0p/hB3B7CbPInqL5sVMaMWl6hJTJ2y1MdGAVIdlOwNyxnOw2bTEX3lO9bUDrq5hycdrlX4pNdHZKQ4dVry9cqddbnhNrtF1IVXSQXEalAcn2EKmuVU3skuxXknXzL5JNXAPdBcpOTSenzi5OfP5NK6wT9QYqeWwCku0PB4Udfi9Fp+9jLXFcOiHOLk5upDRdkfCd1linP7rvUGnipX1Isu3yZHlOwRL9MI/P7OJA7YvQxTlAZ5IjdNbXeY7pYuaDIdnwCyvELQTZ6OvJIubxvJUXujijdCFB6KxT9ksw22ePnM/K0d4qUfRMLkwXneY9VcXd8qd2VejijNLFqeis09z1CVJ2yiZ1Dw/CeHmSc1HrPjQyd72N585l8TsjpbJxm3288UKtha4lft9V2Reijel4Gt89+mSO3ndV/WzJXm9LrwVvxoz3P0Pi5L+iKP0m6KPeo6NQcLUUyBYx7/nx6+AOP9ugtreV6Y9tf8N/+R7ldlDvKZsAAAAASUVORK5CYII=\n", "text/latex": [ "$$a_{0}^{2} b_{2} - a_{0} a_{1} b_{1} + a_{1}^{2} b_{0}$$" ], "text/plain": [ " 2 2 \n", "a[0] ⋅b[2] - a[0]⋅a[1]⋅b[1] + a[1] ⋅b[0]" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "matrix.det()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python [conda env:sympy]", "language": "python", "name": "conda-env-sympy-py" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.4" } }, "nbformat": 4, "nbformat_minor": 2 } sympy-sympy-1.9/examples/notebooks/density.ipynb000066400000000000000000001075251412543434000223000ustar00rootroot00000000000000{ "metadata": { "name": "density" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Density operator and matrix " ] }, { "cell_type": "code", "collapsed": true, "input": [ "from sympy import *\n", "from sympy.physics.quantum import *\n", "from sympy.physics.quantum.density import *\n", "from sympy.physics.quantum.spin import (\n", " Jx, Jy, Jz, Jplus, Jminus, J2,\n", " JxBra, JyBra, JzBra,\n", " JxKet, JyKet, JzKet,\n", ")\n", "from IPython.core.display import display_pretty" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 59 }, { "cell_type": "code", "collapsed": true, "input": [ "%load_ext sympyprinting" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 60 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create n density matrix using symbolic states" ] }, { "cell_type": "code", "collapsed": true, "input": [ "psi = Ket('psi')\n", "phi = Ket('phi')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 61 }, { "cell_type": "code", "collapsed": false, "input": [ "d = Density((psi,0.5),(phi,0.5)); d" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\rho\\left(\\begin{pmatrix}{\\left|\\psi\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}{\\left|\\phi\\right\\rangle }, & 0.5\\end{pmatrix}\\right)$$" ], "output_type": "pyout", "prompt_number": 62, "text": [ "\u03c1((\u2758\u03c8\u27e9, 0.5),(\u2758\u03c6\u27e9, 0.5))" ] } ], "prompt_number": 62 }, { "cell_type": "code", "collapsed": false, "input": [ "display_pretty(d)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "\u03c1((\u2758\u03c8\u27e9, 0.5),(\u2758\u03c6\u27e9, 0.5))" ] } ], "prompt_number": 63 }, { "cell_type": "code", "collapsed": false, "input": [ "d.states()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\begin{pmatrix}{\\left|\\psi\\right\\rangle }, & {\\left|\\phi\\right\\rangle }\\end{pmatrix}$$" ], "output_type": "pyout", "prompt_number": 64, "text": [ "(\u2758\u03c8\u27e9, \u2758\u03c6\u27e9)" ] } ], "prompt_number": 64 }, { "cell_type": "code", "collapsed": false, "input": [ "d.probs()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\begin{pmatrix}0.5, & 0.5\\end{pmatrix}$$" ], "output_type": "pyout", "prompt_number": 65, "text": [ "(0.5, 0.5)" ] } ], "prompt_number": 65 }, { "cell_type": "code", "collapsed": false, "input": [ "d.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$0.5 {\\left|\\phi\\right\\rangle }{\\left\\langle \\phi\\right|} + 0.5 {\\left|\\psi\\right\\rangle }{\\left\\langle \\psi\\right|}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAKoAAAAXCAYAAACbItQpAAAABHNCSVQICAgIfAhkiAAABZhJREFU\naIHt2m2IHdUZB/DfNoYYk1ijgVRtUFpL0ITUVK00GkwQCrVtaPohEVETo7aQUGxDQRFsaSn0Sw1E\nQdRgu2nVFqHS4JdWgm6rokaE+Ja+qEgt1cZopfXdaNIPz8zu3Lln7s7dO7t3U+4flrtzznPm/8x/\nzstznjMMMMAAbbgZJ/bbiZo4knwdD0fqs4z6/YlSxafxa2zDD/ETnFDjhvfhN1iDhbgKD2BTyW4e\nZtV0cnuibB1W1Wz/Axw/QR6687VXTCfd4WeJssnQvhMfBb+LHXUGRvAgtuJHWfnd2jt06obrsQv/\nwg48gp934WwZRyXK7sOGGm2PES//3xPkmUpMN91hZqJsMrTvxNeCohAXYxHuKpTtxJexsQbZTfit\nEHoFbqjrZQKn4flE+Xv4Z1bfCRvwqx54esUXurCdTrrD5/C3RHnT2o/HV4m9Ytko40XcO07bkZoc\nwzi1ht2VOLOi7iTc2KHtEO6s6U8nnmH1fE1hpAvb6aQ7fAunV9Q1qX0dvmGZ3/mMehSWSc8uL6gf\nmzSFpXi6ou4VzMEnK+q/gt83wDMVmG66w2L8uaKuSe3r8I0ij88WitHwdsLmHcwXQe0HHe61Xix5\nQ2Ij8Ev8sb6/zhZL3au4ALdm3D/GmyXbO8RsuC1xn3W4uiGeyUa/dD8Gm3EuduO2Qt2hwv/D+FDM\nejkmon0vfBjrqJ/Kft9JkORlx2F/op4Q+g1cm10vFUH9CjxX0abow3bMxnfFy3tfLDFXCNG/mJXl\neALXiI3Ix4XypWJ2OtgQz2SjX7pvFR16n1iqd4gOsxh/Kdgdrz00moj2vfBhbOnPR+yhhM3MDnU5\n1oiRkuNZ7FFv97ldxD6b8F+sNhaz/ULMEhsT7XbhG6Wyb2sdrU3wTCb6ofs8zMXLWClWkZyjqAnR\nwVKDpBvtm+Ab7ah/FVNuCnPEKHm9op60mK/grMzJKqwR0/yWQtnn8VTh+jUxWsu4F2sL1wuy35Sf\nvfBMJvql+zbx7i8T+dscp+ClwvV+PJ5o3432TfCNdtSDYgqen7CZK17i4Qonvi92qOW2s8Ty8NmK\ndsSo3C3ELfqUv4CjsUTsjFMYKv0/VGHXK08KM8Uyuzfxd3ZF+R4cW7hHP3R/K7vvSpyMewp1H5ds\nV4gYPoW62jfCV0x2Py3yeUXMwHI8WuEEEcjP0560XSbirH0d2i4p3fuMkv1XRWe6P9H2m/hd4fpA\n9rtA+8juhacKB3FeRd2I+jv2fugO54ukfJ71OF3r7nuG2N3/IdG2G+2b4GtJ+D8ldsGzC2XnZI3L\nR1yLCnZ/wiVi1OSYIwLl3dLBdY6HRNyYY7U4oSE2ETeJXeTLibZrtecZbxOxUpM8k41+6E4MzP8U\nrldpjRe3qE41daN9E3wtmC9OCL5TKLsdj5XszhJTdn7TueK47zMFm++JwH5Ba9O2xPNpYlQtz65v\nEUvI4uwhNlf4eo5Y+lLYqX2WmQhP2dduMNKFbT90J579fZHpYOzodp74GOSCCn+71b4XvlG/i0v/\nm/iaOILbkZXNwddLjQ/g73gyu35bpHuuF7PAITH9X6jzRoBIal+E67KHOFfMIodxqdaYsoirjKVk\nyrhH5BaLJyQT5ZkK9EN3YiP3paz9MyI+vFFkIn6qOe175esLhlXPUmeonkGLOEk62ZxjSOu5+UR5\nhk3NjDoVGNb5WVaLbw7GQ6/ad8s3rHSEOh2wEg/XsNsslu4qHM7us7JHnl7w2vgm0wqr1RtcvWrf\nLd8oprqjHtKeksixVMRXnTBbpDheGMduJy7vgYfOvo6HdRNsN1kY71lOFJ8JdkIT2nfDR8Hvqf4W\n8xqRV0vhI51PYYi4bWcNnnfxD3EkV/4usg4PnX090tDpWWZJH+GW0YT23fDx//UOBhhggAEGGGCA\n+vgfqAPSYqWMIZsAAAAASUVORK5CYII=\n", "prompt_number": 66, "text": [ "0.5\u22c5\u2758\u03c6\u27e9\u27e8\u03c6\u2758 + 0.5\u22c5\u2758\u03c8\u27e9\u27e8\u03c8\u2758" ] } ], "prompt_number": 66 }, { "cell_type": "code", "collapsed": false, "input": [ "Dagger(d)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\rho\\left(\\begin{pmatrix}{\\left|\\psi\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}{\\left|\\phi\\right\\rangle }, & 0.5\\end{pmatrix}\\right)$$" ], "output_type": "pyout", "prompt_number": 67, "text": [ "\u03c1((\u2758\u03c8\u27e9, 0.5),(\u2758\u03c6\u27e9, 0.5))" ] } ], "prompt_number": 67 }, { "cell_type": "code", "collapsed": true, "input": [ "A = Operator('A')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 68 }, { "cell_type": "code", "collapsed": false, "input": [ "d.apply_op(A)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\rho\\left(\\begin{pmatrix}A {\\left|\\psi\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}A {\\left|\\phi\\right\\rangle }, & 0.5\\end{pmatrix}\\right)$$" ], "output_type": "pyout", "prompt_number": 69, "text": [ "\u03c1((A\u22c5\u2758\u03c8\u27e9, 0.5),(A\u22c5\u2758\u03c6\u27e9, 0.5))" ] } ], "prompt_number": 69 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now create a density matrix using spin states" ] }, { "cell_type": "code", "collapsed": true, "input": [ "up = JzKet(S(1)/2,S(1)/2)\n", "down = JzKet(S(1)/2,-S(1)/2)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 70 }, { "cell_type": "code", "collapsed": false, "input": [ "d2 = Density((up,0.5),(down,0.5)); d2" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\rho\\left(\\begin{pmatrix}{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }, & 0.5\\end{pmatrix}\\right)$$" ], "output_type": "pyout", "prompt_number": 71, "text": [ "\u03c1((\u27581/2,1/2\u27e9, 0.5),(\u27581/2,-1/2\u27e9, 0.5))" ] } ], "prompt_number": 71 }, { "cell_type": "code", "collapsed": false, "input": [ "represent(d2)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left[\\begin{smallmatrix}0.5 & 0\\\\0 & 0.5\\end{smallmatrix}\\right]$$" ], "output_type": "pyout", "prompt_number": 72, "text": [ "\n", "\u23a10.5 0 \u23a4\n", "\u23a2 \u23a5\n", "\u23a3 0 0.5\u23a6" ] } ], "prompt_number": 72 }, { "cell_type": "code", "collapsed": false, "input": [ "d2.apply_op(Jz)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\rho\\left(\\begin{pmatrix}J_z {\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}J_z {\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }, & 0.5\\end{pmatrix}\\right)$$" ], "output_type": "pyout", "prompt_number": 73, "text": [ "\n", "\u03c1\u239b\u239bJ \u22c5\u27581/2,1/2\u27e9, 0.5\u239e,\u239bJ \u22c5\u27581/2,-1/2\u27e9, 0.5\u239e\u239e\n", " \u239d\u239d z \u23a0 \u239d z \u23a0\u23a0" ] } ], "prompt_number": 73 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(_)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\rho\\left(\\begin{pmatrix}\\frac{1}{2} \\hbar {\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}- \\frac{1}{2} \\hbar {\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }, & 0.5\\end{pmatrix}\\right)$$" ], "output_type": "pyout", "prompt_number": 74, "text": [ "\n", " \u239b\u239b\u210f\u22c5\u27581/2,1/2\u27e9 \u239e \u239b-\u210f\u22c5\u27581/2,-1/2\u27e9 \u239e\u239e\n", "\u03c1\u239c\u239c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500, 0.5\u239f,\u239c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500, 0.5\u239f\u239f\n", " \u239d\u239d 2 \u23a0 \u239d 2 \u23a0\u23a0" ] } ], "prompt_number": 74 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply((Jy*d2).doit())" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$0.5 J_y {\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }{\\left\\langle \\frac{1}{2},- \\frac{1}{2}\\right|} + 0.5 J_y {\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }{\\left\\langle \\frac{1}{2},\\frac{1}{2}\\right|}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAZ0AAAAlCAYAAACZMTQOAAAABHNCSVQICAgIfAhkiAAACElJREFU\neJztnWeMFkUYgB/OO0VBxFgQ2w9RVCxYYtTYTkXsJRorNkw0miixxBbrHxSJPdFoNIIGhaAQjV1B\nwRbFQmJJ7CWKXWNDxYL+eL8vt/fdfvvNzO7Olnmf5MLdMLP73nzz3O7MzsyCoiiKoihKRkwC9kpR\nfhNgSkaxKEpdSeOZOqbUijHAzBTlrwIOyCgWRakraTxTx5TasRAY7lCuC1gErJBtOIpSS1w8C86x\nrqIDyIjtkQ/cllWBwzKOJS/SxDoTONah3D7As8C/FmVCqVNwb3chUhVHfXtWBcfUkxjGAR9a5F8X\nOA94EZiRS0TZkUWsw3H70GcBmxnmDa1Owb7dhUzZHS3KszI7losn3SmDqio/A7cCK2P+gRdFFrH+\nBCwBtgDeMSyzOrAO8K5h/tDqVMkX359REZ6V3bFczleX4TVblgJ/FB2EIVnFOg042SL/sdg9GA2x\nTpX88P0ZFeFZ2R3L5XyhXnRCZD6wB+a926ORrr+iKObYeBakY+0uOrYXozTHWRkY2vI12PL8SmeW\nA08C+xvk3QIZJvg514gUV1xuFtVRP5h6FqxjrQ1uY+AhYCpwBXA9MubYiceBR4DjgFHA2cg0wJM6\nlOsB7gHmAF8AvwJvNc6tZM90zLr+Ext5lXLh6ieooz6ZTmfPgnUs2gXsQbqGlwN3N9IuQ7p/e5M8\npW8lYDxwYOPn/4CLkfHNJP4Gjmx8/yCyQGoH4Huz8BVLPgKGAWsB37XJ0w30Ahd4iilUtgI+Rf6I\nm5DGT1BHfdLJs6Adi/Z0JgAjgPsjafci45OnGhzrKkSG84FtgGss49gdeBU/jbkLWBvYCNgAmRpY\n1pl8Wcd6L/JZt2N/ZHhgueVxQ65TFyYgQyw2+dP4Ceqoz/MleVYVx3I536DI928DXyGLlaK8j0zp\nOyThOAuQK7cr2wCLgcnApQ7lxwG3IcMPJqwLHNWS9jTm04l9knWsQ5AGv2ub/58DXAR8YHncEOvU\ntt1FmYL0HF42zJ/GT1BHfZ8vybOqOJarJz3IVfe2mAJPIvPPk1gQ+d7lIec5SHd/nENZ0EV6ttwF\nbBuTvibwjOdYqkyadjcF2Mkwb1o/QR0tgjjPQnQsdnHoCKTXszSmwFJgNWRMeFnCgSciC4iWA+sj\n3csnDIPqBf4CXjLMr6RjGvJ5LW5JnwDc5z8cpQNZ+AnqqG/iPAveseZFpzkDpl2jBtni4Zs2x/kR\neI++h5KjgdeR8eY3OsTQHCteBPzeOWQlA14AbopJ3w/z5wOKP9L6CepoEcR5FrxjzW52s+HGPdha\nsfFv0uyYw+l/B/R+4+c7DWLYFhFmgUFeW/7L4Ssv8oi1Xby7En/H+hQihe8488JnneZJWj9BHS3i\nfHGeldExr+dr9nQ+oH3XfBVk2uQPCccZFHOir5CxvGHALwllexv/PpsUqCODOmfJnIuw25F1MvAw\nfmOdCNwSkz4DmE3yHyKtUzuuQ6Y0tzISuRDE9RwuRJ7VNEnrJ6ijRZwvzrMyOlaYJ4uBm2PSFwCf\nJ5S7DPgaeUAWZTbSyMd2OO8jwJ/IqmdXQnxI6coQksfl5yJvMlQ642siAbj7CepoESR5Fppj/T77\n6CyWN4ENWzJ3A9sx8IHzpsjdEcjY8DIG3kWNRRa+NafXrYrM8Z8bybMifV3Qqm3AuAqwXtFBOHAk\n/dd6tDIdu41Bs6SqdeoDVz9BHS2CJM+mo44BcC4y9XJIJG0XpKHuFknbsZE2v/HzqQwcoxyKjD9H\nK32/RrmpkbQTGmnjU8ZexF3UY4iwW3s+b1rmISul29ENvEYxm8FWrU599nRc/QR1tIj2lORZaI61\n7encgeytdGYk7TTgOeD5SNrnyN5LzbnmM4Djgc0jeSYhd1/RWRovIA28ufXDpsh4943Iw7Wq8SLw\nMekW3PlmFDJ2324LHIB/kCEb1/UYaahinfrC1U9QR3s9n7eTZ0E7Ft3S4FfgIOSh7Z3I3c0y4NCW\nMl/S/yr5B3BWo9zayN3TZ8jK6eiitd+QxVJXIC8vWgM4kfh1Akcg+zs9RZ88i5CKymLK5grIYrfB\nyNjqEmTc2+aVsZORjRD3zSCeJLKItcnJmG0yOA24BLs/NKHWqS9c/QR11KQ9+fasCo5V0RMnxiLD\nDpcCVzbSxpC8ZYRt1/0c+lYKdyPrFK62ilI4AtkeJE+yirULGa833TtpIbLo0JQQ6zTNkNEF2O29\nVibq6GgRnpXdsVw8KeNL3JYg+1GdQN94cy/27x5PYmdk00OQru48zN4zE6UH2BN5wJsnWcQKMm13\nYeMYJswCjrE4foh1moaplHNfOhPq6GgRnpXdsTJ44o2t6P/e8NlIA2+H7V3UevSfCTQTeMCiPMgY\nuctGj7ZkESvI1hs2d9bDsVuXEWKdhjYNOErdHC3Cs7I7FpQnByI78IJM8fuWgdNFo6T5pTZB1jCM\ncizvE9dYh+N2FzoT2avLlhDqFCoiU07U2VGfnlXFsdp7sjrypsPjkWGITzrkd/2lhgGPAls6lPVN\nmlhPB85wKDceu3euQDh1ChWRKSfq6qhvz6rgWFCedAE3INM2k3D5pQYjr/sd2fh5jGV5n6SNdSFy\nF2ZLF/AKMovFhJDqFComU07UydEiPCu7Y5l7UsaJBEORAEcgu+seTOcGbUs3MvPmdmTq6Ujkjq2M\npI11DDKN1uSdK60sR17aZDK9MqQ6DZ06OlqUZ2V2LBhPepA57qcgi9JGG5TZHlkkZ8pNDNwVNW6r\n/zKQNtZJyGwVVzYGrjXIF1KdNrFtd3Whjo4W6VlZHQvOkzL2whRF6UMdVRRFURRFURRFURRFURRF\nURRFUZQa8j/bVKmwXxjmUgAAAABJRU5ErkJggg==\n", "prompt_number": 75, "text": [ "\n", "0.5\u22c5J \u22c5\u27581/2,-1/2\u27e9\u27e81/2,-1/2\u2758 + 0.5\u22c5J \u22c5\u27581/2,1/2\u27e9\u27e81/2,1/2\u2758\n", " y y " ] } ], "prompt_number": 75 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Evaluate entropy of the density matrices" ] }, { "cell_type": "code", "collapsed": false, "input": [ "entropy(d2)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\log{\\left (2 \\right )}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEUAAAAiCAYAAAAJfBTLAAAABHNCSVQICAgIfAhkiAAAA+RJREFU\naIHt2HuIVVUUx/GPw4w5TtmkZTVmNSkRJTlkRVmYGFH0+qOggoygwv8qIaI/sockTERlEVH0/Ksw\nKeglg1lCRlSERJAUNOlYGoWpPaSHPaY/1jncfe/cO9eZ5sytvF+43LP3WfucddZZ+7f2PjT5RxyC\n1kY78W/hACzAZhzbWFfGh5Z9sLkSB6G7YF/+kwxqZsr+SzMoVSi6mszFhZiGt/FawfebiL1J+2Jc\nJKb+BqzBT8PYo/hM2YOfcQvmFXyvI3Bd0l6JhbgPq7BUBObwxOZWEZhRMUFEe7QVaDvuHu3N94EW\nPKaU+YvwcoXNMeIlbUj6ZuOJaherx7V4GhvRKyI+Un4fxZiRcA3W44+sfSk6lFfLrfgQ89GZ9fVj\nG3oK9q8qA4rNlHXKp8HjIrNvrrB7Nus/O+mbgydTo0Yu2+cJEZyIL7AWX1fYtIgsOBNfYjUOxVXY\niXswBW3KBXMZPsCLFdebJYKyKenrF8Vg3BlQnim3iUo0NWvPwrs4I7FpwSvow3Qcj0+zcTOy4zZR\n4Vbtgw8zReBer3JuM9orOwcL+KUMKAXlPPwm3njKAuzCcVl7YXadxYnNA/hFbDtyFgnNq8dTIrtm\nVjm3XrwYlIR2QgG/WizDx/iuov8d8bBXZO08sNsTm+8xSSnD4IcaD5pyCS4TL+SrKuePVL5+GRcG\nRKZMwI94s4bdLiGaORvFVMt5A+9XjDkMW4a590lCs2qtk1qxW1KJx1toB8WDH1zlXKf4ZrMn6XtV\naElv9r9DKZNydohsaRdTK2U6nhElOhfXGaJ0f5u1u0WW/pUPakT1WSfSOV8Q5vQk53M6cL14i9W0\nKud5oUlrk752UYJvUF5tLheZmgdlIZ4b4TOMCQNKQjtbLJgWV9jcJcpomkWfKQnvcEwSAcnXKi14\nCfeK8p3/rhZZkdtNzcYNp4FVaceNWIElRrZXmIv7RWpuEXuNVqH0fXg0c3a5WFNMqRi/En+KKbVb\nBGmNEMxKenBTdrxc7ar4eTJmhaTq5NSLUAsewZ2ZUw/iVJyTOVuPbiF0KX3J2E6ciI8M1YNFYiO5\nWpTSNhyd2S8RwXyhYswMUa1OU77xS9mJ97LjmapXo2GZg0+EYEGXiPZZI73QKOjH6TXOPaT6ImxM\nqLch3CqE79esnW+42opyKGGT8hVuyhRDS/OYMVKBWSrEar7id75H4Q5Mxlv4Rmz/zxfZ22volBt3\nThD7k65xvm8HTsa5mQ+j/ig01nSJjzF5udzvv+1Ow+1KOnIKLmicO8VTT1MOFEK7V2k12SXK5bYC\n/Woo9Zb5k/FwRd+g/3FAmjRp0mSs+Rvvgds8ldAxMgAAAABJRU5ErkJggg==\n", "prompt_number": 76, "text": [ "\n", "log(2)\n", "\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 76 }, { "cell_type": "code", "collapsed": false, "input": [ "entropy(represent(d2))" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\log{\\left (2 \\right )}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEUAAAAiCAYAAAAJfBTLAAAABHNCSVQICAgIfAhkiAAAA+RJREFU\naIHt2HuIVVUUx/GPw4w5TtmkZTVmNSkRJTlkRVmYGFH0+qOggoygwv8qIaI/sockTERlEVH0/Ksw\nKeglg1lCRlSERJAUNOlYGoWpPaSHPaY/1jncfe/cO9eZ5sytvF+43LP3WfucddZZ+7f2PjT5RxyC\n1kY78W/hACzAZhzbWFfGh5Z9sLkSB6G7YF/+kwxqZsr+SzMoVSi6mszFhZiGt/FawfebiL1J+2Jc\nJKb+BqzBT8PYo/hM2YOfcQvmFXyvI3Bd0l6JhbgPq7BUBObwxOZWEZhRMUFEe7QVaDvuHu3N94EW\nPKaU+YvwcoXNMeIlbUj6ZuOJaherx7V4GhvRKyI+Un4fxZiRcA3W44+sfSk6lFfLrfgQ89GZ9fVj\nG3oK9q8qA4rNlHXKp8HjIrNvrrB7Nus/O+mbgydTo0Yu2+cJEZyIL7AWX1fYtIgsOBNfYjUOxVXY\niXswBW3KBXMZPsCLFdebJYKyKenrF8Vg3BlQnim3iUo0NWvPwrs4I7FpwSvow3Qcj0+zcTOy4zZR\n4Vbtgw8zReBer3JuM9orOwcL+KUMKAXlPPwm3njKAuzCcVl7YXadxYnNA/hFbDtyFgnNq8dTIrtm\nVjm3XrwYlIR2QgG/WizDx/iuov8d8bBXZO08sNsTm+8xSSnD4IcaD5pyCS4TL+SrKuePVL5+GRcG\nRKZMwI94s4bdLiGaORvFVMt5A+9XjDkMW4a590lCs2qtk1qxW1KJx1toB8WDH1zlXKf4ZrMn6XtV\naElv9r9DKZNydohsaRdTK2U6nhElOhfXGaJ0f5u1u0WW/pUPakT1WSfSOV8Q5vQk53M6cL14i9W0\nKud5oUlrk752UYJvUF5tLheZmgdlIZ4b4TOMCQNKQjtbLJgWV9jcJcpomkWfKQnvcEwSAcnXKi14\nCfeK8p3/rhZZkdtNzcYNp4FVaceNWIElRrZXmIv7RWpuEXuNVqH0fXg0c3a5WFNMqRi/En+KKbVb\nBGmNEMxKenBTdrxc7ar4eTJmhaTq5NSLUAsewZ2ZUw/iVJyTOVuPbiF0KX3J2E6ciI8M1YNFYiO5\nWpTSNhyd2S8RwXyhYswMUa1OU77xS9mJ97LjmapXo2GZg0+EYEGXiPZZI73QKOjH6TXOPaT6ImxM\nqLch3CqE79esnW+42opyKGGT8hVuyhRDS/OYMVKBWSrEar7id75H4Q5Mxlv4Rmz/zxfZ22volBt3\nThD7k65xvm8HTsa5mQ+j/ig01nSJjzF5udzvv+1Ow+1KOnIKLmicO8VTT1MOFEK7V2k12SXK5bYC\n/Woo9Zb5k/FwRd+g/3FAmjRp0mSs+Rvvgds8ldAxMgAAAABJRU5ErkJggg==\n", "prompt_number": 77, "text": [ "\n", "log(2)\n", "\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 77 }, { "cell_type": "code", "collapsed": false, "input": [ "entropy(represent(d2,format=\"numpy\"))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 78, "text": [ "(0.69314718056-0j)" ] } ], "prompt_number": 78 }, { "cell_type": "code", "collapsed": false, "input": [ "entropy(represent(d2,format=\"scipy.sparse\"))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 79, "text": [ "(0.69314718056-0j)" ] } ], "prompt_number": 79 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Density operators with Tensor Products as args" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sympy.core.trace import Tr\n", "\n", "A, B, C, D = symbols('A B C D',commutative=False)\n", "\n", "t1 = TensorProduct(A,B,C)\n", "\n", "d = Density([t1, 1.0])\n", "d.doit()\n", "\n", "t2 = TensorProduct(A,B)\n", "t3 = TensorProduct(C,D)\n", "\n", "d = Density([t2, 0.5], [t3, 0.5])\n", "d.doit() " ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$0.5 \\left({A A^{\\dagger}}\\right)\\otimes \\left({B B^{\\dagger}}\\right) + 0.5 \\left({C C^{\\dagger}}\\right)\\otimes \\left({D D^{\\dagger}}\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAUkAAAAaCAYAAAA6565FAAAABHNCSVQICAgIfAhkiAAACTZJREFU\neJztnHuMHVUdxz93i1sW21Ity2tbsCVaRFo1UF6pbW1BNDwkRFAJ0Rof0CogFDSkFZcVC20o4aFE\nUR4tAeVl1NS3KS0qCCrFEnkoyNqGVwElYK0PyvrHdyZ37uw5M2dmzrCz4XySm/bOOb8z537nN2d+\n53fOLAQCgUCgkfQDE0e6E8AY4KGcOrsBF7wGfTHRT9CpSfQzstej6dehn2b4a5JKmnV5744bK4F1\nwIsjdP4kO4CXcuo8H9U5vf7udBB0ahZNuB5Nvg5N0MdEkzUzMg+4bKQ7kWKFQ50xwH3A7Jr7EjOP\noFOTmEdzrkcTr8M8mqOPiSZqZqQF3A3sM5KdSPAT4EZgDbAW+FpO/VnA9+ruFEGnptGU69HU69AU\nfUzUplkPGlVd6bEc3zn1/TDgZwXaTTOhJtsLC7TzADClQj9ccNGpG5ic8RlXg23TdEpS1GdjGxM+\n/XYCGkRczutq17Tr4KLPROz+tofjeaq0UVqznVKFM1HIfC+wHdgXuAj4W06jP0I33s2R7XHAR4EB\n4KZEvWOAewp0NsnxwBXA1BpsDyjQ1uPAJ9BvqwsXnWYAS4Aj0HW6G3g4KmsB84H/oET6dz3ZNk0n\nKO+zUI/fvgFYCMwB3gY8CfQCG4HzgWnAecDHKtg17Tq46HMK8F7gBDTu3Aq8HJX1ooWT+4FL0G/3\n3YYXzcYCTwMnJ44tQXP07pxG1wNDic8rwGmGer8Bji3Q2ZhdgEHg3zXZFhm4LwZuK9GPIhTRaQ36\nbenorwu4A3gVONqTbd06zQD2KlC/is+Cf7+diaKQ7wAH07kw+h7g51F/P1/RbrT66xi0OLLOUNYD\n3IB0yJoFlW3Di2anA9uQ48VMQc5zZk6j69FT7nLgU9gjtkHgUOeutlkObI368qYabH9boL2F6CZ0\n4UNI8FUo2lkJLGb4dC7NIO46DQIbMs4/hKJoH7Z16RRzLsUeolV8Fvz67Zko+l7B8GlyzFejvs2o\naDda/fVg9Du+ZCnvAbYA19fQhhfN/oySnGkeAn6c0+h6x5NvA6Y71o2ZjsLq1Uict9dgW0TAw4Fn\nc+q8FbgGTfPTjv9u4FtoSmvDVad4QOi3lK+Myj/tyda3TmmKDpJVfBb8+e2RKOrOy3sdCTzjwW60\n+usS5FNzM+qspvO3+mqjtGZxWN+NhBo0GGym2JL4+IyyoZxyE6uAL9Lu9J412A4VaHMnsveX7gFc\njW7UHxra3ghchwYn24V21Sm2X28omwacipzjJkN5GVufOlXFp89Ceb+dhG7Kp1EUlsUW2tPEsnZx\nf1xpkr/OQVHzvRl1no36ZIvqy7ZRWrP4P/Hgsc1gsA0JkBdyfw5NGc4CbgFOMtTZSrFI8iPAH4An\naD8ZXAfJIrb/LdCn6eh3mGihgfmUqM55hjoLUOJ5LnAi5hSAq06xwySfkuOj9jcA3wfeD/zLk60v\nnXzgw2ehut9eAuyNpsR5OfOtwKUV7WB0+msL5VfvI/v37hv9O9ZQVqWN0prFq9vx8rnpZoqPTcQe\nBm8GfgX8Mfo+FXgQeAoldWO24D5Ijkf5mgXR9yKRZFHbpxz7BOr/ZkvZO5AGz6EV0w+iFbL4dafj\ngYNQdAuKJD4MfCPVjqtOc9AqXn/i2DQ0Rboa3QA25yhj60snH1T1WfDjt0ejG/bb+V3mH9Gnih2M\nTn+dgQbYu3Lq7YdWrB/13EZpzeJBMn5l51WDQbxKmDUSp7czPIGikW8CByaOr8M9pziAbtTt0fci\ng2RR2wcd+wQS8JeWsll0rqL9AEU1q9DWhMnAlxPl96NpbRoXnXaP+nIhw/OKuwK/R1HRbIYPJGVt\nfenUwrynsSv6pLemgVaek1T1Wajut/ug3O5Gh3P5sIsZjf4aT9WzBrjdgXcBv8Y8Pa7SRmXNxqCb\nod9gsBZNy7IwhcY3IAdOhuezkGPkMZPhCfkD0Y9eXaOtC49id4gBzFtYVqELa7r5rzEcc9EpXn1e\nYClfGpWnt5tUtXUlS6dlaCBOf7YAf7GUnZxqo6rPQnW/PQHptMbhXLvQXp0ua1eGpvjrbcD/yN7e\nsxjpsrjGNlzo0CwWYQdK3O5mMJhA9pRlBbAIbYBN1huHIoYptKcKv0Nh8OHY9y21gCuRGD9NHI8j\nj6xIsoqtC/PRRtOHLeWbgD6UjI85B/gTejXq68AZtKOHLvRifRoXneag6Cpv1a7Ps60LeTpdFH3S\nnAs8gga5PKr4LPjx20eif19w6O8itHm9il1RmuavG4F/Wsq7gE+iB2J6Ou+zjTwyNbsOrW4l6Y46\ndHvq+KFohzvoybsJTdOSPIacLD2tOgzlQUxPKdBO9+WWsu2080e+bfMYi5z7nRl1JqNEfMwyOhcC\npgPXougA4AMox2MiT6cHyF7h24CeqId4ts3DRScbRbcAlfVZ8Oe3z9CZvzQxAW2p8mHnSpP8dX/k\nT5caymLORg/ugyzlPtrII1ezM9DTIPmO89yoY7MSx2ZHx+K8wEI0fUiyK5qy3Gg51zLayeAkk1B+\nw/a2xGPY93xVsXVhAN3EeVyAEsfL0epwmregja69wFVkv29s02kiiqRsDnNSVG4aCKvYuuCqk4mi\ng2RZnwV/frsMTe1tN2YfGpD39mTnSpP89TSk/3EWu6PQvZlOqfhuI49czXpQ2PwV2htKb6dz2gpK\njN6FtkyA3jldTadTXhzVeWPG+ZbS+cc5p6DE8Gcs9btQBLSD4QNhFVsXejFffBPdKOn78Yw6+6Mn\nlst76GmdQNubhtCWjCS9wGfR9OhmzPpXsc2jiE4mig6SZX0W/Pkt0fn/jlaD43xZH1oYuhx7Dq2s\nXR5N89e1DM/ztlDe70qUh87Lu/poIwurZund9XshR3pz9P1FlBg3bbNIMg7lMqaiH7IJTYVezjJK\ncD16q6CFnq5L6fzDCovRk2RS9P05dCOcX9G2LnYGvoAG51vRBXwF6fM+tM1mAPuL/DYWoUGuLzrH\nS7T3c7XQdbgH+AVaqfRl+1pRJCcZU9ZnobrfJjkK5bOOQBHN48Cd6L3rOux8Upe/3oIG2PjaDNLe\n19qDpud3Ip+z5Rl9tFEJ27uiAT9MRZtfD0CRy19R5FP0nebXC6eiQaLsX4oKVCP4ayAQCAQCgUAg\nEAgEAoFAIBAIBAKBQKC5/B+xC2qm0KevJwAAAABJRU5ErkJggg==\n", "prompt_number": 80, "text": [ "\n", " \u239b \u2020\u239e \u239b \u2020\u239e \u239b \u2020\u239e \u239b \u2020\u239e\n", "0.5\u22c5\u239dA\u22c5A \u23a0\u2a02 \u239dB\u22c5B \u23a0 + 0.5\u22c5\u239dC\u22c5C \u23a0\u2a02 \u239dD\u22c5D \u23a0" ] } ], "prompt_number": 80 }, { "cell_type": "code", "collapsed": false, "input": [ "#mixed states\n", "d = Density([t2+t3, 1.0])\n", "d.doit() " ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$1.0 \\left({A A^{\\dagger}}\\right)\\otimes \\left({B B^{\\dagger}}\\right) + 1.0 \\left({A C^{\\dagger}}\\right)\\otimes \\left({B D^{\\dagger}}\\right) + 1.0 \\left({C A^{\\dagger}}\\right)\\otimes \\left({D B^{\\dagger}}\\right) + 1.0 \\left({C C^{\\dagger}}\\right)\\otimes \\left({D D^{\\dagger}}\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAqYAAAAaCAYAAABl7J64AAAABHNCSVQICAgIfAhkiAAAC35JREFU\neJztnXusHUUZwH+3LW0ttsWUPrQUbQleKLQGpYoEb28ALVpTH7FqkKCYiBafUbAhbfByFdTGGgVs\nGl9AVTQ1PjD1rZVKFAWkFRVErUKLlpdF6gPFQv3j283du3d2d2Z29ux49/slJzdnd2fOnG9++92z\nu7OzoCiKoiiKoigdZwg4ou1GABOBOyq2ORK4pAdtMTGExikmhmi/P2LviyHaj1GWqnipt70j5r4Y\nIo4YpcS+n/eKIdrtl9j7YYi4vIWaMZsQvDl2bAC2A39r6fOzPA4cqNjmoWSbtzTfnFFonOIilv6I\nuS9iiVGWqnipt70j1r6IKUYpMe/nvSKGfom5H2KIj4mYY2ZkEPho243I8WGLbSYCNwOnNdyWlEE0\nTjExSFz9EWNfDBJXjLJUxUu97R2x9cUg8cUoJcb9vFcMEk+/xNgPg8QTHxMxxsxIH/BT4Og2G5Hh\n28DngC3ANuCqiu2XAV9tulFonGIjpv6ItS9iilEWl3ipt80SY1/EFqOUWPfzXhFLv8TaD7HEx0Sj\nMZvu0aCJwJNK1p8CfNej3pQZDZW91KGeXcCCGu2wwSZOk4GjSl5PbqBsbHHK4+MsxOvtDCQBZUnb\nGVtfNO3s9JJyT7Non2282vAW4su3Ze7Zli8ipr6wiVFd90Bzbp4Y3R1v+TaEt3Xq8I7ZpIKNTgBu\nAGZbVjoL2Aw8COwBFgHXJXVkWQncZN3U0awCPg4sbKDsYoe6dgPnAcMe7bDFJk5LgPcApwJPR46e\n7kzW9QGnA/9BBkZ/KVDZ2OKUxdVZiM/bw4A3AAPAM4E/I99nJ3Bx0r6LgHOJry+adnYl8ArgJcg/\n8W3A/cm6pwBPRQbbfwT4reGzbePVa28hjnzr4l4VofJtLN7WdQ8056bE5O54z7chvK1TR7CYLQLe\nCNwHHHKo9GvApsz75wAPMzYx/QR4qUO9KdOAu4F/N1TW5UfHB4Eve7TDBZc4bUG+W/6IewLwFeAJ\nYEWgsk3HaQkiugu+zkJc3i5Fjhq/CJzM6BsTXwB8D9gHvCtZ1lVnfwfcZVg+CRnTdDcw17DeNl6+\nseqlu6G9dXWvjJD5NjZvfd3Lojk3Dne7lG9DeOtTh3fMsp1xPLAWmAr8yqHCxcDLkA5O+QWwH9iY\n23Y+cqTkynok4U1BfqWHLps/fV/GXcgRrw2vQgK+ERmkvAG4AIlxGS5xGgB+Dvwjt/wJpE/6kKOd\nEGWbilPKCiRR2eLrLMTl7TuAW5BLM2cDtyJ9kHJjsn4e8MNkWRednQccy9izKwAHkbMc+4HPG9bb\nxsvHW+idu6G99XGvjJD51rUvfNy19baOe1k057bvbpfybQhvfesIHrNrsD8S+iRyy39+WMAm4JHc\n8n8C/Zb1pvQDW4FrkzYd30DZnznU+XxGTmUXcSwSl1WM7ZyTgE8hl26KsI3TAuR7DRWs35Csf1Og\nsqHjlOdC/M5MgpuzEI+3ZyJJsWo8zpnIGYqULjr7mmTd60rqvwz4L2PHlNnGy8db6J27Ib31da+I\n0PnWti/quGvrbR33UjTntu9u1/JtCG996/COWYh5TE9ExmYczC3fgwwmXppZdgj3wdIbkSO0tNHz\nGijrsnNNojxuc5Ed7Q7gG4a6dwKfRZLT8pL22MQpLX+DYd0i4BxEji8EKhsyTm0Tg7ezkH/i+5Cj\n5jL2IvPVZdtky3hxdiD5u6Ok/vuR73uyoX02dMXbOu4VETrf2vRFXXdtva3jXorm3Hbd7WK+DeGt\nbx3eMQsh8Tzk13uedNmczLIHcDvz9FrkVP+fGDl6sf1h6lL2MYc29SPfw0QfkpzPTra5yLDNGcDL\nEeFeiflyl22cBpAB89kjk+lJ/TuArwNnAf8KVDZUnGIgBm8/hNzZeBnV41AfQAaYp3TR2eVITO8t\nqT+9HDQlt9w2Xl3xto57JprIt1V9EcJdW2/ruJeiObddd7uYb0N461uHd8yK7sp3YS7mBqc7V/ZR\nWXux/wc/HRkLckby3uWMqWvZv1i2CaT9ewrWnQD8Ehn7cR0ynmaYkcdurULG86xN3l+LnCbfnKvH\nNk4DyBHoUGbZIuRSwCZkByiSw6dsqDjFQAzerkAS5Kct6n04eaV0zdlZyBi1LRX1H5P8vTW33DZe\nXfG2jnt5msq3VX0Rwl0bb+u6l6I5t113u5ZvQ3hbpw7vmIX4YXqA0QOHUyYnf7M72nbsx4gOIzvq\no8l7lx+mrmVdBnH3Az8oWLeM0XeiXY8cDW4EbkPm/npfZv1tyOWbPDZxmpO05VLGjlmaiQiyGnmi\nQv7sk2/ZUHHqQ+axyzMheZm8zF/+qUvb3h6NjDnbiduRZUrXnB1AvPlxSf2Tkaeh7GbsI/ps41UW\nK2jf3RDe1nUvT1P5tqovQrhr421d90BzLrTrbhfzbQhv69ThHbMQl/KLPvzw5G92APG3sDurshQ4\nDpk+I8X2Ur5P2cst2pTSj3wPEwuRzsmSBvvNjL3zEMwTK9vEKR33caNh3SPIwPSTgPMDlg0Vp3XI\n5az86+1IjEzrXu3w2Ta07e2zk7+/tqh3GjKtS5auOluWIM9C/slvNayzjVdZrKB9d0N4W9e9LE3m\n26q+COGui7e+7mXr0Jw7ll642+V8G8Jbnzq8YxbijOntSMPypE/+2JdZdgvwd+QOrKI5rvqAK5A7\nvL6TWZ4e7ZX9MK1T1obTEanuLFh/OzKNQ/Y7vxv4DfKIrk8giSA9YpsAPGSoxyZOA8gRbdWdb/MD\nl7WhKk4fSF55LkQm6d3m+bkutO1tOhnxXy3augb4psV2JsaLs8uRS0N/KCl3PnAPZrdsqIoVtO9u\nCG9DuddkvrXpixDu2ngbwj3Nue2628V8G8LbWPIuUD0NxPMYedrDucgp+jzfR4J/WG75KcgYi6If\nxedR/Ev70aRsEXXKVjEFkftZJdschQysTlmPXJ5J6Qc+gxyRAbwYGT9ioipOu5D58IrYgfThcwOX\nrcImTkU0OXVJ1lmIw9v7kImSy5iBTCPjw3hxdibwOGOfBpVldVLW15863kLv3A3lbQj3msq3tn0R\nyt0yb0O5pzm3fXe7lG9DeBtd3r2GYuFOS9alp3aXJO+zc25NRRKT6Y4zkM5Ya1g+Cxk7MdmwDuRX\ne9H8YHXK2jCM7MRVXIIMBL4c89HhM4CrkR32SszjflKK4nQEIkzRnbKrk/WmRFinrA22cTLRVJLM\nOwtxeLseuUu3aILr+cj3sn2ucZ7x4uxKpK/WFJRdhtxU8daSdlVRx1vonbuhvK3rXpP51qUvQrlb\n5G0I9zTnCm2726V8G8LbqPLuJGTMwyFkEtg8cxDZ3plZdhXyCK90rMjbkLvOyubZWsfou/AWIAN9\nTePLQE5p70J24HwyrFPWhtmYO9/EZCR+ry/Z5jjkKMHm+en5OIFMzXIImUoiy2xEkseQO/4OZyx1\nylbhEicTvknSx1lo31uA9yNPzVjFyFii+cjZhY9hHl9kw3hydnNS9sTc8mOQG0n2Io8R9KWut9Bb\nd0N4C/7uNZlvXfsipLumGIVwT3PuCG2725V8G8Lb1vJu9okDc5Bnlc5hRJKDyNxSV1D+yKpJyDNl\nlyB3Zc1E7iy7x7KBVyNPWuhDjmjWMfr08QXIwOBZyfsHkTFNF9cs2xRTgfciCXor8HsklguBFyGD\n3IeRqUNcWIMkufnJZxxgZO6vPmSnugm5NHJ9wLK9wnW8Ux1noV1vs7wQOYtwKnKWaTfwIySB94oY\nnb0SOfNyZLLtvYzc9TkNcWU7Eqf9ju0KTS/drettFlf3upJvQ7inOXcsbbpbt1xImsq3IbxtPe+6\nPMtUcWchckSxGBk/80dk0PLNbTYqYs5BkkTRYG6ledRZP9Td9lF33VFv20WdVRRFURRFURRFURRF\nURRFURRFURRFURRFURRFURRFURRFURRFURRF+X/hf2jkcJDynyQoAAAAAElFTkSuQmCC\n", "prompt_number": 81, "text": [ "\n", " \u239b \u2020\u239e \u239b \u2020\u239e \u239b \u2020\u239e \u239b \u2020\u239e \u239b \u2020\u239e \u239b \u2020\u239e \u239b \u2020\u239e \u239b \n", "1.0\u22c5\u239dA\u22c5A \u23a0\u2a02 \u239dB\u22c5B \u23a0 + 1.0\u22c5\u239dA\u22c5C \u23a0\u2a02 \u239dB\u22c5D \u23a0 + 1.0\u22c5\u239dC\u22c5A \u23a0\u2a02 \u239dD\u22c5B \u23a0 + 1.0\u22c5\u239dC\u22c5C \u23a0\u2a02 \u239dD\u22c5\n", "\n", " \u2020\u239e\n", "D \u23a0" ] } ], "prompt_number": 81 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Trace operators on Density Operators with Spin States" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sympy.physics.quantum.density import Density\n", "from sympy.physics.quantum.spin import (\n", " Jx, Jy, Jz, Jplus, Jminus, J2,\n", " JxBra, JyBra, JzBra,\n", " JxKet, JyKet, JzKet,\n", ")\n", "from sympy.core.trace import Tr\n", "\n", "d = Density([JzKet(1,1),0.5],[JzKet(1,-1),0.5]);\n", "t = Tr(d); \n", "\n", "display_pretty(t)\n", "print t.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "Tr(\u03c1((\u27581,1\u27e9, 0.5),(\u27581,-1\u27e9, 0.5)))" ] }, { "output_type": "stream", "stream": "stdout", "text": [ "1.00000000000000" ] } ], "prompt_number": 82 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Partial Trace on Density Operators with Mixed State" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#Partial trace on mixed state\n", "from sympy.core.trace import Tr\n", "\n", "A, B, C, D = symbols('A B C D',commutative=False)\n", "\n", "t1 = TensorProduct(A,B,C)\n", "\n", "d = Density([t1, 1.0])\n", "d.doit()\n", "\n", "t2 = TensorProduct(A,B)\n", "t3 = TensorProduct(C,D)\n", "\n", "d = Density([t2, 0.5], [t3, 0.5])\n", "\n", "\n", "tr = Tr(d,[1])\n", "tr.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$0.5 A A^{\\dagger} \\mbox{Tr}\\left(B B^{\\dagger}\\right) + 0.5 C C^{\\dagger} \\mbox{Tr}\\left(D D^{\\dagger}\\right)$$" ], "output_type": "pyout", "prompt_number": 83, "text": [ "\n", " \u2020 \u2020 \u2020 \u2020 \n", "0.5\u22c5A\u22c5A \u22c5Tr(B\u22c5B ) + 0.5\u22c5C\u22c5C \u22c5Tr(D\u22c5D )" ] } ], "prompt_number": 83 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Partial Trace on Density Operators with Spin states" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sympy.physics.quantum.density import Density\n", "from sympy.physics.quantum.spin import (\n", " Jx, Jy, Jz, Jplus, Jminus, J2,\n", " JxBra, JyBra, JzBra,\n", " JxKet, JyKet, JzKet,\n", ")\n", "from sympy.core.trace import Tr\n", "\n", "tp1 = TensorProduct(JzKet(1,1), JzKet(1,-1))\n", "\n", "#trace out 0 index\n", "d = Density([tp1,1]);\n", "t = Tr(d,[0]); \n", "\n", "display_pretty(t)\n", "display_pretty(t.doit())\n", "\n", "#trace out 1 index\n", "t = Tr(d,[1])\n", "display_pretty(t)\n", "t.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "Tr((\u27581,1\u27e9\u2a02 \u27581,-1\u27e9, 1))" ] }, { "output_type": "display_data", "text": [ "\u27581,-1\u27e9\u27e81,-1\u2758" ] }, { "output_type": "display_data", "text": [ "Tr((\u27581,1\u27e9\u2a02 \u27581,-1\u27e9, 1))" ] }, { "latex": [ "$${\\left|1,1\\right\\rangle }{\\left\\langle 1,1\\right|}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEwAAAAXCAYAAACh3qkfAAAABHNCSVQICAgIfAhkiAAAAedJREFU\nWIXt2D+I1EAUx/GPB+ohCqIiKqKNFjanveXaKNhaeI2Kglpb2Z2FnYKVgoqNeCDYXecfUgoWgoJy\nCGJhIQhiYWexFtksa8hO/kzYm2K/TSbz8t77zeMxyYQ5UbzYaAGJMq7LQsmwu+Lh/VjHlo7JQv63\nsKdhnHsdc9TRxLeqLiCbGG/DKXzCEIsthTTxX8LNBrFO4EbHHDH6CrJiUO6wgiNYxQA/W4ho6/8B\nx7C5Jt4VPOpRY+z6xmQVcw9067Cm/mexHPDfhzuROWJ9s2IwrcNmyRrOBOxX5YtKghQKNsRbnKyw\nLeIQvsxUUYAUCgZPcKFifhnPZislTCoF+4NfOFyaH+DV7OVMJ5WCwX1cm7gf4M0GaZlKSgUbYtPE\nfUraxqQk6rq8ywpeyrssKfoo2IEeYmyXH5G+leZfy7/GY+lDI5oVbNfourfCdhzf8bijf8FF+Zuy\nzFOcrxNYk6NOYxN9U8lG152j8bp8bxniN97h0sTzB/EVH/2//zT1N/JbDWhawdGK+RiNbfRRfQIK\nG2pY6ehHs6PR3Yj4BTEas2LQ16YfE+ccngfsP7BV3hUx9LLWcpC/HWKcxvuO+ZfwuUHeh7jcMQdx\nGgno29Ey0AJuRwjp6wdiiFiNtK/LnDlzZsM/36lpQdemeFcAAAAASUVORK5CYII=\n", "prompt_number": 84, "text": [ "\u27581,1\u27e9\u27e81,1\u2758" ] } ], "prompt_number": 84 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples of qapply() on Density matrices with spin states" ] }, { "cell_type": "code", "collapsed": false, "input": [ "psi = Ket('psi')\n", "phi = Ket('phi')\n", "\n", "u = UnitaryOperator()\n", "d = Density((psi,0.5),(phi,0.5)); d\n", "\n", "display_pretty(qapply(u*d))\n", " \n", "# another example\n", "up = JzKet(S(1)/2, S(1)/2)\n", "down = JzKet(S(1)/2, -S(1)/2)\n", "d = Density((up,0.5),(down,0.5))\n", "\n", "uMat = Matrix([[0,1],[1,0]])\n", "display_pretty(qapply(uMat*d))\n", "\n", "\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "\u03c1((O\u22c5\u2758\u03c8\u27e9, 0.5),(O\u22c5\u2758\u03c6\u27e9, 0.5))" ] }, { "output_type": "display_data", "text": [ "\n", "\u23a1 0 \u03c1((\u27581/2,1/2\u27e9, 0.5),(\u27581/2,-1/2\u27e9, 0.5))\u23a4\n", "\u23a2 \u23a5\n", "\u23a3\u03c1((\u27581/2,1/2\u27e9, 0.5),(\u27581/2,-1/2\u27e9, 0.5)) 0 \u23a6" ] } ], "prompt_number": 85 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example of qapply() on Density Matrices with qubits" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sympy.physics.quantum.gate import UGate\n", "from sympy.physics.quantum.qubit import Qubit\n", "\n", "uMat = UGate((0,), Matrix([[0,1],[1,0]]))\n", "d = Density([Qubit('0'),0.5],[Qubit('1'), 0.5])\n", "\n", "display_pretty(d)\n", "\n", "#after applying Not gate\n", "display_pretty(qapply(uMat*d) )" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "\u03c1((\u27580\u27e9, 0.5),(\u27581\u27e9, 0.5))" ] }, { "output_type": "display_data", "text": [ "\u03c1((\u27581\u27e9, 0.5),(\u27580\u27e9, 0.5))" ] } ], "prompt_number": 90 }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 86 } ], "metadata": {} } ] }sympy-sympy-1.9/examples/notebooks/fidelity.ipynb000066400000000000000000000070351412543434000224250ustar00rootroot00000000000000{ "metadata": { "name": "fidelity" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [ "from sympy import *\n", "from sympy.physics.quantum import *\n", "from sympy.physics.quantum.density import *\n", "from sympy.physics.quantum.spin import (\n", " Jx, Jy, Jz, Jplus, Jminus, J2,\n", " JxBra, JyBra, JzBra,\n", " JxKet, JyKet, JzKet,\n", ")\n", "from IPython.core.display import display_pretty\n", "from sympy.physics.quantum.operator import *\n", "\n", "%load_ext sympyprinting" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "##Fidelity using some kets" ] }, { "cell_type": "code", "collapsed": false, "input": [ "up = JzKet(S(1)/2,S(1)/2)\n", "down = JzKet(S(1)/2,-S(1)/2)\n", "amp = 1/sqrt(2)\n", "updown = (amp * up ) + (amp * down)\n", "\n", "# represent turns Kets into matrices\n", "up_dm = represent(up * Dagger(up))\n", "down_dm = represent(down * Dagger(down)) \n", "updown_dm = represent(updown * Dagger(updown))\n", "updown2 = (sqrt(3)/2 )* up + (1/2)*down\n", "\n", "\n", "display_pretty(fidelity(up_dm, up_dm))\n", "display_pretty(fidelity(up_dm, down_dm)) #orthogonal states\n", "display_pretty(fidelity(up_dm, updown_dm).evalf())\n", "\n", "\n", "# alternatively, puts Kets into Density object and compute fidelity\n", "d1 = Density( [updown, 0.25], [updown2, 0.75])\n", "d2 = Density( [updown, 0.75], [updown2, 0.25])\n", "display_pretty(fidelity(d1, d2))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "1" ] }, { "output_type": "display_data", "text": [ "0" ] }, { "output_type": "display_data", "text": [ "0.707106781186548" ] }, { "output_type": "display_data", "text": [ "0.817293551913876" ] } ], "prompt_number": 7 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Fidelity on states as Qubits" ] }, { "cell_type": "code", "collapsed": false, "input": [ "\n", "from sympy.physics.quantum.qubit import Qubit\n", "state1 = Qubit('0')\n", "state2 = Qubit('1')\n", "state3 = (1/sqrt(2))*state1 + (1/sqrt(2))*state2\n", "state4 = (sqrt(S(2)/3))*state1 + (1/sqrt(3))*state2\n", "\n", "state1_dm = Density([state1, 1])\n", "state2_dm = Density([state2, 1])\n", "state3_dm = Density([state3, 1])\n", "\n", "# mixed qubit states in density\n", "d1 = Density([state3, 0.70], [state4, 0.30])\n", "d2 = Density([state3, 0.20], [state4, 0.80])\n", "\n", "\n", "display_pretty(fidelity(d1, d2))\n", "\n" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "0.996370452558227" ] } ], "prompt_number": 9 }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }sympy-sympy-1.9/examples/notebooks/fresnel_integrals.ipynb000066400000000000000000006415551412543434000243350ustar00rootroot00000000000000{ "metadata": { "name": "fresnel_integrals" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": "%pylab inline", "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": "\nWelcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].\nFor more information, type 'help(pylab)'.\n" } ], "prompt_number": 1 }, { "cell_type": "code", "collapsed": true, "input": "from sympy import Symbol, fresnels, fresnelc, oo, I, re, im, series, Rational, sin, cos, exp, plot\nfrom sympy.plotting import plot, plot_parametric\nfrom matplotlib.pyplot import figsize", "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": "Plot of the two Fresnel integrals $S(x)$ and $C(x)$" }, { "cell_type": "code", "collapsed": false, "input": "x = Symbol(\"x\")", "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": "plot(fresnels(x), fresnelc(x), (x, 0, 8))", "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAWYAAAD8CAYAAABErA6HAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztnXl0HNWd778t4d2WWwveN7UW77IkL2wmlpFkCAkEEGPD\n4yWTTcCbmSQnDA5hMjPRSU4OBE1mkkA2y+GFCZlHhJSEhASI1WwxBtuy2rZkbZZLtmXjVa2WsY1s\nyer3x09XVV1dVV3VXS2VpN/nHA5WV3XVreru7/3V9/7u77qCwWAQDMMwjGNIGO4GMAzDMKGwMDMM\nwzgMFmaGYRiHwcLMMAzjMK4b7gYoqa6uhtvthiRJKC0ttbydYRhmNOCYiLmurg4AUFhYCADw+Xwh\n230+HzweDwoLC+HxeMK2MwzDjBYcI8yVlZVITk4GAHg8HtTU1ITt88QTTwAAJElCXl7ekLaPYRhm\nqHCMMAcCAaSkpAz+3dnZGbI9Ly8P6enpSElJCdmPYRhmtOEoj9lorksgEEBmZiYqKipQWlqK/Px8\npKenD253uVz49re/Pfh3QUEBCgoK4tlchmGYuOAYYXa73fD7/QCArq4upKamhmyvqKjAI488gqSk\nJLjdblRVVWHr1q0h+5SVlQ1VcxmGYeKGY6yMLVu2QJIkAEB7ezuKi4sBUKQsSEpKAkADhG63e+gb\nyTAMMwS4nFQro6KiAh6PJyQdbs2aNaitrQUAlJeXw+PxwO/3h6XLuVwuQyuEYRhmpOAoYY4FFmaG\nYUYLjrEyGIZhGMIxg3+jja4u4NVXgYQE4K67gAF7nGEYJiJsZcQBSQK+/nVg4UKgtxc4dAh4+WVg\n5szhbhnDMCMBFmabuXIF+NzngE98AvjHf6TXvvtd4PBh4IUXAJdreNvHMIzzYY/ZZp5/Hrh6FfiH\nf5Bfe/JJ4MAB4A9/GL52MQwzcuCI2UYuXAAyMoCdO4HFi0O3/eUvwFNPAe++y1EzwzDGcMRsI7/6\nFfDZz4aLMgDccQdw+jTw/vtD3iyGYUYYLMw2EQwCr78OlJRob09IAL7yFWD79qFtF8MwIw8WZpt4\n/32gvR24+Wb9ff7u72ifnp6haxfDMCMPFmab+N3vyMYw8o9nzwauXQO83qFrF8MwIw8WZhu4dg34\n9a8pIo7E5s3ABx/Ev00Mw4xcWJht4IMPaPJIVlbkfQsLScRHRy4MwzDxgIXZBv72N+DBB83tu2QJ\n5TkPVDhlGIYJg4XZBl56Cdiwwdy+LhdQVARoLGnIMAwDgIU5Zs6eBY4eBdatM/+eoiIeAGQYRh8W\n5hjxeilavs5Cnb6NG4FLl9hnZhhGGxbmGKmpoQjYCvPnA/X1wJEj8WkTwzAjGxbmGAgGgR07rAsz\nANx4I6fNMQyjDQtzDEgSRb9Lllh/LwszwzB6OEqYq6ur4fV6UVFREbatrq4OCQkJyMzMRGZmJh59\n9NFhaGEo774LLFgQXbW4SMLc3w/4/dG3jWGYkYtjlpaqq6sDABQWFkKSJPh8PuTl5Q1u7+rqQn9/\nPwDA5/MhOTl5WNqpZNcu4JZbontvXh7Q1ARcvgxMnhy67ehRWgHl8mUgJ4cK7U+cGHNzGYYZITgm\nYq6srBwUW4/HgxpVom9hYeHgv2tra7Fo0aKhbJ4mu3YZFy0yYtIk4L77qIC+kmvXgH/9V4qo//Qn\n4OOPgfLy2NvKMMzIwTHCHAgEkJKSMvh3Z2en5n5erxebN28eqmbp4vcDx49TRBstkycDAw8Kg1RV\nAd3dwDe+AYwfD/zbvwF//COdi2GYsYFjrAwAplYg2bFjR0j0rKSsrGzw3wUFBSgoKLCpZeF88AFN\nKrGSv6wmNzdUmPv7gbIy4Kc/lX3rmTOBW28FfvIT4Pvfj6nJDMOMEBwjzG63G/6B0a6uri6kpqZq\n7lenDjEVKIU53tTXk2DGQm4urREo2LkTyM4G1P3Jo48CX/0q0NcXW0fAMMzIwDFWxpYtWyANVPZp\nb29HcXExALI4BJKDKv+8+SawZk1sx1i5EmhsJMEFyMa45ZbwLI/sbLJO3nortvMxDDMycIwwiwwM\nr9cLt9uN3NxcAECRYvaGy+VCRkbGsLRPSTAI1NYCq1fHdpypU4F584DmZhr0e+kl4P77tfd96CHy\nmhmGGf3wKtlR0N5ONsaJE7Efa8sW4K67aHXt738f+MMftPdraKBC/I2NvMo2w4x2HBMxjyT27o3d\nxhCsXw90dACvvQYsXaq/3/LlwJUrXF+DYcYCLMxRUFtrnzDPnw+89x7V3Ni0SX8/l4v85zfftOe8\nDMM4FxbmKLBTmJcuBQ4dojzlm24y3veOO4CDB+05L8MwzoWF2SL9/cC4cUB+vj3H83iAkyfp/5Gm\nXa9eDfzlL/acl2EY58LCbJFjxyjCnTHDnuONGwckJ5vL8MjOplmBH35oz7kZhnEmLMwWOXgQWLXK\n3mMGg+aKFCUk0Crbe/fae36GYZwFC7NFDhyIrT6GmmvXKAoeKJwXkawswOez7/wMwzgPFmaLHDxo\nrzA3NZGVcfSouf3z88MLHzEMM7pgYbaI3VbG7t0ktk1N5vZnYWaY0Q8LswUuXaLZftnZ9h3z2DHg\nzjuBtja5ZoYRixZRO86csa8NDMM4CxZmCzQ00Pp+dlZ4e+MNWs1k5kxzdobLRfuzz8wwoxcWZgvY\nbWP09ZHY5+TQRBOzdsZtt/HUbIYZzbAwW8DujIzWVmDuXGDaNGvCPG8e8P779rVDyaVLwH/9F/Cj\nHwFXr8bnHAzDGMPCbAG7MzL276di+YA1YV6+nKrMxYNvfxs4fJgWAnjuuficg2EYY1iYTRIMOkeY\nly4FWlooB9pOmpqAd98F/uM/gO98hwor8SAjwww9LMwmOX6cFk+9/nr7jnnsmOxZL10KXLhAHUAk\npk6ldrS329cWAPj1r4G776brnDOH2vTSS6H7BIOU4me2E2EYxjoszCZpaJCjW7t49105Ak9NBc6e\nBc6dM/deu+2MYBD47/8G7r1Xfu2OO4Df/S50v+efB55+Gnj88fj53Awz1mFhNklDg3Ehe6t0ddFA\n27x58muZmZTPbIZly6iYkl3U19MqKsuWya994hPAxYvUVtHml18GnnkG+OIXgWefte/8DMPIsDCb\npLnZXmFuaqKcaOUyUVaEeflye4X5jTcoele2Z+JEIC2NInsA+P3v6R5kZQH33AOcP8/1oRkmHjhK\nmKurq+H1elFRUaG5va6uDtXV1brb40lzM7B4sX3Ha2wMjU4B68J85Yp97XnrLaCgIPz1TZsoTVDs\nc8cd9O/ERNr/r3+1rw0MwxCOEea6gQIQhYWFAACfxtS2p59+GiUlJQgEAprb40UwSFkQS5bYd8xY\nhTkzE3j9dXODhZHo76di/evXh2+74Qbg1VfJxjhzBtiwQd52yy3hg4MMw8SOY4S5srISycnJAACP\nx4OampqQ7VVVVVi7di0AYOvWrcjLyxuytp07R4/4aWn2HbOpKTZhTk4GJkygAcNYaWkhL3nmzPBt\n+fnkr9fU0D1Q1o2++Waanu73x94GhmFkHCPMgUAAKSkpg393dnaGbK+trUVnZyd8Ph/Ky8uHtG3C\nxlD6r7HS2BjuWVsRZoAG6+yYmr17N0XGWkyeTKur/P734VbHuHE0a/G992I7/y9/CTz0ELBrV2zH\nYZjRgmOEGQCCEZ7L09LSBiPl6urqsO1lZWWD/7399tu2tctuG+PiRYrCFy0KfT01lWwFsxGoVSHX\no6EBuPVW/e1ZWcCePdpWR1ERbYuWAwcoJa+wECgvD50GfvYs8PbbwOXL0R+fYUYiNtZJiw232w3/\ngCJ1dXUhNTU1ZHtqairS09MH9927dy9KSkpC9ikrK4tL25qb7RVmEYEnJoa+7nLJYrtuXeTjZGTY\nI8wffAB86lP621eupBxnrQVoV6yg2hrR8tvfAsXFlH63cydlh9x1F9DbS7nS3d10ju99L/pzMMxI\nwzER85YtWyBJEgCgvb0dxcXFAMjiAID7779/cHsgEMA6M8plE0ORkSGwOgAYq5XR3x+5al5SElka\nU6aEb1uzhqrkRTMIee0a2SD33Ud/r19PmR8A8Kc/0RqHL74I7NtH9TsYZqzgGGEWFoXX64Xb7Ubu\nwDS7oqIiAEB6ejrcbjeqq6vh9/txn/g1DwFDkZEhsCrMsUbM7e2A2w0o7P0wrlyh/7TEd+ZMqpJ3\n/Lj1c9fWUrbHggX09+23U252fz/wf/8vpepNmwbceCMJdTQEg/ZkrjDMUOIYYQaA0tJSFBYWorS0\ndPC12trakO0lJSV46qmnhqxNV67QqiUej33H1Br4E1gRWzsG/w4dIgE0or6eMkBOntTevmpVdBNN\n3n6bxFgwdy7ZO3V1dM5PfpJev/VW4G9/s37806eBzZuBrVtDveuPPza3WgzDDBeOEmYn0tZGg3Tj\nxtl3TK1UOYEVYZ4xgzqOAbcnKhoajKNlgEQ3K0t/pmG0wrxrFzCQATnIzJnA//t/lC89kD2J9eup\n0l13t7Xj//jH5I9fvAi88gq99uGHlAHyxS9aPx7DDBUszBGwe+CvpwdYuJCiXS2sCLPLFXvUbNRJ\nAGQr1NfTwJ+eMK9ZYz2fOhikqPWmm0Jf37iRls1S1hCZMIGq3u3ebf74PT00YPnlL1Pk/Ze/0OvP\nP0/pfzNmAP/zP9bazDBDBQtzBOwe+JMk8mP1IvCZMyk9zGw0F6vPbGSrANTWW28lMdOrZpeRAbz5\nprXznjxJHrNSgAHqJPbtI7FXsnixtWp6onLfnDlk1dTWAp2dlPnxwANURc9KRmUwSMWbvvAFOg5A\ng5cHDpA1wjB2wsIcAbsH/lpbyRbQQ6TMmY2CY4mY+/sjX19TE6WurVih78suXmx+lW9BXR0tKque\ntLN8OQneihWhry9dKhdTMsPu3ZSGBwCTJgGzZwMvvEDZJRkZFKnv3w90dJg73q5dJO5pacD27fRa\nRQX510M45MGMEViYI2C3lXH4sLEwA+SvmlkxG4gtYu7oAKZPp//0EBkkGRnAa69p7zN5MkXVA9mM\npmhv157UEgiQDXHpUujrubkkpFaOr0wBvP12av+cOfR3QgL5z2bF/rXXqAzqF75A/75yhXKuy8sp\najZ77a++CpSVyeMCgQAvOsCEw8JsQDBov5Vx+DCQnW28z8SJFMmaIRZhNkrbE5w4QVHsrFkklhcu\naO933XXm2wxQBDowXyiEAwdoBqTaz87MBMaPNzfQ2dcHVFaS/SJYtow+y40b5deKisw9bQSD1K7b\nb6fjJCUBv/kNvb5qFUX3b7wR+TjnzgE/+Ql1Gtu30xPLN74BfO1rNLhphq4u+5cUY5wHC7MBp0+T\nSEbKWrCCmYjZyoy+WKwMSQq3DNTs3UvtjTTQmJVlbRLIoUPanYIkkTesXjYrIYEE0YzP3NJCuc/K\nJ4HVq4FTp0Kj6EWLzKXhHTlCIpqZSX8vW0aDiSKjZPVqc+VPX3+d7vfjj1OWyPvvk9D+n/9DMyAj\n0dAAbNkC/Nu/0d+1tcA//zN1OMzogoXZALttDMCcMFvxmOfNo9oa0dSTOHhQFhs9WlvlCN8oOs/O\npn3N0NtL16f1JLJnD51Hkb4+yLJl5oT54EGaNKMmMTF00HXxYnOidvAgZdIIPzwriyJ+Mfn0ppuA\njz6KPJGlupp89RUrKIulupreu2kT3btIA76/+Q3wmc9Qx9PURFPhu7qAX/wi8jX8+MfAV79KFsy5\nczSB59SpyO9jhgcWZgPstjEuX6YR/fnzjfezEjEnJFDkZ8XfFbS1GXcS3d3U5tmz6W8jYbYSMbe1\nUYcyaVL4tsZGqvOsJZhmVxKvryf/WP2a2x36/gUL6PO4eNH4eHV1oSVRly2j94nMkdmzyeIxWhw3\nGKTFdz/xCRL49espQ2TdOprqPmsWPZ3o0ddH2Sqf+QwFCy++SOf84Q8pkhbLf2nR0EBPBhcukMf9\n3HMUoT/3nPF1791L0fyhQ5R58sILke8/z7S0BxZmA+zOyGhrI19VXbxIzbx59MM3m4YVrc98+LBx\nxCy2i0jRroi5pYVqOasJBumHX1RE3rZyth5gPmI+eVJbmGfNIpESJCZShxKp3cqnBoD89N7e0Kh8\n1izKv9ZDkmjgUaQHrllDxxU+eGYmCbUe9fX0nZg3j9779tvk/Sclkd1m9F6vl2yXO++ktMZXXqEI\n+uBBivT12L6dIuwXXqCc75deAv7zP/WFV3jmX/oS3Z/nn6eMlf5+/XOcOSO34coV9s8FLMwGxGPg\nL5KNAZBgLFxoHIEpiaaY0ccf0+O0qFOhhVqQjIR5/nxaA9CMpdLcTBM81Jw8ScIzaxaJmDozZelS\nc9HYe++RaCnp6CB/WR3xLVkS2c5Q34ejR2kgUjlF/ROfoIhYj/p6YOpU+e/ERBIi8dRw443G7di/\nX546f9NNFMWLoKGwMLTDUbNrF00QWr+eRDo5ma7n2jX9TJfTpymH/ZlnaODzlVcoNfDYMf2OrLaW\n7vN115GQ//739FnodRrd3ZTl8uijZKvcey/wne/oX0dTE3USPT3UBqMJR/399i69NtSwMBtgd8Rs\nVpgB6wOAViNmSSLxv86g8Ku6vUbCnJhI9UTMtEMtdIK2NsrIAMieUR9r0SKKFI1+cFevUrStzvjY\nu5dS7tTiF0mYg8Hw+9DQQNaGMgtl3jzjBQP27Qv9LvX305OIiBCXLzcW9uZm+rwA6rimTJE7t8xM\n/ckyfX00BrF6NXV2V67I92bWLP1r372b9k9LI5uksZHSG8VnoMXOnTRwm5tLVsmKFdSZ6O3/17/S\nd2bqVOAHP6COd/9+/fvw7LPAr39NU/afeAJ48kl9n/z73wfuv586igceoOhdi0uXqBM5dYoCIaPa\n4oEAfR+uXYt/ZM/CrMPlyxQ1qIvZx4IVYbYSBUcTMZtpi1pA586lH7k6x1iQk2PO625p0X4SUXre\nWtd03XUU4RudQ5Ioeh8/PvxabrstfEJLJGH+8EOyC5KS5NfOnQu3biJlt1y4QIIlaG6mqebiqSA9\nnaJqvQHAt96S7ZnLl0kse3ro79xcfZ+8tZUie1F3pLdXvhaja9+7V7ZdsrNp0HTcOIrsB5bnDKOx\nkSyTdevo37m5ZFkZnWPdOrqunTtJ+LOztYW8v59E+YtfpEHQ66+njkO1Ah0AehLct48ClmeeIavn\n97/X/t7+5jfAtm0k+v/yL/RUoPVb2rOHhP7FF4FvfQv4X/+L7qXWNZWV0dPjT38afY46C7MOhw9T\nb24UUVol0qw/JfGOmCMN/AHh4p2QQPdETxjnzTOXy3z5sra3rTyf3jVFGmTUisa7u0m4cnIo2lWu\nEBMpM0PreO++S2KivNaMDODPf9af/fjWW6FR/KFD9B7hmSckAPfco20T9PeTny3sGdGxCStl7lw6\n3vnz4e89eDB0yv2ECXLnZCTMLS3y+65elS2knBztFXb6+0nQ8vPJMjpxgu7bypU0IUdLFHfvpv2X\nLSOxX7uW/q1Vk+X4cUp/vP122nfpUtpXy8J57z0S7ZtvlisYzp6tHQ2/+y7wla/Q59PTQ523ltj/\n+c/UiVRX0/d/0iTtJ6TnnqPr+s53gKoq8vKjgYVZB7ttDCB+EfPChfQjVQ+WRWqL0cCf1iM8QH/r\ndQJmOoiPPqJ7KzI91G0yipjF+Y0G61pbw6PxlhYSiYSE8Fzs7Gw6r96jqVqYxaIAN90U2o5Jk8ga\n0HoMF6KlLFw1YQKts6gU92vXtK/tww/lrBKAorBp02ShcblIpLSis5Mn5fUce3ro0V5E6UadknJ8\n5fJluncACeKrr4Z3QEeP0jWmptL+06fT+SZMoA5JPWh74QIJ3JIlsn01axZ1PlqTbRoa6KkkNZXs\nmGnT6G8tYa6royAhP58+27Vr6X3vvBO63+XLJPh33km/nRkzKMo/cCD8mC0tVJVQkshGysmhlX+U\nnDtHn//f/z2d6/OfpwFhowFWPViYdbA7h/nCBfpv7lxz+1uZODJ+PB3XyKNUE6mTOH+efoTqlcGN\nfGYzbZYkirq1FrZVdhZ6x1q1ynj2nxBh9XGFyKg7j6lT6bFYr9C/+innxAn6oeXkhD8dLF6s/cRw\n6hQJybRp9PfFizQIt3x56P5691Zt/TQ1kSgp37thg/4juLAkWlrI5hFi7PGQcAtLRHDtGrVD3McJ\nE+jYvb0kSnPmhJ+ruVmurS1EWJznhhvCO5zGRhLi666TSwNIEt2T1NRwm0AIczBIloqop6IlzDt3\nUr749Ok09pGUROJcXx9+zI8+ok61t1eeyamOrM+dI4EVTxBTp9K51ddUW0uf4Y03Uke1fj19d6yU\nEhCwMOsQj6pyd98tRx6RWLSIxMJsYSCrKXNXrxpHzEeO0D5qATU6j5koXx05CkRUKdrk8dBgjDqS\nnT3beDRey3pQirWW4Bs90quP19ZGx0hPJ5FWDkTm5WnbPG1tofda/L14cagto/fEoRbmixcpCyQp\nSbYYpk8PFx4gtANuaaEc8fZ2EqJx4+g61Oc8dow6qylT6HN5/XUSTBFpFxSEd0DKgduWFtr/ww/p\n7/nzw+t1Hz4se+6trdT+5mY6Z3t7+H0UwtzZSR3JiRP0G+nsDPflJ00iC6W5mZ4yRHvUn3tTE1kX\n4p729tLTpySF2kL19TTYm5BAv8eeHjr+H/8Ymgp44ICcny8EPymJ/G6rsDDrEI8cZivpOxMmkAiZ\nXbLJivXR00ODFEapcpKkLaCRUubOnDG+Tj1hPnmSfpwiqpw8mX7o6lVTIkXl06eHdzjKc8YqzKLz\nGD+efsTKY4llttSohVlE4VlZoR2P3meofgoQOcz79sklSIUlo0RtR7W2UrSbkyOLrNa1K7/7J06Q\nuKWlyW0TIqrkwAF5lZ/mZhIoMWFmxYrwNMqGBtlzb2gItahuuSX8OyaE+fBhOvaJEySUak/63Dmy\nGGbOpPdMmyb7+W536NPBgQPyxKHz56lDcrnC78nRo9QZBYNyCuusWfQdVQr44cN0TS0t1LE1NVHO\nudm0VyUszBqIcph2R8xWl6eK1wDgsWMkokYDm3rtNRLm666j4xp9EY8c0T6ulrWidS7hp2uNiF+6\nRP6kusZztMLc20v3StmRiIgZCLcu9DoNtTCfOUMDSfPm0eOvGBjT+ww7O+W6IsGg3Abl+bS89zNn\nKCNBeNPiHiclye/TunaljdfaStG58rPQ6gTUkXlenrx/ejpZN+r9xT3p7w+1ddLSQv3yvj55MFJ0\nasIeUNsZra1UqMrlkuuunDpF383Tp0M/n4sXKfL1+6kNYvZkZmbovfT5KKvlww+pbfv20fHnzAnd\nTwxK1tfL1mJ6enS1TBwlzNXV1fB6vaioqNDc/sQTTwCA7na7OHmSelqjcphW0YsUjYhXypyZtujt\nM38+pSOpfUlBpIhW77iSFL5St9axxo+nH4SWny5J9ENQ20XRCvPRo3SuCRNCjyUERZ0yZ1aY9++n\nwlhiOr0yCtOq4Ldnj5zDfO4c3YPk5NDzZWTQNmUEru7sxN/K9+kJswhK2trIXlB2GkuWhM9KVXrx\nR45QRoQkUUeSkRFuSymzgl5/nXxoke2RmRkq/G1tJHRTpsgWSFsbHVstzG1t8qSdxkY6t5iRqc7o\neestuv9iDKKxkZ721J+reGpqbaXv/+HDdG5lxxwM0meyeDF9Dh4PCfTixcYzQvVwjDDXDSRHFhYW\nAgB8GldTUVGBrKwsZFhVOIvEIyMj2ojZSsF8sxGzmbbo7SNmJeqlzEXqIPQskrY2EiYzx9K7L1qi\nf+ECiYh4ZNUq+qSXnaDlVxtFzOnpJOZqX1wtzMp2ejzytWgtknDtGtlZ4rFfeX7lfZg8mToQ4esC\n4cL88cfhkbbWgKXy+y86ImXEvGhRaB3rjz6i7XPmkEAdOUKR6rRpFK0KW+rECdpf7JORQe+9cIEm\nwIixgyVLQr3bhgY5h7u1lf49aRI9EaiFWXlvRUaGuNZ16+T7Iwb7PB5ZmEWOfFZWqIUoSvW2tVFE\nPGkSXdeaNbKVcfo0tWP6dLJwxOc4a1Z063I6RpgrKyuRPJAF7/F4UKORTFhRUYHDhw/jNuHYxwm7\nB/6A6CJmK2KrN1imhZ44KjFqb6TMDL1tvb3yoI3W+dQdgd6x9F7XarM4rhjE1Cr6NGeOPGlDiVqY\ng8HQe6cWtcmTKRJWiqPSehAoO72MjNC2qK/txAl6fBZRoDJiV3dQ6r9Pn5Zzn0Wa4pw54cLc3Bw6\n1V0dMQthFu+ZN4+emsRYgiTRvUtICM1AUV6L8jtz6hRlNghLJSODRFE8iS1cGFpGVfjLgCySIqrW\nipgzMsj+EMuitbeT0KemyqlwYmB9woRQz19YLOKYV65QexYtovbl5pI4t7VRep3w0ZXfvSNHqBNo\na5PL5VotMuYYYQ4EAkhRFD7uFKMaCvx+P7xeL8rLy+PaFrtT5Xp7yR4Rj6NmsWJPTJ5MP2D1YJkW\nej6voKeHIgG1V6tsVzQpc8eP04CmelaeaJNaVK1GzGoBBCgVa8MG4/eLAR915KgW5tOn6T6LmXNa\nhZvUxz57ln78YubdlSsU6YkKg+r91fdW/eSiFzED4ZN/fD55gLe9naJudV3t5GSyCERnEgiQnSLS\nOsX5lB2/GEsQA4jKzqqtTe4MlJ+f8rqUTxDi8xGzOtvb6f+nT8vCr0yVE08B2dl07NmzSWDFYsDi\ne3TsGEWr119Pn9epU6ECqY6ss7PlHP3MTNmGOXZMXqNz/34S4wUL5N+QuD5xvGvX6L4oO4RFi6zP\nzHWMMANAMEKFmtLSUhQWFqKzsxNe9WgCgLKyssH/3ray0qYKu60MI0EyQnzwZssomo2wI1kZ4seh\nVwUv2pQ5vShc+WirJCODOhv19VuxMhobw8uLmvWZ9TIyBOIxVTkTTn1stY3R3h468KoWU/X9U1+T\nlYhZKZhqn10Ij/raRQaIyxX6hDBpEn0Wwo7QEiXxb9Ghqwcnhb+rtFgaG2UPPyeH9h83jo4hhF8I\ns7BFpk+Xxc7lImtDRLiiLepZpHpCCsgRs4jCp0+XrRLl5yfeI+6fOK7y+3vyJEXm119Pxzl1yni2\nrB6OEWY9Aw34AAAgAElEQVS32w3/wDe8q6sLqSIpcoCKigpUV1cDAFJTUyFpXKlSmAsKCqJuSzxy\nmK36ywA9Dore3gxmImzxYzNqT6TtRsKcnk5RhpaloifMfj/9wNQrxbjdNNJ97lzo61aEWS2Meu/X\nE2alR6uOyF0u+p4YDQCqz6+2kbTEVXlv1U83ymucO5csBOGXKwVA3dkpP9Np08hKEN8rtTCLoERp\nOQC0uK04vvJcymMrr9dMxKxs46xZoYOZR47Q09uxY7Kwi45SKbLCzujupv1nztSe3q/M6BHnVUbh\nys5DnF+0VdxPj0c+d0oKBS/nz8v3QJJoYonyvFbGigSOEeYtW7YMim17ezuKB5Y4Dgy45h6PB0VF\nRQDI5lgr1vWxmYsXqbc2yvG1SjT+ssDuAcAzZ0Ifx7WI5EEbCfOkSaEDPerjagm+2gdWonX96ogP\n0Pev9YRZ3X61MF++TB2C8nugdazs7FALZOnS0IwFo4E/ILwj07Iy9NL11H658l6pOzv1edWZGeIa\nlEGJ+j0JCeHCpd5PbbVoecx6wqwUcvEZNzfLeePKjlJpSwhhbm8HPv1pum5lOt7KlfTUOn68PDdA\nnPfMGdlqUpYbENcn9vP76fpTUkLPrd6vrY1+XwAJ9MmTIzxizsvLAwB4vV643W7kDkwLEmJcWFiI\nmpoaVFdXIy0tbXC73Rw5QgMlkYrZWyHaiBmwNgC4dGnkSSxm2hLJg164kDxJvdocViJa0Sa9jkAZ\nGQnUER9AP7ZZs0JT2wBtMdV6slBnZgiBUX4PtNqvHgCcPz90HUGtiFl5bydNokhUdGTz5lEEJsRd\neU6xoowye0V5r5UCoP4M1edVC7NWxKxuu/I9S5fKM+6U59KzWsQ97+8PTZXT21/8u74+fOBPva8Q\n5tZW+TupjJjnzJHzosX7xHdOecyFC8nb7umRf3fiHrS3A5/6lH47e3vl76r4vKZMocktmZnUAVjB\nMcIMyB5yaWnp4Gu1isXfSkpKUFJSgscffzxubdD6IcdKLBGz1WJGkax1M22JFDGrPUA1em3WO7dR\nm/RGtNXir3UMsZSXehBz0SIadFJOd8/MpOsRE1f0UuXU3w2rVkZPT/j4xYUL8nsSE0OjYLXoZWSE\nPllkZsqpXTNmUJsDgfD74feHCnN+vtyxKTsl5cC3uu3KqHfhQlpMtq+P7mV6upyBIt6TlkZPAn4/\niVRyMnVAotO7coXaIJ5KlEGIEDllRoYyYp45kz7fCxdosLGhIfTcegWxRM1w8R1XHlNZVlYZCQvv\nWXw3Zs6kc3Z3036HDtF9E9G48glAWChWFioGHCbMTiAewjxUEbP4IhgNFtoRMSvPpYVWm/UG+MT5\njIRZS+QjDZIB+hNOJkygqFOZqzpxIgm4EEQtYdY6h9rKSE2lqNDvl/1L5ffpnXfCbTL1vRR/+/0k\noKKQlHrwEaDrE9Ggy0VipYwIARLPAwdCy47OmCHXr1iwgKJ0IejKaFbP/sjIoI7s2DGqNzFhAnWC\nSvvE5aLCRuKeZmVRepmYjXj0KN1zsUCuxyPbOuJc6lQ50TaXS566nZJCT1EHD9L7enupsxDfYeXv\nYvFi2m/iRLLzlBGzaKPoONraqI3p6RRJi1xql4vuVVsbta2jQ15JXkxqEec9dowE32pGFguzCruF\n2UiQzGAlYk5Kosjk9Gn9fSK1RdQDiFWY1W0+e5Z+DFqzKY06Ai0rQ+scWqJl9FlGGgBUC7PfT4Kh\nrrYnfshiQoQyHU1ka4hx7P5+urfq+6+ekXbDDRRJtrWRAIgIWSsdUD09WkzNVn7OwuaZOFHeTzm7\nTqx9+M47FPWJLBY9KyMYpH2uv55qEgv7QOszSEiQO67MTJpEouUvA6GZHxkZcr2LFSvo3ktS6PGF\nsAKyQC5eTGI6d66cBZWSQhNYzp+n4zY2ygN06gFeZS6zuMZJk2gatvLJSzkTcM8eel8wSBaU+N5k\nZVE0HQxqr9hjBAuzCruFubOTvvgij9UqViJmIHKVuUgRs5ggoFyfzup5tDoTI3vEaJtexGzGyogk\nzEYDgFqpcmobAaD7lJoaGn2Lx2VxfvGeDz+U84aVqO9lSgrlzKpn7mkJn/q9SqEW7W9vD1/8Vv10\ntWQJlcsUA39qWwKgKHf9ernjz8oioRXn0RscFVaPmLghrunkSaprrWTDBmr/1Kn0WZw7RxFrRwfd\nZ+W9U9oxK1aQ4IoOR9kOl4tys0Wt7uZmOUDQipgPH6ZOobaW6oQAdB7lfjfcQO1fsoQ++zVr6O/u\nbrk2idtNNU7EepNWYGFWYbcwxxItA/RlDAa1V43QQl1nQI2ZVDkz7TUTMSstFb370NND0bSYcKFm\n7lzyXNUrYJgVZr1rycsLv6dGwmz0vVAPAC5bRp+BVg7zjTeGv19LXFtbQwfJ9K5n0SISADHoKyLm\nP/9Z3rexMXRFb4C+VytXyhMzliwhu0P4y+LeqFMYxQxCca6WFrmNkYQ5Kys06t2/X36aEEyfLtdz\nXruWvhciG0Rd5Gr+fHkad3o6ZVTNmaO97223yffz0iW6zr4+Cpq0fHSXi4758cf0pLN7t1xICpAn\nw1x/PUX5ouLeXXeFnjcpiaJmqyshsTAr+Phj6qH1RCIaYvGXgfCZWpEwEszLl+kHZ1Ss34y/HOk8\nbjf5hsr841OnKMJRE2kyS0JC6OCYQHlP9OwiIzGdNSu8rrOIpjo7yadUruRtJPJaA4AtLfSacqCv\nqSlcIAFq44kTsh0iojZ15DdhQngbxo2j7634LLKy6DyXL5NIAdoTplwuOp/oiJYsoWOIiFmSKAtB\n/YSwdKnsaYsKcuLYR4+GihdAg2RiNmpmJn0nhGd86VL4Wol5eXIGw8WLcmQrSaFLZIlji+/YxImU\nppaQQPdSPQ8hLY0i4HHjyOKYOpXu75UroVH40qVy/YtJk+QC/rfeGvrZLVtGxxPXISrgqeu9bNwY\n3bp/LMwK2tspArEzVS7WiBmIbgBQi/Z2ejQzKtZ/7py2gKpJTzcu5K/uTPbvp+hCjZn7o1VoZ8YM\n+lF1d4dPlRYYCbPW2oEiYhbRslKUtGwEgXoAULS3pSX0PXozSqdOJfuoo4P+nj+f2tfRIe//0Udk\nNWjl1y9dKkeZixfTU8jixXL7Ozq0PU6lyC5eTNGzOF9Dg/bvYO1aOcpOT6cOV0zBbmsLP092NnUo\nvb307+5u+o0Fg8Abb4SLbVaWXCBp3DjZF/f5wu/d0qXkcX/8MXXeQiDPnJHbJFi9mu5/MEjtuXaN\nrnFgusQg8+fTto4OeRXz/fvDr2vJErKlGhvpe33pEh1f/dvJyaHvmboOSyRYmBU4LSNDYGUA0GhN\nvrY2eQRcj337QiNFPbQyG5So26y3lJUZ60QtfAD9aNato/dribtIxdIbDRfpccoZimlp1Gnt2xfe\n1kgRs1qYW1vDa3ob1fheskQW18REitr37JHFSEz80BJLpTCLwbM1a+Tte/eGCyBA90/4xdnZJC7i\n+9/WRiKsRtw3gJ68Jk8mMbtyhSJI9XmmTKFORxRKGj+exPPkSRJ2dYSZm0tZE729JGZi9e+LF8Pb\nM2kSvebzkcimpNB5zp8PF8i8PPruHzhAA5xiHcWcnND9XC5g0ybqNMaNo46kri7cI05MpGv9+c/p\nGHv30m9B7ZmvX08BkdbqMkawMCsw+vFFy1BHzCJpXitlzkxbrC4YayYzQ29hV8CcMKutAkFKComd\n1nUJi0TP25s0iX5syqL+opjRnj3hEVJnp/59UbcvOZlSuc6fDxXi8eP1a7AsWxa6YOmiRfKjNEDb\ntMQVoOtQvnfhQjnn9vx5eckkNZmZcgH7q1fpXok622fPap8vJ4c80/5+edbc0aMkjHffLc96U5Ke\nToLo88kLs+7bR+1WWyVutyy2R4/S8draqAPRmlN2xx1kSQUC5JlXV1MEqx5sT0qie/rsszTA2NBA\n5xDZGUo2bABeeIF86dmzgV27gIF5biHcdx+17dFH6XO6+Wa5vKzyev7pn4BHHgl/vxEWLenRTVub\n/pc/WuyKmH/1K3P7JifTj+Xs2fAvyZEjxjVAjARUr11tbRRhqMnIkH/0nZ10bHWqGUCCNlCCW5fs\nbIpM1AjrYfz48AjJzNNPaio9yiv3E4Ngd9whv3buHAmD8GzVLFxI9/vyZVmYAgESOWGvXL4MvPYa\n8Nvfah9jzZrQ8pULFoSKqSRpDxwC5NP+8pfy35cuyaliBw9qCyBAUeT58xTBNjXRd6e+Xq5RrJVJ\nkJZG19XQQMdOT5ftBL2UsPx8iijPniVhP3CAIumByb5hbNpEArtuHVkS3/2uXINZa9/HHqPf7d/9\nHfCznwGK+WkhPPgg8NxzwNatwJtvak/2Achbd7vpvvb10f3UspBuvZWyM8aPN/4Of/rT+tv04IhZ\ngd1WRqSMA7NYGfwD9CPZSE8E585R1KQeibd6HrFNtFmIvZY4mCkYJawC9VOAEGafL3xA08xnqbQA\nlMc8fjxUZA4doohWq/0APdaKFDlBZmbovT50iKIuPSspOzt0KvdHH8nr+QHkeeoFDUuW0Cy8zk6K\nZBMS5Nzi+noSOC2Sk0nwfD4S5tWr6d8HD1IEqDUmAACf/CS1dd8+ijjr6kh4lfaJksJCin5raoAv\nfYnu+e7d4f6uoKSE9rnvPuB//2+6v5/9rPa+a9YAP/gB8K//CmzZAmzfDjz0kPa+69cDL71E9+sf\n/oEEXYvERBqLSUkhW085MUeN1YqRZuGIWYHdwnz0qHHGgVnmzCG/7dKl8BxYLYRg3nJL6OuRrAwr\n0bI4j3IlCyUZGXKOqd5xe3rI6zP64gMUpSUmUseh9L+XLAF+9COKRtWRT1dXuH+oZtkyivaUZGXJ\nA1WCxsbwwSQ1ovMQ57x4MXSJqOZm4+vMySFRFFH35csknMIDP3ZM/3oSE2n0f+dOelzPzqb7eu0a\nCfPdd+ufd9UqugdtbbTfW2+Rv3rDDfrvuece4FvfIn/4sceAL3+Zngz0hHbWLODv/56i88JC2rev\nT/9+ZGQAv/ud3Ik9/7x+W4BQ79nqRA6nwsI8wNWr0RWzN8IOfxmgCEgUqBHTQo3QyjgQ01SNxCEa\nYdaLmGfOpAiuq0v/uG1tJCSRBiQB+tG3toYK8+LF9EitNbPq3XeBf/kX42OuWEGeo5KJE0lUlRke\nkqQ9EKZErHEnmDIldF3EnTvDU8PU5731VvK3N2ygiHnePHrsd7lIrI0GZT/1KRp86+igKPLECeCP\nf6To36gC7l13kbjOnEniefw41Vv50Y/033PTTcC//zv5r7NnU5Q6bpy2vyy4917533oRvBIz34nR\nDAvzAGLevp2PJnb4ywIxAGhGmDMzgT/9KfQ1veprSqwKs3JVC/VTQUKCnBd8+LBcmUuJlZXIp06l\n6E85WDN1KkXT2dmhohAMhlYl02P5cnr/1avy5y5WTO7pkVO19uwxjjoBum8vviifXwyQnT1Lgnrs\nGPDww8bHKCqiiNXtpkyG3Fzy6RMT9W0CwSc/CXzlK9QBf+c7dL4f/5hqVRiVeM3JAZ5+mvz2yZOB\nsjJ6MotkZynFfvZs430Z67AwD2CUpxrLMe3K8rCSMqcVyZrNyFBGNpEQa9x1dGiv46fMk9XyR60I\n88qV2ilHs2eHL3R55gxFuOpULDWirkh9PfmrAHU0aWl0L1auJNH2+fQHqgTr1wOf+xztf+wY2S53\n3UVe7C23kGBGslY2bQK+9z2KkNeupQHIrVtJmL/3PeP3LlgA/PM/U6S9Zg1dT16eufENpehPmGDc\neTNDAwvzAPHKYVavNxctGRmho/ZGKOsgiAErMx2P1YgZII+ypUVbmG+8kR6pX30V2LYtfLvebEC9\n8+zbF/56amqoZQCQkPb26g/WKbnlFuCDD2RhPnKEHtWbm+WBsbvuogjWiNRUilrffpuevj7/eep0\nXnuN7Jy1ayM/nq9aRVHyvn3AT35CHctXv0p+rJny46KuA0DXbtfTGjP0cFbGAE6rw6zGSi5zSgqJ\nonJK9JkzxoVUrKbKKdt16JD2tgUL6FE8OVn7cfr9982vrZiTA/zhD6HL2gPkY4sptIL6evOCv2GD\nfF+vXKF/b9xImQYAibbZFMo776RR/7feIgvh3nup06iuBu6/39wxnnwSqKyUo/0774xsozCjDxbm\nAeJR7lOsTGwHVqwMl4tmLClX5KitNa6RoVzo0grLl4ennAnEIpnq+gkA+dJNTZF9YEFKCo3oq2cA\nJiaSJaEU7F27InuygvXrqWPp66PshDlzKO/U5yNbQgzGmWHzZmrn2rV03KlTgf/4D+CHPzTfHpfL\n3pIAzMiEhXkAu2f9ifKZkR6BzSIWktRbzkmN0t8FIvu50UTLAAmzMt9WyYIFNPCl5a22tVEmgJX7\nM3Mm1S0QnDhB7Q4EZJvn2jUSU3WqoB7z55NP/frrwI4dFC1nZFDbv/QlEkmzx5o4kYT4scdkG2XW\nLHsX9mXGBo4S5urqani9XlRUVBjuV15ebut5+/powMZOT87OjAyA/MmlS6mdZlAK89WrNEBnZw6z\nYOVKEjStVbFdLjnLQU1jo/UZUatW0UQGwd/+Rjm1GzcCf/0rvbZ/P12n0dOBmgcfpLS5tjbZcvjW\nt2jwTAy+McxQ4hhhrhsw9QoH5jb6fD7N/WpqarBjxw5bz93RQZGdcoWHWLHTXxbMnh1qTxihFGZJ\nosjQKBUwWmF2uymS1aplAZAoay0Q+/775oolKdm4kWwKMQOwvp4mQnzmMzTFFqDBNq0p4kbcfjtl\nPYi0MYCeUB57zFx6IsPYjWOEubKyEskDlUc8Hg9qamo093OZGWq3iFOryqkx8nPVKIXZTFpad7f5\ngTg1eXnkyarp6SH/98MPw7ft3Rt50oaaxYtJOOvq5HXsNm6k//r6KCPiwAGKoq3gcpEHbHdHyjDR\n4hhhDgQCSFFktXdqGJc+n28worYTp+cwC9QVyIxYtIiu6cIFEuZIU1XffTf66awbNoRWaRPU19OA\n4s6doXUu+vrImjE7ICYQi3tWVdGU3Rkz6B6PH08VvL73PeokOMplRjqOEWYACBot7wzAb3Z9JYvE\nI2Lu74+PMOulpqlJTCRRPnQocsR89SoJa7TCvGwZDZ6pqa+n6HXt2tAp4gcOUJ6xelkhM3zuc+Sz\n//d/U40Gwd13UzpdpGnYDDMScMwEE7fbPSi8XV1dSFX9as1Ey2VlZYP/LigoQIFRkQAFbW3hi1XG\nSk0NVb2yk6VLyWMWFcQikZNDlcJaWvSrcwHkDy9cGP2Mr3XrKApWTmMG6B4UF1MO9RtvyML/zjuR\nZ8Hp4XYDFRXU6ainApsp8MQwIwHHCPOWLVtQW1uLwsJCtLe3o3igVFUgEIDb7YYkSZAkCZ2dnfD7\n/fD5fMhTzZNVCrMV7I6Yu7up3kCkKcFWmT6dJmscP649007NqlWyMBtFzK2tofWHrSLSAvfupUI8\nAFkXH3xAtXTT0sh+EFRXUxGcaJkyhUWYGd04xsoQIuv1euF2u5E7MAe1aGDpgJKSEpSUlMDlcqG7\nu9u2QcD+fvMrQ5tFeNZxGKe05DPn5ND03uuvN+4kamvDV3ywypo1FCELxIobHg+tBNHcTFOVGxsp\n73njxtjOxzCjGVcwkrE7QnC5XBE9ai1OnCAPVNQOtoPKSlqporravmMKvv51ytF9/PHI+54/TxbF\nypUUverxqU/Rqg9WsxmU7N5N9SEOHSKb5Uc/ohoR4iGmvJwi8/5+mi79j/8Y/bkYZrTjmIh5uHB6\njQw1a9aYr5mRlha+RJEWygLv0bJuHU0/r60l8X399VB75J/+ie7J4sWhg3YMw4TjGI95uOjoiF2U\n1LS1Ga8AEQtLltBECLNcuaK9Vprg7Fma0mzGszbC5aJaEc8+S/czNTX0HkyaBHzzm7Gdg2HGCmM+\nYm5qsr/QdzyicMGKFRSRq0tdGmHkddfWUu6vmSyPSHz2s3LmSFlZfDx2hhkLjPmI+ciR2LxVLeIp\nzBMm0NTphobIEzTEytRGg4VNTeaL9EQiMZHziBnGDsZ8xHzkiL1Tpy9dosI98+bZd0w1elOg1Rw/\nTlbNoUPa9SoAKv5jtnYxwzBDw5gXZrtT5SSJBsHssAb0yM01J8x1dSS6YpFPNX19VEzI7sk1DMPE\nxpgW5q4uKlcZzdRgPeJpYwjWrKGVnCPh85Ewr1hBAqymro5WOklLs7+NDMNEz5gWZlEBzs5BqqEQ\n5rw8ypHWsycEHR0kvMXFwCuvhG/fsYMq1jEM4yzGtDDHI994KIR5yhTKBzayM/r7SYzz86n62+TJ\nVLNCyRtv0EKjDMM4izEvzHbXTB4KYQZIUA8c0N/e2koLoM6eTZkcCxfSatWC9nYqlylqWzAM4xzG\ntDDbPfAHDJ0wL18O/PnP+tv37Akd1HvwQeCXv5SXeXrpJfKex42LbzsZhrHOmBZmuyPmnh7g9Gma\nBh1vNmyg4vZ9fdrba2pCV3e+7TYqmfnii1TP+I9/BL72tfi3k2EY64xpYbY7Ym5vJ8vguiGYtjNz\nJvnHysVJBcEgCfNAYT4ANMD5/e9TgaWvfAX4whcorY9hGOcxZmf+Xb1KFeXsjG6HysYQ3HAD2Rk3\n3RT6+qFDVFND/TSwciXwP/9Dk2DsnobOMIx9jNmI+ehRmp1nZ3Q71MJ8331kZ6irnVZXU5F8rTRA\nMSDIMIxzGbPCHI+Bv3iW+9RizRpagXrfPvm1YBB46y2q9MYwzMhkzArzSE6VE7hcwGOPAdu2ya/t\n3EmZF/EqO8owTPwZ08I8UlPllDz4INkyBw7Q9PLt26kQfTxrdTAME1/G7OCfJNlX7hIAentpCnSs\nBeetkpxMQvzYY5QRMm0a8NBDQ9sGhmHsZcwKs90R87FjwJw5NMtuqNm8mSL106dpkdPExKFvA8Mw\n9uEoYa6urobb7YYkSSgtLQ3bXlVVheTkZLz88sv4+c9/HvV5gkG5gJFdDIeNoYRrKjPM6MExTmRd\nXR0AoLCwEADgU1Xo8Xq98Hq9KCwshCRJ2L9/f9TnOnOGivokJUXfXjXDLcwMw4weHCPMlZWVSE5O\nBgB4PB7U1NSEbC8sLMTPfvYzAIDf70dubm7U5xotA38Mw4xOHCPMgUAAKSkpg393dnaG7dPd3Y3y\n8nI8+eSTMZ3LbhsDYGFmGMY+HOUxB9VT2FRMnz4dW7duxaZNm5Cfn490VbGHsrKywX8XFBSgoKBA\n8zgcMTMM42QcI8xutxt+vx8A0NXVhVTVek91dXVwuVzIy8tDfn4+qqqqsHXr1pB9lMJshCRRtTW7\nuHaNcontjsIZhhmbOMbK2LJlCyRJAgC0t7ejuLgYAFkcAA3+CeEOBALIiCHktXvWX0cHcP31wKRJ\n9h2TYZixi2OEOS8vDwAJsNvtHhzcKxqoXfnwww9DkiRUVFQgOTkZ9913X9TnstvKYBuDYRg7cQUj\nGbsjBJfLFdGjBqjkZVoa/d+uacs//zkVEqqosOd4DMOMbRwTMQ8VkkQF4u2sJcERM8MwdjImhdnu\nQbqhLvfJMMzoZswJczxE9MwZIDvb3mMyDDN2YWGOkb4+wOcDsrLsOybDMGObMSfMdlsZR45QVTlO\nlWMYxi7GnDDbHTE3NdHCpwzDMHYxpoT52jXg+HF7i9k3NwNLl9p3PIZhmDElzCdOUA6znbZDUxML\nM8Mw9jKmhDkeC7CyMDMMYzdjSpglyV5/ORgkK4M9ZoZh7GRMCfOZM/aK6MmTZIsoykgzDMPEzJgS\n5oMHgfnz7TseD/wxDBMPxpQw253DzP4ywzDxYMwJs905zCzMDMPYzZgR5kAAuHqV0uXsgieXMAwT\nD8aMMAsbw+Wy75jsMTMMEw/GnDDbRSAAXLwIzJtn3zEZhmEAFuaoETaGnRE4wzAMMMaEmQf+GIYZ\nCVw33A1QUl1dDbfbDUmSUFpaGra9YmBRvSNHjuDpp5+2dGxJAu65x5ZmAqCVsdets+94DMMwAsdE\nzHV1dQCAwsJCAIDP5wvZ7vV6UVRUhNLSUkiSBK/Xa+n4dtfJ2LWL1g5kGIaxG8cIc2VlJZKTkwEA\nHo8HNTU1IdslSRp8zePxQJIk08fu66PKcgsX2tfeAweAnBz7jscwDCNwjJURCASQoig60dnZGbJd\naW3U1dXhgQceMH3sjg5g1ixgwoTY2wlQzY0rVzgjg2GY+OAYYQaAYDAYcZ+6ujqsXr0aubm5YdvK\nysoG/11QUICCggIA9mdk1NcDq1ZxRgbDMPHBMcLsdrvh9/sBAF1dXUhNTdXcz+v14qmnntLcphRm\nJXYL88GDbGMwDBM/HOMxb9myZdA3bm9vR3FxMQCyOATbtm3D1q1bAcDS4J/dA38szAzDxBPHCHNe\nXh4AEly32z1oVRQVFQEAampq8M1vfhOZmZlISUmBy4KPYHcOMw/8MQwTT1xBM8buCMDlcul61GvW\nAD/9qT15x729wPTpwLlzwJQpsR+PYRhGjWMi5nhip8fc2krF9lmUGYaJF6NemLu6KI9ZZyzRMuwv\nMwwTb0a9MNtd7pOFmWGYeDMmhJkH/hiGGUmMCWG2y18OBoFTpwCNuS0MwzC2wcJsgRMnSJgXLLDn\neAzDMFqwMFtgzx5KueOp2AzDxJNRL8xHjtjnMe/ezTWYGYaJP6NamHt7gZMn7bMe9uwBbrjBnmMx\nDMPoMaqFuaMDmD0bGD8+9mNduwbs20ezCBmGYeLJqBZmO/3lxkZgzhxgoJY/wzBM3GBhNokY+GMY\nhok3o16Y7Rr4Y3+ZYZihYlQLs511mDliZhhmqBjVwjxunD0R8+XLVFVu1arYj8UwDBOJUS3Mr70G\npKfHfpy6OmD5cvsWc2UYhjFi1ApzVxfQ3w8oFt6OGvaXGYYZShwlzNXV1fB6vaioqNDd54knnjB1\nLDHwZ8f06ePHgZtvjv04DMMwZnCMMNfV1QEACgsLAQA+ny9sn23btqG6utrU8exKlQsGgd/+Frjp\nphfamREAAAfESURBVNiPxTAMYwbHCHNlZSWSB2ZveDwe1NTUhO3z8MMPw2NSbe3KyGhtpZmDixbF\nfiyGYRgzOEaYA4EAUhSGcGdnZ0zHsytifvttoKAg9uMwDMOYxTHCDEB3letosEuY33mHhZlhmKHF\nMcLsdrvh9/sBAF1dXUiNcfVUO4Q5GKSIecOG2I7DMAxjheuGuwGCLVu2oLa2FoWFhWhvb0dxcTEA\nsjjcbrepY5SVlQGgNLmOjgIsWFAQU5taW4G1a+3JhWYYhjGLYyLmvLw8AIDX64Xb7UbuwMJ6RUVF\ng/tUVVWhtrYW27dv1zxGWVkZysrK8PnPl2Hu3IKYy32+/jowYwavWMIwzNDiCtpp7A4jLpdr0KPe\nsQN46ingzTdjO+YddwAPPwzcd58NDWQYhjGJYyJmO7Gjqtzly8B77wEDadUMwzBDxqgV5lgH/t55\nB8jPB6ZPt6dNDMMwZmFh1uG118jKYBiGGWpYmDUIBoH2duDTn7avTQzDMGZhYdagthZoaQFWrLCv\nTQzDMGYZdcLs98de7vOll4AHHuA0OYZhhgfHTDCxCxEtRyuq/f1AZSXlMDMMwwwHoy5ijtXG2LUL\ncLtpxRKGYZjhYFQKcyw5zL/9LdkYDMMww8WotDLy86N7b28v8PLLwM6d9raJYRjGCqMyYo7WyvjT\nn2ilksxMe9vEMAxjBRZmBT/4AfDQQ/a2h2EYxiqjSph7e4GTJ4EFC6y/9/33gVOngHvvtb9dDMMw\nVhhVwnz8ODB7NqIq9/mDHwBf/zqQmGh/uxiGYawwqgb/orUxJImKFv3qV7Y3iWEYxjKjKmKOVph/\n+EPgy18Gpk61v00MwzBWGfMR8+HDwAcfAK+8Ep82MQzDWGXURcxWJpcEg8Cjj9KEktmz49cuhmEY\nK4wqYT5yxFrE/OtfA4EA8NWvxq9NDMMwVhlVa/4lJQUhSUBqauT9T56kySR/+EP0MwUZhmHigaM8\n5urqarjdbkiShNLSUsvbAXPlPi9cAO66C3jsMRZlhmGcR1RWxttvv21zM4C6ujoAQOHA6qc+n8/S\ndsBcuc+eHuCee4AbbwS+9rVYW21MPO5TrHCbzOPEdnGbzDHS2+QYYa6srERycjIAwOPxoKamxtJ2\nel3/+MEg8Ne/UqTs8QDPPhv/Qvgj/csxVDixTYAz28VtMsdIb5NjrIxAIIAUhQ/R2dlpaTugLczB\nIOD1At/+Nq1u8u//DmzezDP8GIZxLo4RZgCINA4ZafuiRUBnJwmw3w8cOwY89xxw5gwJ8gMPsCAz\nDON8osrKcPFieAzDMJYxK7dRRczxyLDz+Xyora1FaWkpysvLUVxcjNzcXAQCAbjdbt3tDMMwow1b\nJpg88cQTMR8jLy8PAOD1euF2uwdFt6ioyHC7k7HjvjDDS3l5+XA3gRmLBGPkF7/4RTAjIyPWw8RE\nVVVVsKamJrht27ZhbYcSJ9wXNdu2bQtu27Yt+MQTTwx3UwZ5+eWXgzU1NcFHHnlkuJsSxo4dO4LF\nxcXD3YxBvvGNbwSDwaCjvuf79u0LVlVVOaZN+/btC7pcrmBGRkYwIyPDMd8rqxoVc8T88MMPwxPL\nstQxYia/eTgY7vuixuv1oqioCKWlpZAkCV6vd7ibBK/XC6/Xi8LCQkiShP379w93k0Jw2lhKRUUF\nsrKykBHLasM28/TTT6OkpASBQMARv72uri709/ejra0NL7/8Mr75zW8Od5Pg8/ng8XhQWFgIj8dj\n6j6N+FoZZvKbGUCSpMF74/F4IEnSMLeIOtOf/exnAAC/3+8oe8rn8w129k6hoqIChw8fxm233Tbc\nTQEAVFVVYe3atQCArVu3DtqNw4nyM6utrcWiRYuGrzEKhK0pSZKp+zTihdlMfjMDlJaWDk5jr6ur\nG/xBDTfd3d0oLy/Hk08+OdxNCcHv9w93E8Lw+/3wer2O8b1ra2vR2dkJn8/nmDYJvF4vNm/ePNzN\nAEDjY+np6UhJSQnRKiMiZmVUVFSEvZaSkoKSkhLrLYwTwdFRh2lIqKurw+rVqx0TnU6fPh1bt27F\npk2bkJ+fj/T09OFukiOjZQCDHeuOHTsGLaDhJi0tDXl5eaipqUF1dbVjdGHHjh2OuD8ABY+ZmZmo\nqKhAaWmpqe95RGHWKxbkFNxu92B009XVhVQzpeXGMF6vF0899dRwNwMAdRIulwt5eXnIz89HVVUV\ntm7dOtzNgiRJkCQJnZ2d8Pv98Pl8w/6YXlFRMRgQpaamQpKkYRee1NTUQYFxu93Yu3evY4RZjD05\ngYqKCjzyyCNISkqC2+029T2P2cqoqqpCbW0ttm/fHuuhomLLli2Dfml7ezuKi4uHpR1qhvu+aLFt\n27bBL4RTBv9EpxoIBBwzqFVSUoKSkhK4XC50d3c7YhDQ4/EMpo52dnY6woq6//77B397gUAA69at\nG+YWEU4YP1GTlJQEgDxwt9sdcf9RUY+5oqJicEDL6RH+cFFTU4PNmzcjJSUFfr8fVVVVwz6I1N3d\njcrKSgD0Y3JKJO9UqqurAVAA8vjjjw9zawgRydfW1jrm82tvb8czzzwzOLDsBMrLy+HxeOD3+01p\n1KgQZoZhmNHEiM/KYBiGGW2wMDMMwzgMFmaGYRiHwcLMMAzjMFiYGYZhHAYLM8MwjMNgYWYYhnEY\n/x9TP3s0txWEHwAAAABJRU5ErkJggg==\n", "text": "" }, { "output_type": "pyout", "prompt_number": 4, "text": "" } ], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": "The Cornu spiral defined as the parametric curve $u(t),v(t) := C(t), S(t)$" }, { "cell_type": "code", "collapsed": false, "input": "figsize(8,8)\nplot_parametric(fresnelc(x), fresnels(x))", "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAd0AAAHTCAYAAABiN8IeAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzs3XlYlOX+BvB7EFwQdQDN3RTNFtPE9deiYaCZtpmWthzb\nJDtlq5l22mzVNLOyrKTUbDFRykxzg1zaXBBMTT2mg2aKG5ui7Mzvj/uMA4qAMDPvvHB/rosLhhne\neQaXe77ParHb7XaIiIiI2/kY3QAREZHqQqErIiLiIQpdERERD1HoioiIeIiv0Q0Qqc5iYmJgtVph\ns9kQGRl53veLiLmo0hUxSEJCAgAgPDwcAJCYmFjs/sTERISEhCA8PBwhISFn3S8i5qPQFTFIdHQ0\nAgMDAQAhISGIjY096zFjx44FANhsNoSGhnq0fSLiegpdEYOkp6cjKCjo9O2UlJRi94eGhqJNmzYI\nCgoq9jgRMS+N6YoYqLS9adLT09GuXTtERUUhMjISXbp0QZs2bYo9xmKx4OWXXz59OywsDGFhYe5q\nrohUkkJXxCBWqxWpqakAgLS0NAQHBxe7PyoqCiNHjkT9+vVhtVqxYMECjBkz5qzrjB8/3hPNFREX\nUPeyiEGGDh0Km80GAEhKSkLfvn0BsMJ1qF+/PgBOtrJarZ5vpIi4lEV7L4sYJyoqCiEhIcWWBHXr\n1g3x8fEAgMmTJyMkJASpqaklLhmyWCyldlGLiHdR6IqYmEJXxFzUvSwiIuIhCl0REREPUeiKiIh4\niEJXRETEQxS6IiIiHqLQFRER8RCFroiIiIcodEVERDxEoSsiIuIhCl0REREPUeiKiIh4iEJXRETE\nQxS6IiIiHqLQFRER8RCFroiIiIcodEVERDxEoSsiIuIhCl0REREPUeiKiIh4iK/RDRAREfey24ED\nB4C9e/n54EEgMxP4+29+Dgjg9wDAYgH8/YG6dYH69YEWLYDAQH5u0QIICeH9UjEWu91uN7oRIlIx\nFosF+icsReXnA1u3AuvWAUlJwNq1wPbtQJ06QGgog7RZM6BVK4ZtQAC/Z7EwnO12ICsLOHkSOH4c\nyMhgWP/zD5CbC6xfDzRpAnTsCFx+OdCjB9CzJ9C0qdGv3BwUuiImptAVAPjvf4Hly4EVK4DsbFat\n//d/wLXXAm3bApdeCgQHu+a58vMZ5jt2AAkJwIYN/NrPD+jbF+jfH+jTh2EuZ1PoipiYQrf62r4d\n+OYbYMECoF07oHFjoF8/Bl7Dhp5ti90ObNnC4F++nEHcqxdw/fXAHXeoCi5KoStiYgrd6iUjA/jy\nS2DWLMDXl8E2ZAjQvTvg40XTYjMz2a09bx6waBHQtSswYgRwyy3s5q7OFLoiJqbQrR7++gt4/33g\nq68YskOGAOHhQI0aRresbFlZwJIlwMyZrIAfegh44AFW59WRQlfExBS6Vdv27cDrr3OM9pprgEce\n4SQos9q3D4iOBiZNAnr3BsaM4dhzdaLQFTExhW7V9M8/wGuvAT/+CIwaxbCtV8/oVrlOZiYr3++/\nZ7f4m2+yi7w68KJRABGR6i0ri5XtFVcAjRoBf/4JjB1btQIX4Mzmxx8Hli1jV/mgQcBttwE7dxrd\nMvdT6IqIeIFly7i0Z/NmID6e4Vu/vtGtci8/P2DkSI5ZX301cMMNwJNPAunpRrfMfRS6IiIGSksD\nhg8HHnuMXa4LFgBt2hjdKs+qUwcYPZoTrU6d4mznr7/mUqSqRmO6IiamMV1zi4sDnnuOk4kmTODW\ni8JK/8EHue3kxx8DLVsa3SLXUeiKmJhC15wKCoA33mCgzJkDREQY3SLvk5sLvPUW8Msv7Am4+26j\nW+QaCl0RE1Pomk96OvDss8CuXcDcudqtqSyJicBdd3F28wcfmH+cW2O6IiIesmcPcOWVQO3awMqV\nCtzyCA1ld3Pt2sCdd3JGt5kpdEVEPCA+nmtuH3uMu0v5+RndIvOoWxeYMQO4/XYgLAz49lujW1Rx\n6l4WMTF1L5vDL79wHWpUFPcflorbuBEYPBh44gng6ad5JKGZKHRFTEyh6/1+/RUYOpQHFYSFGd2a\nquHQIWDYMC6tmjHDXL0GCl0RE1PoereEBJ4v+8UXPOZOXOfkSb6ZKSwE5s83z3IrjemKiLjB9u3A\nwIHAJ58ocN2hbl1g4UKgbVtWvRkZRreofFTpipiYKl3vdOAAz4+9+27gnnuMbk3VZrdzctqGDcDy\n5UBgoNEtKp1CV8TEFLreJycHuPZa4Oabgf/8x+jWVA92O7eRPHSIY7wBAUa36NwUuiImptD1Pg89\nBKSmcpzRbDNrzcxuZ+9CcjKPDPTWyVUa0xURcZEZMzhbedYsBa6nWSzcVtNi4Rsfb30vqkpXxMRU\n6XqPbduAMWOA994D2rc3rh25ucCWLdyMY9s2YP9+Hhq/bRvQsSOwahXQrh2/36oVv5eZyUMXmjbl\nDlAdO3IHKDM6eRK47jqgb18ej+htFLoiJqbQ9Q75+Qythx9mF6en7dnDmbwbNwJLlgA9enANa4cO\nwMUXA82bAxdcwH2LHWGanc0ZvykpwN9/82P9ep7nW7s2H3v99Rybvugiz7+myjh6lOfzPvkk8Mgj\nRremOIWuiIkpdL3DhAmsIJcv91y38okTwLx57MpOSwOuuQYYNIh7O1utlbv28ePATz8By5YxyC0W\n4L77OBvb22cHO9hs7GZ+/nmgTx+jW+Ok0BUxMYWu8bZt405TmzYBF17o/uc7ehSYOpXP5+/Pyrp/\nf6BGDfc8X0EBz/398UceQ3j33Zwp3Lq1e57PlVauBO69l78rbzlcQqErYqCYmBhYrVbYbDZERkae\ndX9CQgKSkpKQmppa4v0KXWPZ7dwV6frreei6O506xfNlf/yRx9w9+6zngy85mcfrffMNg/7FF4Em\nTTzbhvM1fjywejUQGwv4+hrdGs1eFjFMQkICACA8PBwAkJiYeNZjJk6ciMGDByM9Pb3E+8VY8+cD\nf/3Frld3WrQIuPRSnsG7YAEwfboxlWbTpsAbb3Dst1Yt4P77WXXn53u+LeX14otAzZrASy8Z3RJS\n6IoYJDo6GoH/GyALCQlBbGxssfsXLFiA7t27AwDGjBmD0NBQj7dRzi0nh92tU6e6r2s3NZVbHL77\nLvdvnjvXM13YZWnYEHjnHc7UXrKEbzp27DC6VSWrUQP46itg61aOUxtNoStikPT0dAQFBZ2+nZKS\nUuz++Ph4pKSkIDExEZMnT/Z086QMM2dyvNNdJwdt3MjxyCZNGGy9e1fuenY7K9L8fNetYW3fnuOm\nvXvz48svvXN9bKNGwMiRQGQklxQZyQt6uEWqr7LGYxs2bIjQ0FDExsYiJiYGgwcPPusx48ePP/11\nWFgYwnR+nNvl5ABvvgnExLjn+nPn8rzYGTOAW289v5/NzmZg//Ybl//88w+X/6SlcX9iiwXo1YsV\nYFoa1+x27MhZzz17nv9pPY7NKHr3Bu64g+OnH37I7mdvcuON/L2+9BIwZYpx7VDoihjEarUiNTUV\nAJCWlobg4OBi9wcHB6NNmzanH7tx48YyQ1c84+uvgYgIrod1Jbudy4+WLeMSpA4dyvdzx4/zDcBv\nv3EZUVgY19becANwySVAixZAcLAzCHNz2XW9fz/Hif/4A5g0iet9L7wQGD4cuOmm81sedMklfP4n\nnuDSpblzgQYNzvtX4FbvvQdcfjnfHPTsaUwb1L0sYpChQ4fCZrMBAJKSktC3b18A7HYGgCFDhpy+\nPz09HT1c/T+8VIjdzhm8t9/u+uu++CJ3k5o3r3yBa7Nxdm6HDsDixQzZffs48WrKFIZnjx5As2bF\nK8+aNdlt3b07lwBNmsSg37wZePRR7mbVpg3w3HPAn3+W/zUEBABRUUBICIP/8OHz/S24V8OGHB9/\n8EH2VhhBoStiEMfEqLi4OFitVnTu3BkAEBERAQBo06YNrFYrYmJikJqaittuu82wtorTunVAejqX\nzLjShAmsOqdNK3tN6eHDHKMcNYphvWEDK93bbqvc5hV167JKff99YPduXmvgQM5STkoq3zV8fPga\n7rgDuOUW4NixirfHHYYO5e5hH39szPNrna6IiWmdrufdfTfQtSvw9NOuu+YXX7DLeubM0gPXbudj\nnnsO+Pe/2ZVbZC7eaYWFXMq0fTsr56ws3vb35zhucDCr0SZNgM6dOabr71/yc2Zmcob2mjUctx03\njpVyWex2PjYujl3l9eqV73fhCbt3M3h37OAkK09S6IqYmELXs9LTWb19913JYVcR69dzyU1MDHDZ\nZed+3JEjrDitVoZZx47F78/P50zi+fOBX34B8vKAAQNYrbZty9CrU4dhmJ7OannHDm54kZ3Nx3Tr\nxkq3pCDav5+VdWEhlwuVZz9mux144QUG/8KF7ltaVRGPP85JYO+959nnVeiKmJhC17O++IKbU3z/\nvWuul5rKU32mTePBAufyxx/sTu7TB3j11eJnxZ44AXzyCavJlBQuM7r+elay5ZWZyVnHa9Zw2U//\n/qzkzwx2u53dsh9+yE0ybrml7Gvn5QH9+nHi0sSJ5W+Tux09yg1H1q/nGw5PUeiKmJhC17NuuQUY\nMgT4178qfy27neOel18OvPzyuR/300/c/vGBBzge6ZCfzyVFS5ZwSdCzzzLAAQbKqlVAQgJPElqz\nhlsgNm3KqrNTJ6BlS3Yzh4byKLwLLuDPpqYCn33GNxedOnGJTcuWxdu0cSMr4ldeKd/2l8eOsUp/\n+GGOEXuLN97gphnffOO551ToipiYQtdzjh9n+Pz9t2uWwixcyHHcOXPOfXbt2rUM+ejo4ptw7NzJ\nMd169XhmbKdOHLddsIABu2kT23rddTzar2VLdofXrMnlQikpwIED7F7++Wfg11+5jjUsDBg8mOO7\nmZmsoGfN4ozmhx8ufoLSvn08s3bUKHbVlmXNGuDOO1m1e3oc9VxOneKM73ffdb5hcTeFroiJKXQ9\nZ9EiHjbgilmvWVkcv/3sMwZjSRIS2M377bc8ts/hm29Y+T75JJcE5eYCn37Kqu3GG1lJXn01u03/\n+IPheOwYN8nYu5fB2bMng7hlS47jdu/OUFy2DPj9d4bjo48yfLdvZ0Wblwd8/nnxCVEHDrCNDz0E\nPPZY2a977FiOH3t6HLU0U6ZwidTcuZ55PoWuiIkpdD1n1ChuHDFmTOWvNXEiQzU6uuT7Dx5kd+zI\nkVwGBLA7esoUVqXjxwNXXMEqddIkbkf55pusxqdPZ4DeeCM3rKhVi0Frt3NtqsXCMeGaNVnxLlvG\npUp3380JXb6+fGMRF8cJU/368edef51j2cuWcd2vw969PF7wiSe4oUZpsrJYlU+b5volVxWVkcHx\n78REoFUr9z+fQlfExBS6ntOxIyvTyu5RkpLCzSx+/50bUJypoICVY+vW3CzD4aWXGLJz53L89dVX\n2Y384INc+vP88wzTvn25VnbhQi4Pat/eWZ1mZfH6J06wi7pWLc5wvvRSzmJes4bB89xznK08ciTD\n+MUXGcbTpzP416wpPs67bh3fjHz2GZ+vND/+CDz1FMdSy7P0yBNGj+ZnT2wPqdAVMTGFrmekpDAg\nU1Mrfybr5MlcMztjRsn3f/wxu5SXLWN4AtysYs0a3levHsPw5Elea9o0VqUjRrBCXruWY6b167NL\nefdudg03b8625+Vx2U+TJtyhyc+P39u1i9VxvXrAihUc6xw2jN3MhYVcH1y/Psd533mHFXfDhs52\nT5vG8enffis+u7okw4cDV13FcWJv8PffHNO12dy/daVCV8TEFLqesXw5w+bbbyt3nawsdlH//DMn\nOJ0pKYnjqxs2OJf8xMVxrevcuQzKJ59khfr44wzfZs245OX334HGjYFDh7gG94ILOJb73/9yrW6t\nWqwsGzRgiFosXLdbUMCq8/bb2b7NmzkTeu5cVr2vv84x2FWrWKU2aAC89hpnMMfEOAPWbufkrjZt\nOHZbmvXr+Xx//eU9ByPceSfHtx1Vr7toG0gRkTJs2eKa8b5Fi7jUpqTABVhBjhvnDNwjR7g86Y03\n+PyObR9HjmS38tVXM2S3b2ew7t/PQM3L47KhkyfZTd2oEbd49PXlRKasLHYxOzbGaNyYP3vkCCdt\nffEFJ3o1aADccw+r3YgIji/n5LAru1kzdnE7WCzslo6K4jhvaXr2ZKXrrlOaKuLJJ7nntbvfwyp0\nRUTKsGXL2RtFVERUFBAeXvJ9CQms/B591Pm9J57grODrrgM++ohLXJ59lt8fOJDjthdeyIo2JYXd\nyceOMXDT0zmmm5bGWcaHD/MxBw+yGzUjg9dLTuZOUceP8+dtNq7fPXyYpw716sUx2Mce43jt2LHs\n9n7tNU4++u03Z3sdJxS98ELZv4sHH+QkMG/pqOnRg7+D33937/ModEVEynD0KGcCV8bhw6w0zzXD\n94svOI5apw5vr1rFEHjiCYbbnDlcuvPyy6wUf/qJ3aEbNrByTU5m0GZk8BqnTrGKPXnS+fnECT7W\n15e3c3K4Hjcriz/r48Ofz8hgF3BAALueL7qIleCECayI589n9XzvvdyXOT/f+Tqeeorhvn176b+P\n8HA+97p1lfu9uorFwjcMc+a493kUuiIiZdi6tfLdy0uXOvc/PlNyMjB7NnedAlj9zZjBZUO1anHC\n0b//zbBzVKeBgZwAlJrK8MzI4LraU6f4JiEz0xmqjoDNyuLH8eO8ffIku6MzM/nzhw7x67Q0Bu3R\no6yCCwv52C++AJ55hkuW0tO5cUf9+tw60qFePXYdlzUT2MeHQb5oUeV+r650zz38HWdnu+85FLoi\nIqVwjI+WddxeWbZtO/dexQsXMmAdS3t+/pn/8d92GzfDaN6c3dvvv891rhkZ3Cs5OZkTpo4f54So\n9HR+nZfHn8/NZWAWFrIaLSjgB8D7T51iCJ88yZ/z9WWQZ2ezovXx4TW2buWWld9+y7C/9VZu0GGx\ncG3vokXFq92HH2a3c1pa6b+TAQM4K9rRJqO1agV06cLZ2+6i0BURKcXhw5ywVJmlQoWF3PLxqqtK\nvn/WrOJ7Ei9c6Ly9cCHwyCNcBztmjLPb+ZJLOHP4+HF+pKczIHNyGICFhc7rWSysWH19i2/lCPCx\nOTn82ZMnWS0nJ/Nxycn8CAlh+wcM4GEHjzzCpUlHjnDM12LhDG+HRo04IeuHH0r/vTiOF3T3OOr5\ncGy76S4KXRGRUqSlsdKtjORkdsOWtBlGcjKfo3dv3s7IAP78k//5//wzt3H09+eRftu2cXnQkSP8\n2lGlOtbe5uQUD9sGDdgtvX49Q/nkSa7Hffdddh87Ariw0Bm62dkM6OxsVrqOjTSsVnaNb9vG30dY\nmHOt8S23nD0WOnAgt40sy9ChXPPrLQYM4Bppd1XfCl0RkVJkZnJCUWXs2MHJT2dWmQAr144dnetd\nV69mF67VynHeO+/k0poePbhBxuHDPLygaVOGrqMruWjg+vpyHe+xY9xFqnt3voaaNYF27Tg5a9cu\nrrutX9/ZFrud4XvqlLPLuV49Xq9+fZ7XGxEBfPUV19n+8APDadAgBlVKivNa/fo5J3aV5ppreD6x\nt2jZkt3569e75/oKXRGRUmRnl+/A9tLs2MF1siVJSOA5uQ5r17IbuqCAE5tuuokbUZw6BXTtyiBz\ndCWfOMGPnBzn0htfX3aPvvde2V3i/ftziVDRvZSLdlEfO8bQzMzkcqb0dHYJz5rFtcb5+TxUoV49\njvPGxjqv4+/P8eeyuo67deOYcVZW6Y/zpAED+IbEHRS6IiKlyM9nF3BlZGby3NySHDrEjSgcVq4E\nrryS3bh793KNbZMmzuCuW5fdvunprGx9fIqvdX3zTVae5RUczGVH/v687Zh4lZPD5/LzY+DXqsVx\n5Lg4hv/q1exidozlXn011zMX1aoV3zCUxt+fIXfmzxpp4ECeU+wOCl0RkVL4+lZ+fK+0Sjczk7tG\nAQz4rCx2N2/YwHHehARWl6mpDNqsLI4B16zJx+flOUO3TZuKnYLUvDkPVHDIy3POdk5LY+DWqMHn\niY3loQrr1zN09+3jz3TsyC7rokJDy9dN61gP7C3+7//Yw3HwoOuvrdAVESlFjRrFl8NURK1arCjP\nZLdz/W7z5rx94AC/rl2b46OXX87u2YAAXiM1laEbEMDqEyg+certtyvextGjnW8MHGO7ubnO3aoc\na4EvuoiVt6NCd0yCuuwyvpaiVfell/K1lOXii7lHtLfw9eXrdMcEL4WuiEgpAgI4qagyjh1jeJ0p\nO5vdq45gSklxBvDWrZxMdeKEc8mPY7LViRP8bLc7Q65mTeDmmyveRl9frlF1sFgY6DVq8PWfPMlZ\n0zVqsEs7NpbbPu7cyXBu0ICToo4ccV6jZUtg8eKyt3q85BLnmwhv0bOneyZTKXRFREoRHMzQrIxT\np0qeuZydDXTu7Lzt2DkKYEXboIGz0q5Zk2Hn6+tc4lM0zAIDK3/sYNGzgh2BnpfHdmRnsyu5Vi3n\nZCtfX/6MY0nV3r3Ff1f+/gzysmYwBwZ6V/cywNe1YYPrr6vQFREpRcOGlQ/diy4quYva1xeIj3fe\nLix0VorBwc5TgRzjtgUFDOEjR3hf0Uq3soELsNvYoaCAz+tYllSjBpcbWa18A9GmDdt7wQXOmceN\nG59dsR48WHZPQcOGDHJv0r07x9MrO7RwJoWuiEgp/P05kanoGtTzlZXFMdAz1anD8HJM1KpXj6EG\nsKLMymIVabE4d43Ky+PPOSpnx2dXhNaZm4D4+rLCTk3l7UOH+PuoWZPt8PEpPqbcuPHZFb3dXnZw\n1avnnklLlWG1Ai1acKMSV1LoioiUwmLhmOvu3RW/huNw+TP5+rLr1hF2wcHOytVi4f7Hl13GsdwT\nJ1j1Zmc7g7lowKWlObumK6roxCE/P4aqnx8rUbudbc3L4/M62pya6twzevv2sw+lv+CCksezi/L1\ndX1F6Qrh4Vy65UoKXRGRMrRvf/ZymPP9+XMF4qlTPGQA4CSqlSv5vQ4dOIbasiVDLjub4XbkiLM7\n18fHGbz5+dwfuaIcG10AvKbFwqB1TKgKCHB2tVssDOCcHM64btiQP1dQcPYs7Z07naF8Lj4+rjmv\n2NVateKxiq6k0BURKUNlQ7dZs3MvP+nRw1lN+fpyYtW2bQyh/ft5OzWV1W3jxgywEyfYzXvmAQYv\nvFDxQ+HffZdrhgFn6Pr58Xr16nE5kb8/lw9lZXE7yN272dVcowa/d8EFbKNDdjbHRotuNVkSx57Q\n3qZdu8r1cJREoSsiUoauXSs3ttepE7uXSwrELl2ApCTn7YgIYPNmfn/3bmcIN2/OEGzZkmGQn198\nGRHAcdGnnz7/9h0+XHxzDMdYrp8fA9duZ9gGBfH5//yTY9Hx8cB11/FnduzgRKyiXcn79jm7o0tz\n/DgrZ2/Tti2wZ49rr6nQFREpQ9euPGyg6KSh8+GYFfzXX2ffFxrKwHLo0gXYtImTpZo1Y5dvQAAn\ncyUlOWczN2jAcPTzKz5z+b33gKlTy9+2tDRWo44ua0eFW7Mmx7IdG2Ts2MGKNDQUmDuXYbt9O/dO\nBrjkp1Gj4tfeubPsKhfgkqKuXcvfZk9p25Z7U1e096AkCl0RkTI0a8bwqMyuSV278kShM4WGcj3o\n3r283bcvT905dgx44AEGXP/+fExKCjekcMwSPnWKwVizpjN47XZWuwMGsIIszU8/sWrev5+3a9Tg\ntRyBC7BbOTDQ2a5Wrdjd3rYtsG4dt4IEOBZddHMNgL8vx/2lSUriGwlvU68e3/BUdu/tohS6IiLl\ncOONZW/eX5p+/Uo+cadGDQbk/Pm8Xa8ecMMNnBQ1cCAnJ3XrxsC9/35WXo4uW8e4rmOmsU+R/9GX\nLmXl2asXz73dvJlV66FDwCefcIvJfv2cy4EcP+/ry8D18+MbjZMnnScJ3X8/K/5hw3jwQW4uK/Dc\nXGDFCr45KGr37uKHOZyLzcYQ90bduzvfELmCQldEpBx69gS+/bbiPz9wICtFx2SlooYPZ4g5ujEf\neQT48EMGX69eDOD77mMXbtu2rLyDghiO+fnOvZn9/IqPn+bmAr/8AowcySq0bl2Oyf773xyXdawP\ntlicFW6tWs5KNyeHlfWAAXzD0LcvK++77gK++QYYMYI/HxvLNwpFjwjMyuJjrr667N9NZia3gvRG\nNWu6dg2xQldEpBwGDGB3bEXPfQ0KYoVY0jmtV17J4IyL4+2ePRmSX34JjBoFzJvHQwEcS4lSUljF\nhoRwAwd/f2dXaECAs/ItyrFJRX6+M9wd1W3t2vwICOAsaR8ftrdFCwbv/v3AkCHA++8Dr77KCnbZ\nMoYvACxaxBORilqxArj2Wuea4tL8+GP5KmIjBAbydCdXUeiKiJRDUBCDcMWKil8jIgKIiTn7+xYL\ncMstrGgdgfjEEzws3m4HPvqI1erYsay2r72WAexYP2u3syJzdDc7do2qUcN5QIFjGZDjo0YNVrX1\n6jl/NiCAXcoXXMCfOXCAs6cDAhjAdeuyi3nMGOD11znZa8cOVvB33ln8Nc2dy+q+LGlpHDP15tBN\nS3Pd9RS6IiLlNHw4q86KuvVWrtfdvPns++68kxOTHIen/9//AVddxaU8N93EE4SmTWPwzp/Pcd68\nPG5GERzs3C3KsbY2IIDfCwgoHqp16zqrYkdAN2rEAHV0NwcHA//8A9x2GydDjRjBruLnnmPoBwcD\n//oXHztpEvDss7yOQ3o6J4INHlz27yQ+nuPlZe1aZRSrVaErImKIQYPYFVrRAxD8/Bii77xz9n2+\nvjwP97PPuCwIYMBu3Qr88AMwfjzHaG024NFH2b07YADvv/BCBmzr1gxPgEHqqGQbNmTFVq8eK1lH\nd3TTpnzeGjX4+Jo12WW9Zw/fBPz2G7u3p01jgDZqBEyfDjzzDF/L+vXOMeOi5s3jIQ9nLiEqyZIl\n7DL3VupeFhExSGAgK84vvqj4Ne65h2O3Jc2EvuEGhuCLL/K21QpMmAA89BCD8N13gYULGQJPPcVl\nOg88wG0ka9dmhduiBSdbHTjAIA4Kco7xOmYmBway4k1LY1DXqsUwbtSIwd63LyvyZ58FZs4ErriC\nIfzoo+y6auQNAAAgAElEQVQG79aNY71PP832BQQ4X0N2Nr8XGVn278Ju5xuKG2+s+O/T3dS9LCJi\noMhIICqq4htl+Ps7q90zN12wWFhJ7tzJGcEAl6xMn85JS5mZHD9dvpyzj197jV3NF13E8eYGDTg7\nuW1bjsU2acLgbtKEO1o1bsxgrV+fQdysGW83aQJs2cJD6C0WLhN68UXg+ec5qes//wGefJKPHz2a\n7Ro7ls9zZhfy9OmcsXzmmt2S7NjByrxTp4r9Lj3B39+1hzEodEVEzsM11zDAli2r+DUefJDBOnfu\n2fc1asQK8q23nDtYDRrELt2wMG7Z+N137GaePp1dv02bcv1saCg3rygo4ESrGjU4/tqoEbuYg4IY\nzE2bcja0vz/3PO7UiUH52298rquu4vM/8wzw8MNcwpSVBXzwAUM5JgZYvZq7XxVdonT0KN8sPP98\n+X4PX3zBtb1lbRNpJMexiq7igmOPRUSqD4uFE4tee43dwRUJDF9fVsv33cftFIseHg8Affqwy3jQ\nIHYhN20K3Hsvu4SHDQPeeIOBPXs2q9A+fRiA33/Pg9f9/bmEx8eHXdHZ2ZwhXLs290yuU4f3tWzJ\nCVPffsvu6tatOSu5RQter1YthmLPnsDEiayOf/6Z63xXrGDXa1EvvABcemn5ZiLn5bH9Je3S5U1c\n/YbAYre7cldJEfEki8UC/RP2vIICTv55/33u6lRRr7/OsdpPPy159u6kSQy32bMZhADHgl95hdXp\n2LEMr7ff5jaRl13GZToWCyc5rVjBsV3HGO/hw3xMYCDHbnv14ilH+/ZxB6usLL4RuP12Ll+aMwcY\nOpSVucXCSVMvvcRZzH37Fm/rd99xstevvxYf4z2X774DpkzhNb3ZokV8g/TDD665nkJXxMQUusZZ\nuJChuX59xZe75OfzoPQbbgDGjSv5MVOnMgBnznSeOZuRwYDbsIHdv0OHcrw3JoYBceQIw7dtW4a1\n43AEgG8Yjh7lBhe7dnHJzuWXc7JWRARvT57MmczPPOMcm128mM81c+bZbzT27mUX9IsvcqOP8rju\nOk7MKs+yIiMtXszff2XOKi5KoStiYgpd49jtrBTvv5+VYEUdPsxx4pdf5szmkixYwKU777/PKtTR\n5blxI6vhbdvYjnvu4WSngwe5beOePQxmx9F5vr6sQoOCuMzokksYkj4+DJcFCziJ6vbbOXGrRg2G\n9JQpfO7vvuPErqIyMxnY3buzi7o81q3jzOi4uOJHE3qj6GhOVnPsjV1ZCl0RE1PoGmvTJm5csX17\n+bY7PJc//2SoPvPMuXdx2rqVQRgWxolKRceBExM5qWrpUlarl1zCU406dOB48JnjkpmZrHITE9m9\nu2gRu4uHDOGSqJo1+bidOzlbu0ULBm/RvZUBTjB6/HHO5J4xo3zjn3Y7q/u77nLu3ezNPv2Ub2A+\n+8w111PoipiYQtd448ZxL+SoqMpdZ8MGjtU+/DCDvCRZWez6/fVXhusjj3BylUNODmcxb9oErF3L\nz82acUZzbi53l0pL4zrbwEBWv//3f9xko2igHjsGvPkmx3QnTGAlf+Zezrm53KErN5ebYZS3Yl2+\nnIc5fPtt8XOAvdWUKRwPL2lDk4pQ6IoYKCYmBlarFTabDZGl7CYwefJkjBkz5qzvK3SNd/w4JzV9\n9BHHZitj40aO1d56a+mbS/z3vzyeLzqaj7v/fgZrSU6e5PF9ubkMzgYNGLglVaW7djEQv/iC1336\naa7tPdPx46yKQ0LY7eyojMuSk8Pf1ZQp3r0hRlEvv8zf1fjxrrme1umKGCQhIQEAEB4eDgBITEws\n8XGxsbFYuXKlx9ol56d+fU4u+s9/Kr49pEP37pw4NX8+N6PIzS35cRdfzMorLo4B2KULu2ujothV\nXXTjDsdxfm3bcrlQUJAzcAsKuA/09OnccapXLwby1q1cp1tS4O7ZwzW9PXpw3W55AxfgsqPrrjNP\n4ALO8XBXMUFxL1I1RUdHo9//poGGhIQgNjYWoaGhZz3O4s07BwgABskNN3Ai05Illdu8v317dtc+\n8ACD8M03GbIlufhiVo2vv87lQb/9xk07YmMZjB078k2Bjw/X7losHM/dv5/juRYLx2svvpjrgOfM\nKb2bODqa63cfeohj0OfzV3PzZuDjjzk72kxq1jx7HXVlKHRFDJKeno6goKDTt1NSUs56TGJiIsLD\nw/HWW295smlSAa++ynHWV17h15URGMjlPx99xNN8bruNXb3nqirr1OGeyLfcwtspKZzRfPAglwcl\nJ3OHKsd5u1ddBdx9NydanbnBRUkOHuT2j4cPM3S7dTu/13PiBDf1ePdd7uZlJgkJ3HzEVRS6IgYq\nazw2NTW1zGuMLzLYFBYWhrCwsEq2SirC15cV6ogR/Dx0aOWu5+PDdaz9+3OGcHw8g2vw4LIrzOBg\nnrlbWSdPcsz2s8/43J99VvwIv/Kw2zk57JprKv87McL+/eceL68Iha6IQaxW6+lQTUtLQ3BwcLH7\nHVVuWca7aoaHVFrjxuzq7duXXZKuCL62bbmGduVKbv/49tvchnHoUG7r6A5Hj3IJ0G+/sTJeupSH\nKlTEhx9yK8pPP3VtGz3Bbud2nC1buu6amkglYpChQ4fCZrMBAJKSktD3f/vqpf/v8E6bzYaYmBjM\nmDEDqamp55xoJd7liiu4L/Kbb7pu/NJi4S5Qq1ez+/r339lN+/DD3Ls4L6/yz3HyJMN9yBDu27xn\nDyc+Oc7GrYjoaF5j+nTnOb9mkprqPJPYVVTpihgkNDQU8fHxiIuLg9VqRefOnQEAERERiI+Px+D/\n7Y8XFRWFjIwMTagykfBwTlgaOJBBduYuThVlsQDXX8+P//yHO0iNGcOAvP12hmPnztxfuWnTs9fW\nOhQUsILbtYsB/t//cgJY//4M908/rdxmHwDfDIwaxQr9wgsrdy2j7N3L34kraZ2uiIlpna53++EH\nLv2ZPZvLcdwlOdm5KcaGDTyn1seHE6WOHuXpQcnJrDZtNm6EcegQx1kvvJATq3r3dt3SmDVrgCee\n4PInV05C8rQ5czgb3FX7LgMKXRFTU+h6v7g4Lv2ZNs2zE4lOneJs4+PHuSmFxcKu0sBA4IIL+LU7\nLF/OGdfffMOlVGY2ZgzXNT/3nOuuqe5lERE3Cg9nF+vNN3M7wSefPHe3ryv5+3MzDE+KiuK64YUL\nWT2b3bZt3GrTlVTpipiYKl3zOHiQ466Bgey2LLJE2/Ryc7ld4tKlnDzVvr3RLXKNFi14IETr1q67\npmYvi4h4QLNmnH18ySWselesMLpFrmGzcferHTs4eaqqBG5aGrvmXblGF1Doioh4jJ8f19m+9BI3\n0Rg3jmtYzaiwkIcujBrF7S+/+658u1uZRUIC3xy5eihAoSsi4mH9+gFbtjC4Lr0UmDWLy3jMYts2\nzkqeNQuYNIkzlavaira1a127KYaDQldExABWKwPrhx/40aMH8OOP3AXJW/3zD8/W7dOHZ+n++itw\n+eVGt8o91q7lMipX00QqERPTRKqqwW5n9+zEiTyK75FHgEGDvOeQ96QknhA0cybP2X322cpvnuHN\ncnK4f/WBA6491g9Q6IqYmkK3aikoYNU7ZQrQsCFP87n3Xs6iNaItcXHsQl65khXuE09wQlhV9+uv\nPGRi0ybXX1uhK2JiCt2qa9Mmrnu12bgk5/bbgZtucv1s2qLy84F163geb1QUt5J89FE+d0CA+57X\n20yYABw5wh21XM1LOi9ERKSorl35kZ3N5UWrVrHytVqBW2/lWGpoKCdiVbQb+tQpHi6/fj2wbx/X\nD194IXeUWrmSezhXR0lJzrOJXU2VroiJqdKtXgoLOet5wwaGcEICJzddeSV3oLrwQnb/+vuzMq1f\nH8jKYqVst/Ns2NRUYPduHnbQujXXovbsyclRV1/N6rY6O36c3fkHDrj2dCEHha6IiSl0JTOTAbpv\nH08OSknh2t/MTFbFx44BNWs6u6UvuIBLYdq3Z+j6+RnafK8zbx4r/iVL3HN9ha6IiSl0RVzrrrtY\n9UdGuuf6Cl0RE1PoirhObi7QuDG3tGzSxD3Poc0xREREwL2xL73UfYELKHRFREQAAD/9xJnb7qTu\nZRETU/eyiGucOsVZy1u3As2bu+95VOmKiEi1t3Ah9792Z+ACCl0RERHMng3cd5/7n0fdyyImpu5l\nkcrbvx/o3JkbjdSp497nUqUrIiLV2tdfA4895v7ABVTpipiaKl2RysnJ4c5csbFAhw7ufz5VuiIi\nUm3Nmwd07OiZwAUUuiIiUk3Z7cC77wJPPum551ToiohItfTLL8DJk0D//p57ToWuiIhUS++9B/zn\nP4CPB5NQE6lETEwTqUQqJj4euPVWni1cu7bnnleVroiIVDuvvQaMHevZwAVU6YqYmipdkfOXmAgM\nHAjs2eOZtblFqdIVEZFq5ZNPgJde8nzgAqp0RUxNla7I+Vm1CnjwQR5UX6uW559fla6IiFQLhYXA\nM88AEyYYE7iAQldERKqJr78G/PyAO+4wrg3qXhYxMXUvi5RPVhZw8cXA3LnA1Vcb1w6FroiJKXRF\nyufll4ETJ4B33jG2HQpdERNT6IqUbedOoFcvYPNmoHlzY9uiMV0REamy7HZg5EguETI6cAGFroiI\nVGGzZwOnTgGPPGJ0S0jdyyImpu5lkXM7fBjo1AlYtgwIDTW6NaTQFTExha5Iyex24Pbbga5dgeee\nM7o1Tr5GN0BERMTVvvySE6i+/NLolhSnSlfExFTpipzt779Z4a5cCXTubHRritNEKhERqTIKC4H7\n7gNGj/a+wAVU6YqYmipdkeJeeYWV7owZQI0aRrfmbBrTFRGRKuHHHxm28fHeGbiAKl0RU1OlK0J7\n9gBXXQV8+62xeyuXRWO6IiJiaidPAoMGcdcpbw5cQJWuiKFiYmJgtVphs9kQGRl51v1RUVEAgD17\n9mDixIln3a9KV6o7ux245x7A15e7T1ksRreodKp0RQySkJAAAAgPDwcAJCYmFrs/Li4OERERiIyM\nhM1mQ1xcnMfbKOLtpk0Dtm8HPv7Y+wMXUOiKGCY6OhqBgYEAgJCQEMTGxha732aznf5eSEgIbDab\nx9so4s3WrgXeeIPjuHXqGN2a8tHsZRGDpKenIygo6PTtlJSUYvcX7W5OSEjAsGHDSrzO+PHjT38d\nFhaGsLAwl7ZTxBvt2gU8/zx3nGrTxujWlJ9CV8RA5RmPTUhIQNeuXdH5HCv9i4auSHVw8CBw/fXA\niy8Cffsa3Zrzo+5lEYNYrVakpqYCANLS0hAcHFzi4+Li4jBhwgRPNk3Ea6WlMXAffhh44AGjW3P+\nFLoiBhk6dOjpcdqkpCT0/d9b9vT09NOPmTFjBsaMGQMAmkgl1d6pU8BNN7G6ffZZo1tTMQpdEYOE\n/u+Az7i4OFit1tPdxxEREQCA2NhYjBs3Du3atUNQUBAsZpiaKeImeXnA0KEcv337bXPMVC6J1umK\nmJjW6Up1YLezK/nwYeD77wE/P6NbVHGqdEVExGsVFgKjRgG5ucD8+eYOXECzl0VExEvl5fGYvgMH\ngEWLgLp1jW5R5Sl0RUTE62RnA3fcwUp36VLzbH5RFnUvi4iIVzlxAhgwAPD3N9duU+Wh0BUREa+R\nmgpERADt2gFffQXUrGl0i1xLoSsiIl4hORm49lqgd2/gk0+89yD6ylDoioiI4fbuBXr1AoYNAyZN\nMu863LJoIpWIiBhq2zbuNDV6NJcHVWUKXRERMcwPP3Dji08+AW67zejWuJ9CV0REPM5uByZMAKZP\nBxYvBnr2NLpFnqHQFRERjzp1itWtzQasXw80b250izxHE6lERMRj9u/nhCk/P2DNmuoVuIBCV0RE\nPOTHH4EbbwTuvhuYM6dqbXpRXupeFhERt8rLA55/Hpg7lxte9O5tdIuMo9AVERG32bePa28DA4GE\nBKBRI6NbZCx1L4uIiMvZ7dw3uUcPYPBgzlCu7oELqNIVEREXS04GHn0U2LGD47hduxrdIu+hSldE\nRFzCbgdmzgSuuALo0AFITFTgnkmVroiIVJrNBjz0EJCeDqxcyeCVs6nSFRGRCisoAKZO5djt9dcD\n69YpcEujSldERCpk2zZgxAigdm3g99+Biy4yukXeT5WuiIicl9xc4JVXgD59uJ3jTz8pcMtLla6I\niJSL3Q4sXQrMng1kZXGiVIsWRrfKXBS6IiJSpvh44NlnuRzorbd4/m1VPWjendS9LCIi55SUBNx1\nF3DzzdxZautWfq3ArRiFroiInCUlBXj6aaBbN+CSS4Bdu7gkyFf9o5Wi0BURkdOysoBJkxi02dnA\n9u3ASy8BAQFGt6xq0HsWERHB8ePAjBnAihUM2F9+AS6+2OhWVT2qdEVEqrGDB4GxY4E2bTgb+a23\neFCBAtc9FLoiItXQ9u1cY3v55UBODrBpE8+6DQ01umVVm7qXRUSqCbud3caTJgEbNwKPPQbs3g0E\nBRndsupDoSsiUsUVFADff8+wTU0FnnkGmD+f2zeKZyl0RUSqqGPH2GX88ceA1cqx25tvBmrUMLpl\n1ZdCV0SkCsnPB5YtA2bNAuLiuHPU7Nk8BUgbWhjPYrfb7UY3QkQqxmKxQP+EBQB27mTQzpkDtG7N\nSVJ33AE0aGB0y6QoVboiIiaVkQHMm8ew3bcP+Ne/eOLPpZca3TI5F1W6IiamSrf6ycxk9/FvvwEz\nZwIREcD99/MAeW3R6P30RyQi4uWOHAF++AFYuBBYswa46ipgyBAu92nY0OjWyflQpStiYqp0qy6b\njSH73Xc82ef664FbbwVuuIEzkcWcFLoiJqbQrToKC4HNmxm0Cxeyur35ZgZteDhQq5bRLRRXUOiK\nmJhC17zsdmDHDk58+ukndhv36gVcdBEwaBDQs6fW01ZFCl0RE1Pomofdzi5jR8iuWgX4+wN9+gDX\nXcfPzZoZ3UpxN4WuiIkpdL3X8ePAli3sMrbZgJgYblzhCNg+fXiyj1QvCl0RE1PoGs9uB/7+m+H6\nxx/Oz4cO8QSfzp3Zbdy9O9C+vXaFqu4UuiImptD1rJwc4M8/i4frH3+wm/iKK/jRuTM/X3SRxmTl\nbApdERNT6LrP0aPFw3XzZmDPHqBtW2ewOj43amR0a8UsKn2I/erVq13QDO+l12du3v76YmJiEBcX\nh6ioqArdX5W5+8/ObucpPJs3A4sX8ySeiROBgQOB5s1Zqb7+OrB/P8dhP/+cx+Jt3Qp88QWPx4uI\nqHjgevvfzcrS6yuZQrcMen3m5s2vLyEhAQAQHh4OAEhMTDyv+6u6yvzZFRYChw8DmzZxzesHHwDj\nxgH33AOEhQHt2rFLuH17YPhwYPp0ICEBqFsXeOghbrGYlgasXg289x63WezSxbXnz3rz301X0Osr\nmbaBFDFIdHQ0+vXrBwAICQlBbGwsQkNDy31/dVJQAGRlFf9ISwMOHAD++efsj4MHebpOixbFP/r1\nc37dvDlDVsSTFLoiBklPT0dQUNDp2ykpKed1v1EKC4HsbAaf43N5Ps73sUePAlOn8nZ+PlCnjvOj\ndm0gJISh6QjR0FDn182aubYqFXGVSk+ksmj+u4iIVEMVic9KV7qaOSlmZrez6zInB8jNdX6c7+2K\n/MzOneMQENAXdeqE4+jRBcjKSkLdumNO33/8+DjY7X2Rnx8Oi2UBfHx4f82a3Ie3Zk3AZrOgUyf7\n6dtFP878Xkm369fn78FRPRatJs/1UasW4FPp2SAi1ZO6l8XrFRYCycnA3r08qHvfPp4pmpHhmvDz\n8SlfSJU3yGrWZJiV9Zh9+4Ziz5543H57OL7+Ogm9evXFFVcA2dnpaNTIip07h2LLlng8/HA43nkn\nCX379kXnzsV/NxYLl7OIiDkodKuxmJgYWK1W2Gw2REZGnvNxkydPxpgxY9zWjrw8Tn7Zt694sDpu\n//MPEBQEXHghP1q3Bpo25Ud5w/Bcj/HzM3IDg1BERcUjIyMOl15qxaBBTNRu3SIQHx+PRo1CsXNn\nPFavjoPVakXnMxNXTMNb/q2J8So9plvWX6by/mXzVmW1PyEhAUlJSUhNTTXV63O0e/DgwYiKikK3\nbt1KnBkbGxuLSZMmYcWKFRV+rqwsbpNXNEiLBuuhQ0CTJgzTosHq+LpVq4pNiinrz86x9nXPnj2Y\nOHFihV+fp5T0eopujlHV/62Z7c/LwZP/1oxSVf+fdHBlzlVqZKasdYSJiYkICQlBeHg4QkJCTLfO\nsDzrJCdOnIjBgwcjPT3dVK8vOjoagYGBAJzLUUpyvhPlkpOBH34Axo8HbroJGDAACAzkhgNvvQWs\nW8cKs29fbjywdi1w8iRDee1abjrw+uvAiBF8TPv2FQvcsv7s4uLiEBERgcjISNhsNsTFxZ3/k3hQ\nVV/TW9X+vIpy1781b1GV/58EXJ9zlQrd8vxlGjt2LADAZrOZbo1hWa9vwYIF6N69OwBgzJgxpnp9\n5VmOkpiYePovWkmSk7mTzyuvMGCbNeMG7x98wLHS++4DPvwQOHUK2L0biIsDPvsMeOkl4N57gWuv\nZUXr5+f611fWn53NZjv9vZCQENhsNtc3woXKej3l/Y/dW1W1P6+iXPFvzZtV5f8nAdfnXKXGdMv6\nyxQaGoo2bdogKCjIlNvYlfX64uPjAfAfTGxsrOnGYsoaWUhNTT399aFD3N0nPp6fN23iWsquXflx\n333AtGnsDvaGN+xl/dkV7QJKSEjAsGHDPNa2ijDrmt7yqmp/Xmc6n39rZlPV/590dc65dclQeno6\n2rVrh6ioKERGRqJLly5oY7IDJMv6x9KwYUOEhoYiNjYWMTExGDx4sIdaVraS/gIEBQVh8ODBsFqt\np/+hp6WlITg4+PRjDh0CoqMTkZ4ejvffZ7fvZZcB3boxYIcP59Z4rVt7R8CeS3mmKyQkJKBr166m\nmKRU1usx+/K9qvbn5VDavzXA3FWug5n/nywPV+ZcmaFb0f+4HT87cuRI1K9fH1arFQsWLPC6dzmV\neX3BwcGnf7lWqxUbN270qr9MpQ3oDx06FPHx8QgPD8eWLUmoUaMvRo0Cvv02HdnZVrRoYUPbtjY0\naZKC9u1TMXt2Irp08a5uocr82TnExcVhwoQJbm2nK5T1esr7er1VVfvzKqrov7WkJC79AviftWPy\njc1mQ0pKClJTU5GYmGiqLliz/z9ZFlfnXJmhW97/uEv6ywQA9f+3+j48PNwrx2Eq8/qGDBmCBQsW\nnP5ejx49PNLmyiosBPLzQ7FoUTzefjsO+/dbMXBgZwwYAKxZE4EtW+JhsfAfRVRUFH76KQM+Pt5X\n0lb27+aMGTNO/+OIi4vz6mrjXK+nvPd7u6r251VUaGgo4uPjERdXfOlXRASXhjkCKCoqChkZGaab\nUFVV/590cHXOVXrJUFRU1OmJDY7/BLt163a6H3/y5MkICQkx7VTxsl5fVFQUgoKCEB8f79XvwI8f\nB1asAJYsAZYudc4oHjgQuOYa90xmMlppf3axsbG44447EBQUhNTUVCxYsADXXXedwS0uXUmvp+iS\noZLuN5Oq9udVnVSV/yfPxZU5p0Psqyi7Hdi1iyG7eDGwcSNw9dXOoA0JMbqF4go6xF7EXBS6VUhO\nDrBmDYN2yRLOLnaEbHi4jjGrihS6Iuai0DW5EydYyc6bB6xaxXWyjqDt1Mm7ZxdL5Sl0RcxFoWtC\nBQXATz8Bc+Zw96devYBhw4D+/QGTTVqVSlLoipiLQtdE/vyTQfvll9zsf/hwhu0FFxjdMjGKQlfE\nXHTKkJfLygLmzmXX8apVwD33cBZyhw5Gt0xERM6XKl0vlZQEfPQRMGsW0LMnMGoUDwAw7hg68Uaq\ndEXMpVIHHohrFRayir35ZqB7d95et44Tpfr3V+CKiJidupe9QEYG8PnnPJGndm3gsceAb74B/P2N\nbpmIiLiSQtdAR48C777LmcitWgGffsrdobTMR0SkalL3sgGSk4HRo4GLLwZSUoCvv+Y62169FLgi\nIlWZQteD9u0DHn2UM48LCoAtW4CPPwZMdtqhiIhUkELXAw4cAF54AejSBahXD9ixg93KLVoY3TIR\nEfEkha4bHT/OsO3UCfDxAf76C5g4EWjc2OiWiYiIERS6bpCXxzW27dsDf/8NJCYCr74KBAUZ3TIR\nETGSZi+7kN0OLFoEjB0LNG/Oc2tDQ41ulYiIeAuFrots2ACMGcPZyO+8A9xwg2Yii4hIcdoGspLS\n04Fx44B//gFuvRW47z7AV29lxEO0DaSIuWhMt4LsdmDBAufBA19+CYwYocAVEZFzU0RUwP79XG+7\nezc3tbjmGqNbJCIiZqBK9zwUFADvvcfJUd27c1ayAldERMpLlW45bd8O3H8/UKcO8Ouv3MJRRETk\nfKjSLYPdDrz/PnDttTzTdtUqBa6IiFSMKt1SHD7M2cipqcDvvwPt2hndIhERMTNVuuewZAnQuTPQ\ntSvwyy8KXBERqTxVumfIyuImFz/8wJnJvXsb3SIREakqVOkW8c8/QHg4kJ8P/PGHAldERFxLofs/\n69YBPXsCt9zCwwqsVqNbJCIiVY26lwHMmQOMHg3MnAncdJPRrRERkaqqWoduQQHw3HNATAywerVz\nS0cRERF3qLahm5EB3HUXcOoUTwgKDja6RSIiUtVVyzHd3buBK68ELrwQWLFCgSsiIp5R7UI3Lg64\n+mrgsceA6dMBPz+jWyQiItVFtepenjsXeOop4JtvgD59jG6NiIhUN9UmdD/4AHj7bWDtWqB9e6Nb\nIyIi1VG1CN133mHorl4NtG5tdGtERKS6qvKhO2ECMGsWsGYN0LKl0a0REZHqrMqGrt0OvPoqx29X\nrwaaNTO6RSIiUt1VydC124EXXgAWLWLgNm5sdItERESqYOja7TwlKC6OB843bGh0i0RERKhKha7d\nDrz1FqvbuDggKMjoFomIiDhVqdCdOhX48ktOmlLgilnExMTAarXCZrMhMjLyrPujoqIAAHv27MHE\niTnWBzMAACAASURBVBM93TwRcaEqsyNVdDRDd+lSbeso5pGQkAAACA8PBwAkJiYWuz8uLg4RERGI\njIyEzWZDXFycx9soIq5TJUL355+BUaOAxYu1LEjMJTo6GoGBgQCAkJAQxMbGFrvfZrOd/l5ISAhs\nNpvH2ygirmP67uUdO4AhQ4CvvgKuuMLo1oicn/T0dAQVGQtJSUkpdn/R7uaEhAQMGzbsrGuMHz/+\n9NdhYWEICwtzeTtFxDVMHbrJycCAAcCkSUDfvka3RqRi7HZ7mY9JSEhA165d0blz57PuKxq6IuLd\nTBu6mZnAjTcCDz4I3Huv0a0ROTfHRKiigoKCMHjwYFitVqSmpgIA0tLSEHyOCQlxcXGYMGGCW9sp\nIu5nsZfnbbaXsduBkSMBf39OnrJYjG6RSMUkJiYiPj4ekZGRmDx5Mvr27YvOnTsjPT0dVqsVADBj\nxgw89NBDABi+jklXAGCxWMpVKYuIdzDlRKr33gM2b+aaXAWumFloaCgAhqnVaj3dfRwREQEAiI2N\nxbhx49CuXTsEBQXBor/wIqZmukp3/Xrgppv4uU0bo1sjYixVuiLmYqpKNzUVGDoU+OQTBa6IiJiP\naSpdux249VYgJITjuCKiSlfEbEwze3nqVODQIWD+fKNbIiIiUjGmqHTXrQNuuYXjuK1bG90aEe+h\nSlfEXLx+TDctDXj4YWDGDAWuiIiYm9dXupGRQJ06wPvvG90SEe+jSlfEXLx6THfVKmD5cmDbNqNb\nIiIiUnle272clcUqd/p0oH59o1sjIiJSeV7bvTxuHLB3L/DNN0a3RMR7qXtZxFy8sns5IQGYORPY\nutXoloiIiLiO13Uv5+cDI0bwuL7GjY1ujYiIiOt4XehGRQEdO+q4PhERqXq8akz3+HGgfXtg2TKg\nhLO6ReQMGtMVMRevqnQnTgT691fgiohI1eQ1le7ffwOhocAffwAtWhjdGhFzUKUrYi5eE7r/+he3\neXztNaNbImIeCl0Rc/GK0N2yBbjjDmDjRqBePaNbI2IeCl0Rc/GKMd3x43mogQJXRESqMsMr3e3b\ngT59gKQkwN/fyJaImI8qXRFzMbzSnTABeOIJBa6IiFR9hla6NhvQowewZw/QoIFRrRAxL1W6IuZi\naKU7aRIwcqQCV0REqgfDDjw4fBjYsIG7T4mIiFQHhlW6UVFA9+7ABRcY1QIRERHPMmRMt6AAaNMG\n+P577kIlIhWjMV0RczGk0l26FGjaVIErIiLViyGh+9FHwL//bcQzi4iIGMfj3cv79gFXXQX89ZfW\n5opUlrqXRczF45XuV18BgwYpcEVEpPrxeOjOmwcMHerpZxURETGeR0N3xw4gJQW4+mpPPquIiIh3\n8GjozpvHI/x8DN/xWURExPM8Fn92O/DNN+paFhGR6stjofvnn0CzZjzgQEREpDry2N7LixcDHToA\nFounntEccnJ4ytKePVxOdfQocOwYewYOHWJXvI8P0KQJH9u0KbfObNMGuOgifq5Rw+hXISIi5eGx\ndbp9+gCjRwM33uiJZ/NeaWnAypXApk1AXBwDNT0duOwy9gQ0agQ0bMhg9fMDCgv5AQCpqXzs3r08\nFrFuXV6rUyegf39+DgsDrFYjX6F4ktbpipiLR0I3M5OV2qFDQECAu5/N+9hs3Pry66+BrVuB3r2B\nm24COnYEOneu3Jrl9HRg82YgIQFYvhz47TcgPBzo1QsYPBho3dplL0O8kEJXxFw8ErqLFwNTpgCr\nVrn7mbxHTg4wfz4r0aVLgeHDgeuvZxjWru2+583OBlavBmJi2F2dmws89BBw223ufV4xhkJXxFw8\nErqPPQY0bw6MG+fuZzJeRgbwySfAu+8yYIcNY5e6n5/n25KbCyxaxGMUCwqAa68FRo0CAgM93xZx\nD4WuiLl4ZPby/v1ARIQnnsk4WVms5i+6CDhyhF298+Zxy0sjAhcAatYEhgxhW6ZNA5KSgEsuAV55\nhW8ORETEs9weuidOsIv1iivc/UzGsNt5LvBll7E7d80a4O23OV7rTS69FJg5E9i4ke1s3x6YPZsV\nsIiIeIbbu5fXrGG38u+/u/NZjHH4MPDww5xd/Nhj5qrmt27lbPK0NHaHd+lidIukItS9LGIubq90\nN24Eund397N43vffA/36sYKMjjZX4AKsxJcvBx59FHj8ceCll4C8PKNbJSJStbm90h06lBOJ/vUv\ndz6L5+TnA6+/DsyaBcydy7OBze7QIeC++zjO+9VXQEiI0S2S8lKlK2Iubq90N2yoOls/pqcDAwcC\n//0vkJhYNQIX4BrqH3/kYRS33QasWGF0i0REqia3hm5KCtCyJWf0mt3Bg1zv2r498MUXQFCQ0S1y\nLR8f4KmngPffB+69F/jsM6NbVH3ExMQgLi4OUVFRpT5u8uTJHmqRiLiLW0N31y5u1mD2o/ySkrjm\ntksXLr3xdcOO1SdP8ve1fj03EVmxAli7FoiPd25y4Qm9e3PS25QpwLPPOregFPdISEgAAISHhwMA\nEhMTS3xcbGwsVq5c6bF2iYh7uPXAg927gbZt3fkM7rd/P/Dgg8DTT3PSkSucPMntGlev5kQzX18e\neFBQAPTsyXHjtDT2EmzezAMQQkLYc9CuHSdtdesGdO3qnsMOWrcGfvmF20g+9xwwYYL53zh5q+jo\naPTr1w8AEBISgtjYWISGhp71OItOChGpEtwaunv2mDt0jx3jDOXIyMoH7qlTwJIlnPX8/ffA7bcD\nrVqxS/fyy4EWLUo/gSkvj29i/vgD2LkTeOABHnjQoQNwzz3cbcqVARwUBPzwA3DDDXzt06frhCh3\nSE9PR1CRsYqUlJSzHpOYmIjw8HC89dZbnmyaiLiB20P3f71mppOdzbC54w5WuRX1zz/ABx9wHHjA\nAH588MH5nwTk58flSZdeytvjxwN//w0sWMD1ts2bswIeMcJ1h0oEBPCNQr9+3MXq5ZcVvO5Q1uzj\n1NRUD7VERNzN7d3LDz3kzmdwD7sdeOQRjmeOH1+xaxw9Crz2Gmc6d+gA/Pqr60/8adWKbwiefpqz\nxN9+mxXpgw8CTzzhmgMO6tfngQ0REUCDBqzM5fyUNEEqKCgIgwcPhtVqPR2qaWlpCA4OLvY4R5Vb\nmvFF/pKGhYUhLCys0m0WEfdwa+gmJ5tzzefnn3Ms97vvzr+yKyzkzN9Jk7g++csveUauu/XowU06\ndu3iOOzFF7Oivummyl87MJC/iyuv5JiyK65ZnURGRp7zvqFDhyI+Ph7h4eFISkpC3759AbDb2Wq1\nwmazwWazISUlBampqUhMTDxrzHd8Rd8ZiojHuS108/LYtdqkibuewT127ACeeYYTic63m/bgQW4y\n0bgxQ+ryy8v+mfR0YMsWHkx/7Bi7jOvV49cNG/L317Ahq+VLLil75nT79jzWb80ablH500/ACy8A\nZxRQ561VK76me+5hO6rCMjBvEBoaivj4eMTFxcFqtaJz584AgIiICMTHx2Pw4MEAWC1nZGRoQpWI\nybltR6pDh3jIweHD7ri6e+Tnc+es667j5KnzERfHrtfBg4Hnnz93OBYUsKt54UIuRTp6lNXxVVcx\nXGvXZmV56hQ/cnJ4QP2+fZz13KwZx5n79Su7uzorC3jxRXbzjxsH/N//nd9rKslHH3Gv5t9/B+rU\nqfz1pHK0I5WIubgtdLdt4xaQf/7pjqu7x9SpwOLFQGzs+XUrR0Ux3L75BjjXcFpqKvD118Cnn3KW\n8dChQJ8+QGho+df9pqdz7e6aNVzH27Ahg37gwNJnLi9aBLzzDmc8Dx9e/tdVErsdGDmS1fxrr1Xu\nWlJ5Cl0Rc3Fb97Kje9QsDh5kkH388fkF7uuvsxL9+eeSu1xPnOAEp59+4hrczz7j+tozFRSwVyAt\njdVtzZqc4dy4sfM8XqsVuPlmfuTkcOnRxImcGT1sGLdwLKntN9/Mto0YwbW+lZkMZbFwvLpjR75p\nuO66il9LRKS6cVulu2QJsGwZd3AygxEjOO55PkshJ01i2M6YATRtevb9S5eym3rIEM4mbtPGed+x\nYzxneM0adjc3bMhu5hMneH9hIbuSN25k2Pbvzw0xwsKACy90XsduZ2U+cya7kydN4rhuSQ4c4BKu\nRx/lUYSV8eOPfDOxeDHg71+5a0nFqdIVMRe3VboZGayqzGDHDo6Zvv12+X/mq684sSgm5uzAPXUK\nePNNYN48din37s3vFxYyaOfPZ1j16sVKccQITpQqaYw0N5djsvHxPGRhzhyG66hRHD+uVQvo25fX\nmTmTM4ynTuXY9JlVb/PmrLj79OHPVWY514ABbMtbb3ENr4iIlM1tle7s2dzmcPZsd1zdtYYP5xKb\n558v3+PXr+dyoDVrgMsuK37fwYPAmDEMvI8+4kxku52V/8cfc/z21ltZ/fr58VqbNjH4d+5kd3Je\nHkMxJYVBefXV7M7t3p3XWrYM+PBDhvjw4exadowL79zJiVYDB3KNca1aZ7c/KYkTsd55p3LLf/7+\nm2PSCQnFq2/xHFW6IubittCdMYPV2YwZ7ri66+zbB9x/P/Dtt+XbJerYMeDOO1lp3nJL8fv++ou7\nQ115JTB2LPcrPngQ+Pe/OQb72GPcVvHXX1kB//wzZypfdRXDu0kThqdjn2PHsqukJIb2sWMM2UGD\nOC4cH88qs25dHk7QpQt/7uRJPi4wkFVvvXpnv45169jNPHfuubujy+ONN9irMWlSxa8hFafQFTEX\nt4XutGncjemDD9xxddf5z3/YHfzuu+V7/L33cvx1ypTi309KYqjecotzuVFsLNe1jh7NMd116zjT\nOSuLlWbbttxLeft2jv+mp3NZT40aDFvHNppt2nDNb5cuvMbChezSfvJJVr9ff81NOPr14/csFk7M\neuQRhv306SWPu0ZFcWw2Oto5Wet8nTjB17FmjXOLSvEcha6Iubi10k1O5n693iovj2OhUVHc8KEs\n33/Pym7t2uJbLKamcly2Tx/nBKUZMzhGPHMmrz16NLtjIyMZiFOnMhzDwthNbLEwdFNSeDsw0Dm5\nKiCA9339NbuDb7+ds5zfeovbM77yCm8/+ihPJpo2jSFaWMjNOnJzGcpnLk2y29lN3r17xbe7BDh+\n/eefHOcWz1LoipiL2w5sy8sDjhxx19VdY/lyBk95Ajc7G5g1i0t0igZuYSGr5bZtnYE7dSrHspcv\nZ9Dddx+3T3zqKW4s8fnnrGAvuYTjuX/8wco2I4Nh6ePDEN2/n99fvhzYupUTp0JCOIFp5ky2p149\nXj89nRXrgQPA448zaH18uETJbmcbz2Sx8A3HL7+wV6KiRo1ie/fsqfg1RESqA7eFrr8/u2292c8/\ns7u4PGbN4ucz16V++iknQU2YwNszZ7LLdsECBuWoURxfTUvjxKWrrmJX9K5dDEqAO2EdOcIx28OH\n+fWhQxwPTk5myJ88ycd//jlDtHdvTpZq3pwTqZ56il28MTG8zpgxfEPg58fu5R07eFTfmZo14zjz\n6NEV+x0CPBTh8sv5PCIicm5u616eN4+Tk+bNc8fVKy8/nzOFt2xhcJUmK4sV5vLlQKdOzu/v3s1J\nTd9/z/t/+YXd6R9/zMrx/fcZZh9/zK7ivDyGap067Ea2WBiu9erxvsxMBurhwzzP1s+P9504wdC9\n/HK2u2FDdlX36cMx3g4duMPVU0+xy7lXL+Cuu7gZx9ixbOsvv/D+pUvP3rQkN5fLjl57zbm86Xwl\nJfENyZ9/at2uJ6l7WcRcqm2lu3Ejg+b/2zvzsCjr9Y0/A7JvI4gbLkCG5jELNXH9qQe3Nk+Fu2md\nzLLjMTuV1jmeLpf2OJ5yKTWUtKyM5KRmZYrWUTulgihu5QJuiJBsoggMML8/7t7eGWaQEWaF+3Nd\nczHLO+/7nenKe57n+zz3U5fgiiBqfeABY8EVgZ/xpEkQ3KIiPH72WaSJly5FUdO8eXCDunQJQpuX\nB1E9ehT39XoIaE4OUthXr6IaWafD4wsXcExgIHyaT59GJNuyJUS/Sxe8Z+1aiPysWTj38uWI5Hfs\nwFoHDECU/dJLpp/P0xMWkQsX1v/7jIhABfbGjfU/ByGENHaarOimpIi0a2fZsUuWwErRkB9+QHSn\nWCq+/jpEuX9/RLdTpkD4YmIQjSpRbVWVyJUrKJQqLoZYV1ZCOEtK8PfaNdyKixGF5uTguywuRpRc\nWAihPn8eKejyctySkmBL+fLLiJJnzsTar17FGhcsQO+0OT/sCROQ8k5NrfdXKg8/jIItQggh5rGZ\n6AYEIEXqrGRnIz1bF0eP4nMMH278/DvvIKr08kIh1Nq1qGyeOxcR37Fj+A4OH8b78/IgqsXFEN/C\nQmORrajA/bIy3EpL8beiQq1sVo69elV9rrQUkXBQEKqos7Mh/vPni4wYgTUoVpxaLSJac3uvnp7o\n9V2+vP7f6f33I12v7FUTQggxxmaiGxLSsKjJluj1SBkrZhI3YutW7JkaTvE5dQrCN2YMHi9ahOjy\n9GlEwMOH46+XFyLa3FxEpbm5ENLqaoivIrDl5Yh2q6txq6pSb+XlqviWlkKoy8ogbO7uWMe5c3C2\n6toVhVSjRmH03q5diMDj4xEti8Co47PPzFcajxmDfXglMr5Z/P0xznHbtvq9nxBCGjs2E92wMKQ+\nq6ttdYX6c+mSyJ13mh9SUJOkJPSyGrJ5M8TFxwcuVNnZ2NtdtQqD4199FY5ReXnYh83KgoD6+aEo\n6/p1fC86nen3Y25En16PYysq8FcR3ooKRLe+vqhwfvttFDOtWIH95FWrkEKfOVONdv39kRL/5BPT\n67RqhcKwr7+27Hs0x333wVeaEEKIKTYTXW9vpDYvX7bVFerPiRMQrbooKUGfbb9+xs+vXo3CKhGI\nco8eiBy//BLHh4RgOEFJCfZv/fxw7LVrqlgaim3Llqg6zslBxHvhAvZep09HpKygRL7l5Wr6ubwc\n1ygvh1HG/v2Iolu1QvS7axeGH2zZguuKwDXr/ffN/yDq3dt8a5Gl3HsvrllVVf9zEEJIY8VmoiuC\nKCs725ZXqB8XL8IfuS7S0xEZGpphnD0r0qEDxEmvhwBPnAjDilmz4JHcpQuEVimSUkb2KZGqIkjN\nmiECvXQJ+6mtW+P5sDCRQYOwv5qfj/1jJQLW63EepfiqrAyRdEUFPldJCaLsDz7AOT/+GMYcPXui\neEwErUfdu5tP/99zD1Lh9c1QdOiA/eGff67f+wkhpDFjU9ENC0PU5mycPasOFbgR6ekQLEP27IGg\nurkhtRwRgVTzoUMQ29JSCI5Gg2OUSmSNxjid7OWFfde//tX84HkFjQZifuyYcf9rZaW67xsQgPNp\nNDC7KC7G5J+YGIzyu3YN6XTDtHHnzub3Xjt0gOg2xKFKGcZACCHEGJuKbq9eagGPM1FWZll/7oUL\nphaRBw6oUfLevTjPyZNIWZ88iWi1shJp9aIiRH2KQOp06nk++wzfj6VERaHvVkE5Z2UlUsvHj6vC\nvno1ImXlR8Pu3ahk3rQJkbIIepRri0ZjYvDZ6stddyHNTQghxBibim5oKETK2bh40fyc2ZocP246\nJ7a0VJ2ms28fIsi0NOyTbt8OE4uAAKSO/f2RAtbpII4K/fqZjgW0hB494LOsUFmppq87dEDh1oUL\nEPN27SC6/fohou7cGVH5xYt47513ojLbXBq5Z0+0OtUXii4hhJjHpqLbrZvIkSO2vEL90OkQgdZF\n8+YoSDJkzx41Stbp0E505Agqoc+cgQjq9bhdv64eZ4hSSVwfDEcQKkJeXY09XXd33Pz98fzp0xDX\n/fsRBd9yCyJyEazX1xfVzzUxPK4+dO+OPmS6ExJCiDF2EV1n+8e3ZUvL/IHT0lQBUwgNVb2Lc3Nx\nrjNn8LyHh1qtrfgoV1YaR7q+vpb1B9dGUJBIeLj6uLoa6fLLlyGsHh5oZSorQwV0x45qEZafH/az\nFbp2xf5tTcLDG1Z9HBSkmoAQQghRsanotmgBAXC2YqqCAohCXXToYDqD1sNDFeyMDKSSmzfH52zT\nBilepS1IRC2iUggNbfj6u3VT7ytmGkq63NMTzxUUQPw8PNS94KAg0/8Wubmm52/RAoVhDWHkSGOB\nJ4QQYmPRFYE7krOlmP380FpTF4o9Y83nlMhd8W5WzC+uXEHFsmLd6OkJMTTcP7aGNaahqYdGA5H1\n9VV7j5Xn2rbFepRisKAg41R3VJTp5xPBjwittmFrLClxvh9bhBDiaGwuuq1bYx/UmQgNRf9rXSjj\n9gw5c0Z9rk0bFFaFhUGIjx2D0Or1iJBLStRIVIl2reFLnJen3q+uRvq4shL9xEphlF4P8dRo1JS3\np6dxuvzKFfOi6+XV8D7bzp0t+2FDCCFNCZuL7oABzie6bdtaFoX17Gkqzr17qynZykrcDwtD207X\nrji3nx8iT6VXt7paFd2LFxu+x52Wpt53c0MKuaoK4ltRoaaby8pwXSVqrVncVFhomj4XwTGW9DHf\nCL2ee7qEEFITm4tunz4QifJyW1/Jctq3t8yeMjDQ1FGrTRtVsFu0gImEVity8CDSt/7+EEEvL0Se\n3t5q9CuC7+H77+u/9itX1OtrNBBaT09cp1kzRN7Xr2Ov+dAhHO/jg+PPnYNFpYKnp+lAexFE+PUd\nZq/g749UPCGEEBWbi25AAFKNzuRQ1KULeljrIizMtM+4RQs10uzdG6Lcuzf6Wjt2VIfP5+erUWSz\nZsaDDGbNqv/alfm9Iqro6nS4X1WFauRmzfC9DxqElLfS4lRRIXLrrer7c3JMW6JEEAEfP17/NYpA\n3BWxJ4QQAmwuuiIwwd++3R5XsoywMAhQXenPnj1NHbX69lXf17OnOiLQywsid/as2i6Un48I1M3N\nWHQPH67f3NqDBzG3V0E5pxJd+/tD+AsKIMR9+8Ila8gQrCczEz+ARBBxp6WZmn+IYM94wICbX58h\nJSWcq0sIITWxi+jGxjZsco210WggRHW1xdx5J0bzGRZT9ekDC8fr10Vuvx2R47lzKM4qL8f+bYsW\nSGFHRCDqVIqpDIV3xgyMCLSUkyeR8lX6Z93dIaQeHriGnx8eR0XB+vHbb+FG9dVXiMSPHYOYKpHt\n8eNwxTJnEpKZab7A6maoqjK/X0wIIU0Zu4hu//6o+nWmiUNdu9a9t+rjg0jV8DitFj8iUlIQwXbq\nBE/jMWPgeRwejmKqw4chiG5uiECDg3E+RYj0eojezJmmjlWG6PUiK1eiN1epBlZMMHx9cXNzQ1R9\n5gxSw507o2DLzw97unfcAcvHuDj1vMrgBnOcOaNGxPXFx8c6PcmEENKYsIvoNmsGswRnGm4eGyuy\nY0fdx40fb5oaHzUK03tERB57TGTJEny+wEBE0KdOIdUcHAxRDAhQBbhmqnnZMgj5lCm4Tk4Oout9\n+0Rmz4ZwTZ+uRp6K4Lq747w+Pijg6tABn6m6Gn3Rzz0nsnGjyBNP4Jrp6RhyoPDddyLDh5v/zPv2\nGRtw1Idz55zPiYwQQhyNXURXBEJ1M+lUWxMTY1lby8iRSO0aVl8/9BAi3ZwcpKD/+EeR9etFxo5F\nRBkTA7E9dQoiaLjn6u0NwTRsySktFfnoI4hg27awloyJEfnXv4xblgxtHgMCkBr29VUrlouKMMg+\nJwdzcdesEZkwQeToUUS2Q4ao17t2Des2x08/IY3eEAoKrGMEQgghjQm7ie7IkehrtcR+0R54e2P/\n8z//ufFxHTtCLA2jdK1WZPBgRKkiIo8/jvOMHo20cps2iDaHDkWkWlwMUdRokNJV5vF6ehpHvbWh\n9OJ6e0NkmzXDe5VINywMFdlBQbjuiBEi778P4W3fXmTxYpGpU9XU9tateK+59G9WFlLvNecI3yx6\nvbFzFiGEEDuKblAQ/qFfv95eV6ybceMsmxs7YYLIW28Zp0vnzBFJTETP7MCBSO8uWSLywQci8fEi\nTz+NCDk8HMVW7dqhwErp5Q0KQsWz0mPr5QVR9PAwvimC6+EBsfb3h9NUYCCKlfz9cY3iYojlsWNI\nM2/cKPLPf2J/9uxZpKgVEhMRrZvjm28QaRv6RdeHtDRE7YQQQlTsJroi2P9MTLTnFW/MyJGo8q3L\n8nDUKAjdtm3qc+3bo992zhw8fuklRMNFRbi/fDn2g7/5BlaYoaEQWq0WQurlhR8hWq0a8SoVv4q5\nhuJs5ecHkfXyUlPVvr6oRA4OhvDffTfG/q1di8roOXMQAb/zDqqYlag2PR2f17CoypD0dHzehlBd\njc9srh2JEEKaMnYV3REjUMHsLAMQPD2RGl6x4sbHubvjuL//3Xjo+9NPwwhj0yaIzLx5IpMnY6+0\nf3+RL74QWbAAbTsRERBbHx8IeEgIRFcRXyV69feHyHp74/mWLfF8SAiOCQiA4FdUIHo+eVLkwQdF\nXnsNrUxLl6II6tFH8SNgyxYUZCksWQJBNtcqlJODvuORIxv2vWZlYR5vUFDDzkMIIY0Nu4quu7vI\nI484V7T75JMwnTA3zN2QuDgMrP/gA/U5X1+RZ5/F/un58xCrf/wDe6mzZiHS27ZN5O23cY2oKIhd\ncLAqsGFhEFgRCHfLlrgFBKB4y91dnRbk46NWP3fvjgrhxx/H+RMSUHWcmyvy6qsoEHvzTXzXyijC\n3bsRFU+ebP4zfvYZ0s61tRJZSkYG2pQIIYQYY1fRFRH5859F1q1ruPmCtWjfHnuu//73jY/TaGDB\n+OGHxi5VAwZAZKdMQR/tk0/i/qhRIs8/j4h34UIUMul0EPeoKDW1HBCA/WBlv1eng0iGhECEtVo8\nDg1VC6Y0Ggh3TAwqwtesgdHH1q34HN7eiG7vvlv1UNbp8Ny0aebtGXU6iPdf/tLw7/TQIfwoIIQQ\nYozdRbdTJ5hCfP65va9cO3PnIsVsODLPHD16oCL5pZdUZygRCFW/ftjDLS0VefFFtA/NnAmryNWr\nRd54A2L39NM4xsMDBVChoUgxu7lBXMPDIcRFRRDC6mr8MAgNRaTq7w8x/e9/IfIrViBC3b8fui7H\n8wAAD6ZJREFU4tumDcReBOtQWLBAJDISJh7mSErC6z17NuCL/I28PJFevRp+HkIIaWxo9Hr7Wxhs\n3Yp9xUOHGl4lay3mzoWb03vv3fi4ykoI78CBIi+/rD5fVYVI8uxZpKADA2F9uXw5hOy55yCKX36J\nqHbYMHV/u7AQhhjh4Yhw9XqkjgsKILLt2yM6DglBCjk1FT28rVohgh44UOT115G6fuopiPqaNWra\nOiUFPxSSk81XFOt0iNZffBGVzw2huhrp8YMHsedMbItGoxEH/C9MCKknDhFdvV4kOhrFP/fcY++r\nm6ewEHu2W7Ygor0RublwehozRuThh9Xnq6og3j//DFHs1Al2jHPmwKDixRchtuvWQXzLy+GL3LEj\nfnzo9WoVswii37IyiOaJEzDPGDEC+6UJCdivffdd7MPm5YlMnAj7xrffRvQsgvdNmCCyaBF6i83x\n3nvoM96+veE/gjIysP998mTDzkMsg6JLiGvhENEVQb/ue++J7NrliKubZ/16RIz795uv7jXk2DFU\nKScmGv9w0OshiJ9/DkGeMgVCtnMn9oN370Y0OnYsouYff4Qw7tkDn+Tr19U93BYtEOF27Yr0dUYG\nrldUhB8tzz+Pvd1t25DKfvRRkRdeUN2usrNxrVGjUHBljvx8FFa99hrctRpKfDyKypYsafi5SN1Q\ndAlxLRwmupWViCwTE1Fs5Azo9RDJLl0QsdZFWhrGFq5YIfLAA8avHTyICmatFoL2hz/g+dRUtdo5\nKAjX6tQJxVTNmyOdXF0NAb54Ee03GRmIHMvKIJATJ+K82dloU9q7F61ChpHs2bNIad91F4S4NiZN\nQpq6rkIySxk0CJH9vfda53zkxlB0CXEtHCa6Ioj8Vq1CUZCz7O3++ivSyytWWCYcGRkoDJs9G1Gl\n4efQ6WAVmZiI1PDkyWo0WVkJAT50CMKal4f92ogIpJh9fSGsYWEit90GL2RlPzYrCynqTz/Ftf/x\nDxRfKaSnYw932DAIf21s2oR96V271LaihvDrr/iMX3zBAfb2gqJLiGvhUNGtqsL+5GuvNdwFyZr8\n8AOMMBITLfMgPncO6eK2bfEerdb49eJijOfbtAnFUn37QhCjoiz/sXHxIvZc9+zBvNv+/WHtaFgY\npdfDkSopCanmsWNrP9+JE2h3+uorRMPWYNkypMs//tg65yN1Q9ElxLVwqOiK4B/92bMRMTrT0POV\nK1F89L//YW+1LsrLUSi1bx/+3n+/6TFVVRip9/33iHKzsyHqkZEit9yC/VkPD4jnlStIKRcUQNQr\nK9H72r8/WoZqRpKXLmFft6wM7UlKOtscV66gf/epp9BXbC369kWE7SzFcU0Bii4hroXDRVevRwvO\n5MmIzpyJhQtRVLVuneWWhjt3IgIdNAip3drm0iptQYcOiRw/DtEsL8d+rjKD19MTRVSdO2Pv181M\nV3VZGfaIk5LQOjRvntoqZI7ycqTN77oLGQZrpfWPHYOIp6TghwOxnOTkZNFqtZKZmSnTpk0zef3A\ngQOSlZUlBQUFJq9TdAlxLRwuuiKIcocNw1i8li0dvRoVvR7RY1oaBhfUTBvXRlkZWnni45E2nzYN\nZhHW3LcuLITpxhdfoJJ5xgzs/d4InQ6OYGVlMNSwZKygpcyciUKwhQutd86mgCKocXFxkpCQIL16\n9ZLo6GijY8aOHStJSUkSHx8vQ4cONXqdokuIa2F3RypzdO+OSFdxUnIWNBpUBd99NyqDDe0fb4S3\nNyqHT5xAhPr88xgjuGhRw/pXr15FOn7SJOzXHjyIfdRly+oW3LIyzPv18MCeqzUFt7AQn8tMkEbq\nICkpSZo3by4iIpGRkZKSkmL0+oYNG+Su3zbdZ8+ebSLIhBDXwml2UefPxz7kzp3of3UWNBrsUzZr\nJnLffXCbstRXODAQAxGeeQYFUFu3igwZgr3brl2Rgg4Ph3NTaCgGDbi7w5e6sBAmHJmZENfMTLx/\n3Djs644ebXlW4PJltA15e2Ovuq4e5Jtl8WJUWbdvb93zNgWKiookODj498f5+flGr6empoqISHp6\nuqSkpMhsw5FRvzF//vzf7w8ePFgG1+aCQghxOE4juv7+SMkuXQqXJn9/R69IRaNBW05UFGwSFy9G\nr6yluLmhcOn//k/klVdETp1ClW9mJlLXBw5g+k+3biI//YS+2S5dIMI+PtjTnTEDlck3OwHo0CH0\nEI8bB9MOc/vCDaGoCJH23r3WPW9Toq70cIsWLSQ6OlpSUlIkOTlZ4moMQzYUXUKIc+M0oiuCSHLD\nBnVcnrMxejSEd/ZspHmXLcM+5s3g5oZzREXZZo0K1dX4AbNlCwqmJkywzXWWLsV/t1tusc35GwMJ\nCQkmzwUHB0tcXJxotVop+G2uZGFhoYSEhBgdFxISIhERESIiotVqZf/+/SaiSwhxHZxKdEVgHxgd\nLbJxo6nLkzPQvTuKl154AcPjp09HFOks5h4i2F995hmkqNeuxehCW5CfD1vLZctsc/7GgrmKZIVx\n48ZJamqqxMbGSlZWlgwbNkxEkHbWarUyevRo2bBhw+/P9e7d2y5rJoTYBqcopDIkMFDko48gZhcu\nOHo15vH1RYT36quoUI6LQ7rY0RQXi7z1Fvpl//QnCKKtBFcEVpmdO9s+am/MKIVRO3bsEK1WK3f+\nZlk2dOhQERGJiIgQrVYrycnJUlBQIA899JDD1koIaThO0TJkjiVLMDRgxw7rF/5YE50OdpYLFiDN\nOmECnJ7sGfnm5qr7qpGRKPwKC7PtNVNTYQBy/LjlrVTE+rBliBDXwmlFt7oa6eV27eqecesMlJXB\nRGPxYojQ+PFIO1viZlUf9HrYVW7Zgork8eNF/vY3+0SdVVX4YfHEE+j7JY6DokuIa+G0oiuCdGlM\nDAqXpk519Goso6oKbU+JiUg5R0Vh7u7AgUjFNiQCLilBNLt5M9ysTp5EGn7CBNuJuzni4zFUYd06\n61dDk5uDokuIa+HUoiuCgfAPPIB2l4EDHb2am+PqVThZbd+Oz3H8OHyJW7dGT3KbNriv1aI1SOnR\nLS3FxJ68PNgr/vwzjDYOHoSA33orUrvdutm/gCs9XWTECNhjduxo32sTUyi6hLgWTi+6IvDznTQJ\nf2+/3dGrqT/Z2bC8TE9HZXF6OjyX3dwwReiOO0SOHMHA+vPnURDl6YkIOToaldNeXo5bf2kp7Czn\nzsV/D+J4KLqEuBYuIboiIuvXw05x927MnCX2Ra/H9KT8fGQdnKlFqilD0SXEtXC6Pt3aGD8e/+AP\nHw5LxVatHL2ipsXSpSJff41RhxRcQgipHy4T6SrMny/yyy9oKQoNdfRqmgbffouxiz/+CK9o4jww\n0iXEtXC52tN582A5eDNTf0j9OXJE5JFH0DNNwSWEkIbhMullBY0GQwN8fTFAICWFVbS24sQJVCq/\n+y76cgkhhDQMl0svG7J4MUT3lVdQ+Uusx+nTyCYsWCDy2GOOXg2pDaaXCXEtXC69bMisWWhdGToU\nRT7EOmRlYYTh3LkUXEIIsSYuLboiqGrevBmOVStXorWF1J+MDJFBg1CwNn26o1dDCCGNC5dOLxuS\nmSny+ONoJXr/fZGAAEevyPXYuRM/YpYtExk71tGrIZbA9DIhroXLR7oKkZEYLB8QANekjAxHr8h1\n0OtFli8XWbRIJCmJgksIIbai0US6hqxbh4k7b72Fdhea8tdOaSnSyAcPiiQn23b+LrE+jHQJcS0a\npRw9/DDG3q1cKTJkCFpfiClHj4oMG4ZI98cfKbiEEGJrGqXoimCk3g8/iDz4IAYIvPmmSGWlo1fl\nHFRWirz+OgqmnnpK5MMPRfz8HL0qQghp/DTK9HJNsrIwcN3XV+S552Cq0VQ5fBiD54ODMbiAxiKu\nDdPLhLgWTUJ0RZBCTU7GpKLbbxd54w3MtG0qXLmC6HbzZux3T53KwQWNAYouIa5Fo00v10SjERk9\nGgPhhwzBbepUkXPnHL0y26LTiaxdi5m8OTki27ejtYqCSwgh9qfJiK6Ct7fIs8+iuKpVK7hZPfKI\nyKFDjl6ZddHpRFavhth+/bXIl1+KrFkj0rato1dGCCFNlyaTXq6NggKYaSxdKnLbbRDkESNE3N0d\nvbL68euvIqtWiXzzjYiHB5ylBg509KqIrWB6mRDXosmLrkJFhcj69TCHOHxYZOJE+Dp36+boldWN\nXi+ybx8MLjZtEnnoIZEZM0R69HD0yoitoegS4lpQdGug18PN6uOPRT79FFW+EyeKjBkD1ytnQa8X\nOXAAPxKSkpBGjo3FgIKQEEevjtgLii4hrgVF9wZUV4vs3i3yySciaWkiRUUQtthYFGKFhtp3PUVF\nIt99h3GGZ8+K/PILLBvHjhXp3p3FUU0Rii4hrgVF10L0epEjR0R27MBt1y6RkSNFPD3RgtStG/62\na2cd8SsqgmPUiRMw+di7V6RlS+zTDh2Kfedu3Si0TR2KLiGuBUW3nuh0SENnZGAP+PBhiLJGA3Fs\n00akdWvcwsMRNXt6qrfycvTOGt4uX8a0pDNnRCIicK4+fZA67tMH0ayHh6M/OXEmKLqEuBYUXSuT\nnw/RvHRJJDcXf/V6kfPnUayl04l4eeF+YKDxrVUrRMrh4RBuRrGkLii6hLgWFF1CXBiKLiGuRZMz\nxyCEEEIcBUWXEEIIsRMUXUIIIcROUHQJIYQQO0HRJYQQQuwERZcQQgixExRdQgghxE5QdAkhhBA7\nQdElhBBC7ARFlxBCCLETFF1CCCHETlB0CSGEEDtB0SWEEELsBEWXEEIIsRMUXUIIIcROUHQJIYQQ\nO0HRJYQQQuwERZcQQgixE80cvQBCmjrJycmi1WolMzNTpk2bdtOvE0JcB0a6hDiQAwcOiIhIbGys\niIikp6cbvZ6eni6RkZESGxsrkZGRJq8TQlwLii4hDiQpKUmaN28uIiKRkZGSkpJicswLL7wgIiKZ\nmZkSHR1t1/URQqwL08uEOJCioiIJDg7+/XF+fr7R69HR0RIRESHBwcGSkJBg9hzz58///f7gwYNl\n8ODBtlgqIcQKUHQJcTB6vb7W14qKiqRTp06SkJAg06ZNkx49ekhERIRF7yWEOB8UXUJsjLkINTg4\nWOLi4kSr1UpBQYGIiBQWFkpISIjJe5988kkJDAwUrVYrGzZskNmzZ9tl3YQQ60PRJcTG3KjieNy4\ncZKamiqxsbGSlZUlw4YNExFEuFqtVkREAgMDRQTFVpmZmbZfMCHEZmj0zE8R4lASEhIkMjLSqCWo\nV69ekpqaKiIi8fHxEhkZKQUFBWwZIsTFoegSQgghdoItQ4QQQoidoOgSQgghdoKiSwghhNgJii4h\nhBBiJyi6hBBCiJ2g6BJCCCF24v8BBiDuvbcyGUYAAAAASUVORK5CYII=\n", "text": "" }, { "output_type": "pyout", "prompt_number": 5, "text": "" } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": "Compute and plot the leading order behaviour around $x=0$" }, { "cell_type": "code", "collapsed": false, "input": "ltc = series(fresnelc(x), x, n=2).removeO()\nlts = series(fresnels(x), x, n=4).removeO()", "language": "python", "metadata": {}, "outputs": [], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": "lts, ltc", "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 7, "text": "(pi*x**3/6, x)" } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": "figsize(4,4)\nplot(fresnels(x), lts, (x, 0, 1))\nplot(fresnelc(x), ltc, (x, 0, 1))", "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAQQAAAD7CAYAAACMu+pyAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAG8tJREFUeJzt3Xt41NWdx/F3vLTenUyoXXerLYPgFtttIoKX7qMjk3hb\nq5Ygcdv1stpg++hWa5uCrq6h3pBIRV1EM3gpaGVDRq23IsyorVQUwowVuXhhRhHtimYycVUUIdk/\nvmQkJMwkmctvJvm8nofHzJxfZr7EyZdzzu97zinp7OzsREQE2M3pAESkcCghiEiSEoKIJCkhiEjS\nHukuCAQCuFwuotEotbW1PdrD4TCxWIx4PN5ru4gUj5Q9hHA4DIDP5wMgEon0uGb69OlUV1eTSCR6\nbReR4pEyITQ1NVFaWgqAx+MhGAx2a29ubmbs2LEA1NXVUVFRkaMwRSQfUiaERCKB2+1OPm5tbe3W\n3tLSQmtrK5FIhIaGhtxEKCJ5k3YOIV3d0rBhw6ioqCAYDBIIBKiurk62lZSUcO211yYfe71evF7v\nwKMVkZxKmRBcLhfxeByAtrY2ysrKurWXlZUxfPjw5LUrVqzolhAA6uvrsxiuiORSyiFDTU0N0WgU\ngFgsRlVVFWBDCYCJEycm2xOJBOPGjctlrCKSYykTQtckYSgUwuVyUV5eDkBlZSUAw4cPx+VyEQgE\niMfjTJgwIcfhikguleRycVNJSUnaOQgRKRyqVBSRJCUEEUlSQhCRJCUEEUlSQhCRJCUEEUlSQhCR\nJCUEEUlSQhCRJCUEEUlSQhCRJCUEEUlSQhCRJCUEEUlSQhCRJCUEEUlSQhCRJCUEEUlSQhCRJCUE\nEUlSQhCRJCUEEUlSQhCRJCUEEUlSQhCRJCUEEUlSQhAZZF57beDfq4QgMsjcc8/AvzdtQggEAoRC\nIfx+f6/tU6ZMAdhlu4jkzxdfwLx5A//+lAkhHA4D4PP5AIhEIj2u8fv9jBw5khEjRgw8ChHJiiee\ngFGjBv79KRNCU1MTpaWlAHg8HoLBYI9r/H4/b7zxBuPHjx94FCKSFffcAxddNPDvT5kQEokEbrc7\n+bi1tbXHNfF4nFAoRENDw8CjEJGMbdwIL7wAEycO/DX2SHdBZ2dnyvba2loAlixZQigUSg4vutTX\n1ye/9nq9eL3e/kcpImndfz9MmgT77jvw10iZEFwuF/F4HIC2tjbKysq6tfv9ftxuN9XV1ZSVlRGN\nRlMmBBHJjY4OuPdeaGrK7HVSDhlqamqIRqMAxGIxqqqqABtKgM0rVFZWAjacGDt2bGbRiMiAPPss\n7L8/jBmT2eukTAgVFRUAhEIhXC4X5eXlAMkk4PP5CAaDBAIBhg0blmwXkfyaNw8uuwxKSjJ7nZLO\ndJMEmbx4SUnaOQgRycymTXD44RCLgcuV2WupUlGkyN1/P/zwh5knA1APQaSodXTAyJHw0EMwblzm\nr6cegkgRC4XggAMgW/P5SggiRezuu+HiizOfTOyiIYNIkfrb32D0aHj7beslZIN6CCJF6t574eyz\ns5cMQD0EkaK0bRuMGAGBQObFSDtSD0GkCP3xj3D00dlNBqCEIFKU7rwTTjkl+6+rIYNIkVm/Ho45\nBjZsgL33zu5rq4cgUmTmzIELLsh+MgD1EESKyqefwqGHwvLl4PFk//XVQxApIgsW2GRiLpIBKCGI\nFI3OTpg9Gy65JHfvoYQgUiReegkSidzcXeiihCBSJGbPhp/9DHbL4W+tJhVFisCmTVBeDq++Cjts\nhJ516iGIFIHGRjjjjNwmA1APQaTgbdkCw4fDokXw3e/m9r3UQxApcAsXwre/nftkAEoIIgWtsxNm\nzYLLL+/796xePfD3U0IQKWDLltmtxtNO69v1nZ2Z1SkoIYgUsFmz4Oc/7/utxgULoL194O+nSUWR\nArVhA1RUwFtv2alM6Xz0kc01LFwIxx03sPdUD0GkQM2eDeef37dkADBtGpx88sCTAfTh9GcRyb9P\nPrE9E5cv79v1q1fbn3nzMntf9RBECtD8+fDP/2z1B+l0TSSecQYcdFBm76segkiB6eiA226Du+7q\n2/UPPWTzBxdfnPl7p+0hBAIBQqEQfr8/5XUNDQ2ZRyMiLFoE3/kOHH98+mvb26GuzvZY3H33zN87\nZUIIh8OAHfsOEIlEer0uGAyyZMmSzKMREW65Bc46q2+nMdXXw6mn2h6L2ZAyITQ1NVFaWgqAx+Mh\nGAz2el1Jts6REhniVq6EN9+ESZPSX/vKK/Dgg3DTTdl7/5QJIZFI4N5heVVra2uPayKRSLIHISKZ\nueUWuOwy2HPP1Nd1dNhE4m9+A1/7WvbeP+0cQrrCong8nrVgRIayt96CxYuhtjb9tfPnwz/8Q9+u\n7Y+UdxlcLlfyF76trY2ysrJu7X3pHdTX1ye/9nq9eL3egUUqMsjddhtcdFH6sxoTCZg6FR57LDsT\niTtKmRBqampoaWnB5/MRi8WoqqraHlACl8tFNBolGo3S2tpKPB4nEolQUVHR7TV2TAgi0ru2Nvjd\n72xeIJ2rr4Yzz4SxY7MfR8ohQ9cvdygUwuVyUV5eDkBlZSUA1dXVVFdXU1JSQnt7uyYXRQbI74fT\nT4dvfCP1deEwNDfDjTfmJg4tbhJx2GefwahR8NRTVn+wKx0dtk5h8mS48MLcxKLSZRGH3X8/fO97\nqZMBwD332DLoCy7IXSzqIYg4aOtW6x3Mnw/f//6ur/vwQ6istOSxfeSeE+ohiDioqcnmDVIlA7C7\nCl5vbpMBaHGTiGM6O2H6dLj55tTXvfAC/PGPsHZt7mNSD0HEIU8+aXUEqY5m27rVTmuaOTN9fUI2\nKCGIOKCz09YgTJ2aehHTHXdYaXJNTX7i0pBBxAFLl8L770N19a6vefdduOEGGzLkq8RHPQQRB9xx\nB/z617BHin+SZ860BUyjRuUvLvUQRPJs5UpoaUm9/+GiRfDoo5kdujIQ6iGI5Nl118EvfgF77dV7\n++bN1jP47/+GvffOb2wqTBLJo5dftlOY1q/f9S/7NdfAunV2vkK+KSGI5NHEibYe4Yorem9ft852\nW/7rX22/g3xTQhDJk1dftfLj9eth3317tnd22l6K48fbrklO0ByCSJ5cf731DHpLBmD7I8bjmR3W\nmin1EETyYO1aOOEEiEZhv/16tre2whFHwOOP52bjk75SQhDJg3/7Nxg9Gq66qvf2n/wE9tkHbr89\nv3HtTHUIIjm2bh28/rod3tqb55+3uoM1a/IbV280hyCSY/X1MGECHHhgz7bPP7eahNtuy8/ipXQ0\nZBDJoVdegZNOssNXeps7uP56q0b8/e/zt14hFSUEkRw66yybTPzFL3q2vf661SSsXAnf/Gb+Y+uN\nEoJIjrS0WEJ4442eVYmdneDzwQ9+0HuycIrmEERy5Jpr7K5CbyXKv/udndz8H/+R/7hSUQ9BJAf+\n8hf48Y/htdfgq1/t3rZpE3z3u7Yt2pFHOhPfrighiOTA+PFWe9Db+Qk//jH84z9aD6LQqA5BJMue\neQbeeQfOO69n26JFtgNSY2P+4+oLJQSRLOrstLqDm2/uuRvSxx/DT39qyWBX6xmcpklFkSx6+GH4\nv/+zuws7u+YaOP54q0soVOohiGTJ1q12V+H22+3ItR0tXw4PPWRLoAuZeggiWXLvvXYK0849gC1b\nbBhx++0wbJgjofVZ2h5CIBDA5XIRjUapra3t0d7c3ExpaSkLFy7krrvuykmQIoXu009h2jTbGHXn\nEuSbb7Yew9lnOxNbf6TsIYTDYQB8Ph8AkUikW3soFCIUCuHz+YhGo7z88ss5ClOksN12m53PuPNe\nBmvWWM9gzpzCWKuQTsqE0NTURGlpKQAej4dgMNit3efzMWfOHADi8TjluT6JUqQAffihnaFwww3d\nn9+2DS66yHZZPuQQZ2Lrr5RDhkQigdvtTj5ubW3tcU17ezuNjY1ceeWV2Y9OpAhcf72dvzhyZPfn\n586Fr3wFJk92Jq6BSDuHkK7S8MADD6Suro6TTjqJI488kuHDh3drr6+vT37t9Xrxer0DClSkEL3x\nBjzwQM/NTdavtzsOL77Y845DIUuZEFwuF/F4HIC2tjbKysq6tYfDYUpKSqioqODII4+kubmZurq6\nbtfsmBBEBpspU6CuDg466MvnOjpsqHDVVT17DYUuZe6qqakhGo0CEIvFqKqqAmwoATap2JUwEokE\nI0aMyGWsIgXlT3+CcLjnlulz5thOSJdf7kxcmUiZECoqKgD7xXe5XMlJw8rKSgAmT55MNBrF7/dT\nWlrKhAkTchyuSGHo6IBf/hKmT+9+JFssBtdeC/fdB7vv7lx8A6XVjiIDMH++bZq6bNmXtxM7O+H0\n0608ecoUZ+MbKJUui/RTVxHSvHndawu6VjD+8pfOxJUN6iGI9FN9vS1vvueeL5+LxWDcOJtXGD3a\nsdAypoQg0g9vv227HEUicOih9lxHh53ZeOqpdsehmBXRHVIR5/3qV3ZXoSsZgN1V+OyzXZ/oXEw0\nhyDSR88+CytW2NxBlzfftA1TH3igOO8q7Ew9BJE+2LrVegYzZ365i/K2bXDBBfCv/wqjRjkaXtYo\nIYj0wd13214GO5bazJwJe+7ZszCpmGnIIJLGBx/Ak0/CrFlf3mZctQoaGuwwlmJaq5DOIPqriOTG\nlCm2bfo//ZM93rIFLr0UZswonCPYskU9BJEU/vIXWLy4+2rG//ov+Pu/t/mDwUYJQWQXtm61fQ5m\nzvzyqPY//9nuMrz8cnHsgNRfGjKI7MIdd8DXvw6TJtnj9nY7fMXv777ceTBRpaJIL959F773PRsy\nHH64PXfeeXbAyvZdAwclDRlEenHddVaV2JUMFi6El16y/Q8GMyUEkZ089pidz/jKK/b4nXfgt7+1\nJc+FegRbtighiOzgo4/gkkvsl3+vvawa8dxz4cwzbTXjYKc5BJEdXHqpLVSaO9ce33ADhEKwZMng\nWKuQjnoIItstW2aHta5ebY9ffNEOWVm5cmgkA9BtRxHAqg9ra608ubTUbjH+6Edw1112XuNQoSGD\nCHZXYflym1AE2wbt008tIQwlGjLIkLd6NSxdavMGJSV2ivPTT9veB0ONEoIMaVu32pqE2lo7f3HN\nGlvM9NxzsM8+TkeXf5pDkCFtxgybM6ittSHCpEl21sIRRzgdmTM0hyBD1quvwokn2l2EQw+1Q1k/\n+cS2QxuMC5f6QkMGGZK++MKGCjfeaMngwQehtRXuv3/oJgNQQpAhatYsKCuDn/wE1q61cxiDQdh/\nf6cjc5aGDDLkhMNWivzCC+B2W0nyFVfYic1DnRKCDCmbN8OYMXD11bZb8nnnWRXiffcN7aFCl7RD\nhkAggMvlIhqNUltb26Pd7/cDsH79eqZPn579CEWyaMoU2+fgRz+yo9heftmWNSsZmJS3HcPbF3/7\nfD4AIpFIt/ZQKERlZSW1tbVEo1FCoVCOwhTJ3OLF8OijcOedVpV4443Q3Dw06w12JWVCaGpqorS0\nFACPx0MwGOzWHo1Gk895PB6i0WiOwhTJzIcf2hzBffdZMdLZZ8Mtt3y5AYqYlEOGRCKB2+1OPm5t\nbe3WvuMQIhwOc84552Q5PJHMdXZa4dFPfwonnAAnn2xDhh/+0OnICk/aOYS+TAqGw2HGjBlDeXl5\nj7b6+vrk116vF6/X268ARTI1Z46d2rxgAfznf9rBKtdf73RUhSllQnC5XMTjcQDa2tooKyvr9bpQ\nKMRNN93Ua9uOCUEk31atgmuvtc1SFy2C//kfO21pqOxv0F8p5xBqamqS8wKxWIyqqirAhhJdGhsb\nqaurA9CkohSUTz+FmhqbK/jsM7j4YnjkETujUXqXMiFUVFQA9ovucrmSQ4LKykoAgsEgU6dO5bDD\nDsPtdlOiezdSQK67Do47Dk47zQqRbr0Vtn+kZRdUmCSD0vz5Nk+wbBlUV8Mxx8AuRrWyAyUEGXTW\nrLG7Cc88Yzsevf02/OEPmjfoCyUEGVQ++QTGjoW6OlvReOuttlnqgQc6HVlx0AYpMmh0dsLUqXD0\n0XZMu99vPQMlg77T8mcZNGbPtt5AYyOccorVHYwa5XRUxUVDBhkUli61ycMnn7RVjFOnajnzQCgh\nSNF77z2bN5gzB2bOtCHDjBlOR1WclBCkqH3+ue2FeNhhtgVaPG7boO2m2bEB0RyCFK3OTluw9PHH\nVon44ot2q1HJYOD0o5OiNWsWRCLg9doahccf194GmdKQQYrS00/Dv/+7bXJy5ZXw/PM2bJDMaMgg\nRWfdOjj3XDuq/d57bcGSkkF2qIcgReWDD+DYY+FnP7NVjHffDWec4XRUg4cSghSNzZvB54OjjrJT\nmuvr7bAVyR4lBCkKHR1wzjmwbZstXrrwQluvINmluwxSFGbMgI0b4atfhR/8QMkgV5QQpODdfrvt\nlrzbbrDffnDzzU5HNHhpyCAFbcEC6w2MHAkHHwzz5mlfg1xSQpCCFQzaduljx8Kee8LChfZfyR0N\nGaQgrVgBv/2tHbt20EHWU1AyyD0lBCk4q1bZxOHmzfb4zjthr72cjWmo0JBBCsrrr8OJJ8KIEdYj\n0PqE/FJCkILx9ttw/PEwerQta37iCSWDfNOQQQrCxo1w+eVQVmabo6pn4AwtbhLHbdxoS5j32ss2\nR21uhr33djqqoUk9BHFUVzLYc0/bEPWRR5QMnKSEII7ZuNHmDPbYA6qqbJOTr3zF6aiGNiUEcUQ0\nCmefDVu2wPjxdqCK6gyclzYhBAIBQqEQfr9/l9dMmTIlq0HJ4LZ6NXz/+7B+vW2VPnu2ypELRcqE\nEA6HAfD5fABEIpEe1zQ2NhIIBHIQmgxGLS127uI++8DVV8O0aaBDwwtHyoTQ1NREaWkpAB6Ph2Aw\n2OOayZMn4/F4chOdDCp/+pPNFXzxhZ3E/POfOx2R7CzlbcdEIoHb7U4+bm1tzXlAMjj94Q/WIwDb\n7eiEE5yNR3qXtg5BlYaSqdmz4aqrbJiwdCkccYTTEcmupEwILpeLeDwOQFtbG2VlZf1+g/r6+uTX\nXq8Xr9fb79eQ4tTRAb/+tR2++q1v2dbpBx/sdFSSSsqEUFNTQ0tLCz6fj1gsRlVVFWBDCZfL1ac3\n2DEhyNCxebOdqvToo7Yx6u9/r4KjYpByUrGiogKAUCiEy+WivLwcgMrKyuQ1zc3NtLS0MHfu3ByG\nKcXkf//XDlxtbraJw4cfVjIoFlrtKFn1179aj2DzZnjwQTjrLKcjkv5QpaJkzUMPwamnWsXhSy8p\nGRQjJQTJ2LZtcMkldtbiqFF21Np3vuN0VDIQSgiSkQ8+gJNOggcegCuusOPYDzzQ6ahkoLQfggzY\n88/D6adbD+GRR6wKUYqbegjSbx0dcN11Nnk4YoQtUlIyGBzUQ5B+ef99mzhctQp+9Ss7kn03/bMy\naCghSJ8FAnDeeXa+4vPPwzHHOB2RZJtyu6T18cc2V1BTA6ecAu+8o2QwWKmHICk98wxUV9uS5UAA\nzjzT6Ygkl9RDkF598gmccYZNFp54Irz7rpLBUKAegvSwcKEVGe22m/UKVHE4dKiHIEnvvQfHHgvn\nnGNnK27apGQw1CghCNu2wdSpcOihlgSWLbN1CTpgdehRQhjiHn4Yhg2DWbNg+nR4800YN87pqMQp\nWv48RL3yig0NWlttS/R582C//ZyOSpymHsIQ89578C//AuXlVmD05z9bL0HJQEAJYchIJGDCBDjk\nEIjFYNEiiETg8MOdjkwKiRLCIJdI2NDga1+D5cth/nxYs8aWLIvsTHUIg9SmTbbJ6dNP2/bnd99t\ntQU6JUlSUQ9hkFm71lYjHnwwhMNw5522icmFFyoZSHpKCIPEE0/YROERR9gx6489Bm+9Beef73Rk\nUkyUEIrY5s1QVwelpbbO4O/+znY9XrXK7iSI9JfmEIrQc8/ZOYlvvGFJ4fzz4cYbYf/9nY5Mip16\nCEXivfdg8mT45jdh/HhbjTh7Nnz0Edxxh5KBZId6CAWsvR1mzLANTNeuha9/3SYHp0zRzsaSG0oI\nBeb99+HWW+Hxxy0JHHCAFRQ98oiKiCT3lBAKwNKlMHcuLF4Mf/sbuN126/DBB+3OgUi+aHGTAzZs\nAL8fnnrKqgY//9xOPDrtNLjsMpsnEHGCEkIerF1rJcPPPguvvQZtbdYLOPZY27j0nHPsPEQRp6W9\nyxAIBAiFQvj9/gG1F5vnnnsuo+/ftMn+9a+uhtGjbZOR0aPtObcbfvMbW1/Q2mrFROeem1kyyDRe\nJxRbzMUWLww85pQJIRwOA+Dz+QCIRCL9ai9Gff1BbtkCS5bAlVdaEdDIkbac+OCDbfehdevguONg\nwQIbEnzwATz5JFx6aXbvEAylD6tTii1eGHjMKScVm5qaOGn7sjiPx0MwGKSioqLP7cWuvd1WCK5c\naV39116zcuB4HHbf3X7R3W749rfh5JNtd+JTToF993U6cpGBSZkQEokEbrc7+bi1tbVf7YWoo8Nq\n/aNR+7Nhg/2Sv/++Pb9hAzQ02D6Dn38Oe+xhRT+HHALf+IYdUHL00eD1Wl2AyGCS9rZjuknBdO0l\nRbnEblryq61bbRKwrc22HXvqKQfD2oVp06alv6jAFFvMxRYvQH19fb+/J2VCcLlcxONxANra2igr\nK+tXu+4wiBSXlJOKNTU1RKNRAGKxGFXbz/xOJBIp20WkOKVMCF0ThKFQCJfLRfn2srnKysqU7ZIb\nfb3F29DQkKeIpFBMmTJll239KQ3IWmFSIBDA5XIRjUapra3td7sT0sXU9QNcv34906dPz3d43YTD\nYWKxGNXV1fj9fo466qhe7+gEg0FmzJjB4sWLHYiyp3Q/466/VzweL5rPRaF9lhsbG5kxYwZvvvlm\nj7a+fm66ZGX5czHWK6SLKRQKUVlZSW1tLdFolFAolPcYd9TU1ERpaSnw5S3e3hTSJG5f/r9Pnz6d\n6upqEolEUXwuIpEIHo8Hn8+Hx+MpiJgnT56Mx+Ppta2vn5suWUkI6d60v0HlQ7qYotFo8jmPx5Oc\nK3FKX27xRiKR5Ae5EKT7GTc3NzN27FgA6urqCqKGpS+f1a7ueTQaLYiYU+lvaUBWEkIx1iuki6m2\ntjbZHQyHw8kPrpPSje667vgUinQ/45aWFlpbW4lEIgUz75Eu5oqKCoYPH47b7e52XSHrz6xA1nZM\nyrRewQl9iSkcDjNmzBjHJ0zT3eIttN5Bl3Q/42HDhiX/lQ0EAvkIKa1UMScSCQ477DD8fj+1tbXE\nYrE8RtZ/6T43O8tKQsi0XsEJfY0pFApx00035TO0XqW7BRyNRgkEAjQ2NhKPxwtibJvuZ1xWVsbw\n4cOT165YsSLvMe4sXcx+v5+LL76Y6upqFi5cSHNzsxNhpjXQ0oCsJIRirFdIFzPY7G1dXR2A45OK\n6W4BV1dXU11dTUlJCe3t7QUxuZjuZzxx4sRkeyKRYFwBHDvdl8/FAQccANjEo8vlyn+QO2lubqal\npYW5c+cmnxtoaUDWbjv6/f7k5FvX2Puoo46ipaVll+1OSxVzMBhk0qRJuN1u4vE4zc3NjB8/3uGI\ni09fPhdut5uWlpaC6IlB+pgbGhrweDwFdas0W3K6QYqIFBdtwy4iSUoIIpKkhCAiSUoIIpKkhCAi\nSUoIIpL0/72sxsqe951gAAAAAElFTkSuQmCC\n", "text": "" }, { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAQQAAAD7CAYAAACMu+pyAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAGJtJREFUeJzt3XtwXHX9xvF3KHeGzummLSIIZHsBSmmTNi0gFJduwkUG\nuQQbEEGQSasiiCOxiDIEfkBrowzjOArd6ijMqBOzIJdBLrsWKCCXsAtiSUvbXS6thZ5msxUGkDrm\n98eXXTZtupvL7p5zdp/XjGPTsw0fwjlPP9/LOadmYGBgABERYC+nCxAR91AgiEiWAkFEsoYVCEuX\nLt3jsXA4TDQaJRQKFa0oEXFGwUBYuXIl4XB4yGOxWAyAYDAIQDweL2JpIlJuBQNh8eLF+P3+IY91\ndXUxYcIEAPx+P5FIpLjViUhZjWkOIZ1O4/P5sl/39fWNuSARcc6YJxW1jUGkcuw9lj9sWRapVAqA\n/v5+amtrBx2vqanhpptuyn4dCAQIBAJj+UeKSAmNKhDS6TSWZdHa2kpPTw/BYJBkMklzc/Nun+3o\n6BhrjSIyArYNkyaN7s8WHDJ0d3fT09PDqlWrsr/X1NQEQENDAwDRaBTLsqivrx9dFSJSFLYNny76\njUpNKe9lqKmp0RyDSJlkwuArX4Fbbx3d99BORZEKkBsG//d/o/8+6hBEPG77drjiCpgzBzo6oKZm\n9N9LHYKIh23fDgsXwqxZYw8DUCCIeFYmDM45x8wZjDUMQIEg4kmlCAPQHIKI59g2XH451NcXNwxA\nHYKIp2RWExobix8GoEAQ8YzcpcViTCAORYEg4gG77jMoRRiA5hBEXM+24eqrYerU0oYBqEMQcbVM\nZzBlSunDABQIIq61670JpQ4DUCCIuFK55gx2pTkEEZexbXNvQmMj3HRT+cIA1CGIuEqmM6ivL38Y\ngAJBxDWcGibk0pBBxAVsGxYtgpNPdi4MQB2CiOMynUEw6GwYgAJBxFG5w4Qf/9jZMAAFgohj3DBn\nsCvNIYg4wLbhkkvglFPgxhvdEQagDkGk7DKdwfz57goDUCCIlJUbhwm5FAgiZbJtGzQ1uTcMYIzv\ndhSR4bFtEwaXXQY/+IE7wwDUIYiUXO4wwc1hAAoEkZJy+5zBrjRkECmRTBhceilcd537wwDUIYiU\nRG5n4JUwAAWCSNF5bZiQS4EgUkReDgPQ1mWRorFt+O53Ydo0b4YBqEMQKYpMZ+DlMAAFgsiYeX2Y\nkEuBIDIGlRQGoEAQGbVKCwPQpKLIqJTz9WrlVHCnYjgcxrIsEokEbW1tIz4uUmkyncE551RWGECB\nIUMsFgMgGAwCEI/HBx2Px+P4/X6CwSB+v3+34yKVxonXq5VT3kDo6upiwoQJAPj9fiKRyG6fWbp0\nKQCJRIKGhoYSlCjiDpU4Z7CrvIGQTqfx+XzZr/v6+gYdb2hooK6uDp/PN+hzIpXGtuG88yo7DGAY\ncwj5JgXT6TRTp04lFArR1tbGnDlzqKurG/SZjo6O7K8DgQCBQGDUxYo4Yft20xm0tsINN1RuGECB\nQLAsi1QqBUB/fz+1tbWDjodCIZYsWcL48eOxLIvu7m7a29sHfSY3EES8Zvt2WLjQTCBWehhAgSFD\na2sriUQCgGQySXNzM2A6g4zx48cDZuLRsqxS1SlSdrlhUIkTiEMpuA8hFArh9/sHLSs2NjbS09MD\nQGdnJ36/n1Qqtduyo/YhiFdt3w4XXAALFlRPGIA2JonsJtMZLFrkjterDcfHH0N/v/n/Tz6Bo48e\n3ffRI9REcuQOE9wSBgMD8N570NsLGzfC+vXwzjvw9ttwyCHw+OPw3//CqafCpk2w777mM6OhDkHk\nU26ZM7BteOEFeO45ePllWLsWdu6E6dPh2GPB74cjj4QjjoDDDoNJk+DAA4tTrwJBBGfDYMcOWL3a\n/E2fTMLf/w6nnQazZ8PcueZ/n/98eWpRIEjVs2245hrzN2+5wiCRgL/8BR55BF55BebMgdNPNy9z\nOf54GDeu9DUMRYEgVS13O/Itt8BeJXwgwNtvwx//CD09sGaN6UbOPdd0JgceWLp/7kgoEKRqlePe\nhPffhwcfhLvvhtdfh5YWuPhis5zpVBeQjwJBqlIpw2BgwHQBK1dCdzeceaYJgTPPNCsAbqZlR6k6\ntg1XXWXa9VtuKV4YfPIJdHXBL39plgFbWkxXcOihxfn+5aAOQapKKTqDVAruvRd++lOYMQOuvRa+\n/OXSzkeUijoEqRrFDoPNm+HOO+G3vzW3Rj/2mFkh8DIFglSFYobB5s2wbJnZDThrFrz6KnzhC8Wr\n1UkebGpERsa24cor4fzzxxYGW7ea/QqzZ8NBB8Ef/gB33FE5YQAKBKlwmc5g1izo6BhdGKTT8KMf\nwcyZMHmyuadgxQrz60qjIYNUrLEOEz75xKwY3HMPNDaaHYWV1A0MRYEgFWksYTAwAA8/DN//Phxz\njBkazJhRulrdRIEgFce2obl5dGHw2mvwve+ZJcO77jL3FlQTzSFIRcl0BpdcMrIwSKfNJqVg0Gwo\nevTR6gsDUCBIBckdJlx33fDCYGDgsyHBtm1mZ+FVV8HeVdo7V+m/tlSa0cwZbNhgguOtt+C+++DE\nE0tfp9upQxDPs21z89BXvzq8MNi5E5Yvh5NOgrPPNjciKQwMdQjiabmdwU9+UjgMYjGzSWnyZBME\nRx1VljI9Qzc3iWeNZJjwn//AzTebx5N985vw9a+74wGqbqNAEE/K3MI8fXrhMHj5ZfjGN2DaNLOU\neMgh5avTazSHIJ6T6QwKhcHOneZeg7POMluP77tPYVCI5hDEU4Y7TFi/3gwLJk6EeNw8rlwKU4cg\nnmHbcPnl5hVrewqDgQFYtQpOPtnMFTzyiMJgJNQhiCfkdgY33TR0GNi2CYFx48xLTqZPL3+dXqcO\nQVxvOMOESATq682Ow64uhcFoaZVBXM224VvfMhf6UA9E3bkTOjvhV7+C3/2uOu8/KCYNGcS1dn2J\nyq5h8NZbcNFF4POZicNJk5yps5JoyCCuVGiY8PDDMH++uTPxoYcUBsWiDkFcZ9s20/oPFQY7d8IN\nN8DTT8MDD+gehGJTIIir2DaccYbZQ9DePjgMtmwxQ4SDDzbLibW1ztVZqTRkENfIDBPOPnv3MFi9\nGk45xbwO7eGHFQalog5BXGFPcwYDA/Czn8HPf27enHzaac7WWekKBkI4HMayLBKJBG1tbbsdj8Vi\nJJNJUqnUkMdFCtlTGLz/PlxxhXmN+osvwhFHOFtnNcg7ZIjFYgAEg0EA4vH4bp9Zvnw5LS0tpNPp\nIY+L5GPb8J3v7B4GGzaYCcPp080EosKgPPIGQldXFxMmTADA7/cTiUQGHe/u7mbevHkAtLe309DQ\nUKIypRJlOoOjjx4cBo88Yu5FuOYauP122H9/Z+usJnkDIZ1O4/P5sl/39fUNOt7T00NfXx/xeJzO\nzs7SVCgVaahhwsCAeWdiWxvcfz8sWeJ0ldWn4BxCoa3HEydOpKGhgUgkQjgcpqWlZdDxjo6O7K8D\ngQCBQGBUhUrlGCoMPvzQvA8hmTTzBbpD0Rl5A8GyLFKpFAD9/f3U7rLWU1tbS11dXfazL730Ut5A\nEMmEwaWXfvao9M2b4dxz4bjjzJKihgjOyTtkaG1tJZFIAJBMJmlubgbMUALgwgsvzB5Pp9PMnz+/\nlLWKxw313oTnn4cTToDWVvj97xUGTssbCJlJwmg0imVZ1NfXA9D06S1ldXV1WJZFOBwmlUpxwQUX\nlLhc8aqhhgn33mu+vvtu+OEP9dBTN9Dtz1Jytg1XXw1Tp5owGBiAG2+EtWvhttvMUEHcQTsVpaQy\nncE555gw+Ogj8wTkrVvNSoLuUnQX3csgJZM7TLj1Vnj3XfjSl8w8QTSqMHAjBYKUxLZtg+cM/vEP\nOP10s5pwzz2w335OVyhD0RyCFJ1tw/nnm/ch3HADPPYYXHYZ/PrX5oEm4l7qEKSoMsOEQMCEwcqV\n5tHp99+vMPACTSpK0eTOGXR0wPXXmyB45hmzwiDup0CQorBtc+/BeeeZ16ZdcgkccIB5uaoeZuId\nGjLImGU6gxkzzP0IZ5xh9hrcdZfCwGsUCDImucOEK680jzmbNw/+9CdtQ/YirTLIqNk2fPvbcOyx\nZlXhxhtNd3DNNU5XJqOlDkFGJdMZHHMMLFhgHn565ZUKA6/TpKKMWO4wYfp0cyvzffeZ4YJ4mwJB\nRsS2zWPSL77YvGW5u9s8In3GDKcrk2LQHIIMW+6NSh9+CE88AY8+Cocf7nRlUizqEGRYcl+ikkiY\npxytWQOfPoNXKoQCQQrKhMGZZ8L27eYW5scfNxuPpLJolUHysm1zl+L555u5AjDzBgqDyqRAkD3K\ndAannGI2Gp1+urlZaW/1lRVLk4oypEwYfPGL5lkGixbBtdc6XZWUmgJBdmPbsHgx+Hzmseh33GFu\nVpLKpyGDDJLpDA48EB58EH7zG4VBNdFoULJytyM/+aTZfbhggdNVSTlpyCCAeQZiU5N5y3IsBn/9\nK8ye7XRVUm7qEATb/iwMXnsNnnoKpk1zuipxgjqEKpcZJhx8MPT1QSSircjVTJOKVSwTBvvua962\nvGaNwqDaqUOoUpm7Fj/6yNyP8PDDMH6801WJ09QhVCHbhoUL4YMPTEfw6KMKAzEUCFXGtuG008zt\nywsXwgMPmD0HIqAhQ1WxbfMClX//26wqrFplHnIikqEOoUrYNrS1mZWE884zOxAVBrIrdQhVwLbN\nW5c/+cTcpHTbbVBT43RV4kbqECqcbcOpp8LWraZDuP12hYHsmXYqVjDbNs8yePdd80p2PSJdClEg\nVKhMZ/Cvf8Gdd5p3JogUUnDIEA6HiUajhEKhvJ/r7OwsWlEyNrZtHmzywQdw990KAxm+vIEQi8UA\nCAaDAMTj8SE/F4lEeOKJJ4pcmoyGbcNJJ5nO4Be/gK99zemKxEvyBkJXVxcTPn3Ott/vJxKJDPm5\nGs1SuYJtw4knmgnE7m7zYFSRkcgbCOl0Gp/Pl/26r69vt8/E4/FsByHOsW044QSzgvDQQ3DWWU5X\nJF5UcFKx0D6CVCpVtGJkdGzbvILdtuGxx/SORRm9vIFgWVb2gu/v76e2tnbQ8eF0Bx0dHdlfBwIB\nAoHA6CqVIdk2NDaaF6isXg3z5ztdkXhZ3kBobW2lp6eHYDBIMpmkubkZMEMJy7JIJBIkEgn6+vpI\npVLE43EaGhoGfY/cQJDism2YOxdSKXj2Waivd7oi8bq8cwiZizsajWJZFvWfnnFNTU0AtLS00NLS\nQk1NDTt27NDkYhllnmewzz7wwgsKAykO3cvgQbZtAuCDD+DFF+Hoo52uSCqFdip6jG2bpyF/+KF5\nOvKUKU5XJJVEgeAhmScdffQRvPoqHHmk0xVJpVEgeIRtw/HHm6cbvfaaHoYqpaE5BA/Yts2Ewf/+\nZ168euihTlcklUodgstt2wYzZ5odiGvXwuTJTlcklUyB4GLbtpknHe21F/zznzBxotMVSaXTE5Nc\nats2mDEDPv4YXn9dYSDloTkEF3rvPRMGBxxgOgPLcroiqRYKBJd57z1zP8LAgAkDvUBFyklDBhd5\n912zmpCZQFQYSLkpEFxi61Y49tjP9hkcfLDTFUk1UiC4wNatcNxx5qWra9cqDMQ5CgSHbdliOoOJ\nE00YHHSQ0xVJNVMgOGjLFrOaMGWK2YF4wAFOVyTVTqsMDtmyxdy16POZMNh/f6crElGH4IjNm80w\nYfJkM4GoMBC3UCCU2TvvmKXFww6DV16B/fZzuiKRzygQyuidd2DOHDjiCPM8g333dboikcEUCGXy\n9ttmAvFzn4OeHoWBuJMCoQzeesvsMzjySPPYs332cboikaEpEErszTdNGBx1lJkzUBiIm2nZsYTe\nfNO8hfnQQ82j0vfW0yfE5dQhlMibb5onHU2apDAQ71AglEAyaYYJU6eaOQOFgXiFhgxFlkya5xkc\nfrhZTRg3zumKRIZPHUIRJRJmn4HCQLxKgVAkiYTZgVhXBy+9pDAQb9KQoQgSCZg3zywtvviiwkC8\nSx3CGCUSZjXhqKPUGYj3KRDGYONGM2cwe7YJg7300xSP0yk8Sps2waxZ5v6EZ59VGEhl0Gk8Chs3\nmgnE446DZ55RGEjl0KTiCG3YYPYZTJsGzz+vMJDKotN5BDZsgLlzFQZSuXRKD9Mbb5g5g5kzFQZS\nuXRaD8Mbb0B9vVlN0JyBVDKd2gWsX2+CYN48eO45hYFUtoL34YXDYSzLIpFI0NbWttvxUCgEwKZN\nm1i+fHnxK3RQpjM48USIRhUGUvnynuKxWAyAYDAIQDweH3Q8Go3S1NREW1sbiUSCaDRaojLLL9MZ\n1NcrDKR65D3Nu7q6mDBhAgB+v59IJDLoeCKRyP6e3+8nkUiUqMzyWr/e7EA84QRtOpLqknfIkE6n\n8fl82a/7+voGHc8dQsRiMS666KIil1d+69ebrmDePPjb3xQGUl0KziEMZ2NRLBZj7ty51NfX73as\no6Mj++tAIEAgEBhRgeWUCYOGBnjySYWBVJ+8gWBZFqlUCoD+/n5qa2uH/Fw0GmXZsmVDHssNBDdb\nt848ELWhQUuLUr3ynvatra3ZeYFkMklzczNghhIZK1eupL29HcCzk4rr1pkgmDUL1qxRGEj1ynvq\nNzQ0AOZCtywrOyRoamoCIBKJcP311zN16lR8Ph81NTUlLrf4MmEwZ46ZM9DzDKSaVfXNTblhoM5A\npIp3Kq5bZ25UWrBAYSCSUZUdgjoDkaFV3aXQ26swENmTqroc1q0zDzc55RSFgchQqmbIkBkmzJ0L\nTz+tMBAZSlVcFgoDkeGp+Eujt9cMExobFQYihVT05bFunZk8nD8fnnpKYSBSSMXOIWiYIDJyFRkI\n69aZZxkcf7zCQGQkKu5SWbfOPMugvl5hIDJSFXW5ZIYJs2fD6tUKA5GRqpghQ2+veRjqzJnadCQy\nWhVx2fT2mtWExkaFgchYeL5DyISBVhNExs7TgZAZJmg1QaQ4PHsJ9fZqaVGk2Dx5GWWGCVpaFCku\nzw0ZNEwQKR1PXU6ZzkBhIFIanukQenvhpJPMPgOFgUhpeOKy6u0125Fnz1YYiJSS6y+t3AlEbUcW\nKS1XX17adCRSXq6dQ+jthZNPNq9X01uYRcrDlZdZpjOYOVNhIFJOrrvUcocJeiW7SHm56nJ7/XXN\nGYg4yTWXXGZpMRBQGIg4xRWTilpNEHEHxy89DRNE3MPRy6+31wSBhgki7uDYkEHDBBH3ceQy1DBB\nxJ3K3iH09prXsc+aBdGowkDETQpejuFwmGg0SigUGtXxXJlhwrHHujcMnnzySadLGBGv1Qveq9lr\n9cLoa857ScZiMQCCwSAA8Xh8RMdzeWXOwGv/8b1WL3ivZq/VCyUKhK6uLiZMmACA3+8nEomM6HhG\nby8sXGg2Hrk5DESqXd5LM51O4/P5sl/39fWN6Dh81hlMmaJ7E0Tcbu9CHyg051jo+IwZNQA8+yyM\nGzeCyhx08803O13CiHitXvBezV6rF6Cjo2PEfyZvIFiWRSqVAqC/v5/a2toRHXfiVfAiMnp5G/jW\n1lYSiQQAyWSS5uZmwAwV8h0XEW/KGwgNDQ0ARKNRLMuivr4egKamprzHpTSGu8Tb2dlZporELZYu\nXbrHYyPZGlC0jUnhcBjLskgkErS1tY34uBMK1ZT5AW7atInly5eXu7xBYrEYyWSSlpYWQqEQjY2N\n2UDOFYlEWLFiBY8//rgDVe6u0M848++VSqU8c1647VxeuXIlK1asYOPGjbsdG+55k1GUOf9i7lco\nl0I1RaNRmpqaaGtrI5FIEI1Gy15jruEu8dbU1JSzrLyG8999+fLltLS0kE6nPXFexONx/H4/wWAQ\nv9/vipoXL16M3+8f8thwz5uMogRCsfYrlFOhmhKJRPb3/H5/dq7EKcNZ4o3H49kT2Q0K/Yy7u7uZ\nN28eAO3t7Xn/5iqX4ZyrmfY8kUi4ouZ8hnPe5CpKIBRjv0K5Faqpra0t2w7GYrHsieukQqO7zIqP\nWxT6Gff09NDX10c8HnfNvEehmhsaGqirq8Pn8w36nJuNZFagaNuExrpfwQnDqSkWizF37lzHJ0wL\nLfG6rTvIKPQznjhxYvZv2XA4XI6SCspXczqdZurUqYRCIdra2kgmk2WsbOQKnTe7KkogjHW/ghOG\nW1M0GmXZsmXlLG1IhZaAE4kE4XCYlStXkkqlXDG2LfQzrq2tpa6uLvvZl156qew17qpQzaFQiCVL\nltDS0sKf//xnuru7nSizoNFuDShKIHhxv0KhmsHM3ra3twM4PqlYaAm4paWFlpYWampq2LFjhysm\nFwv9jC+88MLs8XQ6zfz5850pNMdwzovx48cDZuLRsqzyF7mL7u5uenp6WLVqVfb3Rrs1oGjLjqFQ\nKDv5lhl7NzY20tPTs8fjTstXcyQSYdGiRfh8PlKpFN3d3SxcuNDhir1nOOeFz+ejp6fHFZ0YFK65\ns7MTv9/vqqXSYinpA1JExFt076GIZCkQRCRLgSAiWQoEEclSIIhIlgJBRLL+H6yk3Q+5wb9JAAAA\nAElFTkSuQmCC\n", "text": "" }, { "output_type": "pyout", "prompt_number": 8, "text": "" } ], "prompt_number": 8 }, { "cell_type": "markdown", "metadata": {}, "source": "Compute and plot the asymptotic series expansion at $x=\\infty$" }, { "cell_type": "code", "collapsed": false, "input": "# Series expansion at infinity is not implemented yet\n#ats = series(fresnels(x), x, oo)\n#atc = series(fresnelc(x), x, oo)", "language": "python", "metadata": {}, "outputs": [], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": "# However we can use the well known values\nats = Rational(1,2) - cos(pi*x**2/2)/(pi*x)\natc = Rational(1,2) + sin(pi*x**2/2)/(pi*x)", "language": "python", "metadata": {}, "outputs": [], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": "figsize(4,4)\nplot(fresnels(x), ats, (x, 6, 8))\nplot(fresnelc(x), atc, (x, 6, 8))", "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD0CAYAAACy5jtNAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztnXtQXNd9x7+LQDyEYFneT8EKJEdybLAsPxInwQLFSZM0\nqVGrGWfazKRlnHQy6WRiVW7TadVpMnWsyUwe00zHO/2jkz5lbV5t4tRiHSdOY6fCEFt+SAIWxPu1\nyy4gQCC4/eNw2GW5e/fec37ngs39zGjEPu+5e+/vnN/7uDRN0+Dg4PCuJm27B+Dg4KAeR9AdHHYB\njqA7OOwCHEF3cNgFOIK+w/H7/QgEAvD5fLqvnz17FgA2vd7V1QW/35/0Mw67D0fQdzBdXV0AgJaW\nFgBAd3f3lvf4fD40NDTg4MGDG8899dRTaGtrQyQS0f2Mw+7DEfQdzIULF1BQUAAA8Hq96Ojo2PIe\nn8+Hnp4enDhxAgBw8eJFHD9+HABw5swZNDU12Tdghx2LI+g7mEgkAo/Hs/E4FApteU84HEYgEMD5\n8+cBAJcvX0YoFEJ3d/fGcw4O6ds9AAdjUuUztbe3AwAuXbqEQCAAl8uFoqIiNDU1oaOjA36/H21t\nbRvvd7lc+Ju/+ZuNx83NzWhublYydoedgyPoOxi3241wOAwAmJmZQWFh4abXfT4fPB4P2traUFhY\niGAwiMLCQtTV1W18/vLly5sEHQDOnTtny/gddg6O6r6DOX36NILBIACgv78fJ0+eBMBUeoDZ7a2t\nrQCYWn/8+HGcOnVq4zORSAT33XffNozcYafhCPoOhjvSAoEA3G43GhsbAWBDuFtaWjbU86KiIjQ2\nNqKurg5utxt+vx/hcBiPPvroto3fYefgcopadhculyul3e/w7sNZ0R0cdgGOoDs47AIcQXdw2AU4\ngu7gsAtwBN3BYRfgCLqDwy7AEXQHh12AI+gODrsAR9AdHHYBjqA7OOwCHEF3cNgFbJugaxrwne8A\nP/nJdo3AwWH3sG316P/wD8Bf/iWwZw/wm98Ahw9v10gcHN79bFv12l13Ae99L3DtGnDHHcC//Mt2\njGL34VSv7U62RdBv3QJycoDLl4Ef/Qj43veA9V4JDopxBH13si02+n/9F5CRAdxzD/CHfwiEQsDS\n0naMxMFhd7Btgl5Rwf6urwcWFoBLl7ZjJDH+7M+A970PGB3d3nE4OKhgWwT97beBY8dij0tLgf/5\nn+0YCaO7G/jnfwZGRoAvfGH7xuHgoIptEfQbN4D77489vu8+oKdnO0bC+Na3gMJC4IknmN/AweHd\nhu2CvrYGTE8D6xuLAADq6oArV+weSYznnwc+8hHgj/+Yqe7Xr2/fWBwcVGC7oA8OMmG/++7Ycw88\nAKy3L7cdTWMTz2OPsUhAaSnwH/+xPWNZWgJOngSefHJ7ju/w7sV2QX/pJSAriyXKcJqbgbQ0Fnaz\nm85ONp73vY89PnwY+PWv7R8HAPzFX7DxfPObzG/g4ECF7YLe3Q1UVm5+rriYCfnrr9s9Gqa279kD\nuFzs8V13Af399o8DAL7/feCzn2WTzdNPb88YHN6d2C7o164B6xuEboIn0NjNb3/LQnychx7anhDb\nwkLM63/iBFvZt4OlJWBgYHuO7aAO2wV9YIA53xLxeLbHIffGG4DXG3v88MPA/DywvGzvOH74QyA7\nm/02p06xTEG7E9iWloCGBpbI9Oab9h7bQS22C/rUlH4BS03N9qwkMzPsxuYUFQF79wKvvGLvOF54\nAaiqYn8/+CCQnw90ddk7hvPngZUVJuxxG646vAuwXdBnZ5kdnEhNzfaozOEwi+PHU1hovxnx6qsx\nEyItja3mzz9v7xj8fhYB+cQnmEljN5oG3L5t/3F3A7YK+toac7rFZ8VxvF5gbMzO0TC7eGUFOH58\n8/NuN8ves5PJyc1JRIcOMcel3+9HIBCAz+fT/dzZs2cBQPf18+fPWxpDTw/Q1gb80R8BfX3AzZuW\nPi7F6ipw9Chw4IC9x90t2Cro4+Ps/9rara+95z3A3Jydo2EOr8xMIDd38/MlJcDVq/aOZXoaeP/7\nY49raoCudd29paUFANCtE3Pz+XxoaGjAwYMHNz3f0dGBSxYKCKamgMVF4FOfYsfetw/47/8WOBFB\nvvtdpl2lpwN/+7f2HXe3YKugX7nCLmSazlHvusv+OHp3NxP0RA4etFe7iESY8+/BB2PP3XUXMD5+\nAQXrIQqv14uOjo4tn/X5fOjp6cGJ+FRDsHJUKzz3HLB/P/sHMPPlhResnYcM//qvLInq5El7jwuw\na233ImM3tgr6W2+xMJoehw8zG21mxr7x9PayTLhEjh5lq5tdvPwy+12ysmLPHTsGLC5G4PF4Np4L\nhUJbPhsOhxEIBDap6d3d3RtagFl+9avNYc+77rJXq7l6FXj0URZxsNM/8NprTJs8duzd7R+wVdB7\nepj9q0dGBlvt33jDvvFcv64f0z96lKmydvHqq1vNhwcfZD6N5WXjGFt7eztaWloQCoUQCAQAMOG3\nyltvbY6G1NfbV2gUjbJ/p06xFT0jw77w3t/9Xcxs/N737DnmdmC7jV5Tk/z1zEyWUGMXY2OxkFY8\njY1sdl9bs2ccV69unXAKCoA9e9zo7GRCOzMzg8LCwk3v8fl88Pv9AIDCwkIEg0Gh1Rxgoc077og9\nfuAB+9TZn/2MhRMLC1mWYnY2MyXs4KWXgI9/nJ37hQv2HHNhAfj0p+31gdjaHHJyksWpk5Gby7y9\ndjE1BTzyyNbnS0rY/319LKasmvFx/SSijIzTeOWVTvzpn7agv78fJ0+eBABEIhG43W54vV7ce++9\nAJha39raimAwiGAwiFAohHA4jO7ubjQ1NW363nPnzm383dzcjObmZiwuAvFve+gh5v1eXd1cl6CC\nX/1qs0ZTXs4ahqpmcZHdA5/5DPMP2bWiP/446378/PPAxIS+z4oaWwV9eBi4887kr7vdrLrNLhYW\n9JN3XC7mlHrtNXsEfWwM+MAHtj7v8TRhfLwTgUAAbrcbjY2NAIDW1lZ0dnaipaVlY0UvKipCU1PT\nhlD7fD5Eo1Fdp1y8oHNmZjaH93g9wrVrwJEjcueXitdf3zzRHTnC7hXV/PSnTHuoqgJ+7/eAr36V\n+Yks+jEt89xzwJe+xIqXnnsO+NjH1B4PsFnQZ2dZnDQZRUX2Js3MzyefeHJy7LNRx8b0Q47l5cC+\nfe1oacEmdbwzLhG+ra1N9zvb29vR3t5u6vjDw2xVSZz0srPZyqpa0EdGgA9/OPb46FHg5z9Xe0yA\nHYM7YxsbmYC/9hr7WxUTE2xS/eIXWUu1H//YHkG31UZfWDBeISsq7HOC3brFbPBkN3FOjn2daW/e\n1B9Haak9K1tnJ1PPE1XI0lJ7nKMTE0y4OceOsUVBNa+9FvMZuVxAXh7w4otqj/mDHwBlZcwHc+gQ\ni7jYga2CvrJivFFDdbV94bW+vtjF1aOoyB4h0zQWQ9dLCz5wgCXSqObKlVj8PJ79++2Z7BYWNpsN\nDz7InKGqw11TU5tX76Ii9X0AXnwx9lt/6EP2lUTbJuiLi2wFjS8JTcTrZc4fO7h6lYVxklFezlYa\n1fDEHD2Tpr7enomvr08/n6CqSv1kFwqxCTe+41BREQu1vvaa2mMPDbFNRDher/rcgaGhWMr1Rz7C\n5MKO+L1tgt7Tw1TD7Ozk7/F67Wsp1dubPHkHYCpdJKJ+HK+/zjzOeg6gw4ftyRYcGGChrUQaGtT/\nBl1d7NwTJ92MDLWJM5rGhCw+G/HIEfUa1NWrTGUH2OSuafYkCNkm6L29xisowGKZKyv2jOfGjeRq\nO8CcY3Zkx12/nnzyO3qU1YirrksPhzfX5HNqa9X7TK5cYXn1iZSVqc2pGBpisfv43IGjR9UvNC7X\n5snF67WnJNo2Qe/v35ziqQdPXrEjUWN4mDW7SEZdnT1qczDI6t/1qK5m/+tkvpIyMbG1vRfANIqF\nBbXHDgaZUCeSm6s26tHVxc4t3gHZ1KTWCbi4yK7lAw/Enltbs6fvgG2CPjSk7/CJJyOD/fC9verH\nMz2tf4NxGhrs6TJjNOHs2cP+qS6ZnZ+PqZPxHD3KNCyVGkVfn75mVV2ttrDojTe2ph2/971M8KJR\nNce8fJmda/xxq6rsud9tE/TRUaYqpSIjwx5P7+SksaDX18c84ioZH2fNMZORlaU+LXh5meV7J1Jd\nzSbeyUl1x56e1k+LrqpS6wwdGIhtC8bZu5eZUapWWD2P/h132OMLsk3Qo1H9vPJEsrLsaSmVajzZ\n2cyeUp2SOz9vnP+vOi14ZYV5ffUE3eVigq6ywGRsLGaixHPwoFo1urdXv6ApO5sV+KhAr6ahro5p\nu6qxdUVPpboD7Ma248QXFvSz0eLJyFCfHTcxoR/a4qhe2Xp7mXmQ7NpkZan9DRYW9EOuDQ1sElTF\n5KT+BJudrU6VHh7eurjceac9HXVsXdGNVGVOfn6sE41Kbt/WLySJx47suPl547TgjAy1sexr14yL\nVnJz1f4Gc3P62ZJHjqiNL4dC+r+7x6Ou3mJycqug33038wuojqzYJujz8/qe3UQ8HvWJKprG4tN6\nDqh4cnLUJ4wsLTE1NRklJWpDXH19xrkNpaXqrgdvBqmX/uv1qnWMLS7q/+5lZeqcgENDW2Wgqool\nid24oeaYHFsz44xsUU5xsfpwEnd+lJcbvy8vT22RDb/RjSacsjJ1NzvAbjAjkyo3V90KNzXFfAB6\nC0B6OvunKlMtWX1BVZU656Oe9uJyMSeg6kYbtgn68nJqVRlgN7bqOHpfH7vBUtVZl5WpdQjxCUfP\nGcWpqlI7hokJ4x4BpaXqJt6332Y3erKy0PR0NfYybyqiJ+g1Neom1mTRjexs9ZEVWwR9dZVdTL3s\nq0RU39gAE/RkSSrx5OWxEkpV9PamnnBqatQmrYyNGYc9KyrUJQ719hprEzk5aiIwPEtTL35/8KAa\n59jaWnIzpaREvQPaFkEPhZiwG60cnMpK9amnw8P6oZVESkrUqs3BYOq04IMH1cbyw2Fjr391tToN\na2DAeMLdv1+NAFy/nlyLUFVfMDzMhF1PBlRNaPHYIugDA+ZUZYCFvFQnqfBGC6moqFBrRgwOGjvC\nAGbTra6q88pGIsa+CpXXY3jYuN6goECNYywYTK5J3HEHE0jqKspr15gpojfBlJSod0DbIuj9/alX\nLo4dparj48Y3GKeqSq12MTy8NQ0zkZISdnOochDdvGnsI/B6WWRABeHw1uy0eIqK1EQcBgeT113w\n+4I62tLbm/yYVVVqNUfAJkEfGkq9cnH4hVe5kk5NJW87HU9trdoy0VDIWG0GYtlpqmLZa2vGTtL6\nevYeFR1xR0eNJ7rSUjXVZCMjxtc/PZ2p95QMDCQ/14oK9eWxtgj66Kh+KaIee/awm1tlk8iZGf36\n60S8XrVJG6Oj5ibArCx1gj4/b5whyB11KsKMMzPGE11lpZqVLho11iRU/N7Dw8knFzv2m7NF0MfH\nzaW/ctLT1SYQRKOxls5GcJVWlfpudsLZu1eN9391NXXXH5eLTb4qwlyzs8bZkgcOqEmDHR01Nt32\n7aO//8bHk1/rgwfVNxixRdCnp815uTl796rNSFtbM57R48ehspouGk2tugPsxlPhlOKrdCp/RV6e\nmol3cdHYP1BXp8Zfk+p3Ly6m94nMzSVPGDt0iGmOKtNgbRH0ubnUWWjxZGerzUhLVYueiCrtYn7e\n3O+yf78ar2wwaC4SkpamxpS6dcs4W9LrVdNxaH7euHIxJ4deg4pGk5cj88xAlRmhtq3oZrzcnH37\n1IYbbt0yVzILqM13X1gwl//vdqtx1gwM6O8mm0hurpqJN1Vh0YED7D3U4b2FBeMJprCQ/veemko+\nqbtc7DqoLEe2RdDn582pqJz9+9V6IVdWzOXdA0x1V6Vd3LplXLnGKShQ4302E8cHmEOOWpVdXmaq\nqpGg83AU9eq6smKcpVlaSt8MYmnJ2ExxudQmzdgi6JpmTXV3u9WpMTz5xIyAAUy7UBXDXl01l/9f\nXKzG+5wqvMVRkSHIM95STTTp6bQCoGnsn5Ggl5fTh3eXl42jG1lZatNgbRH0VNlXiXg86vKruaZg\n1jmYm6smaYN3dzWjWZSVqfE+R6PmTAcVK3owyIQ4FXv30voHQiHmjDWKulRX09YXaBqb1I3Kkfft\nU1tXYYugr6wYqy2JFBWpS5gZHGTOJbMb6eXnq1Ob09LM2cgVFWoKW0ZHzTnjiovpC41u3DB37llZ\ntKZTf3/q63/gAG2CEF+0jMzXvDy1finlgq5p7EczaxMDbLZV1UZocNB8Oi7AtAsVzfu4oJuhqkpN\nnDUSMW55zSkro0/oMJstuW8fbcehVIU0ABN0yomVl0UbTS5ut9oGI8oFna/MVpxx5eXqklRGRsyt\nJJzCQjVls8PD5kplAXbjqQgzzc2ZqyisqKC/HmNj5pKoqEOLg4Opr39tbawpCAVGvfs5RUXv8PDa\n0BCbyczYY5zKSnWZQmNj5vPuAXXaxfi4OT+B3+/H0FAAa2s+3YSKs2fPAmD7oXN8Ph98Ph+efPJJ\nw+++edNchmBVFX0yx9SUufbf+fm0AmAmHZu/TmUzj4ykPlfVJdHKBX1w0JqQA0zNV7U108SEOU8z\np7RUjXYxNpbaT9C13mD8k59ke6O/8MLWxuA+nw8NDQ04uO7pCQQCaG1tRXt7O4LBIAKBQNLvX1w0\n5yQ9cID+N5ieNldYRO2YnZgwl9NB2XZ8eDi1DJSXq+16q1zQR0fNq6gc7gxRUTFlNXmnokKNdjE9\nnXrCuXDhAgoKCtbzzb344Q87trzH5/Ohp6cHJ06cAAAEg0F0dLD3eb1eBA3yd2/dMpcKXF0d8xxT\nEYmYMxuoQ4vT0+Y0CZeLLlHKzLlWV6stz7ZF0FPtuZYIdxCpCLGFw9by7quq1DReCIdTTziRSASe\n9R8jLQ0YHt6qw4bDYQQCAZw/fx4A0N7ejvb2dgBMIzjO9+jVwWw0hE9IlLby/LzxDjWc0lLalS4c\nNueAzMyk8/aPjqb2C6huoWZRqbbO5KTx9sR68E4cw8PmqrusEI3qN+hLRk1NTLsw6yU3QyRiTnXV\n1o3jjAz9kCMX6kuXLiEQCKClhan5XV1dOHbsGBobG7d85ty5cwDYOY2MNANoNhwDr2AbHDSnAZjB\nrKBThxaXl83VOeTk0Hn7Z2ZSLy7UIb1ElK/oU1PWbGJORoaaYpLZWXM3GIerXNSz7exs6pXF7XYj\nvB7Ez8ycwdra5lnP5/PB7/cDAAoLCzep6YFAAH//93+v+73nzp3Dl798DsA5fPKTzabGm55Om7m1\ntGTOP0AdWpyaMqfRUSZKzc6mXrBqa5nqrkp9Vy7o4bC5lSuR3Fw1pZk3b1qrXOPaCPXuMfPzqe22\n06dPbwhvWlo/8vNPAmAqPcBs8NbWVgBAKBTaUNOfeeYZnDlzBgCSOuNu3Ih1rzEDpSoLsJXVjHZA\n7ZhdWDB3/fPy6Oot5uZSRze4p19V0oxyQZ+ZERP0PXvUFJMsL1tLx+WVRdQVbGZCW01NTQCYsObk\nuKFpTA3nwt3S0oKOjg74/X4UFRWhsbERHR0dePLJJ1FfXw+PxwNXEte+1WgIpSoLsBi1mQrC2lra\nLYvMOiALCuh8RAsL5vJI9uxRVxKt3EafnbVmE3NyctQUkywtmS9R5aSl0ech37plbmXhNrjX27Jx\n43V2dm683tbWtun9ra2tG+q+EcPD1hKHKIt7rGRLcpU3HKbx1ywvm98ajOqaLy2Zm1wyMph59OCD\nNMeNR/mKbtbpkoiqUtXbt63l3QNMIKjNCLOqK6eggDbMND5uLRpCeT14SrEZweXmBVVMe3XVXOVi\ncTFdvcXKirnFhdo8ike5oK+sWLOJOSqKSbgKaCXvHlCjXZhVXTmFhbSFPhMT1qIhbjedKjs4aLwV\nUyJUjlkeJjWzopeW0nn7b99OvUU3wDI2VW3waMuKbiXPneN20xeT8BXJSqNKgKmtlNoFV13N1sQD\nzJ6nLCyZmrL2O1AW95jJFIuHykcyMsLsYDMJXFT5/bwnvhm/UG6uut4HtqzoZmbQRKhXMMBaxVg8\neXm0+dZcYKw4KalTccNhcxliHMrS4ZERa9mS+fk0jkAr4cHKShpvP1+hzdRXUHr6E1Eu6Kur1m1i\ngNlI1Lm/VlcSTn4+rXYhMuFQF/rMzJjLEOOUltJpFOPj1gqLMjJowk4jI+ZLlGtqaKrXBgfNT2qU\n5lEiSgWdt7AVWdFVFJOYSUXUg9oRNjRkfcKprKTdTMJsiSqnrIxuayar/gEqx9j4uPnrf+AATX7/\n8LC55h4Am3hVVbApFXSubllNgQWYTUNdTGJ1JeEUFdFqFyKFPtRFD6ur1pyklKWqoZC1bMnMTJoV\nfWLC/PWnSpQaGzM/uZSVqavaVCroQ0OxLZasQmUjxSOSdw8wRxhlvvXEhPVCH+7QpBpHOGwt7FlZ\nSXfsUMhaBWFBAU0K8tSU+a3BAJoEFiuTS2GhuuYTSgV9ZETMJgbYCka975mZ0lA9qM0Iq6orwGxL\nl4su3/zWLWvREF7cQ0EkYq2CkMoxa1WT4AksMli558rL1e31p1TQragtiXC7nrJE1KqnOX4slOMQ\nnXD27KETdLNJHBzK4p65OWuOwKIiGkdgJGLt+lP0qwuFzIcxy8vVNAEFbLDRraqoHK7uUCYQRKPW\nVhJORQXtTDszIzbhUG62aDUawhNcKCYaq9mSJSU0GlU0ai2kmZEhf/9ZudbU91k8SgXdqk2USHY2\nbZL/6qpY8k5VFW3HG9FCH6pUXB4NsZrzn55Ok7hitsiDU1ZGo1HNzVnLl6dIlIpGzWsv1dXqatKV\nCvrsrNgNzdE02oops7XIifCbgyr0YVV15VRW0sTzeT61Vc9/RgaNRnHrlrUKQirH7M2b1jQJivx+\nK2FM/j4VveOUCvrkpNyKvncvreq+sGCu62kimZlMbaUai2ihz8oKjaANDpqP7caTlUUz8ZqtIONU\nVtKEFhcXrWkSFIlSCwvmrzWPUKnYmkmpoFu1iRLJzqYtxLfqaY5nzx46+1h0wtm/n6bQx0qGWDxU\nxT1W/QOVlUy7k13VzZYGc9xueS1ucdHaMVX1YVAq6KIqKmffPtrdK1ZWxHueUTrCzLZRSoSq0Ec0\nGpKbK6/K8k0urQg6D0XKTjK3b1vTJCjy+62WI1OZR4koFfSbN+WaBeTm0iYQrK5ad0BxKGvSRScc\nt5smvCWSsAMw/4as/ch/Q6t5BGlp8iqt1etPEdazmgKelaWmnZRSQbdqEyWSn0+X5C+Tdw/Q1qSv\nrYmNg6qCTDQaQlFGKeofkF3pRCINZWXyYb3lZWv9D7Ky1JSqKhV0qzZRIpTFJNwEEElUAehq0nmh\nhJVadA5VKq6VJI54KFJRrew5F4+sY5Z/1orJUl4u1+KbXysr/hhV23QrFXSrjRgT8XjoaqCHh61t\nl5wIVU06nyxEJhyqCjLRhJ3CQnnVfXxczBEou9LxugsrVFbKTWx830Erk0VurpptupUKuoxNDNCl\nPgJyefcAnSNsaEh8laCq6FteFvP6U2gUohWEOTlyK93oqPXrX1UlF9bjHW2sQN37gKNM0FdW5Gxi\ngLaYZGxMTGXkUFVQyUw4VVU0KZKTk2Kqe2mpvEYh4x+QMZ1EIg1cGxXNyrPaSQeg733AUSboXP0Q\nuaE4lDXpop5mDlVNukgtOoenSMrWhVtJ4oiH4npYrSDjyK50VspFOXxiEE0SstLoguPxvMMy40ZG\nmIoq48ygLNsTrUXnUDVnFFVdgZhwyt4Ii4tiqjtFlxtR/4CsoItef5mKwclJ69e6uFhNBZsyQRft\nzxYPVd8uQHwl4ZSXi4WFEhG5+BzuTBwclBuDaIYghUYh6h+QdcyGw+J7AIpmqk1PWzdTVLRQAxQK\nuqxNDNClPgLiteicsjKamL5oaItDUUEm2pmXF13IaDai/gFZx6xMabBoWE/kWpeW0rdQAxQK+sSE\neNMJDl/5KAopolE5QadyhM3MWGujlIjMCsNZXRUTdL6dtUziys2b1ppScmRVWtG6C5l6C6uNLgA1\nLdQAhYI+NSVnE3P27KGpgZbNu+dqq2y9sNl90ZNBUUEmEw2R7XIjmi1ZVia30pnZulgPmbCeSKMT\n2ZBeMoQE/cUXX0z5HtF2SYmkp9Mk+d+8aU7Qk50b/6xsiM3Mvujx+P1+BAIB+Hw+AGyFiU8cOXv2\nLABsvK73GT1EJ2FZjcJqLTqnosJcmCvZ9RPVJGQqBufnrU8ufAJOpj2akT09lAl6OCynonKoiknM\nloYmOzeutsoWVpjZF53T1dUFgG2PDADd3d1b4sk+nw8NDQ04ePBg0s8kIpMhKFt0IVrQU1FhLoKT\n7PqJRhry8sQF3WqjCyBm7iabTG0VdDPI2sQcqmqepSW5AhuAxhG2uGj+4l+4cAEF67qf1+tFR0fH\nllRcn8+Hnp4enDhxIulnEhFJQeUkahRWEd25p7qaaQOippNopEGmJn1pSWxyoTJX41Em6FZV1GRQ\n7cu9siKXdw8wdVfWjLBSix6JROCJ+xFDodCWeHI4HEYgEMD58+eTfiYRGUEvLhaPPoj2qgNifg3R\nWLrLZf8egKJmSlYWfU26S9OsR0Vdonqfg4ODNAIiK7aia5qW8l9RkYZz51K/L9W/hx7S8PDDct+x\ntqYB0DA5Kfc9VVUavvhFue9wuTRcuWLuvWfPnkVHRwc0TcOzzz6Lp59+Gp//vIYDB9jrzzzzDC5e\nvAhN0/D000/jmWee0f1M/HcCQE2N+PgffphdE5HP/u//atizR/zYGRkafvpT659bXWXXf37e+me/\n/nUNBQVi4wU0DAxY/1xJiYavfMXoe62jTHVfWpKrRedQJPlz1UvWlJAtrNA0a22UTp8+jWAwCADo\n7+/HyZMnUVICzM8z/dXr9aK1tRUAU9GPHz+u+xm98xBFprhHtoJw714xjz8Pj4kU04iWBvMIgYjq\nTt1CDTAh6F1dXfD7/UlDNclCObK16ByKmvThYWaj6aWwpjq/+PCVjAcWiH3WbDSiqakJABAIBOB2\nu9HY2Lhd38b0AAAduElEQVSeoceEu6WlBR0dHfD7/SgqKkJjY+PGZ/7xH/8Rf/7nf45Tp06hvr4e\nn/vc5za+lx/fTBguERmbVaTII57MzFgOQVdXF9LS0lBfX7/l/Dj82n372z7hmouKCrEEFtGW2gAT\n9HA49fWxcv1Snv5TTz2FtrY2RCKRLaEao1DO7dvijRjjodgn3agu2Oj8gM3hK9nCCl6LbsXF0d7e\njpaWFrS3twNgv2l6eufG621tbWhra8MTTzyx6TMNDQ3QNA29vb149tln8eSTT2687nabC8PpUVQk\nnqEmW0EYn7wyMzODtbU13fPj8GuXmXlQqjRYJIHFynbJieTnA4OD3fB6vWhpaYHX67Uke3oYCvrF\nixdx/PhxAMCZM2c2VgtOslAOzyCTaTrBodiOZ3RU39Oc6vyAzeErj0cuYYai0MdsBRm/AQCgs7MT\ntbW1G489HnNhOD1krodsn//4dl5G58fh1664+IRw3UVFhVi9hWhLbYAJ+vx8TCMJBoOmZS8ZhoLe\n2dmJUCiE7u7ujfBNPMlCOVwYZDrAcihqoJOtJKnOD9gcvpJtpURR6GN1V9NAIIA/+IM/2PRcYaG5\nMJweMtdDtoJQL0tN7/w4/Np9//vnhTWJ3FymgVltIyazwWhhIXD7dhPq6urg8Xg2XSeO1euXUnUv\nKiramE38fv+W1/W8gKOj7MeRiddyRG2keIyaDqQ6P646h0IhzM8HpAorZDad5PDJ06xmcenSJeQn\nZC7xhB0RD67MRoCiFWSc/Pytjlm98+PEX7u0tIDQMbmpZTUjUqTRBYf5QSKor6+Hz+dDe3s7+vv7\nt7zPyvUzFPTCwkLU1dUBANxuNy5fvrzpdbfbjfD6FDszM4PC9btwdJSmdhtgHmrZJP9QSF9lTHV+\nPp9vQ/gLCwuxthaUaqUk2/wCsH7jcVsuntLS5NcuFdxmFYnyiO5my9Hz+OudH7D52q2tFSI9PSh8\nXJF6C5mirpISIBLx4fHHH0dbWxueffZZXLx4cdN7rF4/Q0E/derURqgmEongvvvu2/gb0A//AGK9\nspJRVcVuKpkS0WQqY6rzSwxfHTt2XGpXT1nVlZOebk7Q+bklUl6e/NqlgodMRSY82QrCRI+/3vnp\nXbtoNITCwuPCx83MtB7Wk+k7UFbG7ve89fBIS0sL3OupgalkLxmGgl5XVwe32w2/349QKIRHH30U\nADZ+QL3wDyAfRomHqz8y+e7J8u5TnV9i+OqDH2yUmnCoCn3MVpC5XK6NYpd4KiuTX7tUcNNDpFRW\ndHNJTmIXWr3z07t2t28XobLS3PnpIVIaHImIX2sWlj6D8+fPb4R+edQllewlRVPAl7+saRUVdN+3\nZ4+mvfyy+OfvukvTPvUp+XFMTLCUl9VVsc/ff7+mPfKI/Dg8Hk372tesf25tjaVrTU7KHX/PHk37\n5S+tf87t1rSnnxY/7re/rWn791v/3B13aNpjj4kft7ZW0z73OWufaWrStN/9XbHjXbmiaS6X2GeT\noSQzTrSlbzJka9JF6oL14PalaKYeVaGP6PZQ3L6VHYNoTbpokQfHbE16IlZKg/UQyYiUMVOqq2NZ\nlFQoEfRwWK4vWiIiNlI8ok0HEsnIkGulJHvDcURTcfm4ZR2lon3UZHazBcS70FopDdZDZA9AmXuO\nm5lU+w4CigRdpFeWEbI16RS16ByZfdJXV2nGIdr1hKrGWbQmXXbnnspKsQiMbN2FyC49shuMpqXJ\nd/vd9H10XxVjdlYujJKIbJK/7GaP8cjskz47SyPobrfYbE+17bNIHzWZWnQO/+1EMvPs3gNQ1kyh\nbj6hRNBlwyiJyO6TLqsyxiPTnPHWLZpxiKbiUgn6/v3WrwfXyGTyCHjI1qoZt7AgN8EUF1tvNS3b\n6ER299hElAi66JY/yZDdJ11WZYxHppWSaJvlRERTcSlacgEsbGT1esgUecSTk2MtS407tazsUZ5I\naan1Qh7RllmcggLaUlUlgi5rnyQi07dLpi5YD5n9q9fWxPZFT0R0V1OKbZ8BsR4BsrXoHE2zZjrx\nCUmmxbbVVtPcTJGZ1F2ud8CKvrxMZxMDbAUTrRrjq5ho3nEi+/eLaRcUNxynvFwsM41K0EVs1tFR\nmiSqvXutmU4ipcGJVFZaC+vx8cmYKbLmaiJKBF10y59kyGzHwzd7pGpzJ7pP+uCg3IaT8ZSXi8WT\nqfbdFrkesrXonJwc64IuazJYrUkfHJQ/pmyTk0TIBV3T6GxRjszGczJ1wXp4PGJmBEUtOkc0nkyx\nvzsgVpNOlUQVX5NuBso9AM3+5hT3nGhkJRnkgs5vAEobXbRvF8Bmf6oCG0DcEUZZ6GO1Jp0j25KL\nI1KTTrVzj1WPP0VpMJ+gzDphR0flr7Vsk5NEyAWd2iYG5Daeo1IZOaKb/VGOg4curWoWVPtul5db\nvx6ytegcq+28KEqDXS5mdpmNa8vUonOKiuRbqMVDLug8jELZ+l1m47lwmCbtlCOqXUxM0Gw6CYg3\nQ5CppY9HZGdZqp17PB5rgk5VGpyRYV7QZVtmAfT7pJML+tgYnS3K4TXpIsI+MUHXBAMQd4RR3XAc\nke2hZGrp4xGpSZ+boykssmo6UZUGW2k1LVOLzpExV/VQIuhUtegcvhKKJHzI7keeSFWVmBlBdcNx\nRHqcU+27zVdmK/kEVAU95eXW/BNUdRdW9kmfmZEPo4pW6iVDiY1OaRNzRPfljkZpYtcc3hXUquoq\nuy96IllZ1hMqZPd253Cb1UrRBVUSVXGxtbDTdpQGU9xz1dVyXZUSIRf06WnaWnSOaE061YXmiDrC\nqMdhNRWX0rEDWLNZAbrCospKax5/qjoHK97+2Vl57YWbq1STM7mgU9gneojWpIvsUW1EVhZb0aya\nEbJtlBKxWpM+OEjrILV6PZaXaXIramqsrXQzMzQTrJX8fop7jpsbMluAxUMu6NQ2MUe0Jv32bdqY\nPiBmRlAX+ljNnKLKNedYsVkBusKi2lq2ypntvrK4SLcHoFlvP8UxuXl044bc93DIBZ3aJuaI1qTP\nzdHm3QNMbbVqRlDWxAPWU3GHh+nCewDTKMyaDrw9tEw1F4evzmYnuZUVmuNa2XOOqhw5I0PML6UH\nuaDLFtwnQ7R90vIyXYkqR0S7EFVdk22kl9jjPH6nGb3PjI3Rhhmt2Kx8QqCYaKyudLdv0wi6lZr0\n27dp7rnMTLleifGQCzp1GIkjUgMNyNcF6yFSky5ywxltpBefOdXR0YFLly5tvEdvcz7KhB3AWi42\nryCjIj3dnMefaxJ2lwZTmSnZ2XSlqkpy3altYkCsJn15Wb59kR5Wa9K5TWlV0I020ou/8VxxXjZN\n03Q355uaonWSWqlJHx6mLSzKzDTn8edCQjHBmc3v59lsFFrtvn3iTU4Seceo7iI16RR1wXpYbc7I\nTQ6rgma0kR7PnOru7t60s+g999yjuzlfKETbsLOoyLzNSlFBFk92trlS1Rs36MwVs3sADg0x84LC\n8ZmXt4O97svL9KoyIFYDTVEXnGwsVrQLmeYHWhL3Ms+cCifMOJGI/uZ8FNla8ZSUmL8e1ElU+/aZ\n85FQahI1NeZSsCnq3zluN11NOnFWuhqbGBBL8h8aolUZOfn51ryhoqEto430WCru5tUcYJsLPv74\n48jLy4Pb7cbFixdx5swZzM4Chw+z95w7d27j/c3NzWhubrY8NivXg3pDD7Mr3fAw3XF5TfrKivE9\nNTxMp714PEBvL813kQo6t2Eom05wRJL8qdoXJWJFbeXjELn4p0+fRmdnJ1paWjZtpBeJRFBd7Yam\nBXHxYhDhcAjhcHjD8Ra/OR/fiC8+1zxe0EWx0l6Jqhad43ab8/hTmgzZ2WyyHhszbjRJue9geTlw\n9SrNd5Gq7jxTSoVwidSkU3uaOWVl1mq7RZsfJNtIr7W1dT2e3IaWlja4XC5Eo1G4XC6cOaO/Od/C\nAm0cv7ra/PWgqkXnmHUETk7SOiA1LbW3f2qKpkoPYN9D1QmWdEVXZRMDYrt0hEJqknfKy62ZETKq\nKxfUeBW9s7MTQKwmvb29feN9AHDmzJkt37O0RNfbHrDW5SYapY3EFBcDv/1t6vdNTdFOMLm5qU02\nyjJtq00pjSBf0VUUtACxjeesCDtFpw89rF4AatWVY6UmfWWFNszI03nNREKoC3pKS805Aqny3Dlm\nKvamp+kml5oauq5ApII+PEybGBEPn0CsqDLhMO3WUByzHlgOterKsVKTvroqt4lBIjyKYCZDLT2d\nVpswq1FFIrT1Bfv2pf69w2G6ycXrpStVJRXL8XE1NjEnLc2atzsapW0jxeHahVkbNRxWY0KY3R5K\nVeJQRgYwMJD6fSMjtAJnVqOam2NhQCry8lKH9WS3YoqntpZdN6uNOPUgFXRq50ciVmugqS80h5+j\nWe2Coj5ZD7fbXOaUKifp3r3mrsetW7STzIED5jSqhQXa5K2CgtS/98QE3bXeu5dpTeupEFKQCjql\nfaKH1Y3nbt5Uk45rtcMK5SaP8WRmmkscGRhQ4zvJyTFXdLG8zFYnKmprmaCnEvalJdoJpqgodX6/\n7IaOiaSn70BBV2UTc6zuZLq0pCamD1grIZyZUZf/byaePDhI16kkntzc1BMN75Li9dIdly8mZtRo\nSr9ESUnqsN7SEu2klplpzjxKBamgz87SxRD1sFIDDahLxwWslRAuLakZh8djroJseFhdRWEq84VP\nRJSmi8vFwrjruUBJWV2lFbry8tQtuVZWgLo6umOa1ZpSQSroqmxizv791gR9dZWmRFEPK3uArayo\nGYfZnPuRETVJTCUlqZtfBIO0e99xMjKMPf78d6FOEjIKd62sMA2GUtDz861psckgFXRq50ciVton\nqfI0czwec/nWKlRXTlmZuaaPExNqfCdm9vDu76etXIs/tlGoKxhkx6UM99bUGKdhc8ckpT8kP5+m\nJp1U0KmzrxIpLjbf7ID/6CpaTwPmmwJwDUSF78JsPHlqSs3xS0tTJ8wMDam5BqmaTwSD9FqE12vs\n6+jro0/QKiqiSYMlFXSVNjHAbiyz5aEDA/Q7xsTj8ZjTLgYG1KiuAPutzTjZZmZo49icqqrUGsXY\nmJrcilQq7cAA/QRz4ADT0JJl5XEzhZKKCvEtw+MhHRa18yOR8nLzJz00pMYu5VRWmhvLwIAa1RVg\ntqCZMVDnmnPMxLPHx9U4AisqjLW7oSH6nI6MDDZhJysdHRykD2NWVNA0nyATdG67qApnAWwFMZv7\nOzysVtALC81dAFWqK8BUSTMZevPzaq7LwYOpJ5poVI2fJC/PeEUfHVWXdtzXp//ayAj9pFZbu8NW\ndN62R6W6XFNjvphkbExNIQmnqsrcBVClugKxmypV+GVxUY1J1dDATAejVZ2y+UM8lZXGZtzEBG1B\nCycrK3kCy/g4vS+kvp5ms0UyQee2qEqsJPlPTKhRGTm1teYuQChE31c+nvR0c11IVJhU/Pc1ShyK\nRNQ4aKurjZt/hMNqzJWSkuQT6/w8/bkePhzrZisDmWgODqqzRTlc/TSjvk9Pq83SO3jQXFGLqi43\nnMxM4xRJTWMren29muOnpwM9Pclfn51Vo03U1RlHHCIRNaHerKzk8fvpafrJpbSUTagi25HFQybo\nIyNqar/jycw0Xxo5N6c2pm/WPp6dVZtElJNjvKLyyIAqrcJIlQWYMKrIIWhoMP7t5+fVTDDFxclT\nb6em6P0RLhdb2GRbSpEJumqbmGM2yX96Wo2NxuF2Z6p898lJtYJeXGycLdjToy68B7DfwWjiXV5W\no03U17Nc/2Tm0759aiaYmprkvoGbN9UcMzt7Bwn6xISamutEzLTzAdR5muMxYx/PzakdR3a28e/R\n16fWpMrLS16qevs2c9YdOkR/3Oxspp4n+/1HR4E77qA/bmVl8ol1ZUXNMffvT+7pNwuZoKu2iTmp\nVhCOKk9zPFlZqSuLFhbU5dsDbEU3ypwaGlJbOlxQkDzMxa+Tqh4Fe/cCb7659fmFBWZWNTTQHzOZ\nF3x5mTnNeEttSowcgGYhE/SZGbUqKic723yzA8riAj3y81NfgNu3meNOFeXlxhl6g4NqnYGlpclL\nZa9fV9NXn7Nvn/6K/vbbzFxRocm85z362YBXr7LjqTBfS0vlS1XJBD0aVev84ng8qat5eChCpYAB\nbNIxyrdeW2MzvQrVlVNZaZxvHgqpvS5GmVt9feqShQBmKur5a65dU+cvuvNOdn8l5nNcuaIuvFxb\nK78HG9nQbt5UbxMDTFVNlZEWDjM1SvXE4/EYF7Zw76xKTefAAeMw040balV3rze5c2p0VG2RU1WV\nvgBcv67OL8GdsG+/vfn5a9fUmSiHDontJBwPmaAvLtJ280hGeXnqk75+na22qhN4UtnH166xbEFV\nHm+A3QRGYSbVK/qhQ8nzGnp71WZKFhToa1Q3bqhtgOJ2A6+/vvm5vj51x7z7bvnsODJRWFlRryoD\nbBZPtR0S1X5VqUiVh6xadQWAo0eZPyJZFVs0qtYZeORIrOFCIqOj6rUZPe3uxg01zTg5e/cCb721\n+bmREXUL3bFj7BrLbOZAIuirq+xGs0PQa2tTZ8b196vbSCKesjLjFV1VU8Z4eK5AMl/B8rLa68IT\nh/QcgpOT6hp/ACyUpWe2RCJq4tmcqqqtvoGhIXWmq9vNtNP1DXqEIBH00VGmnqq0BTn19an7XA8O\nqs1zjx+L0aSjOrQFsN89I0M/zAQwQVAR2+WkpzPz5MoV/ddUhJs4R4/q+weGh9WakdXVW3MXZmfZ\neFSRlwf85jfinycR9N5e9bYox0zF1Oio2qw4zuHDxpNOKGSPgzLZ9rpc3bvzTrXHz87eqsoCbNVT\nEcvmNDbGIhvxLC6qPefa2q3hrrk5YH1PTCUUFprbby4ZJILe12dPsgwQc3gYJfmrTjvlHDpkvJPG\n4KB8tqDf70cgEIDP50v6nsxM4D//8/zG466uLvj9fnztaz64XGp3zwFYnDfZRLO+AawS8vKY1hAv\nALyI55571B23qWmzJjc/z871/vvVHfPOO+Wy40gEXUV/rmSkpTFVNTG8Ec/MjNqwDmffPuPqrVBI\nzhHW1dUFILaTKt//PJHMzA5cv35p4/FTTz2FtrY29PREsHev/mcoKShgkY54JieZ0Kn222RmbrZd\nua9CpSbx0EPMZOBa5csvM61GpT/mrrtYFEcUEkEfGrInz52TlWXsWY9G1ae/cpKprQCz22Ru9AsX\nLqBgXVXyer3o6OjQfV9RkWtDq7h48SKOHz8OAKivP4O8PIX65DqVlVuzFbu7mValahttTnn55t//\nlVdiLZ9UUVfHvp+H2F56Sb2p+MgjcuFiMmecyrhlInl5xoK+tGRPBABgoZZklUXLy3LOqEgkAk/c\nHRTSyTXt7u7Gffe1bMTSL1++jFAohO7ubvzkJ+dt0WwaGrYmrrz6Kt1OoEZUVABvvBF7fPmy+kXH\n5WKT2AsvsMe//a365KwHHzS/qaceJII+Pa22i0oiHo9x6unCglpPc+JY9GyntTVmt733vXLfr6Vo\nLRIOh3H0aGy2d7lcKCoqQlNTE6JRwOXyyw3ABE1NW/MJ3n5bbSybc/jwZsfYtWtq1XZOcTHwi1+w\nv3t6gHvvVXu8tDQ5M5Akb2lmxh7vMqe0NHkxCa9cOnLEvrHoTTq8tZbMBOh2uxFeD1DPzMygMEFt\n6u7uRktLC/LyYvHkwsJC1K1X80SjbuzffxlA26bPnTt3buPv5uZmNDc3iw8SwPvex8yUtbXYhDM8\nrDa0xnn/+4Ef/Sj2uL+fjUc1H/wg8Pzz7O+hIaC1Vf0xH3tM/LMkgj47q7bNcyJVVcCvfqX/2ptv\nsptNdbeb+LHohT26u5mjTsZWPH36NDo7O9HS0oL+/n6cPHkSAFPp3W43gsEggsEgJidDAML4xS+6\ncerUKVy8eBEAMD8fwT333Lfle+MFnYIDB5gt/tZbsbBWTw/Q1mb8OQoeeQT4zGeYuZaVxRzDX/6y\n+uM++ijwb//GHHG3bgGf+IT6Y8qcF4nqrrInmR719ck3DnjrLbVlmYkcOaI/lrfekvdbNK0HZgOB\nANxuNxrXY1Wt68tHW1sb2trakJ7uAhDFm2+6UFdXB7fbDb/fj+XlMD772UflBmECl4tNrC+9FHsu\nGlUbbuKUljKb/LnnWCx7cRH42MfUH/fhh9n/jz3GTBfV/RIBydoNjYA9ezTt7bcpvskcFy5oWmam\n/mt/9VeaVlu7/WN57DFNO3zYvnGUlWna174WexyNahqgaTdvbn4f0SXfwr33atqf/An7e2lJ09LS\nNG1sTMmhtuD1atqnP61pzzzDfge7+M53NO3QIU0LBOw7pijSqvvMDIsn2uXlBlhMMVmCP69cs4vj\nx5nqpmmb1fSBAXv9Fh4PMxc4v/41+x1UJ8twysuB//s/9ncgwLQquxy0H/84W9FnZ+1zwgLAF77A\n/r0TkFbd33iD2WcqO4kkws0EvVrk4WF7GmBwDhxgApUY7hsfV9twIpGGhs1JK6+8oma/tWQ8/HDM\nQfqzn9k7yX3pS6y46MUXgfZ2+477TkJa0N98094VFIjtCPPqq1tfU125lIjLxVbzxIKD2VmmedjF\nPfdsboJhR2w3nt//ffbbR6PMVr/7bvuOXVsL/NM/AX/913Ke6Xcz0oJ+/bo9lWKJ7NunXzE1Omrv\nSgowp1tiCWEoBDzwgH1jaG1lpaI87N7XJx/Dt0JVFcsY+/a3mTZz+rR9xwaYF/yJJ+w95jsJaUFX\nXRKYjIoK/Rxz1YUUeni9m5NmhoaYwNm5oj/wAItjv/Yae9zfD3zoQ/YdH2ChrvPnmRlnR2jNwTzS\nzriBAXvTXzmlpVsLKZaWWHjlvq2hY6UcOQL88pexxy+8wEI+qvO840lLYx1K/X52PZaXgU99yr7j\nA8A3vsHO+6MfVd/Gy8Ea0oIeiTDPs93U1wOXLm1+7tVXWTzTjgYY8Rw/Dnzve7HHL71kb5EPp7YW\n+MEP2Mq+f789O+fEk5kJfPWr9h7TwRzS8+74uL0hDc7dd29tEsnLBe3mkUeYusrTUPv77TcfAJY5\n1dsL/Pu/A5/8pP3Hd9i5SAv60pLazhrJeOghJljxNR9vvGFvKi6nqoqN5cc/Zo9fe82erLBETpwA\nfud3mFbz9a/bf3yHnYtL08R3Xo5GmYp686Z9iRmctTVmA1+7FvOyP/QQs0/jixzs4t57mfPtW99i\nUYgbN7bHSZkKl8uVsiLO4d2H1Ire2cni2XYLOcCcPTU1LAuLc/Xq9qjMAKuieuEF4LvfZbXKO1HI\nHXYvUoJ++bL9Dp94cnKAn/889nhuzp5yQT2eeILFsb/xDXuKKhwcrCAl6H192+OI49x/f6zpQHc3\n62hiRy2yHtXVzOP8gQ8A3/zm9ozBwSEZUoL+6qv2tFVOxkc/GqsFv3CBpXzaGbtO5ItfZHHs7cgU\ndHAwQkrQh4bUttVNxaOPMqF6+WXm8d7OsTg47GSkEmZmZ2MF+NtBRgYLp33lKywV97vf3b6xODjs\nZITDa/39rAZ9acme7hrJeP55VrF0992bPfAO+jjhtd2J8Iru97Mun9sp5ADw4Q+zunS7NpBwcHgn\nIizoly7Z12k1FU4BhYODMcIicvky8JGPUA7FwcFBFUKC/txzTFX+/Oeph+Pg4KACIWdcczNT2x0v\n9zsPxxm3OxES9Nu3WY67wzsPR9B3J0KquyPkDg7vLBx/tYPDLsARdAeHXYAj6A4OuwBH0B0cdgGO\noO9w/H4/AoEAfD6f4fvOnz9v6jmH3Ykj6DuYrq4uAEBLSwsAoDt+F8U4Ojo6cCmh97Xecw67F0fQ\ndzAXLlxAQUEBAMDr9aKjo0P3fS6dih695xx2L46g72AikQg8cS18QqHQlvd0d3dvrPhGzznsbhxB\n3+GkymILh8OmnnPY3TiCvoNxu90bQjszM4PChE3unNXcwSxOMusO5vTp0+js7ERLSwv6+/tx8uRJ\nAEyld7vdCAaDCAaDCIVCCIfD6O7u1n2uKWErnXPnzm383dzcjObmZhvPymE7cAR9B9PU1ITOzk4E\nAgG43W40ru9O0drais7OTrSt703s8/kQjUbhcrl0n4vHKWjZnUhtyeTg4PDOwLHRHRx2AY6gOzjs\nAhxBd3DYBTiC7uCwC3AE3cFhF+AIuoPDLsARdAeHXYAj6A4Ou4D/B7LmloiwqoteAAAAAElFTkSu\nQmCC\n", "text": "" }, { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAPoAAAD0CAYAAACy5jtNAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJztnWlsHOd9/7/LWzyHXN6kxFs+ZFukbSlO4iSMSSVw0iKF\naVipAyQpUCIu0CZvrMhtioYBAkSNkrxpi3+rRdFcSFNJm6NO4SDiJnIS23FEk44j25IpLineh3a5\nPMV7/i8ePdzl7M71HLPrcD6AIHK4u8/Mzvye53c/HlVVVbi4uPxJk5bsE3BxcZGPK+guLvsAV9Bd\nXPYBrqC7uOwDXEFPcfx+PwKBAHw+X8K/nz59GgD2/L2/vx9+v1/3PS77D1fQU5j+/n4AQEdHBwBg\nYGAg7jU+nw8tLS1oamraPXbmzBl0dXUhEokkfI/L/sMV9BTm/PnzKC4uBgA0Njait7c37jU+nw+D\ng4N47LHHAAAXL17EsWPHAACnTp1CW1ubcyfskrK4gp7CRCIRlJSU7P4eCoXiXhMOhxEIBHD27FkA\nwJUrVxAKhTAwMLB7zMUlI9kn4GKMWT5Td3c3AODSpUsIBALweDwoLS1FW1sbent74ff70dXVtft6\nj8eDL3/5y7u/t7e3o729Xcq5u6QOrqCnMIqiIBwOAwDm5+fh9Xr3/N3n86GkpARdXV3wer0IBoPw\ner1oaGjYff+VK1f2CDoA9PT0OHL+LqmDq7qnMCdPnkQwGAQADA8P48SJEwCISg8Qu72zsxMAUeuP\nHTuGJ598cvc9kUgEx48fT8KZu6QarqCnMNSRFggEoCgKWltbAWBXuDs6OnbV89LSUrS2tqKhoQGK\nosDv9yMcDuOJJ55I2vm7pA4et6hlf+HxeEztfpc/PdwV3cVlH+AKuovLPsAVdBeXfYAr6C4u+wBX\n0F1c9gGuoLu47ANcQXdx2Qe4gu7isg9wBd3FZR/gCrqLyz5AiqBPTgKPPAI8+6yMT3dxcbGLlFz3\nxx8H3n4bmJ0Ffv974L77RI/gwoqb674/Eb6iqyoR7jNngMOHgW99S/QILi4udhEu6L/6FbCwADz1\nFPCBD5DfXVxckotwQb9wAWhpAdLSgM98Brh5E9jZET2Ki4uLHYQL+ssvA83N5OeHHgIyM4GXXhI9\nij3OnQMOHQK+8Y3knoeLS7IQLuiTkwDtNejxAEVFwAsviB7FOqoKfOlLQGUl8NWvAtvbyTsXF5dk\nIVTQVRUIh4GPfjR67K67gD/8QeQo9njpJWB5GXjxRSAjA/jxj5N3Li4uyUKooL/1FhH2I0eix44c\nAd55R+Qo9vjud4HycuDAAaCsDPjBD5J3Li4uyUKooL/4IpCXR1R2ytGjwJ2mpUnhN78B7mxcgsce\nA958M3nncvUq8JGPAM8/n7xzcNmfCBX0118Hamv3Hnv0UWB+nqz0yeDWragpceIEMDycnPMAgE99\nCvjjH4HPfz5534fL/kSooF+7RtTjWO69lzjAJidFjmSNjQ0i6I8/Tn4/cQLY3CTHnGZ+nmQL/vzn\nwNIS8ItfOH8OLvsXoYI+Pw/cfffeY+npQHY2Cbs5zUsvkfGplpGXBxQXAwn2KpTOd74DKAoxZYqK\niO8gWWxuJm9sl+QgVNBHR8kKrqWlhTjqnObll4GDB/cey8tLTlz/hReAujry84kTwOCg8+dAqagA\nRkaSN76L8wgV9I0NINEuvapKHFFO89prQEHB3mMHDxIV2mmGhoD3vY/8/MEPAm+84fw5/OQn5P/6\neuCLX3R+fJfkIUzQ19bIvzu7Bu2hpgYYGxM1knWCQeDOfoO73HVXclaz2dloItHHPkYiEwsLzp6D\nz0f+/9Snkp+t6OIswgT96tVoJpyWxkZgakrUSNZZWADuv3/vsYceAm7fdvY8lpbIv44O8ruiEAfl\niy86ex5DQ+T/z36WOEeddkr+5Cck1HnlirPjuggU9DfeAHJyEv/trrucX70AIBSK1zAeeACYmXH2\nPH79ayA3FygsjB6rqgJefdX8vX6/H4FAAD66HGs4ffo0ACT8+9mzZ3d/3t6OJi55vWSy8futXwMv\nqgr87d8CExPA3/2dc+O6EIQJ+vXriVdzgDSe2NoSNZI1VJWsog8+uPf4gw+Sh97JVf13vyOCHktV\nlbmDsr+/HwDZNRUABgYG4l7j8/nQ0tKCpqamPcd7e3tx6dIl3XOoqnK2hPjyZaLV/fSnxBG5tubc\n2C4CBX18PD5ZhnLffcDKirPlqtQnUF+/93h+PqmoSyAz0rh6lQhWLHV1ZHI04vz58yguLgZA9kLv\nTRAX9Pl8GBwcxGOPPbbnuCc2PRHAL39JwpyUe+5xNjX5e98j13zsGJmEL1xwbuwLF0hF5fe+59yY\nqYYwQR8Z0V/RKyrI/6OjokYzZ2CArGBpCa4wN9fZQptwOL6d1gMPmKcGRyIRlJSU7P4eCoUSfHYY\ngUBgj5o+MDCwqwVQ+vuJU5Ry/DgwPW39GngZGIimIpeXAz/7mXNjf+lLxH/0pS85N2aqIUzQQyH9\nFd3jIfFrJ/PMr17V9xnk5Tm7mr3zzl4hA4iTMIHcxmHW3627uxsdHR0IhUIIBAIAiPBrCQZJay/K\nI4+QSIBT3LhBwooAcYiaaTOiuHmT/KMZiU7lL6gqcTo67fjVQ6iga0NZsaSnO5skMjICVFcn/ltZ\nmbM57wsL8Sv6sWPEV2BUH68oyq7Qzs/Pw+v17vm7z+eD/45Hzev1IhgMJlzNAeJhj81xeM97yNhO\nOEm3t4mPhqYiHz8ejQDI5vvfJ7kUTU1AVpZz1YunTpEiqk9/2pnxzBAm6Csr5MvUo7DQWeEKBvd6\nuWM5dAiYm3PuXLa24p2ClZXEZxEM6r/v5MmTCN55wfDwME6cOAGAqPQAsds7OzsBELX+4YcfRjAY\nhN/vx7lz5xAOh3cdeHNz0XPo6enBmTM9yMvrwX/8x2VxF6rD66+TZKrGRvJ7RwewuupMYc+LL0az\nNQ8fBu4oPdL5n/8B/vIvyXipsKoLE/SNDRJG06O42NmkmaWlaMqplupq54ps5udJbrm2BsDjISuM\nka+g7c4SHAgEoCgKWu/ECqlwd3R0oLe3F36/H6WlpWhra0NXVxe6urrg8XiwsLAAj8eDzU1yDtRG\n7unpQU9PD7KyerCz0y76kuP4zW+IuUQ5coRMck5M/LOzRIMASGbizZvyxxwZISHcb36T/O6k41EX\nVQAbG6oKqOrSkv5rOjpU9b3vFTGaNaqqVPXZZxP/7cwZVVUUZ87j8mVVTU9P/DevV1W/8hX55/Da\na9FziL3lzc2q+ulPyx//c59T1fvv33ssN1dVv/td+WNnZ6vq+fPk5//9X1XNz5c/5te+pqpFReTn\n1lZV/eQn5Y9phpAVnc7M+fn6r6mpcVZdXlqKqopaDh8mqqMTvPUW6W6TiJISZ1a1gQGiUWm5915n\nmoJcvUqSdGIpLJSf77++TqIuH/4w+b29nZiYy8tyx33xRVLIBZDoSjILmChCBP36dRKbNqKhwdkk\nibW1vV7mWO65x7lSTaNEovJyZ1TJa9cS35+iImcKfCYn4/03lZXyPe+vvUaEvbSU/F5QQJzCr7wi\nd9zBQSLgAPD+9ye3lRpFiKAPDemvWpT6ehJPdgJVJZ7e2N51sdCV3onVbHJS3/tfU+NMOm4wGH3Y\nY2luduaeLC/H1xy0tMjX8K5cidckFIXsJCST2VkS1QCI43FpKfl7GwgR9Js348tBtTQ3O5cGOzlJ\nhJ0m6mjJyiLOMCdm2tlZ/fNoaHAmvDU2lniyuftuZ0yY+fl4QW9qkj/JvfFG/HNZUyP3vtPUa2ou\nNDYSbSoZpdGxCBH08XEyUxrR0kI8806EVK5fJ62dNVmge8jOdkbQJyYSr6YAedid0CrW1xNHRO6/\nX745tbVF/mmLi5qb5SfsBIPxjUe8XpK8I4vBQWIe0E1MaHQl2WXBQgR9cTE+l1tLeTn53wmH3OCg\nflYcRVGccYRFIvEPG4VOfrIZG0t8f5qbycQr0zl1/Tp50GMyeQGQBCLZ8eXJyfjv/vBhuVrU734X\n1RgpjY3J7T4MCFzRE3l1Y/F4nMuOGx7eG7dNRE6OM3H91VX9RCLqFJRtv62uJnZMZmYSr7RMtfLq\n1cT1BvffT657fV3e2KFQ/HU3NZHnVRZvvBGv3R44QByiyUSIoC8sxOdyJyIryzgTTBRjY+amRGWl\nM46o9fWoGqeFajmybdWNjcS9/ABiwsj0fg8Nxa/mQLTgSGYvwY2N+NTj++6Tq0WNjMTXfNTXy51c\nrCBE0JeX9QtaYsnNdaaCbXo63tuqpaBA/pdPc9nvuSfx36mWI9NXsLhIJlg9rSIvT67NahSROXhQ\nnkqrqiRmfvTo3uOtrcRkkOUrGh6OTuCUI0eS38dfiKDv7Ognp8SSn++Mury0pB/SolRUEG+wTOhE\nYmTW5OTIFbR33iHmgV6eQ1GR3Fi+kTNyZUXetc/NkedS24+gooJoErL6Bi4tRZNlKI2Nye+6K0TQ\nV1aMK9coiuJMDfTsbPysqqWqiqx2Mrl2zdz7n5cn9yG4cYOs6HqUlsrN+5+ZIWZSIoqK5Gl4V6+S\n717rH6BalCxNIhyOX/SOHJHri7ACt6BvbZGZ04qge73WarB5WV42X9EPHiQTlExu3DBPJCoslKvl\njIwYn0NlpVwfQSikH3XweuVNMm+/rR95URR5TuGFhfhErXvvJTLiVNp1IrgFnXZ31SsJjaWiwpnO\no6ur+pVrFCdSckdH9dNfKV6vXC1nbMw4mampyVjj4GV9XX8RqKyUF0sfG9PX6nJy5DiFd3bIwqd1\nAGZnE9MpmSE2bkEfGjJXTymVlcSGkc3GRrxtpqWpSX6m3tSUvn1KqamRG9ednDSOQMjOt19Y0Pff\n1NTIi3wMD+trMrI0ibExYhZo9x8EiIwkY7ciCregj4wY24Cx1NTIV5dpnrteSItSX09eK9N2mpqK\n7/6qRbY5MztrHIGoq5ObuLKxEe+cotTXy9OqjCZZWX6Jt94iPoFEi56iOBNa1oNb0CcmrKntALHV\nZDsl6Aqhl19OyckhN0SmIywUMg/zVVfL9f6Hw/rOMICstrLiyuvrZDLVm3QbGuSlAIdC+s9AZaWc\n73xwUL9UOz8/uZ53bkEfH9/bRtiIujr5gn7jhv6sqiUjQ25oKxIxn3AOHpS7opolMzU3E9tSRpz3\nxg1yH/Sej+Zmef6BSEQ/t6O2Vs4EY+T49HqTs1sRhVvQ5+asr+gNDfIeKsrwsHEDjFhycuTOsla8\n//X1cie/lRXSI08PGuOX4RAMBo37FDQ1EdVdhq9keVn/uuvq5JiQs7P62lN1tfxwrhHcgn7rlnm6\nKYXaTDJTT0dHiUPE6vnIjCGvruqHliiNjXKdgrdvG4c+aVxZRlfWYNC4uIguEDIyFNfW9J2ADQ1y\nJtexMf1FpqLC2T76WrgFfX7e3A7dHSxNblYSQGLCVieejAziY5DF+rq595+ql7JirEY2MiU7W46j\nyOjBp2RkyJlkVFW/w9Dhw3I6DBn5BWprnYk46cEt6Ldvm5eoxpKZKVfQp6as+wzKyuSGtra2jFtg\nA+T78HjkCBpVi83Skw8ckJOhNjlpbtZlZ4t/HtbWiCDraTJUpRddnhuJ6MtCff27PGEmEkkcN9Qj\nO1tuMYkdUyIvT15WGLUBrVT1ZWbKqY0fGYk2PjCioECOZjMzY67t5eaKj+MHg8bXnZ5O/ia6as/I\nL9DU5EzvAT0cX9Hz8uTaxeFw4rLIRHi98sI7VoUMIJOfjBX15k2iGpshswbBLDVaxiQzNGSu1Xk8\n4ifXtTX96z18mDiik9U7jlvQNzbMPcux5OfLdUosLlrXMMrL5dlNIyPWhAwggiYrU8vKRCPLIzw8\nbJ4wVFwsXqsaGzPvSpyTI16TUFV9U41GN5IVYhNS1GLmWY6lqEhuO6nlZfPYNaWyUp7dNDZm3VeQ\nnS1H0MfHzYtqAGJHy4iELC8bJ+sAZFIWPdlOTJhPMPn5Yk3IrS2y6Bk5PtPTk5cdxyXoVBUxitNq\nKS+X65RYXbVuSlRVyUvBtGKfUmQ87ADRnKzkFHi9cgT99m1zH4WiiC90mpoyv+6yMrGpx9T0Mmph\nlpWVvOw4LkGnX5RZv7hYFEVuWeTamrVuNwDRRGQ5SKamEvdKS8SBA3LMGavJTBUVchJI1tfNtb3y\ncvFmw9ycuUM2N1esGm2WHASQ++zk/oOxcAn62Fg0Nm6V0lK5hS2bm9Y1jIYGeckqt25Zz9ArKZET\n5rt1y9okXF0tR7PZ2jLPI5BhPoVC5g7ZkhKx+e6jo+b+kPx85zb31MIt6FYdThSZqjs1Jaw0wQCi\nKr6MXPNw2LwWnVJaKqfl8vy8eZksQDQg0ZrN5iZxTplNutXV4r//SMT8usvLxUZcxsbM/SHl5fLb\nl+nBJegTE9ZLVCmVlfLsYvolWrWN6Y2REUOORKyH+crL5Wg5ViMQhw6J12zoymXmFDt0SHyW2uKi\nuROwslLs5GrFL3DgwLt0RZ+asubVjaWmRp5dPDJi35TIyJATw15ctD7hGE1+fr8fgUAAPp8v4d9P\nnz4NAHv+7vP54PP5MDv7nCXH5MGDZPUVKXAjI8TLbFadVl8vfpJZWTF3yFZXi9UsZ2asdRN6V67o\ns7PmGyVoqa2VZxePjpqvIFoyM+UI+sqKeYNKSk1N4iKL/v5+AEBHRwcAYGBgIO41Pp8PLS0taLoT\nwA0EAujs7ER3dzc2NoJYXAyYjk/voUiHoBWbFYgKpEihW1szNxkOHRJb2GLlfpeVJa+CjUvQb90y\n31xRS20tWT1kZAhNTNivb5alTt2+ba4+UvQmv/Pnz6P4jjetsbERvb29ca/x+XwYHBzEY489BgAI\nBoO7r1PVRmxvmwduaQWbyNCPFVUWiDYAERnT3tw07xlYVydWg5meNo9wVFXJ35tdD+7wmtW8cgpV\nb2TEba20btJy4ICcBoXr69bj+QcPJq7Tj0QiKIkx9EMJAr/hcBiBQABnz54FAHR3d6O7uxsAsLPT\nj/b2Y5bOITNTbOhnasq6/0bkJENbiZk5ZGkrse1tMeMuLpqv6DIcj1ax6TPfy8KCvWQZgMzeaWlE\ntbPiEbZDKGT/M/Pz5WTqbW5aj+fTc15cjLfzVJMuHVSoL126hEAgsKvmv/pqP4CH8NGPtsa9p6en\nZ/fn9vZ2tLe3IydHrGYzO2td2xMZdqKedDOho6vv7Ky9Wg09bt82H9OJVmp6cAn64iKbsNI68Acf\n5Bk9npkZ++G+oiLxzRnpSmF1EqST382bwAMPRI8rioLwHdVnfn4eXo13z+fzoaSkBF1dXfB6vQgG\ng7uC/uMfB5CW9rWEjR9iBZ0iOoEkFLIeXkxLExf5oAUtVkw4qkmIEPTVVfMswLo6+Z2H9eBS3VdW\n7JWoUrKy5CT3z89bf7goxcXiK9hoOqud7yYjI151PnnyJIJ3kqOHh4dx4sQJAESlB4jd3tnZCYCo\n9ceOETX93LlzePzxU0hLI845KxQXi/UIRyLWMyZFlgvb6TAk0hG7vm6tbZiqJkfYuQTdTl55LDk5\ncgR9YcFeOi4gJyuNXpvZHu2xZGXFq69tbW0AiLAqioLWVqKGU+Hu6OhAb28v/H4/SktL0drait7e\nXjz33HM4ebIZW1sl8Fj0Th44IDY1eWHBeh6BSPNpctK6oBcViYs0WCnuotGNZFSwcanuVmaxROTl\nyXGALS1Zj11TysrEe0JHR+2bEDk5iR86aoNTlRwA+vr6dn/u6ura8/rOzk6Ew2F885vAV78K3HHG\nm1JUJHZFX1qyHl4sKhLnnJ2ZsZ7bkZYmxjegqtayAIGouWCn4lMEXCt6ZqZ1h1Ms+flytmZiMSUq\nKsSn5E5MmBc4aMnNFbuiTk/bS2YqKREb411dtR5eVBRx5pOd3A5RCw6dpKyYjU7tKKyFWdC3tohg\nWWmVpKWwUE6G0O3b1mvRKTJKVScn7antAPFQi5z87BTVAOJLZdfWrGt7IicZO9ddWCjGETs6an0v\nAZGORzswCzq1a63aYbGInMFjsRO7pshIyZ2dtR/PF938IRSyl8wkutjITnhRZKefSMS6Q1ZRxCw4\ndoq7vF65jVf0YBZ0erJ2U2ABcrEyUgHtPFyUgwfFJU1Q5ubsraaA+MnPbgRCdLHR9rZ5dhqlokJc\nIokdb78oR+zkpPXkoLS05PR3Zxb0iQlrRQuJkFWTvr1t38lx6JD4kEcoZH33Goroyc+O1xsgarYo\nzYaWqFqddEWaT3aKiUpLxXzndvwhBQVyNzDRg0vQ7ZaoUmQ4wGjGkV3VnWokokNLdlODRXv/l5ft\nJTOJLDYaHycrl9XnQ2Q9vB2HbGWlmHFnZqybakVFcvcS0INZ0GdmrDc/1FJRId4BRh0cLJOP6A0M\n7K6mgPjJz24E4tAhcfvi0c5DVhFpPtlxyJaXi5lc7RR3FRe/CwXdbi06paZGfLMBugk9Czs7YvO8\nl5fth/kqK8XmQdupngOiE5MIP8H4uL3wIjWfRAj7+rr1666qEvOdh8PWTTVZ3YTM4HLGsTjiADk1\n6Syxa4rodsurq/YFXXQ7p40Ne2ZMbLERL9PT9rQ9GooUkTG2sWHdNyDqObSTkSm7Z6IezIJuZxbT\nQmdwkTXpU1P2Y9cU0V1Y19bsraaAeO//5qZ9x2SifHsWWLS9jAwxGyqoqvXrpuYKL3YyMmWYrVZg\nFnSWAhIKDT2JTBCZnWU3JXJzxcY27a6mQLSdk0hNx26oMVG+PQss2l56Ov+KvrVFBNdueTCvKm3H\nVBNlLtiFWdAXF+0XkOwZWJCaSGFpa0UpKBBbqrq1ZT9jkE5SIrz/Kyvkgbeaa07Ry7e3i91kHYCo\n+ryCTicpOzFtj4dfi1ldte4ArK5+l1WvLS/bLyCJJTNTbPsgloeLIrKgg8aQWYp9RG22OD4ebQ9l\nB1H59izaXk4O/9gsDlkR5kp6ur1uQqITtKzALOisteiUggKxdvH8vP3YNUVkyIN6rVnPRYTqTJOZ\n7JKfL0azWVy0H17My+M3n6am7FcNZmbyf+cLC9YndjohOG2nMwu63fCNFo9HbF2unbCKlpIScbnW\n09Pk2lgcg6K8/6wRCFFNOJaW7At6fj5/xtjUlP3cDhHmip2NRjMyyPPhdGELs6BvbPAJumgHmN1q\nrVhEZqWxrqaAGPUVsB/eohQUiDFh7LS6pogwn2Zm7E+whYV8TmHqWLNTNZmMCjZmQWcpIIlFlJpI\n4TElRBZV2Clw0JKXJyYSwRqBEFUuylIuXFTEr02wePuzsvhq0un9suMfysx8lwg6jYHzCLromnSW\n2DWlupqtOCcRrKspIK4hB6t24/WK0WxYwosizKdQyP5185YH07x+O8+PiAiDXZgEnT4MPO2aRZdl\nstSiU6qrxdnoLLXoFBGrGsAegSgvF6fZ2I06iMgYs1OLTuE1GVj8IbL2EjCCSdCpHcmaiQYQx4/I\njiZbW2whLUBsyOPWLfZ4vqjJLxJhy1oUVZNuZUskLSImGRZBVxS+59DORhUUEREGuzAJOo1X8qi7\nopP7WWrRKdXV4jYZ5EkNFuX9Z6meA8TUpFNhtWuji5hkWLz9paV83zmLA1B0gpYVmASdx+FEEakm\n0s9htdHpjRIR12dZVSiiCh6Wl9kFnVezsZudFjs270S7smLfnCwr4ysPnptjaxsmo5WaEUyCzhKv\n1CKydRF9uFir1wCioYgo6GBJFqGI6tvGGoEQUeQxPm4/aQUgKcO8qaGrq/bDerwRFxbHZzJq0pkE\nnaeAhCKyddH4OHvsmiIq5MGTGiyqJn1tzf4DD0Sz+XhWG9ZkHVrUwzPRsCRNVVXxPYcs6b5er1j/\nlBWYBJ2nFp0iQk2kTE7yreaAuG2iWGrRKaIacrBGIGiYiKcGgVXbo34NnlDX5qZ9hyyvJsHSNiwZ\nNelMgs5TQEIR2bpIhCkhaksilmQRigj1FSDCyhpqzMjgE3QebS8tjc98YqkarK3lW3BYTLXy8ndJ\nrjuPw4lCZ0ERtooIU0JUyGNjgz3MJ6ohx+3b9sNbFN6adB5tj2eSoYuG3cgLNXFY7XQWB6DotmFW\nYBJ03lp0gKw6ImqBATGmhKiQB088n14Dz4TD2g2Xkp3NF30Ih9lrDrKy2Mem985uaDMrizyHrJOb\nlX3RtYiIMNiF0Rl3masWnUL3SeeF5+Gi0FTIy5cvM3/Gzg5/arBWffX7/QgEAvD5fAlff/r0aQDY\n/TsRFD9++1v99xhx4ADfRMPTeYinkoxui8Ry/3giLk63DWN9PhlX9MtctegUUa2LeB4uCg158Ag6\nLQjhbchBJ7/+/n4A0Z1UBwYG4l7v8/nQ0tKCpqYmAEBvbz/S0ozfYwRvvj3L1tUUntTQyUmycLDc\nP56Iy+Ym2zZgrAlajgr61ha7wykWXjWRsrjI3uiBUlLCn6k3PU1WFZ7U4NjJ7/z58yi+IzWNjY3o\n7e2Ne73P58Pg4CAeu7M/8vPPn0d6uvF7jODdeJAnvMhT0ciSikrJzmZ3xG5t2dfgRLYNswqToG9v\ns9uAseTmiknuZ9kXXYuImnRaycRDbE16JBJBSYxLN5RACsLhMAKBAM6ePQsAmJuLICvL+D1G8O4k\nwlMuzFNJxrOhCGsfgK0tsjKz7Cicni62lZoZHlW1H+DyiKrpdHFxsQ2DyLKt6MePq5iZUaGqfP+O\nHVPx+OP8n6MoKs6e5fuM739fxYEDfJ/xz/9MzoXnM44cUXHyJPn59OnT6O3thaqquHDhAr7+9a/v\nee25c+dw8eJFqKqKr3/96zh37hyOHj2Nigr999AHRe/fM8+oqKtjP/+cHBU//CHbe0+eVHHvvWzv\nffpp8t2xvLe1VcUnPmH/fa+9piItjW3MggIV//IvbO9lgUnQX32VLcVSi6gN53hq0SkistJExPNj\n1deTJ08iGAwCAIaHh3HixAkARKUHiA3e2dkJgKjox44dQ2npSWRkxL/HKrxFHizZaRSeikaWphMU\n1pr0iQm2vH7A+Zp0U0Hv7++H3+/XDdWYhX+MKC4W07qIxfNJodf38su+hCEPbfjKCJZ90bXE1qS3\ntbUBAAIuckcLAAAd1klEQVSBABRFQWtrKwDsCndHRwd6e3vh9/tRWlqK1tZWqGobcnKAf//3f8cX\nv/hFPPnkk2hubsYzzzwTN1aie8eTtaXe2T+NNbxoZ5Lp7+9HWloampub0dzcjIGBZ+IcslbvnaKw\nPYc8VZxW/FNmsmVH9kwF/cyZM+jq6kIkEokL1VgJ/xghqnURTy06vT4gAlUdiFvVteErI0TE87U1\n6d3d3ejo6EB3d/fusb6+vt2fu7q60NXVhWeffRYAeWDvuqsbLS0tUFUVN27cwIULF/Dcc8/tGUfv\n3vEUG9EJgrVc2E5F4/z8PHZ2dnavr6DgubhUVKv3jrXIhKUWnWKWoDUwMIDGxkZ0dHSgsbGRW/YM\nBf3ixYs4duwYAODUqVO7KwzFSvjHiLIy/uT+7W2ykrCsIrHX9w//cApAW5z3VRu+MiIS4Q/z8U5+\nNGuRPgAAmRjq6+v3vE7v3vGYMLydh+xUkmmvb3OzPqGgW7l3rEUmc3PsppqVjrtUIwkGg2hra9vz\n3diVPUNB7+vrQygUwsDAwG74JhYr4R8jRGw4Rx8uli9ce32JMqS04SsjeJJFKLwNObTVc4FAAE89\n9VTc6/Tu3cGD7Ln2tFyYNSjDUtRDry9RLbrVe8dak87TYlxRjP1TbW1taGhoQElJye59ik0usyt7\npqp7aWnp7kru9/vj/s7qBQT4a4EBIpg8sevY60tL88dlSFHVORQKIRAIGH4Wa2eXWKqq+Ca/1dW9\nRRaXLl1CkU7aYKJ7R9VulnPg2boaIFqZ3YpGen2JUlGt3jvWIpP5efa2YV6vsV8gEomgubkZPp8P\n3d3dGB4ejluE7MieoYh4vV40NDQAABRFwZUrV/b8XVEUhO+4iOfn5+G1mbUiwtPN83Bpr8/jubKn\nJt3n8+1Obl6vd9cDrgfLxgVaeCc/bfMFastp0bt3PBsP8rYYo5qIHdOFXp+2xbSde8daHsxTxen1\nGpsLPp8Pn/vc59DV1YULFy7g4sWLe1Z0u7JnKOhPPvnk7hcUiURw/Pjx3Z8B/fCPVegMzgNP6qP2\n+g4cOI7paePwlRFra/ypwbz10bEPvNHDbXTvWLO2eMOLdhtfxF4frUVnuXcHD7IJOk/bMCvmQuEd\ndaGjowOKomBqil32DAW9oaEBiqLA7/cjFArhiSeeABAN7+iFf6xChYLHJp2dZXf+aK/P630Cc3PG\n4SsjePZ/o1CnIodFtJuS6fF4dD3ORveOdeNBEeXCdmrSY69vZ4fU4LPcO3rP7GpSy8vsexuY+adO\nnTqFs2fP7oa2u7u7MTPDIXtqkvF4VHVwkP39f/M3qlpXJ+ZcHnhAVZ94gv396emq+tvf8p3Dzo6q\nAqoaCsl5r5Vbriiq+o1v2B//L/5CVY8etf++WHJzVfXb37b3nsVFct07O2xj0u9tdNTe+7xeVf3K\nV9jGfOEFVc3MtPee7m62sVRVVTlLMPjh7b566xZ/WysKz64dvMkiFI+HvaUSTbTh9fyzttVi3Tgi\nlpwc+737RkejjUxYoHvJ2zVXeDQ4FnOBp6ow6YLOuz/1/Lw4Qedpw0szukSU77K2VBob43vgKayb\nPYoIL7JMMqwtpmPJyLD/HPLsKFxba79tGE/jzKQLOm9NOksXTj14dkoRsU0VJTOTrSOtiAceYN+r\nnMc5FTu23ZVraoq/CzDLxocstegUlq63POniSRd03j3BFxf5a9EpPDXpdJsqEbCor4CYHXQAdhOG\np9U1haV33/Q0/wRr9zmkqzFr6jWLicbTCz7pgp6Xx2d7rKyIE3SeXTsmJvjbWVFyc9n6tvHkXsfC\nWmzE0+qawrLRpIiqQbtNUBYWiKDyaDB2eybypIsnXdB5u6+ydOHUg6cN7/S0uA0pWPu28WzZHAur\nCbO2xl8uzDLJ8OxgS7FrroyPk1WdR4uz2zORJwyddEHnLeIQkaRC4S3o4F1VKKwtlUQ88AB7kQdP\nLXrs2HYnGZ4dbClFRfa+87Exfn+I3V51PL3gky7oBQV8XUd5NkzQwtOGV0SyCIV1n3QRDzzAZsKI\nCi+yNL4QtaGInYiLCH9IcbE9E40nNTrpgs67JziP51MLzz7p4bDYMB+LjSzigQfI92A3REeFk9eM\nYtllV8SGInafw+lp/m3AsrLs+QV4TMOkC3p5ObuTgeQzsXs+tfC04RXRW57CqjqLCG8BxM62O/lS\nPwtv4w2Woh6eFtMUu70RRPhDrNSkU3j3KUy6oPN4uql6K0rAAPZMPZHxfNZ90kU88ADJGbe7ekxM\nEC80b7vr2lr7GpWIqkG7JgNPLTqluNi6icZj3gIpIOhVVexOBlqLLrL7NOuuHaKEDGCf/HZ2xDgm\naVGMHYEbH+dPWgHYKhrX1vjj93YjLiJMtZIS6yYa3XKKlaQLOs9WwbSjiUhY90nn2bhAC6v3PxIR\nI+jUyWRnwuMpF46Frsx21Oj1dX6HrN2NDyMRfr+AnQQtno6zQAoIOvV0s9gfoh6uWA4cYEvJFRnP\nZ538REYg0tPJKmIVEUkrQFRDszM2y77oWmpr7X3nCwv8/pCKCuvmwswMX0Ql6YLOMoNTRKQ+amHd\nJ11Eb3kKVV/tqrBbW+Ick3ZNmNlZceFFu5VkIsJ6NOJiVdhFmGp2IgyTk3wmatIFnQoqi7osahWJ\nhXWjv81N/lWFQlVCO7F0mnutafbKTE6Ovawtng0UtBQWWh+bCgqvyVJYSCYYq/d+dZV/TDvmAq+X\nP+mCTmuBWTzdIjyfWlgLOnh6y2uhnVTtrKj0ARUVgbBbLsrTKDERVid+WprL6whMSyOTpdXncH2d\nX9Dt1KQvLvKZhkkXdIA8VCyebpG16BS7GVJANO4ryj4GSDKGHTuVemVFRSDsmjAiatEpubnW/SQ3\nb4rT6uwUmayv82twhw5FMwrNmJ7m80elhKBnZLCp7iI2TNDCsmsHPXfeTKlY0tPtfSeiatEpdvdJ\nv32bv18epaDA+iQjcuvh7Gzrgr69zS/oVBu1kh03P8/n/EsJQbczg8ciIvVRC0tWmshadIrdmvSJ\nCbERCLsmjMhJ184kMzkpziGbk2PtOaT+kLo6/jHT04GREfPX8fZdSAlBz89n21lSZJIKxU7IgzIx\nIXY1B4jqPDtrfSO9H/3o7K4Ky7PxJaWkxJ4Js7oqbkW3U9QzPS3O22/1OaRVbiImtsxMayba8jKf\nTyAlBN2umkjZ3hZXokphydSbmhKrNgPkoXvnHWsb6fX29uLatUvIzTXfnM8qdk0YEUkrsWNbnWRE\n7GBLsdoH4OZNcf6Q7GxrEQZe0yglBF1R2DzdkYi4JBWK3QwpQGwtOqWoCLh+3dpGeh6PBxsbZMJU\nVTVucz4WqqrsJZBsboqLOtjJGLt1S5zJYLUmXUQtOiU315qJtrbG5xNICUEvLWXrvrqxIS52TWGp\nSZ+dFR/mKy4GVlfNN9IbGBhAR0cHtraIoD/44INxm/OxUF5u/Z5Qz7EoQbdjPolIRaVY7QI8Pi7O\nVLNqLvAmQ6WEoLM2ZRSR+qilpsZehhQgtrc8xeslE5lqkhtM99/a3KTVUPGb87FQW2vdhKH3TpR2\nVV1tPWNsYYF9txQtVVXWtLnpaXEaXFGRtQjD9jaf80+wZclGRYV9T7dIz2cssTXpVieRcFh8mK+s\nDNjeNt5Ij67mAJmYSkujm/MVFhZCURRcvHgRp06d2vO+np6e3Z/b29vR3t4eN/6hQ9ZNGOqpFvXw\n19Zar0lfXhY3wZSUWBO6mRlxDsDiYnOzlU6kPP6olBD06mr7DjCqYon2ugPRTD2rgr60BDQ3iz0H\nclNPIhjsQ0dHx56N9CKRCBRFQTAYRDAYRCgUwtZWGDs7xPEWuzlfoo0WYwVdj7q6qEpuFjq8eVOs\nM9KO+STS219VZc1kEKnBlZSYx+6DQeKd5ylTTQlBtzODU3i34THCbhvehQXxE051NbC93QagL24j\nvc7OTvT19aGrqwsAWcW3txfg9Xp2N+drbGxEOBxGd3c30/hUQ5mbMxek8XGxMXy6i8nmpnlqq4gM\ntdhxrSw4KyviCpjKy81r0m/e5H/OU0LQDx2yX5Yp0vOpxWrIg7KyIm5VodBOK1RQqYoOAH19fXte\n293djc9/vht3drWOU9VZoBsMjI6aX9vUlNgqQlq8MTFhXqQj0ttv1VyZngZ0Nqm1TVWVudkqwvmX\nEs44Gn+10xRQdCZYLHYLOm7fFpvnDtif/FRVvGPSajKHyKQVSkaGecYYNS1E+Wnq6631ZuMtMIml\nttb8uZ+Y4Pd/pISg09CUnTRYUbuSJMLuTinr6+JWFQqtr7Zi0qgqOQfRjkmrud8ik1YomZnmlWTU\nSSVKjfZ6iRZjlry1vCxOg6urM7/H09P8329KCDotVbVTrSXS86nF7u4xW1vihSwry3r5rugHnmI1\nmSMUEtugEyArmFnBys2bZEIQVWdA7WAzTYI3eSWWhgZzx2MoxB9CTAlBB6zN4LHIqEWn2NkphbbB\nEi3oAHnwbt40fx11TIpozhhLfr41E0Zk0golL898krGzMFglMxMwSz0QuZcAnZyN0o1nZ/lr/VNG\n0O12NFlcFNeMUYudfdLpwyhj0snKsjb5jY7KcUwWFlrL/RbRP01LQYF5xtjNm3KKicw0ifV1cc64\njAwySRtNLvPz/M96ygi63aaMInuUabFT0DEyIr5ElaIo1uqtx8bkOCYVxZpmIzJphVJWZp5IMjkp\nvsYgJ8d4ciXZimI1uMxMY3NhcZHfLEsZQc/Pt+cAW1wUl/qoxU5N+tiYPBMiI8OaliPjgQes1yDs\n7IiPOhQVma/os7PiNYmiIuMFZ2SErMAiNYmCAuMJXURUJ2UE3aqaSFlaEl+iSqmpsa4tjI/z706i\nR2GhNRtZRngLIN+DlQy1SES8oFdUmE8yk5NitomOpaTEeIIJBuVEGIz8DSsrxGnHQ8oIupWc31hW\nV8V7mSlVVdYdgxMT4h82SnGxdRtZtOoMEPXZSmXVxoZ4Z2R1tXmhkwhvtJbSUuPvnLFGyJCSEuMJ\nfXOT3yeQMoJup9kAQBwihw7JOZf6euspubyN9Y0oLbVmI8tY2QDy/ZptDUWTVhobxY5dW2uedx4O\ni5/gKiuNn8PRUfHfdUGBvom2tUVMI95aipQRdLulqpubckJaAHlore5eKbLxgZaKCmt7c4XDciIQ\njY3mEx4VCtFmVH29ed65CCeVlpoaY0fs5KT4ib2sTF+LoHnuvKZZygi6nVJVuouJqBCHFqoOWnEO\nhsNyKugA8hBbmfwWF+X4K1pazLfLGhrir6xKBJ1sjVhZERfPpphpMTMz4nMGqqr0zdbBQTGh05QR\n9Koq67nu1G6UtZLSgo4EFZ5xyLKPAZJWa2VX1eVl8c4wIDqBGdmPQ0NynJEHDxJBN5ro1tbEa3UN\nDcaaxK1b4rWn2lp9zW14WEyqd8oIup1N7oLB6G4mssjKstaGd2lJfOUaxUoeNEAmA9G59kA0NfnG\nDf3XiNxAIZbMTDL+0JD+a0Q4qbQ0NxubbaJ2rI2lsVE/ujE+LmZiSRlBb2y0Lug0x1kmOTnWUixX\nV8VXjVGamqx9J6oqbs81LdnZxprN+Li8PIL8fH1B39oi180bdtJSVUU+V89sy84W/123tOibrSMj\nYpKhUkbQqapmpcPH2Ji8yjVKXp61ZBWZ3v+aGrKqGTmHVJWosLL8FQcOGOfbT06KL2ihpKfrC3ow\nSL4b0ZMM1WKuXUv895ER8X6Be+4h2kmiSX16WowPKGUEPSfHPOeXMjUlL/2VYpYhRdnakreaUieM\nkepMw2+yzIeCAuNS1VBIXuJSRYX+ZCvKSZWInBzy+YlYXwfuukvseIWF5NlPpDktLoqZWFJG0AGi\njhvZZJTpaXmxa4rXax7DpnnPotXHWAoKjAX9xg3iDJOVnacoxhPe7Ky8qEN2tr6fZHBQjm8A0DcZ\ntrfJv3vuET9mZibw9tvxx6emxIQQU0rQs7OtlWXOzcnzuFPMUiGBaNWYTO0iLc1YyxkaktdpBzBP\nRY1E5Pkoysv1Pf43b4pvsU1RlMT+GXpMdHiNjplIi1hcFJOMlFKCbqVEECAPnix1kVJTYx7Xv3FD\nrucfIJqL0eQ3OipvZQOISWDUhGNpSV7iUlWVfiLJ2Jj4ghZKTU3ica9elTepFhQkntC3t4F77+X/\n/JQS9MJCaw6wUEieukiprjZX3YNB+U7B4mLj72R2Vp6gAUTYjDSbtTXx6a+UQ4f0tYnpaXn9CEpL\nE9c6vPOOvEm1uDjeRt/eJs7p++/n//yUEnSz5H7K2pp4z6eWhgbzCMDIiHynoFlhiRWfBg+NjcZJ\nK9vbwOHDcsZuaNBPGFpelhftqKtLnKk2MiLP6VlbGz+hDw8TjVFEQlZKCXppqbVebQsL8m4ypbnZ\nPFllYkK+r6Cy0riaamZGXmYeQDzMehmLy8tyClood9+tP9lOTcnzDRw+nLjt8/CwvIm9sTH+Pg8M\niDMVUkrQKyqs7Yu9vi7v4aIcPhzNqddjakq+CXHwoLEzLBSSV64LEPuQepu1XLtGnIWy7NYHHiDj\nJppwl5ZIookMjhxJvKJPTsqbXO69N35Se/NNcQ7HlBL0ujrziiVaFilLXaTQldqoLv3WLbmrKUBi\n9Eaqs2zthrZATuQQvHZNrse/oICoromSV0Q5qRJx//1kgtdqMjK23qIcPRov6CMj4kK3KSXoNTXm\nzSeoai/LVoolO1s/QwqQG1qiNDcbV4+trMjLigOimWKJYrw3bsg3XbKzgT/+ce+x1VWyyt93n5wx\n8/PJdWvHnZ6Wt8A88AC5ptjn/+23xYXyUkrQm5rMV3SaESUrQSSWrCxjZ5fM0BKFqnRGwi5rlaHk\n5iae8IaG5MWyKQUF8WO/8Qa5/zLDisXFxEaOZXUVePBBOeNlZRHT9eWXo8cmJ8Vl4aWUoB8+TB5o\no4f6xg25NziWsjLjGLZMRxSlooKsqInSUDc3ycMna2WLPYdEGWp2tpZmpbk5vr/71avyNYncXDKh\nUBYXyXP5wAPyxtzeBl59Nfr76irQ1ibms1NK0CsriW1klHI5NCS+l7ceOTnGWWnLy+LznrX86Ed+\nAAGcPeuL+9s77xAVs6gIOHv27O7x/v5++P1++Hzx72GhvDyxr2J0VE4dfCy5ucBbb+09dvWq/Mm+\nsXHvvX/1VfLcycybaGqKmkjb28T/8sEPivnslBJ0j4eo5UZ28diYvGopLWVl+ruFrKyQGV6W5xcg\nAgsAeXkdmJoCBjS65JtvEpWvt7cXly5d2j1+5swZdHV1IRKJxL2HhdLSxBNeKCTXPwCQz9fGlwcH\n5WdGHjq0V4v5/e/lleNS6uvJJAYAr79OFj1RGmNKCTpAZk29yiGAqLCyUh+11NXpe7zffltuaAkA\nzp8/j+LiYlRVAVtbjejt7d3z9+vXqeMomod78eJFHDt2DADZPrlNgO53992JS2Vv35arygLk87VJ\nM+Pj8k2mtra96divvy4/wvLBD0aTo/7v/0jYVFSKdcoJen6+sbo8Oyt/NqckylaiXL0qP/01Eomg\npKQE+fnkoQtpsolGRoDi4oE9e6dfuXIFoVAIAwMDe9R5Hu6+O96coju4ynJOUR5+OD4SMzcn32T6\n0IeiWhtAzBTZvpA/+zMy3uoq8MorYp2sKSfoDQ3GabBLS/Kz4ih33aWfmTU4KF+VAwBVVdHUlDhp\nZmgIOHBgb0K+x+NBaWnp7kru9/u5z+HBB+OjIcPDpBZfZokuADz0EBkn1oRaXASOH5c77tGj5H/q\nH7h+Xf6kdugQ8T384Afk+RJlnwMpKOiZmcati1ZX5Ye0KEeO6Av6xIR8zUJRFITDYRw8CMzOzsOr\nScMLBgfQ2tqx55jX60XDHelTFAVXrlyJ+9yenp7df5cvXzY9D5qYEqvKvvoqcZTJrt7LyCDm3K9+\nRX5fXSUr7Yc+JHfc9HQS2vvxj4ljLCMD+PjH5Y4JkMXlX/+VJGP99V+L+1xJPTrYqakB/vAH/b/f\nukVUSSc4ciTa3krbtH9oSL6v4OTJk+jr68P993dgbW0YJ06cAEBUekVRsLQUxPZ2EOfOhRAOhzEw\nMIAnn3wSFy9e3H3d8QRLX09Pj63zSE8nE/BLLwEnT5JjfX3ym39Q6upIfPnpp4HLl4km5YRD9pFH\ngN/9DvjZz8jkIlt1B4BvfhPo7AROnBC7oKXcil5fr1/Yoqoke0hE2Z4VcnKIsy3RxBOJyPW4A9hV\nvzc3A1hfV3D0aCsAoLOzEwCwstKFp5/ugsfjwcLCAjweDxoaGqAoCvx+P8LhMJ544gkh51JcDMQq\nB1evyuk8m4imJqI6A0AgIL++gPLhD5N7//3vy7/XlLY24oc6f17wB6spxn/+p6rm5ib+2/Q0SafZ\n3nbufPLzVfX//b/44yUlqvrVrzpzDpub5LrHx6PHNjZU1eNR1bk5e5/Fesvb21X18cejvx85oqp/\n9VdMH2WbL39ZVRWF/Pzoo3vPQyZLS6paVqaqRUWq+m//5syYski5Ff3ee/Uz4/74R+fSXymKQuLV\nWjY3ndMsaLuqV16JHuvvJ+q0rK2jtbS07E1cmZwkHnEnePrpqG3+hz8Q1dYJ8vOB//5v4O//Hnjm\nGWfGlEXKCTqNmyZq43T9utySzETU1sZnhe3sEO+/Uw86QAQ6VnV+6SX54b1Y2tujJcQbG+RnJ5xT\nAEmN9nqBU6eIB/4zn3FmXADo6ABOn3Z2cZFByp1+bi75UmmGUCxvvinfy6ulqSk+3/2tt8h5ODnp\nVFSQpA3Ka685U8FH+fjHSYhvZgZ44QXioHMq+gEAn/408N3vEm+7Uzb6nxIpJ+gA8ebGFhRQhoac\nfbgBkrSgXdFffZXEO52cdI4e3VvYEgxGY71OUFREtIrvfAf40Y/kZ8Rp+drXgN5e4gF3sU9KCnpB\nQXwhA0DiuE6uIgBJzNB2OHn9decnnA98YG8L4mvXxFU2WeU97wF++EMSWhOZzGEFj4eEu9LTnR33\nT4WUFPTy8mg4JZa5OfmdZbS8//3EHo/NeX/zTeey8yh//ufkPMJhYqeurJCUSSf5p38iWtXcHPDc\nc86O7cJHSgp6otxqgGRIOamuAkRlzcgAXnwxemxoSH6utRZFIQk6P/wh8ItfkGNOJHDEcvw48Pzz\nJInEqXoDFzGkpKA3N8fvlLGzQ1T3Rx5x/nzKykhGFiUcBt73PufPo6WFhHu+/W2SA+60YxIgKrvs\nyjEX8aSkoD/8cPzG8G++Sewz2f3cE9HcTOqRAXJey8vOhZZi+cIXiLf9F78AnnrK+fFd3r2kpKC/\n732kkCA2lv7SS0SNTsYq9oEPRENsP/0pcRYmI8TzyU8CH/sY0Wq+8AXnx3d595KSgl5SQmLpsery\nK6/I2dzOCk8+ScyG9XXg5z93rqhGi8cDXLxIzuHdnsDh4iwp+7iUlAC//nX09+vXnXc+UdraSBba\nf/0XcOkS8OijyTkPFxdWUlbQjxzZmzQzPi6/8N+Ij3wE+Md/JKmfbmjJ5d1Gygr60aPRlM/tbRJu\nczpuHIvPB7z3vSRDS3bvMBcX0XhU1aiLevL4zW+AT3yCNJr45S/Jz8vLyXHG/Snh8XiQorfcRSIp\n12GG8uijpIrt+eeJp7u21hVyFxdWUlbQPR6SifWtb5G8989+Ntln5OLy7iVlVXeAeN0ff5w0XQgG\nnem6+qeOq7rvT1Ja0AHSVvjAAeerxf5UcQV9f5Lygu4iFlfQ9ycpG15zcXERhyvoLi77AFfQXVz2\nAa6gu7jsA1xBd3HZB7iC7uKyD3AF3cVlH+AKuovLPsAV9BTH7/cjEAjA5/MZvu7s2bOWjrnsT1xB\nT2H6+/sBAB0dHQCAgYGBhK/r7e3FpUuXTI+57F9cQU9hzp8/j+I7jfIaGxvR29ub8HWeBPW7iY65\n7F9cQU9hIpEISkpKdn8PhUJxrxkYGNhd8Y2OuexvXEFPccwKUMLhsKVjLvsbV9BTGEVRdoV2fn4e\nXk0zeXc1d7FKynaYcQFOnjyJvr4+dHR0YHh4GCdOnABAVHpFURAMBhEMBhEKhRAOhzEwMJDwWJtm\n29Wenp7dn9vb29He3u7gVbkkA1fQU5i2tjb09fUhEAhAURS0trYCADo7O9HX14euri4AgM/nw8LC\nAjweT8Jjsbi16PsTt/GEi8s+wLXRXVz2Aa6gu7jsA1xBd3HZB7iC7uKyD3AF3cVlH+AKuovLPsAV\ndBeXfYAr6C4u+4D/D7yUXoFdkz+AAAAAAElFTkSuQmCC\n", "text": "" }, { "output_type": "pyout", "prompt_number": 11, "text": "" } ], "prompt_number": 11 }, { "cell_type": "raw", "metadata": {}, "source": "Another nice example of a parametric plot" }, { "cell_type": "code", "collapsed": false, "input": "alpha = Symbol(\"alpha\")\nr = 3.0\ncirc = r*exp(1.0j*alpha)", "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 }, { "cell_type": "code", "collapsed": false, "input": "figsize(8,8)\nplot_parametric(re(fresnelc(circ)), im(fresnelc(circ)), (alpha, 0, 2*pi))", "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAekAAAHTCAYAAAADL+BcAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnXd4U9Ubx78tiLKklL0ECgiCKGXIEqmUguwpCILKVFFc\niIyfCKgIgsgWoSigiOy9hJYyyh4FZI+yZNNSKHQ37++Pr7EttDRN7k1ukvN5nvsU0uSckzT3vOfd\nHiIiUCgUCoVCYTg8Hb0AhUKhUCgU6aOEtEKhUCgUBkUJaYVCoVAoDIoS0gqFQqFQGJTsjl6AQuEO\nLF26FF5eXggPD0efPn10eUyhULgeSkgrFDoTFhYGHx8f+Pr6/vd/M/7+/ggPD0dYWBjMiRbWPGYe\nW6FQuBbK3K1Q2IFBgwYBAMLDw+Hr64uFCxcif/78AAAfHx8EBQVh0aJF8PLysuoxhULhmighrVDo\njK+vL8qWLQtvb294e3sDAKKiov77NwBERETY9JhCoXBNlLlbodCZqKgolC9fHoGBgejTpw+qV68O\nANCzjpCHhweGDx/+3//9/Pzg5+en23wKhUIflJBWKHQmMDAQ7777Lp5++ml4eXlhyZIl8PLyQmRk\nJAAK8QIFCgBAlh+7c+fOf489zIgRI3R7TwqFwj4oc7dCYQeefvppAAz28vLyQufOnREeHg6AfuqA\ngACrHjt//jwCAgIc8I4UCoU9UJq0QqEzAwcOxLhx4+Dj44PIyMj/Uqb279+P4OBgeHl5oVq1ajY/\nplAoXA8P1WBDoXA9PDw8dPV5KxQK+6DM3QqFQqFQGBQlpBUKhUKhMChKSCsUCoVCYVCUkFYoFAqF\nwqAoIa1QKBQKhUFRQlqhUCgUCoOihLRCoVAoFAZFCWmFQqFQKAyKEtIKhUKhUBgUJaQVCoVCoTAo\nqna3QmEAkpOBmBjg/n1eMTFAQgJ/l7q6p/nfnp7AE08AefIAuXOnXNmypR1XBIiN5VgJCUBiIq/0\n/m0e98knH395eOj/eSgUCqKEtEKhA/HxwNWrwD//PHrlzg0cOpQikO/fB+LiUgRtnjyAjw9w507K\neKkFY3IykC8fcP58ymvj4yloPT15AUD27IDJBHh5AQ8eUIA/8URagZsrF38+8QTw7LPAyZMcK72r\nShXg8GGgSJGMr8KFU/7t5aUEukJhK6rBhkKRRUwm4NIlIDz8UQF85Qp/3rkDFCsGlCz56FWsGJA3\nL4Wx+cqZM0W4RkYCZ84AFy8CFy6k/XnxIoVt6dJAmTIcq0ABwNsbyJ+f4z71FNC6tQdCQgSenhzv\n2jXg+vX0r2LFKPQrVKCgrlAh5SpcOK2gvX8fuHEj4+vmzZR/x8WlFdrVqvG9VqzIq3x5HhAUCkXG\nKCGtUDyGuDjg2DFqvubr8GEKHE/PtMK3RImUfxcu/Kjp+WFEKHQPHQLCwlJ+mkxA0aIUwmZhXLp0\nyuXllfm6Le2CJQJERPDQcfo0Dwepr8TEFIHt60sNv3p1oGzZzLXk2Ni0QvvOHeDoUWrrp07xvZco\nkSK0n38eqFwZePFFavgKhUIJaYXiPyIi0grjQ4eAs2cpoKpVS7lefJHaa1ZITKRwSi2MDx2iBu3r\ny3HNP318UrRqa9GqVaVZqz9zhlr39u3AwYPUqKtVo8CuXp1rr1gx84NJahITaY04dYrXjRtASAhw\n4gS17Bo1gJo1+fPFF/lZKRTuhhLSCrfk7l1g925gx44UgXz3LoVBaoFcuTLNx1nBZAKOHAH27QP2\n7OHYx48DzzyTVhhXq0YzsB7o3U/61i0eNA4eTPmZLx9N7v7+vKpXz5rQNhMfD/z9N3DgAK/9+3nA\nqVCBAtvPjz8rV1Y+b4Xro4S0wi2IiwN27gSCg3kdOwa88go3e7PQLFPGuk1fhOOFhPDauhUoWBBo\n147m6WrVgBdeYFCYvdBbSKfHnTvUtIOC+BlfuwY0bJgitCtVsl6oxsWlCO5z54AlSxgB/+qrKVeF\nCkpoK1wPJaQVLklyMjd0s1Des4fRyf7+QOPGQN26WdeQU3PuHLBpE7B5M7BlCwOiGjWisPDzo6/V\nkThCSD/MtWv8fIKDKbiTk1MEtr8/ffe2cOFCysEoJIQWjNRC2xK/uUJhdJSQVrgMZ88C69dTKGzd\nSkFpFggNG9Icay3JycCuXcCqVbyKFKHmbRYIpUtr9jY0wQhCOjUi/PuYD00hIfTrmw9Nfn6MULdl\n/HPn0grtMmV4GGvTBqhfnylpCoWzoYS0wqk5exZYtAhYuDAljcjfn1pt0aK2jX3/PrBxI4Xy2rUU\n+q1b86pe3fbgLj0xmpB+GJOJUfJmLXvnTqBWLbogXn+d/mZbxz9yBFi5ElixgmlxLVoAbdsCAQH2\ndT0oFLaghLTC6Th/Hli8mIL5yhWgY0egc2dqS7YKzgcPgKVLgdWrgb/+AurUoVBu1cp42vLjMLqQ\nfpiEBAbyLVtGf7OXF9CpEwX2c8/ZPv7FizxsrVjBgD4/Pwrsli2ZLqdQGBUlpBVOweXL1JgXLaKQ\nbt+em3jDhtZFEKdGhFHes2dTSNSvD/ToQTOsLSZyR+JsQjo1JhNdC4sX8/L2prDWSmDfuQOsW0eB\nffQoi7m8/Ta/U3nz2j6+QqElSkgrDMvVq9ykFy1iCk7bttSYGzXSxr94+TLw22/AnDksi9mjB9Ct\nGzdtZ8eZhXRqTCaawhcvZqpXbCzQuzfwxhvaHKDi4ujK+O03xjG0bAl0784Dmq2HP4VCC5SQVhiK\n6GhqOLNm0afYujUFc+PGQI4cto8fG0s/5ezZNHt26kTh/NJLrhUJ7CpCOjXJyYyonzWLfuy2bYFe\nvYCXX9bmb3frFl0ov/1GH3bXrsBbbzF9TqFwFEpIKwzBmTPA1KnAvHkUyq+9BjRtqk1tZxEK5Nmz\nqZXXqEHB3Lat61axckUhnZqbN4Hffwd++YXCu3dvClStisOcPMnx581jHn3TptSw8+TRZnyFwlKU\nkFY4DJOJwVlTpjCnuXdv4P33bc+fNXP9OjfaOXMYmPTOO9zIS5XSZnwj4+pC2owI/dezZjGeoFEj\n4MMPmRanhXZtMtEMPnUq07q6dwf69WMJVIXCHighrbA79+4Bc+dSOOfJA3z0EX2MthQXSc2RI8D3\n39OnXbYstWatTKLOgrsI6dTcu0dz9dy5jNIfPJiR/1r5li9dAmbM4IGgWjUeBpo3V75rhb4oIa2w\nG6dPp5i0AwIonOvV0054hoYCo0czwOiTT4B333Xe6GxbcUchbUaEwWCjR7NpxxdfMHpbq7aYcXEM\nZJsyBbh9m5p1z562FWNRKDJCCWmFrphN2pMnswlDnz7Ae+9pZ9I2mZhOM2YMzdtffEGTtlZaubPi\nzkI6Ndu3U1gfPgx8+ikPblqmWe3dy4PnkSO01gwa5B7uFIX9UEJaoQv37wO//soNLG9eas2dO2sn\nPBMTadr8/numYw0eDHTooEo/mlFCOi2HDvG7EhTEQ+JHHwGFCmk3/rVrwIQJNIV37AgMGUJXi0Jh\nKwYubKhwRmJjgR9/ZD/g06cZtLV/P82NWgjomBhg2jTg2WcZ2fvDD9TQO3dWAlqRMdWqAX/+ySCz\nmzcZ+PXRR/Qza0GxYsDYsfzOFy7MPtg9ejBrQaGwBSWkFZqQkAD8/DNrZ2/fznzWqVO18znfuweM\nGgX4+FAb+vNPRts2bepeAWEK2yhfnsFfR4/y0Ojry6j/48e1Gb9gQeDbb1lTvkwZfv+7dQNOnNBm\nfIX7oYS0wiaSkxlNW6kSi5AsX86ralVtxk9KovB/9llqQJs3c/w6dbQZX+GeFC9OzffsWQruV18F\nunSh71oL8ucHhg9nZ67KlVkrvFMn+q4ViqygfNIKqzCZ2Ijiq6/o2/v2W3Yw0pKNG4HPPuP4P/5I\nrUdhGconnTViYph1MGwYS4N+8w0FuVbcv8/D5vjxrEHerx8PtgpFZihNWpElRIA1a1i1a+xYYNIk\nFnvQUkCfPMm2gv36Ufhv3qwEtEJfcuUC+valT7lgQVqCRoxgvrUW5MkDfP45EB4OlCsHNGgA9O/P\nFC6F4nEoIa2wmOBg+tiGDKEpb+9eoEkT7XzCEREM5mnQgJWjjh1j6U7lc1bYi3z5GAV+4AAFtjlA\nMTlZm/Fz5gQ+/jjFR/3cc9Su4+O1GV/heihztyJTzp/nxpItG/1qnTvb3rc5NQkJwE8/Ad99R1Pg\niBHapse4I8rcrQ1791IDjopiJkGTJtqOf/IkMHAgA9fGjmW7THUoVaRGCWlFhsTFAePG0aT92WfA\ngAHaVW0CUkznn3/OnNLx44EqVbQb351RQlo7RNg57ddfeVCdPFn7giVBQby/nn6a8Re1amk7vsJ5\nUeZuRbr89Rf9cgcP0vQ3dKi2AvrIEZYGHTQImDgR2LBBCWiFMfHwoNtl8WLmW/v68uCqlQkcYCvW\ngweZDtamDRt5XL2q3fgK50UJaUUaLl1i5a4PPuBGtHw5ULq0duPfuweMHEkB3a4dU16aNdNufIVC\nL558krEYoaG8L2rXpmDVimzZ2B/71Cng+eeBF18Epk9nJoXCfVFCWgGAfuExY4Dq1dnk/uhRdvjR\nki1buPFcu0Zf3AcfAE88oe0cCoXeVKrEQjoffsgD5oABTLHSirx5aWHauhX44w8GUh47pt34CudC\nCWkFgoMpmENDGSgzfLi2DSpiY9nc4M03WYXs559Z7EGhcFY8PGiaPnqUWQlVqgCrV2s7R+XKwLZt\nbBjj5wd8+SXjRBTuhRLSbsydO2zp2Ls3I0tXr2bZTS3Zv5/a+dWr9EO3aKHt+AqFIylUiPXpZ8+m\nRv3ZZxTaWuHpyc5dhw/TDP7CC9TiFe6DEtJuyl9/8YY3magNtG6tbepHYiI18hYt+HPhQqBAAe3G\nVyiMRKNGPIRmy8bgMq0FafHiDFz74Qc2q+nTB4iM1HYOhTFRKVhuxoMHzMtcs4anf39/7ec4dowm\nuiJF2LpPy/KKRkCEPsioKODu3ZSfd+8C0dE073t6Pnply/bo/3PmBLy9eRUoQDdAzpy2r1GrFKyE\nBL6/h6/kZB7EPDwefZ8PP5b6/088AeTOTQ20cGH6X10tL3jjRnbAevttBklqHXcRHc10xV9/pRbf\nqJG24yuMhRLSbsTOnRSe9eszctvLS9vxk5PZU/f771mYpHdv59qAk5KAf/5h6cbz51N+xsXx32aB\nHB1NQZovHz/DfPnS/jtHDgpykynlSk5O+39zxO69e9SI7tzhz4gICm+z4Pb2pmaWLRtzycuUSbny\n5Mn4vWQmpOPi+F4vX370SkqideXOHQpiL6+0V/78QNGi/CxMpkffa3qPmf+fLx9w4QKbpdy6xUNA\n4cIpQtv8s3BhHu6KF2fVrxIltC2gozc3b1JQ374NzJ/PUqBas2EDo8G7dmX5XC1TJBXGQQlpNyA+\nnlW8Zs9mSke7dtrPER7OQBoPD57ujdrwPjaWJRnPnk0rjMPDKbQKF6ZfvmxZ/vTxAUqWTCuEn35a\nv97VIlxjZGTa6+xZCrfUV65cFNZVqrC4xgsv8CpfHnjiCQrp27dZzer4cb7v48cpfP/+m4KvZEm+\n9uGrUCEK41y59D1oxcZSWJuFduqfcXE0IZ8+zQNS+fJshfrss2mvAgWMeRgUAaZMYbOOH39ky0qt\n13n7Nk3f4eGMBH/+eW3HVzgeJaRdnCNHWBihbFn20S1SRNvxRYCZMxl5OmQIA9GMovHExDDg5sCB\nlOvsWfrfExNThLBZIJcurZ82cvDgQZw/fx6RkZHo06cPAGDp0qXw8vJCeHh4lh9bsmQpPDy8cOBA\nOHx9++DoUVpKjhyhUE9K8sBTT/HW9vFh8J6vLyOGn3uOgtgofydLiI4Gzpzhdfp02itXLgrwWrVS\nrrJljSO4jxwB3niDn/9PP/GgpyUiNH0PGsQuXv37O9ffVvF4dNIHFI5GhEJ5+HCan99+W/tNKyKC\nwnnvXuZ0Vq6s7fhZITYWCAtLK5DPnaNAqlGD/ac/+IBV1BxhFhwzZgwWLVqEcePGISws7D9TtL+/\nP8LDw7P82P37gLe3Pw4fDsfmzWE4dcoXXl5M1alRgxv2yJHAxYvUmnftYqR9/fq86tWjFmoUQZYZ\nefPyoFG9etrHRah1HzkC7NsHLFjAKOu4uLRCu1YtmugdwQsv8LMfMICC+o8/gLp1tRvfw4Nm74YN\nqa2vXUtrlqvFgrgrSpN2QaKjgZ49acpdtEj7tCoAOHSIzQA6dwa+/tr+RUkSE7kpb97MPO+wMArk\nF16gkKpRg6Y/I/jplixZgvPnz2PgwIH/PTZ48GA0adIEjRo1QnBwMA4ePIiIiAgEBATA39//kcdq\n1/bHlCnB2LDhIE6ejEBcXADq1vVHwYLByJHjIEaPHpjGSvKwTzopicJ6xw5q3Dt2MIiwfn3g1VfZ\nOOK555xHaGfG1av8fqS+GjSgj79xYwZMOkJor1jBlKr+/Wl5ypZN2/GTkuifnj6dglpV83N+lCbt\nYpw4QeHZoAHw++/aFiUx8+efbCk5dSqFtD0wmagtBQdTMIeG8vDRqBGj1Rs0oLZlRPbv3w8ACAsL\nQ1BQEAYOHIioqCh4e3v/95yIiIg0jyUlAYcPR+DUqShs3OiN06cZfPT00xGoVy8KQ4d6o1Ytfh6b\nNkVk6sbInp1anK8vK2UB9MHv3s3mDhMnMritaVNejRs7d8GZ4sVZA7tNG/5fhFXuNm8GlizhZ1Cy\nJIV148bUQu3x/Wnbllp99+60QM2YARQrpt342bMz/qRpUxYP6tSJQluvGAqF/qg/nQuxZAnQrx/L\ne/bsqf34SUnA4MGsWxwUxBKfehITw3zu5cvpi4yM5Kbaowcwdy5QsKC+82tJwYIF4evri6CgICxd\nuhQAHom+Tkpifu2ECdS4ChSg/7JPHwbl7d4NbNrEqGpLNt0RI0b8928/Pz/4+fml+X3JkkDHjrxE\n6N/96y9qYL16MSCtSxfWWX/uOdvev6Px8OB7eO45uj2Sklh3OyiIQV1vvMGD3iuv8JBbsaJ+aylR\ngn/HCRNY/3vlSh6etKRuXWDPHv79XnuNB2vV/tU5UULaBTALz6VLmZbxsN9OC27fptacPTtNh6mU\nQE2JimIO97Jl1BJr1mQ0+jffaNvow54UKFAAZf8Nd/fy8sK+ffvg5eWFyMhI3LkDrFwZhc2bC+DM\nGaBy5Uj06gW8/HIU7t4tgIgIoFKlSOTODURFRaHAvxVhIv+tZHHnzp3/HnuY1EI6Mzw8KJgqVqSV\nJD6e1oqNGymk8+dnr+9OnVi72tnJnh146SVeQ4fyQLhzJw9HjRoxkr99e17VqmnvBsiWjS1ay5Sh\nq2HmTO2zLgoV4n4wbBjvoyVLVAtMZ0TFADo5N27QXHfsWEoJTq05eJA3ea1awLp12gvoa9dYz7tp\nU+CZZ1hZqXVrppUEB9M06awCGgA6duyI8PBwABS01aq9hHz5OmPkyHCULg0EB4ejU6cAbNjQGf36\nhePDD4G7d8MREBCAzp07//fa8PBHHzt//jwCAgI0X/OTT9Jq8f337Iz2888ployqVXloOnlS82kd\nRq5cvI+mTmWu+C+/8KDy+uuMFP/sMx5atGxPCdCKsX49D0ZjxtCioSXZswOjR9Od0bw5EBio7fgK\n/VGBY07Mzp3Ubnv14mlZ6yAUAJg3j80xpk2jFqUVDx5Q81+4kJq5uXXla689vkiHsxIYGIjoaG/M\nn78fFy6MRo0aQNmygWjZ0gfXrqWkVgUGBsLHxydNupWlj6VGq4pjD2My8Xu3eDE1s9q1aSJ+6y39\nrCuORISFXZYt41WsGN0877yjrQvgyhX6zytXpiDVI+Dx5ElaBurV42FEj3gVhQ6IwukwmUQmTxYp\nXFhk7Vp95khOFvnmG5Fy5USOHNFmTJNJJDRUpFcvES8vkebNRRYvFomN1WZ8I3L3rsjPP4vUrClS\nqpTIV1+JnD+v/7z2uLWTk0W2bhXp1o1/z27dRLZt49/ZVTl2TOSLL0SKFROpXVtk+nSRO3e0GfvB\nA5GOHUXq1RO5cUObMR8mOlrk9df5fbx4UZ85FNqiNGknIz6eqRshIdRE9UivSkhgXnVEBPNObdWQ\nrlwBfvuNAUkeHgz86t7ddfM4RZjiNGsWg4L8/VkiNSBAH2tHeuilSWdERASzCWbM4N+4b1/X1a4B\nxoFs3Mjv9MaNTHXq0YN/a1v+xiYTo7N//x1YtYquBa0xV0KbPJmWrBo1tJ9DoR1KSDsR9+4xhaNk\nSW6GWjRieJj794EOHTj2ggXWm8RMJgatrFrFXO2OHRlxXru26+TiPkxEBKPOZ87ke+zdm4eRwoXt\nvxZ7C2kzIvTdzpjBAMBWrZhxUKeOa//d//yTArtoUeae9+1rW9e3+fNZve/XX4GWLTVbahqWL+c6\n58xRLWQNjSPVeIXlXL8u4usr8v77IklJ+sxx65bISy+J9Owpkpho3Rj374v89JNIxYoi1aqJzJtH\nM54rc+GCyEcfieTPLzJggMiOHY43+Rrh1r59W2TCBJFWrUTq1BFZvpwmclfm4EGRHj1o/u/TR+To\nUevH2r1bpHhxkfHj9fs+7dolUrQoXTIKY+L4O1mRKefOiZQvLzJ8uH4366VLIpUqiQwaZN0cly7x\ntQULirRtK7Jli+MFld4cPizy5psi3t4iAweKXLni6BWlYAQhbSYpibEHNWrwO/brryLx8Y5elb5c\nvy4yciQFYOPGImvWWHdAuXhR5I03RD79VL/76cwZ7i+DB7v+IcoZMc6drEiXQ4d4mp42Tb85jh8X\neeYZkR9+yPpr9+zhJpI/v8jHH4ucPav9+oyEySQSEiLSrBk34NGjtQsc0hIjCWkzJpNIUJBIQIBI\nyZLUEO/dc/Sq9CUuTuS332gFq1CBVqb797M2RmQkg9R699bPinbzJq0dXbtyzQrjoHzSBmbbNvpy\np07VNv0pNXv2MPVj7FgG+ljKjh0McMmVi00devbUvruP0dixA/jf/5gi1ro1Py+jprE4yidtKQcO\n8Dtnzr3+6CN+l1wVs69+4UKmrn3+OfD++0Du3Ja9Pjqa92nRoox70KNWfmwsS4lGRtJf7cxlYV0K\nBx8SFBmwfLlIoULUPPRiwwaap1evtvw1oaE035UtK/LLLyIJCfqtzygcOEDNuXRpmmqt9dfbE2e5\ntU+cYEpQsWLUMt3h+3TkCFOtihQRGTvWcs06JkakRQuR1q31S1tMSqJFrHJlxlooHI9z3MluRmAg\nTan79+s3x59/Ms96+3bLnr9jB82UZcqIzJrlHpvpiRPcTIsVE5k61bnMgM4ipM3s3y/SpAnz8ufP\ndw/f6JEjPKAUKSLy/ffMYc6M+Hi+xt8/62bzrDBhgkj9+iJ//63fHArLcK472cUxmUS++46C8NQp\n/eaZNUukRAnLipSkFs6Bga4f8CMiEhVFbSIggJunM0anO5uQNrN5M/2vL74osnGjo1djH/7+W6RT\nJx6af/gh8+9bUhIjyOvV0zceYv58KgthYfrNocgc5ZM2CCYT6wNv3sz8Yr0KfQQGAj/9lHkhlAsX\n2KQ+IYH+17ffBnLk0GdNRkGERSQGD2ad49GjnbdzkNF90o9DhEVgJk+m/3/SJNbPdnWOHWMBnCVL\nWMe7SxfAM4PuCiYT86j37GE9fVtysh/HkiXsGrZunSp64jAcfEhQCLXTrl1FXn5Z35PxggWMFD99\nOuPnxMQw1cvbW+Trr/l/dyAsjOa9mjUZse7suMKtHRcnMmpUynfRlcvHpiY0lN/D2rWZx5wRJpPI\nt9+KVK+u775hjo/ZvVu/ORQZ4/x3spMTHS3StCkLPugpENeupTnt8OH0f28yiSxZwuCo1193n7q+\nkZEiH3zAz2bGDP1SXOyNKwhpMxcuMPe+fHmR9esdvRr7kJwsMncu3VJdu7IOQXqYTCL9+9P0bYlP\n21rWrKGgDg3Vbw5F+rjOneyExMQwUvPDD/WNGN66lVHcGZ3Kjx1jIEqVKiLBwfqtw0gkJzM6vUgR\nkffeY3UsV8KVhLSZtWsZWNa+vfscIqOjRYYNozVh+PD0g8WSk1klsFEjfQ/6GzZQUG/dqt8cikdR\n/aQdRFIS8MYbzA2dNIl9X/Vg/37mWi9YwPrJqbl7l20oGzZkDuahQ2x47+ocOcL6yjNnsr709On6\n+fQU2tG8OdtGvvAC4OvLJhFJSY5elb7kyQN8/TUQFgacOgVUqsT2sSZTynM8PfldLlyY/a8TEvRZ\nS9Om3Ec6dmSfd4V9UELaAZhMbL6QkMDCBBkFh9jK8eMszh8YyIIRqeefPZs3/P37fF7//vodFIxC\nUhIwalRKD+6dO4GaNR29KkVWeOopYPhw9iDftQt4+WXgzBlHr0p/nnmGTTwWLmRA3TvvAH//nfL7\nbNnYaS57dhYk0evw0qgRg8n692eQq8IOOFqVdzdMJpHPPhOpW1ffPMfwcJZe/P33tI/v2cMmGnXq\niOzbp9/8RuPcOfrtGjUSuXzZ0avRH3e4tZOT2Ve9YEHGE7h6rXgzyclMoyxYkP3JU6dFxsUx33zA\nAH0/j5AQzr93r35zKIjr38kG47vvRJ5/XiQiQr85rlwR8fFhAQ4zkZFsAlGsmMicOe5RLEKEG9Xs\n2dxQxo93n/ftDkLazLFjrI3dsiUbW7gL//zDgNMqVdJmJNy/zwPpN9/oO//KlYzpOHFC33ncHfe5\nkw3AjBksp6lnt6Tbt3nTjhqV8timTSKlSokMGSJy965+cxuN27dFOnQQqVo146h2V8WdhLQItcmh\nQ1l8Y8UKR6/GfphMrB5YpAi1Z3MhlGvX2DRn4UJ95589m/NkFH2usB33upMdyOLF1GLPnNFvjnv3\nRGrVEvniC968Dx4wPaNUKfep3mTmr7+YvvLZZ+6TX5sadxPSZkJDaUXq1cv1O2yl5uZNkS5dGP0e\nEsLHDh1iNLbeef8//MAWpLdu6TuPu6ICx+zApk1Av36s2lO+vD5zJCezE9Wrr7Ja0f79QPXqQEQE\ncPgwEBCgz7xGIzYW+PhjBobNnQuMH2/cTlUK7alfn1kKAFCtGrttuQOFCgHz5wMTJgDdugEDBwLl\nygG//AI3WhV9AAAgAElEQVS0awdcuqTf3AMGMDukRQsGoiq0RQlpndm7l9GWS5dy09CLr74Cbt1i\n5OvIkYzq/vpr4I8/3Kfl3MWLjNy+eZMHk9QR7Qr3IW9eltecOBFo1ozZDe5Cq1YsL2oyAbVqAaVL\ns9xwq1Zsd6kXo0cDVasC7dsD8fH6zeOOKCGtIydOsO71r78CDRroN8/ixRTG333HnOe9e5lXqVcP\naiOyfTvzwBs1okbh7e3oFSkcTatW/F5MmAD07es+wiNfPlqQhg7lQTVPHgrsN9+kxU0PPDyAn3/m\nXN276zePO6KEtE5cvMjk/3HjqNXqxeHDbB7fpQtNTr16AWvX6tegw4gEBrLAwty5bDrg4eHoFSmM\nQsWKbEIREcED7JUrjl6R/ejeHQgNZUOdu3eBqCg2j9GL7Nl5QL59m1Y8J+3vYjiUkNaBmzeBJk3o\nq+neXb95IiIomH186HPauRN47z33EVKJicCHHwI//sjNqEkTR69IYUTy5mUBjjZtqFFu3+7oFdmP\nihWB3bvps758mcVQZs3Sb76nngKWLQOWLwemTdNvHndCtarUmAcPWJqvRg3gm2/0mycpiUEyZ86w\nvOiECcCTT+o3n9GIiODnnDMnT+/58jl6RcbCmVtV6smGDWy7Onw4LVDucqAF6BZ77z1WOly5Ut8S\nwOHhQL16LGHauLF+87gDSkhriAgDl/Lnp39Gzw2gWTPWzw0M5KbjThw9Sq2oY0f64bNlc/SKjIcS\n0hlz7hzwxRdAqVK0wuhVlteIhIezBvr587QovPSSfnNt2cL9MDQUqFBBv3lcHSWkNWTMGJp6tm3T\nL+0nIYE32bZtrJ378sv6zGNUVq4E+vTh5tqtm6NXY1yUkH48UVE86BUtylgGd0rTS0hgnMyWLYxf\n0TM9c+ZMWvl27QK8vPSbx5VRQloj1q9n04w9e4CSJfWZ459/qEGfPs0brG5dfeYxKlOmsAvPhAn6\nagCugBLSmRMXB7z1FmNIVqxwPyHSrh0P+lOm8HPQi/79gbNn2XFOWb2yjhLSGnDmDDXaZcvoJ9aD\n0FDeSJGRTOlq316feYyICPPAFy8GNm5kRyDF41FC2jJMJrZrDQnhQbtECUevyH7ExjK3+e5dFlsa\nMUIfF11SEpWLF15gapgia7iRN0YfoqOBtm2ZcqCXgP79dwplHx/g88/dS0CbTIzgXreOPjQloBVa\n4unJoifduzPQ6fhxR6/IfuTMScXCZKIbqXt3fXLJs2cHFi0CVq+mgqHIGkpI24DJxKCt+vWBd9/V\nfnwRnm6/+or9Y+PjgSFDtJ/HqCQm0u987Bg1nUKFHL0ihSvi4cEymqNGMeJ5715Hr8h+vPACMGwY\nkCMHNevGjZnnrDX58wOrVrHy4r592o/vyighbQPffQdcv06fjtbEx9O8vX49MHs2r99+cx+fTkwM\nLRT37/MzePppR69I4ep060arVcuWrDngLnz0EYVolSq0JtStSxee1lSqxP4Cb7xBE7vCMpSQtpJN\nm5hzuXSp9vnJERGMuIyN5RwffwyMHQuULavtPEYlJoZBLRUr8vPNmdPRK1K4CwEBFNRt27qPoPb0\nBObMYSR269ZMT2vQgBkkWtOhA/3TvXurimSWooS0FVy7Ri131CigWDFtxz5zhifZunXpxxkzhr7o\nd97Rdh6jEhfHDbJQIZZUfeIJR69I4W40bep+grpYMWDGDFoTOnXi++/YkcVItOaHHxjt/fPP2o/t\niqjo7ixiMvEmrleP3aa0JCyMgWGdOtHHvW0bTUOHD7uHPzY+nhp0vnzcJLJnd/SKnBcV3W07Gzbw\nML5ypfukO773Hqsm/v47Y0FatKCCMHy4tpHfp08zlmfTJn27A7oCSpPOIuPGUdsbNkzbcXftAl57\nDfjgAwroe/cYlBYY6B4COiGBJ/fcuZWAVhiD115jHEibNrw/3YHx4xnYNX8+fdS7dzOzol8/BnJq\nxbPPApMmUSHRs4WmK6A06SywZw/b3+3fr20q0ObN1Jh/+40bAwD06EFftzuYhJKSeDi5dYsNAJSJ\n23aUJq0dGzYwSHTCBNbkd3UOHuQ+tHcvUKYMY0Q++IBV2hYuZCS4VvTpw/HnzXOvOupZQWnSFnL3\nLtC1K4WmlgJ67VoK6MWLUwT0smUsXvLDD9rNY1REGBh35QqriSkBrTAar73GgietWtGX6upUr86U\nNHNf6Fy56K8GaO3SMpd60iS681T+dMYoTdoCRNgwPV8+YPp07cZdsoQn1FWrgNq1+dj16/TRrFgB\n1Kmj3VxG5ccfeYPu2KE6WWmJ0qS1Z8YMurt27ACKFHH0avTFZGKke6NGwP/+x8cSE6moxMQw60Kr\neufHj1NRWbSIaVqKtChN2gKWLQNOnqRA0Yq5c5mfuHFjioAWYVP2vn3dQ0AvW8bPdN06JaAVxufd\ndxn93Ly56/tRPT25R+3Ywa5zAK1cf/7JmgVt2jBFVAsqV+Zn26MHNXdFWpQmnQk3b7K+7bp12vmj\nfvoJGD2akY2pT47LlzNifO9ebf0+RmTPHhaN2LDBPfx89kZp0vogwgjo8HC6qlz9Pp06lYfp4OAU\nn3FSEiO+r1+nFTBXLtvnMZkAf3/uCQMG2D6eK6GEdCZ07cquVmPHajPetGnsBjNtGvOfzcTG8kT5\nyy/6NmM3AuHhTL+YOZN+PqMhQpNeZCRw5w6v9P4dGclKTRcupBRmMP/MmZOBf3nyMGI9Tx4+N18+\ntkcsVoxXkSL6+OH1EtIifO83bqS9EhPZpS0ujt/l1D9LlgQuX+bn8eSTFGzmf+fJw02+SBFehQun\n/DtfPmMGEyUlAa+/zgjlMWOMuUatSEriIfp//2MktpnkZKBXL+DiRdbkzpPH9rnCw9ndbudOfrYK\nooT0Y1i/ns0d/v5bm9PinDmsw71tG6MmU/P115xn8WLb5zEykZHMMe/fn/54R2EycYM5cwY4dy7t\n5enJPM78+Xl5e2f8M3V7Q/Nm7eHB4JqYGJY1ffCAPxMTGSB37VrKdesWxwoI4IZYsWLaK29e696f\nLUI6KYmfw8mTDJQyX5GRKfeCWZCar7Jl+b5z5qSvMvXPHDmYYhcfz8v874QEfiYRERT0N2+mCP2b\nNyngq1blGJUq8apYkT/LlHFsml5MDKtyde3q+prftm008584wQOnGZOJrrnTp2lVsPa7mprJk+mb\n3rrVfUogZ4YS0hlw/z7w/PPMU9aiKfqSJfRBb978aHDExYs8rR44AJQubftcRiU+noVgatSwb8u6\nuDhGkB46xJ+HDwNHjgB+ftxsy5VLuXx8eNmrt3ByMgX1P/9wszt5Ejh1iteZM1yjpyc1jFq1eBUo\nkPm4lgpp82cTFsbPJyyMPshXX+Xvy5fnVaECP5+SJbULGMqM2FiaVC9c4Odx8mTK53P9Ov9OFSvy\n+1SjBj8jb2/7rA0ALl1i7Mjs2fxeuzJvvsmD0ahRaR83mYD33+ff448/bNeoTSagYUNGkX/8sW1j\nuQpKSGfAp59Sc5g71/ax1q1jUMTGjcCLLz76+44d2Y3mq69sn8uoiLB6U0wMrQWeOoYsRkbSZBYa\nyuvQIVaMKlmSkfMvvsjP254bujWYtf0DB1hgYu9e/rtQIfrvfH15gCxX7lGTa0ZCOjqan822bbwO\nH6abpXJljmf+fIze0CQ2loeYkyf59929m/ULihal4Kxdm1e1avpq3KGhrEcdGsqDjKty5Qq/F7t3\n89CWGpOJCkh4OKuz2eq+MZdG3rOH3213RwnpdNi3j77So0eBggVtG2vLFvpyVq1KP2I7OJgJ/ceO\nuXYjiSlTaE1Yv14b10FqHjwAgoL4d1u5koKtdm3g5Zd51amT1kznzCQnU5MMC+OhLyiIm2JAANsM\nNmpEIW4W0iYTi1OsXk0T9ooV1DobNgReeYWfjRb+RCOQnMx0nj17eP3zDyuFvfoq0KQJLz02/Zkz\n2ZN6927jH25sYexYHuzWrHn0d4mJjPguVgyYNct2P/2PP3LP3LxZ3wO9M6CE9EMkJgI1a7ITzJtv\n2jbW3r2sfbtwYfrBYImJPJ1+9x2L+bsqW7cyD3L/fqBECW3GvHCBfrA1a5gm8tJLtEjUrKm/9mQL\n48aNw8CBAwEAS5cuhZeXF8LDw9GnTx+rHjt3Lhwvv9wHQUHMFjhwgGbJXbs80LmzYNs2Co5WrXi9\n9JL9zNVG4MYNHmQ2buSVKxeFdcuWFN5aHRjff5/a5ooVritUEhIYIzB+PD+/h7l/n59pixbAiBG2\nzZWcTJ9/t24sSerOuOjXyXrGj+dpsGtX28Y5eZJF6WfPzjhae9o0mmDbtLFtLiNz6xZvtDlzbBPQ\nItSUhwzhRvHSSxT6vXtTYwoKYmpMzZrGFdBBQUHYtGkTAODgwYMAAH9/fwBAWFiYVY8xSC0M777L\nXr1161KbBHiA8fZmDfi+fak5u5OABhjU9uabdFtdvUohWr480x2LF+d9vmIFffO2MGkS6+1PnqzN\nuo1Ijhx8f598kv7nlScPD87z5lGbtoVs2VjkaPhwHsjdGSWkU3H2LEtx/vyzbeaaW7d4muzUKf0T\nJ8AT/qhR/NK7agqHyUQB0a2b9YE1J04AX35JM+Vnn1EAz5rFQJXZs+kPdBYTo0eqP/TChQuRP39+\nAICPjw+CgoKwaNEieP0bsWbJYyJAbKwP+vULQokSFBTNm9M3CLDW8uTJTH967z26AGbMYIlbd8TD\ngwe8AQP4HTp9mmb/KVN4MO/WjSZWa8pe5sjBQh9jx9LF5ao0bZqiTadH4cJ0aQ0bRoFtC5UqcZwv\nv7RtHGdHCel/EWHVm6FDH02PygqxsdSMu3RhsFhGDBlCAebKZfDGj6dA+PrrrL3uxg2+tnp1BkjF\nxrIM4bZtwDffUNg4m0kxLCzsP20YAO7evQvvVJFrERERiIqKsuixGzeisGaNN5o1M/fcjsD+/RQO\nvXqlBMRlz04rzk8/AX/9Ra1k0yZmELz1Ft0E7uzsKlyY93xwMC1f9erRF1q0KO/PrH4+xYrx4Ni9\nO3D7tn7rdjQ//shmI5cupf/7ChVonejRgy4/W3jvPY6xfr1t4zgzBjUM2p85cyhQPvrI+jFMJlbi\nKV368YJpzx5W2jp50vq5jM6uXbRK7NtnWbSnCLB9OwVKSAgPOuPGMQXJFfIlIyMjH3ksq+Eg4eHc\nrE6eZKDYyJGM1g4KSv9gOSKVY9DPzw/Nm/uheXNaeubNYyzEjRtsptChg3HdBPagSBH6Pvv1Y/76\nggV0HzzxBF0F3bsznz0zmjZl/EXPngxidEUrWdmyrB/x+efMaU6P2rVprm7Thvf1wxHhlpIjBw8E\nn3zCA7urV3hLDyfTR/Thxg1g0CDmRNuyUX35Jf2js2dnrOmZTCzkMXq085hps8qdO7QkBAZm3jEs\nOppNS154gVpN/fo0Q86cyZvSFQT0w1o0AHh5ef0nuKOiolCgQIF0H8uXzwsbNkSiYUNg0KAoFCtW\nAH37euHTTyNRuzYQFXUHBTJInB4xYsR/l5+f33+PFyrEFMPVq6ldT5tG7WfyZAb/uDvFivHzOXmS\nZTF37aJgevttHrAzO1uNGkX/97Rp9lmvIxg0iAfw7dszfk7LljxIvvYai9NYS4sWdHdNmWL9GM6M\nEtJgU4t33mGeqLX8+itPlStWPD44Z8kSFmHo3t36uYyMCLWIdu2A1q0zft65c6w4Vro0NcFJkxjw\n1L+/6zXbCA8Px9KlSzFz5kxERkYiLCwMnTt3Rvi/zuPw8HAEBASkeezs2XCIBGDZss6YMSMc778P\nfPFFOMaMCUDPninPO3/+PAKsrLbj6cmI723bqDlu305h9OWX9Pm7Ox4etOT8+Sdzd6tWpQCuW5f3\ncUbNIMz+6ZEjmYfuiuTMyZKogwY9/tDSty+D81q2ZKqktUyYwPlu3LB+DGfF7YX07t08EQ4fbv0Y\nwcH0Ya1dSy0lI0wm4Ntv6Q90Np+qpcydy/c5Zkz6vz9xgtG2detSYzlyhP7mRo1c0zQIAB06dECH\nDh3g4eGBu3fvwsPDA77/ngiDg4Ph5eWFatWqwdfXF8nJwNChwZg40QtLl1bDxIm+GDoUKFQoGAUK\npDzv4dfaSu3aLDKzezctIZUrM2jnyhWbh3YJChWieXf5cqZnjh/Pamc//cQCPQ9ToQJ9t6NGadt/\n2Uh07MjCQZs3P/55I0eyemPfvtZ3uapYkZaMoUOte71TI26MySTy6qsigYHWj3HqlEjFiiJbtmT+\n3GXLRGrU4LyuyNWrIgULivz996O/O3pU5I03RAoXFvnuO5G7d+2/PiNjMomsWydSs6bIa6+J/PWX\nbd8TW2/tmzdFBg4U8fYWGTRIJDLSpuFcktBQkTZtRJ59VmTUKJHo6LS/N5lEWrcW+eorx6zPHsyd\nK9KwYebPS0gQadVKZNgw6+eKihIpWlRk3z7rx3BG3FpIb9zIGywx0brXx8SIVK0qMmNG5s81mUR8\nfUVWrLBuLmegUyeRIUPSPnbkiMjrr4sUKSLy/fePbmQKkUOHRBo35ndx5UptDnFanb8vXxbp3ZuH\nrx9/FImN1WRYl+L4cR5AixQRmTAh7Wf0zz8ZH1xdgcREER8fkW3bMn/utWsiJUrwMGotv/wiUreu\n6yo66eG2QtpkotaycKH1Y/Tty5vTki/M6tUiL7zgul+utWtFypXjwUWEgqd9e25c48aJ3L/v2PUZ\nkStXRHr2pHVhyhRqG1qhtZHsxAmRDz/k33jNGk2HdhkOH6bmXKKEyPTpIvHxfHzGDJHatUWSkhy7\nPr0IDBQJCLDsudu2cU+4eNG6uZKTuW///rt1r3dG3FZIL1lCzTY52brXz58vUqGCZWZbk0nkpZdE\nFi2ybi6jc/++SOnSIps2iZw7J9K/v0ixYtS8Hjxw9OqMR3KyyM8/09UycKDInTvaz6GXJ2v9epHy\n5Wm6PHdOlymcnj17KLTKlqUwSUigSXjCBEevTB/i40WeeUZk1y7Lnj9uHPfDuDjr5tu5k4cedzn4\nu6WQTkwUqVSJG441nDpFE1ZYmGXP37BBpHJl6w8ERmfAAJHOnem7LFBA5Ntv3ecGyirnzlE4v/QS\n/fR6oWe4SVwcfbAlS4qMH++6GqKtbNki8vbbItWri/z5J++N8HBHr0offvpJpHlzy55rMom0bUvL\njLW8/jrdZ+6AWwrpX38VeeUV60zPsbEiL75Ic5YlmEwi9eqJ/PFH1udyBvbtE3n6aZps336bJlzF\noyQni0yezMPduHHWx0FYij1iQs+f54Gjfn2Rs2d1n84pMZl475csSctdgwau6fKKjaWZf/9+y55/\n5w5dJ3/+ad18x4+LFCrkHgGobiek4+Jomtmxw7rXv/ceA6QsvdGCgxkQ5IraRmioSN68vNncLeIy\nK5w+LfLyyxRmp07ZZ057JW4kJ9OMW7CgyMyZrimAtCA6WmTwYJHs2UXefNN6U6+RmTiRGrKlhIXx\ne3P8uHXzde8uMnKkda91JtxOSE+cKNKypXWv/fNP+uOycnrz8xOZM8e6+YzKvXv0O+fN69pmfFtJ\nShL54QeaOSdNsu9Bzd7ZlceO0azbsiWjeBXps3ixyJNPijRtallEtDPx4AFTpA4ftvw1s2aJPPec\ndVkfZ8/y3oqIyPprnQkXLamRPtHRLMc5alTWX3vmDKthLVpkeTnP7dtZhN7WtpdGYs0aFia4cYN1\njZcudd3CLLZw5Qq7oG3axFKSH33kGiVOM6JyZZbPrFaN17Jljl6RMenYMaVz2xtvsOpedLSjV6UN\nuXKxU11W9teePVlI5733st7spVw5oH179ghwaRx9SrAnI0eKdO2a9dfFxopUqyYybVrWXvf++7YV\nSjESN27QzF++PE34n34q8s03jl6VMdm0idHt337rOCuDI2/tnTv5PRkyREX3p8fFiywSc+QIU/Ce\necb6IFajER1NX3FWTNgPHjA91dI4n9SYP8sbN7L+WmfBbYT0rVs0jVgT4PL++4wmzIq/LTyc/hZX\nKP6wYQNTrL76innQ+/aJFC+uNuCHSU4WGTGCAnrzZseuxdHn7+hoHoh9fRlgpkjLsGEpCsOmTSJl\nyoj06OEaptuJE5nxkRVOn2alPWsyHvr3p9LgqriNkB4wgMI2qyxcyMCoqKisve5//xP5+OOsz2ck\n4uNFPv+ckakhISmPN23KlAtFCvfuMXf4nXdYHtXROFpIi/BQO2ECi1ds2uTo1RiL6GgedM25xdHR\nPOA984zI1q2OXZut3Lgh4uWV9VKyM2aI1KqV9cyHq1f5ublqZonj72Q7cPkyTSJZ3TzPnaM2bGla\ngZnERGpTeubB6s2ZM6zs06oVrRBmtmxhkQZzNSWFyIULLA/bp49xPhcjCGkzISHUFK0xZ7oyc+Y8\nmimydi2Dr4YO1bYCnb3p2jXrxVtMJpbHHTMm6/N98onIF19k/XXOgHHuZB356qus+0+Tk5nTaM3G\nsmIFc6OdlXnzeDiZPDntBmIyMY3ot98ctzajERrKA9nEicZKPzKSkBahybtyZW6mKhuAJCXxM3nY\nH339ukizZix446z556GhrMiY1b/1+fPce44dy/rrvL1dM2/aWHeyDty9K5I/P7XprDB9ukidOtal\nzbRoITJ7dtZf52iio0XeeotdvdKrprZ2LTcVV8z5tobly0UaNbKtYYBeGE1Ii9D82bChSIcOKTXe\n3Z0FC7jPPHzAM5mYtte0KdO2nA2TidYla9wc06fzgJJVs3fnzixF7GoY707WmClTRDp2zNprLl+2\n7jRnfm3+/M5XFvPAAZ58e/ZMf+3JyYxwX7bM/mszIr/+auy2eUYU0iIs4tGlCy1Nt287ejWOJymJ\nJYo3bkz/9/v3M2hz4ED9q9RpzfTpbLKTVZKTefgdOzZrr9u3T6RUKed2E6SHMe9kjUhOplaYlUAM\nk4masLWVbEaOtC5AzVGYTKwUVbAgm4ZkxMKFDOowkknXUfzwAwNVTp509EoyxqhCWoT35ahRIs8/\n79qpM5Yybx7dSBndW7dusWGHn59zfV737llnxRRhdkyBAuy+lhX8/FyvBLNx72QN2LiRJpesCJb5\n87l5WBMAlJTEzfvgway/1hEkJLDdpp/f4zsaJSSwtKm7R+iaTBTQlSqJXLrk6NU8HiMLaRF+lsOG\nsdqUEaLhHUlSEu+v4ODHP+d//6OmaGm3KSPwwQciX39t3WunTcu6y3HNGqb9uZIyYew72UZataKW\naCm3bjFdZM8e6+Zbt06kRg3rXmtvoqJEmjRhgMq9e49/7h9/MFrTlb741jBsGA99zqDNGF1Im/n6\nawqof/5x9Eocy9y59NdnxsqVvGedJXjz0CFmg1gTLJicTAVi/PisvaZyZZGgoKzPZ1Sc4062gnPn\naC7JSsGNN98U+ewz6+ds1465fkbn4kVaC95/P3M/l8nEmsyrVtlnbUbl66958zuDgBZxHiEtwpSb\n2rWtM4u6ComJrMewZUvmzz16lH7qkSOd4+Bctapl7ys9zGmwWWlM88svLIziKrhs1eXp04EePVhP\n1hLWrmXt4a+/tm6+69eBkBCgSxfrXm8vDhwA6tblZzNtGpA9++Ofv2UL8OAB0KKFXZZnSCZOBP74\nAwgOBgoXdvRqXI9Bg4DXXwdeew2IjHT0ahxD9uzA0KHA779n/twqVbhXrVrF2tcJCfqvzxa6dQPm\nzbPutT4+wMiRwHffWV7b+803gcOHgaNHrZvTcDj6lKAHDx5Qi36cn/Xh57dpY5vPdfRokV69rH+9\nPVixgqfSrERot2iRNZeBqzF3Li0JzmaOdbZb22RiVcC6dZ0vM0Ir4uOZMWBp3ev79+nS8/dnf2aj\nYs54sbZEclISM0sWLLD8NRMnMiLeFXBJTfqPP4B69XgKs4Tx44EcOYDGja2bz2QCZs0C+vSx7vX2\nYNIkoF8/YN06oF07y15z4gSwfz/Qvbu+azMqW7cCn39O7aZECUevxrXx8ADGjQOefZadooyuHepB\njhxA7960AlpC7tzA8uXsQPbyy8DFi/quz1pKlgR8fdlBzxqyZeP+NXAgEBNj2Ws6dwYCA4F796yb\n00i4nJAWAaZOZVtJS7hyhebM77+3fs6dO4FnngFeesn6MfQiKYmfxcyZwI4dQK1alr/2zz+BTz4B\nnnpKv/UZlVOn2Gpy/nxuggr98fDgYfeJJ4Avv8x660JX4N13qWTcv2/Z87NlAyZPpoLw4YfA8eP6\nrs9aune3zJSfEa+8Qjfd2LGWPb9oUcDfn3uYs+NyQnr7diA+nn8gSxgyhDdG2bLWz7lgARAQwE3G\nSCQlAb16AXfuUECXKWP5a6OjgSlTgLff1m15huX2bfrgR42y3rqisI7s2bmxbtlCP6S7UbIk0LAh\nBXVW+Phjao+NG9MfazTatwe2bQMiIqwfY9w47kmWWgz69qVy4uy4nJCeMoUnSk8L3tnevUBQEAW1\ntYgwgKNtW+vH0IPERKBrV+DWLWonXl5Ze/2CBYCfH1CsmC7LMyxxcfxbvv46TY8K+5M7N7BiBfDz\nz8CyZY5ejf3p149BnVm1JHTrRq26aVO6qYzE008DzZszQNdannmGVsEvvrDs+Y0bMxDRaJ9FVnEp\nIf3PP4zAtUT7E6Epd9QoIG9e6+cMC6M5uFIl68fQGrOAfvCAm5w15uqZM43tY9cDEUbLFi/O74XC\ncRQvTkH98cfA3387ejX2xd+fPvkdO7L+2o4d6Ytt3ty61+uJv79tQhqggN69m1p5Znh6cg9zdm3a\npYT0zz8z/N4SobtwIbUmW825K1YAbdoYx9SdmMg0sNhY6wX0oUPAjRs8kbsTEybQVTJ3rmWWGIW+\n1KgB/PADTaV37zp6NfbDwwN4/33gp5+se32rVvT/tmtHt4FRaN4c2LSJe5S15MpFs/dHHwHJyZk/\nv0cPYPFiuu+cFZfZiuLjgSVLaOrOjNhY5mZOnGj7ZrxyJYW0EUhMBN54g5/F0qXAk09aN05gIH3Z\n2UQqz9oAACAASURBVLJpuz4js307g1ImTQJy5nT0ahRmOndmvEfv3u4VSPb228CFC3RXWUPTpsCi\nRdwPQkI0XZrVFC3KjJudO20b5/XXgXz5gF9+yfy5xYoBjRoxCt5ZcRkhvWkTUKQIULFi5s8dP56R\n2K+8Ytuc588D164x6tDRJCRwQ0tM5GHFWgEdG0t/dM+e2q7PyNy+TffAr78ycEdhLH78EQgPZ7yJ\nu+DlxWDWJUusH8PPj4f1Tp1Y/MQItGhhu8nbw4OH6ZUrLYuCf+stxuU4Ky4jpBct4gkrM65f5xfX\n0lD+x7FqFdCypeM1zsREpjgkJ9smoAHeQAEBQKlS2q3PyIjQ79mlC81xCuPx1FM0WW7YQFeMu/DG\nG7anENWvD/z2G4MhjxzRZl22YGvwmJlq1RiMNnVq5s997TXg2DHg8mXb53UELiGk4+KA1auBDh0y\nf+733zPFwZaUKzNGMHWL0H+VOzc3shw5bBtv2TLg1Ve1WZszMHMmc+VVoJix8fGh0Orene4cd6BJ\nEwqXf/6xbZxmzRj13awZcO6cNmuzllq1aMK/cMH2sYYPp5Uls4IlTz5J//zChbbP6QhcQkhv3Ai8\n+GLm6ULXrjEoaNAg2+eMjGQd7IAA28eyhVGjGGE+ebLtAjo+Hli/3vEHD3sRHs6iGdOns4CGwth0\n7w5UqAB89ZWjV2IfnnySGvCiRbaP1bkzP7eAAODqVdvHsxZPTx4W1q2zfaxKleh7nzw58+d26eK8\nhU1cQkgvWkS/S2aMG0f/hBa5v+vWUeO0tIGHHsybR1/LmjVAnjy2j7d5M4v3Fy1q+1hGx2QC3nmH\nOfLPPefo1SgswcMDmDGD5luj+Fj1Rkvh8u67LPAREGBbURFb0cIvbearr+ifjop6/PP8/Hg4OX1a\nm3ntidML6dhYCqn27R//vOvXgTlztNGiAWDPHqB1a23GsoaQEGDAAH7ZtSo4smxZ5p+jqzBzJk2o\nH3/s6JUoskKhQhTUvXu7R31vPz/g0iXg7Fltxhs8mClan3xCN6EjaNKE2RSW1uF+HBUqMC5o4sTH\nPy9bNipyzqhNO72Q3rABqF49c+1v7Fiay7QQaCKMgG7SxPaxrOHYMfrnFiyg5qsFyckMhLO0+YYz\nc/06MGwYC/Y7OuhPkXVatWJMyfjxjl6J/mTPzoBYLUzeZkaPZsngnj0dk9bm5cWGG1qlhg0bxgCy\nzNqcmgPxnC2Vz+mFtCWmbq216NOnGajliHSda9doLvrhB20DvHbsYJUnLQLqjM7nn3OD0uqAo7Av\nHh5Mxxo/nmmQrk7HjtqZhwF+fr/+yiCyb7/Vbtys0KKFNn5pgBaxdu0YRPY46tRh3I0Ra5s/DqcW\n0jExDHTKLKp73Dhq0cWLazPv9u1sDWdv7t+naad3b+3bR7qLqXvrVv793CX4yFUpWxb47DNWnnI2\nzSir1KsHHD0K3Lyp3Zg5c7Ja4qxZ2mrplmL2S2v1t/vf/1hx8nG+dg8PatO25J47AqcW0uvXM6S/\nUKGMn3P9OjB7tnZaNACEhgINGmg3niUkJfEL5uvLL6SWiLAij6ubupOT6YOePJmWEIVz8/nnjIDe\nsMHRK9GXHDlYNeuvv7Qdt1gxppF+8AGwb5+2Y2dG5cpAuXLaBXKVKUOLQ2badIcOrJPhTGR39AJs\nwRJT96RJ2mrRADWxgQO1G88Svv2Wp9/p07WvE37wIDc7Vzf//vYbo+C1CPiLiWEK1+XLzPu8fTvt\nz4IF2ZP6YXx82PikQIGUq3Rpfj8rVuT/jcaDBwxcunyZEbLXrvHngweMqo2N5VWqFE2oOXLw+5Qj\nBzfixEQepAsV4nstUQIoXx7w9rbtu5wjBzs/DRrE+BBXji9o1oyHEa0taNWqsQxwu3ZsXGEvF56H\nB+OIdu60rEqkJQwZwiqSgwax0El6VK9O3/X5887j2vMQcU5j0YMH3NjOneOGmB537zKXbs8etjnT\ngqtXgapVuRHbqwnDihWMxjx4kBub1kycSFP6l19qP7ZRiIkBnn2Wpq46dSx/XXIyhe3Bg8xHv3eP\nFpyICN7kPj5A/vz8DhYqlPLT2zv970dCAjeJiIiUy8ODB79Tp5ivXbEirzp1qHHUqJH1euIeHh7I\n6q0twvvpwAH67Y4eZZDitWs82Ny7x3uuWDH+9PZmCmKuXFxfzpz8vOLj+T7j4xlBfOMG7xfzPRMa\nCpw5w/ddoUJKS9RatbiJZiWtUYRWrd69mVLnqly6xM/mxg19DiNTptDltXGj/WoGTJxITdraRiLp\n0bkz3QOPy9p45x2Whe7XT7t59cRphfTataywNWdOxs+ZMIE9o7UMu1+8mB1mVq3SbszHcf48ULs2\nK6rVrq3PHI0a0TLQrJk+4xuBqVOBEyfYp/dxJCTQ9Ld1KzsIibA6kq8vN8kaNShYSpXSfrMU4SZ8\n6hSvS5do4jx+nAfDtm0pyBo0yLxwjSVCWoTCcuvWtO+3dWsK4SpVgOef50Eku8Y2NxEeUM6c4Xd8\n507eq0eP8vNt0IA18Zs0ebw7C2DOdM+ePEi5cnOUKlUY8KXHPmAyMWq+ShVtSiZbwo4dVD60NLXv\n3s06/GfOZHx/LlzIPXzNGu3m1ROnFdL9+tFk9tln6f8+OZma07x52jbA+OgjmoQsbTxuCwkJDFDr\n0gX49FP95ihQgKZMLy995nA0Dx5Q0ISEUDN9mCtXeMOuXk2B/OSTLB3bsCE/f0eboB88YOP6PXvo\nTzt1ig3tW7XilZ51JSMhLcL614sX8ypYkCZpPz9e5co5tu1qfDxrTIeFMfo3JIRWhWbNWIP5pZfS\n33xff53r/+ADuy/ZbowaRXeNXrn9t2/zIPrTTwxQ1ZuYGB7AIiNt6zfwMHXqMB+8bdv0fx8ZSR/2\nzZvWtfK1O+KkVKwocvBgxr9fuVKkVi0Rk0nbeX19RXbu1HbMjPj4Y5HWrbV/D6nZvVvkxRf1G98I\njB8v0rFj2sdu3hSZOFGkWzeR/PlFunYV+fNPkYgIx6wxK1y/LjJ7tsh774nkyyfy+usia9eKJCam\nPOfhW/vkSZHhw0XKlRPx8REZNEhk3z59v1taEB8vsnmzyMCBIlWrijRpwve9a1fate/ZI/LMM3y+\nq7J8uUizZvrOERoqUriwyKVL+s5j5oUXRPbu1XbMBQtEXnnl8c+pV0/kr7+0nVcvnFJIX7ki4u0t\nkpyc8XMaNRKZN0/bee/eFcmd2z4bwbJlIqVL6y80xo0T+eADfedwJDExIsWKiRw6xL/bsmU8+OTL\nJ9K9u0hQkEhCgqNXaT2RkSI//yxSp45I0aIi330ncvEihXRCgsjixbwXihQRGTVK5MAB4wvmxxEe\nLvLttyIVKog8+yz/ffEif9e4scgvvzh2fXpy/bqIl9fj9z0tGDOGQswe90WvXiLTpmk7ZmKiSKlS\n/K5nxDffiHzyibbz6oVTpmCFhNAUmVHg1t9/0/9oSevKrLBrF1Czpu2NLDLj/HnW2V24UJ9AsdQ4\nIp3MnsyZw9rcs2YxqnjSJJrBLl9mtLe/v3M318ifn9+VXbt4X8THs9kMwGI3U6YAffrQvz10KM2Z\njjRn20rZskxBPHWKzXL++YfxAo0a8Xv83Xd0dbkiRYrQ9XLypL7zDBwI5Mtnn0DSWrW0T//Knh34\n8MPHlwpt3pwBoM6A0wrpx1XbmjyZ7Ru1FqbHjtEvpifx8UwrGzpUv0AxMyYThbQjCrPYg9BQxg6E\nhVFA79nD4KgePYC8eR29Ou0pUYIHDnOQ14kTfJ8VKuh/sLQ3Hh70PU6fzoyLDz6gr/3qVeDttx3b\nQEJP6tdnwJWeeHryADt/vraVztKjZk19crT79GGcybVr6f++WjWmD4aHaz+31jitkG7UKP3fRUQw\nzebdd7Wfd/duRvXqybhxjKy1R+OHU6eYT1iihP5z2QsR5pP6+bGCmrc3ta3Bgxk85ookJbHaUoUK\nDIbZvp2P//MPrQatWwNvvklt2hV58kkWqVi2jD2GQ0IYNDpkSMabtLNSrx4j4fWmYEFmxUyfrm2l\ns4epWpWWw/v3tR03f34G3GaU3uXpSYXLGbRppxPSFy/yD5pelC7AxPy2bYHChbWf+9gxfQt+7NrF\nL9WsWfYxSW7f7jqm7uRkRitXr85KVL17899ff+3YdqJ6s2kTtYKFC7nhTJrE2gAA05F69+ZhrFy5\nlGp10dGOXbOefPwxMxZWr6ZVqkoVdovTU9DYE3sJaYAWtsqVmSalFzlyMM0vLEz7sfv3Z4ZAYmL6\nv2/WTAlpXQgJoZaUnhAT4aalR5J6YiJNI+YNUGsSEmiimTAh87xQrThzhr59Z2fTJuYvr14NfPMN\nU3jq1ePPzp0dvToSGBiIwMBADB48+L/Hli5diuDgYAQGBmb5sTlzlsLfPxgDBwbi22/ZC9zXN/25\n8+ThYeXQIfriO3bUrrmB0XjqKfaMX72aJSKPHuW9+9xz9FffvevoFdpG5cqs2pZZxyetGDGCbiI9\nzd56+KUB7tVPPZVx2dgmTVIK7xgZpxPSmzdnbOres4c5rzVraj/vmTM0deuVVzd2LHP3MitzqiU7\nd1LDclbMMQL9+rFd3dy5zO/09AR++YUlFI2QBxkcHIzGjRujT58+CA8PR3BwMML+VR38/f0BAGFh\nYTh48KBFj40bdxCffgq8+KI/+vQBSpcOs8jyUqoUfY2DBzOwpkcP+uVcjb59Wa8/IYGuo8mTeUCJ\njOTGPXs24zGckWzZaAk5etQ+8+XKxd7r/frpZ4HRS0gDrC6WUcGr/PlpYTl0SJ+5tcKphLTI44PG\n5s9ntRk9TMXHjmVsYreVkycZifjTT/aLvBVhYNFzz9lnPi25f58m7XbtGKV57Bh9kubPzmQC/viD\nPikjEB4ejqCgIACAj48PwsPDsXDhQnj9Wz3Gx8cHQUFBWLRo0WMfK1rUBx9/HITRoxdh5Egv/Pgj\nUKmSz39jW8qrr9LKkDMnfYJbt2r4Zg1AxYr8Xq9cmfJYqVJs77pqFYVOnTo81DsjVarwO28v/P15\nad3Yx0zNmvoF+nXqBAQHs1BLetStSzejkXEqIX3uHIVLhQqP/i4piQ039NqY9fJHm0w8+Q8frl19\ncUu4dYs/7WVa1wIRBgdVrsz1h4ayAtzDkcs7dtDEa05FcjR9+vRBnz59AAAHDx5EzZo1ERUVhQKp\nSplFREQgKioK3qly7lI/duwYtZl79yLQvn0UGjRI+7z0GDFixH/Xli1b0vwuTx4eCmfPZne17793\nrZaP777LzflhatXi96N/fwYWDh0K3Llj//XZgr2FNMADzpIl+gi0Z5/lQVEPs3O+fLSuzZ+f/u/t\n6eO3FqcS0ps3UwtIT9sMCeFpOT0BrgXHj+sjpGfN4pfT3sXezVq0s+TMRkQwQnnyZNbdnTs34+DA\nefNo6jbaezt48CBq1KgB33+dx2KhVFy/nnEYXbrQvG9pHe3UQtrPzy/d5zRuzJrZy5axroCrBJW1\nasXo5PQEsKcnvx/Hj7NpSNWqzlPHGXCMkPb2prWvd2/thekTTzDD5OJFbcc18847PIymh9KkNcYS\nU7de6KFJX71KE1JgoP3b7DmTqTsoiFpxsWJsOPG4YLf4eHby0fO7YC3BwcEYPXo0AMDLywuR/0b/\nmLXqhx/z9i6Av//2wrp1kQgKAmrXfvR5d+7cSaORW0OpUsC2bdyI/f2dI3c0M3Ln5l7xOOGbLx8b\nr8ybx6jwt96yX0CWLThCSAM8xJUrB4wZo/3YPj76fe8aNeIhPz3fc/nybLN65Yo+c2uB0whpsz86\nvaCx2Fi2c9QrkjchgV8grfqemunfn2a5qlW1HdcSTp7UL1JdK+LjmT5jPgmPH595If5t2xgspHc+\ne1aZOXMmBv7bhDw4OBidO3dG+L+7Unh4OAICAtI8duZMOEJDA3D3bme0bx+OF19M/3nnz59HQECA\nzet78kn6anv3Zk9eewUm6UnbttwXMsPPjz56b2+gRQvj++iLF+eeZHZZ2QsPD7pIpkyhFUJL9BTS\nnp4scDN37qO/8/AwvjbtNEL6zBmeesqUefR369YxJ7Z4cX3mPneOc2sZKbxiBTdCR/VwNromfewY\nOx5duMDexpbKoTVruNEaiaCgIAwePBjly5eHt7c3PDw8/jN5BwcHw8vLC9WqVfvvsXXrgrF+vRdE\nqmHPHl/kzZv+81I/phV9+7Kgjr+/8wZWmWnVilaY2NjMn5s7N825X31FH/3IkcYtL+rhwYDJ06ft\nP3fJkkzL6tNH2wh5PYU0wIP+H3+kb6qvW9fgfmlHFw+3lPnzH+1kZKZDB5HAQP3mXrtW5LXXtBsv\nKkqkRAmRLVu0GzOrlColcvas4+bPCJNJZM4ckYIF2SwhK80gTCaRsmVFDh/Wb316ExMjEhAg0qWL\nbQ0ObL2116zh3yA42KZhHM6rr7IjXla4coWva9ZM5OpVfdZlK2++KTJ3rmPmTk4WqVtXZOpU7cZc\nuFCkfXvtxkuPBg3S/y5s2cIGNUbFaTTpjHzCd++ymEWHDvrNfe0a/aFaMWUKUwMcVUjk/n2mJKRn\nlXAkiYmswTxlCiNwe/bMWvDXyZOM8neE+0ALEhLYN7xQIeYzO7LxR4sWrOD22WcpZUadkY4dWc43\nKxQvzj3F35/18/fv12dttlCqFAvTOAJPT8bRzJmjXepUuXL6x0K8/TaDCR+mZk26O+Li9J3fWpxe\nSC9fzgCR/Pn1m1tLIX3pEquKDRqkzXjWcPky80TtHaz2OKKiKBguXGAU/7PPZn2MzZt5+DFaVLcl\nmEw0yd28Sd+ZpRHceuLnx9SbDh3ocnBGXnmFqZlZJVs2xkNMmsTykRml8DiKZ55xbC32KlXojvrm\nG23GM5u79UwDbNGC1cceNnnnzs34nH/rBhkOpxLSzz//6ON6R3UD2grpkSOB995j2zlHcesWNU6j\ncO4c/ULPPcdiE08/bd04ISEZl8Y0Ol98wU33jz+MIaDNNG7MNMEWLRynudlC5crU9q5ft+717drx\n8Pfll7yMUqmsVCnHN0wZPpyR8WfP2j5W/vzU0PWMri9alN+HkJBHf9ewoT71w7XAKYR0bCw3iPLl\n0z5+4wZzPFu21Hf+q1e1EdInT1II/Rvk6zBu32aXGyOwfTvb7/XvT63FWgElwsjuV17Rdn32YNYs\nWhBWrWIVMKPRujWbLLz7LvDggaNXkzU8PXkAtKW9Y9Wq3GcuX6ZCEB+v3fqs5ZlnHH9oKlyY7pAh\nQ7QZT+/gMSDjiP+yZYG//9Z3bmtxCiF98iQF9MM+ukWLGMGpd5cjrTTpYcNYzvLfKo8O4/ZtNo93\nNL//Tp/h77/bXszl1Cl+D4yWepUZe/ey6tV33zEFyKgMGMCCE336OF9lspdftr0Hc8GCwIwZNJW2\nbOn4oi8lSjDS2tF88gmzALSIjq5XT//Wom3bslzswxYRR+WeW4JTCOmM/NH2MHUD2gjpAwf4Re7f\nX5s12YIRNOkff+Tfb8sWy9OrHseePc6nRUdE8PsbGGidD96eeHiw2tv58xk3LDAq9evbLqQBpmAu\nXkytq1Ejx7a/zJ+fwW2OThPLlYt+6c8/t/3wlpiof1GRChV4GN67N+3jzz9POWPEA6jTCunwcPoy\nGzfWd24R+rNsFdL/+x99WkbobexoIf3tt8DPP7N4hla52mFh6ccsGBURmo+7dAHatHH0aiwjZ05G\nnX/xhXFNg+lRqxZrEsTE2D5WtmzUqJs1Y+EXR1Wq8vRk7Ma9e46ZPzXdurF95urVto3j5WWfOupt\n2zLgODWFC/Nva23sgp44rZBet443id5pKpGRFKy2FDLZupXFWHr10m5dtuAoIS3Cg8qCBfQfa2ma\nPniQBW2chQULWFBGr85CelGhAtuqfved8fvwmsmVi4FBWh0sPDzYn7t+fWrUjtrY7SXUMiNbNmZV\njBxpmyaaP799WqeahfTDazWqydsphPTRo49qSWvW6NM3+mFsNXWLMLBi5MhHuzU5CkcJ6eHDWSVp\nyxZGWmqF+WbTsPCWrly9Sl/e3LnG6HedVd55hxrc9987eiWWU6CA9qUsBw2iFunvb/8SnQCFtFH6\ngbdpQ3P12rXWj2GvQ0eNGgxGPnky7eNVqhizHK7hhfSDBzypliuX8lhcHH1M6dXx1hpbhfSaNQwy\nMUpvY8AxQnrcOPrzpk7Vfu4bN6iVOtrPbinDhjEq1h6HTD3w8KC7IiSEFiJnoHJl7YU0wL9l+/Z0\nu+nVEzkj8uc3hiYN0Pz+1Ve0MFirTdtLk/bwSN/kbfZLGw3DC+kTJxhUk7rwxo4dTIuwR5S0LULa\nZKI5c9QoYxUOsbeQ/uknYPp0Brpk1F7SFs6e1a9Fqdbs3MkuXR9+6OiV2EapUmybOWCAo1diGXoJ\naYCCqWlToEkT+2q2RtKkAR5WYmJYMMQa7Gm+b9v20eIlytxtJen5ozdu5A1hD2JirE91WLWKFoBW\nrbRdk614eNgvgG3xYgYbBQXplzJy9uyjOfT/Z++842s6/zj+vUmMmJHYOxFqk9ojpEKpraGoVWq0\npUpL0WpRsyhVW6zaicQoip/E3iJBbJKgFTORkIis+/z++PTITXLHOeeedSPv1yuv1rlnPPeec57v\n891aRK+HmXv2bFQ5snW++QYmQ2PFIbSGuzvRv//Kc26dDqb/jh2VzaOuUEEbOdscdnawLIj1TSul\nSROh4uKBA5mDCWvVQsS+1iK8c4W0BRIS4GsRw+zZ8N9prUxlQoIyYzp5ErW4fX1RqEAuHj2Svo2o\nHOzeDV+8FntdiyFfPgSQff+99ia2rFSogMWcXOPU6SCcChRAzXklKpMlJkoTsS4lPXsimFdMu08l\nNemCBdGj3rBFpYsLXBZa6ymueSGdNWjsyRNUZ2rcWJnrp6WJiyA/dw7BJHJXQxODTif/pHrnDl7Y\nTZvkb3hx65a0DVDkQK9HZPvIkdA4cgoff4xFrFgTp1IUKYJqdnIKATs7FOaJjIR/Vm4cHLRV3pcI\nbr0hQ5ABIBSlfexeXghiNUTNxiWm0Px0kVWTDgpCQw2l6hunpoq71qJF8DtqyRfNIbeQjolBrefp\n05WxeDx9qm4tdD7s3o08Y6UsQEphZ4fFx4wZao/EMk2ayGfy5nB0hJtr2zZE78uJFoU0EYJkL17M\nHj1tiaJF0dVQqfrorVtn1/i1UBM9K5oW0snJCDQybKmopKmbSJwm/fAhNIshQ+QZk7XIKaTT0oj6\n9YOZf9gwea6RlSdP5AlIk5Jt2xBEqDXXhxR07460MqEtIZUmNRVBk3JTogSyOmbNkvc30aqQzp8f\nhXr++EPYcXnywF2gVMnV5s0RPJaUlLFNCzXRs6JpIf3sGV5+ThtljOjCBWnKSPJFjCa9fDn8jmrX\n6DaFnEJ68mSUKlSyFWfp0pgYtcq1a2gkokXXhxQ4OBBNnKi9do5ZUdKcWr062nz26iVf+VAnJ202\nZCEi+vJL9G4W6t/18lKuilqhQnDFGS6kcs3dAsmqIUVGYpVlmDMtN2lpwoT0mzcIlNJCjW5TyCWk\nd+yAxrh1q7Jm/nPn8MJpFV9fWFXkro6nJh9/jCh+tRtPmENpn2eXLrAo9e4tj8b79Kl2WmdmpUwZ\nfP/Vq4Udd/myst8pq18619wtkKy+xrNnETqvJELN3Vu3ojyllqON5RDSd+7ABx8QoHxRkZQU7VRz\ny0pqKqqsmXJ96PV4zm/fJrpyBea3q1eJ7t+HwFMjajopCRasu3cxpitXML6HD023qixRAj6+wEBl\nxyoEV1flhdrUqXg2f/hB+nO/eYMIe63yzTcoXiQkO4YxZV1CWf3SWtSkNdRePjtPn2bWpNUQ0kLM\n3YwhYGzOHHnHZC1SC+nUVJj3p0xRp4pWSop2tdTjxxFIV7EimoCEhkLo3byJ4hpPnsAylJaGlJCI\nCCzwTp+GqbBaNZj/2raFebNZM2Q2SBHNnpqKMZ05Q3TpEn7H//0P2x0dkaZSoAAWyvfuQUBXrIix\nt2uHZ6hFCxQKadKEaOBA+GI/+8z6sclBQoJyAacc9vZwAwwahDiVDh2kO/ebN9ouK9ugAZGnJ9H+\n/ehJzhclhXSLFghy437LXCEtkKzm7rNnifr0UXYMQjTp48dxs7UewSu1kJ49GzmGw4dLd04hpKZq\nU5N+8AAR7gkJ0DTbtYPwq1sX/ukqVdAX2Jw2lJSESSMigigkBEJ08GB0dmrSBGludevyH1N8PKKP\nd+xAERIvL6KyZSH869Uj+u03vHOm0sQYQ8GJe/egXV+7hvt/8SLOdfAgzLvt2mkvs0GtQCsXF1Rm\nGzAA5lyperlrXZMmwqJk5Ur+Qlppy1HhwlhknjsHrbp8edRdSE/XzvOraSFtaO5OSoLmoXSnIyGa\ndEAATL5az4OtXVu6SkUhIURLl0JDVCNyOT0dL7ZWXqiYGFRZ27wZwjUmBlWYBg0Slybm6Ahtulo1\ntEckQtTshQtEwcFIdStVimj0aAhsU5XkQkLgH9y2DcL0k08weQqNitfp4NstVozIwyNje2oqtPEb\nN4i++ALv65AhRD4+0Ki0ENWuZjT0Bx/gN//ySyI/P2l+j+RkbWvSRIhVGD0a7pOyZS3vr7S5mwjv\nw7FjENL58uHZfvwYC2gtoGlxYmjuDg3FikfpaEa+mnR8PAJn+veXf0zWIlVVnaQkaAeLFqn3QGvF\nHx0aCjNvv37QUL//Hu1US5cmGj9e2jxue3u4fX78ERrtrFmoZ1+lChqZGFahOnkSEcY9e6I05t27\nRLt2wT0hZdpanjzQ7r/9Fu/A6dMwl/fqhYX1pk3ql7AsXBh/ajFrFiwPUkXBFyuGIi1apmBBLNQ2\nbuS3v1pC2rAvuKcnFhVaQdNC2tDcrYY/moi/Jr17N262VtOuDHFxkSZf9IcfYCJV2gWRlaxlY5Xk\nzBmY9KZNI6pRAxq0nx8iWy9ckF+LtLeHe2XlSpjC791D+g8RBPPs2agpfecO0bhx8gf1NW+O4Fyk\nBwAAIABJREFU4LEqVZCOFxGBGI3Nm7Ht999NB5/JTUyMuguF/PmxWBk7Vhq/5/nz2k495Bg8mGjd\nOn6mbDWEdL16cP9w43v1Spl8er5oWkgbmrvVEtJ8NWk/P/jibAGuRq01HD4Ms+6yZdKMSSz588PM\nqrQZ8/p1FPEYM4aoRw8if3/khhv6G0+fhtBSijp1EE3L1QYPD8e/Bw9WLrCudm1YNjhLjZ0dOkTt\n3w9fOPeb/Pmn8pHWSUnqm4c9PGBtmDHDev+rtW10laJ5c3xXPoVd1BDSZcrguo8f499OTrCMagXN\nC2m1NWkXF8vm1NhYmBW11u3KFMWLWyekk5LgF121isjZWbpxiUGng0lNKe3s5UtMsj17wod14gSq\nKxkL4ImOVq7GPBF+gxEjEMBIBFNzv37Z6xPLiYMDTMrh4dk/e/99LGZWrkTBn6ZNIbSVwtERJmK1\nGTcO85m/v/hzJCQgHkPr5m4ivKOffQZtmu/+SqLTQZu+cgX/1loLUM0Kab0eFcdKlMB/ixSRt5OS\nKV69slwBZ+dORLOq6e8SgrWa9Pz50Mw6dpRuTNZQq5YyRTT+/hspGy9fQhCOHWt6AccYglGUypeP\njoYGnZICKwcRtLVp0+CnXrNGmXEQIVI8Ksr055xwHj0aecRffaXMIisiQn1NmggLmeXLEfEttroW\np0VrISCPDwMHIrDWUtcutbqp1a2LyHsi1BDPFdI8iIuDhpQvH4ItnJzUeSD59Djdts12TN1E1gnp\nf/6BX3HePGnHZA2JifL6kJKSELX/1VeIZF+92rJv99EjCAQlNLf79xHs0rIltBVDQdSuHdHChXDH\nLFgg/1iI8Hxdu2Z+Hzs7BJj5++P+1a+fuW2gHHCLfi3QvDliGcR2y4qOtg1TN0e5coj03r/f/H5l\ny6oTCJpVk841d/PA0NRtrKe0UlgyfTx9igChTp2UG5O1lCsnPrp74kSkkRg2PVGbMmUgFOXg8mUU\naImJge+7VSt+xz14oEy6YHQ0UZs2COIbP974QrZaNaK1axG05Osr/5jKl88cLWsOJyf4p3/9FQvd\n336Tz1f9/Ll2hDQRAuq2bsVzJZRHj/ilNGmJRo3MV6RLS4ObRI3g27p1M4R0ribNkxcvEBlLpG0h\nHRgIs6+p/FQtUqGC8DZyRDBRHjsGQa0l5BLSAQEobThhAtJmhEweT5/KX93q9WuYEb/8kujzz83v\nW748Ilh9fVEVTE7KleMvpDk+/hiadGAgfOkJCdKPq3hxbbU0LV6caOZMxHcINfPaStCYId26QZM2\nFWEfG4t3TI06EzVrIgMiOTlXk+ZNQkJG9xi1hbS5ovy2FNXN4eqKZiVCJga9HgJrzhztNbOoVEla\nczdjSF369luY9gcOFO5qSUhAXrKc/PILhO933/Hbv3JlosWLcdzdu/KNq0QJca6pcuWQY+7kBHOw\nOb+2UBISsAjQkpAmQuT9hQvCF062KKRLl4Yw5GImshITI101NqHkz4+Yp5s3czVp3uj1yAFlTF0h\nbc4nHR0NE4mU9XiVoGhRPJTPnvE/ZsMGaIZceo+WKFeO6NYtac6VkoJKWQEBiMCtX1/ceV68ENZY\nQCh//YUSnEuXChOITZoQ9e0LQZ2eLs/YChQQ30koXz74/IcPRye50FBpxnT/PhZzWgu0srdHkZNJ\nk4TdD1vzSXP06IFAW2PExqonpIkyTN65mjRP9HqYPbh2bKVLqzMOc+bugACkXWm9fq4xXF35ayoJ\nCfB5LlqkzZKn1aqhjrS1vHkDrTk9HdHb1vj8xPQh58vLlwhiW7IEwZVCGT0a955vSoxQ8ua1blGt\n0yFQ7/PPsQCWIk3rwQP+8QRK07kz5plNm/gfkzcvFh22Ro8eKPxkbEESE6NuSicX4V2kCFyCWkGD\nUy5IT4dA4LRotVbA5szdthbVbUi1aqhOxYclS/ByKZnzK4SqVa1vFP/mDb6jXo8gKzHCzxBHR/nS\nfebOxVhbtBB3vL09itD89JP1v5sxUlPRbtNaevSABadbN9MmUr5cuqTdnGKdDm6kKVP4VURjjGjP\nHm23wzVFlSpQuIxF8qtp7ibKiPC2t88IItMCmhXSnLn7+nV1yz6aMnc/eAATa9u2yo9JCtzc8Nta\n4vVr+GW//FL+MYmlbFmkhnEVg4SSnAwTcJEiCBCTQgO2t5cnLezFC3Ts4euHNkWdOijnKkfFOClb\nKHboAIvVpEnWadRXrgjrFqY0LVvinixfbnnf6GgoMGpZF63FlMlbbSFdowbmejs75avhmUPTQtrO\nDjeOi/JWA1Pm7gMHUM1JC80dxFCnjvGqUFlZswbFJ2rXln9MYtHpkO4kxn+p18MHXbIk6ktLZaJ2\ncZGnuM26dRirFClwgwahMYfUvumXL/F8SUXr1ijK0qOHeA09PFzbQpoIxWd8fS1r05cuIVZCa/51\nvvTogUp9WQNX1RbS5cvjt01PzxXSvODM3SEh0nbrEUqRIhkl+Aw5ckR8UJEW4COkU1JQtOSHH5QZ\nkzU0aCBOSP/0EyLdf/9dWh9ysWLSBT0Z8vff0lk16teH9UHqsqHR0dI3sujQAfeob1/hQWmJiUh3\n4hqPaJV69YgqVrTsm+aEtK1Spw5S9CIiMm9XO3AsTx5E/z97Jl9QpRg0K6Q5c/eDB3hw1cLODlqL\noV+aK/nYurVqw7KaqlXxopgrx7hpE/xeWvVFG9KihfDOQr6+SKH76y/pW6CWKyd9UQaurKWUTTv6\n90ejFCl58kSeEr59+yJlqUcPVIHjy7lzWHBqoSSoJcaPR9ldc5pcWJhtC2k7OxTgOXIk83a1NWki\nBOM9epSrSfOC06TVFtJEmMANizNERGBsatQSl4o8eWD+M+WXTk9HMIstaNFEqBe9bRv/tKdTp1CS\n8u+/5alCVbky0aFDwoSJJc6cgUlOygj7Nm2kz5m+elW+d3bsWCwchw/nn+d/8iR8vrbABx8ghc1c\n3rSta9JE+J5ZgwFzhbRxZK6JJB69Hn8pKep3WnJ3x0RWrx7+fewY0jls1SfEUbs2Cik0apT9s8BA\nmAi9vBQflihKlEDk6Llzlifkp08RNLV8OaLc5SBPHjw3N25YXx40LQ2BT5s2wbo0eTKevfz58b2r\nVYO535wPnDGMJTyc6N9/MSHGxGABGhGB++3pKY1r6coVaLtyoNMhj7pVK/jnhwyxfExYGL/9tIBO\nR/T993Azde2a/fOXLyFE5HpulYIrZWvYmtLFRf2yrVoU0prVpPV6RIlWqKC+MOSENIetm7o5zLUK\nXLYM5T/V/u2F0K4dtFdzMIbOSwMHIj9VTpo0QUyFGNLTUaykd28son74AVaPMmVgwalaFZPa48dI\nGevRAxXhst7PmBiUnfz4Y0RInz+fYQVq0AAar50dguZ69cJ+v/0Gv7IY9Hq4UOQM0ipQAFaTCRMs\nB5IlJhIFBWk3R9oYPj5YSBlLU7pyBYtre3vlxyUllSvjPt64gX8zhmBctXO/K1WC1VRLQlqzmnR6\nOtJ/1DZ1E0FIX7yY8e9jx2zHDGyO5s1R/jIrV6+ijq1WWlHypV07dBWaNs30PitXwnqgRB/jxo2h\n2Q8fzv+Y1FRoiAEBmLh69UIRmdKlMTl/843xyOm4OPjXp0/PmOjWr8dfnTrIwa1Xz/ii6+xZFA7x\n9kYRl6AgpD0OG4b+1FWq8B9/eDjahsqtEbm7oylH//74jU0VFDp8GA1SihaVdzxS4uCA+WX1arhx\nDMkJpm4OzuRdsyYWhYUKqZ/Lzgnp3MAxHuj18OdpQUhXrZqhSd+7h8hVWywkkJXq1RFR+eRJ5u2r\nVsE8KHeDCKlp2RJCwlRJv4gIRHNv2ABztNy0aQPtgK/v9MQJog8/hICeNg1WgeHDM/JhixUzLYyc\nnCBQd+/OeGfWrUPZ0MWLzafsFCoEk7qDA8Y8axYi3gsWRCT5xImW+wBzHD8OYa8EgwdDI5syxfQ+\n+/bJbzGRAx8fuCCytpT999/sgttWMQweu3MH86zaVKwIIa1Ei1m+aFpIa0mTvnMH/59T/NFEMHM2\naZLZrPb6NUyfQ4eqNy6x5M+P2uJ79mT/jGua8cMPKFqgBO7u0BIspWKlpMAUPXIkipT873/GJ+LC\nhS0HouXJk7kNKZ/nNDk5e+RzsWIQfhs2ILOhaVN+VZi2b1eubatOhwVlSAjM+FnR62ElsEUh7eyM\n33Hz5szb/f2Nx5DYIh98gPQ/vV47QrpSJSyEcmt384Azd2uhhmr58qge9fp1zvFHc3TsiO/EsX07\nJmS1fUNi8fIi2rgx+/aNG1GXd/RoZcfTuDH8p6Z48gRWi6tXoVWYEyjFi1tuAennl9G2c9gwNNKw\nFPH+9Klp83Tp0nARjBuH9CB/f9PnefgQ36NdO/PXk5KSJVGU5auvspsojx/H4sxWg6yGDkWaIGeJ\niYqCj71mTXXHJRVly+J9vXYNtfe1cJ8KFoRlSUvpepoV0gULwrSnBSFtb5/R3vH48ZwlpFu3Rp4w\nNxH4+grzoWqNbt2gVRkGPsXFIVhs2TLlA2769YMJ3pigjIqCOblaNZipLaWflC6dEWhjjJQUCOmx\nYzOu7ehItGuX6WPevIFgtdRWc+BA1Az/7js8I8bYuhXfR+mGM/37Y1Jduzbz9vXrIcBt1erl5YX7\nc+EC/n3kCEzEtvp9jFGgAN5XrWjSRPCLa6mSpKxC+qgVpYwcHLAyVzuQgMPdHQEqcXFYyVrz3bRE\n3bqY3G/dgt89Ph5mNlv9fgUKIEJ5y5aMbbNno2KVoZlQqe9Xsya0n6yC8uFDoi++wKT788/8cp+b\nNYPWQUQUGBhIwcHB5GsgMU+ehLbdsCH+rdMRde8OX7cpzpxBYFiBApavX68e8ssXLkT1L0PS09GI\npXt3y+eRAsP7p9Ph2lOnZpj6X73Cb96vnzLjkRLuu+l0cIFwOdOHDyvn75cTw3vXsCHcFVrRpImw\n4LNmoSn13KJZIV20KHxlWonKrFoVL4mnJyZUWxViWdHpYPLetw+mzNatsUCy5e83cCB8qUSoQrZ6\nNdGPP2beR8nvN24cNGXOWhEfj0VDmzZoycgXb298n+Dg0P/+jRk7LCyMHj4k2r8fEwznT9PrYca+\ndAmmfmPa/IEDwgRrxYo45siRzOUrAwKQLaCUvzTr/atfH5Hwc+dmjKd1a5R5tDUMv1v37sjnT0mB\n5cVW6haYI6uQvngR301IFoGc5M1rXWCpTQlpayhaFA+mVoS0uzvRzZtE7durPRLp6dQJQtrPj+iT\nT9QejfV4ekI4XbwIE/eIESjTqRadO6NyXlAQBOeAAYje/f57YecpUgRCcOZMfyr2X/hpXJwbjRwZ\nRKNGQcs9fx4aOhFMzwsXIhBm0SKinj1RcpIT4o8fQ3gL1TYrViSaORPWigsXMqrTDRgg7DxSw5ni\nnzyBqfuzz9QdjxRUrgxXm68vIr0tuSVsjfr14Q5yceFnzVGCvHm1ldmioaFkpkgRvPxaEtKRkdrx\nm0iJt3dGq0ZbKZ9oDjs7oo8+gvnz9OmMyHy1sLeHn/jHHxEh/fw5/l+Mb3HoUKKNG+MoIcGZJk+G\nKbtMmRjatg1R4QcOwES6bRtMdp9/juCqpUvx/C5fjkXLhAnYp3VrFEgRSu3aCEybNAmFVCpWhHVA\nTSpUwILj22/hy1UqylxuPvkE1iClXAlKUrAgrB1qNlHKipYENBGRjjG+WZwiTp6TIhxyySWXXHLJ\nhQdSilVZzd2MMdF/d+8yIhJ/vNR/9+8z0ukYPXqk/ljk+KtXj9FHH6k/Dqn+Hj9mVKkSowED1B8L\nY4zS0xk1bsyoZk1Gd+5Ydy4vrwlUqVIQffYZo3XrttPcuXOJMUavXjHq2pVRkybcBMHI05ORv3/m\n47dsYeThgb/YWPHj0OsZde/OqEIFRqdPq/8bM8boxg1G+fMzmjJF/bFI9XfrFqO8eRkFBak/Fjn+\nGjbU1tzTqhXeG2vOISWa9UlzQS5paeqOg+PaNRQYMFZP19b5919UUgsJ0VbNWmtYtQqm+717xdeh\nlhKuYcnQoagmJrbf8u3bRIz1pi++iKT33iP67bcoSktrR0lJCOaqXBl5zUTwSU+enNFtKDwcuc67\ndyPoq1Ur1PUWi58fXAlTp6IqmRaenTlzYOL39UVMS05g1y5E1pvrjGXL/Ptv9qqHasKYtkzemhXS\nr17Bl/fqldojAeHhSBFQouaz0owZM486doRvesaM7Kk9xtJ9+G5Tg9RUCKrvv0cw05o1qg6H0tJQ\njvSbb4jGjEHVMK4DkFDWriX6+GMPcnEhatQomDp1cqJHj+pTr14I5jpzBjWtifD+rFgBP/Wnn+Jz\nd3f8HjVrYkwXL2KSFEpICNHXX0NQf/YZrmUuH1sJoqIgyGbMQNnegAB1x2OMefPmvf1/vu/Qzp2B\n1LhxMPn7a+9ds5YnT1Ak6v59tUeSQUqKtO1grcXq9UJgYCA5OTlRZGQkDRs2TLJte/dGkoPDMIqP\nV7eOamhoKEVFRdGOHbHk6TmMzpyR/jurSVBQEJ04cYjmzx9PYWGhdPgw0c8/e1NkZCSFhYW9Nd14\newvf5uHhocp3OngQUaPnzvlShQpEP/0UQf37zyFXV3Xu3Y4dKL/arh2Cxdatw//Pnw/Nli9xcSim\ns3cvkbMzrs+lYcXH43wvXhC1aBFIW7cS1a3rS/37D6PJk9F4w9U18+Tj4oJGGjt3QuDy5c4d1M1e\nuxbHEyHNbOlSBJGJDUXhBE5ERATNmTOHiITdm1WrnKhNm0hychpGY8YQzZ4dSKVKaetdO3ToEI0f\nP55CQzPS6My9Q1FRjG7cIDpyxJvWrYukgwfDqEQJ7bxrHNw8GRsbK+gdOneOyNU1kO7edaKFCyNp\n7Fj158nXr7MHLMsl5/h8P6vWC2FhYeTm5kbe3t7k5uZGYWFhFBYWRkSZczgNH0i+25KSiIoWDaO4\nOGtGaD1z5swhHx8fevUqjt57L4wuXgyltDTrvx+3TW3S0nQUG4vUstRUPwoJKUbx8URubm4UFBRE\n/v7+5OTkRETCt6nF5s1EVaoEU9u2bWncuGHk7h5JgwYFS/Zsctv4smgRKqFxwqtwYWidmzYJMzcf\nPozFh7H+6kWLQvDfvx+aqVrSqVNhVKcOclCNaQcffWS87rUp7tyBQB8zhqhLl4ztHTqgaItYd1Bw\nMO7XsGHDKDIykoKDhd2vu3eJwsO9ydMT20qVCqWrV4mqVtXOu2YYSOvn5/c2jc7cOzR3rj99+KET\n5c9P1LChG61dq613jYObJ+Pi4gS9Qzt3hlK1akS1a3vT48famCcTEzNbueSUc9w2c1it1E+YMIGI\niCIjI8nDw4P3w2dpW6FCbvTmTZDFWsVyEhAQQI0aNSLGiO7fH0+9enlQ4cL+9Py59d9PCy9XWFgY\nFSrkTcWKIQUiNTWemjd3pq1b8XlMTAzFxcWRs4FUELJNDRISUNSjcuXIt79v+/ZudO1aJM2f7yf6\nPom9d1evwhLUtWvm7aVLY5xr10LL5RN7cfWq8TaVHM2aEd265U/R0Xg+XV3dyN8/yGwv5aZNkS+d\nkGD5+ufPw4/dqxf8vobY2UFor15t+TzGiIzMuF9ubm4UGRlJfn787pefnz/t2eNE06cT1ayJbTt3\n+lPr1k60bZt23jVuUiYiio+Pt/gOPXsWQ+HhcdS7N7Y1aEB09ap23jUObp4kIho/fjx5eHiQv78/\nLzlw+LA/vf++E1WvTpSWpo158uXL7PEVcsk5Pt/PKiHt4eFBrq6u5Ozs/PahsWZSN9yWnk6UN2+M\nqkI6JCSEYmJi6MiRMNLr51HRokQlSsTRvXvWfz9um5rExsbSiROo78zRvTsTPdFqgV27EDA2duyw\nt2akK1dCacKEhnTuXBwVKZJRIFuJe7dlC3KKjQWilC2LYK8TJ9Ag4vFj8+e6dg2BYabIk4fI1TWO\n/vc/jPPAAaLXr2PMNu3Imxe5qlwrVmPo9TBld+6MIiFZBTTHp5/CdM63raUhw4Zl3K/Q0FBq2LAh\nxcXFkYuL5ft19mwcvXrl/LZ4Cbdf9+7Ob7tIaeFdy4qlKOCoKDR7cHPDvxs0QICnxMHDVsPNk2Fh\nYW997nzeoWfPYig6Oo6aNXOm6tVR8EfteZIxuI4Mq/PJKee4beawyicdFxdH7u7u5OvrS8OGDaP3\n33//vy9q/VPE9bdVU0gTERUvXpwKF/YgZ+cgCgwMpFKliC5f1thbYgJjQSXOzs7k4+PzdmW/YEGG\nz9/JyYmqVo2lZ8+IwsIyJkhugjGcNM1te/HiRabJVUk2b0ZZUI7Q0FBq0KABjR/vQUuXEvn6MsVK\nVzKWYdY2RbFiqPY2cyb8vP37Q9gZ8+tev265cpqrK5Fej+fz5EmU6rQUqeriQvTsmfHPoqKwgHBy\nQkUzc8V8ypRBwY1Dh2DeFwN3vzgfq6W5JDERGv769dmbp3h4wEd/7564sUhFVi2aCO+apffq1i0X\n8vDI2JY/fxwVKOBCqanaeNcMKV68OHl4eFBQEOZJIsv37vlzLEKKFEH72OPHlRipeeLjsdg1XGjK\nKef4YFFIm5vofX19acSIEVSkSBFycnKigIAAXg8fn22vX7+gAgVcREWeCsHc93NxcSFXV1eKiiIq\nWdKJLly4QFWrOtGOHdZ/PyVeLnMBCZGRkXT3biQdORJD1arFUlhYGPXu3ZtCQkJoyBBv2rkzkpYu\nbUeMMQoJCXkbpNKuneVtUVFR1E6BfoVZ711yMlF4uDN17uzzdltwcDDNnj2biIi6dHGizZtjafhw\nZe7d3btYkVuK6cmTB2lMFy4Q/fYbBPuwYRmBZhzFilku/F+woBPFxGS8Q/nyWR6no2N2c/vjx0hj\nWrkyIyqdTz3junWx6BArpA3vl6W55MWLODp50oWaNiUqXjz7fnFxsdS3L1Fw8Avy8FBPkEVGRlJk\nZCTFxMRQbGzmd83UOxQeHklRUe1o6VJGN29m7NeqVTsqVYpRZKSy75o5uHmSCPfswoULvORAXJwL\nVaiAbZUrE129GkcffKDugv/JE5QUNswqklPO8fl+FoW0pcizIv+1qeIeorZt2wqe1I1ti4mJonLl\n2smuSZv7fj179qSAgADS64kKF46jxo0bU+XKrrRlSwj9+69130/tl8vHx4cuXyYqUsSXEhPjSafT\nUf369SkkJISqVQumuXOd6L336pOjI8xZwcHB5OTkRPXr1yci/tvkJOu9+/tvpMkVLox/r1q1isb/\nFz4dHBxMn3/em5KTQ2jQIG/q3z+SPvpI3nt39Ch8vnyjnRs1gnl8xw6kSS1cCD9v+/YI/CpbFuUu\njfHwIfKfz53rTY6OIUREVK9eFIWGtqPRo1G3u0UL4606X72C2fv1awSnbdqE87VuDS21bFl+4yci\n+vDDzP3JhZD1flkSZH5+kZSU1I5WrGB05Yrx/by8vGnUqCj6/nt13zUiTPbx8ZnfNVPv0PXrTjRy\nZH3y9CS6eTNjv7Zt69PFi0Rubsq+a+bg5kkiCKLGjRuTq6urxfcqLa0dde2KBUf9+t707Jn68+Tj\nx4jPyVpbQS45x+f7WWXuHj9+PM2bN4/c3Nwyhd5bM6lz2woUcCJHx/oUHm7NCK3D1dX1v5VTIOXL\nF0sff4wJxM0thFatCqYKFcR/Py28XGFhRD17DqMlSzKEHXcPN2zwpsBAmF+5bYYmO77blCQoKKOV\nX1BQEE2cOJHmzp1LsbGxFBAQQB4eHtSoUQg9eBBMp0870aRJ8t67a9eE9x63s4NA9fGBr/rAAURT\n58mD+7VgAdH770NDT0tDWlZEBEzbPj5EixZ5UGhoCAUFEbVq5UTLltWnrVvRaGTGDORJly6NCHF7\ne5iD9+xBTXHOTebjQ9Snj/EockvUqAE/+7Nn0Ej4Yup+mboP69YF06VLTrRrV32qVYvoyhXj++n1\nwfTwoRNVqaLuu0aU2e/O/Zso+zuUkkI0aJA3TZqUfb/z51GoZ/Vqdd81Q7h5MjAwkGJjY98utCy9\nQ7dv16cZM4jOnQuhsLBgSktzInf3+lSokHrzZEwMLF+GcTpyyjk+30/W2t3WsHgxOvQEBmIiUZMO\nHTBRcgX7Z8/GJLRggbrjspbhw1HJaOTI7J/t24d2j9u22U6T+bp1YaJt0sT8frGxCMKZOxeRynJR\nqxZ85NbOMYyh0tjEiTB316mD71CyJARuzZq4j4apVzqdLpvP7J9/IIwfPIBwT0/H37p1mPhbtEAQ\nmbW0aYP8748+sv5cxnj1Cvf4229Rwc0S3t5ocGIugE5LbNwIH3twcPbPkpIQQxAbi7aktkp0NNGg\nQViEctadqlVRA+C999Qb14wZmNs3bszoTa42Gip+lh1HR/gZExOlmTzEEh+fOaq2TRuUdrR1rl9H\nkJIxOnTAxHb8uHBtUA0eP4YQatDA8r7Ozlj8de8OAccV5JCSlBR0nape3fpz6XSYuLp1IwoNzd4b\nmy8VKuDPkNBQWCA+/ND6cXK0bIl8ajmEtF6PALsWLfgJaCKkv12+bBtCmjHEJfznls+GoyOEWXi4\ncr275WDfPpTJNXS/lC+P6ndqCunbt2GpsqaftNRoqPiZcby8MNmpya1bmZvHN2hAdO6c+pHn1sAY\nhHTNmsY/t7dHWc3/Cj9pnnPniHr35l9z9/33oUl36SJP3eAHD6DBSantfPAB0dat0H6lgqvOJiXF\ni2Oyk4OpU9F3ePFi/sd4eNhO3evgYLgyzLX9bNAA5Vxtmb/+yl47gBPSanLrFtquGlql1EbzQrpA\nAQgTtWAMye2GZeIcHPAS7dun3ris5fFj+D/N+Q0HDIB5VAPFmixy4gRRpUrCjunTB9+xXz9xub3m\niI6GBUZKKlWCxitVqgpjEAqffCLN+TgqV5anFvOaNXAfzJsnbPHj4YHn2DD3VassWIASq+ZcTLYu\npBMTEVyY1dJSvjysYWrBuZUqVMgV0oKoVQuVltQiMRE3LKv5o3Nn21mdG+P6dfy25iaB47GnAAAg\nAElEQVSDfPng9zNletMSoaHQjoUydSp+Bx8fabsmPX4Mf7HUtGmDphZScPEiV+tbmvNxlCpF9PSp\ntOfcswclVP/+O7NViw+FC2OBc+2atGOSmnPn4A815YLiaNAAz7utEhRE1Lgxcu8NqVpV3YXUs2dQ\nXAoVyjV388LBAcKxdm11hXR8fPZi60RIizl6FIEctsi1a6ZN3YYMHw7TrZpR9pbQ67HoECOkdTr4\nAB0docFIJahfvRIuTPjQsyfSosxVCOPLr79CIEjd8adIEWmtCHv3wv+8erV4f2WjRvBLa5nJk5Ef\nbykXvnZt3DMttAYVw+7d2U3dRLCOyOUm4cPt20jhTE3N1aR5YW8PM7NWhbSzM8xoR44oPyYp4DRp\nSxQuDLPwDz/IPyaxREdbNt2bw8EBvt779yEETeUiC0Fq8zlH0aKISF++3LrzcC0qv/hCmnEZUqAA\nJjsp2LePaMgQaNLWBErVrAmTt1Y5ehSxN4MHW963UCGYhS2VkdUi6elYdBk2Z+EoVoxUbah06xYW\ngSkpuZo0LwoXhjbi7o4ALbU0VlNCmsi2Td7mgsay8uWX0KRPnpR3TGK5fdt8uUo+5MtHtH07VvOj\nR2OBaA2OjvJo0kRIB7xzR/wCMT0dZv4vv5Qna0KnkyaO4c8/Yd3YswfmUWtwd0c+uRZhDBH7U6fy\nFw6VK6Nkq61x7hzcQP8VKMuEk5O66ba3bmFxmZKSq0nzghPSefLgBbtxQ51x8BHS2sw0Nw1j/M3d\nRBBgv/xCNGGCNr/rnTvSaG5586LiV9688NNaE/yUkpK9apFUFCoEN8TcueI0jxUrYCrt31/6sRGh\nyIpYqwYRnrGZMyG0uF7c1uLmpl0hffAgFoWWfNGGuLrappA2FtXNobYmffs2NOlcczdPOCFNpK7J\n25yQrl4dmtelS8qOyVqePYNQE6Lp9euHieSvv+Qbl1iiojI6BVmLgwPSe4YORevHc+fEnadgQQQd\nykXnzigVOn68MN/k8eMIwFq+XHpfNEdCgvgAoKQk5Ofv2UN0+jQqmElBlSowJ2ttkZmaiu87Z47x\nkq2mqFxZ/cYhYjAnpLWiSScn55q7eWELQlqnQ/qKv7+yY7KWR48gQIRUErO3J/r9d6IpU/AQa4no\naHRgkgqdDk0lVq3C912xQvjkXry4dOMxxfz5EDx84wVu34YwWLIEuaByERODqlhCiYjAwujJE0QA\nS3lPixRBio/W/LhLliDyvGNHYcfZoiZ95w6EcMOGxj93coImrcZCKi0Nv6e7OxaZpuZ8NbAZIa1W\n+oQ5IU2EoKpNm6QtMCE3z5+LEyLe3ljBz58v+ZCs4tEjaSd0js6doXWuWIHSqULKBJYqJf/CMn9+\nLBAjIiwXnbl7F8VpevZEdy05efHCcucvQxiDm6FHD1gwtmyBSV9q8ueXp3CNWJ4+JZo1C41UhJbe\ndXW1PU16zx4EjJmy4OTPj2p1UgRuCuXePfjKHR3xnmdND1MTzQrpIkUyhLSaudKWhHTt2qihfPSo\nYkOyGrFCmgja9IIF2pogkpPlyUkmgvnrzBm8tHXrEu3fz++4cuWUMZm5uOCenD8PH64xLeTyZaK2\nbaGtDRki/5hu3uT/3Z8+xcJh5kzUqx41Sr5a8c7O6vcBMGTWLMQFiDHp22Lg2P79pk3dHGfOqKNJ\n37qVYc0QawmSC80KaUNN2tUVgsXaiFsxWBLSREQDByIS1VawRkhXrgwf2pgxkg7JKu7elde87OiI\nCXXDBgjC7t0tL1JKl0YEvRJCoVw59H2+ehWR3wkJGZ8FBkJA//47gs2UgE8gX3o6xjxkCCLzL14U\nl+cuhGLFtNM04cQJop074U4RQ5kyme+z1rl3D+9D27Zqj8Q4p09nBDvmCmmeODoiQjYtDeaRmjXV\nMXnzEdJ9+yIgwlZemufPrYu+HT8eCyitpJ+9epXRQ1pO2rRBOcPGjeFXmzMnc3N4Q3Q6WICUemZL\nlIDbRafLiNoeNYpo7Vp0GureXZlxEEEAm8scOHECv9+mTUTTp+N3VKKjk1Y06TdvULRk4ULxZtWC\nBfFdbKHUKRGeQx8f7XbuOnsWvd+JcoU0b3Q6rLBjYvBvtfzSfIR0yZJEnp5IF7EFrNGkiZCSNWUK\nCmGorZno9SgcIocP0xj58yNQKzQUUfJVqkDLNmbladdOWTdN/vyITK9dG/8+cYJo6VJ+ncGkIjUV\n70GdOtk/O3UKv8m4cUjnO35cmO/aWipXxqJfbWbOxCLm44/Fn0Ong0tQDeuiUNLSIKQNWmlrivR0\nopCQjFz8XCEtgLx5M3JN1fJL29vz66w0cCDMobbAs2fWm4dbtYIv8ZtvpBmTWFJSYCaVK53IFBUr\nopzosWNYPDZtSjRpUuaObW5u+FwpLl5E45eQEPzbywsTz6JFyhUDunIF7inOspGaiuC2li2hNffu\njaI4ffoo36c8MVF9TfrSJaL//Q9R3dZStKi6ecV8OXAAkfXGFm5a4MYNBHpygvn581whzZuyZTOE\ndOPG6rQxY4yfSalLF1RZUrOLC1+s1aQ5Zs2CmWjXLuvPJRZ7e3Xz1GvUQGemv/5CAFuTJqjrvmMH\nFg+JifIGwqSmwrc5eDDRV18hMIfLZV+0iOjwYSwcKldGQZoHD+QbCxEEcJcuqFA3YQK0xaVLEcfA\n1eBWKwdV7XrXSUmoNzBqFOY2aylaVPpOa3Lg66tdLZoos6mbKFeTFoShkG7QACsyuWoimyJfPn5N\nF/LnR03lzZvlH5O1SCWkCxQgWrcOaUpSdz3ii709zGlqF6lwd0fU+z//EA0aBIHk6Yl8319/RZqU\nVGN88wbnHTECGupvv6Ht34kTENSG1ZJq14awPnYM13//fVhB1q+XVmAnJSHDYeFCBFEOHAihOGcO\nru3jw7/Xt1yoLaQnToQ2KVWlN1sQ0tHReC579+a3vxrvsdaFtMqvjXkMhXTBgkiBOXsWATxKkTcv\n/+IdAwdCU5gwQXlTnhDS0xFEIwUtWxI1b46+zPv3K292trPLmHyFVGySi/z5Ud7x008hPD/7DAJ1\n8WIsJpo3J2rdGtG5VarAJF6smPHnRa+Ha+Kff+DquXoVUbIHDsDVUKsWnjU+1daqV0ccwcSJOP7Y\nMaKffoIvv0sXRKPXqgVTdZky2G5sTCkpyEuPisJYLlxAwGRAALT42Fjkw3p6Kv8sWMLeXr338uBB\nWDwuX5ZuDLYgpNetg/IiJGZE6Xt09iwWt0RYJLx4kSukeVO2bGZTZuvWmFyUFNL58vEX0s2aIfXk\n+HGMVas8fgwtWCqmTiX64ANojJMmSXdevnDatBaEtCHFiiElatIkuGr++QepHnfvwk8bGQmhd/s2\nfLgVK2LSTU7G9oQEbP/wQ0xctWsjl3PdOvHR7PnyEXXrhr958+CPu3QJedZ//4165dHRmKzq14dA\nrlsX/u7q1aEtN2oErbhlSwR3NmhAtGwZzOwvX2r32U9Kwj1RmuhoWDP+/FPa62tdSOv1RGvWaLsi\nY3w8Fpucv/zpU+VqHPBF00K6XDlMHBxeXvCDKokQIa3TIXBnwQLtTlQcUpqVuFaPDRtCg2rZUrpz\n872+Viu+eXkhuCciAiZxY+U4U1KQyvXyJe5Lvnz4K1zYcm9ha7C3h+CvXTu7CTYhISPFhxtTgQJI\nGTKlIW/aJKxJhNK8fIkSnEry5g388p06YSErJWXLarundHAwFhJKZhcI5cIFuIA4oXzvnjIlfYWg\nMYNUZsqWRZtKjhYtsKJXsm1l3rz8fNIcAweiao6azcstIYc5qXx5rJq/+055/3SzZtqrJ87h4ABz\n8tq1pvfJmxfmNVdXmK7LlcNEIaeAtkShQkQVKmA8Varg/jo7mxbQT54gxUrJfGyh8EmnlBLG0A60\nfHm0opSaFy+EzU1KwwWMadn1l9UfHRVlvI2mmmheSBu2+ytUCKt+sZ2JxCBEkyaCtjFiBCo8aRk5\nAjQ6dcLfxx8rKzTv30cwnFYZNgwmalspPCGGtWuRNy9Hf2qpePlSWSG9eDGUivXr5fHP6/XaFYBP\nniCzoF8/tUdinqxC+t49ZEJoCU0L6ZIlEWlnOLl5eSlbJ1uokCZCM4Zt2zIKsWgNnU6+KMrJkxGE\nNHy4cpGaWRdzWqNGDSxeAgPVHok8pKQg77dvX7VHYp74eBQAUYLgYLjmdu+Wr9AOY9oLzuNYtgyu\nDy11k8pKWhostc2bZ2zL1aQF4uCAnFPDCbh1a+WFtFCTUunS6OizfLk8Y7IWOVffdnYIkLl6FYFJ\nSqB1IU2E52HOHPVTxeQgMJDovfeI6tVTeyTmKVFCmajdqChokFu2yDvh6/XaFNKJiZj7Ro0Sfqyc\nLVSzcuEC3kfD5jy5QloEiYmZ/bstWqCiklLtzISkYBny7bco4qBG2zU+yCksChaEBvHHHxmFNeTE\nFoR0x44Y58GDao9EWtLSEN0/ebLaIzEPY6j0Vb68vNdJSEDk/I8/yp+FolUhvXo1cvEtNVnJSnIy\nhKRS9b0PHIASaMi9e7lCWjDVq6P1HUeRIqh7q5RfWoy5mwg5p/XrYzWtNeQ0d3OUL4+qWytXIr1H\nTrIGGGoRnQ6+6UmTtB2RK5QNG5BXLXXkstTExGDBLaf5NSUFldU8PcVpkULRopBOTUV2y4QJwo99\n+hTWDqX87AcPIhuHQ69HgR+lMwAsobFbnJ0aNTILaSJl/dJihTQRtOkFC7Rn4lTqJWjcGMFEXbui\nTZ1c2IImTYTI5ypViLZvV3sk0vD6NdGMGfC9ajWAiSMqSt6AoLQ0+GCfPEHVNSV+Dy0Gjm3bhme8\nUSPhxz59ihraShATgxoBLVpkbIuORh67o6MyY+CL5oV09er4MQ3x8lKucYGjo/jVatu2OFZrJs7q\n1ZWLvu7ShWj+fJiVLPVgFkvlytptgWeIToeF27ffmm5xaUvMmQOTrmHgjVaR04yZno5SsImJWIAZ\nlmWVk+RkZVq08kWvJ5o7V5wWTYQFTsmS0o7JFEFBMMkb3istmrqJbERIZ9WkW7WC4FaiA4yTk3hT\nqk6HUoxTpmhLm37+XFkh0b8/Xtxu3eTReN3dUYpSS7+xKZo3R7vGBQvUHol1XL+O4KBp09QeCT+e\nPJGnqIZej1LAjx/DvaNkbvvTp+L7UcvBjh0IIPzwQ3HHK6lJHziQ2dRNBCGtdCEmPmheSJcvj/xG\nw/J3hQqh25ASQUnlylnn7+zRAyteNTtFZcXJSfkWd6NGEX3+OawgUnczK1kS1bMeP5b2vHIxbx4E\nnJL5/lKi1yPFbto0vB+2wKlTKM4iJYyh5nNEBOYipc2kWmoEkZ6OWvBDh4o3wSulSTMG62bWoLGQ\nEOU0eSFoXkjb2WF1llWb7tVLGd+etf5OOzui2bMR7amFhvNE6ghpIqLRozG5t26NAiRSUru2Ov3G\nxVCiBGo5DxmifFc3KVi3DouiL75QeyT8CQ0l8vCQ7nyMIUjs8mWiffvUKeISEyNdoxxr2bQJz3VW\nwScEpTTp8HAUnXJ3z7z90iUE+2oNzQtpIuPBY507wy8td4H5EiUg0Kzx4XbogPNs3CjduKxBLSFN\nRDRuHJpOeHmhwYRUtGlDdOuWdOeTm08+wZjHj1d7JMIID0cnrVWrtBdZbIqXL2G9qV5dmvPp9QiY\nO3kSnd/U8Aszph1NOjkZLj1rAwiV0qRPnEAXOUMYg5DWYq6/TbxmxoLHihbFRL9nj7zXtrNDsrs1\nplSdDtr0lCnayJuuVk3Z+udZGTOG6JdfkKoSFibNOatUQRlCW0Gnw0R/4ABaGNoCCQnQ/ufPh3XL\nVrh8GV2OpOhn/eYNorgPHEDetVo+4YQENIXQQsCkry9STq315z59qoyQXr8ecSGG3L8PN2qJEvJf\nXyg2I6SzatJEWA0FBMh/fSnycJs3h7lNC1XI8uQhunNH3TEMGIBiJ+3bEx06ZP35mjdHYxNbCB7j\nKFoUz++IEdBQtQxjRIMHo5nJwIFqj0YYYWHodGQtsbGY3NPTER2spqk5NlYbWnRiItHMmVhwWsuT\nJ/KbuyMikAudtUvh5cva1KKJbERI162Lji9Z6doV2tPLl/Je39rgMY6ZM5G2Ivd4LVG+vDaKf/j4\noKRk//7Ir7SGihWhncqV5iUXHh7Iq+3VS/nuYUJYuBD9sOfO1V5uriWOH7dey4uKwkKwaVMiPz/1\nc2m1YupetAjZNlL4+5XQpLdvx7yT1aqiVX80kY0IaXd3oitXsk9iTk4wme7bJ+/1pSqWUbs2/NO/\n/Wb9uayhfHnpI6zF4ulJdOQISkuOHy++L7ROh7x0W4yY7teP6LPPkFOemKj2aLKzfDlK3O7apQ3z\nqhD0ehQ+sqa/+4ULKHoxahQi87Xgi4+NFVcwREqio4k2b5ZGi9brkRoqt7nZz4+od+/s23OFtJXY\n2SHl6uzZ7J8pEeUtlSZNhLSVvXvVrZClFU2ao2ZNpMiEhaHGtTGrCR+aNtVe4Ri+TJiARVyvXtrq\njb11KyxAhw5lbkRgK1y+jN7cYlPFNm1CXXKxDSPk4vZt9S0a336LKnpVq1p/rthYBODJWQjm9m2Y\n1I1ZVXLN3RLQtKlxId21K9rCJSTId20py05Wrgw/7Lhx0pxPDNyiQ0s1pF1cEIxTqxY0BDHpVO3b\nQ0jbkl+aQ6dDnfMqVbDSF9p5TQ727UOa0YEDRG5uao9GHMHBRN7ewo9LSkLO7/Tp0J67dZN+bNZw\n+7bwBhZScugQrFY//ijN+ZTwR/v7I47J3j7z9rg4omfP8O5pEZsX0s7O8BXJafKWUpMmwsr8zBlp\nAqbEkD8/frMnT9S5vikcHFCJa/ZsTKx//CFsIVGlCvIftR6EZQoHhwxXSM+e6mYCcF3Mdu+Ghm+r\n3L4tPHf31i1Y7l6/RoGLunXlGZs1qCmkk5OJRo4kWrwY75sUPHkif3lZPz+kPmblyhVE/2cV3lrB\nZoR048Z4YYz5LOWO8i5XTpr0DY4CBYiWLEG1IrUm4uRkort31bm2JXr1gvl7yxaYv4VYMQYOROSt\nFvH19SVfX1+aOHHi222BgYEUHBxMvr6+RARzX9++gZQnTzB5ePi+DTLMup+pbVKwdi0KlcyaBWFl\nq8TFISBRSIeuLVtgDh01Cv5WLdXGNuTOHWnMzGKYOxcuqs6dpTvnrVvyCsnr1/E8GFsIaNkfTWRD\nQtrZGWbna9eyf9a9O3IW5Qq6qVwZCfBSmiA7dcLq7ddfpTunEGrUkLczlbW4u6NYRLNmSJ/ZsYPf\ncZ6emFy1RnBwMLVt25aGDRtGkZGRFBwcTGH/JYl7/2ePDQsLo9DQUHJwIPL396aSJYk8PcPowIFQ\no/tl3WYtjMG0O306CgXJUetaSfbsQcEYPoI2Lg7a4dy5sHANH66+z9cUqamItFfDBRERgYjuRYuk\nPe+NG5iT5MLfH4t/Y0F/Fy9qu0mMzQhpIpi8z5zJvt3FBSv+/fvluW7+/EjxkVrzXLQIJiM1cpZr\n1MheIEZrODigAMzOnUTff4/a35Yag3h6YgKTspqZFERGRlLQfyq+m5sbRUZGkp+fHzn9Vw3Dzc2N\ngoKCyN/fn5ycnMjenuinn9zI1TWIevXyp+ho4/sZbrOGN29QqOTsWVgx1PR3SkVAANJtLLFvHxbM\njGExrmWtigjpYOXLK9dti4MxVAscP176nss3bkhXES4rjOG57tXL+GfBwdq2GNmUkG7WzLhfmoio\nb1/kQ8pFzZrSC7UKFYh++AFmb6WDnWrW1LYmbUizZoj81umQU20u/sDBAU1NAgOVGx8fhg0bRsOG\nDSMiotDQUGrYsCHFxcWRi0Gya0xMDMXFxZHzf1UydDqi6tVjqGXLOPr5Z2fasIErB5l5P+7YrEyd\nOvXt31EzDdjv30cKWGIi0YYNsFjZOq9eIbWvSxfT+zx/Du3566/xvZct065525Dbt9Uxde/ciWdl\n7Fjpz33zpnya9KlTWNg0bZr9s8hIxL1kreOtJWxKSJsKHiMi+vhj1MZ+9Eiea8sl1EaPRmShn5/0\n5zaHLWjShhQuTLR6NRY0Y8ZAED94YHzfAQNg8tZilHdoaCg1aNCAPP6r/sB4DLJSJaI1a5AGNGsW\n/xQtQyHt5eVldJ8dOxBNzxXpUKNRhBzs3YvnwFjZzvR0ohUr8E6XKoXAISF+a7VRI2gsIQHv3bJl\n0mvwr14hBatiRWnPy7FypWn3xbFjyKHXqmuDiEjCcCj5qVULRThevCAqVizzZ0WLInXF15fo55+l\nv3bNmvJEkDs4YPL9+muUHFSqilClSngxXr4kKlJEmWtKQfv2iN6eOxfBhGPH4rczjDJt0QKRuWfP\nQgtXCmMBXM7OzuRjYHMNDg6m2bNnExGRk5MTxcbGEhFl0qqNbStaNJaCg4l69Iijv/92oQYNMvZ7\n8eJFJo2cD7GxMFveuQPfrZbNfWLw9cWCLitnziAorGBBBBhqMXLbEvfuKa9JT5uGhYw1RWFMcfMm\nFh1yFImJicHzvXCh8c85Ia1pmI3h5cXYgQPGP7tyhbGyZRlLSZH+uhcvMla3rvTn5fj2W8Z69WJM\nr5fvGlnp35+x06eVu57UREYy1rMnY+XLM7Z2LWNpaRmfzZvH2GefqTc2Y6xcufLt/wcFBbHQ0FC2\natUqxhhjc+fOZWFhYby2/fFHGCtRIpR5ea1i8fEZ+xli6tXW6xnz82OsdGnGRo1i7OVLOb6puty9\ny1iJEoy9eZOx7eJFxjp3Zqx1a8Y2bVL2PZOaJk0YO35cueudO8dYp06MPX4sz/k3bGCsb195zr1g\nAWOffmr688qVGbt+XZ5rS4VNmbuJEPZ//rzxz+rUQa7srl3SX7d6dWgdcvWEnjkT5nQl21kWKmSb\nZTQ5XF1RbW77dpiD+/VDsJBeTzRoEJ4DtVpyZiUoKIgmTpxI7u7u5OzsTDqd7q3JOzg4mJycnKh+\n/fq8tn39dX26fduD8uYlcnMLpps3nahuXcvRTvfuoSjHtGkwcy9ebBs+WKGsW4dnIV8+mLJ79IBv\nun17FGbp10/b5k1zJCfDkiRFwxA+vHyJrl9DhshXbESuoDHGYOoeMcL45w8eIA5DroA1yVB7lSCU\n48cZ8/Aw/bmfH1bLctCsGWO3bslzbsYYu3SJseLFoSEqwfr1jPXpo8y15EavZ2zvXsYaNWKsdm08\nB716MbZkidojk5czZxhr2JCxFi0yW0UMX+3nzxn77jvGnJ0Zmz8/s4aZ03jzBu/pX3/h/pcuDW3q\n9Wu1RyYNZ86Yn/+kpn9/xoYPl/caQ4fi3ZWao0cZq1HDtNVkwwbGfHykv67U2Jwm3bQpIvVM9Xfu\n0QOBFWLKSlqiTBkUVJGLevWIJk5EwIvYRhNCMFUP3RbR6ZB7fu4ccn03boT/ceZMovh4tUcnH02b\n4juPGoWYjE6dkPdJhGCfOXOgKSQm4p347jtomDkRxtDs4d9/UdKzYUOkTY4dq37XKqk4c8Z4lLIc\nbNyIZ8mUP1cKGENVOznqZpsLGCOyEX802Vh0NxF6IXt7o3iJqc+HD0cUotQ0aSK/eXjsWERPKlHk\npFo1mIO1Vh7UGnQ6dBr76y80h7C3R6rbmDGoapQTsbMj6tMH7piOHTPSjrjc/lOnEJxYpoy645SL\npCQIlMaNEVDYsSN+i++/zznR6hxKBUPevYsGGlu3Slf60xhRUZjvypeX9rzPnxP9/bf53uf37+cK\nadno0MF84ZLhw/FwSa1BKSGk7eyI/vwThU7k1Nq5aynxndRAp0N5x19+QQSvoyM0zcaNUZM6Jy1M\nOG7cwDPDlZotWhT55efOabMFpjVwBSq++AIT/MmTqDxYpQoWJLaUsSCEs2fl16RTUuCH/ukn+TtD\nyfV9/vwTzZcMSglk4s4dVK+0hbr0NiukDx0ybRIuW5boww9RoEBKGjZE0IbcrQQrVEBQT79+lits\nWUtOMnkbo39/mD+7doUA++UX9Ad+7z08Rxs3yv8by8nTp0S//07k4YHCHNWqZVTGi4iA+dffH8/U\niBEQ2FrMH+cDY2gpOGUKtOVBg2AtuHQJps2oKKJJk2w3KMwS0dFwYchdeOPnn4lKlkRqo9zIIaTT\n02E9+uIL0/vs3QvXkBZ6g1tEbae4WGrXZuzsWdOfHzvGWPXq0qda1KuHlAQlmDSJsX795E0XOXKE\nsQ4d5Du/Fli+nLGOHTNvS0xkbOtWpOW4uTHWrRtjK1Ywdu+eOmMUwr17jP3xB2Pe3ox5ejI2cCBj\nwcGMpadn7JP11X74kLFZsxhr356xChUYGzuWsZMnGUtNVXjwAklMZOzgQcZ++QX3ydUVQXDnzmV+\nL44dw2fJyeqNVW4CArI/x1ITFIQ01qdP5b0OR6NGjJ04Ie05AwKQpmZu3mzThrHdu6W9rlzoGLPN\ndfX48UghmjLF+OeMwcz5++/i+smaYsQImEiUWGW+fo3CHIMHozKZHCQlYdX8778wj+ZE3ryBGXTP\nHuOpKzEx6EO9fz/+W6cONNKWLfFXsaK62llcHEreHj2KinqHDiEVsVs3FMApVCj7MTqdzmg1M8Zg\n5tu+HWUzw8OJ2raF5al5c1SiU1O7SEiAif7oUdRUDgmBlcDHB8U06tbNfi8YI2rVimjYMPM+SFvn\n66/xHI8ZI8/5nz3Db71uHZ4ruXnzBubo58+l83szBuvgpEkIIjZGfDwsS48fy+tvlwqbFdKHD6Pu\ntTlT7YoVmHR37pTuumvXYvJQqtMSV3N2+3ZMRHLw4YeoztS9uzzn1wJLlyIPfelS8/vp9TCpHj0K\nP+epUxDaefKg8UK9eqg+5+YmfVASYxDCN29CeIaEILq2XDl89sEH6OrUqJHl1qmmhHRWHj1C5a3g\nYHzf2FgI/1KlIBDr1sWCRepSkOnp6NEeEQFz9cWL+HvwAN/zvfewuG7VyvgixJADBxDkFB6u3Z7A\nUlCtGkq3/pc2LylpaURffon7PmOG9Oc3Blf9jctGkILDhzGXXb9uerHp5wdXqMToBZ0AACAASURB\nVBwVJOXAZoV0cjI0wMhI06U0ExLgi/T1xQpUCq5dwySmZC/mgwehTV+4gAlbaubPx+8oR0S8Vnjz\nBlriunVEJspYG4UxRIFevoy/S5cgSK5dg+XBzQ2TpoMDUYkSeCYLFUKgmqMjOqilpsIqkpSU+U+v\nRwDLw4d4ns+fxzHVqkHjr1sXcRA1a2KRIAS+Qjorjx5h0rx0CYVArlzB+FNSUEq2UiW8SwULQgsq\nWRKTYd68+LOzw2/N/aWlIUjv6VP8N39+aPD37hEVL47vWaEC2mI2aCD8uzKGRcvEiegrn1OJjISl\nIzpaHkvH118j+2HfPuHPmlgWLsQ8amnhLIT27REgOmSI6X0GDICF0pzPWkvYrJAmws3o2dN4CzKO\nn3/GJLhmjTTX1OuJPvoI0YOlS0tzTj7MmgVz7dGj0ue5XrmCBiVKLjzUwM8PqW0hIdZPdHo9BFpk\nJP4bHQ1zYWIihBEniEuXxvPHCW3DvwoVYG4rVw5/rq7Za9KLRayQNkZaGr7D/fsQrs+eQejGxGBB\nEhEBIZ6cjAVzQgKEcf78+I56PYR5yZIZ39XNTRpT465diNYPCrKRICCRLF8Oq+Gff0p/7sWLYXU8\ndcp4QxK56N0bbpsBA6Q5X2golLKICNNzZFoa3smwMDybNoE6rnBpWLuWsR49zO8TG8uYiwvq+UpF\n9+6Mbd4s3fn4kJ6O644eLX0gmV7PWKlS0v5GWkSvRzWq9evVHon82PirzYvERMYqVmTs8GG1RyI/\nXbsytmWL9Ofdtw9V2ZSqcsih1zPWtq20FRx790ZFPXMcP85Y/frSXVMJbHrt2aMHfGnm8qGLFYMp\nZ/p06a7bti2Cd5SEy58ODydasEDac+t0RJ98Im8/bi2g0+G3mz7dttOucgGzZsEEbEttJsWQkgIL\nmtTBXOHh6CMeGAgrjpLcuYO8fqm6eUVEwJoyfLj5/Q4cMN9jXIvYtJB2coJ/cfdu8/uNGQNfy+3b\n0ly3bVs8EEo7CooUgaD+/XeibdukPXfr1kRbtkh7Ti3StCkC5eRoZ5qLcty5AxPt/Plqj0R+jh9H\nUGfx4tKd8/FjCKvff8dCR2n+9z+8h1JlTcyfDx+zuYYxej3Rpk22F7tg00KaCOUQLQmsokUhqKXS\npqtVw8MlldAXQoUKWHCMHo3as1LRoQMCl2JipDunVpk+Hc+MqW5quWgbxlDyc+JEeQIptca2bdL2\nvU5KQvDrZ5+hspgaHDyIIC8p+OcfxNNYSlM9dgyKna31ELd5Id21K9Hp08i1M8fXX+PBuHHD+mvq\ndBnatBrUrYsX95NPEGUsBQULwpxmySqRE3Bxgdl76FBELudiW2zciMWkXLUDtERKClJIP/lEmvNx\nbVyrVDFdY0JuUlJgHWjbVprz/fQTIvxLljS/3/r1WJjYGjYvpAsWhBYYGGh+vyJFkEv5yy/SXFcN\nv7QhbdpA0HTsiMhiKfDxsfw75hT69IFVYt48tUeSixAePiQaNw4R3VLnbmuRQ4eQOihVJDKX7bJ2\nrXoFek6fRh68qdRZIYSFwc88caL5/RISoICoZTmwBpsX0kT8TN5ESJw/fFga7dPbG/meampi/fqh\nAEHHjmjObi2dOhGdOIEKVzkdnQ5pLSdPIv85F+3DGKwfo0ahsMy7gJ8fUpWkwNcXc9bOnUiPUwvO\nH20tjGHBNmWK5YYqgYFEnp4o1mJr5Agh3aEDii9Y0igLFUI50WnTrL9mqVJoGXfqlPXnsoYJE/Dw\njRmDghnWUKQIVpr+/tKMTetUrEjUty++s7W/XS7ys2kT8rMnTVJ7JMrw5g1qI0gR6LRqFSqJbdhg\n2SwsN1L5o//+G3P+0KGW9/3zT9s0dRPlECGdPz8CIbZvt7zvl19CW7xyxfrrtmwpbclRMeh0iNBM\nTcVvkJRk3fm6dcOK+12hf3+U+hw3Tu2R5GKOa9fgrtq8WbmKWGqzfz+q2VnbB3zlSqKZM2FFlKry\noliioxG8ZW3nq7Q0KFxz51p+Hu7dw3zfubN111SLHCGkiaAR8TF5FyyIyNCpU62/Zo8eENJq12yz\nt0dQRMmS1gvqDz9ERanQUMmGp2k4s/f+/ahelYv2SExEVcH584mqV1d7NMqxc6f1pu6VK5FPrgUB\nTYTvVK6c9QutNWtQOYyP4N24Eb+j1JUalSLHCOk2bWCuvXnT8r5ffIEIw9OnrbtmzZoo7yhlgXix\n2NvDpFO8OBYPb96IP8/QoTCPvSsULUq0dSvRjz+iKEIu2mLkSHQ2GjRI7ZEox/PnMOeaK3lsiRUr\ntCWgieAb9vGx7hyvXkHJmj/fcvAbY7Zt6ibKQUI6Tx4U6F+50vK+jo4INhs5Et14xKLTQSDu2CH+\nHFLi4ACfk5OTdYJ68GAErCQkSDs+LdO0Kbrn9OgBzS0XbbBhA0yVS5aoPRJl+fNPBHI6O4s7fsUK\notmztSWgnz6Fhc7aoLFff0W6qLG2s1k5dQpZAA0bWndNNckxQpoIJeE2buRn7u3XDxrU8uXWXfPj\nj9X3Sxvi4IAAm8KFsWJNThZ+jnLlUIFM6qpmWuerr/Dif/65+i6MXFDyd/x4PIdStwXVMno9lA2x\nXZqWL4eAPnJEOwKaCO6kDh2gJInl33/x/WbO5Lf/n3/CAqNmP3hryVFCunJlmMX4RCfrdGiRNm0a\nuhaJpWFDmF+kKJIiFQ4OCLCpWBHmMjHpWcOHv1smb6IM/3RMDNGiRWqP5t3m+nXEmfj7o8Lfu8SR\nIxBkYoKrli8nmjMH53Bzk35s1hAYaH2k+uTJWLzwyRt//RrX7N/fumuqTY4S0kS4gXy141q14KsY\nP1789ezsYCL9+2/x55CDPHlgIuS04kePhB3fvj3q+4aFyTM+reLoiCC8BQvePUuCVnjyBKbe337D\ns/uusWIF5jGh2t+yZdoV0DExaLX50Ufiz8EVLpkwgd/+u3YRNW5s+6Vjc5yQ5ipw8RUuU6bgobam\nA1SfPkhb0pqJ1N4eL66PD4ro37ol7NihQ9+tdCyOcuWI9u5F2ckTJ9QezbvF69co9TtokHR9hm2J\nx49RbrhfP/7H6PUIety/X5sCmojor79QpVGs20JI4RIOztRt6+Q4IW1vD1MtnwAyIhQ4WbAA/kix\n1cO4LjJqFzYxhk4HE9FPP0ErOXuW/7FDhkCbfBcDqerWhctg5Eiiq1fVHs27gV4PwVytmnp1pdVm\nwwY8c3wF0evXqOt97BjSkrQooIkQX2DNoosrXDJsGL/9HzwgunAB3cNsnRwnpIkQ+OPvz98X27Mn\nUdmyqAcsBp0OWueaNeKOV4IhQzC+Ll1QxYgP5csj7zogQN6xaZV27VDdqkMHdNnJRT4YQ1rNq1dE\nq1fbdqCPWBITkVbEV5g9fEjUqhVRgQIQgmpXEjPF/fvQ8sVWGUtNhUty3jzE2/BhxQoUrrImSE0z\nsBxKz56MLVvGf/9btxhzcWHs33/FXe/JE8aKFmUsPl7c8Upx7hxjpUsz5uvLb//jxxlzdWUsJUXe\ncWmZlSsZq1SJsXv31B4Jf2zp1dbrGRs9mrGGDRmLjVV7NOqxcCFjPj789g0JYax8ecZmzcLvp2Wm\nTWPsq6/EHz9nDmODB/P/nvHxmMsjI8VfU0vYzpsskKAgxurWFfYA//gjY717i79mjx6Y0LXO7duM\ntW3L2PffM5aaanl/b2/+Qj2n8vvvjLm7MxYdrfZI+GErQlqvZ2zkSMaaNGHsxQu1R6MeyckQuhcu\nWN43IICx4sUZCwyUf1zWkp7OWOXKjF28KO74GzcgcKOi+B8zdy5jn34q7npaxDbeZBGkpzP2wQeM\nBQfzPyYxEQ9UUJC4a+7bx1ijRuKOVZrnzxn78EP8Rk+emN/35En8LsnJyoxNq8ybx5iXF2MPHqg9\nEsvYgpBOT2fsyy8Za9qUsbg4tUejLuvWYeFsDr2esZkzIczFCj2lCQpirF49cdp+WhpjzZoxtmQJ\n/2OSkhgrU4axy5eFX0+r5EifNBFSowYOREoCXwoUQH7syJHiioC0b4/ghvBw4ccqjYsLgjFatECu\n97lzpvdt0YKoalVES77LjBsHn76nJ9Ht22qPxrbR6+EzvHwZXZGKFlV7ROqh16OKlrmeyMnJiFTe\nsQPvKp9qW1pg7VrEw4iJMViyBD7oL7/kf8yGDWhKUreu8OtpFrVXCXLCmZBCQvgfo9cz1qkTfD1i\nmDyZsW++EXesWuzezViJEowtX256xXvqFPyy77o2zRhjq1djtX7pktojMY2WX+20NMZGjGCsZUvG\nXr5UezTqs2MHLHCm3r3Hjxlr3hxxNomJyo7NGmJjEafz/LnwY+/ehZn79m3+x6SlMValCuJochI5\nVpMmQs3W774Tpk3rdESLF2MFKKad5eDBSN0Ro4mrRdeuSB9buhTjN1ZWtXlzovfeI1q3TvnxaY3P\nP4fF5cMPrW/S8q7x+jWyKVJSEPFbuLDaI1KX9HS0mp02zbi2eeQIUic7dUI9/QIFlB+jWLZuhXXR\nxUXYcXo9Uq0mTYIFjy+BgeiM5ekp7HqaR+1Vgty8eoUgi1u3hB3355+M1aghbuXq7c3Ytm3Cj1Ob\nhAQEXNSvj5VsVk6fZqxixVxtmiMoiLFy5RjbuFHtkWRHi6/2kyeMNW7M2IABuc8Qx59/QkvOqkWn\npsIqV6YMYwcOqDM2a2nYkLGDB4Uft2IFnpO0NP7H6PWMeXgwtmeP8OtpHe29yTIwZQpjQ4cKO0av\nh8D64gvh19uyxXIQiFbR6xlbvBiR8atXZ5882reHWTwXcPUqUtQmTEAglFbQmpC+cYMxNzfGfv5Z\n+ylDSpGUxFiFCgjMNOTePQjudu0Ye/RInbFZy+nTiNgXImgZY+z+fShVV68KO+7gQcZq19bWOygV\n2nqTZeLZM8aKFROeAx0Xhwl4xw5hxyUl2X6e3pUrWJl27MjYw4cZ28+excTy5o16Y9Maz54x1ro1\nY126aMfHqiUhvWcP/M9r1qg9Em0xdy7SNg0JCEB8yK+/2rbA8fFh7I8/hB2j12O+mTFD+PU++ECb\nFi0p0M6bLDPffMPYuHHCjztzhrGSJRn75x9hx/34I2OzZwu/npZISYEVokQJvACcBvTRR8IKxbwL\nJCczNmwYVvNaWJxpQUinp+P5KVcOgYe5ZBATA43x5k38++lTxvr2xULv7Fl1x2YtERH4bq9eCTtu\n8WIsWoQWTjp7FkGtObXgkvpvskLcv4/V/LNnwo+dMQOakhDTTUQEY87OOaNAw8WLED7duyPSNCSE\nMU9P7WiNWkGvh/bQoQNjf/2l7ljUFtKxsdCKPD1t12QrJ999B1eaXs/Y1q2MlSrF2Lff2lb0tim+\n/pqxiROFHRMaCsF+547w63XvDgGfU9ExprXeTfLx1VeIjpw/X9hx6eno4NKuHdEPP/A/btAgRCdO\nnizselokORkRqGvXIvp93z6iUqWQ35lLZk6cQI7+Rx/hWVMjIlen05Far/bx40QLF6K/+9y5aJua\nSwb37hE1aIB621OmoC782rVETZqoPTLriY0lqlKF6No19EPgw6tX+D2mTUMPcSHcuEHk5UUUFWVb\nke9CeKeE9OPH6CEdGkpUqZKwY//9Fw/S7t38m7HfuoV0gMhIdNvKCZw7h8VH/fpE//sf0ZkzSM3K\nJTNxcVgUXrpEtGULfi8lUUNIJyWhZeK2behC16WLope3GUaNIvrnH7w7X3yB3yxfPrVHJQ2zZxPd\nvCms8NHAgUiXXb1a+PUGDyZyd8dvmGNRU41Xg59+YmzgQHHH7tiBQDIhJQx790Y5yZzE69coel+g\nAGPVqiFQLhfjbNwIM95vvykbCKT0q33+PGPVqzP2ySfiile8K6xezVjBgsie0HIxHDEkJwsv8rN+\nPVJdExKEXy8qirGqVXN+U5Z3TkjHxyMQTGxt1xEjGOvXj//+ly+j69Tr1+Kup2WuXWOsUCG8mLt2\n5abWmCIyEjWIO3ZUrpOWUkI6ORn5vCVL2mZtAKWIjUWdcnt7xoYP59fYxtZYv15Y6umNG1jAhoeL\nu17//lC6cjrvnJBmjLFFizBhiiExkbGaNRnbsIH/Md265dzAhoMHIYBq1MALKjS/8V0hNRWNAlxc\nEPUvdzEPJYT0lSsofNOpk+10B1OatDQU5yhZEimNXbqoPSJ5SE9nrE4dxvbv57f/69ewJojtGnjx\nIpSfdyF49Z0U0m/ewGx95Ii44y9fFhaJeP48cotzapWlfv2Q4vbHH0jXGjUKKSa5ZCciAkLtvffE\nd1vjg5xC+tUrxiZNQr3pNWtyLSjG0OsZ27uXsa5dEeG+fTvmDMOaAzmJXbsQZc33WZg8mbE+fcQ9\nO3o9Y23avDtpoO+kkGaMsc2bUXpO7ASzZAnyGvmmTLRvn3N7Mj97hlXt2bPwR44cidaW8+YJz5V8\nV9i9G7/RJ58IL7LDBzmEdHo6yliWK4eFmRzjzgkcPYqKYbVqQXilpuLfS5eqPTJ5SE+HVrxrF7/9\nly2D5S0+Xtz19u3DIjen5kVn5Z0V0unpMNUFBIg7Xq9HDeKPP+YXEHTiBMoi5kRfFGPwR9asmVGJ\n7Pp1CKCSJWHefRfMUnyZO3cuYwwLvJ49A1iRIkGsZ89Vb3+7gIAAFhQUxFatWvX2GL7bOKQW0mfO\nYFHbqBFKPuaSnQsX0KPdzQ0Bg1xdhRUr0DPbliuImWPbNvNdvAw5cgQ54WLyoRnD/FmrFha57wo5\nuguWOezskOP7ww9EqanCj9fpiHx9iZ4+5Rf+37IlUYUKSE/JiXzyCXLCZ83Cv2vUQNeeI0fQX9vN\njWj6dKQmvcsEBQXRoUOHiIjo5s1Q6tOHKCTEmx49InJzC6OpU0MpPZ3I29ubiIjCwsIoNDSUiCxv\nk4O7d4nGjiXy8UGf9bNniZo1k+VSNgljREePomdyt25EPXogd7d/fyJ7e6KHD/Hcr1qFOSenkZaG\nXO8ZMyz3jI6MJOrTB10C3d3FXW/9enTVepfS+3LgY8Ofdu0gONeuFXd8vnxEO3cSbd/Or4Xj5MlE\nM2eiOEpOQ6cjWraMaPlyosuXM7bXrImX8tQpoogIvJw//4yiB+8iOoOZzM/Pj4oVK0ZVqxJNm+ZG\nXbsG0dq1/jR2rBNt3EhUubIbBQUFkb+/Pzk5ORERkZub6W1ScvMm0YABqAlQvjz+PXBgzhQ0YkhJ\nIdqwAbUTRowgatQIC5ovvkDOLxFaLg4ZgsVNnTrqjlcuNm8mKlkSc6k5Xr3CImbyZKL/1pWCSUzE\ngmD+fMsLgpzEO/3K6XToNe3rS/TypbhzFC9OtHcv0cSJRMeOmd/X25uoaFGiHTvEXUvrlC1LtGQJ\nJvOsPamrVcMq+Px5okePiDp2RFGH8HBVhqoKYWFhbzVfIqL4+HhydnZ++++iRWOoY8c4mjLFmVau\nxAR/8mQMvXgRl2m/mJgYiovLvk0Krl6FttOqFVH16lhYffddbt9njufPoTVWrgwhPX06NOcvvyRy\ndMy87+LFmFfGj1dlqLKTkkI0dSoUD3NCU6/Hgq9ZMyxYxLJ0KZ7LRo3En8MWeaeFNBFRw4ZEdevi\nYRNL9eqoKtW7N9GdO6b30+mwkly9Omdq00REvXrh9/j+e+Ofu7lhUbR9O8xWHTrAFbBxY3bBntOI\nNWI+YEaqgjVqhNKiX39NFBKCEqxbtsjrKggNhUm7bVui99+HcP7xRywqcyG6fp1o+HC4dKKiiA4e\nJAoKIurUybh1ITwcwnzTJiIHB+XHqwRr16LaoKen+f04y9mSJeI14MhIlJidM0fc8bZMDn18hPHr\nr0S1a2O15+Eh7hze3lhVd+6Mcn8GSk4mOnWCuWbNGrz0OQ2dDiUh69cnat8ev4cxKlRArd7Jk2GJ\nWLmS6NtvcQ9GjLDNUqO+vr7Ztjk7O5OPj082LZqIyMnJ6a3gjouLIxcXFyKCMNfpiKpUiaNvvnGh\nK1eIQkJiydWVqGHDOKpd24WcnDKE/osXL94ea8hUg5Wnl5cXeXl5Zfo8KYkoIAC/fZEiMFlu2EBU\nsKA1v0LOQa8nOnQIdcgvXYK2fOsWzLvmePOG6NNPiebNQx3rnEjS/9s78/CYzvaP33kpiVoiQS1B\n7WpJJLbaKhJB0FIpaitKLG3VVl1eXVT1VaVV/CwR1L5rKIIstlBEJCGpxJIEQUJkj2yTmef3x7dj\nkjRIMufMen+u61wnBs9zZjLnfJ/nXnOwCPHxefG/27MHJvHgYI0boKwIAavbZ5+VvZyzSaDvyDVD\nYcMGRK+WtUl5cebOFcLZ+cU50eHhiHo25fKJQUGI4ixLkYvbt4X44gt8Ns7OiBo1ldzy/fv3i/37\n9wsvLy/RsWNHERoaKkJDQ59FZv/8888iLCzsha8lJAjRv//Pok6dMGFvHyomTUJEuPrfFeZFt3Z0\ntBCzZyNvd8AAIXx8TDfroKyoVEglnDVLiPr1hRg9WohNm8pW+nbmTCGGDzft/PHVq5Hd8iLOnUPR\nKG3Ln+7fj8wRU3kWlBWzN3ermTgR3XpK2AyViSVLsCuZPh0rwJJwcEA0tCl0x3oePXsiiGb8+NKb\n9ps1gzkrPh7/V92kYepUomPH0InLWPHw8CAPDw+ysLCg9PR0srCwIMd/zDaBgYFkbW1NHTp0eOFr\nf/8dSB4e1vTgQQf6/ntH+usvorp1A+nUKWuqWvXFHTxycpBZ0KcPUe/eRJaW2N0cO0Y0dKjpmmRL\ngxDYKX/5Jdwx48cTWVujS9WOHXg2WFqWbiw/P6KDB4nWrTPd4KaEBJiwX/T8ioggGjaMaOZMPO/K\nS2Ym0axZCEgt707c2DGrLlgvIyKCyMUFwTOvvVb+cbKy4KcZNer5vtnUVKQpHT2KCFFTpKAAD7gW\nLXBTl4eYGJjUDh5E+7sBAyAq7u5YDJk7N24gs2DLFkRhv/8+FoCNGllQWpqgo0cRqOjvj5iJvn3x\n+ZnrA68wUVFYuOzZgyCokSPx+dnbl09gY2KIunfH97V7d+mv11AYOxbuqsWLS/77uDg8/5Ytw+ep\nDXPm4FlZmuwZk0XfW3lD4/PPy9ZA43nExwthZ/fiKjwbNwrRtavpFjkQQoiEBFSoOnJEmrG8vIRw\ndxeiWjWcvbyESEzUfmxjR6EQwt8f5tlXX4W5u1IlId56C9+zpCR9X6H+UShQlGXpUlTIql8fZv9L\nl7Q3TWdloXa1qdboV3PmDEocP69rVWKiEM2boyKjtqjdgo8faz+WMcM76WI8fYqe0xs3lj+fT01E\nBHYuv/+OlKPiqFRYcU+dih2nqXLhAnZv58+Xv4hBcTIyYKr18SE6fhxm8caNsYLv3t18UoYKCpCX\nfukSIsAjI4n69SPat8+CpkwR5OcHd8PAgTh69zafiG0hiG7ehBUhIAApko0bwxozcCBcMlLkfQuB\nHWOVKoh4NlUzd0EBrH7z58NaU5z0dLhT3nlHu2wZIjwbe/RAGqKnp3ZjGTss0iVw5AjMLNeuld4X\n9TwuXsSXdudOCHZxQkIQAR0VRVSzpnZzGTJr16LYycWL0kcP5+UR/fUXfIhBQURXriANrFcvzVG7\ntrRz6ou8PKLLl/E+z57F+7azg/+vWzcsLCtXRtEUIQQJgUIkR49CzH18IFTduqFQSbducLuYQpGS\n3Fy8x+BgfEZnz+Jh7+aGe8/FRTs31vNYsoTowAHMp+3zwpBZtQpup4CAfy9EcnOx+GnXDv9O24XK\n778jPujcOdP4bmoDi/Rz8PDAA+yzz7Qf6+xZjHfgAJLxizNtGoLWVq3Sfi5DRQiiSZOIsrOxYJHz\nxissZEFBWBjUrYtdfLt2mqNVKwiaoZKZiZ1xRAQWjKmpRIcOYQHy1ltYfPTsWfICRC3SxVEoMN6F\nC/hcLlxAgY4uXTTC7eSENCND3REKgeClW7eI7tzB7/rSJeQyt2qF99KlCz6f5s3lfR8nTsAKFhyM\nxZKp8vgxLIxnzqCKYGEKClAfoXJlae7t27fxPQwKwgLS3GGRfg4PHyJn+sgRaSrcBAQgd/LPP/EF\nLExyMr6M/v7aRUIaOrm5yA1v2lR7c1hZUCoR1BMZWfSIiyNq0kQj2k2aQMzr1cPZ1lbeB7wQMBHe\nu0d0967mHBtLFBYGIWrTBoFM9vb4bnTsWLqAueeJdEkkJUGw1aKdnAzxa9685KNuXfkFXKXSCPHt\n20XPMTFEVasiILF9e1Sz69IF92uVKvJeV2HUgWL797+8oIexM2kSIt5/+aXo6yoVzN+hoUSHD2sf\nkFhQgIXnqFGIDGdYpF/Inj2oFRsaKs3N7+tLNGECfKhOTkX/zssL1YnOnjXcHYwUPHoEX9O8efDF\n65O8PPgsIyPxwI2OJkpMhDgkJCBK/7XXNKJdrx5EKi8PKUsvOiwtUWUpIwNCnJGh+TkrC4vAe/cg\n1I0bEzVqpDm3bg1xbt4cTRrKQ1lEuiRSUiCKhY+YGJzbt4dY2tqiLK6treZo0ACLokqVYB1Sny0t\nEe+Rl4cjNxfnV17BwuTJEywOkpPxc1ISymyqFwYtWhRdKOg7sj8jAy6Gd9/VrtSlMXDpEt5rVFTR\nz12phL84JgbulKpVtZ9rwQIsFI8dYzO3GhbplzB6NB4+UpmifXyQQ+3vX7TovlJJ1LUrcgLHjpVm\nLkMlJgY7jzVrEFBmqOTlQbTVwp2YCHPxo0dY8b/oqFcPZTxr1MCDrXp1zc81asCc3KgRfpZjUaat\nSL+IrCwIaWFhVYtrxYro/KRQIK1Jfa5fH5+bpSXMopUr4+d69TBmccGvX99wg/9ycpAC2LGj6Td7\neN5zSalEUNe9e7A2ShFncuECFj2hofj9M4BF+iWkpsLUuGnTyzu9lJbduxGYdvIkdk1qLl6E77r4\nitUUuXIFD7o//oB5i5EWOUXanFEocI9WrQrLl6nv9tauhXhu2aJZjBQUwCKYkAATtxRWxsxMlBJe\ntgxCzWhgkS4F/v5YNV67Jl0E9tataLSxalVRP/SkSdhd/fqrNPMYMv7+EV9vfgAAIABJREFUWJ2f\nPImgFEY6WKSlR6WCOCUnI8r5lVf0fUXyog7gOn9eU0u/oAD19dWfgVQxAB9+iAXPhg3SjGdKmPg6\nUBrc3GCWldL39MEH6HLUrx+iGNX89BOqSAUHSzeXoeLmhsWIuztKgTKMoSIE0ezZCDbct8/0BVqp\nxILk6681Aq1QwP2XloYsA6kEWp2+9ttv0oxnarBIl5IlS+Ar2b1bujGHD0dtYA8PmI2IkE4zfjzR\nmDEwAZk6Y8YginPAALgWGMYQ+eEHCIlU5l1DZ8UKBC1++in+nJsLF112NuJqivfOLi8PHhB99BGe\ng1IEnpkibO4uA5cvo7LV5cuoXSvluO+8g1q4EybgtUmTYF4zl5q1c+fCeuDnJ90DwJxhc7d0rFqF\nIyhInmIohkZ0NAI7L11CumRqKtGQIQjm2rJFutoCKhXa2fbqVf7a/uYA76TLQOfORF99hRKACoW0\n4546hfSDZcvw2ooVqCYl5c7dkFm6FNHOH38s7WfLMNqwfTu+m35+5iHQBQWw5C1cCIG+fx8i2rEj\nCpVIWfxn5Uqk5f33v9KNaYrwTrqMqFTY9bZogWbwUnL/PnzUb78N33RoKPy1wcFEr78u7VyGSH4+\nLAlZWUR795p2iUW54Z209hw+jDzgkyf/XWXLVFm8GO/Xzw9ZJu7uiJ2ZO1faVDN1x0H1bp15PizS\n5SA1FSvLn34qudC8NiQnEw0ahGhnLy8EUxw8SHT6tHn0/FUoEPGdkoL3LXWdb3OBRVo7/PwQNLV6\ntTQVB42BiAgEcwYHI5Bz2DBUGJO6bkNuLj7TuXM17j3m+bBIl5PQUPhTgoKK5jpLQVYWgsmsrGBu\ne/ddVOnSZSlNfaJUEk2ejBSQo0dNP2dcDliky4+PD6rh+fjgvjMHsrIgnN99BwvWlCl49vTrJ/1c\n8+fDarh5s2kXgpEK9kmXEycn7KQ9PPAFl5KqVWFqa9UKrQUXL8au+tw5aecxVCpUQKtQe3t0dUpJ\n0fcVMebC9u2INj5+3HwEWgi85zffRIESLy+UMJZDoFevxuJn5UoW6NLCO2kt+fBDmG927JD+SycE\n8oiXLUMqhJcXUXg4Ct2bA0IQff45Og35+5tH4I5U8E667KxbR/Tjj/i+mYsPmggZJEuXYuMRGYkc\n6MaNpZ/H3x+FUM6fJ2rWTPrxTRUWaS3JyUGLv8mTiT75RJ45AgLgF2rZErWOd+82n1WoEIg03bUL\nn4MptwOUEhbpsvHzzxDpgADzCmT6+2+0PbWzw/Nl82Z54kCiozHP/v0lt+tlng+bu7XEygoVcxYu\nRO1tOejbF/Vz09MR0LJ+vTzzGCIWFvCTTZqESNMbN/R9RYwpoVSiktiVK4gvMSeBfvoUmSRCEL33\nHjIq5BDo5GSiwYNREIoFuuzwTloijhzBl3D7dnlMRUSo9vPeezAb+fkR9ekjzzyGyo4dqHq0YwcW\nLszz4Z30y8nORsW7tDQ0epGqLr+x0Ls3UqB27kQktxzk58O33aULrBVM2eGdtEQMHowv+sCB8pW3\nrFIF0c5DhmCeY8fkmcdQGTMGq/1x44j+7/+wA2CY8pCYSOTsjHaYJ06Yl0Dn5+N5FRpKdOaMfAKt\nDkirUQPBr0z5YJGWkNmzkWc4bBh6EcuBhQUK/PfqhdSs5cvNS6x690YlNi8vomnT8MBhmLJw/Tri\nSAYNQpnLSpX0fUW6Iy4OLSH9/YkCA9ErWi6WLycKCYHlq0IF+eYxddjcLTFKJQqcWFoSbdsmX7/Z\n3Fw8aBITYfr18jKPwv9qMjOxs87IQDBKrVr6viLDgs3dJXPoEALERo1CJzpzwscHAa4KBRb6/fvL\nN9eRI8g1v3AB5X6Z8sM7aYmpUAF+6Tt3kLQvF5aWMHdXrEj0+DF2mFeuyDefoVGtGh463brB3xUZ\nqe8rYgwZhQIVrmbORCCiOQl0Xh5SOGfNgln/hx/kFehr15CaeuAAC7QUsEjLgJUVVux//IFVu1zU\nrYt5QkNhYnd3R5S5uTSoqFABvq6FC1EHWN3uk2EKEx+PReyNG1jIvvmmvq9Id8TEoChLfDxRu3YI\nNlW3n5SDR4/Q22DFCvP6nOWERVomatVC1Z6FC+UVDycnojVrsBjw80OhgB49zCtVaexYfMbTp6P4\ni0ql7ytiDAVfX6JOnYiGDiX6808iW1t9X5FuUKngAvv4Y3S1atsWLqLVq+WrsZCbiziZ8ePhTmCk\ngX3SMhMcjEjKo0flLdS/YAFE+uRJVBD69luib75BgRW5/OKGxv372CVkZKAogzkXPjF3n3RBAe6B\nbduQYtSrl76vSHfExsL3nJWFZ8G1a2gHGRxMVLu2PHMKgayL/HwUWzKXZ44u4I9SZrp0IdqwAWlT\nsbHyzfPtt0QNGkCYp07V9KJ2cyO6d0++eQ0JOzsExLi4wMKwa5e+r4jRBw8fouZ7SAjM2+Yi0CoV\n0apVeOa4u+MZkJ6OOviHDskn0ESI5L5xA4tjFmiJEYxOWL1aiJYthXjyRL45srKE6N5diJkzhVCp\nhFAohPjf/4SoVUuILVvwmrkQEiJE69ZCjBolREqKvq9G95jrre3vL0TdukIsXChEQYG+r0Z33Lwp\nRM+euP+jo/FaRIQQdeoIcfy4vHMvXy5E8+ZCJCTIO4+5Yp53sp74/HMhevSAmMpFSooQ7dsLsWiR\n5rWwMCHatRPi3XeFePxYvrkNjadPhZgxQ4iGDYUICND31egWcxNphUKI774Tol498/pdFxQIsWyZ\nELa2Qvz2m2ZhcueOEHZ2QuzYIe/869YJ0bgx5mPkgQ0TOmTxYqLu3RHEkp0tzxw1a6KC0qZNmsjy\nDh1g+mvZEqkXW7aYR3BVlSpoieftjWCWOXMQ3MKYFmFhSMV7+BDmbVdXfV+Rbrh+HUGihw+jvOfM\nmch4SEpCKc5584hGj5Zv/q1biRYtQlEUuUohM2Rmy20DoKBAiDFjhHB1xU5PLm7fFqJ+fSH27Cn6\nenCwEF264LhwQb75DY0nT4QYPlyItm1hWTB1zOHWzsoS4rPPYNLdtMl83DlqN5atLdxoSqXm7zIy\nhOjUSYj//lfea9i9G1aLqCh552F4J61zKlTATrZ+fXSgkWtH3awZ0k8++QRR32o6d0YVoI8/JvLw\nQFGHBw/kuQZDwtaWaM8eoi++QDDdkiWoDscYJ8eOIe83IYEoIoJo4kTzaN8aEIBc50uXYB376CNN\noFZeHuoldOiAHa5cHDqEXfuJE0StW8s3DwM4BUtPKJWoyhMfD3OVHC3iiIjOnUPu4uHD/y4ukJkJ\nE7yXF6oxzZmDSmamzt27SFGxskJVODnrF+sLU03BSkxE5azLl+HOcXPT9xXphuhomK+jotBN6t13\niy5KlEqUyc3PRxOaihXluY7jx+E68vUl6thRnjmYovBOWk9UqAC/caNGyKN++lSeeXr2RFrE0KFo\n8F6YatWI/vc/PPCuXCF64w2U8jPBZ3sRGjfGLsDDAzuPcePMw5pgzKhU6KNub0/UpAl2z+Yg0E+e\nEM2YgTSyPn1wDw8b9m+BnjgR9/POnfIJ9KlTsLwdPMgCrUtYpPVIhQrIYXz9dXTkkUuoBw1CJa5P\nPsFKvDhNm0KcN24k+v575BlfvSrPtRgK//kPdgTR0UQNG+Lhv2gRUU6Ovq+MKc716yjr+fvvCFJa\nvNj0m8nk5RH98gsWzkS4b+fMIapcuei/KyiAcCYkoBSnXJYwX1+iCRNQ6rhbN3nmYEqGRVrPqIW6\naVP0iM7Kkmee0aOx2nZ1fX4zChcX1AEfMQLRodOnI1LUlFFbE0JCiMLD8VDcu9f0rQnGQHY2ivT0\n7o0yk+fPE7Vvr++rkhchIIRt22LnGhSEAiUldXkrKIAV6MkTlDyVa+GyZw+eHXv2wDLH6Bg9B64x\n/6BUCvHhh0L06iVEZqZ88+zYgWIP4eEv/nfJyUJ8+ikKoaxYIURurnzXZEicOiWEgwN+D1eu6Ptq\nyo8x39oKhRDr1wvRoIEQs2cL8eCBvq9IN1y+jO9d+/ZC+Pm9+N/m5yNbYcAAIXJy5Lsmb29EcV+9\nKt8czIvhwDEDQqUimjYNubzLl8vXDGDfPvi5fH1RPvNFXL+Oovx//onI6MmTTT+4TKmEdePbb+Eq\n+PFHdBwzJowxcEwIuF3mz0eJ259+QolLUyckBK4WpRLlgydOhIXteeTnw7KQl4fPq7gJXCqWL4cJ\n3d+fqEULeeZgSoGeFwlMMZRKIebNE6JVKyFiY+Wb548/kF966VLp/v3ly0K88w5yr5cvlzfH21BI\nSxNi7lzkoy5ZYlzv2dhu7cBAITp3FsLRUYgTJ8wj5/n8eeyE7eyEWLlSiOzsl/+fvDwhhgzBvSiX\ndUulQvW2li2FuHtXnjmY0mNcd7IZsXIlBDEkRL45Dh8WonZtPCxKS2goyovWrSvE0qXyljg1FG7e\nFGLWLCFee02IH36AK8DQMRaRDgkRws1NiGbNhNi1q2hhDlNEpcKCpE8fIV5/XQgvr9KLbU6OEIMH\n4/7Ly5Pn+pRKFIhxcBAiMVGeOZiyYRx3sply4AB8wr6+8s3h7y9Eo0ZCHDpUtv939Sp8YnXqoGaw\nnI1DDIW//xZiwgQhataErzQ+Xt9X9HwMWaRVKiHOnBHC3V2I/v2FWLMGPlZTRqXCfdy9O3aomzeX\n7T2npgrRty/iROT6rLKzhRgxAhURzbEpjaFiuHcyI4QQ4tw57OA2bJBvjuBgBIesW1f2/xsZKcSk\nSUJYWwsxZQqEzNSJjxdizhyI9YQJQly/ru8r+jeGKNJKJRaD3bqha9L69aYfkJiZid1y375C2NvD\nWlDW7lz37qFBzowZ8nX2SkwUomtXId5/X95ANKbsGN6dzPyL6GghmjSBn0guX93t23hwfv11+eZI\nTBRiwQIsKPr3F+LYMdM3XSYnw/xdpw58hGVxG8iNIYl0Xh5apbZpI4STkxB795p+G8moKOx6bWzg\nQ/bzK9/9cO0aurgtWybfvR8ZCdP7t9+aRyyAsWE4dzLzQhIShOjYEWlacpm7Hj9G440JE8o/R24u\nTHkODkglWbnS9E3h2dlodPD660ihOXJE/w87QxDpmzeF+OILLP7c3SFU+v5c5EShgIvKxQWL1fnz\ntQu8CgxEzMiuXdJdY3H8/DDH1q3yzcFoB6dgGRFZWSg0IgQKC1SvLv0cT58Svf8+kUKBVK1q1co3\njhBEf/1FtGYN0dGjaJH54YdEffu+OL3EmCkowGe2ZAmK0zg7o4hMSYUo5EZfKVjZ2UgL2rAB1dw+\n+AC/d3XlLFMkIQHv18sLJUs/+gilO7VJjdqxAxXG9u5FMRc58PYm+uYbzPHWW/LMwUiAnhcJTBlR\nKGCWatMGZnC55vD0hGkyIUH78VJSsNPs2BGmu2++ESImRvtxDRWVSojTpxGAU6OGEMOGIZJeodDd\nNej61r5yRYjp02HedXfHjlKuCGRDIDsb7/HTTxGPMXWqNAU/VCohFi9GMGdkpPbjlYQ6grtFC1g7\nGMOGd9JGirc3ij6sX4/mGVIjBAoshISgnneHDtKMe/UqajDv2IESj1OnYpdtbS3N+IZGejqsHps3\nE928GUo9esSRk1MKffedJxERHThwgKytrSk2NpY8PbV/TY0udtKpqfg9btyInydNQn3nhg1lnVZv\n5OejVeTu3egq5+SEzlMeHkQ1amg/vkJB9N13KDLk64t2tlKTmUn06adEcXEoP2pjI/0cjLRw7W4j\nxdOT6MgR3HBffy19b2QLC5jCRo9Gt6Hdu6UZ18GB6LffiO7fh1nwxAl0Ahs0COKdkiLNPIZCjRpE\nU6bA9N+580/Upo0H/fprGrVtG0ZffRVKmZlErq6uREQUFhZGoaGhRFS+13SBUkl08iTR2LEw7Z47\nR7R0KVFsLL4vpibQ6vc7ZQpE88cf0ZP9+nU0+/jwQ2kEOjERdfVjY4nOnpVHoP/+G9deuzZ6zLNA\nGwe8kzZyHj8mGjkS/q8dO+QpJXr1KvrXenigA5HUrfAyMuC33r8fO5Vu3Yjeew8WAn34c+Vg//79\nFBcXR/PmzSOlEqUWZ8/+khSKftSwoQu1ahVI1auH0n/+k0xubm7k6upKgYGBFBoaSsnJpXtt3rx5\nz+aTciedn49mDwcP4rC3RzOYsWPlK12rT5RKogsXYAHZt4/Izg5xGiNGYEEpNX/9hbE9PbHQ+Y8M\nW6ft24lmzyZatgzd3xjjQabOo4yuqFMHD/wvv8Qq+cABIkdHaedwcEDP6ZEj8XDevVvaVXj16qhF\nPGoUguN8fSHY33xD1LIlArBcXYm6dpWvTrHchISEEBF2vAEBATRv3jw6eDCNJkywoeRkonXriHbu\nTCYLizSKj8eHq1AQJScnU1paGtkU+sCf91pxFixY8OxnZ2dncnZ2LvX1ZmQQHTsGUT5+nKhNG9SV\nPn2aqFWrsr13Y+DOHdxH/v7YIffuDXN2UJB8dauFQF38H36AFWngQOnnyM2FOAcG4rC3l34ORl5Y\npE2AihWxQu7cGS0mf/kFUbVSYmuLh7V6MeDjI88NX7UqdhUjRqC387lzeLh89hmihbt1Q0tNFxc8\nRI0pUrxWrVrk6OhIAQEBdODAASIiqlxZ0KBBaFrSti1RTAzMp/Pno6WonR1Mn6mpZZ+vsEi/DKWS\nKCwMpt2YGKJdu4h69YI1Y/ly42sw8jLS02Ed8PeH6Tc9HZkH7u7ovW5nJ+/82dmIx7h2DTvpZs2k\nn+POHVikXn8di2wpzPKM7mGRNiFGjsSDftgwolu3iL76Stoes+rFgJMTdrbr1sEELhdWVvCHu7nh\nz2lpRGfOQEgmTiR68AA7HhcXXE+bNvCl6wtvb+9/vWZjY0MeHh5ka2tLTZo0ISIia2trunz5Mllb\nW1PKP074tLQ0sv3HduzmlkJr1hBt3JhGfn62FB5O9M47KdS+PZGdXRpVq2ZL1arRs/+bmpr67P+W\nFpWKKCICQnXqFPygDRoQ9elDNHgwfs/lTb8zRBQKouBgjShHRGDB5+YGk7a9vTxm5pKIjcU92q4d\nzOpy9IE+ehT+8i+/JJo1S7/3BaMd7JM2QdLTEZQVFgZf1MvaUZaHq1ex2+3eHU3pq1aVfo6X8egR\nBFt9ZGVBsAcMgEm2bVvDEZq4uDjav38/zZs3j5YuXUrNmjWjJk2aUEhICHl6etLSpUvJzc2NhBAl\nvnbxYgi1bu1JixYtpawsN/r7b0FVqoRQv36elJW1lIYPd6PhwztQpUqYr7hPOiODKDQU0fo3b8IS\nUrMmRNnFBS6F117Tz2cjNbm5sEKEhWmOChVQA6BfPwhzjx5YBOoaX18sML/+muiTT6QXT4UCWRmb\nNsEt1aOHtOMzuodF2oTZuROr6DlziObNk940nJWF6PLz52EelWMxUBbu3IFY37yJALSoKPjs27VD\nule7djhatdKPb9vb25tsbGwoJCSEFi9e/Oy1pk2bFkmjKs1rSiXRokXelJnZlIKDYyktzZNiYhA/\n4OhItGaNBc2fLyg2lujKFVgdHByIOnaE9aFrV/lNurogI4MoPLyoIN+6BT+yo6PmcHDQr7lXoUBW\nw2+/ISCtZ0/p54iKgpvL0RFCXaeO9HMwuodF2sS5dw83rkpFtHUr/FNSs2cP0YwZRF98gSAVXZkN\nX4ZSCdNiZCTMm5GROOLikD5UWLjbtUOVMGPxcatURA8fEt24AV99dDTSgiIjYT2IibGgxo0FPXwI\nMX7jDQThNW+uORo3lj5SXw4KCvBe4+PxfX70CAvDsDCkLrVvX1SQ27WDj99QiI4mGjcOmQq//y69\nf1+lIlq5EsL8ww9E06axeduUYJE2A5RKBMP8/DOCgMaMkf4mvnMHOdXVqhFt2WLYgUa5uRC34uLd\nvDl2YXXqwPRbp47mKP7n2rXlETilEu6KtDQEi6nF6f79oue0NMzfuvW/j0aNiCpUgLk7JwcLldu3\n/30kJCCvWS3abduiqEzt2hAU9VltQpeDvLyi7/PevX+fHz3CtTRqhOvt2BFnR0csPAx1YaVSwRW0\naBGOKVPkue8mTkSa3JYt+D0ypgWLtBkRHg4htbcnWrsWPkkpKSggWrgQdYw3bkSkrDGRnY2880eP\ncFYfJf05JQXm0zp1YEpNSdE8gC0sih7Pe61ePex+09I0opydjZQ0a2vsCJVK7IQbNix6trMjevXV\n57+X0uRJ5+XhIa8W7fR0FLxIStIcyckIbHJxwb+xsip6VKmCs50dPpuCAlyzUqn5uaAAYq+eIy0N\n5/R0/H2fPvi/DRtqhFh9btgQAW2vvKL971eX3LsH8czJgQVLavEUAn7nL7+EK2vuXMNdrDDawSJt\nZuTkwCzt44NSlf8UrJKUs2dR6GLyZPjD9RFUJjdKJYT58WOcnz7F60IUPV70mqUlBK5mTYiytTUs\nEVK4C6QqZqJSQVRTUrCAyMnRHIX/XLEizhUq4KhYsejZygpxADVqFD2srEzLNCsE0bZtSBmUKxYk\nMRGFT+LjMVf79tKOzxgWLNJmSkAAzG/dusEULnVkb0oKHlAnT2LXPmCAtOMzL0ZfXbDMmaQk5D7f\nugXxlKrefWH27UP8x+TJRN9+K68rgjEMDCTEh9E1ffvCH1u/Plbi69dj1yQVNjYwea9fj3SwsWPx\nEGMYU+TPP+FGatECaW5SC3R8POogrFpFdOgQfNws0OYBi7QZ8+qraI7g74+o0169INxS4uaGMevW\nxWJg2zaNyZdhjJ0nT+A+mjULfZmXLJE2vU+hQGEZR0dE6J84gfQ5xnxgkWbIwQEpLePGIUDoyy/h\nb5SKV1/Fg+bIEZjWBwxAGhTDGCsqFdrFtmmDALyrV7HIlZKgIIizvz8qky1YoJ8CLIx+YZFmiAjB\nStOmYdd77x7ScXx9pZ2jUyeUZnRxQf3vX39F5C/DGBNhYai09/vvKDH622/SVrZ7/Bh9uUePhjAf\nPy5fkw/G8GGRZopQty4qlXl5oZrYxIkQbal45RWYBy9exM76nXeILl2SbnyGkYv0dNwTAwYg6PLc\nOWl9z0olgizbtUPK2vXraJBhStHvTNlhkWZKpF8/7Krt7WFy++orPKSkonlzdLcaPx7NBsaMkXYx\nwDBSIQTqYLdpg0I416+jeYWUlfX8/Yn690er2cBA02twwpQfFmnmuVhZoczntWswwbVsiejS/Hxp\nxrewQMTqjRsQbUdHtGjMzJRmfIbRlqAgpCkeOoQe5+vXo22rVISGYkH88cdwN/n7c94zUxQWaeal\nNGiAdCp/f7TAa9uW6I8/pIvSrlqV6PvvEXwTH48GGBs2wPzHMPogOppoyBAEU86YQbRjB8RaKmJj\nYT0aNIjo3XdR6Y1N20xJsEgzpcbeHkEsq1dDVHv1QtSpVNjZoYTin3/i7OQE0x/D6IrEROxo33oL\nR3Q0xFQq03ZSEtHMmQicbNUKhU+mTze+sqeM7mCRZspMv34w002eTLR4MdHgwYjalopOnYjOnEFF\npV9/xXxSLgYYpjhZWYikVvcgj45GPWypumk9fYoCJG+8gfStqCh8v02xZC4jLVwWlNGK3FwU+v/p\nJwTWfPedtGbB/HzsqhctQoenBQuI3nxTuvFNFS4LWjoyM4nWrIH7pkULfM+kbOeakUG0bh0WndWq\nYXzuVMWUBd5JM1phaYmyn7duIUp71ChUGQsKkmb8SpWwY795E+OPHInuWlLu3BnzIz0dgtm0KWIh\nNm0i2r5dOoFOSiL6+muMHx4Oi9Pu3SzQTNlhkWYkoXJl5I7eugWhnjABLQhPnZImwKxSJYx/8yYC\net57D0E3nGPNlIWUFFh7mjXDdykoCHUB2raVZvx79+BzbtUKJUMvXcL49vbSjM+YH2zuZmShoAAP\np0WL8IAaPhw7YakCZPLyEHF+8CB+njMHvnHuqQvY3F2UBw+wU/75Z6KhQ5H3L+WuNjoadbsPHSKa\nNAmpi/XrSzc+Y76wSDOyolQiWnvFCqLbt2Ea9/Qkql1bmvEVCvgTf/mFKDUVjQ4mTEC9cHOGRRpc\nvIjv3okTaCM5ZQpRkybSjC0Eat6vXo0shBkzkO9sYyPN+AxDxCLN6JCrV4lWroSoDhuGEosODtKM\nLQTRX39BrM+exULgk0+Q422OmLNI5+ej8MiKFfANz5iBCmE1akgzfmYmduVr18KK8/nnRO+/zwtD\nRh5YpBmd8+QJOgitXg2T46efooZ3xYrSjB8Tgwf09u1EHh4oPdqjh3kVijBHkU5KQs35tWvhE545\nU1oXyLVrGHv3biJXV+Q3u7iY1/eK0T0s0ozeUCiIfHwgqLVrw3f9wQfS+QpTU4n27UOXotxcVI8a\nN848ImzNRaSFQPCXry8E2sMDiz6pArVyc7ErX7uW6O5dWGgmTzZfCw2je1ikGYMgPJxo82aiXbuQ\nrzp+PNGIEdKYKIVA8ZVt2zB+s2ZYDIwYYbr+Q1MX6bg45M9v2UJUpQp8zaNHo3uUtgiBXbOvL9Hy\n5eh0NX060dtvS2ftYZjSwiLNGBQKBdGxY3j4BgYSDRwIwe7bVxqzpUKBHsBbt6LEad++2F0PHIg0\nL1PBFEU6MxO72i1bUOv6/fcRJOjkJI3JOSYGi7idO4mys7FjHjmSezkz+oVFmjFYkpPh/9u8mejh\nQ9RQHjUKOxspHsppaXjob9uG9oMjR0Kwu3Qxfj+jqYi0Ukl0+jS+A4cPE/XuDWEeNEiaRdXDh0R7\n90KY796FdWXUKFTNM/bvAGMasEgzRsH165pdlEqFXNehQxEQJoUJMi4OnY62bsXDedw4orFjpS0R\nqUuMWaRzcmBFOXQI6XsdOsDSMWoUUZ062o+fkoK+zbt2wc0yZAjGdnFhczZjeLBIM0aFEESRkShi\ncvAgKjwNHgzB7tcPPbC1HT84GGK9dy9KnHbqBJFo1cp4dlfGJtLJyWiDeugQUUAAeosPGYKjaVPt\nxhYC5vFjx+BnrlSJqHp1CPPAgdI10WAYOWCRZoyau3ex2/LxIbrgjvDwAAAGGUlEQVRyBakxQ4cS\n9e9P9Npr2o2dn0908iTG9vVFtbSBA3E4OyNgyVAxBpGOi4MoHzpU9Hc3aJD2AWBZWdiN+/pCnCtU\nwO/N3R3lajmnmTEWWKQZk0G9G7t4ET5GOzs8+F1d4cvUJlJcvYNXP/RDQ4l69sRD393d8NK6DFGk\nk5JQaOb0aaL4eBSfeftt7Jb79tVu0SMESnOqfz+XLhF17aoR5tatjccKwjCFYZFmTJKCAgjpyZPY\nUV28iFaarq7wPfbooZ1pPC0NZllfXwQfRUUR9eqlOd54Q7+iYAginZSEFo2nT+N87x4WNr174+jU\nqfwR+wUFRBERKMt5/jz8zFFRGlF2cUFrSIYxdlikGbMgL4/owgWNaFepgnaFXbpgx9WlC1Jt/lOO\nvnBCaDoqqY/MTAhSr144OzigU5iu0LVIC4HdcXAwRPn0aaL79/HenZ0hyo6O5Q/MysjAQkstysHB\nKCjSoweO7t2JWrbk3TJjerBIM2ZJVhZRWBge9uojNZWoc2cIdpcuEJWGDcv34L9/XyPYKSnwu7Zo\ngUhlBwfNWYriGyUhp0irVMgpDg3VHGFhEOChQ/E+e/fGeyyPKCcnY5ccEYHWp2fPojlLx44Q4x49\nkCJlayv9e2MYQ4NFmmH+4fFjosuXi4r29evwZ7ZpAxO2+mjSpGwClJuLCOOrV5H2Ex6On6tXLyrc\n9vYYW9uWnlKItFKJ3fHt2xDLpCRYIcLDiWrWRBERR0ecnZyI6tUr2/i5uTBRR0SgwpdamJ8+JWrf\nHoe9vWYeUyo2wzClhUWaYV6A2tdZ/EhMRLDYG29g1129OsyvDRqgj3CtWi83natURHfuaAQ7PBz/\nx9eXqG5diHVJR716Lx+7tCKdnw+fekwMhPjWLY0ox8XhfTRvjt1xp05Ih3J0LN0uVqGAReHOnZKP\nxo2xEFILsvpo1IjN1gyjhkWaYcpBdjbRjRsQ7MePsQN8+JDowQMcWVkQ2sLC3aABhMnKCkFN1aoR\nVa2q+fnVVxFIpVBgBxsXV/KRloZxGjRA7XFbW5yrVYOv3cqKaNo0C9qxQ1DFirjWpCSiR4+wuCh8\npKcj0CojA0LcooVGlJs100RcFxTAr5+Tg/mTk9HNrKRz1apEp05h/Lp1URCmpKNBA94dM8zLYJFm\nGBnIzYVoFxbuhw+xA46KQmBZVhbO6uPpU42Ad+0K8zgRdpXqnaWFBXbgKhXE9+lTzKVQwPxesSLm\nyM62IEtLQSoVxkxPxwKgYkWY0itVQiCbpSX+/MorRG3bwuycmwtBLnwmwr91cIDY29pil13SuV49\nCLCdnfZme4Yxd1ikGcZAUAtvZiZ2rCoVoqbVd2jhsxAQ2qpVcVhZFTWBFzd3q1QQ8vx8nAv/rD4L\nARG3tNQIuPrM5TIZRj+wSDOMCWIIedIMw2hPObJCGYZhGIbRBSzSDMMwDGOgsEgzDMMwjIHCIs0w\nDMMwBgqLNMMwDMMYKCzSDMMwDGOgsEgzDMMwjIHCIs0wDMMwBgqLNMMwDMMYKFzsj2F0xIEDB8ja\n2ppiY2PJ09NTltcYhjEtWKQZRgeEhYVR06ZNydHR8dmf1bi6ulJsbCyFhYU9K+VZntfUYzMMYzqw\nuZthdMQXX3xBRESxsbHk6OhIe/bsoZo1axIRUdOmTSkgIID27t1L1tbW5XqNYRjTg3fSDKMDHB0d\nqUmTJmRjY0Pe3t5ERJSWlkY2NjbP/k1ycrJWrxVnwYIFz352dnYmZ2dnCd8RwzC6gEWaYXRAWloa\nNW/enLy9vcnT05OcnJyIiGTrVMUdsBjGNGCRZhiJUO+QC2NjY0MeHh7k7e1NU6dOperVq5O1tTXt\n37+frK2tKSUlhYgg4ra2tkREZX4tNTX12WsMw5gWLNIMIxEvi7CuXr06EWmCvfr27UshISHP/uzm\n5kZCiDK/FhcXR25ubrp4iwzD6BgWaYbRAfPmzaOlS5dS06ZNKSUl5Zmgh4SEUGBgIFlbW1OHDh20\nfo1hGNPCQrDzimEYhmEMEk7BYhiGYRgDhUWaYRiGYQwUFmmGYRiGMVBYpBmGYRjGQGGRZhiGYRgD\nhUWaYRiGYQyU/wdTZyvgq7IG/AAAAABJRU5ErkJggg==\n", "text": "" }, { "output_type": "pyout", "prompt_number": 13, "text": "" } ], "prompt_number": 13 }, { "cell_type": "code", "collapsed": true, "input": "", "language": "python", "metadata": {}, "outputs": [], "prompt_number": 13 } ], "metadata": {} } ] }sympy-sympy-1.9/examples/notebooks/qubits.ipynb000066400000000000000000000051771412543434000221300ustar00rootroot00000000000000{ "metadata": { "name": "qubits" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": false, "input": [ "from sympy import symbols\n", "from sympy.core.trace import Tr\n", "from sympy.matrices.matrices import Matrix\n", "from IPython.core.display import display_pretty\n", "from sympy.printing.latex import *\n", "from sympy.physics.quantum.cartesian import *\n", "from sympy.physics.quantum.qubit import *\n", "from sympy.physics.quantum.density import *\n", "\n", "%load_ext sympyprinting\n", "\n", "#TODO: Add examples of simple qubit usage " ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 4 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples of Tr operations on Qubits" ] }, { "cell_type": "code", "collapsed": false, "input": [ "q1 = Qubit('10110')\n", "q2 = Qubit('01010')\n", "d = Density( [q1, 0.6], [q2, 0.4] )\n", "\n", "# Trace one bit \n", "t = Tr(d,[0])\n", "\n", "display_pretty(t.doit())\n", "\n", "\n", "# Partial trace of 3 qubits\n", "# the 0th bit is the right-most bit\n", "t = Tr(d,[2, 1, 3])\n", "display_pretty(t.doit())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "0.4\u22c5(\u27580101\u27e9, 1) + 0.6\u22c5(\u27581011\u27e9, 1)" ] }, { "output_type": "display_data", "text": [ "0.4\u22c5(\u275800\u27e9, 1) + 0.6\u22c5(\u275810\u27e9, 1)" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Partial Tr of mixed state" ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sympy import *\n", "q = (1/sqrt(2)) * (Qubit('00') + Qubit('11'))\n", "\n", "d = Density ( [q, 1.0] )\n", "t = Tr(d, [0])\n", "display_pretty(t.doit())" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "0.5\u22c5(\u27580\u27e9, 1) + 0.5\u22c5(\u27581\u27e9, 1)" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 } ], "metadata": {} } ] }sympy-sympy-1.9/examples/notebooks/sho1d_example.ipynb000066400000000000000000000630221412543434000233430ustar00rootroot00000000000000{ "metadata": { "name": "sho1d_example" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Example Notebook for sho1d.py" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Import the sho1d.py file as well as the test_sho1d.py file" ] }, { "cell_type": "code", "collapsed": false, "input": [ "%load_ext sympy.interactive.ipythonprinting \n", "from sympy import *\n", "from IPython.display import display_pretty\n", "from sympy.physics.quantum import *\n", "from sympy.physics.quantum.sho1d import *\n", "from sympy.physics.quantum.tests.test_sho1d import *" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "The sympy.interactive.ipythonprinting extension is already loaded. To reload it, use:\n", " %reload_ext sympy.interactive.ipythonprinting\n" ] } ], "prompt_number": 1 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Printing Of Operators" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a raising and lowering operator and make sure they print correctly" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ad = RaisingOp('a')\n", "a = LoweringOp('a')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "code", "collapsed": false, "input": [ "ad" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 3, "text": [ "RaisingOp(a)" ] } ], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "a" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 4, "text": [ "a" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "print latex(ad)\n", "print latex(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "a^{\\dag}\n", "a\n" ] } ], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "display_pretty(ad)\n", "display_pretty(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "RaisingOp(a)" ] }, { "output_type": "display_data", "text": [ "a" ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "print srepr(ad)\n", "print srepr(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "RaisingOp(Symbol('a'))\n", "LoweringOp(Symbol('a'))\n" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "print repr(ad)\n", "print repr(a)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "RaisingOp(a)\n", "a\n" ] } ], "prompt_number": 8 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Printing of States" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create a simple harmonic state and check its printing" ] }, { "cell_type": "code", "collapsed": false, "input": [ "k = SHOKet('k')\n", "b = SHOBra('b')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "k" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 10, "text": [ "|k>" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "b" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 11, "text": [ "" ] } ], "prompt_number": 20 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Taking the InnerProduct of the bra and ket will return the KroneckerDelta function" ] }, { "cell_type": "code", "collapsed": false, "input": [ "InnerProduct(b,k).doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 21, "text": [ "KroneckerDelta(k, b)" ] } ], "prompt_number": 21 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Take a look at how the raising and lowering operators act on states. We use qapply to apply an operator to a state" ] }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(ad*k)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 22, "text": [ "sqrt(k + 1)*|k + 1>" ] } ], "prompt_number": 22 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(a*k)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 23, "text": [ "sqrt(k)*|k - 1>" ] } ], "prompt_number": 23 }, { "cell_type": "markdown", "metadata": {}, "source": [ "But the states may have an explicit energy level. Let's look at the ground and first excited states" ] }, { "cell_type": "code", "collapsed": false, "input": [ "kg = SHOKet(0)\n", "kf = SHOKet(1)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(ad*kg)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 25, "text": [ "|1>" ] } ], "prompt_number": 25 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(ad*kf)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 26, "text": [ "sqrt(2)*|2>" ] } ], "prompt_number": 26 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(a*kg)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 27, "text": [ "0" ] } ], "prompt_number": 27 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(a*kf)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 28, "text": [ "|0>" ] } ], "prompt_number": 28 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that a*kg is 0 and a*kf is the |0> the ground state." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "NumberOp & Hamiltonian" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's look at the Number Operator and Hamiltonian Operator" ] }, { "cell_type": "code", "collapsed": false, "input": [ "k = SHOKet('k')\n", "ad = RaisingOp('a')\n", "a = LoweringOp('a')\n", "N = NumberOp('N')\n", "H = Hamiltonian('H')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The number operator is simply expressed as ad*a" ] }, { "cell_type": "code", "collapsed": false, "input": [ "N().rewrite('a').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 30, "text": [ "RaisingOp(a)*a" ] } ], "prompt_number": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The number operator expressed in terms of the position and momentum operators" ] }, { "cell_type": "code", "collapsed": false, "input": [ "N().rewrite('xp').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 31, "text": [ "-1/2 + (m**2*omega**2*X**2 + Px**2)/(2*hbar*m*omega)" ] } ], "prompt_number": 31 }, { "cell_type": "markdown", "metadata": {}, "source": [ "It can also be expressed in terms of the Hamiltonian operator" ] }, { "cell_type": "code", "collapsed": false, "input": [ "N().rewrite('H').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 32, "text": [ "-1/2 + H/(hbar*omega)" ] } ], "prompt_number": 32 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Hamiltonian operator can be expressed in terms of the raising and lowering operators, position and momentum operators, and the number operator" ] }, { "cell_type": "code", "collapsed": false, "input": [ "H().rewrite('a').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 33, "text": [ "hbar*omega*(1/2 + RaisingOp(a)*a)" ] } ], "prompt_number": 33 }, { "cell_type": "code", "collapsed": false, "input": [ "H().rewrite('xp').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 34, "text": [ "(m**2*omega**2*X**2 + Px**2)/(2*m)" ] } ], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "H().rewrite('N').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 35, "text": [ "hbar*omega*(1/2 + N)" ] } ], "prompt_number": 35 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The raising and lowering operators can also be expressed in terms of the position and momentum operators" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ad().rewrite('xp').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 36, "text": [ "sqrt(2)*(m*omega*X - I*Px)/(2*sqrt(hbar)*sqrt(m*omega))" ] } ], "prompt_number": 36 }, { "cell_type": "code", "collapsed": false, "input": [ "a().rewrite('xp').doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 37, "text": [ "sqrt(2)*(m*omega*X + I*Px)/(2*sqrt(hbar)*sqrt(m*omega))" ] } ], "prompt_number": 37 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Properties" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's take a look at how the NumberOp and Hamiltonian act on states" ] }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(N*k)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 38, "text": [ "k*|k>" ] } ], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Apply the Number operator to a state returns the state times the ket" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ks = SHOKet(2)\n", "qapply(N*ks)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 39, "text": [ "2*|2>" ] } ], "prompt_number": 39 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(H*k)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 40, "text": [ "hbar*k*omega*|k> + hbar*omega*|k>/2" ] } ], "prompt_number": 40 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's see how the operators commute with each other" ] }, { "cell_type": "code", "collapsed": false, "input": [ "Commutator(N,ad).doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 41, "text": [ "RaisingOp(a)" ] } ], "prompt_number": 41 }, { "cell_type": "code", "collapsed": false, "input": [ "Commutator(N,a).doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 42, "text": [ "-a" ] } ], "prompt_number": 42 }, { "cell_type": "code", "collapsed": false, "input": [ "Commutator(N,H).doit()" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 43, "text": [ "0" ] } ], "prompt_number": 43 }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Representation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can express the operators in NumberOp basis. There are different ways to create a matrix in Python, we will use 3 different ways." ] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Sympy" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(ad, basis=N, ndim=4, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 44, "text": [ "[0, 0, 0, 0]\n", "[1, 0, 0, 0]\n", "[0, sqrt(2), 0, 0]\n", "[0, 0, sqrt(3), 0]" ] } ], "prompt_number": 44 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Numpy" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(ad, basis=N, ndim=5, format='numpy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 45, "text": [ "array([[ 0. , 0. , 0. , 0. , 0. ],\n", " [ 1. , 0. , 0. , 0. , 0. ],\n", " [ 0. , 1.41421356, 0. , 0. , 0. ],\n", " [ 0. , 0. , 1.73205081, 0. , 0. ],\n", " [ 0. , 0. , 0. , 2. , 0. ]])" ] } ], "prompt_number": 45 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Scipy.Sparse" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(ad, basis=N, ndim=4, format='scipy.sparse', spmatrix='lil')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 46, "text": [ "<4x4 sparse matrix of type ''\n", "\twith 3 stored elements in Compressed Sparse Row format>" ] } ], "prompt_number": 46 }, { "cell_type": "code", "collapsed": false, "input": [ "print represent(ad, basis=N, ndim=4, format='scipy.sparse', spmatrix='lil')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ " (1, 0)\t1.0\n", " (2, 1)\t1.41421356237\n", " (3, 2)\t1.73205080757\n" ] } ], "prompt_number": 47 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same can be done for the other operators" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(a, basis=N, ndim=4, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 48, "text": [ "[0, 1, 0, 0]\n", "[0, 0, sqrt(2), 0]\n", "[0, 0, 0, sqrt(3)]\n", "[0, 0, 0, 0]" ] } ], "prompt_number": 48 }, { "cell_type": "code", "collapsed": false, "input": [ "represent(N, basis=N, ndim=4, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 49, "text": [ "[0, 0, 0, 0]\n", "[0, 1, 0, 0]\n", "[0, 0, 2, 0]\n", "[0, 0, 0, 3]" ] } ], "prompt_number": 49 }, { "cell_type": "code", "collapsed": false, "input": [ "represent(H, basis=N, ndim=4, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 50, "text": [ "[hbar*omega/2, 0, 0, 0]\n", "[ 0, 3*hbar*omega/2, 0, 0]\n", "[ 0, 0, 5*hbar*omega/2, 0]\n", "[ 0, 0, 0, 7*hbar*omega/2]" ] } ], "prompt_number": 50 }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Ket and Bra Representation" ] }, { "cell_type": "code", "collapsed": false, "input": [ "k0 = SHOKet(0)\n", "k1 = SHOKet(1)\n", "b0 = SHOBra(0)\n", "b1 = SHOBra(1)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 51 }, { "cell_type": "code", "collapsed": false, "input": [ "print represent(k0, basis=N, ndim=5, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1]\n", "[0]\n", "[0]\n", "[0]\n", "[0]\n" ] } ], "prompt_number": 52 }, { "cell_type": "code", "collapsed": false, "input": [ "print represent(k1, basis=N, ndim=5, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[0]\n", "[1]\n", "[0]\n", "[0]\n", "[0]\n" ] } ], "prompt_number": 53 }, { "cell_type": "code", "collapsed": false, "input": [ "print represent(b0, basis=N, ndim=5, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[1, 0, 0, 0, 0]\n" ] } ], "prompt_number": 54 }, { "cell_type": "code", "collapsed": false, "input": [ "print represent(b1, basis=N, ndim=5, format='sympy')" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "[0, 1, 0, 0, 0]\n" ] } ], "prompt_number": 55 }, { "cell_type": "code", "collapsed": false, "input": [], "language": "python", "metadata": {}, "outputs": [] } ], "metadata": {} } ] }sympy-sympy-1.9/examples/notebooks/spin.ipynb000066400000000000000000004400261412543434000215660ustar00rootroot00000000000000{ "metadata": { "name": "spin" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Quantum Angular Momentum Module\n", "\n", "This file will show how to use the various objects and methods in the `sympy.physics.quantum.spin` module, with some examples. Much of the work in this module is based off Varschalovich \"Quantum Theory of Angular Momentum\"." ] }, { "cell_type": "code", "collapsed": false, "input": [ "from sympy.physics.quantum.spin import Jminus, Jx, Jz, J2, J2Op, JzKet, JzKetCoupled, Rotation, WignerD, couple, uncouple\n", "from sympy.physics.quantum import Dagger, hbar, qapply, represent, TensorProduct\n", "from sympy import factor, pi, S, Sum, symbols" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 1 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic spin states and operators\n", "\n", "We can define simple spin states and operators and manipulate them with standard quantum machinery." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a spin ket:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jz = JzKet(1,1); jz" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${\\left|1,1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAACcAAAAXCAYAAACI2VaYAAAABHNCSVQICAgIfAhkiAAAATlJREFU\nSInt1i1LREEYxfGfy4KyoEUwaDSIZl+SwU+gWAwiBtNi2o/gFzBYBEEQzQYFg8mtYhExWMRosClY\nRNawXrhc7q6zs4texZNmzsx55s8DMwy/SMc/DZBWKTMfbrGvgpsuzmmX30E5pEg9x5vBFRpRWF/n\nl7GSt5DtXFqTOMMm3iOgQvMnWAwpWG/hH4jvXEi+htms2a5z36l9bGTNosA94wVjabMocLCLatoo\nEtw9RjWfHRQLDg6xlkyKBgd9yaBocOua3UPv4CYw0GWNcTziNTFC4ZKDKzlrC7jDUWQ+UVXzxrZU\nPTUewTluNV/3Bp5wgdXUvqlP/yFTKzQPQ9hrB5aF61RbXWRrmMuavbwQ/ZG5EqZxmbeQ1lvkAfO4\njswu4TRk42BE8TK2pd6nDhX82fzXn9AHkLc0qQpHOW4AAAAASUVORK5CYII=\n", "prompt_number": 2, "text": [ "\u27581,1\u27e9" ] } ], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Find the vector representation of the state:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(jz)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left[\\begin{smallmatrix}1\\\\0\\\\0\\end{smallmatrix}\\right]$$" ], "output_type": "pyout", "prompt_number": 3, "text": [ "\n", "\u23a11\u23a4\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a30\u23a6" ] } ], "prompt_number": 3 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Create and evaluate an innerproduct of a bra and a ket:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ip = Dagger(jz) * jz; ip" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left\\langle 1,1 \\right. {\\left|1,1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEgAAAAXCAYAAACoNQllAAAABHNCSVQICAgIfAhkiAAAActJREFU\nWIXt2D1rFFEUxvGfMRCJqIUgmJQRRDvxJZWg3yCxSaHBQi0sLPwISa2CNgElEJLKQjHprNxWElDE\nwsJgaWGXQJoQYnFdmYyzs3Pnxt0N2X81c84+9zmc3bv3zNDnQPGm2wXkGSjJPW8RH8aXmn7ttKcT\ntCneLzAYs9gNPCiIX8UqdmMWi9A2ErQp3rcwVZRo1bU7eJS5v4An+IWdyOK6pY3RL2MJr6ssOobZ\nkvyC+t9kO23jP/lW0T/GtXyw6D/oIeYSCjmozONePphv0Ckcx89OVNRjbGATo9lgvkH3hU4eVuaE\nHfSXbIOO4hLWOllRj7GOEWEkwN4GTeBdpyvqQRYx3bzJNqhsaDxsHGleZJvyFpOdr6XnuCv8irC3\nQTv4hMuJBudxLHGNbvmOCSf4VjOQ31avhJOsjGYRwwW5m/gmTKWx2nak+Fb1rjQDPsXZXOwM3uOr\nMI3uCuP7B9zOfO7in/iPGlr+naRTfGO9T+KlCpxT/qhRhZmaukaXfAmPGuP5YNHJ9V2YJlP281CC\nNoW6vgO4go9FiSKWZGaBSK7jc03tdk1dqu8EVmJFrV6YlTGIZzJzRCQnaupSfaNfmPXp02df+A0V\naWV8f9YGUgAAAABJRU5ErkJggg==\n", "prompt_number": 4, "text": [ "\u27e81,1\u27581,1\u27e9" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "ip.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$1$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAAsAAAASCAYAAACNdSR1AAAABHNCSVQICAgIfAhkiAAAAF5JREFU\nKJFjYKAC4GJgYLhEjEJTBgaG0wwMDP/RJViQ2JoMDAw9DAwMrxkYGP6S4owF2ExmIsWEUcVUV8wB\npblwaRRjYGDYycDAcIUBEnv/GSBRv5+BgSGaFBfQGAAA/84M5lOscPUAAAAASUVORK5CYII=\n", "prompt_number": 5, "text": [ "1" ] } ], "prompt_number": 5 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Apply an angular momentum operator to the state:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "Jz * jz" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$J_z {\\left|1,1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAADsAAAAZCAYAAACPQVaOAAAABHNCSVQICAgIfAhkiAAAAgtJREFU\nWIXt10+ITWEYx/HPvaZoQqEm+bOQxEgiGVJkVjaKbCyYLJTybzFZWKtZWGChpJSSIiWFskCZu2DB\nSEh2srTAZsTCMGPxntuce7t/zrxnzkzqfut0ep/n/T3v85y398+hw7Rxb7YTSFNu49+Mp3iJcUzg\nHY5ljL+kha8b7zPGmar+MrpiA5fwHW+mqKs0sW/FiPDxYminP4CD9cZ2M1tlAxbjSVRqk/TiEU7i\nb4H6B9gXER+cFr7ininqKi18N8TPbBb9IPrShqwz248/eB6V1uxwHUfThizFlrALr/GzgKSKYhQ/\nsLxqyFLsRmFXHS4oqSK5iuPVRpZi+5N3pYhsCuYTlgnHVKZid2MML4rLqVBuYoD2xZaF9Tri/1qv\n9ZSoLXY7vuFMyrYJi/Bs5vKado4Is1tT7GFhIxpN2QaEw/v2jKU2yVrMyxljNb7gV73jFM6m2nvx\nO7HHUmnhuyNcCrob+PoT391IfZULWNnIMQdDSYcruC+s12YM4St2YKmwDOqp1LV78BgfkkQnkhjD\nOJTqtz6xf47Uw0Jca5F/ZlYJl+35wi2lr0m/Ss5xzuXQDmJbzvFrKGu9o1dyxj8fqSvjViNjLKXk\nGccKzG3QZyxH/J14G6ndj4c5xq5hC04IO2YPLjbptyAyfhcuSc7HCHL9vKfpxTphvb7CR6yZjsAd\nOnTokOYfv15fmYxfZs8AAAAASUVORK5CYII=\n", "prompt_number": 6, "text": [ "\n", "J \u22c5\u27581,1\u27e9\n", " z " ] } ], "prompt_number": 6 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(Jz * jz)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\hbar {\\left|1,1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAADEAAAAXCAYAAACiaac3AAAABHNCSVQICAgIfAhkiAAAAhpJREFU\nWIXt1ztoFUEUxvFfQiR6xYAKikZQoiKKgoUPBA0It1axsVCxsEqZxlZSWSgWNgFF8FEpWMRCEYRc\nRAPBRkREwUc6C9HCF4pILGZX914369y9cQvJH5adOTtn5js7e2Zm+U9ZiB1YX9DmRkVaouhuqe/H\nPUxiTYHf0hnsNTzuQE+R/zn0xHZ0Fp/QW9CmkWPbjoeYjh2oTf+DOJT3IBvZEkwJb6Mb7xL7FDYX\nDL4RZ/AWPyIFl/Efw1VcK+qsFzuFN3ES65JrRU7bxgx9XFJ+JmL8h4V8bSKbE9+wMinfxIvketOB\nqNnmIo63GlsTexAfheRaLEzfZ1z+1+oi+SDo688a84KYQB9O4xTuYl8FAmMZxVDWkA2iD1vxACeE\n7++psNQ+r0ZfFC+Fz76WGrJB7E7qA7ggTNtybMF4dRqjuIKjaSUbxGByf4RXSbmOLtyqRFp7dKWF\n1iDeC7OQUhf2i4lqdEVzTJgN/A6ihm24ji+ZxnXcFjahgVkYfAPmd9jHWmHZ/6UzDWIX5gn7Q8pq\nrMJ9HMH3iAFSgbWcZ3vxTFi2y/inDAkr1B+M4CsWZGz9wlFgTDgaZGlkystwB0+E3XY68RvH4Uy7\nTYn9dUtfsf6EFfR8fmzt0+jAd6QD32HhaNRE62ZXBUWn4yK6hbydzHtQhpj8yGOPsISX4YDmnO2Y\nRSV8eoR/la6/NZyBtn6K5pijJD8BAqxjIW7wMpQAAAAASUVORK5CYII=\n", "prompt_number": 7, "text": [ "\u210f\u22c5\u27581,1\u27e9" ] } ], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "Jminus * jz" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$J_- {\\left|1,1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEIAAAAWCAYAAAB0S0oJAAAABHNCSVQICAgIfAhkiAAAAehJREFU\nWIXt2E+oTGEYx/HPjFt0i0JZkA0LkUT5tyGzslFkY8HNQin/FjcLa2UpSqGUkoVICmWBYhYsNBKy\nlaUFNlcsXFyLd0bHae7MmfedmSPudzPzPr/ze85znt6e98wwQ6ncKruAPNUu+jo8xDP8xBRe4WDi\nfRd20EbxOiF3J/85jCTkVsEnvEhJkqE+TXwDGkLDY+jm34097YRuO6LFaizAg55LK8ZK3MMR/Big\n/w52RuT/zTGhy9tTkmSod9CuiN8RRfzj2JgPFt0RNXzHk57L+vu4jAP5YJFGVLAVz/Glz0WVwQQ+\nY0k2WKQRa4Qp/3gARZXFRRzKBoo0otb8rPe7mhJ5i8XCUYtijdiGSTwdTE2lcRVjrUW3RlSF+dDw\nb8yHPJXWl2wjNuMjjmdiazEfj4ZT11DZL+wK/NmIfcJQnMjExoQXlGtDKa0YKzAnMcdyvMfXduJR\nnMisd+BbM95v6h2068IL0WgbrdbUbkb6W5zG0unEWTjVvOg8bgvzYRDUc+tFuI83wkNM4YNwZO/N\nXLeqGX8X6Yd5uJT6AP2inug/meAdx6Z8MPYn6WEs66A3cCMydxFmR/qqWI+zeSG2ERcifS0mE7xb\n8DLSuwt3E+7dd+ZG+kZwRub875HkP2Zm+F/4BZltWVGn5m3TAAAAAElFTkSuQmCC\n", "prompt_number": 8, "text": [ "\n", "J \u22c5\u27581,1\u27e9\n", " - " ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(Jminus * jz)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\sqrt{2} \\hbar {\\left|1,0\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAFEAAAAfCAYAAACf3SEqAAAABHNCSVQICAgIfAhkiAAABB5JREFU\naIHt2VuIVlUUwPGfl5oaL6WgomJWTllCZDcLM8Eyqqciih5KIXrQogv60EMXQjLyoTSil0px0i6S\nZahol4f6KpIuCJUVFJUgYZSW4Y3ErB7W+ejMcX9n5sx8MI3OHz7Od9ZaZ+/1rbP3Xmvvj376+T8w\noEnt/NOENprlS59lM07qbSd6i4FNaONavI8/m9DWccsGDO9tJ3qTno7Ey/El9jbBl+OWtRjV2070\nNj0ZiedjJ3Y1yRcYgmk4q8Tm9Sb21+uswmkl+mlYhzexDSswvsT+emwV5dLVJXa1El2rWF6qMln4\nugxLxW8bU7B5GoO70XZD2rC8RH8h3sGp2f1QfIBfcXrJc0uxHy0lNrUG8kvwmeo16yn4CbflZA/g\nK5yYk92IWyq2XcqzOKdEv0kEOs8F4geuSdiPFMnpL/wtArlf/JAitcL9uVl/7fhY9SA+Jl5ufpSN\nxGHcmZMNwstVGh5Wohvfhcb2YwdGF+R7sDth34JLRQAeES+gDWMTtrWSfttVD+J32JiQb8O7BdkC\nsUx1oJhYWvESlpR0uhBPduLYdrGmDCnID+HkhP0hjMu+b8D32efnTvrpKcNEEtuR0O3ERQXZCtxR\nNMwHcbAI0I+YK11Aj8QZIgGUcRkmimDWGScC+2mDZ2Zin0gMI7AaB/BCJ331hInZNVXnHhAxyK/P\nezMfyxIkIlAHcV9CtwizKrn5H0twBNMb6LfiLRHA5ZiC9WIJyFMr6aNdtek8PbNflNCtznTFLD0J\ni/OCVJ34u5jSd+l4sjIUF+O9Ck7WacPdeBxbEvrhmIqPcL9Ye74RmfzbbvTXVY5k11TgT8iugwry\nH8Ssaq0LGhXbz+BsXJOTzRdZuSotIhE9h4ca2MzIfDkTz4spMwbn6d5L6yplG4X6er4voVuFOfWb\nRkH8Ah/inuy+RRTAqSxWxgCsFNN0YYndzOz6uViTYXb2/OaKfVbhFzEKRyR0Q/CHdBDp4vnnzaJm\na8M83FrdR4vxcEE2N2G3Bb/JTRER/N2Onk61kv7aVS9xtordSpEdGs+ClbowneENkebvxU3SRXIZ\nt4uX8GhBPqNw3yrW2ldFQqszW2wZj4hp3gwmO/rweJOoUfMjaxIm4LVEG5NE6XUwoUvyoAjE/Cqe\n4koxil4sfNbglYLtVWL0XJeTTcxk88R2bEJOVyvpd032XGtCNyvTrS3Ix4ppOycnewpf67jtq/NE\nwZ9OGSWK3qpH/3uEw6lPcWQuEqfi+SJ8vFj014ttXZ5a4X403hZbxHofu8RUzC9BUzL5dkczVYzI\nZaK8WicdqOEiQfZ5aj18PlUTdpUFYup3oBn/sfQ1yk6Iyhgo1u5PUoq+xuEePHuFKKO6ww1iX39M\nUHbCVMZgcV7Z3f+3m34o208//fRzLPIv82vR8KM+l6AAAAAASUVORK5CYII=\n", "prompt_number": 9, "text": [ "\n", " ___ \n", "\u2572\u2571 2 \u22c5\u210f\u22c5\u27581,0\u27e9" ] } ], "prompt_number": 9 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also do this for symbolic angular momentum states:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "j, m = symbols('j m')\n", "jz = JzKet(j, m); jz" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${\\left|j,m\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAC0AAAAXCAYAAACf+8ZRAAAABHNCSVQICAgIfAhkiAAAAlNJREFU\nWIXt11uITVEYB/DfDI1LzNQIIdF4QEK5ltxGklKUS7xNnjyQSJpX5IkhScqTUnhAyIOHoQ6h5IlS\nHigluT5RyG08rDU5rdln763TIPnX7uz1X9/61v9867+/fQ7/AC78aQFl0JiMRxTEH8ODftKS4igG\nZk2kooswBDfqllMOFawrG/i3YADOZE38aqV/J77hHuYVBVb6XcqvoRknUjLT6AlmYDPG4CV2lFiz\nBssxEx1oxQb0YAG6cBU7hYd/FJriPl+q8rzDe4zD81qbVZLxWBwRbDQtbjq9QHBTXEM43lvYhYbI\ndeI1DmFi5AZEcR0Z+SZhfzVR5Ond2IPvcTF8LlizJAptQJtwOoeEL0yoZKvwkD2N3Ld4jc7I90Qo\n3tBaG1aS8ZSq+y6hQkUYI7TGGVHoomT+LO4kXFuMXVUj51Js6R0UVfpRsrBMj36Bj1gWP+9mCKgk\n3Ep8KsjfUGsiTdaLFnzFtpykKS7jesJNFSq6IuG7cTHeTxA8Xo2TquxRtk8vjIkqGXOTMTjhGrE4\nI75d8PTtKq418qfjuFPwdy8mCaf3oZa4LFFwEG/0PaJ2oXLnEn62bD+fSwTDrBjbjLnYmsx3YXw1\nUaZPE3x4088O0ItXeIs5CT8OD/X180icSrj7OI8DQqfZVzXXHK9neeIqGVyz4OftOev25iWtAzsx\nPyVreXq94FVYLdjiSk7yQXVJy0ajcILpafVBt/DG6xHeQi14LL+Si7Cpfo19sBYbywQOxzBcw3Fc\nEn4P1MJAHJbTQ+tAzT8B//EfOfgB1hltMRlg1uwAAAAASUVORK5CYII=\n", "prompt_number": 10, "text": [ "\u2758j,m\u27e9" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "J2 * jz" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$J^2 {\\left|j,m\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEUAAAAbCAYAAAAqCUKuAAAABHNCSVQICAgIfAhkiAAAA11JREFU\nWIXt2E2IHEUUwPHfbEI0Jk4wojEuomQPKpJo/CYaMys5BAyK4tdBWYIHDwYxiMSj0SCiq4iK4sGL\nYDxERRBRiGgrfhAifoHgQUUQcf26RI3iGtfDq3Z7endmmvlIFOcPTXW/elX1uuq919XFkDnUumx3\nAdZhGS7CPXirX0b9F1mK+wrP1+IARg+POf8O1uAvjKXnOmbE5PxvqYnwyUPvDDEpayu0fX5QRvWT\nkQ71a7EHe4V3zOAjnJnu4U48hA8rjHdsBZ3H8EkFvX7wCBZ227iGn/BBSX4T7lc9YWcVdJ7Co5Ut\n642rcF23jVcLzygm2M1iUuBInFKhn6xbAwbEAuwqCzuFT04jlW+kcgNW4GWcgE1Y2Zt9h4WD2Ifz\nu2n8AqaxBKvws/Cc4lWv0E/WzeADpo4ni4IqSaaGS/A+fsWXOLrPhq3BFuFtU7itg/4V2CgS/gSW\n4xqxOOswiVewTST347EojTFd6mu/WORRfFPV4PxLc2/VBm3I5pGdiIdFKOef99Vt+liU9AnXfxu3\nm0322/E9HjSb5xaIF59o0ecYduYPVXLKeCqzCrrdcAfu0rwh/KON/gYxETURylNiAvItwrTwnF34\nKskOpmtFiz6/EItzVFWjX0xGLqnaoA3ZPLLTCveTYpXbsRKLRcjNYH2p/lm8W5KtSrqXtem3gZvp\n7CkjIp/sE/lkEHxWuG/gzQ763+I3XJrKvaX6hrmTvwm/V+i7RvOkXIgfRXzmnIVj8HqHzvrBsjRe\nJ8NzxvGe5lA7XWwRspLulXgVv+BkkWPKTOBpmiflBpGp9xdkN4pYnLPBGQAXC2OzkvxUsTkskntw\nWXdc5JR3CrLlSf5Met4u3qnImPDAA2WjtqYGOZvFKmxt9RZdkLWpewA/aP5lGBe5YHdJ9xzz55Pd\nmicEzja7jzoPt8wz9iROyh+K+5QnsCMpLBbf7Y0O3eFRI401U5B9J0L63JLuKD41N58cJ4VAgY/x\nnPhHm8Ldpfp6ur7u0u6eyVrI6/gTt7ao3zEQa4Jt4ijkH6r++wyCq0W+gMtF2LzUQveIAdkwIryw\n7HGHlD2pzP+6d4qvzudae8N6XD8ge3o6OugX+T/TUryGx8XmcEsL/YXiAKvbA/ZO9HTINGTIkCFV\n+BvGEKDJmNTtoAAAAABJRU5ErkJggg==\n", "prompt_number": 11, "text": [ "\n", " 2 \n", "J \u22c5\u2758j,m\u27e9" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(J2 * jz)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\hbar^{2} j^{2} {\\left|j,m\\right\\rangle } + \\hbar^{2} j {\\left|j,m\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAALEAAAAcCAYAAAAuq171AAAABHNCSVQICAgIfAhkiAAABQVJREFU\neJzt23/oXXMcx/HHfjCG75j8nFgb+dXGCsuv2YQ0y5iffyhpf0hJll9/IivSSBIptS8yJWIUMuoQ\nSlIsRCElbURqftsvf7zPbcfZ/d7vuZ977o/Nfdbpe++5n8/r8zmv9+d+7vvzOefLkCG7OBMS6szH\nGZiGM3EP3qmzU0OSGcamAvvivsL7K/EHZiRozccK3IV1WNBp5/7n1Bmb3Zq52IbZ+fsRbBeGtcPQ\n8PqpKza7PRPEDNpIQ04URs1rU2doeP3UFZvdgn1wGo6pUPZpPJDQRorhLyS0s7vRi9g02GX9XoqP\nxIA6f5yyy3G/9haHj2B9k/NVDM860K+bhzG5B+0U6XVssoQ63WRMzyeW3q/F2/hd61Xtkvzv7ZiC\nmRU7sneuX2Q5NuDWihrt6neDDJf1oJ0i/YhNN+qkkqng+XRswhaRr/6WH5+Wyp0jBt6h+XEJTk/s\n2JJcC/bS2vAssY1uMAlrOtSYq/ps3o/YZIn1ukUlz6eIPHU77sTR+XFYocws/JqXKR4jCZ1q1/As\noY1uskLkp6mMqj5L9jo2DJ7fVPT8Ur1Z0aYYnnW5T+0ygsc7qD+q+iCmd7FpkPWonXZo6nn552yB\nGFzrcYBIppfheVyb2PBcXCdmjY24Gd9gv0S9KvqtWIrzcJK4pum4QgyQM7AKr4lv/YE4GHvmbWwu\n6GwSXs3A9/VcSkt6FZu669TlNxU9/wivC5OewAliQfFLhYtrxuF4SCwgG9tocxK1shr098zLw4d4\nF7fYsYq/Az+KnZKZ+blJwrhmA2U2Vlbsf5lR7c3EvY5NllCnTN1+08Tz4u7ECE7Ge2JluwKf5+Jf\ntuhoK24Tt5WLNzb+SdSqQ/8cYeQEkdJsFAZuzz/fLGaKNfg2P7c1Pw5pove1COzUxP5XZVBi02+/\nGcfzxbn46rxBudA23Nuio604rvB6lfjWpZLVoH+Y2BaaK6717NLnz+L90rlZedmLxtBciOvHabcZ\no6rPxP2ITZZQp0w3/KbkeTEnbjyA87HIWYlcZgJeHaezY/FFqeG69xTb1d+Q/z0Xf+KD0ucLxUAp\nciH+Gke71U2FJ0U+WOZIsdJuNpMtF+lDg0GJzaD4zRiev4+f/XeaXo2fRJ7SCdPEHueNHWhkNeqv\nxVulc8eLGeCC0vl1eDF/fZSdvVgtLZ0YVX0m7kdssoQ6Y1Gn35Q8b+TEU3EKnhNPkzU4T6wct9rx\nM5bCWXlnsg40UvSPFTdRikwUM1u57CKRo71XODc9P/9M/v4O4UWD2WK2KXpWN4MYm375TRPPG4P4\ndOyBlwuFj8IRIjG/xs7bHe2wUMwan3Wg0a7+IvHz93Sp7Dzsr7mpH4rbug1mimC9gVPt3P8b8Fhy\nr6sxiLFpVqcXftPE88YgXoC/Sw1tyTu6WORn3zW/nkosFPf7t49Trk79H0T/TymVnSHMKednB+Gp\n0rlPxD7s/WKhUTRvJD868aUKgxibZnW67Te983wnRoTpN3WokyXq391hu2OxQtwKTmVUe/vE3aCV\nd1lCHbrnN2N4Xn6KrS4uF/kRXCxWkq/0SX9Kje02mChmnPLs0g6bxCq816TEpt9+U4/nlZkjfmZW\nilXsV+r5dq5L0D8bV9fQdplluKoLut2mHe8GyW967Pm+eBOP4iVxD7wOGs9aVNWfjAel/Uf3ePTj\nofg6aCc2g+Q3u67nQ4YMGTJkyJAhQ4Z0nX8BhgWzuUASqbIAAAAASUVORK5CYII=\n", "prompt_number": 12, "text": [ "\n", " 2 2 2 \n", "\u210f \u22c5j \u22c5\u2758j,m\u27e9 + \u210f \u22c5j\u22c5\u2758j,m\u27e9" ] } ], "prompt_number": 12 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Find the matrix representation of a angular momentum operator:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(Jz, j=1)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left[\\begin{smallmatrix}\\hbar & 0 & 0\\\\0 & 0 & 0\\\\0 & 0 & - \\hbar\\end{smallmatrix}\\right]$$" ], "output_type": "pyout", "prompt_number": 13, "text": [ "\n", "\u23a1\u210f 0 0 \u23a4\n", "\u23a2 \u23a5\n", "\u23a20 0 0 \u23a5\n", "\u23a2 \u23a5\n", "\u23a30 0 -\u210f\u23a6" ] } ], "prompt_number": 13 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Utilizing different bases\n", "\n", "Angular momentum states and operators are able to go between different spin bases" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can rewrite states as states in another basis:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jz = JzKet(1, 1)\n", "jz.rewrite(\"Jx\")" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} {\\left|1,-1\\right\\rangle } - \\frac{1}{2} \\sqrt{2} {\\left|1,0\\right\\rangle } + \\frac{1}{2} {\\left|1,1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAOMAAAAkCAYAAAB7Y41AAAAABHNCSVQICAgIfAhkiAAABcdJREFU\neJztnFtoHUUYx39pq2nTxEukFSy22lSrgvdLtV4riD74IOLlQS1IBK20lSr4ICotVgyKLYpQrJYe\nrUpBraDEK+iqIF4oqBERb4VSFK1YSVXUGuvDt4dsJrOzt9md3WR+cEjOzO7Md/7fNzuzM7MLHo/H\n4/F4RulwbYAnFfstlOF97fFY4FVgumsjPOUyxbUBnkQuA94F/nJtiMcz2XkZOMi1EZ7yUXvGHuAF\nYK4DW5pMWbqdC3wODFsud6LT+Di+CViNTBYc5dSSZlGmbs8DsyyXOdGZUHGc9CNerMiOpmHb+ScD\nj1gsb7L5rXFxnGcC5zBDXhcyrHKBqe5HgWkV2mKDO4CHDflnAduA14AhYBMwx3B8GX5bGNqwHlgH\nPA0crhxTV+3LjGNrsZh0RQli0s8EPsHOmlhWkuq+Eri2ZBts9owLgCcN+acBbwKHhN+7gfeAnw02\nBDHpef12MLALuD6SdhfwBXBgJK0K7XW4imOrsZj1RxwPDAIt4EODEWWQtu6pwHMl22KzMT4OHGfI\nH0QabJRTQxu2xpwTKN+L+u1+pPFHr/K9wD5gWSTNhvYnkb13rTqOS4nFvFcUQkNc9Ixp6l6FDO3K\nIktj7DHkzSHZWb8DO4HZSvoe4JeYcwJDeS2y++1r4BVN+hDwtpJWVPsW2S90LuM46XytHpNp0X8T\n0O/Yhi7gWWDAcMztmO8VAXYg92YzlfS/gRm5rUtPD3AMckFQ+QE4XUmrg/Z1QqtHtDFeB2wI/x8A\nlldgVJUMA3sxT3LkIa1u05CG9j2wFP1Cfi9wNLA9oc6zgXlIo2xzBNJAP05ldTHmhX91659/IL+t\nM5JWlvY6mhDH1vQIDHkt6jtMBegD1pZvipFe4E/gNk3eGmBJznIHgBFgcUx+YDi3RTa/LQ6PX6PJ\n2xLmqbOqRbRvYX/NMEior8xhKmj0mEzDVIDvkB6ky6ENvyJD1VsZ+yRFN3AG8E6OMhcgPcADwAdF\nDUzBSPhXF3AHhH+nKul10L5OjNNjsjVGkLWwGxzb8BhwLHBpJO0WZBY1K53IhM9G4O7ipqVityGv\nfR+7V5NXB+3rxBg96rAYeyISSGmft/sUCdwiROtyUf9nwPvACuB1pEFdQvLEjUoHsDks496CNmXh\nJ6RXPFSTNxP4DX1jBLPOTyE7j1TmIrOP/2jy+km+x64z4/TYn/CJEhgKbmmOr4q0dW/G3lApSTeT\nPVcD/yFDzJuRiYesrAXuUdKWxhwbGMppkd1v25HdNyo7iR9q59W+Rbp7xiz+CBLqK/ueERQ92sPU\njoSPLRbi9iHZPuBHZALFBkm6mbR7CVkGWAlcRfxifRw3Io35PiX9vIzlpEHnt0FgEWN/Yx9wJPLE\nhIpt7XUU8UcWbMTxOD1s3zO2DdRd/ZYAXyGzbWVgqrvNMkanvV3zL2LLcmTT8oj58DFcDDwEzAee\niXy2Yt5QEEcev21AhqTR7XArgC+BJzTl1En7JIrGceFYXITsDFgNvAVcEHNcoHyfDbyB7ElsDwV2\nI0OV6NDrhDB9B/ZIWzfI2tdGi3W3SaubjlnAt2S/yu4hfhim9pRtAuW7Db+dgvSQ65G9tNuQnlGl\nqPYt0i9tuIpja7HYzdhdIdcg3aduUVL9EVnRrU1VwSrEUTbJoptrgoLnF/FbUe1bpGuMTYljrR7t\nYep84E5kHAsyOzcDedLcNp3Jh1hnCrKG95HlcqvUzTV5/WZD+2HSvQOoCXEcq0d7aWMIOAfZqgWj\nQ41vNIXty2kEwPnI0kDVXIG8S8Y2WXRzjSu/2dB+ZcrjmhDHmfXYQvyaV54JApCGvw437++s6gFX\nk26uceU3lw8X1zGOM+nRDzxYoLLJitetXjTeH5cz+mjHdCbAC30qwutWLxrpj+hm3guRbUeDyKzU\nRchVZVf1ZjUKr1u9aLw/5iN7CdU1K//yXDNet3rh/eHxeDwej8fj8Xg8Ho/H4ymP/wEzzZd2JaYA\nVQAAAABJRU5ErkJggg==\n", "prompt_number": 14, "text": [ "\n", " ___ \n", "\u27581,-1\u27e9 \u2572\u2571 2 \u22c5\u27581,0\u27e9 \u27581,1\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500 - \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\n", " 2 2 2 " ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vector representation can also be done into different bases:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(jz, basis=Jx)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left[\\begin{smallmatrix}\\frac{1}{2}\\\\- \\frac{1}{2} \\sqrt{2}\\\\\\frac{1}{2}\\end{smallmatrix}\\right]$$" ], "output_type": "pyout", "prompt_number": 15, "text": [ "\n", "\u23a1 1/2 \u23a4\n", "\u23a2 \u23a5\n", "\u23a2 ___\u23a5\n", "\u23a2-\u2572\u2571 2 \u23a5\n", "\u23a2\u2500\u2500\u2500\u2500\u2500\u2500\u23a5\n", "\u23a2 2 \u23a5\n", "\u23a2 \u23a5\n", "\u23a3 1/2 \u23a6" ] } ], "prompt_number": 15 }, { "cell_type": "markdown", "metadata": {}, "source": [ "When applying operators in another spin basis, any conversion necessary to apply the state is done, then the states are given back in the original basis. So in the following example, the state returned by `qapply` are in the $J_z$ basis:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "Jx * jz" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$J_x {\\left|1,1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAD0AAAAZCAYAAACCXybJAAAABHNCSVQICAgIfAhkiAAAAi1JREFU\nWIXt2E+ITWEYx/HPjClMGaEkUmIhksj/RGYhGxrZWDANKRLSZGGtLEUpKaX8KSn/lQXCXbDQSMjG\nQpYImxGNGYzFe+7MmTv33jnz3u6d1P1u7jnP8/7e9/ec95zzvudSp2rcGGsDaRpHyC/FQzzHX/Tj\nNfaOcpxpZXLNeDPK/rLqT6MptuMGfMPLSH2uRHwFuoSLGcNI+m3YXhgcaabzLMJUPIiyNpwFuIcD\n+FNF/R20RfQPDglXc1OkPlcmd0H8TGfRd2JlOpB1plvxG0+jbI0t57EnHchSdAPW4wV+VMFUtenG\nd8zKB7IUvVh4+z6pkqlacBb78ydZim5NfnPVcFMj3mOmsLxlKnoD+vCsep5qwiW0M3LRjcLz3OX/\nfJ4LaWBo0avxFUdSsSWYgse181U1OoTZHlL0TuGF1Z2KtQuL/5WaWRvOfEyosI95+IifhYmDOJo6\n34zeJF4puTK5q8LmorlIrjXJXYvU5zmB2cUS43A8aXAGt4XnuRhrsQunhDtkH25ibon2uYLz6biP\nt4nhfnwRlsUdqXYLk/iHSD204FwJX5lpMbjDaRO+wOAiZpTQ5Coc81gF2k6sSgeybkPT9OJycrwG\nt5LjDnyKtlae8ZG6Riw3ODEDwdHSIxQOG/EoOZ5cRtMXMU6edXgVqd2KuxWMPcAW4ZaZg1/CR3oD\nDpfRTIocqwknk/5jKPonQkxnu7EM7zBRWNJ6cB2fI83VqVOnTjT/AFLpagvFmvsXAAAAAElFTkSu\nQmCC\n", "prompt_number": 16, "text": [ "\n", "J \u22c5\u27581,1\u27e9\n", " x " ] } ], "prompt_number": 16 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(Jx * jz)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\sqrt{2} \\hbar {\\left|1,0\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAFoAAAAkCAYAAAAJgC2zAAAABHNCSVQICAgIfAhkiAAABKpJREFU\naIHt2mmoVVUUwPGfZT17DuUDFRWzfDYJkU1a2ZxRQVBEw4cyCAMtGtAPfWggpSKJZoKoFF/ZINlA\nhjZB3YqkAaGygkZBpCgrwwnFrD6s8/S847nnjvlK7x8O5561h7XfOnuvtfY+jxYtWtTHcfi7CVeL\nCixFv94eRG+x1y7Scy7exeZdpG+PZTEG9fYgepPsjB6IF3BgE3VMwudY18Q+/9dcjVki4BzUxH4X\nYUgT+9ttaKahj8JDTeorTX9MwCEFdV78F/Q2lWYa+inFbmgCXsJrWIF5GFmhzwuwXIzz7IJ6pYKy\nduHOauUwMd4HcL/4+4Zl6jyMvtV01ixDj8XcgvJj8CYOSJ4H4D38UoX++7EBbQV1SmXkx+MTtefk\n+2M1rkjJbsYX2DcluwiXVdNhswz9GA4vKF8iXkaaoxP9C8u06RBB9U/8JYy9QfyxWUqZ5yMSnV34\nUO2GvktMgvRs7cBWXJOS7Y1nq+mwWkMPLCgbWYWyDViFoRn5Wvxapk0bJoox3i5e1FgMz6lbKtDd\npXZDf4NXc+Qr8HZGNkO4xe3Us2FpxzOYU1BnJu6r0M9K4d/6Z+RbsF+ZNlswIvm9GN8l108VdDXK\nQBF4V+WU/YhjM7J5mJoWpA19OR5Nfs/BdTmd9hVG/AFXyt+EdOBgEbCKOAGjhcG7GSGM/3FBu1Ox\nXgSzwViAjXiygr5GGJ3c8/YCG4Ud0vFiXTLGSoG9Ih3YhBtzymbjjDr7nYNtOKmgznK8Low8F+Pw\ninA5aUoFfXSpzXWclNSfnVO2ICnLZh+duLP7od6zjt+F+7gWfVLyAeKU7p06+hwrVtHdWFamziCM\nxwe4SfjCr0RM+boOndWyLbnnvZx9kvveGfn3YoW209ih0iM4FOekZNNFtlErbSJ4Po5bC+qdLMY8\nBk+I5TkMR6rv5VbLmoKy7hizPqfsKUyhMUN/hvdxffLcJjYQeZG5iD6YL9zBzAp1T03un4o4AZOT\nPpbWqLcWfhazeXBOWX/8Id/Q9FzxdR+2XyLy2bGYJgJqrdyJ2zKyK8vUXYbfJMsxYb5IB7NLt1Sg\ns0vt6d1ysSvMskr51TRfxnX0qXCV42WR3tyAi5XfaJTjKvGi7sjIT86p2y78//MiEHczWWzhtwmX\n0gwOs/NHiiUih0/boxOjxIlnlk6Rdm7KKauLW4SxptfY7kwxE5/OXAvxXE79s8QsPC8lG53Ipomt\n8ahUWalA98KkXXtO2RlJ2aKMfLhwEVNSsgfxpZ5b8G7uzYxnOxNFFJ+Ft+zwh5UYIjYNtX6mWqu8\nq8rOcCK12qznZmakCFSviC12mlLmeSjeENv1bj1rxLJPu7xxiXylnRkvZvYDIrV8Sb4xB4nAvhMD\n9NzpXSqmfMMJdy9SarB9Xs5cLTPExN1Ot48eI/LSzuT5dTFzJjWg7P9O0clgEXuJWPJRVkgcjJxo\nR8rUvRy+rVPZf4GtDbQ9RaSQ9XChOIepigUqHwr91yk6XSyirzjvLsq2iqj64H8q7mlAUYsqON+O\n471+mvuRdo8mvZs6TXzfWyKykNPFrF6964e1+zJG7NWz+ewe/U8vLVq0aNGiRYsm8g9t9gZJzKYP\nXwAAAABJRU5ErkJggg==\n", "prompt_number": 17, "text": [ "\n", " ___ \n", "\u2572\u2571 2 \u22c5\u210f\u22c5\u27581,0\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 17 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rewriting states and applying operators between bases can also be done symbolically. In this case, the result is given in terms of Wigner-D matrix elements (see the next section for more information on the `Rotation` operator)." ] }, { "cell_type": "code", "collapsed": false, "input": [ "jz = JzKet(j, m)\n", "jz.rewrite(\"Jx\")" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\sum_{mi=- j}^{j} d^{j}_{mi,m}\\left(\\frac{3}{2} \\pi\\right) {\\left|j,mi\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAALYAAABCCAYAAAD68ywLAAAABHNCSVQICAgIfAhkiAAACjdJREFU\neJztnX2UFlUdxz+7y/Kyygq7WiKVuKsskqxBlFEIu4itlGJ6cH0BJVvIMA4GZOjxnN6OL70g2uZL\nCmimWRYlpZVHrB4tLcKkE2l6ICWPIRb2ImkvENsf3xlnntmZ55lnnzszz+7ezzl7nmfuzHPvnZnf\nvff3cu9dsFgGIDUpltUNHAv8IsUyLZbEORIYnnUlLBaLpd9SlUIZncAwYAawOIXyLJbEOQHoAKqB\n3RnXxWIxxhjnczLw0ywrYhlcVCec/4vOZzvwSMJlWSyvk7Rgu7QBD6dUlsWSCjXAn4ERWVfEMnhI\no8eeDGwH/pVCWRYLkJxg1wLrgJHAecDXEirHYgklqZD6aGAZEvC9wA0JlWOxWCwWi8VisVgslgrm\naaAnwb8vpncrFovHOXhC+CpaQFCMGjQfeyQwFpgEnARcAtwOvOTL869AnfFaWywxWIcniL+l/Mji\nEOA0FHrvAS4qMz+LpU/UAU/hCfctBvNejhqLxZIJk1Co3BXusw3mfSVSVSyWTFiCJ9j/AJoM5Tsc\nWGAorzh0AytSLC+Ki5BaZppW4N0J5Dug2YAn3FuAodlWp09UwmLjy5GdkRRfAqYkmP+AYxSwE0+4\nr8+0Nv2Tk4E1vuMZwPnAIuAuYLaBMuqATcgzZYnJNGAfnnAn2fOYpBMJ0NoM6zAceBw4yJe2B1jo\nfD8LeA0zAnkaUrssJXA5nmC/DLw52+oUpVIWG18KXBZIOw5P0OehTsNUT7uZwrbQdwyVM2CoBh7C\nE+6fk+5uU2GsAZ5H9WkPnKuExcY1wLPAYQWuuRu4wmCZHwFWFzifi5HHDaTrkm0EdgAf96V1k4yh\nHcrh5EcRr06r4AIsBf5DdBBpBfCZ9KqTRwfwYMS5KehFrsVsJLYRLbSOWmiSi5HHeuDLpioUg7HA\nVmSLuJyJWRdzUTqAA0iwDwQqkwXfRKNHFN8HZqVUlyDdwKoi13wY+DVwsMFynyDa/ZczWE6S1KDR\nLFW+gNdr7wYOTbsCPv4EXBVxLuvFxtuQB8TPu9Cod5RzPAE9x3kGy72RaPUmZ7CcpFkOvDOYmORi\n3iuAXznfnwX+mWBZhWgGjiB6+4csFxuPQBPIngqk7weeBHY5x03IePyNwbJ/z8Dwaa8HuoKJSSre\n+1DLbwDmAv9OsCw/s1D0bifyr29DgvKo75pa4GbU2rNcbNyEdP89gfTHgduQbXAAmA6cioynIPXA\nrcDpRAeYeoCZwM98aS8Ax5RY31bgQmR07wY+VuT605H//XjkumxArssepAatBn6E3kMj8AYU3LsQ\nyQ/AROCjKIB2F1Ir/byC1tWORSNz4swH/kLpD68cutAQ/ibn+C3I/xvck7sRCfoy9FCz4r14u2X1\nhSpgI/ApZNfcggI6s4H7gfc536fTe3RuRy7ZMHIhaUegwFs18FYknJMK1G0oXqBuC7JxVuJthLoK\nqYDXAuOctBokpK7/vta5pxrUiKK8MM1oblHizEDzRt6TRmEOx6NWfm4gfQ/wuRTrUQpnAc+U8fsL\ngDm+42/juVfvK/LbKWgkCyMXknYdGgFBI3AP0FIg/5ORTVCFGtCGwPkVTvlvD6T/HfiE870TNViQ\nGznYW/u5jYTn8I9HPXVnkoWEcD9aoFDrS5uIXsCc0F9kz/lI7TDBKOBe53sd8Msi1x+Nnk1tyLlc\nSNoE3/fVqLctxBhkQ7Q65ZwYOP8N4LFAWpNz7fud4yNRQ21CKlkH0bThm8Nv2ng8FPghWtr1LcN5\nF2IUcAqaB7HPl94G/I/Crr4s2Y/2DjfBfDyVawK670K4XqCoXjvI077vbRTfi/FFZJDPcj43B863\n0bsBnYJsMTfvP6L7WISCbJuKlPn6fu8mBXsY0vc2IVdfmhyNWnZQl25H/tq9mJtOa5JXkfEXJM66\n0CCL8aKnYyjuXj0E2R9heRX73duIv8loO3ov//WlHYsCebnAtWcADyAPmttbD0HG5HrUa0e9x4X4\nnACmBLsK+CrSq5caynMonhFRjFecz+d9aSOQJ8B9AZeUUZdW5B4zzW4kKEGqYvz5mYEE4QnnuB4Z\nzoWm4R5C3+bHTEcClwukt4SUV+3ULXhtOxpZ/Z6qBif9687xKtRbdyBvye1IJsLkqxmNEK/5CzbB\nVejGzqb4EBiX5ahHi8N2ZDGPc45rgZvQKLIDPZiXyqjLM8jDYJqdaGJTuerISjRSus9+FxKyQlNd\nD3PKL5U2ZJA/6UtrR6rKnYFrJyM1MRdIb0eeEv/7HYcazIPAO3z5t6B3+wJwMRLwIEuQ+9YoH0I9\n5ZhiF5bAAtSblLJgYTzwA2S9dyM34wfR8LwW9QiVyC7C3WYnoMb9aSS0weikn53IdehSj/TTuQV+\ncw3587/95Ar8bgu9Z/9NRA6D5wLpc4Hf0fs95ui9WLsGeXW+gu7Z7XTd4NoawldUuX58o5yEbug4\nA3lVoZd3L9L7ktjIsgEJy0Y0f7wL+UevR/cyH/gs3gyyahQcWEdI2LaPeQbZQG+V62DyXZSdaJgd\nW/wWY/MA0SH6XER6PTI2l0Wcz2Ii2XLUCRjDbaVxV3ZUoZZ7EBoGW1D0aRGat/AH8o2jqSYr67AI\nqSnb8Vp/HYr+TXOOJ+KFuM9AasydyOdsIs8gXcgw8tOKDKVm57gePRNTLtQhyDUapt9DvmDPw/NX\nL0DqzlHBHzikHS+oxtPJjfBGNOwktRPUNpOV9eFu1uMPvU4j3+d7ARoS3evrkX4XNUmq1DyDNCJV\nzj+9oQr1Qq6R6Eb6JkfkUSpzgO8VOO+61SY55V6JGsEOonvlE9FGSmkSOW21r3NFPol6pHKiZoW4\nMaF896Je+Ce+tNkoquVyHgrjjgb+hgyTjah3qCXfT97XPP28jOyAOXjRwh7y/b6XIR1za5H7i8tC\nChtbZzqfzwE/RurWHchJEGa8DUHPYKWh+sWljcrYWaAiuIN8nfZh9IBAgrcHCbD7kh5DVvpSvCjd\nLCetr3kGOYboFTxdKC5g6p/NNtO/pqVaYvIongenCum+rtU+AvWai/H2I7wZ9dr+zXvuBr5bRp5h\nXENvY+5UvCmZw/HcmeVwDwNjuqolIeIGj+JSixqL20BmIqE+3Pn7AJ4x2lfOpfhUU8sgpgb14qYZ\njXzu45HuHjSqw8LvcWlFtpElBkmFmuOS1bZk52DWp2ypMIYR7dNMg0rYlsxisVjSwXUhNSBjaCbw\neRQpG4ms8PuQ8dKCZtGtRj7dJShgcCveol03r0sp7J7ajxz9QZ9wXDrRaDEDeRssllCSCDUnRaVs\nS2apYNzI4z1IUOvQSmDQGsKteJP3p+JNJXwI9cjtaDOXcrmYwgsBtjh1BIWfN6PRIkvD1VLBuIJt\nMtTciGaylaKK3FRCnd1V3e3AIyX8zjJIMRFqTpMstyWz9CNMhJrTIuttySyWRJhK/no5iyWPJPfu\nM00tWskykmy3JbP0A7LelL0URqMlSbXI2E1i6ZjFYrFYLBaLxWKxWCyWwcL/AdTvRdeK61V4AAAA\nAElFTkSuQmCC\n", "prompt_number": 18, "text": [ "\n", " j \n", " ____ \n", " \u2572 \n", " \u2572 j \u239b3\u22c5\u03c0\u239e \n", " \u2572 d \u239c\u2500\u2500\u2500\u239f\u22c5\u2758j,mi\u27e9\n", " \u2571 mi,m\u239d 2 \u23a0 \n", " \u2571 \n", " \u2571 \n", " \u203e\u203e\u203e\u203e \n", "mi = -j " ] } ], "prompt_number": 18 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Rotation Operator\n", "\n", "Arbitrary rotations of spin states, written in terms of Euler angles, can be modeled using the rotation operator. These methods are utilized to go between spin bases, as seen in the section above." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define an arbitrary rotation operator. The given angles are Euler angles in the `z-y-z` convention." ] }, { "cell_type": "code", "collapsed": false, "input": [ "a, b, g = symbols('alpha beta gamma')\n", "Rotation(a, b, g)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\mathcal{R}\\left(\\alpha,\\beta,\\gamma\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAE0AAAAWCAYAAACFQBGEAAAABHNCSVQICAgIfAhkiAAAA+1JREFU\nWIXt2HmIV1UUwPGPjqVS6hQqLaSY5ZhhtkEYOpSELUq2WhIVRFZUQkWIlRhmhmmLtqlhlrQXERSY\n0kYRLWQQ/WNUtljQItG+ok5/nPdr3jzvez+n34z0x3z/eu+ce88979x7z7n30UOn6dVNdoejFQ93\nk/0iwzATTdgD++NyfNeAzSZci8Voq2rYGydhNTbi16xDG7bhN3yB53FaiY1mPILdGnC4M0zE9eib\nk63AU11guxU3VzUYg5cxH5PwgAjWVByZGZiRyf/OdOcl7KzI2u8KDsbsEh82dtEYd2FCSnEAtuCM\nnOxxsbr6JtqfL4J2T0HeIgK/q1gsdkeeXvhITG5XcCBeTSmm4+KC7B18UmJonAjahQX5vQlZdzEa\nZyXkF+BLDO7CsV7D4fUaNeEXPFaiv1EEtU9BvgkjK+yOxv24EyvxBIbm9J0pTDegX/a8OrP7Hr4V\nhaCKXpiFT/ETluv4LX0yH2vcgptqL8WlXWMc9sTricEuxVE4BVtzuuGiCGwqsTkNL4nVeHVm52Os\nFZMES0v6puiHP7Pn77PnD0T1vKxO32WYI1LJczgbi3L66Xg29/4uxtdzaJbYfqNFMK4TM/kCLirp\nM1F58h2LP8TWyXNINs5ksTrm1XMsYyCuKdEtxzcVfVvxJAbkZEPxIYZk7ysLfSbgq3pOrc2MwBrx\nYVtFEMs4E2+X6NZhs/YVVWNAZnu2CNh+9RzLmIKjS3S1c1UxddSYg/4J+QyR14/DOQXdofi9yqFB\n+EvH88nSzJFnKvpNx5sJ+WBsF9syRRsexcIqpwrMVZ5a1oqzZGdpxn1imxYnt0UuaKmBp2B3kaRr\nzMMPOB1HlAy6BXsl5CNFLtxQ4fBYLKjQFzlITESRfXCCmITO8iP2FcHZVtDtrc7t4kW8kZDPE6ui\neA6biSswqsTwiKxf6njQP3Ow7NTdor1C1hgkJii1/RaKNNBcx0YZm0WeLTJFehchPny72N9FBopy\n3iZK8DDcKma1n1hNX0vnpfXiZJ3nGJG03xeJt7eOueT4bKynC/2mihy4SMcjyjTx0YfthI0y1pfI\n56qo7PPxkPJ742QRuJ+zAVoL+jV2TKLEzD+IVViC20QlbRLB2yACd2yuzxixoj4r2FqQ+XeyOPXf\nLc5py7RXv3o2UozIbKRYJyagW5hk52d1Z5lfeF/SBTZSXIVLEvIh4lTw76ouq0D/lVfENq66FXSW\n/N23WdxUGrFRxol4KyG/UqSjyt9DjTJC5Lmu+Fc3Eefm3k8V1bERGyl643M7+jxK/ObaJYwX16RG\n6IM7dPyQBeKa1IiNFENxe0HWJP7iDNixeQ899PA/5R/opcWRrIlFmgAAAABJRU5ErkJggg==\n", "prompt_number": 19, "text": [ "\u211b (\u03b1,\u03b2,\u03b3)" ] } ], "prompt_number": 19 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Find the Wigner-D matrix elements of the rotation operator as given by $\\langle j, m'|\\mathcal{R}(\\alpha, \\beta, \\gamma)|j,m\\rangle$:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "mp = symbols('mp')\n", "r = Rotation.D(j, m, mp, a, b, g); r" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$D^{j}_{m,mp}\\left(\\alpha,\\beta,\\gamma\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAHEAAAAgCAYAAAAlrJeCAAAABHNCSVQICAgIfAhkiAAABW1JREFU\naIHt2nmIVXUUwPHPOKNlZZqlWFZWltqmWYlJOqWJFEVClu31R5tERRsRFYWttpsk7XtJe2CQ7WG0\nQSsWFYoRLZbtZthCZX+c+5g7b+59y8ybN0XvC8N7757f75zfvb/lLHdo8J+nuQ425mF7vF4HWw26\niWFYt6cH0aDBv5qmbtQ9E+ugFSd0o53/PXmT+AhGYSf8IvzZ34msP/rhLszFXxn9x2MAnsMKDKnd\nkDvFMLGY7quDrS3Fom3G+hiKk/FNF/U242xchbWVdtolaXxphmwMluKxnL6bJp9j8VLFw+weBuB+\n9K6DrUk4T5xABW7GwzXS3yp7PnI5VUziPjnyPRP5USV0nInZ1RjtBm7GrnWwsx3OybH/UQ3tzMPE\nShs/ij+wXok2S5XeaQsxpVKD3cBIvFAnW1ehV9G1JvGM7qihnW1UcbqtVD63ewU/5MiahR/oW6nB\nbmA+jq2DnVE4OOP6Mfgcm9TY3mLh7kqyvTgqryzT7kOsyZHtjlerGlrtWY7hObJRuBXX4xY8iMEp\neTWR+/nacuE7E71vi40wtEzfJuG6PsEq3ISWlLwlGWOay3Fx4Ufx9i/Qmny+XMJ4H2yLL1PXeuN2\nEb0egXtLDr97GSaCmuUZsul4XuzUM3ASluEpbVWsuVXYWhe/Jd+/T74vEdHprDJ9b8C54thfiEMw\nJyWfiSeK+ryJCeUGtUCkDv1LtNlb7NbbUtc2FrvvNPFwepJJsgOKnfGrOOrSFE6faWL3XFihnQ1F\nAJfFTfi6RN9WPCQWfYHB+BiDkt+3ZPSbiC/KDewLvFumzTxx05PLKeshZuCNjOtP4zMd68b9xP2c\nIyZwswrt7C9cRxaFnK4lR36u7JjhcBwvNsqhGfIdpdxY1nE6XKzEUkdpPxydtOnpPDCPZm0FigKb\niJ32pI5FitXJ5xiR562o0M5YvJMj20ksmD9z5HPEqVDMIpEW7SuyhGLa6cuaxII/XJxjmEhom3Fc\niTY9zbfYqOjacBFIvFWi3864pAo72+q4WIgq1VQ8UIWuAj+Jgska2RWxgcpUgO4WR8CgHPkMUYrb\ntxODqycjdLzRrcW9ZaUDfcUDy6uIjNTxbUx/sViyjsvLxC4cUEZHHp8JP53F/ngtr2MTPhWpQzGD\ncK2I4vascCA9SRO+0tG3PSP8eZrxIgh5TwQSvbT3RZPF5D9S1O8A4UPnaJ+STBeTMLoCHXk8U0J2\ngVT0XFhBW4j8ZnMRmq9KlBQKrX2Sv4eFzyjODQeKpHovkVvuIPzmVsL/DBGr8GdckzGozvRfX6QG\nk8TpsYHwI0+JcH0tnk3kD6VsHSryrtvxo3j4S3CKCFDmiwm9J9VnJb7TMYAZL/K1qYm+Ncm4VmM3\nsUvL6chiaxGh5jFR+Ry+ao4XOeIybbXU9fC7tnxmB9k7vLP9jxYT/ToOSrVZkmozReUrvxKK68BX\n10BHFqfjxBzZIBF11/w1Yj8R0aYT/wnah/jHyH+gnenfX/iXtE+aVqSDOFHyqjbVkk7CB6g8l8zT\nkcciEWBlMRsHpi/kVWyqZbV42/Fi6tpUURUpcIQoIhRHjJ3tvwp7iIkuhNzTxDvMNLPEkdfVlTtJ\n+MwCrUoEFxXqyKKXCGg+yJCNEAtyYZV2K+Ye7YvNi0WySjz478SReVZybQrGdaE/XCTqiMQxs1T4\n0WImCP/ZWVpwnfYL4RLh/7qiI4vBIoAsphk3al/dqTmvansZ3CT8V5/kd18RoJygLWxegMe70J8I\nYK7AkaIGOaY2t9KgGrrymqi3yAPr8W+X/2pq5RM7Q7PSL5zLMQ7vy65oNKgThyn/ri2P0SII+gD7\n1WxEDRo0aNCgQYMGDXqWfwBhwxNCydgNhwAAAABJRU5ErkJggg==\n", "prompt_number": 20, "text": [ "\n", " j \n", "D (\u03b1,\u03b2,\u03b3)\n", " m,mp " ] } ], "prompt_number": 20 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Numerical matrix elements can be evaluated using the `.doit()` method:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "r = Rotation.D(1, 1, 0, pi, pi/2, 0); r" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$D^{1}_{1,0}\\left(\\pi,\\frac{1}{2} \\pi,0\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAGoAAAAhCAYAAAAxvj44AAAABHNCSVQICAgIfAhkiAAABTdJREFU\naIHt2lnMHXMYx/FPqWrR1lJLUcvbUoJWrYmtSmyxJJagtHphDxIubI3YoqkIIi6IEGs0pUhExNLE\ndsGFfU8qqK3SIrTUUuvFMydnet7/zDk9Z87bSs43OZn3P8/M/3lm/tvv/8xLjx4Vcy4Gr+4gusgE\n7FdkXKuLjofjMWxTQV1XYhH+qqCuPFXG2Cnv4RTsMZBOz8K1+BfbdVjXYbi1wzpSVBljVayH+aID\nDSidvoSheAPrVxJNmjWpoeBY3N54smjOn4edsCt+wWv4J7ONFC1+H27D31VHmuMiMTUt76KPgWI8\nZuML0TlG4VIsbrjuKVyFPnzWSsW7ZxXekLBNxAI83qSOTnrr2iLQTdu8v1UGYkSNxNeYljs3Ex9g\nSOL683Bzq5VfJB7i0AL7/pl9WoGdzl7CEXi+zXtXhYFoqFlYYuUZbGP8ifMT12+Cb7Uo9h7DCrHA\nFbEAL5bYO3kJt+PyNu9dFQaioRaIKa2R9/FCwT1vycn1shY7EG/i15JrlohpsBtMEWvj/53h2AFf\nJmyLsGfBfa+Jd4DihtoZm+GVJkFsLJRZI6fjzuzvG3Fhk3oaGZbF8FGBfQTm4jcxIlK/f0RnK6LV\nGDv1tW12XJawLc/qXzdh+1huT1Wk+g7KjmUNNQTjhIpp5OHsl5p/W6EPf+D7hG0QHsTbQnmegNex\nEBfjDjFl/45XS3y0EmMVvkZkxxUJW03Nbqi/+vtajMRS5gjZPbLkmoNFb7q7WWVtcLhYTFOcgaNy\n5XlCIZJeBzqhCl/7ivd0bcI2N7NtmbBNwQ+1QtmIeg9LSwI4ITvOaRJoO4yUniqIHl5jQ/EMfwvR\nU7WUr8LXdyW22kb+54RtqdxASa1RY7GV8mlvOKZn15SpvnYZKh18I6erC46ddHfz3a6vxWLUbJSw\nrY+fpJ91mRi965BuqNr69HKJ85lZJWe2GOyq8pf0AtvI2eodZbTY7bdCkSjI/6rytVyscWMStnF4\np+C+YdmxMBF9vwi0aGifKNJKRyZsrWaj9xL7pBlijRvXYD9OWqTkOQg/qq8ZU4UyS6nQ8QXnW6VT\nX9fjGyFOaowV7/mCAp8HKEmdDRKKJiWLN8Ut+ERkJRppNRs9RDTC6Ky8t1BSefYRU0IZT+LRXHly\n5vuYhuumZOfnNamvm75Gi+eZnjt3Gz6UTiHB0fi0VqiJiTG4F1sL3b8Uz6lPAUOy36Nig5vaBN+T\nHa8pcFxjshiRNVX3htgzbY/Ps3MLxehcV8j0FBNxTq78tthUNk7ni4XM36tJXGV06utboZJnib3R\ncLEHPVJathMDY2EHMTel2Yg6W3+h8pVI7+dZhN2qC8t1DeV9cYmYBearr83d8NUOs+W+w62OT9uj\n9B+Rv+v/sexV0fver8hvXpxsgONxRVY+Gc+KDeY3Fftql0nqs1RXP8UXsdTKiyrx4hqzEM+orpcf\naGV11YfLxIJONNIw6bW3U1/tMFis0/M7D6eYZlPfIXg3Vx4sRtT4hus2EetAp6N+sJhC8p1jkJj6\naud2EXFP6oKvdjhKCJiukmqoQ4S6Ix5mkbqEnyJS+ike0H/t6gYPCUW7pjBXevtTCbVs9L+Zo3w2\neg6eyJUPxV1iH3UfdiyocwfdyXzkORM36XwUVMVYvLQ6A5jR5n2zcVKVgeQ4Rj27MtSa8U8uj0j8\ny9hAiYm1lX8pLuNqnKa+Qa6KydgcT2MLMdVU7WNVmSryiUVLQdc5VSR622UjkWqqajvRJxKhjfm9\nEWU3dZkJolP26NGjR48ePXpUz3+qbzDxAdRwIAAAAABJRU5ErkJggg==\n", "prompt_number": 21, "text": [ "\n", " 1 \u239b \u03c0 \u239e\n", "D \u239c\u03c0,\u2500,0\u239f\n", " 1,0\u239d 2 \u23a0" ] } ], "prompt_number": 21 }, { "cell_type": "code", "collapsed": false, "input": [ "r.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\sqrt{2}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAACwAAAAkCAYAAADy19hsAAAABHNCSVQICAgIfAhkiAAAAjFJREFU\nWIXt2DloVFEUxvFfNBDRJEggIgYkagpBMERFQcGtSiF2phEEURBEEMFSQU0KURQURNwaNwTFQohb\nCjGlpakEK0khIgTcUHAr7sSM4+QtM5cZIvOHKd6575zzvfvuOe/eocH/wxr8ivCrGQ8xp9ogsyII\nyUI/nuNrjfJVzQO0xwhUOsNtuIfFMYIX2ICX+BAxJtiLY8LC7o4Y9y46I8b7h5iCe3EuUqxpiSn4\nuuTltRb38QhjuIauvEliCe7B1YTxVXiK+YXrVoziXd78sQRfwvKE8WHhoYrpK+S/kydRVsFtCWNd\nuJ3i/wlvsKDEPoH3GfL/IU3wXNzChYR7zmB1Sp4xfMOSEvtbfE7xBTtx0dQrOVDmnmYcwSA+Kv8x\n6BAKKY15WFhiW1TI/yyL4Dx04AsOlhk7ji0Vxj2JH1hfoX8iV/AKTUW2VqGYKqFHWNdDVeqall7h\n9fUX2Q5jewWxWvACZyPoSmTU1Iy24Im/ZzwLTUJHOZHHqdJN8w78FF7nPqFw8zKEoyW2XRXEyUQz\nxnEeI5id03+38jN7OSlhNXwXWuEg9gsVnpWtOI3HuFmiKdNRaB0OCVvMEWzMmLgTr+U//kyYfgkO\npjm3Cj1wkgGhz+beOdWKlULxLCtctwtPOlA3RSk0CUtisiWtEAT31U1RTm4IG5gZwR6ckv8DUBe2\nCYIJVd9dPynlKW70m4Tz17DQNTYLszxee1npLBX2t6X9MMqfHw0aNJjB/AanNX6i8nBFNgAAAABJ\nRU5ErkJggg==\n", "prompt_number": 22, "text": [ "\n", " ___\n", "\u2572\u2571 2 \n", "\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 22 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Wigner small-d matrix elements give rotations when $\\alpha=\\gamma=0$. These matrix elements can be found in the same manner as above:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "r = Rotation.d(j, m, mp, b); r" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$d^{j}_{m,mp}\\left(\\beta\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEgAAAAgCAYAAACxSj5wAAAABHNCSVQICAgIfAhkiAAABANJREFU\naIHt2VuMXVMYwPHfdAyqelGXuFcopS41qqlJOqWjKUIIRdzaeaCpB5fgoYkHQqtoXULcHkpJkLjE\nQ4mEuqSNqpCIlJB0PEgpqkNQIY1WPXx7Z/bZs8/kzDmnc4ac/8s+6/v2t/ZaK99lrXVoMiCtdern\nUZyA9XXq73/HBOzd6EE0aQAtNdpfjr0wEwtqH85/k4ewCbswKyOfjnMwAj82YFxFTMC8AfRHYjGW\n4hG8ioNELl6kBoe5AdsxMiM7JHm24/1qO64j4/A82sroO3G78PiUp/By8nsmluSNRlT48Rn4BH9l\nZD8kz1lYW2E/u5P7hLf/XaA7Fh3Cc7bndCcnz7UYI+Y6aDbjnjK6VeiqptM6MgnvDqBfpr8ztGAj\nns7IjlZFNBwj8s+cAl0rflIaeo3gcXSX0R2PSwvk8/EtDsjJ1+DUtLFHgWEXFuIbEdefYwfWFbzb\njh6lodcIzhXhVcRcPJj8fkbMZSoOx2nozb2/Dpfgs6LOrsWWxJjI+n8q3SG3YQVGJ4NaWPk8dgsT\n8PMA+sWZ38vFrn8l/sjpUi7G6qKOpogEd2VO3isSYMr+YpVvwi0DDGyo6MRXZXRjcGsZ3ZOKtycz\n8F2RwRv4RWmZnCzyz3mVjLRBzMVHZXTn4/QyumVibvk0c6KIGvRl9nEijlcrLZNnYSc+GMyIh5hW\n/FNG145Py+hOEhvgHTl5STtdoInJh/Kn8VnJB7aJEjgc2Yr9yugmKl68gzEbLxToxovKjL4F+j15\nbsq8OBJnirIHN1c23iFns8iLecaKECuq1DeK/LOsQDce36eNdIF6sAFHJe02PCG25V+L88qWQQ99\naOgRaeDQnLxTVK0lSs9YF4nz2gX4taC/dnycNtLV3YXL8DCOEOG2VHhPt0h0i8TqdgvPul8k8dFi\nYV8XrjtJeOQDBR+vxn6U2Ep04lnsK/Yvb4rd8y68nehfynxrOu4WobRCJN5RIl1MFaFZxIxkbFVx\nnfCuHlyTyPYR55uOpD0ZX9bRfp5YxPViA5e+syHzThdeyX1reSUTynGgqIhVn+pH4zAR9ykdSsvs\nfP0HW4v9WHFbuVWfx8/J9QFviWMRUZXvGGAe5bgLF2YFlZ7mU7bhbLyXkc3GO5n2VXhRcWWpxv43\nnCEWMS3Bc/Tf7V4vQqpFXF18WMmEMhwnFnjVIO368ZzSg+EasV8iJtUrwui2RNaFaTXYw50iJxJh\nsFFfQcnSIfLVYpFvKqUVjwkPr5l1+i7LWkS+2DNpjxTJdoH4l4PwhtdqsCeS8b24WtwETqnHRIYT\n5a4iKqFNbNzq9RfVoBhsDqqGVlGpqmWauHLZWZ/hDD+uEJWrGk4RCf0Lw/vA3KRJkyZNGsG/dQzH\nyXC4f9IAAAAASUVORK5CYII=\n", "prompt_number": 23, "text": [ "\n", " j \n", "d (\u03b2)\n", " m,mp " ] } ], "prompt_number": 23 }, { "cell_type": "code", "collapsed": false, "input": [ "r = Rotation.d(1, 1, 0, pi/2); r" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$d^{1}_{1,0}\\left(\\frac{1}{2} \\pi\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAEMAAAAhCAYAAACC9hYiAAAABHNCSVQICAgIfAhkiAAAA/NJREFU\naIHt2VuMXVMYwPHf6JSOS6e0SmnGaBXRqFTQxq1mKOoWQlBNTJNqeKiIEOEFL1KESjyQphJBwjRK\nCEI04hLRF5EgvBChYpDUQ1ul0ro8fHvP7O6z957Tc/ZJPMw/2cnZa639rW9/a32XtQ8T/K+5Fd0d\nkLsAZ1cNOKDNCQ7DJvS1KSflPoxgbwfm+AI34PQ25RRyCx7Ev+ivQd5SrOvwHAdjszBwR6hD0Sn4\nFId0cI6UK/FkUUczbrIOWxOFBmpSKM/twhV2dUh+ljewCHNaFbAGf6GnoK/dVZuE73BkxZg6dwbc\nhsdafXgYH5f0tavoJXh3nDF1G2M6fpbzjGazyXn4sEZlslyO9zoku4zfhDEWZxubMcZcHKNzxhjA\nlg7JrmKLJmLgIDbiEawX8WKPxki/Ak+LLTycjNtfekRNMaOkv5k5piZ9fybjiq5/xO7OsgavVCm3\nCr9idnLfhz90buXmay+DdOE1PCBiz3pRm1yEN3FZ8vtcjV5wtSjECjlN7IDlufZteLgNhau4WPhu\nq9yMZZn7l0V2IlJoFQMidoySPQM8hJ0i36ecIiJvp+JFL3a08fzzmd/TxPv8LSrNqlQN25P5R0m3\nzjRcKkrVPZn+CxLhZWm1XaaIBaiDFcbc+WShdxU7xC6anDakxjgh6cjHhgF8JhRuuWKrYC8OKukr\nC4bZK8tqvJ/8nqU8KKekBeTooTA1RrpVt+YGLzHmIndk+po9SZ4hzgFD2CCMnmWXyAZFdDVxpZyP\n48TCSWT2iZ1XRq9IDqNGTWPGNyKy9if3k/GUWLVvMVNkGSJaz8a1uLtisgNF6losguTXeAlnZsb8\nIue3LXKXcPHUNUaEIdKsUkRvMn8hJ+ItPCFWcx5Wiq23AUfkxo9XIi/FV5n7LvyO4zNtM5MXKHOV\nZvleZKaUqfgBV1U8s1KNle94xliNj3JtP4ojdJYRnFoiYxHuFN80Ngt3qIu1ct9POvF5LWWG8Mks\nuzV+WPlEfH36Mtd+KK7Bvcn99XhH7NifatBvIZ7JNrT72a+K7fYNcsQLbsu1va14xefgHnE2IgzR\ng3Nq0K0bZ4ndVgvjuckgPs8psBsn5cZNF1ksv0u7hJukBp2fzLmwNXX3YRler0HOKEXGGDSWLbpF\nPEjTb1qzFPGcxliS5wU8vt9aFjMsisy2qTpJvohXM/cXisPTEJ4VGauIecYKpiJW4VGNbtcKc/FB\nDXKaYqjF59biuoL2K4QxiNqhv0X5KRuV/F1QdwCdJA5JrXA/bhKldMoSHCXqn6PF1p7V+GjTLBdH\njjJ3rZUbcWwbzx8uCrxukU12ajyPlJXv47FAGHyCCSaYYIK6+Q/y58unxR4TVgAAAABJRU5ErkJg\ngg==\n", "prompt_number": 24, "text": [ "\n", " 1 \u239b\u03c0\u239e\n", "d \u239c\u2500\u239f\n", " 1,0\u239d2\u23a0" ] } ], "prompt_number": 24 }, { "cell_type": "code", "collapsed": false, "input": [ "r.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$- \\frac{1}{2} \\sqrt{2}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAADsAAAAkCAYAAAA3pUL9AAAABHNCSVQICAgIfAhkiAAAAl5JREFU\naIHt2E+IjVEYx/HPMEXMTJoayZQGs1BiGoqi/FtNkZ3ZKCWKpKQsEWYWIoqSDDb+pchiapBZyCyt\nZFbKSrOQ1JR/URiLM5Prdu9773vvufcy7rfu4j7nPb/397zvOc95z6HO9KSh1gZSMFFrA9XkIWaX\nIzAjkpFK04Nn+FprI9VgEC3lisR8s824j0URNWE9XuJDZN2S2YsTQhHpiKx9D22RNaMQO9kuXIio\nF5XYyd6QPC3W4AEeYRTX0R7x/onETLYT1xLaV+EJ5k3+b8II3kX0kEjMZK9gWUL7kPBAMume9HA3\nkodE0iTbnNDWjjsF+n/CG8zPio/jfZEeyqKYZOfgNi4lXHMOqwvojOIbFmfF3+Jzgb5lsROX/R5C\nB/Nc14ij6MNHuT8UWoWiU4i5WJAVWzjp4WkR/atGK77gUI62k9hcou5p/MC6EvtXjKt45c+dV5NQ\neEqhU5jH/WX6qghdwpDryYgdwfYStGbhOc4nXZT5VFdgQPF73BfYX4KxTEaEubtVMDwoJJ9m79og\nFLzXOF6mn4JMFPHLxw78FIbgPqHQpaUfx7Jiu0rQqTiNGMNFDGNmyv67cSpHfCDfzWrJd2HJ6sMB\noZIWyxacxWPcyog3qvARzlocFrZ5w9iQom+bMN/SHrmMyz9t+lJqFU2TsL5N0SusoVXbfVSTlUKR\nWTr5v0V4ur01c1RBGoRhPLVkLReS7a6ZoypyU/iQn/bswRn/1uF7SWwTkiVU1o7aWclN2kU8HxuF\ns6IhoTpvEt7uWCT9v4Ylwvdt9lpX9qF2nTp16vw3/AJm7nQeoH85UwAAAABJRU5ErkJggg==\n", "prompt_number": 25, "text": [ "\n", " ___\n", "-\u2572\u2571 2 \n", "\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 25 }, { "cell_type": "markdown", "metadata": {}, "source": [ "You can also directly create a Wigner-D matrix element:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "WignerD(j, m, mp, a, b, g)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$D^{j}_{m,mp}\\left(\\alpha,\\beta,\\gamma\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAHEAAAAgCAYAAAAlrJeCAAAABHNCSVQICAgIfAhkiAAABW1JREFU\naIHt2nmIVXUUwPHPOKNlZZqlWFZWltqmWYlJOqWJFEVClu31R5tERRsRFYWttpsk7XtJe2CQ7WG0\nQSsWFYoRLZbtZthCZX+c+5g7b+59y8ybN0XvC8N7757f75zfvb/lLHdo8J+nuQ425mF7vF4HWw26\niWFYt6cH0aDBv5qmbtQ9E+ugFSd0o53/PXmT+AhGYSf8IvzZ34msP/rhLszFXxn9x2MAnsMKDKnd\nkDvFMLGY7quDrS3Fom3G+hiKk/FNF/U242xchbWVdtolaXxphmwMluKxnL6bJp9j8VLFw+weBuB+\n9K6DrUk4T5xABW7GwzXS3yp7PnI5VUziPjnyPRP5USV0nInZ1RjtBm7GrnWwsx3OybH/UQ3tzMPE\nShs/ij+wXok2S5XeaQsxpVKD3cBIvFAnW1ehV9G1JvGM7qihnW1UcbqtVD63ewU/5MiahR/oW6nB\nbmA+jq2DnVE4OOP6Mfgcm9TY3mLh7kqyvTgqryzT7kOsyZHtjlerGlrtWY7hObJRuBXX4xY8iMEp\neTWR+/nacuE7E71vi40wtEzfJuG6PsEq3ISWlLwlGWOay3Fx4Ufx9i/Qmny+XMJ4H2yLL1PXeuN2\nEb0egXtLDr97GSaCmuUZsul4XuzUM3ASluEpbVWsuVXYWhe/Jd+/T74vEdHprDJ9b8C54thfiEMw\nJyWfiSeK+ryJCeUGtUCkDv1LtNlb7NbbUtc2FrvvNPFwepJJsgOKnfGrOOrSFE6faWL3XFihnQ1F\nAJfFTfi6RN9WPCQWfYHB+BiDkt+3ZPSbiC/KDewLvFumzTxx05PLKeshZuCNjOtP4zMd68b9xP2c\nIyZwswrt7C9cRxaFnK4lR36u7JjhcBwvNsqhGfIdpdxY1nE6XKzEUkdpPxydtOnpPDCPZm0FigKb\niJ32pI5FitXJ5xiR562o0M5YvJMj20ksmD9z5HPEqVDMIpEW7SuyhGLa6cuaxII/XJxjmEhom3Fc\niTY9zbfYqOjacBFIvFWi3864pAo72+q4WIgq1VQ8UIWuAj+Jgska2RWxgcpUgO4WR8CgHPkMUYrb\ntxODqycjdLzRrcW9ZaUDfcUDy6uIjNTxbUx/sViyjsvLxC4cUEZHHp8JP53F/ngtr2MTPhWpQzGD\ncK2I4vascCA9SRO+0tG3PSP8eZrxIgh5TwQSvbT3RZPF5D9S1O8A4UPnaJ+STBeTMLoCHXk8U0J2\ngVT0XFhBW4j8ZnMRmq9KlBQKrX2Sv4eFzyjODQeKpHovkVvuIPzmVsL/DBGr8GdckzGozvRfX6QG\nk8TpsYHwI0+JcH0tnk3kD6VsHSryrtvxo3j4S3CKCFDmiwm9J9VnJb7TMYAZL/K1qYm+Ncm4VmM3\nsUvL6chiaxGh5jFR+Ry+ao4XOeIybbXU9fC7tnxmB9k7vLP9jxYT/ToOSrVZkmozReUrvxKK68BX\n10BHFqfjxBzZIBF11/w1Yj8R0aYT/wnah/jHyH+gnenfX/iXtE+aVqSDOFHyqjbVkk7CB6g8l8zT\nkcciEWBlMRsHpi/kVWyqZbV42/Fi6tpUURUpcIQoIhRHjJ3tvwp7iIkuhNzTxDvMNLPEkdfVlTtJ\n+MwCrUoEFxXqyKKXCGg+yJCNEAtyYZV2K+Ye7YvNi0WySjz478SReVZybQrGdaE/XCTqiMQxs1T4\n0WImCP/ZWVpwnfYL4RLh/7qiI4vBIoAsphk3al/dqTmvansZ3CT8V5/kd18RoJygLWxegMe70J8I\nYK7AkaIGOaY2t9KgGrrymqi3yAPr8W+X/2pq5RM7Q7PSL5zLMQ7vy65oNKgThyn/ri2P0SII+gD7\n1WxEDRo0aNCgQYMGDXqWfwBhwxNCydgNhwAAAABJRU5ErkJggg==\n", "prompt_number": 26, "text": [ "\n", " j \n", "D (\u03b1,\u03b2,\u03b3)\n", " m,mp " ] } ], "prompt_number": 26 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Coupled and Uncoupled States and Operators\n", "\n", "States and operators can also written in terms of coupled or uncoupled angular momentum spaces." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Coupled States and Operators" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Define a simple coupled state of two $j=1$ spin states:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzc = JzKetCoupled(1, 0, (1, 1)); jzc" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${\\left|1,0,j_{1}=1,j_{2}=1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAI8AAAAaCAYAAACOyA9jAAAABHNCSVQICAgIfAhkiAAAA9pJREFU\naIHt2l2MHXMYx/FPdav0ZYsLlNCNVhq0TRERF96uCRIsSUmo3ggRL5GIK4oQEm1CiHjJ4WopJWlc\nCGHckV5UtBLESwiieiNkCcVx8Z9hdsyZnTlnZs9ZmW9yMmf+zzzPPL//Pjv/Z2YOLS0tLQ3xKA7P\nMxyS2X+5IMgSfNjHyddiJ7bFibyAY/qIk/B4n3nUSb9zkWUUtFCsJ8JVZYJEPcbPwm50Kya1At/g\nmtTY3diHQyvGSngWj/XpWwf9zkUew9bC7HoW4qUygaLM/il4HR28V3CCXjyAHzCWGjsKB3FjxVjD\nZtC5GDWq6NmKdbMFjApsnVlOkMen2JUzvhdvV4w1SnTM/+JJ01GsZxW2ZwezPU+dLMfJ+DrH9h3O\nbPDcLfXyldCnzmicx/KPrYVV8fanHNs0xrEYv5WItQHXYyW+x611JDgk5quWHZjE88lAk8UzHm9/\nz7FNx9sjsH+WOMdhM24X1ul9QqO5t0Iuz+GMCscT/qhRRZ/ZqEMLw9GzC1PmqHj+jLd5a+mieLuw\nRJw7cQ/+wup4LK8gi9hc8fimqEMLw9FzUOhh1wlF32jPc6DAtjTe/lwizlP4Mf5+Xhz3kwHyGibz\nXcsz2JLsNFk8+4WrzpE5tqXCJJYpno9T3y/AuwNnNjzmu5bPsSbZaXLZmsYenJBjW4MPKsZbgY3C\nbWVVnsbpFX3u0NwfdxAtDE/PanzRyxgVOHYUPwtYi8MyY1vxLRZkEujiphL+aS6K/bIPq5YLr1VO\nLPCtm47qc5EmT8vZuE3oid4UlrW5oqPcc6sHsb6XMSpwnIpPsCTHdmFs25EZXyksT9emxrbjIzNf\nT/TyT/OI0COkC3GLMNldTBT41k0/c5Emq2UZHkrZJ/ELjh8403IU6UlYhFeLgkSZ/aPxhtBdd+PP\nAbyDTanjTo3Hv8yJuVF4DL5NaLh2+u9SVuSfsBuv9LDNRfHUMRcJWS0bzLwDG4/jT9aReA/K6km4\nHNcVBYwGTOjehvzH8Qdu6WGf6ytPGapoWSAsW8mV6DRBU9W+pklelHnCXPfd1uIa/a8Qege4RJjY\nvPdko0oVLV2879++4y7h5yt7Gs6xLBPC0/Bfiw6KBjjBubi6Jv/1wkTeL9yZfKb4qjZqV55BtNyA\nh83s7YbNfQoa5YSoz+Bjwn9Kv4Kz/svwFp7Aa8K7oCJGqXgG0XKxUDyEu7WJZlKsxJjiHwn+Q9Rs\nHo0xSsXTL+cLhXNs/LkM5ww1o8ClZmmUE65sNo/a2YQnheKZws3DTadvThKetnczn/Eipzlim+Jb\n+JaWlpaWlpaW/zV/AzTy7joiuTv9AAAAAElFTkSuQmCC\n", "prompt_number": 27, "text": [ "\u27581,0,j\u2081=1,j\u2082=1\u27e9" ] } ], "prompt_number": 27 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the Hilbert space of coupled states is the direct sum of the coupled spin spaces. This can be seen in the matrix representation of coupled states:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzc.hilbert_space" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\mathcal{C}^{5}\\oplus \\mathcal{C}^{3}\\oplus \\mathcal{C}^{1}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAGYAAAAZCAYAAADDq1t2AAAABHNCSVQICAgIfAhkiAAAAuNJREFU\naIHt2U+oVGUYx/GPpek1I/zbNSIvSa40rbtIEtp4ixQqlMxFlhIiim5EQQKDiYx2IRRERboxKMid\n3oR0EyhKBS5SSUI3Jl4Qysr+GdjieQfPjHPv3OMZ70zN+W7e8z685zm/mec9z3mecyj537AH/+BP\nfI3+9sppyJN4GeuxDwPtlTMi9+BzPFjUUQW9mF3U0W3kMtam41X4XfwBncZ68X9eR19RZ5WiDsaA\n+bg7Hb+AazozMFVuCsz4W3DSg024gqV4B6eKKmsx32WOV4rN9Gt7pLSeuXgLJ/ETfsbzWIO70poB\nfI872iHQ8BrhMWzHR5jcFnXBSBqrjCqVjccbGBT5uR+vp5PfVXuX9SX7wiLKb4FmGrNswLeYMpYC\n5dPYNJVNwKc4g+UZe08afxQpbAb+cCNvXyvwA/IyGo1DWIzz+Aof4BlR/XSCxoPNHNQHZjfuxM46\n+zp8I0rPSSIosATHcDqHaJiIF/GoqO6GRMAHcaLJuc00HsbTuJjsD4mNc7KDNB7KI2QAf2FOnX0G\njmBemj8rcvcOfIxZeS6Cp0QvtCTNK+I2noRX8D6mF9S4BtuwFftFoDpNI7yUfF0Xd9iWRg6P4rN8\n+nOzAm9iXMZWUZtf7xMipzU4v+s0PiKitqpVDhvQK+6weipurkjuFzspS1dprJa5y9LYLHcWYSPe\nHuXaiyKnZ9NBV2msBmZBGi8VdTgCffghx/ov1L7j6iqN1apsZhp78HdRp8MwR1Qr9SwWL/B+qbPf\ni7OZeVdq/ETkxuHews4XFU4R9g5jr2jc9T6OVzPzrtJYTWXH0/iaqL+zzMUB0a8U4ZzaUrEZy/Bl\nZt6VGifjgoj2oXTBfmwW5V8rvrnMMvqK5wG8V2oMHhYPs6v4LTnaJJqqVvEcdhm5R+gVfcDUUuPY\nslTsyifSvKK2q/5QdMntpO0axzVfcluYiNVYJBq1IfG9ZFDx50Sr+C9oLCkpKSkpyc2/Pkneg0NI\nsz0AAAAASUVORK5CYII=\n", "prompt_number": 28, "text": [ "\n", " 5 3 1\n", "C \u2295 C \u2295 C " ] } ], "prompt_number": 28 }, { "cell_type": "code", "collapsed": false, "input": [ "represent(jzc)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left[\\begin{smallmatrix}0\\\\0\\\\1\\\\0\\\\0\\\\0\\\\0\\\\0\\\\0\\end{smallmatrix}\\right]$$" ], "output_type": "pyout", "prompt_number": 29, "text": [ "\n", "\u23a10\u23a4\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a21\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a30\u23a6" ] } ], "prompt_number": 29 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also couple more than two spaces together. See the `JzKetCoupled` documentation for more complex coupling schemes involving more than 2 spaces." ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzc = JzKetCoupled(1, 1, (S(1)/2, S(1)/2, 1)); jzc" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${\\left|1,1,j_{1}=\\frac{1}{2},j_{2}=\\frac{1}{2},j_{3}=1,j_{1,2}=1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAQMAAAAhCAYAAADdws5CAAAABHNCSVQICAgIfAhkiAAABSNJREFU\neJztnUuoHEUUhr/oFWO8uUaRaCJKjEJ8JWhQVNREowSJokGuIZBo0IggiCTqRtwoRA0+N0GRaBhQ\nLxd8LwQ1YhSCG3GjWSgI9tIXKAgufF0Xp5uZO+npruqqmq4uzgcDPdN1qs/fdbrmVFX3DCiKoozg\nC+DUtp1QFMU7dwILRu08puSz5cBkMHfSYDHwFnBW2454ICUtSjVnAtfbGGTAihCeJMI9wGPAHN0/\nTylpUepZBszYGGRoYJiQ0gWUkhalmlngtLIdZcOEOhYBXzs442oPsM9DHTGRkp4YtPiIMYhDiy11\n2g8Ad5ftsO0MLgM+B1Zb2vmyLzghrycVUtLTthZfMQbta7HFRPtBYAMlE4kThgc5H3gW+AX419JB\nH/bD7PRQR0ykpKctLb5jDLrTLjba54BPgI3AR3UVZ1SPH3t5hU1xtY+FlMbZKWmBdGKsCT3qtS9F\n5g7m0WTOQFGUbvMzkkEsG/zQdJgQA2uAuxABPwK7WvJjG3B1vr0XOIxMNNkSg56UtPgiJS1VvIoM\ng/YUH3SlM1iOzIA+iIyPjiBivrGs5wCw1tJmF/DZwPs38td9lvUM4kOPapmvxQe+4syGtrQfAh4B\nngT+G1UoI745gxeAJfn2Lbn9Kgcf2iYlPTFq6dEsRmPUYksPc+0PA5uKN12ZM3gZ+D3fXofMmn7X\nnjvOpKRHtXSXHjIkArrTGXw7sH0t3Vr7LSMlPaqlu/yK9AEnQ3fmDApOAi5GerQm7AcusbR5iH5Q\nmKRfI58KK8FFj2oJd7G6xpkNbWqfQLT+NqpAhtucwSpgYSD7m3Lbi0r2xfj0Xd25KNNzObAbeYDo\nIJKuxkATLeuAO5AHol4Hbgjm3Xx6uMWojzhrqx17mM8ZbKZmtSSjujOYzQ+2qGTfdfm+NwPZP4OM\n44a/sWJ8+s7kXAzrmUSW+Aq2AH8CZ4Rw0IImWkDS0B359u2IlsUhHBzCNUZd46zNdqzSPsw7wClV\nBTKOFroUuXXxSH6gOeRkHULWqgsuyD//wbN9wZfA2xW+x9QZ1GmBo/WsQZZ5zsnfTyGatoRw0IIm\nWkC+WU/Mt6eBvwnXGfiKMXCPs3G3o6n2QVZgMAzKcL+gHg9gPwX8AzxQYTeOzsA2/Rt1Lsr0LMjr\nL76RLkQ02Y4pTQmpZZgZ4FFL/0LioqUuzsbdjk14AriqrlCG+wW1t76Ikf00/XXe7cgtlGdX2IXu\nDJqkf4PlbfW8Bjxn76YR49KyFlnP3o9Z6jouXNrFNs5CtmMTJoCPTQpmuF1Q1wBbPdivRk76HmTG\n83vqM47QnYFt+jd4Lmz17ASexm5G34ZxagG4F/iKOH5Sz1WLTZyFbscm3Abcb1Iwo/kFNQE8T3Ph\ng/aTyKOWLwLvMXBzRAWhOwOb9G/4XNjouZn+47MLCaMptJYrgJ/of8Oel9c/7cF3F1zapcA0zsbR\njk14F+n4asmIx2lbxj2BGCL9W48E0On5azNwpedjlOFby6XAp8Dx+ftNwF/AuR6P0RZlcbYB+XGR\ngrbasY6VwCumhTO61xlsA15CGmkWwxTIkRDp30rgD/ozwsVryuMxygiVym5HbpDZjczOb/Rc/7ip\nirMZZKkO2mtHE55CMkIjMrrXGYybWNO/JqSkpW121BdpleOAD0ft7MqzCTGxHvl12Q+Q9O9Ghn4k\nokOkpKVtjiWu1ZIybgXetzHQf1QaTczpny0paYmBrbR/p2gd+9D2VRRFURRFURRFURRFURSlCf8D\nTSec3ofIo5IAAAAASUVORK5CYII=\n", "prompt_number": 30, "text": [ "\u27581,1,j\u2081=1/2,j\u2082=1/2,j\u2083=1,j\u2081,\u2082=1\u27e9" ] } ], "prompt_number": 30 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The normal operators are assumed to be diagonal in the corresponding coupled basis:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(Jz * jzc)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\hbar {\\left|1,1,j_{1}=\\frac{1}{2},j_{2}=\\frac{1}{2},j_{3}=1,j_{1,2}=1\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAQ0AAAAhCAYAAADDC/7xAAAABHNCSVQICAgIfAhkiAAABelJREFU\neJztnXuIFVUcxz/WRrbubhmhrVLZWthLKaksqmupSC9UYhOhLSmjCCKy+iciSqiUrOwPKWJLbliL\n0MMMispoqz+kiKCHfxRIDfRH9A6iKHtsf/zOcGfHuXfmzDlnZu54PnDZef3OPd85vznzO6+74PF4\nPAWxBzim7Ex4PB7rXAdMaXfyEIOEZwF9BvYHA/3Ai8DxZWfEAnXS4unMccBSFwkHwBwXCdeEG4H7\ngQm6/z7VSYsnnUFgTMdgGnAucHLKdQHegbJQpwetTlo8ndkBzEw6EW+erATeBz7E3Dl6gc9KtAfY\naiGNKlEnPVXQYsPHoBpadEnTvg24IelEvNLYBbwH/I5UHnk5R6UzvyT7kCNUOnWhTnrK1mLLx6B8\nLbpk0b4bWEJCh2hPZPtopMnRi1QmP6njAXBGxsycCjwC/AD8m9HGpn2cdRbSqBJ10lOWFts+Bt1T\nLjraJ4C3geXAm+0uOhxYpC6+DzhJfQbbXB/QuQnTVGnlxdS+KtSpH6BOWqA+PpaHJunaZyB9G5OI\nRhp/IcOoAK8C+2zkzOPxdC3fIxHJIPBteDDep9EAfkM6SKYD25H+jWeLyaMVFgBbkBry8RLzcQ3w\npNreBNyaM50q6KmTFlvUSUsnniHW/OqJXdBAZnoOAJuBjWp7RRG5s8AspMf3DqT9thcR/blmOtuA\nhZo2twPvRvafV59bNNOJYkOP1zJZiw1s+ZkOZWkfB+4GHgL+i58cQEKRe5HKol8d/xT4ICGxgOr1\naWwBjlLbK5T9PIM8lE2d9FRRS5N8PlpFLbo0ya79LuDycCfaPLlQ7Q8Bo0gzZSYyLDNuI5cF8BTw\nq9puIL3EX5aXHWPqpMdr6V6awPXhTrTSaKi/nwBfqe1lyDjt60XkzAJfRLYvprvGzpOokx6vpXv5\nEakrpsPkPo0G8DMSZYQsQ+Zr7Ckqd5Y4EjgTqSHzMAqcpWlzJy3nyRL2tV1FmICJHq/F3UNt6mc6\nlKm9B9H6S/RgL7CfVg95yDfICApIsyVKgFmfxjxgqiP7K5Rt0qS0Kq7WTLsXSXoWAeuRhWS7aUWK\nZZNHSwO4FlkY9xzysiqCJmY+asPPyirHJtn7NFYhnaqTWKoSuCxy7AR17GZgBFkuGyWgc6WxQ9n3\nJpy7RJ17wZH9ZqSdGX8DVnG1ZpZ7EdfThwx9hqwG/gBmu8igBnm0gIS/a9X21YiWftxj6qOmflZm\nOXbSHudlZMb4JDYAfyJz6ENmIzdkFzKsFCfgwBsyA5lyuldlaEKlMY6M9Yecpo5/bdk+5CPgpTbn\noFqVRpoWOFDPAmT4a67aH0A0rXaRQQ3yaAF5U09T28PA37irNGz5GJj7WdHlmFV7lDlYbH4FmD94\nGxzYDwD/ALd1sCui0tANO9vdiyQ9U1T64RvudESTbps3Ky61xBkD7tHMn0tMtKT5WdHlmIcHgQts\nJRZg/uBtSr8kk/0wrXHyEWS+yYkd7FxXGnnCzuj1unq2A4/qZzMTRWlZiMwHGCVbyFwUJuWi62cu\nyzEPPcBbNhMMMHvwLgLWWLCfjxTOA0gP7z7SIxjXlYZu2Bm9F7p61gEPozeCoUORWgBuAj6mGj8l\naapFx89cl2MeriL/koFEAvI/eD3AY+S/QVH7PmQJ7xPAK0QmoXTAdaWhE3bG74WOnitprQuYihtN\nrrWcB3xH6419ikp/2ELeTTApl5CsflZEOeZhJ1JBWiOgOuJ0Kboj1EXYuRhxtGPVZxVwvuXvSMK2\nlrOBd5CfZgCZrrwf+VmGbifJz5YgP4ITUlY5pjEEPG070YDuqzTC1ZoTyJCT1dCrDS7CziFkmv9E\n7DNg8TuScBVCjyATkdYjoxHLLadfNJ38bAwZwoTyyjELG5EI0yoB3VdpFE1Vw8481ElL2axNv6RU\nDgPeaHfS5P+eeDqzGFnw9xoSdl5K+19Bqzp10lI2h1Kt0aEkViLzs6zj/8Nae6ocdupSJy1VYA3l\nz9xNYyu+fD0ej8fj8Xg8Ho/H4/F4PB7Pwcz/kmrHd1bpdrwAAAAASUVORK5CYII=\n", "prompt_number": 31, "text": [ "\u210f\u22c5\u27581,1,j\u2081=1/2,j\u2082=1/2,j\u2083=1,j\u2081,\u2082=1\u27e9" ] } ], "prompt_number": 31 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Uncoupled States and Operators" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uncoupled states are defined as tensor products of states:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzu = TensorProduct(JzKet(1, 1), JzKet(S(1)/2, -S(1)/2)); jzu" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAHQAAAAgCAYAAADDhVzGAAAABHNCSVQICAgIfAhkiAAABCtJREFU\naIHt2lmIHEUYwPHfxtWEJYl4EI2iWRPEI0QIoiGeaFSCBqMRokRUTES8Hgz44pNRFGM8UVEUo8GL\ngBoVDHiBK6KggooK+mCw34IXokJAYV0fvll2pjPd090zmZ115w/D9FTVd1R/U1VfVTd9+vxP+ASH\nTrYTJbkaA3kNZnTJkV7kCMxuUj4Hr+Lo7rpTyPZRWNE9d6YWCYZTZddhE8aa1O1ritiej5fLKH2t\nLZemFonsGzcZAS1qezsOy6pMT7mHZLQbwtel3Cou/ygG29A93XgW67Mqi6yhp+BDLKnoQCv5EVxW\nUfd05D2cKyM5ygvoCdiJmzFawXBR+TexuoL+6coY3scFzSrzprrvcFHtehuWlTRcVH4Un+NUfFZC\n/0ysxcmik2P4G2/g05K+TjWeE0vVO+mKXlm7tuJ+xQN6PtbhGbwogkmk/euwAbfjt8662TP8LAbC\nfOyur+iVfeif+AtHFmh7KbbgLnxsIphqOp4Ss8N2HFzSjyvxZO16M24pKd8OZW1vFX/cXEYyyrdp\nvHFlKSK/CHe3aHO4mG6GRIeOb9LmRrGnGzZxg5qRmLytSScYEAlSw6DslREKu8TpzVBOm5twH/aI\nwG3E0rr62/CHmIqTWrsF+8DXXmBMrKEr6wt7KaDwPK7KqR/G97Xrf0SA1+MM3IEfNJ6k7MR5Hfey\nd9iGa+sLeiUpqifv8Pnf1O9R3IovsENkuPXsVj47r8oSPK3F4XkdX+GGNm3+KgblQfid3gvoNWLf\nmkV6RtkPj4gEYgUu0RjU+fipoO0iOUJesL7B8oK2OmV7EAeqBZPOTbnHYVabOhaJEbUnp80uLK5d\nH4AnxFHYR+Jg+1ixbRnnQpE4FGGgwKeeTvS5qu1xVuGtPMUjGeXbxb+oWcJyTq3ulRy9efLjPCAe\nD+UxT/EsdwEey9GVqJ7lFulzN9ihxdZspO56nsiivjVxEvMLPhB7pnFOrJX/mNJVVB7mivWnCBfj\nSxyT02Yj3hVrSxaJ6gHN6nM3GRZJUS4jbRi4sw3ZjcolLyvE1mS5xuloDq6v1bV6GyGxd0CX1XzZ\nJKbqs1roaKfPacravgent1I60oZDmyvKzcBLFeRmilcyHsZDte8tOK2gfKIxoLM19mGtWM/zTq+q\n9jlNWduDYgZqSdEEIs2ZuKKi7BpcXlG2HRKNAT1JbIsW1X7PFcvE2gz5dvqcpqztNQoeS86p4Myg\nGCFF919pJusBd6IxoANi2hvvx2JxU5fam3b7nKaMbXhdbFf61JHIT4pewINd8aSc7YUiR+iTIpEd\n0A1iPe7UCCxDK9v36t7p15Qi0Tygq0w8lpqV0WZf0cr2/ng7T0GvHc5PNmeLN+p2ikd1K8XxYa/Y\nXi1e2enThPSb8wvFA/Kx1GduF3wpavvxLvnTp0+fPn36TDv+AxMh2obP427zAAAAAElFTkSuQmCC\n", "prompt_number": 32, "text": [ "\u27581,1\u27e9\u2a02 \u27581/2,-1/2\u27e9" ] } ], "prompt_number": 32 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Vector representation of tensor product states gives the vector in the direct product space:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "represent(jzu)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\left[\\begin{smallmatrix}0\\\\1\\\\0\\\\0\\\\0\\\\0\\end{smallmatrix}\\right]$$" ], "output_type": "pyout", "prompt_number": 33, "text": [ "\n", "\u23a10\u23a4\n", "\u23a2 \u23a5\n", "\u23a21\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a20\u23a5\n", "\u23a2 \u23a5\n", "\u23a30\u23a6" ] } ], "prompt_number": 33 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uncoupled operators are also defined as tensor products:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzopu = TensorProduct(Jz, 1); jzopu" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${J_z}\\otimes {1}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAADQAAAAYCAYAAAC1Ft6mAAAABHNCSVQICAgIfAhkiAAAAkRJREFU\nWIXt1k+IjVEYx/HPnZGpMRaGJkppFmIi0YTxp8mfbNCEBeXPCiOahYmyUSzGQlFqGgv/ZrKQlWaL\nQilCEYmVspOGBaKYZsbieSe3y33v7b5TE+a7ed/znud9nt855znPOfxnLMFtPMIwRvAc7eMpCrV4\nkcVBDh/xdEzkZGMpnojJ/Y1JZTpZiHpcHCNRldCEMxjAUDGjcge0JnnezaYJ1GA7msUsj+A7+kVq\nF+M1NiXvfVieRcQNDGJKFifYgF6sEmk8ylQcwAVML8NPnyIpVw45fMDDSh0kbMUzNKbYdIoiVF/C\nV58iA6oqQ8giMWtZ0m0m2sTKHMf8P9gcxBfsx6lKA5UzoLXJ816lQXAIp/FNCO8UR8IoR/EJl/A2\nsZuTIV4q/fgh2/65WtCuRjdW4wS2FPSvw94Uf30qTLkqtIq6/7WEbRrDBe0hHEZP0u4v6H+HhkoC\n5Q+oRWz+I3nfFmMa7lTivEgcYoXOoUMUncIVmoX3WQPtFpv/c963PWI2r1XiPI83WJC8T8Z5XMF9\nnMRc7Myz3yiqXSY6cCyvvVnsnY6sjkX69Io72GXFq9w+UQy6S/i7LvZQbZpRNbrE9aJH5HVrin2X\nuIasFGW5pYSINuWdQ7dEmhfSgJt46dcNY0AcJ7tKxC5JI7ahTlSjZWX+t16U5hV+vym0J30zsgjL\nlTZJZXQPFlaxNGqwQ5xDI4mGQZERDzLqyUROpCnMFkL/WprF6T9P5PbZ8ZWTjSZRperwGK9E2Z1g\nggn+AX4CKbZnF2vuuR4AAAAASUVORK5CYII=\n", "prompt_number": 34, "text": [ "\n", "J \u2a02 1\n", " z " ] } ], "prompt_number": 34 }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(jzopu * jzu)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\hbar {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAH4AAAAgCAYAAADUp8wPAAAABHNCSVQICAgIfAhkiAAABOJJREFU\naIHt22uMXVMUwPHfUFrVVpSUauiYEtqGaIKmHhXpEEQUHxDPaMU7oolIfGorRD0rCFEt9Yx4E/VO\nTIgmCBrEI1Hut8Y7WhokNT6sc9M7Z+6599xz79yZcv/JzZyz91p7rX32a+2zz9ChQ4eqrMXuw+1E\ng5yPrloC27XJkW2ZvTCuSvp4PIN92utOLtt7Y1773PlvUkJ3Ku0iLEF/lbyhJo/tyXii0YJ3xuHY\nv4bMs40Wug1Tkv2Ah6Ph89p+EntkZaan+vl4B+/XKXS3jPSx+LSGXj1q6d+FUU2U/X/jQSxoROEO\n/I7RNWT6qqQdhg9FTyxCPf3TcWbBspuhZNsc8V14U0aQVzniJ2IjrhIj72fRAT6v48B0rMEV2JLH\n44L6L4oZqUM++vEWjq8nOBqzE4XF2C/5Ta4i25dRxmrFR3we/UUi/miE0TgPd2K5mNFuEnXNQ8m2\nOeJhkljrB1G5Zv4lti7wEr5p1rMhYBVuxQc55Y/D2ViJx2ztVOOT9IW4Tsxu/0V+ELPoZGyozEgH\nd3OxSQRYu+JR/IGHh97HXGwU/k3JIXsabsH1eM/AmWQT7seXYkRMbNCPc3Bfcr0MVzao3wyN2l4l\nOnhNPsJrotFXYoZYW39NyfVl6K82tFM9TMMNdWT2xEMiVlmFA6vIXCb2xN22PshqlAzfdN4KykHe\ngEFeeTMBh4jRca1YT78Qlf66LS7mY71YksbWkLkcN2OzaOBFmFWRfw1+E527lMhNHQJfRwL9eB0n\nVCZWNvxRyX0PHhDT4R44CG+3x8fcPCICtiy68VVy/bfoCAtEHReL+KXyzdYa9Lbcy5HDalxYmVAZ\n3M1N/q7Dt8l1r5gqXhlqzwpQ6xDin9T9FlyNj/EcXkjlb5A/ym+Wg7BCnUOUCtbh0iZt/iQG9a6S\nZTvd8L+I0V6mV0S8a5s03GouEPv+LNJB6/ZiO3elOLw41cDGn4zvc9rOE8PUatTPMCenrVbZHoVd\nVMRq5Qc0FofiKbHelenFq2LE9BTxNMUBGNNkGdPECN1cQ2Y9ZibXO+Je8QrzXXHAsb/YzpU5SQRA\neejK8aukFXUuarvMyXi5WsY80ZtOrEibmqRdgnPFUV+ZvgwDTyY61QKvY5O8pzN06+mXuS3lSzUm\nyR/VT8XdNcoqKR7V56lzO3hOxpZ1Kf7EThVpU/Cj2M5NT8n3VVxPElHj56KS/Yne22LPWWZGkv5d\nqqy8+sTOY0X1ug3iFHyCfWvILMIbYu3LoqR4w2fVuZ10i+CuJfQ1obu0Cd1FGgvC5okt2xwDp8Hx\nuDjJq/d1Tcnghp+d+LJELBFz1aaZOqdp1PaNOLJVxvua0F1WUG87PF5Ab7T4FKn8nn65eKN3RE79\nkoENP87AOpwh4o1abxOL1jlNo7ZHiRmtZeQNhNIcjbMK6o6UY9mDxXZxWnI/QSxPZ2ToN1PnNI3a\nPl2LXyePL6AzSoy4vPvXNMP1IUbJwIbvEtNtuR4zxcOfZTDN1jlNI7bhebGN61CAktrB3aO4vS2e\nNGa7R8QwHQpSkt3wC0W80KoR3Qj1bDfyzUGHKpRUb/iTbT3uHJMhM1TUs72DOGXNpPNdfTGOEQdY\na8QR8Amqf6k0XLbni/cvHZog/Z80PeLksj/1m9AGX/LavqdN/nTo0KFDhw4dRhj/AllqCrlzA7Px\nAAAAAElFTkSuQmCC\n", "prompt_number": 35, "text": [ "\u210f\u22c5\u27581,1\u27e9\u2a02 \u27581/2,-1/2\u27e9" ] } ], "prompt_number": 35 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Coupled operators which are diagonalized by uncoupled states (e.g. $J_z$ and uncoupled $J_z$ eigenstates) can also be applied:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "qapply(Jz * jzu)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\hbar {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAIcAAAAgCAYAAAA4/mtcAAAABHNCSVQICAgIfAhkiAAABRlJREFU\neJzt22msXVMUwPFfq7RoK0pKCX1eCdUQEkNqqEhLSsT0ATGGijmiiUh8okLMKggxlFJEzETNiRei\nCWIIYkgM95uYYwwSng/rXH3vuPfcfc69792+9v6Tm3fO2Xvttfc6e6+99t7n0aNHjxFlFTbvdiUq\ncDLGNUscn7ufgkex7UjWaC1kK0xuktYtm6bo3QbzUwo7HZdiEH1tVmxdo6axzbpl01S9M/BgmYJT\nGrIx9sIOBXkeK6N0jFNTbLNuDbgUvQ9hi0YJ+WklhSPwKt5ooXizgrSN8H4F3SnyN2FCG2Wva9yN\n01Izp/S2G/ArJhbkGWjyfE+8lempQiv5o3FsxbKrUjN2Pcc4vKRBYFrWc0zDzzhfjN7vRSf5MEF2\nNlbiXPxdUm8Z+aeEd+uRxiBexsGpmfuapE3E3lmeS7B99pvRIO9AgY7lqnuOFPnFIiZKZSJOwo1Y\nKjzjlaKtKdSMXc8B00XsMYyyc/OfYtkGT+OzkvKjxTJcizcT8h6E43EX7re6003Jni/CxcJLrq18\nI7zxDHxVfzh0WjkBt2XXV+G8JgXNwy8iINwUK/Ab7u1sfdviZ1HHrVvkOwrX4DK8brg3+gW342Mx\nqqZVqEeqTTtNFb3LxEBoi7fxvOgYd2FnMc//mMs3UFDGciM7rcAsXF6QviXuEbHTMuzUIM/ZYs+g\nz2pjN6Jm7O8N1QPT/xxG2YB0KnYTo+wiMbd/JAzzaUeq2Dk+F1PgRk3Sz8HV+F10gsXYfUj6hfhJ\nDIBalm/mCNV1TWAQL2Bh/UHZzrFfJtOPO4Xr3QK74JXO1LGj3CcCzUb04ZPs+i/RWU4TbbxExFND\ndw9XYsGI1HLNYTlOrd+UDUjnZX/fwxfZ9QLhkp5tt2YjRLODpX9y93/jAryDx/FkLv0r6auXTrAL\n7lBwMJbjPZzVps7vxODfFD/WO0er+btewXn4QXiNOgtEJL+qzYqNBKeIfZFG5L3memIpe544jDrS\n8A4yA1+X0J0SUxW9+A8wt4S+TuidgE1k8eP4IZmLfsTcvQceFvNvnQV4Toy8/tQWtGBHTGqzjFli\ntP/eJP1zzMmuN8CtYiv5NXFotYNYytY5VARsqbSy6dAX1In2VtGb5zA8U0XpfNErDxnybGb27Eyc\nKI6A6wwUlPVQJtcoWDwwS3ukonyd63L1yTNd+mplJm4uKKum+molpb2jxeOqLdktwR/YcMizrfGt\nWMrOzuUfyN1PF9Hwh8IYg5nsK2JdXmfn7PmXFeWJVdUdCW06HO9iu4I8i/GimIebUVO9czRr72jT\nJwLShuwtDHGpcJ/zmmVMZKBN+SVtyC6WHjzOF8vVuYa73Ck4I0tr9ZVXTePOUcam7bS3Hb11rsC+\njRImi520OseIubrVDmMRA23IMrw+ZRiPB0rKTBSfzNXPVZaKndN9EuVr/t85ytq0anvzVHmXE4R3\nbMiuYmk3K7ufKtz2MW1Uskzwlmd/HFdRdk05si9j03bam6fKuzxawRb7OOGK6m51Tlbg7s0EEphS\nUW6CGL2p6/s83fjYp+b/nSPVpu22N0+Vd/mEWMImsQLXV63dOkhN64C0WzZtpbdfxFVJLBLzbad6\n8rpATXHn6JZNU/Qmf7dymNXHtpOM/ZPG0aKmua26ZdMUveuLE/aGDN1CPkAcoq0Ux9kLNf7Cq0c6\n3bJpqt4jxB5VIf3ihHUw95vaocqu7TT6j7du2bSM3ltGoT49evTo0aNHjx6F/AvANSXYBnfGVAAA\nAABJRU5ErkJggg==\n", "prompt_number": 36, "text": [ "\n", "\u210f\u22c5\u27581,1\u27e9\u2a02 \u27581/2,-1/2\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 36 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rewriting states works as before:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzu.rewrite(\"Jx\")" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$- \\frac{1}{4} \\sqrt{2} {{\\left|1,-1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }} - \\frac{1}{4} \\sqrt{2} {{\\left|1,-1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,0\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,0\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} - \\frac{1}{4} \\sqrt{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }} - \\frac{1}{4} \\sqrt{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAA8EAAAAkCAYAAACpKTisAAAABHNCSVQICAgIfAhkiAAADd9JREFU\neJztnWusJEUZhp+FhSULu8SVOwJHlovKTRRFEEVYEQWCioJGIgQwCngF0Wg0ClkJaLiJqJEojKC4\nBkSMouB1jAkRjVc08kNixx+iYEAlEEQRf9ScnJk+fa+qrqrp90lOzpnpqa7vdD9TX3d1dTUIIYQQ\nQgghhBBCCCGEEEIIIYQQoXjKwY8QKXAI8l0IIcQwUM4TKSFXRe98G9gqdBBC9IBcF0IIMRSU80RK\nyNc5YbPQATTklcCPgcdDBzIg7gK2Cx1EB04DVoQOwgK53j+hXE/d1XlC7Z2wRe1IN5TzuqE2Kwzy\ntRtRto+pnASfC3w2dBADYxdgm9BBdGA3YEPoICyQ6/0TyvXUXZ0n1N4JW9SOdEM5rxtqs8IgX7sR\nZfvo8iR4DXALsLvDdQK8GPgt8C/H6xXd8LWfXdV9HXBmBHF0Qa7Hh82+rivbh6tlhPwep0bMbV4o\nh+RPc2y3VQwOKOelQ8ztFchXMYvPYyzoKUe+BbgQc7P3guN13wxs73idop6M5fvS536uo03dm4Ad\nI4ijLXI9DBnF+9JmXzct69PVMkJ+j2Mlw70DtsTqkPwpJsN9zozBAeW8OMnQMZptHG2Rr93JcOtr\nLL7N4Fq6g4BPOlzf1xyua97JKN+XIQ9+mtT9CuCDEcTRBteug3xvSkb1vrTZ13Vl+3C1jLrYhuRP\nhj8HbInVoSbbRA4ZbP2JwQHlvLjI0DGabRxt0PmIHRl+fLXyLfZ7gt8LXF6x/IXArcB3gHuALwC7\nVnz+6RXLVmOGOYSiqv6rgZU9xpI63wOOJq3JF1y7DvH6LteXiNlVH/7si/H4SuAK4AaW99AOzQFb\n5JAcitmBMlLLecpb7pCvcrVPSn2L+SR4L+AJ4M8ly58HfAwz1vtVwGHA3sCvaN+j8ALMbG8HdAnU\nAXX1j4HX9RZN+jwFfB/T+5MCfboOYX2X67Ok5ip092db4AeYA4XzgPOBeyfvbTn1uTHDcsAWOSSH\nUnMgtZynvOUW+VqOXHVPb765HH7wOeBZFctvx4g5zcGTGDaVlBnnXj97sp4R8FP6f4B10/o3B27q\nKaZFMtIdagOwA+Ue9BlHE3y4DnH5nqrr4H+ojgtXD6R9725dbOPca1t/LgYeYDbOdcB/gHOm3ps3\nB2zpwyEf/oAcWsT3cGhQzgP3vqWat2Jvr0C+jnOv59lVCDscGkp8C3lJfA3wSMmyXSfL760ofyTw\nQ+AQTFIE0+vyD+DlDWP4A3D85O8RcGjDcq5oWv+TwM8xwy1+1nDdq4BTgOdjJHkK+DdwG3B3t3CT\n4gHMdtsZuD9wLDG4DmF99+k6pO27C1fPx0wSkbkJqRBbf07G7Iv/Tr33EMb9k1l67MQQHbDF1qE+\n/IG4HUrdH+W85dj6pmM0f8jXWWJ2FdL3tRffmpyRrwa+DHy64jOXYzZ0FfdgdsAzc+//FXi0pMy4\nYn0j+r8S3Kb+tZjeqCYcA1yPmc59egz8GuBtwLVU348A6fcygrkH4MMB4wjpOsTre13dbVwHe98z\nwl4JBntXRw3rmabtleB8fW38WTP5fNF34U7gn7n35skBW/pwaNSwjmm6XAnO1xmLQ7HnzL7aEdsY\n5jnn1ZWfJ99s0DHaEqHOR+rK951fIfyVYPDo26mYHtjFS//vKPncykkAGzG9LmsLPrMOc79PHVsD\nO+Xe22USw49Kyowr1jci7pNggMuonxjitZgeqPyXcZrzMDeKr6v4TMZysZruZx90qXsF5v90ee97\nKq5DvL43qbuJ6+DG94ziRtTG97ZlbV0d0TwRNI1tXFNfG3/2n3z+koJlt06Wrcq9n7oDtvTp0Aj3\n/kAaDsWcM/tuR2ximPec16R86r7ZoGO0WUKejzQp32d+Bfe+xuJbJ9YBjwHvLlh2EXBUx/Veirnc\nfXjJ8nFF2RHxnwSvx9x8X8ZOmN6a1ZiZ6YruYTgH83ytBZaGjhWRMR/PgLwAOC5g/aFch3h9b1J3\nnevgzveMOFy3cXWE+/9hXFNfG38On3z+ooJlN06W5Wf4HaIDtnR1aISf/39cU2doh+YxZyrnFTPC\n/4nFEH2zZai+jivKjgjvKsynrzO+hTobfggzBOFcZi+tb4MZU1/V01fGXpiegEuAu2wDjJT7ML1L\nq0uWnwt8HPOFPgfTO3Pw1PILMEPGPo8R8jFgD0+xxsIIOCNg/XK9G3Wuw/z5PiKsqz55cvK7KDFv\nMfm9ee79ITpgywg5NM0Qc+YI5bxQDNE3W0bI1xAMNb+OmPIt5CXha4B9gGOn3jubduPUF1mFme3s\nWvzdXxALNwBvLlm2wNLN+09gBD4TOAL4KPBHZmeFu512k0ykyN8xnj8tYAxyvRtVrsP8+R6Dq754\nsGLZ1pPfRROTDM0BW+TQcoaWM2NwYMg5b2i+2SJfwzHE/Drj2/Ts0AdgdtqKgkJF/BojSVd+A/wE\neCdwB0acY6h+GHURKzCX6+8APmIRTxf63maLlNX3v9zrJ4H3AL/E3NdwW275/fQ7Q3CI7bUS82zJ\nhwPGIde7U1Vf7L63pcjVPF8EDip4f3fMbI9PFCw7C/iFdXR2/A1zBa/oQGdrzCyaZbNzpupALO3d\nNKn6A34citmfrijnhSdV32Jos0LEMGRfU82vXZnxbfok+B7MA57b0mTcetlG/hTwVczQgQ2YXom2\n4+A3YqYG3zj13mmTdfmm6zaz4XTg7SXL8lf2NweuwgzL2AC8hllpd8YcWDTBZj8vEsKxE4BvRRCH\nXG9PlesQr+9dyxa5muf0kvdHNHvEjYvvcRcexUyusVvBsr0wBzJFpOoA2H1nfDmUqj/gx6GY/XHp\ngHJef6TqG8RxjBai3YRh+ppqfnXmm4vh0Csa/JTxdeAvwLuA19P+wdlnYHoqNubeP6LlepqwL7CV\nh/W2YT2mp+WxkuX3AftN/t4S+AxwHaaH60Jgb+BNU58/DjNTWhPa7meX28vGMZcN0FBch/C+17kO\n8fie31ZdPekjWdo43IYif27H9BJP17Eec1JzS8E6UnbAllgd6ssf6MehWPyBONsR5bx2pOybDTpG\nS+98JOX8GotvTvgQRpy2wxmOxozt/lLuZxPwlZIy44r1bcL0LhTdJH7UZNnNLWNsQ1X9i1xGcS/4\nIjvQfCa3PTA9X2VkwELF8ir62F5NWMBc4YiFPl2HeH134Tq48z0jvOsL2Lk6ovv/UMa4YlkXf3bG\nDFmdvgfpKuD3mASbZ2gO2LJAd4dGuPcH4ndo3nLmAsp5ZdjmPB2juWeB4fo6rlhfDK5CHL66dHWB\nHny7nHY9H9tjbq5u26vxMGbDFP3ke2IWGede7wDcCfxuquyDmNngTp363HMm7/+pZYx1NK0fzDPM\nrm2wzhNp9kyv71I9EUHGcmEPnZS9ENPb89KSsj62V9O6p7kY83BvX8TsOsTluw/XwY3vGcWNcxPn\nyrZVW19tXR3RPME0jW2ce+3Cn+diruZdiZlR8laKE/E8OGBLnw6NcO8PpOFQzDmz73akjqHlPB2j\nNUfHaGHPR2I+xoLuvrpqG8G/bxyJGQ/+Mp+VWDC2LH+RiyA6ch7NbzjfgDk4OIzZYQFrgLdOlm1X\ns46MWWG3wTz3bJFTMMMoqh627Wp7dal7JeZL6YvYXYd0fW/jOtj7nrG8cW7r3PS2alvWhasjmp3E\ntIltbBmTjT+pO2BL3w6NcO8PpONQjDkzRDtShXJeNan7ZoOO0doztiyfUn4Fe19t2kbw7xvbYsbS\nj5lf6S6t/4gXNsM8x6wNqzBj368Erpj8/gTVD5qfJmNW2AMxw0TWT16vxfQ0nVKxDlfbq0vdJ2Fu\n3vdBCq5Dmr53cR3sfM9YfgLQ1rnpbdW2rAtXr8Y82L6ONrGNLWPq6s88OGBL3w758AfScii2nBmi\nHSlDOa+aefDNBh2jtWdsWT6l/Ar2vtq0jeDXNwDeh9lIY+KVrukN20W8BHijq0BachLwhp7rzJgV\ndgWzE5Lsh5HuYIpxub3a1g1mkoNtHdWfJwXXIU3fY3Ad2jmX31ZtffXpap42sYXyZx4csCVWh9rG\nNWSHbHNmTA4o51UzD77ZoGO09gzJVbDz1bZtBM858kRg/8nfY+KVbk3HcisxPR9VM4755GpmH2fV\nBxnVw+NupPwZar63V1XdAHtihmf4IBXXIU3fY3Qdyp1rsq2qfPXpahOqYgvlzzw6YEusDtW1xXJo\nCducGcoB5bx65tE3G3SMVs+QXIXuvtq2jeA5R+6CuUS+yJh4pRPNySgX9izMMIgQJ0lN6r4EPw/s\nluvzSUZ142zje11ZX642IeT3ODYy/DlgS6wOyZ9ZMvzlzFAOKOfFS4aO0fLI13jJ8OOrlW8unhN8\nLOZm5A9MfvbBPDfqeAfrFvFxwuT3+zHDTRYiq3sLzJCIuz3UL9eHh43vdWV9ulpHyO9xasTc5oVy\nSP40x3ZbhXRAOS89Ym6vQL6KWXweY0GNby4uiV+fe302cBP2N32L+DgS2BHzeIqdgBdhZt/LIqr7\n1cA3PMUg14eFje9Nyvp0tYqQ3+PUiL3NC+GQ/GmO7bYK7YByXlrE3l6BfBVL+D7Ggh5z5DMwl6Qf\nB77J0hm6SJO7mJ3yfE/gEZY/A21tD7G0qfuaHmKS6/NF3nWw871p2T5czRPyexwzrh2wJVaH5E85\nrnNmTA4o58WHjtHKka/x4dLX2HwTQgghhBBCCCGEEEIIIYQQQgghhBBCCCGEEEIIIYQQQgghhBBC\nCCGEEEIIIYQQwo7/A1+H0IgzacuTAAAAAElFTkSuQmCC\n", "prompt_number": 37, "text": [ "\n", " ___ ___ \n", " \u2572\u2571 2 \u22c5\u27581,-1\u27e9\u2a02 \u27581/2,-1/2\u27e9 \u2572\u2571 2 \u22c5\u27581,-1\u27e9\u2a02 \u27581/2,1/2\u27e9 \u27581,0\u27e9\u2a02 \u27581/2,-1/2\u27e9 \u27581,\n", "- \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 - \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\n", " 4 4 2 \n", "\n", " ___ ___ \n", "0\u27e9\u2a02 \u27581/2,1/2\u27e9 \u2572\u2571 2 \u22c5\u27581,1\u27e9\u2a02 \u27581/2,-1/2\u27e9 \u2572\u2571 2 \u22c5\u27581,1\u27e9\u2a02 \u27581/2,1/2\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 - \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 - \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 4 4 " ] } ], "prompt_number": 37 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Coulping and Uncoupling States" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `couple` method will couple an uncoupled state:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzu = TensorProduct(JzKet(1, 1), JzKet(S(1)/2, -S(1)/2))\n", "couple(jzu)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{3} \\sqrt{6} {\\left|\\frac{1}{2},\\frac{1}{2},j_{1}=1,j_{2}=\\frac{1}{2}\\right\\rangle } + \\frac{1}{3} \\sqrt{3} {\\left|\\frac{3}{2},\\frac{1}{2},j_{1}=1,j_{2}=\\frac{1}{2}\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAYcAAAAkCAYAAABi4faKAAAABHNCSVQICAgIfAhkiAAACSZJREFU\neJztnWusHVUVx3+33Kal1iKkPGuxVBRUKFoxVhvLRY1poKl8wKJRXhYIMT6hMVH8IJGo8QUigWCF\nDqBY5OELDIJfKAmWBKLBB0/N+IgGMI2BWFEe1w9rxjvnnJk9e8/eM7PvOeuX3PR2zqx91jpr/8/M\n3nvNvqAoiqIoiqIoihITxwOzAX4UZVJQzSgTwc+AxX07oSjzCNWM0hsLOnqfjcA9wHOB2rsPWB6o\nLWU8OAOY6tuJgKhmlLYxaqari8NHgKsCtncYsDRge8r8ZyXwrr6dCIhqRmkbo2aGLw4vB24BDg/o\nwHrgIeCZgG1W4eN/G7ErYbDJzbXAh7txZ4D5rJkNwOnAOcB3gXc3aEN1Ey91ubHWzDnA55EFrFUB\nHMu5GTgwYHsAKaM++vjfVuyKPy652Qkc3LI/Rea7Zv4BnJn9/j5gL/KFYovqJl5sc+OkmZCJPg74\nZqC2iqRU++jjv3byeLHJzXuAz7TvygjzVTPHAC/Lfj8VeB63i0OO6iZe6nLjpJmQib6e+uHma4Eb\ngWuAK4GvU99BU+K/OFyBTA30zRL8/YghFpvcTAF30/3CdNeaWQfsQPSyA7gJuaiYSDH7eCNwkZWH\no4SKP4Z+BmE0A3HEU5ebSs1Mt+QQwJHAf4E/G855PXAn8H6kmuIQ4JfAs8iQaD6zL1Jt0idvQb5A\njvVsJ4ZYbJgFfoHcDf28Z1+aYKOZNwGfQ+7080qmq4B7kTWEXzu+51rgncC/gEsdbUMTQz8LpRmI\nI546nDQT6i7gauBow+vTwKPAJwvHVgJPA5+oaTsl/pFDn7wOuANIgN2Mx4NQtrk5CJlHbcoa3G+a\nutIMyBf4LHBa4dim7NjlBrsUs4/nAQ/SrKJpHHQzjpoBu9yUasanlNU09bMie/0RwzlnAEcgycj5\nC7IQ18ac6yTxMHAycBbmHIwjTwEvAoc2tL8AeGU4dwbw1QzAr5Aqpj2FY/kX+l4HX9YBTyIaBNiF\njCI2OrQxTqhmhjTT5OKwBPge8GXDORcgawcmPgA8AfyzgQ+KYuIaYGvfThQIpRmQNYn9kHninLWI\nuL/v4NMLwO+Av2X/X40sSLtOSynjgVEzH0TmLmeRIcZHS86ZRuY7v4CsCywrOecA4LYaR6aAfyPz\ncRuAS4DLgB8hc6p1pIwOlWz8r8LHtsgaZNi/E4knBhKaDZFjiaVJbvJFtiY3Pwn2UyRdaqaKI5AR\nwHk156WMxvUh4ELgU8CtyLyzCyF0E0s/K5LQfFoplnhcc+OjmQEOQIawZWsDFwMn1tgvR5x+GDi/\ncHwGEdAbauxT4pvjPAzpDAsQ/2dptqh1LXL35vIzY2gvwb2jxxqLC9uAkxrYJbTTt3w1M8wm5ILz\nEPBZ6kWdopppUzMQbzy2NNXMCNuRBeViCdRSZFGnjoORD+45ZEW/yF+B22vsU+Lr6JcCr8h+34zE\nd1R/7vyfBPeOHmssLixHHiZzJaG9vuWjmSqmkTu+3Zj3TkpRzdiS0OziEGs8tjTVzAjHIcEXF7C2\nIR9KHQsz29+WvLYb+A+wyGCfEl9HL1aZfA1Z5ImBBPeOHmssrtwK7O9ok9Be3/LRjIkNWbu3GM5J\nUc3YktDs4hBrPC400Uwpu5i761mE1MnaPoD0FFKbPcw9SGJM1SYp8XX0Ig8Q6AocgAS/sryYYnFh\nGqnfruI6yofne4DfV7z25gB++WgG5AtozdCxZUiOX6K6FDVFNWNLgn8pa0zx2DKgmbyeu+6DqOq8\n30KezjwS2d3veou2cnYDryk5vggZOTxt2Q6W71kVg49tGfsBb2SwRBekTHEHUpVieshpO3aL8kUu\npJ2HbapieSvw9uz19cjc964Se99YfHKzCfP05JkVxxPkAcy05n2b+uajmWVIKetCZLriD9nxFwvv\nt49lW779PqRuxkkzUB6PrWagP93UacaJaWSN4HJk3tO2Y4KUsu5lcM1hCilt/UGNbYrfXdBRNP8j\nKnW2JyPJOaZwrM8NyhLMncUUT1ksSxksydyC5HFFcxdb4TZkEdiVhHZz5KOZxUi56eMMxpb/xbj7\nDbYpqhlbEpprBkbjGXfNVHIRMpw9v+7EIRYgW2VsKxzbgowYVtXYphbnVHEikrgmQz4b268iMZRd\nmfvo6Duz911S8lpdPGWxrEHy/ers//mUxpYQzgZiFaN3obYktJ+jppoB+CLwMQZzcgNS5bfWYJei\nmrHFRzMwGs+81Exxm4ANwKuQaZ2Z7ETTnG3Ot4Gzhxu24CXkCvsN5IN+Hvkw11E/pC/Ddtj2JLJV\n8fGBbIeZyWz7fPz+IOQLYwVzZcF/QgoAvoM8kAX18cwwGstvgLcBf8z+vzL79/EAfpfhMhzPORcZ\nmrdN15oBKVs9C9ko7wVkP7I9yHrIY45t+fZ7G/tJ0wyMxtO1ZsBdN0bN+O7t3iUpg3cTTYZtFwew\nHWYZItiPV7we6x40ZfHUxZJzA3ZP9jahSW6mgbs83jPBPkeTqpkm9pOgGbDTTZuaAffclGqm+ODM\nDHOlcLPIotd8YTXwaeaGbXciaxnrDTZ5qayPLcjumHkt82Zk9PNTW8cjIY/HNZatwN8ZnBoMSZPc\nbAZ+4vGez2D/d5tnmEzNNLEfV82AWzxtawbcc+OkGZ+93bsgZfBuYgoZRuVzfPnTiVUr/u9Atgn3\ntT02O/cSZPj2BNV3FBDnXVAej2ssm5jbi2Ux7cTlmhuAHyL+d80kacbVflw1A27xdKEZcM+tlWbW\nIle07ZQvxsRCivmDNQ3bppF1jqoyOxfbpcgc85XIvlBnG3yC+Dp6MR6XWE5AOvkh2c8pyJxq29QN\nx1cj88Ndopox24+zZsA+nr40A+bcOmvGZ2/3Lkip7jBbga/Q7K+B+diaCLWxXwysRipjZod+yjaU\nC4lNbr6E3DH1waRqJoR9GaqZMNTlplYzw3u7H404f2ogB0OTUt7RfYZtXQ35FHdscrMQmVvtCtVM\nGHulPepyY9RMviA9Dnu7n4Bs6HcHMmzbiP0ffPGxVdrFNjfvBX7coV+TrpkQ9kp72OTGWjO+e7t3\nyX0M7kDpM2zrc8inmHHJzRUVx9tkUjUTwl5pD9vc9KEZRVEURVEURVEURVEURVEURVEURVEUZdL5\nH3bROXO1FYCoAAAAAElFTkSuQmCC\n", "prompt_number": 38, "text": [ "\n", " ___ ___ \n", "\u2572\u2571 6 \u22c5\u27581/2,1/2,j\u2081=1,j\u2082=1/2\u27e9 \u2572\u2571 3 \u22c5\u27583/2,1/2,j\u2081=1,j\u2082=1/2\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 3 3 " ] } ], "prompt_number": 38 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similarly, the uncouple method will uncouple a coupled state" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzc = JzKetCoupled(2, 1, (1, S(1)/2, S(1)/2))\n", "uncouple(jzc)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\sqrt{2} {{\\left|1,0\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAmYAAAAkCAYAAAAjI/bEAAAABHNCSVQICAgIfAhkiAAACyFJREFU\neJztnWvMHUUZx38thZK2b42VSwsBjrSKiqB4IwWU0IoiElGUaiRCoEalXgtoYjTa5tUUTaFQ8Ua8\nHMFLjVggsYr3Y0xI1CgqGvkgceMHUTCgURptrPXDs8d3d89eZnZ2z87ZeX7Jm/bs7Mw+z+z/mTNn\ndmYWFEVRFEVRFEVRFEVRFEXphucBhxr4UxRFURRFURz5JnBk10YoiqIoiqL4yuIpXecC4EfAv6Z0\nvb5wL3BUB9e9HFjUwXUhTJ+VNF1pwBWNG6VLQtRAL9uKaXXMtgCfnNK1+sRxwIoOrnsCsLGD60KY\nPitputKAKxo3SpeEqIEg2oo54A7gxAYNOBv4UIPlhUQEDHKOu96nqvxrgC/XLNuViHyfwc1vn31u\nI+5mmYh2NOCKzxqKCKut0JiZJCIsDUBP24rkiNkbgWuBV9PsSNq7gJsbLC90XO+TSf6H4rRj6xjY\nEi5+++xzW3HXR7qsK581VERf2wqNGXP6qoEqetdWHKK4B2rLs2i+U/b1hsvzmYjie+F6n6ryvwR4\nr0P5dYkot8vFb199hmrbVPcLNNlG2eKrhiLCaytM/NK4EfqqgYgethVt9ySvBW4oSX8BsBf4FnA/\n8Fng+Ioyn1SStgz4tY2BMafEduwCbgRuY7InuxtYUqPsWeW7wAbCmtjrs89t6N4kf2i6d8VnDbWF\nzz5r3EwHnzXgK4V11mbHbB1wAPhjQfpzkLlnVwEvA9YDTwHuo14P9/nIys/TLPM9Afg+0jHbClwD\nPBAfOyJx3ggZmgyFQ8D3kF59KMyiz3V1b5p/RFi6d2UWNeTKLPqscdMss6iBrimsszY7Zu8Gdpak\nzyOrNf8Wf/4n8E7gaOB6i+s8HdgHvBU4aG8m70E6YHsSxz6FjKJtThy7G7i4RvmzzOeBK7s2Yso0\n4fPptP9r2VX3pvlD1L0rGjf10LiZbULUvSu5deYSBHPAPwrSjo/THyjJfy7wA+SNAA/Hx+5DOmov\ntrDjd8DL4/8PgTMt8gJcCvwE+E/i2KOI7ZeysM3HQeBnyOPXnxqWvRTYBDyXhTcX/Bu4K76m7zyM\n+L0Gmaxoyiz7XdfnJNcA25D5D23hqnvT/HV0D7OtAVfqaGjW60vjJo1+X5gz6367YFxnVRPWlgFf\nAj5ecs4NSCWXcT9S+U/OHP8z8HhJvlFJ2hC71zbNxefn+fJt4O+ZYyuBTxuWfT7SGz6b9DPkOeDN\nwK2Uz3+AbidzjtkAvN+iXFe/owq72pz8P8bW5yxDw+skqbJtVHE9l9eVVeW30T34rQFX2tBQqG1F\nlqHhdcaY2DWquJ4vcROqBrStqKizy5DRoUPIY7235ZyzJC5gHhktW5lzzipkvlYVy4HVmWPHxdf/\nYUm+UUnaELtAe2Z8/o6ctL1x2tLM8Z1UL1B4FTL6l+10JtmKTP5bVXJOxOSNNblPZdjmXxTbafLY\nuwm/I/LF7OJ3mz7nMcS8MTC1bVRxvTa/YMBM9+CvBlxpS0OhthV5DDGLGxu7RhXX8yFuQtWAthWC\na9z8n1XAfmROWJbtwHk1y70eGdY7q+ScUUnaELtAOys+f3tO2u1xWnZ15lrKN8xdjfwCWIasMn1a\nzjlXI3udDCh/I0JEd739JNcBF1ac05TfEbPjcxFDmvdhVHG9tr9gqnQP/dOAK1UaCrWtKGJIeHET\nqga0rUiTqrO6PbRHkceZW0gPP65A5oyVjXgVsQ7pWe5A3n81DcaTN/OC6/D438Myxx9ERvaWFZS5\nBfgI0nG9Gunxn5FIvw55RPoZRFT7gZMs7Z42Q6ondfbN7yE6kTVJle6hfxpwZUi5hvpYX0M0bpLo\n90U+ffTbhSGJOnMZOrsFeCrw0sSxt2A3F2XMUuT1BLfiNkfBlkdK0pbH/+YtcLgNeENBvgELix4O\nIAK8CjgH+CDwe9KvYtiH3WKHLvgropUnlpwzoF9+m/gcGmW6h/5pwJUqDQ3oX31p3Eyi3xeTDOif\n3y6k6sxlVeavgB8DbwfuQTpX51O+oWwei5AhzXuADzjYU4e/IKNleQJajqwQLVp5WrSR3n8znw8i\nr6X6BTJv7a5M+kPYrwyaNkuQ/d4eKzmnb36b+PwF5O0WWU5EVmMdyEnbDPzc2bruKNtA0mcNnIb8\n8DPdAPOXyA9NF6o05HN91UXjJh/9vkjjs9+dtxXjjlnVc/IiAz8GfBV5DLkR+WVg+8x+HlmCPJ84\ndnlcVts8jkw+PCEnbR1S4Xlcgexjk0d2FPIw4CbkMe1G4JWkRbcG6SCaYFK3ZWKqm/8i4BsV+Xz1\nu02fryg4PsRs2b/r/Zw2ZboHfzUAsgp8veG1mrp2lYZ8ri9f42bWYgb0+yIPn/3uvK1YnDix7K+I\nO4E/Ae8AXkN6k1YTrkR6zvOZ4+dYlmPKKcCRmWP7kJ540s+1SGftjpwy1iK99/0F13gQODX+/xHA\nJ4DPIaOL25C3G7w+cf6FyIoME6ruU/ZeZf21zT/GpKPsi9/T9NmVurbZkqd7W6p0D/5qwJW2NORL\nfcHsxM20YgamEzehasAXv2elrbDmfUjnynYobwPyXPWLmb89wFdK8o1K0vYgPda8iZbnxWlfyxxf\ngzyyTM4BuAn4LelXMo3ZSf4I25hjMF9tchIy6lhEBAxK0sso8teWAfJLtoqm/I6YHZ+LGFLfhyJG\nJWl1dG+af0yV7qFfGnBlQLWGQm0rihgSXtyEqgFtKxYYUFJnZyIrI7YhPdMXGRZ6NDJRz7bX+RgL\nu/xm/7IjaElGmc/HIJvB/iaR/xFkZehlifOeER//Q06Zz0ZGznYhq0D2kh9MK5Fnz1W8ArP9Wb5D\n+QTJiEnRmd6nIn9t7/OHkc3/TGjC74j8QDOxuwuf8xhi3liY2jbKfHbVvWl+MNc9+KsBV9rSUKht\nRR5DzOLGxq5R5rOPcROqBrStEArrbAXp91NuQoZeTTaUnDYjx/zbHfJuxXwC4kakk7ee9PDlHPCm\nOO2oijIi0qKrc5+S/trmX4IEhQ2ufkdMBpqt3dP2OcsQsy8YG9tGjjZNS/fgnwZcaVtDobYVWYZU\nx42tXSNHm/T7wjx/H74vXGm0zk5HHkeujT+vRH4JbHI2s3lGjvltXpCeZDGyd5sNS5Fnx7uAG+N/\nP0r5BrpJItKiq3Ofkv7a5r+Eejsmu/gdMRlotnZ34XOS3Uy+1SIPG9tGjjZNU/fglwZcmYaGQm0r\nkpjEja1dI0eb9PsirO8LVxqts0WkJ8CfGhd2RlGGDjGdAJjHC4HX1cx7CfBah2vXISItOtv7lPXX\nNv+dyBLeaRIxGWg2ds+Szza2hax7cNOAKz5raExEGG2FrV0hx01fNZAkIqC24nbs9yObFnM18y1B\neuNFqyKq2I3bvm91iCgf2i+7Tyb+luU/GRlGnjYR1Y8ziuyeVZ/HlNmmuk/jogFXfNRQRHhtBVR/\nV2ncLNBHDUQE0lZsRoYR2zRWMSOiWHSu96kq/w662cgwojzQXPz21WfQuEsS0Z4GXPFVQxHhtRUa\nM2kiwtNARABtxUVxYSCrLAeulilOROTfA9f7VJX/cORNDF0QUeyPi98++6xxlyaiHQ244rOGIsJq\nKzRmJokISwPQ07YiufvuucCxyLYRq4ELkD2+FL9wvU8m+S8G7na2tFlc/PbZZ407c7qsK581VERf\n2wqNGXP6qoEqetFWnIy8EzK7n9jKBo1V7LmX9FJh1/tkmv8WizKbJuszuPnts88ad/k0rQFXfNbQ\nmFDaCo2ZYkLRQBJtKxRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFmT7/A1TuLADP\nlUklAAAAAElFTkSuQmCC\n", "prompt_number": 39, "text": [ "\n", " ___ \n", "\u2572\u2571 2 \u22c5\u27581,0\u27e9\u2a02 \u27581/2,1/2\u27e9\u2a02 \u27581/2,1/2\u27e9 \u27581,1\u27e9\u2a02 \u27581/2,-1/2\u27e9\u2a02 \u27581/2,1/2\u27e9 \u27581,1\u27e9\u2a02 \u27581/2\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 2 \n", "\n", " \n", ",1/2\u27e9\u2a02 \u27581/2,-1/2\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Uncoupling can also be done with the `.rewrite` method:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jzc.rewrite(\"Jz\", coupled=False)" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\sqrt{2} {{\\left|1,0\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAmYAAAAkCAYAAAAjI/bEAAAABHNCSVQICAgIfAhkiAAACyFJREFU\neJztnWvMHUUZx38thZK2b42VSwsBjrSKiqB4IwWU0IoiElGUaiRCoEalXgtoYjTa5tUUTaFQ8Ua8\nHMFLjVggsYr3Y0xI1CgqGvkgceMHUTCgURptrPXDs8d3d89eZnZ2z87ZeX7Jm/bs7Mw+z+z/mTNn\ndmYWFEVRFEVRFEVRFEVRFEXphucBhxr4UxRFURRFURz5JnBk10YoiqIoiqL4yuIpXecC4EfAv6Z0\nvb5wL3BUB9e9HFjUwXUhTJ+VNF1pwBWNG6VLQtRAL9uKaXXMtgCfnNK1+sRxwIoOrnsCsLGD60KY\nPitputKAKxo3SpeEqIEg2oo54A7gxAYNOBv4UIPlhUQEDHKOu96nqvxrgC/XLNuViHyfwc1vn31u\nI+5mmYh2NOCKzxqKCKut0JiZJCIsDUBP24rkiNkbgWuBV9PsSNq7gJsbLC90XO+TSf6H4rRj6xjY\nEi5+++xzW3HXR7qsK581VERf2wqNGXP6qoEqetdWHKK4B2rLs2i+U/b1hsvzmYjie+F6n6ryvwR4\nr0P5dYkot8vFb199hmrbVPcLNNlG2eKrhiLCaytM/NK4EfqqgYgethVt9ySvBW4oSX8BsBf4FnA/\n8Fng+Ioyn1SStgz4tY2BMafEduwCbgRuY7InuxtYUqPsWeW7wAbCmtjrs89t6N4kf2i6d8VnDbWF\nzz5r3EwHnzXgK4V11mbHbB1wAPhjQfpzkLlnVwEvA9YDTwHuo14P9/nIys/TLPM9Afg+0jHbClwD\nPBAfOyJx3ggZmgyFQ8D3kF59KMyiz3V1b5p/RFi6d2UWNeTKLPqscdMss6iBrimsszY7Zu8Gdpak\nzyOrNf8Wf/4n8E7gaOB6i+s8HdgHvBU4aG8m70E6YHsSxz6FjKJtThy7G7i4RvmzzOeBK7s2Yso0\n4fPptP9r2VX3pvlD1L0rGjf10LiZbULUvSu5deYSBHPAPwrSjo/THyjJfy7wA+SNAA/Hx+5DOmov\ntrDjd8DL4/8PgTMt8gJcCvwE+E/i2KOI7ZeysM3HQeBnyOPXnxqWvRTYBDyXhTcX/Bu4K76m7zyM\n+L0Gmaxoyiz7XdfnJNcA25D5D23hqnvT/HV0D7OtAVfqaGjW60vjJo1+X5gz6367YFxnVRPWlgFf\nAj5ecs4NSCWXcT9S+U/OHP8z8HhJvlFJ2hC71zbNxefn+fJt4O+ZYyuBTxuWfT7SGz6b9DPkOeDN\nwK2Uz3+AbidzjtkAvN+iXFe/owq72pz8P8bW5yxDw+skqbJtVHE9l9eVVeW30T34rQFX2tBQqG1F\nlqHhdcaY2DWquJ4vcROqBrStqKizy5DRoUPIY7235ZyzJC5gHhktW5lzzipkvlYVy4HVmWPHxdf/\nYUm+UUnaELtAe2Z8/o6ctL1x2tLM8Z1UL1B4FTL6l+10JtmKTP5bVXJOxOSNNblPZdjmXxTbafLY\nuwm/I/LF7OJ3mz7nMcS8MTC1bVRxvTa/YMBM9+CvBlxpS0OhthV5DDGLGxu7RhXX8yFuQtWAthWC\na9z8n1XAfmROWJbtwHk1y70eGdY7q+ScUUnaELtAOys+f3tO2u1xWnZ15lrKN8xdjfwCWIasMn1a\nzjlXI3udDCh/I0JEd739JNcBF1ac05TfEbPjcxFDmvdhVHG9tr9gqnQP/dOAK1UaCrWtKGJIeHET\nqga0rUiTqrO6PbRHkceZW0gPP65A5oyVjXgVsQ7pWe5A3n81DcaTN/OC6/D438Myxx9ERvaWFZS5\nBfgI0nG9Gunxn5FIvw55RPoZRFT7gZMs7Z42Q6ondfbN7yE6kTVJle6hfxpwZUi5hvpYX0M0bpLo\n90U+ffTbhSGJOnMZOrsFeCrw0sSxt2A3F2XMUuT1BLfiNkfBlkdK0pbH/+YtcLgNeENBvgELix4O\nIAK8CjgH+CDwe9KvYtiH3WKHLvgropUnlpwzoF9+m/gcGmW6h/5pwJUqDQ3oX31p3Eyi3xeTDOif\n3y6k6sxlVeavgB8DbwfuQTpX51O+oWwei5AhzXuADzjYU4e/IKNleQJajqwQLVp5WrSR3n8znw8i\nr6X6BTJv7a5M+kPYrwyaNkuQ/d4eKzmnb36b+PwF5O0WWU5EVmMdyEnbDPzc2bruKNtA0mcNnIb8\n8DPdAPOXyA9NF6o05HN91UXjJh/9vkjjs9+dtxXjjlnVc/IiAz8GfBV5DLkR+WVg+8x+HlmCPJ84\ndnlcVts8jkw+PCEnbR1S4Xlcgexjk0d2FPIw4CbkMe1G4JWkRbcG6SCaYFK3ZWKqm/8i4BsV+Xz1\nu02fryg4PsRs2b/r/Zw2ZboHfzUAsgp8veG1mrp2lYZ8ri9f42bWYgb0+yIPn/3uvK1YnDix7K+I\nO4E/Ae8AXkN6k1YTrkR6zvOZ4+dYlmPKKcCRmWP7kJ540s+1SGftjpwy1iK99/0F13gQODX+/xHA\nJ4DPIaOL25C3G7w+cf6FyIoME6ruU/ZeZf21zT/GpKPsi9/T9NmVurbZkqd7W6p0D/5qwJW2NORL\nfcHsxM20YgamEzehasAXv2elrbDmfUjnynYobwPyXPWLmb89wFdK8o1K0vYgPda8iZbnxWlfyxxf\ngzyyTM4BuAn4LelXMo3ZSf4I25hjMF9tchIy6lhEBAxK0sso8teWAfJLtoqm/I6YHZ+LGFLfhyJG\nJWl1dG+af0yV7qFfGnBlQLWGQm0rihgSXtyEqgFtKxYYUFJnZyIrI7YhPdMXGRZ6NDJRz7bX+RgL\nu/xm/7IjaElGmc/HIJvB/iaR/xFkZehlifOeER//Q06Zz0ZGznYhq0D2kh9MK5Fnz1W8ArP9Wb5D\n+QTJiEnRmd6nIn9t7/OHkc3/TGjC74j8QDOxuwuf8xhi3liY2jbKfHbVvWl+MNc9+KsBV9rSUKht\nRR5DzOLGxq5R5rOPcROqBrStEArrbAXp91NuQoZeTTaUnDYjx/zbHfJuxXwC4kakk7ee9PDlHPCm\nOO2oijIi0qKrc5+S/trmX4IEhQ2ufkdMBpqt3dP2OcsQsy8YG9tGjjZNS/fgnwZcaVtDobYVWYZU\nx42tXSNHm/T7wjx/H74vXGm0zk5HHkeujT+vRH4JbHI2s3lGjvltXpCeZDGyd5sNS5Fnx7uAG+N/\nP0r5BrpJItKiq3Ofkv7a5r+Eejsmu/gdMRlotnZ34XOS3Uy+1SIPG9tGjjZNU/fglwZcmYaGQm0r\nkpjEja1dI0eb9PsirO8LVxqts0WkJ8CfGhd2RlGGDjGdAJjHC4HX1cx7CfBah2vXISItOtv7lPXX\nNv+dyBLeaRIxGWg2ds+Szza2hax7cNOAKz5raExEGG2FrV0hx01fNZAkIqC24nbs9yObFnM18y1B\neuNFqyKq2I3bvm91iCgf2i+7Tyb+luU/GRlGnjYR1Y8ziuyeVZ/HlNmmuk/jogFXfNRQRHhtBVR/\nV2ncLNBHDUQE0lZsRoYR2zRWMSOiWHSu96kq/w662cgwojzQXPz21WfQuEsS0Z4GXPFVQxHhtRUa\nM2kiwtNARABtxUVxYSCrLAeulilOROTfA9f7VJX/cORNDF0QUeyPi98++6xxlyaiHQ244rOGIsJq\nKzRmJokISwPQ07YiufvuucCxyLYRq4ELkD2+FL9wvU8m+S8G7na2tFlc/PbZZ407c7qsK581VERf\n2wqNGXP6qoEqetFWnIy8EzK7n9jKBo1V7LmX9FJh1/tkmv8WizKbJuszuPnts88ad/k0rQFXfNbQ\nmFDaCo2ZYkLRQBJtKxRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFmT7/A1TuLADP\nlUklAAAAAElFTkSuQmCC\n", "prompt_number": 40, "text": [ "\n", " ___ \n", "\u2572\u2571 2 \u22c5\u27581,0\u27e9\u2a02 \u27581/2,1/2\u27e9\u2a02 \u27581/2,1/2\u27e9 \u27581,1\u27e9\u2a02 \u27581/2,-1/2\u27e9\u2a02 \u27581/2,1/2\u27e9 \u27581,1\u27e9\u2a02 \u27581/2\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 2 \n", "\n", " \n", ",1/2\u27e9\u2a02 \u27581/2,-1/2\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 40 }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `uncouple` method can also uncouple normal states if given a set of spin bases to consider:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "jz = JzKet(2, 1)\n", "uncouple(jz, (1, S(1)/2, S(1)/2))" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\frac{1}{2} \\sqrt{2} {{\\left|1,0\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }} + \\frac{1}{2} {{\\left|1,1\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},\\frac{1}{2}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},- \\frac{1}{2}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAmYAAAAkCAYAAAAjI/bEAAAABHNCSVQICAgIfAhkiAAACyFJREFU\neJztnWvMHUUZx38thZK2b42VSwsBjrSKiqB4IwWU0IoiElGUaiRCoEalXgtoYjTa5tUUTaFQ8Ua8\nHMFLjVggsYr3Y0xI1CgqGvkgceMHUTCgURptrPXDs8d3d89eZnZ2z87ZeX7Jm/bs7Mw+z+z/mTNn\ndmYWFEVRFEVRFEVRFEVRFEXphucBhxr4UxRFURRFURz5JnBk10YoiqIoiqL4yuIpXecC4EfAv6Z0\nvb5wL3BUB9e9HFjUwXUhTJ+VNF1pwBWNG6VLQtRAL9uKaXXMtgCfnNK1+sRxwIoOrnsCsLGD60KY\nPitputKAKxo3SpeEqIEg2oo54A7gxAYNOBv4UIPlhUQEDHKOu96nqvxrgC/XLNuViHyfwc1vn31u\nI+5mmYh2NOCKzxqKCKut0JiZJCIsDUBP24rkiNkbgWuBV9PsSNq7gJsbLC90XO+TSf6H4rRj6xjY\nEi5+++xzW3HXR7qsK581VERf2wqNGXP6qoEqetdWHKK4B2rLs2i+U/b1hsvzmYjie+F6n6ryvwR4\nr0P5dYkot8vFb199hmrbVPcLNNlG2eKrhiLCaytM/NK4EfqqgYgethVt9ySvBW4oSX8BsBf4FnA/\n8Fng+Ioyn1SStgz4tY2BMafEduwCbgRuY7InuxtYUqPsWeW7wAbCmtjrs89t6N4kf2i6d8VnDbWF\nzz5r3EwHnzXgK4V11mbHbB1wAPhjQfpzkLlnVwEvA9YDTwHuo14P9/nIys/TLPM9Afg+0jHbClwD\nPBAfOyJx3ggZmgyFQ8D3kF59KMyiz3V1b5p/RFi6d2UWNeTKLPqscdMss6iBrimsszY7Zu8Gdpak\nzyOrNf8Wf/4n8E7gaOB6i+s8HdgHvBU4aG8m70E6YHsSxz6FjKJtThy7G7i4RvmzzOeBK7s2Yso0\n4fPptP9r2VX3pvlD1L0rGjf10LiZbULUvSu5deYSBHPAPwrSjo/THyjJfy7wA+SNAA/Hx+5DOmov\ntrDjd8DL4/8PgTMt8gJcCvwE+E/i2KOI7ZeysM3HQeBnyOPXnxqWvRTYBDyXhTcX/Bu4K76m7zyM\n+L0Gmaxoyiz7XdfnJNcA25D5D23hqnvT/HV0D7OtAVfqaGjW60vjJo1+X5gz6367YFxnVRPWlgFf\nAj5ecs4NSCWXcT9S+U/OHP8z8HhJvlFJ2hC71zbNxefn+fJt4O+ZYyuBTxuWfT7SGz6b9DPkOeDN\nwK2Uz3+AbidzjtkAvN+iXFe/owq72pz8P8bW5yxDw+skqbJtVHE9l9eVVeW30T34rQFX2tBQqG1F\nlqHhdcaY2DWquJ4vcROqBrStqKizy5DRoUPIY7235ZyzJC5gHhktW5lzzipkvlYVy4HVmWPHxdf/\nYUm+UUnaELtAe2Z8/o6ctL1x2tLM8Z1UL1B4FTL6l+10JtmKTP5bVXJOxOSNNblPZdjmXxTbafLY\nuwm/I/LF7OJ3mz7nMcS8MTC1bVRxvTa/YMBM9+CvBlxpS0OhthV5DDGLGxu7RhXX8yFuQtWAthWC\na9z8n1XAfmROWJbtwHk1y70eGdY7q+ScUUnaELtAOys+f3tO2u1xWnZ15lrKN8xdjfwCWIasMn1a\nzjlXI3udDCh/I0JEd739JNcBF1ac05TfEbPjcxFDmvdhVHG9tr9gqnQP/dOAK1UaCrWtKGJIeHET\nqga0rUiTqrO6PbRHkceZW0gPP65A5oyVjXgVsQ7pWe5A3n81DcaTN/OC6/D438Myxx9ERvaWFZS5\nBfgI0nG9Gunxn5FIvw55RPoZRFT7gZMs7Z42Q6ondfbN7yE6kTVJle6hfxpwZUi5hvpYX0M0bpLo\n90U+ffTbhSGJOnMZOrsFeCrw0sSxt2A3F2XMUuT1BLfiNkfBlkdK0pbH/+YtcLgNeENBvgELix4O\nIAK8CjgH+CDwe9KvYtiH3WKHLvgropUnlpwzoF9+m/gcGmW6h/5pwJUqDQ3oX31p3Eyi3xeTDOif\n3y6k6sxlVeavgB8DbwfuQTpX51O+oWwei5AhzXuADzjYU4e/IKNleQJajqwQLVp5WrSR3n8znw8i\nr6X6BTJv7a5M+kPYrwyaNkuQ/d4eKzmnb36b+PwF5O0WWU5EVmMdyEnbDPzc2bruKNtA0mcNnIb8\n8DPdAPOXyA9NF6o05HN91UXjJh/9vkjjs9+dtxXjjlnVc/IiAz8GfBV5DLkR+WVg+8x+HlmCPJ84\ndnlcVts8jkw+PCEnbR1S4Xlcgexjk0d2FPIw4CbkMe1G4JWkRbcG6SCaYFK3ZWKqm/8i4BsV+Xz1\nu02fryg4PsRs2b/r/Zw2ZboHfzUAsgp8veG1mrp2lYZ8ri9f42bWYgb0+yIPn/3uvK1YnDix7K+I\nO4E/Ae8AXkN6k1YTrkR6zvOZ4+dYlmPKKcCRmWP7kJ540s+1SGftjpwy1iK99/0F13gQODX+/xHA\nJ4DPIaOL25C3G7w+cf6FyIoME6ruU/ZeZf21zT/GpKPsi9/T9NmVurbZkqd7W6p0D/5qwJW2NORL\nfcHsxM20YgamEzehasAXv2elrbDmfUjnynYobwPyXPWLmb89wFdK8o1K0vYgPda8iZbnxWlfyxxf\ngzyyTM4BuAn4LelXMo3ZSf4I25hjMF9tchIy6lhEBAxK0sso8teWAfJLtoqm/I6YHZ+LGFLfhyJG\nJWl1dG+af0yV7qFfGnBlQLWGQm0rihgSXtyEqgFtKxYYUFJnZyIrI7YhPdMXGRZ6NDJRz7bX+RgL\nu/xm/7IjaElGmc/HIJvB/iaR/xFkZehlifOeER//Q06Zz0ZGznYhq0D2kh9MK5Fnz1W8ArP9Wb5D\n+QTJiEnRmd6nIn9t7/OHkc3/TGjC74j8QDOxuwuf8xhi3liY2jbKfHbVvWl+MNc9+KsBV9rSUKht\nRR5DzOLGxq5R5rOPcROqBrStEArrbAXp91NuQoZeTTaUnDYjx/zbHfJuxXwC4kakk7ee9PDlHPCm\nOO2oijIi0qKrc5+S/trmX4IEhQ2ufkdMBpqt3dP2OcsQsy8YG9tGjjZNS/fgnwZcaVtDobYVWYZU\nx42tXSNHm/T7wjx/H74vXGm0zk5HHkeujT+vRH4JbHI2s3lGjvltXpCeZDGyd5sNS5Fnx7uAG+N/\nP0r5BrpJItKiq3Ofkv7a5r+Eejsmu/gdMRlotnZ34XOS3Uy+1SIPG9tGjjZNU/fglwZcmYaGQm0r\nkpjEja1dI0eb9PsirO8LVxqts0WkJ8CfGhd2RlGGDjGdAJjHC4HX1cx7CfBah2vXISItOtv7lPXX\nNv+dyBLeaRIxGWg2ds+Szza2hax7cNOAKz5raExEGG2FrV0hx01fNZAkIqC24nbs9yObFnM18y1B\neuNFqyKq2I3bvm91iCgf2i+7Tyb+luU/GRlGnjYR1Y8ziuyeVZ/HlNmmuk/jogFXfNRQRHhtBVR/\nV2ncLNBHDUQE0lZsRoYR2zRWMSOiWHSu96kq/w662cgwojzQXPz21WfQuEsS0Z4GXPFVQxHhtRUa\nM2kiwtNARABtxUVxYSCrLAeulilOROTfA9f7VJX/cORNDF0QUeyPi98++6xxlyaiHQ244rOGIsJq\nKzRmJokISwPQ07YiufvuucCxyLYRq4ELkD2+FL9wvU8m+S8G7na2tFlc/PbZZ407c7qsK581VERf\n2wqNGXP6qoEqetFWnIy8EzK7n9jKBo1V7LmX9FJh1/tkmv8WizKbJuszuPnts88ad/k0rQFXfNbQ\nmFDaCo2ZYkLRQBJtKxRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFURRFmT7/A1TuLADP\nlUklAAAAAElFTkSuQmCC\n", "prompt_number": 41, "text": [ "\n", " ___ \n", "\u2572\u2571 2 \u22c5\u27581,0\u27e9\u2a02 \u27581/2,1/2\u27e9\u2a02 \u27581/2,1/2\u27e9 \u27581,1\u27e9\u2a02 \u27581/2,-1/2\u27e9\u2a02 \u27581/2,1/2\u27e9 \u27581,1\u27e9\u2a02 \u27581/2\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 2 \n", "\n", " \n", ",1/2\u27e9\u2a02 \u27581/2,-1/2\u27e9\n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 2 " ] } ], "prompt_number": 41 }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Example: Spin-orbit Coupling\n", "\n", "If we start with a hydrogen atom, i.e. a nucleus of charge $Ze$ orbited by a single electron of charge $e$ with reduced mass $\\mu$, ignoring energy from center-of-mass motion, we can write the Hamiltonian in terms of the relative momentum, $p$, and position, $r$, as:\n", "\n", "$$H=\\frac{p^2}{2\\mu} - \\frac{Ze^2}{r}$$\n", "\n", "The resulting eigenfunctions have a separate radial and angular compents, $\\psi=R_{n,l}(r)Y_{l,m}(\\phi,\\theta)$. While the radial component is a complicated function involving Laguere polynomials, the radial part is the familiar spherical harmonics with orbital angular momentum $\\vec{L}$, where $l$ and $m$ give the orbital angular momentum quantum numbers. We represent this as a angular momentum state:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "l, ml = symbols('l m_l')\n", "orbit = JzKet(l, ml); orbit" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${\\left|l,m_{l}\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAC8AAAAaCAYAAAAnkAWyAAAABHNCSVQICAgIfAhkiAAAAppJREFU\nWIXt102MjVcYB/DfGJQQbTTxsTJFohqfESRidEYmTRtNRRRLhETCykdiJWFlg7AgFixESrS1E1qL\nZto0bYVFg4aIz1j4WpAgxBAW50zmde57e8/lioX5Jzfve/7Pc57zP885zzn3pRfvFDswsMzQJ2n/\nXOLzA+7iJT5rrK4sdGJJrmMZtuNmg8TUi2b8WGZIM18Nc/B7w+TUhxe4iAmpIUf8EEz1/sTDfqxM\nyRzxrcLSvU/xNzBcUrh9Mzq24xYuZfjORwcmYymGYpFQ7LOwDSewFp9iGPpjObpqxP4Ji3GgmkNn\nCXcGhzOE98fO+H4af2I9miK3UTi1tqMlcs14KEy0FvrhaJGotW0+xhR5W+bLKLgJo3E7Cn0Z7V3C\nShzC9ci9iL/hGfG7hNWvKNxudCbtb+Pg4zOCjxT25KTYpzWxH8ZfCTc6+s7LiA9j9Kxuzcy34w4u\nZAS+hSeYG5+nEnubyuR8jafyD4MrGNvdqCW+DX/E95zsEyb8N54VuPEYoVL8AvyCRxgl1MD/YQyu\nVjMWgw8W9uOa2N6b+I7DgITrg/vYlPCrhckMKnBD8Rzfx/ae+PwK/wr1kmIrJhYHq4Zu22XMxD8F\nW7tw6x1M+kzFJyoz3C6cQI8LXIuQ6ZOYjv8ifxIP8GsSox8+x7lqgtNBN+A4dnl9ol/gHq4l/t/h\nvHBspnFXJVyzcHbvxeZC/EFRfLqqC7GsmvAy8bWwpU7/HHwjXGQpjkhu2Nw/ZtXw0Vv2L0OHyi3T\nItwbT4rk24hvFQqr0egQTqAiVmBfrY6dmQP0Fb5wmmo51olheupocGGsso+kN878c6zTc/U3CrPx\nG6ZhRuTm4ViZcyp+d4PF1IuzQqbn6tkFbap8SfWiFx8aXgFjVHm5OC1AbAAAAABJRU5ErkJggg==\n", "prompt_number": 42, "text": [ "\u2758l,m_l\u27e9" ] } ], "prompt_number": 42 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, the spin orbit interaction arises from the electron experiencing a magnetic field as it orbits the electrically charged nucleus. This magnetic field is:\n", "\n", "$$\\vec{B} = \\frac{1}{c}\\frac{Ze\\vec{v}\\times\\vec{r}}{r^3} = \\frac{Ze\\vec{p}\\times\\vec{r}}{mcr^3}=\\frac{Ze\\vec{L}}{mc\\hbar r^3}$$\n", "\n", "Then the spin-orbit Hamiltonian can be written, using the electron's magnetic dipole moment $\\mu$, as:\n", "\n", "$$H_{SO} = -\\vec{\\mu}\\cdot\\vec{B} = -\\left(-\\frac{g\\mu_B \\vec{S}}{\\hbar}\\right)\\cdot\\left(\\frac{Ze\\vec{L}}{mc\\hbar r^3}\\right)$$\n", "\n", "Ignoring the radial term:\n", "\n", "$$\\propto \\vec{L}\\cdot\\vec{S} = J^2 - L^2 - S^2$$\n", "\n", "for $\\vec{J}$, the coupled angular momentum.\n", "\n", "The electron spin angular momentum is given as $\\vec{S}$, where the spin wavefunction is:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "ms = symbols('m_s')\n", "spin = JzKet(S(1)/2, ms); spin" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${\\left|\\frac{1}{2},m_{s}\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAADgAAAAgCAYAAABHA7voAAAABHNCSVQICAgIfAhkiAAAAwpJREFU\nWIXt2F2IVVUUB/DftUnyayTzs6iG6SEiMEpF8HtKYiDDD1CCqCjtpXqRHuZVRUH8wgff/AiSLJhQ\nhKJPoiAL6anE9/NWiSloaCR6fVjn6p1zz9w558610Wn+cOCctfbae/332mvvtQ//Q/yE6SPtRAm8\njspgynE5socxOUc+BZ/isfb41TY8ihfKGCToysg2YQuqObqRxhwcK2OQGJzE3UgQPsGsPEXeEr0X\ncQRv5SlGC8Fv8LyczWa0EKziW7yYVYwWgvAB3swKRxPBc7gudtVb6Cho/CqWpO878SMOFLRdjZV4\nBm9gGtaLZbUIe/AFNuMhzMR4EY1rBceo4TA2YnuzRon2HQXjsT99/0VMzPtubwZ9Yub31o15Hy6L\nySiLithwbq3MO71ElwtSFXTjD0GmmuqviYgeExNLLLPrBjnXhkAVX6G3WaNE+yI4BxMwNx18aUb/\nsah969Gdtn2pxTGno7/2cacj+DuuijPqKk5n9CvwfUbWi3/wQ4tjnhe8HqQYwWqBZyj04Gf8Wyd7\nCrM1ElyLL/E3Hhc5WQYdmIqLFCNYKfDU8CQeyNiPwzKNRHpEDp6qk01L5R+l330iH8tgFT5r1iDR\nWg72iGj2Z+Tz5Odfv4Hk4Lm0bScW4N0W/DguJgrFz8Ei+FOs//kZ+SM4qzH/ZuDDjOxXcefcJXbc\nbSV96MIlXGjWKNEYwYXiIN4izpllTey3lnSqDF7GO3hN/u1hBxYP1UliIMHJonqpYQOuiMjkYecg\n8uFiCn5L32eI6qceHfi6SEeJgQTn4gaeSL87RZ5syLFdileKDNICJqS+nRHlXbYQWIf3inSUGEiw\nIpZobbd8WhB8NmPXgX2a/AAaJiqC5Bp8p3GlnBDHw5BINN9Fj4py679EF/4StS1RrNdHqxuH8gzL\n7qIbRXXSV9JuuDiP3SItJmKS20U8vI2DRTtL5EdwlSBIHOZ5bUYC94vKJxdFa9HlIqk/F+VVr8zF\ncgSxGifLGGT/bHeL+1m2/uxsk4PDxQF3jy9jGMMYMrgJOdmQt/74E/MAAAAASUVORK5CYII=\n", "prompt_number": 43, "text": [ "\u27581/2,m_s\u27e9" ] } ], "prompt_number": 43 }, { "cell_type": "markdown", "metadata": {}, "source": [ "From this we build our uncoupled state:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "state = TensorProduct(orbit, spin); state" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$${{\\left|l,m_{l}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},m_{s}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAHsAAAAgCAYAAAAyjgdLAAAABHNCSVQICAgIfAhkiAAABYdJREFU\naIHt22usXUUVwPFfubdApb0GxEoJyKUFFdFGaAwhvEpRqOFdpBgNQuQVCh9oLNEECBBCgAhGXgo+\nquENBYEPoPjKgaiEYIKCiYQEPIkRlEfASKhS6vXD2od775y9z5lzex69yfknNz0zs/bM2jOzZtas\nPWXIkCF+j50HrUSHfBVzqgq36aMis41dMb8kfwHux0f7q04Wu+OIQSsxG6ljPMk7E5dhoqRsa2AR\n7hq0ElvCtzFvAO3WVQ/o1jrYcA8+UlaQLuP3l8jciVfFC+7ZXb2yqOGUAbQ7W1mPr+UI1iryr8Pf\nuqVNh4zgvgG0Wzc7LXsOfqnEUct10A7F493UqAM243l8akDtzzYm8CscmRaMZjw8hv3w/S4r1Qk/\nwlpc0MEz22E1lokOmMB/8RCe6raCWxk/xg14rJVQrSTvaNFRH+u+Th1xt3xH7fPihQ8yfTlbgHPE\nxP1QmzrqZucy3uBO4Z1XUivJuxYvZzZwPG7EE8KZW4arcZXYBo4Vq8mFRf563IG5GXWvwmkZcifi\nGa2dybViX9uphUxd84B+Bd8Tg30Pzs/QZyq97J+UFbi4lUCtJO8PwqrasS2+U/x+Gr/F101a1jeE\nV3+dyU4cwb/lDeJcPNBGZhdh0R8QS/8nSmTOFeflcTFwVdR113p73T8pDUftfb+snYP2QXxGnnN2\nmHiBOViMfwjFJ4ryTcKS7hIdSThfm1WcCxM24QWtHbU1uAbviEFdK/yNBuvwL/yw0OEd7JHRdjfo\ndf+kTIg9e2WVQC1JH1M8tE9G5YvEnrq0eOaQpPxuEW+eyuJC9uiM+mGJSeso47YkPSKWzYNxKU5I\nylfgjIq66rpr2f3on5SdsaGRaGfZh+Of+EtGxa9go+jAjZo93uWaJ9NK/Ef+se5F7NWi/H9JerPw\n4G8u0g8l5a9gYWbbW0o/+ifldTHGO9J+sJcLZ4I86yYmyJN4d0rePmI/rSWyJ+LneFsspyNt6l6C\nl1qUp+8zIlaC88XymVr2IjGZc5jI+Muhl/2TMiq24jfLCqc2Nl9YxnlF+pZE9uPYPsnbpqj4kiR/\njXi5Habk7YT38MUi/d3i3yPxR7GfpVyFT5cpXnAp9i1+b4tbTd+zL8SXp6SvFV+KyqjbsmW8V/3T\nCSdoEZuoTfk9Jgb7KByA06eUHS5m8gbTaQQw0v1oA36X5O1fyI7hsyYnVUOPNAI0Fw9WKV6wUL43\nvofYz6uom/lg97p/cvmpFsfLWpJeh0dxvelL5CfxGv6ayB+HPwurSus9J8kbES95i/hs2Kh/B7yl\n2SpOMn3CVXGcvHP2LxR7WQV1Mx/sXvZPLuP4SSuBWocVXt6hfA5fwM9K8u+VH0E7QhyvDtQcQTu7\nKGt3C6WuebAPEBPlMnGGPbRNHb3oHyL4sganqv7CdaWIIL5PTmy8Fdtt4fNlfE5zTHdcnEs3Ztbx\na3GmPUXExyfEoG8SHvlM4vzzhcP0zSK9WjhPe+PvFc/0on8WiIFcig+L4+b6RGZULP0Xtaqo1kGj\nh+BLHcjn8ifNe+0VWjtmvaBuumUvFUe7JUV6TEyi1RXP96p/5hW6PScczLKAyyoZodxaZoOj4gZJ\n5eW2GbLQ5D7XuP81qvxSRa+pmz7Yc8Qy3njnfcVg76eZXvVPQ495wtP+jYihpzwojlwtqXVVrc5Z\nJbzoZSL4QHw8OH0AutS1dtBuV3487CXjeMOkg3eyZgteLHySJlIP7+YyoT7yrLCKFSYn3nKDuanS\nijNERGxdn9t9Hd8SW8fZ2E3zmJ2FH/RZr1lPXbllH2Mynr59hcygmCucxlKG98Y74zDhED0iwpsr\ntbkg0GeOx8ODVmI2kv6PkMXi23IaDx/rv2qV3GTr0mfIkCFDhgwZMgP+D8enOQ4jSfDWAAAAAElF\nTkSuQmCC\n", "prompt_number": 44, "text": [ "\u2758l,m_l\u27e9\u2a02 \u27581/2,m_s\u27e9" ] } ], "prompt_number": 44 }, { "cell_type": "markdown", "metadata": {}, "source": [ "For clarity we will define $L^2$ and $S^2$ operators. These behave the same as `J2`, they only display differently." ] }, { "cell_type": "code", "collapsed": false, "input": [ "L2 = J2Op('L')\n", "S2 = J2Op('S')" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 45 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We also have the spin-orbit Hamiltonian:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "hso = J2 - TensorProduct(L2, 1) - TensorProduct(1, S2); hso" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$J^2 - {1}\\otimes {S^2} - {L^2}\\otimes {1}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAKoAAAAZCAYAAAChKLVZAAAABHNCSVQICAgIfAhkiAAABIhJREFU\neJzt2luoVFUcx/HP8ViWmpaZWhGWvSilKVFp5YWkKJSoIIOiJ9OSfCjoIlRIdrNSCiqk+5AvPpWE\nlZcu2EMXArML+GBlT0VYgZhBmZ4e/jM6Z5g5e8+ePTNndL5w2Gfvdfuv33/tvf5rraFLlw6gJ2O5\ny3A5RuMKPIZP8zKqw+kkbTrJ1roZidVl94vwN85ujzmDik7SppNszcQ0HMb5xftR6BMdPd7pJG06\nydZM9IgpoxQ2XCA6OKNtFg0eOkmbTrI1kRnYhi/F29eHb7C0LM96rG2xXcPxbYvbLHESHsImbMA7\nWCGm0k0VeVutzRC8i13CV//hC+HDWQll2+HHajTk2x78gR0VzxfjGdkXZVm4BF8JR7SasdiJZfr3\neQn2iIFboh3alJgn9FmdkK9EO20tp6Zvh6Ss4EKMwdayZwuL1wcwDOdmty8VU/Ae7sahJrdVi/X4\nCOv0F/NV/IMPi/et1qaS2cXrthR5220rKXw7NGVF84rXT4rXuRhfrHwCZuI3/JzNzlTswoLi/wUR\nX9XDMLFQuFgMsj4xuDaK0CaJqbgWq2qk/ygGcTu0qWQuDuLzFPnytDWrxo369ghvi46PwCTsLzOk\n9Dcqa+UZKKhv6r8ab4q9wvLp7RTciVdwekIdi4pt3l4j/WGDQ5sTcEDyIM3b1jw0pn7fHqEHv0vu\neCspSN+ZG/E1zhsgz71imhwzQJ5pxTb34wlcKQbFYGOWsPPpFraZl8Y0MFAvKhZ8MkvhJlGQrjMT\nxFs+HK9jcpU8y3CHiM3WJdS3Rv+vz18ibk0Sv5U8KGxbkJQxJ/LWuCDjQL2nWPCaLIWbREG6zqxy\nVLgT8bL++4T34day+7WYmFDnDDwqjhr/LdrxQQpbWsX7YkEyukXt5a1xQcaBulE4ZESWwk2iIF1n\n3qq478ULYtpeiRsq0q8SWzVpOQs/iD3mU+so1yx6sU9Mw7WYmnObeWtcUMW3Sav+IZgj9rYOJORN\nYqoIqNPu1e3EXQ22ebji/pCYIXaIBeLGivRfVV9xrlB9T/IXvCFi1rRbfbXIQ5/pYjFU64clJ4uF\nzfIsBtYgL40HpHygzhQnK085ekIxHafh43orrsJ3kk9H8qZy8PTieeGo+eJtLxfyTLE9U85IA9s9\nGt/jz4YszUefOcXr9hrpi7G5wTYqyUPjunhRfHKXlD17ThzDTWmk4iZQkG7qXynOsKkeP92vf/y0\nBudU1HGdOHWq9sUch724KYUtrWCj0OWMKmnjxfF32r3ztOShcTkFCb5dLlaMJRaK2DTPaSIvNojO\nDE/IN076FelEEVtV8ix+Eg4oX6BMEiHRI/UY3kSGimPuXVXSZmO3+BjlTR4al5Po2148Lkb8S+Lt\nnFMrcxsYhy1imi1tD+0Vp2W3DVDueun2+LaKMKeS0vbTzeKIdHvRji3ipKrdTBZ27Raa7BO2bRba\n7HFUr0ubZEOjGmf17THHfLwmYsDKU5OlxbSxbbDrWKKpGrf71zKtZBhuEfFTn+j7QTFzfNZGu44l\nuhp36dKlS5cuXbp0OW74H3nWOWF+Ncp/AAAAAElFTkSuQmCC\n", "prompt_number": 46, "text": [ "\n", " 2 2 2 \n", "J - 1\u2a02 S - L \u2a02 1" ] } ], "prompt_number": 46 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now we apply this to our state:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "apply1 = qapply(hso * state); apply1" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$- \\hbar^{2} l^{2} {{\\left|l,m_{l}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},m_{s}\\right\\rangle }} - \\hbar^{2} l {{\\left|l,m_{l}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},m_{s}\\right\\rangle }} + J^2 {{\\left|l,m_{l}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},m_{s}\\right\\rangle }} - \\frac{3}{4} \\hbar^{2} {{\\left|l,m_{l}\\right\\rangle }}\\otimes {{\\left|\\frac{1}{2},m_{s}\\right\\rangle }}$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAqIAAAAhCAYAAAACusmsAAAABHNCSVQICAgIfAhkiAAADGxJREFU\neJztnXmwHEUdgL+XlxCSvCQaEYNB8gh4ABINqCQlOQ2IJCRgcVgaEEwMl38YSSQUWgSvRCSJligi\naB4q4TCJQcEDChwojVgR7wOrVMbCAkHU4lIgJs8/fjO1s7MzszM73XPs/r6qV2+np7ent/ebnu2e\n7h5QFEVRFEVRlB7gOGAVsA64G5hTam56j13AAWVnIgPnAH1lZ8JD3TWP+qhUFXXTLlqfdk7d3IQK\n+TkAbAhsnwn8B5iSIQ2VNx8uMFhyHrJwObCw7Exgxl2lFRf10TRaR5rBRd20hdan+XCpl5tQIT+n\nA/uAw7ztCcAwImEaVN78uEQLPB7YBhxSZGZScBCwtexMkN9dJRoX9dEkWkeaw0XdDDMHOBtYAXyD\nzn9YaH2aD5d6uQkVqjv7kNa63z17FCLfjJTv7yZ5NwFjSjiuS6vAK5Dek+GIfVXgFuAVJechr7tV\nR31MTxV8jKOb6kgfdTM9tt18Eniv9/oMpJEzvoN0uqU+VTezUVjdOQ54C/DqFHG/DmzMkHYn8m7L\nkH6RLAHOLeG4LvGSVlXgE4HLCjiOTXd91MdmXNRHk+S5wKubzbiom2Fej9STAKcDe4j/IWq6Pq2i\nn+pmNgqpO5cCDyIFcUKbuMuBq0gevHoT8ISX3qER+9PI63SQbhH0A7eVcFyX+gnch4x1sznQuSh3\nnQxxi0R9TE8RPrZjhpeHnyI9oMPAr4CVoXhZGkxORJi6GY26KbdZL4/ZZ7o+hWr6qW5mozA/NwHP\nAqMT4ixG5APYn+RC2wg8EhGeR96kdIvkY0gLs0hc6inwpcDbLR+jCHedDHGLRn1MTxE+pqEP+Cfw\n84h9aetIHycmXN1spZfdPAZYDVwPjE2IZ7o+dWLCy/ZT3cyGVT8nAU8D/0Na6M96f78NxZuLiDfZ\n+zsVmJWQ7m5kUHQQE/JGpVs0U4HPFnxMl3oKfCAyvsQGRbrrZIhbNOpjekz4OB0YmTONo5Fy2hAK\nz1JH+jgx4epmK93uZhpWIr2eA6FwW/WpExNetp/qZjYi/cxbEfo8h3TBP4AMmL0pEO4zDbiDVnEn\nxqQ5AbkF9eVA2FxksOudiLwzgceRLyYtUemWwV+RzzIG+G/K94xGJh4ciwg3DLwA7ERu03UrTwB7\nkZl3jxlOuyh341Af64cJHz+E+ObmyMc87/8PA2Em6kgfdbN+2KorZwK3e/8fBu4HrgNOonn8po36\nNI4q+KluZsPmtRyA0zA7822Rl95rvO1pwDM0vjj/b0JCGk6KdMvknTRmIbbjBGAL8Faab7eNB85H\nTsaXtUnDpb4tqQXARyylbdtdHydD3DJQH9OT18ch8n++HciEEX8CSSd1pI8TEaZuRtPtbkbxJuBe\nGrfaTwZeBA6PiGu6PoVq+6luZsPmtZzNSJd8P/BSZKD8c8CNHaZ3NfBozjw5OdNdCnweaf0dirRg\nNgDrgfuAU5Be5TVe+FeR2wSjUqY/CtieIt5pwC9IHpC9ChkIPCkhjkurpO8BrkUEvgX4QIr8+Ngu\nnyD+QOcRHby3HUW562SIG4X6mEydfBwi3wWjD1lO5yc50gjiRISpm830iptxLAMuQcpvOzILOgrT\n9SlU28+6uwnd4Scg40W+j4h3A3Ak0pX/7w7T+xlwc848OTnS3Y/G2I/dwI+Qk9BvxVyKdDNvpCFF\nP9IjkbZ1BPJFJw12noy0oMYCXwFeFxHnQmQdsUFExjhczLWWiiqfIKuRlrhpinLXyRA3jPqYTN18\nHCLfZ38DctH5VI40gjgRYeqmGermZl5M16dQfT/r6iZUwE9Tv0gnAG8Efgx8GPlV/3sk03/sIL2J\nXnr3GcpfJ+nORb6QPuSW19+RL2LY278HabVspTH+aq/3l2XR1hsQ+eK4CPg0snjwhUjZBm95rAae\n8tJxvXhTMxy/U4oqnyBDwHkdvjeOMt1VH83RLT6mZb7337GUvrppjl5y03R9GkfV/Kyrm9BFfp6M\nZHoL8kFAMrgPaSlkZbGX3hE58+XkSPcgZADydO89s0P7bwZ2hcKmeXEXZcznHQn7vhba7ke60I8H\nrkBmGwZZQGPGbBgXcy2pIssnyHakpW2KIt11MsQNoz4mUzcfh8j32XciY/TGtYuYEie0rW72rpt5\nMF2f+jih7Sr6WUc3oQJ+BmfNH40MlE277twvgQu813MCYX/xXi/00vpuBxmcj8z0/EMH7zWVrj+j\nawEyGy48m20ecrIFOQl4nmw9uYfRKLMo9oW29wIfRNYO3IFckII8hjxdxTZFlU+QkUhLOHiLJ4+3\nUK676qM5quJjmBuR2+hhDkGePPNixL7lyO3NOEYg3u6meTaySdRNc1TFzbx1ZRpM16dxVM3Purrp\nHwvK9zM3u5CFlYML3G5BBtP3d5DegzSeWJCnV9QxkO7twD2hsCOQ1kB4sPbdwLe811ORz34iclLG\nPeFkPVJBxBHXkpqNLI8R1ZJ6X0xaLs0tqfDs2qi/duQtnyycipy8JinSXSdD3DhMlHeSk+pjevL4\nOES6Xo2ZiIuXBMKOQT7Pxzs8dhROaFvd7F03o0j7+U3Xpz5OaLtq1/K6uwn19pOxSKs+PLj2EWS2\nHDS66NMwgLQWLva2v5Qjb06GdF+LLP4cZATyi/2jofCLaL0tNglZxPd0b/uLoXxEzTAcRePLjOMK\n5JnRIIOKr6N5bMka4N2B7auBV8Wk5dJ5l77N8knLDpJnE2alaHedDHFtl7dDq5PqYzby+DhEus9+\nDXIheH8gbDOS97xDl4I4gdfqZm+72Smm69MgTuB11a7ldXITKuiniclKs5Av4tuBsKnAwcgA2GXI\nYNe0+Hn6E9I1/YCBPLZLdz7wEI2TxWcG8BJaW2Pzab0tNoi0Cu4C3gz8zgsfhwyqvj8iT0uQVkgS\n1yIDmcd6rzcjS0D4fAbp4l6BlPtozD/yzGb5pGUQWRLkXxnfl0SZ7pblI8Q7qT6mZxDzPkbxELAW\neaQiyNi4i5HeBNNDl3zUzc7pJTfDmK5P46jatbwubkIX+3klMlZgTCBsCvAP5MvppNW+GhlP8jny\n/Vh2UqZ7JJLfh0PxlyCPJtsvIt3zQ2H9wDeR1tm6QPrvAL4Xk79baS63OJaQbv2xu0genO7S2pI6\nznvvOqS7fQ6t2Cwfn1OQ1tfZRN+S+CSyCLBJinbXSRnXdnnHOak+NrDt4xDpejX6gU8gPSRfQMaS\nRZVJXpzQtrrZu26mYSMy0SaIjfrUxwltV+laXhc3wb6f7dyEYvysFE7G+FdayMNGosdCDCInUVre\nhiztMIvWJzKs9PYd0CYNl2aBB2h+TvWZyLIRU2Leb6N8QD7Dr73XL6f1ZB+JnJx1x8kY31Z5Rzk5\niProU4SPQ1TrCShOxvjqZve62Y65yESheZaPE8TJGL+oa/kg9XMT7JRPOzchxk9Tz5rvFka3j5KZ\nhcBZEeHLEenScg9ye+MsRLRhROQ9SC9JJ8/bnYas9XY98GdkEeIxSGvltoj4NsoHZLzJBOA3wA+A\nc0P7l9B8u6dXsFXeUU6qjw2K8PFppPeorqib3etmEhORVSBsDQsxRVHX8jq6CXbKp52b0KPXcidD\n3NnAuwwf/0AaXeADgfCRwDbDx0qDS3NLqg/p0vdbZkcR/4xgG+UTzMcYZCbdvTS37kAGgk+0dOwi\ncTLEtVXeUU6qj830io9BnAxx1c3edXMN8iPGobo9okVdy+voJtjzs52bEOOnlWd91pCRyHNgbzWc\n7vHIF3IssmagzyKSF78timFkzTB/eYe1wCaaB1GDvfIBOaGeRGZB7kQGcv8tsH8ashzIUxaOXVVs\nlneUk+pjg0HUxyTUTaEX3VyC3G59wVL6JijyWl43N8Fe+QyS7Cb0cN15RsnHPxxZ0HoNzT/6N9O8\nzlpRuMSPS1sOXEX6xY5NMYCcOMuQMTKrQnlYT3EL+9qmbB8h2kn1sUEv+RhE3WzGRd0M8krgnMC2\nQ7E9omX7qW4m085N6N66U8mIS7TAi2k8Tmz/mDhlMAoZ76J0Jy7qo1JNXNTNIOcBlyE/NtYCjyLj\nGfM84lHpDJd6uQlt/NTJSspc5FnAdwKTkSe5PI7IXjZLab8+m9JdqI9KVellN8OPeLwA2Er22eyK\nHarsJmjdqQTYRfPSENOAZ2h9HNiE4rMWyTVUJy+KedRHpaqom9EcjNz6fR74DtILpxRL3dwErTsV\nRVEURVEURVEURVEURVEURVEURVEURVEURVEURVEURVEURVEURSmC/wOumnJ1lMu6vAAAAABJRU5E\nrkJggg==\n", "prompt_number": 47, "text": [ "\n", " \n", " 2 2 2 2 \n", "- \u210f \u22c5l \u22c5\u2758l,m_l\u27e9\u2a02 \u27581/2,m_s\u27e9 - \u210f \u22c5l\u22c5\u2758l,m_l\u27e9\u2a02 \u27581/2,m_s\u27e9 + J \u22c5\u2758l,m_l\u27e9\u2a02 \u27581/2,m_s\u27e9 -\n", " \n", "\n", " 2 \n", " 3\u22c5\u210f \u22c5\u2758l,m_l\u27e9\u2a02 \u27581/2,m_s\u27e9\n", " \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " 4 " ] } ], "prompt_number": 47 }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note this has not applied the coupled $J^2$ operator to the states, so we couple the states and apply again:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "apply2 = qapply(couple(apply1)); apply2" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$- \\hbar^{2} l^{2} \\sum_{j=m_{l} + m_{s}}^{l + \\frac{1}{2}} C^{j,m_{l} + m_{s}}_{l,m_{l},\\frac{1}{2},m_{s}} {\\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\\frac{1}{2}\\right\\rangle } - \\hbar^{2} l \\sum_{j=m_{l} + m_{s}}^{l + \\frac{1}{2}} C^{j,m_{l} + m_{s}}_{l,m_{l},\\frac{1}{2},m_{s}} {\\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\\frac{1}{2}\\right\\rangle } - \\frac{3}{4} \\hbar^{2} \\sum_{j=m_{l} + m_{s}}^{l + \\frac{1}{2}} C^{j,m_{l} + m_{s}}_{l,m_{l},\\frac{1}{2},m_{s}} {\\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\\frac{1}{2}\\right\\rangle } + \\sum_{j=m_{l} + m_{s}}^{l + \\frac{1}{2}} \\left(\\hbar^{2} j^{2} C^{j,m_{l} + m_{s}}_{l,m_{l},\\frac{1}{2},m_{s}} {\\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\\frac{1}{2}\\right\\rangle } + \\hbar^{2} j C^{j,m_{l} + m_{s}}_{l,m_{l},\\frac{1}{2},m_{s}} {\\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\\frac{1}{2}\\right\\rangle }\\right)$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAB24AAABKCAYAAABzXXRYAAAABHNCSVQICAgIfAhkiAAAIABJREFU\neJzt3Xu0LGV55/HvuQCCBxhQ8ShREE0QFBwVgyjiEVAEFYFBdJCAFxwTQUdFYxg1s01AEMU4Bh3v\nbqOjUYy3ZCJeoltE0WU0Rh0l3tJjYhSD0YATUSNn/ni67d69+1Jd17eqv5+19jp9qV3vs+t0/56u\n7uq3QJIkSZIkSZIkSZKkJbQZeHnTRUiSamPuS9LysgdIUprMZ0mSJCVna9MFLKG9gScDOxquQ5JU\nD3NfkpaXPUCS0mQ+S5IkSVpnrekCJEm1Wmu6AElSY9aaLkCSNNFa0wVIkiRJozY3XYAkSZIkSZIk\nSZIkLTs/uF3Mw4AvApc3XYgkqXJmviQtL3uAJKXJfJYkSVKn+cHtYj4M/Bj40Jzlzq+hFklStbJm\nPpj7ktQ19gBJSpP5LEmSpE7zg9vF3Br4j8DVc5a7bQ21SJKqlTXzwdyXpK6xB0hSmsxnSZIkdZof\n3C7mGOBa4OYC69gdeCZwCPDs/nVJUnrKyHww9yWpjewBkpQm81mSJEnSr1xOvLCfZ6XiOiRJ1cua\n+WDuS1LX2AMkKU3msyRJkjpta9MFtMzxwGPHbrs9sdOwaeS2o4FbjVy/Cbi42tIkSSWblPlg7kvS\nMrAHSFKazGdJkiRJAOwH/H3/8rY5y67MuG/njB9JUhoWyXww9yWpS+wBkpQm81mSJEmd5zduszsa\n+BhwX2Dv/uU8tgDnMTx/ymXFS5MklayszAdzX5Laxh4gSWkynyVJktR5m5suoEW+RHzQfSywVmA9\njwDeR+wUHEnscEiS0lJW5oO5L0ltYw+QpDSZz5IkSeo8P7jN7pvAOcBLgVvmLPvTGffdFfjP/cvf\nAu5UvDRJUskWyXww9yWpS+wBkpQm81mSJElS6XYD9uxf/hBwxwZrkSRVz9yXpOVlD5CkNJnPkiRJ\nStKWpgtYQr8Efg48iDhC9IPNliNJqpi5L0nLyx4gSWkynyVJkiT9yt7A7zddhCSpNua+JC0ve4Ak\npcl8liRJkgTAecAu/Z/jG65FklQ9c1+Slpc9QJLSZD5LkiRJ4kzgRuAG4EfAPZstR5JUMXNfkpaX\nPUCS0mQ+S5IkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIkSZIk/cpm4E3AYU0XIkmSpMocArwN\n2NJ0IV1xHbCzwp+X1venSJLmMPMlaXnZAyQpTV3O59cApzU4viRJkupxGvBmYFPThXTB4xi+mP9/\nxCfj82wBbgXsCexPHDl5HPBfif+Y60fW+S/AHqVXLUnKw8yXpOVlD5CkNHU1n58OXNzAuJIkSWrG\nJcBzmy6iK97A8AX9l4DdC65vK/Ao4BP9dT614Prq9Erg2U0XIUkVMvOHzHxJy8YeMGQPkJSSruXz\nIcAXgN1qHjc19hpJy84clJbLrYCvAIc3XUgX7AF8leFOwmtLXPeziJ2OtjiAeHDV5fwax5IkMPNH\n1Z35YO5LapY9YMgeICklXcvna4EH1zxmiuw1kpadOSgtn4cCf4NTJpfiMOCnDHcSHlviui8ipuzR\nRitNFyBpKZn5zVlpugBJS88e0JyVpguQlLSu5PNpwMdrGksbrTRdgCQ1bKXpAiRxDXDm+I1bGyik\n7b5MTFvw6v711wGfA75dwrovAk4vYT1VOoOYwucY4CkT7t8XOIc4YvQlwKHEuWQOBP4c2A4cDNwI\nvKykmpoYU9JyMPPTy/wmx5W0XOwB6fUA818SdCOfN/XHemYNY6UsxV7T5LiSlo85KC23i4E/Bt4F\n/HtTRRxJTD2zAnyECKS2ejfDozs/B+zabDm1OBI4AdgMfH/KMucCuwDfAM7q37YH8DPgqP71Q4mp\njRaxMuO+qsYE+DRw2xy/J7XF2aQxHUPq/cHMn6zK/F2ZcZ+5L+WTSuZnlUpvsAdM1kQPqHJMsAeo\n29rWA7Jocz4/FPhmCetJpVfmkWqvqXpce426LOVek2JemoNS9+TJwW8DJ4/eUOc3brcBpwK/179+\nBnAV8OvAdzOu40jgAcDewAOBPwSuLrfMzM4FjiDmnz8CuIzuHyn5HeCzwL2Br01Z5p3AfkSQv61/\n272Iubqv7V8/Avg/M8a5PbEtRx/gR7N+nv+biKMRyhpzmjsSj90bcvyu1AZ3IqYC+2iDNZTRH6pm\n5k9WVv6a+1I9Usj8rFLqDfaAyZroAVXmP9gD1G1t6gFZtTmfzwXeUXAdZfbKJt5vS7XXlDnuJPYa\ndVmqvSalfYtR5qDUPXly8B3Ea8MPVFLRHIcDtwB37V/fizgq8oyMv78NuHTk+hnAvwH7l1VgDkcB\nv2B4hOejGqylTs8GXjTj/rOBt45cfyExBdDAVUSz3GeBMVfm3F/FmAA9YgoIqY32JI5Cv/OMZe4A\nvL2ecqYq2h/qYuZPVlX+rsy539yXNpqX+1Vn/jHAbxE7HG8Dji+wrtR6gz1gsiZ6QFVjgj1A7dWW\n1/1VaGM+bwNuBu5ZcD1l9cqm329LsddUOW4Pe43aq+n9jbxS27cYZw5K7VFFDh5GTJN8mwJ15baJ\nOIJvcFTHPYiAvHfG3081YC9kuIPwQ+IT9a77AHBs//KxwP3G7n8LMQf+wCeAHf3L+xBH0+wCXNC/\n7SLgBXPGXJlz/6JjZtXDRqJ2Opd43uxk/mP4T4kj75pStD/UadkzHzbmfhWZD+a+tKisuV9l5t/A\n8Hn5GOJN3z1zrivF3mAPSKMHVJX/YA9QO7XpdX9V2pbPJzN9SsxFlNUrm36/LcVek2fcrHrYa9RO\nKexv5JXivsUoc1Bqhypz8AfAY3NVlcGtgd8kphmY563A5QusO9WA3Ux87Xmwk3ANsKXRiqq1hXgQ\n7d6//nbgPWPLfIo4sgDi/+urDM81sztxAvOnAIf0b7uImFphlpU59y86ZlY9bCRqtyxv4DyMeLOj\nSlX2hzote+bDxtyvIvPB3Jfympf7VWb+PYm8Bzid+AbUrA9u29Yb7AFp9ICq8h/sAWq3VF73N6Ft\n+fwqYgrKLOrolU2+35Zqr8kzblY97DVqtyb3N2Zp277FgDkotU8VOXgl8Ma8Bc3yaODzRNEPnbPs\nk4lzj8w6Se//IkJrJ3CXCfenFLDbgesZ7iS8uNly5roHsf0/SezcXAm8ntjOm4ijabZP+d0jiNAe\ndc6kBRfwQeafsPl5BccYd1z/50LiyKBpemRvJFcAXypUlSZpcrvOy6F5UnhMZHkDZxPwERY/cXpW\ndfeHqrUt8yF/7k/KfCiW+1kyH9LP/RSe313U9HZdhtyvOvMH3g48f8b9ZfeGutgD7AGQxnO9i5re\nrm3vASm87m9Sm/L5i8S0mPNU3SunPWbzvN9mr7HXtEXT27XtvQbS2d8YVce+xbxtbw6ag23R9HY1\nBye7gOnnui7s5cBPgN1mLPNIIiAhTn594IxlLwf+YcLtKb15M3ACMbXMzv6/85pEE/YiGsZ3gLNY\n//90O+JInjcD14393i7AG4hvTLwceOrIfVuA3ylQ03aicdXtMuAS5h8R1CP7B7dvBP44f0maount\nOi2Hsmi6dsj2Bg7Ei7UTKqyjrv5QlzZkPuTL/VmZD8Vyv6nMh/JzP4XndxelsF2XIferzPz7AM8h\nsmePOcuW3RvqYg/Ixx6geVLYrm3uAam87m9SG/J5V+DnwMMzLl9lr5z0mF30/TZ7zZC9ph1S2K5t\n7jXQ/P7GNFXvW0zb9ubgkDnYDilsV3Nwo5OI89zeKmdNE+0L3Nhf8S1ESP4E+MrYcg8mwnF7/+cU\n4KgZ6/0c8Lax21J882bgMoZHd34fuG2z5axzF2I6g08z/STHdydqv2Ls9tsQR/48A3jW2H2PA/Yv\nUNcTgDOBAwqsY1GnEk+aBxJHP83SI63HWBGHA1ubLqKFJuVQm2R9A2c/Yv79stXZH+qWcuZD/tyf\nlflQLPefQP2ZD8uZ+2Z+finkSxFZcr+qzB/1X4ij3rdNuK+q3lAne8DinoA9oC72gPza3APqet2f\n+uMr9Xy+F1HbvCxsolcu+n6bvWbIXqNFtLnXQD37G4s8vprctzAHh8xBLcIc3Ogu/fXeJ2dNE+1G\nnA9jJ/Dfgbv1f+4wssxBwE0MX0APfvaass69iMB9yshtKb95A3G0zGeJv+vTlPzpeAH7An8HfIM4\ncfgs1xFBW5eziaOKDqxxzAcQDfAk4MQ5y/boRiMBWKU7f0tdJuVQ22R9Awdiqoo7zF1qMXX1hyak\nmvmQbu43kfmwnLm/Sjf+jrqlki9FZM39sjP//sQUlYOpjgZvUJw+YdkqekPd7AGLswfUZ5Vu/B11\na3sPqOt1/+oC4zQh5XyGeB/rFua/0Vt3r1z0/TZ7zXr2GmXV9l4D9exvrGYcA5rbtzAH1zMHlZU5\nONmu/fWWnhWn9ld875LW94j++n6jfz31N28GXkIEdkpHdb6D2FbHZVj2k8B/qLacVunRnQBepTt/\nS13Gc6iNFnkD51jgBRXUUHV/aFKKmQ/mfhE9upGVq3Tj76hbSvmSV9bcLzvzjwA+xnBqsJOIqSDv\nNmX5sntDE+wB3dOjG9m5Sjf+jrq1vQfU9bp/dYFxmpJqPgM8DfhhxmXr6pV53m+z1+TXI/3nUBar\ndOPvqFvbew3Us7+xmnGMgSb2LczB/Hp0Iz9W6cbfUTdzcLp/Ac6Dcr/KfQzxQu9LxFEmrwROA95N\nvpNpPwT4HvD1/vVvE/O+p+zxwJOII0xuaLiWgSOJo10+CfxVhuWvAH5caUXdcjjwROLIie8Dz5yz\n/KOB44npkc4hjs56DPFkfwDwMuIE8s8ips3Yjzja4onAL8ovP9k6F92uVRnPoSxSqf3xwNH9y5cC\n17BxGvRxHwcuBF5MHAVelqr7Q1NSzHww96tk5nc782G5cr/szP9r4E3A+f31HU1MufjNKcuX3Rvq\nZg9YPvYAe8AkKdSf0uv+FKSazwPbgX/OuGwVvXLSY3bR99vsNdWx19hrJkml/qb3N2apat9i2rY3\nB6tjDpqDk6RSf9U5+APitWKpPg9cRYTjG4BDgfcDP8q5vr8mjlxpi2OAfyXmcU/Ja4kAaMMbYCnq\nMf3oiTsCrwA2A/cgtvNhM9a1a395iHncrwEuADb1b3se8eS8fGTMLcQLjzL+/1bJdiRI03Uuul0n\neRPwxQV/dkxYz6I5VEbtZdafx3OIb0mVqYv9IdXMB3O/qB6Ts9LMTzfzwdzPq4rMz6rs3lAne0B3\n9bAH2APqrb+Nr/tXSffbJSnn88AfET0wi7J7ZVnPOXtNMT3sNfaa9ta/qLp6TRX7FrO2vTlYTA9z\n0Bxsb/2LWiQH/4Z4rViavYBfAi8ELmF4pN7fAp/Jsb69iXmuf7uU6qr3G8QRk2c0XcgE3yAezL/W\ndCEt1WN6AP8Rw2kuTia288Ez1vVQ4jxvm4ipkd49dv+zicf9fcdu/zHwu1kLnmGVbM2k6ToX3a5V\nyZNDqdRexG2BK0tcXxf7Q8qZD+Z+UT0mZ6WZv17XMh+WM/fLzvysyu4NdbIHdFsPe8Aoe8BsKdWf\nR94esEqaH9ymns8D/5M49+48VfTKsh6z9ppiethrRtlrZkup/jzq6DVV7VvM2vbmYDE9zMFR5uBs\nKdWfxyI5eC3xWrE0JxEb7M3EuTEAbk98/feSHOt7ZH99h5RSXbVuS0wBV8aTqAo/BX6Scdlfr7KQ\nluoxPYDvPnL5ZcSRMbPcAdid+Gr/TuBBY/e/g407cAf1l33E/FLnWiVbM2m6zkW3a1Xy5FAqtRf1\nZ8RRimXoWn9IPfPB3C+qx+SsNPOHupj5sLy5X2bmZ1V2b6iLPaD7etgDRtkDZkup/rzy9IBV0vvg\ntg35PPAm4BMZlquiV5b1mLXXFNPDXjPKXjNbSvXnVXWvqWrfYta2NweL6WEOjjIHZ0up/ryy5uDV\nwBth/TluDwNex/Ar2vN8keEn48eM3Pbt/uXj++v6y4zrG/UQ4Hrgazl+t067Ae8DPgJc1nAt09xI\nHHU0z67A04FnVFtOp1w3cnkH83e+vtf/91iiwX927P4dxIuMUQ8Hbs6w7lFvIebLH3dn4DeBn0+4\n78kMp2uqq85pFt2uVcmTQ6nUXsRW4uinwXQyRXoDdKs/tCHzwdyviplfrM5pUsrNZcz98cyH4rmf\nRdm9oQ72gOVmDyhW5zQpZag9YKOij6+6tCWfB34O7JJhuSp6ZVmPWXtNNew1xeqcJqWsttdsVEav\nqWrfYta2NwerYQ4Wq3OalHLEHJxtFyY/nnL7NPE17z1GbnszcAMxH/eiPg+8q3851W/dbiKOhvjf\n5PsbJ9mV8ufGfz9xAus95iz3XOA+JY+9iM3Ayxscf5oe84+cGXzF//yM63w/G09cfwhxtMnDxm7/\nCPDe/uUDiMfaw4gXI5dnHG9glcWOjC5aZ1HTtuuexJQSd57xu68n5stf5OfBY+sokkPTaj+SOMn8\nCrHNjmGyovXvzPAzzSmUe4L3rvSHtmQ+mPtF9ZidlXVnPuTL/VWWJ/MhzdzPmvll1J8398vM/EVq\nKLs3VM0eUD57gD1g1DL3gDa+7l8lnW/ctimfB7Ke47bKXrlolo2z1xTTw16Tt84ilrnXlFF/3fsb\nq2R/fFW9bzFp25uDxfQwB/PWWYQ5mH4OlnqO2z2IT4HH517+B+Ct/csHkd024oiV8/rXX1Oouuq8\nGPgCUW9ZnkfMd16mHcTUEE+bscyjiQd4U/Ym5nL/QoM1TNNjfgA/gnhi3nPs9oOBW43dtpk4uuKF\nY7c/jXge3Xrktn2JMBo8Jl49ct8aGwN9nlWyN5Oy6pxl0vYZNWm7nksE8U6qfbNgXg7lqX0bcOnI\n9TOAfwP2L1Rp+d5D/J+WoUv9oS2ZD+Z+UT1m50sTmQ+L5/4qZv4iys79Zcz8rMruDXWwB5TLHmAP\nGGcPaEbeHrBKOh/ctimfB/6A9d8cmaTqXjkty7Lagb2miB72mgF7zZC9Zr1Vsv2f1LFvMemxswNz\nsIge5uCAOThkDsLfAX9Y1sDHERvsxJHbDujf9lTgLOBOC6xvcELxE4hPzJ9QSpXlehLwHWJ+8rKc\nBXyfOLqzbM8BbuqPsXnk9tsRD4SnVzBmHmtNFzBBj/mh9VLgn1k/peBDiOfA+Imn78vkueyvBD41\ndtt9+svuBdyPYajdmjg5+awgm2SV7AFcRp2zTNs+oyZt14Gqm8msHMpb++HEi7q7joyxk2gqqTiQ\neJyUpSv9oW2ZD+Z+ET1m50vdmQ/5cn8VM38RZef+MmZ+VmX3hqrZA6qz1nQBE/SwB+Stcxp7QPd6\nwCppfHDbxnyGeIP2h3OWqbpXznrOZWWvya+HvSZvndPYa5a319SxbzHtsWMO5tfDHMxb5zTmYDdy\n8Edk+//O5EXEfNu7j9y2P7ER30++qSyfQ8xB/z9YH3wpOI742/IemThqE/H17fcSD6orSljnNEcT\nX3n/PPAh4klwOWmdIH2t6QIm6DE/tD5HnGB61KHE4+Tvx24/GfgKG3cE14gXFKO2EP9PryGOfBk8\nF04EPjinpklWyR7AZdQJ8Chix/S3iB3rgWnbZ9Sk7TpQRzOZlkN5a99ENKVBc7kH8Xfcu4xiJ1hk\nqoiBi4EHllhDF/pDWzMfzP28eszOl7ozH/Ll/ir1Zz5Mzv02ZD6Um/t1Zz4snvtlZ/64y4kcGldF\nb6iKPaBaa00XMEEPe8DAGvYAaEcPqPt1/yrNf3Db5nw+hXiTceuMZarulbOec4uw1+TTw14zsIa9\nBtrRa6De/Y1Vsv2f1LFvMeuxYw7m08McHFjDHARzEOKxsRM4NW9xy2zwADo+4/KbiA1+a+Jom4OB\nBxBfQX8V8C3Wz4F9RMn1ts1a0wVM0GN2aO1FTF0w7STzLyq5HogXAG04F9GewJf6l2/H5OY3bfvM\n2651NZNZ8tY+8FYWP09xVnmmitgKfLiietrKzK/eWtMFTNBjer40kfmQL/dXqT8n5+V+mzMfiuV+\nlZkPi+d+1Zn/YOB6YgqxtrIHVG+t6QIm6GEPyMseMF3XXvev0uz/Sdvz+V40+7jOur/aFWtNFzBB\nD3tNXvaa6bq2v7FKGv8nXcjMtaYLmKCHOZiXOThd23PwIOL/ocnzYrfS7YlP/HdW9PPl+v6UzPKc\nlLuItZrGWUSPjaF1OrGzBzEdxi+Bu0z5/Uun3F7E3wJ3z/F7rwS2l1zLLLsT2+/LwMuI59C40e2z\nyHZNoZnkrR3gycBlFJuaapY8U0WcxsaT0y8zM78eazWOlVWP9fnSdOZDvtyvO/Nhfu63OfMhf/1V\nZz4snvtVZv7exM7UGu394NYeUI+1GsfKqoc9IC97wGRdfN3fxONroAv5vCtxLruTahhrYNH91arY\na0IPe01e9prJuri/0WSvqTIzzcHQwxzMyxycrAs5+Ajiw+lFT4+59F4FXFfhz2/X96csZI3FTspd\ndKzU9FgfWocRT8iLiDcmv8n0I0EeBDyu5Hr2YzhlwLaS1122TUQzOQX4GBsb6+j2WWS7QvPNpEjt\njySaCUQQH1hBfXmmingvUb+CmV/feKnpMXxeNp350J3cb3PmQ/7668h8WDz3q8z85wK70e4Pbu0B\n9Y2Xmh72gLzsARv5ur98XcnnLxJTBdZh0edc1daw1/Sw1+Rlr9loGfc3qlRHZq5hDvYwB/MyBzfq\nSg5eAHwtd3VaKnlOyp3H7sRUBNcDz2b9eQma1mP9k30b8FHg1cD7gCdO+b2twMsp/yiP04A3Eic0\nP7bkdZfpQOCHDOftfwzrjzAZ3z5Zt+tAk82kSO0PJhrJ9v7PKcBRlVU6NG+qiIOAN9RQh9JWV+ZD\ne3K/6cyHbuR+mzMf8tffVObD7NyvMvNPZni+wTXa+8HtMrIHhB72gDwOxB4wztf9muVVxDkR67Do\nc65K9prQw16Tx4HYa8Yt4/5G1arOTHMw9DAH8zgQc3Bcl3LwXcTjEKj2q8NqvxOJqe5OnHDfvsA5\nxJPjJcR5ZvYknuB/TjxRDgZuJL62X5a6x+0Rbzr2SlhXGe4GvJA4mfnlxNfzU7SNaBz/COxBvDB5\nBdEEing8cDRxJPQ7gWuAKwqusy4HEdNujB+5tTfxeK3Kk4nnxPOYvv0vIZrgZyusQ+kz80MPcz+P\nKnLfzM9nXu5Xlfl3JM43+Cf962vACmke4a2N7AGhhz0gD3vAer7u1zwnE2/m7dd0ITWz14Qe9po8\n7DXrLeP+RheYg6GHOZiHObhe13LweiIf3lm4OnXerJNynwvsAnyDmGMcIjB+xvCohkOBr5ZcU93j\n9mh+mgApryxTRewCXFVXQUqamR96mPtqr3m5X2XmPxG4EPi9/s8/Aa8jztOi9NkDQg97gNrJ1/3t\nsg24mThX2jKx14Qe9hq1V5P7G11gDoYe5qDaq4ocvCdxftvbFKpMS2PWSbn3BPYHvjty21HAZ0au\nnw1cmWGcnTN+qhw3ix42ErVT1qkiTgd+p8a6lK66Mh+y537dmQ/mvtorS+7Xmfk9nCq5TewBoYc9\nQO3j6/52+lPg4qaLqJm9JvSw16idUtvfaCNzMPQwB9VOVeXgRcAHRm/YmrNAdd9+wF7AdcTRoD8Z\nu/8m4FTiJNgDxxNzjw+cCbwW2Af4EfEAvLn/76gtwHkM59q/bEZdecYt4p/Y+LdLqTsI+AsmTxUx\nbgfw36ouSMmrIvOheO7Xnflg7qudsub+DqrP/F8jpvfZDlzQr+kvKh5TxdgDhuwBahtf97fX64mZ\nKZ7fdCE1sdcM2WvURintb7SVOThkDqqNqszBM4Fn5Sur3V5JnIRb2U06KfexwP1GlnkLMQf+wCcY\nfrNiH+AG4qvhF/Rvuwg4YsK6HgXcqX/5z/pjjio6rqTlYuYvrorMh2Huj69rVu6b+ZKKsAcszh4g\nqQ7m83qbiHPpPbzpQmpSda8ZX5+9RlJqzEFJkzwc+BZL+iXbA4j5plN0ftMFTHE3IrSfC2zu3/Z2\n4D0jy3wKuEP/8iZirvtd+9d3J05g/hTgkP5tH+wvN76uZwK/2798GfEV81FFxz2u/3Mh0WQkdZuZ\nv7gqMh+GuT++rlm5X8a45r60vOwBi7MHSKqD+bzRKcDVDY1dt6p7zfj67DWSUmMOSprkk8Djmy5C\nG600XcCCzpm/yETbieY0aV27EfPpA3wIuGOJ40I0p0tY31wkqQkrTRewoCLZO577o+ual/tFxgVz\nX1KaVpouYEH2AEnLYqXBsa8l3vheVmX2mtH12WsktYU5KC2v44hzX28ev6PrX789gwipY4ijQgb2\nJY5u2TTpl/r+HXgR8Iv+8ucQJx9+CXAoEXwHEkecbAcOBm4EXlZS7U2MOc8WYI+cv/twokkcAPzf\nsXX9rP/zIGCNmOe+rHFPBf6KmDf/D4DH5FyPpPS1OfMHdaaU+0WyF9bn/j+OrWtW7hcd19yXlpM9\noFz2AEllMZ9nexLwDuD+xDkKl0mZvWaR95nsNZJSYQ5Ky2s34BXA2cAtDddSqyOBE4hPq79fcF3n\nEl/5/wZwVv+2PYjwO6p//VBiGoFFrTQwZl6PA/bP+btnA08ldm4mrWtv4PcrGPcB/d8/CTgx5zok\npa/tmV/1uHkUyV5Yn/uT1jUt94uOa+5Ly8ceUD57gKQymM/ZnA9cWuD326rMXjNpffYaSakzB6Xl\ndTHwvKaLaMJgXvZ7Ax8vuK49iTD77shtRwGfGbl+NnDlnPXcnphC4NKRn2vGrj+/5DHb4jxiZ2gX\n4PiGa5HUPm3P/DLHbQtzX1JZ7AHtYw+QloP5nN1rgP9UcB1az14jadmZg1KaTgVWmTHzTJenSv5e\n/9+HAFeP3Xcb4Dlkn5LnJmJjfmzk/uOBj45cPxN4LbAP8KMp67yeOGH3qBUmH91Z1phtcCax4/Qi\nYqqGBzVbjqQWanvmU+K4bWDuSyqTPaBd7AHS8jCfs3sa8Abg68CXc65DQ/YaScvOHJTSdAhwOnEq\njp0N19KoDwDHlrCet7D+pN2fAHb0L+8D3EAcvXJB/7aLgBdkWO9KiWNBlOvwAAABg0lEQVRK0rJr\nKvMhW+6vVDCuJCnYAyQpTeazJEmSlNHmpguo2Bbg/sC1JazrbsCH+5c3AbcDPt2/fnN/jCcAfzny\nO1c1MKYkLaumMx/MfUlqij1AktJkPkuSJEn6lSOATzU09geZPeXPQNknID6u/3MhccSnJC2LJjMf\nsuW+mS9J1bAHSFKazGdJkiRpAV38xu0uxHlB9iTmcv+TBmrYDvyAbHNUv6TksU8gzrfyPuI8MJLU\nZSlkPmTPfTNfkspjD7AHSEqT+Ww+S5IkKactTRdQgX2AZxA7CjcBVzRQw+nA14EbgX+tcdxT++N+\nhTiy88oax5akJqSQ+dBM7pv5kpadPcAeIClN5rP5LEmSpJy2Nl1ABX4IPLDhGm4hjizNMlVyma4H\n7kx8IP+mmseWpCakkPnQTO6b+ZKWnT3AHiApTeaz+SxJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJ\nkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJkiRJ7fL/AWERTP06yLvtAAAAAElFTkSuQmCC\n", "prompt_number": 48, "text": [ "\n", " \n", " \n", " \n", " \n", " \n", " l + 1/2 l + 1\n", " ____ ___\n", " \u2572 \u2572 \n", " \u2572 j,m_l + m_s \u2572 \n", " 2 2 \u2572 C \u22c5\u2758j,m_l + m_s,j\u2081=l,j\u2082=1/2\u27e9 2 \u2572\n", "- \u210f \u22c5l \u22c5 \u2571 l,m_l,1/2,m_s - \u210f \u22c5l\u22c5 \u2571\n", " \u2571 \u2571 \n", " \u2571 \u2571 \n", " \u203e\u203e\u203e\u203e \u203e\u203e\u203e\n", " j = m_l + m_s j = m_l \n", "\n", " l + 1/2 \n", " ____ \n", " \u2572 \n", " \u2572 j,m_l + m\n", " 2 \u2572 C \n", "/2 3\u22c5\u210f \u22c5 \u2571 l,m_l,1/2\n", "_ \u2571 \n", " \u2571 \n", " j,m_l + m_s \u203e\u203e\u203e\u203e \n", " C \u22c5\u2758j,m_l + m_s,j\u2081=l,j\u2082=1/2\u27e9 j = m_l + m_s \n", " l,m_l,1/2,m_s - \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " \n", " \n", "\u203e \n", "+ m_s \n", "\n", " \n", " \n", " \n", "_s \n", " \u22c5\u2758j,m_l + m_s,j\u2081=l,j\u2082=1/2\u27e9 \n", ",m_s l + 1/2 \n", " ____ \n", " \u2572 \n", " \u2572 \u239b 2 2 j,m_l + m_s \n", " \u2572 \u239c\u210f \u22c5j \u22c5C \u22c5\u2758j,m_l + \n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 + \u2571 \u239d l,m_l,1/2,m_s \n", "4 \u2571 \n", " \u2571 \n", " \u203e\u203e\u203e\u203e \n", " j = m_l + m_s \n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " 2 j,m_l + m_s \u239e\n", "m_s,j\u2081=l,j\u2082=1/2\u27e9 + \u210f \u22c5j\u22c5C \u22c5\u2758j,m_l + m_s,j\u2081=l,j\u2082=1/2\u27e9\u239f\n", " l,m_l,1/2,m_s \u23a0\n", " \n", " \n", " \n", " " ] } ], "prompt_number": 48 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We now collect the terms of the sum, since they share the same limits, and factor the result:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "subs = []\n", "for sum_term in apply2.atoms(Sum):\n", " subs.append((sum_term, sum_term.function))\n", " limits = sum_term.limits\n", "final = Sum(factor(apply2.subs(subs)), limits)\n", "final" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\sum_{j=m_{l} + m_{s}}^{l + \\frac{1}{2}} \\frac{1}{4} \\hbar^{2} \\left(4 j^{2} + 4 j - 4 l^{2} - 4 l -3\\right) C^{j,m_{l} + m_{s}}_{l,m_{l},\\frac{1}{2},m_{s}} {\\left|j,m_{l} + m_{s},j_{1}=l,j_{2}=\\frac{1}{2}\\right\\rangle }$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAioAAABKCAYAAACVW3/AAAAABHNCSVQICAgIfAhkiAAAE+VJREFU\neJztnXmUJWV5h5+enhkcZssMywzrDCORMDoIETOCMBvIEnYOIkGCIHBUIEoQMkHU0yQjwpDROEEM\nitCEiBpQFkUWBZtF0BAMWxQFpROVLSKbKJuQP351c6tvV93aq25P/55z6nRX3br1vVXd31fv937v\nAsYYY4wxphATgE81LYQxxhhj6mVi0wKkYCZwDLCsYTmMMcYYY2IZaloAY4wxxtTLhKYFMMYYY4yJ\no2pFZQ/gbmBNxe0YY4wxZh2kakXlBuBp4PqE806sWA5jjDHGjEGqVlSmAtsDtySct2HFchhjjDFm\nDFK1orIEuAN4ocA1pgAnAdsCJwf7xhhjjDGFWYOUjCQGKpbDGGOMMWOQqvOo7A68q+PYHKS89IWO\n7QK8LrT/HPCJakUzxhhjzHhmY+Dh4PdpCecOdPnstS6bMcYYY9ZhqrSo7ALcBLwFZZe9Ked1+oET\naPumrC4umjHGGGPGAlU6096LFKEVFMsquw9wJVJQFiPFxxhjjDHjgCoVlYeA9wDnAK8mnPv7Lp+9\nHviL4PefAVsUF80YY4wxphzWA6YHv18PbNqgLMYYY4ypkf6mBUjBH4CXgF2RZebaZsUxxhhjjBnJ\nTODjTQthjDHGGBPFCcCkYNu9YVmMMcYYY/6fw4FngV8DTwFvalYcY4wxxhhjjDHGGGOMMcYYY4wx\nxhjTQzxA9zo9Rbdz6rsVY4wxxqxrHEZbqXge2DbFd/pRFeXpwGbAImA34EPARcDjoWv+Bli/dKmN\nMcYYM264gLZicS/twoJ5mQjsB9wcXPN9Ba9njBm7rAVObloIY8zYZn3gR7SVlfNLvPZfI+XHGDM+\nmYcssHVyYs3tGWNqYBEqOthSVt5V4rVXoaUhY4ypg4GmBTBmvDGxhjbuQ+bZ84L9zwN3Aj8v4dqr\ngENKuE6vsgg4AljZtCDGxLARsBo4DnilpjYPRcVKlwTtdjIbVW5fCpwNLER+b/OBbwBzgW1QIsl/\nKEmmJto0xpTM5bStKncCk5sVpzYWo2WqAeDbaHBNwxzgu9hh2PQ+R6AJSB0sBvYEJgCPxZxzLCq3\n8SCSDdSPXgR2CvYXomXprAw00CbA7cCGOb9rTK9zJNDXtBAAfwQM01ZW/rFRaephGnBWaP9Q4Hco\noimJb6EBuQryKk9G+PmN5uvAwTW0s0nwcwekyEfRihr8VejYTsD3Q/tHApcltDUH+CTqw63tto79\n00tuM45hZJ0xZl3kdHqojt9OwMu0lZX9mhUnlunIArRlwetsB7wKvD7Yn4Hu+9CE7+0N/HvBtuMo\nojwZP784dkbLuXVZSk8Gzujy+ZHAJaH9j6Gl4hbXAQcBszK2O9BAm2BFxYxd0rxPNwEurUecdJxG\nW1F5EtiiWXFGcSwajF6j+MDQh2bfLZPWG4Pr7pDwvRuB9xZsO468ypMRfn7x/BDlT6qDq4EVof0V\nwFtD+xcjn5EWNwPLgt9noSKnk4APB8dWAR9N0e5Al8+ytpmFYayomLFHlvfpV5AVsyeYAHyHtrJy\nG0r01mukVVSmAn8G/HGKcy8B1iScMw85Jc5Ocb085FWejPDzi+cUZDWomn7gCUbmZboULT+1+B7t\nZaI+5BvSsvZMQQ6ux9FORLkK2DFF2wNdPsvaZhaGsaJixi5p3qd7IENGzzCXkVlmz2xWnEjSPNgD\ngLuCc9+RcO4xKDoiyWHoeFR+IC2nkO6Pey7ReWfSKE9VU/QeqpbjS+jF+BqwVcdndT+/PDIW4W0o\nK/R5wc+vAm+OOXcJ8AJaHkvDG1GfuBVNXi4DvoDk70MWirkR39sRKQWdvCfiWFquJZ0zX9kReLsF\n22nI2hLHMOkUlar7yHil6edatH83LX+a92kf8vnrCafaFnsiE/prwc+kF33dpLWofAr4LQqXjGNf\npKiAElR1u+6XkQksDfNQeYKBFOd+EfinjmNplacqKXoPdcmxBvhFx7G6n18eGYuwA/BNRiZV+xwK\nsd0+4vypyBq4IuKzMDOQQvI/KEIm3Hc2QpaRixipsE9Cma6noz7XmZW6H/hAQrtxzEVKUROsRg67\nSVaWYdKNR1X2kfFMLzzXIv27afnTvk9XUl0QSW5W07aqPEZvhd8lPdjZaMB+BSlavw22+zvOW4pe\naHOD7UDa4YpR/Jj05q/PB3IOpDw/TBblKYntyJ+Tp8g9lEmSHHcC/xraL/P5pSWrjEX5NKOTNO4b\nHFsb852fAKd2ueZWaEnkdmCDmHP+JGjj3NCxDZAV5YMo4qqTw8jv0HwUcDhSBOvkIDQov53kaKBh\n1o2lnyJjxXin7P5dJ2kVlY2JmKhPKFuajJxOO7rl5+hFP1Z4HlmB+lH0wfbBFrYMLUAz0guAR4Pt\nCuC/Yq7Zh/6YcfkhwhwM3JRDbpDyNAe4BilPe9FeW8/DycDmOb5X5B7KJEmOGci6cHOwX/bzS0NW\nGcvgP5Ey/pvQsdayzu9ivvMU+r+PYjbyYZkE7IOc6aN4ACk8N4aOPYle6GuRAtXJVxgZGpyFV5Gl\npm7L4uPIyXYmcGHNbTdF3rFivFNF/+5FngD+QPXjaWbORkmSesmaAuk0wIMo15FyVnC9pGy705Dy\nA9mtEQuA52hbslrbjCyCdjBI9tlekXsokzRy7BN89gaqeX5ly1glq5EVMc5P5TqkjEfxZSRjmrIX\nt6LcS0YMs25YVAZZN+6jburq31WRJYp2BR0ReE2b4N6NwnB3RqF7vcC7gV2C31sJns6NOXcJemnd\ni5SMtWjmezn5HPtaWWifTTjvNLSuncR2wNFIO30MOAlZrqbnkK1sitxD3XIsR9awnwb7dT+/PDJW\nwVbo//p44J6Yc54ieklnMVqeuZWRlpI4zgWeziHjeCRrHzkAJdd6M/p7zgbeiV4mO6MU/9eiJbYN\nkDl+ctDGy+WL37NyVj32ZCFP/+4F+bO8T1t8F415ZyJrZ6MsAZ5B5tyxyl1oBjkLzXgXAlehwToP\nm6FO2M2ZaHtG+rDEzbA3Rdl/J9AOoV2UU64kBsk2S+qVe0grx38ga0AT9IKM+wJ/jxTyj9B9yfhL\nwA0Rx89HsheJzBnPDBPdx7L2kcm0s4LfiV4cH6a97LUSmd/XhNrrRxOyMv52g6QbK5qWs6yx50Lg\n7ozbsojrZO3fZchflux5OAX485KulZs3AP/L2E6SNQOtpX0MzXZbs+x7GJk2OwutpZ+45zIBRSeE\ns3/Gvbg+Tdt0vn9w3jY55UpikPSKSq/cQ1o5ZqKljveX1G4Wek3GiSh88PvEL9VeQfTSz4NIdvsn\n5GOY6D6WtY+8Ay0t9yG/n8s7Pj8Z/S+9peP408DfZBE4hkHSjRVNy1nn+JlEnv7dS/LnYUNCDuZN\nONNuiOrYnAP8WwPtl8Uu6PktQKGWzyEHy0XE1yBJ4mlUxCxubf59qKO/lOJa59M2nS9BiuFPcspV\nJr1yD2nl2BXN1JpwYus1GV9BlpXFwD/HnDMTOYl2sjlyQP9linbSJE80ImsfuR85gS9CSymf6fj8\nrSjA4a7QsQXo7xoXBFAFTcvZS+Nnnv7dS/Ln4dfo/ToL6vdRWQ+4Es3KVtfcdtm0CtHdjfw+QOup\nfUgRy8NrwMNEZ6Wdi5aWPpfyWuEcFMso5yV2MdFOlFui7LxRL9RjaA8mZd7DIhSumzZS427aM5Is\ncixHL94fp2ynk7xyliFjkWcEChOezMhEUXcHPw9GTr6dkXpbAtdHXPtZZIFMYjLwVygM2SSTtZ8/\nGvxcAfwe+EHH58tQDpswe6FEflnGkKJjRV1yxlHF+JmXPGNQL8mfh4lI6czrRpGbPrTGdg3lpcyf\nTLlr3p2RHFFbi9uRSXL90LGLkCZY5P4uJbo40xFIwbsytF0TyPRAsB9VvbZlNjyxgExJDJLOnNsr\n95BFjrtoW/7ypD4fqzLOQC+IV2jXNQIldWv1hZkd35mELIJRVVCvQg6O60d8FuZU4E9zyFsGE1Ay\nuV5kmO59LGsfuYrRTs3bor/rHh3Hv017OW8eGt/2QEpr1qzMg2TzZysqZ1HinmvawrVfQP4lWbal\nHdco0r+j5E9b/b2o7Fnep50cSEPOy2eiomVp02unYSXJobxVsD6aEXTOdn9Bu3pqXC6JJD4APJTy\n3Pkkh/a2wtrelFOeNAySP+RwPr1xD1FyTENWgBOC/bjljrqYT30yvg4pFg8y0sK3YyBD5wy39dlL\nREdFLUMe/Md3afMAopO51cFM5Pfww4baT2KY7n0sro9sw8jMwiCF7CnkXxfmePT3mxo6Nhu96Frj\n7Hmhz4YYrSwkMUg2f7Yy5OxG1PMJE/Vcyyxcm0RS/84q/1ip/v51QuNOXT4q70UzxH0oL6nbEWhQ\nu7qk62VhJzR7DLc9D63D34Zkyxsedw1ScuKydoaZ1PEzimXIylPn+nIWeuUeouRo9Y+H0Cwkr5N0\nWdQp4wvIj2wtI82vH0J9OCpd/RLgFuSv1ckQcnI8G/WP8NizEfJ92ZLoZG518AyypiSlBuhVljG6\njyxH1rdLOs7dAfnBDXUcX44ibJ4PHZuPLBM3IL+Q1vWnooi0W4oK3oUy5OxG3PMJs4zRz/UC6sv7\n1K1/55F/AeqHLSvpdahgZi9F385ndKLJytkNOfKUMRvuQ4PhFYxOsV0Fa2jHgIc5Aw3k4eqtm6H7\nvIri5vfv0N2EOwM57D6CnsMLwB3IXNbJncDXCsqTxCDZZxa9cg9JcpyCfI4+Q3OZnJuU8Si0ZHsJ\nMhN/lfikUz9AeRO6sQsymd+FfFkuQ/2sVxxoh5oWIIZhuvexqD6yEI1JD3cc3x85q07uOD5EdA2l\ny9BMfoD2/9feKIdJVgZJP1aUIWeL/ZAl5i/RxBnin0+YbmNPHRYViO/feeSvu/p72mWmMJ+gZsWp\n9SCj1qyj6EP/lFPRLGsblNjnWOCzwM8Yub6Vpix7XpYiB6ZlFbYRx56UYz2YgcyhVTsmDlJdh63r\nHkwxFqEBs/OlMtYYalqAGIaJ72NJfeSMCuRZQz4fgkHqz0w7nbZD+EaMVrDink/Sc61LUUkir/xQ\nbfX3PMtME4nOw1QZc9DAlcahJs92X4Wyz0R/3CGaUVQAvkG+hDeH0I6XPwKtb+YpC56FtShKpSya\nuAdTjCuoxl8sr9NmXoZqaicrw4x8KWbpI2fFHC/CPSgqLCtljxVpmIKe330om+2cjs/DzyfLc+0V\nRSWv/FVXf98O+aW1lplm0D1PGChAoMrAj1F8Fq2fVbVVmdzqVBRKPURzisrGyJQeFaocxyL0j7AK\nKVsPUc1sqkrWhXsYb+yPwqCrYojsTptF2upFhmm/FLP0kV1R6YIy2Zj2ckOZwRFV0YeUlQNRYc/w\niz38fLKOPb2gqOSVv47q73mWma5gdDShiWB/2v40QzSnqICWzrLMJKch/5bzUPjq0VUIVTHrwj2M\nJzZCzoVV5WSaihJXdYtsKIMpaCnjcRT9M6X76bUzTPtlkraPTEQOwmXPmA8Gvoiywq4o+dplMx+l\nkWgtSb6T9oy98/lkHXuaVlTyyr8UKSlzg+1AFCBSNUnLTAtoF18dQd1lzXudTZE/zb8E+0PICWio\nGXGMGffsjZZh9474bDbKo7QURRMtRP4I89HS6VxkBn8WmfzLool2h9Gkabik6xVhaxQyfD968TRe\nOK4L05Bi8kuUVmIqqoHTLYdHEq1Ce+9HzuVpCu31CgvQsl2nJWwm1Ua8HYP6xErin/0nkYIVlfrA\nhDgaFYD722B7BJm092lSKGPGMd2cNo9FodoPovV40MvoRdozxIXAj0qWqYl2h2l+mcGYPKRZZpqE\nQqVNDoZpdunHmPFON6fN6SiC4FehYzsxMtfEkYSKm3UhS/bMMttNyzBWVMzYI+0y0yFE52YC6q/1\nM1bYHJmb56LS4tOAbzYqkTHjj41RpMADRNcVeg44CDlIttgdrdO3OBwVaJuFEtetQnloVnVcqx9l\n/2z5pnSrRZan3aI8QnnJMo2pgwXovRm1zNTJMuAjWRtYixzKjDGmKaKcNlegzKMtLmZkva+baVtB\nZ6GsnJPQhAOkoLTyL4WvtR+wRfD714I2wxRt1xhTMvOo3ss+D7XGVxtjGmVrpBCcSjsj56WoDkiL\n7wGbBL/3Ib+QVoTHFOTcehztbNHX0g4iCF/rJJRaHGRN6cyQXLRdUJbu3ZAfXLeSEcaYMcxA0wIY\nYxonb8X0uUjxibrWerSLKV6PIgDLarfFahTZUGcVbmPGPJ0+KoeiDrsEzQZazEazmm7hzK+g5DIv\n00z4XlOhisaY+uhHETZ52AspIfOA/+641ovBtitKR/BIie2CfFpuRH4mf4fyeRhjMrIY1ZiZADxW\n8FpVhe8NNNCmMaZ3OIz8JemPRMXs5sdcaybw8QraBdUsOwyVxYjKCWOMSUFrvXUHVKm1CGWE781B\nZtKzQtttHfunl9ymMWb8cgKa7EwifSFVY0zFhJd+Hg1+Lgdu6ThvA1RqOu3STxnhe48jp7MwA8Rb\nVZoIGTTGrBscjiZGZ6Blnl2bFccY042rKad+Q56wwY8mXHOg5DaNMcYY08NM6NjvB94G3FHCtbcG\nbgh+70PFy24P9l8I2jgK+FboO0VT6OZp0xhjjDFjhB1RfoAmCOc3iGNlBe06t4ExxhjTo0xAL+cL\nkDPq4bQrB9fJXOAJkitanl1B23siX5YrkX+NMcYYY3qEfuS78UGksDxHM+WqDwF+inKcPFNjuwcF\n7d6PLCqOCDLGGGN6iInAk8DbG5bjVWTRSVr6KZvHgS2RwnZhzW0bY4wxxhhjjDHGGGOMMcYYY4wx\nxhhjjDHGGGOMMcYYE83/AYh0fTKA9a30AAAAAElFTkSuQmCC\n", "prompt_number": 49, "text": [ "\n", " l + 1/2 \n", " _____ \n", " \u2572 \n", " \u2572 2 \u239b 2 2 \u239e j,m_l + m_s \n", " \u2572 \u210f \u22c5\u239d4\u22c5j + 4\u22c5j - 4\u22c5l - 4\u22c5l - 3\u23a0\u22c5C \u22c5\u2758j,m_l + m_s,j\u2081=\n", " \u2572 l,m_l,1/2,m_s \n", " \u2571 \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " \u2571 4 \n", " \u2571 \n", " \u2571 \n", " \u203e\u203e\u203e\u203e\u203e \n", "j = m_l + m_s \n", "\n", " \n", " \n", " \n", " \n", "l,j\u2082=1/2\u27e9\n", " \n", "\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n", " \n", " \n", " \n", " \n", " " ] } ], "prompt_number": 49 }, { "cell_type": "markdown", "metadata": {}, "source": [ "This gives us the modification of the angular part of the spin-orbit Hamiltonian. We see there is now the new $j$ quantum number in the coupled states, which we see from looking at the equation will have values $l\\pm \\frac{1}{2}$, and $m_j=m_l + m_s$. We still have the $l$ and $s$ quantum numbers." ] } ], "metadata": {} } ] }sympy-sympy-1.9/examples/notebooks/trace.ipynb000066400000000000000000000152241412543434000217110ustar00rootroot00000000000000{ "metadata": { "name": "trace" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "code", "collapsed": true, "input": [ "from sympy import symbols\n", "from sympy.core.trace import Tr\n", "from sympy.matrices.matrices import Matrix\n", "from IPython.core.display import display_pretty\n", "from sympy.printing.latex import *\n", "\n", "%load_ext sympyprinting" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 2 }, { "cell_type": "markdown", "metadata": {}, "source": [ "###Basic Examples" ] }, { "cell_type": "code", "collapsed": true, "input": [ "a, b, c, d = symbols('a b c d'); \n", "A, B = symbols('A B', commutative=False)\n", "t = Tr(A*B)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 3 }, { "cell_type": "code", "collapsed": false, "input": [ "t" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\mbox{Tr}\\left(A B\\right)$$" ], "output_type": "pyout", "prompt_number": 4, "text": [ "Tr(A\u22c5B)" ] } ], "prompt_number": 4 }, { "cell_type": "code", "collapsed": false, "input": [ "latex(t)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 5, "text": [ "\\mbox{Tr}\\left(A B\\right)" ] } ], "prompt_number": 5 }, { "cell_type": "code", "collapsed": false, "input": [ "display_pretty(t)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "display_data", "text": [ "Tr(\u03c1((\u27581,1\u27e9, 0.5),(\u27581,-1\u27e9, 0.5)))" ] } ], "prompt_number": 14 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using Matrices" ] }, { "cell_type": "code", "collapsed": true, "input": [ "t = Tr ( Matrix([ [2,3], [3,4] ]))" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 15 }, { "cell_type": "code", "collapsed": false, "input": [ "t" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$6$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAAAwAAAASCAYAAABvqT8MAAAABHNCSVQICAgIfAhkiAAAAO5JREFU\nKJHN0r1KQ0EQhuHnhAgBhaiIFpLOxs5O8CIsFG/A1spCL0CwsUtnaat4C7aWNooiCAEJKBb+oMGg\nSCzOHlyWlWDnV+3M7vvN7O7wRxWZXAs7+MIL3rCHXs5gGh0shXgS19isDtQSYB9tnIa4jgZec+5r\n+MD4sHtUOsTlsEP1aL2AeyxiGbNoYgs3KTiqfJVzbET5FTxhLgVmMEAfY1G+FqoepcBIAC4ybZ8p\n/6KoHOATd6F8ql5oeSIG4ARTGaCBLh7TjVW8V05BBZ5xkDECx9j1M2PruIpN0uFrYhvzofcH5ajc\n/lbhH+gb6f4rZTpaz0QAAAAASUVORK5CYII=\n", "prompt_number": 16, "text": [ "6" ] } ], "prompt_number": 16 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Example using modules in physics.quantum" ] }, { "cell_type": "code", "collapsed": true, "input": [ "from sympy.physics.quantum.density import Density\n", "from sympy.physics.quantum.spin import (\n", " Jx, Jy, Jz, Jplus, Jminus, J2,\n", " JxBra, JyBra, JzBra,\n", " JxKet, JyKet, JzKet,\n", ")" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 7 }, { "cell_type": "code", "collapsed": false, "input": [ "d = Density([JzKet(1,1),0.5],[JzKet(1,-1),0.5]); d" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\rho\\left(\\begin{pmatrix}{\\left|1,1\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}{\\left|1,-1\\right\\rangle }, & 0.5\\end{pmatrix}\\right)$$" ], "output_type": "pyout", "prompt_number": 8, "text": [ "\u03c1((\u27581,1\u27e9, 0.5),(\u27581,-1\u27e9, 0.5))" ] } ], "prompt_number": 8 }, { "cell_type": "code", "collapsed": true, "input": [ "t = Tr(d)" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 9 }, { "cell_type": "code", "collapsed": false, "input": [ "t" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$\\mbox{Tr}\\left(\\rho\\left(\\begin{pmatrix}{\\left|1,1\\right\\rangle }, & 0.5\\end{pmatrix},\\begin{pmatrix}{\\left|1,-1\\right\\rangle }, & 0.5\\end{pmatrix}\\right)\\right)$$" ], "output_type": "pyout", "prompt_number": 10, "text": [ "Tr(\u03c1((\u27581,1\u27e9, 0.5),(\u27581,-1\u27e9, 0.5)))" ] } ], "prompt_number": 10 }, { "cell_type": "code", "collapsed": false, "input": [ "latex(t)" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "pyout", "prompt_number": 11, "text": [ "\n", "\\mbox{Tr}\\left(\\rho\\left(\\begin{pmatrix}{\\left|1,1\\right\\rangle }, & 0.5\\end{p\n", "matrix},\\begin{pmatrix}{\\left|1,-1\\right\\rangle }, & 0.5\\end{pmatrix}\\right)\\r\n", "ight)" ] } ], "prompt_number": 11 }, { "cell_type": "code", "collapsed": false, "input": [ "t.doit()" ], "language": "python", "metadata": {}, "outputs": [ { "latex": [ "$$1.0$$" ], "output_type": "pyout", "png": "iVBORw0KGgoAAAANSUhEUgAAABsAAAASCAYAAACq26WdAAAABHNCSVQICAgIfAhkiAAAASNJREFU\nOI3t1EErBGEcx/HPimLXgUiU5eKinGxyc8KLkLeDK+WqpChcpJQjBxc33JALsgfFwYrEOsws0za7\nBpOT3+U/z/eZZ77PMzPPwx8mU4P3Yg8DCZ/TjDlkUQzbqziuNyiHSZyinFAEy1iLtMdxja5aAwax\nhVkcfEPWjxdMVPErrCSdaVLZPB4Fry6aJdyioQIa/D4FXOKpip+jA0NpyrrxEMNLYe1JW1aK4RXW\nlqbsGW8xvCmsH31pyE5q8FxYb9KUHaM9hreGtZi2LB/DR3Av+FN/JcujJbw+EqxsNNLfiDEsCr5p\n3WwLNnXccVPAK3bDdgab2PA5+SnBduisJejCPs5CURl3OMR05L4+XGAmwrKCk2QdC9jB8Fcr+s+P\n8g572TfbrLZhHwAAAABJRU5ErkJggg==\n", "prompt_number": 12, "text": [ "1.00000000000000" ] } ], "prompt_number": 12 }, { "cell_type": "code", "collapsed": true, "input": [], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 12 } ], "metadata": {} } ] }sympy-sympy-1.9/github_deploy_key.enc000066400000000000000000000104701412543434000201220ustar00rootroot00000000000000gAAAAABXxcoOhAJRbALiLq2jFDblPXF8AEDdaE2Vi1kUL6ulzwEoVjR85pcVADZrFbYTInABg9FieiG7wbpxMmsJkA-IAsna8K-HS-mB0qFAqx7OYlOsbKKen2S5hY58DLT8hrqJPvZUULoxWQFrEiWbXMykWqraMbQLF6ZAP-fDgrntl8e7UUFF3698PQ4Wjaaf8lLCbPmWFpRfWzfCq0IGw2j4uglxWyOiKgPOrQ4Virbno_cYq1bhJJwe3lHHIfAF-aoBkHaviyM1rF3uEHMzMspu6oUSIWnWi1dA_y_SWxdjLrDCAU8PmoyB4FtE0V85JUX5tSpZGsnwNGghrXO5vCHCnzbZaqPHvP7Tcm2mXuaVl0kb3GD3LYQTnbez-NhJ_nezL2Npjg5WhTh5F1Ny8_a3LxznK7igI134OW8Mhhb9OI_3-bDYXgZSkklBIOAVBz1ppknZQhznoc77wlROOxkw6AzusKpF0t7i7Eujbu0Gx9KV9PlqttUS83wFPoTbjMgY1i-nyGlyxefmUyS3PIAz41fJ5uhBE3YCtWcKI7EVNHJKjbODicw__zDXwKsXsUucxF8Kyf2ryZXLX6BSJJl2fA_hpGg-M5W6j61AEKMVN1t4fVkZ7OcVtb01iVosjSgiNONfSwqPiyPZa6PgtBUHJK8-SpCdV4FK0PNJm1-ZWs9CAR_jPfyjs8oAn_brNGrcXbGSu_3yhQQ0nefru0p8FwFUskdT27Ko9NgzHLDQtsWthCg75-_AQ07oKt56ChQchUs5itlefx7zVNQqwD6XieEgofpDDA0KCxDdAwRJhSo-LbpCC0iKSAgNdAAD662WvaLUZ0kAKAcxZjLL2UHIWObof1DC4jvj4kigofhdEDkhLclymfVW71ec8HnJr7OTzomXdF8b4d6iqN0ozDglrBEfZu1g2WDCBBbibHVQN3Zctucp4o3Hi92IdvkFdV6ENE4XQXWYKhiTC44XiYqoxjQfAK8AFT2JgChJIzk1wQpVnheAar8xjx6Su7eBNYkH_UNP3-NX1aj_ZoklXHD8KuBsWde2V2Vz-m_yBum-7xUmZm0hmht_XMQWk7smYAuu31iK-JeCGtVNAU62_xRY2crv4qFSSJTGe5pwPKXJQSmtkChsaKTgW2D7nBBbXQIr_cWGwbAxuvIvnv50mBHvjtBPTWnp9eX1AsPV2vZn05on8YJ5wwD_Q5oBSQiWP06GDSrFPJp9zl1UJx0cvOzUE7UNfJRx_MxIcEm6HqtuIwhf7wxpsB37bZXFCDCXvMAYHdHucsmy43vVJ2O7UlWz9OAGTDtYvsbRCOkVTIHtlSvI1i8ffyCTDW7Dga86UPq0J_0e8hg-FDd5ymJvIcAV-PzWPAzeU-5FOd9nYgwu3T2T8fOXsLPvYg56dD9qSAiHXJF2U6KhX0Ne0mG2GzGev5FSgypkKtSEdSyUq2bSy43Szx0rabLF3Q98m0NdIy5xQPtMTSi28hliKNdfDTV0GwvLJ32A78jWQNzbm0fYPLWqdtJtVuNrh5JW6C9qfe2fQjJuG76I1s76TzhCpg2JPCiV_buq0Y38lA2OetAAz5UbftK_jfw8eBGxAY8yPnZEeu7-negjg2AXZMZLaTWmPz21APQY-E32KzJmQBTyVoGLs4HpyuGIWcpqwd2TV17lv_scB5DYlWbUtmPmlE8EeNN_s0IFoMUTJ6OOxoN69zuuRcYe8igzpDTmQFKAaN8tSlKO9-ZXpvHIIUztrl270jp_fXXrg5Ux_7wAADjbvUFRzUi-Rg93aEGrDx0CqBrS1B3u5ADNMTgX_kM-flRyV87_nLdhLIfrPyljbM8hj5bAqeuv9unpkt0Ctr0qU_Y3PcmcaiMChJqnvx5OSxeq18wLSaL6wLCZhnuQvUtyhSUCedV5kuQbhcvC0z8xolh8ioYmMAivl3aw7t9Spsq3S-BPhxEwpRY_88c5ws1EI_lUx1ulGXyNzRw0lFuEP6yjIUxeo2AweO2rdMJSuizEZsDOP9XNf6PHFdTldviJKhYbRXKH6SrzKUTM6UQwiAlu02zov6O3ssF6oYEMxVcmprNB3jhW3pG_hXs55VPEXogXRbrmY9NygE5q2hAGgf4U6K7ynvVi9e0fnaSECUeb_c1CXqodmpdqvb8vB0fm73U6M-9ilkhejqo79E6iMvDMAUz9Zf8me468e9nwVlpRmLZkJRNcDkEH18wu8TveC4uxL8zHbvIeZz0JAbVbie-_jWXPEAX_-YZGE7TkgmFovU7mGPlMor4IgFr9nHEdfQkyuga8SbghF_ol6ukuT3tEt2xyLLo33wJSAEOBKkPPNeaSr7PRm9M0BaUqAtc_nj71gizCfZBhTdg0y1Ap8Nitur7jMhEzTZI2bzVhd6e3-xxsiwMD7msiu9tTSdzP16HpLD-X2uAjdzgrenKBb1p0o6TY5v7PRusL3ZKhd7K57V2kDxITaRFqniFxN0dBuop_7mSjz5LbiqNC3o9N5f8XYaD76VMw_k3CQziqY5s16eZ63Pp6kOOaGoK7rJLh0uYNnF7baxeo8ovM2mNcsiZYnMGc8EJTodYcudSRaaOIjuNsx6UnT3J-544MtviG5pAH8a_LcTAGFdRaI0EAVdAVCplk6cS1x57oK73VeCtZJIVY5VGyfNNot867yl6F-dVgsXOcbKbVvg1RCeUUJ6gp1j3BNdubdoh8t8OLUcUwiGadTOvkN1OKSDiw1TtrmYvm8M4jl9IDIwz-EgwDHJfRp54V9EAYsRDnmhd4BMc-QqViOZcZzUdVV_0-b0PqJRoLsA8Wng7itHcdyU2d36HKc3m7BDi66FgT1YX70OtNuJppwjyLEt9t0Q-Gwb9zyoVJIw-J3xMM__ncuboXRXi0UyefSyPIMHJDpKCmjHQlUe2rqELEuB2XfKpsgAGIJPWXtzhMrQmsqXMZR1r5R6IWwaY80djY3EoMxD24-MVrBCWngKhmmcYNGy58tbvfPzbIbfes17WYzP6Ee0u8-qOBoz3_-BkKV0OlHJg4vP-qs9MyWwjnweY3d1DN9GSoKtfYTaAsocIO4Y_2wp_rue2lHtw-DJUeU-opmzFyf3W4R7WKpmXGyJWejB9ijtMlLgpwXRe9ndhwdemAG5jKtPcOaP-c0Mstk8VVYXYoXwaQ1VWLau7Q-NGMt1q3BF9sDWXmW3_Nbie5kS8DzVJN-hQBXFf3fHbNRKYGWgr3t0dOa5yiazBD7wV7QUVlPzr8hpkpXPREVJyZWiN6z7Txcd3ZhPlRtW6G2VtEJSVeVfTetlGX347ZUCtWBVmO2U6FqYg3de53vzslicug8tR3_Wrlsbnuuz27VS4R-5t1Ckwaf6EP2q5hyOc4AzWcTPxtm1LRumO_b47i36kwDYzaG5toYiloR0IE_4P9dpnEbUPc971r1V6H5suG1I3dICo74afik8jN7_AU9FrQdqzaXPa-BEh252bNhelWZZmEGIVzwqwAUbvbb1pRYWa9BhmsYivxgl5XU5_UXpM8s6t6IRy2D9PTr0Al4Emj_7W07Wq6iWHHkvBjT2Eye4SfOC9_viJmTeps3XPYXYyQKTctbdRc4w5zQL6zvtfVrG6jcR9OZt2b1lHKYStxQaVtJmauiVYwlkA9Q52DcYbIETGJGBeMClZMHBpiStURLyI6mtHPpYttA0pZR2jwjc1co9szhPPGYO3jHv0PjhGz8rgUaHYn9dYgmgfyYpsIRfJZz2IZhz6i9ir6dp-KlObMAbmXGkgtw2yXx95Aj1fOwtmSWXXkbjCH6WSk4evBcUR7NZpM_8tFfbbELkONva5dRSc_Q_Z3NFyPtW68Dz3TmTzDyFX1-B6ysHxuG3OlnE1f1ZAPpKpeoiZ4uMmNQ2Geuj8W7sDazKi88sR-Oj_ynk319XyzQbyoRFeEIII5KQANnLPSbxRQIvD_87mYH8QVKngjTAsNTv-LCMPOaLgqcv6dB9ATIp9vxz6JfEJwORRZ1XqTpOWsj9OslTq56AnsmwQTxAQm2lAYiCSaRWR9x9wSPaz6O6Qa-VYmoEjuvaOlHN32VSRAwK0t2Wcm2a_O7PT0N4tg9s-z1S48fhmGMePqfZZrYX3x-dr6mKd8WDwKf1YY6yAv6Tk4H1hhyEwPeZPq36_5gzw0haY0PK9xuKAAn4MKCY468zr-9kuI7l-nFVQHz3O62aa_CDNYh5DEbnd0q7Oi3LTfAdcsYNnpXc2AbrAkSCI9fOV1DoRiR-Tr77zERvs5J2xIo_k0TSzaBrA4zpslVMo1BLxKbvTQ7bjw8UEsEKln1UVP8dDbjckZ4NN0RZMM3qv2hpN2D4tx_SghjjpRsqRQ7TZEOJMEgVrKgo3hT1ZDeBJSHJRqriF_XyphshcqdGRGU82ADKHuPdjkL6cuS1M=sympy-sympy-1.9/isympy.py000066400000000000000000000256771412543434000156500ustar00rootroot00000000000000""" Python shell for SymPy. This is just a normal Python shell (IPython shell if you have the IPython package installed), that executes the following commands for the user: >>> from __future__ import division >>> from sympy import * >>> x, y, z, t = symbols('x y z t') >>> k, m, n = symbols('k m n', integer=True) >>> f, g, h = symbols('f g h', cls=Function) >>> init_printing() So starting 'isympy' is equivalent to starting Python (or IPython) and executing the above commands by hand. It is intended for easy and quick experimentation with SymPy. isympy is a good way to use SymPy as an interactive calculator. If you have IPython and Matplotlib installed, then interactive plotting is enabled by default. COMMAND LINE OPTIONS -------------------- -c CONSOLE, --console=CONSOLE Use the specified shell (Python or IPython) shell as the console backend instead of the default one (IPython if present, Python otherwise), e.g.: $isympy -c python CONSOLE must be one of 'ipython' or 'python' -p PRETTY, --pretty PRETTY Setup pretty-printing in SymPy. When pretty-printing is enabled, expressions can be printed with Unicode or ASCII. The default is to use pretty-printing (with Unicode if the terminal supports it). When this option is 'no', expressions will not be pretty-printed and ASCII will be used: $isympy -p no PRETTY must be one of 'unicode', 'ascii', or 'no' -t TYPES, --types=TYPES Setup the ground types for the polys. By default, gmpy ground types are used if gmpy2 or gmpy is installed, otherwise it falls back to python ground types, which are a little bit slower. You can manually choose python ground types even if gmpy is installed (e.g., for testing purposes): $isympy -t python TYPES must be one of 'gmpy', 'gmpy1' or 'python' Note that the ground type gmpy1 is primarily intended for testing; it forces the use of gmpy version 1 even if gmpy2 is available. This is the same as setting the environment variable SYMPY_GROUND_TYPES to the given ground type (e.g., SYMPY_GROUND_TYPES='gmpy') The ground types can be determined interactively from the variable sympy.polys.domains.GROUND_TYPES. -o ORDER, --order ORDER Setup the ordering of terms for printing. The default is lex, which orders terms lexicographically (e.g., x**2 + x + 1). You can choose other orderings, such as rev-lex, which will use reverse lexicographic ordering (e.g., 1 + x + x**2): $isympy -o rev-lex ORDER must be one of 'lex', 'rev-lex', 'grlex', 'rev-grlex', 'grevlex', 'rev-grevlex', 'old', or 'none'. Note that for very large expressions, ORDER='none' may speed up printing considerably but the terms will have no canonical order. -q, --quiet Print only Python's and SymPy's versions to stdout at startup. -d, --doctest Use the same format that should be used for doctests. This is equivalent to -c python -p no. -C, --no-cache Disable the caching mechanism. Disabling the cache may slow certain operations down considerably. This is useful for testing the cache, or for benchmarking, as the cache can result in deceptive timings. This is equivalent to setting the environment variable SYMPY_USE_CACHE to 'no'. -a, --auto-symbols (requires at least IPython 0.11) Automatically create missing symbols. Normally, typing a name of a Symbol that has not been instantiated first would raise NameError, but with this option enabled, any undefined name will be automatically created as a Symbol. Note that this is intended only for interactive, calculator style usage. In a script that uses SymPy, Symbols should be instantiated at the top, so that it's clear what they are. This will not override any names that are already defined, which includes the single character letters represented by the mnemonic QCOSINE (see the "Gotchas and Pitfalls" document in the documentation). You can delete existing names by executing "del name". If a name is defined, typing "'name' in dir()" will return True. The Symbols that are created using this have default assumptions. If you want to place assumptions on symbols, you should create them using symbols() or var(). Finally, this only works in the top level namespace. So, for example, if you define a function in isympy with an undefined Symbol, it will not work. See also the -i and -I options. -i, --int-to-Integer (requires at least IPython 0.11) Automatically wrap int literals with Integer. This makes it so that things like 1/2 will come out as Rational(1, 2), rather than 0.5. This works by preprocessing the source and wrapping all int literals with Integer. Note that this will not change the behavior of int literals assigned to variables, and it also won't change the behavior of functions that return int literals. If you want an int, you can wrap the literal in int(), e.g. int(3)/int(2) gives 1.5 (with division imported from __future__). -I, --interactive (requires at least IPython 0.11) This is equivalent to --auto-symbols --int-to-Integer. Future options designed for ease of interactive use may be added to this. -D, --debug Enable debugging output. This is the same as setting the environment variable SYMPY_DEBUG to 'True'. The debug status is set in the variable SYMPY_DEBUG within isympy. -- IPython options Additionally you can pass command line options directly to the IPython interpreter (the standard Python shell is not supported). However you need to add the '--' separator between two types of options, e.g the startup banner option and the colors option. You need to enter the options as required by the version of IPython that you are using, too: in IPython 0.11, $isympy -q -- --colors=NoColor or older versions of IPython, $isympy -q -- -colors NoColor See also isympy --help. """ import os import sys # DO NOT IMPORT SYMPY HERE! Or the setting of the sympy environment variables # by the command line will break. def main(): from argparse import ArgumentParser, RawDescriptionHelpFormatter VERSION = None if '--version' in sys.argv: # We cannot import sympy before this is run, because flags like -C and # -t set environment variables that must be set before SymPy is # imported. The only thing we need to import it for is to get the # version, which only matters with the --version flag. import sympy VERSION = sympy.__version__ usage = 'isympy [options] -- [ipython options]' parser = ArgumentParser( usage=usage, description=__doc__, formatter_class=RawDescriptionHelpFormatter, ) parser.add_argument('--version', action='version', version=VERSION) parser.add_argument( '-c', '--console', dest='console', action='store', default=None, choices=['ipython', 'python'], metavar='CONSOLE', help='select type of interactive session: ipython | python; defaults ' 'to ipython if IPython is installed, otherwise python') parser.add_argument( '-p', '--pretty', dest='pretty', action='store', default=None, metavar='PRETTY', choices=['unicode', 'ascii', 'no'], help='setup pretty printing: unicode | ascii | no; defaults to ' 'unicode printing if the terminal supports it, otherwise ascii') parser.add_argument( '-t', '--types', dest='types', action='store', default=None, metavar='TYPES', choices=['gmpy', 'gmpy1', 'python'], help='setup ground types: gmpy | gmpy1 | python; defaults to gmpy if gmpy2 ' 'or gmpy is installed, otherwise python') parser.add_argument( '-o', '--order', dest='order', action='store', default=None, metavar='ORDER', choices=['lex', 'grlex', 'grevlex', 'rev-lex', 'rev-grlex', 'rev-grevlex', 'old', 'none'], help='setup ordering of terms: [rev-]lex | [rev-]grlex | [rev-]grevlex | old | none; defaults to lex') parser.add_argument( '-q', '--quiet', dest='quiet', action='store_true', default=False, help='print only version information at startup') parser.add_argument( '-d', '--doctest', dest='doctest', action='store_true', default=False, help='use the doctest format for output (you can just copy and paste it)') parser.add_argument( '-C', '--no-cache', dest='cache', action='store_false', default=True, help='disable caching mechanism') parser.add_argument( '-a', '--auto-symbols', dest='auto_symbols', action='store_true', default=False, help='automatically construct missing symbols') parser.add_argument( '-i', '--int-to-Integer', dest='auto_int_to_Integer', action='store_true', default=False, help="automatically wrap int literals with Integer") parser.add_argument( '-I', '--interactive', dest='interactive', action='store_true', default=False, help="equivalent to -a -i") parser.add_argument( '-D', '--debug', dest='debug', action='store_true', default=False, help='enable debugging output') (options, ipy_args) = parser.parse_known_args() if '--' in ipy_args: ipy_args.remove('--') if not options.cache: os.environ['SYMPY_USE_CACHE'] = 'no' if options.types: os.environ['SYMPY_GROUND_TYPES'] = options.types if options.debug: os.environ['SYMPY_DEBUG'] = str(options.debug) if options.doctest: options.pretty = 'no' options.console = 'python' session = options.console if session is not None: ipython = session == 'ipython' else: try: import IPython ipython = True except ImportError: if not options.quiet: from sympy.interactive.session import no_ipython print(no_ipython) ipython = False args = { 'pretty_print': True, 'use_unicode': None, 'use_latex': None, 'order': None, 'argv': ipy_args, } if options.pretty == 'unicode': args['use_unicode'] = True elif options.pretty == 'ascii': args['use_unicode'] = False elif options.pretty == 'no': args['pretty_print'] = False if options.order is not None: args['order'] = options.order args['quiet'] = options.quiet args['auto_symbols'] = options.auto_symbols or options.interactive args['auto_int_to_Integer'] = options.auto_int_to_Integer or options.interactive from sympy.interactive import init_session init_session(ipython, **args) if __name__ == "__main__": main() sympy-sympy-1.9/pytest.ini000066400000000000000000000014541412543434000157600ustar00rootroot00000000000000[pytest] # Only run tests under the sympy/ directory. Otherwise pytest will attempt to # collect tests from e.g. the bin/ directory as well. testpaths = sympy doc/src # np.matrix is deprecated but still used in sympy.physics.quantum: # https://github.com/sympy/sympy/issues/15563 # This prevents ~800 warnings showing up running the tests under pytest. filterwarnings = ignore:.*the matrix subclass is not the recommended way.*:PendingDeprecationWarning ignore:IPython.utils.signatures backport for Python 2 is deprecated.*:DeprecationWarning # Normalise output of doctests. doctest_optionflags = NORMALIZE_WHITESPACE IGNORE_EXCEPTION_DETAIL ELLIPSIS FLOAT_CMP norecursedirs = sympy/parsing/autolev/test-examples sympy/integrals/rubi/rubi_tests markers = nocache_fail sympy-sympy-1.9/release/000077500000000000000000000000001412543434000153435ustar00rootroot00000000000000sympy-sympy-1.9/release/.gitignore000066400000000000000000000000351412543434000173310ustar00rootroot00000000000000.vagrant release-* venv_main sympy-sympy-1.9/release/Dockerfile000066400000000000000000000016361412543434000173430ustar00rootroot00000000000000FROM continuumio/anaconda3 WORKDIR /root RUN apt-get update \ && apt-get install -y libc6-i386 libc6 linux-headers-amd64 git make zip graphviz inkscape texlive-xetex texlive-fonts-recommended texlive-latex-extra librsvg2-bin docbook2x latexmk libatlas-dev libatlas-base-dev liblapack-dev gfortran gcc \ && apt-get -y clean RUN conda config --add channels conda-forge RUN conda config --set always_yes yes RUN conda install python=3.6 rever requests requests-oauthlib \ && conda clean --all RUN conda info RUN /opt/conda/bin/pip install xonda # Make matplotlib tests work # https://stackoverflow.com/questions/2801882/generating-a-png-with-matplotlib-when-display-is-undefined ENV MATPLOTLIBRC=/root/matplotlibrc RUN mkdir -p $MATPLOTLIBRC RUN echo "backend : Agg" > $MATPLOTLIBRC/matplotlibrc RUN git clone git://github.com/sympy/sympy.git WORKDIR /root/sympy/release ENTRYPOINT ["./pull_and_run_rever.sh"] sympy-sympy-1.9/release/README.md000066400000000000000000000145361412543434000166330ustar00rootroot00000000000000**NOTE: The release script is currently in the process of moving from Vagrant/fabric to Docker/rever. The fabfile.py is left here for reference, but all release processes should be done with release.sh and rever.xsh.** # Release First, make sure that you have done the following things - Create a release branch. Usually this branch is the same name as the release (e.g., "0.7.3"), although no naming convention is enforced on it. - Change the version in the release branch in sympy/release.py. If you want to do a release candidate, change it to a [PEP 440](https://www.python.org/dev/peps/pep-0440) compliant version like 0.7.3rc1. Note that setuptools normalizes versions like 0.7.3.rc1 to 0.7.3rc1, so there will be errors if you do not use the latter form. - Change the version in master. This way, any additional changes made in master will be shown as coming from the right place. The master release should be e.g. `0.7.4.dev`, see [PEP 440](https://www.python.org/dev/peps/pep-0440) for rules about development version numbers. Note that this version number should the next projected version plus the `.dev`. - Push the release branch up to origin, and make a pull request for it against master. - Create the release notes page for the new release on the wiki. See https://github.com/sympy/sympy-bot/issues/26. The easiest way to do this is to copy the old release notes to a new page and remove all the changes, and update the version number. The formatting on the release notes page is important as otherwise the bot will fail, so it is best to do it this way. It is important to create a new branch because that lets master continue as normal. The release script will automatically checkout the release branch from origin, which is why you need to push it (it determines what the release branch by just looking at what branch you have checked out locally, so make sure you are on the release branch when you release). It is important to change the version number because it uses that in naming the tarballs it creates. Next, make sure you have Docker installed. **TODO: Fix the release script to pull sympy/sympy-release from Dockerhub.** Once you have done these things, execute: ./release.sh where `` is the release branch (e.g., `0.7.3`), and `` is the release version (e.g., `0.7.3rc1`). On Linux, you may need to use `sudo` to execute this. This will run all the release scripts. If they are successful, they will create release tarballs and put them all into a new "release-VERSION" directory of the current directory. Most likely they will fail the first time, in which case you will need to investigate why and fix things (e.g., update authors, run tests, update whitelists in `rever.xsh`, fix setup.py). The whole script can take about an hour or so to run (depending on how long the tests take). Every time you re-run the script, it pulls from the branch and runs everything from scratch. At the end it will print two things, the list of authors, and the sha256 sums. Copy the list of authors into the release notes. You should verify that the sha256 sums of the release files are the same as what are printed. # Tagging the release Once you have made the final release files that you plan to upload, be sure that everything is committed, and that the most recent git HEAD is indeed the same one that was used to build the files (you can always run the release script again if you are not sure). Then tag the release with the command git tag sympy-VERSION -a where you should replace `VERSION` with the version (which should be `x.y.z`, or `x.y.zrcn` for the `n`th release candidate. It is very important to follow the tag naming conventions. The `-a` will cause it to prompt for a tag commit message. Just write something like "SymPy VERSION release". Then, push up the tag, with git push origin sympy-VERSION Note, once a tag is pushed, that's it. It can't be changed. If you need to change the tag, you must bump the release number. So double check that everything is right before pushing. # Uploading **WARNING: This stuff does not fully work yet. Some development on `rever.xsh` may be required.** Before you release, you need to push the tag up, as described above. Release candidates should be uploaded to GitHub only. rever VERSION -a GitHub_release This will create the release on GitHub for the tag, and upload the files to it. Do not upload release candidates to PyPI, as `pip` and `easy_install` will pick them up if you do. This will prompt you for a username and password the first time you call it. After that, it will prompt you to generate a token file. If you don't save the token to a file, you will need to pass it in as an argument. Releasing is only supported via OAuth, so using a token is required. You (obviously) need push access to create a GitHub release. For final releases, you should upload to both GitHub and PyPI. The command rever VERSION -a upload will do both of these (**TODO: This function has not been translated from the fabfile yet**). You will need admin access to the SymPy PyPI project. Note that if either of these commands fails for some reason, you will very likely need to go into the web interface and clean some things up before you can upload again. # Updating websites You should now update the websites. Only do this for final releases. The command rever VERSION -a update_websites will update docs.sympy.org and sympy.org (**TODO: This isn't fully translated from the fabfile yet.**). You will need to have local clones of these repos, and push access to them (obviously). **Note, this command will commit and push the changes automatically.** The other website that needs to be updated is SymPy Live. You should make this as a pull request to the Live repo. # Updating the Dockerfile If you change the Dockerfile, you will need to run docker build -f Dockerfile . -t sympy/sympy-release Once you have it working, push the changes up to Dockerhub docker push sympy/sympy-release You'll need access to the sympy org, ask Aaron or Ondřej if you need it. It is usually not necessary to rebuild the Docker container. The container first pulls the latest version of the release branch before running rever (see `pull_and_run_rever.sh`), so unless you modify that script, or change the packages that are installed in the container, it should not be necessary to rebuild it. sympy-sympy-1.9/release/aptinstall.sh000077500000000000000000000013331412543434000200550ustar00rootroot00000000000000#!/usr/bin/env bash set -o errexit sudo add-apt-repository ppa:deadsnakes/ppa sudo apt update sudo apt install\ antlr4\ libgfortran5\ python3-venv\ python3-pip\ python3-gmpy2\ texlive-latex-recommended\ texlive-fonts-recommended\ texlive-fonts-extra\ texlive-xetex\ latexmk\ dvipng\ librsvg2-bin\ imagemagick\ inkscape\ libcanberra-gtk-module\ docbook2x\ graphviz\ gfortran\ # sudo apt install\ python3.6\ python3.6-venv\ python3.7\ python3.7-venv\ python3.9\ python3.9-venv\ # python3.8 is installed by default in 20.04 python3 -m venv release/venv_main source release/venv_main/bin/activate pip install -U pip wheel pip install -r release/requirements.txt pip install -e . sympy-sympy-1.9/release/authors.py000077500000000000000000000133211412543434000174050ustar00rootroot00000000000000#!/usr/bin/env python3 import os from pathlib import Path from subprocess import check_output import unicodedata def main(version, prevversion, outdir): """ Print authors text to put at the bottom of the release notes """ outdir = Path(outdir) authors, authorcount, newauthorcount = get_authors(version, prevversion) authors_text = f"""## Authors The following people contributed at least one patch to this release (names are given in alphabetical order by last name). A total of {authorcount} people contributed to this release. People with a * by their names contributed a patch for the first time for this release; {newauthorcount} people contributed for the first time for this release. Thanks to everyone who contributed to this release! """ authors_lines = [] for name in authors: authors_lines.append("- " + name) authors_text += '\n'.join(authors_lines) # Output to file and to screen with open(outdir / 'authors.txt', 'w') as authorsfile: authorsfile.write(authors_text) print() print(blue("Here are the authors to put at the bottom of the release notes.")) print() print(authors_text) def blue(text): return "\033[34m%s\033[0m" % text def get_authors(version, prevversion): """ Get the list of authors since the previous release Returns the list in alphabetical order by last name. Authors who contributed for the first time for this release will have a star appended to the end of their names. Note: it's a good idea to use ./bin/mailmap_update.py (from the base sympy directory) to make AUTHORS and .mailmap up-to-date first before using this. fab vagrant release does this automatically. """ def lastnamekey(name): """ Sort key to sort by last name Note, we decided to sort based on the last name, because that way is fair. We used to sort by commit count or line number count, but that bumps up people who made lots of maintenance changes like updating mpmath or moving some files around. """ # Note, this will do the wrong thing for people who have multi-word # last names, but there are also people with middle initials. I don't # know of a perfect way to handle everyone. Feel free to fix up the # list by hand. text = name.strip().split()[-1].lower() # Convert things like Čertík to Certik return unicodedata.normalize('NFKD', text).encode('ascii', 'ignore') # The get_previous_version function can be flakey so we require the # previous version to be provided explicitly by the caller. # #old_release_tag = get_previous_version_tag(version) old_release_tag = 'sympy-' + prevversion out = check_output(['git', '--no-pager', 'log', old_release_tag + '..', '--format=%aN']) releaseauthors = set(out.decode('utf-8').strip().split('\n')) out = check_output(['git', '--no-pager', 'log', old_release_tag, '--format=%aN']) priorauthors = set(out.decode('utf-8').strip().split('\n')) releaseauthors = {name.strip() for name in releaseauthors if name.strip()} priorauthors = {name.strip() for name in priorauthors if name.strip()} newauthors = releaseauthors - priorauthors starred_newauthors = {name + "*" for name in newauthors} authors = releaseauthors - newauthors | starred_newauthors return (sorted(authors, key=lastnamekey), len(releaseauthors), len(newauthors)) def get_previous_version_tag(version): """ Get the version of the previous release """ # We try, probably too hard, to portably get the number of the previous # release of SymPy. Our strategy is to look at the git tags. The # following assumptions are made about the git tags: # - The only tags are for releases # - The tags are given the consistent naming: # sympy-major.minor.micro[.rcnumber] # (e.g., sympy-0.7.2 or sympy-0.7.2.rc1) # In particular, it goes back in the tag history and finds the most recent # tag that doesn't contain the current short version number as a substring. shortversion = get_sympy_short_version(version) curcommit = "HEAD" while True: cmdline = f'git describe --abbrev=0 --tags {curcommit}' print(cmdline) curtag = check_output(cmdline.split()).decode('utf-8').strip() if shortversion in curtag: # If the tagged commit is a merge commit, we cannot be sure # that it will go back in the right direction. This almost # never happens, so just error cmdline = f'git rev-list --parents -n 1 {curtag}' print(cmdline) parents = check_output(cmdline.split()).decode('utf-8').strip().split() # rev-list prints the current commit and then all its parents # If the tagged commit *is* a merge commit, just comment this # out, and manually make sure `get_previous_version_tag` is correct # assert len(parents) == 2, curtag curcommit = curtag + "^" # The parent of the tagged commit else: print(blue("Using {tag} as the tag for the previous " "release.".format(tag=curtag))) return curtag sys.exit(red("Could not find the tag for the previous release.")) def get_sympy_short_version(version): """ Get the short version of SymPy being released, not including any rc tags (like 0.7.3) """ parts = version.split('.') # Remove rc tags # Handle both 1.0.rc1 and 1.1rc1 if not parts[-1].isdigit(): if parts[-1][0].isdigit(): parts[-1] = parts[-1][0] else: parts.pop(-1) return '.'.join(parts) if __name__ == "__main__": import sys sys.exit(main(*sys.argv[1:])) sympy-sympy-1.9/release/build_docs.py000077500000000000000000000027271412543434000200370ustar00rootroot00000000000000#!/usr/bin/env python3 import os from os.path import dirname, join, basename, normpath from os import chdir import shutil from helpers import run ROOTDIR = dirname(dirname(__file__)) DOCSDIR = join(ROOTDIR, 'doc') def main(version, outputdir): os.makedirs(outputdir, exist_ok=True) build_html(DOCSDIR, outputdir, version) build_latex(DOCSDIR, outputdir, version) def build_html(docsdir, outputdir, version): run('make', 'clean', cwd=docsdir) run('make', 'html', cwd=docsdir) builddir = join(docsdir, '_build') docsname = 'sympy-docs-html-%s' % (version,) zipname = docsname + '.zip' cwd = os.getcwd() try: chdir(builddir) shutil.move('html', docsname) run('zip', '-9lr', zipname, docsname) finally: chdir(cwd) shutil.move(join(builddir, zipname), join(outputdir, zipname)) def build_latex(docsdir, outputdir, version): run('make', 'clean', cwd=docsdir) run('make', 'latex', cwd=docsdir) latexdir = join(docsdir, '_build', 'latex') env = os.environ.copy() env['LATEXMKOPTS'] = '-xelatex -silent' run('make', 'clean', cwd=latexdir, env=env) run('make', 'all', cwd=latexdir, env=env) srcfilename = 'sympy-%s.pdf' % (version,) dstfilename = 'sympy-docs-pdf-%s.pdf' % (version,) src = join('doc', '_build', 'latex', srcfilename) dst = join(outputdir, dstfilename) shutil.copyfile(src, dst) if __name__ == "__main__": import sys main(*sys.argv[1:]) sympy-sympy-1.9/release/ci_release_script.sh000077500000000000000000000006201412543434000213570ustar00rootroot00000000000000#!/usr/bin/env bash # # Run # # $ release/ci_release_script.sh version prevversion releasedir # # Example: # # $ release/ci_release_script.sh 1.9rc1 1.8 release-1.9rc1 release/aptinstall.sh python3 -m venv release/venv_main source release/venv_main/bin/activate pip install -U pip wheel pip install -r release/requirements.txt pip install -e . python release/releasecheck.py $1 $2 release-$1 sympy-sympy-1.9/release/compare_tar_against_git.py000077500000000000000000000163431412543434000225740ustar00rootroot00000000000000#!/usr/bin/env python3 from subprocess import check_output import sys import os.path def main(tarname, gitroot): """Run this as ./compare_tar_against_git.py TARFILE GITROOT Args ==== TARFILE: Path to the built sdist (sympy-xx.tar.gz) GITROOT: Path ro root of git (dir containing .git) """ compare_tar_against_git(tarname, gitroot) ## TARBALL WHITELISTS # If a file does not end up in the tarball that should, add it to setup.py if # it is Python, or MANIFEST.in if it is not. (There is a command at the top # of setup.py to gather all the things that should be there). # TODO: Also check that this whitelist isn't growing out of date from files # removed from git. # Files that are in git that should not be in the tarball git_whitelist = { # Git specific dotfiles '.gitattributes', '.gitignore', '.mailmap', # Travis and CI '.travis.yml', '.github/workflows/ci-sage.yml', '.github/workflows/comment-on-pr.yml', '.github/workflows/runtests.yml', '.github/workflows/release.yml', '.ci/durations.json', '.ci/generate_durations_log.sh', '.ci/parse_durations_log.py', '.ci/blacklisted.json', '.ci/README.rst', '.github/FUNDING.yml', '.editorconfig', '.coveragerc', 'CODEOWNERS', 'asv.conf.travis.json', 'asv.conf.actions.json', 'coveragerc_travis', 'codecov.yml', 'pytest.ini', 'MANIFEST.in', 'banner.svg', # Code of conduct 'CODE_OF_CONDUCT.md', # Pull request template 'PULL_REQUEST_TEMPLATE.md', # Contributing guide 'CONTRIBUTING.md', # Nothing from bin/ should be shipped unless we intend to install it. Most # of this stuff is for development anyway. To run the tests from the # tarball, use setup.py test, or import sympy and run sympy.test() or # sympy.doctest(). 'bin/adapt_paths.py', 'bin/ask_update.py', 'bin/authors_update.py', 'bin/build_doc.sh', 'bin/coverage_doctest.py', 'bin/coverage_report.py', 'bin/deploy_doc.sh', 'bin/diagnose_imports', 'bin/doctest', 'bin/generate_module_list.py', 'bin/generate_test_list.py', 'bin/get_sympy.py', 'bin/mailmap_update.py', 'bin/py.bench', 'bin/strip_whitespace', 'bin/sympy_time.py', 'bin/sympy_time_cache.py', 'bin/test', 'bin/test_external_imports.py', 'bin/test_executable.py', 'bin/test_import', 'bin/test_import.py', 'bin/test_isolated', 'bin/test_py2_import.py', 'bin/test_setup.py', 'bin/test_submodule_imports.py', 'bin/test_travis.sh', 'bin/test_optional_dependencies.py', 'bin/test_sphinx.sh', 'bin/test_symengine.py', 'bin/test_tensorflow.py', # The notebooks are not ready for shipping yet. They need to be cleaned # up, and preferably doctested. See also # https://github.com/sympy/sympy/issues/6039. 'examples/advanced/identitysearch_example.ipynb', 'examples/beginner/plot_advanced.ipynb', 'examples/beginner/plot_colors.ipynb', 'examples/beginner/plot_discont.ipynb', 'examples/beginner/plot_gallery.ipynb', 'examples/beginner/plot_intro.ipynb', 'examples/intermediate/limit_examples_advanced.ipynb', 'examples/intermediate/schwarzschild.ipynb', 'examples/notebooks/density.ipynb', 'examples/notebooks/fidelity.ipynb', 'examples/notebooks/fresnel_integrals.ipynb', 'examples/notebooks/qubits.ipynb', 'examples/notebooks/sho1d_example.ipynb', 'examples/notebooks/spin.ipynb', 'examples/notebooks/trace.ipynb', 'examples/notebooks/Bezout_Dixon_resultant.ipynb', 'examples/notebooks/IntegrationOverPolytopes.ipynb', 'examples/notebooks/Macaulay_resultant.ipynb', 'examples/notebooks/Sylvester_resultant.ipynb', 'examples/notebooks/README.txt', # This stuff :) 'release/.gitignore', 'release/README.md', 'release/Vagrantfile', 'release/fabfile.py', 'release/Dockerfile', 'release/Dockerfile-base', 'release/release.sh', 'release/rever.xsh', 'release/pull_and_run_rever.sh', 'release/compare_tar_against_git.py', 'release/update_docs.py', 'release/aptinstall.sh', 'release/build_docs.py', 'release/github_release.py', 'release/helpers.py', 'release/releasecheck.py', 'release/requirements.txt', 'release/update_requirements.sh', 'release/test_install.py', 'release/sha256.py', 'release/authors.py', 'release/ci_release_script.sh', # This is just a distribute version of setup.py. Used mainly for setup.py # develop, which we don't care about in the release tarball 'setupegg.py', # pytest stuff 'conftest.py', # Encrypted deploy key for deploying dev docs to GitHub 'github_deploy_key.enc', } # Files that should be in the tarball should not be in git tarball_whitelist = { # Generated by setup.py. Contains metadata for PyPI. "PKG-INFO", # Generated by setuptools. More metadata. 'setup.cfg', 'sympy.egg-info/PKG-INFO', 'sympy.egg-info/SOURCES.txt', 'sympy.egg-info/dependency_links.txt', 'sympy.egg-info/requires.txt', 'sympy.egg-info/top_level.txt', 'sympy.egg-info/not-zip-safe', 'sympy.egg-info/entry_points.txt', # Not sure where this is generated from... 'doc/commit_hash.txt', } def blue(text): return "\033[34m%s\033[0m" % text def red(text): return "\033[31m%s\033[0m" % text def run(*cmdline, cwd=None): """ Run command in subprocess and get lines of output """ return check_output(cmdline, encoding='utf-8', cwd=cwd).splitlines() def full_path_split(path): """ Function to do a full split on a path. """ # Based on https://stackoverflow.com/a/13505966/161801 rest, tail = os.path.split(path) if not rest or rest == os.path.sep: return (tail,) return full_path_split(rest) + (tail,) def compare_tar_against_git(tarname, gitroot): """ Compare the contents of the tarball against git ls-files See the bottom of the file for the whitelists. """ git_lsfiles = set(i.strip() for i in run('git', 'ls-files', cwd=gitroot)) tar_output_orig = set(run('tar', 'tf', tarname)) tar_output = set() for file in tar_output_orig: # The tar files are like sympy-0.7.3/sympy/__init__.py, and the git # files are like sympy/__init__.py. split_path = full_path_split(file) if split_path[-1]: # Exclude directories, as git ls-files does not include them tar_output.add(os.path.join(*split_path[1:])) # print tar_output # print git_lsfiles fail = False print() print(blue("Files in the tarball from git that should not be there:")) print() for line in sorted(tar_output.intersection(git_whitelist)): fail = True print(line) print() print(blue("Files in git but not in the tarball:")) print() for line in sorted(git_lsfiles - tar_output - git_whitelist): fail = True print(line) print() print(blue("Files in the tarball but not in git:")) print() for line in sorted(tar_output - git_lsfiles - tarball_whitelist): fail = True print(line) print() if fail: sys.exit(red("Non-whitelisted files found or not found in the tarball")) if __name__ == "__main__": main(*sys.argv[1:]) sympy-sympy-1.9/release/fabfile.py000066400000000000000000001307251412543434000173150ustar00rootroot00000000000000# -*- coding: utf-8 -*- """ Fab file for releasing Please read the README in this directory. Guide for this file =================== Vagrant is a tool that gives us a reproducible VM, and fabric is a tool that we use to run commands on that VM. Each function in this file should be run as fab vagrant func Even those functions that do not use vagrant must be run this way, because of the vagrant configuration at the bottom of this file. Any function that should be made available from the command line needs to have the @task decorator. Save any files that should be reset between runs somewhere in the repos directory, so that the remove_userspace() function will clear it. It's best to do a complete vagrant destroy before a full release, but that takes a while, so the remove_userspace() ensures that things are mostly reset for testing. Do not enforce any naming conventions on the release branch. By tradition, the name of the release branch is the same as the version being released (like 0.7.3), but this is not required. Use get_sympy_version() and get_sympy_short_version() to get the SymPy version (the SymPy __version__ *must* be changed in sympy/release.py for this to work). """ from __future__ import print_function from collections import defaultdict, OrderedDict from contextlib import contextmanager from fabric.api import env, local, run, sudo, cd, hide, task from fabric.contrib.files import exists from fabric.colors import blue, red, green from fabric.utils import error, warn env.colorize_errors = True try: import requests from requests.auth import HTTPBasicAuth from requests_oauthlib import OAuth2 except ImportError: warn("requests and requests-oauthlib must be installed to upload to GitHub") requests = False import unicodedata import json from getpass import getpass import os import stat import sys import time import ConfigParser try: # https://pypi.python.org/pypi/fabric-virtualenv/ from fabvenv import virtualenv, make_virtualenv # Note, according to fabvenv docs, always use an absolute path with # virtualenv(). except ImportError: error("fabvenv is required. See https://pypi.python.org/pypi/fabric-virtualenv/") # Note, it's actually good practice to use absolute paths # everywhere. Otherwise, you will get surprising results if you call one # function from another, because your current working directory will be # whatever it was in the calling function, not ~. Also, due to what should # probably be considered a bug, ~ is not treated as an absolute path. You have # to explicitly write out /home/vagrant/ env.use_ssh_config = True def full_path_split(path): """ Function to do a full split on a path. """ # Based on https://stackoverflow.com/a/13505966/161801 rest, tail = os.path.split(path) if not rest or rest == os.path.sep: return (tail,) return full_path_split(rest) + (tail,) @contextmanager def use_venv(pyversion): """ Change make_virtualenv to use a given cmd pyversion should be '2' or '3' """ pyversion = str(pyversion) if pyversion == '2': yield elif pyversion == '3': oldvenv = env.virtualenv env.virtualenv = 'virtualenv -p /usr/bin/python3' yield env.virtualenv = oldvenv else: raise ValueError("pyversion must be one of '2' or '3', not %s" % pyversion) @task def prepare(): """ Setup the VM This only needs to be run once. It downloads all the necessary software, and a git cache. To reset this, use vagrant destroy and vagrant up. Note, this may take a while to finish, depending on your internet connection speed. """ prepare_apt() checkout_cache() @task def prepare_apt(): """ Download software from apt Note, on a slower internet connection, this will take a while to finish, because it has to download many packages, include latex and all its dependencies. """ sudo("apt-get -qq update") sudo("apt-get -y install git python3 make python-virtualenv zip python-dev python-mpmath python3-setuptools") # Need 7.1.2 for Python 3.2 support sudo("easy_install3 pip==7.1.2") sudo("pip3 install mpmath") # Be sure to use the Python 2 pip sudo("/usr/bin/pip install twine") # Needed to build the docs sudo("apt-get -y install graphviz inkscape texlive texlive-xetex texlive-fonts-recommended texlive-latex-extra librsvg2-bin docbook2x") # Our Ubuntu is too old to include Python 3.3 sudo("apt-get -y install python-software-properties") sudo("add-apt-repository -y ppa:fkrull/deadsnakes") sudo("apt-get -y update") sudo("apt-get -y install python3.3") @task def remove_userspace(): """ Deletes (!) the SymPy changes. Use with great care. This should be run between runs to reset everything. """ run("rm -rf repos") if os.path.exists("release"): error("release directory already exists locally. Remove it to continue.") @task def checkout_cache(): """ Checkout a cache of SymPy This should only be run once. The cache is use as a --reference for git clone. This makes deleting and recreating the SymPy a la remove_userspace() and gitrepos() and clone very fast. """ run("rm -rf sympy-cache.git") run("git clone --bare https://github.com/sympy/sympy.git sympy-cache.git") @task def gitrepos(branch=None, fork='sympy'): """ Clone the repo fab vagrant prepare (namely, checkout_cache()) must be run first. By default, the branch checked out is the same one as the one checked out locally. The master branch is not allowed--use a release branch (see the README). No naming convention is put on the release branch. To test the release, create a branch in your fork, and set the fork option. """ with cd("/home/vagrant"): if not exists("sympy-cache.git"): error("Run fab vagrant prepare first") if not branch: # Use the current branch (of this git repo, not the one in Vagrant) branch = local("git rev-parse --abbrev-ref HEAD", capture=True) if branch == "master": raise Exception("Cannot release from master") run("mkdir -p repos") with cd("/home/vagrant/repos"): run("git clone --reference ../sympy-cache.git https://github.com/{fork}/sympy.git".format(fork=fork)) with cd("/home/vagrant/repos/sympy"): run("git checkout -t origin/%s" % branch) @task def get_sympy_version(version_cache=[]): """ Get the full version of SymPy being released (like 0.7.3.rc1) """ if version_cache: return version_cache[0] if not exists("/home/vagrant/repos/sympy"): gitrepos() with cd("/home/vagrant/repos/sympy"): version = run('python -c "import sympy;print(sympy.__version__)"') assert '\n' not in version assert ' ' not in version assert '\t' not in version version_cache.append(version) return version @task def get_sympy_short_version(): """ Get the short version of SymPy being released, not including any rc tags (like 0.7.3) """ version = get_sympy_version() parts = version.split('.') non_rc_parts = [i for i in parts if i.isdigit()] return '.'.join(non_rc_parts) # Remove any rc tags @task def test_sympy(): """ Run the SymPy test suite """ with cd("/home/vagrant/repos/sympy"): run("./setup.py test") @task def test_tarball(release='2'): """ Test that the tarball can be unpacked and installed, and that sympy imports in the install. """ if release not in {'2', '3'}: # TODO: Add win32 raise ValueError("release must be one of '2', '3', not %s" % release) venv = "/home/vagrant/repos/test-{release}-virtualenv".format(release=release) tarball_formatter_dict = tarball_formatter() with use_venv(release): make_virtualenv(venv) with virtualenv(venv): run("cp /vagrant/release/{source} releasetar.tar".format(**tarball_formatter_dict)) run("tar xvf releasetar.tar") with cd("/home/vagrant/{source-orig-notar}".format(**tarball_formatter_dict)): run("python setup.py install") run('python -c "import sympy; print(sympy.__version__)"') @task def release(branch=None, fork='sympy'): """ Perform all the steps required for the release, except uploading In particular, it builds all the release files, and puts them in the release/ directory in the same directory as this one. At the end, it prints some things that need to be pasted into various places as part of the release. To test the release, push a branch to your fork on GitHub and set the fork option to your username. """ remove_userspace() gitrepos(branch, fork) # This has to be run locally because it itself uses fabric. I split it out # into a separate script so that it can be used without vagrant. local("../bin/mailmap_update.py") test_sympy() source_tarball() build_docs() copy_release_files() test_tarball('2') test_tarball('3') compare_tar_against_git() print_authors() @task def source_tarball(): """ Build the source tarball """ with cd("/home/vagrant/repos/sympy"): run("git clean -dfx") run("./setup.py clean") run("./setup.py sdist --keep-temp") run("./setup.py bdist_wininst") run("mv dist/{win32-orig} dist/{win32}".format(**tarball_formatter())) @task def build_docs(): """ Build the html and pdf docs """ with cd("/home/vagrant/repos/sympy"): run("mkdir -p dist") venv = "/home/vagrant/docs-virtualenv" make_virtualenv(venv, dependencies=['sphinx==1.1.3', 'numpy', 'mpmath']) with virtualenv(venv): with cd("/home/vagrant/repos/sympy/doc"): run("make clean") run("make html") run("make man") with cd("/home/vagrant/repos/sympy/doc/_build"): run("mv html {html-nozip}".format(**tarball_formatter())) run("zip -9lr {html} {html-nozip}".format(**tarball_formatter())) run("cp {html} ../../dist/".format(**tarball_formatter())) run("make clean") run("make latex") with cd("/home/vagrant/repos/sympy/doc/_build/latex"): run("make") run("cp {pdf-orig} ../../../dist/{pdf}".format(**tarball_formatter())) @task def copy_release_files(): """ Move the release files from the VM to release/ locally """ with cd("/home/vagrant/repos/sympy"): run("mkdir -p /vagrant/release") run("cp dist/* /vagrant/release/") @task def show_files(file, print_=True): """ Show the contents of a tarball. The current options for file are source: The source tarball win: The Python 2 Windows installer (Not yet implemented!) html: The html docs zip Note, this runs locally, not in vagrant. """ # TODO: Test the unarchived name. See # https://github.com/sympy/sympy/issues/7087. if file == 'source': ret = local("tar tf release/{source}".format(**tarball_formatter()), capture=True) elif file == 'win': # TODO: Windows raise NotImplementedError("Windows installers") elif file == 'html': ret = local("unzip -l release/{html}".format(**tarball_formatter()), capture=True) else: raise ValueError(file + " is not valid") if print_: print(ret) return ret # If a file does not end up in the tarball that should, add it to setup.py if # it is Python, or MANIFEST.in if it is not. (There is a command at the top # of setup.py to gather all the things that should be there). # TODO: Also check that this whitelist isn't growning out of date from files # removed from git. # TODO: Address the "why?" comments below. # Files that are in git that should not be in the tarball git_whitelist = { # Git specific dotfiles '.gitattributes', '.gitignore', '.mailmap', # Travis '.travis.yml', # Code of conduct 'CODE_OF_CONDUCT.md', # Nothing from bin/ should be shipped unless we intend to install it. Most # of this stuff is for development anyway. To run the tests from the # tarball, use setup.py test, or import sympy and run sympy.test() or # sympy.doctest(). 'bin/adapt_paths.py', 'bin/ask_update.py', 'bin/authors_update.py', 'bin/coverage_doctest.py', 'bin/coverage_report.py', 'bin/build_doc.sh', 'bin/deploy_doc.sh', 'bin/diagnose_imports', 'bin/doctest', 'bin/generate_test_list.py', 'bin/get_sympy.py', 'bin/py.bench', 'bin/mailmap_update.py', 'bin/strip_whitespace', 'bin/sympy_time.py', 'bin/sympy_time_cache.py', 'bin/test', 'bin/test_import', 'bin/test_import.py', 'bin/test_isolated', 'bin/test_travis.sh', # The notebooks are not ready for shipping yet. They need to be cleaned # up, and preferably doctested. See also # https://github.com/sympy/sympy/issues/6039. 'examples/advanced/identitysearch_example.ipynb', 'examples/beginner/plot_advanced.ipynb', 'examples/beginner/plot_colors.ipynb', 'examples/beginner/plot_discont.ipynb', 'examples/beginner/plot_gallery.ipynb', 'examples/beginner/plot_intro.ipynb', 'examples/intermediate/limit_examples_advanced.ipynb', 'examples/intermediate/schwarzschild.ipynb', 'examples/notebooks/density.ipynb', 'examples/notebooks/fidelity.ipynb', 'examples/notebooks/fresnel_integrals.ipynb', 'examples/notebooks/qubits.ipynb', 'examples/notebooks/sho1d_example.ipynb', 'examples/notebooks/spin.ipynb', 'examples/notebooks/trace.ipynb', 'examples/notebooks/README.txt', # This stuff :) 'release/.gitignore', 'release/README.md', 'release/Vagrantfile', 'release/fabfile.py', # This is just a distribute version of setup.py. Used mainly for setup.py # develop, which we don't care about in the release tarball 'setupegg.py', # Example on how to use tox to test Sympy. For development. 'tox.ini.sample', } # Files that should be in the tarball should not be in git tarball_whitelist = { # Generated by setup.py. Contains metadata for PyPI. "PKG-INFO", # Generated by setuptools. More metadata. 'setup.cfg', 'sympy.egg-info/PKG-INFO', 'sympy.egg-info/SOURCES.txt', 'sympy.egg-info/dependency_links.txt', 'sympy.egg-info/requires.txt', 'sympy.egg-info/top_level.txt', } @task def compare_tar_against_git(): """ Compare the contents of the tarball against git ls-files """ with hide("commands"): with cd("/home/vagrant/repos/sympy"): git_lsfiles = set([i.strip() for i in run("git ls-files").split("\n")]) tar_output_orig = set(show_files('source', print_=False).split("\n")) tar_output = set() for file in tar_output_orig: # The tar files are like sympy-0.7.3/sympy/__init__.py, and the git # files are like sympy/__init__.py. split_path = full_path_split(file) if split_path[-1]: # Exclude directories, as git ls-files does not include them tar_output.add(os.path.join(*split_path[1:])) # print tar_output # print git_lsfiles fail = False print() print(blue("Files in the tarball from git that should not be there:", bold=True)) print() for line in sorted(tar_output.intersection(git_whitelist)): fail = True print(line) print() print(blue("Files in git but not in the tarball:", bold=True)) print() for line in sorted(git_lsfiles - tar_output - git_whitelist): fail = True print(line) print() print(blue("Files in the tarball but not in git:", bold=True)) print() for line in sorted(tar_output - git_lsfiles - tarball_whitelist): fail = True print(line) if fail: error("Non-whitelisted files found or not found in the tarball") @task def md5(file='*', print_=True): """ Print the md5 sums of the release files """ out = local("md5sum release/" + file, capture=True) # Remove the release/ part for printing. Useful for copy-pasting into the # release notes. out = [i.split() for i in out.strip().split('\n')] out = '\n'.join(["%s\t%s" % (i, os.path.split(j)[1]) for i, j in out]) if print_: print(out) return out descriptions = OrderedDict([ ('source', "The SymPy source installer.",), ('win32', "Python Windows 32-bit installer.",), ('html', '''Html documentation for the Python 2 version. This is the same as the online documentation.''',), ('pdf', '''Pdf version of the html documentation.''',), ]) @task def size(file='*', print_=True): """ Print the sizes of the release files """ out = local("du -h release/" + file, capture=True) out = [i.split() for i in out.strip().split('\n')] out = '\n'.join(["%s\t%s" % (i, os.path.split(j)[1]) for i, j in out]) if print_: print(out) return out @task def table(): """ Make an html table of the downloads. This is for pasting into the GitHub releases page. See GitHub_release(). """ # TODO: Add the file size tarball_formatter_dict = tarball_formatter() shortversion = get_sympy_short_version() tarball_formatter_dict['version'] = shortversion md5s = [i.split('\t') for i in md5(print_=False).split('\n')] md5s_dict = {name: md5 for md5, name in md5s} sizes = [i.split('\t') for i in size(print_=False).split('\n')] sizes_dict = {name: size for size, name in sizes} table = [] version = get_sympy_version() # https://docs.python.org/2/library/contextlib.html#contextlib.contextmanager. Not # recommended as a real way to generate html, but it works better than # anything else I've tried. @contextmanager def tag(name): table.append("<%s>" % name) yield table.append("" % name) @contextmanager def a_href(link): table.append("" % link) yield table.append("") with tag('table'): with tag('tr'): for headname in ["Filename", "Description", "size", "md5"]: with tag("th"): table.append(headname) for key in descriptions: name = get_tarball_name(key) with tag('tr'): with tag('td'): with a_href('https://github.com/sympy/sympy/releases/download/sympy-%s/%s' %(version,name)): with tag('b'): table.append(name) with tag('td'): table.append(descriptions[key].format(**tarball_formatter_dict)) with tag('td'): table.append(sizes_dict[name]) with tag('td'): table.append(md5s_dict[name]) out = ' '.join(table) return out @task def get_tarball_name(file): """ Get the name of a tarball file should be one of source-orig: The original name of the source tarball source-orig-notar: The name of the untarred directory source: The source tarball (after renaming) win32-orig: The original name of the win32 installer win32: The name of the win32 installer (after renaming) html: The name of the html zip html-nozip: The name of the html, without ".zip" pdf-orig: The original name of the pdf file pdf: The name of the pdf file (after renaming) """ version = get_sympy_version() doctypename = defaultdict(str, {'html': 'zip', 'pdf': 'pdf'}) winos = defaultdict(str, {'win32': 'win32', 'win32-orig': 'linux-i686'}) if file in {'source-orig', 'source'}: name = 'sympy-{version}.tar.gz' elif file == 'source-orig-notar': name = "sympy-{version}" elif file in {'win32', 'win32-orig'}: name = "sympy-{version}.{wintype}.exe" elif file in {'html', 'pdf', 'html-nozip'}: name = "sympy-docs-{type}-{version}" if file == 'html-nozip': # zip files keep the name of the original zipped directory. See # https://github.com/sympy/sympy/issues/7087. file = 'html' else: name += ".{extension}" elif file == 'pdf-orig': name = "sympy-{version}.pdf" else: raise ValueError(file + " is not a recognized argument") ret = name.format(version=version, type=file, extension=doctypename[file], wintype=winos[file]) return ret tarball_name_types = { 'source-orig', 'source-orig-notar', 'source', 'win32-orig', 'win32', 'html', 'html-nozip', 'pdf-orig', 'pdf', } # This has to be a function, because you cannot call any function here at # import time (before the vagrant() function is run). def tarball_formatter(): return {name: get_tarball_name(name) for name in tarball_name_types} @task def get_previous_version_tag(): """ Get the version of the previous release """ # We try, probably too hard, to portably get the number of the previous # release of SymPy. Our strategy is to look at the git tags. The # following assumptions are made about the git tags: # - The only tags are for releases # - The tags are given the consistent naming: # sympy-major.minor.micro[.rcnumber] # (e.g., sympy-0.7.2 or sympy-0.7.2.rc1) # In particular, it goes back in the tag history and finds the most recent # tag that doesn't contain the current short version number as a substring. shortversion = get_sympy_short_version() curcommit = "HEAD" with cd("/home/vagrant/repos/sympy"): while True: curtag = run("git describe --abbrev=0 --tags " + curcommit).strip() if shortversion in curtag: # If the tagged commit is a merge commit, we cannot be sure # that it will go back in the right direction. This almost # never happens, so just error parents = local("git rev-list --parents -n 1 " + curtag, capture=True).strip().split() # rev-list prints the current commit and then all its parents # If the tagged commit *is* a merge commit, just comment this # out, and make sure `fab vagrant get_previous_version_tag` is correct assert len(parents) == 2, curtag curcommit = curtag + "^" # The parent of the tagged commit else: print(blue("Using {tag} as the tag for the previous " "release.".format(tag=curtag), bold=True)) return curtag error("Could not find the tag for the previous release.") @task def get_authors(): """ Get the list of authors since the previous release Returns the list in alphabetical order by last name. Authors who contributed for the first time for this release will have a star appended to the end of their names. Note: it's a good idea to use ./bin/mailmap_update.py (from the base sympy directory) to make AUTHORS and .mailmap up-to-date first before using this. fab vagrant release does this automatically. """ def lastnamekey(name): """ Sort key to sort by last name Note, we decided to sort based on the last name, because that way is fair. We used to sort by commit count or line number count, but that bumps up people who made lots of maintenance changes like updating mpmath or moving some files around. """ # Note, this will do the wrong thing for people who have multi-word # last names, but there are also people with middle initials. I don't # know of a perfect way to handle everyone. Feel free to fix up the # list by hand. # Note, you must call unicode() *before* lower, or else it won't # lowercase non-ASCII characters like Č -> č text = unicode(name.strip().split()[-1], encoding='utf-8').lower() # Convert things like Čertík to Certik return unicodedata.normalize('NFKD', text).encode('ascii', 'ignore') old_release_tag = get_previous_version_tag() with cd("/home/vagrant/repos/sympy"), hide('commands'): releaseauthors = set(run('git --no-pager log {tag}.. --format="%aN"'.format(tag=old_release_tag)).strip().split('\n')) priorauthors = set(run('git --no-pager log {tag} --format="%aN"'.format(tag=old_release_tag)).strip().split('\n')) releaseauthors = {name.strip() for name in releaseauthors if name.strip()} priorauthors = {name.strip() for name in priorauthors if name.strip()} newauthors = releaseauthors - priorauthors starred_newauthors = {name + "*" for name in newauthors} authors = releaseauthors - newauthors | starred_newauthors return (sorted(authors, key=lastnamekey), len(releaseauthors), len(newauthors)) @task def print_authors(): """ Print authors text to put at the bottom of the release notes """ authors, authorcount, newauthorcount = get_authors() print(blue("Here are the authors to put at the bottom of the release " "notes.", bold=True)) print() print("""## Authors The following people contributed at least one patch to this release (names are given in alphabetical order by last name). A total of {authorcount} people contributed to this release. People with a * by their names contributed a patch for the first time for this release; {newauthorcount} people contributed for the first time for this release. Thanks to everyone who contributed to this release! """.format(authorcount=authorcount, newauthorcount=newauthorcount)) for name in authors: print("- " + name) print() @task def check_tag_exists(): """ Check if the tag for this release has been uploaded yet. """ version = get_sympy_version() tag = 'sympy-' + version with cd("/home/vagrant/repos/sympy"): all_tags = run("git ls-remote --tags origin") return tag in all_tags # ------------------------------------------------ # Updating websites @task def update_websites(): """ Update various websites owned by SymPy. So far, supports the docs and sympy.org """ update_docs() update_sympy_org() def get_location(location): """ Read/save a location from the configuration file. """ locations_file = os.path.expanduser('~/.sympy/sympy-locations') config = ConfigParser.SafeConfigParser() config.read(locations_file) the_location = config.has_option("Locations", location) and config.get("Locations", location) if not the_location: the_location = raw_input("Where is the SymPy {location} directory? ".format(location=location)) if not config.has_section("Locations"): config.add_section("Locations") config.set("Locations", location, the_location) save = raw_input("Save this to file [yes]? ") if save.lower().strip() in ['', 'y', 'yes']: print("saving to ", locations_file) with open(locations_file, 'w') as f: config.write(f) else: print("Reading {location} location from config".format(location=location)) return os.path.abspath(os.path.expanduser(the_location)) @task def update_docs(docs_location=None): """ Update the docs hosted at docs.sympy.org """ docs_location = docs_location or get_location("docs") print("Docs location:", docs_location) # Check that the docs directory is clean local("cd {docs_location} && git diff --exit-code > /dev/null".format(docs_location=docs_location)) local("cd {docs_location} && git diff --cached --exit-code > /dev/null".format(docs_location=docs_location)) # See the README of the docs repo. We have to remove the old redirects, # move in the new docs, and create redirects. current_version = get_sympy_version() previous_version = get_previous_version_tag().lstrip('sympy-') print("Removing redirects from previous version") local("cd {docs_location} && rm -r {previous_version}".format(docs_location=docs_location, previous_version=previous_version)) print("Moving previous latest docs to old version") local("cd {docs_location} && mv latest {previous_version}".format(docs_location=docs_location, previous_version=previous_version)) print("Unzipping docs into repo") release_dir = os.path.abspath(os.path.expanduser(os.path.join(os.path.curdir, 'release'))) docs_zip = os.path.abspath(os.path.join(release_dir, get_tarball_name('html'))) local("cd {docs_location} && unzip {docs_zip} > /dev/null".format(docs_location=docs_location, docs_zip=docs_zip)) local("cd {docs_location} && mv {docs_zip_name} {version}".format(docs_location=docs_location, docs_zip_name=get_tarball_name("html-nozip"), version=current_version)) print("Writing new version to releases.txt") with open(os.path.join(docs_location, "releases.txt"), 'a') as f: f.write("{version}:SymPy {version}\n".format(version=current_version)) print("Generating indexes") local("cd {docs_location} && ./generate_indexes.py".format(docs_location=docs_location)) local("cd {docs_location} && mv {version} latest".format(docs_location=docs_location, version=current_version)) print("Generating redirects") local("cd {docs_location} && ./generate_redirects.py latest {version} ".format(docs_location=docs_location, version=current_version)) print("Committing") local("cd {docs_location} && git add -A {version} latest".format(docs_location=docs_location, version=current_version)) local("cd {docs_location} && git commit -a -m \'Updating docs to {version}\'".format(docs_location=docs_location, version=current_version)) print("Pushing") local("cd {docs_location} && git push origin".format(docs_location=docs_location)) @task def update_sympy_org(website_location=None): """ Update sympy.org This just means adding an entry to the news section. """ website_location = website_location or get_location("sympy.github.com") # Check that the website directory is clean local("cd {website_location} && git diff --exit-code > /dev/null".format(website_location=website_location)) local("cd {website_location} && git diff --cached --exit-code > /dev/null".format(website_location=website_location)) release_date = time.gmtime(os.path.getctime(os.path.join("release", tarball_formatter()['source']))) release_year = str(release_date.tm_year) release_month = str(release_date.tm_mon) release_day = str(release_date.tm_mday) version = get_sympy_version() with open(os.path.join(website_location, "templates", "index.html"), 'r') as f: lines = f.read().split('\n') # We could try to use some html parser, but this way is easier try: news = lines.index(r"